diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..b49e6481e6702c1a05871d013296ccd86777936a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 + +[*.{cc,cpp,c,h}] +indent_size = 2 diff --git a/.gitignore b/.gitignore index 0bf0233c1990e1cb17e45b7d29206cc01be0d613..3e6891d63f92bc5e07030d36e1c14e83d8b368ef 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ compile_commands.json .vscode/ *.profraw *.iml +**/.idea +**/__pycache__/ +*.py[cod] diff --git a/Android.bp b/Android.bp index beaeb680cbb3a0d1a2659b633f5f16c869a8a733..d585c6c9ca8ca57197d8b9b4ebd8f333271eb60b 100644 --- a/Android.bp +++ b/Android.bp @@ -38,26 +38,37 @@ filegroup { ], } -filegroup { - name: "BluetoothGTestForce32ConfigTemplate", - srcs: [ - "AndroidGTestForce32Template.xml", - ], -} - -// Address Sanitizer is flaky on Android x86_64 binaries but it's not on x86 -// binaries. -// This default workaround the x86_64 ASAN flakyness by running 32bit binaries -// on 64bit targets. -// TODO(b/154347133): Remove this workaround +// This default contains properties that should be common to all the cc targets +// developed by the Bluetooth team. +// +// Be careful when adding new properties here: +// - The option should not impact negatively any target, for example "-Wno-*" +// options should not be added here but instead on every targets needing +// them to avoid allowing adding new warnings in targets that didn't contained +// them (you can use the bpmodify tool to ease the work of adding this warning +// everywhere) and also allows cleaning them one at a time. +// +// - The option should apply to all the c/c++ code developed by the Bluetooth team: +// test, tools, fuzzers, etc, not only production targets, if you need to add an option +// for a subset of Bluetooth cc targets you should look at the defaults including this +// defaults like "fluoride_defaults" and "gd_defaults". +// +// - Try to keep the name as precise as possible to document to the dependent of what +// this default contains. This also means that if you add a new option that isn't +// documented by the name of this default, rename it. +// +// - Try avoiding adding option that would not fit "future" targets, for exemple dependencies, +// even if every modules of Bluetooth depends on a specific dependency it should be left out +// from this default to not push it for future targets that might not need it. cc_defaults { - name: "bluetooth_gtest_x86_asan_workaround", - target: { - android_x86: { - test_config_template: ":BluetoothGTestForce32ConfigTemplate", - }, - android_x86_64: { - enabled: false, - }, - }, + name: "bluetooth_cflags", + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + // Override global.go that demote the error to a warning + "-Werror=reorder-init-list", + ], + c_std: "c99", + cpp_std: "c++17", } diff --git a/AndroidGTestForce32Template.xml b/AndroidGTestForce32Template.xml deleted file mode 100644 index bad033a2936f8689537a4494113e1d4741e1ebe4..0000000000000000000000000000000000000000 --- a/AndroidGTestForce32Template.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - diff --git a/Cargo.toml b/Cargo.toml index e9fef56c38600ba8ec2b0e48d6976b1ca2e592cd..341abaa58307203bbd1ea63793218ba57603ffd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,9 @@ default-members = [ "system/gd/rust/topshim", "system/gd/rust/linux/mgmt", "system/gd/rust/linux/service", + "system/gd/rust/linux/stack", "system/gd/rust/linux/client", + "system/gd/rust/linux/utils", ] members = [ @@ -28,6 +30,8 @@ members = [ "system/gd/rust/topshim", "system/gd/rust/linux/mgmt", "system/gd/rust/linux/service", + "system/gd/rust/linux/stack", "system/gd/rust/linux/client", + "system/gd/rust/linux/utils", "floss/hcidoc", ] diff --git a/OWNERS b/OWNERS index fa4d5e7243ce97fcc35717bc103990984c0c20cb..6511a489aab972db7afd8835fac5cfbedb9b46e8 100644 --- a/OWNERS +++ b/OWNERS @@ -1,3 +1,5 @@ +# Bug component: 27441 + # Project owners girardier@google.com #{LAST_RESORT_SUGGESTION} muhammadfalam@google.com #{LAST_RESORT_SUGGESTION} @@ -7,8 +9,8 @@ sungsoo@google.com #{LAST_RESORT_SUGGESTION} # Per-file ownership -per-file *.bp,*.xml=wescande@google.com -per-file TEST_MAPPING,*.bp,*.xml=licorne@google.com +# Build files / test_config / presubmit / preupload +per-file PREUPLOAD.cfg,TEST_MAPPING,*.bp,*.xml=file:/OWNERS_build # ChromeOS team owns Linux build files # - build.py is used for Linux build diff --git a/OWNERS_automotive b/OWNERS_automotive index 7ecd87651514786390f1d59eb88e120fc34a59ab..267d177006f5c4a8de6456c310087021d1195555 100644 --- a/OWNERS_automotive +++ b/OWNERS_automotive @@ -1,3 +1,2 @@ # Project owners -pirozzoj@google.com salsavage@google.com diff --git a/OWNERS_build b/OWNERS_build new file mode 100644 index 0000000000000000000000000000000000000000..263e0532b6ba983665554ebbeb49c3c0540039df --- /dev/null +++ b/OWNERS_build @@ -0,0 +1,2 @@ +licorne@google.com +wescande@google.com diff --git a/OWNERS_chromeos b/OWNERS_chromeos index 2bc73f23088758220be1f5c2a60f43e2656fe0e5..0280ec47df9af042be2674c2d55beaeb5ceb43cc 100644 --- a/OWNERS_chromeos +++ b/OWNERS_chromeos @@ -5,6 +5,8 @@ sonnysasaka@google.com # Audio enshuo@google.com hychao@google.com +jrwu@google.com +whalechang@google.com # General review michaelfsun@google.com diff --git a/OWNERS_hearingaid b/OWNERS_hearingaid new file mode 100644 index 0000000000000000000000000000000000000000..09f245c2fcca2b51b7bb92e2f0d95d318f0ace8f --- /dev/null +++ b/OWNERS_hearingaid @@ -0,0 +1,2 @@ +charliebout@google.com +licorne@google.com diff --git a/OWNERS_leaudio b/OWNERS_leaudio new file mode 100644 index 0000000000000000000000000000000000000000..30db38d7995a5464633021e6f1f61d743d5e8eb1 --- /dev/null +++ b/OWNERS_leaudio @@ -0,0 +1,3 @@ +siyuanh@google.com +jpawlowski@google.com +rongxuan@google.com diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index a5534dafc06225a6a2786565c43ea02488a40b04..dd650a05874e00400782eceba784fc01f2a47f14 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -2,7 +2,6 @@ ignore_merged_commits = true [Builtin Hooks] -aidl_format = true commit_msg_bug_field = true google_java_format = true clang_format = true @@ -15,6 +14,7 @@ rustfmt = --config-path=rustfmt.toml # Only turn on clang-format check for C and C++ headers and sources clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp,hpp ktfmt = --kotlinlang-style +bpfmt = -s [Hook Scripts] checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} diff --git a/TEST_MAPPING b/TEST_MAPPING index 278530e4779842cf3c7f5575038a8987ad82a8df..4e568c8a98c06c3a7713d86f40c1649b3667f671 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -7,15 +7,16 @@ { "name": "BluetoothInstrumentationTests" }, - //{ - // "name": "GoogleBluetoothInstrumentationTests" - //}, - //{ - // "name": "FrameworkBluetoothTests" - //}, - //{ - // "name": "ServiceBluetoothTests" - //}, + { + "name": "GoogleBluetoothInstrumentationTests", + "keywords": ["internal"] + }, + { + "name": "FrameworkBluetoothTests" + }, + { + "name": "ServiceBluetoothTests" + }, // device only tests // Broken //{ @@ -69,9 +70,6 @@ { "name": "net_test_stack_ad_parser" }, - { - "name": "net_test_stack_multi_adv" - }, // go/a-unit-tests tests (unit_test: true) // Thoses test run on the host in the CI automatically. // Run the one that are available on the device on the @@ -118,9 +116,6 @@ { "name": "bluetooth_vc_test" }, - { - "name": "bt_host_test_bta" - }, { "name": "libaptx_enc_tests" }, @@ -154,9 +149,6 @@ { "name": "net_test_eatt" }, - { - "name": "net_test_hci_fragmenter_native" - }, { "name": "net_test_main_shim" }, @@ -220,15 +212,15 @@ { "name": "BluetoothInstrumentationTests" }, - //{ - // "name": "GoogleBluetoothInstrumentationTests" - //}, - //{ - // "name": "FrameworkBluetoothTests" - //}, - //{ - // "name": "ServiceBluetoothTests" - //}, + { + "name": "GoogleBluetoothInstrumentationTests" + }, + { + "name": "FrameworkBluetoothTests" + }, + { + "name": "ServiceBluetoothTests" + }, // device only tests // Broken //{ @@ -270,160 +262,72 @@ { "name": "net_test_gatt_conn_multiplexing" }, - { - "name": "net_test_hci" - }, { "name": "net_test_stack" }, - { - "name": "net_test_stack_a2dp_codecs_native" - }, { "name": "net_test_stack_ad_parser" }, - { - "name": "net_test_stack_multi_adv" - }, // go/a-unit-tests tests (unit_test: true) // Thoses test run on the host in the CI automatically. // Run the one that are available on the device on the // device as well - { - "name": "bluetooth_csis_test" - }, { "name": "bluetooth_flatbuffer_tests" }, - { - "name": "bluetooth_groups_test" - }, - { - "name": "bluetooth_has_test" - }, - { - "name": "bluetooth_hh_test" - }, - { - "name": "bluetooth_le_audio_client_test" - }, // b/271319421 // { // "name": "bluetooth_le_audio_test" // }, - { - "name": "bluetooth_packet_parser_test" - }, - { - "name": "bluetooth_test_broadcaster" - }, - { - "name": "bluetooth_test_broadcaster_state_machine" - }, { "name": "bluetooth_test_common" }, - { - "name": "bluetooth_test_gd_unit" - }, { "name": "bluetooth_test_sdp" }, { "name": "bluetooth_vc_test" }, - { - "name": "bt_host_test_bta" - }, - { - "name": "libaptx_enc_tests" - }, - { - "name": "libaptxhd_enc_tests" - }, { "name": "net_test_avrcp" }, - { - "name": "net_test_btcore" - }, { "name": "net_test_btif_config_cache" }, - { - "name": "net_test_btif_hh" - }, - { - "name": "net_test_btif_rc" - }, - { - "name": "net_test_btif_stack" - }, - { - "name": "net_test_btm_iso" - }, { "name": "net_test_btpackets" }, { "name": "net_test_eatt" }, - { - "name": "net_test_hci_fragmenter_native" - }, - { - "name": "net_test_main_shim" - }, - { - "name": "net_test_osi" - }, { "name": "net_test_performance" }, - { - "name": "net_test_stack_a2dp_native" - }, - { - "name": "net_test_stack_acl" - }, - { - "name": "net_test_stack_avdtp" - }, - { - "name": "net_test_stack_btm" - }, - { - "name": "net_test_stack_btu" - }, - { - "name": "net_test_stack_gatt" - }, - { - "name": "net_test_stack_gatt_native" - }, { "name": "net_test_stack_gatt_sr_hash_native" }, { - "name": "net_test_stack_hci" + "name": "net_test_stack_rfcomm" }, { - "name": "net_test_stack_hid" + "name": "net_test_stack_sdp" }, { - "name": "net_test_stack_l2cap" + "name": "net_test_stack_smp" }, { - "name": "net_test_stack_rfcomm" - }, + "name": "net_test_types" + } + ], + "postsubmit": [ { - "name": "net_test_stack_sdp" + "name": "bluetooth_le_audio_codec_manager_test" }, { - "name": "net_test_stack_smp" + "name": "bluetooth_test_gdx_unit" }, { - "name": "net_test_types" + "name": "asrc_resampler_test" } ] } diff --git a/android/BluetoothLegacyMigration/OWNERS b/android/BluetoothLegacyMigration/OWNERS index 8f5c903d7e8759d22a59ff162a43fd73a6309d16..fad553d703c19b3439dac3133d1a68a31fe97eae 100644 --- a/android/BluetoothLegacyMigration/OWNERS +++ b/android/BluetoothLegacyMigration/OWNERS @@ -1,8 +1,6 @@ # Reviewers for /android/BluetoothLegacyMigration eruffieux@google.com -rahulsabnis@google.com sattiraju@google.com siyuanh@google.com wescande@google.com -zachoverflow@google.com diff --git a/android/apishim/OWNERS b/android/apishim/OWNERS index c0cdca9fa575b927cacc5f9e3e6096910e61a078..231e3b66efe9f7124405655024df5ff1dcc6a261 100644 --- a/android/apishim/OWNERS +++ b/android/apishim/OWNERS @@ -1,13 +1,9 @@ # Reviewers for /android/apishim cmanton@google.com -cncn@google.com eruffieux@google.com jpawlowski@google.com mylesgw@google.com -optedoblivion@google.com -qasimj@google.com -rahulsabnis@google.com sattiraju@google.com siyuanh@google.com wescande@google.com \ No newline at end of file diff --git a/android/app/Android.bp b/android/app/Android.bp index 4e5e6845a07bb6e496ae6f1920ba1cd963b71a91..1d43cfefa3445f04077b9f95e0a66543e8dbac17 100644 --- a/android/app/Android.bp +++ b/android/app/Android.bp @@ -55,8 +55,14 @@ java_library { cc_library_shared { name: "libbluetooth_jni", - defaults: ["fluoride_basic_defaults"], + defaults: [ + "fluoride_defaults", + "latest_android_hardware_audio_common_ndk_static", + "latest_android_hardware_bluetooth_audio_ndk_static", + "latest_android_media_audio_common_types_ndk_static", + ], srcs: ["jni/**/*.cpp"], + version_script: "libbluetooth_jni.map", header_libs: [ "jni_headers", "libbluetooth_headers", @@ -66,22 +72,49 @@ cc_library_shared { "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/types", ], + // libbluetooth_jni is the jni lib included in the btservices apex. + // As this library is inside an APEX the shared_libs that does not + // expose stubs are copied inside it. As a result using those as + // shared libraries is less interesting as they are not shared, so we link + // them statically to allow the linker to perform more optimisation. + // + // The only exception to this is libcrypto because the shared version + // is required to maintain FIPS compliance. + stl: "libc++_static", static_libs: [ + "android.hardware.audio.common@5.0", + "android.hardware.bluetooth.audio@2.0", + "android.hardware.bluetooth.audio@2.1", + "android.hardware.bluetooth@1.0", + "android.hardware.bluetooth@1.1", + "android.hardware.common-V2-ndk", + "android.hardware.common.fmq-V1-ndk", + "android.system.suspend-V1-ndk", + "android.system.suspend.control-V1-ndk", "avrcp-target-service", "lib-bt-packets-avrcp", "lib-bt-packets-base", + "libFraunhoferAAC", "libaudio-a2dp-hw-utils", + "libbase", "libbluetooth", + "libbluetooth-dumpsys", "libbluetooth-types", "libbluetooth_core_rs", "libbluetooth_core_rs_bridge", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", + "libbt-btu-main-thread", "libbt-common", "libbt-hci", + "libbt-sbc-decoder", + "libbt-sbc-encoder", "libbt-stack", "libbt-stack-core", + "libbt_shim_bridge", "libbtcore", "libbtdevice", "libbte", @@ -89,14 +122,30 @@ cc_library_shared { "libbtif-core", "libc++fs", "libchrome", + "libcutils", "libevent", + "libflatbuffers-cpp", + "libfmq", + "libg722codec", + "libhidlbase", + "liblc3", "libmodpb64", + "libopus", "libosi", + "libprotobuf-cpp-lite", + "libstatslog_bt", + "libudrv-uipc", + "libutils", + "server_configurable_flags", ], shared_libs: [ - "android.hardware.bluetooth.audio-V3-ndk", - "android.hardware.bluetooth@1.0", - "android.hardware.bluetooth@1.1", + "libaaudio", + "libbinder_ndk", + "libcrypto", + "liblog", + "libnativehelper", + "libstatssocket", + "libvndksupport", ], sanitize: { scs: true, @@ -109,7 +158,7 @@ cc_library_shared { cc_library { name: "libbluetooth-core", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], header_libs: [ "jni_headers", "libbluetooth_headers", @@ -160,8 +209,13 @@ android_app { srcs: [ ":statslog-bluetooth-java-gen", ":statslog-bt-restricted-java-gen", + ":system-messages-proto-src", + "proto/keystore.proto", "src/**/*.java", ], + proto: { + type: "lite", + }, aaptflags: [ "--custom-package", "com.android.bluetooth", @@ -169,6 +223,7 @@ android_app { certificate: "bluetooth", jarjar_rules: ":bluetooth-jarjar-rules", + privapp_allowlist: ":privapp_allowlist_com.android.bluetooth.xml", jni_uses_platform_apis: true, libs: [ @@ -178,12 +233,17 @@ android_app { "framework-bluetooth-pre-jarjar", "framework-configinfrastructure", "framework-connectivity.stubs.module_lib", + "framework-location.stubs.module_lib", "framework-mediaprovider", "framework-statsd.stubs.module_lib", "framework-tethering.stubs.module_lib", "unsupportedappusage", + + // Need to link the class at runtime + "framework-bluetooth", ], static_libs: [ + "BluetoothApiShims", "android.hardware.radio-V1.0-java", "android.hardware.radio.sap-V1-java", "androidx.annotation_annotation", @@ -191,11 +251,11 @@ android_app { "androidx.lifecycle_lifecycle-livedata", "androidx.media_media", "androidx.room_room-runtime", - "BluetoothApiShims", "bluetooth-proto-enums-java-gen", "bluetooth-protos-lite", "bluetooth.change-ids", "bluetooth.mapsapi", + "bluetooth_flags_java_lib", "com.android.obex", "com.android.vcard", "guava", @@ -204,7 +264,6 @@ android_app { "modules-utils-backgroundthread", "modules-utils-bytesmatcher", "modules-utils-statemachine", - "modules-utils-synchronous-result-receiver", "net-utils-services-common", "networkstack-client", "sap-api-java-static", @@ -214,13 +273,32 @@ android_app { "androidx.room_room-compiler-plugin", ], - // Add in path to Bluetooth directory because local path does not exist + // Export schemas to the test directory so that we have an history + // to be able to test migrations + // The following path is absolute because a relative path doesn't work + // TODO(b/147596836): Refactor this javacflags: ["-Aroom.schemaLocation=packages/modules/Bluetooth/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/schemas"], + lint: { + error_checks: [ + "ExtraText", + "MissingClass", + "NewApi", + "ObsoleteSdkInt", + "Recycle", + "RtlHardcoded", + "UseSparseArrays", + "UseValueOf", + ], + strict_updatability_linting: true, + }, + optimize: { enabled: true, shrink: true, optimize: false, + // TODO(b/289285719): Revisit after resolving mocking issues in testing. + proguard_compatibility: true, proguard_flags_files: ["proguard.flags"], }, apex_available: [ diff --git a/android/app/AndroidManifest.xml b/android/app/AndroidManifest.xml index bdcc793aac448b045fe8c41fe478be9f5a625acc..3e07cc5b0f58da57d85960c1436b8b34b8b55d36 100644 --- a/android/app/AndroidManifest.xml +++ b/android/app/AndroidManifest.xml @@ -103,6 +103,16 @@ + + + + + + - - - - - - - - @@ -442,7 +440,7 @@ android:process="@string/process" android:excludeFromRecents="true" android:theme="@style/dialog" - android:enabled="false">> + android:enabled="false"> GetMethodID(clazz, "bqrDeliver", "([BIII[B)V"); - - LOG(INFO) << __func__ << ": succeeds"; -} - static void initNative(JNIEnv* env, jobject object) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -131,7 +125,7 @@ static void initNative(JNIEnv* env, jobject object) { sBluetoothQualityReportInterface->init(&sBluetoothQualityReportCallbacks); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -151,17 +145,28 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, -}; - int register_com_android_bluetooth_btservice_BluetoothQualityReport( JNIEnv* env) { - return jniRegisterNativeMethods(env, - "com/android/bluetooth/btservice/" - "BluetoothQualityReportNativeInterface", - sMethods, NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, + "com/android/bluetooth/btservice/BluetoothQualityReportNativeInterface", + methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"bqrDeliver", "([BIII[B)V", &method_bqrDeliver}, + }; + GET_JAVA_METHODS( + env, + "com/android/bluetooth/btservice/BluetoothQualityReportNativeInterface", + javaMethods); + + return 0; } } // namespace android diff --git a/android/app/jni/com_android_bluetooth_a2dp.cpp b/android/app/jni/com_android_bluetooth_a2dp.cpp index 991bc1b69493fb80e296b36206d793e704047536..c2427e10bf04ae2dc0ce21f64aae627c65bfc063 100644 --- a/android/app/jni/com_android_bluetooth_a2dp.cpp +++ b/android/app/jni/com_android_bluetooth_a2dp.cpp @@ -51,7 +51,7 @@ static std::shared_timed_mutex callbacks_mutex; static void bta2dp_connection_state_callback(const RawAddress& bd_addr, btav_connection_state_t state, - const btav_error_t& error) { + const btav_error_t& /* error */) { ALOGI("%s", __func__); std::shared_lock lock(callbacks_mutex); @@ -191,50 +191,8 @@ static btav_source_callbacks_t sBluetoothA2dpCallbacks = { bta2dp_mandatory_codec_preferred_callback, }; -static void classInitNative(JNIEnv* env, jclass clazz) { - jclass jniBluetoothCodecConfigClass = - env->FindClass("android/bluetooth/BluetoothCodecConfig"); - android_bluetooth_BluetoothCodecConfig.constructor = - env->GetMethodID(jniBluetoothCodecConfigClass, "", "(IIIIIJJJJ)V"); - android_bluetooth_BluetoothCodecConfig.getCodecType = - env->GetMethodID(jniBluetoothCodecConfigClass, "getCodecType", "()I"); - android_bluetooth_BluetoothCodecConfig.getCodecPriority = - env->GetMethodID(jniBluetoothCodecConfigClass, "getCodecPriority", "()I"); - android_bluetooth_BluetoothCodecConfig.getSampleRate = - env->GetMethodID(jniBluetoothCodecConfigClass, "getSampleRate", "()I"); - android_bluetooth_BluetoothCodecConfig.getBitsPerSample = - env->GetMethodID(jniBluetoothCodecConfigClass, "getBitsPerSample", "()I"); - android_bluetooth_BluetoothCodecConfig.getChannelMode = - env->GetMethodID(jniBluetoothCodecConfigClass, "getChannelMode", "()I"); - android_bluetooth_BluetoothCodecConfig.getCodecSpecific1 = env->GetMethodID( - jniBluetoothCodecConfigClass, "getCodecSpecific1", "()J"); - android_bluetooth_BluetoothCodecConfig.getCodecSpecific2 = env->GetMethodID( - jniBluetoothCodecConfigClass, "getCodecSpecific2", "()J"); - android_bluetooth_BluetoothCodecConfig.getCodecSpecific3 = env->GetMethodID( - jniBluetoothCodecConfigClass, "getCodecSpecific3", "()J"); - android_bluetooth_BluetoothCodecConfig.getCodecSpecific4 = env->GetMethodID( - jniBluetoothCodecConfigClass, "getCodecSpecific4", "()J"); - - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "([BI)V"); - - method_onAudioStateChanged = - env->GetMethodID(clazz, "onAudioStateChanged", "([BI)V"); - - method_onCodecConfigChanged = - env->GetMethodID(clazz, "onCodecConfigChanged", - "([BLandroid/bluetooth/BluetoothCodecConfig;" - "[Landroid/bluetooth/BluetoothCodecConfig;" - "[Landroid/bluetooth/BluetoothCodecConfig;)V"); - - method_isMandatoryCodecPreferred = - env->GetMethodID(clazz, "isMandatoryCodecPreferred", "([B)Z"); - - ALOGI("%s: succeeds", __func__); -} - static std::vector prepareCodecPreferences( - JNIEnv* env, jobject object, jobjectArray codecConfigArray) { + JNIEnv* env, jobject /* object */, jobjectArray codecConfigArray) { std::vector codec_preferences; int numConfigs = env->GetArrayLength(codecConfigArray); @@ -347,7 +305,7 @@ static void initNative(JNIEnv* env, jobject object, } } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -371,7 +329,52 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectA2dpNative(JNIEnv* env, jobject object, +static jobjectArray getSupportedCodecTypesNative(JNIEnv* env) { + ALOGI("%s: %p", __func__, sBluetoothA2dpInterface); + + jclass android_bluetooth_BluetoothCodecType_clazz = (jclass)env->NewGlobalRef( + env->FindClass("android/bluetooth/BluetoothCodecType")); + if (android_bluetooth_BluetoothCodecType_clazz == nullptr) { + ALOGE("%s: Failed to allocate Global Ref for BluetoothCodecType class", + __func__); + return nullptr; + } + + jmethodID createFromType = env->GetStaticMethodID( + android_bluetooth_BluetoothCodecType_clazz, "createFromType", + "(I)Landroid/bluetooth/BluetoothCodecType;"); + if (createFromType == nullptr) { + ALOGE( + "%s: Failed to find method createFromType of BluetoothCodecType class", + __func__); + return nullptr; + } + + std::array default_supported_codecs = { + BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, + BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, + BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS, + }; + jobjectArray result = + env->NewObjectArray(default_supported_codecs.size(), + android_bluetooth_BluetoothCodecType_clazz, nullptr); + if (result == nullptr) { + ALOGE("%s: Failed to allocate result array of BluetoothCodecType", + __func__); + return nullptr; + } + + for (size_t index = 0; index < default_supported_codecs.size(); index++) { + jobject codec_type = env->CallStaticObjectMethod( + android_bluetooth_BluetoothCodecType_clazz, createFromType, + (jint)default_supported_codecs[index]); + env->SetObjectArrayElement(result, index, codec_type); + } + + return result; +} + +static jboolean connectA2dpNative(JNIEnv* env, jobject /* object */, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock lock(interface_mutex); @@ -396,7 +399,7 @@ static jboolean connectA2dpNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, +static jboolean disconnectA2dpNative(JNIEnv* env, jobject /* object */, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock lock(interface_mutex); @@ -421,7 +424,7 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean setSilenceDeviceNative(JNIEnv* env, jobject object, +static jboolean setSilenceDeviceNative(JNIEnv* env, jobject /* object */, jbyteArray address, jboolean silence) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock lock(interface_mutex); @@ -448,7 +451,7 @@ static jboolean setSilenceDeviceNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, +static jboolean setActiveDeviceNative(JNIEnv* env, jobject /* object */, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); std::shared_lock lock(interface_mutex); @@ -501,24 +504,68 @@ static jboolean setCodecConfigPreferenceNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", - "(I[Landroid/bluetooth/BluetoothCodecConfig;[Landroid/bluetooth/BluetoothCodecConfig;)V", - (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative}, - {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative}, - {"setSilenceDeviceNative", "([BZ)Z", (void*)setSilenceDeviceNative}, - {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, - {"setCodecConfigPreferenceNative", - "([B[Landroid/bluetooth/BluetoothCodecConfig;)Z", - (void*)setCodecConfigPreferenceNative}, -}; - int register_com_android_bluetooth_a2dp(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/a2dp/A2dpNativeInterface", sMethods, - NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initNative", + "(I[Landroid/bluetooth/BluetoothCodecConfig;" + "[Landroid/bluetooth/BluetoothCodecConfig;)V", + (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"getSupportedCodecTypesNative", + "()[Landroid/bluetooth/BluetoothCodecType;", + (void*)getSupportedCodecTypesNative}, + {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative}, + {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative}, + {"setSilenceDeviceNative", "([BZ)Z", (void*)setSilenceDeviceNative}, + {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, + {"setCodecConfigPreferenceNative", + "([B[Landroid/bluetooth/BluetoothCodecConfig;)Z", + (void*)setCodecConfigPreferenceNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/a2dp/A2dpNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectionStateChanged", "([BI)V", &method_onConnectionStateChanged}, + {"onAudioStateChanged", "([BI)V", &method_onAudioStateChanged}, + {"onCodecConfigChanged", + "([BLandroid/bluetooth/BluetoothCodecConfig;" + "[Landroid/bluetooth/BluetoothCodecConfig;" + "[Landroid/bluetooth/BluetoothCodecConfig;)V", + &method_onCodecConfigChanged}, + {"isMandatoryCodecPreferred", "([B)Z", &method_isMandatoryCodecPreferred}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/a2dp/A2dpNativeInterface", + javaMethods); + + const JNIJavaMethod codecConfigCallbacksMethods[] = { + {"", "(IIIIIJJJJ)V", + &android_bluetooth_BluetoothCodecConfig.constructor}, + {"getCodecType", "()I", + &android_bluetooth_BluetoothCodecConfig.getCodecType}, + {"getCodecPriority", "()I", + &android_bluetooth_BluetoothCodecConfig.getCodecPriority}, + {"getSampleRate", "()I", + &android_bluetooth_BluetoothCodecConfig.getSampleRate}, + {"getBitsPerSample", "()I", + &android_bluetooth_BluetoothCodecConfig.getBitsPerSample}, + {"getChannelMode", "()I", + &android_bluetooth_BluetoothCodecConfig.getChannelMode}, + {"getCodecSpecific1", "()J", + &android_bluetooth_BluetoothCodecConfig.getCodecSpecific1}, + {"getCodecSpecific2", "()J", + &android_bluetooth_BluetoothCodecConfig.getCodecSpecific2}, + {"getCodecSpecific3", "()J", + &android_bluetooth_BluetoothCodecConfig.getCodecSpecific3}, + {"getCodecSpecific4", "()J", + &android_bluetooth_BluetoothCodecConfig.getCodecSpecific4}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothCodecConfig", + codecConfigCallbacksMethods); + + return 0; } } diff --git a/android/app/jni/com_android_bluetooth_a2dp_sink.cpp b/android/app/jni/com_android_bluetooth_a2dp_sink.cpp index 2419e4e45e9f8bdc5b0c8926541bed5d39e02a02..d2abfb6055a0c09fa3e7b6869698c2a525b43358 100644 --- a/android/app/jni/com_android_bluetooth_a2dp_sink.cpp +++ b/android/app/jni/com_android_bluetooth_a2dp_sink.cpp @@ -34,9 +34,9 @@ static const btav_sink_interface_t* sBluetoothA2dpInterface = NULL; static jobject mCallbacksObj = NULL; static std::shared_timed_mutex callbacks_mutex; -static void a2dp_sink_connection_state_callback(const RawAddress& bd_addr, - btav_connection_state_t state, - const btav_error_t& error) { +static void a2dp_sink_connection_state_callback( + const RawAddress& bd_addr, btav_connection_state_t state, + const btav_error_t& /* error */) { ALOGI("%s", __func__); std::shared_lock lock(callbacks_mutex); if (!mCallbacksObj) return; @@ -110,19 +110,6 @@ static btav_sink_callbacks_t sBluetoothA2dpCallbacks = { a2dp_sink_audio_config_callback, }; -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "([BI)V"); - - method_onAudioStateChanged = - env->GetMethodID(clazz, "onAudioStateChanged", "([BI)V"); - - method_onAudioConfigChanged = - env->GetMethodID(clazz, "onAudioConfigChanged", "([BII)V"); - - ALOGI("%s: succeeds", __func__); -} - static void initNative(JNIEnv* env, jobject object, jint maxConnectedAudioDevices) { std::unique_lock lock(callbacks_mutex); @@ -164,7 +151,7 @@ static void initNative(JNIEnv* env, jobject object, mCallbacksObj = env->NewGlobalRef(object); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock lock(callbacks_mutex); const bt_interface_t* btInf = getBluetoothInterface(); @@ -184,7 +171,7 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectA2dpNative(JNIEnv* env, jobject object, +static jboolean connectA2dpNative(JNIEnv* env, jobject /* object */, jbyteArray address) { ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface); if (!sBluetoothA2dpInterface) return JNI_FALSE; @@ -205,7 +192,7 @@ static jboolean connectA2dpNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, +static jboolean disconnectA2dpNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sBluetoothA2dpInterface) return JNI_FALSE; @@ -225,19 +212,19 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static void informAudioFocusStateNative(JNIEnv* env, jobject object, +static void informAudioFocusStateNative(JNIEnv* /* env */, jobject /* object */, jint focus_state) { if (!sBluetoothA2dpInterface) return; sBluetoothA2dpInterface->set_audio_focus_state((uint8_t)focus_state); } -static void informAudioTrackGainNative(JNIEnv* env, jobject object, +static void informAudioTrackGainNative(JNIEnv* /* env */, jobject /* object */, jfloat gain) { if (!sBluetoothA2dpInterface) return; sBluetoothA2dpInterface->set_audio_track_gain((float)gain); } -static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, +static jboolean setActiveDeviceNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sBluetoothA2dpInterface) return JNI_FALSE; @@ -260,20 +247,32 @@ static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "(I)V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative}, - {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative}, - {"informAudioFocusStateNative", "(I)V", (void*)informAudioFocusStateNative}, - {"informAudioTrackGainNative", "(F)V", (void*)informAudioTrackGainNative}, - {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, -}; - int register_com_android_bluetooth_a2dp_sink(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface", sMethods, - NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initNative", "(I)V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative}, + {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative}, + {"informAudioFocusStateNative", "(I)V", + (void*)informAudioFocusStateNative}, + {"informAudioTrackGainNative", "(F)V", (void*)informAudioTrackGainNative}, + {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectionStateChanged", "([BI)V", &method_onConnectionStateChanged}, + {"onAudioStateChanged", "([BI)V", &method_onAudioStateChanged}, + {"onAudioConfigChanged", "([BII)V", &method_onAudioConfigChanged}, + }; + GET_JAVA_METHODS(env, + "com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface", + javaMethods); + + return 0; } } diff --git a/android/app/jni/com_android_bluetooth_avrcp_controller.cpp b/android/app/jni/com_android_bluetooth_avrcp_controller.cpp index 316e1d0ac17c52e14582530fb368797064223257..6382f460937bfc2b9a6cbcd8699cfe2c2f805d02 100644 --- a/android/app/jni/com_android_bluetooth_avrcp_controller.cpp +++ b/android/app/jni/com_android_bluetooth_avrcp_controller.cpp @@ -24,10 +24,7 @@ #include namespace android { -static jmethodID method_handlePassthroughRsp; static jmethodID method_onConnectionStateChanged; -static jmethodID method_getRcFeatures; -static jmethodID method_setplayerappsettingrsp; static jmethodID method_handleplayerappsetting; static jmethodID method_handleplayerappsettingchanged; static jmethodID method_handleSetAbsVolume; @@ -37,7 +34,6 @@ static jmethodID method_handleplaypositionchanged; static jmethodID method_handleplaystatuschanged; static jmethodID method_handleGetFolderItemsRsp; static jmethodID method_handleGetPlayerItemsRsp; -static jmethodID method_handleGroupNavigationRsp; static jmethodID method_createFromNativeMediaItem; static jmethodID method_createFromNativeFolderItem; static jmethodID method_createFromNativePlayerItem; @@ -49,6 +45,7 @@ static jmethodID method_handleNowPlayingContentChanged; static jmethodID method_onAvailablePlayerChanged; static jmethodID method_getRcPsm; +static jclass class_AvrcpControllerNativeInterface; static jclass class_AvrcpItem; static jclass class_AvrcpPlayer; @@ -56,42 +53,13 @@ static const btrc_ctrl_interface_t* sBluetoothAvrcpInterface = NULL; static jobject sCallbacksObj = NULL; static std::shared_timed_mutex sCallbacks_mutex; -static void btavrcp_passthrough_response_callback(const RawAddress& bd_addr, - int id, int pressed) { - ALOGI("%s: id: %d, pressed: %d", __func__, id, pressed); - std::shared_lock lock(sCallbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid()) return; - if (!sCallbacksObj) { - ALOGE("%s: sCallbacksObj is null", __func__); - return; - } - - ScopedLocalRef addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - ALOGE("%s: Failed to allocate a new byte array", __func__); - return; - } - - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), - (jbyte*)&bd_addr.address); - sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handlePassthroughRsp, - (jint)id, (jint)pressed, addr.get()); +static void btavrcp_passthrough_response_callback( + const RawAddress& /* bd_addr */, int id, int pressed) { + ALOGV("%s: id: %d, pressed: %d --- Not implemented", __func__, id, pressed); } static void btavrcp_groupnavigation_response_callback(int id, int pressed) { - ALOGV("%s", __func__); - std::shared_lock lock(sCallbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid()) return; - if (!sCallbacksObj) { - ALOGE("%s: sCallbacksObj is null", __func__); - return; - } - - sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGroupNavigationRsp, - (jint)id, (jint)pressed); + ALOGV("%s: id: %d, pressed: %d --- Not implemented", __func__, id, pressed); } static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect, @@ -119,58 +87,19 @@ static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect, addr.get()); } -static void btavrcp_get_rcfeatures_callback(const RawAddress& bd_addr, - int features) { - ALOGV("%s", __func__); - std::shared_lock lock(sCallbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid()) return; - if (!sCallbacksObj) { - ALOGE("%s: sCallbacksObj is null", __func__); - return; - } - - ScopedLocalRef addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - ALOGE("%s: Failed to allocate a new byte array", __func__); - return; - } - - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), - (jbyte*)&bd_addr.address); - sCallbackEnv->CallVoidMethod(sCallbacksObj, method_getRcFeatures, addr.get(), - (jint)features); +static void btavrcp_get_rcfeatures_callback(const RawAddress& /* bd_addr */, + int /* features */) { + ALOGV("%s --- Not implemented", __func__); } - static void btavrcp_setplayerapplicationsetting_rsp_callback( - const RawAddress& bd_addr, uint8_t accepted) { - ALOGV("%s", __func__); - std::shared_lock lock(sCallbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid()) return; - if (!sCallbacksObj) { - ALOGE("%s: sCallbacksObj is null", __func__); - return; - } - - ScopedLocalRef addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - ALOGE("%s: Failed to allocate a new byte array", __func__); - return; - } - - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), - (jbyte*)&bd_addr.address); - sCallbackEnv->CallVoidMethod(sCallbacksObj, method_setplayerappsettingrsp, - addr.get(), (jint)accepted); + const RawAddress& /* bd_addr */, uint8_t /* accepted */) { + ALOGV("%s --- Not implemented", __func__); } static void btavrcp_playerapplicationsetting_callback( const RawAddress& bd_addr, uint8_t num_attr, - btrc_player_app_attr_t* app_attrs, uint8_t num_ext_attr, - btrc_player_app_ext_attr_t* ext_attrs) { + btrc_player_app_attr_t* app_attrs, uint8_t /* num_ext_attr */, + btrc_player_app_ext_attr_t* /* ext_attrs */) { ALOGI("%s", __func__); std::shared_lock lock(sCallbacks_mutex); CallbackEnv sCallbackEnv(__func__); @@ -509,10 +438,11 @@ static void btavrcp_get_folder_items_callback( ScopedLocalRef mediaObj( sCallbackEnv.get(), - (jobject)sCallbackEnv->CallObjectMethod( - sCallbacksObj, method_createFromNativeMediaItem, addr.get(), - uid, (jint)item->media.type, mediaName.get(), - attrIdArray.get(), attrValArray.get())); + (jobject)sCallbackEnv->CallStaticObjectMethod( + class_AvrcpControllerNativeInterface, + method_createFromNativeMediaItem, addr.get(), uid, + (jint)item->media.type, mediaName.get(), attrIdArray.get(), + attrValArray.get())); if (!mediaObj.get()) { ALOGE("%s failed to create AvrcpItem for type ITEM_MEDIA", __func__); return; @@ -534,9 +464,10 @@ static void btavrcp_get_folder_items_callback( long long uid = *(long long*)item->folder.uid; ScopedLocalRef folderObj( sCallbackEnv.get(), - (jobject)sCallbackEnv->CallObjectMethod( - sCallbacksObj, method_createFromNativeFolderItem, addr.get(), - uid, (jint)item->folder.type, folderName.get(), + (jobject)sCallbackEnv->CallStaticObjectMethod( + class_AvrcpControllerNativeInterface, + method_createFromNativeFolderItem, addr.get(), uid, + (jint)item->folder.type, folderName.get(), (jint)item->folder.playable)); if (!folderObj.get()) { ALOGE("%s failed to create AvrcpItem for type ITEM_FOLDER", __func__); @@ -574,9 +505,10 @@ static void btavrcp_get_folder_items_callback( } ScopedLocalRef playerObj( sCallbackEnv.get(), - (jobject)sCallbackEnv->CallObjectMethod( - sCallbacksObj, method_createFromNativePlayerItem, addr.get(), - id, playerName.get(), featureBitArray.get(), playStatus, + (jobject)sCallbackEnv->CallStaticObjectMethod( + class_AvrcpControllerNativeInterface, + method_createFromNativePlayerItem, addr.get(), id, + playerName.get(), featureBitArray.get(), playStatus, playerType)); if (!playerObj.get()) { ALOGE("%s failed to create AvrcpPlayer from ITEM_PLAYER", __func__); @@ -788,81 +720,8 @@ static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = { btavrcp_addressed_player_changed_callback, btavrcp_now_playing_content_changed_callback, btavrcp_available_player_changed_callback, - btavrcp_get_rcpsm_callback}; - -static void classInitNative(JNIEnv* env, jclass clazz) { - method_handlePassthroughRsp = - env->GetMethodID(clazz, "handlePassthroughRsp", "(II[B)V"); - - method_handleGroupNavigationRsp = - env->GetMethodID(clazz, "handleGroupNavigationRsp", "(II)V"); - - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "(ZZ[B)V"); - - method_getRcFeatures = env->GetMethodID(clazz, "getRcFeatures", "([BI)V"); - - method_getRcPsm = env->GetMethodID(clazz, "getRcPsm", "([BI)V"); - - method_setplayerappsettingrsp = - env->GetMethodID(clazz, "setPlayerAppSettingRsp", "([BB)V"); - - method_handleplayerappsetting = - env->GetMethodID(clazz, "handlePlayerAppSetting", "([B[BI)V"); - - method_handleplayerappsettingchanged = - env->GetMethodID(clazz, "onPlayerAppSettingChanged", "([B[BI)V"); - - method_handleSetAbsVolume = - env->GetMethodID(clazz, "handleSetAbsVolume", "([BBB)V"); - - method_handleRegisterNotificationAbsVol = - env->GetMethodID(clazz, "handleRegisterNotificationAbsVol", "([BB)V"); - - method_handletrackchanged = - env->GetMethodID(clazz, "onTrackChanged", "([BB[I[Ljava/lang/String;)V"); - - method_handleplaypositionchanged = - env->GetMethodID(clazz, "onPlayPositionChanged", "([BII)V"); - - method_handleplaystatuschanged = - env->GetMethodID(clazz, "onPlayStatusChanged", "([BB)V"); - - method_handleGetFolderItemsRsp = - env->GetMethodID(clazz, "handleGetFolderItemsRsp", - "([BI[Lcom/android/bluetooth/avrcpcontroller/" - "AvrcpItem;)V"); - method_handleGetPlayerItemsRsp = env->GetMethodID( - clazz, "handleGetPlayerItemsRsp", - "([B[Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;)V"); - - method_createFromNativeMediaItem = - env->GetMethodID(clazz, "createFromNativeMediaItem", - "([BJILjava/lang/String;[I[Ljava/lang/String;)Lcom/" - "android/bluetooth/avrcpcontroller/AvrcpItem;"); - method_createFromNativeFolderItem = env->GetMethodID( - clazz, "createFromNativeFolderItem", - "([BJILjava/lang/String;I)Lcom/android/bluetooth/avrcpcontroller/" - "AvrcpItem;"); - method_createFromNativePlayerItem = - env->GetMethodID(clazz, "createFromNativePlayerItem", - "([BILjava/lang/String;[BII)Lcom/android/bluetooth/" - "avrcpcontroller/AvrcpPlayer;"); - method_handleChangeFolderRsp = - env->GetMethodID(clazz, "handleChangeFolderRsp", "([BI)V"); - method_handleSetBrowsedPlayerRsp = - env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "([BII)V"); - method_handleSetAddressedPlayerRsp = - env->GetMethodID(clazz, "handleSetAddressedPlayerRsp", "([BI)V"); - method_handleAddressedPlayerChanged = - env->GetMethodID(clazz, "handleAddressedPlayerChanged", "([BI)V"); - method_handleNowPlayingContentChanged = - env->GetMethodID(clazz, "handleNowPlayingContentChanged", "([B)V"); - method_onAvailablePlayerChanged = - env->GetMethodID(clazz, "onAvailablePlayerChanged", "([B)V"); - - ALOGI("%s: succeeds", __func__); -} + btavrcp_get_rcpsm_callback, +}; static void initNative(JNIEnv* env, jobject object) { std::unique_lock lock(sCallbacks_mutex); @@ -875,6 +734,11 @@ static void initNative(JNIEnv* env, jobject object) { env->FindClass("com/android/bluetooth/avrcpcontroller/AvrcpPlayer"); class_AvrcpPlayer = (jclass)env->NewGlobalRef(tmpBtPlayer); + jclass tmpControllerInterface = env->FindClass( + "com/android/bluetooth/avrcpcontroller/AvrcpControllerNativeInterface"); + class_AvrcpControllerNativeInterface = + (jclass)env->NewGlobalRef(tmpControllerInterface); + const bt_interface_t* btInf = getBluetoothInterface(); if (btInf == NULL) { ALOGE("Bluetooth module is not loaded"); @@ -913,7 +777,7 @@ static void initNative(JNIEnv* env, jobject object) { sCallbacksObj = env->NewGlobalRef(object); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock lock(sCallbacks_mutex); const bt_interface_t* btInf = getBluetoothInterface(); @@ -933,7 +797,7 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean sendPassThroughCommandNative(JNIEnv* env, jobject object, +static jboolean sendPassThroughCommandNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint key_code, jint key_state) { if (!sBluetoothAvrcpInterface) return JNI_FALSE; @@ -960,7 +824,8 @@ static jboolean sendPassThroughCommandNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean sendGroupNavigationCommandNative(JNIEnv* env, jobject object, +static jboolean sendGroupNavigationCommandNative(JNIEnv* env, + jobject /* object */, jbyteArray address, jint key_code, jint key_state) { @@ -988,11 +853,9 @@ static jboolean sendGroupNavigationCommandNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static void setPlayerApplicationSettingValuesNative(JNIEnv* env, jobject object, - jbyteArray address, - jbyte num_attrib, - jbyteArray attrib_ids, - jbyteArray attrib_val) { +static void setPlayerApplicationSettingValuesNative( + JNIEnv* env, jobject /* object */, jbyteArray address, jbyte num_attrib, + jbyteArray attrib_ids, jbyteArray attrib_val) { ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface); if (!sBluetoothAvrcpInterface) return; @@ -1039,8 +902,8 @@ static void setPlayerApplicationSettingValuesNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void sendAbsVolRspNative(JNIEnv* env, jobject object, jbyteArray address, - jint abs_vol, jint label) { +static void sendAbsVolRspNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jint abs_vol, jint label) { if (!sBluetoothAvrcpInterface) return; jbyte* addr = env->GetByteArrayElements(address, NULL); @@ -1061,7 +924,7 @@ static void sendAbsVolRspNative(JNIEnv* env, jobject object, jbyteArray address, env->ReleaseByteArrayElements(address, addr, 0); } -static void sendRegisterAbsVolRspNative(JNIEnv* env, jobject object, +static void sendRegisterAbsVolRspNative(JNIEnv* env, jobject /* object */, jbyteArray address, jbyte rsp_type, jint abs_vol, jint label) { if (!sBluetoothAvrcpInterface) return; @@ -1085,7 +948,7 @@ static void sendRegisterAbsVolRspNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void getCurrentMetadataNative(JNIEnv* env, jobject object, +static void getCurrentMetadataNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sBluetoothAvrcpInterface) return; @@ -1106,7 +969,7 @@ static void getCurrentMetadataNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void getPlaybackStateNative(JNIEnv* env, jobject object, +static void getPlaybackStateNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sBluetoothAvrcpInterface) return; @@ -1127,7 +990,7 @@ static void getPlaybackStateNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void getNowPlayingListNative(JNIEnv* env, jobject object, +static void getNowPlayingListNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint start, jint end) { if (!sBluetoothAvrcpInterface) return; jbyte* addr = env->GetByteArrayElements(address, NULL); @@ -1147,8 +1010,8 @@ static void getNowPlayingListNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void getFolderListNative(JNIEnv* env, jobject object, jbyteArray address, - jint start, jint end) { +static void getFolderListNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jint start, jint end) { if (!sBluetoothAvrcpInterface) return; jbyte* addr = env->GetByteArrayElements(address, NULL); if (!addr) { @@ -1167,8 +1030,8 @@ static void getFolderListNative(JNIEnv* env, jobject object, jbyteArray address, env->ReleaseByteArrayElements(address, addr, 0); } -static void getPlayerListNative(JNIEnv* env, jobject object, jbyteArray address, - jint start, jint end) { +static void getPlayerListNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jint start, jint end) { if (!sBluetoothAvrcpInterface) return; jbyte* addr = env->GetByteArrayElements(address, NULL); if (!addr) { @@ -1187,7 +1050,7 @@ static void getPlayerListNative(JNIEnv* env, jobject object, jbyteArray address, env->ReleaseByteArrayElements(address, addr, 0); } -static void changeFolderPathNative(JNIEnv* env, jobject object, +static void changeFolderPathNative(JNIEnv* env, jobject /* object */, jbyteArray address, jbyte direction, jlong uid) { if (!sBluetoothAvrcpInterface) return; @@ -1215,7 +1078,7 @@ static void changeFolderPathNative(JNIEnv* env, jobject object, // env->ReleaseByteArrayElements(address, addr, 0); } -static void setBrowsedPlayerNative(JNIEnv* env, jobject object, +static void setBrowsedPlayerNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint id) { if (!sBluetoothAvrcpInterface) return; jbyte* addr = env->GetByteArrayElements(address, NULL); @@ -1235,7 +1098,7 @@ static void setBrowsedPlayerNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void setAddressedPlayerNative(JNIEnv* env, jobject object, +static void setAddressedPlayerNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint id) { if (!sBluetoothAvrcpInterface) return; jbyte* addr = env->GetByteArrayElements(address, NULL); @@ -1256,8 +1119,9 @@ static void setAddressedPlayerNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void playItemNative(JNIEnv* env, jobject object, jbyteArray address, - jbyte scope, jlong uid, jint uidCounter) { +static void playItemNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jbyte scope, jlong uid, + jint uidCounter) { if (!sBluetoothAvrcpInterface) return; jbyte* addr = env->GetByteArrayElements(address, NULL); if (!addr) { @@ -1282,33 +1146,84 @@ static void playItemNative(JNIEnv* env, jobject object, jbyteArray address, env->ReleaseByteArrayElements(address, addr, 0); } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"sendPassThroughCommandNative", "([BII)Z", - (void*)sendPassThroughCommandNative}, - {"sendGroupNavigationCommandNative", "([BII)Z", - (void*)sendGroupNavigationCommandNative}, - {"setPlayerApplicationSettingValuesNative", "([BB[B[B)V", - (void*)setPlayerApplicationSettingValuesNative}, - {"sendAbsVolRspNative", "([BII)V", (void*)sendAbsVolRspNative}, - {"sendRegisterAbsVolRspNative", "([BBII)V", - (void*)sendRegisterAbsVolRspNative}, - {"getCurrentMetadataNative", "([B)V", (void*)getCurrentMetadataNative}, - {"getPlaybackStateNative", "([B)V", (void*)getPlaybackStateNative}, - {"getNowPlayingListNative", "([BII)V", (void*)getNowPlayingListNative}, - {"getFolderListNative", "([BII)V", (void*)getFolderListNative}, - {"getPlayerListNative", "([BII)V", (void*)getPlayerListNative}, - {"changeFolderPathNative", "([BBJ)V", (void*)changeFolderPathNative}, - {"playItemNative", "([BBJI)V", (void*)playItemNative}, - {"setBrowsedPlayerNative", "([BI)V", (void*)setBrowsedPlayerNative}, - {"setAddressedPlayerNative", "([BI)V", (void*)setAddressedPlayerNative}, -}; - int register_com_android_bluetooth_avrcp_controller(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/avrcpcontroller/AvrcpControllerService", - sMethods, NELEM(sMethods)); -} + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"sendPassThroughCommandNative", "([BII)Z", + (void*)sendPassThroughCommandNative}, + {"sendGroupNavigationCommandNative", "([BII)Z", + (void*)sendGroupNavigationCommandNative}, + {"setPlayerApplicationSettingValuesNative", "([BB[B[B)V", + (void*)setPlayerApplicationSettingValuesNative}, + {"sendAbsVolRspNative", "([BII)V", (void*)sendAbsVolRspNative}, + {"sendRegisterAbsVolRspNative", "([BBII)V", + (void*)sendRegisterAbsVolRspNative}, + {"getCurrentMetadataNative", "([B)V", (void*)getCurrentMetadataNative}, + {"getPlaybackStateNative", "([B)V", (void*)getPlaybackStateNative}, + {"getNowPlayingListNative", "([BII)V", (void*)getNowPlayingListNative}, + {"getFolderListNative", "([BII)V", (void*)getFolderListNative}, + {"getPlayerListNative", "([BII)V", (void*)getPlayerListNative}, + {"changeFolderPathNative", "([BBJ)V", (void*)changeFolderPathNative}, + {"playItemNative", "([BBJI)V", (void*)playItemNative}, + {"setBrowsedPlayerNative", "([BI)V", (void*)setBrowsedPlayerNative}, + {"setAddressedPlayerNative", "([BI)V", (void*)setAddressedPlayerNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, + "com/android/bluetooth/avrcpcontroller/AvrcpControllerNativeInterface", + methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectionStateChanged", "(ZZ[B)V", &method_onConnectionStateChanged}, + {"getRcPsm", "([BI)V", &method_getRcPsm}, + {"handlePlayerAppSetting", "([B[BI)V", &method_handleplayerappsetting}, + {"onPlayerAppSettingChanged", "([B[BI)V", + &method_handleplayerappsettingchanged}, + {"handleSetAbsVolume", "([BBB)V", &method_handleSetAbsVolume}, + {"handleRegisterNotificationAbsVol", "([BB)V", + &method_handleRegisterNotificationAbsVol}, + {"onTrackChanged", "([BB[I[Ljava/lang/String;)V", + &method_handletrackchanged}, + {"onPlayPositionChanged", "([BII)V", &method_handleplaypositionchanged}, + {"onPlayStatusChanged", "([BB)V", &method_handleplaystatuschanged}, + {"handleGetFolderItemsRsp", + "([BI[Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;)V", + &method_handleGetFolderItemsRsp}, + {"handleGetPlayerItemsRsp", + "([B[Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;)V", + &method_handleGetPlayerItemsRsp}, + {"handleChangeFolderRsp", "([BI)V", &method_handleChangeFolderRsp}, + {"handleSetBrowsedPlayerRsp", "([BII)V", + &method_handleSetBrowsedPlayerRsp}, + {"handleSetAddressedPlayerRsp", "([BI)V", + &method_handleSetAddressedPlayerRsp}, + {"handleAddressedPlayerChanged", "([BI)V", + &method_handleAddressedPlayerChanged}, + {"handleNowPlayingContentChanged", "([B)V", + &method_handleNowPlayingContentChanged}, + {"onAvailablePlayerChanged", "([B)V", &method_onAvailablePlayerChanged}, + // Fetch static method + {"createFromNativeMediaItem", + "([BJILjava/lang/String;[I[Ljava/lang/String;)" + "Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;", + &method_createFromNativeMediaItem, true}, + {"createFromNativeFolderItem", + "([BJILjava/lang/String;I)" + "Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;", + &method_createFromNativeFolderItem, true}, + {"createFromNativePlayerItem", + "([BILjava/lang/String;[BII)" + "Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;", + &method_createFromNativePlayerItem, true}, + }; + GET_JAVA_METHODS( + env, + "com/android/bluetooth/avrcpcontroller/AvrcpControllerNativeInterface", + javaMethods); + return 0; } +} // namespace android diff --git a/android/app/jni/com_android_bluetooth_avrcp_target.cpp b/android/app/jni/com_android_bluetooth_avrcp_target.cpp index edfb684b5c792f9a51393ab88f4f154ca0ec54af..a5e4949de33a5aaaa1750307fa01833c0d0f1ae3 100644 --- a/android/app/jni/com_android_bluetooth_avrcp_target.cpp +++ b/android/app/jni/com_android_bluetooth_avrcp_target.cpp @@ -150,7 +150,7 @@ class AvrcpMediaInterfaceImpl : public MediaInterface { mServiceCallbacks = callback; } - void UnregisterUpdateCallback(MediaCallbacks* callback) override { + void UnregisterUpdateCallback(MediaCallbacks* /* callback */) override { mServiceCallbacks = nullptr; } @@ -232,63 +232,6 @@ static jmethodID method_listPlayerSettingValues; static jmethodID method_getPlayerSettings; static jmethodID method_setPlayerSettings; -static void classInitNative(JNIEnv* env, jclass clazz) { - method_getCurrentSongInfo = env->GetMethodID( - clazz, "getCurrentSongInfo", "()Lcom/android/bluetooth/audio_util/Metadata;"); - - method_getPlaybackStatus = env->GetMethodID( - clazz, "getPlayStatus", "()Lcom/android/bluetooth/audio_util/PlayStatus;"); - - method_sendMediaKeyEvent = - env->GetMethodID(clazz, "sendMediaKeyEvent", "(IZ)V"); - - method_getCurrentMediaId = - env->GetMethodID(clazz, "getCurrentMediaId", "()Ljava/lang/String;"); - - method_getNowPlayingList = - env->GetMethodID(clazz, "getNowPlayingList", "()Ljava/util/List;"); - - method_getCurrentPlayerId = - env->GetMethodID(clazz, "getCurrentPlayerId", "()I"); - - method_getMediaPlayerList = - env->GetMethodID(clazz, "getMediaPlayerList", "()Ljava/util/List;"); - - method_setBrowsedPlayer = env->GetMethodID(clazz, "setBrowsedPlayer", "(I)V"); - - method_getFolderItemsRequest = env->GetMethodID( - clazz, "getFolderItemsRequest", "(ILjava/lang/String;)V"); - - method_playItem = - env->GetMethodID(clazz, "playItem", "(IZLjava/lang/String;)V"); - - method_setActiveDevice = - env->GetMethodID(clazz, "setActiveDevice", "(Ljava/lang/String;)V"); - - // Volume Management functions - method_volumeDeviceConnected = - env->GetMethodID(clazz, "deviceConnected", "(Ljava/lang/String;Z)V"); - - method_volumeDeviceDisconnected = - env->GetMethodID(clazz, "deviceDisconnected", "(Ljava/lang/String;)V"); - - method_setVolume = env->GetMethodID(clazz, "setVolume", "(I)V"); - - method_listPlayerSettings = - env->GetMethodID(clazz, "listPlayerSettingsRequest", "()V"); - - method_listPlayerSettingValues = - env->GetMethodID(clazz, "listPlayerSettingValuesRequest", "(B)V"); - - method_getPlayerSettings = - env->GetMethodID(clazz, "getCurrentPlayerSettingValuesRequest", "([B)V"); - - method_setPlayerSettings = - env->GetMethodID(clazz, "setPlayerSettingsRequest", "([B[B)V"); - - ALOGI("%s: AvrcpTargetJni initialized!", __func__); -} - static void initNative(JNIEnv* env, jobject object) { ALOGD("%s", __func__); std::unique_lock interface_lock(interface_mutex); @@ -300,7 +243,7 @@ static void initNative(JNIEnv* env, jobject object) { &mPlayerSettingsInterface); } -static void registerBipServerNative(JNIEnv* env, jobject object, +static void registerBipServerNative(JNIEnv* /* env */, jobject /* object */, jint l2cap_psm) { ALOGD("%s: l2cap_psm=%d", __func__, (int)l2cap_psm); std::unique_lock interface_lock(interface_mutex); @@ -311,7 +254,7 @@ static void registerBipServerNative(JNIEnv* env, jobject object, sServiceInterface->RegisterBipServer((int)l2cap_psm); } -static void unregisterBipServerNative(JNIEnv* env, jobject object) { +static void unregisterBipServerNative(JNIEnv* /* env */, jobject /* object */) { ALOGD("%s", __func__); std::unique_lock interface_lock(interface_mutex); if (sServiceInterface == nullptr) { @@ -321,7 +264,7 @@ static void unregisterBipServerNative(JNIEnv* env, jobject object) { sServiceInterface->UnregisterBipServer(); } -static void sendMediaUpdateNative(JNIEnv* env, jobject object, +static void sendMediaUpdateNative(JNIEnv* /* env */, jobject /* object */, jboolean metadata, jboolean state, jboolean queue) { ALOGD("%s", __func__); @@ -335,7 +278,7 @@ static void sendMediaUpdateNative(JNIEnv* env, jobject object, queue == JNI_TRUE); } -static void sendFolderUpdateNative(JNIEnv* env, jobject object, +static void sendFolderUpdateNative(JNIEnv* /* env */, jobject /* object */, jboolean available_players, jboolean addressed_player, jboolean uids) { ALOGD("%s", __func__); @@ -350,7 +293,7 @@ static void sendFolderUpdateNative(JNIEnv* env, jobject object, uids == JNI_TRUE); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -364,7 +307,8 @@ static void cleanupNative(JNIEnv* env, jobject object) { sServiceInterface = nullptr; } -jboolean connectDeviceNative(JNIEnv* env, jobject object, jstring address) { +jboolean connectDeviceNative(JNIEnv* env, jobject /* object */, + jstring address) { ALOGD("%s", __func__); std::unique_lock interface_lock(interface_mutex); if (mServiceCallbacks == nullptr) { @@ -383,7 +327,8 @@ jboolean connectDeviceNative(JNIEnv* env, jobject object, jstring address) { : JNI_FALSE; } -jboolean disconnectDeviceNative(JNIEnv* env, jobject object, jstring address) { +jboolean disconnectDeviceNative(JNIEnv* env, jobject /* object */, + jstring address) { ALOGD("%s", __func__); std::unique_lock interface_lock(interface_mutex); if (mServiceCallbacks == nullptr) { @@ -762,9 +707,10 @@ static void setBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCb cb) { player_id); } -static void setBrowsedPlayerResponseNative(JNIEnv* env, jobject object, - jint player_id, jboolean success, - jstring root_id, jint num_items) { +static void setBrowsedPlayerResponseNative(JNIEnv* env, jobject /* object */, + jint /* player_id */, + jboolean success, jstring root_id, + jint num_items) { ALOGD("%s", __func__); std::string root; @@ -777,7 +723,7 @@ static void setBrowsedPlayerResponseNative(JNIEnv* env, jobject object, set_browsed_player_cb.Run(success == JNI_TRUE, root, num_items); } -static void getFolderItemsResponseNative(JNIEnv* env, jobject object, +static void getFolderItemsResponseNative(JNIEnv* env, jobject /* object */, jstring parent_id, jobject list) { ALOGD("%s", __func__); @@ -932,7 +878,7 @@ static void volumeDeviceDisconnected(const RawAddress& address) { j_bdaddr); } -static void sendVolumeChangedNative(JNIEnv* env, jobject object, +static void sendVolumeChangedNative(JNIEnv* env, jobject /* object */, jstring address, jint volume) { const char* tmp_addr = env->GetStringUTFChars(address, 0); RawAddress bdaddr; @@ -956,8 +902,8 @@ static void setVolume(int8_t volume) { sCallbackEnv->CallVoidMethod(mJavaInterface, method_setVolume, volume); } -static void setBipClientStatusNative(JNIEnv* env, jobject object, - jstring address, jboolean connected) { +static void setBipClientStatusNative(JNIEnv* env, jobject /* object */, + jstring address, jboolean connected) { std::unique_lock interface_lock(interface_mutex); if (mServiceCallbacks == nullptr) { ALOGW("%s: Service not loaded.", __func__); @@ -986,7 +932,7 @@ static void listPlayerSettings(ListPlayerSettingsCb cb) { sCallbackEnv->CallVoidMethod(mJavaInterface, method_listPlayerSettings); } -static void listPlayerSettingsResponseNative(JNIEnv* env, jobject object, +static void listPlayerSettingsResponseNative(JNIEnv* env, jobject /* object */, jbyteArray attributes) { ALOGD("%s", __func__); @@ -1009,7 +955,8 @@ static void listPlayerSettingValues(PlayerAttribute attribute, (jbyte)attribute); } -static void listPlayerSettingValuesResponseNative(JNIEnv* env, jobject object, +static void listPlayerSettingValuesResponseNative(JNIEnv* env, + jobject /* object */, jbyte attribute, jbyteArray values) { ALOGD("%s", __func__); @@ -1037,7 +984,7 @@ static void getPlayerSettings(std::vector attributes, attributes_array); } -static void getPlayerSettingsResponseNative(JNIEnv* env, jobject object, +static void getPlayerSettingsResponseNative(JNIEnv* env, jobject /* object */, jbyteArray attributes, jbyteArray values) { ALOGD("%s", __func__); @@ -1074,13 +1021,14 @@ static void setPlayerSettings(std::vector attributes, attributes_array, values_array); } -static void setPlayerSettingsResponseNative(JNIEnv* env, jobject object, +static void setPlayerSettingsResponseNative(JNIEnv* /* env */, + jobject /* object */, jboolean success) { ALOGD("%s", __func__); set_player_setting_value_cb.Run(success); } -static void sendPlayerSettingsNative(JNIEnv* env, jobject object, +static void sendPlayerSettingsNative(JNIEnv* env, jobject /* object */, jbyteArray attributes, jbyteArray values) { ALOGD("%s", __func__); std::unique_lock interface_lock(interface_mutex); @@ -1096,41 +1044,73 @@ static void sendPlayerSettingsNative(JNIEnv* env, jobject object, values_vector); } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"registerBipServerNative", "(I)V", (void*)registerBipServerNative}, - {"unregisterBipServerNative", "()V", (void*)unregisterBipServerNative}, - {"sendMediaUpdateNative", "(ZZZ)V", (void*)sendMediaUpdateNative}, - {"sendFolderUpdateNative", "(ZZZ)V", (void*)sendFolderUpdateNative}, - {"setBrowsedPlayerResponseNative", "(IZLjava/lang/String;I)V", - (void*)setBrowsedPlayerResponseNative}, - {"getFolderItemsResponseNative", "(Ljava/lang/String;Ljava/util/List;)V", - (void*)getFolderItemsResponseNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectDeviceNative", "(Ljava/lang/String;)Z", - (void*)connectDeviceNative}, - {"disconnectDeviceNative", "(Ljava/lang/String;)Z", - (void*)disconnectDeviceNative}, - {"sendVolumeChangedNative", "(Ljava/lang/String;I)V", - (void*)sendVolumeChangedNative}, - {"setBipClientStatusNative", "(Ljava/lang/String;Z)V", - (void*)setBipClientStatusNative}, - {"listPlayerSettingsResponseNative", "([B)V", - (void*)listPlayerSettingsResponseNative}, - {"listPlayerSettingValuesResponseNative", "(B[B)V", - (void*)listPlayerSettingValuesResponseNative}, - {"getPlayerSettingsResponseNative", "([B[B)V", - (void*)getPlayerSettingsResponseNative}, - {"setPlayerSettingsResponseNative", "(Z)V", - (void*)setPlayerSettingsResponseNative}, - {"sendPlayerSettingsNative", "([B[B)V", (void*)sendPlayerSettingsNative}, -}; - int register_com_android_bluetooth_avrcp_target(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/avrcp/AvrcpNativeInterface", sMethods, - NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"registerBipServerNative", "(I)V", (void*)registerBipServerNative}, + {"unregisterBipServerNative", "()V", (void*)unregisterBipServerNative}, + {"sendMediaUpdateNative", "(ZZZ)V", (void*)sendMediaUpdateNative}, + {"sendFolderUpdateNative", "(ZZZ)V", (void*)sendFolderUpdateNative}, + {"setBrowsedPlayerResponseNative", "(IZLjava/lang/String;I)V", + (void*)setBrowsedPlayerResponseNative}, + {"getFolderItemsResponseNative", "(Ljava/lang/String;Ljava/util/List;)V", + (void*)getFolderItemsResponseNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectDeviceNative", "(Ljava/lang/String;)Z", + (void*)connectDeviceNative}, + {"disconnectDeviceNative", "(Ljava/lang/String;)Z", + (void*)disconnectDeviceNative}, + {"sendVolumeChangedNative", "(Ljava/lang/String;I)V", + (void*)sendVolumeChangedNative}, + {"setBipClientStatusNative", "(Ljava/lang/String;Z)V", + (void*)setBipClientStatusNative}, + {"listPlayerSettingsResponseNative", "([B)V", + (void*)listPlayerSettingsResponseNative}, + {"listPlayerSettingValuesResponseNative", "(B[B)V", + (void*)listPlayerSettingValuesResponseNative}, + {"getPlayerSettingsResponseNative", "([B[B)V", + (void*)getPlayerSettingsResponseNative}, + {"setPlayerSettingsResponseNative", "(Z)V", + (void*)setPlayerSettingsResponseNative}, + {"sendPlayerSettingsNative", "([B[B)V", (void*)sendPlayerSettingsNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/avrcp/AvrcpNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"getCurrentSongInfo", "()Lcom/android/bluetooth/audio_util/Metadata;", + &method_getCurrentSongInfo}, + {"getPlayStatus", "()Lcom/android/bluetooth/audio_util/PlayStatus;", + &method_getPlaybackStatus}, + {"sendMediaKeyEvent", "(IZ)V", &method_sendMediaKeyEvent}, + {"getCurrentMediaId", "()Ljava/lang/String;", &method_getCurrentMediaId}, + {"getNowPlayingList", "()Ljava/util/List;", &method_getNowPlayingList}, + {"getCurrentPlayerId", "()I", &method_getCurrentPlayerId}, + {"getMediaPlayerList", "()Ljava/util/List;", &method_getMediaPlayerList}, + {"setBrowsedPlayer", "(I)V", &method_setBrowsedPlayer}, + {"getFolderItemsRequest", "(ILjava/lang/String;)V", + &method_getFolderItemsRequest}, + {"playItem", "(IZLjava/lang/String;)V", &method_playItem}, + {"setActiveDevice", "(Ljava/lang/String;)V", &method_setActiveDevice}, + {"deviceConnected", "(Ljava/lang/String;Z)V", + &method_volumeDeviceConnected}, + {"deviceDisconnected", "(Ljava/lang/String;)V", + &method_volumeDeviceDisconnected}, + {"setVolume", "(I)V", &method_setVolume}, + {"listPlayerSettingsRequest", "()V", &method_listPlayerSettings}, + {"listPlayerSettingValuesRequest", "(B)V", + &method_listPlayerSettingValues}, + {"getCurrentPlayerSettingValuesRequest", "([B)V", + &method_getPlayerSettings}, + {"setPlayerSettingsRequest", "([B[B)V", &method_setPlayerSettings}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/avrcp/AvrcpNativeInterface", + javaMethods); + + return 0; } } // namespace android diff --git a/android/app/jni/com_android_bluetooth_btservice_ActivityAttribution.cpp b/android/app/jni/com_android_bluetooth_btservice_ActivityAttribution.cpp deleted file mode 100644 index 4e0247dcccd6591b368e2f0e356d15f03087fe4a..0000000000000000000000000000000000000000 --- a/android/app/jni/com_android_bluetooth_btservice_ActivityAttribution.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "BluetoothActivityAttributionJni" - -#include - -#include - -#include "base/logging.h" -#include "com_android_bluetooth.h" -#include "hardware/bt_activity_attribution.h" - -using bluetooth::activity_attribution::ActivityAttributionCallbacks; -using bluetooth::activity_attribution::ActivityAttributionInterface; - -namespace android { -static jmethodID method_onWakeup; -static jmethodID method_onActivityLogsReady; - -static ActivityAttributionInterface* sActivityAttributionInterface = nullptr; -static std::shared_timed_mutex interface_mutex; - -static jobject mCallbacksObj = nullptr; -static std::shared_timed_mutex callbacks_mutex; - -class ActivityAttributionCallbacksImpl : public ActivityAttributionCallbacks { - public: - ~ActivityAttributionCallbacksImpl() = default; - - void OnWakeup(const Activity activity, const RawAddress& bd_addr) override { - LOG(INFO) << __func__; - - std::shared_lock lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - ScopedLocalRef addr( - sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); - if (!addr.get()) { - LOG(ERROR) - << "Failed to allocate jbyteArray for bd_addr of wakeup callback"; - return; - } - - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), - (jbyte*)&bd_addr); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWakeup, (jint)activity, - addr.get()); - } - - void OnActivityLogsReady( - const std::vector logs) override { - LOG(INFO) << __func__; - - std::shared_lock lock(callbacks_mutex); - CallbackEnv sCallbackEnv(__func__); - if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; - - jsize logs_size = logs.size() * sizeof(BtaaAggregationEntry); - ScopedLocalRef addr(sCallbackEnv.get(), - sCallbackEnv->NewByteArray(logs_size)); - if (!addr.get()) { - LOG(ERROR) << "Failed to allocate jbyteArray for logs from activity " - "logging callback"; - return; - } - - sCallbackEnv->SetByteArrayRegion(addr.get(), 0, logs_size, - (jbyte*)logs.data()); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onActivityLogsReady, - addr.get()); - } -}; - -static ActivityAttributionCallbacksImpl sActivityAttributionCallbacks; - -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onWakeup = env->GetMethodID(clazz, "onWakeup", "(I[B)V"); - method_onActivityLogsReady = - env->GetMethodID(clazz, "onActivityLogsReady", "([B)V"); - - LOG(INFO) << __func__ << ": succeeds"; -} - -static void initNative(JNIEnv* env, jobject object) { - std::unique_lock interface_lock(interface_mutex); - std::unique_lock callbacks_lock(callbacks_mutex); - const bt_interface_t* btInf = getBluetoothInterface(); - if (btInf == nullptr) { - LOG(ERROR) << "Bluetooth module is not loaded"; - return; - } - - if (sActivityAttributionInterface != nullptr) { - LOG(INFO) - << "Cleaning up ActivityAttribution Interface before initializing..."; - sActivityAttributionInterface->Cleanup(); - sActivityAttributionInterface = nullptr; - } - - if (mCallbacksObj != nullptr) { - LOG(INFO) << "Cleaning up ActivityAttribution callback object"; - env->DeleteGlobalRef(mCallbacksObj); - mCallbacksObj = nullptr; - } - - if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) { - LOG(ERROR) - << "Failed to allocate Global Ref for ActivityAttribution Callbacks"; - return; - } - - sActivityAttributionInterface = - (ActivityAttributionInterface*)btInf->get_profile_interface( - BT_ACTIVITY_ATTRIBUTION_ID); - if (sActivityAttributionInterface == nullptr) { - LOG(ERROR) << "Failed to get ActivityAttribution Interface"; - return; - } - - sActivityAttributionInterface->RegisterCallbacks( - &sActivityAttributionCallbacks); -} - -static void cleanupNative(JNIEnv* env, jobject object) { - std::unique_lock interface_lock(interface_mutex); - std::unique_lock callbacks_lock(callbacks_mutex); - - const bt_interface_t* btInf = getBluetoothInterface(); - if (btInf == nullptr) { - LOG(ERROR) << "Bluetooth module is not loaded"; - return; - } - - if (sActivityAttributionInterface != nullptr) { - sActivityAttributionInterface->Cleanup(); - sActivityAttributionInterface = nullptr; - } - - if (mCallbacksObj != nullptr) { - env->DeleteGlobalRef(mCallbacksObj); - mCallbacksObj = nullptr; - } -} - -static void notifyActivityAttributionInfoNative(JNIEnv* env, jobject object, - jint uid, jstring packageName, - jstring deviceAddress) { - const bt_interface_t* btInf = getBluetoothInterface(); - if (btInf == nullptr) { - LOG(ERROR) << "Bluetooth module is not loaded"; - return; - } - sActivityAttributionInterface = - (ActivityAttributionInterface*)btInf->get_profile_interface( - BT_ACTIVITY_ATTRIBUTION_ID); - if (sActivityAttributionInterface == nullptr) { - LOG(ERROR) << "Failed to get ActivityAttribution Interface"; - return; - } - - if (packageName == nullptr || deviceAddress == nullptr) { - LOG(ERROR) << "Failed to get package name or device address"; - return; - } - const char* nativeName = env->GetStringUTFChars(packageName, nullptr); - const char* nativeAddress = env->GetStringUTFChars(deviceAddress, nullptr); - sActivityAttributionInterface->NotifyActivityAttributionInfo(uid, nativeName, - nativeAddress); - env->ReleaseStringUTFChars(packageName, nativeName); - env->ReleaseStringUTFChars(deviceAddress, nativeAddress); -} - -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"notifyActivityAttributionInfoNative", - "(ILjava/lang/String;Ljava/lang/String;)V", - (void*)notifyActivityAttributionInfoNative}, -}; - -int register_com_android_bluetooth_btservice_activity_attribution(JNIEnv* env) { - return jniRegisterNativeMethods( - env, - "com/android/bluetooth/btservice/activityattribution/" - "ActivityAttributionNativeInterface", - sMethods, NELEM(sMethods)); -} - -} // namespace android diff --git a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp index 186c3457b1d07708e89173072d8dfdfbfb46ff0f..e3b197afc2bb2552b4ab348da5fc9959290a86de 100644 --- a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +++ b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp @@ -66,7 +66,6 @@ static jmethodID method_discoveryStateChangeCallback; static jmethodID method_linkQualityReportCallback; static jmethodID method_switchBufferSizeCallback; static jmethodID method_switchCodecCallback; -static jmethodID method_setWakeAlarm; static jmethodID method_acquireWakeLock; static jmethodID method_releaseWakeLock; static jmethodID method_energyInfo; @@ -401,7 +400,7 @@ static void acl_state_changed_callback(bt_status_t status, RawAddress* bd_addr, bt_acl_state_t state, int transport_link_type, bt_hci_error_code_t hci_reason, - bt_conn_direction_t direction, + bt_conn_direction_t /* direction */, uint16_t acl_handle) { if (!bd_addr) { ALOGE("Address is null in %s", __func__); @@ -532,8 +531,21 @@ static void ssp_request_callback(RawAddress* bd_addr, bt_bdname_t* bdname, static jobject createClassicOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { ALOGV("%s", __func__); - jclass classicBuilderClass = - env->FindClass("android/bluetooth/OobData$ClassicBuilder"); + jmethodID classicBuilderConstructor; + jmethodID setRMethod; + jmethodID setNameMethod; + jmethodID buildMethod; + + const JNIJavaMethod javaMethods[] = { + {"", "([B[B[B)V", &classicBuilderConstructor}, + {"setRandomizerHash", "([B)Landroid/bluetooth/OobData$ClassicBuilder;", + &setRMethod}, + {"setDeviceName", "([B)Landroid/bluetooth/OobData$ClassicBuilder;", + &setNameMethod}, + {"build", "()Landroid/bluetooth/OobData;", &buildMethod}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/OobData$ClassicBuilder", + javaMethods); jbyteArray confirmationHash = env->NewByteArray(OOB_C_SIZE); env->SetByteArrayRegion(confirmationHash, 0, OOB_C_SIZE, @@ -547,16 +559,15 @@ static jobject createClassicOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { env->SetByteArrayRegion(address, 0, OOB_ADDRESS_SIZE, reinterpret_cast(oob_data.address)); - jmethodID classicBuilderConstructor = - env->GetMethodID(classicBuilderClass, "", "([B[B[B)V"); + jclass classicBuilderClass = + env->FindClass("android/bluetooth/OobData$ClassicBuilder"); jobject oobDataClassicBuilder = env->NewObject(classicBuilderClass, classicBuilderConstructor, confirmationHash, oobDataLength, address); - jmethodID setRMethod = - env->GetMethodID(classicBuilderClass, "setRandomizerHash", - "([B)Landroid/bluetooth/OobData$ClassicBuilder;"); + env->DeleteLocalRef(classicBuilderClass); + jbyteArray randomizerHash = env->NewByteArray(OOB_R_SIZE); env->SetByteArrayRegion(randomizerHash, 0, OOB_R_SIZE, reinterpret_cast(oob_data.r)); @@ -564,10 +575,6 @@ static jobject createClassicOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { oobDataClassicBuilder = env->CallObjectMethod(oobDataClassicBuilder, setRMethod, randomizerHash); - jmethodID setNameMethod = - env->GetMethodID(classicBuilderClass, "setDeviceName", - "([B)Landroid/bluetooth/OobData$ClassicBuilder;"); - int name_char_count = 0; for (int i = 0; i < OOB_NAME_MAX_SIZE; i++) { if (oob_data.device_name[i] == 0) { @@ -583,16 +590,26 @@ static jobject createClassicOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { oobDataClassicBuilder = env->CallObjectMethod(oobDataClassicBuilder, setNameMethod, deviceName); - jmethodID buildMethod = env->GetMethodID(classicBuilderClass, "build", - "()Landroid/bluetooth/OobData;"); - return env->CallObjectMethod(oobDataClassicBuilder, buildMethod); } static jobject createLeOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { ALOGV("%s", __func__); - jclass leBuilderClass = env->FindClass("android/bluetooth/OobData$LeBuilder"); + jmethodID leBuilderConstructor; + jmethodID setRMethod; + jmethodID setNameMethod; + jmethodID buildMethod; + + const JNIJavaMethod javaMethods[] = { + {"", "([B[BI)V", &leBuilderConstructor}, + {"setRandomizerHash", "([B)Landroid/bluetooth/OobData$LeBuilder;", + &setRMethod}, + {"setDeviceName", "([B)Landroid/bluetooth/OobData$LeBuilder;", + &setNameMethod}, + {"build", "()Landroid/bluetooth/OobData;", &buildMethod}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/OobData$LeBuilder", javaMethods); jbyteArray confirmationHash = env->NewByteArray(OOB_C_SIZE); env->SetByteArrayRegion(confirmationHash, 0, OOB_C_SIZE, @@ -604,15 +621,13 @@ static jobject createLeOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { jint le_role = (jint)oob_data.le_device_role; - jmethodID leBuilderConstructor = - env->GetMethodID(leBuilderClass, "", "([B[BI)V"); + jclass leBuilderClass = env->FindClass("android/bluetooth/OobData$LeBuilder"); jobject oobDataLeBuilder = env->NewObject( leBuilderClass, leBuilderConstructor, confirmationHash, address, le_role); - jmethodID setRMethod = - env->GetMethodID(leBuilderClass, "setRandomizerHash", - "([B)Landroid/bluetooth/OobData$LeBuilder;"); + env->DeleteLocalRef(leBuilderClass); + jbyteArray randomizerHash = env->NewByteArray(OOB_R_SIZE); env->SetByteArrayRegion(randomizerHash, 0, OOB_R_SIZE, reinterpret_cast(oob_data.r)); @@ -620,10 +635,6 @@ static jobject createLeOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { oobDataLeBuilder = env->CallObjectMethod(oobDataLeBuilder, setRMethod, randomizerHash); - jmethodID setNameMethod = - env->GetMethodID(leBuilderClass, "setDeviceName", - "([B)Landroid/bluetooth/OobData$LeBuilder;"); - int name_char_count = 0; for (int i = 0; i < OOB_NAME_MAX_SIZE; i++) { if (oob_data.device_name[i] == 0) { @@ -639,9 +650,6 @@ static jobject createLeOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { oobDataLeBuilder = env->CallObjectMethod(oobDataLeBuilder, setNameMethod, deviceName); - jmethodID buildMethod = env->GetMethodID(leBuilderClass, "build", - "()Landroid/bluetooth/OobData;"); - return env->CallObjectMethod(oobDataLeBuilder, buildMethod); } @@ -740,7 +748,7 @@ static void switch_codec_callback(bool is_low_latency_buffer_size) { (jboolean)is_low_latency_buffer_size); } -static void le_rand_callback(uint64_t random) { +static void le_rand_callback(uint64_t /* random */) { // Android doesn't support the LeRand API. } @@ -766,6 +774,14 @@ static void callback_thread_event(bt_cb_thread_evt event) { } } +static void dut_mode_recv_callback(uint16_t /* opcode */, uint8_t* /* buf */, + uint8_t /* len */) {} + +static void le_test_mode_recv_callback(bt_status_t status, + uint16_t packet_count) { + ALOGV("%s: status:%d packet_count:%d ", __func__, status, packet_count); +} + static void energy_info_recv_callback(bt_activity_energy_info* p_energy_info, bt_uid_traffic_t* uid_data) { std::shared_lock lock(jniObjMutex); @@ -797,7 +813,7 @@ static void energy_info_recv_callback(bt_activity_energy_info* p_energy_info, } sCallbackEnv->CallVoidMethod( - sJniAdapterServiceObj, method_energyInfo, p_energy_info->status, + sJniCallbacksObj, method_energyInfo, p_energy_info->status, p_energy_info->ctrl_state, p_energy_info->tx_time, p_energy_info->rx_time, p_energy_info->idle_time, p_energy_info->energy_used, array.get()); } @@ -815,6 +831,8 @@ static bt_callbacks_t sBluetoothCallbacks = {sizeof(sBluetoothCallbacks), le_address_associate_callback, acl_state_changed_callback, callback_thread_event, + dut_mode_recv_callback, + le_test_mode_recv_callback, energy_info_recv_callback, link_quality_report_callback, generate_local_oob_data_callback, @@ -822,12 +840,6 @@ static bt_callbacks_t sBluetoothCallbacks = {sizeof(sBluetoothCallbacks), switch_codec_callback, le_rand_callback}; -// The callback to call when the wake alarm fires. -static alarm_cb sAlarmCallback; - -// The data to pass to the wake alarm callback. -static void* sAlarmCallbackData; - class JNIThreadAttacher { public: JNIThreadAttacher(JavaVM* vm) : vm_(vm), env_(nullptr) { @@ -874,37 +886,6 @@ class JNIThreadAttacher { jint status_; }; -static bool set_wake_alarm_callout(uint64_t delay_millis, bool should_wake, - alarm_cb cb, void* data) { - std::shared_lock lock(jniObjMutex); - if (!sJniAdapterServiceObj) { - ALOGE("%s, JNI obj is null. Failed to call JNI callback", __func__); - return false; - } - - JNIThreadAttacher attacher(vm); - JNIEnv* env = attacher.getEnv(); - - if (env == nullptr) { - ALOGE("%s: Unable to get JNI Env", __func__); - return false; - } - - sAlarmCallback = cb; - sAlarmCallbackData = data; - - jboolean jshould_wake = should_wake ? JNI_TRUE : JNI_FALSE; - jboolean ret = - env->CallBooleanMethod(sJniAdapterServiceObj, method_setWakeAlarm, - (jlong)delay_millis, jshould_wake); - if (!ret) { - sAlarmCallback = NULL; - sAlarmCallbackData = NULL; - } - - return (ret == JNI_TRUE); -} - static int acquire_wake_lock_callout(const char* lock_name) { std::shared_lock lock(jniObjMutex); if (!sJniAdapterServiceObj) { @@ -925,7 +906,7 @@ static int acquire_wake_lock_callout(const char* lock_name) { ScopedLocalRef lock_name_jni(env, env->NewStringUTF(lock_name)); if (lock_name_jni.get()) { bool acquired = env->CallBooleanMethod( - sJniAdapterServiceObj, method_acquireWakeLock, lock_name_jni.get()); + sJniCallbacksObj, method_acquireWakeLock, lock_name_jni.get()); if (!acquired) ret = BT_STATUS_WAKELOCK_ERROR; } else { ALOGE("%s unable to allocate string: %s", __func__, lock_name); @@ -956,7 +937,7 @@ static int release_wake_lock_callout(const char* lock_name) { ScopedLocalRef lock_name_jni(env, env->NewStringUTF(lock_name)); if (lock_name_jni.get()) { bool released = env->CallBooleanMethod( - sJniAdapterServiceObj, method_releaseWakeLock, lock_name_jni.get()); + sJniCallbacksObj, method_releaseWakeLock, lock_name_jni.get()); if (!released) ret = BT_STATUS_WAKELOCK_ERROR; } else { ALOGE("%s unable to allocate string: %s", __func__, lock_name); @@ -967,19 +948,10 @@ static int release_wake_lock_callout(const char* lock_name) { return ret; } -// Called by Java code when alarm is fired. A wake lock is held by the caller -// over the duration of this callback. -static void alarmFiredNative(JNIEnv* env, jobject obj) { - if (sAlarmCallback) { - sAlarmCallback(sAlarmCallbackData); - } else { - ALOGE("%s() - Alarm fired with callback not set!", __func__); - } -} - static bt_os_callouts_t sBluetoothOsCallouts = { - sizeof(sBluetoothOsCallouts), set_wake_alarm_callout, - acquire_wake_lock_callout, release_wake_lock_callout, + sizeof(sBluetoothOsCallouts), + acquire_wake_lock_callout, + release_wake_lock_callout, }; int hal_util_load_bt_library(const bt_interface_t** interface) { @@ -1019,75 +991,6 @@ error: #endif } -static void classInitNative(JNIEnv* env, jclass clazz) { - jclass jniUidTrafficClass = env->FindClass("android/bluetooth/UidTraffic"); - android_bluetooth_UidTraffic.constructor = - env->GetMethodID(jniUidTrafficClass, "", "(IJJ)V"); - - jclass jniCallbackClass = - env->FindClass("com/android/bluetooth/btservice/JniCallbacks"); - sJniCallbacksField = env->GetFieldID( - clazz, "mJniCallbacks", "Lcom/android/bluetooth/btservice/JniCallbacks;"); - - method_oobDataReceivedCallback = - env->GetMethodID(jniCallbackClass, "oobDataReceivedCallback", - "(ILandroid/bluetooth/OobData;)V"); - - method_stateChangeCallback = - env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V"); - - method_adapterPropertyChangedCallback = env->GetMethodID( - jniCallbackClass, "adapterPropertyChangedCallback", "([I[[B)V"); - method_discoveryStateChangeCallback = env->GetMethodID( - jniCallbackClass, "discoveryStateChangeCallback", "(I)V"); - - method_devicePropertyChangedCallback = env->GetMethodID( - jniCallbackClass, "devicePropertyChangedCallback", "([B[I[[B)V"); - method_deviceFoundCallback = - env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V"); - method_pinRequestCallback = - env->GetMethodID(jniCallbackClass, "pinRequestCallback", "([B[BIZ)V"); - method_sspRequestCallback = - env->GetMethodID(jniCallbackClass, "sspRequestCallback", "([B[BIII)V"); - - method_bondStateChangeCallback = - env->GetMethodID(jniCallbackClass, "bondStateChangeCallback", "(I[BII)V"); - - method_addressConsolidateCallback = env->GetMethodID( - jniCallbackClass, "addressConsolidateCallback", "([B[B)V"); - - method_leAddressAssociateCallback = env->GetMethodID( - jniCallbackClass, "leAddressAssociateCallback", "([B[B)V"); - - method_aclStateChangeCallback = env->GetMethodID( - jniCallbackClass, "aclStateChangeCallback", "(I[BIIII)V"); - - method_linkQualityReportCallback = env->GetMethodID( - jniCallbackClass, "linkQualityReportCallback", "(JIIIIII)V"); - - method_switchBufferSizeCallback = - env->GetMethodID(jniCallbackClass, "switchBufferSizeCallback", "(Z)V"); - - method_switchCodecCallback = - env->GetMethodID(jniCallbackClass, "switchCodecCallback", "(Z)V"); - - method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z"); - method_acquireWakeLock = - env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z"); - method_releaseWakeLock = - env->GetMethodID(clazz, "releaseWakeLock", "(Ljava/lang/String;)Z"); - method_energyInfo = env->GetMethodID( - clazz, "energyInfoCallback", "(IIJJJJ[Landroid/bluetooth/UidTraffic;)V"); - - if (env->GetJavaVM(&vm) != JNI_OK) { - ALOGE("Could not get JavaVM"); - } - - if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) { - ALOGE("No Bluetooth Library found"); - } -} - static bool initNative(JNIEnv* env, jobject obj, jboolean isGuest, jboolean isCommonCriteriaMode, int configCompareResult, jobjectArray initFlags, jboolean isAtvDevice, @@ -1160,7 +1063,7 @@ static bool initNative(JNIEnv* env, jobject obj, jboolean isGuest, return JNI_TRUE; } -static bool cleanupNative(JNIEnv* env, jobject obj) { +static bool cleanupNative(JNIEnv* env, jobject /* obj */) { std::unique_lock lock(jniObjMutex); ALOGV("%s", __func__); @@ -1187,7 +1090,7 @@ static bool cleanupNative(JNIEnv* env, jobject obj) { return JNI_TRUE; } -static jboolean enableNative(JNIEnv* env, jobject obj) { +static jboolean enableNative(JNIEnv* /* env */, jobject /* obj */) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1196,7 +1099,7 @@ static jboolean enableNative(JNIEnv* env, jobject obj) { : JNI_FALSE; } -static jboolean disableNative(JNIEnv* env, jobject obj) { +static jboolean disableNative(JNIEnv* /* env */, jobject /* obj */) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1209,7 +1112,7 @@ static jboolean disableNative(JNIEnv* env, jobject obj) { return (ret == BT_STATUS_FAIL) ? JNI_FALSE : JNI_TRUE; } -static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) { +static jboolean startDiscoveryNative(JNIEnv* /* env */, jobject /* obj */) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1218,7 +1121,7 @@ static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) { return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean cancelDiscoveryNative(JNIEnv* env, jobject obj) { +static jboolean cancelDiscoveryNative(JNIEnv* /* env */, jobject /* obj */) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1227,8 +1130,9 @@ static jboolean cancelDiscoveryNative(JNIEnv* env, jobject obj) { return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address, - jint addrType, jint transport) { +static jboolean createBondNative(JNIEnv* env, jobject /* obj */, + jbyteArray address, jint addrType, + jint transport) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1260,6 +1164,7 @@ static jbyteArray callByteArrayGetter(JNIEnv* env, jobject object, const char* methodName) { jclass myClass = env->FindClass(className); jmethodID myMethod = env->GetMethodID(myClass, methodName, "()[B"); + env->DeleteLocalRef(myClass); return (jbyteArray)env->CallObjectMethod(object, myMethod); } @@ -1267,6 +1172,7 @@ static jint callIntGetter(JNIEnv* env, jobject object, const char* className, const char* methodName) { jclass myClass = env->FindClass(className); jmethodID myMethod = env->GetMethodID(myClass, methodName, "()I"); + env->DeleteLocalRef(myClass); return env->CallIntMethod(object, myMethod); } @@ -1450,7 +1356,7 @@ static jboolean set_data(JNIEnv* env, bt_oob_data_t& oob_data, jobject oobData, return JNI_TRUE; } -static void generateLocalOobDataNative(JNIEnv* env, jobject obj, +static void generateLocalOobDataNative(JNIEnv* /* env */, jobject /* obj */, jint transport) { // No BT interface? Can't do anything. if (!sBluetoothInterface) return; @@ -1464,7 +1370,7 @@ static void generateLocalOobDataNative(JNIEnv* env, jobject obj, } } -static jboolean createBondOutOfBandNative(JNIEnv* env, jobject obj, +static jboolean createBondOutOfBandNative(JNIEnv* env, jobject /* obj */, jbyteArray address, jint transport, jobject p192Data, jobject p256Data) { // No BT interface? Can't do anything. @@ -1526,7 +1432,8 @@ static jboolean createBondOutOfBandNative(JNIEnv* env, jobject obj, : JNI_FALSE; } -static jboolean removeBondNative(JNIEnv* env, jobject obj, jbyteArray address) { +static jboolean removeBondNative(JNIEnv* env, jobject /* obj */, + jbyteArray address) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1543,7 +1450,8 @@ static jboolean removeBondNative(JNIEnv* env, jobject obj, jbyteArray address) { return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean cancelBondNative(JNIEnv* env, jobject obj, jbyteArray address) { +static jboolean cancelBondNative(JNIEnv* env, jobject /* obj */, + jbyteArray address) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1559,7 +1467,7 @@ static jboolean cancelBondNative(JNIEnv* env, jobject obj, jbyteArray address) { return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static int getConnectionStateNative(JNIEnv* env, jobject obj, +static int getConnectionStateNative(JNIEnv* env, jobject /* obj */, jbyteArray address) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1576,8 +1484,9 @@ static int getConnectionStateNative(JNIEnv* env, jobject obj, return ret; } -static jboolean pinReplyNative(JNIEnv* env, jobject obj, jbyteArray address, - jboolean accept, jint len, jbyteArray pinArray) { +static jboolean pinReplyNative(JNIEnv* env, jobject /* obj */, + jbyteArray address, jboolean accept, jint len, + jbyteArray pinArray) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1606,8 +1515,9 @@ static jboolean pinReplyNative(JNIEnv* env, jobject obj, jbyteArray address, return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean sspReplyNative(JNIEnv* env, jobject obj, jbyteArray address, - jint type, jboolean accept, jint passkey) { +static jboolean sspReplyNative(JNIEnv* env, jobject /* obj */, + jbyteArray address, jint type, jboolean accept, + jint passkey) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1625,8 +1535,8 @@ static jboolean sspReplyNative(JNIEnv* env, jobject obj, jbyteArray address, return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean setAdapterPropertyNative(JNIEnv* env, jobject obj, jint type, - jbyteArray value) { +static jboolean setAdapterPropertyNative(JNIEnv* env, jobject /* obj */, + jint type, jbyteArray value) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1643,7 +1553,8 @@ static jboolean setAdapterPropertyNative(JNIEnv* env, jobject obj, jint type, return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean getAdapterPropertiesNative(JNIEnv* env, jobject obj) { +static jboolean getAdapterPropertiesNative(JNIEnv* /* env */, + jobject /* obj */) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1652,7 +1563,8 @@ static jboolean getAdapterPropertiesNative(JNIEnv* env, jobject obj) { return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean getAdapterPropertyNative(JNIEnv* env, jobject obj, jint type) { +static jboolean getAdapterPropertyNative(JNIEnv* /* env */, jobject /* obj */, + jint type) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1661,7 +1573,7 @@ static jboolean getAdapterPropertyNative(JNIEnv* env, jobject obj, jint type) { return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean getDevicePropertyNative(JNIEnv* env, jobject obj, +static jboolean getDevicePropertyNative(JNIEnv* env, jobject /* obj */, jbyteArray address, jint type) { ALOGV("%s", __func__); @@ -1679,7 +1591,7 @@ static jboolean getDevicePropertyNative(JNIEnv* env, jobject obj, return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean setDevicePropertyNative(JNIEnv* env, jobject obj, +static jboolean setDevicePropertyNative(JNIEnv* env, jobject /* obj */, jbyteArray address, jint type, jbyteArray value) { ALOGV("%s", __func__); @@ -1712,7 +1624,7 @@ static jboolean setDevicePropertyNative(JNIEnv* env, jobject obj, return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean getRemoteServicesNative(JNIEnv* env, jobject obj, +static jboolean getRemoteServicesNative(JNIEnv* env, jobject /* obj */, jbyteArray address, jint transport) { ALOGV("%s", __func__); @@ -1730,7 +1642,7 @@ static jboolean getRemoteServicesNative(JNIEnv* env, jobject obj, return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static int readEnergyInfo() { +static int readEnergyInfoNative() { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1738,7 +1650,7 @@ static int readEnergyInfo() { return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static void dumpNative(JNIEnv* env, jobject obj, jobject fdObj, +static void dumpNative(JNIEnv* env, jobject /* obj */, jobject fdObj, jobjectArray argArray) { ALOGV("%s", __func__); if (!sBluetoothInterface) return; @@ -1770,7 +1682,7 @@ static void dumpNative(JNIEnv* env, jobject obj, jobject fdObj, delete[] argObjs; } -static jbyteArray dumpMetricsNative(JNIEnv* env, jobject obj) { +static jbyteArray dumpMetricsNative(JNIEnv* env, jobject /* obj */) { ALOGI("%s", __func__); if (!sBluetoothInterface) return env->NewByteArray(0); @@ -1783,14 +1695,14 @@ static jbyteArray dumpMetricsNative(JNIEnv* env, jobject obj) { return output_bytes; } -static jboolean factoryResetNative(JNIEnv* env, jobject obj) { +static jboolean factoryResetNative(JNIEnv* /* env */, jobject /* obj */) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; int ret = sBluetoothInterface->config_clear(); return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jbyteArray obfuscateAddressNative(JNIEnv* env, jobject obj, +static jbyteArray obfuscateAddressNative(JNIEnv* env, jobject /* obj */, jbyteArray address) { ALOGV("%s", __func__); if (!sBluetoothInterface) return env->NewByteArray(0); @@ -1809,8 +1721,9 @@ static jbyteArray obfuscateAddressNative(JNIEnv* env, jobject obj, return output_bytes; } -static jboolean setBufferLengthMillisNative(JNIEnv* env, jobject obj, - jint codec, jint size) { +static jboolean setBufferLengthMillisNative(JNIEnv* /* env */, + jobject /* obj */, jint codec, + jint size) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -1819,9 +1732,9 @@ static jboolean setBufferLengthMillisNative(JNIEnv* env, jobject obj, return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jint connectSocketNative(JNIEnv* env, jobject obj, jbyteArray address, - jint type, jbyteArray uuid, jint port, - jint flag, jint callingUid) { +static jint connectSocketNative(JNIEnv* env, jobject /* obj */, + jbyteArray address, jint type, jbyteArray uuid, + jint port, jint flag, jint callingUid) { int socket_fd = INVALID_FD; jbyte* addr = nullptr; jbyte* uuidBytes = nullptr; @@ -1850,7 +1763,7 @@ done: return socket_fd; } -static jint createSocketChannelNative(JNIEnv* env, jobject obj, jint type, +static jint createSocketChannelNative(JNIEnv* env, jobject /* obj */, jint type, jstring serviceName, jbyteArray uuid, jint port, jint flag, jint callingUid) { int socket_fd = INVALID_FD; @@ -1884,7 +1797,7 @@ done: return socket_fd; } -static void requestMaximumTxDataLengthNative(JNIEnv* env, jobject obj, +static void requestMaximumTxDataLengthNative(JNIEnv* env, jobject /* obj */, jbyteArray address) { if (!sBluetoothSocketInterface) { return; @@ -1900,7 +1813,8 @@ static void requestMaximumTxDataLengthNative(JNIEnv* env, jobject obj, env->ReleaseByteArrayElements(address, addr, 1); } -static int getMetricIdNative(JNIEnv* env, jobject obj, jbyteArray address) { +static int getMetricIdNative(JNIEnv* env, jobject /* obj */, + jbyteArray address) { ALOGV("%s", __func__); if (!sBluetoothInterface) return 0; // 0 is invalid id jbyte* addr = env->GetByteArrayElements(address, nullptr); @@ -1913,7 +1827,7 @@ static int getMetricIdNative(JNIEnv* env, jobject obj, jbyteArray address) { return sBluetoothInterface->get_metric_id(addr_obj); } -static jboolean allowLowLatencyAudioNative(JNIEnv* env, jobject obj, +static jboolean allowLowLatencyAudioNative(JNIEnv* env, jobject /* obj */, jboolean allowed, jbyteArray address) { ALOGV("%s", __func__); @@ -1930,8 +1844,9 @@ static jboolean allowLowLatencyAudioNative(JNIEnv* env, jobject obj, return true; } -static void metadataChangedNative(JNIEnv* env, jobject obj, jbyteArray address, - jint key, jbyteArray value) { +static void metadataChangedNative(JNIEnv* env, jobject /* obj */, + jbyteArray address, jint key, + jbyteArray value) { ALOGV("%s", __func__); if (!sBluetoothInterface) return; jbyte* addr = env->GetByteArrayElements(address, nullptr); @@ -1959,12 +1874,13 @@ static void metadataChangedNative(JNIEnv* env, jobject obj, jbyteArray address, return; } -static jboolean isLogRedactionEnabled(JNIEnv* env, jobject obj) { +static jboolean isLogRedactionEnabledNative(JNIEnv* /* env */, + jobject /* obj */) { ALOGV("%s", __func__); return bluetooth::os::should_log_be_redacted(); } -static jboolean interopMatchAddrNative(JNIEnv* env, jclass clazz, +static jboolean interopMatchAddrNative(JNIEnv* env, jclass /* clazz */, jstring feature_name, jstring address) { ALOGV("%s", __func__); @@ -2001,7 +1917,7 @@ static jboolean interopMatchAddrNative(JNIEnv* env, jclass clazz, return matched ? JNI_TRUE : JNI_FALSE; } -static jboolean interopMatchNameNative(JNIEnv* env, jclass clazz, +static jboolean interopMatchNameNative(JNIEnv* env, jclass /* clazz */, jstring feature_name, jstring name) { ALOGV("%s", __func__); @@ -2031,7 +1947,7 @@ static jboolean interopMatchNameNative(JNIEnv* env, jclass clazz, return matched ? JNI_TRUE : JNI_FALSE; } -static jboolean interopMatchAddrOrNameNative(JNIEnv* env, jclass clazz, +static jboolean interopMatchAddrOrNameNative(JNIEnv* env, jclass /* clazz */, jstring feature_name, jstring address) { ALOGV("%s", __func__); @@ -2069,7 +1985,7 @@ static jboolean interopMatchAddrOrNameNative(JNIEnv* env, jclass clazz, return matched ? JNI_TRUE : JNI_FALSE; } -static void interopDatabaseAddRemoveAddrNative(JNIEnv* env, jclass clazz, +static void interopDatabaseAddRemoveAddrNative(JNIEnv* env, jclass /* clazz */, jboolean do_add, jstring feature_name, jstring address, jint length) { @@ -2113,7 +2029,7 @@ static void interopDatabaseAddRemoveAddrNative(JNIEnv* env, jclass clazz, env->ReleaseStringUTFChars(feature_name, feature_name_str); } -static void interopDatabaseAddRemoveNameNative(JNIEnv* env, jclass clazz, +static void interopDatabaseAddRemoveNameNative(JNIEnv* env, jclass /* clazz */, jboolean do_add, jstring feature_name, jstring name) { @@ -2144,7 +2060,7 @@ static void interopDatabaseAddRemoveNameNative(JNIEnv* env, jclass clazz, env->ReleaseStringUTFChars(name, name_str); } -static int getRemotePbapPceVersionNative(JNIEnv* env, jobject obj, +static int getRemotePbapPceVersionNative(JNIEnv* env, jobject /* obj */, jstring address) { ALOGV("%s", __func__); @@ -2169,8 +2085,8 @@ static int getRemotePbapPceVersionNative(JNIEnv* env, jobject obj, return sBluetoothInterface->get_remote_pbap_pce_version(&bdaddr); } -static jboolean pbapPseDynamicVersionUpgradeIsEnabledNative(JNIEnv* env, - jobject obj) { +static jboolean pbapPseDynamicVersionUpgradeIsEnabledNative(JNIEnv* /* env */, + jobject /* obj */) { ALOGV("%s", __func__); if (!sBluetoothInterface) return JNI_FALSE; @@ -2180,72 +2096,126 @@ static jboolean pbapPseDynamicVersionUpgradeIsEnabledNative(JNIEnv* env, : JNI_FALSE; } -static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "(ZZI[Ljava/lang/String;ZLjava/lang/String;)Z", - (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"enableNative", "()Z", (void*)enableNative}, - {"disableNative", "()Z", (void*)disableNative}, - {"setAdapterPropertyNative", "(I[B)Z", (void*)setAdapterPropertyNative}, - {"getAdapterPropertiesNative", "()Z", (void*)getAdapterPropertiesNative}, - {"getAdapterPropertyNative", "(I)Z", (void*)getAdapterPropertyNative}, - {"getDevicePropertyNative", "([BI)Z", (void*)getDevicePropertyNative}, - {"setDevicePropertyNative", "([BI[B)Z", (void*)setDevicePropertyNative}, - {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative}, - {"cancelDiscoveryNative", "()Z", (void*)cancelDiscoveryNative}, - {"createBondNative", "([BII)Z", (void*)createBondNative}, - {"createBondOutOfBandNative", - "([BILandroid/bluetooth/OobData;Landroid/bluetooth/OobData;)Z", - (void*)createBondOutOfBandNative}, - {"removeBondNative", "([B)Z", (void*)removeBondNative}, - {"cancelBondNative", "([B)Z", (void*)cancelBondNative}, - {"generateLocalOobDataNative", "(I)V", (void*)generateLocalOobDataNative}, - {"getConnectionStateNative", "([B)I", (void*)getConnectionStateNative}, - {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative}, - {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative}, - {"getRemoteServicesNative", "([BI)Z", (void*)getRemoteServicesNative}, - {"alarmFiredNative", "()V", (void*)alarmFiredNative}, - {"readEnergyInfo", "()I", (void*)readEnergyInfo}, - {"dumpNative", "(Ljava/io/FileDescriptor;[Ljava/lang/String;)V", - (void*)dumpNative}, - {"dumpMetricsNative", "()[B", (void*)dumpMetricsNative}, - {"factoryResetNative", "()Z", (void*)factoryResetNative}, - {"obfuscateAddressNative", "([B)[B", (void*)obfuscateAddressNative}, - {"setBufferLengthMillisNative", "(II)Z", - (void*)setBufferLengthMillisNative}, - {"getMetricIdNative", "([B)I", (void*)getMetricIdNative}, - {"connectSocketNative", "([BI[BIII)I", (void*)connectSocketNative}, - {"createSocketChannelNative", "(ILjava/lang/String;[BIII)I", - (void*)createSocketChannelNative}, - {"requestMaximumTxDataLengthNative", "([B)V", - (void*)requestMaximumTxDataLengthNative}, - {"allowLowLatencyAudioNative", "(Z[B)Z", (void*)allowLowLatencyAudioNative}, - {"metadataChangedNative", "([BI[B)V", (void*)metadataChangedNative}, - {"isLogRedactionEnabled", "()Z", (void*)isLogRedactionEnabled}, - {"interopMatchAddrNative", "(Ljava/lang/String;Ljava/lang/String;)Z", - (void*)interopMatchAddrNative}, - {"interopMatchNameNative", "(Ljava/lang/String;Ljava/lang/String;)Z", - (void*)interopMatchNameNative}, - {"interopMatchAddrOrNameNative", "(Ljava/lang/String;Ljava/lang/String;)Z", - (void*)interopMatchAddrOrNameNative}, - {"interopDatabaseAddRemoveAddrNative", - "(ZLjava/lang/String;Ljava/lang/String;I)V", - (void*)interopDatabaseAddRemoveAddrNative}, - {"interopDatabaseAddRemoveNameNative", - "(ZLjava/lang/String;Ljava/lang/String;)V", - (void*)interopDatabaseAddRemoveNameNative}, - {"getRemotePbapPceVersionNative", "(Ljava/lang/String;)I", - (void*)getRemotePbapPceVersionNative}, - {"pbapPseDynamicVersionUpgradeIsEnabledNative", "()Z", - (void*)pbapPseDynamicVersionUpgradeIsEnabledNative}, -}; - int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/btservice/AdapterService", sMethods, - NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initNative", "(ZZI[Ljava/lang/String;ZLjava/lang/String;)Z", + (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"enableNative", "()Z", (void*)enableNative}, + {"disableNative", "()Z", (void*)disableNative}, + {"setAdapterPropertyNative", "(I[B)Z", (void*)setAdapterPropertyNative}, + {"getAdapterPropertiesNative", "()Z", (void*)getAdapterPropertiesNative}, + {"getAdapterPropertyNative", "(I)Z", (void*)getAdapterPropertyNative}, + {"getDevicePropertyNative", "([BI)Z", (void*)getDevicePropertyNative}, + {"setDevicePropertyNative", "([BI[B)Z", (void*)setDevicePropertyNative}, + {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative}, + {"cancelDiscoveryNative", "()Z", (void*)cancelDiscoveryNative}, + {"createBondNative", "([BII)Z", (void*)createBondNative}, + {"createBondOutOfBandNative", + "([BILandroid/bluetooth/OobData;Landroid/bluetooth/OobData;)Z", + (void*)createBondOutOfBandNative}, + {"removeBondNative", "([B)Z", (void*)removeBondNative}, + {"cancelBondNative", "([B)Z", (void*)cancelBondNative}, + {"generateLocalOobDataNative", "(I)V", (void*)generateLocalOobDataNative}, + {"getConnectionStateNative", "([B)I", (void*)getConnectionStateNative}, + {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative}, + {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative}, + {"getRemoteServicesNative", "([BI)Z", (void*)getRemoteServicesNative}, + {"readEnergyInfoNative", "()I", (void*)readEnergyInfoNative}, + {"dumpNative", "(Ljava/io/FileDescriptor;[Ljava/lang/String;)V", + (void*)dumpNative}, + {"dumpMetricsNative", "()[B", (void*)dumpMetricsNative}, + {"factoryResetNative", "()Z", (void*)factoryResetNative}, + {"obfuscateAddressNative", "([B)[B", (void*)obfuscateAddressNative}, + {"setBufferLengthMillisNative", "(II)Z", + (void*)setBufferLengthMillisNative}, + {"getMetricIdNative", "([B)I", (void*)getMetricIdNative}, + {"connectSocketNative", "([BI[BIII)I", (void*)connectSocketNative}, + {"createSocketChannelNative", "(ILjava/lang/String;[BIII)I", + (void*)createSocketChannelNative}, + {"requestMaximumTxDataLengthNative", "([B)V", + (void*)requestMaximumTxDataLengthNative}, + {"allowLowLatencyAudioNative", "(Z[B)Z", + (void*)allowLowLatencyAudioNative}, + {"metadataChangedNative", "([BI[B)V", (void*)metadataChangedNative}, + {"isLogRedactionEnabledNative", "()Z", + (void*)isLogRedactionEnabledNative}, + {"interopMatchAddrNative", "(Ljava/lang/String;Ljava/lang/String;)Z", + (void*)interopMatchAddrNative}, + {"interopMatchNameNative", "(Ljava/lang/String;Ljava/lang/String;)Z", + (void*)interopMatchNameNative}, + {"interopMatchAddrOrNameNative", + "(Ljava/lang/String;Ljava/lang/String;)Z", + (void*)interopMatchAddrOrNameNative}, + {"interopDatabaseAddRemoveAddrNative", + "(ZLjava/lang/String;Ljava/lang/String;I)V", + (void*)interopDatabaseAddRemoveAddrNative}, + {"interopDatabaseAddRemoveNameNative", + "(ZLjava/lang/String;Ljava/lang/String;)V", + (void*)interopDatabaseAddRemoveNameNative}, + {"getRemotePbapPceVersionNative", "(Ljava/lang/String;)I", + (void*)getRemotePbapPceVersionNative}, + {"pbapPseDynamicVersionUpgradeIsEnabledNative", "()Z", + (void*)pbapPseDynamicVersionUpgradeIsEnabledNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/btservice/AdapterNativeInterface", methods); + if (result != 0) { + return result; + } + + jclass jniAdapterNativeInterfaceClass = + env->FindClass("com/android/bluetooth/btservice/AdapterNativeInterface"); + sJniCallbacksField = + env->GetFieldID(jniAdapterNativeInterfaceClass, "mJniCallbacks", + "Lcom/android/bluetooth/btservice/JniCallbacks;"); + env->DeleteLocalRef(jniAdapterNativeInterfaceClass); + + const JNIJavaMethod javaMethods[] = { + {"oobDataReceivedCallback", "(ILandroid/bluetooth/OobData;)V", + &method_oobDataReceivedCallback}, + {"stateChangeCallback", "(I)V", &method_stateChangeCallback}, + {"adapterPropertyChangedCallback", "([I[[B)V", + &method_adapterPropertyChangedCallback}, + {"discoveryStateChangeCallback", "(I)V", + &method_discoveryStateChangeCallback}, + {"devicePropertyChangedCallback", "([B[I[[B)V", + &method_devicePropertyChangedCallback}, + {"deviceFoundCallback", "([B)V", &method_deviceFoundCallback}, + {"pinRequestCallback", "([B[BIZ)V", &method_pinRequestCallback}, + {"sspRequestCallback", "([B[BIII)V", &method_sspRequestCallback}, + {"bondStateChangeCallback", "(I[BII)V", &method_bondStateChangeCallback}, + {"addressConsolidateCallback", "([B[B)V", + &method_addressConsolidateCallback}, + {"leAddressAssociateCallback", "([B[B)V", + &method_leAddressAssociateCallback}, + {"aclStateChangeCallback", "(I[BIIII)V", &method_aclStateChangeCallback}, + {"linkQualityReportCallback", "(JIIIIII)V", + &method_linkQualityReportCallback}, + {"switchBufferSizeCallback", "(Z)V", &method_switchBufferSizeCallback}, + {"switchCodecCallback", "(Z)V", &method_switchCodecCallback}, + {"acquireWakeLock", "(Ljava/lang/String;)Z", &method_acquireWakeLock}, + {"releaseWakeLock", "(Ljava/lang/String;)Z", &method_releaseWakeLock}, + {"energyInfoCallback", "(IIJJJJ[Landroid/bluetooth/UidTraffic;)V", + &method_energyInfo}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/btservice/JniCallbacks", + javaMethods); + + const JNIJavaMethod javaUuidTrafficMethods[] = { + {"", "(IJJ)V", &android_bluetooth_UidTraffic.constructor}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/UidTraffic", javaUuidTrafficMethods); + + if (env->GetJavaVM(&vm) != JNI_OK) { + ALOGE("Could not get JavaVM"); + } + + if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) { + ALOGE("No Bluetooth Library found"); + } + + return 0; } } /* namespace android */ @@ -2253,7 +2223,7 @@ int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) { /* * JNI Initialization */ -jint JNI_OnLoad(JavaVM* jvm, void* reserved) { +jint JNI_OnLoad(JavaVM* jvm, void* /* reserved */) { JNIEnv* e; int status; @@ -2271,13 +2241,6 @@ jint JNI_OnLoad(JavaVM* jvm, void* reserved) { return JNI_ERR; } - status = - android::register_com_android_bluetooth_btservice_activity_attribution(e); - if (status < 0) { - ALOGE("jni activity attribution registration failure: %d", status); - return JNI_ERR; - } - status = android::register_com_android_bluetooth_btservice_BluetoothKeystore(e); if (status < 0) { @@ -2391,3 +2354,32 @@ jint JNI_OnLoad(JavaVM* jvm, void* reserved) { return JNI_VERSION_1_6; } + +namespace android { + +/** Load the java methods or die*/ +void jniGetMethodsOrDie(JNIEnv* env, const char* className, + const JNIJavaMethod* methods, int nMethods) { + jclass clazz = env->FindClass(className); + if (clazz == nullptr) { + LOG(FATAL) << "Native registration unable to find class '" << className + << "'; aborting..."; + } + + for (int i = 0; i < nMethods; i++) { + const JNIJavaMethod& method = methods[i]; + if (method.is_static) { + *method.id = env->GetStaticMethodID(clazz, method.name, method.signature); + } else { + *method.id = env->GetMethodID(clazz, method.name, method.signature); + } + if (method.id == nullptr) { + LOG(FATAL) << "In class " << className << ": Unable to find '" + << method.name << "' with signature=" << method.signature + << " is_static=" << method.is_static; + } + } + + env->DeleteLocalRef(clazz); +} +} // namespace android diff --git a/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp b/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp index bceea1d735b7e7654fa05b87718f6e9cef51c0a8..1c5e382c52b07c6f3ad0fb13778ea2f021261861 100644 --- a/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp +++ b/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp @@ -86,17 +86,6 @@ class BluetoothKeystoreCallbacksImpl static BluetoothKeystoreCallbacksImpl sBluetoothKeystoreCallbacks; -static void classInitNative(JNIEnv* env, jclass clazz) { - method_setEncryptKeyOrRemoveKeyCallback = - env->GetMethodID(clazz, "setEncryptKeyOrRemoveKeyCallback", - "(Ljava/lang/String;Ljava/lang/String;)V"); - - method_getKeyCallback = env->GetMethodID( - clazz, "getKeyCallback", "(Ljava/lang/String;)Ljava/lang/String;"); - - LOG(INFO) << __func__ << ": succeeds"; -} - static void initNative(JNIEnv* env, jobject object) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -135,7 +124,7 @@ static void initNative(JNIEnv* env, jobject object) { sBluetoothKeystoreInterface->init(&sBluetoothKeystoreCallbacks); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -155,17 +144,32 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, -}; - int register_com_android_bluetooth_btservice_BluetoothKeystore(JNIEnv* env) { - return jniRegisterNativeMethods( + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + }; + const int result = REGISTER_NATIVE_METHODS( env, "com/android/bluetooth/btservice/bluetoothkeystore/" "BluetoothKeystoreNativeInterface", - sMethods, NELEM(sMethods)); + methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"setEncryptKeyOrRemoveKeyCallback", + "(Ljava/lang/String;Ljava/lang/String;)V", + &method_setEncryptKeyOrRemoveKeyCallback}, + {"getKeyCallback", "(Ljava/lang/String;)Ljava/lang/String;", + &method_getKeyCallback}, + }; + GET_JAVA_METHODS(env, + "com/android/bluetooth/btservice/bluetoothkeystore/" + "BluetoothKeystoreNativeInterface", + javaMethods); + + return 0; } } // 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 1050bd2ad97e9c6671e5ae3dfb9b6b9259da69e0..bd24892a76443e2a2dc21a7eeebc9242f0c3dd41 100644 --- a/android/app/jni/com_android_bluetooth_csip_set_coordinator.cpp +++ b/android/app/jni/com_android_bluetooth_csip_set_coordinator.cpp @@ -75,7 +75,8 @@ class CsisClientCallbacksImpl : public CsisClientCallbacks { void OnConnectionState(const RawAddress& bd_addr, ConnectionState state) override { - LOG(INFO) << __func__; + LOG(INFO) << __func__ << ", state:" << int(state) + << ", addr: " << bd_addr.ToRedactedStringForLogging(); std::shared_lock lock(callbacks_mutex); CallbackEnv sCallbackEnv(__func__); @@ -152,22 +153,6 @@ class CsisClientCallbacksImpl : public CsisClientCallbacks { static CsisClientCallbacksImpl sCsisClientCallbacks; -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "([BI)V"); - - method_onDeviceAvailable = - env->GetMethodID(clazz, "onDeviceAvailable", "([BIIIJJ)V"); - - method_onSetMemberAvailable = - env->GetMethodID(clazz, "onSetMemberAvailable", "([BI)V"); - - method_onGroupLockChanged = - env->GetMethodID(clazz, "onGroupLockChanged", "(IZI)V"); - - LOG(INFO) << __func__ << ": succeeds"; -} - static void initNative(JNIEnv* env, jobject object) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -205,7 +190,7 @@ static void initNative(JNIEnv* env, jobject object) { sCsisClientInterface->Init(&sCsisClientCallbacks); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -226,7 +211,8 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) { +static jboolean connectNative(JNIEnv* env, jobject /* object */, + jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sCsisClientInterface) { LOG(ERROR) << __func__ @@ -246,7 +232,7 @@ static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) { return JNI_TRUE; } -static jboolean disconnectNative(JNIEnv* env, jobject object, +static jboolean disconnectNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sCsisClientInterface) { @@ -266,8 +252,8 @@ static jboolean disconnectNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static void groupLockSetNative(JNIEnv* env, jobject object, jint group_id, - jboolean lock) { +static void groupLockSetNative(JNIEnv* /* env */, jobject /* object */, + jint group_id, jboolean lock) { LOG(INFO) << __func__; if (!sCsisClientInterface) { @@ -279,18 +265,31 @@ static void groupLockSetNative(JNIEnv* env, jobject object, jint group_id, sCsisClientInterface->LockGroup(group_id, lock); } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectNative", "([B)Z", (void*)connectNative}, - {"disconnectNative", "([B)Z", (void*)disconnectNative}, - {"groupLockSetNative", "(IZ)V", (void*)groupLockSetNative}, -}; - int register_com_android_bluetooth_csip_set_coordinator(JNIEnv* env) { - return jniRegisterNativeMethods( + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectNative", "([B)Z", (void*)connectNative}, + {"disconnectNative", "([B)Z", (void*)disconnectNative}, + {"groupLockSetNative", "(IZ)V", (void*)groupLockSetNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/csip/CsipSetCoordinatorNativeInterface", + methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[]{ + {"onConnectionStateChanged", "([BI)V", &method_onConnectionStateChanged}, + {"onDeviceAvailable", "([BIIIJJ)V", &method_onDeviceAvailable}, + {"onSetMemberAvailable", "([BI)V", &method_onSetMemberAvailable}, + {"onGroupLockChanged", "(IZI)V", &method_onGroupLockChanged}, + }; + GET_JAVA_METHODS( env, "com/android/bluetooth/csip/CsipSetCoordinatorNativeInterface", - sMethods, NELEM(sMethods)); + javaMethods); + + return 0; } } // namespace android diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp index cf12ce0a8742b75f23d7010fe19b00345383357b..0e1836937369d713072fee24fffc594548e9bce8 100644 --- a/android/app/jni/com_android_bluetooth_gatt.cpp +++ b/android/app/jni/com_android_bluetooth_gatt.cpp @@ -28,6 +28,7 @@ #include "com_android_bluetooth.h" #include "gd/common/init_flags.h" #include "hardware/bt_gatt.h" +#include "hardware/bt_gatt_types.h" #include "rust/cxx.h" #include "rust/src/gatt/ffi/gatt_shim.h" #include "src/gatt/ffi.rs.h" @@ -490,14 +491,19 @@ void fillGattDbElementArray(JNIEnv* env, jobject* array, jmethodID gattDbElementConstructor = env->GetMethodID(gattDbElementClazz.get(), "", "()V"); - ScopedLocalRef arrayListclazz(env, - env->FindClass("java/util/ArrayList")); - jmethodID arrayAdd = - env->GetMethodID(arrayListclazz.get(), "add", "(Ljava/lang/Object;)Z"); + jmethodID arrayAdd; - ScopedLocalRef uuidClazz(env, env->FindClass("java/util/UUID")); - jmethodID uuidConstructor = - env->GetMethodID(uuidClazz.get(), "", "(JJ)V"); + const JNIJavaMethod javaMethods[] = { + {"add", "(Ljava/lang/Object;)Z", &arrayAdd}, + }; + GET_JAVA_METHODS(env, "java/util/ArrayList", javaMethods); + + jmethodID uuidConstructor; + + const JNIJavaMethod javaUuidMethods[] = { + {"", "(JJ)V", &uuidConstructor}, + }; + GET_JAVA_METHODS(env, "java/util/UUID", javaUuidMethods); for (int i = 0; i < count; i++) { const btgatt_db_element_t& curr = db[i]; @@ -512,6 +518,7 @@ void fillGattDbElementArray(JNIEnv* env, jobject* array, fid = env->GetFieldID(gattDbElementClazz.get(), "attributeHandle", "I"); env->SetIntField(element.get(), fid, curr.attribute_handle); + ScopedLocalRef uuidClazz(env, env->FindClass("java/util/UUID")); ScopedLocalRef uuid( env, env->NewObject(uuidClazz.get(), uuidConstructor, uuid_msb(curr.uuid), uuid_lsb(curr.uuid))); @@ -1232,121 +1239,6 @@ class JniDistanceMeasurementCallbacks : DistanceMeasurementCallbacks { /** * Native function definitions */ -static void classInitNative(JNIEnv* env, jclass clazz) { - // Client callbacks - - method_onClientRegistered = - env->GetMethodID(clazz, "onClientRegistered", "(IIJJ)V"); - method_onScannerRegistered = - env->GetMethodID(clazz, "onScannerRegistered", "(IIJJ)V"); - method_onScanResult = - env->GetMethodID(clazz, "onScanResult", - "(IILjava/lang/String;IIIIII[BLjava/lang/String;)V"); - method_onConnected = - env->GetMethodID(clazz, "onConnected", "(IIILjava/lang/String;)V"); - method_onDisconnected = - env->GetMethodID(clazz, "onDisconnected", "(IIILjava/lang/String;)V"); - method_onReadCharacteristic = - env->GetMethodID(clazz, "onReadCharacteristic", "(III[B)V"); - method_onWriteCharacteristic = - env->GetMethodID(clazz, "onWriteCharacteristic", "(III[B)V"); - method_onExecuteCompleted = - env->GetMethodID(clazz, "onExecuteCompleted", "(II)V"); - method_onSearchCompleted = - env->GetMethodID(clazz, "onSearchCompleted", "(II)V"); - method_onReadDescriptor = - env->GetMethodID(clazz, "onReadDescriptor", "(III[B)V"); - method_onWriteDescriptor = - env->GetMethodID(clazz, "onWriteDescriptor", "(III[B)V"); - method_onNotify = - env->GetMethodID(clazz, "onNotify", "(ILjava/lang/String;IZ[B)V"); - method_onRegisterForNotifications = - env->GetMethodID(clazz, "onRegisterForNotifications", "(IIII)V"); - method_onReadRemoteRssi = - env->GetMethodID(clazz, "onReadRemoteRssi", "(ILjava/lang/String;II)V"); - method_onConfigureMTU = env->GetMethodID(clazz, "onConfigureMTU", "(III)V"); - method_onScanFilterConfig = - env->GetMethodID(clazz, "onScanFilterConfig", "(IIIII)V"); - method_onScanFilterParamsConfigured = - env->GetMethodID(clazz, "onScanFilterParamsConfigured", "(IIII)V"); - method_onScanFilterEnableDisabled = - env->GetMethodID(clazz, "onScanFilterEnableDisabled", "(III)V"); - method_onClientCongestion = - env->GetMethodID(clazz, "onClientCongestion", "(IZ)V"); - method_onBatchScanStorageConfigured = - env->GetMethodID(clazz, "onBatchScanStorageConfigured", "(II)V"); - method_onBatchScanStartStopped = - env->GetMethodID(clazz, "onBatchScanStartStopped", "(III)V"); - method_onBatchScanReports = - env->GetMethodID(clazz, "onBatchScanReports", "(IIII[B)V"); - method_onBatchScanThresholdCrossed = - env->GetMethodID(clazz, "onBatchScanThresholdCrossed", "(I)V"); - method_createOnTrackAdvFoundLostObject = - env->GetMethodID(clazz, "createOnTrackAdvFoundLostObject", - "(II[BI[BIIILjava/lang/String;IIII)Lcom/android/" - "bluetooth/gatt/AdvtFilterOnFoundOnLostInfo;"); - method_onTrackAdvFoundLost = env->GetMethodID( - clazz, "onTrackAdvFoundLost", - "(Lcom/android/bluetooth/gatt/AdvtFilterOnFoundOnLostInfo;)V"); - method_onScanParamSetupCompleted = - env->GetMethodID(clazz, "onScanParamSetupCompleted", "(II)V"); - method_getSampleGattDbElement = - env->GetMethodID(clazz, "getSampleGattDbElement", - "()Lcom/android/bluetooth/gatt/GattDbElement;"); - method_onGetGattDb = - env->GetMethodID(clazz, "onGetGattDb", "(ILjava/util/ArrayList;)V"); - method_onClientPhyRead = - env->GetMethodID(clazz, "onClientPhyRead", "(ILjava/lang/String;III)V"); - method_onClientPhyUpdate = - env->GetMethodID(clazz, "onClientPhyUpdate", "(IIII)V"); - method_onClientConnUpdate = - env->GetMethodID(clazz, "onClientConnUpdate", "(IIIII)V"); - method_onServiceChanged = - env->GetMethodID(clazz, "onServiceChanged", "(I)V"); - method_onClientSubrateChange = - env->GetMethodID(clazz, "onClientSubrateChange", "(IIIIII)V"); - - // Server callbacks - - method_onServerRegistered = - env->GetMethodID(clazz, "onServerRegistered", "(IIJJ)V"); - method_onClientConnected = - env->GetMethodID(clazz, "onClientConnected", "(Ljava/lang/String;ZII)V"); - method_onServiceAdded = - env->GetMethodID(clazz, "onServiceAdded", "(IILjava/util/List;)V"); - method_onServiceStopped = - env->GetMethodID(clazz, "onServiceStopped", "(III)V"); - method_onServiceDeleted = - env->GetMethodID(clazz, "onServiceDeleted", "(III)V"); - method_onResponseSendCompleted = - env->GetMethodID(clazz, "onResponseSendCompleted", "(II)V"); - method_onServerReadCharacteristic = env->GetMethodID( - clazz, "onServerReadCharacteristic", "(Ljava/lang/String;IIIIZ)V"); - method_onServerReadDescriptor = env->GetMethodID( - clazz, "onServerReadDescriptor", "(Ljava/lang/String;IIIIZ)V"); - method_onServerWriteCharacteristic = env->GetMethodID( - clazz, "onServerWriteCharacteristic", "(Ljava/lang/String;IIIIIZZ[B)V"); - method_onServerWriteDescriptor = env->GetMethodID( - clazz, "onServerWriteDescriptor", "(Ljava/lang/String;IIIIIZZ[B)V"); - method_onExecuteWrite = - env->GetMethodID(clazz, "onExecuteWrite", "(Ljava/lang/String;III)V"); - method_onNotificationSent = - env->GetMethodID(clazz, "onNotificationSent", "(II)V"); - method_onServerCongestion = - env->GetMethodID(clazz, "onServerCongestion", "(IZ)V"); - method_onServerMtuChanged = env->GetMethodID(clazz, "onMtuChanged", "(II)V"); - method_onServerPhyRead = - env->GetMethodID(clazz, "onServerPhyRead", "(ILjava/lang/String;III)V"); - method_onServerPhyUpdate = - env->GetMethodID(clazz, "onServerPhyUpdate", "(IIII)V"); - method_onServerConnUpdate = - env->GetMethodID(clazz, "onServerConnUpdate", "(IIIII)V"); - method_onServerSubrateChange = - env->GetMethodID(clazz, "onServerSubrateChange", "(IIIIII)V"); - - info("classInitNative: Success!"); -} - static const bt_interface_t* btIf; static void initializeNative(JNIEnv* env, jobject object) { @@ -1394,7 +1286,7 @@ static void initializeNative(JNIEnv* env, jobject object) { mCallbacksObj = env->NewGlobalRef(object); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock lock(callbacks_mutex); if (!btIf) return; @@ -1415,13 +1307,13 @@ static void cleanupNative(JNIEnv* env, jobject object) { * Native Client functions */ -static int gattClientGetDeviceTypeNative(JNIEnv* env, jobject object, +static int gattClientGetDeviceTypeNative(JNIEnv* env, jobject /* object */, jstring address) { if (!sGattIf) return 0; return sGattIf->client->get_device_type(str2addr(env, address)); } -static void gattClientRegisterAppNative(JNIEnv* env, jobject object, +static void gattClientRegisterAppNative(JNIEnv* /* env */, jobject /* object */, jlong app_uuid_lsb, jlong app_uuid_msb, jboolean eatt_support) { if (!sGattIf) return; @@ -1429,8 +1321,8 @@ static void gattClientRegisterAppNative(JNIEnv* env, jobject object, sGattIf->client->register_client(uuid, eatt_support); } -static void gattClientUnregisterAppNative(JNIEnv* env, jobject object, - jint clientIf) { +static void gattClientUnregisterAppNative(JNIEnv* /* env */, + jobject /* object */, jint clientIf) { if (!sGattIf) return; sGattIf->client->unregister_client(clientIf); } @@ -1444,7 +1336,7 @@ void btgattc_register_scanner_cb(const Uuid& app_uuid, uint8_t scannerId, status, scannerId, UUID_PARAMS(app_uuid)); } -static void registerScannerNative(JNIEnv* env, jobject object, +static void registerScannerNative(JNIEnv* /* env */, jobject /* object */, jlong app_uuid_lsb, jlong app_uuid_msb) { if (!sGattIf) return; @@ -1453,22 +1345,23 @@ static void registerScannerNative(JNIEnv* env, jobject object, uuid, base::Bind(&btgattc_register_scanner_cb, uuid)); } -static void unregisterScannerNative(JNIEnv* env, jobject object, +static void unregisterScannerNative(JNIEnv* /* env */, jobject /* object */, jint scanner_id) { if (!sGattIf) return; sGattIf->scanner->Unregister(scanner_id); } -static void gattClientScanNative(JNIEnv* env, jobject object, jboolean start) { +static void gattClientScanNative(JNIEnv* /* env */, jobject /* object */, + jboolean start) { if (!sGattIf) return; sGattIf->scanner->Scan(start); } -static void gattClientConnectNative(JNIEnv* env, jobject object, jint clientif, - jstring address, jint addressType, - jboolean isDirect, jint transport, - jboolean opportunistic, +static void gattClientConnectNative(JNIEnv* env, jobject /* object */, + jint clientif, jstring address, + jint addressType, jboolean isDirect, + jint transport, jboolean opportunistic, jint initiating_phys) { if (!sGattIf) return; @@ -1476,17 +1369,17 @@ static void gattClientConnectNative(JNIEnv* env, jobject object, jint clientif, isDirect, transport, opportunistic, initiating_phys); } -static void gattClientDisconnectNative(JNIEnv* env, jobject object, +static void gattClientDisconnectNative(JNIEnv* env, jobject /* object */, jint clientIf, jstring address, jint conn_id) { if (!sGattIf) return; sGattIf->client->disconnect(clientIf, str2addr(env, address), conn_id); } -static void gattClientSetPreferredPhyNative(JNIEnv* env, jobject object, - jint clientIf, jstring address, - jint tx_phy, jint rx_phy, - jint phy_options) { +static void gattClientSetPreferredPhyNative(JNIEnv* env, jobject /* object */, + jint /* clientIf */, + jstring address, jint tx_phy, + jint rx_phy, jint phy_options) { if (!sGattIf) return; sGattIf->client->set_preferred_phy(str2addr(env, address), tx_phy, rx_phy, phy_options); @@ -1505,23 +1398,24 @@ static void readClientPhyCb(uint8_t clientIf, RawAddress bda, uint8_t tx_phy, address.get(), tx_phy, rx_phy, status); } -static void gattClientReadPhyNative(JNIEnv* env, jobject object, jint clientIf, - jstring address) { +static void gattClientReadPhyNative(JNIEnv* env, jobject /* object */, + jint clientIf, jstring address) { if (!sGattIf) return; RawAddress bda = str2addr(env, address); sGattIf->client->read_phy(bda, base::Bind(&readClientPhyCb, clientIf, bda)); } -static void gattClientRefreshNative(JNIEnv* env, jobject object, jint clientIf, - jstring address) { +static void gattClientRefreshNative(JNIEnv* env, jobject /* object */, + jint clientIf, jstring address) { if (!sGattIf) return; sGattIf->client->refresh(clientIf, str2addr(env, address)); } -static void gattClientSearchServiceNative(JNIEnv* env, jobject object, - jint conn_id, jboolean search_all, +static void gattClientSearchServiceNative(JNIEnv* /* env */, + jobject /* object */, jint conn_id, + jboolean search_all, jlong service_uuid_lsb, jlong service_uuid_msb) { if (!sGattIf) return; @@ -1530,7 +1424,8 @@ static void gattClientSearchServiceNative(JNIEnv* env, jobject object, sGattIf->client->search_service(conn_id, search_all ? 0 : &uuid); } -static void gattClientDiscoverServiceByUuidNative(JNIEnv* env, jobject object, +static void gattClientDiscoverServiceByUuidNative(JNIEnv* /* env */, + jobject /* object */, jint conn_id, jlong service_uuid_lsb, jlong service_uuid_msb) { @@ -1540,14 +1435,15 @@ static void gattClientDiscoverServiceByUuidNative(JNIEnv* env, jobject object, sGattIf->client->btif_gattc_discover_service_by_uuid(conn_id, uuid); } -static void gattClientGetGattDbNative(JNIEnv* env, jobject object, +static void gattClientGetGattDbNative(JNIEnv* /* env */, jobject /* object */, jint conn_id) { if (!sGattIf) return; sGattIf->client->get_gatt_db(conn_id); } -static void gattClientReadCharacteristicNative(JNIEnv* env, jobject object, +static void gattClientReadCharacteristicNative(JNIEnv* /* env */, + jobject /* object */, jint conn_id, jint handle, jint authReq) { if (!sGattIf) return; @@ -1556,8 +1452,8 @@ static void gattClientReadCharacteristicNative(JNIEnv* env, jobject object, } static void gattClientReadUsingCharacteristicUuidNative( - JNIEnv* env, jobject object, jint conn_id, jlong uuid_lsb, jlong uuid_msb, - jint s_handle, jint e_handle, jint authReq) { + JNIEnv* /* env */, jobject /* object */, jint conn_id, jlong uuid_lsb, + jlong uuid_msb, jint s_handle, jint e_handle, jint authReq) { if (!sGattIf) return; Uuid uuid = from_java_uuid(uuid_msb, uuid_lsb); @@ -1565,15 +1461,16 @@ static void gattClientReadUsingCharacteristicUuidNative( e_handle, authReq); } -static void gattClientReadDescriptorNative(JNIEnv* env, jobject object, - jint conn_id, jint handle, - jint authReq) { +static void gattClientReadDescriptorNative(JNIEnv* /* env */, + jobject /* object */, jint conn_id, + jint handle, jint authReq) { if (!sGattIf) return; sGattIf->client->read_descriptor(conn_id, handle, authReq); } -static void gattClientWriteCharacteristicNative(JNIEnv* env, jobject object, +static void gattClientWriteCharacteristicNative(JNIEnv* env, + jobject /* object */, jint conn_id, jint handle, jint write_type, jint auth_req, jbyteArray value) { @@ -1595,13 +1492,14 @@ static void gattClientWriteCharacteristicNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(value, p_value, 0); } -static void gattClientExecuteWriteNative(JNIEnv* env, jobject object, - jint conn_id, jboolean execute) { +static void gattClientExecuteWriteNative(JNIEnv* /* env */, + jobject /* object */, jint conn_id, + jboolean execute) { if (!sGattIf) return; sGattIf->client->execute_write(conn_id, execute ? 1 : 0); } -static void gattClientWriteDescriptorNative(JNIEnv* env, jobject object, +static void gattClientWriteDescriptorNative(JNIEnv* env, jobject /* object */, jint conn_id, jint handle, jint auth_req, jbyteArray value) { if (!sGattIf) return; @@ -1622,8 +1520,8 @@ static void gattClientWriteDescriptorNative(JNIEnv* env, jobject object, } static void gattClientRegisterForNotificationsNative( - JNIEnv* env, jobject object, jint clientIf, jstring address, jint handle, - jboolean enable) { + JNIEnv* env, jobject /* object */, jint clientIf, jstring address, + jint handle, jboolean enable) { if (!sGattIf) return; RawAddress bd_addr = str2addr(env, address); @@ -1633,7 +1531,7 @@ static void gattClientRegisterForNotificationsNative( sGattIf->client->deregister_for_notification(clientIf, bd_addr, handle); } -static void gattClientReadRemoteRssiNative(JNIEnv* env, jobject object, +static void gattClientReadRemoteRssiNative(JNIEnv* env, jobject /* object */, jint clientif, jstring address) { if (!sGattIf) return; @@ -1648,7 +1546,7 @@ void set_scan_params_cmpl_cb(int client_if, uint8_t status) { status, client_if); } -static void gattSetScanParametersNative(JNIEnv* env, jobject object, +static void gattSetScanParametersNative(JNIEnv* /* env */, jobject /* object */, jint client_if, jint scan_interval_unit, jint scan_window_unit) { if (!sGattIf) return; @@ -1667,7 +1565,8 @@ void scan_filter_param_cb(uint8_t client_if, uint8_t avbl_space, uint8_t action, status, client_if, avbl_space); } -static void gattClientScanFilterParamAddNative(JNIEnv* env, jobject object, +static void gattClientScanFilterParamAddNative(JNIEnv* env, + jobject /* object */, jobject params) { if (!sGattIf) return; const int add_scan_filter_params_action = 0; @@ -1717,7 +1616,8 @@ static void gattClientScanFilterParamAddNative(JNIEnv* env, jobject object, std::move(filt_params), base::Bind(&scan_filter_param_cb, client_if)); } -static void gattClientScanFilterParamDeleteNative(JNIEnv* env, jobject object, +static void gattClientScanFilterParamDeleteNative(JNIEnv* /* env */, + jobject /* object */, jint client_if, jint filt_index) { if (!sGattIf) return; @@ -1727,7 +1627,8 @@ static void gattClientScanFilterParamDeleteNative(JNIEnv* env, jobject object, base::Bind(&scan_filter_param_cb, client_if)); } -static void gattClientScanFilterParamClearAllNative(JNIEnv* env, jobject object, +static void gattClientScanFilterParamClearAllNative(JNIEnv* /* env */, + jobject /* object */, jint client_if) { if (!sGattIf) return; const int clear_scan_filter_params_action = 2; @@ -1746,16 +1647,19 @@ static void scan_filter_cfg_cb(uint8_t client_if, uint8_t filt_type, status, client_if, filt_type, avbl_space); } -static void gattClientScanFilterAddNative(JNIEnv* env, jobject object, +static void gattClientScanFilterAddNative(JNIEnv* env, jobject /* object */, jint client_if, jobjectArray filters, jint filter_index) { if (!sGattIf) return; - jclass uuidClazz = env->FindClass("java/util/UUID"); - jmethodID uuidGetMsb = - env->GetMethodID(uuidClazz, "getMostSignificantBits", "()J"); - jmethodID uuidGetLsb = - env->GetMethodID(uuidClazz, "getLeastSignificantBits", "()J"); + jmethodID uuidGetMsb; + jmethodID uuidGetLsb; + + const JNIJavaMethod javaMethods[] = { + {"getMostSignificantBits", "()J", &uuidGetMsb}, + {"getLeastSignificantBits", "()J", &uuidGetLsb}, + }; + GET_JAVA_METHODS(env, "java/util/UUID", javaMethods); std::vector native_filters; @@ -1904,7 +1808,8 @@ static void gattClientScanFilterAddNative(JNIEnv* env, jobject object, base::Bind(&scan_filter_cfg_cb, client_if)); } -static void gattClientScanFilterClearNative(JNIEnv* env, jobject object, +static void gattClientScanFilterClearNative(JNIEnv* /* env */, + jobject /* object */, jint client_if, jint filt_index) { if (!sGattIf) return; sGattIf->scanner->ScanFilterClear(filt_index, @@ -1919,33 +1824,33 @@ void scan_enable_cb(uint8_t client_if, uint8_t action, uint8_t status) { action, status, client_if); } -static void gattClientScanFilterEnableNative(JNIEnv* env, jobject object, +static void gattClientScanFilterEnableNative(JNIEnv* /* env */, + jobject /* object */, jint client_if, jboolean enable) { if (!sGattIf) return; sGattIf->scanner->ScanFilterEnable(enable, base::Bind(&scan_enable_cb, client_if)); } -static void gattClientConfigureMTUNative(JNIEnv* env, jobject object, - jint conn_id, jint mtu) { +static void gattClientConfigureMTUNative(JNIEnv* /* env */, + jobject /* object */, jint conn_id, + jint mtu) { if (!sGattIf) return; sGattIf->client->configure_mtu(conn_id, mtu); } -static void gattConnectionParameterUpdateNative(JNIEnv* env, jobject object, - jint client_if, jstring address, - jint min_interval, - jint max_interval, jint latency, - jint timeout, jint min_ce_len, - jint max_ce_len) { +static void gattConnectionParameterUpdateNative( + JNIEnv* env, jobject /* object */, jint /* client_if */, jstring address, + jint min_interval, jint max_interval, jint latency, jint timeout, + jint min_ce_len, jint max_ce_len) { if (!sGattIf) return; sGattIf->client->conn_parameter_update( str2addr(env, address), min_interval, max_interval, latency, timeout, (uint16_t)min_ce_len, (uint16_t)max_ce_len); } -static void gattSubrateRequestNative(JNIEnv* env, jobject object, - jint client_if, jstring address, +static void gattSubrateRequestNative(JNIEnv* env, jobject /* object */, + jint /* client_if */, jstring address, jint subrate_min, jint subrate_max, jint max_latency, jint cont_num, jint sup_timeout) { @@ -1964,8 +1869,9 @@ void batchscan_cfg_storage_cb(uint8_t client_if, uint8_t status) { } static void gattClientConfigBatchScanStorageNative( - JNIEnv* env, jobject object, jint client_if, jint max_full_reports_percent, - jint max_trunc_reports_percent, jint notify_threshold_level_percent) { + JNIEnv* /* env */, jobject /* object */, jint client_if, + jint max_full_reports_percent, jint max_trunc_reports_percent, + jint notify_threshold_level_percent) { if (!sGattIf) return; sGattIf->scanner->BatchscanConfigStorage( client_if, max_full_reports_percent, max_trunc_reports_percent, @@ -1981,8 +1887,9 @@ void batchscan_enable_cb(uint8_t client_if, uint8_t status) { 0 /* unused */, status, client_if); } -static void gattClientStartBatchScanNative(JNIEnv* env, jobject object, - jint client_if, jint scan_mode, +static void gattClientStartBatchScanNative(JNIEnv* /* env */, + jobject /* object */, jint client_if, + jint scan_mode, jint scan_interval_unit, jint scan_window_unit, jint addr_type, jint discard_rule) { @@ -1992,14 +1899,16 @@ static void gattClientStartBatchScanNative(JNIEnv* env, jobject object, base::Bind(&batchscan_enable_cb, client_if)); } -static void gattClientStopBatchScanNative(JNIEnv* env, jobject object, +static void gattClientStopBatchScanNative(JNIEnv* /* env */, + jobject /* object */, jint client_if) { if (!sGattIf) return; sGattIf->scanner->BatchscanDisable( base::Bind(&batchscan_enable_cb, client_if)); } -static void gattClientReadScanReportsNative(JNIEnv* env, jobject object, +static void gattClientReadScanReportsNative(JNIEnv* /* env */, + jobject /* object */, jint client_if, jint scan_type) { if (!sGattIf) return; sGattIf->scanner->BatchscanReadReports(client_if, scan_type); @@ -2008,7 +1917,7 @@ static void gattClientReadScanReportsNative(JNIEnv* env, jobject object, /** * Native server functions */ -static void gattServerRegisterAppNative(JNIEnv* env, jobject object, +static void gattServerRegisterAppNative(JNIEnv* /* env */, jobject /* object */, jlong app_uuid_lsb, jlong app_uuid_msb, jboolean eatt_support) { if (!sGattIf) return; @@ -2016,33 +1925,33 @@ static void gattServerRegisterAppNative(JNIEnv* env, jobject object, sGattIf->server->register_server(uuid, eatt_support); } -static void gattServerUnregisterAppNative(JNIEnv* env, jobject object, - jint serverIf) { +static void gattServerUnregisterAppNative(JNIEnv* /* env */, + jobject /* object */, jint serverIf) { if (!sGattIf) return; bluetooth::gatt::close_server(serverIf); sGattIf->server->unregister_server(serverIf); } -static void gattServerConnectNative(JNIEnv* env, jobject object, jint server_if, - jstring address, jboolean is_direct, - jint transport) { +static void gattServerConnectNative(JNIEnv* env, jobject /* object */, + jint server_if, jstring address, + jboolean is_direct, jint transport) { if (!sGattIf) return; RawAddress bd_addr = str2addr(env, address); sGattIf->server->connect(server_if, bd_addr, is_direct, transport); } -static void gattServerDisconnectNative(JNIEnv* env, jobject object, +static void gattServerDisconnectNative(JNIEnv* env, jobject /* object */, jint serverIf, jstring address, jint conn_id) { if (!sGattIf) return; sGattIf->server->disconnect(serverIf, str2addr(env, address), conn_id); } -static void gattServerSetPreferredPhyNative(JNIEnv* env, jobject object, - jint serverIf, jstring address, - jint tx_phy, jint rx_phy, - jint phy_options) { +static void gattServerSetPreferredPhyNative(JNIEnv* env, jobject /* object */, + jint /* serverIf */, + jstring address, jint tx_phy, + jint rx_phy, jint phy_options) { if (!sGattIf) return; RawAddress bda = str2addr(env, address); sGattIf->server->set_preferred_phy(bda, tx_phy, rx_phy, phy_options); @@ -2061,32 +1970,39 @@ static void readServerPhyCb(uint8_t serverIf, RawAddress bda, uint8_t tx_phy, address.get(), tx_phy, rx_phy, status); } -static void gattServerReadPhyNative(JNIEnv* env, jobject object, jint serverIf, - jstring address) { +static void gattServerReadPhyNative(JNIEnv* env, jobject /* object */, + jint serverIf, jstring address) { if (!sGattIf) return; RawAddress bda = str2addr(env, address); sGattIf->server->read_phy(bda, base::Bind(&readServerPhyCb, serverIf, bda)); } -static void gattServerAddServiceNative(JNIEnv* env, jobject object, +static void gattServerAddServiceNative(JNIEnv* env, jobject /* object */, jint server_if, jobject gatt_db_elements) { if (!sGattIf) return; - jclass arrayListclazz = env->FindClass("java/util/List"); - jmethodID arrayGet = - env->GetMethodID(arrayListclazz, "get", "(I)Ljava/lang/Object;"); - jmethodID arraySize = env->GetMethodID(arrayListclazz, "size", "()I"); + jmethodID arrayGet; + jmethodID arraySize; + + const JNIJavaMethod javaListMethods[] = { + {"get", "(I)Ljava/lang/Object;", &arrayGet}, + {"size", "()I", &arraySize}, + }; + GET_JAVA_METHODS(env, "java/util/List", javaListMethods); int count = env->CallIntMethod(gatt_db_elements, arraySize); std::vector db; - jclass uuidClazz = env->FindClass("java/util/UUID"); - jmethodID uuidGetMsb = - env->GetMethodID(uuidClazz, "getMostSignificantBits", "()J"); - jmethodID uuidGetLsb = - env->GetMethodID(uuidClazz, "getLeastSignificantBits", "()J"); + jmethodID uuidGetMsb; + jmethodID uuidGetLsb; + + const JNIJavaMethod javaUuidMethods[] = { + {"getMostSignificantBits", "()J", &uuidGetMsb}, + {"getLeastSignificantBits", "()J", &uuidGetLsb}, + }; + GET_JAVA_METHODS(env, "java/util/UUID", javaUuidMethods); jobject objectForClass = env->CallObjectMethod(mCallbacksObj, method_getSampleGattDbElement); @@ -2137,19 +2053,20 @@ static void gattServerAddServiceNative(JNIEnv* env, jobject object, sGattIf->server->add_service(server_if, db.data(), db.size()); } -static void gattServerStopServiceNative(JNIEnv* env, jobject object, +static void gattServerStopServiceNative(JNIEnv* /* env */, jobject /* object */, jint server_if, jint svc_handle) { if (!sGattIf) return; sGattIf->server->stop_service(server_if, svc_handle); } -static void gattServerDeleteServiceNative(JNIEnv* env, jobject object, - jint server_if, jint svc_handle) { +static void gattServerDeleteServiceNative(JNIEnv* /* env */, + jobject /* object */, jint server_if, + jint svc_handle) { if (!sGattIf) return; sGattIf->server->delete_service(server_if, svc_handle); } -static void gattServerSendIndicationNative(JNIEnv* env, jobject object, +static void gattServerSendIndicationNative(JNIEnv* env, jobject /* object */, jint server_if, jint attr_handle, jint conn_id, jbyteArray val) { if (!sGattIf) return; @@ -2168,7 +2085,7 @@ static void gattServerSendIndicationNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(val, array, JNI_ABORT); } -static void gattServerSendNotificationNative(JNIEnv* env, jobject object, +static void gattServerSendNotificationNative(JNIEnv* env, jobject /* object */, jint server_if, jint attr_handle, jint conn_id, jbyteArray val) { if (!sGattIf) return; @@ -2182,7 +2099,7 @@ static void gattServerSendNotificationNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(val, array, JNI_ABORT); } -static void gattServerSendResponseNative(JNIEnv* env, jobject object, +static void gattServerSendResponseNative(JNIEnv* env, jobject /* object */, jint server_if, jint conn_id, jint trans_id, jint status, jint handle, jint offset, @@ -2197,10 +2114,10 @@ static void gattServerSendResponseNative(JNIEnv* env, jobject object, response.attr_value.len = 0; if (val != NULL) { - if (env->GetArrayLength(val) < BTGATT_MAX_ATTR_LEN) { + if (env->GetArrayLength(val) < GATT_MAX_ATTR_LEN) { response.attr_value.len = (uint16_t)env->GetArrayLength(val); } else { - response.attr_value.len = BTGATT_MAX_ATTR_LEN; + response.attr_value.len = GATT_MAX_ATTR_LEN; } jbyte* array = env->GetByteArrayElements(val, 0); @@ -2219,27 +2136,6 @@ static void gattServerSendResponseNative(JNIEnv* env, jobject object, } } -static void advertiseClassInitNative(JNIEnv* env, jclass clazz) { - method_onAdvertisingSetStarted = - env->GetMethodID(clazz, "onAdvertisingSetStarted", "(IIII)V"); - method_onOwnAddressRead = - env->GetMethodID(clazz, "onOwnAddressRead", "(IILjava/lang/String;)V"); - method_onAdvertisingEnabled = - env->GetMethodID(clazz, "onAdvertisingEnabled", "(IZI)V"); - method_onAdvertisingDataSet = - env->GetMethodID(clazz, "onAdvertisingDataSet", "(II)V"); - method_onScanResponseDataSet = - env->GetMethodID(clazz, "onScanResponseDataSet", "(II)V"); - method_onAdvertisingParametersUpdated = - env->GetMethodID(clazz, "onAdvertisingParametersUpdated", "(III)V"); - method_onPeriodicAdvertisingParametersUpdated = env->GetMethodID( - clazz, "onPeriodicAdvertisingParametersUpdated", "(II)V"); - method_onPeriodicAdvertisingDataSet = - env->GetMethodID(clazz, "onPeriodicAdvertisingDataSet", "(II)V"); - method_onPeriodicAdvertisingEnabled = - env->GetMethodID(clazz, "onPeriodicAdvertisingEnabled", "(IZI)V"); -} - static void advertiseInitializeNative(JNIEnv* env, jobject object) { std::unique_lock lock(callbacks_mutex); if (mAdvertiseCallbacksObj != NULL) { @@ -2251,7 +2147,7 @@ static void advertiseInitializeNative(JNIEnv* env, jobject object) { mAdvertiseCallbacksObj = env->NewGlobalRef(object); } -static void advertiseCleanupNative(JNIEnv* env, jobject object) { +static void advertiseCleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock lock(callbacks_mutex); if (mAdvertiseCallbacksObj != NULL) { env->DeleteGlobalRef(mAdvertiseCallbacksObj); @@ -2373,7 +2269,7 @@ static void ble_advertising_set_timeout_cb(uint8_t advertiser_id, } static void startAdvertisingSetNative( - JNIEnv* env, jobject object, jobject parameters, jbyteArray adv_data, + JNIEnv* env, jobject /* object */, jobject parameters, jbyteArray adv_data, jbyteArray scan_resp, jobject periodic_parameters, jbyteArray periodic_data, jint duration, jint maxExtAdvEvents, jint reg_id, jint server_if) { if (!sGattIf) return; @@ -2400,12 +2296,13 @@ static void startAdvertisingSetNative( env->ReleaseByteArrayElements(periodic_data, periodic_data_data, JNI_ABORT); sGattIf->advertiser->StartAdvertisingSet( - reg_id, base::Bind(&ble_advertising_set_started_cb, reg_id, server_if), - params, data_vec, scan_resp_vec, periodicParams, periodic_data_vec, - duration, maxExtAdvEvents, base::Bind(ble_advertising_set_timeout_cb)); + kAdvertiserClientIdJni, reg_id, + base::Bind(&ble_advertising_set_started_cb, reg_id, server_if), params, + data_vec, scan_resp_vec, periodicParams, periodic_data_vec, duration, + maxExtAdvEvents, base::Bind(ble_advertising_set_timeout_cb)); } -static void stopAdvertisingSetNative(JNIEnv* env, jobject object, +static void stopAdvertisingSetNative(JNIEnv* /* env */, jobject /* object */, jint advertiser_id) { if (!sGattIf) return; @@ -2426,7 +2323,7 @@ static void getOwnAddressCb(uint8_t advertiser_id, uint8_t address_type, advertiser_id, address_type, addr.get()); } -static void getOwnAddressNative(JNIEnv* env, jobject object, +static void getOwnAddressNative(JNIEnv* /* env */, jobject /* object */, jint advertiser_id) { if (!sGattIf) return; sGattIf->advertiser->GetOwnAddress( @@ -2451,7 +2348,7 @@ static void enableSetCb(uint8_t advertiser_id, bool enable, uint8_t status) { enable, status); } -static void enableAdvertisingSetNative(JNIEnv* env, jobject object, +static void enableAdvertisingSetNative(JNIEnv* /* env */, jobject /* object */, jint advertiser_id, jboolean enable, jint duration, jint maxExtAdvEvents) { if (!sGattIf) return; @@ -2462,7 +2359,7 @@ static void enableAdvertisingSetNative(JNIEnv* env, jobject object, base::Bind(&enableSetCb, advertiser_id, false)); } -static void setAdvertisingDataNative(JNIEnv* env, jobject object, +static void setAdvertisingDataNative(JNIEnv* env, jobject /* object */, jint advertiser_id, jbyteArray data) { if (!sGattIf) return; @@ -2471,7 +2368,7 @@ static void setAdvertisingDataNative(JNIEnv* env, jobject object, base::Bind(&callJniCallback, method_onAdvertisingDataSet, advertiser_id)); } -static void setScanResponseDataNative(JNIEnv* env, jobject object, +static void setScanResponseDataNative(JNIEnv* env, jobject /* object */, jint advertiser_id, jbyteArray data) { if (!sGattIf) return; @@ -2491,7 +2388,7 @@ static void setAdvertisingParametersNativeCb(uint8_t advertiser_id, advertiser_id, tx_power, status); } -static void setAdvertisingParametersNative(JNIEnv* env, jobject object, +static void setAdvertisingParametersNative(JNIEnv* env, jobject /* object */, jint advertiser_id, jobject parameters) { if (!sGattIf) return; @@ -2503,7 +2400,7 @@ static void setAdvertisingParametersNative(JNIEnv* env, jobject object, } static void setPeriodicAdvertisingParametersNative( - JNIEnv* env, jobject object, jint advertiser_id, + JNIEnv* env, jobject /* object */, jint advertiser_id, jobject periodic_parameters) { if (!sGattIf) return; @@ -2515,7 +2412,7 @@ static void setPeriodicAdvertisingParametersNative( method_onPeriodicAdvertisingParametersUpdated, advertiser_id)); } -static void setPeriodicAdvertisingDataNative(JNIEnv* env, jobject object, +static void setPeriodicAdvertisingDataNative(JNIEnv* env, jobject /* object */, jint advertiser_id, jbyteArray data) { if (!sGattIf) return; @@ -2536,7 +2433,8 @@ static void enablePeriodicSetCb(uint8_t advertiser_id, bool enable, advertiser_id, enable, status); } -static void setPeriodicAdvertisingEnableNative(JNIEnv* env, jobject object, +static void setPeriodicAdvertisingEnableNative(JNIEnv* /* env */, + jobject /* object */, jint advertiser_id, jboolean enable) { if (!sGattIf) return; @@ -2548,16 +2446,6 @@ static void setPeriodicAdvertisingEnableNative(JNIEnv* env, jobject object, base::Bind(&enablePeriodicSetCb, advertiser_id, enable)); } -static void periodicScanClassInitNative(JNIEnv* env, jclass clazz) { - method_onSyncStarted = - env->GetMethodID(clazz, "onSyncStarted", "(IIIILjava/lang/String;III)V"); - method_onSyncReport = env->GetMethodID(clazz, "onSyncReport", "(IIII[B)V"); - method_onSyncLost = env->GetMethodID(clazz, "onSyncLost", "(I)V"); - method_onSyncTransferredCallback = env->GetMethodID( - clazz, "onSyncTransferredCallback", "(IILjava/lang/String;)V"); - method_onBigInfoReport = env->GetMethodID(clazz, "onBigInfoReport", "(IZ)V"); -} - static void periodicScanInitializeNative(JNIEnv* env, jobject object) { std::unique_lock lock(callbacks_mutex); if (mPeriodicScanCallbacksObj != NULL) { @@ -2569,7 +2457,7 @@ static void periodicScanInitializeNative(JNIEnv* env, jobject object) { mPeriodicScanCallbacksObj = env->NewGlobalRef(object); } -static void periodicScanCleanupNative(JNIEnv* env, jobject object) { +static void periodicScanCleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock lock(callbacks_mutex); if (mPeriodicScanCallbacksObj != NULL) { env->DeleteGlobalRef(mPeriodicScanCallbacksObj); @@ -2577,7 +2465,7 @@ static void periodicScanCleanupNative(JNIEnv* env, jobject object) { } } -static void startSyncNative(JNIEnv* env, jobject object, jint sid, +static void startSyncNative(JNIEnv* env, jobject /* object */, jint sid, jstring address, jint skip, jint timeout, jint reg_id) { if (!sGattIf) return; @@ -2585,34 +2473,35 @@ static void startSyncNative(JNIEnv* env, jobject object, jint sid, reg_id); } -static void stopSyncNative(JNIEnv* env, jobject object, jint sync_handle) { +static void stopSyncNative(JNIEnv* /* env */, jobject /* object */, + jint sync_handle) { if (!sGattIf) return; sGattIf->scanner->StopSync(sync_handle); } -static void cancelSyncNative(JNIEnv* env, jobject object, jint sid, +static void cancelSyncNative(JNIEnv* env, jobject /* object */, jint sid, jstring address) { if (!sGattIf) return; sGattIf->scanner->CancelCreateSync(sid, str2addr(env, address)); } -static void syncTransferNative(JNIEnv* env, jobject object, jint pa_source, - jstring addr, jint service_data, +static void syncTransferNative(JNIEnv* env, jobject /* object */, + jint pa_source, jstring addr, jint service_data, jint sync_handle) { if (!sGattIf) return; sGattIf->scanner->TransferSync(str2addr(env, addr), service_data, sync_handle, pa_source); } -static void transferSetInfoNative(JNIEnv* env, jobject object, jint pa_source, - jstring addr, jint service_data, - jint adv_handle) { +static void transferSetInfoNative(JNIEnv* env, jobject /* object */, + jint pa_source, jstring addr, + jint service_data, jint adv_handle) { if (!sGattIf) return; sGattIf->scanner->TransferSetInfo(str2addr(env, addr), service_data, adv_handle, pa_source); } -static void gattTestNative(JNIEnv* env, jobject object, jint command, +static void gattTestNative(JNIEnv* env, jobject /* object */, jint command, jlong uuid1_lsb, jlong uuid1_msb, jstring bda1, jint p1, jint p2, jint p3, jint p4, jint p5) { if (!sGattIf) return; @@ -2632,17 +2521,6 @@ static void gattTestNative(JNIEnv* env, jobject object, jint command, sGattIf->client->test_command(command, params); } -static void distanceMeasurementClassInitNative(JNIEnv* env, jclass clazz) { - method_onDistanceMeasurementStarted = env->GetMethodID( - clazz, "onDistanceMeasurementStarted", "(Ljava/lang/String;I)V"); - method_onDistanceMeasurementStartFail = env->GetMethodID( - clazz, "onDistanceMeasurementStartFail", "(Ljava/lang/String;II)V"); - method_onDistanceMeasurementStopped = env->GetMethodID( - clazz, "onDistanceMeasurementStopped", "(Ljava/lang/String;II)V"); - method_onDistanceMeasurementResult = env->GetMethodID( - clazz, "onDistanceMeasurementResult", "(Ljava/lang/String;IIIIIII)V"); -} - static void distanceMeasurementInitializeNative(JNIEnv* env, jobject object) { std::unique_lock lock(callbacks_mutex); if (mDistanceMeasurementCallbacksObj != NULL) { @@ -2654,7 +2532,8 @@ static void distanceMeasurementInitializeNative(JNIEnv* env, jobject object) { mDistanceMeasurementCallbacksObj = env->NewGlobalRef(object); } -static void distanceMeasurementCleanupNative(JNIEnv* env, jobject object) { +static void distanceMeasurementCleanupNative(JNIEnv* env, + jobject /* object */) { std::unique_lock lock(callbacks_mutex); if (mDistanceMeasurementCallbacksObj != NULL) { env->DeleteGlobalRef(mDistanceMeasurementCallbacksObj); @@ -2662,7 +2541,7 @@ static void distanceMeasurementCleanupNative(JNIEnv* env, jobject object) { } } -static void startDistanceMeasurementNative(JNIEnv* env, jobject object, +static void startDistanceMeasurementNative(JNIEnv* env, jobject /* object */, jstring address, jint frequency, jint method) { if (!sGattIf) return; @@ -2670,7 +2549,7 @@ static void startDistanceMeasurementNative(JNIEnv* env, jobject object, str2addr(env, address), frequency, method); } -static void stopDistanceMeasurementNative(JNIEnv* env, jobject object, +static void stopDistanceMeasurementNative(JNIEnv* env, jobject /* object */, jstring address, jint method) { if (!sGattIf) return; sGattIf->distance_measurement_manager->StopDistanceMeasurement( @@ -2681,183 +2560,345 @@ static void stopDistanceMeasurementNative(JNIEnv* env, jobject object, * JNI function definitinos */ -// JNI functions defined in AdvertiseManager class. -static JNINativeMethod sAdvertiseMethods[] = { - {"classInitNative", "()V", (void*)advertiseClassInitNative}, - {"initializeNative", "()V", (void*)advertiseInitializeNative}, - {"cleanupNative", "()V", (void*)advertiseCleanupNative}, - {"startAdvertisingSetNative", - "(Landroid/bluetooth/le/AdvertisingSetParameters;[B[BLandroid/bluetooth/" - "le/PeriodicAdvertisingParameters;[BIIII)V", - (void*)startAdvertisingSetNative}, - {"getOwnAddressNative", "(I)V", (void*)getOwnAddressNative}, - {"stopAdvertisingSetNative", "(I)V", (void*)stopAdvertisingSetNative}, - {"enableAdvertisingSetNative", "(IZII)V", - (void*)enableAdvertisingSetNative}, - {"setAdvertisingDataNative", "(I[B)V", (void*)setAdvertisingDataNative}, - {"setScanResponseDataNative", "(I[B)V", (void*)setScanResponseDataNative}, - {"setAdvertisingParametersNative", - "(ILandroid/bluetooth/le/AdvertisingSetParameters;)V", - (void*)setAdvertisingParametersNative}, - {"setPeriodicAdvertisingParametersNative", - "(ILandroid/bluetooth/le/PeriodicAdvertisingParameters;)V", - (void*)setPeriodicAdvertisingParametersNative}, - {"setPeriodicAdvertisingDataNative", "(I[B)V", - (void*)setPeriodicAdvertisingDataNative}, - {"setPeriodicAdvertisingEnableNative", "(IZ)V", - (void*)setPeriodicAdvertisingEnableNative}, -}; +// JNI functions defined in AdvertiseManagerNativeInterface class. // JNI functions defined in PeriodicScanManager class. -static JNINativeMethod sPeriodicScanMethods[] = { - {"classInitNative", "()V", (void*)periodicScanClassInitNative}, - {"initializeNative", "()V", (void*)periodicScanInitializeNative}, - {"cleanupNative", "()V", (void*)periodicScanCleanupNative}, - {"startSyncNative", "(ILjava/lang/String;III)V", (void*)startSyncNative}, - {"stopSyncNative", "(I)V", (void*)stopSyncNative}, - {"cancelSyncNative", "(ILjava/lang/String;)V", (void*)cancelSyncNative}, - {"syncTransferNative", "(ILjava/lang/String;II)V", - (void*)syncTransferNative}, - {"transferSetInfoNative", "(ILjava/lang/String;II)V", - (void*)transferSetInfoNative}, -}; - -// JNI functions defined in ScanNativeInterface class. -static JNINativeMethod sScanMethods[] = { - {"registerScannerNative", "(JJ)V", (void*)registerScannerNative}, - {"unregisterScannerNative", "(I)V", (void*)unregisterScannerNative}, - {"gattClientScanNative", "(Z)V", (void*)gattClientScanNative}, - // Batch scan JNI functions. - {"gattClientConfigBatchScanStorageNative", "(IIII)V", - (void*)gattClientConfigBatchScanStorageNative}, - {"gattClientStartBatchScanNative", "(IIIIII)V", - (void*)gattClientStartBatchScanNative}, - {"gattClientStopBatchScanNative", "(I)V", - (void*)gattClientStopBatchScanNative}, - {"gattClientReadScanReportsNative", "(II)V", - (void*)gattClientReadScanReportsNative}, - // Scan filter JNI functions. - {"gattClientScanFilterParamAddNative", - "(Lcom/android/bluetooth/gatt/FilterParams;)V", - (void*)gattClientScanFilterParamAddNative}, - {"gattClientScanFilterParamDeleteNative", "(II)V", - (void*)gattClientScanFilterParamDeleteNative}, - {"gattClientScanFilterParamClearAllNative", "(I)V", - (void*)gattClientScanFilterParamClearAllNative}, - {"gattClientScanFilterAddNative", - "(I[Lcom/android/bluetooth/gatt/ScanFilterQueue$Entry;I)V", - (void*)gattClientScanFilterAddNative}, - {"gattClientScanFilterClearNative", "(II)V", - (void*)gattClientScanFilterClearNative}, - {"gattClientScanFilterEnableNative", "(IZ)V", - (void*)gattClientScanFilterEnableNative}, - {"gattSetScanParametersNative", "(III)V", - (void*)gattSetScanParametersNative}, -}; - // JNI functions defined in DistanceMeasurementManager class. -static JNINativeMethod sDistanceMeasurementMethods[] = { - {"classInitNative", "()V", (void*)distanceMeasurementClassInitNative}, - {"initializeNative", "()V", (void*)distanceMeasurementInitializeNative}, - {"cleanupNative", "()V", (void*)distanceMeasurementCleanupNative}, - {"startDistanceMeasurementNative", "(Ljava/lang/String;II)V", - (void*)startDistanceMeasurementNative}, - {"stopDistanceMeasurementNative", "(Ljava/lang/String;I)V", - (void*)stopDistanceMeasurementNative}, -}; // JNI functions defined in GattNativeInterface class. -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNative", "()V", (void*)initializeNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"gattClientGetDeviceTypeNative", "(Ljava/lang/String;)I", - (void*)gattClientGetDeviceTypeNative}, - {"gattClientRegisterAppNative", "(JJZ)V", - (void*)gattClientRegisterAppNative}, - {"gattClientUnregisterAppNative", "(I)V", - (void*)gattClientUnregisterAppNative}, - {"gattClientConnectNative", "(ILjava/lang/String;IZIZI)V", - (void*)gattClientConnectNative}, - {"gattClientDisconnectNative", "(ILjava/lang/String;I)V", - (void*)gattClientDisconnectNative}, - {"gattClientSetPreferredPhyNative", "(ILjava/lang/String;III)V", - (void*)gattClientSetPreferredPhyNative}, - {"gattClientReadPhyNative", "(ILjava/lang/String;)V", - (void*)gattClientReadPhyNative}, - {"gattClientRefreshNative", "(ILjava/lang/String;)V", - (void*)gattClientRefreshNative}, - {"gattClientSearchServiceNative", "(IZJJ)V", - (void*)gattClientSearchServiceNative}, - {"gattClientDiscoverServiceByUuidNative", "(IJJ)V", - (void*)gattClientDiscoverServiceByUuidNative}, - {"gattClientGetGattDbNative", "(I)V", (void*)gattClientGetGattDbNative}, - {"gattClientReadCharacteristicNative", "(III)V", - (void*)gattClientReadCharacteristicNative}, - {"gattClientReadUsingCharacteristicUuidNative", "(IJJIII)V", - (void*)gattClientReadUsingCharacteristicUuidNative}, - {"gattClientReadDescriptorNative", "(III)V", - (void*)gattClientReadDescriptorNative}, - {"gattClientWriteCharacteristicNative", "(IIII[B)V", - (void*)gattClientWriteCharacteristicNative}, - {"gattClientWriteDescriptorNative", "(III[B)V", - (void*)gattClientWriteDescriptorNative}, - {"gattClientExecuteWriteNative", "(IZ)V", - (void*)gattClientExecuteWriteNative}, - {"gattClientRegisterForNotificationsNative", "(ILjava/lang/String;IZ)V", - (void*)gattClientRegisterForNotificationsNative}, - {"gattClientReadRemoteRssiNative", "(ILjava/lang/String;)V", - (void*)gattClientReadRemoteRssiNative}, - {"gattClientConfigureMTUNative", "(II)V", - (void*)gattClientConfigureMTUNative}, - {"gattConnectionParameterUpdateNative", "(ILjava/lang/String;IIIIII)V", - (void*)gattConnectionParameterUpdateNative}, - {"gattServerRegisterAppNative", "(JJZ)V", - (void*)gattServerRegisterAppNative}, - {"gattServerUnregisterAppNative", "(I)V", - (void*)gattServerUnregisterAppNative}, - {"gattServerConnectNative", "(ILjava/lang/String;ZI)V", - (void*)gattServerConnectNative}, - {"gattServerDisconnectNative", "(ILjava/lang/String;I)V", - (void*)gattServerDisconnectNative}, - {"gattServerSetPreferredPhyNative", "(ILjava/lang/String;III)V", - (void*)gattServerSetPreferredPhyNative}, - {"gattServerReadPhyNative", "(ILjava/lang/String;)V", - (void*)gattServerReadPhyNative}, - {"gattServerAddServiceNative", "(ILjava/util/List;)V", - (void*)gattServerAddServiceNative}, - {"gattServerStopServiceNative", "(II)V", - (void*)gattServerStopServiceNative}, - {"gattServerDeleteServiceNative", "(II)V", - (void*)gattServerDeleteServiceNative}, - {"gattServerSendIndicationNative", "(III[B)V", - (void*)gattServerSendIndicationNative}, - {"gattServerSendNotificationNative", "(III[B)V", - (void*)gattServerSendNotificationNative}, - {"gattServerSendResponseNative", "(IIIIII[BI)V", - (void*)gattServerSendResponseNative}, - {"gattSubrateRequestNative", "(ILjava/lang/String;IIIII)V", - (void*)gattSubrateRequestNative}, - - {"gattTestNative", "(IJJLjava/lang/String;IIIII)V", (void*)gattTestNative}, -}; +static int register_com_android_bluetooth_gatt_scan(JNIEnv* env) { + const JNINativeMethod methods[] = { + {"registerScannerNative", "(JJ)V", (void*)registerScannerNative}, + {"unregisterScannerNative", "(I)V", (void*)unregisterScannerNative}, + {"gattClientScanNative", "(Z)V", (void*)gattClientScanNative}, + // Batch scan JNI functions. + {"gattClientConfigBatchScanStorageNative", "(IIII)V", + (void*)gattClientConfigBatchScanStorageNative}, + {"gattClientStartBatchScanNative", "(IIIIII)V", + (void*)gattClientStartBatchScanNative}, + {"gattClientStopBatchScanNative", "(I)V", + (void*)gattClientStopBatchScanNative}, + {"gattClientReadScanReportsNative", "(II)V", + (void*)gattClientReadScanReportsNative}, + // Scan filter JNI functions. + {"gattClientScanFilterParamAddNative", + "(Lcom/android/bluetooth/gatt/FilterParams;)V", + (void*)gattClientScanFilterParamAddNative}, + {"gattClientScanFilterParamDeleteNative", "(II)V", + (void*)gattClientScanFilterParamDeleteNative}, + {"gattClientScanFilterParamClearAllNative", "(I)V", + (void*)gattClientScanFilterParamClearAllNative}, + {"gattClientScanFilterAddNative", + "(I[Lcom/android/bluetooth/gatt/ScanFilterQueue$Entry;I)V", + (void*)gattClientScanFilterAddNative}, + {"gattClientScanFilterClearNative", "(II)V", + (void*)gattClientScanFilterClearNative}, + {"gattClientScanFilterEnableNative", "(IZ)V", + (void*)gattClientScanFilterEnableNative}, + {"gattSetScanParametersNative", "(III)V", + (void*)gattSetScanParametersNative}, + }; + return REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/gatt/ScanNativeInterface", methods); +} + +static int register_com_android_bluetooth_gatt_advertise_manager(JNIEnv* env) { + const JNINativeMethod methods[] = { + {"initializeNative", "()V", (void*)advertiseInitializeNative}, + {"cleanupNative", "()V", (void*)advertiseCleanupNative}, + {"startAdvertisingSetNative", + "(Landroid/bluetooth/le/AdvertisingSetParameters;" + "[B[BLandroid/bluetooth/le/PeriodicAdvertisingParameters;[BIIII)V", + (void*)startAdvertisingSetNative}, + {"stopAdvertisingSetNative", "(I)V", (void*)stopAdvertisingSetNative}, + {"getOwnAddressNative", "(I)V", (void*)getOwnAddressNative}, + {"enableAdvertisingSetNative", "(IZII)V", + (void*)enableAdvertisingSetNative}, + {"setAdvertisingDataNative", "(I[B)V", (void*)setAdvertisingDataNative}, + {"setScanResponseDataNative", "(I[B)V", (void*)setScanResponseDataNative}, + {"setAdvertisingParametersNative", + "(ILandroid/bluetooth/le/AdvertisingSetParameters;)V", + (void*)setAdvertisingParametersNative}, + {"setPeriodicAdvertisingParametersNative", + "(ILandroid/bluetooth/le/PeriodicAdvertisingParameters;)V", + (void*)setPeriodicAdvertisingParametersNative}, + {"setPeriodicAdvertisingDataNative", "(I[B)V", + (void*)setPeriodicAdvertisingDataNative}, + {"setPeriodicAdvertisingEnableNative", "(IZ)V", + (void*)setPeriodicAdvertisingEnableNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/gatt/AdvertiseManagerNativeInterface", + methods); + if (result != 0) { + return result; + } -int register_com_android_bluetooth_gatt(JNIEnv* env) { - int register_success = jniRegisterNativeMethods( - env, "com/android/bluetooth/gatt/ScanNativeInterface", sScanMethods, - NELEM(sScanMethods)); - register_success &= jniRegisterNativeMethods( - env, "com/android/bluetooth/gatt/AdvertiseManager", sAdvertiseMethods, - NELEM(sAdvertiseMethods)); - register_success &= jniRegisterNativeMethods( - env, "com/android/bluetooth/gatt/PeriodicScanManager", - sPeriodicScanMethods, NELEM(sPeriodicScanMethods)); - register_success &= jniRegisterNativeMethods( + const JNIJavaMethod javaMethods[] = { + {"onAdvertisingSetStarted", "(IIII)V", &method_onAdvertisingSetStarted}, + {"onOwnAddressRead", "(IILjava/lang/String;)V", &method_onOwnAddressRead}, + {"onAdvertisingEnabled", "(IZI)V", &method_onAdvertisingEnabled}, + {"onAdvertisingDataSet", "(II)V", &method_onAdvertisingDataSet}, + {"onScanResponseDataSet", "(II)V", &method_onScanResponseDataSet}, + {"onAdvertisingParametersUpdated", "(III)V", + &method_onAdvertisingParametersUpdated}, + {"onPeriodicAdvertisingParametersUpdated", "(II)V", + &method_onPeriodicAdvertisingParametersUpdated}, + {"onPeriodicAdvertisingDataSet", "(II)V", + &method_onPeriodicAdvertisingDataSet}, + {"onPeriodicAdvertisingEnabled", "(IZI)V", + &method_onPeriodicAdvertisingEnabled}, + }; + GET_JAVA_METHODS(env, + "com/android/bluetooth/gatt/AdvertiseManagerNativeInterface", + javaMethods); + + return 0; +} + +static int register_com_android_bluetooth_gatt_periodic_scan(JNIEnv* env) { + const JNINativeMethod methods[] = { + {"initializeNative", "()V", (void*)periodicScanInitializeNative}, + {"cleanupNative", "()V", (void*)periodicScanCleanupNative}, + {"startSyncNative", "(ILjava/lang/String;III)V", (void*)startSyncNative}, + {"stopSyncNative", "(I)V", (void*)stopSyncNative}, + {"cancelSyncNative", "(ILjava/lang/String;)V", (void*)cancelSyncNative}, + {"syncTransferNative", "(ILjava/lang/String;II)V", + (void*)syncTransferNative}, + {"transferSetInfoNative", "(ILjava/lang/String;II)V", + (void*)transferSetInfoNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/gatt/PeriodicScanNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onSyncStarted", "(IIIILjava/lang/String;III)V", &method_onSyncStarted}, + {"onSyncReport", "(IIII[B)V", &method_onSyncReport}, + {"onSyncLost", "(I)V", &method_onSyncLost}, + {"onSyncTransferredCallback", "(IILjava/lang/String;)V", + &method_onSyncTransferredCallback}, + {"onBigInfoReport", "(IZ)V", &method_onBigInfoReport}, + }; + GET_JAVA_METHODS(env, + "com/android/bluetooth/gatt/PeriodicScanNativeInterface", + javaMethods); + + return 0; +} + +static int register_com_android_bluetooth_gatt_distance_measurement( + JNIEnv* env) { + const JNINativeMethod methods[] = { + {"initializeNative", "()V", (void*)distanceMeasurementInitializeNative}, + {"cleanupNative", "()V", (void*)distanceMeasurementCleanupNative}, + {"startDistanceMeasurementNative", "(Ljava/lang/String;II)V", + (void*)startDistanceMeasurementNative}, + {"stopDistanceMeasurementNative", "(Ljava/lang/String;I)V", + (void*)stopDistanceMeasurementNative}, + }; + const int result = REGISTER_NATIVE_METHODS( env, "com/android/bluetooth/gatt/DistanceMeasurementNativeInterface", - sDistanceMeasurementMethods, NELEM(sDistanceMeasurementMethods)); - return register_success & - jniRegisterNativeMethods( - env, "com/android/bluetooth/gatt/GattNativeInterface", sMethods, - NELEM(sMethods)); + methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onDistanceMeasurementStarted", "(Ljava/lang/String;I)V", + &method_onDistanceMeasurementStarted}, + {"onDistanceMeasurementStartFail", "(Ljava/lang/String;II)V", + &method_onDistanceMeasurementStartFail}, + {"onDistanceMeasurementStopped", "(Ljava/lang/String;II)V", + &method_onDistanceMeasurementStopped}, + {"onDistanceMeasurementResult", "(Ljava/lang/String;IIIIIII)V", + &method_onDistanceMeasurementResult}, + }; + GET_JAVA_METHODS( + env, "com/android/bluetooth/gatt/DistanceMeasurementNativeInterface", + javaMethods); + + return 0; +} + +static int register_com_android_bluetooth_gatt_(JNIEnv* env) { + const JNINativeMethod methods[] = { + {"initializeNative", "()V", (void*)initializeNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"gattClientGetDeviceTypeNative", "(Ljava/lang/String;)I", + (void*)gattClientGetDeviceTypeNative}, + {"gattClientRegisterAppNative", "(JJZ)V", + (void*)gattClientRegisterAppNative}, + {"gattClientUnregisterAppNative", "(I)V", + (void*)gattClientUnregisterAppNative}, + {"gattClientConnectNative", "(ILjava/lang/String;IZIZI)V", + (void*)gattClientConnectNative}, + {"gattClientDisconnectNative", "(ILjava/lang/String;I)V", + (void*)gattClientDisconnectNative}, + {"gattClientSetPreferredPhyNative", "(ILjava/lang/String;III)V", + (void*)gattClientSetPreferredPhyNative}, + {"gattClientReadPhyNative", "(ILjava/lang/String;)V", + (void*)gattClientReadPhyNative}, + {"gattClientRefreshNative", "(ILjava/lang/String;)V", + (void*)gattClientRefreshNative}, + {"gattClientSearchServiceNative", "(IZJJ)V", + (void*)gattClientSearchServiceNative}, + {"gattClientDiscoverServiceByUuidNative", "(IJJ)V", + (void*)gattClientDiscoverServiceByUuidNative}, + {"gattClientGetGattDbNative", "(I)V", (void*)gattClientGetGattDbNative}, + {"gattClientReadCharacteristicNative", "(III)V", + (void*)gattClientReadCharacteristicNative}, + {"gattClientReadUsingCharacteristicUuidNative", "(IJJIII)V", + (void*)gattClientReadUsingCharacteristicUuidNative}, + {"gattClientReadDescriptorNative", "(III)V", + (void*)gattClientReadDescriptorNative}, + {"gattClientWriteCharacteristicNative", "(IIII[B)V", + (void*)gattClientWriteCharacteristicNative}, + {"gattClientWriteDescriptorNative", "(III[B)V", + (void*)gattClientWriteDescriptorNative}, + {"gattClientExecuteWriteNative", "(IZ)V", + (void*)gattClientExecuteWriteNative}, + {"gattClientRegisterForNotificationsNative", "(ILjava/lang/String;IZ)V", + (void*)gattClientRegisterForNotificationsNative}, + {"gattClientReadRemoteRssiNative", "(ILjava/lang/String;)V", + (void*)gattClientReadRemoteRssiNative}, + {"gattClientConfigureMTUNative", "(II)V", + (void*)gattClientConfigureMTUNative}, + {"gattConnectionParameterUpdateNative", "(ILjava/lang/String;IIIIII)V", + (void*)gattConnectionParameterUpdateNative}, + {"gattServerRegisterAppNative", "(JJZ)V", + (void*)gattServerRegisterAppNative}, + {"gattServerUnregisterAppNative", "(I)V", + (void*)gattServerUnregisterAppNative}, + {"gattServerConnectNative", "(ILjava/lang/String;ZI)V", + (void*)gattServerConnectNative}, + {"gattServerDisconnectNative", "(ILjava/lang/String;I)V", + (void*)gattServerDisconnectNative}, + {"gattServerSetPreferredPhyNative", "(ILjava/lang/String;III)V", + (void*)gattServerSetPreferredPhyNative}, + {"gattServerReadPhyNative", "(ILjava/lang/String;)V", + (void*)gattServerReadPhyNative}, + {"gattServerAddServiceNative", "(ILjava/util/List;)V", + (void*)gattServerAddServiceNative}, + {"gattServerStopServiceNative", "(II)V", + (void*)gattServerStopServiceNative}, + {"gattServerDeleteServiceNative", "(II)V", + (void*)gattServerDeleteServiceNative}, + {"gattServerSendIndicationNative", "(III[B)V", + (void*)gattServerSendIndicationNative}, + {"gattServerSendNotificationNative", "(III[B)V", + (void*)gattServerSendNotificationNative}, + {"gattServerSendResponseNative", "(IIIIII[BI)V", + (void*)gattServerSendResponseNative}, + {"gattSubrateRequestNative", "(ILjava/lang/String;IIIII)V", + (void*)gattSubrateRequestNative}, + + {"gattTestNative", "(IJJLjava/lang/String;IIIII)V", + (void*)gattTestNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/gatt/GattNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + // Client callbacks + {"onClientRegistered", "(IIJJ)V", &method_onClientRegistered}, + {"onScannerRegistered", "(IIJJ)V", &method_onScannerRegistered}, + {"onScanResult", "(IILjava/lang/String;IIIIII[BLjava/lang/String;)V", + &method_onScanResult}, + {"onConnected", "(IIILjava/lang/String;)V", &method_onConnected}, + {"onDisconnected", "(IIILjava/lang/String;)V", &method_onDisconnected}, + {"onReadCharacteristic", "(III[B)V", &method_onReadCharacteristic}, + {"onWriteCharacteristic", "(III[B)V", &method_onWriteCharacteristic}, + {"onExecuteCompleted", "(II)V", &method_onExecuteCompleted}, + {"onSearchCompleted", "(II)V", &method_onSearchCompleted}, + {"onReadDescriptor", "(III[B)V", &method_onReadDescriptor}, + {"onWriteDescriptor", "(III[B)V", &method_onWriteDescriptor}, + {"onNotify", "(ILjava/lang/String;IZ[B)V", &method_onNotify}, + {"onRegisterForNotifications", "(IIII)V", + &method_onRegisterForNotifications}, + {"onReadRemoteRssi", "(ILjava/lang/String;II)V", + &method_onReadRemoteRssi}, + {"onConfigureMTU", "(III)V", &method_onConfigureMTU}, + {"onScanFilterConfig", "(IIIII)V", &method_onScanFilterConfig}, + {"onScanFilterParamsConfigured", "(IIII)V", + &method_onScanFilterParamsConfigured}, + {"onScanFilterEnableDisabled", "(III)V", + &method_onScanFilterEnableDisabled}, + {"onClientCongestion", "(IZ)V", &method_onClientCongestion}, + {"onBatchScanStorageConfigured", "(II)V", + &method_onBatchScanStorageConfigured}, + {"onBatchScanStartStopped", "(III)V", &method_onBatchScanStartStopped}, + {"onBatchScanReports", "(IIII[B)V", &method_onBatchScanReports}, + {"onBatchScanThresholdCrossed", "(I)V", + &method_onBatchScanThresholdCrossed}, + {"createOnTrackAdvFoundLostObject", + "(II[BI[BIIILjava/lang/String;IIII)" + "Lcom/android/bluetooth/gatt/AdvtFilterOnFoundOnLostInfo;", + &method_createOnTrackAdvFoundLostObject}, + {"onTrackAdvFoundLost", + "(Lcom/android/bluetooth/gatt/AdvtFilterOnFoundOnLostInfo;)V", + &method_onTrackAdvFoundLost}, + {"onScanParamSetupCompleted", "(II)V", &method_onScanParamSetupCompleted}, + {"getSampleGattDbElement", "()Lcom/android/bluetooth/gatt/GattDbElement;", + &method_getSampleGattDbElement}, + {"onGetGattDb", "(ILjava/util/ArrayList;)V", &method_onGetGattDb}, + {"onClientPhyRead", "(ILjava/lang/String;III)V", &method_onClientPhyRead}, + {"onClientPhyUpdate", "(IIII)V", &method_onClientPhyUpdate}, + {"onClientConnUpdate", "(IIIII)V", &method_onClientConnUpdate}, + {"onServiceChanged", "(I)V", &method_onServiceChanged}, + {"onClientSubrateChange", "(IIIIII)V", &method_onClientSubrateChange}, + + // Server callbacks + {"onServerRegistered", "(IIJJ)V", &method_onServerRegistered}, + {"onClientConnected", "(Ljava/lang/String;ZII)V", + &method_onClientConnected}, + {"onServiceAdded", "(IILjava/util/List;)V", &method_onServiceAdded}, + {"onServiceStopped", "(III)V", &method_onServiceStopped}, + {"onServiceDeleted", "(III)V", &method_onServiceDeleted}, + {"onResponseSendCompleted", "(II)V", &method_onResponseSendCompleted}, + {"onServerReadCharacteristic", "(Ljava/lang/String;IIIIZ)V", + &method_onServerReadCharacteristic}, + {"onServerReadDescriptor", "(Ljava/lang/String;IIIIZ)V", + &method_onServerReadDescriptor}, + {"onServerWriteCharacteristic", "(Ljava/lang/String;IIIIIZZ[B)V", + &method_onServerWriteCharacteristic}, + {"onServerWriteDescriptor", "(Ljava/lang/String;IIIIIZZ[B)V", + &method_onServerWriteDescriptor}, + {"onExecuteWrite", "(Ljava/lang/String;III)V", &method_onExecuteWrite}, + {"onNotificationSent", "(II)V", &method_onNotificationSent}, + {"onServerCongestion", "(IZ)V", &method_onServerCongestion}, + {"onMtuChanged", "(II)V", &method_onServerMtuChanged}, + {"onServerPhyRead", "(ILjava/lang/String;III)V", &method_onServerPhyRead}, + {"onServerPhyUpdate", "(IIII)V", &method_onServerPhyUpdate}, + {"onServerConnUpdate", "(IIIII)V", &method_onServerConnUpdate}, + {"onServerSubrateChange", "(IIIIII)V", &method_onServerSubrateChange}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/gatt/GattNativeInterface", + javaMethods); + + return 0; +} + +int register_com_android_bluetooth_gatt(JNIEnv* env) { + const std::array, 5> register_fns = { + register_com_android_bluetooth_gatt_scan, + register_com_android_bluetooth_gatt_advertise_manager, + register_com_android_bluetooth_gatt_periodic_scan, + register_com_android_bluetooth_gatt_distance_measurement, + register_com_android_bluetooth_gatt_, + }; + + for (const auto& fn : register_fns) { + const int result = fn(env); + if (result != 0) { + return result; + } + } + return 0; } } // namespace android diff --git a/android/app/jni/com_android_bluetooth_hap_client.cpp b/android/app/jni/com_android_bluetooth_hap_client.cpp index 1d77a27eb33f000b2e6119b94c200f6dd681ad2f..067af34197bc08cf735b2ba8cd668da87a20c561 100644 --- a/android/app/jni/com_android_bluetooth_hap_client.cpp +++ b/android/app/jni/com_android_bluetooth_hap_client.cpp @@ -301,59 +301,6 @@ class HasClientCallbacksImpl : public HasClientCallbacks { static HasClientCallbacksImpl sHasClientCallbacks; -static void classInitNative(JNIEnv* env, jclass clazz) { - jclass jniBluetoothBluetoothHapPresetInfoClass = - env->FindClass("android/bluetooth/BluetoothHapPresetInfo"); - CHECK(jniBluetoothBluetoothHapPresetInfoClass != NULL); - - android_bluetooth_BluetoothHapPresetInfo.constructor = - env->GetMethodID(jniBluetoothBluetoothHapPresetInfoClass, "", - "(ILjava/lang/String;ZZ)V"); - - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); - - method_onDeviceAvailable = - env->GetMethodID(clazz, "onDeviceAvailable", "([BI)V"); - - method_onFeaturesUpdate = - env->GetMethodID(clazz, "onFeaturesUpdate", "([BI)V"); - - method_onActivePresetSelected = - env->GetMethodID(clazz, "onActivePresetSelected", "([BI)V"); - - method_onGroupActivePresetSelected = - env->GetMethodID(clazz, "onActivePresetGroupSelected", "(II)V"); - - method_onActivePresetSelectError = - env->GetMethodID(clazz, "onActivePresetSelectError", "([BI)V"); - - method_onGroupActivePresetSelectError = - env->GetMethodID(clazz, "onActivePresetGroupSelectError", "(II)V"); - - method_onPresetInfo = - env->GetMethodID(clazz, "onPresetInfo", - "([BI[Landroid/bluetooth/BluetoothHapPresetInfo;)V"); - - method_onGroupPresetInfo = - env->GetMethodID(clazz, "onGroupPresetInfo", - "(II[Landroid/bluetooth/BluetoothHapPresetInfo;)V"); - - method_onPresetNameSetError = - env->GetMethodID(clazz, "onPresetNameSetError", "([BII)V"); - - method_onGroupPresetNameSetError = - env->GetMethodID(clazz, "onGroupPresetNameSetError", "(III)V"); - - method_onPresetInfoError = - env->GetMethodID(clazz, "onPresetInfoError", "([BII)V"); - - method_onGroupPresetInfoError = - env->GetMethodID(clazz, "onGroupPresetInfoError", "(III)V"); - - LOG(INFO) << __func__ << ": succeeds"; -} - static void initNative(JNIEnv* env, jobject object) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -400,7 +347,7 @@ static void initNative(JNIEnv* env, jobject object) { sHasClientInterface->Init(&sHasClientCallbacks); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -421,7 +368,7 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectHapClientNative(JNIEnv* env, jobject object, +static jboolean connectHapClientNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { @@ -441,7 +388,7 @@ static jboolean connectHapClientNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean disconnectHapClientNative(JNIEnv* env, jobject object, +static jboolean disconnectHapClientNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { @@ -461,7 +408,7 @@ static jboolean disconnectHapClientNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static void selectActivePresetNative(JNIEnv* env, jobject object, +static void selectActivePresetNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint preset_index) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { @@ -480,8 +427,9 @@ static void selectActivePresetNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void groupSelectActivePresetNative(JNIEnv* env, jobject object, - jint group_id, jint preset_index) { +static void groupSelectActivePresetNative(JNIEnv* /* env */, + jobject /* object */, jint group_id, + jint preset_index) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; @@ -491,7 +439,7 @@ static void groupSelectActivePresetNative(JNIEnv* env, jobject object, sHasClientInterface->SelectActivePreset(group_id, preset_index); } -static void nextActivePresetNative(JNIEnv* env, jobject object, +static void nextActivePresetNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { @@ -510,7 +458,7 @@ static void nextActivePresetNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void groupNextActivePresetNative(JNIEnv* env, jobject object, +static void groupNextActivePresetNative(JNIEnv* /* env */, jobject /* object */, jint group_id) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { @@ -521,7 +469,7 @@ static void groupNextActivePresetNative(JNIEnv* env, jobject object, sHasClientInterface->NextActivePreset(group_id); } -static void previousActivePresetNative(JNIEnv* env, jobject object, +static void previousActivePresetNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { @@ -540,7 +488,8 @@ static void previousActivePresetNative(JNIEnv* env, jobject object, env->ReleaseByteArrayElements(address, addr, 0); } -static void groupPreviousActivePresetNative(JNIEnv* env, jobject object, +static void groupPreviousActivePresetNative(JNIEnv* /* env */, + jobject /* object */, jint group_id) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { @@ -551,8 +500,8 @@ static void groupPreviousActivePresetNative(JNIEnv* env, jobject object, sHasClientInterface->PreviousActivePreset(group_id); } -static void getPresetInfoNative(JNIEnv* env, jobject object, jbyteArray address, - jint preset_index) { +static void getPresetInfoNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jint preset_index) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; @@ -570,8 +519,9 @@ static void getPresetInfoNative(JNIEnv* env, jobject object, jbyteArray address, env->ReleaseByteArrayElements(address, addr, 0); } -static void setPresetNameNative(JNIEnv* env, jobject object, jbyteArray address, - jint preset_index, jstring name) { +static void setPresetNameNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jint preset_index, + jstring name) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; @@ -597,8 +547,9 @@ static void setPresetNameNative(JNIEnv* env, jobject object, jbyteArray address, env->ReleaseByteArrayElements(address, addr, 0); } -static void groupSetPresetNameNative(JNIEnv* env, jobject object, jint group_id, - jint preset_index, jstring name) { +static void groupSetPresetNameNative(JNIEnv* env, jobject /* object */, + jint group_id, jint preset_index, + jstring name) { std::shared_lock lock(interface_mutex); if (!sHasClientInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth HAP Interface"; @@ -616,30 +567,65 @@ static void groupSetPresetNameNative(JNIEnv* env, jobject object, jint group_id, std::move(name_str)); } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectHapClientNative", "([B)Z", (void*)connectHapClientNative}, - {"disconnectHapClientNative", "([B)Z", (void*)disconnectHapClientNative}, - {"selectActivePresetNative", "([BI)V", (void*)selectActivePresetNative}, - {"groupSelectActivePresetNative", "(II)V", - (void*)groupSelectActivePresetNative}, - {"nextActivePresetNative", "([B)V", (void*)nextActivePresetNative}, - {"groupNextActivePresetNative", "(I)V", (void*)groupNextActivePresetNative}, - {"previousActivePresetNative", "([B)V", (void*)previousActivePresetNative}, - {"groupPreviousActivePresetNative", "(I)V", - (void*)groupPreviousActivePresetNative}, - {"getPresetInfoNative", "([BI)V", (void*)getPresetInfoNative}, - {"setPresetNameNative", "([BILjava/lang/String;)V", - (void*)setPresetNameNative}, - {"groupSetPresetNameNative", "(IILjava/lang/String;)V", - (void*)groupSetPresetNameNative}, -}; - int register_com_android_bluetooth_hap_client(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/hap/HapClientNativeInterface", sMethods, - NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectHapClientNative", "([B)Z", (void*)connectHapClientNative}, + {"disconnectHapClientNative", "([B)Z", (void*)disconnectHapClientNative}, + {"selectActivePresetNative", "([BI)V", (void*)selectActivePresetNative}, + {"groupSelectActivePresetNative", "(II)V", + (void*)groupSelectActivePresetNative}, + {"nextActivePresetNative", "([B)V", (void*)nextActivePresetNative}, + {"groupNextActivePresetNative", "(I)V", + (void*)groupNextActivePresetNative}, + {"previousActivePresetNative", "([B)V", + (void*)previousActivePresetNative}, + {"groupPreviousActivePresetNative", "(I)V", + (void*)groupPreviousActivePresetNative}, + {"getPresetInfoNative", "([BI)V", (void*)getPresetInfoNative}, + {"setPresetNameNative", "([BILjava/lang/String;)V", + (void*)setPresetNameNative}, + {"groupSetPresetNameNative", "(IILjava/lang/String;)V", + (void*)groupSetPresetNameNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/hap/HapClientNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged}, + {"onDeviceAvailable", "([BI)V", &method_onDeviceAvailable}, + {"onFeaturesUpdate", "([BI)V", &method_onFeaturesUpdate}, + {"onActivePresetSelected", "([BI)V", &method_onActivePresetSelected}, + {"onActivePresetGroupSelected", "(II)V", + &method_onGroupActivePresetSelected}, + {"onActivePresetSelectError", "([BI)V", + &method_onActivePresetSelectError}, + {"onActivePresetGroupSelectError", "(II)V", + &method_onGroupActivePresetSelectError}, + {"onPresetInfo", "([BI[Landroid/bluetooth/BluetoothHapPresetInfo;)V", + &method_onPresetInfo}, + {"onGroupPresetInfo", "(II[Landroid/bluetooth/BluetoothHapPresetInfo;)V", + &method_onGroupPresetInfo}, + {"onPresetNameSetError", "([BII)V", &method_onPresetNameSetError}, + {"onGroupPresetNameSetError", "(III)V", + &method_onGroupPresetNameSetError}, + {"onPresetInfoError", "([BII)V", &method_onPresetInfoError}, + {"onGroupPresetInfoError", "(III)V", &method_onGroupPresetInfoError}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/hap/HapClientNativeInterface", + javaMethods); + + const JNIJavaMethod javaHapPresetMethods[] = { + {"", "(ILjava/lang/String;ZZ)V", + &android_bluetooth_BluetoothHapPresetInfo.constructor}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothHapPresetInfo", + javaHapPresetMethods); + + return 0; } } // namespace android diff --git a/android/app/jni/com_android_bluetooth_hearing_aid.cpp b/android/app/jni/com_android_bluetooth_hearing_aid.cpp index 5e2f88e680ae990d09019bfe45b3cf25864fa688..648ff8d1d1d87ca56795a71ae49f22f0b92b8ac0 100644 --- a/android/app/jni/com_android_bluetooth_hearing_aid.cpp +++ b/android/app/jni/com_android_bluetooth_hearing_aid.cpp @@ -87,16 +87,6 @@ class HearingAidCallbacksImpl : public HearingAidCallbacks { static HearingAidCallbacksImpl sHearingAidCallbacks; -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); - - method_onDeviceAvailable = - env->GetMethodID(clazz, "onDeviceAvailable", "(BJ[B)V"); - - LOG(INFO) << __func__ << ": succeeds"; -} - static void initNative(JNIEnv* env, jobject object) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -134,7 +124,7 @@ static void initNative(JNIEnv* env, jobject object) { sHearingAidInterface->Init(&sHearingAidCallbacks); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -155,7 +145,7 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectHearingAidNative(JNIEnv* env, jobject object, +static jboolean connectHearingAidNative(JNIEnv* env, jobject /* object */, jbyteArray address) { LOG(INFO) << __func__; std::shared_lock lock(interface_mutex); @@ -173,7 +163,7 @@ static jboolean connectHearingAidNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean disconnectHearingAidNative(JNIEnv* env, jobject object, +static jboolean disconnectHearingAidNative(JNIEnv* env, jobject /* object */, jbyteArray address) { LOG(INFO) << __func__; std::shared_lock lock(interface_mutex); @@ -191,8 +181,8 @@ static jboolean disconnectHearingAidNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean addToAcceptlistNative(JNIEnv* env, jobject object, - jbyteArray address) { +static jboolean addToAcceptlistNative(JNIEnv* env, jobject /* object */, + jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sHearingAidInterface) return JNI_FALSE; jbyte* addr = env->GetByteArrayElements(address, nullptr); @@ -207,7 +197,8 @@ static jboolean addToAcceptlistNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static void setVolumeNative(JNIEnv* env, jclass clazz, jint volume) { +static void setVolumeNative(JNIEnv* /* env */, jclass /* clazz */, + jint volume) { if (!sHearingAidInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth Hearing Aid Interface"; @@ -216,19 +207,31 @@ static void setVolumeNative(JNIEnv* env, jclass clazz, jint volume) { sHearingAidInterface->SetVolume(volume); } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectHearingAidNative", "([B)Z", (void*)connectHearingAidNative}, - {"disconnectHearingAidNative", "([B)Z", (void*)disconnectHearingAidNative}, - {"addToAcceptlistNative", "([B)Z", (void*)addToAcceptlistNative}, - {"setVolumeNative", "(I)V", (void*)setVolumeNative}, -}; - int register_com_android_bluetooth_hearing_aid(JNIEnv* env) { - return jniRegisterNativeMethods( + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectHearingAidNative", "([B)Z", (void*)connectHearingAidNative}, + {"disconnectHearingAidNative", "([B)Z", + (void*)disconnectHearingAidNative}, + {"addToAcceptlistNative", "([B)Z", (void*)addToAcceptlistNative}, + {"setVolumeNative", "(I)V", (void*)setVolumeNative}, + }; + const int result = REGISTER_NATIVE_METHODS( env, "com/android/bluetooth/hearingaid/HearingAidNativeInterface", - sMethods, NELEM(sMethods)); + methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged}, + {"onDeviceAvailable", "(BJ[B)V", &method_onDeviceAvailable}, + }; + GET_JAVA_METHODS(env, + "com/android/bluetooth/hearingaid/HearingAidNativeInterface", + javaMethods); + + return 0; } } // namespace android diff --git a/android/app/jni/com_android_bluetooth_hfp.cpp b/android/app/jni/com_android_bluetooth_hfp.cpp index ede3e134a36a32ed84ec4e61eea19668434cfde9..d33669f49150ef7743d6e2e85c023cf08b4eafb7 100644 --- a/android/app/jni/com_android_bluetooth_hfp.cpp +++ b/android/app/jni/com_android_bluetooth_hfp.cpp @@ -237,7 +237,8 @@ class JniHeadsetCallbacks : bluetooth::headset::Callbacks { addr.get()); } - void SwbCallback(bluetooth::headset::bthf_swb_config_t swb_config, + void SwbCallback(bluetooth::headset::bthf_swb_codec_t swb_codec, + bluetooth::headset::bthf_swb_config_t swb_config, RawAddress* bd_addr) override { std::shared_lock lock(callbacks_mutex); CallbackEnv sCallbackEnv(__func__); @@ -246,8 +247,8 @@ class JniHeadsetCallbacks : bluetooth::headset::Callbacks { ScopedLocalRef addr(sCallbackEnv.get(), marshall_bda(bd_addr)); if (addr.get() == nullptr) return; - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSWB, swb_config, - addr.get()); + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSWB, swb_codec, + swb_config, addr.get()); } void AtChldCallback(bluetooth::headset::bthf_chld_type_t chld, @@ -409,41 +410,16 @@ class JniHeadsetCallbacks : bluetooth::headset::Callbacks { sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtBia, service, roam, signal, battery, addr.get()); } -}; -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); - method_onAudioStateChanged = - env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V"); - method_onVrStateChanged = - env->GetMethodID(clazz, "onVrStateChanged", "(I[B)V"); - method_onAnswerCall = env->GetMethodID(clazz, "onAnswerCall", "([B)V"); - method_onHangupCall = env->GetMethodID(clazz, "onHangupCall", "([B)V"); - method_onVolumeChanged = - env->GetMethodID(clazz, "onVolumeChanged", "(II[B)V"); - method_onDialCall = - env->GetMethodID(clazz, "onDialCall", "(Ljava/lang/String;[B)V"); - method_onSendDtmf = env->GetMethodID(clazz, "onSendDtmf", "(I[B)V"); - method_onNoiseReductionEnable = - env->GetMethodID(clazz, "onNoiseReductionEnable", "(Z[B)V"); - method_onWBS = env->GetMethodID(clazz, "onWBS", "(I[B)V"); - method_onSWB = env->GetMethodID(clazz, "onSWB", "(I[B)V"); - method_onAtChld = env->GetMethodID(clazz, "onAtChld", "(I[B)V"); - method_onAtCnum = env->GetMethodID(clazz, "onAtCnum", "([B)V"); - method_onAtCind = env->GetMethodID(clazz, "onAtCind", "([B)V"); - method_onAtCops = env->GetMethodID(clazz, "onAtCops", "([B)V"); - method_onAtClcc = env->GetMethodID(clazz, "onAtClcc", "([B)V"); - method_onUnknownAt = - env->GetMethodID(clazz, "onUnknownAt", "(Ljava/lang/String;[B)V"); - method_onKeyPressed = env->GetMethodID(clazz, "onKeyPressed", "([B)V"); - method_onAtBind = - env->GetMethodID(clazz, "onATBind", "(Ljava/lang/String;[B)V"); - method_onAtBiev = env->GetMethodID(clazz, "onATBiev", "(II[B)V"); - method_onAtBia = env->GetMethodID(clazz, "onAtBia", "(ZZZZ[B)V"); - - ALOGI("%s: succeeds", __func__); -} + void DebugDumpCallback(bool /* active */, uint16_t /* codec_id */, + int /* total_num_decoded_frames */, + double /* pkt_loss_ratio */, uint64_t /* begin_ts */, + uint64_t /* end_ts */, + const char* /* pkt_status_in_hex */, + const char* /* pkt_status_in_binary */) override { + ALOGE("Not implemented and shouldn't be called"); + } +}; static void initializeNative(JNIEnv* env, jobject object, jint max_hf_clients, jboolean inband_ringing_enabled) { @@ -491,7 +467,7 @@ static void initializeNative(JNIEnv* env, jobject object, jint max_hf_clients, mCallbacksObj = env->NewGlobalRef(object); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -514,7 +490,7 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectHfpNative(JNIEnv* env, jobject object, +static jboolean connectHfpNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -537,7 +513,7 @@ static jboolean connectHfpNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean disconnectHfpNative(JNIEnv* env, jobject object, +static jboolean disconnectHfpNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -560,7 +536,7 @@ static jboolean disconnectHfpNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean connectAudioNative(JNIEnv* env, jobject object, +static jboolean connectAudioNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -576,7 +552,7 @@ static jboolean connectAudioNative(JNIEnv* env, jobject object, ALOGI("%s: device %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(*((RawAddress*)addr))); bt_status_t status = - sBluetoothHfpInterface->ConnectAudio((RawAddress*)addr, false); + sBluetoothHfpInterface->ConnectAudio((RawAddress*)addr, 0); if (status != BT_STATUS_SUCCESS) { ALOGE("Failed HF audio connection, status: %d", status); } @@ -584,7 +560,7 @@ static jboolean connectAudioNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean disconnectAudioNative(JNIEnv* env, jobject object, +static jboolean disconnectAudioNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -608,7 +584,8 @@ static jboolean disconnectAudioNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean isNoiseReductionSupportedNative(JNIEnv* env, jobject object, +static jboolean isNoiseReductionSupportedNative(JNIEnv* env, + jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -627,7 +604,8 @@ static jboolean isNoiseReductionSupportedNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean isVoiceRecognitionSupportedNative(JNIEnv* env, jobject object, +static jboolean isVoiceRecognitionSupportedNative(JNIEnv* env, + jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -646,7 +624,7 @@ static jboolean isVoiceRecognitionSupportedNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object, +static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -668,7 +646,7 @@ static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object, +static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -690,8 +668,9 @@ static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean setVolumeNative(JNIEnv* env, jobject object, jint volume_type, - jint volume, jbyteArray address) { +static jboolean setVolumeNative(JNIEnv* env, jobject /* object */, + jint volume_type, jint volume, + jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { ALOGW("%s: sBluetoothHfpInterface is null", __func__); @@ -713,7 +692,7 @@ static jboolean setVolumeNative(JNIEnv* env, jobject object, jint volume_type, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean notifyDeviceStatusNative(JNIEnv* env, jobject object, +static jboolean notifyDeviceStatusNative(JNIEnv* env, jobject /* object */, jint network_state, jint service_type, jint signal, jint battery_charge, jbyteArray address) { @@ -739,7 +718,7 @@ static jboolean notifyDeviceStatusNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean copsResponseNative(JNIEnv* env, jobject object, +static jboolean copsResponseNative(JNIEnv* env, jobject /* object */, jstring operator_str, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -763,8 +742,8 @@ static jboolean copsResponseNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean cindResponseNative(JNIEnv* env, jobject object, jint service, - jint num_active, jint num_held, +static jboolean cindResponseNative(JNIEnv* env, jobject /* object */, + jint service, jint num_active, jint num_held, jint call_state, jint signal, jint roam, jint battery_charge, jbyteArray address) { std::shared_lock lock(interface_mutex); @@ -789,7 +768,7 @@ static jboolean cindResponseNative(JNIEnv* env, jobject object, jint service, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean atResponseStringNative(JNIEnv* env, jobject object, +static jboolean atResponseStringNative(JNIEnv* env, jobject /* object */, jstring response_str, jbyteArray address) { std::shared_lock lock(interface_mutex); @@ -814,7 +793,7 @@ static jboolean atResponseStringNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean atResponseCodeNative(JNIEnv* env, jobject object, +static jboolean atResponseCodeNative(JNIEnv* env, jobject /* object */, jint response_code, jint cmee_code, jbyteArray address) { std::shared_lock lock(interface_mutex); @@ -838,10 +817,10 @@ static jboolean atResponseCodeNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean clccResponseNative(JNIEnv* env, jobject object, jint index, - jint dir, jint callStatus, jint mode, - jboolean mpty, jstring number_str, jint type, - jbyteArray address) { +static jboolean clccResponseNative(JNIEnv* env, jobject /* object */, + jint index, jint dir, jint callStatus, + jint mode, jboolean mpty, jstring number_str, + jint type, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { ALOGW("%s: sBluetoothHfpInterface is null", __func__); @@ -875,7 +854,7 @@ static jboolean clccResponseNative(JNIEnv* env, jobject object, jint index, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean phoneStateChangeNative(JNIEnv* env, jobject object, +static jboolean phoneStateChangeNative(JNIEnv* env, jobject /* object */, jint num_active, jint num_held, jint call_state, jstring number_str, jint type, jstring name_str, @@ -911,7 +890,7 @@ static jboolean phoneStateChangeNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean setScoAllowedNative(JNIEnv* env, jobject object, +static jboolean setScoAllowedNative(JNIEnv* /* env */, jobject /* object */, jboolean value) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -925,8 +904,8 @@ static jboolean setScoAllowedNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean sendBsirNative(JNIEnv* env, jobject object, jboolean value, - jbyteArray address) { +static jboolean sendBsirNative(JNIEnv* env, jobject /* object */, + jboolean value, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { ALOGW("%s: sBluetoothHfpInterface is null", __func__); @@ -947,7 +926,7 @@ static jboolean sendBsirNative(JNIEnv* env, jobject object, jboolean value, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, +static jboolean setActiveDeviceNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpInterface) { @@ -969,42 +948,73 @@ static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNative", "(IZ)V", (void*)initializeNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectHfpNative", "([B)Z", (void*)connectHfpNative}, - {"disconnectHfpNative", "([B)Z", (void*)disconnectHfpNative}, - {"connectAudioNative", "([B)Z", (void*)connectAudioNative}, - {"disconnectAudioNative", "([B)Z", (void*)disconnectAudioNative}, - {"isNoiseReductionSupportedNative", "([B)Z", - (void*)isNoiseReductionSupportedNative}, - {"isVoiceRecognitionSupportedNative", "([B)Z", - (void*)isVoiceRecognitionSupportedNative}, - {"startVoiceRecognitionNative", "([B)Z", - (void*)startVoiceRecognitionNative}, - {"stopVoiceRecognitionNative", "([B)Z", (void*)stopVoiceRecognitionNative}, - {"setVolumeNative", "(II[B)Z", (void*)setVolumeNative}, - {"notifyDeviceStatusNative", "(IIII[B)Z", (void*)notifyDeviceStatusNative}, - {"copsResponseNative", "(Ljava/lang/String;[B)Z", - (void*)copsResponseNative}, - {"cindResponseNative", "(IIIIIII[B)Z", (void*)cindResponseNative}, - {"atResponseStringNative", "(Ljava/lang/String;[B)Z", - (void*)atResponseStringNative}, - {"atResponseCodeNative", "(II[B)Z", (void*)atResponseCodeNative}, - {"clccResponseNative", "(IIIIZLjava/lang/String;I[B)Z", - (void*)clccResponseNative}, - {"phoneStateChangeNative", "(IIILjava/lang/String;ILjava/lang/String;[B)Z", - (void*)phoneStateChangeNative}, - {"setScoAllowedNative", "(Z)Z", (void*)setScoAllowedNative}, - {"sendBsirNative", "(Z[B)Z", (void*)sendBsirNative}, - {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, -}; - int register_com_android_bluetooth_hfp(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/hfp/HeadsetNativeInterface", sMethods, - NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initializeNative", "(IZ)V", (void*)initializeNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectHfpNative", "([B)Z", (void*)connectHfpNative}, + {"disconnectHfpNative", "([B)Z", (void*)disconnectHfpNative}, + {"connectAudioNative", "([B)Z", (void*)connectAudioNative}, + {"disconnectAudioNative", "([B)Z", (void*)disconnectAudioNative}, + {"isNoiseReductionSupportedNative", "([B)Z", + (void*)isNoiseReductionSupportedNative}, + {"isVoiceRecognitionSupportedNative", "([B)Z", + (void*)isVoiceRecognitionSupportedNative}, + {"startVoiceRecognitionNative", "([B)Z", + (void*)startVoiceRecognitionNative}, + {"stopVoiceRecognitionNative", "([B)Z", + (void*)stopVoiceRecognitionNative}, + {"setVolumeNative", "(II[B)Z", (void*)setVolumeNative}, + {"notifyDeviceStatusNative", "(IIII[B)Z", + (void*)notifyDeviceStatusNative}, + {"copsResponseNative", "(Ljava/lang/String;[B)Z", + (void*)copsResponseNative}, + {"cindResponseNative", "(IIIIIII[B)Z", (void*)cindResponseNative}, + {"atResponseStringNative", "(Ljava/lang/String;[B)Z", + (void*)atResponseStringNative}, + {"atResponseCodeNative", "(II[B)Z", (void*)atResponseCodeNative}, + {"clccResponseNative", "(IIIIZLjava/lang/String;I[B)Z", + (void*)clccResponseNative}, + {"phoneStateChangeNative", + "(IIILjava/lang/String;ILjava/lang/String;[B)Z", + (void*)phoneStateChangeNative}, + {"setScoAllowedNative", "(Z)Z", (void*)setScoAllowedNative}, + {"sendBsirNative", "(Z[B)Z", (void*)sendBsirNative}, + {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/hfp/HeadsetNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged}, + {"onAudioStateChanged", "(I[B)V", &method_onAudioStateChanged}, + {"onVrStateChanged", "(I[B)V", &method_onVrStateChanged}, + {"onAnswerCall", "([B)V", &method_onAnswerCall}, + {"onHangupCall", "([B)V", &method_onHangupCall}, + {"onVolumeChanged", "(II[B)V", &method_onVolumeChanged}, + {"onDialCall", "(Ljava/lang/String;[B)V", &method_onDialCall}, + {"onSendDtmf", "(I[B)V", &method_onSendDtmf}, + {"onNoiseReductionEnable", "(Z[B)V", &method_onNoiseReductionEnable}, + {"onWBS", "(I[B)V", &method_onWBS}, + {"onSWB", "(II[B)V", &method_onSWB}, + {"onAtChld", "(I[B)V", &method_onAtChld}, + {"onAtCnum", "([B)V", &method_onAtCnum}, + {"onAtCind", "([B)V", &method_onAtCind}, + {"onAtCops", "([B)V", &method_onAtCops}, + {"onAtClcc", "([B)V", &method_onAtClcc}, + {"onUnknownAt", "(Ljava/lang/String;[B)V", &method_onUnknownAt}, + {"onKeyPressed", "([B)V", &method_onKeyPressed}, + {"onATBind", "(Ljava/lang/String;[B)V", &method_onAtBind}, + {"onATBiev", "(II[B)V", &method_onAtBiev}, + {"onAtBia", "(ZZZZ[B)V", &method_onAtBia}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/hfp/HeadsetNativeInterface", + javaMethods); + + return 0; } } /* namespace android */ diff --git a/android/app/jni/com_android_bluetooth_hfpclient.cpp b/android/app/jni/com_android_bluetooth_hfpclient.cpp index d5756845d83163379a9b32981da60f5e99873a86..b5d5910372fc1e2bc30c483d4148d6d1ee48b3c2 100644 --- a/android/app/jni/com_android_bluetooth_hfpclient.cpp +++ b/android/app/jni/com_android_bluetooth_hfpclient.cpp @@ -429,42 +429,6 @@ static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = { unknown_event_cb, }; -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "(III[B)V"); - method_onAudioStateChanged = - env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V"); - method_onVrStateChanged = - env->GetMethodID(clazz, "onVrStateChanged", "(I[B)V"); - method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I[B)V"); - method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I[B)V"); - method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I[B)V"); - method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I[B)V"); - method_onCurrentOperator = - env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;[B)V"); - method_onCall = env->GetMethodID(clazz, "onCall", "(I[B)V"); - method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I[B)V"); - method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I[B)V"); - method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I[B)V"); - method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;[B)V"); - method_onCallWaiting = - env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;[B)V"); - method_onCurrentCalls = - env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;[B)V"); - method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II[B)V"); - method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II[B)V"); - method_onSubscriberInfo = - env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I[B)V"); - method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I[B)V"); - method_onLastVoiceTagNumber = - env->GetMethodID(clazz, "onLastVoiceTagNumber", "(Ljava/lang/String;[B)V"); - method_onRingIndication = env->GetMethodID(clazz, "onRingIndication", "([B)V"); - method_onUnknownEvent = - env->GetMethodID(clazz, "onUnknownEvent", "(Ljava/lang/String;[B)V"); - - ALOGI("%s succeeds", __func__); -} - static void initializeNative(JNIEnv* env, jobject object) { ALOGD("%s: HfpClient", __func__); std::unique_lock interface_lock(interface_mutex); @@ -507,7 +471,7 @@ static void initializeNative(JNIEnv* env, jobject object) { mCallbacksObj = env->NewGlobalRef(object); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -530,7 +494,8 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) { +static jboolean connectNative(JNIEnv* env, jobject /* object */, + jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -549,7 +514,7 @@ static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) { return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean disconnectNative(JNIEnv* env, jobject object, +static jboolean disconnectNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -569,7 +534,7 @@ static jboolean disconnectNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean connectAudioNative(JNIEnv* env, jobject object, +static jboolean connectAudioNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -589,7 +554,7 @@ static jboolean connectAudioNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean disconnectAudioNative(JNIEnv* env, jobject object, +static jboolean disconnectAudioNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -609,7 +574,7 @@ static jboolean disconnectAudioNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object, +static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -629,7 +594,7 @@ static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object, +static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -649,8 +614,9 @@ static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean setVolumeNative(JNIEnv* env, jobject object, jbyteArray address, - jint volume_type, jint volume) { +static jboolean setVolumeNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jint volume_type, + jint volume) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -669,8 +635,8 @@ static jboolean setVolumeNative(JNIEnv* env, jobject object, jbyteArray address, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean dialNative(JNIEnv* env, jobject object, jbyteArray address, - jstring number_str) { +static jboolean dialNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jstring number_str) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -698,7 +664,7 @@ static jboolean dialNative(JNIEnv* env, jobject object, jbyteArray address, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean dialMemoryNative(JNIEnv* env, jobject object, +static jboolean dialMemoryNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint location) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -719,7 +685,7 @@ static jboolean dialMemoryNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean handleCallActionNative(JNIEnv* env, jobject object, +static jboolean handleCallActionNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint action, jint index) { std::shared_lock lock(interface_mutex); @@ -741,7 +707,7 @@ static jboolean handleCallActionNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean queryCurrentCallsNative(JNIEnv* env, jobject object, +static jboolean queryCurrentCallsNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -762,7 +728,8 @@ static jboolean queryCurrentCallsNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean queryCurrentOperatorNameNative(JNIEnv* env, jobject object, +static jboolean queryCurrentOperatorNameNative(JNIEnv* env, + jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -784,7 +751,7 @@ static jboolean queryCurrentOperatorNameNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean retrieveSubscriberInfoNative(JNIEnv* env, jobject object, +static jboolean retrieveSubscriberInfoNative(JNIEnv* env, jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -805,8 +772,8 @@ static jboolean retrieveSubscriberInfoNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean sendDtmfNative(JNIEnv* env, jobject object, jbyteArray address, - jbyte code) { +static jboolean sendDtmfNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jbyte code) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -826,7 +793,8 @@ static jboolean sendDtmfNative(JNIEnv* env, jobject object, jbyteArray address, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean requestLastVoiceTagNumberNative(JNIEnv* env, jobject object, +static jboolean requestLastVoiceTagNumberNative(JNIEnv* env, + jobject /* object */, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -849,9 +817,9 @@ static jboolean requestLastVoiceTagNumberNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean sendATCmdNative(JNIEnv* env, jobject object, jbyteArray address, - jint cmd, jint val1, jint val2, - jstring arg_str) { +static jboolean sendATCmdNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jint cmd, jint val1, + jint val2, jstring arg_str) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -880,7 +848,7 @@ static jboolean sendATCmdNative(JNIEnv* env, jobject object, jbyteArray address, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean sendAndroidAtNative(JNIEnv* env, jobject object, +static jboolean sendAndroidAtNative(JNIEnv* env, jobject /* object */, jbyteArray address, jstring arg_str) { std::shared_lock lock(interface_mutex); if (!sBluetoothHfpClientInterface) return JNI_FALSE; @@ -911,38 +879,72 @@ static jboolean sendAndroidAtNative(JNIEnv* env, jobject object, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNative", "()V", (void*)initializeNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectNative", "([B)Z", (void*)connectNative}, - {"disconnectNative", "([B)Z", (void*)disconnectNative}, - {"connectAudioNative", "([B)Z", (void*)connectAudioNative}, - {"disconnectAudioNative", "([B)Z", (void*)disconnectAudioNative}, - {"startVoiceRecognitionNative", "([B)Z", - (void*)startVoiceRecognitionNative}, - {"stopVoiceRecognitionNative", "([B)Z", (void*)stopVoiceRecognitionNative}, - {"setVolumeNative", "([BII)Z", (void*)setVolumeNative}, - {"dialNative", "([BLjava/lang/String;)Z", (void*)dialNative}, - {"dialMemoryNative", "([BI)Z", (void*)dialMemoryNative}, - {"handleCallActionNative", "([BII)Z", (void*)handleCallActionNative}, - {"queryCurrentCallsNative", "([B)Z", (void*)queryCurrentCallsNative}, - {"queryCurrentOperatorNameNative", "([B)Z", - (void*)queryCurrentOperatorNameNative}, - {"retrieveSubscriberInfoNative", "([B)Z", - (void*)retrieveSubscriberInfoNative}, - {"sendDtmfNative", "([BB)Z", (void*)sendDtmfNative}, - {"requestLastVoiceTagNumberNative", "([B)Z", - (void*)requestLastVoiceTagNumberNative}, - {"sendATCmdNative", "([BIIILjava/lang/String;)Z", (void*)sendATCmdNative}, - {"sendAndroidAtNative", "([BLjava/lang/String;)Z", - (void*)sendAndroidAtNative}, -}; - int register_com_android_bluetooth_hfpclient(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/hfpclient/NativeInterface", - sMethods, NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initializeNative", "()V", (void*)initializeNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectNative", "([B)Z", (void*)connectNative}, + {"disconnectNative", "([B)Z", (void*)disconnectNative}, + {"connectAudioNative", "([B)Z", (void*)connectAudioNative}, + {"disconnectAudioNative", "([B)Z", (void*)disconnectAudioNative}, + {"startVoiceRecognitionNative", "([B)Z", + (void*)startVoiceRecognitionNative}, + {"stopVoiceRecognitionNative", "([B)Z", + (void*)stopVoiceRecognitionNative}, + {"setVolumeNative", "([BII)Z", (void*)setVolumeNative}, + {"dialNative", "([BLjava/lang/String;)Z", (void*)dialNative}, + {"dialMemoryNative", "([BI)Z", (void*)dialMemoryNative}, + {"handleCallActionNative", "([BII)Z", (void*)handleCallActionNative}, + {"queryCurrentCallsNative", "([B)Z", (void*)queryCurrentCallsNative}, + {"queryCurrentOperatorNameNative", "([B)Z", + (void*)queryCurrentOperatorNameNative}, + {"retrieveSubscriberInfoNative", "([B)Z", + (void*)retrieveSubscriberInfoNative}, + {"sendDtmfNative", "([BB)Z", (void*)sendDtmfNative}, + {"requestLastVoiceTagNumberNative", "([B)Z", + (void*)requestLastVoiceTagNumberNative}, + {"sendATCmdNative", "([BIIILjava/lang/String;)Z", (void*)sendATCmdNative}, + {"sendAndroidAtNative", "([BLjava/lang/String;)Z", + (void*)sendAndroidAtNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/hfpclient/NativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectionStateChanged", "(III[B)V", + &method_onConnectionStateChanged}, + {"onAudioStateChanged", "(I[B)V", &method_onAudioStateChanged}, + {"onVrStateChanged", "(I[B)V", &method_onVrStateChanged}, + {"onNetworkState", "(I[B)V", &method_onNetworkState}, + {"onNetworkRoaming", "(I[B)V", &method_onNetworkRoaming}, + {"onNetworkSignal", "(I[B)V", &method_onNetworkSignal}, + {"onBatteryLevel", "(I[B)V", &method_onBatteryLevel}, + {"onCurrentOperator", "(Ljava/lang/String;[B)V", + &method_onCurrentOperator}, + {"onCall", "(I[B)V", &method_onCall}, + {"onCallSetup", "(I[B)V", &method_onCallSetup}, + {"onCallHeld", "(I[B)V", &method_onCallHeld}, + {"onRespAndHold", "(I[B)V", &method_onRespAndHold}, + {"onClip", "(Ljava/lang/String;[B)V", &method_onClip}, + {"onCallWaiting", "(Ljava/lang/String;[B)V", &method_onCallWaiting}, + {"onCurrentCalls", "(IIIILjava/lang/String;[B)V", &method_onCurrentCalls}, + {"onVolumeChange", "(II[B)V", &method_onVolumeChange}, + {"onCmdResult", "(II[B)V", &method_onCmdResult}, + {"onSubscriberInfo", "(Ljava/lang/String;I[B)V", + &method_onSubscriberInfo}, + {"onInBandRing", "(I[B)V", &method_onInBandRing}, + {"onLastVoiceTagNumber", "(Ljava/lang/String;[B)V", + &method_onLastVoiceTagNumber}, + {"onRingIndication", "([B)V", &method_onRingIndication}, + {"onUnknownEvent", "(Ljava/lang/String;[B)V", &method_onUnknownEvent}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/hfpclient/NativeInterface", + javaMethods); + + return 0; } } /* 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 2146222acdb48f5c1e5849747b9646f95c9149d8..4a7c1553e1f45799ad12ac5b4f1e332909222302 100644 --- a/android/app/jni/com_android_bluetooth_hid_device.cpp +++ b/android/app/jni/com_android_bluetooth_hid_device.cpp @@ -150,21 +150,6 @@ static bthd_callbacks_t sHiddCb = { vc_unplug_callback, }; -static void classInitNative(JNIEnv* env, jclass clazz) { - ALOGV("%s: done", __FUNCTION__); - - method_onApplicationStateChanged = - env->GetMethodID(clazz, "onApplicationStateChanged", "([BZ)V"); - method_onConnectStateChanged = - env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V"); - method_onGetReport = env->GetMethodID(clazz, "onGetReport", "(BBS)V"); - method_onSetReport = env->GetMethodID(clazz, "onSetReport", "(BB[B)V"); - method_onSetProtocol = env->GetMethodID(clazz, "onSetProtocol", "(B)V"); - method_onInterruptData = env->GetMethodID(clazz, "onInterruptData", "(B[B)V"); - method_onVirtualCableUnplug = - env->GetMethodID(clazz, "onVirtualCableUnplug", "()V"); -} - static void initNative(JNIEnv* env, jobject object) { const bt_interface_t* btif; bt_status_t status; @@ -205,7 +190,7 @@ static void initNative(JNIEnv* env, jobject object) { ALOGV("%s done", __FUNCTION__); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { ALOGV("%s enter", __FUNCTION__); if (sHiddIf != NULL) { @@ -252,7 +237,7 @@ static void fill_qos(JNIEnv* env, jintArray in, bthd_qos_param_t* out) { free(buf); } -static jboolean registerAppNative(JNIEnv* env, jobject thiz, jstring name, +static jboolean registerAppNative(JNIEnv* env, jobject /* thiz */, jstring name, jstring description, jstring provider, jbyte subclass, jbyteArray descriptors, jintArray p_in_qos, jintArray p_out_qos) { @@ -306,7 +291,7 @@ static jboolean registerAppNative(JNIEnv* env, jobject thiz, jstring name, return result; } -static jboolean unregisterAppNative(JNIEnv* env, jobject thiz) { +static jboolean unregisterAppNative(JNIEnv* /* env */, jobject /* thiz */) { ALOGV("%s enter", __FUNCTION__); jboolean result = JNI_FALSE; @@ -329,7 +314,7 @@ static jboolean unregisterAppNative(JNIEnv* env, jobject thiz) { return result; } -static jboolean sendReportNative(JNIEnv* env, jobject thiz, jint id, +static jboolean sendReportNative(JNIEnv* env, jobject /* thiz */, jint id, jbyteArray data) { jboolean result = JNI_FALSE; @@ -360,7 +345,7 @@ static jboolean sendReportNative(JNIEnv* env, jobject thiz, jint id, return result; } -static jboolean replyReportNative(JNIEnv* env, jobject thiz, jbyte type, +static jboolean replyReportNative(JNIEnv* env, jobject /* thiz */, jbyte type, jbyte id, jbyteArray data) { ALOGV("%s enter", __FUNCTION__); @@ -397,7 +382,8 @@ static jboolean replyReportNative(JNIEnv* env, jobject thiz, jbyte type, return result; } -static jboolean reportErrorNative(JNIEnv* env, jobject thiz, jbyte error) { +static jboolean reportErrorNative(JNIEnv* /* env */, jobject /* thiz */, + jbyte error) { ALOGV("%s enter", __FUNCTION__); if (!sHiddIf) { @@ -420,7 +406,7 @@ static jboolean reportErrorNative(JNIEnv* env, jobject thiz, jbyte error) { return result; } -static jboolean unplugNative(JNIEnv* env, jobject thiz) { +static jboolean unplugNative(JNIEnv* /* env */, jobject /* thiz */) { ALOGV("%s enter", __FUNCTION__); if (!sHiddIf) { @@ -443,7 +429,8 @@ static jboolean unplugNative(JNIEnv* env, jobject thiz) { return result; } -static jboolean connectNative(JNIEnv* env, jobject thiz, jbyteArray address) { +static jboolean connectNative(JNIEnv* env, jobject /* thiz */, + jbyteArray address) { ALOGV("%s enter", __FUNCTION__); if (!sHiddIf) { @@ -472,7 +459,7 @@ static jboolean connectNative(JNIEnv* env, jobject thiz, jbyteArray address) { return result; } -static jboolean disconnectNative(JNIEnv* env, jobject thiz) { +static jboolean disconnectNative(JNIEnv* /* env */, jobject /* thiz */) { ALOGV("%s enter", __FUNCTION__); if (!sHiddIf) { @@ -495,25 +482,40 @@ static jboolean disconnectNative(JNIEnv* env, jobject thiz) { return result; } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"registerAppNative", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;B[B[I[I)Z", - (void*)registerAppNative}, - {"unregisterAppNative", "()Z", (void*)unregisterAppNative}, - {"sendReportNative", "(I[B)Z", (void*)sendReportNative}, - {"replyReportNative", "(BB[B)Z", (void*)replyReportNative}, - {"reportErrorNative", "(B)Z", (void*)reportErrorNative}, - {"unplugNative", "()Z", (void*)unplugNative}, - {"connectNative", "([B)Z", (void*)connectNative}, - {"disconnectNative", "()Z", (void*)disconnectNative}, -}; - int register_com_android_bluetooth_hid_device(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/hid/HidDeviceNativeInterface", sMethods, - NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"registerAppNative", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;B[B[I[I)Z", + (void*)registerAppNative}, + {"unregisterAppNative", "()Z", (void*)unregisterAppNative}, + {"sendReportNative", "(I[B)Z", (void*)sendReportNative}, + {"replyReportNative", "(BB[B)Z", (void*)replyReportNative}, + {"reportErrorNative", "(B)Z", (void*)reportErrorNative}, + {"unplugNative", "()Z", (void*)unplugNative}, + {"connectNative", "([B)Z", (void*)connectNative}, + {"disconnectNative", "()Z", (void*)disconnectNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/hid/HidDeviceNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onApplicationStateChanged", "([BZ)V", + &method_onApplicationStateChanged}, + {"onConnectStateChanged", "([BI)V", &method_onConnectStateChanged}, + {"onGetReport", "(BBS)V", &method_onGetReport}, + {"onSetReport", "(BB[B)V", &method_onSetReport}, + {"onSetProtocol", "(B)V", &method_onSetProtocol}, + {"onInterruptData", "(B[B)V", &method_onInterruptData}, + {"onVirtualCableUnplug", "()V", &method_onVirtualCableUnplug}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/hid/HidDeviceNativeInterface", + javaMethods); + + return 0; } } // 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 7a164233bc1b5d7e315691c80f0e5364db3b3666..e89ce844c29a069b47dcb90dfb7c7ebdbde3661a 100644 --- a/android/app/jni/com_android_bluetooth_hid_host.cpp +++ b/android/app/jni/com_android_bluetooth_hid_host.cpp @@ -161,7 +161,8 @@ static void handshake_callback(RawAddress* bd_addr, bthh_status_t hh_status) { (jint)hh_status); } -static void get_idle_time_callback(RawAddress* bd_addr, bthh_status_t hh_status, +static void get_idle_time_callback(RawAddress* bd_addr, + bthh_status_t /* hh_status */, int idle_time) { std::shared_lock lock(mCallbacks_mutex); CallbackEnv sCallbackEnv(__func__); @@ -187,20 +188,6 @@ static bthh_callbacks_t sBluetoothHidCallbacks = { handshake_callback}; // Define native functions - -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onConnectStateChanged = - env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V"); - method_onGetProtocolMode = - env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V"); - method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V"); - method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V"); - method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V"); - method_onGetIdleTime = env->GetMethodID(clazz, "onGetIdleTime", "([BI)V"); - - ALOGI("%s: succeeds", __func__); -} - static void initializeNative(JNIEnv* env, jobject object) { std::unique_lock lock(mCallbacks_mutex); const bt_interface_t* btInf = getBluetoothInterface(); @@ -238,7 +225,7 @@ static void initializeNative(JNIEnv* env, jobject object) { mCallbacksObj = env->NewGlobalRef(object); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock lock(mCallbacks_mutex); const bt_interface_t* btInf = getBluetoothInterface(); @@ -260,7 +247,7 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectHidNative(JNIEnv* env, jobject object, +static jboolean connectHidNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sBluetoothHidInterface) return JNI_FALSE; @@ -281,7 +268,7 @@ static jboolean connectHidNative(JNIEnv* env, jobject object, return ret; } -static jboolean disconnectHidNative(JNIEnv* env, jobject object, +static jboolean disconnectHidNative(JNIEnv* env, jobject /* object */, jbyteArray address) { jbyte* addr; jboolean ret = JNI_TRUE; @@ -303,7 +290,7 @@ static jboolean disconnectHidNative(JNIEnv* env, jobject object, return ret; } -static jboolean getProtocolModeNative(JNIEnv* env, jobject object, +static jboolean getProtocolModeNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sBluetoothHidInterface) return JNI_FALSE; @@ -327,7 +314,7 @@ static jboolean getProtocolModeNative(JNIEnv* env, jobject object, return ret; } -static jboolean virtualUnPlugNative(JNIEnv* env, jobject object, +static jboolean virtualUnPlugNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sBluetoothHidInterface) return JNI_FALSE; @@ -348,7 +335,7 @@ static jboolean virtualUnPlugNative(JNIEnv* env, jobject object, return ret; } -static jboolean setProtocolModeNative(JNIEnv* env, jobject object, +static jboolean setProtocolModeNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint protocolMode) { if (!sBluetoothHidInterface) return JNI_FALSE; @@ -385,9 +372,9 @@ static jboolean setProtocolModeNative(JNIEnv* env, jobject object, return ret; } -static jboolean getReportNative(JNIEnv* env, jobject object, jbyteArray address, - jbyte reportType, jbyte reportId, - jint bufferSize) { +static jboolean getReportNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jbyte reportType, + jbyte reportId, jint bufferSize) { ALOGV("%s: reportType = %d, reportId = %d, bufferSize = %d", __func__, reportType, reportId, bufferSize); if (!sBluetoothHidInterface) return JNI_FALSE; @@ -413,8 +400,9 @@ static jboolean getReportNative(JNIEnv* env, jobject object, jbyteArray address, return ret; } -static jboolean setReportNative(JNIEnv* env, jobject object, jbyteArray address, - jbyte reportType, jstring report) { +static jboolean setReportNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jbyte reportType, + jstring report) { ALOGV("%s: reportType = %d", __func__, reportType); if (!sBluetoothHidInterface) return JNI_FALSE; @@ -439,8 +427,8 @@ static jboolean setReportNative(JNIEnv* env, jobject object, jbyteArray address, return ret; } -static jboolean sendDataNative(JNIEnv* env, jobject object, jbyteArray address, - jstring report) { +static jboolean sendDataNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jstring report) { ALOGV("%s", __func__); jboolean ret = JNI_TRUE; if (!sBluetoothHidInterface) return JNI_FALSE; @@ -465,7 +453,7 @@ static jboolean sendDataNative(JNIEnv* env, jobject object, jbyteArray address, return ret; } -static jboolean getIdleTimeNative(JNIEnv* env, jobject object, +static jboolean getIdleTimeNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sBluetoothHidInterface) return JNI_FALSE; @@ -484,7 +472,7 @@ static jboolean getIdleTimeNative(JNIEnv* env, jobject object, return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE; } -static jboolean setIdleTimeNative(JNIEnv* env, jobject object, +static jboolean setIdleTimeNative(JNIEnv* env, jobject /* object */, jbyteArray address, jbyte idle_time) { if (!sBluetoothHidInterface) return JNI_FALSE; @@ -504,25 +492,39 @@ static jboolean setIdleTimeNative(JNIEnv* env, jobject object, return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE; } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNative", "()V", (void*)initializeNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectHidNative", "([B)Z", (void*)connectHidNative}, - {"disconnectHidNative", "([B)Z", (void*)disconnectHidNative}, - {"getProtocolModeNative", "([B)Z", (void*)getProtocolModeNative}, - {"virtualUnPlugNative", "([B)Z", (void*)virtualUnPlugNative}, - {"setProtocolModeNative", "([BB)Z", (void*)setProtocolModeNative}, - {"getReportNative", "([BBBI)Z", (void*)getReportNative}, - {"setReportNative", "([BBLjava/lang/String;)Z", (void*)setReportNative}, - {"sendDataNative", "([BLjava/lang/String;)Z", (void*)sendDataNative}, - {"getIdleTimeNative", "([B)Z", (void*)getIdleTimeNative}, - {"setIdleTimeNative", "([BB)Z", (void*)setIdleTimeNative}, -}; - int register_com_android_bluetooth_hid_host(JNIEnv* env) { - return jniRegisterNativeMethods(env, - "com/android/bluetooth/hid/HidHostService", - sMethods, NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initializeNative", "()V", (void*)initializeNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectHidNative", "([B)Z", (void*)connectHidNative}, + {"disconnectHidNative", "([B)Z", (void*)disconnectHidNative}, + {"getProtocolModeNative", "([B)Z", (void*)getProtocolModeNative}, + {"virtualUnPlugNative", "([B)Z", (void*)virtualUnPlugNative}, + {"setProtocolModeNative", "([BB)Z", (void*)setProtocolModeNative}, + {"getReportNative", "([BBBI)Z", (void*)getReportNative}, + {"setReportNative", "([BBLjava/lang/String;)Z", (void*)setReportNative}, + {"sendDataNative", "([BLjava/lang/String;)Z", (void*)sendDataNative}, + {"getIdleTimeNative", "([B)Z", (void*)getIdleTimeNative}, + {"setIdleTimeNative", "([BB)Z", (void*)setIdleTimeNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/hid/HidHostNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectStateChanged", "([BI)V", &method_onConnectStateChanged}, + {"onGetProtocolMode", "([BI)V", &method_onGetProtocolMode}, + {"onGetReport", "([B[BI)V", &method_onGetReport}, + {"onHandshake", "([BI)V", &method_onHandshake}, + {"onVirtualUnplug", "([BI)V", &method_onVirtualUnplug}, + {"onGetIdleTime", "([BI)V", &method_onGetIdleTime}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/hid/HidHostNativeInterface", + javaMethods); + + return 0; } + } // namespace android diff --git a/android/app/jni/com_android_bluetooth_le_audio.cpp b/android/app/jni/com_android_bluetooth_le_audio.cpp index e69bb25fdd4ec118093e22e8eaa304821cc52b5e..e6f07c48f5b6b720e1e722419bf243f2c2c94b89 100644 --- a/android/app/jni/com_android_bluetooth_le_audio.cpp +++ b/android/app/jni/com_android_bluetooth_le_audio.cpp @@ -27,8 +27,12 @@ using bluetooth::le_audio::BroadcastId; using bluetooth::le_audio::BroadcastState; +using bluetooth::le_audio::btle_audio_bits_per_sample_index_t; +using bluetooth::le_audio::btle_audio_channel_count_index_t; using bluetooth::le_audio::btle_audio_codec_config_t; using bluetooth::le_audio::btle_audio_codec_index_t; +using bluetooth::le_audio::btle_audio_frame_duration_index_t; +using bluetooth::le_audio::btle_audio_sample_rate_index_t; using bluetooth::le_audio::ConnectionState; using bluetooth::le_audio::GroupNodeStatus; using bluetooth::le_audio::GroupStatus; @@ -36,6 +40,7 @@ using bluetooth::le_audio::LeAudioBroadcasterCallbacks; using bluetooth::le_audio::LeAudioBroadcasterInterface; using bluetooth::le_audio::LeAudioClientCallbacks; using bluetooth::le_audio::LeAudioClientInterface; +using bluetooth::le_audio::UnicastMonitorModeStatus; namespace android { static jmethodID method_onInitialized; @@ -45,12 +50,22 @@ static jmethodID method_onGroupNodeStatus; static jmethodID method_onAudioConf; static jmethodID method_onSinkAudioLocationAvailable; static jmethodID method_onAudioLocalCodecCapabilities; -static jmethodID method_onAudioGroupCodecConf; +static jmethodID method_onAudioGroupCurrentCodecConf; +static jmethodID method_onAudioGroupSelectableCodecConf; +static jmethodID method_onHealthBasedRecommendationAction; +static jmethodID method_onHealthBasedGroupRecommendationAction; +static jmethodID method_onUnicastMonitorModeStatus; static struct { jclass clazz; jmethodID constructor; jmethodID getCodecType; + jmethodID getSampleRate; + jmethodID getBitsPerSample; + jmethodID getChannelCount; + jmethodID getFrameDuration; + jmethodID getOctetsPerFrame; + jmethodID getCodecPriority; } android_bluetooth_BluetoothLeAudioCodecConfig; static struct { @@ -97,10 +112,21 @@ static std::shared_timed_mutex callbacks_mutex; jobject prepareCodecConfigObj(JNIEnv* env, btle_audio_codec_config_t codecConfig) { - jobject codecConfigObj = - env->NewObject(android_bluetooth_BluetoothLeAudioCodecConfig.clazz, - android_bluetooth_BluetoothLeAudioCodecConfig.constructor, - (jint)codecConfig.codec_type, 0, 0, 0, 0, 0, 0, 0, 0); + LOG(INFO) << __func__ << "ct: " << codecConfig.codec_type + << ", codec_priority: " << codecConfig.codec_priority + << ", sample_rate: " << codecConfig.sample_rate + << ", bits_per_sample: " << codecConfig.bits_per_sample + << ", channel_count: " << codecConfig.channel_count + << ", frame_duration: " << codecConfig.frame_duration + << ", octets_per_frame: " << codecConfig.octets_per_frame; + + jobject codecConfigObj = env->NewObject( + android_bluetooth_BluetoothLeAudioCodecConfig.clazz, + android_bluetooth_BluetoothLeAudioCodecConfig.constructor, + (jint)codecConfig.codec_type, (jint)codecConfig.codec_priority, + (jint)codecConfig.sample_rate, (jint)codecConfig.bits_per_sample, + (jint)codecConfig.channel_count, (jint)codecConfig.frame_duration, + (jint)codecConfig.octets_per_frame, 0, 0); return codecConfigObj; } @@ -135,7 +161,8 @@ class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks { void OnConnectionState(ConnectionState state, const RawAddress& bd_addr) override { - LOG(INFO) << __func__ << ", state:" << int(state); + LOG(INFO) << __func__ << ", state:" << int(state) + << ", addr: " << bd_addr.ToRedactedStringForLogging(); std::shared_lock lock(callbacks_mutex); CallbackEnv sCallbackEnv(__func__); @@ -244,12 +271,9 @@ class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks { localInputCapCodecConfigArray, localOutputCapCodecConfigArray); } - void OnAudioGroupCodecConf( + void OnAudioGroupCurrentCodecConf( int group_id, btle_audio_codec_config_t input_codec_conf, - btle_audio_codec_config_t output_codec_conf, - std::vector input_selectable_codec_conf, - std::vector output_selectable_codec_conf) - override { + btle_audio_codec_config_t output_codec_conf) override { LOG(INFO) << __func__; std::shared_lock lock(callbacks_mutex); @@ -259,52 +283,89 @@ class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks { jobject inputCodecConfigObj = prepareCodecConfigObj(sCallbackEnv.get(), input_codec_conf); jobject outputCodecConfigObj = - prepareCodecConfigObj(sCallbackEnv.get(), input_codec_conf); + prepareCodecConfigObj(sCallbackEnv.get(), output_codec_conf); + + sCallbackEnv->CallVoidMethod( + mCallbacksObj, method_onAudioGroupCurrentCodecConf, (jint)group_id, + inputCodecConfigObj, outputCodecConfigObj); + } + + void OnAudioGroupSelectableCodecConf( + int group_id, + std::vector input_selectable_codec_conf, + std::vector output_selectable_codec_conf) + override { + LOG(INFO) << __func__; + + std::shared_lock lock(callbacks_mutex); + CallbackEnv sCallbackEnv(__func__); + if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; + jobject inputSelectableCodecConfigArray = prepareArrayOfCodecConfigs( sCallbackEnv.get(), input_selectable_codec_conf); jobject outputSelectableCodecConfigArray = prepareArrayOfCodecConfigs( sCallbackEnv.get(), output_selectable_codec_conf); sCallbackEnv->CallVoidMethod( - mCallbacksObj, method_onAudioGroupCodecConf, (jint)group_id, - inputCodecConfigObj, outputCodecConfigObj, + mCallbacksObj, method_onAudioGroupSelectableCodecConf, (jint)group_id, inputSelectableCodecConfigArray, outputSelectableCodecConfigArray); } + + void OnHealthBasedRecommendationAction( + const RawAddress& bd_addr, + bluetooth::le_audio::LeAudioHealthBasedAction action) override { + LOG(INFO) << __func__; + + std::shared_lock lock(callbacks_mutex); + CallbackEnv sCallbackEnv(__func__); + if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; + + ScopedLocalRef addr( + sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); + if (!addr.get()) { + LOG(ERROR) << "Failed to new jbyteArray bd addr for group status"; + return; + } + + sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), + (jbyte*)&bd_addr); + sCallbackEnv->CallVoidMethod(mCallbacksObj, + method_onHealthBasedRecommendationAction, + addr.get(), (jint)action); + } + + void OnHealthBasedGroupRecommendationAction( + int group_id, + bluetooth::le_audio::LeAudioHealthBasedAction action) override { + LOG(INFO) << __func__; + + std::shared_lock lock(callbacks_mutex); + CallbackEnv sCallbackEnv(__func__); + if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; + + sCallbackEnv->CallVoidMethod(mCallbacksObj, + method_onHealthBasedGroupRecommendationAction, + (jint)group_id, (jint)action); + } + + void OnUnicastMonitorModeStatus(uint8_t direction, + UnicastMonitorModeStatus status) override { + LOG(INFO) << __func__; + + std::shared_lock lock(callbacks_mutex); + CallbackEnv sCallbackEnv(__func__); + if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return; + + sCallbackEnv->CallVoidMethod(mCallbacksObj, + method_onUnicastMonitorModeStatus, + (jint)direction, (jint)status); + } }; static LeAudioClientCallbacksImpl sLeAudioClientCallbacks; -static void classInitNative(JNIEnv* env, jclass clazz) { - jclass jniBluetoothLeAudioCodecConfigClass = - env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfig"); - android_bluetooth_BluetoothLeAudioCodecConfig.constructor = env->GetMethodID( - jniBluetoothLeAudioCodecConfigClass, "", "(IIIIIIIII)V"); - android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType = env->GetMethodID( - jniBluetoothLeAudioCodecConfigClass, "getCodecType", "()I"); - - method_onGroupStatus = env->GetMethodID(clazz, "onGroupStatus", "(II)V"); - method_onGroupNodeStatus = - env->GetMethodID(clazz, "onGroupNodeStatus", "([BII)V"); - method_onAudioConf = env->GetMethodID(clazz, "onAudioConf", "(IIIII)V"); - method_onSinkAudioLocationAvailable = - env->GetMethodID(clazz, "onSinkAudioLocationAvailable", "([BI)V"); - method_onInitialized = env->GetMethodID(clazz, "onInitialized", "()V"); - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); - method_onAudioLocalCodecCapabilities = - env->GetMethodID(clazz, "onAudioLocalCodecCapabilities", - "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;" - "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V"); - method_onAudioGroupCodecConf = - env->GetMethodID(clazz, "onAudioGroupCodecConf", - "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;" - "Landroid/bluetooth/BluetoothLeAudioCodecConfig;" - "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;" - "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V"); -} - std::vector prepareCodecPreferences( - JNIEnv* env, jobject object, jobjectArray codecConfigArray) { + JNIEnv* env, jobject /* object */, jobjectArray codecConfigArray) { std::vector codec_preferences; int numConfigs = env->GetArrayLength(codecConfigArray); @@ -375,7 +436,7 @@ static void initNative(JNIEnv* env, jobject object, codec_offloading); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -399,7 +460,7 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectLeAudioNative(JNIEnv* env, jobject object, +static jboolean connectLeAudioNative(JNIEnv* env, jobject /* object */, jbyteArray address) { LOG(INFO) << __func__; std::shared_lock lock(interface_mutex); @@ -417,7 +478,7 @@ static jboolean connectLeAudioNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean disconnectLeAudioNative(JNIEnv* env, jobject object, +static jboolean disconnectLeAudioNative(JNIEnv* env, jobject /* object */, jbyteArray address) { LOG(INFO) << __func__; std::shared_lock lock(interface_mutex); @@ -435,7 +496,7 @@ static jboolean disconnectLeAudioNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean setEnableStateNative(JNIEnv* env, jobject object, +static jboolean setEnableStateNative(JNIEnv* env, jobject /* object */, jbyteArray address, jboolean enabled) { std::shared_lock lock(interface_mutex); jbyte* addr = env->GetByteArrayElements(address, nullptr); @@ -456,8 +517,8 @@ static jboolean setEnableStateNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean groupAddNodeNative(JNIEnv* env, jobject object, jint group_id, - jbyteArray address) { +static jboolean groupAddNodeNative(JNIEnv* env, jobject /* object */, + jint group_id, jbyteArray address) { std::shared_lock lock(interface_mutex); jbyte* addr = env->GetByteArrayElements(address, nullptr); @@ -478,7 +539,7 @@ static jboolean groupAddNodeNative(JNIEnv* env, jobject object, jint group_id, return JNI_TRUE; } -static jboolean groupRemoveNodeNative(JNIEnv* env, jobject object, +static jboolean groupRemoveNodeNative(JNIEnv* env, jobject /* object */, jint group_id, jbyteArray address) { std::shared_lock lock(interface_mutex); if (!sLeAudioClientInterface) { @@ -498,7 +559,8 @@ static jboolean groupRemoveNodeNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static void groupSetActiveNative(JNIEnv* env, jobject object, jint group_id) { +static void groupSetActiveNative(JNIEnv* /* env */, jobject /* object */, + jint group_id) { LOG(INFO) << __func__; std::shared_lock lock(interface_mutex); @@ -510,7 +572,7 @@ static void groupSetActiveNative(JNIEnv* env, jobject object, jint group_id) { sLeAudioClientInterface->GroupSetActive(group_id); } -static void setCodecConfigPreferenceNative(JNIEnv* env, jobject object, +static void setCodecConfigPreferenceNative(JNIEnv* env, jobject /* object */, jint group_id, jobject inputCodecConfig, jobject outputCodecConfig) { @@ -528,22 +590,92 @@ static void setCodecConfigPreferenceNative(JNIEnv* env, jobject object, inputCodecConfig, android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType); + jint inputSampleRate = env->CallIntMethod( + inputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getSampleRate); + + jint inputBitsPerSample = env->CallIntMethod( + inputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getBitsPerSample); + + jint inputChannelCount = env->CallIntMethod( + inputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getChannelCount); + + jint inputFrameDuration = env->CallIntMethod( + inputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getFrameDuration); + + jint inputOctetsPerFrame = env->CallIntMethod( + inputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getOctetsPerFrame); + + jint inputCodecPriority = env->CallIntMethod( + inputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getCodecPriority); + btle_audio_codec_config_t input_codec_config = { - .codec_type = static_cast(inputCodecType)}; + .codec_type = static_cast(inputCodecType), + .sample_rate = + static_cast(inputSampleRate), + .bits_per_sample = + static_cast(inputBitsPerSample), + .channel_count = + static_cast(inputChannelCount), + .frame_duration = + static_cast(inputFrameDuration), + .octets_per_frame = static_cast(inputOctetsPerFrame), + .codec_priority = static_cast(inputCodecPriority), + }; jint outputCodecType = env->CallIntMethod( outputCodecConfig, android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType); + jint outputSampleRate = env->CallIntMethod( + outputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getSampleRate); + + jint outputBitsPerSample = env->CallIntMethod( + outputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getBitsPerSample); + + jint outputChannelCount = env->CallIntMethod( + outputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getChannelCount); + + jint outputFrameDuration = env->CallIntMethod( + outputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getFrameDuration); + + jint outputOctetsPerFrame = env->CallIntMethod( + outputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getOctetsPerFrame); + + jint outputCodecPriority = env->CallIntMethod( + outputCodecConfig, + android_bluetooth_BluetoothLeAudioCodecConfig.getCodecPriority); + btle_audio_codec_config_t output_codec_config = { - .codec_type = static_cast(outputCodecType)}; + .codec_type = static_cast(outputCodecType), + .sample_rate = + static_cast(outputSampleRate), + .bits_per_sample = + static_cast(outputBitsPerSample), + .channel_count = + static_cast(outputChannelCount), + .frame_duration = + static_cast(outputFrameDuration), + .octets_per_frame = static_cast(outputOctetsPerFrame), + .codec_priority = static_cast(outputCodecPriority), + }; sLeAudioClientInterface->SetCodecConfigPreference( group_id, input_codec_config, output_codec_config); } -static void setCcidInformationNative(JNIEnv* env, jobject object, jint ccid, - jint contextType) { +static void setCcidInformationNative(JNIEnv* /* env */, jobject /* object */, + jint ccid, jint contextType) { std::shared_lock lock(interface_mutex); if (!sLeAudioClientInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface"; @@ -553,7 +685,8 @@ static void setCcidInformationNative(JNIEnv* env, jobject object, jint ccid, sLeAudioClientInterface->SetCcidInformation(ccid, contextType); } -static void setInCallNative(JNIEnv* env, jobject object, jboolean inCall) { +static void setInCallNative(JNIEnv* /* env */, jobject /* object */, + jboolean inCall) { std::shared_lock lock(interface_mutex); if (!sLeAudioClientInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface"; @@ -563,8 +696,19 @@ static void setInCallNative(JNIEnv* env, jobject object, jboolean inCall) { sLeAudioClientInterface->SetInCall(inCall); } +static void setUnicastMonitorModeNative(JNIEnv* /* env */, jobject /* object */, + jint direction, jboolean enable) { + std::shared_lock lock(interface_mutex); + if (!sLeAudioClientInterface) { + LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface"; + return; + } + + sLeAudioClientInterface->SetUnicastMonitorMode(direction, enable); +} + static void sendAudioProfilePreferencesNative( - JNIEnv* env, jint groupId, jboolean isOutputPreferenceLeAudio, + JNIEnv* /* env */, jint groupId, jboolean isOutputPreferenceLeAudio, jboolean isDuplexPreferenceLeAudio) { std::shared_lock lock(interface_mutex); if (!sLeAudioClientInterface) { @@ -576,27 +720,6 @@ static void sendAudioProfilePreferencesNative( groupId, isOutputPreferenceLeAudio, isDuplexPreferenceLeAudio); } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V", - (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectLeAudioNative", "([B)Z", (void*)connectLeAudioNative}, - {"disconnectLeAudioNative", "([B)Z", (void*)disconnectLeAudioNative}, - {"setEnableStateNative", "([BZ)Z", (void*)setEnableStateNative}, - {"groupAddNodeNative", "(I[B)Z", (void*)groupAddNodeNative}, - {"groupRemoveNodeNative", "(I[B)Z", (void*)groupRemoveNodeNative}, - {"groupSetActiveNative", "(I)V", (void*)groupSetActiveNative}, - {"setCodecConfigPreferenceNative", - "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;Landroid/bluetooth/" - "BluetoothLeAudioCodecConfig;)V", - (void*)setCodecConfigPreferenceNative}, - {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative}, - {"setInCallNative", "(Z)V", (void*)setInCallNative}, - {"sendAudioProfilePreferencesNative", "(IZZ)V", - (void*)sendAudioProfilePreferencesNative}, -}; - /* Le Audio Broadcaster */ static jmethodID method_onBroadcastCreated; static jmethodID method_onBroadcastDestroyed; @@ -656,47 +779,43 @@ static jlong getAudioLocationOrDefault( const std::map>& metadata, jlong default_location) { if (metadata.count( - bluetooth::le_audio::kLeAudioCodecLC3TypeAudioChannelAllocation) == 0) + bluetooth::le_audio::kLeAudioLtvTypeAudioChannelAllocation) == 0) return default_location; - auto& vec = metadata.at( - bluetooth::le_audio::kLeAudioCodecLC3TypeAudioChannelAllocation); + auto& vec = + metadata.at(bluetooth::le_audio::kLeAudioLtvTypeAudioChannelAllocation); return VEC_UINT8_TO_UINT32(vec); } static jint getSamplingFrequencyOrDefault( const std::map>& metadata, jint default_sampling_frequency) { - if (metadata.count(bluetooth::le_audio::kLeAudioCodecLC3TypeSamplingFreq) == - 0) + if (metadata.count(bluetooth::le_audio::kLeAudioLtvTypeSamplingFreq) == 0) return default_sampling_frequency; - auto& vec = - metadata.at(bluetooth::le_audio::kLeAudioCodecLC3TypeSamplingFreq); + auto& vec = metadata.at(bluetooth::le_audio::kLeAudioLtvTypeSamplingFreq); return (jint)(vec.data()[0]); } static jint getFrameDurationOrDefault( const std::map>& metadata, jint default_frame_duration) { - if (metadata.count(bluetooth::le_audio::kLeAudioCodecLC3TypeFrameDuration) == - 0) + if (metadata.count(bluetooth::le_audio::kLeAudioLtvTypeFrameDuration) == 0) return default_frame_duration; - auto& vec = - metadata.at(bluetooth::le_audio::kLeAudioCodecLC3TypeFrameDuration); + auto& vec = metadata.at(bluetooth::le_audio::kLeAudioLtvTypeFrameDuration); return (jint)(vec.data()[0]); } static jint getOctetsPerFrameOrDefault( const std::map>& metadata, jint default_octets_per_frame) { - if (metadata.count(bluetooth::le_audio::kLeAudioCodecLC3TypeOctetPerFrame) == + if (metadata.count(bluetooth::le_audio::kLeAudioLtvTypeOctetsPerCodecFrame) == 0) return default_octets_per_frame; auto& vec = - metadata.at(bluetooth::le_audio::kLeAudioCodecLC3TypeOctetPerFrame); + metadata.at(bluetooth::le_audio::kLeAudioLtvTypeOctetsPerCodecFrame); return VEC_UINT8_TO_UINT16(vec); } @@ -745,11 +864,15 @@ jobject prepareLeAudioContentMetadataObject( JNIEnv* env, const std::map>& metadata) { jstring program_info_str = nullptr; if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo)) { - program_info_str = env->NewStringUTF( - (const char*)(metadata - .at(bluetooth::le_audio:: - kLeAudioMetadataTypeProgramInfo) - .data())); + // Convert the metadata vector to string with null terminator + std::string p_str( + (const char*)metadata + .at(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo) + .data(), + metadata.at(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo) + .size()); + + program_info_str = env->NewStringUTF(p_str.c_str()); if (!program_info_str) { LOG(ERROR) << "Failed to create new preset name String for preset name"; return nullptr; @@ -758,10 +881,14 @@ jobject prepareLeAudioContentMetadataObject( jstring language_str = nullptr; if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)) { - language_str = env->NewStringUTF( - (const char*)(metadata - .at(bluetooth::le_audio::kLeAudioMetadataTypeLanguage) - .data())); + // Convert the metadata vector to string with null terminator + std::string l_str( + (const char*)metadata + .at(bluetooth::le_audio::kLeAudioMetadataTypeLanguage) + .data(), + metadata.at(bluetooth::le_audio::kLeAudioMetadataTypeLanguage).size()); + + language_str = env->NewStringUTF(l_str.c_str()); if (!language_str) { LOG(ERROR) << "Failed to create new preset name String for language"; return nullptr; @@ -918,16 +1045,14 @@ jobject prepareBluetoothLeBroadcastMetadataObject( return nullptr; } - // Skip the leading null char bytes + // Remove the ending null char bytes int nativeCodeSize = 16; - int nativeCodeLeadingZeros = 0; if (broadcast_metadata.broadcast_code) { auto& nativeCode = broadcast_metadata.broadcast_code.value(); - nativeCodeLeadingZeros = + nativeCodeSize = std::find_if(nativeCode.cbegin(), nativeCode.cend(), - [](int x) { return x != 0x00; }) - + [](int x) { return x == 0x00; }) - nativeCode.cbegin(); - nativeCodeSize = nativeCode.size() - nativeCodeLeadingZeros; } ScopedLocalRef code(env, env->NewByteArray(nativeCodeSize)); @@ -939,8 +1064,7 @@ jobject prepareBluetoothLeBroadcastMetadataObject( if (broadcast_metadata.broadcast_code) { env->SetByteArrayRegion( code.get(), 0, nativeCodeSize, - (const jbyte*)broadcast_metadata.broadcast_code->data() + - nativeCodeLeadingZeros); + (const jbyte*)broadcast_metadata.broadcast_code->data()); CHECK(!env->ExceptionCheck()); } @@ -980,8 +1104,9 @@ jobject prepareBluetoothLeBroadcastMetadataObject( broadcast_metadata.broadcast_code ? true : false, broadcast_metadata.is_public, broadcast_name.get(), broadcast_metadata.broadcast_code ? code.get() : nullptr, - (jint)broadcast_metadata.basic_audio_announcement.presentation_delay, - audio_cfg_quality, public_meta_obj.get(), subgroup_list_obj.get()); + (jint)broadcast_metadata.basic_audio_announcement.presentation_delay_us, + audio_cfg_quality, (jint)bluetooth::le_audio::kLeAudioSourceRssiUnknown, + public_meta_obj.get(), subgroup_list_obj.get()); } class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks { @@ -1047,63 +1172,6 @@ class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks { static LeAudioBroadcasterCallbacksImpl sLeAudioBroadcasterCallbacks; -static void BroadcasterClassInitNative(JNIEnv* env, jclass clazz) { - method_onBroadcastCreated = - env->GetMethodID(clazz, "onBroadcastCreated", "(IZ)V"); - method_onBroadcastDestroyed = - env->GetMethodID(clazz, "onBroadcastDestroyed", "(I)V"); - method_onBroadcastStateChanged = - env->GetMethodID(clazz, "onBroadcastStateChanged", "(II)V"); - method_onBroadcastMetadataChanged = - env->GetMethodID(clazz, "onBroadcastMetadataChanged", - "(ILandroid/bluetooth/BluetoothLeBroadcastMetadata;)V"); - - jclass jniArrayListClass = env->FindClass("java/util/ArrayList"); - java_util_ArrayList.constructor = - env->GetMethodID(jniArrayListClass, "", "()V"); - java_util_ArrayList.add = - env->GetMethodID(jniArrayListClass, "add", "(Ljava/lang/Object;)Z"); - - jclass jniBluetoothLeAudioCodecConfigMetadataClass = - env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfigMetadata"); - android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor = - env->GetMethodID(jniBluetoothLeAudioCodecConfigMetadataClass, "", - "(JIII[B)V"); - - jclass jniBluetoothLeAudioContentMetadataClass = - env->FindClass("android/bluetooth/BluetoothLeAudioContentMetadata"); - android_bluetooth_BluetoothLeAudioContentMetadata.constructor = - env->GetMethodID(jniBluetoothLeAudioContentMetadataClass, "", - "(Ljava/lang/String;Ljava/lang/String;[B)V"); - - jclass jniBluetoothLeBroadcastChannelClass = - env->FindClass("android/bluetooth/BluetoothLeBroadcastChannel"); - android_bluetooth_BluetoothLeBroadcastChannel.constructor = env->GetMethodID( - jniBluetoothLeBroadcastChannelClass, "", - "(ZILandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;)V"); - - jclass jniBluetoothLeBroadcastSubgroupClass = - env->FindClass("android/bluetooth/BluetoothLeBroadcastSubgroup"); - android_bluetooth_BluetoothLeBroadcastSubgroup.constructor = env->GetMethodID( - jniBluetoothLeBroadcastSubgroupClass, "", - "(JLandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;" - "Landroid/bluetooth/BluetoothLeAudioContentMetadata;" - "Ljava/util/List;)V"); - - jclass jniBluetoothDeviceClass = - env->FindClass("android/bluetooth/BluetoothDevice"); - android_bluetooth_BluetoothDevice.constructor = env->GetMethodID( - jniBluetoothDeviceClass, "", "(Ljava/lang/String;I)V"); - - jclass jniBluetoothLeBroadcastMetadataClass = - env->FindClass("android/bluetooth/BluetoothLeBroadcastMetadata"); - android_bluetooth_BluetoothLeBroadcastMetadata.constructor = env->GetMethodID( - jniBluetoothLeBroadcastMetadataClass, "", - "(ILandroid/bluetooth/BluetoothDevice;IIIZZLjava/lang/String;" - "[BIILandroid/bluetooth/BluetoothLeAudioContentMetadata;" - "Ljava/util/List;)V"); -} - static void BroadcasterInitNative(JNIEnv* env, jobject object) { std::unique_lock interface_lock( sBroadcasterInterfaceMutex); @@ -1198,7 +1266,7 @@ static void BroadcasterInitNative(JNIEnv* env, jobject object) { sLeAudioBroadcasterInterface->Initialize(&sLeAudioBroadcasterCallbacks); } -static void BroadcasterStopNative(JNIEnv* env, jobject object) { +static void BroadcasterStopNative(JNIEnv* /* env */, jobject /* object */) { std::unique_lock interface_lock( sBroadcasterInterfaceMutex); @@ -1212,7 +1280,7 @@ static void BroadcasterStopNative(JNIEnv* env, jobject object) { sLeAudioBroadcasterInterface->Stop(); } -static void BroadcasterCleanupNative(JNIEnv* env, jobject object) { +static void BroadcasterCleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock( sBroadcasterInterfaceMutex); std::unique_lock callbacks_lock( @@ -1274,7 +1342,7 @@ std::vector> convertToDataVectors(JNIEnv* env, return res; } -static void CreateBroadcastNative(JNIEnv* env, jobject object, +static void CreateBroadcastNative(JNIEnv* env, jobject /* object */, jboolean isPublic, jstring broadcastName, jbyteArray broadcast_code, jbyteArray publicMetadata, @@ -1328,8 +1396,8 @@ static void CreateBroadcastNative(JNIEnv* env, jobject object, if (quality_array) env->ReleaseIntArrayElements(qualityArray, quality_array, 0); } -static void UpdateMetadataNative(JNIEnv* env, jobject object, jint broadcast_id, - jstring broadcastName, +static void UpdateMetadataNative(JNIEnv* env, jobject /* object */, + jint broadcast_id, jstring broadcastName, jbyteArray publicMetadata, jobjectArray metadataArray) { const char* broadcast_name = nullptr; @@ -1354,7 +1422,7 @@ static void UpdateMetadataNative(JNIEnv* env, jobject object, jint broadcast_id, if (public_meta) env->ReleaseByteArrayElements(publicMetadata, public_meta, 0); } -static void StartBroadcastNative(JNIEnv* env, jobject object, +static void StartBroadcastNative(JNIEnv* /* env */, jobject /* object */, jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock lock(sBroadcasterInterfaceMutex); @@ -1362,7 +1430,7 @@ static void StartBroadcastNative(JNIEnv* env, jobject object, sLeAudioBroadcasterInterface->StartBroadcast(broadcast_id); } -static void StopBroadcastNative(JNIEnv* env, jobject object, +static void StopBroadcastNative(JNIEnv* /* env */, jobject /* object */, jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock lock(sBroadcasterInterfaceMutex); @@ -1370,7 +1438,7 @@ static void StopBroadcastNative(JNIEnv* env, jobject object, sLeAudioBroadcasterInterface->StopBroadcast(broadcast_id); } -static void PauseBroadcastNative(JNIEnv* env, jobject object, +static void PauseBroadcastNative(JNIEnv* /* env */, jobject /* object */, jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock lock(sBroadcasterInterfaceMutex); @@ -1378,7 +1446,7 @@ static void PauseBroadcastNative(JNIEnv* env, jobject object, sLeAudioBroadcasterInterface->PauseBroadcast(broadcast_id); } -static void DestroyBroadcastNative(JNIEnv* env, jobject object, +static void DestroyBroadcastNative(JNIEnv* /* env */, jobject /* object */, jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock lock(sBroadcasterInterfaceMutex); @@ -1386,7 +1454,7 @@ static void DestroyBroadcastNative(JNIEnv* env, jobject object, sLeAudioBroadcasterInterface->DestroyBroadcast(broadcast_id); } -static void getBroadcastMetadataNative(JNIEnv* env, jobject object, +static void getBroadcastMetadataNative(JNIEnv* /* env */, jobject /* object */, jint broadcast_id) { LOG(INFO) << __func__; std::shared_lock lock(sBroadcasterInterfaceMutex); @@ -1394,30 +1462,178 @@ static void getBroadcastMetadataNative(JNIEnv* env, jobject object, sLeAudioBroadcasterInterface->GetBroadcastMetadata(broadcast_id); } -static JNINativeMethod sBroadcasterMethods[] = { - {"classInitNative", "()V", (void*)BroadcasterClassInitNative}, - {"initNative", "()V", (void*)BroadcasterInitNative}, - {"stopNative", "()V", (void*)BroadcasterStopNative}, - {"cleanupNative", "()V", (void*)BroadcasterCleanupNative}, - {"createBroadcastNative", "(ZLjava/lang/String;[B[B[I[[B)V", - (void*)CreateBroadcastNative}, - {"updateMetadataNative", "(ILjava/lang/String;[B[[B)V", - (void*)UpdateMetadataNative}, - {"startBroadcastNative", "(I)V", (void*)StartBroadcastNative}, - {"stopBroadcastNative", "(I)V", (void*)StopBroadcastNative}, - {"pauseBroadcastNative", "(I)V", (void*)PauseBroadcastNative}, - {"destroyBroadcastNative", "(I)V", (void*)DestroyBroadcastNative}, - {"getBroadcastMetadataNative", "(I)V", (void*)getBroadcastMetadataNative}, -}; +static int register_com_android_bluetooth_le_audio_broadcaster(JNIEnv* env) { + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)BroadcasterInitNative}, + {"stopNative", "()V", (void*)BroadcasterStopNative}, + {"cleanupNative", "()V", (void*)BroadcasterCleanupNative}, + {"createBroadcastNative", "(ZLjava/lang/String;[B[B[I[[B)V", + (void*)CreateBroadcastNative}, + {"updateMetadataNative", "(ILjava/lang/String;[B[[B)V", + (void*)UpdateMetadataNative}, + {"startBroadcastNative", "(I)V", (void*)StartBroadcastNative}, + {"stopBroadcastNative", "(I)V", (void*)StopBroadcastNative}, + {"pauseBroadcastNative", "(I)V", (void*)PauseBroadcastNative}, + {"destroyBroadcastNative", "(I)V", (void*)DestroyBroadcastNative}, + {"getBroadcastMetadataNative", "(I)V", (void*)getBroadcastMetadataNative}, + }; + + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface", + methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onBroadcastCreated", "(IZ)V", &method_onBroadcastCreated}, + {"onBroadcastDestroyed", "(I)V", &method_onBroadcastDestroyed}, + {"onBroadcastStateChanged", "(II)V", &method_onBroadcastStateChanged}, + {"onBroadcastMetadataChanged", + "(ILandroid/bluetooth/BluetoothLeBroadcastMetadata;)V", + &method_onBroadcastMetadataChanged}, + }; + GET_JAVA_METHODS( + env, "com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface", + javaMethods); + + const JNIJavaMethod javaArrayListMethods[] = { + {"", "()V", &java_util_ArrayList.constructor}, + {"add", "(Ljava/lang/Object;)Z", &java_util_ArrayList.add}, + }; + GET_JAVA_METHODS(env, "java/util/ArrayList", javaArrayListMethods); + + const JNIJavaMethod javaLeAudioCodecMethods[] = { + {"", "(JIII[B)V", + &android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeAudioCodecConfigMetadata", + javaLeAudioCodecMethods); + + const JNIJavaMethod javaLeAudioContentMethods[] = { + {"", "(Ljava/lang/String;Ljava/lang/String;[B)V", + &android_bluetooth_BluetoothLeAudioContentMetadata.constructor}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeAudioContentMetadata", + javaLeAudioContentMethods); + + const JNIJavaMethod javaLeBroadcastChannelMethods[] = { + {"", "(ZILandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;)V", + &android_bluetooth_BluetoothLeBroadcastChannel.constructor}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeBroadcastChannel", + javaLeBroadcastChannelMethods); + + const JNIJavaMethod javaLeBroadcastSubgroupMethods[] = { + {"", + "(JLandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;" + "Landroid/bluetooth/BluetoothLeAudioContentMetadata;" + "Ljava/util/List;)V", + &android_bluetooth_BluetoothLeBroadcastSubgroup.constructor}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeBroadcastSubgroup", + javaLeBroadcastSubgroupMethods); + + const JNIJavaMethod javaBluetoothDevieceMethods[] = { + {"", "(Ljava/lang/String;I)V", + &android_bluetooth_BluetoothDevice.constructor}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothDevice", + javaBluetoothDevieceMethods); + + const JNIJavaMethod javaLeBroadcastMetadataMethods[] = { + {"", + "(ILandroid/bluetooth/BluetoothDevice;IIIZZLjava/lang/String;" + "[BIIILandroid/bluetooth/BluetoothLeAudioContentMetadata;" + "Ljava/util/List;)V", + &android_bluetooth_BluetoothLeBroadcastMetadata.constructor}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeBroadcastMetadata", + javaLeBroadcastMetadataMethods); + + return 0; +} int register_com_android_bluetooth_le_audio(JNIEnv* env) { - int register_success = jniRegisterNativeMethods( - env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", sMethods, - NELEM(sMethods)); - return register_success & - jniRegisterNativeMethods( - env, - "com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface", - sBroadcasterMethods, NELEM(sBroadcasterMethods)); + const JNINativeMethod methods[] = { + {"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V", + (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectLeAudioNative", "([B)Z", (void*)connectLeAudioNative}, + {"disconnectLeAudioNative", "([B)Z", (void*)disconnectLeAudioNative}, + {"setEnableStateNative", "([BZ)Z", (void*)setEnableStateNative}, + {"groupAddNodeNative", "(I[B)Z", (void*)groupAddNodeNative}, + {"groupRemoveNodeNative", "(I[B)Z", (void*)groupRemoveNodeNative}, + {"groupSetActiveNative", "(I)V", (void*)groupSetActiveNative}, + {"setCodecConfigPreferenceNative", + "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;" + "Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V", + (void*)setCodecConfigPreferenceNative}, + {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative}, + {"setInCallNative", "(Z)V", (void*)setInCallNative}, + {"setUnicastMonitorModeNative", "(IZ)V", + (void*)setUnicastMonitorModeNative}, + {"sendAudioProfilePreferencesNative", "(IZZ)V", + (void*)sendAudioProfilePreferencesNative}, + }; + + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onGroupStatus", "(II)V", &method_onGroupStatus}, + {"onGroupNodeStatus", "([BII)V", &method_onGroupNodeStatus}, + {"onAudioConf", "(IIIII)V", &method_onAudioConf}, + {"onSinkAudioLocationAvailable", "([BI)V", + &method_onSinkAudioLocationAvailable}, + {"onInitialized", "()V", &method_onInitialized}, + {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged}, + {"onAudioLocalCodecCapabilities", + "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;" + "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V", + &method_onAudioLocalCodecCapabilities}, + {"onAudioGroupCurrentCodecConf", + "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;" + "Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V", + &method_onAudioGroupCurrentCodecConf}, + {"onAudioGroupSelectableCodecConf", + "(I[Landroid/bluetooth/BluetoothLeAudioCodecConfig;" + "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V", + &method_onAudioGroupSelectableCodecConf}, + {"onHealthBasedRecommendationAction", "([BI)V", + &method_onHealthBasedRecommendationAction}, + {"onHealthBasedGroupRecommendationAction", "(II)V", + &method_onHealthBasedGroupRecommendationAction}, + {"onUnicastMonitorModeStatus", "(II)V", + &method_onUnicastMonitorModeStatus}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", + javaMethods); + + const JNIJavaMethod javaLeAudioCodecMethods[] = { + {"", "(IIIIIIIII)V", + &android_bluetooth_BluetoothLeAudioCodecConfig.constructor}, + {"getCodecType", "()I", + &android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType}, + {"getSampleRate", "()I", + &android_bluetooth_BluetoothLeAudioCodecConfig.getSampleRate}, + {"getBitsPerSample", "()I", + &android_bluetooth_BluetoothLeAudioCodecConfig.getBitsPerSample}, + {"getChannelCount", "()I", + &android_bluetooth_BluetoothLeAudioCodecConfig.getChannelCount}, + {"getFrameDuration", "()I", + &android_bluetooth_BluetoothLeAudioCodecConfig.getFrameDuration}, + {"getOctetsPerFrame", "()I", + &android_bluetooth_BluetoothLeAudioCodecConfig.getOctetsPerFrame}, + {"getCodecPriority", "()I", + &android_bluetooth_BluetoothLeAudioCodecConfig.getCodecPriority}, + }; + GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeAudioCodecConfig", + javaLeAudioCodecMethods); + + return register_com_android_bluetooth_le_audio_broadcaster(env); } } // namespace android diff --git a/android/app/jni/com_android_bluetooth_pan.cpp b/android/app/jni/com_android_bluetooth_pan.cpp index 84d7b1c78b07dbe131d963b2f3c2471f90022e5e..a216ebb103458e8959497bbca100339a1aaa22db 100644 --- a/android/app/jni/com_android_bluetooth_pan.cpp +++ b/android/app/jni/com_android_bluetooth_pan.cpp @@ -98,19 +98,10 @@ static btpan_callbacks_t sBluetoothPanCallbacks = { connection_state_callback}; // Define native functions - -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onConnectStateChanged = - env->GetMethodID(clazz, "onConnectStateChanged", "([BIIII)V"); - method_onControlStateChanged = env->GetMethodID( - clazz, "onControlStateChanged", "(IIILjava/lang/String;)V"); - - info("succeeds"); -} static const bt_interface_t* btIf; static void initializeNative(JNIEnv* env, jobject object) { - debug("pan"); + debug("Initialize pan"); if (btIf) return; btIf = getBluetoothInterface(); @@ -152,7 +143,8 @@ static void initializeNative(JNIEnv* env, jobject object) { } } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { + debug("Cleanup pan"); if (!btIf) return; if (sPanIf != NULL) { @@ -169,10 +161,10 @@ static void cleanupNative(JNIEnv* env, jobject object) { btIf = NULL; } -static jboolean connectPanNative(JNIEnv* env, jobject object, +static jboolean connectPanNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint src_role, jint dest_role) { - debug("in"); + debug("Connect pan"); if (!sPanIf) return JNI_FALSE; jbyte* addr = env->GetByteArrayElements(address, NULL); @@ -192,8 +184,9 @@ static jboolean connectPanNative(JNIEnv* env, jobject object, return ret; } -static jboolean disconnectPanNative(JNIEnv* env, jobject object, +static jboolean disconnectPanNative(JNIEnv* env, jobject /* object */, jbyteArray address) { + debug("Disconnects pan"); if (!sPanIf) return JNI_FALSE; jbyte* addr = env->GetByteArrayElements(address, NULL); @@ -213,17 +206,27 @@ static jboolean disconnectPanNative(JNIEnv* env, jobject object, return ret; } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNative", "()V", (void*)initializeNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectPanNative", "([BII)Z", (void*)connectPanNative}, - {"disconnectPanNative", "([B)Z", (void*)disconnectPanNative}, - // TBD cleanup -}; - int register_com_android_bluetooth_pan(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/bluetooth/pan/PanService", - sMethods, NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initializeNative", "()V", (void*)initializeNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectPanNative", "([BII)Z", (void*)connectPanNative}, + {"disconnectPanNative", "([B)Z", (void*)disconnectPanNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/pan/PanNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[]{ + {"onConnectStateChanged", "([BIIII)V", &method_onConnectStateChanged}, + {"onControlStateChanged", "(IIILjava/lang/String;)V", + &method_onControlStateChanged}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/pan/PanNativeInterface", + javaMethods); + + return 0; } } diff --git a/android/app/jni/com_android_bluetooth_sdp.cpp b/android/app/jni/com_android_bluetooth_sdp.cpp index ded546a05d85bc6eab7216f7cdac4b3d0c1d9123..62ee16ae3fb19a8bf7d95d491df118c91f28c723 100644 --- a/android/app/jni/com_android_bluetooth_sdp.cpp +++ b/android/app/jni/com_android_bluetooth_sdp.cpp @@ -75,34 +75,8 @@ static void initializeNative(JNIEnv* env, jobject object) { sCallbacksObj = env->NewGlobalRef(object); } -static void classInitNative(JNIEnv* env, jclass clazz) { - /* generic SDP record (raw data)*/ - method_sdpRecordFoundCallback = - env->GetMethodID(clazz, "sdpRecordFoundCallback", "(I[B[BI[B)V"); - - /* MAS SDP record*/ - method_sdpMasRecordFoundCallback = env->GetMethodID( - clazz, "sdpMasRecordFoundCallback", "(I[B[BIIIIIILjava/lang/String;Z)V"); - /* MNS SDP record*/ - method_sdpMnsRecordFoundCallback = env->GetMethodID( - clazz, "sdpMnsRecordFoundCallback", "(I[B[BIIIILjava/lang/String;Z)V"); - /* PBAP PSE record */ - method_sdpPseRecordFoundCallback = env->GetMethodID( - clazz, "sdpPseRecordFoundCallback", "(I[B[BIIIIILjava/lang/String;Z)V"); - /* OPP Server record */ - method_sdpOppOpsRecordFoundCallback = - env->GetMethodID(clazz, "sdpOppOpsRecordFoundCallback", - "(I[B[BIIILjava/lang/String;[BZ)V"); - /* SAP Server record */ - method_sdpSapsRecordFoundCallback = env->GetMethodID( - clazz, "sdpSapsRecordFoundCallback", "(I[B[BIILjava/lang/String;Z)V"); - /* DIP record */ - method_sdpDipRecordFoundCallback = env->GetMethodID( - clazz, "sdpDipRecordFoundCallback", "(I[B[BIIIIIZZ)V"); -} - -static jboolean sdpSearchNative(JNIEnv* env, jobject obj, jbyteArray address, - jbyteArray uuidObj) { +static jboolean sdpSearchNative(JNIEnv* env, jobject /* obj */, + jbyteArray address, jbyteArray uuidObj) { ALOGD("%s", __func__); if (!sBluetoothSdpInterface) return JNI_FALSE; @@ -244,7 +218,7 @@ static void sdp_search_callback(bt_status_t status, const RawAddress& bd_addr, } // End of for-loop } -static jint sdpCreateMapMasRecordNative(JNIEnv* env, jobject obj, +static jint sdpCreateMapMasRecordNative(JNIEnv* env, jobject /* obj */, jstring name_str, jint mas_id, jint scn, jint l2cap_psm, jint version, jint msg_types, jint features) { @@ -283,7 +257,7 @@ static jint sdpCreateMapMasRecordNative(JNIEnv* env, jobject obj, return handle; } -static jint sdpCreateMapMnsRecordNative(JNIEnv* env, jobject obj, +static jint sdpCreateMapMnsRecordNative(JNIEnv* env, jobject /* obj */, jstring name_str, jint scn, jint l2cap_psm, jint version, jint features) { @@ -320,7 +294,7 @@ static jint sdpCreateMapMnsRecordNative(JNIEnv* env, jobject obj, return handle; } -static jint sdpCreatePbapPceRecordNative(JNIEnv* env, jobject obj, +static jint sdpCreatePbapPceRecordNative(JNIEnv* env, jobject /* obj */, jstring name_str, jint version) { ALOGD("%s", __func__); if (!sBluetoothSdpInterface) return -1; @@ -351,7 +325,7 @@ static jint sdpCreatePbapPceRecordNative(JNIEnv* env, jobject obj, return handle; } -static jint sdpCreatePbapPseRecordNative(JNIEnv* env, jobject obj, +static jint sdpCreatePbapPseRecordNative(JNIEnv* env, jobject /* obj */, jstring name_str, jint scn, jint l2cap_psm, jint version, jint supported_repositories, @@ -390,7 +364,7 @@ static jint sdpCreatePbapPseRecordNative(JNIEnv* env, jobject obj, return handle; } -static jint sdpCreateOppOpsRecordNative(JNIEnv* env, jobject obj, +static jint sdpCreateOppOpsRecordNative(JNIEnv* env, jobject /* obj */, jstring name_str, jint scn, jint l2cap_psm, jint version, jbyteArray supported_formats_list) { @@ -439,7 +413,7 @@ static jint sdpCreateOppOpsRecordNative(JNIEnv* env, jobject obj, return handle; } -static jint sdpCreateSapsRecordNative(JNIEnv* env, jobject obj, +static jint sdpCreateSapsRecordNative(JNIEnv* env, jobject /* obj */, jstring name_str, jint scn, jint version) { ALOGD("%s", __func__); @@ -472,7 +446,7 @@ static jint sdpCreateSapsRecordNative(JNIEnv* env, jobject obj, return handle; } -static jboolean sdpRemoveSdpRecordNative(JNIEnv* env, jobject obj, +static jboolean sdpRemoveSdpRecordNative(JNIEnv* /* env */, jobject /* obj */, jint record_id) { ALOGD("%s", __func__); if (!sBluetoothSdpInterface) return false; @@ -487,7 +461,7 @@ static jboolean sdpRemoveSdpRecordNative(JNIEnv* env, jobject obj, return true; } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { const bt_interface_t* btInf = getBluetoothInterface(); if (btInf == NULL) { @@ -508,28 +482,49 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNative", "()V", (void*)initializeNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"sdpSearchNative", "([B[B)Z", (void*)sdpSearchNative}, - {"sdpCreateMapMasRecordNative", "(Ljava/lang/String;IIIIII)I", - (void*)sdpCreateMapMasRecordNative}, - {"sdpCreateMapMnsRecordNative", "(Ljava/lang/String;IIII)I", - (void*)sdpCreateMapMnsRecordNative}, - {"sdpCreatePbapPceRecordNative", "(Ljava/lang/String;I)I", - (void*)sdpCreatePbapPceRecordNative}, - {"sdpCreatePbapPseRecordNative", "(Ljava/lang/String;IIIII)I", - (void*)sdpCreatePbapPseRecordNative}, - {"sdpCreateOppOpsRecordNative", "(Ljava/lang/String;III[B)I", - (void*)sdpCreateOppOpsRecordNative}, - {"sdpCreateSapsRecordNative", "(Ljava/lang/String;II)I", - (void*)sdpCreateSapsRecordNative}, - {"sdpRemoveSdpRecordNative", "(I)Z", (void*)sdpRemoveSdpRecordNative}}; - int register_com_android_bluetooth_sdp(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/bluetooth/sdp/SdpManager", - sMethods, NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initializeNative", "()V", (void*)initializeNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"sdpSearchNative", "([B[B)Z", (void*)sdpSearchNative}, + {"sdpCreateMapMasRecordNative", "(Ljava/lang/String;IIIIII)I", + (void*)sdpCreateMapMasRecordNative}, + {"sdpCreateMapMnsRecordNative", "(Ljava/lang/String;IIII)I", + (void*)sdpCreateMapMnsRecordNative}, + {"sdpCreatePbapPceRecordNative", "(Ljava/lang/String;I)I", + (void*)sdpCreatePbapPceRecordNative}, + {"sdpCreatePbapPseRecordNative", "(Ljava/lang/String;IIIII)I", + (void*)sdpCreatePbapPseRecordNative}, + {"sdpCreateOppOpsRecordNative", "(Ljava/lang/String;III[B)I", + (void*)sdpCreateOppOpsRecordNative}, + {"sdpCreateSapsRecordNative", "(Ljava/lang/String;II)I", + (void*)sdpCreateSapsRecordNative}, + {"sdpRemoveSdpRecordNative", "(I)Z", (void*)sdpRemoveSdpRecordNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/sdp/SdpManagerNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"sdpRecordFoundCallback", "(I[B[BI[B)V", &method_sdpRecordFoundCallback}, + {"sdpMasRecordFoundCallback", "(I[B[BIIIIIILjava/lang/String;Z)V", + &method_sdpMasRecordFoundCallback}, + {"sdpMnsRecordFoundCallback", "(I[B[BIIIILjava/lang/String;Z)V", + &method_sdpMnsRecordFoundCallback}, + {"sdpPseRecordFoundCallback", "(I[B[BIIIIILjava/lang/String;Z)V", + &method_sdpPseRecordFoundCallback}, + {"sdpOppOpsRecordFoundCallback", "(I[B[BIIILjava/lang/String;[BZ)V", + &method_sdpOppOpsRecordFoundCallback}, + {"sdpSapsRecordFoundCallback", "(I[B[BIILjava/lang/String;Z)V", + &method_sdpSapsRecordFoundCallback}, + {"sdpDipRecordFoundCallback", "(I[B[BIIIIIZZ)V", + &method_sdpDipRecordFoundCallback}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/sdp/SdpManagerNativeInterface", + javaMethods); + + return 0; } } diff --git a/android/app/jni/com_android_bluetooth_vc.cpp b/android/app/jni/com_android_bluetooth_vc.cpp index 4c4103ef17d03a45ca7a5b9218db77dc7642f22b..60cd30e49b2bb2cee7c88f3a0118f894c19949cf 100644 --- a/android/app/jni/com_android_bluetooth_vc.cpp +++ b/android/app/jni/com_android_bluetooth_vc.cpp @@ -48,7 +48,8 @@ class VolumeControlCallbacksImpl : public VolumeControlCallbacks { ~VolumeControlCallbacksImpl() = default; void OnConnectionState(ConnectionState state, const RawAddress& bd_addr) override { - LOG(INFO) << __func__; + LOG(INFO) << __func__ << ", state:" << int(state) + << ", addr: " << bd_addr.ToRedactedStringForLogging(); std::shared_lock lock(callbacks_mutex); CallbackEnv sCallbackEnv(__func__); @@ -198,31 +199,6 @@ class VolumeControlCallbacksImpl : public VolumeControlCallbacks { static VolumeControlCallbacksImpl sVolumeControlCallbacks; -static void classInitNative(JNIEnv* env, jclass clazz) { - method_onConnectionStateChanged = - env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); - - method_onVolumeStateChanged = - env->GetMethodID(clazz, "onVolumeStateChanged", "(IZ[BZ)V"); - - method_onGroupVolumeStateChanged = - env->GetMethodID(clazz, "onGroupVolumeStateChanged", "(IZIZ)V"); - - method_onDeviceAvailable = - env->GetMethodID(clazz, "onDeviceAvailable", "(I[B)V"); - - method_onExtAudioOutVolumeOffsetChanged = - env->GetMethodID(clazz, "onExtAudioOutVolumeOffsetChanged", "(II[B)V"); - - method_onExtAudioOutLocationChanged = - env->GetMethodID(clazz, "onExtAudioOutLocationChanged", "(II[B)V"); - - method_onExtAudioOutDescriptionChanged = env->GetMethodID( - clazz, "onExtAudioOutDescriptionChanged", "(ILjava/lang/String;[B)V"); - - LOG(INFO) << __func__ << ": succeeds"; -} - static void initNative(JNIEnv* env, jobject object) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -260,7 +236,7 @@ static void initNative(JNIEnv* env, jobject object) { sVolumeControlInterface->Init(&sVolumeControlCallbacks); } -static void cleanupNative(JNIEnv* env, jobject object) { +static void cleanupNative(JNIEnv* env, jobject /* object */) { std::unique_lock interface_lock(interface_mutex); std::unique_lock callbacks_lock(callbacks_mutex); @@ -281,7 +257,7 @@ static void cleanupNative(JNIEnv* env, jobject object) { } } -static jboolean connectVolumeControlNative(JNIEnv* env, jobject object, +static jboolean connectVolumeControlNative(JNIEnv* env, jobject /* object */, jbyteArray address) { LOG(INFO) << __func__; std::shared_lock lock(interface_mutex); @@ -304,7 +280,7 @@ static jboolean connectVolumeControlNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean disconnectVolumeControlNative(JNIEnv* env, jobject object, +static jboolean disconnectVolumeControlNative(JNIEnv* env, jobject /* object */, jbyteArray address) { LOG(INFO) << __func__; std::shared_lock lock(interface_mutex); @@ -327,8 +303,8 @@ static jboolean disconnectVolumeControlNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static void setVolumeNative(JNIEnv* env, jobject object, jbyteArray address, - jint volume) { +static void setVolumeNative(JNIEnv* env, jobject /* object */, + jbyteArray address, jint volume) { if (!sVolumeControlInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth Volume Control Interface"; @@ -346,8 +322,8 @@ static void setVolumeNative(JNIEnv* env, jobject object, jbyteArray address, env->ReleaseByteArrayElements(address, addr, 0); } -static void setGroupVolumeNative(JNIEnv* env, jobject object, jint group_id, - jint volume) { +static void setGroupVolumeNative(JNIEnv* /* env */, jobject /* object */, + jint group_id, jint volume) { if (!sVolumeControlInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth Volume Control Interface"; @@ -357,7 +333,7 @@ static void setGroupVolumeNative(JNIEnv* env, jobject object, jint group_id, sVolumeControlInterface->SetVolume(group_id, volume); } -static void muteNative(JNIEnv* env, jobject object, jbyteArray address) { +static void muteNative(JNIEnv* env, jobject /* object */, jbyteArray address) { if (!sVolumeControlInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth Volume Control Interface"; @@ -375,7 +351,8 @@ static void muteNative(JNIEnv* env, jobject object, jbyteArray address) { env->ReleaseByteArrayElements(address, addr, 0); } -static void muteGroupNative(JNIEnv* env, jobject object, jint group_id) { +static void muteGroupNative(JNIEnv* /* env */, jobject /* object */, + jint group_id) { if (!sVolumeControlInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth Volume Control Interface"; @@ -384,7 +361,8 @@ static void muteGroupNative(JNIEnv* env, jobject object, jint group_id) { sVolumeControlInterface->Mute(group_id); } -static void unmuteNative(JNIEnv* env, jobject object, jbyteArray address) { +static void unmuteNative(JNIEnv* env, jobject /* object */, + jbyteArray address) { if (!sVolumeControlInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth Volume Control Interface"; @@ -402,7 +380,8 @@ static void unmuteNative(JNIEnv* env, jobject object, jbyteArray address) { env->ReleaseByteArrayElements(address, addr, 0); } -static void unmuteGroupNative(JNIEnv* env, jobject object, jint group_id) { +static void unmuteGroupNative(JNIEnv* /* env */, jobject /* object */, + jint group_id) { if (!sVolumeControlInterface) { LOG(ERROR) << __func__ << ": Failed to get the Bluetooth Volume Control Interface"; @@ -412,7 +391,8 @@ static void unmuteGroupNative(JNIEnv* env, jobject object, jint group_id) { } /* Native methods for exterbak audio outputs */ -static jboolean getExtAudioOutVolumeOffsetNative(JNIEnv* env, jobject object, +static jboolean getExtAudioOutVolumeOffsetNative(JNIEnv* env, + jobject /* object */, jbyteArray address, jint ext_output_id) { LOG(INFO) << __func__; @@ -431,7 +411,8 @@ static jboolean getExtAudioOutVolumeOffsetNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean setExtAudioOutVolumeOffsetNative(JNIEnv* env, jobject object, +static jboolean setExtAudioOutVolumeOffsetNative(JNIEnv* env, + jobject /* object */, jbyteArray address, jint ext_output_id, jint offset) { @@ -452,7 +433,7 @@ static jboolean setExtAudioOutVolumeOffsetNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean getExtAudioOutLocationNative(JNIEnv* env, jobject object, +static jboolean getExtAudioOutLocationNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint ext_output_id) { LOG(INFO) << __func__; @@ -471,7 +452,7 @@ static jboolean getExtAudioOutLocationNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean setExtAudioOutLocationNative(JNIEnv* env, jobject object, +static jboolean setExtAudioOutLocationNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint ext_output_id, jint location) { @@ -492,7 +473,8 @@ static jboolean setExtAudioOutLocationNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean getExtAudioOutDescriptionNative(JNIEnv* env, jobject object, +static jboolean getExtAudioOutDescriptionNative(JNIEnv* env, + jobject /* object */, jbyteArray address, jint ext_output_id) { LOG(INFO) << __func__; @@ -511,7 +493,8 @@ static jboolean getExtAudioOutDescriptionNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static jboolean setExtAudioOutDescriptionNative(JNIEnv* env, jobject object, +static jboolean setExtAudioOutDescriptionNative(JNIEnv* env, + jobject /* object */, jbyteArray address, jint ext_output_id, jstring descr) { @@ -539,36 +522,55 @@ static jboolean setExtAudioOutDescriptionNative(JNIEnv* env, jobject object, return JNI_TRUE; } -static JNINativeMethod sMethods[] = { - {"classInitNative", "()V", (void*)classInitNative}, - {"initNative", "()V", (void*)initNative}, - {"cleanupNative", "()V", (void*)cleanupNative}, - {"connectVolumeControlNative", "([B)Z", (void*)connectVolumeControlNative}, - {"disconnectVolumeControlNative", "([B)Z", - (void*)disconnectVolumeControlNative}, - {"setVolumeNative", "([BI)V", (void*)setVolumeNative}, - {"setGroupVolumeNative", "(II)V", (void*)setGroupVolumeNative}, - {"muteNative", "([B)V", (void*)muteNative}, - {"muteGroupNative", "(I)V", (void*)muteGroupNative}, - {"unmuteNative", "([B)V", (void*)unmuteNative}, - {"unmuteGroupNative", "(I)V", (void*)unmuteGroupNative}, - {"getExtAudioOutVolumeOffsetNative", "([BI)Z", - (void*)getExtAudioOutVolumeOffsetNative}, - {"setExtAudioOutVolumeOffsetNative", "([BII)Z", - (void*)setExtAudioOutVolumeOffsetNative}, - {"getExtAudioOutLocationNative", "([BI)Z", - (void*)getExtAudioOutLocationNative}, - {"setExtAudioOutLocationNative", "([BII)Z", - (void*)setExtAudioOutLocationNative}, - {"getExtAudioOutDescriptionNative", "([BI)Z", - (void*)getExtAudioOutDescriptionNative}, - {"setExtAudioOutDescriptionNative", "([BILjava/lang/String;)Z", - (void*)setExtAudioOutDescriptionNative}, -}; - int register_com_android_bluetooth_vc(JNIEnv* env) { - return jniRegisterNativeMethods( - env, "com/android/bluetooth/vc/VolumeControlNativeInterface", sMethods, - NELEM(sMethods)); + const JNINativeMethod methods[] = { + {"initNative", "()V", (void*)initNative}, + {"cleanupNative", "()V", (void*)cleanupNative}, + {"connectVolumeControlNative", "([B)Z", + (void*)connectVolumeControlNative}, + {"disconnectVolumeControlNative", "([B)Z", + (void*)disconnectVolumeControlNative}, + {"setVolumeNative", "([BI)V", (void*)setVolumeNative}, + {"setGroupVolumeNative", "(II)V", (void*)setGroupVolumeNative}, + {"muteNative", "([B)V", (void*)muteNative}, + {"muteGroupNative", "(I)V", (void*)muteGroupNative}, + {"unmuteNative", "([B)V", (void*)unmuteNative}, + {"unmuteGroupNative", "(I)V", (void*)unmuteGroupNative}, + {"getExtAudioOutVolumeOffsetNative", "([BI)Z", + (void*)getExtAudioOutVolumeOffsetNative}, + {"setExtAudioOutVolumeOffsetNative", "([BII)Z", + (void*)setExtAudioOutVolumeOffsetNative}, + {"getExtAudioOutLocationNative", "([BI)Z", + (void*)getExtAudioOutLocationNative}, + {"setExtAudioOutLocationNative", "([BII)Z", + (void*)setExtAudioOutLocationNative}, + {"getExtAudioOutDescriptionNative", "([BI)Z", + (void*)getExtAudioOutDescriptionNative}, + {"setExtAudioOutDescriptionNative", "([BILjava/lang/String;)Z", + (void*)setExtAudioOutDescriptionNative}, + }; + const int result = REGISTER_NATIVE_METHODS( + env, "com/android/bluetooth/vc/VolumeControlNativeInterface", methods); + if (result != 0) { + return result; + } + + const JNIJavaMethod javaMethods[] = { + {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged}, + {"onVolumeStateChanged", "(IZ[BZ)V", &method_onVolumeStateChanged}, + {"onGroupVolumeStateChanged", "(IZIZ)V", + &method_onGroupVolumeStateChanged}, + {"onDeviceAvailable", "(I[B)V", &method_onDeviceAvailable}, + {"onExtAudioOutVolumeOffsetChanged", "(II[B)V", + &method_onExtAudioOutVolumeOffsetChanged}, + {"onExtAudioOutLocationChanged", "(II[B)V", + &method_onExtAudioOutLocationChanged}, + {"onExtAudioOutDescriptionChanged", "(ILjava/lang/String;[B)V", + &method_onExtAudioOutDescriptionChanged}, + }; + GET_JAVA_METHODS(env, "com/android/bluetooth/vc/VolumeControlNativeInterface", + javaMethods); + + return 0; } } // namespace android diff --git a/android/app/lib/mapapi/com/android/bluetooth/mapapi/BluetoothMapContract.java b/android/app/lib/mapapi/com/android/bluetooth/mapapi/BluetoothMapContract.java index 5040bdc57eee9b2e610b040ed6fea209fd4e6d39..918aecddc5db118db3dc25dd89a0d227939ddb31 100644 --- a/android/app/lib/mapapi/com/android/bluetooth/mapapi/BluetoothMapContract.java +++ b/android/app/lib/mapapi/com/android/bluetooth/mapapi/BluetoothMapContract.java @@ -19,7 +19,6 @@ package com.android.bluetooth.mapapi; import android.content.ContentResolver; import android.net.Uri; - /** * This class defines the minimum sets of data needed for a client to * implement to claim support for the Bluetooth Message Access Profile. diff --git a/android/app/libbluetooth_jni.map b/android/app/libbluetooth_jni.map new file mode 100644 index 0000000000000000000000000000000000000000..655a716d9a12d35db7abb1aadf0dbb918cab571b --- /dev/null +++ b/android/app/libbluetooth_jni.map @@ -0,0 +1,4 @@ +{ + global: JNI_OnLoad; + local: *; +}; diff --git a/android/app/lint-baseline.xml b/android/app/lint-baseline.xml new file mode 100644 index 0000000000000000000000000000000000000000..3c6ab974d702da194f8827155e8f57c4a132e7a5 --- /dev/null +++ b/android/app/lint-baseline.xml @@ -0,0 +1,7146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/proguard.flags b/android/app/proguard.flags index a9426ad4aa651d94e8e7c0c76abbe0ec43dcfa1a..75da0433f5ea01f55e78f971d3186de43cb20709 100644 --- a/android/app/proguard.flags +++ b/android/app/proguard.flags @@ -5,3 +5,6 @@ -keep class android.support.v4.media.MediaMetadataCompat { *; } -keep class android.support.v4.media.MediaBrowserCompat$MediaItem { *; } -keep class android.support.v4.media.MediaDescriptionCompat { *; } + +# Required for tests that use Mockito's thenThrow with checked exceptions. +-keepattributes Exceptions \ No newline at end of file diff --git a/system/gd/proto/bluetooth/bluetoothKeystore/keystore.proto b/android/app/proto/keystore.proto similarity index 90% rename from system/gd/proto/bluetooth/bluetoothKeystore/keystore.proto rename to android/app/proto/keystore.proto index d0e418bd28e52ebd68066f1e283f62f7c214554a..f0641ff6fab911f87513b5ae8a9317efb8870c06 100644 --- a/system/gd/proto/bluetooth/bluetoothKeystore/keystore.proto +++ b/android/app/proto/keystore.proto @@ -16,9 +16,6 @@ syntax = "proto2"; -// C++ namespace: bluetooth::metrics::BluetoothMetricsProto -package bluetooth.keystore.BluetoothKeystoreProto; - option java_package = "com.android.bluetooth"; option java_outer_classname = "BluetoothKeystoreProto"; diff --git a/android/app/res/layout/bluetooth_map_settings_account_group.xml b/android/app/res/layout/bluetooth_map_settings_account_group.xml index 7bbfca473ef1b050e937430ffff57302911ac1ca..b82ddeecf37cb569feaa678e5e29993bf235bfd1 100644 --- a/android/app/res/layout/bluetooth_map_settings_account_group.xml +++ b/android/app/res/layout/bluetooth_map_settings_account_group.xml @@ -24,22 +24,22 @@ android:id="@+id/bluetooth_map_settings_group_icon" android:layout_width="64dp" android:layout_height="64dp" - android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:maxWidth="64dp" android:maxHeight="64dp" - android:layout_marginLeft="30dp" + android:layout_marginStart="30dp" /> + android:layout_toEndOf="@id/bluetooth_map_settings_group_icon"/> diff --git a/android/app/res/layout/bluetooth_map_settings_account_item.xml b/android/app/res/layout/bluetooth_map_settings_account_item.xml index b6fbf8a77adb6a5e1066cdb5a09ede4fc51757de..5dc63d2bbf15398f51c19cbfba7d0603654fafb2 100644 --- a/android/app/res/layout/bluetooth_map_settings_account_item.xml +++ b/android/app/res/layout/bluetooth_map_settings_account_item.xml @@ -22,8 +22,8 @@ android:clickable="true" android:gravity="fill_vertical" android:orientation="horizontal" - android:paddingLeft="51dp" - android:paddingRight="25dp" + android:paddingEnd="51dp" + android:paddingStart="25dp" tools:context=".BluetoothMapSettings" android:baselineAligned="false"> + android:gravity="start|center_vertical"/> + android:gravity="end|center_vertical" /> diff --git a/android/app/res/layout/file_transfer.xml b/android/app/res/layout/file_transfer.xml index 4dea02d4d8acf719eced666737c85dfde09afee1..d508ee6ab02d969d319a6c74920919dd5a0d8225 100644 --- a/android/app/res/layout/file_transfer.xml +++ b/android/app/res/layout/file_transfer.xml @@ -83,15 +83,15 @@ android:id="@+id/progress_percent" android:layout_height="wrap_content" android:layout_width="wrap_content" - android:layout_marginLeft="20dip" + android:layout_marginEnd="20dip" android:textAppearance="?android:attr/textAppearanceSmall" - android:gravity="left" /> + android:gravity="start" /> - - - - "com.android.settings" - diff --git a/android/app/res/values-af/strings.xml b/android/app/res/values-af/strings.xml index 4a99bb952f91d86a58e4ae5ba29828e51f8b7b21..425476f69160e4ae0016ca6b22d0e84d12dda3d7 100644 --- a/android/app/res/values-af/strings.xml +++ b/android/app/res/values-af/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Maak toegang aflaaibestuurder oop." "Gee aan die program toegang tot die BluetoothShare-bestuurder en om dit te gebruik om lêers oor te dra." "Voeg Bluetooth-toesteltoegang by aanvaarlys." diff --git a/android/app/res/values-am/config.xml b/android/app/res/values-am/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-am/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-am/strings.xml b/android/app/res/values-am/strings.xml index ab44be045e7e712926b806097dbdc0bbf37ee82c..4b23792a97ca097baa25ec4e75c99d5aa62dd5f0 100644 --- a/android/app/res/values-am/strings.xml +++ b/android/app/res/values-am/strings.xml @@ -16,6 +16,7 @@ + "ብሉቱá‹" "አá‹áˆ­á‹µ አደራጅን ድረስá¢" "የብሉቱዠአጋራ አስተዳዳሪá‹áŠ• ለመድረስ እና á‹á‹­áˆŽá‰½ እንዲያስተላáˆá‰ ለመጠቀሠለመተáŒá‰ áˆªá‹«á‹ á‹­áˆá‰…ዳáˆá¢" "የብሉቱዠመሣሪያ መዳረሻን በመቀበያ á‹áˆ­á‹áˆ­ ያስገቡá¢" diff --git a/android/app/res/values-ar/config.xml b/android/app/res/values-ar/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ar/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ar/strings.xml b/android/app/res/values-ar/strings.xml index b8092d046b2a37fb216775363e4234410c215a8f..7106e0638d0bd85c984bffe82df247ea12979881 100644 --- a/android/app/res/values-ar/strings.xml +++ b/android/app/res/values-ar/strings.xml @@ -16,6 +16,7 @@ + "بلوتوث" "الدخول إلى إدارة التنزيل." "â€Ù„لسماح للتطبيق بالدخول إلى إدارة BluetoothShare واستخدامها لنقل Ø§Ù„Ù…Ù„ÙØ§Øª." "Ø¥Ø¶Ø§ÙØ© جهاز يتضمّن بلوتوث إلى القائمة المسموح بها." diff --git a/android/app/res/values-as/config.xml b/android/app/res/values-as/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-as/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-as/strings.xml b/android/app/res/values-as/strings.xml index f87c8aa2cbdf2eb342b1a6c5bb5090953cb0b698..020d1b73a3e4a84f7c5e94b4fee7fc194475f4ae 100644 --- a/android/app/res/values-as/strings.xml +++ b/android/app/res/values-as/strings.xml @@ -16,6 +16,7 @@ + "বà§à¦²à§à¦Ÿà§à¦¥" "ডাউনল’ড মেনেজাৰ à¦à¦•à§à¦¸à§‡à¦› কৰিব পাৰে।" "à¦à¦ªà§â€Œà¦Ÿà§‹à¦• BluetoothShare মেনেজাৰ বà§à¦¯à§±à¦¹à¦¾à§° কৰি ফাইল সà§à¦¥à¦¾à¦¨à¦¾à¦¨à§à¦¤à§° কৰিবলৈ অনà§à¦®à¦¤à¦¿ দিয়ে।" "বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইচ à¦à¦•à§à¦¸à§‡à¦› কৰাৰ সà§à¦¬à§€à¦•ৃতি দিয়ে।" diff --git a/android/app/res/values-az/config.xml b/android/app/res/values-az/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-az/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-az/strings.xml b/android/app/res/values-az/strings.xml index 0085ccebc342b343ebbc89a5ecd67f99dbdd90ce..5d1599f998663243bbd48efb2e93d048d032784c 100644 --- a/android/app/res/values-az/strings.xml +++ b/android/app/res/values-az/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "EndirmÉ™ menecerinÉ™ daxil olun." "TÉ™tbiq BluetoothPaylaşım menecerinÉ™ daxil ola vÉ™ faylları ötürmÉ™k üçün ondan istifadÉ™ edÉ™ bilÉ™r." "Bluetooth cihazı giriÅŸini qÉ™bul siyahısına daxil edin." diff --git a/android/app/res/values-b+sr+Latn/config.xml b/android/app/res/values-b+sr+Latn/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-b+sr+Latn/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-b+sr+Latn/strings.xml b/android/app/res/values-b+sr+Latn/strings.xml index e8fb7d89b35e91430e95849b2ed8fe7d7b70b316..6dce4428775b22f23316b6b71c468a3b5e11eb8a 100644 --- a/android/app/res/values-b+sr+Latn/strings.xml +++ b/android/app/res/values-b+sr+Latn/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Pristup menadžeru preuzimanja." "Omogućava aplikaciji da pristupa menadžeru za deljenje preko Bluetooth-a i da ga koristi za prenos datoteka." "Stavi pristup Bluetooth ureÄ‘aja na listu prihvaćenih ureÄ‘aja." diff --git a/android/app/res/values-be/config.xml b/android/app/res/values-be/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-be/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-be/strings.xml b/android/app/res/values-be/strings.xml index 3dbec7ec5b2e6ef81ef7108efce93a85bbe15549..9a2a1f9f12a803383e2db01ad156cec57d2620fe 100644 --- a/android/app/res/values-be/strings.xml +++ b/android/app/res/values-be/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ДоÑтуп да Менеджара Ñпамповак." "ДазвалÑе прыкладаннÑм атрымліваць доÑтуп да менеджÑра BluetoothShare Ñ– выкарыÑтоўваць Ñго Ð´Ð»Ñ Ð¿ÐµÑ€Ð°Ð´Ð°Ñ‡Ñ‹ файлаў." "УноÑьце Ñž белы ÑÐ¿Ñ–Ñ Ð¿Ñ€Ñ‹Ð»Ð°Ð´Ñ‹ з Bluetooth." diff --git a/android/app/res/values-bg/config.xml b/android/app/res/values-bg/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-bg/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-bg/strings.xml b/android/app/res/values-bg/strings.xml index d291a245112d414750535f49e70a607d7daaeaa9..5ec8326d74035f819af87840e047068b32f0117f 100644 --- a/android/app/res/values-bg/strings.xml +++ b/android/app/res/values-bg/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ДоÑтъп до диÑпечера за изтеглÑне." "Дава на приложението доÑтъп и възможноÑÑ‚ за прехвърлÑне на файлове Ñ Ð´Ð¸Ñпечера за BluetoothShare." "ДоÑтъп до уÑтройÑтво Ñ Bluetooth, поÑтавено в ÑпиÑъка за приемане." diff --git a/android/app/res/values-bn/config.xml b/android/app/res/values-bn/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-bn/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-bn/strings.xml b/android/app/res/values-bn/strings.xml index 68889c28d964e61effce682e761b49a9ec559fdb..e4c139f13e66c50466f7667f4a33db8237d0e783 100644 --- a/android/app/res/values-bn/strings.xml +++ b/android/app/res/values-bn/strings.xml @@ -16,6 +16,7 @@ + "বà§à¦²à§à¦Ÿà§à¦¥" "ডাউনলোড মà§à¦¯à¦¾à¦¨à§‡à¦œà¦¾à¦° অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করà§à¦¨à¥¤" "অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•েশানটিকে BluetoothShare মà§à¦¯à¦¾à¦¨à§‡à¦œà¦¾à¦° অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করতে ও ফাইলগà§à¦²à¦¿ সà§à¦¥à¦¾à¦¨à¦¾à¦¨à§à¦¤à¦° করতে à¦à¦Ÿà¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করার অনà§à¦®à¦¤à¦¿ দেয়।" "অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦ªà§à¦Ÿ করা হয়েছে à¦à¦®à¦¨ তালিকাভà§à¦•à§à¦¤ বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইসের অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸à¥¤" diff --git a/android/app/res/values-bs/config.xml b/android/app/res/values-bs/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-bs/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-bs/strings.xml b/android/app/res/values-bs/strings.xml index 09e84ccd6a78e4793ba8fdac3ac78e2cf35dc249..69cbb3c0b3b219da03a40ffa444e0673d9116ec5 100644 --- a/android/app/res/values-bs/strings.xml +++ b/android/app/res/values-bs/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Pristupite upravitelju za preuzimanja." "Dozvoljava aplikaciji da pristupa BluetoothShare upravitelju i koristi ga za prenoÅ¡enje fajlova." "Stavi pristup Bluetooth ureÄ‘aja na listu prihvaćenih." diff --git a/android/app/res/values-ca/config.xml b/android/app/res/values-ca/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ca/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ca/strings.xml b/android/app/res/values-ca/strings.xml index a71fc1d20c93837902ba4b6e46cd1b283ce1f91d..3ee27e5eedd907a307492915942139fb3efaab03 100644 --- a/android/app/res/values-ca/strings.xml +++ b/android/app/res/values-ca/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Accediu al gestor de baixades." "Permet que l\'aplicació accedeixi al gestor d\'ús compartit de Bluetooth i que l\'utilitzi per transferir fitxers." "Afegeix l\'accés al dispositiu Bluetooth a la llista de permesos." diff --git a/android/app/res/values-cs/config.xml b/android/app/res/values-cs/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-cs/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-cs/strings.xml b/android/app/res/values-cs/strings.xml index b3623a29a03ea965dd589fc1a4db3402f68f2600..656778a08b7c0421d2857d762c58b99078b180c6 100644 --- a/android/app/res/values-cs/strings.xml +++ b/android/app/res/values-cs/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Získat přístup ke správci stahování." "Umožňuje aplikaci pÅ™istupovat ke Správci sdílení Bluetooth a využívat jej k pÅ™enosu souborů." "Povolit přístup zařízení Bluetooth." diff --git a/android/app/res/values-da/config.xml b/android/app/res/values-da/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-da/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-da/strings.xml b/android/app/res/values-da/strings.xml index d34f523f0c2d4b0a7ffad3d1354bcb6979a4f5f8..5142cdaebde1bdfef35ade9755ffbecb81a638d8 100644 --- a/android/app/res/values-da/strings.xml +++ b/android/app/res/values-da/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "FÃ¥ adgang til downloadadministrator." "Tillader, at appen fÃ¥r adgang til BluetoothShare-administratoren og kan bruge den til overførsel af filer." "Godkend adgang for Bluetooth-enhed" diff --git a/android/app/res/values-da/strings_sap.xml b/android/app/res/values-da/strings_sap.xml index 13e7a097aa077995a750c4b2e3b1c797b85dd600..47b7b157ea4fbf98a4233530c0e1da600a106256 100644 --- a/android/app/res/values-da/strings_sap.xml +++ b/android/app/res/values-da/strings_sap.xml @@ -5,6 +5,6 @@ "Bluetooth-adgang til SIM-kort" "Vil du anmode klienten om at afbryde forbindelsen?" "Venter pÃ¥, at klienten afbryder forbindelsen" - "Afbryd" + "Afbryd forbindelse" "Gennemtving afbrydelse af forbindelsen" diff --git a/android/app/res/values-de/config.xml b/android/app/res/values-de/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-de/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-de/strings.xml b/android/app/res/values-de/strings.xml index 55fc97ab2f4b09f72cc2d3c2f77e859dae92c77a..7f23b5186ca339a3ccb9df29dc4e24ec50125a39 100644 --- a/android/app/res/values-de/strings.xml +++ b/android/app/res/values-de/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Auf Download-Manager zugreifen" "Ermöglicht der App, auf den Bluetooth-Weiterleitungs-Manager zuzugreifen und diesen für die Übertragung von Dateien zu verwenden." "Bluetooth-Gerät für Zugriff zur Zulassungsliste hinzufügen" diff --git a/android/app/res/values-el/config.xml b/android/app/res/values-el/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-el/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-el/strings.xml b/android/app/res/values-el/strings.xml index 3ba377fa95b1d8d3114b40d7a78a92eea3635613..ada53d395cb75a62e12f7ce83ba283981d4c28af 100644 --- a/android/app/res/values-el/strings.xml +++ b/android/app/res/values-el/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ΠÏόσβαση στη διαχείÏιση λήψεων." "ΕπιτÏέπει στην εφαÏμογή να αποκτά Ï€Ïόσβαση στο Ï€ÏόγÏαμμα διαχείÏισης BluetoothShare και να το χÏησιμοποιεί για τη μεταφοÏά αÏχείων." "ΠÏόσβαση συσκευής Bluetooth επιτÏεπόμενης λίστας." diff --git a/android/app/res/values-en-rAU/config.xml b/android/app/res/values-en-rAU/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-en-rAU/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-en-rAU/strings.xml b/android/app/res/values-en-rAU/strings.xml index 272818403d135d9618dfb23300a76f4f6536a8fb..73ffd04a0ca0d0dab4bd49d920e82b449a847396 100644 --- a/android/app/res/values-en-rAU/strings.xml +++ b/android/app/res/values-en-rAU/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Access download manager." "Allows the application to access the Bluetooth Share manager and to use it to transfer files." "Acceptlist Bluetooth device access." diff --git a/android/app/res/values-en-rCA/config.xml b/android/app/res/values-en-rCA/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-en-rCA/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-en-rCA/strings.xml b/android/app/res/values-en-rCA/strings.xml index 45bedcd3f3ca9aaecad70b61defa279d3aaa8873..bbba4a440a88122b51adaaf06ada23c25e45beb9 100644 --- a/android/app/res/values-en-rCA/strings.xml +++ b/android/app/res/values-en-rCA/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Access download manager." "Allows the app to access the BluetoothShare manager and use it to transfer files." "Acceptlist bluetooth device access." diff --git a/android/app/res/values-en-rGB/config.xml b/android/app/res/values-en-rGB/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-en-rGB/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-en-rGB/strings.xml b/android/app/res/values-en-rGB/strings.xml index 272818403d135d9618dfb23300a76f4f6536a8fb..73ffd04a0ca0d0dab4bd49d920e82b449a847396 100644 --- a/android/app/res/values-en-rGB/strings.xml +++ b/android/app/res/values-en-rGB/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Access download manager." "Allows the application to access the Bluetooth Share manager and to use it to transfer files." "Acceptlist Bluetooth device access." diff --git a/android/app/res/values-en-rIN/config.xml b/android/app/res/values-en-rIN/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-en-rIN/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-en-rIN/strings.xml b/android/app/res/values-en-rIN/strings.xml index 272818403d135d9618dfb23300a76f4f6536a8fb..73ffd04a0ca0d0dab4bd49d920e82b449a847396 100644 --- a/android/app/res/values-en-rIN/strings.xml +++ b/android/app/res/values-en-rIN/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Access download manager." "Allows the application to access the Bluetooth Share manager and to use it to transfer files." "Acceptlist Bluetooth device access." diff --git a/android/app/res/values-en-rXC/config.xml b/android/app/res/values-en-rXC/config.xml deleted file mode 100644 index 5653f1dc93aecc088fe887a2e8eb24e70f87fbb8..0000000000000000000000000000000000000000 --- a/android/app/res/values-en-rXC/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "‎â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€â€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€â€â€Žâ€â€â€â€â€â€â€â€Žâ€â€â€Žâ€Žâ€Žâ€â€â€Žâ€â€Žâ€Žâ€Žâ€â€Žâ€Žâ€â€Žâ€â€â€â€â€Žâ€Žâ€Žâ€â€â€â€Žâ€â€Žâ€â€â€Žâ€Žâ€Žâ€Žâ€â€â€â€Žâ€â€â€â€Žâ€Žâ€Žâ€â€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€Žâ€â€â€Žâ€Žâ€Žâ€â€Žcom.android.settings‎â€â€Žâ€Žâ€â€Ž" - diff --git a/android/app/res/values-en-rXC/strings.xml b/android/app/res/values-en-rXC/strings.xml index ec88c80e1b4b07d230260d8b5cd8f2b0e3236768..c81c28b3ac518569d6c837884c353c251607419a 100644 --- a/android/app/res/values-en-rXC/strings.xml +++ b/android/app/res/values-en-rXC/strings.xml @@ -16,6 +16,7 @@ + "‎â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€â€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€â€â€Žâ€â€â€â€â€â€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€â€Žâ€Žâ€â€Žâ€Žâ€Žâ€â€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€Žâ€â€â€â€Žâ€â€â€â€â€â€â€â€â€â€â€â€â€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€â€â€ŽBluetooth‎â€â€Žâ€Žâ€â€Ž" "‎â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€â€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€â€â€Žâ€â€â€â€â€â€â€â€Žâ€Žâ€â€Žâ€Žâ€â€â€Žâ€Žâ€Žâ€Žâ€â€Žâ€â€â€â€Žâ€Žâ€â€â€Žâ€Žâ€â€Žâ€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€Žâ€â€â€â€Žâ€â€â€â€â€Žâ€â€â€Žâ€Žâ€â€â€Žâ€â€â€â€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€ŽAccess download manager.‎â€â€Žâ€Žâ€â€Ž" "‎â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€â€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€â€â€Žâ€â€â€â€â€Žâ€â€â€Žâ€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€â€â€â€Žâ€â€Žâ€â€Žâ€â€Žâ€Žâ€â€â€Žâ€â€â€â€Žâ€â€Žâ€Žâ€Žâ€Žâ€â€â€Žâ€â€â€Žâ€â€â€Žâ€Žâ€â€â€â€â€Žâ€Žâ€â€Žâ€Žâ€â€â€Žâ€Žâ€â€Žâ€â€ŽAllows the app to access the BluetoothShare manager and use it to transfer files.‎â€â€Žâ€Žâ€â€Ž" "‎â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€â€â€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€â€â€Žâ€â€â€â€â€â€â€â€Žâ€â€Žâ€Žâ€Žâ€Žâ€Žâ€â€Žâ€Žâ€â€Žâ€â€â€â€Žâ€â€â€â€Žâ€Žâ€â€Žâ€â€â€â€Žâ€Žâ€â€â€Žâ€â€Žâ€â€â€Žâ€â€â€â€Žâ€Žâ€Žâ€â€â€Žâ€Žâ€â€Žâ€â€Žâ€â€Žâ€Žâ€Žâ€â€Žâ€Žâ€Žâ€â€â€Žâ€Žâ€ŽAcceptlist bluetooth device access.‎â€â€Žâ€Žâ€â€Ž" diff --git a/android/app/res/values-es-rUS/config.xml b/android/app/res/values-es-rUS/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-es-rUS/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-es-rUS/strings.xml b/android/app/res/values-es-rUS/strings.xml index e71e3ac93af1cafea67a4f3e59160f2b9d78d12d..8a10bd5c3ba62deffa351f78b33f8f6fe08b2bcf 100644 --- a/android/app/res/values-es-rUS/strings.xml +++ b/android/app/res/values-es-rUS/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Accede al administrador de descarga." "Permite a la aplicación acceder al administrador de BluetoothShare y usarlo para transferir archivos." "Acceso del dispositivo Bluetooth a la lista blanca." diff --git a/android/app/res/values-es/config.xml b/android/app/res/values-es/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-es/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-es/strings.xml b/android/app/res/values-es/strings.xml index f83a760406069cb2f3bad4ad417a3e370bbdc7e7..48cf103ec4ae9ad3501cd8e78343a1827fe3f8c0 100644 --- a/android/app/res/values-es/strings.xml +++ b/android/app/res/values-es/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Acceso al administrador de descargas" "Permite que la aplicación acceda al administrador BluetoothShare y lo use para transferir archivos." "Permitir acceso de dispositivo Bluetooth." diff --git a/android/app/res/values-et/config.xml b/android/app/res/values-et/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-et/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-et/strings.xml b/android/app/res/values-et/strings.xml index f2fe79ad996f2722c0b59e325c7152d5d2f36a85..52a5fdf10a9ed1187c4dd62f3877321b399fcb85 100644 --- a/android/app/res/values-et/strings.xml +++ b/android/app/res/values-et/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Pääs allalaadimishalduri juurde." "Võimaldab rakendusel pääseda BluetoothShare\'i haldurisse ja kasutada seda failide edastamiseks." "Bluetooth-seadmele juurdepääsu andmine." diff --git a/android/app/res/values-eu/config.xml b/android/app/res/values-eu/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-eu/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-eu/strings.xml b/android/app/res/values-eu/strings.xml index 5dd5f841a07f80bb95c92f72459e608e5432a7ad..64e721afa756265aece7caee621b631acbd8405d 100644 --- a/android/app/res/values-eu/strings.xml +++ b/android/app/res/values-eu/strings.xml @@ -16,6 +16,7 @@ + "Bluetootha" "Atzitu deskargen kudeatzailea." "Bluetooth bidezko partekatzeen kudeatzailea atzitzea eta fitxategiak transferitzeko erabiltzeko baimena ematen die aplikazioei." "Ezarri Bluetooth bidezko gailuak onartutakoen zerrendan." diff --git a/android/app/res/values-fa/config.xml b/android/app/res/values-fa/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-fa/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-fa/strings.xml b/android/app/res/values-fa/strings.xml index f0a57e008b95ad4bcaadfd19997957d6bf58058a..e72edd954df88f3a2dd08fa298a7ea634007a9a1 100644 --- a/android/app/res/values-fa/strings.xml +++ b/android/app/res/values-fa/strings.xml @@ -16,6 +16,7 @@ + "بلوتوث" "â€Ø¯Ø³ØªØ±Ø³ÛŒ به Download Manager." "â€Ø¨Ù‡ برنامه برای دسترسی به مدیر BluetoothShare Ùˆ Ø§Ø³ØªÙØ§Ø¯Ù‡ از آن برای انتقال ÙØ§ÛŒÙ„‌ها اجازه می‌دهد." "مجاز کردن دسترسی به دستگاه بلوتوثی." diff --git a/android/app/res/values-fi/config.xml b/android/app/res/values-fi/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-fi/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-fi/strings.xml b/android/app/res/values-fi/strings.xml index 5945cfdfcb7a90dcf5ab27378dab4908bee81fb4..8f33c50ce94ff4841ddddee0ac91eb052d1f8a4d 100644 --- a/android/app/res/values-fi/strings.xml +++ b/android/app/res/values-fi/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Lataustenhallinnan käyttö." "Antaa sovelluksen käyttää BluetoothShare-hallintaa tiedostojen siirtoon." "Käyttö Bluetooth-laitteella, jolla on tilapäinen lupa." diff --git a/android/app/res/values-fr-rCA/config.xml b/android/app/res/values-fr-rCA/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-fr-rCA/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-fr-rCA/strings.xml b/android/app/res/values-fr-rCA/strings.xml index 34206c8b852c23737374dce5c1dbfaa61a2a12cf..1884953ea5cf211668d2d4ecda3b319cc07921a0 100644 --- a/android/app/res/values-fr-rCA/strings.xml +++ b/android/app/res/values-fr-rCA/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Accéder au gestionnaire de téléchargement." "Permet à l\'application d\'accéder au gestionnaire BluetoothShare et de l\'utiliser pour le transfert de fichiers." "Ajouter l\'accès d\'un appareil Bluetooth à la liste verte." diff --git a/android/app/res/values-fr/config.xml b/android/app/res/values-fr/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-fr/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-fr/strings.xml b/android/app/res/values-fr/strings.xml index d9cd2363876767122b8ac73694824bd276dc834a..321d505f742deca45cc9a477049242c77fcab204 100644 --- a/android/app/res/values-fr/strings.xml +++ b/android/app/res/values-fr/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Accéder au gestionnaire de téléchargement" "Permet à l\'application d\'accéder au gestionnaire BluetoothShare et de l\'utiliser pour le transfert de fichiers." "Ajouter des appareils Bluetooth à la liste d\'autorisation" diff --git a/android/app/res/values-gl/config.xml b/android/app/res/values-gl/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-gl/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-gl/strings.xml b/android/app/res/values-gl/strings.xml index ce0dafcd3df4069e606ca5990cf51ff2caf4f9b8..5f43ed314877527e726c29319c65a59a21f00b87 100644 --- a/android/app/res/values-gl/strings.xml +++ b/android/app/res/values-gl/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Acceso ao administrador de descargas." "Permite á aplicación acceder ao administrador BluetoothShare e usalo para transferir ficheiros." "Permitir acceso ao dispositivo mediante Bluetooth." diff --git a/android/app/res/values-gu/config.xml b/android/app/res/values-gu/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-gu/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-gu/strings.xml b/android/app/res/values-gu/strings.xml index 2b7fac2def5464bdba53620668482f6de7191f66..1f2a403c2b851322b57508aacb71ad14bc13b20d 100644 --- a/android/app/res/values-gu/strings.xml +++ b/android/app/res/values-gu/strings.xml @@ -16,6 +16,7 @@ + "બà«àª²à«‚ટૂથ" "àªàª•à«àª¸à«‡àª¸ ડાઉનલોડ મેનેજર." "àªàªªà«àª²àª¿àª•ેશનને BluetoothShare મેનેજર અâ€à«…કà«àª¸à«‡àª¸ કરવાની અને ફાઇલો ટà«àª°àª¾àª¨à«àª¸àª«àª° કરવા માટે તેનો ઉપયોગ કરવાની મંજૂરી આપે છે." "વà«àª¹àª¾àª‡àªŸàª²àª¿àª¸à«àªŸ બà«àª²à«‚ટૂથ ડિવાઇસ àªàª•à«àª¸à«‡àª¸." diff --git a/android/app/res/values-hi/config.xml b/android/app/res/values-hi/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-hi/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-hi/strings.xml b/android/app/res/values-hi/strings.xml index 6c9941f95c501b065fc7b07ff907434cb67cc1d0..03c8c3ccfd6871cefabb4307209c923e7b0b2e55 100644 --- a/android/app/res/values-hi/strings.xml +++ b/android/app/res/values-hi/strings.xml @@ -16,6 +16,7 @@ + "बà¥à¤²à¥‚टूथ" "डाउनलोड मैनेजर में पहà¥à¤‚च पाà¤à¤‚." "à¤à¤ªà¥à¤²à¤¿à¤•ेशन को BluetoothShare मैनेजर के इसà¥à¤¤à¥‡à¤®à¤¾à¤² की मंज़ूरी देता है और फ़ाइलों को टà¥à¤°à¤¾à¤‚सफ़र करने के लिठउसका उपयोग करने देता है." "बà¥à¤²à¥‚टूथ डिवाइस à¤à¤•à¥à¤¸à¥‡à¤¸ को वà¥à¤¹à¤¾à¤‡à¤Ÿà¤²à¤¿à¤¸à¥à¤Ÿ में डालें." diff --git a/android/app/res/values-hr/config.xml b/android/app/res/values-hr/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-hr/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-hr/strings.xml b/android/app/res/values-hr/strings.xml index c861a8b47df124733ee2024a303658c2e705ee3c..a0782a3f49cc25019394cd4d9bbc06fd6512075d 100644 --- a/android/app/res/values-hr/strings.xml +++ b/android/app/res/values-hr/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Pristupite upravitelju za preuzimanje." "Aplikaciji omogućuje pristup upravitelju za BluetoothShare i njegovu upotrebu za prijenos datoteka." "Stavi pristup Bluetooth ureÄ‘aja na popis prihvaćenih." diff --git a/android/app/res/values-hu/config.xml b/android/app/res/values-hu/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-hu/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-hu/strings.xml b/android/app/res/values-hu/strings.xml index 229d15cd67591e084f1aca523b4b949c2d124f81..f6dd025e8612067b3fa34618e2f7d1fea4d2e1b3 100644 --- a/android/app/res/values-hu/strings.xml +++ b/android/app/res/values-hu/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Hozzáférés a letöltéskezelÅ‘höz." "LehetÅ‘vé teszi az alkalmazás számára a BluetoothShare kezelÅ‘ elérését és használatát fájlátvitelre." "Bluetooth-eszköz hozzáférésének engedélyezése" diff --git a/android/app/res/values-hy/config.xml b/android/app/res/values-hy/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-hy/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-hy/strings.xml b/android/app/res/values-hy/strings.xml index ecb0a906b45accced4acaf76d604bed5dad221f6..980211304699107aaa2478b46c0d274aded9c6ef 100644 --- a/android/app/res/values-hy/strings.xml +++ b/android/app/res/values-hy/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Õ•Õ£Õ¿Õ¾Õ¥Õ¬ Õ¶Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ´Õ¡Õ¶ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¹Õ«Ö:" "Ô¹Õ¸Ö‚ÕµÕ¬ Õ§ Õ¿Õ¡Õ¬Õ«Õ½, Õ¸Ö€ Õ®Ö€Õ¡Õ£Õ«Ö€Õ¨ Õ´Õ¡Õ¿Õ¹Õ« BluetoothShare Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¹Õ«Õ¶ Ö‡ Õ¡ÕµÕ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ« Ö†Õ¡ÕµÕ¬Õ¥Ö€ ÖƒÕ¸Õ­Õ¡Õ¶ÖÕ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€:" "Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Bluetooth Õ½Õ¡Ö€Ö„Õ« Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ«Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Ö‰" diff --git a/android/app/res/values-in/config.xml b/android/app/res/values-in/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-in/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-in/strings.xml b/android/app/res/values-in/strings.xml index fb188fe6ce04ba08afd5263f9c1a0e9975bccbe6..e6c31b9f38a68c12e3cb7ecccf1a9c7fa35a4607 100644 --- a/android/app/res/values-in/strings.xml +++ b/android/app/res/values-in/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Akses pengelola download." "Izinkan apl mengakses pengelola BluetoothShare dan menggunakannya untuk mentransfer file." "Memasukkan akses perangkat Bluetooth ke daftar yang diizinkan." diff --git a/android/app/res/values-is/config.xml b/android/app/res/values-is/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-is/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-is/strings.xml b/android/app/res/values-is/strings.xml index 2ee9ee86c1147899f9662284801f44ec137aacd5..667a6cb752a7d30a1fe30748d76f0f37bbb324a9 100644 --- a/android/app/res/values-is/strings.xml +++ b/android/app/res/values-is/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Aðgangur að niðurhalsstjórnun." "Leyfir forriti að fá aðgang að BluetoothShare-stjórnun og nota hana til að flytja skrár." "Setja aðgang Bluetooth-tækis á hvítan lista." diff --git a/android/app/res/values-it/config.xml b/android/app/res/values-it/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-it/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-it/strings.xml b/android/app/res/values-it/strings.xml index 5c02e81f0bbb1ba64333003f62d7ebbb7c6eb582..73c7df59438276a852e2fea70da0ea893548778a 100644 --- a/android/app/res/values-it/strings.xml +++ b/android/app/res/values-it/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Accedere alla gestione dei download." "Consente all\'applicazione di accedere al gestore BluetoothShare e di utilizzarlo per trasferire file." "Aggiunta dell\'accesso del dispositivo Bluetooth alla lista consentita." diff --git a/android/app/res/values-iw/config.xml b/android/app/res/values-iw/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-iw/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-iw/strings.xml b/android/app/res/values-iw/strings.xml index f2c3ce1a2ec20d3a9e98859a9034c81e43bd35bf..288935f50d03cd58af0e6022885e89c280b10b90 100644 --- a/android/app/res/values-iw/strings.xml +++ b/android/app/res/values-iw/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "גישה למנהל ההורדות." "â€×ž×פשר ל×פליקציה לגשת למנהל BluetoothShare ולהשתמש בו להעברת קבצי×." "â€×’ישה לרשימת ×”×”×™×ª×¨×™× ×©×œ מכשיר Bluetooth." diff --git a/android/app/res/values-ja/config.xml b/android/app/res/values-ja/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ja/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ja/strings.xml b/android/app/res/values-ja/strings.xml index 22adbff8bc23ff62ce381aada7445e547aaaa02a..39782962a8eb0d16ef4091223b4e8ea239954992 100644 --- a/android/app/res/values-ja/strings.xml +++ b/android/app/res/values-ja/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ダウンロード マãƒãƒ¼ã‚¸ãƒ£ãƒ¼ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚" "BluetoothShareマãƒãƒ¼ã‚¸ãƒ£ãƒ¼ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã¨ãれを利用ã—ãŸãƒ•ァイル転é€ã‚’アプリã«è¨±å¯ã—ã¾ã™ã€‚" "Bluetoothデãƒã‚¤ã‚¹ã«ã‚ˆã‚‹ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã—ã¾ã™ã€‚" diff --git a/android/app/res/values-ka/config.xml b/android/app/res/values-ka/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ka/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ka/strings.xml b/android/app/res/values-ka/strings.xml index 956be9d0bc4fb91fbf8824c4877367af2967537e..a46b7283b0925bc656c87250e3b31cdd22eacdc6 100644 --- a/android/app/res/values-ka/strings.xml +++ b/android/app/res/values-ka/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ჩáƒáƒ›áƒáƒ¢áƒ•ირთვების მენეჯერზე წვდáƒáƒ›áƒ." "áƒáƒœáƒ˜áƒ­áƒ”ბს áƒáƒžáƒ¡ BluetoothShare მენეჯერზე წვდáƒáƒ›áƒáƒ¡ დრმისი გáƒáƒ›áƒáƒ§áƒ”ნების უფლებáƒáƒ¡ ფáƒáƒ˜áƒšáƒ”ბის გáƒáƒ¡áƒáƒ’ზáƒáƒ•ნáƒáƒ“." "შეიყვáƒáƒœáƒ”თ Bluetooth მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის წვდáƒáƒ›áƒ მისáƒáƒ¦áƒ”ბ სიáƒáƒ¨áƒ˜." diff --git a/android/app/res/values-kk/config.xml b/android/app/res/values-kk/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-kk/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-kk/strings.xml b/android/app/res/values-kk/strings.xml index 39911157c3fd9fc983abb6078ed26b9d1acf7f59..4a977f371711cc696ff4f0f2ed44ccc3dd29f018 100644 --- a/android/app/res/values-kk/strings.xml +++ b/android/app/res/values-kk/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Жүктеу менеджеріне қол жетімділік." "Қолданбаға BluetoothБөліÑу менеджеріне кіріп, оны файлдары аудару үшін қолдану мүмкіндігін береді." "Bluetooth құрылғыÑын Ñ€Ò±Ò›Ñатқа ие тізімге қоÑу" diff --git a/android/app/res/values-km/config.xml b/android/app/res/values-km/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-km/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-km/strings.xml b/android/app/res/values-km/strings.xml index c75bf49328c70ab9a8a09c507dafb55030dffab0..c785fd29f32aa1812e8a233e24eeda1f3df6aca3 100644 --- a/android/app/res/values-km/strings.xml +++ b/android/app/res/values-km/strings.xml @@ -16,6 +16,7 @@ + "ប៊្លូធូស" "ចូល​ដំណើរ​ការ​កម្មវិធី​គ្រប់គ្រង​ការ​ទាញ​យក​។" "អនុញ្ញាážâ€‹áž²áŸ’យ​កម្មវិធី​ážáŸ’រូវ​​ចូល​ដំណើរការ​កម្មវិធី​គ្រប់គ្រង BluetoothShare ហើយ​​ប្រើ​វា​ដើម្បី​ផ្ទáŸážšâ€‹áž¯áž€ážŸáž¶ážšáŸ”" "សិទ្ធិ​ចូលប្រើ​ឧបករណáŸâ€‹áž”៊្លូធូស​ក្នុងបញ្ជី​អនុញ្ញាážâ€‹áŸ”" diff --git a/android/app/res/values-kn/config.xml b/android/app/res/values-kn/config.xml deleted file mode 100644 index 26b6b6b36d562ae0eb81d474be2884f605a0d7b2..0000000000000000000000000000000000000000 --- a/android/app/res/values-kn/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³" - diff --git a/android/app/res/values-kn/strings.xml b/android/app/res/values-kn/strings.xml index eafd720f5cde84d012b5cdcd826b48f99656965a..0e0ecd2ff09802fa53e89b47a6d4123d3927a87e 100644 --- a/android/app/res/values-kn/strings.xml +++ b/android/app/res/values-kn/strings.xml @@ -16,6 +16,7 @@ + "ಬà³à²²à³‚ಟೂತà³" "ಡೌನà³â€Œà²²à³‹à²¡à³â€Œ ನಿರà³à²µà²¾à²¹à²•ವನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²¿." "ಬà³à²²à³‚ಟೂತà³â€Œ ಹಂಚಿಕೆ ನಿರà³à²µà²¾à²¹à²• ಮತà³à²¤à³ ಫೈಲà³â€Œà²—ಳ ವರà³à²—ಾವಣೆಯನà³à²¨à³ ಬಳಸಲೠಅಪà³à²²à²¿à²•ೇಶನà³â€Œ ಅನà³à²®à²¤à²¿à²¸à³à²¤à³à²¤à²¦à³†." "ಸಮà³à²®à²¤à²¿à²ªà²Ÿà³à²Ÿà²¿ ಬà³à²²à³‚ಟೂತà³â€Œ ಸಾಧನವನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²¿." @@ -117,7 +118,7 @@ "ಪಟà³à²Ÿà²¿à²¯à²¿à²‚ದ ತೆರವà³à²—ೊಳಿಸಿ" "ತೆರವà³à²—ೊಳಿಸà³" "Now Playing" - "ಉಳಿಸಿ" + "ಸೇವೠಮಾಡಿ" "ರದà³à²¦à³à²®à²¾à²¡à²¿" "ಬà³à²²à³‚ಟೂತà³â€Œ ಮೂಲಕ ಹಂಚಿಕೊಳà³à²³à²²à³ ಬಯಸà³à²µ ಖಾತೆಗಳನà³à²¨à³ ಆಯà³à²•ೆಮಾಡಿ. ಸಂಪರà³à²•ಿಸà³à²µà²¾à²— ಖಾತೆಗಳಿಗೆ ಯಾವà³à²¦à³‡ ಪà³à²°à²µà³‡à²¶à²µà²¨à³à²¨à³ ನೀವೠಈಗಲೂ ಸಮà³à²®à²¤à²¿à²¸à²¬à³‡à²•ಾಗà³à²¤à³à²¤à²¦à³†." "ಉಳಿದಿರà³à²µ ಸà³à²²à²¾à²Ÿà³â€Œà²—ಳà³:" diff --git a/android/app/res/values-ko/config.xml b/android/app/res/values-ko/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ko/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ko/strings.xml b/android/app/res/values-ko/strings.xml index 899a495726c308bff8f6fd706063820f89540776..2995916a079cb6bb2ce3e90d6d9d84969556a335 100644 --- a/android/app/res/values-ko/strings.xml +++ b/android/app/res/values-ko/strings.xml @@ -16,6 +16,7 @@ + "블루투스" "다운로드 관리ìžì— 액세스합니다." "앱ì—서 BluetoothShare 관리ìžì— 액세스하고 ì´ë¥¼ 사용하여 파ì¼ì„ 전송할 수 있ë„ë¡ í•©ë‹ˆë‹¤." "블루투스 기기 액세스 허용" diff --git a/android/app/res/values-ky/config.xml b/android/app/res/values-ky/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ky/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ky/strings.xml b/android/app/res/values-ky/strings.xml index b204a24a9b6fb3c3706a914e8052d24bf88b31e6..f5bcd7526c45f8966a5f9caec7d862b5a047c995 100644 --- a/android/app/res/values-ky/strings.xml +++ b/android/app/res/values-ky/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Жүктөө менежерине жетүү." "Колдонмого BluetoothÐлмашуу менежерине жетип, ал аркылуу файлдарды өткөрүү урукÑатын берет." "Bluetooth түзмөгүнө кирүү мүмкүнчүлүгүн урукÑат берилгендердин тизмеÑине жайгаштыруу." diff --git a/android/app/res/values-lo/config.xml b/android/app/res/values-lo/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-lo/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-lo/strings.xml b/android/app/res/values-lo/strings.xml index 4128c619ab71c25820f4df15f61289896c9bc254..7068a289af9ecabb0ff144b6a297449e5c037179 100644 --- a/android/app/res/values-lo/strings.xml +++ b/android/app/res/values-lo/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ເຂົ້າເຖິງໂຕຈັດàºàº²àº™àºàº²àº™àº”າວໂຫລດ​." "ອະນຸàºàº²àº”ໃຫ້à»àº­àº±àºšàº¯àº™àºµà»‰à»€àº‚ົາເຖິງໂຕຈັດàºàº²àº™ BluetoothShare à»àº¥àº°à»ƒàºŠà»‰àº¡àº±àº™à»€àºžàº·à»ˆàº­àºªàº»à»ˆàº‡à»„ຟລ໌." "ສ້າງລາàºàºŠàº·à»ˆàºàº­àº¡àº®àº±àºšàºàº²àº™à»€àº‚ົ້າເຖິງອຸປະàºàº­àº™ Bluetooth." diff --git a/android/app/res/values-lt/config.xml b/android/app/res/values-lt/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-lt/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-lt/strings.xml b/android/app/res/values-lt/strings.xml index db6e1067cc90887c4fa40341e5156782e7b5f79d..1851fef1cb12a522b9cd06f630ab30a8f00eeb06 100644 --- a/android/app/res/values-lt/strings.xml +++ b/android/app/res/values-lt/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Pasiekti atsisiuntimo tvarkytuvÄ™." "Leidžiama programai pasiekti „BluetoothShare“ tvarkyklÄ™ ir naudoti jÄ… failams perkelti." "Ä® leidžiamųjų sÄ…rašą įtraukto „Bluetooth“ įrenginio prieiga." diff --git a/android/app/res/values-lv/config.xml b/android/app/res/values-lv/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-lv/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-lv/strings.xml b/android/app/res/values-lv/strings.xml index 3b93f36a98678f7d0a83c51ee1e85eb936ba02e2..431013fa6689cf47f29b227bf1bad50b20eca004 100644 --- a/android/app/res/values-lv/strings.xml +++ b/android/app/res/values-lv/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Piekļuve lietojumprogrammai Download Manager." "Ä»auj lietotnei piekļūt BluetoothShare pÄrvaldniekam, lai to izmantotu failu pÄrsÅ«tīšanai." "Iekļaut Bluetooth ierÄ«ces piekļuvi atļauÅ¡anas sarakstÄ." diff --git a/android/app/res/values-mk/config.xml b/android/app/res/values-mk/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-mk/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-mk/strings.xml b/android/app/res/values-mk/strings.xml index bbf1b4f93049c3878c7509e78eb185742b416e5f..383808d3a0c87eb8f09c076f704e2c6298e42301 100644 --- a/android/app/res/values-mk/strings.xml +++ b/android/app/res/values-mk/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ПриÑтапи кон управувач за преземања." "Овозможува апликацијата да приÑтапи до менаџерот на BluetoothShare и да го кориÑти за Ð¿Ñ€ÐµÐ½Ð¾Ñ Ð½Ð° датотеки." "ПриÑтап до уредот Ñо Bluetooth на белата лиÑта." diff --git a/android/app/res/values-ml/config.xml b/android/app/res/values-ml/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ml/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ml/strings.xml b/android/app/res/values-ml/strings.xml index 618069c0fdfcc65d0ca1fdbe48820d456e2e8d44..bd3d6660f0fc96be100bd788a98632c8a73cbb43 100644 --- a/android/app/res/values-ml/strings.xml +++ b/android/app/res/values-ml/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ഡൗൺലോഡൠമാനേജർ ആകàµâ€Œà´¸à´¸àµà´¸àµ ചെയàµà´¯àµà´•." "BluetoothShare മാനേജർ ആകàµâ€Œà´¸à´¸àµà´¸àµà´šàµ†à´¯àµà´¯à´¾à´¨àµà´‚ ഫയലàµà´•ൾ കൈമാറാൻ അതൠഉപയോഗികàµà´•ാനàµà´‚ à´…à´ªàµà´²à´¿à´•àµà´•േഷനെ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨àµ." "Bluetooth ഉപകരണതàµà´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ ആകàµà´¸à´¸à´¿à´¨àµà´±àµ† à´…à´¨àµà´®à´¤à´¿ ലിസàµà´±àµà´±àµ." diff --git a/android/app/res/values-mn/config.xml b/android/app/res/values-mn/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-mn/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-mn/strings.xml b/android/app/res/values-mn/strings.xml index f7eb2cbcdb31e60baedccd29b96e93fcb5d2b814..5f76295016ac62a0bc1426124314057c3cc462b8 100644 --- a/android/app/res/values-mn/strings.xml +++ b/android/app/res/values-mn/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Татан авалтын менежерт хандалт хийх." "Ðпп-д BluetoothShare менежерт хандах, үүнийг ашиглан файл дамжуулах боломж олгоно." "Зөвшөөрөх жагÑаалтын bluetooth төхөөрөмжийн хандалт." diff --git a/android/app/res/values-mr/config.xml b/android/app/res/values-mr/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-mr/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-mr/strings.xml b/android/app/res/values-mr/strings.xml index 1c0b188342d579da6638b7cd2a32e725dbd562c6..0162bfae10aa5c4ef68a592d68efb8177779cabb 100644 --- a/android/app/res/values-mr/strings.xml +++ b/android/app/res/values-mr/strings.xml @@ -16,6 +16,7 @@ + "बà¥à¤²à¥‚टूथ" "डाउनलोड वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• अâ€à¥…कà¥à¤¸à¥‡à¤¸ करा." "अâ€à¥…पला BluetoothShare वà¥â€à¤¯à¤µà¤¸à¥â€à¤¥à¤¾à¤ªà¤•ामधà¥â€à¤¯à¥‡ पà¥à¤°à¤µà¥‡à¤¶ करणà¥â€à¤¯à¤¾à¤šà¥€ आणि फाइल सà¥â€à¤¥à¤¾à¤¨à¤¾à¤‚तरित करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ तà¥à¤¯à¤¾à¤šà¤¾ वापर करणà¥â€à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ देते." "बà¥à¤²à¥‚टूथ डिवà¥â€à¤¹à¤¾à¤‡à¤¸ अâ€à¥…कà¥à¤¸à¥‡à¤¸ ॲकà¥à¤¸à¥‡à¤ªà¥à¤Ÿà¤²à¤¿à¤¸à¥à¤Ÿ करा." diff --git a/android/app/res/values-ms/config.xml b/android/app/res/values-ms/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ms/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ms/strings.xml b/android/app/res/values-ms/strings.xml index 94e0cec3469a4edd01dfa43932af7a1b60185f28..195866c6aa1d48ae7d4c88b2b893413f68aad164 100644 --- a/android/app/res/values-ms/strings.xml +++ b/android/app/res/values-ms/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Akses pengurus muat turun." "Membenarkan aplikasi mengakses pengurus Perkongsian Bluetooth dan menggunakannya untuk memindahkan fail." "Senarai terima akses peranti bluetooth." diff --git a/android/app/res/values-my/config.xml b/android/app/res/values-my/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-my/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-my/strings.xml b/android/app/res/values-my/strings.xml index 00c7d99eb86d985f970ad909f953e4fa319ac4ce..295afd15aeb2d797c3be2c06217c9a6f9087abb6 100644 --- a/android/app/res/values-my/strings.xml +++ b/android/app/res/values-my/strings.xml @@ -16,6 +16,7 @@ + "ဘလူးá€á€¯á€žá€º" "ဒေါင်းလုပ်မန်နေဂျာကို အသုံးပြုနိုင်မည်" "အပလီကေးရှင်းအား ဘလူးá€á€¯á€žá€ºá€™á€»á€¾á€á€±á€™á€¾á€¯ မန်နေဂျာကို အသုံးပြုá€á€½á€„့်ပေးပြီး ဖိုင်လွှဲရန် အသုံးပြုပါ" "ဘလူးá€á€¯á€žá€ºá€šá€¬á€šá€®á€œá€€á€ºá€á€¶á€…ာရင်းကို အသုံးပြုá€á€½á€„့်á‹" diff --git a/android/app/res/values-nb/config.xml b/android/app/res/values-nb/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-nb/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-nb/strings.xml b/android/app/res/values-nb/strings.xml index ca2e17597cdb6ef02f757a1134df36210fee92ce..f1586840857e8e5fca1e3c49a41a77feccd4bd00 100644 --- a/android/app/res/values-nb/strings.xml +++ b/android/app/res/values-nb/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Ã…pne nedlastingsbehandling." "Gir appen tilgang til BluetoothShare-administratoren, og tillatelse til Ã¥ bruke det til filoverføring." "Godkjenn tilgang for Bluetooth-enheter." diff --git a/android/app/res/values-ne/config.xml b/android/app/res/values-ne/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ne/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ne/strings.xml b/android/app/res/values-ne/strings.xml index 9167622ac81dfcbf90dbd7ed11376122b0204d0d..87729300f0e94e33fe53be3a1f99268c29af6a43 100644 --- a/android/app/res/values-ne/strings.xml +++ b/android/app/res/values-ne/strings.xml @@ -16,6 +16,7 @@ + "बà¥à¤²à¥à¤Ÿà¥à¤¥" "डाउनलोड मà¥à¤¯à¤¾à¤¨à¥‡à¤œà¤° पहà¥à¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤" "à¤à¤ªà¤²à¤¾à¤ˆ बà¥à¤²à¥à¤Ÿà¥à¤¥à¤¸à¤¾à¤à¥‡à¤¦à¤¾à¤°à¥€ पà¥à¤°à¤¬à¤¨à¥à¤§à¤• पहà¥à¤à¤šà¤•ो अनà¥à¤®à¤¤à¤¿ दिनà¥à¤› र यसलाई फाइलहरू सà¥à¤¥à¤¾à¤¨à¤¾à¤¨à¥à¤¤à¤°à¤£ गरà¥à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¦à¤›à¥¤" "बà¥à¤²à¥à¤Ÿà¥‚थ चलà¥à¤¨à¥‡ यनà¥à¤¤à¥à¤°à¤•ो à¤à¤•à¥à¤¸à¥‡à¤¸ शà¥à¤µà¥‡à¤¤à¤¸à¥‚चीमा राखà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤" diff --git a/android/app/res/values-nl/config.xml b/android/app/res/values-nl/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-nl/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-nl/strings.xml b/android/app/res/values-nl/strings.xml index 7e40f0f96a3e845d6cc4d32a573a403bee79242f..cbda859d0667e229ab0a7c9b2934e68985520feb 100644 --- a/android/app/res/values-nl/strings.xml +++ b/android/app/res/values-nl/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Downloadbeheer tonen." "Hiermee krijgt de app toegang tot de beheerfunctie voor delen via bluetooth om deze functie te gebruiken voor het overdragen van bestanden." "Toegang voor bluetooth-apparaat op toelatingslijst zetten." diff --git a/android/app/res/values-or/config.xml b/android/app/res/values-or/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-or/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-or/strings.xml b/android/app/res/values-or/strings.xml index 75b5882086e52aa98bc50d79f7bea45cab9fd3d4..920ca675d6ed543ba8bd2a47b8e7cbf782167a94 100644 --- a/android/app/res/values-or/strings.xml +++ b/android/app/res/values-or/strings.xml @@ -16,6 +16,7 @@ + "ବà­à¬²à­à¬Ÿà­à¬¥" "ଡାଉନଲୋଡ ମà­à­Ÿà¬¾à¬¨à­‡à¬œà¬°à­â€Œà¬•ୠଆକà­à¬¸à­‡à¬¸à­â€Œ କରନà­à¬¤à­à¥¤" "BluetoothShare ମà­à­Ÿà¬¾à¬¨à­‡à¬œà¬°à­â€Œ ଆକà­à¬¸à­‡à¬¸à­â€Œ କରି ଫାଇଲà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬• ଟà­à¬°à¬¾à¬¨à­à¬¸à¬«à¬°à­â€Œ କରିବାକୠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବା ପାଇଠଆପà­â€Œà¬•ୠଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­à¥¤" "ବà­à¬²à­à¬Ÿà­à¬¥à­ ଡିଭାଇସର ଆକà­à¬¸à­‡à¬¸à¬•ୠଗà­à¬°à¬¹à¬£-ସୂଚୀରେ ରଖନà­à¬¤à­à¥¤" diff --git a/android/app/res/values-pa/config.xml b/android/app/res/values-pa/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-pa/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-pa/strings.xml b/android/app/res/values-pa/strings.xml index d265fc2ae4c1520f2cb6076a81431347be7f850d..c4258cc308ed9008a252909b7a48ebfddf442f53 100644 --- a/android/app/res/values-pa/strings.xml +++ b/android/app/res/values-pa/strings.xml @@ -16,6 +16,7 @@ + "ਬਲੂਟà©à©±à¨¥" "ਡਾਊਨਲੋਡ ਪà©à¨°à¨¬à©°à¨§à¨• ਤੱਕ ਪਹà©à©°à¨šà¥¤" "à¨à¨ª ਨੂੰ BluetoothShare ਪà©à¨°à¨¬à©°à¨§à¨• ਤੱਕ ਪਹà©à©°à¨š ਅਤੇ ਫ਼ਾਈਲਾਂ ਟà©à¨°à¨¾à¨‚ਸਫਰ ਕਰਨ ਲਈ ਇਸਦੀ ਵਰਤੋਂ ਕਰਨ ਦਿੰਦਾ ਹੈ।" "ਅਕਸੈਪਟਲਿਸਟ ਬਲੂਟà©à©±à¨¥ ਡੀਵਾਈਸ ਪਹà©à©°à¨šà¥¤" diff --git a/android/app/res/values-pl/config.xml b/android/app/res/values-pl/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-pl/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-pl/strings.xml b/android/app/res/values-pl/strings.xml index 2b55f17cec747bcf872d6275716707297c16c73e..d8ef0a41f8ffe1681910bd6a9faf387891434b2b 100644 --- a/android/app/res/values-pl/strings.xml +++ b/android/app/res/values-pl/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "DostÄ™p do menedżera pobierania." "Zezwala aplikacji na dostÄ™p do menedżera BluetoothShare i używanie go do przesyÅ‚ania plików." "Dodanie urzÄ…dzenia Bluetooth do zaufanych." diff --git a/android/app/res/values-pt-rPT/config.xml b/android/app/res/values-pt-rPT/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-pt-rPT/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-pt-rPT/strings.xml b/android/app/res/values-pt-rPT/strings.xml index a73b3a70f5da5d3da2fa66033a69e79dedcb00d7..db13dd6009b48c7ef9743dc28078f9dd42686dad 100644 --- a/android/app/res/values-pt-rPT/strings.xml +++ b/android/app/res/values-pt-rPT/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Aceder ao gestor de transferências." "Permite à app aceder ao gestor BluetoothShare e utilizá-lo para transferir ficheiros." "Colocar na lista de autorizações o acesso do dispositivo Bluetooth." diff --git a/android/app/res/values-pt/config.xml b/android/app/res/values-pt/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-pt/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-pt/strings.xml b/android/app/res/values-pt/strings.xml index fcb55a77a636e0ca60bfde1dc5d7d201a06d912f..68260daa6ac7393b7f6ae1e495b9b29ba5b1a128 100644 --- a/android/app/res/values-pt/strings.xml +++ b/android/app/res/values-pt/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Acessar o gerenciador de download." "Permite que o app acesse e use o gerenciador BluetoothShare para transferir arquivos." "Adicionar o acesso do dispositivo Bluetooth à lista de permissões." diff --git a/android/app/res/values-ro/config.xml b/android/app/res/values-ro/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ro/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ro/strings.xml b/android/app/res/values-ro/strings.xml index c2fc6cdf278250f54223ab200b5f2b4478e93f34..e54f39f37d3b81f8bbc005b01443500ac34435da 100644 --- a/android/app/res/values-ro/strings.xml +++ b/android/app/res/values-ro/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Accesează managerul de descărcare." "Permite aplicaÈ›iilor să acceseze managerul Distribuire prin Bluetooth È™i să-l utilizeze la transferul fiÈ™ierelor." "Acceptă accesul la dispozitivul Bluetooth." diff --git a/android/app/res/values-ru/config.xml b/android/app/res/values-ru/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ru/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ru/strings.xml b/android/app/res/values-ru/strings.xml index df7a0e95d575265e0b29e6ad0f90358e26b59de5..37047a0da35397d79b45ee29bd504c85534c3810 100644 --- a/android/app/res/values-ru/strings.xml +++ b/android/app/res/values-ru/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ДоÑтуп к диÑпетчеру загрузки." "Приложение получит доÑтуп к диÑпетчеру обмена файлами по Bluetooth и Ñможет иÑпользовать его Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸ файлов." "ДоÑтуп Ð´Ð»Ñ ÑƒÑтройÑтв Bluetooth из ÑпиÑка разрешенных" diff --git a/android/app/res/values-si/config.xml b/android/app/res/values-si/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-si/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-si/strings.xml b/android/app/res/values-si/strings.xml index b96de200f6469a84daa84c05b1b2d987fcbb49f9..26a964f9e7cd84106c378bd3c86cbb4154e56694 100644 --- a/android/app/res/values-si/strings.xml +++ b/android/app/res/values-si/strings.xml @@ -16,6 +16,7 @@ + "බ්ලූටූත්" "à¶¶à·à¶œà·à¶±à·“ම් කළමනà·à¶šà¶»à·” à¶´à·Šâ€à¶»à·€à·šà· වන්න." "යෙදුමට බ්ලූටූත් බෙද෠ගà·à¶±à·“ම් කළමනà·à¶šà¶»à·” වෙත à¶´à·Šâ€à¶»à·€à·šà· වීමට ඉඩ දී එය ගොනු මà·à¶»à·” කිරීමට à¶·à·à·€à·’ත෠කරන්න." "පිළිගත් à¶½à·à¶ºà·’ස්තු බ්ලූටූත් à¶‹à¶´à·à¶‚à¶œ à¶´à·Šâ€à¶»à·€à·šà·à¶º." diff --git a/android/app/res/values-sk/config.xml b/android/app/res/values-sk/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-sk/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-sk/strings.xml b/android/app/res/values-sk/strings.xml index 630cbe5dd5b32eb6df284e2acae58e181b043e96..d67347b4de3e792c277b51e05eb736e1ad2edc84 100644 --- a/android/app/res/values-sk/strings.xml +++ b/android/app/res/values-sk/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ZískaÅ¥ prístup k správcovi sÅ¥ahovania." "Umožňuje aplikácii pristupovaÅ¥ k Správcovi BluetoothShare a použiÅ¥ ho na prenos súborov." "Prístup povoleného zariadenia Bluetooth." diff --git a/android/app/res/values-sl/config.xml b/android/app/res/values-sl/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-sl/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-sl/strings.xml b/android/app/res/values-sl/strings.xml index e7ec7116385d8dcabfea1359165980e1964f79d6..3946c0cabee19cf0d28d6d2d8228f6ccb77b6d48 100644 --- a/android/app/res/values-sl/strings.xml +++ b/android/app/res/values-sl/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Dostop do upravitelja prenosov." "Aplikaciji omogoÄa dostop do upravitelja BluetoothShare in njegovo uporabo za prenaÅ¡anje datotek." "Napravo Bluetooth doda na seznam z dovoljenim dostopom." diff --git a/android/app/res/values-sq/config.xml b/android/app/res/values-sq/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-sq/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-sq/strings.xml b/android/app/res/values-sq/strings.xml index ec12ee14ec507f22c2ba1190164f3f1f37edb706..f3ed014bfed4206c42261da4eedb2f75ebed2c17 100644 --- a/android/app/res/values-sq/strings.xml +++ b/android/app/res/values-sq/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Qasu në menaxherin e shkarkimit." "Lejon aplikacionin të ketë qasje në menaxherin \"Shpërndarje përmes bluetooth-it\" (BluetoothShare) dhe ta përdorë për transferim skedarësh." "Autorizimi në listën e pranimit të pajisjes me Bluetooth." diff --git a/android/app/res/values-sr/config.xml b/android/app/res/values-sr/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-sr/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-sr/strings.xml b/android/app/res/values-sr/strings.xml index 1eeb9be29bc4d9572ce9ee0cbab049d9b01723d9..b851eb159504e5384c9d43a1081391cce04531ce 100644 --- a/android/app/res/values-sr/strings.xml +++ b/android/app/res/values-sr/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ПриÑтуп менаџеру преузимања." "Омогућава апликацији да приÑтупа менаџеру за дељење преко Bluetooth-а и да га кориÑти за Ð¿Ñ€ÐµÐ½Ð¾Ñ Ð´Ð°Ñ‚Ð¾Ñ‚ÐµÐºÐ°." "Стави приÑтуп Bluetooth уређаја на лиÑту прихваћених уређаја." diff --git a/android/app/res/values-sv/config.xml b/android/app/res/values-sv/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-sv/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-sv/strings.xml b/android/app/res/values-sv/strings.xml index 5be5f5647638f20e6ed35e09a2b3d6611133db06..a197bdaba32a25797c6111677aa6171f6bc1959f 100644 --- a/android/app/res/values-sv/strings.xml +++ b/android/app/res/values-sv/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Ã…tkomst till nedladdningshanterare." "TillÃ¥ter att appen använder BluetoothShare-hanteraren vid överföring av filer." "Lägg till Ã¥tkomst för Bluetooth-enheten pÃ¥ godkännandelistan." diff --git a/android/app/res/values-sw/config.xml b/android/app/res/values-sw/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-sw/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-sw/strings.xml b/android/app/res/values-sw/strings.xml index f16b20a317f9970e977cf29e8dcf7d7accc22bb7..29768f66afd0b61b94bd4d1c97e39d6534307cc0 100644 --- a/android/app/res/values-sw/strings.xml +++ b/android/app/res/values-sw/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Fikia kidhibiti cha vipakuliwa." "Huruhusu programu kufikia kidhibiti cha BluetoothShare na kukitumia kuhamisha faili." "Orodha ya vifaa vyenye bluetooth vilivyoruhusiwa kufikia." diff --git a/android/app/res/values-ta/config.xml b/android/app/res/values-ta/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ta/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ta/strings.xml b/android/app/res/values-ta/strings.xml index e499491e952bb50a915da84bdc1c0215e1e99d9f..6e040191dd4b22761895399d6d2099cefe6e5e42 100644 --- a/android/app/res/values-ta/strings.xml +++ b/android/app/res/values-ta/strings.xml @@ -16,6 +16,7 @@ + "பà¯à®³à¯‚டூதà¯" "பதிவிறகà¯à®• நிரà¯à®µà®¾à®•ியை அணà¯à®•வà¯à®®à¯." "BluetoothShare நிரà¯à®µà®¾à®•ியை அணà¯à®•à¯à®µà®¤à®±à¯à®•à¯à®ªà¯ ஆபà¯à®¸à¯ˆ அனà¯à®®à®¤à®¿à®¤à¯à®¤à¯, ஃபைலà¯à®•ளைப௠பரிமாறà¯à®± அதைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•ிறதà¯." "பà¯à®³à¯‚டூத௠சாதன அணà¯à®•ல௠à®à®±à¯à®ªà¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®¯à®²à¯." diff --git a/android/app/res/values-te/config.xml b/android/app/res/values-te/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-te/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-te/strings.xml b/android/app/res/values-te/strings.xml index 44532e04c758a4387d148055695466d5d6ec43e8..788a1869271a6b7c05ba7526d3e505428bffe7ca 100644 --- a/android/app/res/values-te/strings.xml +++ b/android/app/res/values-te/strings.xml @@ -16,6 +16,7 @@ + "à°¬à±à°²à±‚టూతà±" "డౌనà±â€Œà°²à±‹à°¡à± మేనేజరà±â€Œà°¨à± యాకà±à°¸à±†à°¸à± చేయండి." "à°¬à±à°²à±‚టూతౠభాగసà±à°µà°¾à°®à±à°¯ మేనేజరà±â€Œà°¨à± యాకà±à°¸à±†à°¸à± చేయడానికి యాపà±â€Œà°¨à± à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది మరియౠఫైళà±à°²à°¨à± బదిలీ చేయడానికి దీనà±à°¨à°¿ ఉపయోగిసà±à°¤à±à°‚ది." "à°…à°¨à±à°®à°¤à°¿ లిసà±à°Ÿà±â€Œà°²à±‹ ఉంచిన à°¬à±à°²à±‚టూతౠపరికర యాకà±à°¸à±†à°¸à±." diff --git a/android/app/res/values-th/config.xml b/android/app/res/values-th/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-th/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-th/strings.xml b/android/app/res/values-th/strings.xml index b90cd058cb71cde78b234760cbcc9772887e6974..c23e367888d219ad59d94e89860611a33b3b84d1 100644 --- a/android/app/res/values-th/strings.xml +++ b/android/app/res/values-th/strings.xml @@ -16,6 +16,7 @@ + "บลูทูธ" "เข้าถึงตัวจัดà¸à¸²à¸£à¸à¸²à¸£à¸”าวน์โหลด" "อนุà¸à¸²à¸•ให้à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันเข้าถึงà¹à¸¥à¸°à¹ƒà¸Šà¹‰à¸•ัวจัดà¸à¸²à¸£ BluetoothShare เพื่อถ่ายโอนไฟล์" "รายà¸à¸²à¸£à¸—ี่อนุà¸à¸²à¸•à¸à¸²à¸£à¹€à¸‚้าถึงอุปà¸à¸£à¸“์บลูทูธ" diff --git a/android/app/res/values-tl/config.xml b/android/app/res/values-tl/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-tl/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-tl/strings.xml b/android/app/res/values-tl/strings.xml index c7fc5e00c3d00bba857372afa7a44445e4e50290..aeffc11a9da57436a242b120b602307b5b2eda43 100644 --- a/android/app/res/values-tl/strings.xml +++ b/android/app/res/values-tl/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "I-access ang tagapamahala ng pag-download." "Binibigyang-daan ang app na i-access ang BluetoothShare manager at gamitin ito upang maglipat ng mga file." "Mag-acceptlist ng access ng bluetooth device." diff --git a/android/app/res/values-tr/config.xml b/android/app/res/values-tr/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-tr/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-tr/strings.xml b/android/app/res/values-tr/strings.xml index 064944a2eefc44ddc532939c2833fd658397aa0e..020bb4f494f0a15403dd5604376aa1c850400c47 100644 --- a/android/app/res/values-tr/strings.xml +++ b/android/app/res/values-tr/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "İndirme yöneticisine eriÅŸin." "Uygulamaya, BluetoothShare yöneticisine eriÅŸme ve bunu dosyaları aktarmak için kullanma izni verir." "Onay listesi Bluetooth cihaz eriÅŸimi." diff --git a/android/app/res/values-uk/config.xml b/android/app/res/values-uk/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-uk/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-uk/strings.xml b/android/app/res/values-uk/strings.xml index 7d1ced556795e8e6c4f06291af79f531460a13b7..244246df51df66ac605211931f894e45304e2c54 100644 --- a/android/app/res/values-uk/strings.xml +++ b/android/app/res/values-uk/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "ДоÑтуп до менедж. завантаж." "ДозволÑÑ” програмі отримувати доÑтуп до менеджера BluetoothShare Ñ– викориÑтовувати його Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ð²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð²." "ДоÑтуп до дозволеного приÑтрою з Bluetooth." diff --git a/android/app/res/values-ur/config.xml b/android/app/res/values-ur/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-ur/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-ur/strings.xml b/android/app/res/values-ur/strings.xml index 21b6ec6743230e74ae39d5eee96df9f3acc710ee..36ce6b90b139e4bcc1adcc5ce2eb4b691e727ce0 100644 --- a/android/app/res/values-ur/strings.xml +++ b/android/app/res/values-ur/strings.xml @@ -16,6 +16,7 @@ + "بلوٹوتھ" "ڈاؤن لوڈ مینیجر تک رسائی حاصل کریں۔" "â€Ø§ÛŒÙ¾ Ú©Ùˆ ÙØ§Ø¦Ù„یں منتقل کرنے کیلئے BluetoothShare مینیجر تک رسائی اور اسے استعمال کرنے Ú©ÛŒ اجازت دیتا ÛÛ’Û”" "بلوٹوتھ Ø¢Ù„Û ØªÚ© رسائی Ú©Ùˆ ÙÛØ±Ø³Øª قبول کریں۔" diff --git a/android/app/res/values-uz/config.xml b/android/app/res/values-uz/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-uz/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-uz/strings.xml b/android/app/res/values-uz/strings.xml index 90051339232fa478e9d5c3cb479ed0b1524970eb..d456f10b118a22abc0877af59fc7e635cfed5617 100644 --- a/android/app/res/values-uz/strings.xml +++ b/android/app/res/values-uz/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Yuklab olish menejeriga ruxsat." "Ilovaga BluetoothShare menejeriga kirishga va undan fayllar uzatishda foydalanishga ruxsat beradi." "Ishonchli Bluetooth qurilmalari roÊ»yxatiga kirish." diff --git a/android/app/res/values-vi/config.xml b/android/app/res/values-vi/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-vi/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-vi/strings.xml b/android/app/res/values-vi/strings.xml index 8ae08be07a394f2e9d7b06aef340a2ec7d5d9186..61ae148f2d4a7c5378bd5d8be6187db0360e1705 100644 --- a/android/app/res/values-vi/strings.xml +++ b/android/app/res/values-vi/strings.xml @@ -16,6 +16,7 @@ + "Bluetooth" "Truy cập trình quản lý tải xuống." "Cho phép ứng dụng truy cập trình quản lý BluetoothShare và sá»­ dụng trình quản lý đó để chuyển tệp." "Quyá»n sá»­ dụng thiết bị Bluetooth trong danh sách chấp nhận." diff --git a/android/app/res/values-zh-rCN/config.xml b/android/app/res/values-zh-rCN/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-zh-rCN/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-zh-rCN/strings.xml b/android/app/res/values-zh-rCN/strings.xml index 79ce555cd17c5ed26c9c916a35deae145efff69f..e04dede015342b392cd9ed41ede629ccb0537a91 100644 --- a/android/app/res/values-zh-rCN/strings.xml +++ b/android/app/res/values-zh-rCN/strings.xml @@ -16,6 +16,7 @@ + "è“牙" "使用下载管ç†å™¨ã€‚" "å…许应用访问è“牙共享 (BluetoothShare) 管ç†å™¨å¹¶å°†å…¶ç”¨äºŽä¼ è¾“文件。" "å°†è“牙设备加入许å¯åå•。" diff --git a/android/app/res/values-zh-rHK/config.xml b/android/app/res/values-zh-rHK/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-zh-rHK/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-zh-rHK/strings.xml b/android/app/res/values-zh-rHK/strings.xml index 09978ecdbc2bb368bf8bd767094ca2f887b7fd01..d3f427c15a091ab8f07027bbd76c20a57fbe7f0d 100644 --- a/android/app/res/values-zh-rHK/strings.xml +++ b/android/app/res/values-zh-rHK/strings.xml @@ -16,6 +16,7 @@ + "è—牙" "å­˜å–下載管ç†å“¡ã€‚" "å…許應用程å¼å­˜å– BluetoothShare 管ç†å“¡ä¸¦ä½¿ç”¨ BluetoothShare 管ç†å“¡å‚³è¼¸æª”案。" "å°‡è—牙è£ç½®åŠ å…¥å…許å單。" diff --git a/android/app/res/values-zh-rTW/config.xml b/android/app/res/values-zh-rTW/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-zh-rTW/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-zh-rTW/strings.xml b/android/app/res/values-zh-rTW/strings.xml index d840289fbf3a9996eb57d984fc0d502a05429216..0884f6e68e7d0a45623a3b4cc8fc32f46016a65a 100644 --- a/android/app/res/values-zh-rTW/strings.xml +++ b/android/app/res/values-zh-rTW/strings.xml @@ -16,6 +16,7 @@ + "è—牙" "å­˜å–下載管ç†å“¡ã€‚" "å…許應用程å¼å­˜å– BluetoothShare 管ç†å“¡ï¼Œä¸¦å¯ä½¿ç”¨ BluetoothShare 管ç†å“¡å‚³è¼¸æª”案。" "å°‡è—牙è£ç½®å­˜å–權é™åŠ å…¥è¨±å¯æ¸…單。" diff --git a/android/app/res/values-zu/config.xml b/android/app/res/values-zu/config.xml deleted file mode 100644 index 4f96544b67afeaba2c5e363d2f65e01bd9e11263..0000000000000000000000000000000000000000 --- a/android/app/res/values-zu/config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - "com.android.settings" - diff --git a/android/app/res/values-zu/strings.xml b/android/app/res/values-zu/strings.xml index fbaf7183daae799e067378e61ca8c2f618360079..d36cbaf1d1ed9559fa1a05ee3d66c8054ad4cef2 100644 --- a/android/app/res/values-zu/strings.xml +++ b/android/app/res/values-zu/strings.xml @@ -16,6 +16,7 @@ + "I-Bluetooth" "Finyelela kumphathi wokulayisha." "Ivumela uhlelo lokusebenza ukufinyelela umphathi we-BluetoothShare ngisho nokuyisebenzisela ukudlulisa amafayela." "Uhlu lokwamukela lokufinyelela kudivayisi ye-Bluetooth." diff --git a/android/app/res/values/config.xml b/android/app/res/values/config.xml index 3e0e9337538e8c0e884ac416a11007b1857af969..7418000e8e26a1bb8d9e508c494d413bd78b78b2 100644 --- a/android/app/res/values/config.xml +++ b/android/app/res/values/config.xml @@ -163,17 +163,6 @@ com.google.android.gms - - true - com.google.android.gms @@ -192,6 +181,8 @@ true - - true + + + https://support.google.com/pixelphone/answer/12639358 + diff --git a/android/app/res/values/strings.xml b/android/app/res/values/strings.xml index 21acf1bdf022cc6b080b237f9f4d955c4f793aa2..4018d3cab302f72c27f7a253976e7110cfe3422e 100644 --- a/android/app/res/values/strings.xml +++ b/android/app/res/values/strings.xml @@ -14,6 +14,8 @@ limitations under the License. --> + Bluetooth + - * * - * * * - * @param uci Bearer Unique Client Identifier - * @param uriSchemes URI Schemes supported list + * @param uci Bearer Unique Client Identifier + * @param uriSchemes URI Schemes supported list * @param capabilities bearer capabilities - * @param provider Network provider name - * @param technology Network technology - * @param executor {@link Executor} object on which callback will be - * executed. The Executor object is required. - * @param callback {@link Callback} object to which callback messages will - * be sent. The Callback object is required. + * @param provider Network provider name + * @param technology Network technology + * @param executor {@link Executor} object on which callback will be executed. The Executor + * object is required. + * @param callback {@link Callback} object to which callback messages will be sent. The Callback + * object is required. * @return true on success, false otherwise * @hide */ @SuppressLint("ExecutorRegistration") @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean registerBearer(@Nullable String uci, - @NonNull List uriSchemes, int capabilities, - @NonNull String provider, int technology, - @NonNull Executor executor, @NonNull Callback callback) { + public boolean registerBearer( + @Nullable String uci, + @NonNull List uriSchemes, + int capabilities, + @NonNull String provider, + int technology, + @NonNull Executor executor, + @NonNull Callback callback) { if (DBG) { Log.d(TAG, "registerBearer"); } @@ -510,8 +510,15 @@ public final class BluetoothLeCallControl implements BluetoothProfile { mCallback = callback; try { CallbackWrapper callbackWrapper = new CallbackWrapper(executor, callback); - service.registerBearer(mToken, callbackWrapper, uci, uriSchemes, capabilities, - provider, technology, mAttributionSource); + service.registerBearer( + mToken, + callbackWrapper, + uci, + uriSchemes, + capabilities, + provider, + technology, + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); @@ -547,7 +554,6 @@ public final class BluetoothLeCallControl implements BluetoothProfile { return; } - int ccid = mCcid; mCcid = 0; mCallback = null; @@ -572,11 +578,9 @@ public final class BluetoothLeCallControl implements BluetoothProfile { /** * Notify about the newly added call. * - *

- * This shall be called as early as possible after the call has been added. + *

This shall be called as early as possible after the call has been added. * - *

- * Requires {@link android.Manifest.permission#BLUETOOTH} permission. + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. * * @param call Newly added call * @hide @@ -606,11 +610,9 @@ public final class BluetoothLeCallControl implements BluetoothProfile { /** * Notify about the removed call. * - *

- * This shall be called as early as possible after the call has been removed. + *

This shall be called as early as possible after the call has been removed. * - *

- * Requires {@link android.Manifest.permission#BLUETOOTH} permission. + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. * * @param callId The Id of a call that has been removed * @param reason Call termination reason @@ -635,21 +637,17 @@ public final class BluetoothLeCallControl implements BluetoothProfile { } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } /** * Notify the call state change * - *

- * This shall be called as early as possible after the state of the call has - * changed. + *

This shall be called as early as possible after the state of the call has changed. * - *

- * Requires {@link android.Manifest.permission#BLUETOOTH} permission. + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. * * @param callId The call Id that state has been changed - * @param state Call state + * @param state Call state * @hide */ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) @@ -677,15 +675,13 @@ public final class BluetoothLeCallControl implements BluetoothProfile { /** * Provide the current calls list * - *

- * This function must be invoked after registration if application has any - * calls. + *

This function must be invoked after registration if application has any calls. * * @param calls current calls list * @hide */ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void currentCallsList(@NonNull List calls) { + public void currentCallsList(@NonNull List calls) { final IBluetoothLeCallControl service = getService(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); @@ -697,23 +693,19 @@ public final class BluetoothLeCallControl implements BluetoothProfile { } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } /** * Provide the network current status * - *

- * This function must be invoked on change of network state. - * - *

- * Requires {@link android.Manifest.permission#BLUETOOTH} permission. + *

This function must be invoked on change of network state. * + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. * * - * @param provider Network provider name + * @param provider Network provider name * @param technology Network technology * @hide */ @@ -742,21 +734,20 @@ public final class BluetoothLeCallControl implements BluetoothProfile { /** * Send a response to a call control request to a remote device. * - *

- * This function must be invoked in when a request is received by one of these - * callback methods: + *

This function must be invoked in when a request is received by one of these callback + * methods: * *

    - *
  • {@link Callback#onAcceptCall} - *
  • {@link Callback#onTerminateCall} - *
  • {@link Callback#onHoldCall} - *
  • {@link Callback#onUnholdCall} - *
  • {@link Callback#onPlaceCall} - *
  • {@link Callback#onJoinCalls} + *
  • {@link Callback#onAcceptCall} + *
  • {@link Callback#onTerminateCall} + *
  • {@link Callback#onHoldCall} + *
  • {@link Callback#onUnholdCall} + *
  • {@link Callback#onPlaceCall} + *
  • {@link Callback#onJoinCalls} *
* * @param requestId The ID of the request that was received with the callback - * @param result The result of the request to be sent to the remote devices + * @param result The result of the request to be sent to the remote devices */ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void requestResult(int requestId, @Result int result) { @@ -780,11 +771,6 @@ public final class BluetoothLeCallControl implements BluetoothProfile { } } - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - private static boolean isValidDevice(@Nullable BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - private static void log(String msg) { Log.d(TAG, msg); } diff --git a/framework/java/android/bluetooth/BluetoothManager.java b/framework/java/android/bluetooth/BluetoothManager.java index b1fc23bd9aae0bf34de9d5a62f026aaeafddc5e0..dd6b86dd2a3e0a6ca8e3af86088fc57ae21f0e00 100644 --- a/framework/java/android/bluetooth/BluetoothManager.java +++ b/framework/java/android/bluetooth/BluetoothManager.java @@ -37,21 +37,17 @@ import java.util.List; import java.util.concurrent.TimeoutException; /** - * High level manager used to obtain an instance of an {@link BluetoothAdapter} - * and to conduct overall Bluetooth Management. - *

- * Use {@link android.content.Context#getSystemService(java.lang.String)} - * with {@link Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager}, - * then call {@link #getAdapter} to obtain the {@link BluetoothAdapter}. - *

- *
+ * High level manager used to obtain an instance of an {@link BluetoothAdapter} and to conduct + * overall Bluetooth Management. + * + *

Use {@link android.content.Context#getSystemService(java.lang.String)} with {@link + * Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager}, then call {@link #getAdapter} + * to obtain the {@link BluetoothAdapter}.

+ * *

Developer Guides

- *

- * For more information about using BLUETOOTH, read the Bluetooth developer - * guide. - *

- *
+ * + *

For more information about using BLUETOOTH, read the Bluetooth developer guide.

* * @see Context#getSystemService * @see BluetoothAdapter#getDefaultAdapter() @@ -65,12 +61,12 @@ public final class BluetoothManager { private final AttributionSource mAttributionSource; private final BluetoothAdapter mAdapter; - /** - * @hide - */ + /** @hide */ public BluetoothManager(Context context) { - mAttributionSource = (context != null) ? context.getAttributionSource() : - AttributionSource.myAttributionSource(); + mAttributionSource = + (context != null) + ? context.getAttributionSource() + : AttributionSource.myAttributionSource(); mAdapter = BluetoothAdapter.createAdapter(mAttributionSource); } @@ -87,16 +83,15 @@ public final class BluetoothManager { /** * Get the current connection state of the profile to the remote device. * - *

This is not specific to any application configuration but represents - * the connection state of the local Bluetooth adapter for certain profile. - * This can be used by applications like status bar which would just like - * to know the state of Bluetooth. + *

This is not specific to any application configuration but represents the connection state + * of the local Bluetooth adapter for certain profile. This can be used by applications like + * status bar which would just like to know the state of Bluetooth. * * @param device Remote bluetooth device. * @param profile GATT or GATT_SERVER * @return State of the profile connection. One of {@link BluetoothProfile#STATE_CONNECTED}, - * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED}, - * {@link BluetoothProfile#STATE_DISCONNECTING} + * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED}, + * {@link BluetoothProfile#STATE_DISCONNECTING} */ @RequiresLegacyBluetoothPermission @RequiresBluetoothConnectPermission @@ -117,12 +112,11 @@ public final class BluetoothManager { /** * Get connected devices for the specified profile. * - *

Return the set of devices which are in state {@link BluetoothProfile#STATE_CONNECTED} + *

Return the set of devices which are in state {@link BluetoothProfile#STATE_CONNECTED} * - *

This is not specific to any application configuration but represents - * the connection state of Bluetooth for this profile. - * This can be used by applications like status bar which would just like - * to know the state of Bluetooth. + *

This is not specific to any application configuration but represents the connection state + * of Bluetooth for this profile. This can be used by applications like status bar which would + * just like to know the state of Bluetooth. * * @param profile GATT or GATT_SERVER * @return List of devices. The list will be empty on error. @@ -132,27 +126,23 @@ public final class BluetoothManager { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List getConnectedDevices(int profile) { if (DBG) Log.d(TAG, "getConnectedDevices"); - return getDevicesMatchingConnectionStates(profile, new int[] { - BluetoothProfile.STATE_CONNECTED - }); + return getDevicesMatchingConnectionStates( + profile, new int[] {BluetoothProfile.STATE_CONNECTED}); } /** - * Get a list of devices that match any of the given connection - * states. + * Get a list of devices that match any of the given connection states. * - *

If none of the devices match any of the given states, - * an empty list will be returned. + *

If none of the devices match any of the given states, an empty list will be returned. * - *

This is not specific to any application configuration but represents - * the connection state of the local Bluetooth adapter for this profile. - * This can be used by applications like status bar which would just like - * to know the state of the local adapter. + *

This is not specific to any application configuration but represents the connection state + * of the local Bluetooth adapter for this profile. This can be used by applications like status + * bar which would just like to know the state of the local adapter. * * @param profile GATT or GATT_SERVER * @param states Array of states. States can be one of {@link BluetoothProfile#STATE_CONNECTED}, - * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED}, - * {@link BluetoothProfile#STATE_DISCONNECTING}, + * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED}, + * {@link BluetoothProfile#STATE_DISCONNECTING}, * @return List of devices. The list will be empty on error. */ @RequiresLegacyBluetoothPermission @@ -168,15 +158,15 @@ public final class BluetoothManager { List devices = new ArrayList(); try { - IBluetoothManager managerService = mAdapter.getBluetoothManager(); - IBluetoothGatt iGatt = managerService.getBluetoothGatt(); + IBluetoothGatt iGatt = mAdapter.getBluetoothGatt(); if (iGatt == null) return devices; final SynchronousResultReceiver> recv = SynchronousResultReceiver.get(); iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); - devices = Attributable.setAttributionSource( - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(devices), - mAttributionSource); + devices = + Attributable.setAttributionSource( + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(devices), + mAttributionSource); } catch (RemoteException | TimeoutException e) { Log.e(TAG, "", e); } @@ -185,11 +175,10 @@ public final class BluetoothManager { } /** - * Open a GATT Server - * The callback is used to deliver results to Caller, such as connection status as well - * as the results of any other GATT server operations. - * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer - * to conduct GATT server operations. + * Open a GATT Server The callback is used to deliver results to Caller, such as connection + * status as well as the results of any other GATT server operations. The method returns a + * BluetoothGattServer instance. You can use BluetoothGattServer to conduct GATT server + * operations. * * @param context App context * @param callback GATT server callback handler that will receive asynchronous callbacks. @@ -197,74 +186,74 @@ public final class BluetoothManager { */ @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGattServer openGattServer(Context context, - BluetoothGattServerCallback callback) { + public BluetoothGattServer openGattServer( + Context context, BluetoothGattServerCallback callback) { return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO)); } /** - * Open a GATT Server - * The callback is used to deliver results to Caller, such as connection status as well - * as the results of any other GATT server operations. - * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer - * to conduct GATT server operations. + * Open a GATT Server The callback is used to deliver results to Caller, such as connection + * status as well as the results of any other GATT server operations. The method returns a + * BluetoothGattServer instance. You can use BluetoothGattServer to conduct GATT server + * operations. * * @param context App context * @param callback GATT server callback handler that will receive asynchronous callbacks. - * @param eattSupport idicates if server should use eatt channel for notifications. + * @param eattSupport indicates if server should use eatt channel for notifications. * @return BluetoothGattServer instance * @hide */ @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGattServer openGattServer(Context context, - BluetoothGattServerCallback callback, boolean eattSupport) { + public BluetoothGattServer openGattServer( + Context context, BluetoothGattServerCallback callback, boolean eattSupport) { return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO, eattSupport)); } /** - * Open a GATT Server - * The callback is used to deliver results to Caller, such as connection status as well - * as the results of any other GATT server operations. - * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer - * to conduct GATT server operations. + * Open a GATT Server The callback is used to deliver results to Caller, such as connection + * status as well as the results of any other GATT server operations. The method returns a + * BluetoothGattServer instance. You can use BluetoothGattServer to conduct GATT server + * operations. * * @param context App context * @param callback GATT server callback handler that will receive asynchronous callbacks. * @param transport preferred transport for GATT connections to remote dual-mode devices {@link - * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link - * BluetoothDevice#TRANSPORT_LE} + * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link + * BluetoothDevice#TRANSPORT_LE} * @return BluetoothGattServer instance * @hide */ @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGattServer openGattServer(Context context, - BluetoothGattServerCallback callback, int transport) { + public BluetoothGattServer openGattServer( + Context context, BluetoothGattServerCallback callback, int transport) { return (openGattServer(context, callback, transport, false)); } /** - * Open a GATT Server - * The callback is used to deliver results to Caller, such as connection status as well - * as the results of any other GATT server operations. - * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer - * to conduct GATT server operations. + * Open a GATT Server The callback is used to deliver results to Caller, such as connection + * status as well as the results of any other GATT server operations. The method returns a + * BluetoothGattServer instance. You can use BluetoothGattServer to conduct GATT server + * operations. * * @param context App context * @param callback GATT server callback handler that will receive asynchronous callbacks. * @param transport preferred transport for GATT connections to remote dual-mode devices {@link - * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link - * BluetoothDevice#TRANSPORT_LE} - * @param eattSupport idicates if server should use eatt channel for notifications. + * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link + * BluetoothDevice#TRANSPORT_LE} + * @param eattSupport indicates if server should use eatt channel for notifications. * @return BluetoothGattServer instance * @hide */ @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public BluetoothGattServer openGattServer(Context context, - BluetoothGattServerCallback callback, int transport, boolean eattSupport) { + public BluetoothGattServer openGattServer( + Context context, + BluetoothGattServerCallback callback, + int transport, + boolean eattSupport) { if (context == null || callback == null) { throw new IllegalArgumentException("null parameter: " + context + " " + callback); } @@ -272,20 +261,13 @@ public final class BluetoothManager { // TODO(Bluetooth) check whether platform support BLE // Do the check here or in GattServer? - try { - IBluetoothManager managerService = mAdapter.getBluetoothManager(); - IBluetoothGatt iGatt = managerService.getBluetoothGatt(); - if (iGatt == null) { - Log.e(TAG, "Fail to get GATT Server connection"); - return null; - } - BluetoothGattServer mGattServer = - new BluetoothGattServer(iGatt, transport, mAdapter); - Boolean regStatus = mGattServer.registerCallback(callback, eattSupport); - return regStatus ? mGattServer : null; - } catch (RemoteException e) { - Log.e(TAG, "", e); + IBluetoothGatt iGatt = mAdapter.getBluetoothGatt(); + if (iGatt == null) { + Log.e(TAG, "Fail to get GATT Server connection"); return null; } + BluetoothGattServer mGattServer = new BluetoothGattServer(iGatt, transport, mAdapter); + Boolean regStatus = mGattServer.registerCallback(callback, eattSupport); + return regStatus ? mGattServer : null; } } diff --git a/framework/java/android/bluetooth/BluetoothMap.java b/framework/java/android/bluetooth/BluetoothMap.java index f47a3a91bf298f0ad31f16cfa723a46ebdbb88cd..dc71adfec493b6d2f63a16d5cb0ddbeddc8bc18f 100644 --- a/framework/java/android/bluetooth/BluetoothMap.java +++ b/framework/java/android/bluetooth/BluetoothMap.java @@ -45,8 +45,7 @@ import java.util.List; import java.util.concurrent.TimeoutException; /** - * This class provides the APIs to control the Bluetooth MAP - * Profile. + * This class provides the APIs to control the Bluetooth MAP Profile. * * @hide */ @@ -77,8 +76,10 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { /** @hide */ public static final int RESULT_FAILURE = 0; + /** @hide */ public static final int RESULT_SUCCESS = 1; + /** * Connection canceled before completion. * @@ -88,28 +89,21 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { private final BluetoothAdapter mAdapter; private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.MAP, - "BluetoothMap", IBluetoothMap.class.getName()) { - @Override - public IBluetoothMap getServiceInterface(IBinder service) { - return IBluetoothMap.Stub.asInterface(service); - } - }; - /** - * Create a BluetoothMap proxy object. - */ - /* package */ BluetoothMap(Context context, ServiceListener listener, - BluetoothAdapter adapter) { + private IBluetoothMap mService; + + /** Create a BluetoothMap proxy object. */ + /* package */ BluetoothMap(Context context, BluetoothAdapter adapter) { if (DBG) Log.d(TAG, "Create BluetoothMap proxy object"); mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); + mService = null; mCloseGuard = new CloseGuard(); mCloseGuard.open("close"); } + @Override + @SuppressWarnings("Finalize") // TODO(b/314811467) protected void finalize() { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); @@ -128,19 +122,36 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { @Override public void close() { if (VDBG) log("close()"); - mProfileConnector.disconnect(); + mAdapter.closeProfileProxy(this); + } + + /** @hide */ + @Override + public void onServiceConnected(IBinder service) { + mService = IBluetoothMap.Stub.asInterface(service); + } + + /** @hide */ + @Override + public void onServiceDisconnected() { + mService = null; } private IBluetoothMap getService() { - return mProfileConnector.getService(); + return mService; + } + + /** @hide */ + @Override + public BluetoothAdapter getAdapter() { + return mAdapter; } /** * Get the current state of the BluetoothMap service. * * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not - * connected to the Map service. - * + * connected to the Map service. * @hide */ @RequiresBluetoothConnectPermission @@ -168,8 +179,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { * Get the currently connected remote Bluetooth device (PCE). * * @return The remote Bluetooth device, or null if not in connected or connecting state, or if - * this proxy object is not connected to the Map service. - * + * this proxy object is not connected to the Map service. * @hide */ @RequiresBluetoothConnectPermission @@ -197,9 +207,8 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { } /** - * Returns true if the specified Bluetooth device is connected. - * Returns false if not connected, or if this proxy object is not - * currently connected to the Map service. + * Returns true if the specified Bluetooth device is connected. Returns false if not connected, + * or if this proxy object is not currently connected to the Map service. * * @hide */ @@ -225,8 +234,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { } /** - * Initiate connection. Initiation of outgoing connections is not - * supported for MAP server. + * Initiate connection. Initiation of outgoing connections is not supported for MAP server. * * @hide */ @@ -241,7 +249,6 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { * * @param device Remote Bluetooth Device * @return false on error, true otherwise - * * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -267,13 +274,11 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { } /** - * Check class bits for possible Map support. - * This is a simple heuristic that tries to guess if a device with the - * given class bits might support Map. It is not accurate for all - * devices. It tries to err on the side of false positives. + * Check class bits for possible Map support. This is a simple heuristic that tries to guess if + * a device with the given class bits might support Map. It is not accurate for all devices. It + * tries to err on the side of false positives. * * @return True if this device might support Map. - * * @hide */ public static boolean doesClassMatchSink(BluetoothClass btClass) { @@ -293,15 +298,15 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { * Get the list of connected devices. Currently at most one. * * @return list of connected devices - * * @hide */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @NonNull List getConnectedDevices() { if (DBG) log("getConnectedDevices()"); final IBluetoothMap service = getService(); @@ -328,7 +333,6 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { * Get the list of devices matching specified states. Currently at most one. * * @return list of matching devices - * * @hide */ @RequiresBluetoothConnectPermission @@ -356,14 +360,16 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { } /** - * There are several instances of IpcDataCache used in this class. - * BluetoothCache wraps up the common code. All caches are created with a maximum of - * eight entries, and the key is in the bluetooth module. The name is set to the api. + * There are several instances of IpcDataCache used in this class. BluetoothCache wraps up the + * common code. All caches are created with a maximum of eight entries, and the key is in the + * bluetooth module. The name is set to the api. */ private static class BluetoothCache extends IpcDataCache { BluetoothCache(String api, IpcDataCache.QueryHandler query) { super(8, IpcDataCache.MODULE_BLUETOOTH, api, api, query); - }}; + } + } + ; /** @hide */ public void disableBluetoothGetConnectionStateCache() { @@ -376,44 +382,49 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { } /** - * Invalidate a bluetooth cache. This method is just a short-hand wrapper that - * enforces the bluetooth module. + * Invalidate a bluetooth cache. This method is just a short-hand wrapper that enforces the + * bluetooth module. */ private static void invalidateCache(@NonNull String api) { IpcDataCache.invalidateCache(IpcDataCache.MODULE_BLUETOOTH, api); } - private static final IpcDataCache - .QueryHandler>, Integer> - sBluetoothConnectionQuery = new IpcDataCache.QueryHandler<>() { - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @Override - public Integer apply(Pair> pairQuery) { - IBluetoothMap service = pairQuery.first; - AttributionSource source = pairQuery.second.first; - BluetoothDevice device = pairQuery.second.second; - if (DBG) { - log("getConnectionState(" + device.getAnonymizedAddress() + ") uncached"); - } - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - try { - service.getConnectionState(device, source, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()) - .getValue(BluetoothProfile.STATE_DISCONNECTED); - } catch (RemoteException | TimeoutException e) { - throw new RuntimeException(e); - } - } - }; + private static final IpcDataCache.QueryHandler< + Pair>, Integer> + sBluetoothConnectionQuery = + new IpcDataCache.QueryHandler<>() { + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @Override + public Integer apply( + Pair> pairQuery) { + IBluetoothMap service = IBluetoothMap.Stub.asInterface(pairQuery.first); + AttributionSource source = pairQuery.second.first; + BluetoothDevice device = pairQuery.second.second; + if (DBG) { + log( + "getConnectionState(" + + device.getAnonymizedAddress() + + ") uncached"); + } + final SynchronousResultReceiver recv = + SynchronousResultReceiver.get(); + try { + service.getConnectionState(device, source, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()) + .getValue(BluetoothProfile.STATE_DISCONNECTED); + } catch (RemoteException | TimeoutException e) { + throw new RuntimeException(e); + } + } + }; private static final String GET_CONNECTION_STATE_API = "BluetoothMap_getConnectionState"; - private static final - BluetoothCache>, Integer> - sBluetoothConnectionCache = new BluetoothCache<>(GET_CONNECTION_STATE_API, - sBluetoothConnectionQuery); + private static final BluetoothCache< + Pair>, Integer> + sBluetoothConnectionCache = + new BluetoothCache<>(GET_CONNECTION_STATE_API, sBluetoothConnectionQuery); /** * Get connection state of device @@ -432,7 +443,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { } else if (isEnabled() && isValidDevice(device)) { try { return sBluetoothConnectionCache.query( - new Pair<>(service, new Pair<>(mAttributionSource, device))); + new Pair<>(service.asBinder(), new Pair<>(mAttributionSource, device))); } catch (RuntimeException e) { if (!(e.getCause() instanceof TimeoutException) && !(e.getCause() instanceof RemoteException)) { @@ -447,19 +458,19 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { /** * Set priority of the profile * - *

The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, + *

The device should already be paired. Priority can be one of {@link #PRIORITY_ON} or {@link + * #PRIORITY_OFF}, * * @param device Paired bluetooth device - * @param priority * @return true if priority is set, false on error * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setPriority(BluetoothDevice device, int priority) { if (DBG) log("setPriority(" + device + ", " + priority + ")"); return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); @@ -468,9 +479,9 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { /** * Set connection policy of the profile * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + *

The device should already be paired. Connection policy can be one of {@link + * #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, {@link + * #CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device * @param connectionPolicy is the connection policy to set to for this profile @@ -479,20 +490,22 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean setConnectionPolicy( + @NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothMap service = getService(); final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) - && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + } else if (isEnabled() + && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); @@ -508,18 +521,19 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { /** * Get the priority of the profile. * - *

The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} + *

The priority can be any of: {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link + * #PRIORITY_UNDEFINED} * * @param device Bluetooth device * @return priority of the device * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public int getPriority(BluetoothDevice device) { if (VDBG) log("getPriority(" + device + ")"); return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); @@ -528,9 +542,8 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { /** * Get the connection policy of the profile. * - *

The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} + *

The connection policy can be any of: {@link #CONNECTION_POLICY_ALLOWED}, {@link + * #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} * * @param device Bluetooth device * @return connection policy of the device @@ -538,10 +551,11 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothMap service = getService(); diff --git a/framework/java/android/bluetooth/BluetoothMapClient.java b/framework/java/android/bluetooth/BluetoothMapClient.java index f4f1301e7611779e885fd5989b00a5c24f0ad491..a47cd76a83e152a6d4b2f8206f486e41f995319e 100644 --- a/framework/java/android/bluetooth/BluetoothMapClient.java +++ b/framework/java/android/bluetooth/BluetoothMapClient.java @@ -63,33 +63,37 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable * Intent used to broadcast the change in connection state of the MAP Client profile. * *

This intent will have 3 extras: + * *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • + *
  • {@link #EXTRA_STATE} - The current state of the profile. + *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. + *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. *
* - *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link + * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link + * #STATE_DISCONNECTING}. * * @hide */ @SystemApi @SuppressLint("ActionValue") @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED"; + /** @hide */ @RequiresPermission(android.Manifest.permission.RECEIVE_SMS) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_MESSAGE_RECEIVED = "android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED"; + /* Actions to be used for pending intents */ /** @hide */ @RequiresBluetoothConnectPermission @@ -97,6 +101,7 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_MESSAGE_SENT_SUCCESSFULLY = "android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY"; + /** @hide */ @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @@ -127,31 +132,32 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED"; /** - * Extras used in ACTION_MESSAGE_RECEIVED intent. - * NOTE: HANDLE is only valid for a single session with the device. + * Extras used in ACTION_MESSAGE_RECEIVED intent. NOTE: HANDLE is only valid for a single + * session with the device. */ /** @hide */ public static final String EXTRA_MESSAGE_HANDLE = "android.bluetooth.mapmce.profile.extra.MESSAGE_HANDLE"; + /** @hide */ public static final String EXTRA_MESSAGE_TIMESTAMP = "android.bluetooth.mapmce.profile.extra.MESSAGE_TIMESTAMP"; + /** @hide */ public static final String EXTRA_MESSAGE_READ_STATUS = "android.bluetooth.mapmce.profile.extra.MESSAGE_READ_STATUS"; + /** @hide */ public static final String EXTRA_SENDER_CONTACT_URI = "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_URI"; + /** @hide */ public static final String EXTRA_SENDER_CONTACT_NAME = "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME"; /** - * Used as a boolean extra in ACTION_MESSAGE_DELETED_STATUS_CHANGED - * Contains the MAP message deleted status - * Possible values are: - * true: deleted - * false: undeleted + * Used as a boolean extra in ACTION_MESSAGE_DELETED_STATUS_CHANGED Contains the MAP message + * deleted status Possible values are: true: deleted false: undeleted * * @hide */ @@ -160,30 +166,32 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * Extra used in ACTION_MESSAGE_READ_STATUS_CHANGED or ACTION_MESSAGE_DELETED_STATUS_CHANGED - * Possible values are: - * 0: failure - * 1: success + * Possible values are: 0: failure 1: success * * @hide */ - public static final String EXTRA_RESULT_CODE = - "android.bluetooth.device.extra.RESULT_CODE"; + public static final String EXTRA_RESULT_CODE = "android.bluetooth.device.extra.RESULT_CODE"; /** * There was an error trying to obtain the state + * * @hide */ public static final int STATE_ERROR = -1; /** @hide */ public static final int RESULT_FAILURE = 0; + /** @hide */ public static final int RESULT_SUCCESS = 1; + /** * Connection canceled before completion. + * * @hide */ public static final int RESULT_CANCELED = 2; + /** @hide */ private static final int UPLOADING_FEATURE_BITMASK = 0x08; @@ -194,38 +202,34 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** @hide */ public static final int UNREAD = 0; + /** @hide */ public static final int READ = 1; + /** @hide */ public static final int UNDELETED = 2; + /** @hide */ public static final int DELETED = 3; private final BluetoothAdapter mAdapter; private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT, - "BluetoothMapClient", IBluetoothMapClient.class.getName()) { - @Override - public IBluetoothMapClient getServiceInterface(IBinder service) { - return IBluetoothMapClient.Stub.asInterface(service); - } - }; - /** - * Create a BluetoothMapClient proxy object. - */ - /* package */ BluetoothMapClient(Context context, ServiceListener listener, - BluetoothAdapter adapter) { + private IBluetoothMapClient mService; + + /** Create a BluetoothMapClient proxy object. */ + /* package */ BluetoothMapClient(Context context, BluetoothAdapter adapter) { if (DBG) Log.d(TAG, "Create BluetoothMapClient proxy object"); mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); + mService = null; mCloseGuard = new CloseGuard(); mCloseGuard.open("close"); } /** @hide */ + @Override + @SuppressWarnings("Finalize") // TODO(b/314811467) protected void finalize() { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); @@ -242,20 +246,38 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable */ @Override public void close() { - mProfileConnector.disconnect(); + mAdapter.closeProfileProxy(this); if (mCloseGuard != null) { mCloseGuard.close(); } } + /** @hide */ + @Override + public void onServiceConnected(IBinder service) { + mService = IBluetoothMapClient.Stub.asInterface(service); + } + + /** @hide */ + @Override + public void onServiceDisconnected() { + mService = null; + } + private IBluetoothMapClient getService() { - return mProfileConnector.getService(); + return mService; + } + + /** @hide */ + @Override + public BluetoothAdapter getAdapter() { + return mAdapter; } /** - * Returns true if the specified Bluetooth device is connected. - * Returns false if not connected, or if this proxy object is not - * currently connected to the Map service. + * Returns true if the specified Bluetooth device is connected. Returns false if not connected, + * or if this proxy object is not currently connected to the Map service. + * * @hide */ @RequiresBluetoothConnectPermission @@ -280,16 +302,16 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable } /** - * Initiate connection. Initiation of outgoing connections is not - * supported for MAP server. + * Initiate connection. Initiation of outgoing connections is not supported for MAP server. * * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean connect(BluetoothDevice device) { if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE"); final IBluetoothMapClient service = getService(); @@ -314,14 +336,14 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable * * @param device Remote Bluetooth Device * @return false on error, true otherwise - * * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean disconnect(BluetoothDevice device) { if (DBG) Log.d(TAG, "disconnect(" + device + ")"); final IBluetoothMapClient service = getService(); @@ -343,15 +365,17 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * {@inheritDoc} + * * @hide */ @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @NonNull List getConnectedDevices() { if (DBG) Log.d(TAG, "getConnectedDevices()"); final IBluetoothMapClient service = getService(); @@ -369,7 +393,7 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -379,15 +403,17 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * {@inheritDoc} + * * @hide */ @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) @NonNull public List getDevicesMatchingConnectionStates(@NonNull int[] states) { if (DBG) Log.d(TAG, "getDevicesMatchingStates()"); @@ -406,7 +432,7 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -416,19 +442,21 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * {@inheritDoc} + * * @hide */ @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) { if (DBG) Log.d(TAG, "getConnectionState(" + device + ")"); final IBluetoothMapClient service = getService(); - final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); @@ -439,7 +467,7 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -450,19 +478,19 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * Set priority of the profile * - *

The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, + *

The device should already be paired. Priority can be one of {@link #PRIORITY_ON} or {@link + * #PRIORITY_OFF}, * * @param device Paired bluetooth device - * @param priority * @return true if priority is set, false on error * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setPriority(BluetoothDevice device, int priority) { if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")"); return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); @@ -471,9 +499,9 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * Set connection policy of the profile * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + *

The device should already be paired. Connection policy can be one of {@link + * #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, {@link + * #CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device * @param connectionPolicy is the connection policy to set to for this profile @@ -482,28 +510,30 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean setConnectionPolicy( + @NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothMapClient service = getService(); final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) + } else if (isEnabled() + && isValidDevice(device) && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -514,18 +544,19 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * Get the priority of the profile. * - *

The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} + *

The priority can be any of: {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link + * #PRIORITY_UNDEFINED} * * @param device Bluetooth device * @return priority of the device * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public int getPriority(BluetoothDevice device) { if (VDBG) Log.d(TAG, "getPriority(" + device + ")"); return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); @@ -534,9 +565,8 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * Get the connection policy of the profile. * - *

The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} + *

The connection policy can be any of: {@link #CONNECTION_POLICY_ALLOWED}, {@link + * #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} * * @param device Bluetooth device * @return connection policy of the device @@ -544,10 +574,11 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")"); final IBluetoothMapClient service = getService(); @@ -562,7 +593,7 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -573,7 +604,8 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * Send a message. * - * Send an SMS message to either the contacts primary number or the telephone number specified. + *

Send an SMS message to either the contacts primary number or the telephone number + * specified. * * @param device Bluetooth device * @param contacts Uri Collection of the contacts @@ -585,21 +617,30 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.SEND_SMS, - }) - public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection contacts, - @NonNull String message, @Nullable PendingIntent sentIntent, + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.SEND_SMS, + }) + public boolean sendMessage( + @NonNull BluetoothDevice device, + @NonNull Collection contacts, + @NonNull String message, + @Nullable PendingIntent sentIntent, @Nullable PendingIntent deliveredIntent) { - return sendMessage(device, contacts.toArray(new Uri[contacts.size()]), message, sentIntent, + return sendMessage( + device, + contacts.toArray(new Uri[contacts.size()]), + message, + sentIntent, deliveredIntent); } - /** + /** * Send a message. * - * Send an SMS message to either the contacts primary number or the telephone number specified. + *

Send an SMS message to either the contacts primary number or the telephone number + * specified. * * @param device Bluetooth device * @param contacts Uri[] of the contacts @@ -611,15 +652,19 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.SEND_SMS, - }) - public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message, - PendingIntent sentIntent, PendingIntent deliveredIntent) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.SEND_SMS, + }) + public boolean sendMessage( + BluetoothDevice device, + Uri[] contacts, + String message, + PendingIntent sentIntent, + PendingIntent deliveredIntent) { if (DBG) { - Log.d(TAG, "sendMessage(" + device + ", " + Arrays.toString(contacts) - + ", " + message); + Log.d(TAG, "sendMessage(" + device + ", " + Arrays.toString(contacts) + ", " + message); } final IBluetoothMapClient service = getService(); final boolean defaultValue = false; @@ -629,8 +674,14 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable } else if (isEnabled() && isValidDevice(device)) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - service.sendMessage(device, contacts, message, sentIntent, deliveredIntent, - mAttributionSource, recv); + service.sendMessage( + device, + contacts, + message, + sentIntent, + deliveredIntent, + mAttributionSource, + recv); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); @@ -640,17 +691,18 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable } /** - * Get unread messages. Unread messages will be published via {@link #ACTION_MESSAGE_RECEIVED}. + * Get unread messages. Unread messages will be published via {@link #ACTION_MESSAGE_RECEIVED}. * * @param device Bluetooth device * @return true if the message is enqueued, false on error * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.READ_SMS, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.READ_SMS, + }) public boolean getUnreadMessages(BluetoothDevice device) { if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")"); final IBluetoothMapClient service = getService(); @@ -671,11 +723,12 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable } /** - * Returns the "Uploading" feature bit value from the SDP record's - * MapSupportedFeatures field (see Bluetooth MAP 1.4 spec, page 114). + * Returns the "Uploading" feature bit value from the SDP record's MapSupportedFeatures field + * (see Bluetooth MAP 1.4 spec, page 114). + * * @param device The Bluetooth device to get this value for. - * @return Returns true if the Uploading bit value in SDP record's - * MapSupportedFeatures field is set. False is returned otherwise. + * @return Returns true if the Uploading bit value in SDP record's MapSupportedFeatures field is + * set. False is returned otherwise. * @hide */ @RequiresBluetoothConnectPermission @@ -692,7 +745,8 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); service.getSupportedFeatures(device, mAttributionSource, recv); return (recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue) - & UPLOADING_FEATURE_BITMASK) > 0; + & UPLOADING_FEATURE_BITMASK) + > 0; } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -702,25 +756,24 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable /** * Set message status of message on MSE - *

- * When read status changed, the result will be published via - * {@link #ACTION_MESSAGE_READ_STATUS_CHANGED} - * When deleted status changed, the result will be published via - * {@link #ACTION_MESSAGE_DELETED_STATUS_CHANGED} + * + *

When read status changed, the result will be published via {@link + * #ACTION_MESSAGE_READ_STATUS_CHANGED} When deleted status changed, the result will be + * published via {@link #ACTION_MESSAGE_DELETED_STATUS_CHANGED} * * @param device Bluetooth device * @param handle message handle - * @param status UNREAD for "unread", READ for - * "read", UNDELETED for "undeleted", DELETED for - * "deleted", otherwise return error + * @param status UNREAD for "unread", READ for "read", UNDELETED + * for "undeleted", DELETED for "deleted", otherwise return error * @return true if request has been sent, false on error * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.READ_SMS, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.READ_SMS, + }) public boolean setMessageStatus(BluetoothDevice device, String handle, int status) { if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")"); final IBluetoothMapClient service = getService(); @@ -728,8 +781,13 @@ public final class BluetoothMapClient implements BluetoothProfile, AutoCloseable if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) && handle != null && (status == READ - || status == UNREAD || status == UNDELETED || status == DELETED)) { + } else if (isEnabled() + && isValidDevice(device) + && handle != null + && (status == READ + || status == UNREAD + || status == UNDELETED + || status == DELETED)) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); service.setMessageStatus(device, handle, status, mAttributionSource, recv); diff --git a/framework/java/android/bluetooth/BluetoothMasInstance.java b/framework/java/android/bluetooth/BluetoothMasInstance.java index b22ac15029197a7280aa958ae0106f7c9b0e0be9..9c1095b059969f8c44eebcf9b3faabfdc541cc35 100644 --- a/framework/java/android/bluetooth/BluetoothMasInstance.java +++ b/framework/java/android/bluetooth/BluetoothMasInstance.java @@ -22,6 +22,7 @@ import android.os.Parcel; import android.os.Parcelable; /** @hide */ +@SuppressWarnings("InconsistentHashCode") // TODO(b/314811467) public final class BluetoothMasInstance implements Parcelable { private final int mId; private final String mName; @@ -50,7 +51,12 @@ public final class BluetoothMasInstance implements Parcelable { @Override public String toString() { - return Integer.toString(mId) + ":" + mName + ":" + mChannel + ":" + return Integer.toString(mId) + + ":" + + mName + + ":" + + mChannel + + ":" + Integer.toHexString(mMsgTypes); } @@ -59,10 +65,11 @@ public final class BluetoothMasInstance implements Parcelable { return 0; } - public static final @NonNull Creator CREATOR = new Creator<>() { + public static final @NonNull Creator CREATOR = + new Creator<>() { public BluetoothMasInstance createFromParcel(Parcel in) { - return new BluetoothMasInstance(in.readInt(), in.readString(), - in.readInt(), in.readInt()); + return new BluetoothMasInstance( + in.readInt(), in.readString(), in.readInt(), in.readInt()); } public BluetoothMasInstance[] newArray(int size) { diff --git a/framework/java/android/bluetooth/BluetoothOutputStream.java b/framework/java/android/bluetooth/BluetoothOutputStream.java index ac2b3edb0eb85df2c05b7c9f1db24b56d5d4868f..4d579ca00dcd5a9ed447a1550623b519fec908d7 100644 --- a/framework/java/android/bluetooth/BluetoothOutputStream.java +++ b/framework/java/android/bluetooth/BluetoothOutputStream.java @@ -24,7 +24,7 @@ import java.io.OutputStream; /** * BluetoothOutputStream. * - * Used to read from a Bluetooth socket. + *

Used to read from a Bluetooth socket. * * @hide */ @@ -36,16 +36,14 @@ import java.io.OutputStream; mSocket = s; } - /** - * Close this output stream and the socket associated with it. - */ + /** Close this output stream and the socket associated with it. */ public void close() throws IOException { mSocket.close(); } /** - * Writes a single byte to this stream. Only the least significant byte of - * the integer {@code oneByte} is written to the stream. + * Writes a single byte to this stream. Only the least significant byte of the integer {@code + * oneByte} is written to the stream. * * @param oneByte the byte to be written. * @throws IOException if an error occurs while writing to this stream. @@ -58,15 +56,15 @@ import java.io.OutputStream; } /** - * Writes {@code count} bytes from the byte array {@code buffer} starting - * at position {@code offset} to this stream. + * Writes {@code count} bytes from the byte array {@code buffer} starting at position {@code + * offset} to this stream. * * @param b the buffer to be written. * @param offset the start position in {@code buffer} from where to get bytes. * @param count the number of bytes from {@code buffer} to write to this stream. * @throws IOException if an error occurs while writing to this stream. * @throws IndexOutOfBoundsException if {@code offset < 0} or {@code count < 0}, or if {@code - * offset + count} is bigger than the length of {@code buffer}. + * offset + count} is bigger than the length of {@code buffer}. * @since Android 1.0 */ public void write(byte[] b, int offset, int count) throws IOException { diff --git a/framework/java/android/bluetooth/BluetoothPan.java b/framework/java/android/bluetooth/BluetoothPan.java index e970b7b6141fcbcf075c7f3681639f4fc53125f1..614305b9cebd07c6f09d9aedb7f0cd049823e6ea 100644 --- a/framework/java/android/bluetooth/BluetoothPan.java +++ b/framework/java/android/bluetooth/BluetoothPan.java @@ -50,12 +50,10 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; /** - * This class provides the APIs to control the Bluetooth Pan - * Profile. + * This class provides the APIs to control the Bluetooth Pan Profile. * - *

BluetoothPan is a proxy object for controlling the Bluetooth - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothPan proxy object. + *

BluetoothPan is a proxy object for controlling the Bluetooth Service via IPC. Use {@link + * BluetoothAdapter#getProfileProxy} to get the BluetoothPan proxy object. * *

Each method is protected with its appropriate permission. * @@ -68,24 +66,23 @@ public final class BluetoothPan implements BluetoothProfile { private static final boolean VDBG = false; /** - * Intent used to broadcast the change in connection state of the Pan - * profile. + * Intent used to broadcast the change in connection state of the Pan profile. * *

This intent will have 4 extras: + * *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • - *
  • {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is - * bound to.
  • + *
  • {@link #EXTRA_STATE} - The current state of the profile. + *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. + *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. + *
  • {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is bound to. *
* - *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link + * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link + * #STATE_DISCONNECTING}. * - *

{@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or - * {@link #LOCAL_PANU_ROLE} + *

{@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or {@link + * #LOCAL_PANU_ROLE} */ @SuppressLint("ActionValue") @RequiresLegacyBluetoothPermission @@ -96,25 +93,24 @@ public final class BluetoothPan implements BluetoothProfile { "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED"; /** - * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent - * The local role of the PAN profile that the remote device is bound to. - * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}. + * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent The local role of the PAN profile + * that the remote device is bound to. It can be one of {@link #LOCAL_NAP_ROLE} or {@link + * #LOCAL_PANU_ROLE}. */ @SuppressLint("ActionValue") public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE"; /** - * Intent used to broadcast the change in tethering state of the Pan - * Profile + * Intent used to broadcast the change in tethering state of the Pan Profile * *

This intent will have 1 extra: + * *

    - *
  • {@link #EXTRA_TETHERING_STATE} - The current state of Bluetooth - * tethering.
  • + *
  • {@link #EXTRA_TETHERING_STATE} - The current state of Bluetooth tethering. *
* - *

{@link #EXTRA_TETHERING_STATE} can be any of {@link #TETHERING_STATE_OFF} or - * {@link #TETHERING_STATE_ON} + *

{@link #EXTRA_TETHERING_STATE} can be any of {@link #TETHERING_STATE_OFF} or {@link + * #TETHERING_STATE_ON} */ @RequiresLegacyBluetoothPermission @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @@ -122,12 +118,10 @@ public final class BluetoothPan implements BluetoothProfile { "android.bluetooth.action.TETHERING_STATE_CHANGED"; /** - * Extra for {@link #ACTION_TETHERING_STATE_CHANGED} intent - * The tethering state of the PAN profile. - * It can be one of {@link #TETHERING_STATE_OFF} or {@link #TETHERING_STATE_ON}. + * Extra for {@link #ACTION_TETHERING_STATE_CHANGED} intent The tethering state of the PAN + * profile. It can be one of {@link #TETHERING_STATE_OFF} or {@link #TETHERING_STATE_ON}. */ - public static final String EXTRA_TETHERING_STATE = - "android.bluetooth.extra.TETHERING_STATE"; + public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE"; /** @hide */ @IntDef({PAN_ROLE_NONE, LOCAL_NAP_ROLE, LOCAL_PANU_ROLE}) @@ -135,14 +129,11 @@ public final class BluetoothPan implements BluetoothProfile { public @interface LocalPanRole {} public static final int PAN_ROLE_NONE = 0; - /** - * The local device is acting as a Network Access Point. - */ + + /** The local device is acting as a Network Access Point. */ public static final int LOCAL_NAP_ROLE = 1; - /** - * The local device is acting as a PAN User. - */ + /** The local device is acting as a PAN User. */ public static final int LOCAL_PANU_ROLE = 2; /** @hide */ @@ -154,14 +145,17 @@ public final class BluetoothPan implements BluetoothProfile { public static final int REMOTE_PANU_ROLE = 2; - /** @hide **/ + /** + * @hide * + */ @IntDef({TETHERING_STATE_OFF, TETHERING_STATE_ON}) @Retention(RetentionPolicy.SOURCE) - public @interface TetheringState{} + public @interface TetheringState {} public static final int TETHERING_STATE_OFF = 1; public static final int TETHERING_STATE_ON = 2; + /** * Return codes for the connect and disconnect Bluez / Dbus calls. * @@ -169,24 +163,16 @@ public final class BluetoothPan implements BluetoothProfile { */ public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000; - /** - * @hide - */ + /** @hide */ public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001; - /** - * @hide - */ + /** @hide */ public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002; - /** - * @hide - */ + /** @hide */ public static final int PAN_OPERATION_GENERIC_FAILURE = 1003; - /** - * @hide - */ + /** @hide */ public static final int PAN_OPERATION_SUCCESS = 1004; /** @@ -200,21 +186,22 @@ public final class BluetoothPan implements BluetoothProfile { private final IBluetoothPanCallback mPanCallback; private final int mId; - private BluetoothTetheredInterfaceRequest(@NonNull IBluetoothPan service, - @NonNull IBluetoothPanCallback panCallback, int id) { + private BluetoothTetheredInterfaceRequest( + @NonNull IBluetoothPan service, + @NonNull IBluetoothPanCallback panCallback, + int id) { this.mService = service; this.mPanCallback = panCallback; this.mId = id; } - /** - * Called when the Tethering interface has been released. - */ - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.TETHER_PRIVILEGED, - }) + /** Called when the Tethering interface has been released. */ + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.TETHER_PRIVILEGED, + }) @Override public void release() { if (mService == null) { @@ -237,29 +224,21 @@ public final class BluetoothPan implements BluetoothProfile { private final BluetoothAdapter mAdapter; private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.PAN, - "BluetoothPan", IBluetoothPan.class.getName()) { - @Override - public IBluetoothPan getServiceInterface(IBinder service) { - return IBluetoothPan.Stub.asInterface(service); - } - }; + private IBluetoothPan mService; /** - * Create a BluetoothPan proxy object for interacting with the local - * Bluetooth Service which handles the Pan profile + * Create a BluetoothPan proxy object for interacting with the local Bluetooth Service which + * handles the Pan profile * * @hide */ @UnsupportedAppUsage - /* package */ BluetoothPan(Context context, ServiceListener listener, - BluetoothAdapter adapter) { + /* package */ BluetoothPan(Context context, BluetoothAdapter adapter) { mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); mContext = context; - mProfileConnector.connect(context, listener); + mService = null; } /** @@ -268,17 +247,35 @@ public final class BluetoothPan implements BluetoothProfile { * @hide */ @UnsupportedAppUsage - @Override public void close() { if (VDBG) log("close()"); - mProfileConnector.disconnect(); + mAdapter.closeProfileProxy(this); + } + + /** @hide */ + @Override + public void onServiceConnected(IBinder service) { + mService = IBluetoothPan.Stub.asInterface(service); + } + + /** @hide */ + @Override + public void onServiceDisconnected() { + mService = null; } private IBluetoothPan getService() { - return mProfileConnector.getService(); + return mService; + } + + /** @hide */ + @Override + public BluetoothAdapter getAdapter() { + return mAdapter; } /** @hide */ + @SuppressWarnings("Finalize") // TODO(b/314811467) protected void finalize() { close(); } @@ -286,12 +283,10 @@ public final class BluetoothPan implements BluetoothProfile { /** * Initiate connection to a profile of the remote bluetooth device. * - *

This API returns false in scenarios like the profile on the - * device is already connected or Bluetooth is not turned on. - * When this API returns true, it is guaranteed that - * connection state intent for the profile will be broadcasted with - * the state. Users can get the connection state of the profile - * from this intent. + *

This API returns false in scenarios like the profile on the device is already connected or + * Bluetooth is not turned on. When this API returns true, it is guaranteed that connection + * state intent for the profile will be broadcasted with the state. Users can get the connection + * state of the profile from this intent. * * @param device Remote Bluetooth Device * @return false on immediate error, true otherwise @@ -299,10 +294,11 @@ public final class BluetoothPan implements BluetoothProfile { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); final IBluetoothPan service = getService(); @@ -325,20 +321,16 @@ public final class BluetoothPan implements BluetoothProfile { /** * Initiate disconnection from a profile * - *

This API will return false in scenarios like the profile on the - * Bluetooth device is not in connected state etc. When this API returns, - * true, it is guaranteed that the connection state change - * intent will be broadcasted with the state. Users can get the - * disconnection state of the profile from this intent. + *

This API will return false in scenarios like the profile on the Bluetooth device is not in + * connected state etc. When this API returns, true, it is guaranteed that the connection state + * change intent will be broadcasted with the state. Users can get the disconnection state of + * the profile from this intent. * - *

If the disconnection is initiated by a remote device, the state - * will transition from {@link #STATE_CONNECTED} to - * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the - * host (local) device the state will transition from - * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to - * state {@link #STATE_DISCONNECTED}. The transition to - * {@link #STATE_DISCONNECTING} can be used to distinguish between the - * two scenarios. + *

If the disconnection is initiated by a remote device, the state will transition from + * {@link #STATE_CONNECTED} to {@link #STATE_DISCONNECTED}. If the disconnect is initiated by + * the host (local) device the state will transition from {@link #STATE_CONNECTED} to state + * {@link #STATE_DISCONNECTING} to state {@link #STATE_DISCONNECTED}. The transition to {@link + * #STATE_DISCONNECTING} can be used to distinguish between the two scenarios. * * @param device Remote Bluetooth Device * @return false on immediate error, true otherwise @@ -369,9 +361,9 @@ public final class BluetoothPan implements BluetoothProfile { /** * Set connection policy of the profile * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + *

The device should already be paired. Connection policy can be one of {@link + * #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, {@link + * #CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device * @param connectionPolicy is the connection policy to set to for this profile @@ -380,21 +372,23 @@ public final class BluetoothPan implements BluetoothProfile { */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean setConnectionPolicy( + @NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothPan service = getService(); final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) + } else if (isEnabled() + && isValidDevice(device) && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); @@ -408,15 +402,17 @@ public final class BluetoothPan implements BluetoothProfile { /** * {@inheritDoc} + * * @hide */ @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @NonNull List getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothPan service = getService(); @@ -441,15 +437,17 @@ public final class BluetoothPan implements BluetoothProfile { /** * {@inheritDoc} + * * @hide */ @Override @RequiresLegacyBluetoothPermission @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public List getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); final IBluetoothPan service = getService(); @@ -474,15 +472,17 @@ public final class BluetoothPan implements BluetoothProfile { /** * {@inheritDoc} + * * @hide */ @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public int getConnectionState(@NonNull BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); final IBluetoothPan service = getService(); @@ -506,18 +506,18 @@ public final class BluetoothPan implements BluetoothProfile { * Turns on/off bluetooth tethering. * * @param value is whether to enable or disable bluetooth tethering - * - * @deprecated Use {@link #requestTetheredInterface} with - * {@link TetheredInterfaceCallback} instead. + * @deprecated Use {@link #requestTetheredInterface} with {@link TetheredInterfaceCallback} + * instead. * @hide */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.TETHER_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.TETHER_PRIVILEGED, + }) @Deprecated public void setBluetoothTethering(boolean value) { String pkgName = mContext.getOpPackageName(); @@ -540,33 +540,32 @@ public final class BluetoothPan implements BluetoothProfile { /** * Turns on Bluetooth tethering. * - *

When one or more devices are connected, the PAN service will trigger - * {@link TetheredInterfaceCallback#onAvailable} to inform the caller that - * it is ready to tether. On the contrary, when all devices have been disconnected, - * the PAN service will trigger {@link TetheredInterfaceCallback#onUnavailable}. - *

To turn off Bluetooth tethering, the caller must use - * {@link TetheredInterfaceRequest#release} method. + *

When one or more devices are connected, the PAN service will trigger {@link + * TetheredInterfaceCallback#onAvailable} to inform the caller that it is ready to tether. On + * the contrary, when all devices have been disconnected, the PAN service will trigger {@link + * TetheredInterfaceCallback#onUnavailable}. * - * @param executor thread to execute callback methods - * @param callback is the tethering callback to indicate PAN service is ready - * or not to tether to one or more devices + *

To turn off Bluetooth tethering, the caller must use {@link + * TetheredInterfaceRequest#release} method. * - * @return new instance of {@link TetheredInterfaceRequest} which can be - * used to turn off Bluetooth tethering or {@code null} if service - * is not enabled + * @param executor thread to execute callback methods + * @param callback is the tethering callback to indicate PAN service is ready or not to tether + * to one or more devices + * @return new instance of {@link TetheredInterfaceRequest} which can be used to turn off + * Bluetooth tethering or {@code null} if service is not enabled * @hide */ @SystemApi(client = MODULE_LIBRARIES) @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.TETHER_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.TETHER_PRIVILEGED, + }) @Nullable public TetheredInterfaceRequest requestTetheredInterface( - @NonNull final Executor executor, - @NonNull final TetheredInterfaceCallback callback) { + @NonNull final Executor executor, @NonNull final TetheredInterfaceCallback callback) { Objects.requireNonNull(callback, "Callback must be non-null"); Objects.requireNonNull(executor, "Executor must be non-null"); final IBluetoothPan service = getService(); @@ -574,24 +573,25 @@ public final class BluetoothPan implements BluetoothProfile { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled()) { - final IBluetoothPanCallback panCallback = new IBluetoothPanCallback.Stub() { - @Override - public void onAvailable(String iface) { - executor.execute(() -> callback.onAvailable(iface)); - } - - @Override - public void onUnavailable() { - executor.execute(() -> callback.onUnavailable()); - } - }; + final IBluetoothPanCallback panCallback = + new IBluetoothPanCallback.Stub() { + @Override + public void onAvailable(String iface) { + executor.execute(() -> callback.onAvailable(iface)); + } + + @Override + public void onUnavailable() { + executor.execute(() -> callback.onUnavailable()); + } + }; try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - service.setBluetoothTethering(panCallback, callback.hashCode(), true, - mAttributionSource, recv); + service.setBluetoothTethering( + panCallback, callback.hashCode(), true, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - return new BluetoothTetheredInterfaceRequest(service, panCallback, - callback.hashCode()); + return new BluetoothTetheredInterfaceRequest( + service, panCallback, callback.hashCode()); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } diff --git a/framework/java/android/bluetooth/BluetoothPbap.java b/framework/java/android/bluetooth/BluetoothPbap.java index f0580e04eedcaa87b295974085b68303c2436af2..5e5e6188c9233cf3558f685018c0196201d882af 100644 --- a/framework/java/android/bluetooth/BluetoothPbap.java +++ b/framework/java/android/bluetooth/BluetoothPbap.java @@ -36,27 +36,23 @@ import java.util.Arrays; import java.util.List; /** - * Public API for controlling the Bluetooth Pbap Service. This includes - * Bluetooth Phone book Access profile. - * BluetoothPbap is a proxy object for controlling the Bluetooth Pbap - * Service via IPC. + * Public API for controlling the Bluetooth Pbap Service. This includes Bluetooth Phone book Access + * profile. BluetoothPbap is a proxy object for controlling the Bluetooth Pbap Service via IPC. * - * Creating a BluetoothPbap object will create a binding with the - * BluetoothPbap service. Users of this object should call close() when they - * are finished with the BluetoothPbap, so that this proxy object can unbind - * from the service. + *

Creating a BluetoothPbap object will create a binding with the BluetoothPbap service. Users of + * this object should call close() when they are finished with the BluetoothPbap, so that this proxy + * object can unbind from the service. * - * This BluetoothPbap object is not immediately bound to the - * BluetoothPbap service. Use the ServiceListener interface to obtain a - * notification when it is bound, this is especially important if you wish to - * immediately call methods on BluetoothPbap after construction. + *

This BluetoothPbap object is not immediately bound to the BluetoothPbap service. Use the + * ServiceListener interface to obtain a notification when it is bound, this is especially important + * if you wish to immediately call methods on BluetoothPbap after construction. * - * To get an instance of the BluetoothPbap class, you can call - * {@link BluetoothAdapter#getProfileProxy(Context, ServiceListener, int)} with the final param - * being {@link BluetoothProfile#PBAP}. The ServiceListener should be able to get the instance of + *

To get an instance of the BluetoothPbap class, you can call {@link + * BluetoothAdapter#getProfileProxy(Context, ServiceListener, int)} with the final param being + * {@link BluetoothProfile#PBAP}. The ServiceListener should be able to get the instance of * BluetoothPbap in {@link android.bluetooth.BluetoothProfile.ServiceListener#onServiceConnected}. * - * Android only supports one connected Bluetooth Pce at a time. + *

Android only supports one connected Bluetooth Pce at a time. * * @hide */ @@ -67,19 +63,20 @@ public class BluetoothPbap implements BluetoothProfile { private static final boolean DBG = false; /** - * Intent used to broadcast the change in connection state of the PBAP - * profile. + * Intent used to broadcast the change in connection state of the PBAP profile. * *

This intent will have 3 extras: + * *

    - *
  • {@link BluetoothProfile#EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link BluetoothProfile#EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • + *
  • {@link BluetoothProfile#EXTRA_STATE} - The current state of the profile. + *
  • {@link BluetoothProfile#EXTRA_PREVIOUS_STATE}- The previous state of the profile. + *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. *
- *

{@link BluetoothProfile#EXTRA_STATE} or {@link BluetoothProfile#EXTRA_PREVIOUS_STATE} - * can be any of {@link BluetoothProfile#STATE_DISCONNECTED}, - * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, - * {@link BluetoothProfile#STATE_DISCONNECTING}. + * + *

{@link BluetoothProfile#EXTRA_STATE} or {@link BluetoothProfile#EXTRA_PREVIOUS_STATE} can + * be any of {@link BluetoothProfile#STATE_DISCONNECTED}, {@link + * BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, {@link + * BluetoothProfile#STATE_DISCONNECTING}. * * @hide */ @@ -95,8 +92,10 @@ public class BluetoothPbap implements BluetoothProfile { /** @hide */ public static final int RESULT_FAILURE = 0; + /** @hide */ public static final int RESULT_SUCCESS = 1; + /** * Connection canceled before completion. * @@ -105,49 +104,40 @@ public class BluetoothPbap implements BluetoothProfile { public static final int RESULT_CANCELED = 2; private BluetoothAdapter mAdapter; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.PBAP, "BluetoothPbap", - IBluetoothPbap.class.getName()) { - @Override - public IBluetoothPbap getServiceInterface(IBinder service) { - return IBluetoothPbap.Stub.asInterface(service); - } - }; + + private IBluetoothPbap mService; /** * Create a BluetoothPbap proxy object. * * @hide */ - public BluetoothPbap(Context context, ServiceListener listener, BluetoothAdapter adapter) { + public BluetoothPbap(Context context, BluetoothAdapter adapter) { mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); + mService = null; } /** @hide */ - protected void finalize() throws Throwable { - try { - close(); - } finally { - super.finalize(); - } + @Override + public void onServiceConnected(IBinder service) { + mService = IBluetoothPbap.Stub.asInterface(service); } - /** - * Close the connection to the backing service. Other public functions of BluetoothPbap will - * return default error results once close() has been called. Multiple invocations of close() - * are ok. - * - * @hide - */ + /** @hide */ @Override - public synchronized void close() { - mProfileConnector.disconnect(); + public void onServiceDisconnected() { + mService = null; } private IBluetoothPbap getService() { - return (IBluetoothPbap) mProfileConnector.getService(); + return mService; + } + + /** @hide */ + @Override + public BluetoothAdapter getAdapter() { + return mAdapter; } /** @@ -182,10 +172,11 @@ public class BluetoothPbap implements BluetoothProfile { @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) { log("getConnectionState: device=" + device); try { @@ -229,34 +220,32 @@ public class BluetoothPbap implements BluetoothProfile { } /** - * Set connection policy of the profile and tries to disconnect it if connectionPolicy is - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} + * Set connection policy of the profile and tries to disconnect it if connectionPolicy is {@link + * BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} * - *

The device should already be paired. - * Connection policy can be one of: - * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, - * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, - * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} + *

The device should already be paired. Connection policy can be one of: {@link + * BluetoothProfile#CONNECTION_POLICY_ALLOWED}, {@link + * BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, {@link + * BluetoothProfile#CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device * @param connectionPolicy is the connection policy to set to for this profile * @return true if connectionPolicy is set, false on error - * * @hide */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean setConnectionPolicy( + @NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); try { final IBluetoothPbap service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { + if (service != null && isEnabled() && isValidDevice(device)) { if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { return false; @@ -272,9 +261,9 @@ public class BluetoothPbap implements BluetoothProfile { } /** - * Disconnects the current Pbap client (PCE). Currently this call blocks, - * it may soon be made asynchronous. Returns false if this proxy object is - * not currently connected to the Pbap service. + * Disconnects the current Pbap client (PCE). Currently this call blocks, it may soon be made + * asynchronous. Returns false if this proxy object is not currently connected to the Pbap + * service. * * @hide */ diff --git a/framework/java/android/bluetooth/BluetoothPbapClient.java b/framework/java/android/bluetooth/BluetoothPbapClient.java index cdec02fb18381b7c447dac244a5ba550c6f5f9c5..176cad56af48eed610c687f17fd7e4879b5508bc 100644 --- a/framework/java/android/bluetooth/BluetoothPbapClient.java +++ b/framework/java/android/bluetooth/BluetoothPbapClient.java @@ -56,25 +56,27 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl * Intent used to broadcast the change in connection state of the PBAP Client profile. * *

This intent will have 3 extras: + * *

    - *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • - *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • - *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • + *
  • {@link #EXTRA_STATE} - The current state of the profile. + *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. + *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. *
* - *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link + * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link + * #STATE_DISCONNECTING}. * * @hide */ @SystemApi @SuppressLint("ActionValue") @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED"; @@ -85,40 +87,37 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl /** @hide */ public static final int RESULT_FAILURE = 0; + /** @hide */ public static final int RESULT_SUCCESS = 1; + /** Connection canceled before completion. */ /** @hide */ public static final int RESULT_CANCELED = 2; private final BluetoothAdapter mAdapter; private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.PBAP_CLIENT, - "BluetoothPbapClient", IBluetoothPbapClient.class.getName()) { - @Override - public IBluetoothPbapClient getServiceInterface(IBinder service) { - return IBluetoothPbapClient.Stub.asInterface(service); - } - }; + + private IBluetoothPbapClient mService; /** * Create a BluetoothPbapClient proxy object. * * @hide */ - BluetoothPbapClient(Context context, ServiceListener listener, BluetoothAdapter adapter) { + BluetoothPbapClient(Context context, BluetoothAdapter adapter) { if (DBG) { Log.d(TAG, "Create BluetoothPbapClient proxy object"); } mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); + mService = null; mCloseGuard = new CloseGuard(); mCloseGuard.open("close"); } /** @hide */ + @SuppressWarnings("Finalize") // TODO(b/314811467) protected void finalize() { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); @@ -135,32 +134,49 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl */ @Override public synchronized void close() { - mProfileConnector.disconnect(); + mAdapter.closeProfileProxy(this); if (mCloseGuard != null) { mCloseGuard.close(); } } + /** @hide */ + @Override + public void onServiceConnected(IBinder service) { + mService = IBluetoothPbapClient.Stub.asInterface(service); + } + + /** @hide */ + @Override + public void onServiceDisconnected() { + mService = null; + } + private IBluetoothPbapClient getService() { - return mProfileConnector.getService(); + return mService; + } + + /** @hide */ + @Override + public BluetoothAdapter getAdapter() { + return mAdapter; } /** - * Initiate connection. - * Upon successful connection to remote PBAP server the Client will - * attempt to automatically download the users phonebook and call log. + * Initiate connection. Upon successful connection to remote PBAP server the Client will attempt + * to automatically download the users phonebook and call log. * * @param device a remote device we want connect to * @return true if command has been issued successfully; false - * otherwise; - * + * otherwise; * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean connect(BluetoothDevice device) { if (DBG) { log("connect(" + device + ") for PBAP Client."); @@ -187,14 +203,14 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl * * @param device Remote Bluetooth Device * @return false on error, true otherwise - * * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean disconnect(BluetoothDevice device) { if (DBG) { log("disconnect(" + device + ")" + new Exception()); @@ -219,15 +235,17 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl /** * {@inheritDoc} + * * @hide */ @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @NonNull List getConnectedDevices() { if (DBG) { log("getConnectedDevices()"); @@ -247,7 +265,7 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -257,15 +275,17 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl /** * {@inheritDoc} + * * @hide */ @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) @NonNull public List getDevicesMatchingConnectionStates(@NonNull int[] states) { if (DBG) { @@ -286,7 +306,7 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -296,15 +316,17 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl /** * {@inheritDoc} + * * @hide */ @SystemApi @Override @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) { if (DBG) { log("getConnectionState(" + device + ")"); @@ -321,7 +343,7 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -344,19 +366,19 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl /** * Set priority of the profile * - *

The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, + *

The device should already be paired. Priority can be one of {@link #PRIORITY_ON} or {@link + * #PRIORITY_OFF}, * * @param device Paired bluetooth device - * @param priority * @return true if priority is set, false on error * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setPriority(BluetoothDevice device, int priority) { if (DBG) log("setPriority(" + device + ", " + priority + ")"); return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); @@ -365,9 +387,9 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl /** * Set connection policy of the profile * - *

The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + *

The device should already be paired. Connection policy can be one of {@link + * #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, {@link + * #CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device * @param connectionPolicy is the connection policy to set to for this profile @@ -376,12 +398,13 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean setConnectionPolicy( + @NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) { log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); } @@ -390,16 +413,17 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) + } else if (isEnabled() + && isValidDevice(device) && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -410,18 +434,19 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl /** * Get the priority of the profile. * - *

The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} + *

The priority can be any of: {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link + * #PRIORITY_UNDEFINED} * * @param device Bluetooth device * @return priority of the device * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public int getPriority(BluetoothDevice device) { if (VDBG) log("getPriority(" + device + ")"); return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); @@ -430,9 +455,8 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl /** * Get the connection policy of the profile. * - *

The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} + *

The connection policy can be any of: {@link #CONNECTION_POLICY_ALLOWED}, {@link + * #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} * * @param device Bluetooth device * @return connection policy of the device @@ -440,10 +464,11 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) { log("getConnectionPolicy(" + device + ")"); @@ -460,7 +485,7 @@ public final class BluetoothPbapClient implements BluetoothProfile, AutoCloseabl return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } diff --git a/framework/java/android/bluetooth/BluetoothProfile.java b/framework/java/android/bluetooth/BluetoothProfile.java index 58521c2512bc3260c2ce05032493a8fe0ea39abe..fe7c5d7a36bb46755da643829baece7e1530ef0d 100644 --- a/framework/java/android/bluetooth/BluetoothProfile.java +++ b/framework/java/android/bluetooth/BluetoothProfile.java @@ -18,12 +18,12 @@ package android.bluetooth; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresNoPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +import android.os.IBinder; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -32,17 +32,15 @@ import java.util.List; /** * Public APIs for the Bluetooth Profiles. * - *

Clients should call {@link BluetoothAdapter#getProfileProxy}, - * to get the Profile Proxy. Each public profile implements this - * interface. + *

Clients should call {@link BluetoothAdapter#getProfileProxy}, to get the Profile Proxy. Each + * public profile implements this interface. */ public interface BluetoothProfile { /** * Extra for the connection state intents of the individual profiles. * - * This extra represents the current connection state of the profile of the - * Bluetooth device. + *

This extra represents the current connection state of the profile of the Bluetooth device. */ @SuppressLint("ActionValue") String EXTRA_STATE = "android.bluetooth.profile.extra.STATE"; @@ -50,85 +48,75 @@ public interface BluetoothProfile { /** * Extra for the connection state intents of the individual profiles. * - * This extra represents the previous connection state of the profile of the - * Bluetooth device. + *

This extra represents the previous connection state of the profile of the Bluetooth + * device. */ @SuppressLint("ActionValue") - String EXTRA_PREVIOUS_STATE = - "android.bluetooth.profile.extra.PREVIOUS_STATE"; + String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE"; /** The profile is in disconnected state */ int STATE_DISCONNECTED = 0; + /** The profile is in connecting state */ int STATE_CONNECTING = 1; + /** The profile is in connected state */ int STATE_CONNECTED = 2; + /** The profile is in disconnecting state */ int STATE_DISCONNECTING = 3; /** @hide */ @IntDef({ - STATE_DISCONNECTED, - STATE_CONNECTING, - STATE_CONNECTED, - STATE_DISCONNECTING, + STATE_DISCONNECTED, + STATE_CONNECTING, + STATE_CONNECTED, + STATE_DISCONNECTING, }) @Retention(RetentionPolicy.SOURCE) public @interface BtProfileState {} - /** - * Headset and Handsfree profile - */ + /** Headset and Handsfree profile */ int HEADSET = 1; - /** - * A2DP profile. - */ + /** A2DP profile. */ int A2DP = 2; /** * Health Profile * - * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New - * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, - * {@link BluetoothAdapter#listenUsingL2capChannel()}, or - * {@link BluetoothDevice#createL2capChannel(int)} + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New apps should + * use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, {@link + * BluetoothAdapter#listenUsingL2capChannel()}, or {@link + * BluetoothDevice#createL2capChannel(int)} */ - @Deprecated - int HEALTH = 3; + @Deprecated int HEALTH = 3; /** * HID Host * * @hide */ - @SystemApi - int HID_HOST = 4; + @SystemApi int HID_HOST = 4; /** * PAN Profile * * @hide */ - @SystemApi - int PAN = 5; + @SystemApi int PAN = 5; /** * PBAP * * @hide */ - @SystemApi - int PBAP = 6; + @SystemApi int PBAP = 6; - /** - * GATT - */ + /** GATT */ int GATT = 7; - /** - * GATT_SERVER - */ + /** GATT_SERVER */ int GATT_SERVER = 8; /** @@ -136,8 +124,7 @@ public interface BluetoothProfile { * * @hide */ - @SystemApi - int MAP = 9; + @SystemApi int MAP = 9; /* * SAP Profile @@ -150,16 +137,14 @@ public interface BluetoothProfile { * * @hide */ - @SystemApi - int A2DP_SINK = 11; + @SystemApi int A2DP_SINK = 11; /** * AVRCP Controller Profile * * @hide */ - @SystemApi - int AVRCP_CONTROLLER = 12; + @SystemApi int AVRCP_CONTROLLER = 12; /** * AVRCP Target Profile @@ -173,28 +158,23 @@ public interface BluetoothProfile { * * @hide */ - @SystemApi - int HEADSET_CLIENT = 16; + @SystemApi int HEADSET_CLIENT = 16; /** * PBAP Client * * @hide */ - @SystemApi - int PBAP_CLIENT = 17; + @SystemApi int PBAP_CLIENT = 17; /** * MAP Messaging Client Equipment (MCE) * * @hide */ - @SystemApi - int MAP_CLIENT = 18; + @SystemApi int MAP_CLIENT = 18; - /** - * HID Device - */ + /** HID Device */ int HID_DEVICE = 19; /** @@ -202,19 +182,12 @@ public interface BluetoothProfile { * * @hide */ - @SystemApi - int OPP = 20; + @SystemApi int OPP = 20; - /** - * Hearing Aid Device - * - */ + /** Hearing Aid Device */ int HEARING_AID = 21; - /** - * LE Audio Device - * - */ + /** LE Audio Device */ int LE_AUDIO = 22; /** @@ -222,20 +195,14 @@ public interface BluetoothProfile { * * @hide */ - @SystemApi - int VOLUME_CONTROL = 23; + @SystemApi int VOLUME_CONTROL = 23; /** - * @hide - * Media Control Profile server - * + * @hide Media Control Profile server */ int MCP_SERVER = 24; - /** - * Coordinated Set Identification Profile set coordinator - * - */ + /** Coordinated Set Identification Profile set coordinator */ int CSIP_SET_COORDINATOR = 25; /** @@ -243,13 +210,10 @@ public interface BluetoothProfile { * * @hide */ - @SystemApi - int LE_AUDIO_BROADCAST = 26; + @SystemApi int LE_AUDIO_BROADCAST = 26; /** - * @hide - * Telephone Bearer Service from Call Control Profile - * + * @hide Telephone Bearer Service from Call Control Profile */ int LE_CALL_CONTROL = 27; @@ -264,8 +228,7 @@ public interface BluetoothProfile { * * @hide */ - @SystemApi - int LE_AUDIO_BROADCAST_ASSISTANT = 29; + @SystemApi int LE_AUDIO_BROADCAST_ASSISTANT = 29; /** * Battery Service @@ -275,102 +238,96 @@ public interface BluetoothProfile { int BATTERY = 30; /** - * Max profile ID. This value should be updated whenever a new profile is added to match - * the largest value assigned to a profile. + * Max profile ID. This value should be updated whenever a new profile is added to match the + * largest value assigned to a profile. * * @hide */ int MAX_PROFILE_ID = 30; /** - * Default priority for devices that we try to auto-connect to and - * and allow incoming connections for the profile + * Default priority for devices that we try to auto-connect to and allow incoming connections + * for the profile * * @hide - **/ + */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) int PRIORITY_AUTO_CONNECT = 1000; /** - * Default priority for devices that allow incoming - * and outgoing connections for the profile + * Default priority for devices that allow incoming and outgoing connections for the profile * * @hide * @deprecated Replaced with {@link #CONNECTION_POLICY_ALLOWED} - **/ - @Deprecated - @SystemApi - int PRIORITY_ON = 100; + */ + @Deprecated @SystemApi int PRIORITY_ON = 100; /** - * Default priority for devices that does not allow incoming - * connections and outgoing connections for the profile. + * Default priority for devices that does not allow incoming connections and outgoing + * connections for the profile. * * @hide * @deprecated Replaced with {@link #CONNECTION_POLICY_FORBIDDEN} - **/ - @Deprecated - @SystemApi - int PRIORITY_OFF = 0; + */ + @Deprecated @SystemApi int PRIORITY_OFF = 0; /** * Default priority when not set or when the device is unpaired * * @hide */ - @UnsupportedAppUsage - int PRIORITY_UNDEFINED = -1; + @UnsupportedAppUsage int PRIORITY_UNDEFINED = -1; /** @hide */ - @IntDef(prefix = "CONNECTION_POLICY_", value = {CONNECTION_POLICY_ALLOWED, - CONNECTION_POLICY_FORBIDDEN, CONNECTION_POLICY_UNKNOWN}) + @IntDef( + prefix = "CONNECTION_POLICY_", + value = { + CONNECTION_POLICY_ALLOWED, + CONNECTION_POLICY_FORBIDDEN, + CONNECTION_POLICY_UNKNOWN + }) @Retention(RetentionPolicy.SOURCE) - public @interface ConnectionPolicy{} + public @interface ConnectionPolicy {} /** - * Default connection policy for devices that allow incoming and outgoing connections - * for the profile + * Default connection policy for devices that allow incoming and outgoing connections for the + * profile * * @hide - **/ - @SystemApi - int CONNECTION_POLICY_ALLOWED = 100; + */ + @SystemApi int CONNECTION_POLICY_ALLOWED = 100; /** - * Default connection policy for devices that do not allow incoming or outgoing connections - * for the profile. + * Default connection policy for devices that do not allow incoming or outgoing connections for + * the profile. * * @hide - **/ - @SystemApi - int CONNECTION_POLICY_FORBIDDEN = 0; + */ + @SystemApi int CONNECTION_POLICY_FORBIDDEN = 0; /** * Default connection policy when not set or when the device is unpaired * * @hide */ - @SystemApi - int CONNECTION_POLICY_UNKNOWN = -1; + @SystemApi int CONNECTION_POLICY_UNKNOWN = -1; /** * Get connected devices for this specific profile. * - *

Return the set of devices which are in state {@link #STATE_CONNECTED} + *

Return the set of devices which are in state {@link #STATE_CONNECTED} * * @return List of devices. The list will be empty on error. */ List getConnectedDevices(); /** - * Get a list of devices that match any of the given connection - * states. + * Get a list of devices that match any of the given connection states. * - *

If none of the devices match any of the given states, - * an empty list will be returned. + *

If none of the devices match any of the given states, an empty list will be returned. * * @param states Array of states. States can be one of {@link #STATE_CONNECTED}, {@link - * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}, + * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}, * @return List of devices. The list will be empty on error. */ List getDevicesMatchingConnectionStates(int[] states); @@ -380,25 +337,40 @@ public interface BluetoothProfile { * * @param device Remote bluetooth device. * @return State of the profile connection. One of {@link #STATE_CONNECTED}, {@link - * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING} + * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING} + */ + @BtProfileState + int getConnectionState(BluetoothDevice device); + + /** + * Called by the BluetoothAdapter when the Bluetooth service is connected with a Binder instance + * corresponding to the service associated with the profile + * + * @hide */ - @BtProfileState int getConnectionState(BluetoothDevice device); + void onServiceConnected(IBinder service); /** - * Releases any held resources. + * Called by the BluetoothAdapter when the Bluetooth service connection has been lost * * @hide */ - void close(); + void onServiceDisconnected(); /** - * An interface for notifying BluetoothProfile IPC clients when they have - * been connected or disconnected to the service. + * Get the BluetoothAdapter that created this proxy + * + * @hide + */ + BluetoothAdapter getAdapter(); + + /** + * An interface for notifying BluetoothProfile IPC clients when they have been connected or + * disconnected to the service. */ public interface ServiceListener { /** - * Called to notify the client when the proxy object has been - * connected to the service. + * Called to notify the client when the proxy object has been connected to the service. * * @param profile - One of {@link #HEADSET} or {@link #A2DP} * @param proxy - One of {@link BluetoothHeadset} or {@link BluetoothA2dp} @@ -407,8 +379,8 @@ public interface BluetoothProfile { void onServiceConnected(int profile, BluetoothProfile proxy); /** - * Called to notify the client that this proxy object has been - * disconnected from the service. + * Called to notify the client that this proxy object has been disconnected from the + * service. * * @param profile - One of {@link #HEADSET} or {@link #A2DP} */ @@ -416,40 +388,13 @@ public interface BluetoothProfile { void onServiceDisconnected(int profile); } - /** - * A service listener that forwards methods calls to the given listener. - * This can be used to override specific method. - * @hide - */ - class ForwardingServiceListener implements ServiceListener { - private final ServiceListener mListener; - - ForwardingServiceListener(@Nullable ServiceListener listener) { - mListener = listener; - } - - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (mListener != null) { - mListener.onServiceConnected(profile, proxy); - } - } - - @Override - public void onServiceDisconnected(int profile) { - if (mListener != null) { - mListener.onServiceDisconnected(profile); - } - } - } - /** * Convert an integer value of connection state into human readable string * * @param connectionState - One of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, or {@link #STATE_DISCONNECTED} - * @return a string representation of the connection state, STATE_UNKNOWN if the state - * is not defined + * {@link #STATE_CONNECTED}, or {@link #STATE_DISCONNECTED} + * @return a string representation of the connection state, STATE_UNKNOWN if the state is not + * defined * @hide */ @SystemApi @@ -474,14 +419,14 @@ public interface BluetoothProfile { * Convert an integer value of profile ID into human readable string * * @param profile profile ID - * @return profile name as String, UNKOWN_PROFILE if the profile ID is not defined. + * @return profile name as String, UNKNOWN_PROFILE if the profile ID is not defined. * @hide */ @SystemApi @NonNull @RequiresNoPermission static String getProfileName(int profile) { - switch(profile) { + switch (profile) { case HEADSET: return "HEADSET"; case A2DP: @@ -537,7 +482,7 @@ public interface BluetoothProfile { case BATTERY: return "BATTERY"; default: - return "UNKNOWN_PROFILE"; + return "UNKNOWN_PROFILE (" + profile + ")"; } } } diff --git a/framework/java/android/bluetooth/BluetoothProfileConnector.java b/framework/java/android/bluetooth/BluetoothProfileConnector.java index 8620ed67eebb7ce9769e9a3db360f97101fd19eb..a5c94f6d99f07b3ea46cad332c0979bb5418749e 100644 --- a/framework/java/android/bluetooth/BluetoothProfileConnector.java +++ b/framework/java/android/bluetooth/BluetoothProfileConnector.java @@ -16,232 +16,191 @@ package android.bluetooth; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SuppressLint; import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.os.UserHandle; import android.util.CloseGuard; import android.util.Log; -import java.util.List; +import java.util.Objects; + /** - * Connector for Bluetooth profile proxies to bind manager service and - * profile services - * @param The Bluetooth profile interface for this connection. + * Connector for Bluetooth profile proxies to bind manager service and profile services + * * @hide */ @SuppressLint("AndroidFrameworkBluetoothPermission") -public abstract class BluetoothProfileConnector { +public final class BluetoothProfileConnector extends Handler { + private static final String TAG = BluetoothProfileConnector.class.getSimpleName(); private final CloseGuard mCloseGuard = new CloseGuard(); private final int mProfileId; private BluetoothProfile.ServiceListener mServiceListener; private final BluetoothProfile mProfileProxy; - private Context mContext; - private final String mProfileName; - private final String mServiceName; - private volatile T mService; - - // -3 match with UserHandle.USER_CURRENT_OR_SELF - private static final UserHandle USER_HANDLE_CURRENT_OR_SELF = UserHandle.of(-3); + private String mPackageName; + private final IBluetoothManager mBluetoothManager; + private boolean mBound = false; private static final int MESSAGE_SERVICE_CONNECTED = 100; private static final int MESSAGE_SERVICE_DISCONNECTED = 101; private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new IBluetoothStateChangeCallback.Stub() { - public void onBluetoothStateChange(boolean up) { - if (up) { - doBind(); - } else { - doUnbind(); - } - } - }; - - private @Nullable ComponentName resolveSystemService(@NonNull Intent intent, - @NonNull PackageManager pm) { - List results = pm.queryIntentServices(intent, - PackageManager.ResolveInfoFlags.of(0)); - if (results == null) { - return null; - } - ComponentName comp = null; - for (int i = 0; i < results.size(); i++) { - ResolveInfo ri = results.get(i); - if ((ri.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - continue; - } - ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName, - ri.serviceInfo.name); - if (comp != null) { - throw new IllegalStateException("Multiple system services handle " + intent - + ": " + comp + ", " + foundComp); - } - comp = foundComp; - } - return comp; - } + public void onBluetoothStateChange(boolean up) { + if (up) { + doBind(); + } else { + doUnbind(); + } + } + }; private final IBluetoothProfileServiceConnection mConnection = new IBluetoothProfileServiceConnection.Stub() { - @Override - public void onServiceConnected(ComponentName className, IBinder service) { - logDebug("Proxy object connected"); - mService = getServiceInterface(service); - mHandler.sendMessage(mHandler.obtainMessage( - MESSAGE_SERVICE_CONNECTED)); - } - - @Override - public void onServiceDisconnected(ComponentName className) { - logDebug("Proxy object disconnected"); - doUnbind(); - mHandler.sendMessage(mHandler.obtainMessage( - MESSAGE_SERVICE_DISCONNECTED)); - } - }; + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + Log.d( + TAG, + "Proxy object connected for " + + BluetoothProfile.getProfileName(mProfileId)); + mProfileProxy.onServiceConnected(service); + sendEmptyMessage(MESSAGE_SERVICE_CONNECTED); + } - BluetoothProfileConnector(BluetoothProfile profile, int profileId, String profileName, - String serviceName) { + @Override + public void onServiceDisconnected(ComponentName className) { + Log.d( + TAG, + "Proxy object disconnected for " + + BluetoothProfile.getProfileName(mProfileId)); + boolean bound = mBound; + doUnbind(); + if (bound) { + sendEmptyMessage(MESSAGE_SERVICE_DISCONNECTED); + } + } + }; + + /** @hide */ + public BluetoothProfileConnector( + Looper looper, + BluetoothProfile profile, + int profileId, + IBluetoothManager bluetoothManager) { + super(looper); mProfileId = profileId; mProfileProxy = profile; - mProfileName = profileName; - mServiceName = serviceName; + mBluetoothManager = Objects.requireNonNull(bluetoothManager); } - /** {@hide} */ + BluetoothProfileConnector(BluetoothProfile profile, int profileId) { + this( + Looper.getMainLooper(), + profile, + profileId, + BluetoothAdapter.getDefaultAdapter().getBluetoothManager()); + } + + /** @hide */ @Override + @SuppressWarnings("Finalize") // TODO(b/314811467) public void finalize() { mCloseGuard.warnIfOpen(); doUnbind(); } - private boolean doBind() { + private void doBind() { synchronized (mConnection) { - if (mService == null) { - logDebug("Binding service..."); + if (!mBound) { + Log.d( + TAG, + "Binding service " + + BluetoothProfile.getProfileName(mProfileId) + + " for " + + mPackageName); mCloseGuard.open("doUnbind"); try { - return BluetoothAdapter.getDefaultAdapter().getBluetoothManager() - .bindBluetoothProfileService(mProfileId, mServiceName, mConnection); + mBluetoothManager.bindBluetoothProfileService(mProfileId, mConnection); + mBound = true; } catch (RemoteException re) { - logError("Failed to bind service. " + re); - return false; + Log.e( + TAG, + "Failed to bind service. " + + BluetoothProfile.getProfileName(mProfileId), + re); } } } - return true; } private void doUnbind() { synchronized (mConnection) { - if (mService != null) { - logDebug("Unbinding service..."); + if (mBound) { + Log.d( + TAG, + "Unbinding service " + + BluetoothProfile.getProfileName(mProfileId) + + " for " + + mPackageName); mCloseGuard.close(); try { - BluetoothAdapter.getDefaultAdapter().getBluetoothManager() - .unbindBluetoothProfileService(mProfileId, mConnection); + mBluetoothManager.unbindBluetoothProfileService(mProfileId, mConnection); + mBound = false; } catch (RemoteException re) { - logError("Unable to unbind service: " + re); + Log.e( + TAG, + "Unable to unbind service " + + BluetoothProfile.getProfileName(mProfileId), + re); } finally { - mService = null; + mProfileProxy.onServiceDisconnected(); } } } } - void connect(Context context, BluetoothProfile.ServiceListener listener) { - mContext = context; + /** @hide */ + public void connect(String packageName, BluetoothProfile.ServiceListener listener) { + mPackageName = packageName; mServiceListener = listener; - IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager(); - - // Preserve legacy compatibility where apps were depending on - // registerStateChangeCallback() performing a permissions check which - // has been relaxed in modern platform versions - if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R - && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Need BLUETOOTH permission"); - } - if (mgr != null) { - try { - mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException re) { - logError("Failed to register state change callback. " + re); - } + try { + mBluetoothManager.registerStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException re) { + Log.e(TAG, "Failed to register state change callback.", re); } - doBind(); } - void disconnect() { + /** @hide */ + public void disconnect() { if (mServiceListener != null) { BluetoothProfile.ServiceListener listener = mServiceListener; mServiceListener = null; listener.onServiceDisconnected(mProfileId); } - IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager(); - if (mgr != null) { - try { - mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException re) { - logError("Failed to unregister state change callback" + re); - } + try { + mBluetoothManager.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException re) { + Log.e(TAG, "Failed to unregister state change callback", re); } - doUnbind(); - } - - T getService() { - return mService; } - /** - * This abstract function is used to implement method to get the - * connected Bluetooth service interface. - * @param service the connected binder service. - * @return T the binder interface of {@code service}. - * @hide - */ - public abstract T getServiceInterface(IBinder service); - - private void logDebug(String log) { - Log.d(mProfileName, log); - } - - private void logError(String log) { - Log.e(mProfileName, log); - } - - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final Handler mHandler = new Handler(Looper.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_SERVICE_CONNECTED: { - if (mServiceListener != null) { - mServiceListener.onServiceConnected(mProfileId, mProfileProxy); - } - break; + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_SERVICE_CONNECTED: + if (mServiceListener != null) { + mServiceListener.onServiceConnected(mProfileId, mProfileProxy); } - case MESSAGE_SERVICE_DISCONNECTED: { - if (mServiceListener != null) { - mServiceListener.onServiceDisconnected(mProfileId); - } - break; + break; + case MESSAGE_SERVICE_DISCONNECTED: + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(mProfileId); } - } + break; } - }; + } } diff --git a/framework/java/android/bluetooth/BluetoothQualityReport.java b/framework/java/android/bluetooth/BluetoothQualityReport.java index b74bb3b6955b6eb570289d89a50b9fb8dd43defe..92b3de7524d59980347db68df68aeaa58478787d 100644 --- a/framework/java/android/bluetooth/BluetoothQualityReport.java +++ b/framework/java/android/bluetooth/BluetoothQualityReport.java @@ -44,57 +44,56 @@ import java.util.Objects; * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link * BluetoothQualityReport.BqrVsLsto} object. *

  • For A2DP choppy event, you can call {@link #getBqrCommon} to get a {@link - * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a - * {@link BluetoothQualityReport.BqrVsA2dpChoppy} object. + * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link + * BluetoothQualityReport.BqrVsA2dpChoppy} object. *
  • For SCO choppy event, you can call {@link #getBqrCommon} to get a {@link - * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a - * {@link BluetoothQualityReport.BqrVsScoChoppy} object. + * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link + * BluetoothQualityReport.BqrVsScoChoppy} object. *
  • For Connect fail event, you can call {@link #getBqrCommon} to get a {@link - * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a - * {@link BluetoothQualityReport.BqrConnectFail} object. + * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link + * BluetoothQualityReport.BqrConnectFail} object. * * * @hide */ @SystemApi public final class BluetoothQualityReport implements Parcelable { - private static final String TAG = "BluetoothQualityReport"; + private static final String TAG = BluetoothQualityReport.class.getSimpleName(); /** * Quality report ID: Monitor. * * @hide */ - @SystemApi - public static final int QUALITY_REPORT_ID_MONITOR = 0x01; + @SystemApi public static final int QUALITY_REPORT_ID_MONITOR = 0x01; + /** * Quality report ID: Approaching LSTO. * * @hide */ - @SystemApi - public static final int QUALITY_REPORT_ID_APPROACH_LSTO = 0x02; + @SystemApi public static final int QUALITY_REPORT_ID_APPROACH_LSTO = 0x02; + /** * Quality report ID: A2DP choppy. * * @hide */ - @SystemApi - public static final int QUALITY_REPORT_ID_A2DP_CHOPPY = 0x03; + @SystemApi public static final int QUALITY_REPORT_ID_A2DP_CHOPPY = 0x03; + /** * Quality report ID: SCO choppy. * * @hide */ - @SystemApi - public static final int QUALITY_REPORT_ID_SCO_CHOPPY = 0x04; + @SystemApi public static final int QUALITY_REPORT_ID_SCO_CHOPPY = 0x04; + /** * Quality report ID: Connect Fail. * * @hide */ - @SystemApi - public static final int QUALITY_REPORT_ID_CONN_FAIL = 0x08; + @SystemApi public static final int QUALITY_REPORT_ID_CONN_FAIL = 0x08; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -390,18 +389,16 @@ public final class BluetoothQualityReport implements Parcelable { } /** - * Get the event data object based on current Quality Report Id. - * If the report id is {@link #QUALITY_REPORT_ID_MONITOR}, - * this returns a {@link BluetoothQualityReport.BqrCommon} object. - * If the report id is {@link #QUALITY_REPORT_ID_APPROACH_LSTO}, - * this returns a {@link BluetoothQualityReport.BqrVsLsto} object. - * If the report id is {@link #QUALITY_REPORT_ID_A2DP_CHOPPY}, - * this returns a {@link BluetoothQualityReport.BqrVsA2dpChoppy} object. - * If the report id is {@link #QUALITY_REPORT_ID_SCO_CHOPPY}, - * this returns a {@link BluetoothQualityReport.BqrVsScoChoppy} object. - * If the report id is {@link #QUALITY_REPORT_ID_CONN_FAIL}, - * this returns a {@link BluetoothQualityReport.BqrConnectFail} object. - * If the report id is none of the above, this returns {@code null}. + * Get the event data object based on current Quality Report Id. If the report id is {@link + * #QUALITY_REPORT_ID_MONITOR}, this returns a {@link BluetoothQualityReport.BqrCommon} object. + * If the report id is {@link #QUALITY_REPORT_ID_APPROACH_LSTO}, this returns a {@link + * BluetoothQualityReport.BqrVsLsto} object. If the report id is {@link + * #QUALITY_REPORT_ID_A2DP_CHOPPY}, this returns a {@link + * BluetoothQualityReport.BqrVsA2dpChoppy} object. If the report id is {@link + * #QUALITY_REPORT_ID_SCO_CHOPPY}, this returns a {@link BluetoothQualityReport.BqrVsScoChoppy} + * object. If the report id is {@link #QUALITY_REPORT_ID_CONN_FAIL}, this returns a {@link + * BluetoothQualityReport.BqrConnectFail} object. If the report id is none of the above, this + * returns {@code null}. * * @return the event data object based on the quality report id * @hide @@ -477,9 +474,7 @@ public final class BluetoothQualityReport implements Parcelable { } } - /** - * BluetoothQualityReport to String. - */ + /** BluetoothQualityReport to String. */ @Override @NonNull public String toString() { @@ -525,12 +520,12 @@ public final class BluetoothQualityReport implements Parcelable { */ @SystemApi public static final class Builder { - private String remoteAddr; + private String remoteAddr = "00:00:00:00:00:00"; private int lmpVer; private int lmpSubVer; private int manufacturerId; - private String remoteName; - private BluetoothClass bluetoothClass; + private String remoteName = ""; + private BluetoothClass bluetoothClass = new BluetoothClass(0); private byte[] rawData; /** @@ -555,7 +550,11 @@ public final class BluetoothQualityReport implements Parcelable { @NonNull @SystemApi public Builder setRemoteAddress(@Nullable String remoteAddr) { - this.remoteAddr = remoteAddr; + if (!BluetoothAdapter.checkBluetoothAddress(remoteAddr)) { + Log.d(TAG, "remote address is not a valid bluetooth address: " + remoteAddr); + } else { + this.remoteAddr = remoteAddr; + } return this; } @@ -611,7 +610,11 @@ public final class BluetoothQualityReport implements Parcelable { @NonNull @SystemApi public Builder setRemoteName(@Nullable String remoteName) { - this.remoteName = remoteName; + if (remoteName == null) { + Log.d(TAG, "remote name is null"); + } else { + this.remoteName = remoteName; + } return this; } @@ -625,7 +628,11 @@ public final class BluetoothQualityReport implements Parcelable { @NonNull @SystemApi public Builder setBluetoothClass(@Nullable BluetoothClass bluetoothClass) { - this.bluetoothClass = bluetoothClass; + if (bluetoothClass == null) { + Log.d(TAG, "remote bluetooth class is null"); + } else { + this.bluetoothClass = bluetoothClass; + } return this; } @@ -639,7 +646,6 @@ public final class BluetoothQualityReport implements Parcelable { @NonNull @SystemApi public BluetoothQualityReport build() { - validateBluetoothQualityReport(); return new BluetoothQualityReport( remoteAddr, lmpVer, @@ -649,18 +655,6 @@ public final class BluetoothQualityReport implements Parcelable { bluetoothClass, rawData); } - - private void validateBluetoothQualityReport() { - if (!BluetoothAdapter.checkBluetoothAddress(remoteAddr)) { - Log.d(TAG, "remote addr is invalid"); - remoteAddr = "00:00:00:00:00:00"; - } - - if (remoteName == null) { - Log.d(TAG, "remote name is null"); - remoteName = ""; - } - } } /** @@ -822,16 +816,14 @@ public final class BluetoothQualityReport implements Parcelable { * * @hide */ - @SystemApi - public static final int CONNECTION_ROLE_CENTRAL = 0; + @SystemApi public static final int CONNECTION_ROLE_CENTRAL = 0; /** * Connection role: peripheral. * * @hide */ - @SystemApi - public static final int CONNECTION_ROLE_PERIPHERAL = 1; + @SystemApi public static final int CONNECTION_ROLE_PERIPHERAL = 1; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -1106,9 +1098,7 @@ public final class BluetoothQualityReport implements Parcelable { } }; - /** - * BqrCommon to String. - */ + /** BqrCommon to String. */ @Override @NonNull public String toString() { @@ -1364,9 +1354,7 @@ public final class BluetoothQualityReport implements Parcelable { } }; - /** - * BqrVsLsto to String. - */ + /** BqrVsLsto to String. */ @Override @NonNull public String toString() { @@ -1573,9 +1561,7 @@ public final class BluetoothQualityReport implements Parcelable { } }; - /** - * BqrVsA2dpChoppy to String. - */ + /** BqrVsA2dpChoppy to String. */ @Override @NonNull public String toString() { @@ -1799,9 +1785,9 @@ public final class BluetoothQualityReport implements Parcelable { } /** - * Get the count of missed Mic interrrupts. + * Get the count of missed Mic interrupts. * - * @return the count of missed Mic interrrupts + * @return the count of missed Mic interrupts * @hide */ @SystemApi @@ -1810,9 +1796,9 @@ public final class BluetoothQualityReport implements Parcelable { } /** - * Get the count of missed LPA interrrupts. + * Get the count of missed LPA interrupts. * - * @return the count of missed LPA interrrupts + * @return the count of missed LPA interrupts * @hide */ @SystemApi @@ -1821,9 +1807,9 @@ public final class BluetoothQualityReport implements Parcelable { } /** - * Get the count of missed Speaker interrrupts. + * Get the count of missed Speaker interrupts. * - * @return the count of missed Speaker interrrupts + * @return the count of missed Speaker interrupts * @hide */ @SystemApi @@ -1948,9 +1934,7 @@ public final class BluetoothQualityReport implements Parcelable { } }; - /** - * BqrVsScoChoppy to String. - */ + /** BqrVsScoChoppy to String. */ @Override @NonNull public String toString() { @@ -2012,41 +1996,41 @@ public final class BluetoothQualityReport implements Parcelable { @SystemApi public static final class BqrConnectFail implements Parcelable { private static final String TAG = BluetoothQualityReport.TAG + ".BqrConnectFail"; + /** * Connect Fail reason: No error. * * @hide */ - @SystemApi - public static final int CONNECT_FAIL_ID_NO_ERROR = 0x00; + @SystemApi public static final int CONNECT_FAIL_ID_NO_ERROR = 0x00; + /** * Connect Fail reason: Page timeout. * * @hide */ - @SystemApi - public static final int CONNECT_FAIL_ID_PAGE_TIMEOUT = 0x04; + @SystemApi public static final int CONNECT_FAIL_ID_PAGE_TIMEOUT = 0x04; + /** * Connect Fail reason: Connection timeout. * * @hide */ - @SystemApi - public static final int CONNECT_FAIL_ID_CONNECTION_TIMEOUT = 0x08; + @SystemApi public static final int CONNECT_FAIL_ID_CONNECTION_TIMEOUT = 0x08; + /** * Connect Fail reason: ACL already exists. * * @hide */ - @SystemApi - public static final int CONNECT_FAIL_ID_ACL_ALREADY_EXIST = 0x0b; + @SystemApi public static final int CONNECT_FAIL_ID_ACL_ALREADY_EXIST = 0x0b; + /** * Connect Fail reason: Controller busy. * * @hide */ - @SystemApi - public static final int CONNECT_FAIL_ID_CONTROLLER_BUSY = 0x3a; + @SystemApi public static final int CONNECT_FAIL_ID_CONTROLLER_BUSY = 0x3a; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -2150,9 +2134,7 @@ public final class BluetoothQualityReport implements Parcelable { } } - /** - * BqrConnectFail to String. - */ + /** BqrConnectFail to String. */ @Override @NonNull public String toString() { diff --git a/framework/java/android/bluetooth/BluetoothSap.java b/framework/java/android/bluetooth/BluetoothSap.java index 2aada0d2f0b14e0eeeab6c435f6f6f9fa92a733b..8192aab4276944bf1506b3149b60431fec797275 100644 --- a/framework/java/android/bluetooth/BluetoothSap.java +++ b/framework/java/android/bluetooth/BluetoothSap.java @@ -47,12 +47,10 @@ import java.util.Objects; import java.util.concurrent.TimeoutException; /** - * This class provides the APIs to control the Bluetooth SIM - * Access Profile (SAP). + * This class provides the APIs to control the Bluetooth SIM Access Profile (SAP). * - *

    BluetoothSap is a proxy object for controlling the Bluetooth - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothSap proxy object. + *

    BluetoothSap is a proxy object for controlling the Bluetooth Service via IPC. Use {@link + * BluetoothAdapter#getProfileProxy} to get the BluetoothSap proxy object. * *

    Each method is protected with its appropriate permission. * @@ -71,15 +69,16 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { * Intent used to broadcast the change in connection state of the profile. * *

    This intent will have 3 extras: + * *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • + *
    • {@link #EXTRA_STATE} - The current state of the profile. + *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. + *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. *
    * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link + * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link + * #STATE_DISCONNECTING}. * * @hide */ @@ -100,7 +99,7 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { public static final int STATE_ERROR = -1; /** - * Connection state change succceeded. + * Connection state change succeeded. * * @hide */ @@ -115,32 +114,21 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { private final BluetoothAdapter mAdapter; private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.SAP, - "BluetoothSap", IBluetoothSap.class.getName()) { - @Override - public IBluetoothSap getServiceInterface(IBinder service) { - return IBluetoothSap.Stub.asInterface(service); - } - }; - /** - * Create a BluetoothSap proxy object. - */ - /* package */ BluetoothSap(Context context, ServiceListener listener, - BluetoothAdapter adapter) { + private IBluetoothSap mService; + + /** Create a BluetoothSap proxy object. */ + /* package */ BluetoothSap(Context context, BluetoothAdapter adapter) { if (DBG) Log.d(TAG, "Create BluetoothSap proxy object"); mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); + mService = null; mCloseGuard = new CloseGuard(); mCloseGuard.open("close"); } - /** - * - * @hide - */ + /** @hide */ + @SuppressWarnings("Finalize") // TODO(b/314811467) protected void finalize() { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); @@ -157,18 +145,36 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { */ @Override public synchronized void close() { - mProfileConnector.disconnect(); + mAdapter.closeProfileProxy(this); + } + + /** @hide */ + @Override + public void onServiceConnected(IBinder service) { + mService = IBluetoothSap.Stub.asInterface(service); + } + + /** @hide */ + @Override + public void onServiceDisconnected() { + mService = null; } private IBluetoothSap getService() { - return mProfileConnector.getService(); + return mService; + } + + /** @hide */ + @Override + public BluetoothAdapter getAdapter() { + return mAdapter; } /** * Get the current state of the BluetoothSap service. * * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not - * connected to the Sap service. + * connected to the Sap service. * @hide */ @RequiresBluetoothConnectPermission @@ -196,7 +202,7 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { * Get the currently connected remote Bluetooth device (PCE). * * @return The remote Bluetooth device, or null if not in connected or connecting state, or if - * this proxy object is not connected to the Sap service. + * this proxy object is not connected to the Sap service. * @hide */ @RequiresBluetoothConnectPermission @@ -224,9 +230,8 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { } /** - * Returns true if the specified Bluetooth device is connected. - * Returns false if not connected, or if this proxy object is not - * currently connected to the Sap service. + * Returns true if the specified Bluetooth device is connected. Returns false if not connected, + * or if this proxy object is not currently connected to the Sap service. * * @hide */ @@ -252,8 +257,7 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { } /** - * Initiate connection. Initiation of outgoing connections is not - * supported for SAP server. + * Initiate connection. Initiation of outgoing connections is not supported for SAP server. * * @hide */ @@ -353,14 +357,16 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { } /** - * There are several instances of IpcDataCache used in this class. - * BluetoothCache wraps up the common code. All caches are created with a maximum of - * eight entries, and the key is in the bluetooth module. The name is set to the api. + * There are several instances of IpcDataCache used in this class. BluetoothCache wraps up the + * common code. All caches are created with a maximum of eight entries, and the key is in the + * bluetooth module. The name is set to the api. */ private static class BluetoothCache extends IpcDataCache { BluetoothCache(String api, IpcDataCache.QueryHandler query) { super(8, IpcDataCache.MODULE_BLUETOOTH, api, api, query); - }}; + } + } + ; /** @hide */ public void disableBluetoothGetConnectionStateCache() { @@ -373,44 +379,49 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { } /** - * Invalidate a bluetooth cache. This method is just a short-hand wrapper that - * enforces the bluetooth module. + * Invalidate a bluetooth cache. This method is just a short-hand wrapper that enforces the + * bluetooth module. */ private static void invalidateCache(@NonNull String api) { IpcDataCache.invalidateCache(IpcDataCache.MODULE_BLUETOOTH, api); } - private static final IpcDataCache - .QueryHandler>, Integer> - sBluetoothConnectionQuery = new IpcDataCache.QueryHandler<>() { - @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - @Override - public Integer apply(Pair> pairQuery) { - IBluetoothSap service = pairQuery.first; - AttributionSource source = pairQuery.second.first; - BluetoothDevice device = pairQuery.second.second; - if (DBG) { - log("getConnectionState(" + device.getAnonymizedAddress() + ") uncached"); - } - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - try { - service.getConnectionState(device, source, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()) - .getValue(BluetoothProfile.STATE_DISCONNECTED); - } catch (RemoteException | TimeoutException e) { - throw new RuntimeException(e); - } - } - }; + private static final IpcDataCache.QueryHandler< + Pair>, Integer> + sBluetoothConnectionQuery = + new IpcDataCache.QueryHandler<>() { + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @Override + public Integer apply( + Pair> pairQuery) { + IBluetoothSap service = IBluetoothSap.Stub.asInterface(pairQuery.first); + AttributionSource source = pairQuery.second.first; + BluetoothDevice device = pairQuery.second.second; + if (DBG) { + log( + "getConnectionState(" + + device.getAnonymizedAddress() + + ") uncached"); + } + final SynchronousResultReceiver recv = + SynchronousResultReceiver.get(); + try { + service.getConnectionState(device, source, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()) + .getValue(BluetoothProfile.STATE_DISCONNECTED); + } catch (RemoteException | TimeoutException e) { + throw new RuntimeException(e); + } + } + }; private static final String GET_CONNECTION_STATE_API = "BluetoothSap_getConnectionState"; - private static final - BluetoothCache>, Integer> - sBluetoothConnectionCache = new BluetoothCache<>(GET_CONNECTION_STATE_API, - sBluetoothConnectionQuery); + private static final BluetoothCache< + Pair>, Integer> + sBluetoothConnectionCache = + new BluetoothCache<>(GET_CONNECTION_STATE_API, sBluetoothConnectionQuery); /** * Get connection state of device @@ -429,7 +440,7 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { } else if (isEnabled() && isValidDevice(device)) { try { return sBluetoothConnectionCache.query( - new Pair<>(service, new Pair<>(mAttributionSource, device))); + new Pair<>(service.asBinder(), new Pair<>(mAttributionSource, device))); } catch (RuntimeException e) { if (!(e.getCause() instanceof TimeoutException) && !(e.getCause() instanceof RemoteException)) { @@ -444,19 +455,19 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { /** * Set priority of the profile * - *

    The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, + *

    The device should already be paired. Priority can be one of {@link #PRIORITY_ON} or {@link + * #PRIORITY_OFF}, * * @param device Paired bluetooth device - * @param priority * @return true if priority is set, false on error * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setPriority(BluetoothDevice device, int priority) { if (DBG) log("setPriority(" + device + ", " + priority + ")"); return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); @@ -465,26 +476,25 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { /** * Set connection policy of the profile * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + *

    The device should already be paired. Connection policy can be one of {@link + * #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, {@link + * #CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device * @param connectionPolicy is the connection policy to set to for this profile * @return true if connectionPolicy is set, false on error - * * @throws NullPointerException if device is null - * * @hide */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean setConnectionPolicy( + @NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); Objects.requireNonNull(device, "BluetoothDevice cannot be null"); final IBluetoothSap service = getService(); @@ -492,9 +502,10 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) + } else if (isEnabled() + && isValidDevice(device) && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); @@ -509,19 +520,19 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { /** * Get the priority of the profile. * - *

    The priority can be any of: - * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} + *

    The priority can be any of: {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link + * #PRIORITY_UNDEFINED} * * @param device Bluetooth device * @return priority of the device - * * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public int getPriority(BluetoothDevice device) { if (VDBG) log("getPriority(" + device + ")"); return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); @@ -530,23 +541,21 @@ public final class BluetoothSap implements BluetoothProfile, AutoCloseable { /** * Get the connection policy of the profile. * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} + *

    The connection policy can be any of: {@link #CONNECTION_POLICY_ALLOWED}, {@link + * #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} * * @param device Bluetooth device * @return connection policy of the device - * * @throws NullPointerException if device is null - * * @hide */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); Objects.requireNonNull(device, "BluetoothDevice cannot be null"); diff --git a/framework/java/android/bluetooth/BluetoothServerSocket.java b/framework/java/android/bluetooth/BluetoothServerSocket.java index 55f51feee25226d1970030cbdc76d34cbe5a8091..540df737a6c9161020b1b5a926f79ea18d0abb18 100644 --- a/framework/java/android/bluetooth/BluetoothServerSocket.java +++ b/framework/java/android/bluetooth/BluetoothServerSocket.java @@ -34,18 +34,17 @@ import java.util.concurrent.TimeoutException; /** * A listening Bluetooth socket. * - *

    The interface for Bluetooth Sockets is similar to that of TCP sockets: - * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server - * side, use a {@link BluetoothServerSocket} to create a listening server - * socket. When a connection is accepted by the {@link BluetoothServerSocket}, - * it will return a new {@link BluetoothSocket} to manage the connection. - * On the client side, use a single {@link BluetoothSocket} to both initiate - * an outgoing connection and to manage the connection. + *

    The interface for Bluetooth Sockets is similar to that of TCP sockets: {@link java.net.Socket} + * and {@link java.net.ServerSocket}. On the server side, use a {@link BluetoothServerSocket} to + * create a listening server socket. When a connection is accepted by the {@link + * BluetoothServerSocket}, it will return a new {@link BluetoothSocket} to manage the connection. On + * the client side, use a single {@link BluetoothSocket} to both initiate an outgoing connection and + * to manage the connection. * *

    For Bluetooth BR/EDR, the most common type of socket is RFCOMM, which is the type supported by * the Android APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth BR/EDR. It - * is also known as the Serial Port Profile (SPP). To create a listening - * {@link BluetoothServerSocket} that's ready for incoming Bluetooth BR/EDR connections, use {@link + * is also known as the Serial Port Profile (SPP). To create a listening {@link + * BluetoothServerSocket} that's ready for incoming Bluetooth BR/EDR connections, use {@link * BluetoothAdapter#listenUsingRfcommWithServiceRecord * BluetoothAdapter.listenUsingRfcommWithServiceRecord()}. * @@ -57,34 +56,35 @@ import java.util.concurrent.TimeoutException; * to get the protocol/service multiplexer (PSM) value that the peer needs to use to connect to your * socket. * - *

    After the listening {@link BluetoothServerSocket} is created, call {@link #accept()} to - * listen for incoming connection requests. This call will block until a connection is established, - * at which point, it will return a {@link BluetoothSocket} to manage the connection. Once the - * {@link BluetoothSocket} is acquired, it's a good idea to call {@link #close()} on the {@link - * BluetoothServerSocket} when it's no longer needed for accepting - * connections. Closing the {@link BluetoothServerSocket} will not close the returned - * {@link BluetoothSocket}. + *

    After the listening {@link BluetoothServerSocket} is created, call {@link #accept()} to listen + * for incoming connection requests. This call will block until a connection is established, at + * which point, it will return a {@link BluetoothSocket} to manage the connection. Once the {@link + * BluetoothSocket} is acquired, it's a good idea to call {@link #close()} on the {@link + * BluetoothServerSocket} when it's no longer needed for accepting connections. Closing the {@link + * BluetoothServerSocket} will not close the returned {@link BluetoothSocket}. * - *

    {@link BluetoothServerSocket} is thread - * safe. In particular, {@link #close} will always immediately abort ongoing - * operations and close the server socket. + *

    {@link BluetoothServerSocket} is thread safe. In particular, {@link #close} will always + * immediately abort ongoing operations and close the server socket. + * + *

    * - *
    *

    Developer Guides

    - *

    For more information about using Bluetooth, read the - * Bluetooth developer guide.

    - *
    * - * {@see BluetoothSocket} + *

    For more information about using Bluetooth, read the Bluetooth developer guide.

    + * + * @see BluetoothSocket */ @SuppressLint("AndroidFrameworkBluetoothPermission") public final class BluetoothServerSocket implements Closeable { private static final String TAG = "BluetoothServerSocket"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); - @UnsupportedAppUsage(publicAlternatives = "Use public {@link BluetoothServerSocket} API " - + "instead.") + + @UnsupportedAppUsage( + publicAlternatives = "Use public {@link BluetoothServerSocket} API " + "instead.") /*package*/ final BluetoothSocket mSocket; + private Handler mHandler; private int mMessage; private int mChannel; @@ -102,15 +102,14 @@ public final class BluetoothServerSocket implements Closeable { * @param auth require the remote device to be authenticated * @param encrypt require the connection to be encrypted * @param port remote port - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges + * @throws IOException On error, for example Bluetooth not available, or insufficient privileges */ /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port) throws IOException { mSocketCreationTimeMillis = System.currentTimeMillis(); mType = type; mChannel = port; - mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null); + mSocket = new BluetoothSocket(type, auth, encrypt, null, port, null); if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { mSocket.setExcludeSdp(true); } @@ -126,17 +125,15 @@ public final class BluetoothServerSocket implements Closeable { * @param port remote port * @param mitm enforce person-in-the-middle protection for authentication. * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges + * @throws IOException On error, for example Bluetooth not available, or insufficient privileges */ - /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port, - boolean mitm, boolean min16DigitPin) + /*package*/ BluetoothServerSocket( + int type, boolean auth, boolean encrypt, int port, boolean mitm, boolean min16DigitPin) throws IOException { mSocketCreationTimeMillis = System.currentTimeMillis(); mType = type; mChannel = port; - mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null, mitm, - min16DigitPin); + mSocket = new BluetoothSocket(type, auth, encrypt, null, port, null, mitm, min16DigitPin); if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { mSocket.setExcludeSdp(true); } @@ -150,25 +147,25 @@ public final class BluetoothServerSocket implements Closeable { * @param auth require the remote device to be authenticated * @param encrypt require the connection to be encrypted * @param uuid uuid - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges + * @throws IOException On error, for example Bluetooth not available, or insufficient privileges */ /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid) throws IOException { mSocketCreationTimeMillis = System.currentTimeMillis(); mType = type; - mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, -1, uuid); + mSocket = new BluetoothSocket(type, auth, encrypt, null, -1, uuid); // TODO: This is the same as mChannel = -1 - is this intentional? mChannel = mSocket.getPort(); mSocketCreationLatencyMillis = System.currentTimeMillis() - mSocketCreationTimeMillis; } - /** * Block until a connection is established. + * *

    Returns a connected {@link BluetoothSocket} on successful connection. - *

    Once this call returns, it can be called again to accept subsequent - * incoming connections. + * + *

    Once this call returns, it can be called again to accept subsequent incoming connections. + * *

    {@link #close} can be used to abort this call from another thread. * * @return a connected {@link BluetoothSocket} @@ -180,9 +177,11 @@ public final class BluetoothServerSocket implements Closeable { /** * Block until a connection is established, with timeout. + * *

    Returns a connected {@link BluetoothSocket} on successful connection. - *

    Once this call returns, it can be called again to accept subsequent - * incoming connections. + * + *

    Once this call returns, it can be called again to accept subsequent incoming connections. + * *

    {@link #close} can be used to abort this call from another thread. * * @return a connected {@link BluetoothSocket} @@ -217,11 +216,9 @@ public final class BluetoothServerSocket implements Closeable { if (mType != BluetoothSocket.TYPE_L2CAP_LE) { return; } - IBluetooth bluetoothProxy = - BluetoothAdapter.getDefaultAdapter().getBluetoothService(); + IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); if (bluetoothProxy == null) { - Log.w(TAG, - "bluetoothProxy is null while trying to log l2cap soc server connection"); + Log.w(TAG, "bluetoothProxy is null while trying to log l2cap soc server connection"); return; } try { @@ -242,12 +239,14 @@ public final class BluetoothServerSocket implements Closeable { Log.w(TAG, "logL2capcocServerConnection failed due to remote exception"); } } + /** * Immediately close this socket, and release all associated resources. - *

    Causes blocked calls on this socket in other threads to immediately - * throw an IOException. - *

    Closing the {@link BluetoothServerSocket} will not - * close any {@link BluetoothSocket} received from {@link #accept()}. + * + *

    Causes blocked calls on this socket in other threads to immediately throw an IOException. + * + *

    Closing the {@link BluetoothServerSocket} will not close any {@link + * BluetoothSocket} received from {@link #accept()}. */ public void close() throws IOException { if (DBG) Log.d(TAG, "BluetoothServerSocket:close() called. mChannel=" + mChannel); @@ -292,8 +291,8 @@ public final class BluetoothServerSocket implements Closeable { } /** - * Sets the channel on which future sockets are bound. - * Currently used only when a channel is auto generated. + * Sets the channel on which future sockets are bound. Currently used only when a channel is + * auto generated. */ /*package*/ void setChannel(int newChannel) { /* TODO: From a design/architecture perspective this is wrong. @@ -302,8 +301,12 @@ public final class BluetoothServerSocket implements Closeable { * not set from BluetoothAdapter. */ if (mSocket != null) { if (mSocket.getPort() != newChannel) { - Log.w(TAG, "The port set is different that the underlying port. mSocket.getPort(): " - + mSocket.getPort() + " requested newChannel: " + newChannel); + Log.w( + TAG, + "The port set is different that the underlying port. mSocket.getPort(): " + + mSocket.getPort() + + " requested newChannel: " + + newChannel); } } mChannel = newChannel; @@ -314,22 +317,26 @@ public final class BluetoothServerSocket implements Closeable { StringBuilder sb = new StringBuilder(); sb.append("ServerSocket: Type: "); switch (mSocket.getConnectionType()) { - case BluetoothSocket.TYPE_RFCOMM: { - sb.append("TYPE_RFCOMM"); - break; - } - case BluetoothSocket.TYPE_L2CAP: { - sb.append("TYPE_L2CAP"); - break; - } - case BluetoothSocket.TYPE_L2CAP_LE: { - sb.append("TYPE_L2CAP_LE"); - break; - } - case BluetoothSocket.TYPE_SCO: { - sb.append("TYPE_SCO"); - break; - } + case BluetoothSocket.TYPE_RFCOMM: + { + sb.append("TYPE_RFCOMM"); + break; + } + case BluetoothSocket.TYPE_L2CAP: + { + sb.append("TYPE_L2CAP"); + break; + } + case BluetoothSocket.TYPE_L2CAP_LE: + { + sb.append("TYPE_L2CAP_LE"); + break; + } + case BluetoothSocket.TYPE_SCO: + { + sb.append("TYPE_SCO"); + break; + } } sb.append(" Channel: ").append(mChannel); return sb.toString(); diff --git a/framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java b/framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java index db44bc2e532d041579e1e255a3c512452997c323..5a11a7fbe5f6a7d285bf9128ca369674fb7d6051 100644 --- a/framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java +++ b/framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java @@ -28,87 +28,80 @@ import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** - * Represents Bluetooth Audio Policies of a Handsfree (HF) device (if HFP is used) - * and Call Terminal (CT) device (if BLE Audio is used), which describes the - * preferences of allowing or disallowing audio based on the use cases. The HF/CT - * devices shall send objects of this class to send its preference to the AG/CG - * devices. + * Represents Bluetooth Audio Policies of a Handsfree (HF) device (if HFP is used) and Call Terminal + * (CT) device (if BLE Audio is used), which describes the preferences of allowing or disallowing + * audio based on the use cases. The HF/CT devices shall send objects of this class to send its + * preference to the AG/CG devices. * - *

    HF/CT side applications on can use {@link BluetoothDevice#requestAudioPolicyAsSink} - * API to set and send a {@link BluetoothSinkAudioPolicy} object containing the - * preference/policy values. This object will be stored in the memory of HF/CT - * side, will be send to the AG/CG side using Android Specific AT Commands and will - * be stored in the AG side memory and database. + *

    HF/CT side applications on can use {@link BluetoothDevice#requestAudioPolicyAsSink} API to set + * and send a {@link BluetoothSinkAudioPolicy} object containing the preference/policy values. This + * object will be stored in the memory of HF/CT side, will be send to the AG/CG side using Android + * Specific AT Commands and will be stored in the AG side memory and database. * *

    HF/CT side API {@link BluetoothDevice#getRequestedAudioPolicyAsSink} can be used to retrieve * the stored audio policies currently. * - *

    Note that the setter APIs of this class will only set the values of the - * object. To actually set the policies, API {@link BluetoothDevice#requestAudioPolicyAsSink} - * must need to be invoked with the {@link BluetoothSinkAudioPolicy} object. - * - *

    Note that any API related to this feature should be used after configuring - * the support of the AG device and after checking whether the AG device supports - * this feature or not by invoking {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported}. - * Only after getting a {@link BluetoothStatusCodes#FEATURE_SUPPORTED} response - * from the API should the APIs related to this feature be used. + *

    Note that the setter APIs of this class will only set the values of the object. To actually + * set the policies, API {@link BluetoothDevice#requestAudioPolicyAsSink} must need to be invoked + * with the {@link BluetoothSinkAudioPolicy} object. * + *

    Note that any API related to this feature should be used after configuring the support of the + * AG device and after checking whether the AG device supports this feature or not by invoking + * {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported}. Only after getting a {@link + * BluetoothStatusCodes#FEATURE_SUPPORTED} response from the API should the APIs related to this + * feature be used. * * @hide */ @SystemApi public final class BluetoothSinkAudioPolicy implements Parcelable { - /** - * @hide - */ + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( - prefix = {"POLICY_"}, - value = { - POLICY_UNCONFIGURED, - POLICY_ALLOWED, - POLICY_NOT_ALLOWED, - } - ) - public @interface AudioPolicyValues{} + prefix = {"POLICY_"}, + value = { + POLICY_UNCONFIGURED, + POLICY_ALLOWED, + POLICY_NOT_ALLOWED, + }) + public @interface AudioPolicyValues {} /** * Audio behavior not configured for the policy. * - * If a policy is set with this value, it means that the policy is not - * configured with a value yet and should not be used to make any decision. + *

    If a policy is set with this value, it means that the policy is not configured with a + * value yet and should not be used to make any decision. + * * @hide */ - @SystemApi - public static final int POLICY_UNCONFIGURED = 0; + @SystemApi public static final int POLICY_UNCONFIGURED = 0; /** * Audio is preferred by HF device for the policy. * - * If a policy is set with this value, then the HF device will prefer the - * audio for the policy use case. For example, if the Call Establish audio - * policy is set with this value, then the HF will prefer the audio - * during making or picking up a call. + *

    If a policy is set with this value, then the HF device will prefer the audio for the + * policy use case. For example, if the Call Establish audio policy is set with this value, then + * the HF will prefer the audio during making or picking up a call. + * * @hide */ - @SystemApi - public static final int POLICY_ALLOWED = 1; + @SystemApi public static final int POLICY_ALLOWED = 1; /** * Audio is not preferred by HF device for the policy. * - * If a policy is set with this value, then the HF device will not prefer the - * audio for the policy use case. For example, if the Call Establish audio - * policy is set with this value, then the HF will not prefer the audio - * during making or picking up a call. + *

    If a policy is set with this value, then the HF device will not prefer the audio for the + * policy use case. For example, if the Call Establish audio policy is set with this value, then + * the HF will not prefer the audio during making or picking up a call. + * * @hide */ - @SystemApi - public static final int POLICY_NOT_ALLOWED = 2; + @SystemApi public static final int POLICY_NOT_ALLOWED = 2; /** * The feature ID used in the HFP AT command. + * * @hide */ public static final String HFP_SET_SINK_AUDIO_POLICY_ID = "SINKAUDIOPOLICY"; @@ -117,11 +110,9 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { @AudioPolicyValues private final int mConnectingTimePolicy; @AudioPolicyValues private final int mInBandRingtonePolicy; - /** - * @hide - */ - public BluetoothSinkAudioPolicy(int callEstablishPolicy, - int connectingTimePolicy, int inBandRingtonePolicy) { + /** @hide */ + public BluetoothSinkAudioPolicy( + int callEstablishPolicy, int connectingTimePolicy, int inBandRingtonePolicy) { mCallEstablishPolicy = callEstablishPolicy; mConnectingTimePolicy = connectingTimePolicy; mInBandRingtonePolicy = inBandRingtonePolicy; @@ -129,12 +120,11 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { /** * Get Call establishment policy audio policy. - *

    This policy is used to determine the audio preference when the - * HF device makes or answers a call. That is, if this device - * makes or answers a call, is the audio preferred by HF. * - * @return the call pick up audio policy value + *

    This policy is used to determine the audio preference when the HF device makes or answers + * a call. That is, if this device makes or answers a call, is the audio preferred by HF. * + * @return the call pick up audio policy value * @hide */ @SystemApi @@ -144,15 +134,14 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { /** * Get during connection audio up policy. - *

    This policy is used to determine the audio preference when the - * HF device connects with the AG device. That is, when the - * HF device gets connected, should the HF become active and get audio - * is decided by this policy. This also covers the case of during a call. - * If the HF connects with the AG during an ongoing call, should the call - * audio be routed to the HF will be decided by this policy. * - * @return the during connection audio policy value + *

    This policy is used to determine the audio preference when the HF device connects with the + * AG device. That is, when the HF device gets connected, should the HF become active and get + * audio is decided by this policy. This also covers the case of during a call. If the HF + * connects with the AG during an ongoing call, should the call audio be routed to the HF will + * be decided by this policy. * + * @return the during connection audio policy value * @hide */ @SystemApi @@ -162,12 +151,12 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { /** * Get In band ringtone audio up policy. - *

    This policy is used to determine the audio preference of the - * in band ringtone. That is, if there is an incoming call, should the - * inband ringtone audio be routed to the HF will be decided by this policy. * - * @return the in band ringtone audio policy value + *

    This policy is used to determine the audio preference of the in band ringtone. That is, if + * there is an incoming call, should the inband ringtone audio be routed to the HF will be + * decided by this policy. * + * @return the in band ringtone audio policy value * @hide */ @SystemApi @@ -188,22 +177,21 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { return builder.toString(); } - /** - * {@link Parcelable.Creator} interface implementation. - */ + /** {@link Parcelable.Creator} interface implementation. */ public static final @android.annotation.NonNull Parcelable.Creator - CREATOR = new Parcelable.Creator() { - @Override - public BluetoothSinkAudioPolicy createFromParcel(@NonNull Parcel in) { - return new BluetoothSinkAudioPolicy( - in.readInt(), in.readInt(), in.readInt()); - } + CREATOR = + new Parcelable.Creator() { + @Override + public BluetoothSinkAudioPolicy createFromParcel(@NonNull Parcel in) { + return new BluetoothSinkAudioPolicy( + in.readInt(), in.readInt(), in.readInt()); + } - @Override - public BluetoothSinkAudioPolicy[] newArray(int size) { - return new BluetoothSinkAudioPolicy[size]; - } - }; + @Override + public BluetoothSinkAudioPolicy[] newArray(int size) { + return new BluetoothSinkAudioPolicy[size]; + } + }; @Override public void writeToParcel(@NonNull Parcel out, int flags) { @@ -212,9 +200,7 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { out.writeInt(mInBandRingtonePolicy); } - /** - * @hide - */ + /** @hide */ @Override public int describeContents() { return 0; @@ -232,8 +218,7 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { } /** - * Returns a hash representation of this BluetoothCodecConfig - * based on all the config values. + * Returns a hash representation of this BluetoothCodecConfig based on all the config values. * * @hide */ @@ -244,17 +229,16 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { /** * Builder for {@link BluetoothSinkAudioPolicy}. - *

    By default, the audio policy values will be set to - * {@link BluetoothSinkAudioPolicy#POLICY_UNCONFIGURED}. + * + *

    By default, the audio policy values will be set to {@link + * BluetoothSinkAudioPolicy#POLICY_UNCONFIGURED}. */ public static final class Builder { private int mCallEstablishPolicy = POLICY_UNCONFIGURED; private int mConnectingTimePolicy = POLICY_UNCONFIGURED; private int mInBandRingtonePolicy = POLICY_UNCONFIGURED; - public Builder() { - - } + public Builder() {} public Builder(@NonNull BluetoothSinkAudioPolicy policies) { mCallEstablishPolicy = policies.mCallEstablishPolicy; @@ -264,42 +248,44 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { /** * Set Call Establish (pick up and answer) policy. - *

    This policy is used to determine the audio preference when the - * HF device makes or answers a call. That is, if this device - * makes or answers a call, is the audio preferred by HF. - *

    If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, answering or making - * a call from the HF device will route the call audio to it. - * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, answering or making - * a call from the HF device will NOT route the call audio to it. * - * @return reference to the current object + *

    This policy is used to determine the audio preference when the HF device makes or + * answers a call. That is, if this device makes or answers a call, is the audio preferred + * by HF. + * + *

    If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, answering or making a call + * from the HF device will route the call audio to it. If set to {@link + * BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, answering or making a call from the HF + * device will NOT route the call audio to it. * + * @return reference to the current object * @hide */ - @SystemApi public @NonNull Builder setCallEstablishPolicy( - @AudioPolicyValues int callEstablishPolicy) { + @SystemApi + public @NonNull Builder setCallEstablishPolicy(@AudioPolicyValues int callEstablishPolicy) { mCallEstablishPolicy = callEstablishPolicy; return this; } /** * Set during connection audio up policy. - *

    This policy is used to determine the audio preference when the - * HF device connects with the AG device. That is, when the - * HF device gets connected, should the HF become active and get audio - * is decided by this policy. This also covers the case of during a call. - * If the HF connects with the AG during an ongoing call, should the call - * audio be routed to the HF will be decided by this policy. - *

    If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, connecting HF - * during a call will route the call audio to it. - * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, connecting HF - * during a call will NOT route the call audio to it. * - * @return reference to the current object + *

    This policy is used to determine the audio preference when the HF device connects with + * the AG device. That is, when the HF device gets connected, should the HF become active + * and get audio is decided by this policy. This also covers the case of during a call. If + * the HF connects with the AG during an ongoing call, should the call audio be routed to + * the HF will be decided by this policy. + * + *

    If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, connecting HF during a call + * will route the call audio to it. If set to {@link + * BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, connecting HF during a call will NOT route + * the call audio to it. * + * @return reference to the current object * @hide */ - @SystemApi public @NonNull Builder setActiveDevicePolicyAfterConnection( + @SystemApi + public @NonNull Builder setActiveDevicePolicyAfterConnection( @AudioPolicyValues int connectingTimePolicy) { mConnectingTimePolicy = connectingTimePolicy; return this; @@ -307,19 +293,21 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { /** * Set In band ringtone audio up policy. - *

    This policy is used to determine the audio preference of the - * in band ringtone. That is, if there is an incoming call, should the - * inband ringtone audio be routed to the HF will be decided by this policy. - *

    If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, there will be - * in band ringtone in the HF device during an incoming call. - * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, there will NOT - * be in band ringtone in the HF device during an incoming call. * - * @return reference to the current object + *

    This policy is used to determine the audio preference of the in band ringtone. That + * is, if there is an incoming call, should the inband ringtone audio be routed to the HF + * will be decided by this policy. * + *

    If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, there will be in band + * ringtone in the HF device during an incoming call. If set to {@link + * BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, there will NOT be in band ringtone in the + * HF device during an incoming call. + * + * @return reference to the current object * @hide */ - @SystemApi public @NonNull Builder setInBandRingtonePolicy( + @SystemApi + public @NonNull Builder setInBandRingtonePolicy( @AudioPolicyValues int inBandRingtonePolicy) { mInBandRingtonePolicy = inBandRingtonePolicy; return this; @@ -327,11 +315,12 @@ public final class BluetoothSinkAudioPolicy implements Parcelable { /** * Build {@link BluetoothSinkAudioPolicy}. - * @return new BluetoothSinkAudioPolicy object * + * @return new BluetoothSinkAudioPolicy object * @hide */ - @SystemApi public @NonNull BluetoothSinkAudioPolicy build() { + @SystemApi + public @NonNull BluetoothSinkAudioPolicy build() { return new BluetoothSinkAudioPolicy( mCallEstablishPolicy, mConnectingTimePolicy, mInBandRingtonePolicy); } diff --git a/framework/java/android/bluetooth/BluetoothSocket.java b/framework/java/android/bluetooth/BluetoothSocket.java index 7b197ce99976007108633846ed6edce8b62e33d7..6527056433952999887efc961cf08c0d0a427d10 100644 --- a/framework/java/android/bluetooth/BluetoothSocket.java +++ b/framework/java/android/bluetooth/BluetoothSocket.java @@ -46,47 +46,44 @@ import java.util.concurrent.TimeoutException; /** * A connected or connecting Bluetooth socket. * - *

    The interface for Bluetooth Sockets is similar to that of TCP sockets: - * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server - * side, use a {@link BluetoothServerSocket} to create a listening server - * socket. When a connection is accepted by the {@link BluetoothServerSocket}, - * it will return a new {@link BluetoothSocket} to manage the connection. - * On the client side, use a single {@link BluetoothSocket} to both initiate - * an outgoing connection and to manage the connection. + *

    The interface for Bluetooth Sockets is similar to that of TCP sockets: {@link java.net.Socket} + * and {@link java.net.ServerSocket}. On the server side, use a {@link BluetoothServerSocket} to + * create a listening server socket. When a connection is accepted by the {@link + * BluetoothServerSocket}, it will return a new {@link BluetoothSocket} to manage the connection. On + * the client side, use a single {@link BluetoothSocket} to both initiate an outgoing connection and + * to manage the connection. * - *

    The most common type of Bluetooth socket is RFCOMM, which is the type - * supported by the Android APIs. RFCOMM is a connection-oriented, streaming - * transport over Bluetooth. It is also known as the Serial Port Profile (SPP). + *

    The most common type of Bluetooth socket is RFCOMM, which is the type supported by the Android + * APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth. It is also known as + * the Serial Port Profile (SPP). * - *

    To create a {@link BluetoothSocket} for connecting to a known device, use - * {@link BluetoothDevice#createRfcommSocketToServiceRecord - * BluetoothDevice.createRfcommSocketToServiceRecord()}. - * Then call {@link #connect()} to attempt a connection to the remote device. - * This call will block until a connection is established or the connection - * fails. + *

    To create a {@link BluetoothSocket} for connecting to a known device, use {@link + * BluetoothDevice#createRfcommSocketToServiceRecord + * BluetoothDevice.createRfcommSocketToServiceRecord()}. Then call {@link #connect()} to attempt a + * connection to the remote device. This call will block until a connection is established or the + * connection fails. * - *

    To create a {@link BluetoothSocket} as a server (or "host"), see the - * {@link BluetoothServerSocket} documentation. + *

    To create a {@link BluetoothSocket} as a server (or "host"), see the {@link + * BluetoothServerSocket} documentation. * - *

    Once the socket is connected, whether initiated as a client or accepted - * as a server, open the IO streams by calling {@link #getInputStream} and - * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream} - * and {@link java.io.OutputStream} objects, respectively, which are + *

    Once the socket is connected, whether initiated as a client or accepted as a server, open the + * IO streams by calling {@link #getInputStream} and {@link #getOutputStream} in order to retrieve + * {@link java.io.InputStream} and {@link java.io.OutputStream} objects, respectively, which are * automatically connected to the socket. * - *

    {@link BluetoothSocket} is thread - * safe. In particular, {@link #close} will always immediately abort ongoing - * operations and close the socket. + *

    {@link BluetoothSocket} is thread safe. In particular, {@link #close} will always immediately + * abort ongoing operations and close the socket. + * + *

    * - *
    *

    Developer Guides

    - *

    For more information about using Bluetooth, read the - * Bluetooth developer guide.

    - *
    * - * {@see BluetoothServerSocket} - * {@see java.io.InputStream} - * {@see java.io.OutputStream} + *

    For more information about using Bluetooth, read the Bluetooth developer guide.

    + * + * @see BluetoothServerSocket + * @see java.io.InputStream + * @see java.io.OutputStream */ public final class BluetoothSocket implements Closeable { private static final String TAG = "BluetoothSocket"; @@ -95,6 +92,7 @@ public final class BluetoothSocket implements Closeable { /** @hide */ public static final int MAX_RFCOMM_CHANNEL = 30; + /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF; /** RFCOMM socket */ @@ -106,17 +104,22 @@ public final class BluetoothSocket implements Closeable { /** L2CAP socket */ public static final int TYPE_L2CAP = 3; - /** L2CAP socket on BR/EDR transport + /** + * L2CAP socket on BR/EDR transport + * * @hide */ public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP; - /** L2CAP socket on LE transport + /** + * L2CAP socket on LE transport + * * @hide */ public static final int TYPE_L2CAP_LE = 4; /*package*/ static final int EBADFD = 77; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) /*package*/ static final int EADDRINUSE = 98; @@ -127,7 +130,6 @@ public final class BluetoothSocket implements Closeable { /*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4; // Defined in BluetoothProtoEnums.L2capCocConnectionResult of proto logging - private static final int RESULT_L2CAP_CONN_UNKNOWN = 0; /*package*/ static final int RESULT_L2CAP_CONN_SUCCESS = 1; private static final int RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_FAILED = 1000; private static final int RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED = 1001; @@ -137,31 +139,32 @@ public final class BluetoothSocket implements Closeable { private static final int RESULT_L2CAP_CONN_BLUETOOTH_NULL_FILE_DESCRIPTOR = 1005; /*package*/ static final int RESULT_L2CAP_CONN_SERVER_FAILURE = 2000; - private final int mType; /* one of TYPE_RFCOMM etc */ - private BluetoothDevice mDevice; /* remote device */ - private String mAddress; /* remote address */ + private final int mType; /* one of TYPE_RFCOMM etc */ + private BluetoothDevice mDevice; /* remote device */ + private String mAddress; /* remote address */ private final boolean mAuth; private final boolean mEncrypt; private final BluetoothInputStream mInputStream; private final BluetoothOutputStream mOutputStream; private final ParcelUuid mUuid; + /** when true no SPP SDP record will be created */ private boolean mExcludeSdp = false; + /** when true Person-in-the-middle protection will be enabled */ private boolean mAuthMitm = false; + /** Minimum 16 digit pin for sec mode 2 connections */ private boolean mMin16DigitPin = false; + @UnsupportedAppUsage(publicAlternatives = "Use {@link BluetoothSocket} public API instead.") private ParcelFileDescriptor mPfd; - @UnsupportedAppUsage - private LocalSocket mSocket; + + @UnsupportedAppUsage private LocalSocket mSocket; private InputStream mSocketIS; private OutputStream mSocketOS; - @UnsupportedAppUsage - private int mPort; /* RFCOMM channel or L2CAP psm */ - private int mFd; + @UnsupportedAppUsage private int mPort; /* RFCOMM channel or L2CAP psm */ private String mServiceName; - private static final int PROXY_CONNECTION_TIMEOUT = 5000; private static final int SOCK_SIGNAL_SIZE = 20; @@ -183,31 +186,34 @@ public final class BluetoothSocket implements Closeable { private volatile SocketState mSocketState; /** protects mSocketState */ - //private final ReentrantReadWriteLock mLock; + // private final ReentrantReadWriteLock mLock; /** * Construct a BluetoothSocket. * * @param type type of socket - * @param fd fd to use for connected socket, or -1 for a new socket * @param auth require the remote device to be authenticated * @param encrypt require the connection to be encrypted * @param device remote device that this socket can connect to * @param port remote port * @param uuid SDP uuid - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges + * @throws IOException On error, for example Bluetooth not available, or insufficient privileges */ - /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, - BluetoothDevice device, int port, ParcelUuid uuid) throws IOException { - this(type, fd, auth, encrypt, device, port, uuid, false, false); + /*package*/ BluetoothSocket( + int type, + boolean auth, + boolean encrypt, + BluetoothDevice device, + int port, + ParcelUuid uuid) + throws IOException { + this(type, auth, encrypt, device, port, uuid, false, false); } /** * Construct a BluetoothSocket. * * @param type type of socket - * @param fd fd to use for connected socket, or -1 for a new socket * @param auth require the remote device to be authenticated * @param encrypt require the connection to be encrypted * @param device remote device that this socket can connect to @@ -215,15 +221,22 @@ public final class BluetoothSocket implements Closeable { * @param uuid SDP uuid * @param mitm enforce person-in-the-middle protection. * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges + * @throws IOException On error, for example Bluetooth not available, or insufficient privileges */ - /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, - BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin) + /*package*/ BluetoothSocket( + int type, + boolean auth, + boolean encrypt, + BluetoothDevice device, + int port, + ParcelUuid uuid, + boolean mitm, + boolean min16DigitPin) throws IOException { if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type); mSocketCreationTimeMillis = System.currentTimeMillis(); - if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1 + if (type == BluetoothSocket.TYPE_RFCOMM + && uuid == null && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { if (port < 1 || port > MAX_RFCOMM_CHANNEL) { throw new IOException("Invalid RFCOMM channel: " + port); @@ -241,7 +254,6 @@ public final class BluetoothSocket implements Closeable { mEncrypt = encrypt; mDevice = device; mPort = port; - mFd = fd; mSocketState = SocketState.INIT; @@ -261,8 +273,8 @@ public final class BluetoothSocket implements Closeable { * Creates a BluetoothSocket from a {@link ParcelFileDescriptor}. This is used for when the * underlying mPfd is transferred to a separate process (e.g. over a binder), and the socket * must be reconstructed. - *

    - * The socket should already be connected in this case, so {@link #connect()} should not be + * + *

    The socket should already be connected in this case, so {@link #connect()} should not be * called. * * @param pfd is the {@link ParcelFileDescriptor} for an already connected BluetoothSocket @@ -273,7 +285,7 @@ public final class BluetoothSocket implements Closeable { /*package*/ static BluetoothSocket createSocketFromOpenFd( ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid) throws IOException { BluetoothSocket bluetoothSocket = - new BluetoothSocket(TYPE_RFCOMM, pfd.getFd(), true, true, device, -1, uuid); + new BluetoothSocket(TYPE_RFCOMM, true, true, device, -1, uuid); bluetoothSocket.mPfd = pfd; bluetoothSocket.mSocket = new LocalSocket(pfd.getFileDescriptor()); @@ -312,7 +324,7 @@ public final class BluetoothSocket implements Closeable { if (fds == null || fds.length != 1) { Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds)); as.close(); - throw new IOException("bt socket acept failed"); + throw new IOException("bt socket accept failed"); } as.mPfd = ParcelFileDescriptor.dup(fds[0]); @@ -324,25 +336,9 @@ public final class BluetoothSocket implements Closeable { return as; } - /** - * Construct a BluetoothSocket from address. Used by native code. - * - * @param type type of socket - * @param fd fd to use for connected socket, or -1 for a new socket - * @param auth require the remote device to be authenticated - * @param encrypt require the connection to be encrypted - * @param address remote device that this socket can connect to - * @param port remote port - * @throws IOException On error, for example Bluetooth not available, or insufficient - * privileges - */ - private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, - int port) throws IOException { - this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null, false, false); - } - /** @hide */ @Override + @SuppressWarnings("Finalize") // TODO(b/314811467) protected void finalize() throws Throwable { try { close(); @@ -383,9 +379,9 @@ public final class BluetoothSocket implements Closeable { /** * Get the input stream associated with this socket. - *

    The input stream will be returned even if the socket is not yet - * connected, but operations on that stream will throw IOException until - * the associated socket is connected. + * + *

    The input stream will be returned even if the socket is not yet connected, but operations + * on that stream will throw IOException until the associated socket is connected. * * @return InputStream */ @@ -396,9 +392,9 @@ public final class BluetoothSocket implements Closeable { /** * Get the output stream associated with this socket. - *

    The output stream will be returned even if the socket is not yet - * connected, but operations on that stream will throw IOException until - * the associated socket is connected. + * + *

    The output stream will be returned even if the socket is not yet connected, but operations + * on that stream will throw IOException until the associated socket is connected. * * @return OutputStream */ @@ -425,28 +421,30 @@ public final class BluetoothSocket implements Closeable { /*package*/ boolean isAuth() { return mAuth; } + /** * Attempt to connect to a remote device. + * *

    This method will block until a connection is made or the connection fails. If this method * returns without an exception then this socket is now connected. + * *

    Creating new connections to remote Bluetooth devices should not be attempted while device * discovery is in progress. Device discovery is a heavyweight procedure on the Bluetooth - * adapter and will significantly slow a device connection. Use - * {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing discovery. Discovery is not - * managed by the Activity, but is run as a system service, so an application should always call - * {@link BluetoothAdapter#cancelDiscovery()} even if it did not directly request a discovery, - * just to be sure. + * adapter and will significantly slow a device connection. Use {@link + * BluetoothAdapter#cancelDiscovery()} to cancel an ongoing discovery. Discovery is not managed + * by the Activity, but is run as a system service, so an application should always call {@link + * BluetoothAdapter#cancelDiscovery()} even if it did not directly request a discovery, just to + * be sure. + * *

    {@link #close} can be used to abort this call from another thread. * - * @throws BluetoothSocketException in case of failure, with the corresponding - * {@link BluetoothSocketException#ErrorCode}. + * @throws BluetoothSocketException in case of failure, with the corresponding error code. * @throws IOException for other errors (eg: InputStream read failures etc.). */ @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void connect() throws IOException { - IBluetooth bluetoothProxy = - BluetoothAdapter.getDefaultAdapter().getBluetoothService(); + IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); long socketConnectionTimeMillis = System.currentTimeMillis(); if (bluetoothProxy == null) { throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE); @@ -526,23 +524,22 @@ public final class BluetoothSocket implements Closeable { mSocketState = SocketState.CONNECTED; if (DBG) Log.d(TAG, "connect(), socket connected"); } - logL2capcocClientConnection(bluetoothProxy, - RESULT_L2CAP_CONN_SUCCESS, - socketConnectionTimeMillis); + logL2capcocClientConnection( + bluetoothProxy, RESULT_L2CAP_CONN_SUCCESS, socketConnectionTimeMillis); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); logL2capcocClientConnection( bluetoothProxy, RESULT_L2CAP_CONN_BLUETOOTH_UNABLE_TO_SEND_RPC, socketConnectionTimeMillis); - throw new BluetoothSocketException(BluetoothSocketException.RPC_FAILURE, - "unable to send RPC: " + e.getMessage()); + throw new BluetoothSocketException( + BluetoothSocketException.RPC_FAILURE, "unable to send RPC: " + e.getMessage()); } } /** - * Currently returns unix errno instead of throwing IOException, - * so that BluetoothAdapter can check the error code for EADDRINUSE + * Currently returns unix errno instead of throwing IOException, so that BluetoothAdapter can + * check the error code for EADDRINUSE */ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) /*package*/ int bindListen() { @@ -560,8 +557,9 @@ public final class BluetoothSocket implements Closeable { Log.e(TAG, "bindListen() bt get socket manager failed"); return -1; } - mPfd = socketManager - .createSocketChannel(mType, mServiceName, mUuid, mPort, getSecurityFlags()); + mPfd = + socketManager.createSocketChannel( + mType, mServiceName, mUuid, mPort, getSecurityFlags()); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); return -1; @@ -632,7 +630,7 @@ public final class BluetoothSocket implements Closeable { throw new IOException("bt socket is not in listen state"); } acceptedSocket = acceptSocket(RemoteAddr); - //quick drop the reference of the file handle + // quick drop the reference of the file handle } return acceptedSocket; } @@ -648,8 +646,14 @@ public final class BluetoothSocket implements Closeable { if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { int bytesToRead = length; if (VDBG) { - Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length - + "mL2capBuffer= " + mL2capBuffer); + Log.v( + TAG, + "l2cap: read(): offset: " + + offset + + " length:" + + length + + "mL2capBuffer= " + + mL2capBuffer); } if (mL2capBuffer == null) { createL2capRxBuffer(); @@ -664,8 +668,7 @@ public final class BluetoothSocket implements Closeable { bytesToRead = mL2capBuffer.remaining(); } if (VDBG) { - Log.v(TAG, "get(): offset: " + offset - + " bytesToRead: " + bytesToRead); + Log.v(TAG, "get(): offset: " + offset + " bytesToRead: " + bytesToRead); } mL2capBuffer.get(b, offset, bytesToRead); ret = bytesToRead; @@ -682,7 +685,7 @@ public final class BluetoothSocket implements Closeable { /*package*/ int write(byte[] b, int offset, int length) throws IOException { - //TODO: Since bindings can exist between the SDU size and the + // TODO: Since bindings can exist between the SDU size and the // protocol, we might need to throw an exception instead of just // splitting the write into multiple smaller writes. // Rfcomm uses dynamic allocation, and should not have any bindings @@ -693,16 +696,17 @@ public final class BluetoothSocket implements Closeable { mSocketOS.write(b, offset, length); } else { if (DBG) { - Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n" - + "Packet will be divided into SDU packets of size " - + mMaxTxPacketSize); + Log.w( + TAG, + "WARNING: Write buffer larger than L2CAP packet size!\n" + + "Packet will be divided into SDU packets of size " + + mMaxTxPacketSize); } int tmpOffset = offset; int bytesToWrite = length; while (bytesToWrite > 0) { - int tmpLength = (bytesToWrite > mMaxTxPacketSize) - ? mMaxTxPacketSize - : bytesToWrite; + int tmpLength = + (bytesToWrite > mMaxTxPacketSize) ? mMaxTxPacketSize : bytesToWrite; mSocketOS.write(b, tmpOffset, tmpLength); tmpOffset += tmpLength; bytesToWrite -= tmpLength; @@ -718,9 +722,20 @@ public final class BluetoothSocket implements Closeable { @Override public void close() throws IOException { - Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS - + ", mSocketOS: " + mSocketOS + ", mSocket: " + mSocket + ", mSocketState: " - + mSocketState); + Log.d( + TAG, + "close() this: " + + this + + ", channel: " + + mPort + + ", mSocketIS: " + + mSocketIS + + ", mSocketOS: " + + mSocketOS + + ", mSocket: " + + mSocket + + ", mSocketState: " + + mSocketState); if (mSocketState == SocketState.CLOSED) { return; } else { @@ -766,8 +781,7 @@ public final class BluetoothSocket implements Closeable { } } - /*package */ void removeChannel() { - } + /*package */ void removeChannel() {} /*package */ int getPort() { return mPort; @@ -778,9 +792,8 @@ public final class BluetoothSocket implements Closeable { } /** - * Get the maximum supported Transmit packet size for the underlying transport. - * Use this to optimize the writes done to the output socket, to avoid sending - * half full packets. + * Get the maximum supported Transmit packet size for the underlying transport. Use this to + * optimize the writes done to the output socket, to avoid sending half full packets. * * @return the maximum supported Transmit packet size for the underlying transport. */ @@ -790,10 +803,9 @@ public final class BluetoothSocket implements Closeable { } /** - * Get the maximum supported Receive packet size for the underlying transport. - * Use this to optimize the reads done on the input stream, as any call to read - * will return a maximum of this amount of bytes - or for some transports a - * multiple of this value. + * Get the maximum supported Receive packet size for the underlying transport. Use this to + * optimize the reads done on the input stream, as any call to read will return a maximum of + * this amount of bytes - or for some transports a multiple of this value. * * @return the maximum supported Receive packet size for the underlying transport. */ @@ -817,11 +829,12 @@ public final class BluetoothSocket implements Closeable { } /** - * Change if a SDP entry should be automatically created. - * Must be called before calling .bind, for the call to have any effect. + * Change if a SDP entry should be automatically created. Must be called before calling .bind, + * for the call to have any effect. * - * @param excludeSdp

  • TRUE - do not auto generate SDP record.
  • FALSE - default - auto - * generate SPP SDP record. + * @param excludeSdp + *
  • TRUE - do not auto generate SDP record. + *
  • FALSE - default - auto generate SPP SDP record. * @hide */ @RequiresNoPermission @@ -833,6 +846,7 @@ public final class BluetoothSocket implements Closeable { * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This * parameter is used by the BT Controller to set the maximum transmission packet size on this * connection. This function is currently used for testing only. + * * @hide */ @RequiresBluetoothConnectPermission @@ -846,8 +860,7 @@ public final class BluetoothSocket implements Closeable { if (mSocketState == SocketState.CLOSED) { throw new IOException("socket closed"); } - IBluetooth bluetoothProxy = - BluetoothAdapter.getDefaultAdapter().getBluetoothService(); + IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); if (bluetoothProxy == null) { throw new IOException("Bluetooth is off"); } @@ -868,8 +881,15 @@ public final class BluetoothSocket implements Closeable { } private String convertAddr(final byte[] addr) { - return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + return String.format( + Locale.US, + "%02X:%02X:%02X:%02X:%02X:%02X", + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5]); } private String waitSocketSignal(InputStream is) throws IOException { @@ -893,9 +913,20 @@ public final class BluetoothSocket implements Closeable { mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value String RemoteAddr = convertAddr(addr); if (VDBG) { - Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: " - + RemoteAddr + ", channel: " + channel + ", status: " + status - + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize); + Log.d( + TAG, + "waitSocketSignal: sig size: " + + size + + ", remote addr: " + + RemoteAddr + + ", channel: " + + channel + + ", status: " + + status + + " MaxRxPktSize: " + + mMaxRxPacketSize + + " MaxTxPktSize: " + + mMaxTxPacketSize); } if (status != 0) { throw new IOException("Connection failure, status: " + status); @@ -921,13 +952,17 @@ public final class BluetoothSocket implements Closeable { while (left > 0) { int ret = is.read(b, b.length - left, left); if (ret <= 0) { - throw new IOException("read failed, socket might closed or timeout, read ret: " - + ret); + throw new IOException( + "read failed, socket might closed or timeout, read ret: " + ret); } left -= ret; if (left != 0) { - Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) - + ", expect size: " + b.length); + Log.w( + TAG, + "readAll() looping, read partial size: " + + (b.length - left) + + ", expect size: " + + b.length); } } return b.length; diff --git a/framework/java/android/bluetooth/BluetoothSocketException.java b/framework/java/android/bluetooth/BluetoothSocketException.java index 48d47e34dfaba0cc0681d82ec2c4623d6a40d1ae..75c21588c1b28879dffc1a843522f24a87a45f11 100644 --- a/framework/java/android/bluetooth/BluetoothSocketException.java +++ b/framework/java/android/bluetooth/BluetoothSocketException.java @@ -27,8 +27,8 @@ import java.lang.annotation.Retention; /** * Thrown when an error occurs during a Bluetooth Socket related exception. * - *

    This is currently only intended to be thrown for a failure during - * {@link BluetoothSocket#connect()} operation. + *

    This is currently only intended to be thrown for a failure during {@link + * BluetoothSocket#connect()} operation. */ public class BluetoothSocketException extends IOException { @@ -54,8 +54,9 @@ public class BluetoothSocketException extends IOException { SOCKET_CLOSED, SOCKET_CONNECTION_FAILURE, NULL_DEVICE, - RPC_FAILURE}) - private @interface ErrorCode {} + RPC_FAILURE + }) + private @interface ErrorCode {} /** * Error code representing a failure during {@link BluetoothSocket}. The reason for failure @@ -64,115 +65,93 @@ public class BluetoothSocketException extends IOException { public static final int UNSPECIFIED = 0; /** - * Error code during connect when socket connection fails for unknown reason - * during L2CAP connection. + * Error code during connect when socket connection fails for unknown reason during L2CAP + * connection. */ public static final int L2CAP_UNKNOWN = 1; - /** - * Error code during connect when there is an ACL connection failure. - */ + /** Error code during connect when there is an ACL connection failure. */ public static final int L2CAP_ACL_FAILURE = 2; /** - * Error code during connect when security clearance fails on the client during - * L2CAP connection. + * Error code during connect when security clearance fails on the client during L2CAP + * connection. */ public static final int L2CAP_CLIENT_SECURITY_FAILURE = 3; /** - * Error code during connect when authentication fails on the peer device - * during L2CAP connection. + * Error code during connect when authentication fails on the peer device during L2CAP + * connection. */ public static final int L2CAP_INSUFFICIENT_AUTHENTICATION = 4; /** - * Error code during connect when authorization fails on the peer device during - * L2CAP connection. + * Error code during connect when authorization fails on the peer device during L2CAP + * connection. */ public static final int L2CAP_INSUFFICIENT_AUTHORIZATION = 5; /** - * Error code during connect indicating insufficient encryption key size on the - * peer device during L2CAP connection. + * Error code during connect indicating insufficient encryption key size on the peer device + * during L2CAP connection. */ public static final int L2CAP_INSUFFICIENT_ENCRYPT_KEY_SIZE = 6; /** - * Error code during connect for insufficient encryption from the peer device - * during L2CAP connection. + * Error code during connect for insufficient encryption from the peer device during L2CAP + * connection. */ public static final int L2CAP_INSUFFICIENT_ENCRYPTION = 7; /** - * Error code during connect for invalid Channel ID from the peer device during - * L2CAP connection. + * Error code during connect for invalid Channel ID from the peer device during L2CAP + * connection. */ public static final int L2CAP_INVALID_SOURCE_CID = 8; /** - * Error code during connect for already allocated Channel ID from the peer - * device during L2CAP connection. + * Error code during connect for already allocated Channel ID from the peer device during L2CAP + * connection. */ public static final int L2CAP_SOURCE_CID_ALREADY_ALLOCATED = 9; /** - * Error code during connect for unacceptable Parameters from the peer device - * during L2CAP connection. + * Error code during connect for unacceptable Parameters from the peer device during L2CAP + * connection. */ public static final int L2CAP_UNACCEPTABLE_PARAMETERS = 10; /** - * Error code during connect for invalid parameters from the peer device during - * L2CAP connection. + * Error code during connect for invalid parameters from the peer device during L2CAP + * connection. */ public static final int L2CAP_INVALID_PARAMETERS = 11; - /** - * Error code during connect when no resources are available for L2CAP - * connection. - */ + /** Error code during connect when no resources are available for L2CAP connection. */ public static final int L2CAP_NO_RESOURCES = 12; - /** - * Error code during connect when no PSM is available for L2CAP connection. - */ + /** Error code during connect when no PSM is available for L2CAP connection. */ public static final int L2CAP_NO_PSM_AVAILABLE = 13; - /** - * Error code during connect when L2CAP connection timeout. - */ + /** Error code during connect when L2CAP connection timeout. */ public static final int L2CAP_TIMEOUT = 14; - /** - * Error code during connect when Bluetooth is off and socket connection is - * triggered. - */ + /** Error code during connect when Bluetooth is off and socket connection is triggered. */ public static final int BLUETOOTH_OFF_FAILURE = 15; - /** - * Error code during connect when socket manager is not available. - */ + /** Error code during connect when socket manager is not available. */ public static final int SOCKET_MANAGER_FAILURE = 16; - /** - * Error code during connect when socket is closed. - */ + /** Error code during connect when socket is closed. */ public static final int SOCKET_CLOSED = 17; - /** - * Error code during connect for generic socket connection failures. - */ + /** Error code during connect for generic socket connection failures. */ public static final int SOCKET_CONNECTION_FAILURE = 18; - /** - * Error code during connect when null device attempts to do socket connection. - */ + /** Error code during connect when null device attempts to do socket connection. */ public static final int NULL_DEVICE = 19; - /** - * Error code during connect when a Runtime RPC exception occurs. - */ + /** Error code during connect when a Runtime RPC exception occurs. */ public static final int RPC_FAILURE = 20; /* Corresponding messages for respective error codes. */ @@ -204,9 +183,9 @@ public class BluetoothSocketException extends IOException { @ErrorCode private final int mErrorCode; /** - * Create a {@link BluetoothSocketException} with a {@link ErrorCode} and custom error message. + * Create a {@link BluetoothSocketException} with an error code and custom error message. * - * @param code : {@link ErrorCode} representing the reason for failure. + * @param code : error code representing the reason for failure. * @param msg : Custom error message associated to the failure. */ public BluetoothSocketException(@ErrorCode int code, @NonNull String msg) { @@ -215,24 +194,22 @@ public class BluetoothSocketException extends IOException { } /** - * Create a {@link BluetoothSocketException} with an error {@link ErrorCode}. A generic error - * message is generated based on the {@code code} provided. + * Create a {@link BluetoothSocketException} with an error code. A generic error message is + * generated based on the {@code code} provided. * - * @param code : {@link ErrorCode} representing the reason for failure. + * @param code : error code representing the reason for failure. */ public BluetoothSocketException(@ErrorCode int code) { this(code, getMessage(code)); } - /** - * Returns the error code associated to this failure. - */ + /** Returns the error code associated to this failure. */ public @ErrorCode int getErrorCode() { return mErrorCode; } private static String getMessage(@ErrorCode int code) { - switch(code) { + switch (code) { case BLUETOOTH_OFF_FAILURE: return BLUETOOTH_OFF_FAILURE_MSG; case SOCKET_MANAGER_FAILURE: diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java index 0335fa8c3a0e7e44ab29b37adf16acdd1c9a6e14..f59c539828bab3c30bf5c28cdfe6ad7f8977acf3 100644 --- a/framework/java/android/bluetooth/BluetoothStatusCodes.java +++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java @@ -27,14 +27,10 @@ import android.annotation.SystemApi; public final class BluetoothStatusCodes { private BluetoothStatusCodes() {} - /** - * Indicates that the API call was successful. - */ + /** Indicates that the API call was successful. */ public static final int SUCCESS = 0; - /** - * Error code indicating that Bluetooth is not enabled. - */ + /** Error code indicating that Bluetooth is not enabled. */ public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; /** @@ -43,9 +39,7 @@ public final class BluetoothStatusCodes { */ public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; - /** - * Error code indicating that the Bluetooth Device specified is not bonded. - */ + /** Error code indicating that the Bluetooth Device specified is not bonded. */ public static final int ERROR_DEVICE_NOT_BONDED = 3; /** @@ -56,14 +50,14 @@ public final class BluetoothStatusCodes { public static final int ERROR_DEVICE_NOT_CONNECTED = 4; /** - * Error code indicating that the caller does not have the - * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. + * Error code indicating that the caller does not have the {@link + * android.Manifest.permission#BLUETOOTH_CONNECT} permission. */ public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; /** - * Error code indicating that the caller does not have the - * {@link android.Manifest.permission#BLUETOOTH_SCAN} permission. + * Error code indicating that the caller does not have the {@link + * android.Manifest.permission#BLUETOOTH_SCAN} permission. * * @hide */ @@ -75,14 +69,10 @@ public final class BluetoothStatusCodes { */ public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; - /** - * Indicates that the feature is supported. - */ + /** Indicates that the feature is supported. */ public static final int FEATURE_SUPPORTED = 10; - /** - * Indicates that the feature is not supported. - */ + /** Indicates that the feature is not supported. */ public static final int FEATURE_NOT_SUPPORTED = 11; /** @@ -90,159 +80,146 @@ public final class BluetoothStatusCodes { * * @hide */ - @SystemApi - public static final int ERROR_NOT_ACTIVE_DEVICE = 12; + @SystemApi public static final int ERROR_NOT_ACTIVE_DEVICE = 12; /** * Error code indicating that there are no active devices for the profile. * * @hide */ - @SystemApi - public static final int ERROR_NO_ACTIVE_DEVICES = 13; + @SystemApi public static final int ERROR_NO_ACTIVE_DEVICES = 13; /** * Indicates that the Bluetooth profile is not connected to this device. * * @hide */ - @SystemApi - public static final int ERROR_PROFILE_NOT_CONNECTED = 14; + @SystemApi public static final int ERROR_PROFILE_NOT_CONNECTED = 14; /** * Error code indicating that the requested operation timed out. * * @hide */ - @SystemApi - public static final int ERROR_TIMEOUT = 15; + @SystemApi public static final int ERROR_TIMEOUT = 15; /** * Indicates that some local application caused the event. + * * @hide */ - @SystemApi - public static final int REASON_LOCAL_APP_REQUEST = 16; + @SystemApi public static final int REASON_LOCAL_APP_REQUEST = 16; /** * Indicate that this change was initiated by the Bluetooth implementation on this device + * * @hide */ - @SystemApi - public static final int REASON_LOCAL_STACK_REQUEST = 17; + @SystemApi public static final int REASON_LOCAL_STACK_REQUEST = 17; /** * Indicate that this change was initiated by the remote device. + * * @hide */ - @SystemApi - public static final int REASON_REMOTE_REQUEST = 18; + @SystemApi public static final int REASON_REMOTE_REQUEST = 18; /** * Indicates that the local system policy caused the change, such as privacy policy, power * management policy, permission changes, and more. + * * @hide */ - @SystemApi - public static final int REASON_SYSTEM_POLICY = 19; + @SystemApi public static final int REASON_SYSTEM_POLICY = 19; /** - * Indicates that an underlying hardware incurred some error maybe try again later or toggle - * the hardware state. + * Indicates that an underlying hardware incurred some error maybe try again later or toggle the + * hardware state. + * * @hide */ - @SystemApi - public static final int ERROR_HARDWARE_GENERIC = 20; + @SystemApi public static final int ERROR_HARDWARE_GENERIC = 20; /** - * Indicates that the operation failed due to bad API input parameter that is not covered - * by other more detailed error code + * Indicates that the operation failed due to bad API input parameter that is not covered by + * other more detailed error code + * * @hide */ - @SystemApi - public static final int ERROR_BAD_PARAMETERS = 21; + @SystemApi public static final int ERROR_BAD_PARAMETERS = 21; /** * Indicate that there is not enough local resource to perform the requested operation + * * @hide */ - @SystemApi - public static final int ERROR_LOCAL_NOT_ENOUGH_RESOURCES = 22; + @SystemApi public static final int ERROR_LOCAL_NOT_ENOUGH_RESOURCES = 22; /** * Indicate that a remote device does not have enough resource to perform the requested * operation + * * @hide */ - @SystemApi - public static final int ERROR_REMOTE_NOT_ENOUGH_RESOURCES = 23; + @SystemApi public static final int ERROR_REMOTE_NOT_ENOUGH_RESOURCES = 23; /** * Indicates that the remote rejected this operation for reasons not covered above + * * @hide */ - @SystemApi - public static final int ERROR_REMOTE_OPERATION_REJECTED = 24; + @SystemApi public static final int ERROR_REMOTE_OPERATION_REJECTED = 24; /** * Indicates that there is an underlying link error between the local and remote devices. * - * Maybe try again later or disconnect and retry. + *

    Maybe try again later or disconnect and retry. + * * @hide */ - @SystemApi - public static final int ERROR_REMOTE_LINK_ERROR = 25; + @SystemApi public static final int ERROR_REMOTE_LINK_ERROR = 25; /** * A generic error code to indicate that the system is already in a target state that an API * tries to request. * - * For example, this error code will be delivered if someone tries to stop scanning when - * scan has already stopped, or start scanning when scan has already started. + *

    For example, this error code will be delivered if someone tries to stop scanning when scan + * has already stopped, or start scanning when scan has already started. * * @hide */ - @SystemApi - public static final int ERROR_ALREADY_IN_TARGET_STATE = 26; + @SystemApi public static final int ERROR_ALREADY_IN_TARGET_STATE = 26; /** * Indicates that the requested operation is not supported by the remote device * - * Caller should stop trying this operation + *

    Caller should stop trying this operation + * * @hide */ - @SystemApi - public static final int ERROR_REMOTE_OPERATION_NOT_SUPPORTED = 27; + @SystemApi public static final int ERROR_REMOTE_OPERATION_NOT_SUPPORTED = 27; /** * Indicates that the callback is not registered and therefore, this operation is not allowed. * * @hide */ - @SystemApi - public static final int ERROR_CALLBACK_NOT_REGISTERED = 28; + @SystemApi public static final int ERROR_CALLBACK_NOT_REGISTERED = 28; /** * Indicates that there is another active request and therefore, this operation is not allowed. * * @hide */ - @SystemApi - public static final int ERROR_ANOTHER_ACTIVE_REQUEST = 29; + @SystemApi public static final int ERROR_ANOTHER_ACTIVE_REQUEST = 29; - /** - * Indicates that the feature status is not configured yet. - */ + /** Indicates that the feature status is not configured yet. */ public static final int FEATURE_NOT_CONFIGURED = 30; - /** - * A GATT writeCharacteristic request is not permitted on the remote device. - */ + /** A GATT writeCharacteristic request is not permitted on the remote device. */ public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200; - /** - * A GATT writeCharacteristic request is issued to a busy remote device. - */ + /** A GATT writeCharacteristic request is issued to a busy remote device. */ public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 201; /** @@ -250,16 +227,14 @@ public final class BluetoothStatusCodes { * * @hide */ - @SystemApi - public static final int ALLOWED = 400; + @SystemApi public static final int ALLOWED = 400; /** * Indicates that the operation is not allowed. * * @hide */ - @SystemApi - public static final int NOT_ALLOWED = 401; + @SystemApi public static final int NOT_ALLOWED = 401; /** * If another application has already requested {@link OobData} then another fetch will be @@ -267,14 +242,12 @@ public final class BluetoothStatusCodes { * * @hide */ - @SystemApi - public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; + @SystemApi public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; /** * Indicates that the ACL disconnected due to an explicit request from the local device. - *

    - * Example cause: This is a normal disconnect reason, e.g., user/app initiates - * disconnection. + * + *

    Example cause: This is a normal disconnect reason, e.g., user/app initiates disconnection. * * @hide */ @@ -282,11 +255,10 @@ public final class BluetoothStatusCodes { /** * Indicates that the ACL disconnected due to an explicit request from the remote device. - *

    - * Example cause: This is a normal disconnect reason, e.g., user/app initiates - * disconnection. - *

    - * Example solution: The app can also prompt the user to check their remote device. + * + *

    Example cause: This is a normal disconnect reason, e.g., user/app initiates disconnection. + * + *

    Example solution: The app can also prompt the user to check their remote device. * * @hide */ @@ -295,9 +267,8 @@ public final class BluetoothStatusCodes { /** * Generic disconnect reason indicating the ACL disconnected due to an error on the local * device. - *

    - * Example solution: Prompt the user to check their local device (e.g., phone, car - * headunit). + * + *

    Example solution: Prompt the user to check their local device (e.g., phone, car headunit). * * @hide */ @@ -306,8 +277,8 @@ public final class BluetoothStatusCodes { /** * Generic disconnect reason indicating the ACL disconnected due to an error on the remote * device. - *

    - * Example solution: Prompt the user to check their remote device (e.g., headset, car + * + *

    Example solution: Prompt the user to check their remote device (e.g., headset, car * headunit, watch). * * @hide @@ -316,11 +287,11 @@ public final class BluetoothStatusCodes { /** * Indicates that the ACL disconnected due to a timeout. - *

    - * Example cause: remote device might be out of range. - *

    - * Example solution: Prompt user to verify their remote device is on or in - * connection/pairing mode. + * + *

    Example cause: remote device might be out of range. + * + *

    Example solution: Prompt user to verify their remote device is on or in connection/pairing + * mode. * * @hide */ @@ -328,11 +299,11 @@ public final class BluetoothStatusCodes { /** * Indicates that the ACL disconnected due to link key issues. - *

    - * Example cause: Devices are either unpaired or remote device is refusing our pairing + * + *

    Example cause: Devices are either unpaired or remote device is refusing our pairing * request. - *

    - * Example solution: Prompt user to unpair and pair again. + * + *

    Example solution: Prompt user to unpair and pair again. * * @hide */ @@ -340,10 +311,10 @@ public final class BluetoothStatusCodes { /** * Indicates that the ACL disconnected due to the local device's system policy. - *

    - * Example cause: privacy policy, power management policy, permissions, etc. - *

    - * Example solution: Prompt the user to check settings, or check with their system + * + *

    Example cause: privacy policy, power management policy, permissions, etc. + * + *

    Example solution: Prompt the user to check settings, or check with their system * administrator (e.g. some corp-managed devices do not allow OPP connection). * * @hide @@ -351,14 +322,14 @@ public final class BluetoothStatusCodes { public static final int ERROR_DISCONNECT_REASON_SYSTEM_POLICY = 1106; /** - * Indicates that the ACL disconnected due to resource constraints, either on the local - * device or the remote device. - *

    - * Example cause: controller is busy, memory limit reached, maximum number of connections + * Indicates that the ACL disconnected due to resource constraints, either on the local device + * or the remote device. + * + *

    Example cause: controller is busy, memory limit reached, maximum number of connections * reached. - *

    - * Example solution: The app should wait and try again. If still failing, prompt the user - * to disconnect some devices, or toggle Bluetooth on the local and/or the remote device. + * + *

    Example solution: The app should wait and try again. If still failing, prompt the user to + * disconnect some devices, or toggle Bluetooth on the local and/or the remote device. * * @hide */ @@ -373,8 +344,8 @@ public final class BluetoothStatusCodes { /** * Indicates that the ACL disconnected due to incorrect parameters passed in from the app. - *

    - * Example solution: Change parameters and try again. If error persists, the app can report + * + *

    Example solution: Change parameters and try again. If error persists, the app can report * telemetry and/or log the error in a bugreport. * * @hide @@ -386,148 +357,137 @@ public final class BluetoothStatusCodes { * * @hide */ - @SystemApi - public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116; + @SystemApi public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116; /** * Indicates that SCO audio was already not connected for this device. * * @hide */ - @SystemApi - public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117; + @SystemApi public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117; /** * Indicates that there audio route is currently blocked by the system. * * @hide */ - @SystemApi - public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118; + @SystemApi public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118; /** * Indicates that there is an active call preventing this operation from succeeding. * * @hide */ - @SystemApi - public static final int ERROR_CALL_ACTIVE = 1119; + @SystemApi public static final int ERROR_CALL_ACTIVE = 1119; // LE audio related return codes reserved from 1200 to 1300 /** * Indicates that the broadcast ID cannot be found among existing Broadcast Sources. + * * @hide */ - @SystemApi - public static final int ERROR_LE_BROADCAST_INVALID_BROADCAST_ID = 1200; + @SystemApi public static final int ERROR_LE_BROADCAST_INVALID_BROADCAST_ID = 1200; /** * Indicates that encryption code entered does not meet the specification requirement + * * @hide */ - @SystemApi - public static final int ERROR_LE_BROADCAST_INVALID_CODE = 1201; + @SystemApi public static final int ERROR_LE_BROADCAST_INVALID_CODE = 1201; /** * Indicates that the source ID cannot be found in the given Broadcast sink device + * * @hide */ - @SystemApi - public static final int ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID = 1202; + @SystemApi public static final int ERROR_LE_BROADCAST_ASSISTANT_INVALID_SOURCE_ID = 1202; /** * Indicates that the same Broadcast Source is already added to the Broadcast Sink * - * Broadcast Source is identified by their advertising SID and broadcast ID + *

    Broadcast Source is identified by their advertising SID and broadcast ID + * * @hide */ - @SystemApi - public static final int ERROR_LE_BROADCAST_ASSISTANT_DUPLICATE_ADDITION = 1203; - + @SystemApi public static final int ERROR_LE_BROADCAST_ASSISTANT_DUPLICATE_ADDITION = 1203; /** * Indicates that the program info in a {@link BluetoothLeAudioContentMetadata} is not valid + * * @hide */ - @SystemApi - public static final int ERROR_LE_CONTENT_METADATA_INVALID_PROGRAM_INFO = 1204; + @SystemApi public static final int ERROR_LE_CONTENT_METADATA_INVALID_PROGRAM_INFO = 1204; /** * Indicates that the language code in a {@link BluetoothLeAudioContentMetadata} is not valid + * * @hide */ - @SystemApi - public static final int ERROR_LE_CONTENT_METADATA_INVALID_LANGUAGE = 1205; + @SystemApi public static final int ERROR_LE_CONTENT_METADATA_INVALID_LANGUAGE = 1205; /** * Indicates that operation failed due to other {@link BluetoothLeAudioContentMetadata} related * issues not covered by other reason codes. + * * @hide */ - @SystemApi - public static final int ERROR_LE_CONTENT_METADATA_INVALID_OTHER = 1206; + @SystemApi public static final int ERROR_LE_CONTENT_METADATA_INVALID_OTHER = 1206; /** * Indicates that provided group ID is invalid for the coordinated set + * * @hide */ - @SystemApi - public static final int ERROR_CSIP_INVALID_GROUP_ID = 1207; + @SystemApi public static final int ERROR_CSIP_INVALID_GROUP_ID = 1207; /** * Indicating that CSIP group locked failed due to group member being already locked. * * @hide */ - @SystemApi - public static final int ERROR_CSIP_GROUP_LOCKED_BY_OTHER = 1208; + @SystemApi public static final int ERROR_CSIP_GROUP_LOCKED_BY_OTHER = 1208; /** * Indicating that CSIP device has been lost while being locked. + * * @hide */ - @SystemApi - public static final int ERROR_CSIP_LOCKED_GROUP_MEMBER_LOST = 1209; + @SystemApi public static final int ERROR_CSIP_LOCKED_GROUP_MEMBER_LOST = 1209; /** * Indicates that the set preset name is too long. - *

    - * Example solution: Try using shorter name. + * + *

    Example solution: Try using shorter name. * * @hide */ - @SystemApi - public static final int ERROR_HAP_PRESET_NAME_TOO_LONG = 1210; + @SystemApi public static final int ERROR_HAP_PRESET_NAME_TOO_LONG = 1210; /** * Indicates that provided preset index parameters is invalid - *

    - * Example solution: Use preset index of a known existing preset. + * + *

    Example solution: Use preset index of a known existing preset. * * @hide */ - @SystemApi - public static final int ERROR_HAP_INVALID_PRESET_INDEX = 1211; + @SystemApi public static final int ERROR_HAP_INVALID_PRESET_INDEX = 1211; /** * Indicates that LE connection is required but not exist or disconnected. - *

    - * Example solution: create LE connection then retry again. + * + *

    Example solution: create LE connection then retry again. * * @hide */ - @SystemApi - public static final int ERROR_NO_LE_CONNECTION = 1300; + @SystemApi public static final int ERROR_NO_LE_CONNECTION = 1300; /** * Indicates internal error of distance measurement, such as read RSSI data fail. * * @hide */ - @SystemApi - public static final int ERROR_DISTANCE_MEASUREMENT_INTERNAL = 1301; - + @SystemApi public static final int ERROR_DISTANCE_MEASUREMENT_INTERNAL = 1301; /** * Indicates that the RFCOMM listener could not be started due to the requested UUID already @@ -535,8 +495,7 @@ public final class BluetoothStatusCodes { * * @hide */ - @SystemApi - public static final int RFCOMM_LISTENER_START_FAILED_UUID_IN_USE = 2000; + @SystemApi public static final int RFCOMM_LISTENER_START_FAILED_UUID_IN_USE = 2000; /** * Indicates that the operation could not be competed because the service record on which the @@ -553,32 +512,28 @@ public final class BluetoothStatusCodes { * * @hide */ - @SystemApi - public static final int RFCOMM_LISTENER_OPERATION_FAILED_DIFFERENT_APP = 2002; + @SystemApi public static final int RFCOMM_LISTENER_OPERATION_FAILED_DIFFERENT_APP = 2002; /** * Indicates that the creation of the underlying BluetoothServerSocket failed. * * @hide */ - @SystemApi - public static final int RFCOMM_LISTENER_FAILED_TO_CREATE_SERVER_SOCKET = 2003; + @SystemApi public static final int RFCOMM_LISTENER_FAILED_TO_CREATE_SERVER_SOCKET = 2003; /** * Indicates that closing the underlying BluetoothServerSocket failed. * * @hide */ - @SystemApi - public static final int RFCOMM_LISTENER_FAILED_TO_CLOSE_SERVER_SOCKET = 2004; + @SystemApi public static final int RFCOMM_LISTENER_FAILED_TO_CLOSE_SERVER_SOCKET = 2004; /** * Indicates that there is no socket available to retrieve from the given listener. * * @hide */ - @SystemApi - public static final int RFCOMM_LISTENER_NO_SOCKET_AVAILABLE = 2005; + @SystemApi public static final int RFCOMM_LISTENER_NO_SOCKET_AVAILABLE = 2005; /** * Error code indicating that this operation is not allowed because the remote device does not @@ -586,11 +541,8 @@ public final class BluetoothStatusCodes { * * @hide */ - @SystemApi - public static final int ERROR_NOT_DUAL_MODE_AUDIO_DEVICE = 3000; + @SystemApi public static final int ERROR_NOT_DUAL_MODE_AUDIO_DEVICE = 3000; - /** - * Indicates that an unknown error has occurred. - */ + /** Indicates that an unknown error has occurred. */ public static final int ERROR_UNKNOWN = Integer.MAX_VALUE; } diff --git a/framework/java/android/bluetooth/BluetoothUtils.java b/framework/java/android/bluetooth/BluetoothUtils.java index 116783755bcd30ff16d04aae7ee1dfa53293f2ca..f7fcf4825f8bd3e87ac58a7620f14244cb517edf 100644 --- a/framework/java/android/bluetooth/BluetoothUtils.java +++ b/framework/java/android/bluetooth/BluetoothUtils.java @@ -24,21 +24,15 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -/** - * {@hide} - */ +/** @hide */ public final class BluetoothUtils { private static final String TAG = "BluetoothUtils"; - /** - * This utility class cannot be instantiated - */ + /** This utility class cannot be instantiated */ private BluetoothUtils() {} - /** - * Timeout value for synchronous binder call - */ - private static final Duration SYNC_CALLS_TIMEOUT = Duration.ofSeconds(5); + /** Timeout value for synchronous binder call */ + private static final Duration SYNC_CALLS_TIMEOUT = Duration.ofSeconds(3); /** * @return timeout value for synchronous binder call @@ -47,14 +41,10 @@ public final class BluetoothUtils { return SYNC_CALLS_TIMEOUT; } - /** - * Match with UserHandl.NULL but accessible inside bluetooth package - */ + /** Match with UserHandl.NULL but accessible inside bluetooth package */ public static final UserHandle USER_HANDLE_NULL = UserHandle.of(-10000); - /** - * Class for Length-Value-Entry array parsing - */ + /** Class for Length-Value-Entry array parsing */ public static class TypeValueEntry { private final int mType; private final byte[] mValue; @@ -77,9 +67,16 @@ public final class BluetoothUtils { private static byte[] extractBytes(byte[] rawBytes, int start, int length) { int remainingLength = rawBytes.length - start; if (remainingLength < length) { - Log.w(TAG, "extractBytes() remaining length " + remainingLength - + " is less than copying length " + length + ", array length is " - + rawBytes.length + " start is " + start); + Log.w( + TAG, + "extractBytes() remaining length " + + remainingLength + + " is less than copying length " + + length + + ", array length is " + + rawBytes.length + + " start is " + + start); return null; } byte[] bytes = new byte[length]; @@ -90,11 +87,12 @@ public final class BluetoothUtils { /** * Parse Length Value Entry from raw bytes * - * The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18. + *

    The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18. * * @param rawBytes raw bytes of Length-Value-Entry array * @hide */ + @SuppressWarnings("MixedMutabilityReturnType") // TODO(b/314811467) public static List parseLengthTypeValueBytes(byte[] rawBytes) { if (rawBytes == null) { return Collections.emptyList(); @@ -113,8 +111,12 @@ public final class BluetoothUtils { } currentPos++; if (currentPos >= rawBytes.length) { - Log.w(TAG, "parseLtv() no type and value after length, rawBytes length = " - + rawBytes.length + ", currentPost = " + currentPos); + Log.w( + TAG, + "parseLtv() no type and value after length, rawBytes length = " + + rawBytes.length + + ", currentPost = " + + currentPos); break; } // Note the length includes the length of the field type itself. @@ -123,8 +125,12 @@ public final class BluetoothUtils { int type = rawBytes[currentPos] & 0xFF; currentPos++; if (currentPos >= rawBytes.length) { - Log.w(TAG, "parseLtv() no value after length, rawBytes length = " - + rawBytes.length + ", currentPost = " + currentPos); + Log.w( + TAG, + "parseLtv() no value after length, rawBytes length = " + + rawBytes.length + + ", currentPost = " + + currentPos); break; } byte[] value = extractBytes(rawBytes, currentPos, dataLength); @@ -140,6 +146,7 @@ public final class BluetoothUtils { /** * Serialize type value entries to bytes + * * @param typeValueEntries type value entries * @return serialized type value entries on success, null on failure */ @@ -150,8 +157,11 @@ public final class BluetoothUtils { // 1 for length and 1 for type length += 2; if ((entry.getType() - (entry.getType() & 0xFF)) != 0) { - Log.w(TAG, "serializeTypeValue() type " + entry.getType() - + " is out of range of 0-0xFF"); + Log.w( + TAG, + "serializeTypeValue() type " + + entry.getType() + + " is out of range of 0-0xFF"); return null; } if (entry.getValue() == null) { @@ -160,8 +170,11 @@ public final class BluetoothUtils { } int lengthValue = entry.getValue().length + 1; if ((lengthValue - (lengthValue & 0xFF)) != 0) { - Log.w(TAG, "serializeTypeValue() entry length " + entry.getValue().length - + " is not in range of 0 to 254"); + Log.w( + TAG, + "serializeTypeValue() entry length " + + entry.getValue().length + + " is not in range of 0 to 254"); return null; } length += entry.getValue().length; @@ -181,6 +194,7 @@ public final class BluetoothUtils { /** * Convert an address to an obfuscate one for logging purpose + * * @param address Mac address to be log * @return Loggable mac address */ diff --git a/framework/java/android/bluetooth/BluetoothUuid.java b/framework/java/android/bluetooth/BluetoothUuid.java index 63f293ae662bc4111325e5b3343ca2a69786c626..97228ef9ade7a698fe8170fb4ec63c2d8b9ad9ee 100644 --- a/framework/java/android/bluetooth/BluetoothUuid.java +++ b/framework/java/android/bluetooth/BluetoothUuid.java @@ -16,6 +16,7 @@ package android.bluetooth; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; @@ -31,8 +32,8 @@ import java.util.UUID; /** * Static helper methods and constants to decode the ParcelUuid of remote devices. Bluetooth service - * UUIDs are defined in the SDP section of the Bluetooth Assigned Numbers document. The constant - * 128 bit values in this class are calculated as: uuid * 2^96 + {@link #BASE_UUID}. + * UUIDs are defined in the SDP section of the Bluetooth Assigned Numbers document. The constant 128 + * bit values in this class are calculated as: uuid * 2^96 + {@link #BASE_UUID}. * * @hide */ @@ -45,17 +46,16 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid A2DP_SINK = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); + /** * UUID corresponding to the Audio source role (also referred to as the A2DP source role). * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid A2DP_SOURCE = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); @@ -64,8 +64,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid ADV_AUDIO_DIST = ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB"); @@ -74,8 +73,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid HSP = ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB"); @@ -84,8 +82,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid HSP_AG = ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB"); @@ -94,8 +91,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid HFP = ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB"); @@ -104,8 +100,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid HFP_AG = ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB"); @@ -114,8 +109,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid AVRCP = ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB"); @@ -124,8 +118,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid AVRCP_CONTROLLER = ParcelUuid.fromString("0000110F-0000-1000-8000-00805F9B34FB"); @@ -134,8 +127,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid AVRCP_TARGET = ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"); @@ -144,8 +136,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid OBEX_OBJECT_PUSH = ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb"); @@ -154,8 +145,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid HID = ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb"); @@ -164,8 +154,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid HOGP = ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb"); @@ -174,8 +163,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid PANU = ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB"); @@ -184,8 +172,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid NAP = ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB"); @@ -194,8 +181,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid BNEP = ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB"); @@ -204,8 +190,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid PBAP_PCE = ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB"); @@ -214,8 +199,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid PBAP_PSE = ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB"); @@ -224,8 +208,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid MAP = ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB"); @@ -234,8 +217,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid MNS = ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB"); @@ -244,8 +226,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid MAS = ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB"); @@ -254,8 +235,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid SAP = ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB"); @@ -264,8 +244,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid HEARING_AID = ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb"); @@ -274,18 +253,27 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid HAS = ParcelUuid.fromString("00001854-0000-1000-8000-00805F9B34FB"); /** - * UUID corresponding to Audio Stream Control (also known as Bluetooth Low Energy Audio). + * UUID corresponding to the Made For iPhone/iPod/iPad Hearing Aid Service (MFi HAS). * * @hide */ @NonNull @SystemApi + @FlaggedApi("com.android.bluetooth.flags.mfi_has_uuid") + public static final ParcelUuid MFI_HAS = + ParcelUuid.fromString("7D74F4BD-C74A-4431-862C-CCE884371592"); + + /** + * UUID corresponding to Audio Stream Control (also known as Bluetooth Low Energy Audio). + * + * @hide + */ + @NonNull @SystemApi public static final ParcelUuid LE_AUDIO = ParcelUuid.fromString("0000184E-0000-1000-8000-00805F9B34FB"); @@ -294,8 +282,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid DIP = ParcelUuid.fromString("00001200-0000-1000-8000-00805F9B34FB"); @@ -304,8 +291,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid VOLUME_CONTROL = ParcelUuid.fromString("00001844-0000-1000-8000-00805F9B34FB"); @@ -314,8 +300,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid GENERIC_MEDIA_CONTROL = ParcelUuid.fromString("00001849-0000-1000-8000-00805F9B34FB"); @@ -324,8 +309,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid MEDIA_CONTROL = ParcelUuid.fromString("00001848-0000-1000-8000-00805F9B34FB"); @@ -334,8 +318,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid COORDINATED_SET = ParcelUuid.fromString("00001846-0000-1000-8000-00805F9B34FB"); @@ -344,8 +327,7 @@ public final class BluetoothUuid { * * @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid CAP = ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB"); @@ -358,14 +340,15 @@ public final class BluetoothUuid { @NonNull public static final ParcelUuid BATTERY = ParcelUuid.fromString("0000180F-0000-1000-8000-00805F9B34FB"); + /** @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid BASS = ParcelUuid.fromString("0000184F-0000-1000-8000-00805F9B34FB"); /** * Telephony and Media Audio Profile (TMAP) UUID + * * @hide */ @NonNull @@ -373,8 +356,7 @@ public final class BluetoothUuid { ParcelUuid.fromString("00001855-0000-1000-8000-00805F9B34FB"); /** @hide */ - @NonNull - @SystemApi + @NonNull @SystemApi public static final ParcelUuid BASE_UUID = ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB"); @@ -383,34 +365,32 @@ public final class BluetoothUuid { * * @hide */ - @SystemApi - public static final int UUID_BYTES_16_BIT = 2; + @SystemApi public static final int UUID_BYTES_16_BIT = 2; + /** * Length of bytes for 32 bit UUID * * @hide */ - @SystemApi - public static final int UUID_BYTES_32_BIT = 4; + @SystemApi public static final int UUID_BYTES_32_BIT = 4; + /** * Length of bytes for 128 bit UUID * * @hide */ - @SystemApi - public static final int UUID_BYTES_128_BIT = 16; + @SystemApi public static final int UUID_BYTES_128_BIT = 16; /** * Returns true if there any common ParcelUuids in uuidA and uuidB. * * @param uuidA - List of ParcelUuids * @param uuidB - List of ParcelUuids - * * @hide */ @SystemApi - public static boolean containsAnyUuid(@Nullable ParcelUuid[] uuidA, - @Nullable ParcelUuid[] uuidB) { + public static boolean containsAnyUuid( + @Nullable ParcelUuid[] uuidA, @Nullable ParcelUuid[] uuidB) { if (uuidA == null && uuidB == null) return true; if (uuidA == null) { @@ -429,12 +409,8 @@ public final class BluetoothUuid { } /** - * Extract the Service Identifier or the actual uuid from the Parcel Uuid. - * For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid, - * this function will return 110B - * - * @param parcelUuid - * @return the service identifier. + * Extract the Service Identifier or the actual uuid from the Parcel Uuid. For example, if + * 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid, this function will return 110B */ private static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) { UUID uuid = parcelUuid.getUuid(); @@ -444,13 +420,11 @@ public final class BluetoothUuid { /** * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID, - * but the returned UUID is always in 128-bit format. - * Note UUID is little endian in Bluetooth. + * but the returned UUID is always in 128-bit format. Note UUID is little endian in Bluetooth. * * @param uuidBytes Byte representation of uuid. * @return {@link ParcelUuid} parsed from bytes. * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed. - * * @hide */ @NonNull @@ -460,7 +434,8 @@ public final class BluetoothUuid { throw new IllegalArgumentException("uuidBytes cannot be null"); } int length = uuidBytes.length; - if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT + if (length != UUID_BYTES_16_BIT + && length != UUID_BYTES_32_BIT && length != UUID_BYTES_128_BIT) { throw new IllegalArgumentException("uuidBytes length invalid - " + length); } @@ -497,7 +472,6 @@ public final class BluetoothUuid { * @param uuid uuid to parse. * @return shortest representation of {@code uuid} as bytes. * @throws IllegalArgumentException If the {@code uuid} is null. - * * @hide */ public static byte[] uuidToBytes(ParcelUuid uuid) { @@ -537,9 +511,7 @@ public final class BluetoothUuid { /** * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid. * - * @param parcelUuid * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise. - * * @hide */ @UnsupportedAppUsage @@ -551,13 +523,10 @@ public final class BluetoothUuid { return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L); } - /** * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid. * - * @param parcelUuid * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise. - * * @hide */ @UnsupportedAppUsage diff --git a/framework/java/android/bluetooth/BluetoothVolumeControl.java b/framework/java/android/bluetooth/BluetoothVolumeControl.java index 8f16ae3b40091545bc3c92fb1bdbff1df1ebd9cd..aa7f748bdd11313226b29813ada2139c3184f2a5 100644 --- a/framework/java/android/bluetooth/BluetoothVolumeControl.java +++ b/framework/java/android/bluetooth/BluetoothVolumeControl.java @@ -21,6 +21,7 @@ import static android.bluetooth.BluetoothUtils.getSyncTimeout; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -50,9 +51,9 @@ import java.util.concurrent.TimeoutException; /** * This class provides the public APIs to control the Bluetooth Volume Control service. * - *

    BluetoothVolumeControl is a proxy object for controlling the Bluetooth VC - * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get - * the BluetoothVolumeControl proxy object. + *

    BluetoothVolumeControl is a proxy object for controlling the Bluetooth VC Service via IPC. Use + * {@link BluetoothAdapter#getProfileProxy} to get the BluetoothVolumeControl proxy object. + * * @hide */ @SystemApi @@ -65,61 +66,89 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose private final Map mCallbackExecutorMap = new HashMap<>(); /** - * This class provides a callback that is invoked when volume offset value changes on - * the remote device. + * This class provides a callback that is invoked when volume offset value changes on the remote + * device. * - *

    In order to balance volume on the group of Le Audio devices, - * Volume Offset Control Service (VOCS) shall be used. User can verify - * if the remote device supports VOCS by calling {@link #isVolumeOffsetAvailable(device)}. + *

    In order to balance volume on the group of Le Audio devices, Volume Offset Control Service + * (VOCS) shall be used. User can verify if the remote device supports VOCS by calling {@link + * #isVolumeOffsetAvailable(device)}. * * @hide */ @SystemApi public interface Callback { /** - * Callback invoked when callback is registered and when volume offset - * changes on the remote device. Change can be triggered autonomously by the remote device - * or after volume offset change on the user request done by calling - * {@link #setVolumeOffset(device, volumeOffset)} + * Callback invoked when callback is registered and when volume offset changes on the remote + * device. Change can be triggered autonomously by the remote device or after volume offset + * change on the user request done by calling {@link #setVolumeOffset(device, volumeOffset)} * * @param device remote device whose volume offset changed * @param volumeOffset latest volume offset for this device * @hide */ @SystemApi - void onVolumeOffsetChanged(@NonNull BluetoothDevice device, - @IntRange(from = -255, to = 255) int volumeOffset); + void onVolumeOffsetChanged( + @NonNull BluetoothDevice device, @IntRange(from = -255, to = 255) int volumeOffset); + + /** + * Callback for le audio connected device volume level change + * + *

    The valid volume range is [0, 255], as defined in 2.3.1.1 Volume_Setting field of + * Volume Control Service, Version 1.0. + * + * @param device remote device whose volume changed + * @param volume level + * @hide + */ + @FlaggedApi( + "com.android.bluetooth.flags.leaudio_broadcast_volume_control_for_connected_devices") + @SystemApi + default void onDeviceVolumeChanged( + @NonNull BluetoothDevice device, @IntRange(from = 0, to = 255) int volume) {} } @SuppressLint("AndroidFrameworkBluetoothPermission") private final IBluetoothVolumeControlCallback mCallback = new IBluetoothVolumeControlCallback.Stub() { - @Override - public void onVolumeOffsetChanged(@NonNull BluetoothDevice device, int volumeOffset) { - Attributable.setAttributionSource(device, mAttributionSource); - for (Map.Entry callbackExecutorEntry: - mCallbackExecutorMap.entrySet()) { + @Override + public void onVolumeOffsetChanged( + @NonNull BluetoothDevice device, int volumeOffset) { + Attributable.setAttributionSource(device, mAttributionSource); + for (Map.Entry + callbackExecutorEntry : mCallbackExecutorMap.entrySet()) { BluetoothVolumeControl.Callback callback = callbackExecutorEntry.getKey(); - Executor executor = callbackExecutorEntry.getValue(); - executor.execute(() -> callback.onVolumeOffsetChanged(device, volumeOffset)); - } - } - }; + Executor executor = callbackExecutorEntry.getValue(); + executor.execute( + () -> callback.onVolumeOffsetChanged(device, volumeOffset)); + } + } + + @Override + public void onDeviceVolumeChanged(@NonNull BluetoothDevice device, int volume) { + Attributable.setAttributionSource(device, mAttributionSource); + for (Map.Entry + callbackExecutorEntry : mCallbackExecutorMap.entrySet()) { + BluetoothVolumeControl.Callback callback = callbackExecutorEntry.getKey(); + Executor executor = callbackExecutorEntry.getValue(); + executor.execute(() -> callback.onDeviceVolumeChanged(device, volume)); + } + } + }; /** - * Intent used to broadcast the change in connection state of the Volume Control - * profile. + * Intent used to broadcast the change in connection state of the Volume Control profile. * *

    This intent will have 3 extras: + * *

      - *
    • {@link #EXTRA_STATE} - The current state of the profile.
    • - *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
    • - *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
    • + *
    • {@link #EXTRA_STATE} - The current state of the profile. + *
    • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. + *
    • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. *
    * - *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, - * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + *

    {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link + * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link + * #STATE_DISCONNECTING}. * * @hide */ @@ -133,71 +162,24 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose private BluetoothAdapter mAdapter; private final AttributionSource mAttributionSource; - private final BluetoothProfileConnector mProfileConnector = - new BluetoothProfileConnector(this, BluetoothProfile.VOLUME_CONTROL, TAG, - IBluetoothVolumeControl.class.getName()) { - @Override - public IBluetoothVolumeControl getServiceInterface(IBinder service) { - return IBluetoothVolumeControl.Stub.asInterface(service); - } - }; - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = - new IBluetoothStateChangeCallback.Stub() { - public void onBluetoothStateChange(boolean up) { - if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); - if (!up) { - return; - } - // re-register the service-to-app callback - synchronized (mCallbackExecutorMap) { - if (!mCallbackExecutorMap.isEmpty()) { - try { - final IBluetoothVolumeControl service = getService(); - if (service != null) { - final SynchronousResultReceiver recv = - SynchronousResultReceiver.get(); - service.registerCallback(mCallback, mAttributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } - } catch (RemoteException e) { - Log.e(TAG, "onBluetoothServiceUp: Failed to register" - + "Volume Control callback", e); - } catch (TimeoutException e) { - Log.e(TAG, e.toString() + "\n" - + Log.getStackTraceString(new Throwable())); - } - } - } - } - }; + private IBluetoothVolumeControl mService; /** - * Create a BluetoothVolumeControl proxy object for interacting with the local - * Bluetooth Volume Control service. + * Create a BluetoothVolumeControl proxy object for interacting with the local Bluetooth Volume + * Control service. */ - /*package*/ BluetoothVolumeControl(Context context, ServiceListener listener, - BluetoothAdapter adapter) { + /*package*/ BluetoothVolumeControl(Context context, BluetoothAdapter adapter) { mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); - mProfileConnector.connect(context, listener); - - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); - } - } + mService = null; mCloseGuard = new CloseGuard(); mCloseGuard.open("close"); } @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @SuppressWarnings("Finalize") // TODO(b/314811467) protected void finalize() { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); @@ -216,34 +198,64 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose public void close() { if (VDBG) log("close()"); - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + mAdapter.closeProfileProxy(this); + } + + /** @hide */ + @Override + public void onServiceConnected(IBinder service) { + mService = IBluetoothVolumeControl.Stub.asInterface(service); + // re-register the service-to-app callback + synchronized (mCallbackExecutorMap) { + if (!mCallbackExecutorMap.isEmpty()) { + try { + if (service != null) { + final SynchronousResultReceiver recv = + SynchronousResultReceiver.get(); + mService.registerCallback(mCallback, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } + } catch (RemoteException e) { + Log.e( + TAG, + "onBluetoothServiceUp: Failed to register" + "Volume Control callback", + e); + } catch (TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } } - mProfileConnector.disconnect(); + } + + /** @hide */ + @Override + public void onServiceDisconnected() { + mService = null; } private IBluetoothVolumeControl getService() { - return mProfileConnector.getService(); + return mService; + } + + /** @hide */ + @Override + public BluetoothAdapter getAdapter() { + return mAdapter; } /** * Get the list of connected devices. Currently at most one. * * @return list of connected devices - * * @hide */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @NonNull List getConnectedDevices() { if (DBG) log("getConnectedDevices()"); final IBluetoothVolumeControl service = getService(); @@ -270,7 +282,6 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose * Get the list of devices matching specified states. Currently at most one. * * @return list of matching devices - * * @hide */ @RequiresBluetoothConnectPermission @@ -301,7 +312,6 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose * Get connection state of device * * @return device connection state - * * @hide */ @RequiresBluetoothConnectPermission @@ -326,13 +336,12 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose } /** - * Register a {@link Callback} that will be invoked during the - * operation of this profile. + * Register a {@link Callback} that will be invoked during the operation of this profile. * - * Repeated registration of the same callback object will have no effect after - * the first call to this method, even when the executor is different. API caller - * would have to call {@link #unregisterCallback(Callback)} with - * the same callback object before registering it again. + *

    Repeated registration of the same callback object will have no effect after the + * first call to this method, even when the executor is different. API caller would + * have to call {@link #unregisterCallback(Callback)} with the same callback object before + * registering it again. * * @param executor an {@link Executor} to execute given callback * @param callback user implementation of the {@link Callback} @@ -341,12 +350,13 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public void registerCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull Callback callback) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void registerCallback( + @NonNull @CallbackExecutor Executor executor, @NonNull Callback callback) { Objects.requireNonNull(executor, "executor cannot be null"); Objects.requireNonNull(callback, "callback cannot be null"); if (DBG) log("registerCallback"); @@ -364,13 +374,13 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose final IBluetoothVolumeControl service = getService(); if (service != null) { final SynchronousResultReceiver recv = - SynchronousResultReceiver.get(); + SynchronousResultReceiver.get(); service.registerCallback(mCallback, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -386,8 +396,9 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose /** * Unregister the specified {@link Callback}. - *

    The same {@link Callback} object used when calling - * {@link #registerCallback(Executor, Callback)} must be used. + * + *

    The same {@link Callback} object used when calling {@link #registerCallback(Executor, + * Callback)} must be used. * *

    Callbacks are automatically unregistered when application process goes away * @@ -397,10 +408,11 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public void unregisterCallback(@NonNull Callback callback) { Objects.requireNonNull(callback, "callback cannot be null"); if (DBG) log("unregisterCallback"); @@ -421,7 +433,7 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose } } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } catch (IllegalStateException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } @@ -433,18 +445,18 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose * * @param device {@link BluetoothDevice} representing the remote device * @param volumeOffset volume offset to be set on the remote device - * * @hide */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public void setVolumeOffset(@NonNull BluetoothDevice device, - @IntRange(from = -255, to = 255) int volumeOffset) { - if (DBG) log("setVolumeOffset(" + device + " volumeOffset: " + volumeOffset + ")"); + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void setVolumeOffset( + @NonNull BluetoothDevice device, @IntRange(from = -255, to = 255) int volumeOffset) { + if (DBG) log("setVolumeOffset(" + device + " volumeOffset: " + volumeOffset + ")"); final IBluetoothVolumeControl service = getService(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); @@ -461,22 +473,21 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose } /** - * Provides information about the possibility to set volume offset on the remote device. - * If the remote device supports Volume Offset Control Service, it is automatically - * connected. + * Provides information about the possibility to set volume offset on the remote device. If the + * remote device supports Volume Offset Control Service, it is automatically connected. * * @param device {@link BluetoothDevice} representing the remote device * @return {@code true} if volume offset function is supported and available to use on the - * remote device. When Bluetooth is off, the return value should always be - * {@code false}. + * remote device. When Bluetooth is off, the return value should always be {@code false}. * @hide */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean isVolumeOffsetAvailable(@NonNull BluetoothDevice device) { if (DBG) log("isVolumeOffsetAvailable(" + device + ")"); final IBluetoothVolumeControl service = getService(); @@ -505,9 +516,9 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose /** * Set connection policy of the profile * - *

    The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + *

    The device should already be paired. Connection policy can be one of {@link + * #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, {@link + * #CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device * @param connectionPolicy is the connection policy to set to for this profile @@ -516,21 +527,23 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean setConnectionPolicy(@NonNull BluetoothDevice device, - @ConnectionPolicy int connectionPolicy) { + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean setConnectionPolicy( + @NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothVolumeControl service = getService(); final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); - } else if (isEnabled() && isValidDevice(device) + } else if (isEnabled() + && isValidDevice(device) && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); @@ -545,9 +558,8 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose /** * Get the connection policy of the profile. * - *

    The connection policy can be any of: - * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, - * {@link #CONNECTION_POLICY_UNKNOWN} + *

    The connection policy can be any of: {@link #CONNECTION_POLICY_ALLOWED}, {@link + * #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} * * @param device Bluetooth device * @return connection policy of the device @@ -555,10 +567,11 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose */ @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothVolumeControl service = getService(); @@ -578,6 +591,55 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose return defaultValue; } + /** + * Set volume for the le audio device + * + *

    This provides volume control for connected remote device directly by volume control + * service. The valid volume range is [0, 255], as defined in 2.3.1.1 Volume_Setting field of + * Volume Control Service, Version 1.0. + * + *

    For le audio unicast devices volume control, application should consider to use {@link + * BluetoothLeAudio#setVolume} instead to control active device volume. + * + * @param device {@link BluetoothDevice} representing the remote device + * @param volume level to set + * @param isGroupOperation {@code true} if Application wants to perform this operation for all + * coordinated set members throughout this session. Otherwise, caller would have to control + * individual device volume. + * @throws IllegalArgumentException if volume is not in the range [0, 255]. + * @hide + */ + @FlaggedApi( + "com.android.bluetooth.flags.leaudio_broadcast_volume_control_for_connected_devices") + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void setDeviceVolume( + @NonNull BluetoothDevice device, + @IntRange(from = 0, to = 255) int volume, + boolean isGroupOperation) { + if (volume < 0 || volume > 255) { + throw new IllegalArgumentException("illegal volume " + volume); + } + final IBluetoothVolumeControl service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); + service.setDeviceVolume(device, volume, isGroupOperation, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } + } + } + private boolean isEnabled() { return mAdapter.getState() == BluetoothAdapter.STATE_ON; } diff --git a/framework/java/android/bluetooth/BufferConstraint.java b/framework/java/android/bluetooth/BufferConstraint.java index cbffc788c35dcbccd7dcb22c65be44d84768b623..25fb21798a45e0d931696c9b50c264cb6be61eb6 100644 --- a/framework/java/android/bluetooth/BufferConstraint.java +++ b/framework/java/android/bluetooth/BufferConstraint.java @@ -24,7 +24,7 @@ import android.os.Parcelable; /** * Stores a codec's constraints on buffering length in milliseconds. * - * {@hide} + * @hide */ @SystemApi public final class BufferConstraint implements Parcelable { @@ -34,8 +34,7 @@ public final class BufferConstraint implements Parcelable { private int mMaxMillis; private int mMinMillis; - public BufferConstraint(int defaultMillis, int maxMillis, - int minMillis) { + public BufferConstraint(int defaultMillis, int maxMillis, int minMillis) { mDefaultMillis = defaultMillis; mMaxMillis = maxMillis; mMinMillis = minMillis; diff --git a/framework/java/android/bluetooth/BufferConstraints.java b/framework/java/android/bluetooth/BufferConstraints.java index 97d97232b7a682c34dab5ebca8116a17a30df1d0..38b5f339c142488d0bdbf9bfb66e2eaff91dc96c 100644 --- a/framework/java/android/bluetooth/BufferConstraints.java +++ b/framework/java/android/bluetooth/BufferConstraints.java @@ -27,11 +27,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - /** * A parcelable collection of buffer constraints by codec type. * - * {@hide} + * @hide */ @SystemApi public final class BufferConstraints implements Parcelable { @@ -42,8 +41,7 @@ public final class BufferConstraints implements Parcelable { private Map mBufferConstraints; private List mBufferConstraintList; - public BufferConstraints(@NonNull List - bufferConstraintList) { + public BufferConstraints(@NonNull List bufferConstraintList) { mBufferConstraintList = new ArrayList(bufferConstraintList); mBufferConstraints = new HashMap(); diff --git a/framework/java/android/bluetooth/OWNERS b/framework/java/android/bluetooth/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..af162a5de5dca0c3cd28b68be5b40230a7dcb1d8 --- /dev/null +++ b/framework/java/android/bluetooth/OWNERS @@ -0,0 +1 @@ +per-file BluetoothHearingAid.java=file:/OWNERS_hearingaid diff --git a/framework/java/android/bluetooth/OobData.java b/framework/java/android/bluetooth/OobData.java index fb1983dd36013a26e315bdbdd0f3adc5a8f3ce31..eaac01c91419d960a7799a86d5f27b82001f41e6 100644 --- a/framework/java/android/bluetooth/OobData.java +++ b/framework/java/android/bluetooth/OobData.java @@ -1,19 +1,16 @@ /** * Copyright (C) 2016 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + *

    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 + *

    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 + *

    Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ - package android.bluetooth; import static java.util.Objects.requireNonNull; @@ -31,41 +28,26 @@ import java.lang.annotation.RetentionPolicy; /** * Out Of Band Data for Bluetooth device pairing. * - *

    This object represents optional data obtained from a remote device through - * an out-of-band channel (eg. NFC, QR). + *

    This object represents optional data obtained from a remote device through an out-of-band + * channel (eg. NFC, QR). + * + *

    References: NFC + * AD Forum SSP 1.1 (AD) * - *

    References: - * NFC AD Forum SSP 1.1 (AD) - * {@link https://members.nfc-forum.org//apps/group_public/download.php/24620/NFCForum-AD-BTSSP_1_1.pdf} - * Core Specification Supplement (CSS) V9 + *

    Core Specification Supplement (CSS) V9 * *

    There are several BR/EDR Examples * - *

    Negotiated Handover: - * Bluetooth Carrier Configuration Record: - * - OOB Data Length - * - Device Address - * - Class of Device - * - Simple Pairing Hash C - * - Simple Pairing Randomizer R - * - Service Class UUID - * - Bluetooth Local Name + *

    Negotiated Handover: Bluetooth Carrier Configuration Record: - OOB Data Length - Device + * Address - Class of Device - Simple Pairing Hash C - Simple Pairing Randomizer R - Service Class + * UUID - Bluetooth Local Name * - *

    Static Handover: - * Bluetooth Carrier Configuration Record: - * - OOB Data Length - * - Device Address - * - Class of Device - * - Service Class UUID - * - Bluetooth Local Name + *

    Static Handover: Bluetooth Carrier Configuration Record: - OOB Data Length - Device Address - + * Class of Device - Service Class UUID - Bluetooth Local Name * - *

    Simplified Tag Format for Single BT Carrier: - * Bluetooth OOB Data Record: - * - OOB Data Length - * - Device Address - * - Class of Device - * - Service Class UUID - * - Bluetooth Local Name + *

    Simplified Tag Format for Single BT Carrier: Bluetooth OOB Data Record: - OOB Data Length - + * Device Address - Class of Device - Service Class UUID - Bluetooth Local Name * * @hide */ @@ -73,99 +55,96 @@ import java.lang.annotation.RetentionPolicy; public final class OobData implements Parcelable { private static final String TAG = "OobData"; + /** The {@link OobData#mClassicLength} may be. (AD 3.1.1) (CSS 1.6.2) @hide */ - @SystemApi - public static final int OOB_LENGTH_OCTETS = 2; + @SystemApi public static final int OOB_LENGTH_OCTETS = 2; + /** - * The length for the {@link OobData#mDeviceAddressWithType}(6) and Address Type(1). - * (AD 3.1.2) (CSS 1.6.2) + * The length for the {@link OobData#mDeviceAddressWithType}(6) and Address Type(1). (AD 3.1.2) + * (CSS 1.6.2) + * * @hide */ - @SystemApi - public static final int DEVICE_ADDRESS_OCTETS = 7; + @SystemApi public static final int DEVICE_ADDRESS_OCTETS = 7; + /** The Class of Device is 3 octets. (AD 3.1.3) (CSS 1.6.2) @hide */ - @SystemApi - public static final int CLASS_OF_DEVICE_OCTETS = 3; + @SystemApi public static final int CLASS_OF_DEVICE_OCTETS = 3; + /** The Confirmation data must be 16 octets. (AD 3.2.2) (CSS 1.6.2) @hide */ - @SystemApi - public static final int CONFIRMATION_OCTETS = 16; + @SystemApi public static final int CONFIRMATION_OCTETS = 16; + /** The Randomizer data must be 16 octets. (AD 3.2.3) (CSS 1.6.2) @hide */ - @SystemApi - public static final int RANDOMIZER_OCTETS = 16; + @SystemApi public static final int RANDOMIZER_OCTETS = 16; + /** The LE Device Role length is 1 octet. (AD 3.3.2) (CSS 1.17) @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_OCTETS = 1; + @SystemApi public static final int LE_DEVICE_ROLE_OCTETS = 1; + /** The {@link OobData#mLeTemporaryKey} length. (3.4.1) @hide */ - @SystemApi - public static final int LE_TK_OCTETS = 16; + @SystemApi public static final int LE_TK_OCTETS = 16; + /** The {@link OobData#mLeAppearance} length. (3.4.1) @hide */ - @SystemApi - public static final int LE_APPEARANCE_OCTETS = 2; + @SystemApi public static final int LE_APPEARANCE_OCTETS = 2; + /** The {@link OobData#mLeFlags} length. (3.4.1) @hide */ - @SystemApi - public static final int LE_DEVICE_FLAG_OCTETS = 1; // 1 octet to hold the 0-4 value. + @SystemApi public static final int LE_DEVICE_FLAG_OCTETS = 1; // 1 octet to hold the 0-4 value. // Le Roles /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( - prefix = { "LE_DEVICE_ROLE_" }, - value = { - LE_DEVICE_ROLE_PERIPHERAL_ONLY, - LE_DEVICE_ROLE_CENTRAL_ONLY, - LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL, - LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL - } - ) + prefix = {"LE_DEVICE_ROLE_"}, + value = { + LE_DEVICE_ROLE_PERIPHERAL_ONLY, + LE_DEVICE_ROLE_CENTRAL_ONLY, + LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL, + LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL + }) public @interface LeRole {} /** @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0x00; + @SystemApi public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0x00; + /** @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 0x01; + @SystemApi public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 0x01; + /** @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 0x02; + @SystemApi public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 0x02; + /** @hide */ - @SystemApi - public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 0x03; + @SystemApi public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 0x03; // Le Flags /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( - prefix = { "LE_FLAG_" }, - value = { - LE_FLAG_LIMITED_DISCOVERY_MODE, - LE_FLAG_GENERAL_DISCOVERY_MODE, - LE_FLAG_BREDR_NOT_SUPPORTED, - LE_FLAG_SIMULTANEOUS_CONTROLLER, - LE_FLAG_SIMULTANEOUS_HOST - } - ) + prefix = {"LE_FLAG_"}, + value = { + LE_FLAG_LIMITED_DISCOVERY_MODE, + LE_FLAG_GENERAL_DISCOVERY_MODE, + LE_FLAG_BREDR_NOT_SUPPORTED, + LE_FLAG_SIMULTANEOUS_CONTROLLER, + LE_FLAG_SIMULTANEOUS_HOST + }) public @interface LeFlag {} /** @hide */ - @SystemApi - public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0x00; + @SystemApi public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0x00; + /** @hide */ - @SystemApi - public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 0x01; + @SystemApi public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 0x01; + /** @hide */ - @SystemApi - public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 0x02; + @SystemApi public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 0x02; + /** @hide */ - @SystemApi - public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 0x03; + @SystemApi public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 0x03; + /** @hide */ - @SystemApi - public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04; + @SystemApi public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04; /** - * Builds an {@link OobData} object and validates that the required combination - * of values are present to create the LE specific OobData type. + * Builds an {@link OobData} object and validates that the required combination of values are + * present to create the LE specific OobData type. * * @hide */ @@ -173,11 +152,10 @@ public final class OobData implements Parcelable { public static final class LeBuilder { /** - * It is recommended that this Hash C is generated anew for each - * pairing. + * It is recommended that this Hash C is generated anew for each pairing. * - *

    It should be noted that on passive NFC this isn't possible as the data is static - * and immutable. + *

    It should be noted that on passive NFC this isn't possible as the data is static and + * immutable. */ private byte[] mConfirmationHash = null; @@ -186,10 +164,11 @@ public final class OobData implements Parcelable { * *

    If not present a value of 0 is assumed. */ - private byte[] mRandomizerHash = new byte[] { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - }; + private byte[] mRandomizerHash = + new byte[] { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; /** * The Bluetooth Device user-friendly name presented over Bluetooth Technology. @@ -204,11 +183,8 @@ public final class OobData implements Parcelable { *

    Optional attribute. * * @param deviceName byte array representing the name, may be 0 in length, not null. - * * @return {@link OobData#ClassicBuilder} - * * @throws NullPointerException if deviceName is null. - * * @hide */ @NonNull @@ -224,7 +200,7 @@ public final class OobData implements Parcelable { * *

    The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets. * - *

    Address is encoded in Little Endian order. + *

    Address is encoded in Little Endian order. * *

    e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00 */ @@ -234,20 +210,18 @@ public final class OobData implements Parcelable { * During an LE connection establishment, one must be in the Peripheral mode and the other * in the Central role. * - *

    Possible Values: - * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported - * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported - * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; - * Peripheral Preferred - * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred - * 0x04 - 0xFF Reserved + *

    Possible Values: {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported + * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported {@link + * LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; Peripheral + * Preferred {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central + * Preferred 0x04 - 0xFF Reserved */ private final @LeRole int mLeDeviceRole; /** * Temporary key value from the Security Manager. * - *

    Must be {@link LE_TK_OCTETS} in size + *

    Must be {@link LE_TK_OCTETS} in size */ private byte[] mLeTemporaryKey = null; @@ -263,61 +237,56 @@ public final class OobData implements Parcelable { /** * Contains which discoverable mode to use, BR/EDR support and capability. * - *

    Possible LE Flags: - * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. - * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. - * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of - * LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to - * Same Device Capable (Controller). - * Bit 49 of LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to - * Same Device Capable (Host). - * Bit 55 of LMP Feature Mask Definitions. - * 0x05- 0x07 Reserved + *

    Possible LE Flags: {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable + * Mode. {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. {@link + * LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of LMP Feature Mask + * Definitions. {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to Same + * Device Capable (Controller). Bit 49 of LMP Feature Mask Definitions. {@link + * LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to Same Device Capable (Host). Bit + * 55 of LMP Feature Mask Definitions. 0x05- 0x07 Reserved */ private @LeFlag int mLeFlags = LE_FLAG_GENERAL_DISCOVERY_MODE; // Invalid default /** * Main creation method for creating a LE version of {@link OobData}. * - *

    This object will allow the caller to call {@link LeBuilder#build()} - * to build the data object or add any option information to the builder. - * - * @param deviceAddressWithType the LE device address plus the address type (7 octets); - * not null. - * @param leDeviceRole whether the device supports Peripheral, Central, - * Both including preference; not null. (1 octet) - * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets - * of data. Data is derived from controller/host stack and is - * required for pairing OOB. - * - *

    Possible Values: - * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported - * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported - * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; - * Peripheral Preferred - * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred - * 0x04 - 0xFF Reserved - * + *

    This object will allow the caller to call {@link LeBuilder#build()} to build the data + * object or add any option information to the builder. + * + * @param deviceAddressWithType the LE device address plus the address type (7 octets); not + * null. + * @param leDeviceRole whether the device supports Peripheral, Central, Both including + * preference; not null. (1 octet) + * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets of + * data. Data is derived from controller/host stack and is required for pairing OOB. + *

    Possible Values: {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported + * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported {@link + * LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; Peripheral + * Preferred {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; + * Central Preferred 0x04 - 0xFF Reserved * @throws IllegalArgumentException if any of the values fail to be set. * @throws NullPointerException if any argument is null. - * * @hide */ @SystemApi - public LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType, + public LeBuilder( + @NonNull byte[] confirmationHash, + @NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole) { requireNonNull(confirmationHash); requireNonNull(deviceAddressWithType); if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) { - throw new IllegalArgumentException("confirmationHash must be " - + OobData.CONFIRMATION_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "confirmationHash must be " + + OobData.CONFIRMATION_OCTETS + + " octets in length."); } this.mConfirmationHash = confirmationHash; if (deviceAddressWithType.length != OobData.DEVICE_ADDRESS_OCTETS) { - throw new IllegalArgumentException("confirmationHash must be " - + OobData.DEVICE_ADDRESS_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "confirmationHash must be " + + OobData.DEVICE_ADDRESS_OCTETS + + " octets in length."); } this.mDeviceAddressWithType = deviceAddressWithType; if (leDeviceRole < LE_DEVICE_ROLE_PERIPHERAL_ONLY @@ -328,17 +297,13 @@ public final class OobData implements Parcelable { } /** - * Sets the Temporary Key value to be used by the LE Security Manager during - * LE pairing. - * - * @param leTemporaryKey byte array that shall be 16 bytes. Please see Bluetooth CSSv6, - * Part A 1.8 for a detailed description. + * Sets the Temporary Key value to be used by the LE Security Manager during LE pairing. * + * @param leTemporaryKey byte array that shall be 16 bytes. Please see Bluetooth CSSv6, Part + * A 1.8 for a detailed description. * @return {@link OobData#Builder} - * * @throws IllegalArgumentException if the leTemporaryKey is an invalid format. * @throws NullinterException if leTemporaryKey is null. - * * @hide */ @NonNull @@ -346,8 +311,8 @@ public final class OobData implements Parcelable { public LeBuilder setLeTemporaryKey(@NonNull byte[] leTemporaryKey) { requireNonNull(leTemporaryKey); if (leTemporaryKey.length != LE_TK_OCTETS) { - throw new IllegalArgumentException("leTemporaryKey must be " - + LE_TK_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "leTemporaryKey must be " + LE_TK_OCTETS + " octets in length."); } this.mLeTemporaryKey = leTemporaryKey; return this; @@ -355,12 +320,10 @@ public final class OobData implements Parcelable { /** * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets - * of data. Data is derived from controller/host stack and is required for pairing OOB. - * Also, randomizerHash may be all 0s or null in which case it becomes all 0s. - * + * of data. Data is derived from controller/host stack and is required for pairing OOB. + * Also, randomizerHash may be all 0s or null in which case it becomes all 0s. * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed. * @throws NullPointerException if randomizerHash is null. - * * @hide */ @NonNull @@ -368,8 +331,10 @@ public final class OobData implements Parcelable { public LeBuilder setRandomizerHash(@NonNull byte[] randomizerHash) { requireNonNull(randomizerHash); if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) { - throw new IllegalArgumentException("randomizerHash must be " - + OobData.RANDOMIZER_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "randomizerHash must be " + + OobData.RANDOMIZER_OCTETS + + " octets in length."); } this.mRandomizerHash = randomizerHash; return this; @@ -379,19 +344,13 @@ public final class OobData implements Parcelable { * Sets the LE Flags necessary for the pairing scenario or discovery mode. * * @param leFlags enum value representing the 1 octet of data about discovery modes. - * - *

    Possible LE Flags: - * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. - * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. - * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of - * LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to - * Same Device Capable (Controller) Bit 49 of LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to - * Same Device Capable (Host). - * Bit 55 of LMP Feature Mask Definitions. - * 0x05- 0x07 Reserved - * + *

    Possible LE Flags: {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable + * Mode. {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. {@link + * LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of LMP Feature Mask + * Definitions. {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to + * Same Device Capable (Controller) Bit 49 of LMP Feature Mask Definitions. {@link + * LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to Same Device Capable (Host). + * Bit 55 of LMP Feature Mask Definitions. 0x05- 0x07 Reserved * @throws IllegalArgumentException for invalid flag * @hide */ @@ -409,23 +368,23 @@ public final class OobData implements Parcelable { * Validates and builds the {@link OobData} object for LE Security. * * @return {@link OobData} with given builder values - * * @throws IllegalStateException if either of the 2 required fields were not set. - * * @hide */ @NonNull @SystemApi public OobData build() { final OobData oob = - new OobData(this.mDeviceAddressWithType, this.mLeDeviceRole, + new OobData( + this.mDeviceAddressWithType, + this.mLeDeviceRole, this.mConfirmationHash); // If we have values, set them, otherwise use default oob.mLeTemporaryKey = (this.mLeTemporaryKey != null) ? this.mLeTemporaryKey : oob.mLeTemporaryKey; - oob.mLeAppearance = (this.mLeAppearance != null) - ? this.mLeAppearance : oob.mLeAppearance; + oob.mLeAppearance = + (this.mLeAppearance != null) ? this.mLeAppearance : oob.mLeAppearance; oob.mLeFlags = (this.mLeFlags != 0xF) ? this.mLeFlags : oob.mLeFlags; oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName; oob.mRandomizerHash = this.mRandomizerHash; @@ -434,8 +393,8 @@ public final class OobData implements Parcelable { } /** - * Builds an {@link OobData} object and validates that the required combination - * of values are present to create the Classic specific OobData type. + * Builds an {@link OobData} object and validates that the required combination of values are + * present to create the Classic specific OobData type. * * @hide */ @@ -443,11 +402,10 @@ public final class OobData implements Parcelable { public static final class ClassicBuilder { // Used by both Classic and LE /** - * It is recommended that this Hash C is generated anew for each - * pairing. + * It is recommended that this Hash C is generated anew for each pairing. * - *

    It should be noted that on passive NFC this isn't possible as the data is static - * and immutable. + *

    It should be noted that on passive NFC this isn't possible as the data is static and + * immutable. * * @hide */ @@ -460,10 +418,11 @@ public final class OobData implements Parcelable { * * @hide */ - private byte[] mRandomizerHash = new byte[] { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - }; + private byte[] mRandomizerHash = + new byte[] { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; /** * The Bluetooth Device user-friendly name presented over Bluetooth Technology. @@ -475,11 +434,11 @@ public final class OobData implements Parcelable { private byte[] mDeviceName = null; /** - * This length value provides the absolute length of total OOB data block used for - * Bluetooth BR/EDR + * This length value provides the absolute length of total OOB data block used for Bluetooth + * BR/EDR * - *

    OOB communication, which includes the length field itself and the Bluetooth - * Device Address. + *

    OOB communication, which includes the length field itself and the Bluetooth Device + * Address. * *

    The minimum length that may be represented in this field is 8. * @@ -492,7 +451,7 @@ public final class OobData implements Parcelable { * *

    The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets. * - *

    Address is encoded in Little Endian order. + *

    Address is encoded in Little Endian order. * *

    e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00 * @@ -501,8 +460,8 @@ public final class OobData implements Parcelable { private final byte[] mDeviceAddressWithType; /** - * Class of Device information is to be used to provide a graphical representation - * to the user as part of UI involving operations. + * Class of Device information is to be used to provide a graphical representation to the + * user as part of UI involving operations. * *

    This is not to be used to determine a particular service can be used. * @@ -515,53 +474,55 @@ public final class OobData implements Parcelable { /** * Main creation method for creating a Classic version of {@link OobData}. * - *

    This object will allow the caller to call {@link ClassicBuilder#build()} - * to build the data object or add any option information to the builder. + *

    This object will allow the caller to call {@link ClassicBuilder#build()} to build the + * data object or add any option information to the builder. * * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} - * octets of data. Data is derived from controller/host stack and is required for pairing - * OOB. + * octets of data. Data is derived from controller/host stack and is required for + * pairing OOB. * @param classicLength byte array representing the length of data from 8-65535 across 2 - * octets (0xXXXX). + * octets (0xXXXX). * @param deviceAddressWithType byte array representing the Bluetooth Address of the device - * that owns the OOB data. (i.e. the originator) [6 octets] - * + * that owns the OOB data. (i.e. the originator) [6 octets] * @throws IllegalArgumentException if any of the values fail to be set. * @throws NullPointerException if any argument is null. - * * @hide */ @SystemApi - public ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength, + public ClassicBuilder( + @NonNull byte[] confirmationHash, + @NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType) { requireNonNull(confirmationHash); requireNonNull(classicLength); requireNonNull(deviceAddressWithType); if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) { - throw new IllegalArgumentException("confirmationHash must be " - + OobData.CONFIRMATION_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "confirmationHash must be " + + OobData.CONFIRMATION_OCTETS + + " octets in length."); } this.mConfirmationHash = confirmationHash; if (classicLength.length != OOB_LENGTH_OCTETS) { - throw new IllegalArgumentException("classicLength must be " - + OOB_LENGTH_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "classicLength must be " + OOB_LENGTH_OCTETS + " octets in length."); } this.mClassicLength = classicLength; if (deviceAddressWithType.length != DEVICE_ADDRESS_OCTETS) { - throw new IllegalArgumentException("deviceAddressWithType must be " - + DEVICE_ADDRESS_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "deviceAddressWithType must be " + + DEVICE_ADDRESS_OCTETS + + " octets in length."); } this.mDeviceAddressWithType = deviceAddressWithType; } /** * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets - * of data. Data is derived from controller/host stack and is required for pairing OOB. - * Also, randomizerHash may be all 0s or null in which case it becomes all 0s. - * + * of data. Data is derived from controller/host stack and is required for pairing OOB. + * Also, randomizerHash may be all 0s or null in which case it becomes all 0s. * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed. * @throws NullPointerException if randomizerHash is null. - * * @hide */ @NonNull @@ -569,8 +530,10 @@ public final class OobData implements Parcelable { public ClassicBuilder setRandomizerHash(@NonNull byte[] randomizerHash) { requireNonNull(randomizerHash); if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) { - throw new IllegalArgumentException("randomizerHash must be " - + OobData.RANDOMIZER_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "randomizerHash must be " + + OobData.RANDOMIZER_OCTETS + + " octets in length."); } this.mRandomizerHash = randomizerHash; return this; @@ -582,11 +545,8 @@ public final class OobData implements Parcelable { *

    Optional attribute. * * @param deviceName byte array representing the name, may be 0 in length, not null. - * * @return {@link OobData#ClassicBuilder} - * * @throws NullPointerException if deviceName is null - * * @hide */ @NonNull @@ -605,13 +565,10 @@ public final class OobData implements Parcelable { *

    Optional attribute. * * @param classOfDevice byte array of {@link OobData#CLASS_OF_DEVICE_OCTETS} octets. - * * @return {@link OobData#ClassicBuilder} - * - * @throws IllegalArgumentException if length is not equal to - * {@link OobData#CLASS_OF_DEVICE_OCTETS} octets. + * @throws IllegalArgumentException if length is not equal to {@link + * OobData#CLASS_OF_DEVICE_OCTETS} octets. * @throws NullPointerException if classOfDevice is null. - * * @hide */ @NonNull @@ -619,8 +576,10 @@ public final class OobData implements Parcelable { public ClassicBuilder setClassOfDevice(@NonNull byte[] classOfDevice) { requireNonNull(classOfDevice); if (classOfDevice.length != OobData.CLASS_OF_DEVICE_OCTETS) { - throw new IllegalArgumentException("classOfDevice must be " - + OobData.CLASS_OF_DEVICE_OCTETS + " octets in length."); + throw new IllegalArgumentException( + "classOfDevice must be " + + OobData.CLASS_OF_DEVICE_OCTETS + + " octets in length."); } this.mClassOfDevice = classOfDevice; return this; @@ -637,12 +596,14 @@ public final class OobData implements Parcelable { @SystemApi public OobData build() { final OobData oob = - new OobData(this.mClassicLength, this.mDeviceAddressWithType, + new OobData( + this.mClassicLength, + this.mDeviceAddressWithType, this.mConfirmationHash); // If we have values, set them, otherwise use default oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName; - oob.mClassOfDevice = (this.mClassOfDevice != null) - ? this.mClassOfDevice : oob.mClassOfDevice; + oob.mClassOfDevice = + (this.mClassOfDevice != null) ? this.mClassOfDevice : oob.mClassOfDevice; oob.mRandomizerHash = this.mRandomizerHash; return oob; } @@ -652,17 +613,33 @@ public final class OobData implements Parcelable { // Both private final byte[] mDeviceAddressWithType; private final byte[] mConfirmationHash; - private byte[] mRandomizerHash = new byte[] { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - }; + private byte[] mRandomizerHash = + new byte[] { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; // Default the name to "Bluetooth Device" - private byte[] mDeviceName = new byte[] { - // Bluetooth - 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, - // Device - 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65 - }; + private byte[] mDeviceName = + new byte[] { + // Bluetooth + 0x42, + 0x6c, + 0x75, + 0x65, + 0x74, + 0x6f, + 0x6f, + 0x74, + 0x68, + // Device + 0x20, + 0x44, + 0x65, + 0x76, + 0x69, + 0x63, + 0x65 + }; // Classic private final byte[] mClassicLength; @@ -675,12 +652,10 @@ public final class OobData implements Parcelable { private @LeFlag int mLeFlags = LE_FLAG_LIMITED_DISCOVERY_MODE; /** - * @return byte array representing the MAC address of a bluetooth device. - * The Address is 6 octets long with a 1 octet address type associated with the address. - * - *

    For classic this will be 6 byte address plus the default of PUBLIC_ADDRESS Address Type. - * For LE there are more choices for Address Type. - * + * @return byte array representing the MAC address of a bluetooth device. The Address is 6 + * octets long with a 1 octet address type associated with the address. + *

    For classic this will be 6 byte address plus the default of PUBLIC_ADDRESS Address + * Type. For LE there are more choices for Address Type. * @hide */ @NonNull @@ -690,9 +665,8 @@ public final class OobData implements Parcelable { } /** - * @return byte array representing the confirmationHash value - * which is used to confirm the identity to the controller. - * + * @return byte array representing the confirmationHash value which is used to confirm the + * identity to the controller. * @hide */ @NonNull @@ -702,9 +676,8 @@ public final class OobData implements Parcelable { } /** - * @return byte array representing the randomizerHash value - * which is used to verify the identity of the controller. - * + * @return byte array representing the randomizerHash value which is used to verify the identity + * of the controller. * @hide */ @NonNull @@ -715,9 +688,7 @@ public final class OobData implements Parcelable { /** * @return Device Name used for displaying name in UI. - * - *

    Also, this will be populated with the LE Local Name if the data is for LE. - * + *

    Also, this will be populated with the LE Local Name if the data is for LE. * @hide */ @Nullable @@ -727,9 +698,8 @@ public final class OobData implements Parcelable { } /** - * @return byte array representing the oob data length which is the length - * of all of the data including these octets. - * + * @return byte array representing the oob data length which is the length of all of the data + * including these octets. * @hide */ @NonNull @@ -740,9 +710,7 @@ public final class OobData implements Parcelable { /** * @return byte array representing the class of device for UI display. - * - *

    Does not indicate services available; for display only. - * + *

    Does not indicate services available; for display only. * @hide */ @NonNull @@ -753,7 +721,6 @@ public final class OobData implements Parcelable { /** * @return Temporary Key used for LE pairing. - * * @hide */ @Nullable @@ -763,10 +730,8 @@ public final class OobData implements Parcelable { } /** - * @return Appearance used for LE pairing. For use in UI situations - * when determining what sort of icons or text to display regarding - * the device. - * + * @return Appearance used for LE pairing. For use in UI situations when determining what sort + * of icons or text to display regarding the device. * @hide */ @Nullable @@ -776,21 +741,14 @@ public final class OobData implements Parcelable { } /** - * @return Flags used to determing discoverable mode to use, BR/EDR Support, and Capability. - * - *

    Possible LE Flags: - * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. - * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. - * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of - * LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to - * Same Device Capable (Controller). - * Bit 49 of LMP Feature Mask Definitions. - * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to - * Same Device Capable (Host). - * Bit 55 of LMP Feature Mask Definitions. - * 0x05- 0x07 Reserved - * + * @return Flags used to determining discoverable mode to use, BR/EDR Support, and Capability. + *

    Possible LE Flags: {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable + * Mode. {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. {@link + * LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of LMP Feature Mask + * Definitions. {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to Same + * Device Capable (Controller). Bit 49 of LMP Feature Mask Definitions. {@link + * LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to Same Device Capable (Host). Bit + * 55 of LMP Feature Mask Definitions. 0x05- 0x07 Reserved * @hide */ @NonNull @@ -802,15 +760,11 @@ public final class OobData implements Parcelable { /** * @return the supported and preferred roles of the LE device. - * - *

    Possible Values: - * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported - * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported - * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; - * Peripheral Preferred - * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred - * 0x04 - 0xFF Reserved - * + *

    Possible Values: {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported + * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported {@link + * LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; Peripheral + * Preferred {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central + * Preferred 0x04 - 0xFF Reserved * @hide */ @NonNull @@ -820,10 +774,10 @@ public final class OobData implements Parcelable { return mLeDeviceRole; } - /** - * Classic Security Constructor - */ - private OobData(@NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType, + /** Classic Security Constructor */ + private OobData( + @NonNull byte[] classicLength, + @NonNull byte[] deviceAddressWithType, @NonNull byte[] confirmationHash) { mClassicLength = classicLength; mDeviceAddressWithType = deviceAddressWithType; @@ -831,10 +785,10 @@ public final class OobData implements Parcelable { mLeDeviceRole = -1; // Satisfy final } - /** - * LE Security Constructor - */ - private OobData(@NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole, + /** LE Security Constructor */ + private OobData( + @NonNull byte[] deviceAddressWithType, + @LeRole int leDeviceRole, @NonNull byte[] confirmationHash) { mDeviceAddressWithType = deviceAddressWithType; mLeDeviceRole = leDeviceRole; @@ -860,17 +814,13 @@ public final class OobData implements Parcelable { mLeFlags = in.readInt(); } - /** - * @hide - */ + /** @hide */ @Override public int describeContents() { return 0; } - /** - * @hide - */ + /** @hide */ @Override public void writeToParcel(@NonNull Parcel out, int flags) { // Both @@ -903,37 +853,56 @@ public final class OobData implements Parcelable { // For Parcelable public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { - public OobData createFromParcel(Parcel in) { - return new OobData(in); - } + public OobData createFromParcel(Parcel in) { + return new OobData(in); + } - public OobData[] newArray(int size) { - return new OobData[size]; - } - }; + public OobData[] newArray(int size) { + return new OobData[size]; + } + }; /** * @return a {@link String} representation of the OobData object. - * * @hide */ @Override @NonNull public String toString() { return "OobData: \n\t" - // Both - + "Device Address With Type: " + toHexString(mDeviceAddressWithType) + "\n\t" - + "Confirmation: " + toHexString(mConfirmationHash) + "\n\t" - + "Randomizer: " + toHexString(mRandomizerHash) + "\n\t" - + "Device Name: " + toHexString(mDeviceName) + "\n\t" - // Classic - + "OobData Length: " + toHexString(mClassicLength) + "\n\t" - + "Class of Device: " + toHexString(mClassOfDevice) + "\n\t" - // LE - + "LE Device Role: " + toHexString(mLeDeviceRole) + "\n\t" - + "LE Temporary Key: " + toHexString(mLeTemporaryKey) + "\n\t" - + "LE Appearance: " + toHexString(mLeAppearance) + "\n\t" - + "LE Flags: " + toHexString(mLeFlags) + "\n\t"; + // Both + + "Device Address With Type: " + + toHexString(mDeviceAddressWithType) + + "\n\t" + + "Confirmation: " + + toHexString(mConfirmationHash) + + "\n\t" + + "Randomizer: " + + toHexString(mRandomizerHash) + + "\n\t" + + "Device Name: " + + toHexString(mDeviceName) + + "\n\t" + // Classic + + "OobData Length: " + + toHexString(mClassicLength) + + "\n\t" + + "Class of Device: " + + toHexString(mClassOfDevice) + + "\n\t" + // LE + + "LE Device Role: " + + toHexString(mLeDeviceRole) + + "\n\t" + + "LE Temporary Key: " + + toHexString(mLeTemporaryKey) + + "\n\t" + + "LE Appearance: " + + toHexString(mLeAppearance) + + "\n\t" + + "LE Flags: " + + toHexString(mLeFlags) + + "\n\t"; } @NonNull @@ -941,16 +910,11 @@ public final class OobData implements Parcelable { return toHexString(new byte[] {(byte) b}); } - @NonNull - private String toHexString(byte b) { - return toHexString(new byte[] {b}); - } - @NonNull private String toHexString(byte[] array) { if (array == null) return "null"; StringBuilder builder = new StringBuilder(array.length * 2); - for (byte b: array) { + for (byte b : array) { builder.append(String.format("%02x", b)); } return builder.toString(); diff --git a/framework/java/android/bluetooth/SdpDipRecord.java b/framework/java/android/bluetooth/SdpDipRecord.java index 26d0115744cc40efe682a0ed17e0c855c37af94c..b701c22832a3368604255dd5892158f1776ef0e3 100644 --- a/framework/java/android/bluetooth/SdpDipRecord.java +++ b/framework/java/android/bluetooth/SdpDipRecord.java @@ -1,25 +1,23 @@ /* -* Copyright (C) 2015 Samsung System LSI -* 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. -*/ + * Copyright (C) 2015 Samsung System LSI + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package android.bluetooth; import android.os.Parcel; import android.os.Parcelable; -/** - * Data representation of a Object Push Profile Server side SDP record. - */ +/** Data representation of a Object Push Profile Server side SDP record. */ /** @hide */ public class SdpDipRecord implements Parcelable { private final int mSpecificationId; @@ -29,9 +27,12 @@ public class SdpDipRecord implements Parcelable { private final int mVersion; private final boolean mPrimaryRecord; - public SdpDipRecord(int specificationId, - int vendorId, int vendorIdSource, - int productId, int version, + public SdpDipRecord( + int specificationId, + int vendorId, + int vendorIdSource, + int productId, + int version, boolean primaryRecord) { super(); this.mSpecificationId = specificationId; @@ -91,12 +92,14 @@ public class SdpDipRecord implements Parcelable { return 0; } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpDipRecord createFromParcel(Parcel in) { - return new SdpDipRecord(in); - } - public SdpDipRecord[] newArray(int size) { - return new SdpDipRecord[size]; - } - }; + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SdpDipRecord createFromParcel(Parcel in) { + return new SdpDipRecord(in); + } + + public SdpDipRecord[] newArray(int size) { + return new SdpDipRecord[size]; + } + }; } diff --git a/framework/java/android/bluetooth/SdpMasRecord.java b/framework/java/android/bluetooth/SdpMasRecord.java index a964fe4632597d042b2257e1ccd38f957a72b339..d386d5c420007eda27f9303fcbdbcb28084587bd 100644 --- a/framework/java/android/bluetooth/SdpMasRecord.java +++ b/framework/java/android/bluetooth/SdpMasRecord.java @@ -1,17 +1,17 @@ /* -* Copyright (C) 2015 Samsung System LSI -* 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. -*/ + * Copyright (C) 2015 Samsung System LSI + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package android.bluetooth; import android.os.Parcel; @@ -35,7 +35,8 @@ public class SdpMasRecord implements Parcelable { public static final int MMS = 0x08; } - public SdpMasRecord(int masInstanceId, + public SdpMasRecord( + int masInstanceId, int l2capPsm, int rfcommChannelNumber, int profileVersion, @@ -139,13 +140,14 @@ public class SdpMasRecord implements Parcelable { return ret; } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpMasRecord createFromParcel(Parcel in) { - return new SdpMasRecord(in); - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SdpMasRecord createFromParcel(Parcel in) { + return new SdpMasRecord(in); + } - public SdpRecord[] newArray(int size) { - return new SdpRecord[size]; - } - }; + public SdpRecord[] newArray(int size) { + return new SdpRecord[size]; + } + }; } diff --git a/framework/java/android/bluetooth/SdpMnsRecord.java b/framework/java/android/bluetooth/SdpMnsRecord.java index 3178ebf444b7ffced88a8b4f56acb80ce247135a..898a7a886ac46269b89a801c68c3165acdcf7bcc 100644 --- a/framework/java/android/bluetooth/SdpMnsRecord.java +++ b/framework/java/android/bluetooth/SdpMnsRecord.java @@ -1,17 +1,17 @@ /* -* Copyright (C) 2015 Samsung System LSI -* 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. -*/ + * Copyright (C) 2015 Samsung System LSI + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package android.bluetooth; import android.os.Parcel; @@ -25,7 +25,8 @@ public class SdpMnsRecord implements Parcelable { private final int mProfileVersion; private final String mServiceName; - public SdpMnsRecord(int l2capPsm, + public SdpMnsRecord( + int l2capPsm, int rfcommChannelNumber, int profileVersion, int supportedFeatures, @@ -51,7 +52,6 @@ public class SdpMnsRecord implements Parcelable { return 0; } - public int getL2capPsm() { return mL2capPsm; } @@ -103,13 +103,14 @@ public class SdpMnsRecord implements Parcelable { return ret; } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpMnsRecord createFromParcel(Parcel in) { - return new SdpMnsRecord(in); - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SdpMnsRecord createFromParcel(Parcel in) { + return new SdpMnsRecord(in); + } - public SdpMnsRecord[] newArray(int size) { - return new SdpMnsRecord[size]; - } - }; + public SdpMnsRecord[] newArray(int size) { + return new SdpMnsRecord[size]; + } + }; } diff --git a/framework/java/android/bluetooth/SdpOppOpsRecord.java b/framework/java/android/bluetooth/SdpOppOpsRecord.java index e30745b898214fe0a79c0a0ed9d976b7a2328274..0b904f79d19f427b23b0378d4136ccf5554e2df0 100644 --- a/framework/java/android/bluetooth/SdpOppOpsRecord.java +++ b/framework/java/android/bluetooth/SdpOppOpsRecord.java @@ -1,17 +1,17 @@ /* -* Copyright (C) 2015 Samsung System LSI -* 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. -*/ + * Copyright (C) 2015 Samsung System LSI + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package android.bluetooth; import android.os.Parcel; @@ -19,9 +19,7 @@ import android.os.Parcelable; import java.util.Arrays; -/** - * Data representation of a Object Push Profile Server side SDP record. - */ +/** Data representation of a Object Push Profile Server side SDP record. */ /** @hide */ public class SdpOppOpsRecord implements Parcelable { @@ -32,8 +30,8 @@ public class SdpOppOpsRecord implements Parcelable { private final int mProfileVersion; private final byte[] mFormatsList; - public SdpOppOpsRecord(String serviceName, int rfcommChannel, - int l2capPsm, int version, byte[] formatsList) { + public SdpOppOpsRecord( + String serviceName, int rfcommChannel, int l2capPsm, int version, byte[] formatsList) { super(); mServiceName = serviceName; mRfcommChannel = rfcommChannel; @@ -108,14 +106,14 @@ public class SdpOppOpsRecord implements Parcelable { return sb.toString(); } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpOppOpsRecord createFromParcel(Parcel in) { - return new SdpOppOpsRecord(in); - } - - public SdpOppOpsRecord[] newArray(int size) { - return new SdpOppOpsRecord[size]; - } - }; + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SdpOppOpsRecord createFromParcel(Parcel in) { + return new SdpOppOpsRecord(in); + } + public SdpOppOpsRecord[] newArray(int size) { + return new SdpOppOpsRecord[size]; + } + }; } diff --git a/framework/java/android/bluetooth/SdpPseRecord.java b/framework/java/android/bluetooth/SdpPseRecord.java index 72249d0585c63f8fd08774bd9ae4de5f1b288bcd..56a92c47279dd55c5ace0917c31a08d134268ab8 100644 --- a/framework/java/android/bluetooth/SdpPseRecord.java +++ b/framework/java/android/bluetooth/SdpPseRecord.java @@ -1,17 +1,17 @@ /* -* Copyright (C) 2015 Samsung System LSI -* 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. -*/ + * Copyright (C) 2015 Samsung System LSI + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package android.bluetooth; @@ -27,7 +27,8 @@ public class SdpPseRecord implements Parcelable { private final int mSupportedRepositories; private final String mServiceName; - public SdpPseRecord(int l2capPsm, + public SdpPseRecord( + int l2capPsm, int rfcommChannelNumber, int profileVersion, int supportedFeatures, @@ -88,7 +89,6 @@ public class SdpPseRecord implements Parcelable { dest.writeInt(mSupportedFeatures); dest.writeInt(mSupportedRepositories); dest.writeString(mServiceName); - } @Override @@ -117,13 +117,14 @@ public class SdpPseRecord implements Parcelable { return ret; } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpPseRecord createFromParcel(Parcel in) { - return new SdpPseRecord(in); - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SdpPseRecord createFromParcel(Parcel in) { + return new SdpPseRecord(in); + } - public SdpPseRecord[] newArray(int size) { - return new SdpPseRecord[size]; - } - }; + public SdpPseRecord[] newArray(int size) { + return new SdpPseRecord[size]; + } + }; } diff --git a/framework/java/android/bluetooth/SdpRecord.java b/framework/java/android/bluetooth/SdpRecord.java index 730862ec6f914216a2f87a0ba581386dac1b1a64..d1eac9ff874a46fbd1bc1afbcb2242a055d47fbd 100644 --- a/framework/java/android/bluetooth/SdpRecord.java +++ b/framework/java/android/bluetooth/SdpRecord.java @@ -1,17 +1,17 @@ /* -* Copyright (C) 2015 Samsung System LSI -* 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. -*/ + * Copyright (C) 2015 Samsung System LSI + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package android.bluetooth; @@ -28,8 +28,11 @@ public class SdpRecord implements Parcelable { @Override public String toString() { - return "BluetoothSdpRecord [rawData=" + Arrays.toString(mRawData) - + ", rawSize=" + mRawSize + "]"; + return "BluetoothSdpRecord [rawData=" + + Arrays.toString(mRawData) + + ", rawSize=" + + mRawSize + + "]"; } public SdpRecord(int sizeRecord, byte[] record) { @@ -41,7 +44,6 @@ public class SdpRecord implements Parcelable { mRawSize = in.readInt(); mRawData = new byte[mRawSize]; in.readByteArray(mRawData); - } @Override @@ -53,19 +55,18 @@ public class SdpRecord implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mRawSize); dest.writeByteArray(mRawData); - - } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpRecord createFromParcel(Parcel in) { - return new SdpRecord(in); - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SdpRecord createFromParcel(Parcel in) { + return new SdpRecord(in); + } - public SdpRecord[] newArray(int size) { - return new SdpRecord[size]; - } - }; + public SdpRecord[] newArray(int size) { + return new SdpRecord[size]; + } + }; public byte[] getRawData() { return mRawData; diff --git a/framework/java/android/bluetooth/SdpSapsRecord.java b/framework/java/android/bluetooth/SdpSapsRecord.java index a1e2f7b51f35646a17f1ebb3e754a6d468e149be..fd567dd689bee282d800786a5205c7e196db9626 100644 --- a/framework/java/android/bluetooth/SdpSapsRecord.java +++ b/framework/java/android/bluetooth/SdpSapsRecord.java @@ -59,7 +59,6 @@ public class SdpSapsRecord implements Parcelable { dest.writeInt(mRfcommChannelNumber); dest.writeInt(mProfileVersion); dest.writeString(mServiceName); - } @Override @@ -78,13 +77,14 @@ public class SdpSapsRecord implements Parcelable { return ret; } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SdpSapsRecord createFromParcel(Parcel in) { - return new SdpSapsRecord(in); - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SdpSapsRecord createFromParcel(Parcel in) { + return new SdpSapsRecord(in); + } - public SdpRecord[] newArray(int size) { - return new SdpRecord[size]; - } - }; + public SdpRecord[] newArray(int size) { + return new SdpRecord[size]; + } + }; } diff --git a/framework/java/android/bluetooth/UidTraffic.java b/framework/java/android/bluetooth/UidTraffic.java index 58d9ad57874802e4864dbbf21d3266ee4a7b9676..581a0a857d03c118867e2dc51f8a43461a7e9bdb 100644 --- a/framework/java/android/bluetooth/UidTraffic.java +++ b/framework/java/android/bluetooth/UidTraffic.java @@ -109,19 +109,25 @@ public final class UidTraffic implements Cloneable, Parcelable { /** @hide */ @Override public String toString() { - return "UidTraffic{mAppUid=" + mAppUid + ", mRxBytes=" + mRxBytes + ", mTxBytes=" - + mTxBytes + '}'; + return "UidTraffic{mAppUid=" + + mAppUid + + ", mRxBytes=" + + mRxBytes + + ", mTxBytes=" + + mTxBytes + + '}'; } - public static final @NonNull Creator CREATOR = new Creator() { - @Override - public UidTraffic createFromParcel(Parcel source) { - return new UidTraffic(source); - } - - @Override - public UidTraffic[] newArray(int size) { - return new UidTraffic[size]; - } - }; + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public UidTraffic createFromParcel(Parcel source) { + return new UidTraffic(source); + } + + @Override + public UidTraffic[] newArray(int size) { + return new UidTraffic[size]; + } + }; } diff --git a/framework/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java b/framework/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java index c508c2c9ca0b09be3891c5ee7baff99ea47cf292..069d0b5caf90bc02586b0faad1173c7b2250ff68 100644 --- a/framework/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java +++ b/framework/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java @@ -27,13 +27,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, - * this requires the {@link Manifest.permission#BLUETOOTH_ADVERTISE} - * permission which can be gained with - * {@link android.app.Activity#requestPermissions(String[], int)}. + * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, this requires the + * {@link Manifest.permission#BLUETOOTH_ADVERTISE} permission which can be gained with {@link + * android.app.Activity#requestPermissions(String[], int)}. * @hide */ @Retention(SOURCE) @Target({METHOD, FIELD}) -public @interface RequiresBluetoothAdvertisePermission { -} +@SuppressWarnings("InvalidBlockTag") +public @interface RequiresBluetoothAdvertisePermission {} diff --git a/framework/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java b/framework/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java index e159eaafe2e48aa6edb0a30dc331a3a9afd0c452..75503df9b4d15aeebd8fe60470d8f4e22b29debc 100644 --- a/framework/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java +++ b/framework/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java @@ -27,13 +27,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, - * this requires the {@link Manifest.permission#BLUETOOTH_CONNECT} - * permission which can be gained with - * {@link android.app.Activity#requestPermissions(String[], int)}. + * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, this requires the + * {@link Manifest.permission#BLUETOOTH_CONNECT} permission which can be gained with {@link + * android.app.Activity#requestPermissions(String[], int)}. * @hide */ @Retention(SOURCE) @Target({METHOD, FIELD}) -public @interface RequiresBluetoothConnectPermission { -} +@SuppressWarnings("InvalidBlockTag") +public @interface RequiresBluetoothConnectPermission {} diff --git a/framework/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java b/framework/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java index 2bb320413941e98f86b56a638c0e6d522b0a1484..d91f7b64a063d888eeeba1a6a9dc6f877559cde1 100644 --- a/framework/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java +++ b/framework/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java @@ -26,16 +26,14 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * @memberDoc In addition, this requires either the - * {@link Manifest.permission#ACCESS_FINE_LOCATION} - * permission or a strong assertion that you will never derive the - * physical location of the device. You can make this assertion by - * declaring {@code usesPermissionFlags="neverForLocation"} on the - * relevant {@code } manifest tag, but it may - * restrict the types of Bluetooth devices you can interact with. + * @memberDoc In addition, this requires either the {@link Manifest.permission#ACCESS_FINE_LOCATION} + * permission or a strong assertion that you will never derive the physical location of the + * device. You can make this assertion by declaring {@code + * usesPermissionFlags="neverForLocation"} on the relevant {@code } manifest + * tag, but it may restrict the types of Bluetooth devices you can interact with. * @hide */ @Retention(SOURCE) @Target({METHOD, FIELD}) -public @interface RequiresBluetoothLocationPermission { -} +@SuppressWarnings("InvalidBlockTag") +public @interface RequiresBluetoothLocationPermission {} diff --git a/framework/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java b/framework/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java index 800ff39933f2ceccdc0f83ff2d4de271f54819f4..c5d844fe684ebf483e66562443b48898599e1f52 100644 --- a/framework/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java +++ b/framework/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java @@ -27,13 +27,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, - * this requires the {@link Manifest.permission#BLUETOOTH_SCAN} - * permission which can be gained with - * {@link android.app.Activity#requestPermissions(String[], int)}. + * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher, this requires the + * {@link Manifest.permission#BLUETOOTH_SCAN} permission which can be gained with {@link + * android.app.Activity#requestPermissions(String[], int)}. * @hide */ @Retention(SOURCE) @Target({METHOD, FIELD}) -public @interface RequiresBluetoothScanPermission { -} +@SuppressWarnings("InvalidBlockTag") +public @interface RequiresBluetoothScanPermission {} diff --git a/framework/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java b/framework/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java index 9adf695cde0f01ef0a50ac897993d4529471cc85..cc4a260b02c50949052898f4f367f94cbd48e442 100644 --- a/framework/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java +++ b/framework/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java @@ -27,13 +27,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this - * requires the {@link Manifest.permission#BLUETOOTH_ADMIN} - * permission which can be gained with a simple - * {@code } manifest tag. + * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this requires the {@link + * Manifest.permission#BLUETOOTH_ADMIN} permission which can be gained with a simple {@code + * } manifest tag. * @hide */ @Retention(SOURCE) @Target({METHOD, FIELD}) -public @interface RequiresLegacyBluetoothAdminPermission { -} +@SuppressWarnings("InvalidBlockTag") +public @interface RequiresLegacyBluetoothAdminPermission {} diff --git a/framework/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java b/framework/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java index 79621c366f591b9e8fc507cfc0d80bf88d4d28c6..4482e901f571bd97f7fafff92c09669487a0d7c5 100644 --- a/framework/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java +++ b/framework/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java @@ -27,13 +27,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this - * requires the {@link Manifest.permission#BLUETOOTH} permission - * which can be gained with a simple {@code } - * manifest tag. + * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this requires the {@link + * Manifest.permission#BLUETOOTH} permission which can be gained with a simple {@code + * } manifest tag. * @hide */ @Retention(SOURCE) @Target({METHOD, FIELD}) -public @interface RequiresLegacyBluetoothPermission { -} +@SuppressWarnings("InvalidBlockTag") +public @interface RequiresLegacyBluetoothPermission {} diff --git a/framework/java/android/bluetooth/le/AdvertiseCallback.java b/framework/java/android/bluetooth/le/AdvertiseCallback.java index 4fa8c4f2f5393efb0ec054ff15adb05a4a4c44b2..c4d6496d6c550134081de25c2af7e6c2a0e53081 100644 --- a/framework/java/android/bluetooth/le/AdvertiseCallback.java +++ b/framework/java/android/bluetooth/le/AdvertiseCallback.java @@ -16,9 +16,7 @@ package android.bluetooth.le; -/** - * Bluetooth LE advertising callbacks, used to deliver advertising operation status. - */ +/** Bluetooth LE advertising callbacks, used to deliver advertising operation status. */ public abstract class AdvertiseCallback { /** @@ -33,24 +31,16 @@ public abstract class AdvertiseCallback { */ public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1; - /** - * Failed to start advertising because no advertising instance is available. - */ + /** Failed to start advertising because no advertising instance is available. */ public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2; - /** - * Failed to start advertising as the advertising is already started. - */ + /** Failed to start advertising as the advertising is already started. */ public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3; - /** - * Operation failed due to an internal error. - */ + /** Operation failed due to an internal error. */ public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4; - /** - * This feature is not supported on this platform. - */ + /** This feature is not supported on this platform. */ public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5; /** @@ -58,17 +48,15 @@ public abstract class AdvertiseCallback { * that the advertising has been started successfully. * * @param settingsInEffect The actual settings used for advertising, which may be different from - * what has been requested. + * what has been requested. */ - public void onStartSuccess(AdvertiseSettings settingsInEffect) { - } + public void onStartSuccess(AdvertiseSettings settingsInEffect) {} /** * Callback when advertising could not be started. * * @param errorCode Error code (see ADVERTISE_FAILED_* constants) for advertising start - * failures. + * failures. */ - public void onStartFailure(int errorCode) { - } + public void onStartFailure(int errorCode) {} } diff --git a/framework/java/android/bluetooth/le/AdvertiseData.java b/framework/java/android/bluetooth/le/AdvertiseData.java index fdf62ec3a647082045f98289a68fe979446bcfd0..99335d35d72d4a7afbfebc9bdb5dbbfdeec1ab91 100644 --- a/framework/java/android/bluetooth/le/AdvertiseData.java +++ b/framework/java/android/bluetooth/le/AdvertiseData.java @@ -33,8 +33,8 @@ import java.util.Objects; /** * Advertise data packet container for Bluetooth LE advertising. This represents the data to be * advertised as well as the scan response data for active scans. - *

    - * Use {@link AdvertiseData.Builder} to create an instance of {@link AdvertiseData} to be + * + *

    Use {@link AdvertiseData.Builder} to create an instance of {@link AdvertiseData} to be * advertised. * * @see BluetoothLeAdvertiser @@ -42,21 +42,19 @@ import java.util.Objects; */ public final class AdvertiseData implements Parcelable { - @Nullable - private final List mServiceUuids; + @Nullable private final List mServiceUuids; - @NonNull - private final List mServiceSolicitationUuids; + @NonNull private final List mServiceSolicitationUuids; - @Nullable - private final List mTransportDiscoveryData; + @Nullable private final List mTransportDiscoveryData; private final SparseArray mManufacturerSpecificData; private final Map mServiceData; private final boolean mIncludeTxPowerLevel; private final boolean mIncludeDeviceName; - private AdvertiseData(List serviceUuids, + private AdvertiseData( + List serviceUuids, List serviceSolicitationUuids, List transportDiscoveryData, SparseArray manufacturerData, @@ -81,16 +79,15 @@ public final class AdvertiseData implements Parcelable { } /** - * Returns a list of service solicitation UUIDs within the advertisement that we invite to connect. + * Returns a list of service solicitation UUIDs within the advertisement that we invite to + * connect. */ @NonNull public List getServiceSolicitationUuids() { return mServiceSolicitationUuids; } - /** - * Returns a list of {@link TransportDiscoveryData} within the advertisement. - */ + /** Returns a list of {@link TransportDiscoveryData} within the advertisement. */ @NonNull public List getTransportDiscoveryData() { if (mTransportDiscoveryData == null) { @@ -107,39 +104,35 @@ public final class AdvertiseData implements Parcelable { return mManufacturerSpecificData; } - /** - * Returns a map of 16-bit UUID and its corresponding service data. - */ + /** Returns a map of 16-bit UUID and its corresponding service data. */ public Map getServiceData() { return mServiceData; } - /** - * Whether the transmission power level will be included in the advertisement packet. - */ + /** Whether the transmission power level will be included in the advertisement packet. */ public boolean getIncludeTxPowerLevel() { return mIncludeTxPowerLevel; } - /** - * Whether the device name will be included in the advertisement packet. - */ + /** Whether the device name will be included in the advertisement packet. */ public boolean getIncludeDeviceName() { return mIncludeDeviceName; } - /** - * @hide - */ + /** @hide */ @Override public int hashCode() { - return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mTransportDiscoveryData, - mManufacturerSpecificData, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel); + return Objects.hash( + mServiceUuids, + mServiceSolicitationUuids, + mTransportDiscoveryData, + mManufacturerSpecificData, + mServiceData, + mIncludeDeviceName, + mIncludeTxPowerLevel); } - /** - * @hide - */ + /** @hide */ @Override public boolean equals(@Nullable Object obj) { if (this == obj) { @@ -152,8 +145,8 @@ public final class AdvertiseData implements Parcelable { return Objects.equals(mServiceUuids, other.mServiceUuids) && Objects.equals(mServiceSolicitationUuids, other.mServiceSolicitationUuids) && Objects.equals(mTransportDiscoveryData, other.mTransportDiscoveryData) - && BluetoothLeUtils.equals(mManufacturerSpecificData, - other.mManufacturerSpecificData) + && BluetoothLeUtils.equals( + mManufacturerSpecificData, other.mManufacturerSpecificData) && BluetoothLeUtils.equals(mServiceData, other.mServiceData) && mIncludeDeviceName == other.mIncludeDeviceName && mIncludeTxPowerLevel == other.mIncludeTxPowerLevel; @@ -161,13 +154,21 @@ public final class AdvertiseData implements Parcelable { @Override public String toString() { - return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids=" - + mServiceSolicitationUuids + ", mTransportDiscoveryData=" - + mTransportDiscoveryData + ", mManufacturerSpecificData=" - + BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData=" + return "AdvertiseData [mServiceUuids=" + + mServiceUuids + + ", mServiceSolicitationUuids=" + + mServiceSolicitationUuids + + ", mTransportDiscoveryData=" + + mTransportDiscoveryData + + ", mManufacturerSpecificData=" + + BluetoothLeUtils.toString(mManufacturerSpecificData) + + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData) - + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName=" - + mIncludeDeviceName + "]"; + + ", mIncludeTxPowerLevel=" + + mIncludeTxPowerLevel + + ", mIncludeDeviceName=" + + mIncludeDeviceName + + "]"; } @Override @@ -178,8 +179,9 @@ public final class AdvertiseData implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeTypedArray(mServiceUuids.toArray(new ParcelUuid[mServiceUuids.size()]), flags); - dest.writeTypedArray(mServiceSolicitationUuids.toArray( - new ParcelUuid[mServiceSolicitationUuids.size()]), flags); + dest.writeTypedArray( + mServiceSolicitationUuids.toArray(new ParcelUuid[mServiceSolicitationUuids.size()]), + flags); dest.writeTypedList(mTransportDiscoveryData); @@ -213,7 +215,8 @@ public final class AdvertiseData implements Parcelable { builder.addServiceUuid(uuid); } - ArrayList solicitationUuids = in.createTypedArrayList(ParcelUuid.CREATOR); + ArrayList solicitationUuids = + in.createTypedArrayList(ParcelUuid.CREATOR); for (ParcelUuid uuid : solicitationUuids) { builder.addServiceSolicitationUuid(uuid); } @@ -242,17 +245,15 @@ public final class AdvertiseData implements Parcelable { } }; - /** - * Builder for {@link AdvertiseData}. - */ + /** Builder for {@link AdvertiseData}. */ public static final class Builder { - @Nullable - private List mServiceUuids = new ArrayList(); - @NonNull - private List mServiceSolicitationUuids = new ArrayList(); + @Nullable private List mServiceUuids = new ArrayList(); + @NonNull private List mServiceSolicitationUuids = new ArrayList(); + @Nullable private List mTransportDiscoveryData = new ArrayList(); + private SparseArray mManufacturerSpecificData = new SparseArray(); private Map mServiceData = new ArrayMap(); private boolean mIncludeTxPowerLevel; @@ -293,12 +294,11 @@ public final class AdvertiseData implements Parcelable { * @param serviceDataUuid 16-bit UUID of the service the data is associated with * @param serviceData Service data * @throws IllegalArgumentException If the {@code serviceDataUuid} or {@code serviceData} is - * empty. + * empty. */ public Builder addServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) { if (serviceDataUuid == null || serviceData == null) { - throw new IllegalArgumentException( - "serviceDataUuid or serviceDataUuid is null"); + throw new IllegalArgumentException("serviceDataUuid or serviceDataUuid is null"); } mServiceData.put(serviceDataUuid, serviceData); return this; @@ -308,7 +308,7 @@ public final class AdvertiseData implements Parcelable { * Add Transport Discovery Data to advertise data. * * @param transportDiscoveryData Transport Discovery Data, consisting of one or more - * Transport Blocks. Transport Discovery Data AD Type Code is already included. + * Transport Blocks. Transport Discovery Data AD Type Code is already included. * @throws IllegalArgumentException If the {@code transportDiscoveryData} is empty */ @NonNull @@ -323,20 +323,19 @@ public final class AdvertiseData implements Parcelable { /** * Add manufacturer specific data. - *

    - * Please refer to the Bluetooth Assigned Numbers document provided by the Please refer to the Bluetooth Assigned Numbers document provided by the Bluetooth SIG for a list of existing company * identifiers. * * @param manufacturerId Manufacturer ID assigned by Bluetooth SIG. * @param manufacturerSpecificData Manufacturer specific data * @throws IllegalArgumentException If the {@code manufacturerId} is negative or {@code - * manufacturerSpecificData} is null. + * manufacturerSpecificData} is null. */ public Builder addManufacturerData(int manufacturerId, byte[] manufacturerSpecificData) { if (manufacturerId < 0) { - throw new IllegalArgumentException( - "invalid manufacturerId - " + manufacturerId); + throw new IllegalArgumentException("invalid manufacturerId - " + manufacturerId); } if (manufacturerSpecificData == null) { throw new IllegalArgumentException("manufacturerSpecificData is null"); @@ -354,21 +353,22 @@ public final class AdvertiseData implements Parcelable { return this; } - /** - * Set whether the device name should be included in advertise packet. - */ + /** Set whether the device name should be included in advertise packet. */ public Builder setIncludeDeviceName(boolean includeDeviceName) { mIncludeDeviceName = includeDeviceName; return this; } - /** - * Build the {@link AdvertiseData}. - */ + /** Build the {@link AdvertiseData}. */ public AdvertiseData build() { - return new AdvertiseData(mServiceUuids, mServiceSolicitationUuids, - mTransportDiscoveryData, mManufacturerSpecificData, mServiceData, - mIncludeTxPowerLevel, mIncludeDeviceName); + return new AdvertiseData( + mServiceUuids, + mServiceSolicitationUuids, + mTransportDiscoveryData, + mManufacturerSpecificData, + mServiceData, + mIncludeTxPowerLevel, + mIncludeDeviceName); } } } diff --git a/framework/java/android/bluetooth/le/AdvertiseSettings.java b/framework/java/android/bluetooth/le/AdvertiseSettings.java index e796973ecba8b874f5a469f92aff6fc9126eed7a..d0ec495334f88034505e3f687d67a50537f233d2 100644 --- a/framework/java/android/bluetooth/le/AdvertiseSettings.java +++ b/framework/java/android/bluetooth/le/AdvertiseSettings.java @@ -21,13 +21,16 @@ import android.annotation.SystemApi; import android.bluetooth.le.AdvertisingSetParameters.AddressTypeStatus; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; /** - * The {@link AdvertiseSettings} provide a way to adjust advertising preferences for each - * Bluetooth LE advertisement instance. Use {@link AdvertiseSettings.Builder} to create an - * instance of this class. + * The {@link AdvertiseSettings} provide a way to adjust advertising preferences for each Bluetooth + * LE advertisement instance. Use {@link AdvertiseSettings.Builder} to create an instance of this + * class. */ public final class AdvertiseSettings implements Parcelable { + private static final String TAG = AdvertiseSettings.class.getSimpleName(); + /** * Perform Bluetooth LE advertising in low power mode. This is the default and preferred * advertising mode as it consumes the least power. @@ -52,14 +55,10 @@ public final class AdvertiseSettings implements Parcelable { */ public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0; - /** - * Advertise using low TX power level. - */ + /** Advertise using low TX power level. */ public static final int ADVERTISE_TX_POWER_LOW = 1; - /** - * Advertise using medium TX power level. - */ + /** Advertise using medium TX power level. */ public static final int ADVERTISE_TX_POWER_MEDIUM = 2; /** @@ -68,12 +67,9 @@ public final class AdvertiseSettings implements Parcelable { */ public static final int ADVERTISE_TX_POWER_HIGH = 3; - /** - * The maximum limited advertisement duration as specified by the Bluetooth SIG - */ + /** The maximum limited advertisement duration as specified by the Bluetooth SIG */ private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000; - private final int mAdvertiseMode; private final int mAdvertiseTxPowerLevel; private final int mAdvertiseTimeoutMillis; @@ -105,23 +101,17 @@ public final class AdvertiseSettings implements Parcelable { mAdvertiseDiscoverable = in.readInt() != 0; } - /** - * Returns the advertise mode. - */ + /** Returns the advertise mode. */ public int getMode() { return mAdvertiseMode; } - /** - * Returns the TX power level for advertising. - */ + /** Returns the TX power level for advertising. */ public int getTxPowerLevel() { return mAdvertiseTxPowerLevel; } - /** - * Returns whether the advertisement will indicate connectable. - */ + /** Returns whether the advertisement will indicate connectable. */ public boolean isConnectable() { return mAdvertiseConnectable; } @@ -131,16 +121,13 @@ public final class AdvertiseSettings implements Parcelable { return mAdvertiseDiscoverable; } - /** - * Returns the advertising time limit in milliseconds. - */ + /** Returns the advertising time limit in milliseconds. */ public int getTimeout() { return mAdvertiseTimeoutMillis; } /** * @return the own address type for advertising - * * @hide */ @SystemApi @@ -150,12 +137,19 @@ public final class AdvertiseSettings implements Parcelable { @Override public String toString() { - return "Settings [mAdvertiseMode=" + mAdvertiseMode - + ", mAdvertiseTxPowerLevel=" + mAdvertiseTxPowerLevel - + ", mAdvertiseConnectable=" + mAdvertiseConnectable - + ", mAdvertiseDiscoverable=" + mAdvertiseDiscoverable - + ", mAdvertiseTimeoutMillis=" + mAdvertiseTimeoutMillis - + ", mOwnAddressType=" + mOwnAddressType + "]"; + return "Settings [mAdvertiseMode=" + + mAdvertiseMode + + ", mAdvertiseTxPowerLevel=" + + mAdvertiseTxPowerLevel + + ", mAdvertiseConnectable=" + + mAdvertiseConnectable + + ", mAdvertiseDiscoverable=" + + mAdvertiseDiscoverable + + ", mAdvertiseTimeoutMillis=" + + mAdvertiseTimeoutMillis + + ", mOwnAddressType=" + + mOwnAddressType + + "]"; } @Override @@ -186,9 +180,7 @@ public final class AdvertiseSettings implements Parcelable { } }; - /** - * Builder class for {@link AdvertiseSettings}. - */ + /** Builder class for {@link AdvertiseSettings}. */ public static final class Builder { private int mMode = ADVERTISE_MODE_LOW_POWER; private int mTxPowerLevel = ADVERTISE_TX_POWER_MEDIUM; @@ -201,9 +193,9 @@ public final class AdvertiseSettings implements Parcelable { * Set advertise mode to control the advertising power and latency. * * @param advertiseMode Bluetooth LE Advertising mode, can only be one of {@link - * AdvertiseSettings#ADVERTISE_MODE_LOW_POWER}, - * {@link AdvertiseSettings#ADVERTISE_MODE_BALANCED}, - * or {@link AdvertiseSettings#ADVERTISE_MODE_LOW_LATENCY}. + * AdvertiseSettings#ADVERTISE_MODE_LOW_POWER}, {@link + * AdvertiseSettings#ADVERTISE_MODE_BALANCED}, or {@link + * AdvertiseSettings#ADVERTISE_MODE_LOW_LATENCY}. * @throws IllegalArgumentException If the advertiseMode is invalid. */ public Builder setAdvertiseMode(int advertiseMode) { @@ -219,10 +211,10 @@ public final class AdvertiseSettings implements Parcelable { * Set advertise TX power level to control the transmission power level for the advertising. * * @param txPowerLevel Transmission power of Bluetooth LE Advertising, can only be one of - * {@link AdvertiseSettings#ADVERTISE_TX_POWER_ULTRA_LOW}, {@link - * AdvertiseSettings#ADVERTISE_TX_POWER_LOW}, - * {@link AdvertiseSettings#ADVERTISE_TX_POWER_MEDIUM} - * or {@link AdvertiseSettings#ADVERTISE_TX_POWER_HIGH}. + * {@link AdvertiseSettings#ADVERTISE_TX_POWER_ULTRA_LOW}, {@link + * AdvertiseSettings#ADVERTISE_TX_POWER_LOW}, {@link + * AdvertiseSettings#ADVERTISE_TX_POWER_MEDIUM} or {@link + * AdvertiseSettings#ADVERTISE_TX_POWER_HIGH}. * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid. */ public Builder setTxPowerLevel(int txPowerLevel) { @@ -230,6 +222,7 @@ public final class AdvertiseSettings implements Parcelable { || txPowerLevel > ADVERTISE_TX_POWER_HIGH) { throw new IllegalArgumentException("unknown tx power level " + txPowerLevel); } + Log.d(TAG, "setTxPowerLevel: " + txPowerLevel); mTxPowerLevel = txPowerLevel; return this; } @@ -237,8 +230,8 @@ public final class AdvertiseSettings implements Parcelable { /** * Set whether the advertisement type should be connectable or non-connectable. * - * @param connectable Controls whether the advertisment type will be connectable (true) or - * non-connectable (false). + * @param connectable Controls whether the advertisement type will be connectable (true) or + * non-connectable (false). */ public Builder setConnectable(boolean connectable) { mConnectable = connectable; @@ -248,8 +241,8 @@ public final class AdvertiseSettings implements Parcelable { /** * Set whether the advertisement type should be discoverable or non-discoverable. * - * @param discoverable Controls whether the advertisment type will be discoverable - * ({@code true}) or non-discoverable ({@code false}). + * @param discoverable Controls whether the advertisement type will be discoverable ({@code + * true}) or non-discoverable ({@code false}). */ public @NonNull Builder setDiscoverable(boolean discoverable) { mDiscoverable = discoverable; @@ -260,13 +253,15 @@ public final class AdvertiseSettings implements Parcelable { * Limit advertising to a given amount of time. * * @param timeoutMillis Advertising time limit. May not exceed 180000 milliseconds. A value - * of 0 will disable the time limit. + * of 0 will disable the time limit. * @throws IllegalArgumentException If the provided timeout is over 180000 ms. */ public Builder setTimeout(int timeoutMillis) { if (timeoutMillis < 0 || timeoutMillis > LIMITED_ADVERTISING_MAX_MILLIS) { - throw new IllegalArgumentException("timeoutMillis invalid (must be 0-" - + LIMITED_ADVERTISING_MAX_MILLIS + " milliseconds)"); + throw new IllegalArgumentException( + "timeoutMillis invalid (must be 0-" + + LIMITED_ADVERTISING_MAX_MILLIS + + " milliseconds)"); } mTimeoutMillis = timeoutMillis; return this; @@ -275,11 +270,10 @@ public final class AdvertiseSettings implements Parcelable { /** * Set own address type for advertising to control public or privacy mode. If used to set * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT}, - * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the - * time of starting advertising. + * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the time of + * starting advertising. * * @throws IllegalArgumentException If the {@code ownAddressType} is invalid - * * @hide */ @SystemApi @@ -293,9 +287,7 @@ public final class AdvertiseSettings implements Parcelable { return this; } - /** - * Build the {@link AdvertiseSettings} object. - */ + /** Build the {@link AdvertiseSettings} object. */ public AdvertiseSettings build() { return new AdvertiseSettings( mMode, diff --git a/framework/java/android/bluetooth/le/AdvertisingSet.java b/framework/java/android/bluetooth/le/AdvertisingSet.java index 2c5f4dba26a688f4911da1e9817fe558a00a0c37..299f0b900e4fddb6ea508297e1107fac37b3f800 100644 --- a/framework/java/android/bluetooth/le/AdvertisingSet.java +++ b/framework/java/android/bluetooth/le/AdvertisingSet.java @@ -18,12 +18,13 @@ package android.bluetooth.le; import static android.bluetooth.le.BluetoothLeUtils.getSyncTimeout; +import static java.util.Objects.requireNonNull; + import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.bluetooth.BluetoothAdapter; import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.content.AttributionSource; @@ -36,9 +37,9 @@ import java.util.concurrent.TimeoutException; /** * This class provides a way to control single Bluetooth LE advertising instance. - *

    - * To get an instance of {@link AdvertisingSet}, call the - * {@link BluetoothLeAdvertiser#startAdvertisingSet} method. + * + *

    To get an instance of {@link AdvertisingSet}, call the {@link + * BluetoothLeAdvertiser#startAdvertisingSet} method. * * @see AdvertiseData */ @@ -49,16 +50,13 @@ public final class AdvertisingSet { private int mAdvertiserId; private AttributionSource mAttributionSource; - /* package */ AdvertisingSet(int advertiserId, IBluetoothManager bluetoothManager, + /* package */ AdvertisingSet( + int advertiserId, + BluetoothAdapter bluetoothAdapter, AttributionSource attributionSource) { mAdvertiserId = advertiserId; mAttributionSource = attributionSource; - try { - mGatt = bluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - throw new IllegalStateException("Failed to get Bluetooth"); - } + mGatt = requireNonNull(bluetoothAdapter.getBluetoothGatt(), "Failed to get Bluetooth gatt"); } /* package */ void setAdvertiserId(int advertiserId) { @@ -66,25 +64,29 @@ public final class AdvertisingSet { } /** - * Enables Advertising. This method returns immediately, the operation status is - * delivered through {@code callback.onAdvertisingEnabled()}. + * Enables Advertising. This method returns immediately, the operation status is delivered + * through {@code callback.onAdvertisingEnabled()}. * * @param enable whether the advertising should be enabled (true), or disabled (false) * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535 - * (655,350 ms) + * (655,350 ms) * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the - * controller shall attempt to send prior to terminating the extended advertising, even if the - * duration has not expired. Valid range is from 1 to 255. + * controller shall attempt to send prior to terminating the extended advertising, even if + * the duration has not expired. Valid range is from 1 to 255. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void enableAdvertising(boolean enable, int duration, - int maxExtendedAdvertisingEvents) { + public void enableAdvertising(boolean enable, int duration, int maxExtendedAdvertisingEvents) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mGatt.enableAdvertisingSet(mAdvertiserId, enable, duration, - maxExtendedAdvertisingEvents, mAttributionSource, recv); + mGatt.enableAdvertisingSet( + mAdvertiserId, + enable, + duration, + maxExtendedAdvertisingEvents, + mAttributionSource, + recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (TimeoutException | RemoteException e) { Log.e(TAG, "remote exception - ", e); @@ -95,13 +97,13 @@ public final class AdvertisingSet { * Set/update data being Advertised. Make sure that data doesn't exceed the size limit for * specified AdvertisingSetParameters. This method returns immediately, the operation status is * delivered through {@code callback.onAdvertisingDataSet()}. - *

    - * Advertising data must be empty if non-legacy scannable advertising is used. + * + *

    Advertising data must be empty if non-legacy scannable advertising is used. * * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. If the update takes place when the advertising set is - * enabled, the data can be maximum 251 bytes long. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, + * three bytes will be added for flags. If the update takes place when the advertising set + * is enabled, the data can be maximum 251 bytes long. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @@ -118,12 +120,12 @@ public final class AdvertisingSet { /** * Set/update scan response data. Make sure that data doesn't exceed the size limit for - * specified AdvertisingSetParameters. This method returns immediately, the operation status - * is delivered through {@code callback.onScanResponseDataSet()}. + * specified AdvertisingSetParameters. This method returns immediately, the operation status is + * delivered through {@code callback.onScanResponseDataSet()}. * * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place - * when the advertising set is enabled, the data can be maximum 251 bytes long. + * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes + * place when the advertising set is enabled, the data can be maximum 251 bytes long. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @@ -159,9 +161,9 @@ public final class AdvertisingSet { } /** - * Update periodic advertising parameters associated with this set. Must be called when - * periodic advertising is not enabled. This method returns immediately, the operation - * status is delivered through {@code callback.onPeriodicAdvertisingParametersUpdated()}. + * Update periodic advertising parameters associated with this set. Must be called when periodic + * advertising is not enabled. This method returns immediately, the operation status is + * delivered through {@code callback.onPeriodicAdvertisingParametersUpdated()}. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @@ -169,8 +171,8 @@ public final class AdvertisingSet { public void setPeriodicAdvertisingParameters(PeriodicAdvertisingParameters parameters) { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mGatt.setPeriodicAdvertisingParameters(mAdvertiserId, parameters, mAttributionSource, - recv); + mGatt.setPeriodicAdvertisingParameters( + mAdvertiserId, parameters, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (TimeoutException | RemoteException e) { Log.e(TAG, "remote exception - ", e); @@ -180,12 +182,12 @@ public final class AdvertisingSet { /** * Used to set periodic advertising data, must be called after setPeriodicAdvertisingParameters, * or after advertising was started with periodic advertising data set. This method returns - * immediately, the operation status is delivered through - * {@code callback.onPeriodicAdvertisingDataSet()}. + * immediately, the operation status is delivered through {@code + * callback.onPeriodicAdvertisingDataSet()}. * * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place when the - * periodic advertising is enabled for this set, the data can be maximum 251 bytes long. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place when the + * periodic advertising is enabled for this set, the data can be maximum 251 bytes long. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @@ -204,8 +206,7 @@ public final class AdvertisingSet { * Used to enable/disable periodic advertising. This method returns immediately, the operation * status is delivered through {@code callback.onPeriodicAdvertisingEnable()}. * - * @param enable whether the periodic advertising should be enabled (true), or disabled - * (false). + * @param enable whether the periodic advertising should be enabled (true), or disabled (false). */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @@ -221,17 +222,17 @@ public final class AdvertisingSet { } /** - * Returns address associated with this advertising set. - * This method is exposed only for Bluetooth PTS tests, no app or system service - * should ever use it. + * Returns address associated with this advertising set. This method is exposed only for + * Bluetooth PTS tests, no app or system service should ever use it. * * @hide */ @RequiresBluetoothAdvertisePermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_ADVERTISE, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_ADVERTISE, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public void getOwnAddress() { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); diff --git a/framework/java/android/bluetooth/le/AdvertisingSetCallback.java b/framework/java/android/bluetooth/le/AdvertisingSetCallback.java index 51324fdb01ffeed6c306ae37fa1634c8dc50f55a..6031b1d4e844f7ad9241d002c9de1e2d1dfefbce 100644 --- a/framework/java/android/bluetooth/le/AdvertisingSetCallback.java +++ b/framework/java/android/bluetooth/le/AdvertisingSetCallback.java @@ -16,64 +16,46 @@ package android.bluetooth.le; -/** - * Bluetooth LE advertising set callbacks, used to deliver advertising operation - * status. - */ +/** Bluetooth LE advertising set callbacks, used to deliver advertising operation status. */ public abstract class AdvertisingSetCallback { - /** - * The requested operation was successful. - */ + /** The requested operation was successful. */ public static final int ADVERTISE_SUCCESS = 0; - /** - * Failed to start advertising as the advertise data to be broadcasted is too - * large. - */ + /** Failed to start advertising as the advertise data to be broadcasted is too large. */ public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1; - /** - * Failed to start advertising because no advertising instance is available. - */ + /** Failed to start advertising because no advertising instance is available. */ public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2; - /** - * Failed to start advertising as the advertising is already started. - */ + /** Failed to start advertising as the advertising is already started. */ public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3; - /** - * Operation failed due to an internal error. - */ + /** Operation failed due to an internal error. */ public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4; - /** - * This feature is not supported on this platform. - */ + /** This feature is not supported on this platform. */ public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5; /** * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet} * indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertisingSet - * contains the started set and it is advertising. If error occurred, advertisingSet is - * null, and status will be set to proper error code. + * contains the started set and it is advertising. If error occurred, advertisingSet is null, + * and status will be set to proper error code. * * @param advertisingSet The advertising set that was started or null if error. * @param txPower tx power that will be used for this set. * @param status Status of the operation. */ - public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) { - } + public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {} /** - * Callback triggered in response to {@link BluetoothLeAdvertiser#stopAdvertisingSet} - * indicating advertising set is stopped. + * Callback triggered in response to {@link BluetoothLeAdvertiser#stopAdvertisingSet} indicating + * advertising set is stopped. * * @param advertisingSet The advertising set. */ - public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) { - } + public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {} /** * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet} @@ -83,40 +65,36 @@ public abstract class AdvertisingSetCallback { * @param advertisingSet The advertising set. * @param status Status of the operation. */ - public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, int status) { - } + public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, int status) {} /** - * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating - * result of the operation. If status is ADVERTISE_SUCCESS, then data was changed. + * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating result + * of the operation. If status is ADVERTISE_SUCCESS, then data was changed. * * @param advertisingSet The advertising set. * @param status Status of the operation. */ - public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) { - } + public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {} /** - * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating - * result of the operation. + * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating result + * of the operation. * * @param advertisingSet The advertising set. * @param status Status of the operation. */ - public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) { - } + public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {} /** - * Callback triggered in response to {@link AdvertisingSet#setAdvertisingParameters} - * indicating result of the operation. + * Callback triggered in response to {@link AdvertisingSet#setAdvertisingParameters} indicating + * result of the operation. * * @param advertisingSet The advertising set. * @param txPower tx power that will be used for this set. * @param status Status of the operation. */ - public void onAdvertisingParametersUpdated(AdvertisingSet advertisingSet, - int txPower, int status) { - } + public void onAdvertisingParametersUpdated( + AdvertisingSet advertisingSet, int txPower, int status) {} /** * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingParameters} @@ -125,8 +103,7 @@ public abstract class AdvertisingSetCallback { * @param advertisingSet The advertising set. * @param status Status of the operation. */ - public void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet, int status) { - } + public void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet, int status) {} /** * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingData} @@ -135,9 +112,7 @@ public abstract class AdvertisingSetCallback { * @param advertisingSet The advertising set. * @param status Status of the operation. */ - public void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet, - int status) { - } + public void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {} /** * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnabled} @@ -146,19 +121,17 @@ public abstract class AdvertisingSetCallback { * @param advertisingSet The advertising set. * @param status Status of the operation. */ - public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, - int status) { - } + public void onPeriodicAdvertisingEnabled( + AdvertisingSet advertisingSet, boolean enable, int status) {} /** - * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()} - * indicating result of the operation. + * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()} indicating result of + * the operation. * * @param advertisingSet The advertising set. * @param addressType type of address. * @param address advertising set bluetooth address. * @hide */ - public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) { - } + public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) {} } diff --git a/framework/java/android/bluetooth/le/AdvertisingSetParameters.java b/framework/java/android/bluetooth/le/AdvertisingSetParameters.java index 9216fea2bc518fc4bc705e1d7ac999b89757dd8d..e614109299ef55e3948b2719a1444f232dcfda98 100644 --- a/framework/java/android/bluetooth/le/AdvertisingSetParameters.java +++ b/framework/java/android/bluetooth/le/AdvertisingSetParameters.java @@ -28,88 +28,69 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * The {@link AdvertisingSetParameters} provide a way to adjust advertising - * preferences for each - * Bluetooth LE advertising set. Use {@link AdvertisingSetParameters.Builder} to - * create an - * instance of this class. + * The {@link AdvertisingSetParameters} provide a way to adjust advertising preferences for each + * Bluetooth LE advertising set. Use {@link AdvertisingSetParameters.Builder} to create an instance + * of this class. */ public final class AdvertisingSetParameters implements Parcelable { /** - * Advertise on low frequency, around every 1000ms. This is the default and - * preferred advertising mode as it consumes the least power. + * Advertise on low frequency, around every 1000ms. This is the default and preferred + * advertising mode as it consumes the least power. */ public static final int INTERVAL_HIGH = 1600; /** - * Advertise on medium frequency, around every 250ms. This is balanced - * between advertising frequency and power consumption. + * Advertise on medium frequency, around every 250ms. This is balanced between advertising + * frequency and power consumption. */ public static final int INTERVAL_MEDIUM = 400; /** - * Perform high frequency, low latency advertising, around every 100ms. This - * has the highest power consumption and should not be used for continuous - * background advertising. + * Perform high frequency, low latency advertising, around every 100ms. This has the highest + * power consumption and should not be used for continuous background advertising. */ public static final int INTERVAL_LOW = 160; - /** - * Minimum value for advertising interval. - */ + /** Minimum value for advertising interval. */ public static final int INTERVAL_MIN = 160; - /** - * Maximum value for advertising interval. - */ + /** Maximum value for advertising interval. */ public static final int INTERVAL_MAX = 16777215; /** - * Advertise using the lowest transmission (TX) power level. Low transmission - * power can be used to restrict the visibility range of advertising packets. + * Advertise using the lowest transmission (TX) power level. Low transmission power can be used + * to restrict the visibility range of advertising packets. */ public static final int TX_POWER_ULTRA_LOW = -21; - /** - * Advertise using low TX power level. - */ + /** Advertise using low TX power level. */ public static final int TX_POWER_LOW = -15; - /** - * Advertise using medium TX power level. - */ + /** Advertise using medium TX power level. */ public static final int TX_POWER_MEDIUM = -7; /** - * Advertise using high TX power level. This corresponds to largest visibility - * range of the advertising packet. + * Advertise using high TX power level. This corresponds to largest visibility range of the + * advertising packet. */ public static final int TX_POWER_HIGH = 1; - /** - * Minimum value for TX power. - */ + /** Minimum value for TX power. */ public static final int TX_POWER_MIN = -127; - /** - * Maximum value for TX power. - */ + /** Maximum value for TX power. */ public static final int TX_POWER_MAX = 1; - /** - * The maximum limited advertisement duration as specified by the Bluetooth - * SIG - */ - private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000; - /** @hide */ - @IntDef(prefix = "ADDRESS_TYPE_", value = { - ADDRESS_TYPE_DEFAULT, - ADDRESS_TYPE_PUBLIC, - ADDRESS_TYPE_RANDOM, - ADDRESS_TYPE_RANDOM_NON_RESOLVABLE, - }) + @IntDef( + prefix = "ADDRESS_TYPE_", + value = { + ADDRESS_TYPE_DEFAULT, + ADDRESS_TYPE_PUBLIC, + ADDRESS_TYPE_RANDOM, + ADDRESS_TYPE_RANDOM_NON_RESOLVABLE, + }) @Retention(RetentionPolicy.SOURCE) public @interface AddressTypeStatus {} @@ -118,32 +99,28 @@ public final class AdvertisingSetParameters implements Parcelable { * * @hide */ - @SystemApi - public static final int ADDRESS_TYPE_DEFAULT = -1; + @SystemApi public static final int ADDRESS_TYPE_DEFAULT = -1; /** * Advertise own public address type. * * @hide */ - @SystemApi - public static final int ADDRESS_TYPE_PUBLIC = 0; + @SystemApi public static final int ADDRESS_TYPE_PUBLIC = 0; /** * Generate and adverise own resolvable private address. * * @hide */ - @SystemApi - public static final int ADDRESS_TYPE_RANDOM = 1; + @SystemApi public static final int ADDRESS_TYPE_RANDOM = 1; /** * Generate and advertise on non-resolvable private address. * * @hide */ - @SystemApi - public static final int ADDRESS_TYPE_RANDOM_NON_RESOLVABLE = 2; + @SystemApi public static final int ADDRESS_TYPE_RANDOM_NON_RESOLVABLE = 2; private final boolean mIsLegacy; private final boolean mIsAnonymous; @@ -196,79 +173,58 @@ public final class AdvertisingSetParameters implements Parcelable { mDiscoverable = in.readInt() != 0; } - /** - * Returns whether the advertisement will be connectable. - */ + /** Returns whether the advertisement will be connectable. */ public boolean isConnectable() { return mConnectable; } - /** - * Returns whether the advertisement will be discoverable. - */ + /** Returns whether the advertisement will be discoverable. */ public boolean isDiscoverable() { return mDiscoverable; } - /** - * Returns whether the advertisement will be scannable. - */ + /** Returns whether the advertisement will be scannable. */ public boolean isScannable() { return mScannable; } - /** - * Returns whether the legacy advertisement will be used. - */ + /** Returns whether the legacy advertisement will be used. */ public boolean isLegacy() { return mIsLegacy; } - /** - * Returns whether the advertisement will be anonymous. - */ + /** Returns whether the advertisement will be anonymous. */ public boolean isAnonymous() { return mIsAnonymous; } - /** - * Returns whether the TX Power will be included. - */ + /** Returns whether the TX Power will be included. */ public boolean includeTxPower() { return mIncludeTxPower; } - /** - * Returns the primary advertising phy. - */ + /** Returns the primary advertising phy. */ public int getPrimaryPhy() { return mPrimaryPhy; } - /** - * Returns the secondary advertising phy. - */ + /** Returns the secondary advertising phy. */ public int getSecondaryPhy() { return mSecondaryPhy; } - /** - * Returns the advertising interval. - */ + /** Returns the advertising interval. */ public int getInterval() { return mInterval; } - /** - * Returns the TX power level for advertising. - */ + /** Returns the TX power level for advertising. */ public int getTxPowerLevel() { return mTxPowerLevel; } /** * @return the own address type for advertising - * * @hide */ @SystemApi @@ -278,16 +234,27 @@ public final class AdvertisingSetParameters implements Parcelable { @Override public String toString() { - return "AdvertisingSetParameters [connectable=" + mConnectable - + ", discoverable=" + mDiscoverable - + ", isLegacy=" + mIsLegacy - + ", isAnonymous=" + mIsAnonymous - + ", includeTxPower=" + mIncludeTxPower - + ", primaryPhy=" + mPrimaryPhy - + ", secondaryPhy=" + mSecondaryPhy - + ", interval=" + mInterval - + ", txPowerLevel=" + mTxPowerLevel - + ", ownAddressType=" + mOwnAddressType + "]"; + return "AdvertisingSetParameters [connectable=" + + mConnectable + + ", discoverable=" + + mDiscoverable + + ", isLegacy=" + + mIsLegacy + + ", isAnonymous=" + + mIsAnonymous + + ", includeTxPower=" + + mIncludeTxPower + + ", primaryPhy=" + + mPrimaryPhy + + ", secondaryPhy=" + + mSecondaryPhy + + ", interval=" + + mInterval + + ", txPowerLevel=" + + mTxPowerLevel + + ", ownAddressType=" + + mOwnAddressType + + "]"; } @Override @@ -310,22 +277,21 @@ public final class AdvertisingSetParameters implements Parcelable { dest.writeInt(mDiscoverable ? 1 : 0); } - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public AdvertisingSetParameters[] newArray(int size) { - return new AdvertisingSetParameters[size]; - } - - @Override - public AdvertisingSetParameters createFromParcel(Parcel in) { - return new AdvertisingSetParameters(in); - } - }; - - /** - * Builder class for {@link AdvertisingSetParameters}. - */ + public static final @android.annotation.NonNull Parcelable.Creator + CREATOR = + new Creator() { + @Override + public AdvertisingSetParameters[] newArray(int size) { + return new AdvertisingSetParameters[size]; + } + + @Override + public AdvertisingSetParameters createFromParcel(Parcel in) { + return new AdvertisingSetParameters(in); + } + }; + + /** Builder class for {@link AdvertisingSetParameters}. */ public static final class Builder { private boolean mConnectable = false; private boolean mDiscoverable = true; @@ -340,13 +306,12 @@ public final class AdvertisingSetParameters implements Parcelable { private int mOwnAddressType = ADDRESS_TYPE_DEFAULT; /** - * Set whether the advertisement type should be connectable or - * non-connectable. - * Legacy advertisements can be both connectable and scannable. Non-legacy - * advertisements can be only scannable or only connectable. + * Set whether the advertisement type should be connectable or non-connectable. Legacy + * advertisements can be both connectable and scannable. Non-legacy advertisements can be + * only scannable or only connectable. * * @param connectable Controls whether the advertisement type will be connectable (true) or - * non-connectable (false). + * non-connectable (false). */ public Builder setConnectable(boolean connectable) { mConnectable = connectable; @@ -358,8 +323,8 @@ public final class AdvertisingSetParameters implements Parcelable { * default, advertisements will be discoverable. Devices connecting to non-discoverable * advertisements cannot initiate bonding. * - * @param discoverable Controls whether the advertisement type will be discoverable - * ({@code true}) or non-discoverable ({@code false}). + * @param discoverable Controls whether the advertisement type will be discoverable ({@code + * true}) or non-discoverable ({@code false}). */ public @NonNull Builder setDiscoverable(boolean discoverable) { mDiscoverable = discoverable; @@ -367,12 +332,12 @@ public final class AdvertisingSetParameters implements Parcelable { } /** - * Set whether the advertisement type should be scannable. - * Legacy advertisements can be both connectable and scannable. Non-legacy - * advertisements can be only scannable or only connectable. + * Set whether the advertisement type should be scannable. Legacy advertisements can be both + * connectable and scannable. Non-legacy advertisements can be only scannable or only + * connectable. * * @param scannable Controls whether the advertisement type will be scannable (true) or - * non-scannable (false). + * non-scannable (false). */ public Builder setScannable(boolean scannable) { mScannable = scannable; @@ -380,8 +345,7 @@ public final class AdvertisingSetParameters implements Parcelable { } /** - * When set to true, advertising set will advertise 4.x Spec compliant - * advertisements. + * When set to true, advertising set will advertise 4.x Spec compliant advertisements. * * @param isLegacy whether legacy advertising mode should be used. */ @@ -391,10 +355,10 @@ public final class AdvertisingSetParameters implements Parcelable { } /** - * Set whether advertiser address should be ommited from all packets. If this - * mode is used, periodic advertising can't be enabled for this set. + * Set whether advertiser address should be omitted from all packets. If this mode is used, + * periodic advertising can't be enabled for this set. * - * This is used only if legacy mode is not used. + *

    This is used only if legacy mode is not used. * * @param isAnonymous whether anonymous advertising should be used. */ @@ -406,7 +370,7 @@ public final class AdvertisingSetParameters implements Parcelable { /** * Set whether TX power should be included in the extended header. * - * This is used only if legacy mode is not used. + *

    This is used only if legacy mode is not used. * * @param includeTxPower whether TX power should be included in extended header */ @@ -418,13 +382,13 @@ public final class AdvertisingSetParameters implements Parcelable { /** * Set the primary physical channel used for this advertising set. * - * This is used only if legacy mode is not used. + *

    This is used only if legacy mode is not used. * - * Use {@link BluetoothAdapter#isLeCodedPhySupported} to determine if LE Coded PHY is + *

    Use {@link BluetoothAdapter#isLeCodedPhySupported} to determine if LE Coded PHY is * supported on this device. * * @param primaryPhy Primary advertising physical channel, can only be {@link - * BluetoothDevice#PHY_LE_1M} or {@link BluetoothDevice#PHY_LE_CODED}. + * BluetoothDevice#PHY_LE_1M} or {@link BluetoothDevice#PHY_LE_CODED}. * @throws IllegalArgumentException If the primaryPhy is invalid. */ public Builder setPrimaryPhy(int primaryPhy) { @@ -439,15 +403,15 @@ public final class AdvertisingSetParameters implements Parcelable { /** * Set the secondary physical channel used for this advertising set. * - * This is used only if legacy mode is not used. + *

    This is used only if legacy mode is not used. * - * Use {@link BluetoothAdapter#isLeCodedPhySupported} and - * {@link BluetoothAdapter#isLe2MPhySupported} to determine if LE Coded PHY or 2M PHY is - * supported on this device. + *

    Use {@link BluetoothAdapter#isLeCodedPhySupported} and {@link + * BluetoothAdapter#isLe2MPhySupported} to determine if LE Coded PHY or 2M PHY is supported + * on this device. * * @param secondaryPhy Secondary advertising physical channel, can only be one of {@link - * BluetoothDevice#PHY_LE_1M}, {@link BluetoothDevice#PHY_LE_2M} or {@link - * BluetoothDevice#PHY_LE_CODED}. + * BluetoothDevice#PHY_LE_1M}, {@link BluetoothDevice#PHY_LE_2M} or {@link + * BluetoothDevice#PHY_LE_CODED}. * @throws IllegalArgumentException If the secondaryPhy is invalid. */ public Builder setSecondaryPhy(int secondaryPhy) { @@ -464,9 +428,10 @@ public final class AdvertisingSetParameters implements Parcelable { * Set advertising interval. * * @param interval Bluetooth LE Advertising interval, in 0.625ms unit. Valid range is from - * 160 (100ms) to 16777215 (10,485.759375 s). Recommended values are: {@link - * AdvertisingSetParameters#INTERVAL_LOW}, {@link AdvertisingSetParameters#INTERVAL_MEDIUM}, - * or {@link AdvertisingSetParameters#INTERVAL_HIGH}. + * 160 (100ms) to 16777215 (10,485.759375 s). Recommended values are: {@link + * AdvertisingSetParameters#INTERVAL_LOW}, {@link + * AdvertisingSetParameters#INTERVAL_MEDIUM}, or {@link + * AdvertisingSetParameters#INTERVAL_HIGH}. * @throws IllegalArgumentException If the interval is invalid. */ public Builder setInterval(int interval) { @@ -481,11 +446,11 @@ public final class AdvertisingSetParameters implements Parcelable { * Set the transmission power level for the advertising. * * @param txPowerLevel Transmission power of Bluetooth LE Advertising, in dBm. The valid - * range is [-127, 1] Recommended values are: - * {@link AdvertisingSetParameters#TX_POWER_ULTRA_LOW}, - * {@link AdvertisingSetParameters#TX_POWER_LOW}, - * {@link AdvertisingSetParameters#TX_POWER_MEDIUM}, - * or {@link AdvertisingSetParameters#TX_POWER_HIGH}. + * range is [-127, 1] Recommended values are: {@link + * AdvertisingSetParameters#TX_POWER_ULTRA_LOW}, {@link + * AdvertisingSetParameters#TX_POWER_LOW}, {@link + * AdvertisingSetParameters#TX_POWER_MEDIUM}, or {@link + * AdvertisingSetParameters#TX_POWER_HIGH}. * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid. */ public Builder setTxPowerLevel(int txPowerLevel) { @@ -499,11 +464,10 @@ public final class AdvertisingSetParameters implements Parcelable { /** * Set own address type for advertising to control public or privacy mode. If used to set * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT}, - * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the - * time of starting advertising. + * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the time of + * starting advertising. * * @throws IllegalArgumentException If the {@code ownAddressType} is invalid - * * @hide */ @SystemApi diff --git a/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java index 9e8dcdec14de19c29c2617da1bc6fa28541b2bcc..50b3a82d2136e165028c4ff79d0b575616ae071b 100644 --- a/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -29,7 +29,6 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGattServer; import android.bluetooth.BluetoothUuid; import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.content.AttributionSource; @@ -51,9 +50,9 @@ import java.util.concurrent.TimeoutException; * This class provides a way to perform Bluetooth LE advertise operations, such as starting and * stopping advertising. An advertiser can broadcast up to 31 bytes of advertisement data * represented by {@link AdvertiseData}. - *

    - * To get an instance of {@link BluetoothLeAdvertiser}, call the - * {@link BluetoothAdapter#getBluetoothLeAdvertiser()} method. + * + *

    To get an instance of {@link BluetoothLeAdvertiser}, call the {@link + * BluetoothAdapter#getBluetoothLeAdvertiser()} method. * * @see AdvertiseData */ @@ -61,7 +60,6 @@ public final class BluetoothLeAdvertiser { private static final String TAG = "BluetoothLeAdvertiser"; - private static final int MAX_ADVERTISING_DATA_BYTES = 1650; private static final int MAX_LEGACY_ADVERTISING_DATA_BYTES = 31; // Each fields need one byte for field length and another byte for field type. private static final int OVERHEAD_BYTES_PER_FIELD = 2; @@ -70,26 +68,23 @@ public final class BluetoothLeAdvertiser { private static final int MANUFACTURER_SPECIFIC_DATA_LENGTH = 2; private final BluetoothAdapter mBluetoothAdapter; - private final IBluetoothManager mBluetoothManager; private final AttributionSource mAttributionSource; private final Handler mHandler; - private final Map - mLegacyAdvertisers = new HashMap<>(); - private final Map - mCallbackWrappers = Collections.synchronizedMap(new HashMap<>()); - private final Map - mAdvertisingSets = Collections.synchronizedMap(new HashMap<>()); + private final Map mLegacyAdvertisers = + new HashMap<>(); + private final Map mCallbackWrappers = + Collections.synchronizedMap(new HashMap<>()); + private final Map mAdvertisingSets = + Collections.synchronizedMap(new HashMap<>()); /** * Use BluetoothAdapter.getLeAdvertiser() instead. * - * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management * @hide */ public BluetoothLeAdvertiser(BluetoothAdapter bluetoothAdapter) { mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter); - mBluetoothManager = mBluetoothAdapter.getBluetoothManager(); mAttributionSource = mBluetoothAdapter.getAttributionSource(); mHandler = new Handler(Looper.getMainLooper()); } @@ -105,8 +100,10 @@ public final class BluetoothLeAdvertiser { @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertising(AdvertiseSettings settings, - AdvertiseData advertiseData, final AdvertiseCallback callback) { + public void startAdvertising( + AdvertiseSettings settings, + AdvertiseData advertiseData, + final AdvertiseCallback callback) { startAdvertising(settings, advertiseData, null, callback); } @@ -124,8 +121,10 @@ public final class BluetoothLeAdvertiser { @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertising(AdvertiseSettings settings, - AdvertiseData advertiseData, AdvertiseData scanResponse, + public void startAdvertising( + AdvertiseSettings settings, + AdvertiseData advertiseData, + AdvertiseData scanResponse, final AdvertiseCallback callback) { synchronized (mLegacyAdvertisers) { BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); @@ -160,12 +159,16 @@ public final class BluetoothLeAdvertiser { } if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW) { + Log.d(TAG, "TxPower == ADVERTISE_TX_POWER_ULTRA_LOW"); parameters.setTxPowerLevel(-21); } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_LOW) { + Log.d(TAG, "TxPower == ADVERTISE_TX_POWER_LOW"); parameters.setTxPowerLevel(-15); } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) { + Log.d(TAG, "TxPower == ADVERTISE_TX_POWER_MEDIUM"); parameters.setTxPowerLevel(-7); } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) { + Log.d(TAG, "TxPower == ADVERTISE_TX_POWER_HIGH"); parameters.setTxPowerLevel(1); } @@ -177,20 +180,27 @@ public final class BluetoothLeAdvertiser { AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings); mLegacyAdvertisers.put(callback, wrapped); - startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null, - duration, 0, wrapped); + startAdvertisingSet( + parameters.build(), + advertiseData, + scanResponse, + null, + null, + duration, + 0, + wrapped); } } @SuppressLint({ - "AndroidFrameworkBluetoothPermission", - "AndroidFrameworkRequiresPermission", + "AndroidFrameworkBluetoothPermission", + "AndroidFrameworkRequiresPermission", }) AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) { return new AdvertisingSetCallback() { @Override - public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, - int status) { + public void onAdvertisingSetStarted( + AdvertisingSet advertisingSet, int txPower, int status) { if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) { postStartFailure(callback, status); return; @@ -201,23 +211,24 @@ public final class BluetoothLeAdvertiser { /* Legacy advertiser is disabled on timeout */ @Override - public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enabled, - int status) { + public void onAdvertisingEnabled( + AdvertisingSet advertisingSet, boolean enabled, int status) { if (enabled) { - Log.e(TAG, "Legacy advertiser should be only disabled on timeout," - + " but was enabled!"); + Log.e( + TAG, + "Legacy advertiser should be only disabled on timeout," + + " but was enabled!"); return; } stopAdvertising(callback); } - }; } /** - * Stop Bluetooth LE advertising. The {@code callback} must be the same one use in - * {@link BluetoothLeAdvertiser#startAdvertising}. + * Stop Bluetooth LE advertising. The {@code callback} must be the same one use in {@link + * BluetoothLeAdvertiser#startAdvertising}. * * @param callback {@link AdvertiseCallback} identifies the advertising instance to stop. */ @@ -240,201 +251,254 @@ public final class BluetoothLeAdvertiser { /** * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. + * method returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()}. + * *

    * * @param parameters advertising set parameters. * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, + * three bytes will be added for flags. * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. + * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will - * not be started. + * not be started. * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. * @param callback Callback for advertising set. * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller. + * size, or unsupported advertising PHY is selected, or when attempt to use Periodic + * Advertising feature is made when it's not supported by the controller. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertisingSet(AdvertisingSetParameters parameters, - AdvertiseData advertiseData, AdvertiseData scanResponse, + public void startAdvertisingSet( + AdvertisingSetParameters parameters, + AdvertiseData advertiseData, + AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, - AdvertiseData periodicData, AdvertisingSetCallback callback) { - startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, 0, 0, callback, new Handler(Looper.getMainLooper())); + AdvertiseData periodicData, + AdvertisingSetCallback callback) { + startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + 0, + 0, + callback, + new Handler(Looper.getMainLooper())); } /** * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. + * method returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()}. + * *

    * * @param parameters advertising set parameters. * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, + * three bytes will be added for flags. * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. + * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will - * not be started. + * not be started. * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. * @param callback Callback for advertising set. * @param handler thread upon which the callbacks will be invoked. * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller. + * size, or unsupported advertising PHY is selected, or when attempt to use Periodic + * Advertising feature is made when it's not supported by the controller. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertisingSet(AdvertisingSetParameters parameters, - AdvertiseData advertiseData, AdvertiseData scanResponse, + public void startAdvertisingSet( + AdvertisingSetParameters parameters, + AdvertiseData advertiseData, + AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, - AdvertiseData periodicData, AdvertisingSetCallback callback, + AdvertiseData periodicData, + AdvertisingSetCallback callback, Handler handler) { - startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, 0, 0, callback, handler); + startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + 0, + 0, + callback, + handler); } /** * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. + * method returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()}. + * *

    * * @param parameters advertising set parameters. * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, + * three bytes will be added for flags. * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. + * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will - * not be started. + * not be started. * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535 - * (655,350 ms). 0 means advertising should continue until stopped. + * (655,350 ms). 0 means advertising should continue until stopped. * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the - * controller shall attempt to send prior to terminating the extended advertising, even if the - * duration has not expired. Valid range is from 1 to 255. 0 means no maximum. + * controller shall attempt to send prior to terminating the extended advertising, even if + * the duration has not expired. Valid range is from 1 to 255. 0 means no maximum. * @param callback Callback for advertising set. * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller. + * size, or unsupported advertising PHY is selected, or when attempt to use Periodic + * Advertising feature is made when it's not supported by the controller. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertisingSet(AdvertisingSetParameters parameters, - AdvertiseData advertiseData, AdvertiseData scanResponse, + public void startAdvertisingSet( + AdvertisingSetParameters parameters, + AdvertiseData advertiseData, + AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, - AdvertiseData periodicData, int duration, + AdvertiseData periodicData, + int duration, int maxExtendedAdvertisingEvents, AdvertisingSetCallback callback) { - startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, duration, maxExtendedAdvertisingEvents, callback, + startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + duration, + maxExtendedAdvertisingEvents, + callback, new Handler(Looper.getMainLooper())); } /** * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. + * method returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()}. + * *

    * * @param parameters Advertising set parameters. * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, + * three bytes will be added for flags. * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength} + * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength} * @param periodicParameters Periodic advertisng parameters. If null, periodic advertising will - * not be started. + * not be started. * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength} + * BluetoothAdapter#getLeMaximumAdvertisingDataLength} * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535 - * (655,350 ms). 0 means advertising should continue until stopped. + * (655,350 ms). 0 means advertising should continue until stopped. * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the - * controller shall attempt to send prior to terminating the extended advertising, even if the - * duration has not expired. Valid range is from 1 to 255. 0 means no maximum. + * controller shall attempt to send prior to terminating the extended advertising, even if + * the duration has not expired. Valid range is from 1 to 255. 0 means no maximum. * @param callback Callback for advertising set. * @param handler Thread upon which the callbacks will be invoked. * @throws IllegalArgumentException When any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller, or when - * maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended - * Advertising + * size, or unsupported advertising PHY is selected, or when attempt to use Periodic + * Advertising feature is made when it's not supported by the controller, or when + * maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended + * Advertising */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothAdvertisePermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) - public void startAdvertisingSet(AdvertisingSetParameters parameters, - AdvertiseData advertiseData, AdvertiseData scanResponse, - PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, - int duration, int maxExtendedAdvertisingEvents, AdvertisingSetCallback callback, + public void startAdvertisingSet( + AdvertisingSetParameters parameters, + AdvertiseData advertiseData, + AdvertiseData scanResponse, + PeriodicAdvertisingParameters periodicParameters, + AdvertiseData periodicData, + int duration, + int maxExtendedAdvertisingEvents, + AdvertisingSetCallback callback, Handler handler) { - startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, duration, maxExtendedAdvertisingEvents, null, callback, handler); + startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + duration, + maxExtendedAdvertisingEvents, + null, + callback, + handler); } /** * Creates a new advertising set. If operation succeed, device will start advertising. This - * method returns immediately, the operation status is delivered through - * {@code callback.onAdvertisingSetStarted()}. + * method returns immediately, the operation status is delivered through {@code + * callback.onAdvertisingSetStarted()}. * - *

    If the {@code gattServer} is provided, connections to this advertisement will only see - * the services/characteristics in this server, rather than the union of all GATT - * services (across all opened servers). + *

    If the {@code gattServer} is provided, connections to this advertisement will only see the + * services/characteristics in this server, rather than the union of all GATT services (across + * all opened servers). * * @param parameters Advertising set parameters. * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, - * three bytes will be added for flags. + * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable, + * three bytes will be added for flags. * @param scanResponse Scan response associated with the advertisement data. Size must not - * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength} + * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength} * @param periodicParameters Periodic advertisng parameters. If null, periodic advertising will - * not be started. + * not be started. * @param periodicData Periodic advertising data. Size must not exceed {@link - * BluetoothAdapter#getLeMaximumAdvertisingDataLength} + * BluetoothAdapter#getLeMaximumAdvertisingDataLength} * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535 - * (655,350 ms). 0 means advertising should continue until stopped. + * (655,350 ms). 0 means advertising should continue until stopped. * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the - * controller shall attempt to send prior to terminating the extended advertising, even if the - * duration has not expired. Valid range is from 1 to 255. 0 means no maximum. + * controller shall attempt to send prior to terminating the extended advertising, even if + * the duration has not expired. Valid range is from 1 to 255. 0 means no maximum. * @param gattServer the GATT server that will "own" connections derived from this advertising - * set. + * set. * @param callback Callback for advertising set. * @param handler Thread upon which the callbacks will be invoked. * @throws IllegalArgumentException When any of the data parameter exceed the maximum allowable - * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising - * feature is made when it's not supported by the controller, or when - * maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended - * Advertising - * + * size, or unsupported advertising PHY is selected, or when attempt to use Periodic + * Advertising feature is made when it's not supported by the controller, or when + * maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended + * Advertising * @hide */ @SystemApi @SuppressLint("ExecutorRegistration") @RequiresBluetoothAdvertisePermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.BLUETOOTH_ADVERTISE, - android.Manifest.permission.BLUETOOTH_CONNECT, - }) - public void - startAdvertisingSet(@NonNull AdvertisingSetParameters parameters, - @Nullable AdvertiseData advertiseData, @Nullable AdvertiseData scanResponse, + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.BLUETOOTH_ADVERTISE, + android.Manifest.permission.BLUETOOTH_CONNECT, + }) + public void startAdvertisingSet( + @NonNull AdvertisingSetParameters parameters, + @Nullable AdvertiseData advertiseData, + @Nullable AdvertiseData scanResponse, @Nullable PeriodicAdvertisingParameters periodicParameters, - @Nullable AdvertiseData periodicData, int duration, - int maxExtendedAdvertisingEvents, @Nullable BluetoothGattServer gattServer, + @Nullable AdvertiseData periodicData, + int duration, + int maxExtendedAdvertisingEvents, + @Nullable BluetoothGattServer gattServer, @Nullable AdvertisingSetCallback callback, @SuppressLint("ListenerLast") @NonNull Handler handler) { BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); @@ -503,20 +567,12 @@ public final class BluetoothLeAdvertiser { throw new IllegalArgumentException("duration out of range: " + duration); } - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth GATT - ", e); - postStartSetFailure(handler, callback, - AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); - return; - } + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); if (gatt == null) { Log.e(TAG, "Bluetooth GATT is null"); - postStartSetFailure(handler, callback, - AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); + postStartSetFailure( + handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); return; } @@ -528,15 +584,23 @@ public final class BluetoothLeAdvertiser { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, duration, maxExtendedAdvertisingEvents, - gattServer == null ? 0 : gattServer.getServerIf(), wrapped, mAttributionSource, + gatt.startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + duration, + maxExtendedAdvertisingEvents, + gattServer == null ? 0 : gattServer.getServerIf(), + wrapped, + mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (TimeoutException | RemoteException e) { Log.e(TAG, "Failed to start advertising set - ", e); - postStartSetFailure(handler, callback, - AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); + postStartSetFailure( + handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); return; } catch (SecurityException e) { mCallbackWrappers.remove(callback); @@ -561,9 +625,12 @@ public final class BluetoothLeAdvertiser { return; } - IBluetoothGatt gatt; + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); + if (gatt == null) { + Log.e(TAG, "Bluetooth GATT is null"); + return; + } try { - gatt = mBluetoothManager.getBluetoothGatt(); final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); gatt.stopAdvertisingSet(wrapped, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); @@ -614,8 +681,9 @@ public final class BluetoothLeAdvertiser { } // 128 bit service uuids are grouped into one field when doing advertising. if (num128BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD - + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; + size += + OVERHEAD_BYTES_PER_FIELD + + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; } } if (data.getServiceSolicitationUuids() != null) { @@ -641,8 +709,9 @@ public final class BluetoothLeAdvertiser { } // 128 bit service uuids are grouped into one field when doing advertising. if (num128BitUuids != 0) { - size += OVERHEAD_BYTES_PER_FIELD - + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; + size += + OVERHEAD_BYTES_PER_FIELD + + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; } } for (TransportDiscoveryData transportDiscoveryData : data.getTransportDiscoveryData()) { @@ -650,12 +719,16 @@ public final class BluetoothLeAdvertiser { } for (ParcelUuid uuid : data.getServiceData().keySet()) { int uuidLen = BluetoothUuid.uuidToBytes(uuid).length; - size += OVERHEAD_BYTES_PER_FIELD + uuidLen - + byteLength(data.getServiceData().get(uuid)); + size += + OVERHEAD_BYTES_PER_FIELD + + uuidLen + + byteLength(data.getServiceData().get(uuid)); } for (int i = 0; i < data.getManufacturerSpecificData().size(); ++i) { - size += OVERHEAD_BYTES_PER_FIELD + MANUFACTURER_SPECIFIC_DATA_LENGTH - + byteLength(data.getManufacturerSpecificData().valueAt(i)); + size += + OVERHEAD_BYTES_PER_FIELD + + MANUFACTURER_SPECIFIC_DATA_LENGTH + + byteLength(data.getManufacturerSpecificData().valueAt(i)); } if (data.getIncludeTxPowerLevel()) { size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte. @@ -678,156 +751,175 @@ public final class BluetoothLeAdvertiser { return new IAdvertisingSetCallback.Stub() { @Override public void onAdvertisingSetStarted(int advertiserId, int txPower, int status) { - handler.post(new Runnable() { - @Override - public void run() { - if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) { - callback.onAdvertisingSetStarted(null, 0, status); - mCallbackWrappers.remove(callback); - return; - } - - AdvertisingSet advertisingSet = new AdvertisingSet( - advertiserId, mBluetoothManager, mAttributionSource); - mAdvertisingSets.put(advertiserId, advertisingSet); - callback.onAdvertisingSetStarted(advertisingSet, txPower, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) { + callback.onAdvertisingSetStarted(null, 0, status); + mCallbackWrappers.remove(callback); + return; + } + + AdvertisingSet advertisingSet = + new AdvertisingSet( + advertiserId, + mBluetoothAdapter, + mAttributionSource); + mAdvertisingSets.put(advertiserId, advertisingSet); + callback.onAdvertisingSetStarted(advertisingSet, txPower, status); + } + }); } @Override public void onOwnAddressRead(int advertiserId, int addressType, String address) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onOwnAddressRead(advertisingSet, addressType, address); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onOwnAddressRead(advertisingSet, addressType, address); + } + }); } @Override public void onAdvertisingSetStopped(int advertiserId) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onAdvertisingSetStopped(advertisingSet); - mAdvertisingSets.remove(advertiserId); - mCallbackWrappers.remove(callback); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onAdvertisingSetStopped(advertisingSet); + mAdvertisingSets.remove(advertiserId); + mCallbackWrappers.remove(callback); + } + }); } @Override public void onAdvertisingEnabled(int advertiserId, boolean enabled, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onAdvertisingEnabled(advertisingSet, enabled, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onAdvertisingEnabled(advertisingSet, enabled, status); + } + }); } @Override public void onAdvertisingDataSet(int advertiserId, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onAdvertisingDataSet(advertisingSet, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onAdvertisingDataSet(advertisingSet, status); + } + }); } @Override public void onScanResponseDataSet(int advertiserId, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onScanResponseDataSet(advertisingSet, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onScanResponseDataSet(advertisingSet, status); + } + }); } @Override public void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onAdvertisingParametersUpdated(advertisingSet, txPower, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onAdvertisingParametersUpdated( + advertisingSet, txPower, status); + } + }); } @Override public void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onPeriodicAdvertisingParametersUpdated(advertisingSet, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onPeriodicAdvertisingParametersUpdated( + advertisingSet, status); + } + }); } @Override public void onPeriodicAdvertisingDataSet(int advertiserId, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onPeriodicAdvertisingDataSet(advertisingSet, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onPeriodicAdvertisingDataSet(advertisingSet, status); + } + }); } @Override public void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status) { - handler.post(new Runnable() { - @Override - public void run() { - AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); - callback.onPeriodicAdvertisingEnabled(advertisingSet, enable, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); + callback.onPeriodicAdvertisingEnabled( + advertisingSet, enable, status); + } + }); } }; } @SuppressLint("AndroidFrameworkBluetoothPermission") - private void postStartSetFailure(Handler handler, final AdvertisingSetCallback callback, - final int error) { - handler.post(new Runnable() { - @Override - public void run() { - callback.onAdvertisingSetStarted(null, 0, error); - } - }); + private void postStartSetFailure( + Handler handler, final AdvertisingSetCallback callback, final int error) { + handler.post( + new Runnable() { + @Override + public void run() { + callback.onAdvertisingSetStarted(null, 0, error); + } + }); } @SuppressLint("AndroidFrameworkBluetoothPermission") private void postStartFailure(final AdvertiseCallback callback, final int error) { - mHandler.post(new Runnable() { - @Override - public void run() { - callback.onStartFailure(error); - } - }); + mHandler.post( + new Runnable() { + @Override + public void run() { + callback.onStartFailure(error); + } + }); } @SuppressLint("AndroidFrameworkBluetoothPermission") - private void postStartSuccess(final AdvertiseCallback callback, - final AdvertiseSettings settings) { - mHandler.post(new Runnable() { + private void postStartSuccess( + final AdvertiseCallback callback, final AdvertiseSettings settings) { + mHandler.post( + new Runnable() { - @Override - public void run() { - callback.onStartSuccess(settings); - } - }); + @Override + public void run() { + callback.onStartSuccess(settings); + } + }); } } diff --git a/framework/java/android/bluetooth/le/BluetoothLeScanner.java b/framework/java/android/bluetooth/le/BluetoothLeScanner.java index 28d408ec6534567f38f1ef2fe11e4d9741edc6f6..e5820f05ecbd42ebf26f3961585802b146ea7bac 100644 --- a/framework/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/framework/java/android/bluetooth/le/BluetoothLeScanner.java @@ -29,7 +29,6 @@ import android.bluetooth.Attributable; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothGatt; import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; import android.bluetooth.annotations.RequiresBluetoothLocationPermission; import android.bluetooth.annotations.RequiresBluetoothScanPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; @@ -53,9 +52,9 @@ import java.util.concurrent.TimeoutException; * This class provides methods to perform scan related operations for Bluetooth LE devices. An * application can scan for a particular type of Bluetooth LE devices using {@link ScanFilter}. It * can also request different types of callbacks for delivering the result. - *

    - * Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of - * {@link BluetoothLeScanner}. + * + *

    Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of {@link + * BluetoothLeScanner}. * * @see ScanFilter */ @@ -67,8 +66,8 @@ public final class BluetoothLeScanner { /** * Extra containing a list of ScanResults. It can have one or more results if there was no - * error. In case of error, {@link #EXTRA_ERROR_CODE} will contain the error code and this - * extra will not be available. + * error. In case of error, {@link #EXTRA_ERROR_CODE} will contain the error code and this extra + * will not be available. */ public static final String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT"; @@ -80,15 +79,14 @@ public final class BluetoothLeScanner { public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE"; /** - * Optional extra indicating the callback type, which will be one of - * CALLBACK_TYPE_* constants in {@link ScanSettings}. + * Optional extra indicating the callback type, which will be one of CALLBACK_TYPE_* constants + * in {@link ScanSettings}. * * @see ScanCallback#onScanResult(int, ScanResult) */ public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE"; private final BluetoothAdapter mBluetoothAdapter; - private final IBluetoothManager mBluetoothManager; private final AttributionSource mAttributionSource; private final Handler mHandler; @@ -97,14 +95,10 @@ public final class BluetoothLeScanner { /** * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead. * - * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management. - * @param opPackageName The opPackageName of the context this object was created from - * @param featureId The featureId of the context this object was created from * @hide */ public BluetoothLeScanner(BluetoothAdapter bluetoothAdapter) { mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter); - mBluetoothManager = mBluetoothAdapter.getBluetoothManager(); mAttributionSource = mBluetoothAdapter.getAttributionSource(); mHandler = new Handler(Looper.getMainLooper()); mLeScanClients = new HashMap(); @@ -112,15 +106,14 @@ public final class BluetoothLeScanner { /** * Start Bluetooth LE scan with default parameters and no filters. The scan results will be - * delivered through {@code callback}. For unfiltered scans, scanning is stopped on screen - * off to save power. Scanning is resumed when screen is turned on again. To avoid this, use - * {@link #startScan(List, ScanSettings, ScanCallback)} with desired {@link ScanFilter}. - *

    - * An app must have - * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission - * in order to get results. An App targeting Android Q or later must have - * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission - * in order to get results. + * delivered through {@code callback}. For unfiltered scans, scanning is stopped on screen off + * to save power. Scanning is resumed when screen is turned on again. To avoid this, use {@link + * #startScan(List, ScanSettings, ScanCallback)} with desired {@link ScanFilter}. + * + *

    An app must have {@link android.Manifest.permission#ACCESS_COARSE_LOCATION + * ACCESS_COARSE_LOCATION} permission in order to get results. An App targeting Android Q or + * later must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} + * permission in order to get results. * * @param callback Callback used to deliver scan results. * @throws IllegalArgumentException If {@code callback} is null. @@ -134,16 +127,15 @@ public final class BluetoothLeScanner { } /** - * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}. - * For unfiltered scans, scanning is stopped on screen off to save power. Scanning is - * resumed when screen is turned on again. To avoid this, do filetered scanning by - * using proper {@link ScanFilter}. - *

    - * An app must have - * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission - * in order to get results. An App targeting Android Q or later must have - * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission - * in order to get results. + * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}. For + * unfiltered scans, scanning is stopped on screen off to save power. Scanning is resumed when + * screen is turned on again. To avoid this, do filtered scanning by using proper {@link + * ScanFilter}. + * + *

    An app must have {@link android.Manifest.permission#ACCESS_COARSE_LOCATION + * ACCESS_COARSE_LOCATION} permission in order to get results. An App targeting Android Q or + * later must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} + * permission in order to get results. * * @param filters {@link ScanFilter}s for finding exact BLE devices. * @param settings Settings for the scan. @@ -154,43 +146,46 @@ public final class BluetoothLeScanner { @RequiresBluetoothScanPermission @RequiresBluetoothLocationPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void startScan(List filters, ScanSettings settings, - final ScanCallback callback) { - startScan(filters, settings, null, callback, /*callbackIntent=*/ null); + public void startScan( + List filters, ScanSettings settings, final ScanCallback callback) { + startScan(filters, settings, null, callback, /* callbackIntent= */ null); } /** * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via * the PendingIntent. Use this method of scanning if your process is not always running and it * should be started when scan results are available. - *

    - * An app must have - * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission - * in order to get results. An App targeting Android Q or later must have - * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission - * in order to get results. - *

    - * When the PendingIntent is delivered, the Intent passed to the receiver or activity - * will contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE}, - * {@link #EXTRA_ERROR_CODE} and {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of - * the scan. + * + *

    An app must have {@link android.Manifest.permission#ACCESS_COARSE_LOCATION + * ACCESS_COARSE_LOCATION} permission in order to get results. An App targeting Android Q or + * later must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} + * permission in order to get results. + * + *

    When the PendingIntent is delivered, the Intent passed to the receiver or activity will + * contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE}, {@link #EXTRA_ERROR_CODE} and + * {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of the scan. * * @param filters Optional list of ScanFilters for finding exact BLE devices. * @param settings Optional settings for the scan. * @param callbackIntent The PendingIntent to deliver the result to. * @return Returns 0 for success or an error code from {@link ScanCallback} if the scan request - * could not be sent. + * could not be sent. * @see #stopScan(PendingIntent) */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothScanPermission @RequiresBluetoothLocationPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public int startScan(@Nullable List filters, @Nullable ScanSettings settings, + public int startScan( + @Nullable List filters, + @Nullable ScanSettings settings, @NonNull PendingIntent callbackIntent) { - return startScan(filters, + return startScan( + filters, settings != null ? settings : new ScanSettings.Builder().build(), - null, null, callbackIntent); + null, + null, + callbackIntent); } /** @@ -198,7 +193,7 @@ public final class BluetoothLeScanner { * specify on behalf of which application(s) the work is being done. * * @param workSource {@link WorkSource} identifying the application(s) for which to blame for - * the scan. + * the scan. * @param callback Callback used to deliver scan results. * @hide */ @@ -206,10 +201,11 @@ public final class BluetoothLeScanner { @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothScanPermission @RequiresBluetoothLocationPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_SCAN, - android.Manifest.permission.UPDATE_DEVICE_STATS - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_SCAN, + android.Manifest.permission.UPDATE_DEVICE_STATS + }) public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) { startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback); } @@ -221,7 +217,7 @@ public final class BluetoothLeScanner { * @param filters {@link ScanFilter}s for finding exact BLE devices. * @param settings Settings for the scan. * @param workSource {@link WorkSource} identifying the application(s) for which to blame for - * the scan. + * the scan. * @param callback Callback used to deliver scan results. * @hide */ @@ -229,19 +225,26 @@ public final class BluetoothLeScanner { @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothScanPermission @RequiresBluetoothLocationPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_SCAN, - android.Manifest.permission.UPDATE_DEVICE_STATS - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_SCAN, + android.Manifest.permission.UPDATE_DEVICE_STATS + }) @SuppressLint("AndroidFrameworkRequiresPermission") - public void startScanFromSource(List filters, ScanSettings settings, - final WorkSource workSource, final ScanCallback callback) { + public void startScanFromSource( + List filters, + ScanSettings settings, + final WorkSource workSource, + final ScanCallback callback) { startScan(filters, settings, workSource, callback, null); } @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - private int startScan(List filters, ScanSettings settings, - final WorkSource workSource, final ScanCallback callback, + private int startScan( + List filters, + ScanSettings settings, + final WorkSource workSource, + final ScanCallback callback, final PendingIntent callbackIntent) { BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); if (callback == null && callbackIntent == null) { @@ -252,39 +255,34 @@ public final class BluetoothLeScanner { } synchronized (mLeScanClients) { if (callback != null && mLeScanClients.containsKey(callback)) { - return postCallbackErrorOrReturn(callback, - ScanCallback.SCAN_FAILED_ALREADY_STARTED); - } - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - gatt = null; + return postCallbackErrorOrReturn( + callback, ScanCallback.SCAN_FAILED_ALREADY_STARTED); } + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); if (gatt == null) { return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); } if (!isSettingsConfigAllowedForScan(settings)) { - return postCallbackErrorOrReturn(callback, - ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); + return postCallbackErrorOrReturn( + callback, ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); } if (!isHardwareResourcesAvailableForScan(settings)) { - return postCallbackErrorOrReturn(callback, - ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES); + return postCallbackErrorOrReturn( + callback, ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES); } if (!isSettingsAndFilterComboAllowed(settings, filters)) { - return postCallbackErrorOrReturn(callback, - ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); + return postCallbackErrorOrReturn( + callback, ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); } if (callback != null) { - BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters, - settings, workSource, callback); + BleScanCallbackWrapper wrapper = + new BleScanCallbackWrapper(gatt, filters, settings, workSource, callback); wrapper.startRegistration(); } else { try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - gatt.startScanForIntent(callbackIntent, settings, filters, - mAttributionSource, recv); + gatt.startScanForIntent( + callbackIntent, settings, filters, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (TimeoutException | RemoteException e) { return ScanCallback.SCAN_FAILED_INTERNAL_ERROR; @@ -296,8 +294,6 @@ public final class BluetoothLeScanner { /** * Stops an ongoing Bluetooth LE scan. - * - * @param callback */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothScanPermission @@ -329,11 +325,12 @@ public final class BluetoothLeScanner { BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); IBluetoothGatt gatt; try { - gatt = mBluetoothManager.getBluetoothGatt(); + gatt = mBluetoothAdapter.getBluetoothGatt(); final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); gatt.stopScanForIntent(callbackIntent, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (TimeoutException | RemoteException e) { + Log.e(TAG, "Failed to stop scan", e); } } @@ -343,7 +340,7 @@ public final class BluetoothLeScanner { * will be delivered through the {@code callback}. * * @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one - * used to start scan. + * used to start scan. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothScanPermission @@ -366,14 +363,15 @@ public final class BluetoothLeScanner { * Start truncated scan. * * @deprecated this is not used anywhere - * * @hide */ @Deprecated @SystemApi @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void startTruncatedScan(List truncatedFilters, ScanSettings settings, + public void startTruncatedScan( + List truncatedFilters, + ScanSettings settings, final ScanCallback callback) { int filterSize = truncatedFilters.size(); List scanFilters = new ArrayList(filterSize); @@ -393,9 +391,7 @@ public final class BluetoothLeScanner { mLeScanClients.clear(); } - /** - * Bluetooth GATT interface callbacks - */ + /** Bluetooth GATT interface callbacks */ @SuppressLint("AndroidFrameworkRequiresPermission") private class BleScanCallbackWrapper extends IScannerCallback.Stub { private static final int REGISTRATION_CALLBACK_TIMEOUT_MILLIS = 2000; @@ -412,9 +408,12 @@ public final class BluetoothLeScanner { // > 0: registered and scan started private int mScannerId; - public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt, - List filters, ScanSettings settings, - WorkSource workSource, ScanCallback scanCallback) { + public BleScanCallbackWrapper( + IBluetoothGatt bluetoothGatt, + List filters, + ScanSettings settings, + WorkSource workSource, + ScanCallback scanCallback) { mBluetoothGatt = bluetoothGatt; mFilters = filters; mSettings = settings; @@ -423,6 +422,7 @@ public final class BluetoothLeScanner { mScannerId = 0; } + @SuppressWarnings("WaitNotInLoop") // TODO(b/314811467) public void startRegistration() { synchronized (this) { // Scan stopped. @@ -433,7 +433,7 @@ public final class BluetoothLeScanner { recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS); } catch (TimeoutException | InterruptedException | RemoteException e) { - Log.e(TAG, "application registeration exception", e); + Log.e(TAG, "application registration exception", e); postCallbackError(mScanCallback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); } if (mScannerId > 0) { @@ -446,7 +446,8 @@ public final class BluetoothLeScanner { // If scanning too frequently, don't report anything to the app. if (mScannerId == -2) return; - postCallbackError(mScanCallback, + postCallbackError( + mScanCallback, ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED); } } @@ -491,13 +492,17 @@ public final class BluetoothLeScanner { } } - /** - * Application interface registered - app is ready to go - */ + /** Application interface registered - app is ready to go */ @Override public void onScannerRegistered(int status, int scannerId) { - Log.d(TAG, "onScannerRegistered() - status=" + status - + " scannerId=" + scannerId + " mScannerId=" + mScannerId); + Log.d( + TAG, + "onScannerRegistered() - status=" + + status + + " scannerId=" + + scannerId + + " mScannerId=" + + mScannerId); synchronized (this) { if (status == BluetoothGatt.GATT_SUCCESS) { try { @@ -507,8 +512,8 @@ public final class BluetoothLeScanner { mBluetoothGatt.unregisterScanner(scannerId, mAttributionSource, recv); } else { mScannerId = scannerId; - mBluetoothGatt.startScan(mScannerId, mSettings, mFilters, - mAttributionSource, recv); + mBluetoothGatt.startScan( + mScannerId, mSettings, mFilters, mAttributionSource, recv); } recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (TimeoutException | RemoteException e) { @@ -516,7 +521,7 @@ public final class BluetoothLeScanner { mScannerId = -1; } } else if (status == ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY) { - // applicaiton was scanning too frequently + // application was scanning too frequently mScannerId = -2; } else { // registration failed @@ -546,30 +551,34 @@ public final class BluetoothLeScanner { Log.d(TAG, "Ignoring result as scan stopped."); } return; - }; + } + ; } Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "onScanResult() - handler run"); - } - mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "onScanResult() - handler run"); + } + mScanCallback.onScanResult( + ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult); + } + }); } @Override public void onBatchScanResults(final List results) { Attributable.setAttributionSource(results, mAttributionSource); Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - mScanCallback.onBatchScanResults(results); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + mScanCallback.onBatchScanResults(results); + } + }); } @Override @@ -586,18 +595,19 @@ public final class BluetoothLeScanner { } } Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - if (onFound) { - mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, - scanResult); - } else { - mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST, - scanResult); - } - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + if (onFound) { + mScanCallback.onScanResult( + ScanSettings.CALLBACK_TYPE_FIRST_MATCH, scanResult); + } else { + mScanCallback.onScanResult( + ScanSettings.CALLBACK_TYPE_MATCH_LOST, scanResult); + } + } + }); } @Override @@ -625,12 +635,13 @@ public final class BluetoothLeScanner { @SuppressLint("AndroidFrameworkBluetoothPermission") private void postCallbackError(final ScanCallback callback, final int errorCode) { - mHandler.post(new Runnable() { - @Override - public void run() { - callback.onScanFailed(errorCode); - } - }); + mHandler.post( + new Runnable() { + @Override + public void run() { + callback.onScanFailed(errorCode); + } + }); } private boolean isSettingsConfigAllowedForScan(ScanSettings settings) { @@ -646,12 +657,14 @@ public final class BluetoothLeScanner { return false; } - private boolean isSettingsAndFilterComboAllowed(ScanSettings settings, - List filterList) { + private boolean isSettingsAndFilterComboAllowed( + ScanSettings settings, List filterList) { final int callbackType = settings.getCallbackType(); // If onlost/onfound is requested, a non-empty filter is expected - if ((callbackType & (ScanSettings.CALLBACK_TYPE_FIRST_MATCH - | ScanSettings.CALLBACK_TYPE_MATCH_LOST)) != 0) { + if ((callbackType + & (ScanSettings.CALLBACK_TYPE_FIRST_MATCH + | ScanSettings.CALLBACK_TYPE_MATCH_LOST)) + != 0) { if (filterList == null) { return false; } diff --git a/framework/java/android/bluetooth/le/BluetoothLeUtils.java b/framework/java/android/bluetooth/le/BluetoothLeUtils.java index fe11558e5ce0406c959feb664091d5e4d6d3483c..241035ccb21cc6a7d22783464173ae2fee1ad031 100644 --- a/framework/java/android/bluetooth/le/BluetoothLeUtils.java +++ b/framework/java/android/bluetooth/le/BluetoothLeUtils.java @@ -34,9 +34,7 @@ import java.util.UUID; */ public class BluetoothLeUtils { - /** - * Timeout value for synchronous binder call - */ + /** Timeout value for synchronous binder call */ private static final Duration SYNC_CALLS_TIMEOUT = Duration.ofSeconds(5); /** @@ -46,10 +44,8 @@ public class BluetoothLeUtils { return SYNC_CALLS_TIMEOUT; } - /** - * Returns a string composed from a byte array. - */ - static String toString(byte[] data) { + /** Returns a string composed from a byte array. */ + static String toString(byte[] data) { if (data == null) { return "null"; } @@ -68,9 +64,7 @@ public class BluetoothLeUtils { return buffer.toString(); } - /** - * Returns a string composed from a {@link SparseArray}. - */ + /** Returns a string composed from a {@link SparseArray}. */ static String toString(SparseArray array) { if (array == null) { return "null"; @@ -87,9 +81,7 @@ public class BluetoothLeUtils { return buffer.toString(); } - /** - * Returns a string composed from a {@link Map}. - */ + /** Returns a string composed from a {@link Map}. */ static String toString(Map map) { if (map == null) { return "null"; @@ -112,9 +104,7 @@ public class BluetoothLeUtils { return buffer.toString(); } - /** - * Check whether two {@link SparseArray} equal. - */ + /** Check whether two {@link SparseArray} equal. */ static boolean equals(SparseArray array, SparseArray otherArray) { if (array == otherArray) { return true; @@ -136,9 +126,7 @@ public class BluetoothLeUtils { return true; } - /** - * Check whether two {@link Map} equal. - */ + /** Check whether two {@link Map} equal. */ static boolean equals(Map map, Map otherMap) { if (map == otherMap) { return true; @@ -165,7 +153,7 @@ public class BluetoothLeUtils { * Ensure Bluetooth is turned on. * * @throws IllegalStateException If {@code adapter} is null or Bluetooth state is not {@link - * BluetoothAdapter#STATE_ON}. + * BluetoothAdapter#STATE_ON}. */ static void checkAdapterStateOn(BluetoothAdapter adapter) { if (adapter == null || !adapter.isLeEnabled()) { @@ -186,8 +174,8 @@ public class BluetoothLeUtils { return Objects.equals(data, uuid); } return (data.getLeastSignificantBits() & mask.getLeastSignificantBits()) - == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits()) + == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits()) && (data.getMostSignificantBits() & mask.getMostSignificantBits()) - == (uuid.getMostSignificantBits() & mask.getMostSignificantBits()); + == (uuid.getMostSignificantBits() & mask.getMostSignificantBits()); } } diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java index eb0f9b3899bb4d64071b9a0662de480a6f540086..55245d7b4e3c33a0373b2d1d72c753235df1e3c2 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java @@ -26,7 +26,6 @@ import android.annotation.SystemApi; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; import android.content.AttributionSource; import android.os.CancellationSignal; import android.os.ParcelUuid; @@ -44,12 +43,12 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; /** - * This class provides methods to perform distance measurement related - * operations. An application can start distance measurement by using - * {@link DistanceMeasurementManager#startMeasurementSession}. - *

    - * Use {@link BluetoothAdapter#getDistanceMeasurementManager()} to get an instance of - * {@link DistanceMeasurementManager}. + * This class provides methods to perform distance measurement related operations. An application + * can start distance measurement by using {@link + * DistanceMeasurementManager#startMeasurementSession}. + * + *

    Use {@link BluetoothAdapter#getDistanceMeasurementManager()} to get an instance of {@link + * DistanceMeasurementManager}. * * @hide */ @@ -60,7 +59,6 @@ public final class DistanceMeasurementManager { private final ConcurrentHashMap mSessionMap = new ConcurrentHashMap<>(); private final BluetoothAdapter mBluetoothAdapter; - private final IBluetoothManager mBluetoothManager; private final AttributionSource mAttributionSource; private final ParcelUuid mUuid; @@ -71,7 +69,6 @@ public final class DistanceMeasurementManager { */ public DistanceMeasurementManager(BluetoothAdapter bluetoothAdapter) { mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter); - mBluetoothManager = mBluetoothAdapter.getBluetoothManager(); mAttributionSource = mBluetoothAdapter.getAttributionSource(); mUuid = new ParcelUuid(UUID.randomUUID()); } @@ -79,28 +76,28 @@ public final class DistanceMeasurementManager { /** * Get the supported methods of distance measurement. * - *

    This can be used to check supported methods before start distance measurement. + *

    This can be used to check supported methods before start distance measurement. * * @return a list of {@link DistanceMeasurementMethod} - * * @hide */ @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @NonNull List getSupportedMethods() { final ArrayList supportedMethods = new ArrayList(); try { - IBluetoothGatt gatt = mBluetoothManager.getBluetoothGatt(); + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); if (gatt == null) { Log.e(TAG, "Bluetooth GATT is null"); return supportedMethods; } final SynchronousResultReceiver> recv = - SynchronousResultReceiver.get(); + SynchronousResultReceiver.get(); gatt.getSupportedDistanceMeasurementMethods(mAttributionSource, recv); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(new ArrayList<>()); } catch (TimeoutException | RemoteException e) { @@ -112,31 +109,30 @@ public final class DistanceMeasurementManager { /** * Start distance measurement and create a {@link DistanceMeasurementSession} for this * operation. Once the session is started, a {@link DistanceMeasurementSession} object is - * provided through - * {@link DistanceMeasurementSession.Callback#onStarted(DistanceMeasurementSession)}. - * If starting a session fails, the failure is reported through - * {@link DistanceMeasurementSession.Callback#onStartFail(int)} with the failure reason. + * provided through {@link + * DistanceMeasurementSession.Callback#onStarted(DistanceMeasurementSession)}. If starting a + * session fails, the failure is reported through {@link + * DistanceMeasurementSession.Callback#onStartFail(int)} with the failure reason. * * @param params parameters of this operation * @param executor Executor to run callback - * @param callback callback to associate with the - * {@link DistanceMeasurementSession} that is being started. The callback is - * registered by this function and unregisted when - * {@link DistanceMeasurementSession.Callback#onStartFail(int)} or - * {@link DistanceMeasurementSession - * .Callback#onStopped(DistanceMeasurementSession, int)} - * @return a CancellationSignal that may be used to cancel the starting of the - * {@link DistanceMeasurementSession} + * @param callback callback to associate with the {@link DistanceMeasurementSession} that is + * being started. The callback is registered by this function and unregistered when {@link + * DistanceMeasurementSession.Callback#onStartFail(int)} or {@link + * DistanceMeasurementSession .Callback#onStopped(DistanceMeasurementSession, int)} + * @return a CancellationSignal that may be used to cancel the starting of the {@link + * DistanceMeasurementSession} * @throws NullPointerException if any input parameter is null * @throws IllegalStateException if the session is already registered * @hide */ @SystemApi @Nullable - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public CancellationSignal startMeasurementSession( @NonNull DistanceMeasurementParams params, @NonNull Executor executor, @@ -145,62 +141,63 @@ public final class DistanceMeasurementManager { Objects.requireNonNull(executor, "executor is null"); Objects.requireNonNull(callback, "callback is null"); try { - IBluetoothGatt gatt = mBluetoothManager.getBluetoothGatt(); + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); if (gatt == null) { Log.e(TAG, "Bluetooth GATT is null"); return null; } - DistanceMeasurementSession session = new DistanceMeasurementSession(gatt, mUuid, - params, executor, mAttributionSource, callback); + DistanceMeasurementSession session = + new DistanceMeasurementSession( + gatt, mUuid, params, executor, mAttributionSource, callback); CancellationSignal cancellationSignal = new CancellationSignal(); cancellationSignal.setOnCancelListener(() -> session.stopSession()); if (mSessionMap.containsKey(params.getDevice())) { - throw new IllegalStateException(params.getDevice().getAnonymizedAddress() - + " already registered"); + throw new IllegalStateException( + params.getDevice().getAnonymizedAddress() + " already registered"); } mSessionMap.put(params.getDevice(), session); final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - gatt.startDistanceMeasurement(mUuid, params, mCallbackWrapper, mAttributionSource, - recv); + gatt.startDistanceMeasurement( + mUuid, params, mCallbackWrapper, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); return cancellationSignal; } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); return null; } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } } @SuppressLint("AndroidFrameworkBluetoothPermission") private final IDistanceMeasurementCallback mCallbackWrapper = new IDistanceMeasurementCallback.Stub() { - @Override - public void onStarted(BluetoothDevice device) { - DistanceMeasurementSession session = mSessionMap.get(device); - session.onStarted(); - } - - @Override - public void onStartFail(BluetoothDevice device, int reason) { - DistanceMeasurementSession session = mSessionMap.get(device); - session.onStartFail(reason); - mSessionMap.remove(device); - } - - @Override - public void onStopped(BluetoothDevice device, int reason) { - DistanceMeasurementSession session = mSessionMap.get(device); - session.onStopped(reason); - mSessionMap.remove(device); - } - - @Override - public void onResult(BluetoothDevice device, DistanceMeasurementResult result) { - DistanceMeasurementSession session = mSessionMap.get(device); - session.onResult(device, result); - } - }; + @Override + public void onStarted(BluetoothDevice device) { + DistanceMeasurementSession session = mSessionMap.get(device); + session.onStarted(); + } + + @Override + public void onStartFail(BluetoothDevice device, int reason) { + DistanceMeasurementSession session = mSessionMap.get(device); + session.onStartFail(reason); + mSessionMap.remove(device); + } + + @Override + public void onStopped(BluetoothDevice device, int reason) { + DistanceMeasurementSession session = mSessionMap.get(device); + session.onStopped(reason); + mSessionMap.remove(device); + } + + @Override + public void onResult(BluetoothDevice device, DistanceMeasurementResult result) { + DistanceMeasurementSession session = mSessionMap.get(device); + session.onResult(device, result); + } + }; } diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementMethod.java b/framework/java/android/bluetooth/le/DistanceMeasurementMethod.java index f44f6053ab3642ed4a9fda75c629e13a9f8ca401..b4a49075fdc5e20e4f62f212042a885bd3dbd15d 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementMethod.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementMethod.java @@ -27,9 +27,9 @@ import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** - * Method of distance measurement. A list of this class will be returned by - * {@link DistanceMeasurementManager#getSupportedMethods()} to indicate the supported methods and - * their capability about angle measurement. + * Method of distance measurement. A list of this class will be returned by {@link + * DistanceMeasurementManager#getSupportedMethods()} to indicate the supported methods and their + * capability about angle measurement. * * @hide */ @@ -40,34 +40,28 @@ public final class DistanceMeasurementMethod implements Parcelable { private final boolean mIsAzimuthAngleSupported; private final boolean mIsAltitudeAngleSupported; - /** - * @hide - */ + /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - DISTANCE_MEASUREMENT_METHOD_AUTO, - DISTANCE_MEASUREMENT_METHOD_RSSI}) - @interface DistanceMeasurementMethodId {} + @IntDef(value = {DISTANCE_MEASUREMENT_METHOD_AUTO, DISTANCE_MEASUREMENT_METHOD_RSSI}) + @interface DistanceMeasurementMethodId {} /** - * Choose method automatically, Bluetooth will use the most accurate method that local - * device supported to measurement distance. + * Choose method automatically, Bluetooth will use the most accurate method that local device + * supported to measurement distance. * * @hide */ - @SystemApi - public static final int DISTANCE_MEASUREMENT_METHOD_AUTO = 0; + @SystemApi public static final int DISTANCE_MEASUREMENT_METHOD_AUTO = 0; /** * Use remote RSSI and transmit power to measure the distance. * * @hide */ - @SystemApi - public static final int DISTANCE_MEASUREMENT_METHOD_RSSI = 1; + @SystemApi public static final int DISTANCE_MEASUREMENT_METHOD_RSSI = 1; - private DistanceMeasurementMethod(int id, boolean isAzimuthAngleSupported, - boolean isAltitudeAngleSupported) { + private DistanceMeasurementMethod( + int id, boolean isAzimuthAngleSupported, boolean isAltitudeAngleSupported) { mId = id; mIsAzimuthAngleSupported = isAzimuthAngleSupported; mIsAltitudeAngleSupported = isAltitudeAngleSupported; @@ -77,7 +71,6 @@ public final class DistanceMeasurementMethod implements Parcelable { * Id of the method used for {@link DistanceMeasurementParams.Builder#setMethod(int)} * * @return id of the method - * * @hide */ @SystemApi @@ -89,7 +82,6 @@ public final class DistanceMeasurementMethod implements Parcelable { * Checks whether the azimuth angle is supported for this method. * * @return true if azimuth angle is supported, false otherwise - * * @hide */ @SystemApi @@ -101,7 +93,6 @@ public final class DistanceMeasurementMethod implements Parcelable { * Checks whether the altitude angle is supported for this method. * * @return true if altitude angle is supported, false otherwise - * * @hide */ @SystemApi @@ -111,6 +102,7 @@ public final class DistanceMeasurementMethod implements Parcelable { /** * {@inheritDoc} + * * @hide */ @Override @@ -120,6 +112,7 @@ public final class DistanceMeasurementMethod implements Parcelable { /** * {@inheritDoc} + * * @hide */ @Override @@ -129,13 +122,18 @@ public final class DistanceMeasurementMethod implements Parcelable { out.writeBoolean(mIsAltitudeAngleSupported); } - /** @hide **/ + /** + * @hide * + */ @Override public String toString() { return "DistanceMeasurementMethod[" - + "id: " + mId - + ", isAzimuthAngleSupported: " + mIsAzimuthAngleSupported - + ", isAltitudeAngleSupported: " + mIsAltitudeAngleSupported + + "id: " + + mId + + ", isAzimuthAngleSupported: " + + mIsAzimuthAngleSupported + + ", isAltitudeAngleSupported: " + + mIsAltitudeAngleSupported + "]"; } @@ -159,23 +157,22 @@ public final class DistanceMeasurementMethod implements Parcelable { return Objects.hash(mId); } - /** - * A {@link Parcelable.Creator} to create {@link DistanceMeasurementMethod} from parcel. - * - */ + /** A {@link Parcelable.Creator} to create {@link DistanceMeasurementMethod} from parcel. */ public static final @NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public @NonNull DistanceMeasurementMethod createFromParcel(@NonNull Parcel in) { - return new Builder(in.readInt()).setAzimuthAngleSupported(in.readBoolean()) - .setAltitudeAngleSupported(in.readBoolean()).build(); + return new Builder(in.readInt()) + .setAzimuthAngleSupported(in.readBoolean()) + .setAltitudeAngleSupported(in.readBoolean()) + .build(); } @Override public @NonNull DistanceMeasurementMethod[] newArray(int size) { return new DistanceMeasurementMethod[size]; } - }; + }; /** * Builder for {@link DistanceMeasurementMethod}. @@ -204,11 +201,10 @@ public final class DistanceMeasurementMethod implements Parcelable { } } - /** + /** * Set if azimuth angle supported or not. * * @param supported {@code true} if azimuth angle supported, {@code false} otherwise - * * @hide */ @SystemApi @@ -222,7 +218,6 @@ public final class DistanceMeasurementMethod implements Parcelable { * Set if altitude angle supported or not. * * @param supported {@code true} if altitude angle supported, {@code false} otherwise - * * @hide */ @SystemApi @@ -240,8 +235,8 @@ public final class DistanceMeasurementMethod implements Parcelable { @SystemApi @NonNull public DistanceMeasurementMethod build() { - return new DistanceMeasurementMethod(mId, mIsAzimuthAngleSupported, - mIsAltitudeAngleSupported); + return new DistanceMeasurementMethod( + mId, mIsAzimuthAngleSupported, mIsAltitudeAngleSupported); } } } diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementParams.java b/framework/java/android/bluetooth/le/DistanceMeasurementParams.java index 734154a2fdc5a5a746b04c67fddb69a22593a6bc..5ff40a28719e88c0be73d43d4b48926f1c1302df 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementParams.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementParams.java @@ -38,15 +38,10 @@ import java.util.Objects; @SystemApi public final class DistanceMeasurementParams implements Parcelable { - /** - * @hide - */ + /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - REPORT_FREQUENCY_LOW, - REPORT_FREQUENCY_MEDIUM, - REPORT_FREQUENCY_HIGH}) - @interface ReportFrequency {} + @IntDef(value = {REPORT_FREQUENCY_LOW, REPORT_FREQUENCY_MEDIUM, REPORT_FREQUENCY_HIGH}) + @interface ReportFrequency {} /** * Perform distance measurement in low frequency. This is the default frequency as it consumes @@ -54,9 +49,7 @@ public final class DistanceMeasurementParams implements Parcelable { * * @hide */ - @SystemApi - public static final int REPORT_FREQUENCY_LOW = 0; - + @SystemApi public static final int REPORT_FREQUENCY_LOW = 0; /** * Perform distance measurement in medium frequency. Provides a good trade-off between report @@ -64,8 +57,7 @@ public final class DistanceMeasurementParams implements Parcelable { * * @hide */ - @SystemApi - public static final int REPORT_FREQUENCY_MEDIUM = 1; + @SystemApi public static final int REPORT_FREQUENCY_MEDIUM = 1; /** * Perform distance measurement in high frequency. It's recommended to only use this mode when @@ -73,8 +65,7 @@ public final class DistanceMeasurementParams implements Parcelable { * * @hide */ - @SystemApi - public static final int REPORT_FREQUENCY_HIGH = 2; + @SystemApi public static final int REPORT_FREQUENCY_HIGH = 2; private static final int REPORT_DURATION_DEFAULT = 60; private static final int REPORT_DURATION_MAX = 3600; @@ -84,11 +75,9 @@ public final class DistanceMeasurementParams implements Parcelable { private int mFrequency; private int mMethodId; - /** - * @hide - */ - public DistanceMeasurementParams(BluetoothDevice device, int duration, int frequency, - int methodId) { + /** @hide */ + public DistanceMeasurementParams( + BluetoothDevice device, int duration, int frequency, int methodId) { mDevice = Objects.requireNonNull(device); mDuration = duration; mFrequency = frequency; @@ -107,9 +96,9 @@ public final class DistanceMeasurementParams implements Parcelable { /** * Returns duration in seconds of this DistanceMeasurementParams. Once the distance measurement - * successfully started, the Bluetooth process will keep reporting the measurement result - * until this time has been reached or the session is explicitly stopped with - * {@link DistanceMeasurementSession#stopSession} + * successfully started, the Bluetooth process will keep reporting the measurement result until + * this time has been reached or the session is explicitly stopped with {@link + * DistanceMeasurementSession#stopSession} * * @hide */ @@ -119,8 +108,8 @@ public final class DistanceMeasurementParams implements Parcelable { } /** - * Returns frequency of this DistanceMeasurementParams. The Bluetooth process uses this value - * to determine report frequency of the measurement result. + * Returns frequency of this DistanceMeasurementParams. The Bluetooth process uses this value to + * determine report frequency of the measurement result. * * @hide */ @@ -141,6 +130,7 @@ public final class DistanceMeasurementParams implements Parcelable { /** * Get the default duration in seconds of the parameter. + * * @hide */ @SystemApi @@ -150,6 +140,7 @@ public final class DistanceMeasurementParams implements Parcelable { /** * Get the maximum duration in seconds that can be set for the parameter. + * * @hide */ @SystemApi @@ -159,6 +150,7 @@ public final class DistanceMeasurementParams implements Parcelable { /** * {@inheritDoc} + * * @hide */ @Override @@ -168,6 +160,7 @@ public final class DistanceMeasurementParams implements Parcelable { /** * {@inheritDoc} + * * @hide */ @Override @@ -178,10 +171,7 @@ public final class DistanceMeasurementParams implements Parcelable { out.writeInt(mMethodId); } - /** - * A {@link Parcelable.Creator} to create {@link DistanceMeasurementParams} from parcel. - * - */ + /** A {@link Parcelable.Creator} to create {@link DistanceMeasurementParams} from parcel. */ public static final @NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override @@ -197,8 +187,7 @@ public final class DistanceMeasurementParams implements Parcelable { public @NonNull DistanceMeasurementParams[] newArray(int size) { return new DistanceMeasurementParams[size]; } - }; - + }; /** * Builder for {@link DistanceMeasurementParams}. @@ -224,13 +213,13 @@ public final class DistanceMeasurementParams implements Parcelable { /** * Set duration in seconds for the DistanceMeasurementParams. Once the distance measurement * successfully started, the Bluetooth process will keep reporting the measurement result - * until this time has been reached or the session is explicitly stopped with - * {@link DistanceMeasurementSession#stopSession}. + * until this time has been reached or the session is explicitly stopped with {@link + * DistanceMeasurementSession#stopSession}. * * @param duration duration in seconds of this DistanceMeasurementParams * @return the same Builder instance - * @throws IllegalArgumentException if duration greater than - * {@link DistanceMeasurementParams#getMaxDurationSeconds()} or less than zero. + * @throws IllegalArgumentException if duration greater than {@link + * DistanceMeasurementParams#getMaxDurationSeconds()} or less than zero. * @hide */ @SystemApi @@ -243,12 +232,11 @@ public final class DistanceMeasurementParams implements Parcelable { } /** - * Set frequency for the DistanceMeasurementParams. The Bluetooth process uses this value - * to determine report frequency of the measurement result. + * Set frequency for the DistanceMeasurementParams. The Bluetooth process uses this value to + * determine report frequency of the measurement result. * * @param frequency frequency of this DistanceMeasurementParams * @return the same Builder instance - * * @hide */ @SystemApi @@ -270,7 +258,6 @@ public final class DistanceMeasurementParams implements Parcelable { * * @param methodId method id of this DistanceMeasurementParams * @return the same Builder instance - * * @hide */ @SystemApi diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementResult.java b/framework/java/android/bluetooth/le/DistanceMeasurementResult.java index 59bbf2af6fb4b0b5cb32101b89acb53f14452921..513bab6c07549cb2523921ca95c20aab19986ce3 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementResult.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementResult.java @@ -37,8 +37,13 @@ public final class DistanceMeasurementResult implements Parcelable { private final double mAltitudeAngle; private final double mErrorAltitudeAngle; - private DistanceMeasurementResult(double meters, double errorMeters, double azimuthAngle, - double errorAzimuthAngle, double altitudeAngle, double errorAltitudeAngle) { + private DistanceMeasurementResult( + double meters, + double errorMeters, + double azimuthAngle, + double errorAzimuthAngle, + double altitudeAngle, + double errorAltitudeAngle) { mMeters = meters; mErrorMeters = errorMeters; mAzimuthAngle = azimuthAngle; @@ -51,7 +56,6 @@ public final class DistanceMeasurementResult implements Parcelable { * Distance measurement in meters. * * @return distance in meters - * * @hide */ @SystemApi @@ -61,10 +65,10 @@ public final class DistanceMeasurementResult implements Parcelable { /** * Error of distance measurement in meters. + * *

    Must be positive. * * @return error of distance measurement in meters - * * @hide */ @SystemApi @@ -76,12 +80,12 @@ public final class DistanceMeasurementResult implements Parcelable { /** * Azimuth Angle measurement in degrees. * - * Azimuth of remote device in horizontal coordinate system, this measured from azimuth north + *

    Azimuth of remote device in horizontal coordinate system, this measured from azimuth north * and increasing eastward. When the remote device in azimuth north, this angle is 0, whe the * remote device in azimuth south, this angle is 180. * *

    See: Horizontal - * coordinate systemfor the details + * coordinate systemfor the details * *

    On an Android device, azimuth north is defined as the angle perpendicular away from the * back of the device when holding it in portrait mode upright. @@ -90,7 +94,6 @@ public final class DistanceMeasurementResult implements Parcelable { * facing when it is placed flat. * * @return azimuth angle in degrees or Double.NaN if not available - * * @hide */ @SystemApi @@ -105,7 +108,6 @@ public final class DistanceMeasurementResult implements Parcelable { *

    Must be a positive value. * * @return azimuth angle measurement error in degrees or Double.NaN if not available - * * @hide */ @SystemApi @@ -123,7 +125,6 @@ public final class DistanceMeasurementResult implements Parcelable { *

    See: https://en.wikipedia.org/wiki/Horizontal_coordinate_system * * @return altitude angle in degrees or Double.NaN if not available - * * @hide */ @SystemApi @@ -138,7 +139,6 @@ public final class DistanceMeasurementResult implements Parcelable { *

    Must be a positive value. * * @return altitude angle measurement error in degrees or Double.NaN if not available - * * @hide */ @SystemApi @@ -148,6 +148,7 @@ public final class DistanceMeasurementResult implements Parcelable { /** * {@inheritDoc} + * * @hide */ @Override @@ -157,6 +158,7 @@ public final class DistanceMeasurementResult implements Parcelable { /** * {@inheritDoc} + * * @hide */ @Override @@ -169,23 +171,28 @@ public final class DistanceMeasurementResult implements Parcelable { out.writeDouble(mErrorAltitudeAngle); } - /** @hide **/ + /** + * @hide * + */ @Override public String toString() { return "DistanceMeasurement[" - + "meters: " + mMeters - + ", errorMeters: " + mErrorMeters - + ", azimuthAngle: " + mAzimuthAngle - + ", errorAzimuthAngle: " + mErrorAzimuthAngle - + ", altitudeAngle: " + mAltitudeAngle - + ", errorAltitudeAngle: " + mErrorAltitudeAngle + + "meters: " + + mMeters + + ", errorMeters: " + + mErrorMeters + + ", azimuthAngle: " + + mAzimuthAngle + + ", errorAzimuthAngle: " + + mErrorAzimuthAngle + + ", altitudeAngle: " + + mAltitudeAngle + + ", errorAltitudeAngle: " + + mErrorAltitudeAngle + "]"; } - /** - * A {@link Parcelable.Creator} to create {@link DistanceMeasurementResult} from parcel. - * - */ + /** A {@link Parcelable.Creator} to create {@link DistanceMeasurementResult} from parcel. */ public static final @NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override @@ -202,7 +209,7 @@ public final class DistanceMeasurementResult implements Parcelable { public @NonNull DistanceMeasurementResult[] newArray(int size) { return new DistanceMeasurementResult[size]; } - }; + }; /** * Builder for {@link DistanceMeasurementResult}. @@ -225,11 +232,10 @@ public final class DistanceMeasurementResult implements Parcelable { * @param errorMeters distance error in meters * @throws IllegalArgumentException if meters is NaN or error is negative or NaN */ - public Builder(@FloatRange(from = 0.0) double meters, - @FloatRange(from = 0.0)double errorMeters) { + public Builder( + @FloatRange(from = 0.0) double meters, @FloatRange(from = 0.0) double errorMeters) { if (Double.isNaN(meters) || meters < 0.0) { - throw new IllegalArgumentException( - "meters must be >= 0.0 and not NaN: " + meters); + throw new IllegalArgumentException("meters must be >= 0.0 and not NaN: " + meters); } if (Double.isNaN(errorMeters) || errorMeters < 0.0) { throw new IllegalArgumentException( @@ -244,7 +250,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @param angle azimuth angle in degrees * @throws IllegalArgumentException if value is invalid - * * @hide */ @SystemApi @@ -263,7 +268,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @param angle azimuth angle error in degrees * @throws IllegalArgumentException if value is invalid - * * @hide */ @SystemApi @@ -282,7 +286,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @param angle altitude angle in degrees * @throws IllegalArgumentException if value is invalid - * * @hide */ @SystemApi @@ -301,7 +304,6 @@ public final class DistanceMeasurementResult implements Parcelable { * * @param angle altitude angle error in degrees * @throws IllegalArgumentException if value is invalid - * * @hide */ @SystemApi @@ -319,14 +321,18 @@ public final class DistanceMeasurementResult implements Parcelable { * Builds the {@link DistanceMeasurementResult} object. * * @throws IllegalStateException if meters, error, or confidence are not set - * * @hide */ @SystemApi @NonNull public DistanceMeasurementResult build() { - return new DistanceMeasurementResult(mMeters, mErrorMeters, mAzimuthAngle, - mErrorAzimuthAngle, mAltitudeAngle, mErrorAltitudeAngle); + return new DistanceMeasurementResult( + mMeters, + mErrorMeters, + mAzimuthAngle, + mErrorAzimuthAngle, + mAltitudeAngle, + mErrorAltitudeAngle); } } } diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementSession.java b/framework/java/android/bluetooth/le/DistanceMeasurementSession.java index d88dba4c8ce28b882235432f73b7bafadafcb1d8..f645e78771a2c314b25d23bb943836860d638b10 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementSession.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementSession.java @@ -41,17 +41,18 @@ import java.util.concurrent.TimeoutException; /** * This class provides a way to control an active distance measurement session. + * *

    It also defines the required {@link DistanceMeasurementSession.Callback} that must be * implemented in order to be notified of distance measurement results and status events related to * the {@link DistanceMeasurementSession}. * - *

    To get an instance of {@link DistanceMeasurementSession}, first use - * {@link DistanceMeasurementManager#startMeasurementSession(DistanceMeasurementParams, Executor, + *

    To get an instance of {@link DistanceMeasurementSession}, first use {@link + * DistanceMeasurementManager#startMeasurementSession(DistanceMeasurementParams, Executor, * DistanceMeasurementSession.Callback)} to request to start a session. Once the session is started, - * a {@link DistanceMeasurementSession} object is provided through - * {@link DistanceMeasurementSession.Callback#onStarted(DistanceMeasurementSession)}. - * If starting a session fails, the failure is reported through - * {@link DistanceMeasurementSession.Callback#onStartFail(int)} with the failure reason. + * a {@link DistanceMeasurementSession} object is provided through {@link + * DistanceMeasurementSession.Callback#onStarted(DistanceMeasurementSession)}. If starting a session + * fails, the failure is reported through {@link + * DistanceMeasurementSession.Callback#onStartFail(int)} with the failure reason. * * @hide */ @@ -68,19 +69,22 @@ public final class DistanceMeasurementSession { /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.SUCCESS, - BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, - BluetoothStatusCodes.ERROR_DISTANCE_MEASUREMENT_INTERNAL, - }) - public @interface StopSessionReturnValues{} + @IntDef( + value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, + BluetoothStatusCodes.ERROR_DISTANCE_MEASUREMENT_INTERNAL, + }) + public @interface StopSessionReturnValues {} - /** - * @hide - */ - public DistanceMeasurementSession(IBluetoothGatt gatt, ParcelUuid uuid, - DistanceMeasurementParams params, Executor executor, - AttributionSource attributionSource, Callback callback) { + /** @hide */ + public DistanceMeasurementSession( + IBluetoothGatt gatt, + ParcelUuid uuid, + DistanceMeasurementParams params, + Executor executor, + AttributionSource attributionSource, + Callback callback) { Objects.requireNonNull(gatt, "gatt is null"); Objects.requireNonNull(params, "params is null"); Objects.requireNonNull(executor, "executor is null"); @@ -97,63 +101,54 @@ public final class DistanceMeasurementSession { * Stops actively ranging, {@link Callback#onStopped} will be invoked if this succeeds. * * @return whether successfully stop or not - * * @hide */ @SystemApi - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @StopSessionReturnValues int stopSession() { final int defaultValue = BluetoothStatusCodes.ERROR_TIMEOUT; try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mGatt.stopDistanceMeasurement(mUuid, mDistanceMeasurementParams.getDevice(), - mDistanceMeasurementParams.getMethodId(), mAttributionSource, recv); + mGatt.stopDistanceMeasurement( + mUuid, + mDistanceMeasurementParams.getDevice(), + mDistanceMeasurementParams.getMethodId(), + mAttributionSource, + recv); return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); } return defaultValue; } - /** - * @hide - */ + /** @hide */ void onStarted() { executeCallback(() -> mCallback.onStarted(this)); } - /** - * @hide - */ + /** @hide */ void onStartFail(int reason) { executeCallback(() -> mCallback.onStartFail(reason)); } - - /** - * @hide - */ + /** @hide */ void onStopped(int reason) { executeCallback(() -> mCallback.onStopped(this, reason)); } - /** - * @hide - */ - void onResult(@NonNull BluetoothDevice device, - @NonNull DistanceMeasurementResult result) { + /** @hide */ + void onResult(@NonNull BluetoothDevice device, @NonNull DistanceMeasurementResult result) { executeCallback(() -> mCallback.onResult(device, result)); } - - /** - * @hide - */ + /** @hide */ private void executeCallback(@NonNull Runnable runnable) { final long identity = Binder.clearCallingIdentity(); try { @@ -170,22 +165,21 @@ public final class DistanceMeasurementSession { */ @SystemApi public interface Callback { - /** - * @hide - */ + /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - BluetoothStatusCodes.ERROR_UNKNOWN, - BluetoothStatusCodes.FEATURE_NOT_SUPPORTED, - BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED, - BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST, - BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST, - BluetoothStatusCodes.REASON_REMOTE_REQUEST, - BluetoothStatusCodes.ERROR_TIMEOUT, - BluetoothStatusCodes.ERROR_NO_LE_CONNECTION, - BluetoothStatusCodes.ERROR_BAD_PARAMETERS, - BluetoothStatusCodes.ERROR_DISTANCE_MEASUREMENT_INTERNAL, - }) + @IntDef( + value = { + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.FEATURE_NOT_SUPPORTED, + BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED, + BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST, + BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST, + BluetoothStatusCodes.REASON_REMOTE_REQUEST, + BluetoothStatusCodes.ERROR_TIMEOUT, + BluetoothStatusCodes.ERROR_NO_LE_CONNECTION, + BluetoothStatusCodes.ERROR_BAD_PARAMETERS, + BluetoothStatusCodes.ERROR_DISTANCE_MEASUREMENT_INTERNAL, + }) @interface Reason {} /** @@ -193,18 +187,16 @@ public final class DistanceMeasurementSession { * DistanceMeasurementParams, Executor, DistanceMeasurementSession.Callback)} is successful. * * @param session the started {@link DistanceMeasurementSession} - * * @hide */ @SystemApi void onStarted(@NonNull DistanceMeasurementSession session); - /** + /** * Invoked if {@link DistanceMeasurementManager#startMeasurementSession( * DistanceMeasurementParams, Executor, DistanceMeasurementSession.Callback)} fails. * * @param reason the failure reason - * * @hide */ @SystemApi @@ -214,7 +206,6 @@ public final class DistanceMeasurementSession { * Invoked when a distance measurement session stopped. * * @param reason reason for the session stop - * * @hide */ @SystemApi @@ -225,11 +216,9 @@ public final class DistanceMeasurementSession { * * @param device remote device * @param result {@link DistanceMeasurementResult} for this device - * * @hide */ @SystemApi - void onResult(@NonNull BluetoothDevice device, - @NonNull DistanceMeasurementResult result); + void onResult(@NonNull BluetoothDevice device, @NonNull DistanceMeasurementResult result); } } diff --git a/framework/java/android/bluetooth/le/PeriodicAdvertisingCallback.java b/framework/java/android/bluetooth/le/PeriodicAdvertisingCallback.java index c4b9313ceb4760c8f5a684d9cd41360a0cd81fe5..dafcb0272ad70cfd596422a97875621dcbd46718 100644 --- a/framework/java/android/bluetooth/le/PeriodicAdvertisingCallback.java +++ b/framework/java/android/bluetooth/le/PeriodicAdvertisingCallback.java @@ -19,8 +19,8 @@ package android.bluetooth.le; import android.bluetooth.BluetoothDevice; /** - * Bluetooth LE periodic advertising callbacks, used to deliver periodic - * advertising operation status. + * Bluetooth LE periodic advertising callbacks, used to deliver periodic advertising operation + * status. * * @hide * @see PeriodicAdvertisingManager#createSync @@ -34,17 +34,12 @@ public abstract class PeriodicAdvertisingCallback { */ public static final int SYNC_SUCCESS = 0; - /** - * Sync failed to be established because remote device did not respond. - */ + /** Sync failed to be established because remote device did not respond. */ public static final int SYNC_NO_RESPONSE = 1; - /** - * Sync failed to be established because controller can't support more syncs. - */ + /** Sync failed to be established because controller can't support more syncs. */ public static final int SYNC_NO_RESOURCES = 2; - /** * Callback when synchronization was established. * @@ -52,41 +47,37 @@ public abstract class PeriodicAdvertisingCallback { * @param device remote device. * @param advertisingSid synchronized advertising set id. * @param skip The number of periodic advertising packets that can be skipped after a successful - * receive in force. @see PeriodicAdvertisingManager#createSync + * receive in force. @see PeriodicAdvertisingManager#createSync * @param timeout Synchronization timeout for the periodic advertising in force. One unit is - * 10ms. @see PeriodicAdvertisingManager#createSync - * @param timeout + * 10ms. @see PeriodicAdvertisingManager#createSync * @param status operation status. */ - public void onSyncEstablished(int syncHandle, BluetoothDevice device, - int advertisingSid, int skip, int timeout, - int status) { - } + public void onSyncEstablished( + int syncHandle, + BluetoothDevice device, + int advertisingSid, + int skip, + int timeout, + int status) {} /** * Callback when periodic advertising report is received. * * @param report periodic advertising report. */ - public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) { - } + public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) {} /** * Callback when periodic advertising synchronization was lost. * * @param syncHandle handle used to identify this synchronization. */ - public void onSyncLost(int syncHandle) { - } + public void onSyncLost(int syncHandle) {} /** * Callback when periodic sync transferred. - * - * @param device - * @param status */ - public void onSyncTransferred(BluetoothDevice device, int status) { - } + public void onSyncTransferred(BluetoothDevice device, int status) {} /** * Callback when BIGInfo advertising report is received. @@ -94,6 +85,5 @@ public abstract class PeriodicAdvertisingCallback { * @param syncHandle handle used to identify this synchronization. * @param encrypted BIG carries encrypted data or not */ - public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) { - } + public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) {} } diff --git a/framework/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/framework/java/android/bluetooth/le/PeriodicAdvertisingManager.java index 2fd1d9f5f191a1a1f8a9378a2f69066c83bd81de..93748bdabbc0564af41c195b08fa1a5c7039bfb0 100644 --- a/framework/java/android/bluetooth/le/PeriodicAdvertisingManager.java +++ b/framework/java/android/bluetooth/le/PeriodicAdvertisingManager.java @@ -25,7 +25,6 @@ import android.bluetooth.Attributable; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.IBluetoothGatt; -import android.bluetooth.IBluetoothManager; import android.bluetooth.annotations.RequiresBluetoothLocationPermission; import android.bluetooth.annotations.RequiresBluetoothScanPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; @@ -38,17 +37,15 @@ import android.util.Log; import com.android.modules.utils.SynchronousResultReceiver; import java.util.IdentityHashMap; -import java.util.Map; import java.util.Objects; import java.util.concurrent.TimeoutException; /** - * This class provides methods to perform periodic advertising related - * operations. An application can register for periodic advertisements using - * {@link PeriodicAdvertisingManager#registerSync}. - *

    - * Use {@link BluetoothAdapter#getPeriodicAdvertisingManager()} to get an - * instance of {@link PeriodicAdvertisingManager}. + * This class provides methods to perform periodic advertising related operations. An application + * can register for periodic advertisements using {@link PeriodicAdvertisingManager#registerSync}. + * + *

    Use {@link BluetoothAdapter#getPeriodicAdvertisingManager()} to get an instance of {@link + * PeriodicAdvertisingManager}. * * @hide */ @@ -61,81 +58,78 @@ public final class PeriodicAdvertisingManager { private static final int TIMEOUT_MIN = 10; private static final int TIMEOUT_MAX = 16384; - private static final int SYNC_STARTING = -1; - private final BluetoothAdapter mBluetoothAdapter; - private final IBluetoothManager mBluetoothManager; private final AttributionSource mAttributionSource; /* maps callback, to callback wrapper and sync handle */ - Map mCallbackWrappers; + IdentityHashMap + mCallbackWrappers; /** * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead. * - * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management. * @hide */ public PeriodicAdvertisingManager(BluetoothAdapter bluetoothAdapter) { mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter); - mBluetoothManager = mBluetoothAdapter.getBluetoothManager(); mAttributionSource = mBluetoothAdapter.getAttributionSource(); mCallbackWrappers = new IdentityHashMap<>(); } /** - * Synchronize with periodic advertising pointed to by the {@code scanResult}. - * The {@code scanResult} used must contain a valid advertisingSid. First - * call to registerSync will use the {@code skip} and {@code timeout} provided. - * Subsequent calls from other apps, trying to sync with same set will reuse - * existing sync, thus {@code skip} and {@code timeout} values will not take - * effect. The values in effect will be returned in - * {@link PeriodicAdvertisingCallback#onSyncEstablished}. + * Synchronize with periodic advertising pointed to by the {@code scanResult}. The {@code + * scanResult} used must contain a valid advertisingSid. First call to registerSync will use the + * {@code skip} and {@code timeout} provided. Subsequent calls from other apps, trying to sync + * with same set will reuse existing sync, thus {@code skip} and {@code timeout} values will not + * take effect. The values in effect will be returned in {@link + * PeriodicAdvertisingCallback#onSyncEstablished}. * * @param scanResult Scan result containing advertisingSid. * @param skip The number of periodic advertising packets that can be skipped after a successful - * receive. Must be between 0 and 499. + * receive. Must be between 0 and 499. * @param timeout Synchronization timeout for the periodic advertising. One unit is 10ms. Must - * be between 10 (100ms) and 16384 (163.84s). + * be between 10 (100ms) and 16384 (163.84s). * @param callback Callback used to deliver all operations status. * @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or - * {@code timeout} is invalid or {@code callback} is null. + * {@code timeout} is invalid or {@code callback} is null. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothScanPermission @RequiresBluetoothLocationPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void registerSync(ScanResult scanResult, int skip, int timeout, - PeriodicAdvertisingCallback callback) { + public void registerSync( + ScanResult scanResult, int skip, int timeout, PeriodicAdvertisingCallback callback) { registerSync(scanResult, skip, timeout, callback, null); } /** - * Synchronize with periodic advertising pointed to by the {@code scanResult}. - * The {@code scanResult} used must contain a valid advertisingSid. First - * call to registerSync will use the {@code skip} and {@code timeout} provided. - * Subsequent calls from other apps, trying to sync with same set will reuse - * existing sync, thus {@code skip} and {@code timeout} values will not take - * effect. The values in effect will be returned in - * {@link PeriodicAdvertisingCallback#onSyncEstablished}. + * Synchronize with periodic advertising pointed to by the {@code scanResult}. The {@code + * scanResult} used must contain a valid advertisingSid. First call to registerSync will use the + * {@code skip} and {@code timeout} provided. Subsequent calls from other apps, trying to sync + * with same set will reuse existing sync, thus {@code skip} and {@code timeout} values will not + * take effect. The values in effect will be returned in {@link + * PeriodicAdvertisingCallback#onSyncEstablished}. * * @param scanResult Scan result containing advertisingSid. * @param skip The number of periodic advertising packets that can be skipped after a successful - * receive. Must be between 0 and 499. + * receive. Must be between 0 and 499. * @param timeout Synchronization timeout for the periodic advertising. One unit is 10ms. Must - * be between 10 (100ms) and 16384 (163.84s). + * be between 10 (100ms) and 16384 (163.84s). * @param callback Callback used to deliver all operations status. * @param handler thread upon which the callbacks will be invoked. * @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or - * {@code timeout} is invalid or {@code callback} is null. + * {@code timeout} is invalid or {@code callback} is null. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothScanPermission @RequiresBluetoothLocationPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) - public void registerSync(ScanResult scanResult, int skip, int timeout, - PeriodicAdvertisingCallback callback, Handler handler) { + public void registerSync( + ScanResult scanResult, + int skip, + int timeout, + PeriodicAdvertisingCallback callback, + Handler handler) { if (callback == null) { throw new IllegalArgumentException("callback can't be null"); } @@ -158,16 +152,7 @@ public final class PeriodicAdvertisingManager { "timeout must be between " + TIMEOUT_MIN + " and " + TIMEOUT_MAX); } - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - callback.onSyncEstablished(0, scanResult.getDevice(), scanResult.getAdvertisingSid(), - skip, timeout, - PeriodicAdvertisingCallback.SYNC_NO_RESOURCES); - return; - } + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); if (handler == null) { handler = new Handler(Looper.getMainLooper()); @@ -191,7 +176,7 @@ public final class PeriodicAdvertisingManager { * * @param callback Callback used to deliver all operations status. * @throws IllegalArgumentException if {@code callback} is null, or not a properly registered - * callback. + * callback. */ @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothScanPermission @@ -201,13 +186,7 @@ public final class PeriodicAdvertisingManager { throw new IllegalArgumentException("callback can't be null"); } - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - return; - } + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); IPeriodicAdvertisingCallback wrapper = mCallbackWrappers.remove(callback); if (wrapper == null) { @@ -230,24 +209,11 @@ public final class PeriodicAdvertisingManager { * @hide */ public void transferSync(BluetoothDevice bda, int serviceData, int syncHandle) { - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - PeriodicAdvertisingCallback callback = null; - for (PeriodicAdvertisingCallback cb : mCallbackWrappers.keySet()) { - callback = cb; - } - if (callback != null) { - callback.onSyncTransferred(bda, - PeriodicAdvertisingCallback.SYNC_NO_RESOURCES); - } - return; - } + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); + try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - gatt.transferSync(bda, serviceData , syncHandle, mAttributionSource, recv); + gatt.transferSync(bda, serviceData, syncHandle, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (TimeoutException | RemoteException e) { Log.e(TAG, "Failed to register sync - ", e); @@ -260,8 +226,11 @@ public final class PeriodicAdvertisingManager { * * @hide */ - public void transferSetInfo(BluetoothDevice bda, int serviceData, - int advHandle, PeriodicAdvertisingCallback callback) { + public void transferSetInfo( + BluetoothDevice bda, + int serviceData, + int advHandle, + PeriodicAdvertisingCallback callback) { transferSetInfo(bda, serviceData, advHandle, callback, null); } @@ -270,19 +239,16 @@ public final class PeriodicAdvertisingManager { * * @hide */ - public void transferSetInfo(BluetoothDevice bda, int serviceData, - int advHandle, PeriodicAdvertisingCallback callback, - @Nullable Handler handler) { + public void transferSetInfo( + BluetoothDevice bda, + int serviceData, + int advHandle, + PeriodicAdvertisingCallback callback, + @Nullable Handler handler) { if (callback == null) { throw new IllegalArgumentException("callback can't be null"); } - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - return; - } + IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt(); if (handler == null) { handler = new Handler(Looper.getMainLooper()); } @@ -292,76 +258,85 @@ public final class PeriodicAdvertisingManager { } try { final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - gatt.transferSetInfo(bda, serviceData , advHandle, wrapper, mAttributionSource, recv); + gatt.transferSetInfo(bda, serviceData, advHandle, wrapper, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Failed to register sync - ", e); return; } - } @SuppressLint("AndroidFrameworkBluetoothPermission") - private IPeriodicAdvertisingCallback wrap(PeriodicAdvertisingCallback callback, - Handler handler) { + private IPeriodicAdvertisingCallback wrap( + PeriodicAdvertisingCallback callback, Handler handler) { return new IPeriodicAdvertisingCallback.Stub() { - public void onSyncEstablished(int syncHandle, BluetoothDevice device, - int advertisingSid, int skip, int timeout, int status) { + public void onSyncEstablished( + int syncHandle, + BluetoothDevice device, + int advertisingSid, + int skip, + int timeout, + int status) { Attributable.setAttributionSource(device, mAttributionSource); - handler.post(new Runnable() { - @Override - public void run() { - callback.onSyncEstablished(syncHandle, device, advertisingSid, skip, - timeout, - status); - - if (status != PeriodicAdvertisingCallback.SYNC_SUCCESS) { - // App can still unregister the sync until notified it failed. Remove - // callback - // after app was notifed. - mCallbackWrappers.remove(callback); - } - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + callback.onSyncEstablished( + syncHandle, device, advertisingSid, skip, timeout, status); + + if (status != PeriodicAdvertisingCallback.SYNC_SUCCESS) { + // App can still unregister the sync until notified it failed. + // Remove + // callback + // after app was notified. + mCallbackWrappers.remove(callback); + } + } + }); } public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) { - handler.post(new Runnable() { - @Override - public void run() { - callback.onPeriodicAdvertisingReport(report); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + callback.onPeriodicAdvertisingReport(report); + } + }); } public void onSyncLost(int syncHandle) { - handler.post(new Runnable() { - @Override - public void run() { - callback.onSyncLost(syncHandle); - // App can still unregister the sync until notified it's lost. - // Remove callback after app was notifed. - mCallbackWrappers.remove(callback); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + callback.onSyncLost(syncHandle); + // App can still unregister the sync until notified it's lost. + // Remove callback after app was notified. + mCallbackWrappers.remove(callback); + } + }); } public void onSyncTransferred(BluetoothDevice device, int status) { - handler.post(new Runnable() { - @Override - public void run() { - callback.onSyncTransferred(device, status); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + callback.onSyncTransferred(device, status); + } + }); } public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) { - handler.post(new Runnable() { - @Override - public void run() { - callback.onBigInfoAdvertisingReport(syncHandle, encrypted); - } - }); + handler.post( + new Runnable() { + @Override + public void run() { + callback.onBigInfoAdvertisingReport(syncHandle, encrypted); + } + }); } }; } diff --git a/framework/java/android/bluetooth/le/PeriodicAdvertisingParameters.java b/framework/java/android/bluetooth/le/PeriodicAdvertisingParameters.java index 4e64dbed7017b3e8fbaa71b09e1d14c1a57d1d7e..47639b481e47a86f4cea81c8d0187bf0c6a45648 100644 --- a/framework/java/android/bluetooth/le/PeriodicAdvertisingParameters.java +++ b/framework/java/android/bluetooth/le/PeriodicAdvertisingParameters.java @@ -20,8 +20,8 @@ import android.os.Parcel; import android.os.Parcelable; /** - * The {@link PeriodicAdvertisingParameters} provide a way to adjust periodic - * advertising preferences for each Bluetooth LE advertising set. Use {@link + * The {@link PeriodicAdvertisingParameters} provide a way to adjust periodic advertising + * preferences for each Bluetooth LE advertising set. Use {@link * PeriodicAdvertisingParameters.Builder} to create an instance of this class. */ public final class PeriodicAdvertisingParameters implements Parcelable { @@ -42,16 +42,14 @@ public final class PeriodicAdvertisingParameters implements Parcelable { mInterval = in.readInt(); } - /** - * Returns whether the TX Power will be included. - */ + /** Returns whether the TX Power will be included. */ public boolean getIncludeTxPower() { return mIncludeTxPower; } /** - * Returns the periodic advertising interval, in 1.25ms unit. - * Valid values are from 80 (100ms) to 65519 (81.89875s). + * Returns the periodic advertising interval, in 1.25ms unit. Valid values are from 80 (100ms) + * to 65519 (81.89875s). */ public int getInterval() { return mInterval; @@ -68,8 +66,7 @@ public final class PeriodicAdvertisingParameters implements Parcelable { dest.writeInt(mInterval); } - public static final Parcelable - .Creator CREATOR = + public static final Parcelable.Creator CREATOR = new Creator() { @Override public PeriodicAdvertisingParameters[] newArray(int size) { @@ -86,34 +83,29 @@ public final class PeriodicAdvertisingParameters implements Parcelable { private boolean mIncludeTxPower = false; private int mInterval = INTERVAL_MAX; - /** - * Whether the transmission power level should be included in the periodic - * packet. - */ + /** Whether the transmission power level should be included in the periodic packet. */ public Builder setIncludeTxPower(boolean includeTxPower) { mIncludeTxPower = includeTxPower; return this; } /** - * Set advertising interval for periodic advertising, in 1.25ms unit. - * Valid values are from 80 (100ms) to 65519 (81.89875s). - * Value from range [interval, interval+20ms] will be picked as the actual value. + * Set advertising interval for periodic advertising, in 1.25ms unit. Valid values are from + * 80 (100ms) to 65519 (81.89875s). Value from range [interval, interval+20ms] will be + * picked as the actual value. * * @throws IllegalArgumentException If the interval is invalid. */ public Builder setInterval(int interval) { if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { - throw new IllegalArgumentException("Invalid interval (must be " + INTERVAL_MIN - + "-" + INTERVAL_MAX + ")"); + throw new IllegalArgumentException( + "Invalid interval (must be " + INTERVAL_MIN + "-" + INTERVAL_MAX + ")"); } mInterval = interval; return this; } - /** - * Build the {@link AdvertisingSetParameters} object. - */ + /** Build the {@link AdvertisingSetParameters} object. */ public PeriodicAdvertisingParameters build() { return new PeriodicAdvertisingParameters(mIncludeTxPower, mInterval); } diff --git a/framework/java/android/bluetooth/le/PeriodicAdvertisingReport.java b/framework/java/android/bluetooth/le/PeriodicAdvertisingReport.java index 54b953c25c277493c81433d7ad8593afa1d110d8..095b04613bdc0ae0ee84fee0b445f039ceaf6bdd 100644 --- a/framework/java/android/bluetooth/le/PeriodicAdvertisingReport.java +++ b/framework/java/android/bluetooth/le/PeriodicAdvertisingReport.java @@ -29,14 +29,12 @@ import java.util.Objects; */ public final class PeriodicAdvertisingReport implements Parcelable { - /** - * The data returned is complete - */ + /** The data returned is complete */ public static final int DATA_COMPLETE = 0; /** - * The data returned is incomplete. The controller was unsuccessfull to - * receive all chained packets, returning only partial data. + * The data returned is incomplete. The controller was unsuccessful to receive all chained + * packets, returning only partial data. */ public static final int DATA_INCOMPLETE_TRUNCATED = 2; @@ -46,17 +44,14 @@ public final class PeriodicAdvertisingReport implements Parcelable { private int mDataStatus; // periodic advertising data. - @Nullable - private ScanRecord mData; + @Nullable private ScanRecord mData; // Device timestamp when the result was last seen. private long mTimestampNanos; - /** - * Constructor of periodic advertising result. - */ - public PeriodicAdvertisingReport(int syncHandle, int txPower, int rssi, - int dataStatus, ScanRecord data) { + /** Constructor of periodic advertising result. */ + public PeriodicAdvertisingReport( + int syncHandle, int txPower, int rssi, int dataStatus, ScanRecord data) { mSyncHandle = syncHandle; mTxPower = txPower; mRssi = rssi; @@ -97,47 +92,39 @@ public final class PeriodicAdvertisingReport implements Parcelable { return 0; } - /** - * Returns the synchronization handle. - */ + /** Returns the synchronization handle. */ public int getSyncHandle() { return mSyncHandle; } /** - * Returns the transmit power in dBm. The valid range is [-127, 126]. Value - * of 127 means information was not available. + * Returns the transmit power in dBm. The valid range is [-127, 126]. Value of 127 means + * information was not available. */ public int getTxPower() { return mTxPower; } - /** - * Returns the received signal strength in dBm. The valid range is [-127, 20]. - */ + /** Returns the received signal strength in dBm. The valid range is [-127, 20]. */ public int getRssi() { return mRssi; } /** - * Returns the data status. Can be one of {@link PeriodicAdvertisingReport#DATA_COMPLETE} - * or {@link PeriodicAdvertisingReport#DATA_INCOMPLETE_TRUNCATED}. + * Returns the data status. Can be one of {@link PeriodicAdvertisingReport#DATA_COMPLETE} or + * {@link PeriodicAdvertisingReport#DATA_INCOMPLETE_TRUNCATED}. */ public int getDataStatus() { return mDataStatus; } - /** - * Returns the data contained in this periodic advertising report. - */ + /** Returns the data contained in this periodic advertising report. */ @Nullable public ScanRecord getData() { return mData; } - /** - * Returns timestamp since boot when the scan record was observed. - */ + /** Returns timestamp since boot when the scan record was observed. */ public long getTimestampNanos() { return mTimestampNanos; } @@ -166,21 +153,32 @@ public final class PeriodicAdvertisingReport implements Parcelable { @Override public String toString() { - return "PeriodicAdvertisingReport{syncHandle=" + mSyncHandle - + ", txPower=" + mTxPower + ", rssi=" + mRssi + ", dataStatus=" + mDataStatus - + ", data=" + Objects.toString(mData) + ", timestampNanos=" + mTimestampNanos + '}'; + return "PeriodicAdvertisingReport{syncHandle=" + + mSyncHandle + + ", txPower=" + + mTxPower + + ", rssi=" + + mRssi + + ", dataStatus=" + + mDataStatus + + ", data=" + + Objects.toString(mData) + + ", timestampNanos=" + + mTimestampNanos + + '}'; } - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public PeriodicAdvertisingReport createFromParcel(Parcel source) { - return new PeriodicAdvertisingReport(source); - } - - @Override - public PeriodicAdvertisingReport[] newArray(int size) { - return new PeriodicAdvertisingReport[size]; - } - }; + public static final @android.annotation.NonNull Parcelable.Creator + CREATOR = + new Creator() { + @Override + public PeriodicAdvertisingReport createFromParcel(Parcel source) { + return new PeriodicAdvertisingReport(source); + } + + @Override + public PeriodicAdvertisingReport[] newArray(int size) { + return new PeriodicAdvertisingReport[size]; + } + }; } diff --git a/framework/java/android/bluetooth/le/ResultStorageDescriptor.java b/framework/java/android/bluetooth/le/ResultStorageDescriptor.java index f65048975deb56763292c9826b8ed04979ab7cab..4b5bd76c341997ebc77418d279e8a2232e108ab0 100644 --- a/framework/java/android/bluetooth/le/ResultStorageDescriptor.java +++ b/framework/java/android/bluetooth/le/ResultStorageDescriptor.java @@ -24,7 +24,6 @@ import android.os.Parcelable; * Describes the way to store scan result. * * @deprecated this is not used anywhere - * * @hide */ @Deprecated @@ -81,16 +80,17 @@ public final class ResultStorageDescriptor implements Parcelable { mLength = in.readInt(); } - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Creator() { - @Override - public ResultStorageDescriptor createFromParcel(Parcel source) { - return new ResultStorageDescriptor(source); - } + public static final @android.annotation.NonNull Parcelable.Creator + CREATOR = + new Creator() { + @Override + public ResultStorageDescriptor createFromParcel(Parcel source) { + return new ResultStorageDescriptor(source); + } - @Override - public ResultStorageDescriptor[] newArray(int size) { - return new ResultStorageDescriptor[size]; - } - }; + @Override + public ResultStorageDescriptor[] newArray(int size) { + return new ResultStorageDescriptor[size]; + } + }; } diff --git a/framework/java/android/bluetooth/le/ScanCallback.java b/framework/java/android/bluetooth/le/ScanCallback.java index 45d72ef7846e94944951a7f5dbaa257bfef19a3d..ec9164186f9f84470caddd728553c90edf396ad5 100644 --- a/framework/java/android/bluetooth/le/ScanCallback.java +++ b/framework/java/android/bluetooth/le/ScanCallback.java @@ -32,45 +32,33 @@ public abstract class ScanCallback { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( - prefix = { "SCAN_FAILED_" }, - value = { - SCAN_FAILED_ALREADY_STARTED, - SCAN_FAILED_APPLICATION_REGISTRATION_FAILED, - SCAN_FAILED_INTERNAL_ERROR, - SCAN_FAILED_FEATURE_UNSUPPORTED, - SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES, - SCAN_FAILED_SCANNING_TOO_FREQUENTLY, - } - ) + prefix = {"SCAN_FAILED_"}, + value = { + SCAN_FAILED_ALREADY_STARTED, + SCAN_FAILED_APPLICATION_REGISTRATION_FAILED, + SCAN_FAILED_INTERNAL_ERROR, + SCAN_FAILED_FEATURE_UNSUPPORTED, + SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES, + SCAN_FAILED_SCANNING_TOO_FREQUENTLY, + }) public @interface ScanFailed {} - /** - * Fails to start scan as BLE scan with the same settings is already started by the app. - */ + + /** Fails to start scan as BLE scan with the same settings is already started by the app. */ public static final int SCAN_FAILED_ALREADY_STARTED = 1; - /** - * Fails to start scan as app cannot be registered. - */ + /** Fails to start scan as app cannot be registered. */ public static final int SCAN_FAILED_APPLICATION_REGISTRATION_FAILED = 2; - /** - * Fails to start scan due an internal error - */ + /** Fails to start scan due an internal error */ public static final int SCAN_FAILED_INTERNAL_ERROR = 3; - /** - * Fails to start power optimized scan as this feature is not supported. - */ + /** Fails to start power optimized scan as this feature is not supported. */ public static final int SCAN_FAILED_FEATURE_UNSUPPORTED = 4; - /** - * Fails to start scan as it is out of hardware resources. - */ + /** Fails to start scan as it is out of hardware resources. */ public static final int SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5; - /** - * Fails to start scan as application tries to scan too frequently. - */ + /** Fails to start scan as application tries to scan too frequently. */ public static final int SCAN_FAILED_SCANNING_TOO_FREQUENTLY = 6; static final int NO_ERROR = 0; @@ -79,26 +67,23 @@ public abstract class ScanCallback { * Callback when a BLE advertisement has been found. * * @param callbackType Determines how this callback was triggered. Could be one of {@link - * ScanSettings#CALLBACK_TYPE_ALL_MATCHES}, {@link ScanSettings#CALLBACK_TYPE_FIRST_MATCH} or - * {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST} + * ScanSettings#CALLBACK_TYPE_ALL_MATCHES}, {@link ScanSettings#CALLBACK_TYPE_FIRST_MATCH} + * or {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST} * @param result A Bluetooth LE scan result. */ - public void onScanResult(int callbackType, ScanResult result) { - } + public void onScanResult(int callbackType, ScanResult result) {} /** * Callback when batch results are delivered. * * @param results List of scan results that are previously scanned. */ - public void onBatchScanResults(List results) { - } + public void onBatchScanResults(List results) {} /** * Callback when scan could not be started. * * @param errorCode Error code (one of SCAN_FAILED_*) for scan failure. */ - public void onScanFailed(@ScanFailed int errorCode) { - } + public void onScanFailed(@ScanFailed int errorCode) {} } diff --git a/framework/java/android/bluetooth/le/ScanFilter.java b/framework/java/android/bluetooth/le/ScanFilter.java index 6d66af8ea36bfa44a9aac5995031814bea18ac82..cd8de2905832e6f41ac03969e1ca2f99887350b7 100644 --- a/framework/java/android/bluetooth/le/ScanFilter.java +++ b/framework/java/android/bluetooth/le/ScanFilter.java @@ -38,8 +38,8 @@ import java.util.UUID; /** * Criteria for filtering result from Bluetooth LE scans. A {@link ScanFilter} allows clients to * restrict scan results to only those that are of interest to them. - *

    - * Current filtering on the following fields are supported: + * + *

    Current filtering on the following fields are supported: *

  • Service UUIDs which identify the bluetooth gatt services running on the device. *
  • Name of remote Bluetooth LE device. *
  • Mac address of the remote device. @@ -52,58 +52,55 @@ import java.util.UUID; */ public final class ScanFilter implements Parcelable { - @Nullable - private final String mDeviceName; + @Nullable private final String mDeviceName; - @Nullable - private final String mDeviceAddress; + @Nullable private final String mDeviceAddress; private final @AddressType int mAddressType; - @Nullable - private final byte[] mIrk; + @Nullable private final byte[] mIrk; - @Nullable - private final ParcelUuid mServiceUuid; - @Nullable - private final ParcelUuid mServiceUuidMask; + @Nullable private final ParcelUuid mServiceUuid; + @Nullable private final ParcelUuid mServiceUuidMask; - @Nullable - private final ParcelUuid mServiceSolicitationUuid; - @Nullable - private final ParcelUuid mServiceSolicitationUuidMask; + @Nullable private final ParcelUuid mServiceSolicitationUuid; + @Nullable private final ParcelUuid mServiceSolicitationUuidMask; - @Nullable - private final ParcelUuid mServiceDataUuid; - @Nullable - private final byte[] mServiceData; - @Nullable - private final byte[] mServiceDataMask; + @Nullable private final ParcelUuid mServiceDataUuid; + @Nullable private final byte[] mServiceData; + @Nullable private final byte[] mServiceDataMask; private final int mManufacturerId; - @Nullable - private final byte[] mManufacturerData; - @Nullable - private final byte[] mManufacturerDataMask; + @Nullable private final byte[] mManufacturerData; + @Nullable private final byte[] mManufacturerDataMask; private int mAdvertisingDataType = ScanRecord.DATA_TYPE_NONE; - @Nullable - private final byte[] mAdvertisingData; - @Nullable - private final byte[] mAdvertisingDataMask; + @Nullable private final byte[] mAdvertisingData; + @Nullable private final byte[] mAdvertisingDataMask; - @Nullable - private final TransportBlockFilter mTransportBlockFilter; + @Nullable private final TransportBlockFilter mTransportBlockFilter; /** @hide */ public static final ScanFilter EMPTY = new ScanFilter.Builder().build(); - private ScanFilter(String name, String deviceAddress, ParcelUuid uuid, ParcelUuid uuidMask, - ParcelUuid solicitationUuid, ParcelUuid solicitationUuidMask, - ParcelUuid serviceDataUuid, byte[] serviceData, byte[] serviceDataMask, - int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask, - @AddressType int addressType, @Nullable byte[] irk, int advertisingDataType, - @Nullable byte[] advertisingData, @Nullable byte[] advertisingDataMask, + private ScanFilter( + String name, + String deviceAddress, + ParcelUuid uuid, + ParcelUuid uuidMask, + ParcelUuid solicitationUuid, + ParcelUuid solicitationUuidMask, + ParcelUuid serviceDataUuid, + byte[] serviceData, + byte[] serviceDataMask, + int manufacturerId, + byte[] manufacturerData, + byte[] manufacturerDataMask, + @AddressType int addressType, + @Nullable byte[] irk, + int advertisingDataType, + @Nullable byte[] advertisingData, + @Nullable byte[] advertisingDataMask, @Nullable TransportBlockFilter transportBlockFilter) { mDeviceName = name; mServiceUuid = uuid; @@ -213,132 +210,127 @@ public final class ScanFilter implements Parcelable { } } - /** - * A {@link android.os.Parcelable.Creator} to create {@link ScanFilter} from parcel. - */ + /** A {@link android.os.Parcelable.Creator} to create {@link ScanFilter} from parcel. */ public static final @android.annotation.NonNull Creator CREATOR = new Creator() { - @Override - public ScanFilter[] newArray(int size) { - return new ScanFilter[size]; - } - - @Override - public ScanFilter createFromParcel(Parcel in) { - Builder builder = new Builder(); - if (in.readInt() == 1) { - builder.setDeviceName(in.readString()); - } - String address = null; - // If we have a non-null address - if (in.readInt() == 1) { - address = in.readString(); - } - if (in.readInt() == 1) { - ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader()); - builder.setServiceUuid(uuid); - if (in.readInt() == 1) { - ParcelUuid uuidMask = in.readParcelable( - ParcelUuid.class.getClassLoader()); - builder.setServiceUuid(uuid, uuidMask); + @Override + public ScanFilter[] newArray(int size) { + return new ScanFilter[size]; } - } - if (in.readInt() == 1) { - ParcelUuid solicitationUuid = in.readParcelable( - ParcelUuid.class.getClassLoader()); - builder.setServiceSolicitationUuid(solicitationUuid); - if (in.readInt() == 1) { - ParcelUuid solicitationUuidMask = in.readParcelable( - ParcelUuid.class.getClassLoader()); - builder.setServiceSolicitationUuid(solicitationUuid, - solicitationUuidMask); - } - } - if (in.readInt() == 1) { - ParcelUuid servcieDataUuid = - in.readParcelable(ParcelUuid.class.getClassLoader()); - if (in.readInt() == 1) { - int serviceDataLength = in.readInt(); - byte[] serviceData = new byte[serviceDataLength]; - in.readByteArray(serviceData); - if (in.readInt() == 0) { - builder.setServiceData(servcieDataUuid, serviceData); - } else { - int serviceDataMaskLength = in.readInt(); - byte[] serviceDataMask = new byte[serviceDataMaskLength]; - in.readByteArray(serviceDataMask); - builder.setServiceData( - servcieDataUuid, serviceData, serviceDataMask); + + @Override + public ScanFilter createFromParcel(Parcel in) { + Builder builder = new Builder(); + if (in.readInt() == 1) { + builder.setDeviceName(in.readString()); + } + String address = null; + // If we have a non-null address + if (in.readInt() == 1) { + address = in.readString(); + } + if (in.readInt() == 1) { + ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader()); + builder.setServiceUuid(uuid); + if (in.readInt() == 1) { + ParcelUuid uuidMask = + in.readParcelable(ParcelUuid.class.getClassLoader()); + builder.setServiceUuid(uuid, uuidMask); + } + } + if (in.readInt() == 1) { + ParcelUuid solicitationUuid = + in.readParcelable(ParcelUuid.class.getClassLoader()); + builder.setServiceSolicitationUuid(solicitationUuid); + if (in.readInt() == 1) { + ParcelUuid solicitationUuidMask = + in.readParcelable(ParcelUuid.class.getClassLoader()); + builder.setServiceSolicitationUuid( + solicitationUuid, solicitationUuidMask); + } + } + if (in.readInt() == 1) { + ParcelUuid serviceDataUuid = + in.readParcelable(ParcelUuid.class.getClassLoader()); + if (in.readInt() == 1) { + int serviceDataLength = in.readInt(); + byte[] serviceData = new byte[serviceDataLength]; + in.readByteArray(serviceData); + if (in.readInt() == 0) { + builder.setServiceData(serviceDataUuid, serviceData); + } else { + int serviceDataMaskLength = in.readInt(); + byte[] serviceDataMask = new byte[serviceDataMaskLength]; + in.readByteArray(serviceDataMask); + builder.setServiceData( + serviceDataUuid, serviceData, serviceDataMask); + } + } } - } - } - int manufacturerId = in.readInt(); - if (in.readInt() == 1) { - int manufacturerDataLength = in.readInt(); - byte[] manufacturerData = new byte[manufacturerDataLength]; - in.readByteArray(manufacturerData); - if (in.readInt() == 0) { - builder.setManufacturerData(manufacturerId, manufacturerData); - } else { - int manufacturerDataMaskLength = in.readInt(); - byte[] manufacturerDataMask = new byte[manufacturerDataMaskLength]; - in.readByteArray(manufacturerDataMask); - builder.setManufacturerData(manufacturerId, manufacturerData, - manufacturerDataMask); - } - } + int manufacturerId = in.readInt(); + if (in.readInt() == 1) { + int manufacturerDataLength = in.readInt(); + byte[] manufacturerData = new byte[manufacturerDataLength]; + in.readByteArray(manufacturerData); + if (in.readInt() == 0) { + builder.setManufacturerData(manufacturerId, manufacturerData); + } else { + int manufacturerDataMaskLength = in.readInt(); + byte[] manufacturerDataMask = new byte[manufacturerDataMaskLength]; + in.readByteArray(manufacturerDataMask); + builder.setManufacturerData( + manufacturerId, manufacturerData, manufacturerDataMask); + } + } - // IRK - if (address != null) { - final int addressType = in.readInt(); - if (in.readInt() == 1) { - final byte[] irk = new byte[16]; - in.readByteArray(irk); - builder.setDeviceAddress(address, addressType, irk); - } else { - builder.setDeviceAddress(address, addressType); - } - } + // IRK + if (address != null) { + final int addressType = in.readInt(); + if (in.readInt() == 1) { + final byte[] irk = new byte[16]; + in.readByteArray(irk); + builder.setDeviceAddress(address, addressType, irk); + } else { + builder.setDeviceAddress(address, addressType); + } + } - // Advertising data type - int advertisingDataType = in.readInt(); - if (in.readInt() == 1) { - byte[] advertisingData = null; - byte[] advertisingDataMask = null; - - int advertisingDataLength = in.readInt(); - advertisingData = new byte[advertisingDataLength]; - in.readByteArray(advertisingData); - if (in.readInt() == 1) { - int advertisingDataMaskLength = in.readInt(); - advertisingDataMask = new byte[advertisingDataMaskLength]; - in.readByteArray(advertisingDataMask); - } - builder.setAdvertisingDataTypeWithData(advertisingDataType, advertisingData, - advertisingDataMask); - } + // Advertising data type + int advertisingDataType = in.readInt(); + if (in.readInt() == 1) { + byte[] advertisingData = null; + byte[] advertisingDataMask = null; + + int advertisingDataLength = in.readInt(); + advertisingData = new byte[advertisingDataLength]; + in.readByteArray(advertisingData); + if (in.readInt() == 1) { + int advertisingDataMaskLength = in.readInt(); + advertisingDataMask = new byte[advertisingDataMaskLength]; + in.readByteArray(advertisingDataMask); + } + builder.setAdvertisingDataTypeWithData( + advertisingDataType, advertisingData, advertisingDataMask); + } - if (in.readInt() == 1) { - builder.setTransportBlockFilter(in.readTypedObject(TransportBlockFilter.CREATOR)); - } + if (in.readInt() == 1) { + builder.setTransportBlockFilter( + in.readTypedObject(TransportBlockFilter.CREATOR)); + } - return builder.build(); - } - }; + return builder.build(); + } + }; - /** - * Returns the filter set the device name field of Bluetooth advertisement data. - */ + /** Returns the filter set the device name field of Bluetooth advertisement data. */ @Nullable public String getDeviceName() { return mDeviceName; } - /** - * Returns the filter set on the service uuid. - */ + /** Returns the filter set on the service uuid. */ @Nullable public ParcelUuid getServiceUuid() { return mServiceUuid; @@ -349,17 +341,13 @@ public final class ScanFilter implements Parcelable { return mServiceUuidMask; } - /** - * Returns the filter set on the service Solicitation uuid. - */ + /** Returns the filter set on the service Solicitation uuid. */ @Nullable public ParcelUuid getServiceSolicitationUuid() { return mServiceSolicitationUuid; } - /** - * Returns the filter set on the service Solicitation uuid mask. - */ + /** Returns the filter set on the service Solicitation uuid mask. */ @Nullable public ParcelUuid getServiceSolicitationUuidMask() { return mServiceSolicitationUuidMask; @@ -370,17 +358,13 @@ public final class ScanFilter implements Parcelable { return mDeviceAddress; } - /** - * @hide - */ + /** @hide */ @SystemApi public @AddressType int getAddressType() { return mAddressType; } - /** - * @hide - */ + /** @hide */ @SystemApi @Nullable public byte[] getIrk() { @@ -402,9 +386,7 @@ public final class ScanFilter implements Parcelable { return mServiceDataUuid; } - /** - * Returns the manufacturer id. -1 if the manufacturer filter is not set. - */ + /** Returns the manufacturer id. -1 if the manufacturer filter is not set. */ public int getManufacturerId() { return mManufacturerId; } @@ -431,26 +413,21 @@ public final class ScanFilter implements Parcelable { } /** - * Returns the advertising data type of this filter. - * Returns {@link ScanRecord#DATA_TYPE_NONE} if the type is not set. - * The values of advertising data type are defined in the Bluetooth Generic Access Profile - * (https://www.bluetooth.com/specifications/assigned-numbers/) - */ + * Returns the advertising data type of this filter. Returns {@link ScanRecord#DATA_TYPE_NONE} + * if the type is not set. The values of advertising data type are defined in the Bluetooth + * Generic Access Profile (https://www.bluetooth.com/specifications/assigned-numbers/) + */ @AdvertisingDataType public int getAdvertisingDataType() { return mAdvertisingDataType; } - /** - * Returns the advertising data of this filter. - */ + /** Returns the advertising data of this filter. */ public @Nullable byte[] getAdvertisingData() { return mAdvertisingData; } - /** - * Returns the advertising data mask of this filter. - */ + /** Returns the advertising data mask of this filter. */ public @Nullable byte[] getAdvertisingDataMask() { return mAdvertisingDataMask; } @@ -474,9 +451,12 @@ public final class ScanFilter implements Parcelable { // Scan record is null but there exist filters on it. if (scanRecord == null - && (mDeviceName != null || mServiceUuid != null || mManufacturerData != null - || mServiceData != null || mServiceSolicitationUuid != null - || mAdvertisingData != null)) { + && (mDeviceName != null + || mServiceUuid != null + || mManufacturerData != null + || mServiceData != null + || mServiceSolicitationUuid != null + || mAdvertisingData != null)) { return false; } @@ -486,29 +466,34 @@ public final class ScanFilter implements Parcelable { } // UUID match. - if (mServiceUuid != null && !matchesServiceUuids(mServiceUuid, mServiceUuidMask, - scanRecord.getServiceUuids())) { + if (mServiceUuid != null + && !matchesServiceUuids( + mServiceUuid, mServiceUuidMask, scanRecord.getServiceUuids())) { return false; } // solicitation UUID match. - if (mServiceSolicitationUuid != null && !matchesServiceSolicitationUuids( - mServiceSolicitationUuid, mServiceSolicitationUuidMask, - scanRecord.getServiceSolicitationUuids())) { + if (mServiceSolicitationUuid != null + && !matchesServiceSolicitationUuids( + mServiceSolicitationUuid, + mServiceSolicitationUuidMask, + scanRecord.getServiceSolicitationUuids())) { return false; } // Service data match if (mServiceDataUuid != null) { - if (!matchesPartialData(mServiceData, mServiceDataMask, - scanRecord.getServiceData(mServiceDataUuid))) { + if (!matchesPartialData( + mServiceData, mServiceDataMask, scanRecord.getServiceData(mServiceDataUuid))) { return false; } } // Manufacturer data match. if (mManufacturerId >= 0) { - if (!matchesPartialData(mManufacturerData, mManufacturerDataMask, + if (!matchesPartialData( + mManufacturerData, + mManufacturerDataMask, scanRecord.getManufacturerSpecificData(mManufacturerId))) { return false; } @@ -517,8 +502,9 @@ public final class ScanFilter implements Parcelable { // Advertising data type match if (mAdvertisingDataType > 0) { byte[] advertisingData = scanRecord.getAdvertisingDataMap().get(mAdvertisingDataType); - if (advertisingData == null || !matchesPartialData(mAdvertisingData, - mAdvertisingDataMask, advertisingData)) { + if (advertisingData == null + || !matchesPartialData( + mAdvertisingData, mAdvertisingDataMask, advertisingData)) { return false; } } @@ -537,8 +523,8 @@ public final class ScanFilter implements Parcelable { * * @hide */ - public static boolean matchesServiceUuids(ParcelUuid uuid, ParcelUuid parcelUuidMask, - List uuids) { + public static boolean matchesServiceUuids( + ParcelUuid uuid, ParcelUuid parcelUuidMask, List uuids) { if (uuid == null) { return true; } @@ -560,12 +546,11 @@ public final class ScanFilter implements Parcelable { return BluetoothLeUtils.maskedEquals(data, uuid, mask); } - /** - * Check if the solicitation uuid pattern is contained in a list of parcel uuids. - * - */ - private static boolean matchesServiceSolicitationUuids(ParcelUuid solicitationUuid, - ParcelUuid parcelSolicitationUuidMask, List solicitationUuids) { + /** Check if the solicitation uuid pattern is contained in a list of parcel uuids. */ + private static boolean matchesServiceSolicitationUuids( + ParcelUuid solicitationUuid, + ParcelUuid parcelSolicitationUuidMask, + List solicitationUuids) { if (solicitationUuid == null) { return true; } @@ -574,9 +559,13 @@ public final class ScanFilter implements Parcelable { } for (ParcelUuid parcelSolicitationUuid : solicitationUuids) { - UUID solicitationUuidMask = parcelSolicitationUuidMask == null - ? null : parcelSolicitationUuidMask.getUuid(); - if (matchesServiceUuid(solicitationUuid.getUuid(), solicitationUuidMask, + UUID solicitationUuidMask = + parcelSolicitationUuidMask == null + ? null + : parcelSolicitationUuidMask.getUuid(); + if (matchesServiceUuid( + solicitationUuid.getUuid(), + solicitationUuidMask, parcelSolicitationUuid.getUuid())) { return true; } @@ -584,12 +573,6 @@ public final class ScanFilter implements Parcelable { return false; } - // Check if the solicitation uuid pattern matches the particular service solicitation uuid. - private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid, - UUID solicitationUuidMask, UUID data) { - return BluetoothLeUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); - } - // Check whether the data pattern matches the parsed data. static boolean matchesPartialData(byte[] data, byte[] dataMask, byte[] parsedData) { if (parsedData == null || parsedData.length < data.length) { @@ -613,31 +596,56 @@ public final class ScanFilter implements Parcelable { @Override public String toString() { - return "BluetoothLeScanFilter [mDeviceName=" + mDeviceName + ", mDeviceAddress=" - + mDeviceAddress + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask - + ", mServiceSolicitationUuid=" + mServiceSolicitationUuid - + ", mServiceSolicitationUuidMask=" + mServiceSolicitationUuidMask - + ", mServiceDataUuid=" + Objects.toString(mServiceDataUuid) - + ", mServiceData=" + Arrays.toString(mServiceData) + ", mServiceDataMask=" - + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId - + ", mManufacturerData=" + Arrays.toString(mManufacturerData) - + ", mManufacturerDataMask=" + Arrays.toString(mManufacturerDataMask) - + ", mAdvertisingDataType=" + mAdvertisingDataType + ", mAdvertisingData=" - + Arrays.toString(mAdvertisingData) + ", mAdvertisingDataMask=" + return "BluetoothLeScanFilter [mDeviceName=" + + mDeviceName + + ", mDeviceAddress=" + + mDeviceAddress + + ", mUuid=" + + mServiceUuid + + ", mUuidMask=" + + mServiceUuidMask + + ", mServiceSolicitationUuid=" + + mServiceSolicitationUuid + + ", mServiceSolicitationUuidMask=" + + mServiceSolicitationUuidMask + + ", mServiceDataUuid=" + + Objects.toString(mServiceDataUuid) + + ", mServiceData=" + + Arrays.toString(mServiceData) + + ", mServiceDataMask=" + + Arrays.toString(mServiceDataMask) + + ", mManufacturerId=" + + mManufacturerId + + ", mManufacturerData=" + + Arrays.toString(mManufacturerData) + + ", mManufacturerDataMask=" + + Arrays.toString(mManufacturerDataMask) + + ", mAdvertisingDataType=" + + mAdvertisingDataType + + ", mAdvertisingData=" + + Arrays.toString(mAdvertisingData) + + ", mAdvertisingDataMask=" + Arrays.toString(mAdvertisingDataMask) - + ", mTransportBlockFilter=" + mTransportBlockFilter + "]"; + + ", mTransportBlockFilter=" + + mTransportBlockFilter + + "]"; } @Override public int hashCode() { - return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId, + return Objects.hash( + mDeviceName, + mDeviceAddress, + mManufacturerId, Arrays.hashCode(mManufacturerData), Arrays.hashCode(mManufacturerDataMask), mServiceDataUuid, Arrays.hashCode(mServiceData), Arrays.hashCode(mServiceDataMask), - mServiceUuid, mServiceUuidMask, - mServiceSolicitationUuid, mServiceSolicitationUuidMask, + mServiceUuid, + mServiceUuidMask, + mServiceSolicitationUuid, + mServiceSolicitationUuidMask, mAdvertisingDataType, Arrays.hashCode(mAdvertisingData), Arrays.hashCode(mAdvertisingDataMask), @@ -664,8 +672,7 @@ public final class ScanFilter implements Parcelable { && Objects.equals(mServiceUuid, other.mServiceUuid) && Objects.equals(mServiceUuidMask, other.mServiceUuidMask) && Objects.equals(mServiceSolicitationUuid, other.mServiceSolicitationUuid) - && Objects.equals(mServiceSolicitationUuidMask, - other.mServiceSolicitationUuidMask) + && Objects.equals(mServiceSolicitationUuidMask, other.mServiceSolicitationUuidMask) && mAdvertisingDataType == other.mAdvertisingDataType && Objects.deepEquals(mAdvertisingData, other.mAdvertisingData) && Objects.deepEquals(mAdvertisingDataMask, other.mAdvertisingDataMask) @@ -681,16 +688,11 @@ public final class ScanFilter implements Parcelable { return EMPTY.equals(this); } - /** - * Builder class for {@link ScanFilter}. - */ + /** Builder class for {@link ScanFilter}. */ public static final class Builder { - /** - * @hide - */ - @SystemApi - public static final int LEN_IRK_OCTETS = 16; + /** @hide */ + @SystemApi public static final int LEN_IRK_OCTETS = 16; private String mDeviceName; private String mDeviceAddress; @@ -716,9 +718,8 @@ public final class ScanFilter implements Parcelable { private byte[] mAdvertisingDataMask; private TransportBlockFilter mTransportBlockFilter = null; - /** - * Set filter on device name. - */ + + /** Set filter on device name. */ public Builder setDeviceName(String deviceName) { mDeviceName = deviceName; return this; @@ -726,11 +727,11 @@ public final class ScanFilter implements Parcelable { /** * Set a scan filter on the remote device address. - *

    - * The address passed to this API must be in big endian byte order. It needs to be in the - * format of "01:02:03:AB:CD:EF". The device address can be validated using - * {@link BluetoothAdapter#checkBluetoothAddress}. The @AddressType is defaulted to - * {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}. + * + *

    The address passed to this API must be in big endian byte order. It needs to be in the + * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link + * BluetoothAdapter#checkBluetoothAddress}. The @AddressType is defaulted to {@link + * BluetoothDevice#ADDRESS_TYPE_PUBLIC}. * * @param deviceAddress the remote device Bluetooth address for the filter * @throws IllegalArgumentException if the {@code deviceAddress} is invalid @@ -745,57 +746,66 @@ public final class ScanFilter implements Parcelable { /** * Set a scan filter on the remote device address with an address type. - *

    - * The address passed to this API must be in big endian byte order. It needs to be in the - * format of "01:02:03:AB:CD:EF". The device address can be validated using - * {@link BluetoothAdapter#checkBluetoothAddress}. + * + *

    The address passed to this API must be in big endian byte order. It needs to be in the + * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link + * BluetoothAdapter#checkBluetoothAddress}. * * @param deviceAddress the remote device Bluetooth address for the filter * @param addressType indication of the type of address - * * @throws IllegalArgumentException If the {@code deviceAddress} is invalid * @throws IllegalArgumentException If the {@code addressType} is invalid length or is not - * either {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} or - * {@link BluetoothDevice#ADDRESS_TYPE_RANDOM} + * either {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} or {@link + * BluetoothDevice#ADDRESS_TYPE_RANDOM} * @throws NullPointerException if {@code deviceAddress} is null - * * @hide */ @NonNull @SystemApi - public Builder setDeviceAddress(@NonNull String deviceAddress, - @AddressType int addressType) { + public Builder setDeviceAddress( + @NonNull String deviceAddress, @AddressType int addressType) { return setDeviceAddressInternal(deviceAddress, addressType, null); } /** * Set a scan filter on the remote device address with an address type and the Identity * Resolving Key (IRK). - *

    - * The address passed to this API must be either a public or random static address in big + * + *

    The address passed to this API must be either a public or random static address in big * endian byte order. It needs to be in the format of "01:02:03:AB:CD:EF". The device * address can be validated using {@link BluetoothAdapter#checkBluetoothAddress}. - *

    - * The IRK is used to resolve a static address from a private address. The IRK must be + * + *

    The IRK is used to resolve a static address from a private address. The IRK must be * provided in little endian byte order. * - * @param deviceAddress the remote device Bluetooth address for the filter + *

    When using this API, it is recommended to continue scanning until the device is + * bonded. + * + *

    The resulting {@link ScanResult} that matches this filter will contain an {@link + * BluetoothDevice} object for which the {@link BluetoothDevice#getAddress} method will + * return the device address passed as a parameter in this method. + * + *

    It is not recommended to use this API for discovering devices that are already bonded, + * but note if the device with this IRK is already bonded, calling {@link + * BluetoothDevice#getAddress} on the {@link ScanResult} using this filter will return the + * device address that was used to initiate bonding, and may not match the address passed + * into this method in that scenario. + * + * @param deviceAddress the remote device Bluetooth address for the filter in big endian + * order * @param addressType indication of the type of address * @param irk non-null little endian byte array representing the Identity Resolving Key - * * @throws IllegalArgumentException If the {@code deviceAddress} is invalid * @throws IllegalArgumentException if the {@code irk} is invalid length * @throws IllegalArgumentException If the {@code addressType} is an invalid length or is - * not PUBLIC or RANDOM STATIC + * not PUBLIC or RANDOM STATIC * @throws NullPointerException if {@code deviceAddress} or {@code irk} is null - * * @hide */ @NonNull @SystemApi - public Builder setDeviceAddress(@NonNull String deviceAddress, - @AddressType int addressType, - @NonNull byte[] irk) { + public Builder setDeviceAddress( + @NonNull String deviceAddress, @AddressType int addressType, @NonNull byte[] irk) { requireNonNull(irk); if (irk.length != LEN_IRK_OCTETS) { throw new IllegalArgumentException("'irk' is invalid length!"); @@ -809,23 +819,20 @@ public final class ScanFilter implements Parcelable { *

    Internal setter for the device address * * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the - * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link - * BluetoothAdapter#checkBluetoothAddress}. + * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link + * BluetoothAdapter#checkBluetoothAddress}. * @param addressType indication of the type of address * @param irk non-null little endian byte array representing the Identity Resolving Key; - * nullable internally. - * + * nullable internally. * @throws IllegalArgumentException if the {@code deviceAddress} is invalid * @throws IllegalArgumentException if the {@code addressType} is not PUBLIC or RANDOM - * STATIC when an IRK is present + * STATIC when an IRK is present * @throws NullPointerException if {@code deviceAddress} is null - * * @hide */ @NonNull - private Builder setDeviceAddressInternal(@NonNull String deviceAddress, - @AddressType int addressType, - @Nullable byte[] irk) { + private Builder setDeviceAddressInternal( + @NonNull String deviceAddress, @AddressType int addressType, @Nullable byte[] irk) { // Make sure our deviceAddress is valid! requireNonNull(deviceAddress); @@ -835,7 +842,7 @@ public final class ScanFilter implements Parcelable { // Verify type range if (addressType < BluetoothDevice.ADDRESS_TYPE_PUBLIC - || addressType > BluetoothDevice.ADDRESS_TYPE_RANDOM) { + || addressType > BluetoothDevice.ADDRESS_TYPE_RANDOM) { throw new IllegalArgumentException("'addressType' is invalid!"); } @@ -848,7 +855,7 @@ public final class ScanFilter implements Parcelable { if (!BluetoothAdapter.isAddressRandomStatic(deviceAddress)) { throw new IllegalArgumentException( "Invalid combination: IRK requires either a PUBLIC or " - + "RANDOM (STATIC) Address"); + + "RANDOM (STATIC) Address"); } } } @@ -862,9 +869,7 @@ public final class ScanFilter implements Parcelable { return this; } - /** - * Set filter on service uuid. - */ + /** Set filter on service uuid. */ public Builder setServiceUuid(ParcelUuid serviceUuid) { mServiceUuid = serviceUuid; mUuidMask = null; // clear uuid mask @@ -872,12 +877,12 @@ public final class ScanFilter implements Parcelable { } /** - * Set filter on partial service uuid. The {@code uuidMask} is the bit mask for the - * {@code serviceUuid}. Set any bit in the mask to 1 to indicate a match is needed for the - * bit in {@code serviceUuid}, and 0 to ignore that bit. + * Set filter on partial service uuid. The {@code uuidMask} is the bit mask for the {@code + * serviceUuid}. Set any bit in the mask to 1 to indicate a match is needed for the bit in + * {@code serviceUuid}, and 0 to ignore that bit. * * @throws IllegalArgumentException If {@code serviceUuid} is {@code null} but {@code - * uuidMask} is not {@code null}. + * uuidMask} is not {@code null}. */ public Builder setServiceUuid(ParcelUuid serviceUuid, ParcelUuid uuidMask) { if (mUuidMask != null && mServiceUuid == null) { @@ -888,10 +893,7 @@ public final class ScanFilter implements Parcelable { return this; } - - /** - * Set filter on service solicitation uuid. - */ + /** Set filter on service solicitation uuid. */ public @NonNull Builder setServiceSolicitationUuid( @Nullable ParcelUuid serviceSolicitationUuid) { mServiceSolicitationUuid = serviceSolicitationUuid; @@ -901,7 +903,6 @@ public final class ScanFilter implements Parcelable { return this; } - /** * Set filter on partial service Solicitation uuid. The {@code SolicitationUuidMask} is the * bit mask for the {@code serviceSolicitationUuid}. Set any bit in the mask to 1 to @@ -910,9 +911,8 @@ public final class ScanFilter implements Parcelable { * * @param serviceSolicitationUuid can only be null if solicitationUuidMask is null. * @param solicitationUuidMask can be null or a mask with no restriction. - * * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but - * {@code serviceSolicitationUuidMask} is not {@code null}. + * {@code solicitationUuidMask} is not {@code null}. */ public @NonNull Builder setServiceSolicitationUuid( @Nullable ParcelUuid serviceSolicitationUuid, @@ -944,15 +944,15 @@ public final class ScanFilter implements Parcelable { /** * Set partial filter on service data. For any bit in the mask, set it to 1 if it needs to * match the one in service data, otherwise set it to 0 to ignore that bit. - *

    - * The {@code serviceDataMask} must have the same length of the {@code serviceData}. + * + *

    The {@code serviceDataMask} must have the same length of the {@code serviceData}. * * @throws IllegalArgumentException If {@code serviceDataUuid} is null or {@code - * serviceDataMask} is {@code null} while {@code serviceData} is not or {@code - * serviceDataMask} and {@code serviceData} has different length. + * serviceDataMask} is {@code null} while {@code serviceData} is not or {@code + * serviceDataMask} and {@code serviceData} has different length. */ - public Builder setServiceData(ParcelUuid serviceDataUuid, - byte[] serviceData, byte[] serviceDataMask) { + public Builder setServiceData( + ParcelUuid serviceDataUuid, byte[] serviceData, byte[] serviceDataMask) { if (serviceDataUuid == null) { throw new IllegalArgumentException("serviceDataUuid is null"); } @@ -992,15 +992,16 @@ public final class ScanFilter implements Parcelable { /** * Set filter on partial manufacture data. For any bit in the mask, set it the 1 if it needs * to match the one in manufacturer data, otherwise set it to 0. - *

    - * The {@code manufacturerDataMask} must have the same length of {@code manufacturerData}. + * + *

    The {@code manufacturerDataMask} must have the same length of {@code + * manufacturerData}. * * @throws IllegalArgumentException If the {@code manufacturerId} is invalid, or {@code - * manufacturerData} is null while {@code manufacturerDataMask} is not, or {@code - * manufacturerData} and {@code manufacturerDataMask} have different length. + * manufacturerData} is null while {@code manufacturerDataMask} is not, or {@code + * manufacturerData} and {@code manufacturerDataMask} have different length. */ - public Builder setManufacturerData(int manufacturerId, byte[] manufacturerData, - byte[] manufacturerDataMask) { + public Builder setManufacturerData( + int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) { if (manufacturerData != null && manufacturerId < 0) { throw new IllegalArgumentException("invalid manufacture id"); } @@ -1025,12 +1026,12 @@ public final class ScanFilter implements Parcelable { /** * Set filter information for a transport block in Transport Discovery Service advertisement * - * Use {@link BluetoothAdapter#getOffloadedTransportDiscoveryDataScanSupported()} to check - * whether transport discovery data filtering is supported on this device before calling - * this method. + *

    Use {@link BluetoothAdapter#getOffloadedTransportDiscoveryDataScanSupported()} to + * check whether transport discovery data filtering is supported on this device before + * calling this method. * * @param transportBlockFilter filter data for a transport block in Transport Discovery - * Service advertisement + * Service advertisement * @throws IllegalArgumentException if Transport Discovery Data filter is not supported. * @return this builder * @hide @@ -1054,21 +1055,22 @@ public final class ScanFilter implements Parcelable { } /** - * Set filter on advertising data with specific advertising data type. - * For any bit in the mask, set it the 1 if it needs to match the one in - * advertising data, otherwise set it to 0. - *

    - * The values of {@code advertisingDataType} are assigned by Bluetooth SIG. For more + * Set filter on advertising data with specific advertising data type. For any bit in the + * mask, set it the 1 if it needs to match the one in advertising data, otherwise set it to + * 0. + * + *

    The values of {@code advertisingDataType} are assigned by Bluetooth SIG. For more * details refer to Bluetooth Generic Access Profile. - * (https://www.bluetooth.com/specifications/assigned-numbers/) - * The {@code advertisingDataMask} must have the same length of {@code advertisingData}. + * (https://www.bluetooth.com/specifications/assigned-numbers/) The {@code + * advertisingDataMask} must have the same length of {@code advertisingData}. * * @throws IllegalArgumentException If the {@code advertisingDataType} is invalid, {@code - * advertisingData} or {@code advertisingDataMask} is null or {@code - * advertisingData} and {@code advertisingDataMask} have different length. + * advertisingData} or {@code advertisingDataMask} is null or {@code advertisingData} + * and {@code advertisingDataMask} have different length. */ public @NonNull Builder setAdvertisingDataTypeWithData( - @AdvertisingDataType int advertisingDataType, @NonNull byte[] advertisingData, + @AdvertisingDataType int advertisingDataType, + @NonNull byte[] advertisingData, @NonNull byte[] advertisingDataMask) { if (advertisingDataType < 0) { throw new IllegalArgumentException("invalid advertising data type"); @@ -1091,13 +1093,13 @@ public final class ScanFilter implements Parcelable { return this; } - /** * Set filter on advertising data with specific advertising data type. - *

    - * The values of {@code advertisingDataType} are assigned by Bluetooth SIG. For more + * + *

    The values of {@code advertisingDataType} are assigned by Bluetooth SIG. For more * details refer to Bluetooth Generic Access Profile. * (https://www.bluetooth.com/specifications/assigned-numbers/) + * * @throws IllegalArgumentException If the {@code advertisingDataType} is invalid */ public @NonNull Builder setAdvertisingDataType( @@ -1115,11 +1117,25 @@ public final class ScanFilter implements Parcelable { * @throws IllegalArgumentException If the filter cannot be built. */ public ScanFilter build() { - return new ScanFilter(mDeviceName, mDeviceAddress, mServiceUuid, mUuidMask, - mServiceSolicitationUuid, mServiceSolicitationUuidMask, mServiceDataUuid, - mServiceData, mServiceDataMask, mManufacturerId, mManufacturerData, - mManufacturerDataMask, mAddressType, mIrk, mAdvertisingDataType, - mAdvertisingData, mAdvertisingDataMask, mTransportBlockFilter); + return new ScanFilter( + mDeviceName, + mDeviceAddress, + mServiceUuid, + mUuidMask, + mServiceSolicitationUuid, + mServiceSolicitationUuidMask, + mServiceDataUuid, + mServiceData, + mServiceDataMask, + mManufacturerId, + mManufacturerData, + mManufacturerDataMask, + mAddressType, + mIrk, + mAdvertisingDataType, + mAdvertisingData, + mAdvertisingDataMask, + mTransportBlockFilter); } } } diff --git a/framework/java/android/bluetooth/le/ScanRecord.java b/framework/java/android/bluetooth/le/ScanRecord.java index 8d3c16d4952c56e471352cfc88b0a51388e475e7..637fea5d80776d418a67e146aa989e665b820b4c 100644 --- a/framework/java/android/bluetooth/le/ScanRecord.java +++ b/framework/java/android/bluetooth/le/ScanRecord.java @@ -37,278 +37,298 @@ import java.util.List; import java.util.Map; import java.util.function.Predicate; -/** - * Represents a scan record from Bluetooth LE scan. - */ +/** Represents a scan record from Bluetooth LE scan. */ @SuppressLint("AndroidFrameworkBluetoothPermission") public final class ScanRecord { private static final String TAG = "ScanRecord"; /** @hide */ - @IntDef(prefix = "DATA_TYPE_", value = { - DATA_TYPE_FLAGS, - DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL, - DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE, - DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL, - DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE, - DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL, - DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE, - DATA_TYPE_LOCAL_NAME_SHORT, - DATA_TYPE_LOCAL_NAME_COMPLETE, - DATA_TYPE_TX_POWER_LEVEL, - DATA_TYPE_CLASS_OF_DEVICE, - DATA_TYPE_SIMPLE_PAIRING_HASH_C, - DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R, - DATA_TYPE_DEVICE_ID, - DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS, - DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE, - DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT, - DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT, - DATA_TYPE_SERVICE_DATA_16_BIT, - DATA_TYPE_PUBLIC_TARGET_ADDRESS, - DATA_TYPE_RANDOM_TARGET_ADDRESS, - DATA_TYPE_APPEARANCE, - DATA_TYPE_ADVERTISING_INTERVAL, - DATA_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS, - DATA_TYPE_LE_ROLE, - DATA_TYPE_SIMPLE_PAIRING_HASH_C_256, - DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R_256, - DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT, - DATA_TYPE_SERVICE_DATA_32_BIT, - DATA_TYPE_SERVICE_DATA_128_BIT, - DATA_TYPE_LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE, - DATA_TYPE_LE_SECURE_CONNECTIONS_RANDOM_VALUE, - DATA_TYPE_URI, - DATA_TYPE_INDOOR_POSITIONING, - DATA_TYPE_TRANSPORT_DISCOVERY_DATA, - DATA_TYPE_LE_SUPPORTED_FEATURES, - DATA_TYPE_CHANNEL_MAP_UPDATE_INDICATION, - DATA_TYPE_PB_ADV, - DATA_TYPE_MESH_MESSAGE, - DATA_TYPE_MESH_BEACON, - DATA_TYPE_BIG_INFO, - DATA_TYPE_BROADCAST_CODE, - DATA_TYPE_RESOLVABLE_SET_IDENTIFIER, - DATA_TYPE_ADVERTISING_INTERVAL_LONG, - DATA_TYPE_3D_INFORMATION_DATA, - DATA_TYPE_MANUFACTURER_SPECIFIC_DATA, - }) + @IntDef( + prefix = "DATA_TYPE_", + value = { + DATA_TYPE_FLAGS, + DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL, + DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE, + DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL, + DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE, + DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL, + DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE, + DATA_TYPE_LOCAL_NAME_SHORT, + DATA_TYPE_LOCAL_NAME_COMPLETE, + DATA_TYPE_TX_POWER_LEVEL, + DATA_TYPE_CLASS_OF_DEVICE, + DATA_TYPE_SIMPLE_PAIRING_HASH_C, + DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R, + DATA_TYPE_DEVICE_ID, + DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS, + DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE, + DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT, + DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT, + DATA_TYPE_SERVICE_DATA_16_BIT, + DATA_TYPE_PUBLIC_TARGET_ADDRESS, + DATA_TYPE_RANDOM_TARGET_ADDRESS, + DATA_TYPE_APPEARANCE, + DATA_TYPE_ADVERTISING_INTERVAL, + DATA_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS, + DATA_TYPE_LE_ROLE, + DATA_TYPE_SIMPLE_PAIRING_HASH_C_256, + DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R_256, + DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT, + DATA_TYPE_SERVICE_DATA_32_BIT, + DATA_TYPE_SERVICE_DATA_128_BIT, + DATA_TYPE_LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE, + DATA_TYPE_LE_SECURE_CONNECTIONS_RANDOM_VALUE, + DATA_TYPE_URI, + DATA_TYPE_INDOOR_POSITIONING, + DATA_TYPE_TRANSPORT_DISCOVERY_DATA, + DATA_TYPE_LE_SUPPORTED_FEATURES, + DATA_TYPE_CHANNEL_MAP_UPDATE_INDICATION, + DATA_TYPE_PB_ADV, + DATA_TYPE_MESH_MESSAGE, + DATA_TYPE_MESH_BEACON, + DATA_TYPE_BIG_INFO, + DATA_TYPE_BROADCAST_CODE, + DATA_TYPE_RESOLVABLE_SET_IDENTIFIER, + DATA_TYPE_ADVERTISING_INTERVAL_LONG, + DATA_TYPE_3D_INFORMATION_DATA, + DATA_TYPE_MANUFACTURER_SPECIFIC_DATA, + }) @Retention(RetentionPolicy.SOURCE) public @interface AdvertisingDataType {} - /** - * Data type is not set for the filter. Will not filter advertising data type. - */ + /** Data type is not set for the filter. Will not filter advertising data type. */ public static final int DATA_TYPE_NONE = -1; - /** - * Data type is Flags, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is Flags, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_FLAGS = 0x01; + /** * Data type is Incomplete List of 16-bit Service Class UUIDs, see the Bluetooth Generic Access * Profile for the details. */ public static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02; + /** * Data type is Complete List of 16-bit Service Class UUIDs, see the Bluetooth Generic Access * Profile for more details. */ public static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03; + /** * Data type is Incomplete List of 32-bit Service Class UUIDs, see the Bluetooth Generic Access * Profile for the details. */ public static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04; + /** * Data type is Complete List of 32-bit Service Class UUIDs, see the Bluetooth Generic Access * Profile for more details. */ public static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05; + /** * Data type is Incomplete List of 128-bit Service Class UUIDs, see the Bluetooth Generic Access * Profile for the details. */ public static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06; + /** * Data type is Complete List of 128-bit Service Class UUIDs, see the Bluetooth Generic Access * Profile for more details. */ public static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07; + /** * Data type is Shortened Local Name, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08; + /** * Data type is Complete Local Name, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09; - /** - * Data type is Tx Power Level, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is Tx Power Level, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A; - /** - * Data type is Class of Device, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is Class of Device, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_CLASS_OF_DEVICE = 0x0D; + /** * Data type is Simple Pairing Hash C, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_SIMPLE_PAIRING_HASH_C = 0x0E; + /** * Data type is Simple Pairing Randomizer R, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R = 0x0F; - /** - * Data type is Device ID, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is Device ID, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_DEVICE_ID = 0x10; + /** * Data type is Security Manager Out of Band Flags, see the Bluetooth Generic Access Profile for * more details. */ public static final int DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS = 0x11; + /** * Data type is Slave Connection Interval Range, see the Bluetooth Generic Access Profile for * more details. */ public static final int DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE = 0x12; + /** * Data type is List of 16-bit Service Solicitation UUIDs, see the Bluetooth Generic Access * Profile for more details. */ public static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT = 0x14; + /** * Data type is List of 128-bit Service Solicitation UUIDs, see the Bluetooth Generic Access * Profile for more details. */ public static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15; + /** * Data type is Service Data - 16-bit UUID, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16; + /** * Data type is Public Target Address, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_PUBLIC_TARGET_ADDRESS = 0x17; + /** * Data type is Random Target Address, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_RANDOM_TARGET_ADDRESS = 0x18; - /** - * Data type is Appearance, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is Appearance, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_APPEARANCE = 0x19; + /** * Data type is Advertising Interval, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_ADVERTISING_INTERVAL = 0x1A; + /** * Data type is LE Bluetooth Device Address, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS = 0x1B; - /** - * Data type is LE Role, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is LE Role, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_LE_ROLE = 0x1C; + /** * Data type is Simple Pairing Hash C-256, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_SIMPLE_PAIRING_HASH_C_256 = 0x1D; + /** * Data type is Simple Pairing Randomizer R-256, see the Bluetooth Generic Access Profile for * more details. */ public static final int DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R_256 = 0x1E; + /** * Data type is List of 32-bit Service Solicitation UUIDs, see the Bluetooth Generic Access * Profile for more details. */ public static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT = 0x1F; + /** * Data type is Service Data - 32-bit UUID, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20; + /** * Data type is Service Data - 128-bit UUID, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21; + /** * Data type is LE Secure Connections Confirmation Value, see the Bluetooth Generic Access * Profile for more details. */ public static final int DATA_TYPE_LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE = 0x22; + /** * Data type is LE Secure Connections Random Value, see the Bluetooth Generic Access Profile for * more details. */ public static final int DATA_TYPE_LE_SECURE_CONNECTIONS_RANDOM_VALUE = 0x23; - /** - * Data type is URI, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is URI, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_URI = 0x24; + /** * Data type is Indoor Positioning, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_INDOOR_POSITIONING = 0x25; + /** * Data type is Transport Discovery Data, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_TRANSPORT_DISCOVERY_DATA = 0x26; + /** * Data type is LE Supported Features, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_LE_SUPPORTED_FEATURES = 0x27; + /** * Data type is Channel Map Update Indication, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_CHANNEL_MAP_UPDATE_INDICATION = 0x28; - /** - * Data type is PB-ADV, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is PB-ADV, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_PB_ADV = 0x29; - /** - * Data type is Mesh Message, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is Mesh Message, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_MESH_MESSAGE = 0x2A; - /** - * Data type is Mesh Beacon, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is Mesh Beacon, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_MESH_BEACON = 0x2B; - /** - * Data type is BIGInfo, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is BIGInfo, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_BIG_INFO = 0x2C; - /** - * Data type is Broadcast_Code, see the Bluetooth Generic Access Profile for more details. - */ + + /** Data type is Broadcast_Code, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_BROADCAST_CODE = 0x2D; + /** * Data type is Resolvable Set Identifier, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_RESOLVABLE_SET_IDENTIFIER = 0x2E; + /** * Data type is Advertising Interval - long, see the Bluetooth Generic Access Profile for more * details. */ public static final int DATA_TYPE_ADVERTISING_INTERVAL_LONG = 0x2F; + /** * Data type is 3D Information Data, see the Bluetooth Generic Access Profile for more details. */ public static final int DATA_TYPE_3D_INFORMATION_DATA = 0x3D; + /** * Data type is Manufacturer Specific Data, see the Bluetooth Generic Access Profile for more * details. @@ -318,10 +338,8 @@ public final class ScanRecord { // Flags of the advertising data. private final int mAdvertiseFlags; - @Nullable - private final List mServiceUuids; - @Nullable - private final List mServiceSolicitationUuids; + @Nullable private final List mServiceUuids; + @Nullable private final List mServiceSolicitationUuids; private final SparseArray mManufacturerSpecificData; @@ -336,7 +354,7 @@ public final class ScanRecord { // Raw bytes of scan record. private final byte[] mBytes; - private final HashMap mAdvertisingDataMap; + private final Map mAdvertisingDataMap; // Transport Discovery data. private final TransportDiscoveryData mTransportDiscoveryData; @@ -375,8 +393,8 @@ public final class ScanRecord { } /** - * Returns the manufacturer specific data associated with the manufacturer id. Returns - * {@code null} if the {@code manufacturerId} is not found. + * Returns the manufacturer specific data associated with the manufacturer id. Returns {@code + * null} if the {@code manufacturerId} is not found. */ @Nullable public byte[] getManufacturerSpecificData(int manufacturerId) { @@ -386,16 +404,14 @@ public final class ScanRecord { return mManufacturerSpecificData.get(manufacturerId); } - /** - * Returns a map of service UUID and its corresponding service data. - */ + /** Returns a map of service UUID and its corresponding service data. */ public Map getServiceData() { return mServiceData; } /** - * Returns the service data byte array associated with the {@code serviceUuid}. Returns - * {@code null} if the {@code serviceDataUuid} is not found. + * Returns the service data byte array associated with the {@code serviceUuid}. Returns {@code + * null} if the {@code serviceDataUuid} is not found. */ @Nullable public byte[] getServiceData(ParcelUuid serviceDataUuid) { @@ -409,25 +425,22 @@ public final class ScanRecord { * Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE} * if the field is not set. This value can be used to calculate the path loss of a received * packet using the following equation: - *

    - * pathloss = txPowerLevel - rssi + * + *

    pathloss = txPowerLevel - rssi */ public int getTxPowerLevel() { return mTxPowerLevel; } - /** - * Returns the local name of the BLE device. This is a UTF-8 encoded string. - */ + /** Returns the local name of the BLE device. This is a UTF-8 encoded string. */ @Nullable public String getDeviceName() { return mDeviceName; } - /** - * Returns a map of advertising data type and its corresponding advertising data. - * The values of advertising data type are defined in the Bluetooth Generic Access Profile + * Returns a map of advertising data type and its corresponding advertising data. The values of + * advertising data type are defined in the Bluetooth Generic Access Profile * (https://www.bluetooth.com/specifications/assigned-numbers/) */ public @NonNull Map getAdvertisingDataMap() { @@ -445,16 +458,13 @@ public final class ScanRecord { return mTransportDiscoveryData; } - /** - * Returns raw bytes of scan record. - */ + /** Returns raw bytes of scan record. */ public byte[] getBytes() { return mBytes; } /** - * Test if any fields contained inside this scan record are matched by the - * given matcher. + * Test if any fields contained inside this scan record are matched by the given matcher. * * @hide */ @@ -473,13 +483,17 @@ public final class ScanRecord { return false; } - private ScanRecord(List serviceUuids, + private ScanRecord( + List serviceUuids, List serviceSolicitationUuids, SparseArray manufacturerData, Map serviceData, - int advertiseFlags, int txPowerLevel, - String localName, HashMap advertisingDataMap, - TransportDiscoveryData transportDiscoveryData, byte[] bytes) { + int advertiseFlags, + int txPowerLevel, + String localName, + Map advertisingDataMap, + TransportDiscoveryData transportDiscoveryData, + byte[] bytes) { mServiceSolicitationUuids = serviceSolicitationUuids; mServiceUuids = serviceUuids; mManufacturerSpecificData = manufacturerData; @@ -494,10 +508,10 @@ public final class ScanRecord { /** * Parse scan record bytes to {@link ScanRecord}. - *

    - * The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18. - *

    - * All numerical multi-byte entities and values shall use little-endian byte + * + *

    The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18. + * + *

    All numerical multi-byte entities and values shall use little-endian byte * order. * * @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response. @@ -541,35 +555,58 @@ public final class ScanRecord { break; case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL: case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE: - parseServiceUuid(scanRecord, currentPos, - dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceUuids); + parseServiceUuid( + scanRecord, + currentPos, + dataLength, + BluetoothUuid.UUID_BYTES_16_BIT, + serviceUuids); break; case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL: case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE: - parseServiceUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_32_BIT, serviceUuids); + parseServiceUuid( + scanRecord, + currentPos, + dataLength, + BluetoothUuid.UUID_BYTES_32_BIT, + serviceUuids); break; case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL: case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE: - parseServiceUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids); + parseServiceUuid( + scanRecord, + currentPos, + dataLength, + BluetoothUuid.UUID_BYTES_128_BIT, + serviceUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT: - parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_16_BIT, serviceSolicitationUuids); + parseServiceSolicitationUuid( + scanRecord, + currentPos, + dataLength, + BluetoothUuid.UUID_BYTES_16_BIT, + serviceSolicitationUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT: - parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_32_BIT, serviceSolicitationUuids); + parseServiceSolicitationUuid( + scanRecord, + currentPos, + dataLength, + BluetoothUuid.UUID_BYTES_32_BIT, + serviceSolicitationUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT: - parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, - BluetoothUuid.UUID_BYTES_128_BIT, serviceSolicitationUuids); + parseServiceSolicitationUuid( + scanRecord, + currentPos, + dataLength, + BluetoothUuid.UUID_BYTES_128_BIT, + serviceSolicitationUuids); break; case DATA_TYPE_LOCAL_NAME_SHORT: case DATA_TYPE_LOCAL_NAME_COMPLETE: - localName = new String( - extractBytes(scanRecord, currentPos, dataLength)); + localName = new String(extractBytes(scanRecord, currentPos, dataLength)); break; case DATA_TYPE_TX_POWER_LEVEL: txPowerLevel = scanRecord[currentPos]; @@ -584,21 +621,25 @@ public final class ScanRecord { serviceUuidLength = BluetoothUuid.UUID_BYTES_128_BIT; } - byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos, - serviceUuidLength); - ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom( - serviceDataUuidBytes); - byte[] serviceDataArray = extractBytes(scanRecord, - currentPos + serviceUuidLength, dataLength - serviceUuidLength); + byte[] serviceDataUuidBytes = + extractBytes(scanRecord, currentPos, serviceUuidLength); + ParcelUuid serviceDataUuid = + BluetoothUuid.parseUuidFrom(serviceDataUuidBytes); + byte[] serviceDataArray = + extractBytes( + scanRecord, + currentPos + serviceUuidLength, + dataLength - serviceUuidLength); serviceData.put(serviceDataUuid, serviceDataArray); break; case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA: // The first two bytes of the manufacturer specific data are // manufacturer ids in little endian. - int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) - + (scanRecord[currentPos] & 0xFF); - byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2, - dataLength - 2); + int manufacturerId = + ((scanRecord[currentPos + 1] & 0xFF) << 8) + + (scanRecord[currentPos] & 0xFF); + byte[] manufacturerDataBytes = + extractBytes(scanRecord, currentPos + 2, dataLength - 2); manufacturerData.put(manufacturerId, manufacturerDataBytes); break; case DATA_TYPE_TRANSPORT_DISCOVERY_DATA: @@ -619,35 +660,65 @@ public final class ScanRecord { if (serviceUuids.isEmpty()) { serviceUuids = null; } - return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData, - serviceData, advertiseFlag, txPowerLevel, localName, advertisingDataMap, - transportDiscoveryData, scanRecord); + return new ScanRecord( + serviceUuids, + serviceSolicitationUuids, + manufacturerData, + serviceData, + advertiseFlag, + txPowerLevel, + localName, + advertisingDataMap, + transportDiscoveryData, + scanRecord); } catch (Exception e) { Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord)); // As the record is invalid, ignore all the parsed results for this packet // and return an empty record with raw scanRecord bytes in results - return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, - advertisingDataMap, null, scanRecord); + return new ScanRecord( + null, + null, + null, + null, + -1, + Integer.MIN_VALUE, + null, + advertisingDataMap, + null, + scanRecord); } } @Override public String toString() { - return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids - + ", mServiceSolicitationUuids=" + mServiceSolicitationUuids + return "ScanRecord [mAdvertiseFlags=" + + mAdvertiseFlags + + ", mServiceUuids=" + + mServiceUuids + + ", mServiceSolicitationUuids=" + + mServiceSolicitationUuids + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(mManufacturerSpecificData) - + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData) - + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName - + ", mTransportDiscoveryData=" + mTransportDiscoveryData + "]"; + + ", mServiceData=" + + BluetoothLeUtils.toString(mServiceData) + + ", mTxPowerLevel=" + + mTxPowerLevel + + ", mDeviceName=" + + mDeviceName + + ", mTransportDiscoveryData=" + + mTransportDiscoveryData + + "]"; } // Parse service UUIDs. - private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength, - int uuidLength, List serviceUuids) { + private static int parseServiceUuid( + byte[] scanRecord, + int currentPos, + int dataLength, + int uuidLength, + List serviceUuids) { while (dataLength > 0) { - byte[] uuidBytes = extractBytes(scanRecord, currentPos, - uuidLength); + byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength); serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes)); dataLength -= uuidLength; currentPos += uuidLength; @@ -655,11 +726,13 @@ public final class ScanRecord { return currentPos; } - /** - * Parse service Solicitation UUIDs. - */ - private static int parseServiceSolicitationUuid(byte[] scanRecord, int currentPos, - int dataLength, int uuidLength, List serviceSolicitationUuids) { + /** Parse service Solicitation UUIDs. */ + private static int parseServiceSolicitationUuid( + byte[] scanRecord, + int currentPos, + int dataLength, + int uuidLength, + List serviceSolicitationUuids) { while (dataLength > 0) { byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength); serviceSolicitationUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes)); diff --git a/framework/java/android/bluetooth/le/ScanResult.java b/framework/java/android/bluetooth/le/ScanResult.java index f437d867ea3736b3b581bc3f276ad5fe57f682dd..690dc79f319153401e81750a0e04c36a194f1a9a 100644 --- a/framework/java/android/bluetooth/le/ScanResult.java +++ b/framework/java/android/bluetooth/le/ScanResult.java @@ -26,60 +26,44 @@ import android.os.Parcelable; import java.util.Objects; -/** - * ScanResult for Bluetooth LE scan. - */ +/** ScanResult for Bluetooth LE scan. */ public final class ScanResult implements Parcelable, Attributable { /** - * For chained advertisements, inidcates tha the data contained in this - * scan result is complete. + * For chained advertisements, indicates that the data contained in this scan result is + * complete. */ public static final int DATA_COMPLETE = 0x00; /** - * For chained advertisements, indicates that the controller was - * unable to receive all chained packets and the scan result contains - * incomplete truncated data. + * For chained advertisements, indicates that the controller was unable to receive all chained + * packets and the scan result contains incomplete truncated data. */ public static final int DATA_TRUNCATED = 0x02; - /** - * Indicates that the secondary physical layer was not used. - */ + /** Indicates that the secondary physical layer was not used. */ public static final int PHY_UNUSED = 0x00; - /** - * Advertising Set ID is not present in the packet. - */ + /** Advertising Set ID is not present in the packet. */ public static final int SID_NOT_PRESENT = 0xFF; - /** - * TX power is not present in the packet. - */ + /** TX power is not present in the packet. */ public static final int TX_POWER_NOT_PRESENT = 0x7F; - /** - * Periodic advertising interval is not present in the packet. - */ + /** Periodic advertising interval is not present in the packet. */ public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0x00; - /** - * Mask for checking whether event type represents legacy advertisement. - */ + /** Mask for checking whether event type represents legacy advertisement. */ private static final int ET_LEGACY_MASK = 0x10; - /** - * Mask for checking whether event type represents connectable advertisement. - */ + /** Mask for checking whether event type represents connectable advertisement. */ private static final int ET_CONNECTABLE_MASK = 0x01; // Remote Bluetooth device. private BluetoothDevice mDevice; // Scan record, including advertising data and scan response data. - @Nullable - private ScanRecord mScanRecord; + @Nullable private ScanRecord mScanRecord; // Received signal strength. private int mRssi; @@ -102,11 +86,11 @@ public final class ScanResult implements Parcelable, Attributable { * @param rssi Received signal strength. * @param timestampNanos Timestamp at which the scan result was observed. * @deprecated use {@link #ScanResult(BluetoothDevice, int, int, int, int, int, int, int, - * ScanRecord, long)} + * ScanRecord, long)} */ @Deprecated - public ScanResult(BluetoothDevice device, ScanRecord scanRecord, int rssi, - long timestampNanos) { + public ScanResult( + BluetoothDevice device, ScanRecord scanRecord, int rssi, long timestampNanos) { mDevice = device; mScanRecord = scanRecord; mRssi = rssi; @@ -133,9 +117,17 @@ public final class ScanResult implements Parcelable, Attributable { * @param scanRecord Scan record including both advertising data and scan response data. * @param timestampNanos Timestamp at which the scan result was observed. */ - public ScanResult(BluetoothDevice device, int eventType, int primaryPhy, int secondaryPhy, - int advertisingSid, int txPower, int rssi, int periodicAdvertisingInterval, - ScanRecord scanRecord, long timestampNanos) { + public ScanResult( + BluetoothDevice device, + int eventType, + int primaryPhy, + int secondaryPhy, + int advertisingSid, + int txPower, + int rssi, + int periodicAdvertisingInterval, + ScanRecord scanRecord, + long timestampNanos) { mDevice = device; mEventType = eventType; mPrimaryPhy = primaryPhy; @@ -198,60 +190,53 @@ public final class ScanResult implements Parcelable, Attributable { return 0; } - /** {@hide} */ + /** @hide */ public void setAttributionSource(@NonNull AttributionSource attributionSource) { Attributable.setAttributionSource(mDevice, attributionSource); } /** - * Returns the remote Bluetooth device identified by the Bluetooth device address. + * Returns the remote Bluetooth device identified by the Bluetooth device address. If the device + * is bonded, calling {@link BluetoothDevice#getAddress} on the object returned by this method + * will return the address that was originally bonded with (either identity address or random + * address). */ public BluetoothDevice getDevice() { return mDevice; } - /** - * Returns the scan record, which is a combination of advertisement and scan response. - */ + /** Returns the scan record, which is a combination of advertisement and scan response. */ @Nullable public ScanRecord getScanRecord() { return mScanRecord; } - /** - * Returns the received signal strength in dBm. The valid range is [-127, 126]. - */ + /** Returns the received signal strength in dBm. The valid range is [-127, 126]. */ public int getRssi() { return mRssi; } - /** - * Returns timestamp since boot when the scan record was observed. - */ + /** Returns timestamp since boot when the scan record was observed. */ public long getTimestampNanos() { return mTimestampNanos; } /** - * Returns true if this object represents legacy scan result. - * Legacy scan results do not contain advanced advertising information - * as specified in the Bluetooth Core Specification v5. + * Returns true if this object represents legacy scan result. Legacy scan results do not contain + * advanced advertising information as specified in the Bluetooth Core Specification v5. */ public boolean isLegacy() { return (mEventType & ET_LEGACY_MASK) != 0; } - /** - * Returns true if this object represents connectable scan result. - */ + /** Returns true if this object represents connectable scan result. */ public boolean isConnectable() { return (mEventType & ET_CONNECTABLE_MASK) != 0; } /** - * Returns the data status. - * Can be one of {@link ScanResult#DATA_COMPLETE} or - * {@link ScanResult#DATA_TRUNCATED}. + * Returns the data status. Can be one of {@link ScanResult#DATA_COMPLETE} or {@link + * ScanResult#DATA_TRUNCATED}. */ public int getDataStatus() { // return bit 5 and 6 @@ -259,50 +244,43 @@ public final class ScanResult implements Parcelable, Attributable { } /** - * Returns the primary Physical Layer - * on which this advertisment was received. - * Can be one of {@link BluetoothDevice#PHY_LE_1M} or - * {@link BluetoothDevice#PHY_LE_CODED}. + * Returns the primary Physical Layer on which this advertisement was received. Can be one of + * {@link BluetoothDevice#PHY_LE_1M} or {@link BluetoothDevice#PHY_LE_CODED}. */ public int getPrimaryPhy() { return mPrimaryPhy; } /** - * Returns the secondary Physical Layer - * on which this advertisment was received. - * Can be one of {@link BluetoothDevice#PHY_LE_1M}, - * {@link BluetoothDevice#PHY_LE_2M}, {@link BluetoothDevice#PHY_LE_CODED} - * or {@link ScanResult#PHY_UNUSED} - if the advertisement - * was not received on a secondary physical channel. + * Returns the secondary Physical Layer on which this advertisement was received. Can be one of + * {@link BluetoothDevice#PHY_LE_1M}, {@link BluetoothDevice#PHY_LE_2M}, {@link + * BluetoothDevice#PHY_LE_CODED} or {@link ScanResult#PHY_UNUSED} - if the advertisement was not + * received on a secondary physical channel. */ public int getSecondaryPhy() { return mSecondaryPhy; } /** - * Returns the advertising set id. - * May return {@link ScanResult#SID_NOT_PRESENT} if - * no set id was is present. + * Returns the advertising set id. May return {@link ScanResult#SID_NOT_PRESENT} if no set id + * was is present. */ public int getAdvertisingSid() { return mAdvertisingSid; } /** - * Returns the transmit power in dBm. - * Valid range is [-127, 126]. A value of {@link ScanResult#TX_POWER_NOT_PRESENT} - * indicates that the TX power is not present. + * Returns the transmit power in dBm. Valid range is [-127, 126]. A value of {@link + * ScanResult#TX_POWER_NOT_PRESENT} indicates that the TX power is not present. */ public int getTxPower() { return mTxPower; } /** - * Returns the periodic advertising interval in units of 1.25ms. - * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of - * {@link ScanResult#PERIODIC_INTERVAL_NOT_PRESENT} means periodic - * advertising interval is not present. + * Returns the periodic advertising interval in units of 1.25ms. Valid range is 6 (7.5ms) to + * 65536 (81918.75ms). A value of {@link ScanResult#PERIODIC_INTERVAL_NOT_PRESENT} means + * periodic advertising interval is not present. */ public int getPeriodicAdvertisingInterval() { return mPeriodicAdvertisingInterval; @@ -310,9 +288,16 @@ public final class ScanResult implements Parcelable, Attributable { @Override public int hashCode() { - return Objects.hash(mDevice, mRssi, mScanRecord, mTimestampNanos, - mEventType, mPrimaryPhy, mSecondaryPhy, - mAdvertisingSid, mTxPower, + return Objects.hash( + mDevice, + mRssi, + mScanRecord, + mTimestampNanos, + mEventType, + mPrimaryPhy, + mSecondaryPhy, + mAdvertisingSid, + mTxPower, mPeriodicAdvertisingInterval); } @@ -325,7 +310,8 @@ public final class ScanResult implements Parcelable, Attributable { return false; } ScanResult other = (ScanResult) obj; - return Objects.equals(mDevice, other.mDevice) && (mRssi == other.mRssi) + return Objects.equals(mDevice, other.mDevice) + && (mRssi == other.mRssi) && Objects.equals(mScanRecord, other.mScanRecord) && (mTimestampNanos == other.mTimestampNanos) && mEventType == other.mEventType @@ -338,24 +324,40 @@ public final class ScanResult implements Parcelable, Attributable { @Override public String toString() { - return "ScanResult{" + "device=" + mDevice + ", scanRecord=" - + Objects.toString(mScanRecord) + ", rssi=" + mRssi - + ", timestampNanos=" + mTimestampNanos + ", eventType=" + mEventType - + ", primaryPhy=" + mPrimaryPhy + ", secondaryPhy=" + mSecondaryPhy - + ", advertisingSid=" + mAdvertisingSid + ", txPower=" + mTxPower - + ", periodicAdvertisingInterval=" + mPeriodicAdvertisingInterval + '}'; + return "ScanResult{" + + "device=" + + mDevice + + ", scanRecord=" + + Objects.toString(mScanRecord) + + ", rssi=" + + mRssi + + ", timestampNanos=" + + mTimestampNanos + + ", eventType=" + + mEventType + + ", primaryPhy=" + + mPrimaryPhy + + ", secondaryPhy=" + + mSecondaryPhy + + ", advertisingSid=" + + mAdvertisingSid + + ", txPower=" + + mTxPower + + ", periodicAdvertisingInterval=" + + mPeriodicAdvertisingInterval + + '}'; } - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Creator() { - @Override - public ScanResult createFromParcel(Parcel source) { - return new ScanResult(source); - } - - @Override - public ScanResult[] newArray(int size) { - return new ScanResult[size]; - } - }; - + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = + new Creator() { + @Override + public ScanResult createFromParcel(Parcel source) { + return new ScanResult(source); + } + + @Override + public ScanResult[] newArray(int size) { + return new ScanResult[size]; + } + }; } diff --git a/framework/java/android/bluetooth/le/ScanSettings.java b/framework/java/android/bluetooth/le/ScanSettings.java index dd9d596c2634c07fe2df67641b27939a9f726fe2..ac0179b7ec5c804687380aadf8bd4a8e958ea824 100644 --- a/framework/java/android/bluetooth/le/ScanSettings.java +++ b/framework/java/android/bluetooth/le/ScanSettings.java @@ -58,21 +58,20 @@ public final class ScanSettings implements Parcelable { * * @hide */ - @SystemApi - public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; + @SystemApi public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; /** - * Default Bluetooth LE scan mode when the screen is off. - * This mode has the low duty cycle and long scan interval which results in the lowest - * power consumption among all modes. It is for the framework internal use only. + * Default Bluetooth LE scan mode when the screen is off. This mode has the low duty cycle and + * long scan interval which results in the lowest power consumption among all modes. It is for + * the framework internal use only. * * @hide */ public static final int SCAN_MODE_SCREEN_OFF = 4; /** - * Balanced Bluetooth LE scan mode for foreground service when the screen is off. - * It is for the framework internal use only. + * Balanced Bluetooth LE scan mode for foreground service when the screen is off. It is for the + * framework internal use only. * * @hide */ @@ -97,76 +96,69 @@ public final class ScanSettings implements Parcelable { public static final int CALLBACK_TYPE_MATCH_LOST = 4; /** - * A result callback for every Bluetooth advertisement found that matches the filter criteria - * is only triggered when screen is turned on. While the screen is turned off, the - * advertisements are batched and the batched result callbacks are triggered every report delay. - * When the batch scan with this callback type is activated, the batched result callbacks are - * also triggered while turning on screen or disabling the scan. This callback type must be used - * with a report delay of {@link ScanSettings#AUTO_BATCH_MIN_REPORT_DELAY_MILLIS} or greater. + * A result callback for every Bluetooth advertisement found that matches the filter criteria is + * only triggered when screen is turned on. While the screen is turned off, the advertisements + * are batched and the batched result callbacks are triggered every report delay. When the batch + * scan with this callback type is activated, the batched result callbacks are also triggered + * while turning on screen or disabling the scan. This callback type must be used with a report + * delay of {@link ScanSettings#AUTO_BATCH_MIN_REPORT_DELAY_MILLIS} or greater. */ public static final int CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH = 8; - /** - * Minimum report delay for {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH}. - */ + /** Minimum report delay for {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH}. */ public static final long AUTO_BATCH_MIN_REPORT_DELAY_MILLIS = 1000 * 60 * 10; /** - * Determines how many advertisements to match per filter, as this is scarce hw resource. - * Match one advertisement per filter. + * Determines how many advertisements to match per filter, as this is scarce hw resource. Match + * one advertisement per filter. */ public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; /** - * Match few advertisement per filter, depends on current capability and availability of - * the resources in hw. + * Match few advertisement per filter, depends on current capability and availability of the + * resources in hw. */ public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; /** - * Match as many advertisement per filter as hw could allow, depends on current - * capability and availability of the resources in hw. + * Match as many advertisement per filter as hw could allow, depends on current capability and + * availability of the resources in hw. */ public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; - /** - * In Aggressive mode, hw will determine a match sooner even with feeble signal strength - * and few number of sightings/match in a duration. + * In Aggressive mode, hw will determine a match sooner even with feeble signal strength and few + * number of sightings/match in a duration. */ public static final int MATCH_MODE_AGGRESSIVE = 1; /** - * For sticky mode, higher threshold of signal strength and sightings is required - * before reporting by hw. + * For sticky mode, higher threshold of signal strength and sightings is required before + * reporting by hw. */ public static final int MATCH_MODE_STICKY = 2; /** - * Request full scan results which contain the device, rssi, advertising data, scan response - * as well as the scan timestamp. + * Request full scan results which contain the device, rssi, advertising data, scan response as + * well as the scan timestamp. * * @hide */ - @SystemApi - public static final int SCAN_RESULT_TYPE_FULL = 0; + @SystemApi public static final int SCAN_RESULT_TYPE_FULL = 0; /** * Request abbreviated scan results which contain the device, rssi and scan timestamp. - *

    - * Note: It is possible for an application to get more scan results than it asked for, if - * there are multiple apps using this type. + * + *

    Note: It is possible for an application to get more scan results than it asked for, + * if there are multiple apps using this type. * * @hide */ - @SystemApi - public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; + @SystemApi public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; /** - * Use all supported PHYs for scanning. - * This will check the controller capabilities, and start - * the scan on 1Mbit and LE Coded PHYs if supported, or on - * the 1Mbit PHY only. + * Use all supported PHYs for scanning. This will check the controller capabilities, and start + * the scan on 1Mbit and LE Coded PHYs if supported, or on the 1Mbit PHY only. */ public static final int PHY_LE_ALL_SUPPORTED = 255; @@ -203,46 +195,43 @@ public final class ScanSettings implements Parcelable { return mScanResultType; } - /** - * @hide - */ + /** @hide */ public int getMatchMode() { return mMatchMode; } - /** - * @hide - */ + /** @hide */ public int getNumOfMatches() { return mNumOfMatchesPerFilter; } /** - * Returns whether only legacy advertisements will be returned. - * Legacy advertisements include advertisements as specified - * by the Bluetooth core specification 4.2 and below. + * Returns whether only legacy advertisements will be returned. Legacy advertisements include + * advertisements as specified by the Bluetooth core specification 4.2 and below. */ public boolean getLegacy() { return mLegacy; } - /** - * Returns the physical layer used during a scan. - */ + /** Returns the physical layer used during a scan. */ public int getPhy() { return mPhy; } - /** - * Returns report delay timestamp based on the device clock. - */ + /** Returns report delay timestamp based on the device clock. */ public long getReportDelayMillis() { return mReportDelayMillis; } - private ScanSettings(int scanMode, int callbackType, int scanResultType, - long reportDelayMillis, int matchMode, - int numOfMatchesPerFilter, boolean legacy, int phy) { + private ScanSettings( + int scanMode, + int callbackType, + int scanResultType, + long reportDelayMillis, + int matchMode, + int numOfMatchesPerFilter, + boolean legacy, + int phy) { mScanMode = scanMode; mCallbackType = callbackType; mScanResultType = scanResultType; @@ -283,20 +272,18 @@ public final class ScanSettings implements Parcelable { public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Creator() { - @Override - public ScanSettings[] newArray(int size) { - return new ScanSettings[size]; - } - - @Override - public ScanSettings createFromParcel(Parcel in) { - return new ScanSettings(in); - } - }; - - /** - * Builder for {@link ScanSettings}. - */ + @Override + public ScanSettings[] newArray(int size) { + return new ScanSettings[size]; + } + + @Override + public ScanSettings createFromParcel(Parcel in) { + return new ScanSettings(in); + } + }; + + /** Builder for {@link ScanSettings}. */ public static final class Builder { private int mScanMode = SCAN_MODE_LOW_POWER; private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES; @@ -311,7 +298,8 @@ public final class ScanSettings implements Parcelable { * Set scan mode for Bluetooth LE scan. * * @param scanMode The scan mode can be one of {@link ScanSettings#SCAN_MODE_LOW_POWER}, - * {@link ScanSettings#SCAN_MODE_BALANCED} or {@link ScanSettings#SCAN_MODE_LOW_LATENCY}. + * {@link ScanSettings#SCAN_MODE_BALANCED} or {@link + * ScanSettings#SCAN_MODE_LOW_LATENCY}. * @throws IllegalArgumentException If the {@code scanMode} is invalid. */ public Builder setScanMode(int scanMode) { @@ -361,7 +349,8 @@ public final class ScanSettings implements Parcelable { * Set scan result type for Bluetooth LE scan. * * @param scanResultType Type for scan result, could be either {@link - * ScanSettings#SCAN_RESULT_TYPE_FULL} or {@link ScanSettings#SCAN_RESULT_TYPE_ABBREVIATED}. + * ScanSettings#SCAN_RESULT_TYPE_FULL} or {@link + * ScanSettings#SCAN_RESULT_TYPE_ABBREVIATED}. * @throws IllegalArgumentException If the {@code scanResultType} is invalid. * @hide */ @@ -369,8 +358,7 @@ public final class ScanSettings implements Parcelable { public Builder setScanResultType(int scanResultType) { if (scanResultType < SCAN_RESULT_TYPE_FULL || scanResultType > SCAN_RESULT_TYPE_ABBREVIATED) { - throw new IllegalArgumentException( - "invalid scanResultType - " + scanResultType); + throw new IllegalArgumentException("invalid scanResultType - " + scanResultType); } mScanResultType = scanResultType; return this; @@ -382,8 +370,7 @@ public final class ScanSettings implements Parcelable { * requested delay or 5000 milliseconds (whichever is higher). Note scan results may be * delivered sooner if the internal buffers fill up. * - * @param reportDelayMillis how frequently scan results should be delivered in - * milliseconds + * @param reportDelayMillis how frequently scan results should be delivered in milliseconds * @throws IllegalArgumentException if {@code reportDelayMillis} < 0 */ public Builder setReportDelay(long reportDelayMillis) { @@ -397,10 +384,10 @@ public final class ScanSettings implements Parcelable { /** * Set the number of matches for Bluetooth LE scan filters hardware match. * - * @param numOfMatches The num of matches can be one of - * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} - * or {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or {@link - * ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT} + * @param numOfMatches The num of matches can be one of {@link + * ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} or {@link + * ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or {@link + * ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT} * @throws IllegalArgumentException If the {@code matchMode} is invalid. */ public Builder setNumOfMatches(int numOfMatches) { @@ -416,12 +403,11 @@ public final class ScanSettings implements Parcelable { * Set match mode for Bluetooth LE scan filters hardware match. * * @param matchMode The match mode can be one of {@link ScanSettings#MATCH_MODE_AGGRESSIVE} - * or {@link ScanSettings#MATCH_MODE_STICKY} + * or {@link ScanSettings#MATCH_MODE_STICKY} * @throws IllegalArgumentException If the {@code matchMode} is invalid. */ public Builder setMatchMode(int matchMode) { - if (matchMode < MATCH_MODE_AGGRESSIVE - || matchMode > MATCH_MODE_STICKY) { + if (matchMode < MATCH_MODE_AGGRESSIVE || matchMode > MATCH_MODE_STICKY) { throw new IllegalArgumentException("invalid matchMode " + matchMode); } mMatchMode = matchMode; @@ -429,10 +415,9 @@ public final class ScanSettings implements Parcelable { } /** - * Set whether only legacy advertisments should be returned in scan results. - * Legacy advertisements include advertisements as specified by the - * Bluetooth core specification 4.2 and below. This is true by default - * for compatibility with older apps. + * Set whether only legacy advertisements should be returned in scan results. Legacy + * advertisements include advertisements as specified by the Bluetooth core specification + * 4.2 and below. This is true by default for compatibility with older apps. * * @param legacy true if only legacy advertisements will be returned */ @@ -442,16 +427,15 @@ public final class ScanSettings implements Parcelable { } /** - * Set the Physical Layer to use during this scan. - * This is used only if {@link ScanSettings.Builder#setLegacy} - * is set to false. - * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported} - * may be used to check whether LE Coded phy is supported by calling - * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}. - * Selecting an unsupported phy will result in failure to start scan. + * Set the Physical Layer to use during this scan. This is used only if {@link + * ScanSettings.Builder#setLegacy} is set to false. {@link + * android.bluetooth.BluetoothAdapter#isLeCodedPhySupported} may be used to check whether LE + * Coded phy is supported by calling {@link + * android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}. Selecting an unsupported phy + * will result in failure to start scan. * * @param phy Can be one of {@link BluetoothDevice#PHY_LE_1M}, {@link - * BluetoothDevice#PHY_LE_CODED} or {@link ScanSettings#PHY_LE_ALL_SUPPORTED} + * BluetoothDevice#PHY_LE_CODED} or {@link ScanSettings#PHY_LE_ALL_SUPPORTED} */ public Builder setPhy(int phy) { mPhy = phy; @@ -466,12 +450,19 @@ public final class ScanSettings implements Parcelable { public ScanSettings build() { if (mCallbackType == CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH && mReportDelayMillis < AUTO_BATCH_MIN_REPORT_DELAY_MILLIS) { - throw new IllegalArgumentException("report delay for auto batch must be >= " - + AUTO_BATCH_MIN_REPORT_DELAY_MILLIS); + throw new IllegalArgumentException( + "report delay for auto batch must be >= " + + AUTO_BATCH_MIN_REPORT_DELAY_MILLIS); } - return new ScanSettings(mScanMode, mCallbackType, mScanResultType, - mReportDelayMillis, mMatchMode, - mNumOfMatchesPerFilter, mLegacy, mPhy); + return new ScanSettings( + mScanMode, + mCallbackType, + mScanResultType, + mReportDelayMillis, + mMatchMode, + mNumOfMatchesPerFilter, + mLegacy, + mPhy); } } } diff --git a/framework/java/android/bluetooth/le/TransportBlock.java b/framework/java/android/bluetooth/le/TransportBlock.java index 18bad9c3c259c90648b8e03477f08a660126fb05..15acafd01a9af92e3172a31bb72adf14be687a53 100644 --- a/framework/java/android/bluetooth/le/TransportBlock.java +++ b/framework/java/android/bluetooth/le/TransportBlock.java @@ -27,8 +27,8 @@ import java.nio.ByteBuffer; import java.util.Arrays; /** - * Wrapper for Transport Discovery Data Transport Blocks. - * This class represents a Transport Block from a Transport Discovery Data. + * Wrapper for Transport Discovery Data Transport Blocks. This class represents a Transport Block + * from a Transport Discovery Data. * * @see TransportDiscoveryData * @see AdvertiseData @@ -48,8 +48,8 @@ public final class TransportBlock implements Parcelable { * @param transportDataLength the total length of the Transport Data * @param transportData the Transport Data */ - public TransportBlock(int orgId, int tdsFlags, int transportDataLength, - @Nullable byte[] transportData) { + public TransportBlock( + int orgId, int tdsFlags, int transportDataLength, @Nullable byte[] transportData) { mOrgId = orgId; mTdsFlags = tdsFlags; mTransportDataLength = transportDataLength; @@ -78,17 +78,13 @@ public final class TransportBlock implements Parcelable { } } - /** - * @hide - */ + /** @hide */ @Override public int describeContents() { return 0; } - /** - * @hide - */ + /** @hide */ @Override public boolean equals(@Nullable Object obj) { if (this == obj) { @@ -101,21 +97,28 @@ public final class TransportBlock implements Parcelable { return Arrays.equals(toByteArray(), other.toByteArray()); } - public static final @NonNull Creator CREATOR = new Creator() { - @Override - public TransportBlock createFromParcel(Parcel in) { - return new TransportBlock(in); - } + /** @hide */ + @Override + public int hashCode() { + return Arrays.hashCode(toByteArray()); + } - @Override - public TransportBlock[] newArray(int size) { - return new TransportBlock[size]; - } - }; + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public TransportBlock createFromParcel(Parcel in) { + return new TransportBlock(in); + } + + @Override + public TransportBlock[] newArray(int size) { + return new TransportBlock[size]; + } + }; /** - * Gets the Organization ID of the Transport Block which corresponds to one of the - * the Bluetooth SIG Assigned Numbers. + * Gets the Organization ID of the Transport Block which corresponds to one of the Bluetooth SIG + * Assigned Numbers. */ public int getOrgId() { return mOrgId; @@ -129,16 +132,12 @@ public final class TransportBlock implements Parcelable { return mTdsFlags; } - /** - * Gets the total number of octets in the Transport Data field in this Transport Block. - */ + /** Gets the total number of octets in the Transport Data field in this Transport Block. */ public int getTransportDataLength() { return mTransportDataLength; } - /** - * Gets the Transport Data of the Transport Block which contains organization-specific data. - */ + /** Gets the Transport Data of the Transport Block which contains organization-specific data. */ @Nullable public byte[] getTransportData() { return mTransportData; diff --git a/framework/java/android/bluetooth/le/TransportBlockFilter.java b/framework/java/android/bluetooth/le/TransportBlockFilter.java index 39ecf04023e7c5b2a00ed4d2a5fa573a50700714..d7755621631d44041a3a367f937ea53d006f4e97 100644 --- a/framework/java/android/bluetooth/le/TransportBlockFilter.java +++ b/framework/java/android/bluetooth/le/TransportBlockFilter.java @@ -27,9 +27,8 @@ import java.util.Arrays; import java.util.Objects; /** - * Wrapper for filter input for Transport Discovery Data Transport Blocks. - * This class represents the filter for a Transport Block from a Transport Discovery Data - * advertisement data. + * Wrapper for filter input for Transport Discovery Data Transport Blocks. This class represents the + * filter for a Transport Block from a Transport Discovery Data advertisement data. * * @see ScanFilter * @hide @@ -46,13 +45,17 @@ public final class TransportBlockFilter implements Parcelable { /** * Length of a Wi-FI NAN hash in bytes/ + * * @hide */ - @SystemApi - public static final int WIFI_NAN_HASH_LENGTH_BYTES = 8; - - private TransportBlockFilter(int orgId, int tdsFlags, int tdsFlagsMask, - @Nullable byte[] transportData, @Nullable byte[] transportDataMask, + @SystemApi public static final int WIFI_NAN_HASH_LENGTH_BYTES = 8; + + private TransportBlockFilter( + int orgId, + int tdsFlags, + int tdsFlagsMask, + @Nullable byte[] transportData, + @Nullable byte[] transportDataMask, @Nullable byte[] wifiNanHash) { if (orgId < 1) { throw new IllegalArgumentException("invalid organization id " + orgId); @@ -73,12 +76,14 @@ public final class TransportBlockFilter implements Parcelable { if (wifiNanHash != null && wifiNanHash.length != WIFI_NAN_HASH_LENGTH_BYTES) { throw new IllegalArgumentException( "wifiNanHash should be WIFI_NAN_HASH_LENGTH_BYTES long, but the input is " - + wifiNanHash.length + " bytes"); + + wifiNanHash.length + + " bytes"); } } else { if (wifiNanHash != null) { - throw new IllegalArgumentException("wifiNanHash should not be used when orgId is " - + "not WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING"); + throw new IllegalArgumentException( + "wifiNanHash should not be used when orgId is " + + "not WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING"); } } mOrgId = orgId; @@ -91,8 +96,10 @@ public final class TransportBlockFilter implements Parcelable { /** * Get Organization ID assigned by Bluetooth SIG. For more details refer to Transport Discovery - * Service Organization IDs in - * Bluetooth Assigned Numbers + * Service Organization IDs in Bluetooth Assigned + * Numbers + * * @hide */ @SystemApi @@ -100,7 +107,6 @@ public final class TransportBlockFilter implements Parcelable { return mOrgId; } - /** * Get Transport Discovery Service (TDS) flags to filter Transport Discovery Blocks * @@ -115,7 +121,7 @@ public final class TransportBlockFilter implements Parcelable { * Get masks for filtering Transport Discovery Service (TDS) flags in Transport Discovery Blocks * * @return a bitmask to select which bits in {@code tdsFlag} to match. 0 means no bit in - * tdsFlags will be used for matching + * tdsFlags will be used for matching * @hide */ @SystemApi @@ -126,7 +132,7 @@ public final class TransportBlockFilter implements Parcelable { /** * Get data to filter Transport Discovery Blocks. * - * Cannot be used when {@code orgId} is {@link OrganizationId + *

    Cannot be used when {@code orgId} is {@link OrganizationId * #WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} * * @return Data to filter Transport Discovery Blocks, null if not used @@ -141,11 +147,11 @@ public final class TransportBlockFilter implements Parcelable { /** * Get masks for filtering data in Transport Discovery Blocks. * - * Cannot be used when {@code orgId} is - * {@link OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} + *

    Cannot be used when {@code orgId} is {@link + * OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} * - * @return a byte array with matching length to {@code transportData} to - * select which bit to use in filter, null is not used + * @return a byte array with matching length to {@code transportData} to select which bit to use + * in filter, null is not used * @hide */ @SystemApi @@ -155,12 +161,12 @@ public final class TransportBlockFilter implements Parcelable { } /** - * Get hashed bloom filter value to filter - * {@link OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} services in Transport - * Discovery Blocks. + * Get hashed bloom filter value to filter {@link + * OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} services in Transport Discovery + * Blocks. * - * Can only be used when {@code orgId} is - * {@link OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING}. + *

    Can only be used when {@code orgId} is {@link + * OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING}. * * @return 8 octets Wi-Fi NAN defined bloom filter hash, null if not used * @hide @@ -186,7 +192,7 @@ public final class TransportBlockFilter implements Parcelable { if ((transportDiscoveryData != null)) { for (TransportBlock transportBlock : transportDiscoveryData.getTransportBlocks()) { int orgId = transportBlock.getOrgId(); - int tdsFlags = transportBlock.getTdsFlags(); + int tdsFlags = transportBlock.getTdsFlags(); int transportDataLength = transportBlock.getTransportDataLength(); byte[] transportData = transportBlock.getTransportData(); @@ -197,7 +203,8 @@ public final class TransportBlockFilter implements Parcelable { continue; } if ((mOrgId != OrganizationId.WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING) - && (mTransportData != null) && (mTransportDataMask != null)) { + && (mTransportData != null) + && (mTransportDataMask != null)) { if (transportDataLength != 0) { if (!ScanFilter.matchesPartialData( mTransportData, mTransportDataMask, transportData)) { @@ -214,9 +221,7 @@ public final class TransportBlockFilter implements Parcelable { return false; } - /** - * @hide - */ + /** @hide */ @Override public int describeContents() { return 0; @@ -224,6 +229,7 @@ public final class TransportBlockFilter implements Parcelable { /** * {@inheritDoc} + * * @hide */ @SystemApi @@ -249,22 +255,33 @@ public final class TransportBlockFilter implements Parcelable { } } - /** - * Get a human-readable string for this object. - */ + /** Get a human-readable string for this object. */ @Override public String toString() { - return "TransportBlockFilter [mOrgId=" + mOrgId + ", mTdsFlags=" + mTdsFlags - + ", mTdsFlagsMask=" + mTdsFlagsMask + ", mTransportData=" - + Arrays.toString(mTransportData) + ", mTransportDataMask=" - + Arrays.toString(mTransportDataMask) + ", mWifiNanHash=" - + Arrays.toString(mWifiNanHash) + "]"; + return "TransportBlockFilter [mOrgId=" + + mOrgId + + ", mTdsFlags=" + + mTdsFlags + + ", mTdsFlagsMask=" + + mTdsFlagsMask + + ", mTransportData=" + + Arrays.toString(mTransportData) + + ", mTransportDataMask=" + + Arrays.toString(mTransportDataMask) + + ", mWifiNanHash=" + + Arrays.toString(mWifiNanHash) + + "]"; } @Override public int hashCode() { - return Objects.hash(mOrgId, mTdsFlags, mTdsFlagsMask, Arrays.hashCode(mTransportData), - Arrays.hashCode(mTransportDataMask), Arrays.hashCode(mWifiNanHash)); + return Objects.hash( + mOrgId, + mTdsFlags, + mTdsFlagsMask, + Arrays.hashCode(mTransportData), + Arrays.hashCode(mTransportDataMask), + Arrays.hashCode(mWifiNanHash)); } @Override @@ -286,42 +303,43 @@ public final class TransportBlockFilter implements Parcelable { /** * Creator for {@link TransportBlockFilter} so that we can create it from {@link Parcel}. + * * @hide */ - @SystemApi - @NonNull - public static final Creator CREATOR = new Creator<>() { - @Override - public TransportBlockFilter createFromParcel(Parcel source) { - final int orgId = source.readInt(); - Builder builder = new Builder(orgId); - builder.setTdsFlags(source.readInt(), source.readInt()); - if (source.readInt() == 1) { - int transportDataLength = source.readInt(); - byte[] transportData = new byte[transportDataLength]; - source.readByteArray(transportData); - byte[] transportDataMask = null; - if (source.readInt() == 1) { - int transportDataMaskLength = source.readInt(); - transportDataMask = new byte[transportDataMaskLength]; - source.readByteArray(transportDataMask); + @SystemApi @NonNull + public static final Creator CREATOR = + new Creator<>() { + @Override + public TransportBlockFilter createFromParcel(Parcel source) { + final int orgId = source.readInt(); + Builder builder = new Builder(orgId); + builder.setTdsFlags(source.readInt(), source.readInt()); + if (source.readInt() == 1) { + int transportDataLength = source.readInt(); + byte[] transportData = new byte[transportDataLength]; + source.readByteArray(transportData); + byte[] transportDataMask = null; + if (source.readInt() == 1) { + int transportDataMaskLength = source.readInt(); + transportDataMask = new byte[transportDataMaskLength]; + source.readByteArray(transportDataMask); + } + builder.setTransportData(transportData, transportDataMask); + } + if (source.readInt() == 1) { + int wifiNanHashLength = source.readInt(); + byte[] wifiNanHash = new byte[wifiNanHashLength]; + source.readByteArray(wifiNanHash); + builder.setWifiNanHash(wifiNanHash); + } + return builder.build(); } - builder.setTransportData(transportData, transportDataMask); - } - if (source.readInt() == 1) { - int wifiNanHashLength = source.readInt(); - byte[] wifiNanHash = new byte[wifiNanHashLength]; - source.readByteArray(wifiNanHash); - builder.setWifiNanHash(wifiNanHash); - } - return builder.build(); - } - @Override - public TransportBlockFilter[] newArray(int size) { - return new TransportBlockFilter[0]; - } - }; + @Override + public TransportBlockFilter[] newArray(int size) { + return new TransportBlockFilter[0]; + } + }; /** * Builder class for {@link TransportBlockFilter}. @@ -342,8 +360,9 @@ public final class TransportBlockFilter implements Parcelable { * Builder for {@link TransportBlockFilter}. * * @param orgId Organization ID assigned by Bluetooth SIG. For more details refer to - * Transport Discovery Service Organization IDs in - * Bluetooth Assigned Numbers. + * Transport Discovery Service Organization IDs in Bluetooth Assigned + * Numbers. * @throws IllegalArgumentException If the {@code orgId} is invalid * @see OrganizationId * @hide @@ -360,13 +379,13 @@ public final class TransportBlockFilter implements Parcelable { * Set Transport Discovery Service (TDS) flags to filter Transport Discovery Blocks. * * @param tdsFlags 1 octet value that represents the role of the device and information - * about its state and supported features. Negative values are invalid for this argument. - * Default to 0. See Transport Discovery Service specification for more details. - * @param tdsFlagsMask a bitmask to select which bits in {@code tdsFlag} - * to match. Default to 0, meaning no flag match required. Negative values are invalid for - * this argument. + * about its state and supported features. Negative values are invalid for this + * argument. Default to 0. See Transport Discovery Service specification for more + * details. + * @param tdsFlagsMask a bitmask to select which bits in {@code tdsFlags} to match. Default + * to 0, meaning no flag match required. Negative values are invalid for this argument. * @throws IllegalArgumentException if either {@code tdsFlags} or {@code tdsFlagsMask} is - * invalid. + * invalid. * @return this builder * @hide */ @@ -387,28 +406,28 @@ public final class TransportBlockFilter implements Parcelable { /** * Set data to filter Transport Discovery Blocks. * - * Cannot be used when {@code orgId} is - * {@link OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} + *

    Cannot be used when {@code orgId} is {@link + * OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} * - * @param transportData must be valid value for the particular {@code orgId}. See - * Transport Discovery Service specification for more details. + * @param transportData must be valid value for the particular {@code orgId}. See Transport + * Discovery Service specification for more details. * @param transportDataMask a byte array with matching length to {@code transportData} to - * select which bit to use in filter. - * @throws IllegalArgumentException when {@code orgId} is - * {@link OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} + * select which bit to use in filter. + * @throws IllegalArgumentException when {@code orgId} is {@link + * OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} * @throws NullPointerException if {@code transportData} or {@code transportDataMask} is - * {@code null} + * {@code null} * @throws IllegalArgumentException if {@code transportData} or {@code transportDataMask} is - * empty - * @throws IllegalArgumentException if length of {@code transportData} and - * {@code transportDataMask} do not match + * empty + * @throws IllegalArgumentException if length of {@code transportData} and {@code + * transportDataMask} do not match * @return this builder * @hide */ @SystemApi @NonNull - public Builder setTransportData(@NonNull byte[] transportData, - @NonNull byte[] transportDataMask) { + public Builder setTransportData( + @NonNull byte[] transportData, @NonNull byte[] transportDataMask) { if (mOrgId == OrganizationId.WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING) { throw new IllegalArgumentException( "setWifiNanHash() should be used instead of setTransportData() when orgId " @@ -435,16 +454,16 @@ public final class TransportBlockFilter implements Parcelable { * Set hashed bloom filter value to filter {@link OrganizationId * #WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} services in Transport Discovery Blocks. * - * Can only be used when {@code orgId} is {@link OrganizationId + *

    Can only be used when {@code orgId} is {@link OrganizationId * #WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING}. * - * Cannot be used together with {@link #setTransportData(byte[], byte[])} + *

    Cannot be used together with {@link #setTransportData(byte[], byte[])} * * @param wifiNanHash 8 octets Wi-Fi NAN defined bloom filter hash - * @throws IllegalArgumentException when {@code orgId} is not - * {@link OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} - * @throws IllegalArgumentException when {@code wifiNanHash} is not - * {@link TransportBlockFilter#WIFI_NAN_HASH_LENGTH_BYTES} long + * @throws IllegalArgumentException when {@code orgId} is not {@link + * OrganizationId#WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING} + * @throws IllegalArgumentException when {@code wifiNanHash} is not {@link + * TransportBlockFilter#WIFI_NAN_HASH_LENGTH_BYTES} long * @throws NullPointerException when {@code wifiNanHash} is null * @return this builder * @hide @@ -453,8 +472,9 @@ public final class TransportBlockFilter implements Parcelable { @NonNull public Builder setWifiNanHash(@NonNull byte[] wifiNanHash) { if (mOrgId != OrganizationId.WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING) { - throw new IllegalArgumentException("setWifiNanHash() can only be used when orgId is" - + " WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING"); + throw new IllegalArgumentException( + "setWifiNanHash() can only be used when orgId is" + + " WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING"); } Objects.requireNonNull(wifiNanHash); if (wifiNanHash.length != WIFI_NAN_HASH_LENGTH_BYTES) { @@ -474,8 +494,13 @@ public final class TransportBlockFilter implements Parcelable { @SystemApi @NonNull public TransportBlockFilter build() { - return new TransportBlockFilter(mOrgId, mTdsFlags, mTdsFlagsMask, mTransportData, - mTransportDataMask, mWifiNanHash); + return new TransportBlockFilter( + mOrgId, + mTdsFlags, + mTdsFlagsMask, + mTransportData, + mTransportDataMask, + mWifiNanHash); } } } diff --git a/framework/java/android/bluetooth/le/TransportDiscoveryData.java b/framework/java/android/bluetooth/le/TransportDiscoveryData.java index ba1d5f1de30d45f5fa04bf857a92f5ef65071dcb..21492e168112dd90864b5b92df160cdab6807e14 100644 --- a/framework/java/android/bluetooth/le/TransportDiscoveryData.java +++ b/framework/java/android/bluetooth/le/TransportDiscoveryData.java @@ -31,9 +31,8 @@ import java.util.Collections; import java.util.List; /** - * Wrapper for Transport Discovery Data AD Type. - * This class contains the Transport Discovery Data AD Type Code as well as - * a list of potential Transport Blocks. + * Wrapper for Transport Discovery Data AD Type. This class contains the Transport Discovery Data AD + * Type Code as well as a list of potential Transport Blocks. * * @see AdvertiseData */ @@ -48,8 +47,8 @@ public final class TransportDiscoveryData implements Parcelable { * @param transportDataType the Transport Discovery Data AD Type * @param transportBlocks the list of Transport Blocks */ - public TransportDiscoveryData(int transportDataType, - @NonNull List transportBlocks) { + public TransportDiscoveryData( + int transportDataType, @NonNull List transportBlocks) { mTransportDataType = transportDataType; mTransportBlocks = transportBlocks; } @@ -57,7 +56,7 @@ public final class TransportDiscoveryData implements Parcelable { /** * Creates a TransportDiscoveryData instance from byte arrays. * - * Uses the transport discovery data bytes and parses them into an usable class. + *

    Uses the transport discovery data bytes and parses them into an usable class. * * @param transportDiscoveryData the raw discovery data */ @@ -76,8 +75,8 @@ public final class TransportDiscoveryData implements Parcelable { int transportDataLength = byteBuffer.get(); byte[] transportData = new byte[transportDataLength]; byteBuffer.get(transportData, 0, transportDataLength); - mTransportBlocks.add(new TransportBlock(orgId, tdsFlags, - transportDataLength, transportData)); + mTransportBlocks.add( + new TransportBlock(orgId, tdsFlags, transportDataLength, transportData)); } } catch (BufferUnderflowException e) { Log.e(TAG, "Error while parsing data: " + e.toString()); @@ -89,17 +88,13 @@ public final class TransportDiscoveryData implements Parcelable { mTransportBlocks = in.createTypedArrayList(TransportBlock.CREATOR); } - /** - * @hide - */ + /** @hide */ @Override public int describeContents() { return 0; } - /** - * @hide - */ + /** @hide */ @Override public boolean equals(@Nullable Object obj) { if (this == obj) { @@ -112,6 +107,12 @@ public final class TransportDiscoveryData implements Parcelable { return Arrays.equals(toByteArray(), other.toByteArray()); } + /** @hide */ + @Override + public int hashCode() { + return Arrays.hashCode(toByteArray()); + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mTransportDataType); @@ -129,18 +130,16 @@ public final class TransportDiscoveryData implements Parcelable { public TransportDiscoveryData[] newArray(int size) { return new TransportDiscoveryData[size]; } - }; + }; - /** - * Gets the transport data type. - */ + /** Gets the transport data type. */ public int getTransportDataType() { return mTransportDataType; } /** - * @return the list of {@link TransportBlock} in this TransportDiscoveryData - * or an empty list if there are no Transport Blocks + * @return the list of {@link TransportBlock} in this TransportDiscoveryData or an empty list if + * there are no Transport Blocks */ @NonNull public List getTransportBlocks() { @@ -153,8 +152,8 @@ public final class TransportDiscoveryData implements Parcelable { /** * Converts this TransportDiscoveryData to byte array * - * @return byte array representation of this Transport Discovery Data or null if the - * conversion failed + * @return byte array representation of this Transport Discovery Data or null if the conversion + * failed */ @Nullable public byte[] toByteArray() { diff --git a/framework/java/android/bluetooth/le/TruncatedFilter.java b/framework/java/android/bluetooth/le/TruncatedFilter.java index 25925888a0d237a408502159b3942f808089cf7e..2867a87d3391c45d8e8ae5cf0f7b88dbeb560f21 100644 --- a/framework/java/android/bluetooth/le/TruncatedFilter.java +++ b/framework/java/android/bluetooth/le/TruncatedFilter.java @@ -25,7 +25,6 @@ import java.util.List; * A special scan filter that lets the client decide how the scan record should be stored. * * @deprecated this is not used anywhere - * * @hide */ @Deprecated @@ -46,19 +45,13 @@ public final class TruncatedFilter { mStorageDescriptors = storageDescriptors; } - /** - * Returns the scan filter. - */ + /** Returns the scan filter. */ public ScanFilter getFilter() { return mFilter; } - /** - * Returns a list of descriptor for scan result storage. - */ + /** Returns a list of descriptor for scan result storage. */ public List getStorageDescriptors() { return mStorageDescriptors; } - - } diff --git a/framework/tests/bumble/Android.bp b/framework/tests/bumble/Android.bp index e28883af62a429a335b2509d7aa7d08b79605ab9..d1cfa300155fa9e58d64f77a0e5607439769ef42 100644 --- a/framework/tests/bumble/Android.bp +++ b/framework/tests/bumble/Android.bp @@ -15,27 +15,30 @@ android_test_helper_app { target_sdk_version: "current", libs: [ "android.test.base", - "android.test.runner", "libprotobuf-java-micro", ], static_libs: [ + "androidx.core_core", + "androidx.test.espresso.intents", + "androidx.test.ext.junit", "androidx.test.ext.truth", "androidx.test.rules", - "androidx.core_core", + "bluetooth-test-util-lib", + "compatibility-device-util-axt", "grpc-java-lite", "grpc-java-okhttp-client-lite", + "mockito-kotlin2", "opencensus-java-contrib-grpc-metrics", "pandora_experimental-grpc-java", "pandora_experimental-proto-java", + "truth-java8-extension", ], - // Include all test java files. - srcs: ["src/**/*.java"], - - platform_apis: true, - test_suites: [ - "general-tests", + // Include all test java and kotlin files. + srcs: [ + "src/**/*.java", + "src/**/*.kt", ], } @@ -50,7 +53,10 @@ java_test_host { data: [ ":BumbleBluetoothTestsApp", - ":bumble_pandora_server" + "bumble_config.json", + ], + data_native_bins: [ + "bumble_pandora_server", ], required: ["bumble_pandora_server"], @@ -59,3 +65,17 @@ java_test_host { "general-tests", ], } + +python_binary_host { + name: "bumble_pandora_server", + main: "src/bumble_server.py", + srcs: [ + "src/bumble_server.py", + ], + libs: [ + "bumble-pandora", + "bumble_services_experimental-python", + "pandora-python", + "pandora_experimental-python", + ], +} diff --git a/framework/tests/bumble/AndroidManifest.xml b/framework/tests/bumble/AndroidManifest.xml index 4e17c37dab5198db82e840266f79d1109ee12627..2eb1e39a0f6a5316964a81c288ebd9fdda302020 100644 --- a/framework/tests/bumble/AndroidManifest.xml +++ b/framework/tests/bumble/AndroidManifest.xml @@ -9,6 +9,12 @@ + + + + + + + + + diff --git a/framework/tests/bumble/OWNERS b/framework/tests/bumble/OWNERS index 2992b8c474ade21b0af427a42d1e81127f20057a..c0af7f1c792b31c7f815afec3b9fbe773305361b 100644 --- a/framework/tests/bumble/OWNERS +++ b/framework/tests/bumble/OWNERS @@ -1,5 +1,6 @@ # Bug component: 1099313 # Project owners +set noparent girardier@google.com -qiaoccolato@google.com licorne@google.com +charliebout@google.com diff --git a/framework/tests/bumble/bumble_config.json b/framework/tests/bumble/bumble_config.json new file mode 100644 index 0000000000000000000000000000000000000000..adbd21fa3d2881f6ef8784b128e687821adab9fb --- /dev/null +++ b/framework/tests/bumble/bumble_config.json @@ -0,0 +1,6 @@ +{ + "advertising_interval": 200, + "address": "51:F7:A8:75:AC:5E", + "classic_enabled": true, + "irk": "1F66F4B5F0C742F807DD0DDBF64E9213" +} diff --git a/framework/tests/bumble/doc/asset/java-bumble-test-setup-without-tf.png b/framework/tests/bumble/doc/asset/java-bumble-test-setup-without-tf.png new file mode 100644 index 0000000000000000000000000000000000000000..2524bb23ee70a3d6b97045b5a408c8e7b1674731 Binary files /dev/null and b/framework/tests/bumble/doc/asset/java-bumble-test-setup-without-tf.png differ diff --git a/framework/tests/bumble/doc/guide.md b/framework/tests/bumble/doc/guide.md new file mode 100644 index 0000000000000000000000000000000000000000..608be8738afe6b61cd42d9c1b3e02e5eda7446bd --- /dev/null +++ b/framework/tests/bumble/doc/guide.md @@ -0,0 +1,229 @@ +# Writing a BumbleBluetoothTests: A Comprehensive Guide + +This guide seeks to demystify the process using `testDiscoverDkGattService` as an example. +By the end, you should have a blueprint for constructing similar tests for your Bluetooth +functionalities. + +The BumbleBluetoothTests source code can be found in the Android codebase [here][bumble-bluetooth-tests-code]. + +Pandora APIs are implemented both on Android in a [PandoraServer][pandora-server-code] app and on +[BumblePandoraServer][bumble-github-pandora-server]. The communication between the virtual Android +DUT and the virtual Bumble Reference device is made through [Rootcanal][rootcanal-code], a virtual +Bluetooth Controller. + + +## Prerequisites + +Before diving in, ensure you are acquainted with: +- [Android Junit4][android-junit4] for unit testing +- [Mockito](https://site.mockito.org/) for mocking dependencies +- [Java gRPC documentation][grpc-java-doc] +- [Pandora stable APIs][pandora-stable-apis] +- [Pandora experimental APIs][pandora-experimental-apis] + +You must have a running Cuttlefish instance. If not, you can run the following commands from the +root of your Android repository: + +```shell +cd $ANDROID_BUILD_TOP +source build/envsetup.sh +lunch aosp_cf_x86_64_phone-trunk_staging-userdebug +acloud create # Create a remote instance using the latest know good build image. +acloud create --local-image # OR: Create a remote instance using a local image. +acloud create --local-image --local-instance # OR: Create a local instance using a local image. +``` + +Install virtual env: + +```shell +sudo apt install virtualenv +``` +Note: For Googlers, from an internal Android repository, use the `cf_x86_64_phone-userdebug` target +instead. + +## Run existing tests + +You can run all the existing BumbleBluetoothTests by doing so: + +```shell +atest BumbleBluetoothTests +``` + +If you wish to run a specific test file: + +```shell +atest BumbleBluetoothTests:. +atest BumbleBluetoothTests:android.bluetooth.DckTest +``` + +And to run a specific test from a test file: + +```shell +atest BumbleBluetoothTests:.# +atest BumbleBluetoothTests:android.bluetooth.DckTest#testDiscoverDkGattService +``` + +Note: The process might not shut down correctly when interrupted with a SIGINT (Ctrl + C) command. +This can leave behind a ghost process. To locate and terminate it, simply follow these steps: + +```shell +ps aux | grep python3 # Identify the ghost process and its process id +kill +``` + +## Crafting the test: Step by Step + +### 0. Create the test file + +You can either choose to build your new test in Kotlin or in Java. It is totally up to you. +However for this example we will build one in Kotlin. + +Let say we are creating a DCK test. + +First, create your file under `p/m/Blueooth/frameworks/bumble/src/android/bluetooth` like so: + +```shell +cd p/m/Bluetooth/frameworks/bumble/src/android/bluetooth +touch DckTest.kt # We usualy name our test file Test.kt/.java +``` + +Then add the minimum requirements: + +```kotlin +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Rule +import org.junit.Test + +@RunWith(AndroidJUnit4::class) +public class DckTest { + private val TAG = "DckTest" + + // A Rule live from a test setup through it's teardown. + // Gives shell permissions during the test. + @Rule @JvmField val mPermissionRule = AdoptShellPermissionsRule() + + // Setup a Bumble Pandora device for the duration of the test. + // Acting as a Pandora client, it can be interacted with through the Pandora APIs. + @Rule @JvmField val mBumble = PandoraDevice() + + @Test + fun testDiscoverDkGattService() { + // Test implementation + } +} +``` + +### 1. Register with Service via gRPC + +Here, we're dealing with Bumble's DCK (Digital Car Key) service. First, we need Bumble to register +the Dck Gatt service. + +```kotlin +//- `dckBlocking()` is likely a stub accessing the DCK service over gRPC in a synchronous manner. +//- `withDeadline(Deadline.after(TIMEOUT, TimeUnit.MILLISECONDS))` sets a timeout for the call. +//- `register(Empty.getDefaultInstance())` communicates our registration to the server. +mBumble + .dckBlocking() + .withDeadline(Deadline.after(TIMEOUT, TimeUnit.MILLISECONDS)) + .register(Empty.getDefaultInstance()) +``` + +### 2. Advertise Bluetooth Capabilities + +If our device wants to be discoverable and indicate its capabilities, it would "advertise" these +capabilities. Here, it's done via another gRPC call. + +```kotlin +mBumble + .hostBlocking() + .advertise( + AdvertiseRequest.newBuilder() + .setLegacy(true) // As of now, Bumble only support legacy advertising (b/266124496). + .setConnectable(true) + .setOwnAddressType(OwnAddressType.RANDOM) // Ask Bumble to advertise it's `RANDOM` address. + .build() + ) +``` + +### 3. Fetch a Known Remote Bluetooth Device + +To keep things straightforward, the Bumble RANDOM address is set to a predefined constant. +Typically, an LE scan would be conducted to identify the Bumble device, matching it based on its +Advertising data. + +```kotlin +val bumbleDevice = + bluetoothAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, + BluetoothDevice.ADDRESS_TYPE_RANDOM // Specify address type as RANDOM because the device advertises with this address type. + ) +``` + +### 4. Create Mock Callback for GATT Events + +Interactions over Bluetooth often involve callback mechanisms. Here, we're mocking the callback +with Mockito to verify later that expected events occurred. + +```kotlin +val gattCallback = mock(BluetoothGattCallback::class.java) +``` +### 5. Initiate and Verify Connection + +To bond with Bumble, we initiate a connection and then verify that the connection is successful. + +```kotlin +var bumbleGatt = bumbleDevice.connectGatt(context, false, gattCallback) +verify(gattCallback, timeout(TIMEOUT)) + .onConnectionStateChange( + any(), + eq(BluetoothGatt.GATT_SUCCESS), + eq(BluetoothProfile.STATE_CONNECTED) + ) +``` +### 6. Discover and Verify GATT Services + +After connecting, we seek to find out the services offered by Bumble and affirm their successful +discovery. + +```kotlin +bumbleGatt.discoverServices() +verify(gattCallback, timeout(TIMEOUT)) + .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS)) + +``` + +### 7. Confirm Service Availability + +Ensure that the specific service (in this example, CCC_DK_UUID) is present on the remote device. + +```kotlin +assertThat(bumbleGatt.getService(CCC_DK_UUID)).isNotNull() +``` +### 8. Disconnect and Confirm +Finally, after our operations, we disconnect and ensure it is done gracefully. + +```kotlin +bumbleGatt.disconnect() +verify(gattCallback, timeout(TIMEOUT)) + .onConnectionStateChange( + any(), + eq(BluetoothGatt.GATT_SUCCESS), + eq(BluetoothProfile.STATE_DISCONNECTED) + ) +``` + +## Conclusion + +This tutorial provided a step-by-step guide on testing some Bluetooth functionalities on top of the +Android Bluetooth frameworks, leveraging both gRPC and Bluetooth GATT interactions. For the detailed +implementation and the full code, refer to our [source code][bumble-bluetooth-tests-code]. + +[android-junit4]: https://developer.android.com/reference/androidx/test/runner/AndroidJUnit4 +[bumble-bluetooth-tests-code]: https://cs.android.com/android/platform/superproject/+/main:packages/modules/Bluetooth/framework/tests/bumble/ +[bumble-github-pandora-server]: https://github.com/google/bumble/tree/main/bumble/pandora +[grpc-java-doc]: https://grpc.io/docs/languages/java/ +[pandora-experimental-apis]: https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/pandora/interfaces/pandora_experimental/ +[pandora-server-code]: https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/android/pandora/server/ +[pandora-stable-apis]: https://cs.android.com/android/platform/superproject/main/+/main:external/pandora/bt-test-interfaces/ +[rootcanal-code]: https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/tools/rootcanal diff --git a/framework/tests/bumble/doc/overview.md b/framework/tests/bumble/doc/overview.md new file mode 100644 index 0000000000000000000000000000000000000000..024e77623506daedb251b76d7e57b55703610480 --- /dev/null +++ b/framework/tests/bumble/doc/overview.md @@ -0,0 +1,75 @@ +# BumbleBluetoothTests + +Bumble Bluetooth tests are instrumented Android-specific multi-device tests using a reference +peer device implementing the Pandora APIs. + +## Architecture + +BumbleBluetoothTests is an Android APK that offers enhanced control over Android compared to Avatar +by interacting directly with the Device Under Test (DUT) via Android APIs. Instead of mocking every +API call, it communicates with actual reference devices using gRPC and limits peer device interactions +to the Pandora APIs. + +Here is an overview of the BumbleBluetoothTests architecture: +![BumbleBluetoothTests architecture](asset/java-bumble-test-setup.png) + +A simple LE connection test looks like this: + +```kotlin +// Setup a Bumble Pandora device for the duration of the test. +// Acting as a Pandora client, it can be interacted with through the Pandora APIs. +@Rule @JvmField val mBumble = PandoraDevice() + +/** + * Tests the Bluetooth GATT connection process with a mock callback. + * This verifies both successful connection and disconnection events for a + * remote Bluetooth device. + * + * @throws Exception if there's an unexpected error during the test execution. + */ +@Test +fun testGattConnect() { + // 1. Advertise the host's Bluetooth capabilities using another + // gRPC call: + // - `hostBlocking()` accesses another gRPC service related to the host. + // The following `advertise(...)` sends an advertise request to the server, setting + // specific attributes. + mBumble + .hostBlocking() + .advertise( + AdvertiseRequest.newBuilder() + .setLegacy(true) + .setConnectable(true) + .setOwnAddressType(OwnAddressType.RANDOM) + .build() + ) + + // 2. Create a mock callback to handle Bluetooth GATT (Generic Attribute Profile) related events. + val gattCallback = mock(BluetoothGattCallback::class.java) + + // 3. Fetch a remote Bluetooth device instance (here, Bumble). + val bumbleDevice = + bluetoothAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, + BluetoothDevice.ADDRESS_TYPE_RANDOM // Specify address type as RANDOM because the device advertises with this address type. + ) + + // 4. Connect to the Bumble device and expect a successful connection callback. + var bumbleGatt = bumbleDevice.connectGatt(context, false, gattCallback) + verify(gattCallback, timeout(TIMEOUT)) + .onConnectionStateChange( + any(), + eq(BluetoothGatt.GATT_SUCCESS), + eq(BluetoothProfile.STATE_CONNECTED) + ) + + // 5. Disconnect from the Bumble device and expect a successful disconnection callback. + bumbleGatt.disconnect() + verify(gattCallback, timeout(TIMEOUT)) + .onConnectionStateChange( + any(), + eq(BluetoothGatt.GATT_SUCCESS), + eq(BluetoothProfile.STATE_DISCONNECTED) + ) +} +``` diff --git a/framework/tests/bumble/src/android/bluetooth/DckTest.kt b/framework/tests/bumble/src/android/bluetooth/DckTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..fe7095682f31aa6534e8f57b0782905aaf4c4524 --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/DckTest.kt @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.compatibility.common.util.AdoptShellPermissionsRule +import com.google.common.truth.Truth.assertThat +import com.google.protobuf.Empty +import io.grpc.Deadline +import java.util.UUID +import java.util.concurrent.TimeUnit +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.timeout +import org.mockito.kotlin.verify +import pandora.HostProto.AdvertiseRequest +import pandora.HostProto.OwnAddressType + +@RunWith(AndroidJUnit4::class) +public class DckTest { + + private val context: Context = ApplicationProvider.getApplicationContext() + private val bluetoothManager = context.getSystemService(BluetoothManager::class.java)!! + private val bluetoothAdapter = bluetoothManager.adapter + + // A Rule live from a test setup through it's teardown. + // Gives shell permissions during the test. + @Rule @JvmField val mPermissionRule = AdoptShellPermissionsRule() + + // Setup a Bumble Pandora device for the duration of the test. + // Acting as a Pandora client, it can be interacted with through the Pandora APIs. + @Rule @JvmField val mBumble = PandoraDevice() + + /** + * Tests the discovery of the Digital Car Key (DCK) GATT service via Bluetooth on an Android + * device. + * + *

    This test method goes through the following steps: + *

      + *
    • 1. Register the Dck Gatt service on Bumble over a gRPC call.
    • + *
    • 2. Advertises the host's (potentially the car's) Bluetooth capabilities through a gRPC + * call.
    • + *
    • 3. Fetches a remote LE (Low Energy) Bluetooth device instance.
    • + *
    • 4. Sets up a mock GATT callback for Bluetooth related events.
    • + *
    • 5. Connects to the Bumble device and verifies a successful connection.
    • + *
    • 6. Discovers the GATT services offered by Bumble and checks for a successful service + * discovery.
    • + *
    • 7. Validates the presence of the required GATT service (CCC_DK_UUID) on the Bumble + * device.
    • + *
    • 8. Disconnects from the Bumble device and ensures a successful disconnection.
    • + *
    + * + *

    + * + * @throws AssertionError if any of the assertions (like service discovery or connection checks) + * fail. + * @see BluetoothGatt + * @see BluetoothGattCallback + */ + @Test + fun testDiscoverDkGattService() { + // 1. Register Bumble's DCK (Digital Car Key) service via a gRPC call: + // - `dckBlocking()` is likely a stub that accesses the DCK service over gRPC in a + // blocking/synchronous manner. + // - `withDeadline(Deadline.after(TIMEOUT, TimeUnit.MILLISECONDS))` sets a timeout for the + // gRPC call. + // - `register(Empty.getDefaultInstance())` sends a registration request to the server. + mBumble + .dckBlocking() + .withDeadline(Deadline.after(TIMEOUT, TimeUnit.MILLISECONDS)) + .register(Empty.getDefaultInstance()) + + // 2. Advertise the host's (presumably the car's) Bluetooth capabilities using another + // gRPC call: + // - `hostBlocking()` accesses another gRPC service related to the host. + // The following `advertise(...)` sends an advertise request to the server, setting + // specific attributes. + mBumble + .hostBlocking() + .advertise( + AdvertiseRequest.newBuilder() + .setLegacy( + true + ) // As of now, Bumble only support legacy advertising (b/266124496). + .setConnectable(true) + .setOwnAddressType( + OwnAddressType.RANDOM + ) // Ask Bumble to advertise it's `RANDOM` address. + .build() + ) + + // 3. Fetch a remote Bluetooth device instance (here, Bumble). + val bumbleDevice = + bluetoothAdapter.getRemoteLeDevice( + // To keep things straightforward, the Bumble RANDOM address is set to a predefined + // constant. + // Typically, an LE scan would be conducted to identify the Bumble device, matching + // it based on its + // Advertising data. + Utils.BUMBLE_RANDOM_ADDRESS, + BluetoothDevice + .ADDRESS_TYPE_RANDOM // Specify address type as RANDOM because the device + // advertises with this address type. + ) + + // 4. Create a mock callback to handle Bluetooth GATT (Generic Attribute Profile) related + // events. + val gattCallback = mock() + + // 5. Connect to the Bumble device and expect a successful connection callback. + var bumbleGatt = bumbleDevice.connectGatt(context, false, gattCallback) + verify(gattCallback, timeout(TIMEOUT)) + .onConnectionStateChange( + any(), + eq(BluetoothGatt.GATT_SUCCESS), + eq(BluetoothProfile.STATE_CONNECTED) + ) + + // 6. Discover GATT services offered by Bumble and expect successful service discovery. + bumbleGatt.discoverServices() + verify(gattCallback, timeout(TIMEOUT)) + .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS)) + + // 7. Check if the required service (CCC_DK_UUID) is available on Bumble. + assertThat(bumbleGatt.getService(CCC_DK_UUID)).isNotNull() + + // 8. Disconnect from the Bumble device and expect a successful disconnection callback. + bumbleGatt.disconnect() + verify(gattCallback, timeout(TIMEOUT)) + .onConnectionStateChange( + any(), + eq(BluetoothGatt.GATT_SUCCESS), + eq(BluetoothProfile.STATE_DISCONNECTED) + ) + } + + companion object { + private const val TAG = "DckTest" + private const val TIMEOUT: Long = 2000 + + // CCC DK Specification R3 1.2.0 r14 section 19.2.1.2 Bluetooth Le Pairing + private val CCC_DK_UUID = UUID.fromString("0000FFF5-0000-1000-8000-00805f9b34fb") + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/DeviceDiscoveryTest.java b/framework/tests/bumble/src/android/bluetooth/DeviceDiscoveryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fc80efaac9ce130cf3a11cc7f2193cd8c56d72ee --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/DeviceDiscoveryTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.util.Log; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.compatibility.common.util.AdoptShellPermissionsRule; + +import com.google.common.util.concurrent.SettableFuture; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import pandora.HostProto.DiscoverabilityMode; +import pandora.HostProto.SetDiscoverabilityModeRequest; + +import java.util.ArrayList; + +/** Test cases for {@link DeviceDiscoveryManager}. */ +@RunWith(AndroidJUnit4.class) +public class DeviceDiscoveryTest { + private static final String TAG = "DeviceDiscoveryTest"; + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final BluetoothManager mManager = mContext.getSystemService(BluetoothManager.class); + private final BluetoothAdapter mAdapter = mManager.getAdapter(); + + private SettableFuture mFutureDiscoveryStartedIntent; + private SettableFuture mFutureDiscoveryFinishedIntent; + + @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); + + @Rule public final PandoraDevice mBumble = new PandoraDevice(); + + private ArrayList mDeviceFoundData; + + private BroadcastReceiver mConnectionStateReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) { + mFutureDiscoveryStartedIntent.set( + BluetoothAdapter.ACTION_DISCOVERY_STARTED); + } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals( + intent.getAction())) { + mFutureDiscoveryFinishedIntent.set( + BluetoothAdapter.ACTION_DISCOVERY_FINISHED); + } else if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) { + mDeviceFoundData.add(intent); + } + } + }; + + @Test + public void startDeviceDiscoveryTest() throws Exception { + mFutureDiscoveryStartedIntent = SettableFuture.create(); + mFutureDiscoveryFinishedIntent = SettableFuture.create(); + + IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED); + filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); + mContext.registerReceiver(mConnectionStateReceiver, filter); + + assertThat(mAdapter.startDiscovery()).isTrue(); + assertThat(mFutureDiscoveryStartedIntent.get()) + .isEqualTo(BluetoothAdapter.ACTION_DISCOVERY_STARTED); + + // Wait for device discovery to complete + assertThat(mFutureDiscoveryFinishedIntent.get()) + .isEqualTo(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); + + mContext.unregisterReceiver(mConnectionStateReceiver); + } + + @Test + public void cancelDeviceDiscoveryTest() throws Exception { + mFutureDiscoveryStartedIntent = SettableFuture.create(); + mFutureDiscoveryFinishedIntent = SettableFuture.create(); + + IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED); + filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); + mContext.registerReceiver(mConnectionStateReceiver, filter); + + assertThat(mAdapter.startDiscovery()).isTrue(); + assertThat(mFutureDiscoveryStartedIntent.get()) + .isEqualTo(BluetoothAdapter.ACTION_DISCOVERY_STARTED); + + // Issue a cancel discovery and wait for device discovery finished + assertThat(mAdapter.cancelDiscovery()).isTrue(); + assertThat(mFutureDiscoveryFinishedIntent.get()) + .isEqualTo(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); + + mContext.unregisterReceiver(mConnectionStateReceiver); + } + + @Test + public void checkDeviceIsDiscoveredTest() throws Exception { + mFutureDiscoveryStartedIntent = SettableFuture.create(); + mFutureDiscoveryFinishedIntent = SettableFuture.create(); + mDeviceFoundData = new ArrayList(); + + // Ensure remote device is discoverable + mBumble.hostBlocking() + .setDiscoverabilityMode( + SetDiscoverabilityModeRequest.newBuilder() + .setMode(DiscoverabilityMode.DISCOVERABLE_GENERAL) + .build()); + + IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED); + filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); + filter.addAction(BluetoothDevice.ACTION_FOUND); + mContext.registerReceiver(mConnectionStateReceiver, filter); + + assertThat(mAdapter.startDiscovery()).isTrue(); + assertThat(mFutureDiscoveryStartedIntent.get()) + .isEqualTo(BluetoothAdapter.ACTION_DISCOVERY_STARTED); + + // Wait for device discovery to complete + assertThat(mFutureDiscoveryFinishedIntent.get()) + .isEqualTo(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); + + mContext.unregisterReceiver(mConnectionStateReceiver); + + // Ensure we received at least one inquiry response + assertThat(!mDeviceFoundData.isEmpty()).isTrue(); + Log.i(TAG, "Found inquiry results count:" + mDeviceFoundData.size()); + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java new file mode 100644 index 0000000000000000000000000000000000000000..051a3e33a93dcf8b59d39c5042f77e7d81f5f4bb --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth8.assertThat; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockingDetails; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.bluetooth.le.BluetoothLeScanner; +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.compatibility.common.util.AdoptShellPermissionsRule; + +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.invocation.Invocation; + +import pandora.GattProto.GattCharacteristicParams; +import pandora.GattProto.GattServiceParams; +import pandora.GattProto.RegisterServiceRequest; +import pandora.HostProto.AdvertiseRequest; +import pandora.HostProto.AdvertiseResponse; +import pandora.HostProto.OwnAddressType; + +import java.util.Collection; +import java.util.UUID; + +@RunWith(AndroidJUnit4.class) +public class GattClientTest { + private static final String TAG = "GattClientTest"; + private static final int ANDROID_MTU = 517; + private static final int MTU_REQUESTED = 23; + private static final int ANOTHER_MTU_REQUESTED = 42; + + private static final UUID GAP_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); + + @ClassRule public static final AdoptShellPermissionsRule PERM = new AdoptShellPermissionsRule(); + + @Rule public final PandoraDevice mBumble = new PandoraDevice(); + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final BluetoothManager mManager = mContext.getSystemService(BluetoothManager.class); + private final BluetoothAdapter mAdapter = mManager.getAdapter(); + private final BluetoothLeScanner mLeScanner = mAdapter.getBluetoothLeScanner(); + + @Test + public void directConnectGattAfterClose() throws Exception { + advertiseWithBumble(); + + BluetoothDevice device = + mAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); + + for (int i = 0; i < 10; i++) { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = device.connectGatt(mContext, false, gattCallback); + gatt.close(); + + // Save the number of call in the callback to be checked later + Collection invocations = mockingDetails(gattCallback).getInvocations(); + int numberOfCalls = invocations.size(); + + BluetoothGattCallback gattCallback2 = mock(BluetoothGattCallback.class); + BluetoothGatt gatt2 = device.connectGatt(mContext, false, gattCallback2); + verify(gattCallback2, timeout(1000)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + gatt2.close(); + + // After reconnecting with the second set of callback, check that nothing happened on + // the first set of callback + Collection invocationsAfterSomeTimes = + mockingDetails(gattCallback).getInvocations(); + int numberOfCallsAfterSomeTimes = invocationsAfterSomeTimes.size(); + assertThat(numberOfCallsAfterSomeTimes).isEqualTo(numberOfCalls); + } + } + + @Test + public void fullGattClientLifecycle() throws Exception { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); + disconnectAndWaitDisconnection(gatt, gattCallback); + } + + @Test + public void reconnectExistingClient() throws Exception { + advertiseWithBumble(); + + BluetoothDevice device = + mAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + InOrder inOrder = inOrder(gattCallback); + + BluetoothGatt gatt = device.connectGatt(mContext, false, gattCallback); + inOrder.verify(gattCallback, timeout(1000)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + + gatt.disconnect(); + inOrder.verify(gattCallback, timeout(1000)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_DISCONNECTED)); + + gatt.connect(); + inOrder.verify(gattCallback, timeout(1000)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + + gatt.close(); + verifyNoMoreInteractions(gattCallback); + } + + @Test + public void clientGattDiscoverServices() throws Exception { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); + + try { + gatt.discoverServices(); + verify(gattCallback, timeout(10000)) + .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS)); + + assertThat(gatt.getServices().stream().map(BluetoothGattService::getUuid)) + .contains(GAP_UUID); + + } finally { + disconnectAndWaitDisconnection(gatt, gattCallback); + } + } + + @Test + public void clientGattReadCharacteristics() throws Exception { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); + + try { + gatt.discoverServices(); + verify(gattCallback, timeout(10000)) + .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS)); + + BluetoothGattService firstService = gatt.getServices().get(0); + + BluetoothGattCharacteristic firstCharacteristic = + firstService.getCharacteristics().get(0); + + gatt.readCharacteristic(firstCharacteristic); + + verify(gattCallback, timeout(5000)).onCharacteristicRead(any(), any(), any(), anyInt()); + + } finally { + disconnectAndWaitDisconnection(gatt, gattCallback); + } + } + + @Test + public void clientGattWriteCharacteristic() throws Exception { + registerWritableGattService(); + + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); + + try { + gatt.discoverServices(); + verify(gattCallback, timeout(10000)) + .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS)); + + BluetoothGattCharacteristic characteristic = null; + + outer: + for (BluetoothGattService candidateService : gatt.getServices()) { + for (BluetoothGattCharacteristic candidateCharacteristic : + candidateService.getCharacteristics()) { + if ((candidateCharacteristic.getProperties() + & BluetoothGattCharacteristic.PROPERTY_WRITE) + != 0) { + characteristic = candidateCharacteristic; + break outer; + } + } + } + + byte[] newValue = new byte[] {13}; + + gatt.writeCharacteristic( + characteristic, newValue, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); + + verify(gattCallback, timeout(5000)) + .onCharacteristicWrite( + any(), eq(characteristic), eq(BluetoothGatt.GATT_SUCCESS)); + + } finally { + disconnectAndWaitDisconnection(gatt, gattCallback); + } + } + + private void registerWritableGattService() { + + String characteristicUuidString = "11111111-1111-1111-1111-111111111111"; + String serviceUuidString = "00000000-0000-0000-0000-000000000000"; + + GattCharacteristicParams characteristicParams = + GattCharacteristicParams.newBuilder() + .setProperties(BluetoothGattCharacteristic.PROPERTY_WRITE) + .setUuid(characteristicUuidString) + .build(); + + GattServiceParams serviceParams = + GattServiceParams.newBuilder() + .addCharacteristics(characteristicParams) + .setUuid(serviceUuidString) + .build(); + + RegisterServiceRequest request = + RegisterServiceRequest.newBuilder().setService(serviceParams).build(); + + mBumble.gattBlocking().registerService(request); + } + + private void advertiseWithBumble() { + AdvertiseRequest request = + AdvertiseRequest.newBuilder() + .setLegacy(true) + .setConnectable(true) + .setOwnAddressType(OwnAddressType.RANDOM) + .build(); + + StreamObserverSpliterator responseObserver = + new StreamObserverSpliterator<>(); + + mBumble.host().advertise(request, responseObserver); + } + + private BluetoothGatt connectGattAndWaitConnection(BluetoothGattCallback callback) { + final int status = BluetoothGatt.GATT_SUCCESS; + final int state = BluetoothProfile.STATE_CONNECTED; + + advertiseWithBumble(); + + BluetoothDevice device = + mAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); + + BluetoothGatt gatt = device.connectGatt(mContext, false, callback); + verify(callback, timeout(1000)).onConnectionStateChange(eq(gatt), eq(status), eq(state)); + + return gatt; + } + + private void disconnectAndWaitDisconnection( + BluetoothGatt gatt, BluetoothGattCallback callback) { + final int state = BluetoothProfile.STATE_DISCONNECTED; + gatt.disconnect(); + verify(callback, timeout(1000)).onConnectionStateChange(eq(gatt), anyInt(), eq(state)); + + gatt.close(); + gatt = null; + } + + @Test + @Ignore("b/307981748: requestMTU should return a direct error") + public void requestMtu_notConnected_isFalse() { + advertiseWithBumble(); + + BluetoothDevice device = + mAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + + BluetoothGatt gatt = device.connectGatt(mContext, false, gattCallback); + // Do not wait for connection state change callback and ask MTU directly + assertThat(gatt.requestMtu(MTU_REQUESTED)).isFalse(); + } + + @Test + @Ignore("b/307981748: requestMTU should return a direct error or a error on the callback") + public void requestMtu_invalidParamer_isFalse() { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); + + try { + assertThat(gatt.requestMtu(1024)).isTrue(); + // verify(gattCallback, timeout(5000).atLeast(1)).onMtuChanged(eq(gatt), + // eq(ANDROID_MTU), eq(BluetoothGatt.GATT_FAILURE)); + } finally { + disconnectAndWaitDisconnection(gatt, gattCallback); + } + } + + @Test + public void requestMtu_once_isSuccess() { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); + + try { + assertThat(gatt.requestMtu(MTU_REQUESTED)).isTrue(); + // Check that only the ANDROID_MTU is returned, not the MTU_REQUESTED + verify(gattCallback, timeout(5000)) + .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS)); + } finally { + disconnectAndWaitDisconnection(gatt, gattCallback); + } + } + + @Test + public void requestMtu_multipleTimeFromSameClient_isRejected() { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); + + try { + assertThat(gatt.requestMtu(MTU_REQUESTED)).isTrue(); + // Check that only the ANDROID_MTU is returned, not the MTU_REQUESTED + verify(gattCallback, timeout(5000)) + .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS)); + + assertThat(gatt.requestMtu(ANOTHER_MTU_REQUESTED)).isTrue(); + verify(gattCallback, timeout(5000).times(2)) + .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS)); + } finally { + disconnectAndWaitDisconnection(gatt, gattCallback); + } + } + + @Test + public void requestMtu_onceFromMultipleClient_secondIsSuccessWithoutUpdate() { + BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); + BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); + + try { + assertThat(gatt.requestMtu(MTU_REQUESTED)).isTrue(); + verify(gattCallback, timeout(5000)) + .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS)); + + BluetoothGattCallback gattCallback2 = mock(BluetoothGattCallback.class); + BluetoothGatt gatt2 = connectGattAndWaitConnection(gattCallback2); + try { + // first callback because there is already a connected device + verify(gattCallback2, timeout(9000)) + .onMtuChanged(eq(gatt2), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS)); + assertThat(gatt2.requestMtu(ANOTHER_MTU_REQUESTED)).isTrue(); + verify(gattCallback2, timeout(9000).times(2)) + .onMtuChanged(eq(gatt2), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS)); + } finally { + disconnectAndWaitDisconnection(gatt2, gattCallback2); + } + } finally { + disconnectAndWaitDisconnection(gatt, gattCallback); + } + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/LeAdvertisingTest.java b/framework/tests/bumble/src/android/bluetooth/LeAdvertisingTest.java index be416b79471ce4416e883f201bbf7398dbb9e9c6..81f863b67a2b4fc50c1823093a45765a2ffdac73 100644 --- a/framework/tests/bumble/src/android/bluetooth/LeAdvertisingTest.java +++ b/framework/tests/bumble/src/android/bluetooth/LeAdvertisingTest.java @@ -1,8 +1,23 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.bluetooth; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothManager; -import android.bluetooth.Utils; +import static com.google.common.truth.Truth.assertThat; + import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertisingSet; import android.bluetooth.le.AdvertisingSetCallback; @@ -12,101 +27,72 @@ import android.util.Log; import androidx.core.util.Pair; import androidx.test.core.app.ApplicationProvider; -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; -import static com.google.common.truth.Truth.assertThat; -import com.google.protobuf.Empty; +import com.android.compatibility.common.util.AdoptShellPermissionsRule; -import io.grpc.Context.CancellableContext; import io.grpc.Deadline; -import io.grpc.ManagedChannel; -import io.grpc.okhttp.OkHttpChannelBuilder; -import io.grpc.stub.StreamObserver; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import pandora.HostGrpc; import pandora.HostProto.ScanRequest; import pandora.HostProto.ScanningResponse; +import java.util.Iterator; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; -/** - * Test cases for {@link AdvertiseManager}. - */ +/** Test cases for {@link AdvertiseManager}. */ @RunWith(AndroidJUnit4.class) public class LeAdvertisingTest { - - private static final String LOG_TAG = "LeAdvertisingTest"; + private static final String TAG = "LeAdvertisingTest"; private static final int TIMEOUT_ADVERTISING_MS = 1000; - private static ManagedChannel mChannel; - - private static HostGrpc.HostBlockingStub mHostBlockingStub; - - private static HostGrpc.HostStub mHostStub; - - @BeforeClass - public static void setUpClass() throws Exception { - InstrumentationRegistry.getInstrumentation().getUiAutomation() - .adoptShellPermissionIdentity(); - } - - @Before - public void setUp() throws Exception { - // FactorReset is killing the server and restart - // all channel created before the server restarted - // cannot be reused - ManagedChannel channel = OkHttpChannelBuilder - .forAddress("localhost", 7999) - .usePlaintext() - .build(); - - HostGrpc.HostBlockingStub stub = HostGrpc.newBlockingStub(channel); - stub.factoryReset(Empty.getDefaultInstance()); - - // terminate the channel - channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); - - // Create a new channel for all successive grpc calls - mChannel = OkHttpChannelBuilder - .forAddress("localhost", 7999) - .usePlaintext() - .build(); - - mHostBlockingStub = HostGrpc.newBlockingStub(mChannel); - mHostStub = HostGrpc.newStub(mChannel); - mHostBlockingStub.withWaitForReady().readLocalAddress(Empty.getDefaultInstance()); - } + @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); - @After - public void tearDown() throws Exception { - // terminate the channel - mChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS); - } + @Rule public final PandoraDevice mBumble = new PandoraDevice(); @Test public void advertisingSet() throws Exception { - ScanningResponse response = startAdvertising() - .thenCompose(advAddressPair -> scanWithBumble(advAddressPair)) - .join(); + Pair addressPair = startAdvertising().join(); + ScanningResponse response = scanWithBumble(addressPair); - Log.i(LOG_TAG, "scan response: " + response); + Log.i(TAG, "scan response: " + response); assertThat(response).isNotNull(); } + private ScanningResponse scanWithBumble(Pair addressPair) { + Log.d(TAG, "scanWithBumble"); + String address = addressPair.first; + int addressType = addressPair.second; + + StreamObserverSpliterator responseObserver = + new StreamObserverSpliterator<>(); + Deadline deadline = Deadline.after(TIMEOUT_ADVERTISING_MS, TimeUnit.MILLISECONDS); + mBumble.host() + .withDeadline(deadline) + .scan(ScanRequest.newBuilder().build(), responseObserver); + Iterator responseObserverIterator = responseObserver.iterator(); + while (true) { + ScanningResponse scanningResponse = responseObserverIterator.next(); + String addr = + Utils.addressStringFromByteString( + addressType == AdvertisingSetParameters.ADDRESS_TYPE_PUBLIC + ? scanningResponse.getPublic() + : scanningResponse.getRandom()); + + if (addr.equals(address)) { + return scanningResponse; + } + } + } + private CompletableFuture> startAdvertising() { CompletableFuture> future = - new CompletableFuture>(); + new CompletableFuture>(); android.content.Context context = ApplicationProvider.getApplicationContext(); BluetoothManager bluetoothManager = context.getSystemService(BluetoothManager.class); @@ -114,83 +100,56 @@ public class LeAdvertisingTest { // Start advertising BluetoothLeAdvertiser leAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser(); - AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder(). - setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM).build(); + AdvertisingSetParameters parameters = + new AdvertisingSetParameters.Builder() + .setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_RANDOM) + .build(); AdvertiseData advertiseData = new AdvertiseData.Builder().build(); AdvertiseData scanResponse = new AdvertiseData.Builder().build(); - AdvertisingSetCallback advertisingSetCallback = new AdvertisingSetCallback() { - @Override - public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, - int status) { - Log.i(LOG_TAG, "onAdvertisingSetStarted " + " txPower:" + txPower - + " status:" + status); - advertisingSet.enableAdvertising(true, TIMEOUT_ADVERTISING_MS, 0); - } - @Override - public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, - String address) { - Log.i(LOG_TAG, "onOwnAddressRead " + " addressType:" + addressType - + " address:" + address); - future.complete(new Pair(address, addressType)); - } - @Override - public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enabled, - int status) { - Log.i(LOG_TAG, "onAdvertisingEnabled " + " enabled:" + enabled - + " status:" + status); - advertisingSet.getOwnAddress(); - } - }; - leAdvertiser.startAdvertisingSet(parameters, advertiseData, scanResponse, - null, null, 0, 0, advertisingSetCallback); + AdvertisingSetCallback advertisingSetCallback = + new AdvertisingSetCallback() { + @Override + public void onAdvertisingSetStarted( + AdvertisingSet advertisingSet, int txPower, int status) { + Log.i( + TAG, + "onAdvertisingSetStarted " + + " txPower:" + + txPower + + " status:" + + status); + advertisingSet.enableAdvertising(true, TIMEOUT_ADVERTISING_MS, 0); + } + + @Override + public void onOwnAddressRead( + AdvertisingSet advertisingSet, int addressType, String address) { + Log.i( + TAG, + "onOwnAddressRead " + + " addressType:" + + addressType + + " address:" + + address); + future.complete(new Pair(address, addressType)); + } + + @Override + public void onAdvertisingEnabled( + AdvertisingSet advertisingSet, boolean enabled, int status) { + Log.i( + TAG, + "onAdvertisingEnabled " + + " enabled:" + + enabled + + " status:" + + status); + advertisingSet.getOwnAddress(); + } + }; + leAdvertiser.startAdvertisingSet( + parameters, advertiseData, scanResponse, null, null, 0, 0, advertisingSetCallback); return future; } - - private CompletableFuture scanWithBumble(Pair addressPair) { - final CompletableFuture future = - new CompletableFuture(); - CancellableContext withCancellation = io.grpc.Context.current().withCancellation(); - - String address = addressPair.first; - int addressType = addressPair.second; - - ScanRequest request = ScanRequest.newBuilder().build(); - StreamObserver responseObserver = new StreamObserver(){ - public void onNext(ScanningResponse response) { - String addr = ""; - if (addressType == AdvertisingSetParameters.ADDRESS_TYPE_PUBLIC) { - addr = Utils.addressStringFromByteString(response.getPublic()); - } - else { - addr = Utils.addressStringFromByteString(response.getRandom()); - } - Log.i(LOG_TAG,"scan observer: scan response address: " + addr); - - if (addr.equals(address)) { - future.complete(response); - } - } - - @Override - public void onError(Throwable e) { - Log.e(LOG_TAG,"scan observer: on error " + e); - future.completeExceptionally(e); - } - - @Override - public void onCompleted() { - Log.i(LOG_TAG,"scan observer: on completed"); - future.complete(null); - } - }; - - Deadline initialDeadline = Deadline.after(TIMEOUT_ADVERTISING_MS, TimeUnit.MILLISECONDS); - withCancellation.run(() -> mHostStub.withDeadline(initialDeadline) - .scan(request, responseObserver)); - - return future.whenComplete((input, exception) -> { - withCancellation.cancel(null); - }); - } } diff --git a/framework/tests/bumble/src/android/bluetooth/LeScanningTest.java b/framework/tests/bumble/src/android/bluetooth/LeScanningTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3f0b38668c108daf49c3237dfea3b050ded2dd78 --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/LeScanningTest.java @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import static com.google.common.io.BaseEncoding.base16; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.after; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + +import android.app.PendingIntent; +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanFilter; +import android.bluetooth.le.ScanResult; +import android.bluetooth.le.ScanSettings; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.ParcelUuid; +import android.util.Log; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.compatibility.common.util.AdoptShellPermissionsRule; + +import com.google.protobuf.ByteString; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +import pandora.HostProto; +import pandora.HostProto.AdvertiseRequest; +import pandora.HostProto.AdvertiseResponse; +import pandora.HostProto.OwnAddressType; + +@RunWith(AndroidJUnit4.class) +public class LeScanningTest { + private static final String TAG = "LeScanningTest"; + private static final int TIMEOUT_SCANNING_MS = 2000; + + @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); + + @Rule public final PandoraDevice mBumble = new PandoraDevice(); + + private static final String TEST_ADDRESS_RANDOM_STATIC = "F0:43:A8:23:10:11"; + + // IRK must match what's defined in bumble_config.json + private static final byte[] TEST_IRK = base16().decode("1F66F4B5F0C742F807DD0DDBF64E9213"); + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final BluetoothManager mBluetoothManager = + mContext.getSystemService(BluetoothManager.class); + private final BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter(); + private final BluetoothLeScanner mLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); + + private static final String TEST_UUID_STRING = "00001805-0000-1000-8000-00805f9b34fb"; + + private static final String ACTION_DYNAMIC_RECEIVER_SCAN_RESULT = + "android.bluetooth.test.ACTION_DYNAMIC_RECEIVER_SCAN_RESULT"; + + @Test + public void startBleScan_withCallbackTypeAllMatches() { + advertiseWithBumble(TEST_UUID_STRING, OwnAddressType.PUBLIC); + + ScanFilter scanFilter = + new ScanFilter.Builder() + .setServiceUuid(ParcelUuid.fromString(TEST_UUID_STRING)) + .build(); + + List results = + startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); + + assertThat(results).isNotNull(); + assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)) + .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); + assertThat(results.get(1).getScanRecord().getServiceUuids().get(0)) + .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); + } + + @Test + public void scanForIrkIdentityAddress_withCallbackTypeAllMatches() { + advertiseWithBumble(null, OwnAddressType.RANDOM); + + ScanFilter scanFilter = + new ScanFilter.Builder() + .setDeviceAddress( + TEST_ADDRESS_RANDOM_STATIC, + BluetoothDevice.ADDRESS_TYPE_RANDOM, + TEST_IRK) + .build(); + + List results = + startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); + + assertThat(results).isNotEmpty(); + assertThat(results.get(0).getDevice().getAddress()).isEqualTo(TEST_ADDRESS_RANDOM_STATIC); + } + + @Test + public void startBleScan_withCallbackTypeFirstMatchSilentlyFails() { + advertiseWithBumble(TEST_UUID_STRING, OwnAddressType.PUBLIC); + + ScanSettings scanSettings = + new ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH) + .build(); + + ScanFilter scanFilter = + new ScanFilter.Builder() + .setServiceUuid(ParcelUuid.fromString(TEST_UUID_STRING)) + .build(); + + ScanCallback mockScanCallback = mock(ScanCallback.class); + + mLeScanner.startScan(List.of(scanFilter), scanSettings, mockScanCallback); + verify(mockScanCallback, after(TIMEOUT_SCANNING_MS).never()).onScanFailed(anyInt()); + mLeScanner.stopScan(mockScanCallback); + } + + @Test + public void startBleScan_withCallbackTypeMatchLostSilentlyFails() { + advertiseWithBumble(TEST_UUID_STRING, OwnAddressType.PUBLIC); + + ScanSettings scanSettings = + new ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setCallbackType(ScanSettings.CALLBACK_TYPE_MATCH_LOST) + .build(); + + ScanFilter scanFilter = + new ScanFilter.Builder() + .setServiceUuid(ParcelUuid.fromString(TEST_UUID_STRING)) + .build(); + + ScanCallback mockScanCallback = mock(ScanCallback.class); + + mLeScanner.startScan(List.of(scanFilter), scanSettings, mockScanCallback); + verify(mockScanCallback, after(TIMEOUT_SCANNING_MS).never()).onScanFailed(anyInt()); + mLeScanner.stopScan(mockScanCallback); + } + + @Test + public void startBleScan_withPendingIntentAndDynamicReceiverAndCallbackTypeAllMatches() { + BroadcastReceiver mockReceiver = mock(BroadcastReceiver.class); + IntentFilter intentFilter = new IntentFilter(ACTION_DYNAMIC_RECEIVER_SCAN_RESULT); + mContext.registerReceiver(mockReceiver, intentFilter); + + advertiseWithBumble(TEST_UUID_STRING, OwnAddressType.PUBLIC); + + ScanSettings scanSettings = + new ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .build(); + + ScanFilter scanFilter = + new ScanFilter.Builder() + .setServiceUuid(ParcelUuid.fromString(TEST_UUID_STRING)) + .build(); + + // NOTE: Intent.setClass() must not be called, or else scan results won't be received. + Intent scanIntent = new Intent(ACTION_DYNAMIC_RECEIVER_SCAN_RESULT); + PendingIntent pendingIntent = + PendingIntent.getBroadcast( + mContext, 0, scanIntent, PendingIntent.FLAG_CANCEL_CURRENT); + + mLeScanner.startScan(List.of(scanFilter), scanSettings, pendingIntent); + + ArgumentCaptor intent = ArgumentCaptor.forClass(Intent.class); + verify(mockReceiver, timeout(TIMEOUT_SCANNING_MS)).onReceive(any(), intent.capture()); + + mLeScanner.stopScan(pendingIntent); + mContext.unregisterReceiver(mockReceiver); + + assertThat(intent.getValue().getAction()).isEqualTo(ACTION_DYNAMIC_RECEIVER_SCAN_RESULT); + assertThat(intent.getValue().getIntExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, -1)) + .isEqualTo(ScanSettings.CALLBACK_TYPE_ALL_MATCHES); + + List results = + intent.getValue() + .getParcelableArrayListExtra( + BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT, ScanResult.class); + assertThat(results).isNotEmpty(); + assertThat(results.get(0).getScanRecord().getServiceUuids()).isNotEmpty(); + assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)) + .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); + assertThat(results.get(0).getScanRecord().getServiceUuids()) + .containsExactly(ParcelUuid.fromString(TEST_UUID_STRING)); + } + + @Test + public void startBleScan_withPendingIntentAndStaticReceiverAndCallbackTypeAllMatches() { + advertiseWithBumble(TEST_UUID_STRING, OwnAddressType.PUBLIC); + + ScanSettings scanSettings = + new ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .build(); + + ArrayList scanFilters = new ArrayList<>(); + ScanFilter scanFilter = + new ScanFilter.Builder() + .setServiceUuid(ParcelUuid.fromString(TEST_UUID_STRING)) + .build(); + scanFilters.add(scanFilter); + + PendingIntent pendingIntent = + PendingIntentScanReceiver.newBroadcastPendingIntent(mContext, 0); + + mLeScanner.startScan(scanFilters, scanSettings, pendingIntent); + List results = + PendingIntentScanReceiver.nextScanResult() + .completeOnTimeout(null, TIMEOUT_SCANNING_MS, TimeUnit.MILLISECONDS) + .join(); + mLeScanner.stopScan(pendingIntent); + PendingIntentScanReceiver.resetNextScanResultFuture(); + + assertThat(results).isNotEmpty(); + assertThat(results.get(0).getScanRecord().getServiceUuids()).isNotEmpty(); + assertThat(results.get(0).getScanRecord().getServiceUuids()) + .containsExactly(ParcelUuid.fromString(TEST_UUID_STRING)); + } + + @Test + public void startBleScan_oneTooManyScansFails() { + final int maxNumScans = 32; + advertiseWithBumble(TEST_UUID_STRING, OwnAddressType.PUBLIC); + + ScanSettings scanSettings = + new ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .build(); + + ScanFilter scanFilter = + new ScanFilter.Builder() + .setServiceUuid(ParcelUuid.fromString(TEST_UUID_STRING)) + .build(); + + List scanCallbacks = + Stream.generate(() -> mock(ScanCallback.class)).limit(maxNumScans).toList(); + for (ScanCallback mockScanCallback : scanCallbacks) { + mLeScanner.startScan(List.of(scanFilter), scanSettings, mockScanCallback); + } + // This last scan should fail + ScanCallback lastMockScanCallback = mock(ScanCallback.class); + mLeScanner.startScan(List.of(scanFilter), scanSettings, lastMockScanCallback); + + // We expect an error only for the last scan, which was over the maximum active scans limit. + for (ScanCallback mockScanCallback : scanCallbacks) { + verify(mockScanCallback, timeout(TIMEOUT_SCANNING_MS).atLeast(1)) + .onScanResult(eq(ScanSettings.CALLBACK_TYPE_ALL_MATCHES), any()); + verify(mockScanCallback, never()).onScanFailed(anyInt()); + mLeScanner.stopScan(mockScanCallback); + } + verify(lastMockScanCallback, timeout(TIMEOUT_SCANNING_MS)) + .onScanFailed(eq(ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED)); + mLeScanner.stopScan(lastMockScanCallback); + } + + @Test + public void startBleScan_withNonConnectablePublicAdvertisement() { + AdvertiseRequest.Builder requestBuilder = + AdvertiseRequest.newBuilder() + .setConnectable(false) + .setOwnAddressType(OwnAddressType.PUBLIC); + advertiseWithBumble(requestBuilder); + + ScanFilter scanFilter = + new ScanFilter.Builder() + .setDeviceAddress(mBumble.getRemoteDevice().getAddress()) + .build(); + + List results = + startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); + + assertThat(results).isNotNull(); + assertThat(results.get(0).isConnectable()).isFalse(); + assertThat(results.get(1).isConnectable()).isFalse(); + } + + @Test + public void startBleScan_withNonConnectableScannablePublicAdvertisement() { + byte[] payload = {0x02, 0x03}; + // first 2 bytes are the manufacturer ID 0x00E0 (Google) in little endian + byte[] manufacturerData = {(byte) 0xE0, 0x00, payload[0], payload[1]}; + HostProto.DataTypes.Builder scanResponse = + HostProto.DataTypes.newBuilder() + .setManufacturerSpecificData(ByteString.copyFrom(manufacturerData)); + + AdvertiseRequest.Builder requestBuilder = + AdvertiseRequest.newBuilder() + .setConnectable(false) + .setOwnAddressType(OwnAddressType.PUBLIC) + .setScanResponseData(scanResponse); + advertiseWithBumble(requestBuilder); + + ScanFilter scanFilter = + new ScanFilter.Builder() + .setDeviceAddress(mBumble.getRemoteDevice().getAddress()) + .build(); + + List results = + startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); + + assertThat(results).isNotNull(); + assertThat(results.get(0).isConnectable()).isFalse(); + assertThat(results.get(0).getScanRecord().getManufacturerSpecificData(0x00E0)) + .isEqualTo(payload); + } + + private List startScanning(ScanFilter scanFilter, int callbackType) { + CompletableFuture> future = new CompletableFuture<>(); + List scanResults = new ArrayList<>(); + + ScanSettings scanSettings = + new ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setCallbackType(callbackType) + .build(); + + ScanCallback scanCallback = + new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + Log.i( + TAG, + "onScanResult " + + "address: " + + result.getDevice().getAddress() + + ", connectable: " + + result.isConnectable() + + ", callbackType: " + + callbackType + + ", service uuids: " + + result.getScanRecord().getServiceUuids()); + + if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { + if (scanResults.size() < 2) { + scanResults.add(result); + } else { + future.complete(scanResults); + } + } else { + scanResults.add(result); + future.complete(scanResults); + } + } + + @Override + public void onScanFailed(int errorCode) { + Log.i(TAG, "onScanFailed " + "errorCode: " + errorCode); + future.complete(null); + } + }; + + mLeScanner.startScan(List.of(scanFilter), scanSettings, scanCallback); + + List result = + future.completeOnTimeout(null, TIMEOUT_SCANNING_MS, TimeUnit.MILLISECONDS).join(); + + mLeScanner.stopScan(scanCallback); + + return result; + } + + private void advertiseWithBumble(String serviceUuid, OwnAddressType addressType) { + AdvertiseRequest.Builder requestBuilder = + AdvertiseRequest.newBuilder().setOwnAddressType(addressType); + + if (serviceUuid != null) { + HostProto.DataTypes.Builder dataTypeBuilder = HostProto.DataTypes.newBuilder(); + dataTypeBuilder.addCompleteServiceClassUuids128(serviceUuid); + requestBuilder.setData(dataTypeBuilder.build()); + } + + advertiseWithBumble(requestBuilder); + } + + private void advertiseWithBumble(AdvertiseRequest.Builder requestBuilder) { + // Bumble currently only supports legacy advertising. + requestBuilder.setLegacy(true); + // Collect and ignore responses. + StreamObserverSpliterator responseObserver = + new StreamObserverSpliterator<>(); + mBumble.host().advertise(requestBuilder.build(), responseObserver); + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/PairingTest.java b/framework/tests/bumble/src/android/bluetooth/PairingTest.java new file mode 100644 index 0000000000000000000000000000000000000000..847d78d68ff2665128386dd396662fba70dcbbda --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/PairingTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +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.inOrder; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.bluetooth.test_utils.EnableBluetoothRule; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.compatibility.common.util.AdoptShellPermissionsRule; + +import io.grpc.stub.StreamObserver; + +import org.hamcrest.Matcher; +import org.hamcrest.core.AllOf; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.hamcrest.MockitoHamcrest; + +import pandora.SecurityProto.PairingEvent; +import pandora.SecurityProto.PairingEventAnswer; + +import java.time.Duration; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class PairingTest { + private static final Duration BOND_INTENT_TIMEOUT = Duration.ofSeconds(10); + + private static final Context sTargetContext = + InstrumentationRegistry.getInstrumentation().getTargetContext(); + private static final BluetoothAdapter sAdapter = + sTargetContext.getSystemService(BluetoothManager.class).getAdapter(); + + @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); + + @Rule public final PandoraDevice mBumble = new PandoraDevice(); + + @Rule + public final EnableBluetoothRule mEnableBluetoothRule = + new EnableBluetoothRule(false /* enableTestMode */, true /* toggleBluetooth */); + + @Mock private BroadcastReceiver mReceiver; + private InOrder mInOrder = null; + private BluetoothDevice mBumbleDevice; + + private final StreamObserverSpliterator mPairingEventStreamObserver = + new StreamObserverSpliterator<>(); + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mInOrder = inOrder(mReceiver); + + IntentFilter filter = new IntentFilter(); + filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST); + sTargetContext.registerReceiver(mReceiver, filter); + + mBumbleDevice = mBumble.getRemoteDevice(); + Set bondedDevices = sAdapter.getBondedDevices(); + if (bondedDevices.contains(mBumbleDevice)) { + removeBond(mBumbleDevice); + } + } + + @After + public void tearDown() throws Exception { + Set bondedDevices = sAdapter.getBondedDevices(); + if (bondedDevices.contains(mBumbleDevice)) { + removeBond(mBumbleDevice); + } + mBumbleDevice = null; + sTargetContext.unregisterReceiver(mReceiver); + } + + /** + * Test a simple BR/EDR just works pairing flow in the follow steps: + * + *
      + *
    1. 1. Bumble resets, enables inquiry and page scan, and sets I/O cap to no display no + * input + *
    2. 2. Android connects to Bumble via its MAC address + *
    3. 3. Android tries to create bond, emitting bonding intent 4. Android confirms the + * pairing via pairing request intent + *
    4. 5. Bumble confirms the pairing internally (optional, added only for test confirmation) + *
    5. 6. Android verifies bonded intent + *
    + */ + @Test + public void testBrEdrPairing_phoneInitiatedBrEdrInquiryOnlyJustWorks() { + StreamObserver pairingEventAnswerObserver = + mBumble.security() + .withDeadlineAfter(BOND_INTENT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS) + .onPairing(mPairingEventStreamObserver); + + assertThat(mBumbleDevice.createBond()).isTrue(); + verifyIntentReceived( + hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED), + hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice), + hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING)); + + verifyIntentReceived( + hasAction(BluetoothDevice.ACTION_PAIRING_REQUEST), + hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice), + hasExtra( + BluetoothDevice.EXTRA_PAIRING_VARIANT, + BluetoothDevice.PAIRING_VARIANT_CONSENT)); + mBumbleDevice.setPairingConfirmation(true); + + PairingEvent pairingEvent = mPairingEventStreamObserver.iterator().next(); + assertThat(pairingEvent.hasJustWorks()).isTrue(); + pairingEventAnswerObserver.onNext( + PairingEventAnswer.newBuilder().setEvent(pairingEvent).setConfirm(true).build()); + + verifyIntentReceived( + hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED), + hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice), + hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED)); + + verifyNoMoreInteractions(mReceiver); + } + + private void removeBond(BluetoothDevice device) { + assertThat(device.removeBond()).isTrue(); + verifyIntentReceived( + hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED), + hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice), + hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE)); + verifyNoMoreInteractions(mReceiver); + } + + @SafeVarargs + private void verifyIntentReceived(Matcher... matchers) { + mInOrder.verify(mReceiver, timeout(BOND_INTENT_TIMEOUT.toMillis())) + .onReceive(any(Context.class), MockitoHamcrest.argThat(AllOf.allOf(matchers))); + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/PandoraDevice.java b/framework/tests/bumble/src/android/bluetooth/PandoraDevice.java new file mode 100644 index 0000000000000000000000000000000000000000..a03115aae34c74cf77819ed5e3a9ff7c6270853a --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/PandoraDevice.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import android.util.Log; + +import androidx.test.core.app.ApplicationProvider; + +import com.google.protobuf.Empty; + +import io.grpc.ManagedChannel; +import io.grpc.okhttp.OkHttpChannelBuilder; + +import org.junit.rules.ExternalResource; + +import pandora.DckGrpc; +import pandora.GATTGrpc; +import pandora.HostGrpc; +import pandora.HostProto; +import pandora.SecurityGrpc; + +import java.util.concurrent.TimeUnit; + +public final class PandoraDevice extends ExternalResource { + private static final String TAG = PandoraDevice.class.getSimpleName(); + private final String mNetworkAddress; + private String mPublicBluetoothAddress; + private final int mPort; + private ManagedChannel mChannel; + + public PandoraDevice(String networkAddress, int port) { + mNetworkAddress = networkAddress; + mPort = port; + } + + public PandoraDevice() { + this("localhost", 7999); + } + + @Override + protected void before() { + Log.i(TAG, "factoryReset"); + // FactoryReset is killing the server and restarting all channels created before the server + // restarted that cannot be reused + ManagedChannel channel = + OkHttpChannelBuilder.forAddress(mNetworkAddress, mPort).usePlaintext().build(); + HostGrpc.HostBlockingStub stub = HostGrpc.newBlockingStub(channel); + stub.factoryReset(Empty.getDefaultInstance()); + try { + // terminate the channel + channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + mChannel = OkHttpChannelBuilder.forAddress(mNetworkAddress, mPort).usePlaintext().build(); + stub = HostGrpc.newBlockingStub(mChannel); + HostProto.ReadLocalAddressResponse readLocalAddressResponse = + stub.withWaitForReady().readLocalAddress(Empty.getDefaultInstance()); + mPublicBluetoothAddress = + Utils.addressStringFromByteString(readLocalAddressResponse.getAddress()); + } + + @Override + protected void after() { + Log.i(TAG, "shutdown"); + try { + // terminate the channel + mChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS); + mChannel = null; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + /** + * @return bumble as a remote device + */ + public BluetoothDevice getRemoteDevice() { + return ApplicationProvider.getApplicationContext() + .getSystemService(BluetoothManager.class) + .getAdapter() + .getRemoteDevice(mPublicBluetoothAddress); + } + + /** Get Pandora Host service */ + public HostGrpc.HostStub host() { + return HostGrpc.newStub(mChannel); + } + + /** Get Pandora Host service */ + public HostGrpc.HostBlockingStub hostBlocking() { + return HostGrpc.newBlockingStub(mChannel); + } + + /** Get Pandora Dck service */ + public DckGrpc.DckStub dck() { + return DckGrpc.newStub(mChannel); + } + + /** Get Pandora Dck blocking service */ + public DckGrpc.DckBlockingStub dckBlocking() { + return DckGrpc.newBlockingStub(mChannel); + } + + /** Get Pandora Security service */ + public SecurityGrpc.SecurityStub security() { + return SecurityGrpc.newStub(mChannel); + } + + /** Get Pandora GATT service */ + public GATTGrpc.GATTStub gatt() { + return GATTGrpc.newStub(mChannel); + } + + /** Get Pandora GATT blocking service */ + public GATTGrpc.GATTBlockingStub gattBlocking() { + return GATTGrpc.newBlockingStub(mChannel); + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/PendingIntentScanReceiver.java b/framework/tests/bumble/src/android/bluetooth/PendingIntentScanReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..14af1d08af0d48e5e657257d33b4e2b9f13d58e5 --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/PendingIntentScanReceiver.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import android.app.PendingIntent; +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanResult; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +/** + * PendingIntentScanReceiver is registered statically in the manifest file as a BroadcastReceiver + * for the android.bluetooth.ACTION_SCAN_RESULT action. Tests can use nextScanResult() to get a + * future that completes when scan results are next delivered. + */ +public class PendingIntentScanReceiver extends BroadcastReceiver { + private static final String TAG = "PendingIntentScanReceiver"; + + public static final String ACTION_SCAN_RESULT = "android.bluetooth.test.ACTION_SCAN_RESULT"; + + private static Optional>> sNextScanResultFuture = + Optional.empty(); + + /** + * Constructs a new Intent associated with this class. + * + * @param context The context the to associate with the Intent. + * @return The new Intent. + */ + private static Intent newIntent(Context context) { + Intent intent = new Intent(); + intent.setAction(PendingIntentScanReceiver.ACTION_SCAN_RESULT); + intent.setClass(context, PendingIntentScanReceiver.class); + return intent; + } + + /** + * Constructs a new PendingIntent associated with this class. + * + * @param context The context to associate the PendingIntent with. + * @param requestCode The request code to uniquely identify this PendingIntent with. + * @return + */ + public static PendingIntent newBroadcastPendingIntent(Context context, int requestCode) { + return PendingIntent.getBroadcast( + context, requestCode, newIntent(context), PendingIntent.FLAG_CANCEL_CURRENT); + } + + /** + * Use this method for statically registered receivers. + * + * @return A future that will complete when the next scan result is received. + */ + public static CompletableFuture> nextScanResult() + throws IllegalStateException { + if (sNextScanResultFuture.isPresent()) { + throw new IllegalStateException("scan result future already set"); + } + sNextScanResultFuture = Optional.of(new CompletableFuture>()); + return sNextScanResultFuture.get(); + } + + /** Clears the future waiting for the next static receiver scan result, if any. */ + public static void resetNextScanResultFuture() { + sNextScanResultFuture = Optional.empty(); + } + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceive() intent: " + intent); + + if (intent.getAction() != ACTION_SCAN_RESULT) { + throw new RuntimeException(); + } + + int errorCode = intent.getIntExtra(BluetoothLeScanner.EXTRA_ERROR_CODE, 0); + if (errorCode != 0) { + Log.e(TAG, "onReceive() error: " + errorCode); + throw new RuntimeException("onReceive() unexpected error: " + errorCode); + } + + List scanResults = + intent.getParcelableExtra( + BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT, + new ArrayList().getClass()); + + if (sNextScanResultFuture.isPresent()) { + sNextScanResultFuture.get().complete(scanResults); + sNextScanResultFuture = Optional.empty(); + } else { + throw new IllegalStateException("scan result received but no future set"); + } + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/SdpClientTest.java b/framework/tests/bumble/src/android/bluetooth/SdpClientTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c4238ceea4ea070c4e62220883db72977e72762b --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/SdpClientTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.ParcelUuid; +import android.os.Parcelable; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.compatibility.common.util.AdoptShellPermissionsRule; + +import com.google.common.util.concurrent.SettableFuture; +import com.google.protobuf.ByteString; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import pandora.HostProto.ConnectRequest; +import pandora.HostProto.WaitConnectionRequest; + +import java.util.ArrayList; +import java.util.UUID; + +/** Test cases for {@link ServiceDiscoveryManager}. */ +@RunWith(AndroidJUnit4.class) +public class SdpClientTest { + private static final String TAG = "SdpClientTest"; + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final BluetoothManager mManager = mContext.getSystemService(BluetoothManager.class); + private final BluetoothAdapter mAdapter = mManager.getAdapter(); + + private SettableFuture> mFutureIntent; + + @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); + + @Rule public final PandoraDevice mBumble = new PandoraDevice(); + + private BroadcastReceiver mConnectionStateReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (BluetoothDevice.ACTION_UUID.equals(intent.getAction())) { + Parcelable[] parcelable = + (Parcelable[]) intent.getExtra(BluetoothDevice.EXTRA_UUID); + if (parcelable != null) { + ArrayList list = new ArrayList(); + for (Parcelable p : parcelable) { + ParcelUuid uuid = (ParcelUuid) p; + list.add(uuid.getUuid()); + } + mFutureIntent.set(list); + } + } + } + }; + + @Test + public void remoteConnectServiceDiscoveryTest() throws Exception { + IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_UUID); + mContext.registerReceiver(mConnectionStateReceiver, filter); + + mFutureIntent = SettableFuture.create(); + + String local_addr = mAdapter.getAddress(); + byte[] local_bytes_addr = Utils.addressBytesFromString(local_addr); + + // Initiate connect from remote + mBumble.hostBlocking() + .connect( + ConnectRequest.newBuilder() + .setAddress(ByteString.copyFrom(local_bytes_addr)) + .build()); + + // Wait until connection is stable + mBumble.hostBlocking() + .waitConnection( + WaitConnectionRequest.newBuilder() + .setAddress(ByteString.copyFrom(local_bytes_addr)) + .build()); + + // Get the remote device + BluetoothDevice device = mBumble.getRemoteDevice(); + + // Execute service discovery procedure + assertThat(device.fetchUuidsWithSdp()).isTrue(); + + ArrayList list = mFutureIntent.get(); + assertThat(list.isEmpty()).isFalse(); + + mContext.unregisterReceiver(mConnectionStateReceiver); + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/StreamObserverSpliterator.java b/framework/tests/bumble/src/android/bluetooth/StreamObserverSpliterator.java new file mode 100644 index 0000000000000000000000000000000000000000..e8739068bb277602e3dec80c95876a5e40885f7d --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/StreamObserverSpliterator.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import io.grpc.stub.StreamObserver; + +import java.util.Iterator; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.function.Consumer; + +public class StreamObserverSpliterator implements Spliterator, StreamObserver { + private BlockingQueue mQueue = new LinkedBlockingQueue<>(); + private static final Object COMPLETED_INDICATOR = new Object(); + + /** + * Creates and returns an iterator over the elements contained in the internal blocking queue. + * + *

    The iterator is based on this class's Spliterator implementation. As elements are consumed + * from the iterator, they are removed from the queue. The iterator continues to provide + * elements as long as new items are added to the queue via the onNext method or until the + * onCompleted method is called. + * + *

    If the onError method was called previously and the corresponding Throwable is retrieved + * by the iterator, it will throw a RuntimeException wrapping the original Throwable. + * + * @return an iterator over the elements contained in the internal blocking queue + */ + public Iterator iterator() { + return Spliterators.iterator(this); + } + + @Override + public int characteristics() { + return ORDERED | NONNULL; + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + + @Override + public boolean tryAdvance(Consumer action) { + try { + Object item = mQueue.take(); + if (item == COMPLETED_INDICATOR) { + return false; + } + if (item instanceof Throwable) { + throw new RuntimeException((Throwable) item); + } + action.accept((T) item); + return true; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Override + public Spliterator trySplit() { + return null; + } + + @Override + public void onNext(T value) { + mQueue.add(value); + } + + @Override + public void onError(Throwable t) { + mQueue.add(t); + } + + @Override + public void onCompleted() { + mQueue.add(COMPLETED_INDICATOR); + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/Utils.java b/framework/tests/bumble/src/android/bluetooth/Utils.java index 8ee7f536a84d5f4e299bb47d0c48937083e442bc..09e32814cf44a71d652ae04bb98c1b96f726bb4e 100644 --- a/framework/tests/bumble/src/android/bluetooth/Utils.java +++ b/framework/tests/bumble/src/android/bluetooth/Utils.java @@ -1,16 +1,46 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.bluetooth; +import static com.google.common.io.BaseEncoding.base16; + import com.google.protobuf.ByteString; +import java.util.Locale; + public final class Utils { + public static final String BUMBLE_RANDOM_ADDRESS = "51:F7:A8:75:AC:5E"; + public static String addressStringFromByteString(ByteString bs) { StringBuilder refAddrBuilder = new StringBuilder(); for (int i = 0; i < bs.size(); i++) { if (i != 0) { - refAddrBuilder.append(':'); + refAddrBuilder.append(':'); } refAddrBuilder.append(String.format("%02X", bs.byteAt(i))); } return refAddrBuilder.toString(); } + + /** + * @param address String representing Bluetooth address (case insensitive). + * @return Decoded address. + */ + public static byte[] addressBytesFromString(String address) { + return base16().upperCase().withSeparator(":", 2).decode(address.toUpperCase(Locale.US)); + } } diff --git a/framework/tests/bumble/src/bumble_server.py b/framework/tests/bumble/src/bumble_server.py new file mode 100644 index 0000000000000000000000000000000000000000..ccdc25ed79523b929cea47d1b3b07f94a4217fac --- /dev/null +++ b/framework/tests/bumble/src/bumble_server.py @@ -0,0 +1,80 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import asyncio +import click +import logging +import json + +from bumble import pandora as bumble_server +from bumble.pandora import PandoraDevice, Config, serve + +from bumble_experimental.asha import AshaService +from bumble_experimental.dck import DckService +from bumble_experimental.gatt import GATTService + +from pandora_experimental.asha_grpc_aio import add_AshaServicer_to_server +from pandora_experimental.dck_grpc_aio import add_DckServicer_to_server +from pandora_experimental.gatt_grpc_aio import add_GATTServicer_to_server + +from typing import Dict, Any + +BUMBLE_SERVER_GRPC_PORT = 7999 +ROOTCANAL_PORT_CUTTLEFISH = 7300 + + +@click.command() +@click.option('--grpc-port', help='gRPC port to serve', default=BUMBLE_SERVER_GRPC_PORT) +@click.option('--rootcanal-port', help='Rootcanal TCP port', default=ROOTCANAL_PORT_CUTTLEFISH) +@click.option( + '--transport', + help='HCI transport', + default=f'tcp-client:127.0.0.1:', +) +@click.option( + '--config', + help='Bumble json configuration file', +) +def main(grpc_port: int, rootcanal_port: int, transport: str, config: str) -> None: + bumble_server.register_servicer_hook( + lambda bumble, _, server: add_AshaServicer_to_server(AshaService(bumble.device), server)) + bumble_server.register_servicer_hook( + lambda bumble, _, server: add_DckServicer_to_server(DckService(bumble.device), server)) + bumble_server.register_servicer_hook( + lambda bumble, _, server: add_GATTServicer_to_server(GATTService(bumble.device), server)) + + if '' in transport: + transport = transport.replace('', str(rootcanal_port)) + + bumble_config = retrieve_config(config) + bumble_config.setdefault('transport', transport) + device = PandoraDevice(bumble_config) + + server_config = Config() + server_config.load_from_dict(bumble_config.get('server', {})) + + logging.basicConfig(level=logging.DEBUG) + asyncio.run(serve(device, config=server_config, port=grpc_port)) + + +def retrieve_config(config: str) -> Dict[str, Any]: + if not config: + return {} + + with open(config, 'r') as f: + return json.load(f) + + +if __name__ == '__main__': + main() # pylint: disable=no-value-for-parameter diff --git a/framework/tests/metrics/OWNERS b/framework/tests/metrics/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..01d41baf7edd03d2404c12e15ef9bf7c8fd54be0 --- /dev/null +++ b/framework/tests/metrics/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 1099313 +# Project owners +ahujapalash@google.com diff --git a/framework/tests/metrics/device/Android.bp b/framework/tests/metrics/device/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..3f0ac4ceb1415bbe27ca95608eb2f9f6975df2ac --- /dev/null +++ b/framework/tests/metrics/device/Android.bp @@ -0,0 +1,46 @@ +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"], +} + +android_test_helper_app { + name: "BluetoothMetricsTestApp", + + min_sdk_version: "current", + target_sdk_version: "current", + libs: [ + "libprotobuf-java-micro", + + "framework", + "framework-bluetooth.impl", + "framework-res", + ], + + static_libs: [ + "PandoraServerLib", + "androidx.core_core", + "androidx.test.ext.junit", + "androidx.test.ext.truth", + "androidx.test.rules", + "grpc-java-lite", + "grpc-java-okhttp-client-lite", + "kotlinx_coroutines_test", + "opencensus-java-contrib-grpc-metrics", + "pandora_experimental-grpc-java", + "pandora_experimental-proto-java", + ], + + // Include all test java files. + srcs: [ + "**/*.kt", + ], + + platform_apis: true, + test_suites: [ + "general-tests", + ], +} diff --git a/framework/tests/metrics/device/AndroidManifest.xml b/framework/tests/metrics/device/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..7b050509b7a70561cbd081df555464bf77d87f4b --- /dev/null +++ b/framework/tests/metrics/device/AndroidManifest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/framework/tests/metrics/device/android/bluetooth/BluetoothMetricsHelperTest.kt b/framework/tests/metrics/device/android/bluetooth/BluetoothMetricsHelperTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..e105366e4d239770ca86ed285164b8dd014ce543 --- /dev/null +++ b/framework/tests/metrics/device/android/bluetooth/BluetoothMetricsHelperTest.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth + +import android.content.Intent +import android.content.IntentFilter +import android.net.MacAddress +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.android.pandora.intentFlow +import com.google.common.truth.Truth.assertThat +import com.google.protobuf.ByteString +import com.google.protobuf.Empty +import io.grpc.ManagedChannel +import io.grpc.okhttp.OkHttpChannelBuilder +import java.util.concurrent.TimeUnit +import kotlinx.coroutines.async +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.shareIn +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Test +import org.junit.runner.RunWith +import pandora.HostGrpc +import pandora.HostProto.ConnectRequest +import pandora.HostProto.DisconnectRequest + +@kotlinx.coroutines.ExperimentalCoroutinesApi +@RunWith(AndroidJUnit4::class) +class BluetoothMetricsHelperTest { + + companion object { + private const val TAG = "BluetoothMetricsHelperTest" + + private lateinit var mChannel: ManagedChannel + private lateinit var mHostBlockingStub: HostGrpc.HostBlockingStub + private lateinit var mHostStub: HostGrpc.HostStub + + @BeforeClass + fun setUpClass() { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity() + } + } + + private val testDispatcher = UnconfinedTestDispatcher() + private val testScope = TestScope(testDispatcher) + private val context = InstrumentationRegistry.getInstrumentation().getContext() + private val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java)!!.adapter + + @Before + fun setUp() { + val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation() + // Adopt all the permissions of the shell + uiAutomation.adoptShellPermissionIdentity() + + // FactorReset is killing the server and restart + // all channel created before the server restarted + // cannot be reused + val channel = OkHttpChannelBuilder.forAddress("localhost", 7999).usePlaintext().build() + + HostGrpc.newBlockingStub(channel).factoryReset(Empty.getDefaultInstance()) + + // terminate the channel + channel.shutdown().awaitTermination(1, TimeUnit.SECONDS) + + // Create a new channel for all successive grpc calls + mChannel = OkHttpChannelBuilder.forAddress("localhost", 7999).usePlaintext().build() + + mHostBlockingStub = HostGrpc.newBlockingStub(mChannel) + mHostStub = HostGrpc.newStub(mChannel) + mHostBlockingStub.withWaitForReady()?.readLocalAddress(Empty.getDefaultInstance()) + } + + @After + fun tearDown() { + // terminate the channel + mChannel.shutdown()?.awaitTermination(1, TimeUnit.SECONDS) + } + + @Test + fun incomingClassicConnectionTest() = runTest { + val intentFilter = IntentFilter() + intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED) + intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED) + val flow: Flow = + intentFlow(context, intentFilter, testScope).shareIn(testScope, SharingStarted.Eagerly) + + val incomingConnection = async { + flow + .filter { it.action == BluetoothDevice.ACTION_ACL_CONNECTED } + .filter { + it.getIntExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.ERROR) == + BluetoothDevice.TRANSPORT_BREDR + } + .first() + } + + val localMacAddress = MacAddress.fromString(bluetoothAdapter.getAddress()) + val connectRequest = + ConnectRequest.newBuilder() + .setAddress(ByteString.copyFrom(localMacAddress.toByteArray())) + .build() + val connectResponse = mHostBlockingStub.connect(connectRequest) + assertThat(connectResponse).isNotNull() + assertThat(connectResponse.hasConnection()).isTrue() + incomingConnection.await() + + val disconnectRequest = + DisconnectRequest.newBuilder().setConnection(connectResponse.connection).build() + mHostBlockingStub.disconnect(disconnectRequest) + } +} diff --git a/framework/tests/metrics/host/Android.bp b/framework/tests/metrics/host/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..818e88ac4054909e3d927a5eed6a11986060bd4b --- /dev/null +++ b/framework/tests/metrics/host/Android.bp @@ -0,0 +1,28 @@ +// This empty test host is needed for building required host binary +// "bumble_pandora_server" and include it in test zip +java_test_host { + name: "BluetoothMetricsTests", + + srcs: [ + "**/*.kt", + ], + + static_libs: [ + "cts-statsd-atom-host-test-utils", + "platformprotos", + ], + + libs: [ + "tradefed", + ], + + data: [ + ":BluetoothMetricsTestApp", + ], + + required: ["bumble_pandora_server"], + + test_suites: [ + "general-tests", + ], +} diff --git a/framework/tests/metrics/host/AndroidTest.xml b/framework/tests/metrics/host/AndroidTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..860fb0a02066d8052270245962ce215927fba54a --- /dev/null +++ b/framework/tests/metrics/host/AndroidTest.xml @@ -0,0 +1,31 @@ + + + + diff --git a/framework/tests/metrics/host/android/bluetooth/MetricsTest.kt b/framework/tests/metrics/host/android/bluetooth/MetricsTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..a8c0674da6b14e067cff09dad29bcfd265e6c430 --- /dev/null +++ b/framework/tests/metrics/host/android/bluetooth/MetricsTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth + +import android.cts.statsdatom.lib.ConfigUtils +import android.cts.statsdatom.lib.DeviceUtils +import android.cts.statsdatom.lib.ReportUtils +import com.android.os.AtomsProto +import com.android.os.StatsLog +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(DeviceJUnit4ClassRunner::class) +class MetricsTest : BaseHostJUnit4Test() { + + companion object { + private const val TAG = "BluetoothMetricsTests" + private const val TEST_APP_PKG_NAME = "android.bluetooth" + private const val TEST_APP_CLASS_NAME = ".BluetoothMetricsHelperTest" + } + + @Before + fun setUp() { + ConfigUtils.removeConfig(getDevice()) + ReportUtils.clearReports(getDevice()) + } + + @Test + fun aclMetricTest() { + val data = uploadAtomConfigAndTriggerTest("incomingClassicConnectionTest") + assertThat(data.size).isAtLeast(2) + val atom1 = data.get(0).getAtom().getBluetoothAclConnectionStateChanged() + assertThat(atom1.getState()).isEqualTo(ConnectionStateEnum.CONNECTION_STATE_CONNECTED) + assertThat(atom1.getTransport()).isEqualTo(TransportTypeEnum.TRANSPORT_TYPE_BREDR) + val atom2 = data.get(1).getAtom().getBluetoothAclConnectionStateChanged() + assertThat(atom2.getState()).isEqualTo(ConnectionStateEnum.CONNECTION_STATE_DISCONNECTED) + assertThat(atom2.getTransport()).isEqualTo(TransportTypeEnum.TRANSPORT_TYPE_BREDR) + assertThat(atom2.getMetricId()).isEqualTo(atom1.getMetricId()) + } + + private fun uploadAtomConfigAndTriggerTest(testName: String): List { + val device = getDevice() + ConfigUtils.uploadConfigForPushedAtoms( + device, + TEST_APP_PKG_NAME, + intArrayOf(AtomsProto.Atom.BLUETOOTH_ACL_CONNECTION_STATE_CHANGED_FIELD_NUMBER) + ) + + DeviceUtils.runDeviceTests(device, TEST_APP_PKG_NAME, TEST_APP_CLASS_NAME, testName) + + return ReportUtils.getEventMetricDataList(device) + } +} diff --git a/framework/tests/stress/src/android/bluetooth/BluetoothInstrumentation.java b/framework/tests/stress/src/android/bluetooth/BluetoothInstrumentation.java index f438592a19557119aa66bb458f04e9909e090a8c..554c76b9e1aaa9804249be42384953daa640aaef 100644 --- a/framework/tests/stress/src/android/bluetooth/BluetoothInstrumentation.java +++ b/framework/tests/stress/src/android/bluetooth/BluetoothInstrumentation.java @@ -31,16 +31,18 @@ public class BluetoothInstrumentation extends Instrumentation { private BluetoothTestUtils getBluetoothTestUtils() { if (mUtils == null) { - mUtils = new BluetoothTestUtils(getContext(), - BluetoothInstrumentation.class.getSimpleName()); + mUtils = + new BluetoothTestUtils( + getContext(), BluetoothInstrumentation.class.getSimpleName()); } return mUtils; } private BluetoothAdapter getBluetoothAdapter() { if (mAdapter == null) { - mAdapter = ((BluetoothManager) getContext().getSystemService( - Context.BLUETOOTH_SERVICE)).getAdapter(); + mAdapter = + ((BluetoothManager) getContext().getSystemService(Context.BLUETOOTH_SERVICE)) + .getAdapter(); } return mAdapter; } diff --git a/framework/tests/stress/src/android/bluetooth/BluetoothRebootStressTest.java b/framework/tests/stress/src/android/bluetooth/BluetoothRebootStressTest.java index 33e9dd7fabc6c8460655c168bdcca027323a8b85..d98955a703a6ed1b603a8e43edf9b8a4671c39b5 100644 --- a/framework/tests/stress/src/android/bluetooth/BluetoothRebootStressTest.java +++ b/framework/tests/stress/src/android/bluetooth/BluetoothRebootStressTest.java @@ -21,10 +21,9 @@ import android.test.InstrumentationTestCase; /** * Instrumentation test case for stress test involving rebooting the device. - *

    - * This test case tests that bluetooth is enabled after a device reboot. Because - * the device will reboot, the instrumentation must be driven by a script on the - * host side. + * + *

    This test case tests that bluetooth is enabled after a device reboot. Because the device will + * reboot, the instrumentation must be driven by a script on the host side. */ public class BluetoothRebootStressTest extends InstrumentationTestCase { private static final String TAG = "BluetoothRebootStressTest"; @@ -47,18 +46,16 @@ public class BluetoothRebootStressTest extends InstrumentationTestCase { mTestUtils.close(); } - /** - * Test method used to start the test by turning bluetooth on. - */ + /** Test method used to start the test by turning bluetooth on. */ public void testStart() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); mTestUtils.enable(adapter); } /** - * Test method used in the middle iterations of the test to check if - * bluetooth is on. Does not toggle bluetooth after the check. Assumes that - * bluetooth has been turned on by {@code #testStart()} + * Test method used in the middle iterations of the test to check if bluetooth is on. Does not + * toggle bluetooth after the check. Assumes that bluetooth has been turned on by {@code + * #testStart()} */ public void testMiddleNoToggle() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); @@ -67,9 +64,8 @@ public class BluetoothRebootStressTest extends InstrumentationTestCase { } /** - * Test method used in the middle iterations of the test to check if - * bluetooth is on. Toggles bluetooth after the check. Assumes that - * bluetooth has been turned on by {@code #testStart()} + * Test method used in the middle iterations of the test to check if bluetooth is on. Toggles + * bluetooth after the check. Assumes that bluetooth has been turned on by {@code #testStart()} */ public void testMiddleToggle() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); @@ -81,8 +77,8 @@ public class BluetoothRebootStressTest extends InstrumentationTestCase { } /** - * Test method used in the stop the test by turning bluetooth off. Assumes - * that bluetooth has been turned on by {@code #testStart()} + * Test method used in the stop the test by turning bluetooth off. Assumes that bluetooth has + * been turned on by {@code #testStart()} */ public void testStop() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); diff --git a/framework/tests/stress/src/android/bluetooth/BluetoothStressTest.java b/framework/tests/stress/src/android/bluetooth/BluetoothStressTest.java index 89dbe3f75b56f9d9deab04e2f1c0ab6ff3666c20..fb002225d3eb8a65731294c3254935153330ecc9 100644 --- a/framework/tests/stress/src/android/bluetooth/BluetoothStressTest.java +++ b/framework/tests/stress/src/android/bluetooth/BluetoothStressTest.java @@ -22,16 +22,17 @@ import android.test.InstrumentationTestCase; /** * Stress test suite for Bluetooth related functions. * - * Includes tests for enabling/disabling bluetooth, enabling/disabling discoverable mode, + *

    Includes tests for enabling/disabling bluetooth, enabling/disabling discoverable mode, * starting/stopping scans, connecting/disconnecting to HFP, A2DP, HID, PAN profiles, and verifying * that remote connections/disconnections occur for the PAN profile. - *

    - * This test suite uses {@link android.bluetooth.BluetoothTestRunner} to for parameters such as the - * number of iterations and the addresses of remote Bluetooth devices. + * + *

    This test suite uses {@link android.bluetooth.BluetoothTestRunner} to for parameters such as + * the number of iterations and the addresses of remote Bluetooth devices. */ public class BluetoothStressTest extends InstrumentationTestCase { private static final String TAG = "BluetoothStressTest"; private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt"; + /** The amount of time to sleep between issuing start/stop SCO in ms. */ private static final long SCO_SLEEP_TIME = 2 * 1000; @@ -58,9 +59,7 @@ public class BluetoothStressTest extends InstrumentationTestCase { mTestUtils.close(); } - /** - * Stress test for enabling and disabling Bluetooth. - */ + /** Stress test for enabling and disabling Bluetooth. */ public void testEnable() { int iterations = BluetoothTestRunner.sEnableIterations; if (iterations == 0) { @@ -74,9 +73,7 @@ public class BluetoothStressTest extends InstrumentationTestCase { } } - /** - * Stress test for putting the device in and taking the device out of discoverable mode. - */ + /** Stress test for putting the device in and taking the device out of discoverable mode. */ public void testDiscoverable() { int iterations = BluetoothTestRunner.sDiscoverableIterations; if (iterations == 0) { @@ -93,9 +90,7 @@ public class BluetoothStressTest extends InstrumentationTestCase { } } - /** - * Stress test for starting and stopping Bluetooth scans. - */ + /** Stress test for starting and stopping Bluetooth scans. */ public void testScan() { int iterations = BluetoothTestRunner.sScanIterations; if (iterations == 0) { @@ -112,9 +107,7 @@ public class BluetoothStressTest extends InstrumentationTestCase { } } - /** - * Stress test for enabling and disabling the PAN NAP profile. - */ + /** Stress test for enabling and disabling the PAN NAP profile. */ public void testEnablePan() { int iterations = BluetoothTestRunner.sEnablePanIterations; if (iterations == 0) { @@ -125,8 +118,7 @@ public class BluetoothStressTest extends InstrumentationTestCase { mTestUtils.disablePan(mAdapter); for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of " - + iterations); + mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of " + iterations); mTestUtils.enablePan(mAdapter); mTestUtils.disablePan(mAdapter); } @@ -134,9 +126,9 @@ public class BluetoothStressTest extends InstrumentationTestCase { /** * Stress test for pairing and unpairing with a remote device. - *

    - * In this test, the local device initiates pairing with a remote device, and then unpairs with - * the device after the pairing has successfully completed. + * + *

    In this test, the local device initiates pairing with a remote device, and then unpairs + * with the device after the pairing has successfully completed. */ public void testPair() { int iterations = BluetoothTestRunner.sPairIterations; @@ -150,7 +142,10 @@ public class BluetoothStressTest extends InstrumentationTestCase { for (int i = 0; i < iterations; i++) { mTestUtils.writeOutput("pair iteration " + (i + 1) + " of " + iterations); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, + mTestUtils.pair( + mAdapter, + device, + BluetoothTestRunner.sDevicePairPasskey, BluetoothTestRunner.sDevicePairPin); mTestUtils.unpair(mAdapter, device); } @@ -158,9 +153,9 @@ public class BluetoothStressTest extends InstrumentationTestCase { /** * Stress test for accepting a pairing request and unpairing with a remote device. - *

    - * In this test, the local device waits for a pairing request from a remote device. It accepts - * the request and then unpairs after the paring has successfully completed. + * + *

    In this test, the local device waits for a pairing request from a remote device. It + * accepts the request and then unpairs after the paring has successfully completed. */ public void testAcceptPair() { int iterations = BluetoothTestRunner.sPairIterations; @@ -173,7 +168,10 @@ public class BluetoothStressTest extends InstrumentationTestCase { for (int i = 0; i < iterations; i++) { mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations); - mTestUtils.acceptPair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, + mTestUtils.acceptPair( + mAdapter, + device, + BluetoothTestRunner.sDevicePairPasskey, BluetoothTestRunner.sDevicePairPin); mTestUtils.unpair(mAdapter, device); } @@ -181,9 +179,9 @@ public class BluetoothStressTest extends InstrumentationTestCase { /** * Stress test for connecting and disconnecting with an A2DP source. - *

    - * In this test, the local device plays the role of an A2DP sink, and initiates connections and - * disconnections with an A2DP source. + * + *

    In this test, the local device plays the role of an A2DP sink, and initiates connections + * and disconnections with an A2DP source. */ public void testConnectA2dp() { int iterations = BluetoothTestRunner.sConnectA2dpIterations; @@ -194,15 +192,24 @@ public class BluetoothStressTest extends InstrumentationTestCase { BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); mTestUtils.enable(mAdapter); mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, + mTestUtils.pair( + mAdapter, + device, + BluetoothTestRunner.sDevicePairPasskey, BluetoothTestRunner.sDevicePairPin); mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.A2DP, null); for (int i = 0; i < iterations; i++) { mTestUtils.writeOutput("connectA2dp iteration " + (i + 1) + " of " + iterations); - mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.A2DP, + mTestUtils.connectProfile( + mAdapter, + device, + BluetoothProfile.A2DP, String.format("connectA2dp(device=%s)", device)); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.A2DP, + mTestUtils.disconnectProfile( + mAdapter, + device, + BluetoothProfile.A2DP, String.format("disconnectA2dp(device=%s)", device)); } @@ -211,8 +218,8 @@ public class BluetoothStressTest extends InstrumentationTestCase { /** * Stress test for connecting and disconnecting the HFP with a hands free device. - *

    - * In this test, the local device plays the role of an HFP audio gateway, and initiates + * + *

    In this test, the local device plays the role of an HFP audio gateway, and initiates * connections and disconnections with a hands free device. */ public void testConnectHeadset() { @@ -224,15 +231,24 @@ public class BluetoothStressTest extends InstrumentationTestCase { BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); mTestUtils.enable(mAdapter); mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, + mTestUtils.pair( + mAdapter, + device, + BluetoothTestRunner.sDevicePairPasskey, BluetoothTestRunner.sDevicePairPin); mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null); for (int i = 0; i < iterations; i++) { mTestUtils.writeOutput("connectHeadset iteration " + (i + 1) + " of " + iterations); - mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HEADSET, + mTestUtils.connectProfile( + mAdapter, + device, + BluetoothProfile.HEADSET, String.format("connectHeadset(device=%s)", device)); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, + mTestUtils.disconnectProfile( + mAdapter, + device, + BluetoothProfile.HEADSET, String.format("disconnectHeadset(device=%s)", device)); } @@ -241,8 +257,8 @@ public class BluetoothStressTest extends InstrumentationTestCase { /** * Stress test for connecting and disconnecting with a HID device. - *

    - * In this test, the local device plays the role of a HID host, and initiates connections and + * + *

    In this test, the local device plays the role of a HID host, and initiates connections and * disconnections with a HID device. */ public void testConnectInput() { @@ -254,15 +270,24 @@ public class BluetoothStressTest extends InstrumentationTestCase { BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); mTestUtils.enable(mAdapter); mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, + mTestUtils.pair( + mAdapter, + device, + BluetoothTestRunner.sDevicePairPasskey, BluetoothTestRunner.sDevicePairPin); mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HID_HOST, null); for (int i = 0; i < iterations; i++) { mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations); - mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HID_HOST, + mTestUtils.connectProfile( + mAdapter, + device, + BluetoothProfile.HID_HOST, String.format("connectInput(device=%s)", device)); - mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HID_HOST, + mTestUtils.disconnectProfile( + mAdapter, + device, + BluetoothProfile.HID_HOST, String.format("disconnectInput(device=%s)", device)); } @@ -271,8 +296,8 @@ public class BluetoothStressTest extends InstrumentationTestCase { /** * Stress test for connecting and disconnecting with a PAN NAP. - *

    - * In this test, the local device plays the role of a PANU, and initiates connections and + * + *

    In this test, the local device plays the role of a PANU, and initiates connections and * disconnections with a NAP. */ public void testConnectPan() { @@ -284,7 +309,10 @@ public class BluetoothStressTest extends InstrumentationTestCase { BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); mTestUtils.enable(mAdapter); mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, + mTestUtils.pair( + mAdapter, + device, + BluetoothTestRunner.sDevicePairPasskey, BluetoothTestRunner.sDevicePairPin); for (int i = 0; i < iterations; i++) { @@ -298,8 +326,8 @@ public class BluetoothStressTest extends InstrumentationTestCase { /** * Stress test for verifying a PANU connecting and disconnecting with the device. - *

    - * In this test, the local device plays the role of a NAP which a remote PANU connects and + * + *

    In this test, the local device plays the role of a NAP which a remote PANU connects and * disconnects from. */ public void testIncomingPanConnection() { @@ -313,12 +341,15 @@ public class BluetoothStressTest extends InstrumentationTestCase { mTestUtils.disablePan(mAdapter); mTestUtils.enablePan(mAdapter); mTestUtils.unpair(mAdapter, device); - mTestUtils.acceptPair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, + mTestUtils.acceptPair( + mAdapter, + device, + BluetoothTestRunner.sDevicePairPasskey, BluetoothTestRunner.sDevicePairPin); for (int i = 0; i < iterations; i++) { - mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of " - + iterations); + mTestUtils.writeOutput( + "incomingPanConnection iteration " + (i + 1) + " of " + iterations); mTestUtils.incomingPanConnection(mAdapter, device); mTestUtils.incomingPanDisconnection(mAdapter, device); } @@ -329,9 +360,9 @@ public class BluetoothStressTest extends InstrumentationTestCase { /** * Stress test for verifying that AudioManager can open and close SCO connections. - *

    - * In this test, a HSP connection is opened with an external headset and the SCO connection is - * repeatibly opened and closed. + * + *

    In this test, a HSP connection is opened with an external headset and the SCO connection + * is repeatibly opened and closed. */ public void testStartStopSco() { int iterations = BluetoothTestRunner.sStartStopScoIterations; @@ -342,7 +373,10 @@ public class BluetoothStressTest extends InstrumentationTestCase { BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); mTestUtils.enable(mAdapter); mTestUtils.unpair(mAdapter, device); - mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey, + mTestUtils.pair( + mAdapter, + device, + BluetoothTestRunner.sDevicePairPasskey, BluetoothTestRunner.sDevicePairPin); mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null); mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HEADSET, null); @@ -378,9 +412,9 @@ public class BluetoothStressTest extends InstrumentationTestCase { } /** - * It is hard to find device to support set undeleted status, so just - * set deleted in 1 iteration - **/ + * It is hard to find device to support set undeleted status, so just set deleted in 1 + * iteration + */ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.DELETED); } diff --git a/framework/tests/stress/src/android/bluetooth/BluetoothTestRunner.java b/framework/tests/stress/src/android/bluetooth/BluetoothTestRunner.java index 905d6baf5becf00062e10cffbe2a09c3a6e8b48a..adce2df0d1319bf0db00a44171d0665c501eb12e 100644 --- a/framework/tests/stress/src/android/bluetooth/BluetoothTestRunner.java +++ b/framework/tests/stress/src/android/bluetooth/BluetoothTestRunner.java @@ -25,10 +25,10 @@ import junit.framework.TestSuite; /** * Instrumentation test runner for Bluetooth tests. - *

    - * To run: - *

    - * {@code
    + *
    + * 

    To run: + * + *

    {@code
      * adb shell am instrument \
      *     [-e enable_iterations ] \
      *     [-e discoverable_iterations ] \
    @@ -49,8 +49,7 @@ import junit.framework.TestSuite;
      *     [-e pair_pin ] \
      *     [-e pair_passkey ] \
      *     -w com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner
    - * }
    - * 
    + * }
    */ public class BluetoothTestRunner extends InstrumentationTestRunner { private static final String TAG = "BluetoothTestRunner"; diff --git a/framework/tests/stress/src/android/bluetooth/BluetoothTestUtils.java b/framework/tests/stress/src/android/bluetooth/BluetoothTestUtils.java index ac25923621653869be7de2cfc48c8b413ca5b2c0..f2d19f0a0b909af50c60275c256d0bb819a45b57 100644 --- a/framework/tests/stress/src/android/bluetooth/BluetoothTestUtils.java +++ b/framework/tests/stress/src/android/bluetooth/BluetoothTestUtils.java @@ -43,22 +43,31 @@ public class BluetoothTestUtils extends Assert { /** Timeout for enable/disable in ms. */ private static final int ENABLE_DISABLE_TIMEOUT = 20000; + /** Timeout for discoverable/undiscoverable in ms. */ private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000; + /** Timeout for starting/stopping a scan in ms. */ private static final int START_STOP_SCAN_TIMEOUT = 5000; + /** Timeout for pair/unpair in ms. */ private static final int PAIR_UNPAIR_TIMEOUT = 20000; + /** Timeout for connecting/disconnecting a profile in ms. */ private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000; + /** Timeout to start or stop a SCO channel in ms. */ private static final int START_STOP_SCO_TIMEOUT = 10000; + /** Timeout to connect a profile proxy in ms. */ private static final int CONNECT_PROXY_TIMEOUT = 5000; + /** Time between polls in ms. */ private static final int POLL_TIME = 100; + /** Timeout to get map message in ms. */ private static final int GET_UNREAD_MESSAGE_TIMEOUT = 10000; + /** Timeout to set map message status in ms. */ private static final int SET_MESSAGE_STATUS_TIMEOUT = 2000; @@ -175,9 +184,9 @@ public class BluetoothTestUtils extends Assert { } if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) { - int varient = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1); - assertNotSame(-1, varient); - switch (varient) { + int variant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1); + assertNotSame(-1, variant); + switch (variant) { case BluetoothDevice.PAIRING_VARIANT_PIN: case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS: mDevice.setPin(mPin); @@ -303,10 +312,12 @@ public class BluetoothTestUtils extends Assert { @Override public void onReceive(Context context, Intent intent) { if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(intent.getAction())) { - int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, - AudioManager.SCO_AUDIO_STATE_ERROR); + int state = + intent.getIntExtra( + AudioManager.EXTRA_SCO_AUDIO_STATE, + AudioManager.SCO_AUDIO_STATE_ERROR); assertNotSame(AudioManager.SCO_AUDIO_STATE_ERROR, state); - switch(state) { + switch (state) { case AudioManager.SCO_AUDIO_STATE_CONNECTED: setFiredFlag(STATE_CONNECTED_FLAG); break; @@ -318,7 +329,6 @@ public class BluetoothTestUtils extends Assert { } } - private class MceSetMessageStatusReceiver extends FlagReceiver { private static final int MESSAGE_RECEIVED_FLAG = 1; private static final int STATUS_CHANGED_FLAG = 1 << 1; @@ -334,16 +344,20 @@ public class BluetoothTestUtils extends Assert { assertNotNull(handle); setFiredFlag(MESSAGE_RECEIVED_FLAG); mMsgHandle = handle; - } else if (BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED - .equals(intent.getAction())) { - int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, - BluetoothMapClient.RESULT_FAILURE); + } else if (BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED.equals( + intent.getAction())) { + int result = + intent.getIntExtra( + BluetoothMapClient.EXTRA_RESULT_CODE, + BluetoothMapClient.RESULT_FAILURE); assertEquals(result, BluetoothMapClient.RESULT_SUCCESS); setFiredFlag(STATUS_CHANGED_FLAG); - } else if (BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED - .equals(intent.getAction())) { - int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, - BluetoothMapClient.RESULT_FAILURE); + } else if (BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED.equals( + intent.getAction())) { + int result = + intent.getIntExtra( + BluetoothMapClient.EXTRA_RESULT_CODE, + BluetoothMapClient.RESULT_FAILURE); assertEquals(result, BluetoothMapClient.RESULT_SUCCESS); setFiredFlag(STATUS_CHANGED_FLAG); } @@ -352,52 +366,52 @@ public class BluetoothTestUtils extends Assert { private BluetoothProfile.ServiceListener mServiceListener = new BluetoothProfile.ServiceListener() { - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - synchronized (this) { - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = (BluetoothA2dp) proxy; - break; - case BluetoothProfile.HEADSET: - mHeadset = (BluetoothHeadset) proxy; - break; - case BluetoothProfile.HID_HOST: - mInput = (BluetoothHidHost) proxy; - break; - case BluetoothProfile.PAN: - mPan = (BluetoothPan) proxy; - break; - case BluetoothProfile.MAP_CLIENT: - mMce = (BluetoothMapClient) proxy; - break; + @Override + public void onServiceConnected(int profile, BluetoothProfile proxy) { + synchronized (this) { + switch (profile) { + case BluetoothProfile.A2DP: + mA2dp = (BluetoothA2dp) proxy; + break; + case BluetoothProfile.HEADSET: + mHeadset = (BluetoothHeadset) proxy; + break; + case BluetoothProfile.HID_HOST: + mInput = (BluetoothHidHost) proxy; + break; + case BluetoothProfile.PAN: + mPan = (BluetoothPan) proxy; + break; + case BluetoothProfile.MAP_CLIENT: + mMce = (BluetoothMapClient) proxy; + break; + } + } } - } - } - @Override - public void onServiceDisconnected(int profile) { - synchronized (this) { - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = null; - break; - case BluetoothProfile.HEADSET: - mHeadset = null; - break; - case BluetoothProfile.HID_HOST: - mInput = null; - break; - case BluetoothProfile.PAN: - mPan = null; - break; - case BluetoothProfile.MAP_CLIENT: - mMce = null; - break; + @Override + public void onServiceDisconnected(int profile) { + synchronized (this) { + switch (profile) { + case BluetoothProfile.A2DP: + mA2dp = null; + break; + case BluetoothProfile.HEADSET: + mHeadset = null; + break; + case BluetoothProfile.HID_HOST: + mInput = null; + break; + case BluetoothProfile.PAN: + mPan = null; + break; + case BluetoothProfile.MAP_CLIENT: + mMce = null; + break; + } + } } - } - } - }; + }; private List mReceivers = new ArrayList(); @@ -430,8 +444,8 @@ public class BluetoothTestUtils extends Assert { * * @param context The context of the application using the utility. * @param tag The log tag of the application using the utility. - * @param outputFile The path to an output file if the utility is to write results to a - * separate file. + * @param outputFile The path to an output file if the utility is to write results to a separate + * file. */ public BluetoothTestUtils(Context context, String tag, String outputFile) { mContext = context; @@ -442,8 +456,13 @@ public class BluetoothTestUtils extends Assert { mOutputWriter = null; } else { try { - mOutputWriter = new BufferedWriter(new FileWriter(new File( - Environment.getExternalStorageDirectory(), mOutputFile), true)); + mOutputWriter = + new BufferedWriter( + new FileWriter( + new File( + Environment.getExternalStorageDirectory(), + mOutputFile), + true)); } catch (IOException e) { Log.w(mTag, "Test output file could not be opened", e); mOutputWriter = null; @@ -451,9 +470,7 @@ public class BluetoothTestUtils extends Assert { } } - /** - * Closes the utility instance and unregisters any BroadcastReceivers. - */ + /** Closes the utility instance and unregisters any BroadcastReceivers. */ public void close() { while (!mReceivers.isEmpty()) { mContext.unregisterReceiver(mReceivers.remove(0)); @@ -479,20 +496,22 @@ public class BluetoothTestUtils extends Assert { assertFalse(adapter.isEnabled()); int btState = adapter.getState(); final Semaphore completionSemaphore = new Semaphore(0); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { - return; - } - final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, - BluetoothAdapter.ERROR); - if (state == BluetoothAdapter.STATE_ON) { - completionSemaphore.release(); - } - } - }; + final BroadcastReceiver receiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { + return; + } + final int state = + intent.getIntExtra( + BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); + if (state == BluetoothAdapter.STATE_ON) { + completionSemaphore.release(); + } + } + }; final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); @@ -510,8 +529,10 @@ public class BluetoothTestUtils extends Assert { } mContext.unregisterReceiver(receiver); if (!success) { - fail(String.format("enable() timeout: state=%d (expected %d)", btState, - BluetoothAdapter.STATE_ON)); + fail( + String.format( + "enable() timeout: state=%d (expected %d)", + btState, BluetoothAdapter.STATE_ON)); } } @@ -526,20 +547,22 @@ public class BluetoothTestUtils extends Assert { assertTrue(adapter.isEnabled()); int btState = adapter.getState(); final Semaphore completionSemaphore = new Semaphore(0); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { - return; - } - final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, - BluetoothAdapter.ERROR); - if (state == BluetoothAdapter.STATE_OFF) { - completionSemaphore.release(); - } - } - }; + final BroadcastReceiver receiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { + return; + } + final int state = + intent.getIntExtra( + BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); + if (state == BluetoothAdapter.STATE_OFF) { + completionSemaphore.release(); + } + } + }; final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); @@ -557,14 +580,16 @@ public class BluetoothTestUtils extends Assert { } mContext.unregisterReceiver(receiver); if (!success) { - fail(String.format("disable() timeout: state=%d (expected %d)", btState, - BluetoothAdapter.STATE_OFF)); + fail( + String.format( + "disable() timeout: state=%d (expected %d)", + btState, BluetoothAdapter.STATE_OFF)); } } /** - * Puts the local device into discoverable mode and checks to make sure that the local device - * is in discoverable mode and that the correct actions were broadcast. + * Puts the local device into discoverable mode and checks to make sure that the local device is + * in discoverable mode and that the correct actions were broadcast. * * @param adapter The BT adapter. */ @@ -579,44 +604,51 @@ public class BluetoothTestUtils extends Assert { } final Semaphore completionSemaphore = new Semaphore(0); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) { - return; - } - final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, - BluetoothAdapter.SCAN_MODE_NONE); - if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { - completionSemaphore.release(); - } - } - }; + final BroadcastReceiver receiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) { + return; + } + final int mode = + intent.getIntExtra( + BluetoothAdapter.EXTRA_SCAN_MODE, + BluetoothAdapter.SCAN_MODE_NONE); + if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { + completionSemaphore.release(); + } + } + }; final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(receiver, filter); - assertEquals(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE), + assertEquals( + adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE), BluetoothStatusCodes.SUCCESS); boolean success = false; try { - success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, - TimeUnit.MILLISECONDS); + success = + completionSemaphore.tryAcquire( + DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, TimeUnit.MILLISECONDS); writeOutput(String.format("discoverable() completed in 0 ms")); } catch (final InterruptedException e) { // This should never happen but just in case it does, the test will fail anyway. } mContext.unregisterReceiver(receiver); if (!success) { - fail(String.format("discoverable() timeout: scanMode=%d (expected %d)", scanMode, - BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)); + fail( + String.format( + "discoverable() timeout: scanMode=%d (expected %d)", + scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)); } } /** * Puts the local device into connectable only mode and checks to make sure that the local - * device is in in connectable mode and that the correct actions were broadcast. + * device is in connectable mode and that the correct actions were broadcast. * * @param adapter The BT adapter. */ @@ -631,38 +663,45 @@ public class BluetoothTestUtils extends Assert { } final Semaphore completionSemaphore = new Semaphore(0); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) { - return; - } - final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, - BluetoothAdapter.SCAN_MODE_NONE); - if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) { - completionSemaphore.release(); - } - } - }; + final BroadcastReceiver receiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) { + return; + } + final int mode = + intent.getIntExtra( + BluetoothAdapter.EXTRA_SCAN_MODE, + BluetoothAdapter.SCAN_MODE_NONE); + if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) { + completionSemaphore.release(); + } + } + }; final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(receiver, filter); - assertEquals(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE), + assertEquals( + adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE), BluetoothStatusCodes.SUCCESS); boolean success = false; try { - success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, - TimeUnit.MILLISECONDS); + success = + completionSemaphore.tryAcquire( + DISCOVERABLE_UNDISCOVERABLE_TIMEOUT, TimeUnit.MILLISECONDS); writeOutput(String.format("undiscoverable() completed in 0 ms")); } catch (InterruptedException e) { // This should never happen but just in case it does, the test will fail anyway. } mContext.unregisterReceiver(receiver); if (!success) { - fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d)", scanMode, - BluetoothAdapter.SCAN_MODE_CONNECTABLE)); + fail( + String.format( + "undiscoverable() timeout: scanMode=%d (expected %d)", + scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE)); } } @@ -690,8 +729,10 @@ public class BluetoothTestUtils extends Assert { while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) { if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) { - writeOutput(String.format("startScan() completed in %d ms", - (receiver.getCompletedTime() - start))); + writeOutput( + String.format( + "startScan() completed in %d ms", + (receiver.getCompletedTime() - start))); removeReceiver(receiver); return; } @@ -700,8 +741,10 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)", - adapter.isDiscovering(), firedFlags, mask)); + fail( + String.format( + "startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)", + adapter.isDiscovering(), firedFlags, mask)); } /** @@ -728,8 +771,10 @@ public class BluetoothTestUtils extends Assert { while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) { if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) { - writeOutput(String.format("stopScan() completed in %d ms", - (receiver.getCompletedTime() - start))); + writeOutput( + String.format( + "stopScan() completed in %d ms", + (receiver.getCompletedTime() - start))); removeReceiver(receiver); return; } @@ -738,9 +783,10 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)", - adapter.isDiscovering(), firedFlags, mask)); - + fail( + String.format( + "stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)", + adapter.isDiscovering(), firedFlags, mask)); } /** @@ -753,17 +799,16 @@ public class BluetoothTestUtils extends Assert { assertNotNull(mPan); long start = System.currentTimeMillis(); - mPanCallback = new TetheringManager.TetheredInterfaceCallback() { + mPanCallback = + new TetheringManager.TetheredInterfaceCallback() { @Override - public void onAvailable(String iface) { - } + public void onAvailable(String iface) {} @Override - public void onUnavailable() { - } + public void onUnavailable() {} }; - mBluetoothIfaceRequest = mPan.requestTetheredInterface(mContext.getMainExecutor(), - mPanCallback); + mBluetoothIfaceRequest = + mPan.requestTetheredInterface(mContext.getMainExecutor(), mPanCallback); long stop = System.currentTimeMillis(); assertTrue(mPan.isTetheringOn()); @@ -813,8 +858,8 @@ public class BluetoothTestUtils extends Assert { * @param passkey The pairing passkey if pairing requires a passkey. Any value if not. * @param pin The pairing pin if pairing requires a pin. Any value if not. */ - public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, - byte[] pin) { + public void acceptPair( + BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) { pairOrAcceptPair(adapter, device, passkey, pin, false); } @@ -829,8 +874,12 @@ public class BluetoothTestUtils extends Assert { * @param pin The pairing pin if pairing requires a pin. Any value if not. * @param shouldPair Whether to pair or accept the pair. */ - private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, - byte[] pin, boolean shouldPair) { + private void pairOrAcceptPair( + BluetoothAdapter adapter, + BluetoothDevice device, + int passkey, + byte[] pin, + boolean shouldPair) { int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG; long start = -1; String methodName; @@ -873,8 +922,8 @@ public class BluetoothTestUtils extends Assert { assertTrue(adapter.getBondedDevices().contains(device)); long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); + writeOutput( + String.format("%s completed in %d ms", methodName, (finish - start))); } else { writeOutput(String.format("%s completed", methodName)); } @@ -886,8 +935,10 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", - methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask)); + fail( + String.format( + "%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", + methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask)); } /** @@ -935,8 +986,8 @@ public class BluetoothTestUtils extends Assert { assertFalse(adapter.getBondedDevices().contains(device)); long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); + writeOutput( + String.format("%s completed in %d ms", methodName, (finish - start))); } else { writeOutput(String.format("%s completed", methodName)); } @@ -947,12 +998,15 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", - methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask)); + fail( + String.format( + "%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", + methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask)); } /** * Deletes all pairings of remote devices + * * @param adapter the BT adapter */ public void unpairAll(BluetoothAdapter adapter) { @@ -968,18 +1022,20 @@ public class BluetoothTestUtils extends Assert { * * @param adapter The BT adapter. * @param device The remote device. - * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP}, - * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#HID_HOST} or {@link BluetoothProfile#MAP_CLIENT}.. - * @param methodName The method name to printed in the logs. If null, will be - * "connectProfile(profile=<profile>, device=<device>)" + * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP}, {@link + * BluetoothProfile#HEADSET}, {@link BluetoothProfile#HID_HOST} or {@link + * BluetoothProfile#MAP_CLIENT}.. + * @param methodName The method name to printed in the logs. If null, will be + * "connectProfile(profile=<profile>, device=<device>)" */ - public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile, - String methodName) { + public void connectProfile( + BluetoothAdapter adapter, BluetoothDevice device, int profile, String methodName) { if (methodName == null) { methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device); } - int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG - | ConnectProfileReceiver.STATE_CONNECTED_FLAG); + int mask = + (ConnectProfileReceiver.STATE_CONNECTING_FLAG + | ConnectProfileReceiver.STATE_CONNECTED_FLAG); long start = -1; if (!adapter.isEnabled()) { @@ -1028,8 +1084,8 @@ public class BluetoothTestUtils extends Assert { && (receiver.getFiredFlags() & mask) == mask) { long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); + writeOutput( + String.format("%s completed in %d ms", methodName, (finish - start))); } else { writeOutput(String.format("%s completed", methodName)); } @@ -1041,8 +1097,10 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", - methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask)); + fail( + String.format( + "%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", + methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask)); } /** @@ -1051,18 +1109,19 @@ public class BluetoothTestUtils extends Assert { * * @param adapter The BT adapter. * @param device The remote device. - * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP}, - * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}. - * @param methodName The method name to printed in the logs. If null, will be - * "connectProfile(profile=<profile>, device=<device>)" + * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP}, {@link + * BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}. + * @param methodName The method name to printed in the logs. If null, will be + * "connectProfile(profile=<profile>, device=<device>)" */ - public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile, - String methodName) { + public void disconnectProfile( + BluetoothAdapter adapter, BluetoothDevice device, int profile, String methodName) { if (methodName == null) { methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device); } - int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG - | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG); + int mask = + (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG + | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG); long start = -1; if (!adapter.isEnabled()) { @@ -1111,8 +1170,8 @@ public class BluetoothTestUtils extends Assert { && (receiver.getFiredFlags() & mask) == mask) { long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); + writeOutput( + String.format("%s completed in %d ms", methodName, (finish - start))); } else { writeOutput(String.format("%s completed", methodName)); } @@ -1124,8 +1183,10 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", - methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask)); + fail( + String.format( + "%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)", + methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask)); } /** @@ -1151,24 +1212,25 @@ public class BluetoothTestUtils extends Assert { } /** - * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and - * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a - * remote NAP or verify that a remote device connected to the local NAP. + * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and {@link + * #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a remote NAP + * or verify that a remote device connected to the local NAP. * * @param adapter The BT adapter. * @param device The remote device. * @param connect If the method should initiate the connection (is PANU) */ - private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device, - boolean connect) { + private void connectPanOrIncomingPanConnection( + BluetoothAdapter adapter, BluetoothDevice device, boolean connect) { long start = -1; int mask, role; String methodName; if (connect) { methodName = String.format("connectPan(device=%s)", device); - mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG - | ConnectProfileReceiver.STATE_CONNECTING_FLAG); + mask = + (ConnectProfileReceiver.STATE_CONNECTED_FLAG + | ConnectProfileReceiver.STATE_CONNECTING_FLAG); role = BluetoothPan.LOCAL_PANU_ROLE; } else { methodName = String.format("incomingPanConnection(device=%s)", device); @@ -1216,8 +1278,8 @@ public class BluetoothTestUtils extends Assert { && (receiver.getFiredFlags() & mask) == mask) { long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); + writeOutput( + String.format("%s completed in %d ms", methodName, (finish - start))); } else { writeOutput(String.format("%s completed", methodName)); } @@ -1229,8 +1291,10 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", - methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask)); + fail( + String.format( + "%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", + methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask)); } /** @@ -1256,24 +1320,25 @@ public class BluetoothTestUtils extends Assert { } /** - * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and - * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect - * from a remote NAP or verify that a remote device disconnected from the local NAP. + * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and {@link + * #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect from a + * remote NAP or verify that a remote device disconnected from the local NAP. * * @param adapter The BT adapter. * @param device The remote device. * @param disconnect Whether the method should connect or verify. */ - private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter, - BluetoothDevice device, boolean disconnect) { + private void disconnectFromRemoteOrVerifyConnectNap( + BluetoothAdapter adapter, BluetoothDevice device, boolean disconnect) { long start = -1; int mask, role; String methodName; if (disconnect) { methodName = String.format("disconnectPan(device=%s)", device); - mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG - | ConnectProfileReceiver.STATE_DISCONNECTING_FLAG); + mask = + (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG + | ConnectProfileReceiver.STATE_DISCONNECTING_FLAG); role = BluetoothPan.LOCAL_PANU_ROLE; } else { methodName = String.format("incomingPanDisconnection(device=%s)", device); @@ -1320,8 +1385,8 @@ public class BluetoothTestUtils extends Assert { && (receiver.getFiredFlags() & mask) == mask) { long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); + writeOutput( + String.format("%s completed in %d ms", methodName, (finish - start))); } else { writeOutput(String.format("%s completed", methodName)); } @@ -1333,8 +1398,10 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", - methodName, state, BluetoothHidHost.STATE_DISCONNECTED, firedFlags, mask)); + fail( + String.format( + "%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", + methodName, state, BluetoothHidHost.STATE_DISCONNECTED, firedFlags, mask)); } /** @@ -1350,7 +1417,7 @@ public class BluetoothTestUtils extends Assert { /** * Closes a SCO channel using {@link android.media.AudioManager#stopBluetoothSco()} and checks - * to make sure that the channel is closed and that the correct actions were broadcast. + * to make sure that the channel is closed and that the correct actions were broadcast. * * @param adapter The BT adapter. * @param device The remote device. @@ -1358,9 +1425,10 @@ public class BluetoothTestUtils extends Assert { public void stopSco(BluetoothAdapter adapter, BluetoothDevice device) { startStopSco(adapter, device, false); } + /** - * Helper method for {@link #startSco(BluetoothAdapter, BluetoothDevice)} and - * {@link #stopSco(BluetoothAdapter, BluetoothDevice)}. + * Helper method for {@link #startSco(BluetoothAdapter, BluetoothDevice)} and {@link + * #stopSco(BluetoothAdapter, BluetoothDevice)}. * * @param adapter The BT adapter. * @param device The remote device. @@ -1413,8 +1481,8 @@ public class BluetoothTestUtils extends Assert { if (isStart == isScoOn && (receiver.getFiredFlags() & mask) == mask) { long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { - writeOutput(String.format("%s completed in %d ms", methodName, - (finish - start))); + writeOutput( + String.format("%s completed in %d ms", methodName, (finish - start))); } else { writeOutput(String.format("%s completed", methodName)); } @@ -1426,8 +1494,10 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)", - methodName, isScoOn, isStart, firedFlags, mask)); + fail( + String.format( + "%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)", + methodName, isScoOn, isStart, firedFlags, mask)); } /** @@ -1483,14 +1553,17 @@ public class BluetoothTestUtils extends Assert { } int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", - methodName, mMce.getConnectionState(device), BluetoothMapClient.STATE_CONNECTED, - firedFlags, mask)); + fail( + String.format( + "%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", + methodName, + mMce.getConnectionState(device), + BluetoothMapClient.STATE_CONNECTED, + firedFlags, + mask)); } - /** - * Set a message to read/unread/deleted/undeleted - */ + /** Set a message to read/unread/deleted/undeleted */ public void mceSetMessageStatus(BluetoothAdapter adapter, BluetoothDevice device, int status) { int mask; String methodName = "setMessageStatus"; @@ -1528,15 +1601,20 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", - methodName, mMce.getConnectionState(device), BluetoothPan.STATE_CONNECTED, - firedFlags, mask)); + fail( + String.format( + "%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", + methodName, + mMce.getConnectionState(device), + BluetoothPan.STATE_CONNECTED, + firedFlags, + mask)); } private void addReceiver(BroadcastReceiver receiver, String[] actions) { IntentFilter filter = new IntentFilter(); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - for (String action: actions) { + for (String action : actions) { filter.addAction(action); } mContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED); @@ -1545,40 +1623,42 @@ public class BluetoothTestUtils extends Assert { private BluetoothReceiver getBluetoothReceiver(int expectedFlags) { String[] actions = { - BluetoothAdapter.ACTION_DISCOVERY_FINISHED, - BluetoothAdapter.ACTION_DISCOVERY_STARTED, - BluetoothAdapter.ACTION_SCAN_MODE_CHANGED, - BluetoothAdapter.ACTION_STATE_CHANGED}; + BluetoothAdapter.ACTION_DISCOVERY_FINISHED, + BluetoothAdapter.ACTION_DISCOVERY_STARTED, + BluetoothAdapter.ACTION_SCAN_MODE_CHANGED, + BluetoothAdapter.ACTION_STATE_CHANGED + }; BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags); addReceiver(receiver, actions); return receiver; } - private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin, - int expectedFlags) { + private PairReceiver getPairReceiver( + BluetoothDevice device, int passkey, byte[] pin, int expectedFlags) { String[] actions = { - BluetoothDevice.ACTION_PAIRING_REQUEST, - BluetoothDevice.ACTION_BOND_STATE_CHANGED}; + BluetoothDevice.ACTION_PAIRING_REQUEST, BluetoothDevice.ACTION_BOND_STATE_CHANGED + }; PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags); addReceiver(receiver, actions); return receiver; } - private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile, - int expectedFlags) { + private ConnectProfileReceiver getConnectProfileReceiver( + BluetoothDevice device, int profile, int expectedFlags) { String[] actions = { - BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED, - BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED, - BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED, - BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED}; - ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile, - expectedFlags); + BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED, + BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED, + BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED, + BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED + }; + ConnectProfileReceiver receiver = + new ConnectProfileReceiver(device, profile, expectedFlags); addReceiver(receiver, actions); return receiver; } - private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role, - int expectedFlags) { + private ConnectPanReceiver getConnectPanReceiver( + BluetoothDevice device, int role, int expectedFlags) { String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED}; ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags); addReceiver(receiver, actions); @@ -1592,11 +1672,13 @@ public class BluetoothTestUtils extends Assert { return receiver; } - private MceSetMessageStatusReceiver getMceSetMessageStatusReceiver(BluetoothDevice device, - int expectedFlags) { - String[] actions = {BluetoothMapClient.ACTION_MESSAGE_RECEIVED, + private MceSetMessageStatusReceiver getMceSetMessageStatusReceiver( + BluetoothDevice device, int expectedFlags) { + String[] actions = { + BluetoothMapClient.ACTION_MESSAGE_RECEIVED, BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED, - BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED}; + BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED + }; MceSetMessageStatusReceiver receiver = new MceSetMessageStatusReceiver(expectedFlags); addReceiver(receiver, actions); return receiver; diff --git a/framework/tests/unit/Android.bp b/framework/tests/unit/Android.bp index 3eeb86cadead796e98da254db4d87a4065a5023c..ef7870315b8a8b0a83108877a62f8a1aefb41331 100644 --- a/framework/tests/unit/Android.bp +++ b/framework/tests/unit/Android.bp @@ -23,7 +23,9 @@ android_test { static_libs: [ "androidx.test.ext.truth", "androidx.test.rules", + "frameworks-base-testutils", "junit", + "mockito-target", "modules-utils-bytesmatcher", ], test_suites: [ diff --git a/framework/tests/unit/src/android/bluetooth/BluetoothActivityEnergyInfoTest.java b/framework/tests/unit/src/android/bluetooth/BluetoothActivityEnergyInfoTest.java index d095a9ca9e070478c7dc143f8e9628c8d4444add..75f604fe36f1a4100bc47ec0b48a4b10fc1407fc 100644 --- a/framework/tests/unit/src/android/bluetooth/BluetoothActivityEnergyInfoTest.java +++ b/framework/tests/unit/src/android/bluetooth/BluetoothActivityEnergyInfoTest.java @@ -31,9 +31,7 @@ import org.junit.runner.RunWith; import java.util.ArrayList; -/** - * Test cases for {@link BluetoothActivityEnergyInfo}. - */ +/** Test cases for {@link BluetoothActivityEnergyInfo}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class BluetoothActivityEnergyInfoTest { @@ -46,8 +44,9 @@ public class BluetoothActivityEnergyInfoTest { long rxTime = 200; long idleTime = 300; long energyUsed = 10; - BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo( - timestamp, stackState, txTime, rxTime, idleTime, energyUsed); + BluetoothActivityEnergyInfo info = + new BluetoothActivityEnergyInfo( + timestamp, stackState, txTime, rxTime, idleTime, energyUsed); assertThat(info.getTimestampMillis()).isEqualTo(timestamp); assertThat(info.getBluetoothStackState()).isEqualTo(stackState); @@ -66,8 +65,9 @@ public class BluetoothActivityEnergyInfoTest { long rxTime = 200; long idleTime = 300; long energyUsed = 10; - BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo( - timestamp, stackState, txTime, rxTime, idleTime, energyUsed); + BluetoothActivityEnergyInfo info = + new BluetoothActivityEnergyInfo( + timestamp, stackState, txTime, rxTime, idleTime, energyUsed); ArrayList traffics = new ArrayList<>(); UidTraffic traffic = new UidTraffic(123, 300, 400); @@ -86,21 +86,25 @@ public class BluetoothActivityEnergyInfoTest { long rxTime = 200; long idleTime = 300; long energyUsed = 10; - BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo( - timestamp, stackState, txTime, rxTime, idleTime, energyUsed); + BluetoothActivityEnergyInfo info = + new BluetoothActivityEnergyInfo( + timestamp, stackState, txTime, rxTime, idleTime, energyUsed); assertThat(info.isValid()).isEqualTo(true); - info = new BluetoothActivityEnergyInfo( - timestamp, stackState, -1, rxTime, idleTime, energyUsed); + info = + new BluetoothActivityEnergyInfo( + timestamp, stackState, -1, rxTime, idleTime, energyUsed); assertThat(info.isValid()).isEqualTo(false); - info = new BluetoothActivityEnergyInfo( - timestamp, stackState, txTime, -1, idleTime, energyUsed); + info = + new BluetoothActivityEnergyInfo( + timestamp, stackState, txTime, -1, idleTime, energyUsed); assertThat(info.isValid()).isEqualTo(false); - info = new BluetoothActivityEnergyInfo( - timestamp, stackState, txTime, rxTime, -1, energyUsed); + info = + new BluetoothActivityEnergyInfo( + timestamp, stackState, txTime, rxTime, -1, energyUsed); assertThat(info.isValid()).isEqualTo(false); } @@ -112,8 +116,9 @@ public class BluetoothActivityEnergyInfoTest { long rxTime = 200; long idleTime = 300; long energyUsed = 10; - BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo( - timestamp, stackState, txTime, rxTime, idleTime, energyUsed); + BluetoothActivityEnergyInfo info = + new BluetoothActivityEnergyInfo( + timestamp, stackState, txTime, rxTime, idleTime, energyUsed); Parcel parcel = Parcel.obtain(); info.writeToParcel(parcel, 0); @@ -140,8 +145,9 @@ public class BluetoothActivityEnergyInfoTest { long rxTime = 200; long idleTime = 300; long energyUsed = 10; - BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo( - timestamp, stackState, txTime, rxTime, idleTime, energyUsed); + BluetoothActivityEnergyInfo info = + new BluetoothActivityEnergyInfo( + timestamp, stackState, txTime, rxTime, idleTime, energyUsed); try { String infoString = info.toString(); diff --git a/framework/tests/unit/src/android/bluetooth/BluetoothAudioConfigTest.java b/framework/tests/unit/src/android/bluetooth/BluetoothAudioConfigTest.java index c18d6aee018a6c5d970b7c9406e21fe5587142ea..2360dcad14e01857e244277085e688ae5913e36e 100644 --- a/framework/tests/unit/src/android/bluetooth/BluetoothAudioConfigTest.java +++ b/framework/tests/unit/src/android/bluetooth/BluetoothAudioConfigTest.java @@ -27,9 +27,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -/** - * Test cases for {@link BluetoothAudioConfig}. - */ +/** Test cases for {@link BluetoothAudioConfig}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class BluetoothAudioConfigTest { @@ -39,11 +37,9 @@ public class BluetoothAudioConfigTest { @Test public void createBluetoothAudioConfig() { - BluetoothAudioConfig audioConfig = new BluetoothAudioConfig( - TEST_SAMPLE_RATE, - TEST_CHANNEL_COUNT, - AudioFormat.ENCODING_PCM_16BIT - ); + BluetoothAudioConfig audioConfig = + new BluetoothAudioConfig( + TEST_SAMPLE_RATE, TEST_CHANNEL_COUNT, AudioFormat.ENCODING_PCM_16BIT); assertThat(audioConfig.getSampleRate()).isEqualTo(TEST_SAMPLE_RATE); assertThat(audioConfig.getChannelConfig()).isEqualTo(TEST_CHANNEL_COUNT); @@ -52,11 +48,9 @@ public class BluetoothAudioConfigTest { @Test public void writeToParcel() { - BluetoothAudioConfig originalConfig = new BluetoothAudioConfig( - TEST_SAMPLE_RATE, - TEST_CHANNEL_COUNT, - AudioFormat.ENCODING_PCM_16BIT - ); + BluetoothAudioConfig originalConfig = + new BluetoothAudioConfig( + TEST_SAMPLE_RATE, TEST_CHANNEL_COUNT, AudioFormat.ENCODING_PCM_16BIT); Parcel parcel = Parcel.obtain(); originalConfig.writeToParcel(parcel, 0); @@ -65,24 +59,21 @@ public class BluetoothAudioConfigTest { BluetoothAudioConfig configOut = BluetoothAudioConfig.CREATOR.createFromParcel(parcel); parcel.recycle(); - assertThat(configOut.getSampleRate()) - .isEqualTo(originalConfig.getSampleRate()); - assertThat(configOut.getChannelConfig()) - .isEqualTo(originalConfig.getChannelConfig()); - assertThat(configOut.getAudioFormat()) - .isEqualTo(originalConfig.getAudioFormat()); + assertThat(configOut.getSampleRate()).isEqualTo(originalConfig.getSampleRate()); + assertThat(configOut.getChannelConfig()).isEqualTo(originalConfig.getChannelConfig()); + assertThat(configOut.getAudioFormat()).isEqualTo(originalConfig.getAudioFormat()); } @Test public void bluetoothAudioConfigHashCode() { - BluetoothAudioConfig audioConfig = new BluetoothAudioConfig( - TEST_SAMPLE_RATE, - TEST_CHANNEL_COUNT, - AudioFormat.ENCODING_PCM_16BIT - ); - - int hashCode = audioConfig.getSampleRate() | (audioConfig.getChannelConfig() << 24) | ( - audioConfig.getAudioFormat() << 28); + BluetoothAudioConfig audioConfig = + new BluetoothAudioConfig( + TEST_SAMPLE_RATE, TEST_CHANNEL_COUNT, AudioFormat.ENCODING_PCM_16BIT); + + int hashCode = + audioConfig.getSampleRate() + | (audioConfig.getChannelConfig() << 24) + | (audioConfig.getAudioFormat() << 28); int describeContents = 0; assertThat(audioConfig.hashCode()).isEqualTo(hashCode); @@ -91,16 +82,19 @@ public class BluetoothAudioConfigTest { @Test public void bluetoothAudioConfigToString() { - BluetoothAudioConfig audioConfig = new BluetoothAudioConfig( - TEST_SAMPLE_RATE, - TEST_CHANNEL_COUNT, - AudioFormat.ENCODING_PCM_16BIT - ); + BluetoothAudioConfig audioConfig = + new BluetoothAudioConfig( + TEST_SAMPLE_RATE, TEST_CHANNEL_COUNT, AudioFormat.ENCODING_PCM_16BIT); String audioConfigString = audioConfig.toString(); - String expectedToString = "{mSampleRate:" + audioConfig.getSampleRate() - + ",mChannelConfig:" + audioConfig.getChannelConfig() - + ",mAudioFormat:" + audioConfig.getAudioFormat() + "}"; + String expectedToString = + "{mSampleRate:" + + audioConfig.getSampleRate() + + ",mChannelConfig:" + + audioConfig.getChannelConfig() + + ",mAudioFormat:" + + audioConfig.getAudioFormat() + + "}"; assertThat(audioConfigString).isEqualTo(expectedToString); } diff --git a/framework/tests/unit/src/android/bluetooth/BluetoothCodecConfigTest.java b/framework/tests/unit/src/android/bluetooth/BluetoothCodecConfigTest.java index 23588be2a1447d1d5443c75de9f5f247c79729d2..b75b8f9476529f4cf4b207827da2b5470266c31e 100644 --- a/framework/tests/unit/src/android/bluetooth/BluetoothCodecConfigTest.java +++ b/framework/tests/unit/src/android/bluetooth/BluetoothCodecConfigTest.java @@ -20,73 +20,74 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; -/** - * Unit test cases for {@link BluetoothCodecConfig}. - */ +/** Unit test cases for {@link BluetoothCodecConfig}. */ public class BluetoothCodecConfigTest extends TestCase { - private static final int[] sCodecTypeArray = new int[] { - BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS, - BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID, - }; - private static final int[] sCodecPriorityArray = new int[] { - BluetoothCodecConfig.CODEC_PRIORITY_DISABLED, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST, - }; - private static final int[] sSampleRateArray = new int[] { - BluetoothCodecConfig.SAMPLE_RATE_NONE, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.SAMPLE_RATE_88200, - BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.SAMPLE_RATE_176400, - BluetoothCodecConfig.SAMPLE_RATE_192000, - }; - private static final int[] sBitsPerSampleArray = new int[] { - BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.BITS_PER_SAMPLE_32, - }; - private static final int[] sChannelModeArray = new int[] { - BluetoothCodecConfig.CHANNEL_MODE_NONE, - BluetoothCodecConfig.CHANNEL_MODE_MONO, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - }; - private static final long[] sCodecSpecific1Array = new long[] { - 1000, - 1001, - 1002, - 1003, - }; - private static final long[] sCodecSpecific2Array = new long[] { - 2000, - 2001, - 2002, - 2003, - }; - private static final long[] sCodecSpecific3Array = new long[] { - 3000, - 3001, - 3002, - 3003, - }; - private static final long[] sCodecSpecific4Array = new long[] { - 4000, - 4001, - 4002, - 4003, - }; - - private static final int sTotalConfigs = sCodecTypeArray.length * sCodecPriorityArray.length - * sSampleRateArray.length * sBitsPerSampleArray.length * sChannelModeArray.length - * sCodecSpecific1Array.length * sCodecSpecific2Array.length - * sCodecSpecific3Array.length * sCodecSpecific4Array.length; + private static final int[] sCodecTypeArray = + new int[] { + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, + BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, + BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS, + BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID, + }; + private static final int[] sCodecPriorityArray = + new int[] { + BluetoothCodecConfig.CODEC_PRIORITY_DISABLED, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST, + }; + private static final int[] sSampleRateArray = + new int[] { + BluetoothCodecConfig.SAMPLE_RATE_NONE, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.SAMPLE_RATE_88200, + BluetoothCodecConfig.SAMPLE_RATE_96000, + BluetoothCodecConfig.SAMPLE_RATE_176400, + BluetoothCodecConfig.SAMPLE_RATE_192000, + }; + private static final int[] sBitsPerSampleArray = + new int[] { + BluetoothCodecConfig.BITS_PER_SAMPLE_NONE, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.BITS_PER_SAMPLE_24, + BluetoothCodecConfig.BITS_PER_SAMPLE_32, + }; + private static final int[] sChannelModeArray = + new int[] { + BluetoothCodecConfig.CHANNEL_MODE_NONE, + BluetoothCodecConfig.CHANNEL_MODE_MONO, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + }; + private static final long[] sCodecSpecific1Array = + new long[] { + 1000, 1001, 1002, 1003, + }; + private static final long[] sCodecSpecific2Array = + new long[] { + 2000, 2001, 2002, 2003, + }; + private static final long[] sCodecSpecific3Array = + new long[] { + 3000, 3001, 3002, 3003, + }; + private static final long[] sCodecSpecific4Array = + new long[] { + 4000, 4001, 4002, 4003, + }; + + private static final int sTotalConfigs = + sCodecTypeArray.length + * sCodecPriorityArray.length + * sSampleRateArray.length + * sBitsPerSampleArray.length + * sChannelModeArray.length + * sCodecSpecific1Array.length + * sCodecSpecific2Array.length + * sCodecSpecific3Array.length + * sCodecSpecific4Array.length; private int selectCodecType(int configId) { int left = sCodecTypeArray.length; @@ -113,8 +114,11 @@ public class BluetoothCodecConfigTest extends TestCase { } private int selectBitsPerSample(int configId) { - int left = sCodecTypeArray.length * sCodecPriorityArray.length * sSampleRateArray.length - * sBitsPerSampleArray.length; + int left = + sCodecTypeArray.length + * sCodecPriorityArray.length + * sSampleRateArray.length + * sBitsPerSampleArray.length; int right = sTotalConfigs / left; int index = configId / right; index = index % sBitsPerSampleArray.length; @@ -122,8 +126,12 @@ public class BluetoothCodecConfigTest extends TestCase { } private int selectChannelMode(int configId) { - int left = sCodecTypeArray.length * sCodecPriorityArray.length * sSampleRateArray.length - * sBitsPerSampleArray.length * sChannelModeArray.length; + int left = + sCodecTypeArray.length + * sCodecPriorityArray.length + * sSampleRateArray.length + * sBitsPerSampleArray.length + * sChannelModeArray.length; int right = sTotalConfigs / left; int index = configId / right; index = index % sChannelModeArray.length; @@ -131,9 +139,13 @@ public class BluetoothCodecConfigTest extends TestCase { } private long selectCodecSpecific1(int configId) { - int left = sCodecTypeArray.length * sCodecPriorityArray.length * sSampleRateArray.length - * sBitsPerSampleArray.length * sChannelModeArray.length - * sCodecSpecific1Array.length; + int left = + sCodecTypeArray.length + * sCodecPriorityArray.length + * sSampleRateArray.length + * sBitsPerSampleArray.length + * sChannelModeArray.length + * sCodecSpecific1Array.length; int right = sTotalConfigs / left; int index = configId / right; index = index % sCodecSpecific1Array.length; @@ -141,9 +153,14 @@ public class BluetoothCodecConfigTest extends TestCase { } private long selectCodecSpecific2(int configId) { - int left = sCodecTypeArray.length * sCodecPriorityArray.length * sSampleRateArray.length - * sBitsPerSampleArray.length * sChannelModeArray.length - * sCodecSpecific1Array.length * sCodecSpecific2Array.length; + int left = + sCodecTypeArray.length + * sCodecPriorityArray.length + * sSampleRateArray.length + * sBitsPerSampleArray.length + * sChannelModeArray.length + * sCodecSpecific1Array.length + * sCodecSpecific2Array.length; int right = sTotalConfigs / left; int index = configId / right; index = index % sCodecSpecific2Array.length; @@ -151,10 +168,15 @@ public class BluetoothCodecConfigTest extends TestCase { } private long selectCodecSpecific3(int configId) { - int left = sCodecTypeArray.length * sCodecPriorityArray.length * sSampleRateArray.length - * sBitsPerSampleArray.length * sChannelModeArray.length - * sCodecSpecific1Array.length * sCodecSpecific2Array.length - * sCodecSpecific3Array.length; + int left = + sCodecTypeArray.length + * sCodecPriorityArray.length + * sSampleRateArray.length + * sBitsPerSampleArray.length + * sChannelModeArray.length + * sCodecSpecific1Array.length + * sCodecSpecific2Array.length + * sCodecSpecific3Array.length; int right = sTotalConfigs / left; int index = configId / right; index = index % sCodecSpecific3Array.length; @@ -162,10 +184,16 @@ public class BluetoothCodecConfigTest extends TestCase { } private long selectCodecSpecific4(int configId) { - int left = sCodecTypeArray.length * sCodecPriorityArray.length * sSampleRateArray.length - * sBitsPerSampleArray.length * sChannelModeArray.length - * sCodecSpecific1Array.length * sCodecSpecific2Array.length - * sCodecSpecific3Array.length * sCodecSpecific4Array.length; + int left = + sCodecTypeArray.length + * sCodecPriorityArray.length + * sSampleRateArray.length + * sBitsPerSampleArray.length + * sChannelModeArray.length + * sCodecSpecific1Array.length + * sCodecSpecific2Array.length + * sCodecSpecific3Array.length + * sCodecSpecific4Array.length; int right = sTotalConfigs / left; int index = configId / right; index = index % sCodecSpecific4Array.length; @@ -186,11 +214,17 @@ public class BluetoothCodecConfigTest extends TestCase { long codec_specific3 = selectCodecSpecific3(config_id); long codec_specific4 = selectCodecSpecific4(config_id); - BluetoothCodecConfig bcc = buildBluetoothCodecConfig(codec_type, codec_priority, - sample_rate, bits_per_sample, - channel_mode, codec_specific1, - codec_specific2, codec_specific3, - codec_specific4); + BluetoothCodecConfig bcc = + buildBluetoothCodecConfig( + codec_type, + codec_priority, + sample_rate, + bits_per_sample, + channel_mode, + codec_specific1, + codec_specific2, + codec_specific3, + codec_specific4); if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) { assertTrue(bcc.isMandatoryCodec()); @@ -235,118 +269,168 @@ public class BluetoothCodecConfigTest extends TestCase { @SmallTest public void testBluetoothCodecConfig_equals() { BluetoothCodecConfig bcc1 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); BluetoothCodecConfig bcc2_same = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); assertTrue(bcc1.equals(bcc2_same)); BluetoothCodecConfig bcc3_codec_type = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); assertFalse(bcc1.equals(bcc3_codec_type)); BluetoothCodecConfig bcc4_codec_priority = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); assertFalse(bcc1.equals(bcc4_codec_priority)); BluetoothCodecConfig bcc5_sample_rate = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); assertFalse(bcc1.equals(bcc5_sample_rate)); BluetoothCodecConfig bcc6_bits_per_sample = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_24, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); assertFalse(bcc1.equals(bcc6_bits_per_sample)); BluetoothCodecConfig bcc7_channel_mode = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); assertFalse(bcc1.equals(bcc7_channel_mode)); BluetoothCodecConfig bcc8_codec_specific1 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1001, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1001, + 2000, + 3000, + 4000); assertFalse(bcc1.equals(bcc8_codec_specific1)); BluetoothCodecConfig bcc9_codec_specific2 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2002, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2002, + 3000, + 4000); assertFalse(bcc1.equals(bcc9_codec_specific2)); BluetoothCodecConfig bcc10_codec_specific3 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3003, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3003, + 4000); assertFalse(bcc1.equals(bcc10_codec_specific3)); BluetoothCodecConfig bcc11_codec_specific4 = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4004); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4004); assertFalse(bcc1.equals(bcc11_codec_specific4)); } - private BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType, - int codecPriority, int sampleRate, int bitsPerSample, int channelMode, - long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) { + private BluetoothCodecConfig buildBluetoothCodecConfig( + int sourceCodecType, + int codecPriority, + int sampleRate, + int bitsPerSample, + int channelMode, + long codecSpecific1, + long codecSpecific2, + long codecSpecific3, + long codecSpecific4) { return new BluetoothCodecConfig.Builder() - .setCodecType(sourceCodecType) - .setCodecPriority(codecPriority) - .setSampleRate(sampleRate) - .setBitsPerSample(bitsPerSample) - .setChannelMode(channelMode) - .setCodecSpecific1(codecSpecific1) - .setCodecSpecific2(codecSpecific2) - .setCodecSpecific3(codecSpecific3) - .setCodecSpecific4(codecSpecific4) - .build(); - + .setCodecType(sourceCodecType) + .setCodecPriority(codecPriority) + .setSampleRate(sampleRate) + .setBitsPerSample(bitsPerSample) + .setChannelMode(channelMode) + .setCodecSpecific1(codecSpecific1) + .setCodecSpecific2(codecSpecific2) + .setCodecSpecific3(codecSpecific3) + .setCodecSpecific4(codecSpecific4) + .build(); } } diff --git a/framework/tests/unit/src/android/bluetooth/BluetoothCodecStatusTest.java b/framework/tests/unit/src/android/bluetooth/BluetoothCodecStatusTest.java index 7d10a4d6571c9c870535c68bee48274c86f71ce0..48d5265762c97776a39b354810c428ad8aa7317e 100644 --- a/framework/tests/unit/src/android/bluetooth/BluetoothCodecStatusTest.java +++ b/framework/tests/unit/src/android/bluetooth/BluetoothCodecStatusTest.java @@ -20,409 +20,532 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; -import java.util.ArrayList; import java.util.List; import java.util.Objects; -/** - * Unit test cases for {@link BluetoothCodecStatus}. - */ +/** Unit test cases for {@link BluetoothCodecStatus}. */ public class BluetoothCodecStatusTest extends TestCase { // Codec configs: A and B are same; C is different private static final BluetoothCodecConfig CONFIG_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig CONFIG_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig CONFIG_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); // Local capabilities: A and B are same; C is different private static final BluetoothCodecConfig LOCAL_CAPABILITY_1_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_1_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_1_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_2_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_2_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_2_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_3_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_3_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_3_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_4_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_24, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_4_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_24, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_4_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 | BluetoothCodecConfig.SAMPLE_RATE_48000, + BluetoothCodecConfig.BITS_PER_SAMPLE_24, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_5_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000 - | BluetoothCodecConfig.SAMPLE_RATE_88200 - | BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 - | BluetoothCodecConfig.BITS_PER_SAMPLE_24 - | BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 + | BluetoothCodecConfig.SAMPLE_RATE_48000 + | BluetoothCodecConfig.SAMPLE_RATE_88200 + | BluetoothCodecConfig.SAMPLE_RATE_96000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16 + | BluetoothCodecConfig.BITS_PER_SAMPLE_24 + | BluetoothCodecConfig.BITS_PER_SAMPLE_32, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_5_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000 - | BluetoothCodecConfig.SAMPLE_RATE_88200 - | BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 - | BluetoothCodecConfig.BITS_PER_SAMPLE_24 - | BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 + | BluetoothCodecConfig.SAMPLE_RATE_48000 + | BluetoothCodecConfig.SAMPLE_RATE_88200 + | BluetoothCodecConfig.SAMPLE_RATE_96000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16 + | BluetoothCodecConfig.BITS_PER_SAMPLE_24 + | BluetoothCodecConfig.BITS_PER_SAMPLE_32, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig LOCAL_CAPABILITY_5_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000 - | BluetoothCodecConfig.SAMPLE_RATE_88200 - | BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 - | BluetoothCodecConfig.BITS_PER_SAMPLE_24 - | BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 + | BluetoothCodecConfig.SAMPLE_RATE_48000 + | BluetoothCodecConfig.SAMPLE_RATE_88200 + | BluetoothCodecConfig.SAMPLE_RATE_96000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16 + | BluetoothCodecConfig.BITS_PER_SAMPLE_24 + | BluetoothCodecConfig.BITS_PER_SAMPLE_32, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); // Selectable capabilities: A and B are same; C is different private static final BluetoothCodecConfig SELECTABE_CAPABILITY_1_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_1_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_1_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_2_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_2_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_2_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_3_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_3_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_3_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_16, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_16, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_4_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_24, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_4_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_24, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_4_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100, - BluetoothCodecConfig.BITS_PER_SAMPLE_24, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100, + BluetoothCodecConfig.BITS_PER_SAMPLE_24, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_5_A = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000 - | BluetoothCodecConfig.SAMPLE_RATE_88200 - | BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 - | BluetoothCodecConfig.BITS_PER_SAMPLE_24 - | BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 + | BluetoothCodecConfig.SAMPLE_RATE_48000 + | BluetoothCodecConfig.SAMPLE_RATE_88200 + | BluetoothCodecConfig.SAMPLE_RATE_96000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16 + | BluetoothCodecConfig.BITS_PER_SAMPLE_24 + | BluetoothCodecConfig.BITS_PER_SAMPLE_32, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_5_B = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000 - | BluetoothCodecConfig.SAMPLE_RATE_88200 - | BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 - | BluetoothCodecConfig.BITS_PER_SAMPLE_24 - | BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO - | BluetoothCodecConfig.CHANNEL_MODE_MONO, - 1000, 2000, 3000, 4000); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 + | BluetoothCodecConfig.SAMPLE_RATE_48000 + | BluetoothCodecConfig.SAMPLE_RATE_88200 + | BluetoothCodecConfig.SAMPLE_RATE_96000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16 + | BluetoothCodecConfig.BITS_PER_SAMPLE_24 + | BluetoothCodecConfig.BITS_PER_SAMPLE_32, + BluetoothCodecConfig.CHANNEL_MODE_STEREO + | BluetoothCodecConfig.CHANNEL_MODE_MONO, + 1000, + 2000, + 3000, + 4000); private static final BluetoothCodecConfig SELECTABE_CAPABILITY_5_C = - buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, - BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, - BluetoothCodecConfig.SAMPLE_RATE_44100 - | BluetoothCodecConfig.SAMPLE_RATE_48000 - | BluetoothCodecConfig.SAMPLE_RATE_88200 - | BluetoothCodecConfig.SAMPLE_RATE_96000, - BluetoothCodecConfig.BITS_PER_SAMPLE_16 - | BluetoothCodecConfig.BITS_PER_SAMPLE_24 - | BluetoothCodecConfig.BITS_PER_SAMPLE_32, - BluetoothCodecConfig.CHANNEL_MODE_STEREO, - 1000, 2000, 3000, 4000); - - private static final List LOCAL_CAPABILITY_A = List.of( - LOCAL_CAPABILITY_1_A, - LOCAL_CAPABILITY_2_A, - LOCAL_CAPABILITY_3_A, - LOCAL_CAPABILITY_4_A, - LOCAL_CAPABILITY_5_A); - - private static final List LOCAL_CAPABILITY_B = List.of( - LOCAL_CAPABILITY_1_B, - LOCAL_CAPABILITY_2_B, - LOCAL_CAPABILITY_3_B, - LOCAL_CAPABILITY_4_B, - LOCAL_CAPABILITY_5_B); - - private static final List LOCAL_CAPABILITY_B_REORDERED = List.of( - LOCAL_CAPABILITY_5_B, - LOCAL_CAPABILITY_4_B, - LOCAL_CAPABILITY_2_B, - LOCAL_CAPABILITY_3_B, - LOCAL_CAPABILITY_1_B); - - private static final List LOCAL_CAPABILITY_C = List.of( - LOCAL_CAPABILITY_1_C, - LOCAL_CAPABILITY_2_C, - LOCAL_CAPABILITY_3_C, - LOCAL_CAPABILITY_4_C, - LOCAL_CAPABILITY_5_C); - - private static final List SELECTABLE_CAPABILITY_A = List.of( - SELECTABE_CAPABILITY_1_A, - SELECTABE_CAPABILITY_2_A, - SELECTABE_CAPABILITY_3_A, - SELECTABE_CAPABILITY_4_A, - SELECTABE_CAPABILITY_5_A); - - private static final List SELECTABLE_CAPABILITY_B = List.of( - SELECTABE_CAPABILITY_1_B, - SELECTABE_CAPABILITY_2_B, - SELECTABE_CAPABILITY_3_B, - SELECTABE_CAPABILITY_4_B, - SELECTABE_CAPABILITY_5_B); - - private static final List SELECTABLE_CAPABILITY_B_REORDERED = List.of( - SELECTABE_CAPABILITY_5_B, - SELECTABE_CAPABILITY_4_B, - SELECTABE_CAPABILITY_2_B, - SELECTABE_CAPABILITY_3_B, - SELECTABE_CAPABILITY_1_B); - - private static final List SELECTABLE_CAPABILITY_C = List.of( - SELECTABE_CAPABILITY_1_C, - SELECTABE_CAPABILITY_2_C, - SELECTABE_CAPABILITY_3_C, - SELECTABE_CAPABILITY_4_C, - SELECTABE_CAPABILITY_5_C); + buildBluetoothCodecConfig( + BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC, + BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT, + BluetoothCodecConfig.SAMPLE_RATE_44100 + | BluetoothCodecConfig.SAMPLE_RATE_48000 + | BluetoothCodecConfig.SAMPLE_RATE_88200 + | BluetoothCodecConfig.SAMPLE_RATE_96000, + BluetoothCodecConfig.BITS_PER_SAMPLE_16 + | BluetoothCodecConfig.BITS_PER_SAMPLE_24 + | BluetoothCodecConfig.BITS_PER_SAMPLE_32, + BluetoothCodecConfig.CHANNEL_MODE_STEREO, + 1000, + 2000, + 3000, + 4000); + + private static final List LOCAL_CAPABILITY_A = + List.of( + LOCAL_CAPABILITY_1_A, + LOCAL_CAPABILITY_2_A, + LOCAL_CAPABILITY_3_A, + LOCAL_CAPABILITY_4_A, + LOCAL_CAPABILITY_5_A); + + private static final List LOCAL_CAPABILITY_B = + List.of( + LOCAL_CAPABILITY_1_B, + LOCAL_CAPABILITY_2_B, + LOCAL_CAPABILITY_3_B, + LOCAL_CAPABILITY_4_B, + LOCAL_CAPABILITY_5_B); + + private static final List LOCAL_CAPABILITY_B_REORDERED = + List.of( + LOCAL_CAPABILITY_5_B, + LOCAL_CAPABILITY_4_B, + LOCAL_CAPABILITY_2_B, + LOCAL_CAPABILITY_3_B, + LOCAL_CAPABILITY_1_B); + + private static final List LOCAL_CAPABILITY_C = + List.of( + LOCAL_CAPABILITY_1_C, + LOCAL_CAPABILITY_2_C, + LOCAL_CAPABILITY_3_C, + LOCAL_CAPABILITY_4_C, + LOCAL_CAPABILITY_5_C); + + private static final List SELECTABLE_CAPABILITY_A = + List.of( + SELECTABE_CAPABILITY_1_A, + SELECTABE_CAPABILITY_2_A, + SELECTABE_CAPABILITY_3_A, + SELECTABE_CAPABILITY_4_A, + SELECTABE_CAPABILITY_5_A); + + private static final List SELECTABLE_CAPABILITY_B = + List.of( + SELECTABE_CAPABILITY_1_B, + SELECTABE_CAPABILITY_2_B, + SELECTABE_CAPABILITY_3_B, + SELECTABE_CAPABILITY_4_B, + SELECTABE_CAPABILITY_5_B); + + private static final List SELECTABLE_CAPABILITY_B_REORDERED = + List.of( + SELECTABE_CAPABILITY_5_B, + SELECTABE_CAPABILITY_4_B, + SELECTABE_CAPABILITY_2_B, + SELECTABE_CAPABILITY_3_B, + SELECTABE_CAPABILITY_1_B); + + private static final List SELECTABLE_CAPABILITY_C = + List.of( + SELECTABE_CAPABILITY_1_C, + SELECTABE_CAPABILITY_2_C, + SELECTABE_CAPABILITY_3_C, + SELECTABE_CAPABILITY_4_C, + SELECTABE_CAPABILITY_5_C); private static final BluetoothCodecStatus BCS_A = new BluetoothCodecStatus(CONFIG_A, LOCAL_CAPABILITY_A, SELECTABLE_CAPABILITY_A); private static final BluetoothCodecStatus BCS_B = new BluetoothCodecStatus(CONFIG_B, LOCAL_CAPABILITY_B, SELECTABLE_CAPABILITY_B); private static final BluetoothCodecStatus BCS_B_REORDERED = - new BluetoothCodecStatus(CONFIG_B, LOCAL_CAPABILITY_B_REORDERED, - SELECTABLE_CAPABILITY_B_REORDERED); + new BluetoothCodecStatus( + CONFIG_B, LOCAL_CAPABILITY_B_REORDERED, SELECTABLE_CAPABILITY_B_REORDERED); private static final BluetoothCodecStatus BCS_C = new BluetoothCodecStatus(CONFIG_C, LOCAL_CAPABILITY_C, SELECTABLE_CAPABILITY_C); @@ -437,12 +560,9 @@ public class BluetoothCodecStatusTest extends TestCase { assertTrue(BCS_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_B)); assertFalse(BCS_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_C)); - assertTrue(BCS_A.getCodecsSelectableCapabilities() - .equals(SELECTABLE_CAPABILITY_A)); - assertTrue(BCS_A.getCodecsSelectableCapabilities() - .equals(SELECTABLE_CAPABILITY_B)); - assertFalse(BCS_A.getCodecsSelectableCapabilities() - .equals(SELECTABLE_CAPABILITY_C)); + assertTrue(BCS_A.getCodecsSelectableCapabilities().equals(SELECTABLE_CAPABILITY_A)); + assertTrue(BCS_A.getCodecsSelectableCapabilities().equals(SELECTABLE_CAPABILITY_B)); + assertFalse(BCS_A.getCodecsSelectableCapabilities().equals(SELECTABLE_CAPABILITY_C)); } @SmallTest @@ -455,20 +575,26 @@ public class BluetoothCodecStatusTest extends TestCase { assertFalse(BCS_C.equals(BCS_A)); } - private static BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType, - int codecPriority, int sampleRate, int bitsPerSample, int channelMode, - long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) { + private static BluetoothCodecConfig buildBluetoothCodecConfig( + int sourceCodecType, + int codecPriority, + int sampleRate, + int bitsPerSample, + int channelMode, + long codecSpecific1, + long codecSpecific2, + long codecSpecific3, + long codecSpecific4) { return new BluetoothCodecConfig.Builder() - .setCodecType(sourceCodecType) - .setCodecPriority(codecPriority) - .setSampleRate(sampleRate) - .setBitsPerSample(bitsPerSample) - .setChannelMode(channelMode) - .setCodecSpecific1(codecSpecific1) - .setCodecSpecific2(codecSpecific2) - .setCodecSpecific3(codecSpecific3) - .setCodecSpecific4(codecSpecific4) - .build(); - + .setCodecType(sourceCodecType) + .setCodecPriority(codecPriority) + .setSampleRate(sampleRate) + .setBitsPerSample(bitsPerSample) + .setChannelMode(channelMode) + .setCodecSpecific1(codecSpecific1) + .setCodecSpecific2(codecSpecific2) + .setCodecSpecific3(codecSpecific3) + .setCodecSpecific4(codecSpecific4) + .build(); } } diff --git a/framework/tests/unit/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java b/framework/tests/unit/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java index c3d707cd759696a112bdb86ebca8c9ab7b738afa..b3e88970f2d47f5dfeea9fec2c8f2ae037d837df 100644 --- a/framework/tests/unit/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java +++ b/framework/tests/unit/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java @@ -20,14 +20,13 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; -/** - * Unit test cases for {@link BluetoothLeAudioCodecConfig}. - */ +/** Unit test cases for {@link BluetoothLeAudioCodecConfig}. */ public class BluetoothLeAudioCodecConfigTest extends TestCase { - private int[] mCodecTypeArray = new int[] { - BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3, - BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID, - }; + private int[] mCodecTypeArray = + new int[] { + BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3, + BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID, + }; @SmallTest public void testBluetoothLeAudioCodecConfig_valid_get_methods() { @@ -50,9 +49,6 @@ public class BluetoothLeAudioCodecConfigTest extends TestCase { } private BluetoothLeAudioCodecConfig buildBluetoothLeAudioCodecConfig(int sourceCodecType) { - return new BluetoothLeAudioCodecConfig.Builder() - .setCodecType(sourceCodecType) - .build(); - + return new BluetoothLeAudioCodecConfig.Builder().setCodecType(sourceCodecType).build(); } } diff --git a/framework/tests/unit/src/android/bluetooth/BluetoothProfileConnectorTest.java b/framework/tests/unit/src/android/bluetooth/BluetoothProfileConnectorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..63fbcabe23e55c8577ae7ea3c935122f0fb205a4 --- /dev/null +++ b/framework/tests/unit/src/android/bluetooth/BluetoothProfileConnectorTest.java @@ -0,0 +1,241 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +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.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.content.ComponentName; +import android.os.Binder; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.os.test.TestLooper; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; + +/** Test cases for {@link BluetoothProfileConnector}. */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class BluetoothProfileConnectorTest { + static class FakeBluetoothManager extends IBluetoothManager.Default { + private IBluetoothStateChangeCallback mStateChangeCallback; + private IBluetoothProfileServiceConnection mServiceConnection; + private final Handler mHandler; + + private FakeBluetoothManager(Looper looper) { + mHandler = new Handler(looper); + } + + Looper getLooper() { + return mHandler.getLooper(); + } + + @Override + public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { + mStateChangeCallback = callback; + } + + @Override + public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) + throws RemoteException { + if (callback != mStateChangeCallback) throw new IllegalStateException(); + + mStateChangeCallback.onBluetoothStateChange(false); + + mStateChangeCallback = null; + } + + @Override + public boolean bindBluetoothProfileService( + int profile, IBluetoothProfileServiceConnection proxy) { + mServiceConnection = proxy; + return true; + } + + @Override + public void unbindBluetoothProfileService( + int profile, IBluetoothProfileServiceConnection proxy) { + if (proxy != mServiceConnection) throw new IllegalStateException(); + + mHandler.post( + () -> { + try { + proxy.onServiceDisconnected(new ComponentName("pkg", "cls")); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + }); + + mServiceConnection = null; + } + } + + private BluetoothProfileConnector createBluetoothProfileConnector( + BluetoothProfile profile, FakeBluetoothManager bluetoothManager) { + return new BluetoothProfileConnector( + bluetoothManager.getLooper(), profile, BluetoothProfile.HEADSET, bluetoothManager); + } + + @Test + public void bind_registerServiceConnection() throws RemoteException { + TestLooper looper = new TestLooper(); + FakeBluetoothManager bluetoothManager = new FakeBluetoothManager(looper.getLooper()); + BluetoothProfileConnector connector = + createBluetoothProfileConnector(null, bluetoothManager); + BluetoothProfile.ServiceListener listener = mock(BluetoothProfile.ServiceListener.class); + + connector.connect("test.package", listener); + bluetoothManager.mStateChangeCallback.onBluetoothStateChange(true); + looper.dispatchAll(); + + assertThat(bluetoothManager.mServiceConnection).isNotNull(); + verifyZeroInteractions(listener); + } + + @Test + public void unbind_unregisterServiceConnection() throws RemoteException { + TestLooper looper = new TestLooper(); + FakeBluetoothManager bluetoothManager = new FakeBluetoothManager(looper.getLooper()); + BluetoothProfile profile = mock(BluetoothProfile.class); + BluetoothProfileConnector connector = + createBluetoothProfileConnector(profile, bluetoothManager); + ComponentName componentName = new ComponentName("pkg", "cls"); + BluetoothProfile.ServiceListener listener = mock(BluetoothProfile.ServiceListener.class); + + connector.connect("test.package", listener); + bluetoothManager.mStateChangeCallback.onBluetoothStateChange(true); + bluetoothManager.mServiceConnection.onServiceConnected(componentName, new Binder()); + looper.dispatchAll(); + bluetoothManager.mServiceConnection.onServiceDisconnected(componentName); + bluetoothManager.mStateChangeCallback.onBluetoothStateChange(false); + looper.dispatchAll(); + + assertThat(bluetoothManager.mServiceConnection).isNull(); + InOrder order = inOrder(listener, profile); + order.verify(profile).onServiceConnected(any()); + order.verify(listener).onServiceConnected(anyInt(), any()); + order.verify(profile).onServiceDisconnected(); + order.verify(listener).onServiceDisconnected(anyInt()); + verifyNoMoreInteractions(listener); + } + + @Test + public void upThenDown_unregisterServiceConnection() throws RemoteException { + TestLooper looper = new TestLooper(); + FakeBluetoothManager bluetoothManager = new FakeBluetoothManager(looper.getLooper()); + BluetoothProfile profile = mock(BluetoothProfile.class); + BluetoothProfileConnector connector = + createBluetoothProfileConnector(profile, bluetoothManager); + BluetoothProfile.ServiceListener listener = mock(BluetoothProfile.ServiceListener.class); + + connector.connect("test.package", listener); + bluetoothManager.mStateChangeCallback.onBluetoothStateChange(true); + bluetoothManager.mStateChangeCallback.onBluetoothStateChange(false); + looper.dispatchAll(); + + assertThat(bluetoothManager.mServiceConnection).isNull(); + verifyZeroInteractions(listener); + } + + @Test + public void disconnectAfterConnect_unregisterCallbacks() { + TestLooper looper = new TestLooper(); + FakeBluetoothManager bluetoothManager = new FakeBluetoothManager(looper.getLooper()); + BluetoothProfileConnector connector = + createBluetoothProfileConnector(null, bluetoothManager); + BluetoothProfile.ServiceListener listener = mock(BluetoothProfile.ServiceListener.class); + + connector.connect("test.package", listener); + connector.disconnect(); + looper.dispatchAll(); + + assertThat(bluetoothManager.mServiceConnection).isNull(); + assertThat(bluetoothManager.mStateChangeCallback).isNull(); + InOrder order = inOrder(listener); + // TODO(b/309635805): This should not be here + order.verify(listener).onServiceDisconnected(anyInt()); + verifyNoMoreInteractions(listener); + } + + @Test + public void disconnectAfterBind_unregisterCallbacks() throws RemoteException { + TestLooper looper = new TestLooper(); + FakeBluetoothManager bluetoothManager = new FakeBluetoothManager(looper.getLooper()); + BluetoothProfile profile = mock(BluetoothProfile.class); + BluetoothProfileConnector connector = + createBluetoothProfileConnector(profile, bluetoothManager); + BluetoothProfile.ServiceListener listener = mock(BluetoothProfile.ServiceListener.class); + + connector.connect("test.package", listener); + bluetoothManager.mStateChangeCallback.onBluetoothStateChange(true); + looper.dispatchAll(); + connector.disconnect(); + looper.dispatchAll(); + + assertThat(bluetoothManager.mServiceConnection).isNull(); + assertThat(bluetoothManager.mStateChangeCallback).isNull(); + InOrder order = inOrder(listener, profile); + // TODO(b/309635805): This should not be here + order.verify(listener).onServiceDisconnected(anyInt()); + order.verify(profile).onServiceDisconnected(); + verifyNoMoreInteractions(listener); + } + + @Test + public void disconnectAfterUnbind_unregisterCallbacks() throws RemoteException { + TestLooper looper = new TestLooper(); + FakeBluetoothManager bluetoothManager = new FakeBluetoothManager(looper.getLooper()); + BluetoothProfile profile = mock(BluetoothProfile.class); + BluetoothProfileConnector connector = + createBluetoothProfileConnector(profile, bluetoothManager); + ComponentName componentName = new ComponentName("pkg", "cls"); + BluetoothProfile.ServiceListener listener = mock(BluetoothProfile.ServiceListener.class); + + connector.connect("test.package", listener); + bluetoothManager.mStateChangeCallback.onBluetoothStateChange(true); + bluetoothManager.mServiceConnection.onServiceConnected(componentName, new Binder()); + looper.dispatchAll(); + bluetoothManager.mServiceConnection.onServiceDisconnected(componentName); + bluetoothManager.mStateChangeCallback.onBluetoothStateChange(false); + looper.dispatchAll(); + connector.disconnect(); + looper.dispatchAll(); + + assertThat(bluetoothManager.mServiceConnection).isNull(); + assertThat(bluetoothManager.mStateChangeCallback).isNull(); + InOrder order = inOrder(listener, profile); + order.verify(profile).onServiceConnected(any()); + order.verify(listener).onServiceConnected(anyInt(), any()); + order.verify(profile).onServiceDisconnected(); + // TODO(b/309635805): Should be only one + order.verify(listener, times(2)).onServiceDisconnected(anyInt()); + verifyNoMoreInteractions(listener); + } +} diff --git a/framework/tests/unit/src/android/bluetooth/BluetoothUuidTest.java b/framework/tests/unit/src/android/bluetooth/BluetoothUuidTest.java index 4087dc58922339f6a9ef27d1d4686744578e2b2b..b3d7758396e3689f1eceb6f08462aabb3505f9ff 100644 --- a/framework/tests/unit/src/android/bluetooth/BluetoothUuidTest.java +++ b/framework/tests/unit/src/android/bluetooth/BluetoothUuidTest.java @@ -21,43 +21,62 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; -/** - * Unit test cases for {@link BluetoothUuid}. - */ +/** Unit test cases for {@link BluetoothUuid}. */ public class BluetoothUuidTest extends TestCase { @SmallTest public void testUuidParser() { - byte[] uuid16 = new byte[] { - 0x0B, 0x11 }; - assertEquals(ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"), + byte[] uuid16 = new byte[] {0x0B, 0x11}; + assertEquals( + ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"), BluetoothUuid.parseUuidFrom(uuid16)); - byte[] uuid32 = new byte[] { - 0x0B, 0x11, 0x33, (byte) 0xFE }; - assertEquals(ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"), + byte[] uuid32 = new byte[] {0x0B, 0x11, 0x33, (byte) 0xFE}; + assertEquals( + ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"), BluetoothUuid.parseUuidFrom(uuid32)); - byte[] uuid128 = new byte[] { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, (byte) 0xFF }; - assertEquals(ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-060504030201"), + byte[] uuid128 = + new byte[] { + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + (byte) 0xFF + }; + assertEquals( + ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-060504030201"), BluetoothUuid.parseUuidFrom(uuid128)); } @SmallTest public void testUuidType() { - assertTrue(BluetoothUuid.is16BitUuid( - ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"))); - assertFalse(BluetoothUuid.is32BitUuid( - ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"))); - - assertFalse(BluetoothUuid.is16BitUuid( - ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"))); - assertTrue(BluetoothUuid.is32BitUuid( - ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"))); - assertFalse(BluetoothUuid.is32BitUuid( - ParcelUuid.fromString("FE33110B-1000-1000-8000-00805F9B34FB"))); + assertTrue( + BluetoothUuid.is16BitUuid( + ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"))); + assertFalse( + BluetoothUuid.is32BitUuid( + ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"))); + assertFalse( + BluetoothUuid.is16BitUuid( + ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"))); + assertTrue( + BluetoothUuid.is32BitUuid( + ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"))); + assertFalse( + BluetoothUuid.is32BitUuid( + ParcelUuid.fromString("FE33110B-1000-1000-8000-00805F9B34FB"))); } } diff --git a/framework/tests/unit/src/android/bluetooth/SdpDipRecordTest.java b/framework/tests/unit/src/android/bluetooth/SdpDipRecordTest.java index 0ce85bf0e72af11105d3e6e5b17fe5d2686724e1..b8a0d48f6665fde1a633ca77b55fe63be094cb9e 100644 --- a/framework/tests/unit/src/android/bluetooth/SdpDipRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/SdpDipRecordTest.java @@ -26,9 +26,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -/** - * Test cases for {@link SdpDipRecord}. - */ +/** Test cases for {@link SdpDipRecord}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class SdpDipRecordTest { @@ -42,14 +40,14 @@ public class SdpDipRecordTest { int version = 1; boolean primaryRecord = true; - SdpDipRecord record = new SdpDipRecord( - specificationId, - vendorId, - vendorIdSource, - productId, - version, - primaryRecord - ); + SdpDipRecord record = + new SdpDipRecord( + specificationId, + vendorId, + vendorIdSource, + productId, + version, + primaryRecord); assertThat(record.getSpecificationId()).isEqualTo(specificationId); assertThat(record.getVendorId()).isEqualTo(vendorId); @@ -68,14 +66,14 @@ public class SdpDipRecordTest { int version = 1; boolean primaryRecord = true; - SdpDipRecord originalRecord = new SdpDipRecord( - specificationId, - vendorId, - vendorIdSource, - productId, - version, - primaryRecord - ); + SdpDipRecord originalRecord = + new SdpDipRecord( + specificationId, + vendorId, + vendorIdSource, + productId, + version, + primaryRecord); Parcel parcel = Parcel.obtain(); originalRecord.writeToParcel(parcel, 0); @@ -84,17 +82,11 @@ public class SdpDipRecordTest { SdpDipRecord recordOut = (SdpDipRecord) SdpDipRecord.CREATOR.createFromParcel(parcel); parcel.recycle(); - assertThat(recordOut.getSpecificationId()) - .isEqualTo(originalRecord.getSpecificationId()); - assertThat(recordOut.getVendorId()) - .isEqualTo(originalRecord.getVendorId()); - assertThat(recordOut.getVendorIdSource()) - .isEqualTo(originalRecord.getVendorIdSource()); - assertThat(recordOut.getProductId()) - .isEqualTo(originalRecord.getProductId()); - assertThat(recordOut.getVersion()) - .isEqualTo(originalRecord.getVersion()); - assertThat(recordOut.getPrimaryRecord()) - .isEqualTo(originalRecord.getPrimaryRecord()); + assertThat(recordOut.getSpecificationId()).isEqualTo(originalRecord.getSpecificationId()); + assertThat(recordOut.getVendorId()).isEqualTo(originalRecord.getVendorId()); + assertThat(recordOut.getVendorIdSource()).isEqualTo(originalRecord.getVendorIdSource()); + assertThat(recordOut.getProductId()).isEqualTo(originalRecord.getProductId()); + assertThat(recordOut.getVersion()).isEqualTo(originalRecord.getVersion()); + assertThat(recordOut.getPrimaryRecord()).isEqualTo(originalRecord.getPrimaryRecord()); } } diff --git a/framework/tests/unit/src/android/bluetooth/SdpMasRecordTest.java b/framework/tests/unit/src/android/bluetooth/SdpMasRecordTest.java index 724ab7daff06e517909e247f4050553af63e1f85..4575e0104f82ede7cd369a69aaf442bc4414c070 100644 --- a/framework/tests/unit/src/android/bluetooth/SdpMasRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/SdpMasRecordTest.java @@ -26,9 +26,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -/** - * Test cases for {@link SdpMasRecord}. - */ +/** Test cases for {@link SdpMasRecord}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class SdpMasRecordTest { @@ -43,15 +41,15 @@ public class SdpMasRecordTest { int supportedMessageTypes = 1; String serviceName = "MasRecord"; - SdpMasRecord record = new SdpMasRecord( - masInstanceId, - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - supportedMessageTypes, - serviceName - ); + SdpMasRecord record = + new SdpMasRecord( + masInstanceId, + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + supportedMessageTypes, + serviceName); assertThat(record.getMasInstanceId()).isEqualTo(masInstanceId); assertThat(record.getL2capPsm()).isEqualTo(l2capPsm); @@ -72,15 +70,15 @@ public class SdpMasRecordTest { int supportedMessageTypes = 1; String serviceName = "MasRecord"; - SdpMasRecord originalRecord = new SdpMasRecord( - masInstanceId, - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - supportedMessageTypes, - serviceName - ); + SdpMasRecord originalRecord = + new SdpMasRecord( + masInstanceId, + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + supportedMessageTypes, + serviceName); Parcel parcel = Parcel.obtain(); originalRecord.writeToParcel(parcel, 0); @@ -89,20 +87,16 @@ public class SdpMasRecordTest { SdpMasRecord recordOut = (SdpMasRecord) SdpMasRecord.CREATOR.createFromParcel(parcel); parcel.recycle(); - assertThat(recordOut.getMasInstanceId()) - .isEqualTo(originalRecord.getMasInstanceId()); - assertThat(recordOut.getL2capPsm()) - .isEqualTo(originalRecord.getL2capPsm()); + assertThat(recordOut.getMasInstanceId()).isEqualTo(originalRecord.getMasInstanceId()); + assertThat(recordOut.getL2capPsm()).isEqualTo(originalRecord.getL2capPsm()); assertThat(recordOut.getRfcommCannelNumber()) .isEqualTo(originalRecord.getRfcommCannelNumber()); - assertThat(recordOut.getProfileVersion()) - .isEqualTo(originalRecord.getProfileVersion()); + assertThat(recordOut.getProfileVersion()).isEqualTo(originalRecord.getProfileVersion()); assertThat(recordOut.getSupportedFeatures()) .isEqualTo(originalRecord.getSupportedFeatures()); assertThat(recordOut.getSupportedMessageTypes()) .isEqualTo(originalRecord.getSupportedMessageTypes()); - assertThat(recordOut.getServiceName()) - .isEqualTo(originalRecord.getServiceName()); + assertThat(recordOut.getServiceName()).isEqualTo(originalRecord.getServiceName()); } @Test @@ -115,25 +109,40 @@ public class SdpMasRecordTest { int supportedMessageTypes = 1; String serviceName = "MasRecord"; - SdpMasRecord record = new SdpMasRecord( - masInstanceId, - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - supportedMessageTypes, - serviceName - ); + SdpMasRecord record = + new SdpMasRecord( + masInstanceId, + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + supportedMessageTypes, + serviceName); String sdpMasRecordString = record.toString(); - String expectedToString = "Bluetooth MAS SDP Record:\n" - + "Mas Instance Id: " + masInstanceId + "\n" - + "RFCOMM Chan Number: " + l2capPsm + "\n" - + "L2CAP PSM: " + rfcommChannelNumber + "\n" - + "Service Name: " + serviceName + "\n" - + "Profile version: " + profileVersion + "\n" - + "Supported msg types: " + supportedMessageTypes + "\n" - + "Supported features: " + supportedFeatures + "\n"; + String expectedToString = + "Bluetooth MAS SDP Record:\n" + + "Mas Instance Id: " + + masInstanceId + + "\n" + + "RFCOMM Chan Number: " + + l2capPsm + + "\n" + + "L2CAP PSM: " + + rfcommChannelNumber + + "\n" + + "Service Name: " + + serviceName + + "\n" + + "Profile version: " + + profileVersion + + "\n" + + "Supported msg types: " + + supportedMessageTypes + + "\n" + + "Supported features: " + + supportedFeatures + + "\n"; assertThat(sdpMasRecordString).isEqualTo(expectedToString); } diff --git a/framework/tests/unit/src/android/bluetooth/SdpMnsRecordTest.java b/framework/tests/unit/src/android/bluetooth/SdpMnsRecordTest.java index d5e11367213640dd30ddf1eb36be7d2167303b3c..5e686d1bfc7fb2c81d3a1f39434908c11ad412aa 100644 --- a/framework/tests/unit/src/android/bluetooth/SdpMnsRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/SdpMnsRecordTest.java @@ -26,9 +26,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -/** - * Test cases for {@link SdpMnsRecord}. - */ +/** Test cases for {@link SdpMnsRecord}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class SdpMnsRecordTest { @@ -41,13 +39,13 @@ public class SdpMnsRecordTest { int supportedFeatures = 1; String serviceName = "MnsRecord"; - SdpMnsRecord record = new SdpMnsRecord( - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - serviceName - ); + SdpMnsRecord record = + new SdpMnsRecord( + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + serviceName); assertThat(record.getL2capPsm()).isEqualTo(l2capPsm); assertThat(record.getRfcommChannelNumber()).isEqualTo(rfcommChannelNumber); @@ -64,13 +62,13 @@ public class SdpMnsRecordTest { int supportedFeatures = 1; String serviceName = "MnsRecord"; - SdpMnsRecord originalRecord = new SdpMnsRecord( - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - serviceName - ); + SdpMnsRecord originalRecord = + new SdpMnsRecord( + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + serviceName); Parcel parcel = Parcel.obtain(); originalRecord.writeToParcel(parcel, 0); @@ -79,16 +77,13 @@ public class SdpMnsRecordTest { SdpMnsRecord recordOut = (SdpMnsRecord) SdpMnsRecord.CREATOR.createFromParcel(parcel); parcel.recycle(); - assertThat(recordOut.getL2capPsm()) - .isEqualTo(originalRecord.getL2capPsm()); + assertThat(recordOut.getL2capPsm()).isEqualTo(originalRecord.getL2capPsm()); assertThat(recordOut.getRfcommChannelNumber()) .isEqualTo(originalRecord.getRfcommChannelNumber()); - assertThat(recordOut.getProfileVersion()) - .isEqualTo(originalRecord.getProfileVersion()); + assertThat(recordOut.getProfileVersion()).isEqualTo(originalRecord.getProfileVersion()); assertThat(recordOut.getSupportedFeatures()) .isEqualTo(originalRecord.getSupportedFeatures()); - assertThat(recordOut.getServiceName()) - .isEqualTo(originalRecord.getServiceName()); + assertThat(recordOut.getServiceName()).isEqualTo(originalRecord.getServiceName()); } @Test @@ -99,21 +94,32 @@ public class SdpMnsRecordTest { int supportedFeatures = 1; String serviceName = "MnsRecord"; - SdpMnsRecord record = new SdpMnsRecord( - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - serviceName - ); + SdpMnsRecord record = + new SdpMnsRecord( + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + serviceName); String sdpMnsRecordString = record.toString(); - String expectedToString = "Bluetooth MNS SDP Record:\n" - + "RFCOMM Chan Number: " + rfcommChannelNumber + "\n" - + "L2CAP PSM: " + l2capPsm + "\n" - + "Service Name: " + serviceName + "\n" - + "Supported features: " + supportedFeatures + "\n" - + "Profile_version: " + profileVersion + "\n"; + String expectedToString = + "Bluetooth MNS SDP Record:\n" + + "RFCOMM Chan Number: " + + rfcommChannelNumber + + "\n" + + "L2CAP PSM: " + + l2capPsm + + "\n" + + "Service Name: " + + serviceName + + "\n" + + "Supported features: " + + supportedFeatures + + "\n" + + "Profile_version: " + + profileVersion + + "\n"; assertThat(sdpMnsRecordString).isEqualTo(expectedToString); } diff --git a/framework/tests/unit/src/android/bluetooth/SdpOppOpsRecordTest.java b/framework/tests/unit/src/android/bluetooth/SdpOppOpsRecordTest.java index 521133cecc5bab43d8a1a7d87904d227d4431eee..dcff94073dfe49fc64ef52d0903e976eef4428dd 100644 --- a/framework/tests/unit/src/android/bluetooth/SdpOppOpsRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/SdpOppOpsRecordTest.java @@ -28,9 +28,7 @@ import org.junit.runner.RunWith; import java.util.Arrays; -/** - * Test cases for {@link SdpOppOpsRecord}. - */ +/** Test cases for {@link SdpOppOpsRecord}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class SdpOppOpsRecordTest { @@ -41,15 +39,10 @@ public class SdpOppOpsRecordTest { int rfcommChannel = 1; int l2capPsm = 1; int version = 1; - byte[] formatsList = new byte[]{0x01}; + byte[] formatsList = new byte[] {0x01}; - SdpOppOpsRecord record = new SdpOppOpsRecord( - serviceName, - rfcommChannel, - l2capPsm, - version, - formatsList - ); + SdpOppOpsRecord record = + new SdpOppOpsRecord(serviceName, rfcommChannel, l2capPsm, version, formatsList); assertThat(record.getServiceName()).isEqualTo(serviceName); assertThat(record.getRfcommChannel()).isEqualTo(rfcommChannel); @@ -64,15 +57,10 @@ public class SdpOppOpsRecordTest { int rfcommChannel = 1; int l2capPsm = 1; int version = 1; - byte[] formatsList = new byte[]{0x01}; + byte[] formatsList = new byte[] {0x01}; - SdpOppOpsRecord originalRecord = new SdpOppOpsRecord( - serviceName, - rfcommChannel, - l2capPsm, - version, - formatsList - ); + SdpOppOpsRecord originalRecord = + new SdpOppOpsRecord(serviceName, rfcommChannel, l2capPsm, version, formatsList); Parcel parcel = Parcel.obtain(); originalRecord.writeToParcel(parcel, 0); @@ -82,18 +70,12 @@ public class SdpOppOpsRecordTest { (SdpOppOpsRecord) SdpOppOpsRecord.CREATOR.createFromParcel(parcel); parcel.recycle(); - assertThat(recordOut.getServiceName()) - .isEqualTo(originalRecord.getServiceName()); - assertThat(recordOut.getRfcommChannel()) - .isEqualTo(originalRecord.getRfcommChannel()); - assertThat(recordOut.getL2capPsm()) - .isEqualTo(originalRecord.getL2capPsm()); - assertThat(recordOut.getProfileVersion()) - .isEqualTo(originalRecord.getProfileVersion()); - assertThat(recordOut.getProfileVersion()) - .isEqualTo(originalRecord.getProfileVersion()); - assertThat(recordOut.getFormatsList()) - .isEqualTo(originalRecord.getFormatsList()); + assertThat(recordOut.getServiceName()).isEqualTo(originalRecord.getServiceName()); + assertThat(recordOut.getRfcommChannel()).isEqualTo(originalRecord.getRfcommChannel()); + assertThat(recordOut.getL2capPsm()).isEqualTo(originalRecord.getL2capPsm()); + assertThat(recordOut.getProfileVersion()).isEqualTo(originalRecord.getProfileVersion()); + assertThat(recordOut.getProfileVersion()).isEqualTo(originalRecord.getProfileVersion()); + assertThat(recordOut.getFormatsList()).isEqualTo(originalRecord.getFormatsList()); } @Test @@ -102,23 +84,28 @@ public class SdpOppOpsRecordTest { int rfcommChannel = 1; int l2capPsm = 1; int version = 1; - byte[] formatsList = new byte[]{0x01}; + byte[] formatsList = new byte[] {0x01}; - SdpOppOpsRecord record = new SdpOppOpsRecord( - serviceName, - rfcommChannel, - l2capPsm, - version, - formatsList - ); + SdpOppOpsRecord record = + new SdpOppOpsRecord(serviceName, rfcommChannel, l2capPsm, version, formatsList); String sdpOppOpsRecordString = record.toString(); - String expectedToString = "Bluetooth OPP Server SDP Record:\n" - + " RFCOMM Chan Number: " + rfcommChannel + "\n" - + " L2CAP PSM: " + l2capPsm + "\n" - + " Profile version: " + version + "\n" - + " Service Name: " + serviceName + "\n" - + " Formats List: " + Arrays.toString(formatsList); + String expectedToString = + "Bluetooth OPP Server SDP Record:\n" + + " RFCOMM Chan Number: " + + rfcommChannel + + "\n" + + " L2CAP PSM: " + + l2capPsm + + "\n" + + " Profile version: " + + version + + "\n" + + " Service Name: " + + serviceName + + "\n" + + " Formats List: " + + Arrays.toString(formatsList); assertThat(sdpOppOpsRecordString).isEqualTo(expectedToString); } diff --git a/framework/tests/unit/src/android/bluetooth/SdpPseRecordTest.java b/framework/tests/unit/src/android/bluetooth/SdpPseRecordTest.java index 0332d4acb358611d1f867d289d67eb3760c4f5d0..c9eeaa29409f41c40aaaad57c07573735208f354 100644 --- a/framework/tests/unit/src/android/bluetooth/SdpPseRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/SdpPseRecordTest.java @@ -26,9 +26,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -/** - * Test cases for {@link SdpPseRecord}. - */ +/** Test cases for {@link SdpPseRecord}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class SdpPseRecordTest { @@ -42,14 +40,14 @@ public class SdpPseRecordTest { int supportedRepositories = 1; String serviceName = "PseRecord"; - SdpPseRecord record = new SdpPseRecord( - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - supportedRepositories, - serviceName - ); + SdpPseRecord record = + new SdpPseRecord( + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + supportedRepositories, + serviceName); assertThat(record.getL2capPsm()).isEqualTo(l2capPsm); assertThat(record.getRfcommChannelNumber()).isEqualTo(rfcommChannelNumber); @@ -68,14 +66,14 @@ public class SdpPseRecordTest { int supportedRepositories = 1; String serviceName = "PseRecord"; - SdpPseRecord originalRecord = new SdpPseRecord( - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - supportedRepositories, - serviceName - ); + SdpPseRecord originalRecord = + new SdpPseRecord( + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + supportedRepositories, + serviceName); Parcel parcel = Parcel.obtain(); originalRecord.writeToParcel(parcel, 0); @@ -84,18 +82,15 @@ public class SdpPseRecordTest { SdpPseRecord recordOut = (SdpPseRecord) SdpPseRecord.CREATOR.createFromParcel(parcel); parcel.recycle(); - assertThat(recordOut.getL2capPsm()) - .isEqualTo(originalRecord.getL2capPsm()); + assertThat(recordOut.getL2capPsm()).isEqualTo(originalRecord.getL2capPsm()); assertThat(recordOut.getRfcommChannelNumber()) .isEqualTo(originalRecord.getRfcommChannelNumber()); - assertThat(recordOut.getProfileVersion()) - .isEqualTo(originalRecord.getProfileVersion()); + assertThat(recordOut.getProfileVersion()).isEqualTo(originalRecord.getProfileVersion()); assertThat(recordOut.getSupportedFeatures()) .isEqualTo(originalRecord.getSupportedFeatures()); assertThat(recordOut.getSupportedRepositories()) .isEqualTo(originalRecord.getSupportedRepositories()); - assertThat(recordOut.getServiceName()) - .isEqualTo(originalRecord.getServiceName()); + assertThat(recordOut.getServiceName()).isEqualTo(originalRecord.getServiceName()); } @Test @@ -107,23 +102,36 @@ public class SdpPseRecordTest { int supportedRepositories = 1; String serviceName = "PseRecord"; - SdpPseRecord record = new SdpPseRecord( - l2capPsm, - rfcommChannelNumber, - profileVersion, - supportedFeatures, - supportedRepositories, - serviceName - ); + SdpPseRecord record = + new SdpPseRecord( + l2capPsm, + rfcommChannelNumber, + profileVersion, + supportedFeatures, + supportedRepositories, + serviceName); String sdpPseRecordString = record.toString(); - String expectedToString = "Bluetooth MNS SDP Record:\n" - + "RFCOMM Chan Number: " + rfcommChannelNumber + "\n" - + "L2CAP PSM: " + l2capPsm + "\n" - + "profile version: " + profileVersion + "\n" - + "Service Name: " + serviceName + "\n" - + "Supported features: " + supportedFeatures + "\n" - + "Supported repositories: " + supportedRepositories + "\n"; + String expectedToString = + "Bluetooth MNS SDP Record:\n" + + "RFCOMM Chan Number: " + + rfcommChannelNumber + + "\n" + + "L2CAP PSM: " + + l2capPsm + + "\n" + + "profile version: " + + profileVersion + + "\n" + + "Service Name: " + + serviceName + + "\n" + + "Supported features: " + + supportedFeatures + + "\n" + + "Supported repositories: " + + supportedRepositories + + "\n"; assertThat(sdpPseRecordString).isEqualTo(expectedToString); } diff --git a/framework/tests/unit/src/android/bluetooth/SdpRecordTest.java b/framework/tests/unit/src/android/bluetooth/SdpRecordTest.java index 95a804e19e78f3ac9e2b024a709972f9a4825088..f7afe42688044561fed37222d8a1570773577014 100644 --- a/framework/tests/unit/src/android/bluetooth/SdpRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/SdpRecordTest.java @@ -28,9 +28,7 @@ import org.junit.runner.RunWith; import java.util.Arrays; -/** - * Test cases for {@link SdpRecord}. - */ +/** Test cases for {@link SdpRecord}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class SdpRecordTest { @@ -38,12 +36,9 @@ public class SdpRecordTest { @Test public void createSdpRecord() { int rawSize = 1; - byte[] rawData = new byte[]{0x1}; + byte[] rawData = new byte[] {0x1}; - SdpRecord record = new SdpRecord( - rawSize, - rawData - ); + SdpRecord record = new SdpRecord(rawSize, rawData); assertThat(record.getRawSize()).isEqualTo(rawSize); assertThat(record.getRawData()).isEqualTo(rawData); @@ -52,12 +47,9 @@ public class SdpRecordTest { @Test public void writeToParcel() { int rawSize = 1; - byte[] rawData = new byte[]{0x1}; + byte[] rawData = new byte[] {0x1}; - SdpRecord originalRecord = new SdpRecord( - rawSize, - rawData - ); + SdpRecord originalRecord = new SdpRecord(rawSize, rawData); Parcel parcel = Parcel.obtain(); originalRecord.writeToParcel(parcel, 0); @@ -66,25 +58,24 @@ public class SdpRecordTest { SdpRecord recordOut = (SdpRecord) SdpRecord.CREATOR.createFromParcel(parcel); parcel.recycle(); - assertThat(recordOut.getRawSize()) - .isEqualTo(originalRecord.getRawSize()); - assertThat(recordOut.getRawData()) - .isEqualTo(originalRecord.getRawData()); + assertThat(recordOut.getRawSize()).isEqualTo(originalRecord.getRawSize()); + assertThat(recordOut.getRawData()).isEqualTo(originalRecord.getRawData()); } @Test public void sdpRecordToString() { int rawSize = 1; - byte[] rawData = new byte[]{0x1}; + byte[] rawData = new byte[] {0x1}; - SdpRecord record = new SdpRecord( - rawSize, - rawData - ); + SdpRecord record = new SdpRecord(rawSize, rawData); String sdpRecordString = record.toString(); - String expectedToString = "BluetoothSdpRecord [rawData=" + Arrays.toString(rawData) - + ", rawSize=" + rawSize + "]"; + String expectedToString = + "BluetoothSdpRecord [rawData=" + + Arrays.toString(rawData) + + ", rawSize=" + + rawSize + + "]"; assertThat(sdpRecordString).isEqualTo(expectedToString); } diff --git a/framework/tests/unit/src/android/bluetooth/SdpSapsRecordTest.java b/framework/tests/unit/src/android/bluetooth/SdpSapsRecordTest.java index cdca38cf0862770f49baf0835daf50c5ba57a990..eedfb9ac647bb724d57459224cd58a6cecd61fc9 100644 --- a/framework/tests/unit/src/android/bluetooth/SdpSapsRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/SdpSapsRecordTest.java @@ -26,9 +26,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -/** - * Test cases for {@link SdpSapsRecord}. - */ +/** Test cases for {@link SdpSapsRecord}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class SdpSapsRecordTest { @@ -39,11 +37,7 @@ public class SdpSapsRecordTest { int profileVersion = 1; String serviceName = "SdpSapsRecord"; - SdpSapsRecord record = new SdpSapsRecord( - rfcommChannelNumber, - profileVersion, - serviceName - ); + SdpSapsRecord record = new SdpSapsRecord(rfcommChannelNumber, profileVersion, serviceName); assertThat(record.getRfcommCannelNumber()).isEqualTo(rfcommChannelNumber); assertThat(record.getProfileVersion()).isEqualTo(profileVersion); @@ -56,11 +50,8 @@ public class SdpSapsRecordTest { int profileVersion = 1; String serviceName = "SdpSapsRecord"; - SdpSapsRecord originalRecord = new SdpSapsRecord( - rfcommChannelNumber, - profileVersion, - serviceName - ); + SdpSapsRecord originalRecord = + new SdpSapsRecord(rfcommChannelNumber, profileVersion, serviceName); Parcel parcel = Parcel.obtain(); originalRecord.writeToParcel(parcel, 0); @@ -71,10 +62,8 @@ public class SdpSapsRecordTest { assertThat(recordOut.getRfcommCannelNumber()) .isEqualTo(originalRecord.getRfcommCannelNumber()); - assertThat(recordOut.getProfileVersion()) - .isEqualTo(originalRecord.getProfileVersion()); - assertThat(recordOut.getServiceName()) - .isEqualTo(originalRecord.getServiceName()); + assertThat(recordOut.getProfileVersion()).isEqualTo(originalRecord.getProfileVersion()); + assertThat(recordOut.getServiceName()).isEqualTo(originalRecord.getServiceName()); } @Test @@ -83,17 +72,20 @@ public class SdpSapsRecordTest { int profileVersion = 1; String serviceName = "SdpSapsRecord"; - SdpSapsRecord record = new SdpSapsRecord( - rfcommChannelNumber, - profileVersion, - serviceName - ); + SdpSapsRecord record = new SdpSapsRecord(rfcommChannelNumber, profileVersion, serviceName); String sdpSapsRecordString = record.toString(); - String expectedToString = "Bluetooth MAS SDP Record:\n" - + "RFCOMM Chan Number: " + rfcommChannelNumber + "\n" - + "Service Name: " + serviceName + "\n" - + "Profile version: " + profileVersion + "\n"; + String expectedToString = + "Bluetooth MAS SDP Record:\n" + + "RFCOMM Chan Number: " + + rfcommChannelNumber + + "\n" + + "Service Name: " + + serviceName + + "\n" + + "Profile version: " + + profileVersion + + "\n"; assertThat(sdpSapsRecordString).isEqualTo(expectedToString); } diff --git a/framework/tests/unit/src/android/bluetooth/le/ScanRecordTest.java b/framework/tests/unit/src/android/bluetooth/le/ScanRecordTest.java index b37f80593a2e90a4e8756ec022548ded3b18965c..879ac56c7796d5538e8897e1693dfd9aea687f52 100644 --- a/framework/tests/unit/src/android/bluetooth/le/ScanRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/le/ScanRecordTest.java @@ -31,49 +31,49 @@ import java.util.function.Predicate; /** * Unit test cases for {@link ScanRecord}. - *

    - * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanRecordTest' -w + * + *

    To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanRecordTest' -w * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner' */ public class ScanRecordTest extends TestCase { - /** - * Example raw beacons captured from a Blue Charm BC011 - */ + /** Example raw beacons captured from a Blue Charm BC011 */ private static final String RECORD_URL = "0201060303AAFE1716AAFE10EE01626C7565636861726D626561636F6E730" - + "009168020691E0EFE13551109426C7565436861726D5F313639363835000000"; + + "009168020691E0EFE13551109426C7565436861726D5F313639363835000000"; + private static final String RECORD_UUID = "0201060303AAFE1716AAFE00EE626C7565636861726D3100000000000100000" - + "9168020691E0EFE13551109426C7565436861726D5F313639363835000000"; + + "9168020691E0EFE13551109426C7565436861726D5F313639363835000000"; private static final String RECORD_TLM = "0201060303AAFE1116AAFE20000BF017000008874803FB93540916802069080" - + "EFE13551109426C7565436861726D5F313639363835000000000000000000"; + + "EFE13551109426C7565436861726D5F313639363835000000000000000000"; private static final String RECORD_IBEACON = "0201061AFF4C000215426C7565436861726D426561636F6E730EFE1355C5091" - + "68020691E0EFE13551109426C7565436861726D5F31363936383500000000"; + + "68020691E0EFE13551109426C7565436861726D5F31363936383500000000"; - /** - * Example Eddystone E2EE-EID beacon from design doc - */ + /** Example Eddystone E2EE-EID beacon from design doc */ private static final String RECORD_E2EE_EID = "0201061816AAFE400000000000000000000000000000000000000000"; @SmallTest public void testMatchesAnyField_Eddystone_Parser() { final List found = new ArrayList<>(); - final Predicate matcher = (v) -> { - found.add(HexDump.toHexString(v)); - return false; - }; + final Predicate matcher = + (v) -> { + found.add(HexDump.toHexString(v)); + return false; + }; ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_URL)) .matchesAnyField(matcher); - assertEquals(Arrays.asList( - "020106", - "0303AAFE", - "1716AAFE10EE01626C7565636861726D626561636F6E7300", - "09168020691E0EFE1355", - "1109426C7565436861726D5F313639363835"), found); + assertEquals( + Arrays.asList( + "020106", + "0303AAFE", + "1716AAFE10EE01626C7565636861726D626561636F6E7300", + "09168020691E0EFE1355", + "1109426C7565436861726D5F313639363835"), + found); } @SmallTest @@ -88,8 +88,8 @@ public class ScanRecordTest extends TestCase { @SmallTest public void testMatchesAnyField_Eddystone_ExceptE2eeEid() { - final BytesMatcher matcher = BytesMatcher - .decode("⊈0016AAFE40/00FFFFFFFF,⊆0016AAFE/00FFFFFF"); + final BytesMatcher matcher = + BytesMatcher.decode("⊈0016AAFE40/00FFFFFFFF,⊆0016AAFE/00FFFFFF"); assertMatchesAnyField(RECORD_URL, matcher); assertMatchesAnyField(RECORD_UUID, matcher); assertMatchesAnyField(RECORD_TLM, matcher); @@ -100,18 +100,21 @@ public class ScanRecordTest extends TestCase { @SmallTest public void testMatchesAnyField_iBeacon_Parser() { final List found = new ArrayList<>(); - final Predicate matcher = (v) -> { - found.add(HexDump.toHexString(v)); - return false; - }; + final Predicate matcher = + (v) -> { + found.add(HexDump.toHexString(v)); + return false; + }; ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_IBEACON)) .matchesAnyField(matcher); - assertEquals(Arrays.asList( - "020106", - "1AFF4C000215426C7565436861726D426561636F6E730EFE1355C5", - "09168020691E0EFE1355", - "1109426C7565436861726D5F313639363835"), found); + assertEquals( + Arrays.asList( + "020106", + "1AFF4C000215426C7565436861726D426561636F6E730EFE1355C5", + "09168020691E0EFE1355", + "1109426C7565436861726D5F313639363835"), + found); } @SmallTest @@ -126,15 +129,42 @@ public class ScanRecordTest extends TestCase { @SmallTest public void testParser() { - byte[] scanRecord = new byte[] { - 0x02, 0x01, 0x1a, // advertising flags - 0x05, 0x02, 0x0b, 0x11, 0x0a, 0x11, // 16 bit service uuids - 0x04, 0x09, 0x50, 0x65, 0x64, // name - 0x02, 0x0A, (byte) 0xec, // tx power level - 0x05, 0x16, 0x0b, 0x11, 0x50, 0x64, // service data - 0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data - 0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble - }; + byte[] scanRecord = + new byte[] { + 0x02, + 0x01, + 0x1a, // advertising flags + 0x05, + 0x02, + 0x0b, + 0x11, + 0x0a, + 0x11, // 16 bit service uuids + 0x04, + 0x09, + 0x50, + 0x65, + 0x64, // name + 0x02, + 0x0A, + (byte) 0xec, // tx power level + 0x05, + 0x16, + 0x0b, + 0x11, + 0x50, + 0x64, // service data + 0x05, + (byte) 0xff, + (byte) 0xe0, + 0x00, + 0x02, + 0x15, // manufacturer specific data + 0x03, + 0x50, + 0x01, + 0x02, // an unknown data type won't cause trouble + }; ScanRecord data = ScanRecord.parseFromBytes(scanRecord); assertEquals(0x1a, data.getAdvertiseFlags()); ParcelUuid uuid1 = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); @@ -146,30 +176,33 @@ public class ScanRecordTest extends TestCase { assertEquals(-20, data.getTxPowerLevel()); assertTrue(data.getManufacturerSpecificData().get(0x00E0) != null); - assertArrayEquals(new byte[] { - 0x02, 0x15 }, data.getManufacturerSpecificData().get(0x00E0)); + assertArrayEquals(new byte[] {0x02, 0x15}, data.getManufacturerSpecificData().get(0x00E0)); assertTrue(data.getServiceData().containsKey(uuid2)); - assertArrayEquals(new byte[] { - 0x50, 0x64 }, data.getServiceData().get(uuid2)); + assertArrayEquals(new byte[] {0x50, 0x64}, data.getServiceData().get(uuid2)); } // Assert two byte arrays are equal. private static void assertArrayEquals(byte[] expected, byte[] actual) { if (!Arrays.equals(expected, actual)) { - fail("expected:<" + Arrays.toString(expected) - + "> but was:<" + Arrays.toString(actual) + ">"); + fail( + "expected:<" + + Arrays.toString(expected) + + "> but was:<" + + Arrays.toString(actual) + + ">"); } - } private static void assertMatchesAnyField(String record, BytesMatcher matcher) { - assertTrue(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record)) - .matchesAnyField(matcher)); + assertTrue( + ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record)) + .matchesAnyField(matcher)); } private static void assertNotMatchesAnyField(String record, BytesMatcher matcher) { - assertFalse(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record)) - .matchesAnyField(matcher)); + assertFalse( + ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record)) + .matchesAnyField(matcher)); } } diff --git a/framework/tests/unit/src/android/bluetooth/le/ScanSettingsTest.java b/framework/tests/unit/src/android/bluetooth/le/ScanSettingsTest.java index f0fb173cb72edc40b5ba5a6bcb6f9293c965a7d2..8848c7273c80a81974d782cf8170f3e4e131a5ad 100644 --- a/framework/tests/unit/src/android/bluetooth/le/ScanSettingsTest.java +++ b/framework/tests/unit/src/android/bluetooth/le/ScanSettingsTest.java @@ -20,9 +20,7 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; -/** - * Test for Bluetooth LE {@link ScanSettings}. - */ +/** Test for Bluetooth LE {@link ScanSettings}. */ public class ScanSettingsTest extends TestCase { @SmallTest @@ -64,8 +62,8 @@ public class ScanSettingsTest extends TestCase { try { builder.setCallbackType( ScanSettings.CALLBACK_TYPE_ALL_MATCHES - | ScanSettings.CALLBACK_TYPE_FIRST_MATCH - | ScanSettings.CALLBACK_TYPE_MATCH_LOST); + | ScanSettings.CALLBACK_TYPE_FIRST_MATCH + | ScanSettings.CALLBACK_TYPE_MATCH_LOST); fail("should have thrown IllegalArgumentException!"); } catch (IllegalArgumentException e) { // nothing to do diff --git a/framework/tests/util/Android.bp b/framework/tests/util/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..274746b2e22e2e4df4ad9d673ccde3dc163d2be5 --- /dev/null +++ b/framework/tests/util/Android.bp @@ -0,0 +1,32 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +java_library { + name: "bluetooth-test-util-lib", + defaults: ["cts_defaults"], + static_libs: [ + "PlatformProperties", + "androidx.test.ext.truth", + "compatibility-device-util-axt", + "junit", + ], + srcs: ["src/**/*.java"], + sdk_version: "test_current", + // Keep it public for now to avoid merge conflicts + visibility: ["//visibility:public"], +} diff --git a/framework/tests/util/src/android/bluetooth/cts/BTAdapterUtils.java b/framework/tests/util/src/android/bluetooth/cts/BTAdapterUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..01f18648c5763de598c46db9aab3b4a8d90d629d --- /dev/null +++ b/framework/tests/util/src/android/bluetooth/cts/BTAdapterUtils.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth.cts; + +import android.bluetooth.test_utils.BluetoothAdapterUtils; + +public class BTAdapterUtils extends BluetoothAdapterUtils {} diff --git a/framework/tests/util/src/android/bluetooth/cts/EnableBluetoothRule.java b/framework/tests/util/src/android/bluetooth/cts/EnableBluetoothRule.java new file mode 100644 index 0000000000000000000000000000000000000000..3eb60074463a1c44099621cdd3ac99986d9ea9d8 --- /dev/null +++ b/framework/tests/util/src/android/bluetooth/cts/EnableBluetoothRule.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth.cts; + +public class EnableBluetoothRule extends android.bluetooth.test_utils.EnableBluetoothRule { + /** + * Constructor that allows test mode + * + * @param enableTestMode whether test mode is enabled + * @param toggleBluetooth whether to toggle Bluetooth at the beginning of the test if it is + * already enabled + */ + public EnableBluetoothRule(boolean enableTestMode, boolean toggleBluetooth) { + super(enableTestMode, toggleBluetooth); + } + + /** + * Constructor that allows test mode + * + * @param enableTestMode whether test mode is enabled + */ + public EnableBluetoothRule(boolean enableTestMode) { + super(enableTestMode); + } +} diff --git a/framework/tests/util/src/android/bluetooth/cts/TestUtils.java b/framework/tests/util/src/android/bluetooth/cts/TestUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..35a391692a4f358cd2d643d4fa2a83793eed3a54 --- /dev/null +++ b/framework/tests/util/src/android/bluetooth/cts/TestUtils.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth.cts; + +import static com.google.common.truth.Truth.assertThat; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.sysprop.BluetoothProperties; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.google.errorprone.annotations.InlineMe; + +public class TestUtils extends android.bluetooth.test_utils.TestUtils { + /** + * Get the current enabled status of a given profile. + * + *

    This method also adds default value to profile enable state based on the designed logic of + * the Android framework. For example:
    + * {@link BluetoothProfile#GATT} is always enabled by default
    + * {@link BluetoothProfile#HEARING_AID} should be enabled by default except for Watch, + * Automotive, and TV + * + * @param profile a Bluetooth profile from {@link BluetoothProfile} + * @return true if the profile should be enabled + * @deprecated one should use functions from {@link BluetoothProperties} as much as possible + */ + @Deprecated + public static boolean isProfileEnabled(int profile) { + switch (profile) { + case BluetoothProfile.A2DP -> { + return BluetoothProperties.isProfileA2dpSourceEnabled().orElse(false); + } + case BluetoothProfile.A2DP_SINK -> { + return BluetoothProperties.isProfileA2dpSinkEnabled().orElse(false); + } + // Hidden profile + // case BluetoothProfile.AVRCP: + // return BluetoothProperties.isProfileAvrcpTargetEnabled().orElse(false); + case BluetoothProfile.AVRCP_CONTROLLER -> { + return BluetoothProperties.isProfileAvrcpControllerEnabled().orElse(false); + } + case BluetoothProfile.CSIP_SET_COORDINATOR -> { + return BluetoothProperties.isProfileCsipSetCoordinatorEnabled().orElse(false); + } + case BluetoothProfile.GATT -> { + return BluetoothProperties.isProfileGattEnabled().orElse(true); + } + case BluetoothProfile.HAP_CLIENT -> { + return BluetoothProperties.isProfileHapClientEnabled().orElse(false); + } + case BluetoothProfile.HEADSET -> { + return BluetoothProperties.isProfileHfpAgEnabled().orElse(false); + } + case BluetoothProfile.HEADSET_CLIENT -> { + return BluetoothProperties.isProfileHfpHfEnabled().orElse(false); + } + case BluetoothProfile.HEARING_AID -> { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + if (!isBleSupported(context)) { + return false; + } + boolean default_value = true; + if (isAutomotive(context) || isWatch(context) || isTv(context)) { + default_value = false; + } + return BluetoothProperties.isProfileAshaCentralEnabled().orElse(default_value); + } + case BluetoothProfile.HID_DEVICE -> { + return BluetoothProperties.isProfileHidDeviceEnabled().orElse(false); + } + case BluetoothProfile.HID_HOST -> { + return BluetoothProperties.isProfileHidHostEnabled().orElse(false); + } + case BluetoothProfile.LE_AUDIO -> { + return BluetoothProperties.isProfileBapUnicastClientEnabled().orElse(false); + } + case BluetoothProfile.LE_AUDIO_BROADCAST -> { + return BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false); + } + case BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT -> { + return BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false); + } + // Hidden profile + // case BluetoothProfile.LE_CALL_CONTROL: + // return BluetoothProperties.isProfileCcpServerEnabled().orElse(false); + case BluetoothProfile.MAP -> { + return BluetoothProperties.isProfileMapServerEnabled().orElse(false); + } + case BluetoothProfile.MAP_CLIENT -> { + return BluetoothProperties.isProfileMapClientEnabled().orElse(false); + } + // Hidden profile + // case BluetoothProfile.MCP_SERVER: + // return BluetoothProperties.isProfileMcpServerEnabled().orElse(false); + case BluetoothProfile.OPP -> { + return BluetoothProperties.isProfileOppEnabled().orElse(false); + } + case BluetoothProfile.PAN -> { + return BluetoothProperties.isProfilePanNapEnabled().orElse(false) + || BluetoothProperties.isProfilePanPanuEnabled().orElse(false); + } + case BluetoothProfile.PBAP -> { + return BluetoothProperties.isProfilePbapServerEnabled().orElse(false); + } + case BluetoothProfile.PBAP_CLIENT -> { + return BluetoothProperties.isProfilePbapClientEnabled().orElse(false); + } + case BluetoothProfile.SAP -> { + return BluetoothProperties.isProfileSapServerEnabled().orElse(false); + } + case BluetoothProfile.VOLUME_CONTROL -> { + return BluetoothProperties.isProfileVcpControllerEnabled().orElse(false); + } + default -> { + return false; + } + } + } + + /** + * Get {@link BluetoothAdapter} via {@link android.bluetooth.BluetoothManager} Fail the test if + * {@link BluetoothAdapter} is null + * + * @return instance of {@link BluetoothAdapter} + * @deprecated keeping assert here as many tests currently depend on this method to fail if + * adapter is null + */ + @Deprecated + @NonNull + public static BluetoothAdapter getBluetoothAdapterOrDie() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + BluetoothManager manager = context.getSystemService(BluetoothManager.class); + assertThat(manager).isNotNull(); + BluetoothAdapter adapter = manager.getAdapter(); + assertThat(adapter).isNotNull(); + return adapter; + } + + /** + * Utility method to assert two byte arrays are equal. + * + * @param expected expected value + * @param actual actual value + * @deprecated Please use {@link com.google.common.truth.Truth}, + * "assertThat(actual).isEqualTo(expected)". Keeping it here since some tests are still + * using it. + */ + @Deprecated + @InlineMe( + replacement = "assertThat(actual).isEqualTo(expected)", + staticImports = "com.google.common.truth.Truth.assertThat") + public static void assertArrayEquals(byte[] expected, byte[] actual) { + assertThat(actual).isEqualTo(expected); + } + + /** + * DANGER: Put the current thread to sleep. Please only use this when it is ok to block the + * current thread. + * + * @param sleepMillis number of milliseconds to sleep for + * @deprecated Please try to avoid using this method at all cost, but use asynchronous wait to + * handle timing conditions + */ + @Deprecated + public static void sleep(int sleepMillis) { + try { + Thread.sleep(sleepMillis); + } catch (InterruptedException e) { + Log.e(TAG, "interrupted", e); + } + } +} diff --git a/framework/tests/util/src/android/bluetooth/test_utils/BluetoothAdapterUtils.java b/framework/tests/util/src/android/bluetooth/test_utils/BluetoothAdapterUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..6fa4d3c1ec382a904cf89f8fd15aef7bd0a0977d --- /dev/null +++ b/framework/tests/util/src/android/bluetooth/test_utils/BluetoothAdapterUtils.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth.test_utils; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; + +import android.app.UiAutomation; +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.util.Log; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** Utility for controlling the Bluetooth adapter from CTS test. */ +public class BluetoothAdapterUtils { + private static final String TAG = BluetoothAdapterUtils.class.getSimpleName(); + + /** + * ADAPTER_ENABLE_TIMEOUT_MS = AdapterState.BLE_START_TIMEOUT_DELAY + + * AdapterState.BREDR_START_TIMEOUT_DELAY + (10 seconds of additional delay) + */ + private static final Duration ADAPTER_ENABLE_TIMEOUT = Duration.ofSeconds(18); + + /** + * ADAPTER_DISABLE_TIMEOUT_MS = AdapterState.BLE_STOP_TIMEOUT_DELAY + + * AdapterState.BREDR_STOP_TIMEOUT_DELAY + */ + private static final Duration ADAPTER_DISABLE_TIMEOUT = Duration.ofSeconds(5); + + /** Redefined from {@link BluetoothAdapter} because of hidden APIs */ + public static final int STATE_BLE_TURNING_ON = 14; + + public static final int STATE_BLE_TURNING_OFF = 16; + + private static final HashMap sStateTimeouts = new HashMap<>(); + + static { + sStateTimeouts.put(BluetoothAdapter.STATE_OFF, ADAPTER_DISABLE_TIMEOUT); + sStateTimeouts.put(BluetoothAdapter.STATE_TURNING_ON, ADAPTER_ENABLE_TIMEOUT); + sStateTimeouts.put(BluetoothAdapter.STATE_ON, ADAPTER_ENABLE_TIMEOUT); + sStateTimeouts.put(BluetoothAdapter.STATE_TURNING_OFF, ADAPTER_DISABLE_TIMEOUT); + sStateTimeouts.put(STATE_BLE_TURNING_ON, ADAPTER_ENABLE_TIMEOUT); + sStateTimeouts.put(BluetoothAdapter.STATE_BLE_ON, ADAPTER_ENABLE_TIMEOUT); + sStateTimeouts.put(STATE_BLE_TURNING_OFF, ADAPTER_DISABLE_TIMEOUT); + } + + private static boolean sAdapterVarsInitialized; + private static ReentrantLock sBluetoothAdapterLock; + private static Condition sConditionAdapterStateReached; + private static int sDesiredState; + private static int sAdapterState; + + /** Handles BluetoothAdapter state changes and signals when we have reached a desired state */ + private static class BluetoothAdapterReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (BluetoothAdapter.ACTION_BLE_STATE_CHANGED.equals(action)) { + int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); + Log.d(TAG, "Bluetooth adapter state changed: " + newState); + + // Signal if the state is set to the one we are waiting on + sBluetoothAdapterLock.lock(); + try { + sAdapterState = newState; + if (sDesiredState == newState) { + Log.d(TAG, "Adapter has reached desired state: " + sDesiredState); + sConditionAdapterStateReached.signal(); + } + } finally { + sBluetoothAdapterLock.unlock(); + } + } + } + } + + /** Initialize all static state variables */ + private static void initAdapterStateVariables(Context context) { + Log.d(TAG, "Initializing adapter state variables"); + BluetoothAdapterReceiver sAdapterReceiver = new BluetoothAdapterReceiver(); + sBluetoothAdapterLock = new ReentrantLock(); + sConditionAdapterStateReached = sBluetoothAdapterLock.newCondition(); + sDesiredState = -1; + sAdapterState = -1; + IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_BLE_STATE_CHANGED); + context.registerReceiver(sAdapterReceiver, filter); + sAdapterVarsInitialized = true; + } + + /** + * Helper method to wait for the bluetooth adapter to be in a given state + * + *

    Assumes all state variables are initialized. Assumes it's being run with + * sBluetoothAdapterLock in the locked state. + */ + private static boolean waitForAdapterStateLocked(int desiredState, BluetoothAdapter adapter) + throws InterruptedException { + Duration timeout = sStateTimeouts.getOrDefault(desiredState, ADAPTER_ENABLE_TIMEOUT); + + Log.d(TAG, "Waiting for adapter state " + desiredState); + sDesiredState = desiredState; + + // Wait until we have reached the desired state + // Handle spurious wakeup + while (desiredState != sAdapterState) { + if (sConditionAdapterStateReached.await(timeout.toMillis(), TimeUnit.MILLISECONDS)) { + // Handle spurious wakeup + continue; + } + // Handle timeout cases + // Case 1: situation where state change occurs, but we don't receive the broadcast + if (desiredState >= BluetoothAdapter.STATE_OFF + && desiredState <= BluetoothAdapter.STATE_TURNING_OFF) { + int currentState = adapter.getState(); + Log.d(TAG, "desiredState: " + desiredState + ", currentState: " + currentState); + return desiredState == currentState; + } else if (desiredState == BluetoothAdapter.STATE_BLE_ON) { + Log.d(TAG, "adapter isLeEnabled: " + adapter.isLeEnabled()); + return adapter.isLeEnabled(); + } + // Case 2: Actual timeout + Log.e( + TAG, + "Timeout while waiting for Bluetooth adapter state " + + desiredState + + " while current state is " + + sAdapterState); + break; + } + + Log.d(TAG, "Final state while waiting: " + sAdapterState); + return sAdapterState == desiredState; + } + + /** Utility method to wait on any specific adapter state */ + public static boolean waitForAdapterState(int desiredState, BluetoothAdapter adapter) { + sBluetoothAdapterLock.lock(); + try { + return waitForAdapterStateLocked(desiredState, adapter); + } catch (InterruptedException e) { + Log.w(TAG, "waitForAdapterState(): interrupted", e); + } finally { + sBluetoothAdapterLock.unlock(); + } + return false; + } + + /** Enables Bluetooth to a Low Energy only mode */ + public static boolean enableBLE(BluetoothAdapter bluetoothAdapter, Context context) { + if (!sAdapterVarsInitialized) { + initAdapterStateVariables(context); + } + + if (bluetoothAdapter.isLeEnabled()) { + return true; + } + + sBluetoothAdapterLock.lock(); + try { + Log.d(TAG, "Enabling Bluetooth low energy only mode"); + if (!bluetoothAdapter.enableBLE()) { + Log.e(TAG, "Unable to enable Bluetooth low energy only mode"); + return false; + } + return waitForAdapterStateLocked(BluetoothAdapter.STATE_BLE_ON, bluetoothAdapter); + } catch (InterruptedException e) { + Log.w(TAG, "enableBLE(): interrupted", e); + } finally { + sBluetoothAdapterLock.unlock(); + } + return false; + } + + /** Disable Bluetooth Low Energy mode */ + public static boolean disableBLE(BluetoothAdapter bluetoothAdapter, Context context) { + if (!sAdapterVarsInitialized) { + initAdapterStateVariables(context); + } + + if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { + return true; + } + + sBluetoothAdapterLock.lock(); + try { + Log.d(TAG, "Disabling Bluetooth low energy"); + bluetoothAdapter.disableBLE(); + return waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter); + } catch (InterruptedException e) { + Log.w(TAG, "disableBLE(): interrupted", e); + } finally { + sBluetoothAdapterLock.unlock(); + } + return false; + } + + /** Enables the Bluetooth Adapter. Return true if it is already enabled or is enabled. */ + public static boolean enableAdapter(BluetoothAdapter bluetoothAdapter, Context context) { + if (!sAdapterVarsInitialized) { + initAdapterStateVariables(context); + } + + if (bluetoothAdapter.isEnabled()) { + return true; + } + + Set permissionsAdopted = TestUtils.getAdoptedShellPermissions(); + String[] permissionArray = permissionsAdopted.toArray(String[]::new); + if (UiAutomation.ALL_PERMISSIONS.equals(permissionsAdopted)) { + permissionArray = null; + } + + sBluetoothAdapterLock.lock(); + try { + Log.d(TAG, "Enabling Bluetooth adapter"); + TestUtils.dropPermissionAsShellUid(); + TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); + bluetoothAdapter.enable(); + return waitForAdapterStateLocked(BluetoothAdapter.STATE_ON, bluetoothAdapter); + } catch (InterruptedException e) { + Log.w(TAG, "enableAdapter(): interrupted", e); + } finally { + TestUtils.dropPermissionAsShellUid(); + TestUtils.adoptPermissionAsShellUid(permissionArray); + sBluetoothAdapterLock.unlock(); + } + return false; + } + + /** Disable the Bluetooth Adapter. Return true if it is already disabled or is disabled. */ + public static boolean disableAdapter(BluetoothAdapter bluetoothAdapter, Context context) { + return disableAdapter(bluetoothAdapter, true, context); + } + + /** + * Disable the Bluetooth Adapter with then option to persist the off state or not. + * + *

    Returns true if the adapter is already disabled or was disabled. + */ + public static boolean disableAdapter( + BluetoothAdapter bluetoothAdapter, boolean persist, Context context) { + if (!sAdapterVarsInitialized) { + initAdapterStateVariables(context); + } + + if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { + return true; + } + + Set permissionsAdopted = TestUtils.getAdoptedShellPermissions(); + String[] permissionArray = permissionsAdopted.toArray(String[]::new); + if (UiAutomation.ALL_PERMISSIONS.equals(permissionsAdopted)) { + permissionArray = null; + } + + sBluetoothAdapterLock.lock(); + try { + Log.d(TAG, "Disabling Bluetooth adapter, persist=" + persist); + TestUtils.dropPermissionAsShellUid(); + TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); + bluetoothAdapter.disable(persist); + return waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter); + } catch (InterruptedException e) { + Log.w(TAG, "disableAdapter(persist=" + persist + "): interrupted", e); + } finally { + TestUtils.dropPermissionAsShellUid(); + TestUtils.adoptPermissionAsShellUid(permissionArray); + sBluetoothAdapterLock.unlock(); + } + return false; + } +} diff --git a/framework/tests/util/src/android/bluetooth/test_utils/EnableBluetoothRule.java b/framework/tests/util/src/android/bluetooth/test_utils/EnableBluetoothRule.java new file mode 100644 index 0000000000000000000000000000000000000000..42a0443edb56e66f926746e3ae6a9bf902365d35 --- /dev/null +++ b/framework/tests/util/src/android/bluetooth/test_utils/EnableBluetoothRule.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth.test_utils; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assume.assumeTrue; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.compatibility.common.util.BeforeAfterRule; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * This is a test rule that, when used in a test, will enable Bluetooth before the test starts. When + * the test is done, Bluetooth will be disabled if and only if it was disabled before the test + * started. If setTestMode is set to true, the Bluetooth scanner will return a hardcoded set of + * Bluetooth scan results while the test runs . + */ +public class EnableBluetoothRule extends BeforeAfterRule { + private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + private final BluetoothAdapter mBluetoothAdapter = + mContext.getSystemService(BluetoothManager.class).getAdapter(); + private final boolean mEnableTestMode; + private final boolean mToggleBluetooth; + + private boolean mWasBluetoothAdapterEnabled = true; + + /** Empty constructor */ + public EnableBluetoothRule() { + mEnableTestMode = false; + mToggleBluetooth = false; + } + + /** + * Constructor that allows test mode + * + * @param enableTestMode whether test mode is enabled + * @param toggleBluetooth whether to toggle Bluetooth at the beginning of the test if it is + * already enabled + */ + public EnableBluetoothRule(boolean enableTestMode, boolean toggleBluetooth) { + mEnableTestMode = enableTestMode; + mToggleBluetooth = toggleBluetooth; + } + + /** + * Constructor that allows test mode + * + * @param enableTestMode whether test mode is enabled + */ + public EnableBluetoothRule(boolean enableTestMode) { + mEnableTestMode = enableTestMode; + mToggleBluetooth = false; + } + + private void enableBluetoothAdapter() { + assertThat(BluetoothAdapterUtils.enableAdapter(mBluetoothAdapter, mContext)).isTrue(); + } + + private void disableBluetoothAdapter() { + assertThat(BluetoothAdapterUtils.disableAdapter(mBluetoothAdapter, mContext)).isTrue(); + } + + private void enableBluetoothTestMode() { + runShellCommandOrThrow( + "dumpsys activity service" + + " com.android.bluetooth.btservice.AdapterService set-test-mode enabled"); + } + + private void disableBluetoothTestMode() { + runShellCommandOrThrow( + "dumpsys activity service" + + " com.android.bluetooth.btservice.AdapterService set-test-mode disabled"); + } + + @Override + protected void onBefore(Statement base, Description description) { + assumeTrue(TestUtils.hasBluetooth()); + mWasBluetoothAdapterEnabled = mBluetoothAdapter.isEnabled(); + if (!mWasBluetoothAdapterEnabled) { + enableBluetoothAdapter(); + } else if (mToggleBluetooth) { + disableBluetoothAdapter(); + enableBluetoothAdapter(); + } + if (mEnableTestMode) { + enableBluetoothTestMode(); + } + } + + @Override + protected void onAfter(Statement base, Description description) { + assumeTrue(TestUtils.hasBluetooth()); + disableBluetoothTestMode(); + if (!mWasBluetoothAdapterEnabled) { + disableBluetoothAdapter(); + } + } +} diff --git a/framework/tests/util/src/android/bluetooth/test_utils/TestUtils.java b/framework/tests/util/src/android/bluetooth/test_utils/TestUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..8cc5563d7a53763ac8e1fc226ba62e6273389b42 --- /dev/null +++ b/framework/tests/util/src/android/bluetooth/test_utils/TestUtils.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth.test_utils; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.le.ScanRecord; +import android.content.Context; +import android.content.pm.PackageManager; +import android.provider.Settings; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.google.errorprone.annotations.InlineMe; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.time.Duration; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** Utility class for Bluetooth CTS test. */ +public class TestUtils { + protected static final String TAG = TestUtils.class.getSimpleName(); + + /** + * Checks whether this device has Bluetooth feature + * + * @return true if this device has Bluetooth feature + */ + public static boolean hasBluetooth() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); + } + + /** + * Adopt shell UID's permission via {@link android.app.UiAutomation} + * + * @param permission permission to adopt + */ + public static void adoptPermissionAsShellUid(@Nullable String... permission) { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(permission); + } + + /** Drop all permissions adopted as shell UID */ + public static void dropPermissionAsShellUid() { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } + + /** + * @return permissions adopted from Shell on this process + */ + public static Set getAdoptedShellPermissions() { + return InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .getAdoptedShellPermissions(); + } + + /** + * Utility method to call hidden ScanRecord.parseFromBytes method. + * + * @param bytes Raw bytes from BLE payload + * @return parsed {@link ScanRecord}, null if parsing failed + */ + public static ScanRecord parseScanRecord(byte[] bytes) { + Class scanRecordClass = ScanRecord.class; + try { + Method method = scanRecordClass.getDeclaredMethod("parseFromBytes", byte[].class); + return (ScanRecord) method.invoke(null, bytes); + } catch (NoSuchMethodException + | IllegalAccessException + | IllegalArgumentException + | InvocationTargetException e) { + return null; + } + } + + /** + * Get current location mode settings. + * + * @param context current running context + * @return values among {@link Settings.Secure#LOCATION_MODE_OFF}, {@link + * Settings.Secure#LOCATION_MODE_ON}, {@link Settings.Secure#LOCATION_MODE_SENSORS_ONLY}, + * {@link Settings.Secure#LOCATION_MODE_HIGH_ACCURACY}, {@link + * Settings.Secure#LOCATION_MODE_BATTERY_SAVING} + */ + public static int getLocationMode(Context context) { + return Settings.Secure.getInt( + context.getContentResolver(), + Settings.Secure.LOCATION_MODE, + Settings.Secure.LOCATION_MODE_OFF); + } + + /** + * Set location settings mode. + * + * @param context current running context + * @param mode a value for {@link Settings.Secure#LOCATION_MODE} among {@link + * Settings.Secure#LOCATION_MODE_OFF}, {@link Settings.Secure#LOCATION_MODE_ON}, {@link + * Settings.Secure#LOCATION_MODE_SENSORS_ONLY}, {@link + * Settings.Secure#LOCATION_MODE_HIGH_ACCURACY}, {@link + * Settings.Secure#LOCATION_MODE_BATTERY_SAVING} + */ + public static void setLocationMode(Context context, int mode) { + Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE, mode); + } + + /** + * Return true if location is on. + * + * @param context current running context + * @return true if location mode is in one of the enabled value + */ + public static boolean isLocationOn(Context context) { + return getLocationMode(context) != Settings.Secure.LOCATION_MODE_OFF; + } + + /** Enable location and set the mode to GPS only. */ + public static void enableLocation(Context context) { + setLocationMode(context, Settings.Secure.LOCATION_MODE_SENSORS_ONLY); + } + + /** + * Disable location by setting is to {@link Settings.Secure#LOCATION_MODE_OFF} + * + * @param context current running context + */ + public static void disableLocation(Context context) { + setLocationMode(context, Settings.Secure.LOCATION_MODE_OFF); + } + + /** + * Check if BLE is supported by this platform + * + * @param context current device context + * @return true if BLE is supported, false otherwise + */ + public static boolean isBleSupported(Context context) { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE); + } + + /** + * Check if this is an automotive device + * + * @param context current device context + * @return true if this Android device is an automotive device, false otherwise + */ + public static boolean isAutomotive(Context context) { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + + /** + * Check if this is a watch device + * + * @param context current device context + * @return true if this Android device is a watch device, false otherwise + */ + public static boolean isWatch(Context context) { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); + } + + /** + * Check if this is a TV device + * + * @param context current device context + * @return true if this Android device is a TV device, false otherwise + */ + public static boolean isTv(Context context) { + PackageManager pm = context.getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION) + || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK); + } + + /** Boilerplate class for profile listener */ + public static class BluetoothCtsServiceConnector { + // Timeout for Proxy Connect + private static final Duration PROXY_CONNECTION_TIMEOUT = Duration.ofMillis(500); + private BluetoothProfile mProfileProxy = null; + private boolean mIsProfileReady = false; + private boolean mIsProfileConnecting = false; + private final Condition mConditionProfileConnection; + private final ReentrantLock mProfileConnectionLock; + private final String mLogTag; + private final int mProfileId; + private final BluetoothAdapter mAdapter; + private final Context mContext; + + public BluetoothCtsServiceConnector( + String logTag, int profileId, BluetoothAdapter adapter, Context context) { + mLogTag = Objects.requireNonNull(logTag); + mProfileId = profileId; + mAdapter = Objects.requireNonNull(adapter); + mContext = Objects.requireNonNull(context); + mProfileConnectionLock = new ReentrantLock(); + mConditionProfileConnection = mProfileConnectionLock.newCondition(); + } + + public BluetoothProfile getProfileProxy() { + return mProfileProxy; + } + + /** Close profile proxy */ + public void closeProfileProxy() { + if (mProfileProxy != null) { + mAdapter.closeProfileProxy(mProfileId, mProfileProxy); + mProfileProxy = null; + mIsProfileReady = false; + } + } + + /** + * Open profile proxy + * + * @return true if the profile proxy is opened successfully + */ + public boolean openProfileProxyAsync() { + mIsProfileConnecting = mAdapter.getProfileProxy(mContext, mServiceListener, mProfileId); + return mIsProfileConnecting; + } + + /** + * Wait for profile service to connect + * + * @return true if the service is connected on time + */ + public boolean waitForProfileConnect() { + return waitForProfileConnect(PROXY_CONNECTION_TIMEOUT); + } + + /** + * Wait for profile service to connect with timeouts + * + * @param timeoutMs duration of the timeout in milliseconds + * @return true if the service is connected on time + * @deprecated Please use {@link #waitForProfileConnect(Duration)} instead + */ + @Deprecated + @InlineMe( + replacement = "this.waitForProfileConnect(Duration.ofMillis(timeoutMs))", + imports = "java.time.Duration") + public final boolean waitForProfileConnect(int timeoutMs) { + return waitForProfileConnect(Duration.ofMillis(timeoutMs)); + } + + /** + * Wait for profile service to connect with timeouts + * + * @param timeout duration of the timeout + * @return true if the service is connected on time + */ + public boolean waitForProfileConnect(Duration timeout) { + if (!mIsProfileConnecting) { + mIsProfileConnecting = + mAdapter.getProfileProxy(mContext, mServiceListener, mProfileId); + } + if (!mIsProfileConnecting) { + return false; + } + mProfileConnectionLock.lock(); + try { + // Wait for the Adapter to be disabled + while (!mIsProfileReady) { + if (!mConditionProfileConnection.await( + timeout.toMillis(), TimeUnit.MILLISECONDS)) { + // Timeout + Log.e(mLogTag, "Timeout while waiting for Profile Connect"); + break; + } // else spurious wake-ups + } + } catch (InterruptedException e) { + Log.e(mLogTag, "waitForProfileConnect: interrupted"); + } finally { + mProfileConnectionLock.unlock(); + } + mIsProfileConnecting = false; + return mIsProfileReady; + } + + private final BluetoothProfile.ServiceListener mServiceListener = + new BluetoothProfile.ServiceListener() { + @Override + public void onServiceConnected(int profile, BluetoothProfile proxy) { + mProfileConnectionLock.lock(); + try { + mProfileProxy = proxy; + mIsProfileReady = true; + mConditionProfileConnection.signal(); + } finally { + mProfileConnectionLock.unlock(); + } + } + + @Override + public void onServiceDisconnected(int profile) { + mProfileConnectionLock.lock(); + try { + mIsProfileReady = false; + mConditionProfileConnection.signal(); + } finally { + mProfileConnectionLock.unlock(); + } + } + }; + } +} diff --git a/pandora/interfaces/Android.bp b/pandora/interfaces/Android.bp index a496381ca15cc8bee1d6ed2ed7ca020c5a8bcc31..41687eac08f0bf54acb5f92c36d5835f9c56f27a 100644 --- a/pandora/interfaces/Android.bp +++ b/pandora/interfaces/Android.bp @@ -7,6 +7,7 @@ java_library { visibility: [ "//packages/modules/Bluetooth/android/pandora/server", "//packages/modules/Bluetooth/framework/tests/bumble", + "//packages/modules/Bluetooth/framework/tests/metrics:__subpackages__", ], srcs: [ ":pandora-protos", @@ -38,6 +39,7 @@ java_library { visibility: [ "//packages/modules/Bluetooth/android/pandora/server", "//packages/modules/Bluetooth/framework/tests/bumble", + "//packages/modules/Bluetooth/framework/tests/metrics:__subpackages__", ], srcs: [ ":libprotobuf-internal-protos", diff --git a/pandora/interfaces/pandora_experimental/a2dp.proto b/pandora/interfaces/pandora_experimental/a2dp.proto deleted file mode 100644 index be6ab5f0efe4e21f814e387a6f8ad74f3080ffa2..0000000000000000000000000000000000000000 --- a/pandora/interfaces/pandora_experimental/a2dp.proto +++ /dev/null @@ -1,264 +0,0 @@ - -// Copyright 2022 Google LLC -// -// 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 -// -// https://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"; - -option java_outer_classname = "A2dpProto"; - -package pandora; - -import "pandora/host.proto"; - -// Service to trigger A2DP (Advanced Audio Distribution Profile) procedures. -// -// Requirements for the implementor: -// - Streams must not be automatically opened, even if discovered. -// - The `Host` service must be implemented -// -// References: -// - [A2DP] Bluetooth SIG, Specification of the Bluetooth System, -// Advanced Audio Distribution, Version 1.3 or Later -// - [AVDTP] Bluetooth SIG, Specification of the Bluetooth System, -// Audio/Video Distribution Transport Protocol, Version 1.3 or Later -service A2DP { - // Open a stream from a local **Source** endpoint to a remote **Sink** - // endpoint. - // - // The returned source should be in the AVDTP_OPEN state (see [AVDTP] 9.1). - // The rpc must block until the stream has reached this state. - // - // A cancellation of this call must result in aborting the current - // AVDTP procedure (see [AVDTP] 9.9). - rpc OpenSource(OpenSourceRequest) returns (OpenSourceResponse); - // Open a stream from a local **Sink** endpoint to a remote **Source** - // endpoint. - // - // The returned sink must be in the AVDTP_OPEN state (see [AVDTP] 9.1). - // The rpc must block until the stream has reached this state. - // - // A cancellation of this call must result in aborting the current - // AVDTP procedure (see [AVDTP] 9.9). - rpc OpenSink(OpenSinkRequest) returns (OpenSinkResponse); - // Wait for a stream from a local **Source** endpoint to - // a remote **Sink** endpoint to open. - // - // The returned source should be in the AVDTP_OPEN state (see [AVDTP] 9.1). - // The rpc must block until the stream has reached this state. - // - // If the peer has opened a source prior to this call, the server will - // return it. The server must return the same source only once. - rpc WaitSource(WaitSourceRequest) returns (WaitSourceResponse); - // Wait for a stream from a local **Sink** endpoint to - // a remote **Source** endpoint to open. - // - // The returned sink should be in the AVDTP_OPEN state (see [AVDTP] 9.1). - // The rpc must block until the stream has reached this state. - // - // If the peer has opened a sink prior to this call, the server will - // return it. The server must return the same sink only once. - rpc WaitSink(WaitSinkRequest) returns (WaitSinkResponse); - // Get if the stream is suspended - rpc IsSuspended(IsSuspendedRequest) returns (IsSuspendedResponse); - // Start a suspended stream. - rpc Start(StartRequest) returns (StartResponse); - // Suspend a started stream. - rpc Suspend(SuspendRequest) returns (SuspendResponse); - // Close a stream, the source or sink tokens must not be reused afterwards. - rpc Close(CloseRequest) returns (CloseResponse); - // Get the `AudioEncoding` value of a stream - rpc GetAudioEncoding(GetAudioEncodingRequest) returns (GetAudioEncodingResponse); - // Playback audio by a `Source` - rpc PlaybackAudio(stream PlaybackAudioRequest) returns (PlaybackAudioResponse); - // Capture audio from a `Sink` - rpc CaptureAudio(CaptureAudioRequest) returns (stream CaptureAudioResponse); -} - -// Audio encoding formats. -enum AudioEncoding { - // Interleaved stereo frames with 16-bit signed little-endian linear PCM - // samples at 44100Hz sample rate - PCM_S16_LE_44K1_STEREO = 0; - // Interleaved stereo frames with 16-bit signed little-endian linear PCM - // samples at 48000Hz sample rate - PCM_S16_LE_48K_STEREO = 1; -} - -// A Token representing a Source stream (see [A2DP] 2.2). -// It's acquired via an OpenSource on the A2DP service. -message Source { - // Opaque value filled by the GRPC server, must not - // be modified nor crafted. - Connection connection = 1; -} - -// A Token representing a Sink stream (see [A2DP] 2.2). -// It's acquired via an OpenSink on the A2DP service. -message Sink { - // Opaque value filled by the GRPC server, must not - // be modified nor crafted. - Connection connection = 1; -} - -// Request for the `OpenSource` method. -message OpenSourceRequest { - // The connection that will open the stream. - Connection connection = 1; -} - -// Response for the `OpenSource` method. -message OpenSourceResponse { - // Result of the `OpenSource` call: - // - If successful: a Source - oneof result { - Source source = 1; - } -} - -// Request for the `OpenSink` method. -message OpenSinkRequest { - // The connection that will open the stream. - Connection connection = 1; -} - -// Response for the `OpenSink` method. -message OpenSinkResponse { - // Result of the `OpenSink` call: - // - If successful: a Sink - oneof result { - Sink sink = 1; - } -} - -// Request for the `WaitSource` method. -message WaitSourceRequest { - // The connection that is awaiting the stream. - Connection connection = 1; -} - -// Response for the `WaitSource` method. -message WaitSourceResponse { - // Result of the `WaitSource` call: - // - If successful: a Source - oneof result { - Source source = 1; - } -} - -// Request for the `WaitSink` method. -message WaitSinkRequest { - // The connection that is awaiting the stream. - Connection connection = 1; -} - -// Response for the `WaitSink` method. -message WaitSinkResponse { - // Result of the `WaitSink` call: - // - If successful: a Sink - oneof result { - Sink sink = 1; - } -} - -// Request for the `IsSuspended` method. -message IsSuspendedRequest { - // The stream on which the function will check if it's suspended - oneof target { - Sink sink = 1; - Source source = 2; - } -} - -// Response for the `IsSuspended` method. -message IsSuspendedResponse { - bool is_suspended = 1; -} - -// Request for the `Start` method. -message StartRequest { - // Target of the start, either a Sink or a Source. - oneof target { - Sink sink = 1; - Source source = 2; - } -} - -// Response for the `Start` method. -message StartResponse {} - -// Request for the `Suspend` method. -message SuspendRequest { - // Target of the suspend, either a Sink or a Source. - oneof target { - Sink sink = 1; - Source source = 2; - } -} - -// Response for the `Suspend` method. -message SuspendResponse {} - -// Request for the `Close` method. -message CloseRequest { - // Target of the close, either a Sink or a Source. - oneof target { - Sink sink = 1; - Source source = 2; - } -} - -// Response for the `Close` method. -message CloseResponse {} - -// Request for the `GetAudioEncoding` method. -message GetAudioEncodingRequest { - // The stream on which the function will read the `AudioEncoding`. - oneof target { - Sink sink = 1; - Source source = 2; - } -} - -// Response for the `GetAudioEncoding` method. -message GetAudioEncodingResponse { - // Audio encoding of the stream. - AudioEncoding encoding = 1; -} - -// Request for the `PlaybackAudio` method. -message PlaybackAudioRequest { - // Source that will playback audio. - Source source = 1; - // Audio data to playback. - // The audio data must be encoded in the specified `AudioEncoding` value - // obtained in response of a `GetAudioEncoding` method call. - bytes data = 2; -} - -// Response for the `PlaybackAudio` method. -message PlaybackAudioResponse {} - -// Request for the `CaptureAudio` method. -message CaptureAudioRequest { - // Sink that will capture audio - Sink sink = 1; -} - -// Response for the `CaptureAudio` method. -message CaptureAudioResponse { - // Captured audio data. - // The audio data is encoded in the specified `AudioEncoding` value - // obained in response of a `GetAudioEncoding` method call. - bytes data = 1; -} diff --git a/tools/pdl/src/backends/json.rs b/pandora/interfaces/pandora_experimental/dck.proto similarity index 68% rename from tools/pdl/src/backends/json.rs rename to pandora/interfaces/pandora_experimental/dck.proto index 460d72cc2925539002120ca793989bc2d6bc9032..622393226125b2a608748f0a4e9809e85b0c4d65 100644 --- a/tools/pdl/src/backends/json.rs +++ b/pandora/interfaces/pandora_experimental/dck.proto @@ -12,12 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Rust compiler backend. +syntax = "proto3"; -use crate::parser; +option java_outer_classname = "DckProto"; -/// Turn the AST into a JSON representation. -pub fn generate(file: &parser::ast::File) -> Result { - serde_json::to_string_pretty(&file) - .map_err(|err| format!("could not JSON serialize grammar: {err}")) -} +package pandora; + +import "google/protobuf/empty.proto"; + +service Dck { + // Register DCK Service. + rpc Register(google.protobuf.Empty) returns (google.protobuf.Empty); +} \ No newline at end of file diff --git a/pandora/interfaces/pandora_experimental/le_audio.proto b/pandora/interfaces/pandora_experimental/le_audio.proto new file mode 100644 index 0000000000000000000000000000000000000000..45005649915ab2dbd38e06f1b52dbe6a0c196a4b --- /dev/null +++ b/pandora/interfaces/pandora_experimental/le_audio.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +import "pandora/host.proto"; +import "google/protobuf/empty.proto"; + +option java_outer_classname = "LeAudioProto"; + +package pandora; + +// Service to trigger LE Audio procedures. +service LeAudio { + rpc Open(OpenRequest) returns (google.protobuf.Empty); +} + +message OpenRequest { + Connection connection = 1; +} diff --git a/tools/pdl/src/backends.rs b/pandora/interfaces/pandora_experimental/map.proto similarity index 74% rename from tools/pdl/src/backends.rs rename to pandora/interfaces/pandora_experimental/map.proto index a80f1f9549a4ce650830455794c7612ee6615106..0e906601dde7e0357fbb1b627fb9947ec79e90c0 100644 --- a/tools/pdl/src/backends.rs +++ b/pandora/interfaces/pandora_experimental/map.proto @@ -12,9 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Compiler backends. +syntax = "proto3"; -pub mod intermediate; -pub mod json; -pub mod rust; -pub mod rust_no_allocation; +option java_outer_classname = "MapProto"; + +package pandora; + +import "google/protobuf/empty.proto"; + +service Map { + rpc SendSMS(google.protobuf.Empty) returns (google.protobuf.Empty); +} \ No newline at end of file diff --git a/pandora/interfaces/pandora_experimental/opp.proto b/pandora/interfaces/pandora_experimental/opp.proto new file mode 100644 index 0000000000000000000000000000000000000000..82bfa548ec736815b9cb95f09073688d43a23733 --- /dev/null +++ b/pandora/interfaces/pandora_experimental/opp.proto @@ -0,0 +1,47 @@ +// Copyright 2023 Google LLC +// +// 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 +// +// https://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"; + +option java_outer_classname = "OppProto"; + +package pandora; + +import "google/protobuf/empty.proto"; + +service Opp { + // Open an rfcommChannel for an OBEX connection. + rpc OpenRfcommChannel(OpenRfcommChannelRequest) returns (google.protobuf.Empty); + // Open an l2cap channel for an OBEX connection. + rpc OpenL2capChannel(OpenL2capChannelRequest) returns (google.protobuf.Empty); + // Accept Put request by the Push Client to the Push Server within an OBEX connection. + rpc AcceptPutOperation(google.protobuf.Empty) returns (AcceptPutOperationResponse); +} + +message OpenRfcommChannelRequest { + bytes address = 1; +} + +message OpenL2capChannelRequest { + bytes address = 1; +} + +enum PutStatus { + ACCEPTED = 0; + DECLINED = 1; +} + +message AcceptPutOperationResponse { + PutStatus status = 1; +} \ No newline at end of file diff --git a/pandora/interfaces/pandora_experimental/_android.proto b/pandora/interfaces/pandora_experimental/os.proto similarity index 50% rename from pandora/interfaces/pandora_experimental/_android.proto rename to pandora/interfaces/pandora_experimental/os.proto index feaa3b6b399fc84ec6ebf25b92847982435318da..46628e4127f626b7a0daf55a9d826bf6aed243cc 100644 --- a/pandora/interfaces/pandora_experimental/_android.proto +++ b/pandora/interfaces/pandora_experimental/os.proto @@ -1,27 +1,34 @@ +// Copyright 2023 Google LLC +// +// 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 +// +// https://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"; -option java_outer_classname = "AndroidProto"; +option java_outer_classname = "OsProto"; package pandora; +import "pandora/host.proto"; import "google/protobuf/empty.proto"; -// This file contains Android-specific protos and rpcs that should not be part -// of the general interface. They should not be invoked from MMIs directly since -// this will couple them too tightly with Android. - -// Service for Android-specific operations. -service Android { +// Service for OS specific operations. +service Os { // Log text (for utility only) rpc Log(LogRequest) returns (LogResponse); // Set Message, PhoneBook and SIM access permission rpc SetAccessPermission(SetAccessPermissionRequest) returns (google.protobuf.Empty); - // Send SMS - rpc SendSMS(google.protobuf.Empty) returns (google.protobuf.Empty); - // Accept incoming file - rpc AcceptIncomingFile(google.protobuf.Empty) returns (google.protobuf.Empty); - // Send file - rpc SendFile(google.protobuf.Empty) returns (google.protobuf.Empty); + // Send ping + rpc SendPing(SendPingRequest) returns (google.protobuf.Empty); } message LogRequest { @@ -48,4 +55,9 @@ message SetAccessPermissionRequest { message InternalConnectionRef { bytes address = 1; int32 transport = 2; -} \ No newline at end of file +} + +// Request for the `SendPing` rpc. +message SendPingRequest { + string ip_address = 1; +} diff --git a/pandora/interfaces/python/Android.bp b/pandora/interfaces/python/Android.bp index abf8ee674163d11857a544ad743d8ef1784a600a..4893f597c23c27993022ad210f62ee7b4ffd3f27 100644 --- a/pandora/interfaces/python/Android.bp +++ b/pandora/interfaces/python/Android.bp @@ -15,24 +15,17 @@ genrule { " --plugin=protoc-gen-grpc=$(location protoc-gen-pandora-python)" + " --python_out=$(genDir)" + " --grpc_out=$(genDir)" + - " $(in) &&" + + " $(locations :pandora-protos) $(locations :pandora_experimental-protos) &&" + "touch $(genDir)/pandora_experimental/py.typed &&" + "touch $(genDir)/pandora_experimental/__init__.py", srcs: [ + ":libprotobuf-internal-protos", ":pandora-protos", ":pandora_experimental-protos", ], out: [ "pandora_experimental/__init__.py", - "pandora_experimental/_android_grpc.py", - "pandora_experimental/_android_grpc_aio.py", - "pandora_experimental/_android_pb2.py", - "pandora_experimental/_android_pb2.pyi", "pandora_experimental/_utils.py", - "pandora_experimental/a2dp_grpc.py", - "pandora_experimental/a2dp_grpc_aio.py", - "pandora_experimental/a2dp_pb2.py", - "pandora_experimental/a2dp_pb2.pyi", "pandora_experimental/asha_grpc.py", "pandora_experimental/asha_grpc_aio.py", "pandora_experimental/asha_pb2.py", @@ -41,6 +34,10 @@ genrule { "pandora_experimental/avrcp_grpc_aio.py", "pandora_experimental/avrcp_pb2.py", "pandora_experimental/avrcp_pb2.pyi", + "pandora_experimental/dck_grpc.py", + "pandora_experimental/dck_grpc_aio.py", + "pandora_experimental/dck_pb2.py", + "pandora_experimental/dck_pb2.pyi", "pandora_experimental/gatt_grpc.py", "pandora_experimental/gatt_grpc_aio.py", "pandora_experimental/gatt_pb2.py", @@ -57,10 +54,26 @@ genrule { "pandora_experimental/l2cap_grpc_aio.py", "pandora_experimental/l2cap_pb2.py", "pandora_experimental/l2cap_pb2.pyi", + "pandora_experimental/le_audio_grpc.py", + "pandora_experimental/le_audio_grpc_aio.py", + "pandora_experimental/le_audio_pb2.py", + "pandora_experimental/le_audio_pb2.pyi", + "pandora_experimental/map_grpc.py", + "pandora_experimental/map_grpc_aio.py", + "pandora_experimental/map_pb2.py", + "pandora_experimental/map_pb2.pyi", "pandora_experimental/mediaplayer_grpc.py", "pandora_experimental/mediaplayer_grpc_aio.py", "pandora_experimental/mediaplayer_pb2.py", "pandora_experimental/mediaplayer_pb2.pyi", + "pandora_experimental/opp_grpc.py", + "pandora_experimental/opp_grpc_aio.py", + "pandora_experimental/opp_pb2.py", + "pandora_experimental/opp_pb2.pyi", + "pandora_experimental/os_grpc.py", + "pandora_experimental/os_grpc_aio.py", + "pandora_experimental/os_pb2.py", + "pandora_experimental/os_pb2.pyi", "pandora_experimental/pan_grpc.py", "pandora_experimental/pan_grpc_aio.py", "pandora_experimental/pan_pb2.py", @@ -90,15 +103,18 @@ filegroup { filegroup { name: "pandora_experimental-python-stubs", srcs: [ - ":pandora_experimental-python-gen-src{pandora_experimental/_android_pb2.pyi}", - ":pandora_experimental-python-gen-src{pandora_experimental/a2dp_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/asha_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/avrcp_pb2.pyi}", + ":pandora_experimental-python-gen-src{pandora_experimental/dck_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/gatt_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/hfp_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/hid_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/l2cap_pb2.pyi}", + ":pandora_experimental-python-gen-src{pandora_experimental/le_audio_pb2.pyi}", + ":pandora_experimental-python-gen-src{pandora_experimental/map_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/mediaplayer_pb2.pyi}", + ":pandora_experimental-python-gen-src{pandora_experimental/opp_pb2.pyi}", + ":pandora_experimental-python-gen-src{pandora_experimental/os_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/pan_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/pbap_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/py.typed}", diff --git a/pandora/server/bumble_experimental/asha.py b/pandora/server/bumble_experimental/asha.py index fab9100c56caabb3f976c3fefcbe034ed653ae88..0739773afa3e1c167e5c8f07484c3e26a0220efa 100644 --- a/pandora/server/bumble_experimental/asha.py +++ b/pandora/server/bumble_experimental/asha.py @@ -17,8 +17,8 @@ import grpc import logging import struct -from avatar.bumble_server import utils from bumble.core import AdvertisingData +from bumble.decoder import G722Decoder from bumble.device import Connection, Connection as BumbleConnection, Device from bumble.gatt import ( GATT_ASHA_AUDIO_CONTROL_POINT_CHARACTERISTIC, @@ -32,6 +32,7 @@ from bumble.gatt import ( TemplateService, ) from bumble.l2cap import Channel +from bumble.pandora import utils from bumble.utils import AsyncRunner from google.protobuf.empty_pb2 import Empty # pytype: disable=pyi-error from pandora_experimental.asha_grpc_aio import AshaServicer @@ -197,6 +198,8 @@ class AshaGattService(TemplateService): class AshaService(AshaServicer): + DECODE_FRAME_LENGTH = 80 + device: Device asha_service: Optional[AshaGattService] @@ -208,9 +211,12 @@ class AshaService(AshaServicer): @utils.rpc async def Register(self, request: RegisterRequest, context: grpc.ServicerContext) -> Empty: logging.info("Register") - # asha service from bumble profile - self.asha_service = AshaGattService(request.capability, request.hisyncid, self.device) - self.device.add_service(self.asha_service) # type: ignore[no-untyped-call] + if self.asha_service: + self.asha_service.capability = request.capability + self.asha_service.hisyncid = request.hisyncid + else: + self.asha_service = AshaGattService(request.capability, request.hisyncid, self.device) + self.device.add_service(self.asha_service) # type: ignore[no-untyped-call] return Empty() @utils.rpc @@ -223,6 +229,7 @@ class AshaService(AshaServicer): if not (connection := self.device.lookup_connection(connection_handle)): raise RuntimeError(f"Unknown connection for connection_handle:{connection_handle}") + decoder = G722Decoder() # type: ignore queue: asyncio.Queue[bytes] = asyncio.Queue() def on_data(asha_connection: BumbleConnection, data: bytes) -> None: @@ -233,6 +240,18 @@ class AshaService(AshaServicer): try: while data := await queue.get(): - yield CaptureAudioResponse(data=data) + output_bytes = bytearray() + # First byte is sequence number, last 160 bytes are audio payload. + audio_payload = data[1:] + data_length = int(len(audio_payload) / AshaService.DECODE_FRAME_LENGTH) + for i in range(0, data_length): + input_data = audio_payload[ + i * AshaService.DECODE_FRAME_LENGTH : i * AshaService.DECODE_FRAME_LENGTH + + AshaService.DECODE_FRAME_LENGTH + ] + decoded_data = decoder.decode_frame(input_data) # type: ignore + output_bytes.extend(decoded_data) + + yield CaptureAudioResponse(data=bytes(output_bytes)) finally: self.asha_service.remove_listener("data", on_data) # type: ignore diff --git a/pandora/server/bumble_experimental/dck.py b/pandora/server/bumble_experimental/dck.py new file mode 100644 index 0000000000000000000000000000000000000000..f9fdd7837f47da59ac6f74f37b8a8dbd0ff85592 --- /dev/null +++ b/pandora/server/bumble_experimental/dck.py @@ -0,0 +1,100 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import grpc +import logging + +from bumble.core import UUID as BumbleUUID, AdvertisingData +from bumble.device import Device +from bumble.gatt import Characteristic, CharacteristicValue, TemplateService +from bumble.l2cap import Channel +from bumble.pandora import utils +from google.protobuf.empty_pb2 import Empty +from pandora_experimental.dck_grpc_aio import DckServicer +from typing import Optional + + +class DckGattService(TemplateService): + CCC_DK_UUID: BumbleUUID = BumbleUUID.from_16_bits(0xFFF5, 'Car Connectivity Consortium, LLC') + UUID = CCC_DK_UUID + UUID_SPSM = BumbleUUID("D3B5A130-9E23-4B3A-8BE4-6B1EE5F980A3", "Vehicle SPSM") + UUID_SPSM_DK_VERSION = BumbleUUID("D3B5A130-9E23-4B3A-8BE4-6B1EE5B780A3", "DK version") + UUID_DEVICE_DK_VERSION = BumbleUUID("BD4B9502-3F54-11EC-B919-0242AC120005", "Device Selected DK version") + UUID_ANTENNA_IDENTIFIER = BumbleUUID("c6d7d4a1-e2b0-4e95-b576-df983d1a5d9f", "Vehicle Antenna Identifier") + + def __init__(self, device: Device): + logger = logging.getLogger(__name__) + + def on_l2cap_server(channel: Channel) -> None: + logger.info(f"--- DckGattService on_l2cap_server") + + self.device_dk_version_value = None + self.psm = device.register_l2cap_channel_server(0, on_l2cap_server) # type: ignore + + def on_device_version_write(value: bytes) -> None: + logger.info(f"--- DK Device Version Write: {value!r}") + self.device_dk_version_value = value + + characteristics = [ + Characteristic( + DckGattService.UUID_SPSM, + Characteristic.Properties.READ, + Characteristic.READABLE, + CharacteristicValue(read=bytes(self.psm)), # type: ignore[no-untyped-call] + ), + Characteristic( + DckGattService.UUID_SPSM_DK_VERSION, + Characteristic.Properties.READ, + Characteristic.READ_REQUIRES_ENCRYPTION, + CharacteristicValue(read=b''), # type: ignore[no-untyped-call] + ), + Characteristic( + DckGattService.UUID_DEVICE_DK_VERSION, + Characteristic.Properties.WRITE, + Characteristic.READ_REQUIRES_ENCRYPTION, + CharacteristicValue(write=on_device_version_write), # type: ignore[no-untyped-call] + ), + Characteristic( + DckGattService.UUID_ANTENNA_IDENTIFIER, + Characteristic.READ, + Characteristic.READABLE, + CharacteristicValue(read=b''), # type: ignore[no-untyped-call] + ), + ] + + super().__init__(characteristics) # type: ignore[no-untyped-call] + + def get_advertising_data(self) -> bytes: + # CCC Specification Digital-Key R3-1.2.0-r14 + # 19.2 LE Procedures AdvData field of ADV_IND + + return bytes(AdvertisingData([(AdvertisingData.SERVICE_DATA_16_BIT_UUID, bytes(DckGattService.CCC_DK_UUID))])) + + +class DckService(DckServicer): + device: Device + dck_gatt_service: Optional[DckGattService] + + def __init__(self, device: Device) -> None: + self.log = utils.BumbleServerLoggerAdapter(logging.getLogger(), {"service_name": "Dck", "device": device}) + self.device = device + self.dck_gatt_service = None + + @utils.rpc + def Register(self, request: Empty, context: grpc.ServicerContext) -> Empty: + if self.dck_gatt_service is None: + self.dck_gatt_service = DckGattService(self.device) + self.device.add_service(self.dck_gatt_service) # type: ignore[no-untyped-call] + + return Empty() diff --git a/pandora/server/bumble_experimental/gatt.py b/pandora/server/bumble_experimental/gatt.py index 323a43e9c40cda1a43b54496fda213968c580961..211d11ca1a3b1ae0b78a4a9e4feb7582f1b3b2ad 100644 --- a/pandora/server/bumble_experimental/gatt.py +++ b/pandora/server/bumble_experimental/gatt.py @@ -16,13 +16,16 @@ import asyncio import grpc import logging -from avatar.bumble_server import utils +from bumble.att import Attribute from bumble.core import ProtocolError from bumble.device import Connection as BumbleConnection, Device, Peer +from bumble.gatt import Characteristic, Descriptor, Service from bumble.gatt_client import CharacteristicProxy, ServiceProxy +from bumble.pandora import utils from pandora_experimental.gatt_grpc_aio import GATTServicer from pandora_experimental.gatt_pb2 import ( SUCCESS, + AttStatusCode, AttValue, ClearCacheRequest, ClearCacheResponse, @@ -40,6 +43,8 @@ from pandora_experimental.gatt_pb2 import ( ReadCharacteristicResponse, ReadCharacteristicsFromUuidRequest, ReadCharacteristicsFromUuidResponse, + RegisterServiceRequest, + RegisterServiceResponse, WriteRequest, WriteResponse, ) @@ -92,16 +97,15 @@ class GATTService(GATTServicer): try: await peer.write_value(request.handle, request.value, with_response=True) # type: ignore - status = SUCCESS + status: AttStatusCode = SUCCESS except ProtocolError as e: - status = e.error_code + status = e.error_code # type: ignore return WriteResponse(handle=request.handle, status=status) @utils.rpc - async def DiscoverServiceByUuid( - self, request: DiscoverServiceByUuidRequest, context: grpc.ServicerContext - ) -> DiscoverServicesResponse: + async def DiscoverServiceByUuid(self, request: DiscoverServiceByUuidRequest, + context: grpc.ServicerContext) -> DiscoverServicesResponse: connection_handle = int.from_bytes(request.connection.cookie.value, 'big') logging.info(f"DiscoverServiceByUuid: {connection_handle}") @@ -118,38 +122,32 @@ class GATTService(GATTServicer): await asyncio.gather(*(feed_service(service) for service in services)) - return DiscoverServicesResponse( - services=[ - GattService( - handle=service.handle, - type=int.from_bytes(bytes(service.type), 'little'), - uuid=service.uuid.to_hex_str('-'), # type: ignore - characteristics=[ - GattCharacteristic( - properties=characteristic.properties, # type: ignore - permissions=0, # TODO - uuid=characteristic.uuid.to_hex_str('-'), # type: ignore - handle=characteristic.handle, # type: ignore - descriptors=[ - GattCharacteristicDescriptor( - handle=descriptor.handle, # type: ignore - permissions=0, # TODO - uuid=str(descriptor.type), # type: ignore - ) - for descriptor in characteristic.descriptors # type: ignore - ], - ) - for characteristic in service.characteristics # type: ignore - ], - ) - for service in services - ] - ) + return DiscoverServicesResponse(services=[ + GattService( + handle=service.handle, + type=int.from_bytes(bytes(service.type), 'little'), + uuid=service.uuid.to_hex_str('-'), # type: ignore + characteristics=[ + GattCharacteristic( + properties=characteristic.properties, # type: ignore + permissions=0, # TODO + uuid=characteristic.uuid.to_hex_str('-'), # type: ignore + handle=characteristic.handle, # type: ignore + descriptors=[ + GattCharacteristicDescriptor( + handle=descriptor.handle, # type: ignore + permissions=0, # TODO + uuid=str(descriptor.type), # type: ignore + ) for descriptor in characteristic.descriptors # type: ignore + ], + ) for characteristic in service.characteristics # type: ignore + ], + ) for service in services + ]) @utils.rpc - async def DiscoverServices( - self, request: DiscoverServicesRequest, context: grpc.ServicerContext - ) -> DiscoverServicesResponse: + async def DiscoverServices(self, request: DiscoverServicesRequest, + context: grpc.ServicerContext) -> DiscoverServicesResponse: connection_handle = int.from_bytes(request.connection.cookie.value, 'big') logging.info(f"DiscoverServices: {connection_handle}") @@ -165,33 +163,28 @@ class GATTService(GATTServicer): await asyncio.gather(*(feed_service(service) for service in services)) - return DiscoverServicesResponse( - services=[ - GattService( - handle=service.handle, - type=int.from_bytes(bytes(service.type), 'little'), - uuid=service.uuid.to_hex_str('-'), # type: ignore - characteristics=[ - GattCharacteristic( - properties=characteristic.properties, # type: ignore - permissions=0, # TODO - uuid=characteristic.uuid.to_hex_str('-'), # type: ignore - handle=characteristic.handle, # type: ignore - descriptors=[ - GattCharacteristicDescriptor( - handle=descriptor.handle, # type: ignore - permissions=0, # TODO - uuid=str(descriptor.type), # type: ignore - ) - for descriptor in characteristic.descriptors # type: ignore - ], - ) - for characteristic in service.characteristics # type: ignore - ], - ) - for service in services - ] - ) + return DiscoverServicesResponse(services=[ + GattService( + handle=service.handle, + type=int.from_bytes(bytes(service.type), 'little'), + uuid=service.uuid.to_hex_str('-'), # type: ignore + characteristics=[ + GattCharacteristic( + properties=characteristic.properties, # type: ignore + permissions=0, # TODO + uuid=characteristic.uuid.to_hex_str('-'), # type: ignore + handle=characteristic.handle, # type: ignore + descriptors=[ + GattCharacteristicDescriptor( + handle=descriptor.handle, # type: ignore + permissions=0, # TODO + uuid=str(descriptor.type), # type: ignore + ) for descriptor in characteristic.descriptors # type: ignore + ], + ) for characteristic in service.characteristics # type: ignore + ], + ) for service in services + ]) # TODO: implement `DiscoverServicesSdp` @@ -201,9 +194,8 @@ class GATTService(GATTServicer): return ClearCacheResponse() @utils.rpc - async def ReadCharacteristicFromHandle( - self, request: ReadCharacteristicRequest, context: grpc.ServicerContext - ) -> ReadCharacteristicResponse: + async def ReadCharacteristicFromHandle(self, request: ReadCharacteristicRequest, + context: grpc.ServicerContext) -> ReadCharacteristicResponse: connection_handle = int.from_bytes(request.connection.cookie.value, 'big') logging.info(f"ReadCharacteristicFromHandle: {connection_handle}") @@ -213,17 +205,16 @@ class GATTService(GATTServicer): try: value = await peer.read_value(request.handle) # type: ignore - status = SUCCESS + status: AttStatusCode = SUCCESS except ProtocolError as e: value = bytes() - status = e.error_code + status = e.error_code # type: ignore return ReadCharacteristicResponse(value=AttValue(value=value), status=status) @utils.rpc - async def ReadCharacteristicsFromUuid( - self, request: ReadCharacteristicsFromUuidRequest, context: grpc.ServicerContext - ) -> ReadCharacteristicsFromUuidResponse: + async def ReadCharacteristicsFromUuid(self, request: ReadCharacteristicsFromUuidRequest, + context: grpc.ServicerContext) -> ReadCharacteristicsFromUuidResponse: connection_handle = int.from_bytes(request.connection.cookie.value, 'big') logging.info(f"ReadCharacteristicsFromUuid: {connection_handle}") @@ -236,25 +227,22 @@ class GATTService(GATTServicer): try: characteristics = await peer.read_characteristics_by_uuid(request.uuid, service_mock) # type: ignore - return ReadCharacteristicsFromUuidResponse( - characteristics_read=[ - ReadCharacteristicResponse( - value=AttValue(value=value, handle=handle), # type: ignore - status=SUCCESS, - ) - for handle, value in characteristics # type: ignore - ] - ) + return ReadCharacteristicsFromUuidResponse(characteristics_read=[ + ReadCharacteristicResponse( + value=AttValue(value=value, handle=handle), # type: ignore + status=SUCCESS, + ) for handle, value in characteristics # type: ignore + ]) except ProtocolError as e: return ReadCharacteristicsFromUuidResponse( - characteristics_read=[ReadCharacteristicResponse(status=e.error_code)] + characteristics_read=[ReadCharacteristicResponse(status=e.error_code)] # type: ignore ) @utils.rpc async def ReadCharacteristicDescriptorFromHandle( - self, request: ReadCharacteristicDescriptorRequest, context: grpc.ServicerContext - ) -> ReadCharacteristicDescriptorResponse: + self, request: ReadCharacteristicDescriptorRequest, + context: grpc.ServicerContext) -> ReadCharacteristicDescriptorResponse: connection_handle = int.from_bytes(request.connection.cookie.value, 'big') logging.info(f"ReadCharacteristicDescriptorFromHandle: {connection_handle}") @@ -264,9 +252,34 @@ class GATTService(GATTServicer): try: value = await peer.read_value(request.handle) # type: ignore - status = SUCCESS + status: AttStatusCode = SUCCESS except ProtocolError as e: value = bytes() - status = e.error_code + status = e.error_code # type: ignore return ReadCharacteristicDescriptorResponse(value=AttValue(value=value), status=status) + + @utils.rpc + def RegisterService(self, request: RegisterServiceRequest, + context: grpc.ServicerContext) -> RegisterServiceResponse: + logging.info(f"RegisterService") + + serviceUUID = request.service.uuid + characteristics = [ + Characteristic( + properties=Characteristic.Properties(characteristicParam.properties), + permissions=Attribute.Permissions(characteristicParam.permissions), + uuid=characteristicParam.uuid, + descriptors=[ + Descriptor( + attribute_type=descParam.uuid, + permissions=Attribute.Permissions(descParam.permissions), + ) for descParam in characteristicParam.descriptors + ], + ) for characteristicParam in request.service.characteristics + ] + service = Service(serviceUUID, characteristics) + self.device.add_service(service) # type: ignore[no-untyped-call] + + logging.info(f"RegisterService complete") + return RegisterServiceResponse() diff --git a/service/Android.bp b/service/Android.bp index cbe1bb62e1d91e63f401774a9a9024b5160aaad5..5a6665388d0dcb15275ba4ba1da01d5a96ee6640 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -21,48 +21,52 @@ filegroup { srcs: [ ":statslog-bluetooth-java-gen", "src/**/*.java", - "src/**/*.kt", - ], - visibility: [ - "//frameworks/base/services", - "//frameworks/base/services/core", - ], -} - -java_defaults { - name: "service-bluetooth-common-defaults", - defaults: ["bluetooth-module-sdk-version-defaults"], - errorprone: { - javacflags: ["-Xep:CheckReturnValue:ERROR"], - }, - product_variables: { - pdk: { - enabled: false, - }, - }, - apex_available: [ - "com.android.btservices", - ], - min_sdk_version: "Tiramisu", - defaults_visibility: [ - ":__subpackages__", + "src/AdapterState.kt", + "src/Log.kt", + "src/RadioModeListener.kt", + "src/airplane/ModeListener.kt", + "src/com/**/*.kt", + "src/satellite/ModeListener.kt", ], + visibility: [":__subpackages__"], } // pre-jarjar version of service-bluetooth that builds against pre-jarjar version of framework-bluetooth -java_library { +java_defaults { name: "service-bluetooth-pre-jarjar", - installable: false, - defaults: ["service-bluetooth-common-defaults"], srcs: [ ":services.bluetooth-sources", ], + errorprone: { + javacflags: [ + "-Xep:AlreadyChecked:ERROR", + "-Xep:CheckReturnValue:ERROR", + "-Xep:ClassCanBeStatic:ERROR", + "-Xep:EqualsIncompatibleType:ERROR", + "-Xep:ReferenceEquality:ERROR", + ], + }, + sdk_version: "system_server_current", lint: { + error_checks: [ + "ExtraText", + "NewApi", + "ObsoleteSdkInt", + "Recycle", + "RtlHardcoded", + "UseSparseArrays", + "UseValueOf", + ], strict_updatability_linting: true, }, + + kotlincflags: [ + "-Werror", + ], + libs: [ "framework-annotations-lib", "framework-bluetooth-pre-jarjar", @@ -77,25 +81,23 @@ java_library { "bluetooth-manager-service-proto-java-gen", "bluetooth-nano-protos", "bluetooth-proto-enums-java-gen", + "bluetooth_flags_java_lib", "modules-utils-shell-command-handler", ], + + visibility: [":__subpackages__"], } // service-bluetooth static library // ============================================================== java_library { name: "service-bluetooth", - defaults: ["service-bluetooth-common-defaults"], + defaults: ["service-bluetooth-pre-jarjar"], installable: true, - static_libs: [ - "androidx.appcompat_appcompat", - "service-bluetooth-pre-jarjar", - ], libs: [ "framework-bluetooth.impl", ], - sdk_version: "system_server_current", jarjar_rules: ":bluetooth-jarjar-rules", @@ -107,6 +109,10 @@ java_library { visibility: [ "//packages/modules/Bluetooth/apex", ], + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "Tiramisu", } java_library { @@ -130,8 +136,7 @@ java_library { java_library { name: "bluetooth-nano-protos", - sdk_version: "system_current", - min_sdk_version: "Tiramisu", + installable: false, proto: { type: "nano", }, @@ -139,10 +144,44 @@ java_library { ":system-messages-proto-src", ], libs: ["libprotobuf-java-nano"], - apex_available: [ - "com.android.btservices", - ], lint: { strict_updatability_linting: true, }, + sdk_version: "system_current", + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "Tiramisu", +} + +android_robolectric_test { + name: "ServiceBluetoothRoboTests", + instrumentation_for: "ServiceBluetoothFakeTestApp", + + srcs: [ + ":statslog-bluetooth-java-gen", + "src/AdapterState.kt", + "src/AdapterStateTest.kt", + "src/Log.kt", + "src/LogTest.kt", + "src/RadioModeListener.kt", + "src/RadioModeListenerTest.kt", + "src/airplane/ModeListener.kt", + "src/airplane/ModeListenerTest.kt", + "src/satellite/ModeListener.kt", + "src/satellite/ModeListenerTest.kt", + ], + + static_libs: [ + "androidx.test.core", + "kotlinx_coroutines", + "kotlinx_coroutines_test", + "mockito-robolectric-prebuilt", + "platform-test-annotations", + "testng", + "truth", + ], + + upstream: true, + test_suites: ["general-tests"], } diff --git a/system/osi/test/fuzzers/array/Android.bp b/service/aidl/Android.bp similarity index 55% rename from system/osi/test/fuzzers/array/Android.bp rename to service/aidl/Android.bp index 97cbacbc812672390e411272b600c6d905900a46..28abb8ecac0dcc8d2c9d0389c509c36dced4ab2e 100644 --- a/system/osi/test/fuzzers/array/Android.bp +++ b/service/aidl/Android.bp @@ -7,18 +7,14 @@ package { default_applicable_licenses: ["system_bt_license"], } -cc_fuzz { - name: "libosi_fuzz_array", - defaults: ["libosi_fuzz_defaults"], - host_supported: true, - srcs: [ - "fuzz_array.cc", - ], - shared_libs: [ - "liblog", +// AIDL interface used in service-bluetooth +filegroup { + name: "service-bluetooth-binder-aidl", + visibility: [ + "//packages/modules/Bluetooth:__subpackages__", ], - static_libs: [ - "libchrome", - "libosi", + srcs: [ + "android/bluetooth/IBluetoothManager.aidl", + "android/bluetooth/IBluetoothManagerCallback.aidl", ], } diff --git a/system/binder/android/bluetooth/IBluetoothManager.aidl b/service/aidl/android/bluetooth/IBluetoothManager.aidl similarity index 93% rename from system/binder/android/bluetooth/IBluetoothManager.aidl rename to service/aidl/android/bluetooth/IBluetoothManager.aidl index 4507cb3e02ae0e24ef533ce751b0297d291f04fd..df32f2a2680da23e2ee28dae4c339234e3b61cfc 100644 --- a/system/binder/android/bluetooth/IBluetoothManager.aidl +++ b/service/aidl/android/bluetooth/IBluetoothManager.aidl @@ -17,7 +17,6 @@ package android.bluetooth; import android.bluetooth.IBluetooth; -import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; @@ -44,11 +43,9 @@ interface IBluetoothManager boolean disable(in AttributionSource attributionSource, boolean persist); @JavaPassthrough(annotation="@android.annotation.RequiresNoPermission") int getState(); - @JavaPassthrough(annotation="@android.annotation.RequiresNoPermission") - IBluetoothGatt getBluetoothGatt(); @JavaPassthrough(annotation="@android.annotation.RequiresNoPermission") - boolean bindBluetoothProfileService(int profile, String serviceName, IBluetoothProfileServiceConnection proxy); + boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); @JavaPassthrough(annotation="@android.annotation.RequiresNoPermission") void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); diff --git a/system/binder/android/bluetooth/IBluetoothManagerCallback.aidl b/service/aidl/android/bluetooth/IBluetoothManagerCallback.aidl similarity index 97% rename from system/binder/android/bluetooth/IBluetoothManagerCallback.aidl rename to service/aidl/android/bluetooth/IBluetoothManagerCallback.aidl index 27ad2a0bab73262e9df89cdaed1f3bb7e7b348c4..01b686709e6cf0f43237aae4b1a609c6b3cade3f 100644 --- a/system/binder/android/bluetooth/IBluetoothManagerCallback.aidl +++ b/service/aidl/android/bluetooth/IBluetoothManagerCallback.aidl @@ -26,5 +26,4 @@ import android.bluetooth.IBluetooth; oneway interface IBluetoothManagerCallback { void onBluetoothServiceUp(in IBluetooth bluetoothService); void onBluetoothServiceDown(); - void onBrEdrDown(); } diff --git a/service/change-ids/Android.bp b/service/change-ids/Android.bp index 0d85825cb2cac09eb6fc59b361a98b5432642c06..f9e8fefc961b7033107b96220ccf3ff9a72ab185 100644 --- a/service/change-ids/Android.bp +++ b/service/change-ids/Android.bp @@ -18,13 +18,16 @@ package { java_library { name: "service-bluetooth.change-ids", - defaults: ["service-bluetooth-common-defaults"], srcs: [ "com/android/server/bluetooth/ChangeIds.java", ], libs: [ "app-compat-annotations", ], + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "Tiramisu", sdk_version: "system_server_current", } diff --git a/service/fake_app/Android.bp b/service/fake_app/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..01bd3772f6aac108609e713b72e09a145c16fa97 --- /dev/null +++ b/service/fake_app/Android.bp @@ -0,0 +1,4 @@ +android_app { + name: "ServiceBluetoothFakeTestApp", + sdk_version: "Tiramisu", +} diff --git a/service/fake_app/AndroidManifest.xml b/service/fake_app/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..b934b0f29762183dcac56d2490ef3fd78ad7eade --- /dev/null +++ b/service/fake_app/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + diff --git a/service/generate_local_coverage.sh b/service/generate_local_coverage.sh new file mode 100755 index 0000000000000000000000000000000000000000..38dbc88ace1cf0db5d63ef95f142f00edd6ad8d3 --- /dev/null +++ b/service/generate_local_coverage.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +set -e + +# Setup tmp folder +COVERAGE_TMP_FOLDER=/tmp/coverage_robolectric +rm -rf ${COVERAGE_TMP_FOLDER} +mkdir -p ${COVERAGE_TMP_FOLDER}/com/android/server/ + +# Run test + collect coverage +script -q ${COVERAGE_TMP_FOLDER}/atest_log \ + -c 'atest ServiceBluetoothRoboTests -- \ + --jacocoagent-path gs://tradefed_test_resources/teams/code_coverage/jacocoagent.jar \ + --coverage --coverage-toolchain JACOCO' + +COVERAGE_COLLECTED=$(rg 'Test Logs have saved in ' ${COVERAGE_TMP_FOLDER}/atest_log | sed -e 's/^.* //' -e 's/log.*$/log/') + +# Link source into the tmp folder +ln -s "${ANDROID_BUILD_TOP}"/packages/modules/Bluetooth/service/src ${COVERAGE_TMP_FOLDER}/com/android/server/bluetooth + +# Extract class coverage and delete unwanted class for the report +unzip "${ANDROID_HOST_OUT}"/testcases/ServiceBluetoothRoboTests/ServiceBluetoothRoboTests.jar "com/android/server/bluetooth*" -d ${COVERAGE_TMP_FOLDER}/ServiceBluetoothRobo_unzip +# shellcheck disable=SC2046 +rm -rf $(find ${COVERAGE_TMP_FOLDER}/ServiceBluetoothRobo_unzip -iname "*test*") +# shellcheck disable=SC2016 +rm ${COVERAGE_TMP_FOLDER}/ServiceBluetoothRobo_unzip/com/android/server/bluetooth/'BluetoothAdapterState$waitForState$3$invokeSuspend$$inlined$filter$1.class' +rm ${COVERAGE_TMP_FOLDER}/ServiceBluetoothRobo_unzip/com/android/server/bluetooth/R.class + +# Generate report: +java -jar "${ANDROID_BUILD_TOP}"/out/dist/jacoco-cli.jar report "${COVERAGE_COLLECTED}"/invocation_*/inv_*/coverage_*.ec --classfiles ${COVERAGE_TMP_FOLDER}/ServiceBluetoothRobo_unzip --html ${COVERAGE_TMP_FOLDER}/coverage --name coverage.html --sourcefiles ${COVERAGE_TMP_FOLDER} + +# Start python server and expose URL +printf "Url to connect to the coverage \033[32m http://%s:8000 \033[0m\n" "$(hostname)" +python3 -m http.server --directory ${COVERAGE_TMP_FOLDER}/coverage diff --git a/service/lint-baseline.xml b/service/lint-baseline.xml new file mode 100644 index 0000000000000000000000000000000000000000..1bd04e6790d9b13bc5468d888ec1a90ff0157fdc --- /dev/null +++ b/service/lint-baseline.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/service/src/AdapterState.kt b/service/src/AdapterState.kt new file mode 100644 index 0000000000000000000000000000000000000000..672c200abe043eab46cd28a365a2946f5dc494c6 --- /dev/null +++ b/service/src/AdapterState.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth + +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothAdapter.STATE_OFF +import kotlin.time.Duration +import kotlin.time.toKotlinDuration +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeoutOrNull + +/** Thread safe class that allow waiting on a specific state change */ +class BluetoothAdapterState { + // MutableStateFlow cannot be used because it is conflated (See official doc) + private val _uiState = MutableSharedFlow(1 /* replay only most recent value*/) + + init { + set(STATE_OFF) + } + + fun set(s: Int) = runBlocking { _uiState.emit(s) } + + fun get(): Int = _uiState.replayCache.get(0) + + fun oneOf(vararg states: Int): Boolean = states.contains(get()) + + override fun toString() = BluetoothAdapter.nameForState(get()) + + fun waitForState(timeout: java.time.Duration, vararg states: Int) = runBlocking { + waitForState(timeout.toKotlinDuration(), *states) + } + + suspend fun waitForState(timeout: Duration, vararg states: Int): Boolean = + withTimeoutOrNull(timeout) { _uiState.filter { states.contains(it) }.first() } != null +} diff --git a/service/src/AdapterStateTest.kt b/service/src/AdapterStateTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..0b73558b6c3530ba149fba7948fd6468314cba3f --- /dev/null +++ b/service/src/AdapterStateTest.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth.test + +import android.bluetooth.BluetoothAdapter.STATE_OFF +import com.android.server.bluetooth.BluetoothAdapterState +import com.android.server.bluetooth.Log +import com.google.common.truth.Truth.assertThat +import kotlin.time.Duration.Companion.days +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.yield +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestName +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +@kotlinx.coroutines.ExperimentalCoroutinesApi +class BluetoothAdapterStateTest { + + lateinit var mState: BluetoothAdapterState + @JvmField @Rule val testName = TestName() + + @Before + fun setUp() { + Log.i("BluetoothAdapterStateTest", "\t--> setup of " + testName.getMethodName()) + mState = BluetoothAdapterState() + } + + @Test + fun init_isStateOff() { + Log.d("BluetoothAdapterStateTest", "Initial state is " + mState) + assertThat(mState.get()).isEqualTo(STATE_OFF) + } + + @Test + fun get_afterBusy_returnLastValue() { + val max = 10 + for (i in 0..max) mState.set(i) + assertThat(mState.get()).isEqualTo(max) + } + + @Test + fun immediateReturn_whenStateIsAlreadyCorrect() = runTest { + val state = 10 + mState.set(state) + assertThat(runBlocking { mState.waitForState(100.days, state) }).isTrue() + } + + @Test fun expectTimeout() = runTest { assertThat(mState.waitForState(100.days, -1)).isFalse() } + + @Test + fun expectTimeout_CalledJavaApi() = runTest { + assertThat(mState.waitForState(java.time.Duration.ofMillis(10), -1)).isFalse() + } + + @Test + fun setState_whileWaiting() = runTest { + val state = 42 + val waiter = async { mState.waitForState(100.days, state) } + mState.set(state) + assertThat(waiter.await()).isTrue() + } + + @Test + fun concurrentWaiter_NoStateMissed() = runTest { + val state0 = 42 + val state1 = 50 + val state2 = 65 + val waiter0 = + async(start = CoroutineStart.UNDISPATCHED) { mState.waitForState(100.days, state0) } + val waiter1 = + async(start = CoroutineStart.UNDISPATCHED) { mState.waitForState(100.days, state1) } + val waiter2 = + async(start = CoroutineStart.UNDISPATCHED) { mState.waitForState(100.days, state2) } + val waiter3 = + async(start = CoroutineStart.UNDISPATCHED) { mState.waitForState(100.days, -1) } + mState.set(state0) + yield() + mState.set(state1) + yield() + mState.set(state2) + assertThat(waiter0.await()).isTrue() + assertThat(waiter1.await()).isTrue() + assertThat(waiter2.await()).isTrue() + assertThat(waiter3.await()).isFalse() + } + + @Test + fun expectTimeout_waitAfterOverride() = runTest { + val state0 = 42 + val state1 = 50 + mState.set(state0) + yield() + mState.set(state1) + val waiter = + async(start = CoroutineStart.UNDISPATCHED) { mState.waitForState(100.days, state0) } + assertThat(waiter.await()).isFalse() + } + + @Test + fun oneOf_expectMatch() { + val state0 = 42 + val state1 = 50 + mState.set(state0) + assertThat(mState.oneOf(state0, state1)).isTrue() + } + + @Test + fun oneOf_expectNotMatch() { + val state0 = 42 + val state1 = 50 + val state2 = 65 + mState.set(state0) + assertThat(mState.oneOf(state1, state2)).isFalse() + } +} diff --git a/service/src/Log.kt b/service/src/Log.kt new file mode 100644 index 0000000000000000000000000000000000000000..72a423662d6d1cd7bc0580b80b8c520a9b1d22db --- /dev/null +++ b/service/src/Log.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth + +import android.util.Log + +private const val SYSTEM_SERVER_TAG = "BluetoothSystemServer" + +public class Log private constructor() { + companion object { + @JvmStatic + fun v(subtag: String, msg: String) = Log.v(SYSTEM_SERVER_TAG, "${subtag}: ${msg}") + @JvmStatic + fun d(subtag: String, msg: String) = Log.d(SYSTEM_SERVER_TAG, "${subtag}: ${msg}") + @JvmStatic + fun i(subtag: String, msg: String) = Log.i(SYSTEM_SERVER_TAG, "${subtag}: ${msg}") + @JvmStatic + fun w(subtag: String, msg: String) = Log.w(SYSTEM_SERVER_TAG, "${subtag}: ${msg}") + @JvmStatic + fun e(subtag: String, msg: String) = Log.e(SYSTEM_SERVER_TAG, "${subtag}: ${msg}") + @JvmStatic + fun e(subtag: String, msg: String, tr: Throwable) = + Log.e(SYSTEM_SERVER_TAG, "${subtag}: ${msg}", tr) + } +} diff --git a/service/src/LogTest.kt b/service/src/LogTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..86ced2230efcba1b586e3459a1db36fc03d25cbb --- /dev/null +++ b/service/src/LogTest.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth.test + +import com.android.server.bluetooth.Log +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +private const val TAG: String = "LogTest" + +@RunWith(RobolectricTestRunner::class) +class LogTest { + @Test + fun log_verbose() { + Log.v(TAG, "Logging verbose") + } + + @Test + fun log_debug() { + Log.d(TAG, "Logging debug") + } + + @Test + fun log_info() { + Log.i(TAG, "Logging info") + } + + @Test + fun log_warning() { + Log.w(TAG, "Logging warning") + } + + @Test + fun log_error() { + Log.e(TAG, "Logging error") + } + + @Test + fun log_errorThrowable() { + Log.e(TAG, "Logging error… ", RuntimeException("With a Throwable")) + } +} diff --git a/service/src/RadioModeListener.kt b/service/src/RadioModeListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..472fa0480e847946427beba09e80a446e448e121 --- /dev/null +++ b/service/src/RadioModeListener.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth + +import android.content.ContentResolver +import android.database.ContentObserver +import android.os.Handler +import android.os.Looper +import android.provider.Settings + +private const val TAG = "BluetoothRadioModeListener" + +/** + * Listen on radio mode and trigger the callback when it change + * + * @param radio: The radio to listen for, eg: Settings.Global.AIRPLANE_MODE_RADIOS + * @param modeKey: The associated mode key, eg: Settings.Global.AIRPLANE_MODE_ON + * @param callback: The callback to trigger when there is a mode change, pass new mode as parameter + * @return The initial value of the radio + */ +internal fun initializeRadioModeListener( + looper: Looper, + resolver: ContentResolver, + radio: String, + modeKey: String, + callback: (m: Boolean) -> Unit +): Boolean { + val observer = + object : ContentObserver(Handler(looper)) { + override fun onChange(selfChange: Boolean) { + callback(getRadioModeValue(resolver, radio, modeKey)) + } + } + + val notifyForDescendants = false + + resolver.registerContentObserver( + Settings.Global.getUriFor(radio), + notifyForDescendants, + observer + ) + resolver.registerContentObserver( + Settings.Global.getUriFor(modeKey), + notifyForDescendants, + observer + ) + return getRadioModeValue(resolver, radio, modeKey) +} + +/** + * Check if Bluetooth is impacted by the radio and fetch global mode status + * + * @return weither Bluetooth should consider this radio or not + */ +private fun getRadioModeValue(resolver: ContentResolver, radio: String, modeKey: String): Boolean { + return if (isSensitive(resolver, radio)) { + isGlobalModeOn(resolver, modeKey) + } else { + Log.d(TAG, "Not sensitive to " + radio + " change. Forced to false") + false + } +} + +/** + * *Do not use outside of this file to avoid async issues* + * + * @return false if Bluetooth should not listen for mode change related to the {@code radio} + */ +private fun isSensitive(resolver: ContentResolver, radio: String): Boolean { + val radios = Settings.Global.getString(resolver, radio) + return radios != null && radios.contains(Settings.Global.RADIO_BLUETOOTH) +} + +/** + * *Do not use outside of this file to avoid async issues* + * + * @return whether mode {@code modeKey} is on or off in Global settings + */ +private fun isGlobalModeOn(resolver: ContentResolver, modeKey: String): Boolean { + return Settings.Global.getInt(resolver, modeKey, 0) == 1 +} diff --git a/service/src/RadioModeListenerTest.kt b/service/src/RadioModeListenerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..a393bc2770f8af66a3aaadfcc5c83eb56a053beb --- /dev/null +++ b/service/src/RadioModeListenerTest.kt @@ -0,0 +1,223 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth.test + +import android.content.ContentResolver +import android.content.Context +import android.os.Looper +import android.provider.Settings +import androidx.test.core.app.ApplicationProvider +import com.android.server.bluetooth.Log +import com.android.server.bluetooth.initializeRadioModeListener +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestName +import org.junit.runner.RunWith +import org.mockito.Mockito.times +import org.robolectric.RobolectricTestRunner +import org.robolectric.Shadows.shadowOf + +private const val RADIO = "my_awesome_radio" +private const val MODE_KEY = "is_awesome_radio_enabled" +private const val RADIO_BLUETOOTH = Settings.Global.RADIO_BLUETOOTH + +internal fun enableSensitive(resolver: ContentResolver, looper: Looper, radio: String) { + Settings.Global.putString(resolver, radio, "foo," + RADIO_BLUETOOTH + ",bar") + shadowOf(looper).idle() +} + +internal fun disableSensitive(resolver: ContentResolver, looper: Looper, radio: String) { + Settings.Global.putString(resolver, radio, "foo,bar") + shadowOf(looper).idle() +} + +internal fun disableMode(resolver: ContentResolver, looper: Looper, modeKey: String) { + Settings.Global.putInt(resolver, modeKey, 0) + shadowOf(looper).idle() +} + +internal fun enableMode(resolver: ContentResolver, looper: Looper, modeKey: String) { + Settings.Global.putInt(resolver, modeKey, 1) + shadowOf(looper).idle() +} + +@RunWith(RobolectricTestRunner::class) +class RadioModeListenerTest { + private val resolver: ContentResolver = + ApplicationProvider.getApplicationContext().getContentResolver() + @JvmField @Rule val testName = TestName() + + private val looper: Looper = Looper.getMainLooper() + + private lateinit var mode: ArrayList + + @Before + public fun setup() { + Log.i("RadioModeListenerTest", "\t--> setup of " + testName.getMethodName()) + mode = ArrayList() + } + + private fun startListener(): Boolean { + return initializeRadioModeListener(looper, resolver, RADIO, MODE_KEY, this::callback) + } + + private fun enableSensitive() { + enableSensitive(resolver, looper, RADIO) + } + + private fun disableSensitive() { + disableSensitive(resolver, looper, RADIO) + } + + private fun disableMode() { + disableMode(resolver, looper, MODE_KEY) + } + + private fun enableMode() { + enableMode(resolver, looper, MODE_KEY) + } + + private fun callback(newMode: Boolean) = mode.add(newMode) + + @Test + fun initialize_whenNullSensitive_isOff() { + Settings.Global.putString(resolver, RADIO, null) + enableMode() + + val initialValue = startListener() + + assertThat(initialValue).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenNotSensitive_isOff() { + disableSensitive() + enableMode() + + val initialValue = startListener() + + assertThat(initialValue).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun enable_whenNotSensitive_isOff() { + disableSensitive() + disableMode() + + val initialValue = startListener() + + enableMode() + + assertThat(initialValue).isFalse() + assertThat(mode).containsExactly(false) + } + + @Test + fun initialize_whenSensitive_isOff() { + enableSensitive() + disableMode() + + val initialValue = startListener() + + assertThat(initialValue).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenSensitive_isOn() { + enableSensitive() + enableMode() + + val initialValue = startListener() + + assertThat(initialValue).isTrue() + assertThat(mode).isEmpty() + } + + @Test + fun toggleSensitive_whenEnabled_isOnOffOn() { + enableSensitive() + enableMode() + + val initialValue = startListener() + + disableSensitive() + enableSensitive() + + assertThat(initialValue).isTrue() + assertThat(mode).containsExactly(false, true) + } + + @Test + fun toggleEnable_whenSensitive_isOffOnOff() { + enableSensitive() + disableMode() + + val initialValue = startListener() + + enableMode() + disableMode() + + assertThat(initialValue).isFalse() + assertThat(mode).containsExactly(true, false) + } + + @Test + fun disable_whenDisabled_isDicarded() { + enableSensitive() + disableMode() + + val initialValue = startListener() + + disableMode() + disableMode() + + assertThat(initialValue).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun enabled_whenEnabled_isDiscarded() { + enableSensitive() + enableMode() + + val initialValue = startListener() + + enableMode() + enableMode() + + assertThat(initialValue).isTrue() + assertThat(mode).isEmpty() + } + + @Test + fun changeContent_whenDisabled_noDiscard() { + enableSensitive() + disableMode() + + val initialValue = startListener() + + disableSensitive() // The value is changed but the result is still false + enableMode() // The value is changed but the result is still false + + assertThat(initialValue).isFalse() + assertThat(mode).containsExactly(false, false) + } +} diff --git a/service/src/airplane/ModeListener.kt b/service/src/airplane/ModeListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..c53b27e54673134687957ff1eb378d7d2a4de989 --- /dev/null +++ b/service/src/airplane/ModeListener.kt @@ -0,0 +1,352 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:JvmName("AirplaneModeListener") + +package com.android.server.bluetooth.airplane + +import android.bluetooth.BluetoothAdapter.STATE_ON +import android.bluetooth.BluetoothAdapter.STATE_TURNING_OFF +import android.bluetooth.BluetoothAdapter.STATE_TURNING_ON +import android.content.ContentResolver +import android.content.Context +import android.content.res.Resources +import android.os.Looper +import android.provider.Settings +import android.widget.Toast +import com.android.bluetooth.BluetoothStatsLog +import com.android.server.bluetooth.BluetoothAdapterState +import com.android.server.bluetooth.Log +import com.android.server.bluetooth.initializeRadioModeListener +import kotlin.time.Duration.Companion.minutes +import kotlin.time.TimeMark +import kotlin.time.TimeSource + +private const val TAG = "AirplaneModeListener" + +/** @return true if Bluetooth state is impacted by airplane mode */ +public var isOn = false + private set + +/** + * The airplane ModeListener handles system airplane mode change and checks whether it need to + * trigger the callback or not. + * + *

    The information of airplane mode being turns on would not be passed when Bluetooth is on and + * one of the following situations is met: + *

      + *
    • "Airplane Enhancement Mode" is enabled and the user asked for Bluetooth to be on previously + *
    • A media profile is connected (one of A2DP | Hearing Aid | Le Audio) + *
    + */ +@kotlin.time.ExperimentalTime +public fun initialize( + looper: Looper, + systemResolver: ContentResolver, + state: BluetoothAdapterState, + modeCallback: (m: Boolean) -> Unit, + notificationCallback: (state: String) -> Unit, + mediaCallback: () -> Boolean, + userCallback: () -> Context, + timeSource: TimeSource, +) { + + // Wifi got support for "Airplane Enhancement Mode" prior to Bluetooth. + // In order for Wifi to be aware that Bluetooth also support the feature, Bluetooth need to set + // the APM_ENHANCEMENT settings to `1`. + // Value will be set to DEFAULT_APM_ENHANCEMENT_STATE only if the APM_ENHANCEMENT is not set. + Settings.Global.putInt( + systemResolver, + APM_ENHANCEMENT, + Settings.Global.getInt(systemResolver, APM_ENHANCEMENT, DEFAULT_APM_ENHANCEMENT_STATE) + ) + + val airplaneModeAtBoot = + initializeRadioModeListener( + looper, + systemResolver, + Settings.Global.AIRPLANE_MODE_RADIOS, + Settings.Global.AIRPLANE_MODE_ON, + fun(newMode: Boolean) { + val previousMode = isOn + val isBluetoothOn = state.oneOf(STATE_ON, STATE_TURNING_ON, STATE_TURNING_OFF) + val isMediaConnected = isBluetoothOn && mediaCallback() + + isOn = + airplaneModeValueOverride( + systemResolver, + newMode, + isBluetoothOn, + notificationCallback, + userCallback, + isMediaConnected, + ) + + AirplaneMetricSession.handleModeChange( + newMode, + isBluetoothOn, + notificationCallback, + userCallback, + isMediaConnected, + timeSource.markNow(), + ) + + if (previousMode == isOn) { + Log.d(TAG, "Ignore airplane mode change because is already: $isOn") + return + } + + Log.i(TAG, "Trigger callback with state: $isOn") + modeCallback(isOn) + } + ) + + isOn = + airplaneModeValueOverride( + systemResolver, + airplaneModeAtBoot, + null, // Do not provide a Bluetooth on / off as we want to evaluate override + null, // Do not provide a notification callback as we want to keep the boot silent + userCallback, + false, + ) + + // Bluetooth is always off during initialize, and no media profile can be connected + AirplaneMetricSession.handleModeChange( + airplaneModeAtBoot, + false, + notificationCallback, + userCallback, + false, + timeSource.markNow(), + ) + Log.i(TAG, "Initialized successfully with state: $isOn") +} + +@kotlin.time.ExperimentalTime +public fun notifyUserToggledBluetooth( + resolver: ContentResolver, + userContext: Context, + isBluetoothOn: Boolean, +) { + AirplaneMetricSession.notifyUserToggledBluetooth(resolver, userContext, isBluetoothOn) +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////// PRIVATE METHODS ///////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +private fun airplaneModeValueOverride( + resolver: ContentResolver, + currentAirplaneMode: Boolean, + currentBluetoothStatus: Boolean?, + sendAirplaneModeNotification: ((state: String) -> Unit)?, + getUser: () -> Context, + isMediaConnected: Boolean, +): Boolean { + // Airplane mode is being disabled or bluetooth was not on: no override + if (!currentAirplaneMode || currentBluetoothStatus == false) { + return currentAirplaneMode + } + // If "Airplane Enhancement Mode" is on and the user already used the feature … + if (isApmEnhancementEnabled(resolver) && hasUserToggledApm(getUser)) { + // … Staying on only depend on its last action in airplane mode + if (isBluetoothOnAPM(getUser)) { + Log.i(TAG, "Bluetooth stay on during airplane mode because of last user action") + + val isWifiOn = isWifiOnApm(resolver, getUser) + sendAirplaneModeNotification?.invoke( + if (isWifiOn) APM_WIFI_BT_NOTIFICATION else APM_BT_NOTIFICATION + ) + return false + } + return true + } + // … Else, staying on only depend on media profile being connected or not + // + // Note: Once the "Airplane Enhancement Mode" has been used, media override no longer apply + // This has been done on purpose to avoid complexe scenario like: + // 1. User wants Bt off according to "Airplane Enhancement Mode" + // 2. User swithes airplane while there is media => so Bt stays on + // 3. User turns airplane off, stops media and toggles airplane back on + // Should we turn Bt off like asked initialy ? Or keep it `on` like the toggle ? + if (isMediaConnected) { + Log.i(TAG, "Bluetooth stay on during airplane mode because media profile are connected") + ToastNotification.displayIfNeeded(resolver, getUser) + return false + } + return true +} + +internal class ToastNotification private constructor() { + companion object { + private const val TOAST_COUNT = "bluetooth_airplane_toast_count" + internal const val MAX_TOAST_COUNT = 10 + + private fun userNeedToBeNotified(resolver: ContentResolver): Boolean { + val currentToastCount = Settings.Global.getInt(resolver, TOAST_COUNT, 0) + if (currentToastCount >= MAX_TOAST_COUNT) { + return false + } + Settings.Global.putInt(resolver, TOAST_COUNT, currentToastCount + 1) + return true + } + + fun displayIfNeeded(resolver: ContentResolver, getUser: () -> Context) { + if (!userNeedToBeNotified(resolver)) { + Log.d(TAG, "Dismissed Toast notification") + return + } + val userContext = getUser() + val r = userContext.getResources() + val text: CharSequence = + r.getString( + Resources.getSystem() + .getIdentifier("bluetooth_airplane_mode_toast", "string", "android") + ) + Toast.makeText(userContext, text, Toast.LENGTH_LONG).show() + Log.d(TAG, "Displayed Toast notification") + } + } +} + +@kotlin.time.ExperimentalTime +private class AirplaneMetricSession( + private val isBluetoothOnBeforeApmToggle: Boolean, + private val sendAirplaneModeNotification: (state: String) -> Unit, + private val isMediaProfileConnectedBeforeApmToggle: Boolean, + private val sessionStartTime: TimeMark, +) { + companion object { + private var session: AirplaneMetricSession? = null + + fun handleModeChange( + isAirplaneModeOn: Boolean, + isBluetoothOn: Boolean, + sendAirplaneModeNotification: (state: String) -> Unit, + getUser: () -> Context, + isMediaProfileConnected: Boolean, + startTime: TimeMark, + ) { + if (isAirplaneModeOn) { + session = + AirplaneMetricSession( + isBluetoothOn, + sendAirplaneModeNotification, + isMediaProfileConnected, + startTime, + ) + } else { + session?.let { it.terminate(getUser, isBluetoothOn) } + session = null + } + } + + fun notifyUserToggledBluetooth( + resolver: ContentResolver, + userContext: Context, + isBluetoothOn: Boolean, + ) { + session?.let { it.notifyUserToggledBluetooth(resolver, userContext, isBluetoothOn) } + } + } + + private val isBluetoothOnAfterApmToggle = !isOn + private var userToggledBluetoothDuringApm = false + private var userToggledBluetoothDuringApmWithinMinute = false + + fun notifyUserToggledBluetooth( + resolver: ContentResolver, + userContext: Context, + isBluetoothOn: Boolean, + ) { + val isFirstToggle = !userToggledBluetoothDuringApm + userToggledBluetoothDuringApm = true + + if (isFirstToggle) { + val oneMinute = sessionStartTime + 1.minutes + userToggledBluetoothDuringApmWithinMinute = !oneMinute.hasPassedNow() + } + + if (isApmEnhancementEnabled(resolver)) { + // Set "Airplane Enhancement Mode" settings for a specific user + setUserSettingsSecure(userContext, BLUETOOTH_APM_STATE, if (isBluetoothOn) 1 else 0) + setUserSettingsSecure(userContext, APM_USER_TOGGLED_BLUETOOTH, 1) + + if (isBluetoothOn) { + sendAirplaneModeNotification(APM_BT_ENABLED_NOTIFICATION) + } + } + } + + /** Log current airplaneSession. Session cannot be re-use */ + fun terminate(getUser: () -> Context, isBluetoothOn: Boolean) { + BluetoothStatsLog.write( + BluetoothStatsLog.AIRPLANE_MODE_SESSION_REPORTED, + BluetoothStatsLog.AIRPLANE_MODE_SESSION_REPORTED__PACKAGE_NAME__BLUETOOTH, + isBluetoothOnBeforeApmToggle, + isBluetoothOnAfterApmToggle, + isBluetoothOn, + hasUserToggledApm(getUser), + userToggledBluetoothDuringApm, + userToggledBluetoothDuringApmWithinMinute, + isMediaProfileConnectedBeforeApmToggle, + ) + } +} + +// Notification Id for when the airplane mode is turn on but Bluetooth stay on +internal const val APM_BT_NOTIFICATION = "apm_bt_notification" + +// Notification Id for when the airplane mode is turn on but Bluetooth and Wifi stay on +internal const val APM_WIFI_BT_NOTIFICATION = "apm_wifi_bt_notification" + +// Notification Id for when the Bluetooth is turned back on durin airplane mode +internal const val APM_BT_ENABLED_NOTIFICATION = "apm_bt_enabled_notification" + +// Whether the "Airplane Enhancement Mode" is enabled +internal const val APM_ENHANCEMENT = "apm_enhancement_enabled" + +// Whether the user has already toggled and used the "Airplane Enhancement Mode" feature +internal const val APM_USER_TOGGLED_BLUETOOTH = "apm_user_toggled_bluetooth" + +// Whether Bluetooth should remain on in airplane mode +internal const val BLUETOOTH_APM_STATE = "bluetooth_apm_state" + +// Whether Wifi should remain on in airplane mode +internal const val WIFI_APM_STATE = "wifi_apm_state" + +private fun setUserSettingsSecure(userContext: Context, name: String, value: Int) = + Settings.Secure.putInt(userContext.contentResolver, name, value) + +// Define if the "Airplane Enhancement Mode" feature is enabled by default. `0` == disabled +private const val DEFAULT_APM_ENHANCEMENT_STATE = 1 + +/** Airplane Enhancement Mode: Indicate if the feature is enabled or not. */ +private fun isApmEnhancementEnabled(resolver: ContentResolver) = + Settings.Global.getInt(resolver, APM_ENHANCEMENT, DEFAULT_APM_ENHANCEMENT_STATE) == 1 + +/** Airplane Enhancement Mode: Return true if the wifi should stays on during airplane mode */ +private fun isWifiOnApm(resolver: ContentResolver, getUser: () -> Context) = + Settings.Global.getInt(resolver, Settings.Global.WIFI_ON, 0) != 0 && + Settings.Secure.getInt(getUser().contentResolver, WIFI_APM_STATE, 0) == 1 + +/** Airplane Enhancement Mode: Return true if this user already toggled (aka used) the feature */ +private fun hasUserToggledApm(getUser: () -> Context) = + Settings.Secure.getInt(getUser().contentResolver, APM_USER_TOGGLED_BLUETOOTH, 0) == 1 + +/** Airplane Enhancement Mode: Return true if the bluetooth should stays on during airplane mode */ +private fun isBluetoothOnAPM(getUser: () -> Context) = + Settings.Secure.getInt(getUser().contentResolver, BLUETOOTH_APM_STATE, 0) == 1 diff --git a/service/src/airplane/ModeListenerTest.kt b/service/src/airplane/ModeListenerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..2180cc430ad3114be477a77ff20e1f121d45ee93 --- /dev/null +++ b/service/src/airplane/ModeListenerTest.kt @@ -0,0 +1,530 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth.airplane.test + +import android.app.ActivityManager +import android.bluetooth.BluetoothAdapter +import android.content.ContentResolver +import android.content.Context +import android.content.res.Resources +import android.os.Looper +import android.os.UserHandle +import android.provider.Settings +import androidx.test.core.app.ApplicationProvider +import com.android.server.bluetooth.BluetoothAdapterState +import com.android.server.bluetooth.Log +import com.android.server.bluetooth.airplane.APM_BT_ENABLED_NOTIFICATION +import com.android.server.bluetooth.airplane.APM_BT_NOTIFICATION +import com.android.server.bluetooth.airplane.APM_ENHANCEMENT +import com.android.server.bluetooth.airplane.APM_USER_TOGGLED_BLUETOOTH +import com.android.server.bluetooth.airplane.APM_WIFI_BT_NOTIFICATION +import com.android.server.bluetooth.airplane.BLUETOOTH_APM_STATE +import com.android.server.bluetooth.airplane.WIFI_APM_STATE +import com.android.server.bluetooth.airplane.initialize +import com.android.server.bluetooth.airplane.isOn +import com.android.server.bluetooth.airplane.notifyUserToggledBluetooth +import com.android.server.bluetooth.test.disableMode +import com.android.server.bluetooth.test.disableSensitive +import com.android.server.bluetooth.test.enableMode +import com.android.server.bluetooth.test.enableSensitive +import com.google.common.truth.Truth.assertThat +import kotlin.time.Duration.Companion.minutes +import kotlin.time.TestTimeSource +import kotlin.time.TimeSource +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestName +import org.junit.runner.RunWith +import org.mockito.Mockito.times +import org.robolectric.RobolectricTestRunner +import org.robolectric.shadows.ShadowToast + +@RunWith(RobolectricTestRunner::class) +@kotlin.time.ExperimentalTime +class ModeListenerTest { + private val looper: Looper = Looper.getMainLooper() + private val state = BluetoothAdapterState() + private val mContext = ApplicationProvider.getApplicationContext() + private val resolver: ContentResolver = mContext.contentResolver + @JvmField @Rule val testName = TestName() + + private val userContext = + mContext.createContextAsUser(UserHandle.of(ActivityManager.getCurrentUser()), 0) + + private var isMediaProfileConnected = false + private lateinit var mode: ArrayList + private lateinit var notification: ArrayList + + @Before + public fun setup() { + Log.i("AirplaneModeListenerTest", "\t--> setup of " + testName.getMethodName()) + + // Most test will expect the system to be sensitive + off + enableSensitive() + disableMode() + + isMediaProfileConnected = false + mode = ArrayList() + notification = ArrayList() + } + + private fun initializeAirplane() { + initialize( + looper, + resolver, + state, + this::callback, + this::notificationCallback, + this::mediaCallback, + this::userCallback, + TimeSource.Monotonic, + ) + } + + private fun enableSensitive() { + enableSensitive(resolver, looper, Settings.Global.AIRPLANE_MODE_RADIOS) + } + + private fun disableSensitive() { + disableSensitive(resolver, looper, Settings.Global.AIRPLANE_MODE_RADIOS) + } + + private fun disableMode() { + disableMode(resolver, looper, Settings.Global.AIRPLANE_MODE_ON) + } + + private fun enableMode() { + enableMode(resolver, looper, Settings.Global.AIRPLANE_MODE_ON) + } + + private fun callback(newMode: Boolean) = mode.add(newMode) + + private fun notificationCallback(state: String) = notification.add(state) + + private fun mediaCallback() = isMediaProfileConnected + + private fun userCallback() = userContext + + @Test + fun initialize_whenNullSensitive_isOff() { + Settings.Global.putString(resolver, Settings.Global.AIRPLANE_MODE_RADIOS, null) + enableMode() + + initializeAirplane() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenNotSensitive_isOff() { + disableSensitive() + enableMode() + + initializeAirplane() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun enable_whenNotSensitive_isOff() { + disableSensitive() + disableMode() + + initializeAirplane() + + enableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenSensitive_isOff() { + initializeAirplane() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenSensitive_isOn() { + enableSensitive() + enableMode() + + initializeAirplane() + + assertThat(isOn).isTrue() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenApmToggled_isOn() { + enableSensitive() + enableMode() + Settings.Secure.putInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 1) + Settings.Secure.putInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 1) + + initializeAirplane() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun toggleSensitive_whenEnabled_isOnOffOn() { + enableSensitive() + enableMode() + + initializeAirplane() + + disableSensitive() + enableSensitive() + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(false, true) + } + + @Test + fun toggleEnable_whenSensitive_isOffOnOff() { + initializeAirplane() + + enableMode() + disableMode() + + assertThat(isOn).isFalse() + assertThat(mode).containsExactly(true, false) + } + + @Test + fun disable_whenDisabled_discardUpdate() { + initializeAirplane() + + disableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun enabled_whenEnabled_discardOnChange() { + enableSensitive() + enableMode() + + initializeAirplane() + + enableMode() + + assertThat(isOn).isTrue() + assertThat(mode).isEmpty() + } + + @Test + fun changeContent_whenDisabled_discard() { + initializeAirplane() + + disableSensitive() + enableMode() + + assertThat(isOn).isFalse() + // As opposed to the bare RadioModeListener, similar consecutive event are discarded + assertThat(mode).isEmpty() + } + + @Test + fun triggerOverride_whenNoOverride_turnOff() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + + enableMode() + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(true) + assertThat(ShadowToast.shownToastCount()).isEqualTo(0) + } + + @Test + fun triggerOverride_whenMedia_staysOn() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + isMediaProfileConnected = true + + enableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + + assertThat(ShadowToast.shownToastCount()).isEqualTo(1) + assertThat(ShadowToast.getTextOfLatestToast()) + .isEqualTo( + mContext.getString( + Resources.getSystem() + .getIdentifier("bluetooth_airplane_mode_toast", "string", "android") + ) + ) + } + + @Test + fun triggerOverride_whenApmEnhancementNotTrigger_turnOff() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + Settings.Global.putInt(resolver, APM_ENHANCEMENT, 0) + + enableMode() + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(true) + } + + @Test + fun triggerOverride_whenApmEnhancementNotTriggerButMedia_staysOn() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + Settings.Global.putInt(resolver, APM_ENHANCEMENT, 0) + isMediaProfileConnected = true + + enableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun triggerOverride_whenApmEnhancementWasToggled_turnOff() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + Settings.Secure.putInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 1) + + enableMode() + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(true) + } + + @Test + fun triggerOverride_whenApmEnhancementWasToggled_staysOnWithBtNotification() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + Settings.Secure.putInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 1) + Settings.Secure.putInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 1) + + enableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + assertThat(notification).containsExactly(APM_BT_NOTIFICATION) + } + + @Test + fun triggerOverride_whenApmEnhancementWasToggledAndWifiOn_staysOnWithBtWifiNotification() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + Settings.Secure.putInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 1) + Settings.Secure.putInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 1) + + Settings.Global.putInt(resolver, Settings.Global.WIFI_ON, 1) + Settings.Secure.putInt(userContext.contentResolver, WIFI_APM_STATE, 1) + + enableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + assertThat(notification).containsExactly(APM_WIFI_BT_NOTIFICATION) + } + + @Test + fun triggerOverride_whenApmEnhancementWasToggledAndWifiNotOn_staysOnWithBtNotification() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + Settings.Secure.putInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 1) + Settings.Secure.putInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 1) + + Settings.Global.putInt(resolver, Settings.Global.WIFI_ON, 1) + + enableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + assertThat(notification).containsExactly(APM_BT_NOTIFICATION) + } + + @Test + fun showToast_inLoop_stopNotifyWhenMaxToastReached() { + initializeAirplane() + + state.set(BluetoothAdapter.STATE_ON) + isMediaProfileConnected = true + + repeat(30) { + enableMode() + disableMode() + } + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + assertThat(notification).isEmpty() + + assertThat(ShadowToast.shownToastCount()) + .isEqualTo(com.android.server.bluetooth.airplane.ToastNotification.MAX_TOAST_COUNT) + } + + @Test + fun userToggleBluetooth_whenNoSession_nothingHappen() { + initializeAirplane() + + notifyUserToggledBluetooth(resolver, userContext, false) + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + assertThat(notification).isEmpty() + assertThat(ShadowToast.shownToastCount()).isEqualTo(0) + } + + @Test + fun userToggleBluetooth_whenSessionButNoApm_noNotificationAndNoSettingSave() { + initializeAirplane() + Settings.Global.putInt(resolver, APM_ENHANCEMENT, 0) + + enableMode() + notifyUserToggledBluetooth(resolver, userContext, true) + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(true) + assertThat(notification).isEmpty() + assertThat(ShadowToast.shownToastCount()).isEqualTo(0) + assertThat(Settings.Secure.getInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 0)) + .isEqualTo(0) + assertThat( + Settings.Secure.getInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 0) + ) + .isEqualTo(0) + } + + @Test + fun userToggleBluetooth_whenSession_noNotificationAndSettingSaved() { + initializeAirplane() + + enableMode() + notifyUserToggledBluetooth(resolver, userContext, false) + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(true) + assertThat(notification).isEmpty() + assertThat(ShadowToast.shownToastCount()).isEqualTo(0) + assertThat(Settings.Secure.getInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 0)) + .isEqualTo(0) + assertThat( + Settings.Secure.getInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 0) + ) + .isEqualTo(1) + } + + @Test + fun userToggleBluetooth_whenSession_notificationAndSettingSaved() { + initializeAirplane() + + enableMode() + notifyUserToggledBluetooth(resolver, userContext, true) + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(true) + assertThat(notification).containsExactly(APM_BT_ENABLED_NOTIFICATION) + assertThat(ShadowToast.shownToastCount()).isEqualTo(0) + assertThat(Settings.Secure.getInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 0)) + .isEqualTo(1) + assertThat( + Settings.Secure.getInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 0) + ) + .isEqualTo(1) + } + + @Test + fun userToggleTwiceBluetooth_whenSession_notificationAndSettingSaved() { + initializeAirplane() + + enableMode() + notifyUserToggledBluetooth(resolver, userContext, true) + notifyUserToggledBluetooth(resolver, userContext, false) + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(true) + assertThat(notification).containsExactly(APM_BT_ENABLED_NOTIFICATION) + assertThat(ShadowToast.shownToastCount()).isEqualTo(0) + assertThat(Settings.Secure.getInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 0)) + .isEqualTo(0) + assertThat( + Settings.Secure.getInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 0) + ) + .isEqualTo(1) + } + + @Test + fun userToggleBluetooth_whenSessionButNoApm_noNotificationAndNoSettingSave_skipTime() { + val timesource = TestTimeSource() + initialize( + looper, + resolver, + state, + this::callback, + this::notificationCallback, + this::mediaCallback, + this::userCallback, + timesource, + ) + Settings.Global.putInt(resolver, APM_ENHANCEMENT, 0) + + enableMode() + timesource += 2.minutes + notifyUserToggledBluetooth(resolver, userContext, true) + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(true) + assertThat(notification).isEmpty() + assertThat(ShadowToast.shownToastCount()).isEqualTo(0) + assertThat(Settings.Secure.getInt(userContext.contentResolver, BLUETOOTH_APM_STATE, 0)) + .isEqualTo(0) + assertThat( + Settings.Secure.getInt(userContext.contentResolver, APM_USER_TOGGLED_BLUETOOTH, 0) + ) + .isEqualTo(0) + } + + @Test + fun initialize_firstTime_apmSettingIsSet() { + initializeAirplane() + assertThat(Settings.Global.getInt(resolver, APM_ENHANCEMENT, 0)).isEqualTo(1) + } + + @Test + fun initialize_secondTime_apmSettingIsNotOverride() { + val settingValue = 42 + Settings.Global.putInt(resolver, APM_ENHANCEMENT, settingValue) + + initializeAirplane() + + assertThat(Settings.Global.getInt(resolver, APM_ENHANCEMENT, 0)).isEqualTo(settingValue) + } +} diff --git a/service/src/com/android/server/bluetooth/AdapterBinder.kt b/service/src/com/android/server/bluetooth/AdapterBinder.kt new file mode 100644 index 0000000000000000000000000000000000000000..769e6a546f3c57b0f394d12c5e0c582194737e9a --- /dev/null +++ b/service/src/com/android/server/bluetooth/AdapterBinder.kt @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth + +import android.bluetooth.BluetoothProfile +import android.bluetooth.IBluetooth +import android.bluetooth.IBluetoothCallback +import android.content.AttributionSource +import android.os.IBinder +import android.os.RemoteException +import com.android.modules.utils.SynchronousResultReceiver +import com.android.server.bluetooth.BluetoothManagerService.timeToLog +import java.time.Duration +import java.util.concurrent.TimeoutException + +val SYNC_TIMEOUT = Duration.ofSeconds(3) + +class AdapterBinder(rawBinder: IBinder) { + private val TAG = "AdapterBinder" + val adapterBinder: IBluetooth = IBluetooth.Stub.asInterface(rawBinder) + val createdAt = System.currentTimeMillis() + + override fun toString(): String = + "[Binder=" + adapterBinder.hashCode() + ", createdAt=" + timeToLog(createdAt) + "]" + + @Throws(RemoteException::class, TimeoutException::class) + fun disable(source: AttributionSource): Boolean { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.disable(source, recv) + return recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(false) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun enable(quietMode: Boolean, source: AttributionSource): Boolean { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.enable(quietMode, source, recv) + return recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(false) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun getAddress(source: AttributionSource): String? { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.getAddress(source, recv) + return recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(null) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun getName(source: AttributionSource): String? { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.getName(source, recv) + return recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(null) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun stopBle(source: AttributionSource) { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.stopBle(source, recv) + recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(null) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun startBrEdr(source: AttributionSource) { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.startBrEdr(source, recv) + recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(null) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun registerCallback(callback: IBluetoothCallback, source: AttributionSource) { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.registerCallback(callback, source, recv) + recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(null) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun unregisterCallback(callback: IBluetoothCallback, source: AttributionSource) { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.unregisterCallback(callback, source, recv) + recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(null) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun getSupportedProfiles(source: AttributionSource): MutableList { + val supportedProfiles = ArrayList() + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.getSupportedProfiles(source, recv) + val supportedProfilesBitMask = recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(0L) + for (i in 0..BluetoothProfile.MAX_PROFILE_ID) { + if (supportedProfilesBitMask and (1 shl i).toLong() != 0L) { + supportedProfiles.add(i) + } + } + return supportedProfiles + } + + @Throws(RemoteException::class) + fun setForegroundUserId(userId: Int, source: AttributionSource) { + adapterBinder.setForegroundUserId(userId, source) + } + + @Throws(RemoteException::class, TimeoutException::class) + fun unregAllGattClient(source: AttributionSource) { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.unregAllGattClient(source, recv) + recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(null) + } + + fun isMediaProfileConnected(source: AttributionSource): Boolean { + try { + val recv: SynchronousResultReceiver = SynchronousResultReceiver.get() + adapterBinder.isMediaProfileConnected(source, recv) + return recv.awaitResultNoInterrupt(SYNC_TIMEOUT).getValue(false) + } catch (ex: Exception) { + when (ex) { + is RemoteException, + is TimeoutException -> { + Log.e(TAG, "Error when calling isMediaProfileConnected", ex) + } + else -> throw ex + } + return false + } + } +} diff --git a/service/src/com/android/server/bluetooth/BluetoothAirplaneModeListener.java b/service/src/com/android/server/bluetooth/BluetoothAirplaneModeListener.java index 3fda9bebd927fc1c2aef7052cdc3ffd9f2887657..45aa7365e1eef2cac58f843466f0a92ad2aeb72e 100644 --- a/service/src/com/android/server/bluetooth/BluetoothAirplaneModeListener.java +++ b/service/src/com/android/server/bluetooth/BluetoothAirplaneModeListener.java @@ -17,32 +17,38 @@ package com.android.server.bluetooth; import android.annotation.RequiresPermission; +import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; +import android.os.Binder; import android.os.Handler; import android.os.Looper; -import android.os.Message; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; -import android.util.Log; import com.android.bluetooth.BluetoothStatsLog; +import com.android.bluetooth.flags.FeatureFlags; import com.android.internal.annotations.VisibleForTesting; /** - * The BluetoothAirplaneModeListener handles system airplane mode change callback and checks - * whether we need to inform BluetoothManagerService on this change. + * The BluetoothAirplaneModeListener handles system airplane mode change callback and checks whether + * we need to inform BluetoothManagerService on this change. * - * The information of airplane mode turns on would not be passed to the BluetoothManagerService + *

    The information of airplane mode turns on would not be passed to the BluetoothManagerService * when Bluetooth is on and Bluetooth is in one of the following situations: - * 1. Bluetooth A2DP is connected. - * 2. Bluetooth Hearing Aid profile is connected. - * 3. Bluetooth LE Audio is connected + * + *

      + *
    • Bluetooth A2DP is connected. + *
    • Bluetooth Hearing Aid profile is connected. + *
    • Bluetooth LE Audio is connected + *
    */ -public class BluetoothAirplaneModeListener { - private static final String TAG = "BluetoothAirplaneModeListener"; +class BluetoothAirplaneModeListener extends Handler { + private static final String TAG = BluetoothAirplaneModeListener.class.getSimpleName(); + @VisibleForTesting static final String TOAST_COUNT = "bluetooth_airplane_toast_count"; // keeps track of whether wifi should remain on in airplane mode @@ -66,6 +72,9 @@ public class BluetoothAirplaneModeListener { public static final int UNUSED = 0; public static final int USED = 1; + private static final int BLUETOOTH_OFF_APM = 0; + private static final int BLUETOOTH_ON_APM = 1; + @VisibleForTesting static final int MAX_TOAST_COUNT = 10; // 10 times /* Tracks the bluetooth state before entering airplane mode*/ @@ -82,55 +91,76 @@ public class BluetoothAirplaneModeListener { private long mApmEnabledTime = 0; private final BluetoothManagerService mBluetoothManager; - private final BluetoothAirplaneModeHandler mHandler; + private final FeatureFlags mFeatureFlags; private final Context mContext; private BluetoothModeChangeHelper mAirplaneHelper; - private BluetoothNotificationManager mNotificationManager; + private final BluetoothNotificationManager mNotificationManager; + + private boolean mIsAirplaneModeOn; @VisibleForTesting int mToastCount = 0; - BluetoothAirplaneModeListener(BluetoothManagerService service, Looper looper, Context context, - BluetoothNotificationManager notificationManager) { + BluetoothAirplaneModeListener( + BluetoothManagerService service, + Looper looper, + Context context, + BluetoothNotificationManager notificationManager, + FeatureFlags featureFlags) { + super(looper); + mBluetoothManager = service; + mFeatureFlags = featureFlags; mNotificationManager = notificationManager; mContext = context; - mHandler = new BluetoothAirplaneModeHandler(looper); - context.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true, - mAirplaneModeObserver); - } - - private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) { - @Override - public void onChange(boolean unused) { - // Post from system main thread to android_io thread. - Message msg = mHandler.obtainMessage(MSG_AIRPLANE_MODE_CHANGED); - mHandler.sendMessage(msg); + String airplaneModeRadios = + Settings.Global.getString( + mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_RADIOS); + if (airplaneModeRadios != null + && !airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH)) { + Log.w(TAG, "BluetoothAirplaneModeListener: blocked by AIRPLANE_MODE_RADIOS"); + mIsAirplaneModeOn = false; + return; } - }; - private class BluetoothAirplaneModeHandler extends Handler { - BluetoothAirplaneModeHandler(Looper looper) { - super(looper); - } + mIsAirplaneModeOn = isGlobalAirplaneModeOn(mContext); - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_AIRPLANE_MODE_CHANGED: - handleAirplaneModeChange(); - break; - default: - Log.e(TAG, "Invalid message: " + msg.what); - break; - } - } + mContext.getContentResolver() + .registerContentObserver( + Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), + true, + new ContentObserver(this) { + @Override + public void onChange(boolean selfChange) { + // This is called on the looper and doesn't need a lock + boolean isGlobalAirplaneModeOn = isGlobalAirplaneModeOn(mContext); + if (mIsAirplaneModeOn == isGlobalAirplaneModeOn) { + Log.d( + TAG, + "Ignore airplane mode change:" + + (" mIsAirplaneModeOn=" + mIsAirplaneModeOn)); + return; + } + mIsAirplaneModeOn = isGlobalAirplaneModeOn; + handleAirplaneModeChange(mIsAirplaneModeOn); + } + }); + } + + /** Do not use outside of this class to avoid async issues */ + private static boolean isGlobalAirplaneModeOn(Context ctx) { + return BluetoothServerProxy.getInstance() + .settingsGlobalGetInt( + ctx.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) + == 1; } - /** - * Call after boot complete - */ + /** return true if airplaneMode is currently On */ + boolean isAirplaneModeOn() { + return mIsAirplaneModeOn; + } + + /** Call after boot complete */ @VisibleForTesting void start(BluetoothModeChangeHelper helper) { Log.i(TAG, "start"); @@ -150,51 +180,30 @@ public class BluetoothAirplaneModeListener { @VisibleForTesting @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - void handleAirplaneModeChange() { + void handleAirplaneModeChange(boolean isAirplaneModeOn) { if (mAirplaneHelper == null) { return; } - if (mAirplaneHelper.isAirplaneModeOn()) { + if (isAirplaneModeOn) { mApmEnabledTime = SystemClock.elapsedRealtime(); mIsBluetoothOnBeforeApmToggle = mAirplaneHelper.isBluetoothOn(); - mIsBluetoothOnAfterApmToggle = shouldSkipAirplaneModeChange(); - mIsMediaProfileConnectedBeforeApmToggle = mAirplaneHelper.isMediaProfileConnected(); + mIsMediaProfileConnectedBeforeApmToggle = mBluetoothManager.isMediaProfileConnected(); + mIsBluetoothOnAfterApmToggle = + shouldSkipAirplaneModeChange(mIsMediaProfileConnectedBeforeApmToggle); if (mIsBluetoothOnAfterApmToggle) { Log.i(TAG, "Ignore airplane mode change"); - // Airplane mode enabled when Bluetooth is being used for audio/headering aid. + // Airplane mode enabled when Bluetooth is being used for audio/hearing aid. // Bluetooth is not disabled in such case, only state is changed to // BLUETOOTH_ON_AIRPLANE mode. - mAirplaneHelper.setSettingsInt(Settings.Global.BLUETOOTH_ON, + mAirplaneHelper.setSettingsInt( + Settings.Global.BLUETOOTH_ON, BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); - if (!isApmEnhancementEnabled() || !isBluetoothToggledOnApm()) { - if (shouldPopToast()) { - mAirplaneHelper.showToastMessage(); - } - } else { - if (isWifiEnabledOnApm() && isFirstTimeNotification(APM_WIFI_BT_NOTIFICATION)) { - try { - sendApmNotification("bluetooth_and_wifi_stays_on_title", - "bluetooth_and_wifi_stays_on_message", - APM_WIFI_BT_NOTIFICATION); - } catch (Exception e) { - Log.e(TAG, - "APM enhancement BT and Wi-Fi stays on notification not shown"); - } - } else if (!isWifiEnabledOnApm() && isFirstTimeNotification( - APM_BT_NOTIFICATION)) { - try { - sendApmNotification("bluetooth_stays_on_title", - "bluetooth_stays_on_message", - APM_BT_NOTIFICATION); - } catch (Exception e) { - Log.e(TAG, "APM enhancement BT stays on notification not shown"); - } - } - } + displayUserNotificationIfNeeded(); return; } } else { - BluetoothStatsLog.write(BluetoothStatsLog.AIRPLANE_MODE_SESSION_REPORTED, + BluetoothStatsLog.write( + BluetoothStatsLog.AIRPLANE_MODE_SESSION_REPORTED, BluetoothStatsLog.AIRPLANE_MODE_SESSION_REPORTED__PACKAGE_NAME__BLUETOOTH, mIsBluetoothOnBeforeApmToggle, mIsBluetoothOnAfterApmToggle, @@ -206,28 +215,66 @@ public class BluetoothAirplaneModeListener { mUserToggledBluetoothDuringApm = false; mUserToggledBluetoothDuringApmWithinMinute = false; } - mAirplaneHelper.onAirplaneModeChanged(mBluetoothManager); + mBluetoothManager.onAirplaneModeChanged(isAirplaneModeOn); + } + + private void displayUserNotificationIfNeeded() { + if (!isApmEnhancementEnabled() || !isBluetoothToggledOnApm()) { + if (shouldPopToast()) { + mAirplaneHelper.showToastMessage(); + } + return; + } else { + if (mFeatureFlags.airplaneRessourcesInApp()) { + if (isWifiEnabledOnApm()) { + mBluetoothManager.sendAirplaneModeNotification(APM_WIFI_BT_NOTIFICATION); + } else { + mBluetoothManager.sendAirplaneModeNotification(APM_BT_NOTIFICATION); + } + return; + } + if (isWifiEnabledOnApm() && isFirstTimeNotification(APM_WIFI_BT_NOTIFICATION)) { + try { + sendApmNotification( + "bluetooth_and_wifi_stays_on_title", + "bluetooth_and_wifi_stays_on_message", + APM_WIFI_BT_NOTIFICATION); + } catch (Exception e) { + Log.e(TAG, "APM enhancement BT and Wi-Fi stays on notification not shown"); + } + } else if (!isWifiEnabledOnApm() && isFirstTimeNotification(APM_BT_NOTIFICATION)) { + try { + sendApmNotification( + "bluetooth_stays_on_title", + "bluetooth_stays_on_message", + APM_BT_NOTIFICATION); + } catch (Exception e) { + Log.e(TAG, "APM enhancement BT stays on notification not shown"); + } + } + } } @VisibleForTesting - boolean shouldSkipAirplaneModeChange() { + boolean shouldSkipAirplaneModeChange(boolean isMediaProfileConnected) { boolean apmEnhancementUsed = isApmEnhancementEnabled() && isBluetoothToggledOnApm(); // APM feature disabled or user has not used the feature yet by changing BT state in APM // BT will only remain on in APM when media profile is connected - if (!apmEnhancementUsed && mAirplaneHelper.isBluetoothOn() - && mAirplaneHelper.isMediaProfileConnected()) { + if (!apmEnhancementUsed && mAirplaneHelper.isBluetoothOn() && isMediaProfileConnected) { return true; } // APM feature enabled and user has used the feature by changing BT state in APM // BT will only remain on in APM based on user's last action in APM - if (apmEnhancementUsed && mAirplaneHelper.isBluetoothOn() + if (apmEnhancementUsed + && mAirplaneHelper.isBluetoothOn() && mAirplaneHelper.isBluetoothOnAPM()) { return true; } // APM feature enabled and user has not used the feature yet by changing BT state in APM // BT will only remain on in APM if the default value is set to on - if (isApmEnhancementEnabled() && !isBluetoothToggledOnApm() + if (isApmEnhancementEnabled() + && !isBluetoothToggledOnApm() && mAirplaneHelper.isBluetoothOn() && mAirplaneHelper.isBluetoothOnAPM()) { return true; @@ -248,40 +295,88 @@ public class BluetoothAirplaneModeListener { && mAirplaneHelper.getSettingsSecureInt(WIFI_APM_STATE, 0) == 1; } - private boolean isFirstTimeNotification(String name) { - return mAirplaneHelper.getSettingsSecureInt( - name, NOTIFICATION_NOT_SHOWN) == NOTIFICATION_NOT_SHOWN; - } - - /** - * Helper method to send APM notification - */ + /** Helper method to send APM notification */ public void sendApmNotification(String titleId, String messageId, String notificationState) throws PackageManager.NameNotFoundException { String btPackageName = mAirplaneHelper.getBluetoothPackageName(); if (btPackageName == null) { - Log.e(TAG, "Unable to find Bluetooth package name with " - + "APM notification resources"); + Log.e( + TAG, + "Unable to find Bluetooth package name with " + "APM notification resources"); return; } - Resources resources = mContext.getPackageManager() - .getResourcesForApplication(btPackageName); + Resources resources = + mContext.getPackageManager().getResourcesForApplication(btPackageName); int title = resources.getIdentifier(titleId, "string", btPackageName); int message = resources.getIdentifier(messageId, "string", btPackageName); mNotificationManager.sendApmNotification( resources.getString(title), resources.getString(message)); - mAirplaneHelper.setSettingsSecureInt(notificationState, - NOTIFICATION_SHOWN); + mAirplaneHelper.setSettingsSecureInt(notificationState, NOTIFICATION_SHOWN); } - /** - * Helper method to update whether user toggled Bluetooth in airplane mode - */ - public void updateBluetoothToggledTime() { + /** Helper method to update whether user toggled Bluetooth in airplane mode */ + public void notifyUserToggledBluetooth(boolean isOn) { + if (!mIsAirplaneModeOn) { + // User not in Airplane mode, discard event + return; + } if (!mUserToggledBluetoothDuringApm) { mUserToggledBluetoothDuringApmWithinMinute = SystemClock.elapsedRealtime() - mApmEnabledTime < 60000; } mUserToggledBluetoothDuringApm = true; + if (isApmEnhancementEnabled()) { + setSettingsSecureInt(BLUETOOTH_APM_STATE, isOn ? BLUETOOTH_ON_APM : BLUETOOTH_OFF_APM); + setSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, USED); + if (mFeatureFlags.airplaneRessourcesInApp()) { + if (isOn) { + mBluetoothManager.sendAirplaneModeNotification(APM_BT_ENABLED_NOTIFICATION); + } + return; + } + if (isOn && isFirstTimeNotification(APM_BT_ENABLED_NOTIFICATION)) { + // waive WRITE_SECURE_SETTINGS permission check + final long callingIdentity = Binder.clearCallingIdentity(); + try { + sendApmNotification( + "bluetooth_enabled_apm_title", + "bluetooth_enabled_apm_message", + APM_BT_ENABLED_NOTIFICATION); + } catch (Exception e) { + Log.e(TAG, "APM enhancement BT enabled notification not shown"); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + } + } + + /** Return whether APM notification has been shown */ + private boolean isFirstTimeNotification(String name) { + // waive WRITE_SECURE_SETTINGS permission check + final long callingIdentity = Binder.clearCallingIdentity(); + try { + Context userContext = + mContext.createContextAsUser( + UserHandle.of(ActivityManager.getCurrentUser()), 0); + return mAirplaneHelper.getSettingsSecureInt(name, NOTIFICATION_NOT_SHOWN) + == NOTIFICATION_NOT_SHOWN; + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + /** Set the Settings Secure Int value for foreground user */ + private void setSettingsSecureInt(String name, int value) { + // waive WRITE_SECURE_SETTINGS permission check + final long callingIdentity = Binder.clearCallingIdentity(); + try { + Context userContext = + mContext.createContextAsUser( + UserHandle.of(ActivityManager.getCurrentUser()), 0); + Settings.Secure.putInt(userContext.getContentResolver(), name, value); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } } } diff --git a/service/src/com/android/server/bluetooth/BluetoothDeviceConfigChangeTracker.java b/service/src/com/android/server/bluetooth/BluetoothDeviceConfigChangeTracker.java deleted file mode 100644 index a035338b4fa7fc82c7a9e460d1087f635ad20db1..0000000000000000000000000000000000000000 --- a/service/src/com/android/server/bluetooth/BluetoothDeviceConfigChangeTracker.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.bluetooth; - -import android.provider.DeviceConfig; -import android.provider.DeviceConfig.Properties; -import android.util.Log; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * The BluetoothDeviceConfigChangeTracker receives changes to the DeviceConfig for - * NAMESPACE_BLUETOOTH, and determines whether we should queue a restart, if any Bluetooth-related - * INIT_ flags have been changed. - * - *

    The initialProperties should be fetched from the BLUETOOTH namespace in DeviceConfig - */ -public final class BluetoothDeviceConfigChangeTracker { - private static final String TAG = "BluetoothDeviceConfigChangeTracker"; - - private final HashMap mCurrFlags; - - public BluetoothDeviceConfigChangeTracker(Properties initialProperties) { - mCurrFlags = getFlags(initialProperties); - } - - /** - * Updates the instance state tracking the latest init flag values, and determines whether an - * init flag has changed (requiring a restart at some point) - */ - public boolean shouldRestartWhenPropertiesUpdated(Properties newProperties) { - if (!newProperties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) { - return false; - } - ArrayList flags = new ArrayList<>(); - for (String name : newProperties.getKeyset()) { - flags.add(name + "='" + newProperties.getString(name, "") + "'"); - } - Log.d(TAG, "shouldRestartWhenPropertiesUpdated: " + String.join(",", flags)); - boolean shouldRestart = false; - for (String name : newProperties.getKeyset()) { - if (!isInitFlag(name)) { - continue; - } - var oldValue = mCurrFlags.get(name); - var newValue = newProperties.getString(name, ""); - if (newValue.equals(oldValue)) { - continue; - } - Log.d(TAG, "Property " + name + " changed from " + oldValue + " -> " + newValue); - mCurrFlags.put(name, newValue); - shouldRestart = true; - } - return shouldRestart; - } - - private HashMap getFlags(Properties initialProperties) { - var out = new HashMap(); - for (var name : initialProperties.getKeyset()) { - if (isInitFlag(name)) { - out.put(name, initialProperties.getString(name, "")); - } - } - return out; - } - - private Boolean isInitFlag(String flagName) { - return flagName.startsWith("INIT_"); - } -} diff --git a/service/src/com/android/server/bluetooth/BluetoothDeviceConfigListener.java b/service/src/com/android/server/bluetooth/BluetoothDeviceConfigListener.java deleted file mode 100644 index 197ec46e57148a989c10a3d6a420b60c60c5233a..0000000000000000000000000000000000000000 --- a/service/src/com/android/server/bluetooth/BluetoothDeviceConfigListener.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.bluetooth; - -import android.provider.DeviceConfig; -import android.util.Log; - -/** - * The BluetoothDeviceConfigListener handles system device config change callback and checks - * whether we need to inform BluetoothManagerService on this change. - * - * The information of device config change would not be passed to the BluetoothManagerService - * when Bluetooth is on and Bluetooth is in one of the following situations: - * 1. Bluetooth A2DP is connected. - * 2. Bluetooth Hearing Aid profile is connected. - */ -public class BluetoothDeviceConfigListener { - private static final String TAG = "BluetoothDeviceConfigListener"; - - private final BluetoothManagerService mService; - private final boolean mLogDebug; - private final BluetoothDeviceConfigChangeTracker mConfigChangeTracker; - - BluetoothDeviceConfigListener(BluetoothManagerService service, boolean logDebug) { - mService = service; - mLogDebug = logDebug; - mConfigChangeTracker = - new BluetoothDeviceConfigChangeTracker( - DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BLUETOOTH)); - DeviceConfig.addOnPropertiesChangedListener( - DeviceConfig.NAMESPACE_BLUETOOTH, - (Runnable r) -> r.run(), - mDeviceConfigChangedListener); - } - - private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener = - new DeviceConfig.OnPropertiesChangedListener() { - @Override - public void onPropertiesChanged(DeviceConfig.Properties newProperties) { - if (mConfigChangeTracker.shouldRestartWhenPropertiesUpdated(newProperties)) { - Log.d(TAG, "Properties changed, enqueuing restart"); - mService.onInitFlagsChanged(); - } else { - Log.d(TAG, "All properties unchanged, skipping restart"); - } - } - }; -} diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java index 66476d60f7c0523f82ffcd935ee80d57c2a2eb55..2658568c376c8471e792945a45a52ad6cb624ba5 100644 --- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java +++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java @@ -16,38 +16,29 @@ package com.android.server.bluetooth; -import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.bluetooth.BluetoothAdapter.STATE_BLE_ON; +import static android.bluetooth.BluetoothAdapter.STATE_BLE_TURNING_OFF; +import static android.bluetooth.BluetoothAdapter.STATE_BLE_TURNING_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 android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; -import static android.permission.PermissionManager.PERMISSION_GRANTED; -import static android.permission.PermissionManager.PERMISSION_HARD_DENIED; -import static com.android.server.bluetooth.BluetoothAirplaneModeListener.APM_BT_ENABLED_NOTIFICATION; import static com.android.server.bluetooth.BluetoothAirplaneModeListener.APM_ENHANCEMENT; -import static com.android.server.bluetooth.BluetoothAirplaneModeListener.APM_USER_TOGGLED_BLUETOOTH; -import static com.android.server.bluetooth.BluetoothAirplaneModeListener.BLUETOOTH_APM_STATE; -import static com.android.server.bluetooth.BluetoothAirplaneModeListener.NOTIFICATION_NOT_SHOWN; -import static com.android.server.bluetooth.BluetoothAirplaneModeListener.USED; -import static com.android.server.bluetooth.ChangeIds.RESTRICT_ENABLE_DISABLE; -import android.Manifest; +import static java.util.Objects.requireNonNull; + import android.annotation.NonNull; import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; import android.app.ActivityManager; -import android.app.AppOpsManager; import android.app.BroadcastOptions; -import android.app.admin.DevicePolicyManager; -import android.app.compat.CompatChanges; -import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothHearingAid; -import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothCallback; -import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothManager; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; @@ -64,16 +55,13 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.database.ContentObserver; import android.os.Binder; import android.os.Bundle; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.ParcelFileDescriptor; import android.os.PowerExemptionManager; import android.os.Process; import android.os.RemoteCallbackList; @@ -82,20 +70,21 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; -import android.permission.PermissionManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.sysprop.BluetoothProperties; -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; import android.util.proto.ProtoOutputStream; import com.android.bluetooth.BluetoothStatsLog; +import com.android.bluetooth.flags.FeatureFlags; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.modules.utils.SynchronousResultReceiver; import com.android.server.BluetoothManagerServiceDumpProto; +import com.android.server.bluetooth.airplane.AirplaneModeListener; +import com.android.server.bluetooth.satellite.SatelliteModeListener; + +import kotlin.Unit; +import kotlin.time.TimeSource; import java.io.FileDescriptor; import java.io.FileOutputStream; @@ -111,14 +100,12 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantReadWriteLock; -public class BluetoothManagerService extends IBluetoothManager.Stub { - private static final String TAG = "BluetoothManagerService"; - private static final boolean DBG = true; +class BluetoothManagerService { + private static final String TAG = BluetoothManagerService.class.getSimpleName(); private static final String BLUETOOTH_PRIVILEGED = android.Manifest.permission.BLUETOOTH_PRIVILEGED; @@ -127,12 +114,13 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { private static final int CRASH_LOG_MAX_SIZE = 100; private static final int DEFAULT_REBIND_COUNT = 3; - private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind + // Maximum msec to wait for a bind + private static final int TIMEOUT_BIND_MS = + 3000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); - /** - * Timeout value for synchronous binder call - */ - private static final Duration SYNC_CALLS_TIMEOUT = Duration.ofSeconds(3); + // Timeout value for synchronous binder call + private static final Duration SYNC_CALLS_TIMEOUT = + Duration.ofSeconds(3 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1)); /** * @return timeout value for synchronous binder call @@ -141,38 +129,39 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { return SYNC_CALLS_TIMEOUT; } - //Maximum msec to wait for service restart - private static final int SERVICE_RESTART_TIME_MS = 400; - //Maximum msec to wait for restart due to error - private static final int ERROR_RESTART_TIME_MS = 3000; - //Maximum msec to delay MESSAGE_USER_SWITCHED - private static final int USER_SWITCHED_TIME_MS = 200; + // Maximum msec to wait for service restart + private static final int SERVICE_RESTART_TIME_MS + = 400 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); + // Maximum msec to wait for restart due to error + private static final int ERROR_RESTART_TIME_MS + = 3000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); + // Maximum msec to delay MESSAGE_USER_SWITCHED + private static final int USER_SWITCHED_TIME_MS + = 200 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); // Delay for the addProxy function in msec - private static final int ADD_PROXY_DELAY_MS = 100; + private static final int ADD_PROXY_DELAY_MS + = 100 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); // Delay for retrying enable and disable in msec - private static final int ENABLE_DISABLE_DELAY_MS = 300; - private static final int DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS = 300; - private static final int DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS = 86400000; - - private static final int MESSAGE_ENABLE = 1; - @VisibleForTesting - static final int MESSAGE_DISABLE = 2; - private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3; - private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4; - private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; - private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; - private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; - private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; - private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; - private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60; - private static final int MESSAGE_TIMEOUT_BIND = 100; - private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200; - private static final int MESSAGE_USER_SWITCHED = 300; - private static final int MESSAGE_USER_UNLOCKED = 301; - private static final int MESSAGE_ADD_PROXY_DELAYED = 400; - private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; - private static final int MESSAGE_RESTORE_USER_SETTING = 500; - private static final int MESSAGE_INIT_FLAGS_CHANGED = 600; + private static final int ENABLE_DISABLE_DELAY_MS + = 300 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1); + + @VisibleForTesting static final int MESSAGE_ENABLE = 1; + @VisibleForTesting static final int MESSAGE_DISABLE = 2; + @VisibleForTesting static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3; + @VisibleForTesting static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4; + @VisibleForTesting static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; + @VisibleForTesting static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; + @VisibleForTesting static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; + @VisibleForTesting static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; + @VisibleForTesting static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; + @VisibleForTesting static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60; + @VisibleForTesting static final int MESSAGE_TIMEOUT_BIND = 100; + @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_ADD_PROXY_DELAYED = 400; + @VisibleForTesting static final int MESSAGE_BIND_PROFILE_SERVICE = 401; + @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; @@ -181,26 +170,65 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { private static final int MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES = 10; // Bluetooth persisted setting is off - private static final int BLUETOOTH_OFF = 0; + @VisibleForTesting static final int BLUETOOTH_OFF = 0; // Bluetooth persisted setting is on // and Airplane mode won't affect Bluetooth state at start up - private static final int BLUETOOTH_ON_BLUETOOTH = 1; + // This is the default value + @VisibleForTesting static final int BLUETOOTH_ON_BLUETOOTH = 1; // Bluetooth persisted setting is on // but Airplane mode will affect Bluetooth state at start up // and Airplane mode will have higher priority. - @VisibleForTesting - static final int BLUETOOTH_ON_AIRPLANE = 2; - - private static final int BLUETOOTH_OFF_APM = 0; - private static final int BLUETOOTH_ON_APM = 1; - - private static final int SERVICE_IBLUETOOTH = 1; - private static final int SERVICE_IBLUETOOTHGATT = 2; + @VisibleForTesting static final int BLUETOOTH_ON_AIRPLANE = 2; private static final int FLAGS_SYSTEM_APP = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + // APM enhancement feature is enabled by default + // Set this value to 0 to disable the feature + private static final int DEFAULT_APM_ENHANCEMENT_STATE = 1; + + private static final Map PROFILE_TO_SERVICE_NAME = + Map.ofEntries( + Map.entry(BluetoothProfile.HEADSET, "android.bluetooth.IBluetoothHeadset"), + Map.entry(BluetoothProfile.A2DP, "android.bluetooth.IBluetoothA2dp"), + Map.entry(BluetoothProfile.HID_HOST, "android.bluetooth.IBluetoothHidHost"), + Map.entry(BluetoothProfile.PAN, "android.bluetooth.IBluetoothPan"), + Map.entry(BluetoothProfile.PBAP, "android.bluetooth.IBluetoothPbap"), + Map.entry(BluetoothProfile.MAP, "android.bluetooth.IBluetoothMap"), + Map.entry(BluetoothProfile.SAP, "android.bluetooth.IBluetoothSap"), + Map.entry(BluetoothProfile.A2DP_SINK, "android.bluetooth.IBluetoothA2dpSink"), + Map.entry( + BluetoothProfile.AVRCP_CONTROLLER, + "android.bluetooth.IBluetoothAvrcpController"), + Map.entry( + BluetoothProfile.HEADSET_CLIENT, + "android.bluetooth.IBluetoothHeadsetClient"), + Map.entry( + BluetoothProfile.PBAP_CLIENT, "android.bluetooth.IBluetoothPbapClient"), + Map.entry(BluetoothProfile.MAP_CLIENT, "android.bluetooth.IBluetoothMapClient"), + Map.entry(BluetoothProfile.HID_DEVICE, "android.bluetooth.IBluetoothHidDevice"), + Map.entry( + BluetoothProfile.HEARING_AID, "android.bluetooth.IBluetoothHearingAid"), + Map.entry(BluetoothProfile.LE_AUDIO, "android.bluetooth.IBluetoothLeAudio"), + Map.entry( + BluetoothProfile.VOLUME_CONTROL, + "android.bluetooth.IBluetoothVolumeControl"), + Map.entry( + BluetoothProfile.CSIP_SET_COORDINATOR, + "android.bluetooth.IBluetoothCsipSetCoordinator"), + Map.entry( + BluetoothProfile.LE_AUDIO_BROADCAST, + "android.bluetooth.IBluetoothLeAudio"), + Map.entry( + BluetoothProfile.LE_CALL_CONTROL, + "android.bluetooth.IBluetoothLeCallControl"), + Map.entry(BluetoothProfile.HAP_CLIENT, "android.bluetooth.IBluetoothHapClient"), + Map.entry( + BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, + "android.bluetooth.IBluetoothLeBroadcastAssistant")); + private final Context mContext; + private final Looper mLooper; private final UserManager mUserManager; @@ -211,46 +239,51 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { // Locks are not provided for mName and mAddress. // They are accessed in handler or broadcast receiver, same thread context. - private String mAddress; - private String mName; + private String mAddress = null; + private String mName = null; private final ContentResolver mContentResolver; - private final RemoteCallbackList mCallbacks; - private final RemoteCallbackList mStateChangeCallbacks; - private IBinder mBluetoothBinder; + private final RemoteCallbackList mCallbacks = + new RemoteCallbackList(); + private final RemoteCallbackList mStateChangeCallbacks = + new RemoteCallbackList(); + private final BluetoothServiceBinder mBinder; - private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock(); - @GuardedBy("mBluetoothLock") - private IBluetooth mBluetooth; + private final ReentrantReadWriteLock mAdapterLock = new ReentrantReadWriteLock(); - private IBluetoothGatt mBluetoothGatt; - private boolean mBinding; - private boolean mUnbinding; - private List mSupportedProfileList = new ArrayList<>(); + private final FeatureFlags mFeatureFlags; - private BluetoothModeChangeHelper mBluetoothModeChangeHelper; + @GuardedBy("mAdapterLock") + private AdapterBinder mAdapter = null; - private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; + private List mSupportedProfileList = new ArrayList<>(); - private BluetoothDeviceConfigListener mBluetoothDeviceConfigListener; + // TODO(b/309033118): remove BluetoothAirplaneModeListener once use_new_airplane_mode ship + private final BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; + // TODO(b/303552318): remove BluetoothNotificationManager once airplane_ressources_in_app ship private BluetoothNotificationManager mBluetoothNotificationManager; + // TODO(b/289584302): remove BluetoothSatelliteModeListener once use_new_satellite_mode ship private BluetoothSatelliteModeListener mBluetoothSatelliteModeListener; + private final boolean mUseNewSatelliteMode; + private final boolean mUseNewAirplaneMode; + // used inside handler thread private boolean mQuietEnable = false; - private boolean mEnable; + private boolean mEnable = false; private boolean mShutdownInProgress = false; - private static String timeToLog(long timestamp) { - return DateTimeFormatter.ofPattern("MM-dd HH:mm:ss.SSS").withZone(ZoneId.systemDefault()) - .format(Instant.ofEpochMilli(timestamp)); + private Context mCurrentUserContext = null; + + static String timeToLog(long timestamp) { + return DateTimeFormatter.ofPattern("MM-dd HH:mm:ss.SSS") + .withZone(ZoneId.systemDefault()) + .format(Instant.ofEpochMilli(timestamp)); } - /** - * Used for tracking apps that enabled / disabled Bluetooth. - */ - private class ActiveLog { + // Used for tracking apps that enabled / disabled Bluetooth. + private static class ActiveLog { private int mReason; private String mPackageName; private boolean mEnable; @@ -261,11 +294,17 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { mPackageName = packageName; mEnable = enable; mTimestamp = timestamp; + Log.d(TAG, this.toString()); } + @Override public String toString() { - return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ") - + " due to " + getEnableDisableReasonString(mReason) + " by " + mPackageName; + return timeToLog(mTimestamp) + + (mEnable ? " Enabled " : " Disabled ") + + " due to " + + getEnableDisableReasonString(mReason) + + " by " + + mPackageName; } void dump(ProtoOutputStream proto) { @@ -278,77 +317,70 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { private final LinkedList mActiveLogs = new LinkedList<>(); private final LinkedList mCrashTimestamps = new LinkedList<>(); - private int mCrashes; + private int mCrashes = 0; private long mLastEnabledTime; // configuration from external IBinder call which is used to // synchronize with broadcast receiver. - private boolean mQuietEnableExternal; - private boolean mEnableExternal; + private boolean mQuietEnableExternal = false; + private boolean mEnableExternal = false; // Map of apps registered to keep BLE scanning on. private Map mBleApps = new ConcurrentHashMap(); - private int mState; - private final HandlerThread mBluetoothHandlerThread; - private final BluetoothHandler mHandler; - private int mErrorRecoveryRetryCounter; - private final int mSystemUiUid; + private final BluetoothAdapterState mState = new BluetoothAdapterState(); - private boolean mIsHearingAidProfileSupported; + private final BluetoothHandler mHandler; + private int mErrorRecoveryRetryCounter = 0; - private AppOpsManager mAppOps; + private final boolean mIsHearingAidProfileSupported; // Save a ProfileServiceConnections object for each of the bound // bluetooth profile services private final Map mProfileServices = new HashMap<>(); - @GuardedBy("mProfileServices") - private boolean mUnbindingAll = false; - private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { - @Override - public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { - Message msg = - mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState); - mHandler.sendMessage(msg); - } - }; + private volatile boolean mUnbindingAll = false; + + private final IBluetoothCallback mBluetoothCallback = + new IBluetoothCallback.Stub() { + @Override + public void onBluetoothStateChange(int prevState, int newState) + throws RemoteException { + mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState) + .sendToTarget(); + } + }; public void onUserRestrictionsChanged(UserHandle userHandle) { - final boolean newBluetoothDisallowed = mUserManager.hasUserRestrictionForUser( - UserManager.DISALLOW_BLUETOOTH, userHandle); + final boolean newBluetoothDisallowed = + mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_BLUETOOTH, userHandle); // Disallow Bluetooth sharing when either Bluetooth is disallowed or Bluetooth sharing // is disallowed - final boolean newBluetoothSharingDisallowed = mUserManager.hasUserRestrictionForUser( - UserManager.DISALLOW_BLUETOOTH_SHARING, userHandle) || newBluetoothDisallowed; + final boolean newBluetoothSharingDisallowed = + mUserManager.hasUserRestrictionForUser( + UserManager.DISALLOW_BLUETOOTH_SHARING, userHandle) + || newBluetoothDisallowed; // Disable OPP activities for this userHandle updateOppLauncherComponentState(userHandle, newBluetoothSharingDisallowed); // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user. // Only trigger once instead of for all users - if (userHandle == UserHandle.SYSTEM && newBluetoothDisallowed) { - sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED, + if (UserHandle.SYSTEM.equals(userHandle) && newBluetoothDisallowed) { + sendDisableMsg( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED, mContext.getPackageName()); } } - @VisibleForTesting - public void onInitFlagsChanged() { - // TODO(b/265386284) - } - - public boolean onFactoryReset(AttributionSource attributionSource) { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, - "Need BLUETOOTH_PRIVILEGED permission"); - + boolean onFactoryReset(AttributionSource source) { // Wait for stable state if bluetooth is temporary state. int state = getState(); - if (state == BluetoothAdapter.STATE_BLE_TURNING_ON - || state == BluetoothAdapter.STATE_TURNING_ON - || state == BluetoothAdapter.STATE_TURNING_OFF) { - if (!waitForState(Set.of(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_ON))) { + if (state == STATE_BLE_TURNING_ON + || state == STATE_TURNING_ON + || state == STATE_TURNING_OFF) { + if (!waitForState(STATE_BLE_ON, STATE_ON)) { return false; } } @@ -356,38 +388,39 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { // Clear registered LE apps to force shut-off Bluetooth clearBleApps(); state = getState(); - mBluetoothLock.readLock().lock(); + mAdapterLock.readLock().lock(); try { - if (mBluetooth == null) { + if (mAdapter == null) { return false; } - if (state == BluetoothAdapter.STATE_BLE_ON) { + if (state == STATE_BLE_ON) { addActiveLog( BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET, - mContext.getPackageName(), false); - synchronousOnBrEdrDown(attributionSource); + mContext.getPackageName(), + false); + mAdapter.stopBle(source); return true; - } else if (state == BluetoothAdapter.STATE_ON) { + } else if (state == STATE_ON) { addActiveLog( BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET, - mContext.getPackageName(), false); - synchronousDisable(attributionSource); + mContext.getPackageName(), + false); + mAdapter.disable(source); return true; } } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to shutdown Bluetooth", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } return false; } private int estimateBusyTime(int state) { - if (state == BluetoothAdapter.STATE_BLE_ON && isBluetoothPersistedStateOn()) { + if (state == STATE_BLE_ON && isBluetoothPersistedStateOn()) { // Bluetooth is in BLE and is starting classic return SERVICE_RESTART_TIME_MS; - } else if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF - && state != BluetoothAdapter.STATE_BLE_ON) { + } else if (state != STATE_ON && state != STATE_OFF && state != STATE_BLE_ON) { // Bluetooth is turning state return ADD_PROXY_DELAY_MS; } else if (mHandler.hasMessages(MESSAGE_ENABLE) @@ -397,6 +430,23 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { || mHandler.hasMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE) || mHandler.hasMessages(MESSAGE_TIMEOUT_BIND) || mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE)) { + Log.d( + TAG, + "Busy reason:" + + " ENABLE=" + + mHandler.hasMessages(MESSAGE_ENABLE) + + " DISABLE=" + + mHandler.hasMessages(MESSAGE_DISABLE) + + " HANDLE_ENABLE_DELAYED=" + + mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED) + + " HANDLE_DISABLE_DELAYED=" + + mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) + + " RESTART_BLUETOOTH_SERVICE=" + + mHandler.hasMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE) + + " TIMEOUT_BIND=" + + mHandler.hasMessages(MESSAGE_TIMEOUT_BIND) + + " BIND_PROFILE_SERVICE=" + + mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE)); // Bluetooth is restarting return SERVICE_RESTART_TIME_MS; } @@ -404,124 +454,154 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } private void delayModeChangedIfNeeded(Object token, Runnable r, String modechanged) { - mHandler.removeCallbacksAndMessages(token); - final int state = getState(); final int delayMs = estimateBusyTime(state); - Log.d(TAG, "delayModeChangedIfNeeded(" + modechanged + "): " - + "state=" + BluetoothAdapter.nameForState(state) - + ", isAirplaneModeOn()=" + isAirplaneModeOn() - + ", isSatelliteModeSensitive()=" + isSatelliteModeSensitive() - + ", isSatelliteModeOn()=" + isSatelliteModeOn() - + ", delayed=" + delayMs + "ms"); + Log.d( + TAG, + ("delayModeChangedIfNeeded(" + modechanged + "):") + + (" state=" + BluetoothAdapter.nameForState(state)) + + (" isAirplaneModeOn()=" + isAirplaneModeOn()) + + (" isSatelliteModeOn()=" + isSatelliteModeOn()) + + (" delayed=" + delayMs + "ms")); + + mHandler.removeCallbacksAndMessages(token); if (delayMs > 0) { - mHandler.postDelayed(() -> delayModeChangedIfNeeded(token, r, modechanged), - token, delayMs); + mHandler.postDelayed( + () -> delayModeChangedIfNeeded(token, r, modechanged), token, delayMs); } else { r.run(); } } + /** Send Intent to the Notification Service in the Bluetooth app */ + Unit sendAirplaneModeNotification(String notificationState) { + Intent intent = new Intent("android.bluetooth.airplane.action.SEND_NOTIFICATION"); + intent.setComponent(resolveSystemService(intent)); + intent.putExtra("android.bluetooth.airplane.extra.NOTIFICATION_STATE", notificationState); + mContext.startService(intent); + return Unit.INSTANCE; + } + private static final Object ON_AIRPLANE_MODE_CHANGED_TOKEN = new Object(); private static final Object ON_SATELLITE_MODE_CHANGED_TOKEN = new Object(); private static final Object ON_SWITCH_USER_TOKEN = new Object(); @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - void onAirplaneModeChanged() { - delayModeChangedIfNeeded(ON_AIRPLANE_MODE_CHANGED_TOKEN, - () -> handleAirplaneModeChanged(), "onAirplaneModeChanged"); - } - + Unit onAirplaneModeChanged(boolean isAirplaneModeOn) { + mHandler.postDelayed( + () -> + delayModeChangedIfNeeded( + ON_AIRPLANE_MODE_CHANGED_TOKEN, + () -> handleAirplaneModeChanged(isAirplaneModeOn), + "onAirplaneModeChanged"), + ON_AIRPLANE_MODE_CHANGED_TOKEN, + 0); + return Unit.INSTANCE; + } + + // TODO(b/289584302): Update to private once use_new_satellite_mode is enabled @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - void onSatelliteModeChanged() { - delayModeChangedIfNeeded(ON_SATELLITE_MODE_CHANGED_TOKEN, - () -> handleSatelliteModeChanged(), "onSatelliteModeChanged"); + Unit onSatelliteModeChanged(boolean isSatelliteModeOn) { + mHandler.postDelayed( + () -> + delayModeChangedIfNeeded( + ON_SATELLITE_MODE_CHANGED_TOKEN, + () -> handleSatelliteModeChanged(isSatelliteModeOn), + "onSatelliteModeChanged"), + ON_SATELLITE_MODE_CHANGED_TOKEN, + 0); + return Unit.INSTANCE; } @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) void onSwitchUser(UserHandle userHandle) { - delayModeChangedIfNeeded(ON_SWITCH_USER_TOKEN, - () -> handleSwitchUser(userHandle), "onSwitchUser"); + mHandler.postDelayed( + () -> + delayModeChangedIfNeeded( + ON_SWITCH_USER_TOKEN, + () -> handleSwitchUser(userHandle), + "onSwitchUser"), + ON_SWITCH_USER_TOKEN, + 0); } @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - private void handleAirplaneModeChanged() { + private void handleAirplaneModeChanged(boolean isAirplaneModeOn) { synchronized (this) { if (isBluetoothPersistedStateOn()) { - if (isAirplaneModeOn()) { + if (isAirplaneModeOn) { persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); } else { persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); } } - int st = BluetoothAdapter.STATE_OFF; - try { - mBluetoothLock.readLock().lock(); - st = synchronousGetState(); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "Unable to call getState", e); - return; - } finally { - mBluetoothLock.readLock().unlock(); - } + int st = mState.get(); - Log.d(TAG, - "Airplane Mode change - current state: " + BluetoothAdapter.nameForState( - st) + ", isAirplaneModeOn()=" + isAirplaneModeOn()); + Log.d( + TAG, + "handleAirplaneModeChanged(isAirplaneModeOn=" + + isAirplaneModeOn + + ") | current state=" + + BluetoothAdapter.nameForState(st)); - if (isAirplaneModeOn()) { + if (isAirplaneModeOn) { // Clear registered LE apps to force shut-off clearBleApps(); - // If state is BLE_ON make sure we trigger disableBLE - if (st == BluetoothAdapter.STATE_BLE_ON) { - mBluetoothLock.readLock().lock(); + // If state is BLE_ON make sure we trigger stopBle + if (st == STATE_BLE_ON) { + mAdapterLock.readLock().lock(); try { - if (mBluetooth != null) { + if (mAdapter != null) { addActiveLog( BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, - mContext.getPackageName(), false); - synchronousOnBrEdrDown(mContext.getAttributionSource()); + mContext.getPackageName(), + false); + mAdapter.stopBle(mContext.getAttributionSource()); mEnable = false; mEnableExternal = false; } } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "Unable to call onBrEdrDown", e); + Log.e(TAG, "Unable to call stopBle", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } - } else if (st == BluetoothAdapter.STATE_ON) { - sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, + } else if (st == STATE_ON) { + sendDisableMsg( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, mContext.getPackageName()); } } else if (mEnableExternal) { - sendEnableMsg(mQuietEnableExternal, + sendEnableMsg( + mQuietEnableExternal, BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, mContext.getPackageName()); } } } - private void handleSatelliteModeChanged() { - if (shouldBluetoothBeOn() && getState() != BluetoothAdapter.STATE_ON) { - sendEnableMsg(mQuietEnableExternal, + private void handleSatelliteModeChanged(boolean isSatelliteModeOn) { + if (shouldBluetoothBeOn(isSatelliteModeOn) && getState() != STATE_ON) { + sendEnableMsg( + mQuietEnableExternal, BluetoothProtoEnums.ENABLE_DISABLE_REASON_SATELLITE_MODE, mContext.getPackageName()); - } else if (!shouldBluetoothBeOn() && getState() != BluetoothAdapter.STATE_OFF) { - sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_SATELLITE_MODE, + } else if (!shouldBluetoothBeOn(isSatelliteModeOn) && getState() != STATE_OFF) { + sendDisableMsg( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_SATELLITE_MODE, mContext.getPackageName()); } } - private boolean shouldBluetoothBeOn() { + private boolean shouldBluetoothBeOn(boolean isSatelliteModeOn) { if (!isBluetoothPersistedStateOn()) { Log.d(TAG, "shouldBluetoothBeOn: User want BT off."); return false; } - if (isSatelliteModeOn()) { + if (isSatelliteModeOn) { Log.d(TAG, "shouldBluetoothBeOn: BT should be off as satellite mode is on."); return false; } @@ -535,117 +615,96 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { return true; } - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { - String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); - if (DBG) { - Log.d(TAG, "Bluetooth Adapter name changed to " + newName + " by " - + mContext.getPackageName()); - } - if (newName != null) { - storeNameAndAddress(newName, null); - } - } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) { - String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS); - if (newAddress != null) { - if (DBG) { - Log.d(TAG, "Bluetooth Adapter address changed to " + newAddress); - } - storeNameAndAddress(null, newAddress); - } else { - if (DBG) { - Log.e(TAG, "No Bluetooth Adapter address parameter found"); - } - } - } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { - final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); - if (Settings.Global.BLUETOOTH_ON.equals(name)) { - // The Bluetooth On state may be changed during system restore. - final String prevValue = - intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE); - final String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); - - if (DBG) { - Log.d(TAG, - "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" + prevValue - + ", newValue=" + newValue); - } - - if ((newValue != null) && (prevValue != null) && !prevValue.equals(newValue)) { - Message msg = mHandler.obtainMessage(MESSAGE_RESTORE_USER_SETTING, - newValue.equals("0") ? RESTORE_SETTING_TO_OFF - : RESTORE_SETTING_TO_ON, 0); - mHandler.sendMessage(msg); - } - } - } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action) - || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action) - || BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED.equals(action)) { - final int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, - BluetoothProfile.STATE_CONNECTED); - if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED) - && state == BluetoothProfile.STATE_DISCONNECTED - && !mBluetoothModeChangeHelper.isMediaProfileConnected()) { - Log.i(TAG, "Device disconnected, reactivating pending flag changes"); - onInitFlagsChanged(); - } - } else if (action.equals(Intent.ACTION_SHUTDOWN)) { - Log.i(TAG, "Device is shutting down."); - mShutdownInProgress = true; - mBluetoothLock.readLock().lock(); - try { - mEnable = false; - mEnableExternal = false; - if (mBluetooth != null && (mState == BluetoothAdapter.STATE_BLE_ON)) { - synchronousOnBrEdrDown(mContext.getAttributionSource()); - } else if (mBluetooth != null && (mState == BluetoothAdapter.STATE_ON)) { - synchronousDisable(mContext.getAttributionSource()); + private final BroadcastReceiver mReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { + String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); + if (newName != null) { + Log.d(TAG, "Bluetooth Adapter name changed to " + newName); + storeNameAndAddress(newName, null); + } + } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) { + String newAddress = + intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS); + if (newAddress != null) { + Log.d(TAG, "Bluetooth Adapter address changed to " + newAddress); + storeNameAndAddress(null, newAddress); + } else { + Log.e(TAG, "No Bluetooth Adapter address parameter found"); + } + } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { + final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); + if (Settings.Global.BLUETOOTH_ON.equals(name)) { + // The Bluetooth On state may be changed during system restore. + final String prevValue = + intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE); + final String newValue = + intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); + + Log.d( + TAG, + "ACTION_SETTING_RESTORED with BLUETOOTH_ON" + + (" 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(); + } + } + } else if (action.equals(Intent.ACTION_SHUTDOWN)) { + Log.i(TAG, "Device is shutting down."); + mShutdownInProgress = true; + mAdapterLock.readLock().lock(); + try { + mEnable = false; + mEnableExternal = false; + if (mAdapter != null && mState.oneOf(STATE_BLE_ON)) { + mAdapter.stopBle(mContext.getAttributionSource()); + } else if (mAdapter != null && mState.oneOf(STATE_ON)) { + mAdapter.disable(mContext.getAttributionSource()); + } + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, "Unable to shutdown Bluetooth", e); + } finally { + mAdapterLock.readLock().unlock(); + } } - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "Unable to shutdown Bluetooth", e); - } finally { - mBluetoothLock.readLock().unlock(); } - } - } - }; + }; - BluetoothManagerService(Context context) { - mBluetoothHandlerThread = BluetoothServerProxy.getInstance() - .createHandlerThread("BluetoothManagerService"); - mBluetoothHandlerThread.start(); + BluetoothManagerService( + @NonNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags) { + mContext = requireNonNull(context, "Context cannot be null"); + mContentResolver = requireNonNull(mContext.getContentResolver(), "Resolver cannot be null"); + mLooper = requireNonNull(looper, "Looper cannot be null"); + mFeatureFlags = requireNonNull(featureFlags, "Feature Flags cannot be null"); - mHandler = BluetoothServerProxy.getInstance().newBluetoothHandler( - new BluetoothHandler(mBluetoothHandlerThread.getLooper())); + mUserManager = + requireNonNull( + mContext.getSystemService(UserManager.class), + "UserManager system service cannot be null"); - mContext = context; + mBinder = new BluetoothServiceBinder(this, mContext, mUserManager); + mHandler = new BluetoothHandler(mLooper); - mCrashes = 0; - mBluetooth = null; - mBluetoothBinder = null; - mBluetoothGatt = null; - mBinding = false; - mUnbinding = false; - mEnable = false; - mState = BluetoothAdapter.STATE_OFF; - mQuietEnableExternal = false; - mEnableExternal = false; - mAddress = null; - mName = null; - mErrorRecoveryRetryCounter = 0; - mContentResolver = context.getContentResolver(); // Observe BLE scan only mode settings change. registerForBleScanModeChange(); - mCallbacks = new RemoteCallbackList(); - mStateChangeCallbacks = new RemoteCallbackList(); - mUserManager = mContext.getSystemService(UserManager.class); - - mBluetoothNotificationManager = new BluetoothNotificationManager(mContext); + if (!mFeatureFlags.airplaneRessourcesInApp() && !mFeatureFlags.useNewAirplaneMode()) { + mBluetoothNotificationManager = new BluetoothNotificationManager(mContext); + } // Disable ASHA if BLE is not supported, overriding any system property if (!isBleSupported(mContext)) { @@ -662,24 +721,10 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { .orElse(isAshaEnabledByDefault); } - String value = SystemProperties.get( - "persist.sys.fflag.override.settings_bluetooth_hearing_aid"); - - if (!TextUtils.isEmpty(value)) { - boolean isHearingAidEnabled = Boolean.parseBoolean(value); - Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled); - if (isHearingAidEnabled && !mIsHearingAidProfileSupported) { - // Overwrite to enable support by FeatureFlag - mIsHearingAidProfileSupported = true; - } - } - IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); filter.addAction(Intent.ACTION_SETTING_RESTORED); - filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); - filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(Intent.ACTION_SHUTDOWN); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(mReceiver, filter); @@ -688,404 +733,199 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { filterUser.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED); filterUser.addAction(Intent.ACTION_USER_SWITCHED); filterUser.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - mContext.registerReceiverForAllUsers(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - switch (intent.getAction()) { - case Intent.ACTION_USER_SWITCHED: - int foregroundUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); - propagateForegroundUserId(foregroundUserId); - break; - case UserManager.ACTION_USER_RESTRICTIONS_CHANGED: - onUserRestrictionsChanged(getSendingUser()); - break; - default: - Log.e(TAG, "Unknown broadcast received in BluetoothManagerService receiver" - + " registered across all users"); - } - } - }, filterUser, null, null); + mContext.registerReceiverForAllUsers( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case Intent.ACTION_USER_SWITCHED: + int foregroundUserId = + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); + propagateForegroundUserId(foregroundUserId); + break; + case UserManager.ACTION_USER_RESTRICTIONS_CHANGED: + onUserRestrictionsChanged(getSendingUser()); + break; + default: + Log.e( + TAG, + "Unknown broadcast received in BluetoothManagerService" + + " receiver registered across all users"); + } + } + }, + filterUser, + null, + null); loadStoredNameAndAddress(); if (isBluetoothPersistedStateOn()) { - if (DBG) { - Log.d(TAG, "Startup: Bluetooth persisted state is ON."); - } + Log.i(TAG, "Startup: Bluetooth persisted state is ON."); mEnableExternal = true; } - String airplaneModeRadios = - Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS); - if (airplaneModeRadios == null || airplaneModeRadios.contains( - Settings.Global.RADIO_BLUETOOTH)) { - mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener( - this, mBluetoothHandlerThread.getLooper(), context, - mBluetoothNotificationManager); + // Caching is necessary to prevent caller requiring the READ_DEVICE_CONFIG permission + mUseNewAirplaneMode = mFeatureFlags.useNewAirplaneMode(); + if (mUseNewAirplaneMode) { + mBluetoothAirplaneModeListener = null; + } else { + mBluetoothAirplaneModeListener = + new BluetoothAirplaneModeListener( + this, mLooper, mContext, mBluetoothNotificationManager, mFeatureFlags); } - int systemUiUid = -1; - // Check if device is configured with no home screen, which implies no SystemUI. - try { - systemUiUid = mContext.createContextAsUser(UserHandle.SYSTEM, 0) - .getPackageManager() - .getPackageUid("com.android.systemui", - PackageManager.PackageInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY)); - Log.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid)); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Unable to resolve SystemUI's UID."); + // Caching is necessary to prevent caller requiring the READ_DEVICE_CONFIG permission + mUseNewSatelliteMode = mFeatureFlags.useNewSatelliteMode(); + if (!mUseNewSatelliteMode) { + // Only instantiate the legacy listener + // New implementation is instantiated during onBootPhase on correct thread + mBluetoothSatelliteModeListener = + new BluetoothSatelliteModeListener(this, mLooper, mContext); } - mSystemUiUid = systemUiUid; - - mBluetoothSatelliteModeListener = new BluetoothSatelliteModeListener( - this, mBluetoothHandlerThread.getLooper(), context); } - /** - * Returns true if airplane mode is currently on - */ - private boolean isAirplaneModeOn() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0) == 1; + IBluetoothManager.Stub getBinder() { + return mBinder; } - /** - * @hide constant copied from {@link Settings.Global} - * TODO(b/274636414): Migrate to official API in Android V. - */ - @VisibleForTesting - static final String SETTINGS_SATELLITE_MODE_RADIOS = "satellite_mode_radios"; - /** - * @hide constant copied from {@link Settings.Global} - * TODO(b/274636414): Migrate to official API in Android V. - */ - @VisibleForTesting - static final String SETTINGS_SATELLITE_MODE_ENABLED = "satellite_mode_enabled"; - - private boolean isSatelliteModeSensitive() { - final String satelliteRadios = Settings.Global.getString(mContext.getContentResolver(), - SETTINGS_SATELLITE_MODE_RADIOS); - return satelliteRadios != null - && satelliteRadios.contains(Settings.Global.RADIO_BLUETOOTH); + /** Returns true if airplane mode is currently on */ + private boolean isAirplaneModeOn() { + if (mUseNewAirplaneMode) { + return AirplaneModeListener.isOn(); + } + return mBluetoothAirplaneModeListener.isAirplaneModeOn(); } /** Returns true if satellite mode is turned on. */ private boolean isSatelliteModeOn() { - if (!isSatelliteModeSensitive()) return false; - return Settings.Global.getInt(mContext.getContentResolver(), - SETTINGS_SATELLITE_MODE_ENABLED, 0) == 1; - } - - /** - * Returns true if airplane mode enhancement feature is enabled - */ - private boolean isApmEnhancementOn() { - return Settings.Global.getInt(mContext.getContentResolver(), APM_ENHANCEMENT, 0) == 1; - } - - private boolean supportBluetoothPersistedState() { - // Set default support to true to copy config default. - return BluetoothProperties.isSupportPersistedStateEnabled().orElse(true); + if (mUseNewSatelliteMode) { + return SatelliteModeListener.isOn(); + } + return mBluetoothSatelliteModeListener.isSatelliteModeOn(); } - /** - * Returns true if the Bluetooth saved state is "on" - */ + /** Returns true if the Bluetooth saved state is "on" */ private boolean isBluetoothPersistedStateOn() { - if (!supportBluetoothPersistedState()) { - return false; - } - int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1); - if (DBG) { - Log.d(TAG, "Bluetooth persisted state: " + state); - } + final int state = + BluetoothServerProxy.getInstance() + .getBluetoothPersistedState(mContentResolver, BLUETOOTH_ON_BLUETOOTH); + Log.d(TAG, "isBluetoothPersistedStateOn: " + state); return state != BLUETOOTH_OFF; } private boolean isBluetoothPersistedStateOnAirplane() { - if (!supportBluetoothPersistedState()) { - return false; - } - int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1); - if (DBG) { - Log.d(TAG, "Bluetooth persisted state: " + state); - } + final int state = + BluetoothServerProxy.getInstance() + .getBluetoothPersistedState(mContentResolver, BLUETOOTH_ON_BLUETOOTH); + Log.d(TAG, "isBluetoothPersistedStateOnAirplane: " + state); return state == BLUETOOTH_ON_AIRPLANE; } - /** - * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH - */ + /** Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH */ private boolean isBluetoothPersistedStateOnBluetooth() { - if (!supportBluetoothPersistedState()) { - return false; - } - return Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, - BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH; + final int state = + BluetoothServerProxy.getInstance() + .getBluetoothPersistedState(mContentResolver, BLUETOOTH_ON_BLUETOOTH); + Log.d(TAG, "isBluetoothPersistedStateOnBluetooth: " + state); + return state == BLUETOOTH_ON_BLUETOOTH; } - /** - * Save the Bluetooth on/off state - */ + /** Save the Bluetooth on/off state */ private void persistBluetoothSetting(int value) { - if (DBG) { - Log.d(TAG, "Persisting Bluetooth Setting: " + value); - } + Log.i(TAG, "Persisting Bluetooth Setting: " + value); // waive WRITE_SECURE_SETTINGS permission check final long callingIdentity = Binder.clearCallingIdentity(); try { - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.BLUETOOTH_ON, value); + Settings.Global.putInt( + mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, value); } finally { Binder.restoreCallingIdentity(callingIdentity); } } /** - * Set the Settings Secure Int value for foreground user - */ - private void setSettingsSecureInt(String name, int value) { - if (DBG) { - Log.d(TAG, "Persisting Settings Secure Int: " + name + "=" + value); - } - - // waive WRITE_SECURE_SETTINGS permission check - final long callingIdentity = Binder.clearCallingIdentity(); - try { - Context userContext = mContext.createContextAsUser( - UserHandle.of(ActivityManager.getCurrentUser()), 0); - Settings.Secure.putInt(userContext.getContentResolver(), name, value); - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - } - - /** - * Return whether APM notification has been shown - */ - private boolean isFirstTimeNotification(String name) { - boolean firstTime = false; - // waive WRITE_SECURE_SETTINGS permission check - final long callingIdentity = Binder.clearCallingIdentity(); - try { - Context userContext = mContext.createContextAsUser( - UserHandle.of(ActivityManager.getCurrentUser()), 0); - firstTime = Settings.Secure.getInt(userContext.getContentResolver(), name, - NOTIFICATION_NOT_SHOWN) == NOTIFICATION_NOT_SHOWN; - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - return firstTime; - } - - /** - * Returns true if the Bluetooth Adapter's name and address is - * locally cached + * Returns true if the Bluetooth Adapter's name and address is locally cached + * * @return */ private boolean isNameAndAddressSet() { return mName != null && mAddress != null && mName.length() > 0 && mAddress.length() > 0; } - /** - * Retrieve the Bluetooth Adapter's name and address and save it in - * in the local cache - */ + /** Retrieve the Bluetooth Adapter's name and address and save it in the local cache */ private void loadStoredNameAndAddress() { - if (DBG) { - Log.d(TAG, "Loading stored name and address"); - } if (BluetoothProperties.isAdapterAddressValidationEnabled().orElse(false) - && Settings.Secure.getInt(mContentResolver, - Settings.Secure.BLUETOOTH_ADDR_VALID, 0) == 0) { + && Settings.Secure.getInt(mContentResolver, Settings.Secure.BLUETOOTH_ADDR_VALID, 0) + == 0) { // if the valid flag is not set, don't load the address and name - if (DBG) { - Log.d(TAG, "invalid bluetooth name and address stored"); - } + Log.w(TAG, "There is no valid bluetooth name and address stored"); return; } - mName = BluetoothServerProxy.getInstance() - .settingsSecureGetString(mContentResolver, Settings.Secure.BLUETOOTH_NAME); - mAddress = BluetoothServerProxy.getInstance() - .settingsSecureGetString(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS); + mName = + BluetoothServerProxy.getInstance() + .settingsSecureGetString(mContentResolver, Settings.Secure.BLUETOOTH_NAME); + mAddress = + BluetoothServerProxy.getInstance() + .settingsSecureGetString( + mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS); - if (DBG) { - Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); - } + Log.d(TAG, "loadStoredNameAndAddress: Name=" + mName + ", Address=" + mAddress); } /** - * Save the Bluetooth name and address in the persistent store. - * Only non-null values will be saved. + * Save the Bluetooth name and address in the persistent store. Only non-null values will be + * saved. + * * @param name * @param address */ private void storeNameAndAddress(String name, String address) { if (name != null) { - Settings.Secure.putString(mContentResolver, Settings.Secure.BLUETOOTH_NAME, name); - mName = name; - if (DBG) { - Log.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getString(mContentResolver, - Settings.Secure.BLUETOOTH_NAME)); + if (Settings.Secure.putString(mContentResolver, Settings.Secure.BLUETOOTH_NAME, name)) { + mName = name; + } else { + Log.e(TAG, "Failed to store name=" + name + ". Name is still " + mName); } } if (address != null) { - Settings.Secure.putString(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS, address); - mAddress = address; - if (DBG) { - Log.d(TAG, "Stored Bluetoothaddress: " + Settings.Secure.getString(mContentResolver, - Settings.Secure.BLUETOOTH_ADDRESS)); + if (Settings.Secure.putString( + mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS, address)) { + mAddress = address; + } else { + Log.e(TAG, "Failed to store address=" + address + ". Address is still " + mAddress); } } - if ((name != null) && (address != null)) { + if ((mName != null) && (mAddress != null)) { Settings.Secure.putInt(mContentResolver, Settings.Secure.BLUETOOTH_ADDR_VALID, 1); } + Log.d(TAG, "storeNameAndAddress: Name=" + mName + ", Address=" + mAddress); } - public IBluetooth registerAdapter(IBluetoothManagerCallback callback) { - if (callback == null) { - Log.w(TAG, "Callback is null in registerAdapter"); - return null; - } + IBluetooth registerAdapter(IBluetoothManagerCallback callback) { synchronized (mCallbacks) { mCallbacks.register(callback); } - return mBluetooth; + return mAdapter != null ? mAdapter.getAdapterBinder() : null; } - public void unregisterAdapter(IBluetoothManagerCallback callback) { - if (callback == null) { - Log.w(TAG, "Callback is null in unregisterAdapter"); - return; - } + void unregisterAdapter(IBluetoothManagerCallback callback) { synchronized (mCallbacks) { mCallbacks.unregister(callback); } } - public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { - if (callback == null) { - Log.w(TAG, "registerStateChangeCallback: Callback is null!"); - return; - } - Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); - msg.obj = callback; - mHandler.sendMessage(msg); + void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { + mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK, callback).sendToTarget(); } - public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { - if (callback == null) { - Log.w(TAG, "unregisterStateChangeCallback: Callback is null!"); - return; - } - Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); - msg.obj = callback; - mHandler.sendMessage(msg); - } - - public boolean isEnabled() { - return getState() == BluetoothAdapter.STATE_ON; - } - - @GuardedBy("mBluetoothLock") - private boolean synchronousDisable(AttributionSource attributionSource) - throws RemoteException, TimeoutException { - if (mBluetooth == null) return false; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.disable(attributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false); - } - - @GuardedBy("mBluetoothLock") - private boolean synchronousEnable(boolean quietMode, AttributionSource attributionSource) - throws RemoteException, TimeoutException { - if (mBluetooth == null) return false; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.enable(quietMode, attributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false); - } - - @GuardedBy("mBluetoothLock") - private String synchronousGetAddress(AttributionSource attributionSource) - throws RemoteException, TimeoutException { - if (mBluetooth == null) return null; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.getAddress(attributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } - - @GuardedBy("mBluetoothLock") - private String synchronousGetName(AttributionSource attributionSource) - throws RemoteException, TimeoutException { - if (mBluetooth == null) return null; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.getName(attributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } - - @GuardedBy("mBluetoothLock") - private int synchronousGetState() - throws RemoteException, TimeoutException { - if (mBluetooth == null) return BluetoothAdapter.STATE_OFF; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.getState(recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(BluetoothAdapter.STATE_OFF); - } - - @GuardedBy("mBluetoothLock") - private void synchronousOnBrEdrDown(AttributionSource attributionSource) - throws RemoteException, TimeoutException { - if (mBluetooth == null) return; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.onBrEdrDown(attributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } - - @GuardedBy("mBluetoothLock") - private void synchronousOnLeServiceUp(AttributionSource attributionSource) - throws RemoteException, TimeoutException { - if (mBluetooth == null) return; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.onLeServiceUp(attributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } - - @GuardedBy("mBluetoothLock") - private void synchronousRegisterCallback(IBluetoothCallback callback, - AttributionSource attributionSource) throws RemoteException, TimeoutException { - if (mBluetooth == null) return; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.registerCallback(callback, attributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } - - @GuardedBy("mBluetoothLock") - private void synchronousUnregisterCallback(IBluetoothCallback callback, - AttributionSource attributionSource) throws RemoteException, TimeoutException { - if (mBluetooth == null) return; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.unregisterCallback(callback, attributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } - - @GuardedBy("mBluetoothLock") - private List synchronousGetSupportedProfiles(AttributionSource attributionSource) - throws RemoteException, TimeoutException { - final ArrayList supportedProfiles = new ArrayList(); - if (mBluetooth == null) return supportedProfiles; - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetooth.getSupportedProfiles(attributionSource, recv); - final long supportedProfilesBitMask = - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue((long) 0); - - for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) { - if ((supportedProfilesBitMask & (1 << i)) != 0) { - supportedProfiles.add(i); - } - } + void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { + mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK, callback).sendToTarget(); + } - return supportedProfiles; + boolean isEnabled() { + return getState() == STATE_ON; } /** @@ -1095,35 +935,20 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { * @param userId is the foreground user id we are propagating to the Bluetooth process */ private void propagateForegroundUserId(int userId) { - mBluetoothLock.readLock().lock(); + mAdapterLock.readLock().lock(); try { - if (mBluetooth != null) { - mBluetooth.setForegroundUserId(userId, mContext.getAttributionSource()); + if (mAdapter != null) { + mAdapter.setForegroundUserId(userId, mContext.getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "Unable to set foreground user id", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } } - public int getState() { - if (!isCallerSystem(getCallingAppId()) && !checkIfCallerIsForegroundUser()) { - Log.w(TAG, "getState(): report OFF for non-active and non system user"); - return BluetoothAdapter.STATE_OFF; - } - - mBluetoothLock.readLock().lock(); - try { - if (mBluetooth != null) { - return synchronousGetState(); - } - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "getState()", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - return BluetoothAdapter.STATE_OFF; + int getState() { + return mState.get(); } class ClientDeathRecipient implements IBinder.DeathRecipient { @@ -1134,9 +959,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } public void binderDied() { - if (DBG) { - Log.d(TAG, "Binder is dead - unregister " + mPackageName); - } + Log.w(TAG, "Binder is dead - unregister " + mPackageName); for (Map.Entry entry : mBleApps.entrySet()) { IBinder token = entry.getKey(); @@ -1153,102 +976,86 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } } - @Override - public boolean isBleScanAlwaysAvailable() { + boolean isBleScanAlwaysAvailable() { if (isAirplaneModeOn() && !mEnable) { return false; } try { - return Settings.Global.getInt(mContentResolver, - Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE) != 0; + return Settings.Global.getInt( + mContentResolver, Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE) + != 0; } catch (SettingNotFoundException e) { } return false; } - @Override - public boolean isHearingAidProfileSupported() { + boolean isHearingAidProfileSupported() { return mIsHearingAidProfileSupported; } - private boolean isDeviceProvisioned() { - return Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, - 0) != 0; + Context getCurrentUserContext() { + return mCurrentUserContext; } - // Monitor change of BLE scan only mode settings. - private void registerForProvisioningStateChange() { - ContentObserver contentObserver = new ContentObserver(null) { - @Override - public void onChange(boolean selfChange) { - if (!isDeviceProvisioned()) { - if (DBG) { - Log.d(TAG, "DEVICE_PROVISIONED setting changed, but device is not " - + "provisioned"); - } - return; - } - if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)) { - Log.i(TAG, "Device provisioned, reactivating pending flag changes"); - onInitFlagsChanged(); - } - } - }; - - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), false, - contentObserver); + boolean isMediaProfileConnected() { + if (mAdapter == null || !mState.oneOf(STATE_ON)) { + return false; + } + return mAdapter.isMediaProfileConnected(mContext.getAttributionSource()); } // Monitor change of BLE scan only mode settings. private void registerForBleScanModeChange() { - ContentObserver contentObserver = new ContentObserver(null) { - @Override - public void onChange(boolean selfChange) { - if (isBleScanAlwaysAvailable()) { - // Nothing to do - return; - } - // BLE scan is not available. - disableBleScanMode(); - clearBleApps(); - mBluetoothLock.readLock().lock(); - try { - if (mBluetooth != null) { - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, - mContext.getPackageName(), false); - synchronousOnBrEdrDown(mContext.getAttributionSource()); + ContentObserver contentObserver = + new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + if (isBleScanAlwaysAvailable()) { + // Nothing to do + return; + } + // BLE scan is not available. + disableBleScanMode(); + clearBleApps(); + mAdapterLock.readLock().lock(); + try { + if (mAdapter != null) { + addActiveLog( + BluetoothProtoEnums + .ENABLE_DISABLE_REASON_APPLICATION_REQUEST, + mContext.getPackageName(), + false); + mAdapter.stopBle(mContext.getAttributionSource()); + } + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, "error when disabling bluetooth", e); + } finally { + mAdapterLock.readLock().unlock(); + } } - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "error when disabling bluetooth", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - } - }; + }; - mContentResolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), false, contentObserver); + mContentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), + false, + contentObserver); } // Disable ble scan only mode. private void disableBleScanMode() { - mBluetoothLock.writeLock().lock(); + mAdapterLock.writeLock().lock(); try { - if (mBluetooth != null && synchronousGetState() != BluetoothAdapter.STATE_ON) { - if (DBG) { - Log.d(TAG, "Resetting the mEnable flag for clean disable"); - } + if (mAdapter != null && mState.oneOf(STATE_ON)) { + Log.d(TAG, "disableBleScanMode: Resetting the mEnable flag for clean disable"); mEnable = false; } - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "getState()", e); } finally { - mBluetoothLock.writeLock().unlock(); + mAdapterLock.writeLock().unlock(); } } private int updateBleAppCount(IBinder token, boolean enable, String packageName) { + String header = "updateBleAppCount(" + token + ", " + enable + ", " + packageName + ")"; ClientDeathRecipient r = mBleApps.get(token); if (r == null && enable) { ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName); @@ -1258,127 +1065,90 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!"); } mBleApps.put(token, deathRec); - if (DBG) { - Log.d(TAG, "Registered for death of " + packageName); - } + Log.d(TAG, header + " linkToDeath"); } else if (!enable && r != null) { // Unregister death recipient as the app goes away. token.unlinkToDeath(r, 0); mBleApps.remove(token); - if (DBG) { - Log.d(TAG, "Unregistered for death of " + packageName); - } + Log.d(TAG, header + " unlinkToDeath"); } int appCount = mBleApps.size(); - if (DBG) { - Log.d(TAG, appCount + " registered Ble Apps"); - } + Log.d(TAG, header + " Number of BLE app registered: appCount=" + appCount); return appCount; } - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - private boolean checkBluetoothPermissions(AttributionSource attributionSource, String message, - boolean requireForeground) { - if (isBluetoothDisallowed()) { - if (DBG) { - Log.d(TAG, "checkBluetoothPermissions: bluetooth disallowed"); - } - return false; - } - int callingAppId = getCallingAppId(); - if (!isCallerSystem(callingAppId) - && !isCallerShell(callingAppId) - && !isCallerRoot(callingAppId)) { - checkPackage(attributionSource.getPackageName()); - - if (requireForeground && !checkIfCallerIsForegroundUser()) { - Log.w(TAG, "Not allowed for non-active and non system user"); - return false; - } - - if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, message)) { - return false; - } - } - return true; - } + boolean enableBle(String packageName, IBinder token) { + Log.i( + TAG, + ("enableBle(" + packageName + ", " + token + "):") + + (" mAdapter=" + mAdapter) + + (" isBinding=" + isBinding()) + + (" mState=" + mState)); - public boolean enableBle(AttributionSource attributionSource, IBinder token) - throws RemoteException { - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "enableBle", false) - || isAirplaneModeOn()) { - if (DBG) { - Log.d(TAG, "enableBle(): bluetooth disallowed"); - } + if (isAirplaneModeOn()) { + Log.d(TAG, "enableBle: not enabling - Airplane mode is on"); return false; } - if (DBG) { - Log.d(TAG, "enableBle(" + packageName + "): mBluetooth =" + mBluetooth - + " mBinding = " + mBinding + " mState = " - + BluetoothAdapter.nameForState(mState)); - } - if (isSatelliteModeOn()) { - Log.d(TAG, "enableBle(): not enabling - satellite mode is on."); + Log.d(TAG, "enableBle: not enabling - Satellite mode is on."); return false; } + + // TODO(b/262605980): enableBle/disableBle should be on handler thread updateBleAppCount(token, true, packageName); - if (mState == BluetoothAdapter.STATE_ON - || mState == BluetoothAdapter.STATE_BLE_ON - || mState == BluetoothAdapter.STATE_TURNING_ON - || mState == BluetoothAdapter.STATE_TURNING_OFF - || mState == BluetoothAdapter.STATE_BLE_TURNING_ON) { - Log.d(TAG, "enableBLE(): Bluetooth is already enabled or is turning on"); + if (mState.oneOf( + STATE_ON, + STATE_BLE_ON, + STATE_TURNING_ON, + STATE_TURNING_OFF, + STATE_BLE_TURNING_ON)) { + Log.i(TAG, "enableBle: Bluetooth is already in state" + mState); return true; } synchronized (mReceiver) { // waive WRITE_SECURE_SETTINGS permission check - sendEnableMsg(false, BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, - packageName, true); + sendEnableMsg( + false, + BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, + packageName, + true); } return true; } - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean disableBle(AttributionSource attributionSource, IBinder token) - throws RemoteException { - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "disableBle", false)) { - if (DBG) { - Log.d(TAG, "disableBLE(): bluetooth disallowed"); - } - return false; - } - - if (DBG) { - Log.d(TAG, "disableBle(" + packageName + "): mBluetooth =" + mBluetooth - + " mBinding = " + mBinding + " mState = " - + BluetoothAdapter.nameForState(mState)); - } + boolean disableBle(AttributionSource source, String packageName, IBinder token) { + Log.i( + TAG, + ("disableBle(" + source + ", " + packageName + ", " + token + "):") + + (" mAdapter=" + mAdapter) + + (" isBinding=" + isBinding()) + + (" mState=" + mState)); if (isSatelliteModeOn()) { - Log.d(TAG, "disableBle(): not disabling - satellite mode is on."); + Log.d(TAG, "disableBle: not disabling - satellite mode is on."); return false; } - if (mState == BluetoothAdapter.STATE_OFF) { - Log.d(TAG, "disableBLE(): Already disabled"); + if (mState.oneOf(STATE_OFF)) { + Log.i(TAG, "disableBle: Already disabled"); return false; } + // TODO(b/262605980): enableBle/disableBle should be on handler thread updateBleAppCount(token, false, packageName); - if (mState == BluetoothAdapter.STATE_BLE_ON && !isBleAppPresent()) { + if (mState.oneOf(STATE_BLE_ON) && !isBleAppPresent()) { if (mEnable) { disableBleScanMode(); } if (!mEnableExternal) { - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, - packageName, false); - sendBrEdrDownCallback(attributionSource); + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, + packageName, + false); + sendBrEdrDownCallback(source); } } return true; @@ -1389,229 +1159,149 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { mBleApps.clear(); } - /** @hide */ - public boolean isBleAppPresent() { - if (DBG) { - Log.d(TAG, "isBleAppPresent() count: " + mBleApps.size()); - } + boolean isBleAppPresent() { + Log.d(TAG, "isBleAppPresent(): Number of BLE app registered: " + mBleApps.size()); return mBleApps.size() > 0; } /** - * Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on, - * call IBluetooth.onBrEdrDown() to disable if Bluetooth should be off. + * Will call startBrEdr() if bluetooth classic should be on and will call stopBle if bluetooth + * BLE should be off */ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) private void continueFromBleOnState() { - if (DBG) { - Log.d(TAG, "continueFromBleOnState()"); - } - mBluetoothLock.readLock().lock(); + mAdapterLock.readLock().lock(); try { - if (mBluetooth == null) { - Log.e(TAG, "onBluetoothServiceUp: mBluetooth is null!"); + if (mAdapter == null) { + Log.e(TAG, "continueFromBleOnState: Adapter is null"); return; } if (!mEnableExternal && !isBleAppPresent()) { - Log.i(TAG, "Bluetooth was disabled while enabling BLE, disable BLE now"); + // TODO(b/262605980): this code is unlikely to be trigger and will never be once + // enableBle & disableBle are executed on the handler + Log.i(TAG, "continueFromBleOnState: Disabled while enabling BLE, disable BLE now"); mEnable = false; - synchronousOnBrEdrDown(mContext.getAttributionSource()); + mAdapter.stopBle(mContext.getAttributionSource()); return; } if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) { + Log.i(TAG, "continueFromBleOnState: Starting br edr"); // This triggers transition to STATE_ON - synchronousOnLeServiceUp(mContext.getAttributionSource()); + mAdapter.startBrEdr(mContext.getAttributionSource()); persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); + } else { + Log.i(TAG, "continueFromBleOnState: Staying in BLE_ON"); } } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to call onServiceUp", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } } /** - * Inform BluetoothAdapter instances that BREDR part is down - * and turn off all service and stack if no LE app needs it + * Inform BluetoothAdapter instances that BREDR part is down and turn off all service and stack + * if no LE app needs it */ - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - private void sendBrEdrDownCallback(AttributionSource attributionSource) { - if (DBG) { - Log.d(TAG, "Calling sendBrEdrDownCallback callbacks"); - } - - if (mBluetooth == null) { - Log.w(TAG, "Bluetooth handle is null"); - return; - } - - if (isBleAppPresent()) { - // Need to stay at BLE ON. Disconnect all Gatt connections - try { - final SynchronousResultReceiver recv = SynchronousResultReceiver.get(); - mBluetoothGatt.unregAll(attributionSource, recv); - recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "Unable to disconnect all apps.", e); + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + private void sendBrEdrDownCallback(AttributionSource source) { + mAdapterLock.readLock().lock(); + try { + if (mAdapter == null) { + Log.w(TAG, "sendBrEdrDownCallback: mAdapter is null"); + return; } - } else { - mBluetoothLock.readLock().lock(); - try { - if (mBluetooth != null) { - synchronousOnBrEdrDown(attributionSource); - } - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "Call to onBrEdrDown() failed.", e); - } finally { - mBluetoothLock.readLock().unlock(); + if (isBleAppPresent()) { + // Need to stay at BLE ON. Disconnect all Gatt connections + Log.i(TAG, "sendBrEdrDownCallback: Staying in BLE_ON"); + mAdapter.unregAllGattClient(source); + } else { + Log.i(TAG, "sendBrEdrDownCallback: Stopping ble"); + mAdapter.stopBle(source); } + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, "sendBrEdrDownCallback: Call to mAdapter failed.", e); + } finally { + mAdapterLock.readLock().unlock(); } - } - public boolean enableNoAutoConnect(AttributionSource attributionSource) { - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "enableNoAutoConnect", false)) { - if (DBG) { - Log.d(TAG, "enableNoAutoConnect(): not enabling - bluetooth disallowed"); - } - return false; - } - - if (DBG) { - Log.d(TAG, "enableNoAutoConnect(): mBluetooth =" + mBluetooth + " mBinding = " - + mBinding); - } - - int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); - if (callingAppId != Process.NFC_UID) { - throw new SecurityException("no permission to enable Bluetooth quietly"); - } - + boolean enableNoAutoConnect(String packageName) { if (isSatelliteModeOn()) { - Log.d(TAG, "enableNoAutoConnect(): not enabling - satellite mode is on."); + Log.d(TAG, "enableNoAutoConnect(" + packageName + "): Blocked by satellite mode"); return false; } synchronized (mReceiver) { mQuietEnableExternal = true; mEnableExternal = true; - sendEnableMsg(true, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName); + sendEnableMsg( + true, + BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, + packageName); } return true; } - public boolean enable(AttributionSource attributionSource) throws RemoteException { - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "enable", true)) { - if (DBG) { - Log.d(TAG, "enable(): not enabling - bluetooth disallowed"); - } - return false; - } - - final int callingUid = Binder.getCallingUid(); - final int callingPid = Binder.getCallingPid(); - if (CompatChanges.isChangeEnabled(RESTRICT_ENABLE_DISABLE, callingUid) - && !isPrivileged(callingPid, callingUid) - && !isSystem(packageName, callingUid) - && !isDeviceOwner(callingUid, packageName) - && !isProfileOwner(callingUid, packageName)) { - Log.d(TAG, "enable(): not enabling - Caller is not one of: " - + "privileged | system | deviceOwner | profileOwner"); - return false; - } + boolean enable(String packageName) { + Log.d( + TAG, + ("enable(" + packageName + "):") + + (" mAdapter=" + mAdapter) + + (" isBinding=" + isBinding()) + + (" mState=" + mState)); if (isSatelliteModeOn()) { - Log.d(TAG, "enable(): not enabling - satellite mode is on."); + Log.d(TAG, "enable: not enabling - satellite mode is on."); return false; } - if (DBG) { - Log.d(TAG, "enable(" + packageName + "): mBluetooth=" + mBluetooth + " mBinding=" - + mBinding + " mState=" + BluetoothAdapter.nameForState(mState)); - } - synchronized (mReceiver) { mQuietEnableExternal = false; mEnableExternal = true; - if (isAirplaneModeOn()) { - mBluetoothAirplaneModeListener.updateBluetoothToggledTime(); - if (isApmEnhancementOn()) { - setSettingsSecureInt(BLUETOOTH_APM_STATE, BLUETOOTH_ON_APM); - setSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, USED); - if (isFirstTimeNotification(APM_BT_ENABLED_NOTIFICATION)) { - final long callingIdentity = Binder.clearCallingIdentity(); - try { - mBluetoothAirplaneModeListener.sendApmNotification( - "bluetooth_enabled_apm_title", - "bluetooth_enabled_apm_message", - APM_BT_ENABLED_NOTIFICATION); - } catch (Exception e) { - Log.e(TAG, "APM enhancement BT enabled notification not shown"); - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - } + if (!mUseNewAirplaneMode) { + mBluetoothAirplaneModeListener.notifyUserToggledBluetooth(true); + } else { + // TODO(b/288450479): Remove clearCallingIdentity when threading is fixed + final long callingIdentity = Binder.clearCallingIdentity(); + try { + AirplaneModeListener.notifyUserToggledBluetooth( + mContentResolver, mCurrentUserContext, true); + } finally { + Binder.restoreCallingIdentity(callingIdentity); } } - // waive WRITE_SECURE_SETTINGS permission check - sendEnableMsg(false, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName); - } - if (DBG) { - Log.d(TAG, "enable returning"); + sendEnableMsg( + false, + BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, + packageName); } return true; } - public boolean disable(AttributionSource attributionSource, boolean persist) - throws RemoteException { - if (!persist) { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, - "Need BLUETOOTH_PRIVILEGED permission"); - } - - final String packageName = attributionSource.getPackageName(); - if (!checkBluetoothPermissions(attributionSource, "disable", true)) { - if (DBG) { - Log.d(TAG, "disable(): not disabling - bluetooth disallowed"); - } - return false; - } - - final int callingUid = Binder.getCallingUid(); - final int callingPid = Binder.getCallingPid(); - if (CompatChanges.isChangeEnabled(RESTRICT_ENABLE_DISABLE, callingUid) - && !isPrivileged(callingPid, callingUid) - && !isSystem(packageName, callingUid) - && !isDeviceOwner(callingUid, packageName) - && !isProfileOwner(callingUid, packageName)) { - Log.d(TAG, "disable(): not disabling - Caller is not one of: " - + "privileged | system | deviceOwner | profileOwner"); - return false; - } - - if (isSatelliteModeOn()) { - Log.d(TAG, "disable: not disabling - satellite mode is on."); - return false; - } - - if (DBG) { - Log.d(TAG, "disable(): mBluetooth=" + mBluetooth + ", persist=" + persist - + ", mBinding=" + mBinding); - } + boolean disable(String packageName, boolean persist) { + Log.d( + TAG, + ("disable(" + packageName + ", " + persist + "):") + + (" mAdapter=" + mAdapter) + + (" isBinding=" + isBinding()) + + (" mState=" + mState)); synchronized (mReceiver) { - if (isAirplaneModeOn()) { - mBluetoothAirplaneModeListener.updateBluetoothToggledTime(); - if (isApmEnhancementOn()) { - setSettingsSecureInt(BLUETOOTH_APM_STATE, BLUETOOTH_OFF_APM); - setSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, USED); + if (!mUseNewAirplaneMode) { + mBluetoothAirplaneModeListener.notifyUserToggledBluetooth(false); + } else { + // TODO(b/288450479): Remove clearCallingIdentity when threading is fixed + final long callingIdentity = Binder.clearCallingIdentity(); + try { + AirplaneModeListener.notifyUserToggledBluetooth( + mContentResolver, mCurrentUserContext, false); + } finally { + Binder.restoreCallingIdentity(callingIdentity); } } @@ -1619,127 +1309,72 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { persistBluetoothSetting(BLUETOOTH_OFF); } mEnableExternal = false; - sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, - packageName); + sendDisableMsg( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName); } return true; } - /** - * Check if AppOpsManager is available and the packageName belongs to calling uid - * - * A null package belongs to any uid - */ - private void checkPackage(String packageName) { - int callingUid = Binder.getCallingUid(); - - if (mAppOps == null) { - Log.w(TAG, "checkPackage(): called before system boot up, uid " - + callingUid + ", packageName " + packageName); - throw new IllegalStateException("System has not boot yet"); - } - if (packageName == null) { - Log.w(TAG, "checkPackage(): called with null packageName from " + callingUid); - return; - } - - try { - mAppOps.checkPackage(callingUid, packageName); - } catch (SecurityException e) { - Log.w(TAG, "checkPackage(): " + packageName + " does not belong to uid " + callingUid); - throw new SecurityException(e.getMessage()); - } - } - - /** - * Check if the caller must still pass permission check or if the caller is exempted - * from the consent UI via the MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED check. - * - * Commands from some callers may be exempted from triggering the consent UI when - * enabling bluetooth. This exemption is checked via the - * MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED and allows calls to skip - * the consent UI where it may otherwise be required. - * - * @hide - */ - @SuppressLint("AndroidFrameworkRequiresPermission") - private boolean checkBluetoothPermissionWhenWirelessConsentRequired() { - int result = mContext.checkCallingPermission( - android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED); - return result == PackageManager.PERMISSION_GRANTED; - } - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void unbindAndFinish() { - if (DBG) { - Log.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding - + " mUnbinding = " + mUnbinding); - } + void unbindAndFinish() { + Log.d(TAG, "unbindAndFinish(): mAdapter=" + mAdapter + " isBinding=" + isBinding()); - mBluetoothLock.writeLock().lock(); + mAdapterLock.writeLock().lock(); try { - if (mUnbinding) { - return; - } - mUnbinding = true; mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE); - if (mBluetooth != null) { - //Unregister callback object + if (mAdapter != null) { + // Unregister callback object try { - synchronousUnregisterCallback(mBluetoothCallback, - mContext.getAttributionSource()); + mAdapter.unregisterCallback( + mBluetoothCallback, mContext.getAttributionSource()); } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to unregister BluetoothCallback", e); } - mBluetoothBinder = null; - mBluetooth = null; + mAdapter = null; mContext.unbindService(mConnection); - mUnbinding = false; - mBinding = false; - } else { - mUnbinding = false; + mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); } - mBluetoothGatt = null; } finally { - mBluetoothLock.writeLock().unlock(); + mAdapterLock.writeLock().unlock(); } } - public IBluetoothGatt getBluetoothGatt() { - // sync protection - return mBluetoothGatt; - } + boolean bindBluetoothProfileService( + int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { + String header = "bindBluetoothProfileService(" + bluetoothProfile + ", " + proxy + "):"; - @Override - public boolean bindBluetoothProfileService(int bluetoothProfile, String serviceName, - IBluetoothProfileServiceConnection proxy) { - if (mState != BluetoothAdapter.STATE_ON) { - if (DBG) { - Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile - + ", while Bluetooth was disabled"); - } + if (!mState.oneOf(BluetoothAdapter.STATE_ON)) { + Log.d(TAG, header + " Invalid state, Bluetooth is disabled"); return false; } synchronized (mProfileServices) { if (!mSupportedProfileList.contains(bluetoothProfile)) { - Log.w(TAG, "Cannot bind profile: " + bluetoothProfile - + ", not in supported profiles list"); + Log.w(TAG, header + " Profile is not supported"); return false; } - ProfileServiceConnections psc = - mProfileServices.get(Integer.valueOf(bluetoothProfile)); + ProfileServiceConnections psc = mProfileServices.get(bluetoothProfile); if (psc == null) { - if (DBG) { - Log.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: " - + bluetoothProfile); - } - psc = new ProfileServiceConnections(new Intent(serviceName)); - if (!psc.bindService(DEFAULT_REBIND_COUNT)) { - return false; + Log.d(TAG, header + " Creating new ProfileServiceConnections"); + psc = + new ProfileServiceConnections( + new Intent(PROFILE_TO_SERVICE_NAME.get(bluetoothProfile))); + + // TODO: b/291815510 or b/288450479 - Remove clearCallingIdentity + // bindService is using bindServiceAsUser that require permission to interact + // across users. + // Because this method is called on the binderThread, we need to clear identity + // before attempting to bind + final long callingIdentity = Binder.clearCallingIdentity(); + try { + if (!psc.bindService(DEFAULT_REBIND_COUNT)) { + return false; + } + } finally { + Binder.restoreCallingIdentity(callingIdentity); } - mProfileServices.put(new Integer(bluetoothProfile), psc); + mProfileServices.put(bluetoothProfile, psc); } } @@ -1751,33 +1386,32 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { return true; } - @Override - public void unbindBluetoothProfileService(int bluetoothProfile, - IBluetoothProfileServiceConnection proxy) { + void unbindBluetoothProfileService( + int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { + if (mUnbindingAll) { + return; + } synchronized (mProfileServices) { - Integer profile = new Integer(bluetoothProfile); - ProfileServiceConnections psc = mProfileServices.get(profile); + ProfileServiceConnections psc = mProfileServices.get(bluetoothProfile); if (psc == null) { return; } psc.removeProxy(proxy); if (psc.isEmpty()) { - // All prxoies are disconnected, unbind with the service. + // All proxies are disconnected, unbind with the service. try { mContext.unbindService(psc); } catch (IllegalArgumentException e) { Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e); } - if (!mUnbindingAll) { - mProfileServices.remove(profile); - } + mProfileServices.remove(bluetoothProfile); } } } private void unbindAllBluetoothProfileServices() { + mUnbindingAll = true; synchronized (mProfileServices) { - mUnbindingAll = true; for (Integer i : mProfileServices.keySet()) { ProfileServiceConnections psc = mProfileServices.get(i); try { @@ -1787,102 +1421,92 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } psc.removeAllProxies(); } - mUnbindingAll = false; mProfileServices.clear(); } + mUnbindingAll = false; } /** * Send enable message and set adapter name and address. Called when the boot phase becomes * PHASE_SYSTEM_SERVICES_READY. */ - public void handleOnBootPhase() { - if (DBG) { - Log.d(TAG, "Bluetooth boot completed"); + void handleOnBootPhase(UserHandle userHandle) { + mHandler.post(() -> internalHandleOnBootPhase(userHandle)); + } + + @VisibleForTesting + void initialize(UserHandle userHandle) { + if (mUseNewAirplaneMode) { + mCurrentUserContext = + requireNonNull( + mContext.createContextAsUser(userHandle, 0), + "Current User Context cannot be null"); + AirplaneModeListener.initialize( + mLooper, + mContentResolver, + mState, + this::onAirplaneModeChanged, + this::sendAirplaneModeNotification, + this::isMediaProfileConnected, + this::getCurrentUserContext, + TimeSource.Monotonic.INSTANCE); } - mAppOps = mContext.getSystemService(AppOpsManager.class); + + if (mUseNewSatelliteMode) { + SatelliteModeListener.initialize( + mLooper, mContentResolver, this::onSatelliteModeChanged); + } + } + + private void internalHandleOnBootPhase(UserHandle userHandle) { + Log.d(TAG, "internalHandleOnBootPhase(" + userHandle + "): Bluetooth boot completed"); + + initialize(userHandle); + final boolean isBluetoothDisallowed = isBluetoothDisallowed(); if (isBluetoothDisallowed) { return; } final boolean isSafeMode = mContext.getPackageManager().isSafeMode(); if (mEnableExternal && isBluetoothPersistedStateOnBluetooth() && !isSafeMode) { - if (DBG) { - Log.d(TAG, "Auto-enabling Bluetooth."); - } - sendEnableMsg(mQuietEnableExternal, + Log.i(TAG, "internalHandleOnBootPhase: Auto-enabling Bluetooth."); + sendEnableMsg( + mQuietEnableExternal, BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT, mContext.getPackageName()); } else if (!isNameAndAddressSet()) { - if (DBG) { - Log.d(TAG, "Getting adapter name and address"); - } - Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); - mHandler.sendMessage(getMsg); - } - - mBluetoothModeChangeHelper = new BluetoothModeChangeHelper(mContext); - if (mBluetoothAirplaneModeListener != null) { - mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper); - } - registerForProvisioningStateChange(); - mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG); - loadApmEnhancementStateFromResource(); - } - - /** - * Set BluetoothModeChangeHelper for testing - */ - @VisibleForTesting - void setBluetoothModeChangeHelper(BluetoothModeChangeHelper bluetoothModeChangeHelper) { - mBluetoothModeChangeHelper = bluetoothModeChangeHelper; + Log.i(TAG, "internalHandleOnBootPhase: Getting adapter name and address"); + mHandler.sendEmptyMessage(MESSAGE_GET_NAME_AND_ADDRESS); + } + + if (!mUseNewAirplaneMode) { + mBluetoothAirplaneModeListener.start(new BluetoothModeChangeHelper(mContext)); + setApmEnhancementState(); + } } - /** - * Load whether APM Enhancement feature should be enabled from overlay - */ + /** set APM enhancement feature state */ @VisibleForTesting - void loadApmEnhancementStateFromResource() { - String btPackageName = mBluetoothModeChangeHelper.getBluetoothPackageName(); - if (btPackageName == null) { - Log.e(TAG, "Unable to find Bluetooth package name with APM resources"); - return; - } - try { - Resources resources = mContext.getPackageManager() - .getResourcesForApplication(btPackageName); - int apmEnhancement = resources.getIdentifier("config_bluetooth_apm_enhancement_enabled", - "bool", btPackageName); - Settings.Global.putInt(mContext.getContentResolver(), - APM_ENHANCEMENT, resources.getBoolean(apmEnhancement) ? 1 : 0); - } catch (Exception e) { - Log.e(TAG, "Unable to set whether APM enhancement should be enabled"); - } + void setApmEnhancementState() { + Settings.Global.putInt( + mContext.getContentResolver(), APM_ENHANCEMENT, DEFAULT_APM_ENHANCEMENT_STATE); } - /** - * Called when switching to a different foreground user. - */ - void handleSwitchUser(UserHandle userHandle) { - if (DBG) { - Log.d(TAG, "User " + userHandle + " switched"); - } - mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle.getIdentifier(), 0).sendToTarget(); + /** Called when switching to a different foreground user. */ + private void handleSwitchUser(UserHandle userHandle) { + Log.d(TAG, "handleSwitchUser(" + userHandle + ")"); + mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle).sendToTarget(); } - /** - * Called when user is unlocked. - */ - public void handleOnUnlockUser(UserHandle userHandle) { - if (DBG) { - Log.d(TAG, "User " + userHandle + " unlocked"); - } - mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle.getIdentifier(), 0).sendToTarget(); + /** Called when user is unlocked. */ + void handleOnUnlockUser(UserHandle userHandle) { + Log.d(TAG, "handleOnUnlockUser(" + userHandle + ")"); + mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle).sendToTarget(); } /** - * This class manages the clients connected to a given ProfileService - * and maintains the connection with that service. + * This class manages the clients connected to a given ProfileService and maintains the + * connection with that service. */ private final class ProfileServiceConnections implements ServiceConnection, IBinder.DeathRecipient { @@ -1899,33 +1523,20 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } private boolean bindService(int rebindCount) { - int state = BluetoothAdapter.STATE_OFF; - try { - mBluetoothLock.readLock().lock(); - state = synchronousGetState(); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "Unable to call getState", e); - return false; - } finally { - mBluetoothLock.readLock().unlock(); - } - - if (state != BluetoothAdapter.STATE_ON) { - if (DBG) { - Log.d(TAG, "Unable to bindService while Bluetooth is disabled"); - } + if (!mState.oneOf(STATE_ON)) { + Log.e(TAG, "bindService: Invalid state, Bluetooth is disabled"); return false; } - if (mIntent != null && mService == null + if (mIntent != null + && mService == null && doBind(mIntent, this, 0, USER_HANDLE_CURRENT_OR_SELF)) { - Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); - msg.obj = this; + Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE, this); msg.arg1 = rebindCount; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); return true; } - Log.w(TAG, "Unable to bind with intent: " + mIntent); + Log.w(TAG, "bindService: Unable to bind. intent=" + mIntent); return false; } @@ -1939,8 +1550,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } } else { if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { - Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); - msg.obj = this; + Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE, this); msg.arg1 = DEFAULT_REBIND_COUNT; mHandler.sendMessage(msg); } @@ -1948,16 +1558,16 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } private void removeProxy(IBluetoothProfileServiceConnection proxy) { - if (proxy != null) { - if (mProxies.unregister(proxy)) { - try { - proxy.onServiceDisconnected(mClassName); - } catch (RemoteException e) { - Log.e(TAG, "Unable to disconnect proxy", e); - } + if (proxy == null) { + Log.w(TAG, "removeProxy: null proxy for " + mIntent); + return; + } + if (mProxies.unregister(proxy)) { + try { + proxy.onServiceDisconnected(mClassName); + } catch (RemoteException e) { + Log.e(TAG, "Unable to disconnect proxy", e); } - } else { - Log.w(TAG, "Trying to remove a null proxy"); } } @@ -2029,13 +1639,10 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { @Override public void binderDied() { - if (DBG) { - Log.w(TAG, "Profile service for profile: " + mClassName + " died."); - } + Log.w(TAG, "binderDied(): profile=" + mClassName); onServiceDisconnected(mClassName); // Trigger rebind - Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); - msg.obj = this; + Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE, this); mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); } } @@ -2044,10 +1651,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { synchronized (mStateChangeCallbacks) { try { int n = mStateChangeCallbacks.beginBroadcast(); - if (DBG) { - Log.d(TAG, "Broadcasting onBluetoothStateChange(" + isUp + ") to " + n - + " receivers."); - } + Log.d(TAG, "sendBluetoothStateCallback(" + isUp + "): to " + n + " receivers"); for (int i = 0; i < n; i++) { try { mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); @@ -2061,37 +1665,35 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } } - /** - * Inform BluetoothAdapter instances that Adapter service is up - */ + /** Inform BluetoothAdapter instances that Adapter service is up */ private void sendBluetoothServiceUpCallback() { synchronized (mCallbacks) { - mBluetoothLock.readLock().lock(); + mAdapterLock.readLock().lock(); try { int n = mCallbacks.beginBroadcast(); - Log.d(TAG, "Broadcasting onBluetoothServiceUp() to " + n + " receivers."); + Log.d(TAG, "sendBluetoothServiceUpCallback(): to " + n + " receivers"); for (int i = 0; i < n; i++) { try { - mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); + mCallbacks + .getBroadcastItem(i) + .onBluetoothServiceUp(mAdapter.getAdapterBinder()); } catch (RemoteException e) { Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); } } } finally { mCallbacks.finishBroadcast(); - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } } } - /** - * Inform BluetoothAdapter instances that Adapter service is down - */ + /** Inform BluetoothAdapter instances that Adapter service is down */ private void sendBluetoothServiceDownCallback() { synchronized (mCallbacks) { try { int n = mCallbacks.beginBroadcast(); - Log.d(TAG, "Broadcasting onBluetoothServiceDown() to " + n + " receivers."); + Log.d(TAG, "sendBluetoothServiceDownCallback(): to " + n + " receivers"); for (int i = 0; i < n; i++) { try { mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); @@ -2105,32 +1707,19 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } } - public String getAddress(AttributionSource attributionSource) { - if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getAddress")) { - return null; - } - - if (!isCallerSystem(getCallingAppId()) && !checkIfCallerIsForegroundUser()) { - Log.w(TAG, "getAddress(): not allowed for non-active and non system user"); - return null; - } - - if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS) - != PackageManager.PERMISSION_GRANTED) { - return BluetoothAdapter.DEFAULT_MAC_ADDRESS; - } - - mBluetoothLock.readLock().lock(); + String getAddress(AttributionSource source) { + mAdapterLock.readLock().lock(); try { - if (mBluetooth != null) { - return synchronousGetAddress(attributionSource); + if (mAdapter != null) { + return mAdapter.getAddress(source); } } catch (RemoteException | TimeoutException e) { - Log.e(TAG, + Log.e( + TAG, "getAddress(): Unable to retrieve address remotely. Returning cached address", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } // mAddress is accessed from outside. @@ -2139,25 +1728,16 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { return mAddress; } - public String getName(AttributionSource attributionSource) { - if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getName")) { - return null; - } - - if (!isCallerSystem(getCallingAppId()) && !checkIfCallerIsForegroundUser()) { - Log.w(TAG, "getName(): not allowed for non-active and non system user"); - return null; - } - - mBluetoothLock.readLock().lock(); + String getName(AttributionSource source) { + mAdapterLock.readLock().lock(); try { - if (mBluetooth != null) { - return synchronousGetName(attributionSource); + if (mAdapter != null) { + return mAdapter.getName(source); } } catch (RemoteException | TimeoutException e) { Log.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } // mName is accessed from outside. @@ -2166,41 +1746,27 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { return mName; } - private class BluetoothServiceConnection implements ServiceConnection { + @VisibleForTesting + class BluetoothServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName componentName, IBinder service) { String name = componentName.getClassName(); - if (DBG) { - Log.d(TAG, "BluetoothServiceConnection: " + name); - } - Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); - if (name.equals("com.android.bluetooth.btservice.AdapterService")) { - msg.arg1 = SERVICE_IBLUETOOTH; - } else if (name.equals("com.android.bluetooth.gatt.GattService")) { - msg.arg1 = SERVICE_IBLUETOOTHGATT; - } else { + Log.d(TAG, "ServiceConnection.onServiceConnected(" + name + ", " + service + ")"); + if (!name.equals("com.android.bluetooth.btservice.AdapterService")) { Log.e(TAG, "Unknown service connected: " + name); return; } - msg.obj = service; - mHandler.sendMessage(msg); + mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED, service).sendToTarget(); } public void onServiceDisconnected(ComponentName componentName) { // Called if we unexpectedly disconnect. String name = componentName.getClassName(); - if (DBG) { - Log.d(TAG, "BluetoothServiceConnection, disconnected: " + name); - } - Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); - if (name.equals("com.android.bluetooth.btservice.AdapterService")) { - msg.arg1 = SERVICE_IBLUETOOTH; - } else if (name.equals("com.android.bluetooth.gatt.GattService")) { - msg.arg1 = SERVICE_IBLUETOOTHGATT; - } else { + Log.d(TAG, "ServiceConnection.onServiceDisconnected(" + name + ")"); + if (!name.equals("com.android.bluetooth.btservice.AdapterService")) { Log.e(TAG, "Unknown service disconnected: " + name); return; } - mHandler.sendMessage(msg); + mHandler.sendEmptyMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); } } @@ -2220,31 +1786,26 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_GET_NAME_AND_ADDRESS: - if (DBG) { - Log.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS"); - } - mBluetoothLock.writeLock().lock(); + Log.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS"); + mAdapterLock.writeLock().lock(); try { - if ((mBluetooth == null) && (!mBinding)) { - if (DBG) { - Log.d(TAG, "Binding to service to get name and address"); - } + if (mAdapter == null && !isBinding()) { + Log.d(TAG, "Binding to service to get name and address"); mGetNameAddressOnly = true; - Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); - mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS); + mHandler.sendEmptyMessageDelayed(MESSAGE_TIMEOUT_BIND, TIMEOUT_BIND_MS); Intent i = new Intent(IBluetooth.class.getName()); - if (!doBind(i, mConnection, + if (!doBind( + i, + mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT)) { mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); - } else { - mBinding = true; } - } else if (mBluetooth != null) { + } else if (mAdapter != null) { try { storeNameAndAddress( - synchronousGetName(mContext.getAttributionSource()), - synchronousGetAddress(mContext.getAttributionSource())); + mAdapter.getName(mContext.getAttributionSource()), + mAdapter.getAddress(mContext.getAttributionSource())); } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to grab names", e); } @@ -2254,30 +1815,29 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { mGetNameAddressOnly = false; } } finally { - mBluetoothLock.writeLock().unlock(); + mAdapterLock.writeLock().unlock(); } break; case MESSAGE_ENABLE: int quietEnable = msg.arg1; - int isBle = msg.arg2; + int isBle = msg.arg2; if (mShutdownInProgress) { Log.d(TAG, "Skip Bluetooth Enable in device shutdown process"); break; } + Log.d(TAG, "MESSAGE_ENABLE(" + quietEnable + "): mAdapter=" + mAdapter); + if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) { // We are handling enable or disable right now, wait for it. - mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE, - quietEnable, isBle), ENABLE_DISABLE_DELAY_MS); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MESSAGE_ENABLE, quietEnable, isBle), + ENABLE_DISABLE_DELAY_MS); break; } - if (DBG) { - Log.d(TAG, "MESSAGE_ENABLE(" + quietEnable + "): mBluetooth =" - + mBluetooth); - } mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); mEnable = true; @@ -2286,23 +1846,22 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } // Use service interface to get the exact state - mBluetoothLock.readLock().lock(); + mAdapterLock.readLock().lock(); try { - if (mBluetooth != null) { + if (mAdapter != null) { boolean isHandled = true; - int state = synchronousGetState(); - switch (state) { - case BluetoothAdapter.STATE_BLE_ON: + switch (mState.get()) { + case STATE_BLE_ON: if (isBle == 1) { Log.i(TAG, "Already at BLE_ON State"); } else { Log.w(TAG, "BT Enable in BLE_ON State, going to ON"); - synchronousOnLeServiceUp(mContext.getAttributionSource()); + mAdapter.startBrEdr(mContext.getAttributionSource()); } break; - case BluetoothAdapter.STATE_BLE_TURNING_ON: - case BluetoothAdapter.STATE_TURNING_ON: - case BluetoothAdapter.STATE_ON: + case STATE_BLE_TURNING_ON: + case STATE_TURNING_ON: + case STATE_ON: Log.i(TAG, "MESSAGE_ENABLE: already enabled"); break; default: @@ -2314,11 +1873,11 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } catch (RemoteException | TimeoutException e) { Log.e(TAG, "", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } mQuietEnable = (quietEnable == 1); - if (mBluetooth == null) { + if (mAdapter == null) { handleEnable(mQuietEnable); } else { // @@ -2338,46 +1897,40 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { // continuously failed to turn on itself. // mWaitForEnableRetry = 0; - Message enableDelayedMsg = - mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED); - mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS); + mHandler.sendEmptyMessageDelayed( + MESSAGE_HANDLE_ENABLE_DELAYED, ENABLE_DISABLE_DELAY_MS); } break; case MESSAGE_DISABLE: - if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mBinding + Log.d(TAG, "MESSAGE_DISABLE: mAdapter=" + mAdapter); + if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) + || isBinding() || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) { // We are handling enable or disable right now, wait for it. - mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_DISABLE), - ENABLE_DISABLE_DELAY_MS); + mHandler.sendEmptyMessageDelayed(MESSAGE_DISABLE, ENABLE_DISABLE_DELAY_MS); break; } - if (DBG) { - Log.d(TAG, "MESSAGE_DISABLE: mBluetooth =" + mBluetooth - + ", mBinding = " + mBinding); - } mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); - if (mEnable && mBluetooth != null) { + if (mEnable && mAdapter != null) { mWaitForDisableRetry = 0; - Message disableDelayedMsg = - mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0); - mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS); + mHandler.sendEmptyMessageDelayed( + MESSAGE_HANDLE_DISABLE_DELAYED, ENABLE_DISABLE_DELAY_MS); } else { mEnable = false; handleDisable(); } break; - case MESSAGE_HANDLE_ENABLE_DELAYED: { + case MESSAGE_HANDLE_ENABLE_DELAYED: // The Bluetooth is turning off, wait for STATE_OFF - if (mState != BluetoothAdapter.STATE_OFF) { + if (!mState.oneOf(STATE_OFF)) { if (mWaitForEnableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) { mWaitForEnableRetry++; - Message enableDelayedMsg = - mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED); - mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS); + mHandler.sendEmptyMessageDelayed( + MESSAGE_HANDLE_ENABLE_DELAYED, ENABLE_DISABLE_DELAY_MS); break; } else { Log.e(TAG, "Wait for STATE_OFF timeout"); @@ -2386,25 +1939,21 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { // Either state is changed to STATE_OFF or reaches the maximum retry, we // should move forward to the next step. mWaitForEnableRetry = 0; - Message restartMsg = - mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs()); + mHandler.sendEmptyMessageDelayed( + MESSAGE_RESTART_BLUETOOTH_SERVICE, getServiceRestartMs()); Log.d(TAG, "Handle enable is finished"); break; - } - case MESSAGE_HANDLE_DISABLE_DELAYED: { + case MESSAGE_HANDLE_DISABLE_DELAYED: boolean disabling = (msg.arg1 == 1); Log.d(TAG, "MESSAGE_HANDLE_DISABLE_DELAYED: disabling:" + disabling); if (!disabling) { // The Bluetooth is turning on, wait for STATE_ON - if (mState != BluetoothAdapter.STATE_ON) { + if (!mState.oneOf(STATE_ON)) { if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) { mWaitForDisableRetry++; - Message disableDelayedMsg = mHandler.obtainMessage( - MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0); - mHandler.sendMessageDelayed(disableDelayedMsg, - ENABLE_DISABLE_DELAY_MS); + mHandler.sendEmptyMessageDelayed( + MESSAGE_HANDLE_DISABLE_DELAYED, ENABLE_DISABLE_DELAY_MS); break; } else { Log.e(TAG, "Wait for STATE_ON timeout"); @@ -2421,13 +1970,14 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS); } else { // The Bluetooth is turning off, wait for exiting STATE_ON - if (mState == BluetoothAdapter.STATE_ON) { + if (mState.oneOf(STATE_ON)) { if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) { mWaitForDisableRetry++; - Message disableDelayedMsg = mHandler.obtainMessage( - MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0); - mHandler.sendMessageDelayed(disableDelayedMsg, - ENABLE_DISABLE_DELAY_MS); + Message disableDelayedMsg = + mHandler.obtainMessage( + MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0); + mHandler.sendMessageDelayed( + disableDelayedMsg, ENABLE_DISABLE_DELAY_MS); break; } else { Log.e(TAG, "Wait for exiting STATE_ON timeout"); @@ -2438,53 +1988,70 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { Log.d(TAG, "Handle disable is finished"); } break; - } case MESSAGE_RESTORE_USER_SETTING: if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) { - if (DBG) { - Log.d(TAG, "Restore Bluetooth state to disabled"); - } + Log.d(TAG, "MESSAGE_RESTORE_USER_SETTING: set Bluetooth state to disabled"); persistBluetoothSetting(BLUETOOTH_OFF); mEnableExternal = false; sendDisableMsg( BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING, mContext.getPackageName()); } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) { - if (DBG) { - Log.d(TAG, "Restore Bluetooth state to enabled"); - } + Log.d(TAG, "MESSAGE_RESTORE_USER_SETTING: set Bluetooth state to enabled"); mQuietEnableExternal = false; mEnableExternal = true; - // waive WRITE_SECURE_SETTINGS permission check - sendEnableMsg(false, + sendEnableMsg( + false, BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING, mContext.getPackageName()); + } else { + Log.w( + TAG, + "MESSAGE_RESTORE_USER_SETTING: Unhandled." + + (" mEnable=" + mEnable) + + (" msg.arg1=" + msg.arg1)); } break; - case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: { - IBluetoothStateChangeCallback callback = + + case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: + IBluetoothStateChangeCallback regCallback = (IBluetoothStateChangeCallback) msg.obj; - mStateChangeCallbacks.register(callback); + if (mState.oneOf(STATE_ON)) { + try { + regCallback.onBluetoothStateChange(true); + } catch (RemoteException e) { + Log.e(TAG, "REGISTER_STATE_CHANGE_CALLBACK: callback failed", e); + break; + } + } + mStateChangeCallbacks.register(regCallback); break; - } - case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: { - IBluetoothStateChangeCallback callback = - (IBluetoothStateChangeCallback) msg.obj; - mStateChangeCallbacks.unregister(callback); + + case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: + IBluetoothStateChangeCallback unregCallback = + (IBluetoothStateChangeCallback)msg.obj; + try { + // LINT.IfChange + unregCallback.onBluetoothStateChange(false); + // LINT.ThenChange(/framework/tests/unit/src/android/bluetooth/BluetoothProfileConnectorTest.java) + } catch (RemoteException e) { + Log.e(TAG, "UNREGISTER_STATE_CHANGE_CALLBACK: callback failed", e); + } + mStateChangeCallbacks.unregister(unregCallback); break; - } - case MESSAGE_ADD_PROXY_DELAYED: { - ProfileServiceConnections psc = mProfileServices.get(msg.arg1); - if (psc == null) { + + case MESSAGE_ADD_PROXY_DELAYED: + ProfileServiceConnections connection = mProfileServices.get(msg.arg1); + if (connection == null) { break; } IBluetoothProfileServiceConnection proxy = (IBluetoothProfileServiceConnection) msg.obj; - psc.addProxy(proxy); + connection.addProxy(proxy); break; - } - case MESSAGE_BIND_PROFILE_SERVICE: { + + case MESSAGE_BIND_PROFILE_SERVICE: ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); if (psc == null) { @@ -2499,117 +2066,107 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { psc.bindService(msg.arg1 - 1); } break; - } - case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: { - if (DBG) { - Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); - } + case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: IBinder service = (IBinder) msg.obj; - mBluetoothLock.writeLock().lock(); - try { - if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { - mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service); - continueFromBleOnState(); - break; - } // else must be SERVICE_IBLUETOOTH + Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: service=" + service); - //Remove timeout + mAdapterLock.writeLock().lock(); + try { + // Remove timeout mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); - mBinding = false; - mBluetoothBinder = service; - mBluetooth = IBluetooth.Stub.asInterface(service); + mAdapter = BluetoothServerProxy.getInstance().createAdapterBinder(service); int foregroundUserId = ActivityManager.getCurrentUser(); propagateForegroundUserId(foregroundUserId); if (!isNameAndAddressSet()) { - Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); - mHandler.sendMessage(getMsg); + mHandler.sendEmptyMessage(MESSAGE_GET_NAME_AND_ADDRESS); if (mGetNameAddressOnly) { return; } } - //Register callback object + // Register callback object try { - synchronousRegisterCallback(mBluetoothCallback, - mContext.getAttributionSource()); + mAdapter.registerCallback( + mBluetoothCallback, mContext.getAttributionSource()); } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to register BluetoothCallback", e); } - //Inform BluetoothAdapter instances that service is up + // Inform BluetoothAdapter instances that service is up sendBluetoothServiceUpCallback(); // Get the supported profiles list try { - mSupportedProfileList = synchronousGetSupportedProfiles( - mContext.getAttributionSource()); + mSupportedProfileList = + mAdapter.getSupportedProfiles(mContext.getAttributionSource()); } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to get the supported profiles list", e); } - //Do enable request + // Do enable request try { - if (!synchronousEnable(mQuietEnable, mContext.getAttributionSource())) { + if (!mAdapter.enable(mQuietEnable, mContext.getAttributionSource())) { Log.e(TAG, "IBluetooth.enable() returned false"); } } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to call enable()", e); } } finally { - mBluetoothLock.writeLock().unlock(); + mAdapterLock.writeLock().unlock(); } if (!mEnable) { - waitForState(Set.of(BluetoothAdapter.STATE_ON)); + waitForState(STATE_ON); handleDisable(); - waitForState(Set.of(BluetoothAdapter.STATE_OFF, - BluetoothAdapter.STATE_TURNING_ON, - BluetoothAdapter.STATE_TURNING_OFF, - BluetoothAdapter.STATE_BLE_TURNING_ON, - BluetoothAdapter.STATE_BLE_ON, - BluetoothAdapter.STATE_BLE_TURNING_OFF)); + waitForState( + STATE_OFF, + STATE_TURNING_ON, + STATE_TURNING_OFF, + STATE_BLE_TURNING_ON, + STATE_BLE_ON, + STATE_BLE_TURNING_OFF); } break; - } - case MESSAGE_BLUETOOTH_STATE_CHANGE: { + + case MESSAGE_BLUETOOTH_STATE_CHANGE: int prevState = msg.arg1; int newState = msg.arg2; - if (DBG) { - Log.d(TAG, - "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState( - prevState) + " > " + BluetoothAdapter.nameForState( - newState)); - } - mState = newState; + Log.d( + TAG, + "MESSAGE_BLUETOOTH_STATE_CHANGE:" + + (" prevState=" + BluetoothAdapter.nameForState(prevState)) + + (" newState=" + BluetoothAdapter.nameForState(newState))); + mState.set(newState); bluetoothStateChangeHandler(prevState, newState); // handle error state transition case from TURNING_ON to OFF // unbind and rebind bluetooth service and enable bluetooth - if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && (newState - == BluetoothAdapter.STATE_OFF) && (mBluetooth != null) && mEnable) { + if ((prevState == STATE_BLE_TURNING_ON) + && (newState == STATE_OFF) + && (mAdapter != null) + && mEnable) { recoverBluetoothServiceFromError(false); } - if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && (newState - == BluetoothAdapter.STATE_BLE_ON) && (mBluetooth != null) && mEnable) { + if ((prevState == STATE_TURNING_ON) + && (newState == STATE_BLE_ON) + && (mAdapter != null) + && mEnable) { recoverBluetoothServiceFromError(true); } // If we tried to enable BT while BT was in the process of shutting down, // wait for the BT process to fully tear down and then force a restart // here. This is a bit of a hack (b/29363429). - if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) && (newState - == BluetoothAdapter.STATE_OFF)) { + if (prevState == STATE_BLE_TURNING_OFF && newState == STATE_OFF) { if (mEnable) { Log.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting."); - waitForState(Set.of(BluetoothAdapter.STATE_OFF)); - Message restartMsg = - mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs()); + waitForState(STATE_OFF); + mHandler.sendEmptyMessageDelayed( + MESSAGE_RESTART_BLUETOOTH_SERVICE, getServiceRestartMs()); } } - if (newState == BluetoothAdapter.STATE_ON - || newState == BluetoothAdapter.STATE_BLE_ON) { + if (newState == STATE_ON || newState == STATE_BLE_ON) { // bluetooth is working, reset the counter if (mErrorRecoveryRetryCounter != 0) { Log.w(TAG, "bluetooth is recovered from error"); @@ -2617,218 +2174,158 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } } break; - } - case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: { - Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED(" + msg.arg1 + ")"); - mBluetoothLock.writeLock().lock(); + + case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: + Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); + mAdapterLock.writeLock().lock(); try { - if (msg.arg1 == SERVICE_IBLUETOOTH) { - // if service is unbinded already, do nothing and return - if (mBluetooth == null) { - break; - } - mBluetooth = null; - mSupportedProfileList.clear(); - } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { - mBluetoothGatt = null; - break; - } else { - Log.e(TAG, "Unknown argument for service disconnect!"); + // if service is unbinded already, do nothing and return + if (mAdapter == null) { break; } + mAdapter = null; + mSupportedProfileList.clear(); } finally { - mBluetoothLock.writeLock().unlock(); + mAdapterLock.writeLock().unlock(); } // log the unexpected crash addCrashLog(); - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH, - mContext.getPackageName(), false); + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH, + mContext.getPackageName(), + false); if (mEnable) { mEnable = false; - // Send a Bluetooth Restart message - Message restartMsg = - mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs()); + mHandler.sendEmptyMessageDelayed( + MESSAGE_RESTART_BLUETOOTH_SERVICE, getServiceRestartMs()); } sendBluetoothServiceDownCallback(); // Send BT state broadcast to update // the BT icon correctly - if ((mState == BluetoothAdapter.STATE_TURNING_ON) || (mState - == BluetoothAdapter.STATE_ON)) { - bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, - BluetoothAdapter.STATE_TURNING_OFF); - mState = BluetoothAdapter.STATE_TURNING_OFF; + if (mState.oneOf(STATE_TURNING_ON, STATE_ON)) { + bluetoothStateChangeHandler(STATE_ON, STATE_TURNING_OFF); + mState.set(STATE_TURNING_OFF); } - if (mState == BluetoothAdapter.STATE_TURNING_OFF) { - bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, - BluetoothAdapter.STATE_OFF); + if (mState.oneOf(STATE_TURNING_OFF)) { + bluetoothStateChangeHandler(STATE_TURNING_OFF, STATE_OFF); } mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); - mState = BluetoothAdapter.STATE_OFF; + mState.set(STATE_OFF); break; - } - case MESSAGE_RESTART_BLUETOOTH_SERVICE: { + + case MESSAGE_RESTART_BLUETOOTH_SERVICE: mErrorRecoveryRetryCounter++; - Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE: retry count=" - + mErrorRecoveryRetryCounter); + Log.d( + TAG, + "MESSAGE_RESTART_BLUETOOTH_SERVICE: retry count=" + + mErrorRecoveryRetryCounter); if (mErrorRecoveryRetryCounter < MAX_ERROR_RESTART_RETRIES) { /* Enable without persisting the setting as - it doesnt change when IBluetooth - service restarts */ + * it doesn't change when IBluetooth + * service restarts */ mEnable = true; - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED, - mContext.getPackageName(), true); + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED, + mContext.getPackageName(), + true); handleEnable(mQuietEnable); } else { - mBluetoothLock.writeLock().lock(); - mBluetooth = null; - mBluetoothLock.writeLock().unlock(); + mAdapterLock.writeLock().lock(); + mAdapter = null; + mAdapterLock.writeLock().unlock(); Log.e(TAG, "Reach maximum retry to restart Bluetooth!"); } break; - } - case MESSAGE_TIMEOUT_BIND: { + + case MESSAGE_TIMEOUT_BIND: Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); - mBluetoothLock.writeLock().lock(); - mBinding = false; - mBluetoothLock.writeLock().unlock(); + // TODO(b/286082382): Timeout should be more than a log. We should at least call + // context.unbindService, eventually log a metric with it break; - } - case MESSAGE_USER_SWITCHED: { - if (DBG) { - Log.d(TAG, "MESSAGE_USER_SWITCHED"); - } + case MESSAGE_USER_SWITCHED: + UserHandle userTo = (UserHandle) msg.obj; + Log.d(TAG, "MESSAGE_USER_SWITCHED: userTo=" + userTo); mHandler.removeMessages(MESSAGE_USER_SWITCHED); - mBluetoothNotificationManager.createNotificationChannels(); + if (!mFeatureFlags.airplaneRessourcesInApp() && !mUseNewAirplaneMode) { + mBluetoothNotificationManager.createNotificationChannels(); + } + + if (mUseNewAirplaneMode) { + mCurrentUserContext = mContext.createContextAsUser(userTo, 0); + } /* disable and enable BT when detect a user switch */ - if (mBluetooth != null && isEnabled()) { - restartForReason(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH); - } else if (mBinding || mBluetooth != null) { - Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); - userMsg.arg2 = 1 + msg.arg2; + if (mAdapter != null && mState.oneOf(STATE_ON)) { + restartForNewUser(userTo); + } else if (isBinding() || mAdapter != null) { + Message userMsg = Message.obtain(msg); + userMsg.arg1++; // if user is switched when service is binding retry after a delay mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); - if (DBG) { - Log.d(TAG, "Retry MESSAGE_USER_SWITCHED " + userMsg.arg2); - } + Log.d( + TAG, + "MESSAGE_USER_SWITCHED:" + + (" userTo=" + userTo) + + (" number of retry attempt=" + userMsg.arg1) + + (" isBinding=" + isBinding()) + + (" mAdapter=" + mAdapter)); } break; - } - case MESSAGE_USER_UNLOCKED: { - if (DBG) { - Log.d(TAG, "MESSAGE_USER_UNLOCKED"); - } + + case MESSAGE_USER_UNLOCKED: + Log.d(TAG, "MESSAGE_USER_UNLOCKED"); mHandler.removeMessages(MESSAGE_USER_SWITCHED); - if (mEnable && !mBinding && (mBluetooth == null)) { + if (mEnable && !isBinding() && (mAdapter == null)) { // We should be connected, but we gave up for some // reason; maybe the Bluetooth service wasn't encryption // aware, so try binding again. - if (DBG) { - Log.d(TAG, "Enabled but not bound; retrying after unlock"); - } + Log.d(TAG, "Enabled but not bound; retrying after unlock"); handleEnable(mQuietEnable); } break; - } - case MESSAGE_INIT_FLAGS_CHANGED: { - if (DBG) { - Log.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED"); - } - mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED); - if (mBluetoothModeChangeHelper.isMediaProfileConnected()) { - Log.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by " - + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS - + " ms due to existing connections"); - mHandler.sendEmptyMessageDelayed( - MESSAGE_INIT_FLAGS_CHANGED, - DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS); - break; - } - if (!isDeviceProvisioned()) { - Log.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by " - + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS - + "ms because device is not provisioned"); - mHandler.sendEmptyMessageDelayed( - MESSAGE_INIT_FLAGS_CHANGED, - DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS); - break; - } - if (mBluetooth != null && isEnabled()) { - Log.i(TAG, "Restarting Bluetooth due to init flag change"); - restartForReason( - BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED); - } - break; - } } } - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED - }) - private void restartForReason(int reason) { - mBluetoothLock.readLock().lock(); + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + private void restartForNewUser(UserHandle newUser) { + mAdapterLock.readLock().lock(); try { - if (mBluetooth != null) { - synchronousUnregisterCallback(mBluetoothCallback, - mContext.getAttributionSource()); + if (mAdapter != null) { + mAdapter.unregisterCallback( + mBluetoothCallback, mContext.getAttributionSource()); } } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to unregister", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } - if (mState == BluetoothAdapter.STATE_TURNING_OFF) { - // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE - bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF); - mState = BluetoothAdapter.STATE_OFF; - } - if (mState == BluetoothAdapter.STATE_OFF) { - bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON); - mState = BluetoothAdapter.STATE_TURNING_ON; - } - - waitForState(Set.of(BluetoothAdapter.STATE_ON)); - - if (mState == BluetoothAdapter.STATE_TURNING_ON) { - bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); - } + // This method is always called while bluetooth is in STATE_ON + assert (mState.oneOf(STATE_ON)); unbindAllBluetoothProfileServices(); // disable - addActiveLog(reason, mContext.getPackageName(), false); + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH, + mContext.getPackageName(), + false); handleDisable(); // Pbap service need receive STATE_TURNING_OFF intent to close - bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, - BluetoothAdapter.STATE_TURNING_OFF); - - boolean didDisableTimeout = - !waitForState(Set.of(BluetoothAdapter.STATE_OFF)); + bluetoothStateChangeHandler(STATE_ON, STATE_TURNING_OFF); - bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, - BluetoothAdapter.STATE_OFF); - sendBluetoothServiceDownCallback(); + boolean didDisableTimeout = !waitForState(STATE_OFF); - mBluetoothLock.writeLock().lock(); - try { - if (mBluetooth != null) { - mBluetooth = null; - // Unbind - mContext.unbindService(mConnection); - } - mBluetoothGatt = null; - } finally { - mBluetoothLock.writeLock().unlock(); - } + bluetoothStateChangeHandler(STATE_TURNING_OFF, STATE_OFF); // // If disabling Bluetooth times out, wait for an @@ -2842,37 +2339,44 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); - mState = BluetoothAdapter.STATE_OFF; + mState.set(STATE_OFF); // enable - addActiveLog(reason, mContext.getPackageName(), true); - // mEnable flag could have been reset on disableBLE. Reenable it. + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH, + mContext.getPackageName(), + true); + // mEnable flag could have been reset on stopBle. Reenable it. mEnable = true; handleEnable(mQuietEnable); } } + private boolean isBinding() { + return mHandler.hasMessages(MESSAGE_TIMEOUT_BIND); + } + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) private void handleEnable(boolean quietMode) { mQuietEnable = quietMode; - mBluetoothLock.writeLock().lock(); + mAdapterLock.writeLock().lock(); try { - if ((mBluetooth == null) && (!mBinding)) { + if (mAdapter == null && !isBinding()) { Log.d(TAG, "binding Bluetooth service"); - //Start bind timeout and bind - Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); - mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS); + // Start bind timeout and bind + mHandler.sendEmptyMessageDelayed(MESSAGE_TIMEOUT_BIND, TIMEOUT_BIND_MS); Intent i = new Intent(IBluetooth.class.getName()); - if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, + if (!doBind( + i, + mConnection, + Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT)) { mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); - } else { - mBinding = true; } - } else if (mBluetooth != null) { - //Enable bluetooth + } else if (mAdapter != null) { + // Enable bluetooth try { - if (!synchronousEnable(mQuietEnable, mContext.getAttributionSource())) { + if (!mAdapter.enable(mQuietEnable, mContext.getAttributionSource())) { Log.e(TAG, "IBluetooth.enable() returned false"); } } catch (RemoteException | TimeoutException e) { @@ -2880,12 +2384,12 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } } } finally { - mBluetoothLock.writeLock().unlock(); + mAdapterLock.writeLock().unlock(); } } boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) { - ComponentName comp = resolveSystemService(intent, mContext.getPackageManager(), 0); + ComponentName comp = resolveSystemService(intent); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) { Log.e(TAG, "Fail to bind to: " + intent); @@ -2896,224 +2400,95 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) private void handleDisable() { - mBluetoothLock.readLock().lock(); + mAdapterLock.readLock().lock(); try { - if (mBluetooth != null) { - if (DBG) { - Log.d(TAG, "Sending off request."); - } - if (!synchronousDisable(mContext.getAttributionSource())) { + if (mAdapter != null) { + Log.d(TAG, "handleDisable: Sending off request."); + if (!mAdapter.disable(mContext.getAttributionSource())) { Log.e(TAG, "IBluetooth.disable() returned false"); } } } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to call disable()", e); } finally { - mBluetoothLock.readLock().unlock(); - } - } - - private static int getCallingAppId() { - return UserHandle.getAppId(Binder.getCallingUid()); - } - private static boolean isCallerSystem(int callingAppId) { - return callingAppId == Process.SYSTEM_UID; - } - private static boolean isCallerShell(int callingAppId) { - return callingAppId == Process.SHELL_UID; - } - private static boolean isCallerRoot(int callingAppId) { - return callingAppId == Process.ROOT_UID; - } - - private boolean checkIfCallerIsForegroundUser() { - int callingUid = Binder.getCallingUid(); - UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid); - final long callingIdentity = Binder.clearCallingIdentity(); - UserManager userManager = mContext.getSystemService(UserManager.class); - UserHandle uh = userManager.getProfileParent(callingUser); - UserHandle parentUser = (uh != null) ? uh : USER_HANDLE_NULL; - int callingAppId = UserHandle.getAppId(callingUid); - boolean valid = false; - try { - UserHandle foregroundUser = UserHandle.of(ActivityManager.getCurrentUser()); - valid = (callingUser == foregroundUser) || parentUser == foregroundUser - || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid - || callingAppId == Process.SHELL_UID; - if (DBG && !valid) { - Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser=" - + callingUser + " parentUser=" + parentUser + " foregroundUser=" - + foregroundUser); - } - } finally { - Binder.restoreCallingIdentity(callingIdentity); + mAdapterLock.readLock().unlock(); } - return valid; } - private void sendBleStateChanged(int prevState, int newState) { - if (DBG) { - Log.d(TAG, - "Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) + " > " - + BluetoothAdapter.nameForState(newState)); - } + private void broadcastIntentStateChange(String action, int prevState, int newState) { + Log.d( + TAG, + "broadcastIntentStateChange:" + + (" action=" + action.substring(action.lastIndexOf('.') + 1)) + + (" prevState=" + BluetoothAdapter.nameForState(prevState)) + + (" newState=" + BluetoothAdapter.nameForState(newState))); // Send broadcast message to everyone else - Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED); + Intent intent = new Intent(action); intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null, getTempAllowlistBroadcastOptions()); + mContext.sendBroadcastAsUser( + intent, UserHandle.ALL, null, getTempAllowlistBroadcastOptions()); } private boolean isBleState(int state) { switch (state) { - case BluetoothAdapter.STATE_BLE_ON: - case BluetoothAdapter.STATE_BLE_TURNING_ON: - case BluetoothAdapter.STATE_BLE_TURNING_OFF: + case STATE_BLE_ON: + case STATE_BLE_TURNING_ON: + case STATE_BLE_TURNING_OFF: return true; } return false; } - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) private void bluetoothStateChangeHandler(int prevState, int newState) { - boolean isStandardBroadcast = true; if (prevState == newState) { // No change. Nothing to do. return; } + // Notify all proxy objects first of adapter state change - if (newState == BluetoothAdapter.STATE_BLE_ON || newState == BluetoothAdapter.STATE_OFF) { - boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF - && newState == BluetoothAdapter.STATE_BLE_ON); - - if (newState == BluetoothAdapter.STATE_OFF) { - // If Bluetooth is off, send service down event to proxy objects, and unbind - if (DBG) { - Log.d(TAG, "Bluetooth is complete send Service Down"); - } - sendBluetoothServiceDownCallback(); - unbindAndFinish(); - sendBleStateChanged(prevState, newState); - - /* Currently, the OFF intent is broadcasted externally only when we transition - * from TURNING_OFF to BLE_ON state. So if the previous state is a BLE state, - * we are guaranteed that the OFF intent has been broadcasted earlier and we - * can safely skip it. - * Conversely, if the previous state is not a BLE state, it indicates that some - * sort of crash has occurred, moving us directly to STATE_OFF without ever - * passing through BLE_ON. We should broadcast the OFF intent in this case. */ - isStandardBroadcast = !isBleState(prevState); - - } else if (!intermediate_off) { - // connect to GattService - if (DBG) { - Log.d(TAG, "Bluetooth is in LE only mode"); - } - if (mBluetoothGatt != null || !mContext.getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { - continueFromBleOnState(); - } else { - if (DBG) { - Log.d(TAG, "Binding Bluetooth GATT service"); - } - Intent i = new Intent(IBluetoothGatt.class.getName()); - doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, - UserHandle.CURRENT); - } - sendBleStateChanged(prevState, newState); - //Don't broadcase this as std intent - isStandardBroadcast = false; + if (newState == STATE_ON) { + sendBluetoothStateCallback(true); + } else if (newState == STATE_OFF) { + // If Bluetooth is off, send service down event to proxy objects, and unbind + Log.d(TAG, "bluetoothStateChangeHandler: Bluetooth is OFF send Service Down"); + sendBluetoothServiceDownCallback(); + unbindAndFinish(); + } else if (newState == STATE_BLE_ON && prevState == STATE_BLE_TURNING_ON) { + continueFromBleOnState(); + } // Nothing specific to do for STATE_TURNING_ - } else if (intermediate_off) { - if (DBG) { - Log.d(TAG, "Intermediate off, back to LE only mode"); - } - // For LE only mode, broadcast as is - sendBleStateChanged(prevState, newState); - sendBluetoothStateCallback(false); // BT is OFF for general users - // Broadcast as STATE_OFF - newState = BluetoothAdapter.STATE_OFF; - sendBrEdrDownCallback(mContext.getAttributionSource()); - } - } else if (newState == BluetoothAdapter.STATE_ON) { - boolean isUp = (newState == BluetoothAdapter.STATE_ON); - sendBluetoothStateCallback(isUp); - sendBleStateChanged(prevState, newState); - - } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON) { - sendBleStateChanged(prevState, newState); - isStandardBroadcast = false; - } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_OFF) { - sendBleStateChanged(prevState, newState); - if (prevState != BluetoothAdapter.STATE_TURNING_OFF) { - isStandardBroadcast = false; - } else { - // Broadcast as STATE_OFF for app that do not receive BLE update - newState = BluetoothAdapter.STATE_OFF; - sendBrEdrDownCallback(mContext.getAttributionSource()); - } - } else if (newState == BluetoothAdapter.STATE_TURNING_ON - || newState == BluetoothAdapter.STATE_TURNING_OFF) { - sendBleStateChanged(prevState, newState); - } + broadcastIntentStateChange(BluetoothAdapter.ACTION_BLE_STATE_CHANGED, prevState, newState); - if (isStandardBroadcast) { - if (prevState == BluetoothAdapter.STATE_BLE_ON) { - // Show prevState of BLE_ON as OFF to standard users - prevState = BluetoothAdapter.STATE_OFF; - } - if (DBG) { - Log.d(TAG, - "Sending State Change: " + BluetoothAdapter.nameForState(prevState) + " > " - + BluetoothAdapter.nameForState(newState)); + // BLE state are shown as STATE_OFF for BrEdr users + final int prevBrEdrState = isBleState(prevState) ? STATE_OFF : prevState; + final int newBrEdrState = isBleState(newState) ? STATE_OFF : newState; + + if (prevBrEdrState != newBrEdrState) { // Only broadcast when there is a BrEdr state change. + if (newBrEdrState == STATE_OFF) { + sendBluetoothStateCallback(false); + sendBrEdrDownCallback(mContext.getAttributionSource()); } - Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); - intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); - intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null, - getTempAllowlistBroadcastOptions()); + broadcastIntentStateChange( + BluetoothAdapter.ACTION_STATE_CHANGED, prevBrEdrState, newBrEdrState); } } boolean waitForManagerState(int state) { - return waitForState(Set.of(state), false); + return mState.waitForState(getSyncTimeout(), state); } - private boolean waitForState(Set states) { - return waitForState(states, true); - } - private boolean waitForState(Set states, boolean failIfUnbind) { - for (int i = 0; i < 10; i++) { - mBluetoothLock.readLock().lock(); - try { - if (mBluetooth == null && failIfUnbind) { - Log.e(TAG, "waitForState " + states + " Bluetooth is not unbind"); - return false; - } - if (mBluetooth == null && states.contains(BluetoothAdapter.STATE_OFF)) { - return true; // We are so OFF that the bluetooth is not bind - } - if (mBluetooth != null && states.contains(synchronousGetState())) { - return true; - } - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, "getState()", e); - break; - } finally { - mBluetoothLock.readLock().unlock(); - } - SystemClock.sleep(300); - } - Log.e(TAG, "waitForState " + states + " time out"); - return false; + private boolean waitForState(int... states) { + return mState.waitForState(getSyncTimeout(), states); } private void sendDisableMsg(int reason, String packageName) { - BluetoothServerProxy.getInstance().handlerSendWhatMessage(mHandler, MESSAGE_DISABLE); + mHandler.sendEmptyMessage(MESSAGE_DISABLE); addActiveLog(reason, packageName, false); } @@ -3122,8 +2497,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } private void sendEnableMsg(boolean quietMode, int reason, String packageName, boolean isBle) { - mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, - isBle ? 1 : 0)); + mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, isBle ? 1 : 0).sendToTarget(); addActiveLog(reason, packageName, true); mLastEnabledTime = SystemClock.elapsedRealtime(); } @@ -3133,8 +2507,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { if (mActiveLogs.size() > ACTIVE_LOG_MAX_SIZE) { mActiveLogs.remove(); } - mActiveLogs.add( - new ActiveLog(reason, packageName, enable, System.currentTimeMillis())); + mActiveLogs.add(new ActiveLog(reason, packageName, enable, System.currentTimeMillis())); int state = enable @@ -3161,10 +2534,11 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } } - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) + @RequiresPermission( + allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) private void recoverBluetoothServiceFromError(boolean clearBle) { Log.e(TAG, "recoverBluetoothServiceFromError"); boolean repeatAirplaneRunnable = false; @@ -3174,43 +2548,44 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { mHandler.removeCallbacksAndMessages(ON_AIRPLANE_MODE_CHANGED_TOKEN); repeatAirplaneRunnable = true; } - mBluetoothLock.readLock().lock(); + mAdapterLock.readLock().lock(); try { - if (mBluetooth != null) { - //Unregister callback object - synchronousUnregisterCallback(mBluetoothCallback, mContext.getAttributionSource()); + if (mAdapter != null) { + // Unregister callback object + mAdapter.unregisterCallback(mBluetoothCallback, mContext.getAttributionSource()); } } catch (RemoteException | TimeoutException e) { Log.e(TAG, "Unable to unregister", e); } finally { - mBluetoothLock.readLock().unlock(); + mAdapterLock.readLock().unlock(); } SystemClock.sleep(500); // disable - addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR, - mContext.getPackageName(), false); + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR, + mContext.getPackageName(), + false); handleDisable(); - waitForState(Set.of(BluetoothAdapter.STATE_OFF)); + waitForState(STATE_OFF); sendBluetoothServiceDownCallback(); - mBluetoothLock.writeLock().lock(); + mAdapterLock.writeLock().lock(); try { - if (mBluetooth != null) { - mBluetooth = null; + if (mAdapter != null) { + mAdapter = null; // Unbind mContext.unbindService(mConnection); } - mBluetoothGatt = null; } finally { - mBluetoothLock.writeLock().unlock(); + mAdapterLock.writeLock().unlock(); } mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); - mState = BluetoothAdapter.STATE_OFF; + mState.set(STATE_OFF); if (clearBle) { clearBleApps(); @@ -3219,11 +2594,10 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { mEnable = false; // Send a Bluetooth Restart message to reenable bluetooth - Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS); + mHandler.sendEmptyMessageDelayed(MESSAGE_RESTART_BLUETOOTH_SERVICE, ERROR_RESTART_TIME_MS); if (repeatAirplaneRunnable) { - onAirplaneModeChanged(); + onAirplaneModeChanged(isAirplaneModeOn()); } } @@ -3245,8 +2619,8 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { * @param userHandle user to disable bluetooth sharing for * @param bluetoothSharingDisallowed whether bluetooth sharing is disallowed. */ - private void updateOppLauncherComponentState(UserHandle userHandle, - boolean bluetoothSharingDisallowed) { + private void updateOppLauncherComponentState( + UserHandle userHandle, boolean bluetoothSharingDisallowed) { try { int newState; if (bluetoothSharingDisallowed) { @@ -3259,29 +2633,31 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { // Bluetooth OPP activities that should always be enabled, // even when Bluetooth is turned OFF. - List baseBluetoothOppActivities = List.of( - // Base sharing activity - "com.android.bluetooth.opp.BluetoothOppLauncherActivity", - // BT enable activities - "com.android.bluetooth.opp.BluetoothOppBtEnableActivity", - "com.android.bluetooth.opp.BluetoothOppBtEnablingActivity", - "com.android.bluetooth.opp.BluetoothOppBtErrorActivity"); + List baseBluetoothOppActivities = + List.of( + // Base sharing activity + "com.android.bluetooth.opp.BluetoothOppLauncherActivity", + // BT enable activities + "com.android.bluetooth.opp.BluetoothOppBtEnableActivity", + "com.android.bluetooth.opp.BluetoothOppBtEnablingActivity", + "com.android.bluetooth.opp.BluetoothOppBtErrorActivity"); PackageManager systemPackageManager = mContext.getPackageManager(); - PackageManager userPackageManager = mContext.createContextAsUser(userHandle, 0) - .getPackageManager(); + PackageManager userPackageManager = + mContext.createContextAsUser(userHandle, 0).getPackageManager(); var allPackages = systemPackageManager.getPackagesForUid(Process.BLUETOOTH_UID); for (String candidatePackage : allPackages) { Log.v(TAG, "Searching package " + candidatePackage); PackageInfo packageInfo; try { - packageInfo = systemPackageManager.getPackageInfo( - candidatePackage, - PackageManager.PackageInfoFlags.of( - PackageManager.GET_ACTIVITIES - | PackageManager.MATCH_ANY_USER - | PackageManager.MATCH_UNINSTALLED_PACKAGES - | PackageManager.MATCH_DISABLED_COMPONENTS)); + packageInfo = + systemPackageManager.getPackageInfo( + candidatePackage, + PackageManager.PackageInfoFlags.of( + PackageManager.GET_ACTIVITIES + | PackageManager.MATCH_ANY_USER + | PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_DISABLED_COMPONENTS)); } catch (PackageManager.NameNotFoundException e) { // ignore, try next package Log.e(TAG, "Could not find package " + candidatePackage); @@ -3300,15 +2676,15 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { userPackageManager.setComponentEnabledSetting( new ComponentName(candidatePackage, activityName), newState, - PackageManager.DONT_KILL_APP - ); + PackageManager.DONT_KILL_APP); } return; } } } - Log.e(TAG, + Log.e( + TAG, "Cannot toggle Bluetooth OPP activities, could not find them in any package"); } catch (Exception e) { Log.e(TAG, "updateOppLauncherComponentState failed: " + e); @@ -3319,12 +2695,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { return (mErrorRecoveryRetryCounter + 1) * SERVICE_RESTART_TIME_MS; } - @Override - public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - if ((mContext.checkCallingOrSelfPermission( - android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED)) { - return; - } + void dump(FileDescriptor fd, PrintWriter writer, String[] args) { if ((args.length > 0) && args[0].startsWith("--proto")) { dumpProto(fd); return; @@ -3333,15 +2704,19 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { writer.println("Bluetooth Status"); writer.println(" enabled: " + isEnabled()); - writer.println(" state: " + BluetoothAdapter.nameForState(mState)); + writer.println(" state: " + mState); writer.println(" address: " + mAddress); writer.println(" name: " + mName); if (mEnable) { long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime; - String onDurationString = String.format(Locale.US, "%02d:%02d:%02d.%03d", - (int) (onDuration / (1000 * 60 * 60)), - (int) ((onDuration / (1000 * 60)) % 60), (int) ((onDuration / 1000) % 60), - (int) (onDuration % 1000)); + String onDurationString = + String.format( + Locale.US, + "%02d:%02d:%02d.%03d", + (int) (onDuration / (1000 * 60 * 60)), + (int) ((onDuration / (1000 * 60)) % 60), + (int) ((onDuration / 1000) % 60), + (int) (onDuration % 1000)); writer.println(" time since enabled: " + onDurationString); } @@ -3354,8 +2729,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { } } - writer.println( - "\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s")); + writer.println("\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s")); if (mCrashes == CRASH_LOG_MAX_SIZE) { writer.println("(last " + CRASH_LOG_MAX_SIZE + ")"); } @@ -3363,8 +2737,12 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { writer.println(" " + timeToLog(time)); } - writer.println("\n" + mBleApps.size() + " BLE app" + (mBleApps.size() == 1 ? "" : "s") - + " registered"); + writer.println( + "\n" + + mBleApps.size() + + " BLE app" + + (mBleApps.size() == 1 ? "" : "s") + + " registered"); for (ClientDeathRecipient app : mBleApps.values()) { writer.println(" " + app.getPackageName()); } @@ -3383,11 +2761,12 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { args[0] = "--print"; } - if (mBluetoothBinder == null) { + if (mAdapter == null) { errorMsg = "Bluetooth Service not connected"; } else { try { - mBluetoothBinder.dump(fd, args); + // TODO(b/239890880): system_server cannot make non-oneway call + mAdapter.getAdapterBinder().asBinder().dump(fd, args); } catch (RemoteException re) { errorMsg = "RemoteException while dumping Bluetooth Service"; } @@ -3400,31 +2779,32 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { private void dumpProto(FileDescriptor fd) { final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd)); proto.write(BluetoothManagerServiceDumpProto.ENABLED, isEnabled()); - proto.write(BluetoothManagerServiceDumpProto.STATE, mState); - proto.write(BluetoothManagerServiceDumpProto.STATE_NAME, - BluetoothAdapter.nameForState(mState)); + proto.write(BluetoothManagerServiceDumpProto.STATE, mState.get()); + proto.write( + BluetoothManagerServiceDumpProto.STATE_NAME, + BluetoothAdapter.nameForState(mState.get())); proto.write(BluetoothManagerServiceDumpProto.ADDRESS, mAddress); proto.write(BluetoothManagerServiceDumpProto.NAME, mName); if (mEnable) { proto.write(BluetoothManagerServiceDumpProto.LAST_ENABLED_TIME_MS, mLastEnabledTime); } - proto.write(BluetoothManagerServiceDumpProto.CURR_TIMESTAMP_MS, - SystemClock.elapsedRealtime()); + proto.write( + BluetoothManagerServiceDumpProto.CURR_TIMESTAMP_MS, SystemClock.elapsedRealtime()); for (ActiveLog log : mActiveLogs) { long token = proto.start(BluetoothManagerServiceDumpProto.ACTIVE_LOGS); log.dump(proto); proto.end(token); } proto.write(BluetoothManagerServiceDumpProto.NUM_CRASHES, mCrashes); - proto.write(BluetoothManagerServiceDumpProto.CRASH_LOG_MAXED, - mCrashes == CRASH_LOG_MAX_SIZE); + proto.write( + BluetoothManagerServiceDumpProto.CRASH_LOG_MAXED, mCrashes == CRASH_LOG_MAX_SIZE); for (Long time : mCrashTimestamps) { proto.write(BluetoothManagerServiceDumpProto.CRASH_TIMESTAMPS_MS, time); } proto.write(BluetoothManagerServiceDumpProto.NUM_BLE_APPS, mBleApps.size()); for (ClientDeathRecipient app : mBleApps.values()) { - proto.write(BluetoothManagerServiceDumpProto.BLE_APP_PACKAGE_NAMES, - app.getPackageName()); + proto.write( + BluetoothManagerServiceDumpProto.BLE_APP_PACKAGE_NAMES, app.getPackageName()); } proto.flush(); } @@ -3454,74 +2834,24 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { case BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED: return "INIT_FLAGS_CHANGED"; case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED: - default: return "UNKNOWN[" + reason + "]"; - } - } - - @SuppressLint("AndroidFrameworkRequiresPermission") - private static boolean checkPermissionForDataDelivery(Context context, String permission, - AttributionSource attributionSource, String message) { - PermissionManager pm = context.getSystemService(PermissionManager.class); - if (pm == null) { - return false; - } - AttributionSource currentAttribution = new AttributionSource - .Builder(context.getAttributionSource()) - .setNext(attributionSource) - .build(); - final int result = pm.checkPermissionForDataDeliveryFromDataSource(permission, - currentAttribution, message); - if (result == PERMISSION_GRANTED) { - return true; - } - - final String msg = "Need " + permission + " permission for " + attributionSource + ": " - + message; - if (result == PERMISSION_HARD_DENIED) { - throw new SecurityException(msg); - } else { - Log.w(TAG, msg); - return false; + default: + return "UNKNOWN[" + reason + "]"; } } - /** - * Returns true if the BLUETOOTH_CONNECT permission is granted for the calling app. Returns - * false if the result is a soft denial. Throws SecurityException if the result is a hard - * denial. - * - *

    Should be used in situations where the app op should not be noted. - */ - @SuppressLint("AndroidFrameworkRequiresPermission") - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public static boolean checkConnectPermissionForDataDelivery( - Context context, AttributionSource attributionSource, String message) { - return checkPermissionForDataDelivery(context, BLUETOOTH_CONNECT, - attributionSource, message); - } - - @Override - public int handleShellCommand(@NonNull ParcelFileDescriptor in, - @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, - @NonNull String[] args) { - return new BluetoothShellCommand(this, mContext).exec(this, in.getFileDescriptor(), - out.getFileDescriptor(), err.getFileDescriptor(), args); - } - - // TODO(b/193460475): Remove when tooling supports SystemApi to public API. - @SuppressLint("NewApi") static @NonNull Bundle getTempAllowlistBroadcastOptions() { final long duration = 10_000; final BroadcastOptions bOptions = BroadcastOptions.makeBasic(); - bOptions.setTemporaryAppAllowlist(duration, + bOptions.setTemporaryAppAllowlist( + duration, TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, - PowerExemptionManager.REASON_BLUETOOTH_BROADCAST, ""); + PowerExemptionManager.REASON_BLUETOOTH_BROADCAST, + ""); return bOptions.toBundle(); } - private ComponentName resolveSystemService(@NonNull Intent intent, - @NonNull PackageManager pm, int flags) { - List results = pm.queryIntentServices(intent, flags); + private ComponentName resolveSystemService(@NonNull Intent intent) { + List results = mContext.getPackageManager().queryIntentServices(intent, 0); if (results == null) { return null; } @@ -3531,102 +2861,24 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { if ((ri.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { continue; } - ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName, - ri.serviceInfo.name); + ComponentName foundComp = + new ComponentName( + ri.serviceInfo.applicationInfo.packageName, ri.serviceInfo.name); if (comp != null) { - throw new IllegalStateException("Multiple system services handle " + intent - + ": " + comp + ", " + foundComp); + throw new IllegalStateException( + "Multiple system services handle " + + intent + + ": " + + comp + + ", " + + foundComp); } comp = foundComp; } return comp; } - private boolean isPrivileged(int pid, int uid) { - return (mContext.checkPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED, pid, uid) - == PackageManager.PERMISSION_GRANTED) - || (mContext.getPackageManager().checkSignatures(uid, Process.SYSTEM_UID) - == PackageManager.SIGNATURE_MATCH); - } - - private Pair getDeviceOwner() { - DevicePolicyManager devicePolicyManager = - mContext.getSystemService(DevicePolicyManager.class); - if (devicePolicyManager == null) return null; - long ident = Binder.clearCallingIdentity(); - UserHandle deviceOwnerUser = null; - ComponentName deviceOwnerComponent = null; - try { - deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser(); - deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser(); - } finally { - Binder.restoreCallingIdentity(ident); - } - if (deviceOwnerUser == null || deviceOwnerComponent == null - || deviceOwnerComponent.getPackageName() == null) { - return null; - } - return new Pair<>(deviceOwnerUser, deviceOwnerComponent); - } - - private boolean isDeviceOwner(int uid, String packageName) { - if (packageName == null) { - Log.e(TAG, "isDeviceOwner: packageName is null, returning false"); - return false; - } - - Pair deviceOwner = getDeviceOwner(); - - // no device owner - if (deviceOwner == null) return false; - - return deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid)) - && deviceOwner.second.getPackageName().equals(packageName); - } - - private boolean isProfileOwner(int uid, String packageName) { - Context userContext; - try { - userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0, - UserHandle.getUserHandleForUid(uid)); - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Unknown package name"); - return false; - } - if (userContext == null) { - Log.e(TAG, "Unable to retrieve user context for " + uid); - return false; - } - DevicePolicyManager devicePolicyManager = - userContext.getSystemService(DevicePolicyManager.class); - if (devicePolicyManager == null) { - Log.w(TAG, "Error retrieving DPM service"); - return false; - } - return devicePolicyManager.isProfileOwnerApp(packageName); - } - - public boolean isSystem(String packageName, int uid) { - long ident = Binder.clearCallingIdentity(); - try { - ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser( - packageName, 0, UserHandle.getUserHandleForUid(uid)); - return (info.flags & FLAGS_SYSTEM_APP) != 0; - } catch (PackageManager.NameNotFoundException e) { - return false; - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - /** - * Sets Bluetooth HCI snoop log mode - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - @Override - public int setBtHciSnoopLogMode(int mode) { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, - "Need BLUETOOTH_PRIVILEGED permission"); + int setBtHciSnoopLogMode(int mode) { final BluetoothProperties.snoop_log_mode_values snoopMode; switch (mode) { @@ -3652,16 +2904,10 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { return BluetoothStatusCodes.SUCCESS; } - /** - * Gets Bluetooth HCI snoop log mode - */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - @Override - public int getBtHciSnoopLogMode() { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, - "Need BLUETOOTH_PRIVILEGED permission"); - BluetoothProperties.snoop_log_mode_values mode = BluetoothProperties.snoop_log_mode() - .orElse(BluetoothProperties.snoop_log_mode_values.DISABLED); + int getBtHciSnoopLogMode() { + BluetoothProperties.snoop_log_mode_values mode = + BluetoothProperties.snoop_log_mode() + .orElse(BluetoothProperties.snoop_log_mode_values.DISABLED); if (mode == BluetoothProperties.snoop_log_mode_values.FILTERED) { return BluetoothAdapter.BT_SNOOP_LOG_MODE_FILTERED; } else if (mode == BluetoothProperties.snoop_log_mode_values.FULL) { @@ -3672,6 +2918,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { /** * Check if BLE is supported by this platform + * * @param context current device context * @return true if BLE is supported, false otherwise */ @@ -3681,6 +2928,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { /** * Check if this is an automotive device + * * @param context current device context * @return true if this Android device is an automotive device, false otherwise */ @@ -3690,6 +2938,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { /** * Check if this is a watch device + * * @param context current device context * @return true if this Android device is a watch device, false otherwise */ @@ -3699,6 +2948,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { /** * Check if this is a TV device + * * @param context current device context * @return true if this Android device is a TV device, false otherwise */ @@ -3708,4 +2958,3 @@ public class BluetoothManagerService extends IBluetoothManager.Stub { || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK); } } - diff --git a/service/src/com/android/server/bluetooth/BluetoothModeChangeHelper.java b/service/src/com/android/server/bluetooth/BluetoothModeChangeHelper.java index 58325e7a76ab1d40c7f35e6acd2bb8d0cc8abaaf..b90e9bbc185918e863c3762aa70232a745a30e86 100644 --- a/service/src/com/android/server/bluetooth/BluetoothModeChangeHelper.java +++ b/service/src/com/android/server/bluetooth/BluetoothModeChangeHelper.java @@ -18,21 +18,14 @@ package com.android.server.bluetooth; import static com.android.server.bluetooth.BluetoothAirplaneModeListener.BLUETOOTH_APM_STATE; -import android.annotation.RequiresPermission; import android.app.ActivityManager; -import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothHearingAid; -import android.bluetooth.BluetoothLeAudio; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothProfile.ServiceListener; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Process; import android.os.UserHandle; import android.provider.Settings; -import android.util.Log; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; @@ -42,11 +35,8 @@ import com.android.internal.annotations.VisibleForTesting; * complex logic. */ public class BluetoothModeChangeHelper { - private static final String TAG = "BluetoothModeChangeHelper"; + private static final String TAG = BluetoothModeChangeHelper.class.getSimpleName(); - private volatile BluetoothA2dp mA2dp; - private volatile BluetoothHearingAid mHearingAid; - private volatile BluetoothLeAudio mLeAudio; private final BluetoothAdapter mAdapter; private final Context mContext; @@ -55,54 +45,6 @@ public class BluetoothModeChangeHelper { BluetoothModeChangeHelper(Context context) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mContext = context; - - mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP); - mAdapter.getProfileProxy(mContext, mProfileServiceListener, - BluetoothProfile.HEARING_AID); - mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.LE_AUDIO); - } - - private final ServiceListener mProfileServiceListener = new ServiceListener() { - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - // Setup Bluetooth profile proxies - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = (BluetoothA2dp) proxy; - break; - case BluetoothProfile.HEARING_AID: - mHearingAid = (BluetoothHearingAid) proxy; - break; - case BluetoothProfile.LE_AUDIO: - mLeAudio = (BluetoothLeAudio) proxy; - break; - default: - break; - } - } - - @Override - public void onServiceDisconnected(int profile) { - // Clear Bluetooth profile proxies - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = null; - break; - case BluetoothProfile.HEARING_AID: - mHearingAid = null; - break; - case BluetoothProfile.LE_AUDIO: - mLeAudio = null; - break; - default: - break; - } - } - }; - - @VisibleForTesting - public boolean isMediaProfileConnected() { - return isA2dpConnected() || isHearingAidConnected() || isLeAudioConnected(); } @VisibleForTesting @@ -114,18 +56,6 @@ public class BluetoothModeChangeHelper { return adapter.isLeEnabled(); } - @VisibleForTesting - public boolean isAirplaneModeOn() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0) == 1; - } - - @VisibleForTesting - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - public void onAirplaneModeChanged(BluetoothManagerService managerService) { - managerService.onAirplaneModeChanged(); - } - @VisibleForTesting public int getSettingsInt(String name) { return Settings.Global.getInt(mContext.getContentResolver(), @@ -164,30 +94,6 @@ public class BluetoothModeChangeHelper { Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); } - private boolean isA2dpConnected() { - final BluetoothA2dp a2dp = mA2dp; - if (a2dp == null) { - return false; - } - return a2dp.getConnectedDevices().size() > 0; - } - - private boolean isHearingAidConnected() { - final BluetoothHearingAid hearingAid = mHearingAid; - if (hearingAid == null) { - return false; - } - return hearingAid.getConnectedDevices().size() > 0; - } - - private boolean isLeAudioConnected() { - final BluetoothLeAudio leAudio = mLeAudio; - if (leAudio == null) { - return false; - } - return leAudio.getConnectedDevices().size() > 0; - } - /** * Helper method to check whether BT should be enabled on APM */ diff --git a/service/src/com/android/server/bluetooth/BluetoothNotificationManager.java b/service/src/com/android/server/bluetooth/BluetoothNotificationManager.java index bfe30f25cdee3bc40987b14022f41bb90fe48b9e..90ff384dff7ce5b3a58fa961db5b95333e771f44 100644 --- a/service/src/com/android/server/bluetooth/BluetoothNotificationManager.java +++ b/service/src/com/android/server/bluetooth/BluetoothNotificationManager.java @@ -27,7 +27,6 @@ import android.net.Uri; import android.os.Binder; import android.os.UserHandle; import android.service.notification.StatusBarNotification; -import android.util.Log; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; diff --git a/service/src/com/android/server/bluetooth/BluetoothSatelliteModeListener.java b/service/src/com/android/server/bluetooth/BluetoothSatelliteModeListener.java index b845035b8266999362199146ac5cbf37f00ef1bd..0105ecbc97c884a5e91be9ca626de3a6aafd5a57 100644 --- a/service/src/com/android/server/bluetooth/BluetoothSatelliteModeListener.java +++ b/service/src/com/android/server/bluetooth/BluetoothSatelliteModeListener.java @@ -22,7 +22,6 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.provider.Settings; -import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -35,21 +34,39 @@ public class BluetoothSatelliteModeListener { private final BluetoothManagerService mBluetoothManagerService; private final BluetoothSatelliteModeHandler mHandler; + private final Context mContext; private static final int MSG_SATELLITE_MODE_CHANGED = 0; + /** + * @hide constant copied from {@link Settings.Global} TODO(b/274636414): Migrate to official API + * in Android V. + */ + @VisibleForTesting static final String SETTINGS_SATELLITE_MODE_RADIOS = "satellite_mode_radios"; + /** + * @hide constant copied from {@link Settings.Global} TODO(b/274636414): Migrate to official API + * in Android V. + */ + @VisibleForTesting + static final String SETTINGS_SATELLITE_MODE_ENABLED = "satellite_mode_enabled"; + BluetoothSatelliteModeListener(BluetoothManagerService service, Looper looper, Context context) { Log.d(TAG, " BluetoothSatelliteModeListener"); mBluetoothManagerService = service; mHandler = new BluetoothSatelliteModeHandler(looper); + mContext = context; - context.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(BluetoothManagerService.SETTINGS_SATELLITE_MODE_RADIOS), - false, mSatelliteModeObserver); - context.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(BluetoothManagerService.SETTINGS_SATELLITE_MODE_ENABLED), - false, mSatelliteModeObserver); + context.getContentResolver() + .registerContentObserver( + Settings.Global.getUriFor(SETTINGS_SATELLITE_MODE_RADIOS), + false, + mSatelliteModeObserver); + context.getContentResolver() + .registerContentObserver( + Settings.Global.getUriFor(SETTINGS_SATELLITE_MODE_ENABLED), + false, + mSatelliteModeObserver); } private final ContentObserver mSatelliteModeObserver = new ContentObserver(null) { @@ -77,7 +94,21 @@ public class BluetoothSatelliteModeListener { @VisibleForTesting public void handleSatelliteModeChange() { - mBluetoothManagerService.onSatelliteModeChanged(); + mBluetoothManagerService.onSatelliteModeChanged(isSatelliteModeOn()); + } + + boolean isSatelliteModeSensitive() { + final String satelliteRadios = + Settings.Global.getString( + mContext.getContentResolver(), SETTINGS_SATELLITE_MODE_RADIOS); + return satelliteRadios != null && satelliteRadios.contains(Settings.Global.RADIO_BLUETOOTH); + } + + boolean isSatelliteModeOn() { + if (!isSatelliteModeSensitive()) return false; + return Settings.Global.getInt( + mContext.getContentResolver(), SETTINGS_SATELLITE_MODE_ENABLED, 0) + == 1; } } diff --git a/service/src/com/android/server/bluetooth/BluetoothServerProxy.java b/service/src/com/android/server/bluetooth/BluetoothServerProxy.java index 1d66000969342f3f7f84cb0a809879f82d846129..62803153d20e71e91e3cf3715b77039074bb4727 100644 --- a/service/src/com/android/server/bluetooth/BluetoothServerProxy.java +++ b/service/src/com/android/server/bluetooth/BluetoothServerProxy.java @@ -16,17 +16,15 @@ package com.android.server.bluetooth; +import android.annotation.NonNull; import android.content.ContentResolver; -import android.os.HandlerThread; +import android.os.IBinder; import android.provider.Settings; -import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -/** - * Proxy class for method calls to help with unit testing - */ -public class BluetoothServerProxy { +/** Proxy class for method calls to help with unit testing */ +class BluetoothServerProxy { private static final String TAG = BluetoothServerProxy.class.getSimpleName(); private static final Object INSTANCE_LOCK = new Object(); private static BluetoothServerProxy sInstance; @@ -39,7 +37,7 @@ public class BluetoothServerProxy { * * @return the singleton instance, guaranteed not null */ - public static BluetoothServerProxy getInstance() { + static @NonNull BluetoothServerProxy getInstance() { synchronized (INSTANCE_LOCK) { if (sInstance == null) { sInstance = new BluetoothServerProxy(); @@ -48,56 +46,28 @@ public class BluetoothServerProxy { return sInstance; } - /** - * Allow unit tests to substitute BluetoothPbapMethodCallProxy with a test instance - * - * @param proxy a test instance of the BluetoothPbapMethodCallProxy - */ + /** Allow unit tests to substitute proxy with a test instance */ @VisibleForTesting - public static void setInstanceForTesting(BluetoothServerProxy proxy) { + static void setInstanceForTesting(BluetoothServerProxy proxy) { synchronized (INSTANCE_LOCK) { Log.d(TAG, "setInstanceForTesting(), set to " + proxy); sInstance = proxy; } } - /** - * Proxies {@link com.android.server.bluetooth.BluetoothManagerService.BluetoothHandler}. - */ - public BluetoothManagerService.BluetoothHandler createBluetoothHandler( - BluetoothManagerService.BluetoothHandler bluetoothHandler) { - return bluetoothHandler; - } - - /** - * Proxies {@link com.android.server.bluetooth.BluetoothManagerService.BluetoothHandler}. - */ - public BluetoothManagerService.BluetoothHandler newBluetoothHandler( - BluetoothManagerService.BluetoothHandler bluetoothHandler) { - return bluetoothHandler; + AdapterBinder createAdapterBinder(IBinder binder) { + return new AdapterBinder(binder); } - /** - * Proxies {@link HandlerThread(String)}. - */ - public HandlerThread createHandlerThread(String name) { - return new HandlerThread(name); + String settingsSecureGetString(ContentResolver contentResolver, String name) { + return Settings.Secure.getString(contentResolver, name); } - /** - * Proxies {@link android.provider.Settings.Secure.getString}. - */ - public String settingsSecureGetString(ContentResolver contentResolver, String name) { - return Settings.Secure.getString(contentResolver, name); + int settingsGlobalGetInt(ContentResolver contentResolver, String name, int def) { + return Settings.Global.getInt(contentResolver, name, def); } - /** - * Proxies - * {@link com.android.server.bluetooth.BluetoothManagerService.BluetoothHandler.sendMessage}. - */ - public boolean handlerSendWhatMessage( - com.android.server.bluetooth.BluetoothManagerService.BluetoothHandler handler, - int what) { - return handler.sendMessage(handler.obtainMessage(what)); + int getBluetoothPersistedState(ContentResolver resolver, int defaultValue) { + return Settings.Global.getInt(resolver, Settings.Global.BLUETOOTH_ON, defaultValue); } } diff --git a/service/src/com/android/server/bluetooth/BluetoothService.kt b/service/src/com/android/server/bluetooth/BluetoothService.kt index 10c822b4154ce2033ba67318259ffe380c6063d8..3fcba588f9e96ae4f1f36934e7809e053e9ed4ed 100644 --- a/service/src/com/android/server/bluetooth/BluetoothService.kt +++ b/service/src/com/android/server/bluetooth/BluetoothService.kt @@ -17,17 +17,27 @@ package com.android.server.bluetooth import android.bluetooth.BluetoothAdapter import android.content.Context +import android.os.HandlerThread import android.os.UserManager +import com.android.bluetooth.flags.FeatureFlagsImpl import com.android.server.SystemService import com.android.server.SystemService.TargetUser class BluetoothService(context: Context) : SystemService(context) { - private val mBluetoothManagerService = BluetoothManagerService(context) + private val mHandlerThread: HandlerThread + private val mBluetoothManagerService: BluetoothManagerService private var mInitialized = false - private fun initialize() { + init { + mHandlerThread = HandlerThread("BluetoothManagerService") + mHandlerThread.start() + mBluetoothManagerService = + BluetoothManagerService(context, mHandlerThread.getLooper(), FeatureFlagsImpl()) + } + + private fun initialize(user: TargetUser) { if (!mInitialized) { - mBluetoothManagerService.handleOnBootPhase() + mBluetoothManagerService.handleOnBootPhase(user.userHandle) mInitialized = true } } @@ -38,20 +48,20 @@ class BluetoothService(context: Context) : SystemService(context) { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { publishBinderService( BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, - mBluetoothManagerService + mBluetoothManagerService.getBinder() ) } } override fun onUserStarting(user: TargetUser) { if (!UserManager.isHeadlessSystemUserMode()) { - initialize() + initialize(user) } } - override fun onUserSwitching(from: TargetUser?, to: TargetUser) { + override fun onUserSwitching(_from: TargetUser?, to: TargetUser) { if (!mInitialized) { - initialize() + initialize(to) } else { mBluetoothManagerService.onSwitchUser(to.userHandle) } diff --git a/service/src/com/android/server/bluetooth/BluetoothServiceBinder.java b/service/src/com/android/server/bluetooth/BluetoothServiceBinder.java new file mode 100644 index 0000000000000000000000000000000000000000..352364022b8c73be63df884ec248c4551428c956 --- /dev/null +++ b/service/src/com/android/server/bluetooth/BluetoothServiceBinder.java @@ -0,0 +1,361 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.bluetooth; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.LOCAL_MAC_ADDRESS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import static com.android.server.bluetooth.BtPermissionUtils.checkConnectPermissionForDataDelivery; +import static com.android.server.bluetooth.BtPermissionUtils.getCallingAppId; +import static com.android.server.bluetooth.BtPermissionUtils.isCallerSystem; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.app.AppOpsManager; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.IBluetooth; +import android.bluetooth.IBluetoothManager; +import android.bluetooth.IBluetoothManagerCallback; +import android.bluetooth.IBluetoothProfileServiceConnection; +import android.bluetooth.IBluetoothStateChangeCallback; +import android.content.AttributionSource; +import android.content.Context; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.UserManager; +import android.permission.PermissionManager; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +class BluetoothServiceBinder extends IBluetoothManager.Stub { + private static final String TAG = BluetoothServiceBinder.class.getSimpleName(); + + private final BluetoothManagerService mBluetoothManagerService; + private final Context mContext; + private final UserManager mUserManager; + private final AppOpsManager mAppOpsManager; + private final PermissionManager mPermissionManager; + private final BtPermissionUtils mPermissionUtils; + + BluetoothServiceBinder(BluetoothManagerService bms, Context ctx, UserManager userManager) { + mBluetoothManagerService = bms; + mContext = ctx; + mUserManager = userManager; + mAppOpsManager = + requireNonNull( + ctx.getSystemService(AppOpsManager.class), + "AppOpsManager system service cannot be null"); + mPermissionManager = + requireNonNull( + ctx.getSystemService(PermissionManager.class), + "PermissionManager system service cannot be null"); + mPermissionUtils = new BtPermissionUtils(ctx); + } + + @Override + @Nullable + public IBluetooth registerAdapter(@NonNull IBluetoothManagerCallback callback) { + requireNonNull(callback, "Callback cannot be null in registerAdapter"); + return mBluetoothManagerService.registerAdapter(callback); + } + + @Override + public void unregisterAdapter(@NonNull IBluetoothManagerCallback callback) { + requireNonNull(callback, "Callback cannot be null in unregisterAdapter"); + mBluetoothManagerService.unregisterAdapter(callback); + } + + @Override + public void registerStateChangeCallback(@NonNull IBluetoothStateChangeCallback callback) { + requireNonNull(callback, "Callback cannot be null in registerStateChangeCallback"); + mBluetoothManagerService.registerStateChangeCallback(callback); + } + + @Override + public void unregisterStateChangeCallback(@NonNull IBluetoothStateChangeCallback callback) { + requireNonNull(callback, "Callback cannot be null in unregisterStateChangeCallback"); + mBluetoothManagerService.unregisterStateChangeCallback(callback); + } + + @Override + public boolean enable(@NonNull AttributionSource source) { + requireNonNull(source, "AttributionSource cannot be null in enable"); + + final String errorMsg = + mPermissionUtils.callerCanToggle( + mContext, + source, + mUserManager, + mAppOpsManager, + mPermissionManager, + "enable", + true); + if (!errorMsg.isEmpty()) { + Log.d(TAG, "enable(): FAILED: " + errorMsg); + return false; + } + + return mBluetoothManagerService.enable(source.getPackageName()); + } + + @Override + public boolean enableNoAutoConnect(AttributionSource source) { + requireNonNull(source, "AttributionSource cannot be null in enableNoAutoConnect"); + + final String errorMsg = + mPermissionUtils.callerCanToggle( + mContext, + source, + mUserManager, + mAppOpsManager, + mPermissionManager, + "enableNoAutoConnect", + false); + if (!errorMsg.isEmpty()) { + Log.d(TAG, "enableNoAutoConnect(): FAILED: " + errorMsg); + return false; + } + + if (!mPermissionUtils.isCallerNfc(getCallingAppId())) { + throw new SecurityException("No permission to enable Bluetooth quietly"); + } + + return mBluetoothManagerService.enableNoAutoConnect(source.getPackageName()); + } + + @Override + public boolean disable(AttributionSource source, boolean persist) { + requireNonNull(source, "AttributionSource cannot be null in disable"); + + if (!persist) { + mPermissionUtils.enforcePrivileged(mContext); + } + + final String errorMsg = + mPermissionUtils.callerCanToggle( + mContext, + source, + mUserManager, + mAppOpsManager, + mPermissionManager, + "disable", + true); + if (!errorMsg.isEmpty()) { + Log.d(TAG, "disable(): FAILED: " + errorMsg); + return false; + } + + return mBluetoothManagerService.disable(source.getPackageName(), persist); + } + + @Override + public int getState() { + if (!isCallerSystem(getCallingAppId()) + && !mPermissionUtils.checkIfCallerIsForegroundUser(mUserManager)) { + Log.w(TAG, "getState(): UNAUTHORIZED. Report OFF for non-active and non system user"); + return BluetoothAdapter.STATE_OFF; + } + + return mBluetoothManagerService.getState(); + } + + @Override + public boolean bindBluetoothProfileService( + int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { + requireNonNull( + proxy, + "IBluetoothProfileServiceConnection cannot be null in bindBluetoothProfileService"); + + return mBluetoothManagerService.bindBluetoothProfileService(bluetoothProfile, proxy); + } + + @Override + public void unbindBluetoothProfileService( + int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { + mBluetoothManagerService.unbindBluetoothProfileService(bluetoothProfile, proxy); + } + + @Override + @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS}) + public String getAddress(AttributionSource source) { + requireNonNull(source, "AttributionSource cannot be null in getAddress"); + + if (!checkConnectPermissionForDataDelivery( + mContext, mPermissionManager, source, "getAddress")) { + return null; + } + + if (!isCallerSystem(getCallingAppId()) + && !mPermissionUtils.checkIfCallerIsForegroundUser(mUserManager)) { + Log.w(TAG, "getAddress(): Not allowed for non-active and non system user"); + return null; + } + + if (mContext.checkCallingOrSelfPermission(LOCAL_MAC_ADDRESS) != PERMISSION_GRANTED) { + // TODO(b/280890575): Throws a SecurityException instead + Log.w(TAG, "getAddress(): Client does not have LOCAL_MAC_ADDRESS permission"); + return BluetoothAdapter.DEFAULT_MAC_ADDRESS; + } + + return mBluetoothManagerService.getAddress(source); + } + + @Override + @RequiresPermission(BLUETOOTH_CONNECT) + public String getName(AttributionSource source) { + requireNonNull(source, "AttributionSource cannot be null in getName"); + + if (!checkConnectPermissionForDataDelivery( + mContext, mPermissionManager, source, "getName")) { + return null; + } + + if (!isCallerSystem(getCallingAppId()) + && !mPermissionUtils.checkIfCallerIsForegroundUser(mUserManager)) { + Log.w(TAG, "getName(): not allowed for non-active and non system user"); + return null; + } + + return mBluetoothManagerService.getName(source); + } + + @Override + @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) + public boolean onFactoryReset(AttributionSource source) { + requireNonNull(source, "AttributionSource cannot be null in onFactoryReset"); + + mPermissionUtils.enforcePrivileged(mContext); + + if (!checkConnectPermissionForDataDelivery( + mContext, mPermissionManager, source, "onFactoryReset")) { + return false; + } + + return mBluetoothManagerService.onFactoryReset(source); + } + + @Override + public boolean isBleScanAlwaysAvailable() { + return mBluetoothManagerService.isBleScanAlwaysAvailable(); + } + + @Override + @RequiresPermission(BLUETOOTH_CONNECT) + public boolean enableBle(AttributionSource source, IBinder token) { + requireNonNull(source, "AttributionSource cannot be null in enableBle"); + requireNonNull(token, "IBinder cannot be null in enableBle"); + + final String errorMsg = + mPermissionUtils.callerCanToggle( + mContext, + source, + mUserManager, + mAppOpsManager, + mPermissionManager, + "enableBle", + false); + if (!errorMsg.isEmpty()) { + Log.d(TAG, "enableBle(): FAILED: " + errorMsg); + return false; + } + + return mBluetoothManagerService.enableBle(source.getPackageName(), token); + } + + @Override + @RequiresPermission(BLUETOOTH_CONNECT) + public boolean disableBle(AttributionSource source, IBinder token) { + requireNonNull(source, "AttributionSource cannot be null in disableBle"); + requireNonNull(token, "IBinder cannot be null in disableBle"); + + final String errorMsg = + mPermissionUtils.callerCanToggle( + mContext, + source, + mUserManager, + mAppOpsManager, + mPermissionManager, + "disableBle", + false); + if (!errorMsg.isEmpty()) { + Log.d(TAG, "disableBle(): FAILED: " + errorMsg); + return false; + } + + return mBluetoothManagerService.disableBle(source, source.getPackageName(), token); + } + + @Override + public boolean isBleAppPresent() { + return mBluetoothManagerService.isBleAppPresent(); + } + + @Override + public boolean isHearingAidProfileSupported() { + return mBluetoothManagerService.isHearingAidProfileSupported(); + } + + @Override + @RequiresPermission(BLUETOOTH_PRIVILEGED) + public int setBtHciSnoopLogMode(int mode) { + mPermissionUtils.enforcePrivileged(mContext); + + return mBluetoothManagerService.setBtHciSnoopLogMode(mode); + } + + @Override + @RequiresPermission(BLUETOOTH_PRIVILEGED) + public int getBtHciSnoopLogMode() { + mPermissionUtils.enforcePrivileged(mContext); + + return mBluetoothManagerService.getBtHciSnoopLogMode(); + } + + @Override + public int handleShellCommand( + @NonNull ParcelFileDescriptor in, + @NonNull ParcelFileDescriptor out, + @NonNull ParcelFileDescriptor err, + @NonNull String[] args) { + return new BluetoothShellCommand(mBluetoothManagerService, mContext) + .exec( + this, + in.getFileDescriptor(), + out.getFileDescriptor(), + err.getFileDescriptor(), + args); + } + + @Override + @RequiresPermission(DUMP) + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + if (mContext.checkCallingOrSelfPermission(DUMP) != PERMISSION_GRANTED) { + // TODO(b/280890575): Throws SecurityException instead + Log.w(TAG, "dump(): Client does not have DUMP permission"); + return; + } + + mBluetoothManagerService.dump(fd, writer, args); + } +} diff --git a/service/src/com/android/server/bluetooth/BluetoothShellCommand.java b/service/src/com/android/server/bluetooth/BluetoothShellCommand.java index c18208a9e5c846f422b36edbebfd039fdd4d166c..712475f142dd5da4f9434bde1a43671a2975223b 100644 --- a/service/src/com/android/server/bluetooth/BluetoothShellCommand.java +++ b/service/src/com/android/server/bluetooth/BluetoothShellCommand.java @@ -24,7 +24,6 @@ import android.content.Context; import android.os.Binder; import android.os.Process; import android.os.RemoteException; -import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.BasicShellCommandHandler; @@ -45,7 +44,7 @@ class BluetoothShellCommand extends BasicShellCommandHandler { }; @VisibleForTesting - abstract class BluetoothCommand { + abstract static class BluetoothCommand { final boolean mIsPrivileged; final String mName; @@ -75,7 +74,9 @@ class BluetoothShellCommand extends BasicShellCommandHandler { } @Override public int exec(String cmd) throws RemoteException { - return mManagerService.enable(AttributionSource.myAttributionSource()) ? 0 : -1; + return mManagerService.getBinder().enable(AttributionSource.myAttributionSource()) + ? 0 + : -1; } @Override public void onHelp(PrintWriter pw) { @@ -91,7 +92,11 @@ class BluetoothShellCommand extends BasicShellCommandHandler { } @Override public int exec(String cmd) throws RemoteException { - return mManagerService.disable(AttributionSource.myAttributionSource(), true) ? 0 : -1; + return mManagerService + .getBinder() + .disable(AttributionSource.myAttributionSource(), true) + ? 0 + : -1; } @Override public void onHelp(PrintWriter pw) { diff --git a/service/src/com/android/server/bluetooth/BtPermissionUtils.java b/service/src/com/android/server/bluetooth/BtPermissionUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..c68f25b65fb8e84356103a32082d415a485e2920 --- /dev/null +++ b/service/src/com/android/server/bluetooth/BtPermissionUtils.java @@ -0,0 +1,357 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.bluetooth; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.content.pm.PackageManager.SIGNATURE_MATCH; +import static android.os.Process.SYSTEM_UID; +import static android.permission.PermissionManager.PERMISSION_GRANTED; +import static android.permission.PermissionManager.PERMISSION_HARD_DENIED; + +import static com.android.server.bluetooth.ChangeIds.RESTRICT_ENABLE_DISABLE; + +import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.app.admin.DevicePolicyManager; +import android.app.compat.CompatChanges; +import android.content.AttributionSource; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Process; +import android.os.UserHandle; +import android.os.UserManager; +import android.permission.PermissionManager; + +import java.util.Objects; + +class BtPermissionUtils { + private static final String TAG = BtPermissionUtils.class.getSimpleName(); + + private static final int FLAGS_SYSTEM_APP = + ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + + private final int mSystemUiUid; + + BtPermissionUtils(Context ctx) { + // Check if device is configured with no home screen, which implies no SystemUI. + int systemUiUid = -1; + try { + systemUiUid = + ctx.createContextAsUser(UserHandle.SYSTEM, 0) + .getPackageManager() + .getPackageUid( + "com.android.systemui", + PackageManager.PackageInfoFlags.of( + PackageManager.MATCH_SYSTEM_ONLY)); + Log.d(TAG, "Detected SystemUiUid: " + systemUiUid); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Unable to resolve SystemUI's UID."); + } + mSystemUiUid = systemUiUid; + } + + /** + * Returns true if the BLUETOOTH_CONNECT permission is granted for the calling app. Returns + * false if the result is a soft denial. Throws SecurityException if the result is a hard + * denial. + * + *

    Should be used in situations where the app op should not be noted. + */ + @SuppressLint("AndroidFrameworkRequiresPermission") + @RequiresPermission(BLUETOOTH_CONNECT) + static boolean checkConnectPermissionForDataDelivery( + Context ctx, + PermissionManager permissionManager, + AttributionSource source, + String message) { + final String permission = BLUETOOTH_CONNECT; + AttributionSource currentSource = + new AttributionSource.Builder(ctx.getAttributionSource()).setNext(source).build(); + final int result = + permissionManager.checkPermissionForDataDeliveryFromDataSource( + permission, currentSource, message); + if (result == PERMISSION_GRANTED) { + return true; + } + + final String msg = "Need " + permission + " permission for " + source + ": " + message; + if (result == PERMISSION_HARD_DENIED) { + throw new SecurityException(msg); + } + Log.w(TAG, msg); + return false; + } + + /** + * Return an empty string if the current call is allowed to toggle bluetooth state + * + *

    Return the error description if this caller is not allowed to toggle Bluetooth + */ + String callerCanToggle( + Context ctx, + AttributionSource source, + UserManager userManager, + AppOpsManager appOpsManager, + PermissionManager permissionManager, + String message, + boolean requireForeground) { + if (isBluetoothDisallowed(userManager)) { + return "Bluetooth is not allowed"; + } + + if (!checkBluetoothPermissions( + ctx, + source, + userManager, + appOpsManager, + permissionManager, + message, + requireForeground)) { + return "Missing Bluetooth permission"; + } + + if (requireForeground && !checkCompatChangeRestriction(source, ctx)) { + return "Caller does not match restriction criteria"; + } + + return ""; + } + + static void enforcePrivileged(Context ctx) { + ctx.enforceCallingOrSelfPermission( + BLUETOOTH_PRIVILEGED, "Need BLUETOOTH_PRIVILEGED permission"); + } + + static int getCallingAppId() { + return UserHandle.getAppId(Binder.getCallingUid()); + } + + static boolean isCallerSystem(int callingAppId) { + return callingAppId == Process.SYSTEM_UID; + } + + static boolean isCallerNfc(int callingAppId) { + return callingAppId == Process.NFC_UID; + } + + private static boolean isCallerShell(int callingAppId) { + return callingAppId == Process.SHELL_UID; + } + + private static boolean isCallerRoot(int callingAppId) { + return callingAppId == Process.ROOT_UID; + } + + private boolean isCallerSystemUi(int callingAppId) { + return callingAppId == mSystemUiUid; + } + + private static boolean isPrivileged(Context ctx, int pid, int uid) { + return (ctx.checkPermission(BLUETOOTH_PRIVILEGED, pid, uid) == PERMISSION_GRANTED) + || (ctx.getPackageManager().checkSignatures(uid, SYSTEM_UID) == SIGNATURE_MATCH); + } + + private static boolean isProfileOwner(Context ctx, int uid, String packageName) { + Context userContext; + try { + userContext = + ctx.createPackageContextAsUser( + ctx.getPackageName(), 0, UserHandle.getUserHandleForUid(uid)); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Unknown package name"); + return false; + } + if (userContext == null) { + Log.e(TAG, "Unable to retrieve user context for " + uid); + return false; + } + DevicePolicyManager devicePolicyManager = + userContext.getSystemService(DevicePolicyManager.class); + if (devicePolicyManager == null) { + Log.w(TAG, "isProfileOwner: Error retrieving DevicePolicyManager service"); + return false; + } + return devicePolicyManager.isProfileOwnerApp(packageName); + } + + private static boolean isDeviceOwner(Context ctx, int uid, String packageName) { + if (packageName == null) { + Log.e(TAG, "isDeviceOwner: packageName is null, returning false"); + return false; + } + + DevicePolicyManager devicePolicyManager = ctx.getSystemService(DevicePolicyManager.class); + if (devicePolicyManager == null) { + Log.w(TAG, "isDeviceOwner: Error retrieving DevicePolicyManager service"); + return false; + } + UserHandle deviceOwnerUser = null; + ComponentName deviceOwnerComponent = null; + long ident = Binder.clearCallingIdentity(); + try { + deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser(); + deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser(); + } finally { + Binder.restoreCallingIdentity(ident); + } + if (deviceOwnerUser == null + || deviceOwnerComponent == null + || deviceOwnerComponent.getPackageName() == null) { + return false; + } + + return deviceOwnerUser.equals(UserHandle.getUserHandleForUid(uid)) + && deviceOwnerComponent.getPackageName().equals(packageName); + } + + private static boolean isSystem(Context ctx, String packageName, int uid) { + long ident = Binder.clearCallingIdentity(); + try { + ApplicationInfo info = + ctx.getPackageManager() + .getApplicationInfoAsUser( + packageName, 0, UserHandle.getUserHandleForUid(uid)); + return (info.flags & FLAGS_SYSTEM_APP) != 0; + } catch (PackageManager.NameNotFoundException e) { + return false; + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private static boolean isBluetoothDisallowed(UserManager userManager) { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + return userManager.hasUserRestrictionForUser( + UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + /** + * Check ifthe packageName belongs to calling uid + * + *

    A null package belongs to any uid + */ + private static void checkPackage(AppOpsManager appOpsManager, String packageName) { + final int callingUid = Binder.getCallingUid(); + if (packageName == null) { + Log.w(TAG, "checkPackage(): called with null packageName from " + callingUid); + return; + } + + try { + appOpsManager.checkPackage(callingUid, packageName); + } catch (SecurityException e) { + Log.w(TAG, "checkPackage(): " + packageName + " does not belong to uid " + callingUid); + throw new SecurityException(e.getMessage()); + } + } + + boolean checkIfCallerIsForegroundUser(UserManager userManager) { + final int callingUid = Binder.getCallingUid(); + final UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid); + final UserHandle foregroundUser; + final UserHandle parentUser; + final long callingIdentity = Binder.clearCallingIdentity(); + try { + // `getCurrentUser` need to be call by system server because it require one of + // INTERACT_ACROSS_USERS | INTERACT_ACROSS_USERS_FULL + foregroundUser = UserHandle.of(ActivityManager.getCurrentUser()); + // `getProfileParent` need to be call by system server because it require one of + // MANAGE_USERS | INTERACT_ACROSS_USER and + parentUser = userManager.getProfileParent(callingUser); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + final int callingAppId = UserHandle.getAppId(callingUid); + + // TODO(b/280890575): Remove isCallerX() to only check isForegroundUser + + final boolean valid = + Objects.equals(callingUser, foregroundUser) + || Objects.equals(parentUser, foregroundUser) + || isCallerNfc(callingAppId) + || isCallerSystemUi(callingAppId) + || isCallerShell(callingAppId); + + if (!valid) { + Log.d( + TAG, + "checkIfCallerIsForegroundUser: REJECTED:" + + " callingUser=" + + callingUser + + " parentUser=" + + parentUser + + " foregroundUser=" + + foregroundUser + + " callingAppId=" + + callingAppId); + } + return valid; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private boolean checkBluetoothPermissions( + Context ctx, + AttributionSource source, + UserManager userManager, + AppOpsManager appOpsManager, + PermissionManager permissionManager, + String message, + boolean requireForeground) { + final int callingAppId = getCallingAppId(); + if (isCallerSystem(callingAppId)) return true; + if (isCallerShell(callingAppId)) return true; + if (isCallerRoot(callingAppId)) return true; + checkPackage(appOpsManager, source.getPackageName()); + + if (requireForeground && !checkIfCallerIsForegroundUser(userManager)) { + Log.w(TAG, "Not allowed for non-active and non system user"); + return false; + } + + if (!checkConnectPermissionForDataDelivery(ctx, permissionManager, source, message)) { + return false; + } + return true; + } + + /** Starting from T, enable/disable APIs are limited to system apps or device owners. */ + private static boolean checkCompatChangeRestriction(AttributionSource source, Context ctx) { + final String packageName = source.getPackageName(); + + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + if (CompatChanges.isChangeEnabled(RESTRICT_ENABLE_DISABLE, callingUid) + && !isPrivileged(ctx, callingPid, callingUid) + && !isSystem(ctx, packageName, callingUid) + && !isDeviceOwner(ctx, callingUid, packageName) + && !isProfileOwner(ctx, callingUid, packageName)) { + Log.e(TAG, "Caller is not one of: privileged | system | deviceOwner | profileOwner"); + return false; + } + return true; + } +} diff --git a/service/src/satellite/ModeListener.kt b/service/src/satellite/ModeListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..37009b1137afcf78cfa44fe41b38d9522dcab381 --- /dev/null +++ b/service/src/satellite/ModeListener.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:JvmName("SatelliteModeListener") + +package com.android.server.bluetooth.satellite + +import android.content.ContentResolver +import android.os.Looper +import com.android.server.bluetooth.Log +import com.android.server.bluetooth.initializeRadioModeListener + +/** + * constant copied from {@link Settings.Global} + * + * TODO(b/274636414): Migrate to official API in Android V. + */ +internal const val SETTINGS_SATELLITE_MODE_RADIOS = "satellite_mode_radios" + +/** + * constant copied from {@link Settings.Global} + * + * TODO(b/274636414): Migrate to official API in Android V. + */ +internal const val SETTINGS_SATELLITE_MODE_ENABLED = "satellite_mode_enabled" + +private const val TAG = "SatelliteModeListener" + +public var isOn = false + private set + +/** Listen on satellite mode and trigger the callback if it has changed */ +public fun initialize(looper: Looper, resolver: ContentResolver, callback: (m: Boolean) -> Unit) { + isOn = + initializeRadioModeListener( + looper, + resolver, + SETTINGS_SATELLITE_MODE_RADIOS, + SETTINGS_SATELLITE_MODE_ENABLED, + fun(newMode: Boolean) { + val previousMode = isOn + isOn = newMode + if (previousMode == isOn) { + Log.d(TAG, "Ignore satellite mode change because is already: " + isOn) + return + } + Log.i(TAG, "Trigger callback with state: $isOn") + callback(isOn) + } + ) + Log.i(TAG, "Initialized successfully with state: $isOn") +} diff --git a/service/src/satellite/ModeListenerTest.kt b/service/src/satellite/ModeListenerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..f3adeeaf919886c2cbedd871d192cb44536edf2e --- /dev/null +++ b/service/src/satellite/ModeListenerTest.kt @@ -0,0 +1,200 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.bluetooth.satellite.test + +import android.content.ContentResolver +import android.content.Context +import android.os.Looper +import android.provider.Settings +import androidx.test.core.app.ApplicationProvider +import com.android.server.bluetooth.Log +import com.android.server.bluetooth.satellite.SETTINGS_SATELLITE_MODE_ENABLED +import com.android.server.bluetooth.satellite.SETTINGS_SATELLITE_MODE_RADIOS +import com.android.server.bluetooth.satellite.initialize +import com.android.server.bluetooth.satellite.isOn +import com.android.server.bluetooth.test.disableMode +import com.android.server.bluetooth.test.disableSensitive +import com.android.server.bluetooth.test.enableMode +import com.android.server.bluetooth.test.enableSensitive +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestName +import org.junit.runner.RunWith +import org.mockito.Mockito.times +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class ModeListenerTest { + private val resolver: ContentResolver = + ApplicationProvider.getApplicationContext().getContentResolver() + @JvmField @Rule val testName = TestName() + + private val looper: Looper = Looper.getMainLooper() + + private lateinit var mode: ArrayList + + @Before + public fun setup() { + Log.i("SatelliteModeListener", "\t--> setup of " + testName.getMethodName()) + mode = ArrayList() + } + + private fun enableSensitive() { + enableSensitive(resolver, looper, SETTINGS_SATELLITE_MODE_RADIOS) + } + + private fun disableSensitive() { + disableSensitive(resolver, looper, SETTINGS_SATELLITE_MODE_RADIOS) + } + + private fun disableMode() { + disableMode(resolver, looper, SETTINGS_SATELLITE_MODE_ENABLED) + } + + private fun enableMode() { + enableMode(resolver, looper, SETTINGS_SATELLITE_MODE_ENABLED) + } + + private fun callback(newMode: Boolean) = mode.add(newMode) + + @Test + fun initialize_whenNullSensitive_isOff() { + Settings.Global.putString(resolver, SETTINGS_SATELLITE_MODE_RADIOS, null) + enableMode() + + initialize(looper, resolver, this::callback) + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenNotSensitive_isOff() { + disableSensitive() + enableMode() + + initialize(looper, resolver, this::callback) + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun enable_whenNotSensitive_isOff() { + disableSensitive() + disableMode() + + initialize(looper, resolver, this::callback) + + enableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenSensitive_isOff() { + enableSensitive() + disableMode() + + initialize(looper, resolver, this::callback) + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun initialize_whenSensitive_isOn() { + enableSensitive() + enableMode() + + initialize(looper, resolver, this::callback) + + assertThat(isOn).isTrue() + assertThat(mode).isEmpty() + } + + @Test + fun toggleSensitive_whenEnabled_isOnOffOn() { + enableSensitive() + enableMode() + + initialize(looper, resolver, this::callback) + + disableSensitive() + enableSensitive() + + assertThat(isOn).isTrue() + assertThat(mode).containsExactly(false, true) + } + + @Test + fun toggleEnable_whenSensitive_isOffOnOff() { + enableSensitive() + disableMode() + + initialize(looper, resolver, this::callback) + + enableMode() + disableMode() + + assertThat(isOn).isFalse() + assertThat(mode).containsExactly(true, false) + } + + @Test + fun disable_whenDisabled_discardUpdate() { + enableSensitive() + disableMode() + + initialize(looper, resolver, this::callback) + + disableMode() + + assertThat(isOn).isFalse() + assertThat(mode).isEmpty() + } + + @Test + fun enabled_whenEnabled_discardOnChange() { + enableSensitive() + enableMode() + + initialize(looper, resolver, this::callback) + + enableMode() + + assertThat(isOn).isTrue() + assertThat(mode).isEmpty() + } + + @Test + fun changeContent_whenDisabled_discard() { + enableSensitive() + disableMode() + + initialize(looper, resolver, this::callback) + + disableSensitive() + enableMode() + + assertThat(isOn).isFalse() + // As opposed to the bare RadioModeListener, similar consecutive event are discarded + assertThat(mode).isEmpty() + } +} diff --git a/service/tests/Android.bp b/service/tests/Android.bp index 97dc0b6f03f2c81232e7f34b3dcb892d69f1965c..96c89961e57e232e56ec24d27a6108f544469d5d 100644 --- a/service/tests/Android.bp +++ b/service/tests/Android.bp @@ -20,46 +20,38 @@ package { android_test { name: "ServiceBluetoothTests", + // Linking source to test the working copy, not the on-device copy. + // Use 'pre-jarjar' so that we can reference symbols before renaming. + // Then apply the same common jarjar_rules + defaults: ["service-bluetooth-pre-jarjar"], + jarjar_rules: ":bluetooth-jarjar-rules", + srcs: [ "src/**/*.java", + "src/**/*.kt", ], - dxflags: ["--multi-dex"], - - java_version: "1.9", - static_libs: [ "androidx.test.rules", "frameworks-base-testutils", + "kotlinx_coroutines_test", + "libprotobuf-java-nano", "mockito-target-extended-minus-junit4", + "platform-compat-test-rules", "platform-test-annotations", - "truth-prebuilt", - - // Statically link service-bluetooth-pre-jarjar since we want to test the working copy of - // service-bluetooth, not the on-device copy. - // Use pre-jarjar version so that we can reference symbols before they are renamed. - // Then, the jarjar_rules here will perform the rename for the entire APK - // i.e. service-bluetooth + test code - "service-bluetooth-pre-jarjar", + "truth", ], - jarjar_rules: ":bluetooth-jarjar-rules", - libs: [ "android.test.base", "android.test.mock", "android.test.runner", - "framework-bluetooth-pre-jarjar", ], - jni_libs: [ // these are needed for Extended Mockito - "libbluetooth_jni", "libdexmakerjvmtiagent", "libstaticjvmtiagent", ], - compile_multilib: "both", - certificate: "bluetooth", min_sdk_version: "Tiramisu", diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothAirplaneModeListenerTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothAirplaneModeListenerTest.java index cc3dd456c997339795d5ede723fbca9d33452f42..d25ba428a7b455a09f9275b3d01fd163bf475b83 100644 --- a/service/tests/src/com/android/server/bluetooth/BluetoothAirplaneModeListenerTest.java +++ b/service/tests/src/com/android/server/bluetooth/BluetoothAirplaneModeListenerTest.java @@ -28,16 +28,21 @@ import static com.android.server.bluetooth.BluetoothAirplaneModeListener.WIFI_AP import static org.mockito.Mockito.*; -import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Looper; import android.provider.Settings; +import android.test.mock.MockContentResolver; import androidx.test.filters.MediumTest; +import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.bluetooth.flags.FakeFeatureFlagsImpl; +import com.android.bluetooth.flags.Flags; +import com.android.internal.util.test.FakeSettingsProvider; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -53,130 +58,138 @@ public class BluetoothAirplaneModeListenerTest { private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; @Mock private Context mContext; - @Mock private ContentResolver mContentResolver; + @Mock private BluetoothServerProxy mBluetoothServerProxy; @Mock private BluetoothManagerService mBluetoothManagerService; @Mock private BluetoothModeChangeHelper mHelper; @Mock private BluetoothNotificationManager mBluetoothNotificationManager; @Mock private PackageManager mPackageManager; @Mock private Resources mResources; + private MockContentResolver mContentResolver; + private FakeFeatureFlagsImpl mFakeFlagsImpl; + + static { + // Required for reading DeviceConfig during BluetoothManagerService static init + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(android.Manifest.permission.READ_DEVICE_CONFIG); + } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + + mFakeFlagsImpl = new FakeFeatureFlagsImpl(); + + mContentResolver = new MockContentResolver(); + mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolver); + when(mHelper.getSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT)) .thenReturn(BluetoothAirplaneModeListener.MAX_TOAST_COUNT); - doNothing().when(mHelper).setSettingsInt(anyString(), anyInt()); - doNothing().when(mHelper).showToastMessage(); - doNothing().when(mHelper).onAirplaneModeChanged(any(BluetoothManagerService.class)); - mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener( - mBluetoothManagerService, Looper.getMainLooper(), mContext, - mBluetoothNotificationManager); + BluetoothServerProxy.setInstanceForTesting(mBluetoothServerProxy); + + mBluetoothAirplaneModeListener = + new BluetoothAirplaneModeListener( + mBluetoothManagerService, + Looper.getMainLooper(), + mContext, + mBluetoothNotificationManager, + mFakeFlagsImpl); mBluetoothAirplaneModeListener.start(mHelper); } @Test public void testIgnoreOnAirplanModeChange() { - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(false)); when(mHelper.isBluetoothOn()).thenReturn(true); - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(false)); - when(mHelper.isMediaProfileConnected()).thenReturn(true); - Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(true)); } @Test public void testIgnoreOnAirplanModeChangeApmEnhancement() { - when(mHelper.isAirplaneModeOn()).thenReturn(true); when(mHelper.isBluetoothOn()).thenReturn(true); // When APM enhancement is disabled, BT remains on when connected to a media profile when(mHelper.getSettingsInt(APM_ENHANCEMENT)).thenReturn(0); - when(mHelper.isMediaProfileConnected()).thenReturn(true); - Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(true)); // When APM enhancement is disabled, BT turns off when not connected to a media profile - when(mHelper.isMediaProfileConnected()).thenReturn(false); - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(false)); // When APM enhancement is enabled but not activated by toggling BT in APM, // BT remains on when connected to a media profile when(mHelper.getSettingsInt(APM_ENHANCEMENT)).thenReturn(1); when(mHelper.getSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, UNUSED)).thenReturn(UNUSED); - when(mHelper.isMediaProfileConnected()).thenReturn(true); - Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(true)); // When APM enhancement is enabled but not activated by toggling BT in APM, // BT turns off when not connected to a media profile - when(mHelper.isMediaProfileConnected()).thenReturn(false); - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(false)); // When APM enhancement is enabled but not activated by toggling BT in APM, // BT remains on when the default value for BT in APM is on when(mHelper.isBluetoothOnAPM()).thenReturn(true); - Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(false)); // When APM enhancement is enabled but not activated by toggling BT in APM, // BT remains off when the default value for BT in APM is off when(mHelper.isBluetoothOnAPM()).thenReturn(false); - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(false)); // When APM enhancement is enabled and activated by toggling BT in APM, // BT remains on if user's last choice in APM was on when(mHelper.getSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, UNUSED)).thenReturn(USED); when(mHelper.isBluetoothOnAPM()).thenReturn(true); - Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(false)); // When APM enhancement is enabled and activated by toggling BT in APM, // BT turns off if user's last choice in APM was off when(mHelper.isBluetoothOnAPM()).thenReturn(false); - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(false)); // When APM enhancement is enabled and activated by toggling BT in APM, // BT turns off if user's last choice in APM was off even when connected to a media profile - when(mHelper.isMediaProfileConnected()).thenReturn(true); - Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange(true)); } @Test public void testHandleAirplaneModeChange_InvokeAirplaneModeChanged() { - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); - verify(mHelper).onAirplaneModeChanged(mBluetoothManagerService); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(false); + verify(mBluetoothManagerService).onAirplaneModeChanged(eq(false)); } @Test public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_NotPopToast() { mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT; when(mHelper.isBluetoothOn()).thenReturn(true); - when(mHelper.isMediaProfileConnected()).thenReturn(true); - when(mHelper.isAirplaneModeOn()).thenReturn(true); - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + when(mBluetoothManagerService.isMediaProfileConnected()).thenReturn(true); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(true); verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); verify(mHelper, times(0)).showToastMessage(); - verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService); + verify(mBluetoothManagerService, times(0)).onAirplaneModeChanged(anyBoolean()); } @Test public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_PopToast() { mBluetoothAirplaneModeListener.mToastCount = 0; when(mHelper.isBluetoothOn()).thenReturn(true); - when(mHelper.isMediaProfileConnected()).thenReturn(true); - when(mHelper.isAirplaneModeOn()).thenReturn(true); - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + when(mBluetoothManagerService.isMediaProfileConnected()).thenReturn(true); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(true); verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); verify(mHelper).showToastMessage(); - verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService); + verify(mBluetoothManagerService, times(0)).onAirplaneModeChanged(anyBoolean()); } private void setUpApmNotificationTests() throws Exception { when(mHelper.isBluetoothOn()).thenReturn(true); - when(mHelper.isAirplaneModeOn()).thenReturn(true); when(mHelper.isBluetoothOnAPM()).thenReturn(true); when(mHelper.getSettingsInt(APM_ENHANCEMENT)).thenReturn(1); when(mHelper.getSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, UNUSED)).thenReturn(USED); @@ -187,13 +200,14 @@ public class BluetoothAirplaneModeListenerTest { @Test public void testHandleAirplaneModeChange_ShowBtAndWifiApmNotification() throws Exception { + mFakeFlagsImpl.setFlag(Flags.FLAG_AIRPLANE_RESSOURCES_IN_APP, false); setUpApmNotificationTests(); when(mHelper.getSettingsInt(Settings.Global.WIFI_ON)).thenReturn(1); when(mHelper.getSettingsSecureInt(WIFI_APM_STATE, 0)).thenReturn(1); when(mHelper.getSettingsSecureInt(APM_WIFI_BT_NOTIFICATION, NOTIFICATION_NOT_SHOWN)) .thenReturn(NOTIFICATION_NOT_SHOWN); - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(true); verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); @@ -203,13 +217,14 @@ public class BluetoothAirplaneModeListenerTest { @Test public void testHandleAirplaneModeChange_NotShowBtAndWifiApmNotification() throws Exception { + mFakeFlagsImpl.setFlag(Flags.FLAG_AIRPLANE_RESSOURCES_IN_APP, false); setUpApmNotificationTests(); when(mHelper.getSettingsInt(Settings.Global.WIFI_ON)).thenReturn(1); when(mHelper.getSettingsSecureInt(WIFI_APM_STATE, 0)).thenReturn(1); when(mHelper.getSettingsSecureInt(APM_WIFI_BT_NOTIFICATION, NOTIFICATION_NOT_SHOWN)) .thenReturn(NOTIFICATION_SHOWN); - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(true); verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); @@ -217,15 +232,28 @@ public class BluetoothAirplaneModeListenerTest { verify(mHelper, never()).setSettingsSecureInt(APM_WIFI_BT_NOTIFICATION, NOTIFICATION_SHOWN); } + @Test + public void testHandleAirplaneModeChange_SendBtAndWifiApmNotification() throws Exception { + mFakeFlagsImpl.setFlag(Flags.FLAG_AIRPLANE_RESSOURCES_IN_APP, true); + setUpApmNotificationTests(); + when(mHelper.getSettingsInt(Settings.Global.WIFI_ON)).thenReturn(1); + when(mHelper.getSettingsSecureInt(WIFI_APM_STATE, 0)).thenReturn(1); + + mBluetoothAirplaneModeListener.handleAirplaneModeChange(true); + + verify(mBluetoothManagerService).sendAirplaneModeNotification(eq(APM_WIFI_BT_NOTIFICATION)); + } + @Test public void testHandleAirplaneModeChange_ShowBtApmNotification() throws Exception { + mFakeFlagsImpl.setFlag(Flags.FLAG_AIRPLANE_RESSOURCES_IN_APP, false); setUpApmNotificationTests(); when(mHelper.getSettingsInt(Settings.Global.WIFI_ON)).thenReturn(1); when(mHelper.getSettingsSecureInt(WIFI_APM_STATE, 0)).thenReturn(0); when(mHelper.getSettingsSecureInt(APM_BT_NOTIFICATION, NOTIFICATION_NOT_SHOWN)) .thenReturn(NOTIFICATION_NOT_SHOWN); - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(true); verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); @@ -235,13 +263,14 @@ public class BluetoothAirplaneModeListenerTest { @Test public void testHandleAirplaneModeChange_NotShowBtApmNotification() throws Exception { + mFakeFlagsImpl.setFlag(Flags.FLAG_AIRPLANE_RESSOURCES_IN_APP, false); setUpApmNotificationTests(); when(mHelper.getSettingsInt(Settings.Global.WIFI_ON)).thenReturn(1); when(mHelper.getSettingsSecureInt(WIFI_APM_STATE, 0)).thenReturn(0); when(mHelper.getSettingsSecureInt(APM_BT_NOTIFICATION, NOTIFICATION_NOT_SHOWN)) .thenReturn(NOTIFICATION_SHOWN); - mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(true); verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); @@ -249,6 +278,18 @@ public class BluetoothAirplaneModeListenerTest { verify(mHelper, never()).setSettingsSecureInt(APM_BT_NOTIFICATION, NOTIFICATION_SHOWN); } + @Test + public void testHandleAirplaneModeChange_SendBtApmNotification() throws Exception { + mFakeFlagsImpl.setFlag(Flags.FLAG_AIRPLANE_RESSOURCES_IN_APP, true); + setUpApmNotificationTests(); + when(mHelper.getSettingsInt(Settings.Global.WIFI_ON)).thenReturn(1); + when(mHelper.getSettingsSecureInt(WIFI_APM_STATE, 0)).thenReturn(0); + + mBluetoothAirplaneModeListener.handleAirplaneModeChange(true); + + verify(mBluetoothManagerService).sendAirplaneModeNotification(eq(APM_BT_NOTIFICATION)); + } + @Test public void testIsPopToast_PopToast() { mBluetoothAirplaneModeListener.mToastCount = 0; @@ -262,4 +303,17 @@ public class BluetoothAirplaneModeListenerTest { Assert.assertFalse(mBluetoothAirplaneModeListener.shouldPopToast()); verify(mHelper, times(0)).setSettingsInt(anyString(), anyInt()); } + + @Test + public void testFastToggle() { + boolean expectedIsOn = false; + // return true on proxy while calling the method with false in order to simulate the + // settings having already changed after the wake-up of the observer and before calling + // BluetoothManagerService + doReturn(1) + .when(mBluetoothServerProxy) + .settingsGlobalGetInt(any(), eq(Settings.Global.AIRPLANE_MODE_ON), anyInt()); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(expectedIsOn); + verify(mBluetoothManagerService).onAirplaneModeChanged(eq(expectedIsOn)); + } } diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothDeviceConfigChangeTrackerTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothDeviceConfigChangeTrackerTest.java deleted file mode 100644 index 9eaffc16bdd64351b1ec3a8d17f1812aa497eac2..0000000000000000000000000000000000000000 --- a/service/tests/src/com/android/server/bluetooth/BluetoothDeviceConfigChangeTrackerTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.bluetooth; - -import static com.google.common.truth.Truth.assertThat; - -import android.provider.DeviceConfig; -import android.provider.DeviceConfig.Properties; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class BluetoothDeviceConfigChangeTrackerTest { - @Test - public void testNoProperties() { - BluetoothDeviceConfigChangeTracker changeTracker = - new BluetoothDeviceConfigChangeTracker( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH).build()); - - boolean shouldRestart = - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH).build()); - - assertThat(shouldRestart).isFalse(); - } - - @Test - public void testNewFlag() { - BluetoothDeviceConfigChangeTracker changeTracker = - new BluetoothDeviceConfigChangeTracker( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "true") - .build()); - - boolean shouldRestart = - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "true") - .setString("INIT_b", "true") - .build()); - - assertThat(shouldRestart).isTrue(); - } - - @Test - public void testChangedFlag() { - BluetoothDeviceConfigChangeTracker changeTracker = - new BluetoothDeviceConfigChangeTracker( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "true") - .build()); - - boolean shouldRestart = - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "false") - .build()); - - assertThat(shouldRestart).isTrue(); - } - - @Test - public void testUnchangedInitFlag() { - BluetoothDeviceConfigChangeTracker changeTracker = - new BluetoothDeviceConfigChangeTracker( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "true") - .build()); - - boolean shouldRestart = - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "true") - .build()); - - assertThat(shouldRestart).isFalse(); - } - - @Test - public void testRepeatedChangeInitFlag() { - BluetoothDeviceConfigChangeTracker changeTracker = - new BluetoothDeviceConfigChangeTracker( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH).build()); - - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "true") - .build()); - - boolean shouldRestart = - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "true") - .build()); - - assertThat(shouldRestart).isFalse(); - } - - @Test - public void testWrongNamespace() { - BluetoothDeviceConfigChangeTracker changeTracker = - new BluetoothDeviceConfigChangeTracker( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH).build()); - - boolean shouldRestart = - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder("another_namespace") - .setString("INIT_a", "true") - .build()); - - assertThat(shouldRestart).isFalse(); - } - - @Test - public void testSkipProperty() { - BluetoothDeviceConfigChangeTracker changeTracker = - new BluetoothDeviceConfigChangeTracker( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_a", "true") - .setString("INIT_b", "false") - .build()); - - boolean shouldRestart = - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("INIT_b", "false") - .build()); - - assertThat(shouldRestart).isFalse(); - } - - @Test - public void testNonInitFlag() { - BluetoothDeviceConfigChangeTracker changeTracker = - new BluetoothDeviceConfigChangeTracker( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("a", "true") - .build()); - - boolean shouldRestart = - changeTracker.shouldRestartWhenPropertiesUpdated( - new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH) - .setString("a", "false") - .build()); - - assertThat(shouldRestart).isFalse(); - } -} diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java index a8eb5a1daa3def87003a7d7e499366cb66b949ca..6c78346493b30003fa0f17a5627f2f7f76db1900 100644 --- a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java +++ b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java @@ -16,115 +16,419 @@ 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_ON; + +import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_SERVICE_CONNECTED; +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_REGISTER_STATE_CHANGE_CALLBACK; +import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_TIMEOUT_BIND; + import static com.google.common.truth.Truth.assertThat; +import static org.junit.runners.Parameterized.Parameter; +import static org.junit.runners.Parameterized.Parameters; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.validateMockitoUsage; import static org.mockito.Mockito.verify; +import android.bluetooth.IBluetooth; +import android.bluetooth.IBluetoothCallback; +import android.bluetooth.IBluetoothManagerCallback; +import android.bluetooth.IBluetoothStateChangeCallback; +import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; -import android.os.HandlerThread; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.Message; import android.os.UserHandle; import android.os.UserManager; +import android.os.test.TestLooper; import android.provider.Settings; import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; + +import com.android.bluetooth.flags.FakeFeatureFlagsImpl; +import com.android.bluetooth.flags.Flags; + +import com.google.common.collect.Lists; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) public class BluetoothManagerServiceTest { - static int sTimeout = 3000; + private static final String TAG = BluetoothManagerServiceTest.class.getSimpleName(); + private static final int STATE_BLE_TURNING_ON = 14; // can't find the symbol because hidden api + private static final int TIMEOUT_MS = 1000; // TO use to wait for handler execution + BluetoothManagerService mManagerService; - Context mContext; - @Mock - BluetoothServerProxy mBluetoothServerProxy; - @Mock - BluetoothManagerService.BluetoothHandler mHandler; - HandlerThread mHandlerThread; + + @Spy + private final Context mContext = + new ContextWrapper(InstrumentationRegistry.getInstrumentation().getTargetContext()); + + @Spy BluetoothServerProxy mBluetoothServerProxy; + @Mock UserManager mUserManager; + @Mock UserHandle mUserHandle; + + @Mock IBinder mBinder; + @Mock IBluetoothManagerCallback mManagerCallback; + @Mock IBluetoothStateChangeCallback mStateChangeCallback; + + @Mock IBluetooth mAdapterService; + @Mock AdapterBinder mAdapterBinder; + private FakeFeatureFlagsImpl mFakeFlagsImpl; + + @Parameter public FlagsValue mFlagsValue; + + static class FlagsValue { + final Map mFlagsValue; + + FlagsValue(Map flagsValue) { + mFlagsValue = flagsValue; + } + + private static String formatFlag(String key) { + return key.substring(key.lastIndexOf(".") + 1); + } + + @Override + public String toString() { + return mFlagsValue.entrySet().stream() + .filter(Map.Entry::getValue) + .map(Map.Entry::getKey) + .map(FlagsValue::formatFlag) + .sorted() + .collect(Collectors.joining(", ")); + } + } + + private static boolean filterFlags(Map map) { + if (map.get(Flags.FLAG_USE_NEW_AIRPLANE_MODE)) { + return !map.get(Flags.FLAG_AIRPLANE_RESSOURCES_IN_APP); + } + return true; + } + + /** Generate the Map of flag for this test Suite */ + @Parameters(name = "{0}") + public static Iterable generateParameterizedFlagsValue() { + final String[] flags = { + Flags.FLAG_AIRPLANE_RESSOURCES_IN_APP, + Flags.FLAG_USE_NEW_AIRPLANE_MODE, + Flags.FLAG_USE_NEW_SATELLITE_MODE, + }; + final Boolean[] values = {true, false}; + + List>> flagValues = + Arrays.stream(flags) + .map(flag -> Arrays.stream(values).map(val -> Map.entry(flag, val))) + .map(Stream::toList) + .toList(); + + return Lists.cartesianProduct(flagValues).stream() + .map(list -> list.toArray(new Map.Entry[0])) + .map(Map::ofEntries) + .filter(BluetoothManagerServiceTest::filterFlags) + .map(FlagsValue::new) + .map(List::of) + .map(List::toArray) + .toList(); + } + + TestLooper mLooper; + + boolean mHasException = false; + + static { + // Required for reading DeviceConfig. + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(android.Manifest.permission.READ_DEVICE_CONFIG); + } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = spy(new ContextWrapper( - InstrumentationRegistry.getInstrumentation().getTargetContext())); - mHandlerThread = new HandlerThread("BluetoothManagerServiceTest"); + + // Mock these functions so security errors won't throw + doReturn("name") + .when(mBluetoothServerProxy) + .settingsSecureGetString(any(), eq(Settings.Secure.BLUETOOTH_NAME)); + doReturn("00:11:22:33:44:55") + .when(mBluetoothServerProxy) + .settingsSecureGetString(any(), eq(Settings.Secure.BLUETOOTH_ADDRESS)); + + // Test is not allowed to send broadcast as Bluetooth. doNothing Prevent SecurityException + doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any(), any()); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + + doReturn(mBinder).when(mManagerCallback).asBinder(); + doReturn(mBinder).when(mStateChangeCallback).asBinder(); + + doReturn(mAdapterBinder).when(mBluetoothServerProxy).createAdapterBinder(any()); + doReturn(mAdapterService).when(mAdapterBinder).getAdapterBinder(); + + doReturn(mock(Intent.class)) + .when(mContext) + .registerReceiverForAllUsers(any(), any(), eq(null), eq(null)); + + doReturn(true) + .when(mContext) + .bindServiceAsUser( + any(Intent.class), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class)); + + BluetoothServerProxy.setInstanceForTesting(mBluetoothServerProxy); + + mLooper = new TestLooper(); + + mFakeFlagsImpl = new FakeFeatureFlagsImpl(); + mFlagsValue.mFlagsValue.forEach(mFakeFlagsImpl::setFlag); + + mManagerService = + new BluetoothManagerService(mContext, mLooper.getLooper(), mFakeFlagsImpl); + mManagerService.initialize(mUserHandle); + + mManagerService.registerAdapter(mManagerCallback); } @After public void tearDown() { - mHandlerThread.quitSafely(); + if (mManagerService != null) { + mManagerService.unregisterAdapter(mManagerCallback); + mManagerService = null; + } + mLooper.moveTimeForward(120_000); // 120 seconds + // Do not try to assert if `syncHandler()` already raised an exception for it + if (!mHasException) { + assertThat(mLooper.nextMessage()).isNull(); + } + validateMockitoUsage(); } - private void createBluetoothManagerService() { - doReturn(mock(Intent.class)).when(mContext).registerReceiverForAllUsers(any(), any(), - eq(null), eq(null)); - BluetoothServerProxy.setInstanceForTesting(mBluetoothServerProxy); - // Mock the handler to avoid handle message & to terminate the thread after - // test - doReturn(mHandlerThread).when(mBluetoothServerProxy).createHandlerThread(any()); - doReturn(mHandler).when(mBluetoothServerProxy).newBluetoothHandler(any()); - - // Mock these functions so security errors won't throw - doReturn("name").when(mBluetoothServerProxy).settingsSecureGetString(any(), - eq(Settings.Secure.BLUETOOTH_NAME)); - doReturn("00:11:22:33:44:55").when(mBluetoothServerProxy).settingsSecureGetString(any(), - eq(Settings.Secure.BLUETOOTH_ADDRESS)); - mManagerService = new BluetoothManagerService(mContext); + /** + * Dispatch all the message on the Loopper and check that the what is expected + * + * @param what list of message that are expected to be run by the handler + */ + private void syncHandler(int... what) { + IntStream.of(what) + .forEach( + w -> { + Message msg = mLooper.nextMessage(); + assertThat(msg).isNotNull(); + assertThat(msg.what).isEqualTo(w); + msg.getTarget().dispatchMessage(msg); + }); } @Test public void onUserRestrictionsChanged_disallowBluetooth_onlySendDisableMessageOnSystemUser() throws InterruptedException { - // Spy UserManager so we can mimic the case when restriction settings changed - UserManager userManager = mock(UserManager.class); - doReturn(userManager).when(mContext).getSystemService(UserManager.class); - doReturn(true).when(userManager).hasUserRestrictionForUser( - eq(UserManager.DISALLOW_BLUETOOTH), any()); - doReturn(false).when(userManager).hasUserRestrictionForUser( - eq(UserManager.DISALLOW_BLUETOOTH_SHARING), any()); - createBluetoothManagerService(); + // Mimic the case when restriction settings changed + doReturn(true) + .when(mUserManager) + .hasUserRestrictionForUser(eq(UserManager.DISALLOW_BLUETOOTH), any()); + doReturn(false) + .when(mUserManager) + .hasUserRestrictionForUser(eq(UserManager.DISALLOW_BLUETOOTH_SHARING), any()); // Check if disable message sent once for system user only - // Since Message object is recycled after processed, use proxy function to get what value // test run on user -1, should not turning Bluetooth off mManagerService.onUserRestrictionsChanged(UserHandle.CURRENT); - verify(mBluetoothServerProxy, timeout(sTimeout).times(0)).handlerSendWhatMessage(mHandler, - BluetoothManagerService.MESSAGE_DISABLE); + assertThat(mLooper.nextMessage()).isNull(); // called from SYSTEM user, should try to toggle Bluetooth off mManagerService.onUserRestrictionsChanged(UserHandle.SYSTEM); - verify(mBluetoothServerProxy, timeout(sTimeout)).handlerSendWhatMessage(mHandler, - BluetoothManagerService.MESSAGE_DISABLE); + syncHandler(MESSAGE_DISABLE); } @Test public void testApmEnhancementEnabled() { - createBluetoothManagerService(); - mManagerService.setBluetoothModeChangeHelper(new BluetoothModeChangeHelper(mContext)); - // Change the apm enhancement enabled value to 0 - Settings.Global.putInt(mContext.getContentResolver(), - "apm_enhancement_enabled", 0); - assertThat(Settings.Global.getInt(mContext.getContentResolver(), - "apm_enhancement_enabled", 0)).isEqualTo(0); + Settings.Global.putInt(mContext.getContentResolver(), "apm_enhancement_enabled", 0); + assertThat( + Settings.Global.getInt( + mContext.getContentResolver(), "apm_enhancement_enabled", 0)) + .isEqualTo(0); // Confirm that apm enhancement enabled value has been updated to 1 - mManagerService.loadApmEnhancementStateFromResource(); - assertThat(Settings.Global.getInt(mContext.getContentResolver(), - "apm_enhancement_enabled", 0)).isEqualTo(1); + mManagerService.setApmEnhancementState(); + assertThat( + Settings.Global.getInt( + mContext.getContentResolver(), "apm_enhancement_enabled", 0)) + .isEqualTo(1); + } + + @Test + public void enable_bindFailure_removesTimeout() throws Exception { + doReturn(false) + .when(mContext) + .bindServiceAsUser( + any(Intent.class), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class)); + mManagerService.enableBle("enable_bindFailure_removesTimeout", mBinder); + syncHandler(MESSAGE_ENABLE); + + // TODO(b/280518177): Failed to start should be noted / reported in metrics + // Maybe show a popup or a crash notification + // Should we attempt to re-bind ? + } + + @Test + public void enable_bindTimeout() throws Exception { + mManagerService.enableBle("enable_bindTimeout", mBinder); + syncHandler(MESSAGE_ENABLE); + + mLooper.moveTimeForward(120_000); // 120 seconds + syncHandler(MESSAGE_TIMEOUT_BIND); + // Force handling the message now without waiting for the timeout to fire + + // TODO(b/280518177): A lot of stuff is wrong here since when a timeout occur: + // * No error is printed to the user + // * Code stop trying to start the bluetooth. + // * if user ask to enable again, it will start a second bind but the first still run + } + + private void acceptBluetoothBinding(IBinder binder, String name, int n) { + ComponentName compName = new ComponentName("", "com.android.bluetooth." + name); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(BluetoothManagerService.BluetoothServiceConnection.class); + verify(mContext, times(n)) + .bindServiceAsUser( + any(Intent.class), captor.capture(), anyInt(), any(UserHandle.class)); + assertThat(captor.getAllValues().size()).isEqualTo(n); + + captor.getAllValues().get(n - 1).onServiceConnected(compName, binder); + syncHandler(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); + } + + private static IBluetoothCallback captureBluetoothCallback(AdapterBinder adapterBinder) + throws Exception { + ArgumentCaptor captor = + ArgumentCaptor.forClass(IBluetoothCallback.class); + verify(adapterBinder).registerCallback(captor.capture(), any()); + assertThat(captor.getAllValues().size()).isEqualTo(1); + return captor.getValue(); + } + + IBluetoothCallback transition_offToBleOn() throws Exception { + // Binding of IBluetooth + acceptBluetoothBinding(mBinder, "btservice.AdapterService", 1); + + // TODO(b/280518177): This callback is too early, bt is not ON nor BLE_ON + verify(mManagerCallback).onBluetoothServiceUp(any()); + + IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder); + verify(mAdapterBinder).enable(anyBoolean(), any()); + + // AdapterService is sending AdapterState.BLE_TURN_ON that will trigger this callback + // and in parallel it call its `bringUpBle()` + btCallback.onBluetoothStateChange(STATE_OFF, STATE_BLE_TURNING_ON); + syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON); + + // assertThat(mManagerService.waitForManagerState(STATE_BLE_TURNING_ON)).isTrue(); + + // GattService has been started by AdapterService and it will enable native side then + // trigger the stateChangeCallback from native + btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON); + syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_ON); + + // Check that we sent 2 intent, one for BLE_TURNING_ON, one for BLE_ON + // TODO(b/280518177): assert the intent are the correct one + verify(mContext, times(2)).sendBroadcastAsUser(any(), any(), any(), any()); + return btCallback; + } + + private IBluetoothCallback transition_offToOn() throws Exception { + IBluetoothCallback btCallback = transition_offToBleOn(); + verify(mAdapterBinder, times(1)).startBrEdr(any()); + + // AdapterService go to turning_on and start all profile on its own + btCallback.onBluetoothStateChange(STATE_BLE_ON, STATE_TURNING_ON); + syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + // When all the profile are started, adapterService consider it is ON + btCallback.onBluetoothStateChange(STATE_TURNING_ON, STATE_ON); + syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + + // Check that we sent 6 intent, 4 for BLE: BLE_TURNING_ON + BLE_ON + TURNING_ON + ON + // and 2 for classic: TURNING_ON + ON + // TODO(b/280518177): assert the intent are the correct one + verify(mContext, times(6)).sendBroadcastAsUser(any(), any(), any(), any()); + + return btCallback; + } + + @Test + public void offToBleOn() throws Exception { + // In order to go to BLE only, the persisted state should be BLUETOOTH_OFF + doReturn(BluetoothManagerService.BLUETOOTH_OFF) + .when(mBluetoothServerProxy) + .getBluetoothPersistedState(any(), anyInt()); + + mManagerService.enableBle("test_offToBleOn", mBinder); + syncHandler(MESSAGE_ENABLE); + + transition_offToBleOn(); + + // Check that there was no transition to STATE_ON + verify(mAdapterBinder, times(0)).startBrEdr(any()); + assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_ON); + } + + @Test + public void offToOn() throws Exception { + // In order to not go to BLE only, the persisted state should not be BLUETOOTH_OFF + doReturn(BluetoothManagerService.BLUETOOTH_ON_BLUETOOTH) + .when(mBluetoothServerProxy) + .getBluetoothPersistedState(any(), anyInt()); + + mManagerService.registerStateChangeCallback(mStateChangeCallback); + syncHandler(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); + + mManagerService.enable("test_offToOn"); + syncHandler(MESSAGE_ENABLE); + + transition_offToOn(); + + verify(mStateChangeCallback).onBluetoothStateChange(eq(true)); + assertThat(mManagerService.getState()).isEqualTo(STATE_ON); } } diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothModeChangeHelperTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothModeChangeHelperTest.java index 7c50c98057d3681555f7325167c0f8c1c06f3072..3861896ac268e2e40aa8e7d3d692d77dbc8abc46 100644 --- a/service/tests/src/com/android/server/bluetooth/BluetoothModeChangeHelperTest.java +++ b/service/tests/src/com/android/server/bluetooth/BluetoothModeChangeHelperTest.java @@ -19,11 +19,9 @@ package com.android.server.bluetooth; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import android.content.Context; import android.content.ContextWrapper; -import android.provider.Settings; import android.text.TextUtils; import androidx.test.InstrumentationRegistry; @@ -55,11 +53,6 @@ public class BluetoothModeChangeHelperTest { mHelper = new BluetoothModeChangeHelper(mContext); } - @Test - public void isMediaProfileConnected() { - assertThat(mHelper.isMediaProfileConnected()).isFalse(); - } - @Test public void isBluetoothOn_doesNotCrash() { // assertThat(mHelper.isBluetoothOn()).isFalse(); @@ -69,44 +62,6 @@ public class BluetoothModeChangeHelperTest { mHelper.isBluetoothOn(); } - @Test - public void isAirplaneModeOn() { - assertThat(mHelper.isAirplaneModeOn()).isFalse(); - } - - @Test - public void onAirplaneModeChanged() { - mHelper.onAirplaneModeChanged(mService); - - verify(mService).onAirplaneModeChanged(); - } - - @Test - public void setSettingsInt() { - String testSettingsName = "BluetoothModeChangeHelperTest_test_settings_name"; - int value = 9876; - - try { - mHelper.setSettingsInt(testSettingsName, value); - assertThat(mHelper.getSettingsInt(testSettingsName)).isEqualTo(value); - } finally { - Settings.Global.resetToDefaults(mContext.getContentResolver(), null); - } - } - - @Test - public void setSettingsSecureInt() { - String testSettingsName = "BluetoothModeChangeHelperTest_test_settings_name"; - int value = 1234; - - try { - mHelper.setSettingsSecureInt(testSettingsName, value); - assertThat(mHelper.getSettingsSecureInt(testSettingsName, 0)).isEqualTo(value); - } finally { - Settings.Global.resetToDefaults(mContext.getContentResolver(), null); - } - } - @Test public void isBluetoothOnAPM_doesNotCrash() { mHelper.isBluetoothOnAPM(); diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothSatelliteModeListenerTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothSatelliteModeListenerTest.java deleted file mode 100644 index 204d1a5da2dcfa44ec8e4c83e577a0cf4aa7f8a6..0000000000000000000000000000000000000000 --- a/service/tests/src/com/android/server/bluetooth/BluetoothSatelliteModeListenerTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.bluetooth; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.ContentResolver; -import android.content.Context; -import android.os.Looper; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class BluetoothSatelliteModeListenerTest { - - private BluetoothSatelliteModeListener mBluetoothSatelliteModeListener; - - @Mock private Context mContext; - @Mock private ContentResolver mContentResolver; - @Mock private BluetoothManagerService mBluetoothManagerService; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(mContext.getContentResolver()).thenReturn(mContentResolver); - - mBluetoothSatelliteModeListener = new BluetoothSatelliteModeListener( - mBluetoothManagerService, Looper.getMainLooper(), mContext); - } - - @Test - public void testHandleSatelliteModeChange_InvokeSatelliteModeChanged() { - mBluetoothSatelliteModeListener.handleSatelliteModeChange(); - verify(mBluetoothManagerService).onSatelliteModeChanged(); - } -} - diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothServiceBinderTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothServiceBinderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cd31a27ffadbf605527c97e86ede325b0bb53423 --- /dev/null +++ b/service/tests/src/com/android/server/bluetooth/BluetoothServiceBinderTest.java @@ -0,0 +1,472 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.bluetooth; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.Manifest.permission.LOCAL_MAC_ADDRESS; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockingDetails; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.quality.Strictness.STRICT_STUBS; + +import android.app.AppOpsManager; +import android.app.admin.DevicePolicyManager; +import android.bluetooth.IBluetoothManagerCallback; +import android.bluetooth.IBluetoothProfileServiceConnection; +import android.bluetooth.IBluetoothStateChangeCallback; +import android.compat.testing.PlatformCompatChangeRule; +import android.content.AttributionSource; +import android.content.Context; +import android.content.ContextWrapper; +import android.os.IBinder; +import android.os.Process; +import android.os.UserManager; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.function.ThrowingRunnable; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.function.BooleanSupplier; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class BluetoothServiceBinderTest { + private static final String TAG = BluetoothServiceBinderTest.class.getSimpleName(); + private static final String LOG_COMPAT_CHANGE = "android.permission.LOG_COMPAT_CHANGE"; + private static final String READ_COMPAT_CHANGE_CONFIG = + "android.permission.READ_COMPAT_CHANGE_CONFIG"; + + @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(STRICT_STUBS); + + @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); + + @Mock private BluetoothManagerService mManagerService; + @Mock private UserManager mUserManager; + @Mock private AppOpsManager mAppOpsManager; + @Mock private DevicePolicyManager mDevicePolicyManager; + + private Context mContext = + spy( + new ContextWrapper( + InstrumentationRegistry.getInstrumentation().getTargetContext())); + + private final AttributionSource mSource = + spy(new AttributionSource.Builder(Process.myUid()).build()); + + private BluetoothServiceBinder mBinder; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + lenient().doReturn(TAG).when(mSource).getPackageName(); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG); + + final String appops = mContext.getSystemServiceName(AppOpsManager.class); + final String devicePolicy = mContext.getSystemServiceName(DevicePolicyManager.class); + doReturn(mAppOpsManager).when(mContext).getSystemService(eq(appops)); + doReturn(mDevicePolicyManager).when(mContext).getSystemService(eq(devicePolicy)); + + mBinder = new BluetoothServiceBinder(mManagerService, mContext, mUserManager); + } + + @After + public void tearDown() { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + // Do not call verifyMock here. If the test fails the initial error will be lost + } + + @Test + public void registerAdapter() { + assertThrows(NullPointerException.class, () -> mBinder.registerAdapter(null)); + mBinder.registerAdapter(mock(IBluetoothManagerCallback.class)); + verify(mManagerService).registerAdapter(any()); + verifyMock(); + } + + @Test + public void unregisterAdapter() { + assertThrows(NullPointerException.class, () -> mBinder.unregisterAdapter(null)); + mBinder.unregisterAdapter(mock(IBluetoothManagerCallback.class)); + verify(mManagerService).unregisterAdapter(any()); + verifyMock(); + } + + @Test + public void registerStateChangeCallback() { + assertThrows(NullPointerException.class, () -> mBinder.registerStateChangeCallback(null)); + mBinder.registerStateChangeCallback(mock(IBluetoothStateChangeCallback.class)); + verify(mManagerService).registerStateChangeCallback(any()); + verifyMock(); + } + + @Test + public void unregisterStateChangeCallback() { + assertThrows(NullPointerException.class, () -> mBinder.unregisterStateChangeCallback(null)); + mBinder.unregisterStateChangeCallback(mock(IBluetoothStateChangeCallback.class)); + verify(mManagerService).unregisterStateChangeCallback(any()); + verifyMock(); + } + + @Test + @DisableCompatChanges({ChangeIds.RESTRICT_ENABLE_DISABLE}) + public void enableNoRestrictEnable() { + assertThrows(NullPointerException.class, () -> mBinder.enable(null)); + + checkDisabled(() -> mBinder.enable(mSource)); + checkHardDenied(() -> mBinder.enable(mSource), true); + doReturn(true).when(mManagerService).enable(any()); + checkGranted(() -> mBinder.enable(mSource), true); + verify(mUserManager).getProfileParent(any()); + verify(mManagerService).enable(eq(TAG)); + verifyMock(); + } + + @Test + @EnableCompatChanges({ChangeIds.RESTRICT_ENABLE_DISABLE}) + public void enableWithRestrictEnable() { + assertThrows(NullPointerException.class, () -> mBinder.enable(null)); + + checkDisabled(() -> mBinder.enable(mSource)); + checkHardDenied(() -> mBinder.enable(mSource), true); + checkGranted(() -> mBinder.enable(mSource), false); + verify(mUserManager).getProfileParent(any()); + verifyMock(); + + // TODO(b/280518177): add more test around compatChange + } + + @Test + public void enableNoAutoConnect() { + assertThrows(NullPointerException.class, () -> mBinder.enableNoAutoConnect(null)); + + checkDisabled(() -> mBinder.enableNoAutoConnect(mSource)); + checkHardDenied(() -> mBinder.enableNoAutoConnect(mSource), false); + + // enableNoAutoConnect is only available for Nfc and will fail otherwise + assertThrows(SecurityException.class, () -> mBinder.enableNoAutoConnect(mSource)); + + verify(mUserManager).hasUserRestrictionForUser(eq(UserManager.DISALLOW_BLUETOOTH), any()); + verify(mAppOpsManager).checkPackage(anyInt(), eq(TAG)); + verifyMock(); + + // TODO(b/280518177): add test that simulate NFC caller to have a successful case + } + + @Test + @DisableCompatChanges({ChangeIds.RESTRICT_ENABLE_DISABLE}) + public void disableNoRestrictEnable() { + assertThrows(NullPointerException.class, () -> mBinder.disable(null, true)); + + assertThrows(SecurityException.class, () -> mBinder.disable(mSource, false)); + + checkDisabled(() -> mBinder.disable(mSource, true)); + checkHardDenied(() -> mBinder.disable(mSource, true), true); + doReturn(true).when(mManagerService).disable(any(), anyBoolean()); + checkGranted(() -> mBinder.disable(mSource, true), true); + verify(mUserManager).getProfileParent(any()); + verify(mManagerService).disable(eq(TAG), anyBoolean()); + verifyMock(); + } + + @Test + @EnableCompatChanges({ChangeIds.RESTRICT_ENABLE_DISABLE}) + public void disableWithRestrictEnable() { + assertThrows(NullPointerException.class, () -> mBinder.disable(null, true)); + + assertThrows(SecurityException.class, () -> mBinder.disable(mSource, false)); + + checkDisabled(() -> mBinder.disable(mSource, true)); + checkHardDenied(() -> mBinder.disable(mSource, true), true); + checkGranted(() -> mBinder.disable(mSource, true), false); + verify(mUserManager).getProfileParent(any()); + verifyMock(); + + // TODO(b/280518177): add more test around compatChange + } + + @Test + public void getState() { + // TODO(b/280518177): add more test from not System / ... + // TODO(b/280518177): add more test when caller is not in foreground + + mBinder.getState(); + verify(mManagerService).getState(); + verify(mUserManager).getProfileParent(any()); + verifyMock(); + } + + @Test + public void bindBluetoothProfileService() { + assertThrows( + NullPointerException.class, () -> mBinder.bindBluetoothProfileService(0, null)); + // No permission needed for this call + + mBinder.bindBluetoothProfileService(0, mock(IBluetoothProfileServiceConnection.class)); + verify(mManagerService).bindBluetoothProfileService(anyInt(), any()); + verifyMock(); + } + + @Test + public void unbindBluetoothProfileService() { + // No permission needed for this call + mBinder.unbindBluetoothProfileService(0, null); + verify(mManagerService).unbindBluetoothProfileService(anyInt(), any()); + verifyMock(); + } + + @Test + public void getAddress() { + assertThrows(NullPointerException.class, () -> mBinder.getAddress(null)); + + assertThrows(SecurityException.class, () -> mBinder.getAddress(mSource)); + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(BLUETOOTH_CONNECT); + + // TODO(b/280518177): Throws SecurityException and remove DEFAULT_MAC_ADDRESS + // assertThrows(SecurityException.class, () -> mBinder.getAddress(mSource)); + assertThat(mBinder.getAddress(mSource)).isEqualTo("02:00:00:00:00:00"); + verifyMockForCheckIfCallerIsForegroundUser(); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS); + + // TODO(b/280518177): add more test from not System / ... + // TODO(b/280518177): add more test when caller is not in foreground + + doReturn("foo").when(mManagerService).getAddress(any()); + assertThat(mBinder.getAddress(mSource)).isEqualTo("foo"); + + verify(mManagerService).getAddress(any()); + verifyMockForCheckIfCallerIsForegroundUser(); + } + + @Test + public void getName() { + assertThrows(NullPointerException.class, () -> mBinder.getName(null)); + + assertThrows(SecurityException.class, () -> mBinder.getName(mSource)); + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(BLUETOOTH_CONNECT); + + // TODO(b/280518177): add more test from not System / ... + // TODO(b/280518177): add more test when caller is not in foreground + + doReturn("foo").when(mManagerService).getName(any()); + assertThat(mBinder.getName(mSource)).isEqualTo("foo"); + verify(mManagerService).getName(any()); + verifyMockForCheckIfCallerIsForegroundUser(); + } + + @Test + public void onFactoryReset() { + assertThrows(NullPointerException.class, () -> mBinder.onFactoryReset(null)); + + assertThrows(SecurityException.class, () -> mBinder.onFactoryReset(mSource)); + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(BLUETOOTH_PRIVILEGED); + + assertThrows(SecurityException.class, () -> mBinder.onFactoryReset(mSource)); + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(BLUETOOTH_PRIVILEGED, BLUETOOTH_CONNECT); + + assertThat(mBinder.onFactoryReset(mSource)).isFalse(); + verify(mManagerService).onFactoryReset(any()); + verifyMock(); + } + + @Test + public void isBleScanAlwaysAvailable() { + // No permission needed for this call + mBinder.isBleScanAlwaysAvailable(); + verify(mManagerService).isBleScanAlwaysAvailable(); + verifyMock(); + } + + @Test + public void enableBle() { + IBinder token = mock(IBinder.class); + assertThrows(NullPointerException.class, () -> mBinder.enableBle(null, token)); + assertThrows(NullPointerException.class, () -> mBinder.enableBle(mSource, null)); + + checkDisabled(() -> mBinder.enableBle(mSource, token)); + checkHardDenied(() -> mBinder.enableBle(mSource, token), false); + doReturn(true).when(mManagerService).enableBle(eq(TAG), eq(token)); + checkGranted(() -> mBinder.enableBle(mSource, token), true); + verify(mManagerService).enableBle(eq(TAG), eq(token)); + verifyMock(); + } + + @Test + public void disableBle() { + IBinder token = mock(IBinder.class); + assertThrows(NullPointerException.class, () -> mBinder.disableBle(null, token)); + assertThrows(NullPointerException.class, () -> mBinder.disableBle(mSource, null)); + + checkDisabled(() -> mBinder.disableBle(mSource, token)); + checkHardDenied(() -> mBinder.disableBle(mSource, token), false); + doReturn(true).when(mManagerService).disableBle(eq(mSource), eq(TAG), eq(token)); + checkGranted(() -> mBinder.disableBle(mSource, token), true); + verify(mManagerService).disableBle(eq(mSource), eq(TAG), eq(token)); + verifyMock(); + } + + @Test + public void isBleAppPresent() { + // No permission needed for this call + mBinder.isBleAppPresent(); + verify(mManagerService).isBleAppPresent(); + verifyMock(); + } + + @Test + public void isHearingAidProfileSupported() { + // No permission needed for this call + mBinder.isHearingAidProfileSupported(); + verify(mManagerService).isHearingAidProfileSupported(); + verifyMock(); + } + + @Test + public void setBtHciSnoopLogMode() { + assertThrows(SecurityException.class, () -> mBinder.setBtHciSnoopLogMode(0)); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(BLUETOOTH_PRIVILEGED); + assertThat(mBinder.setBtHciSnoopLogMode(0)).isEqualTo(0); + verify(mManagerService).setBtHciSnoopLogMode(anyInt()); + verifyMock(); + } + + @Test + public void getBtHciSnoopLogMode() { + assertThrows(SecurityException.class, () -> mBinder.getBtHciSnoopLogMode()); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(BLUETOOTH_PRIVILEGED); + assertThat(mBinder.getBtHciSnoopLogMode()).isEqualTo(0); + verify(mManagerService).getBtHciSnoopLogMode(); + verifyMock(); + } + + // TODO(b/280518177): Add test for `handleShellCommand` and `dump` + + // ********************************************************************************************* + // Utility method used in tests + + private void verifyAndClearMock(Object o) { + assertThat(mockingDetails(o).isMock() || mockingDetails(o).isSpy()).isTrue(); + verifyNoMoreInteractions(o); + clearInvocations(o); + } + + private void verifyMock() { + verifyAndClearMock(mManagerService); + verifyAndClearMock(mUserManager); + verifyAndClearMock(mAppOpsManager); + verifyAndClearMock(mDevicePolicyManager); + } + + private void verifyMockForCheckIfCallerIsForegroundUser() { + verify(mUserManager).getProfileParent(any()); + verifyMock(); + } + + private void checkDisabled(BooleanSupplier binderCall) { + doReturn(true) + .when(mUserManager) + .hasUserRestrictionForUser(eq(UserManager.DISALLOW_BLUETOOTH), any()); + + assertThat(binderCall.getAsBoolean()).isFalse(); + + verify(mUserManager).hasUserRestrictionForUser(eq(UserManager.DISALLOW_BLUETOOTH), any()); + verifyMock(); + } + + private void checkHardDenied(ThrowingRunnable binderCall, boolean requireForeground) { + doReturn(false) + .when(mUserManager) + .hasUserRestrictionForUser(eq(UserManager.DISALLOW_BLUETOOTH), any()); + + assertThrows(SecurityException.class, binderCall); + + verify(mUserManager).hasUserRestrictionForUser(eq(UserManager.DISALLOW_BLUETOOTH), any()); + if (requireForeground) { + verify(mUserManager).getProfileParent(any()); + } + verify(mAppOpsManager).checkPackage(anyInt(), eq(TAG)); + verifyMock(); + } + + private void checkGranted(BooleanSupplier binderCall, boolean expectedResult) { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity( + LOG_COMPAT_CHANGE, READ_COMPAT_CHANGE_CONFIG, BLUETOOTH_CONNECT); + + assertThat(binderCall.getAsBoolean()).isEqualTo(expectedResult); + + verify(mUserManager).hasUserRestrictionForUser(eq(UserManager.DISALLOW_BLUETOOTH), any()); + verify(mAppOpsManager).checkPackage(anyInt(), eq(TAG)); + if (!expectedResult) { + verify(mDevicePolicyManager).getDeviceOwnerUser(); + verify(mDevicePolicyManager).getDeviceOwnerComponentOnAnyUser(); + } + } +} diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothShellCommandTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothShellCommandTest.java index db14999e47decacfcfdf6488e6f52d32ed2fb1c5..8f71a563f1b8f237dbea0d1b8fd6dd1d4a8f54fb 100644 --- a/service/tests/src/com/android/server/bluetooth/BluetoothShellCommandTest.java +++ b/service/tests/src/com/android/server/bluetooth/BluetoothShellCommandTest.java @@ -21,10 +21,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; @@ -39,6 +41,7 @@ import com.android.server.bluetooth.BluetoothShellCommand.BluetoothCommand; import com.google.common.truth.Expect; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -57,6 +60,8 @@ public class BluetoothShellCommandTest { @Mock BluetoothManagerService mManagerService; + @Mock BluetoothServiceBinder mBinder; + @Mock Context mContext; @@ -65,12 +70,20 @@ public class BluetoothShellCommandTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + doReturn(mBinder).when(mManagerService).getBinder(); + mShellCommand = new BluetoothShellCommand(mManagerService, mContext); mShellCommand.init( mock(Binder.class), mock(FileDescriptor.class), mock(FileDescriptor.class), mock(FileDescriptor.class), new String[0], -1); } + @After + public void tearDown() { + verifyNoMoreInteractions(mBinder); + // verifyNoMoreInteractions(mManagerService); // TODO(b/280518177): Apply after cleanup + } + @Test public void enableCommand() throws Exception { BluetoothCommand enableCmd = mShellCommand.new Enable(); @@ -79,8 +92,9 @@ public class BluetoothShellCommandTest { assertThat(enableCmd.getName()).isEqualTo(cmdName); assertThat(enableCmd.isMatch(cmdName)).isTrue(); assertThat(enableCmd.isPrivileged()).isFalse(); - when(mManagerService.enable(any())).thenReturn(true); + when(mBinder.enable(any())).thenReturn(true); assertThat(enableCmd.exec(cmdName)).isEqualTo(0); + verify(mBinder).enable(any()); } @Test @@ -91,8 +105,9 @@ public class BluetoothShellCommandTest { assertThat(disableCmd.getName()).isEqualTo(cmdName); assertThat(disableCmd.isMatch(cmdName)).isTrue(); assertThat(disableCmd.isPrivileged()).isFalse(); - when(mManagerService.disable(any(), anyBoolean())).thenReturn(true); + when(mBinder.disable(any(), anyBoolean())).thenReturn(true); assertThat(disableCmd.exec(cmdName)).isEqualTo(0); + verify(mBinder).disable(any(), anyBoolean()); } @Test @@ -147,23 +162,29 @@ public class BluetoothShellCommandTest { mShellCommand.onCommand("enable"); verify(enableCmd).exec(eq("enable")); + verify(mBinder).enable(any()); + } + + static class TestPrivilegedCmd extends BluetoothCommand { + TestPrivilegedCmd() { + super(true, TestPrivilegedCmd.class.getSimpleName()); + } + + @Override + int exec(String cmd) throws RemoteException { + return 0; + } + + @Override + public void onHelp(PrintWriter pw) {} } @Test public void onCommand_withPrivilegedCommandName_throwsSecurityException() { - final String privilegedCommandName = "test_privileged_cmd_name"; - BluetoothCommand privilegedCommand = - mShellCommand.new BluetoothCommand(true, privilegedCommandName) { - @Override - int exec(String cmd) throws RemoteException { - return 0; - } - @Override - public void onHelp(PrintWriter pw) { } - }; - mShellCommand.mBluetoothCommands[0] = privilegedCommand; + mShellCommand.mBluetoothCommands[0] = new TestPrivilegedCmd(); - assertThrows(SecurityException.class, - () -> mShellCommand.onCommand(privilegedCommandName)); + assertThrows( + SecurityException.class, + () -> mShellCommand.onCommand(TestPrivilegedCmd.class.getSimpleName())); } } diff --git a/sysprop/Android.bp b/sysprop/Android.bp index f3842c8c3b7ddeb345d2b4f98f5a3c7aa7bcf076..b399a8d7b86ab4573d362597e2464c922eaa5679 100644 --- a/sysprop/Android.bp +++ b/sysprop/Android.bp @@ -6,10 +6,11 @@ sysprop_library { name: "com.android.sysprop.bluetooth", host_supported: true, srcs: [ + "a2dp.sysprop", "avrcp.sysprop", + "ble.sysprop", "bta.sysprop", "hfp.sysprop", - "pan.sysprop", ], property_owner: "Platform", api_packages: ["android.sysprop"], @@ -18,3 +19,14 @@ sysprop_library { }, apex_available: ["com.android.btservices"], } + +cc_library_static { + name: "libcom.android.sysprop.bluetooth.wrapped", + host_supported: true, + whole_static_libs: ["libcom.android.sysprop.bluetooth"], + export_include_dirs: ["exported_include"], + export_static_lib_headers: ["libcom.android.sysprop.bluetooth"], + visibility: ["//packages/modules/Bluetooth/system:__subpackages__"], + apex_available: ["com.android.btservices"], + min_sdk_version: "Tiramisu", +} diff --git a/sysprop/a2dp.sysprop b/sysprop/a2dp.sysprop new file mode 100644 index 0000000000000000000000000000000000000000..80b359c39099e1a126540b6f0c9c2d29665878e0 --- /dev/null +++ b/sysprop/a2dp.sysprop @@ -0,0 +1,11 @@ +module: "android.sysprop.bluetooth.A2dp" +owner: Platform + +prop { + api_name: "src_sink_coexist" + type: Boolean + scope: Internal + access: Readonly + prop_name: "bluetooth.a2dp.src_sink_coexist.enabled" +} + diff --git a/sysprop/ble.sysprop b/sysprop/ble.sysprop new file mode 100644 index 0000000000000000000000000000000000000000..50723897c6fd16241e35440ee3a35bab940c4bb1 --- /dev/null +++ b/sysprop/ble.sysprop @@ -0,0 +1,10 @@ +module: "android.sysprop.bluetooth.Ble" +owner: Platform + +prop { + api_name: "vnd_included" + type: Boolean + scope: Internal + access: Readonly + prop_name: "bluetooth.ble.vnd.included" +} diff --git a/system/main/shim/activity_attribution.h b/sysprop/exported_include/android_bluetooth_sysprop.h similarity index 60% rename from system/main/shim/activity_attribution.h rename to sysprop/exported_include/android_bluetooth_sysprop.h index 00d809997173a7d62194c6e1b950af27ea1fed8b..3e76262114362637684e54903ad44a734ae2684b 100644 --- a/system/main/shim/activity_attribution.h +++ b/sysprop/exported_include/android_bluetooth_sysprop.h @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,21 @@ * limitations under the License. */ -/** - * Gd shim layer to activity attribution - */ #pragma once -#include "include/hardware/bt_activity_attribution.h" +#ifndef TARGET_FLOSS -using namespace bluetooth::activity_attribution; +#include +#include +#include +#include +#include -namespace bluetooth { -namespace shim { +#define GET_SYSPROP(namespace, prop, default) \ + android::sysprop::bluetooth::namespace ::prop().value_or(default) -ActivityAttributionInterface* get_activity_attribution_instance(); +#else -void init_activity_attribution(); +#define GET_SYSPROP(namespace, prop, default) default -} // namespace shim -} // namespace bluetooth +#endif diff --git a/sysprop/hfp.sysprop b/sysprop/hfp.sysprop index f07124f0eb850adfb5f7212792cd5e4c12c17fb8..4924d299b6780f924d7befe1ca312287f95fba43 100644 --- a/sysprop/hfp.sysprop +++ b/sysprop/hfp.sysprop @@ -33,3 +33,11 @@ prop { prop_name: "bluetooth.hfp.version.config" } +prop { + api_name: "codec_aptx_voice" + type: Boolean + scope: Internal + access: Readonly + prop_name: "bluetooth.hfp.codec_aptx_voice.enabled" +} + diff --git a/sysprop/pan.sysprop b/sysprop/pan.sysprop deleted file mode 100644 index fa64bb3856d0b5adc44e46247305217bba4ac81a..0000000000000000000000000000000000000000 --- a/sysprop/pan.sysprop +++ /dev/null @@ -1,10 +0,0 @@ -module: "android.sysprop.bluetooth.Pan" -owner: Platform - -prop { - api_name: "nap" - type: Boolean - scope: Internal - access: Readonly - prop_name: "bluetooth.pan.nap.enabled" -} diff --git a/system/Android.bp b/system/Android.bp index 481a55a63d50234561984700fede4279a982d676..326e2efad65421894a6f0879f31e619addb377f0 100644 --- a/system/Android.bp +++ b/system/Android.bp @@ -39,9 +39,10 @@ genrule { "aprotoc", "protoc-gen-grpc-cpp-plugin", ], - cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", + cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(locations :BlueberryFacadeProto) --grpc_out=$(genDir) --cpp_out=$(genDir)", srcs: [ ":BlueberryFacadeProto", + ":libprotobuf-internal-protos", ], out: [ "blueberry/facade/common.grpc.pb.h", @@ -85,9 +86,10 @@ genrule { "aprotoc", "protoc-gen-grpc-cpp-plugin", ], - cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", + cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(locations :BlueberryFacadeProto) --grpc_out=$(genDir) --cpp_out=$(genDir)", srcs: [ ":BlueberryFacadeProto", + ":libprotobuf-internal-protos", ], out: [ "blueberry/facade/common.grpc.pb.cc", @@ -133,11 +135,12 @@ genrule { "soong_zip", ], cmd: "mkdir -p $(genDir)/files && " + - "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) $(in) --grpc_out=$(genDir)/files --python_out=$(genDir)/files && " + + "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) $(locations :BlueberryFacadeProto) --grpc_out=$(genDir)/files --python_out=$(genDir)/files && " + "find $(genDir)/files -type d -exec touch {}/__init__.py \\; &&" + "$(location soong_zip) -C $(genDir)/files -D $(genDir)/files -o $(out)", srcs: [ ":BlueberryFacadeProto", + ":libprotobuf-internal-protos", ], out: ["blueberry_facade_generated_py.zip"], } @@ -158,6 +161,7 @@ rust_protobuf { "com.android.btservices", ], min_sdk_version: "30", + use_protobuf3: true, } rust_protobuf { @@ -166,6 +170,7 @@ rust_protobuf { source_stem: "topshim_facade", host_supported: true, grpc_protos: ["blueberry/facade/topshim/facade.proto"], + use_protobuf3: true, } genrule { @@ -175,8 +180,11 @@ genrule { "protoc-gen-grpc-python-plugin", "soong_zip", ], - cmd: "$(location aprotoc) --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) -Iexternal/protobuf/src -Ipackages/modules/Bluetooth/system $(in) --grpc_out=$(genDir) --python_out=$(genDir)", - srcs: ["blueberry/facade/topshim/facade.proto"], + cmd: "$(location aprotoc) --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) -Iexternal/protobuf/src -Ipackages/modules/Bluetooth/system $(location blueberry/facade/topshim/facade.proto) --grpc_out=$(genDir) --python_out=$(genDir)", + srcs: [ + ":libprotobuf-internal-protos", + "blueberry/facade/topshim/facade.proto", + ], out: [ "blueberry/facade/topshim/facade_pb2.py", "blueberry/facade/topshim/facade_pb2_grpc.py", @@ -186,7 +194,6 @@ genrule { // Export system headers for rules that can't simply use `include_dirs` cc_library_headers { name: "libbluetooth_system_headers", - defaults: ["libchrome_support_defaults"], visibility: [ "//packages/modules/Bluetooth/system:__subpackages__", ], diff --git a/system/Android.mk b/system/Android.mk index 7aedfcbfb7e799d2ad9872f786353d2f621575d6..c4d9180da9182ba3541ef24bb8f6867dd21cc7bf 100644 --- a/system/Android.mk +++ b/system/Android.mk @@ -19,13 +19,18 @@ LOCAL_host_executables := \ $(HOST_OUT_EXECUTABLES)/root-canal LOCAL_host_python_hci_packets_library := \ - $(SOONG_OUT_DIR)/.intermediates/packages/modules/Bluetooth/system/gd/gd_hci_packets_python3_gen/gen/hci_packets.py + $(SOONG_OUT_DIR)/.intermediates/packages/modules/Bluetooth/system/pdl/hci/gd_hci_packets_python3_gen/gen/hci_packets.py + +LOCAL_host_python_smp_packets_library := \ + $(SOONG_OUT_DIR)/.intermediates/packages/modules/Bluetooth/system/pdl/security/gd_smp_packets_python3_gen/gen/smp_packets.py LOCAL_host_python_extension_libraries := \ $(HOST_OUT_SHARED_LIBRARIES)/bluetooth_packets_python3.so LOCAL_host_libraries := \ $(HOST_OUT_SHARED_LIBRARIES)/libbase.so \ + $(HOST_OUT_SHARED_LIBRARIES)/libbinder.so \ + $(HOST_OUT_SHARED_LIBRARIES)/libbinder_ndk.so \ $(HOST_OUT_SHARED_LIBRARIES)/libbluetooth.so \ $(HOST_OUT_SHARED_LIBRARIES)/libbluetooth_gd.so \ $(HOST_OUT_SHARED_LIBRARIES)/libc++.so \ @@ -34,7 +39,6 @@ LOCAL_host_libraries := \ $(HOST_OUT_SHARED_LIBRARIES)/libcutils.so \ $(HOST_OUT_SHARED_LIBRARIES)/libevent-host.so \ $(HOST_OUT_SHARED_LIBRARIES)/libflatbuffers-cpp.so \ - $(HOST_OUT_SHARED_LIBRARIES)/libgrpc++_unsecure.so \ $(HOST_OUT_SHARED_LIBRARIES)/libgrpc++.so \ $(HOST_OUT_SHARED_LIBRARIES)/libgrpc_wrap.so \ $(HOST_OUT_SHARED_LIBRARIES)/liblog.so \ @@ -42,7 +46,9 @@ LOCAL_host_libraries := \ $(HOST_OUT_SHARED_LIBRARIES)/libz-host.so \ $(HOST_OUT_SHARED_LIBRARIES)/libprotobuf-cpp-full.so \ $(HOST_OUT_SHARED_LIBRARIES)/libunwindstack.so \ - $(HOST_OUT_SHARED_LIBRARIES)/liblzma.so + $(HOST_OUT_SHARED_LIBRARIES)/libutils.so \ + $(HOST_OUT_SHARED_LIBRARIES)/liblzma.so \ + $(HOST_OUT_SHARED_LIBRARIES)/server_configurable_flags.so LOCAL_target_executables := \ $(TARGET_OUT_EXECUTABLES)/bluetooth_stack_with_facade @@ -58,7 +64,6 @@ LOCAL_target_libraries := \ $(TARGET_OUT_SHARED_LIBRARIES)/libcrypto.so \ $(TARGET_OUT_SHARED_LIBRARIES)/libcutils.so \ $(TARGET_OUT_SHARED_LIBRARIES)/libgrpc_wrap.so \ - $(TARGET_OUT_SHARED_LIBRARIES)/libgrpc++_unsecure.so \ $(TARGET_OUT_SHARED_LIBRARIES)/libgrpc++.so \ $(TARGET_OUT_SHARED_LIBRARIES)/libhidlbase.so \ $(TARGET_OUT_SHARED_LIBRARIES)/liblog.so \ @@ -68,7 +73,8 @@ LOCAL_target_libraries := \ $(TARGET_OUT_SHARED_LIBRARIES)/libstatslog_bt.so \ $(TARGET_OUT_SHARED_LIBRARIES)/libunwindstack.so \ $(TARGET_OUT_SHARED_LIBRARIES)/libutils.so \ - $(TARGET_OUT_SHARED_LIBRARIES)/libz.so + $(TARGET_OUT_SHARED_LIBRARIES)/libz.so \ + $(TARGET_OUT_SHARED_LIBRARIES)/server_configurable_flags.so # libclang_rt.asan-aarch64-android.so is only generated for ASAN build and included automatically # on devices # $(TARGET_OUT_SHARED_LIBRARIES)/libclang_rt.asan-aarch64-android.so \ @@ -94,16 +100,19 @@ $(bluetooth_cert_src_and_bin_zip): PRIVATE_host_executables := $(LOCAL_host_exec $(bluetooth_cert_src_and_bin_zip): PRIVATE_host_libraries := $(LOCAL_host_libraries) $(bluetooth_cert_src_and_bin_zip): PRIVATE_host_python_extension_libraries := $(LOCAL_host_python_extension_libraries) $(bluetooth_cert_src_and_bin_zip): PRIVATE_host_python_hci_packets_library := $(LOCAL_host_python_hci_packets_library) +$(bluetooth_cert_src_and_bin_zip): PRIVATE_host_python_smp_packets_library := $(LOCAL_host_python_smp_packets_library) $(bluetooth_cert_src_and_bin_zip): PRIVATE_target_executables := $(LOCAL_target_executables) $(bluetooth_cert_src_and_bin_zip): PRIVATE_target_libraries := $(LOCAL_target_libraries) $(bluetooth_cert_src_and_bin_zip): $(SOONG_ZIP) $(LOCAL_cert_test_sources) \ $(LOCAL_host_executables) $(LOCAL_host_libraries) $(LOCAL_host_python_libraries) \ $(LOCAL_host_python_extension_libraries) \ $(LOCAL_host_python_hci_packets_library) \ + $(LOCAL_host_python_smp_packets_library) \ $(LOCAL_target_executables) $(LOCAL_target_libraries) $(hide) $(SOONG_ZIP) -d -o $@ \ -C $(PRIVATE_bluetooth_project_dir) $(addprefix -f ,$(PRIVATE_cert_test_sources)) \ -C $(dir $(PRIVATE_host_python_hci_packets_library)) -f $(PRIVATE_host_python_hci_packets_library) \ + -C $(dir $(PRIVATE_host_python_smp_packets_library)) -f $(PRIVATE_host_python_smp_packets_library) \ -C $(HOST_OUT_EXECUTABLES) $(addprefix -f ,$(PRIVATE_host_executables)) \ -C $(HOST_OUT_SHARED_LIBRARIES) $(addprefix -f ,$(PRIVATE_host_python_extension_libraries)) \ -P lib64 \ @@ -145,7 +154,7 @@ $(bluetooth_cert_tests_py_package_zip): $(SOONG_ZIP) \ -f $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION)/bin/llvm-cov \ -f $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION)/bin/llvm-profdata \ -f $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION)/bin/llvm-symbolizer \ - -f $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION)/lib/x86_64-unknown-linux-gnu/libc++.so.1 + -f $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION)/lib/x86_64-unknown-linux-gnu/libc++.so $(call declare-container-license-metadata,$(bluetooth_cert_tests_py_package_zip),\ SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-MIT legacy_unencumbered,\ diff --git a/system/BUILD.gn b/system/BUILD.gn index 9bd951494b8fd55138a4b83419bd78bcf5eb1890..02b92d245b2a8e475f70452f08ec6c79ffd2c252 100644 --- a/system/BUILD.gn +++ b/system/BUILD.gn @@ -75,6 +75,8 @@ if (defined(use.android) && use.android) { config("target_defaults") { include_dirs = [ "//bt/system", + "//bt/flags/exported_include", + "//bt/sysprop/exported_include", "//bt/system/linux_include", "//bt/system/types", "//bt/system/include", @@ -113,15 +115,12 @@ config("target_defaults") { ]), ] - cflags_cc = [ "-std=c++17" ] + cflags_cc = [ "-std=c++20" ] defines = [ "TARGET_FLOSS", "EXPORT_SYMBOL=__attribute__((visibility(\"default\")))", "FALLTHROUGH_INTENDED=[[clang::fallthrough]]", - # BTA_AG_FEAT_ECS (Enhanced Call Status 0x040) | - # BTA_AG_FEAT_CODEC (Codec Negotiation 0x200) - "BTIF_HF_FEATURES=0x00000240", ] if (!(defined(use.bt_nonstandard_codecs) && use.bt_nonstandard_codecs)) { @@ -204,34 +203,6 @@ pkg_config("pkg_tinyxml2") { pkg_deps = [ "tinyxml2" ] } -# To use non-standard codecs (i.e. ldac, aac, aptx), set this use flag when -# building. These codecs may have licensing issues that need to be resolved -# first. -if (defined(use.bt_nonstandard_codecs) && use.bt_nonstandard_codecs) { - config("external_aac") { - configs = [ ":pkg_aac" ] - } - - pkg_config("pkg_aac") { - pkg_deps = [ "fdk-aac" ] - } - - config("external_libldac") { - configs = [ - ":pkg_libldacBT_enc", - ":pkg_libldacBT_abr", - ] - } - - pkg_config("pkg_libldacBT_enc") { - pkg_deps = [ "ldacBT-enc" ] - } - - pkg_config("pkg_libldacBT_abr") { - pkg_deps = [ "ldacBT-abr" ] - } -} - # To include ChroemOS-specific libraries and build dependencies. if (target_os == "chromeos") { config("external_chromeos") { diff --git a/system/OWNERS b/system/OWNERS index 9f56ed3e602384d9c384273473daa47066c8d62e..ca3ea8ae667e6603a7c8c150421153ea31c2165f 100644 --- a/system/OWNERS +++ b/system/OWNERS @@ -1,13 +1,10 @@ # Reviewers for /system -bidsharma@google.com cmanton@google.com -cncn@google.com eruffieux@google.com hallstrom@google.com jpawlowski@google.com mylesgw@google.com -rahulsabnis@google.com -sattiraju@google.com -siyuanh@google.com +rwt@google.com wescande@google.com +yuyangh@google.com \ No newline at end of file diff --git a/system/audio_a2dp_hw/Android.bp b/system/audio_a2dp_hw/Android.bp index 97f86a16392a2dc5af6541bf9c3c4013b6decbf5..d75554928dba47d582be3a0cf12de12ed2037bcf 100644 --- a/system/audio_a2dp_hw/Android.bp +++ b/system/audio_a2dp_hw/Android.bp @@ -9,7 +9,7 @@ package { cc_defaults { name: "audio_a2dp_hw_defaults", - defaults: ["fluoride_common_options"], + defaults: ["bluetooth_cflags"], shared_libs: ["libchrome"], include_dirs: [ "packages/modules/Bluetooth/system", @@ -58,10 +58,9 @@ cc_library_static { // Audio A2DP library unit tests for target and host cc_test { name: "net_test_audio_a2dp_hw", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ "audio_a2dp_hw_defaults", - "bluetooth_gtest_x86_asan_workaround", "mts_defaults", ], srcs: [ diff --git a/system/audio_a2dp_hw/src/audio_a2dp_hw.cc b/system/audio_a2dp_hw/src/audio_a2dp_hw.cc index 2c56fc74f9f62fdda6cc5afd2eeebe694dd4de94..bab0b8ff0cb1d25c3fb7cae0cadc0164be066e2f 100644 --- a/system/audio_a2dp_hw/src/audio_a2dp_hw.cc +++ b/system/audio_a2dp_hw/src/audio_a2dp_hw.cc @@ -26,30 +26,28 @@ #define LOG_TAG "bt_a2dp_hw" -#include +#include "audio_a2dp_hw.h" + #include +#include +#include #include #include #include -#include #include #include #include #include +#include #include +#include #include -#include -#include -#include - #include "osi/include/hash_map_utils.h" #include "osi/include/osi.h" #include "osi/include/socket_utils/sockets.h" -#include "audio_a2dp_hw.h" - /***************************************************************************** * Constants & Macros *****************************************************************************/ diff --git a/system/audio_bluetooth_hw/Android.bp b/system/audio_bluetooth_hw/Android.bp index 5e2e16876bbe36da44284dcf3900805161d31651..01763dc2bdefa06b70255129d826d973e9c57e0e 100644 --- a/system/audio_bluetooth_hw/Android.bp +++ b/system/audio_bluetooth_hw/Android.bp @@ -11,7 +11,7 @@ package { cc_defaults { name: "audio_bluetooth_hw_defaults", - defaults: ["fluoride_common_options"], + defaults: ["bluetooth_cflags"], cflags: [ // suppress the warning in stream_apis.cc "-Wno-sign-compare", @@ -20,7 +20,11 @@ cc_defaults { cc_library_shared { name: "audio.bluetooth.default", - defaults: ["audio_bluetooth_hw_defaults"], + defaults: [ + "audio_bluetooth_hw_defaults", + "latest_android_hardware_audio_common_ndk_shared", + "latest_android_hardware_bluetooth_audio_ndk_shared", + ], relative_install_path: "hw", proprietary: true, srcs: [ @@ -32,7 +36,6 @@ cc_library_shared { ], header_libs: ["libhardware_headers"], shared_libs: [ - "android.hardware.bluetooth.audio-V3-ndk", "libaudioutils", "libbase", "libbinder_ndk", @@ -47,6 +50,7 @@ cc_library_shared { "libbluetooth_audio_session", "libhidlbase", ], + cflags: ["-Wno-unused-parameter"], } cc_test { diff --git a/system/audio_bluetooth_hw/audio_bluetooth_hw.cc b/system/audio_bluetooth_hw/audio_bluetooth_hw.cc index 9280e5ec79b0122b74b54238069fa6260b3f9c93..f85cbb8923d7aee23101ec1c7360c651e262d326 100644 --- a/system/audio_bluetooth_hw/audio_bluetooth_hw.cc +++ b/system/audio_bluetooth_hw/audio_bluetooth_hw.cc @@ -17,7 +17,6 @@ #define LOG_TAG "BTAudioHw" #include -#include #include #include #include @@ -145,6 +144,14 @@ static int adev_release_audio_patch(struct audio_hw_device* device, return 0; } +static int adev_get_audio_port_v7(struct audio_hw_device* device, + struct audio_port_v7* port) { + if (device == nullptr || port == nullptr) { + return -EINVAL; + } + return -ENOSYS; +} + static int adev_get_audio_port(struct audio_hw_device* device, struct audio_port* port) { if (device == nullptr || port == nullptr) { @@ -171,7 +178,7 @@ static int adev_open(const hw_module_t* module, const char* name, if (!adev) return -ENOMEM; adev->common.tag = HARDWARE_DEVICE_TAG; - adev->common.version = AUDIO_DEVICE_API_VERSION_3_0; + adev->common.version = AUDIO_DEVICE_API_VERSION_3_2; adev->common.module = (struct hw_module_t*)module; adev->common.close = adev_close; @@ -194,6 +201,7 @@ static int adev_open(const hw_module_t* module, const char* name, adev->get_master_mute = adev_get_master_mute; adev->create_audio_patch = adev_create_audio_patch; adev->release_audio_patch = adev_release_audio_patch; + adev->get_audio_port_v7 = adev_get_audio_port_v7; adev->get_audio_port = adev_get_audio_port; *device = &adev->common; diff --git a/system/audio_bluetooth_hw/device_port_proxy.cc b/system/audio_bluetooth_hw/device_port_proxy.cc index 8b49c4df255b3e3860cbea5ebd15415a07307c5c..3e361b854278fc5f2a69c227b950d84eae494e40 100644 --- a/system/audio_bluetooth_hw/device_port_proxy.cc +++ b/system/audio_bluetooth_hw/device_port_proxy.cc @@ -34,12 +34,17 @@ namespace bluetooth { namespace audio { namespace aidl { +using ::aidl::android::hardware::audio::common::SinkMetadata; +using ::aidl::android::hardware::audio::common::SourceMetadata; using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration; using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl; using ::aidl::android::hardware::bluetooth::audio::ChannelMode; using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; using ::aidl::android::hardware::bluetooth::audio::PortStatusCallbacks; using ::aidl::android::hardware::bluetooth::audio::PresentationPosition; +using ::aidl::android::media::audio::common::AudioContentType; +using ::aidl::android::media::audio::common::AudioSource; +using ::aidl::android::media::audio::common::AudioUsage; using ::android::base::StringPrintf; using ControlResultCallback = std::function CovertAudioTagFromV7(char* tags_v7) { + std::vector tags; + char tags_copy[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; + strlcpy(tags_copy, tags_v7, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE); + char* tag = strtok(tags_copy, ";"); + + while (tag != NULL) { + tags.push_back(tag); + tag = strtok(NULL, ";"); + } + + return tags; +} + // The maximum time to wait in std::condition_variable::wait_for() constexpr unsigned int kMaxWaitingTimeMs = 4500; @@ -577,7 +596,7 @@ bool BluetoothAudioPortAidl::GetPresentationPosition( } void BluetoothAudioPortAidl::UpdateSourceMetadata( - const source_metadata* source_metadata) const { + const source_metadata_v7* source_metadata) const { if (!in_use()) { LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; return; @@ -586,13 +605,25 @@ void BluetoothAudioPortAidl::UpdateSourceMetadata( << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", " << source_metadata->track_count << " track(s)"; - if (source_metadata->track_count == 0) return; + ssize_t track_count = source_metadata->track_count; + if (track_count == 0) return; + SourceMetadata hal_source_metadata; + hal_source_metadata.tracks.resize(track_count); + for (int i = 0; i < track_count; i++) { + hal_source_metadata.tracks[i].usage = + static_cast(source_metadata->tracks[i].base.usage); + hal_source_metadata.tracks[i].contentType = static_cast( + source_metadata->tracks[i].base.content_type); + hal_source_metadata.tracks[i].tags = + std::move(CovertAudioTagFromV7(source_metadata->tracks[i].tags)); + } + BluetoothAudioSessionControl::UpdateSourceMetadata(session_type_, - *source_metadata); + hal_source_metadata); } void BluetoothAudioPortAidl::UpdateSinkMetadata( - const sink_metadata* sink_metadata) const { + const sink_metadata_v7* sink_metadata) const { if (!in_use()) { LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; return; @@ -601,9 +632,20 @@ void BluetoothAudioPortAidl::UpdateSinkMetadata( << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", " << sink_metadata->track_count << " track(s)"; - if (sink_metadata->track_count == 0) return; + ssize_t track_count = sink_metadata->track_count; + if (track_count == 0) return; + SinkMetadata hal_sink_metadata; + hal_sink_metadata.tracks.resize(track_count); + for (int i = 0; i < track_count; i++) { + hal_sink_metadata.tracks[i].source = + static_cast(sink_metadata->tracks[i].base.source); + hal_sink_metadata.tracks[i].gain = sink_metadata->tracks[i].base.gain; + hal_sink_metadata.tracks[i].tags = + std::move(CovertAudioTagFromV7(sink_metadata->tracks[i].tags)); + } + BluetoothAudioSessionControl::UpdateSinkMetadata(session_type_, - *sink_metadata); + hal_sink_metadata); } BluetoothStreamState BluetoothAudioPortAidl::GetState() const { return state_; } diff --git a/system/audio_bluetooth_hw/device_port_proxy.h b/system/audio_bluetooth_hw/device_port_proxy.h index c2c24ec7bbcf7f9ad1f066fecfdc0552de7e5a06..ff3deddffb7c03ebea7139fe82ecebba95338e62 100644 --- a/system/audio_bluetooth_hw/device_port_proxy.h +++ b/system/audio_bluetooth_hw/device_port_proxy.h @@ -16,6 +16,8 @@ #pragma once +#include +#include #include #include #include @@ -93,12 +95,6 @@ class BluetoothAudioPort { return false; } - /*** - * Called by the Audio framework / HAL when the metadata of the stream's - * source has been changed. - ***/ - virtual void UpdateSourceMetadata(const source_metadata*) const {}; - /*** * Return the current BluetoothStreamState ***/ @@ -148,14 +144,13 @@ class BluetoothAudioPortAidl : public BluetoothAudioPort { bool GetPresentationPosition(uint64_t* delay_ns, uint64_t* byte, timespec* timestamp) const override; - void UpdateSourceMetadata( - const source_metadata* source_metadata) const override; + void UpdateSourceMetadata(const source_metadata_v7* source_metadata) const; /*** * Called by the Audio framework / HAL when the metadata of the stream's * sink has been changed. ***/ - virtual void UpdateSinkMetadata(const sink_metadata* sink_metadata) const; + virtual void UpdateSinkMetadata(const sink_metadata_v7* sink_metadata) const; BluetoothStreamState GetState() const override; diff --git a/system/audio_bluetooth_hw/device_port_proxy_hidl.cc b/system/audio_bluetooth_hw/device_port_proxy_hidl.cc index 0f8aa3ddbe79e122af6acc15e39dbf2efaeaf14e..3aa3a9c89c56a0bac9af191aff0f668ba631dbc5 100644 --- a/system/audio_bluetooth_hw/device_port_proxy_hidl.cc +++ b/system/audio_bluetooth_hw/device_port_proxy_hidl.cc @@ -486,7 +486,7 @@ bool BluetoothAudioPortHidl::GetPresentationPosition( return retval; } -void BluetoothAudioPortHidl::UpdateSourceMetadata( +void BluetoothAudioPortHidl::UpdateTracksMetadata( const source_metadata* source_metadata) const { if (!in_use()) { LOG(ERROR) << __func__ << ": BluetoothAudioPort is not in use"; diff --git a/system/audio_bluetooth_hw/device_port_proxy_hidl.h b/system/audio_bluetooth_hw/device_port_proxy_hidl.h index 4104af8ad942dc33b0908c6cfedb6c3d74aa82ad..5b32889ba470c67ac11bc0e4e6c8b644ea717d36 100644 --- a/system/audio_bluetooth_hw/device_port_proxy_hidl.h +++ b/system/audio_bluetooth_hw/device_port_proxy_hidl.h @@ -55,8 +55,7 @@ class BluetoothAudioPortHidl : public BluetoothAudioPort { bool GetPresentationPosition(uint64_t* delay_ns, uint64_t* bytes, timespec* timestamp) const override; - void UpdateSourceMetadata( - const source_metadata* source_metadata) const override; + void UpdateTracksMetadata(const source_metadata* source_metadata) const; BluetoothStreamState GetState() const override; diff --git a/system/audio_bluetooth_hw/stream_apis.cc b/system/audio_bluetooth_hw/stream_apis.cc index ae0f10e68d51b8ba19c0aedd59dc4cd36c6a8b76..1a108032ce7e37190256605fbaf68543d1163d3b 100644 --- a/system/audio_bluetooth_hw/stream_apis.cc +++ b/system/audio_bluetooth_hw/stream_apis.cc @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -704,17 +703,32 @@ static int out_get_presentation_position(const struct audio_stream_out* stream, return 0; } -static void out_update_source_metadata( +static void out_update_source_metadata_v7( struct audio_stream_out* stream, - const struct source_metadata* source_metadata) { + const struct source_metadata_v7* source_metadata_v7) { auto* out = reinterpret_cast(stream); std::unique_lock lock(out->mutex_); - if (source_metadata == nullptr || source_metadata->track_count == 0) { + if (source_metadata_v7 == nullptr || source_metadata_v7->track_count == 0) { return; } LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_->GetState() - << ", " << source_metadata->track_count << " track(s)"; - out->bluetooth_output_->UpdateSourceMetadata(source_metadata); + << ", " << source_metadata_v7->track_count << " track(s)"; + if (!out->is_aidl) { + struct source_metadata source_metadata; + source_metadata.track_count = source_metadata_v7->track_count; + struct playback_track_metadata playback_track; + playback_track_metadata_from_v7(&playback_track, + source_metadata_v7->tracks); + source_metadata.tracks = &playback_track; + + static_cast<::android::bluetooth::audio::hidl::BluetoothAudioPortHidl*>( + out->bluetooth_output_.get()) + ->UpdateTracksMetadata(&source_metadata); + } else { + static_cast<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl*>( + out->bluetooth_output_.get()) + ->UpdateSourceMetadata(source_metadata_v7); + } } int adev_open_output_stream(struct audio_hw_device* dev, @@ -762,7 +776,7 @@ int adev_open_output_stream(struct audio_hw_device* dev, out->stream_out_.pause = out_pause; out->stream_out_.resume = out_resume; out->stream_out_.get_presentation_position = out_get_presentation_position; - out->stream_out_.update_source_metadata = out_update_source_metadata; + out->stream_out_.update_source_metadata_v7 = out_update_source_metadata_v7; /** Fix Coverity Scan Issue @{ */ out->channel_mask_ = AUDIO_CHANNEL_NONE; /** @} */ @@ -1207,8 +1221,9 @@ static int in_set_microphone_field_dimension( return -ENOSYS; } -static void in_update_sink_metadata(struct audio_stream_in* stream, - const struct sink_metadata* sink_metadata) { +static void in_update_sink_metadata_v7( + struct audio_stream_in* stream, + const struct sink_metadata_v7* sink_metadata) { LOG(INFO) << __func__; if (sink_metadata == nullptr || sink_metadata->track_count == 0) { return; @@ -1279,7 +1294,7 @@ int adev_open_input_stream(struct audio_hw_device* dev, in->stream_in_.set_microphone_direction = in_set_microphone_direction; in->stream_in_.set_microphone_field_dimension = in_set_microphone_field_dimension; - in->stream_in_.update_sink_metadata = in_update_sink_metadata; + in->stream_in_.update_sink_metadata_v7 = in_update_sink_metadata_v7; if (!in->bluetooth_input_->LoadAudioConfig(config)) { LOG(ERROR) << __func__ << ": state=" << in->bluetooth_input_->GetState() diff --git a/system/audio_hal_interface/Android.bp b/system/audio_hal_interface/Android.bp index 994db05fd69076ad22ba14e8e65d468ca6873ac5..b25a88c6c7f21ecfc3089d087a3b728210e166a8 100644 --- a/system/audio_hal_interface/Android.bp +++ b/system/audio_hal_interface/Android.bp @@ -17,22 +17,23 @@ cc_library_static { "packages/modules/Bluetooth/system/bta/sys", "packages/modules/Bluetooth/system/btif/include", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/stack/include", ], shared_libs: [ "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", "libhidlbase", + "libutils", ], static_libs: [ "libbt-common", + "libbt_shim_bridge", "libosi", ], target: { android: { shared_libs: [ - "android.hardware.bluetooth.audio-V3-ndk", + "android.hardware.bluetooth.audio-V4-ndk", "libbinder_ndk", "libfmq", ], @@ -43,9 +44,11 @@ cc_library_static { "aidl/client_interface_aidl.cc", "aidl/codec_status_aidl.cc", "aidl/hearing_aid_software_encoding_aidl.cc", + "aidl/hfp_client_interface_aidl.cc", "aidl/le_audio_software_aidl.cc", "hal_version_manager.cc", "hearing_aid_software_encoding.cc", + "hfp_client_interface.cc", "hidl/a2dp_encoding_hidl.cc", "hidl/client_interface_hidl.cc", "hidl/codec_status_hidl.cc", @@ -66,17 +69,22 @@ cc_library_static { host_supported: true, cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], apex_available: [ "com.android.btservices", ], min_sdk_version: "Tiramisu", + header_libs: ["libbluetooth_headers"], } // Bluetooth Audio client interface library unit tests for target and host cc_test { name: "bluetooth-test-audio-hal-interface", - defaults: ["fluoride_defaults"], + defaults: [ + "fluoride_defaults", + "latest_android_hardware_bluetooth_audio_ndk_shared", + ], include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/gd", @@ -86,7 +94,6 @@ cc_test { "hidl/client_interface_hidl_unittest.cc", ], shared_libs: [ - "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", "libbinder_ndk", @@ -99,9 +106,11 @@ cc_test { static_libs: [ "libbt-audio-hal-interface", "libbt-common", + "libbt_shim_bridge", "libchrome", ], cflags: [ "-DBUILDCFG", ], + header_libs: ["libbluetooth_headers"], } diff --git a/system/audio_hal_interface/BUILD.gn b/system/audio_hal_interface/BUILD.gn index 73d0b0cdd11501916e38eba752a130cff43a62b0..7c250ab864a2fe4d2782915f4409aa22c69949ad 100644 --- a/system/audio_hal_interface/BUILD.gn +++ b/system/audio_hal_interface/BUILD.gn @@ -18,6 +18,7 @@ static_library("audio_hal_interface") { sources = [ "a2dp_encoding_host.cc", "hearing_aid_software_encoding_host.cc", + "le_audio_software_host.cc", ] include_dirs = [ diff --git a/system/audio_hal_interface/a2dp_encoding_host.cc b/system/audio_hal_interface/a2dp_encoding_host.cc index 85d92490eec5c5137563785d882930174425e5f5..fcf8dc780f4fb75e4db79d177c7d23b3835dcefc 100644 --- a/system/audio_hal_interface/a2dp_encoding_host.cc +++ b/system/audio_hal_interface/a2dp_encoding_host.cc @@ -16,20 +16,17 @@ #include "a2dp_encoding_host.h" -#include #include #include #include #include "a2dp_encoding.h" -#include "a2dp_sbc_constants.h" #include "btif_a2dp_source.h" #include "btif_av.h" -#include "btif_av_co.h" #include "btif_hf.h" -#include "osi/include/log.h" -#include "osi/include/properties.h" +#include "os/log.h" +#include "stack/include/avdt_api.h" #include "types/raw_address.h" #include "udrv/include/uipc.h" @@ -44,8 +41,8 @@ std::unique_ptr a2dp_uipc = nullptr; static void btif_a2dp_data_cb([[maybe_unused]] tUIPC_CH_ID ch_id, tUIPC_EVENT event) { - APPL_TRACE_WARNING("%s: BTIF MEDIA (A2DP-DATA) EVENT %s", __func__, - dump_uipc_event(event)); + LOG_WARN("%s: BTIF MEDIA (A2DP-DATA) EVENT %s", __func__, + dump_uipc_event(event)); switch (event) { case UIPC_OPEN_EVT: @@ -69,8 +66,7 @@ static void btif_a2dp_data_cb([[maybe_unused]] tUIPC_CH_ID ch_id, break; default: - APPL_TRACE_ERROR("%s: ### A2DP-DATA EVENT %d NOT HANDLED ###", __func__, - event); + LOG_ERROR("%s: ### A2DP-DATA EVENT %d NOT HANDLED ###", __func__, event); break; } } @@ -231,6 +227,7 @@ void cleanup() { if (a2dp_uipc != nullptr) { UIPC_Close(*a2dp_uipc, UIPC_CH_ID_ALL); + a2dp_uipc = nullptr; } } diff --git a/system/audio_hal_interface/aidl/a2dp_encoding_aidl.cc b/system/audio_hal_interface/aidl/a2dp_encoding_aidl.cc index 4f70ebd12b76d8e294f7fcac34d0214cb0b6b744..1300ac1c99b038887c46b4efd5987c7978587066 100644 --- a/system/audio_hal_interface/aidl/a2dp_encoding_aidl.cc +++ b/system/audio_hal_interface/aidl/a2dp_encoding_aidl.cc @@ -140,7 +140,8 @@ void A2dpTransport::StopRequest() { btif_av_stream_stop(RawAddress::kEmpty); } -void A2dpTransport::SetLowLatency(bool is_low_latency) { +void A2dpTransport::SetLatencyMode(LatencyMode latency_mode) { + bool is_low_latency = latency_mode == LatencyMode::LOW_LATENCY ? true : false; btif_av_set_low_latency(is_low_latency); } @@ -158,20 +159,20 @@ bool A2dpTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns, } void A2dpTransport::SourceMetadataChanged( - const source_metadata_t& source_metadata) { + const source_metadata_v7_t& source_metadata) { auto track_count = source_metadata.track_count; auto tracks = source_metadata.tracks; VLOG(1) << __func__ << ": " << track_count << " track(s) received"; while (track_count) { - VLOG(2) << __func__ << ": usage=" << tracks->usage - << ", content_type=" << tracks->content_type - << ", gain=" << tracks->gain; + VLOG(2) << __func__ << ": usage=" << tracks->base.usage + << ", content_type=" << tracks->base.content_type + << ", gain=" << tracks->base.gain; --track_count; ++tracks; } } -void A2dpTransport::SinkMetadataChanged(const sink_metadata_t&) {} +void A2dpTransport::SinkMetadataChanged(const sink_metadata_v7_t&) {} tA2DP_CTRL_CMD A2dpTransport::GetPendingCmd() const { return a2dp_pending_cmd_; @@ -485,7 +486,11 @@ void start_session() { LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled"; return; } - active_hal_interface->SetLowLatencyModeAllowed(is_low_latency_mode_allowed); + std::vector latency_modes = {LatencyMode::FREE}; + if (is_low_latency_mode_allowed) { + latency_modes.push_back(LatencyMode::LOW_LATENCY); + } + active_hal_interface->SetAllowedLatencyModes(latency_modes); active_hal_interface->StartSession(); } @@ -575,7 +580,11 @@ void set_low_latency_mode_allowed(bool allowed) { LOG(ERROR) << __func__ << ": BluetoothAudio HAL is not enabled"; return; } - active_hal_interface->SetLowLatencyModeAllowed(allowed); + std::vector latency_modes = {LatencyMode::FREE}; + if (is_low_latency_mode_allowed) { + latency_modes.push_back(LatencyMode::LOW_LATENCY); + } + active_hal_interface->SetAllowedLatencyModes(latency_modes); } } // namespace a2dp diff --git a/system/audio_hal_interface/aidl/a2dp_transport.h b/system/audio_hal_interface/aidl/a2dp_transport.h index 1b53da0c419793e3caf23ae728b3d613c8d4d52c..7d840103aa4d179cd8515542718fc70a457f740b 100644 --- a/system/audio_hal_interface/aidl/a2dp_transport.h +++ b/system/audio_hal_interface/aidl/a2dp_transport.h @@ -25,6 +25,8 @@ namespace a2dp { namespace { +using ::bluetooth::audio::aidl::LatencyMode; + BluetoothAudioCtrlAck a2dp_ack_to_bt_audio_ctrl_ack(tA2DP_CTRL_ACK ack); // Provide call-in APIs for the Bluetooth Audio HAL @@ -39,15 +41,15 @@ class A2dpTransport void StopRequest() override; - void SetLowLatency(bool is_low_latency) override; + void SetLatencyMode(LatencyMode latency_mode) override; bool GetPresentationPosition(uint64_t* remote_delay_report_ns, uint64_t* total_bytes_read, timespec* data_position) override; - void SourceMetadataChanged(const source_metadata_t& source_metadata); + void SourceMetadataChanged(const source_metadata_v7_t& source_metadata); - void SinkMetadataChanged(const sink_metadata_t&) override; + void SinkMetadataChanged(const sink_metadata_v7_t&) override; tA2DP_CTRL_CMD GetPendingCmd() const; diff --git a/system/audio_hal_interface/aidl/bluetooth_audio_port_impl.cc b/system/audio_hal_interface/aidl/bluetooth_audio_port_impl.cc index 813648acb5acc173233ba9ee5089f2a6d324fa85..2250b76184fe3c884392b1d71b1b3f989ff03b50 100644 --- a/system/audio_hal_interface/aidl/bluetooth_audio_port_impl.cc +++ b/system/audio_hal_interface/aidl/bluetooth_audio_port_impl.cc @@ -97,19 +97,58 @@ ndk::ScopedAStatus BluetoothAudioPortImpl::getPresentationPosition( ndk::ScopedAStatus BluetoothAudioPortImpl::updateSourceMetadata( const SourceMetadata& source_metadata) { StopWatchLegacy stop_watch(__func__); - LOG(INFO) << __func__ << ": " << source_metadata.tracks.size() << "track(s)"; - - std::vector metadata_vec; - metadata_vec.reserve(source_metadata.tracks.size()); - for (const auto& metadata : source_metadata.tracks) { - metadata_vec.push_back({ - .usage = static_cast(metadata.usage), - .content_type = static_cast(metadata.contentType), - .gain = metadata.gain, - }); + LOG(INFO) << __func__ << ": " << source_metadata.tracks.size() << " track(s)"; + + std::vector tracks_vec; + tracks_vec.reserve(source_metadata.tracks.size()); + for (const auto& track : source_metadata.tracks) { + auto num_of_tags = track.tags.size(); + LOG(INFO) << __func__ << " metadata tags size: " << num_of_tags; + + playback_track_metadata_v7 desc_track = { + .base = {.usage = static_cast(track.usage), + .content_type = + static_cast(track.contentType), + .gain = track.gain}, + }; + + if (num_of_tags != 0) { + int copied_size = 0; + int max_tags_size = sizeof(desc_track.tags); + std::string separator(1, AUDIO_ATTRIBUTES_TAGS_SEPARATOR); + for (size_t i = 0; i < num_of_tags - 1; i++) { + int string_len = track.tags[i].length(); + + if ((copied_size >= max_tags_size) || + (copied_size + string_len >= max_tags_size)) { + LOG(ERROR) << __func__ + << "Too many tags, copied size: " << copied_size; + break; + } + + track.tags[i].copy(desc_track.tags + copied_size, string_len, 0); + copied_size += string_len; + separator.copy(desc_track.tags + copied_size, 1, 0); + copied_size += 1; + } + + int string_len = track.tags[num_of_tags - 1].length(); + if ((copied_size >= max_tags_size) || + (copied_size + string_len >= max_tags_size)) { + LOG(ERROR) << __func__ << "Too many tags, copied size: " << copied_size; + } else { + track.tags[num_of_tags - 1].copy(desc_track.tags + copied_size, + string_len, 0); + } + } else { + memset(desc_track.tags, 0, sizeof(desc_track.tags)); + } + + tracks_vec.push_back(desc_track); } - const source_metadata_t legacy_source_metadata = { - .track_count = metadata_vec.size(), .tracks = metadata_vec.data()}; + + const source_metadata_v7_t legacy_source_metadata = { + .track_count = tracks_vec.size(), .tracks = tracks_vec.data()}; transport_instance_->SourceMetadataChanged(legacy_source_metadata); return ndk::ScopedAStatus::ok(); } @@ -119,16 +158,57 @@ ndk::ScopedAStatus BluetoothAudioPortImpl::updateSinkMetadata( StopWatchLegacy stop_watch(__func__); LOG(INFO) << __func__ << ": " << sink_metadata.tracks.size() << " track(s)"; - std::vector metadata_vec; - metadata_vec.reserve(sink_metadata.tracks.size()); - for (const auto& metadata : sink_metadata.tracks) { - metadata_vec.push_back({ - .source = static_cast(metadata.source), - .gain = metadata.gain, - }); + std::vector tracks_vec; + tracks_vec.reserve(sink_metadata.tracks.size()); + for (const auto& track : sink_metadata.tracks) { + auto num_of_tags = track.tags.size(); + LOG(INFO) << __func__ << " metadata tags size: " << num_of_tags; + + record_track_metadata_v7 desc_track = { + .base = + { + .source = static_cast(track.source), + .gain = track.gain, + }, + }; + + if (num_of_tags != 0) { + int copied_size = 0; + int max_tags_size = sizeof(desc_track.tags); + std::string separator(1, AUDIO_ATTRIBUTES_TAGS_SEPARATOR); + for (size_t i = 0; i < num_of_tags - 1; i++) { + int string_len = track.tags[i].length(); + + if ((copied_size >= max_tags_size) || + (copied_size + string_len >= max_tags_size)) { + LOG(ERROR) << __func__ + << "Too many tags, copied size: " << copied_size; + break; + } + + track.tags[i].copy(desc_track.tags + copied_size, string_len, 0); + copied_size += string_len; + separator.copy(desc_track.tags + copied_size, 1, 0); + copied_size += 1; + } + + int string_len = track.tags[num_of_tags - 1].length(); + if ((copied_size >= max_tags_size) || + (copied_size + string_len >= max_tags_size)) { + LOG(ERROR) << __func__ << "Too many tags, copied size: " << copied_size; + } else { + track.tags[num_of_tags - 1].copy(desc_track.tags + copied_size, + string_len, 0); + } + } else { + memset(desc_track.tags, 0, sizeof(desc_track.tags)); + } + + tracks_vec.push_back(desc_track); } - const sink_metadata_t legacy_sink_metadata = { - .track_count = metadata_vec.size(), .tracks = metadata_vec.data()}; + + const sink_metadata_v7_t legacy_sink_metadata = { + .track_count = tracks_vec.size(), .tracks = tracks_vec.data()}; transport_instance_->SinkMetadataChanged(legacy_sink_metadata); return ndk::ScopedAStatus::ok(); } @@ -137,7 +217,7 @@ ndk::ScopedAStatus BluetoothAudioPortImpl::setLatencyMode( LatencyMode latency_mode) { bool is_low_latency = latency_mode == LatencyMode::LOW_LATENCY ? true : false; invoke_switch_buffer_size_cb(is_low_latency); - transport_instance_->SetLowLatency(is_low_latency); + transport_instance_->SetLatencyMode(latency_mode); return ndk::ScopedAStatus::ok(); } diff --git a/system/audio_hal_interface/aidl/client_interface_aidl.cc b/system/audio_hal_interface/aidl/client_interface_aidl.cc index 897b891aa77de6418e9bc30aad036c7c2559c8f5..9faa725022661e6eba95c73fb71de39d6823a7eb 100644 --- a/system/audio_hal_interface/aidl/client_interface_aidl.cc +++ b/system/audio_hal_interface/aidl/client_interface_aidl.cc @@ -19,6 +19,7 @@ #include "client_interface_aidl.h" #include +#include namespace bluetooth { namespace audio { @@ -49,7 +50,8 @@ BluetoothAudioClientInterface::BluetoothAudioClientInterface( provider_factory_(nullptr), session_started_(false), data_mq_(nullptr), - transport_(instance) { + transport_(instance), + latency_modes_({LatencyMode::FREE}) { death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient( AIBinder_DeathRecipient_new(binderDiedCallbackAidl)); } @@ -134,7 +136,7 @@ void BluetoothAudioClientInterface::FetchAudioProvider() { CHECK(provider_ != nullptr); binder_status_t binder_status = AIBinder_linkToDeath( - provider_factory->asBinder().get(), death_recipient_.get(), this); + provider_factory->asBinder().get(), death_recipient_.get(), this); if (binder_status != STATUS_OK) { LOG(ERROR) << "Failed to linkToDeath " << static_cast(binder_status); } @@ -154,8 +156,8 @@ BluetoothAudioSinkClientInterface::BluetoothAudioSinkClientInterface( BluetoothAudioSinkClientInterface::~BluetoothAudioSinkClientInterface() { if (provider_factory_ != nullptr) { - AIBinder_unlinkToDeath(provider_factory_->asBinder().get(), death_recipient_.get(), - nullptr); + AIBinder_unlinkToDeath(provider_factory_->asBinder().get(), + death_recipient_.get(), nullptr); } } @@ -168,8 +170,8 @@ BluetoothAudioSourceClientInterface::BluetoothAudioSourceClientInterface( BluetoothAudioSourceClientInterface::~BluetoothAudioSourceClientInterface() { if (provider_factory_ != nullptr) { - AIBinder_unlinkToDeath(provider_factory_->asBinder().get(), death_recipient_.get(), - nullptr); + AIBinder_unlinkToDeath(provider_factory_->asBinder().get(), + death_recipient_.get(), nullptr); } } @@ -195,7 +197,12 @@ bool BluetoothAudioClientInterface::UpdateAudioConfig( transport_->GetSessionType() == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH || transport_->GetSessionType() == - SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH); + SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH || + (IS_FLAG_ENABLED(is_sco_managed_by_audio) && + (transport_->GetSessionType() == + SessionType::HFP_SOFTWARE_ENCODING_DATAPATH || + transport_->GetSessionType() == + SessionType::HFP_SOFTWARE_DECODING_DATAPATH))); bool is_a2dp_offload_session = (transport_->GetSessionType() == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH); @@ -220,9 +227,15 @@ bool BluetoothAudioClientInterface::UpdateAudioConfig( bool is_leaudio_broadcast_offload_audio_config = (is_leaudio_broadcast_offload_session && audio_config_tag == AudioConfiguration::leAudioBroadcastConfig); + bool is_hfp_offload_audio_config = + (IS_FLAG_ENABLED(is_sco_managed_by_audio) && + transport_->GetSessionType() == + SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH && + audio_config_tag == AudioConfiguration::hfpConfig); if (!is_software_audio_config && !is_a2dp_offload_audio_config && !is_leaudio_unicast_offload_audio_config && - !is_leaudio_broadcast_offload_audio_config) { + !is_leaudio_broadcast_offload_audio_config && + !is_hfp_offload_audio_config) { return false; } transport_->UpdateAudioConfiguration(audio_config); @@ -241,46 +254,34 @@ bool BluetoothAudioClientInterface::UpdateAudioConfig( return true; } -bool BluetoothAudioClientInterface::SetLowLatencyModeAllowed(bool allowed) { - is_low_latency_allowed_ = allowed; +bool BluetoothAudioClientInterface::SetAllowedLatencyModes( + std::vector latency_modes) { if (provider_ == nullptr) { LOG(INFO) << __func__ << ": BluetoothAudioHal nullptr"; return false; } - auto aidl_retval = provider_->setLowLatencyModeAllowed(allowed); - if (!aidl_retval.isOk()) { - LOG(WARNING) << __func__ << ": BluetoothAudioHal is not ready: " - << aidl_retval.getDescription() - << ". is_low_latency_allowed_ is saved " - <<"and it will be sent to BluetoothAudioHal at StartSession."; - } - return true; -} - -int BluetoothAudioClientInterface::GetAidlInterfaceVersion() { - int aidl_version = -1; - if (!is_aidl_available()) { - return aidl_version; - } - - auto provider_factory = IBluetoothAudioProviderFactory::fromBinder( - ::ndk::SpAIBinder(AServiceManager_waitForService( - kDefaultAudioProviderFactoryInterface.c_str()))); + /* Ensure that FREE is always included and remove duplicates if any */ + std::set temp_set(latency_modes.begin(), latency_modes.end()); + temp_set.insert(LatencyMode::FREE); + latency_modes_.clear(); + latency_modes_.assign(temp_set.begin(), temp_set.end()); - if (provider_factory == nullptr) { - LOG(ERROR) << __func__ << ", can't get aidl version from unknown factory"; - return aidl_version; + for (auto latency_mode : latency_modes) { + LOG(INFO) << "Latency mode allowed: " + << ::aidl::android::hardware::bluetooth::audio::toString( + latency_mode); } - auto aidl_retval = provider_factory->getInterfaceVersion(&aidl_version); + /* Low latency mode is used if modes other than FREE are present */ + bool allowed = (latency_modes_.size() > 1); + auto aidl_retval = provider_->setLowLatencyModeAllowed(allowed); if (!aidl_retval.isOk()) { - LOG(FATAL) << __func__ - << ": BluetoothAudioHal::getInterfaceVersion failure: " - << aidl_retval.getDescription(); + LOG(WARNING) << __func__ << ": BluetoothAudioHal is not ready: " + << aidl_retval.getDescription() << ". latency_modes_ is saved " + << "and it will be sent to BluetoothAudioHal at StartSession."; } - - return aidl_version; + return true; } int BluetoothAudioClientInterface::StartSession() { @@ -300,12 +301,9 @@ int BluetoothAudioClientInterface::StartSession() { std::unique_ptr data_mq; DataMQDesc mq_desc; - std::vector latency_modes = {LatencyMode::FREE}; - if (is_low_latency_allowed_) { - latency_modes.push_back(LatencyMode::LOW_LATENCY); - } + auto aidl_retval = provider_->startSession( - stack_if, transport_->GetAudioConfiguration(), latency_modes, &mq_desc); + stack_if, transport_->GetAudioConfiguration(), latency_modes_, &mq_desc); if (!aidl_retval.isOk()) { if (aidl_retval.getExceptionCode() == EX_ILLEGAL_ARGUMENT) { LOG(ERROR) << __func__ << ": BluetoothAudioHal Error: " @@ -329,7 +327,10 @@ int BluetoothAudioClientInterface::StartSession() { SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || transport_->GetSessionType() == SessionType:: - LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { + LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + (IS_FLAG_ENABLED(is_sco_managed_by_audio) && + transport_->GetSessionType() == + SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH)) { transport_->ResetPresentationPosition(); session_started_ = true; return 0; @@ -420,7 +421,10 @@ void BluetoothAudioClientInterface::FlushAudioData() { transport_->GetSessionType() == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH || transport_->GetSessionType() == - SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { + SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + (IS_FLAG_ENABLED(is_sco_managed_by_audio) && + transport_->GetSessionType() == + SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH)) { return; } @@ -556,6 +560,132 @@ size_t BluetoothAudioSourceClientInterface::WriteAudioData(const uint8_t* p_buf, return total_written; } +std::optional +BluetoothAudioClientInterface::GetProviderInfo(SessionType session_type) { + if (provider_factory_ == nullptr) { + LOG(WARNING) << __func__ << ": No provider factory"; + return std::nullopt; + } + std::optional provider_info; + auto aidl_retval = + provider_factory_->getProviderInfo(session_type, &provider_info); + if (!aidl_retval.isOk()) { + LOG(FATAL) << __func__ << ": BluetoothAudioHal::getProviderInfo failure: " + << aidl_retval.getDescription(); + } + return provider_info; +} + +void BluetoothAudioClientInterface::SetCodecPriority(CodecId codec_id, + int32_t priority) { + CHECK(provider_ != nullptr); + auto aidl_retval = provider_->setCodecPriority(codec_id, priority); + if (!aidl_retval.isOk()) { + LOG(FATAL) << __func__ << ": BluetoothAudioHal::setCodecPriority failure: " + << aidl_retval.getDescription(); + } +} + +std::vector +BluetoothAudioClientInterface::GetLeAudioAseConfiguration( + std::optional>>& + remoteSinkAudioCapabilities, + std::optional>>& + remoteSourceAudioCapabilities, + std::vector& + requirements) { + CHECK(provider_ != nullptr); + + std::vector + configurations; + auto aidl_retval = provider_->getLeAudioAseConfiguration( + remoteSinkAudioCapabilities, remoteSourceAudioCapabilities, requirements, + &configurations); + + if (!aidl_retval.isOk()) { + LOG(FATAL) << __func__ + << ": BluetoothAudioHal::getLeAudioAseConfiguration failure: " + << aidl_retval.getDescription(); + } + + LOG(INFO) << __func__ + << ": BluetoothAudioHal::getLeAudioAseConfiguration returned " + << configurations.size() << " configurations."; + return configurations; +} + +IBluetoothAudioProvider::LeAudioAseQosConfigurationPair +BluetoothAudioClientInterface::getLeAudioAseQosConfiguration( + IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement& + qosRequirement) { + CHECK(provider_ != nullptr); + + IBluetoothAudioProvider::LeAudioAseQosConfigurationPair qos_configuration; + auto aidl_retval = provider_->getLeAudioAseQosConfiguration( + qosRequirement, &qos_configuration); + + if (!aidl_retval.isOk()) { + LOG(FATAL) << __func__ + << ": BluetoothAudioHal::getLeAudioAseQosConfiguration failure: " + << aidl_retval.getDescription(); + } + return qos_configuration; +} + +void BluetoothAudioClientInterface::onSinkAseMetadataChanged( + IBluetoothAudioProvider::AseState state, int32_t cigId, int32_t cisId, + std::optional>>& metadata) { + CHECK(provider_ != nullptr); + + auto aidl_retval = + provider_->onSinkAseMetadataChanged(state, cigId, cisId, metadata); + + if (!aidl_retval.isOk()) { + LOG(FATAL) << __func__ + << ": BluetoothAudioHal::onSinkAseMetadataChanged failure: " + << aidl_retval.getDescription(); + } +} + +void BluetoothAudioClientInterface::onSourceAseMetadataChanged( + IBluetoothAudioProvider::AseState state, int32_t cigId, int32_t cisId, + std::optional>>& metadata) { + CHECK(provider_ != nullptr); + + auto aidl_retval = + provider_->onSourceAseMetadataChanged(state, cigId, cisId, metadata); + + if (!aidl_retval.isOk()) { + LOG(FATAL) << __func__ + << ": BluetoothAudioHal::onSinkAseMetadataChanged failure: " + << aidl_retval.getDescription(); + } +} + +IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting +BluetoothAudioClientInterface::getLeAudioBroadcastConfiguration( + const std::optional>>& + remoteSinkAudioCapabilities, + const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement& + requirement) { + CHECK(provider_ != nullptr); + + IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting setting; + auto aidl_retval = provider_->getLeAudioBroadcastConfiguration( + remoteSinkAudioCapabilities, requirement, &setting); + + if (!aidl_retval.isOk()) { + LOG(FATAL) << __func__ + << ": BluetoothAudioHal::onSinkAseMetadataChanged failure: " + << aidl_retval.getDescription(); + } + + return setting; +} + } // namespace aidl } // namespace audio } // namespace bluetooth diff --git a/system/audio_hal_interface/aidl/client_interface_aidl.h b/system/audio_hal_interface/aidl/client_interface_aidl.h index 8a40c1d7d753768b70a301f4d0052fe4824623fd..0dd9575acba81f8330b7e685d251bee223729cb7 100644 --- a/system/audio_hal_interface/aidl/client_interface_aidl.h +++ b/system/audio_hal_interface/aidl/client_interface_aidl.h @@ -39,11 +39,17 @@ namespace aidl { using ::aidl::android::hardware::bluetooth::audio::AudioCapabilities; using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration; using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus; +using ::aidl::android::hardware::bluetooth::audio::CodecId; +using ::aidl::android::hardware::bluetooth::audio::CodecInfo; +using ::aidl::android::hardware::bluetooth::audio::CodecSpecificCapabilitiesLtv; +using ::aidl::android::hardware::bluetooth::audio:: + CodecSpecificConfigurationLtv; using ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort; using ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider; using ::aidl::android::hardware::bluetooth::audio:: IBluetoothAudioProviderFactory; using ::aidl::android::hardware::bluetooth::audio::LatencyMode; +using ::aidl::android::hardware::bluetooth::audio::MetadataLtv; using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; using ::aidl::android::hardware::common::fmq::MQDescriptor; @@ -85,16 +91,51 @@ class BluetoothAudioClientInterface { bool UpdateAudioConfig(const AudioConfiguration& audioConfig); - bool SetLowLatencyModeAllowed(bool allowed); + bool SetAllowedLatencyModes(std::vector latency_modes); void FlushAudioData(); + std::optional GetProviderInfo( + SessionType session_type); + + void SetCodecPriority(CodecId codec_id, int32_t priority); + + std::vector + GetLeAudioAseConfiguration( + std::optional>>& + remoteSinkAudioCapabilities, + std::optional>>& + remoteSourceAudioCapabilities, + std::vector& + requirements); + + IBluetoothAudioProvider::LeAudioAseQosConfigurationPair + getLeAudioAseQosConfiguration( + IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement& + qosRequirement); + + void onSinkAseMetadataChanged( + IBluetoothAudioProvider::AseState state, int32_t cigId, int32_t cisId, + std::optional>>& metadata); + + void onSourceAseMetadataChanged( + IBluetoothAudioProvider::AseState state, int32_t cigId, int32_t cisId, + std::optional>>& metadata); + + IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting + getLeAudioBroadcastConfiguration( + const std::optional>>& + remoteSinkAudioCapabilities, + const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement& + requirement); + static constexpr PcmConfiguration kInvalidPcmConfiguration = {}; static bool is_aidl_available(); - static int GetAidlInterfaceVersion(); - protected: mutable std::mutex internal_mutex_; /*** @@ -123,7 +164,7 @@ class BluetoothAudioClientInterface { private: IBluetoothTransportInstance* transport_; std::vector capabilities_; - bool is_low_latency_allowed_{false}; + std::vector latency_modes_; }; /*** 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 c233941b37b2265708e299c12ccbc075a4464cd0..813de3b31079c7029bc381e0aa925810ec96a838 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 @@ -29,6 +29,7 @@ using ::aidl::android::hardware::bluetooth::audio::ChannelMode; using ::aidl::android::hardware::bluetooth::audio::CodecType; using ::bluetooth::audio::aidl::AudioConfiguration; using ::bluetooth::audio::aidl::BluetoothAudioCtrlAck; +using ::bluetooth::audio::aidl::LatencyMode; using ::bluetooth::audio::aidl::PcmConfiguration; using ::bluetooth::audio::aidl::SessionType; using ::bluetooth::audio::aidl::hearing_aid::StreamCallbacks; @@ -74,7 +75,7 @@ class HearingAidTransport } } - void SetLowLatency(bool is_low_latency) override {} + void SetLatencyMode(LatencyMode latency_mode) override {} bool GetPresentationPosition(uint64_t* remote_delay_report_ns, uint64_t* total_bytes_read, @@ -97,20 +98,20 @@ class HearingAidTransport } void SourceMetadataChanged( - const source_metadata_t& source_metadata) override { + const source_metadata_v7_t& source_metadata) override { auto track_count = source_metadata.track_count; auto tracks = source_metadata.tracks; LOG(INFO) << __func__ << ": " << track_count << " track(s) received"; while (track_count) { - VLOG(1) << __func__ << ": usage=" << tracks->usage - << ", content_type=" << tracks->content_type - << ", gain=" << tracks->gain; + VLOG(1) << __func__ << ": usage=" << tracks->base.usage + << ", content_type=" << tracks->base.content_type + << ", gain=" << tracks->base.gain; --track_count; ++tracks; } } - void SinkMetadataChanged(const sink_metadata_t&) override {} + void SinkMetadataChanged(const sink_metadata_v7_t&) override {} void ResetPresentationPosition() override { VLOG(2) << __func__ << ": called."; diff --git a/system/audio_hal_interface/aidl/hfp_client_interface_aidl.cc b/system/audio_hal_interface/aidl/hfp_client_interface_aidl.cc new file mode 100644 index 0000000000000000000000000000000000000000..63bfc917bd74c1b4772d49b378444ad56a0db191 --- /dev/null +++ b/system/audio_hal_interface/aidl/hfp_client_interface_aidl.cc @@ -0,0 +1,241 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "BTAudioHfpAIDL" + +#include "hfp_client_interface_aidl.h" + +#include + +#include "aidl/android/hardware/bluetooth/audio/AudioConfiguration.h" +#include "aidl/transport_instance.h" +#include "bta/ag/bta_ag_int.h" +#include "btif_hf.h" +#include "btm_api_types.h" +#include "hardware/bluetooth.h" +#include "hardware/bluetooth_headset_interface.h" +#include "types/raw_address.h" + +namespace bluetooth { +namespace audio { +namespace aidl { +namespace hfp { + +std::map status_to_ack_map = { + {BT_STATUS_SUCCESS, BluetoothAudioCtrlAck::SUCCESS_FINISHED}, + {BT_STATUS_DONE, BluetoothAudioCtrlAck::SUCCESS_FINISHED}, + {BT_STATUS_FAIL, BluetoothAudioCtrlAck::FAILURE}, + {BT_STATUS_NOT_READY, BluetoothAudioCtrlAck::FAILURE_BUSY}, + {BT_STATUS_BUSY, BluetoothAudioCtrlAck::FAILURE_BUSY}, + {BT_STATUS_UNSUPPORTED, BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED}, +}; + +tBTA_AG_SCB* get_hfp_active_device_callback() { + const RawAddress& addr = bta_ag_get_active_device(); + if (addr.IsEmpty()) { + LOG(ERROR) << __func__ << ": No active device found"; + return nullptr; + } + auto idx = bta_ag_idx_by_bdaddr(&addr); + if (idx == 0) { + LOG(ERROR) << __func__ << ": No index found for active device"; + return nullptr; + } + auto cb = bta_ag_scb_by_idx(idx); + if (cb == nullptr) { + LOG(ERROR) << __func__ << ": No callback for the active device"; + return nullptr; + } + return cb; +} + +HfpTransport::HfpTransport() { hfp_pending_cmd_ = HFP_CTRL_CMD_NONE; } + +BluetoothAudioCtrlAck HfpTransport::StartRequest() { + if (hfp_pending_cmd_ == HFP_CTRL_CMD_START) { + LOG(INFO) << __func__ << ": HFP_CTRL_CMD_START in progress"; + return BluetoothAudioCtrlAck::PENDING; + } else if (hfp_pending_cmd_ != HFP_CTRL_CMD_NONE) { + LOG(WARNING) << __func__ << ": busy in pending_cmd=" << hfp_pending_cmd_; + return BluetoothAudioCtrlAck::FAILURE_BUSY; + } + + auto cb = get_hfp_active_device_callback(); + if (cb == nullptr) return BluetoothAudioCtrlAck::FAILURE; + + if (bta_ag_sco_is_open(cb)) { + // Already started, ACK back immediately. + return BluetoothAudioCtrlAck::SUCCESS_FINISHED; + } + + /* Post start SCO event and wait for sco to open */ + hfp_pending_cmd_ = HFP_CTRL_CMD_START; + auto status = + bluetooth::headset::GetInterface()->ConnectAudio(&cb->peer_addr, 0); + hfp_pending_cmd_ = HFP_CTRL_CMD_NONE; + LOG(INFO) << __func__ << ": ConnectAudio status = " << status << " - " + << bt_status_text(status).c_str(); + auto ctrl_ack = status_to_ack_map.find(status); + if (ctrl_ack == status_to_ack_map.end()) + return BluetoothAudioCtrlAck::FAILURE; + return ctrl_ack->second; +} + +void HfpTransport::StopRequest() { + LOG(INFO) << __func__ << ": handling"; + RawAddress addr = bta_ag_get_active_device(); + if (addr.IsEmpty()) { + LOG(ERROR) << __func__ << ": No active device found"; + return; + } + hfp_pending_cmd_ = HFP_CTRL_CMD_STOP; + auto status = bluetooth::headset::GetInterface()->DisconnectAudio(&addr); + LOG(INFO) << __func__ << ": DisconnectAudio status = " << status << " - " + << bt_status_text(status).c_str(); + hfp_pending_cmd_ = HFP_CTRL_CMD_NONE; + return; +} + +void HfpTransport::ResetPendingCmd() { hfp_pending_cmd_ = HFP_CTRL_CMD_NONE; } + +uint8_t HfpTransport::GetPendingCmd() const { return hfp_pending_cmd_; } + +// Unimplemented functions +void HfpTransport::LogBytesProcessed(size_t bytes_read) {} + +BluetoothAudioCtrlAck HfpTransport::SuspendRequest() { + return BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED; +} + +void HfpTransport::SetLatencyMode(LatencyMode latency_mode) {} + +bool GetPresentationPosition(uint64_t* remote_delay_report_ns, + uint64_t* total_bytes_read, + timespec* data_position) { + return false; +} + +void HfpTransport::SourceMetadataChanged( + const source_metadata_v7_t& source_metadata) {} + +void HfpTransport::SinkMetadataChanged(const sink_metadata_v7_t&) {} + +void HfpTransport::ResetPresentationPosition() {} + +// Source / sink functions +HfpDecodingTransport::HfpDecodingTransport(SessionType session_type) + : IBluetoothSinkTransportInstance(session_type, (AudioConfiguration){}) { + transport_ = new HfpTransport(); +}; + +HfpDecodingTransport::~HfpDecodingTransport() { delete transport_; } + +BluetoothAudioCtrlAck HfpDecodingTransport::StartRequest(bool is_low_latency) { + return transport_->StartRequest(); +} + +BluetoothAudioCtrlAck HfpDecodingTransport::SuspendRequest() { + return transport_->SuspendRequest(); +} + +void HfpDecodingTransport::SetLatencyMode(LatencyMode latency_mode) { + transport_->SetLatencyMode(latency_mode); +} + +bool HfpDecodingTransport::GetPresentationPosition( + uint64_t* remote_delay_report_ns, uint64_t* total_bytes_written, + timespec* data_position) { + return transport_->GetPresentationPosition( + remote_delay_report_ns, total_bytes_written, data_position); +} + +void HfpDecodingTransport::SourceMetadataChanged( + const source_metadata_v7_t& source_metadata) { + transport_->SourceMetadataChanged(source_metadata); +} + +void HfpDecodingTransport::SinkMetadataChanged( + const sink_metadata_v7_t& sink_metadata) { + transport_->SinkMetadataChanged(sink_metadata); +} + +void HfpDecodingTransport::ResetPresentationPosition() { + transport_->ResetPresentationPosition(); +} + +void HfpDecodingTransport::LogBytesRead(size_t bytes_written) { + transport_->LogBytesProcessed(bytes_written); +} + +uint8_t HfpDecodingTransport::GetPendingCmd() const { + return transport_->GetPendingCmd(); +} + +void HfpDecodingTransport::ResetPendingCmd() { transport_->ResetPendingCmd(); } + +HfpEncodingTransport::HfpEncodingTransport(SessionType session_type) + : IBluetoothSourceTransportInstance(session_type, (AudioConfiguration){}) { + transport_ = new HfpTransport(); +}; + +HfpEncodingTransport::~HfpEncodingTransport() { delete transport_; } + +BluetoothAudioCtrlAck HfpEncodingTransport::StartRequest(bool is_low_latency) { + return transport_->StartRequest(); +} + +BluetoothAudioCtrlAck HfpEncodingTransport::SuspendRequest() { + return transport_->SuspendRequest(); +} + +void HfpEncodingTransport::SetLatencyMode(LatencyMode latency_mode) { + transport_->SetLatencyMode(latency_mode); +} + +bool HfpEncodingTransport::GetPresentationPosition( + uint64_t* remote_delay_report_ns, uint64_t* total_bytes_written, + timespec* data_position) { + return transport_->GetPresentationPosition( + remote_delay_report_ns, total_bytes_written, data_position); +} + +void HfpEncodingTransport::SourceMetadataChanged( + const source_metadata_v7_t& source_metadata) { + transport_->SourceMetadataChanged(source_metadata); +} + +void HfpEncodingTransport::SinkMetadataChanged( + const sink_metadata_v7_t& sink_metadata) { + transport_->SinkMetadataChanged(sink_metadata); +} + +void HfpEncodingTransport::ResetPresentationPosition() { + transport_->ResetPresentationPosition(); +} + +void HfpEncodingTransport::LogBytesWritten(size_t bytes_written) { + transport_->LogBytesProcessed(bytes_written); +} + +uint8_t HfpEncodingTransport::GetPendingCmd() const { + return transport_->GetPendingCmd(); +} + +void HfpEncodingTransport::ResetPendingCmd() { transport_->ResetPendingCmd(); } + +} // namespace hfp +} // namespace aidl +} // namespace audio +} // namespace bluetooth diff --git a/system/audio_hal_interface/aidl/hfp_client_interface_aidl.h b/system/audio_hal_interface/aidl/hfp_client_interface_aidl.h new file mode 100644 index 0000000000000000000000000000000000000000..8db6b5f48c07e58a0d20d382927c9c7110cd960a --- /dev/null +++ b/system/audio_hal_interface/aidl/hfp_client_interface_aidl.h @@ -0,0 +1,166 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "client_interface_aidl.h" +#include "common/message_loop_thread.h" + +namespace bluetooth { +namespace audio { +namespace aidl { +namespace hfp { + +using ::aidl::android::hardware::bluetooth::audio::LatencyMode; + +typedef enum { + HFP_CTRL_CMD_NONE, + HFP_CTRL_CMD_CHECK_READY, + HFP_CTRL_CMD_START, + HFP_CTRL_CMD_STOP, + HFP_CTRL_CMD_SUSPEND, + HFP_CTRL_GET_INPUT_AUDIO_CONFIG, + HFP_CTRL_GET_OUTPUT_AUDIO_CONFIG, + HFP_CTRL_SET_OUTPUT_AUDIO_CONFIG, + HFP_CTRL_GET_PRESENTATION_POSITION, +} tHFP_CTRL_CMD; + +// Provide call-in APIs for the Bluetooth Audio HAL +class HfpTransport { + public: + HfpTransport(); + + BluetoothAudioCtrlAck StartRequest(); + + BluetoothAudioCtrlAck SuspendRequest(); + + void StopRequest(); + + void SetLatencyMode(LatencyMode latency_mode); + + bool GetPresentationPosition(uint64_t* remote_delay_report_ns, + uint64_t* total_bytes_read, + timespec* data_position); + + void SourceMetadataChanged(const source_metadata_v7_t& source_metadata); + + void SinkMetadataChanged(const sink_metadata_v7_t&); + + void ResetPresentationPosition(); + + uint8_t GetPendingCmd() const; + + void ResetPendingCmd(); + + void LogBytesProcessed(size_t bytes_read); + + private: + tHFP_CTRL_CMD hfp_pending_cmd_; +}; + +// Sink transport implementation +class HfpDecodingTransport + : public ::bluetooth::audio::aidl::IBluetoothSinkTransportInstance { + public: + HfpDecodingTransport(SessionType sessionType); + + ~HfpDecodingTransport(); + + BluetoothAudioCtrlAck StartRequest(bool is_low_latency); + + BluetoothAudioCtrlAck SuspendRequest(); + + void StopRequest(); + + void SetLatencyMode(LatencyMode latency_mode); + + bool GetPresentationPosition(uint64_t* remote_delay_report_ns, + uint64_t* total_bytes_read, + timespec* data_position); + + void SourceMetadataChanged(const source_metadata_v7_t& source_metadata); + + void SinkMetadataChanged(const sink_metadata_v7_t& sink_metadata); + + void ResetPresentationPosition(); + + void LogBytesRead(size_t bytes_read) override; + + uint8_t GetPendingCmd() const; + + void ResetPendingCmd(); + + static inline HfpDecodingTransport* instance_ = nullptr; + static inline BluetoothAudioSinkClientInterface* software_hal_interface = + nullptr; + static inline BluetoothAudioSinkClientInterface* offloading_hal_interface = + nullptr; + static inline BluetoothAudioSinkClientInterface* active_hal_interface = + nullptr; + + private: + HfpTransport* transport_; +}; + +class HfpEncodingTransport + : public ::bluetooth::audio::aidl::IBluetoothSourceTransportInstance { + public: + HfpEncodingTransport(SessionType sessionType); + + ~HfpEncodingTransport(); + + BluetoothAudioCtrlAck StartRequest(bool is_low_latency); + + BluetoothAudioCtrlAck SuspendRequest(); + + void StopRequest(); + + void SetLatencyMode(LatencyMode latency_mode); + + bool GetPresentationPosition(uint64_t* remote_delay_report_ns, + uint64_t* total_bytes_read, + timespec* data_position); + + void SourceMetadataChanged(const source_metadata_v7_t& source_metadata); + + void SinkMetadataChanged(const sink_metadata_v7_t& sink_metadata); + + void ResetPresentationPosition(); + + void LogBytesWritten(size_t bytes_written) override; + + uint8_t GetPendingCmd() const; + + void ResetPendingCmd(); + + static inline HfpEncodingTransport* instance_ = nullptr; + static inline BluetoothAudioSourceClientInterface* software_hal_interface = + nullptr; + static inline BluetoothAudioSourceClientInterface* offloading_hal_interface = + nullptr; + static inline BluetoothAudioSourceClientInterface* active_hal_interface = + nullptr; + + private: + HfpTransport* transport_; +}; + +} // namespace hfp +} // namespace aidl +} // namespace audio +} // namespace bluetooth 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 b0aac66ecd5fab1378b62d59f4cb6faa0ec9d13d..3168bea2494029aaa2d4aa180be4c28773b270ac 100644 --- a/system/audio_hal_interface/aidl/le_audio_software_aidl.cc +++ b/system/audio_hal_interface/aidl/le_audio_software_aidl.cc @@ -45,7 +45,7 @@ using ::bluetooth::audio::le_audio::LeAudioClientInterface; using ::bluetooth::audio::le_audio::StartRequestState; using ::bluetooth::audio::le_audio::StreamCallbacks; using ::le_audio::set_configurations::SetConfiguration; -using ::le_audio::types::LeAudioLc3Config; +using ::le_audio::types::LeAudioCoreCodecConfig; static ChannelMode le_audio_channel_mode2audio_hal(uint8_t channels_count) { switch (channels_count) { @@ -69,6 +69,12 @@ LeAudioTransport::LeAudioTransport(void (*flush)(void), start_request_state_(StartRequestState::IDLE){}; BluetoothAudioCtrlAck LeAudioTransport::StartRequest(bool is_low_latency) { + // Check if operation is pending already + if (GetStartRequestState() == StartRequestState::PENDING_AFTER_RESUME) { + LOG_INFO("Start request is already pending. Ignore the request"); + return BluetoothAudioCtrlAck::PENDING; + } + SetStartRequestState(StartRequestState::PENDING_BEFORE_RESUME); if (stream_cb_.on_resume_(true)) { auto expected = StartRequestState::CONFIRMED; @@ -118,7 +124,25 @@ void LeAudioTransport::StopRequest() { } } -void LeAudioTransport::SetLowLatency(bool is_low_latency) {} +void LeAudioTransport::SetLatencyMode(LatencyMode latency_mode) { + switch (latency_mode) { + case LatencyMode::FREE: + dsa_mode_ = DsaMode::DISABLED; + break; + case LatencyMode::LOW_LATENCY: + dsa_mode_ = DsaMode::ACL; + break; + case LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE: + dsa_mode_ = DsaMode::ISO_SW; + break; + case LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE: + dsa_mode_ = DsaMode::ISO_HW; + break; + default: + LOG(WARNING) << ", invalid latency mode: " << (int)latency_mode; + break; + } +} bool LeAudioTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns, uint64_t* total_bytes_processed, @@ -138,7 +162,7 @@ bool LeAudioTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns, } void LeAudioTransport::SourceMetadataChanged( - const source_metadata_t& source_metadata) { + const source_metadata_v7_t& source_metadata) { auto track_count = source_metadata.track_count; if (track_count == 0) { @@ -146,11 +170,11 @@ void LeAudioTransport::SourceMetadataChanged( return; } - stream_cb_.on_metadata_update_(source_metadata); + stream_cb_.on_metadata_update_(source_metadata, dsa_mode_); } void LeAudioTransport::SinkMetadataChanged( - const sink_metadata_t& sink_metadata) { + const sink_metadata_v7_t& sink_metadata) { auto track_count = sink_metadata.track_count; if (track_count == 0) { @@ -274,8 +298,8 @@ BluetoothAudioCtrlAck LeAudioSinkTransport::SuspendRequest() { void LeAudioSinkTransport::StopRequest() { transport_->StopRequest(); } -void LeAudioSinkTransport::SetLowLatency(bool is_low_latency) { - transport_->SetLowLatency(is_low_latency); +void LeAudioSinkTransport::SetLatencyMode(LatencyMode latency_mode) { + transport_->SetLatencyMode(latency_mode); } bool LeAudioSinkTransport::GetPresentationPosition( @@ -286,12 +310,12 @@ bool LeAudioSinkTransport::GetPresentationPosition( } void LeAudioSinkTransport::SourceMetadataChanged( - const source_metadata_t& source_metadata) { + const source_metadata_v7_t& source_metadata) { transport_->SourceMetadataChanged(source_metadata); } void LeAudioSinkTransport::SinkMetadataChanged( - const sink_metadata_t& sink_metadata) { + const sink_metadata_v7_t& sink_metadata) { transport_->SinkMetadataChanged(sink_metadata); } @@ -364,8 +388,8 @@ BluetoothAudioCtrlAck LeAudioSourceTransport::SuspendRequest() { void LeAudioSourceTransport::StopRequest() { transport_->StopRequest(); } -void LeAudioSourceTransport::SetLowLatency(bool is_low_latency) { - transport_->SetLowLatency(is_low_latency); +void LeAudioSourceTransport::SetLatencyMode(LatencyMode latency_mode) { + transport_->SetLatencyMode(latency_mode); } bool LeAudioSourceTransport::GetPresentationPosition( @@ -376,12 +400,12 @@ bool LeAudioSourceTransport::GetPresentationPosition( } void LeAudioSourceTransport::SourceMetadataChanged( - const source_metadata_t& source_metadata) { + const source_metadata_v7_t& source_metadata) { transport_->SourceMetadataChanged(source_metadata); } void LeAudioSourceTransport::SinkMetadataChanged( - const sink_metadata_t& sink_metadata) { + const sink_metadata_v7_t& sink_metadata) { transport_->SinkMetadataChanged(sink_metadata); } @@ -433,15 +457,16 @@ std::unordered_map sampling_freq_map{ {192000, ::le_audio::codec_spec_conf::kLeAudioSamplingFreq192000Hz}}; std::unordered_map frame_duration_map{ - {7500, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameDur7500us}, - {10000, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameDur10000us}}; + {7500, ::le_audio::codec_spec_conf::kLeAudioCodecFrameDur7500us}, + {10000, ::le_audio::codec_spec_conf::kLeAudioCodecFrameDur10000us}}; std::unordered_map octets_per_frame_map{ - {30, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen30}, - {40, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen40}, - {60, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen60}, - {80, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen80}, - {120, ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameLen120}}; + {30, ::le_audio::codec_spec_conf::kLeAudioCodecFrameLen30}, + {40, ::le_audio::codec_spec_conf::kLeAudioCodecFrameLen40}, + {60, ::le_audio::codec_spec_conf::kLeAudioCodecFrameLen60}, + {80, ::le_audio::codec_spec_conf::kLeAudioCodecFrameLen80}, + {100, ::le_audio::codec_spec_conf::kLeAudioCodecFrameLen100}, + {120, ::le_audio::codec_spec_conf::kLeAudioCodecFrameLen120}}; std::unordered_map audio_location_map{ {AudioLocation::UNKNOWN, @@ -458,7 +483,7 @@ std::unordered_map audio_location_map{ bool hal_ucast_capability_to_stack_format( const UnicastCapability& hal_capability, - CodecCapabilitySetting& stack_capability) { + CodecConfigSetting& stack_capability) { if (hal_capability.codecType != CodecType::LC3) { LOG(WARNING) << "Unsupported codecType: " << toString(hal_capability.codecType); @@ -485,28 +510,37 @@ bool hal_ucast_capability_to_stack_format( octets_per_frame_map.end() || audio_location_map.find(supported_channel) == audio_location_map.end()) { LOG(ERROR) << __func__ << ": Failed to convert HAL format to stack format" - << "\nsample rate = " << sample_rate_hz - << "\nframe duration = " << frame_duration_us + << "\nsample rate hz = " << sample_rate_hz + << "\nframe duration us = " << frame_duration_us << "\noctets per frame= " << octets_per_frame - << "\naudio location = " << toString(supported_channel); + << "\nsupported channel = " << toString(supported_channel) + << "\nchannel count per device = " << channel_count + << "\ndevice count = " << hal_capability.deviceCount; return false; } - stack_capability = { - .id = ::le_audio::set_configurations::LeAudioCodecIdLc3, - .config = LeAudioLc3Config( - {.sampling_frequency = sampling_freq_map[sample_rate_hz], - .frame_duration = frame_duration_map[frame_duration_us], - .audio_channel_allocation = audio_location_map[supported_channel], - .octets_per_codec_frame = octets_per_frame_map[octets_per_frame], - .channel_count = static_cast(channel_count)})}; + stack_capability.id = ::le_audio::set_configurations::LeAudioCodecIdLc3; + stack_capability.channel_count_per_iso_stream = channel_count; + + stack_capability.params.Add( + ::le_audio::codec_spec_conf::kLeAudioLtvTypeSamplingFreq, + sampling_freq_map[sample_rate_hz]); + stack_capability.params.Add( + ::le_audio::codec_spec_conf::kLeAudioLtvTypeFrameDuration, + frame_duration_map[frame_duration_us]); + stack_capability.params.Add( + ::le_audio::codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation, + audio_location_map[supported_channel]); + stack_capability.params.Add( + ::le_audio::codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame, + octets_per_frame_map[octets_per_frame]); return true; } bool hal_bcast_capability_to_stack_format( const BroadcastCapability& hal_bcast_capability, - CodecCapabilitySetting& stack_capability) { + CodecConfigSetting& stack_capability) { if (hal_bcast_capability.codecType != CodecType::LC3) { LOG(WARNING) << "Unsupported codecType: " << toString(hal_bcast_capability.codecType); @@ -539,22 +573,30 @@ bool hal_bcast_capability_to_stack_format( audio_location_map.find(supported_channel) == audio_location_map.end()) { LOG(WARNING) << __func__ << " : Failed to convert HAL format to stack format" - << "\nsample rate = " << sample_rate_hz - << "\nframe duration = " << frame_duration_us + << "\nsample rate hz = " << sample_rate_hz + << "\nframe duration us = " << frame_duration_us << "\noctets per frame= " << octets_per_frame - << "\naudio location = " << toString(supported_channel); + << "\nsupported channel = " << toString(supported_channel) + << "\nchannel count per stream = " << channel_count; return false; } - stack_capability = { - .id = ::le_audio::set_configurations::LeAudioCodecIdLc3, - .config = LeAudioLc3Config( - {.sampling_frequency = sampling_freq_map[sample_rate_hz], - .frame_duration = frame_duration_map[frame_duration_us], - .audio_channel_allocation = audio_location_map[supported_channel], - .octets_per_codec_frame = octets_per_frame_map[octets_per_frame], - .channel_count = static_cast(channel_count)})}; + stack_capability.id = ::le_audio::set_configurations::LeAudioCodecIdLc3; + stack_capability.channel_count_per_iso_stream = channel_count; + + stack_capability.params.Add( + ::le_audio::codec_spec_conf::kLeAudioLtvTypeSamplingFreq, + sampling_freq_map[sample_rate_hz]); + stack_capability.params.Add( + ::le_audio::codec_spec_conf::kLeAudioLtvTypeFrameDuration, + frame_duration_map[frame_duration_us]); + stack_capability.params.Add( + ::le_audio::codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation, + audio_location_map[supported_channel]); + stack_capability.params.Add( + ::le_audio::codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame, + octets_per_frame_map[octets_per_frame]); return true; } @@ -567,7 +609,7 @@ std::vector get_offload_capabilities() { std::string str_capability_log; for (auto hal_cap : le_audio_hal_capabilities) { - CodecCapabilitySetting encode_cap, decode_cap, bcast_cap; + CodecConfigSetting encode_cap, decode_cap, bcast_cap; UnicastCapability hal_encode_cap = hal_cap.get() .unicastEncodeCapability; @@ -643,10 +685,6 @@ AudioConfiguration offload_config_to_hal_audio_config( return AudioConfiguration(ucast_config); } -int GetAidlInterfaceVersion() { - return BluetoothAudioSinkClientInterface::GetAidlInterfaceVersion(); -} - } // namespace le_audio } // namespace aidl } // namespace audio diff --git a/system/audio_hal_interface/aidl/le_audio_software_aidl.h b/system/audio_hal_interface/aidl/le_audio_software_aidl.h index 652bc6ddb94635b3f4efa4b8ac2857b6bb007615..c75a76d6b24f32b3d2e19887d61e1b06555097b0 100644 --- a/system/audio_hal_interface/aidl/le_audio_software_aidl.h +++ b/system/audio_hal_interface/aidl/le_audio_software_aidl.h @@ -34,9 +34,11 @@ using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; using ::aidl::android::hardware::bluetooth::audio::SessionType; using ::aidl::android::hardware::bluetooth::audio::UnicastCapability; using ::bluetooth::audio::aidl::BluetoothAudioCtrlAck; +using ::bluetooth::audio::aidl::LatencyMode; using ::bluetooth::audio::le_audio::StartRequestState; +using ::le_audio::DsaMode; using ::le_audio::set_configurations::AudioSetConfiguration; -using ::le_audio::set_configurations::CodecCapabilitySetting; +using ::le_audio::set_configurations::CodecConfigSetting; constexpr uint8_t kChannelNumberMono = 1; constexpr uint8_t kChannelNumberStereo = 2; @@ -54,19 +56,14 @@ constexpr uint8_t kBitsPerSample32 = 32; using ::bluetooth::audio::le_audio::StreamCallbacks; -void flush_sink(); void flush_source(); bool hal_ucast_capability_to_stack_format( const UnicastCapability& ucast_capability, - CodecCapabilitySetting& stack_capability); + CodecConfigSetting& stack_capability); AudioConfiguration offload_config_to_hal_audio_config( const ::le_audio::offload_config& offload_config); -bool is_source_hal_enabled(); -bool is_sink_hal_enabled(); - std::vector get_offload_capabilities(); -int GetAidlInterfaceVersion(); class LeAudioTransport { public: @@ -79,15 +76,15 @@ class LeAudioTransport { void StopRequest(); - void SetLowLatency(bool is_low_latency); + void SetLatencyMode(LatencyMode latency_mode); bool GetPresentationPosition(uint64_t* remote_delay_report_ns, uint64_t* total_bytes_processed, timespec* data_position); - void SourceMetadataChanged(const source_metadata_t& source_metadata); + void SourceMetadataChanged(const source_metadata_v7_t& source_metadata); - void SinkMetadataChanged(const sink_metadata_t& sink_metadata); + void SinkMetadataChanged(const sink_metadata_v7_t& sink_metadata); void ResetPresentationPosition(); @@ -119,6 +116,7 @@ class LeAudioTransport { PcmConfiguration pcm_config_; LeAudioBroadcastConfiguration broadcast_config_; std::atomic start_request_state_; + DsaMode dsa_mode_; }; // Sink transport implementation for Le Audio @@ -135,15 +133,16 @@ class LeAudioSinkTransport void StopRequest() override; - void SetLowLatency(bool is_low_latency) override; + void SetLatencyMode(LatencyMode latency_mode) override; bool GetPresentationPosition(uint64_t* remote_delay_report_ns, uint64_t* total_bytes_read, timespec* data_position) override; - void SourceMetadataChanged(const source_metadata_t& source_metadata) override; + void SourceMetadataChanged( + const source_metadata_v7_t& source_metadata) override; - void SinkMetadataChanged(const sink_metadata_t& sink_metadata) override; + void SinkMetadataChanged(const sink_metadata_v7_t& sink_metadata) override; void ResetPresentationPosition() override; @@ -190,15 +189,16 @@ class LeAudioSourceTransport void StopRequest() override; - void SetLowLatency(bool is_low_latency) override; + void SetLatencyMode(LatencyMode latency_mode) override; bool GetPresentationPosition(uint64_t* remote_delay_report_ns, uint64_t* total_bytes_written, timespec* data_position) override; - void SourceMetadataChanged(const source_metadata_t& source_metadata) override; + void SourceMetadataChanged( + const source_metadata_v7_t& source_metadata) override; - void SinkMetadataChanged(const sink_metadata_t& sink_metadata) override; + void SinkMetadataChanged(const sink_metadata_v7_t& sink_metadata) override; void ResetPresentationPosition() override; diff --git a/system/audio_hal_interface/aidl/transport_instance.h b/system/audio_hal_interface/aidl/transport_instance.h index e7967ab2c4a7ce586f296c5e98fc6c019d4861a6..6b0adf0944847b24cad0a3357b8eac30fa12c0ed 100644 --- a/system/audio_hal_interface/aidl/transport_instance.h +++ b/system/audio_hal_interface/aidl/transport_instance.h @@ -55,6 +55,10 @@ class IBluetoothTransportInstance { audio_config_.set( audio_config.get()); break; + case AudioConfiguration::hfpConfig: + audio_config_.set( + audio_config.get()); + break; case AudioConfiguration::leAudioConfig: audio_config_.set( audio_config.get()); @@ -62,6 +66,11 @@ class IBluetoothTransportInstance { case AudioConfiguration::leAudioBroadcastConfig: audio_config_.set( audio_config.get()); + break; + case AudioConfiguration::a2dp: + audio_config_.set( + audio_config.get()); + break; } } @@ -71,15 +80,15 @@ class IBluetoothTransportInstance { virtual void StopRequest() = 0; - virtual void SetLowLatency(bool is_low_latency) = 0; + virtual void SetLatencyMode(LatencyMode latency_mode) = 0; virtual bool GetPresentationPosition(uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed, timespec* data_position) = 0; virtual void SourceMetadataChanged( - const source_metadata_t& source_metadata) = 0; - virtual void SinkMetadataChanged(const sink_metadata_t& sink_metadata) = 0; + const source_metadata_v7_t& source_metadata) = 0; + virtual void SinkMetadataChanged(const sink_metadata_v7_t& sink_metadata) = 0; /*** * Invoked when the transport is requested to reset presentation position diff --git a/system/audio_hal_interface/audio_linux.h b/system/audio_hal_interface/audio_linux.h new file mode 100644 index 0000000000000000000000000000000000000000..1c723f7d31b9a6be14a35dd41a564bc07e52dbb2 --- /dev/null +++ b/system/audio_hal_interface/audio_linux.h @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +/* maximum audio device address length */ +#define AUDIO_DEVICE_MAX_ADDRESS_LEN 32 + +/* Audio attributes */ +#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256 + +static const char AUDIO_ATTRIBUTES_TAGS_SEPARATOR = ';'; + +typedef enum { + AUDIO_SOURCE_DEFAULT = 0, + AUDIO_SOURCE_MIC = 1, + AUDIO_SOURCE_VOICE_UPLINK = 2, + AUDIO_SOURCE_VOICE_DOWNLINK = 3, + AUDIO_SOURCE_VOICE_CALL = 4, + AUDIO_SOURCE_CAMCORDER = 5, + AUDIO_SOURCE_VOICE_RECOGNITION = 6, + AUDIO_SOURCE_VOICE_COMMUNICATION = 7, + AUDIO_SOURCE_REMOTE_SUBMIX = 8, + AUDIO_SOURCE_UNPROCESSED = 9, + AUDIO_SOURCE_VOICE_PERFORMANCE = 10, + AUDIO_SOURCE_ECHO_REFERENCE = 1997, + AUDIO_SOURCE_FM_TUNER = 1998, + AUDIO_SOURCE_HOTWORD = 1999, + AUDIO_SOURCE_INVALID = -1, +} audio_source_t; + +typedef enum { + AUDIO_CONTENT_TYPE_UNKNOWN = 0u, + AUDIO_CONTENT_TYPE_SPEECH = 1u, + AUDIO_CONTENT_TYPE_MUSIC = 2u, + AUDIO_CONTENT_TYPE_MOVIE = 3u, + AUDIO_CONTENT_TYPE_SONIFICATION = 4u, +} audio_content_type_t; + +typedef enum { + AUDIO_USAGE_UNKNOWN = 0, + AUDIO_USAGE_MEDIA = 1, + AUDIO_USAGE_VOICE_COMMUNICATION = 2, + AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING = 3, + AUDIO_USAGE_ALARM = 4, + AUDIO_USAGE_NOTIFICATION = 5, + AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6, + AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7, + AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8, + AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9, + AUDIO_USAGE_NOTIFICATION_EVENT = 10, + AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY = 11, + AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12, + AUDIO_USAGE_ASSISTANCE_SONIFICATION = 13, + AUDIO_USAGE_GAME = 14, + AUDIO_USAGE_VIRTUAL_SOURCE = 15, + AUDIO_USAGE_ASSISTANT = 16, + AUDIO_USAGE_CALL_ASSISTANT = 17, + AUDIO_USAGE_EMERGENCY = 1000, + AUDIO_USAGE_SAFETY = 1001, + AUDIO_USAGE_VEHICLE_STATUS = 1002, + AUDIO_USAGE_ANNOUNCEMENT = 1003, +} audio_usage_t; + +typedef enum { + AUDIO_DEVICE_DEFAULT = 0, +} audio_devices_t; + +// The "channel mask" enum is comprised of discrete channels, +// their combinations (masks), and special values. +typedef enum : uint32_t { + AUDIO_CHANNEL_REPRESENTATION_POSITION = 0x0u, + AUDIO_CHANNEL_REPRESENTATION_INDEX = 0x2u, + AUDIO_CHANNEL_NONE = 0x0u, + AUDIO_CHANNEL_INVALID = 0xC0000000u, + + AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1u, + AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2u, + AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4u, + AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8u, + AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10u, + AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20u, + AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40u, + AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u, + AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100u, + AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200u, + AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400u, + AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800u, + AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000u, + AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000u, + AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000u, + AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000u, + AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000u, + AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000u, + AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT = 0x40000u, + AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT = 0x80000u, + AUDIO_CHANNEL_OUT_HAPTIC_A = 0x20000000u, + AUDIO_CHANNEL_OUT_HAPTIC_B = 0x10000000u, + AUDIO_CHANNEL_OUT_MONO = 0x1u, // OUT_FRONT_LEFT + AUDIO_CHANNEL_OUT_STEREO = 0x3u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT + AUDIO_CHANNEL_OUT_2POINT1 = + 0xBu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY + AUDIO_CHANNEL_OUT_2POINT0POINT2 = + 0xC0003u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | + // OUT_TOP_SIDE_RIGHT + AUDIO_CHANNEL_OUT_2POINT1POINT2 = + 0xC000Bu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | + // OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY + AUDIO_CHANNEL_OUT_3POINT0POINT2 = + 0xC0007u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | + // OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT + AUDIO_CHANNEL_OUT_3POINT1POINT2 = + 0xC000Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | + // OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY + AUDIO_CHANNEL_OUT_QUAD = 0x33u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + // OUT_BACK_LEFT | OUT_BACK_RIGHT + AUDIO_CHANNEL_OUT_QUAD_BACK = 0x33u, // OUT_QUAD + AUDIO_CHANNEL_OUT_QUAD_SIDE = 0x603u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + // OUT_SIDE_LEFT | OUT_SIDE_RIGHT + AUDIO_CHANNEL_OUT_SURROUND = 0x107u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + // OUT_FRONT_CENTER | OUT_BACK_CENTER + AUDIO_CHANNEL_OUT_PENTA = 0x37u, // OUT_QUAD | OUT_FRONT_CENTER + AUDIO_CHANNEL_OUT_5POINT1 = + 0x3Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | + // OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT + AUDIO_CHANNEL_OUT_5POINT1_BACK = 0x3Fu, // OUT_5POINT1 + AUDIO_CHANNEL_OUT_5POINT1_SIDE = + 0x60Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | + // OUT_LOW_FREQUENCY | OUT_SIDE_LEFT | OUT_SIDE_RIGHT + AUDIO_CHANNEL_OUT_5POINT1POINT2 = + 0xC003Fu, // OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT + AUDIO_CHANNEL_OUT_5POINT1POINT4 = + 0x2D03Fu, // OUT_5POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | + // OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT + AUDIO_CHANNEL_OUT_6POINT1 = + 0x13Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | + // OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | + // OUT_BACK_CENTER + AUDIO_CHANNEL_OUT_7POINT1 = + 0x63Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | + // OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | + // OUT_SIDE_LEFT | OUT_SIDE_RIGHT + AUDIO_CHANNEL_OUT_7POINT1POINT2 = + 0xC063Fu, // OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT + AUDIO_CHANNEL_OUT_7POINT1POINT4 = + 0x2D63Fu, // OUT_7POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | + // OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT + AUDIO_CHANNEL_OUT_MONO_HAPTIC_A = + 0x20000001u, // OUT_FRONT_LEFT | OUT_HAPTIC_A + AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A = + 0x20000003u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A + AUDIO_CHANNEL_OUT_HAPTIC_AB = 0x30000000u, // OUT_HAPTIC_A | OUT_HAPTIC_B + AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB = + 0x30000001u, // OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B + AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB = + 0x30000003u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A | + // OUT_HAPTIC_B + + AUDIO_CHANNEL_IN_LEFT = 0x4u, + AUDIO_CHANNEL_IN_RIGHT = 0x8u, + AUDIO_CHANNEL_IN_FRONT = 0x10u, + AUDIO_CHANNEL_IN_BACK = 0x20u, + AUDIO_CHANNEL_IN_LEFT_PROCESSED = 0x40u, + AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80u, + AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100u, + AUDIO_CHANNEL_IN_BACK_PROCESSED = 0x200u, + AUDIO_CHANNEL_IN_PRESSURE = 0x400u, + AUDIO_CHANNEL_IN_X_AXIS = 0x800u, + AUDIO_CHANNEL_IN_Y_AXIS = 0x1000u, + AUDIO_CHANNEL_IN_Z_AXIS = 0x2000u, + AUDIO_CHANNEL_IN_BACK_LEFT = 0x10000u, + AUDIO_CHANNEL_IN_BACK_RIGHT = 0x20000u, + AUDIO_CHANNEL_IN_CENTER = 0x40000u, + AUDIO_CHANNEL_IN_LOW_FREQUENCY = 0x100000u, + AUDIO_CHANNEL_IN_TOP_LEFT = 0x200000u, + AUDIO_CHANNEL_IN_TOP_RIGHT = 0x400000u, + AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000u, + AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000u, + AUDIO_CHANNEL_IN_MONO = 0x10u, // IN_FRONT + AUDIO_CHANNEL_IN_STEREO = 0xCu, // IN_LEFT | IN_RIGHT + AUDIO_CHANNEL_IN_FRONT_BACK = 0x30u, // IN_FRONT | IN_BACK + AUDIO_CHANNEL_IN_6 = 0xFCu, // IN_LEFT | IN_RIGHT | IN_FRONT | IN_BACK | + // IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED + AUDIO_CHANNEL_IN_2POINT0POINT2 = + 0x60000Cu, // IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT + AUDIO_CHANNEL_IN_2POINT1POINT2 = + 0x70000Cu, // IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | + // IN_LOW_FREQUENCY + AUDIO_CHANNEL_IN_3POINT0POINT2 = + 0x64000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT + AUDIO_CHANNEL_IN_3POINT1POINT2 = + 0x74000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT + // | IN_LOW_FREQUENCY + AUDIO_CHANNEL_IN_5POINT1 = + 0x17000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_BACK_LEFT | + // IN_BACK_RIGHT | IN_LOW_FREQUENCY + AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO = 0x4010u, // IN_VOICE_UPLINK | IN_MONO + AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO = 0x8010u, // IN_VOICE_DNLINK | IN_MONO + AUDIO_CHANNEL_IN_VOICE_CALL_MONO = + 0xC010u, // IN_VOICE_UPLINK_MONO | IN_VOICE_DNLINK_MONO + + AUDIO_CHANNEL_COUNT_MAX = 30u, + AUDIO_CHANNEL_INDEX_HDR = 0x80000000u, // REPRESENTATION_INDEX << COUNT_MAX + AUDIO_CHANNEL_INDEX_MASK_1 = 0x80000001u, // INDEX_HDR | (1 << 1) - 1 + AUDIO_CHANNEL_INDEX_MASK_2 = 0x80000003u, // INDEX_HDR | (1 << 2) - 1 + AUDIO_CHANNEL_INDEX_MASK_3 = 0x80000007u, // INDEX_HDR | (1 << 3) - 1 + AUDIO_CHANNEL_INDEX_MASK_4 = 0x8000000Fu, // INDEX_HDR | (1 << 4) - 1 + AUDIO_CHANNEL_INDEX_MASK_5 = 0x8000001Fu, // INDEX_HDR | (1 << 5) - 1 + AUDIO_CHANNEL_INDEX_MASK_6 = 0x8000003Fu, // INDEX_HDR | (1 << 6) - 1 + AUDIO_CHANNEL_INDEX_MASK_7 = 0x8000007Fu, // INDEX_HDR | (1 << 7) - 1 + AUDIO_CHANNEL_INDEX_MASK_8 = 0x800000FFu, // INDEX_HDR | (1 << 8) - 1 + AUDIO_CHANNEL_INDEX_MASK_9 = 0x800001FFu, // INDEX_HDR | (1 << 9) - 1 + AUDIO_CHANNEL_INDEX_MASK_10 = 0x800003FFu, // INDEX_HDR | (1 << 10) - 1 + AUDIO_CHANNEL_INDEX_MASK_11 = 0x800007FFu, // INDEX_HDR | (1 << 11) - 1 + AUDIO_CHANNEL_INDEX_MASK_12 = 0x80000FFFu, // INDEX_HDR | (1 << 12) - 1 + AUDIO_CHANNEL_INDEX_MASK_13 = 0x80001FFFu, // INDEX_HDR | (1 << 13) - 1 + AUDIO_CHANNEL_INDEX_MASK_14 = 0x80003FFFu, // INDEX_HDR | (1 << 14) - 1 + AUDIO_CHANNEL_INDEX_MASK_15 = 0x80007FFFu, // INDEX_HDR | (1 << 15) - 1 + AUDIO_CHANNEL_INDEX_MASK_16 = 0x8000FFFFu, // INDEX_HDR | (1 << 16) - 1 + AUDIO_CHANNEL_INDEX_MASK_17 = 0x8001FFFFu, // INDEX_HDR | (1 << 17) - 1 + AUDIO_CHANNEL_INDEX_MASK_18 = 0x8003FFFFu, // INDEX_HDR | (1 << 18) - 1 + AUDIO_CHANNEL_INDEX_MASK_19 = 0x8007FFFFu, // INDEX_HDR | (1 << 19) - 1 + AUDIO_CHANNEL_INDEX_MASK_20 = 0x800FFFFFu, // INDEX_HDR | (1 << 20) - 1 + AUDIO_CHANNEL_INDEX_MASK_21 = 0x801FFFFFu, // INDEX_HDR | (1 << 21) - 1 + AUDIO_CHANNEL_INDEX_MASK_22 = 0x803FFFFFu, // INDEX_HDR | (1 << 22) - 1 + AUDIO_CHANNEL_INDEX_MASK_23 = 0x807FFFFFu, // INDEX_HDR | (1 << 23) - 1 + AUDIO_CHANNEL_INDEX_MASK_24 = 0x80FFFFFFu, // INDEX_HDR | (1 << 24) - 1 +} audio_channel_mask_t; + +/** Metadata of a playback track for an in stream. */ +typedef struct playback_track_metadata { + audio_usage_t usage; + audio_content_type_t content_type; + float gain; // Normalized linear volume. 0=silence, 1=0dbfs... +} playback_track_metadata_t; + +/** Metadata of a record track for an out stream. */ +typedef struct record_track_metadata { + audio_source_t source; + float gain; // Normalized linear volume. 0=silence, 1=0dbfs... + // For record tracks originating from a software patch, the + // dest_device fields provide information about the downstream + // device. + audio_devices_t dest_device; + char dest_device_address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; +} record_track_metadata_t; + +typedef struct source_metadata { + size_t track_count; + /** Array of metadata of each track connected to this source. */ + struct playback_track_metadata* tracks; +} source_metadata_t; + +typedef struct sink_metadata { + size_t track_count; + /** Array of metadata of each track connected to this sink. */ + struct record_track_metadata* tracks; +} sink_metadata_t; + +/** Metadata of a playback track for an in stream. */ +typedef struct playback_track_metadata_v7 { + struct playback_track_metadata base; + audio_channel_mask_t channel_mask; + char tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */ +} playback_track_metadata_v7_t; + +/** Metadata of a record track for an out stream. */ +typedef struct record_track_metadata_v7 { + struct record_track_metadata base; + audio_channel_mask_t channel_mask; + char tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */ +} record_track_metadata_v7_t; + +/* HAL version 3.2 and higher only. */ +typedef struct source_metadata_v7 { + size_t track_count; + /** Array of metadata of each track connected to this source. */ + struct playback_track_metadata_v7* tracks; +} source_metadata_v7_t; + +/* HAL version 3.2 and higher only. */ +typedef struct sink_metadata_v7 { + size_t track_count; + /** Array of metadata of each track connected to this sink. */ + struct record_track_metadata_v7* tracks; +} sink_metadata_v7_t; \ No newline at end of file diff --git a/system/audio_hal_interface/fuzzer/Android.bp b/system/audio_hal_interface/fuzzer/Android.bp index eaaa0d12e4dc80b5e6a9d10c0b5172b875f024a2..2528fa893cfec72c46871aa613f28eafe0df0a9b 100644 --- a/system/audio_hal_interface/fuzzer/Android.bp +++ b/system/audio_hal_interface/fuzzer/Android.bp @@ -29,9 +29,11 @@ cc_defaults { "avrcp_headers", "libbluetooth_headers", ], + defaults: [ + "latest_android_hardware_bluetooth_audio_ndk_shared", + ], shared_libs: [ "android.hardware.bluetooth.a2dp@1.0", - "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", "android.hardware.bluetooth@1.0", @@ -46,6 +48,7 @@ cc_defaults { "libstatslog", "libstatssocket", "libz", + "server_configurable_flags", ], static_libs: [ "libFraunhoferAAC", @@ -55,11 +58,13 @@ cc_defaults { "libbluetooth-protos", "libbluetooth-types", "libbluetooth_core_rs", + "libbluetooth_crypto_toolbox", "libbluetooth_gd", "libbluetooth_rust_interop", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", + "libbt-btu-main-thread", "libbt-common", "libbt-hci", "libbt-sbc-decoder", @@ -77,7 +82,6 @@ cc_defaults { "libchrome", "libcutils", "libevent", - "libflatbuffers-cpp", "libg722codec", "libhidlbase", "libjsoncpp", @@ -96,16 +100,19 @@ cc_defaults { "packages/modules/Bluetooth/system/bta/include", "packages/modules/Bluetooth/system/btif", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/stack/include", ], - cflags: [ - // http://b/264549607 - "-Wno-deprecated-builtins", - ], fuzz_config: { cc: ["android-bluetooth-security@google.com"], componentid: 27441, + hotlists: [ + "4593311", + ], + description: "The fuzzer targets the APIs of libbt-audio-hal-interface", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped", }, } diff --git a/system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp b/system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp index 1a33b5b39e6e6b18a78fb70bb08ef5250afb4e44..4f7954e01c1bf746d5ace0ae95d227de47a29766 100644 --- a/system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp +++ b/system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp @@ -93,8 +93,14 @@ void A2dpEncodingFuzzer::process(const uint8_t* data, size_t size) { uint16_t delayReport = fdp.ConsumeIntegral(); bluetooth::audio::a2dp::set_remote_delay(delayReport); - (void)bluetooth::audio::a2dp::init(&messageLoopThread); - (void)bluetooth::audio::a2dp::setup_codec(); + if (!bluetooth::audio::a2dp::init(&messageLoopThread)) { + return; + } + + if (!bluetooth::audio::a2dp::setup_codec()) { + return; + } + bluetooth::audio::a2dp::start_session(); tA2DP_CTRL_ACK status = fdp.PickValueInArray(kCtrlAckStatus); diff --git a/system/audio_hal_interface/fuzzer/libbt_audio_hal_le_audio_software_fuzzer.cpp b/system/audio_hal_interface/fuzzer/libbt_audio_hal_le_audio_software_fuzzer.cpp index bf24b176ae1b51fe8913579e92de12fe3e7d8cbb..4fa4c79cbfc9a601acd8b994a56e306c0ba252eb 100644 --- a/system/audio_hal_interface/fuzzer/libbt_audio_hal_le_audio_software_fuzzer.cpp +++ b/system/audio_hal_interface/fuzzer/libbt_audio_hal_le_audio_software_fuzzer.cpp @@ -24,12 +24,11 @@ using ::bluetooth::audio::le_audio::LeAudioClientInterface; constexpr int32_t kRandomStringLength = 256; -constexpr uint8_t kBitsPerSample[] = {0, 16, 24, 32}; +constexpr uint8_t kBitsPerSample[] = {16, 24, 32}; -constexpr uint8_t kChannelCount[] = {0, 1, 2}; +constexpr uint8_t kChannelCount[] = {1, 2}; -constexpr uint32_t kSampleRates[] = {0, 8000, 16000, 24000, 32000, 44100, - 48000, 88200, 96000, 176400, 192000}; +constexpr uint32_t kSampleRates[] = {16000, 24000, 44100, 48000, 88200, 96000}; extern "C" { struct android_namespace_t* android_get_exported_namespace(const char*) { @@ -41,9 +40,11 @@ bool onResume(bool) { return true; } bool onSuspend(void) { return true; } -bool onMetadataUpdate(const source_metadata_t&) { return true; } +bool onMetadataUpdate(const source_metadata_v7_t&, le_audio::DsaMode) { + return true; +} -bool onSinkMetadataUpdate(const sink_metadata_t&) { return true; } +bool onSinkMetadataUpdate(const sink_metadata_v7_t&) { return true; } static void source_init_delayed(void) {} @@ -65,15 +66,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { LeAudioClientInterface::Source* source = interface->GetSource(streamCb, &messageLoopThread); if (source != nullptr) { - source->StartSession(); uint16_t delay = fdp.ConsumeIntegral(); source->SetRemoteDelay(delay); LeAudioClientInterface::PcmParameters params; - params.data_interval_us = fdp.ConsumeIntegral(); + params.data_interval_us = fdp.ConsumeIntegralInRange( + 1000, std::numeric_limits::max()); params.sample_rate = fdp.PickValueInArray(kSampleRates); params.bits_per_sample = fdp.PickValueInArray(kBitsPerSample); params.channels_count = fdp.PickValueInArray(kChannelCount); source->SetPcmParameters(params); + source->StartSession(); source->StopSession(); source->Cleanup(); } @@ -84,15 +86,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { LeAudioClientInterface::Sink* sink = interface->GetSink(streamCb, &messageLoopThread, false); if (sink != nullptr) { - sink->StartSession(); uint16_t delay = fdp.ConsumeIntegral(); sink->SetRemoteDelay(delay); LeAudioClientInterface::PcmParameters params; - params.data_interval_us = fdp.ConsumeIntegral(); + params.data_interval_us = fdp.ConsumeIntegralInRange( + 1000, std::numeric_limits::max()); params.sample_rate = fdp.PickValueInArray(kSampleRates); params.bits_per_sample = fdp.PickValueInArray(kBitsPerSample); params.channels_count = fdp.PickValueInArray(kChannelCount); sink->SetPcmParameters(params); + sink->StartSession(); sink->StopSession(); sink->Cleanup(); } diff --git a/system/audio_hal_interface/hal_version_manager.cc b/system/audio_hal_interface/hal_version_manager.cc index a2c192f37d1975298ecec642f5cb35df5f5be6b7..275bbb067eef77e14bf33b5adaa062533cc7611d 100644 --- a/system/audio_hal_interface/hal_version_manager.cc +++ b/system/audio_hal_interface/hal_version_manager.cc @@ -24,6 +24,7 @@ #include #include "aidl/audio_aidl_interfaces.h" +#include "osi/include/log.h" namespace bluetooth { namespace audio { @@ -43,15 +44,7 @@ BluetoothAudioHalVersion HalVersionManager::GetHalVersion() { } BluetoothAudioHalTransport HalVersionManager::GetHalTransport() { - switch (GetHalVersion()) { - case BluetoothAudioHalVersion::VERSION_AIDL_V1: - return BluetoothAudioHalTransport::AIDL; - case BluetoothAudioHalVersion::VERSION_2_0: - case BluetoothAudioHalVersion::VERSION_2_1: - return BluetoothAudioHalTransport::HIDL; - default: - return BluetoothAudioHalTransport::UNKNOWN; - } + return instance_ptr->hal_transport_; } android::sp @@ -90,10 +83,48 @@ HalVersionManager::GetProvidersFactory_2_0() { return providers_factory; } +BluetoothAudioHalVersion GetAidlInterfaceVersion() { + int aidl_version = 0; + + auto provider_factory = IBluetoothAudioProviderFactory::fromBinder( + ::ndk::SpAIBinder(AServiceManager_waitForService( + kDefaultAudioProviderFactoryInterface.c_str()))); + + if (provider_factory == nullptr) { + LOG_ERROR("Can't get aidl version from unknown factory"); + return BluetoothAudioHalVersion::VERSION_UNAVAILABLE; + } + + auto aidl_retval = provider_factory->getInterfaceVersion(&aidl_version); + if (!aidl_retval.isOk()) { + LOG_ERROR("BluetoothAudioHal::getInterfaceVersion failure: %s", + aidl_retval.getDescription().c_str()); + return BluetoothAudioHalVersion::VERSION_UNAVAILABLE; + } + + switch (aidl_version) { + case 1: + return BluetoothAudioHalVersion::VERSION_AIDL_V1; + case 2: + return BluetoothAudioHalVersion::VERSION_AIDL_V2; + case 3: + return BluetoothAudioHalVersion::VERSION_AIDL_V3; + case 4: + return BluetoothAudioHalVersion::VERSION_AIDL_V4; + default: + LOG_ERROR("Unknown AIDL version %d", aidl_version); + return BluetoothAudioHalVersion::VERSION_UNAVAILABLE; + } + + return BluetoothAudioHalVersion::VERSION_UNAVAILABLE; +} + HalVersionManager::HalVersionManager() { + hal_transport_ = BluetoothAudioHalTransport::UNKNOWN; if (AServiceManager_checkService( kDefaultAudioProviderFactoryInterface.c_str()) != nullptr) { - hal_version_ = BluetoothAudioHalVersion::VERSION_AIDL_V1; + hal_version_ = GetAidlInterfaceVersion(); + hal_transport_ = BluetoothAudioHalTransport::AIDL; return; } @@ -115,6 +146,7 @@ HalVersionManager::HalVersionManager() { if (instance_count > 0) { hal_version_ = BluetoothAudioHalVersion::VERSION_2_1; + hal_transport_ = BluetoothAudioHalTransport::HIDL; return; } @@ -128,6 +160,7 @@ HalVersionManager::HalVersionManager() { if (instance_count > 0) { hal_version_ = BluetoothAudioHalVersion::VERSION_2_0; + hal_transport_ = BluetoothAudioHalTransport::HIDL; return; } diff --git a/system/audio_hal_interface/hal_version_manager.h b/system/audio_hal_interface/hal_version_manager.h index 99dc0e93112d285aff25bdb62da94c555deef2d9..f08cbe10aa5a0ef37ad601aa75008d5b0e60c513 100644 --- a/system/audio_hal_interface/hal_version_manager.h +++ b/system/audio_hal_interface/hal_version_manager.h @@ -39,13 +39,14 @@ enum class BluetoothAudioHalVersion : uint8_t { VERSION_2_0, VERSION_2_1, VERSION_AIDL_V1, + VERSION_AIDL_V2, + VERSION_AIDL_V3, + VERSION_AIDL_V4, }; enum class BluetoothAudioHalTransport : uint8_t { // Uninit, default value UNKNOWN, - // No HAL available after init or force disabled - DISABLED, AIDL, HIDL, }; @@ -69,6 +70,7 @@ class HalVersionManager { std::mutex mutex_; BluetoothAudioHalVersion hal_version_; + BluetoothAudioHalTransport hal_transport_; }; } // namespace audio diff --git a/system/audio_hal_interface/hal_version_manager_host.cc b/system/audio_hal_interface/hal_version_manager_host.cc index b680ce06ff9bc7449bf7de6682c20f4f3bd82fee..35aadbce98af6397825f80fbe0344dd34df8d72e 100644 --- a/system/audio_hal_interface/hal_version_manager_host.cc +++ b/system/audio_hal_interface/hal_version_manager_host.cc @@ -41,6 +41,7 @@ HalVersionManager::GetProvidersFactory_2_0() { HalVersionManager::HalVersionManager() { hal_version_ = BluetoothAudioHalVersion::VERSION_UNAVAILABLE; + hal_transport_ = BluetoothAudioHalTransport::UNKNOWN; } } // namespace audio diff --git a/system/audio_hal_interface/hfp_client_interface.cc b/system/audio_hal_interface/hfp_client_interface.cc new file mode 100644 index 0000000000000000000000000000000000000000..5613157786fbf5fc6bc3f0fe516a98d3996481d2 --- /dev/null +++ b/system/audio_hal_interface/hfp_client_interface.cc @@ -0,0 +1,467 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "BTAudioClientHfpStub" + +#include "aidl/client_interface_aidl.h" +#include "aidl/hfp_client_interface_aidl.h" +#include "hal_version_manager.h" +#include "hfp_client_interface.h" +#include "osi/include/log.h" +#include "osi/include/properties.h" + +using ::bluetooth::audio::aidl::hfp::HfpDecodingTransport; +using ::bluetooth::audio::aidl::hfp::HfpEncodingTransport; +using AudioConfiguration = + ::aidl::android::hardware::bluetooth::audio::AudioConfiguration; +using ::aidl::android::hardware::bluetooth::audio::ChannelMode; +using ::aidl::android::hardware::bluetooth::audio::CodecId; +using ::aidl::android::hardware::bluetooth::audio::HfpConfiguration; +using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; + +namespace bluetooth { +namespace audio { +namespace hfp { + +// Helper functions +aidl::BluetoothAudioSinkClientInterface* get_decode_client_interface() { + return HfpDecodingTransport::active_hal_interface; +} + +aidl::BluetoothAudioSourceClientInterface* get_encode_client_interface() { + return HfpEncodingTransport::active_hal_interface; +} + +HfpDecodingTransport* get_decode_transport_instance() { + return HfpDecodingTransport::instance_; +} + +HfpDecodingTransport* get_encode_transport_instance() { + return HfpDecodingTransport::instance_; +} + +PcmConfiguration get_default_pcm_configuration() { + PcmConfiguration pcm_config{ + .sampleRateHz = 8000, + .channelMode = ChannelMode::MONO, + .bitsPerSample = 16, + .dataIntervalUs = 7500, + }; + return pcm_config; +} + +HfpConfiguration get_default_hfp_configuration() { + HfpConfiguration hfp_config{ + .codecId = CodecId::Core::CVSD, + .connectionHandle = 6, + .nrec = false, + .controllerCodec = true, + }; + return hfp_config; +} + +CodecId get_codec_id_by_peer_codec(tBTA_AG_PEER_CODEC sco_codec) { + if (sco_codec & BTM_SCO_CODEC_LC3) return CodecId::Core::LC3; + if (sco_codec & BTM_SCO_CODEC_MSBC) return CodecId::Core::MSBC; + if (sco_codec & BTM_SCO_CODEC_CVSD) return CodecId::Core::CVSD; + // Unknown vendor codec otherwise + CodecId codec_id = CodecId::Vendor(); + return codec_id; +} + +AudioConfiguration offload_config_to_hal_audio_config( + const ::hfp::offload_config& offload_config) { + HfpConfiguration hfp_config{ + .codecId = get_codec_id_by_peer_codec(offload_config.sco_codec), + .connectionHandle = offload_config.connection_handle, + .nrec = offload_config.is_nrec, + .controllerCodec = offload_config.is_controller_codec, + }; + return AudioConfiguration(hfp_config); +} + +bool is_hal_enabled() { + return !osi_property_get_bool(BLUETOOTH_AUDIO_HAL_PROP_DISABLED, false); +} + +bool is_aidl_support_hfp() { + return HalVersionManager::GetHalTransport() == + BluetoothAudioHalTransport::AIDL && + HalVersionManager::GetHalVersion() >= + BluetoothAudioHalVersion::VERSION_AIDL_V4; +} + +// Parent client implementation +HfpClientInterface* HfpClientInterface::interface = nullptr; +HfpClientInterface* HfpClientInterface::Get() { + if (!is_hal_enabled()) { + LOG(ERROR) << __func__ << ": BluetoothAudio HAL is disabled"; + return nullptr; + } + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return nullptr; + } + if (HfpClientInterface::interface == nullptr) { + HfpClientInterface::interface = new HfpClientInterface(); + } + return HfpClientInterface::interface; +} + +// Decode client implementation +void HfpClientInterface::Decode::Cleanup() { + LOG(INFO) << __func__ << " decode"; + StopSession(); + if (HfpDecodingTransport::instance_) { + delete HfpDecodingTransport::software_hal_interface; + HfpDecodingTransport::software_hal_interface = nullptr; + delete HfpDecodingTransport::instance_; + HfpDecodingTransport::instance_ = nullptr; + } +} + +void HfpClientInterface::Decode::StartSession() { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + LOG(INFO) << __func__ << " decode"; + AudioConfiguration audio_config; + audio_config.set( + get_default_pcm_configuration()); + if (!get_decode_client_interface()->UpdateAudioConfig(audio_config)) { + LOG(ERROR) << __func__ << ": cannot update audio config to HAL"; + return; + } + get_decode_client_interface()->StartSession(); +} + +void HfpClientInterface::Decode::StopSession() { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + LOG(INFO) << __func__ << " decode"; + get_decode_client_interface()->EndSession(); + if (get_decode_transport_instance()) { + get_decode_transport_instance()->ResetPendingCmd(); + get_decode_transport_instance()->ResetPresentationPosition(); + } +} + +void HfpClientInterface::Decode::UpdateAudioConfigToHal( + const ::hfp::offload_config& offload_config) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + + LOG(WARNING) + << __func__ + << " decode - Unsupported update audio config for software session"; + return; +} + +size_t HfpClientInterface::Decode::Read(uint8_t* p_buf, uint32_t len) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return 0; + } + LOG(INFO) << __func__ << " decode"; + return get_decode_client_interface()->ReadAudioData(p_buf, len); +} + +HfpClientInterface::Decode* HfpClientInterface::GetDecode( + bluetooth::common::MessageLoopThread* message_loop) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return nullptr; + } + + if (decode_ == nullptr) { + decode_ = new Decode(); + } else { + LOG(WARNING) << __func__ << ": Decode is already acquired"; + return nullptr; + } + + LOG(INFO) << __func__ << " decode"; + + HfpDecodingTransport::instance_ = new HfpDecodingTransport( + aidl::SessionType::HFP_SOFTWARE_DECODING_DATAPATH); + HfpDecodingTransport::software_hal_interface = + new aidl::BluetoothAudioSinkClientInterface( + HfpDecodingTransport::instance_, message_loop); + if (!HfpDecodingTransport::software_hal_interface->IsValid()) { + LOG(WARNING) << __func__ << ": BluetoothAudio HAL for HFP is invalid"; + delete HfpDecodingTransport::software_hal_interface; + HfpDecodingTransport::software_hal_interface = nullptr; + delete HfpDecodingTransport::instance_; + HfpDecodingTransport::instance_ = nullptr; + return nullptr; + } + + HfpDecodingTransport::active_hal_interface = + HfpDecodingTransport::software_hal_interface; + + return decode_; +} + +bool HfpClientInterface::ReleaseDecode(HfpClientInterface::Decode* decode) { + if (decode != decode_) { + LOG(WARNING) << __func__ << ", can't release not acquired decode"; + return false; + } + + LOG(INFO) << __func__ << " decode"; + if (get_decode_client_interface()) decode->Cleanup(); + + delete decode_; + decode_ = nullptr; + + return true; +} + +// Encoding client implementation +void HfpClientInterface::Encode::Cleanup() { + LOG(INFO) << __func__ << " encode"; + StopSession(); + if (HfpEncodingTransport::instance_) { + delete HfpEncodingTransport::software_hal_interface; + HfpEncodingTransport::software_hal_interface = nullptr; + delete HfpEncodingTransport::instance_; + HfpEncodingTransport::instance_ = nullptr; + } +} + +void HfpClientInterface::Encode::StartSession() { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + LOG(INFO) << __func__ << " encode"; + AudioConfiguration audio_config; + audio_config.set( + get_default_pcm_configuration()); + if (!get_encode_client_interface()->UpdateAudioConfig(audio_config)) { + LOG(ERROR) << __func__ << ": cannot update audio config to HAL"; + return; + } + get_encode_client_interface()->StartSession(); +} + +void HfpClientInterface::Encode::StopSession() { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + LOG(INFO) << __func__ << " encode"; + get_encode_client_interface()->EndSession(); + if (get_encode_transport_instance()) { + get_encode_transport_instance()->ResetPendingCmd(); + get_encode_transport_instance()->ResetPresentationPosition(); + } +} + +void HfpClientInterface::Encode::UpdateAudioConfigToHal( + const ::hfp::offload_config& offload_config) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + + LOG(WARNING) + << __func__ + << " encode - Unsupported update audio config for software session"; + return; +} + +size_t HfpClientInterface::Encode::Write(const uint8_t* p_buf, uint32_t len) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return 0; + } + LOG(INFO) << __func__ << " encode"; + return get_encode_client_interface()->WriteAudioData(p_buf, len); +} + +HfpClientInterface::Encode* HfpClientInterface::GetEncode( + bluetooth::common::MessageLoopThread* message_loop) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return nullptr; + } + + if (encode_ == nullptr) { + encode_ = new Encode(); + } else { + LOG(WARNING) << __func__ << ": Encoding is already acquired"; + return nullptr; + } + + LOG(INFO) << __func__ << " encode"; + + HfpEncodingTransport::instance_ = new HfpEncodingTransport( + aidl::SessionType::HFP_SOFTWARE_ENCODING_DATAPATH); + HfpEncodingTransport::software_hal_interface = + new aidl::BluetoothAudioSourceClientInterface( + HfpEncodingTransport::instance_, message_loop); + if (!HfpEncodingTransport::software_hal_interface->IsValid()) { + LOG(WARNING) << __func__ << ": BluetoothAudio HAL for HFP is invalid"; + delete HfpEncodingTransport::software_hal_interface; + HfpEncodingTransport::software_hal_interface = nullptr; + delete HfpEncodingTransport::instance_; + HfpEncodingTransport::instance_ = nullptr; + return nullptr; + } + + HfpEncodingTransport::active_hal_interface = + HfpEncodingTransport::software_hal_interface; + + return encode_; +} + +bool HfpClientInterface::ReleaseEncode(HfpClientInterface::Encode* encode) { + if (encode != encode_) { + LOG(WARNING) << __func__ << ", can't release not acquired encode"; + return false; + } + + if (get_encode_client_interface()) encode->Cleanup(); + + delete encode_; + encode_ = nullptr; + + return true; +} + +// Offload client implementation +// Based on HfpEncodingTransport +void HfpClientInterface::Offload::Cleanup() { + LOG(INFO) << __func__ << " offload"; + StopSession(); + if (HfpEncodingTransport::instance_) { + delete HfpEncodingTransport::offloading_hal_interface; + HfpEncodingTransport::offloading_hal_interface = nullptr; + delete HfpEncodingTransport::instance_; + HfpEncodingTransport::instance_ = nullptr; + } +} + +void HfpClientInterface::Offload::StartSession() { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + LOG(INFO) << __func__ << " offload"; + AudioConfiguration audio_config; + audio_config.set( + get_default_hfp_configuration()); + if (!get_encode_client_interface()->UpdateAudioConfig(audio_config)) { + LOG(ERROR) << __func__ << ": cannot update audio config to HAL"; + return; + } + get_encode_client_interface()->StartSession(); +} + +void HfpClientInterface::Offload::StopSession() { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + LOG(INFO) << __func__ << " offload"; + get_encode_client_interface()->EndSession(); + if (get_encode_transport_instance()) { + get_encode_transport_instance()->ResetPendingCmd(); + get_encode_transport_instance()->ResetPresentationPosition(); + } +} + +void HfpClientInterface::Offload::UpdateAudioConfigToHal( + const ::hfp::offload_config& offload_config) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + + LOG(INFO) << __func__ << " offload"; + get_encode_client_interface()->UpdateAudioConfig( + offload_config_to_hal_audio_config(offload_config)); +} + +HfpClientInterface::Offload* HfpClientInterface::GetOffload( + bluetooth::common::MessageLoopThread* message_loop) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return nullptr; + } + + if (offload_ == nullptr) { + offload_ = new Offload(); + } else { + LOG(WARNING) << __func__ << ": Offload is already acquired"; + return nullptr; + } + + LOG(INFO) << __func__ << " offload"; + + // Prepare offload hal interface. + if (bta_ag_get_sco_offload_enabled()) { + HfpEncodingTransport::instance_ = new HfpEncodingTransport( + aidl::SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH); + HfpEncodingTransport::offloading_hal_interface = + new aidl::BluetoothAudioSourceClientInterface( + HfpEncodingTransport::instance_, message_loop); + if (!HfpEncodingTransport::offloading_hal_interface->IsValid()) { + LOG(FATAL) << __func__ + << ": BluetoothAudio HAL for HFP offloading is invalid"; + delete HfpEncodingTransport::offloading_hal_interface; + HfpEncodingTransport::offloading_hal_interface = nullptr; + delete HfpEncodingTransport::instance_; + HfpEncodingTransport::instance_ = static_cast( + HfpEncodingTransport::software_hal_interface->GetTransportInstance()); + delete HfpEncodingTransport::software_hal_interface; + HfpEncodingTransport::software_hal_interface = nullptr; + delete HfpEncodingTransport::instance_; + return nullptr; + } + } + + HfpEncodingTransport::active_hal_interface = + HfpEncodingTransport::offloading_hal_interface; + + return offload_; +} + +bool HfpClientInterface::ReleaseOffload(HfpClientInterface::Offload* offload) { + if (offload != offload_) { + LOG(WARNING) << __func__ << ", can't release not acquired offload"; + return false; + } + + if (get_encode_client_interface()) offload->Cleanup(); + + delete offload_; + offload_ = nullptr; + + return true; +} + +} // namespace hfp +} // namespace audio +} // namespace bluetooth diff --git a/system/audio_hal_interface/hfp_client_interface.h b/system/audio_hal_interface/hfp_client_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..0f52b06acc865aacd36ef82bd79207c3d6be8085 --- /dev/null +++ b/system/audio_hal_interface/hfp_client_interface.h @@ -0,0 +1,104 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "bta/ag/bta_ag_int.h" +#include "common/message_loop_thread.h" + +namespace bluetooth { +namespace audio { +namespace hfp { + +/* + * Client interface for HFP. + * Only available if HFP is managed by AIDL sessions + */ +class HfpClientInterface { + private: + class IClientInterfaceEndpoint { + public: + virtual ~IClientInterfaceEndpoint() = default; + virtual void Cleanup() = 0; + virtual void StartSession() = 0; + virtual void StopSession() = 0; + virtual void UpdateAudioConfigToHal( + const ::hfp::offload_config& config) = 0; + }; + + public: + class Decode : public IClientInterfaceEndpoint { + public: + Decode(){}; + virtual ~Decode() = default; + + void Cleanup() override; + void StartSession() override; + void StopSession() override; + void UpdateAudioConfigToHal(const ::hfp::offload_config& config) override; + size_t Read(uint8_t* p_buf, uint32_t len); + }; + + class Encode : public IClientInterfaceEndpoint { + public: + virtual ~Encode() = default; + + void Cleanup() override; + void StartSession() override; + void StopSession() override; + void UpdateAudioConfigToHal(const ::hfp::offload_config& config) override; + size_t Write(const uint8_t* p_buf, uint32_t len); + }; + + class Offload : public IClientInterfaceEndpoint { + public: + virtual ~Offload() = default; + + void Cleanup() override; + void StartSession() override; + void StopSession() override; + void UpdateAudioConfigToHal(const ::hfp::offload_config& config) override; + }; + + // Get HFP software decoding client interface if it's not previously acquired + // and not yet released. + Decode* GetDecode(bluetooth::common::MessageLoopThread* message_loop); + // Release interface if belongs to HFP client interface + bool ReleaseDecode(Decode* decode); + + // Get HFP software encoding client interface if it's not previously acquired + // and not yet released. + Encode* GetEncode(bluetooth::common::MessageLoopThread* message_loop); + // Release interface if belongs to HFP client interface + bool ReleaseEncode(Encode* encode); + + // Get HFP offload client interface + Offload* GetOffload(bluetooth::common::MessageLoopThread* message_loop); + // Release offload interface if belongs to HFP client interface + bool ReleaseOffload(Offload* offload); + + // Get interface, if previously not initialized - it'll initialize singleton. + static HfpClientInterface* Get(); + + private: + static HfpClientInterface* interface; + Decode* decode_ = nullptr; + Encode* encode_ = nullptr; + Offload* offload_ = nullptr; +}; +} // namespace hfp +} // namespace audio +} // namespace bluetooth 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 5b97465cfe50cbc410b513f04e5306ce2053fcc5..d938c695dd5b40b86a403a77ade644000093ff66 100644 --- a/system/audio_hal_interface/hidl/le_audio_software_hidl.cc +++ b/system/audio_hal_interface/hidl/le_audio_software_hidl.cc @@ -35,6 +35,7 @@ using ::bluetooth::audio::hidl::SessionType_2_1; using ::bluetooth::audio::le_audio::LeAudioClientInterface; using ::bluetooth::audio::le_audio::StartRequestState; +using ::le_audio::DsaMode; /** * Helper utils @@ -175,8 +176,22 @@ void LeAudioTransport::MetadataChanged( LOG(WARNING) << ", invalid number of metadata changed tracks"; return; } + std::vector tracks_vec; + tracks_vec.reserve(track_count); + for (size_t i = 0; i < track_count; i++) { + tracks_vec.push_back({ + .base = + { + .usage = source_metadata.tracks[i].usage, + .content_type = source_metadata.tracks[i].content_type, + .gain = source_metadata.tracks[i].gain, + }, + }); + } + const source_metadata_v7_t source_metadata_v7 = { + .track_count = tracks_vec.size(), .tracks = tracks_vec.data()}; - stream_cb_.on_metadata_update_(source_metadata); + stream_cb_.on_metadata_update_(source_metadata_v7, DsaMode::DISABLED); } void LeAudioTransport::ResetPresentationPosition() { diff --git a/system/audio_hal_interface/hidl/le_audio_software_hidl.h b/system/audio_hal_interface/hidl/le_audio_software_hidl.h index 01bf6faeef9f55a5b5bdb8d548fec88abacd49b4..80051f8d0ae8c53c8723c5bfaa39fac556f41771 100644 --- a/system/audio_hal_interface/hidl/le_audio_software_hidl.h +++ b/system/audio_hal_interface/hidl/le_audio_software_hidl.h @@ -28,7 +28,7 @@ namespace le_audio { using ::android::hardware::bluetooth::audio::V2_1::PcmParameters; using ::bluetooth::audio::hidl::BluetoothAudioCtrlAck; using ::le_audio::set_configurations::AudioSetConfiguration; -using ::le_audio::set_configurations::CodecCapabilitySetting; +using ::le_audio::set_configurations::CodecConfigSetting; using ::bluetooth::audio::le_audio::StartRequestState; diff --git a/system/audio_hal_interface/le_audio_software.cc b/system/audio_hal_interface/le_audio_software.cc index 9abdfd65e7fda07cfd3873ffb2a701d4959a056c..50844ffd71c9844ec4e9c7813b17236442ccf567 100644 --- a/system/audio_hal_interface/le_audio_software.cc +++ b/system/audio_hal_interface/le_audio_software.cc @@ -40,6 +40,7 @@ using AudioConfiguration_2_1 = ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration; using AudioConfigurationAIDL = ::aidl::android::hardware::bluetooth::audio::AudioConfiguration; +using ::aidl::android::hardware::bluetooth::audio::LatencyMode; using ::aidl::android::hardware::bluetooth::audio::LeAudioCodecConfiguration; using ::le_audio::CodecManager; @@ -63,15 +64,6 @@ aidl::BluetoothAudioSinkClientInterface* get_aidl_client_interface( return aidl::le_audio::LeAudioSinkTransport::interface_unicast_; } -int GetAidlInterfaceVersion() { - if (HalVersionManager::GetHalTransport() == - BluetoothAudioHalTransport::HIDL) { - return -1; - } - - return aidl::le_audio::GetAidlInterfaceVersion(); -} - aidl::le_audio::LeAudioSinkTransport* get_aidl_transport_instance( bool is_broadcaster) { if (is_broadcaster) @@ -106,31 +98,47 @@ LeAudioClientInterface* LeAudioClientInterface::Get() { } void LeAudioClientInterface::Sink::Cleanup() { - LOG(INFO) << __func__ << " sink"; + LOG_INFO("HAL transport: 0x%02x, is broadcast: %d", + static_cast(HalVersionManager::GetHalTransport()), + is_broadcaster_); + StopSession(); - if (hidl::le_audio::LeAudioSinkTransport::interface) { - delete hidl::le_audio::LeAudioSinkTransport::interface; - hidl::le_audio::LeAudioSinkTransport::interface = nullptr; - } - if (hidl::le_audio::LeAudioSinkTransport::instance) { - delete hidl::le_audio::LeAudioSinkTransport::instance; - hidl::le_audio::LeAudioSinkTransport::instance = nullptr; - } - if (aidl::le_audio::LeAudioSinkTransport::interface_unicast_) { - delete aidl::le_audio::LeAudioSinkTransport::interface_unicast_; - aidl::le_audio::LeAudioSinkTransport::interface_unicast_ = nullptr; - } - if (aidl::le_audio::LeAudioSinkTransport::interface_broadcast_) { - delete aidl::le_audio::LeAudioSinkTransport::interface_broadcast_; - aidl::le_audio::LeAudioSinkTransport::interface_broadcast_ = nullptr; - } - if (aidl::le_audio::LeAudioSinkTransport::instance_unicast_) { - delete aidl::le_audio::LeAudioSinkTransport::instance_unicast_; - aidl::le_audio::LeAudioSinkTransport::instance_unicast_ = nullptr; - } - if (aidl::le_audio::LeAudioSinkTransport::instance_broadcast_) { - delete aidl::le_audio::LeAudioSinkTransport::instance_broadcast_; - aidl::le_audio::LeAudioSinkTransport::instance_broadcast_ = nullptr; + + /* Cleanup transport interface and instance according to type and role */ + if (HalVersionManager::GetHalTransport() == + BluetoothAudioHalTransport::HIDL) { + if (hidl::le_audio::LeAudioSinkTransport::interface) { + delete hidl::le_audio::LeAudioSinkTransport::interface; + hidl::le_audio::LeAudioSinkTransport::interface = nullptr; + } + if (hidl::le_audio::LeAudioSinkTransport::instance) { + delete hidl::le_audio::LeAudioSinkTransport::instance; + hidl::le_audio::LeAudioSinkTransport::instance = nullptr; + } + } else if (HalVersionManager::GetHalTransport() == + BluetoothAudioHalTransport::AIDL) { + if (IsBroadcaster()) { + if (aidl::le_audio::LeAudioSinkTransport::interface_broadcast_) { + delete aidl::le_audio::LeAudioSinkTransport::interface_broadcast_; + aidl::le_audio::LeAudioSinkTransport::interface_broadcast_ = nullptr; + } + if (aidl::le_audio::LeAudioSinkTransport::instance_broadcast_) { + delete aidl::le_audio::LeAudioSinkTransport::instance_broadcast_; + aidl::le_audio::LeAudioSinkTransport::instance_broadcast_ = nullptr; + } + } else { + if (aidl::le_audio::LeAudioSinkTransport::interface_unicast_) { + delete aidl::le_audio::LeAudioSinkTransport::interface_unicast_; + aidl::le_audio::LeAudioSinkTransport::interface_unicast_ = nullptr; + } + if (aidl::le_audio::LeAudioSinkTransport::instance_unicast_) { + delete aidl::le_audio::LeAudioSinkTransport::instance_unicast_; + aidl::le_audio::LeAudioSinkTransport::instance_unicast_ = nullptr; + } + } + } else { + LOG_ERROR("Invalid HAL transport: 0x%02x", + static_cast(HalVersionManager::GetHalTransport())); } } @@ -175,8 +183,8 @@ void LeAudioClientInterface::Sink::StartSession() { } hidl::le_audio::LeAudioSinkTransport::interface->StartSession_2_1(); return; - } else if (HalVersionManager::GetHalVersion() == - BluetoothAudioHalVersion::VERSION_AIDL_V1) { + } else if (HalVersionManager::GetHalTransport() == + BluetoothAudioHalTransport::AIDL) { AudioConfigurationAIDL audio_config; if (is_aidl_offload_encoding_session(is_broadcaster_)) { if (is_broadcaster_) { @@ -440,8 +448,8 @@ void LeAudioClientInterface::Source::StartSession() { } hidl::le_audio::LeAudioSourceTransport::interface->StartSession_2_1(); return; - } else if (HalVersionManager::GetHalVersion() == - BluetoothAudioHalVersion::VERSION_AIDL_V1) { + } else if (HalVersionManager::GetHalTransport() == + BluetoothAudioHalTransport::AIDL) { AudioConfigurationAIDL audio_config; if (aidl::le_audio::LeAudioSourceTransport:: interface->GetTransportInstance() @@ -861,6 +869,38 @@ bool LeAudioClientInterface::ReleaseSource( return true; } +void LeAudioClientInterface::SetAllowedDsaModes(DsaModes dsa_modes) { + if (HalVersionManager::GetHalTransport() == + BluetoothAudioHalTransport::AIDL) { + std::vector latency_modes; + for (auto dsa_mode : dsa_modes) { + switch (dsa_mode) { + case DsaMode::DISABLED: + latency_modes.push_back(LatencyMode::FREE); + break; + case DsaMode::ACL: + latency_modes.push_back(LatencyMode::LOW_LATENCY); + break; + case DsaMode::ISO_SW: + latency_modes.push_back(LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE); + break; + case DsaMode::ISO_HW: + latency_modes.push_back(LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE); + break; + default: + LOG(WARNING) << "Unsupported latency mode ignored: " << (int)dsa_mode; + break; + } + } + if (aidl::le_audio::LeAudioSourceTransport::interface) { + aidl::le_audio::LeAudioSourceTransport::interface->SetAllowedLatencyModes( + latency_modes); + } else { + LOG(WARNING) << "LeAudioSourceTransport::interface is null"; + } + } +} + } // namespace le_audio } // namespace audio } // namespace bluetooth diff --git a/system/audio_hal_interface/le_audio_software.h b/system/audio_hal_interface/le_audio_software.h index 9102a14da798749dc1e7789c0c94f5d59bdb7eca..4544387abb720a2e68ae90378fcd76790744ce54 100644 --- a/system/audio_hal_interface/le_audio_software.h +++ b/system/audio_hal_interface/le_audio_software.h @@ -16,7 +16,11 @@ #pragma once +#ifdef TARGET_FLOSS +#include +#else #include +#endif #include @@ -28,6 +32,9 @@ namespace bluetooth { namespace audio { namespace le_audio { +using ::le_audio::DsaMode; +using ::le_audio::DsaModes; + enum class StartRequestState { IDLE = 0x00, PENDING_BEFORE_RESUME, @@ -53,13 +60,12 @@ constexpr uint8_t kBitsPerSample32 = 32; struct StreamCallbacks { std::function on_resume_; std::function on_suspend_; - std::function on_metadata_update_; - std::function on_sink_metadata_update_; + std::function on_metadata_update_; + std::function on_sink_metadata_update_; }; std::vector<::le_audio::set_configurations::AudioSetConfiguration> get_offload_capabilities(); -int GetAidlInterfaceVersion(); class LeAudioClientInterface { public: @@ -153,7 +159,11 @@ class LeAudioClientInterface { // Release source interface if belongs to LE audio client interface bool ReleaseSource(Source* source); - // Get interface, if previously not initialized - it'll initialize singleton. + // Sets Dynamic Spatial Audio modes supported by the remote device + void SetAllowedDsaModes(DsaModes dsa_modes); + + // Get interface, if previously not initialized - it'll initialize + // singleton. static LeAudioClientInterface* Get(); private: diff --git a/system/audio_hal_interface/le_audio_software_host.cc b/system/audio_hal_interface/le_audio_software_host.cc index cd3ace10d4209c6056db006ec6067c399cf18978..bb2a3952361b51a798d1a07fe955ce2ef1822f35 100644 --- a/system/audio_hal_interface/le_audio_software_host.cc +++ b/system/audio_hal_interface/le_audio_software_host.cc @@ -15,7 +15,6 @@ * limitations under the License. */ -#include "audio_hal_interface/hal_version_manager.h" #include "audio_hal_interface/le_audio_software.h" #include "bta/le_audio/codec_manager.h" @@ -72,7 +71,7 @@ bool LeAudioClientInterface::ReleaseSource( return false; } -int GetAidlInterfaceVersion() { return 0; } +void LeAudioClientInterface::SetAllowedDsaModes(DsaModes dsa_modes) { return; } } // namespace le_audio } // namespace audio diff --git a/system/audio_hearing_aid_hw/Android.bp b/system/audio_hearing_aid_hw/Android.bp index 90ea13649c2f26168e8b193c1a646080248bb69c..920bfa7a0b8f5d0a09067a8c92ef2a5ed9f50fb8 100644 --- a/system/audio_hearing_aid_hw/Android.bp +++ b/system/audio_hearing_aid_hw/Android.bp @@ -9,7 +9,7 @@ package { cc_defaults { name: "audio_hearing_aid_hw_defaults", - defaults: ["fluoride_common_options"], + defaults: ["bluetooth_cflags"], shared_libs: ["libchrome"], include_dirs: [ "packages/modules/Bluetooth/system", @@ -40,10 +40,9 @@ cc_library { // Audio A2DP library unit tests for target and host cc_test { name: "net_test_audio_hearing_aid_hw", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ "audio_hearing_aid_hw_defaults", - "bluetooth_gtest_x86_asan_workaround", "mts_defaults", ], srcs: [ diff --git a/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc b/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc index a373d171af7fed00618fbac5cb2177564f1e6f50..9ee73b28c2e8d94a4aa73fa631cc330f6a9352f1 100644 --- a/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc +++ b/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc @@ -20,30 +20,28 @@ #define LOG_TAG "bt_hearing_aid_hw" -#include +#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" + #include +#include +#include #include +#include #include -#include #include #include #include #include +#include #include +#include #include -#include -#include -#include -#include - #include "osi/include/hash_map_utils.h" #include "osi/include/osi.h" #include "osi/include/socket_utils/sockets.h" -#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" - /***************************************************************************** * Constants & Macros *****************************************************************************/ diff --git a/system/binder/android/os/parcel_uuid.cc b/system/binder/android/os/parcel_uuid.cc deleted file mode 100644 index ea97104bc26ab2e2e10fd089a2ba03fd7ac4bb0d..0000000000000000000000000000000000000000 --- a/system/binder/android/os/parcel_uuid.cc +++ /dev/null @@ -1,81 +0,0 @@ -// -// Copyright 2017, The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "android/os/parcel_uuid.h" - -using android::OK; -using android::Parcel; -using android::status_t; -using ::bluetooth::Uuid; - -namespace android { -namespace os { - -namespace { -static uint64_t uuid_lsb(const Uuid& uuid) { - uint64_t lsb = 0; - - auto uu = uuid.To128BitBE(); - for (int i = 8; i <= 15; i++) { - lsb <<= 8; - lsb |= uu[i]; - } - - return lsb; -} - -static uint64_t uuid_msb(const Uuid& uuid) { - uint64_t msb = 0; - - auto uu = uuid.To128BitBE(); - for (int i = 0; i <= 7; i++) { - msb <<= 8; - msb |= uu[i]; - } - - return msb; -} -} // namespace - -status_t ParcelUuid::writeToParcel(Parcel* parcel) const { - status_t status = parcel->writeInt64(uuid_msb(uuid)); - if (status != OK) return status; - - status = parcel->writeInt64(uuid_lsb(uuid)); - return status; -} - -status_t ParcelUuid::readFromParcel(const Parcel* parcel) { - int64_t uuid_msb, uuid_lsb; - - status_t status = parcel->readInt64(&uuid_msb); - if (status != OK) return status; - - status = parcel->readInt64(&uuid_lsb); - if (status != OK) return status; - - std::array uu; - for (int i = 0; i < 8; i++) { - uu[7 - i] = (uuid_msb >> (8 * i)) & 0xFF; - uu[15 - i] = (uuid_lsb >> (8 * i)) & 0xFF; - } - - uuid = Uuid::From128BitBE(uu); - return OK; -} - -} // namespace os -} // namespace android \ No newline at end of file diff --git a/system/binder/android/os/parcel_uuid.h b/system/binder/android/os/parcel_uuid.h deleted file mode 100644 index 76bf9c4b76dbd0971651a21cf65a7bf9dfc4b17b..0000000000000000000000000000000000000000 --- a/system/binder/android/os/parcel_uuid.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright 2017, The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#pragma once - -#include -#include -#include - -namespace android { -namespace os { - -class ParcelUuid : public android::Parcelable { - public: - ParcelUuid() = default; - ~ParcelUuid() = default; - - // Write |this| parcelable to the given |parcel|. Keep in mind that - // implementations of writeToParcel must be manually kept in sync - // with readFromParcel and the Java equivalent versions of these methods. - // - // Returns android::OK on success and an appropriate error otherwise. - android::status_t writeToParcel(android::Parcel* parcel) const override; - - // Read data from the given |parcel| into |this|. After readFromParcel - // completes, |this| should have equivalent state to the object that - // wrote itself to the parcel. - // - // Returns android::OK on success and an appropriate error otherwise. - android::status_t readFromParcel(const android::Parcel* parcel) override; - - ::bluetooth::Uuid uuid; -}; - -} // namespace os -} // namespace android diff --git a/system/blueberry/facade/topshim/facade.proto b/system/blueberry/facade/topshim/facade.proto index 6f935631e7c96103ede7541ad9666f6e331b944a..b7e5cb7de7b7f4f710d89005918279b07ae227bb 100644 --- a/system/blueberry/facade/topshim/facade.proto +++ b/system/blueberry/facade/topshim/facade.proto @@ -208,7 +208,7 @@ message StopSlcResponse { message ConnectAudioRequest { Connection connection = 1; bool is_sco_offload_enabled = 2; - bool force_cvsd = 3; + int32 disabled_codecs = 3; } message ConnectAudioResponse { @@ -267,4 +267,4 @@ message CreateBondRequest { message CreateBondResponse { int32 status = 1; -} \ No newline at end of file +} diff --git a/system/blueberry/tests/gd/cert/gd_device.py b/system/blueberry/tests/gd/cert/gd_device.py index f3accd89c4423d80a66e66d89817ffab128f2293..772460122ed81c9b7eb27486121926af4461d3d3 100644 --- a/system/blueberry/tests/gd/cert/gd_device.py +++ b/system/blueberry/tests/gd/cert/gd_device.py @@ -203,18 +203,21 @@ class GdDeviceBase(ABC): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + + self.backing_process_logger = AsyncSubprocessLogger( + self.backing_process, [self.backing_process_log_path], + log_to_stdout=self.verbose_mode, + tag=self.label, + color=self.terminal_color) + asserts.assert_true( self.backing_process, msg="[%s] failed to open backing process for %s" % (self.type_identifier, self.label)) self.is_backing_process_alive = is_subprocess_alive(self.backing_process) + asserts.assert_true( self.is_backing_process_alive, msg="[%s] backing process for %s died after starting" % (self.type_identifier, self.label)) - self.backing_process_logger = AsyncSubprocessLogger( - self.backing_process, [self.backing_process_log_path], - log_to_stdout=self.verbose_mode, - tag=self.label, - color=self.terminal_color) # If gRPC root server port is not specified, we can skip settings up the root server if self.grpc_root_server_port != -1: @@ -523,7 +526,6 @@ class GdAndroidDevice(GdDeviceBase): self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libcutils.so"), overwrite_existing=False) self.push_or_die( *generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libgrpc_wrap.so"), overwrite_existing=False) - self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libgrpc++_unsecure.so")) self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libgrpc++.so")) self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libhidlbase.so"), overwrite_existing=False) self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "liblog.so"), overwrite_existing=False) diff --git a/system/blueberry/tests/gd/cert/matchers.py b/system/blueberry/tests/gd/cert/matchers.py index 3be05977d2a8ea9113724caf30b4bb555aa065b7..e438b7bbce3a19c0d4e60276717a718fd47a8465 100644 --- a/system/blueberry/tests/gd/cert/matchers.py +++ b/system/blueberry/tests/gd/cert/matchers.py @@ -183,10 +183,6 @@ class HciMatchers(object): def UserConfirmationRequest(): return HciMatchers.EventWithCode(hci.EventCode.USER_CONFIRMATION_REQUEST) - @staticmethod - def RemoteHostSupportedFeaturesNotification(): - return HciMatchers.EventWithCode(hci.EventCode.REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION) - @staticmethod def LinkKeyNotification(): return HciMatchers.EventWithCode(hci.EventCode.LINK_KEY_NOTIFICATION) diff --git a/system/blueberry/tests/gd/cert/py_neighbor.py b/system/blueberry/tests/gd/cert/py_neighbor.py index 1617cda647f111d8112ce76bfe057f5afdb1de25..1352d61a12f00ba529afedb1099cf8eb82bc0272 100644 --- a/system/blueberry/tests/gd/cert/py_neighbor.py +++ b/system/blueberry/tests/gd/cert/py_neighbor.py @@ -53,7 +53,6 @@ class PyNeighbor(object): def __init__(self, device): self.device = device - self.remote_host_supported_features_notification_registered = False def set_inquiry_mode(self, inquiry_msg): """ diff --git a/system/blueberry/tests/gd/iso/le_iso_test.py b/system/blueberry/tests/gd/iso/le_iso_test.py index b31091d4c8c183e477f9ce7c5c4daa8e8d09f9ed..ff7dbab8c57e49338958011a11b4648154179ff1 100644 --- a/system/blueberry/tests/gd/iso/le_iso_test.py +++ b/system/blueberry/tests/gd/iso/le_iso_test.py @@ -127,12 +127,12 @@ class LeIsoTest(gd_base_test.GdBaseTestClass): packing = 0 framing = 0 max_transport_latency_m_to_s = 0 - max_transport_latency_s_to_m = 0 + max_transport_latency_s_to_m = 7 cis_id = 0x01 - max_sdu_m_to_s = 100 + max_sdu_m_to_s = 0 max_sdu_s_to_m = 100 phy_m_to_s = 0x02 - phy_s_to_m = 0x00 + phy_s_to_m = 0x02 bn_m_to_s = 0 bn_s_to_m = 2 @@ -159,13 +159,13 @@ class LeIsoTest(gd_base_test.GdBaseTestClass): peripherals_clock_accuracy = 0 packing = 0 framing = 0 - max_transport_latency_m_to_s = 0 - max_transport_latency_s_to_m = 0 + max_transport_latency_m_to_s = 30 + max_transport_latency_s_to_m = 30 cis_id = 0x01 max_sdu_m_to_s = 100 max_sdu_s_to_m = 100 phy_m_to_s = 0x02 - phy_s_to_m = 0x00 + phy_s_to_m = 0x02 bn_m_to_s = 3 bn_s_to_m = 1 @@ -193,12 +193,12 @@ class LeIsoTest(gd_base_test.GdBaseTestClass): packing = 0 framing = 1 max_transport_latency_m_to_s = 0 - max_transport_latency_s_to_m = 0 + max_transport_latency_s_to_m = 21 cis_id = 0x01 - max_sdu_m_to_s = 100 + max_sdu_m_to_s = 0 max_sdu_s_to_m = 100 phy_m_to_s = 0x02 - phy_s_to_m = 0x00 + phy_s_to_m = 0x02 bn_m_to_s = 0 bn_s_to_m = 2 @@ -225,13 +225,13 @@ class LeIsoTest(gd_base_test.GdBaseTestClass): peripherals_clock_accuracy = 0 packing = 0 framing = 1 - max_transport_latency_m_to_s = 0 - max_transport_latency_s_to_m = 0 + max_transport_latency_m_to_s = 6 + max_transport_latency_s_to_m = 6 cis_id = 0x01 max_sdu_m_to_s = 100 max_sdu_s_to_m = 100 phy_m_to_s = 0x02 - phy_s_to_m = 0x00 + phy_s_to_m = 0x02 bn_m_to_s = 1 bn_s_to_m = 1 diff --git a/system/blueberry/tests/gd/l2cap/classic/cert_l2cap.py b/system/blueberry/tests/gd/l2cap/classic/cert_l2cap.py index 21137a86fd52a7e120aad29647756ee493c81ffb..513f7e6d75df290f31aed7eff24bef64ad91eceb 100644 --- a/system/blueberry/tests/gd/l2cap/classic/cert_l2cap.py +++ b/system/blueberry/tests/gd/l2cap/classic/cert_l2cap.py @@ -15,6 +15,7 @@ # limitations under the License. import logging +from queue import SimpleQueue from blueberry.tests.gd.cert.behavior import IHasBehaviors, SingleArgumentBehavior, ReplyStage from blueberry.tests.gd.cert.captures import L2capCaptures @@ -151,7 +152,7 @@ class CertL2capControlChannelBehaviors(object): def _send_configuration_response(self, request, result=ConfigurationResponseResult.SUCCESS, options=None): dcid = request.GetDestinationCid() if dcid not in self.parent.scid_to_channel: - logging.warning("Received config request with unknown dcid") + logging.warning("_send_configuration_response with unknown dcid 0x{:X}".format(dcid)) return self.parent.scid_to_channel[dcid].send_configuration_response(request, result, options) @@ -172,6 +173,7 @@ class CertL2cap(Closable, IHasBehaviors): CommandCode.INFORMATION_REQUEST: self._on_information_request_default, CommandCode.INFORMATION_RESPONSE: self._on_information_response_default } + self.pending_configuration_requests = SimpleQueue() self.scid_to_channel = {} @@ -191,8 +193,12 @@ class CertL2cap(Closable, IHasBehaviors): def connect_acl(self, remote_addr): self._acl_manager.initiate_connection(remote_addr) self._acl = self._acl_manager.complete_outgoing_connection() - self.control_channel = CertL2capChannel( - self._device, 1, 1, self._acl.acl_stream, self._acl, control_channel=None) + self.control_channel = CertL2capChannel(self._device, + 1, + 1, + self._acl.acl_stream, + self._acl, + control_channel=None) self._acl.acl_stream.register_callback(self._handle_control_packet) def accept_incoming_connection(self): @@ -208,11 +214,17 @@ class CertL2cap(Closable, IHasBehaviors): response.get().GetDestinationCid(), self._acl.acl_stream, self._acl, self.control_channel, fcs) self.scid_to_channel[scid] = channel + logging.debug("Opened channel for PSM 0x{:X} SCID 0x{:X} DCID 0x{:X}".format( + psm, scid, + response.get().GetDestinationCid())) + while not self.pending_configuration_requests.empty(): + l2cap_control_view = self.pending_configuration_requests.get_nowait() + logging.info("Handling deferred configuration requests") + self._on_configuration_request_default(l2cap_control_view, defer_unknown_dcid=False) return channel def verify_and_respond_open_channel_from_remote(self, psm=0x33, scid=None, fcs=None): - request = L2capCaptures.ConnectionRequest(psm) assertThat(self.control_channel).emits(request) @@ -259,18 +271,22 @@ class CertL2cap(Closable, IHasBehaviors): def get_control_channel(self): return self.control_channel - # Disable ERTM when exchange extened feature + # Disable ERTM when exchange extended feature def claim_ertm_unsupported(self): self.support_ertm = False def _on_connection_response_default(self, l2cap_control_view): pass - def _on_configuration_request_default(self, l2cap_control_view): + def _on_configuration_request_default(self, l2cap_control_view, defer_unknown_dcid=True): request = l2cap_packets.ConfigurationRequestView(l2cap_control_view) dcid = request.GetDestinationCid() if dcid not in self.scid_to_channel: - logging.warning("Received config request with unknown dcid") + if defer_unknown_dcid: + logging.info("Received config request with unknown dcid 0x{:X} deferring".format(dcid)) + self.pending_configuration_requests.put(l2cap_control_view) + else: + logging.warning("Received config request with unknown dcid 0x{:X}".format(dcid)) return self._control_behaviors.on_config_req_behavior.run(request) diff --git a/system/blueberry/tests/gd/security/cert_security.py b/system/blueberry/tests/gd/security/cert_security.py index eb32f0deaff5c40ebd892a1ae6990e7ee51fe534..37528554a3856d4a6a6faab70fb7dd708f5c49cd 100644 --- a/system/blueberry/tests/gd/security/cert_security.py +++ b/system/blueberry/tests/gd/security/cert_security.py @@ -90,15 +90,16 @@ class CertSecurity(PySecurity): self._device = device self._device.wait_channel_ready() self._hci = PyHci(device) - self._hci.register_for_events( - hci.EventCode.ENCRYPTION_CHANGE, hci.EventCode.CHANGE_CONNECTION_LINK_KEY_COMPLETE, - hci.EventCode.CENTRAL_LINK_KEY_COMPLETE, hci.EventCode.RETURN_LINK_KEYS, hci.EventCode.PIN_CODE_REQUEST, - hci.EventCode.LINK_KEY_REQUEST, hci.EventCode.LINK_KEY_NOTIFICATION, - hci.EventCode.ENCRYPTION_KEY_REFRESH_COMPLETE, hci.EventCode.IO_CAPABILITY_REQUEST, - hci.EventCode.IO_CAPABILITY_RESPONSE, hci.EventCode.REMOTE_OOB_DATA_REQUEST, - hci.EventCode.SIMPLE_PAIRING_COMPLETE, hci.EventCode.USER_PASSKEY_NOTIFICATION, - hci.EventCode.KEYPRESS_NOTIFICATION, hci.EventCode.USER_CONFIRMATION_REQUEST, - hci.EventCode.USER_PASSKEY_REQUEST, hci.EventCode.REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION) + self._hci.register_for_events(hci.EventCode.ENCRYPTION_CHANGE, + hci.EventCode.CHANGE_CONNECTION_LINK_KEY_COMPLETE, + hci.EventCode.CENTRAL_LINK_KEY_COMPLETE, hci.EventCode.RETURN_LINK_KEYS, + hci.EventCode.PIN_CODE_REQUEST, hci.EventCode.LINK_KEY_REQUEST, + hci.EventCode.LINK_KEY_NOTIFICATION, + hci.EventCode.ENCRYPTION_KEY_REFRESH_COMPLETE, + hci.EventCode.IO_CAPABILITY_REQUEST, hci.EventCode.IO_CAPABILITY_RESPONSE, + hci.EventCode.REMOTE_OOB_DATA_REQUEST, hci.EventCode.SIMPLE_PAIRING_COMPLETE, + hci.EventCode.USER_PASSKEY_NOTIFICATION, hci.EventCode.KEYPRESS_NOTIFICATION, + hci.EventCode.USER_CONFIRMATION_REQUEST, hci.EventCode.USER_PASSKEY_REQUEST) self._hci_event_stream = self._hci.get_event_stream() def create_bond(self, address, type): @@ -232,7 +233,7 @@ class CertSecurity(PySecurity): self._enqueue_hci_command( hci.SendKeypressNotification(bd_addr=peer, notification_type=hci.KeypressNotificationType.ENTRY_COMPLETED), True) - self._enqueue_hci_command(hci.UserPasskeyRequestReply(bd_addr=peer, numerical_value=passkey), True) + self._enqueue_hci_command(hci.UserPasskeyRequestReply(bd_addr=peer, numeric_value=passkey), True) def input_pin(self, address, pin): """ diff --git a/system/blueberry/tests/gd/security/le_security_test.py b/system/blueberry/tests/gd/security/le_security_test.py index 824c39bbda4cc8bfb6b5ed0fd3764fae17ab129c..6368c30f43407901faf34ba630de59f8dd76b8ae 100644 --- a/system/blueberry/tests/gd/security/le_security_test.py +++ b/system/blueberry/tests/gd/security/le_security_test.py @@ -14,7 +14,7 @@ # limitations under the License. import hci_packets as hci -from bluetooth_packets_python3.security_packets import PairingFailedReason +import smp_packets as smp from blueberry.tests.gd.cert.matchers import SecurityMatchers from blueberry.tests.gd.cert.metadata import metadata from blueberry.tests.gd.cert.py_hci import PyHci @@ -585,7 +585,7 @@ class LeSecurityTest(gd_base_test.GdBaseTestClass): # 3. IUT transmits the Pairing Failed command. assertThat(self.dut_security.get_bond_stream()).emits( SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.cert_address, - int(PairingFailedReason.ENCRYPTION_KEY_SIZE))) + int(smp.PairingFailedReason.ENCRYPTION_KEY_SIZE))) @metadata(pts_test_id="SM/SLA/EKS/BI-02-C", pts_test_name="IUT Responder, Lower Tester Maximum Encryption Key Size < Min_Encryption_Key_Length") @@ -622,7 +622,7 @@ class LeSecurityTest(gd_base_test.GdBaseTestClass): #3. IUT transmits the Pairing Failed command. assertThat(self.cert_security.get_bond_stream()).emits( SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.dut_address, - int(PairingFailedReason.ENCRYPTION_KEY_SIZE))) + int(smp.PairingFailedReason.ENCRYPTION_KEY_SIZE))) @metadata(pts_test_id="SM/MAS/SCPK/BV-01-C", pts_test_name="Passkey Entry, IUT Initiator, Secure Connections – Success") diff --git a/system/blueberry/tests/sl4a_sl4a/gatt/gatt_connect_test.py b/system/blueberry/tests/sl4a_sl4a/gatt/gatt_connect_test.py index db9186094e872af0c49c2c61520d2ed703d0bdb8..2fc1025e7d66bc9235ef0803c95652f88ee5b1ce 100644 --- a/system/blueberry/tests/sl4a_sl4a/gatt/gatt_connect_test.py +++ b/system/blueberry/tests/sl4a_sl4a/gatt/gatt_connect_test.py @@ -63,6 +63,10 @@ class GattConnectTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): default_timeout = 10 default_discovery_timeout = 3 + ADDR_TYPE_PUBLIC = 0 + ADDR_TYPE_RPA = 1 + ADDR_TYPE_NRPA = 2 + def setup_class(self): super().setup_class() self.central = self.dut @@ -265,7 +269,7 @@ class GattConnectTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): self.gatt_server_list.append(gatt_server) autoconnect = False mac_address, adv_callback, scan_callback = (get_mac_address_of_generic_advertisement( - self.central, self.peripheral)) + self.central, self.peripheral, self.ADDR_TYPE_PUBLIC)) self.adv_instances.append(adv_callback) self.central.log.info("Discovered BLE advertisement, connecting GATT with autoConnect={}".format(autoconnect)) try: @@ -292,8 +296,9 @@ class GattConnectTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): return autoconnect = True self.central.log.info("Connecting GATT with autoConnect={}".format(autoconnect)) - bluetooth_gatt = self.central.sl4a.gattClientConnectGatt( - gatt_callback, mac_address, autoconnect, GattTransport.TRANSPORT_AUTO, False, GattPhyMask.PHY_LE_1M_MASK) + bluetooth_gatt = self.central.sl4a.gattClientConnectGatt(gatt_callback, mac_address, autoconnect, + GattTransport.TRANSPORT_LE, False, + GattPhyMask.PHY_LE_1M_MASK) self.central.log.info("Waiting for GATt to become connected") self.bluetooth_gatt_list.append(bluetooth_gatt) expected_event = GattCallbackString.GATT_CONN_CHANGE.format(gatt_callback) @@ -344,8 +349,11 @@ class GattConnectTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): self.central, self.peripheral)) # Make GATT connection 1 try: - bluetooth_gatt_1, gatt_callback_1 = setup_gatt_connection( - self.central, mac_address, False, transport=GattTransport.TRANSPORT_AUTO, opportunistic=False) + bluetooth_gatt_1, gatt_callback_1 = setup_gatt_connection(self.central, + mac_address, + False, + transport=GattTransport.TRANSPORT_AUTO, + opportunistic=False) self.central.sl4a.bleStopBleScan(scan_callback) self.adv_instances.append(adv_callback) self.bluetooth_gatt_list.append(bluetooth_gatt_1) @@ -355,8 +363,11 @@ class GattConnectTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): return # Make GATT connection 2 try: - bluetooth_gatt_2, gatt_callback_2 = setup_gatt_connection( - self.central, mac_address, False, transport=GattTransport.TRANSPORT_AUTO, opportunistic=True) + bluetooth_gatt_2, gatt_callback_2 = setup_gatt_connection(self.central, + mac_address, + False, + transport=GattTransport.TRANSPORT_AUTO, + opportunistic=True) self.bluetooth_gatt_list.append(bluetooth_gatt_2) except GattTestUtilsError as err: logging.error(err) @@ -378,96 +389,6 @@ class GattConnectTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): if bluetooth_gatt_2 in self.bluetooth_gatt_list: self.bluetooth_gatt_list.remove(bluetooth_gatt_2) - @test_tracker_info(uuid='1e01838e-c4de-4720-9adf-9e0419378226') - def test_gatt_request_min_mtu(self): - """Test GATT connection over LE and exercise MTU sizes. - - Test establishing a gatt connection between a GATT server and GATT - client. Request an MTU size that matches the correct minimum size. - - Steps: - 1. Start a generic advertisement. - 2. Start a generic scanner. - 3. Find the advertisement and extract the mac address. - 4. Stop the first scanner. - 5. Create a GATT connection between the scanner and advertiser. - 6. From the scanner (client) request MTU size change to the - minimum value. - 7. Find the MTU changed event on the client. - 8. Disconnect the GATT connection. - - Expected Result: - Verify that a connection was established and the MTU value found - matches the expected MTU value. - - Returns: - Pass if True - Fail if False - - TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU - Priority: 0 - """ - gatt_server_cb = self.peripheral.sl4a.gattServerCreateGattServerCallback() - gatt_server = self.peripheral.sl4a.gattServerOpenGattServer(gatt_server_cb) - self.gatt_server_list.append(gatt_server) - try: - bluetooth_gatt, gatt_callback, adv_callback = (orchestrate_gatt_connection(self.central, self.peripheral)) - self.bluetooth_gatt_list.append(bluetooth_gatt) - except GattTestUtilsError as err: - logging.error(err) - asserts.fail("Failed to connect to GATT, error: {}".format(err)) - return - self.adv_instances.append(adv_callback) - expected_mtu = GattMtuSize.MIN - self.central.sl4a.gattClientRequestMtu(bluetooth_gatt, expected_mtu) - assertThat(self._verify_mtu_changed_on_client_and_server(expected_mtu, gatt_callback, gatt_server_cb)).isTrue() - assertThat(self._orchestrate_gatt_disconnection(bluetooth_gatt, gatt_callback)).isTrue() - - @test_tracker_info(uuid='c1fa3a2d-fb47-47db-bdd1-458928cd6a5f') - def test_gatt_request_max_mtu(self): - """Test GATT connection over LE and exercise MTU sizes. - - Test establishing a gatt connection between a GATT server and GATT - client. Request an MTU size that matches the correct maximum size. - - Steps: - 1. Start a generic advertisement. - 2. Start a generic scanner. - 3. Find the advertisement and extract the mac address. - 4. Stop the first scanner. - 5. Create a GATT connection between the scanner and advertiser. - 6. From the scanner (client) request MTU size change to the - maximum value. - 7. Find the MTU changed event on the client. - 8. Disconnect the GATT connection. - - Expected Result: - Verify that a connection was established and the MTU value found - matches the expected MTU value. - - Returns: - Pass if True - Fail if False - - TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU - Priority: 0 - """ - gatt_server_cb = self.peripheral.sl4a.gattServerCreateGattServerCallback() - gatt_server = self.peripheral.sl4a.gattServerOpenGattServer(gatt_server_cb) - self.gatt_server_list.append(gatt_server) - try: - bluetooth_gatt, gatt_callback, adv_callback = (orchestrate_gatt_connection(self.central, self.peripheral)) - self.bluetooth_gatt_list.append(bluetooth_gatt) - except GattTestUtilsError as err: - logging.error(err) - asserts.fail("Failed to connect to GATT, error: {}".format(err)) - return - self.adv_instances.append(adv_callback) - expected_mtu = GattMtuSize.MAX - self.central.sl4a.gattClientRequestMtu(bluetooth_gatt, expected_mtu) - assertThat(self._verify_mtu_changed_on_client_and_server(expected_mtu, gatt_callback, gatt_server_cb)).isTrue() - assertThat(self._orchestrate_gatt_disconnection(bluetooth_gatt, gatt_callback)).isTrue() - @test_tracker_info(uuid='4416d483-dec3-46cb-8038-4d82620f873a') def test_gatt_request_out_of_bounds_mtu(self): """Test GATT connection over LE and exercise an out of bound MTU size. @@ -933,7 +854,8 @@ class GattConnectTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): conn_cen_devices = self.central.sl4a.bluetoothGetConnectedLeDevices(BluetoothProfile.GATT) conn_per_devices = self.peripheral.sl4a.bluetoothGetConnectedLeDevices(BluetoothProfile.GATT_SERVER) target_name = self.peripheral.sl4a.bluetoothGetLocalName() - error_message = ("Connected device {} not found in list of connected " "devices {}") + error_message = ("Connected device {} not found in list of connected " + "devices {}") if not any(d['name'] == target_name for d in conn_cen_devices): logging.error(error_message.format(target_name, conn_cen_devices)) asserts.fail(error_message.format(target_name, conn_cen_devices)) diff --git a/system/blueberry/tests/sl4a_sl4a/gatt/gatt_connect_with_irk_test.py b/system/blueberry/tests/sl4a_sl4a/gatt/gatt_connect_with_irk_test.py index eab98feeaf0a6c70c6e8d8d1a9bf2d58210d0772..eb96468da7facba517ce5b758e86b0262378cefa 100644 --- a/system/blueberry/tests/sl4a_sl4a/gatt/gatt_connect_with_irk_test.py +++ b/system/blueberry/tests/sl4a_sl4a/gatt/gatt_connect_with_irk_test.py @@ -111,8 +111,8 @@ class GattConnectWithIrkTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): # Set up SL4A DUT side to scan addr_type = ble_address_types["public"] - logging.info("Start scanning for PUBLIC_ADDRESS %s with address type %d and IRK %s" % (cert_public_address, - addr_type, irk)) + logging.info("Start scanning for PUBLIC_ADDRESS %s with address type %d and IRK %s" % + (cert_public_address, addr_type, irk)) self.dut.sl4a.bleSetScanSettingsScanMode(ble_scan_settings_modes['low_latency']) self.dut.sl4a.bleSetScanSettingsLegacy(False) filter_list, scan_settings, scan_callback = generate_ble_scan_objects(self.dut.sl4a) @@ -129,8 +129,7 @@ class GattConnectWithIrkTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): assertThat(mac_address).isNotNone() logging.info("Filter advertisement with address {}".format(mac_address)) - # Stop scanning and try to connect GATT - self.dut.sl4a.bleStopBleScan(scan_callback) + # Try to connect GATT gatt_callback = self.dut.sl4a.gattCreateGattCallback() bluetooth_gatt = self.dut.sl4a.gattClientConnectGatt(gatt_callback, mac_address, False, GattTransport.TRANSPORT_LE, False, None) @@ -142,6 +141,7 @@ class GattConnectWithIrkTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): # Test over self.cert.sl4a.bleStopBleAdvertising(advertise_callback) + self.dut.sl4a.bleStopBleScan(scan_callback) if __name__ == '__main__': diff --git a/system/blueberry/tests/sl4a_sl4a/lib/security.py b/system/blueberry/tests/sl4a_sl4a/lib/security.py index 78cc7583895dbfa583fcefae78f2878c485949cf..5181a3eaf945015525a238206b0ec4c1947ae0f8 100644 --- a/system/blueberry/tests/sl4a_sl4a/lib/security.py +++ b/system/blueberry/tests/sl4a_sl4a/lib/security.py @@ -61,7 +61,7 @@ class Security: logging.error("Failed to generate OOB data!") # Check if generating oob data failed without blocking try: - generate_failure_event = self.__device.ed.pop_event(self.SL4A_EVENT_GENERATE_OOB_DATA_FAILURE, 0) + generate_failure_event = self.__device.ed.pop_event(self.SL4A_EVENT_GENERATE_OOB_DATA_ERROR, 0) except queue.Empty as error: logging.error("Failed to generate OOB Data without error code") assertThat(True).isFalse() diff --git a/system/blueberry/tests/sl4a_sl4a/security/irk_rotation_test.py b/system/blueberry/tests/sl4a_sl4a/security/irk_rotation_test.py index 2f5271e18843d92154d895c8685f8cd0a96dae7d..8dc9e74c5eccb6fb7796e4f808e7b5a48951012e 100644 --- a/system/blueberry/tests/sl4a_sl4a/security/irk_rotation_test.py +++ b/system/blueberry/tests/sl4a_sl4a/security/irk_rotation_test.py @@ -91,7 +91,7 @@ class IrkRotationTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): return address, irk - def test_le_reconnect_after_irk_rotation_cert_privacy_enabled(self): + def __test_le_reconnect_after_irk_rotation_cert_privacy_enabled(self): self._test_le_reconnect_after_irk_rotation(True) def test_le_reconnect_after_irk_rotation_cert_privacy_disabled(self): diff --git a/system/blueberry/tests/sl4a_sl4a/security/oob_pairing_test.py b/system/blueberry/tests/sl4a_sl4a/security/oob_pairing_test.py index 17ff46079b897ab2473777f4ada1b55cc217f57b..63972a718b71914792a14356801d5ccd90f4f13e 100644 --- a/system/blueberry/tests/sl4a_sl4a/security/oob_pairing_test.py +++ b/system/blueberry/tests/sl4a_sl4a/security/oob_pairing_test.py @@ -58,6 +58,33 @@ class OobPairingTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): return address, irk + def __get_dut_public_address_and_irk_from_bt_config(self): + # Pull IRK from SL4A dut side + bt_config_file_path = os.path.join(get_current_context().get_full_output_path(), + "DUT_%s_bt_config.conf" % self.dut.serial) + try: + self.dut.adb.pull(["/data/misc/bluedroid/bt_config.conf", bt_config_file_path]) + except AdbError as error: + logging.error("Failed to pull SL4A dut BT config") + return False + logging.debug("Reading SL4A dut BT config") + with io.open(bt_config_file_path) as f: + for line in f.readlines(): + stripped_line = line.strip() + if (stripped_line.startswith("Address")): + address_fields = stripped_line.split(' ') + # API currently requires public address to be capitalized + address = address_fields[2].upper() + logging.debug("Found dut address: %s" % address) + continue + if (stripped_line.startswith("LE_LOCAL_KEY_IRK")): + irk_fields = stripped_line.split(' ') + irk = irk_fields[2] + logging.debug("Found dut IRK: %s" % irk) + continue + + return address, irk + def setup_class(self): super().setup_class() @@ -79,7 +106,7 @@ class OobPairingTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): if wait_for_oob_data: assertThat(oob_data[0]).isEqualTo(0) assertThat(oob_data[1]).isNotNone() - self.dut_security_.create_bond_out_of_band(oob_data[1], wait_for_device_bonded) + self.dut_security_.create_bond_out_of_band(oob_data[1], None, -1, wait_for_device_bonded) def __create_le_bond_oob_double_sided(self, wait_for_oob_data=True, wait_for_device_bonded=True): # Genearte OOB data on DUT, but we don't use it @@ -100,9 +127,11 @@ class OobPairingTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): def test_le_generate_local_oob_data(self): oob_data = self.dut_security_.generate_oob_data(Security.TRANSPORT_LE) - assertThat(oob_data).isNotNone() + assertThat(oob_data[0]).isEqualTo(0) + assertThat(oob_data[1]).isNotNone() oob_data = self.cert_security_.generate_oob_data(Security.TRANSPORT_LE) - assertThat(oob_data).isNotNone() + assertThat(oob_data[0]).isEqualTo(0) + assertThat(oob_data[1]).isNotNone() def test_le_generate_local_oob_data_stress(self): for i in range(1, 20): @@ -132,12 +161,13 @@ class OobPairingTest(sl4a_sl4a_base_test.Sl4aSl4aBaseTestClass): def test_le_oob_advertiser_not_using_public_address(self): #TODO(optedoblivion): Use sysprop and make another test to handle non privacy case oob_data = self.dut_security_.generate_oob_data(Security.TRANSPORT_LE) - assertThat(oob_data).isNotNone() - advertiser_address = oob_data.to_sl4a_address() - public_address = self.dut_advertiser_.get_local_public_address() + assertThat(oob_data[0]).isEqualTo(0) + assertThat(oob_data[1]).isNotNone() + advertiser_address = oob_data[1].to_sl4a_address() + dut_public_address, dut_irk = self.__get_dut_public_address_and_irk_from_bt_config() logging.info("DUT Advertiser Address: %s " % advertiser_address) - logging.info("DUT Public Address: %s " % public_address) - assertThat(advertiser_address).isNotEqualTo(public_address) + logging.info("DUT Public Address: %s " % dut_public_address) + assertThat(advertiser_address).isNotEqualTo(dut_public_address) if __name__ == '__main__': diff --git a/system/blueberry/tests/sl4a_sl4a/sl4a_sl4a_test_runner.py b/system/blueberry/tests/sl4a_sl4a/sl4a_sl4a_test_runner.py index 3081aa4370a9e88afe8faae933feb12082f9aa76..4dc099f20debe8d4fdb708002314d6dc7b785914 100644 --- a/system/blueberry/tests/sl4a_sl4a/sl4a_sl4a_test_runner.py +++ b/system/blueberry/tests/sl4a_sl4a/sl4a_sl4a_test_runner.py @@ -20,7 +20,6 @@ from blueberry.tests.sl4a_sl4a.gatt.gatt_connect_with_irk_test import GattConnec from blueberry.tests.sl4a_sl4a.gatt.gatt_notify_test import GattNotifyTest from blueberry.tests.sl4a_sl4a.l2cap.le_l2cap_coc_test import LeL2capCoCTest from blueberry.tests.sl4a_sl4a.scanning.le_scanning import LeScanningTest -from blueberry.tests.sl4a_sl4a.security.irk_rotation_test import IrkRotationTest from blueberry.tests.sl4a_sl4a.security.oob_pairing_test import OobPairingTest from mobly import suite_runner @@ -30,7 +29,6 @@ ALL_TESTS = [ GattConnectTest, GattConnectWithIrkTest, GattNotifyTest, - IrkRotationTest, LeAdvertisingTest, LeL2capCoCTest, LeScanningTest, @@ -44,15 +42,18 @@ def main(): test config file location """ parser = argparse.ArgumentParser(description="Run local GD SL4A tests.") - parser.add_argument( - '-c', '--config', type=str, required=True, metavar='', help='Path to the test configuration file.') - parser.add_argument( - '--tests', - '--test_case', - nargs='+', - type=str, - metavar='[ClassA[.test_a] ClassB[.test_b] ...]', - help='A list of test classes and optional tests to execute.') + parser.add_argument('-c', + '--config', + type=str, + required=True, + metavar='', + help='Path to the test configuration file.') + parser.add_argument('--tests', + '--test_case', + nargs='+', + type=str, + metavar='[ClassA[.test_a] ClassB[.test_b] ...]', + help='A list of test classes and optional tests to execute.') parser.add_argument("--all_tests", "-A", type=bool, dest="all_tests", default=False, nargs="?") parser.add_argument("--presubmit", type=bool, dest="presubmit", default=False, nargs="?") parser.add_argument("--postsubmit", type=bool, dest="postsubmit", default=False, nargs="?") diff --git a/system/blueberry/tests/topshim/lib/hfp_client.py b/system/blueberry/tests/topshim/lib/hfp_client.py index cdad676b260e5db331a4d4ed5be6be968fbc1ac1..c4bfd80f8a928a962ae7a20a2d997ba08c540c83 100644 --- a/system/blueberry/tests/topshim/lib/hfp_client.py +++ b/system/blueberry/tests/topshim/lib/hfp_client.py @@ -63,13 +63,13 @@ class HfpClient(AsyncClosable): facade_pb2.StopSlcRequest(connection=facade_pb2.Connection(cookie=address.encode()))) return await self._listen_for_event(facade_pb2.EventType.HFP_CONNECTION_STATE) - async def connect_audio(self, address, is_sco_offload_enabled=False, force_cvsd=False): + async def connect_audio(self, address, is_sco_offload_enabled=False, disabled_codecs=0): """ """ await self.__hfp_stub.ConnectAudio( facade_pb2.ConnectAudioRequest(connection=facade_pb2.Connection(cookie=address.encode()), is_sco_offload_enabled=is_sco_offload_enabled, - force_cvsd=force_cvsd)) + disabled_codecs=disabled_codecs)) async def disconnect_audio(self, address): """ diff --git a/system/blueberry/utils/bt_test_utils.py b/system/blueberry/utils/bt_test_utils.py index c1948e7d950ee41d4dcb3ec5c238fbf99e7fd721..414be14938a13d20681419b68f830f5995304fc1 100644 --- a/system/blueberry/utils/bt_test_utils.py +++ b/system/blueberry/utils/bt_test_utils.py @@ -206,12 +206,13 @@ def write_record_file(file_name, audio_params, frames): wf.close() -def get_mac_address_of_generic_advertisement(scan_device, adv_device): +def get_mac_address_of_generic_advertisement(scan_device, adv_device, adv_addr_type=None): """Start generic advertisement and get it's mac address by LE scanning. Args: scan_ad: The Android device to use as the scanner. adv_device: The Android device to use as the advertiser. + adv_addr_type: The address type for the advertiser (refer to AdvertiseSettings.java) Returns: mac_address: The mac address of the advertisement. @@ -222,6 +223,10 @@ def get_mac_address_of_generic_advertisement(scan_device, adv_device): adv_device.sl4a.bleSetAdvertiseSettingsAdvertiseMode(ble_advertise_settings_modes['low_latency']) adv_device.sl4a.bleSetAdvertiseSettingsIsConnectable(True) adv_device.sl4a.bleSetAdvertiseSettingsTxPowerLevel(ble_advertise_settings_tx_powers['high']) + + if adv_addr_type is not None: + adv_device.sl4a.bleSetAdvertiseSettingsOwnAddressType(adv_addr_type) + advertise_callback, advertise_data, advertise_settings = (generate_ble_advertise_objects(adv_device.sl4a)) adv_device.sl4a.bleStartBleAdvertising(advertise_callback, advertise_data, advertise_settings) try: diff --git a/system/bta/Android.bp b/system/bta/Android.bp index fe13a8ad5bb38dea2a080ff9a1cd94dbbbfc6bc3..b3c47939031a55b40120cb600f36f1556dd918c1 100644 --- a/system/bta/Android.bp +++ b/system/bta/Android.bp @@ -9,7 +9,7 @@ package { cc_defaults { name: "fluoride_bta_defaults", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], local_include_dirs: [ "dm", "hd", @@ -23,12 +23,10 @@ cc_defaults { "packages/modules/Bluetooth/system/btif/avrcp", "packages/modules/Bluetooth/system/btif/include", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/stack/btm", "packages/modules/Bluetooth/system/stack/include", "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/include", ], header_libs: ["libbluetooth_headers"], generated_headers: [ @@ -44,8 +42,12 @@ filegroup { "dm/bta_dm_api.cc", "dm/bta_dm_cfg.cc", "dm/bta_dm_ci.cc", + "dm/bta_dm_disc.cc", + "dm/bta_dm_gatt_client.cc", "dm/bta_dm_main.cc", "dm/bta_dm_pm.cc", + "dm/bta_dm_sec.cc", + "dm/bta_dm_sec_api.cc", ], } @@ -63,6 +65,7 @@ cc_library_static { "ag/bta_ag_rfc.cc", "ag/bta_ag_sco.cc", "ag/bta_ag_sdp.cc", + "ag/bta_ag_swb_aptx.cc", "ar/bta_ar.cc", "av/bta_av_aact.cc", "av/bta_av_act.cc", @@ -97,19 +100,23 @@ cc_library_static { "hh/bta_hh_le.cc", "hh/bta_hh_main.cc", "hh/bta_hh_utils.cc", + "le_audio/audio_hal_client/asrc_tables.cc", "le_audio/audio_hal_client/audio_sink_hal_client.cc", + "le_audio/audio_hal_client/audio_source_hal_asrc.cc", "le_audio/audio_hal_client/audio_source_hal_client.cc", "le_audio/broadcaster/broadcaster.cc", "le_audio/broadcaster/broadcaster_types.cc", "le_audio/broadcaster/state_machine.cc", "le_audio/client.cc", "le_audio/client_parser.cc", + "le_audio/codec_interface.cc", "le_audio/codec_manager.cc", "le_audio/content_control_id_keeper.cc", + "le_audio/device_groups.cc", "le_audio/devices.cc", "le_audio/hal_verifier.cc", + "le_audio/le_audio_health_status.cc", "le_audio/le_audio_log_history.cc", - "le_audio/le_audio_set_configuration_provider.cc", "le_audio/le_audio_set_configuration_provider_json.cc", "le_audio/le_audio_types.cc", "le_audio/le_audio_utils.cc", @@ -124,14 +131,23 @@ cc_library_static { "vc/vc.cc", ], cflags: [ + "-Wno-unused-parameter", /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/ "-fvisibility=default", ], static_libs: [ "avrcp-target-service", "lib-bt-packets", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-bta-core", - "libcom.android.sysprop.bluetooth", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libcom.android.sysprop.bluetooth.wrapped", + "liblc3", + ], + shared_libs: [ + "android.hardware.bluetooth.audio@2.1", ], generated_headers: [ "LeAudioSetConfigSchemas_h", @@ -143,6 +159,9 @@ cc_library_static { ], }, }, + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", } @@ -169,6 +188,7 @@ cc_library_static { "jv/bta_jv_act.cc", "jv/bta_jv_api.cc", "jv/bta_jv_cfg.cc", + "rfcomm/bta_rfcomm_scn.cc", "sdp/bta_sdp.cc", "sdp/bta_sdp_act.cc", "sdp/bta_sdp_api.cc", @@ -178,57 +198,105 @@ cc_library_static { "sys/utl.cc", ], cflags: [ + "-Wno-unused-parameter", /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/ "-fvisibility=default", ], static_libs: [ + "bluetooth_flags_c_lib", "lib-bt-packets", - "libcom.android.sysprop.bluetooth", + "libbase", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libcom.android.sysprop.bluetooth.wrapped", + "server_configurable_flags", + ], + apex_available: [ + "com.android.btservices", ], host_supported: true, min_sdk_version: "Tiramisu", } -// bta unit tests for target cc_test { name: "net_test_bta", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], + host_supported: true, srcs: [ - ":TestCommonLogMsg", + ":LegacyStackSdp", + ":OsiCompatSources", ":TestCommonMockFunctions", + ":TestCommonSyncMainHandler", + ":TestFakeOsi", ":TestMockBtif", + ":TestMockDevice", + ":TestMockMainShim", + ":TestMockStackA2dp", + ":TestMockStackAcl", + ":TestMockStackAvct", + ":TestMockStackAvdt", + ":TestMockStackAvrc", ":TestMockStackBtm", + ":TestMockStackGap", + ":TestMockStackGatt", + ":TestMockStackHid", + ":TestMockStackL2cap", + ":TestMockStackMetrics", + ":TestMockStackPan", + ":TestMockStackRfcomm", + "test/bta_ag_sco_test.cc", + "test/bta_ag_test.cc", + "test/bta_api_test.cc", + "test/bta_av_test.cc", "test/bta_dip_test.cc", + "test/bta_disc_test.cc", "test/bta_dm_cust_uuid_test.cc", + "test/bta_dm_test.cc", + "test/bta_gatt_test.cc", "test/bta_hf_client_add_record_test.cc", "test/bta_hf_client_test.cc", - "test/gatt/database_builder_sample_device_test.cc", - "test/gatt/database_builder_test.cc", - "test/gatt/database_test.cc", + "test/bta_pan_test.cc", + "test/bta_sdp_test.cc", + "test/bta_sec_test.cc", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", ], shared_libs: [ "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", + "libbase", "libcrypto", + "libcutils", "liblog", + "server_configurable_flags", ], static_libs: [ - "crypto_toolbox_for_tests", + "bluetooth_flags_c_lib", "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_hci_pdl", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", + "libbt-btu-main-thread", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtcore", + "libbtdevice", "libchrome", - "libcom.android.sysprop.bluetooth", - "libosi", + "libcom.android.sysprop.bluetooth.wrapped", + "libevent", + "libflagtest", + "libgmock", + "server_configurable_flags", ], data: [ ":audio_set_configurations_bfbs", @@ -236,6 +304,56 @@ cc_test { ":audio_set_scenarios_bfbs", ":audio_set_scenarios_json", ], + cflags: ["-Wno-unused-parameter"], +} + +// bta GATT unit tests +cc_test { + name: "net_test_bta_gatt", + defaults: [ + "fluoride_bta_defaults", + "mts_defaults", + ], + test_suites: ["general-tests"], + srcs: [ + ":LegacyStackSdp", + ":TestCommonMockFunctions", + ":TestFakeOsi", + ":TestMockBtif", + ":TestMockDevice", + ":TestMockMainShim", + ":TestMockStackBtm", + ":TestMockStackL2cap", + ":TestMockStackMetrics", + "test/gatt/database_builder_sample_device_test.cc", + "test/gatt/database_builder_test.cc", + "test/gatt/database_test.cc", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", + ], + shared_libs: [ + "libcrypto", + "liblog", + ], + static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_hci_pdl", + "libbt-audio-hal-interface", + "libbt-bta", + "libbt-bta-core", + "libbt-common", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libbtcore", + "libchrome", + "libcom.android.sysprop.bluetooth.wrapped", + "libgmock", + ], + cflags: ["-Wno-unused-parameter"], } // bta unit tests for target @@ -245,9 +363,8 @@ cc_test { "fluoride_bta_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], srcs: [ - ":TestCommonLogMsg", ":TestCommonMockFunctions", ":TestMockBtif", ":TestMockDevice", @@ -258,31 +375,37 @@ cc_test { "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", "libcrypto", + "libcutils", "liblog", "libprotobuf-cpp-lite", + "libstatssocket", ], static_libs: [ - "crypto_toolbox_for_tests", "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtcore", "libchrome", "libosi", + "libstatslog_bt", ], + cflags: ["-Wno-unused-parameter"], } cc_test { - name: "bt_host_test_bta", + name: "bt_host_test_bta_scn", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, include_dirs: [ "packages/modules/Bluetooth/system", @@ -290,74 +413,38 @@ cc_test { ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], srcs: [ - ":OsiCompatSources", - ":TestCommonLogMsg", - ":TestCommonMainHandler", ":TestCommonMockFunctions", - ":TestMockBtaSdp", + ":TestFakeOsi", + ":TestMockBtaSys", ":TestMockBtif", - ":TestMockDevice", - ":TestMockMainShim", - ":TestMockOsi", - ":TestMockStack", - "ar/bta_ar.cc", - "av/bta_av_aact.cc", - "av/bta_av_act.cc", - "av/bta_av_cfg.cc", - "av/bta_av_main.cc", - "av/bta_av_ssm.cc", - "dm/bta_dm_act.cc", - "dm/bta_dm_api.cc", - "dm/bta_dm_cfg.cc", - "dm/bta_dm_ci.cc", - "dm/bta_dm_main.cc", - "dm/bta_dm_pm.cc", - "gatt/bta_gattc_act.cc", - "gatt/bta_gattc_api.cc", - "gatt/bta_gattc_cache.cc", - "gatt/bta_gattc_db_storage.cc", - "gatt/bta_gattc_main.cc", - "gatt/bta_gattc_queue.cc", - "gatt/bta_gattc_utils.cc", - "gatt/database.cc", - "gatt/database_builder.cc", - "hh/bta_hh_act.cc", - "hh/bta_hh_api.cc", - "hh/bta_hh_cfg.cc", - "hh/bta_hh_le.cc", - "hh/bta_hh_main.cc", - "hh/bta_hh_utils.cc", - "pan/bta_pan_act.cc", - "pan/bta_pan_api.cc", - "pan/bta_pan_main.cc", - "sys/bta_sys_conn.cc", - "sys/bta_sys_main.cc", - "sys/utl.cc", - "test/bta_api_test.cc", - "test/bta_av_test.cc", - "test/bta_dm_test.cc", - "test/bta_gatt_test.cc", - "test/bta_pan_test.cc", - "test/bta_sdp_test.cc", + ":TestMockStackBtm", + ":TestMockStackGap", + ":TestMockStackL2cap", + ":TestMockStackRfcomm", + ":TestMockStackSdp", + "jv/bta_jv_act.cc", + "rfcomm/bta_rfcomm_scn.cc", + "test/bta_rfcomm_scn_test.cc", ], shared_libs: [ "libbase", "libcrypto", + "libcutils", "liblog", ], static_libs: [ "libbluetooth-types", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtcore", "libbtdevice", "libchrome", - "libcom.android.sysprop.bluetooth", + "libcom.android.sysprop.bluetooth.wrapped", "libevent", - "libflatbuffers-cpp", "libgmock", ], sanitize: { @@ -365,14 +452,21 @@ cc_test { cfi: true, misc_undefined: ["bounds"], }, + target: { + android: { + whole_static_libs: [ + "libPlatformProperties", + ], + }, + }, + cflags: ["-Wno-unused-parameter"], } // csis unit tests for host cc_test { name: "bluetooth_csis_test", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], @@ -400,13 +494,20 @@ cc_test { "test/common/btm_api_mock.cc", ], shared_libs: [ + "libbase", "libcrypto", + "liblog", + "server_configurable_flags", ], static_libs: [ - "crypto_toolbox_for_tests", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", + "libcutils", "libgmock", "libosi", ], @@ -420,14 +521,14 @@ cc_test { undefined: true, }, }, + cflags: ["-Wno-unused-parameter"], } // groups unit tests for host cc_test { name: "bluetooth_groups_test", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], @@ -444,11 +545,15 @@ cc_test { ], shared_libs: [ "libcrypto", + "liblog", ], static_libs: [ - "crypto_toolbox_for_tests", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libgmock", "libosi", @@ -463,14 +568,14 @@ cc_test { undefined: true, }, }, + cflags: ["-Wno-unused-parameter"], } // bta unit tests for host cc_test { name: "bluetooth_vc_test", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], @@ -498,11 +603,16 @@ cc_test { ], shared_libs: [ "libcrypto", + "liblog", ], static_libs: [ - "crypto_toolbox_for_tests", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libgmock", "libosi", @@ -510,6 +620,7 @@ cc_test { sanitize: { cfi: false, }, + cflags: ["-Wno-unused-parameter"], } genrule { @@ -586,11 +697,87 @@ prebuilt_etc { // bta unit tests for LE Audio // ======================================================== +cc_test { + name: "bluetooth_le_audio_codec_manager_test", + test_suites: ["general-tests"], + defaults: [ + "fluoride_defaults", + "mts_defaults", + ], + host_supported: true, + target: { + darwin: { + enabled: false, + }, + android: { + sanitize: { + misc_undefined: ["bounds"], + }, + whole_static_libs: [ + "libPlatformProperties", + ], + }, + }, + include_dirs: [ + "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/bta/include", + "packages/modules/Bluetooth/system/bta/test/common", + "packages/modules/Bluetooth/system/btif/include", + "packages/modules/Bluetooth/system/gd", + "packages/modules/Bluetooth/system/stack/include", + ], + srcs: [ + ":TestCommonMockFunctions", + ":TestMockBtaLeAudioHalVerifier", + ":TestMockLegacyHciInterface", + ":TestStubOsi", + "le_audio/codec_manager.cc", + "le_audio/codec_manager_test.cc", + "le_audio/le_audio_set_configuration_provider_json.cc", + "le_audio/le_audio_types.cc", + "le_audio/le_audio_utils.cc", + "test/common/mock_controller.cc", + ], + data: [ + ":audio_set_configurations_bfbs", + ":audio_set_configurations_json", + ":audio_set_scenarios_bfbs", + ":audio_set_scenarios_json", + ], + generated_headers: [ + "LeAudioSetConfigSchemas_h", + ], + shared_libs: [ + "android.hardware.bluetooth.audio@2.0", + "android.hardware.bluetooth.audio@2.1", + "libcrypto", + "libhidlbase", + "liblog", // __android_log_print + ], + static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbt-common", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libchrome", + "libevent", + "libflatbuffers-cpp", + "libgmock", + "libosi", + ], + sanitize: { + cfi: false, + }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], +} + cc_test { name: "bluetooth_le_audio_test", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -619,21 +806,27 @@ cc_test { srcs: [ ":TestCommonMockFunctions", ":TestMockBtaLeAudioHalVerifier", + ":TestMockMainShim", ":TestStubOsi", + "le_audio/audio_hal_client/asrc_tables.cc", "le_audio/audio_hal_client/audio_hal_client_test.cc", "le_audio/audio_hal_client/audio_sink_hal_client.cc", + "le_audio/audio_hal_client/audio_source_hal_asrc.cc", "le_audio/audio_hal_client/audio_source_hal_client.cc", "le_audio/client_parser.cc", "le_audio/client_parser_test.cc", "le_audio/content_control_id_keeper.cc", "le_audio/content_control_id_keeper_test.cc", + "le_audio/device_groups.cc", "le_audio/devices.cc", "le_audio/devices_test.cc", + "le_audio/le_audio_health_status.cc", "le_audio/le_audio_log_history.cc", "le_audio/le_audio_set_configuration_provider_json.cc", "le_audio/le_audio_types.cc", "le_audio/le_audio_types_test.cc", "le_audio/metrics_collector_linux.cc", + "le_audio/mock_codec_interface.cc", "le_audio/mock_codec_manager.cc", "le_audio/mock_iso_manager.cc", "le_audio/state_machine.cc", @@ -654,6 +847,7 @@ cc_test { ":audio_set_scenarios_json", ], generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", "LeAudioSetConfigSchemas_h", ], shared_libs: [ @@ -662,10 +856,16 @@ cc_test { "libcrypto", "libhidlbase", "liblog", // __android_log_print + "server_configurable_flags", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", "libflatbuffers-cpp", @@ -675,13 +875,14 @@ cc_test { sanitize: { cfi: false, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "bluetooth_le_audio_client_test", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], @@ -697,20 +898,25 @@ cc_test { srcs: [ ":TestCommonMockFunctions", ":TestMockBtaLeAudioHalVerifier", + ":TestMockMainShim", ":TestStubOsi", "gatt/database.cc", "gatt/database_builder.cc", "le_audio/client.cc", "le_audio/client_parser.cc", "le_audio/content_control_id_keeper.cc", + "le_audio/device_groups.cc", "le_audio/devices.cc", "le_audio/le_audio_client_test.cc", + "le_audio/le_audio_health_status.cc", + "le_audio/le_audio_health_status_test.cc", "le_audio/le_audio_log_history.cc", "le_audio/le_audio_set_configuration_provider_json.cc", "le_audio/le_audio_types.cc", "le_audio/le_audio_utils.cc", "le_audio/metrics_collector.cc", "le_audio/metrics_collector_test.cc", + "le_audio/mock_codec_interface.cc", "le_audio/mock_codec_manager.cc", "le_audio/mock_iso_manager.cc", "le_audio/mock_state_machine.cc", @@ -726,19 +932,26 @@ cc_test { shared_libs: [ "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", + "libbase", "libbinder_ndk", "libcrypto", "libfmq", "libhidlbase", "liblog", + "server_configurable_flags", ], static_libs: [ - "crypto_toolbox_for_tests", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", + "libflagtest", "libflatbuffers-cpp", "libgmock", "liblc3", @@ -770,13 +983,13 @@ cc_test { undefined: true, }, }, + cflags: ["-Wno-unused-parameter"], } cc_test { name: "bluetooth_test_broadcaster_state_machine", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], @@ -799,15 +1012,21 @@ cc_test { "le_audio/broadcaster/state_machine.cc", "le_audio/broadcaster/state_machine_test.cc", "le_audio/le_audio_types.cc", + "le_audio/mock_codec_interface.cc", "le_audio/mock_codec_manager.cc", "le_audio/mock_iso_manager.cc", ], shared_libs: [ "libcrypto", + "liblog", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libgmock", "liblc3", @@ -822,13 +1041,13 @@ cc_test { undefined: true, }, }, + cflags: ["-Wno-unused-parameter"], } cc_test { name: "bluetooth_test_broadcaster", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], @@ -855,6 +1074,7 @@ cc_test { "le_audio/le_audio_types.cc", "le_audio/le_audio_utils.cc", "le_audio/metrics_collector_linux.cc", + "le_audio/mock_codec_interface.cc", "le_audio/mock_codec_manager.cc", "le_audio/mock_iso_manager.cc", "test/common/mock_controller.cc", @@ -866,11 +1086,14 @@ cc_test { "libcrypto", "libfmq", "libhidlbase", + "liblog", ], static_libs: [ + "libbluetooth-types", "libbt-audio-hal-interface", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", "libgmock", @@ -887,13 +1110,13 @@ cc_test { undefined: true, }, }, + cflags: ["-Wno-unused-parameter"], } cc_test { name: "bluetooth_has_test", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], @@ -926,11 +1149,15 @@ cc_test { ], shared_libs: [ "libcrypto", + "liblog", ], static_libs: [ - "crypto_toolbox_for_tests", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libgmock", ], @@ -944,13 +1171,13 @@ cc_test { undefined: true, }, }, + cflags: ["-Wno-unused-parameter"], } cc_test { name: "bluetooth_hh_test", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_bta_defaults", "mts_defaults", ], @@ -964,7 +1191,7 @@ cc_test { "packages/modules/Bluetooth/system/stack/include", ], srcs: [ - ":TestCommonLogMsg", + ":BtaDmSources", ":TestCommonMainHandler", ":TestCommonMockFunctions", ":TestMockBtaGatt", @@ -975,11 +1202,6 @@ cc_test { ":TestMockMainShim", ":TestMockOsi", ":TestMockStack", - "dm/bta_dm_act.cc", - "dm/bta_dm_cfg.cc", - "dm/bta_dm_ci.cc", - "dm/bta_dm_main.cc", - "dm/bta_dm_pm.cc", "gatt/bta_gattc_queue.cc", "hh/bta_hh_act.cc", "hh/bta_hh_api.cc", @@ -990,21 +1212,28 @@ cc_test { "test/bta_hh_test.cc", ], shared_libs: [ + "libbase", "libcrypto", + "liblog", + "server_configurable_flags", ], static_libs: [ - "crypto_toolbox_for_tests", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_hci_pdl", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", - "libcom.android.sysprop.bluetooth", + "libcom.android.sysprop.bluetooth.wrapped", "libevent", "libgmock", "libosi", ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], sanitize: { cfi: true, @@ -1016,4 +1245,39 @@ cc_test { undefined: true, }, }, + cflags: ["-Wno-unused-parameter"], +} + +cc_library_host_shared { + name: "libasrc_resampler_test", + defaults: ["bluetooth_cflags"], + srcs: [ + "le_audio/audio_hal_client/asrc_resampler_test.cc", + "le_audio/audio_hal_client/asrc_tables.cc", + ], + static_libs: [ + "libchrome", + "libflatbuffers-cpp", + ], + stl: "libc++_static", + include_dirs: [ + "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/gd", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", + ], +} + +python_test_host { + name: "asrc_resampler_test", + main: "le_audio/audio_hal_client/asrc_resampler_test.py", + srcs: ["le_audio/audio_hal_client/asrc_resampler_test.py"], + libs: ["mobly"], + data: [":libasrc_resampler_test"], + test_config: "le_audio/audio_hal_client/asrc_resampler_test.config", + test_suites: ["general-tests"], + test_options: { + unit_test: false, + }, } diff --git a/system/bta/BUILD.gn b/system/bta/BUILD.gn index 5b48ff31bdc07e5757bd15b2e52ae6819e9ab32e..f2b16d3066932faa1292c5cb33a95c05f5bc1c47 100644 --- a/system/bta/BUILD.gn +++ b/system/bta/BUILD.gn @@ -14,6 +14,9 @@ # limitations under the License. # +import("//bt/system/gd/dumpsys/bundler/bundler.gni") +import("//common-mk/flatbuffer.gni") + static_library("bta") { sources = [ "ag/bta_ag_act.cc", @@ -25,6 +28,7 @@ static_library("bta") { "ag/bta_ag_rfc.cc", "ag/bta_ag_sco.cc", "ag/bta_ag_sdp.cc", + "ag/bta_ag_swb_aptx.cc", "ar/bta_ar.cc", "av/bta_av_aact.cc", "av/bta_av_act.cc", @@ -36,10 +40,14 @@ static_library("bta") { "csis/csis_client.cc", "dm/bta_dm_act.cc", "dm/bta_dm_api.cc", + "dm/bta_dm_sec_api.cc", "dm/bta_dm_cfg.cc", "dm/bta_dm_ci.cc", + "dm/bta_dm_disc.cc", + "dm/bta_dm_gatt_client.cc", "dm/bta_dm_main.cc", "dm/bta_dm_pm.cc", + "dm/bta_dm_sec.cc", "gatt/bta_gattc_act.cc", "gatt/bta_gattc_api.cc", "gatt/bta_gattc_db_storage.cc", @@ -54,11 +62,11 @@ static_library("bta") { "gatt/database.cc", "gatt/database_builder.cc", "groups/groups.cc", - # TODO(abps) - Enable with long-term effort for LE Audio - #"has/has_client.cc", - #"has/has_ctp.cc", - #"has/has_preset.cc", - #"has/has_types.cc", + "has/has_client.cc", + "has/has_ctp.cc", + "has/has_preset.cc", + "has/has_types.cc", + "has/has_journal.cc", "hearing_aid/hearing_aid.cc", "hearing_aid/hearing_aid_audio_source.cc", "hf_client/bta_hf_client_act.cc", @@ -81,12 +89,34 @@ static_library("bta") { "jv/bta_jv_act.cc", "jv/bta_jv_api.cc", "jv/bta_jv_cfg.cc", - "le_audio/client_linux.cc", + "le_audio/audio_hal_client/asrc_tables.cc", + "le_audio/audio_hal_client/audio_sink_hal_client.cc", + "le_audio/audio_hal_client/audio_source_hal_asrc.cc", + "le_audio/audio_hal_client/audio_source_hal_client.cc", + "le_audio/broadcaster/broadcaster.cc", + "le_audio/broadcaster/broadcaster_types.cc", + "le_audio/broadcaster/state_machine.cc", + "le_audio/client.cc", + "le_audio/client_parser.cc", + "le_audio/codec_interface.cc", + "le_audio/codec_manager.cc", + "le_audio/content_control_id_keeper.cc", + "le_audio/device_groups.cc", + "le_audio/devices.cc", "le_audio/hal_verifier_linux.cc", + "le_audio/le_audio_health_status.cc", + "le_audio/le_audio_log_history.cc", + "le_audio/le_audio_set_configuration_provider_json.cc", + "le_audio/le_audio_types.cc", + "le_audio/le_audio_utils.cc", + "le_audio/metrics_collector.cc", + "le_audio/state_machine.cc", + "le_audio/storage_helper.cc", "pan/bta_pan_act.cc", "pan/bta_pan_api.cc", "pan/bta_pan_ci.cc", "pan/bta_pan_main.cc", + "rfcomm/bta_rfcomm_scn.cc", "sdp/bta_sdp.cc", "sdp/bta_sdp_act.cc", "sdp/bta_sdp_api.cc", @@ -106,6 +136,7 @@ static_library("bta") { "include", "sys", "//bt/system/", + "//bt/system/include", "//bt/system/linux_include", "//bt/system/bta", "//bt/system/gd", @@ -128,9 +159,57 @@ static_library("bta") { ] deps = [ + "//bt/system/bta:LeAudioSetScenariosSchema_bfbs", + "//bt/system/bta:LeAudioSetConfigsSchema_bfbs", + "//bt/system/bta:install_audio_set_scenarios_json", + "//bt/system/bta:install_audio_set_configurations_json", + "//bt/system/bta:install_audio_set_scenarios_bfbs", + "//bt/system/bta:install_audio_set_configurations_bfbs", "//bt/system:libbt-platform-protos-lite", "//bt/system/gd/rust/shim:init_flags_bridge_header", ] + + libs = [ + "lc3", + ] +} + +bt_flatc_binary_schema("LeAudioSetScenariosSchema_bfbs") { + sources = [ + "le_audio/audio_set_scenarios.fbs", + ] + + include_dir = "system" + gen_header = true +} + +bt_flatc_binary_schema("LeAudioSetConfigsSchema_bfbs") { + sources = [ + "le_audio/audio_set_configurations.fbs", + ] + + include_dir = "system" + gen_header = true +} + +install_config("install_audio_set_scenarios_bfbs") { + sources = [ "$target_gen_dir/audio_set_scenarios.bfbs" ] + install_path = "/etc/bluetooth/le_audio/" +} + +install_config("install_audio_set_configurations_bfbs") { + sources = [ "$target_gen_dir/audio_set_configurations.bfbs" ] + install_path = "/etc/bluetooth/le_audio/" +} + +install_config("install_audio_set_scenarios_json") { + sources = [ "le_audio/audio_set_scenarios.json" ] + install_path = "/etc/bluetooth/le_audio/" +} + +install_config("install_audio_set_configurations_json") { + sources = [ "le_audio/audio_set_configurations.json" ] + install_path = "/etc/bluetooth/le_audio/" } if (use.test) { diff --git a/system/bta/ag/bta_ag_act.cc b/system/bta/ag/bta_ag_act.cc index b8a8a24518dd216f28b779ddaa07a60c4c5a5183..40896c172c63565552b4d8a06d0460bbf1eee265 100644 --- a/system/bta/ag/bta_ag_act.cc +++ b/system/bta/ag/bta_ag_act.cc @@ -22,6 +22,7 @@ * ******************************************************************************/ +#include #include #include @@ -29,6 +30,8 @@ #include "bta/ag/bta_ag_int.h" #include "bta/include/bta_dm_api.h" +#include "bta/include/bta_hfp_api.h" +#include "bta_ag_swb_aptx.h" #ifdef __ANDROID__ #include "bta/le_audio/devices.h" @@ -36,12 +39,16 @@ #include "btif/include/btif_config.h" #include "device/include/device_iot_config.h" -#include "os/system_properties.h" #include "osi/include/osi.h" // UNUSED_ATTR +#include "stack/include/bt_uuid16.h" +#include "stack/include/btm_sec_api_types.h" #include "stack/include/l2c_api.h" #include "stack/include/port_api.h" +#include "stack/include/sdp_api.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + /***************************************************************************** * Constants ****************************************************************************/ @@ -217,7 +224,7 @@ void bta_ag_start_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { uint16_t event = BTA_AG_DISC_FAIL_EVT; - APPL_TRACE_DEBUG("bta_ag_disc_int_res: Status: %d", data.disc_result.status); + LOG_VERBOSE("bta_ag_disc_int_res: Status: %d", data.disc_result.status); /* if found service */ if (data.disc_result.status == SDP_SUCCESS || @@ -348,6 +355,7 @@ void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) { p_scb->peer_features = 0; p_scb->peer_codecs = BTM_SCO_CODEC_CVSD; p_scb->sco_codec = BTM_SCO_CODEC_CVSD; + p_scb->is_aptx_swb_codec = false; p_scb->role = 0; p_scb->svc_conn = false; p_scb->hsp_version = HSP_VERSION_1_2; @@ -387,6 +395,8 @@ void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, p_scb->codec_updated = false; p_scb->codec_fallback = false; p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2; + p_scb->codec_aptx_settings = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + p_scb->is_aptx_swb_codec = false; p_scb->codec_lc3_settings = BTA_AG_SCO_LC3_SETTINGS_T2; p_scb->role = 0; p_scb->svc_conn = false; @@ -476,8 +486,8 @@ void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { if (!btif_config_get_bin( p_scb->peer_addr.ToString(), HFP_VERSION_CONFIG_KEY, (uint8_t*)&p_scb->peer_version, &version_value_size)) { - APPL_TRACE_WARNING("%s: Failed read cached peer HFP version for %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr)); + LOG_WARN("%s: Failed read cached peer HFP version for %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr)); p_scb->peer_version = HFP_HSP_VERSION_UNKNOWN; } size_t sdp_features_size = sizeof(p_scb->peer_sdp_features); @@ -497,8 +507,8 @@ void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { p_scb->sco_codec = BTM_SCO_CODEC_LC3; } } else { - APPL_TRACE_WARNING("%s: Failed read cached peer HFP SDP features for %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr)); + LOG_WARN("%s: Failed read cached peer HFP SDP features for %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr)); } } @@ -535,8 +545,8 @@ void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { * ******************************************************************************/ void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { - APPL_TRACE_DEBUG("%s: serv_handle0 = %d serv_handle = %d", __func__, - p_scb->serv_handle[0], p_scb->serv_handle[1]); + LOG_VERBOSE("%s: serv_handle0 = %d serv_handle = %d", __func__, + p_scb->serv_handle[0], p_scb->serv_handle[1]); /* set role */ p_scb->role = BTA_AG_ACP; @@ -588,9 +598,8 @@ void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { /* determine connected service from port handle */ for (uint8_t i = 0; i < BTA_AG_NUM_IDX; i++) { - APPL_TRACE_DEBUG( - "bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", i, - p_scb->serv_handle[i], data.rfc.port_handle); + LOG_VERBOSE("bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", + i, p_scb->serv_handle[i], data.rfc.port_handle); if (p_scb->serv_handle[i] == data.rfc.port_handle) { p_scb->conn_service = i; @@ -599,8 +608,8 @@ void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { } } - APPL_TRACE_DEBUG("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d", - p_scb->conn_service, p_scb->conn_handle); + LOG_VERBOSE("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d", + p_scb->conn_service, p_scb->conn_handle); /* close any unopened server */ bta_ag_close_servers( @@ -637,7 +646,7 @@ void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) { uint16_t len; char buf[BTA_AG_RFC_READ_MAX] = ""; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* do the following */ for (;;) { @@ -659,7 +668,7 @@ void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) { bta_ag_at_parse(&p_scb->at_cb, buf, len); if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) && bta_ag_sco_is_open(p_scb)) { - APPL_TRACE_DEBUG("%s change link policy for SCO", __func__); + LOG_VERBOSE("%s change link policy for SCO", __func__); bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); } else { bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); @@ -837,12 +846,18 @@ void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb, void bta_ag_setcodec(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { tBTA_AG_PEER_CODEC codec_type = data.api_setcodec.codec; tBTA_AG_VAL val = {}; + const bool aptx_voice = is_hfp_aptx_voice_enabled() && + (codec_type == BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + LOG_VERBOSE("aptx_voice=%s, codec_type=%#x", logbool(aptx_voice).c_str(), + codec_type); + val.hdr.handle = bta_ag_scb_to_idx(p_scb); /* Check if the requested codec type is valid */ if ((codec_type != BTM_SCO_CODEC_NONE) && (codec_type != BTM_SCO_CODEC_CVSD) && - (codec_type != BTM_SCO_CODEC_MSBC) && (codec_type != BTM_SCO_CODEC_LC3)) { + (codec_type != BTM_SCO_CODEC_MSBC) && (codec_type != BTM_SCO_CODEC_LC3) && + !aptx_voice) { val.num = codec_type; val.hdr.status = BTA_AG_FAIL_RESOURCES; LOG_ERROR("bta_ag_setcodec error: unsupported codec type %d", codec_type); @@ -856,7 +871,7 @@ void bta_ag_setcodec(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { p_scb->codec_updated = true; val.num = codec_type; val.hdr.status = BTA_AG_SUCCESS; - APPL_TRACE_DEBUG("bta_ag_setcodec: Updated codec type %d", codec_type); + LOG_VERBOSE("bta_ag_setcodec: Updated codec type %d", codec_type); } else { val.num = codec_type; val.hdr.status = BTA_AG_FAIL_RESOURCES; @@ -880,7 +895,8 @@ void bta_ag_handle_collision(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) { /* Cancel SDP if it had been started. */ if (p_scb->p_disc_db) { - SDP_CancelServiceSearch(p_scb->p_disc_db); + get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch( + p_scb->p_disc_db); bta_ag_free_db(p_scb, tBTA_AG_DATA::kEmpty); } diff --git a/system/bta/ag/bta_ag_api.cc b/system/bta/ag/bta_ag_api.cc index cdb63536ba5e30ee72142477162abaa8e23b0477..980e13bda4697a49f589e9829e86834ea3e582f0 100644 --- a/system/bta/ag/bta_ag_api.cc +++ b/system/bta/ag/bta_ag_api.cc @@ -34,7 +34,7 @@ #include #include "bta/ag/bta_ag_int.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" #include "types/raw_address.h" /***************************************************************************** @@ -66,7 +66,7 @@ tBTA_STATUS BTA_AgEnable(tBTA_AG_CBACK* p_cback) { } } bta_sys_register(BTA_ID_AG, &bta_ag_reg); - do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_api_enable, p_cback)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_api_enable, p_cback)); return BTA_SUCCESS; } @@ -81,7 +81,7 @@ tBTA_STATUS BTA_AgEnable(tBTA_AG_CBACK* p_cback) { * ******************************************************************************/ void BTA_AgDisable() { - do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_api_disable)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_api_disable)); } /******************************************************************************* @@ -97,8 +97,8 @@ void BTA_AgDisable() { void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_AG_FEAT features, const std::vector& service_names, uint8_t app_id) { - do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_api_register, services, - features, service_names, app_id)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_api_register, services, + features, service_names, app_id)); } /******************************************************************************* @@ -112,9 +112,9 @@ void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_AG_FEAT features, * ******************************************************************************/ void BTA_AgDeregister(uint16_t handle) { - do_in_main_thread( - FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_API_DEREGISTER_EVT, tBTA_AG_DATA::kEmpty)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_sm_execute_by_handle, + handle, BTA_AG_API_DEREGISTER_EVT, + tBTA_AG_DATA::kEmpty)); } /******************************************************************************* @@ -133,8 +133,9 @@ void BTA_AgDeregister(uint16_t handle) { void BTA_AgOpen(uint16_t handle, const RawAddress& bd_addr) { tBTA_AG_DATA data = {}; data.api_open.bd_addr = bd_addr; - do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_API_OPEN_EVT, data)); + do_in_main_thread(FROM_HERE, + base::BindOnce(&bta_ag_sm_execute_by_handle, handle, + BTA_AG_API_OPEN_EVT, data)); } /******************************************************************************* @@ -150,8 +151,8 @@ void BTA_AgOpen(uint16_t handle, const RawAddress& bd_addr) { ******************************************************************************/ void BTA_AgClose(uint16_t handle) { do_in_main_thread(FROM_HERE, - base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_API_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); + base::BindOnce(&bta_ag_sm_execute_by_handle, handle, + BTA_AG_API_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); } /******************************************************************************* @@ -159,18 +160,21 @@ void BTA_AgClose(uint16_t handle) { * Function BTA_AgAudioOpen * * Description Opens an audio connection to the currently connected - * headset or handsfree. Specifying force_cvsd to true to - * force the stack to use CVSD even if mSBC is supported. + * headset or handsfree. Specify `disabled_codecs` to + * force the stack to avoid using certain codecs. + * + * Note that CVSD is a mandatory codec and cannot be disabled. * * * Returns void * ******************************************************************************/ -void BTA_AgAudioOpen(uint16_t handle, bool force_cvsd) { +void BTA_AgAudioOpen(uint16_t handle, tBTA_AG_PEER_CODEC disabled_codecs) { tBTA_AG_DATA data = {}; - data.api_audio_open.force_cvsd = force_cvsd; - do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_API_AUDIO_OPEN_EVT, data)); + data.api_audio_open.disabled_codecs = disabled_codecs; + do_in_main_thread(FROM_HERE, + base::BindOnce(&bta_ag_sm_execute_by_handle, handle, + BTA_AG_API_AUDIO_OPEN_EVT, data)); } /******************************************************************************* @@ -186,8 +190,9 @@ void BTA_AgAudioOpen(uint16_t handle, bool force_cvsd) { ******************************************************************************/ void BTA_AgAudioClose(uint16_t handle) { do_in_main_thread( - FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_API_AUDIO_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); + FROM_HERE, + base::BindOnce(&bta_ag_sm_execute_by_handle, handle, + BTA_AG_API_AUDIO_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); } /******************************************************************************* @@ -205,7 +210,7 @@ void BTA_AgAudioClose(uint16_t handle) { void BTA_AgResult(uint16_t handle, tBTA_AG_RES result, const tBTA_AG_RES_DATA& data) { do_in_main_thread(FROM_HERE, - base::Bind(&bta_ag_api_result, handle, result, data)); + base::BindOnce(&bta_ag_api_result, handle, result, data)); } /******************************************************************************* @@ -223,20 +228,25 @@ void BTA_AgResult(uint16_t handle, tBTA_AG_RES result, void BTA_AgSetCodec(uint16_t handle, tBTA_AG_PEER_CODEC codec) { tBTA_AG_DATA data = {}; data.api_setcodec.codec = codec; - do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_API_SETCODEC_EVT, data)); + do_in_main_thread(FROM_HERE, + base::BindOnce(&bta_ag_sm_execute_by_handle, handle, + BTA_AG_API_SETCODEC_EVT, data)); } void BTA_AgSetScoOffloadEnabled(bool value) { do_in_main_thread(FROM_HERE, - base::Bind(&bta_ag_set_sco_offload_enabled, value)); + base::BindOnce(&bta_ag_set_sco_offload_enabled, value)); } void BTA_AgSetScoAllowed(bool value) { - do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_set_sco_allowed, value)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_set_sco_allowed, value)); } void BTA_AgSetActiveDevice(const RawAddress& active_device_addr) { - do_in_main_thread( - FROM_HERE, base::Bind(&bta_ag_api_set_active_device, active_device_addr)); + if (active_device_addr.IsEmpty()) { + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_clear_active_device)); + } else { + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_api_set_active_device, + active_device_addr)); + } } diff --git a/system/bta/ag/bta_ag_cfg.cc b/system/bta/ag/bta_ag_cfg.cc index c331973949088a07dead535a6558b9c0a15af2db..99e5faa9843746c718d4f27732a69f4112946254 100644 --- a/system/bta/ag/bta_ag_cfg.cc +++ b/system/bta/ag/bta_ag_cfg.cc @@ -23,28 +23,19 @@ * ******************************************************************************/ -#include "bt_target.h" // Must be first to define build configuration #include "bta/ag/bta_ag_int.h" #include "bta/include/bta_ag_api.h" #include "device/include/esco_parameters.h" -#include "osi/include/allocator.h" -#include "osi/include/compat.h" -#include "stack/include/bt_types.h" +#include "internal_include/bt_target.h" -#ifndef BTA_AG_CIND_INFO +/* Set the CIND to match HFP 1.5 */ #define BTA_AG_CIND_INFO \ - "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-3)),(\"signal\",(0-" \ - "6)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2)),(\"bearer\"," \ - "(0-7))" -#endif + "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-1)),(\"signal\",(0-" \ + "5)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2))" -#ifndef BTA_AG_CHLD_VAL_ECC -#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3,4)" -#endif +#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3)" -#ifndef BTA_AG_CHLD_VAL -#define BTA_AG_CHLD_VAL "(0,1,2,3,4)" -#endif +#define BTA_AG_CHLD_VAL "(0,1,2,3)" #ifndef BTA_AG_CONN_TIMEOUT #define BTA_AG_CONN_TIMEOUT 5000 diff --git a/system/bta/ag/bta_ag_cmd.cc b/system/bta/ag/bta_ag_cmd.cc index 6457a326a22739b405e06749e1f971eeed35fb47..07308c958e3b70761e52ad05e2f9d78c6eed7600 100644 --- a/system/bta/ag/bta_ag_cmd.cc +++ b/system/bta/ag/bta_ag_cmd.cc @@ -18,6 +18,7 @@ #define LOG_TAG "bta_ag_cmd" +#include #include #include @@ -27,17 +28,20 @@ #include "bta/ag/bta_ag_int.h" #include "bta/include/bta_ag_api.h" #include "bta/include/utl.h" +#include "bta_ag_swb_aptx.h" #ifdef __ANDROID__ -#include "bta/le_audio/devices.h" +#include "bta_le_audio_api.h" #endif +#include "bta/include/bta_hfp_api.h" #include "device/include/interop.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" +#include "os/log.h" #include "os/system_properties.h" #include "osi/include/compat.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR -#include "osi/include/properties.h" #include "stack/btm/btm_sco_hfp_hal.h" #include "stack/include/port_api.h" @@ -113,6 +117,10 @@ static const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] = { BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST, BTA_AG_AT_STR, 0, 0}, {"+BIEV", BTA_AG_AT_BIEV_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, {"+BAC", BTA_AG_AT_BAC_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, + {"+%QAC", BTA_AG_AT_QAC_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, + {"+%QCS", BTA_AG_AT_QCS_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, + BTA_AG_CMD_MAX_VAL}, + /* End-of-table marker used to stop lookup iteration */ {"", 0, 0, 0, 0, 0}}; @@ -165,6 +173,9 @@ static const tBTA_AG_RESULT bta_ag_result_tbl[] = { {"+CME ERROR: ", BTA_AG_LOCAL_RES_CMEE, BTA_AG_RES_FMT_INT}, {"+BCS: ", BTA_AG_LOCAL_RES_BCS, BTA_AG_RES_FMT_INT}, {"+BIND: ", BTA_AG_BIND_RES, BTA_AG_RES_FMT_STR}, + {"+%QAC: ", BTA_AG_LOCAL_RES_QAC, BTA_AG_RES_FMT_STR}, + {"+%QCS: ", BTA_AG_LOCAL_RES_QCS, BTA_AG_RES_FMT_INT}, + {"", BTA_AG_UNAT_RES, BTA_AG_RES_FMT_STR}}; static const tBTA_AG_RESULT* bta_ag_result_by_code(size_t code) { @@ -479,7 +490,7 @@ static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB* p_scb, char* p_s, retval |= BTM_SCO_CODEC_LC3; break; default: - APPL_TRACE_ERROR("Unknown Codec UUID(%d) received", uuid_codec); + LOG_ERROR("Unknown Codec UUID(%d) received", uuid_codec); break; } @@ -591,8 +602,8 @@ void bta_ag_send_call_inds(tBTA_AG_SCB* p_scb, tBTA_AG_RES result) { void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t command_id, uint8_t arg_type, char* p_arg, char* p_end, int16_t int_arg) { - APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", command_id, arg_type, - int_arg, p_arg); + LOG_VERBOSE("AT cmd:%d arg_type:%d arg:%d arg:%s", command_id, arg_type, + int_arg, p_arg); bta_ag_send_ok(p_scb); @@ -602,7 +613,7 @@ void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t command_id, val.num = (uint16_t)int_arg; if ((p_end - p_arg + 1) >= (long)sizeof(val.str)) { - APPL_TRACE_ERROR("%s: p_arg is too long, send error and return", __func__); + LOG_ERROR("%s: p_arg is too long, send error and return", __func__); bta_ag_send_error(p_scb, BTA_AG_ERR_TEXT_TOO_LONG); return; } @@ -687,12 +698,12 @@ static bool bta_ag_parse_bind_set(tBTA_AG_SCB* p_scb, tBTA_AG_VAL val) { uint16_t rcv_ind_id = atoi(p_token); int index = bta_ag_find_empty_hf_ind(p_scb); if (index == -1) { - APPL_TRACE_WARNING("%s Can't save more indicators", __func__); + LOG_WARN("%s Can't save more indicators", __func__); return false; } p_scb->peer_hf_indicators[index].ind_id = rcv_ind_id; - APPL_TRACE_DEBUG("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id); + LOG_VERBOSE("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id); p_token = strtok(nullptr, ","); } @@ -736,7 +747,7 @@ static void bta_ag_bind_response(tBTA_AG_SCB* p_scb, uint8_t arg_type) { /* bta_ag_local_hf_ind_cfg[0].ind_id is used as BTA_AG_NUM_LOCAL_HF_IND */ for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++) { if (i == BTA_AG_MAX_NUM_LOCAL_HF_IND) { - APPL_TRACE_WARNING("%s No space for more HF indicators", __func__); + LOG_WARN("%s No space for more HF indicators", __func__); break; } @@ -797,13 +808,12 @@ static bool bta_ag_parse_biev_response(tBTA_AG_SCB* p_scb, tBTA_AG_VAL* val) { if (p_token == nullptr) return false; uint16_t rcv_ind_val = atoi(p_token); - APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id, - rcv_ind_val); + LOG_VERBOSE("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id, + rcv_ind_val); /* Check whether indicator ID is valid or not */ if (rcv_ind_id > BTA_AG_NUM_LOCAL_HF_IND) { - APPL_TRACE_WARNING("%s received invalid indicator id %d", __func__, - rcv_ind_id); + LOG_WARN("%s received invalid indicator id %d", __func__, rcv_ind_id); return false; } @@ -813,15 +823,15 @@ static bool bta_ag_parse_biev_response(tBTA_AG_SCB* p_scb, tBTA_AG_VAL* val) { if (local_index == -1 || !p_scb->local_hf_indicators[local_index].is_supported || !p_scb->local_hf_indicators[local_index].is_enable) { - APPL_TRACE_WARNING("%s indicator id %d not supported or disabled", __func__, - rcv_ind_id); + LOG_WARN("%s indicator id %d not supported or disabled", __func__, + rcv_ind_id); return false; } /* For each indicator ID, check whether the indicator value is in range */ if (rcv_ind_val < bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_min_val || rcv_ind_val > bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_max_val) { - APPL_TRACE_WARNING("%s invalid ind_val %d", __func__, rcv_ind_val); + LOG_WARN("%s invalid ind_val %d", __func__, rcv_ind_val); return false; } @@ -868,8 +878,8 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, return; } - APPL_TRACE_DEBUG("%s: AT command %d, arg_type %d, int_arg %d, arg %s", - __func__, cmd, arg_type, int_arg, p_arg); + LOG_VERBOSE("%s: AT command %d, arg_type %d, int_arg %d, arg %s", __func__, + cmd, arg_type, int_arg, p_arg); val.hdr.handle = bta_ag_scb_to_idx(p_scb); val.hdr.app_id = p_scb->app_id; @@ -899,22 +909,11 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, case BTA_AG_AT_A_EVT: case BTA_AG_SPK_EVT: case BTA_AG_MIC_EVT: + case BTA_AG_AT_CHUP_EVT: case BTA_AG_AT_CBC_EVT: /* send OK */ bta_ag_send_ok(p_scb); break; - - case BTA_AG_AT_CHUP_EVT: - if (!bta_ag_sco_is_active_device(p_scb->peer_addr)) { - LOG(WARNING) << __func__ << ": AT+CHUP rejected as " << p_scb->peer_addr - << " is not the active device"; - event = BTA_AG_ENABLE_EVT; - bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_ALLOWED); - } else { - bta_ag_send_ok(p_scb); - } - break; - case BTA_AG_AT_BLDN_EVT: /* Do not send OK, App will send error or OK depending on ** last dial number enabled or not */ @@ -1038,8 +1037,7 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, break; case BTA_AG_AT_BIND_EVT: - APPL_TRACE_DEBUG("%s BTA_AG_AT_BIND_EVT arg_type: %d", __func__, - arg_type); + LOG_VERBOSE("%s BTA_AG_AT_BIND_EVT arg_type: %d", __func__, arg_type); alarm_cancel(p_scb->bind_timer); if (arg_type == BTA_AG_AT_SET) { if (bta_ag_parse_bind_set(p_scb, val)) { @@ -1139,8 +1137,8 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, p_scb->masked_features &= HFP_1_6_FEAT_MASK; } - APPL_TRACE_DEBUG("%s BRSF HF: 0x%x, phone: 0x%x", __func__, - p_scb->peer_features, p_scb->masked_features); + LOG_VERBOSE("%s BRSF HF: 0x%x, phone: 0x%x", __func__, + p_scb->peer_features, p_scb->masked_features); /* send BRSF, send OK */ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, nullptr, @@ -1258,17 +1256,27 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg, p_end); p_scb->codec_updated = true; + bool wbs_supported = hfp_hal_interface::get_wbs_supported(); bool swb_supported = hfp_hal_interface::get_swb_supported(); + const bool aptx_voice = + is_hfp_aptx_voice_enabled() && p_scb->is_aptx_swb_codec; + LOG_VERBOSE("BTA_AG_AT_BAC_EVT aptx_voice=%s", + logbool(aptx_voice).c_str()); - if ((p_scb->peer_codecs & BTM_SCO_CODEC_LC3) && swb_supported) { + if (swb_supported && (p_scb->peer_codecs & BTM_SCO_CODEC_LC3) && + !(p_scb->disabled_codecs & BTM_SCO_CODEC_LC3)) { p_scb->sco_codec = BTM_SCO_CODEC_LC3; - APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to LC3"); - } else if (p_scb->peer_codecs & BTM_SCO_CODEC_MSBC) { + LOG_VERBOSE("Received AT+BAC, updating sco codec to LC3"); + } else if (aptx_voice) { + p_scb->sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + LOG_VERBOSE("Received AT+BAC, updating sco codec to AptX Voice"); + } else if (wbs_supported && (p_scb->peer_codecs & BTM_SCO_CODEC_MSBC) && + !(p_scb->disabled_codecs & BTM_SCO_CODEC_MSBC)) { p_scb->sco_codec = BTM_SCO_CODEC_MSBC; - APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to MSBC"); + LOG_VERBOSE("Received AT+BAC, updating sco codec to MSBC"); } else { p_scb->sco_codec = BTM_SCO_CODEC_CVSD; - APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to CVSD"); + LOG_VERBOSE("Received AT+BAC, updating sco codec to CVSD"); } /* The above logic sets the stack preferred codec based on local and peer codec @@ -1284,8 +1292,7 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, } } else { p_scb->peer_codecs = BTM_SCO_CODEC_CVSD; - APPL_TRACE_ERROR( - "Unexpected CMD:AT+BAC, Codec Negotiation is not supported"); + LOG_ERROR("Unexpected CMD:AT+BAC, Codec Negotiation is not supported"); } break; @@ -1305,7 +1312,7 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, codec_type = BTM_SCO_CODEC_LC3; break; default: - APPL_TRACE_ERROR("Unknown codec_uuid %d", int_arg); + LOG_ERROR("Unknown codec_uuid %d", int_arg); codec_type = 0xFFFF; break; } @@ -1339,6 +1346,28 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, bta_ag_sco_open(p_scb, tBTA_AG_DATA::kEmpty); break; } + case BTA_AG_AT_QAC_EVT: + if (!is_hfp_aptx_voice_enabled()) { + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + break; + } + p_scb->peer_codecs |= bta_ag_parse_qac(p_arg); + // AT+%QAC needs to be responded with +%QAC + bta_ag_swb_handle_vs_at_events(p_scb, cmd, int_arg, &val); + // followed by OK + bta_ag_send_ok(p_scb); + break; + case BTA_AG_AT_QCS_EVT: + if (!is_hfp_aptx_voice_enabled()) { + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + break; + } + // AT+%QCS is a response to +%QCS sent from AG. + // Send OK to BT headset + bta_ag_send_ok(p_scb); + // Handle AT+%QCS + bta_ag_swb_handle_vs_at_events(p_scb, cmd, int_arg, &val); + break; default: bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); break; @@ -1362,7 +1391,7 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, ******************************************************************************/ void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, const char* p_arg) { if (unknown && (!strlen(p_arg))) { - APPL_TRACE_DEBUG("Empty AT cmd string received"); + LOG_VERBOSE("Empty AT cmd string received"); bta_ag_send_ok(p_scb); return; } @@ -1393,7 +1422,7 @@ void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, const char* p_arg) { ******************************************************************************/ static void bta_ag_hsp_result(tBTA_AG_SCB* p_scb, const tBTA_AG_API_RESULT& result) { - APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", result.result); + LOG_VERBOSE("bta_ag_hsp_result : res = %d", result.result); switch (result.result) { case BTA_AG_SPK_RES: @@ -1465,7 +1494,7 @@ static void bta_ag_hsp_result(tBTA_AG_SCB* p_scb, case BTA_AG_INBAND_RING_RES: p_scb->inband_enabled = result.data.state; - APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled); + LOG_VERBOSE("inband_enabled set to %d", p_scb->inband_enabled); break; case BTA_AG_UNAT_RES: @@ -1597,7 +1626,7 @@ static void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, case BTA_AG_MULTI_CALL_RES: /* open SCO at SLC for this three way call */ - APPL_TRACE_DEBUG("Headset Connected in three way call"); + LOG_VERBOSE("Headset Connected in three way call"); if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) { if (result.data.audio_handle == bta_ag_scb_to_idx(p_scb)) { if (!bta_ag_is_sco_open_allowed(p_scb, @@ -1656,7 +1685,7 @@ static void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, case BTA_AG_INBAND_RING_RES: p_scb->inband_enabled = result.data.state; - APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled); + LOG_VERBOSE("inband_enabled set to %d", p_scb->inband_enabled); bta_ag_send_result(p_scb, result.result, nullptr, result.data.state); break; @@ -1669,8 +1698,8 @@ static void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, p_scb->roam_ind = result.data.str[8] - '0'; p_scb->battchg_ind = result.data.str[10] - '0'; p_scb->callheld_ind = result.data.str[12] - '0'; - APPL_TRACE_DEBUG("cind call:%d callsetup:%d", p_scb->call_ind, - p_scb->callsetup_ind); + LOG_VERBOSE("cind call:%d callsetup:%d", p_scb->call_ind, + p_scb->callsetup_ind); bta_ag_send_result(p_scb, result.result, result.data.str, 0); bta_ag_send_ok(p_scb); @@ -1696,7 +1725,7 @@ static void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, if (result.data.str[0] != 0) { tBTA_AG_API_RESULT result_copy(result); bta_ag_process_unat_res(result_copy.data.str); - APPL_TRACE_DEBUG("BTA_AG_RES :%s", result_copy.data.str); + LOG_VERBOSE("BTA_AG_RES :%s", result_copy.data.str); bta_ag_send_result(p_scb, result_copy.result, result_copy.data.str, 0); } @@ -1750,8 +1779,7 @@ static void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, BTA_AG_MAX_NUM_LOCAL_HF_IND, result.data.ind.id); if (local_index == -1) { - APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__, - result.data.ind.id); + LOG_WARN("%s Invalid HF Indicator ID %d", __func__, result.data.ind.id); return; } @@ -1760,8 +1788,7 @@ static void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, BTA_AG_MAX_NUM_PEER_HF_IND, result.data.ind.id); if (peer_index == -1) { - APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__, - result.data.ind.id); + LOG_WARN("%s Invalid HF Indicator ID %d", __func__, result.data.ind.id); return; } else { /* If the current state is different from the one upper layer request @@ -1779,9 +1806,9 @@ static void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, bta_ag_send_result(p_scb, result.result, buffer, 0); } else { - APPL_TRACE_DEBUG( - "%s HF Indicator %d already %s", result.data.ind.id, - (result.data.ind.on_demand) ? "Enabled" : "Disabled"); + LOG_VERBOSE("%s HF Indicator %d already %s", __func__, + result.data.ind.id, + (result.data.ind.on_demand) ? "Enabled" : "Disabled"); } } break; @@ -1838,15 +1865,15 @@ void bta_ag_send_bcs(tBTA_AG_SCB* p_scb) { codec_uuid = UUID_CODEC_LC3; break; default: - APPL_TRACE_ERROR("bta_ag_send_bcs: unknown codec %d, use CVSD", - p_scb->sco_codec); + LOG_ERROR("bta_ag_send_bcs: unknown codec %d, use CVSD", + p_scb->sco_codec); codec_uuid = UUID_CODEC_CVSD; break; } } /* send +BCS */ - APPL_TRACE_DEBUG("send +BCS codec is %d", codec_uuid); + LOG_VERBOSE("send +BCS codec is %d", codec_uuid); bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BCS, nullptr, codec_uuid); } @@ -1909,3 +1936,46 @@ void bta_ag_send_ring(tBTA_AG_SCB* p_scb, bta_sys_start_timer(p_scb->ring_timer, BTA_AG_RING_TIMEOUT_MS, BTA_AG_RING_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb)); } + +/******************************************************************************* + * + * Function bta_ag_send_qcs + * + * Description Send +%QCS AT command to peer. + * + * Returns void + * + ******************************************************************************/ +void bta_ag_send_qcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) { + uint16_t codec_uuid; + if (p_scb->codec_fallback) { + if (p_scb->peer_codecs & BTM_SCO_CODEC_MSBC) { + codec_uuid = UUID_CODEC_MSBC; + } else { + codec_uuid = UUID_CODEC_CVSD; + } + } else { + codec_uuid = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + } + + LOG_VERBOSE("send +QCS codec is %d", codec_uuid); + bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_QCS, NULL, codec_uuid); +} + +/******************************************************************************* + * + * Function bta_ag_send_qac + * + * Description Send +%QAC AT command to peer. + * + * Returns void + * + ******************************************************************************/ +void bta_ag_send_qac(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) { + LOG_VERBOSE("send +QAC codecs supported"); + bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_QAC, SWB_CODECS_SUPPORTED, 0); + + if (p_scb->sco_codec == BTA_AG_SCO_APTX_SWB_SETTINGS_Q0) { + p_scb->is_aptx_swb_codec = true; + } +} diff --git a/system/bta/ag/bta_ag_int.h b/system/bta/ag/bta_ag_int.h index c5f21b8ea54eec2e051b66cfd63e7bbd6d73d715..9f1f92b334d983f96e4314f5ba8a5327c82dade7 100644 --- a/system/bta/ag/bta_ag_int.h +++ b/system/bta/ag/bta_ag_int.h @@ -30,7 +30,9 @@ #include "bta/include/bta_ag_api.h" #include "bta/include/bta_api.h" #include "bta/sys/bta_sys.h" +#include "internal_include/bt_target.h" #include "stack/include/bt_hdr.h" +#include "stack/sdp/sdp_discovery_db.h" #include "types/raw_address.h" /***************************************************************************** @@ -136,7 +138,7 @@ typedef struct { /* data type for BTA_AG_API_AUDIO_OPEN_EVT */ typedef struct { - bool force_cvsd; + tBTA_AG_PEER_CODEC disabled_codecs; } tBTA_AG_API_AUDIO_OPEN; /* data type for BTA_AG_API_RESULT_EVT */ @@ -208,6 +210,14 @@ typedef enum { BTA_AG_SCO_LC3_SETTINGS_T1, } tBTA_AG_SCO_LC3_SETTINGS; +typedef enum { + BTA_AG_SCO_APTX_SWB_SETTINGS_Q0 = 0, /* preferred/default when codec is SWB */ + BTA_AG_SCO_APTX_SWB_SETTINGS_Q1 = 4, + BTA_AG_SCO_APTX_SWB_SETTINGS_Q2 = 6, + BTA_AG_SCO_APTX_SWB_SETTINGS_Q3 = 7, + BTA_AG_SCO_APTX_SWB_SETTINGS_UNKNOWN = 0xFFFF, +} tBTA_AG_SCO_APTX_SWB_SETTINGS; + /* type for each service control block */ struct tBTA_AG_SCB { char clip[BTA_AG_AT_MAX_LEN + 1]; /* number string used for CLIP */ @@ -252,6 +262,8 @@ struct tBTA_AG_SCB { alarm_t* ring_timer; alarm_t* codec_negotiation_timer; bool received_at_bac; /* indicate AT+BAC is received at least once */ + tBTA_AG_PEER_CODEC + disabled_codecs; /* set by app to block certain codecs from being used */ tBTA_AG_PEER_CODEC peer_codecs; /* codecs for eSCO supported by the peer */ tBTA_AG_PEER_CODEC sco_codec; /* codec to be used for eSCO connection */ tBTA_AG_PEER_CODEC @@ -262,6 +274,10 @@ struct tBTA_AG_SCB { impending eSCO on WB */ tBTA_AG_SCO_LC3_SETTINGS codec_lc3_settings; /* settings to be used for the impending eSCO on SWB */ + tBTA_AG_SCO_APTX_SWB_SETTINGS + codec_aptx_settings; /* settings to be used for the + aptX Voice SWB eSCO */ + bool is_aptx_swb_codec; /* Flag to determine aptX Voice SWB codec */ tBTA_AG_HF_IND peer_hf_indicators[BTA_AG_MAX_NUM_PEER_HF_IND]; /* Peer supported @@ -318,7 +334,7 @@ extern const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[]; /***************************************************************************** * Function prototypes ****************************************************************************/ -bool bta_ag_hdl_event(BT_HDR_RIGID* p_msg); +bool bta_ag_hdl_event(const BT_HDR_RIGID* p_msg); /* API functions */ void bta_ag_api_enable(tBTA_AG_CBACK* p_cback); @@ -342,7 +358,7 @@ void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event, const tBTA_AG_DATA& data); void bta_ag_sm_execute_by_handle(uint16_t handle, uint16_t event, const tBTA_AG_DATA& data); -void bta_ag_collision_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, +void bta_ag_collision_cback(tBTA_SYS_CONN_STATUS status, tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr); void bta_ag_resume_open(tBTA_AG_SCB* p_scb); @@ -367,6 +383,9 @@ bool bta_ag_sco_is_active_device(const RawAddress& bd_addr); bool bta_ag_sco_is_open(tBTA_AG_SCB* p_scb); bool bta_ag_sco_is_opening(tBTA_AG_SCB* p_scb); void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA* data); +// Testonly +void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig); +void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local); /* AT command functions */ void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, @@ -411,9 +430,12 @@ void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result); void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb); bool bta_ag_is_sco_open_allowed(tBTA_AG_SCB* p_scb, const std::string event); void bta_ag_send_bcs(tBTA_AG_SCB* p_scb); +bool bta_ag_get_sco_offload_enabled(); void bta_ag_set_sco_offload_enabled(bool value); void bta_ag_set_sco_allowed(bool value); const RawAddress& bta_ag_get_active_device(); void bta_clear_active_device(); +void bta_ag_send_qac(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data); +void bta_ag_send_qcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data); #endif /* BTA_AG_INT_H */ diff --git a/system/bta/ag/bta_ag_main.cc b/system/bta/ag/bta_ag_main.cc index f3be07f05fb1c3f1d7fb9342e4c5a4b952783af3..fbc4603f7b8c967c32517285fea15d022857e2a1 100644 --- a/system/bta/ag/bta_ag_main.cc +++ b/system/bta/ag/bta_ag_main.cc @@ -22,21 +22,22 @@ * ******************************************************************************/ +#include + #include #include #include "bta/ag/bta_ag_int.h" -#include "main/shim/dumpsys.h" +#include "bta/include/bta_hfp_api.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/alarm.h" #include "osi/include/compat.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "stack/include/btm_api.h" #include "types/raw_address.h" -#include - /***************************************************************************** * Constants and types ****************************************************************************/ @@ -160,7 +161,10 @@ static tBTA_AG_SCB* bta_ag_scb_alloc(void) { /* set eSCO mSBC setting to T2 as the preferred */ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2; p_scb->codec_lc3_settings = BTA_AG_SCO_LC3_SETTINGS_T2; - APPL_TRACE_DEBUG("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb)); + /* set eSCO SWB setting to Q0 as the preferred */ + p_scb->codec_aptx_settings = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + p_scb->is_aptx_swb_codec = false; + LOG_VERBOSE("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb)); break; } } @@ -187,7 +191,7 @@ void bta_ag_scb_dealloc(tBTA_AG_SCB* p_scb) { uint8_t idx; bool allocated = false; - APPL_TRACE_DEBUG("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb)); + LOG_VERBOSE("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb)); /* stop and free timers */ alarm_free(p_scb->ring_timer); @@ -246,11 +250,11 @@ tBTA_AG_SCB* bta_ag_scb_by_idx(uint16_t idx) { p_scb = &bta_ag_cb.scb[idx - 1]; if (!p_scb->in_use) { p_scb = nullptr; - APPL_TRACE_WARNING("ag scb idx %d not allocated", idx); + LOG_WARN("ag scb idx %d not allocated", idx); } } else { p_scb = nullptr; - APPL_TRACE_DEBUG("ag scb idx %d out of range", idx); + LOG_VERBOSE("ag scb idx %d out of range", idx); } return p_scb; } @@ -294,7 +298,7 @@ uint16_t bta_ag_idx_by_bdaddr(const RawAddress* peer_addr) { } /* no scb found */ - APPL_TRACE_WARNING("No ag scb for peer addr"); + LOG_WARN("No ag scb for peer addr"); return 0; } @@ -346,8 +350,8 @@ bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb) { * Returns void * ******************************************************************************/ -void bta_ag_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, uint8_t id, - UNUSED_ATTR uint8_t app_id, +void bta_ag_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, + tBTA_SYS_ID id, UNUSED_ATTR uint8_t app_id, const RawAddress& peer_addr) { /* Check if we have opening scb for the peer device. */ uint16_t handle = bta_ag_idx_by_bdaddr(&peer_addr); @@ -439,7 +443,7 @@ void bta_ag_api_disable() { int i; if (!bta_sys_is_register(BTA_ID_AG)) { - APPL_TRACE_ERROR("BTA AG is already disabled, ignoring ..."); + LOG_ERROR("BTA AG is already disabled, ignoring ..."); return; } @@ -771,7 +775,7 @@ void bta_ag_sm_execute_by_handle(uint16_t handle, uint16_t event, * @param p_msg event message * @return True to free p_msg, or False if p_msg is freed within this function */ -bool bta_ag_hdl_event(BT_HDR_RIGID* p_msg) { +bool bta_ag_hdl_event(const BT_HDR_RIGID* p_msg) { switch (p_msg->event) { case BTA_AG_RING_TIMEOUT_EVT: case BTA_AG_SVC_TIMEOUT_EVT: diff --git a/system/bta/ag/bta_ag_rfc.cc b/system/bta/ag/bta_ag_rfc.cc index e504a7fe8d7ea89d28e68bc0ea3b3221d214af98..95696736adce0a45df25a770352e09341a4ecc60 100644 --- a/system/bta/ag/bta_ag_rfc.cc +++ b/system/bta/ag/bta_ag_rfc.cc @@ -26,11 +26,11 @@ #include #include -#include - #include "bta/ag/bta_ag_int.h" +#include "bta/include/bta_sec_api.h" +#include "internal_include/bt_trace.h" #include "osi/include/osi.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" #include "stack/include/port_api.h" #include "types/raw_address.h" @@ -77,7 +77,7 @@ static void bta_ag_port_cback(UNUSED_ATTR uint32_t code, uint16_t port_handle, if (p_scb != nullptr) { /* ignore port events for port handles other than connected handle */ if (port_handle != p_scb->conn_handle) { - APPL_TRACE_ERROR( + LOG_ERROR( "ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d", port_handle, p_scb->conn_handle, handle); return; @@ -87,9 +87,9 @@ static void bta_ag_port_cback(UNUSED_ATTR uint32_t code, uint16_t port_handle, << handle << " peer_addr " << p_scb->peer_addr << " state " << std::to_string(p_scb->state); } - do_in_main_thread(FROM_HERE, - base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_RFC_DATA_EVT, tBTA_AG_DATA::kEmpty)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&bta_ag_sm_execute_by_handle, handle, + BTA_AG_RFC_DATA_EVT, tBTA_AG_DATA::kEmpty)); } } @@ -106,8 +106,8 @@ static void bta_ag_port_cback(UNUSED_ATTR uint32_t code, uint16_t port_handle, static void bta_ag_mgmt_cback(uint32_t code, uint16_t port_handle, uint16_t handle) { tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(handle); - APPL_TRACE_DEBUG("%s: code=%d, port_handle=%d, scb_handle=%d, p_scb=0x%08x", - __func__, code, port_handle, handle, p_scb); + LOG_VERBOSE("%s: code=%d, port_handle=%d, scb_handle=%d, p_scb=0x%p", + __func__, code, port_handle, handle, p_scb); if (p_scb == nullptr) { LOG(WARNING) << __func__ << ": cannot find scb, code=" << code << ", port_handle=" << port_handle << ", handle=" << handle; @@ -152,8 +152,8 @@ static void bta_ag_mgmt_cback(uint32_t code, uint16_t port_handle, tBTA_AG_DATA data = {}; data.rfc.port_handle = port_handle; - do_in_main_thread( - FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, event, data)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_sm_execute_by_handle, + handle, event, data)); } /******************************************************************************* @@ -267,8 +267,8 @@ void bta_ag_start_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) { << ", services=" << loghex(services) << ", mgmt_cback_index=" << management_callback_index; } - APPL_TRACE_DEBUG("%s: p_scb=0x%08x, services=0x%04x, mgmt_cback_index=%d", - __func__, p_scb, services, management_callback_index); + LOG_VERBOSE("%s: p_scb=0x%p, services=0x%04x, mgmt_cback_index=%d", + __func__, p_scb, services, management_callback_index); } } } @@ -332,8 +332,8 @@ void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { p_scb->peer_addr, &(p_scb->conn_handle), bta_ag_mgmt_cback_tbl[management_callback_index], BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); - APPL_TRACE_DEBUG( - "%s: p_scb=0x%08x, conn_handle=%d, mgmt_cback_index=%d," + LOG_VERBOSE( + "%s: p_scb=0x%p, conn_handle=%d, mgmt_cback_index=%d," " status=%d", __func__, p_scb, p_scb->conn_handle, management_callback_index, status); if (status == PORT_SUCCESS) { @@ -367,8 +367,8 @@ void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, /* and move back to INIT state. */ do_in_main_thread( FROM_HERE, - base::Bind(&bta_ag_sm_execute_by_handle, bta_ag_scb_to_idx(p_scb), - BTA_AG_RFC_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); + base::BindOnce(&bta_ag_sm_execute_by_handle, bta_ag_scb_to_idx(p_scb), + BTA_AG_RFC_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); /* Cancel SDP if it had been started. */ /* diff --git a/system/bta/ag/bta_ag_sco.cc b/system/bta/ag/bta_ag_sco.cc index f81c82f29cfd09d196a0d1aa470cacb508e54636..5ecfdd5e00f5172a89fc7ac0e2560342c7122545 100644 --- a/system/bta/ag/bta_ag_sco.cc +++ b/system/bta/ag/bta_ag_sco.cc @@ -22,25 +22,25 @@ * ******************************************************************************/ +#include #include #include #include -#include "bt_target.h" // Must be first to define build configuration -#include "bt_trace.h" // Legacy trace logging #include "bta/ag/bta_ag_int.h" +#include "bta_ag_swb_aptx.h" #include "common/init_flags.h" #include "device/include/controller.h" -#include "main/shim/dumpsys.h" -#include "osi/include/log.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" +#include "os/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/btm/btm_int_types.h" #include "stack/btm/btm_sco.h" #include "stack/btm/btm_sco_hfp_hal.h" -#include "stack/include/acl_api.h" #include "stack/include/btm_api.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" #include "types/raw_address.h" extern tBTM_CB btm_cb; @@ -50,6 +50,14 @@ extern tBTM_CB btm_cb; #define BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS (3 * 1000) /* 3 seconds */ #endif +#define BTM_VOICE_SETTING_CVSD \ + ((uint16_t)(HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | \ + HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_CVSD)) + +#define BTM_VOICE_SETTING_TRANS \ + ((uint16_t)(HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | \ + HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_TRANSPNT)) + static bool sco_allowed = true; static RawAddress active_device_addr = {}; @@ -115,8 +123,6 @@ bool bta_ag_sco_is_active_device(const RawAddress& bd_addr) { return !active_device_addr.IsEmpty() && active_device_addr == bd_addr; } -static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local); - /******************************************************************************* * * Function bta_ag_sco_conn_cback @@ -144,9 +150,9 @@ static void bta_ag_sco_conn_cback(uint16_t sco_idx) { } if (handle != 0) { - do_in_main_thread(FROM_HERE, - base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_SCO_OPEN_EVT, tBTA_AG_DATA::kEmpty)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&bta_ag_sm_execute_by_handle, handle, + BTA_AG_SCO_OPEN_EVT, tBTA_AG_DATA::kEmpty)); } else { /* no match found; disconnect sco, init sco variables */ bta_ag_cb.sco.p_curr_scb = nullptr; @@ -190,9 +196,17 @@ static void bta_ag_sco_disc_cback(uint16_t sco_idx) { } if (handle != 0) { + const bool aptx_voice = + is_hfp_aptx_voice_enabled() && + (bta_ag_cb.sco.p_curr_scb->is_aptx_swb_codec == true) && + (bta_ag_cb.sco.p_curr_scb->inuse_codec == + BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + LOG_VERBOSE("aptx_voice=%s, inuse_codec=%#x", logbool(aptx_voice).c_str(), + bta_ag_cb.sco.p_curr_scb->inuse_codec); + /* Restore settings */ if (bta_ag_cb.sco.p_curr_scb->inuse_codec == UUID_CODEC_MSBC || - bta_ag_cb.sco.p_curr_scb->inuse_codec == UUID_CODEC_LC3) { + bta_ag_cb.sco.p_curr_scb->inuse_codec == UUID_CODEC_LC3 || aptx_voice) { /* Bypass vendor specific and voice settings if enhanced eSCO supported */ if (!(controller_get_interface() ->supports_enhanced_setup_synchronous_connection())) { @@ -207,13 +221,13 @@ static void bta_ag_sco_disc_cback(uint16_t sco_idx) { if (bta_ag_cb.sco.p_curr_scb->inuse_codec == UUID_CODEC_LC3) { if (bta_ag_cb.sco.p_curr_scb->codec_lc3_settings == BTA_AG_SCO_LC3_SETTINGS_T2) { - APPL_TRACE_WARNING( + LOG_WARN( "%s: eSCO/SCO failed to open, falling back to LC3 T1 settings", __func__); bta_ag_cb.sco.p_curr_scb->codec_lc3_settings = BTA_AG_SCO_LC3_SETTINGS_T1; } else { - APPL_TRACE_WARNING( + LOG_WARN( "%s: eSCO/SCO failed to open, falling back to CVSD settings", __func__); bta_ag_cb.sco.p_curr_scb->inuse_codec = UUID_CODEC_CVSD; @@ -222,33 +236,32 @@ static void bta_ag_sco_disc_cback(uint16_t sco_idx) { } else { if (bta_ag_cb.sco.p_curr_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2) { - APPL_TRACE_WARNING( + LOG_WARN( "%s: eSCO/SCO failed to open, falling back to mSBC T1 settings", __func__); bta_ag_cb.sco.p_curr_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T1; } else { - APPL_TRACE_WARNING( - "%s: eSCO/SCO failed to open, falling back to CVSD", __func__); + LOG_WARN("%s: eSCO/SCO failed to open, falling back to CVSD", + __func__); bta_ag_cb.sco.p_curr_scb->inuse_codec = UUID_CODEC_CVSD; bta_ag_cb.sco.p_curr_scb->codec_fallback = true; } } } } else if (bta_ag_sco_is_opening(bta_ag_cb.sco.p_curr_scb)) { - APPL_TRACE_ERROR("%s: eSCO/SCO failed to open, no more fall back", - __func__); + LOG_ERROR("%s: eSCO/SCO failed to open, no more fall back", __func__); } bta_ag_cb.sco.p_curr_scb->inuse_codec = BTM_SCO_CODEC_NONE; - do_in_main_thread(FROM_HERE, - base::Bind(&bta_ag_sm_execute_by_handle, handle, - BTA_AG_SCO_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&bta_ag_sm_execute_by_handle, handle, + BTA_AG_SCO_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); } else { /* no match found */ - APPL_TRACE_DEBUG("no scb for ag_sco_disc_cback"); + LOG_VERBOSE("no scb for ag_sco_disc_cback"); /* sco could be closed after scb dealloc'ed */ if (bta_ag_cb.sco.p_curr_scb != nullptr) { @@ -312,8 +325,8 @@ static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, /* If no other SCO active, allow this one */ if (!bta_ag_cb.sco.p_curr_scb) { - APPL_TRACE_EVENT("%s: Accept Conn Request (sco_inx 0x%04x)", __func__, - sco_inx); + LOG_VERBOSE("%s: Accept Conn Request (sco_inx 0x%04x)", __func__, + sco_inx); bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt); bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST; @@ -321,13 +334,13 @@ static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, bta_ag_cb.sco.cur_idx = p_scb->sco_idx; } else { /* Begin a transfer: Close current SCO before responding */ - APPL_TRACE_DEBUG("bta_ag_esco_connreq_cback: Begin XFER"); + LOG_VERBOSE("bta_ag_esco_connreq_cback: Begin XFER"); bta_ag_cb.sco.p_xfer_scb = p_scb; bta_ag_cb.sco.conn_data = p_data->conn_evt; bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST; if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, true)) { - APPL_TRACE_ERROR( + LOG_ERROR( "%s: Nothing to remove,so accept Conn Request(sco_inx 0x%04x)", __func__, sco_inx); bta_ag_cb.sco.p_xfer_scb = nullptr; @@ -377,7 +390,7 @@ static void bta_ag_cback_sco(tBTA_AG_SCB* p_scb, tBTA_AG_EVT event) { * Returns void * ******************************************************************************/ -static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) { +void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) { LOG_DEBUG("BEFORE %s", p_scb->ToString().c_str()); tBTA_AG_PEER_CODEC esco_codec = UUID_CODEC_CVSD; @@ -386,17 +399,16 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) { << " is not active, active_device=" << active_device_addr; if (bta_ag_cb.sco.p_curr_scb != nullptr && bta_ag_cb.sco.p_curr_scb->in_use && p_scb == bta_ag_cb.sco.p_curr_scb) { - do_in_main_thread( - FROM_HERE, base::Bind(&bta_ag_sm_execute, p_scb, BTA_AG_SCO_CLOSE_EVT, - tBTA_AG_DATA::kEmpty)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_sm_execute, p_scb, + BTA_AG_SCO_CLOSE_EVT, + tBTA_AG_DATA::kEmpty)); } return; } /* Make sure this SCO handle is not already in use */ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) { - APPL_TRACE_ERROR("%s: device %s, index 0x%04x already in use!", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr), - p_scb->sco_idx); + LOG_ERROR("%s: device %s, index 0x%04x already in use!", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr), p_scb->sco_idx); return; } @@ -407,6 +419,13 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) { } #endif + if (is_hfp_aptx_voice_enabled()) { + if ((p_scb->sco_codec == BTA_AG_SCO_APTX_SWB_SETTINGS_Q0) && + !p_scb->codec_fallback) { + esco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + } + } + if ((p_scb->sco_codec == BTM_SCO_CODEC_LC3) && !p_scb->codec_fallback && hfp_hal_interface::get_swb_supported()) { esco_codec = UUID_CODEC_LC3; @@ -420,6 +439,8 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) { p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2; /* Reset LC3 settings to T2 for the next audio connection */ p_scb->codec_lc3_settings = BTA_AG_SCO_LC3_SETTINGS_T2; + /* Reset SWB settings to Q3 for the next audio connection */ + p_scb->codec_aptx_settings = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; } bool offload = hfp_hal_interface::get_offload_enabled(); @@ -442,8 +463,19 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) { } else { params = esco_parameters_for_codec(ESCO_CODEC_MSBC_T1, offload); } + } else if (is_hfp_aptx_voice_enabled() && + (p_scb->is_aptx_swb_codec == true && !p_scb->codec_updated)) { + if (p_scb->codec_aptx_settings == BTA_AG_SCO_APTX_SWB_SETTINGS_Q3) { + params = esco_parameters_for_codec(ESCO_CODEC_SWB_Q3, true); + } else if (p_scb->codec_aptx_settings == BTA_AG_SCO_APTX_SWB_SETTINGS_Q2) { + params = esco_parameters_for_codec(ESCO_CODEC_SWB_Q2, true); + } else if (p_scb->codec_aptx_settings == BTA_AG_SCO_APTX_SWB_SETTINGS_Q1) { + params = esco_parameters_for_codec(ESCO_CODEC_SWB_Q1, true); + } else if (p_scb->codec_aptx_settings == BTA_AG_SCO_APTX_SWB_SETTINGS_Q0) { + params = esco_parameters_for_codec(ESCO_CODEC_SWB_Q0, true); + } } else { - if (p_scb->features & BTA_AG_PEER_FEAT_ESCO_S4 && + if ((p_scb->features & BTA_AG_FEAT_ESCO_S4) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ESCO_S4)) { // HFP >=1.7 eSCO params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4, offload); @@ -500,7 +532,7 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) { * Returns void * ******************************************************************************/ -static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) { +void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) { tBTA_AG_PEER_CODEC esco_codec = p_scb->inuse_codec; enh_esco_params_t params = {}; bool offload = hfp_hal_interface::get_offload_enabled(); @@ -515,6 +547,20 @@ static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) { } else { params = esco_parameters_for_codec(ESCO_CODEC_LC3_T1, offload); } + } else if (is_hfp_aptx_voice_enabled() && + (p_scb->is_aptx_swb_codec == true && !p_scb->codec_updated)) { + if (p_scb->codec_aptx_settings == BTA_AG_SCO_APTX_SWB_SETTINGS_Q3) { + params = esco_parameters_for_codec(ESCO_CODEC_SWB_Q3, true); + } else if (p_scb->codec_aptx_settings == + BTA_AG_SCO_APTX_SWB_SETTINGS_Q2) { + params = esco_parameters_for_codec(ESCO_CODEC_SWB_Q2, true); + } else if (p_scb->codec_aptx_settings == + BTA_AG_SCO_APTX_SWB_SETTINGS_Q1) { + params = esco_parameters_for_codec(ESCO_CODEC_SWB_Q1, true); + } else if (p_scb->codec_aptx_settings == + BTA_AG_SCO_APTX_SWB_SETTINGS_Q0) { + params = esco_parameters_for_codec(ESCO_CODEC_SWB_Q0, true); + } } else if (esco_codec == UUID_CODEC_MSBC) { if (p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2) { params = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2, offload); @@ -522,7 +568,7 @@ static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) { params = esco_parameters_for_codec(ESCO_CODEC_MSBC_T1, offload); } } else { - if (p_scb->features & BTA_AG_PEER_FEAT_ESCO_S4 && + if ((p_scb->features & BTA_AG_FEAT_ESCO_S4) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ESCO_S4)) { // HFP >=1.7 eSCO params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4, offload); @@ -535,7 +581,7 @@ static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) { /* Bypass voice settings if enhanced SCO setup command is supported */ if (!(controller_get_interface() ->supports_enhanced_setup_synchronous_connection())) { - if (esco_codec == BTM_SCO_CODEC_MSBC) { + if (esco_codec == UUID_CODEC_MSBC || esco_codec == UUID_CODEC_LC3) { BTM_WriteVoiceSettings(BTM_VOICE_SETTING_TRANS); } else { BTM_WriteVoiceSettings(BTM_VOICE_SETTING_CVSD); @@ -550,14 +596,14 @@ static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) { /* Configure input/output data. */ hfp_hal_interface::set_codec_datapath(esco_codec); } - APPL_TRACE_DEBUG("%s: initiated SCO connection", __func__); + LOG_VERBOSE("%s: initiated SCO connection", __func__); } else { // Local device accepted SCO connection from peer(HF) // Because HF devices usually do not send AT+BAC and +BCS command, // and there is no plan to implement corresponding command handlers, // so we only accept CVSD connection from HF no matter what's // requested. - if (p_scb->features & BTA_AG_PEER_FEAT_ESCO_S4 && + if ((p_scb->features & BTA_AG_FEAT_ESCO_S4) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ESCO_S4)) { // HFP >=1.7 eSCO params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4, offload); @@ -571,12 +617,12 @@ static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) { if (p_scb->sco_idx < BTM_MAX_SCO_LINKS) p_sco = &btm_cb.sco_cb.sco_db[p_scb->sco_idx]; if (p_sco && (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO || - !sco_peer_supports_esco_ev3(p_sco->esco.data.bd_addr))) { + !btm_peer_supports_esco_ev3(p_sco->esco.data.bd_addr))) { params = esco_parameters_for_codec(SCO_CODEC_CVSD_D1, offload); } BTM_EScoConnRsp(p_scb->sco_idx, HCI_SUCCESS, ¶ms); - APPL_TRACE_DEBUG("%s: listening for SCO connection", __func__); + LOG_VERBOSE("%s: listening for SCO connection", __func__); } } @@ -636,16 +682,42 @@ void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb) { LOG_INFO("Assume CVSD by default due to mask mismatch"); p_scb->sco_codec = UUID_CODEC_CVSD; } - - if ((p_scb->codec_updated || p_scb->codec_fallback) && - (p_scb->features & BTA_AG_FEAT_CODEC) && - (p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) { + const bool aptx_voice = + is_hfp_aptx_voice_enabled() && p_scb->is_aptx_swb_codec && + (p_scb->peer_codecs & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK); + LOG_VERBOSE("aptx_voice=%s, is_aptx_swb_codec=%s, Q0 codec supported=%s", + logbool(aptx_voice).c_str(), + logbool(p_scb->is_aptx_swb_codec).c_str(), + logbool(p_scb->peer_codecs & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK) + .c_str()); + + if (((p_scb->codec_updated || p_scb->codec_fallback) && + (p_scb->features & BTA_AG_FEAT_CODEC) && + (p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) || + (aptx_voice)) { LOG_INFO("Starting codec negotiation"); /* Change the power mode to Active until SCO open is completed. */ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); - /* Send +BCS to the peer */ - bta_ag_send_bcs(p_scb); + if (p_scb->peer_codecs & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK) { + if (p_scb->is_aptx_swb_codec == false) { + p_scb->sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + p_scb->is_aptx_swb_codec = true; + } + LOG_VERBOSE("Sending +QCS, sco_codec=%d, is_aptx_swb_codec=%s", + p_scb->sco_codec, logbool(p_scb->is_aptx_swb_codec).c_str()); + /* Send +QCS to the peer */ + bta_ag_send_qcs(p_scb, NULL); + } else { + if (aptx_voice) { + p_scb->sco_codec = BTM_SCO_CODEC_MSBC; + p_scb->is_aptx_swb_codec = false; + } + LOG_VERBOSE("Sending +BCS, sco_codec=%d, is_aptx_swb_codec=%s", + p_scb->sco_codec, logbool(p_scb->is_aptx_swb_codec).c_str()); + /* Send +BCS to the peer */ + bta_ag_send_bcs(p_scb); + } /* Start timer to handle timeout */ alarm_set_on_mloop(p_scb->codec_negotiation_timer, @@ -1237,9 +1309,26 @@ void bta_ag_sco_open(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) { return; } - if (data.api_audio_open.force_cvsd) { - LOG(INFO) << __func__ << ": set to use fallback codec"; - p_scb->codec_fallback = true; + p_scb->disabled_codecs = data.api_audio_open.disabled_codecs; + LOG(INFO) << __func__ << ": disabled_codecs = " << p_scb->disabled_codecs + << ", sco_codec = " << p_scb->sco_codec; + + if (p_scb->disabled_codecs & p_scb->sco_codec) { + tBTA_AG_PEER_CODEC updated_codec = BTM_SCO_CODEC_NONE; + + if (hfp_hal_interface::get_swb_supported() && + (p_scb->peer_codecs & BTM_SCO_CODEC_LC3) && + !(p_scb->disabled_codecs & BTM_SCO_CODEC_LC3)) { + updated_codec = BTM_SCO_CODEC_LC3; + } else if ((p_scb->peer_codecs & BTM_SCO_CODEC_MSBC) && + !(p_scb->disabled_codecs & BTM_SCO_CODEC_MSBC)) { + updated_codec = BTM_SCO_CODEC_MSBC; + } else { + updated_codec = BTM_SCO_CODEC_CVSD; + } + + p_scb->sco_codec = updated_codec; + p_scb->codec_updated = true; } /* if another scb using sco, this is a transfer */ @@ -1272,7 +1361,7 @@ void bta_ag_sco_close(tBTA_AG_SCB* p_scb, * state. */ if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) || (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST)) { - APPL_TRACE_DEBUG("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx); + LOG_VERBOSE("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx); bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E); } } @@ -1340,6 +1429,8 @@ void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb, p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2; /* reset to LC3 T2 settings as the preferred */ p_scb->codec_lc3_settings = BTA_AG_SCO_LC3_SETTINGS_T2; + /* reset to SWB Q0 settings as the preferred */ + p_scb->codec_aptx_settings = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; } /******************************************************************************* @@ -1357,6 +1448,12 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb, /* clear current scb */ bta_ag_cb.sco.p_curr_scb = nullptr; p_scb->sco_idx = BTM_INVALID_SCO_INDEX; + const bool aptx_voice = is_hfp_aptx_voice_enabled() && + p_scb->codec_fallback && + (p_scb->sco_codec == BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + LOG_VERBOSE("aptx_voice=%s, codec_fallback=%#x, sco_codec=%#x", + logbool(aptx_voice).c_str(), p_scb->codec_fallback, + p_scb->sco_codec); /* codec_fallback is set when AG is initiator and connection failed for mSBC. * OR if codec is msbc and T2 settings failed, then retry Safe T1 settings @@ -1366,7 +1463,8 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb, (p_scb->sco_codec == BTM_SCO_CODEC_MSBC && p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T1) || (p_scb->sco_codec == BTM_SCO_CODEC_LC3 && - p_scb->codec_lc3_settings == BTA_AG_SCO_LC3_SETTINGS_T1))) { + p_scb->codec_lc3_settings == BTA_AG_SCO_LC3_SETTINGS_T1) || + aptx_voice)) { bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E); } else { /* Indicate if the closing of audio is because of transfer */ @@ -1386,6 +1484,7 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb, bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT); p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2; p_scb->codec_lc3_settings = BTA_AG_SCO_LC3_SETTINGS_T2; + p_scb->codec_aptx_settings = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; } } @@ -1403,10 +1502,10 @@ void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) { bta_ag_cb.sco.is_local = false; - APPL_TRACE_DEBUG("%s: eSCO %d, state %d", __func__, - controller_get_interface() - ->supports_enhanced_setup_synchronous_connection(), - bta_ag_cb.sco.state); + LOG_VERBOSE("%s: eSCO %d, state %d", __func__, + controller_get_interface() + ->supports_enhanced_setup_synchronous_connection(), + bta_ag_cb.sco.state); if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST || bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST || @@ -1422,22 +1521,29 @@ void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb, bta_ag_create_pending_sco(p_scb, bta_ag_cb.sco.is_local); } +bool bta_ag_get_sco_offload_enabled() { + return hfp_hal_interface::get_offload_enabled(); +} + void bta_ag_set_sco_offload_enabled(bool value) { hfp_hal_interface::enable_offload(value); } void bta_ag_set_sco_allowed(bool value) { sco_allowed = value; - APPL_TRACE_DEBUG(sco_allowed ? "sco now allowed" : "sco now not allowed"); + LOG_VERBOSE("%s", sco_allowed ? "sco now allowed" : "sco now not allowed"); } const RawAddress& bta_ag_get_active_device() { return active_device_addr; } -void bta_clear_active_device() { active_device_addr = RawAddress::kEmpty; } +void bta_clear_active_device() { + LOG_DEBUG("Set bta active device to null"); + active_device_addr = RawAddress::kEmpty; +} void bta_ag_api_set_active_device(const RawAddress& new_active_device) { if (new_active_device.IsEmpty()) { - APPL_TRACE_ERROR("%s: empty device", __func__); + LOG_ERROR("%s: empty device", __func__); return; } active_device_addr = new_active_device; diff --git a/system/bta/ag/bta_ag_sdp.cc b/system/bta/ag/bta_ag_sdp.cc index 7e99d2b407267fbe8baba5d65b900d5c9d4f50a4..1314cc4b9ac07bd78d4fdecf0f979a4e02153b37 100644 --- a/system/bta/ag/bta_ag_sdp.cc +++ b/system/bta/ag/bta_ag_sdp.cc @@ -27,21 +27,25 @@ #include #include -#include "bt_target.h" // Legacy stack config -#include "bt_trace.h" // Legacy trace logging #include "bta/ag/bta_ag_int.h" +#include "bta/include/bta_hfp_api.h" +#include "bta/include/bta_rfcomm_scn.h" #include "btif/include/btif_config.h" #include "common/init_flags.h" #include "device/include/interop.h" #include "device/include/interop_config.h" +#include "internal_include/bt_target.h" #include "os/log.h" #include "osi/include/allocator.h" +#include "osi/include/osi.h" // UNUSED_ATTR #include "stack/btm/btm_sco_hfp_hal.h" -#include "stack/include/btm_api.h" -#include "stack/include/btu.h" // do_in_main_thread -#include "stack/include/port_api.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/main_thread.h" +#include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" +using namespace bluetooth::legacy::stack::sdp; using bluetooth::Uuid; /* Number of protocol elements in protocol element list. */ @@ -56,12 +60,12 @@ using bluetooth::Uuid; #endif /* declare sdp callback functions */ -void bta_ag_sdp_cback_1(tSDP_RESULT); -void bta_ag_sdp_cback_2(tSDP_RESULT); -void bta_ag_sdp_cback_3(tSDP_RESULT); -void bta_ag_sdp_cback_4(tSDP_RESULT); -void bta_ag_sdp_cback_5(tSDP_RESULT); -void bta_ag_sdp_cback_6(tSDP_RESULT); +void bta_ag_sdp_cback_1(const RawAddress& bd_addr, tSDP_RESULT); +void bta_ag_sdp_cback_2(const RawAddress& bd_addr, tSDP_RESULT); +void bta_ag_sdp_cback_3(const RawAddress& bd_addr, tSDP_RESULT); +void bta_ag_sdp_cback_4(const RawAddress& bd_addr, tSDP_RESULT); +void bta_ag_sdp_cback_5(const RawAddress& bd_addr, tSDP_RESULT); +void bta_ag_sdp_cback_6(const RawAddress& bd_addr, tSDP_RESULT); /* SDP callback function table */ typedef tSDP_DISC_CMPL_CB* tBTA_AG_SDP_CBACK; @@ -80,7 +84,7 @@ const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] = { * ******************************************************************************/ static void bta_ag_sdp_cback(uint16_t status, uint8_t idx) { - APPL_TRACE_DEBUG("%s status:0x%x", __func__, status); + LOG_VERBOSE("%s status:0x%x", __func__, status); tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(idx); if (p_scb) { uint16_t event; @@ -91,8 +95,8 @@ static void bta_ag_sdp_cback(uint16_t status, uint8_t idx) { event = BTA_AG_DISC_INT_RES_EVT; } tBTA_AG_DATA disc_result = {.disc_result = {.status = status}}; - do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, idx, - event, disc_result)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_ag_sm_execute_by_handle, + idx, event, disc_result)); } } @@ -108,12 +112,30 @@ static void bta_ag_sdp_cback(uint16_t status, uint8_t idx) { * Returns void * ******************************************************************************/ -void bta_ag_sdp_cback_1(tSDP_STATUS status) { bta_ag_sdp_cback(status, 1); } -void bta_ag_sdp_cback_2(tSDP_STATUS status) { bta_ag_sdp_cback(status, 2); } -void bta_ag_sdp_cback_3(tSDP_STATUS status) { bta_ag_sdp_cback(status, 3); } -void bta_ag_sdp_cback_4(tSDP_STATUS status) { bta_ag_sdp_cback(status, 4); } -void bta_ag_sdp_cback_5(tSDP_STATUS status) { bta_ag_sdp_cback(status, 5); } -void bta_ag_sdp_cback_6(tSDP_STATUS status) { bta_ag_sdp_cback(status, 6); } +void bta_ag_sdp_cback_1(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status) { + bta_ag_sdp_cback(status, 1); +} +void bta_ag_sdp_cback_2(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status) { + bta_ag_sdp_cback(status, 2); +} +void bta_ag_sdp_cback_3(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status) { + bta_ag_sdp_cback(status, 3); +} +void bta_ag_sdp_cback_4(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status) { + bta_ag_sdp_cback(status, 4); +} +void bta_ag_sdp_cback_5(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status) { + bta_ag_sdp_cback(status, 5); +} +void bta_ag_sdp_cback_6(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status) { + bta_ag_sdp_cback(status, 6); +} /****************************************************************************** * @@ -139,10 +161,9 @@ bool bta_ag_add_record(uint16_t service_uuid, const char* p_service_name, uint8_t network; bool result = true; bool codec_supported = false; - bool swb_supported = false; uint8_t buf[2]; - APPL_TRACE_DEBUG("%s uuid: %x", __func__, service_uuid); + LOG_VERBOSE("%s uuid: %x", __func__, service_uuid); LOG_INFO("features: %d", features); for (auto& proto_element : proto_elem_list) { @@ -155,14 +176,14 @@ bool bta_ag_add_record(uint16_t service_uuid, const char* p_service_name, proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; proto_elem_list[1].num_params = 1; proto_elem_list[1].params[0] = scn; - result &= - SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList( + sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list); /* add service class id list */ svc_class_id_list[0] = service_uuid; svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO; - result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS, - svc_class_id_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList( + sdp_handle, BTA_AG_NUM_SVC_ELEMS, svc_class_id_list); /* add profile descriptor list */ if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) { @@ -176,11 +197,12 @@ bool bta_ag_add_record(uint16_t service_uuid, const char* p_service_name, profile_uuid = UUID_SERVCLASS_HEADSET; version = HSP_VERSION_1_2; } - result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList( + sdp_handle, profile_uuid, version); /* add service name */ if (p_service_name != nullptr && p_service_name[0] != 0) { - result &= SDP_AddAttribute( + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name); } @@ -188,31 +210,29 @@ bool bta_ag_add_record(uint16_t service_uuid, const char* p_service_name, /* add features and network */ if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) { network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0; - result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK, - UINT_DESC_TYPE, 1, &network); - - // check property for SWB support - if (hfp_hal_interface::get_swb_supported()) { - features |= BTA_AG_FEAT_SWB; - } + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK, UINT_DESC_TYPE, 1, + &network); if (features & BTA_AG_FEAT_CODEC) codec_supported = true; - if (features & BTA_AG_FEAT_SWB) swb_supported = true; features &= BTA_AG_SDP_FEAT_SPEC; /* Codec bit position is different in SDP and in BRSF */ if (codec_supported) features |= BTA_AG_FEAT_WBS_SUPPORT; - if (swb_supported) features |= BTA_AG_FEAT_SWB_SUPPORT; + // check property for SWB support + if (hfp_hal_interface::get_swb_supported()) { + features |= BTA_AG_FEAT_SWB_SUPPORT; + } UINT16_TO_BE_FIELD(buf, features); - result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, - UINT_DESC_TYPE, 2, buf); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf); } /* add browse group list */ - result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, - browse_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence( + sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); return result; } @@ -237,8 +257,9 @@ void bta_ag_create_records(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { if (services & 1) { /* add sdp record if not already registered */ if (bta_ag_cb.profile[i].sdp_handle == 0) { - bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord(); - bta_ag_cb.profile[i].scn = BTM_AllocateSCN(); + bta_ag_cb.profile[i].sdp_handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); + bta_ag_cb.profile[i].scn = BTA_AllocateSCN(); bta_ag_add_record(bta_ag_uuid[i], data.api_register.p_name[i], bta_ag_cb.profile[i].scn, data.api_register.features, bta_ag_cb.profile[i].sdp_handle); @@ -282,12 +303,13 @@ void bta_ag_del_records(tBTA_AG_SCB* p_scb) { /* if service registered for this scb and not registered for any other scb */ if (((services & 1) == 1) && ((others & 1) == 0)) { - APPL_TRACE_DEBUG("bta_ag_del_records %d", i); + LOG_VERBOSE("bta_ag_del_records %d", i); if (bta_ag_cb.profile[i].sdp_handle != 0) { - SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + bta_ag_cb.profile[i].sdp_handle); bta_ag_cb.profile[i].sdp_handle = 0; } - BTM_FreeSCN(bta_ag_cb.profile[i].scn); + BTA_FreeSCN(bta_ag_cb.profile[i].scn); bta_sys_remove_uuid(bta_ag_uuid[i]); } } @@ -328,13 +350,15 @@ bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) { /* loop through all records we found */ while (true) { /* get next record; if none found, we're done */ - p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb(p_scb->p_disc_db, + uuid, p_rec); if (p_rec == nullptr) { if (uuid == UUID_SERVCLASS_HEADSET_HS) { /* Search again in case the peer device uses the old HSP UUID */ uuid = UUID_SERVCLASS_HEADSET; p_scb->peer_version = HSP_VERSION_1_0; - p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_scb->p_disc_db, uuid, p_rec); if (p_rec == nullptr) { break; } @@ -344,7 +368,8 @@ bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) { /* get scn from proto desc list if initiator */ if (p_scb->role == BTA_AG_INT) { - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { p_scb->peer_scn = (uint8_t)pe.params[0]; } else { continue; @@ -353,9 +378,10 @@ bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) { /* get profile version (if failure, version parameter is not updated) */ uint16_t peer_version = HFP_HSP_VERSION_UNKNOWN; - if (!SDP_FindProfileVersionInRec(p_rec, uuid, &peer_version)) { - APPL_TRACE_WARNING("%s: Get peer_version failed, using default 0x%04x", - __func__, p_scb->peer_version); + if (!get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, uuid, &peer_version)) { + LOG_WARN("%s: Get peer_version failed, using default 0x%04x", __func__, + p_scb->peer_version); peer_version = p_scb->peer_version; } @@ -367,13 +393,13 @@ bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) { p_scb->peer_addr.ToString(), HFP_VERSION_CONFIG_KEY, (const uint8_t*)&peer_version, sizeof(peer_version))) { } else { - APPL_TRACE_WARNING("%s: Failed to store peer HFP version for %s", - __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr)); + LOG_WARN("%s: Failed to store peer HFP version for %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr)); } } /* get features if HFP */ - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SUPPORTED_FEATURES); if (p_attr != nullptr && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -397,9 +423,8 @@ bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) { p_scb->peer_addr.ToString(), HFP_SDP_FEATURES_CONFIG_KEY, (const uint8_t*)&sdp_features, sizeof(sdp_features))) { } else { - APPL_TRACE_WARNING( - "%s: Failed to store peer HFP SDP Features for %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr)); + LOG_WARN("%s: Failed to store peer HFP SDP Features for %s", + __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->peer_addr)); } } if (p_scb->peer_features == 0) { @@ -407,7 +432,10 @@ bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) { } /* Remote supports 1.7, store it in HFP 1.7 BL file */ if (bluetooth::common::init_flags::hfp_dynamic_version_is_enabled()) { - if (p_scb->peer_version == HFP_VERSION_1_7) { + if (p_scb->peer_version >= HFP_VERSION_1_9) { + interop_database_add_addr(INTEROP_HFP_1_9_ALLOWLIST, + &p_scb->peer_addr, 3); + } else if (p_scb->peer_version >= HFP_VERSION_1_7) { interop_database_add_addr(INTEROP_HFP_1_7_ALLOWLIST, &p_scb->peer_addr, 3); } @@ -417,8 +445,8 @@ bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) { /* No peer version caching for HSP, use discovered one directly */ p_scb->peer_version = peer_version; /* get features if HSP */ - p_attr = - SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL); if (p_attr != nullptr && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) { @@ -510,9 +538,10 @@ void bta_ag_do_disc(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) { /* allocate buffer for sdp database */ p_scb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_AG_DISC_BUF_SIZE); /* set up service discovery database; attr happens to be attr_list len */ - if (SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid, - uuid_list, num_attr, attr_list)) { - if (SDP_ServiceSearchAttributeRequest( + if (get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid, uuid_list, num_attr, + attr_list)) { + if (get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest( p_scb->peer_addr, p_scb->p_disc_db, bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1])) { return; diff --git a/system/bta/ag/bta_ag_swb_aptx.cc b/system/bta/ag/bta_ag_swb_aptx.cc new file mode 100644 index 0000000000000000000000000000000000000000..b24f5c8fc40be2ff8b8924e1b2def77db14dce2e --- /dev/null +++ b/system/bta/ag/bta_ag_swb_aptx.cc @@ -0,0 +1,121 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bta_ag_swb_aptx.h" + +#include +#include +#include +#include + +#include "bta/ag/bta_ag_int.h" +#include "common/strings.h" +#include "stack/include/btm_api_types.h" + +bool is_hfp_aptx_voice_enabled() { + return IS_FLAG_ENABLED(hfp_codec_aptx_voice) && + GET_SYSPROP(Hfp, codec_aptx_voice, false); +} + +void bta_ag_swb_handle_vs_at_events(tBTA_AG_SCB* p_scb, uint16_t cmd, + int16_t int_arg, tBTA_AG_VAL* val) { + switch (cmd) { + case BTA_AG_AT_QAC_EVT: + LOG_VERBOSE("BTA_AG_AT_QAC_EVT"); + p_scb->codec_updated = true; + if (p_scb->peer_codecs & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK) { + p_scb->sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + } else if (p_scb->peer_codecs & BTM_SCO_CODEC_MSBC) { + p_scb->sco_codec = UUID_CODEC_MSBC; + } + bta_ag_send_qac(p_scb, NULL); + LOG_VERBOSE("Received AT+QAC, updating sco codec to SWB: %d", + p_scb->sco_codec); + val->num = p_scb->peer_codecs; + break; + case BTA_AG_AT_QCS_EVT: { + tBTA_AG_PEER_CODEC codec_type, codec_sent; + alarm_cancel(p_scb->codec_negotiation_timer); + + LOG_VERBOSE("BTA_AG_AT_QCS_EVT int_arg=%d", int_arg); + switch (int_arg) { + case BTA_AG_SCO_APTX_SWB_SETTINGS_Q0: + codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + break; + case BTA_AG_SCO_APTX_SWB_SETTINGS_Q1: + codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q1; + break; + case BTA_AG_SCO_APTX_SWB_SETTINGS_Q2: + codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q2; + break; + case BTA_AG_SCO_APTX_SWB_SETTINGS_Q3: + codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q3; + break; + default: + LOG_ERROR("Unknown codec_uuid %d", int_arg); + p_scb->is_aptx_swb_codec = false; + codec_type = BTM_SCO_CODEC_MSBC; + p_scb->codec_fallback = true; + p_scb->sco_codec = BTM_SCO_CODEC_MSBC; + break; + } + + if (p_scb->codec_fallback) { + codec_sent = BTM_SCO_CODEC_MSBC; + } else { + codec_sent = p_scb->sco_codec; + } + + bta_ag_sco_codec_nego(p_scb, codec_type == codec_sent); + + /* send final codec info to callback */ + val->num = codec_sent; + break; + } + } +} + +tBTA_AG_PEER_CODEC bta_ag_parse_qac(char* p_s) { + tBTA_AG_PEER_CODEC retval = BTM_SCO_CODEC_NONE; + tBTA_AG_SCO_APTX_SWB_SETTINGS codec_mode = + BTA_AG_SCO_APTX_SWB_SETTINGS_UNKNOWN; + + auto codec_modes = + bluetooth::common::StringSplit(std::string(p_s), ",", SWB_CODECS_NUMBER); + for (auto& codec_mode_str : codec_modes) { + if (!std::isdigit(*codec_mode_str.c_str())) continue; + codec_mode = static_cast( + std::atoi(codec_mode_str.c_str())); + switch (codec_mode) { + case BTA_AG_SCO_APTX_SWB_SETTINGS_Q0: + retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK; + break; + case BTA_AG_SCO_APTX_SWB_SETTINGS_Q1: + retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK; + break; + case BTA_AG_SCO_APTX_SWB_SETTINGS_Q2: + retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK; + break; + case BTA_AG_SCO_APTX_SWB_SETTINGS_Q3: + retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK; + break; + default: + LOG_VERBOSE("Unknown Codec UUID(%d) received\n", codec_mode); + break; + } + } + return (retval); +} diff --git a/system/bta/ar/bta_ar.cc b/system/bta/ar/bta_ar.cc index ea6108f9671c28cbecb285595398ea6bbffb1d56..028fc8e62d113a17facbb5c67b9ab19a106bfc01 100644 --- a/system/bta/ar/bta_ar.cc +++ b/system/bta/ar/bta_ar.cc @@ -28,11 +28,46 @@ #include "bta/sys/bta_sys.h" #include "stack/include/avct_api.h" #include "stack/include/avrc_api.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/sdp_api.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + /* AV control block */ tBTA_AR_CB bta_ar_cb; +/******************************************************************************* + * + * Function bta_ar_id + * + * Description This function maps sys_id to ar id mask. + * + * Returns void + * + ******************************************************************************/ +static uint8_t bta_ar_id(tBTA_SYS_ID sys_id) { + uint8_t mask = 0; + if (sys_id == BTA_ID_AV) { + mask = BTA_AR_AV_MASK; + } else if (sys_id == BTA_ID_AVK) { + mask = BTA_AR_AVK_MASK; + } + return mask; +} +static void bta_ar_avrc_add_cat(uint16_t categories) { + uint8_t temp[sizeof(uint16_t)], *p; + /* Change supported categories on the second one */ + if (bta_ar_cb.sdp_tg_handle != 0) { + p = temp; + UINT16_TO_BE_STREAM(p, categories); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + bta_ar_cb.sdp_tg_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + sizeof(temp), (uint8_t*)temp); + } +} + /******************************************************************************* * * Function bta_ar_init @@ -78,8 +113,8 @@ void bta_ar_reg_avdt(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback) { if (bta_ar_cb.avdt_registered == 0) { AVDT_Register(p_reg, bta_ar_avdt_cback); } else { - APPL_TRACE_WARNING("%s: doesn't register again (registered:%d)", __func__, - bta_ar_cb.avdt_registered); + LOG_WARN("%s: doesn't register again (registered:%d)", __func__, + bta_ar_cb.avdt_registered); } bta_ar_cb.avdt_registered |= BTA_AR_AV_MASK; } @@ -167,7 +202,8 @@ void bta_ar_reg_avrc(uint16_t service_uuid, const char* service_name, if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) { if (bta_ar_cb.sdp_tg_handle == 0) { bta_ar_cb.tg_registered = mask; - bta_ar_cb.sdp_tg_handle = SDP_CreateRecord(); + bta_ar_cb.sdp_tg_handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_tg_handle, browse_supported, profile_version, 0); @@ -180,7 +216,8 @@ void bta_ar_reg_avrc(uint16_t service_uuid, const char* service_name, bta_ar_cb.ct_categories[mask - 1] = categories; categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1]; if (bta_ar_cb.sdp_ct_handle == 0) { - bta_ar_cb.sdp_ct_handle = SDP_CreateRecord(); + bta_ar_cb.sdp_ct_handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_ct_handle, browse_supported, profile_version, 0); @@ -190,8 +227,9 @@ void bta_ar_reg_avrc(uint16_t service_uuid, const char* service_name, * Change supported categories on the second one */ p = temp; UINT16_TO_BE_STREAM(p, categories); - SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, - UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (uint32_t)2, (uint8_t*)temp); } } } @@ -214,7 +252,8 @@ void bta_ar_dereg_avrc(uint16_t service_uuid) { if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) { if (bta_ar_cb.sdp_tg_handle && mask == bta_ar_cb.tg_registered) { bta_ar_cb.tg_registered = 0; - SDP_DeleteRecord(bta_ar_cb.sdp_tg_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + bta_ar_cb.sdp_tg_handle); bta_ar_cb.sdp_tg_handle = 0; bta_sys_remove_uuid(service_uuid); } @@ -224,16 +263,98 @@ void bta_ar_dereg_avrc(uint16_t service_uuid) { categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1]; if (!categories) { /* no CT is still registered - cleaup */ - SDP_DeleteRecord(bta_ar_cb.sdp_ct_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + bta_ar_cb.sdp_ct_handle); bta_ar_cb.sdp_ct_handle = 0; bta_sys_remove_uuid(service_uuid); } else { /* change supported categories to the remaning one */ p = temp; UINT16_TO_BE_STREAM(p, categories); - SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, - UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (uint32_t)2, (uint8_t*)temp); + } + } + } +} + +/****************************************************************************** + * + * Function bta_ar_reg_avrc_for_src_sink_coexist + * + * Description This function is called to register an SDP record for AVRCP. + * Add sys_id to distinguish src or sink role and add also save + *tg_categories + * + * Returns void + * + *****************************************************************************/ +void bta_ar_reg_avrc_for_src_sink_coexist( + uint16_t service_uuid, const char* service_name, const char* provider_name, + uint16_t categories, tBTA_SYS_ID sys_id, bool browse_supported, + uint16_t profile_version) { + uint8_t mask = bta_ar_id(sys_id); + uint8_t temp[8], *p; + uint16_t class_list[2]; + uint16_t count = 1; + if (!mask || !categories) return; + if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) { + bta_ar_cb.tg_categories[mask - 1] = categories; + categories = bta_ar_cb.tg_categories[0] | bta_ar_cb.tg_categories[1]; + if (bta_ar_cb.sdp_tg_handle == 0) { + bta_ar_cb.tg_registered = mask; + bta_ar_cb.sdp_tg_handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); + AVRC_AddRecord(service_uuid, service_name, provider_name, categories, + bta_ar_cb.sdp_tg_handle, browse_supported, profile_version, + 0); + bta_sys_add_uuid(service_uuid); + } + /* Change supported categories on the second one */ + bta_ar_avrc_add_cat(categories); + /* only one TG is allowed (first-come, first-served). + * If sdp_tg_handle is non-0, ignore this request */ + } else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) || + (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL)) { + bta_ar_cb.ct_categories[mask - 1] = categories; + categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1]; + if (bta_ar_cb.sdp_ct_handle == 0) { + bta_ar_cb.sdp_ct_handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); + AVRC_AddRecord(service_uuid, service_name, provider_name, categories, + bta_ar_cb.sdp_ct_handle, browse_supported, profile_version, + 0); + bta_sys_add_uuid(service_uuid); + bta_ar_cb.ct_ver = categories; + } else { + /* If first reg 1,3 version, reg 1.6 must update class id */ + if (bta_ar_cb.ct_ver < profile_version) { + LOG_VERBOSE("%s ver=0x%x", __FUNCTION__, profile_version); + if (bta_ar_cb.ct_ver <= AVRC_REV_1_3 && + profile_version > AVRC_REV_1_3) { + bta_ar_cb.ct_ver = profile_version; + /* add service class id list */ + class_list[0] = service_uuid; + if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) { + class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL; + count = 2; + } + get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList( + bta_ar_cb.sdp_ct_handle, count, class_list); + } else { + bta_ar_cb.ct_ver = profile_version; + } + get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList( + bta_ar_cb.sdp_ct_handle, service_uuid, profile_version); } + /* multiple CT are allowed. + * Change supported categories on the second one */ + p = temp; + UINT16_TO_BE_STREAM(p, categories); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (uint32_t)2, (uint8_t*)temp); } } } diff --git a/system/bta/ar/bta_ar_int.h b/system/bta/ar/bta_ar_int.h index c2676a7d617dafeaa9e4d62236094b4e721c584a..596495da56ba47626f6594eb94a3bcbe39200333 100644 --- a/system/bta/ar/bta_ar_int.h +++ b/system/bta/ar/bta_ar_int.h @@ -44,6 +44,8 @@ typedef struct { uint8_t tg_registered; tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the connection. */ + uint16_t ct_ver; + uint16_t tg_categories[2]; } tBTA_AR_CB; /***************************************************************************** diff --git a/system/bta/av/bta_av_aact.cc b/system/bta/av/bta_av_aact.cc index fc5e55bb6f7188c2ba075ef90e12f4bbfcf6b3ec..46912d0bd03585356ff3a21ded197a79d85238ea 100644 --- a/system/bta/av/bta_av_aact.cc +++ b/system/bta/av/bta_av_aact.cc @@ -32,26 +32,28 @@ #include #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/av/bta_av_int.h" #include "bta/include/bta_ar_api.h" #include "bta/include/bta_av_co.h" #include "btif/avrcp/avrcp_service.h" +#include "btif/include/btif_av.h" #include "btif/include/btif_av_co.h" #include "btif/include/btif_config.h" #include "btif/include/btif_storage.h" #include "device/include/device_iot_config.h" #include "device/include/interop.h" -#include "main/shim/dumpsys.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "osi/include/properties.h" #include "stack/include/a2dp_sbc.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_api.h" #include "stack/include/btm_client_interface.h" +#include "stack/include/btm_log_history.h" #include "stack/include/l2c_api.h" #include "types/hci_role.h" #include "types/raw_address.h" @@ -181,7 +183,7 @@ static uint8_t bta_av_get_scb_handle(tBTA_AV_SCB* p_scb, uint8_t local_sep) { return (p_scb->seps[i].av_handle); } } - APPL_TRACE_DEBUG("%s: local sep_type %d not found", __func__, local_sep) + LOG_VERBOSE("%s: local sep_type %d not found", __func__, local_sep); return 0; /* return invalid handle */ } @@ -199,7 +201,7 @@ static uint8_t bta_av_get_scb_sep_type(tBTA_AV_SCB* p_scb, for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) { if (p_scb->seps[i].av_handle == tavdt_handle) return (p_scb->seps[i].tsep); } - APPL_TRACE_DEBUG("%s: avdt_handle %d not found", __func__, tavdt_handle) + LOG_VERBOSE("%s: avdt_handle %d not found", __func__, tavdt_handle); return AVDT_TSEP_INVALID; } @@ -214,9 +216,9 @@ static uint8_t bta_av_get_scb_sep_type(tBTA_AV_SCB* p_scb, * ******************************************************************************/ static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const RawAddress& bd_addr) { - APPL_TRACE_DEBUG("%s: peer=%s recfg_sup:%d, suspend_sup:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), p_scb->recfg_sup, - p_scb->suspend_sup); + LOG_VERBOSE("%s: peer=%s recfg_sup:%d, suspend_sup:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), p_scb->recfg_sup, + p_scb->suspend_sup); if (p_scb->PeerAddress() != bd_addr) { LOG_INFO("%s: reset flags old_addr=%s new_addr=%s", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), @@ -274,8 +276,8 @@ static void notify_start_failed(tBTA_AV_SCB* p_scb) { * ******************************************************************************/ void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s: rc_handle:%d, use_rc: %d", __func__, p_scb->rc_handle, - p_scb->use_rc); + LOG_VERBOSE("%s: rc_handle:%d, use_rc: %d", __func__, p_scb->rc_handle, + p_scb->use_rc); /* for outgoing RC connection as INT/CT */ if ((p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) && /* (bta_av_cb.features & BTA_AV_FEAT_RCCT) && */ @@ -329,8 +331,8 @@ static bool bta_av_next_getcap(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { /* if no streams available then stream open fails */ if (!sent_cmd) { - APPL_TRACE_ERROR("%s: BTA_AV_STR_GETCAP_FAIL_EVT: peer_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: BTA_AV_STR_GETCAP_FAIL_EVT: peer_addr=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data); } @@ -353,7 +355,7 @@ void bta_av_proc_stream_evt(uint8_t handle, const RawAddress& bd_addr, tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[scb_index]; uint16_t sec_len = 0; - APPL_TRACE_EVENT( + LOG_VERBOSE( "%s: peer_address: %s avdt_handle: %d event=0x%x scb_index=%d p_scb=%p", __func__, ADDRESS_TO_LOGGABLE_CSTR(bd_addr), handle, event, scb_index, p_scb); @@ -379,8 +381,8 @@ void bta_av_proc_stream_evt(uint8_t handle, const RawAddress& bd_addr, p_msg->bd_addr = bd_addr; p_msg->scb_index = scb_index; - APPL_TRACE_EVENT("%s: stream event bd_addr: %s scb_index: %u", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_msg->bd_addr), scb_index); + LOG_VERBOSE("%s: stream event bd_addr: %s scb_index: %u", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_msg->bd_addr), scb_index); if (p_data != NULL) { memcpy(&p_msg->msg, p_data, sizeof(tAVDT_CTRL)); @@ -430,8 +432,8 @@ void bta_av_proc_stream_evt(uint8_t handle, const RawAddress& bd_addr, p_msg->initiator = false; if (event == AVDT_SUSPEND_CFM_EVT) p_msg->initiator = true; - APPL_TRACE_VERBOSE("%s: bta_handle:0x%x avdt_handle:%d", __func__, - p_scb->hndl, handle); + LOG_VERBOSE("%s: bta_handle:0x%x avdt_handle:%d", __func__, p_scb->hndl, + handle); p_msg->hdr.layer_specific = p_scb->hndl; p_msg->handle = handle; p_msg->avdt_event = event; @@ -441,7 +443,7 @@ void bta_av_proc_stream_evt(uint8_t handle, const RawAddress& bd_addr, if (p_data) { bta_av_conn_cback(handle, bd_addr, event, p_data, scb_index); } else { - APPL_TRACE_ERROR("%s: p_data is null", __func__); + LOG_ERROR("%s: p_data is null", __func__); } } @@ -458,7 +460,7 @@ void bta_av_sink_data_cback(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp, uint8_t m_pt) { int index = 0; tBTA_AV_SCB* p_scb; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: avdt_handle: %d pkt_len=0x%x offset = 0x%x " "number of frames 0x%x sequence number 0x%x", __func__, handle, p_pkt->len, p_pkt->offset, @@ -494,9 +496,9 @@ void bta_av_sink_data_cback(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp, ******************************************************************************/ static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service, const RawAddress& peer_address) { - APPL_TRACE_DEBUG("%s: peer %s : found=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), - (found) ? "true" : "false"); + LOG_VERBOSE("%s: peer %s : found=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), + (found) ? "true" : "false"); tBTA_AV_SCB* p_scb = NULL; if (peer_address != RawAddress::kEmpty) { @@ -506,22 +508,22 @@ static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service, p_scb = bta_av_hndl_to_scb(bta_av_cb.handle); } if (p_scb == NULL) { - APPL_TRACE_ERROR("%s: no scb found for SDP handle(0x%x)", __func__, - bta_av_cb.handle); + LOG_ERROR("%s: no scb found for SDP handle(0x%x)", __func__, + bta_av_cb.handle); return; } if (bta_av_cb.handle != p_scb->hndl) { - APPL_TRACE_WARNING("%s: SDP bta_handle expected=0x%x processing=0x%x", - __func__, bta_av_cb.handle, p_scb->hndl); + LOG_WARN("%s: SDP bta_handle expected=0x%x processing=0x%x", __func__, + bta_av_cb.handle, p_scb->hndl); } if (!found) { - APPL_TRACE_ERROR("%s: peer %s A2DP service discovery failed", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: peer %s A2DP service discovery failed", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); } - APPL_TRACE_DEBUG("%s: peer %s found=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - (found) ? "true" : "false"); + LOG_VERBOSE("%s: peer %s found=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), + (found) ? "true" : "false"); tBTA_AV_SDP_RES* p_msg = (tBTA_AV_SDP_RES*)osi_malloc(sizeof(tBTA_AV_SDP_RES)); @@ -529,8 +531,8 @@ static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service, p_msg->hdr.event = BTA_AV_SDP_DISC_OK_EVT; } else { p_msg->hdr.event = BTA_AV_SDP_DISC_FAIL_EVT; - APPL_TRACE_ERROR("%s: BTA_AV_SDP_DISC_FAIL_EVT: peer_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: BTA_AV_SDP_DISC_FAIL_EVT: peer_addr=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); } if (found && (p_service != NULL)) { p_scb->SetAvdtpVersion(p_service->avdt_version); @@ -544,9 +546,8 @@ static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service, (const uint8_t*)&p_service->avdt_version, sizeof(p_service->avdt_version))) { } else { - APPL_TRACE_WARNING("%s: Failed to store peer AVDTP version for %s", - __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_WARN("%s: Failed to store peer AVDTP version for %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); } } } else { @@ -567,12 +568,11 @@ static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service, * ******************************************************************************/ static void bta_av_adjust_seps_idx(tBTA_AV_SCB* p_scb, uint8_t avdt_handle) { - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecName(p_scb->cfg.codec_info)); + LOG_VERBOSE("%s: codec: %s", __func__, A2DP_CodecName(p_scb->cfg.codec_info)); for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) { - APPL_TRACE_DEBUG("%s: avdt_handle: %d codec: %s", __func__, - p_scb->seps[i].av_handle, - A2DP_CodecName(p_scb->seps[i].codec_info)); + LOG_VERBOSE("%s: avdt_handle: %d codec: %s", __func__, + p_scb->seps[i].av_handle, + A2DP_CodecName(p_scb->seps[i].codec_info)); if (p_scb->seps[i].av_handle && (p_scb->seps[i].av_handle == avdt_handle) && A2DP_CodecTypeEquals(p_scb->seps[i].codec_info, p_scb->cfg.codec_info)) { @@ -597,8 +597,8 @@ void bta_av_switch_role(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { tBTA_AV_RS_RES switch_res = BTA_AV_RS_NONE; tBTA_AV_API_OPEN* p_buf = &p_scb->q_info.open; - APPL_TRACE_DEBUG("%s: peer %s wait:0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->wait); + LOG_VERBOSE("%s: peer %s wait:0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->wait); if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START) p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY; @@ -617,9 +617,8 @@ void bta_av_switch_role(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { } } else { /* report failure on OPEN */ - APPL_TRACE_ERROR("%s: peer %s role switch failed (wait=0x%x)", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->wait); + LOG_ERROR("%s: peer %s role switch failed (wait=0x%x)", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->wait); switch_res = BTA_AV_RS_FAIL; } @@ -647,9 +646,9 @@ void bta_av_switch_role(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { bool initiator = false; - APPL_TRACE_DEBUG("%s: peer %s q_tag:%d, wait:0x%x, role:0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->q_tag, - p_scb->wait, p_scb->role); + LOG_VERBOSE("%s: peer %s q_tag:%d, wait:0x%x, role:0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->q_tag, + p_scb->wait, p_scb->role); if (p_scb->role & BTA_AV_ROLE_START_INT) initiator = true; if (p_scb->q_tag == BTA_AV_Q_TAG_START) { @@ -706,16 +705,16 @@ void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { bta_av_do_disc_a2dp(p_scb, (tBTA_AV_DATA*)&(p_scb->q_info.open)); } } else { - APPL_TRACE_WARNING( + LOG_WARN( "%s: peer %s unexpected role switch event: q_tag = %d wait = 0x%x", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->q_tag, p_scb->wait); } } - APPL_TRACE_DEBUG("%s: peer %s wait:0x%x, role:0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->wait, - p_scb->role); + LOG_VERBOSE("%s: peer %s wait:0x%x, role:0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->wait, + p_scb->role); } /******************************************************************************* @@ -729,9 +728,9 @@ void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_delay_co(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s: peer %s bta_handle:0x%x delay:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, - p_data->str_msg.msg.delay_rpt_cmd.delay); + LOG_VERBOSE("%s: peer %s bta_handle:0x%x delay:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, + p_data->str_msg.msg.delay_rpt_cmd.delay); p_scb->p_cos->delay(p_scb->hndl, p_scb->PeerAddress(), p_data->str_msg.msg.delay_rpt_cmd.delay); } @@ -753,10 +752,10 @@ void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { ATTR_ID_BT_PROFILE_DESC_LIST}; uint16_t sdp_uuid = 0; /* UUID for which SDP has to be done */ - APPL_TRACE_DEBUG("%s: peer_addr: %s use_rc: %d switch_res:%d, oc:%d", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_data->api_open.bd_addr), - p_data->api_open.use_rc, p_data->api_open.switch_res, - bta_av_cb.audio_open_cnt); + LOG_VERBOSE("%s: peer_addr: %s use_rc: %d switch_res:%d, oc:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_data->api_open.bd_addr), + p_data->api_open.use_rc, p_data->api_open.switch_res, + bta_av_cb.audio_open_cnt); memcpy(&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN)); @@ -777,8 +776,8 @@ void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { case BTA_AV_RS_FAIL: /* report a new failure event */ p_scb->open_status = BTA_AV_FAIL_ROLE; - APPL_TRACE_ERROR("%s: BTA_AV_SDP_DISC_FAIL_EVT: peer_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: BTA_AV_SDP_DISC_FAIL_EVT: peer_addr=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL); break; @@ -797,8 +796,8 @@ void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { break; } - APPL_TRACE_DEBUG("%s: ok_continue: %d wait:0x%x, q_tag: %d", __func__, - ok_continue, p_scb->wait, p_scb->q_tag); + LOG_VERBOSE("%s: ok_continue: %d wait:0x%x, q_tag: %d", __func__, ok_continue, + p_scb->wait, p_scb->q_tag); if (!ok_continue) return; /* clear the role switch bits */ @@ -827,7 +826,7 @@ void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) sdp_uuid = UUID_SERVCLASS_AUDIO_SINK; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: Initiate SDP discovery for peer %s : uuid_int=0x%x " "sdp_uuid=0x%x", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->uuid_int, @@ -835,7 +834,7 @@ void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { tA2DP_STATUS find_service_status = A2DP_FindService( sdp_uuid, p_scb->PeerAddress(), &db_params, bta_av_a2dp_sdp_cback); if (find_service_status != A2DP_SUCCESS) { - APPL_TRACE_ERROR( + LOG_ERROR( "%s: A2DP_FindService() failed for peer %s uuid_int=0x%x " "sdp_uuid=0x%x : status=%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), @@ -880,6 +879,7 @@ void bta_av_cleanup(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { p_scb->wait = 0; p_scb->num_disc_snks = 0; p_scb->coll_mask = 0; + p_scb->uuid_int = 0; alarm_cancel(p_scb->avrc_ct_timer); alarm_cancel(p_scb->link_signalling_timer); alarm_cancel(p_scb->accept_signalling_timer); @@ -945,11 +945,11 @@ void bta_av_config_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { local_sep = bta_av_get_scb_sep_type(p_scb, p_msg->handle); p_scb->avdt_label = p_data->str_msg.msg.hdr.label; - APPL_TRACE_DEBUG("%s: peer %s bta_handle:0x%x local_sep:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, - local_sep); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_evt_cfg->codec_info).c_str()); + LOG_VERBOSE("%s: peer %s bta_handle:0x%x local_sep:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, + local_sep); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_evt_cfg->codec_info).c_str()); memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE); bta_av_save_addr(p_scb, p_data->str_msg.bd_addr); @@ -995,8 +995,8 @@ void bta_av_config_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { p_scb->num_seps = 1; p_scb->sep_info_idx = 0; - APPL_TRACE_DEBUG("%s: SEID: %d use_rc: %d cur_psc_mask:0x%x", __func__, - p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask); + LOG_VERBOSE("%s: SEID: %d use_rc: %d cur_psc_mask:0x%x", __func__, + p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask); /* in case of A2DP SINK this is the first time peer data is being sent to * co functions */ if (local_sep == AVDT_TSEP_SNK) { @@ -1026,9 +1026,8 @@ void bta_av_disconnect_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { tBTA_AV_RCB* p_rcb; - APPL_TRACE_API("%s: conn_lcb: 0x%x peer_addr: %s", __func__, - bta_av_cb.conn_lcb, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_VERBOSE("%s: conn_lcb: 0x%x peer_addr: %s", __func__, bta_av_cb.conn_lcb, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); alarm_cancel(p_scb->link_signalling_timer); alarm_cancel(p_scb->accept_signalling_timer); @@ -1038,11 +1037,13 @@ void bta_av_disconnect_req(tBTA_AV_SCB* p_scb, // the same index, it should be safe to use SCB index here. if ((bta_av_cb.conn_lcb & (1 << p_scb->hdi)) != 0) { p_rcb = bta_av_get_rcb_by_shdl((uint8_t)(p_scb->hdi + 1)); - if (p_rcb) bta_av_del_rc(p_rcb); + if (p_rcb && p_scb->rc_handle != BTA_AV_RC_HANDLE_NONE) { + bta_av_del_rc(p_rcb); + } AVDT_DisconnectReq(p_scb->PeerAddress(), &bta_av_proc_stream_evt); } else { - APPL_TRACE_WARNING("%s: conn_lcb=0x%x bta_handle=0x%x (hdi=%u) no link", - __func__, bta_av_cb.conn_lcb, p_scb->hndl, p_scb->hdi); + LOG_WARN("%s: conn_lcb=0x%x bta_handle=0x%x (hdi=%u) no link", __func__, + bta_av_cb.conn_lcb, p_scb->hndl, p_scb->hdi); bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL); } } @@ -1127,8 +1128,8 @@ void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON; if (p_data->ci_setconfig.recfg_needed) p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT; - APPL_TRACE_DEBUG("%s: recfg_needed:%d role:0x%x num:%d", __func__, - p_data->ci_setconfig.recfg_needed, p_scb->role, num); + LOG_VERBOSE("%s: recfg_needed:%d role:0x%x num:%d", __func__, + p_data->ci_setconfig.recfg_needed, p_scb->role, num); /* callout module tells BTA the number of "good" SEPs and their SEIDs. * getcap on these SEID */ p_scb->num_seps = num; @@ -1155,7 +1156,7 @@ void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { } for (i = 1; i < num; i++) { - APPL_TRACE_DEBUG("%s: sep_info[%d] SEID: %d", __func__, i, p_seid[i - 1]); + LOG_VERBOSE("%s: sep_info[%d] SEID: %d", __func__, i, p_seid[i - 1]); /* initialize the sep_info[] to get capabilities */ p_scb->sep_info[i].in_use = false; p_scb->sep_info[i].tsep = AVDT_TSEP_SNK; @@ -1165,10 +1166,23 @@ void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { /* only in case of local sep as SRC we need to look for other SEPs, In case * of SINK we don't */ - if (local_sep == AVDT_TSEP_SRC) { - /* Make sure UUID has been initialized... */ - if (p_scb->uuid_int == 0) p_scb->uuid_int = p_scb->open_api.uuid; - bta_av_next_getcap(p_scb, p_data); + if (btif_av_src_sink_coexist_enabled()) { + if (local_sep == AVDT_TSEP_SRC) { + /* Make sure UUID has been initialized... */ + /* if local sep is source, uuid_int should be source */ + p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SOURCE; + bta_av_next_getcap(p_scb, p_data); + } else { + p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SINK; + } + } else { + if (local_sep == AVDT_TSEP_SRC) { + /* Make sure UUID has been initialized... */ + if (p_scb->uuid_int == 0) { + p_scb->uuid_int = p_scb->open_api.uuid; + } + bta_av_next_getcap(p_scb, p_data); + } } } } @@ -1187,8 +1201,8 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { char remote_name[BTM_MAX_REM_BD_NAME_LEN] = ""; uint8_t* p; - APPL_TRACE_DEBUG("%s: peer %s bta_handle: 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl); + LOG_VERBOSE("%s: peer %s bta_handle: 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl); msg.hdr.layer_specific = p_scb->hndl; msg.is_up = true; @@ -1210,8 +1224,8 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { p_scb->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE; - APPL_TRACE_DEBUG("%s: l2c_cid: 0x%x stream_mtu: %d", __func__, p_scb->l2c_cid, - p_scb->stream_mtu); + LOG_VERBOSE("%s: l2c_cid: 0x%x stream_mtu: %d", __func__, p_scb->l2c_cid, + p_scb->stream_mtu); /* Set the media channel as high priority */ L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_HIGH); @@ -1277,7 +1291,7 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { char value[PROPERTY_VALUE_MAX] = {0}; if ((osi_property_get("bluetooth.pts.force_a2dp_abort", value, "false")) && (!strcmp(value, "true"))) { - APPL_TRACE_ERROR("%s: Calling AVDT_AbortReq", __func__); + LOG_ERROR("%s: Calling AVDT_AbortReq", __func__); AVDT_AbortReq(p_scb->avdt_handle); } } @@ -1348,7 +1362,7 @@ void bta_av_security_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_do_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s: p_scb->co_started=%d", __func__, p_scb->co_started); + LOG_VERBOSE("%s: p_scb->co_started=%d", __func__, p_scb->co_started); /* stop stream if started */ if (p_scb->co_started) { @@ -1383,18 +1397,16 @@ void bta_av_do_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_connect_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s: peer %s coll_mask=0x%02x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->coll_mask); + LOG_VERBOSE("%s: peer %s coll_mask=0x%02x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->coll_mask); p_scb->sdp_discovery_started = false; if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) { /* SNK initiated L2C connection while SRC was doing SDP. */ /* Wait until timeout to check if SNK starts signalling. */ - APPL_TRACE_WARNING("%s: coll_mask=0x%02x incoming timer is up", __func__, - p_scb->coll_mask); + LOG_WARN("%s: coll_mask=0x%02x incoming timer is up", __func__, + p_scb->coll_mask); p_scb->coll_mask |= BTA_AV_COLL_API_CALLED; - APPL_TRACE_EVENT("%s: updated coll_mask=0x%02x", __func__, - p_scb->coll_mask); + LOG_VERBOSE("%s: updated coll_mask=0x%02x", __func__, p_scb->coll_mask); return; } @@ -1411,9 +1423,8 @@ void bta_av_connect_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_sdp_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { - APPL_TRACE_ERROR("%s: peer_addr=%s open_status=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->open_status); + LOG_ERROR("%s: peer_addr=%s open_status=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->open_status); if (p_scb->open_status == BTA_AV_SUCCESS) { p_scb->open_status = BTA_AV_FAIL_SDP; @@ -1439,24 +1450,52 @@ void bta_av_disc_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { /* our uuid in case we initiate connection */ uint16_t uuid_int = p_scb->uuid_int; - APPL_TRACE_DEBUG("%s: peer %s bta_handle: 0x%x initiator UUID 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, - uuid_int); + LOG_VERBOSE("%s: peer %s bta_handle: 0x%x initiator UUID 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, + uuid_int); /* store number of stream endpoints returned */ p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps; - for (i = 0; i < p_scb->num_seps; i++) { - /* steam not in use, is a sink, and is audio */ - if ((!p_scb->sep_info[i].in_use) && - (p_scb->sep_info[i].media_type == p_scb->media_type)) { - if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && - (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)) - num_snks++; + if (btif_av_src_sink_coexist_enabled()) { + for (i = 0; i < p_scb->num_seps; i++) { + /* steam not in use, is a sink, and is audio */ + if ((!p_scb->sep_info[i].in_use) && + (p_scb->sep_info[i].media_type == p_scb->media_type)) { + if (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) num_snks++; - if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SRC) && - (uuid_int == UUID_SERVCLASS_AUDIO_SINK)) - num_srcs++; + if (p_scb->sep_info[i].tsep == AVDT_TSEP_SRC) num_srcs++; + } + } + LOG_VERBOSE("both_enable=%d, uuid_int=0x%x, incoming=%d", + btif_av_both_enable(), uuid_int, p_scb->open_api.incoming); + if (btif_av_both_enable() && p_scb->open_api.incoming) { + if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE && num_snks == 0 && + num_srcs > 0) { + p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SINK; + LOG_VERBOSE(" change UUID to 0x%x, num_snks=%u, num_srcs=%u", + p_scb->uuid_int, num_snks, num_srcs); + } else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK && num_srcs == 0 && + num_snks > 0) { + p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SOURCE; + LOG_VERBOSE(" change UUID to 0x%x, num_snks=%u, num_srcs=%u", + p_scb->uuid_int, num_snks, num_srcs); + } + uuid_int = p_scb->uuid_int; + } + } else { + for (i = 0; i < p_scb->num_seps; i++) { + /* steam not in use, is a sink, and is audio */ + if ((!p_scb->sep_info[i].in_use) && + (p_scb->sep_info[i].media_type == p_scb->media_type)) { + if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && + (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)) + num_snks++; + + if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SRC) && + (uuid_int == UUID_SERVCLASS_AUDIO_SINK)) + num_srcs++; + } } } @@ -1475,8 +1514,8 @@ void bta_av_disc_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { } /* else we got discover response but with no streams; we're done */ else { - APPL_TRACE_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data); } } @@ -1495,8 +1534,8 @@ void bta_av_disc_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { void bta_av_disc_res_as_acp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { uint8_t num_snks = 0, i; - APPL_TRACE_DEBUG("%s: peer %s bta_handle: 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl); + LOG_VERBOSE("%s: peer %s bta_handle: 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl); /* store number of stream endpoints returned */ p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps; @@ -1524,8 +1563,8 @@ void bta_av_disc_res_as_acp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { } /* else we got discover response but with no streams; we're done */ else { - APPL_TRACE_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data); } } @@ -1545,12 +1584,12 @@ void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { uint8_t old_wait = p_scb->wait; bool getcap_done = false; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer %s bta_handle:0x%x num_seps:%d sep_info_idx:%d wait:0x%x", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_scb->peer_cap.codec_info).c_str()); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_scb->peer_cap.codec_info).c_str()); cfg = p_scb->peer_cap; /* let application know the capability of the SNK */ @@ -1558,16 +1597,16 @@ void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { &p_scb->sep_info_idx, p_info->seid, &cfg.num_protect, cfg.protect_info) != A2DP_SUCCESS) { p_scb->sep_info_idx++; - APPL_TRACE_DEBUG("%s: result: next sep_info_idx:%d", __func__, - p_scb->sep_info_idx); + LOG_VERBOSE("%s: result: next sep_info_idx:%d", __func__, + p_scb->sep_info_idx); } else { // All capabilities found getcap_done = true; - APPL_TRACE_DEBUG("%s: result: done sep_info_idx:%d", __func__, - p_scb->sep_info_idx); + LOG_VERBOSE("%s: result: done sep_info_idx:%d", __func__, + p_scb->sep_info_idx); } - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(cfg.codec_info).c_str()); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(cfg.codec_info).c_str()); if (p_scb->num_seps > p_scb->sep_info_idx && !getcap_done) { /* Some devices have seps at the end of the discover list, which is not */ @@ -1580,9 +1619,8 @@ void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { } if (getcap_done) { - APPL_TRACE_DEBUG("%s: getcap_done: num_seps:%d sep_info_idx:%d wait:0x%x", - __func__, p_scb->num_seps, p_scb->sep_info_idx, - p_scb->wait); + LOG_VERBOSE("%s: getcap_done: num_seps:%d sep_info_idx:%d wait:0x%x", + __func__, p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait); p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON | BTA_AV_WAIT_ACP_CAPS_STARTED); if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED) { bta_av_start_ok(p_scb, NULL); @@ -1613,8 +1651,8 @@ void bta_av_set_use_rc(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_cco_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s: peer %s bta_handle:0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl); + LOG_VERBOSE("%s: peer %s bta_handle:0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl); p_scb->p_cos->close(p_scb->hndl, p_scb->PeerAddress()); } @@ -1632,8 +1670,8 @@ void bta_av_open_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { tBTA_AV_SCB* p_opened_scb = NULL; uint8_t idx; - APPL_TRACE_ERROR("%s: peer_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: peer_addr=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); p_scb->open_status = BTA_AV_FAIL_STREAM; bta_av_cco_close(p_scb, p_data); @@ -1668,7 +1706,7 @@ void bta_av_open_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { bta_av_data.open.sep = AVDT_TSEP_SRC; } - APPL_TRACE_ERROR( + LOG_ERROR( "%s: there is already an active connection: peer_addr=%s chnl=%d " "hndl=0x%x status=%d starting=%d edr=%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(bta_av_data.open.bd_addr), @@ -1702,13 +1740,13 @@ void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { memcpy(cfg.codec_info, p_scb->peer_cap.codec_info, AVDT_CODEC_SIZE); memcpy(cfg.protect_info, p_scb->peer_cap.protect_info, AVDT_PROTECT_SIZE); - APPL_TRACE_DEBUG("%s: peer %s bta_handle:0x%x num_codec:%d psc_mask=0x%x", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->hndl, p_scb->peer_cap.num_codec, p_scb->cfg.psc_mask); - APPL_TRACE_DEBUG("%s: media type 0x%x, 0x%x", __func__, media_type, - p_scb->media_type); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); + LOG_VERBOSE("%s: peer %s bta_handle:0x%x num_codec:%d psc_mask=0x%x", + __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), + p_scb->hndl, p_scb->peer_cap.num_codec, p_scb->cfg.psc_mask); + LOG_VERBOSE("%s: media type 0x%x, 0x%x", __func__, media_type, + p_scb->media_type); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); /* if codec present and we get a codec configuration */ if ((p_scb->peer_cap.num_codec != 0) && (media_type == p_scb->media_type) && @@ -1722,12 +1760,11 @@ void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { /* save copy of codec configuration */ p_scb->cfg = cfg; - APPL_TRACE_DEBUG("%s: result: sep_info_idx=%d", __func__, - p_scb->sep_info_idx); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); + LOG_VERBOSE("%s: result: sep_info_idx=%d", __func__, p_scb->sep_info_idx); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); - APPL_TRACE_DEBUG("%s: initiator UUID = 0x%x", __func__, uuid_int); + LOG_VERBOSE("%s: initiator UUID = 0x%x", __func__, uuid_int); if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC)); @@ -1740,7 +1777,7 @@ void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { /* use only the services peer supports */ cfg.psc_mask &= p_scb->peer_cap.psc_mask; p_scb->cur_psc_mask = cfg.psc_mask; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer %s bta_handle:0x%x sep_idx:%d sep_info_idx:%d " "cur_psc_mask:0x%x", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, @@ -1748,7 +1785,7 @@ void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) && (p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback != NULL)) { - APPL_TRACE_DEBUG("%s: configure decoder for Sink connection", __func__); + LOG_VERBOSE("%s: configure decoder for Sink connection", __func__); tBTA_AV_MEDIA av_sink_codec_info = { .avk_config = { @@ -1828,9 +1865,8 @@ void bta_av_discover_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_conn_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { - APPL_TRACE_ERROR("%s: peer_addr=%s open_status=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->open_status); + LOG_ERROR("%s: peer_addr=%s open_status=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->open_status); p_scb->open_status = BTA_AV_FAIL_STREAM; bta_av_str_closed(p_scb, p_data); @@ -1934,10 +1970,9 @@ void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { bool sus_evt = true; BT_HDR* p_buf; - APPL_TRACE_ERROR( - "%s: peer %s bta_handle:0x%x audio_open_cnt:%d, p_data %p start:%d", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, - bta_av_cb.audio_open_cnt, p_data, start); + LOG_INFO("peer %s bta_handle:0x%x audio_open_cnt:%d, p_data %p start:%d", + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, + bta_av_cb.audio_open_cnt, p_data, start); bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress()); BTM_unblock_role_switch_and_sniff_mode_for(p_scb->PeerAddress()); @@ -1947,7 +1982,7 @@ void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { bta_av_vendor_offload_stop(); bta_av_cb.offload_started_hndl = BTA_AV_INVALID_HANDLE; } else if (bta_av_cb.offload_start_pending_hndl == p_scb->hndl) { - APPL_TRACE_WARNING("%s: Stop pending offload start command", __func__); + LOG_WARN("%s: Stop pending offload start command", __func__); bta_av_vendor_offload_stop(); bta_av_cb.offload_start_pending_hndl = BTA_AV_INVALID_HANDLE; } @@ -1976,9 +2011,9 @@ void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { suspend_rsp.hndl = p_scb->hndl; if (p_data && p_data->api_stop.suspend) { - APPL_TRACE_DEBUG("%s: peer %s suspending: %d, sup:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), start, - p_scb->suspend_sup); + LOG_VERBOSE("%s: peer %s suspending: %d, sup:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), start, + p_scb->suspend_sup); if ((start) && (p_scb->suspend_sup)) { sus_evt = false; p_scb->l2c_bufs = 0; @@ -1997,7 +2032,7 @@ void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { } else { suspend_rsp.status = BTA_AV_SUCCESS; suspend_rsp.initiator = true; - APPL_TRACE_EVENT("%s: status %d", __func__, suspend_rsp.status); + LOG_VERBOSE("%s: status %d", __func__, suspend_rsp.status); // Send STOP_EVT event only if not in reconfiguring state. // However, we should send STOP_EVT if we are reconfiguring when taking @@ -2027,8 +2062,8 @@ void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { tBTA_AV_API_STOP stop = {}; tBTA_AV_API_RCFG* p_rcfg = &p_data->api_reconfig; - APPL_TRACE_DEBUG("%s: r:%d, s:%d idx: %d (o:%d)", __func__, p_scb->recfg_sup, - p_scb->suspend_sup, p_scb->rcfg_idx, p_scb->sep_info_idx); + LOG_VERBOSE("%s: r:%d, s:%d idx: %d (o:%d)", __func__, p_scb->recfg_sup, + p_scb->suspend_sup, p_scb->rcfg_idx, p_scb->sep_info_idx); p_scb->num_recfg = 0; /* store the new configuration in control block */ @@ -2070,17 +2105,16 @@ void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { bta_av_str_stopped(p_scb, (tBTA_AV_DATA*)&stop); } else { // Reconfigure - APPL_TRACE_DEBUG("%s: reconfig", __func__); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); + LOG_VERBOSE("%s: reconfig", __func__); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); AVDT_ReconfigReq(p_scb->avdt_handle, &p_scb->cfg); p_scb->cfg.psc_mask = p_scb->cur_psc_mask; } } else { // Close the stream first, and then Configure it - APPL_TRACE_DEBUG("%s: Close/Open started: %d state: %d num_protect: %d", - __func__, p_scb->started, p_scb->state, - p_cfg->num_protect); + LOG_VERBOSE("%s: Close/Open started: %d state: %d num_protect: %d", + __func__, p_scb->started, p_scb->state, p_cfg->num_protect); if (p_scb->started) { // Close->Configure->Open->Start if ((p_scb->rcfg_idx != p_scb->sep_info_idx) && p_scb->recfg_sup) { @@ -2271,12 +2305,12 @@ void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { if ((p_scb->avdt_handle == p_scb->seps[p_scb->sep_idx].av_handle) && (local_tsep == AVDT_TSEP_SNK)) { p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON); - APPL_TRACE_DEBUG("%s: local SEP type is SNK new wait is 0x%x", __func__, - p_scb->wait); + LOG_VERBOSE("%s: local SEP type is SNK new wait is 0x%x", __func__, + p_scb->wait); } if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED) { /* role switch has failed */ - APPL_TRACE_ERROR( + LOG_ERROR( "%s: peer %s role switch failed: bta_handle:0x%x wait:0x%x, role:0x%x", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, p_scb->wait, p_scb->role); @@ -2284,10 +2318,9 @@ void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { p_data = (tBTA_AV_DATA*)&hdr; hdr.offset = BTA_AV_RS_FAIL; } - APPL_TRACE_DEBUG("%s: peer %s wait:0x%x use_rtp_header_marker_bit:%s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->wait, - (p_scb->use_rtp_header_marker_bit) ? "true" : "false"); + LOG_VERBOSE("%s: peer %s wait:0x%x use_rtp_header_marker_bit:%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->wait, + (p_scb->use_rtp_header_marker_bit) ? "true" : "false"); if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE)) { p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; @@ -2327,9 +2360,9 @@ void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { } if (p_scb->wait) { - APPL_TRACE_ERROR("%s: peer %s wait:0x%x q_tag:%d not started", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->wait, p_scb->q_tag); + LOG_ERROR("%s: peer %s wait:0x%x q_tag:%d not started", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->wait, + p_scb->q_tag); /* Clear first bit of p_scb->wait and not to return from this point else * HAL layer gets blocked. And if there is delay in Get Capability response * as @@ -2373,7 +2406,7 @@ void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { { /* If sink starts stream, disable sniff mode here */ if (!initiator) { - /* If souce is the central role, disable role switch during streaming. + /* If source is the central role, disable role switch during streaming. * Otherwise allow role switch, if source is peripheral. * Because it would not hurt source, if the peer device wants source to be * central. @@ -2395,9 +2428,9 @@ void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { p_scb->cfg.codec_info, &p_scb->no_rtp_header); p_scb->co_started = true; - APPL_TRACE_DEBUG("%s: peer %s suspending: %d, role:0x%x, init %d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), suspend, - p_scb->role, initiator); + LOG_VERBOSE("%s: peer %s suspending: %d, role:0x%x, init %d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), suspend, + p_scb->role, initiator); tBTA_AV bta_av_data = { .start = @@ -2438,7 +2471,7 @@ void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_start_failed(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_ERROR( + LOG_ERROR( "%s: peer %s bta_handle:0x%x audio_open_cnt:%d started:%s co_started:%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, bta_av_cb.audio_open_cnt, logbool(p_scb->started).c_str(), @@ -2466,10 +2499,9 @@ void bta_av_str_closed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { tBTA_AV data = {}; tBTA_AV_EVT event = {}; - APPL_TRACE_WARNING( - "%s: peer %s bta_handle:0x%x open_status:%d chnl:%d co_started:%d", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, - p_scb->open_status, p_scb->chnl, p_scb->co_started); + LOG_WARN("%s: peer %s bta_handle:0x%x open_status:%d chnl:%d co_started:%d", + __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), + p_scb->hndl, p_scb->open_status, p_scb->chnl, p_scb->co_started); BTM_unblock_role_switch_and_sniff_mode_for(p_scb->PeerAddress()); if (bta_av_cb.audio_open_cnt <= 1) { @@ -2525,7 +2557,7 @@ void bta_av_str_closed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_clr_cong(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (p_scb->co_started) { p_scb->cong = false; } @@ -2544,17 +2576,16 @@ void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { tBTA_AV_SUSPEND suspend_rsp = {}; uint8_t err_code = p_data->str_msg.msg.hdr.err_code; - APPL_TRACE_DEBUG("%s: peer %s bta_handle:0x%x audio_open_cnt:%d err_code:%d", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->hndl, bta_av_cb.audio_open_cnt, err_code); + LOG_VERBOSE("%s: peer %s bta_handle:0x%x audio_open_cnt:%d err_code:%d", + __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), + p_scb->hndl, bta_av_cb.audio_open_cnt, err_code); if (!p_scb->started) { /* handle the condition where there is a collision of SUSPEND req from *either side ** Second SUSPEND req could be rejected. Do not treat this as a failure */ - APPL_TRACE_WARNING("%s: already suspended, ignore, err_code %d", __func__, - err_code); + LOG_WARN("%s: already suspended, ignore, err_code %d", __func__, err_code); return; } @@ -2562,7 +2593,7 @@ void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { if (err_code && (err_code != AVDT_ERR_BAD_STATE)) { suspend_rsp.status = BTA_AV_FAIL; - APPL_TRACE_ERROR("%s: suspend failed, closing connection", __func__); + LOG_ERROR("%s: suspend failed, closing connection", __func__); /* SUSPEND failed. Close connection. */ bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL); @@ -2585,7 +2616,7 @@ void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { bta_av_vendor_offload_stop(); bta_av_cb.offload_started_hndl = BTA_AV_INVALID_HANDLE; } else if (bta_av_cb.offload_start_pending_hndl == p_scb->hndl) { - APPL_TRACE_WARNING("%s: Stop pending offload start command", __func__); + LOG_WARN("%s: Stop pending offload start command", __func__); bta_av_vendor_offload_stop(); bta_av_cb.offload_start_pending_hndl = BTA_AV_INVALID_HANDLE; } @@ -2618,16 +2649,16 @@ void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { ******************************************************************************/ void bta_av_rcfg_str_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle); - APPL_TRACE_DEBUG("%s: peer %s bta_handle:0x%x l2c_cid:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, - p_scb->l2c_cid); + LOG_VERBOSE("%s: peer %s bta_handle:0x%x l2c_cid:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, + p_scb->l2c_cid); if (p_data != NULL) { // p_data could be NULL if the reconfig was triggered by the local device p_scb->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE; - APPL_TRACE_DEBUG("%s: l2c_cid: 0x%x stream_mtu: %d", __func__, - p_scb->l2c_cid, p_scb->stream_mtu); + LOG_VERBOSE("%s: l2c_cid: 0x%x stream_mtu: %d", __func__, p_scb->l2c_cid, + p_scb->stream_mtu); p_scb->p_cos->update_mtu(p_scb->hndl, p_scb->PeerAddress(), p_scb->stream_mtu); } @@ -2664,9 +2695,9 @@ void bta_av_rcfg_str_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_rcfg_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { - APPL_TRACE_ERROR("%s: num_recfg=%d conn_lcb=0x%x peer_addr=%s", __func__, - p_scb->num_recfg, bta_av_cb.conn_lcb, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: num_recfg=%d conn_lcb=0x%x peer_addr=%s", __func__, + p_scb->num_recfg, bta_av_cb.conn_lcb, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) { bta_av_cco_close(p_scb, p_data); @@ -2690,8 +2721,8 @@ void bta_av_rcfg_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { if ((bta_av_cb.conn_lcb & (1 << p_scb->hdi)) != 0) { AVDT_DisconnectReq(p_scb->PeerAddress(), &bta_av_proc_stream_evt); } else { - APPL_TRACE_WARNING("%s: conn_lcb=0x%x bta_handle=0x%x (hdi=%u) no link", - __func__, bta_av_cb.conn_lcb, p_scb->hndl, p_scb->hdi); + LOG_WARN("%s: conn_lcb=0x%x bta_handle=0x%x (hdi=%u) no link", __func__, + bta_av_cb.conn_lcb, p_scb->hndl, p_scb->hdi); bta_av_connect_req(p_scb, NULL); } } @@ -2707,11 +2738,11 @@ void bta_av_rcfg_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_rcfg_connect(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); p_scb->cong = false; p_scb->num_recfg++; - APPL_TRACE_DEBUG("%s: num_recfg: %d", __func__, p_scb->num_recfg); + LOG_VERBOSE("%s: num_recfg: %d", __func__, p_scb->num_recfg); if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) { /* let bta_av_rcfg_failed report fail */ bta_av_rcfg_failed(p_scb, NULL); @@ -2730,9 +2761,9 @@ void bta_av_rcfg_connect(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_rcfg_discntd(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_ERROR("%s: num_recfg=%d conn_lcb=0x%x peer_addr=%s", __func__, - p_scb->num_recfg, bta_av_cb.conn_lcb, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: num_recfg=%d conn_lcb=0x%x peer_addr=%s", __func__, + p_scb->num_recfg, bta_av_cb.conn_lcb, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); p_scb->num_recfg++; if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) { @@ -2766,7 +2797,7 @@ void bta_av_rcfg_discntd(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { uint8_t err_code = p_data->str_msg.msg.hdr.err_code; - APPL_TRACE_DEBUG("%s: err_code=%d", __func__, err_code); + LOG_VERBOSE("%s: err_code=%d", __func__, err_code); p_scb->started = false; p_scb->cong = false; @@ -2782,22 +2813,22 @@ void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { }, }; (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, &bta_av_data); - APPL_TRACE_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + LOG_ERROR("%s: BTA_AV_STR_DISC_FAIL_EVT: peer_addr=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL); } else { - APPL_TRACE_ERROR("%s: suspend rejected, try close", __func__); + LOG_ERROR("%s: suspend rejected, try close", __func__); /* drop the buffers queued in L2CAP */ L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); AVDT_CloseReq(p_scb->avdt_handle); } } else { - APPL_TRACE_DEBUG("%s: calling AVDT_ReconfigReq", __func__); + LOG_VERBOSE("%s: calling AVDT_ReconfigReq", __func__); /* reconfig the stream */ - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); AVDT_ReconfigReq(p_scb->avdt_handle, &p_scb->cfg); p_scb->cfg.psc_mask = p_scb->cur_psc_mask; } @@ -2816,7 +2847,7 @@ void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { void bta_av_rcfg_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { uint8_t err_code = p_data->str_msg.msg.hdr.err_code; - APPL_TRACE_DEBUG("%s: err_code = %d", __func__, err_code); + LOG_VERBOSE("%s: err_code = %d", __func__, err_code); // Disable AVDTP RECONFIGURE for rejectlisted devices bool disable_avdtp_reconfigure = false; @@ -2838,7 +2869,7 @@ void bta_av_rcfg_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { } if ((err_code != 0) || disable_avdtp_reconfigure) { - APPL_TRACE_ERROR("%s: reconfig rejected, try close", __func__); + LOG_ERROR("%s: reconfig rejected, try close", __func__); /* Disable reconfiguration feature only with explicit rejection(not with * timeout) */ if ((err_code != AVDT_ERR_TIMEOUT) || disable_avdtp_reconfigure) { @@ -2850,7 +2881,7 @@ void bta_av_rcfg_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { AVDT_CloseReq(p_scb->avdt_handle); } else { /* update the codec info after rcfg cfm */ - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: updating from codec %s to codec %s", __func__, A2DP_CodecName(p_scb->cfg.codec_info), A2DP_CodecName(p_data->str_msg.msg.reconfig_cfm.p_cfg->codec_info)); @@ -2872,9 +2903,9 @@ void bta_av_rcfg_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s: peer %s bta_handle:0x%x num_disc_snks:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, - p_scb->num_disc_snks); + LOG_VERBOSE("%s: peer %s bta_handle:0x%x num_disc_snks:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, + p_scb->num_disc_snks); if (p_scb->num_disc_snks == 0) { /* Need to update call-out module so that it will be ready for discover */ @@ -2884,9 +2915,9 @@ void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) { AVDT_DiscoverReq(p_scb->PeerAddress(), p_scb->hdi, p_scb->sep_info, BTA_AV_NUM_SEPS, &bta_av_proc_stream_evt); } else { - APPL_TRACE_DEBUG("%s: calling AVDT_OpenReq()", __func__); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); + LOG_VERBOSE("%s: calling AVDT_OpenReq()", __func__); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_scb->cfg.codec_info).c_str()); /* we may choose to use a different SEP at reconfig. * adjust the sep_idx now */ @@ -2978,15 +3009,14 @@ void bta_av_chk_2nd_start(tBTA_AV_SCB* p_scb, * ******************************************************************************/ void bta_av_open_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { - APPL_TRACE_DEBUG("%s: use_rc: %d, wait: 0x%x role: 0x%x", __func__, - p_scb->use_rc, p_scb->wait, p_scb->role); + LOG_VERBOSE("%s: use_rc: %d, wait: 0x%x role: 0x%x", __func__, p_scb->use_rc, + p_scb->wait, p_scb->role); if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) && (p_scb->q_tag == BTA_AV_Q_TAG_START)) { /* waiting for role switch for some reason & the timer expires */ if (!bta_av_link_role_ok(p_scb, A2DP_SET_ONE_BIT)) { - APPL_TRACE_ERROR( - "%s: failed to start streaming for role management reasons!!", - __func__); + LOG_ERROR("%s: failed to start streaming for role management reasons!!", + __func__); alarm_cancel(p_scb->avrc_ct_timer); tBTA_AV bta_av_data = { @@ -3025,8 +3055,25 @@ void bta_av_open_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { } } else { /* use main SM for AVRC SDP activities */ - if (is_new_avrcp_enabled()) { - APPL_TRACE_WARNING("%s: Using the new AVRCP Profile", __func__); + if (btif_av_both_enable()) { + /* if peer is sink, it should run new avrcp */ + if ((p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC) && + is_new_avrcp_enabled()) { + LOG_WARN("%s: local src Using the new AVRCP Profile", __func__); + if (bluetooth::avrcp::AvrcpService::Get() != nullptr) { + bluetooth::avrcp::AvrcpService::Get()->ConnectDevice( + p_scb->PeerAddress()); + return; + } + } + + LOG_WARN("%s: local sink Using the legacy AVRCP Profile", __func__); + bta_av_rc_disc((uint8_t)(p_scb->hdi + 1)); + + return; + } + if (btif_av_is_source_enabled() && is_new_avrcp_enabled()) { + LOG_WARN("%s: Using the new AVRCP Profile", __func__); bluetooth::avrcp::AvrcpService::Get()->ConnectDevice( p_scb->PeerAddress()); } else { @@ -3055,9 +3102,8 @@ void bta_av_open_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { memcpy(&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN)); - APPL_TRACE_DEBUG("%s: peer %s coll_mask=0x%02x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - p_scb->coll_mask); + LOG_VERBOSE("%s: peer %s coll_mask=0x%02x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->coll_mask); if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) { p_scb->coll_mask |= BTA_AV_COLL_API_CALLED; @@ -3081,20 +3127,20 @@ void offload_vendor_callback(tBTM_VSC_CMPL* param) { tBTA_AV value{0}; uint8_t sub_opcode = 0; if (param->param_len) { - APPL_TRACE_DEBUG("%s: param_len = %d status = %d", __func__, - param->param_len, param->p_param_buf[0]); + LOG_VERBOSE("%s: param_len = %d status = %d", __func__, param->param_len, + param->p_param_buf[0]); value.status = static_cast(param->p_param_buf[0]); } if (value.status == 0) { sub_opcode = param->p_param_buf[1]; - APPL_TRACE_DEBUG("%s: subopcode = %d", __func__, sub_opcode); + LOG_VERBOSE("%s: subopcode = %d", __func__, sub_opcode); switch (sub_opcode) { case VS_HCI_A2DP_OFFLOAD_STOP: - APPL_TRACE_DEBUG("%s: VS_HCI_STOP_A2DP_MEDIA successful", __func__); + LOG_VERBOSE("%s: VS_HCI_STOP_A2DP_MEDIA successful", __func__); break; case VS_HCI_A2DP_OFFLOAD_START: if (bta_av_cb.offload_start_pending_hndl) { - APPL_TRACE_DEBUG("%s: VS_HCI_START_A2DP_MEDIA successful", __func__); + LOG_VERBOSE("%s: VS_HCI_START_A2DP_MEDIA successful", __func__); bta_av_cb.offload_started_hndl = bta_av_cb.offload_start_pending_hndl; bta_av_cb.offload_start_pending_hndl = BTA_AV_INVALID_HANDLE; } else { @@ -3106,8 +3152,7 @@ void offload_vendor_callback(tBTM_VSC_CMPL* param) { break; } } else { - APPL_TRACE_DEBUG("%s: Offload failed for subopcode= %d", __func__, - sub_opcode); + LOG_VERBOSE("%s: Offload failed for subopcode= %d", __func__, sub_opcode); if (param->opcode != VS_HCI_A2DP_OFFLOAD_STOP) { bta_av_cb.offload_start_pending_hndl = BTA_AV_INVALID_HANDLE; (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &value); @@ -3118,7 +3163,7 @@ void offload_vendor_callback(tBTM_VSC_CMPL* param) { void bta_av_vendor_offload_start(tBTA_AV_SCB* p_scb, tBT_A2DP_OFFLOAD* offload_start) { uint8_t param[sizeof(tBT_A2DP_OFFLOAD)]; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); uint8_t* p_param = param; *p_param++ = VS_HCI_A2DP_OFFLOAD_START; @@ -3150,7 +3195,7 @@ void bta_av_vendor_offload_start(tBTA_AV_SCB* p_scb, void bta_av_vendor_offload_stop() { uint8_t param[sizeof(tBT_A2DP_OFFLOAD)]; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); param[0] = VS_HCI_A2DP_OFFLOAD_STOP; BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP, 1, param, offload_vendor_callback); @@ -3169,16 +3214,15 @@ void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { tBTA_AV_STATUS status = BTA_AV_FAIL_RESOURCES; tBT_A2DP_OFFLOAD offload_start; - APPL_TRACE_DEBUG("%s: stream %s, audio channels open %d", __func__, - p_scb->started ? "STARTED" : "STOPPED", - bta_av_cb.audio_open_cnt); + LOG_VERBOSE("%s: stream %s, audio channels open %d", __func__, + p_scb->started ? "STARTED" : "STOPPED", bta_av_cb.audio_open_cnt); /* Check if stream has already been started. */ /* Support offload if only one audio source stream is open. */ if (p_scb->started != true) { status = BTA_AV_FAIL_STREAM; } else if (bta_av_cb.offload_start_pending_hndl || bta_av_cb.offload_started_hndl) { - APPL_TRACE_WARNING("%s: offload already started, ignore request", __func__); + LOG_WARN("%s: offload already started, ignore request", __func__); return; } else { bta_av_offload_codec_builder(p_scb, &offload_start); @@ -3199,7 +3243,7 @@ void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { if (L2CA_GetConnectionConfig( p_scb->l2c_cid, &a2dp_offload_start.acl_data_size, &a2dp_offload_start.remote_cid, &a2dp_offload_start.lm_handle)) { - APPL_TRACE_DEBUG("%s: l2cmtu %d lcid 0x%02X rcid 0x%02X lm_handle + LOG_VERBOSE("%s: l2cmtu %d lcid 0x%02X rcid 0x%02X lm_handle 0x%02X", __func__, a2dp_offload_start.acl_data_size, p_scb->l2c_cid, a2dp_offload_start.remote_cid, @@ -3240,9 +3284,9 @@ void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) { tBTA_AV_STATUS status = p_data->api_status_rsp.status; - APPL_TRACE_DEBUG("%s: stream %s status %s", __func__, - p_scb->started ? "STARTED" : "STOPPED", - status ? "FAIL" : "SUCCESS"); + LOG_VERBOSE("%s: stream %s status %s", __func__, + p_scb->started ? "STARTED" : "STOPPED", + status ? "FAIL" : "SUCCESS"); /* Check if stream has already been started. */ if (status == BTA_AV_SUCCESS && p_scb->started != true) { @@ -3262,14 +3306,13 @@ static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb, A2DP_SourceCodecIndex(p_scb->cfg.codec_info); uint32_t codec_type = 0; uint16_t mtu = p_scb->stream_mtu; - APPL_TRACE_DEBUG("%s:codec_index = %d", __func__, codec_index); + LOG_VERBOSE("%s:codec_index = %d", __func__, codec_index); switch (codec_index) { case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC: codec_type = BTA_AV_CODEC_TYPE_SBC; if (A2DP_GetMaxBitpoolSbc(p_scb->cfg.codec_info) <= A2DP_SBC_BITPOOL_MIDDLE_QUALITY) { - APPL_TRACE_WARNING("%s: Restricting streaming MTU size for MQ Bitpool", - __func__); + LOG_WARN("%s: Restricting streaming MTU size for MQ Bitpool", __func__); mtu = MAX_2MBPS_AVDTP_MTU; } break; @@ -3289,7 +3332,7 @@ static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb, codec_type = BTA_AV_CODEC_TYPE_OPUS; break; default: - APPL_TRACE_ERROR("%s: Unknown Codec type ", __func__); + LOG_ERROR("%s: Unknown Codec type ", __func__); return; } if (mtu > MAX_3MBPS_AVDTP_MTU) mtu = MAX_3MBPS_AVDTP_MTU; @@ -3303,7 +3346,7 @@ static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb, p_scb->p_cos->get_scmst_info(p_scb->PeerAddress()); p_a2dp_offload->scms_t_enable[0] = scmst_info.enable_status; p_a2dp_offload->scms_t_enable[1] = scmst_info.cp_header; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: SCMS-T_enable status: %d, " "SCMS-T header (if it's enabled): 0x%02x", __func__, scmst_info.enable_status, scmst_info.cp_header); @@ -3323,7 +3366,7 @@ static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb, break; } if (L2CA_GetRemoteCid(p_scb->l2c_cid, &p_a2dp_offload->l2c_rcid) == false) { - APPL_TRACE_ERROR("%s: Failed to fetch l2c rcid", __func__); + LOG_ERROR("%s: Failed to fetch l2c rcid", __func__); return; } switch (CodecConfig->getAudioBitsPerSample()) { @@ -3340,6 +3383,28 @@ static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb, p_a2dp_offload->ch_mode = A2DP_GetTrackChannelCount(p_scb->cfg.codec_info); p_a2dp_offload->encoded_audio_bitrate = CodecConfig->getTrackBitRate(); if (!CodecConfig->getCodecSpecificConfig(p_a2dp_offload)) { - APPL_TRACE_ERROR("%s: not a valid codec info", __func__); + LOG_ERROR("%s: not a valid codec info", __func__); + } +} +void bta_av_api_set_peer_sep(tBTA_AV_DATA* p_data) { + LOG_VERBOSE("%s, bd_addr=%s, sep:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_data->peer_sep.addr), + p_data->peer_sep.sep); + const tBTA_AV_SCB* p_scb = bta_av_addr_to_scb(p_data->peer_sep.addr); + if (!p_scb) { + LOG_WARN("%s scb not found", __func__); + return; + } + LOG_VERBOSE("%s, rc_handle:%d", __func__, p_scb->rc_handle); + if (btif_av_both_enable()) { + if (p_data->peer_sep.sep == AVDT_TSEP_SNK) { + // src close legacy cback + LOG_WARN("%s: current dut is src", __func__); + AVRC_UpdateCcb(&p_data->peer_sep.addr, AVRC_CO_METADATA); + } else if (p_data->peer_sep.sep == AVDT_TSEP_SRC) { + // sink close new cback + LOG_WARN("%s: current dut is sink", __func__); + AVRC_UpdateCcb(&p_data->peer_sep.addr, AVRC_CO_GOOGLE); + } } } diff --git a/system/bta/av/bta_av_act.cc b/system/bta/av/bta_av_act.cc index c63950285230e5fef016a03d593c97152e701af1..3fac7a9b3eef4848c3dd907ae11348cf31db5ca4 100644 --- a/system/bta/av/bta_av_act.cc +++ b/system/bta/av/bta_av_act.cc @@ -27,21 +27,26 @@ #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/av/bta_av_int.h" #include "bta/include/bta_ar_api.h" #include "bta/include/utl.h" #include "btif/avrcp/avrcp_service.h" #include "device/include/device_iot_config.h" +#include "device/include/interop.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "osi/include/properties.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/l2c_api.h" +#include "stack/include/sdp_api.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + /***************************************************************************** * Constants ****************************************************************************/ @@ -62,6 +67,13 @@ static void bta_av_accept_signalling_timer_cback(void* data); #define AVRC_MIN_META_CMD_LEN 20 #endif +extern bool btif_av_is_source_enabled(void); +extern bool btif_av_both_enable(void); +extern bool btif_av_src_sink_coexist_enabled(void); +extern bool btif_av_is_sink_enabled(void); +extern bool btif_av_peer_is_connected_sink(const RawAddress& peer_address); +extern const RawAddress& btif_av_find_by_handle(tBTA_AV_HNDL bta_handle); + /******************************************************************************* * * Function bta_av_get_rcb_by_shdl @@ -107,8 +119,8 @@ void bta_av_del_rc(tBTA_AV_RCB* p_rcb) { p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; } if (p_scb) { - APPL_TRACE_DEBUG("%s: shdl:%d, srch:%d rc_handle:%d", __func__, - p_rcb->shdl, p_scb->rc_handle, p_rcb->handle); + LOG_VERBOSE("%s: shdl:%d, srch:%d rc_handle:%d", __func__, p_rcb->shdl, + p_scb->rc_handle, p_rcb->handle); if (p_scb->rc_handle == p_rcb->handle) p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE; /* just in case the RC timer is active @@ -118,9 +130,9 @@ void bta_av_del_rc(tBTA_AV_RCB* p_rcb) { } } - APPL_TRACE_EVENT("%s: handle: %d status=0x%x, rc_acp_handle:%d, idx:%d", - __func__, p_rcb->handle, p_rcb->status, - bta_av_cb.rc_acp_handle, bta_av_cb.rc_acp_idx); + LOG_VERBOSE("%s: handle: %d status=0x%x, rc_acp_handle:%d, idx:%d", + __func__, p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, + bta_av_cb.rc_acp_idx); rc_handle = p_rcb->handle; if (!(p_rcb->status & BTA_AV_RC_CONN_MASK) || ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) { @@ -133,7 +145,7 @@ void bta_av_del_rc(tBTA_AV_RCB* p_rcb) { AVRC_Close(rc_handle); if (rc_handle == bta_av_cb.rc_acp_handle) bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE; - APPL_TRACE_EVENT( + LOG_VERBOSE( "%s: end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d", __func__, p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx); @@ -169,7 +181,7 @@ static void bta_av_close_all_rc(tBTA_AV_CB* p_cb) { ******************************************************************************/ static void bta_av_del_sdp_rec(uint32_t* p_sdp_handle) { if (*p_sdp_handle != 0) { - SDP_DeleteRecord(*p_sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(*p_sdp_handle); *p_sdp_handle = 0; } } @@ -205,7 +217,23 @@ static void bta_av_rc_ctrl_cback(uint8_t handle, uint8_t event, const RawAddress* peer_addr) { uint16_t msg_event = 0; - APPL_TRACE_EVENT("%s: handle: %d event=0x%x", __func__, handle, event); + if (btif_av_both_enable() && peer_addr != NULL && + btif_av_peer_is_connected_sink(*peer_addr)) { + LOG_WARN("%s: not cback legacy cback, and close the handle", __func__); + + if (event == AVRC_CLOSE_IND_EVT || event == AVRC_OPEN_IND_EVT) { + LOG_VERBOSE("%s: resend close event", __func__); + tBTA_AV_RC_CONN_CHG* p_msg = + (tBTA_AV_RC_CONN_CHG*)osi_malloc(sizeof(tBTA_AV_RC_CONN_CHG)); + p_msg->hdr.event = BTA_AV_AVRC_CLOSE_EVT; + p_msg->handle = handle; + p_msg->peer_addr = *peer_addr; + bta_sys_sendmsg(p_msg); + } + return; + } + + LOG_VERBOSE("%s: handle: %d event=0x%x", __func__, handle, event); if (event == AVRC_OPEN_IND_EVT) { /* save handle of opened connection bta_av_cb.rc_handle = handle;*/ @@ -243,7 +271,7 @@ static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode, uint8_t* p_data_src = NULL; uint16_t data_len = 0; - APPL_TRACE_DEBUG("%s: handle: %u opcode=0x%x", __func__, handle, opcode); + LOG_VERBOSE("%s: handle: %u opcode=0x%x", __func__, handle, opcode); /* Copy avrc packet into BTA message buffer (for sending to BTA state machine) */ @@ -301,7 +329,10 @@ static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode, ******************************************************************************/ uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, uint8_t lidx) { - if (is_new_avrcp_enabled()) { + if ((!btif_av_src_sink_coexist_enabled() || + (btif_av_src_sink_coexist_enabled() && !btif_av_is_sink_enabled() && + btif_av_is_source_enabled())) && + is_new_avrcp_enabled()) { LOG_INFO("Skipping RC creation for the old AVRCP profile"); return BTA_AV_RC_HANDLE_NONE; } @@ -316,7 +347,7 @@ uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, if (role == AVCT_INT) { // Can't grab a stream control block that doesn't have a valid handle if (!shdl) { - APPL_TRACE_ERROR( + LOG_ERROR( "%s: Can't grab stream control block for shdl = %d -> index = %d", __func__, shdl, shdl - 1); return BTA_AV_RC_HANDLE_NONE; @@ -330,7 +361,7 @@ uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, } else { p_rcb = bta_av_get_rcb_by_shdl(shdl); if (p_rcb != NULL) { - APPL_TRACE_ERROR("%s: ACP handle exist for shdl:%d", __func__, shdl); + LOG_ERROR("%s: ACP handle exist for shdl:%d", __func__, shdl); p_rcb->lidx = lidx; return p_rcb->handle; } @@ -354,7 +385,7 @@ uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, p_rcb = &p_cb->rcb[i]; if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) { - APPL_TRACE_ERROR("%s: found duplicated handle:%d", __func__, rc_handle); + LOG_ERROR("%s: found duplicated handle:%d", __func__, rc_handle); } p_rcb->handle = rc_handle; @@ -362,15 +393,17 @@ uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, p_rcb->shdl = shdl; p_rcb->lidx = lidx; p_rcb->peer_features = 0; + p_rcb->peer_ct_features = 0; + p_rcb->peer_tg_features = 0; p_rcb->cover_art_psm = 0; if (lidx == (BTA_AV_NUM_LINKS + 1)) { /* this LIDX is reserved for the AVRCP ACP connection */ p_cb->rc_acp_handle = p_rcb->handle; p_cb->rc_acp_idx = (i + 1); - APPL_TRACE_DEBUG("%s: rc_acp_handle:%d idx:%d", __func__, - p_cb->rc_acp_handle, p_cb->rc_acp_idx); + LOG_VERBOSE("%s: rc_acp_handle:%d idx:%d", __func__, p_cb->rc_acp_handle, + p_cb->rc_acp_idx); } - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x", __func__, i, role, shdl, p_rcb->handle, lidx, p_rcb->status); @@ -458,15 +491,15 @@ tBTA_AV_LCB* bta_av_find_lcb(const RawAddress& addr, uint8_t op) { uint8_t mask; tBTA_AV_LCB* p_lcb = NULL; - APPL_TRACE_DEBUG("%s: address: %s op:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(addr), op); + LOG_VERBOSE("%s: address: %s op:%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(addr), + op); for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) { mask = 1 << xx; /* the used mask for this lcb */ if ((mask & p_cb->conn_lcb) && p_cb->lcb[xx].addr == addr) { p_lcb = &p_cb->lcb[xx]; if (op == BTA_AV_LCB_FREE) { p_cb->conn_lcb &= ~mask; /* clear the connect mask */ - APPL_TRACE_DEBUG("%s: conn_lcb: 0x%x", __func__, p_cb->conn_lcb); + LOG_VERBOSE("%s: conn_lcb: 0x%x", __func__, p_cb->conn_lcb); } break; } @@ -498,8 +531,7 @@ void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { p_scb = p_cb->p_scb[i]; if (p_scb && p_scb->PeerAddress() == p_data->rc_conn_chg.peer_addr) { p_scb->rc_handle = p_data->rc_conn_chg.handle; - APPL_TRACE_DEBUG("%s: shdl:%d, srch %d", __func__, i + 1, - p_scb->rc_handle); + LOG_VERBOSE("%s: shdl:%d, srch %d", __func__, i + 1, p_scb->rc_handle); shdl = i + 1; LOG_INFO("%s: allow incoming AVRCP connections:%d", __func__, p_scb->use_rc); @@ -511,12 +543,12 @@ void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { i = p_data->rc_conn_chg.handle; if (p_cb->rcb[i].handle == BTA_AV_RC_HANDLE_NONE) { - APPL_TRACE_ERROR("%s: not a valid handle:%d any more", __func__, i); + LOG_ERROR("%s: not a valid handle:%d any more", __func__, i); return; } - APPL_TRACE_DEBUG("%s: local features %d peer features %d", __func__, - p_cb->features, p_cb->rcb[i].peer_features); + LOG_VERBOSE("%s: local features %d peer features %d", __func__, + p_cb->features, p_cb->rcb[i].peer_features); /* listen to browsing channel when the connection is open, * if peer initiated AVRCP connection and local device supports browsing @@ -534,15 +566,15 @@ void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { p_cb->rcb[i].lidx = tmp; p_cb->rc_acp_handle = p_rcb->handle; p_cb->rc_acp_idx = (p_rcb - p_cb->rcb) + 1; - APPL_TRACE_DEBUG("%s: switching RCB rc_acp_handle:%d idx:%d", __func__, - p_cb->rc_acp_handle, p_cb->rc_acp_idx); + LOG_VERBOSE("%s: switching RCB rc_acp_handle:%d idx:%d", __func__, + p_cb->rc_acp_handle, p_cb->rc_acp_idx); } } p_cb->rcb[i].shdl = shdl; rc_open.rc_handle = i; - APPL_TRACE_ERROR("%s: rcb[%d] shdl:%d lidx:%d/%d", __func__, i, shdl, - p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx); + LOG_ERROR("%s: rcb[%d] shdl:%d lidx:%d/%d", __func__, i, shdl, + p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx); p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK; if (!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx) { @@ -553,19 +585,64 @@ void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { p_lcb->lidx = BTA_AV_NUM_LINKS + 1; p_cb->rcb[i].lidx = p_lcb->lidx; p_lcb->conn_msk = 1; - APPL_TRACE_ERROR("%s: bd_addr: %s rcb[%d].lidx=%d, lcb.conn_msk=x%x", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_lcb->addr), i, - p_cb->rcb[i].lidx, p_lcb->conn_msk); + LOG_ERROR("%s: bd_addr: %s rcb[%d].lidx=%d, lcb.conn_msk=x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_lcb->addr), i, p_cb->rcb[i].lidx, + p_lcb->conn_msk); disc = p_data->rc_conn_chg.handle | BTA_AV_CHNL_MSK; } rc_open.peer_addr = p_data->rc_conn_chg.peer_addr; rc_open.peer_features = p_cb->rcb[i].peer_features; rc_open.cover_art_psm = p_cb->rcb[i].cover_art_psm; + if (btif_av_both_enable()) { + if (rc_open.peer_addr == p_cb->rc_feature.peer_addr) { + rc_open.peer_features = p_cb->rc_feature.peer_features; + rc_open.peer_ct_features = p_cb->rc_feature.peer_ct_features; + rc_open.peer_tg_features = p_cb->rc_feature.peer_tg_features; + } else { + rc_open.peer_features = p_cb->rcb[i].peer_features; + rc_open.peer_ct_features = p_cb->rcb[i].peer_ct_features; + rc_open.peer_tg_features = p_cb->rcb[i].peer_tg_features; + } + rc_open.status = BTA_AV_SUCCESS; + LOG_VERBOSE( + "local features:0x%x peer_features:0x%x, peer_ct_feature:0x%x, " + "peer_tg_feature:0x%x", + p_cb->features, rc_open.peer_features, rc_open.peer_ct_features, + rc_open.peer_tg_features); + if (rc_open.peer_features == 0 && rc_open.peer_ct_features == 0 && + rc_open.peer_tg_features == 0) { + /* we have not done SDP on peer RC capabilities. + * peer must have initiated the RC connection + * We Don't have SDP records of Peer, so we by + * default will take values depending upon registered + * features */ + if (p_cb->features & BTA_AV_FEAT_RCTG) { + rc_open.peer_ct_features |= BTA_AV_FEAT_RCCT; + rc_open.peer_features |= BTA_AV_FEAT_RCCT; + } + bta_av_rc_disc(disc); + } + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV*)&rc_open); + + /* if local initiated AVRCP connection and both peer and locals device + * support + * browsing channel, open the browsing channel now + * Some TG would not broadcast browse feature hence check inter-op. */ + if ((p_cb->features & BTA_AV_FEAT_BROWSE) && + ((rc_open.peer_ct_features & BTA_AV_FEAT_BROWSE) || + (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("%s: opening AVRC Browse channel", __func__); + AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_INT); + } + } + return; + } rc_open.status = BTA_AV_SUCCESS; - APPL_TRACE_DEBUG("%s: local features:x%x peer_features:x%x", __func__, - p_cb->features, rc_open.peer_features); - APPL_TRACE_DEBUG("%s: cover art psm:x%x", __func__, rc_open.cover_art_psm); + LOG_VERBOSE("%s: local features:x%x peer_features:x%x", __func__, + p_cb->features, rc_open.peer_features); + LOG_VERBOSE("%s: cover art psm:x%x", __func__, rc_open.cover_art_psm); if (rc_open.peer_features == 0) { /* we have not done SDP on peer RC capabilities. * peer must have initiated the RC connection */ @@ -587,7 +664,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)) { - APPL_TRACE_DEBUG("%s: opening AVRC Browse channel", __func__); + LOG_VERBOSE("%s: opening AVRC Browse channel", __func__); AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_INT); } } @@ -676,7 +753,8 @@ void bta_av_rc_meta_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) { AVRC_MsgReq(p_rcb->handle, p_data->api_meta_rsp.label, - p_data->api_meta_rsp.rsp_code, p_data->api_meta_rsp.p_pkt); + p_data->api_meta_rsp.rsp_code, p_data->api_meta_rsp.p_pkt, + false); do_free = false; } } @@ -734,6 +812,19 @@ static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR* p_vendor) { if ((u16 != 5) || (p_vendor->vendor_len != 9)) { status = AVRC_STS_INTERNAL_ERR; } else { + if (btif_av_both_enable()) { + for (xx = 0; xx < bta_av_cfg.num_evt_ids; xx++) { + if (*p == bta_av_cfg.p_meta_evt_ids[xx]) { + return status; + } + } + for (xx = 0; xx < get_bta_avk_cfg()->num_evt_ids; xx++) { + if (*p == get_bta_avk_cfg()->p_meta_evt_ids[xx]) { + return status; + } + } + return AVRC_STS_BAD_PARAM; + } /* make sure the player_id is valid */ for (xx = 0; xx < p_bta_av_cfg->num_evt_ids; xx++) { if (*p == p_bta_av_cfg->p_meta_evt_ids[xx]) { @@ -748,6 +839,33 @@ static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR* p_vendor) { return status; } +void bta_av_proc_rsp(tAVRC_RESPONSE* p_rc_rsp) { + uint16_t rc_ver = 0x105; + const tBTA_AV_CFG* p_src_cfg = NULL; + if (rc_ver != 0x103) + p_src_cfg = &bta_av_cfg; + else + p_src_cfg = &bta_av_cfg_compatibility; + p_rc_rsp->get_caps.count = p_src_cfg->num_evt_ids; + memcpy(p_rc_rsp->get_caps.param.event_id, p_src_cfg->p_meta_evt_ids, + p_src_cfg->num_evt_ids); + LOG_VERBOSE("%s: ver: 0x%x", __func__, rc_ver); + /* if it's not 1.3, then there should be a absolute volume */ + if (rc_ver != 0x103) { + uint8_t evt_cnt = p_rc_rsp->get_caps.count; + p_rc_rsp->get_caps.count += get_bta_avk_cfg()->num_evt_ids; + if (evt_cnt < AVRC_CAP_MAX_NUM_EVT_ID) { + uint32_t i = 0; + for (i = 0; i < get_bta_avk_cfg()->num_evt_ids && + i + evt_cnt < AVRC_CAP_MAX_NUM_EVT_ID; + i++) { + p_rc_rsp->get_caps.param.event_id[evt_cnt + i] = + get_bta_avk_cfg()->p_meta_evt_ids[i]; + } + } + } +} + /******************************************************************************* * * Function bta_av_proc_meta_cmd @@ -766,7 +884,7 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE* p_rc_rsp, if (p_vendor->vendor_len == 0) { p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM; - APPL_TRACE_DEBUG("%s: p_vendor->vendor_len == 0", __func__); + LOG_VERBOSE("%s: p_vendor->vendor_len == 0", __func__); // the caller of this function assume 0 to be an invalid event return 0; } @@ -779,22 +897,22 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE* p_rc_rsp, if ((AVRC_MIN_META_CMD_LEN + p_vendor->vendor_len) > AVRC_META_CMD_BUF_SIZE) { /* reject it */ p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM; - APPL_TRACE_ERROR("%s: Invalid meta-command length: %d", __func__, - p_vendor->vendor_len); + LOG_ERROR("%s: Invalid meta-command length: %d", __func__, + p_vendor->vendor_len); return 0; } /* Metadata messages only use PANEL sub-unit type */ if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL) { - APPL_TRACE_DEBUG("%s: SUBUNIT must be PANEL", __func__); + LOG_VERBOSE("%s: SUBUNIT must be PANEL", __func__); /* reject it */ evt = 0; p_vendor->hdr.ctype = AVRC_RSP_NOT_IMPL; p_vendor->vendor_len = 0; p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM; } else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype)) { - APPL_TRACE_DEBUG("%s: Invalid pdu/ctype: 0x%x, %d", __func__, pdu, - p_vendor->hdr.ctype); + LOG_VERBOSE("%s: Invalid pdu/ctype: 0x%x, %d", __func__, pdu, + p_vendor->hdr.ctype); /* reject invalid message without reporting to app */ evt = 0; p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD; @@ -823,11 +941,15 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE* p_rc_rsp, (p_bta_av_cfg->num_co_ids << 2)); } else if (u8 == AVRC_CAP_EVENTS_SUPPORTED) { *p_ctype = AVRC_RSP_IMPL_STBL; + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + bta_av_proc_rsp(p_rc_rsp); + break; + } p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids; memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids, p_bta_av_cfg->num_evt_ids); } else { - APPL_TRACE_DEBUG("%s: Invalid capability ID: 0x%x", __func__, u8); + LOG_VERBOSE("%s: Invalid capability ID: 0x%x", __func__, u8); /* reject - unknown capability ID */ p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM; } @@ -867,12 +989,12 @@ void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { rc_rsp.rsp.status = BTA_AV_STS_NO_RSP; if (NULL == p_data) { - APPL_TRACE_ERROR("%s: Message from peer with no data", __func__); + LOG_ERROR("%s: Message from peer with no data", __func__); return; } - APPL_TRACE_DEBUG("%s: opcode=%x, ctype=%x", __func__, p_data->rc_msg.opcode, - p_data->rc_msg.msg.hdr.ctype); + LOG_VERBOSE("%s: opcode=%x, ctype=%x", __func__, p_data->rc_msg.opcode, + p_data->rc_msg.msg.hdr.ctype); if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU) { /* if this is a pass thru command */ @@ -898,7 +1020,7 @@ void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry); } - APPL_TRACE_DEBUG("%s: ctype %d", __func__, p_data->rc_msg.msg.hdr.ctype) + LOG_VERBOSE("%s: ctype %d", __func__, p_data->rc_msg.msg.hdr.ctype); /* send response */ if (p_data->rc_msg.msg.hdr.ctype != AVRC_RSP_INTERIM) @@ -926,14 +1048,16 @@ void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state; av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype; av.remote_rsp.label = p_data->rc_msg.label; + av.remote_rsp.len = p_data->rc_msg.msg.pass.pass_len; + av.remote_rsp.p_data = NULL; /* If this response is for vendor unique command */ if ((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) && (p_data->rc_msg.msg.pass.pass_len > 0)) { av.remote_rsp.p_data = (uint8_t*)osi_malloc(p_data->rc_msg.msg.pass.pass_len); - APPL_TRACE_DEBUG("%s: Vendor Unique data len = %d", __func__, - p_data->rc_msg.msg.pass.pass_len); + LOG_VERBOSE("%s: Vendor Unique data len = %d", __func__, + p_data->rc_msg.msg.pass.pass_len); memcpy(av.remote_rsp.p_data, p_data->rc_msg.msg.pass.p_pass_data, p_data->rc_msg.msg.pass.pass_len); } @@ -1006,7 +1130,8 @@ void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { AVRC_BldResponse(0, &rc_rsp, &p_pkt); } if (p_pkt) - AVRC_MsgReq(p_data->rc_msg.handle, p_data->rc_msg.label, ctype, p_pkt); + AVRC_MsgReq(p_data->rc_msg.handle, p_data->rc_msg.label, ctype, p_pkt, + false); } /* call callback */ @@ -1038,8 +1163,8 @@ void bta_av_rc_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { if (handle < BTA_AV_NUM_RCB) { p_rcb = &p_cb->rcb[handle]; - APPL_TRACE_DEBUG("%s: handle: %d, status=0x%x", __func__, p_rcb->handle, - p_rcb->status); + LOG_VERBOSE("%s: handle: %d, status=0x%x", __func__, p_rcb->handle, + p_rcb->status); if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) { if (p_rcb->shdl) { p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; @@ -1066,7 +1191,7 @@ void bta_av_rc_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { * ******************************************************************************/ void bta_av_rc_browse_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { - APPL_TRACE_WARNING("%s: empty placeholder does nothing!", __func__); + LOG_WARN("%s: empty placeholder does nothing!", __func__); } /******************************************************************************* @@ -1101,9 +1226,9 @@ static uint8_t bta_av_get_shdl(tBTA_AV_SCB* p_scb) { void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started) { uint8_t started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi); - APPL_TRACE_DEBUG("%s: peer %s started:%s started_msk:0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - logbool(started).c_str(), started_msk); + LOG_VERBOSE("%s: peer %s started:%s started_msk:0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), + logbool(started).c_str(), started_msk); if (started) { /* Let L2CAP know this channel is processed with high priority */ @@ -1153,7 +1278,7 @@ void bta_av_conn_chg(tBTA_AV_DATA* p_data) { for (i = 0; i < BTA_AV_NUM_RCB; i++) { if (bta_av_cb.rcb[i].lidx == p_lcb->lidx) { bta_av_cb.rcb[i].shdl = index + 1; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d", __func__, i, bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status, bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx); @@ -1169,13 +1294,13 @@ void bta_av_conn_chg(tBTA_AV_DATA* p_data) { bta_av_cb.audio_open_cnt++; } - APPL_TRACE_DEBUG("%s: rc_acp_handle:%d rc_acp_idx:%d", __func__, - p_cb->rc_acp_handle, p_cb->rc_acp_idx); + LOG_VERBOSE("%s: rc_acp_handle:%d rc_acp_idx:%d", __func__, + p_cb->rc_acp_handle, p_cb->rc_acp_idx); /* check if the AVRCP ACP channel is already connected */ if (p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx) { p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS]; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: rc_acp is connected && conn_chg on same addr " "p_lcb_rc->conn_msk:x%x", __func__, p_lcb_rc->conn_msk); @@ -1193,25 +1318,24 @@ void bta_av_conn_chg(tBTA_AV_DATA* p_data) { p_scb->rc_handle = p_cb->rc_acp_handle; p_rcb = &p_cb->rcb[p_cb->rc_acp_idx - 1]; p_rcb->shdl = bta_av_get_shdl(p_scb); - APPL_TRACE_DEBUG("%s: update rc_acp shdl:%d/%d srch:%d", __func__, - index + 1, p_rcb->shdl, p_scb->rc_handle); + LOG_VERBOSE("%s: update rc_acp shdl:%d/%d srch:%d", __func__, + index + 1, p_rcb->shdl, p_scb->rc_handle); p_rcb2 = bta_av_get_rcb_by_shdl(p_rcb->shdl); if (p_rcb2) { /* found the RCB that was created to associated with this SCB */ p_cb->rc_acp_handle = p_rcb2->handle; p_cb->rc_acp_idx = (p_rcb2 - p_cb->rcb) + 1; - APPL_TRACE_DEBUG("%s: new rc_acp_handle:%d, idx:%d", __func__, - p_cb->rc_acp_handle, p_cb->rc_acp_idx); + LOG_VERBOSE("%s: new rc_acp_handle:%d, idx:%d", __func__, + p_cb->rc_acp_handle, p_cb->rc_acp_idx); p_rcb2->lidx = (BTA_AV_NUM_LINKS + 1); - APPL_TRACE_DEBUG("%s: rc2 handle:%d lidx:%d/%d", __func__, - p_rcb2->handle, p_rcb2->lidx, - p_cb->lcb[p_rcb2->lidx - 1].lidx); + LOG_VERBOSE("%s: rc2 handle:%d lidx:%d/%d", __func__, + p_rcb2->handle, p_rcb2->lidx, + p_cb->lcb[p_rcb2->lidx - 1].lidx); } p_rcb->lidx = p_lcb->lidx; - APPL_TRACE_DEBUG("%s: rc handle:%d lidx:%d/%d", __func__, - p_rcb->handle, p_rcb->lidx, - p_cb->lcb[p_rcb->lidx - 1].lidx); + LOG_VERBOSE("%s: rc handle:%d lidx:%d/%d", __func__, p_rcb->handle, + p_rcb->lidx, p_cb->lcb[p_rcb->lidx - 1].lidx); } } } @@ -1240,12 +1364,11 @@ void bta_av_conn_chg(tBTA_AV_DATA* p_data) { } } - APPL_TRACE_DEBUG("%s: shdl:%d", __func__, index + 1); + LOG_VERBOSE("%s: shdl:%d", __func__, index + 1); for (i = 0; i < BTA_AV_NUM_RCB; i++) { - APPL_TRACE_DEBUG("%s: conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", - __func__, i, bta_av_cb.rcb[i].handle, - bta_av_cb.rcb[i].status, bta_av_cb.rcb[i].shdl, - bta_av_cb.rcb[i].lidx); + LOG_VERBOSE("%s: conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", + __func__, i, bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status, + bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx); if (bta_av_cb.rcb[i].shdl == index + 1) { bta_av_del_rc(&bta_av_cb.rcb[i]); /* since the connection is already down and info was removed, clean @@ -1267,7 +1390,7 @@ void bta_av_conn_chg(tBTA_AV_DATA* p_data) { bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); } - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: audio:%x up:%d conn_msk:0x%x chk_restore:%d " "audio_open_cnt:%d", __func__, p_cb->conn_audio, p_data->conn_chg.is_up, conn_msk, chk_restore, @@ -1400,8 +1523,8 @@ void bta_av_api_set_latency(tBTA_AV_DATA* p_data) { */ static uint8_t bta_av_find_lcb_index_by_scb_and_address( const RawAddress& peer_address) { - APPL_TRACE_DEBUG("%s: peer_address: %s conn_lcb: 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_cb.conn_lcb); + LOG_VERBOSE("%s: peer_address: %s conn_lcb: 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_cb.conn_lcb); // Find the index if there is already SCB entry for the peer address for (uint8_t index = 0; index < BTA_AV_NUM_LINKS; index++) { @@ -1429,6 +1552,12 @@ static uint8_t bta_av_find_lcb_index_by_scb_and_address( continue; } if (!p_scb->IsAssigned()) { + const RawAddress& btif_addr = btif_av_find_by_handle(p_scb->hndl); + if (!btif_addr.IsEmpty() && btif_addr != peer_address) { + LOG_DEBUG("%s: btif_addr = %s, index=%d!", + __func__, btif_addr.ToString().c_str(), index); + continue; + } return index; } } @@ -1452,10 +1581,10 @@ void bta_av_sig_chg(tBTA_AV_DATA* p_data) { uint8_t mask; tBTA_AV_LCB* p_lcb = NULL; - APPL_TRACE_DEBUG("%s: event: %d", __func__, event); + LOG_VERBOSE("%s: event: %d", __func__, event); if (event == AVDT_CONNECT_IND_EVT) { - APPL_TRACE_DEBUG("%s: AVDT_CONNECT_IND_EVT: peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_data->str_msg.bd_addr)); + LOG_VERBOSE("%s: AVDT_CONNECT_IND_EVT: peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_data->str_msg.bd_addr)); p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND); if (!p_lcb) { @@ -1466,9 +1595,8 @@ void bta_av_sig_chg(tBTA_AV_DATA* p_data) { if (xx >= BTA_AV_NUM_LINKS) { /* We do not have scb for this avdt connection. */ /* Silently close the connection. */ - APPL_TRACE_ERROR("%s: av scb not available for avdt connection for %s", - __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_data->str_msg.bd_addr)); + LOG_ERROR("%s: av scb not available for avdt connection for %s", + __func__, ADDRESS_TO_LOGGABLE_CSTR(p_data->str_msg.bd_addr)); AVDT_DisconnectReq(p_data->str_msg.bd_addr, NULL); return; } @@ -1487,10 +1615,10 @@ void bta_av_sig_chg(tBTA_AV_DATA* p_data) { } /* this entry is not used yet. */ p_cb->conn_lcb |= mask; /* mark it as used */ - APPL_TRACE_DEBUG("%s: start sig timer %d", __func__, p_data->hdr.offset); + LOG_VERBOSE("%s: start sig timer %d", __func__, p_data->hdr.offset); if (p_data->hdr.offset == AVDT_ACP) { - APPL_TRACE_DEBUG("%s: Incoming L2CAP acquired, set state as incoming", - __func__); + LOG_VERBOSE("%s: Incoming L2CAP acquired, set state as incoming", + __func__); p_scb->OnConnected(p_data->str_msg.bd_addr); p_scb->use_rc = true; /* allowing RC for incoming connection */ bta_av_ssm_execute(p_scb, BTA_AV_ACP_CONNECT_EVT, p_data); @@ -1509,7 +1637,7 @@ void bta_av_sig_chg(tBTA_AV_DATA* p_data) { hdr.layer_specific = p_scb->hndl; bta_av_signalling_timer((tBTA_AV_DATA*)&hdr); - APPL_TRACE_DEBUG("%s: Re-start timer for AVDTP service", __func__); + LOG_VERBOSE("%s: Re-start timer for AVDTP service", __func__); bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->PeerAddress()); /* Possible collision : need to avoid outgoing processing while the * timer is running */ @@ -1529,17 +1657,22 @@ void bta_av_sig_chg(tBTA_AV_DATA* p_data) { } else { /* disconnected. */ - APPL_TRACE_DEBUG("%s: bta_av_cb.conn_lcb=0x%x", __func__, - bta_av_cb.conn_lcb); + LOG_VERBOSE("%s: bta_av_cb.conn_lcb=0x%x", __func__, bta_av_cb.conn_lcb); p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE); if (p_lcb && (p_lcb->conn_msk || bta_av_cb.conn_lcb)) { - APPL_TRACE_DEBUG("%s: conn_msk: 0x%x", __func__, p_lcb->conn_msk); + LOG_VERBOSE("%s: conn_msk: 0x%x", __func__, p_lcb->conn_msk); /* clean up ssm */ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { if (p_cb->p_scb[xx] && p_cb->p_scb[xx]->PeerAddress() == p_data->str_msg.bd_addr) { - APPL_TRACE_DEBUG("%s: Closing timer for AVDTP service", __func__); + if ((p_cb->p_scb[xx]->state == 1) && + alarm_is_scheduled(p_cb->p_scb[xx]->accept_signalling_timer) && + interop_match_addr(INTEROP_IGNORE_DISC_BEFORE_SIGNALLING_TIMEOUT, + &(p_data->str_msg.bd_addr))) { + continue; + } + LOG_VERBOSE("%s: Closing timer for AVDTP service", __func__); bta_sys_conn_close(BTA_ID_AV, p_cb->p_scb[xx]->app_id, p_cb->p_scb[xx]->PeerAddress()); } @@ -1547,16 +1680,15 @@ void bta_av_sig_chg(tBTA_AV_DATA* p_data) { if (((mask & p_lcb->conn_msk) || bta_av_cb.conn_lcb) && p_cb->p_scb[xx] && p_cb->p_scb[xx]->PeerAddress() == p_data->str_msg.bd_addr) { - APPL_TRACE_WARNING( - "%s: Sending AVDT_DISCONNECT_EVT peer_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_cb->p_scb[xx]->PeerAddress())); + LOG_WARN("%s: Sending AVDT_DISCONNECT_EVT peer_addr=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_cb->p_scb[xx]->PeerAddress())); bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL); } } } } - APPL_TRACE_DEBUG("%s: bta_av_cb.conn_lcb=0x%x after sig_chg", __func__, - p_cb->conn_lcb); + LOG_VERBOSE("%s: bta_av_cb.conn_lcb=0x%x after sig_chg", __func__, + p_cb->conn_lcb); } /******************************************************************************* @@ -1580,18 +1712,18 @@ void bta_av_signalling_timer(UNUSED_ATTR tBTA_AV_DATA* p_data) { uint8_t mask; tBTA_AV_LCB* p_lcb = NULL; - APPL_TRACE_DEBUG("%s: conn_lcb=0x%x", __func__, p_cb->conn_lcb); + LOG_VERBOSE("%s: conn_lcb=0x%x", __func__, p_cb->conn_lcb); for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) { p_lcb = &p_cb->lcb[xx]; mask = 1 << xx; - APPL_TRACE_DEBUG( - "%s: index=%d conn_lcb=0x%x peer=%s conn_mask=0x%x lidx=%d", __func__, - xx, p_cb->conn_lcb, ADDRESS_TO_LOGGABLE_CSTR(p_lcb->addr), - p_lcb->conn_msk, p_lcb->lidx); + LOG_VERBOSE("%s: index=%d conn_lcb=0x%x peer=%s conn_mask=0x%x lidx=%d", + __func__, xx, p_cb->conn_lcb, + ADDRESS_TO_LOGGABLE_CSTR(p_lcb->addr), p_lcb->conn_msk, + p_lcb->lidx); if (mask & p_cb->conn_lcb) { /* this entry is used. check if it is connected */ if (!p_lcb->conn_msk) { - APPL_TRACE_DEBUG("%s hndl 0x%x", __func__, p_scb->hndl); + LOG_VERBOSE("%s hndl 0x%x", __func__, p_scb->hndl); bta_sys_start_timer(p_scb->link_signalling_timer, BTA_AV_SIGNALLING_TIMEOUT_MS, BTA_AV_SIGNALLING_TIMER_EVT, hndl); @@ -1599,7 +1731,7 @@ void bta_av_signalling_timer(UNUSED_ATTR tBTA_AV_DATA* p_data) { pend.bd_addr = p_lcb->addr; tBTA_AV bta_av_data; bta_av_data.pend = pend; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: BTA_AV_PENDING_EVT for %s index=%d conn_mask=0x%x lidx=%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(pend.bd_addr), xx, p_lcb->conn_msk, p_lcb->lidx); @@ -1627,14 +1759,14 @@ static void bta_av_accept_signalling_timer_cback(void* data) { p_scb = p_cb->p_scb[inx]; } if (p_scb) { - APPL_TRACE_DEBUG("%s: coll_mask=0x%02x", __func__, p_scb->coll_mask); + LOG_VERBOSE("%s: coll_mask=0x%02x", __func__, p_scb->coll_mask); if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) { p_scb->coll_mask &= ~BTA_AV_COLL_INC_TMR; if (bta_av_is_scb_opening(p_scb)) { - APPL_TRACE_DEBUG("%s: stream state opening: SDP started = %d", __func__, - p_scb->sdp_discovery_started); + LOG_VERBOSE("%s: stream state opening: SDP started = %d", __func__, + p_scb->sdp_discovery_started); if (p_scb->sdp_discovery_started) { /* We are still doing SDP. Run the timer again. */ p_scb->coll_mask |= BTA_AV_COLL_INC_TMR; @@ -1650,7 +1782,7 @@ static void bta_av_accept_signalling_timer_cback(void* data) { } else if (bta_av_is_scb_incoming(p_scb)) { /* Stay in incoming state if SNK does not start signalling */ - APPL_TRACE_DEBUG("%s: stream state incoming", __func__); + LOG_VERBOSE("%s: stream state incoming", __func__); /* API open was called right after SNK opened L2C connection. */ if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED) { p_scb->coll_mask &= ~BTA_AV_COLL_API_CALLED; @@ -1671,12 +1803,13 @@ static void bta_av_store_peer_rc_version() { tSDP_DISC_REC* p_rec = NULL; uint16_t peer_rc_version = 0; /*Assuming Default peer version as 1.3*/ - if ((p_rec = SDP_FindServiceInDb( + if ((p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL)) != NULL) { - if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { + if ((get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { /* get profile version (if failure, version parameter is not updated) */ - SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, - &peer_rc_version); + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version); } if (peer_rc_version != 0) DEVICE_IOT_CONFIG_ADDR_SET_HEX_IF_GREATER( @@ -1685,12 +1818,13 @@ static void bta_av_store_peer_rc_version() { } peer_rc_version = 0; - if ((p_rec = SDP_FindServiceInDb( + if ((p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) != NULL) { - if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { + if ((get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { /* get profile version (if failure, version parameter is not updated) */ - SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, - &peer_rc_version); + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version); } if (peer_rc_version != 0) DEVICE_IOT_CONFIG_ADDR_SET_HEX_IF_GREATER( @@ -1717,40 +1851,43 @@ tBTA_AV_FEAT bta_av_check_peer_features(uint16_t service_uuid) { uint16_t peer_rc_version = 0; uint16_t categories = 0; - APPL_TRACE_DEBUG("%s: service_uuid:x%x", __func__, service_uuid); + LOG_VERBOSE("%s: service_uuid:x%x", __func__, service_uuid); /* loop through all records we found */ while (true) { /* get next record; if none found, we're done */ - p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, service_uuid, p_rec); if (p_rec == NULL) { break; } - if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != - NULL) { + if ((get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL) { /* find peer features */ - if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, - NULL)) { + if (get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL)) { peer_features |= BTA_AV_FEAT_RCCT; } - if (SDP_FindServiceInDb(p_cb->p_disc_db, - UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) { + if (get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) { peer_features |= BTA_AV_FEAT_RCTG; } } - if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { + if ((get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { /* get profile version (if failure, version parameter is not updated) */ - SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, - &peer_rc_version); - APPL_TRACE_DEBUG("%s: peer_rc_version 0x%x", __func__, peer_rc_version); + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version); + LOG_VERBOSE("%s: peer_rc_version 0x%x", __func__, peer_rc_version); if (peer_rc_version >= AVRC_REV_1_3) peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA); if (peer_rc_version >= AVRC_REV_1_4) { /* get supported categories */ - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SUPPORTED_FEATURES); if (p_attr != NULL && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -1763,7 +1900,7 @@ tBTA_AV_FEAT bta_av_check_peer_features(uint16_t service_uuid) { } } } - APPL_TRACE_DEBUG("%s: peer_features:x%x", __func__, peer_features); + LOG_VERBOSE("%s: peer_features:x%x", __func__, peer_features); return peer_features; } @@ -1781,42 +1918,43 @@ tBTA_AV_FEAT bta_avk_check_peer_features(uint16_t service_uuid) { tBTA_AV_FEAT peer_features = 0; tBTA_AV_CB* p_cb = &bta_av_cb; - APPL_TRACE_DEBUG("%s: service_uuid:x%x", __func__, service_uuid); + LOG_VERBOSE("%s: service_uuid:x%x", __func__, service_uuid); /* loop through all records we found */ - tSDP_DISC_REC* p_rec = - SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, NULL); + tSDP_DISC_REC* p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, service_uuid, NULL); while (p_rec) { - APPL_TRACE_DEBUG("%s: found Service record for x%x", __func__, - service_uuid); + LOG_VERBOSE("%s: found Service record for x%x", __func__, service_uuid); - if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != - NULL) { + if ((get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL) { /* find peer features */ - if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, - NULL)) { + if (get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL)) { peer_features |= BTA_AV_FEAT_RCCT; } - if (SDP_FindServiceInDb(p_cb->p_disc_db, - UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) { + if (get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) { peer_features |= BTA_AV_FEAT_RCTG; } } - if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { + if ((get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { /* get profile version (if failure, version parameter is not updated) */ uint16_t peer_rc_version = 0; - bool val = SDP_FindProfileVersionInRec( + bool val = get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version); - APPL_TRACE_DEBUG("%s: peer_rc_version for TG 0x%x, profile_found %d", - __func__, peer_rc_version, val); + LOG_VERBOSE("%s: peer_rc_version for TG 0x%x, profile_found %d", __func__, + peer_rc_version, val); if (peer_rc_version >= AVRC_REV_1_3) peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA); /* Get supported features */ tSDP_DISC_ATTR* p_attr = - SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES); + get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SUPPORTED_FEATURES); if (p_attr != NULL && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -1845,9 +1983,10 @@ tBTA_AV_FEAT bta_avk_check_peer_features(uint16_t service_uuid) { } } /* get next record; if none found, we're done */ - p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, service_uuid, p_rec); } - APPL_TRACE_DEBUG("%s: peer_features:x%x", __func__, peer_features); + LOG_VERBOSE("%s: peer_features:x%x", __func__, peer_features); return peer_features; } @@ -1863,15 +2002,15 @@ tBTA_AV_FEAT bta_avk_check_peer_features(uint16_t service_uuid) { * *****************************************************************************/ uint16_t bta_avk_get_cover_art_psm() { - APPL_TRACE_DEBUG("%s: searching for cover art psm", __func__); + LOG_VERBOSE("%s: searching for cover art psm", __func__); /* Cover Art L2CAP PSM is only available on a target device */ tBTA_AV_CB* p_cb = &bta_av_cb; - tSDP_DISC_REC* p_rec = - SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, - NULL); + tSDP_DISC_REC* p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL); while (p_rec) { tSDP_DISC_ATTR* p_attr = - (SDP_FindAttributeInRec(p_rec, ATTR_ID_ADDITION_PROTO_DESC_LISTS)); + (get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_ADDITION_PROTO_DESC_LISTS)); /* * If we have the Additional Protocol Description Lists attribute then we * specifically want the list that is an L2CAP protocol leading to OBEX. @@ -1935,7 +2074,7 @@ uint16_t bta_avk_get_cover_art_psm() { } // If this protocol has l2cap and obex then we're found the BIP PSM if (protocol_has_l2cap && protocol_has_obex) { - APPL_TRACE_DEBUG("%s: found psm 0x%x", __func__, psm); + LOG_VERBOSE("%s: found psm 0x%x", __func__, psm); return psm; } p_protocol = p_protocol->p_next_attr; // next protocol element @@ -1945,14 +2084,197 @@ uint16_t bta_avk_get_cover_art_psm() { } } /* get next record; if none found, we're done */ - p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, - UUID_SERVCLASS_AV_REM_CTRL_TARGET, p_rec); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, p_rec); } /* L2CAP PSM range is 0x1000-0xFFFF so 0x0000 is safe default invalid */ - APPL_TRACE_DEBUG("%s: could not find a BIP psm", __func__); + LOG_VERBOSE("%s: could not find a BIP psm", __func__); return 0x0000; } +void bta_av_rc_disc_done_all(UNUSED_ATTR tBTA_AV_DATA* p_data) { + tBTA_AV_CB* p_cb = &bta_av_cb; + tBTA_AV_SCB* p_scb = NULL; + tBTA_AV_LCB* p_lcb; + uint8_t rc_handle = BTA_AV_RC_HANDLE_NONE; + tBTA_AV_FEAT peer_tg_features = 0; + tBTA_AV_FEAT peer_ct_features = 0; + uint16_t cover_art_psm = 0x0000; + + LOG_VERBOSE("%s: bta_av_rc_disc_done disc:x%x", __func__, p_cb->disc); + if (!p_cb->disc) { + return; + } + + if ((p_cb->disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) { + /* this is the rc handle/index to tBTA_AV_RCB */ + rc_handle = p_cb->disc & (~BTA_AV_CHNL_MSK); + LOG_ERROR("%s: WRONG MASK A2dp not connect", __func__); + } else { + /* Validate array index*/ + if (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS) { + LOG_VERBOSE("%s: wrong data bta_av_rc_disc_done disc:x%x", __func__, + p_cb->disc); + p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1]; + } + if (p_scb) { + rc_handle = p_scb->rc_handle; + } else { + p_cb->disc = 0; + return; + } + } + + LOG_VERBOSE("%s: rc_handle %d", __func__, rc_handle); + if (p_cb->sdp_a2dp_snk_handle) { + /* This is Sink + CT + TG(Abs Vol) */ + peer_tg_features = + bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET); + LOG_VERBOSE("%s: populating rem ctrl target features %d", __func__, + peer_tg_features); + if (BTA_AV_FEAT_ADV_CTRL & + bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL)) + peer_tg_features |= (BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCCT); + + if (peer_tg_features & BTA_AV_FEAT_COVER_ARTWORK) + cover_art_psm = bta_avk_get_cover_art_psm(); + + LOG_VERBOSE("%s: populating rem ctrl target bip psm 0x%x", __func__, + cover_art_psm); + } else if (p_cb->sdp_a2dp_handle) { + /* check peer version and whether support CT and TG role */ + peer_ct_features = + bta_av_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL); + if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && + ((peer_ct_features & BTA_AV_FEAT_ADV_CTRL) == 0)) { + /* if we support advance control and peer does not, check their support on + * TG role + * some implementation uses 1.3 on CT ans 1.4 on TG */ + peer_ct_features |= + bta_av_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET); + } + + /* Change our features if the remote AVRCP version is 1.3 or less */ + tSDP_DISC_REC* p_rec = nullptr; + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, p_rec); + if (p_rec != NULL && + get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_BT_PROFILE_DESC_LIST) != NULL) { + /* get profile version (if failure, version parameter is not updated) */ + uint16_t peer_rc_version = 0xFFFF; // Don't change the AVRCP version + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version); + if (peer_rc_version <= AVRC_REV_1_3) { + LOG_VERBOSE("%s: Using AVRCP 1.3 Capabilities with remote device", + __func__); + p_bta_av_cfg = &bta_av_cfg_compatibility; + } + } + } + + p_cb->disc = 0; + osi_free_and_reset((void**)&p_cb->p_disc_db); + p_cb->rc_feature.peer_ct_features = peer_ct_features; + p_cb->rc_feature.peer_tg_features = peer_tg_features; + p_cb->rc_feature.rc_handle = rc_handle; + if (p_scb) p_cb->rc_feature.peer_addr = p_scb->PeerAddress(); + + LOG_VERBOSE("peer_tg_features 0x%x, peer_ct_features 0x%x, features 0x%x", + peer_tg_features, peer_ct_features, p_cb->features); + + /* if we have no rc connection */ + if (rc_handle == BTA_AV_RC_HANDLE_NONE) { + if (p_scb) { + /* if peer remote control service matches ours and USE_RC is true */ + if ((((p_cb->features & BTA_AV_FEAT_RCCT) && + (peer_tg_features & BTA_AV_FEAT_RCTG)) || + ((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); + 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; + p_cb->rcb[rc_handle].peer_features = 0; + p_cb->rcb[rc_handle].cover_art_psm = cover_art_psm; + } else { + /* cannot create valid rc_handle for current device. report failure + */ + LOG_ERROR("%s: no link resources available", __func__); + p_scb->use_rc = false; + tBTA_AV bta_av_data = { + .rc_open = + { + .peer_addr = p_scb->PeerAddress(), + .status = BTA_AV_FAIL_RESOURCES, + }, + }; + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, &bta_av_data); + } + } else { + LOG_ERROR("%s: can not find LCB!!", __func__); + } + } else if (p_scb->use_rc) { + /* can not find AVRC on peer device. report failure */ + p_scb->use_rc = false; + tBTA_AV bta_av_data = { + .rc_open = + { + .peer_ct_features = peer_ct_features, + .peer_tg_features = peer_tg_features, + .peer_addr = p_scb->PeerAddress(), + .status = BTA_AV_FAIL_SDP, + }, + }; + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, &bta_av_data); + } + } + } else { + p_cb->rcb[rc_handle].peer_ct_features = peer_ct_features; + p_cb->rcb[rc_handle].peer_tg_features = peer_tg_features; + p_cb->rcb[rc_handle].peer_features = 0; + + RawAddress peer_addr = RawAddress::kEmpty; + if (p_scb == NULL) { + /* + * In case scb is not created by the time we are done with SDP + * we still need to send RC feature event. So we need to get BD + * from Message. Note that lidx is 1 based not 0 based + */ + if (p_cb->rcb[rc_handle].lidx > 0) + peer_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx - 1].addr; + else + peer_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx].addr; + } else { + peer_addr = p_scb->PeerAddress(); + } + + tBTA_AV bta_av_feat = {.rc_feat = { + .rc_handle = rc_handle, + .peer_ct_features = peer_ct_features, + .peer_tg_features = peer_tg_features, + .peer_addr = peer_addr, + }}; + (*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, &bta_av_feat); + + // Send PSM data + LOG_VERBOSE("%s: Send PSM data. rc_psm = %#x", __func__, cover_art_psm); + p_cb->rcb[rc_handle].cover_art_psm = cover_art_psm; + tBTA_AV bta_av_psm = { + .rc_cover_art_psm = + { + .rc_handle = rc_handle, + .cover_art_psm = cover_art_psm, + .peer_addr = peer_addr, + }, + }; + (*p_cb->p_cback)(BTA_AV_RC_PSM_EVT, &bta_av_psm); + } +} + /******************************************************************************* * * Function bta_av_rc_disc_done @@ -1971,7 +2293,12 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { tBTA_AV_FEAT peer_features = 0; /* peer features mask */ uint16_t cover_art_psm = 0x0000; - APPL_TRACE_DEBUG("%s: bta_av_rc_disc_done disc:x%x", __func__, p_cb->disc); + if (btif_av_both_enable()) { + bta_av_rc_disc_done_all(p_data); + return; + } + + LOG_VERBOSE("%s: bta_av_rc_disc_done disc:x%x", __func__, p_cb->disc); if (!p_cb->disc) { return; } @@ -1992,13 +2319,13 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { } } - APPL_TRACE_DEBUG("%s: rc_handle %d", __func__, rc_handle); + LOG_VERBOSE("%s: rc_handle %d", __func__, rc_handle); if (p_cb->sdp_a2dp_snk_handle) { /* This is Sink + CT + TG(Abs Vol) */ peer_features = bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET); - APPL_TRACE_DEBUG("%s: populating rem ctrl target features %d", __func__, - peer_features); + LOG_VERBOSE("%s: populating rem ctrl target features %d", __func__, + peer_features); if (BTA_AV_FEAT_ADV_CTRL & bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL)) peer_features |= (BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCCT); @@ -2006,8 +2333,8 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { if (peer_features & BTA_AV_FEAT_COVER_ARTWORK) cover_art_psm = bta_avk_get_cover_art_psm(); - APPL_TRACE_DEBUG("%s: populating rem ctrl target bip psm 0x%x", __func__, - cover_art_psm); + LOG_VERBOSE("%s: populating rem ctrl target bip psm 0x%x", __func__, + cover_art_psm); } else if (p_cb->sdp_a2dp_handle) { /* check peer version and whether support CT and TG role */ peer_features = @@ -2023,17 +2350,18 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { /* Change our features if the remote AVRCP version is 1.3 or less */ tSDP_DISC_REC* p_rec = nullptr; - p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, - UUID_SERVCLASS_AV_REMOTE_CONTROL, p_rec); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, p_rec); if (p_rec != NULL && - SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST) != NULL) { + get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_BT_PROFILE_DESC_LIST) != NULL) { /* get profile version (if failure, version parameter is not updated) */ uint16_t peer_rc_version = 0xFFFF; // Don't change the AVRCP version - SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, - &peer_rc_version); + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version); if (peer_rc_version <= AVRC_REV_1_3) { - APPL_TRACE_DEBUG("%s: Using AVRCP 1.3 Capabilities with remote device", - __func__); + LOG_VERBOSE("%s: Using AVRCP 1.3 Capabilities with remote device", + __func__); p_bta_av_cfg = &bta_av_cfg_compatibility; } } @@ -2044,8 +2372,8 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { p_cb->disc = 0; osi_free_and_reset((void**)&p_cb->p_disc_db); - APPL_TRACE_DEBUG("%s: peer_features 0x%x, features 0x%x", __func__, - peer_features, p_cb->features); + LOG_VERBOSE("%s: peer_features 0x%x, features 0x%x", __func__, peer_features, + p_cb->features); /* if we have no rc connection */ if (rc_handle == BTA_AV_RC_HANDLE_NONE) { @@ -2065,7 +2393,7 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { } else { /* cannot create valid rc_handle for current device. report failure */ - APPL_TRACE_ERROR("%s: no link resources available", __func__); + LOG_ERROR("%s: no link resources available", __func__); p_scb->use_rc = false; tBTA_AV_RC_OPEN rc_open; rc_open.peer_addr = p_scb->PeerAddress(); @@ -2077,7 +2405,7 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, &bta_av_data); } } else { - APPL_TRACE_ERROR("%s: can not find LCB!!", __func__); + LOG_ERROR("%s: can not find LCB!!", __func__); } } else if (p_scb->use_rc) { /* can not find AVRC on peer device. report failure */ @@ -2124,7 +2452,7 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { IOT_CONF_BYTE_NUM_2); // Send PSM data - APPL_TRACE_DEBUG("%s: Send PSM data", __func__); + LOG_VERBOSE("%s: Send PSM data", __func__); tBTA_AV_RC_PSM rc_psm; p_cb->rcb[rc_handle].cover_art_psm = cover_art_psm; rc_psm.rc_handle = rc_handle; @@ -2135,7 +2463,7 @@ void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) { rc_psm.peer_addr = p_scb->PeerAddress(); } - APPL_TRACE_DEBUG("%s: rc_psm = 0x%x", __func__, rc_psm.cover_art_psm); + LOG_VERBOSE("%s: rc_psm = 0x%x", __func__, rc_psm.cover_art_psm); tBTA_AV bta_av_psm; bta_av_psm.rc_cover_art_psm = rc_psm; @@ -2163,19 +2491,34 @@ void bta_av_rc_closed(tBTA_AV_DATA* p_data) { tBTA_AV_LCB* p_lcb; rc_close.rc_handle = BTA_AV_RC_HANDLE_NONE; + rc_close.peer_addr = RawAddress::kEmpty; p_scb = NULL; - APPL_TRACE_DEBUG("%s: rc_handle:%d", __func__, p_msg->handle); + LOG_VERBOSE("%s: rc_handle:%d, address:%s", __func__, p_msg->handle, + ADDRESS_TO_LOGGABLE_CSTR(p_msg->peer_addr)); for (i = 0; i < BTA_AV_NUM_RCB; i++) { p_rcb = &p_cb->rcb[i]; - APPL_TRACE_DEBUG("%s: rcb[%d] rc_handle:%d, status=0x%x", __func__, i, - p_rcb->handle, p_rcb->status); + LOG_VERBOSE("%s: rcb[%d] rc_handle:%d, status=0x%x, shdl:%d, lidx:%d", + __func__, i, p_rcb->handle, p_rcb->status, p_rcb->shdl, + p_rcb->lidx); if (p_rcb->handle == p_msg->handle) { + if (btif_av_src_sink_coexist_enabled() && p_rcb->shdl && + (p_rcb->shdl - 1) < BTA_AV_NUM_STRS) { + p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; + if (p_scb && !(p_scb->PeerAddress() == p_msg->peer_addr)) { + LOG_VERBOSE("%s: handle%d %s error p_scb or addr", __func__, i, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress())); + conn = true; + continue; + } + } rc_close.rc_handle = i; p_rcb->status &= ~BTA_AV_RC_CONN_MASK; p_rcb->peer_features = 0; p_rcb->cover_art_psm = 0; - APPL_TRACE_DEBUG("%s: shdl:%d, lidx:%d", __func__, p_rcb->shdl, - p_rcb->lidx); + p_rcb->peer_ct_features = 0; + p_rcb->peer_tg_features = 0; + p_cb->rc_feature = {}; + LOG_VERBOSE("%s: shdl:%d, lidx:%d", __func__, p_rcb->shdl, p_rcb->lidx); if (p_rcb->shdl) { if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) { p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; @@ -2184,8 +2527,8 @@ void bta_av_rc_closed(tBTA_AV_DATA* p_data) { rc_close.peer_addr = p_scb->PeerAddress(); if (p_scb->rc_handle == p_rcb->handle) p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE; - APPL_TRACE_DEBUG("%s: shdl:%d, srch:%d", __func__, p_rcb->shdl, - p_scb->rc_handle); + LOG_VERBOSE("%s: shdl:%d, srch:%d", __func__, p_rcb->shdl, + p_scb->rc_handle); } p_rcb->shdl = 0; } else if (p_rcb->lidx == (BTA_AV_NUM_LINKS + 1)) { @@ -2303,8 +2646,8 @@ void bta_av_rc_disc(uint8_t disc) { RawAddress peer_addr = RawAddress::kEmpty; uint8_t rc_handle; - APPL_TRACE_DEBUG("%s: disc: 0x%x, bta_av_cb.disc: 0x%x", __func__, disc, - bta_av_cb.disc); + LOG_VERBOSE("%s: disc: 0x%x, bta_av_cb.disc: 0x%x", __func__, disc, + bta_av_cb.disc); if ((bta_av_cb.disc != 0) || (disc == 0)) return; if ((disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) { @@ -2318,7 +2661,7 @@ void bta_av_rc_disc(uint8_t disc) { p_scb = p_cb->p_scb[hdi]; if (p_scb) { - APPL_TRACE_DEBUG("%s: rc_handle %d", __func__, p_scb->rc_handle); + LOG_VERBOSE("%s: rc_handle %d", __func__, p_scb->rc_handle); peer_addr = p_scb->PeerAddress(); } } @@ -2339,7 +2682,7 @@ void bta_av_rc_disc(uint8_t disc) { &db_params, base::Bind(bta_av_avrc_sdp_cback)) == AVRC_SUCCESS) { p_cb->disc = disc; - APPL_TRACE_DEBUG("%s: disc 0x%x", __func__, p_cb->disc); + LOG_VERBOSE("%s: disc 0x%x", __func__, p_cb->disc); } } } @@ -2369,8 +2712,7 @@ void bta_av_dereg_comp(tBTA_AV_DATA* p_data) { p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific); if (p_scb) { - APPL_TRACE_DEBUG("%s: deregistered %d(h%d)", __func__, p_scb->chnl, - p_scb->hndl); + LOG_VERBOSE("%s: deregistered %d(h%d)", __func__, p_scb->chnl, p_scb->hndl); mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi); p_cb->reg_audio &= ~mask; if ((p_cb->conn_audio & mask) && p_cb->audio_open_cnt) { @@ -2390,14 +2732,14 @@ void bta_av_dereg_comp(tBTA_AV_DATA* p_data) { /* remove the A2DP SDP record, if no more audio stream is left */ if (!p_cb->reg_audio) { - /* Only remove the SDP record if we're the ones that created it */ if (is_new_avrcp_enabled()) { - APPL_TRACE_DEBUG("%s: newavrcp is the owner of the AVRCP Target SDP " - "record. Don't dereg the SDP record", __func__); - } else { - APPL_TRACE_DEBUG("%s: newavrcp is not enabled. Remove SDP record", + LOG_VERBOSE( + "%s: newavrcp is the owner of the AVRCP Target SDP " + "record. Don't dereg the SDP record", __func__); + } else { + LOG_VERBOSE("%s: newavrcp is not enabled. Remove SDP record", __func__); bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL); } @@ -2417,8 +2759,8 @@ void bta_av_dereg_comp(tBTA_AV_DATA* p_data) { bta_av_free_scb(p_scb); } - APPL_TRACE_DEBUG("%s: audio 0x%x, disable:%d", __func__, p_cb->reg_audio, - p_cb->disabling); + LOG_VERBOSE("%s: audio 0x%x, disable:%d", __func__, p_cb->reg_audio, + p_cb->disabling); /* if no stream control block is active */ if (p_cb->reg_audio == 0) { /* deregister from AVDT */ @@ -2433,6 +2775,8 @@ void bta_av_dereg_comp(tBTA_AV_DATA* p_data) { // reset enabling parameters p_cb->features = 0; p_cb->sec_mask = 0; + bta_av_cb.sink_features = 0; + bta_av_cb.reg_role = 0; } /* Clear the Capturing service class bit */ diff --git a/system/bta/av/bta_av_api.cc b/system/bta/av/bta_av_api.cc index af5469ea072dfef41b94bee1802a89123226776b..8c99211c215cf108d8aa92aceb94676db48ab16a 100644 --- a/system/bta/av/bta_av_api.cc +++ b/system/bta/av/bta_av_api.cc @@ -28,10 +28,12 @@ #include "bt_target.h" // Must be first to define build configuration #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 "osi/include/log.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_uuid16.h" #include "types/raw_address.h" /***************************************************************************** @@ -161,6 +163,17 @@ void BTA_AvOpen(const RawAddress& bd_addr, tBTA_AV_HNDL handle, bool use_rc, p_buf->use_rc = use_rc; p_buf->switch_res = BTA_AV_RS_NONE; p_buf->uuid = uuid; + if (btif_av_src_sink_coexist_enabled()) { + if (p_buf->uuid == AVDT_TSEP_SRC) { + p_buf->uuid = UUID_SERVCLASS_AUDIO_SOURCE; + p_buf->incoming = TRUE; + } else if (p_buf->uuid == AVDT_TSEP_SNK) { + p_buf->uuid = UUID_SERVCLASS_AUDIO_SINK; + p_buf->incoming = TRUE; + } else { + p_buf->incoming = FALSE; + } + } bta_sys_sendmsg(p_buf); } @@ -640,3 +653,25 @@ void BTA_AvSetLatency(tBTA_AV_HNDL handle, bool is_low_latency) { bta_sys_sendmsg(p_buf); } + +/******************************************************************************* + * + * Function BTA_AvSetPeerSep + * + * Description Set peer sep in order to delete wrong avrcp handle + * there are may be two avrcp handle at start, delete the + * wrong when a2dp connected + * + * Returns void + * + ******************************************************************************/ +void BTA_AvSetPeerSep(const RawAddress& bdaddr, uint8_t sep) { + tBTA_AV_API_PEER_SEP* p_buf = + (tBTA_AV_API_PEER_SEP*)osi_malloc(sizeof(tBTA_AV_API_PEER_SEP)); + + p_buf->hdr.event = BTA_AV_API_PEER_SEP_EVT; + p_buf->addr = bdaddr; + p_buf->sep = sep; + + bta_sys_sendmsg(p_buf); +} diff --git a/system/bta/av/bta_av_cfg.cc b/system/bta/av/bta_av_cfg.cc index bebd05e412d918fde23f26a23335ea565e332cfb..077b8d17e42f429c58083d1ac8e1ba092cc26ff9 100644 --- a/system/bta/av/bta_av_cfg.cc +++ b/system/bta/av/bta_av_cfg.cc @@ -42,10 +42,11 @@ const uint32_t bta_av_meta_caps_co_ids[] = {AVRC_CO_METADATA, AVRC_CO_BROADCOM}; /* AVRCP supported categories */ #define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2) -#define BTA_AVK_RC_SUPF_CT (AVRC_SUPF_CT_CAT1 | \ - AVRC_SUPF_CT_BROWSE | \ - AVRC_SUPF_CT_COVER_ART_GET_IMAGE_PROP | \ - AVRC_SUPF_CT_COVER_ART_GET_IMAGE) +#define BTA_AVK_RC_SUPF_CT \ + (AVRC_SUPF_CT_CAT1 | AVRC_SUPF_CT_BROWSE | \ + AVRC_SUPF_CT_COVER_ART_GET_IMAGE_PROP | AVRC_SUPF_CT_COVER_ART_GET_IMAGE) +#define BTA_AVK_RC_SUPF_CT_V15 (AVRC_SUPF_CT_CAT1 | AVRC_SUPF_CT_BROWSE) + #define BTA_AVK_RC_SUPF_TG (AVRC_SUPF_TG_CAT2) /* AVRCP Controller and Targer default name */ @@ -117,7 +118,8 @@ const uint8_t bta_av_meta_caps_evt_ids_avrcp13[] = { /* This configuration to be used when we are Src + TG + CT( only for abs vol) */ extern const tBTA_AV_CFG bta_av_cfg = { - BTA_AV_RC_COMP_ID, /* AVRCP Company ID */ + AVRC_CO_METADATA, /* AVRCP Company ID */ + BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */ BTA_AV_RC_SUPF_TG, /* AVRCP target categories */ 6, /* AVDTP audio channel max data queue size */ @@ -139,10 +141,10 @@ extern const tBTA_AV_CFG bta_av_cfg = { const tBTA_AV_CFG* get_bta_avk_cfg() { static const tBTA_AV_CFG bta_avk_cfg = { - AVRC_CO_METADATA, /* AVRCP Company ID */ - BTA_AVK_RC_SUPF_CT, /* AVRCP controller categories */ - BTA_AVK_RC_SUPF_TG, /* AVRCP target categories */ - 6, /* AVDTP audio channel max data queue size */ + AVRC_CO_METADATA, /* AVRCP Company ID */ + BTA_AVK_RC_SUPF_CT_V15, /* AVRCP controller categories */ + BTA_AVK_RC_SUPF_TG, /* AVRCP target categories */ + 6, /* AVDTP audio channel max data queue size */ false, /* true, to accept AVRC 1.3 group nevigation command */ 2, /* company id count in p_meta_co_ids */ (uint8_t)(avrcp_absolute_volume_is_enabled() @@ -162,7 +164,8 @@ const tBTA_AV_CFG* get_bta_avk_cfg() { /* This configuration to be used when we are using AVRCP1.3 */ extern const tBTA_AV_CFG bta_av_cfg_compatibility = { - BTA_AV_RC_COMP_ID, /* AVRCP Company ID */ + AVRC_CO_METADATA, /* AVRCP Company ID */ + BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */ AVRC_SUPF_TG_CAT1, /* Only support CAT1 for AVRCP1.3 */ 6, /* AVDTP audio channel max data queue size */ diff --git a/system/bta/av/bta_av_int.h b/system/bta/av/bta_av_int.h index 997aa9b0c589c3f3c142a458c142f3768d7c3b0c..41637c4b0423b6134ecbb07c01b0cbbd8c82320a 100644 --- a/system/bta/av/bta_av_int.h +++ b/system/bta/av/bta_av_int.h @@ -27,20 +27,21 @@ #include #include -#include "bta/av/bta_av_int.h" #include "bta/include/bta_av_api.h" -#include "bta/include/bta_av_co.h" +#include "bta/include/bta_sec_api.h" #include "bta/sys/bta_sys.h" +#include "include/hardware/bt_av.h" +#include "internal_include/bt_target.h" +#include "macros.h" #include "osi/include/list.h" +#include "stack/include/a2dp_error_codes.h" #include "stack/include/avdt_api.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" +#include "stack/include/hci_error_code.h" +#include "stack/sdp/sdp_discovery_db.h" +#include "types/hci_role.h" #include "types/raw_address.h" -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - /***************************************************************************** * Constants ****************************************************************************/ @@ -112,6 +113,7 @@ enum { BTA_AV_CONN_CHG_EVT, BTA_AV_DEREG_COMP_EVT, BTA_AV_AVDT_RPT_CONN_EVT, + BTA_AV_API_PEER_SEP_EVT, BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as the *AP_*EVT */ BTA_AV_API_STOP_EVT, @@ -263,6 +265,7 @@ typedef struct { bool use_rc; tBTA_AV_RS_RES switch_res; uint16_t uuid; /* uuid of initiator */ + bool incoming; /* peer launch connection */ } tBTA_AV_API_OPEN; /* data type for BTA_AV_API_SET_LATENCY_EVT */ @@ -398,8 +401,8 @@ typedef struct { /* data type for BTA_AV_ROLE_CHANGE_EVT */ typedef struct { BT_HDR_RIGID hdr; - uint8_t new_role; - uint8_t hci_status; + tHCI_ROLE new_role; + tHCI_STATUS hci_status; } tBTA_AV_ROLE_RES; /* data type for BTA_AV_SDP_DISC_OK_EVT */ @@ -436,6 +439,12 @@ enum : uint8_t { }; typedef uint8_t tBTA_AV_ROLE; +typedef struct { + BT_HDR_RIGID hdr; + RawAddress addr; + uint8_t sep; +} tBTA_AV_API_PEER_SEP; + /* union of all event datatypes */ union tBTA_AV_DATA { BT_HDR_RIGID hdr; @@ -460,6 +469,7 @@ union tBTA_AV_DATA { tBTA_AV_SDP_RES sdp_res; tBTA_AV_API_META_RSP api_meta_rsp; tBTA_AV_API_STATUS_RSP api_status_rsp; + tBTA_AV_API_PEER_SEP peer_sep; }; typedef union { @@ -612,6 +622,8 @@ typedef struct { uint8_t lidx; /* (index+1) to LCB */ tBTA_AV_FEAT peer_features; /* peer features mask */ uint16_t cover_art_psm; /* BIP PSM for cover art feature */ + tBTA_AV_FEAT peer_ct_features; + tBTA_AV_FEAT peer_tg_features; } tBTA_AV_RCB; #define BTA_AV_NUM_RCB (BTA_AV_NUM_STRS + 2) @@ -654,6 +666,9 @@ typedef struct { bool sco_occupied; /* true if SCO is being used or call is in progress */ uint16_t offload_start_pending_hndl; uint16_t offload_started_hndl; + tBTA_AV_FEAT sink_features; /* sink features */ + uint8_t reg_role; /* bit0-src, bit1-sink */ + tBTA_AV_RC_FEAT rc_feature; /* save peer rc feature */ } tBTA_AV_CB; // total attempts are half seconds @@ -730,7 +745,7 @@ void bta_av_dup_audio_buf(tBTA_AV_SCB* p_scb, BT_HDR* p_buf); void bta_av_sm_execute(tBTA_AV_CB* p_cb, uint16_t event, tBTA_AV_DATA* p_data); void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event, tBTA_AV_DATA* p_data); -bool bta_av_hdl_event(BT_HDR_RIGID* p_msg); +bool bta_av_hdl_event(const BT_HDR_RIGID* p_msg); const char* bta_av_evt_code(uint16_t evt_code); bool bta_av_switch_if_needed(tBTA_AV_SCB* p_scb); bool bta_av_link_role_ok(tBTA_AV_SCB* p_scb, uint8_t bits); @@ -822,5 +837,6 @@ void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data); void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data); void bta_av_vendor_offload_stop(void); void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data); +void bta_av_api_set_peer_sep(tBTA_AV_DATA* p_data); #endif /* BTA_AV_INT_H */ diff --git a/system/bta/av/bta_av_main.cc b/system/bta/av/bta_av_main.cc index f646da3161f2718e4213142256e576013edc8e54..30dbbbde320c4b420acb4862d0fb792ab6a296ff 100644 --- a/system/bta/av/bta_av_main.cc +++ b/system/bta/av/bta_av_main.cc @@ -24,27 +24,33 @@ #define LOG_TAG "bt_bta_av" +#include + #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/av/bta_av_int.h" #include "bta/include/bta_ar_api.h" +#include "bta/include/bta_av_co.h" #include "bta/include/utl.h" +#include "bta/sys/bta_sys.h" #include "btif/avrcp/avrcp_service.h" +#include "btif/include/btif_av.h" #include "btif/include/btif_av_co.h" #include "btif/include/btif_config.h" -#include "main/shim/dumpsys.h" +#include "gd/os/log.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "osi/include/properties.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_api.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/hci_error_code.h" +#include "stack/include/sdp_api.h" #include "types/hci_role.h" #include "types/raw_address.h" -#include +using namespace bluetooth::legacy::stack::sdp; /***************************************************************************** * Constants and types @@ -101,10 +107,12 @@ static void bta_av_ci_data(tBTA_AV_DATA* p_data); static void bta_av_rpc_conn(tBTA_AV_DATA* p_data); static void bta_av_api_to_ssm(tBTA_AV_DATA* p_data); -static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, - uint8_t app_id, const RawAddress& peer_addr); -static void bta_av_sys_rs_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, - uint8_t app_id, const RawAddress& peer_addr); +static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, + uint8_t num_sco_links, uint8_t app_id, + const RawAddress& peer_addr); +static void bta_av_sys_rs_cback(tBTA_SYS_CONN_STATUS status, tHCI_ROLE new_role, + tHCI_STATUS hci_status, + const RawAddress& peer_addr); /***************************************************************************** * Global data @@ -126,10 +134,27 @@ static const char* bta_av_st_code(uint8_t state); * ******************************************************************************/ static void bta_av_api_enable(tBTA_AV_DATA* p_data) { + if (btif_av_src_sink_coexist_enabled() && bta_av_cb.features != 0) { + tBTA_AV_ENABLE enable; + tBTA_AV bta_av_data; + bta_av_cb.sink_features = p_data->api_enable.features; + + enable.features = p_data->api_enable.features; + bta_av_data.enable = enable; + (*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, &bta_av_data); + + /* if this is source feature, then exchange them */ + if (p_data->api_enable.features & BTA_AV_FEAT_SRC) { + tBTA_AV_FEAT tmp_feature = bta_av_cb.features; + bta_av_cb.features = bta_av_cb.sink_features; + bta_av_cb.sink_features = tmp_feature; + } + return; + } + if (bta_av_cb.disabling) { - APPL_TRACE_WARNING( - "%s: previous (reg_audio=%#x) is still disabling (attempts=%d)", - __func__, bta_av_cb.reg_audio, bta_av_cb.enabling_attempts); + LOG_WARN("%s: previous (reg_audio=%#x) is still disabling (attempts=%d)", + __func__, bta_av_cb.reg_audio, bta_av_cb.enabling_attempts); if (++bta_av_cb.enabling_attempts <= kEnablingAttemptsCountMaximum) { tBTA_AV_API_ENABLE* p_buf = (tBTA_AV_API_ENABLE*)osi_malloc(sizeof(tBTA_AV_API_ENABLE)); @@ -143,11 +168,13 @@ static void bta_av_api_enable(tBTA_AV_DATA* p_data) { return; } if (bta_av_cb.sdp_a2dp_handle) { - SDP_DeleteRecord(bta_av_cb.sdp_a2dp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + bta_av_cb.sdp_a2dp_handle); bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE); } if (bta_av_cb.sdp_a2dp_snk_handle) { - SDP_DeleteRecord(bta_av_cb.sdp_a2dp_snk_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + bta_av_cb.sdp_a2dp_snk_handle); bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK); } // deregister from AVDT @@ -209,6 +236,7 @@ tBTA_AV_SCB* bta_av_addr_to_scb(const RawAddress& bd_addr) { return p_scb; } +extern const RawAddress& btif_av_find_by_handle(tBTA_AV_HNDL bta_handle); int BTA_AvObtainPeerChannelIndex(const RawAddress& peer_address) { // Find the entry for the peer (if exists) tBTA_AV_SCB* p_scb = bta_av_addr_to_scb(peer_address); @@ -223,6 +251,12 @@ int BTA_AvObtainPeerChannelIndex(const RawAddress& peer_address) { continue; } if (p_scb->PeerAddress().IsEmpty()) { + const RawAddress& btif_addr = btif_av_find_by_handle(p_scb->hndl); + if (!btif_addr.IsEmpty() && btif_addr != peer_address) { + LOG_VERBOSE("%s: btif_addr = %s, index=%d!", __func__, + btif_addr.ToString().c_str(), index); + continue; + } return p_scb->hdi; } } @@ -263,7 +297,7 @@ tBTA_AV_SCB* bta_av_hndl_to_scb(uint16_t handle) { ******************************************************************************/ static tBTA_AV_SCB* bta_av_alloc_scb(tBTA_AV_CHNL chnl) { if (chnl != BTA_AV_CHNL_AUDIO) { - APPL_TRACE_ERROR("%s: bad channel: %d", __func__, chnl); + LOG_ERROR("%s: bad channel: %d", __func__, chnl); return nullptr; } @@ -286,6 +320,24 @@ static tBTA_AV_SCB* bta_av_alloc_scb(tBTA_AV_CHNL chnl) { return nullptr; } +static tBTA_AV_SCB* bta_av_find_scb(tBTA_AV_CHNL chnl, uint8_t app_id) { + if (chnl != BTA_AV_CHNL_AUDIO) { + LOG_ERROR("%s: bad channel: %d", __func__, chnl); + return nullptr; + } + + for (int xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + if ((bta_av_cb.p_scb[xx] != nullptr) && + (bta_av_cb.p_scb[xx]->chnl == chnl) && + (bta_av_cb.p_scb[xx]->app_id == app_id)) { + LOG_VERBOSE("%s: found at: %d", __func__, xx); + return bta_av_cb.p_scb[xx]; + } + } + + return nullptr; +} + void bta_av_free_scb(tBTA_AV_SCB* p_scb) { if (p_scb == nullptr) return; uint8_t scb_index = p_scb->hdi; @@ -294,6 +346,8 @@ void bta_av_free_scb(tBTA_AV_SCB* p_scb) { CHECK(p_scb == bta_av_cb.p_scb[scb_index]); bta_av_cb.p_scb[scb_index] = nullptr; alarm_free(p_scb->avrc_ct_timer); + list_free(p_scb->a2dp_list); + p_scb->a2dp_list = NULL; // TODO: After tBTA_AV_SCB is changed to a proper class, the entry // here should be de-allocated by C++ 'delete' statement. osi_free(p_scb); @@ -345,8 +399,7 @@ void bta_av_conn_cback(UNUSED_ATTR uint8_t handle, const RawAddress& bd_addr, if (event == AVDT_DISCONNECT_IND_EVT) { p_scb = bta_av_addr_to_scb(bd_addr); } else if (event == AVDT_CONNECT_IND_EVT) { - APPL_TRACE_DEBUG("%s: CONN_IND is ACP:%d", __func__, - p_data->hdr.err_param); + LOG_VERBOSE("%s: CONN_IND is ACP:%d", __func__, p_data->hdr.err_param); } tBTA_AV_STR_MSG* p_msg = @@ -357,11 +410,11 @@ void bta_av_conn_cback(UNUSED_ATTR uint8_t handle, const RawAddress& bd_addr, p_msg->bd_addr = bd_addr; p_msg->scb_index = scb_index; if (p_scb) { - APPL_TRACE_DEBUG("%s: bta_handle x%x, role x%x", __func__, p_scb->hndl, - p_scb->role); + LOG_VERBOSE("%s: bta_handle x%x, role x%x", __func__, p_scb->hndl, + p_scb->role); } - LOG_INFO("%s: conn_cback bd_addr: %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_INFO("%s: conn_cback bd_addr: %s, scb_index: %d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), scb_index); bta_sys_sendmsg(p_msg); } } @@ -394,15 +447,16 @@ static void bta_av_a2dp_report_cback(UNUSED_ATTR uint8_t handle, * ******************************************************************************/ static void bta_av_api_register(tBTA_AV_DATA* p_data) { - tBTA_AV_REGISTER registr; + tBTA_AV_REGISTER reg_data; tBTA_AV_SCB* p_scb; /* stream control block */ AvdtpRcb reg; AvdtpStreamConfig avdtp_stream_config; char* p_service_name; tBTA_UTL_COD cod; + uint8_t local_role = 0; if (bta_av_cb.disabling || (bta_av_cb.features == 0)) { - APPL_TRACE_WARNING( + LOG_WARN( "%s: AV instance (features=%#x, reg_audio=%#x) is not " "ready for app_id %d", __func__, bta_av_cb.features, bta_av_cb.reg_audio, @@ -420,10 +474,15 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { } avdtp_stream_config.Reset(); + if (btif_av_src_sink_coexist_enabled()) { + local_role = (p_data->api_reg.service_uuid == UUID_SERVCLASS_AUDIO_SINK) + ? AVDT_TSEP_SNK + : AVDT_TSEP_SRC; + } - registr.status = BTA_AV_FAIL_RESOURCES; - registr.app_id = p_data->api_reg.app_id; - registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific; + reg_data.status = BTA_AV_FAIL_RESOURCES; + reg_data.app_id = p_data->api_reg.app_id; + reg_data.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific; char avrcp_version[PROPERTY_VALUE_MAX] = {0}; osi_property_get(AVRCP_VERSION_PROPERTY, avrcp_version, @@ -442,26 +501,34 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { } } - APPL_TRACE_DEBUG("%s: profile: 0x%x", __func__, profile_initialized); + LOG_VERBOSE("%s: profile: 0x%x", __func__, profile_initialized); if (p_bta_av_cfg == NULL) { - APPL_TRACE_ERROR("%s: AV configuration is null!", __func__); + LOG_ERROR("%s: AV configuration is null!", __func__); return; } do { - p_scb = bta_av_alloc_scb(registr.chnl); + p_scb = nullptr; + if (btif_av_src_sink_coexist_enabled()) { + p_scb = bta_av_find_scb(reg_data.chnl, reg_data.app_id); + } + if (p_scb == nullptr) { + p_scb = bta_av_alloc_scb(reg_data.chnl); + } if (p_scb == NULL) { - APPL_TRACE_ERROR("%s: failed to alloc SCB", __func__); + LOG_ERROR("%s: failed to alloc SCB", __func__); break; } - registr.hndl = p_scb->hndl; - p_scb->app_id = registr.app_id; + reg_data.hndl = p_scb->hndl; + p_scb->app_id = reg_data.app_id; /* initialize the stream control block */ - registr.status = BTA_AV_SUCCESS; + reg_data.status = BTA_AV_SUCCESS; - if (bta_av_cb.reg_audio == 0) { + if ((btif_av_src_sink_coexist_enabled() && + !(bta_av_cb.reg_role & (1 << local_role))) || + (!btif_av_src_sink_coexist_enabled() && bta_av_cb.reg_audio == 0)) { /* the first channel registered. register to AVDTP */ reg.ctrl_mtu = 672; reg.ret_tout = BTA_AV_RET_TOUT; @@ -481,11 +548,13 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { * absolute volume. */ if (is_new_avrcp_enabled()) { - APPL_TRACE_DEBUG("%s: newavrcp is the owner of the AVRCP Target SDP " - "record. Don't create the SDP record", __func__); - } else { - APPL_TRACE_DEBUG("%s: newavrcp is not enabled. Create SDP record", + LOG_VERBOSE( + "%s: newavrcp is the owner of the AVRCP Target SDP " + "record. Don't create the SDP record", __func__); + } else { + LOG_VERBOSE("%s: newavrcp is not enabled. Create SDP record", + __func__); uint16_t profile_version = AVRC_REV_1_0; if (!strncmp(AVRCP_1_6_STRING, avrcp_version, @@ -500,11 +569,18 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { } else { profile_version = AVRC_REV_1_4; } - - bta_ar_reg_avrc( - UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL, - p_bta_av_cfg->avrc_tg_cat, - (bta_av_cb.features & BTA_AV_FEAT_BROWSE), profile_version); + if (btif_av_src_sink_coexist_enabled()) { + bta_ar_reg_avrc_for_src_sink_coexist( + UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", + NULL, p_bta_av_cfg->avrc_tg_cat, + static_cast(BTA_ID_AV + local_role), + (bta_av_cb.features & BTA_AV_FEAT_BROWSE), profile_version); + } else { + bta_ar_reg_avrc( + UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", + NULL, p_bta_av_cfg->avrc_tg_cat, + (bta_av_cb.features & BTA_AV_FEAT_BROWSE), profile_version); + } } } @@ -522,8 +598,7 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { if (!(bta_av_cb.features & BTA_AV_FEAT_PROTECT)) { avdtp_stream_config.nsc_mask |= AvdtpStreamConfig::AVDT_NSC_SECURITY; } - APPL_TRACE_DEBUG("%s: nsc_mask: 0x%x", __func__, - avdtp_stream_config.nsc_mask); + LOG_VERBOSE("%s: nsc_mask: 0x%x", __func__, avdtp_stream_config.nsc_mask); if (p_data->api_reg.p_service_name[0] == 0) { p_service_name = NULL; @@ -564,9 +639,14 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { codec_index_max = BTAV_A2DP_CODEC_INDEX_SINK_MAX; } - /* Initialize handles to zero */ - for (int xx = 0; xx < BTAV_A2DP_CODEC_INDEX_MAX; xx++) { - p_scb->seps[xx].av_handle = 0; + if (btif_av_src_sink_coexist_enabled()) { + for (int xx = codec_index_min; xx < codec_index_max; xx++) { + p_scb->seps[xx].av_handle = 0; + } + } else { + for (int xx = 0; xx < BTAV_A2DP_CODEC_INDEX_MAX; xx++) { + p_scb->seps[xx].av_handle = 0; + } } /* keep the configuration in the stream control block */ @@ -582,7 +662,7 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { } if (AVDT_CreateStream(p_scb->app_id, &p_scb->seps[codec_index].av_handle, avdtp_stream_config) != AVDT_SUCCESS) { - APPL_TRACE_WARNING( + LOG_WARN( "%s: bta_handle=0x%x (app_id %d) failed to alloc an SEP index:%d", __func__, p_scb->hndl, p_scb->app_id, codec_index); continue; @@ -601,18 +681,21 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { p_scb->seps[codec_index].p_app_sink_data_cback = NULL; } } - - if (!bta_av_cb.reg_audio) { + if ((btif_av_src_sink_coexist_enabled() && + !(bta_av_cb.reg_role & (1 << local_role))) || + (!btif_av_src_sink_coexist_enabled() && !bta_av_cb.reg_audio)) { bta_av_cb.sdp_a2dp_handle = 0; bta_av_cb.sdp_a2dp_snk_handle = 0; if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) { /* create the SDP records on the 1st audio channel */ - bta_av_cb.sdp_a2dp_handle = SDP_CreateRecord(); + bta_av_cb.sdp_a2dp_handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL, A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_handle); bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE); } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) { - bta_av_cb.sdp_a2dp_snk_handle = SDP_CreateRecord(); + bta_av_cb.sdp_a2dp_snk_handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL, A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_snk_handle); bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK); @@ -635,27 +718,58 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { * * We create 1.4 for SINK since we support browsing. */ - if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE && - !is_new_avrcp_enabled()) { - bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, - p_bta_av_cfg->avrc_ct_cat, - (bta_av_cb.features & BTA_AV_FEAT_BROWSE), - AVRC_REV_1_3); - } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) { - bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, - p_bta_av_cfg->avrc_ct_cat, - (bta_av_cb.features & BTA_AV_FEAT_BROWSE), - AVRC_REV_1_6); + if (btif_av_src_sink_coexist_enabled()) { + if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) { + bta_ar_reg_avrc_for_src_sink_coexist( + UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, + p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV, + (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_5); + } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) + bta_ar_reg_avrc_for_src_sink_coexist( + UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, + p_bta_av_cfg->avrc_ct_cat, BTA_ID_AVK, + (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_5); + } else { + if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE && + !is_new_avrcp_enabled()) { + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, + p_bta_av_cfg->avrc_ct_cat, + (bta_av_cb.features & BTA_AV_FEAT_BROWSE), + AVRC_REV_1_3); + } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, + p_bta_av_cfg->avrc_ct_cat, + (bta_av_cb.features & BTA_AV_FEAT_BROWSE), + AVRC_REV_1_6); } } } bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi); - APPL_TRACE_DEBUG("%s: reg_audio: 0x%x", __func__, bta_av_cb.reg_audio); + LOG_VERBOSE("%s: reg_audio: 0x%x", __func__, bta_av_cb.reg_audio); } while (0); + if (btif_av_src_sink_coexist_enabled()) { + bta_av_cb.reg_role |= (1 << local_role); + reg_data.peer_sep = (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) + ? AVDT_TSEP_SNK + : AVDT_TSEP_SRC; + + /* there are too much check depend on it's only source */ + if ((profile_initialized == UUID_SERVCLASS_AUDIO_SINK) && + (bta_av_cb.reg_role & (1 << AVDT_TSEP_SRC))) { + p_bta_av_cfg = &bta_av_cfg; + + if (!strncmp(AVRCP_1_3_STRING, avrcp_version, + sizeof(AVRCP_1_3_STRING))) { // ver if need + LOG_VERBOSE("%s: AVRCP 1.3 capabilites used", __func__); + p_bta_av_cfg = &bta_av_cfg_compatibility; + } + } + } + /* call callback with register event */ tBTA_AV bta_av_data; - bta_av_data.registr = registr; + bta_av_data.reg = reg_data; (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, &bta_av_data); } @@ -794,7 +908,7 @@ void bta_av_restore_switch(void) { int i; uint8_t mask; - APPL_TRACE_DEBUG("%s: reg_audio: 0x%x", __func__, bta_av_cb.reg_audio); + LOG_VERBOSE("%s: reg_audio: 0x%x", __func__, bta_av_cb.reg_audio); for (i = 0; i < BTA_AV_NUM_STRS; i++) { mask = BTA_AV_HNDL_TO_MSK(i); if (p_cb->conn_audio == mask) { @@ -816,16 +930,16 @@ void bta_av_restore_switch(void) { * ******************************************************************************/ static void bta_av_sys_rs_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, - uint8_t id, uint8_t app_id, + tHCI_ROLE new_role, tHCI_STATUS hci_status, const RawAddress& peer_addr) { int i; tBTA_AV_SCB* p_scb = NULL; tHCI_ROLE cur_role; uint8_t peer_idx = 0; - APPL_TRACE_DEBUG( - "%s: peer %s new_role:%d hci_status:0x%x bta_av_cb.rs_idx:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_addr), id, app_id, bta_av_cb.rs_idx); + LOG_VERBOSE("%s: peer %s new_role:%d hci_status:0x%x bta_av_cb.rs_idx:%d", + __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_addr), new_role, + hci_status, bta_av_cb.rs_idx); for (i = 0; i < BTA_AV_NUM_STRS; i++) { /* loop through all the SCBs to find matching peer addresses and report the @@ -835,14 +949,14 @@ static void bta_av_sys_rs_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, if (p_scb && p_scb->PeerAddress() == peer_addr) { tBTA_AV_ROLE_RES* p_buf = (tBTA_AV_ROLE_RES*)osi_malloc(sizeof(tBTA_AV_ROLE_RES)); - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer %s found: new_role:%d, hci_status:0x%x bta_handle:0x%x", - __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_addr), id, app_id, + __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_addr), new_role, hci_status, p_scb->hndl); p_buf->hdr.event = BTA_AV_ROLE_CHANGE_EVT; p_buf->hdr.layer_specific = p_scb->hndl; - p_buf->new_role = id; - p_buf->hci_status = app_id; + p_buf->new_role = new_role; + p_buf->hci_status = hci_status; bta_sys_sendmsg(p_buf); peer_idx = p_scb->hdi + 1; /* Handle index for the peer_addr */ @@ -850,7 +964,7 @@ static void bta_av_sys_rs_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, } /* restore role switch policy, if role switch failed */ - if ((HCI_SUCCESS != app_id) && + if ((HCI_SUCCESS != hci_status) && (BTM_GetRole(peer_addr, &cur_role) == BTM_SUCCESS) && (cur_role == HCI_ROLE_PERIPHERAL)) { BTM_unblock_role_switch_for(peer_addr); @@ -864,18 +978,19 @@ static void bta_av_sys_rs_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, p_scb = bta_av_cb.p_scb[bta_av_cb.rs_idx - 1]; } if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN) { - APPL_TRACE_DEBUG("%s: peer %s rs_idx:%d, bta_handle:0x%x q_tag:%d", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), - bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag); + LOG_VERBOSE("%s: peer %s rs_idx:%d, bta_handle:0x%x q_tag:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), + bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag); - if (HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id) { + if (HCI_SUCCESS == hci_status || HCI_ERR_NO_CONNECTION == hci_status) { p_scb->q_info.open.switch_res = BTA_AV_RS_OK; } else { - APPL_TRACE_ERROR( + LOG_ERROR( "%s: peer %s (p_scb peer %s) role switch failed: new_role:%d " "hci_status:0x%x", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_addr), - ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), id, app_id); + ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), new_role, + hci_status); p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL; } @@ -898,7 +1013,8 @@ static void bta_av_sys_rs_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, * Returns void * ******************************************************************************/ -static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, +static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, + uint8_t num_sco_links, UNUSED_ATTR uint8_t app_id, UNUSED_ATTR const RawAddress& peer_addr) { tBTA_AV_SCB* p_scb; @@ -906,8 +1022,8 @@ static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, tBTA_AV_API_STOP stop; LOG(INFO) << __func__ << ": status=" << bta_sys_conn_status_text(status) - << ", num_links=" << +id; - if (id) { + << ", num_links=" << +num_sco_links; + if (num_sco_links) { bta_av_cb.sco_occupied = true; LOG_DEBUG("SCO occupied peer:%s status:%s", ADDRESS_TO_LOGGABLE_CSTR(peer_addr), bta_sys_conn_status_text(status).c_str()); @@ -1145,6 +1261,9 @@ static void bta_av_non_state_machine_event(uint16_t event, case BTA_AV_API_STOP_EVT: bta_av_api_to_ssm(p_data); break; + case BTA_AV_API_PEER_SEP_EVT: + bta_av_api_set_peer_sep(p_data); + break; } } @@ -1204,9 +1323,8 @@ static void bta_av_better_state_machine(tBTA_AV_CB* p_cb, uint16_t event, } void bta_av_sm_execute(tBTA_AV_CB* p_cb, uint16_t event, tBTA_AV_DATA* p_data) { - APPL_TRACE_EVENT("%s: AV event=0x%x(%s) state=%d(%s)", __func__, event, - bta_av_evt_code(event), p_cb->state, - bta_av_st_code(p_cb->state)); + LOG_VERBOSE("%s: AV event=0x%x(%s) state=%d(%s)", __func__, event, + bta_av_evt_code(event), p_cb->state, bta_av_st_code(p_cb->state)); bta_av_better_state_machine(p_cb, event, p_data); } @@ -1220,22 +1338,22 @@ void bta_av_sm_execute(tBTA_AV_CB* p_cb, uint16_t event, tBTA_AV_DATA* p_data) { * Returns bool * ******************************************************************************/ -bool bta_av_hdl_event(BT_HDR_RIGID* p_msg) { +bool bta_av_hdl_event(const BT_HDR_RIGID* p_msg) { if (p_msg->event > BTA_AV_LAST_EVT) { return true; /* to free p_msg */ } if (p_msg->event >= BTA_AV_FIRST_NSM_EVT) { - APPL_TRACE_VERBOSE("%s: AV nsm event=0x%x(%s)", __func__, p_msg->event, - bta_av_evt_code(p_msg->event)); + LOG_VERBOSE("%s: AV nsm event=0x%x(%s)", __func__, p_msg->event, + bta_av_evt_code(p_msg->event)); bta_av_non_state_machine_event(p_msg->event, (tBTA_AV_DATA*)p_msg); } else if (p_msg->event >= BTA_AV_FIRST_SM_EVT && p_msg->event <= BTA_AV_LAST_SM_EVT) { - APPL_TRACE_VERBOSE("%s: AV sm event=0x%x(%s)", __func__, p_msg->event, - bta_av_evt_code(p_msg->event)); + LOG_VERBOSE("%s: AV sm event=0x%x(%s)", __func__, p_msg->event, + bta_av_evt_code(p_msg->event)); /* state machine events */ bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA*)p_msg); } else { - APPL_TRACE_VERBOSE("%s: bta_handle=0x%x", __func__, p_msg->layer_specific); + LOG_VERBOSE("%s: bta_handle=0x%x", __func__, p_msg->layer_specific); /* stream state machine events */ bta_av_ssm_execute(bta_av_hndl_to_scb(p_msg->layer_specific), p_msg->event, (tBTA_AV_DATA*)p_msg); @@ -1406,8 +1524,6 @@ const char* bta_av_evt_code(uint16_t evt_code) { } void bta_debug_av_dump(int fd) { - if (appl_trace_level < BT_TRACE_LEVEL_DEBUG) return; - dprintf(fd, "\nBTA AV State:\n"); dprintf(fd, " State Machine State: %s\n", bta_av_st_code(bta_av_cb.state)); dprintf(fd, " SDP A2DP source handle: %d\n", bta_av_cb.sdp_a2dp_handle); diff --git a/system/bta/av/bta_av_ssm.cc b/system/bta/av/bta_av_ssm.cc index 033afb87766e8ba22357b0107e96bd18af8168dc..383591b54655af7ddc9a201a380e47363227181d 100644 --- a/system/bta/av/bta_av_ssm.cc +++ b/system/bta/av/bta_av_ssm.cc @@ -454,7 +454,7 @@ void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event, tBTA_AV_DATA* p_data) { if (p_scb == NULL) { /* this stream is not registered */ - APPL_TRACE_EVENT("%s: AV channel not registered", __func__); + LOG_VERBOSE("%s: AV channel not registered", __func__); return; } @@ -518,7 +518,7 @@ void bta_av_set_scb_sst_init(tBTA_AV_SCB* p_scb) { uint8_t next_state = BTA_AV_INIT_SST; - APPL_TRACE_VERBOSE( + LOG_VERBOSE( "%s: peer %s AV (hndl=0x%x) state=%d(%s) next state=%d(%s) p_scb=%p", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl, p_scb->state, bta_av_sst_code(p_scb->state), next_state, diff --git a/system/bta/csis/csis_client.cc b/system/bta/csis/csis_client.cc index 886c3a96125dc569b71b977059218f2b660eab32..9083ef366ee517f63a7d8fbe5c6e516d4252b26a 100644 --- a/system/bta/csis/csis_client.cc +++ b/system/bta/csis/csis_client.cc @@ -33,17 +33,22 @@ #include "bta_gatt_api.h" #include "bta_gatt_queue.h" #include "bta_groups.h" +#include "bta_le_audio_uuids.h" +#include "bta_sec_api.h" #include "btif_storage.h" +#include "crypto_toolbox/crypto_toolbox.h" #include "csis_types.h" #include "gap_api.h" #include "gatt_api.h" +#include "gd/common/init_flags.h" +#include "internal_include/bt_target.h" #include "main/shim/le_scanning_manager.h" -#include "main/shim/shim.h" #include "osi/include/osi.h" -#include "osi/include/properties.h" -#include "stack/btm/btm_dev.h" +#include "osi/include/stack_power_telemetry.h" #include "stack/btm/btm_sec.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" +#include "stack/gatt/gatt_int.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_ble_sec_api.h" using base::Closure; using bluetooth::Uuid; @@ -118,8 +123,9 @@ class CsisClientImpl : public CsisClient { base::Bind( [](Closure initCb, uint8_t client_id, uint8_t status) { if (status != GATT_SUCCESS) { - LOG(ERROR) << "Can't start Coordinated Set Service client " - "profile - no gatt clients left!"; + LOG_ERROR( + "Can't start Coordinated Set Service client " + "profile - no gatt clients left!"); return; } instance->gatt_if_ = client_id; @@ -131,7 +137,17 @@ class CsisClientImpl : public CsisClient { initCb), true); - DLOG(INFO) << __func__ << " Background scan enabled"; + BTA_DmSirkSecCbRegister([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { + if (event != BTA_DM_SIRK_VERIFICATION_REQ_EVT) { + LOG_ERROR("Invalid event received by CSIP: %d", + static_cast(event)); + return; + } + + instance->VerifySetMember(p_data->ble_req.bd_addr); + }); + + LOG_DEBUG(" Background scan enabled"); CsisObserverSetBackground(true); } @@ -146,12 +162,12 @@ class CsisClientImpl : public CsisClient { if (!csis_group) { if (create_group_if_non_existing) { /* Let's create a group */ - LOG(INFO) << __func__ << ": Create a new group"; + LOG_DEBUG(": Create a new group %d", group_id); auto g = std::make_shared(group_id, uuid); csis_groups_.push_back(g); csis_group = FindCsisGroup(group_id); } else { - LOG(ERROR) << __func__ << ": Missing group - that shall not happen"; + LOG_ERROR(": Missing group - that shall not happen"); return nullptr; } } @@ -170,16 +186,15 @@ class CsisClientImpl : public CsisClient { void OnGroupAddedCb(const RawAddress& address, const bluetooth::Uuid& uuid, int group_id) { - DLOG(INFO) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address) - << " uuid: " << uuid - << " group_id: " << group_id; + LOG_DEBUG(" address: %s, uuid: %s, group_id: %d", + ADDRESS_TO_LOGGABLE_CSTR(address), uuid.ToString().c_str(), + group_id); AssignCsisGroup(address, group_id, true, uuid); } void OnGroupMemberAddedCb(const RawAddress& address, int group_id) { - DLOG(INFO) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address) - << " group_id: " << group_id; + LOG_DEBUG("%s, group_id: %d", ADDRESS_TO_LOGGABLE_CSTR(address), group_id); AssignCsisGroup(address, group_id, false, Uuid::kEmpty); } @@ -189,8 +204,7 @@ class CsisClientImpl : public CsisClient { } void OnGroupMemberRemovedCb(const RawAddress& address, int group_id) { - DLOG(INFO) << __func__ << ": " << ADDRESS_TO_LOGGABLE_STR(address) - << " group_id: " << group_id; + LOG_DEBUG("%s, group_id: %d", ADDRESS_TO_LOGGABLE_CSTR(address), group_id); auto device = FindDeviceByAddress(address); if (device) RemoveCsisDevice(device, group_id); @@ -203,15 +217,13 @@ class CsisClientImpl : public CsisClient { auto csis_group = FindCsisGroup(group_id); if (csis_group == nullptr) { - LOG(ERROR) << __func__ << "the csis group (id: " << group_id - << ") does not exist"; + LOG_ERROR("the csis group (id: %d ) does not exist ", group_id); return; } if (!csis_group->IsDeviceInTheGroup(device)) { - LOG(ERROR) << __func__ << "the csis group (id: " << group_id - << ") does contain the device: " - << ADDRESS_TO_LOGGABLE_STR(address); + LOG_ERROR("the csis group (id: %d ) does contain the device: %s", + group_id, ADDRESS_TO_LOGGABLE_CSTR(address)); return; } @@ -221,9 +233,8 @@ class CsisClientImpl : public CsisClient { auto csis_instance = device->GetCsisInstanceByGroupId(group_id); if (!csis_instance) { - LOG(ERROR) << __func__ << " device: " << ADDRESS_TO_LOGGABLE_STR(address) - << " does not have the rank info for group (id:" << group_id - << " )"; + LOG_ERROR(" device: %s, does not have the rank info for group (id: %d )", + ADDRESS_TO_LOGGABLE_CSTR(address), group_id); return; } @@ -233,7 +244,7 @@ class CsisClientImpl : public CsisClient { } void Connect(const RawAddress& address) override { - DLOG(INFO) << __func__ << ": " << ADDRESS_TO_LOGGABLE_STR(address); + LOG_DEBUG("%s ", ADDRESS_TO_LOGGABLE_CSTR(address)); auto device = FindDeviceByAddress(address); if (device == nullptr) { @@ -246,7 +257,7 @@ class CsisClientImpl : public CsisClient { } void Disconnect(const RawAddress& addr) override { - DLOG(INFO) << __func__ << ": " << ADDRESS_TO_LOGGABLE_STR(addr); + LOG_DEBUG("%s ", ADDRESS_TO_LOGGABLE_CSTR(addr)); btif_storage_set_csis_autoconnect(addr, false); @@ -269,7 +280,7 @@ class CsisClientImpl : public CsisClient { } void RemoveDevice(const RawAddress& addr) override { - DLOG(INFO) << __func__ << ": " << ADDRESS_TO_LOGGABLE_STR(addr); + LOG_DEBUG("%s ", ADDRESS_TO_LOGGABLE_CSTR(addr)); auto device = FindDeviceByAddress(addr); if (!device) return; @@ -319,14 +330,14 @@ class CsisClientImpl : public CsisClient { uint16_t handle, void* data) { auto device = FindDeviceByConnId(conn_id); if (device == nullptr) { - LOG(ERROR) << __func__ << " Device not there"; + LOG_ERROR(" Device not there for conn_id: 0x%04x", conn_id); return; } int group_id = PTR_TO_UINT(data); auto csis_group = FindCsisGroup(group_id); if (csis_group == nullptr) { - LOG(ERROR) << __func__ << " There is no group? " << group_id; + LOG_ERROR(" There is no group: %d ", group_id); return; } @@ -365,7 +376,7 @@ class CsisClientImpl : public CsisClient { csis_instance->SetLockState(target_lock_state); if (csis_group->GetLockTransitionCnt() == 0) { - LOG(ERROR) << __func__ << " Not expected lock state"; + LOG_ERROR("Not expected lock state"); return; } @@ -410,10 +421,9 @@ class CsisClientImpl : public CsisClient { std::vector value = { (std::underlying_type::type)lock}; - LOG(INFO) << __func__ << " " << ADDRESS_TO_LOGGABLE_STR(device->addr) - << " rank: " << int(csis_instance->GetRank()) << " conn_id " - << device->conn_id << " handle " - << loghex(+(csis_instance->svc_data.lock_handle.val_hdl)); + LOG_INFO("%s, rank: %d, conn_id: 0x%04x, handle: 0x%04x", + ADDRESS_TO_LOGGABLE_CSTR(device->addr), csis_instance->GetRank(), + device->conn_id, csis_instance->svc_data.lock_handle.val_hdl); BtaGattQueue::WriteCharacteristic( device->conn_id, csis_instance->svc_data.lock_handle.val_hdl, value, @@ -448,10 +458,11 @@ class CsisClientImpl : public CsisClient { } void LockGroup(int group_id, bool lock, CsisLockCb cb) override { - if (lock) - DLOG(INFO) << __func__ << " Locking group: " << int(group_id); - else - DLOG(INFO) << __func__ << " Unlocking group: " << int(group_id); + if (lock) { + LOG_DEBUG("Locking group: %d", group_id); + } else { + LOG_DEBUG("Unlocking group: %d", group_id); + } /* For now we try to lock only connected devices in the group * TODO: We can consider reconnected to not connected devices and then @@ -459,7 +470,7 @@ class CsisClientImpl : public CsisClient { */ auto csis_group = FindCsisGroup(group_id); if (csis_group == nullptr) { - LOG(ERROR) << __func__ << " Group not found: " << group_id; + LOG_ERROR("Group not found: %d", group_id); NotifyGroupStatus(group_id, false, CsisGroupLockStatus::FAILED_INVALID_GROUP, std::move(cb)); @@ -475,12 +486,11 @@ class CsisClientImpl : public CsisClient { if (csis_group->GetTargetLockState() != CsisLockState::CSIS_STATE_UNSET) { /* CSIS operation ongoing */ - DLOG(INFO) << __func__ << " Lock operation ongoing:" - << "group id: " << group_id << "target state " - << (csis_group->GetTargetLockState() == - CsisLockState::CSIS_STATE_LOCKED - ? "lock" - : "unlock"); + LOG_DEBUG( + "Lock operation ongoing: group id: %d, target state %s", group_id, + (csis_group->GetTargetLockState() == CsisLockState::CSIS_STATE_LOCKED + ? "lock" + : "unlock")); return; } @@ -488,7 +498,7 @@ class CsisClientImpl : public CsisClient { : CsisLockState::CSIS_STATE_UNLOCKED; if (csis_group->GetCurrentLockState() == new_lock_state) { - DLOG(INFO) << __func__ << " Nothing to do as requested lock is there"; + LOG_DEBUG("Nothing to do as requested lock is there"); NotifyGroupStatus(group_id, lock, CsisGroupLockStatus::SUCCESS, std::move(cb)); return; @@ -496,7 +506,7 @@ class CsisClientImpl : public CsisClient { #if CSIP_UPPER_TESTER_FORCE_TO_SEND_LOCK == FALSE if (lock && !csis_group->IsAvailableForCsisLockOperation()) { - DLOG(INFO) << __func__ << " Group " << group_id << " locked by other"; + LOG_DEBUG("Group %d locked by other", group_id); NotifyGroupStatus(group_id, false, CsisGroupLockStatus::FAILED_LOCKED_BY_OTHER, std::move(cb)); @@ -551,19 +561,18 @@ class CsisClientImpl : public CsisClient { bool SerializeSets(const RawAddress& addr, std::vector& out) const { auto device = FindDeviceByAddress(addr); if (device == nullptr) { - LOG(WARNING) << __func__ << " Skipping unknown device addr= " - << ADDRESS_TO_LOGGABLE_STR(addr); + LOG_WARN("Skipping unknown device addr= %s", + ADDRESS_TO_LOGGABLE_CSTR(addr)); return false; } if (device->GetNumberOfCsisInstances() == 0) { - LOG(WARNING) << __func__ << " No CSIS instances for addr= " - << ADDRESS_TO_LOGGABLE_STR(addr); + LOG_WARN("No CSIS instances for addr= %s", + ADDRESS_TO_LOGGABLE_CSTR(addr)); return false; } - DLOG(INFO) << __func__ << ": device=" - << ADDRESS_TO_LOGGABLE_STR(device->addr); + LOG_DEBUG(": device= %s", ADDRESS_TO_LOGGABLE_CSTR(device->addr)); auto num_sets = device->GetNumberOfCsisInstances(); if ((num_sets == 0) || (num_sets > std::numeric_limits::max())) @@ -582,7 +591,7 @@ class CsisClientImpl : public CsisClient { auto gid = csis_inst->GetGroupId(); auto csis_group = FindCsisGroup(gid); if (csis_group == nullptr) { - LOG(ERROR) << "SerializeSets: No matching group found!"; + LOG_ERROR("SerializeSets: No matching group found!"); return; } @@ -614,7 +623,7 @@ class CsisClientImpl : public CsisClient { if (in.size() < CSIS_STORAGE_HEADER_SZ + (num_sets * CSIS_STORAGE_ENTRY_SZ)) { - LOG(ERROR) << "Invalid persistent storage data"; + LOG_ERROR("Invalid persistent storage data"); return group_rank_map; } @@ -632,6 +641,10 @@ class CsisClientImpl : public CsisClient { // Set grouping and SIRK auto csis_group = AssignCsisGroup(addr, gid, true, Uuid::kEmpty); + if (csis_group == nullptr) { + continue; + } + csis_group->SetDesiredSize(size); csis_group->SetSirk(sirk); @@ -653,6 +666,7 @@ class CsisClientImpl : public CsisClient { devices_.push_back(device); } + bool is_le_audio_device = false; for (const auto& csis_group : csis_groups_) { if (!csis_group->IsDeviceInTheGroup(device)) continue; @@ -666,16 +680,25 @@ class CsisClientImpl : public CsisClient { callbacks_->OnDeviceAvailable(device->addr, group_id, csis_group->GetDesiredSize(), rank, csis_group->GetUuid()); + + if (csis_group->GetUuid() == + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)) { + is_le_audio_device = true; + } } } + /* For now, if this is LeAudio device, CSIP is opportunistic profile. */ + bool is_opportunistic = is_le_audio_device; + if (autoconnect) { - BTA_GATTC_Open(gatt_if_, addr, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); + BTA_GATTC_Open(gatt_if_, addr, BTM_BLE_BKG_CONNECT_ALLOW_LIST, + is_opportunistic); } } void CleanUp() { - DLOG(INFO) << __func__; + LOG_DEBUG(); BTA_GATTC_AppDeregister(gatt_if_); for (auto& device : devices_) { @@ -684,6 +707,7 @@ class CsisClientImpl : public CsisClient { } devices_.clear(); + csis_groups_.clear(); CsisObserverSetBackground(false); dev_groups_->CleanUp(device_group_callbacks); @@ -706,10 +730,16 @@ class CsisClientImpl : public CsisClient { << static_cast(g->GetTargetLockState()) << "\n" << " devices: \n"; for (auto& device : devices_) { - if (!g->IsDeviceInTheGroup(device)) continue; + if (!g->IsDeviceInTheGroup(device)) { + if (device->GetExpectedGroupIdMember() == g->GetGroupId()) { + stream << " == candidate addr: " + << ADDRESS_TO_LOGGABLE_STR(device->addr) << "\n"; + } + continue; + } - stream << " == addr: " - << ADDRESS_TO_LOGGABLE_STR(device->addr) << " ==\n" + stream << " == addr: " << ADDRESS_TO_LOGGABLE_STR(device->addr) + << " ==\n" << " csis instance: data:" << "\n"; @@ -753,14 +783,30 @@ class CsisClientImpl : public CsisClient { if (!csis_group) { /* This could happen when remove device is called when bonding is * removed */ - DLOG(INFO) << __func__ << " group not found " << group_id; + LOG_DEBUG("group not found %d", group_id); return; } csis_group->RemoveDevice(device->addr); + if (csis_group->IsEmpty()) { RemoveCsisGroup(group_id); + + /* Remove cached candidate devices for group */ + devices_.erase( + std::remove_if(devices_.begin(), devices_.end(), + [group_id](auto& dev) { + if (dev->GetNumberOfCsisInstances() == 0 && + dev->GetExpectedGroupIdMember() == group_id && + dev->GetPairingSirkReadFlag() == false) { + return true; + } + + return false; + }), + devices_.end()); } + device->RemoveCsisInstance(group_id); } @@ -798,7 +844,7 @@ class CsisClientImpl : public CsisClient { /* Handle encryption */ void OnEncrypted(std::shared_ptr& device) { - DLOG(INFO) << __func__ << " " << ADDRESS_TO_LOGGABLE_STR(device->addr); + LOG_DEBUG("%s ", ADDRESS_TO_LOGGABLE_CSTR(device->addr)); if (device->is_gatt_service_valid) { NotifyCsisDeviceValidAndStoreIfNeeded(device); @@ -820,7 +866,7 @@ class CsisClientImpl : public CsisClient { int group_id = csis_group->GetGroupId(); auto csis_instance = device->GetCsisInstanceByGroupId(group_id); - DLOG(INFO) << __func__ << " group id " << group_id; + LOG_DEBUG("group id %d", group_id); if (!csis_instance) { /* This can happen when some other user added device to group in the @@ -829,8 +875,7 @@ class CsisClientImpl : public CsisClient { * context. We will endup in having device in 2 groups. One in generic * context with valid csis_instance, and one in CAP context without csis * instance */ - LOG(INFO) << __func__ << " csis_instance does not exist for group " - << group_id; + LOG_INFO("csis_instance does not exist for group %d", group_id); continue; } @@ -847,11 +892,14 @@ class CsisClientImpl : public CsisClient { if (notify_connected) { callbacks_->OnConnectionState(device->addr, ConnectionState::CONNECTED); + LOG_DEBUG("group_id %d", group_id_to_discover); if (group_id_to_discover != bluetooth::groups::kGroupUnknown) { /* Start active search for the other device * b/281120322 */ auto g = FindCsisGroup(group_id_to_discover); + LOG_DEBUG("Group size %d target size %d", g->GetDesiredSize(), + g->GetCurrentSize()); if (g->GetDesiredSize() > g->GetCurrentSize()) { CsisActiveDiscovery(g); } @@ -866,11 +914,9 @@ class CsisClientImpl : public CsisClient { void OnGattWriteCcc(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, void* user_data) { - LOG(INFO) << __func__ << " handle=" << loghex(handle); - auto device = FindDeviceByConnId(conn_id); if (device == nullptr) { - LOG(INFO) << __func__ << " unknown conn_id=" << loghex(conn_id); + LOG_INFO("unknown conn_id= 0x%04x", conn_id); BtaGattQueue::Clean(conn_id); return; } @@ -879,6 +925,29 @@ class CsisClientImpl : public CsisClient { LOG_INFO("Database out of sync for %s", ADDRESS_TO_LOGGABLE_CSTR(device->addr)); ClearDeviceInformationAndStartSearch(device); + return; + } + + if (status == GATT_SUCCESS) { + LOG_INFO("Successfully registered on ccc: 0x%04x, device: %s", handle, + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); + return; + } + + LOG_ERROR( + "Failed to register for indications: 0x%04x, device: %s, status: " + "0x%02x", + handle, ADDRESS_TO_LOGGABLE_CSTR(device->addr), status); + + auto val_handle = device->FindValueHandleByCccHandle(handle); + if (!val_handle) { + LOG_ERROR("Unknown ccc handle: 0x%04x, device: %s", handle, + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); + return; + } + + if (val_handle != GAP_INVALID_HANDLE) { + BTA_GATTC_DeregisterForNotifications(gatt_if_, device->addr, val_handle); } } @@ -886,15 +955,14 @@ class CsisClientImpl : public CsisClient { const uint8_t* value) { auto device = FindDeviceByConnId(conn_id); if (device == nullptr) { - LOG(WARNING) << "Skipping unknown device, conn_id=" << loghex(conn_id); + LOG_WARN("Skipping unknown device, conn_id= 0x%04x", conn_id); return; } auto csis_instance = device->GetCsisInstanceByOwningHandle(handle); if (csis_instance == nullptr) { - LOG(ERROR) << __func__ - << " unknown notification handle: " << loghex(handle) - << " for conn_id: " << loghex(conn_id); + LOG_ERROR("unknown notification handle: 0x%04x for conn_id: 0x%04x", + handle, conn_id); return; } @@ -905,8 +973,8 @@ class CsisClientImpl : public CsisClient { } else if (handle == csis_instance->svc_data.size_handle.val_hdl) { OnCsisSizeValueUpdate(conn_id, GATT_SUCCESS, handle, len, value); } else { - LOG(WARNING) << __func__ << " unknown notification handle " - << loghex(handle) << " for conn_id " << loghex(conn_id); + LOG_WARN("unknown notification handle 0x%04x for conn_id= 0x%04x ", + handle, conn_id); } } @@ -925,8 +993,8 @@ class CsisClientImpl : public CsisClient { void CsisLockCompleted(std::shared_ptr& csis_group, bool lock, CsisGroupLockStatus status) { - DLOG(INFO) << __func__ << " group id: " << int(csis_group->GetGroupId()) - << "target state " << (lock ? "lock" : "unlock"); + LOG_DEBUG("group id: %d, target state %s", csis_group->GetGroupId(), + (lock ? "lock" : "unlock")); NotifyGroupStatus(csis_group->GetGroupId(), lock, status, std::move(csis_group->GetLockCb())); @@ -937,14 +1005,14 @@ class CsisClientImpl : public CsisClient { std::shared_ptr& csis_instance, uint16_t len, const uint8_t* value) { if (len != 1) { - LOG(ERROR) << __func__ << " invalid notification len: " << loghex(len); + LOG_ERROR("invalid notification len: %d", len); return; } CsisLockState new_lock = (CsisLockState)(value[0]); - DLOG(INFO) << " New lock state: " << int(new_lock) - << " device rank: " << int(csis_instance->GetRank()) << "\n"; + LOG_DEBUG("New lock state: %d, device rank: %d", + static_cast(new_lock), csis_instance->GetRank()); csis_instance->SetLockState(new_lock); @@ -993,7 +1061,7 @@ class CsisClientImpl : public CsisClient { auto device = FindDeviceByConnId(conn_id); if (device == nullptr) { - LOG(WARNING) << "Skipping unknown device, conn_id=" << loghex(conn_id); + LOG_WARN("Skipping unknown device, conn_id=0x%04x", conn_id); return; } @@ -1013,21 +1081,20 @@ class CsisClientImpl : public CsisClient { } if (len != 1) { - LOG(ERROR) << "Invalid size value length=" << +len - << " at handle=" << loghex(handle); + LOG_ERROR("Invalid size value length=%d at handle= 0x%04x", len, handle); BTA_GATTC_Close(device->conn_id); return; } auto csis_instance = device->GetCsisInstanceByOwningHandle(handle); if (csis_instance == nullptr) { - LOG(ERROR) << __func__ << " Unknown csis instance"; + LOG_ERROR("Unknown csis instance"); BTA_GATTC_Close(device->conn_id); return; } auto csis_group = FindCsisGroup(csis_instance->GetGroupId()); if (!csis_group) { - LOG(ERROR) << __func__ << " Unknown group id yet"; + LOG_ERROR("Unknown group id yet"); return; } @@ -1042,7 +1109,7 @@ class CsisClientImpl : public CsisClient { bool notify_valid_services = false) { auto device = FindDeviceByConnId(conn_id); if (device == nullptr) { - LOG(WARNING) << "Skipping unknown device, conn_id=" << loghex(conn_id); + LOG_WARN("Skipping unknown device, conn_id=0x%04x", conn_id); return; } @@ -1062,15 +1129,14 @@ class CsisClientImpl : public CsisClient { } if (len != 1) { - LOG(ERROR) << " Invalid lock value length=" << +len - << " at handle=" << loghex(handle); + LOG_ERROR("Invalid lock value length=%d, at handle=0x%04x", len, handle); BTA_GATTC_Close(device->conn_id); return; } auto csis_instance = device->GetCsisInstanceByOwningHandle(handle); if (csis_instance == nullptr) { - LOG(ERROR) << __func__ << " Unknown csis instance"; + LOG_ERROR("Unknown csis instance"); BTA_GATTC_Close(device->conn_id); return; } @@ -1084,14 +1150,12 @@ class CsisClientImpl : public CsisClient { bool notify_valid_services) { auto device = FindDeviceByConnId(conn_id); if (device == nullptr) { - LOG(WARNING) << __func__ - << " Skipping unknown device, conn_id=" << loghex(conn_id); + LOG_WARN("Skipping unknown device, conn_id= 0x%04x", conn_id); return; } LOG_DEBUG("%s, status: 0x%02x, rank: %d", ADDRESS_TO_LOGGABLE_CSTR(device->addr), status, value[0]); - if (status != GATT_SUCCESS) { if (status == GATT_DATABASE_OUT_OF_SYNC) { LOG_INFO("Database out of sync for %s", @@ -1105,15 +1169,15 @@ class CsisClientImpl : public CsisClient { } if (len != 1) { - LOG(ERROR) << __func__ << "Invalid rank value length=" << +len - << " at handle=" << loghex(handle); + LOG_ERROR("Invalid rank value length= %d, at handle= 0x%04x", len, + handle); BTA_GATTC_Close(device->conn_id); return; } auto csis_instance = device->GetCsisInstanceByOwningHandle(handle); if (csis_instance == nullptr) { - LOG(ERROR) << __func__ << " Unknown csis instance handle " << int(handle); + LOG_ERROR("Unknown csis instance handle 0x%04x", handle); BTA_GATTC_Close(device->conn_id); return; } @@ -1121,7 +1185,7 @@ class CsisClientImpl : public CsisClient { csis_instance->SetRank((value[0])); auto csis_group = FindCsisGroup(csis_instance->GetGroupId()); if (!csis_group) { - LOG(ERROR) << __func__ << " Unknown group id yet"; + LOG_ERROR("Unknown group id yet"); return; } @@ -1162,17 +1226,17 @@ class CsisClientImpl : public CsisClient { */ bool sdf(const RawAddress& address, const Octet16& encrypted_sirk, Octet16& sirk) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); - if (!p_dev_rec) { - LOG(ERROR) << __func__ << " No security for " - << ADDRESS_TO_LOGGABLE_STR(address); + auto pltk = BTM_BleGetPeerLTK(address); + if (!pltk.has_value()) { + LOG_ERROR("No security for %s", ADDRESS_TO_LOGGABLE_CSTR(address)); return false; } - DLOG(INFO) << __func__ << " LTK " - << base::HexEncode(p_dev_rec->ble.keys.pltk.data(), 16); - DLOG(INFO) << __func__ << " IRK " - << base::HexEncode(p_dev_rec->ble.keys.irk.data(), 16); +#ifdef CSIS_DEBUG + auto irk = BTM_BleGetPeerIRK(address); + LOG_INFO("LTK %s", (base::HexEncode(*pltk.data(), 16)).c_str()); + LOG_INFO("IRK %s", base::HexEncode(*irk.data(), 16).c_str()); +#endif /* Calculate salt CSIS d1.0r05 4.3 */ Octet16 zero_key; @@ -1183,25 +1247,34 @@ class CsisClientImpl : public CsisClient { Octet16 s1 = crypto_toolbox::aes_cmac(zero_key, (uint8_t*)(msg1.c_str()), msg1.size()); - DLOG(INFO) << "s1 (le) " << base::HexEncode(s1.data(), 16); +#ifdef CSIS_DEBUG + LOG_INFO("s1 (le) %s", base::HexEncode(s1.data(), 16).c_str()); /* Create K = LTK */ - DLOG(INFO) << "K (le) " - << base::HexEncode(p_dev_rec->ble.keys.pltk.data(), 16) << "\n"; + LOG_INFO("K (le) %s", base::HexEncode(*pltk.data(), 16).c_str()); +#endif + + Octet16 T = crypto_toolbox::aes_cmac(s1, *pltk); - Octet16 T = crypto_toolbox::aes_cmac(s1, p_dev_rec->ble.keys.pltk); - DLOG(INFO) << "T (le)" << base::HexEncode(T.data(), 16) << "\n"; +#ifdef CSIS_DEBUG + LOG_INFO("T (le) %s", base::HexEncode(T.data(), 16).c_str()); +#endif std::string msg2 = "csis"; std::reverse(msg2.begin(), msg2.end()); Octet16 k1 = crypto_toolbox::aes_cmac(T, (uint8_t*)(msg2.c_str()), msg2.size()); - DLOG(INFO) << "K1 (le) " << base::HexEncode(k1.data(), 16) << "\n"; +#ifdef CSIS_DEBUG + LOG_INFO("K1 (le) %s", base::HexEncode(k1.data(), 16).c_str()); +#endif for (int i = 0; i < 16; i++) sirk[i] = encrypted_sirk[i] ^ k1[i]; - DLOG(INFO) << "SIRK (le)" << base::HexEncode(sirk.data(), 16) << "\n"; +#ifdef CSIS_DEBUG + LOG_INFO("SIRK (le)%s", base::HexEncode(sirk.data(), 16).c_str()); +#endif + return true; } @@ -1217,9 +1290,9 @@ class CsisClientImpl : public CsisClient { service_data_len, BTM_BLE_AD_TYPE_RSI, &service_data_len))) { RawAddress bda; - const uint8_t *p_bda = p_service_data; + const uint8_t* p_bda = p_service_data; if (service_data_len < RawAddress::kLength) { - continue; + continue; } STREAM_TO_BDADDR(bda, p_bda); @@ -1229,11 +1302,39 @@ class CsisClientImpl : public CsisClient { return std::move(devices); } + void CacheAndAdvertiseExpectedMember(const RawAddress& address, + int group_id) { + auto device = FindDeviceByAddress(address); + if (device == nullptr) { + device = std::make_shared(address, false); + devices_.push_back(device); + } + + /* + * Expected group ID will be checked while reading SIRK if this device + * truly is member of group. + */ + device.get()->SetExpectedGroupIdMember(group_id); + callbacks_->OnSetMemberAvailable(address, + device.get()->GetExpectedGroupIdMember()); + } + void OnActiveScanResult(const tBTA_DM_INQ_RES* result) { auto csis_device = FindDeviceByAddress(result->bd_addr); if (csis_device) { - DLOG(INFO) << __func__ << " Drop same device .." - << ADDRESS_TO_LOGGABLE_STR(result->bd_addr); + LOG_DEBUG("Drop same device .. %s", + ADDRESS_TO_LOGGABLE_CSTR(result->bd_addr)); + return; + } + + /* Make sure device is not already bonded which could + * be a case for dual mode devices where + */ + if (BTM_BleIsLinkKeyKnown(result->bd_addr)) { + LOG_VERBOSE("Device %s already bonded. Identity address: %s", + ADDRESS_TO_LOGGABLE_CSTR(result->bd_addr), + ADDRESS_TO_LOGGABLE_CSTR( + *BTM_BleGetIdentityAddress(result->bd_addr))); return; } @@ -1243,7 +1344,7 @@ class CsisClientImpl : public CsisClient { /* Notify only the actively searched group */ auto csis_group = FindCsisGroup(discovering_group_); if (csis_group == nullptr) { - LOG(ERROR) << " No ongoing CSIS discovery - disable scan"; + LOG_ERROR("No ongoing CSIS discovery - disable scan"); CsisActiveObserverSet(false); return; } @@ -1259,10 +1360,11 @@ class CsisClientImpl : public CsisClient { return csis_group->IsRsiMatching(rsi); }); if (discovered_group_rsi != all_rsi.cend()) { - DLOG(INFO) << "Found set member " - << ADDRESS_TO_LOGGABLE_STR(result->bd_addr); - callbacks_->OnSetMemberAvailable(result->bd_addr, - csis_group->GetGroupId()); + LOG_DEBUG("Found set member %s", + ADDRESS_TO_LOGGABLE_CSTR(result->bd_addr)); + + CacheAndAdvertiseExpectedMember(result->bd_addr, + csis_group->GetGroupId()); /* Switch back to the opportunistic observer mode. * When second device will pair, csis will restart active scan @@ -1272,39 +1374,49 @@ class CsisClientImpl : public CsisClient { } } - void CsisActiveObserverSet(bool enable) { + static void csis_ad_type_filter_set(bool enable) { bool is_ad_type_filter_supported = bluetooth::shim::is_ad_type_filter_supported(); - LOG_INFO("Group_id %d: enable: %d, is_ad_type_filter_supported: %d", - discovering_group_, enable, is_ad_type_filter_supported); + + LOG_INFO("enable: %d, is_ad_type_filter_supported: %d", enable, + is_ad_type_filter_supported); + if (is_ad_type_filter_supported) { bluetooth::shim::set_ad_type_rsi_filter(enable); } else { bluetooth::shim::set_empty_filter(enable); } + } - BTA_DmBleCsisObserve( - enable, [](tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) { - /* If there's no instance we are most likely shutting - * down the whole stack and we can ignore this event. - */ - if (instance == nullptr) return; - - if (event == BTA_DM_INQ_CMPL_EVT) { - LOG(INFO) << "BLE observe complete. Num Resp: " - << static_cast(p_data->inq_cmpl.num_resps); - instance->OnCsisObserveCompleted(); - instance->CsisObserverSetBackground(true); - return; - } - - if (event != BTA_DM_INQ_RES_EVT) { - LOG(WARNING) << "Unknown event: " << event; - return; - } - - instance->OnActiveScanResult(&p_data->inq_res); - }); + void CsisActiveObserverSet(bool enable) { + LOG_INFO("Group_id %d: enable: %d", discovering_group_, enable); + csis_ad_type_filter_set(enable); + + BTA_DmBleCsisObserve(enable, + [](tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) { + /* If there's no instance we are most likely shutting + * down the whole stack and we can ignore this event. + */ + if (instance == nullptr) return; + + if (event == BTA_DM_INQ_CMPL_EVT) { + power_telemetry::GetInstance().LogBleScan( + static_cast(p_data->inq_cmpl.num_resps)); + LOG_INFO("BLE observe complete. Num Resp: %d", + p_data->inq_cmpl.num_resps); + csis_ad_type_filter_set(false); + instance->OnCsisObserveCompleted(); + instance->CsisObserverSetBackground(true); + return; + } + + if (event != BTA_DM_INQ_RES_EVT) { + LOG_WARN("Unknown event: 0x%02x", event); + return; + } + + instance->OnActiveScanResult(&p_data->inq_res); + }); BTA_DmBleScan(enable, bluetooth::csis::kDefaultScanDurationS, true); /* Need to call it by ourselfs */ @@ -1337,14 +1449,15 @@ class CsisClientImpl : public CsisClient { } void CsisActiveDiscovery(std::shared_ptr csis_group) { - CheckForGroupInInqDb(csis_group); + if (bluetooth::common::InitFlags::UseRsiFromCachedInquiryResults()) { + CheckForGroupInInqDb(csis_group); + } if ((csis_group->GetDiscoveryState() != CsisDiscoveryState::CSIS_DISCOVERY_IDLE)) { - LOG(ERROR) << __func__ - << " Incorrect ase group: " << csis_group->GetGroupId() - << " state " - << loghex(static_cast(csis_group->GetDiscoveryState())); + LOG_ERROR("Incorrect ase group: %d, state 0x%02x", + csis_group->GetGroupId(), + static_cast(csis_group->GetDiscoveryState())); return; } @@ -1364,6 +1477,17 @@ class CsisClientImpl : public CsisClient { return; } + /* Make sure device is not already bonded which could + * be a case for dual mode devices where + */ + if (BTM_BleIsLinkKeyKnown(result->bd_addr)) { + LOG_VERBOSE("Device %s already bonded. Identity address: %s", + ADDRESS_TO_LOGGABLE_CSTR(result->bd_addr), + ADDRESS_TO_LOGGABLE_CSTR( + *BTM_BleGetIdentityAddress(result->bd_addr))); + return; + } + auto all_rsi = GetAllRsiFromAdvertising(result); if (all_rsi.empty()) return; @@ -1381,8 +1505,8 @@ class CsisClientImpl : public CsisClient { break; } - callbacks_->OnSetMemberAvailable(result->bd_addr, - group->GetGroupId()); + CacheAndAdvertiseExpectedMember(result->bd_addr, group->GetGroupId()); + break; } } @@ -1390,28 +1514,30 @@ class CsisClientImpl : public CsisClient { } void CsisObserverSetBackground(bool enable) { - DLOG(INFO) << __func__ << " CSIS Discovery background: " << enable; + LOG_DEBUG("CSIS Discovery background: %d", enable); - BTA_DmBleCsisObserve( - enable, [](tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) { - /* If there's no instance we are most likely shutting - * down the whole stack and we can ignore this event. - */ - if (instance == nullptr) return; + BTA_DmBleCsisObserve(enable, + [](tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) { + /* If there's no instance we are most likely shutting + * down the whole stack and we can ignore this event. + */ + if (instance == nullptr) return; - if (event == BTA_DM_INQ_CMPL_EVT) { - DLOG(INFO) << "BLE observe complete. Num Resp: " - << static_cast(p_data->inq_cmpl.num_resps); - return; - } + if (event == BTA_DM_INQ_CMPL_EVT) { + power_telemetry::GetInstance().LogBleScan( + static_cast(p_data->inq_cmpl.num_resps)); + LOG_VERBOSE("BLE observe complete. Num Resp: %d", + p_data->inq_cmpl.num_resps); + return; + } - if (event != BTA_DM_INQ_RES_EVT) { - LOG(WARNING) << "Unknown event: " << event; - return; - } + if (event != BTA_DM_INQ_RES_EVT) { + LOG_WARN("Unknown event: 0x%02x", event); + return; + } - instance->OnScanBackgroundResult(&p_data->inq_res); - }); + instance->OnScanBackgroundResult(&p_data->inq_res); + }); } void OnCsisSirkValueUpdate(uint16_t conn_id, tGATT_STATUS status, @@ -1420,8 +1546,7 @@ class CsisClientImpl : public CsisClient { bool notify_valid_services = true) { auto device = FindDeviceByConnId(conn_id); if (device == nullptr) { - LOG(WARNING) << __func__ - << " Skipping unknown device, conn_id=" << loghex(conn_id); + LOG_WARN("Skipping unknown device, conn_id=0x%04x", conn_id); return; } @@ -1445,28 +1570,26 @@ class CsisClientImpl : public CsisClient { } if (len != bluetooth::csis::kCsisSirkCharLen) { - LOG(ERROR) << "Invalid sirk value length=" << +len - << " at handle=" << loghex(handle); + LOG_ERROR("Invalid sirk value length= %d at handle= 0x%04x", len, handle); BTA_GATTC_Close(device->conn_id); return; } auto csis_instance = device->GetCsisInstanceByOwningHandle(handle); if (csis_instance == nullptr) { - LOG(ERROR) << __func__ << " Unknown csis instance: handle " - << loghex(handle); + LOG_ERROR("Unknown csis instance: handle 0x%04x", handle); BTA_GATTC_Close(device->conn_id); return; } uint8_t sirk_type = value[0]; - LOG(INFO) << __func__ << " SIRK Type: " << +sirk_type; + LOG_INFO("SIRK Type: 0x%02x", sirk_type); /* Verify if sirk is not all zeros */ Octet16 zero{}; if (memcmp(zero.data(), value + 1, 16) == 0) { - LOG(ERROR) << "Received invalid zero SIRK address: " - << loghex(device->conn_id) << ". Disconnecting "; + LOG_ERROR("Received invalid zero SIRK conn_id: 0x%02x. Disconnecting ", + device->conn_id); BTA_GATTC_Close(device->conn_id); return; } @@ -1522,13 +1645,33 @@ class CsisClientImpl : public CsisClient { if (notify_valid_services) NotifyCsisDeviceValidAndStoreIfNeeded(device); - DLOG(INFO) << " SIRK " << base::HexEncode(received_sirk.data(), 16) - << " address" << ADDRESS_TO_LOGGABLE_STR(device->addr); +#ifdef CSIS_DEBUG + LOG_INFO("SIRK %s, address: %s", + base::HexEncode(received_sirk.data(), 16).c_str(), + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); +#endif + + LOG_VERBOSE("Expected group size %d, actual group Size: %d", + csis_group->GetDesiredSize(), csis_group->GetCurrentSize()); + + if (csis_group->GetDesiredSize() == csis_group->GetCurrentSize()) { + auto iter = devices_.cbegin(); - DLOG(INFO) << " Expected group size " - << loghex(csis_group->GetDesiredSize()) - << ", actual group Size: " - << loghex(csis_group->GetCurrentSize()); + /* + * Remove devices which are expected members but are not connected and + * group is already completed. Those devices are cached ivalid devices + * kept on list to not trigger "new device" found every time advertising + * event is received. + */ + while (iter != devices_.cend()) { + if (((*iter)->GetExpectedGroupIdMember() == csis_group->GetGroupId()) && + !(*iter)->IsConnected()) { + iter = devices_.erase(iter); + } else { + ++iter; + } + } + } } void DeregisterNotifications(std::shared_ptr device) { @@ -1558,9 +1701,9 @@ class CsisClientImpl : public CsisClient { const gatt::Service* service, const bluetooth::Uuid& context_uuid, bool is_last_instance) { - DLOG(INFO) << __func__ << " service handle: " << loghex(service->handle) - << " end handle: " << loghex(service->end_handle) - << " uuid: " << context_uuid; + LOG_DEBUG("service handle: 0x%04x, end handle: 0x%04x, uuid: %s", + service->handle, service->end_handle, + context_uuid.ToString().c_str()); auto csis_inst = std::make_shared( (uint16_t)service->handle, (uint16_t)service->end_handle, context_uuid); @@ -1570,6 +1713,8 @@ class CsisClientImpl : public CsisClient { if (group_id != bluetooth::groups::kGroupUnknown) csis_inst->SetGroupId(group_id); + device->SetCsisInstance(csis_inst->svc_data.start_handle, csis_inst); + /* Initially validate and store GATT service discovery data */ for (const gatt::Characteristic& charac : service->characteristics) { if (charac.uuid == kCsisLockUuid) { @@ -1577,8 +1722,8 @@ class CsisClientImpl : public CsisClient { uint16_t ccc_handle = FindCccHandle(device->conn_id, charac.value_handle); if (ccc_handle == GAP_INVALID_HANDLE) { - DLOG(ERROR) << __func__ - << ": no HAS Active Preset CCC descriptor found!"; + LOG_ERROR("no HAS Active Preset CCC descriptor found!"); + device->RemoveCsisInstance(group_id); return false; } csis_inst->svc_data.lock_handle.val_hdl = charac.value_handle; @@ -1587,15 +1732,17 @@ class CsisClientImpl : public CsisClient { SubscribeForNotifications(device->conn_id, device->addr, charac.value_handle, ccc_handle); - DLOG(INFO) << __func__ << " Lock UUID found handle: " - << loghex(csis_inst->svc_data.lock_handle.val_hdl) - << " ccc handle: " - << loghex(csis_inst->svc_data.lock_handle.ccc_hdl); + LOG_DEBUG( + "Lock UUID found handle: 0x%04x, ccc handle: 0x%04x, device: %s", + csis_inst->svc_data.lock_handle.val_hdl, + csis_inst->svc_data.lock_handle.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); } else if (charac.uuid == kCsisRankUuid) { csis_inst->svc_data.rank_handle = charac.value_handle; - DLOG(INFO) << __func__ << " Rank UUID found handle: " - << loghex(csis_inst->svc_data.rank_handle); + LOG_DEBUG("Rank UUID found handle: 0x%04x, device: %s", + csis_inst->svc_data.rank_handle, + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); } else if (charac.uuid == kCsisSirkUuid) { /* Find the optional CCC descriptor */ uint16_t ccc_handle = @@ -1607,10 +1754,11 @@ class CsisClientImpl : public CsisClient { SubscribeForNotifications(device->conn_id, device->addr, charac.value_handle, ccc_handle); - DLOG(INFO) << __func__ << " SIRK UUID found handle: " - << loghex(csis_inst->svc_data.sirk_handle.val_hdl) - << " ccc handle: " - << loghex(csis_inst->svc_data.sirk_handle.ccc_hdl); + LOG_DEBUG( + "SIRK UUID found handle: 0x%04x, ccc handle: 0x%04x, device: %s", + csis_inst->svc_data.sirk_handle.val_hdl, + csis_inst->svc_data.sirk_handle.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); } else if (charac.uuid == kCsisSizeUuid) { /* Find the optional CCC descriptor */ uint16_t ccc_handle = @@ -1622,10 +1770,11 @@ class CsisClientImpl : public CsisClient { SubscribeForNotifications(device->conn_id, device->addr, charac.value_handle, ccc_handle); - DLOG(INFO) << __func__ << " Size UUID found handle: " - << loghex(csis_inst->svc_data.size_handle.val_hdl) - << " ccc handle: " - << loghex(csis_inst->svc_data.size_handle.ccc_hdl); + LOG_DEBUG( + "Size UUID found handle: 0x%04x, ccc handle: 0x%04x, device: %s", + csis_inst->svc_data.size_handle.val_hdl, + csis_inst->svc_data.size_handle.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); } } @@ -1634,10 +1783,10 @@ class CsisClientImpl : public CsisClient { */ if (csis_inst->svc_data.sirk_handle.val_hdl == GAP_INVALID_HANDLE) { /* We have some characteristics but all dependencies are not satisfied */ - LOG(ERROR) << __func__ << " Service has a broken structure."; + LOG_ERROR("Service has a broken structure."); + device->RemoveCsisInstance(group_id); return false; } - device->SetCsisInstance(csis_inst->svc_data.start_handle, csis_inst); bool notify_after_sirk_read = false; bool notify_after_lock_read = false; @@ -1714,7 +1863,7 @@ class CsisClientImpl : public CsisClient { /* These are all generic GATT event handlers calling HAS specific code. */ void GattcCallback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) { - LOG(INFO) << __func__ << " event = " << static_cast(event); + LOG_INFO("event = 0x%02x", event); /* This is in case Csis CleanUp is already done * while GATT is still up and could send events @@ -1765,20 +1914,29 @@ class CsisClientImpl : public CsisClient { } void OnGattConnected(const tBTA_GATTC_OPEN& evt) { - DLOG(INFO) << __func__ << ": address=" - << ADDRESS_TO_LOGGABLE_STR(evt.remote_bda) - << ", conn_id=" << evt.conn_id; + LOG_INFO("%s, conn_id=0x%04x, transport=%s, status=%s(0x%02x)", + ADDRESS_TO_LOGGABLE_CSTR(evt.remote_bda), evt.conn_id, + bt_transport_text(evt.transport).c_str(), + gatt_status_text(evt.status).c_str(), evt.status); + + if (evt.transport != BT_TRANSPORT_LE) { + LOG_WARN("Only LE connection is allowed (transport %s)", + bt_transport_text(evt.transport).c_str()); + BTA_GATTC_Close(evt.conn_id); + return; + } auto device = FindDeviceByAddress(evt.remote_bda); if (device == nullptr) { - DLOG(WARNING) << "Skipping unknown device, address=" - << ADDRESS_TO_LOGGABLE_STR(evt.remote_bda); + LOG_DEBUG("Skipping unknown device, address= %s", + ADDRESS_TO_LOGGABLE_CSTR(evt.remote_bda)); BTA_GATTC_Close(evt.conn_id); return; } if (evt.status != GATT_SUCCESS) { - DLOG(INFO) << "Failed to connect to server device"; + LOG_ERROR("Failed to connect to server device %s", + ADDRESS_TO_LOGGABLE_CSTR(evt.remote_bda)); if (device->connecting_actively) callbacks_->OnConnectionState(evt.remote_bda, ConnectionState::DISCONNECTED); @@ -1805,19 +1963,26 @@ class CsisClientImpl : public CsisClient { int result = BTM_SetEncryption(device->addr, BT_TRANSPORT_LE, nullptr, nullptr, BTM_BLE_SEC_ENCRYPT); - LOG_INFO("Encryption required. Request result: 0x%02x", result); + + LOG_INFO("Encryption required for %s. Request result: 0x%02x", + ADDRESS_TO_LOGGABLE_CSTR(device->addr), result); + + if (result == BTM_ERR_KEY_MISSING) { + LOG_ERROR("Link key unknown for %s, disconnect profile", + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); + BTA_GATTC_Close(device->conn_id); + } } void OnGattDisconnected(const tBTA_GATTC_CLOSE& evt) { auto device = FindDeviceByAddress(evt.remote_bda); if (device == nullptr) { - LOG(WARNING) << "Skipping unknown device disconnect, conn_id=" - << loghex(evt.conn_id); + LOG_WARN("Skipping unknown device disconnect, conn_id= 0x%04x", + evt.conn_id); return; } - DLOG(INFO) << __func__ << ": device=" - << ADDRESS_TO_LOGGABLE_STR(device->addr); + LOG_DEBUG("device=%s", ADDRESS_TO_LOGGABLE_CSTR(device->addr)); callbacks_->OnConnectionState(evt.remote_bda, ConnectionState::DISCONNECTED); @@ -1846,8 +2011,13 @@ class CsisClientImpl : public CsisClient { auto device = FindDeviceByConnId(evt.conn_id); if (device == nullptr) { - LOG(WARNING) << __func__ << " Skipping unknown device, conn_id=" - << loghex(evt.conn_id); + LOG_WARN("Skipping unknown device, conn_id= 0x%4x", evt.conn_id); + return; + } + + /* verify encryption enabled */ + if (!BTM_IsEncrypted(device->addr, BT_TRANSPORT_LE)) { + LOG_WARN("Device not yet bonded - waiting for encryption"); return; } @@ -1855,13 +2025,13 @@ class CsisClientImpl : public CsisClient { * else?) */ if (!device->is_gatt_service_valid) { if (evt.status != GATT_SUCCESS) { - LOG(ERROR) << __func__ << " Service discovery failed"; + LOG_ERROR("Service discovery failed"); BTA_GATTC_Close(device->conn_id); DoDisconnectCleanUp(device); return; } - DLOG(INFO) << __func__; + LOG_VERBOSE(); const std::list* all_services = BTA_GATTC_GetServices(device->conn_id); @@ -1877,7 +2047,7 @@ class CsisClientImpl : public CsisClient { } if (all_csis_start_handles.size() == 0) { - DLOG(INFO) << __func__ << " No Csis instances found"; + LOG_DEBUG("No Csis instances found"); BTA_GATTC_Close(device->conn_id); RemoveCsisDevice(device, bluetooth::groups::kGroupUnknown); return; @@ -1908,8 +2078,8 @@ class CsisClientImpl : public CsisClient { * As per spec, there can be only one service like this. */ if (all_csis_start_handles.size()) { - DLOG(INFO) << __func__ << " there is " << all_csis_start_handles.size() - << " primary services without a context"; + LOG_DEBUG("there is %d primary services without a context", + static_cast(all_csis_start_handles.size())); auto csis_svrc = BTA_GATTC_GetOwningService(device->conn_id, all_csis_start_handles[0]); instance->OnCsisServiceFound( @@ -1929,8 +2099,8 @@ class CsisClientImpl : public CsisClient { void OnGattNotification(const tBTA_GATTC_NOTIFY& evt) { /* Reject invalid lengths and indications as they are not supported */ if (!evt.is_notify || evt.len > GATT_MAX_ATTR_LEN) { - LOG(ERROR) << __func__ << ": rejected BTA_GATTC_NOTIF_EVT. is_notify = " - << evt.is_notify << ", len=" << static_cast(evt.len); + LOG_ERROR(": rejected BTA_GATTC_NOTIF_EVT. is_notify = %d, len= %d", + evt.is_notify, evt.len); } OnCsisNotification(evt.conn_id, evt.handle, evt.len, evt.value); @@ -1978,7 +2148,7 @@ class CsisClientImpl : public CsisClient { void OnGattServiceChangeEvent(const RawAddress& address) { auto device = FindDeviceByAddress(address); if (!device) { - LOG(WARNING) << "Skipping unknown device" << address; + LOG_WARN("Skipping unknown device %s", ADDRESS_TO_LOGGABLE_CSTR(address)); return; } @@ -1989,11 +2159,11 @@ class CsisClientImpl : public CsisClient { void OnGattServiceDiscoveryDoneEvent(const RawAddress& address) { auto device = FindDeviceByAddress(address); if (!device) { - LOG(WARNING) << "Skipping unknown device" << ADDRESS_TO_LOGGABLE_STR(address); + LOG_WARN("Skipping unknown device %s", ADDRESS_TO_LOGGABLE_CSTR(address)); return; } - DLOG(INFO) << __func__ << ": address=" << ADDRESS_TO_LOGGABLE_STR(address); + LOG_DEBUG("address=%s", ADDRESS_TO_LOGGABLE_CSTR(address)); if (!device->is_gatt_service_valid) BTA_GATTC_ServiceSearchRequest(device->conn_id, &kCsisServiceUuid); @@ -2003,7 +2173,7 @@ class CsisClientImpl : public CsisClient { const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(conn_id, char_handle); if (!p_char) { - LOG(WARNING) << __func__ << ": No such characteristic: " << char_handle; + LOG_WARN("No such characteristic: 0x%04x", char_handle); return GAP_INVALID_HANDLE; } @@ -2020,10 +2190,10 @@ class CsisClientImpl : public CsisClient { if (value_handle != GAP_INVALID_HANDLE) { tGATT_STATUS register_status = BTA_GATTC_RegisterForNotifications(gatt_if_, address, value_handle); - DLOG(INFO) << __func__ << ": BTA_GATTC_RegisterForNotifications, status=" - << loghex(+register_status) - << " value=" << loghex(value_handle) - << " ccc=" << loghex(ccc_handle); + LOG_DEBUG( + "BTA_GATTC_RegisterForNotifications, status=0x%02x, value=%s, " + "ccc=0x%04x", + register_status, loghex(value_handle).c_str(), ccc_handle); if (register_status != GATT_SUCCESS) return; } @@ -2033,10 +2203,10 @@ class CsisClientImpl : public CsisClient { UINT16_TO_STREAM(value_ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION); BtaGattQueue::WriteDescriptor( conn_id, ccc_handle, std::move(value), GATT_WRITE, - [](uint16_t conn_id, tGATT_STATUS status, uint16_t value_handle, - uint16_t len, const uint8_t* value, void* user_data) { + [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, + const uint8_t* value, void* user_data) { if (instance) - instance->OnGattWriteCcc(conn_id, status, value_handle, user_data); + instance->OnGattWriteCcc(conn_id, status, handle, user_data); }, nullptr); } @@ -2046,20 +2216,128 @@ class CsisClientImpl : public CsisClient { if (value_handle != GAP_INVALID_HANDLE) { tGATT_STATUS register_status = BTA_GATTC_DeregisterForNotifications(gatt_if_, address, value_handle); - DLOG(INFO) << __func__ << ": DisableGattNotification, status=" - << loghex(+register_status) - << " value=" << loghex(value_handle); + LOG_DEBUG("DisableGattNotification, status=0x%02x, value_handle=0x%04x", + register_status, value_handle); if (register_status != GATT_SUCCESS) return; } } + void SirkValueReadCompleteDuringPairing(tGATT_STATUS status, + const RawAddress& address, + uint8_t sirk_type, + Octet16& received_sirk) { + LOG_INFO("%s, status: 0x%02x", ADDRESS_TO_LOGGABLE_CSTR(address), status); + + auto device = FindDeviceByAddress(address); + if (device == nullptr) { + LOG_ERROR("Unknown device %s", ADDRESS_TO_LOGGABLE_CSTR(address)); + BTA_DmSirkConfirmDeviceReply(address, false); + return; + } + + auto group_id_to_join = device->GetExpectedGroupIdMember(); + device->SetPairingSirkReadFlag(false); + + /* Verify group still exist, if not it means user forget the group and + * paring should be rejected. + */ + auto csis_group = FindCsisGroup(group_id_to_join); + if (!csis_group) { + LOG_ERROR("Group %d removed during paring a set member", + group_id_to_join); + RemoveDevice(address); + BTA_DmSirkConfirmDeviceReply(address, false); + return; + } + + if (status != GATT_SUCCESS) { + LOG_INFO("Invalid member, can't read SIRK (status: 0x%02x)", status); + BTA_DmSirkConfirmDeviceReply(address, false); + return; + } + + /* Verify if sirk is not all zeros */ + Octet16 zero{}; + if (memcmp(zero.data(), received_sirk.data(), 16) == 0) { + LOG_ERROR("Received invalid zero SIRK address: %s ", + ADDRESS_TO_LOGGABLE_CSTR(address)); + BTA_DmSirkConfirmDeviceReply(address, false); + return; + } + + if (sirk_type == bluetooth::csis::kCsisSirkTypeEncrypted) { + /* Decrypt encrypted SIRK */ + Octet16 sirk; + sdf(address, received_sirk, sirk); + received_sirk = sirk; + } + + if (!csis_group->IsSirkBelongsToGroup(received_sirk)) { + /* + * Joining member must join already existing group otherwise it means + * that its SIRK is different. Device connection was triggered by RSI + * match for group. + */ + LOG_ERROR("Joining device %s, does not match any existig group", + ADDRESS_TO_LOGGABLE_CSTR(address)); + BTA_DmSirkConfirmDeviceReply(address, false); + return; + } + + LOG_INFO("Device %s, verified successfully by SIRK", + ADDRESS_TO_LOGGABLE_CSTR(address)); + BTA_DmSirkConfirmDeviceReply(address, true); + + /* It was temporary device and we can remove it. When upper layer + * decides to connect CSIS it will be added then + */ + RemoveDevice(address); + } + + void VerifySetMember(const RawAddress& address) { + auto device = FindDeviceByAddress(address); + + LOG_INFO("Device: %s", ADDRESS_TO_LOGGABLE_CSTR(address)); + + /* It's ok for device to not be a CSIS device at all */ + if (!device) { + LOG_INFO("Valid - new member"); + BTA_DmSirkConfirmDeviceReply(address, true); + return; + } + + auto group_id_to_join = device->GetExpectedGroupIdMember(); + if (group_id_to_join == bluetooth::groups::kGroupUnknown) { + LOG_WARN( + "Device %s (conn_id=0x%04x) is already known to CSIS (# of " + "instances=%d) but it is " + "not scheduled to join any group.", + ADDRESS_TO_LOGGABLE_CSTR(address), device->conn_id, + device->GetNumberOfCsisInstances()); + BTA_DmSirkConfirmDeviceReply(address, true); + return; + } + + if (!gatt_cl_read_sirk_req( + address, + base::BindOnce(&CsisClientImpl::SirkValueReadCompleteDuringPairing, + weak_factory_.GetWeakPtr()))) { + LOG_ERROR("Could not read SIKR of %s", ADDRESS_TO_LOGGABLE_CSTR(address)); + BTA_DmSirkConfirmDeviceReply(address, false); + return; + } + device->SetPairingSirkReadFlag(true); + } + uint8_t gatt_if_; bluetooth::csis::CsisClientCallbacks* callbacks_; std::list> devices_; std::list> csis_groups_; DeviceGroups* dev_groups_; int discovering_group_ = bluetooth::groups::kGroupUnknown; + + base::WeakPtrFactory weak_factory_{this}; }; class DeviceGroupsCallbacksImpl : public DeviceGroupsCallbacks { @@ -2097,7 +2375,7 @@ void CsisClient::Initialize(bluetooth::csis::CsisClientCallbacks* callbacks, Closure initCb) { std::scoped_lock lock(instance_mutex); if (instance) { - LOG(ERROR) << __func__ << ": Already initialized!"; + LOG_INFO("Already initialized!"); return; } @@ -2116,7 +2394,7 @@ void CsisClient::AddFromStorage(const RawAddress& addr, const std::vector& in, bool autoconnect) { if (!instance) { - LOG(ERROR) << __func__ << ": Not initialized yet!"; + LOG_ERROR("Not initialized yet!"); return; } @@ -2126,7 +2404,7 @@ void CsisClient::AddFromStorage(const RawAddress& addr, bool CsisClient::GetForStorage(const RawAddress& addr, std::vector& out) { if (!instance) { - LOG(ERROR) << __func__ << ": Not initialized yet"; + LOG_ERROR("Not initialized yet!"); return false; } @@ -2135,6 +2413,7 @@ bool CsisClient::GetForStorage(const RawAddress& addr, void CsisClient::CleanUp() { std::scoped_lock lock(instance_mutex); + BTA_DmSirkSecCbRegister(nullptr); CsisClientImpl* ptr = instance; instance = nullptr; diff --git a/system/bta/csis/csis_client_test.cc b/system/bta/csis/csis_client_test.cc index f83758cfdb0aec1fbe6cae454ed831675bf8ff3e..b2cd110d422a9f06c1713d2f12247d8af2c70fb2 100644 --- a/system/bta/csis/csis_client_test.cc +++ b/system/bta/csis/csis_client_test.cc @@ -24,13 +24,23 @@ #include "bta_dm_api_mock.h" #include "bta_gatt_api_mock.h" #include "bta_gatt_queue_mock.h" +#include "bta_le_audio_uuids.h" #include "btif_profile_storage.h" #include "btm_api_mock.h" #include "csis_types.h" #include "gatt/database_builder.h" #include "hardware/bt_gatt_types.h" +#include "stack/include/bt_uuid16.h" #include "test/common/mock_functions.h" +bool gatt_cl_read_sirk_req( + const RawAddress& peer_bda, + base::OnceCallback + cb) { + return true; +} + namespace bluetooth { namespace csis { namespace internal { @@ -48,6 +58,7 @@ using bluetooth::csis::CsisGroupLockStatus; using bluetooth::groups::DeviceGroups; using testing::_; +using testing::AtLeast; using testing::DoAll; using testing::DoDefault; using testing::Invoke; @@ -116,6 +127,92 @@ class MockCsisCallbacks : public CsisClientCallbacks { class CsisClientTest : public ::testing::Test { private: + void set_sample_cap_included_database(uint16_t conn_id, bool csis, + bool csis_broken, uint8_t rank, + uint8_t sirk_msb = 1) { + gatt::DatabaseBuilder builder; + builder.AddService(0x0001, 0x0003, Uuid::From16Bit(0x1800), true); + builder.AddCharacteristic(0x0002, 0x0003, Uuid::From16Bit(0x2a00), + GATT_CHAR_PROP_BIT_READ); + if (csis) { + builder.AddService(0x0005, 0x0009, + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE), + true); + builder.AddIncludedService(0x0006, kCsisServiceUuid, 0x0010, 0x0030); + + builder.AddService(0x0010, 0x0030, kCsisServiceUuid, true); + builder.AddCharacteristic( + 0x0020, 0x0021, kCsisSirkUuid, + GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY); + + builder.AddDescriptor(0x0022, + Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)); + builder.AddCharacteristic( + 0x0023, 0x0024, kCsisSizeUuid, + GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY); + builder.AddDescriptor(0x0025, + Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)); + builder.AddCharacteristic(0x0026, 0x0027, kCsisLockUuid, + GATT_CHAR_PROP_BIT_READ | + GATT_CHAR_PROP_BIT_NOTIFY | + GATT_CHAR_PROP_BIT_WRITE); + builder.AddDescriptor(0x0028, + Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)); + builder.AddCharacteristic(0x0029, 0x0030, kCsisRankUuid, + GATT_CHAR_PROP_BIT_READ); + } + if (csis_broken) { + builder.AddCharacteristic( + 0x0020, 0x0021, kCsisSirkUuid, + GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY); + + builder.AddDescriptor(0x0022, + Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)); + } + builder.AddService(0x0090, 0x0093, + Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER), true); + builder.AddCharacteristic(0x0091, 0x0092, + Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD), + GATT_CHAR_PROP_BIT_NOTIFY); + builder.AddDescriptor(0x0093, + Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)); + services_map[conn_id] = builder.Build().Services(); + + ON_CALL(gatt_queue, ReadCharacteristic(conn_id, _, _, _)) + .WillByDefault( + Invoke([rank, sirk_msb](uint16_t conn_id, uint16_t handle, + GATT_READ_OP_CB cb, void* cb_data) -> void { + std::vector value; + + switch (handle) { + case 0x0003: + /* device name */ + value.resize(20); + break; + case 0x0021: + value.assign(17, 1); + value[16] = sirk_msb; + break; + case 0x0024: + value.resize(1); + break; + case 0x0027: + value.resize(1); + break; + case 0x0030: + value.resize(1); + value.assign(1, rank); + break; + default: + FAIL(); + return; + } + + cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), + cb_data); + })); + } + void set_sample_database(uint16_t conn_id, bool csis, bool csis_broken, uint8_t rank, uint8_t sirk_msb = 1) { gatt::DatabaseBuilder builder; @@ -334,6 +431,9 @@ class CsisClientTest : public ::testing::Test { SetMockCsisLockCallback(&csis_lock_cb); callbacks.reset(new MockCsisCallbacks()); + ON_CALL(btm_interface, BTM_IsEncrypted(_, _)) + .WillByDefault(DoAll(Return(true))); + ON_CALL(gatt_interface, GetCharacteristic(_, _)) .WillByDefault( Invoke([&](uint16_t conn_id, @@ -419,11 +519,11 @@ class CsisClientTest : public ::testing::Test { gatt_callback = nullptr; } - void TestConnect(const RawAddress& address) { + void TestConnect(const RawAddress& address, bool encrypted = true) { // by default indicate link as encrypted ON_CALL(btm_interface, GetSecurityFlagsByTransport(address, NotNull(), _)) .WillByDefault( - DoAll(SetArgPointee<1>(BTM_SEC_FLAG_ENCRYPTED), Return(true))); + DoAll(SetArgPointee<1>(BTM_SEC_FLAG_ENCRYPTED), Return(encrypted))); EXPECT_CALL(gatt_interface, Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, _)); @@ -444,19 +544,28 @@ class CsisClientTest : public ::testing::Test { } void TestAddFromStorage(const RawAddress& address, uint16_t conn_id, + std::vector& storage_group_buf, std::vector& storage_buf) { EXPECT_CALL(*callbacks, OnConnectionState(address, ConnectionState::CONNECTED)) .Times(1); - EXPECT_CALL(*callbacks, OnDeviceAvailable(address, _, _, _, _)).Times(1); + EXPECT_CALL(*callbacks, OnDeviceAvailable(address, _, _, _, _)) + .Times(AtLeast(1)); + + /* In testing only whe set info is empty, there is no CAP context. */ + bool is_opportunistic = (storage_buf.size() != 0); + EXPECT_CALL(gatt_interface, - Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, _)) + Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, + is_opportunistic)) .WillOnce(Invoke([this, conn_id](tGATT_IF client_if, const RawAddress& remote_bda, bool is_direct, bool opportunistic) { InjectConnectedEvent(remote_bda, conn_id); GetSearchCompleteEvent(conn_id); })); + + DeviceGroups::AddFromStorage(address, storage_group_buf); CsisClient::AddFromStorage(address, storage_buf, true); } @@ -486,8 +595,8 @@ class CsisClientTest : public ::testing::Test { const RawAddress& address, uint16_t conn_id, tGATT_DISCONN_REASON reason = GATT_CONN_TERMINATE_PEER_USER) { tBTA_GATTC_CLOSE event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, .client_if = gatt_if, .remote_bda = address, .reason = reason, @@ -498,8 +607,8 @@ class CsisClientTest : public ::testing::Test { void GetSearchCompleteEvent(uint16_t conn_id) { tBTA_GATTC_SEARCH_CMPL event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, }; gatt_callback(BTA_GATTC_SEARCH_CMPL_EVT, (tBTA_GATTC*)&event_data); @@ -523,10 +632,46 @@ class CsisClientTest : public ::testing::Test { TestAppUnregister(); } + void TestGattWriteCCC(uint16_t ccc_handle, GattStatus status, + int deregister_times) { + SetSampleDatabaseCsis(1, 1); + TestAppRegister(); + TestConnect(test_address); + InjectConnectedEvent(test_address, 1); + + auto WriteDescriptorCbGenerator = [](tGATT_STATUS status, + uint16_t ccc_handle) { + return [status, ccc_handle](uint16_t conn_id, uint16_t handle, + std::vector value, + tGATT_WRITE_TYPE write_type, + GATT_WRITE_OP_CB cb, void* cb_data) -> void { + if (cb) { + if (ccc_handle) { + handle = ccc_handle; + } + cb(conn_id, status, handle, value.size(), value.data(), cb_data); + } + }; + }; + + // sirk, size, lock + EXPECT_CALL(gatt_queue, WriteDescriptor(_, _, _, _, _, _)) + .Times(3) + .WillOnce(Invoke(WriteDescriptorCbGenerator(GATT_SUCCESS, 0))) + .WillOnce(Invoke(WriteDescriptorCbGenerator(GATT_SUCCESS, 0))) + .WillOnce(Invoke(WriteDescriptorCbGenerator(status, ccc_handle))); + + EXPECT_CALL(gatt_interface, DeregisterForNotifications(_, _, _)) + .Times(deregister_times); + + GetSearchCompleteEvent(1); + Mock::VerifyAndClearExpectations(&gatt_interface); + } + void GetDisconnectedEvent(const RawAddress& address, uint16_t conn_id) { tBTA_GATTC_CLOSE event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, .client_if = gatt_if, .remote_bda = address, .reason = GATT_CONN_TERMINATE_PEER_USER, @@ -535,21 +680,10 @@ class CsisClientTest : public ::testing::Test { gatt_callback(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC*)&event_data); } - void SetEncryptionResult(const RawAddress& address, uint16_t conn_id, - bool success) { - ON_CALL(btm_interface, BTM_IsEncrypted(address, _)) - .WillByDefault(DoAll(Return(success))); - - ON_CALL(btm_interface, SetEncryption(address, _, _, _, _)) - .WillByDefault( - Invoke([&](const RawAddress& bd_addr, tBT_TRANSPORT transport, - tBTM_SEC_CALLBACK* p_callback, void* p_ref_data, - tBTM_BLE_SEC_ACT sec_act) -> tBTM_STATUS { - InjectEncryptionEvent(bd_addr, conn_id); - return BTM_SUCCESS; - })); + void SetSampleCapIncludedDatabaseCsis(uint16_t conn_id, uint8_t rank, + uint8_t sirk_msb = 1) { + set_sample_cap_included_database(conn_id, true, false, rank, sirk_msb); } - void SetSampleDatabaseCsis(uint16_t conn_id, uint8_t rank, uint8_t sirk_msb = 1) { set_sample_database(conn_id, true, false, rank, sirk_msb); @@ -686,6 +820,24 @@ TEST_F(CsisClientTest, test_discovery_csis_broken) { TestAppUnregister(); } +TEST_F(CsisClientTest, test_ccc_reg_fail_handle_not_found) { + // service handle range: 0x0001 ~ 0x0030 + uint16_t not_existed_ccc_handle = 0x0031; + TestGattWriteCCC(not_existed_ccc_handle, GATT_INVALID_HANDLE, 0); +} + +TEST_F(CsisClientTest, test_ccc_reg_fail_handle_found) { + // kCsisLockUuid ccc handle + uint16_t existed_ccc_hande = 0x0028; + TestGattWriteCCC(existed_ccc_hande, GATT_INVALID_HANDLE, 1); +} + +TEST_F(CsisClientTest, test_ccc_reg_fail_out_of_sync) { + // kCsisLockUuid ccc handle + uint16_t ccc_handle = 0x0028; + TestGattWriteCCC(ccc_handle, GATT_DATABASE_OUT_OF_SYNC, 0); +} + class CsisClientCallbackTest : public CsisClientTest { protected: const RawAddress test_address = GetTestAddress(0); @@ -751,6 +903,64 @@ TEST_F(CsisClientTest, test_get_group_id) { TestAppUnregister(); } +TEST_F(CsisClientTest, test_search_complete_before_encryption) { + SetSampleDatabaseCsis(1, 1); + TestAppRegister(); + TestConnect(test_address, false); + EXPECT_CALL(*callbacks, + OnConnectionState(test_address, ConnectionState::CONNECTED)) + .Times(0); + EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _, _, _, _)).Times(0); + + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)) + .WillByDefault(DoAll(Return(false))); + + InjectConnectedEvent(test_address, 1); + GetSearchCompleteEvent(1); + Mock::VerifyAndClearExpectations(callbacks.get()); + + /* Incject encryption and expect device connection */ + EXPECT_CALL(*callbacks, + OnConnectionState(test_address, ConnectionState::CONNECTED)) + .Times(1); + EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _, _, _, _)).Times(1); + + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)) + .WillByDefault(DoAll(Return(true))); + EXPECT_CALL(gatt_interface, ServiceSearchRequest(_, _)).Times(1); + + InjectEncryptionEvent(test_address, 1); + GetSearchCompleteEvent(1); + + Mock::VerifyAndClearExpectations(&gatt_interface); + Mock::VerifyAndClearExpectations(callbacks.get()); + + TestAppUnregister(); +} + +TEST_F(CsisClientTest, test_disconnect_when_link_key_is_gone) { + SetSampleDatabaseCsis(1, 1); + TestAppRegister(); + TestConnect(test_address, false); + EXPECT_CALL(*callbacks, + OnConnectionState(test_address, ConnectionState::CONNECTED)) + .Times(0); + + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)) + .WillByDefault(DoAll(Return(false))); + ON_CALL(btm_interface, SetEncryption(test_address, _, _, _, _)) + .WillByDefault(Return(BTM_ERR_KEY_MISSING)); + + EXPECT_CALL(gatt_interface, Close(1)); + + InjectConnectedEvent(test_address, 1); + + Mock::VerifyAndClearExpectations(&gatt_interface); + Mock::VerifyAndClearExpectations(callbacks.get()); + + TestAppUnregister(); +} + TEST_F(CsisClientTest, test_is_group_empty) { std::list> csis_groups_; auto g_1 = std::make_shared(666, bluetooth::Uuid::kEmpty); @@ -877,6 +1087,40 @@ TEST_F(CsisClientTest, test_get_set_sirk) { ASSERT_EQ(g_1->GetSirk(), sirk); } +TEST_F(CsisClientTest, test_csis_member_not_found) { + EXPECT_CALL(dm_interface, BTA_DmBleCsisObserve(true, _)).Times(1); + SetSampleDatabaseDoubleCsis(0x001, 1, 2); + TestAppRegister(); + + /* Here we handle Background Scan request */ + Mock::VerifyAndClearExpectations(&dm_interface); + + tBTA_DM_SEARCH_CBACK* p_results_cb = nullptr; + /* Here is actual Active Scan request */ + EXPECT_CALL(dm_interface, BTA_DmBleCsisObserve(true, _)) + .WillOnce(DoAll(SaveArg<1>(&p_results_cb))); + + TestConnect(test_address); + InjectConnectedEvent(test_address, 1); + GetSearchCompleteEvent(1); + + Mock::VerifyAndClearExpectations(&dm_interface); + /* Verify that scanner has been called to start filtering */ + ASSERT_EQ(1, get_func_call_count("set_empty_filter")); + + /* Check callback is not null and simulate no member found and scan + * completed*/ + ASSERT_NE(p_results_cb, nullptr); + + tBTA_DM_SEARCH result; + result.inq_cmpl.num_resps = 80; + + p_results_cb(BTA_DM_INQ_CMPL_EVT, &result); + + /* Verify that scanner has been called to stop filtering */ + ASSERT_EQ(2, get_func_call_count("set_empty_filter")); +} + class CsisMultiClientTest : public CsisClientTest { protected: const RawAddress test_address_1 = GetTestAddress(1); @@ -1064,30 +1308,33 @@ TEST_F(CsisClientTest, test_storage_calls) { TEST_F(CsisClientTest, test_storage_content) { // Two devices in one set - SetSampleDatabaseCsis(1, 1); - SetSampleDatabaseCsis(2, 2); + SetSampleCapIncludedDatabaseCsis(1, 1); + SetSampleCapIncludedDatabaseCsis(2, 2); // Devices in the other set - SetSampleDatabaseCsis(3, 1, 2); - SetSampleDatabaseCsis(4, 1, 2); + SetSampleCapIncludedDatabaseCsis(3, 1, 2); + SetSampleCapIncludedDatabaseCsis(4, 1, 3); TestAppRegister(); TestConnect(GetTestAddress(1)); InjectConnectedEvent(GetTestAddress(1), 1); GetSearchCompleteEvent(1); ASSERT_EQ(1, CsisClient::Get()->GetGroupId( - GetTestAddress(1), bluetooth::Uuid::From16Bit(0x0000))); + GetTestAddress(1), + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE))); TestConnect(GetTestAddress(2)); InjectConnectedEvent(GetTestAddress(2), 2); GetSearchCompleteEvent(2); ASSERT_EQ(1, CsisClient::Get()->GetGroupId( - GetTestAddress(2), bluetooth::Uuid::From16Bit(0x0000))); + GetTestAddress(2), + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE))); TestConnect(GetTestAddress(3)); InjectConnectedEvent(GetTestAddress(3), 3); GetSearchCompleteEvent(3); ASSERT_EQ(2, CsisClient::Get()->GetGroupId( - GetTestAddress(3), bluetooth::Uuid::From16Bit(0x0000))); + GetTestAddress(3), + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE))); std::vector dev1_storage; std::vector dev2_storage; @@ -1097,10 +1344,23 @@ TEST_F(CsisClientTest, test_storage_content) { CsisClient::GetForStorage(GetTestAddress(1), dev1_storage); CsisClient::GetForStorage(GetTestAddress(2), dev2_storage); CsisClient::GetForStorage(GetTestAddress(3), dev3_storage); + ASSERT_NE(0u, dev1_storage.size()); ASSERT_NE(0u, dev2_storage.size()); ASSERT_NE(0u, dev3_storage.size()); + std::vector dev1_group_storage; + std::vector dev2_group_storage; + std::vector dev3_group_storage; + + DeviceGroups::GetForStorage(GetTestAddress(1), dev1_group_storage); + DeviceGroups::GetForStorage(GetTestAddress(2), dev2_group_storage); + DeviceGroups::GetForStorage(GetTestAddress(3), dev3_group_storage); + + ASSERT_NE(0u, dev1_group_storage.size()); + ASSERT_NE(0u, dev2_group_storage.size()); + ASSERT_NE(0u, dev3_group_storage.size()); + // Clean it up TestAppUnregister(); @@ -1108,25 +1368,29 @@ TEST_F(CsisClientTest, test_storage_content) { TestAppRegister(); // Restore dev1 from the byte buffer - TestAddFromStorage(GetTestAddress(1), 1, dev1_storage); + TestAddFromStorage(GetTestAddress(1), 1, dev1_group_storage, dev1_storage); ASSERT_EQ(1, CsisClient::Get()->GetGroupId( - GetTestAddress(1), bluetooth::Uuid::From16Bit(0x0000))); + GetTestAddress(1), + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE))); // Restore dev2 from the byte buffer - TestAddFromStorage(GetTestAddress(2), 2, dev2_storage); + TestAddFromStorage(GetTestAddress(2), 2, dev2_group_storage, dev2_storage); ASSERT_EQ(1, CsisClient::Get()->GetGroupId( - GetTestAddress(2), bluetooth::Uuid::From16Bit(0x0000))); + GetTestAddress(2), + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE))); // Restore dev3 from the byte buffer - TestAddFromStorage(GetTestAddress(3), 3, dev3_storage); + TestAddFromStorage(GetTestAddress(3), 3, dev3_group_storage, dev3_storage); ASSERT_EQ(2, CsisClient::Get()->GetGroupId( - GetTestAddress(3), bluetooth::Uuid::From16Bit(0x0000))); + GetTestAddress(3), + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE))); // Restore not inerrogated dev4 - empty buffer but valid sirk for group 2 std::vector no_set_info; - TestAddFromStorage(GetTestAddress(4), 4, no_set_info); - ASSERT_EQ(2, CsisClient::Get()->GetGroupId( - GetTestAddress(4), bluetooth::Uuid::From16Bit(0x0000))); + TestAddFromStorage(GetTestAddress(4), 4, no_set_info, no_set_info); + ASSERT_EQ(3, CsisClient::Get()->GetGroupId( + GetTestAddress(4), + bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE))); TestAppUnregister(); } diff --git a/system/bta/csis/csis_types.h b/system/bta/csis/csis_types.h index cf84ade58df6229a124bdfdcdda8bf7d527fa678..25b43a60633210e92372c6e4cde651c869d80eb3 100644 --- a/system/bta/csis/csis_types.h +++ b/system/bta/csis/csis_types.h @@ -27,10 +27,13 @@ #include "bta_gatt_api.h" #include "bta_groups.h" #include "btif_storage.h" +#include "common/init_flags.h" +#include "common/strings.h" +#include "crypto_toolbox/crypto_toolbox.h" #include "gap_api.h" -#include "gd/common/init_flags.h" -#include "gd/common/strings.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" + +// Uncomment to debug SIRK calculations +// #define CSIS_DEBUG namespace bluetooth { namespace csis { @@ -39,7 +42,8 @@ using bluetooth::csis::CsisLockCb; // CSIP additions /* Generic UUID is used when CSIS is not included in any context */ -static const bluetooth::Uuid kCsisServiceUuid = bluetooth::Uuid::From16Bit(0x1846); +static const bluetooth::Uuid kCsisServiceUuid = + bluetooth::Uuid::From16Bit(0x1846); static const bluetooth::Uuid kCsisSirkUuid = bluetooth::Uuid::From16Bit(0x2B84); static const bluetooth::Uuid kCsisSizeUuid = bluetooth::Uuid::From16Bit(0x2B85); static const bluetooth::Uuid kCsisLockUuid = bluetooth::Uuid::From16Bit(0x2B86); @@ -57,7 +61,8 @@ static constexpr uint8_t kCsisSirkCharLen = 17; struct hdl_pair { hdl_pair() {} - hdl_pair(uint16_t val_hdl, uint16_t ccc_hdl) : val_hdl(val_hdl), ccc_hdl(ccc_hdl) {} + hdl_pair(uint16_t val_hdl, uint16_t ccc_hdl) + : val_hdl(val_hdl), ccc_hdl(ccc_hdl) {} uint16_t val_hdl; uint16_t ccc_hdl; @@ -158,7 +163,8 @@ class CsisInstance { {GAP_INVALID_HANDLE, GAP_INVALID_HANDLE}, }; - CsisInstance(uint16_t start_handle, uint16_t end_handle, const bluetooth::Uuid& uuid) + CsisInstance(uint16_t start_handle, uint16_t end_handle, + const bluetooth::Uuid& uuid) : coordinated_service(uuid), group_id_(bluetooth::groups::kGroupUnknown), rank_(kUnknownRank), @@ -168,21 +174,21 @@ class CsisInstance { } void SetLockState(CsisLockState state) { - DLOG(INFO) << __func__ << " current lock state: " << (int)(lock_state_) - << " new lock state: " << (int)(state); + LOG_DEBUG("current lock state: %d, new lock state: %d", + static_cast(lock_state_), static_cast(state)); lock_state_ = state; } CsisLockState GetLockState(void) const { return lock_state_; } uint8_t GetRank(void) const { return rank_; } void SetRank(uint8_t rank) { - DLOG(INFO) << __func__ << " current rank state: " << loghex(rank_) - << " new rank state: " << loghex(rank); + LOG_DEBUG("current rank: %d, new rank: %d", static_cast(rank_), + static_cast(rank)); rank_ = rank; } void SetGroupId(int group_id) { - LOG(INFO) << __func__ << " set group id: " << group_id - << " instance handle: " << loghex(svc_data.start_handle); + LOG_INFO("set group id: %d, instance handle: 0x%04x", group_id, + svc_data.start_handle); group_id_ = group_id; } @@ -193,7 +199,9 @@ class CsisInstance { } const bluetooth::Uuid& GetUuid(void) const { return coordinated_service; } - bool IsForUuid(const bluetooth::Uuid& uuid) const { return coordinated_service == uuid; } + bool IsForUuid(const bluetooth::Uuid& uuid) const { + return coordinated_service == uuid; + } private: int group_id_; @@ -220,12 +228,30 @@ class CsisDevice : public GattServiceDevice { csis_instances_.clear(); } + uint16_t FindValueHandleByCccHandle(uint16_t ccc_handle) { + uint16_t val_handle = 0; + for (const auto& [_, inst] : csis_instances_) { + if (inst->svc_data.sirk_handle.ccc_hdl == ccc_handle) { + val_handle = inst->svc_data.sirk_handle.val_hdl; + } else if (inst->svc_data.lock_handle.ccc_hdl == ccc_handle) { + val_handle = inst->svc_data.lock_handle.val_hdl; + } else if (inst->svc_data.size_handle.ccc_hdl == ccc_handle) { + val_handle = inst->svc_data.size_handle.val_hdl; + } + if (val_handle) { + break; + } + } + return val_handle; + } + std::shared_ptr GetCsisInstanceByOwningHandle(uint16_t handle) { uint16_t hdl = 0; for (const auto& [h, inst] : csis_instances_) { - if (handle >= inst->svc_data.start_handle && handle <= inst->svc_data.end_handle) { + if (handle >= inst->svc_data.start_handle && + handle <= inst->svc_data.end_handle) { hdl = h; - DLOG(INFO) << __func__ << " found " << loghex(hdl); + LOG_VERBOSE("found 0x%04x", hdl); break; } } @@ -243,15 +269,17 @@ class CsisDevice : public GattServiceDevice { return (hdl > 0) ? csis_instances_.at(hdl) : nullptr; } - void SetCsisInstance(uint16_t handle, std::shared_ptr csis_instance) { + void SetCsisInstance(uint16_t handle, + std::shared_ptr csis_instance) { if (csis_instances_.count(handle)) { - DLOG(INFO) << __func__ << " instance is already here: " << csis_instance->GetUuid(); + LOG_DEBUG("instance is already here: %s", + csis_instance->GetUuid().ToString().c_str()); return; } csis_instances_.insert({handle, csis_instance}); - DLOG(INFO) << __func__ << " instance added: " << loghex(handle) - << "device: " << ADDRESS_TO_LOGGABLE_STR(addr); + LOG_DEBUG("instance added: 0x%04x, device %s", handle, + ADDRESS_TO_LOGGABLE_CSTR(addr)); } void RemoveCsisInstance(int group_id) { @@ -265,15 +293,33 @@ class CsisDevice : public GattServiceDevice { int GetNumberOfCsisInstances(void) { return csis_instances_.size(); } - void ForEachCsisInstance(std::function&)> cb) { + void ForEachCsisInstance( + std::function&)> cb) { for (auto const& kv_pair : csis_instances_) { cb(kv_pair.second); } } + void SetExpectedGroupIdMember(int group_id) { + LOG_INFO("Expected Group ID: %d, for member: %s is set", group_id, + ADDRESS_TO_LOGGABLE_CSTR(addr)); + expected_group_id_member_ = group_id; + } + + void SetPairingSirkReadFlag(bool flag) { + LOG_INFO("Pairing flag for Group ID: %d, member: %s is set to %d", + expected_group_id_member_, ADDRESS_TO_LOGGABLE_CSTR(addr), flag); + pairing_sirk_read_flag_ = flag; + } + + inline int GetExpectedGroupIdMember() { return expected_group_id_member_; } + inline bool GetPairingSirkReadFlag() { return pairing_sirk_read_flag_; } + private: /* Instances per start handle */ std::map> csis_instances_; + int expected_group_id_member_ = bluetooth::groups::kGroupUnknown; + bool pairing_sirk_read_flag_ = false; }; /* @@ -300,15 +346,16 @@ class CsisGroup { bt_bdname_t model_name_val = {0}; void AddDevice(std::shared_ptr csis_device) { - auto it = - find_if(devices_.begin(), devices_.end(), CsisDevice::MatchAddress(csis_device->addr)); + auto it = find_if(devices_.begin(), devices_.end(), + CsisDevice::MatchAddress(csis_device->addr)); if (it != devices_.end()) return; devices_.push_back(std::move(csis_device)); } void RemoveDevice(const RawAddress& bd_addr) { - auto it = find_if(devices_.begin(), devices_.end(), CsisDevice::MatchAddress(bd_addr)); + auto it = find_if(devices_.begin(), devices_.end(), + CsisDevice::MatchAddress(bd_addr)); if (it != devices_.end()) devices_.erase(it); } @@ -322,16 +369,20 @@ class CsisGroup { bool IsEmpty(void) const { return devices_.empty(); } bool IsDeviceInTheGroup(std::shared_ptr& csis_device) { - auto it = - find_if(devices_.begin(), devices_.end(), CsisDevice::MatchAddress(csis_device->addr)); + auto it = find_if(devices_.begin(), devices_.end(), + CsisDevice::MatchAddress(csis_device->addr)); return (it != devices_.end()); } - bool IsRsiMatching(const RawAddress& rsi) const { return is_rsi_match_sirk(rsi, GetSirk()); } - bool IsSirkBelongsToGroup(Octet16 sirk) const { return (sirk_available_ && sirk_ == sirk); } + bool IsRsiMatching(const RawAddress& rsi) const { + return is_rsi_match_sirk(rsi, GetSirk()); + } + bool IsSirkBelongsToGroup(Octet16 sirk) const { + return (sirk_available_ && sirk_ == sirk); + } Octet16 GetSirk(void) const { return sirk_; } void SetSirk(Octet16& sirk) { if (sirk_available_) { - DLOG(INFO) << __func__ << " Updating SIRK"; + LOG_DEBUG("Updating SIRK"); } sirk_available_ = true; sirk_ = sirk; @@ -342,16 +393,20 @@ class CsisGroup { [](auto& d) { return d->IsConnected(); }); } - CsisDiscoveryState GetDiscoveryState(void) const { return member_discovery_state_; } + CsisDiscoveryState GetDiscoveryState(void) const { + return member_discovery_state_; + } void SetDiscoveryState(CsisDiscoveryState state) { - DLOG(INFO) << __func__ << " current discovery state: " << (int)(member_discovery_state_) - << " new discovery state: " << (int)(state); + LOG_DEBUG("current discovery state: %d, new discovery state: %d", + static_cast(member_discovery_state_), + static_cast(state)); member_discovery_state_ = state; } void SetCurrentLockState(CsisLockState state) { lock_state_ = state; } - void SetTargetLockState(CsisLockState state, CsisLockCb cb = base::DoNothing()) { + void SetTargetLockState(CsisLockState state, + CsisLockCb cb = base::DoNothing()) { target_lock_state_ = state; cb_ = std::move(cb); switch (state) { @@ -410,19 +465,23 @@ class CsisGroup { auto inst2 = dev2->GetCsisInstanceByGroupId(id); if (!inst1 || !inst2) { /* One of the device is not connected */ - DLOG(INFO) << __func__ << " one of the device is not connected: inst1: " << inst1 - << " inst2: " << inst2; + LOG_DEBUG("Device %s is not connected.", + inst1 == nullptr ? ADDRESS_TO_LOGGABLE_CSTR(dev1->addr) + : ADDRESS_TO_LOGGABLE_CSTR(dev2->addr)); return dev1->IsConnected(); } return (inst1->GetRank() < inst2->GetRank()); }); } - std::shared_ptr GetFirstDevice(void) { return (devices_.front()); } + std::shared_ptr GetFirstDevice(void) { + return (devices_.front()); + } std::shared_ptr GetLastDevice(void) { return (devices_.back()); } - std::shared_ptr GetNextDevice(std::shared_ptr& device) { - auto iter = - std::find_if(devices_.begin(), devices_.end(), CsisDevice::MatchAddress(device->addr)); + std::shared_ptr GetNextDevice( + std::shared_ptr& device) { + auto iter = std::find_if(devices_.begin(), devices_.end(), + CsisDevice::MatchAddress(device->addr)); /* If reference device not found */ if (iter == devices_.end()) return nullptr; @@ -433,9 +492,10 @@ class CsisGroup { return (*iter); } - std::shared_ptr GetPrevDevice(std::shared_ptr& device) { - auto iter = - std::find_if(devices_.rbegin(), devices_.rend(), CsisDevice::MatchAddress(device->addr)); + std::shared_ptr GetPrevDevice( + std::shared_ptr& device) { + auto iter = std::find_if(devices_.rbegin(), devices_.rend(), + CsisDevice::MatchAddress(device->addr)); /* If reference device not found */ if (iter == devices_.rend()) return nullptr; @@ -456,23 +516,29 @@ class CsisGroup { * Resolving Key |sirk| */ static bool is_rsi_match_sirk(const RawAddress& rsi, const Octet16& sirk) { /* use the 3 MSB of bd address as prand */ - uint8_t rand[3]; + Octet16 rand{}; rand[0] = rsi.address[2]; rand[1] = rsi.address[1]; rand[2] = rsi.address[0]; - DLOG(INFO) << "Prand " << base::HexEncode(rand, 3); +#ifdef CSIS_DEBUG + LOG_INFO("Prand %s", base::HexEncode(rand.data(), 3).c_str()); + LOG_INFO("SIRK %s", base::HexEncode(sirk.data(), 16).c_str()); +#endif - DLOG(INFO) << "SIRK " << base::HexEncode(sirk.data(), 16); /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */ - Octet16 x = crypto_toolbox::aes_128(sirk, &rand[0], 3); + Octet16 x = crypto_toolbox::aes_128(sirk, rand); - DLOG(INFO) << "X" << base::HexEncode(x.data(), 16); +#ifdef CSIS_DEBUG + LOG_INFO("X %s", base::HexEncode(x.data(), 16).c_str()); +#endif rand[0] = rsi.address[5]; rand[1] = rsi.address[4]; rand[2] = rsi.address[3]; - DLOG(INFO) << "Hash " << base::HexEncode(rand, 3); +#ifdef CSIS_DEBUG + LOG_INFO("Hash %s", base::HexEncode(rand.data(), 3).c_str()); +#endif if (memcmp(x.data(), &rand[0], 3) == 0) { // match diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc index 6184cee6e900afce61c8b0cc256a95d231493779..a0b92321db2915bd2593e842c005185e24ef31d4 100644 --- a/system/bta/dm/bta_dm_act.cc +++ b/system/bta/dm/bta_dm_act.cc @@ -25,90 +25,49 @@ #define LOG_TAG "bt_bta_dm" +#include +#include #include -#ifdef __ANDROID__ -#include -#endif #include +#include "bta/dm/bta_dm_disc.h" +#include "bta/dm/bta_dm_gatt_client.h" #include "bta/dm/bta_dm_int.h" -#include "bta/gatt/bta_gattc_int.h" -#include "bta/include/bta_dm_ci.h" -#include "bta_sdp_api.h" -#include "btif/include/btif_config.h" +#include "bta/dm/bta_dm_sec_int.h" +#include "bta/include/bta_api.h" +#include "bta/include/bta_sdp_api.h" +#include "bta/include/bta_sec_api.h" +#include "bta/sys/bta_sys.h" #include "btif/include/btif_dm.h" -#include "btif/include/btif_storage.h" #include "btif/include/stack_manager.h" #include "device/include/controller.h" -#include "device/include/interop.h" -#include "gd/common/init_flags.h" +#include "include/bind_helpers.h" +#include "internal_include/bt_target.h" #include "main/shim/acl_api.h" #include "main/shim/btm_api.h" -#include "main/shim/dumpsys.h" -#include "main/shim/shim.h" #include "osi/include/allocator.h" -#include "osi/include/compat.h" -#include "osi/include/fixed_queue.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "osi/include/osi.h" // UNUSED_ATTR #include "osi/include/properties.h" -#include "sdp_api.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_dev.h" -#include "stack/btm/btm_sec.h" -#include "stack/btm/neighbor_inquiry.h" #include "stack/gatt/connection_manager.h" #include "stack/include/acl_api.h" -#include "stack/include/avrc_api.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_octets.h" #include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_client_interface.h" -#include "stack/include/btm_log_history.h" -#include "stack/include/btu.h" // do_in_main_thread -#include "stack/include/srvc_api.h" // DIS_ReadDISInfo -#include "stack/sdp/sdpint.h" +#include "stack/include/gatt_api.h" +#include "stack/include/l2c_api.h" +#include "stack/include/main_thread.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#if (GAP_INCLUDED == TRUE) -#include "gap_api.h" -#endif - using bluetooth::Uuid; -namespace { -constexpr char kBtmLogTag[] = "SDP"; -} - +bool ble_vnd_is_included(); void BTIF_dm_disable(); void BTIF_dm_enable(); -void btm_ble_adv_init(void); void btm_ble_scanner_init(void); -static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status); -static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, - uint16_t eir_len); -static void bta_dm_inq_cmpl_cb(void* p_result); -static void bta_dm_service_search_remname_cback(const RawAddress& bd_addr, - DEV_CLASS dc, - tBTM_BD_NAME bd_name); -static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p); -static void bta_dm_find_services(const RawAddress& bd_addr); -static void bta_dm_discover_next_device(void); -static void bta_dm_sdp_callback(tSDP_STATUS sdp_status); -static uint8_t bta_dm_pin_cback(const RawAddress& bd_addr, DEV_CLASS dev_class, - const tBTM_BD_NAME bd_name, bool min_16_digit); -static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr, - DEV_CLASS dev_class, - tBTM_BD_NAME bd_name, - const LinkKey& key, uint8_t key_type, - bool is_ctkd); -static void bta_dm_authentication_complete_cback(const RawAddress& bd_addr, - DEV_CLASS dev_class, - tBTM_BD_NAME bd_name, - tHCI_REASON result); static void bta_dm_local_name_cback(void* p_name); static void bta_dm_check_av(); @@ -116,35 +75,14 @@ void BTA_dm_update_policy(tBTA_SYS_CONN_STATUS status, uint8_t id, uint8_t app_id, const RawAddress& peer_addr); /* Extended Inquiry Response */ -static tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data); - static void bta_dm_set_eir(char* local_name); -static void bta_dm_search_timer_cback(void* data); static void bta_dm_disable_conn_down_timer_cback(void* data); -void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, uint8_t app_id, - const RawAddress& peer_addr); +static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, tBTA_SYS_ID id, + uint8_t app_id, const RawAddress& peer_addr); static void bta_dm_adjust_roles(bool delay_role_switch); -static char* bta_dm_get_remname(void); -static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result); - -static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, - tBT_TRANSPORT transport); -static void bta_dm_discover_device(const RawAddress& remote_bd_addr); - -static void bta_dm_disable_search_and_disc(void); - -static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, const RawAddress& bda, - tBTM_LE_EVT_DATA* p_data); -static void bta_dm_ble_id_key_cback(uint8_t key_type, - tBTM_BLE_LOCAL_KEYS* p_key); -static void bta_dm_gattc_register(void); -static void btm_dm_start_gatt_discovery(const RawAddress& bd_addr); -static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data); tBTM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void); -#if (BLE_VND_INCLUDED == TRUE) static void bta_dm_ctrl_features_rd_cmpl_cback(tHCI_STATUS result); -#endif #ifndef BTA_DM_BLE_ADV_CHNL_MAP #define BTA_DM_BLE_ADV_CHNL_MAP \ @@ -176,17 +114,6 @@ static void bta_dm_ctrl_features_rd_cmpl_cback(tHCI_STATUS result); #define PROPERTY_PAGE_TIMEOUT "bluetooth.core.classic.page_timeout" #endif -// Time to wait after receiving shutdown request to delay the actual shutdown -// process. This time may be zero which invokes immediate shutdown. -static uint64_t get_DisableDelayTimerInMs() { -#ifndef __ANDROID__ - return 200; -#else - static const uint64_t kDisableDelayTimerInMs = - android::sysprop::bluetooth::Bta::disable_delay().value_or(200); - return kDisableDelayTimerInMs; -#endif -} namespace { struct WaitForAllAclConnectionsToDrain { @@ -223,77 +150,17 @@ WaitForAllAclConnectionsToDrain::FromAlarmCallbackData(void* data) { } // namespace -static void bta_dm_reset_sec_dev_pending(const RawAddress& remote_bd_addr); -static void bta_dm_remove_sec_dev_entry(const RawAddress& remote_bd_addr); -static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, - const uint8_t* p_eir, uint16_t eir_len); -static void bta_dm_observe_cmpl_cb(void* p_result); static void bta_dm_delay_role_switch_cback(void* data); static void bta_dm_wait_for_acl_to_drain_cback(void* data); -const uint16_t bta_service_id_to_uuid_lkup_tbl[BTA_MAX_SERVICE_ID] = { - UUID_SERVCLASS_PNP_INFORMATION, /* Reserved */ - UUID_SERVCLASS_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */ - UUID_SERVCLASS_DIALUP_NETWORKING, /* BTA_DUN_SERVICE_ID */ - UUID_SERVCLASS_AUDIO_SOURCE, /* BTA_A2DP_SOURCE_SERVICE_ID */ - UUID_SERVCLASS_LAN_ACCESS_USING_PPP, /* BTA_LAP_SERVICE_ID */ - UUID_SERVCLASS_HEADSET, /* BTA_HSP_HS_SERVICE_ID */ - UUID_SERVCLASS_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */ - UUID_SERVCLASS_OBEX_OBJECT_PUSH, /* BTA_OPP_SERVICE_ID */ - UUID_SERVCLASS_OBEX_FILE_TRANSFER, /* BTA_FTP_SERVICE_ID */ - UUID_SERVCLASS_CORDLESS_TELEPHONY, /* BTA_CTP_SERVICE_ID */ - UUID_SERVCLASS_INTERCOM, /* BTA_ICP_SERVICE_ID */ - UUID_SERVCLASS_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */ - UUID_SERVCLASS_DIRECT_PRINTING, /* BTA_BPP_SERVICE_ID */ - UUID_SERVCLASS_IMAGING_RESPONDER, /* BTA_BIP_SERVICE_ID */ - UUID_SERVCLASS_PANU, /* BTA_PANU_SERVICE_ID */ - UUID_SERVCLASS_NAP, /* BTA_NAP_SERVICE_ID */ - UUID_SERVCLASS_GN, /* BTA_GN_SERVICE_ID */ - UUID_SERVCLASS_SAP, /* BTA_SAP_SERVICE_ID */ - UUID_SERVCLASS_AUDIO_SINK, /* BTA_A2DP_SERVICE_ID */ - UUID_SERVCLASS_AV_REMOTE_CONTROL, /* BTA_AVRCP_SERVICE_ID */ - UUID_SERVCLASS_HUMAN_INTERFACE, /* BTA_HID_SERVICE_ID */ - UUID_SERVCLASS_VIDEO_SINK, /* BTA_VDP_SERVICE_ID */ - UUID_SERVCLASS_PBAP_PSE, /* BTA_PBAP_SERVICE_ID */ - UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, /* BTA_HSP_SERVICE_ID */ - UUID_SERVCLASS_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */ - UUID_SERVCLASS_MESSAGE_ACCESS, /* BTA_MAP_SERVICE_ID */ - UUID_SERVCLASS_MESSAGE_NOTIFICATION, /* BTA_MN_SERVICE_ID */ - UUID_SERVCLASS_HDP_PROFILE, /* BTA_HDP_SERVICE_ID */ - UUID_SERVCLASS_PBAP_PCE, /* BTA_PCE_SERVICE_ID */ - UUID_PROTOCOL_ATT /* BTA_GATT_SERVICE_ID */ -}; - -/* bta security callback */ -const tBTM_APPL_INFO bta_security = { - .p_pin_callback = &bta_dm_pin_cback, - .p_link_key_callback = &bta_dm_new_link_key_cback, - .p_auth_complete_callback = &bta_dm_authentication_complete_cback, - .p_bond_cancel_cmpl_callback = &bta_dm_bond_cancel_complete_cback, - .p_sp_callback = &bta_dm_sp_cback, - .p_le_callback = &bta_dm_ble_smp_cback, - .p_le_key_callback = &bta_dm_ble_id_key_cback}; - -#define MAX_DISC_RAW_DATA_BUF (4096) -uint8_t g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF]; - -// Stores the local Input/Output Capabilities of the Bluetooth device. -static uint8_t btm_local_io_caps; - /** Initialises the BT device manager */ -void bta_dm_enable(tBTA_DM_SEC_CBACK* p_sec_cback) { - /* make sure security callback is saved - if no callback, do not erase the - previous one, - it could be an error recovery mechanism */ - if (p_sec_cback != NULL) bta_dm_cb.p_sec_cback = p_sec_cback; +void bta_dm_enable(tBTA_DM_SEC_CBACK* p_sec_cback, + tBTA_DM_ACL_CBACK *p_acl_cback) { - btm_local_io_caps = btif_storage_get_local_io_caps(); -} + if (p_acl_cback != NULL) bta_dm_acl_cb.p_acl_cback = p_acl_cback; -void bta_dm_search_set_state(tBTA_DM_STATE state) { - bta_dm_search_cb.state = state; + bta_dm_sec_enable(p_sec_cback); } -tBTA_DM_STATE bta_dm_search_get_state() { return bta_dm_search_cb.state; } /******************************************************************************* * @@ -305,8 +172,9 @@ tBTA_DM_STATE bta_dm_search_get_state() { return bta_dm_search_cb.state; } * Returns void * ******************************************************************************/ -void bta_dm_init_cb(void) { +static void bta_dm_init_cb(void) { bta_dm_cb = {}; + bta_dm_cb.disable_timer = alarm_new("bta_dm.disable_timer"); bta_dm_cb.switch_delay_timer = alarm_new("bta_dm.switch_delay_timer"); for (size_t i = 0; i < BTA_DM_NUM_PM_TIMER; i++) { @@ -326,7 +194,7 @@ void bta_dm_init_cb(void) { * Returns void * ******************************************************************************/ -void bta_dm_deinit_cb(void) { +static void bta_dm_deinit_cb(void) { /* * TODO: Should alarm_free() the bta_dm_cb timers during graceful * shutdown. @@ -347,43 +215,20 @@ void BTA_dm_on_hw_off() { /* reinitialize the control block */ bta_dm_deinit_cb(); - /* hw is ready, go on with BTA DM initialization */ - alarm_free(bta_dm_search_cb.search_timer); - alarm_free(bta_dm_search_cb.gatt_close_timer); - osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search); - fixed_queue_free(bta_dm_search_cb.pending_discovery_queue, osi_free); - bta_dm_search_cb = {}; + bta_dm_disc_stop(); } void BTA_dm_on_hw_on() { DEV_CLASS dev_class; - tBTA_DM_SEC_CBACK* temp_cback; + uint8_t key_mask = 0; tBTA_BLE_LOCAL_ID_KEYS id_key; - /* save security callback */ - temp_cback = bta_dm_cb.p_sec_cback; /* make sure the control block is properly initialized */ bta_dm_init_cb(); - /* and retrieve the callback */ - bta_dm_cb.p_sec_cback = temp_cback; - - /* hw is ready, go on with BTA DM initialization */ - alarm_free(bta_dm_search_cb.search_timer); - alarm_free(bta_dm_search_cb.gatt_close_timer); - osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search); - fixed_queue_free(bta_dm_search_cb.pending_discovery_queue, osi_free); - bta_dm_search_cb = {}; - /* - * TODO: Should alarm_free() the bta_dm_search_cb timers during - * graceful shutdown. - */ - bta_dm_search_cb.search_timer = alarm_new("bta_dm_search.search_timer"); - bool delay_close_gatt = - osi_property_get_bool("bluetooth.gatt.delay_close.enabled", true); - bta_dm_search_cb.gatt_close_timer = - delay_close_gatt ? alarm_new("bta_dm_search.gatt_close_timer") : nullptr; - bta_dm_search_cb.pending_discovery_queue = fixed_queue_new(SIZE_MAX); + + bta_dm_disc_start( + osi_property_get_bool("bluetooth.gatt.delay_close.enabled", true)); memset(&bta_dm_conn_srvcs, 0, sizeof(bta_dm_conn_srvcs)); memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB)); @@ -392,7 +237,7 @@ void BTA_dm_on_hw_on() { LOG_INFO("%s: Read default class of device {0x%x, 0x%x, 0x%x}", __func__, dev_class[0], dev_class[1], dev_class[2]); - BTM_SetDeviceClass(dev_class); + get_btm_client_interface().local.BTM_SetDeviceClass(dev_class); /* load BLE local information: ID keys, ER if available */ Octet16 er; @@ -406,24 +251,22 @@ void BTA_dm_on_hw_on() { get_btm_client_interface().ble.BTM_BleLoadLocalKeys( BTA_BLE_LOCAL_KEY_TYPE_ID, (tBTM_BLE_LOCAL_KEYS*)&id_key); } - bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; - get_btm_client_interface().security.BTM_SecRegister(&bta_security); + btm_dm_sec_init(); + btm_sec_on_hw_on(); - BTM_WritePageTimeout(osi_property_get_int32(PROPERTY_PAGE_TIMEOUT, - p_bta_dm_cfg->page_timeout)); + get_btm_client_interface().link_policy.BTM_WritePageTimeout( + osi_property_get_int32(PROPERTY_PAGE_TIMEOUT, + p_bta_dm_cfg->page_timeout)); -#if (BLE_VND_INCLUDED == TRUE) - BTM_BleReadControllerFeatures(bta_dm_ctrl_features_rd_cmpl_cback); -#else - /* If VSC multi adv commands are available, advertising will be initialized - * when capabilities are read. If they are not available, initialize - * advertising here */ - btm_ble_adv_init(); - /* Set controller features even if vendor support is not included */ - if (bta_dm_cb.p_sec_cback) - bta_dm_cb.p_sec_cback(BTA_DM_LE_FEATURES_READ, NULL); -#endif + if (ble_vnd_is_included()) { + get_btm_client_interface().ble.BTM_BleReadControllerFeatures( + bta_dm_ctrl_features_rd_cmpl_cback); + } else { + /* Set controller features even if vendor support is not included */ + if (bta_dm_acl_cb.p_acl_cback) + bta_dm_acl_cb.p_acl_cback(BTA_DM_LE_FEATURES_READ, NULL); + } btm_ble_scanner_init(); @@ -445,7 +288,7 @@ void BTA_dm_on_hw_on() { /* initialize bluetooth low power manager */ bta_dm_init_pm(); - bta_dm_gattc_register(); + bta_dm_disc_gattc_register(); } /** Disables the BT device manager */ @@ -462,22 +305,25 @@ void bta_dm_disable() { BTM_SetConnectability(BTM_NON_CONNECTABLE); bta_dm_disable_pm(); - bta_dm_disable_search_and_disc(); + bta_dm_disc_disable_search_and_disc(); bta_dm_cb.disabling = true; connection_manager::reset(false); + // We can shut down faster if there are no ACL links if (BTM_GetNumAclLinks() == 0) { - // We can shut down faster if there are no ACL links - switch (get_DisableDelayTimerInMs()) { + // Time to wait after receiving shutdown request to delay the actual + // shutdown process. This time may be zero which invokes immediate shutdown. + const uint64_t disable_delay_ms = GET_SYSPROP(Bta, disable_delay, 200); + switch (disable_delay_ms) { case 0: LOG_DEBUG("Immediately disabling device manager"); bta_dm_disable_conn_down_timer_cback(nullptr); break; default: LOG_DEBUG("Set timer to delay disable initiation:%lu ms", - static_cast(get_DisableDelayTimerInMs())); - alarm_set_on_mloop(bta_dm_cb.disable_timer, get_DisableDelayTimerInMs(), + static_cast(disable_delay_ms)); + alarm_set_on_mloop(bta_dm_cb.disable_timer, disable_delay_ms, bta_dm_disable_conn_down_timer_cback, nullptr); } } else { @@ -489,18 +335,6 @@ void bta_dm_disable() { } } -void bta_dm_consolidate(const RawAddress& identity_addr, - const RawAddress& rpa) { - for (auto i = 0; i < bta_dm_cb.device_list.count; i++) { - if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr != rpa) continue; - - LOG_INFO("consolidating bda_dm_cb record %s -> %s", - ADDRESS_TO_LOGGABLE_CSTR(rpa), - ADDRESS_TO_LOGGABLE_CSTR(identity_addr)); - bta_dm_cb.device_list.peer_device[i].peer_bdaddr = identity_addr; - } -} - /******************************************************************************* * * Function bta_dm_wait_for_all_acl_to_drain @@ -551,7 +385,8 @@ static void bta_dm_wait_for_acl_to_drain_cback(void* data) { /** Sets local device name */ void bta_dm_set_dev_name(const std::vector& name) { - BTM_SetLocalDeviceName((const char*)name.data()); + get_btm_client_interface().local.BTM_SetLocalDeviceName( + (const char*)name.data()); bta_dm_set_eir((char*)name.data()); } @@ -589,35 +424,26 @@ bool BTA_DmSetVisibility(bt_scan_mode_t mode) { BTM_SetConnectability(conn_mode_param); return true; } - -static void bta_dm_process_remove_device_no_callback( - const RawAddress& bd_addr) { +void bta_dm_process_remove_device_no_callback(const RawAddress& bd_addr) { /* need to remove all pending background connection before unpair */ - BTA_GATTC_CancelOpen(0, bd_addr, false); + bta_dm_disc_gatt_cancel_open(bd_addr); - BTM_SecDeleteDevice(bd_addr); + get_btm_client_interface().security.BTM_SecDeleteDevice(bd_addr); /* remove all cached GATT information */ - BTA_GATTC_Refresh(bd_addr); + bta_dm_disc_gatt_refresh(bd_addr); } void bta_dm_process_remove_device(const RawAddress& bd_addr) { bta_dm_process_remove_device_no_callback(bd_addr); /* Conclude service search if it was pending */ - if (bta_dm_search_cb.state == BTA_DM_DISCOVER_ACTIVE && - bta_dm_search_cb.peer_bdaddr == bd_addr) { - LOG_INFO( - "Device removed while service discovery was pending, " - "conclude the service disvovery"); - bta_dm_gatt_disc_complete((uint16_t)GATT_INVALID_CONN_ID, - (tGATT_STATUS)GATT_ERROR); - } + bta_dm_disc_remove_device(bd_addr); - if (bta_dm_cb.p_sec_cback) { + if (bta_dm_sec_cb.p_sec_cback) { tBTA_DM_SEC sec_event; - sec_event.link_down.bd_addr = bd_addr; - bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &sec_event); + sec_event.dev_unpair.bd_addr = bd_addr; + bta_dm_sec_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &sec_event); } } @@ -625,13 +451,14 @@ void bta_dm_process_remove_device(const RawAddress& bd_addr) { void bta_dm_remove_device(const RawAddress& bd_addr) { /* If ACL exists for the device in the remove_bond message*/ bool is_bd_addr_connected = - BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) || - BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR); + get_btm_client_interface().peer.BTM_IsAclConnectionUp(bd_addr, + BT_TRANSPORT_LE) || + get_btm_client_interface().peer.BTM_IsAclConnectionUp( + bd_addr, BT_TRANSPORT_BR_EDR); tBT_TRANSPORT other_transport = BT_TRANSPORT_AUTO; if (is_bd_addr_connected) { - APPL_TRACE_DEBUG("%s: ACL Up count: %d", __func__, - bta_dm_cb.device_list.count); + LOG_VERBOSE("%s: ACL Up count: %d", __func__, bta_dm_cb.device_list.count); /* Take the link down first, and mark the device for removal when * disconnected */ @@ -644,7 +471,7 @@ void bta_dm_remove_device(const RawAddress& bd_addr) { GATT_CancelConnect(0, bd_addr, false); btm_remove_acl(bd_addr, peer_device.transport); - APPL_TRACE_DEBUG("%s: transport: %d", __func__, peer_device.transport); + LOG_VERBOSE("%s: transport: %d", __func__, peer_device.transport); /* save the other transport to check if device is connected on * other_transport */ @@ -665,18 +492,20 @@ void bta_dm_remove_device(const RawAddress& bd_addr) { // device bool other_address_connected = (other_transport) - ? BTM_ReadConnectedTransportAddress(&other_address, other_transport) - : (BTM_ReadConnectedTransportAddress(&other_address, - BT_TRANSPORT_BR_EDR) || - BTM_ReadConnectedTransportAddress(&other_address2, - BT_TRANSPORT_LE)); + ? get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( + &other_address, other_transport) + : (get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( + &other_address, BT_TRANSPORT_BR_EDR) || + get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( + &other_address2, BT_TRANSPORT_LE)); if (other_address == bd_addr) other_address = other_address2; if (other_address_connected) { // Get real transport if (other_transport == BT_TRANSPORT_AUTO) { bool connected_with_br_edr = - BTM_IsAclConnectionUp(other_address, BT_TRANSPORT_BR_EDR); + get_btm_client_interface().peer.BTM_IsAclConnectionUp( + other_address, BT_TRANSPORT_BR_EDR); other_transport = connected_with_br_edr ? BT_TRANSPORT_BR_EDR : BT_TRANSPORT_LE; } @@ -711,39 +540,13 @@ void bta_dm_remove_device(const RawAddress& bd_addr) { } } -/******************************************************************************* - * - * Function bta_dm_add_device - * - * Description This function adds a Link Key to an security database entry. - * It is normally called during host startup to restore all - * required information stored in the NVRAM. - ******************************************************************************/ -void bta_dm_add_device(std::unique_ptr msg) { - uint8_t* p_dc = NULL; - LinkKey* p_lc = NULL; - - /* If not all zeros, the device class has been specified */ - if (msg->dc_known) p_dc = (uint8_t*)msg->dc; - - if (msg->link_key_known) p_lc = &msg->link_key; - - auto add_result = - BTM_SecAddDevice(msg->bd_addr, p_dc, msg->bd_name, nullptr, p_lc, - msg->key_type, msg->pin_length); - if (!add_result) { - LOG(ERROR) << "BTA_DM: Error adding device " - << ADDRESS_TO_LOGGABLE_STR(msg->bd_addr); - } -} - /** This function forces to close the connection to a remote device and * optionaly remove the device from security database if required. */ void bta_dm_close_acl(const RawAddress& bd_addr, bool remove_dev, tBT_TRANSPORT transport) { uint8_t index; - APPL_TRACE_DEBUG("bta_dm_close_acl"); + LOG_VERBOSE("bta_dm_close_acl"); if (BTM_IsAclConnectionUp(bd_addr, transport)) { for (index = 0; index < bta_dm_cb.device_list.count; index++) { @@ -751,10 +554,13 @@ void bta_dm_close_acl(const RawAddress& bd_addr, bool remove_dev, break; } if (index != bta_dm_cb.device_list.count) { - if (remove_dev) + if (remove_dev) { + LOG_INFO("Setting remove_dev_pending for %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); bta_dm_cb.device_list.peer_device[index].remove_dev_pending = true; + } } else { - APPL_TRACE_ERROR("unknown device, remove ACL failed"); + LOG_ERROR("unknown device, remove ACL failed"); } /* Make sure device is not in acceptlist before we disconnect */ @@ -770,3234 +576,859 @@ void bta_dm_close_acl(const RawAddress& bd_addr, bool remove_dev, /* otherwise, no action needed */ } -/** Bonds with peer device */ -void bta_dm_bond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) { - LOG_DEBUG("Bonding with peer device:%s type:%s transport:%s type:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), AddressTypeText(addr_type).c_str(), - bt_transport_text(transport).c_str(), - DeviceTypeText(device_type).c_str()); - - tBTA_DM_SEC sec_event; - char* p_name; - - tBTM_STATUS status = - BTM_SecBond(bd_addr, addr_type, transport, device_type, 0, NULL); - - if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)) { - memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); - sec_event.auth_cmpl.bd_addr = bd_addr; - p_name = BTM_SecReadDevName(bd_addr); - if (p_name != NULL) { - memcpy(sec_event.auth_cmpl.bd_name, p_name, BD_NAME_LEN); - sec_event.auth_cmpl.bd_name[BD_NAME_LEN] = 0; - } - - /* taken care of by memset [above] - sec_event.auth_cmpl.key_present = false; - sec_event.auth_cmpl.success = false; - */ - sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND; - if (status == BTM_SUCCESS) { - sec_event.auth_cmpl.success = true; - } else { - /* delete this device entry from Sec Dev DB */ - bta_dm_remove_sec_dev_entry(bd_addr); - } - bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); - } -} - -/** Cancels bonding with a peer device */ -void bta_dm_bond_cancel(const RawAddress& bd_addr) { - tBTM_STATUS status; - tBTA_DM_SEC sec_event; - - APPL_TRACE_EVENT(" bta_dm_bond_cancel "); - - status = BTM_SecBondCancel(bd_addr); - - if (bta_dm_cb.p_sec_cback && - (status != BTM_CMD_STARTED && status != BTM_SUCCESS)) { - sec_event.bond_cancel_cmpl.result = BTA_FAILURE; - - bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event); - } -} - -/** Send the pin_reply to a request from BTM */ -void bta_dm_pin_reply(std::unique_ptr msg) { - if (msg->accept) { - BTM_PINCodeReply(msg->bd_addr, BTM_SUCCESS, msg->pin_len, msg->p_pin); - } else { - BTM_PINCodeReply(msg->bd_addr, BTM_NOT_AUTHORIZED, 0, NULL); - } -} - -/** Send the user confirm request reply in response to a request from BTM */ -void bta_dm_confirm(const RawAddress& bd_addr, bool accept) { - BTM_ConfirmReqReply(accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED, bd_addr); -} - -/** respond to the OOB data request for the remote device from BTM */ -void bta_dm_ci_rmt_oob_act(std::unique_ptr msg) { - BTM_RemoteOobDataReply(msg->accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED, - msg->bd_addr, msg->c, msg->r); -} - -/******************************************************************************* - * - * Function bta_dm_search_start - * - * Description Starts an inquiry - * - * - * Returns void - * - ******************************************************************************/ -void bta_dm_search_start(tBTA_DM_MSG* p_data) { - bta_dm_gattc_register(); - - APPL_TRACE_DEBUG("%s avoid_scatter=%d", __func__, - p_bta_dm_cfg->avoid_scatter); - - BTM_ClearInqDb(nullptr); - /* save search params */ - bta_dm_search_cb.p_search_cback = p_data->search.p_cback; - bta_dm_search_cb.services = p_data->search.services; - - const tBTM_STATUS btm_status = - BTM_StartInquiry(bta_dm_inq_results_cb, bta_dm_inq_cmpl_cb); - switch (btm_status) { - case BTM_CMD_STARTED: - // Completion callback will be executed when controller inquiry - // timer pops or is cancelled by the user - break; - default: - LOG_WARN("Unable to start device discovery search btm_status:%s", - btm_status_text(btm_status).c_str()); - // Not started so completion callback is executed now - bta_dm_inq_cmpl(0); - break; - } -} - /******************************************************************************* * - * Function bta_dm_search_cancel - * - * Description Cancels an ongoing search for devices - * - * - * Returns void - * - ******************************************************************************/ -void bta_dm_search_cancel() { - if (BTM_IsInquiryActive()) { - BTM_CancelInquiry(); - bta_dm_search_cancel_notify(); - bta_dm_search_cmpl(); - } - /* If no Service Search going on then issue cancel remote name in case it is - active */ - else if (!bta_dm_search_cb.name_discover_done) { - BTM_CancelRemoteDeviceName(); - bta_dm_search_cmpl(); - } else { - bta_dm_inq_cmpl(0); - } -} - -/******************************************************************************* - * - * Function bta_dm_discover + * Function bta_dm_local_name_cback * - * Description Discovers services on a remote device + * Description Callback from btm after local name is read * * * Returns void * ******************************************************************************/ -void bta_dm_discover(tBTA_DM_MSG* p_data) { - /* save the search condition */ - bta_dm_search_cb.services = BTA_ALL_SERVICE_MASK; - - bta_dm_gattc_register(); - - bta_dm_search_cb.p_search_cback = p_data->discover.p_cback; - bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; - bta_dm_search_cb.service_index = 0; - bta_dm_search_cb.services_found = 0; - bta_dm_search_cb.peer_name[0] = 0; - bta_dm_search_cb.p_btm_inq_info = BTM_InqDbRead(p_data->discover.bd_addr); - bta_dm_search_cb.transport = p_data->discover.transport; - - bta_dm_search_cb.name_discover_done = false; - - LOG_INFO("bta_dm_discovery: starting service discovery to %s , transport: %s", - ADDRESS_TO_LOGGABLE_CSTR(p_data->discover.bd_addr), - bt_transport_text(p_data->discover.transport).c_str()); - bta_dm_discover_device(p_data->discover.bd_addr); +static void bta_dm_local_name_cback(UNUSED_ATTR void* p_name) { + BTIF_dm_enable(); } -/******************************************************************************* - * - * Function bta_dm_disable_search_and_disc - * - * Description Cancels an ongoing search or discovery for devices in case - * of a Bluetooth disable - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_disable_search_and_disc(void) { - switch (bta_dm_search_get_state()) { - case BTA_DM_SEARCH_IDLE: - break; - case BTA_DM_SEARCH_ACTIVE: - case BTA_DM_SEARCH_CANCELLING: - case BTA_DM_DISCOVER_ACTIVE: - default: - LOG_DEBUG( - "Search state machine is not idle so issuing search cancel current " - "state:%s", - bta_dm_state_text(bta_dm_search_get_state()).c_str()); - bta_dm_search_cancel(); +static void handle_role_change(const RawAddress& bd_addr, tHCI_ROLE new_role, + tHCI_STATUS hci_status) { + tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr); + if (!p_dev) { + LOG_WARN( + "Unable to find device for role change peer:%s new_role:%s " + "hci_status:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), RoleText(new_role).c_str(), + hci_error_code_text(hci_status).c_str()); + return; } -} - -/******************************************************************************* - * - * Function bta_dm_read_remote_device_name - * - * Description Initiate to get remote device name - * - * Returns true if started to get remote name - * - ******************************************************************************/ -static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, - tBT_TRANSPORT transport) { - tBTM_STATUS btm_status; - - APPL_TRACE_DEBUG("%s", __func__); - - bta_dm_search_cb.peer_bdaddr = bd_addr; - bta_dm_search_cb.peer_name[0] = 0; - - btm_status = BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr, - bta_dm_remname_cback, transport); - - if (btm_status == BTM_CMD_STARTED) { - APPL_TRACE_DEBUG("%s: BTM_ReadRemoteDeviceName is started", __func__); - return (true); - } else if (btm_status == BTM_BUSY) { - APPL_TRACE_DEBUG("%s: BTM_ReadRemoteDeviceName is busy", __func__); + LOG_INFO( + "Role change callback peer:%s info:%s new_role:%s dev count:%d " + "hci_status:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), p_dev->info_text().c_str(), + RoleText(new_role).c_str(), bta_dm_cb.device_list.count, + hci_error_code_text(hci_status).c_str()); - /* Remote name discovery is on going now so BTM cannot notify through - * "bta_dm_remname_cback" */ - /* adding callback to get notified that current reading remote name done */ + if (p_dev->is_av_active()) { + bool need_policy_change = false; - BTM_SecAddRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + /* there's AV activity on this link */ + if (new_role == HCI_ROLE_PERIPHERAL && bta_dm_cb.device_list.count > 1 && + hci_status == HCI_SUCCESS) { + /* more than one connections and the AV connection is role switched + * to peripheral + * switch it back to central and remove the switch policy */ + get_btm_client_interface().link_policy.BTM_SwitchRoleToCentral(bd_addr); + need_policy_change = true; + } else if (p_bta_dm_cfg->avoid_scatter && (new_role == HCI_ROLE_CENTRAL)) { + /* if the link updated to be central include AV activities, remove + * the switch policy */ + need_policy_change = true; + } - return (true); + if (need_policy_change) { + get_btm_client_interface().link_policy.BTM_block_role_switch_for( + p_dev->peer_bdaddr); + } } else { - APPL_TRACE_WARNING("%s: BTM_ReadRemoteDeviceName returns 0x%02X", __func__, - btm_status); - - return (false); + /* there's AV no activity on this link and role switch happened + * check if AV is active + * if so, make sure the AV link is central */ + bta_dm_check_av(); } + bta_sys_notify_role_chg(bd_addr, new_role, hci_status); } -/******************************************************************************* - * - * Function bta_dm_inq_cmpl - * - * Description Process the inquiry complete event from BTM - * - * Returns void - * - ******************************************************************************/ -void bta_dm_inq_cmpl(uint8_t num) { - if (bta_dm_search_get_state() == BTA_DM_SEARCH_CANCELLING) { - bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); - bta_dm_execute_queued_request(); - return; - } +void BTA_dm_report_role_change(const RawAddress bd_addr, tHCI_ROLE new_role, + tHCI_STATUS hci_status) { + do_in_main_thread(FROM_HERE, base::BindOnce(handle_role_change, bd_addr, + new_role, hci_status)); +} - if (bta_dm_search_get_state() != BTA_DM_SEARCH_ACTIVE) { +void handle_remote_features_complete(const RawAddress& bd_addr) { + tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr); + if (!p_dev) { + LOG_WARN("Unable to find device peer:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); return; } - tBTA_DM_SEARCH data; - - APPL_TRACE_DEBUG("bta_dm_inq_cmpl"); - - data.inq_cmpl.num_resps = num; - bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data); - - bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst(); - if (bta_dm_search_cb.p_btm_inq_info != NULL) { - /* start name and service discovery from the first device on inquiry result - */ - bta_dm_search_cb.name_discover_done = false; - bta_dm_search_cb.peer_name[0] = 0; - bta_dm_discover_device( - bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); + if (controller_get_interface()->supports_sniff_subrating() && + acl_peer_supports_sniff_subrating(bd_addr)) { + LOG_DEBUG("Device supports sniff subrating peer:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + p_dev->set_both_device_ssr_capable(); } else { - bta_dm_search_cb.services = 0; - bta_dm_search_cmpl(); + LOG_DEBUG("Device does NOT support sniff subrating peer:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } } -/******************************************************************************* - * - * Function bta_dm_rmt_name - * - * Description Process the remote name result from BTM - * - * Returns void - * - ******************************************************************************/ -void bta_dm_rmt_name(tBTA_DM_MSG* p_data) { - APPL_TRACE_DEBUG("bta_dm_rmt_name"); - - if (p_data->rem_name.result.disc_res.bd_name[0] && - bta_dm_search_cb.p_btm_inq_info) { - bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name = true; - } - - bta_dm_discover_device(bta_dm_search_cb.peer_bdaddr); +void BTA_dm_notify_remote_features_complete(const RawAddress bd_addr) { + do_in_main_thread(FROM_HERE, + base::BindOnce(handle_remote_features_complete, bd_addr)); } -/******************************************************************************* - * - * Function bta_dm_disc_rmt_name - * - * Description Process the remote name result from BTM when application - * wants to find the name for a bdaddr - * - * Returns void - * - ******************************************************************************/ -void bta_dm_disc_rmt_name(tBTA_DM_MSG* p_data) { - CHECK(p_data != nullptr); - - APPL_TRACE_DEBUG("bta_dm_disc_rmt_name"); - - const tBTA_DM_DISC_RES* disc_res = &p_data->rem_name.result.disc_res; - - BTM_LogHistory( - kBtmLogTag, disc_res->bd_addr, "Remote name completed", - base::StringPrintf( - "status:%s name:\"%s\" service:0x%x device_type:%s num_uuids:%zu", - hci_status_code_text(disc_res->hci_status).c_str(), disc_res->bd_name, - disc_res->services, DeviceTypeText(disc_res->device_type).c_str(), - disc_res->num_uuids)); - - tBTM_INQ_INFO* p_btm_inq_info = - BTM_InqDbRead(p_data->rem_name.result.disc_res.bd_addr); - if (p_btm_inq_info) { - if (p_data->rem_name.result.disc_res.bd_name[0]) { - p_btm_inq_info->appl_knows_rem_name = true; +static tBTA_DM_PEER_DEVICE* allocate_device_for(const RawAddress& bd_addr, + tBT_TRANSPORT transport) { + for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) { + auto device = &bta_dm_cb.device_list.peer_device[i]; + if (device->peer_bdaddr == bd_addr && device->transport == transport) { + return device; } } - bta_dm_discover_device(p_data->rem_name.result.disc_res.bd_addr); + if (bta_dm_cb.device_list.count < BTA_DM_NUM_PEER_DEVICE) { + auto device = + &bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]; + device->peer_bdaddr = bd_addr; + bta_dm_cb.device_list.count++; + if (transport == BT_TRANSPORT_LE) { + bta_dm_cb.device_list.le_count++; + } + return device; + } + return nullptr; } -static void store_avrcp_profile_feature(tSDP_DISC_REC* sdp_rec) { - tSDP_DISC_ATTR* p_attr = - SDP_FindAttributeInRec(sdp_rec, ATTR_ID_SUPPORTED_FEATURES); - if (p_attr == NULL || - SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != UINT_DESC_TYPE || - SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < 2) { +void bta_dm_acl_up(const RawAddress& bd_addr, tBT_TRANSPORT transport, + uint16_t acl_handle) { + auto device = allocate_device_for(bd_addr, transport); + if (device == nullptr) { + LOG_WARN("Unable to allocate device resources for new connection"); return; } + LOG_INFO("Acl connected peer:%s transport:%s handle:%hu", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + bt_transport_text(transport).c_str(), acl_handle); + device->conn_state = BTA_DM_CONNECTED; + device->pref_role = BTA_ANY_ROLE; + device->reset_device_info(); + device->transport = transport; - uint16_t avrcp_features = p_attr->attr_value.v.u16; - if (avrcp_features == 0) { - return; + if (controller_get_interface()->supports_sniff_subrating() && + acl_peer_supports_sniff_subrating(bd_addr)) { + // NOTE: This callback assumes upon ACL connection that + // the read remote features has completed and is valid. + // The only guaranteed contract for valid read remote features + // data is when the BTA_dm_notify_remote_features_complete() + // callback has completed. The below assignment is kept for + // transitional informational purposes only. + device->set_both_device_ssr_capable(); } - if (btif_config_set_bin(sdp_rec->remote_bd_addr.ToString().c_str(), - AV_REM_CTRL_FEATURES_CONFIG_KEY, - (const uint8_t*)&avrcp_features, - sizeof(avrcp_features))) { - LOG_INFO("Saving avrcp_features: 0x%x", avrcp_features); - } else { - LOG_INFO("Failed to store avrcp_features 0x%x for %s", avrcp_features, - ADDRESS_TO_LOGGABLE_CSTR(sdp_rec->remote_bd_addr)); + if (bta_dm_acl_cb.p_acl_cback) { + tBTA_DM_ACL conn{}; + conn.link_up.bd_addr = bd_addr; + conn.link_up.transport_link_type = transport; + conn.link_up.acl_handle = acl_handle; + + bta_dm_acl_cb.p_acl_cback(BTA_DM_LINK_UP_EVT, &conn); + LOG_DEBUG("Executed security callback for new connection available"); } + bta_dm_adjust_roles(true); } -static void bta_dm_store_audio_profiles_version() { - struct AudioProfile { - const uint16_t servclass_uuid; - const uint16_t btprofile_uuid; - const char* profile_key; - void (*store_audio_profile_feature)(tSDP_DISC_REC*); - }; - - std::array audio_profiles = {{ - { - .servclass_uuid = UUID_SERVCLASS_AV_REMOTE_CONTROL, - .btprofile_uuid = UUID_SERVCLASS_AV_REMOTE_CONTROL, - .profile_key = AVRCP_CONTROLLER_VERSION_CONFIG_KEY, - .store_audio_profile_feature = store_avrcp_profile_feature, - }, - }}; - - for (const auto& audio_profile : audio_profiles) { - tSDP_DISC_REC* sdp_rec = SDP_FindServiceInDb( - bta_dm_search_cb.p_sdp_db, audio_profile.servclass_uuid, NULL); - if (sdp_rec == NULL) continue; - - if (SDP_FindAttributeInRec(sdp_rec, ATTR_ID_BT_PROFILE_DESC_LIST) == NULL) - continue; +void BTA_dm_acl_up(const RawAddress bd_addr, tBT_TRANSPORT transport, + uint16_t acl_handle) { + do_in_main_thread( + FROM_HERE, base::BindOnce(bta_dm_acl_up, bd_addr, transport, acl_handle)); +} - uint16_t profile_version = 0; - /* get profile version (if failure, version parameter is not updated) */ - SDP_FindProfileVersionInRec(sdp_rec, audio_profile.btprofile_uuid, - &profile_version); - if (profile_version != 0) { - if (btif_config_set_bin(sdp_rec->remote_bd_addr.ToString().c_str(), - audio_profile.profile_key, - (const uint8_t*)&profile_version, - sizeof(profile_version))) { - } else { - LOG_INFO("Failed to store peer profile version for %s", - ADDRESS_TO_LOGGABLE_CSTR(sdp_rec->remote_bd_addr)); - } - } - audio_profile.store_audio_profile_feature(sdp_rec); +static void bta_dm_acl_up_failed(const RawAddress bd_addr, + tBT_TRANSPORT transport, tHCI_STATUS status) { + if (bta_dm_acl_cb.p_acl_cback) { + tBTA_DM_ACL conn = {}; + conn.link_up_failed.bd_addr = bd_addr; + conn.link_up_failed.transport_link_type = transport; + conn.link_up_failed.status = status; + bta_dm_acl_cb.p_acl_cback(BTA_DM_LINK_UP_FAILED_EVT, &conn); } } -/******************************************************************************* - * - * Function bta_dm_sdp_result - * - * Description Process the discovery result from sdp - * - * Returns void - * - ******************************************************************************/ -void bta_dm_sdp_result(tBTA_DM_MSG* p_data) { - tSDP_DISC_REC* p_sdp_rec = NULL; - tBTA_DM_MSG* p_msg; - bool scn_found = false; - uint16_t service = 0xFFFF; - tSDP_PROTOCOL_ELEM pe; - - std::vector uuid_list; - - const tSDP_RESULT sdp_result = p_data->sdp_event.sdp_result; - - if ((p_data->sdp_event.sdp_result == SDP_SUCCESS) || - (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) || - (p_data->sdp_event.sdp_result == SDP_DB_FULL)) { - APPL_TRACE_DEBUG("sdp_result::0x%x", p_data->sdp_event.sdp_result); - do { - p_sdp_rec = NULL; - if (bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID + 1)) { - if (p_sdp_rec && SDP_FindProtocolListElemInRec( - p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) { - bta_dm_search_cb.peer_scn = (uint8_t)pe.params[0]; - scn_found = true; - } - } else { - service = - bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index - 1]; - p_sdp_rec = - SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, service, p_sdp_rec); - } - /* finished with BR/EDR services, now we check the result for GATT based - * service UUID */ - if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID) { - /* all GATT based services */ - - std::vector gatt_uuids; - - do { - /* find a service record, report it */ - p_sdp_rec = - SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, 0, p_sdp_rec); - if (p_sdp_rec) { - Uuid service_uuid; - if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) { - gatt_uuids.push_back(service_uuid); - } - } - } while (p_sdp_rec); +void BTA_dm_acl_up_failed(const RawAddress bd_addr, tBT_TRANSPORT transport, + tHCI_STATUS status) { + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_acl_up_failed, bd_addr, + transport, status)); +} - if (!gatt_uuids.empty()) { - LOG_INFO("GATT services discovered using SDP"); +static void bta_dm_acl_down(const RawAddress& bd_addr, + tBT_TRANSPORT transport) { + bool issue_unpair_cb = false; + bool remove_device = false; - // send all result back to app - tBTA_DM_SEARCH result; - result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(), - BD_NAME_LEN + 1); + for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) { + auto device = &bta_dm_cb.device_list.peer_device[i]; + if (device->peer_bdaddr != bd_addr || device->transport != transport) + continue; - result.disc_ble_res.services = &gatt_uuids; - bta_dm_search_cb.p_search_cback(BTA_DM_GATT_OVER_SDP_RES_EVT, - &result); - } - } else { - /* SDP_DB_FULL means some records with the - required attributes were received */ - if (((p_data->sdp_event.sdp_result == SDP_DB_FULL) && - bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) || - (p_sdp_rec != NULL)) { - if (service != UUID_SERVCLASS_PNP_INFORMATION) { - bta_dm_search_cb.services_found |= - (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK( - bta_dm_search_cb.service_index - 1)); - uint16_t tmp_svc = - bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index - - 1]; - /* Add to the list of UUIDs */ - uuid_list.push_back(Uuid::From16Bit(tmp_svc)); - } - } - } + if (device->conn_state == BTA_DM_UNPAIRING) { + issue_unpair_cb = get_btm_client_interface().security.BTM_SecDeleteDevice( + device->peer_bdaddr); - if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK && - bta_dm_search_cb.services_to_search == 0) { - bta_dm_search_cb.service_index++; - } else /* regular one service per search or PNP search */ - break; + /* remove all cached GATT information */ + get_gatt_interface().BTA_GATTC_Refresh(bd_addr); - } while (bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID); - - APPL_TRACE_DEBUG("%s services_found = %04x", __func__, - bta_dm_search_cb.services_found); - - /* Collect the 128-bit services here and put them into the list */ - if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) { - p_sdp_rec = NULL; - do { - /* find a service record, report it */ - p_sdp_rec = - SDP_FindServiceInDb_128bit(bta_dm_search_cb.p_sdp_db, p_sdp_rec); - if (p_sdp_rec) { - // SDP_FindServiceUUIDInRec_128bit is used only once, refactor? - Uuid temp_uuid; - if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid)) { - uuid_list.push_back(temp_uuid); - } - } - } while (p_sdp_rec); + LOG_VERBOSE("%s: Unpairing: issue unpair CB = %d ", __func__, + issue_unpair_cb); } - if (bluetooth::common::init_flags:: - dynamic_avrcp_version_enhancement_is_enabled() && - bta_dm_search_cb.services_to_search == 0) { - bta_dm_store_audio_profiles_version(); - } + remove_device = device->remove_dev_pending; -#if TARGET_FLOSS - tSDP_DI_GET_RECORD di_record; - if (SDP_GetDiRecord(1, &di_record, bta_dm_search_cb.p_sdp_db) == - SDP_SUCCESS) { - tBTA_DM_SEARCH result; - result.did_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - result.did_res.vendor_id_src = di_record.rec.vendor_id_source; - result.did_res.vendor_id = di_record.rec.vendor; - result.did_res.product_id = di_record.rec.product; - result.did_res.version = di_record.rec.version; - bta_dm_search_cb.p_search_cback(BTA_DM_DID_RES_EVT, &result); + // Iterate to the one before the last when shrinking the list, + // otherwise we memcpy garbage data into the record. + // Then clear out the last item in the list since we are shrinking. + for (; i < bta_dm_cb.device_list.count - 1; i++) { + memcpy(&bta_dm_cb.device_list.peer_device[i], + &bta_dm_cb.device_list.peer_device[i + 1], + sizeof(bta_dm_cb.device_list.peer_device[i])); } -#endif - - /* if there are more services to search for */ - if (bta_dm_search_cb.services_to_search) { - /* Free up the p_sdp_db before checking the next one */ - bta_dm_free_sdp_db(); - bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); - } else { - /* callbacks */ - /* start next bd_addr if necessary */ - - BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); - - BTM_LogHistory( - kBtmLogTag, bta_dm_search_cb.peer_bdaddr, "Discovery completed", - base::StringPrintf("Result:%s services_found:0x%x service_index:0x%d", - sdp_result_text(sdp_result).c_str(), - bta_dm_search_cb.services_found, - bta_dm_search_cb.service_index)); - - p_msg = (tBTA_DM_MSG*)osi_calloc(sizeof(tBTA_DM_MSG)); - p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; - p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; - p_msg->disc_result.result.disc_res.num_uuids = uuid_list.size(); - p_msg->disc_result.result.disc_res.p_uuid_list = NULL; - if (uuid_list.size() > 0) { - // TODO(jpawlowski): make p_uuid_list into vector, and just copy - // vectors, but first get rid of bta_sys_sendmsg below. - p_msg->disc_result.result.disc_res.p_uuid_list = - (Uuid*)osi_calloc(uuid_list.size() * sizeof(Uuid)); - memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list.data(), - uuid_list.size() * sizeof(Uuid)); - } - // Copy the raw_data to the discovery result structure - if (bta_dm_search_cb.p_sdp_db != NULL && - bta_dm_search_cb.p_sdp_db->raw_used != 0 && - bta_dm_search_cb.p_sdp_db->raw_data != NULL) { - APPL_TRACE_DEBUG("%s raw_data used = 0x%x raw_data_ptr = 0x%x", - __func__, bta_dm_search_cb.p_sdp_db->raw_used, - bta_dm_search_cb.p_sdp_db->raw_data); - - bta_dm_search_cb.p_sdp_db->raw_data = - NULL; // no need to free this - it is a global assigned. - bta_dm_search_cb.p_sdp_db->raw_used = 0; - bta_dm_search_cb.p_sdp_db->raw_size = 0; - } else { - APPL_TRACE_DEBUG("%s raw data size is 0 or raw_data is null!!", - __func__); - } - /* Done with p_sdp_db. Free it */ - bta_dm_free_sdp_db(); - p_msg->disc_result.result.disc_res.services = - bta_dm_search_cb.services_found; - - // Piggy back the SCN over result field - if (scn_found) { - p_msg->disc_result.result.disc_res.result = - static_cast((3 + bta_dm_search_cb.peer_scn)); - p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK; - - APPL_TRACE_EVENT(" Piggy back the SCN over result field SCN=%d", - bta_dm_search_cb.peer_scn); - } - p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, - bta_dm_get_remname(), BD_NAME_LEN + 1); - - bta_sys_sendmsg(p_msg); + if (bta_dm_cb.device_list.count > 0) { + int clear_index = bta_dm_cb.device_list.count - 1; + memset(&bta_dm_cb.device_list.peer_device[clear_index], 0, + sizeof(bta_dm_cb.device_list.peer_device[clear_index])); } - } else { - BTM_LogHistory( - kBtmLogTag, bta_dm_search_cb.peer_bdaddr, "Discovery failed", - base::StringPrintf("Result:%s", sdp_result_text(sdp_result).c_str())); - LOG_ERROR("SDP connection failed %s", sdp_status_text(sdp_result).c_str()); - if (p_data->sdp_event.sdp_result == SDP_CONN_FAILED) - bta_dm_search_cb.wait_disc = false; - - /* not able to connect go to next device */ - if (bta_dm_search_cb.p_sdp_db) - osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db); - - BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); - - p_msg = (tBTA_DM_MSG*)osi_calloc(sizeof(tBTA_DM_MSG)); - p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; - p_msg->disc_result.result.disc_res.result = BTA_FAILURE; - p_msg->disc_result.result.disc_res.services = - bta_dm_search_cb.services_found; - p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, - bta_dm_get_remname(), BD_NAME_LEN + 1); - - bta_sys_sendmsg(p_msg); + break; } -} - -/** Callback of peer's DIS reply. This is only called for floss */ -#if TARGET_FLOSS -static void bta_dm_read_dis_cmpl(const RawAddress& addr, - tDIS_VALUE* p_dis_value) { - if (!p_dis_value) { - LOG_WARN("read DIS failed"); - } else { - tBTA_DM_SEARCH result; - result.did_res.bd_addr = addr; - result.did_res.vendor_id_src = p_dis_value->pnp_id.vendor_id_src; - result.did_res.vendor_id = p_dis_value->pnp_id.vendor_id; - result.did_res.product_id = p_dis_value->pnp_id.product_id; - result.did_res.version = p_dis_value->pnp_id.product_version; - bta_dm_search_cb.p_search_cback(BTA_DM_DID_RES_EVT, &result); + if (bta_dm_cb.device_list.count) bta_dm_cb.device_list.count--; + if ((transport == BT_TRANSPORT_LE) && (bta_dm_cb.device_list.le_count)) { + bta_dm_cb.device_list.le_count--; } - bta_dm_execute_queued_request(); -} -#endif + bta_dm_disc_acl_down(bd_addr, transport); -/******************************************************************************* - * - * Function bta_dm_search_cmpl - * - * Description Sends event to application - * - * Returns void - * - ******************************************************************************/ -void bta_dm_search_cmpl() { - bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); - - uint16_t conn_id = bta_dm_search_cb.conn_id; - - tBTA_DM_SEARCH result; - std::vector gatt_services; - result.disc_ble_res.services = &gatt_services; - result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(), - BD_NAME_LEN + 1); - - bool send_gatt_results = - bluetooth::common::init_flags:: - always_send_services_if_gatt_disc_done_is_enabled() - ? bta_dm_search_cb.gatt_disc_active - : false; - - /* no BLE connection, i.e. Classic service discovery end */ - if (conn_id == GATT_INVALID_CONN_ID) { - if (bta_dm_search_cb.gatt_disc_active) { - LOG_WARN( - "GATT active but no BLE connection, likely disconnected midway " - "through"); - } else { - LOG_INFO("No BLE connection, processing classic results"); - } - } else { - btgatt_db_element_t* db = NULL; - int count = 0; - BTA_GATTC_GetGattDb(conn_id, 0x0000, 0xFFFF, &db, &count); - if (count != 0) { - for (int i = 0; i < count; i++) { - // we process service entries only - if (db[i].type == BTGATT_DB_PRIMARY_SERVICE) { - gatt_services.push_back(db[i].uuid); - } - } - osi_free(db); - LOG_INFO( - "GATT services discovered using LE Transport, will always send to " - "upper layer"); - send_gatt_results = true; - } else { - LOG_WARN("Empty GATT database - no BLE services discovered"); + if (bta_dm_cb.disabling) { + if (!BTM_GetNumAclLinks()) { + /* + * Start a timer to make sure that the profiles + * get the disconnect event. + */ + alarm_set_on_mloop(bta_dm_cb.disable_timer, + BTA_DM_DISABLE_CONN_DOWN_TIMER_MS, + bta_dm_disable_conn_down_timer_cback, NULL); } } + if (remove_device) { + LOG_INFO("remove_dev_pending actually removing %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + bta_dm_process_remove_device_no_callback(bd_addr); + } - // send all result back to app - if (send_gatt_results) { - LOG_INFO("Sending GATT results to upper layer"); - bta_dm_search_cb.p_search_cback(BTA_DM_GATT_OVER_LE_RES_EVT, &result); + if (bta_dm_acl_cb.p_acl_cback) { + tBTA_DM_ACL conn{}; + conn.link_down.bd_addr = bd_addr; + conn.link_down.transport_link_type = transport; + + bta_dm_acl_cb.p_acl_cback(BTA_DM_LINK_DOWN_EVT, &conn); } - bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr); - bta_dm_search_cb.gatt_disc_active = false; + // TODO: reorganize and factor out the following logic + if (issue_unpair_cb && bta_dm_sec_cb.p_sec_cback) { + tBTA_DM_SEC conn{}; + conn.dev_unpair.bd_addr = bd_addr; + conn.dev_unpair.transport_link_type = transport; -#if TARGET_FLOSS - if (DIS_ReadDISInfo(bta_dm_search_cb.peer_bdaddr, bta_dm_read_dis_cmpl, - DIS_ATTR_PNP_ID_BIT)) { - return; + bta_dm_sec_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn); } -#endif - bta_dm_execute_queued_request(); + bta_dm_adjust_roles(true); } -/******************************************************************************* - * - * Function bta_dm_disc_result - * - * Description Service discovery result when discovering services on a - * device - * - * Returns void - * - ******************************************************************************/ -void bta_dm_disc_result(tBTA_DM_MSG* p_data) { - APPL_TRACE_EVENT("%s", __func__); - - /* disc_res.device_type is set only when GATT discovery is finished in - * bta_dm_gatt_disc_complete */ - bool is_gatt_over_ble = ((p_data->disc_result.result.disc_res.device_type & - BT_DEVICE_TYPE_BLE) != 0); - - /* if any BR/EDR service discovery has been done, report the event */ - if (!is_gatt_over_ble && (bta_dm_search_cb.services & - ((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK) & - ~BTA_BLE_SERVICE_MASK))) - bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, - &p_data->disc_result.result); - - bta_dm_search_cmpl(); +void BTA_dm_acl_down(const RawAddress bd_addr, tBT_TRANSPORT transport) { + do_in_main_thread(FROM_HERE, + base::BindOnce(bta_dm_acl_down, bd_addr, transport)); } /******************************************************************************* * - * Function bta_dm_search_result - * - * Description Service discovery result while searching for devices + * Function bta_dm_check_av * - * Returns void + * Description This function checks if AV is active + * if yes, make sure the AV link is central * ******************************************************************************/ -void bta_dm_search_result(tBTA_DM_MSG* p_data) { - APPL_TRACE_DEBUG("%s searching:0x%04x, result:0x%04x", __func__, - bta_dm_search_cb.services, - p_data->disc_result.result.disc_res.services); - - /* call back if application wants name discovery or found services that - * application is searching */ - if ((!bta_dm_search_cb.services) || - ((bta_dm_search_cb.services) && - (p_data->disc_result.result.disc_res.services))) { - bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, - &p_data->disc_result.result); - } +static void bta_dm_check_av() { + uint8_t i; + tBTA_DM_PEER_DEVICE* p_dev; - /* if searching did not initiate to create link */ - if (!bta_dm_search_cb.wait_disc) { - /* if service searching is done with EIR, don't search next device */ - if (bta_dm_search_cb.p_btm_inq_info) bta_dm_discover_next_device(); - } else { - /* wait until link is disconnected or timeout */ - bta_dm_search_cb.sdp_results = true; - alarm_set_on_mloop(bta_dm_search_cb.search_timer, - 1000 * (L2CAP_LINK_INACTIVITY_TOUT + 1), - bta_dm_search_timer_cback, NULL); + if (bta_dm_cb.cur_av_count) { + LOG_INFO("av_count:%d", bta_dm_cb.cur_av_count); + for (i = 0; i < bta_dm_cb.device_list.count; i++) { + p_dev = &bta_dm_cb.device_list.peer_device[i]; + LOG_WARN("[%d]: state:%d, info:%s", i, p_dev->conn_state, + p_dev->info_text().c_str()); + if ((p_dev->conn_state == BTA_DM_CONNECTED) && p_dev->is_av_active()) { + /* make central and take away the role switch policy */ + get_btm_client_interface().link_policy.BTM_SwitchRoleToCentral( + p_dev->peer_bdaddr); + /* else either already central or can not switch for some reasons */ + get_btm_client_interface().link_policy.BTM_block_role_switch_for( + p_dev->peer_bdaddr); + break; + } + } } } /******************************************************************************* * - * Function bta_dm_search_timer_cback + * Function bta_dm_disable_conn_down_timer_cback * - * Description Called when ACL disconnect time is over + * Description Sends disable event to application * * * Returns void * ******************************************************************************/ -static void bta_dm_search_timer_cback(UNUSED_ATTR void* data) { - APPL_TRACE_EVENT("%s", __func__); - bta_dm_search_cb.wait_disc = false; +static void bta_dm_disable_conn_down_timer_cback(UNUSED_ATTR void* data) { + /* disable the power managment module */ + bta_dm_disable_pm(); - /* proceed with next device */ - bta_dm_discover_next_device(); + bta_dm_cb.disabling = false; + LOG_INFO("Stack device manager shutdown completed"); + future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS); } /******************************************************************************* * - * Function bta_dm_free_sdp_db - * - * Description Frees SDP data base - * - * Returns void - * - ******************************************************************************/ -void bta_dm_free_sdp_db() { - osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db); -} - -/******************************************************************************* + * Function bta_dm_rm_cback * - * Function bta_dm_queue_search + * Description Role management callback from sys * - * Description Queues search command * * Returns void * ******************************************************************************/ -void bta_dm_queue_search(tBTA_DM_MSG* p_data) { - if (bta_dm_search_cb.p_pending_search) { - LOG_WARN("Overwrote previous device discovery inquiry scan request"); +static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, tBTA_SYS_ID id, + uint8_t app_id, const RawAddress& peer_addr) { + uint8_t j; + tBTA_PREF_ROLES role; + tBTA_DM_PEER_DEVICE* p_dev; + + LOG_DEBUG("BTA Role management callback count:%d status:%s peer:%s", + bta_dm_cb.cur_av_count, bta_sys_conn_status_text(status).c_str(), + ADDRESS_TO_LOGGABLE_CSTR(peer_addr)); + + p_dev = bta_dm_find_peer_device(peer_addr); + if (status == BTA_SYS_CONN_OPEN) { + if (p_dev) { + /* Do not set to connected if we are in the middle of unpairing. When AV + * stream is + * started it fakes out a SYS_CONN_OPEN to potentially trigger a role + * switch command. + * But this should not be done if we are in the middle of unpairing. + */ + if (p_dev->conn_state != BTA_DM_UNPAIRING) + p_dev->conn_state = BTA_DM_CONNECTED; + + for (j = 1; j <= p_bta_dm_rm_cfg[0].app_id; j++) { + if (((p_bta_dm_rm_cfg[j].app_id == app_id) || + (p_bta_dm_rm_cfg[j].app_id == BTA_ALL_APP_ID)) && + (p_bta_dm_rm_cfg[j].id == id)) { + ASSERT_LOG(p_bta_dm_rm_cfg[j].cfg <= BTA_PERIPHERAL_ROLE_ONLY, + "Passing illegal preferred role:0x%02x [0x%02x<=>0x%02x]", + p_bta_dm_rm_cfg[j].cfg, BTA_ANY_ROLE, + BTA_PERIPHERAL_ROLE_ONLY); + role = static_cast(p_bta_dm_rm_cfg[j].cfg); + if (role > p_dev->pref_role) p_dev->pref_role = role; + break; + } + } + } + } + + if (BTA_ID_AV == id) { + if (status == BTA_SYS_CONN_BUSY) { + if (p_dev) p_dev->set_av_active(); + /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */ + if (BTA_ID_AV == id) bta_dm_cb.cur_av_count = bta_dm_get_av_count(); + } else if (status == BTA_SYS_CONN_IDLE) { + if (p_dev) p_dev->reset_av_active(); + + /* get cur_av_count from connected services */ + if (BTA_ID_AV == id) bta_dm_cb.cur_av_count = bta_dm_get_av_count(); + } } - osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search); - bta_dm_search_cb.p_pending_search = - (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_SEARCH)); - memcpy(bta_dm_search_cb.p_pending_search, p_data, sizeof(tBTA_DM_API_SEARCH)); - LOG_INFO("Queued device discovery inquiry scan request"); + + /* Don't adjust roles for each busy/idle state transition to avoid + excessive switch requests when individual profile busy/idle status + changes */ + if ((status != BTA_SYS_CONN_BUSY) && (status != BTA_SYS_CONN_IDLE)) + bta_dm_adjust_roles(false); } /******************************************************************************* * - * Function bta_dm_queue_disc + * Function bta_dm_delay_role_switch_cback * - * Description Queues discovery command + * Description Callback from btm to delay a role switch * * Returns void * ******************************************************************************/ -void bta_dm_queue_disc(tBTA_DM_MSG* p_data) { - tBTA_DM_MSG* p_pending_discovery = - (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_DISCOVER)); - memcpy(p_pending_discovery, p_data, sizeof(tBTA_DM_API_DISCOVER)); - - LOG_INFO("bta_dm_discovery: queuing service discovery to %s", - ADDRESS_TO_LOGGABLE_CSTR(p_pending_discovery->discover.bd_addr)); - fixed_queue_enqueue(bta_dm_search_cb.pending_discovery_queue, - p_pending_discovery); +static void bta_dm_delay_role_switch_cback(UNUSED_ATTR void* data) { + LOG_VERBOSE("%s: initiating Delayed RS", __func__); + bta_dm_adjust_roles(false); } /******************************************************************************* * - * Function bta_dm_execute_queued_request + * Function bta_dm_adjust_roles + * + * Description Adjust roles * - * Description Executes queued request if one exists * * Returns void * ******************************************************************************/ -void bta_dm_execute_queued_request() { - tBTA_DM_MSG* p_pending_discovery = (tBTA_DM_MSG*)fixed_queue_try_dequeue( - bta_dm_search_cb.pending_discovery_queue); - if (p_pending_discovery) { - LOG_INFO("%s Start pending discovery", __func__); - bta_sys_sendmsg(p_pending_discovery); - } else if (bta_dm_search_cb.p_pending_search) { - LOG_INFO("%s Start pending search", __func__); - bta_sys_sendmsg(bta_dm_search_cb.p_pending_search); - bta_dm_search_cb.p_pending_search = NULL; +static void bta_dm_adjust_roles(bool delay_role_switch) { + uint8_t i; + uint8_t link_count = bta_dm_cb.device_list.count; + if (link_count) { + for (i = 0; i < bta_dm_cb.device_list.count; i++) { + if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED && + bta_dm_cb.device_list.peer_device[i].transport == + BT_TRANSPORT_BR_EDR) { + if ((bta_dm_cb.device_list.peer_device[i].pref_role == + BTA_CENTRAL_ROLE_ONLY) || + (link_count > 1)) { + /* Initiating immediate role switch with certain remote devices + has caused issues due to role switch colliding with link encryption + setup and + causing encryption (and in turn the link) to fail . These device . + Firmware + versions are stored in a rejectlist and role switch with these + devices are + delayed to avoid the collision with link encryption setup */ + + if (bta_dm_cb.device_list.peer_device[i].pref_role != + BTA_PERIPHERAL_ROLE_ONLY && + !delay_role_switch) { + get_btm_client_interface().link_policy.BTM_SwitchRoleToCentral( + bta_dm_cb.device_list.peer_device[i].peer_bdaddr); + } else { + alarm_set_on_mloop(bta_dm_cb.switch_delay_timer, + BTA_DM_SWITCH_DELAY_TIMER_MS, + bta_dm_delay_role_switch_cback, NULL); + } + } + } + } } } /******************************************************************************* * - * Function bta_dm_is_search_request_queued + * Function find_utf8_char_boundary * - * Description Checks if there is a queued search request + * Description This function checks a UTF8 string |utf8str| starting at + * |offset|, moving backwards and returns the offset of the + * next valid UTF8 character boundary found. * - * Returns bool + * Returns Offset of UTF8 character boundary * ******************************************************************************/ -bool bta_dm_is_search_request_queued() { - return bta_dm_search_cb.p_pending_search != NULL; -} +static size_t find_utf8_char_boundary(const char* utf8str, size_t offset) { + CHECK(utf8str); + CHECK(offset > 0); -/******************************************************************************* - * - * Function bta_dm_search_clear_queue - * - * Description Clears the queue if API search cancel is called - * - * Returns void - * - ******************************************************************************/ -void bta_dm_search_clear_queue() { - osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search); - if (bluetooth::common::InitFlags:: - IsBtmDmFlushDiscoveryQueueOnSearchCancel()) { - fixed_queue_flush(bta_dm_search_cb.pending_discovery_queue, osi_free); + while (--offset) { + uint8_t ch = (uint8_t)utf8str[offset]; + if ((ch & 0x80) == 0x00) // ASCII + return offset + 1; + if ((ch & 0xC0) == 0xC0) // Multi-byte sequence start + return offset; } + + return 0; } /******************************************************************************* * - * Function bta_dm_search_cancel_notify + * Function bta_dm_set_eir * - * Description Notify application that search has been cancelled + * Description This function creates EIR tagged data and writes it to + * controller. * - * Returns void + * Returns None * ******************************************************************************/ -void bta_dm_search_cancel_notify() { - if (bta_dm_search_cb.p_search_cback) { - bta_dm_search_cb.p_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL); - } - switch (bta_dm_search_get_state()) { - case BTA_DM_SEARCH_ACTIVE: - case BTA_DM_SEARCH_CANCELLING: - if (!bta_dm_search_cb.name_discover_done) { - BTM_CancelRemoteDeviceName(); - } - break; - case BTA_DM_SEARCH_IDLE: - case BTA_DM_DISCOVER_ACTIVE: - // Nothing to do - break; - } -} +static void bta_dm_set_eir(char* local_name) { + uint8_t* p; + uint8_t* p_length; +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) + uint8_t* p_type; + uint8_t max_num_uuid; +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + uint8_t custom_uuid_idx; +#endif // BTA_EIR_SERVER_NUM_CUSTOM_UUID +#endif // BTA_EIR_CANNED_UUID_LIST +#if (BTM_EIR_DEFAULT_FEC_REQUIRED == FALSE) + uint8_t free_eir_length = HCI_EXT_INQ_RESPONSE_LEN; +#else // BTM_EIR_DEFAULT_FEC_REQUIRED + uint8_t free_eir_length = HCI_DM5_PACKET_SIZE; +#endif // BTM_EIR_DEFAULT_FEC_REQUIRED + uint8_t num_uuid; + uint8_t data_type; + uint8_t local_name_len; -/******************************************************************************* - * - * Function bta_dm_find_services - * - * Description Starts discovery on a device - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_find_services(const RawAddress& bd_addr) { - while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) { - Uuid uuid = Uuid::kEmpty; - if (bta_dm_search_cb.services_to_search & - (tBTA_SERVICE_MASK)( - BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))) { - bta_dm_search_cb.p_sdp_db = - (tSDP_DISCOVERY_DB*)osi_malloc(BTA_DM_SDP_DB_SIZE); - APPL_TRACE_DEBUG("bta_dm_search_cb.services = %04x***********", - bta_dm_search_cb.services); - /* try to search all services by search based on L2CAP UUID */ - if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) { - LOG_INFO("%s services_to_search=%08x", __func__, - bta_dm_search_cb.services_to_search); - if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) { - uuid = Uuid::From16Bit(bta_service_id_to_uuid_lkup_tbl[0]); - bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK; - } else { - uuid = Uuid::From16Bit(UUID_PROTOCOL_L2CAP); - bta_dm_search_cb.services_to_search = 0; - } - } else { - /* for LE only profile */ - if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) { - uuid = Uuid::From16Bit( - bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]); - - bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~( - BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))); - } else { - /* remove the service from services to be searched */ - bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~( - BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))); - uuid = Uuid::From16Bit( - bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]); - } - } + /* wait until complete to disable */ + if (alarm_is_scheduled(bta_dm_cb.disable_timer)) return; - LOG_INFO("%s search UUID = %s", __func__, uuid.ToString().c_str()); - SDP_InitDiscoveryDb(bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, - &uuid, 0, NULL); - - memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); - bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf; - - bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF; - - if (!SDP_ServiceSearchAttributeRequest(bd_addr, bta_dm_search_cb.p_sdp_db, - &bta_dm_sdp_callback)) { - /* - * If discovery is not successful with this device, then - * proceed with the next one. - */ - osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db); - bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID; - - } else { - if (uuid == Uuid::From16Bit(UUID_PROTOCOL_L2CAP)) { - if (!is_sdp_pbap_pce_disabled(bd_addr)) { - LOG_DEBUG("SDP search for PBAP Client "); - BTA_SdpSearch(bd_addr, Uuid::From16Bit(UUID_SERVCLASS_PBAP_PCE)); - } - } - bta_dm_search_cb.service_index++; - return; - } +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) + /* if local name is not provided, get it from controller */ + if (local_name == NULL) { + if (BTM_ReadLocalDeviceName((const char**)&local_name) != BTM_SUCCESS) { + LOG_ERROR("Fail to read local device name for EIR"); } - - bta_dm_search_cb.service_index++; } +#endif // BTA_EIR_CANNED_UUID_LIST - /* no more services to be discovered */ - if (bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) { - tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); - /* initialize the data structure */ - memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES)); - p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; - p_msg->disc_result.result.disc_res.services = - bta_dm_search_cb.services_found; - p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, - bta_dm_get_remname(), BD_NAME_LEN + 1); - - bta_sys_sendmsg(p_msg); - } -} + /* Allocate a buffer to hold HCI command */ + BT_HDR* p_buf = (BT_HDR*)osi_malloc(BTM_CMD_BUF_SIZE); + ASSERT(p_buf != nullptr); + p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET; -/******************************************************************************* - * - * Function bta_dm_discover_next_device - * - * Description Starts discovery on the next device in Inquiry data base - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_discover_next_device(void) { - APPL_TRACE_DEBUG("bta_dm_discover_next_device"); - - /* searching next device on inquiry result */ - bta_dm_search_cb.p_btm_inq_info = - BTM_InqDbNext(bta_dm_search_cb.p_btm_inq_info); - if (bta_dm_search_cb.p_btm_inq_info != NULL) { - bta_dm_search_cb.name_discover_done = false; - bta_dm_search_cb.peer_name[0] = 0; - bta_dm_discover_device( - bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); - } else { - tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); + memset(p, 0x00, HCI_EXT_INQ_RESPONSE_LEN); - /* no devices, search complete */ - bta_dm_search_cb.services = 0; + LOG_INFO("Generating extended inquiry response packet EIR"); - p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; - bta_sys_sendmsg(p_msg); - } -} + if (local_name) + local_name_len = strlen(local_name); + else + local_name_len = 0; -/******************************************************************************* - * - * Function bta_dm_discover_device - * - * Description Starts name and service discovery on the device - * - * Returns void - * - ******************************************************************************/ -static tBT_TRANSPORT bta_dm_determine_discovery_transport( - const RawAddress& remote_bd_addr) { - tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; - if (bta_dm_search_cb.transport == BT_TRANSPORT_AUTO) { - tBT_DEVICE_TYPE dev_type; - tBLE_ADDR_TYPE addr_type; - - BTM_ReadDevInfo(remote_bd_addr, &dev_type, &addr_type); - if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM) { - transport = BT_TRANSPORT_LE; + data_type = HCI_EIR_COMPLETE_LOCAL_NAME_TYPE; + /* if local name is longer than minimum length of shortened name */ + /* check whether it needs to be shortened or not */ + if (local_name_len > p_bta_dm_eir_cfg->bta_dm_eir_min_name_len) { +/* get number of UUID 16-bit list */ +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / Uuid::kNumBytes16; +#else // BTA_EIR_CANNED_UUID_LIST + max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes16; + data_type = get_btm_client_interface().eir.BTM_GetEirSupportedServices( + bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid); + p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */ +#endif // BTA_EIR_CANNED_UUID_LIST + + /* if UUID doesn't fit remaing space, shorten local name */ + if (local_name_len > (free_eir_length - 4 - num_uuid * Uuid::kNumBytes16)) { + local_name_len = find_utf8_char_boundary( + local_name, p_bta_dm_eir_cfg->bta_dm_eir_min_name_len); + LOG_WARN("%s local name is shortened (%d)", __func__, local_name_len); + data_type = HCI_EIR_SHORTENED_LOCAL_NAME_TYPE; + } else { + data_type = HCI_EIR_COMPLETE_LOCAL_NAME_TYPE; } - } else { - transport = bta_dm_search_cb.transport; } - return transport; -} - -static void bta_dm_discover_device(const RawAddress& remote_bd_addr) { - const tBT_TRANSPORT transport = - bta_dm_determine_discovery_transport(remote_bd_addr); - - VLOG(1) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(remote_bd_addr); - bta_dm_search_cb.peer_bdaddr = remote_bd_addr; - - APPL_TRACE_DEBUG( - "%s name_discover_done = %d p_btm_inq_info 0x%x state = %d, transport=%d", - __func__, bta_dm_search_cb.name_discover_done, - bta_dm_search_cb.p_btm_inq_info, bta_dm_search_get_state(), transport); + UINT8_TO_STREAM(p, local_name_len + 1); + UINT8_TO_STREAM(p, data_type); - if (bta_dm_search_cb.p_btm_inq_info) { - APPL_TRACE_DEBUG("%s appl_knows_rem_name %d", __func__, - bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name); - } - if (((bta_dm_search_cb.p_btm_inq_info) && - (bta_dm_search_cb.p_btm_inq_info->results.device_type == - BT_DEVICE_TYPE_BLE) && - (bta_dm_search_get_state() == BTA_DM_SEARCH_ACTIVE)) || - (transport == BT_TRANSPORT_LE && - interop_match_addr(INTEROP_DISABLE_NAME_REQUEST, - &bta_dm_search_cb.peer_bdaddr))) { - /* Do not perform RNR for LE devices at inquiry complete*/ - bta_dm_search_cb.name_discover_done = true; - } - // If we already have the name we can skip getting the name - if (BTM_IsRemoteNameKnown(remote_bd_addr, transport) && - bluetooth::common::init_flags::sdp_skip_rnr_if_known_is_enabled()) { - LOG_DEBUG("Security record already known skipping read remote name peer:%s", - ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); - bta_dm_search_cb.name_discover_done = true; + if (local_name != NULL) { + memcpy(p, local_name, local_name_len); + p += local_name_len; } + free_eir_length -= local_name_len + 2; + +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + /* if UUID list is provided as static data in configuration */ + if ((p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0) && + (p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) { + if (free_eir_length > Uuid::kNumBytes16 + 2) { + free_eir_length -= 2; - /* if name discovery is not done and application needs remote name */ - if ((!bta_dm_search_cb.name_discover_done) && - ((bta_dm_search_cb.p_btm_inq_info == NULL) || - (bta_dm_search_cb.p_btm_inq_info && - (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) { - if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr, - transport)) { - if (bta_dm_search_get_state() != BTA_DM_DISCOVER_ACTIVE) { - LOG_DEBUG("Reset transport state for next discovery"); - bta_dm_search_cb.transport = BT_TRANSPORT_AUTO; + if (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) { + num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / Uuid::kNumBytes16; + data_type = HCI_EIR_COMPLETE_16BITS_UUID_TYPE; + } else /* not enough room for all UUIDs */ + { + LOG_WARN("BTA EIR: UUID 16-bit list is truncated"); + num_uuid = free_eir_length / Uuid::kNumBytes16; + data_type = HCI_EIR_MORE_16BITS_UUID_TYPE; } - BTM_LogHistory(kBtmLogTag, bta_dm_search_cb.peer_bdaddr, - "Read remote name", - base::StringPrintf("Transport:%s", - bt_transport_text(transport).c_str())); - return; - } else { - LOG_ERROR("Unable to start read remote device name"); + UINT8_TO_STREAM(p, num_uuid * Uuid::kNumBytes16 + 1); + UINT8_TO_STREAM(p, data_type); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, + num_uuid * Uuid::kNumBytes16); + p += num_uuid * Uuid::kNumBytes16; + free_eir_length -= num_uuid * Uuid::kNumBytes16; } - - /* starting name discovery failed */ - bta_dm_search_cb.name_discover_done = true; } +#else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ + /* if UUID list is dynamic */ + if (free_eir_length >= 2) { + p_length = p++; + p_type = p++; + num_uuid = 0; - /* Reset transport state for next discovery */ - bta_dm_search_cb.transport = BT_TRANSPORT_AUTO; - - /* if application wants to discover service */ - if (bta_dm_search_cb.services) { - BTM_LogHistory(kBtmLogTag, remote_bd_addr, "Discovery started ", - base::StringPrintf("Transport:%s", - bt_transport_text(transport).c_str())); - - /* initialize variables */ - bta_dm_search_cb.service_index = 0; - bta_dm_search_cb.services_found = 0; - bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; - - /* if seaching with EIR is not completed */ - if (bta_dm_search_cb.services_to_search) { - /* check whether connection already exists to the device - if connection exists, we don't have to wait for ACL - link to go down to start search on next device */ - if (transport == BT_TRANSPORT_BR_EDR) { - if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr, - BT_TRANSPORT_BR_EDR)) - bta_dm_search_cb.wait_disc = false; - else - bta_dm_search_cb.wait_disc = true; - } - if (bta_dm_search_cb.p_btm_inq_info) { - APPL_TRACE_DEBUG( - "%s p_btm_inq_info 0x%x results.device_type 0x%x " - "services_to_search 0x%x", - __func__, bta_dm_search_cb.p_btm_inq_info, - bta_dm_search_cb.p_btm_inq_info->results.device_type, - bta_dm_search_cb.services_to_search); - } + max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes16; + data_type = get_btm_client_interface().eir.BTM_GetEirSupportedServices( + bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid); - if (transport == BT_TRANSPORT_LE) { - if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) { - LOG_INFO("bta_dm_discovery: starting GATT discovery on %s", - ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr)); - // set the raw data buffer here - memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); - /* start GATT for service discovery */ - btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr); - return; + if (data_type == HCI_EIR_MORE_16BITS_UUID_TYPE) { + LOG_WARN("BTA EIR: UUID 16-bit list is truncated"); + } +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + else { + for (custom_uuid_idx = 0; + custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; + custom_uuid_idx++) { + const Uuid& curr = bta_dm_cb.bta_custom_uuid[custom_uuid_idx].custom_uuid; + if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes16) { + if (num_uuid < max_num_uuid) { + UINT16_TO_STREAM(p, curr.As16Bit()); + num_uuid++; + } else { + data_type = HCI_EIR_MORE_16BITS_UUID_TYPE; + LOG_WARN("BTA EIR: UUID 16-bit list is truncated"); + break; + } } - } else { - LOG_INFO("bta_dm_discovery: starting SDP discovery on %s", - ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr)); - bta_dm_search_cb.sdp_results = false; - bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); - return; } } - } - - /* name discovery and service discovery are done for this device */ - tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); - p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; - /* initialize the data structure */ - memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES)); - p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; - p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; - p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, - bta_dm_get_remname(), BD_NAME_LEN + 1); - - bta_sys_sendmsg(p_msg); -} - -/******************************************************************************* - * - * Function bta_dm_sdp_callback - * - * Description Callback from sdp with discovery status - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_sdp_callback(tSDP_STATUS sdp_status) { - tBTA_DM_SDP_RESULT* p_msg = - (tBTA_DM_SDP_RESULT*)osi_malloc(sizeof(tBTA_DM_SDP_RESULT)); +#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ - p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT; - p_msg->sdp_result = sdp_status; + UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes16 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * Uuid::kNumBytes16 + 2; + } +#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ - bta_sys_sendmsg(p_msg); -} +#if (BTA_EIR_CANNED_UUID_LIST != TRUE && BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + /* Adding 32-bit UUID list */ + if (free_eir_length >= 2) { + p_length = p++; + p_type = p++; + num_uuid = 0; + data_type = HCI_EIR_COMPLETE_32BITS_UUID_TYPE; -/******************************************************************************* - * - * Function bta_dm_inq_results_cb - * - * Description Inquiry results callback from BTM - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, - uint16_t eir_len) { - tBTA_DM_SEARCH result; - tBTM_INQ_INFO* p_inq_info; - uint16_t service_class; - - result.inq_res.bd_addr = p_inq->remote_bd_addr; - - // Pass the original address to GattService#onScanResult - result.inq_res.original_bda = p_inq->original_bda; - - memcpy(result.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN); - BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class); - result.inq_res.is_limited = - (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? true : false; - result.inq_res.rssi = p_inq->rssi; - - result.inq_res.ble_addr_type = p_inq->ble_addr_type; - result.inq_res.inq_result_type = p_inq->inq_result_type; - result.inq_res.device_type = p_inq->device_type; - result.inq_res.flag = p_inq->flag; - result.inq_res.include_rsi = p_inq->include_rsi; - - /* application will parse EIR to find out remote device name */ - result.inq_res.p_eir = const_cast(p_eir); - result.inq_res.eir_len = eir_len; - - result.inq_res.ble_evt_type = p_inq->ble_evt_type; - - p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr); - if (p_inq_info != NULL) { - /* initialize remt_name_not_required to false so that we get the name by - * default */ - result.inq_res.remt_name_not_required = false; - } + max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes32; - if (bta_dm_search_cb.p_search_cback) - bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result); + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; + custom_uuid_idx++) { + const Uuid& curr = bta_dm_cb.bta_custom_uuid[custom_uuid_idx].custom_uuid; + if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes32) { + if (num_uuid < max_num_uuid) { + UINT32_TO_STREAM(p, curr.As32Bit()); + num_uuid++; + } else { + data_type = HCI_EIR_MORE_32BITS_UUID_TYPE; + LOG_WARN("BTA EIR: UUID 32-bit list is truncated"); + break; + } + } + } - if (p_inq_info) { - /* application indicates if it knows the remote name, inside the callback - copy that to the inquiry data base*/ - if (result.inq_res.remt_name_not_required) - p_inq_info->appl_knows_rem_name = true; + UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes32 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * Uuid::kNumBytes32 + 2; } -} -/******************************************************************************* - * - * Function bta_dm_inq_cmpl_cb - * - * Description Inquiry complete callback from BTM - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_inq_cmpl_cb(void* p_result) { - APPL_TRACE_DEBUG("%s", __func__); + /* Adding 128-bit UUID list */ + if (free_eir_length >= 2) { + p_length = p++; + p_type = p++; + num_uuid = 0; + data_type = HCI_EIR_COMPLETE_128BITS_UUID_TYPE; - bta_dm_inq_cmpl(((tBTM_INQUIRY_CMPL*)p_result)->num_resp); -} + max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes128; -/******************************************************************************* - * - * Function bta_dm_service_search_remname_cback - * - * Description Remote name call back from BTM during service discovery - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_service_search_remname_cback(const RawAddress& bd_addr, - UNUSED_ATTR DEV_CLASS dc, - tBTM_BD_NAME bd_name) { - tBTM_REMOTE_DEV_NAME rem_name = {}; - tBTM_STATUS btm_status; - - APPL_TRACE_DEBUG("%s name=<%s>", __func__, bd_name); - - - /* if this is what we are looking for */ - if (bta_dm_search_cb.peer_bdaddr == bd_addr) { - rem_name.bd_addr = bd_addr; - rem_name.length = strlcpy((char*)rem_name.remote_bd_name, (char*)bd_name, - BD_NAME_LEN + 1); - if (rem_name.length > BD_NAME_LEN) { - rem_name.length = BD_NAME_LEN; - } - rem_name.status = BTM_SUCCESS; - rem_name.hci_status = HCI_SUCCESS; - bta_dm_remname_cback(&rem_name); - } else { - /* get name of device */ - btm_status = - BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr, - bta_dm_remname_cback, BT_TRANSPORT_BR_EDR); - if (btm_status == BTM_BUSY) { - /* wait for next chance(notification of remote name discovery done) */ - APPL_TRACE_DEBUG("%s: BTM_ReadRemoteDeviceName is busy", __func__); - } else if (btm_status != BTM_CMD_STARTED) { - /* if failed to start getting remote name then continue */ - APPL_TRACE_WARNING("%s: BTM_ReadRemoteDeviceName returns 0x%02X", - __func__, btm_status); - - // needed so our response is not ignored, since this corresponds to the - // actual peer_bdaddr - rem_name.bd_addr = bta_dm_search_cb.peer_bdaddr; - rem_name.length = 0; - rem_name.remote_bd_name[0] = 0; - rem_name.status = btm_status; - rem_name.hci_status = HCI_SUCCESS; - bta_dm_remname_cback(&rem_name); + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; + custom_uuid_idx++) { + const Uuid& curr = bta_dm_cb.bta_custom_uuid[custom_uuid_idx].custom_uuid; + if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes128) { + if (num_uuid < max_num_uuid) { + ARRAY16_TO_STREAM(p, curr.To128BitBE().data()); + num_uuid++; + } else { + data_type = HCI_EIR_MORE_128BITS_UUID_TYPE; + LOG_WARN("BTA EIR: UUID 128-bit list is truncated"); + break; + } + } } + + UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes128 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * Uuid::kNumBytes128 + 2; } -} +#endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE \ + )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ -/******************************************************************************* - * - * Function bta_dm_remname_cback - * - * Description Remote name complete call back from BTM - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p) { - CHECK(p != nullptr); - - tBTM_REMOTE_DEV_NAME* p_remote_name = (tBTM_REMOTE_DEV_NAME*)p; - LOG_INFO( - "Remote name request complete peer:%s btm_status:%s hci_status:%s " - "name[0]:%c length:%hu", - ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr), - btm_status_text(p_remote_name->status).c_str(), - hci_error_code_text(p_remote_name->hci_status).c_str(), - p_remote_name->remote_bd_name[0], p_remote_name->length); - - if (bta_dm_search_cb.peer_bdaddr == p_remote_name->bd_addr) { - BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); - } else { - // if we got a different response, maybe ignore it - // we will have made a request directly from BTM_ReadRemoteDeviceName so we - // expect a dedicated response for us - if (p_remote_name->hci_status == HCI_ERR_CONNECTION_EXISTS) { - BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); - LOG_INFO( - "Assume command failed due to disconnection hci_status:%s peer:%s", - hci_error_code_text(p_remote_name->hci_status).c_str(), - ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr)); - } else { - LOG_INFO( - "Ignored remote name response for the wrong address exp:%s act:%s", - ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr), - ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr)); - return; - } - } - - /* remote name discovery is done but it could be failed */ - bta_dm_search_cb.name_discover_done = true; - strlcpy((char*)bta_dm_search_cb.peer_name, - (char*)p_remote_name->remote_bd_name, BD_NAME_LEN + 1); - - if (bta_dm_search_cb.transport == BT_TRANSPORT_LE) { - GAP_BleReadPeerPrefConnParams(bta_dm_search_cb.peer_bdaddr); - } - - tBTA_DM_REM_NAME* p_msg = - (tBTA_DM_REM_NAME*)osi_malloc(sizeof(tBTA_DM_REM_NAME)); - p_msg->result.disc_res.hci_status = p->hci_status; - p_msg->result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - strlcpy((char*)p_msg->result.disc_res.bd_name, - (char*)p_remote_name->remote_bd_name, BD_NAME_LEN + 1); - p_msg->hdr.event = BTA_DM_REMT_NAME_EVT; - - bta_sys_sendmsg(p_msg); -} - -/******************************************************************************* - * - * Function bta_dm_pinname_cback - * - * Description Callback requesting pin_key - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_pinname_cback(const tBTM_REMOTE_DEV_NAME* p_data) { - tBTM_REMOTE_DEV_NAME* p_result = (tBTM_REMOTE_DEV_NAME*)p_data; - tBTA_DM_SEC sec_event; - uint32_t bytes_to_copy; - tBTA_DM_SEC_EVT event = bta_dm_cb.pin_evt; - - if (BTA_DM_SP_CFM_REQ_EVT == event) { - /* Retrieved saved device class and bd_addr */ - sec_event.cfm_req.bd_addr = bta_dm_cb.pin_bd_addr; - BTA_COPY_DEVICE_CLASS(sec_event.cfm_req.dev_class, bta_dm_cb.pin_dev_class); - - if (p_result && p_result->status == BTM_SUCCESS) { - bytes_to_copy = - (p_result->length < BD_NAME_LEN) ? p_result->length : BD_NAME_LEN; - memcpy(sec_event.cfm_req.bd_name, p_result->remote_bd_name, - bytes_to_copy); - sec_event.pin_req.bd_name[BD_NAME_LEN] = 0; - } else /* No name found */ - sec_event.cfm_req.bd_name[0] = 0; - - sec_event.key_notif.passkey = - bta_dm_cb.num_val; /* get PIN code numeric number */ - - /* 1 additional event data fields for this event */ - sec_event.cfm_req.just_works = bta_dm_cb.just_works; - /* retrieve the loc and rmt caps */ - sec_event.cfm_req.loc_io_caps = bta_dm_cb.loc_io_caps; - sec_event.cfm_req.rmt_io_caps = bta_dm_cb.rmt_io_caps; - sec_event.cfm_req.loc_auth_req = bta_dm_cb.loc_auth_req; - sec_event.cfm_req.rmt_auth_req = bta_dm_cb.rmt_auth_req; - - } else { - /* Retrieved saved device class and bd_addr */ - sec_event.pin_req.bd_addr = bta_dm_cb.pin_bd_addr; - BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, bta_dm_cb.pin_dev_class); - - if (p_result && p_result->status == BTM_SUCCESS) { - bytes_to_copy = (p_result->length < BD_NAME_LEN) ? p_result->length - : (BD_NAME_LEN - 1); - memcpy(sec_event.pin_req.bd_name, p_result->remote_bd_name, - bytes_to_copy); - sec_event.pin_req.bd_name[BD_NAME_LEN] = 0; - } else /* No name found */ - sec_event.pin_req.bd_name[0] = 0; - - event = bta_dm_cb.pin_evt; - sec_event.key_notif.passkey = - bta_dm_cb.num_val; /* get PIN code numeric number */ - } - - if (bta_dm_cb.p_sec_cback) bta_dm_cb.p_sec_cback(event, &sec_event); -} - -/******************************************************************************* - * - * Function bta_dm_pin_cback - * - * Description Callback requesting pin_key - * - * Returns void - * - ******************************************************************************/ -static uint8_t bta_dm_pin_cback(const RawAddress& bd_addr, DEV_CLASS dev_class, - const tBTM_BD_NAME bd_name, bool min_16_digit) { - if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED; - - /* If the device name is not known, save bdaddr and devclass and initiate a - * name request */ - if (bd_name[0] == 0) { - bta_dm_cb.pin_evt = BTA_DM_PIN_REQ_EVT; - bta_dm_cb.pin_bd_addr = bd_addr; - BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, dev_class); - if ((BTM_ReadRemoteDeviceName(bd_addr, bta_dm_pinname_cback, - BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) - return BTM_CMD_STARTED; - - APPL_TRACE_WARNING( - " bta_dm_pin_cback() -> Failed to start Remote Name Request "); - } - - tBTA_DM_SEC sec_event = {.pin_req = { - .bd_addr = bd_addr, - }}; - BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, dev_class); - strlcpy((char*)sec_event.pin_req.bd_name, (char*)bd_name, BD_NAME_LEN + 1); - sec_event.pin_req.min_16_digit = min_16_digit; - - bta_dm_cb.p_sec_cback(BTA_DM_PIN_REQ_EVT, &sec_event); - return BTM_CMD_STARTED; -} - -/******************************************************************************* - * - * Function bta_dm_new_link_key_cback - * - * Description Callback from BTM to notify new link key - * - * Returns void - * - ******************************************************************************/ -static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr, - UNUSED_ATTR DEV_CLASS dev_class, - tBTM_BD_NAME bd_name, - const LinkKey& key, uint8_t key_type, - bool is_ctkd) { - tBTA_DM_SEC sec_event; - tBTA_DM_AUTH_CMPL* p_auth_cmpl; - tBTA_DM_SEC_EVT event = BTA_DM_AUTH_CMPL_EVT; - - memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); - - p_auth_cmpl = &sec_event.auth_cmpl; - - p_auth_cmpl->bd_addr = bd_addr; - - memcpy(p_auth_cmpl->bd_name, bd_name, BD_NAME_LEN); - p_auth_cmpl->bd_name[BD_NAME_LEN] = 0; - p_auth_cmpl->key_present = true; - p_auth_cmpl->key_type = key_type; - p_auth_cmpl->success = true; - p_auth_cmpl->key = key; - p_auth_cmpl->is_ctkd = is_ctkd; - - sec_event.auth_cmpl.fail_reason = HCI_SUCCESS; - - // Report the BR link key based on the BR/EDR address and type - BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type, - &sec_event.auth_cmpl.addr_type); - if (bta_dm_cb.p_sec_cback) bta_dm_cb.p_sec_cback(event, &sec_event); - - // Setting remove_dev_pending flag to false, where it will avoid deleting - // the - // security device record when the ACL connection link goes down in case of - // reconnection. - if (bta_dm_cb.device_list.count) - bta_dm_reset_sec_dev_pending(p_auth_cmpl->bd_addr); - - return BTM_CMD_STARTED; -} - -/******************************************************************************* - * - * Function bta_dm_authentication_complete_cback - * - * Description Authentication complete callback from BTM - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_authentication_complete_cback( - const RawAddress& bd_addr, UNUSED_ATTR DEV_CLASS dev_class, - tBTM_BD_NAME bd_name, tHCI_REASON reason) { - if (reason != HCI_SUCCESS) { - if (bta_dm_cb.p_sec_cback) { - // Build out the security event data structure - tBTA_DM_SEC sec_event = { - .auth_cmpl = - { - .bd_addr = bd_addr, - }, - }; - memcpy(sec_event.auth_cmpl.bd_name, bd_name, BD_NAME_LEN); - sec_event.auth_cmpl.bd_name[BD_NAME_LEN] = 0; - - // Report the BR link key based on the BR/EDR address and type - BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type, - &sec_event.auth_cmpl.addr_type); - sec_event.auth_cmpl.fail_reason = reason; - - bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); - } - - switch (reason) { - case HCI_ERR_AUTH_FAILURE: - case HCI_ERR_KEY_MISSING: - case HCI_ERR_HOST_REJECT_SECURITY: - case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE: - LOG_WARN( - "Deleting device record as authentication failed entry:%s " - "reason:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), hci_reason_code_text(reason).c_str()); - break; - - default: - break; - } - } -} - -/******************************************************************************* - * - * Function bta_dm_sp_cback - * - * Description simple pairing callback from BTM - * - * Returns void - * - ******************************************************************************/ -static tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, - tBTM_SP_EVT_DATA* p_data) { - tBTM_STATUS status = BTM_CMD_STARTED; - tBTA_DM_SEC sec_event; - tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT; - - APPL_TRACE_EVENT("bta_dm_sp_cback: %d", event); - if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED; - - bool sp_rmt_result = false; - /* TODO_SP */ - switch (event) { - case BTM_SP_IO_REQ_EVT: - if (btm_local_io_caps != BTM_IO_CAP_NONE) { - /* translate auth_req */ - btif_dm_set_oob_for_io_req(&p_data->io_req.oob_data); - btif_dm_proc_io_req(&p_data->io_req.auth_req, p_data->io_req.is_orig); - } - APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req, - p_data->io_req.oob_data); - break; - case BTM_SP_IO_RSP_EVT: - if (btm_local_io_caps != BTM_IO_CAP_NONE) { - btif_dm_proc_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap, - p_data->io_rsp.oob_data, p_data->io_rsp.auth_req); - } - break; - - case BTM_SP_CFM_REQ_EVT: - pin_evt = BTA_DM_SP_CFM_REQ_EVT; - bta_dm_cb.just_works = sec_event.cfm_req.just_works = - p_data->cfm_req.just_works; - sec_event.cfm_req.loc_auth_req = p_data->cfm_req.loc_auth_req; - sec_event.cfm_req.rmt_auth_req = p_data->cfm_req.rmt_auth_req; - sec_event.cfm_req.loc_io_caps = p_data->cfm_req.loc_io_caps; - sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps; - - [[fallthrough]]; - /* Passkey entry mode, mobile device with output capability is very - unlikely to receive key request, so skip this event */ - /*case BTM_SP_KEY_REQ_EVT: */ - case BTM_SP_KEY_NOTIF_EVT: - if (btm_local_io_caps == BTM_IO_CAP_NONE && - BTM_SP_KEY_NOTIF_EVT == event) { - status = BTM_NOT_AUTHORIZED; - break; - } - - bta_dm_cb.num_val = sec_event.key_notif.passkey = - p_data->key_notif.passkey; - - if (BTM_SP_CFM_REQ_EVT == event) { - /* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT, - call remote name request using values from cfm_req */ - if (p_data->cfm_req.bd_name[0] == 0) { - bta_dm_cb.pin_evt = pin_evt; - bta_dm_cb.pin_bd_addr = p_data->cfm_req.bd_addr; - bta_dm_cb.rmt_io_caps = sec_event.cfm_req.rmt_io_caps; - bta_dm_cb.loc_io_caps = sec_event.cfm_req.loc_io_caps; - bta_dm_cb.rmt_auth_req = sec_event.cfm_req.rmt_auth_req; - bta_dm_cb.loc_auth_req = sec_event.cfm_req.loc_auth_req; - - BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, - p_data->cfm_req.dev_class); - if ((BTM_ReadRemoteDeviceName( - p_data->cfm_req.bd_addr, bta_dm_pinname_cback, - BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) - return BTM_CMD_STARTED; - APPL_TRACE_WARNING( - " bta_dm_sp_cback() -> Failed to start Remote Name Request "); - } else { - /* Due to the switch case falling through below to - BTM_SP_KEY_NOTIF_EVT, - copy these values into key_notif from cfm_req */ - sec_event.key_notif.bd_addr = p_data->cfm_req.bd_addr; - BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class, - p_data->cfm_req.dev_class); - strlcpy((char*)sec_event.key_notif.bd_name, - (char*)p_data->cfm_req.bd_name, BD_NAME_LEN + 1); - } - } - - if (BTM_SP_KEY_NOTIF_EVT == event) { - /* If the device name is not known, save bdaddr and devclass - and initiate a name request with values from key_notif */ - if (p_data->key_notif.bd_name[0] == 0) { - bta_dm_cb.pin_evt = pin_evt; - bta_dm_cb.pin_bd_addr = p_data->key_notif.bd_addr; - BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, - p_data->key_notif.dev_class); - if ((BTM_ReadRemoteDeviceName( - p_data->key_notif.bd_addr, bta_dm_pinname_cback, - BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) - return BTM_CMD_STARTED; - APPL_TRACE_WARNING( - " bta_dm_sp_cback() -> Failed to start Remote Name Request "); - } else { - sec_event.key_notif.bd_addr = p_data->key_notif.bd_addr; - BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class, - p_data->key_notif.dev_class); - strlcpy((char*)sec_event.key_notif.bd_name, - (char*)p_data->key_notif.bd_name, BD_NAME_LEN + 1); - sec_event.key_notif.bd_name[BD_NAME_LEN] = 0; - } - } - - bta_dm_cb.p_sec_cback(pin_evt, &sec_event); - - break; - - case BTM_SP_LOC_OOB_EVT: -#ifdef BTIF_DM_OOB_TEST - btif_dm_proc_loc_oob(BT_TRANSPORT_BR_EDR, - (bool)(p_data->loc_oob.status == BTM_SUCCESS), - p_data->loc_oob.c, p_data->loc_oob.r); -#endif - break; - - case BTM_SP_RMT_OOB_EVT: { - Octet16 c; - Octet16 r; - sp_rmt_result = false; -#ifdef BTIF_DM_OOB_TEST - sp_rmt_result = btif_dm_proc_rmt_oob(p_data->rmt_oob.bd_addr, &c, &r); -#endif - BTIF_TRACE_DEBUG("bta_dm_ci_rmt_oob: result=%d", sp_rmt_result); - bta_dm_ci_rmt_oob(sp_rmt_result, p_data->rmt_oob.bd_addr, c, r); - break; - } - - default: - status = BTM_NOT_AUTHORIZED; - break; - } - APPL_TRACE_EVENT("dm status: %d", status); - return status; -} - -/******************************************************************************* - * - * Function bta_dm_local_name_cback - * - * Description Callback from btm after local name is read - * - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_local_name_cback(UNUSED_ATTR void* p_name) { - BTIF_dm_enable(); -} - -static void handle_role_change(const RawAddress& bd_addr, tHCI_ROLE new_role, - tHCI_STATUS hci_status) { - tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr); - if (!p_dev) { - LOG_WARN( - "Unable to find device for role change peer:%s new_role:%s " - "hci_status:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), RoleText(new_role).c_str(), - hci_error_code_text(hci_status).c_str()); - return; - } - - LOG_INFO( - "Role change callback peer:%s info:0x%x new_role:%s dev count:%d " - "hci_status:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), p_dev->Info(), RoleText(new_role).c_str(), - bta_dm_cb.device_list.count, hci_error_code_text(hci_status).c_str()); - - if (p_dev->Info() & BTA_DM_DI_AV_ACTIVE) { - bool need_policy_change = false; - - /* there's AV activity on this link */ - if (new_role == HCI_ROLE_PERIPHERAL && bta_dm_cb.device_list.count > 1 && - hci_status == HCI_SUCCESS) { - /* more than one connections and the AV connection is role switched - * to peripheral - * switch it back to central and remove the switch policy */ - BTM_SwitchRoleToCentral(bd_addr); - need_policy_change = true; - } else if (p_bta_dm_cfg->avoid_scatter && (new_role == HCI_ROLE_CENTRAL)) { - /* if the link updated to be central include AV activities, remove - * the switch policy */ - need_policy_change = true; - } - - if (need_policy_change) { - BTM_block_role_switch_for(p_dev->peer_bdaddr); - } - } else { - /* there's AV no activity on this link and role switch happened - * check if AV is active - * if so, make sure the AV link is central */ - bta_dm_check_av(); - } - bta_sys_notify_role_chg(bd_addr, new_role, hci_status); -} - -void BTA_dm_report_role_change(const RawAddress bd_addr, tHCI_ROLE new_role, - tHCI_STATUS hci_status) { - do_in_main_thread( - FROM_HERE, base::Bind(handle_role_change, bd_addr, new_role, hci_status)); -} - -void handle_remote_features_complete(const RawAddress& bd_addr) { - tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr); - if (!p_dev) { - LOG_WARN("Unable to find device peer:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - return; - } - - if (controller_get_interface()->supports_sniff_subrating() && - acl_peer_supports_sniff_subrating(bd_addr)) { - LOG_DEBUG("Device supports sniff subrating peer:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - p_dev->info = BTA_DM_DI_USE_SSR; - } else { - LOG_DEBUG("Device does NOT support sniff subrating peer:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - } -} - -void BTA_dm_notify_remote_features_complete(const RawAddress bd_addr) { - do_in_main_thread(FROM_HERE, - base::Bind(handle_remote_features_complete, bd_addr)); -} - -static tBTA_DM_PEER_DEVICE* allocate_device_for(const RawAddress& bd_addr, - tBT_TRANSPORT transport) { - for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) { - auto device = &bta_dm_cb.device_list.peer_device[i]; - if (device->peer_bdaddr == bd_addr && device->transport == transport) { - return device; - } - } - - if (bta_dm_cb.device_list.count < BTA_DM_NUM_PEER_DEVICE) { - auto device = - &bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]; - device->peer_bdaddr = bd_addr; - bta_dm_cb.device_list.count++; - if (transport == BT_TRANSPORT_LE) { - bta_dm_cb.device_list.le_count++; - } - return device; - } - return nullptr; -} - -void bta_dm_acl_up(const RawAddress& bd_addr, tBT_TRANSPORT transport, - uint16_t acl_handle) { - auto device = allocate_device_for(bd_addr, transport); - if (device == nullptr) { - LOG_WARN("Unable to allocate device resources for new connection"); - return; - } - device->conn_state = BTA_DM_CONNECTED; - device->pref_role = BTA_ANY_ROLE; - device->info = BTA_DM_DI_NONE; - device->transport = transport; - - if (controller_get_interface()->supports_sniff_subrating() && - acl_peer_supports_sniff_subrating(bd_addr)) { - // NOTE: This callback assumes upon ACL connection that - // the read remote features has completed and is valid. - // The only guaranteed contract for valid read remote features - // data is when the BTA_dm_notify_remote_features_complete() - // callback has completed. The below assignment is kept for - // transitional informational purposes only. - device->info = BTA_DM_DI_USE_SSR; - } - - if (bta_dm_cb.p_sec_cback) { - tBTA_DM_SEC conn; - memset(&conn, 0, sizeof(tBTA_DM_SEC)); - conn.link_up.bd_addr = bd_addr; - conn.link_up.transport_link_type = transport; - conn.link_up.acl_handle = acl_handle; - - bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, &conn); - LOG_DEBUG("Executed security callback for new connection available"); - } - bta_dm_adjust_roles(true); -} - -void BTA_dm_acl_up(const RawAddress bd_addr, tBT_TRANSPORT transport, - uint16_t acl_handle) { - do_in_main_thread(FROM_HERE, - base::Bind(bta_dm_acl_up, bd_addr, transport, acl_handle)); -} - -static void bta_dm_acl_up_failed(const RawAddress bd_addr, - tBT_TRANSPORT transport, tHCI_STATUS status) { - if (bta_dm_cb.p_sec_cback) { - tBTA_DM_SEC conn = {}; - conn.link_up_failed.bd_addr = bd_addr; - conn.link_up_failed.transport_link_type = transport; - conn.link_up_failed.status = status; - bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_FAILED_EVT, &conn); - } -} - -void BTA_dm_acl_up_failed(const RawAddress bd_addr, tBT_TRANSPORT transport, - tHCI_STATUS status) { - do_in_main_thread( - FROM_HERE, base::Bind(bta_dm_acl_up_failed, bd_addr, transport, status)); -} - -static void bta_dm_acl_down(const RawAddress& bd_addr, - tBT_TRANSPORT transport) { - bool issue_unpair_cb = false; - bool remove_device = false; - - for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) { - auto device = &bta_dm_cb.device_list.peer_device[i]; - if (device->peer_bdaddr != bd_addr || device->transport != transport) - continue; - - if (device->conn_state == BTA_DM_UNPAIRING) { - issue_unpair_cb = BTM_SecDeleteDevice(device->peer_bdaddr); - - /* remove all cached GATT information */ - BTA_GATTC_Refresh(bd_addr); - - APPL_TRACE_DEBUG("%s: Unpairing: issue unpair CB = %d ", __func__, - issue_unpair_cb); - } - - remove_device = device->remove_dev_pending; - - // Iterate to the one before the last when shrinking the list, - // otherwise we memcpy garbage data into the record. - // Then clear out the last item in the list since we are shrinking. - for (; i < bta_dm_cb.device_list.count - 1; i++) { - memcpy(&bta_dm_cb.device_list.peer_device[i], - &bta_dm_cb.device_list.peer_device[i + 1], - sizeof(bta_dm_cb.device_list.peer_device[i])); - } - if (bta_dm_cb.device_list.count > 0) { - int clear_index = bta_dm_cb.device_list.count - 1; - memset(&bta_dm_cb.device_list.peer_device[clear_index], 0, - sizeof(bta_dm_cb.device_list.peer_device[clear_index])); - } - break; - } - if (bta_dm_cb.device_list.count) bta_dm_cb.device_list.count--; - if ((transport == BT_TRANSPORT_LE) && (bta_dm_cb.device_list.le_count)) { - bta_dm_cb.device_list.le_count--; - } - - if ((transport == BT_TRANSPORT_BR_EDR) && - (bta_dm_search_cb.wait_disc && bta_dm_search_cb.peer_bdaddr == bd_addr)) { - bta_dm_search_cb.wait_disc = false; - - if (bta_dm_search_cb.sdp_results) { - APPL_TRACE_EVENT(" timer stopped "); - alarm_cancel(bta_dm_search_cb.search_timer); - bta_dm_discover_next_device(); - } - } - - if (bta_dm_cb.disabling) { - if (!BTM_GetNumAclLinks()) { - /* - * Start a timer to make sure that the profiles - * get the disconnect event. - */ - alarm_set_on_mloop(bta_dm_cb.disable_timer, - BTA_DM_DISABLE_CONN_DOWN_TIMER_MS, - bta_dm_disable_conn_down_timer_cback, NULL); - } - } - if (remove_device) { - bta_dm_process_remove_device_no_callback(bd_addr); - } - - if (bta_dm_cb.p_sec_cback) { - tBTA_DM_SEC conn; - memset(&conn, 0, sizeof(tBTA_DM_SEC)); - conn.link_down.bd_addr = bd_addr; - conn.link_down.transport_link_type = transport; - - bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn); - if (issue_unpair_cb) bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn); - } - - bta_dm_adjust_roles(true); -} - -void BTA_dm_acl_down(const RawAddress bd_addr, tBT_TRANSPORT transport) { - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_acl_down, bd_addr, transport)); -} - -/******************************************************************************* - * - * Function bta_dm_check_av - * - * Description This function checks if AV is active - * if yes, make sure the AV link is central - * - ******************************************************************************/ -static void bta_dm_check_av() { - uint8_t i; - tBTA_DM_PEER_DEVICE* p_dev; - - if (bta_dm_cb.cur_av_count) { - LOG_INFO("av_count:%d", bta_dm_cb.cur_av_count); - for (i = 0; i < bta_dm_cb.device_list.count; i++) { - p_dev = &bta_dm_cb.device_list.peer_device[i]; - APPL_TRACE_WARNING("[%d]: state:%d, info:x%x", i, p_dev->conn_state, - p_dev->Info()); - if ((p_dev->conn_state == BTA_DM_CONNECTED) && - (p_dev->Info() & BTA_DM_DI_AV_ACTIVE)) { - /* make central and take away the role switch policy */ - BTM_SwitchRoleToCentral(p_dev->peer_bdaddr); - /* else either already central or can not switch for some reasons */ - BTM_block_role_switch_for(p_dev->peer_bdaddr); - break; - } - } - } -} - -/******************************************************************************* - * - * Function bta_dm_disable_conn_down_timer_cback - * - * Description Sends disable event to application - * - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_disable_conn_down_timer_cback(UNUSED_ATTR void* data) { - /* disable the power managment module */ - bta_dm_disable_pm(); - - bta_dm_cb.disabling = false; - LOG_INFO("Stack device manager shutdown completed"); - future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS); -} - -/******************************************************************************* - * - * Function bta_dm_rm_cback - * - * Description Role management callback from sys - * - * - * Returns void - * - ******************************************************************************/ -void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, uint8_t app_id, - const RawAddress& peer_addr) { - uint8_t j; - tBTA_PREF_ROLES role; - tBTA_DM_PEER_DEVICE* p_dev; - - LOG_DEBUG("BTA Role management callback count:%d status:%s peer:%s", - bta_dm_cb.cur_av_count, bta_sys_conn_status_text(status).c_str(), - ADDRESS_TO_LOGGABLE_CSTR(peer_addr)); - - p_dev = bta_dm_find_peer_device(peer_addr); - if (status == BTA_SYS_CONN_OPEN) { - if (p_dev) { - /* Do not set to connected if we are in the middle of unpairing. When AV - * stream is - * started it fakes out a SYS_CONN_OPEN to potentially trigger a role - * switch command. - * But this should not be done if we are in the middle of unpairing. - */ - if (p_dev->conn_state != BTA_DM_UNPAIRING) - p_dev->conn_state = BTA_DM_CONNECTED; - - for (j = 1; j <= p_bta_dm_rm_cfg[0].app_id; j++) { - if (((p_bta_dm_rm_cfg[j].app_id == app_id) || - (p_bta_dm_rm_cfg[j].app_id == BTA_ALL_APP_ID)) && - (p_bta_dm_rm_cfg[j].id == id)) { - ASSERT_LOG(p_bta_dm_rm_cfg[j].cfg <= BTA_PERIPHERAL_ROLE_ONLY, - "Passing illegal preferred role:0x%02x [0x%02x<=>0x%02x]", - p_bta_dm_rm_cfg[j].cfg, BTA_ANY_ROLE, - BTA_PERIPHERAL_ROLE_ONLY); - role = static_cast(p_bta_dm_rm_cfg[j].cfg); - if (role > p_dev->pref_role) p_dev->pref_role = role; - break; - } - } - } - } - - if (BTA_ID_AV == id) { - if (status == BTA_SYS_CONN_BUSY) { - if (p_dev) p_dev->info |= BTA_DM_DI_AV_ACTIVE; - /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */ - if (BTA_ID_AV == id) bta_dm_cb.cur_av_count = bta_dm_get_av_count(); - } else if (status == BTA_SYS_CONN_IDLE) { - if (p_dev) p_dev->info &= ~BTA_DM_DI_AV_ACTIVE; - - /* get cur_av_count from connected services */ - if (BTA_ID_AV == id) bta_dm_cb.cur_av_count = bta_dm_get_av_count(); - } - } - - /* Don't adjust roles for each busy/idle state transition to avoid - excessive switch requests when individual profile busy/idle status - changes */ - if ((status != BTA_SYS_CONN_BUSY) && (status != BTA_SYS_CONN_IDLE)) - bta_dm_adjust_roles(false); -} - -/******************************************************************************* - * - * Function bta_dm_delay_role_switch_cback - * - * Description Callback from btm to delay a role switch - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_delay_role_switch_cback(UNUSED_ATTR void* data) { - APPL_TRACE_EVENT("%s: initiating Delayed RS", __func__); - bta_dm_adjust_roles(false); -} - -/******************************************************************************* - * - * Function bta_dm_reset_sec_dev_pending - * - * Description Setting the remove device pending status to false from - * security device DB, when the link key notification - * event comes. - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_reset_sec_dev_pending(const RawAddress& remote_bd_addr) { - for (size_t i = 0; i < bta_dm_cb.device_list.count; i++) { - if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == remote_bd_addr) { - bta_dm_cb.device_list.peer_device[i].remove_dev_pending = false; - return; - } - } -} - -/******************************************************************************* - * - * Function bta_dm_remove_sec_dev_entry - * - * Description Removes device entry from Security device DB if ACL - connection with - * remtoe device does not exist, else schedule for dev entry - removal upon - ACL close - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_remove_sec_dev_entry(const RawAddress& remote_bd_addr) { - if (BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_LE) || - BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_BR_EDR)) { - APPL_TRACE_DEBUG( - "%s ACL is not down. Schedule for Dev Removal when ACL closes", - __func__); - BTM_SecClearSecurityFlags(remote_bd_addr); - for (int i = 0; i < bta_dm_cb.device_list.count; i++) { - if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == remote_bd_addr) { - bta_dm_cb.device_list.peer_device[i].remove_dev_pending = TRUE; - break; - } - } - } else { - // remote_bd_addr comes from security record, which is removed in - // BTM_SecDeleteDevice. - RawAddress addr_copy = remote_bd_addr; - bta_dm_process_remove_device_no_callback(addr_copy); - } -} - -/******************************************************************************* - * - * Function bta_dm_adjust_roles - * - * Description Adjust roles - * - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_adjust_roles(bool delay_role_switch) { - uint8_t i; - uint8_t link_count = bta_dm_cb.device_list.count; - if (link_count) { - for (i = 0; i < bta_dm_cb.device_list.count; i++) { - if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED && - bta_dm_cb.device_list.peer_device[i].transport == - BT_TRANSPORT_BR_EDR) { - if ((bta_dm_cb.device_list.peer_device[i].pref_role == - BTA_CENTRAL_ROLE_ONLY) || - (link_count > 1)) { - /* Initiating immediate role switch with certain remote devices - has caused issues due to role switch colliding with link encryption - setup and - causing encryption (and in turn the link) to fail . These device . - Firmware - versions are stored in a rejectlist and role switch with these - devices are - delayed to avoid the collision with link encryption setup */ - - if (bta_dm_cb.device_list.peer_device[i].pref_role != - BTA_PERIPHERAL_ROLE_ONLY && - !delay_role_switch) { - BTM_SwitchRoleToCentral( - bta_dm_cb.device_list.peer_device[i].peer_bdaddr); - } else { - alarm_set_on_mloop(bta_dm_cb.switch_delay_timer, - BTA_DM_SWITCH_DELAY_TIMER_MS, - bta_dm_delay_role_switch_cback, NULL); - } - } - } - } - } -} - -/******************************************************************************* - * - * Function bta_dm_get_remname - * - * Description Returns a pointer to the remote name stored in the DM - * control block if it exists, or from the BTM memory. - * - * Returns char * - Pointer to the remote device name - ******************************************************************************/ -static char* bta_dm_get_remname(void) { - char* p_name = (char*)bta_dm_search_cb.peer_name; - char* p_temp; - - /* If the name isn't already stored, try retrieving from BTM */ - if (*p_name == '\0') { - p_temp = BTM_SecReadDevName(bta_dm_search_cb.peer_bdaddr); - if (p_temp != NULL) p_name = p_temp; - } - - return p_name; -} - -/******************************************************************************* - * - * Function bta_dm_bond_cancel_complete_cback - * - * Description Authentication complete callback from BTM - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result) { - tBTA_DM_SEC sec_event; - - if (result == BTM_SUCCESS) - sec_event.bond_cancel_cmpl.result = BTA_SUCCESS; - else - sec_event.bond_cancel_cmpl.result = BTA_FAILURE; - - if (bta_dm_cb.p_sec_cback) { - bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event); - } -} - -/******************************************************************************* - * - * Function find_utf8_char_boundary - * - * Description This function checks a UTF8 string |utf8str| starting at - * |offset|, moving backwards and returns the offset of the - * next valid UTF8 character boundary found. - * - * Returns Offset of UTF8 character boundary - * - ******************************************************************************/ -static size_t find_utf8_char_boundary(const char* utf8str, size_t offset) { - CHECK(utf8str); - CHECK(offset > 0); - - while (--offset) { - uint8_t ch = (uint8_t)utf8str[offset]; - if ((ch & 0x80) == 0x00) // ASCII - return offset + 1; - if ((ch & 0xC0) == 0xC0) // Multi-byte sequence start - return offset; - } - - return 0; -} - -/******************************************************************************* - * - * Function bta_dm_set_eir - * - * Description This function creates EIR tagged data and writes it to - * controller. - * - * Returns None - * - ******************************************************************************/ -static void bta_dm_set_eir(char* local_name) { - uint8_t* p; - uint8_t* p_length; -#if (BTA_EIR_CANNED_UUID_LIST != TRUE) - uint8_t* p_type; - uint8_t max_num_uuid; -#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) - uint8_t custom_uuid_idx; -#endif // BTA_EIR_SERVER_NUM_CUSTOM_UUID -#endif // BTA_EIR_CANNED_UUID_LIST -#if (BTM_EIR_DEFAULT_FEC_REQUIRED == FALSE) - uint8_t free_eir_length = HCI_EXT_INQ_RESPONSE_LEN; -#else // BTM_EIR_DEFAULT_FEC_REQUIRED - uint8_t free_eir_length = HCI_DM5_PACKET_SIZE; -#endif // BTM_EIR_DEFAULT_FEC_REQUIRED - uint8_t num_uuid; - uint8_t data_type; - uint8_t local_name_len; - - /* wait until complete to disable */ - if (alarm_is_scheduled(bta_dm_cb.disable_timer)) return; - -#if (BTA_EIR_CANNED_UUID_LIST != TRUE) - /* if local name is not provided, get it from controller */ - if (local_name == NULL) { - if (BTM_ReadLocalDeviceName((const char**)&local_name) != BTM_SUCCESS) { - APPL_TRACE_ERROR("Fail to read local device name for EIR"); - } - } -#endif // BTA_EIR_CANNED_UUID_LIST - - /* Allocate a buffer to hold HCI command */ - BT_HDR* p_buf = (BT_HDR*)osi_malloc(BTM_CMD_BUF_SIZE); - ASSERT(p_buf != nullptr); - p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET; - - memset(p, 0x00, HCI_EXT_INQ_RESPONSE_LEN); - - LOG_INFO("Generating extended inquiry response packet EIR"); - - if (local_name) - local_name_len = strlen(local_name); - else - local_name_len = 0; - - data_type = HCI_EIR_COMPLETE_LOCAL_NAME_TYPE; - /* if local name is longer than minimum length of shortened name */ - /* check whether it needs to be shortened or not */ - if (local_name_len > p_bta_dm_eir_cfg->bta_dm_eir_min_name_len) { -/* get number of UUID 16-bit list */ -#if (BTA_EIR_CANNED_UUID_LIST == TRUE) - num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / Uuid::kNumBytes16; -#else // BTA_EIR_CANNED_UUID_LIST - max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes16; - data_type = get_btm_client_interface().eir.BTM_GetEirSupportedServices( - bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid); - p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */ -#endif // BTA_EIR_CANNED_UUID_LIST - - /* if UUID doesn't fit remaing space, shorten local name */ - if (local_name_len > (free_eir_length - 4 - num_uuid * Uuid::kNumBytes16)) { - local_name_len = find_utf8_char_boundary( - local_name, p_bta_dm_eir_cfg->bta_dm_eir_min_name_len); - APPL_TRACE_WARNING("%s local name is shortened (%d)", __func__, - local_name_len); - data_type = HCI_EIR_SHORTENED_LOCAL_NAME_TYPE; - } else { - data_type = HCI_EIR_COMPLETE_LOCAL_NAME_TYPE; - } - } - - UINT8_TO_STREAM(p, local_name_len + 1); - UINT8_TO_STREAM(p, data_type); - - if (local_name != NULL) { - memcpy(p, local_name, local_name_len); - p += local_name_len; - } - free_eir_length -= local_name_len + 2; - -#if (BTA_EIR_CANNED_UUID_LIST == TRUE) - /* if UUID list is provided as static data in configuration */ - if ((p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0) && - (p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) { - if (free_eir_length > Uuid::kNumBytes16 + 2) { - free_eir_length -= 2; - - if (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) { - num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / Uuid::kNumBytes16; - data_type = HCI_EIR_COMPLETE_16BITS_UUID_TYPE; - } else /* not enough room for all UUIDs */ - { - APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); - num_uuid = free_eir_length / Uuid::kNumBytes16; - data_type = HCI_EIR_MORE_16BITS_UUID_TYPE; - } - UINT8_TO_STREAM(p, num_uuid * Uuid::kNumBytes16 + 1); - UINT8_TO_STREAM(p, data_type); - memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, - num_uuid * Uuid::kNumBytes16); - p += num_uuid * Uuid::kNumBytes16; - free_eir_length -= num_uuid * Uuid::kNumBytes16; - } - } -#else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ - /* if UUID list is dynamic */ - if (free_eir_length >= 2) { - p_length = p++; - p_type = p++; - num_uuid = 0; - - max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes16; - data_type = get_btm_client_interface().eir.BTM_GetEirSupportedServices( - bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid); - - if (data_type == HCI_EIR_MORE_16BITS_UUID_TYPE) { - APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); - } -#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) - else { - for (custom_uuid_idx = 0; - custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; - custom_uuid_idx++) { - const Uuid& curr = bta_dm_cb.bta_custom_uuid[custom_uuid_idx].custom_uuid; - if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes16) { - if (num_uuid < max_num_uuid) { - UINT16_TO_STREAM(p, curr.As16Bit()); - num_uuid++; - } else { - data_type = HCI_EIR_MORE_16BITS_UUID_TYPE; - APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); - break; - } - } - } - } -#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ - - UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes16 + 1); - UINT8_TO_STREAM(p_type, data_type); - free_eir_length -= num_uuid * Uuid::kNumBytes16 + 2; - } -#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ - -#if (BTA_EIR_CANNED_UUID_LIST != TRUE && BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) - /* Adding 32-bit UUID list */ - if (free_eir_length >= 2) { - p_length = p++; - p_type = p++; - num_uuid = 0; - data_type = HCI_EIR_COMPLETE_32BITS_UUID_TYPE; - - max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes32; - - for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; - custom_uuid_idx++) { - const Uuid& curr = bta_dm_cb.bta_custom_uuid[custom_uuid_idx].custom_uuid; - if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes32) { - if (num_uuid < max_num_uuid) { - UINT32_TO_STREAM(p, curr.As32Bit()); - num_uuid++; - } else { - data_type = HCI_EIR_MORE_32BITS_UUID_TYPE; - APPL_TRACE_WARNING("BTA EIR: UUID 32-bit list is truncated"); - break; - } - } - } - - UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes32 + 1); - UINT8_TO_STREAM(p_type, data_type); - free_eir_length -= num_uuid * Uuid::kNumBytes32 + 2; - } - - /* Adding 128-bit UUID list */ - if (free_eir_length >= 2) { - p_length = p++; - p_type = p++; - num_uuid = 0; - data_type = HCI_EIR_COMPLETE_128BITS_UUID_TYPE; - - max_num_uuid = (free_eir_length - 2) / Uuid::kNumBytes128; - - for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; - custom_uuid_idx++) { - const Uuid& curr = bta_dm_cb.bta_custom_uuid[custom_uuid_idx].custom_uuid; - if (curr.GetShortestRepresentationSize() == Uuid::kNumBytes128) { - if (num_uuid < max_num_uuid) { - ARRAY16_TO_STREAM(p, curr.To128BitBE().data()); - num_uuid++; - } else { - data_type = HCI_EIR_MORE_128BITS_UUID_TYPE; - APPL_TRACE_WARNING("BTA EIR: UUID 128-bit list is truncated"); - break; - } - } - } - - UINT8_TO_STREAM(p_length, num_uuid * Uuid::kNumBytes128 + 1); - UINT8_TO_STREAM(p_type, data_type); - free_eir_length -= num_uuid * Uuid::kNumBytes128 + 2; - } -#endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE \ - )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ - - /* if Flags are provided in configuration */ - if ((p_bta_dm_eir_cfg->bta_dm_eir_flag_len > 0) && - (p_bta_dm_eir_cfg->bta_dm_eir_flags) && - (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2)) { - UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 1); - UINT8_TO_STREAM(p, HCI_EIR_FLAGS_TYPE); - memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_flags, - p_bta_dm_eir_cfg->bta_dm_eir_flag_len); - p += p_bta_dm_eir_cfg->bta_dm_eir_flag_len; - free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2; - } - - /* if Manufacturer Specific are provided in configuration */ - if ((p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0) && - (p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec) && - (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2)) { - p_length = p; - - UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1); - UINT8_TO_STREAM(p, HCI_EIR_MANUFACTURER_SPECIFIC_TYPE); - memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec, - p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len); - p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len; - free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2; - - } else { - p_length = NULL; - } - - /* if Inquiry Tx Resp Power compiled */ - if ((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && (free_eir_length >= 3)) { - UINT8_TO_STREAM(p, 2); /* Length field */ - UINT8_TO_STREAM(p, HCI_EIR_TX_POWER_LEVEL_TYPE); - UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power)); - free_eir_length -= 3; - } - - if (free_eir_length) - UINT8_TO_STREAM(p, 0); /* terminator of significant part */ - - get_btm_client_interface().eir.BTM_WriteEIR(p_buf); -} - -#if (BTA_EIR_CANNED_UUID_LIST != TRUE) -/******************************************************************************* - * - * Function bta_dm_get_cust_uuid_index - * - * Description Get index of custom uuid from list - * Note, handle equals to 0 means to find a vacant - * from list. - * - * Returns Index of array - * bta_dm_cb.bta_custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID] - * - ******************************************************************************/ -static uint8_t bta_dm_get_cust_uuid_index(uint32_t handle) { -#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) - uint8_t c_uu_idx = 0; - - while(c_uu_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID && - bta_dm_cb.bta_custom_uuid[c_uu_idx].handle != handle) { - c_uu_idx++; - } - - return c_uu_idx; -#else - return 0; -#endif -} - -/******************************************************************************* - * - * Function bta_dm_update_cust_uuid - * - * Description Update custom uuid with given value - * - * Returns None - * - ******************************************************************************/ -static void bta_dm_update_cust_uuid(uint8_t c_uu_idx, const Uuid& uuid, uint32_t handle) { -#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) - if (c_uu_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID) { - tBTA_CUSTOM_UUID& curr = bta_dm_cb.bta_custom_uuid[c_uu_idx]; - curr.custom_uuid.UpdateUuid(uuid); - curr.handle = handle; - } else { - APPL_TRACE_ERROR("%s invalid uuid index %d", __func__, c_uu_idx); - } -#endif -} - -/******************************************************************************* - * - * Function bta_dm_eir_update_cust_uuid - * - * Description This function adds or removes custom service UUID in EIR database. - * - * Returns None - * - ******************************************************************************/ -void bta_dm_eir_update_cust_uuid(const tBTA_CUSTOM_UUID& curr, bool adding) { - APPL_TRACE_DEBUG("%s", __func__); -#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) - uint8_t c_uu_idx = 0; - if (adding) { - c_uu_idx = bta_dm_get_cust_uuid_index(0); /* find a vacant from uuid list */ - bta_dm_update_cust_uuid(c_uu_idx, curr.custom_uuid, curr.handle); - } else { - c_uu_idx = bta_dm_get_cust_uuid_index(curr.handle); /* find the uuid from uuid list */ - bta_dm_update_cust_uuid(c_uu_idx, curr.custom_uuid, 0); - } - - /* Update EIR when UUIDs are changed */ - if (c_uu_idx <= BTA_EIR_SERVER_NUM_CUSTOM_UUID) { - bta_dm_set_eir(NULL); - } -#endif -} - -/******************************************************************************* - * - * Function bta_dm_eir_update_uuid - * - * Description This function adds or removes service UUID in EIR database. - * - * Returns None - * - ******************************************************************************/ -void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding) { - /* if this UUID is not advertised in EIR */ - if (!BTM_HasEirService(p_bta_dm_eir_cfg->uuid_mask, uuid16)) return; - - if (adding) { - LOG_INFO("EIR Adding UUID=0x%04X into extended inquiry response", uuid16); - - BTM_AddEirService(bta_dm_cb.eir_uuid, uuid16); - } else { - LOG_INFO("EIR Removing UUID=0x%04X from extended inquiry response", uuid16); - - get_btm_client_interface().eir.BTM_RemoveEirService(bta_dm_cb.eir_uuid, - uuid16); - } - - bta_dm_set_eir(NULL); -} -#endif - -static tBTA_DM_PEER_DEVICE* find_connected_device( - const RawAddress& bd_addr, UNUSED_ATTR tBT_TRANSPORT transport) { - for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) { - if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == bd_addr && - bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED) - return &bta_dm_cb.device_list.peer_device[i]; - } - return nullptr; -} - -/******************************************************************************* - * - * Function bta_dm_encrypt_cback - * - * Description link encryption complete callback. - * - * Returns None - * - ******************************************************************************/ -void bta_dm_encrypt_cback(const RawAddress* bd_addr, tBT_TRANSPORT transport, - UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) { - tBTA_DM_ENCRYPT_CBACK* p_callback = nullptr; - tBTA_DM_PEER_DEVICE* device = find_connected_device(*bd_addr, transport); - if (device != nullptr) { - p_callback = device->p_encrypt_cback; - device->p_encrypt_cback = nullptr; - } - - tBTA_STATUS bta_status = BTA_SUCCESS; - switch (result) { - case BTM_SUCCESS: - LOG_WARN("Encrypted link peer:%s transport:%s status:%s callback:%c", - ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), - bt_transport_text(transport).c_str(), - btm_status_text(result).c_str(), (p_callback) ? 'T' : 'F'); - break; - case BTM_WRONG_MODE: - LOG_WARN( - "Unable to encrypt link peer:%s transport:%s status:%s callback:%c", - ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), bt_transport_text(transport).c_str(), - btm_status_text(result).c_str(), (p_callback) ? 'T' : 'F'); - bta_status = BTA_WRONG_MODE; - break; - case BTM_NO_RESOURCES: - LOG_WARN( - "Unable to encrypt link peer:%s transport:%s status:%s callback:%c", - ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), bt_transport_text(transport).c_str(), - btm_status_text(result).c_str(), (p_callback) ? 'T' : 'F'); - bta_status = BTA_NO_RESOURCES; - break; - case BTM_BUSY: - LOG_WARN( - "Unable to encrypt link peer:%s transport:%s status:%s callback:%c", - ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), bt_transport_text(transport).c_str(), - btm_status_text(result).c_str(), (p_callback) ? 'T' : 'F'); - bta_status = BTA_BUSY; - break; - default: - LOG_ERROR( - "Failed to encrypt link peer:%s transport:%s status:%s callback:%c", - ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), bt_transport_text(transport).c_str(), - btm_status_text(result).c_str(), (p_callback) ? 'T' : 'F'); - bta_status = BTA_FAILURE; - break; - } - if (p_callback) { - (*p_callback)(*bd_addr, transport, bta_status); - } -} - -/**This function to encrypt the link */ -void bta_dm_set_encryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, - tBTA_DM_ENCRYPT_CBACK* p_callback, - tBTM_BLE_SEC_ACT sec_act) { - if (p_callback == nullptr) { - LOG_ERROR("bta_dm_set_encryption callback is not provided"); - return; - } - - tBTA_DM_PEER_DEVICE* device = find_connected_device(bd_addr, transport); - if (device == nullptr) { - LOG_ERROR("Unable to find active ACL connection device:%s transport:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); - return; - } - - if (device->p_encrypt_cback) { - LOG_ERROR( - "Unable to start encryption as already in progress peer:%s " - "transport:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); - (*p_callback)(bd_addr, transport, BTA_BUSY); - return; - } - - if (BTM_SetEncryption(bd_addr, transport, bta_dm_encrypt_cback, NULL, - sec_act) == BTM_CMD_STARTED) { - device->p_encrypt_cback = p_callback; - LOG_DEBUG("Started encryption peer:%s transport:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); - } else { - LOG_ERROR("Unable to start encryption process peer:%s transport:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); - } -} - -bool bta_dm_check_if_only_hd_connected(const RawAddress& peer_addr) { - APPL_TRACE_DEBUG("%s: count(%d)", __func__, bta_dm_conn_srvcs.count); - - for (uint8_t j = 0; j < bta_dm_conn_srvcs.count; j++) { - // Check if profiles other than hid are connected - if ((bta_dm_conn_srvcs.conn_srvc[j].id != BTA_ID_HD) && - bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr == peer_addr) { - APPL_TRACE_DEBUG("%s: Another profile (id=%d) is connected", __func__, - bta_dm_conn_srvcs.conn_srvc[j].id); - return false; - } - } - - return true; -} - -/******************************************************************************* - * - * Function bta_dm_observe_results_cb - * - * Description Callback for BLE Observe result - * - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, - const uint8_t* p_eir, uint16_t eir_len) { - tBTA_DM_SEARCH result; - tBTM_INQ_INFO* p_inq_info; - APPL_TRACE_DEBUG("bta_dm_observe_results_cb"); - - result.inq_res.bd_addr = p_inq->remote_bd_addr; - result.inq_res.original_bda = p_inq->original_bda; - result.inq_res.rssi = p_inq->rssi; - result.inq_res.ble_addr_type = p_inq->ble_addr_type; - result.inq_res.inq_result_type = p_inq->inq_result_type; - result.inq_res.device_type = p_inq->device_type; - result.inq_res.flag = p_inq->flag; - result.inq_res.ble_evt_type = p_inq->ble_evt_type; - result.inq_res.ble_primary_phy = p_inq->ble_primary_phy; - result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy; - result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid; - result.inq_res.ble_tx_power = p_inq->ble_tx_power; - result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int; - - /* application will parse EIR to find out remote device name */ - result.inq_res.p_eir = const_cast(p_eir); - result.inq_res.eir_len = eir_len; - - p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr); - if (p_inq_info != NULL) { - /* initialize remt_name_not_required to false so that we get the name by - * default */ - result.inq_res.remt_name_not_required = false; - } - - if (bta_dm_search_cb.p_scan_cback) - bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_RES_EVT, &result); - - if (p_inq_info) { - /* application indicates if it knows the remote name, inside the callback - copy that to the inquiry data base*/ - if (result.inq_res.remt_name_not_required) - p_inq_info->appl_knows_rem_name = true; - } -} - -/******************************************************************************* - * - * Function bta_dm_opportunistic_observe_results_cb - * - * Description Callback for BLE Observe result - * - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_opportunistic_observe_results_cb(tBTM_INQ_RESULTS* p_inq, - const uint8_t* p_eir, - uint16_t eir_len) { - tBTA_DM_SEARCH result; - tBTM_INQ_INFO* p_inq_info; - - result.inq_res.bd_addr = p_inq->remote_bd_addr; - result.inq_res.rssi = p_inq->rssi; - result.inq_res.ble_addr_type = p_inq->ble_addr_type; - result.inq_res.inq_result_type = p_inq->inq_result_type; - result.inq_res.device_type = p_inq->device_type; - result.inq_res.flag = p_inq->flag; - result.inq_res.ble_evt_type = p_inq->ble_evt_type; - result.inq_res.ble_primary_phy = p_inq->ble_primary_phy; - result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy; - result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid; - result.inq_res.ble_tx_power = p_inq->ble_tx_power; - result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int; - - /* application will parse EIR to find out remote device name */ - result.inq_res.p_eir = const_cast(p_eir); - result.inq_res.eir_len = eir_len; - - p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr); - if (p_inq_info != NULL) { - /* initialize remt_name_not_required to false so that we get the name by - * default */ - result.inq_res.remt_name_not_required = false; - } - - if (bta_dm_search_cb.p_csis_scan_cback) - bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_RES_EVT, &result); - - if (p_inq_info) { - /* application indicates if it knows the remote name, inside the callback - copy that to the inquiry data base*/ - if (result.inq_res.remt_name_not_required) - p_inq_info->appl_knows_rem_name = true; - } -} - -/******************************************************************************* - * - * Function bta_dm_observe_cmpl_cb - * - * Description Callback for BLE Observe complete - * - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_observe_cmpl_cb(void* p_result) { - tBTA_DM_SEARCH data; - - APPL_TRACE_DEBUG("bta_dm_observe_cmpl_cb"); - - data.inq_cmpl.num_resps = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp; - if (bta_dm_search_cb.p_scan_cback) { - bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); - } - if (bta_dm_search_cb.p_csis_scan_cback) { - bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); - } -} - -static void ble_io_req(const RawAddress& bd_addr, tBTM_IO_CAP* p_io_cap, - tBTM_OOB_DATA* p_oob_data, tBTM_LE_AUTH_REQ* p_auth_req, - uint8_t* p_max_key_size, tBTM_LE_KEY_TYPE* p_init_key, - tBTM_LE_KEY_TYPE* p_resp_key) { - /* Retrieve the properties from file system if possible */ - tBTE_APPL_CFG nv_config; - if (btif_dm_get_smp_config(&nv_config)) bte_appl_cfg = nv_config; - - /* *p_auth_req by default is false for devices with NoInputNoOutput; true for - * other devices. */ - - if (bte_appl_cfg.ble_auth_req) - *p_auth_req = bte_appl_cfg.ble_auth_req | - (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04); - - /* if OOB is not supported, this call-out function does not need to do - * anything - * otherwise, look for the OOB data associated with the address and set - * *p_oob_data accordingly. - * If the answer can not be obtained right away, - * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the - * answer is available. - */ - - btif_dm_set_oob_for_le_io_req(bd_addr, p_oob_data, p_auth_req); - - if (bte_appl_cfg.ble_io_cap <= 4) *p_io_cap = bte_appl_cfg.ble_io_cap; - - if (bte_appl_cfg.ble_init_key <= BTM_BLE_INITIATOR_KEY_SIZE) - *p_init_key = bte_appl_cfg.ble_init_key; - - if (bte_appl_cfg.ble_resp_key <= BTM_BLE_RESPONDER_KEY_SIZE) - *p_resp_key = bte_appl_cfg.ble_resp_key; - - if (bte_appl_cfg.ble_max_key_size > 7 && bte_appl_cfg.ble_max_key_size <= 16) - *p_max_key_size = bte_appl_cfg.ble_max_key_size; -} - -/******************************************************************************* - * - * Function bta_dm_ble_smp_cback - * - * Description Callback for BLE SMP - * - * - * Returns void - * - ******************************************************************************/ -static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, const RawAddress& bda, - tBTM_LE_EVT_DATA* p_data) { - tBTM_STATUS status = BTM_SUCCESS; - tBTA_DM_SEC sec_event; - char* p_name = NULL; - - if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED; - - memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); - switch (event) { - case BTM_LE_IO_REQ_EVT: - ble_io_req(bda, &p_data->io_req.io_cap, &p_data->io_req.oob_data, - &p_data->io_req.auth_req, &p_data->io_req.max_key_size, - &p_data->io_req.init_keys, &p_data->io_req.resp_keys); - APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req, - p_data->io_req.oob_data); - break; - - case BTM_LE_CONSENT_REQ_EVT: - sec_event.ble_req.bd_addr = bda; - p_name = BTM_SecReadDevName(bda); - if (p_name != NULL) - strlcpy((char*)sec_event.ble_req.bd_name, p_name, BD_NAME_LEN); - else - sec_event.ble_req.bd_name[0] = 0; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_CONSENT_REQ_EVT, &sec_event); - break; - - case BTM_LE_SEC_REQUEST_EVT: - sec_event.ble_req.bd_addr = bda; - p_name = BTM_SecReadDevName(bda); - if (p_name != NULL) - strlcpy((char*)sec_event.ble_req.bd_name, p_name, BD_NAME_LEN + 1); - else - sec_event.ble_req.bd_name[0] = 0; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_SEC_REQ_EVT, &sec_event); - break; - - case BTM_LE_KEY_NOTIF_EVT: - sec_event.key_notif.bd_addr = bda; - p_name = BTM_SecReadDevName(bda); - if (p_name != NULL) - strlcpy((char*)sec_event.key_notif.bd_name, p_name, BD_NAME_LEN + 1); - else - sec_event.key_notif.bd_name[0] = 0; - sec_event.key_notif.passkey = p_data->key_notif; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_NOTIF_EVT, &sec_event); - break; - - case BTM_LE_KEY_REQ_EVT: - sec_event.ble_req.bd_addr = bda; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_REQ_EVT, &sec_event); - break; - - case BTM_LE_OOB_REQ_EVT: - sec_event.ble_req.bd_addr = bda; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_OOB_REQ_EVT, &sec_event); - break; - - case BTM_LE_NC_REQ_EVT: - sec_event.key_notif.bd_addr = bda; - strlcpy((char*)sec_event.key_notif.bd_name, bta_dm_get_remname(), - (BD_NAME_LEN + 1)); - sec_event.key_notif.passkey = p_data->key_notif; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_NC_REQ_EVT, &sec_event); - break; - - case BTM_LE_SC_OOB_REQ_EVT: - sec_event.ble_req.bd_addr = bda; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_SC_OOB_REQ_EVT, &sec_event); - break; - - case BTM_LE_SC_LOC_OOB_EVT: - tBTA_DM_LOC_OOB_DATA local_oob_data; - local_oob_data.local_oob_c = p_data->local_oob_data.commitment; - local_oob_data.local_oob_r = p_data->local_oob_data.randomizer; - sec_event.local_oob_data = local_oob_data; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_SC_CR_LOC_OOB_EVT, &sec_event); - break; + /* if Flags are provided in configuration */ + if ((p_bta_dm_eir_cfg->bta_dm_eir_flag_len > 0) && + (p_bta_dm_eir_cfg->bta_dm_eir_flags) && + (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2)) { + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 1); + UINT8_TO_STREAM(p, HCI_EIR_FLAGS_TYPE); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_flags, + p_bta_dm_eir_cfg->bta_dm_eir_flag_len); + p += p_bta_dm_eir_cfg->bta_dm_eir_flag_len; + free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2; + } - case BTM_LE_KEY_EVT: - sec_event.ble_key.bd_addr = bda; - sec_event.ble_key.key_type = p_data->key.key_type; - sec_event.ble_key.p_key_value = p_data->key.p_key_value; - bta_dm_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event); - break; + /* if Manufacturer Specific are provided in configuration */ + if ((p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0) && + (p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec) && + (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2)) { + p_length = p; - case BTM_LE_COMPLT_EVT: - sec_event.auth_cmpl.bd_addr = bda; - BTM_ReadDevInfo(bda, &sec_event.auth_cmpl.dev_type, - &sec_event.auth_cmpl.addr_type); - p_name = BTM_SecReadDevName(bda); - if (p_name != NULL) - strlcpy((char*)sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN + 1)); - else - sec_event.auth_cmpl.bd_name[0] = 0; - - if (p_data->complt.reason != HCI_SUCCESS) { - // TODO This is not a proper use of this type - sec_event.auth_cmpl.fail_reason = - static_cast(BTA_DM_AUTH_CONVERT_SMP_CODE( - (static_cast(p_data->complt.reason)))); - - if (btm_sec_is_a_bonded_dev(bda) && - p_data->complt.reason == SMP_CONN_TOUT && - !p_data->complt.smp_over_br) { - // Bonded device failed to encrypt - to test this remove battery from - // HID device right after connection, but before encryption is - // established - LOG(INFO) << __func__ - << ": bonded device disconnected when encrypting - no " - "reason to unbond"; - } else { - /* delete this device entry from Sec Dev DB */ - bta_dm_remove_sec_dev_entry(bda); - } + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1); + UINT8_TO_STREAM(p, HCI_EIR_MANUFACTURER_SPECIFIC_TYPE); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec, + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len); + p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len; + free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2; - } else { - sec_event.auth_cmpl.success = true; - if (!p_data->complt.smp_over_br) - GATT_ConfigServiceChangeCCC(bda, true, BT_TRANSPORT_LE); - } + } else { + p_length = NULL; + } - if (bta_dm_cb.p_sec_cback) { - // bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); - bta_dm_cb.p_sec_cback(BTA_DM_BLE_AUTH_CMPL_EVT, &sec_event); - } - break; + /* if Inquiry Tx Resp Power compiled */ + if ((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && (free_eir_length >= 3)) { + UINT8_TO_STREAM(p, 2); /* Length field */ + UINT8_TO_STREAM(p, HCI_EIR_TX_POWER_LEVEL_TYPE); + UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power)); + free_eir_length -= 3; + } - case BTM_LE_ADDR_ASSOC_EVT: - sec_event.proc_id_addr.pairing_bda = bda; - sec_event.proc_id_addr.id_addr = p_data->id_addr; - bta_dm_cb.p_sec_cback(BTA_DM_LE_ADDR_ASSOC_EVT, &sec_event); - break; + if (free_eir_length) + UINT8_TO_STREAM(p, 0); /* terminator of significant part */ - default: - status = BTM_NOT_AUTHORIZED; - break; - } - return status; + get_btm_client_interface().eir.BTM_WriteEIR(p_buf); } +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) /******************************************************************************* * - * Function bta_dm_ble_id_key_cback - * - * Description Callback for BLE local ID keys + * Function bta_dm_get_cust_uuid_index * + * Description Get index of custom uuid from list + * Note, handle equals to 0 means to find a vacant + * from list. * - * Returns void + * Returns Index of array + * bta_dm_cb.bta_custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID] * ******************************************************************************/ -static void bta_dm_ble_id_key_cback(uint8_t key_type, - tBTM_BLE_LOCAL_KEYS* p_key) { - switch (key_type) { - case BTM_BLE_KEY_TYPE_ID: - case BTM_BLE_KEY_TYPE_ER: - if (bta_dm_cb.p_sec_cback) { - tBTA_DM_SEC dm_key = { - .ble_id_keys = {}, - }; - memcpy(&dm_key.ble_id_keys, p_key, sizeof(tBTM_BLE_LOCAL_KEYS)); - - tBTA_DM_SEC_EVT evt = (key_type == BTM_BLE_KEY_TYPE_ID) - ? BTA_DM_BLE_LOCAL_IR_EVT - : BTA_DM_BLE_LOCAL_ER_EVT; - bta_dm_cb.p_sec_cback(evt, &dm_key); - } - break; +static uint8_t bta_dm_get_cust_uuid_index(uint32_t handle) { +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + uint8_t c_uu_idx = 0; - default: - APPL_TRACE_DEBUG("Unknown key type %d", key_type); - break; + while(c_uu_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID && + bta_dm_cb.bta_custom_uuid[c_uu_idx].handle != handle) { + c_uu_idx++; } - return; + + return c_uu_idx; +#else + return 0; +#endif } /******************************************************************************* * - * Function bta_dm_add_blekey + * Function bta_dm_update_cust_uuid * - * Description This function adds an BLE Key to an security database entry. - * This function shall only be called AFTER BTA_DmAddBleDevice - * has been called. - * It is normally called during host startup to restore all - * required information stored in the NVRAM. + * Description Update custom uuid with given value * - * Parameters: + * Returns None * ******************************************************************************/ -void bta_dm_add_blekey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE blekey, - tBTM_LE_KEY_TYPE key_type) { - BTM_SecAddBleKey(bd_addr, (tBTM_LE_KEY_VALUE*)&blekey, key_type); +static void bta_dm_update_cust_uuid(uint8_t c_uu_idx, const Uuid& uuid, uint32_t handle) { +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + if (c_uu_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID) { + tBTA_CUSTOM_UUID& curr = bta_dm_cb.bta_custom_uuid[c_uu_idx]; + curr.custom_uuid.UpdateUuid(uuid); + curr.handle = handle; + } else { + LOG_ERROR("%s invalid uuid index %d", __func__, c_uu_idx); + } +#endif } /******************************************************************************* * - * Function bta_dm_add_ble_device + * Function bta_dm_eir_update_cust_uuid * - * Description This function adds an BLE device to an security database - * entry. - * It is normally called during host startup to restore all - * required information stored in the NVRAM. + * Description This function adds or removes custom service UUID in EIR database. * - * Parameters: + * Returns None * ******************************************************************************/ -void bta_dm_add_ble_device(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_DEVICE_TYPE dev_type) { - BTM_SecAddBleDevice(bd_addr, dev_type, addr_type); +void bta_dm_eir_update_cust_uuid(const tBTA_CUSTOM_UUID& curr, bool adding) { + LOG_VERBOSE("%s", __func__); +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + uint8_t c_uu_idx = 0; + if (adding) { + c_uu_idx = bta_dm_get_cust_uuid_index(0); /* find a vacant from uuid list */ + bta_dm_update_cust_uuid(c_uu_idx, curr.custom_uuid, curr.handle); + } else { + c_uu_idx = bta_dm_get_cust_uuid_index(curr.handle); /* find the uuid from uuid list */ + bta_dm_update_cust_uuid(c_uu_idx, curr.custom_uuid, 0); + } + + /* Update EIR when UUIDs are changed */ + if (c_uu_idx <= BTA_EIR_SERVER_NUM_CUSTOM_UUID) { + bta_dm_set_eir(NULL); + } +#endif } /******************************************************************************* * - * Function bta_dm_add_ble_device + * Function bta_dm_eir_update_uuid * - * Description This function adds an BLE device to an security database - * entry. - * It is normally called during host startup to restore all - * required information stored in the NVRAM. + * Description This function adds or removes service UUID in EIR database. * - * Parameters: + * Returns None * ******************************************************************************/ -void bta_dm_ble_passkey_reply(const RawAddress& bd_addr, bool accept, - uint32_t passkey) { - BTM_BlePasskeyReply(bd_addr, accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED, - passkey); +void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding) { + /* if this UUID is not advertised in EIR */ + if (!BTM_HasEirService(p_bta_dm_eir_cfg->uuid_mask, uuid16)) return; + + if (adding) { + LOG_INFO("EIR Adding UUID=0x%04X into extended inquiry response", uuid16); + + get_btm_client_interface().eir.BTM_AddEirService(bta_dm_cb.eir_uuid, + uuid16); + } else { + LOG_INFO("EIR Removing UUID=0x%04X from extended inquiry response", uuid16); + + get_btm_client_interface().eir.BTM_RemoveEirService(bta_dm_cb.eir_uuid, + uuid16); + } + + bta_dm_set_eir(NULL); +} +#endif // BTA_EIR_CANNED_UUID_LIST + +tBTA_DM_PEER_DEVICE* find_connected_device( + const RawAddress& bd_addr, UNUSED_ATTR tBT_TRANSPORT transport) { + for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) { + if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr == bd_addr && + bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED) + return &bta_dm_cb.device_list.peer_device[i]; + } + return nullptr; } -/** This is response to SM numeric comparison request submitted to application. - */ -void bta_dm_ble_confirm_reply(const RawAddress& bd_addr, bool accept) { - BTM_BleConfirmReply(bd_addr, accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED); +bool bta_dm_check_if_only_hd_connected(const RawAddress& peer_addr) { + LOG_VERBOSE("%s: count(%d)", __func__, bta_dm_conn_srvcs.count); + + for (uint8_t j = 0; j < bta_dm_conn_srvcs.count; j++) { + // Check if profiles other than hid are connected + if ((bta_dm_conn_srvcs.conn_srvc[j].id != BTA_ID_HD) && + bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr == peer_addr) { + LOG_VERBOSE("%s: Another profile (id=%d) is connected", __func__, + bta_dm_conn_srvcs.conn_srvc[j].id); + return false; + } + } + + return true; } /** This function set the preferred connection parameters */ @@ -4008,8 +1439,9 @@ void bta_dm_ble_set_conn_params(const RawAddress& bd_addr, L2CA_AdjustConnectionIntervals(&conn_int_min, &conn_int_max, BTM_BLE_CONN_INT_MIN); - BTM_BleSetPrefConnParams(bd_addr, conn_int_min, conn_int_max, - peripheral_latency, supervision_tout); + get_btm_client_interface().ble.BTM_BleSetPrefConnParams( + bd_addr, conn_int_min, conn_int_max, peripheral_latency, + supervision_tout); } /** This function update LE connection parameters */ @@ -4021,75 +1453,8 @@ void bta_dm_ble_update_conn_params(const RawAddress& bd_addr, uint16_t min_int, if (!L2CA_UpdateBleConnParams(bd_addr, min_int, max_int, latency, timeout, min_ce_len, max_ce_len)) { - APPL_TRACE_ERROR("Update connection parameters failed!"); - } -} - -/** This function set the local device LE privacy settings. */ -void bta_dm_ble_config_local_privacy(bool privacy_enable) { - BTM_BleConfigPrivacy(privacy_enable); -} - -static void bta_dm_start_scan(uint8_t duration_sec, - bool low_latency_scan = false) { - tBTM_STATUS status = - BTM_BleObserve(true, duration_sec, bta_dm_observe_results_cb, - bta_dm_observe_cmpl_cb, low_latency_scan); - - if (status != BTM_CMD_STARTED) { - tBTA_DM_SEARCH data = { - .inq_cmpl = - { - .num_resps = 0, - }, - }; - APPL_TRACE_WARNING(" %s BTM_BleObserve failed. status %d", __func__, - status); - if (bta_dm_search_cb.p_scan_cback) { - bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); - } - if (bta_dm_search_cb.p_csis_scan_cback) { - bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); - } - } -} - -void bta_dm_ble_observe(bool start, uint8_t duration, - tBTA_DM_SEARCH_CBACK* p_cback) { - if (!start) { - bta_dm_search_cb.p_scan_cback = NULL; - BTM_BleObserve(false, 0, NULL, NULL); - return; - } - - /*Save the callback to be called when a scan results are available */ - bta_dm_search_cb.p_scan_cback = p_cback; - bta_dm_start_scan(duration); -} - -void bta_dm_ble_scan(bool start, uint8_t duration_sec, - bool low_latency_scan = false) { - /* Start or stop only if there is no active main scanner */ - if (bta_dm_search_cb.p_scan_cback != NULL) return; - - if (!start) { - BTM_BleObserve(false, 0, NULL, NULL); - return; + LOG_ERROR("Update connection parameters failed!"); } - - bta_dm_start_scan(duration_sec, low_latency_scan); -} - -void bta_dm_ble_csis_observe(bool observe, tBTA_DM_SEARCH_CBACK* p_cback) { - if (!observe) { - bta_dm_search_cb.p_csis_scan_cback = NULL; - BTM_BleOpportunisticObserve(false, NULL); - return; - } - - /* Save the callback to be called when a scan results are available */ - bta_dm_search_cb.p_csis_scan_cback = p_cback; - BTM_BleOpportunisticObserve(true, bta_dm_opportunistic_observe_results_cb); } /** This function set the maximum transmission packet size */ @@ -4131,165 +1496,12 @@ static void bta_ble_energy_info_cmpl(tBTM_BLE_TX_TIME_MS tx_time, void bta_dm_ble_get_energy_info( tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback) { bta_dm_cb.p_energy_info_cback = p_energy_info_cback; - tBTM_STATUS btm_status = BTM_BleGetEnergyInfo(bta_ble_energy_info_cmpl); + tBTM_STATUS btm_status = get_btm_client_interface().ble.BTM_BleGetEnergyInfo( + bta_ble_energy_info_cmpl); if (btm_status != BTM_CMD_STARTED) bta_ble_energy_info_cmpl(0, 0, 0, 0, HCI_ERR_UNSPECIFIED); } -#ifndef BTA_DM_GATT_CLOSE_DELAY_TOUT -#define BTA_DM_GATT_CLOSE_DELAY_TOUT 1000 -#endif - -/******************************************************************************* - * - * Function bta_dm_gattc_register - * - * Description Register with GATTC in DM if BLE is needed. - * - * - * Returns void - * - ******************************************************************************/ -static void bta_dm_gattc_register(void) { - if (bta_dm_search_cb.client_if == BTA_GATTS_INVALID_IF) { - BTA_GATTC_AppRegister(bta_dm_gattc_callback, - base::Bind([](uint8_t client_id, uint8_t status) { - if (status == GATT_SUCCESS) - bta_dm_search_cb.client_if = client_id; - else - bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF; - - }), false); - } -} - -/******************************************************************************* - * - * Function bta_dm_gatt_disc_complete - * - * Description This function process the GATT service search complete. - * - * Parameters: - * - ******************************************************************************/ -static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status) { - APPL_TRACE_DEBUG("%s conn_id = %d", __func__, conn_id); - - tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); - - /* no more services to be discovered */ - p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; - p_msg->disc_result.result.disc_res.result = - (status == GATT_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE; - APPL_TRACE_DEBUG("%s service found: 0x%08x", __func__, - bta_dm_search_cb.services_found); - p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; - p_msg->disc_result.result.disc_res.num_uuids = 0; - p_msg->disc_result.result.disc_res.p_uuid_list = NULL; - p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; - strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, - bta_dm_get_remname(), BD_NAME_LEN + 1); - - p_msg->disc_result.result.disc_res.device_type |= BT_DEVICE_TYPE_BLE; - - bta_sys_sendmsg(p_msg); - - if (conn_id != GATT_INVALID_CONN_ID) { - bta_dm_search_cb.pending_close_bda = bta_dm_search_cb.peer_bdaddr; - // Gatt will be close immediately if bluetooth.gatt.delay_close.enabled is - // set to false. If property is true / unset there will be a delay - if (bta_dm_search_cb.gatt_close_timer != nullptr) { - /* start a GATT channel close delay timer */ - bta_sys_start_timer(bta_dm_search_cb.gatt_close_timer, - BTA_DM_GATT_CLOSE_DELAY_TOUT, - BTA_DM_DISC_CLOSE_TOUT_EVT, 0); - } else { - p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); - p_msg->hdr.event = BTA_DM_DISC_CLOSE_TOUT_EVT; - p_msg->hdr.layer_specific = 0; - bta_sys_sendmsg(p_msg); - } - } else { - if (bluetooth::common::init_flags:: - bta_dm_clear_conn_id_on_client_close_is_enabled()) { - bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; - } - } -} - -/******************************************************************************* - * - * Function bta_dm_close_gatt_conn - * - * Description This function close the GATT connection after delay - *timeout. - * - * Parameters: - * - ******************************************************************************/ -void bta_dm_close_gatt_conn(UNUSED_ATTR tBTA_DM_MSG* p_data) { - if (bta_dm_search_cb.conn_id != GATT_INVALID_CONN_ID) - BTA_GATTC_Close(bta_dm_search_cb.conn_id); - - bta_dm_search_cb.pending_close_bda = RawAddress::kEmpty; - bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; -} -/******************************************************************************* - * - * Function btm_dm_start_gatt_discovery - * - * Description This is GATT initiate the service search by open a GATT - * connection first. - * - * Parameters: - * - ******************************************************************************/ -void btm_dm_start_gatt_discovery(const RawAddress& bd_addr) { - bta_dm_search_cb.gatt_disc_active = true; - - /* connection is already open */ - if (bta_dm_search_cb.pending_close_bda == bd_addr && - bta_dm_search_cb.conn_id != GATT_INVALID_CONN_ID) { - bta_dm_search_cb.pending_close_bda = RawAddress::kEmpty; - alarm_cancel(bta_dm_search_cb.gatt_close_timer); - BTA_GATTC_ServiceSearchRequest(bta_dm_search_cb.conn_id, nullptr); - } else { - if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) { - BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, - BTM_BLE_DIRECT_CONNECTION, true); - } else { - BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, - BTM_BLE_DIRECT_CONNECTION, false); - } - } -} - -/******************************************************************************* - * - * Function bta_dm_proc_open_evt - * - * Description process BTA_GATTC_OPEN_EVT in DM. - * - * Parameters: - * - ******************************************************************************/ -void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) { - VLOG(1) << "DM Search state= " << bta_dm_search_get_state() - << " search_cb.peer_dbaddr:" << bta_dm_search_cb.peer_bdaddr - << " connected_bda=" << p_data->remote_bda.address; - - APPL_TRACE_DEBUG("BTA_GATTC_OPEN_EVT conn_id = %d client_if=%d status = %d", - p_data->conn_id, p_data->client_if, p_data->status); - - bta_dm_search_cb.conn_id = p_data->conn_id; - - if (p_data->status == GATT_SUCCESS) { - BTA_GATTC_ServiceSearchRequest(p_data->conn_id, nullptr); - } else { - bta_dm_gatt_disc_complete(GATT_INVALID_CONN_ID, p_data->status); - } -} - /******************************************************************************* * * Function bta_dm_clear_event_filter @@ -4351,7 +1563,7 @@ void bta_dm_disconnect_all_acls(void) { ******************************************************************************/ void bta_dm_le_rand(LeRandCallback cb) { VLOG(1) << "bta_dm_le_rand in bta_dm_act"; - bluetooth::shim::BTM_LeRand(cb); + bluetooth::shim::BTM_LeRand(std::move(cb)); } /******************************************************************************* @@ -4450,70 +1662,6 @@ void bta_dm_ble_reset_id(void) { bluetooth::shim::BTM_BleResetId(); } -/******************************************************************************* - * - * Function bta_dm_gattc_callback - * - * Description This is GATT client callback function used in DM. - * - * Parameters: - * - ******************************************************************************/ -static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) { - APPL_TRACE_DEBUG("bta_dm_gattc_callback event = %d", event); - - switch (event) { - case BTA_GATTC_OPEN_EVT: - bta_dm_proc_open_evt(&p_data->open); - break; - - case BTA_GATTC_SEARCH_RES_EVT: - break; - - case BTA_GATTC_SEARCH_CMPL_EVT: - switch (bta_dm_search_get_state()) { - case BTA_DM_SEARCH_IDLE: - break; - case BTA_DM_SEARCH_ACTIVE: - case BTA_DM_SEARCH_CANCELLING: - case BTA_DM_DISCOVER_ACTIVE: - bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id, - p_data->search_cmpl.status); - break; - } - break; - - case BTA_GATTC_CLOSE_EVT: - LOG_INFO("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason); - - if (p_data->close.remote_bda == bta_dm_search_cb.peer_bdaddr) { - if (bluetooth::common::init_flags:: - bta_dm_clear_conn_id_on_client_close_is_enabled()) { - bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; - } - } - - switch (bta_dm_search_get_state()) { - case BTA_DM_SEARCH_IDLE: - case BTA_DM_SEARCH_ACTIVE: - break; - - case BTA_DM_SEARCH_CANCELLING: - case BTA_DM_DISCOVER_ACTIVE: - /* in case of disconnect before search is completed */ - if (p_data->close.remote_bda == bta_dm_search_cb.peer_bdaddr) { - bta_dm_gatt_disc_complete((uint16_t)GATT_INVALID_CONN_ID, - (tGATT_STATUS)GATT_ERROR); - } - } - break; - - default: - break; - } -} - -#if (BLE_VND_INCLUDED == TRUE) /******************************************************************************* * * Function bta_dm_ctrl_features_rd_cmpl_cback @@ -4524,16 +1672,14 @@ static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) { * ******************************************************************************/ static void bta_dm_ctrl_features_rd_cmpl_cback(tHCI_STATUS result) { - APPL_TRACE_DEBUG("%s status = %d ", __func__, result); + LOG_VERBOSE("%s status = %d ", __func__, result); if (result == HCI_SUCCESS) { - if (bta_dm_cb.p_sec_cback) - bta_dm_cb.p_sec_cback(BTA_DM_LE_FEATURES_READ, NULL); + if (bta_dm_acl_cb.p_acl_cback) + bta_dm_acl_cb.p_acl_cback(BTA_DM_LE_FEATURES_READ, NULL); } else { - APPL_TRACE_ERROR("%s Ctrl BLE feature read failed: status :%d", __func__, - result); + LOG_ERROR("%s Ctrl BLE feature read failed: status :%d", __func__, result); } } -#endif /* BLE_VND_INCLUDED */ /******************************************************************************* * @@ -4560,14 +1706,9 @@ tBTA_DM_PEER_DEVICE* allocate_device_for(const RawAddress& bd_addr, return ::allocate_device_for(bd_addr, transport); } -void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p) { - ::bta_dm_remname_cback(p); -} - -tBT_TRANSPORT bta_dm_determine_discovery_transport(const RawAddress& bd_addr) { - return ::bta_dm_determine_discovery_transport(bd_addr); -} +void bta_dm_init_cb() { ::bta_dm_init_cb(); } +void bta_dm_deinit_cb() { ::bta_dm_deinit_cb(); } } // namespace testing } // namespace legacy -} // namespace bluetooth +} // namespace bluetooth \ No newline at end of file diff --git a/system/bta/dm/bta_dm_act.h b/system/bta/dm/bta_dm_act.h new file mode 100644 index 0000000000000000000000000000000000000000..9de44b29005795d028203e9314a7274ece719eff --- /dev/null +++ b/system/bta/dm/bta_dm_act.h @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "bta/dm/bta_dm_int.h" +#include "osi/include/osi.h" +#include "types/bt_transport.h" +#include "types/raw_address.h" + +void bta_dm_process_remove_device_no_callback(const RawAddress& bd_addr); + +tBTA_DM_PEER_DEVICE* find_connected_device(const RawAddress& bd_addr, + UNUSED_ATTR tBT_TRANSPORT transport); diff --git a/system/bta/dm/bta_dm_api.cc b/system/bta/dm/bta_dm_api.cc index 72a99d47faeaba442eabe92c5cec7ecdc361d3c6..44367bb9aef432816efa3fe325c987bc20f71319 100644 --- a/system/bta/dm/bta_dm_api.cc +++ b/system/bta/dm/bta_dm_api.cc @@ -26,18 +26,21 @@ #include -#include "bt_target.h" // Must be first to define build configuration +#include "android_bluetooth_flags.h" +#include "bta/dm/bta_dm_disc.h" #include "bta/dm/bta_dm_int.h" -#include "osi/include/allocator.h" +#include "bta/dm/bta_dm_sec_int.h" #include "osi/include/compat.h" -#include "stack/btm/btm_sec.h" -#include "stack/include/bt_octets.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_api.h" #include "stack/include/btm_client_interface.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" +#include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + using bluetooth::Uuid; /***************************************************************************** @@ -55,12 +58,18 @@ void BTA_dm_init() { BTM_SetConsolidationCallback(bta_dm_consolidate); } +/** Enables bluetooth device under test mode */ +void BTA_EnableTestMode(void) { + do_in_main_thread(FROM_HERE, + base::BindOnce(base::IgnoreResult(BTM_EnableTestMode))); +} + /** This function sets the Bluetooth name of local device */ void BTA_DmSetDeviceName(const char* p_name) { std::vector name(BD_NAME_LEN + 1); strlcpy((char*)name.data(), p_name, BD_NAME_LEN + 1); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_set_dev_name, name)); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_set_dev_name, name)); } /******************************************************************************* @@ -71,18 +80,11 @@ void BTA_DmSetDeviceName(const char* p_name) { * performs an inquiry and gets the remote name for devices. * Service discovery is done if services is non zero * - * * Returns void * ******************************************************************************/ void BTA_DmSearch(tBTA_DM_SEARCH_CBACK* p_cback) { - tBTA_DM_API_SEARCH* p_msg = - (tBTA_DM_API_SEARCH*)osi_calloc(sizeof(tBTA_DM_API_SEARCH)); - - p_msg->hdr.event = BTA_DM_API_SEARCH_EVT; - p_msg->p_cback = p_cback; - - bta_sys_sendmsg(p_msg); + bta_dm_disc_start_device_discovery(p_cback); } /******************************************************************************* @@ -91,18 +93,10 @@ void BTA_DmSearch(tBTA_DM_SEARCH_CBACK* p_cback) { * * Description This function cancels a search initiated by BTA_DmSearch * - * * Returns void * ******************************************************************************/ -void BTA_DmSearchCancel(void) { - tBTA_DM_API_DISCOVERY_CANCEL* p_msg = - (tBTA_DM_API_DISCOVERY_CANCEL*)osi_calloc( - sizeof(tBTA_DM_API_DISCOVERY_CANCEL)); - - p_msg->hdr.event = BTA_DM_API_SEARCH_CANCEL_EVT; - bta_sys_sendmsg(p_msg); -} +void BTA_DmSearchCancel(void) { bta_dm_disc_stop_device_discovery(); } /******************************************************************************* * @@ -117,128 +111,7 @@ void BTA_DmSearchCancel(void) { ******************************************************************************/ void BTA_DmDiscover(const RawAddress& bd_addr, tBTA_DM_SEARCH_CBACK* p_cback, tBT_TRANSPORT transport) { - tBTA_DM_API_DISCOVER* p_msg = - (tBTA_DM_API_DISCOVER*)osi_calloc(sizeof(tBTA_DM_API_DISCOVER)); - - p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT; - p_msg->bd_addr = bd_addr; - p_msg->transport = transport; - p_msg->p_cback = p_cback; - - bta_sys_sendmsg(p_msg); -} - -/** This function initiates a bonding procedure with a peer device */ -void BTA_DmBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) { - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_bond, bd_addr, addr_type, - transport, device_type)); -} - -/** This function cancels the bonding procedure with a peer device - */ -void BTA_DmBondCancel(const RawAddress& bd_addr) { - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_bond_cancel, bd_addr)); -} - -/******************************************************************************* - * - * Function BTA_DmPinReply - * - * Description This function provides a pincode for a remote device when - * one is requested by DM through BTA_DM_PIN_REQ_EVT - * - * - * Returns void - * - ******************************************************************************/ -void BTA_DmPinReply(const RawAddress& bd_addr, bool accept, uint8_t pin_len, - uint8_t* p_pin) { - std::unique_ptr msg = - std::make_unique(); - - msg->bd_addr = bd_addr; - msg->accept = accept; - if (accept) { - msg->pin_len = pin_len; - memcpy(msg->p_pin, p_pin, pin_len); - } - - do_in_main_thread(FROM_HERE, - base::Bind(bta_dm_pin_reply, base::Passed(&msg))); -} - -/******************************************************************************* - * - * Function BTA_DmLocalOob - * - * Description This function retrieves the OOB data from local controller. - * The result is reported by: - * - bta_dm_co_loc_oob_ext() if device supports secure - * connections (SC) - * - bta_dm_co_loc_oob() if device doesn't support SC - * - * Returns void - * - ******************************************************************************/ -void BTA_DmLocalOob(void) { - do_in_main_thread(FROM_HERE, base::Bind(BTM_ReadLocalOobData)); -} - -/******************************************************************************* - * - * Function BTA_DmConfirm - * - * Description This function accepts or rejects the numerical value of the - * Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT - * - * Returns void - * - ******************************************************************************/ -void BTA_DmConfirm(const RawAddress& bd_addr, bool accept) { - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_confirm, bd_addr, accept)); -} - -/******************************************************************************* - * - * Function BTA_DmAddDevice - * - * Description This function adds a device to the security database list of - * peer device - * - * - * Returns void - * - ******************************************************************************/ -void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, - const LinkKey& link_key, uint8_t key_type, - uint8_t pin_length) { - std::unique_ptr msg = - std::make_unique(); - - msg->bd_addr = bd_addr; - msg->link_key_known = true; - msg->key_type = key_type; - msg->link_key = link_key; - - /* Load device class if specified */ - if (dev_class) { - msg->dc_known = true; - memcpy(msg->dc, dev_class, DEV_CLASS_LEN); - } - - memset(msg->bd_name, 0, BD_NAME_LEN + 1); - msg->pin_length = pin_length; - - do_in_main_thread(FROM_HERE, - base::Bind(bta_dm_add_device, base::Passed(&msg))); -} - -/** This function removes a device fromthe security database list of peer - * device. It manages unpairing even while connected */ -tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr) { - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_remove_device, bd_addr)); - return BTA_SUCCESS; + bta_dm_disc_start_service_discovery(p_cback, bd_addr, transport); } /******************************************************************************* @@ -317,8 +190,8 @@ tBTA_STATUS BTA_DmSetLocalDiRecord(tSDP_DI_RECORD* p_device_info, tBTA_STATUS status = BTA_FAILURE; if (bta_dm_di_cb.di_num < BTA_DI_NUM_MAX) { - if (SDP_SetLocalDiRecord((tSDP_DI_RECORD*)p_device_info, p_handle) == - SDP_SUCCESS) { + if (get_legacy_stack_sdp_api()->device_id.SDP_SetLocalDiRecord( + (tSDP_DI_RECORD*)p_device_info, p_handle) == SDP_SUCCESS) { if (!p_device_info->primary_record) { bta_dm_di_cb.di_handle[bta_dm_di_cb.di_num] = *p_handle; bta_dm_di_cb.di_num++; @@ -332,104 +205,6 @@ tBTA_STATUS BTA_DmSetLocalDiRecord(tSDP_DI_RECORD* p_device_info, return status; } -/******************************************************************************* - * - * Function BTA_DmAddBleKey - * - * Description Add/modify LE device information. This function will be - * normally called during host startup to restore all required - * information stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * p_le_key - LE key values. - * key_type - LE SMP key type. - * - * Returns BTA_SUCCESS if successful - * BTA_FAIL if operation failed. - * - ******************************************************************************/ -void BTA_DmAddBleKey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type) { - do_in_main_thread( - FROM_HERE, base::Bind(bta_dm_add_blekey, bd_addr, *p_le_key, key_type)); -} - -/******************************************************************************* - * - * Function BTA_DmAddBleDevice - * - * Description Add a BLE device. This function will be normally called - * during host startup to restore all required information - * for a LE device stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * dev_type - Remote device's device type. - * addr_type - LE device address type. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmAddBleDevice(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_DEVICE_TYPE dev_type) { - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_add_ble_device, bd_addr, - addr_type, dev_type)); -} - -/******************************************************************************* - * - * Function BTA_DmBlePasskeyReply - * - * Description Send BLE SMP passkey reply. - * - * Parameters: bd_addr - BD address of the peer - * accept - passkey entry sucessful or declined. - * passkey - passkey value, must be a 6 digit number, - * can be lead by 0. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmBlePasskeyReply(const RawAddress& bd_addr, bool accept, - uint32_t passkey) { - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_ble_passkey_reply, bd_addr, - accept, accept ? passkey : 0)); -} - -/******************************************************************************* - * - * Function BTA_DmBleConfirmReply - * - * Description Send BLE SMP SC user confirmation reply. - * - * Parameters: bd_addr - BD address of the peer - * accept - numbers to compare are the same or - * different. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmBleConfirmReply(const RawAddress& bd_addr, bool accept) { - do_in_main_thread(FROM_HERE, - base::Bind(bta_dm_ble_confirm_reply, bd_addr, accept)); -} - -/******************************************************************************* - * - * Function BTA_DmBleSecurityGrant - * - * Description Grant security request access. - * - * Parameters: bd_addr - BD address of the peer - * res - security grant status. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmBleSecurityGrant(const RawAddress& bd_addr, - tBTA_DM_BLE_SEC_GRANT res) { - do_in_main_thread(FROM_HERE, base::Bind(BTM_SecurityGrant, bd_addr, res)); -} - /******************************************************************************* * * Function BTA_DmSetBlePrefConnParams @@ -455,8 +230,8 @@ void BTA_DmSetBlePrefConnParams(const RawAddress& bd_addr, uint16_t supervision_tout) { do_in_main_thread( FROM_HERE, - base::Bind(bta_dm_ble_set_conn_params, bd_addr, min_conn_int, - max_conn_int, peripheral_latency, supervision_tout)); + base::BindOnce(bta_dm_ble_set_conn_params, bd_addr, min_conn_int, + max_conn_int, peripheral_latency, supervision_tout)); } /******************************************************************************* @@ -482,8 +257,9 @@ void BTA_DmBleUpdateConnectionParams(const RawAddress& bd_addr, uint16_t latency, uint16_t timeout, uint16_t min_ce_len, uint16_t max_ce_len) { do_in_main_thread( - FROM_HERE, base::Bind(bta_dm_ble_update_conn_params, bd_addr, min_int, - max_int, latency, timeout, min_ce_len, max_ce_len)); + FROM_HERE, + base::BindOnce(bta_dm_ble_update_conn_params, bd_addr, min_int, max_int, + latency, timeout, min_ce_len, max_ce_len)); } /******************************************************************************* @@ -498,8 +274,12 @@ void BTA_DmBleUpdateConnectionParams(const RawAddress& bd_addr, * ******************************************************************************/ void BTA_DmBleConfigLocalPrivacy(bool privacy_enable) { - do_in_main_thread( - FROM_HERE, base::Bind(bta_dm_ble_config_local_privacy, privacy_enable)); + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_ble_config_local_privacy(privacy_enable); + } else { + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_ble_config_local_privacy, + privacy_enable)); + } } /******************************************************************************* @@ -515,43 +295,13 @@ void BTA_DmBleConfigLocalPrivacy(bool privacy_enable) { ******************************************************************************/ void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK* p_cmpl_cback) { do_in_main_thread(FROM_HERE, - base::Bind(bta_dm_ble_get_energy_info, p_cmpl_cback)); + base::BindOnce(bta_dm_ble_get_energy_info, p_cmpl_cback)); } /** This function is to set maximum LE data packet size */ void BTA_DmBleRequestMaxTxDataLength(const RawAddress& remote_device) { do_in_main_thread(FROM_HERE, - base::Bind(bta_dm_ble_set_data_length, remote_device)); -} - -/******************************************************************************* - * - * Function BTA_DmSetEncryption - * - * Description This function is called to ensure that connection is - * encrypted. Should be called only on an open connection. - * Typically only needed for connections that first want to - * bring up unencrypted links, then later encrypt them. - * - * Parameters: bd_addr - Address of the peer device - * transport - transport of the link to be encruypted - * p_callback - Pointer to callback function to indicat the - * link encryption status - * sec_act - This is the security action to indicate - * what kind of BLE security level is required - * for the BLE link if BLE is supported. - * Note: This parameter is ignored for the - * BR/EDR or if BLE is not supported. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmSetEncryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, - tBTA_DM_ENCRYPT_CBACK* p_callback, - tBTM_BLE_SEC_ACT sec_act) { - APPL_TRACE_API("%s", __func__); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_set_encryption, bd_addr, - transport, p_callback, sec_act)); + base::BindOnce(bta_dm_ble_set_data_length, remote_device)); } /******************************************************************************* @@ -569,8 +319,8 @@ void BTA_DmSetEncryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, ******************************************************************************/ void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev, tBT_TRANSPORT transport) { - do_in_main_thread( - FROM_HERE, base::Bind(bta_dm_close_acl, bd_addr, remove_dev, transport)); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_close_acl, bd_addr, + remove_dev, transport)); } /******************************************************************************* @@ -590,9 +340,9 @@ void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev, ******************************************************************************/ void BTA_DmBleObserve(bool start, uint8_t duration, tBTA_DM_SEARCH_CBACK* p_results_cb) { - APPL_TRACE_API("%s:start = %d ", __func__, start); - do_in_main_thread( - FROM_HERE, base::Bind(bta_dm_ble_observe, start, duration, p_results_cb)); + LOG_VERBOSE("%s:start = %d ", __func__, start); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_ble_observe, start, + duration, p_results_cb)); } /******************************************************************************* @@ -612,9 +362,9 @@ void BTA_DmBleObserve(bool start, uint8_t duration, * ******************************************************************************/ void BTA_DmBleScan(bool start, uint8_t duration_sec, bool low_latency_scan) { - APPL_TRACE_API("%s:start = %d ", __func__, start); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_ble_scan, start, duration_sec, - low_latency_scan)); + LOG_VERBOSE("%s:start = %d ", __func__, start); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_ble_scan, start, + duration_sec, low_latency_scan)); } /******************************************************************************* @@ -631,9 +381,9 @@ void BTA_DmBleScan(bool start, uint8_t duration_sec, bool low_latency_scan) { * ******************************************************************************/ void BTA_DmBleCsisObserve(bool observe, tBTA_DM_SEARCH_CBACK* p_results_cb) { - APPL_TRACE_API("%s:enable = %d ", __func__, observe); - do_in_main_thread(FROM_HERE, - base::Bind(bta_dm_ble_csis_observe, observe, p_results_cb)); + LOG_VERBOSE("%s:enable = %d ", __func__, observe); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_ble_csis_observe, observe, + p_results_cb)); } /******************************************************************************* @@ -645,7 +395,7 @@ void BTA_DmBleCsisObserve(bool observe, tBTA_DM_SEARCH_CBACK* p_results_cb) { * Returns void * ******************************************************************************/ -void BTA_VendorInit(void) { APPL_TRACE_API("BTA_VendorInit"); } +void BTA_VendorInit(void) { LOG_VERBOSE("BTA_VendorInit"); } /******************************************************************************* * @@ -657,8 +407,8 @@ void BTA_VendorInit(void) { APPL_TRACE_API("BTA_VendorInit"); } * ******************************************************************************/ void BTA_DmClearEventFilter(void) { - APPL_TRACE_API("BTA_DmClearEventFilter"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_clear_event_filter)); + LOG_VERBOSE("BTA_DmClearEventFilter"); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_clear_event_filter)); } /******************************************************************************* @@ -671,8 +421,8 @@ void BTA_DmClearEventFilter(void) { * ******************************************************************************/ void BTA_DmClearEventMask(void) { - APPL_TRACE_API("BTA_DmClearEventMask"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_clear_event_mask)); + LOG_VERBOSE("BTA_DmClearEventMask"); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_clear_event_mask)); } /******************************************************************************* @@ -685,8 +435,8 @@ void BTA_DmClearEventMask(void) { * ******************************************************************************/ void BTA_DmClearFilterAcceptList(void) { - APPL_TRACE_API("BTA_DmClearFilterAcceptList"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_clear_filter_accept_list)); + LOG_VERBOSE("BTA_DmClearFilterAcceptList"); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_clear_filter_accept_list)); } /******************************************************************************* @@ -699,8 +449,8 @@ void BTA_DmClearFilterAcceptList(void) { * ******************************************************************************/ void BTA_DmLeRand(LeRandCallback cb) { - APPL_TRACE_API("BTA_DmLeRand"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_le_rand, cb)); + LOG_VERBOSE("BTA_DmLeRand"); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_le_rand, std::move(cb))); } /******************************************************************************* @@ -713,44 +463,45 @@ void BTA_DmLeRand(LeRandCallback cb) { * ******************************************************************************/ void BTA_DmDisconnectAllAcls() { - APPL_TRACE_API("BTA_DmLeRand"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_disconnect_all_acls)); + LOG_VERBOSE("BTA_DmLeRand"); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_disconnect_all_acls)); } void BTA_DmSetEventFilterConnectionSetupAllDevices() { - APPL_TRACE_API("BTA_DmSetEventFilterConnectionSetupAllDevices"); + LOG_VERBOSE("BTA_DmSetEventFilterConnectionSetupAllDevices"); do_in_main_thread( FROM_HERE, - base::Bind(bta_dm_set_event_filter_connection_setup_all_devices)); + base::BindOnce(bta_dm_set_event_filter_connection_setup_all_devices)); } void BTA_DmAllowWakeByHid( std::vector classic_hid_devices, std::vector> le_hid_devices) { - APPL_TRACE_API("BTA_DmAllowWakeByHid"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_allow_wake_by_hid, - std::move(classic_hid_devices), - std::move(le_hid_devices))); + LOG_VERBOSE("BTA_DmAllowWakeByHid"); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_allow_wake_by_hid, + std::move(classic_hid_devices), + std::move(le_hid_devices))); } void BTA_DmRestoreFilterAcceptList( std::vector> le_devices) { - APPL_TRACE_API("BTA_DmRestoreFilterAcceptList"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_restore_filter_accept_list, - std::move(le_devices))); + LOG_VERBOSE("BTA_DmRestoreFilterAcceptList"); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_restore_filter_accept_list, + std::move(le_devices))); } void BTA_DmSetDefaultEventMaskExcept(uint64_t mask, uint64_t le_mask) { - APPL_TRACE_API("BTA_DmSetDefaultEventMaskExcept"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_set_default_event_mask_except, - mask, le_mask)); + LOG_VERBOSE("BTA_DmSetDefaultEventMaskExcept"); + do_in_main_thread( + FROM_HERE, + base::BindOnce(bta_dm_set_default_event_mask_except, mask, le_mask)); } void BTA_DmSetEventFilterInquiryResultAllDevices() { - APPL_TRACE_API("BTA_DmSetEventFilterInquiryResultAllDevices"); + LOG_VERBOSE("BTA_DmSetEventFilterInquiryResultAllDevices"); do_in_main_thread( FROM_HERE, - base::Bind(bta_dm_set_event_filter_inquiry_result_all_devices)); + base::BindOnce(bta_dm_set_event_filter_inquiry_result_all_devices)); } /******************************************************************************* @@ -763,8 +514,8 @@ void BTA_DmSetEventFilterInquiryResultAllDevices() { * ******************************************************************************/ void BTA_DmBleResetId(void) { - APPL_TRACE_API("BTA_DmBleResetId"); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_ble_reset_id)); + LOG_VERBOSE("BTA_DmBleResetId"); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_ble_reset_id)); } /******************************************************************************* @@ -786,19 +537,24 @@ void BTA_DmBleResetId(void) { void BTA_DmBleSubrateRequest(const RawAddress& bd_addr, uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t timeout) { - APPL_TRACE_API("%s", __func__); - do_in_main_thread(FROM_HERE, - base::Bind(bta_dm_ble_subrate_request, bd_addr, subrate_min, - subrate_max, max_latency, cont_num, timeout)); + LOG_VERBOSE("%s", __func__); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_ble_subrate_request, + bd_addr, subrate_min, subrate_max, + max_latency, cont_num, timeout)); } bool BTA_DmCheckLeAudioCapable(const RawAddress& address) { - for (tBTM_INQ_INFO* inq_ent = BTM_InqDbFirst(); inq_ent != nullptr; - inq_ent = BTM_InqDbNext(inq_ent)) { + for (tBTM_INQ_INFO* inq_ent = get_btm_client_interface().db.BTM_InqDbFirst(); + inq_ent != nullptr; + inq_ent = get_btm_client_interface().db.BTM_InqDbNext(inq_ent)) { if (inq_ent->results.remote_bd_addr != address) continue; - LOG_INFO("Device is LE Audio capable based on AD content"); - return inq_ent->results.ble_ad_is_le_audio_capable; + if (inq_ent->results.ble_ad_is_le_audio_capable) { + LOG_INFO("Device is LE Audio capable based on AD content"); + return true; + } + + return false; } return false; } diff --git a/system/bta/dm/bta_dm_cfg.cc b/system/bta/dm/bta_dm_cfg.cc index fed90dbadc8c916c89cbdff15733ebb4ca5763e4..ace7c25e6c0b3c0bdf6269b341d325be79baa7ab 100644 --- a/system/bta/dm/bta_dm_cfg.cc +++ b/system/bta/dm/bta_dm_cfg.cc @@ -25,14 +25,13 @@ #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/dm/bta_dm_int.h" #include "bta/include/bta_api.h" #include "bta/include/bta_hh_api.h" #include "bta/include/bta_jv_api.h" #include "bta/sys/bta_sys.h" +#include "internal_include/bt_target.h" #include "osi/include/properties.h" -#include "types/raw_address.h" /* page timeout in 625uS */ #ifndef BTA_DM_PAGE_TIMEOUT diff --git a/system/bta/dm/bta_dm_ci.cc b/system/bta/dm/bta_dm_ci.cc index 6fc4242bb4b6009ea923b4210467ac47757487bf..b1f9be483bd026b25e406622ba63bcb8a9f80b4f 100644 --- a/system/bta/dm/bta_dm_ci.cc +++ b/system/bta/dm/bta_dm_ci.cc @@ -22,11 +22,11 @@ * ******************************************************************************/ #include + #include -#include "bta/dm/bta_dm_int.h" -#include "stack/include/bt_types.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "bta/dm/bta_dm_sec_int.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" /******************************************************************************* diff --git a/system/bta/dm/bta_dm_disc.cc b/system/bta/dm/bta_dm_disc.cc new file mode 100644 index 0000000000000000000000000000000000000000..784c48396589505898b9d5f4cec02c89135308b1 --- /dev/null +++ b/system/bta/dm/bta_dm_disc.cc @@ -0,0 +1,2551 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "bt_bta_dm" + +#include "bta/dm/bta_dm_disc.h" + +#include +#include +#include + +#include + +#include "bta/dm/bta_dm_disc.h" +#include "bta/dm/bta_dm_disc_int.h" +#include "bta/include/bta_gatt_api.h" +#include "bta/include/bta_sdp_api.h" +#include "btif/include/btif_config.h" +#include "common/circular_buffer.h" +#include "common/init_flags.h" +#include "common/strings.h" +#include "device/include/interop.h" +#include "include/bind_helpers.h" +#include "internal_include/bt_target.h" +#include "main/shim/dumpsys.h" +#include "os/log.h" +#include "osi/include/allocator.h" +#include "osi/include/fixed_queue.h" +#include "osi/include/osi.h" // UNUSED_ATTR +#include "stack/btm/btm_int_types.h" // TimestampedStringCircularBuffer +#include "stack/btm/neighbor_inquiry.h" +#include "stack/include/avrc_api.h" +#include "stack/include/bt_dev_class.h" +#include "stack/include/bt_hdr.h" +#include "stack/include/bt_name.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/btm_client_interface.h" +#include "stack/include/btm_log_history.h" +#include "stack/include/btm_sec_api.h" // BTM_IsRemoteNameKnown +#include "stack/include/gap_api.h" // GAP_BleReadPeerPrefConnParams +#include "stack/include/hidh_api.h" +#include "stack/include/sdp_status.h" +#include "stack/sdp/sdpint.h" // is_sdp_pbap_pce_disabled +#include "types/raw_address.h" + +#ifdef TARGET_FLOSS +#include "stack/include/srvc_api.h" +#endif + +using bluetooth::Uuid; +using namespace bluetooth::legacy::stack::sdp; + +tBTM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void); + +namespace { +constexpr char kBtmLogTag[] = "SDP"; + +tBTA_DM_SEARCH_CB bta_dm_search_cb; +} // namespace + +static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status); +static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, + uint16_t eir_len); +static void bta_dm_inq_cmpl(uint8_t num); +static void bta_dm_inq_cmpl_cb(void* p_result); +static void bta_dm_service_search_remname_cback(const RawAddress& bd_addr, + DEV_CLASS dc, + tBTM_BD_NAME bd_name); +static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p); +static void bta_dm_find_services(const RawAddress& bd_addr); +static void bta_dm_discover_next_device(void); +static void bta_dm_sdp_callback(const RawAddress& bd_addr, + tSDP_STATUS sdp_status); + +static void bta_dm_search_timer_cback(void* data); +static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, + tBT_TRANSPORT transport); +static void bta_dm_discover_device(const RawAddress& remote_bd_addr); + +static void bta_dm_disable_search_and_disc(void); + +static void bta_dm_gattc_register(void); +static void btm_dm_start_gatt_discovery(const RawAddress& bd_addr); +static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data); +static void bta_dm_search_cmpl(); +static void bta_dm_free_sdp_db(); +static void bta_dm_execute_queued_request(); +static void bta_dm_search_cancel_notify(); +static void bta_dm_close_gatt_conn(UNUSED_ATTR tBTA_DM_MSG* p_data); + +TimestampedStringCircularBuffer disc_gatt_history_{50}; + +namespace { + +struct gatt_interface_t { + void (*BTA_GATTC_CancelOpen)(tGATT_IF client_if, const RawAddress& remote_bda, + bool is_direct); + void (*BTA_GATTC_Refresh)(const RawAddress& remote_bda); + void (*BTA_GATTC_GetGattDb)(uint16_t conn_id, uint16_t start_handle, + uint16_t end_handle, btgatt_db_element_t** db, + int* count); + void (*BTA_GATTC_AppRegister)(tBTA_GATTC_CBACK* p_client_cb, + BtaAppRegisterCallback cb, bool eatt_support); + void (*BTA_GATTC_Close)(uint16_t conn_id); + void (*BTA_GATTC_ServiceSearchRequest)(uint16_t conn_id, + const bluetooth::Uuid* p_srvc_uuid); + void (*BTA_GATTC_Open)(tGATT_IF client_if, const RawAddress& remote_bda, + tBTM_BLE_CONN_TYPE connection_type, + bool opportunistic); +} default_gatt_interface = { + .BTA_GATTC_CancelOpen = + [](tGATT_IF client_if, const RawAddress& remote_bda, bool is_direct) { + disc_gatt_history_.Push(base::StringPrintf( + "%-32s bd_addr:%s client_if:%hu is_direct:%c", "GATTC_CancelOpen", + ADDRESS_TO_LOGGABLE_CSTR(remote_bda), client_if, + (is_direct) ? 'T' : 'F')); + BTA_GATTC_CancelOpen(client_if, remote_bda, is_direct); + }, + .BTA_GATTC_Refresh = + [](const RawAddress& remote_bda) { + disc_gatt_history_.Push( + base::StringPrintf("%-32s bd_addr:%s", "GATTC_Refresh", + ADDRESS_TO_LOGGABLE_CSTR(remote_bda))); + BTA_GATTC_Refresh(remote_bda); + }, + .BTA_GATTC_GetGattDb = + [](uint16_t conn_id, uint16_t start_handle, uint16_t end_handle, + btgatt_db_element_t** db, int* count) { + disc_gatt_history_.Push(base::StringPrintf( + "%-32s conn_id:%hu start_handle:%hu end:handle:%hu", + "GATTC_GetGattDb", conn_id, start_handle, end_handle)); + BTA_GATTC_GetGattDb(conn_id, start_handle, end_handle, db, count); + }, + .BTA_GATTC_AppRegister = + [](tBTA_GATTC_CBACK* p_client_cb, BtaAppRegisterCallback cb, + bool eatt_support) { + disc_gatt_history_.Push( + base::StringPrintf("%-32s eatt_support:%c", "GATTC_AppRegister", + (eatt_support) ? 'T' : 'F')); + BTA_GATTC_AppRegister(p_client_cb, cb, eatt_support); + }, + .BTA_GATTC_Close = + [](uint16_t conn_id) { + disc_gatt_history_.Push( + base::StringPrintf("%-32s conn_id:%hu", "GATTC_Close", conn_id)); + BTA_GATTC_Close(conn_id); + }, + .BTA_GATTC_ServiceSearchRequest = + [](uint16_t conn_id, const bluetooth::Uuid* p_srvc_uuid) { + disc_gatt_history_.Push(base::StringPrintf( + "%-32s conn_id:%hu", "GATTC_ServiceSearchRequest", conn_id)); + BTA_GATTC_ServiceSearchRequest(conn_id, p_srvc_uuid); + }, + .BTA_GATTC_Open = + [](tGATT_IF client_if, const RawAddress& remote_bda, + tBTM_BLE_CONN_TYPE connection_type, bool opportunistic) { + disc_gatt_history_.Push(base::StringPrintf( + "%-32s bd_addr:%s client_if:%hu type:0x%x opportunistic:%c", + "GATTC_Open", ADDRESS_TO_LOGGABLE_CSTR(remote_bda), client_if, + connection_type, (opportunistic) ? 'T' : 'F')); + BTA_GATTC_Open(client_if, remote_bda, connection_type, opportunistic); + }, +}; + +gatt_interface_t* gatt_interface = &default_gatt_interface; + +gatt_interface_t& get_gatt_interface() { return *gatt_interface; } + +} // namespace + +void bta_dm_disc_disable_search_and_disc() { bta_dm_disable_search_and_disc(); } + +void bta_dm_disc_gatt_cancel_open(const RawAddress& bd_addr) { + get_gatt_interface().BTA_GATTC_CancelOpen(0, bd_addr, false); +} + +void bta_dm_disc_gatt_refresh(const RawAddress& bd_addr) { + get_gatt_interface().BTA_GATTC_Refresh(bd_addr); +} + +void bta_dm_disc_remove_device(const RawAddress& bd_addr) { + if (bta_dm_search_cb.state == BTA_DM_DISCOVER_ACTIVE && + bta_dm_search_cb.peer_bdaddr == bd_addr) { + LOG_INFO( + "Device removed while service discovery was pending, " + "conclude the service disvovery"); + bta_dm_gatt_disc_complete((uint16_t)GATT_INVALID_CONN_ID, + (tGATT_STATUS)GATT_ERROR); + } +} + +void bta_dm_disc_discover_next_device() { bta_dm_discover_next_device(); } + +void bta_dm_disc_gattc_register() { bta_dm_gattc_register(); } + +static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, + const uint8_t* p_eir, uint16_t eir_len); +static void bta_dm_observe_cmpl_cb(void* p_result); + +const uint16_t bta_service_id_to_uuid_lkup_tbl[BTA_MAX_SERVICE_ID] = { + UUID_SERVCLASS_PNP_INFORMATION, /* Reserved */ + UUID_SERVCLASS_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */ + UUID_SERVCLASS_DIALUP_NETWORKING, /* BTA_DUN_SERVICE_ID */ + UUID_SERVCLASS_AUDIO_SOURCE, /* BTA_A2DP_SOURCE_SERVICE_ID */ + UUID_SERVCLASS_LAN_ACCESS_USING_PPP, /* BTA_LAP_SERVICE_ID */ + UUID_SERVCLASS_HEADSET, /* BTA_HSP_HS_SERVICE_ID */ + UUID_SERVCLASS_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */ + UUID_SERVCLASS_OBEX_OBJECT_PUSH, /* BTA_OPP_SERVICE_ID */ + UUID_SERVCLASS_OBEX_FILE_TRANSFER, /* BTA_FTP_SERVICE_ID */ + UUID_SERVCLASS_CORDLESS_TELEPHONY, /* BTA_CTP_SERVICE_ID */ + UUID_SERVCLASS_INTERCOM, /* BTA_ICP_SERVICE_ID */ + UUID_SERVCLASS_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */ + UUID_SERVCLASS_DIRECT_PRINTING, /* BTA_BPP_SERVICE_ID */ + UUID_SERVCLASS_IMAGING_RESPONDER, /* BTA_BIP_SERVICE_ID */ + UUID_SERVCLASS_PANU, /* BTA_PANU_SERVICE_ID */ + UUID_SERVCLASS_NAP, /* BTA_NAP_SERVICE_ID */ + UUID_SERVCLASS_GN, /* BTA_GN_SERVICE_ID */ + UUID_SERVCLASS_SAP, /* BTA_SAP_SERVICE_ID */ + UUID_SERVCLASS_AUDIO_SINK, /* BTA_A2DP_SERVICE_ID */ + UUID_SERVCLASS_AV_REMOTE_CONTROL, /* BTA_AVRCP_SERVICE_ID */ + UUID_SERVCLASS_HUMAN_INTERFACE, /* BTA_HID_SERVICE_ID */ + UUID_SERVCLASS_VIDEO_SINK, /* BTA_VDP_SERVICE_ID */ + UUID_SERVCLASS_PBAP_PSE, /* BTA_PBAP_SERVICE_ID */ + UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, /* BTA_HSP_SERVICE_ID */ + UUID_SERVCLASS_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */ + UUID_SERVCLASS_MESSAGE_ACCESS, /* BTA_MAP_SERVICE_ID */ + UUID_SERVCLASS_MESSAGE_NOTIFICATION, /* BTA_MN_SERVICE_ID */ + UUID_SERVCLASS_HDP_PROFILE, /* BTA_HDP_SERVICE_ID */ + UUID_SERVCLASS_PBAP_PCE, /* BTA_PCE_SERVICE_ID */ + UUID_PROTOCOL_ATT /* BTA_GATT_SERVICE_ID */ +}; + +#define MAX_DISC_RAW_DATA_BUF (4096) +static uint8_t g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF]; + +static void bta_dm_search_set_state(tBTA_DM_STATE state) { + bta_dm_search_cb.state = state; +} +static tBTA_DM_STATE bta_dm_search_get_state() { + return bta_dm_search_cb.state; +} + +/******************************************************************************* + * + * Function bta_dm_search_start + * + * Description Starts an inquiry + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_search_start(tBTA_DM_MSG* p_data) { + bta_dm_gattc_register(); + + get_btm_client_interface().db.BTM_ClearInqDb(nullptr); + /* save search params */ + bta_dm_search_cb.p_search_cback = p_data->search.p_cback; + bta_dm_search_cb.services = p_data->search.services; + + const tBTM_STATUS btm_status = + BTM_StartInquiry(bta_dm_inq_results_cb, bta_dm_inq_cmpl_cb); + switch (btm_status) { + case BTM_CMD_STARTED: + // Completion callback will be executed when controller inquiry + // timer pops or is cancelled by the user + break; + default: + LOG_WARN("Unable to start device discovery search btm_status:%s", + btm_status_text(btm_status).c_str()); + // Not started so completion callback is executed now + bta_dm_inq_cmpl(0); + break; + } +} + +/******************************************************************************* + * + * Function bta_dm_search_cancel + * + * Description Cancels an ongoing search for devices + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_search_cancel() { + if (BTM_IsInquiryActive()) { + BTM_CancelInquiry(); + bta_dm_search_cancel_notify(); + bta_dm_search_cmpl(); + } + /* If no Service Search going on then issue cancel remote name in case it is + active */ + else if (!bta_dm_search_cb.name_discover_done) { + get_btm_client_interface().peer.BTM_CancelRemoteDeviceName(); + bta_dm_search_cmpl(); + } else { + bta_dm_inq_cmpl(0); + } +} + +/******************************************************************************* + * + * Function bta_dm_discover + * + * Description Discovers services on a remote device + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_discover(tBTA_DM_MSG* p_data) { + /* save the search condition */ + bta_dm_search_cb.services = BTA_ALL_SERVICE_MASK; + + bta_dm_gattc_register(); + + bta_dm_search_cb.p_search_cback = p_data->discover.p_cback; + bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; + bta_dm_search_cb.service_index = 0; + bta_dm_search_cb.services_found = 0; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_search_cb.p_btm_inq_info = + get_btm_client_interface().db.BTM_InqDbRead(p_data->discover.bd_addr); + bta_dm_search_cb.transport = p_data->discover.transport; + + bta_dm_search_cb.name_discover_done = false; + + LOG_INFO("bta_dm_discovery: starting service discovery to %s , transport: %s", + ADDRESS_TO_LOGGABLE_CSTR(p_data->discover.bd_addr), + bt_transport_text(p_data->discover.transport).c_str()); + bta_dm_discover_device(p_data->discover.bd_addr); +} + +/******************************************************************************* + * + * Function bta_dm_disable_search_and_disc + * + * Description Cancels an ongoing search or discovery for devices in case + * of a Bluetooth disable + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_disable_search_and_disc(void) { + switch (bta_dm_search_get_state()) { + case BTA_DM_SEARCH_IDLE: + break; + case BTA_DM_SEARCH_ACTIVE: + case BTA_DM_SEARCH_CANCELLING: + case BTA_DM_DISCOVER_ACTIVE: + default: + LOG_DEBUG( + "Search state machine is not idle so issuing search cancel current " + "state:%s", + bta_dm_state_text(bta_dm_search_get_state()).c_str()); + bta_dm_search_cancel(); + } +} + +/******************************************************************************* + * + * Function bta_dm_read_remote_device_name + * + * Description Initiate to get remote device name + * + * Returns true if started to get remote name + * + ******************************************************************************/ +static bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, + tBT_TRANSPORT transport) { + tBTM_STATUS btm_status; + + LOG_VERBOSE("%s", __func__); + + bta_dm_search_cb.peer_bdaddr = bd_addr; + bta_dm_search_cb.peer_name[0] = 0; + + btm_status = get_btm_client_interface().peer.BTM_ReadRemoteDeviceName( + bta_dm_search_cb.peer_bdaddr, bta_dm_remname_cback, transport); + + if (btm_status == BTM_CMD_STARTED) { + LOG_VERBOSE("%s: BTM_ReadRemoteDeviceName is started", __func__); + + return (true); + } else if (btm_status == BTM_BUSY) { + LOG_VERBOSE("%s: BTM_ReadRemoteDeviceName is busy", __func__); + + /* Remote name discovery is on going now so BTM cannot notify through + * "bta_dm_remname_cback" */ + /* adding callback to get notified that current reading remote name done */ + + get_btm_client_interface().security.BTM_SecAddRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); + + return (true); + } else { + LOG_WARN("%s: BTM_ReadRemoteDeviceName returns 0x%02X", __func__, + btm_status); + + return (false); + } +} + +/******************************************************************************* + * + * Function bta_dm_inq_cmpl + * + * Description Process the inquiry complete event from BTM + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_inq_cmpl(uint8_t num) { + if (bta_dm_search_get_state() == BTA_DM_SEARCH_CANCELLING) { + bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); + bta_dm_execute_queued_request(); + return; + } + + if (bta_dm_search_get_state() != BTA_DM_SEARCH_ACTIVE) { + return; + } + + tBTA_DM_SEARCH data; + + LOG_VERBOSE("bta_dm_inq_cmpl"); + + data.inq_cmpl.num_resps = num; + bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data); + + bta_dm_search_cb.p_btm_inq_info = + get_btm_client_interface().db.BTM_InqDbFirst(); + if (bta_dm_search_cb.p_btm_inq_info != NULL) { + /* start name and service discovery from the first device on inquiry result + */ + bta_dm_search_cb.name_discover_done = false; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_discover_device( + bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); + } else { + bta_dm_search_cb.services = 0; + bta_dm_search_cmpl(); + } +} + +static void bta_dm_remote_name_cmpl(const tBTA_DM_MSG* p_data) { + CHECK(p_data != nullptr); + + const tBTA_DM_REMOTE_NAME& remote_name_msg = p_data->remote_name_msg; + + BTM_LogHistory(kBtmLogTag, remote_name_msg.bd_addr, "Remote name completed", + base::StringPrintf( + "status:%s state:%s name:\"%s\"", + hci_status_code_text(remote_name_msg.hci_status).c_str(), + bta_dm_state_text(bta_dm_search_get_state()).c_str(), + PRIVATE_NAME(remote_name_msg.bd_name))); + + tBTM_INQ_INFO* p_btm_inq_info = + get_btm_client_interface().db.BTM_InqDbRead(remote_name_msg.bd_addr); + if (!bd_name_is_empty(remote_name_msg.bd_name) && p_btm_inq_info) { + p_btm_inq_info->appl_knows_rem_name = true; + } + + // Callback with this property + if (bta_dm_search_cb.p_search_cback != nullptr) { + tBTA_DM_SEARCH search_data = { + .disc_res = // tBTA_DM_DISC_RES + { + .bd_addr = remote_name_msg.bd_addr, + .bd_name = {}, + .services = {}, + .device_type = {}, + .num_uuids = 0UL, + .p_uuid_list = nullptr, + .result = (remote_name_msg.hci_status == HCI_SUCCESS) ? BTA_SUCCESS + : BTA_FAILURE, + .hci_status = remote_name_msg.hci_status, + }, + }; + if (remote_name_msg.hci_status == HCI_SUCCESS) { + bd_name_copy(search_data.disc_res.bd_name, remote_name_msg.bd_name); + } + bta_dm_search_cb.p_search_cback(BTA_DM_NAME_READ_EVT, &search_data); + } else { + LOG_WARN("Received remote name complete without callback"); + } + + switch (bta_dm_search_get_state()) { + case BTA_DM_SEARCH_ACTIVE: + bta_dm_discover_device(bta_dm_search_cb.peer_bdaddr); + break; + case BTA_DM_DISCOVER_ACTIVE: + bta_dm_discover_device(remote_name_msg.bd_addr); + break; + case BTA_DM_SEARCH_IDLE: + case BTA_DM_SEARCH_CANCELLING: + LOG_WARN("Received remote name request in state:%s", + bta_dm_state_text(bta_dm_search_get_state()).c_str()); + break; + } +} + +static void store_avrcp_profile_feature(tSDP_DISC_REC* sdp_rec) { + tSDP_DISC_ATTR* p_attr = + get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + sdp_rec, ATTR_ID_SUPPORTED_FEATURES); + if (p_attr == NULL) { + return; + } + + uint16_t avrcp_features = p_attr->attr_value.v.u16; + if (avrcp_features == 0) { + return; + } + + if (btif_config_set_bin(sdp_rec->remote_bd_addr.ToString().c_str(), + AV_REM_CTRL_FEATURES_CONFIG_KEY, + (const uint8_t*)&avrcp_features, + sizeof(avrcp_features))) { + LOG_INFO("Saving avrcp_features: 0x%x", avrcp_features); + } else { + LOG_INFO("Failed to store avrcp_features 0x%x for %s", avrcp_features, + ADDRESS_TO_LOGGABLE_CSTR(sdp_rec->remote_bd_addr)); + } +} + +static void bta_dm_store_audio_profiles_version() { + struct AudioProfile { + const uint16_t servclass_uuid; + const uint16_t btprofile_uuid; + const char* profile_key; + void (*store_audio_profile_feature)(tSDP_DISC_REC*); + }; + + std::array audio_profiles = {{ + { + .servclass_uuid = UUID_SERVCLASS_AV_REMOTE_CONTROL, + .btprofile_uuid = UUID_SERVCLASS_AV_REMOTE_CONTROL, + .profile_key = AVRCP_CONTROLLER_VERSION_CONFIG_KEY, + .store_audio_profile_feature = store_avrcp_profile_feature, + }, + }}; + + for (const auto& audio_profile : audio_profiles) { + tSDP_DISC_REC* sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + bta_dm_search_cb.p_sdp_db, audio_profile.servclass_uuid, NULL); + if (sdp_rec == NULL) continue; + + if (get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + sdp_rec, ATTR_ID_BT_PROFILE_DESC_LIST) == NULL) + continue; + + uint16_t profile_version = 0; + /* get profile version (if failure, version parameter is not updated) */ + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + sdp_rec, audio_profile.btprofile_uuid, &profile_version); + if (profile_version != 0) { + if (btif_config_set_bin(sdp_rec->remote_bd_addr.ToString().c_str(), + audio_profile.profile_key, + (const uint8_t*)&profile_version, + sizeof(profile_version))) { + } else { + LOG_INFO("Failed to store peer profile version for %s", + ADDRESS_TO_LOGGABLE_CSTR(sdp_rec->remote_bd_addr)); + } + } + audio_profile.store_audio_profile_feature(sdp_rec); + } +} + +/******************************************************************************* + * + * Function bta_dm_sdp_result + * + * Description Process the discovery result from sdp + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_sdp_result(tBTA_DM_MSG* p_data) { + tSDP_DISC_REC* p_sdp_rec = NULL; + tBTA_DM_MSG* p_msg; + bool scn_found = false; + uint16_t service = 0xFFFF; + tSDP_PROTOCOL_ELEM pe; + + std::vector uuid_list; + + const tSDP_RESULT sdp_result = p_data->sdp_event.sdp_result; + + if ((p_data->sdp_event.sdp_result == SDP_SUCCESS) || + (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) || + (p_data->sdp_event.sdp_result == SDP_DB_FULL)) { + LOG_VERBOSE("sdp_result::0x%x", p_data->sdp_event.sdp_result); + do { + p_sdp_rec = NULL; + if (bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID + 1)) { + if (p_sdp_rec && + get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + bta_dm_search_cb.peer_scn = (uint8_t)pe.params[0]; + scn_found = true; + } + } else { + service = + bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index - 1]; + p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + bta_dm_search_cb.p_sdp_db, service, p_sdp_rec); + } + /* finished with BR/EDR services, now we check the result for GATT based + * service UUID */ + if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID) { + /* all GATT based services */ + + std::vector gatt_uuids; + + do { + /* find a service record, report it */ + p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + bta_dm_search_cb.p_sdp_db, 0, p_sdp_rec); + if (p_sdp_rec) { + Uuid service_uuid; + if (get_legacy_stack_sdp_api()->record.SDP_FindServiceUUIDInRec( + p_sdp_rec, &service_uuid)) { + gatt_uuids.push_back(service_uuid); + } + } + } while (p_sdp_rec); + + if (!gatt_uuids.empty()) { + LOG_INFO("GATT services discovered using SDP"); + + // send all result back to app + tBTA_DM_SEARCH result; + result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr; + strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(), + BD_NAME_LEN + 1); + + result.disc_ble_res.services = &gatt_uuids; + bta_dm_search_cb.p_search_cback(BTA_DM_GATT_OVER_SDP_RES_EVT, + &result); + } + } else { + /* SDP_DB_FULL means some records with the + required attributes were received */ + if (((p_data->sdp_event.sdp_result == SDP_DB_FULL) && + bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) || + (p_sdp_rec != NULL)) { + if (service != UUID_SERVCLASS_PNP_INFORMATION) { + bta_dm_search_cb.services_found |= + (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK( + bta_dm_search_cb.service_index - 1)); + uint16_t tmp_svc = + bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index - + 1]; + /* Add to the list of UUIDs */ + uuid_list.push_back(Uuid::From16Bit(tmp_svc)); + } + } + } + + if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK && + bta_dm_search_cb.services_to_search == 0) { + bta_dm_search_cb.service_index++; + } else /* regular one service per search or PNP search */ + break; + + } while (bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID); + + LOG_VERBOSE("%s services_found = %04x", __func__, + bta_dm_search_cb.services_found); + + /* Collect the 128-bit services here and put them into the list */ + if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) { + p_sdp_rec = NULL; + do { + /* find a service record, report it */ + p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb_128bit( + bta_dm_search_cb.p_sdp_db, p_sdp_rec); + if (p_sdp_rec) { + // SDP_FindServiceUUIDInRec_128bit is used only once, refactor? + Uuid temp_uuid; + if (get_legacy_stack_sdp_api() + ->record.SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, + &temp_uuid)) { + uuid_list.push_back(temp_uuid); + } + } + } while (p_sdp_rec); + } + + if (bluetooth::common::init_flags:: + dynamic_avrcp_version_enhancement_is_enabled() && + bta_dm_search_cb.services_to_search == 0) { + bta_dm_store_audio_profiles_version(); + } + +#if TARGET_FLOSS + tSDP_DI_GET_RECORD di_record; + if (get_legacy_stack_sdp_api()->device_id.SDP_GetDiRecord( + 1, &di_record, bta_dm_search_cb.p_sdp_db) == SDP_SUCCESS) { + tBTA_DM_SEARCH result; + result.did_res.bd_addr = bta_dm_search_cb.peer_bdaddr; + result.did_res.vendor_id_src = di_record.rec.vendor_id_source; + result.did_res.vendor_id = di_record.rec.vendor; + result.did_res.product_id = di_record.rec.product; + result.did_res.version = di_record.rec.version; + bta_dm_search_cb.p_search_cback(BTA_DM_DID_RES_EVT, &result); + } +#endif + + /* if there are more services to search for */ + if (bta_dm_search_cb.services_to_search) { + /* Free up the p_sdp_db before checking the next one */ + bta_dm_free_sdp_db(); + bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); + } else { + /* callbacks */ + /* start next bd_addr if necessary */ + + get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); + + BTM_LogHistory( + kBtmLogTag, bta_dm_search_cb.peer_bdaddr, "Discovery completed", + base::StringPrintf("Result:%s services_found:0x%x service_index:0x%d", + sdp_result_text(sdp_result).c_str(), + bta_dm_search_cb.services_found, + bta_dm_search_cb.service_index)); + + p_msg = (tBTA_DM_MSG*)osi_calloc(sizeof(tBTA_DM_MSG)); + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; + p_msg->disc_result.result.disc_res.num_uuids = uuid_list.size(); + p_msg->disc_result.result.disc_res.p_uuid_list = NULL; + if (uuid_list.size() > 0) { + // TODO(jpawlowski): make p_uuid_list into vector, and just copy + // vectors, but first get rid of bta_sys_sendmsg below. + p_msg->disc_result.result.disc_res.p_uuid_list = + (Uuid*)osi_calloc(uuid_list.size() * sizeof(Uuid)); + memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list.data(), + uuid_list.size() * sizeof(Uuid)); + } + // Copy the raw_data to the discovery result structure + if (bta_dm_search_cb.p_sdp_db != NULL && + bta_dm_search_cb.p_sdp_db->raw_used != 0 && + bta_dm_search_cb.p_sdp_db->raw_data != NULL) { + LOG_VERBOSE("%s raw_data used = 0x%x raw_data_ptr = 0x%p", __func__, + bta_dm_search_cb.p_sdp_db->raw_used, + bta_dm_search_cb.p_sdp_db->raw_data); + + bta_dm_search_cb.p_sdp_db->raw_data = + NULL; // no need to free this - it is a global assigned. + bta_dm_search_cb.p_sdp_db->raw_used = 0; + bta_dm_search_cb.p_sdp_db->raw_size = 0; + } else { + LOG_VERBOSE("%s raw data size is 0 or raw_data is null!!", __func__); + } + /* Done with p_sdp_db. Free it */ + bta_dm_free_sdp_db(); + p_msg->disc_result.result.disc_res.services = + bta_dm_search_cb.services_found; + + // Piggy back the SCN over result field + if (scn_found) { + p_msg->disc_result.result.disc_res.result = + static_cast((3 + bta_dm_search_cb.peer_scn)); + p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK; + + LOG_VERBOSE(" Piggy back the SCN over result field SCN=%d", + bta_dm_search_cb.peer_scn); + } + p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; + strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, + bta_dm_get_remname(), BD_NAME_LEN + 1); + + bta_sys_sendmsg(p_msg); + } + } else { + BTM_LogHistory( + kBtmLogTag, bta_dm_search_cb.peer_bdaddr, "Discovery failed", + base::StringPrintf("Result:%s", sdp_result_text(sdp_result).c_str())); + LOG_ERROR("SDP connection failed %s", sdp_status_text(sdp_result).c_str()); + if (p_data->sdp_event.sdp_result == SDP_CONN_FAILED) + bta_dm_search_cb.wait_disc = false; + + /* not able to connect go to next device */ + if (bta_dm_search_cb.p_sdp_db) + osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db); + + get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); + + p_msg = (tBTA_DM_MSG*)osi_calloc(sizeof(tBTA_DM_MSG)); + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = BTA_FAILURE; + p_msg->disc_result.result.disc_res.services = + bta_dm_search_cb.services_found; + p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; + strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, + bta_dm_get_remname(), BD_NAME_LEN + 1); + + bta_sys_sendmsg(p_msg); + } +} + +/** Callback of peer's DIS reply. This is only called for floss */ +#if TARGET_FLOSS +static void bta_dm_read_dis_cmpl(const RawAddress& addr, + tDIS_VALUE* p_dis_value) { + if (!p_dis_value) { + LOG_WARN("read DIS failed"); + } else { + tBTA_DM_SEARCH result; + result.did_res.bd_addr = addr; + result.did_res.vendor_id_src = p_dis_value->pnp_id.vendor_id_src; + result.did_res.vendor_id = p_dis_value->pnp_id.vendor_id; + result.did_res.product_id = p_dis_value->pnp_id.product_id; + result.did_res.version = p_dis_value->pnp_id.product_version; + bta_dm_search_cb.p_search_cback(BTA_DM_DID_RES_EVT, &result); + } + + bta_dm_execute_queued_request(); +} +#endif + +/******************************************************************************* + * + * Function bta_dm_search_cmpl + * + * Description Sends event to application + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_search_cmpl() { + bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); + + uint16_t conn_id = bta_dm_search_cb.conn_id; + + tBTA_DM_SEARCH result; + std::vector gatt_services; + result.disc_ble_res.services = &gatt_services; + result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr; + strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(), + BD_NAME_LEN + 1); + + bool send_gatt_results = + bluetooth::common::init_flags:: + always_send_services_if_gatt_disc_done_is_enabled() + ? bta_dm_search_cb.gatt_disc_active + : false; + + /* no BLE connection, i.e. Classic service discovery end */ + if (conn_id == GATT_INVALID_CONN_ID) { + if (bta_dm_search_cb.gatt_disc_active) { + LOG_WARN( + "GATT active but no BLE connection, likely disconnected midway " + "through"); + } else { + LOG_INFO("No BLE connection, processing classic results"); + } + } else { + btgatt_db_element_t* db = NULL; + int count = 0; + get_gatt_interface().BTA_GATTC_GetGattDb(conn_id, 0x0000, 0xFFFF, &db, + &count); + if (count != 0) { + for (int i = 0; i < count; i++) { + // we process service entries only + if (db[i].type == BTGATT_DB_PRIMARY_SERVICE) { + gatt_services.push_back(db[i].uuid); + } + } + osi_free(db); + LOG_INFO( + "GATT services discovered using LE Transport, will always send to " + "upper layer"); + send_gatt_results = true; + } else { + LOG_WARN("Empty GATT database - no BLE services discovered"); + } + } + + // send all result back to app + if (send_gatt_results) { + LOG_INFO("Sending GATT results to upper layer"); + bta_dm_search_cb.p_search_cback(BTA_DM_GATT_OVER_LE_RES_EVT, &result); + } + + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr); + bta_dm_search_cb.gatt_disc_active = false; + +#if TARGET_FLOSS + if (conn_id != GATT_INVALID_CONN_ID && + DIS_ReadDISInfo(bta_dm_search_cb.peer_bdaddr, bta_dm_read_dis_cmpl, + DIS_ATTR_PNP_ID_BIT)) { + return; + } +#endif + + bta_dm_execute_queued_request(); +} + +/******************************************************************************* + * + * Function bta_dm_disc_result + * + * Description Service discovery result when discovering services on a + * device + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_disc_result(tBTA_DM_MSG* p_data) { + LOG_VERBOSE("%s", __func__); + + /* disc_res.device_type is set only when GATT discovery is finished in + * bta_dm_gatt_disc_complete */ + bool is_gatt_over_ble = ((p_data->disc_result.result.disc_res.device_type & + BT_DEVICE_TYPE_BLE) != 0); + + /* if any BR/EDR service discovery has been done, report the event */ + if (!is_gatt_over_ble && (bta_dm_search_cb.services & + ((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK) & + ~BTA_BLE_SERVICE_MASK))) + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, + &p_data->disc_result.result); + + get_gatt_interface().BTA_GATTC_CancelOpen(0, bta_dm_search_cb.peer_bdaddr, + true); + + bta_dm_search_cmpl(); +} + +/******************************************************************************* + * + * Function bta_dm_search_result + * + * Description Service discovery result while searching for devices + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_search_result(tBTA_DM_MSG* p_data) { + LOG_VERBOSE("%s searching:0x%04x, result:0x%04x", __func__, + bta_dm_search_cb.services, + p_data->disc_result.result.disc_res.services); + + /* call back if application wants name discovery or found services that + * application is searching */ + if ((!bta_dm_search_cb.services) || + ((bta_dm_search_cb.services) && + (p_data->disc_result.result.disc_res.services))) { + if (bta_dm_search_cb.p_search_cback) { + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, + &p_data->disc_result.result); + } else { + LOG_WARN("Received search result without valid callback"); + } + } + + /* if searching did not initiate to create link */ + if (!bta_dm_search_cb.wait_disc) { + /* if service searching is done with EIR, don't search next device */ + if (bta_dm_search_cb.p_btm_inq_info) bta_dm_discover_next_device(); + } else { + /* wait until link is disconnected or timeout */ + bta_dm_search_cb.sdp_results = true; + alarm_set_on_mloop(bta_dm_search_cb.search_timer, + 1000 * (L2CAP_LINK_INACTIVITY_TOUT + 1), + bta_dm_search_timer_cback, NULL); + } +} + +/******************************************************************************* + * + * Function bta_dm_search_timer_cback + * + * Description Called when ACL disconnect time is over + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_search_timer_cback(UNUSED_ATTR void* data) { + LOG_VERBOSE("%s", __func__); + bta_dm_search_cb.wait_disc = false; + + /* proceed with next device */ + bta_dm_discover_next_device(); +} + +/******************************************************************************* + * + * Function bta_dm_free_sdp_db + * + * Description Frees SDP data base + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_free_sdp_db() { + osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db); +} + +/******************************************************************************* + * + * Function bta_dm_queue_search + * + * Description Queues search command + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_queue_search(tBTA_DM_MSG* p_data) { + if (bta_dm_search_cb.p_pending_search) { + LOG_WARN("Overwrote previous device discovery inquiry scan request"); + } + osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search); + bta_dm_search_cb.p_pending_search = + (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_SEARCH)); + memcpy(bta_dm_search_cb.p_pending_search, p_data, sizeof(tBTA_DM_API_SEARCH)); + LOG_INFO("Queued device discovery inquiry scan request"); +} + +/******************************************************************************* + * + * Function bta_dm_queue_disc + * + * Description Queues discovery command + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_queue_disc(tBTA_DM_MSG* p_data) { + tBTA_DM_MSG* p_pending_discovery = + (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_DISCOVER)); + memcpy(p_pending_discovery, p_data, sizeof(tBTA_DM_API_DISCOVER)); + + LOG_INFO("bta_dm_discovery: queuing service discovery to %s", + ADDRESS_TO_LOGGABLE_CSTR(p_pending_discovery->discover.bd_addr)); + fixed_queue_enqueue(bta_dm_search_cb.pending_discovery_queue, + p_pending_discovery); +} + +/******************************************************************************* + * + * Function bta_dm_execute_queued_request + * + * Description Executes queued request if one exists + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_execute_queued_request() { + tBTA_DM_MSG* p_pending_discovery = (tBTA_DM_MSG*)fixed_queue_try_dequeue( + bta_dm_search_cb.pending_discovery_queue); + if (p_pending_discovery) { + LOG_INFO("%s Start pending discovery", __func__); + bta_sys_sendmsg(p_pending_discovery); + } else if (bta_dm_search_cb.p_pending_search) { + LOG_INFO("%s Start pending search", __func__); + bta_sys_sendmsg(bta_dm_search_cb.p_pending_search); + bta_dm_search_cb.p_pending_search = NULL; + } +} + +/******************************************************************************* + * + * Function bta_dm_is_search_request_queued + * + * Description Checks if there is a queued search request + * + * Returns bool + * + ******************************************************************************/ +bool bta_dm_is_search_request_queued() { + return bta_dm_search_cb.p_pending_search != NULL; +} + +/******************************************************************************* + * + * Function bta_dm_search_clear_queue + * + * Description Clears the queue if API search cancel is called + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_search_clear_queue() { + osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search); + if (bluetooth::common::InitFlags:: + IsBtmDmFlushDiscoveryQueueOnSearchCancel()) { + fixed_queue_flush(bta_dm_search_cb.pending_discovery_queue, osi_free); + } +} + +/******************************************************************************* + * + * Function bta_dm_search_cancel_notify + * + * Description Notify application that search has been cancelled + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_search_cancel_notify() { + if (bta_dm_search_cb.p_search_cback) { + bta_dm_search_cb.p_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL); + } + switch (bta_dm_search_get_state()) { + case BTA_DM_SEARCH_ACTIVE: + case BTA_DM_SEARCH_CANCELLING: + if (!bta_dm_search_cb.name_discover_done) { + get_btm_client_interface().peer.BTM_CancelRemoteDeviceName(); + } + break; + case BTA_DM_SEARCH_IDLE: + case BTA_DM_DISCOVER_ACTIVE: + // Nothing to do + break; + } +} + +/******************************************************************************* + * + * Function bta_dm_find_services + * + * Description Starts discovery on a device + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_find_services(const RawAddress& bd_addr) { + while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) { + Uuid uuid = Uuid::kEmpty; + if (bta_dm_search_cb.services_to_search & + (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK( + bta_dm_search_cb.service_index))) { + bta_dm_search_cb.p_sdp_db = + (tSDP_DISCOVERY_DB*)osi_malloc(BTA_DM_SDP_DB_SIZE); + LOG_VERBOSE("bta_dm_search_cb.services = %04x***********", + bta_dm_search_cb.services); + /* try to search all services by search based on L2CAP UUID */ + if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) { + LOG_INFO("%s services_to_search=%08x", __func__, + bta_dm_search_cb.services_to_search); + if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) { + uuid = Uuid::From16Bit(bta_service_id_to_uuid_lkup_tbl[0]); + bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK; + } else { + uuid = Uuid::From16Bit(UUID_PROTOCOL_L2CAP); + bta_dm_search_cb.services_to_search = 0; + } + } else { + /* for LE only profile */ + if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) { + uuid = Uuid::From16Bit( + bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]); + + bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~( + BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))); + } else { + /* remove the service from services to be searched */ + bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~( + BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))); + uuid = Uuid::From16Bit( + bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]); + } + } + + LOG_INFO("%s search UUID = %s", __func__, uuid.ToString().c_str()); + get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, 0, NULL); + + memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); + bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf; + + bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF; + + if (!get_legacy_stack_sdp_api() + ->service.SDP_ServiceSearchAttributeRequest( + bd_addr, bta_dm_search_cb.p_sdp_db, &bta_dm_sdp_callback)) { + /* + * If discovery is not successful with this device, then + * proceed with the next one. + */ + osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID; + + } else { + if (uuid == Uuid::From16Bit(UUID_PROTOCOL_L2CAP)) { + if (!is_sdp_pbap_pce_disabled(bd_addr)) { + LOG_DEBUG("SDP search for PBAP Client "); + BTA_SdpSearch(bd_addr, Uuid::From16Bit(UUID_SERVCLASS_PBAP_PCE)); + } + } + bta_dm_search_cb.service_index++; + return; + } + } + + bta_dm_search_cb.service_index++; + } + + /* no more services to be discovered */ + if (bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) { + tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); + /* initialize the data structure */ + memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES)); + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.services = + bta_dm_search_cb.services_found; + p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; + strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, + bta_dm_get_remname(), BD_NAME_LEN + 1); + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* + * + * Function bta_dm_discover_next_device + * + * Description Starts discovery on the next device in Inquiry data base + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_discover_next_device(void) { + LOG_VERBOSE("bta_dm_discover_next_device"); + + /* searching next device on inquiry result */ + bta_dm_search_cb.p_btm_inq_info = get_btm_client_interface().db.BTM_InqDbNext( + bta_dm_search_cb.p_btm_inq_info); + if (bta_dm_search_cb.p_btm_inq_info != NULL) { + bta_dm_search_cb.name_discover_done = false; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_discover_device( + bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); + } else { + tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); + + /* no devices, search complete */ + bta_dm_search_cb.services = 0; + + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* + * + * Function bta_dm_discover_device + * + * Description Starts name and service discovery on the device + * + * Returns void + * + ******************************************************************************/ +static tBT_TRANSPORT bta_dm_determine_discovery_transport( + const RawAddress& remote_bd_addr) { + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + if (bta_dm_search_cb.transport == BT_TRANSPORT_AUTO) { + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; + + get_btm_client_interface().peer.BTM_ReadDevInfo(remote_bd_addr, &dev_type, + &addr_type); + if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM) { + transport = BT_TRANSPORT_LE; + } else if (dev_type == BT_DEVICE_TYPE_DUMO) { + if (get_btm_client_interface().peer.BTM_IsAclConnectionUp( + remote_bd_addr, BT_TRANSPORT_BR_EDR)) { + transport = BT_TRANSPORT_BR_EDR; + } else if (get_btm_client_interface().peer.BTM_IsAclConnectionUp( + remote_bd_addr, BT_TRANSPORT_LE)) { + transport = BT_TRANSPORT_LE; + } + } + } else { + transport = bta_dm_search_cb.transport; + } + return transport; +} + +static void bta_dm_discover_device(const RawAddress& remote_bd_addr) { + const tBT_TRANSPORT transport = + bta_dm_determine_discovery_transport(remote_bd_addr); + + VLOG(1) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(remote_bd_addr); + + bta_dm_search_cb.peer_bdaddr = remote_bd_addr; + + LOG_VERBOSE( + "%s name_discover_done = %d p_btm_inq_info 0x%p state = %d, transport=%d", + __func__, bta_dm_search_cb.name_discover_done, + bta_dm_search_cb.p_btm_inq_info, bta_dm_search_get_state(), transport); + + if (bta_dm_search_cb.p_btm_inq_info) { + LOG_VERBOSE("%s appl_knows_rem_name %d", __func__, + bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name); + } + if (((bta_dm_search_cb.p_btm_inq_info) && + (bta_dm_search_cb.p_btm_inq_info->results.device_type == + BT_DEVICE_TYPE_BLE) && + (bta_dm_search_get_state() == BTA_DM_SEARCH_ACTIVE)) || + (transport == BT_TRANSPORT_LE && + interop_match_addr(INTEROP_DISABLE_NAME_REQUEST, + &bta_dm_search_cb.peer_bdaddr))) { + /* Do not perform RNR for LE devices at inquiry complete*/ + bta_dm_search_cb.name_discover_done = true; + } + // If we already have the name we can skip getting the name + if (BTM_IsRemoteNameKnown(remote_bd_addr, transport) && + bluetooth::common::init_flags::sdp_skip_rnr_if_known_is_enabled()) { + LOG_DEBUG("Security record already known skipping read remote name peer:%s", + ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); + bta_dm_search_cb.name_discover_done = true; + } + + /* if name discovery is not done and application needs remote name */ + if ((!bta_dm_search_cb.name_discover_done) && + ((bta_dm_search_cb.p_btm_inq_info == NULL) || + (bta_dm_search_cb.p_btm_inq_info && + (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) { + if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr, + transport)) { + if (bta_dm_search_get_state() != BTA_DM_DISCOVER_ACTIVE) { + LOG_DEBUG("Reset transport state for next discovery"); + bta_dm_search_cb.transport = BT_TRANSPORT_AUTO; + } + BTM_LogHistory(kBtmLogTag, bta_dm_search_cb.peer_bdaddr, + "Read remote name", + base::StringPrintf("Transport:%s", + bt_transport_text(transport).c_str())); + return; + } else { + LOG_ERROR("Unable to start read remote device name"); + } + + /* starting name discovery failed */ + bta_dm_search_cb.name_discover_done = true; + } + + /* Reset transport state for next discovery */ + bta_dm_search_cb.transport = BT_TRANSPORT_AUTO; + + bool sdp_disable = HID_HostSDPDisable(remote_bd_addr); + if (sdp_disable) + LOG_DEBUG("peer:%s with HIDSDPDisable attribute.", + ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); + + /* if application wants to discover service and HIDSDPDisable attribute is + false. + Classic mouses with this attribute should not start SDP here, because the + SDP has been done during bonding. SDP request here will interleave with + connections to the Control or Interrupt channels */ + if (bta_dm_search_cb.services && !sdp_disable) { + BTM_LogHistory(kBtmLogTag, remote_bd_addr, "Discovery started ", + base::StringPrintf("Transport:%s", + bt_transport_text(transport).c_str())); + + /* initialize variables */ + bta_dm_search_cb.service_index = 0; + bta_dm_search_cb.services_found = 0; + bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; + + /* if seaching with EIR is not completed */ + if (bta_dm_search_cb.services_to_search) { + /* check whether connection already exists to the device + if connection exists, we don't have to wait for ACL + link to go down to start search on next device */ + if (transport == BT_TRANSPORT_BR_EDR) { + if (get_btm_client_interface().peer.BTM_IsAclConnectionUp( + bta_dm_search_cb.peer_bdaddr, BT_TRANSPORT_BR_EDR)) + bta_dm_search_cb.wait_disc = false; + else + bta_dm_search_cb.wait_disc = true; + } + if (bta_dm_search_cb.p_btm_inq_info) { + LOG_VERBOSE( + "%s p_btm_inq_info 0x%p results.device_type 0x%x " + "services_to_search 0x%x", + __func__, bta_dm_search_cb.p_btm_inq_info, + bta_dm_search_cb.p_btm_inq_info->results.device_type, + bta_dm_search_cb.services_to_search); + } + + if (transport == BT_TRANSPORT_LE) { + if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) { + LOG_INFO("bta_dm_discovery: starting GATT discovery on %s", + ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr)); + // set the raw data buffer here + memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); + /* start GATT for service discovery */ + btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr); + return; + } + } else { + LOG_INFO("bta_dm_discovery: starting SDP discovery on %s", + ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr)); + bta_dm_search_cb.sdp_results = false; + bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); + return; + } + } + } + + /* name discovery and service discovery are done for this device */ + tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + /* initialize the data structure */ + memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES)); + p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; + strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, + bta_dm_get_remname(), BD_NAME_LEN + 1); + + bta_sys_sendmsg(p_msg); +} + +/******************************************************************************* + * + * Function bta_dm_sdp_callback + * + * Description Callback from sdp with discovery status + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_sdp_callback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS sdp_status) { + tBTA_DM_SDP_RESULT* p_msg = + (tBTA_DM_SDP_RESULT*)osi_malloc(sizeof(tBTA_DM_SDP_RESULT)); + + p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT; + p_msg->sdp_result = sdp_status; + + bta_sys_sendmsg(p_msg); +} + +/******************************************************************************* + * + * Function bta_dm_inq_results_cb + * + * Description Inquiry results callback from BTM + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, + uint16_t eir_len) { + tBTA_DM_SEARCH result; + tBTM_INQ_INFO* p_inq_info; + uint16_t service_class; + + result.inq_res.bd_addr = p_inq->remote_bd_addr; + + // Pass the original address to GattService#onScanResult + result.inq_res.original_bda = p_inq->original_bda; + + memcpy(result.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN); + BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class); + result.inq_res.is_limited = + (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? true : false; + result.inq_res.rssi = p_inq->rssi; + + result.inq_res.ble_addr_type = p_inq->ble_addr_type; + result.inq_res.inq_result_type = p_inq->inq_result_type; + result.inq_res.device_type = p_inq->device_type; + result.inq_res.flag = p_inq->flag; + result.inq_res.include_rsi = p_inq->include_rsi; + result.inq_res.clock_offset = p_inq->clock_offset; + + /* application will parse EIR to find out remote device name */ + result.inq_res.p_eir = const_cast(p_eir); + result.inq_res.eir_len = eir_len; + + result.inq_res.ble_evt_type = p_inq->ble_evt_type; + + p_inq_info = + get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr); + if (p_inq_info != NULL) { + /* initialize remt_name_not_required to false so that we get the name by + * default */ + result.inq_res.remt_name_not_required = false; + } + + if (bta_dm_search_cb.p_search_cback) + bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result); + + if (p_inq_info) { + /* application indicates if it knows the remote name, inside the callback + copy that to the inquiry data base*/ + if (result.inq_res.remt_name_not_required) + p_inq_info->appl_knows_rem_name = true; + } +} + +/******************************************************************************* + * + * Function bta_dm_inq_cmpl_cb + * + * Description Inquiry complete callback from BTM + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_inq_cmpl_cb(void* p_result) { + LOG_VERBOSE("%s", __func__); + + bta_dm_inq_cmpl(((tBTM_INQUIRY_CMPL*)p_result)->num_resp); +} + +/******************************************************************************* + * + * Function bta_dm_service_search_remname_cback + * + * Description Remote name call back from BTM during service discovery + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_service_search_remname_cback(const RawAddress& bd_addr, + UNUSED_ATTR DEV_CLASS dc, + tBTM_BD_NAME bd_name) { + tBTM_REMOTE_DEV_NAME rem_name = {}; + tBTM_STATUS btm_status; + + LOG_VERBOSE("%s name=<%s>", __func__, bd_name); + + /* if this is what we are looking for */ + if (bta_dm_search_cb.peer_bdaddr == bd_addr) { + rem_name.bd_addr = bd_addr; + rem_name.length = strlcpy((char*)rem_name.remote_bd_name, (char*)bd_name, + BD_NAME_LEN + 1); + if (rem_name.length > BD_NAME_LEN) { + rem_name.length = BD_NAME_LEN; + } + rem_name.status = BTM_SUCCESS; + rem_name.hci_status = HCI_SUCCESS; + bta_dm_remname_cback(&rem_name); + } else { + /* get name of device */ + btm_status = get_btm_client_interface().peer.BTM_ReadRemoteDeviceName( + bta_dm_search_cb.peer_bdaddr, bta_dm_remname_cback, + BT_TRANSPORT_BR_EDR); + if (btm_status == BTM_BUSY) { + /* wait for next chance(notification of remote name discovery done) */ + LOG_VERBOSE("%s: BTM_ReadRemoteDeviceName is busy", __func__); + } else if (btm_status != BTM_CMD_STARTED) { + /* if failed to start getting remote name then continue */ + LOG_WARN("%s: BTM_ReadRemoteDeviceName returns 0x%02X", __func__, + btm_status); + + // needed so our response is not ignored, since this corresponds to the + // actual peer_bdaddr + rem_name.bd_addr = bta_dm_search_cb.peer_bdaddr; + rem_name.length = 0; + rem_name.remote_bd_name[0] = 0; + rem_name.status = btm_status; + rem_name.hci_status = HCI_SUCCESS; + bta_dm_remname_cback(&rem_name); + } + } +} + +/******************************************************************************* + * + * Function bta_dm_remname_cback + * + * Description Remote name complete call back from BTM + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p_remote_name) { + CHECK(p_remote_name != nullptr); + + LOG_INFO( + "Remote name request complete peer:%s btm_status:%s hci_status:%s " + "name[0]:%c length:%hu", + ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr), + btm_status_text(p_remote_name->status).c_str(), + hci_error_code_text(p_remote_name->hci_status).c_str(), + p_remote_name->remote_bd_name[0], p_remote_name->length); + + if (bta_dm_search_cb.peer_bdaddr == p_remote_name->bd_addr) { + get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); + } else { + // if we got a different response, maybe ignore it + // we will have made a request directly from BTM_ReadRemoteDeviceName so we + // expect a dedicated response for us + if (p_remote_name->hci_status == HCI_ERR_CONNECTION_EXISTS) { + get_btm_client_interface().security.BTM_SecDeleteRmtNameNotifyCallback( + &bta_dm_service_search_remname_cback); + LOG_INFO( + "Assume command failed due to disconnection hci_status:%s peer:%s", + hci_error_code_text(p_remote_name->hci_status).c_str(), + ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr)); + } else { + LOG_INFO( + "Ignored remote name response for the wrong address exp:%s act:%s", + ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr), + ADDRESS_TO_LOGGABLE_CSTR(p_remote_name->bd_addr)); + return; + } + } + + /* remote name discovery is done but it could be failed */ + bta_dm_search_cb.name_discover_done = true; + strlcpy((char*)bta_dm_search_cb.peer_name, + (char*)p_remote_name->remote_bd_name, BD_NAME_LEN + 1); + + if (bta_dm_search_cb.transport == BT_TRANSPORT_LE) { + GAP_BleReadPeerPrefConnParams(bta_dm_search_cb.peer_bdaddr); + } + + tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); + *p_msg = { + .remote_name_msg = + { + // tBTA_DM_REMOTE_NAME + .hdr = + { + .event = BTA_DM_REMT_NAME_EVT, + .len = 0, + .offset = 0, + .layer_specific = 0, + }, + .bd_addr = bta_dm_search_cb.peer_bdaddr, + .bd_name = {}, + .hci_status = p_remote_name->hci_status, + }, + }; + bd_name_copy(p_msg->remote_name_msg.bd_name, p_remote_name->remote_bd_name); + bta_sys_sendmsg(p_msg); +} + +/******************************************************************************* + * + * Function bta_dm_get_remname + * + * Description Returns a pointer to the remote name stored in the DM + * control block if it exists, or from the BTM memory. + * + * Returns char * - Pointer to the remote device name + ******************************************************************************/ +const char* bta_dm_get_remname(void) { + const char* p_name = (const char*)bta_dm_search_cb.peer_name; + + /* If the name isn't already stored, try retrieving from BTM */ + if (*p_name == '\0') { + const char* p_temp = get_btm_client_interface().security.BTM_SecReadDevName( + bta_dm_search_cb.peer_bdaddr); + if (p_temp != NULL) p_name = (const char*)p_temp; + } + + return p_name; +} + +/******************************************************************************* + * + * Function bta_dm_observe_results_cb + * + * Description Callback for BLE Observe result + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, + const uint8_t* p_eir, uint16_t eir_len) { + tBTA_DM_SEARCH result; + tBTM_INQ_INFO* p_inq_info; + LOG_VERBOSE("bta_dm_observe_results_cb"); + + result.inq_res.bd_addr = p_inq->remote_bd_addr; + result.inq_res.original_bda = p_inq->original_bda; + result.inq_res.rssi = p_inq->rssi; + result.inq_res.ble_addr_type = p_inq->ble_addr_type; + result.inq_res.inq_result_type = p_inq->inq_result_type; + result.inq_res.device_type = p_inq->device_type; + result.inq_res.flag = p_inq->flag; + result.inq_res.ble_evt_type = p_inq->ble_evt_type; + result.inq_res.ble_primary_phy = p_inq->ble_primary_phy; + result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy; + result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid; + result.inq_res.ble_tx_power = p_inq->ble_tx_power; + result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int; + + /* application will parse EIR to find out remote device name */ + result.inq_res.p_eir = const_cast(p_eir); + result.inq_res.eir_len = eir_len; + + p_inq_info = + get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr); + if (p_inq_info != NULL) { + /* initialize remt_name_not_required to false so that we get the name by + * default */ + result.inq_res.remt_name_not_required = false; + } + + if (bta_dm_search_cb.p_scan_cback) + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_RES_EVT, &result); + + if (p_inq_info) { + /* application indicates if it knows the remote name, inside the callback + copy that to the inquiry data base*/ + if (result.inq_res.remt_name_not_required) + p_inq_info->appl_knows_rem_name = true; + } +} + +/******************************************************************************* + * + * Function bta_dm_opportunistic_observe_results_cb + * + * Description Callback for BLE Observe result + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_opportunistic_observe_results_cb(tBTM_INQ_RESULTS* p_inq, + const uint8_t* p_eir, + uint16_t eir_len) { + tBTA_DM_SEARCH result; + tBTM_INQ_INFO* p_inq_info; + + result.inq_res.bd_addr = p_inq->remote_bd_addr; + result.inq_res.rssi = p_inq->rssi; + result.inq_res.ble_addr_type = p_inq->ble_addr_type; + result.inq_res.inq_result_type = p_inq->inq_result_type; + result.inq_res.device_type = p_inq->device_type; + result.inq_res.flag = p_inq->flag; + result.inq_res.ble_evt_type = p_inq->ble_evt_type; + result.inq_res.ble_primary_phy = p_inq->ble_primary_phy; + result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy; + result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid; + result.inq_res.ble_tx_power = p_inq->ble_tx_power; + result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int; + + /* application will parse EIR to find out remote device name */ + result.inq_res.p_eir = const_cast(p_eir); + result.inq_res.eir_len = eir_len; + + p_inq_info = + get_btm_client_interface().db.BTM_InqDbRead(p_inq->remote_bd_addr); + if (p_inq_info != NULL) { + /* initialize remt_name_not_required to false so that we get the name by + * default */ + result.inq_res.remt_name_not_required = false; + } + + if (bta_dm_search_cb.p_csis_scan_cback) + bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_RES_EVT, &result); + + if (p_inq_info) { + /* application indicates if it knows the remote name, inside the callback + copy that to the inquiry data base*/ + if (result.inq_res.remt_name_not_required) + p_inq_info->appl_knows_rem_name = true; + } +} + +/******************************************************************************* + * + * Function bta_dm_observe_cmpl_cb + * + * Description Callback for BLE Observe complete + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_observe_cmpl_cb(void* p_result) { + tBTA_DM_SEARCH data; + + LOG_VERBOSE("bta_dm_observe_cmpl_cb"); + + data.inq_cmpl.num_resps = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp; + if (bta_dm_search_cb.p_scan_cback) { + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); + } + if (bta_dm_search_cb.p_csis_scan_cback) { + bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); + } +} + +static void bta_dm_start_scan(uint8_t duration_sec, + bool low_latency_scan = false) { + tBTM_STATUS status = get_btm_client_interface().ble.BTM_BleObserve( + true, duration_sec, bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb, + low_latency_scan); + + if (status != BTM_CMD_STARTED) { + tBTA_DM_SEARCH data = { + .inq_cmpl = + { + .num_resps = 0, + }, + }; + LOG_WARN(" %s BTM_BleObserve failed. status %d", __func__, status); + if (bta_dm_search_cb.p_scan_cback) { + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); + } + if (bta_dm_search_cb.p_csis_scan_cback) { + bta_dm_search_cb.p_csis_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); + } + } +} + +void bta_dm_ble_observe(bool start, uint8_t duration, + tBTA_DM_SEARCH_CBACK* p_cback) { + if (!start) { + bta_dm_search_cb.p_scan_cback = NULL; + get_btm_client_interface().ble.BTM_BleObserve(false, 0, NULL, NULL, false); + return; + } + + /*Save the callback to be called when a scan results are available */ + bta_dm_search_cb.p_scan_cback = p_cback; + bta_dm_start_scan(duration); +} + +void bta_dm_ble_scan(bool start, uint8_t duration_sec, + bool low_latency_scan = false) { + /* Start or stop only if there is no active main scanner */ + if (bta_dm_search_cb.p_scan_cback != NULL) return; + + if (!start) { + get_btm_client_interface().ble.BTM_BleObserve(false, 0, NULL, NULL, false); + return; + } + + bta_dm_start_scan(duration_sec, low_latency_scan); +} + +void bta_dm_ble_csis_observe(bool observe, tBTA_DM_SEARCH_CBACK* p_cback) { + if (!observe) { + bta_dm_search_cb.p_csis_scan_cback = NULL; + BTM_BleOpportunisticObserve(false, NULL); + return; + } + + /* Save the callback to be called when a scan results are available */ + bta_dm_search_cb.p_csis_scan_cback = p_cback; + BTM_BleOpportunisticObserve(true, bta_dm_opportunistic_observe_results_cb); +} + +#ifndef BTA_DM_GATT_CLOSE_DELAY_TOUT +#define BTA_DM_GATT_CLOSE_DELAY_TOUT 1000 +#endif + +/******************************************************************************* + * + * Function bta_dm_gattc_register + * + * Description Register with GATTC in DM if BLE is needed. + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_gattc_register(void) { + if (bta_dm_search_cb.client_if != BTA_GATTS_INVALID_IF) { + // Already registered + return; + } + get_gatt_interface().BTA_GATTC_AppRegister( + bta_dm_gattc_callback, base::Bind([](uint8_t client_id, uint8_t status) { + tGATT_STATUS gatt_status = static_cast(status); + disc_gatt_history_.Push(base::StringPrintf( + "%-32s client_id:%hu status:%s", "GATTC_RegisteredCallback", + client_id, gatt_status_text(gatt_status).c_str())); + if (static_cast(status) == GATT_SUCCESS) { + LOG_INFO( + "Registered device discovery search gatt client tGATT_IF:%hhu", + client_id); + bta_dm_search_cb.client_if = client_id; + } else { + LOG_WARN( + "Failed to register device discovery search gatt client" + " gatt_status:%hhu previous tGATT_IF:%hhu", + bta_dm_search_cb.client_if, status); + bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF; + } + }), + false); +} + +/******************************************************************************* + * + * Function bta_dm_gatt_disc_complete + * + * Description This function process the GATT service search complete. + * + * Parameters: + * + ******************************************************************************/ +static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status) { + LOG_VERBOSE("%s conn_id = %d", __func__, conn_id); + + tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); + + /* no more services to be discovered */ + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = + (status == GATT_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE; + LOG_VERBOSE("%s service found: 0x%08x", __func__, + bta_dm_search_cb.services_found); + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + p_msg->disc_result.result.disc_res.num_uuids = 0; + p_msg->disc_result.result.disc_res.p_uuid_list = NULL; + p_msg->disc_result.result.disc_res.bd_addr = bta_dm_search_cb.peer_bdaddr; + strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name, + bta_dm_get_remname(), BD_NAME_LEN + 1); + + p_msg->disc_result.result.disc_res.device_type |= BT_DEVICE_TYPE_BLE; + + bta_sys_sendmsg(p_msg); + + if (conn_id != GATT_INVALID_CONN_ID) { + bta_dm_search_cb.pending_close_bda = bta_dm_search_cb.peer_bdaddr; + // Gatt will be close immediately if bluetooth.gatt.delay_close.enabled is + // set to false. If property is true / unset there will be a delay + if (bta_dm_search_cb.gatt_close_timer != nullptr) { + /* start a GATT channel close delay timer */ + bta_sys_start_timer(bta_dm_search_cb.gatt_close_timer, + BTA_DM_GATT_CLOSE_DELAY_TOUT, + BTA_DM_DISC_CLOSE_TOUT_EVT, 0); + } else { + p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG)); + p_msg->hdr.event = BTA_DM_DISC_CLOSE_TOUT_EVT; + p_msg->hdr.layer_specific = 0; + bta_sys_sendmsg(p_msg); + } + } else { + if (bluetooth::common::init_flags:: + bta_dm_clear_conn_id_on_client_close_is_enabled()) { + bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; + } + } +} + +/******************************************************************************* + * + * Function bta_dm_close_gatt_conn + * + * Description This function close the GATT connection after delay + *timeout. + * + * Parameters: + * + ******************************************************************************/ +static void bta_dm_close_gatt_conn(UNUSED_ATTR tBTA_DM_MSG* p_data) { + if (bta_dm_search_cb.conn_id != GATT_INVALID_CONN_ID) + BTA_GATTC_Close(bta_dm_search_cb.conn_id); + + bta_dm_search_cb.pending_close_bda = RawAddress::kEmpty; + bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; +} +/******************************************************************************* + * + * Function btm_dm_start_gatt_discovery + * + * Description This is GATT initiate the service search by open a GATT + * connection first. + * + * Parameters: + * + ******************************************************************************/ +static void btm_dm_start_gatt_discovery(const RawAddress& bd_addr) { + constexpr bool kUseOpportunistic = true; + + bta_dm_search_cb.gatt_disc_active = true; + + /* connection is already open */ + if (bta_dm_search_cb.pending_close_bda == bd_addr && + bta_dm_search_cb.conn_id != GATT_INVALID_CONN_ID) { + bta_dm_search_cb.pending_close_bda = RawAddress::kEmpty; + alarm_cancel(bta_dm_search_cb.gatt_close_timer); + get_gatt_interface().BTA_GATTC_ServiceSearchRequest( + bta_dm_search_cb.conn_id, nullptr); + } else { + if (get_btm_client_interface().peer.BTM_IsAclConnectionUp( + bd_addr, BT_TRANSPORT_LE)) { + LOG_DEBUG( + "Use existing gatt client connection for discovery peer:%s " + "transport:%s opportunistic:%c", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + bt_transport_text(BT_TRANSPORT_LE).c_str(), + (kUseOpportunistic) ? 'T' : 'F'); + get_gatt_interface().BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, + BTM_BLE_DIRECT_CONNECTION, + kUseOpportunistic); + } else { + LOG_DEBUG( + "Opening new gatt client connection for discovery peer:%s " + "transport:%s opportunistic:%c", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + bt_transport_text(BT_TRANSPORT_LE).c_str(), + (!kUseOpportunistic) ? 'T' : 'F'); + get_gatt_interface().BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, + BTM_BLE_DIRECT_CONNECTION, + !kUseOpportunistic); + } + } +} + +/******************************************************************************* + * + * Function bta_dm_proc_open_evt + * + * Description process BTA_GATTC_OPEN_EVT in DM. + * + * Parameters: + * + ******************************************************************************/ +static void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) { + VLOG(1) << "DM Search state= " << bta_dm_search_get_state() + << " search_cb.peer_dbaddr:" << bta_dm_search_cb.peer_bdaddr + << " connected_bda=" << p_data->remote_bda.address; + + LOG_DEBUG("BTA_GATTC_OPEN_EVT conn_id = %d client_if=%d status = %d", + p_data->conn_id, p_data->client_if, p_data->status); + + disc_gatt_history_.Push(base::StringPrintf( + "%-32s bd_addr:%s conn_id:%hu client_if:%hu event:%s", + "GATTC_EventCallback", ADDRESS_TO_LOGGABLE_CSTR(p_data->remote_bda), + p_data->conn_id, p_data->client_if, + gatt_client_event_text(BTA_GATTC_OPEN_EVT).c_str())); + + bta_dm_search_cb.conn_id = p_data->conn_id; + + if (p_data->status == GATT_SUCCESS) { + get_gatt_interface().BTA_GATTC_ServiceSearchRequest(p_data->conn_id, + nullptr); + } else { + bta_dm_gatt_disc_complete(GATT_INVALID_CONN_ID, p_data->status); + } +} + +void bta_dm_proc_close_evt(const tBTA_GATTC_CLOSE& close) { + LOG_INFO("Gatt connection closed peer:%s reason:%s", + ADDRESS_TO_LOGGABLE_CSTR(close.remote_bda), + gatt_disconnection_reason_text(close.reason).c_str()); + + disc_gatt_history_.Push(base::StringPrintf( + "%-32s bd_addr:%s client_if:%hu status:%s event:%s", + "GATTC_EventCallback", ADDRESS_TO_LOGGABLE_CSTR(close.remote_bda), + close.client_if, gatt_status_text(close.status).c_str(), + gatt_client_event_text(BTA_GATTC_CLOSE_EVT).c_str())); + + if (close.remote_bda == bta_dm_search_cb.peer_bdaddr) { + if (bluetooth::common::init_flags:: + bta_dm_clear_conn_id_on_client_close_is_enabled()) { + LOG_DEBUG("Clearing connection id on client close"); + bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; + } + } else { + LOG_WARN("Received close event for unknown peer:%s", + ADDRESS_TO_LOGGABLE_CSTR(close.remote_bda)); + } + + /* in case of disconnect before search is completed */ + if ((bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) && + (bta_dm_search_cb.state != BTA_DM_SEARCH_ACTIVE) && + close.remote_bda == bta_dm_search_cb.peer_bdaddr) { + bta_dm_gatt_disc_complete((uint16_t)GATT_INVALID_CONN_ID, + (tGATT_STATUS)GATT_ERROR); + } +} + +/******************************************************************************* + * + * Function bta_dm_gattc_callback + * + * Description This is GATT client callback function used in DM. + * + * Parameters: + * + ******************************************************************************/ +static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) { + LOG_VERBOSE("bta_dm_gattc_callback event = %d", event); + + switch (event) { + case BTA_GATTC_OPEN_EVT: + bta_dm_proc_open_evt(&p_data->open); + break; + + case BTA_GATTC_SEARCH_CMPL_EVT: + switch (bta_dm_search_get_state()) { + case BTA_DM_SEARCH_IDLE: + break; + case BTA_DM_SEARCH_ACTIVE: + case BTA_DM_SEARCH_CANCELLING: + case BTA_DM_DISCOVER_ACTIVE: + bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id, + p_data->search_cmpl.status); + break; + } + disc_gatt_history_.Push(base::StringPrintf( + "%-32s conn_id:%hu status:%s", "GATTC_EventCallback", + p_data->search_cmpl.conn_id, + gatt_status_text(p_data->search_cmpl.status).c_str())); + break; + + case BTA_GATTC_CLOSE_EVT: + LOG_INFO("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason); + + if (p_data->close.remote_bda == bta_dm_search_cb.peer_bdaddr) { + if (bluetooth::common::init_flags:: + bta_dm_clear_conn_id_on_client_close_is_enabled()) { + bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; + } + } + + switch (bta_dm_search_get_state()) { + case BTA_DM_SEARCH_IDLE: + case BTA_DM_SEARCH_ACTIVE: + break; + + case BTA_DM_SEARCH_CANCELLING: + case BTA_DM_DISCOVER_ACTIVE: + /* in case of disconnect before search is completed */ + if (p_data->close.remote_bda == bta_dm_search_cb.peer_bdaddr) { + bta_dm_gatt_disc_complete((uint16_t)GATT_INVALID_CONN_ID, + (tGATT_STATUS)GATT_ERROR); + } + } + break; + + case BTA_GATTC_ACL_EVT: + case BTA_GATTC_CANCEL_OPEN_EVT: + case BTA_GATTC_CFG_MTU_EVT: + case BTA_GATTC_CONGEST_EVT: + case BTA_GATTC_CONN_UPDATE_EVT: + case BTA_GATTC_DEREG_EVT: + case BTA_GATTC_ENC_CMPL_CB_EVT: + case BTA_GATTC_EXEC_EVT: + case BTA_GATTC_NOTIF_EVT: + case BTA_GATTC_PHY_UPDATE_EVT: + case BTA_GATTC_SEARCH_RES_EVT: + case BTA_GATTC_SRVC_CHG_EVT: + case BTA_GATTC_SRVC_DISC_DONE_EVT: + case BTA_GATTC_SUBRATE_CHG_EVT: + disc_gatt_history_.Push( + base::StringPrintf("%-32s event:%s", "GATTC_EventCallback", + gatt_client_event_text(event).c_str())); + break; + } +} + +namespace bluetooth { +namespace legacy { +namespace testing { + +void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p) { + ::bta_dm_remname_cback(p); +} + +tBT_TRANSPORT bta_dm_determine_discovery_transport(const RawAddress& bd_addr) { + return ::bta_dm_determine_discovery_transport(bd_addr); +} + +void bta_dm_remote_name_cmpl(const tBTA_DM_MSG* p_data) { + ::bta_dm_remote_name_cmpl(p_data); +} + +void bta_dm_sdp_result(tBTA_DM_MSG* p_data) { ::bta_dm_sdp_result(p_data); } + +} // namespace testing +} // namespace legacy +} // namespace bluetooth + +namespace { +constexpr size_t kSearchStateHistorySize = 50; +constexpr char kTimeFormatString[] = "%Y-%m-%d %H:%M:%S"; + +constexpr unsigned MillisPerSecond = 1000; +std::string EpochMillisToString(long long time_ms) { + time_t time_sec = time_ms / MillisPerSecond; + struct tm tm; + localtime_r(&time_sec, &tm); + std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm); + return base::StringPrintf( + "%s.%03u", s.c_str(), + static_cast(time_ms % MillisPerSecond)); +} + +} // namespace + +struct tSEARCH_STATE_HISTORY { + const tBTA_DM_STATE state; + const tBTA_DM_EVT event; + std::string ToString() const { + return base::StringPrintf("state:%25s event:%s", + bta_dm_state_text(state).c_str(), + bta_dm_event_text(event).c_str()); + } +}; + +bluetooth::common::TimestampedCircularBuffer + search_state_history_(kSearchStateHistorySize); + +/******************************************************************************* + * + * Function bta_dm_sm_search_disable + * + * Description unregister BTA SEARCH DM + * + * + * Returns void + * + ******************************************************************************/ +void bta_dm_search_sm_disable() { bta_sys_deregister(BTA_ID_DM_SEARCH); } + +/******************************************************************************* + * + * Function bta_dm_search_sm_execute + * + * Description State machine event handling function for DM + * + * + * Returns void + * + ******************************************************************************/ +bool bta_dm_search_sm_execute(const BT_HDR_RIGID* p_msg) { + const tBTA_DM_EVT event = static_cast(p_msg->event); + LOG_INFO("state:%s, event:%s[0x%x]", + bta_dm_state_text(bta_dm_search_get_state()).c_str(), + bta_dm_event_text(event).c_str(), event); + search_state_history_.Push({ + .state = bta_dm_search_get_state(), + .event = event, + }); + tBTA_DM_MSG* message = (tBTA_DM_MSG*)p_msg; + switch (bta_dm_search_get_state()) { + case BTA_DM_SEARCH_IDLE: + switch (p_msg->event) { + case BTA_DM_API_SEARCH_EVT: + bta_dm_search_set_state(BTA_DM_SEARCH_ACTIVE); + bta_dm_search_start(message); + break; + case BTA_DM_API_DISCOVER_EVT: + bta_dm_search_set_state(BTA_DM_DISCOVER_ACTIVE); + bta_dm_discover(message); + break; + case BTA_DM_API_SEARCH_CANCEL_EVT: + bta_dm_search_clear_queue(); + bta_dm_search_cancel_notify(); + break; + case BTA_DM_SDP_RESULT_EVT: + bta_dm_free_sdp_db(); + break; + case BTA_DM_DISC_CLOSE_TOUT_EVT: + bta_dm_close_gatt_conn(message); + break; + default: + LOG_INFO("Received unexpected event %s[0x%x] in state %s", + bta_dm_event_text(event).c_str(), event, + bta_dm_state_text(bta_dm_search_get_state()).c_str()); + } + break; + case BTA_DM_SEARCH_ACTIVE: + switch (p_msg->event) { + case BTA_DM_REMT_NAME_EVT: + bta_dm_remote_name_cmpl(message); + break; + case BTA_DM_SEARCH_CMPL_EVT: + bta_dm_search_cmpl(); + break; + case BTA_DM_DISCOVERY_RESULT_EVT: + bta_dm_search_result(message); + break; + case BTA_DM_DISC_CLOSE_TOUT_EVT: + bta_dm_close_gatt_conn(message); + break; + case BTA_DM_API_DISCOVER_EVT: + bta_dm_queue_disc(message); + break; + case BTA_DM_API_SEARCH_CANCEL_EVT: + bta_dm_search_clear_queue(); + bta_dm_search_set_state(BTA_DM_SEARCH_CANCELLING); + bta_dm_search_cancel(); + break; + default: + LOG_INFO("Received unexpected event %s[0x%x] in state %s", + bta_dm_event_text(event).c_str(), event, + bta_dm_state_text(bta_dm_search_get_state()).c_str()); + } + break; + case BTA_DM_SEARCH_CANCELLING: + switch (p_msg->event) { + case BTA_DM_API_SEARCH_EVT: + bta_dm_queue_search(message); + break; + case BTA_DM_API_DISCOVER_EVT: + bta_dm_queue_disc(message); + break; + case BTA_DM_API_SEARCH_CANCEL_EVT: + bta_dm_search_clear_queue(); + bta_dm_search_cancel_notify(); + break; + case BTA_DM_SDP_RESULT_EVT: + case BTA_DM_REMT_NAME_EVT: + case BTA_DM_SEARCH_CMPL_EVT: + case BTA_DM_DISCOVERY_RESULT_EVT: + bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); + bta_dm_free_sdp_db(); + bta_dm_search_cancel_notify(); + bta_dm_execute_queued_request(); + break; + case BTA_DM_DISC_CLOSE_TOUT_EVT: + if (bluetooth::common::init_flags:: + bta_dm_clear_conn_id_on_client_close_is_enabled()) { + bta_dm_close_gatt_conn(message); + break; + } + [[fallthrough]]; + default: + LOG_INFO("Received unexpected event %s[0x%x] in state %s", + bta_dm_event_text(event).c_str(), event, + bta_dm_state_text(bta_dm_search_get_state()).c_str()); + } + break; + case BTA_DM_DISCOVER_ACTIVE: + switch (p_msg->event) { + case BTA_DM_REMT_NAME_EVT: + bta_dm_remote_name_cmpl(message); + break; + case BTA_DM_SDP_RESULT_EVT: + bta_dm_sdp_result(message); + break; + case BTA_DM_SEARCH_CMPL_EVT: + bta_dm_search_cmpl(); + break; + case BTA_DM_DISCOVERY_RESULT_EVT: + bta_dm_disc_result(message); + break; + case BTA_DM_API_SEARCH_EVT: + bta_dm_queue_search(message); + break; + case BTA_DM_API_DISCOVER_EVT: + bta_dm_queue_disc(message); + break; + case BTA_DM_API_SEARCH_CANCEL_EVT: + bta_dm_search_clear_queue(); + bta_dm_search_set_state(BTA_DM_SEARCH_CANCELLING); + bta_dm_search_cancel_notify(); + break; + case BTA_DM_DISC_CLOSE_TOUT_EVT: + if (bluetooth::common::init_flags:: + bta_dm_clear_conn_id_on_client_close_is_enabled()) { + bta_dm_close_gatt_conn(message); + break; + } + [[fallthrough]]; + default: + LOG_INFO("Received unexpected event %s[0x%x] in state %s", + bta_dm_event_text(event).c_str(), event, + bta_dm_state_text(bta_dm_search_get_state()).c_str()); + } + break; + } + return true; +} + +static void bta_dm_disc_init_search_cb(tBTA_DM_SEARCH_CB& bta_dm_search_cb) { + bta_dm_search_cb = {}; + bta_dm_search_cb.state = BTA_DM_SEARCH_IDLE; + bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; + bta_dm_search_cb.transport = BT_TRANSPORT_AUTO; +} + +static void bta_dm_disc_reset() { + alarm_free(bta_dm_search_cb.search_timer); + alarm_free(bta_dm_search_cb.gatt_close_timer); + osi_free_and_reset((void**)&bta_dm_search_cb.p_pending_search); + fixed_queue_free(bta_dm_search_cb.pending_discovery_queue, osi_free); + bta_dm_disc_init_search_cb(::bta_dm_search_cb); +} + +void bta_dm_disc_start(bool delay_close_gatt) { + bta_dm_disc_reset(); + bta_dm_search_cb.search_timer = alarm_new("bta_dm_search.search_timer"); + bta_dm_search_cb.gatt_close_timer = + delay_close_gatt ? alarm_new("bta_dm_search.gatt_close_timer") : nullptr; + bta_dm_search_cb.pending_discovery_queue = fixed_queue_new(SIZE_MAX); +} + +void bta_dm_disc_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + switch (transport) { + case BT_TRANSPORT_BR_EDR: + if (bta_dm_search_cb.wait_disc && + bta_dm_search_cb.peer_bdaddr == bd_addr) { + bta_dm_search_cb.wait_disc = false; + + if (bta_dm_search_cb.sdp_results) { + LOG_VERBOSE(" timer stopped "); + alarm_cancel(bta_dm_search_cb.search_timer); + bta_dm_disc_discover_next_device(); + } + } + break; + + case BT_TRANSPORT_LE: + default: + break; + } +} + +void bta_dm_disc_stop() { bta_dm_disc_reset(); } + +void bta_dm_disc_start_device_discovery(tBTA_DM_SEARCH_CBACK* p_cback) { + tBTA_DM_API_SEARCH* p_msg = + (tBTA_DM_API_SEARCH*)osi_calloc(sizeof(tBTA_DM_API_SEARCH)); + + p_msg->hdr.event = BTA_DM_API_SEARCH_EVT; + p_msg->p_cback = p_cback; + + bta_sys_sendmsg(p_msg); +} + +void bta_dm_disc_stop_device_discovery() { + tBTA_DM_API_DISCOVERY_CANCEL* p_msg = + (tBTA_DM_API_DISCOVERY_CANCEL*)osi_calloc( + sizeof(tBTA_DM_API_DISCOVERY_CANCEL)); + + p_msg->hdr.event = BTA_DM_API_SEARCH_CANCEL_EVT; + bta_sys_sendmsg(p_msg); +} + +void bta_dm_disc_start_service_discovery(tBTA_DM_SEARCH_CBACK* p_cback, + const RawAddress& bd_addr, + tBT_TRANSPORT transport) { + tBTA_DM_API_DISCOVER* p_msg = + (tBTA_DM_API_DISCOVER*)osi_calloc(sizeof(tBTA_DM_API_DISCOVER)); + + p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT; + p_msg->bd_addr = bd_addr; + p_msg->transport = transport; + p_msg->p_cback = p_cback; + + bta_sys_sendmsg(p_msg); +} + +void bta_dm_disc_stop_service_discovery(const RawAddress& bd_addr, + tBT_TRANSPORT transport) { + LOG_WARN("Stop service discovery not yet implemented for legacy module"); +} + +#define DUMPSYS_TAG "shim::legacy::bta::dm" +void DumpsysBtaDmDisc(int fd) { + auto copy = search_state_history_.Pull(); + LOG_DUMPSYS(fd, " last %zu search state transitions", copy.size()); + for (const auto& it : copy) { + LOG_DUMPSYS(fd, " %s %s", EpochMillisToString(it.timestamp).c_str(), + it.entry.ToString().c_str()); + } + LOG_DUMPSYS(fd, " current bta_dm_search_state:%s", + bta_dm_state_text(bta_dm_search_get_state()).c_str()); +} +#undef DUMPSYS_TAG + +namespace bluetooth { +namespace legacy { +namespace testing { + +void bta_dm_disc_init_search_cb(tBTA_DM_SEARCH_CB& bta_dm_search_cb) { + ::bta_dm_disc_init_search_cb(bta_dm_search_cb); +} +tBTA_DM_SEARCH_CB bta_dm_disc_get_search_cb() { + tBTA_DM_SEARCH_CB search_cb = {}; + ::bta_dm_disc_init_search_cb(search_cb); + return search_cb; +} +void bta_dm_disc_search_cb(const tBTA_DM_SEARCH_CB& search_cb) { + ::bta_dm_search_cb = search_cb; +} +const tBTA_DM_SEARCH_CB& bta_dm_disc_search_cb() { return ::bta_dm_search_cb; } +bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, + tBT_TRANSPORT transport) { + return ::bta_dm_read_remote_device_name(bd_addr, transport); +} +void bta_dm_discover_next_device() { ::bta_dm_discover_next_device(); } + +void bta_dm_execute_queued_request() { ::bta_dm_execute_queued_request(); } +void bta_dm_find_services(const RawAddress& bd_addr) { + ::bta_dm_find_services(bd_addr); +} +void bta_dm_inq_cmpl(uint8_t num) { ::bta_dm_inq_cmpl(num); } +void bta_dm_inq_cmpl_cb(void* p_result) { ::bta_dm_inq_cmpl_cb(p_result); } +void bta_dm_observe_cmpl_cb(void* p_result) { + ::bta_dm_observe_cmpl_cb(p_result); +} +void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, + uint16_t eir_len) { + ::bta_dm_observe_results_cb(p_inq, p_eir, eir_len); +} +void bta_dm_opportunistic_observe_results_cb(tBTM_INQ_RESULTS* p_inq, + const uint8_t* p_eir, + uint16_t eir_len) { + ::bta_dm_opportunistic_observe_results_cb(p_inq, p_eir, eir_len); +} +void bta_dm_queue_search(tBTA_DM_MSG* p_data) { ::bta_dm_queue_search(p_data); } +void bta_dm_search_result(tBTA_DM_MSG* p_data) { + ::bta_dm_search_result(p_data); +} +void bta_dm_search_timer_cback(void* data) { + ::bta_dm_search_timer_cback(data); +} + +void bta_dm_service_search_remname_cback(const RawAddress& bd_addr, + DEV_CLASS dc, tBTM_BD_NAME bd_name) { + ::bta_dm_service_search_remname_cback(bd_addr, dc, bd_name); +} + +void bta_dm_start_scan(uint8_t duration_sec, bool low_latency_scan = false) { + ::bta_dm_start_scan(duration_sec, low_latency_scan); +} + +void store_avrcp_profile_feature(tSDP_DISC_REC* sdp_rec) { + ::store_avrcp_profile_feature(sdp_rec); +} + +} // namespace testing +} // namespace legacy +} // namespace bluetooth diff --git a/system/bta/dm/bta_dm_disc.h b/system/bta/dm/bta_dm_disc.h new file mode 100644 index 0000000000000000000000000000000000000000..e010efddf5245374b566a64ffcb766b655f814c2 --- /dev/null +++ b/system/bta/dm/bta_dm_disc.h @@ -0,0 +1,71 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "bta/include/bta_api.h" // tBTA_DM_SEARCH_CBACK +#include "stack/include/bt_hdr.h" +#include "types/bt_transport.h" +#include "types/raw_address.h" + +// Bta module start and stop entry points +void bta_dm_disc_start(bool delay_close_gatt); +void bta_dm_disc_stop(); + +// Bta device discovery start and stop entry points +void bta_dm_disc_start_device_discovery(tBTA_DM_SEARCH_CBACK*); +void bta_dm_disc_stop_device_discovery(); + +// Bta service discovery start and stop entry points +void bta_dm_disc_start_service_discovery(tBTA_DM_SEARCH_CBACK*, + const RawAddress& bd_addr, + tBT_TRANSPORT transport); +void bta_dm_disc_stop_service_discovery(const RawAddress& bd_addr, + tBT_TRANSPORT transport); + +// Bta subsystem entrypoint and lifecycle +bool bta_dm_search_sm_execute(const BT_HDR_RIGID* p_msg); +void bta_dm_search_sm_disable(); +void bta_dm_disc_disable_search_and_disc(); +// Indication that an acl has gone down and to examine the current +// service discovery procedure, if any. +void bta_dm_disc_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport); + +// Return most recent remote name +const char* bta_dm_get_remname(void); + +// LE observe and scan interface +void bta_dm_ble_observe(bool start, uint8_t duration, + tBTA_DM_SEARCH_CBACK* p_cback); +void bta_dm_ble_scan(bool start, uint8_t duration_sec, bool low_latency_scan); +void bta_dm_ble_csis_observe(bool observe, tBTA_DM_SEARCH_CBACK* p_cback); + +// Checks if there is a device discovery request queued +bool bta_dm_is_search_request_queued(); + +// Proceed to execute service discovery on next device in queue +void bta_dm_disc_discover_next_device(); + +// GATT service discovery +void bta_dm_disc_gattc_register(); +void bta_dm_disc_gatt_cancel_open(const RawAddress& bd_addr); +void bta_dm_disc_gatt_refresh(const RawAddress& bd_addr); + +// Stop service discovery procedure, if any, for removed device +void bta_dm_disc_remove_device(const RawAddress& bd_addr); + +// Provide data for the dumpsys procedure +void DumpsysBtaDmDisc(int fd); diff --git a/system/bta/dm/bta_dm_disc_int.h b/system/bta/dm/bta_dm_disc_int.h new file mode 100644 index 0000000000000000000000000000000000000000..7a5c8a47bb93ac39df764211b123dff77006b956 --- /dev/null +++ b/system/bta/dm/bta_dm_disc_int.h @@ -0,0 +1,187 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +#include "bta/include/bta_api.h" +#include "bta/sys/bta_sys.h" +#include "macros.h" +#include "stack/btm/neighbor_inquiry.h" +#include "stack/include/bt_hdr.h" +#include "stack/include/sdp_status.h" +#include "stack/sdp/sdp_discovery_db.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id)) + +/* DM search events */ +typedef enum : uint16_t { + /* DM search API events */ + BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH), + BTA_DM_API_SEARCH_CANCEL_EVT, + BTA_DM_API_DISCOVER_EVT, + BTA_DM_INQUIRY_CMPL_EVT, + BTA_DM_REMT_NAME_EVT, + BTA_DM_SDP_RESULT_EVT, + BTA_DM_SEARCH_CMPL_EVT, + BTA_DM_DISCOVERY_RESULT_EVT, + BTA_DM_DISC_CLOSE_TOUT_EVT, +} tBTA_DM_EVT; + +inline std::string bta_dm_event_text(const tBTA_DM_EVT& event) { + switch (event) { + CASE_RETURN_TEXT(BTA_DM_API_SEARCH_EVT); + CASE_RETURN_TEXT(BTA_DM_API_SEARCH_CANCEL_EVT); + CASE_RETURN_TEXT(BTA_DM_API_DISCOVER_EVT); + CASE_RETURN_TEXT(BTA_DM_INQUIRY_CMPL_EVT); + CASE_RETURN_TEXT(BTA_DM_REMT_NAME_EVT); + CASE_RETURN_TEXT(BTA_DM_SDP_RESULT_EVT); + CASE_RETURN_TEXT(BTA_DM_SEARCH_CMPL_EVT); + CASE_RETURN_TEXT(BTA_DM_DISCOVERY_RESULT_EVT); + CASE_RETURN_TEXT(BTA_DM_DISC_CLOSE_TOUT_EVT); + default: + return base::StringPrintf("UNKNOWN[0x%04x]", event); + } +} + +/* data type for BTA_DM_API_SEARCH_EVT */ +typedef struct { + BT_HDR_RIGID hdr; + tBTA_SERVICE_MASK services; + tBTA_DM_SEARCH_CBACK* p_cback; +} tBTA_DM_API_SEARCH; + +/* data type for BTA_DM_API_DISCOVER_EVT */ +typedef struct { + BT_HDR_RIGID hdr; + RawAddress bd_addr; + tBTA_DM_SEARCH_CBACK* p_cback; + tBT_TRANSPORT transport; +} tBTA_DM_API_DISCOVER; + +typedef struct { + BT_HDR_RIGID hdr; +} tBTA_DM_API_DISCOVERY_CANCEL; + +typedef struct { + BT_HDR_RIGID hdr; + RawAddress bd_addr; + BD_NAME bd_name; /* Name of peer device. */ + tHCI_STATUS hci_status; +} tBTA_DM_REMOTE_NAME; + +/* data type for tBTA_DM_DISC_RESULT */ +typedef struct { + BT_HDR_RIGID hdr; + tBTA_DM_SEARCH result; +} tBTA_DM_DISC_RESULT; + +/* data type for BTA_DM_INQUIRY_CMPL_EVT */ +typedef struct { + BT_HDR_RIGID hdr; + uint8_t num; +} tBTA_DM_INQUIRY_CMPL; + +/* data type for BTA_DM_SDP_RESULT_EVT */ +typedef struct { + BT_HDR_RIGID hdr; + tSDP_RESULT sdp_result; +} tBTA_DM_SDP_RESULT; + +typedef struct { + BT_HDR_RIGID hdr; + bool enable; +} tBTA_DM_API_BLE_FEATURE; + +/* union of all data types */ +typedef union { + /* GKI event buffer header */ + BT_HDR_RIGID hdr; + + tBTA_DM_API_SEARCH search; + + tBTA_DM_API_DISCOVER discover; + + tBTA_DM_REMOTE_NAME remote_name_msg; + + tBTA_DM_DISC_RESULT disc_result; + + tBTA_DM_INQUIRY_CMPL inq_cmpl; + + tBTA_DM_SDP_RESULT sdp_event; + +} tBTA_DM_MSG; + +/* DM search state */ +typedef enum { + + BTA_DM_SEARCH_IDLE, + BTA_DM_SEARCH_ACTIVE, + BTA_DM_SEARCH_CANCELLING, + BTA_DM_DISCOVER_ACTIVE + +} tBTA_DM_STATE; + +inline std::string bta_dm_state_text(const tBTA_DM_STATE& state) { + switch (state) { + CASE_RETURN_TEXT(BTA_DM_SEARCH_IDLE); + CASE_RETURN_TEXT(BTA_DM_SEARCH_ACTIVE); + CASE_RETURN_TEXT(BTA_DM_SEARCH_CANCELLING); + CASE_RETURN_TEXT(BTA_DM_DISCOVER_ACTIVE); + default: + return base::StringPrintf("UNKNOWN[%d]", state); + } +} + +/* DM search control block */ +typedef struct { + tBTA_DM_SEARCH_CBACK* p_search_cback; + tBTM_INQ_INFO* p_btm_inq_info; + tBTA_SERVICE_MASK services; + tBTA_SERVICE_MASK services_to_search; + tBTA_SERVICE_MASK services_found; + tSDP_DISCOVERY_DB* p_sdp_db; + tBTA_DM_STATE state; + RawAddress peer_bdaddr; + bool name_discover_done; + BD_NAME peer_name; + alarm_t* search_timer; + uint8_t service_index; + tBTA_DM_MSG* p_pending_search; + fixed_queue_t* pending_discovery_queue; + bool wait_disc; + bool sdp_results; + bluetooth::Uuid uuid; + uint8_t peer_scn; + tBT_TRANSPORT transport; + tBTA_DM_SEARCH_CBACK* p_scan_cback; + tBTA_DM_SEARCH_CBACK* p_csis_scan_cback; + tGATT_IF client_if; + uint8_t uuid_to_search; + bool gatt_disc_active; + uint16_t conn_id; + alarm_t* gatt_close_timer; /* GATT channel close delay timer */ + RawAddress pending_close_bda; /* pending GATT channel remote device address */ + +} tBTA_DM_SEARCH_CB; + +extern const uint32_t bta_service_id_to_btm_srv_id_lkup_tbl[]; +extern const uint16_t bta_service_id_to_uuid_lkup_tbl[]; diff --git a/system/bta/dm/bta_dm_gatt_client.cc b/system/bta/dm/bta_dm_gatt_client.cc new file mode 100644 index 0000000000000000000000000000000000000000..29656ea0e0823bd62ef1cb8b840b6daee7fd5251 --- /dev/null +++ b/system/bta/dm/bta_dm_gatt_client.cc @@ -0,0 +1,137 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bta/dm/bta_dm_gatt_client.h" + +#include + +#include +#include +#include + +#include "bta/include/bta_gatt_api.h" +#include "gd/common/strings.h" +#include "main/shim/dumpsys.h" +#include "stack/btm/btm_int_types.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +namespace { +TimestampedStringCircularBuffer gatt_history_{50}; +constexpr char kTimeFormatString[] = "%Y-%m-%d %H:%M:%S"; + +constexpr unsigned MillisPerSecond = 1000; +std::string EpochMillisToString(long long time_ms) { + time_t time_sec = time_ms / MillisPerSecond; + struct tm tm; + localtime_r(&time_sec, &tm); + std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm); + return base::StringPrintf( + "%s.%03u", s.c_str(), + static_cast(time_ms % MillisPerSecond)); +} +} // namespace + +gatt_interface_t default_gatt_interface = { + .BTA_GATTC_CancelOpen = + [](tGATT_IF client_if, const RawAddress& remote_bda, bool is_direct) { + gatt_history_.Push(base::StringPrintf( + "%-32s bd_addr:%s client_if:%hu is_direct:%c", "GATTC_CancelOpen", + ADDRESS_TO_LOGGABLE_CSTR(remote_bda), client_if, + (is_direct) ? 'T' : 'F')); + BTA_GATTC_CancelOpen(client_if, remote_bda, is_direct); + }, + .BTA_GATTC_Refresh = + [](const RawAddress& remote_bda) { + gatt_history_.Push( + base::StringPrintf("%-32s bd_addr:%s", "GATTC_Refresh", + ADDRESS_TO_LOGGABLE_CSTR(remote_bda))); + BTA_GATTC_Refresh(remote_bda); + }, + .BTA_GATTC_GetGattDb = + [](uint16_t conn_id, uint16_t start_handle, uint16_t end_handle, + btgatt_db_element_t** db, int* count) { + gatt_history_.Push(base::StringPrintf( + "%-32s conn_id:%hu start_handle:%hu end:handle:%hu", + "GATTC_GetGattDb", conn_id, start_handle, end_handle)); + BTA_GATTC_GetGattDb(conn_id, start_handle, end_handle, db, count); + }, + .BTA_GATTC_AppRegister = + [](tBTA_GATTC_CBACK* p_client_cb, BtaAppRegisterCallback cb, + bool eatt_support) { + gatt_history_.Push(base::StringPrintf("%-32s eatt_support:%c", + "GATTC_AppRegister", + (eatt_support) ? 'T' : 'F')); + BTA_GATTC_AppRegister(p_client_cb, cb, eatt_support); + }, + .BTA_GATTC_Close = + [](uint16_t conn_id) { + gatt_history_.Push( + base::StringPrintf("%-32s conn_id:%hu", "GATTC_Close", conn_id)); + BTA_GATTC_Close(conn_id); + }, + .BTA_GATTC_ServiceSearchRequest = + [](uint16_t conn_id, const bluetooth::Uuid* p_srvc_uuid) { + gatt_history_.Push(base::StringPrintf( + "%-32s conn_id:%hu", "GATTC_ServiceSearchRequest", conn_id)); + BTA_GATTC_ServiceSearchRequest(conn_id, p_srvc_uuid); + }, + .BTA_GATTC_Open = + [](tGATT_IF client_if, const RawAddress& remote_bda, + tBTM_BLE_CONN_TYPE connection_type, bool opportunistic) { + gatt_history_.Push(base::StringPrintf( + "%-32s bd_addr:%s client_if:%hu type:0x%x opportunistic:%c", + "GATTC_Open", ADDRESS_TO_LOGGABLE_CSTR(remote_bda), client_if, + connection_type, (opportunistic) ? 'T' : 'F')); + BTA_GATTC_Open(client_if, remote_bda, connection_type, opportunistic); + }, +}; + +gatt_interface_t* gatt_interface = &default_gatt_interface; + +gatt_interface_t& get_gatt_interface() { return *gatt_interface; } + +void gatt_history_callback(const std::string& entry) { + gatt_history_.Push(entry); +} + +#define DUMPSYS_TAG "shim::legacy::bta::dm" +void DumpsysBtaDmGattClient(int fd) { + auto gatt_history = gatt_history_.Pull(); + LOG_DUMPSYS(fd, " last %zu gatt history entries", gatt_history.size()); + for (const auto& it : gatt_history) { + LOG_DUMPSYS(fd, " %s %s", EpochMillisToString(it.timestamp).c_str(), + it.entry.c_str()); + } +} +#undef DUMPSYS_TAG + +void bluetooth::testing::set_gatt_interface(const gatt_interface_t& interface) { + *gatt_interface = interface; +} + +namespace bluetooth { +namespace legacy { +namespace testing { + +std::vector> +PullCopyOfGattHistory() { + return gatt_history_.Pull(); +} + +} // namespace testing +} // namespace legacy +} // namespace bluetooth diff --git a/system/bta/dm/bta_dm_gatt_client.h b/system/bta/dm/bta_dm_gatt_client.h new file mode 100644 index 0000000000000000000000000000000000000000..4113b7d828b02f6d0d4a21a247eb3ada23eaaa01 --- /dev/null +++ b/system/bta/dm/bta_dm_gatt_client.h @@ -0,0 +1,71 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "bta/include/bta_gatt_api.h" +#include "include/hardware/bt_common_types.h" +#include "stack/include/btm_ble_api_types.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +// +// Interface as a GATT client for bta clients +// +struct gatt_interface_t { + void (*BTA_GATTC_CancelOpen)(tGATT_IF client_if, const RawAddress& remote_bda, + bool is_direct); + void (*BTA_GATTC_Refresh)(const RawAddress& remote_bda); + void (*BTA_GATTC_GetGattDb)(uint16_t conn_id, uint16_t start_handle, + uint16_t end_handle, btgatt_db_element_t** db, + int* count); + void (*BTA_GATTC_AppRegister)(tBTA_GATTC_CBACK* p_client_cb, + BtaAppRegisterCallback cb, bool eatt_support); + void (*BTA_GATTC_Close)(uint16_t conn_id); + void (*BTA_GATTC_ServiceSearchRequest)(uint16_t conn_id, + const bluetooth::Uuid* p_srvc_uuid); + void (*BTA_GATTC_Open)(tGATT_IF client_if, const RawAddress& remote_bda, + tBTM_BLE_CONN_TYPE connection_type, + bool opportunistic); +}; + +// +// Returns the current GATT client interface +// +gatt_interface_t& get_gatt_interface(); + +// +// Appends a callback entry into GATT client API/callback history +// +void gatt_history_callback(const std::string& entry); + +// +// Dumps the GATT client API/callback history to dumpsys +// +void DumpsysBtaDmGattClient(int fd); + +namespace bluetooth { +namespace testing { + +// +// TESTING: Sets a specialzed GATT client interface implementation for testing +// +void set_gatt_interface(const gatt_interface_t& interface); + +} // namespace testing +} // namespace bluetooth diff --git a/system/bta/dm/bta_dm_int.h b/system/bta/dm/bta_dm_int.h index 96f1f16ad0a1cb38de02916ea6ec30ec33f45f7c..dfeaee59a2e4f106d926391b55931d34630ff602 100644 --- a/system/bta/dm/bta_dm_int.h +++ b/system/bta/dm/bta_dm_int.h @@ -26,25 +26,16 @@ #include -#include #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/include/bta_api.h" -#include "bta/include/bta_gatt_api.h" +#include "bta/include/bta_sec_api.h" #include "bta/sys/bta_sys.h" -#include "main/shim/dumpsys.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/bt_octets.h" -#include "types/bluetooth/uuid.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" +#include "macros.h" #include "types/raw_address.h" -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - /***************************************************************************** * Constants and data types ****************************************************************************/ @@ -58,138 +49,6 @@ #define BTA_DM_MSG_LEN 50 -#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id)) - -/* DM search events */ -typedef enum : uint16_t { - /* DM search API events */ - BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH), - BTA_DM_API_SEARCH_CANCEL_EVT, - BTA_DM_API_DISCOVER_EVT, - BTA_DM_INQUIRY_CMPL_EVT, - BTA_DM_REMT_NAME_EVT, - BTA_DM_SDP_RESULT_EVT, - BTA_DM_SEARCH_CMPL_EVT, - BTA_DM_DISCOVERY_RESULT_EVT, - BTA_DM_DISC_CLOSE_TOUT_EVT, -} tBTA_DM_EVT; - -inline std::string bta_dm_event_text(const tBTA_DM_EVT& event) { - switch (event) { - CASE_RETURN_TEXT(BTA_DM_API_SEARCH_EVT); - CASE_RETURN_TEXT(BTA_DM_API_SEARCH_CANCEL_EVT); - CASE_RETURN_TEXT(BTA_DM_API_DISCOVER_EVT); - CASE_RETURN_TEXT(BTA_DM_INQUIRY_CMPL_EVT); - CASE_RETURN_TEXT(BTA_DM_REMT_NAME_EVT); - CASE_RETURN_TEXT(BTA_DM_SDP_RESULT_EVT); - CASE_RETURN_TEXT(BTA_DM_SEARCH_CMPL_EVT); - CASE_RETURN_TEXT(BTA_DM_DISCOVERY_RESULT_EVT); - CASE_RETURN_TEXT(BTA_DM_DISC_CLOSE_TOUT_EVT); - default: - return base::StringPrintf("UNKNOWN[0x%04x]", event); - } -} - -/* data type for BTA_DM_API_SEARCH_EVT */ -typedef struct { - BT_HDR_RIGID hdr; - tBTA_SERVICE_MASK services; - tBTA_DM_SEARCH_CBACK* p_cback; -} tBTA_DM_API_SEARCH; - -/* data type for BTA_DM_API_DISCOVER_EVT */ -typedef struct { - BT_HDR_RIGID hdr; - RawAddress bd_addr; - tBTA_DM_SEARCH_CBACK* p_cback; - tBT_TRANSPORT transport; -} tBTA_DM_API_DISCOVER; - -typedef struct { - BT_HDR_RIGID hdr; -} tBTA_DM_API_DISCOVERY_CANCEL; - -typedef struct { - RawAddress bd_addr; - bool accept; - uint8_t pin_len; - uint8_t p_pin[PIN_CODE_LEN]; -} tBTA_DM_API_PIN_REPLY; - -typedef struct { - BT_HDR_RIGID hdr; - RawAddress bd_addr; - tBTM_IO_CAP io_cap; - tBTM_OOB_DATA oob_data; - tBTM_AUTH_REQ auth_req; -} tBTA_DM_CI_IO_REQ; - -typedef struct { - RawAddress bd_addr; - Octet16 c; - Octet16 r; - bool accept; -} tBTA_DM_CI_RMT_OOB; - -/* data type for BTA_DM_REMT_NAME_EVT */ -typedef struct { - BT_HDR_RIGID hdr; - tBTA_DM_SEARCH result; -} tBTA_DM_REM_NAME; - -/* data type for tBTA_DM_DISC_RESULT */ -typedef struct { - BT_HDR_RIGID hdr; - tBTA_DM_SEARCH result; -} tBTA_DM_DISC_RESULT; - -/* data type for BTA_DM_INQUIRY_CMPL_EVT */ -typedef struct { - BT_HDR_RIGID hdr; - uint8_t num; -} tBTA_DM_INQUIRY_CMPL; - -/* data type for BTA_DM_SDP_RESULT_EVT */ -typedef struct { - BT_HDR_RIGID hdr; - tSDP_RESULT sdp_result; -} tBTA_DM_SDP_RESULT; - -typedef struct { - RawAddress bd_addr; - DEV_CLASS dc; - LinkKey link_key; - uint8_t key_type; - bool link_key_known; - bool dc_known; - BD_NAME bd_name; - uint8_t pin_length; -} tBTA_DM_API_ADD_DEVICE; - -typedef struct { - BT_HDR_RIGID hdr; - bool enable; -} tBTA_DM_API_BLE_FEATURE; - -/* union of all data types */ -typedef union { - /* GKI event buffer header */ - BT_HDR_RIGID hdr; - - tBTA_DM_API_SEARCH search; - - tBTA_DM_API_DISCOVER discover; - - tBTA_DM_REM_NAME rem_name; - - tBTA_DM_DISC_RESULT disc_result; - - tBTA_DM_INQUIRY_CMPL inq_cmpl; - - tBTA_DM_SDP_RESULT sdp_event; - -} tBTA_DM_MSG; - #define BTA_DM_NUM_PEER_DEVICE 7 typedef enum : uint8_t { @@ -248,20 +107,37 @@ struct tBTA_DM_PEER_DEVICE { bool in_use; private: - friend void bta_dm_acl_up(const RawAddress& bd_addr, tBT_TRANSPORT transport, - uint16_t acl_handle); - friend void bta_dm_pm_btm_status(const RawAddress& bd_addr, - tBTM_PM_STATUS status, uint16_t value, - tHCI_STATUS hci_status); - friend void bta_dm_pm_sniff(struct tBTA_DM_PEER_DEVICE* p_peer_dev, - uint8_t index); - friend void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, - uint8_t app_id, const RawAddress& peer_addr); - friend void handle_remote_features_complete(const RawAddress& bd_addr); - tBTA_DM_DEV_INFO info; + // Dynamic pieces of operational device information + tBTA_DM_DEV_INFO info{BTA_DM_DI_NONE}; public: - tBTA_DM_DEV_INFO Info() const { return info; } + std::string info_text() const { return device_info_text(info); } + + void reset_device_info() { info = BTA_DM_DI_NONE; } + + void set_av_active() { info |= BTA_DM_DI_AV_ACTIVE; } + void reset_av_active() { info &= ~BTA_DM_DI_AV_ACTIVE; } + bool is_av_active() const { return info & BTA_DM_DI_AV_ACTIVE; } + + void set_local_init_sniff() { info |= BTA_DM_DI_INT_SNIFF; } + bool is_local_init_sniff() const { return info & BTA_DM_DI_INT_SNIFF; } + void set_remote_init_sniff() { info |= BTA_DM_DI_ACP_SNIFF; } + bool is_remote_init_sniff() const { return info & BTA_DM_DI_ACP_SNIFF; } + + void set_sniff_command_sent() { info |= BTA_DM_DI_SET_SNIFF; } + void reset_sniff_command_sent() { info &= ~BTA_DM_DI_SET_SNIFF; } + bool is_sniff_command_sent() const { return info & BTA_DM_DI_SET_SNIFF; } + + // NOTE: Why is this not used as a bitmask + void set_both_device_ssr_capable() { info = BTA_DM_DI_USE_SSR; } + + void reset_sniff_flags() { + info &= ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF); + } + + void set_ssr_active() { info |= BTA_DM_DI_USE_SSR; } + void reset_ssr_active() { info &= ~BTA_DM_DI_USE_SSR; } + bool is_ssr_active() const { return info & BTA_DM_DI_USE_SSR; } tBTA_DM_ENCRYPT_CBACK* p_encrypt_cback; tBTM_PM_STATUS prev_low; /* previous low power mode used */ @@ -328,10 +204,13 @@ extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; #define BTA_DM_NUM_PM_TIMER 7 +typedef struct { + tBTA_DM_ACL_CBACK* p_acl_cback; +} tBTA_DM_ACL_CB; + /* DM control block */ typedef struct { tBTA_DM_ACTIVE_LINK device_list; - tBTA_DM_SEC_CBACK* p_sec_cback; tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback; bool disabling; alarm_t* disable_timer; @@ -339,17 +218,6 @@ typedef struct { tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER]; uint8_t cur_av_count; /* current AV connecions */ - /* Storage for pin code request parameters */ - RawAddress pin_bd_addr; - DEV_CLASS pin_dev_class; - tBTA_DM_SEC_EVT pin_evt; - tBTM_IO_CAP loc_io_caps; /* IO Capabilities of local device */ - tBTM_IO_CAP rmt_io_caps; /* IO Capabilities of remote device */ - tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */ - tBTM_AUTH_REQ rmt_auth_req; - uint32_t num_val; /* the numeric value for comparison. If just_works, do not - show this number to UI */ - bool just_works; /* true, if "Just Works" association model */ #if (BTA_EIR_CANNED_UUID_LIST != TRUE) /* store UUID list for EIR */ uint32_t eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE]; @@ -359,63 +227,9 @@ typedef struct { #endif - tBTA_DM_ENCRYPT_CBACK* p_encrypt_cback; alarm_t* switch_delay_timer; } tBTA_DM_CB; -/* DM search state */ -typedef enum { - - BTA_DM_SEARCH_IDLE, - BTA_DM_SEARCH_ACTIVE, - BTA_DM_SEARCH_CANCELLING, - BTA_DM_DISCOVER_ACTIVE - -} tBTA_DM_STATE; - -inline std::string bta_dm_state_text(const tBTA_DM_STATE& state) { - switch (state) { - CASE_RETURN_TEXT(BTA_DM_SEARCH_IDLE); - CASE_RETURN_TEXT(BTA_DM_SEARCH_ACTIVE); - CASE_RETURN_TEXT(BTA_DM_SEARCH_CANCELLING); - CASE_RETURN_TEXT(BTA_DM_DISCOVER_ACTIVE); - default: - return base::StringPrintf("UNKNOWN[%d]", state); - } -} - -/* DM search control block */ -typedef struct { - tBTA_DM_SEARCH_CBACK* p_search_cback; - tBTM_INQ_INFO* p_btm_inq_info; - tBTA_SERVICE_MASK services; - tBTA_SERVICE_MASK services_to_search; - tBTA_SERVICE_MASK services_found; - tSDP_DISCOVERY_DB* p_sdp_db; - tBTA_DM_STATE state; - RawAddress peer_bdaddr; - bool name_discover_done; - BD_NAME peer_name; - alarm_t* search_timer; - uint8_t service_index; - tBTA_DM_MSG* p_pending_search; - fixed_queue_t* pending_discovery_queue; - bool wait_disc; - bool sdp_results; - bluetooth::Uuid uuid; - uint8_t peer_scn; - tBT_TRANSPORT transport; - tBTA_DM_SEARCH_CBACK* p_scan_cback; - tBTA_DM_SEARCH_CBACK* p_csis_scan_cback; - tGATT_IF client_if; - uint8_t uuid_to_search; - bool gatt_disc_active; - uint16_t conn_id; - alarm_t* gatt_close_timer; /* GATT channel close delay timer */ - RawAddress pending_close_bda; /* pending GATT channel remote device address */ - -} tBTA_DM_SEARCH_CB; - /* DI control block */ typedef struct { uint8_t di_num; /* total local DI record number */ @@ -497,85 +311,34 @@ extern const tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg; /* DM control block */ extern tBTA_DM_CB bta_dm_cb; -/* DM search control block */ -extern tBTA_DM_SEARCH_CB bta_dm_search_cb; +/* DM control block for ACL management */ +extern tBTA_DM_ACL_CB bta_dm_acl_cb; /* DI control block */ extern tBTA_DM_DI_CB bta_dm_di_cb; -bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg); -void bta_dm_search_sm_disable(void); - -void bta_dm_enable(tBTA_DM_SEC_CBACK*); +void bta_dm_enable(tBTA_DM_SEC_CBACK*, tBTA_DM_ACL_CBACK*); void bta_dm_disable(); -void bta_dm_init_cb(void); -void bta_dm_deinit_cb(void); void bta_dm_set_dev_name(const std::vector&); -void bta_dm_set_visibility(tBTA_DM_DISC, tBTA_DM_CONN); -void bta_dm_set_scan_config(tBTA_DM_MSG* p_data); -void bta_dm_vendor_spec_command(tBTA_DM_MSG* p_data); -void bta_dm_bond(const RawAddress&, tBLE_ADDR_TYPE, tBT_TRANSPORT, - tBT_DEVICE_TYPE); -void bta_dm_bond_cancel(const RawAddress&); -void bta_dm_pin_reply(std::unique_ptr msg); -void bta_dm_add_device(std::unique_ptr msg); -void bta_dm_remove_device(const RawAddress& bd_addr); void bta_dm_close_acl(const RawAddress&, bool, tBT_TRANSPORT); void bta_dm_pm_btm_status(const RawAddress&, tBTM_PM_STATUS, uint16_t, tHCI_STATUS); void bta_dm_pm_timer(const RawAddress&, tBTA_DM_PM_ACTION); -void bta_dm_add_ampkey(tBTA_DM_MSG* p_data); - -void bta_dm_add_blekey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE blekey, - tBTM_LE_KEY_TYPE key_type); -void bta_dm_add_ble_device(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_DEVICE_TYPE dev_type); -void bta_dm_ble_passkey_reply(const RawAddress& bd_addr, bool accept, - uint32_t passkey); -void bta_dm_ble_confirm_reply(const RawAddress&, bool); + void bta_dm_ble_set_conn_params(const RawAddress&, uint16_t, uint16_t, uint16_t, uint16_t); -void bta_dm_close_gatt_conn(tBTA_DM_MSG* p_data); -void bta_dm_ble_observe(bool, uint8_t, tBTA_DM_SEARCH_CBACK*); -void bta_dm_ble_scan(bool, uint8_t, bool); -void bta_dm_ble_csis_observe(bool, tBTA_DM_SEARCH_CBACK*); void bta_dm_ble_update_conn_params(const RawAddress&, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t); -void bta_dm_ble_config_local_privacy(bool); void bta_dm_ble_set_data_length(const RawAddress& bd_addr); void bta_dm_ble_get_energy_info(tBTA_BLE_ENERGY_INFO_CBACK*); -void bta_dm_set_encryption(const RawAddress&, tBT_TRANSPORT, - tBTA_DM_ENCRYPT_CBACK*, tBTM_BLE_SEC_ACT); -void bta_dm_confirm(const RawAddress&, bool); - -void bta_dm_ci_rmt_oob_act(std::unique_ptr msg); - void bta_dm_init_pm(void); void bta_dm_disable_pm(void); uint8_t bta_dm_get_av_count(void); -void bta_dm_search_start(tBTA_DM_MSG* p_data); -void bta_dm_search_cancel(); -void bta_dm_discover(tBTA_DM_MSG* p_data); -void bta_dm_inq_cmpl(uint8_t num); -void bta_dm_rmt_name(tBTA_DM_MSG* p_data); -void bta_dm_sdp_result(tBTA_DM_MSG* p_data); -void bta_dm_search_cmpl(); -void bta_dm_free_sdp_db(); -void bta_dm_disc_result(tBTA_DM_MSG* p_data); -void bta_dm_search_result(tBTA_DM_MSG* p_data); -void bta_dm_discovery_cmpl(tBTA_DM_MSG* p_data); -void bta_dm_queue_search(tBTA_DM_MSG* p_data); -void bta_dm_queue_disc(tBTA_DM_MSG* p_data); -void bta_dm_execute_queued_request(); -bool bta_dm_is_search_request_queued(); -void bta_dm_search_clear_queue(); -void bta_dm_search_cancel_notify(); -void bta_dm_disc_rmt_name(tBTA_DM_MSG* p_data); tBTA_DM_PEER_DEVICE* bta_dm_find_peer_device(const RawAddress& peer_addr); void bta_dm_clear_event_filter(void); @@ -594,16 +357,11 @@ void bta_dm_set_event_filter_inquiry_result_all_devices(); void bta_dm_ble_reset_id(void); -tBTA_DM_STATE bta_dm_search_get_state(); -void bta_dm_search_set_state(tBTA_DM_STATE state); - void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding); void bta_dm_eir_update_cust_uuid(const tBTA_CUSTOM_UUID &curr, bool adding); void bta_dm_ble_subrate_request(const RawAddress& bd_addr, uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t timeout); -void bta_dm_consolidate(const RawAddress& identity_addr, const RawAddress& rpa); -#undef CASE_RETURN_TEXT #endif /* BTA_DM_INT_H */ diff --git a/system/bta/dm/bta_dm_main.cc b/system/bta/dm/bta_dm_main.cc index 532b979e7bbaccd7c9b5a5fe9e8e3c18d85dce46..1b3e7444a9cdabf1dfdedc0874e7d4a302a8d6e5 100644 --- a/system/bta/dm/bta_dm_main.cc +++ b/system/bta/dm/bta_dm_main.cc @@ -24,222 +24,22 @@ #include #include -#include "bt_trace.h" +#include "bta/dm/bta_dm_disc.h" +#include "bta/dm/bta_dm_gatt_client.h" #include "bta/dm/bta_dm_int.h" -#include "gd/common/circular_buffer.h" -#include "gd/common/strings.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" - -/***************************************************************************** - * Constants and types - ****************************************************************************/ - -namespace { -constexpr size_t kSearchStateHistorySize = 50; -constexpr char kTimeFormatString[] = "%Y-%m-%d %H:%M:%S"; - -constexpr unsigned MillisPerSecond = 1000; -std::string EpochMillisToString(long long time_ms) { - time_t time_sec = time_ms / MillisPerSecond; - struct tm tm; - localtime_r(&time_sec, &tm); - std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm); - return base::StringPrintf( - "%s.%03u", s.c_str(), - static_cast(time_ms % MillisPerSecond)); -} -} // namespace +#include "bta/dm/bta_dm_sec_int.h" +#include "main/shim/dumpsys.h" +tBTA_DM_ACL_CB bta_dm_acl_cb; tBTA_DM_CB bta_dm_cb; -tBTA_DM_SEARCH_CB bta_dm_search_cb; tBTA_DM_DI_CB bta_dm_di_cb; -struct tSEARCH_STATE_HISTORY { - const tBTA_DM_STATE state; - const tBTA_DM_EVT event; - std::string ToString() const { - return base::StringPrintf("state:%25s event:%s", - bta_dm_state_text(state).c_str(), - bta_dm_event_text(event).c_str()); - } -}; -bluetooth::common::TimestampedCircularBuffer - search_state_history_(kSearchStateHistorySize); - -/******************************************************************************* - * - * Function bta_dm_sm_search_disable - * - * Description unregister BTA SEARCH DM - * - * - * Returns void - * - ******************************************************************************/ -void bta_dm_search_sm_disable() { bta_sys_deregister(BTA_ID_DM_SEARCH); } - -/******************************************************************************* - * - * Function bta_dm_search_sm_execute - * - * Description State machine event handling function for DM - * - * - * Returns void - * - ******************************************************************************/ -bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg) { - const tBTA_DM_EVT event = static_cast(p_msg->event); - LOG_INFO("state:%s, event:%s[0x%x]", - bta_dm_state_text(bta_dm_search_get_state()).c_str(), - bta_dm_event_text(event).c_str(), event); - search_state_history_.Push({ - .state = bta_dm_search_get_state(), - .event = event, - }); - tBTA_DM_MSG* message = (tBTA_DM_MSG*)p_msg; - switch (bta_dm_search_get_state()) { - case BTA_DM_SEARCH_IDLE: - switch (p_msg->event) { - case BTA_DM_API_SEARCH_EVT: - bta_dm_search_set_state(BTA_DM_SEARCH_ACTIVE); - bta_dm_search_start(message); - break; - case BTA_DM_API_DISCOVER_EVT: - bta_dm_search_set_state(BTA_DM_DISCOVER_ACTIVE); - bta_dm_discover(message); - break; - case BTA_DM_API_SEARCH_CANCEL_EVT: - bta_dm_search_clear_queue(); - bta_dm_search_cancel_notify(); - break; - case BTA_DM_SDP_RESULT_EVT: - bta_dm_free_sdp_db(); - break; - case BTA_DM_DISC_CLOSE_TOUT_EVT: - bta_dm_close_gatt_conn(message); - break; - default: - LOG_INFO("Received unexpected event %s[0x%x] in state %s", - bta_dm_event_text(event).c_str(), event, - bta_dm_state_text(bta_dm_search_get_state()).c_str()); - } - break; - case BTA_DM_SEARCH_ACTIVE: - switch (p_msg->event) { - case BTA_DM_REMT_NAME_EVT: - bta_dm_rmt_name(message); - break; - case BTA_DM_SEARCH_CMPL_EVT: - bta_dm_search_cmpl(); - break; - case BTA_DM_DISCOVERY_RESULT_EVT: - bta_dm_search_result(message); - break; - case BTA_DM_DISC_CLOSE_TOUT_EVT: - bta_dm_close_gatt_conn(message); - break; - case BTA_DM_API_DISCOVER_EVT: - bta_dm_queue_disc(message); - break; - case BTA_DM_API_SEARCH_CANCEL_EVT: - bta_dm_search_clear_queue(); - bta_dm_search_set_state(BTA_DM_SEARCH_CANCELLING); - bta_dm_search_cancel(); - break; - default: - LOG_INFO("Received unexpected event %s[0x%x] in state %s", - bta_dm_event_text(event).c_str(), event, - bta_dm_state_text(bta_dm_search_get_state()).c_str()); - } - break; - case BTA_DM_SEARCH_CANCELLING: - switch (p_msg->event) { - case BTA_DM_API_SEARCH_EVT: - bta_dm_queue_search(message); - break; - case BTA_DM_API_DISCOVER_EVT: - bta_dm_queue_disc(message); - break; - case BTA_DM_API_SEARCH_CANCEL_EVT: - bta_dm_search_clear_queue(); - bta_dm_search_cancel_notify(); - break; - case BTA_DM_SDP_RESULT_EVT: - case BTA_DM_REMT_NAME_EVT: - case BTA_DM_SEARCH_CMPL_EVT: - case BTA_DM_DISCOVERY_RESULT_EVT: - bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); - bta_dm_free_sdp_db(); - bta_dm_search_cancel_notify(); - bta_dm_execute_queued_request(); - break; - case BTA_DM_DISC_CLOSE_TOUT_EVT: - if (bluetooth::common::init_flags:: - bta_dm_clear_conn_id_on_client_close_is_enabled()) { - bta_dm_close_gatt_conn(message); - break; - } - [[fallthrough]]; - default: - LOG_INFO("Received unexpected event %s[0x%x] in state %s", - bta_dm_event_text(event).c_str(), event, - bta_dm_state_text(bta_dm_search_get_state()).c_str()); - } - break; - case BTA_DM_DISCOVER_ACTIVE: - switch (p_msg->event) { - case BTA_DM_REMT_NAME_EVT: - bta_dm_disc_rmt_name(message); - break; - case BTA_DM_SDP_RESULT_EVT: - bta_dm_sdp_result(message); - break; - case BTA_DM_SEARCH_CMPL_EVT: - bta_dm_search_cmpl(); - break; - case BTA_DM_DISCOVERY_RESULT_EVT: - bta_dm_disc_result(message); - break; - case BTA_DM_API_SEARCH_EVT: - bta_dm_queue_search(message); - break; - case BTA_DM_API_DISCOVER_EVT: - bta_dm_queue_disc(message); - break; - case BTA_DM_API_SEARCH_CANCEL_EVT: - bta_dm_search_clear_queue(); - bta_dm_search_set_state(BTA_DM_SEARCH_CANCELLING); - bta_dm_search_cancel_notify(); - break; - case BTA_DM_DISC_CLOSE_TOUT_EVT: - if (bluetooth::common::init_flags:: - bta_dm_clear_conn_id_on_client_close_is_enabled()) { - bta_dm_close_gatt_conn(message); - break; - } - [[fallthrough]]; - default: - LOG_INFO("Received unexpected event %s[0x%x] in state %s", - bta_dm_event_text(event).c_str(), event, - bta_dm_state_text(bta_dm_search_get_state()).c_str()); - } - break; - } - return true; -} +tBTA_DM_SEC_CB bta_dm_sec_cb; #define DUMPSYS_TAG "shim::legacy::bta::dm" void DumpsysBtaDm(int fd) { LOG_DUMPSYS_TITLE(fd, DUMPSYS_TAG); - auto copy = search_state_history_.Pull(); - LOG_DUMPSYS(fd, " last %zu search state transitions", copy.size()); - for (const auto& it : copy) { - LOG_DUMPSYS(fd, " %s %s", EpochMillisToString(it.timestamp).c_str(), - it.entry.ToString().c_str()); - } - LOG_DUMPSYS(fd, " current bta_dm_search_state:%s", - bta_dm_state_text(bta_dm_search_get_state()).c_str()); + DumpsysBtaDmDisc(fd); + DumpsysBtaDmGattClient(fd); } #undef DUMPSYS_TAG diff --git a/system/bta/dm/bta_dm_pm.cc b/system/bta/dm/bta_dm_pm.cc index c2cbce4ee1e6db98ce1bb432b4faeef66834515c..95020a50589806a4dfe69e390b98529ae9fda9c5 100644 --- a/system/bta/dm/bta_dm_pm.cc +++ b/system/bta/dm/bta_dm_pm.cc @@ -37,13 +37,14 @@ #include "btif/include/stack_manager.h" #include "device/include/controller.h" #include "main/shim/dumpsys.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/properties.h" #include "stack/include/acl_api.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/btm_client_interface.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" -static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, +static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, const tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr); static void bta_dm_pm_set_mode(const RawAddress& peer_addr, tBTA_DM_PM_ACTION pm_mode, @@ -95,7 +96,8 @@ void bta_dm_init_pm(void) { if (p_bta_dm_pm_cfg[0].app_id != 0) { bta_sys_pm_register(bta_dm_pm_cback); - BTM_PmRegister((BTM_PM_REG_SET), &bta_dm_cb.pm_id, bta_dm_pm_btm_cback); + get_btm_client_interface().lifecycle.BTM_PmRegister( + (BTM_PM_REG_SET), &bta_dm_cb.pm_id, bta_dm_pm_btm_cback); } /* Need to initialize all PM timer service IDs */ @@ -116,7 +118,8 @@ void bta_dm_init_pm(void) { * ******************************************************************************/ void bta_dm_disable_pm(void) { - BTM_PmRegister(BTM_PM_DEREG, &bta_dm_cb.pm_id, bta_dm_pm_btm_cback); + get_btm_client_interface().lifecycle.BTM_PmRegister( + BTM_PM_DEREG, &bta_dm_cb.pm_id, bta_dm_pm_btm_cback); /* * Deregister the PM callback from the system handling to prevent @@ -162,7 +165,7 @@ uint8_t bta_dm_get_av_count(void) { * ******************************************************************************/ static void bta_dm_pm_stop_timer(const RawAddress& peer_addr) { - APPL_TRACE_DEBUG("%s: ", __func__); + LOG_VERBOSE("%s: ", __func__); for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) { if (bta_dm_cb.pm_timer[i].in_use && @@ -341,13 +344,13 @@ static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER* p_timer, * Returns void * ******************************************************************************/ -static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, +static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, const tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { uint8_t i, j; tBTA_DM_PEER_DEVICE* p_dev; tBTA_DM_PM_REQ pm_req = BTA_DM_PM_NEW_REQ; - LOG_DEBUG("Power management callback status:%s[%hhu] id:%s[%d], app:%hhu", + LOG_DEBUG("Power management callback status:%s[%hhu] id:%s[%hhu], app:%hhu", bta_sys_conn_status_text(status).c_str(), status, BtaIdSysText(id).c_str(), id, app_id); @@ -366,21 +369,20 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, return; } - LOG_DEBUG("Stopped all timers for service to device:%s id:%hhu", - ADDRESS_TO_LOGGABLE_CSTR(peer_addr), id); - bta_dm_pm_stop_timer_by_srvc_id(peer_addr, id); + LOG_DEBUG("Stopped all timers for service to device:%s id:%s[%hhu]", + ADDRESS_TO_LOGGABLE_CSTR(peer_addr), BtaIdSysText(id).c_str(), id); + bta_dm_pm_stop_timer_by_srvc_id(peer_addr, static_cast(id)); p_dev = bta_dm_find_peer_device(peer_addr); if (p_dev) { - LOG_DEBUG("Device info:%s", device_info_text(p_dev->Info()).c_str()); + LOG_DEBUG("Device info:%s", p_dev->info_text().c_str()); } else { LOG_ERROR("Unable to find peer device...yet soldiering on..."); } /* set SSR parameters on SYS CONN OPEN */ int index = BTA_DM_PM_SSR0; - if ((BTA_SYS_CONN_OPEN == status) && p_dev && - (p_dev->Info() & BTA_DM_DI_USE_SSR)) { + if ((BTA_SYS_CONN_OPEN == status) && p_dev && (p_dev->is_ssr_active())) { index = get_bta_dm_pm_spec()[p_bta_dm_pm_cfg[i].spec_idx].ssr; } else if (BTA_ID_AV == id) { if (BTA_SYS_CONN_BUSY == status) { @@ -423,7 +425,7 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, sizeof(bta_dm_conn_srvcs.conn_srvc[j])); } } else { - APPL_TRACE_WARNING("bta_dm_act no entry for connected service cbs"); + LOG_WARN("bta_dm_act no entry for connected service cbs"); return; } } else if (j == bta_dm_conn_srvcs.count) { @@ -453,7 +455,7 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, bta_dm_pm_stop_timer(peer_addr); if (bta_dm_conn_srvcs.count > 0) { pm_req = BTA_DM_PM_RESTART; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s bta_dm_pm_stop_timer for current service, restart other " "service timers: count = %d", __func__, bta_dm_conn_srvcs.count); @@ -475,14 +477,16 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, const controller_t* controller = controller_get_interface(); uint8_t* p = NULL; if (controller->supports_sniff_subrating() && - ((NULL != (p = BTM_ReadRemoteFeatures(peer_addr))) && + ((NULL != (p = get_btm_client_interface().peer.BTM_ReadRemoteFeatures( + peer_addr))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) && (index == BTA_DM_PM_SSR0)) { if (status == BTA_SYS_SCO_OPEN) { - APPL_TRACE_DEBUG("%s: SCO inactive, reset SSR to zero", __func__); - BTM_SetSsrParams(peer_addr, 0, 0, 0); + LOG_VERBOSE("%s: SCO inactive, reset SSR to zero", __func__); + get_btm_client_interface().link_policy.BTM_SetSsrParams(peer_addr, 0, 0, + 0); } else if (status == BTA_SYS_SCO_CLOSE) { - APPL_TRACE_DEBUG("%s: SCO active, back to old SSR", __func__); + LOG_VERBOSE("%s: SCO active, back to old SSR", __func__); bta_dm_pm_ssr(peer_addr, BTA_DM_PM_SSR0); } } @@ -696,8 +700,9 @@ static bool bta_dm_pm_park(const RawAddress& peer_addr) { } if (mode != BTM_PM_MD_PARK) { - tBTM_STATUS status = BTM_SetPowerMode(bta_dm_cb.pm_id, peer_addr, - &p_bta_dm_pm_md[BTA_DM_PM_PARK_IDX]); + tBTM_STATUS status = + get_btm_client_interface().link_policy.BTM_SetPowerMode( + bta_dm_cb.pm_id, peer_addr, &p_bta_dm_pm_md[BTA_DM_PM_PARK_IDX]); if (status == BTM_CMD_STORED || status == BTM_CMD_STARTED) { return true; } @@ -779,23 +784,23 @@ void bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE* p_peer_dev, uint8_t index) { ADDRESS_TO_LOGGABLE_CSTR(p_peer_dev->peer_bdaddr)); } tBTM_PM_STATUS mode_status = static_cast(mode); - LOG_DEBUG("Current power mode:%s[0x%x] peer_info:%s[0x%02x]", + LOG_DEBUG("Current power mode:%s[0x%x] peer_info:%s", power_mode_status_text(mode_status).c_str(), mode_status, - device_info_text(p_peer_dev->Info()).c_str(), p_peer_dev->Info()); + p_peer_dev->info_text().c_str()); - uint8_t* p_rem_feat = BTM_ReadRemoteFeatures(p_peer_dev->peer_bdaddr); + uint8_t* p_rem_feat = get_btm_client_interface().peer.BTM_ReadRemoteFeatures( + p_peer_dev->peer_bdaddr); const controller_t* controller = controller_get_interface(); if (mode != BTM_PM_MD_SNIFF || (controller->supports_sniff_subrating() && p_rem_feat && HCI_SNIFF_SUB_RATE_SUPPORTED(p_rem_feat) && - !(p_peer_dev->Info() & BTA_DM_DI_USE_SSR))) { + !(p_peer_dev->is_ssr_active()))) { /* Dont initiate Sniff if controller has alreay accepted * remote sniff params. This avoid sniff loop issue with * some agrresive headsets who use sniff latencies more than * DUT supported range of Sniff intervals.*/ - if ((mode == BTM_PM_MD_SNIFF) && - (p_peer_dev->Info() & BTA_DM_DI_ACP_SNIFF)) { + if ((mode == BTM_PM_MD_SNIFF) && (p_peer_dev->is_remote_init_sniff())) { LOG_DEBUG("Link already in sniff mode peer:%s", ADDRESS_TO_LOGGABLE_CSTR(p_peer_dev->peer_bdaddr)); return; @@ -805,24 +810,23 @@ void bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE* p_peer_dev, uint8_t index) { * If sniff, but SSR is not used in this link, still issue the command */ tBTM_PM_PWR_MD sniff_entry = get_sniff_entry(index); memcpy(&pwr_md, &sniff_entry, sizeof(tBTM_PM_PWR_MD)); - if (p_peer_dev->Info() & BTA_DM_DI_INT_SNIFF) { + if (p_peer_dev->is_local_init_sniff()) { LOG_DEBUG("Trying to force power mode"); pwr_md.mode |= BTM_PM_MD_FORCE; } - status = BTM_SetPowerMode(bta_dm_cb.pm_id, p_peer_dev->peer_bdaddr, &pwr_md); + status = get_btm_client_interface().link_policy.BTM_SetPowerMode( + bta_dm_cb.pm_id, p_peer_dev->peer_bdaddr, &pwr_md); if (status == BTM_CMD_STORED || status == BTM_CMD_STARTED) { - p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF); - p_peer_dev->info |= BTA_DM_DI_SET_SNIFF; + p_peer_dev->reset_sniff_flags(); + p_peer_dev->set_sniff_command_sent(); } else if (status == BTM_SUCCESS) { - APPL_TRACE_DEBUG("bta_dm_pm_sniff BTM_SetPowerMode() returns BTM_SUCCESS"); - p_peer_dev->info &= - ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF); + LOG_VERBOSE("bta_dm_pm_sniff BTM_SetPowerMode() returns BTM_SUCCESS"); + p_peer_dev->reset_sniff_flags(); } else { LOG_ERROR("Unable to set power mode peer:%s status:%s", ADDRESS_TO_LOGGABLE_CSTR(p_peer_dev->peer_bdaddr), btm_status_text(status).c_str()); - p_peer_dev->info &= - ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF); + p_peer_dev->reset_sniff_flags(); } } /******************************************************************************* @@ -901,8 +905,8 @@ static void bta_dm_pm_ssr(const RawAddress& peer_addr, const int ssr) { ticks_to_seconds(p_spec->max_lat), ticks_to_seconds(p_spec->min_loc_to), ticks_to_seconds(p_spec->min_rmt_to)); /* set the SSR parameters. */ - BTM_SetSsrParams(peer_addr, p_spec->max_lat, p_spec->min_rmt_to, - p_spec->min_loc_to); + get_btm_client_interface().link_policy.BTM_SetSsrParams( + peer_addr, p_spec->max_lat, p_spec->min_rmt_to, p_spec->min_loc_to); } } @@ -921,7 +925,8 @@ void bta_dm_pm_active(const RawAddress& peer_addr) { }; /* switch to active mode */ - tBTM_STATUS status = BTM_SetPowerMode(bta_dm_cb.pm_id, peer_addr, &pm); + tBTM_STATUS status = get_btm_client_interface().link_policy.BTM_SetPowerMode( + bta_dm_cb.pm_id, peer_addr, &pm); switch (status) { case BTM_CMD_STORED: LOG_DEBUG("Active power mode stored for execution later for remote:%s", @@ -946,8 +951,8 @@ void bta_dm_pm_active(const RawAddress& peer_addr) { static void bta_dm_pm_btm_cback(const RawAddress& bd_addr, tBTM_PM_STATUS status, uint16_t value, tHCI_STATUS hci_status) { - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_pm_btm_status, bd_addr, status, - value, hci_status)); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_pm_btm_status, bd_addr, + status, value, hci_status)); } /******************************************************************************* @@ -966,14 +971,13 @@ static void bta_dm_pm_timer_cback(void* data) { std::unique_lock state_lock(pm_timer_state_mutex); for (i = 0; i < BTA_DM_NUM_PM_TIMER; i++) { - APPL_TRACE_DEBUG("dm_pm_timer[%d] in use? %d", i, - bta_dm_cb.pm_timer[i].in_use); + LOG_VERBOSE("dm_pm_timer[%d] in use? %d", i, bta_dm_cb.pm_timer[i].in_use); if (bta_dm_cb.pm_timer[i].in_use) { for (j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) { if (bta_dm_cb.pm_timer[i].timer[j] == alarm) { bta_dm_cb.pm_timer[i].active--; bta_dm_cb.pm_timer[i].srvc_id[j] = BTA_ID_MAX; - APPL_TRACE_DEBUG("dm_pm_timer[%d] expires, timer_idx=%d", i, j); + LOG_VERBOSE("dm_pm_timer[%d] expires, timer_idx=%d", i, j); break; } } @@ -988,8 +992,9 @@ static void bta_dm_pm_timer_cback(void* data) { if (i == BTA_DM_NUM_PM_TIMER) return; do_in_main_thread( - FROM_HERE, base::Bind(bta_dm_pm_timer, bta_dm_cb.pm_timer[i].peer_bdaddr, - bta_dm_cb.pm_timer[i].pm_action[j])); + FROM_HERE, + base::BindOnce(bta_dm_pm_timer, bta_dm_cb.pm_timer[i].peer_bdaddr, + bta_dm_cb.pm_timer[i].pm_action[j])); } /** Process pm status event from btm */ @@ -1008,16 +1013,14 @@ void bta_dm_pm_btm_status(const RawAddress& bd_addr, tBTM_PM_STATUS status, return; } - tBTA_DM_DEV_INFO info = p_dev->Info(); /* check new mode */ switch (status) { case BTM_PM_STS_ACTIVE: /* if our sniff or park attempt failed we should not try it again*/ if (hci_status != 0) { - APPL_TRACE_ERROR("%s hci_status=%d", __func__, hci_status); - p_dev->info &= - ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF); + LOG_ERROR("%s hci_status=%d", __func__, hci_status); + p_dev->reset_sniff_flags(); if (p_dev->pm_mode_attempted & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) { p_dev->pm_mode_failed |= @@ -1043,7 +1046,7 @@ void bta_dm_pm_btm_status(const RawAddress& bd_addr, tBTM_PM_STATUS status, /* save the previous low power mode - for SSR. * SSR parameters are sent to controller on "conn open". * the numbers stay good until park/hold/detach */ - if (p_dev->info & BTA_DM_DI_USE_SSR) p_dev->prev_low = status; + if (p_dev->is_ssr_active()) p_dev->prev_low = status; break; case BTM_PM_STS_SSR: @@ -1051,11 +1054,11 @@ void bta_dm_pm_btm_status(const RawAddress& bd_addr, tBTM_PM_STATUS status, LOG_WARN("Received error when attempting to set sniff subrating mode"); } if (interval) { - p_dev->info |= BTA_DM_DI_USE_SSR; + p_dev->set_ssr_active(); LOG_DEBUG("Enabling sniff subrating mode for peer:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } else { - p_dev->info &= ~BTA_DM_DI_USE_SSR; + p_dev->reset_ssr_active(); LOG_DEBUG("Disabling sniff subrating mode for peer:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } @@ -1070,17 +1073,17 @@ void bta_dm_pm_btm_status(const RawAddress& bd_addr, tBTM_PM_STATUS status, */ bta_dm_pm_stop_timer(bd_addr); } else { - p_dev->info &= - ~(BTA_DM_DI_SET_SNIFF | BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF); - if (info & BTA_DM_DI_SET_SNIFF) - p_dev->info |= BTA_DM_DI_INT_SNIFF; + bool is_sniff_command_sent = p_dev->is_sniff_command_sent(); + p_dev->reset_sniff_flags(); + if (is_sniff_command_sent) + p_dev->set_local_init_sniff(); else - p_dev->info |= BTA_DM_DI_ACP_SNIFF; + p_dev->set_remote_init_sniff(); } break; case BTM_PM_STS_ERROR: - p_dev->info &= ~BTA_DM_DI_SET_SNIFF; + p_dev->reset_sniff_command_sent(); break; default: @@ -1091,7 +1094,7 @@ void bta_dm_pm_btm_status(const RawAddress& bd_addr, tBTM_PM_STATUS status, /** Process pm timer event from btm */ void bta_dm_pm_timer(const RawAddress& bd_addr, tBTA_DM_PM_ACTION pm_request) { - APPL_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_dm_pm_set_mode(bd_addr, pm_request, BTA_DM_PM_EXECUTE); } @@ -1154,6 +1157,6 @@ tBTM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void) { tBTM_CONTRL_STATE cur_state = BTM_CONTRL_UNKNOWN; cur_state = BTM_PM_ReadControllerState(); - APPL_TRACE_DEBUG("bta_dm_pm_obtain_controller_state: %d", cur_state); + LOG_VERBOSE("bta_dm_pm_obtain_controller_state: %d", cur_state); return cur_state; } diff --git a/system/bta/dm/bta_dm_sec.cc b/system/bta/dm/bta_dm_sec.cc new file mode 100644 index 0000000000000000000000000000000000000000..efca3e6996bf2f3ec846b7f5f4aa3dc39c9728cf --- /dev/null +++ b/system/bta/dm/bta_dm_sec.cc @@ -0,0 +1,1102 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "bt_bta_dm_sec" + +#include + +#include + +#include "bta/dm/bta_dm_act.h" +#include "bta/dm/bta_dm_disc.h" +#include "bta/dm/bta_dm_int.h" +#include "bta/dm/bta_dm_sec_int.h" +#include "bta/include/bta_dm_ci.h" // bta_dm_ci_rmt_oob +#include "btif/include/btif_dm.h" +#include "btif/include/btif_storage.h" +#include "internal_include/bt_target.h" +#include "osi/include/compat.h" // strlcpy +#include "osi/include/osi.h" // UNUSED_ATTR +#include "stack/include/btm_ble_sec_api_types.h" +#include "stack/include/btm_client_interface.h" +#include "stack/include/btm_sec_api.h" +#include "stack/include/gatt_api.h" +#include "stack/include/security_client_callbacks.h" +#include "types/raw_address.h" + +static tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data); +static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, const RawAddress& bda, + tBTM_LE_EVT_DATA* p_data); +static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr, + DEV_CLASS dev_class, + tBTM_BD_NAME bd_name, + const LinkKey& key, uint8_t key_type, + bool is_ctkd); +static uint8_t bta_dm_pin_cback(const RawAddress& bd_addr, DEV_CLASS dev_class, + const tBTM_BD_NAME bd_name, bool min_16_digit); +static uint8_t bta_dm_sirk_verifiction_cback(const RawAddress& bd_addr); +static void bta_dm_authentication_complete_cback(const RawAddress& bd_addr, + DEV_CLASS dev_class, + tBTM_BD_NAME bd_name, + tHCI_REASON result); +static void bta_dm_ble_id_key_cback(uint8_t key_type, + tBTM_BLE_LOCAL_KEYS* p_key); +static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result); +static void bta_dm_remove_sec_dev_entry(const RawAddress& remote_bd_addr); +static void bta_dm_reset_sec_dev_pending(const RawAddress& remote_bd_addr); + +/* bta security callback */ +const tBTM_APPL_INFO bta_security = { + .p_pin_callback = &bta_dm_pin_cback, + .p_link_key_callback = &bta_dm_new_link_key_cback, + .p_auth_complete_callback = &bta_dm_authentication_complete_cback, + .p_bond_cancel_cmpl_callback = &bta_dm_bond_cancel_complete_cback, + .p_sp_callback = &bta_dm_sp_cback, + .p_le_callback = &bta_dm_ble_smp_cback, + .p_le_key_callback = &bta_dm_ble_id_key_cback, + .p_sirk_verification_callback = &bta_dm_sirk_verifiction_cback}; + +// Stores the local Input/Output Capabilities of the Bluetooth device. +static uint8_t btm_local_io_caps; + +void btm_sec_on_hw_on() { + tBTA_DM_SEC_CBACK* temp_sec_cback = bta_dm_sec_cb.p_sec_cback; + bta_dm_sec_cb = {}; + bta_dm_sec_cb.p_sec_cback = temp_sec_cback; +} + +void bta_dm_ble_sirk_sec_cb_register(tBTA_DM_SEC_CBACK* p_cback) { + /* Save the callback to be called when a request of member validation will be + * needed. */ + LOG_DEBUG(""); + bta_dm_sec_cb.p_sec_sirk_cback = p_cback; +} + +void bta_dm_ble_sirk_confirm_device_reply(const RawAddress& bd_addr, + bool accept) { + LOG_DEBUG(""); + get_btm_client_interface().security.BTM_BleSirkConfirmDeviceReply( + bd_addr, accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED); +} + +void bta_dm_consolidate(const RawAddress& identity_addr, + const RawAddress& rpa) { + for (auto i = 0; i < bta_dm_cb.device_list.count; i++) { + if (bta_dm_cb.device_list.peer_device[i].peer_bdaddr != rpa) continue; + + LOG_INFO("consolidating bda_dm_cb record %s -> %s", + ADDRESS_TO_LOGGABLE_CSTR(rpa), + ADDRESS_TO_LOGGABLE_CSTR(identity_addr)); + bta_dm_cb.device_list.peer_device[i].peer_bdaddr = identity_addr; + } +} + +void btm_dm_sec_init() { + get_btm_client_interface().security.BTM_SecRegister(&bta_security); +} + +/** Initialises the BT device security manager */ +void bta_dm_sec_enable(tBTA_DM_SEC_CBACK* p_sec_cback) { + /* make sure security callback is saved - if no callback, do not erase the + previous one, + it could be an error recovery mechanism */ + if (p_sec_cback != NULL) bta_dm_sec_cb.p_sec_cback = p_sec_cback; + + btm_local_io_caps = btif_storage_get_local_io_caps(); +} + +/******************************************************************************* + * + * Function bta_dm_add_device + * + * Description This function adds a Link Key to an security database entry. + * It is normally called during host startup to restore all + * required information stored in the NVRAM. + ******************************************************************************/ +void bta_dm_add_device(std::unique_ptr msg) { + uint8_t* p_dc = NULL; + LinkKey* p_lc = NULL; + + /* If not all zeros, the device class has been specified */ + if (msg->dc_known) p_dc = (uint8_t*)msg->dc; + + if (msg->link_key_known) p_lc = &msg->link_key; + + auto add_result = get_btm_client_interface().security.BTM_SecAddDevice( + msg->bd_addr, p_dc, msg->bd_name, nullptr, p_lc, msg->key_type, + msg->pin_length); + if (!add_result) { + LOG(ERROR) << "BTA_DM: Error adding device " + << ADDRESS_TO_LOGGABLE_STR(msg->bd_addr); + } +} + +/** Bonds with peer device */ +void bta_dm_bond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) { + LOG_DEBUG("Bonding with peer device:%s type:%s transport:%s type:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + AddressTypeText(addr_type).c_str(), + bt_transport_text(transport).c_str(), + DeviceTypeText(device_type).c_str()); + + tBTA_DM_SEC sec_event; + const char* p_name; + + tBTM_STATUS status = get_btm_client_interface().security.BTM_SecBond( + bd_addr, addr_type, transport, device_type); + + if (bta_dm_sec_cb.p_sec_cback && (status != BTM_CMD_STARTED)) { + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + sec_event.auth_cmpl.bd_addr = bd_addr; + p_name = get_btm_client_interface().security.BTM_SecReadDevName(bd_addr); + if (p_name != NULL) { + memcpy(sec_event.auth_cmpl.bd_name, p_name, BD_NAME_LEN); + sec_event.auth_cmpl.bd_name[BD_NAME_LEN] = 0; + } + + /* taken care of by memset [above] + sec_event.auth_cmpl.key_present = false; + sec_event.auth_cmpl.success = false; + */ + sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND; + if (status == BTM_SUCCESS) { + sec_event.auth_cmpl.success = true; + } else { + /* delete this device entry from Sec Dev DB */ + bta_dm_remove_sec_dev_entry(bd_addr); + } + bta_dm_sec_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + } +} + +/** Cancels bonding with a peer device */ +void bta_dm_bond_cancel(const RawAddress& bd_addr) { + tBTM_STATUS status; + tBTA_DM_SEC sec_event; + + LOG_VERBOSE(" bta_dm_bond_cancel "); + + status = get_btm_client_interface().security.BTM_SecBondCancel(bd_addr); + + if (bta_dm_sec_cb.p_sec_cback && + (status != BTM_CMD_STARTED && status != BTM_SUCCESS)) { + sec_event.bond_cancel_cmpl.result = BTA_FAILURE; + + bta_dm_sec_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event); + } +} + +/** Send the pin_reply to a request from BTM */ +void bta_dm_pin_reply(std::unique_ptr msg) { + if (msg->accept) { + get_btm_client_interface().security.BTM_PINCodeReply( + msg->bd_addr, BTM_SUCCESS, msg->pin_len, msg->p_pin); + } else { + get_btm_client_interface().security.BTM_PINCodeReply( + msg->bd_addr, BTM_NOT_AUTHORIZED, 0, NULL); + } +} + +/** Send the user confirm request reply in response to a request from BTM */ +void bta_dm_confirm(const RawAddress& bd_addr, bool accept) { + get_btm_client_interface().security.BTM_ConfirmReqReply( + accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED, bd_addr); +} + +/** respond to the OOB data request for the remote device from BTM */ +void bta_dm_ci_rmt_oob_act(std::unique_ptr msg) { + get_btm_client_interface().security.BTM_RemoteOobDataReply( + msg->accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED, msg->bd_addr, msg->c, + msg->r); +} + +/******************************************************************************* + * + * Function bta_dm_pinname_cback + * + * Description Callback requesting pin_key + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_pinname_cback(const tBTM_REMOTE_DEV_NAME* p_data) { + tBTM_REMOTE_DEV_NAME* p_result = (tBTM_REMOTE_DEV_NAME*)p_data; + tBTA_DM_SEC sec_event; + uint32_t bytes_to_copy; + tBTA_DM_SEC_EVT event = bta_dm_sec_cb.pin_evt; + + if (BTA_DM_SP_CFM_REQ_EVT == event) { + /* Retrieved saved device class and bd_addr */ + sec_event.cfm_req.bd_addr = bta_dm_sec_cb.pin_bd_addr; + BTA_COPY_DEVICE_CLASS(sec_event.cfm_req.dev_class, bta_dm_sec_cb.pin_dev_class); + + if (p_result && p_result->status == BTM_SUCCESS) { + bytes_to_copy = + (p_result->length < BD_NAME_LEN) ? p_result->length : BD_NAME_LEN; + memcpy(sec_event.cfm_req.bd_name, p_result->remote_bd_name, + bytes_to_copy); + sec_event.pin_req.bd_name[BD_NAME_LEN] = 0; + } else /* No name found */ + sec_event.cfm_req.bd_name[0] = 0; + + sec_event.key_notif.passkey = + bta_dm_sec_cb.num_val; /* get PIN code numeric number */ + + /* 1 additional event data fields for this event */ + sec_event.cfm_req.just_works = bta_dm_sec_cb.just_works; + /* retrieve the loc and rmt caps */ + sec_event.cfm_req.loc_io_caps = bta_dm_sec_cb.loc_io_caps; + sec_event.cfm_req.rmt_io_caps = bta_dm_sec_cb.rmt_io_caps; + sec_event.cfm_req.loc_auth_req = bta_dm_sec_cb.loc_auth_req; + sec_event.cfm_req.rmt_auth_req = bta_dm_sec_cb.rmt_auth_req; + + } else { + /* Retrieved saved device class and bd_addr */ + sec_event.pin_req.bd_addr = bta_dm_sec_cb.pin_bd_addr; + BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, bta_dm_sec_cb.pin_dev_class); + + if (p_result && p_result->status == BTM_SUCCESS) { + bytes_to_copy = (p_result->length < BD_NAME_LEN) ? p_result->length + : (BD_NAME_LEN - 1); + memcpy(sec_event.pin_req.bd_name, p_result->remote_bd_name, + bytes_to_copy); + sec_event.pin_req.bd_name[BD_NAME_LEN] = 0; + } else /* No name found */ + sec_event.pin_req.bd_name[0] = 0; + + event = bta_dm_sec_cb.pin_evt; + sec_event.key_notif.passkey = + bta_dm_sec_cb.num_val; /* get PIN code numeric number */ + } + + if (bta_dm_sec_cb.p_sec_cback) bta_dm_sec_cb.p_sec_cback(event, &sec_event); +} + +/******************************************************************************* + * + * Function bta_dm_pin_cback + * + * Description Callback requesting pin_key + * + * Returns void + * + ******************************************************************************/ +static uint8_t bta_dm_pin_cback(const RawAddress& bd_addr, DEV_CLASS dev_class, + const tBTM_BD_NAME bd_name, bool min_16_digit) { + if (!bta_dm_sec_cb.p_sec_cback) return BTM_NOT_AUTHORIZED; + + /* If the device name is not known, save bdaddr and devclass and initiate a + * name request */ + if (bd_name[0] == 0) { + bta_dm_sec_cb.pin_evt = BTA_DM_PIN_REQ_EVT; + bta_dm_sec_cb.pin_bd_addr = bd_addr; + BTA_COPY_DEVICE_CLASS(bta_dm_sec_cb.pin_dev_class, dev_class); + if ((get_btm_client_interface().peer.BTM_ReadRemoteDeviceName( + bd_addr, bta_dm_pinname_cback, BT_TRANSPORT_BR_EDR)) == + BTM_CMD_STARTED) + return BTM_CMD_STARTED; + + LOG_WARN(" bta_dm_pin_cback() -> Failed to start Remote Name Request "); + } + + tBTA_DM_SEC sec_event = {.pin_req = { + .bd_addr = bd_addr, + }}; + BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, dev_class); + strlcpy((char*)sec_event.pin_req.bd_name, (char*)bd_name, BD_NAME_LEN + 1); + sec_event.pin_req.min_16_digit = min_16_digit; + + bta_dm_sec_cb.p_sec_cback(BTA_DM_PIN_REQ_EVT, &sec_event); + return BTM_CMD_STARTED; +} + +/******************************************************************************* + * + * Function bta_dm_new_link_key_cback + * + * Description Callback from BTM to notify new link key + * + * Returns void + * + ******************************************************************************/ +static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr, + UNUSED_ATTR DEV_CLASS dev_class, + tBTM_BD_NAME bd_name, + const LinkKey& key, uint8_t key_type, + bool is_ctkd) { + tBTA_DM_SEC sec_event; + tBTA_DM_AUTH_CMPL* p_auth_cmpl; + tBTA_DM_SEC_EVT event = BTA_DM_AUTH_CMPL_EVT; + + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + + p_auth_cmpl = &sec_event.auth_cmpl; + + p_auth_cmpl->bd_addr = bd_addr; + + memcpy(p_auth_cmpl->bd_name, bd_name, BD_NAME_LEN); + p_auth_cmpl->bd_name[BD_NAME_LEN] = 0; + p_auth_cmpl->key_present = true; + p_auth_cmpl->key_type = key_type; + p_auth_cmpl->success = true; + p_auth_cmpl->key = key; + p_auth_cmpl->is_ctkd = is_ctkd; + + sec_event.auth_cmpl.fail_reason = HCI_SUCCESS; + + // Report the BR link key based on the BR/EDR address and type + get_btm_client_interface().peer.BTM_ReadDevInfo( + bd_addr, &sec_event.auth_cmpl.dev_type, &sec_event.auth_cmpl.addr_type); + if (bta_dm_sec_cb.p_sec_cback) bta_dm_sec_cb.p_sec_cback(event, &sec_event); + + // Setting remove_dev_pending flag to false, where it will avoid deleting + // the + // security device record when the ACL connection link goes down in case of + // reconnection. + if (bta_dm_cb.device_list.count) + bta_dm_reset_sec_dev_pending(p_auth_cmpl->bd_addr); + + return BTM_CMD_STARTED; +} + +/******************************************************************************* + * + * Function bta_dm_authentication_complete_cback + * + * Description Authentication complete callback from BTM + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_authentication_complete_cback( + const RawAddress& bd_addr, UNUSED_ATTR DEV_CLASS dev_class, + tBTM_BD_NAME bd_name, tHCI_REASON reason) { + if (reason != HCI_SUCCESS) { + if (bta_dm_sec_cb.p_sec_cback) { + // Build out the security event data structure + tBTA_DM_SEC sec_event = { + .auth_cmpl = + { + .bd_addr = bd_addr, + }, + }; + memcpy(sec_event.auth_cmpl.bd_name, bd_name, BD_NAME_LEN); + sec_event.auth_cmpl.bd_name[BD_NAME_LEN] = 0; + + // Report the BR link key based on the BR/EDR address and type + get_btm_client_interface().peer.BTM_ReadDevInfo( + bd_addr, &sec_event.auth_cmpl.dev_type, + &sec_event.auth_cmpl.addr_type); + sec_event.auth_cmpl.fail_reason = reason; + + bta_dm_sec_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + } + + switch (reason) { + case HCI_ERR_AUTH_FAILURE: + case HCI_ERR_KEY_MISSING: + case HCI_ERR_HOST_REJECT_SECURITY: + case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE: + LOG_WARN( + "Deleting device record as authentication failed entry:%s " + "reason:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + hci_reason_code_text(reason).c_str()); + break; + + default: + break; + } + } +} + +/******************************************************************************* + * + * Function bta_dm_sp_cback + * + * Description simple pairing callback from BTM + * + * Returns void + * + ******************************************************************************/ +static tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, + tBTM_SP_EVT_DATA* p_data) { + tBTM_STATUS status = BTM_CMD_STARTED; + tBTA_DM_SEC sec_event = {}; + tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT; + + LOG_VERBOSE("bta_dm_sp_cback: %d", event); + if (!bta_dm_sec_cb.p_sec_cback) return BTM_NOT_AUTHORIZED; + + bool sp_rmt_result = false; + /* TODO_SP */ + switch (event) { + case BTM_SP_IO_REQ_EVT: + if (btm_local_io_caps != BTM_IO_CAP_NONE) { + /* translate auth_req */ + btif_dm_set_oob_for_io_req(&p_data->io_req.oob_data); + btif_dm_proc_io_req(&p_data->io_req.auth_req, p_data->io_req.is_orig); + } + LOG_VERBOSE("io mitm: %d oob_data:%d", p_data->io_req.auth_req, + p_data->io_req.oob_data); + break; + case BTM_SP_IO_RSP_EVT: + if (btm_local_io_caps != BTM_IO_CAP_NONE) { + btif_dm_proc_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap, + p_data->io_rsp.oob_data, p_data->io_rsp.auth_req); + } + break; + + case BTM_SP_CFM_REQ_EVT: + pin_evt = BTA_DM_SP_CFM_REQ_EVT; + bta_dm_sec_cb.just_works = sec_event.cfm_req.just_works = + p_data->cfm_req.just_works; + sec_event.cfm_req.loc_auth_req = p_data->cfm_req.loc_auth_req; + sec_event.cfm_req.rmt_auth_req = p_data->cfm_req.rmt_auth_req; + sec_event.cfm_req.loc_io_caps = p_data->cfm_req.loc_io_caps; + sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps; + + [[fallthrough]]; + /* Passkey entry mode, mobile device with output capability is very + unlikely to receive key request, so skip this event */ + /*case BTM_SP_KEY_REQ_EVT: */ + case BTM_SP_KEY_NOTIF_EVT: + if (btm_local_io_caps == BTM_IO_CAP_NONE && + BTM_SP_KEY_NOTIF_EVT == event) { + status = BTM_NOT_AUTHORIZED; + break; + } + + // TODO PleaseFix: This assignment only works with event + // BTM_SP_KEY_NOTIF_EVT + bta_dm_sec_cb.num_val = sec_event.key_notif.passkey = + p_data->key_notif.passkey; + + if (BTM_SP_CFM_REQ_EVT == event) { + /* Due to the switch case falling through below to + BTM_SP_KEY_NOTIF_EVT, + copy these values into key_notif from cfm_req */ + sec_event.key_notif.bd_addr = p_data->cfm_req.bd_addr; + dev_class_copy(sec_event.key_notif.dev_class, + p_data->cfm_req.dev_class); + bd_name_copy(sec_event.key_notif.bd_name, p_data->cfm_req.bd_name); + /* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT, + call remote name request using values from cfm_req */ + if (p_data->cfm_req.bd_name[0] == 0) { + bta_dm_sec_cb.pin_evt = pin_evt; + bta_dm_sec_cb.pin_bd_addr = p_data->cfm_req.bd_addr; + bta_dm_sec_cb.rmt_io_caps = sec_event.cfm_req.rmt_io_caps; + bta_dm_sec_cb.loc_io_caps = sec_event.cfm_req.loc_io_caps; + bta_dm_sec_cb.rmt_auth_req = sec_event.cfm_req.rmt_auth_req; + bta_dm_sec_cb.loc_auth_req = sec_event.cfm_req.loc_auth_req; + + dev_class_copy(bta_dm_sec_cb.pin_dev_class, p_data->cfm_req.dev_class); + { + const tBTM_STATUS btm_status = + get_btm_client_interface().peer.BTM_ReadRemoteDeviceName( + p_data->cfm_req.bd_addr, bta_dm_pinname_cback, + BT_TRANSPORT_BR_EDR); + switch (btm_status) { + case BTM_CMD_STARTED: + return btm_status; + default: + // NOTE: This will issue callback on this failure path + LOG_WARN("Failed to start Remote Name Request btm_status:%s", + btm_status_text(btm_status).c_str()); + }; + } + } + } + + if (BTM_SP_KEY_NOTIF_EVT == event) { + /* If the device name is not known, save bdaddr and devclass + and initiate a name request with values from key_notif */ + if (p_data->key_notif.bd_name[0] == 0) { + bta_dm_sec_cb.pin_evt = pin_evt; + bta_dm_sec_cb.pin_bd_addr = p_data->key_notif.bd_addr; + BTA_COPY_DEVICE_CLASS(bta_dm_sec_cb.pin_dev_class, + p_data->key_notif.dev_class); + if ((get_btm_client_interface().peer.BTM_ReadRemoteDeviceName( + p_data->key_notif.bd_addr, bta_dm_pinname_cback, + BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) + return BTM_CMD_STARTED; + LOG_WARN( + " bta_dm_sp_cback() -> Failed to start Remote Name Request "); + } else { + sec_event.key_notif.bd_addr = p_data->key_notif.bd_addr; + BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class, + p_data->key_notif.dev_class); + strlcpy((char*)sec_event.key_notif.bd_name, + (char*)p_data->key_notif.bd_name, BD_NAME_LEN + 1); + sec_event.key_notif.bd_name[BD_NAME_LEN] = 0; + } + } + + bta_dm_sec_cb.p_sec_cback(pin_evt, &sec_event); + + break; + + case BTM_SP_LOC_OOB_EVT: +#ifdef BTIF_DM_OOB_TEST + btif_dm_proc_loc_oob(BT_TRANSPORT_BR_EDR, + (bool)(p_data->loc_oob.status == BTM_SUCCESS), + p_data->loc_oob.c, p_data->loc_oob.r); +#endif + break; + + case BTM_SP_RMT_OOB_EVT: { + Octet16 c; + Octet16 r; + sp_rmt_result = false; +#ifdef BTIF_DM_OOB_TEST + sp_rmt_result = btif_dm_proc_rmt_oob(p_data->rmt_oob.bd_addr, &c, &r); +#endif + LOG_VERBOSE("bta_dm_ci_rmt_oob: result=%d", sp_rmt_result); + bta_dm_ci_rmt_oob(sp_rmt_result, p_data->rmt_oob.bd_addr, c, r); + break; + } + + default: + status = BTM_NOT_AUTHORIZED; + break; + } + LOG_VERBOSE("dm status: %d", status); + return status; +} + +/******************************************************************************* + * + * Function bta_dm_reset_sec_dev_pending + * + * Description Setting the remove device pending status to false from + * security device DB, when the link key notification + * event comes. + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_reset_sec_dev_pending(const RawAddress& remote_bd_addr) { + for (size_t i = 0; i < bta_dm_cb.device_list.count; i++) { + auto& dev = bta_dm_cb.device_list.peer_device[i]; + if (dev.peer_bdaddr == remote_bd_addr) { + if (dev.remove_dev_pending) { + LOG_INFO("Clearing remove_dev_pending for %s", + ADDRESS_TO_LOGGABLE_CSTR(dev.peer_bdaddr)); + dev.remove_dev_pending = false; + } + return; + } + } +} + +/******************************************************************************* + * + * Function bta_dm_remove_sec_dev_entry + * + * Description Removes device entry from Security device DB if ACL + connection with + * remtoe device does not exist, else schedule for dev entry + removal upon + ACL close + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_remove_sec_dev_entry(const RawAddress& remote_bd_addr) { + if (get_btm_client_interface().peer.BTM_IsAclConnectionUp(remote_bd_addr, + BT_TRANSPORT_LE) || + get_btm_client_interface().peer.BTM_IsAclConnectionUp( + remote_bd_addr, BT_TRANSPORT_BR_EDR)) { + LOG_VERBOSE("%s ACL is not down. Schedule for Dev Removal when ACL closes", + __func__); + get_btm_client_interface().security.BTM_SecClearSecurityFlags( + remote_bd_addr); + for (int i = 0; i < bta_dm_cb.device_list.count; i++) { + auto& dev = bta_dm_cb.device_list.peer_device[i]; + if (dev.peer_bdaddr == remote_bd_addr) { + LOG_INFO("Setting remove_dev_pending for %s", + ADDRESS_TO_LOGGABLE_CSTR(dev.peer_bdaddr)); + dev.remove_dev_pending = TRUE; + break; + } + } + } else { + // remote_bd_addr comes from security record, which is removed in + // BTM_SecDeleteDevice. + RawAddress addr_copy = remote_bd_addr; + bta_dm_process_remove_device_no_callback(addr_copy); + } +} + +/******************************************************************************* + * + * Function bta_dm_bond_cancel_complete_cback + * + * Description Authentication complete callback from BTM + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result) { + tBTA_DM_SEC sec_event; + + if (result == BTM_SUCCESS) + sec_event.bond_cancel_cmpl.result = BTA_SUCCESS; + else + sec_event.bond_cancel_cmpl.result = BTA_FAILURE; + + if (bta_dm_sec_cb.p_sec_cback) { + bta_dm_sec_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event); + } +} + +static void ble_io_req(const RawAddress& bd_addr, tBTM_IO_CAP* p_io_cap, + tBTM_OOB_DATA* p_oob_data, tBTM_LE_AUTH_REQ* p_auth_req, + uint8_t* p_max_key_size, tBTM_LE_KEY_TYPE* p_init_key, + tBTM_LE_KEY_TYPE* p_resp_key) { + /* Retrieve the properties from file system if possible */ + tBTE_APPL_CFG nv_config; + if (btif_dm_get_smp_config(&nv_config)) bte_appl_cfg = nv_config; + + /* *p_auth_req by default is false for devices with NoInputNoOutput; true for + * other devices. */ + + if (bte_appl_cfg.ble_auth_req) + *p_auth_req = bte_appl_cfg.ble_auth_req | + (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04); + + /* if OOB is not supported, this call-out function does not need to do + * anything + * otherwise, look for the OOB data associated with the address and set + * *p_oob_data accordingly. + * If the answer can not be obtained right away, + * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the + * answer is available. + */ + + btif_dm_set_oob_for_le_io_req(bd_addr, p_oob_data, p_auth_req); + + if (bte_appl_cfg.ble_io_cap <= 4) + *p_io_cap = static_cast(bte_appl_cfg.ble_io_cap); + + if (bte_appl_cfg.ble_init_key <= BTM_BLE_INITIATOR_KEY_SIZE) + *p_init_key = bte_appl_cfg.ble_init_key; + + if (bte_appl_cfg.ble_resp_key <= BTM_BLE_RESPONDER_KEY_SIZE) + *p_resp_key = bte_appl_cfg.ble_resp_key; + + if (bte_appl_cfg.ble_max_key_size > 7 && bte_appl_cfg.ble_max_key_size <= 16) + *p_max_key_size = bte_appl_cfg.ble_max_key_size; +} + +/******************************************************************************* + * + * Function bta_dm_ble_smp_cback + * + * Description Callback for BLE SMP + * + * + * Returns void + * + ******************************************************************************/ +static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, const RawAddress& bda, + tBTM_LE_EVT_DATA* p_data) { + tBTM_STATUS status = BTM_SUCCESS; + tBTA_DM_SEC sec_event; + const char* p_name = NULL; + + if (!bta_dm_sec_cb.p_sec_cback) return BTM_NOT_AUTHORIZED; + + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + switch (event) { + case BTM_LE_IO_REQ_EVT: + ble_io_req(bda, &p_data->io_req.io_cap, &p_data->io_req.oob_data, + &p_data->io_req.auth_req, &p_data->io_req.max_key_size, + &p_data->io_req.init_keys, &p_data->io_req.resp_keys); + LOG_VERBOSE("io mitm: %d oob_data:%d", p_data->io_req.auth_req, + p_data->io_req.oob_data); + break; + + case BTM_LE_CONSENT_REQ_EVT: + sec_event.ble_req.bd_addr = bda; + p_name = get_btm_client_interface().security.BTM_SecReadDevName(bda); + if (p_name != NULL) + strlcpy((char*)sec_event.ble_req.bd_name, p_name, BD_NAME_LEN); + else + sec_event.ble_req.bd_name[0] = 0; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_CONSENT_REQ_EVT, &sec_event); + break; + + case BTM_LE_SEC_REQUEST_EVT: + sec_event.ble_req.bd_addr = bda; + p_name = get_btm_client_interface().security.BTM_SecReadDevName(bda); + if (p_name != NULL) + strlcpy((char*)sec_event.ble_req.bd_name, p_name, BD_NAME_LEN + 1); + else + sec_event.ble_req.bd_name[0] = 0; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_SEC_REQ_EVT, &sec_event); + break; + + case BTM_LE_KEY_NOTIF_EVT: + sec_event.key_notif.bd_addr = bda; + p_name = get_btm_client_interface().security.BTM_SecReadDevName(bda); + if (p_name != NULL) + strlcpy((char*)sec_event.key_notif.bd_name, p_name, BD_NAME_LEN + 1); + else + sec_event.key_notif.bd_name[0] = 0; + sec_event.key_notif.passkey = p_data->key_notif; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_NOTIF_EVT, &sec_event); + break; + + case BTM_LE_KEY_REQ_EVT: + sec_event.ble_req.bd_addr = bda; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_REQ_EVT, &sec_event); + break; + + case BTM_LE_OOB_REQ_EVT: + sec_event.ble_req.bd_addr = bda; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_OOB_REQ_EVT, &sec_event); + break; + + case BTM_LE_NC_REQ_EVT: + sec_event.key_notif.bd_addr = bda; + // TODO: get rid of this + strlcpy((char*)sec_event.key_notif.bd_name, bta_dm_get_remname(), + (BD_NAME_LEN + 1)); + sec_event.key_notif.passkey = p_data->key_notif; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_NC_REQ_EVT, &sec_event); + break; + + case BTM_LE_SC_OOB_REQ_EVT: + sec_event.ble_req.bd_addr = bda; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_SC_OOB_REQ_EVT, &sec_event); + break; + + case BTM_LE_SC_LOC_OOB_EVT: + tBTA_DM_LOC_OOB_DATA local_oob_data; + local_oob_data.local_oob_c = p_data->local_oob_data.commitment; + local_oob_data.local_oob_r = p_data->local_oob_data.randomizer; + sec_event.local_oob_data = local_oob_data; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_SC_CR_LOC_OOB_EVT, &sec_event); + break; + + case BTM_LE_KEY_EVT: + sec_event.ble_key.bd_addr = bda; + sec_event.ble_key.key_type = p_data->key.key_type; + sec_event.ble_key.p_key_value = p_data->key.p_key_value; + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event); + break; + + case BTM_LE_COMPLT_EVT: + sec_event.auth_cmpl.bd_addr = bda; + get_btm_client_interface().peer.BTM_ReadDevInfo( + bda, &sec_event.auth_cmpl.dev_type, &sec_event.auth_cmpl.addr_type); + p_name = get_btm_client_interface().security.BTM_SecReadDevName(bda); + if (p_name != NULL) + strlcpy((char*)sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN + 1)); + else + sec_event.auth_cmpl.bd_name[0] = 0; + + if (p_data->complt.reason != HCI_SUCCESS) { + // TODO This is not a proper use of this type + sec_event.auth_cmpl.fail_reason = + static_cast(BTA_DM_AUTH_CONVERT_SMP_CODE( + (static_cast(p_data->complt.reason)))); + + if (btm_sec_is_a_bonded_dev(bda) && + p_data->complt.reason == SMP_CONN_TOUT && + !p_data->complt.smp_over_br) { + // Bonded device failed to encrypt - to test this remove battery from + // HID device right after connection, but before encryption is + // established + LOG(INFO) << __func__ + << ": bonded device disconnected when encrypting - no " + "reason to unbond"; + } else { + /* delete this device entry from Sec Dev DB */ + bta_dm_remove_sec_dev_entry(bda); + } + + } else { + sec_event.auth_cmpl.success = true; + if (!p_data->complt.smp_over_br) + GATT_ConfigServiceChangeCCC(bda, true, BT_TRANSPORT_LE); + } + + if (bta_dm_sec_cb.p_sec_cback) { + // bta_dm_sec_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + bta_dm_sec_cb.p_sec_cback(BTA_DM_BLE_AUTH_CMPL_EVT, &sec_event); + } + break; + + case BTM_LE_ADDR_ASSOC_EVT: + sec_event.proc_id_addr.pairing_bda = bda; + sec_event.proc_id_addr.id_addr = p_data->id_addr; + bta_dm_sec_cb.p_sec_cback(BTA_DM_LE_ADDR_ASSOC_EVT, &sec_event); + break; + + default: + status = BTM_NOT_AUTHORIZED; + break; + } + return status; +} + +/******************************************************************************* + * + * Function bta_dm_encrypt_cback + * + * Description link encryption complete callback. + * + * Returns None + * + ******************************************************************************/ +void bta_dm_encrypt_cback(const RawAddress* bd_addr, tBT_TRANSPORT transport, + UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) { + tBTA_DM_ENCRYPT_CBACK* p_callback = nullptr; + tBTA_DM_PEER_DEVICE* device = find_connected_device(*bd_addr, transport); + if (device != nullptr) { + p_callback = device->p_encrypt_cback; + device->p_encrypt_cback = nullptr; + } + + tBTA_STATUS bta_status = BTA_SUCCESS; + switch (result) { + case BTM_SUCCESS: + LOG_WARN("Encrypted link peer:%s transport:%s status:%s callback:%c", + ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), + bt_transport_text(transport).c_str(), + btm_status_text(result).c_str(), (p_callback) ? 'T' : 'F'); + break; + case BTM_WRONG_MODE: + LOG_WARN( + "Unable to encrypt link peer:%s transport:%s status:%s callback:%c", + ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), + bt_transport_text(transport).c_str(), btm_status_text(result).c_str(), + (p_callback) ? 'T' : 'F'); + bta_status = BTA_WRONG_MODE; + break; + case BTM_NO_RESOURCES: + LOG_WARN( + "Unable to encrypt link peer:%s transport:%s status:%s callback:%c", + ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), + bt_transport_text(transport).c_str(), btm_status_text(result).c_str(), + (p_callback) ? 'T' : 'F'); + bta_status = BTA_NO_RESOURCES; + break; + case BTM_BUSY: + LOG_WARN( + "Unable to encrypt link peer:%s transport:%s status:%s callback:%c", + ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), + bt_transport_text(transport).c_str(), btm_status_text(result).c_str(), + (p_callback) ? 'T' : 'F'); + bta_status = BTA_BUSY; + break; + default: + LOG_ERROR( + "Failed to encrypt link peer:%s transport:%s status:%s callback:%c", + ADDRESS_TO_LOGGABLE_CSTR((*bd_addr)), + bt_transport_text(transport).c_str(), btm_status_text(result).c_str(), + (p_callback) ? 'T' : 'F'); + bta_status = BTA_FAILURE; + break; + } + if (p_callback) { + (*p_callback)(*bd_addr, transport, bta_status); + } +} + +/**This function to encrypt the link */ +void bta_dm_set_encryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, + tBTA_DM_ENCRYPT_CBACK* p_callback, + tBTM_BLE_SEC_ACT sec_act) { + if (p_callback == nullptr) { + LOG_ERROR("bta_dm_set_encryption callback is not provided"); + return; + } + + tBTA_DM_PEER_DEVICE* device = find_connected_device(bd_addr, transport); + if (device == nullptr) { + LOG_ERROR("Unable to find active ACL connection device:%s transport:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + bt_transport_text(transport).c_str()); + return; + } + + if (device->p_encrypt_cback) { + LOG_ERROR( + "Unable to start encryption as already in progress peer:%s " + "transport:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + bt_transport_text(transport).c_str()); + (*p_callback)(bd_addr, transport, BTA_BUSY); + return; + } + + if (get_btm_client_interface().security.BTM_SetEncryption( + bd_addr, transport, bta_dm_encrypt_cback, NULL, sec_act) == + BTM_CMD_STARTED) { + device->p_encrypt_cback = p_callback; + LOG_DEBUG("Started encryption peer:%s transport:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + bt_transport_text(transport).c_str()); + } else { + LOG_ERROR("Unable to start encryption process peer:%s transport:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + bt_transport_text(transport).c_str()); + } +} + +/******************************************************************************* + * + * Function bta_dm_ble_id_key_cback + * + * Description Callback for BLE local ID keys + * + * + * Returns void + * + ******************************************************************************/ +static void bta_dm_ble_id_key_cback(uint8_t key_type, + tBTM_BLE_LOCAL_KEYS* p_key) { + switch (key_type) { + case BTM_BLE_KEY_TYPE_ID: + case BTM_BLE_KEY_TYPE_ER: + if (bta_dm_sec_cb.p_sec_cback) { + tBTA_DM_SEC dm_key = { + .ble_id_keys = {}, + }; + memcpy(&dm_key.ble_id_keys, p_key, sizeof(tBTM_BLE_LOCAL_KEYS)); + + tBTA_DM_SEC_EVT evt = (key_type == BTM_BLE_KEY_TYPE_ID) + ? BTA_DM_BLE_LOCAL_IR_EVT + : BTA_DM_BLE_LOCAL_ER_EVT; + bta_dm_sec_cb.p_sec_cback(evt, &dm_key); + } + break; + + default: + LOG_VERBOSE("Unknown key type %d", key_type); + break; + } + return; +} + +/******************************************************************************* + * + * Function bta_dm_sirk_verifiction_cback + * + * Description SIRK verification when pairing CSIP set member. + * + * Returns void + * + ******************************************************************************/ +static uint8_t bta_dm_sirk_verifiction_cback(const RawAddress& bd_addr) { + tBTA_DM_SEC sec_event = {.ble_req = { + .bd_addr = bd_addr, + }}; + + if (bta_dm_sec_cb.p_sec_sirk_cback) { + LOG_DEBUG("callback called"); + bta_dm_sec_cb.p_sec_sirk_cback(BTA_DM_SIRK_VERIFICATION_REQ_EVT, &sec_event); + return BTM_CMD_STARTED; + } + + LOG_DEBUG("no callback registered"); + + return BTM_SUCCESS_NO_SECURITY; +} + +/******************************************************************************* + * + * Function bta_dm_add_blekey + * + * Description This function adds a BLE Key to an security database entry. + * This function shall only be called AFTER BTA_DmAddBleDevice + * has been called. + * It is normally called during host startup to restore all + * required information stored in the NVRAM. + * + * Parameters: + * + ******************************************************************************/ +void bta_dm_add_blekey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE blekey, + tBTM_LE_KEY_TYPE key_type) { + get_btm_client_interface().security.BTM_SecAddBleKey( + bd_addr, (tBTM_LE_KEY_VALUE*)&blekey, key_type); +} + +/******************************************************************************* + * + * Function bta_dm_add_ble_device + * + * Description This function adds a BLE device to an security database + * entry. + * It is normally called during host startup to restore all + * required information stored in the NVRAM. + * + * Parameters: + * + ******************************************************************************/ +void bta_dm_add_ble_device(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_DEVICE_TYPE dev_type) { + get_btm_client_interface().security.BTM_SecAddBleDevice(bd_addr, dev_type, + addr_type); +} + +/******************************************************************************* + * + * Function bta_dm_add_ble_device + * + * Description This function adds a BLE device to an security database + * entry. + * It is normally called during host startup to restore all + * required information stored in the NVRAM. + * + * Parameters: + * + ******************************************************************************/ +void bta_dm_ble_passkey_reply(const RawAddress& bd_addr, bool accept, + uint32_t passkey) { + get_btm_client_interface().ble.BTM_BlePasskeyReply( + bd_addr, accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED, passkey); +} + +/** This is response to SM numeric comparison request submitted to application. + */ +void bta_dm_ble_confirm_reply(const RawAddress& bd_addr, bool accept) { + get_btm_client_interface().ble.BTM_BleConfirmReply( + bd_addr, accept ? BTM_SUCCESS : BTM_NOT_AUTHORIZED); +} + +/** This function set the local device LE privacy settings. */ +void bta_dm_ble_config_local_privacy(bool privacy_enable) { + BTM_BleConfigPrivacy(privacy_enable); +} + +namespace bluetooth { +namespace legacy { +namespace testing { +void btm_set_local_io_caps(uint8_t io_caps) { ::btm_local_io_caps = io_caps; } + +tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data) { + return ::bta_dm_sp_cback(event, p_data); +} + +} // namespace testing +} // namespace legacy +} // namespace bluetooth diff --git a/system/bta/dm/bta_dm_sec_api.cc b/system/bta/dm/bta_dm_sec_api.cc new file mode 100644 index 0000000000000000000000000000000000000000..969586853628c8da03c84c3b63a3c2b8513a5912 --- /dev/null +++ b/system/bta/dm/bta_dm_sec_api.cc @@ -0,0 +1,377 @@ +/****************************************************************************** + * + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the API implementation file for the BTA device manager. + * + ******************************************************************************/ + +#include + +#include "android_bluetooth_flags.h" +#include "bta/dm/bta_dm_sec_int.h" +#include "stack/btm/btm_sec.h" +#include "stack/include/bt_octets.h" +#include "stack/include/btm_ble_sec_api.h" +#include "stack/include/main_thread.h" +#include "types/raw_address.h" + +/** This function initiates a bonding procedure with a peer device */ +void BTA_DmBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_bond(bd_addr, addr_type, transport, device_type); + } else { + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_bond, bd_addr, addr_type, + transport, device_type)); + } +} + +/** This function cancels the bonding procedure with a peer device + */ +void BTA_DmBondCancel(const RawAddress& bd_addr) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_bond_cancel(bd_addr); + } else { + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_bond_cancel, bd_addr)); + } +} + +/******************************************************************************* + * + * Function BTA_DmPinReply + * + * Description This function provides a pincode for a remote device when + * one is requested by DM through BTA_DM_PIN_REQ_EVT + * + * + * Returns void + * + ******************************************************************************/ +void BTA_DmPinReply(const RawAddress& bd_addr, bool accept, uint8_t pin_len, + uint8_t* p_pin) { + std::unique_ptr msg = + std::make_unique(); + + msg->bd_addr = bd_addr; + msg->accept = accept; + if (accept) { + msg->pin_len = pin_len; + memcpy(msg->p_pin, p_pin, pin_len); + } + + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_pin_reply(std::move(msg)); + } else { + do_in_main_thread(FROM_HERE, + base::Bind(bta_dm_pin_reply, base::Passed(&msg))); + } +} + +/******************************************************************************* + * + * Function BTA_DmLocalOob + * + * Description This function retrieves the OOB data from local controller. + * The result is reported by: + * - bta_dm_co_loc_oob_ext() if device supports secure + * connections (SC) + * - bta_dm_co_loc_oob() if device doesn't support SC + * + * Returns void + * + ******************************************************************************/ +void BTA_DmLocalOob(void) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + BTM_ReadLocalOobData(); + } else { + do_in_main_thread(FROM_HERE, base::BindOnce(BTM_ReadLocalOobData)); + } +} + +/******************************************************************************* + * + * Function BTA_DmConfirm + * + * Description This function accepts or rejects the numerical value of the + * Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT + * + * Returns void + * + ******************************************************************************/ +void BTA_DmConfirm(const RawAddress& bd_addr, bool accept) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_confirm(bd_addr, accept); + } else { + do_in_main_thread(FROM_HERE, + base::BindOnce(bta_dm_confirm, bd_addr, accept)); + } +} + +/******************************************************************************* + * + * Function BTA_DmAddDevice + * + * Description This function adds a device to the security database list of + * peer device + * + * + * Returns void + * + ******************************************************************************/ +void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, + const LinkKey& link_key, uint8_t key_type, + uint8_t pin_length) { + std::unique_ptr msg = + std::make_unique(); + + msg->bd_addr = bd_addr; + msg->link_key_known = true; + msg->key_type = key_type; + msg->link_key = link_key; + + /* Load device class if specified */ + if (dev_class) { + msg->dc_known = true; + memcpy(msg->dc, dev_class, DEV_CLASS_LEN); + } + + memset(msg->bd_name, 0, BD_NAME_LEN + 1); + msg->pin_length = pin_length; + + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_add_device(std::move(msg)); + } else { + do_in_main_thread(FROM_HERE, + base::Bind(bta_dm_add_device, base::Passed(&msg))); + } +} + +/** This function removes a device fromthe security database list of peer + * device. It manages unpairing even while connected */ +tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_remove_device(bd_addr); + } else { + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_remove_device, bd_addr)); + } + return BTA_SUCCESS; +} + +/******************************************************************************* + * + * Function BTA_DmAddBleKey + * + * Description Add/modify LE device information. This function will be + * normally called during host startup to restore all required + * information stored in the NVRAM. + * + * Parameters: bd_addr - BD address of the peer + * p_le_key - LE key values. + * key_type - LE SMP key type. + * + * Returns BTA_SUCCESS if successful + * BTA_FAIL if operation failed. + * + ******************************************************************************/ +void BTA_DmAddBleKey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE* p_le_key, + tBTM_LE_KEY_TYPE key_type) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_add_blekey(bd_addr, *p_le_key, key_type); + } else { + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_add_blekey, bd_addr, + *p_le_key, key_type)); + } +} + +/******************************************************************************* + * + * Function BTA_DmAddBleDevice + * + * Description Add a BLE device. This function will be normally called + * during host startup to restore all required information + * for a LE device stored in the NVRAM. + * + * Parameters: bd_addr - BD address of the peer + * dev_type - Remote device's device type. + * addr_type - LE device address type. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmAddBleDevice(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_DEVICE_TYPE dev_type) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_add_ble_device(bd_addr, addr_type, dev_type); + } else { + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_add_ble_device, bd_addr, + addr_type, dev_type)); + } +} + +/******************************************************************************* + * + * Function BTA_DmBlePasskeyReply + * + * Description Send BLE SMP passkey reply. + * + * Parameters: bd_addr - BD address of the peer + * accept - passkey entry successful or declined. + * passkey - passkey value, must be a 6 digit number, + * can be lead by 0. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmBlePasskeyReply(const RawAddress& bd_addr, bool accept, + uint32_t passkey) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_ble_passkey_reply(bd_addr, accept, accept ? passkey : 0); + } else { + do_in_main_thread(FROM_HERE, + base::BindOnce(bta_dm_ble_passkey_reply, bd_addr, accept, + accept ? passkey : 0)); + } +} + +/******************************************************************************* + * + * Function BTA_DmBleConfirmReply + * + * Description Send BLE SMP SC user confirmation reply. + * + * Parameters: bd_addr - BD address of the peer + * accept - numbers to compare are the same or + * different. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmBleConfirmReply(const RawAddress& bd_addr, bool accept) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_ble_confirm_reply(bd_addr, accept); + } else { + do_in_main_thread( + FROM_HERE, base::BindOnce(bta_dm_ble_confirm_reply, bd_addr, accept)); + } +} + +/******************************************************************************* + * + * Function BTA_DmBleSecurityGrant + * + * Description Grant security request access. + * + * Parameters: bd_addr - BD address of the peer + * res - security grant status. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmBleSecurityGrant(const RawAddress& bd_addr, + tBTA_DM_BLE_SEC_GRANT res) { + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + BTM_SecurityGrant(bd_addr, res); + } else { + do_in_main_thread(FROM_HERE, + base::BindOnce(BTM_SecurityGrant, bd_addr, res)); + } +} + +/******************************************************************************* + * + * Function BTA_DmSetEncryption + * + * Description This function is called to ensure that connection is + * encrypted. Should be called only on an open connection. + * Typically only needed for connections that first want to + * bring up unencrypted links, then later encrypt them. + * + * Parameters: bd_addr - Address of the peer device + * transport - transport of the link to be encruypted + * p_callback - Pointer to callback function to indicat the + * link encryption status + * sec_act - This is the security action to indicate + * what kind of BLE security level is required + * for the BLE link if BLE is supported. + * Note: This parameter is ignored for the + * BR/EDR or if BLE is not supported. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmSetEncryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, + tBTA_DM_ENCRYPT_CBACK* p_callback, + tBTM_BLE_SEC_ACT sec_act) { + LOG_VERBOSE("%s", __func__); + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_set_encryption(bd_addr, transport, p_callback, sec_act); + } else { + do_in_main_thread(FROM_HERE, + base::BindOnce(bta_dm_set_encryption, bd_addr, transport, + p_callback, sec_act)); + } +} + +/******************************************************************************* + * + * Function BTA_DmSirkSecCbRegister + * + * Description This procedure registeres in requested a callback for + * verification by CSIP potential set member. + * + * Parameters p_cback - callback to member verificator + * + * Returns void + * + ******************************************************************************/ +void BTA_DmSirkSecCbRegister(tBTA_DM_SEC_CBACK* p_cback) { + LOG_DEBUG(""); + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_ble_sirk_sec_cb_register(p_cback); + } else { + do_in_main_thread(FROM_HERE, + base::BindOnce(bta_dm_ble_sirk_sec_cb_register, p_cback)); + } +} + +/******************************************************************************* + * + * Function BTA_DmSirkConfirmDeviceReply + * + * Description This procedure confirms requested to validate set device. + * + * Parameters bd_addr - BD address of the peer + * accept - True if device is authorized by CSIP, false + * otherwise. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmSirkConfirmDeviceReply(const RawAddress& bd_addr, bool accept) { + LOG_DEBUG(""); + if (IS_FLAG_ENABLED(synchronous_bta_sec)) { + bta_dm_ble_sirk_confirm_device_reply(bd_addr, accept); + } else { + do_in_main_thread( + FROM_HERE, + base::BindOnce(bta_dm_ble_sirk_confirm_device_reply, bd_addr, accept)); + } +} + diff --git a/system/bta/dm/bta_dm_sec_int.h b/system/bta/dm/bta_dm_sec_int.h new file mode 100644 index 0000000000000000000000000000000000000000..1b17655ecff1677c5ba8b38a43b7f3dcd6e1f547 --- /dev/null +++ b/system/bta/dm/bta_dm_sec_int.h @@ -0,0 +1,105 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "bta/include/bta_api.h" +#include "bta/include/bta_sec_api.h" +#include "osi/include/osi.h" // UNUSED_ATTR + +typedef struct { + RawAddress bd_addr; + bool accept; + uint8_t pin_len; + uint8_t p_pin[PIN_CODE_LEN]; +} tBTA_DM_API_PIN_REPLY; + +typedef struct { + BT_HDR_RIGID hdr; + RawAddress bd_addr; + tBTM_IO_CAP io_cap; + tBTM_OOB_DATA oob_data; + tBTM_AUTH_REQ auth_req; +} tBTA_DM_CI_IO_REQ; + +typedef struct { + RawAddress bd_addr; + Octet16 c; + Octet16 r; + bool accept; +} tBTA_DM_CI_RMT_OOB; + +typedef struct { + RawAddress bd_addr; + DEV_CLASS dc; + LinkKey link_key; + uint8_t key_type; + bool link_key_known; + bool dc_known; + BD_NAME bd_name; + uint8_t pin_length; +} tBTA_DM_API_ADD_DEVICE; + +typedef struct { + tBTA_DM_SEC_CBACK* p_sec_cback; + tBTA_DM_SEC_CBACK* p_sec_sirk_cback; +/* Storage for pin code request parameters */ + RawAddress pin_bd_addr; + DEV_CLASS pin_dev_class; + tBTA_DM_SEC_EVT pin_evt; + tBTM_IO_CAP loc_io_caps; /* IO Capabilities of local device */ + tBTM_IO_CAP rmt_io_caps; /* IO Capabilities of remote device */ + tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */ + tBTM_AUTH_REQ rmt_auth_req; + uint32_t num_val; /* the numeric value for comparison. If just_works, do not + show this number to UI */ + bool just_works; /* true, if "Just Works" association model */ +} tBTA_DM_SEC_CB; + +extern tBTA_DM_SEC_CB bta_dm_sec_cb; + +void bta_dm_sec_enable(tBTA_DM_SEC_CBACK* p_sec_cback); +void btm_sec_on_hw_on(); + +void bta_dm_add_ble_device(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_DEVICE_TYPE dev_type); +void bta_dm_add_blekey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE blekey, + tBTM_LE_KEY_TYPE key_type); +void bta_dm_add_device(std::unique_ptr msg); +void bta_dm_ble_config_local_privacy(bool privacy_enable); +void bta_dm_ble_confirm_reply(const RawAddress& bd_addr, bool accept); +void bta_dm_ble_passkey_reply(const RawAddress& bd_addr, bool accept, + uint32_t passkey); +void bta_dm_ble_sirk_confirm_device_reply(const RawAddress& bd_addr, + bool accept); +void bta_dm_ble_sirk_sec_cb_register(tBTA_DM_SEC_CBACK* p_cback); +void bta_dm_bond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type); +void bta_dm_bond_cancel(const RawAddress& bd_addr); +void bta_dm_remove_device(const RawAddress& bd_addr); +void bta_dm_ci_rmt_oob_act(std::unique_ptr msg); +void bta_dm_confirm(const RawAddress& bd_addr, bool accept); +void bta_dm_consolidate(const RawAddress& identity_addr, const RawAddress& rpa); +void bta_dm_enable(tBTA_DM_SEC_CBACK* p_sec_cback); +void bta_dm_encrypt_cback(const RawAddress* bd_addr, tBT_TRANSPORT transport, + UNUSED_ATTR void* p_ref_data, tBTM_STATUS result); +void bta_dm_pin_reply(std::unique_ptr msg); +void bta_dm_set_encryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, + tBTA_DM_ENCRYPT_CBACK* p_callback, + tBTM_BLE_SEC_ACT sec_act); +void btm_dm_sec_init(); diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc index 087b537630169aca624e8973516572ef8910abe2..c925eacde5a2766d3d4af0c5388c9baedc17e85a 100644 --- a/system/bta/gatt/bta_gattc_act.cc +++ b/system/bta/gatt/bta_gattc_act.cc @@ -29,22 +29,20 @@ #include #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/gatt/bta_gattc_int.h" -#include "bta/hh/bta_hh_int.h" +#include "bta/include/bta_api.h" #include "btif/include/btif_debug_conn.h" -#include "btif/include/core_callbacks.h" -#include "btif/include/stack_manager.h" #include "device/include/controller.h" -#include "device/include/interop.h" -#include "main/shim/dumpsys.h" +#include "hardware/bt_gatt_types.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_ble_api_types.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/btm_sec_api.h" #include "stack/include/l2c_api.h" +#include "stack/include/main_thread.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -205,7 +203,7 @@ void bta_gattc_register(const Uuid& app_uuid, tBTA_GATTC_CBACK* p_cback, +client_if, app_uuid.ToString().c_str()); do_in_main_thread(FROM_HERE, - base::Bind(&bta_gattc_start_if, client_if)); + base::BindOnce(&bta_gattc_start_if, client_if)); status = GATT_SUCCESS; break; @@ -418,8 +416,9 @@ static void bta_gattc_init_bk_conn(const tBTA_GATTC_API_OPEN* p_data, p_data->connection_type, p_data->transport, false)) { LOG_ERROR("Unable to connect to remote bd_addr=%s", ADDRESS_TO_LOGGABLE_CSTR(p_data->remote_bda)); - bta_gattc_send_open_cback(p_clreg, GATT_ERROR, p_data->remote_bda, - GATT_INVALID_CONN_ID, BT_TRANSPORT_LE, 0); + bta_gattc_send_open_cback(p_clreg, GATT_ILLEGAL_PARAMETER, + p_data->remote_bda, GATT_INVALID_CONN_ID, + BT_TRANSPORT_LE, 0); return; } @@ -551,7 +550,7 @@ void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { if (!db.IsEmpty()) p_clcb->p_srcb->gatt_database = db; if (db.IsEmpty() || - robust_caching_support == RobustCachingSupport::SUPPORTED) { + robust_caching_support != RobustCachingSupport::UNSUPPORTED) { // If the peer device is expected to support robust caching, or if we // don't know its services yet, then we should do discovery (which may // short-circuit through a hash match, but might also do the full @@ -769,7 +768,11 @@ void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { case MTU_EXCHANGE_IN_PROGRESS: LOG_INFO("Enqueue MTU Request - waiting for response on p_clcb %p", p_clcb); - bta_gattc_enqueue(p_clcb, p_data); + /* MTU request is in progress and this one will not be sent to remote + * device. Just push back on the queue and response will be sent up to + * the upper layer when MTU Exchange will be completed. + */ + p_clcb->p_q_cmd_queue.push_back(p_data); return; case MTU_EXCHANGE_NOT_DONE_YET: @@ -807,6 +810,10 @@ void bta_gattc_start_discover_internal(tBTA_GATTC_CLCB* p_clcb) { p_clcb->disc_active = true; } +static void bta_gattc_continue_with_version_and_cache_known( + tBTA_GATTC_CLCB* p_clcb, RobustCachingSupport cache_support, + bool is_svc_chg); + /** Start a discovery on server */ void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb, UNUSED_ATTR const tBTA_GATTC_DATA* p_data) { @@ -821,41 +828,38 @@ void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb, { p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE; - if (p_clcb->p_srcb != NULL) { - /* set all srcb related clcb into discovery ST */ - bta_gattc_set_discover_st(p_clcb->p_srcb); - - // Before clear mask, set is_svc_chg to - // 1. true, invoked by service changed indication - // 2. false, invoked by connect API - bool is_svc_chg = p_clcb->p_srcb->srvc_hdl_chg; - - /* clear the service change mask */ - p_clcb->p_srcb->srvc_hdl_chg = false; - p_clcb->p_srcb->update_count = 0; - p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC_ACT; - - if (GetRobustCachingSupport(p_clcb, p_clcb->p_srcb->gatt_database) == - RobustCachingSupport::UNSUPPORTED) { - // Skip initial DB hash read if we have strong reason (due to interop, - // or a prior discovery) to believe that it is unsupported. - p_clcb->p_srcb->srvc_hdl_db_hash = false; - } - - /* read db hash if db hash characteristic exists */ - if (bta_gattc_is_robust_caching_enabled() && - p_clcb->p_srcb->srvc_hdl_db_hash && - bta_gattc_read_db_hash(p_clcb, is_svc_chg)) { - LOG(INFO) << __func__ - << ": pending service discovery, read db hash first"; - p_clcb->p_srcb->srvc_hdl_db_hash = false; - return; - } - - bta_gattc_start_discover_internal(p_clcb); - } else { + if (p_clcb->p_srcb == NULL) { LOG(ERROR) << "unknown device, can not start discovery"; + return; + } + + /* set all srcb related clcb into discovery ST */ + bta_gattc_set_discover_st(p_clcb->p_srcb); + + // Before clear mask, set is_svc_chg to + // 1. true, invoked by service changed indication + // 2. false, invoked by connect API + bool is_svc_chg = p_clcb->p_srcb->srvc_hdl_chg; + + /* clear the service change mask */ + p_clcb->p_srcb->srvc_hdl_chg = false; + p_clcb->p_srcb->update_count = 0; + p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC_ACT; + p_clcb->p_srcb->disc_blocked_waiting_on_version = false; + + auto cache_support = + GetRobustCachingSupport(p_clcb, p_clcb->p_srcb->gatt_database); + if (cache_support == RobustCachingSupport::W4_REMOTE_VERSION) { + LOG_INFO( + "Pausing service discovery till remote version is read conn_id:%d", + p_clcb->bta_conn_id); + p_clcb->p_srcb->disc_blocked_waiting_on_version = true; + p_clcb->p_srcb->blocked_conn_id = p_clcb->bta_conn_id; + return; } + + bta_gattc_continue_with_version_and_cache_known(p_clcb, cache_support, + is_svc_chg); } /* pending operation, wait until it finishes */ else { @@ -866,6 +870,58 @@ void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb, } } +void bta_gattc_continue_discovery_if_needed(const RawAddress& bd_addr, + uint16_t /* acl_handle */) { + tBTA_GATTC_SERV* p_srcb = bta_gattc_find_srvr_cache(bd_addr); + if (!p_srcb || !p_srcb->disc_blocked_waiting_on_version) { + return; + } + + uint16_t conn_id = p_srcb->blocked_conn_id; + + p_srcb->disc_blocked_waiting_on_version = false; + p_srcb->blocked_conn_id = 0; + + LOG_INFO("Received remote version, continue service discovery for %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + + tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + if (!p_clcb) { + LOG_ERROR("Can't find CLCB to continue service discovery, id:%d", conn_id); + return; + } + + bool is_svc_chg = p_clcb->p_srcb->srvc_hdl_chg; + + auto cache_support = + GetRobustCachingSupport(p_clcb, p_clcb->p_srcb->gatt_database); + bta_gattc_continue_with_version_and_cache_known(p_clcb, cache_support, + is_svc_chg); +} + +void bta_gattc_continue_with_version_and_cache_known( + tBTA_GATTC_CLCB* p_clcb, RobustCachingSupport cache_support, + bool is_svc_chg) { + if (cache_support == RobustCachingSupport::UNSUPPORTED) { + // Skip initial DB hash read if we have strong reason (due to interop, + // or a prior discovery) to believe that it is unsupported. + p_clcb->p_srcb->srvc_hdl_db_hash = false; + } + + /* read db hash if db hash characteristic exists */ + if (bta_gattc_is_robust_caching_enabled() && + p_clcb->p_srcb->srvc_hdl_db_hash && + bta_gattc_read_db_hash(p_clcb, is_svc_chg)) { + LOG(INFO) << __func__ + << ": pending service discovery, read db hash first conn_id:" + << loghex(p_clcb->bta_conn_id); + p_clcb->p_srcb->srvc_hdl_db_hash = false; + return; + } + bta_gattc_start_discover_internal(p_clcb); +} + /** discovery on server is finished */ void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb, UNUSED_ATTR const tBTA_GATTC_DATA* p_data) { @@ -958,16 +1014,26 @@ void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { if (bta_gattc_enqueue(p_clcb, p_data) == ENQUEUED_FOR_LATER) return; + if (p_data->api_read_multi.handles.num_attr > GATT_MAX_READ_MULTI_HANDLES) { + LOG(ERROR) << "api_read_multi.num_attr > GATT_MAX_READ_MULTI_HANDLES"; + return; + } + tGATT_READ_PARAM read_param; memset(&read_param, 0, sizeof(tGATT_READ_PARAM)); - read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr; + read_param.read_multiple.num_handles = + p_data->api_read_multi.handles.num_attr; read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req; - memcpy(&read_param.read_multiple.handles, p_data->api_read_multi.handles, - sizeof(uint16_t) * p_data->api_read_multi.num_attr); - - tGATT_STATUS status = - GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param); + read_param.read_multiple.variable_len = p_data->api_read_multi.variable_len; + memcpy(&read_param.read_multiple.handles, + p_data->api_read_multi.handles.handles, + sizeof(uint16_t) * p_data->api_read_multi.handles.num_attr); + + tGATT_READ_TYPE read_type = (read_param.read_multiple.variable_len) + ? GATT_READ_MULTIPLE_VAR_LEN + : GATT_READ_MULTIPLE; + tGATT_STATUS status = GATTC_Read(p_clcb->bta_conn_id, read_type, &read_param); /* read fail */ if (status != GATT_SUCCESS) { /* Dequeue the data, if it was enqueued */ @@ -1049,21 +1115,37 @@ void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { /** read complete */ static void bta_gattc_read_cmpl(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_OP_CMPL* p_data) { - GATT_READ_OP_CB cb = p_clcb->p_q_cmd->api_read.read_cb; - void* my_cb_data = p_clcb->p_q_cmd->api_read.read_cb_data; + void* my_cb_data; - /* if it was read by handle, return the handle requested, if read by UUID, use - * handle returned from remote - */ - uint16_t handle = p_clcb->p_q_cmd->api_read.handle; - if (handle == 0) handle = p_data->p_cmpl->att_value.handle; + if (!p_clcb->p_q_cmd->api_read.is_multi_read) { + GATT_READ_OP_CB cb = p_clcb->p_q_cmd->api_read.read_cb; + my_cb_data = p_clcb->p_q_cmd->api_read.read_cb_data; - osi_free_and_reset((void**)&p_clcb->p_q_cmd); + /* if it was read by handle, return the handle requested, if read by UUID, + * use handle returned from remote + */ + uint16_t handle = p_clcb->p_q_cmd->api_read.handle; + if (handle == 0) handle = p_data->p_cmpl->att_value.handle; - if (cb) { - cb(p_clcb->bta_conn_id, p_data->status, handle, - p_data->p_cmpl->att_value.len, p_data->p_cmpl->att_value.value, - my_cb_data); + osi_free_and_reset((void**)&p_clcb->p_q_cmd); + + if (cb) { + cb(p_clcb->bta_conn_id, p_data->status, handle, + p_data->p_cmpl->att_value.len, p_data->p_cmpl->att_value.value, + my_cb_data); + } + } else { + GATT_READ_MULTI_OP_CB cb = p_clcb->p_q_cmd->api_read_multi.read_cb; + my_cb_data = p_clcb->p_q_cmd->api_read_multi.read_cb_data; + tBTA_GATTC_MULTI handles = p_clcb->p_q_cmd->api_read_multi.handles; + + osi_free_and_reset((void**)&p_clcb->p_q_cmd); + + if (cb) { + cb(p_clcb->bta_conn_id, p_data->status, handles, + p_data->p_cmpl->att_value.len, p_data->p_cmpl->att_value.value, + my_cb_data); + } } } @@ -1162,9 +1244,12 @@ void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { } if (p_clcb->p_q_cmd->hdr.event != - bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) { + bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ] && + (p_clcb->p_q_cmd->hdr.event != BTA_GATTC_API_READ_MULTI_EVT || + op != GATTC_OPTYPE_READ)) { uint8_t mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ; + if (mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0; LOG(ERROR) << StringPrintf( @@ -1335,7 +1420,7 @@ static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, const RawAddress& bda) { VLOG(1) << __func__ << ": cif:" << +gattc_if; do_in_main_thread(FROM_HERE, - base::Bind(&bta_gattc_process_enc_cmpl, gattc_if, bda)); + base::BindOnce(&bta_gattc_process_enc_cmpl, gattc_if, bda)); } /** process refresh API to delete cache and start a new discovery if currently diff --git a/system/bta/gatt/bta_gattc_api.cc b/system/bta/gatt/bta_gattc_api.cc index 5e052b46bbf8d7ba8868792a7bfb62be70829589..26797ac03cc5a22c080db455c4d3a5cc57b3efaa 100644 --- a/system/bta/gatt/bta_gattc_api.cc +++ b/system/bta/gatt/bta_gattc_api.cc @@ -38,7 +38,7 @@ #include "osi/include/allocator.h" #include "osi/include/log.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -69,7 +69,7 @@ void BTA_GATTC_Disable(void) { return; } - do_in_main_thread(FROM_HERE, base::Bind(&bta_gattc_disable)); + do_in_main_thread(FROM_HERE, base::BindOnce(&bta_gattc_disable)); bta_sys_deregister(BTA_ID_GATTC); } @@ -86,9 +86,9 @@ void BTA_GATTC_AppRegister(tBTA_GATTC_CBACK* p_client_cb, bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg); } - do_in_main_thread( - FROM_HERE, base::Bind(&bta_gattc_register, Uuid::GetRandom(), p_client_cb, - std::move(cb), eatt_support)); + do_in_main_thread(FROM_HERE, + base::BindOnce(&bta_gattc_register, Uuid::GetRandom(), + p_client_cb, std::move(cb), eatt_support)); } static void app_deregister_impl(tGATT_IF client_if) { @@ -113,7 +113,7 @@ static void app_deregister_impl(tGATT_IF client_if) { * ******************************************************************************/ void BTA_GATTC_AppDeregister(tGATT_IF client_if) { - do_in_main_thread(FROM_HERE, base::Bind(&app_deregister_impl, client_if)); + do_in_main_thread(FROM_HERE, base::BindOnce(&app_deregister_impl, client_if)); } /******************************************************************************* @@ -129,8 +129,8 @@ void BTA_GATTC_AppDeregister(tGATT_IF client_if) { * transport: Transport to be used for GATT connection * (BREDR/LE) * initiating_phys: LE PHY to use, optional - * opportunistic: wether the connection shall be opportunistic, - * and don't impact the disconnection timer + * opportunistic: whether the connection shall be + * opportunistic, and don't impact the disconnection timer * ******************************************************************************/ void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda, @@ -152,12 +152,12 @@ void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda, .event = BTA_GATTC_API_OPEN_EVT, }, .remote_bda = remote_bda, - .remote_addr_type = addr_type, .client_if = client_if, .connection_type = connection_type, .transport = transport, .initiating_phys = initiating_phys, .opportunistic = opportunistic, + .remote_addr_type = addr_type, }, }; @@ -287,7 +287,7 @@ void BTA_GATTC_ServiceSearchRequest(uint16_t conn_id, const Uuid* p_srvc_uuid) { void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id, const Uuid& srvc_uuid) { do_in_main_thread( FROM_HERE, - base::Bind( + base::BindOnce( base::IgnoreResult( &GATTC_Discover), @@ -398,6 +398,7 @@ void BTA_GATTC_ReadCharacteristic(uint16_t conn_id, uint16_t handle, p_buf->hdr.event = BTA_GATTC_API_READ_EVT; p_buf->hdr.layer_specific = conn_id; + p_buf->is_multi_read = false; p_buf->auth_req = auth_req; p_buf->handle = handle; p_buf->read_cb = callback; @@ -419,6 +420,7 @@ void BTA_GATTC_ReadUsingCharUuid(uint16_t conn_id, const Uuid& uuid, p_buf->hdr.event = BTA_GATTC_API_READ_EVT; p_buf->hdr.layer_specific = conn_id; + p_buf->is_multi_read = false; p_buf->auth_req = auth_req; p_buf->handle = 0; p_buf->uuid = uuid; @@ -450,6 +452,7 @@ void BTA_GATTC_ReadCharDescr(uint16_t conn_id, uint16_t handle, p_buf->hdr.event = BTA_GATTC_API_READ_EVT; p_buf->hdr.layer_specific = conn_id; + p_buf->is_multi_read = false; p_buf->auth_req = auth_req; p_buf->handle = handle; p_buf->read_cb = callback; @@ -466,25 +469,28 @@ void BTA_GATTC_ReadCharDescr(uint16_t conn_id, uint16_t handle, * characteristic descriptors. * * Parameters conn_id - connectino ID. - * p_read_multi - pointer to the read multiple parameter. + * p_read_multi - pointer to the read multiple parameter. + * variable_len - whether "read multi variable length" variant + * shall be used. + * * * Returns None * ******************************************************************************/ -void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI* p_read_multi, - tGATT_AUTH_REQ auth_req) { +void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI& handles, + bool variable_len, tGATT_AUTH_REQ auth_req, + GATT_READ_MULTI_OP_CB callback, void* cb_data) { tBTA_GATTC_API_READ_MULTI* p_buf = (tBTA_GATTC_API_READ_MULTI*)osi_calloc(sizeof(tBTA_GATTC_API_READ_MULTI)); p_buf->hdr.event = BTA_GATTC_API_READ_MULTI_EVT; p_buf->hdr.layer_specific = conn_id; + p_buf->is_multi_read = true; p_buf->auth_req = auth_req; - p_buf->num_attr = p_read_multi->num_attr; - - if (p_buf->num_attr > 0) - memcpy(p_buf->handles, p_read_multi->handles, - sizeof(uint16_t) * p_read_multi->num_attr); - + p_buf->handles = handles; + p_buf->variable_len = variable_len; + p_buf->read_cb = callback; + p_buf->read_cb_data = cb_data; bta_sys_sendmsg(p_buf); } diff --git a/system/bta/gatt/bta_gattc_cache.cc b/system/bta/gatt/bta_gattc_cache.cc index cd0f64db09b658323a3317c08e878d55d916b0e7..d337fa795f9a8bb0cef52711a9054c68c7899911 100644 --- a/system/bta/gatt/bta_gattc_cache.cc +++ b/system/bta/gatt/bta_gattc_cache.cc @@ -31,19 +31,25 @@ #include #include -#include #include "bt_target.h" // Must be first to define build configuration #include "bta/gatt/bta_gattc_int.h" #include "bta/gatt/database.h" +#include "common/init_flags.h" #include "device/include/interop.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" +#include "osi/include/osi.h" // UNUSED_ATTR #include "stack/btm/btm_sec.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/gatt_api.h" +#include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + using base::StringPrintf; using bluetooth::Uuid; using gatt::Characteristic; @@ -160,6 +166,12 @@ RobustCachingSupport GetRobustCachingSupport(const tBTA_GATTC_CLCB* p_clcb, return RobustCachingSupport::UNSUPPORTED; } + if (p_clcb->transport == BT_TRANSPORT_LE && + !BTM_IsRemoteVersionReceived(p_clcb->bda)) { + LOG_INFO("version info is not ready yet"); + return RobustCachingSupport::W4_REMOTE_VERSION; + } + // This is workaround for the embedded devices being already on the market // and having a serious problem with handle Read By Type with // GATT_UUID_DATABASE_HASH. With this workaround, Android will assume that @@ -243,9 +255,8 @@ static void bta_gattc_explore_next_service(uint16_t conn_id, BTA_GATTC_DISCOVER_REQ_READ_EXT_PROP_DESC; if (p_srvc_cb->read_multiple_not_supported || descriptors.size() == 1) { - tGATT_READ_PARAM read_param{ - .by_handle = {.handle = descriptors.front(), - .auth_req = GATT_AUTH_REQ_NONE}}; + tGATT_READ_PARAM read_param{.by_handle = {.auth_req = GATT_AUTH_REQ_NONE, + .handle = descriptors.front()}}; GATTC_Read(conn_id, GATT_READ_BY_HANDLE, &read_param); // asynchronous continuation in bta_gattc_op_cmpl_during_discovery return; @@ -340,14 +351,13 @@ void bta_gattc_start_disc_char_dscp(uint16_t conn_id, descriptor_discovery_done: /* all characteristic has been explored, start with next service if any */ - DVLOG(3) << "all characteristics explored"; - bta_gattc_explore_next_service(conn_id, p_srvc_cb); return; } /* Process the discovery result from sdp */ -void bta_gattc_sdp_callback(tSDP_STATUS sdp_status, const void* user_data) { +void bta_gattc_sdp_callback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS sdp_status, const void* user_data) { tBTA_GATTC_CB_DATA* cb_data = (tBTA_GATTC_CB_DATA*)user_data; tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(cb_data->sdp_conn_id); @@ -368,14 +378,18 @@ void bta_gattc_sdp_callback(tSDP_STATUS sdp_status, const void* user_data) { bool no_pending_disc = !p_srvc_cb->pending_discovery.InProgress(); - tSDP_DISC_REC* p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, nullptr); + tSDP_DISC_REC* p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + cb_data->p_sdp_db, 0, nullptr); while (p_sdp_rec != nullptr) { /* find a service record, report it */ Uuid service_uuid; - if (!SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) continue; + if (!get_legacy_stack_sdp_api()->record.SDP_FindServiceUUIDInRec( + p_sdp_rec, &service_uuid)) + continue; tSDP_PROTOCOL_ELEM pe; - if (!SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT, &pe)) + if (!get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_sdp_rec, UUID_PROTOCOL_ATT, &pe)) continue; uint16_t start_handle = (uint16_t)pe.params[0]; @@ -391,7 +405,8 @@ void bta_gattc_sdp_callback(tSDP_STATUS sdp_status, const void* user_data) { !GATT_HANDLE_IS_VALID(end_handle)) { LOG(ERROR) << "invalid start_handle=" << loghex(start_handle) << ", end_handle=" << loghex(end_handle); - p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec); + p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + cb_data->p_sdp_db, 0, p_sdp_rec); continue; } @@ -399,7 +414,8 @@ void bta_gattc_sdp_callback(tSDP_STATUS sdp_status, const void* user_data) { p_srvc_cb->pending_discovery.AddService(start_handle, end_handle, service_uuid, true); - p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec); + p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + cb_data->p_sdp_db, 0, p_sdp_rec); } // If discovery is already pending, no need to call @@ -431,10 +447,10 @@ static tGATT_STATUS bta_gattc_sdp_service_disc(uint16_t conn_id, attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; Uuid uuid = Uuid::From16Bit(UUID_PROTOCOL_ATT); - SDP_InitDiscoveryDb(cb_data->p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, &uuid, - num_attrs, attr_list); + get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + cb_data->p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, &uuid, num_attrs, attr_list); - if (!SDP_ServiceSearchAttributeRequest2( + if (!get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest2( p_server_cb->server_bda, cb_data->p_sdp_db, &bta_gattc_sdp_callback, const_cast(static_cast(cb_data)))) { osi_free(cb_data); diff --git a/system/bta/gatt/bta_gattc_db_storage.cc b/system/bta/gatt/bta_gattc_db_storage.cc index 6273d7c9bf7f1a14b7f6093fd1be92de3bffbbfd..9a862c8671d413287f1a15468fda84d9112a22da 100644 --- a/system/bta/gatt/bta_gattc_db_storage.cc +++ b/system/bta/gatt/bta_gattc_db_storage.cc @@ -27,7 +27,10 @@ #include #include "bta/gatt/bta_gattc_int.h" -#include "osi/include/log.h" +#include "gatt/database.h" +#include "os/log.h" +#include "stack/include/gattdefs.h" +#include "types/bluetooth/uuid.h" using gatt::StoredAttribute; using std::string; @@ -165,6 +168,61 @@ gatt::Database bta_gattc_hash_load(const Octet16& hash) { return bta_gattc_load_db(fname); } +void StoredAttribute::SerializeStoredAttribute(const StoredAttribute& attr, + std::vector& bytes) { + size_t original_size = bytes.size(); + // handle + bytes.push_back(attr.handle & 0xff); + bytes.push_back(attr.handle >> 8); + auto uuid = attr.type.To128BitBE(); + bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend()); + + if (attr.type.Is16Bit()) { + switch (attr.type.As16Bit()) { + /* primary or secondary service definition */ + case GATT_UUID_PRI_SERVICE: + case GATT_UUID_SEC_SERVICE: + uuid = attr.value.service.uuid.To128BitBE(); + bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend()); + bytes.push_back(attr.value.service.end_handle & 0xff); + bytes.push_back(attr.value.service.end_handle >> 8); + break; + case GATT_UUID_INCLUDE_SERVICE: + /* included service definition */ + bytes.push_back(attr.value.included_service.handle & 0xff); + bytes.push_back(attr.value.included_service.handle >> 8); + bytes.push_back(attr.value.included_service.end_handle & 0xff); + bytes.push_back(attr.value.included_service.end_handle >> 8); + uuid = attr.value.included_service.uuid.To128BitBE(); + bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend()); + break; + case GATT_UUID_CHAR_DECLARE: + /* characteristic definition */ + bytes.push_back(attr.value.characteristic.properties); + bytes.push_back(0); // Padding byte + bytes.push_back(attr.value.characteristic.value_handle & 0xff); + bytes.push_back(attr.value.characteristic.value_handle >> 8); + uuid = attr.value.characteristic.uuid.To128BitBE(); + bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend()); + break; + case GATT_UUID_CHAR_EXT_PROP: + /* for descriptor we store value only for + * «Characteristic Extended Properties» */ + bytes.push_back(attr.value.characteristic_extended_properties & 0xff); + bytes.push_back(attr.value.characteristic_extended_properties >> 8); + break; + default: + // LOG_VERBOSE("Unhandled type UUID 0x%04x", attr.type.As16Bit()); + break; + } + } + // padding + for (size_t i = bytes.size() - original_size; + i < StoredAttribute::kSizeOnDisk; i++) { + bytes.push_back(0); + } +} + /******************************************************************************* * * Function bta_gattc_store_db @@ -201,7 +259,14 @@ static bool bta_gattc_store_db(const char* fname, return false; } - if (fwrite(attr.data(), sizeof(StoredAttribute), num_attr, fd) != num_attr) { + std::vector db_bytes; + db_bytes.reserve(num_attr * StoredAttribute::kSizeOnDisk); + for (const auto attribute : attr) { + StoredAttribute::SerializeStoredAttribute(attribute, db_bytes); + } + + if (fwrite(db_bytes.data(), sizeof(uint8_t), db_bytes.size(), fd) != + db_bytes.size()) { LOG(ERROR) << __func__ << ": can't write GATT cache attributes: " << fname; fclose(fd); return false; diff --git a/system/bta/gatt/bta_gattc_int.h b/system/bta/gatt/bta_gattc_int.h index cc76645cd7f7c8846ea66ea3f00ff9260c5da528..7582e769a452c4869e2733ab904dd6b6602c1893 100644 --- a/system/bta/gatt/bta_gattc_int.h +++ b/system/bta/gatt/bta_gattc_int.h @@ -27,11 +27,11 @@ #include #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/gatt/database.h" #include "bta/gatt/database_builder.h" #include "bta/include/bta_gatt_api.h" #include "bta/sys/bta_sys.h" +#include "internal_include/bt_target.h" #include "stack/include/bt_hdr.h" #include "stack/include/gatt_api.h" #include "types/bluetooth/uuid.h" @@ -108,6 +108,12 @@ typedef struct { typedef struct { BT_HDR_RIGID hdr; + + /* it is important that is_multi_read field stays at same position between + * tBTA_GATTC_API_READ and tBTA_GATTC_API_READ_MULTI, as it is read from + * parent union */ + uint8_t is_multi_read; + tGATT_AUTH_REQ auth_req; // read by handle data @@ -159,9 +165,17 @@ typedef struct { typedef struct { BT_HDR_RIGID hdr; + + /* it is important that is_multi_read field stays at same position between + * tBTA_GATTC_API_READ and tBTA_GATTC_API_READ_MULTI, as it is read from + * parent union */ + uint8_t is_multi_read; + tGATT_AUTH_REQ auth_req; - uint8_t num_attr; - uint16_t handles[GATT_MAX_READ_MULTI_HANDLES]; + tBTA_GATTC_MULTI handles; + uint8_t variable_len; + GATT_READ_MULTI_OP_CB read_cb; + void* read_cb_data; } tBTA_GATTC_API_READ_MULTI; typedef struct { @@ -232,6 +246,9 @@ typedef struct { uint16_t attr_index; /* cahce NV saving/loading attribute index */ uint16_t mtu; + + bool disc_blocked_waiting_on_version; + uint16_t blocked_conn_id; } tBTA_GATTC_SERV; #ifndef BTA_GATTC_NOTIF_REG_MAX @@ -334,7 +351,7 @@ extern tBTA_GATTC_CB bta_gattc_cb; /***************************************************************************** * Function prototypes ****************************************************************************/ -bool bta_gattc_hdl_event(BT_HDR_RIGID* p_msg); +bool bta_gattc_hdl_event(const BT_HDR_RIGID* p_msg); bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event, const tBTA_GATTC_DATA* p_data); @@ -480,6 +497,7 @@ enum class RobustCachingSupport { UNSUPPORTED, SUPPORTED, UNKNOWN, + W4_REMOTE_VERSION }; RobustCachingSupport GetRobustCachingSupport(const tBTA_GATTC_CLCB* p_clcb, const gatt::Database& db); diff --git a/system/bta/gatt/bta_gattc_main.cc b/system/bta/gatt/bta_gattc_main.cc index b624c5afa76e330e961c27ac306f3bfedf51cebc..643fb72e55167db2c63a6261362fd8d2fd457805 100644 --- a/system/bta/gatt/bta_gattc_main.cc +++ b/system/bta/gatt/bta_gattc_main.cc @@ -364,7 +364,7 @@ bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event, * Returns bool * ******************************************************************************/ -bool bta_gattc_hdl_event(BT_HDR_RIGID* p_msg) { +bool bta_gattc_hdl_event(const BT_HDR_RIGID* p_msg) { tBTA_GATTC_CLCB* p_clcb = NULL; bool rt = true; #if (BTA_GATT_DEBUG == TRUE) diff --git a/system/bta/gatt/bta_gattc_queue.cc b/system/bta/gatt/bta_gattc_queue.cc index b4c4f51ac3f17faf9ae7fef9d3797a988fbda3e4..982d67b81f3d0f0d7458a091cba18bbcb33df555 100644 --- a/system/bta/gatt/bta_gattc_queue.cc +++ b/system/bta/gatt/bta_gattc_queue.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "gatt" + #include "bta_gatt_queue.h" #include @@ -21,6 +23,7 @@ #include #include "osi/include/allocator.h" +#include "osi/include/log.h" #include @@ -31,6 +34,7 @@ constexpr uint8_t GATT_READ_DESC = 2; constexpr uint8_t GATT_WRITE_CHAR = 3; constexpr uint8_t GATT_WRITE_DESC = 4; constexpr uint8_t GATT_CONFIG_MTU = 5; +constexpr uint8_t GATT_READ_MULTI = 6; struct gatt_read_op_data { GATT_READ_OP_CB cb; @@ -109,22 +113,47 @@ void BtaGattQueue::gatt_configure_mtu_op_finished(uint16_t conn_id, } } +struct gatt_read_multi_op_data { + GATT_READ_MULTI_OP_CB cb; + void* cb_data; +}; + +void BtaGattQueue::gatt_read_multi_op_finished(uint16_t conn_id, + tGATT_STATUS status, + tBTA_GATTC_MULTI& handles, + uint16_t len, uint8_t* value, + void* data) { + gatt_read_multi_op_data* tmp = (gatt_read_multi_op_data*)data; + GATT_READ_MULTI_OP_CB tmp_cb = tmp->cb; + void* tmp_cb_data = tmp->cb_data; + + osi_free(data); + + mark_as_not_executing(conn_id); + gatt_execute_next_op(conn_id); + + if (tmp_cb) { + tmp_cb(conn_id, status, handles, len, value, tmp_cb_data); + return; + } +} + void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) { - APPL_TRACE_DEBUG("%s: conn_id=0x%x", __func__, conn_id); + LOG_VERBOSE("%s: conn_id=0x%x", __func__, conn_id); if (gatt_op_queue.empty()) { - APPL_TRACE_DEBUG("%s: op queue is empty", __func__); + LOG_VERBOSE("%s: op queue is empty", __func__); return; } auto map_ptr = gatt_op_queue.find(conn_id); if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) { - APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__, - conn_id); + LOG_VERBOSE("%s: no more operations queued for conn_id %d", __func__, + conn_id); return; } if (gatt_op_queue_executing.count(conn_id)) { - APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__); + LOG_VERBOSE("%s: can't enqueue next op, already executing", __func__); return; } @@ -174,6 +203,14 @@ void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) { BTA_GATTC_ConfigureMTU(conn_id, static_cast(op.value[0] | (op.value[1] << 8)), gatt_configure_mtu_op_finished, data); + } else if (op.type == GATT_READ_MULTI) { + gatt_read_multi_op_data* data = + (gatt_read_multi_op_data*)osi_malloc(sizeof(gatt_read_multi_op_data)); + data->cb = op.read_multi_cb; + data->cb_data = op.read_cb_data; + BTA_GATTC_ReadMultiple(conn_id, op.handles, op.variable_len, + GATT_AUTH_REQ_NONE, gatt_read_multi_op_finished, + data); } gatt_ops.pop_front(); @@ -236,3 +273,16 @@ void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) { .value = std::move(value)}); gatt_execute_next_op(conn_id); } + +void BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id, + tBTA_GATTC_MULTI& handles, + bool variable_len, + GATT_READ_MULTI_OP_CB cb, + void* cb_data) { + gatt_op_queue[conn_id].push_back({.type = GATT_READ_MULTI, + .handles = handles, + .variable_len = variable_len, + .read_multi_cb = cb, + .read_cb_data = cb_data}); + gatt_execute_next_op(conn_id); +} \ No newline at end of file diff --git a/system/bta/gatt/bta_gattc_utils.cc b/system/bta/gatt/bta_gattc_utils.cc index edf5dbbb2791b570f6aa342a6098660321701b03..aed8721085efd964e520c9ad084f0b75b5fb0b93 100644 --- a/system/bta/gatt/bta_gattc_utils.cc +++ b/system/bta/gatt/bta_gattc_utils.cc @@ -28,12 +28,12 @@ #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/gatt/bta_gattc_int.h" +#include "common/init_flags.h" #include "device/include/controller.h" -#include "gd/common/init_flags.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "types/bt_transport.h" #include "types/hci_role.h" #include "types/raw_address.h" diff --git a/system/bta/gatt/bta_gatts_api.cc b/system/bta/gatt/bta_gatts_api.cc index 3c6f26586b0755171000b9d50b9c56c69b32aff4..19bc234abc559d780436e1dc3f9c30372c05496c 100644 --- a/system/bta/gatt/bta_gatts_api.cc +++ b/system/bta/gatt/bta_gatts_api.cc @@ -34,7 +34,7 @@ #include "bta/gatt/bta_gatts_int.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -177,8 +177,8 @@ void BTA_GATTS_AddService(tGATT_IF server_if, std::vector service, BTA_GATTS_AddServiceCb cb) { do_in_main_thread(FROM_HERE, - base::Bind(&bta_gatts_add_service_impl, server_if, - std::move(service), std::move(cb))); + base::BindOnce(&bta_gatts_add_service_impl, server_if, + std::move(service), std::move(cb))); } /******************************************************************************* diff --git a/system/bta/gatt/bta_gatts_int.h b/system/bta/gatt/bta_gatts_int.h index 102ea3e6f5a2c85c30731de28fd54568b10a0811..a26fdb695e42875c4b96e6558f49ade7215720d2 100644 --- a/system/bta/gatt/bta_gatts_int.h +++ b/system/bta/gatt/bta_gatts_int.h @@ -26,11 +26,11 @@ #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/include/bta_gatt_api.h" #include "bta/sys/bta_sys.h" +#include "hardware/bt_gatt_types.h" +#include "internal_include/bt_target.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "stack/include/btm_ble_api_types.h" #include "stack/include/gatt_api.h" #include "types/bluetooth/uuid.h" @@ -168,7 +168,7 @@ extern tBTA_GATTS_CB bta_gatts_cb; /***************************************************************************** * Function prototypes ****************************************************************************/ -bool bta_gatts_hdl_event(BT_HDR_RIGID* p_msg); +bool bta_gatts_hdl_event(const BT_HDR_RIGID* p_msg); void bta_gatts_api_disable(tBTA_GATTS_CB* p_cb); void bta_gatts_api_enable(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_data); diff --git a/system/bta/gatt/bta_gatts_main.cc b/system/bta/gatt/bta_gatts_main.cc index 458f5e2ea940b041e87306613874ff4e8ccd9a59..459961cb331d50b2f63cc021e0ad3117be5e6f1a 100644 --- a/system/bta/gatt/bta_gatts_main.cc +++ b/system/bta/gatt/bta_gatts_main.cc @@ -41,7 +41,7 @@ tBTA_GATTS_CB bta_gatts_cb; * Returns void * ******************************************************************************/ -bool bta_gatts_hdl_event(BT_HDR_RIGID* p_msg) { +bool bta_gatts_hdl_event(const BT_HDR_RIGID* p_msg) { tBTA_GATTS_CB* p_cb = &bta_gatts_cb; switch (p_msg->event) { diff --git a/system/bta/gatt/bta_gatts_queue.cc b/system/bta/gatt/bta_gatts_queue.cc index d8c51adb2f032d19336a6afd1b1a0faff274cd87..33317c697fadab48ed983baffd188bee1d3acfb3 100644 --- a/system/bta/gatt/bta_gatts_queue.cc +++ b/system/bta/gatt/bta_gatts_queue.cc @@ -14,11 +14,14 @@ * limitations under the License. */ +#define LOG_TAG "gatt" + #include #include #include #include "bta_gatt_server_queue.h" +#include "osi/include/log.h" using gatts_operation = BtaGattServerQueue::gatts_operation; using bluetooth::Uuid; @@ -35,10 +38,10 @@ void BtaGattServerQueue::mark_as_not_executing(uint16_t conn_id) { } void BtaGattServerQueue::gatts_execute_next_op(uint16_t conn_id) { - APPL_TRACE_DEBUG("%s: conn_id=0x%x", __func__, conn_id); + LOG_VERBOSE("%s: conn_id=0x%x", __func__, conn_id); if (gatts_op_queue.empty()) { - APPL_TRACE_DEBUG("%s: op queue is empty", __func__); + LOG_VERBOSE("%s: op queue is empty", __func__); return; } @@ -46,11 +49,10 @@ void BtaGattServerQueue::gatts_execute_next_op(uint16_t conn_id) { if (ptr != congestion_queue.end()) { bool is_congested = ptr->second; - APPL_TRACE_DEBUG( - "%s: congestion queue exist, conn_id: %d, is_congested: %d", __func__, - conn_id, is_congested); + LOG_VERBOSE("%s: congestion queue exist, conn_id: %d, is_congested: %d", + __func__, conn_id, is_congested); if (is_congested) { - APPL_TRACE_DEBUG("%s: lower layer is congested", __func__); + LOG_VERBOSE("%s: lower layer is congested", __func__); return; } } @@ -58,22 +60,22 @@ void BtaGattServerQueue::gatts_execute_next_op(uint16_t conn_id) { auto map_ptr = gatts_op_queue.find(conn_id); if (map_ptr == gatts_op_queue.end()) { - APPL_TRACE_DEBUG("%s: Queue is null", __func__); + LOG_VERBOSE("%s: Queue is null", __func__); return; } if (map_ptr->second.empty()) { - APPL_TRACE_DEBUG("%s: queue is empty for conn_id: %d", __func__, conn_id); + LOG_VERBOSE("%s: queue is empty for conn_id: %d", __func__, conn_id); return; } if (gatts_op_queue_executing.count(conn_id)) { - APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__); + LOG_VERBOSE("%s: can't enqueue next op, already executing", __func__); return; } gatts_operation op = map_ptr->second.front(); - APPL_TRACE_DEBUG("%s: op.type=%d, attr_id=%d", __func__, op.type, op.attr_id); + LOG_VERBOSE("%s: op.type=%d, attr_id=%d", __func__, op.type, op.attr_id); if (op.type == GATT_NOTIFY) { BTA_GATTS_HandleValueIndication(conn_id, op.attr_id, op.value, @@ -83,7 +85,7 @@ void BtaGattServerQueue::gatts_execute_next_op(uint16_t conn_id) { } void BtaGattServerQueue::Clean(uint16_t conn_id) { - APPL_TRACE_DEBUG("%s: conn_id=0x%x", __func__, conn_id); + LOG_VERBOSE("%s: conn_id=0x%x", __func__, conn_id); gatts_op_queue.erase(conn_id); gatts_op_queue_executing.erase(conn_id); @@ -103,8 +105,8 @@ void BtaGattServerQueue::SendNotification(uint16_t conn_id, uint16_t handle, void BtaGattServerQueue::NotificationCallback(uint16_t conn_id) { auto map_ptr = gatts_op_queue.find(conn_id); if (map_ptr == gatts_op_queue.end() || map_ptr->second.empty()) { - APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__, - conn_id); + LOG_VERBOSE("%s: no more operations queued for conn_id %d", __func__, + conn_id); return; } @@ -115,8 +117,7 @@ void BtaGattServerQueue::NotificationCallback(uint16_t conn_id) { } void BtaGattServerQueue::CongestionCallback(uint16_t conn_id, bool congested) { - APPL_TRACE_DEBUG("%s: conn_id: %d, congested: %d", __func__, conn_id, - congested); + LOG_VERBOSE("%s: conn_id: %d, congested: %d", __func__, conn_id, congested); congestion_queue[conn_id] = congested; if (!congested) { diff --git a/system/bta/gatt/database.cc b/system/bta/gatt/database.cc index 184ff9223f5828195d46e315e1f07d74f70e0c36..c5bef7632479ebe48cd14540f66ba0e89576cf0f 100644 --- a/system/bta/gatt/database.cc +++ b/system/bta/gatt/database.cc @@ -22,11 +22,11 @@ #include #include -#include #include -#include "bt_trace.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" +#include "crypto_toolbox/crypto_toolbox.h" +#include "internal_include/bt_trace.h" +#include "stack/include/bt_types.h" #include "stack/include/gattdefs.h" #include "types/bluetooth/uuid.h" @@ -151,6 +151,8 @@ Database Database::Deserialize(const std::vector& nv_attr, .uuid = attr.value.service.uuid, .is_primary = (attr.type == PRIMARY_SERVICE), .end_handle = attr.value.service.end_handle, + .included_services = {}, + .characteristics = {}, }); } @@ -193,6 +195,7 @@ Database Database::Deserialize(const std::vector& nv_attr, .uuid = attr.value.characteristic.uuid, .value_handle = attr.value.characteristic.value_handle, .properties = attr.value.characteristic.properties, + .descriptors = {}, }); } else { @@ -205,7 +208,11 @@ Database Database::Deserialize(const std::vector& nv_attr, } else { current_service_it->characteristics.back().descriptors.emplace_back( - Descriptor{.handle = attr.handle, .uuid = attr.type}); + Descriptor{ + .handle = attr.handle, + .uuid = attr.type, + .characteristic_extended_properties = {}, + }); } } } diff --git a/system/bta/gatt/database.h b/system/bta/gatt/database.h index 53c03e5db22c51b769d0ef07c0e6ebb0c864051c..3a87ebc792e32bc71b761e309ea40ade3c08f7c9 100644 --- a/system/bta/gatt/database.h +++ b/system/bta/gatt/database.h @@ -19,12 +19,10 @@ #pragma once #include -#include #include -#include #include -#include "stack/include/bt_types.h" /* for Octet16 */ +#include "stack/include/bt_octets.h" #include "types/bluetooth/uuid.h" namespace gatt { @@ -33,6 +31,8 @@ constexpr uint16_t HANDLE_MAX = 0xffff; /* Representation of GATT attribute for storage */ struct StoredAttribute { + // kSizeOnDisk includes two padding bytes for backward compatibility. + static constexpr size_t kSizeOnDisk = 38; uint16_t handle; bluetooth::Uuid type; @@ -61,6 +61,8 @@ struct StoredAttribute { * «Characteristic Extended Properties» */ uint16_t characteristic_extended_properties; } value; + static void SerializeStoredAttribute(const StoredAttribute& attr, + std::vector& bytes); }; struct IncludedService; diff --git a/system/bta/gatt/database_builder.h b/system/bta/gatt/database_builder.h index f33b2e7d31946fc8b4bd0019bbe34d86f0c7412e..0c8830eb53e6bc0d069e3e0eccc44400ace91375 100644 --- a/system/bta/gatt/database_builder.h +++ b/system/bta/gatt/database_builder.h @@ -18,6 +18,7 @@ #pragma once +#include #include #include "bta/gatt/database.h" diff --git a/system/bta/groups/groups.cc b/system/bta/groups/groups.cc index 2b88b79248eab21259ad0165ae5e325d104fba2f..f8337c4cb8b5c33792864c949449e7bbfa42da24 100644 --- a/system/bta/groups/groups.cc +++ b/system/bta/groups/groups.cc @@ -25,6 +25,7 @@ #include "bta_groups.h" #include "btif_profile_storage.h" +#include "stack/include/bt_types.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" diff --git a/system/bta/has/has_client.cc b/system/bta/has/has_client.cc index 1b7cfe78015508af084190e69f344533410d56c8..71beba452f709f36edc86efd0c618eaa5e3042a3 100644 --- a/system/bta/has/has_client.cc +++ b/system/bta/has/has_client.cc @@ -31,17 +31,15 @@ #include "bta_csis_api.h" #include "bta_gatt_api.h" #include "bta_gatt_queue.h" -#include "bta_groups.h" #include "bta_has_api.h" #include "bta_le_audio_uuids.h" #include "btm_sec.h" -#include "device/include/controller.h" #include "gap_api.h" #include "gatt_api.h" #include "has_types.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "os/log.h" #include "osi/include/properties.h" +#include "stack/include/bt_types.h" using base::Closure; using bluetooth::Uuid; @@ -1836,9 +1834,17 @@ class HasClientImpl : public HasClient { } void OnGattConnected(const tBTA_GATTC_OPEN& evt) { - DLOG(INFO) << __func__ << ": address=" - << ADDRESS_TO_LOGGABLE_STR(evt.remote_bda) - << ", conn_id=" << evt.conn_id; + LOG_INFO("%s, conn_id=0x%04x, transport=%s, status=%s(0x%02x)", + ADDRESS_TO_LOGGABLE_CSTR(evt.remote_bda), evt.conn_id, + bt_transport_text(evt.transport).c_str(), + gatt_status_text(evt.status).c_str(), evt.status); + + if (evt.transport != BT_TRANSPORT_LE) { + LOG_WARN("Only LE connection is allowed (transport %s)", + bt_transport_text(evt.transport).c_str()); + BTA_GATTC_Close(evt.conn_id); + return; + } auto device = std::find_if(devices_.begin(), devices_.end(), HasDevice::MatchAddress(evt.remote_bda)); @@ -1880,7 +1886,15 @@ class HasClientImpl : public HasClient { int result = BTM_SetEncryption(device->addr, BT_TRANSPORT_LE, nullptr, nullptr, BTM_BLE_SEC_ENCRYPT); - LOG_INFO("Encryption required. Request result: 0x%02x", result); + + LOG_INFO("Encryption required for %s. Request result: 0x%02x", + ADDRESS_TO_LOGGABLE_CSTR(device->addr), result); + + if (result == BTM_ERR_KEY_MISSING) { + LOG_ERROR("Link key unknown for %s, disconnect profile", + ADDRESS_TO_LOGGABLE_CSTR(device->addr)); + BTA_GATTC_Close(device->conn_id); + } } void OnGattDisconnected(const tBTA_GATTC_CLOSE& evt) { @@ -1920,6 +1934,12 @@ class HasClientImpl : public HasClient { DLOG(INFO) << __func__; + /* verify link is encrypted */ + if (!BTM_IsEncrypted(device->addr, BT_TRANSPORT_LE)) { + LOG_WARN("Device not yet bonded - waiting for encryption"); + return; + } + /* Ignore if our service data is valid (service discovery initiated by * someone else?) */ diff --git a/system/bta/has/has_client_test.cc b/system/bta/has/has_client_test.cc index 0e8a0cfc96d816b5a91df37e9fd507f6059f75e4..74daaf3cba5e9c7600faafaebc7daf51d7e9df7c 100644 --- a/system/bta/has/has_client_test.cc +++ b/system/bta/has/has_client_test.cc @@ -37,6 +37,7 @@ #include "has_types.h" #include "mock_controller.h" #include "mock_csis_client.h" +#include "stack/include/bt_uuid16.h" #include "test/common/mock_functions.h" bool gatt_profile_get_eatt_support(const RawAddress& addr) { return true; } @@ -841,8 +842,8 @@ class HasClientTestBase : public ::testing::Test { if (!allow_fake_conn) ASSERT_NE(connected_devices.count(conn_id), 0u); tBTA_GATTC_CLOSE event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, .client_if = gatt_if, .remote_bda = connected_devices[conn_id], .reason = reason, @@ -854,8 +855,8 @@ class HasClientTestBase : public ::testing::Test { void InjectSearchCompleteEvent(uint16_t conn_id) { tBTA_GATTC_SEARCH_CMPL event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, }; gatt_callback(BTA_GATTC_SEARCH_CMPL_EVT, (tBTA_GATTC*)&event_data); @@ -891,6 +892,9 @@ class HasClientTestBase : public ::testing::Test { ON_CALL(btm_interface, BTM_IsEncrypted(address, _)) .WillByDefault(DoAll(Return(encryption_result))); + + ON_CALL(btm_interface, IsLinkKeyKnown(address, _)) + .WillByDefault(DoAll(Return(true))); } void InjectNotifyReadPresetResponse(uint16_t conn_id, @@ -1291,6 +1295,61 @@ TEST_F(HasClientTest, test_encryption_failed) { TestConnect(test_address); } +TEST_F(HasClientTest, test_service_discovery_complete_before_encryption) { + const RawAddress test_address = GetTestAddress(1); + SetSampleDatabaseHasPresetsNtf( + test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural); + + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::DISCONNECTED, test_address)) + .Times(0); + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::CONNECTED, test_address)) + .Times(0); + + SetEncryptionResult(test_address, false); + ON_CALL(btm_interface, SetEncryption(_, _, _, _, _)) + .WillByDefault(Return(BTM_SUCCESS)); + + TestConnect(test_address); + auto test_conn_id = GetTestConnId(test_address); + InjectSearchCompleteEvent(test_conn_id); + + Mock::VerifyAndClearExpectations(callbacks.get()); + + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::CONNECTED, test_address)) + .Times(1); + + SetEncryptionResult(test_address, true); + InjectEncryptionEvent(test_address); + Mock::VerifyAndClearExpectations(callbacks.get()); +} + +TEST_F(HasClientTest, test_disconnect_when_link_key_is_gone) { + const RawAddress test_address = GetTestAddress(1); + SetSampleDatabaseHasPresetsNtf( + test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural); + + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::DISCONNECTED, test_address)) + .Times(0); + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::CONNECTED, test_address)) + .Times(0); + + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)) + .WillByDefault(DoAll(Return(false))); + ON_CALL(btm_interface, SetEncryption(test_address, _, _, _, _)) + .WillByDefault(Return(BTM_ERR_KEY_MISSING)); + + auto test_conn_id = GetTestConnId(test_address); + EXPECT_CALL(gatt_interface, Close(test_conn_id)).Times(1); + InjectConnectedEvent(test_address, GetTestConnId(test_address)); + + Mock::VerifyAndClearExpectations(callbacks.get()); +} + TEST_F(HasClientTest, test_reconnect_after_encryption_failed) { const RawAddress test_address = GetTestAddress(1); SetSampleDatabaseHasNoPresetChange( diff --git a/system/bta/has/has_ctp.cc b/system/bta/has/has_ctp.cc index 05274dd3590614e407057da890e2e6f1e9f9aedc..a2beffea84e2292e4df7f1eef6aebba42d1b37dd 100644 --- a/system/bta/has/has_ctp.cc +++ b/system/bta/has/has_ctp.cc @@ -16,7 +16,9 @@ */ #include "has_ctp.h" + #include "os/log.h" +#include "stack/include/bt_types.h" namespace le_audio { namespace has { @@ -267,9 +269,7 @@ std::ostream& operator<<(std::ostream& out, const HasCtpNtf& ntf) { } break; case PresetCtpChangeId::PRESET_DELETED: - FALLTHROUGH; case PresetCtpChangeId::PRESET_AVAILABLE: - FALLTHROUGH; case PresetCtpChangeId::PRESET_UNAVAILABLE: out << ", \"index\": " << +ntf.index; break; diff --git a/system/bta/has/has_ctp.h b/system/bta/has/has_ctp.h index 963a23c7b1e07b6252cabea336571b1344fb1c59..ff58748e66b2103bcfec93a2c3aa559c0e0b1ba7 100644 --- a/system/bta/has/has_ctp.h +++ b/system/bta/has/has_ctp.h @@ -17,6 +17,8 @@ #pragma once +#include + #include #include diff --git a/system/bta/has/has_preset.cc b/system/bta/has/has_preset.cc index b54831150f56670f4a3069f7f28799f507d58b4a..ab8c97b8840f0f5a50cb1f6e33433b1692966828 100644 --- a/system/bta/has/has_preset.cc +++ b/system/bta/has/has_preset.cc @@ -17,6 +17,8 @@ #include "has_preset.h" +#include "stack/include/bt_types.h" + namespace le_audio { namespace has { diff --git a/system/bta/has/has_preset.h b/system/bta/has/has_preset.h index fae011ade2d08910b3aee4b48d5aab07ce562c86..3ba5a72816507c88bc482b9456f75fe7c02a3228 100644 --- a/system/bta/has/has_preset.h +++ b/system/bta/has/has_preset.h @@ -17,10 +17,11 @@ #pragma once +#include + #include #include -#include "bt_types.h" #include "hardware/bt_has.h" namespace le_audio { diff --git a/system/bta/has/has_types.h b/system/bta/has/has_types.h index 66d0dd3fb87b593e4249b5bb90fa90041a2e6b80..5b1fe54b920c3e4263d2e6818bd5f8ba75725ecb 100644 --- a/system/bta/has/has_types.h +++ b/system/bta/has/has_types.h @@ -22,12 +22,14 @@ #include #include -#include "bta_gatt_api.h" #include "gap_api.h" #include "hardware/bt_has.h" #include "has_ctp.h" #include "has_journal.h" #include "has_preset.h" +#include "internal_include/bt_trace.h" +#include "stack/include/bt_types.h" +#include "stack/include/gatt_api.h" namespace le_audio { namespace has { diff --git a/system/bta/hd/bta_hd_act.cc b/system/bta/hd/bta_hd_act.cc index 76fc8ece9c1f18d569993be611aa543c2fc2aac5..766be520765cc94abd14515de52746264e422eaa 100644 --- a/system/bta/hd/bta_hd_act.cc +++ b/system/bta/hd/bta_hd_act.cc @@ -25,21 +25,22 @@ #include #include -#include -// BTA_HD_INCLUDED -#include "bt_target.h" // Must be first to define build configuration +#include "internal_include/bt_target.h" #if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE) #include "bta/hd/bta_hd_int.h" #include "include/hardware/bt_hd.h" #include "main/shim/metrics_api.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/hidd_api.h" +#include "stack/include/sdp_api.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + static void bta_hd_cback(const RawAddress& bd_addr, uint8_t event, uint32_t data, BT_HDR* pdata); @@ -86,7 +87,7 @@ void bta_hd_api_enable(tBTA_HD_DATA* p_data) { tBTA_HD_STATUS status = BTA_HD_ERROR; tHID_STATUS ret; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); HID_DevInit(); @@ -99,7 +100,7 @@ void bta_hd_api_enable(tBTA_HD_DATA* p_data) { if (ret == HID_SUCCESS) { status = BTA_HD_OK; } else { - APPL_TRACE_ERROR("%s: Failed to register HID device (%d)", __func__, ret); + LOG_ERROR("%s: Failed to register HID device (%d)", __func__, ret); } /* signal BTA call back event */ @@ -121,14 +122,14 @@ void bta_hd_api_disable(void) { tBTA_HD_STATUS status = BTA_HD_ERROR; tHID_STATUS ret; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* service is not enabled */ if (bta_hd_cb.p_cback == NULL) return; /* Remove service record */ if (bta_hd_cb.sdp_handle != 0) { - SDP_DeleteRecord(bta_hd_cb.sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(bta_hd_cb.sdp_handle); bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE); } @@ -137,7 +138,8 @@ void bta_hd_api_disable(void) { if (ret == HID_SUCCESS) { status = BTA_HD_OK; } else { - APPL_TRACE_ERROR("%s: Failed to deregister HID device (%s)", __func__, ret); + LOG_ERROR("%s: Failed to deregister HID device (%s)", __func__, + hid_status_text(ret).c_str()); } tBTA_HD bta_hd; @@ -161,7 +163,7 @@ void bta_hd_register_act(tBTA_HD_DATA* p_data) { tBTA_HD_REGISTER_APP* p_app_data = (tBTA_HD_REGISTER_APP*)p_data; bool use_report_id = FALSE; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); ret.reg_status.in_use = FALSE; @@ -171,7 +173,7 @@ void bta_hd_register_act(tBTA_HD_DATA* p_data) { if (p_app_data->d_len > BTA_HD_APP_DESCRIPTOR_LEN || !check_descriptor(p_app_data->d_data, p_app_data->d_len, &use_report_id)) { - APPL_TRACE_ERROR("%s: Descriptor is too long or malformed", __func__); + LOG_ERROR("%s: Descriptor is too long or malformed", __func__); ret.reg_status.status = BTA_HD_ERROR; (*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret); bluetooth::shim::CountCounterMetrics( @@ -185,11 +187,11 @@ void bta_hd_register_act(tBTA_HD_DATA* p_data) { /* Remove old record if for some reason it's already registered */ if (bta_hd_cb.sdp_handle != 0) { - SDP_DeleteRecord(bta_hd_cb.sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(bta_hd_cb.sdp_handle); } bta_hd_cb.use_report_id = use_report_id; - bta_hd_cb.sdp_handle = SDP_CreateRecord(); + bta_hd_cb.sdp_handle = get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); HID_DevAddRecord(bta_hd_cb.sdp_handle, p_app_data->name, p_app_data->description, p_app_data->provider, p_app_data->subclass, p_app_data->d_len, p_app_data->d_data); @@ -227,13 +229,13 @@ void bta_hd_register_act(tBTA_HD_DATA* p_data) { void bta_hd_unregister_act() { tBTA_HD_STATUS status = BTA_HD_OK; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); // application is no longer registered so we do not want incoming connections HID_DevSetIncomingPolicy(FALSE); if (bta_hd_cb.sdp_handle != 0) { - SDP_DeleteRecord(bta_hd_cb.sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(bta_hd_cb.sdp_handle); } bta_hd_cb.sdp_handle = 0; @@ -254,7 +256,7 @@ void bta_hd_unregister_act() { * ******************************************************************************/ void bta_hd_unregister2_act(tBTA_HD_DATA* p_data) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); // close first bta_hd_close_act(p_data); @@ -281,17 +283,17 @@ void bta_hd_connect_act(tBTA_HD_DATA* p_data) { tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data; tBTA_HD cback_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); ret = HID_DevPlugDevice(p_ctrl->addr); if (ret != HID_SUCCESS) { - APPL_TRACE_WARNING("%s: HID_DevPlugDevice returned %d", __func__, ret); + LOG_WARN("%s: HID_DevPlugDevice returned %d", __func__, ret); return; } ret = HID_DevConnect(); if (ret != HID_SUCCESS) { - APPL_TRACE_WARNING("%s: HID_DevConnect returned %d", __func__, ret); + LOG_WARN("%s: HID_DevConnect returned %d", __func__, ret); return; } @@ -314,12 +316,12 @@ void bta_hd_disconnect_act() { tHID_STATUS ret; tBTA_HD cback_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); ret = HID_DevDisconnect(); if (ret != HID_SUCCESS) { - APPL_TRACE_WARNING("%s: HID_DevDisconnect returned %d", __func__, ret); + LOG_WARN("%s: HID_DevDisconnect returned %d", __func__, ret); return; } @@ -341,7 +343,7 @@ void bta_hd_disconnect_act() { void bta_hd_add_device_act(tBTA_HD_DATA* p_data) { tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); HID_DevPlugDevice(p_ctrl->addr); } @@ -358,7 +360,7 @@ void bta_hd_add_device_act(tBTA_HD_DATA* p_data) { void bta_hd_remove_device_act(tBTA_HD_DATA* p_data) { tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); HID_DevUnplugDevice(p_ctrl->addr); } @@ -377,7 +379,7 @@ void bta_hd_send_report_act(tBTA_HD_DATA* p_data) { uint8_t channel; uint8_t report_id; - APPL_TRACE_VERBOSE("%s", __func__); + LOG_VERBOSE("%s", __func__); channel = p_report->use_intr ? HID_CHANNEL_INTR : HID_CHANNEL_CTRL; report_id = @@ -404,12 +406,12 @@ void bta_hd_report_error_act(tBTA_HD_DATA* p_data) { tBTA_HD_REPORT_ERR* p_report = (tBTA_HD_REPORT_ERR*)p_data; tHID_STATUS ret; - APPL_TRACE_API("%s: error = %d", __func__, p_report->error); + LOG_VERBOSE("%s: error = %d", __func__, p_report->error); ret = HID_DevReportError(p_report->error); if (ret != HID_SUCCESS) { - APPL_TRACE_WARNING("%s: HID_DevReportError returned %d", __func__, ret); + LOG_WARN("%s: HID_DevReportError returned %d", __func__, ret); } } @@ -425,15 +427,14 @@ void bta_hd_report_error_act(tBTA_HD_DATA* p_data) { void bta_hd_vc_unplug_act() { tHID_STATUS ret; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_hd_cb.vc_unplug = TRUE; ret = HID_DevVirtualCableUnplug(); if (ret != HID_SUCCESS) { - APPL_TRACE_WARNING("%s: HID_DevVirtualCableUnplug returned %d", __func__, - ret); + LOG_WARN("%s: HID_DevVirtualCableUnplug returned %d", __func__, ret); } /* trigger PM */ @@ -454,7 +455,7 @@ void bta_hd_open_act(tBTA_HD_DATA* p_data) { tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data; tBTA_HD cback_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); HID_DevPlugDevice(p_cback->addr); bta_sys_conn_open(BTA_ID_HD, 1, p_cback->addr); @@ -479,7 +480,7 @@ void bta_hd_close_act(tBTA_HD_DATA* p_data) { tBTA_HD cback_data; tBTA_HD_EVT cback_event = BTA_HD_CLOSE_EVT; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr); @@ -511,7 +512,7 @@ void bta_hd_intr_data_act(tBTA_HD_DATA* p_data) { uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset; tBTA_HD_INTR_DATA ret; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) { if (len < 1) { @@ -549,7 +550,7 @@ void bta_hd_get_report_act(tBTA_HD_DATA* p_data) { uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset; tBTA_HD_GET_REPORT ret = {0, 0, 0}; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); uint16_t remaining_len = p_msg->len; if (remaining_len < 1) { @@ -597,7 +598,7 @@ void bta_hd_set_report_act(tBTA_HD_DATA* p_data) { uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset; tBTA_HD_SET_REPORT ret = {0, 0, 0, NULL}; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (len < 1) { return; @@ -639,7 +640,7 @@ void bta_hd_set_protocol_act(tBTA_HD_DATA* p_data) { tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data; tBTA_HD cback_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_hd_cb.boot_mode = (p_cback->data == HID_PAR_PROTOCOL_BOOT_MODE); cback_data.set_protocol = p_cback->data; @@ -660,7 +661,7 @@ void bta_hd_vc_unplug_done_act(tBTA_HD_DATA* p_data) { tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data; tBTA_HD cback_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr); @@ -684,7 +685,7 @@ void bta_hd_vc_unplug_done_act(tBTA_HD_DATA* p_data) { void bta_hd_suspend_act(tBTA_HD_DATA* p_data) { tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_sys_idle(BTA_ID_HD, 1, p_cback->addr); } @@ -701,7 +702,7 @@ void bta_hd_suspend_act(tBTA_HD_DATA* p_data) { void bta_hd_exit_suspend_act(tBTA_HD_DATA* p_data) { tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data; - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_sys_busy(BTA_ID_HD, 1, p_cback->addr); bta_sys_idle(BTA_ID_HD, 1, p_cback->addr); @@ -721,7 +722,7 @@ static void bta_hd_cback(const RawAddress& bd_addr, uint8_t event, tBTA_HD_CBACK_DATA* p_buf = NULL; uint16_t sm_event = BTA_HD_INVALID_EVT; - APPL_TRACE_API("%s: event=%d", __func__, event); + LOG_VERBOSE("%s: event=%d", __func__, event); switch (event) { case HID_DHOST_EVT_OPEN: diff --git a/system/bta/hd/bta_hd_api.cc b/system/bta/hd/bta_hd_api.cc index 72ed04198f273d548c75b08bd56a2a69b84a7952..b6aa6b9355e32829d40e39941467b074f9b92c0d 100644 --- a/system/bta/hd/bta_hd_api.cc +++ b/system/bta/hd/bta_hd_api.cc @@ -52,7 +52,7 @@ static const tBTA_SYS_REG bta_hd_reg = {bta_hd_hdl_event, BTA_HdDisable}; * ******************************************************************************/ void BTA_HdEnable(tBTA_HD_CBACK* p_cback) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_sys_register(BTA_ID_HD, &bta_hd_reg); @@ -77,7 +77,7 @@ void BTA_HdEnable(tBTA_HD_CBACK* p_cback) { * ******************************************************************************/ void BTA_HdDisable(void) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!bluetooth::common::init_flags:: delay_hidh_cleanup_until_hidh_ready_start_is_enabled()) { @@ -101,7 +101,7 @@ void BTA_HdDisable(void) { ******************************************************************************/ void BTA_HdRegisterApp(tBTA_HD_APP_INFO* p_app_info, tBTA_HD_QOS_INFO* p_in_qos, tBTA_HD_QOS_INFO* p_out_qos) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HD_REGISTER_APP* p_buf = (tBTA_HD_REGISTER_APP*)osi_malloc(sizeof(tBTA_HD_REGISTER_APP)); @@ -153,7 +153,7 @@ void BTA_HdRegisterApp(tBTA_HD_APP_INFO* p_app_info, tBTA_HD_QOS_INFO* p_in_qos, * ******************************************************************************/ void BTA_HdUnregisterApp(void) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID)); p_buf->event = BTA_HD_API_UNREGISTER_APP_EVT; @@ -171,10 +171,10 @@ void BTA_HdUnregisterApp(void) { * ******************************************************************************/ void BTA_HdSendReport(tBTA_HD_REPORT* p_report) { - APPL_TRACE_VERBOSE("%s", __func__); + LOG_VERBOSE("%s", __func__); if (p_report->len > BTA_HD_REPORT_LEN) { - APPL_TRACE_WARNING( + LOG_WARN( "%s, report len (%d) > MTU len (%d), can't send report." " Increase value of HID_DEV_MTU_SIZE to send larger reports", __func__, p_report->len, BTA_HD_REPORT_LEN); @@ -204,7 +204,7 @@ void BTA_HdSendReport(tBTA_HD_REPORT* p_report) { * ******************************************************************************/ void BTA_HdVirtualCableUnplug(void) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID)); p_buf->event = BTA_HD_API_VC_UNPLUG_EVT; @@ -223,7 +223,7 @@ void BTA_HdVirtualCableUnplug(void) { * ******************************************************************************/ void BTA_HdConnect(const RawAddress& addr) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HD_DEVICE_CTRL* p_buf = (tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL)); @@ -244,7 +244,7 @@ void BTA_HdConnect(const RawAddress& addr) { * ******************************************************************************/ void BTA_HdDisconnect(void) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID)); p_buf->event = BTA_HD_API_DISCONNECT_EVT; @@ -261,7 +261,7 @@ void BTA_HdDisconnect(void) { * ******************************************************************************/ void BTA_HdAddDevice(const RawAddress& addr) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HD_DEVICE_CTRL* p_buf = (tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL)); p_buf->hdr.event = BTA_HD_API_ADD_DEVICE_EVT; @@ -281,7 +281,7 @@ void BTA_HdAddDevice(const RawAddress& addr) { * ******************************************************************************/ void BTA_HdRemoveDevice(const RawAddress& addr) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HD_DEVICE_CTRL* p_buf = (tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL)); p_buf->hdr.event = BTA_HD_API_REMOVE_DEVICE_EVT; @@ -301,7 +301,7 @@ void BTA_HdRemoveDevice(const RawAddress& addr) { * ******************************************************************************/ void BTA_HdReportError(uint8_t error) { - APPL_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HD_REPORT_ERR* p_buf = (tBTA_HD_REPORT_ERR*)osi_malloc(sizeof(tBTA_HD_REPORT_ERR)); p_buf->hdr.event = BTA_HD_API_REPORT_ERROR_EVT; diff --git a/system/bta/hd/bta_hd_int.h b/system/bta/hd/bta_hd_int.h index 4953da60df0c296341b77960a6187381817b17d4..5e03e7d16288306cdc96c9996aba77a073fa2ec2 100644 --- a/system/bta/hd/bta_hd_int.h +++ b/system/bta/hd/bta_hd_int.h @@ -30,8 +30,8 @@ #include "bta/include/bta_hd_api.h" #include "bta/sys/bta_sys.h" +#include "internal_include/bt_target.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "stack/include/hiddefs.h" #include "types/raw_address.h" @@ -137,7 +137,6 @@ typedef struct { typedef struct { tBTA_HD_CBACK* p_cback; uint32_t sdp_handle; - uint8_t trace_level; uint8_t state; RawAddress bd_addr; bool use_report_id; @@ -151,7 +150,7 @@ extern tBTA_HD_CB bta_hd_cb; /***************************************************************************** * Function prototypes ****************************************************************************/ -bool bta_hd_hdl_event(BT_HDR_RIGID* p_msg); +bool bta_hd_hdl_event(const BT_HDR_RIGID* p_msg); void bta_hd_api_enable(tBTA_HD_DATA* p_data); void bta_hd_api_disable(void); diff --git a/system/bta/hd/bta_hd_main.cc b/system/bta/hd/bta_hd_main.cc index 67ff3fc5dac3bc75688b4b707a4b644cb6707c12..79799ed2c92ba79e39dbf84fce314e16f14b6927 100644 --- a/system/bta/hd/bta_hd_main.cc +++ b/system/bta/hd/bta_hd_main.cc @@ -25,8 +25,7 @@ #include -// BTA_HD_INCLUDED -#include "bt_target.h" // Must be first to define build configuration +#include "internal_include/bt_target.h" #if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE) #include "bta/hd/bta_hd_int.h" @@ -177,8 +176,8 @@ static void bta_hd_better_state_machine(uint16_t event, tBTA_HD_DATA* p_data) { * Returns void * ******************************************************************************/ -bool bta_hd_hdl_event(BT_HDR_RIGID* p_msg) { - APPL_TRACE_API("%s: p_msg->event=%d", __func__, p_msg->event); +bool bta_hd_hdl_event(const BT_HDR_RIGID* p_msg) { + LOG_VERBOSE("%s: p_msg->event=%d", __func__, p_msg->event); switch (p_msg->event) { case BTA_HD_API_ENABLE_EVT: @@ -187,8 +186,7 @@ bool bta_hd_hdl_event(BT_HDR_RIGID* p_msg) { case BTA_HD_API_DISABLE_EVT: if (bta_hd_cb.state == BTA_HD_CONN_ST) { - APPL_TRACE_WARNING("%s: host connected, disconnect before disabling", - __func__); + LOG_WARN("%s: host connected, disconnect before disabling", __func__); // unregister (and disconnect) bta_hd_cb.disable_w4_close = TRUE; diff --git a/system/bta/hearing_aid/OWNERS b/system/bta/hearing_aid/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..bbaa85ddbb41407029721ce62189f0419a9d9da2 --- /dev/null +++ b/system/bta/hearing_aid/OWNERS @@ -0,0 +1 @@ +include /OWNERS_hearingaid diff --git a/system/bta/hearing_aid/hearing_aid.cc b/system/bta/hearing_aid/hearing_aid.cc index 50835a4b2494828c1f95ef3f6987e4a839cef304..5530abbabb3f3acd86d9b0002613aded4c8166e1 100644 --- a/system/bta/hearing_aid/hearing_aid.cc +++ b/system/bta/hearing_aid/hearing_aid.cc @@ -20,6 +20,7 @@ #define LOG_TAG "bluetooth" +#include #include #include #include @@ -34,17 +35,18 @@ #include "bta/include/bta_gatt_queue.h" #include "bta/include/bta_hearing_aid_api.h" #include "btm_iso_api.h" -#include "common/init_flags.h" #include "device/include/controller.h" #include "embdrv/g722/g722_enc_dec.h" -#include "osi/include/compat.h" -#include "osi/include/log.h" +#include "hardware/bt_gatt_types.h" +#include "os/log.h" +#include "osi/include/allocator.h" #include "osi/include/properties.h" #include "stack/btm/btm_sec.h" #include "stack/include/acl_api.h" // BTM_ReadRSSI #include "stack/include/acl_api_types.h" // tBTM_RSSI_RESULT #include "stack/include/bt_hdr.h" -#include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/l2c_api.h" // L2CAP_MIN_OFFSET #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" @@ -160,6 +162,16 @@ class HearingDevices { return (iter == devices.end()) ? nullptr : &(*iter); } + HearingDevice* FindOtherConnectedDeviceFromSet(const HearingDevice& device) { + auto iter = std::find_if( + devices.begin(), devices.end(), [&device](const HearingDevice& other) { + return &device != &other && device.hi_sync_id == other.hi_sync_id && + other.conn_id != 0; + }); + + return (iter == devices.end()) ? nullptr : &(*iter); + } + HearingDevice* FindByConnId(uint16_t conn_id) { auto iter = std::find_if(devices.begin(), devices.end(), [&conn_id](const HearingDevice& device) { @@ -178,14 +190,6 @@ class HearingDevices { return (iter == devices.end()) ? nullptr : &(*iter); } - bool IsAnyConnectionUpdateStarted() { - for (const auto& d : devices) { - if (d.connection_update_status == STARTED) return true; - } - - return false; - } - void StartRssiLog() { int read_rssi_start_interval_count = 0; @@ -424,7 +428,7 @@ class HearingAidImpl : public HearingAid { BTA_GATTC_Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); } - void AddFromStorage(const HearingDevice& dev_info, uint16_t is_acceptlisted) { + void AddFromStorage(const HearingDevice& dev_info, bool is_acceptlisted) { LOG_DEBUG("%s, hiSyncId=%s, isAcceptlisted=%u", ADDRESS_TO_LOGGABLE_CSTR(dev_info.address), loghex(dev_info.hi_sync_id).c_str(), is_acceptlisted); @@ -468,31 +472,45 @@ class HearingAidImpl : public HearingAid { return; } - LOG_INFO("Failed to connect to Hearing Aid device"); - hearingDevices.Remove(address); - callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address); + if (hearingDevice->switch_to_background_connection_after_failure) { + hearingDevice->connecting_actively = false; + hearingDevice->switch_to_background_connection_after_failure = false; + BTA_GATTC_Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); + } else { + LOG_INFO("Failed to connect to Hearing Aid device, bda=%s", + ADDRESS_TO_LOGGABLE_CSTR(address)); + + hearingDevices.Remove(address); + callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address); + } return; } hearingDevice->conn_id = conn_id; - /* We must update connection parameters one at a time, otherwise anchor - * point (start of connection event) for two devices can be too close to - * each other. Here, by setting min_ce_len=max_ce_len=X, we force controller - * to move anchor point of both connections away from each other, to make - * sure we'll be able to fit all the data we want in one connection event. - */ - bool any_update_pending = hearingDevices.IsAnyConnectionUpdateStarted(); - // mark the device as pending connection update. If we don't start the - // update now, it'll be started once current device finishes. - if (!any_update_pending) { - hearingDevice->connection_update_status = STARTED; - hearingDevice->requested_connection_interval = - UpdateBleConnParams(address); - } else { - hearingDevice->connection_update_status = AWAITING; + uint64_t hi_sync_id = hearingDevice->hi_sync_id; + + // If there a background connection to the other device of a pair, promote + // it to a direct connection to scan more agressively for it + if (hi_sync_id != 0) { + for (auto& device : hearingDevices.devices) { + if (device.hi_sync_id == hi_sync_id && device.conn_id == 0 && + !device.connecting_actively) { + LOG_INFO( + "Promoting device from the set from background to direct" + "connection, bda=%s", + ADDRESS_TO_LOGGABLE_CSTR(device.address)); + device.connecting_actively = true; + device.switch_to_background_connection_after_failure = true; + BTA_GATTC_Open(gatt_if, device.address, BTM_BLE_DIRECT_CONNECTION, + false); + } + } } + hearingDevice->connection_update_status = STARTED; + hearingDevice->requested_connection_interval = UpdateBleConnParams(address); + if (controller_get_interface()->supports_ble_2m_phy()) { LOG_INFO("%s set preferred 2M PHY", ADDRESS_TO_LOGGABLE_CSTR(address)); BTM_BleSetPhy(address, PHY_LE_2M, PHY_LE_2M, 0); @@ -907,8 +925,10 @@ class HearingAidImpl : public HearingAid { hearingDevice->capabilities = capabilities; bool side = capabilities & CAPABILITY_SIDE; bool standalone = capabilities & CAPABILITY_BINAURAL; - LOG_DEBUG("capabilities: %s, %s", (side ? "right" : "left"), - (standalone ? "binaural" : "monaural")); + bool csis_capable = capabilities & CAPABILITY_CSIS; + LOG_DEBUG("capabilities: %s, %s, CSIS %s", (side ? "right" : "left"), + (standalone ? "binaural" : "monaural"), + (csis_capable ? "capable" : "not capable")); if (capabilities & CAPABILITY_RESERVED) { LOG_WARN("reserved capabilities are set"); @@ -1392,6 +1412,11 @@ class HearingAidImpl : public HearingAid { } } + uint16_t l2cap_flush_threshold = 0; + if (IS_FLAG_ENABLED(higher_l2cap_flush_threshold)) { + l2cap_flush_threshold = 1; + } + // TODO: monural, binarual check // divide encoded data into packets, add header, send. @@ -1412,7 +1437,7 @@ class HearingAidImpl : public HearingAid { uint16_t cid = GAP_ConnGetL2CAPCid(left->gap_handle); uint16_t packets_in_chans = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); - if (packets_in_chans) { + if (packets_in_chans > l2cap_flush_threshold) { // Compare the two sides LE CoC credit value to confirm need to drop or // skip audio packet. if (NeedToDropPacket(left, right) && IsBelowDropFrequency(time_point)) { @@ -1446,7 +1471,7 @@ class HearingAidImpl : public HearingAid { uint16_t cid = GAP_ConnGetL2CAPCid(right->gap_handle); uint16_t packets_in_chans = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); - if (packets_in_chans) { + if (packets_in_chans > l2cap_flush_threshold) { // Compare the two sides LE CoC credit value to confirm need to drop or // skip audio packet. if (NeedToDropPacket(right, left) && IsBelowDropFrequency(time_point)) { @@ -1763,10 +1788,31 @@ class HearingAidImpl : public HearingAid { DoDisconnectCleanUp(hearingDevice); + HearingDevice* other_connected_device_from_set = + hearingDevices.FindOtherConnectedDeviceFromSet(*hearingDevice); + + if (other_connected_device_from_set != nullptr) { + LOG_INFO( + "Another device from the set is still connected, issuing a direct " + "connection, other_device_bda=%s", + ADDRESS_TO_LOGGABLE_CSTR(other_connected_device_from_set->address)); + } + + // If another device from the pair is still connected, do a direct + // connection to scan more aggressively and connect as fast as possible + hearingDevice->connecting_actively = + other_connected_device_from_set != nullptr; + + auto connection_type = hearingDevice->connecting_actively + ? BTM_BLE_DIRECT_CONNECTION + : BTM_BLE_BKG_CONNECT_ALLOW_LIST; + + hearingDevice->switch_to_background_connection_after_failure = + connection_type == BTM_BLE_DIRECT_CONNECTION; + // This is needed just for the first connection. After stack is restarted, // code that loads device will add them to acceptlist. - BTA_GATTC_Open(gatt_if, hearingDevice->address, - BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); + BTA_GATTC_Open(gatt_if, hearingDevice->address, connection_type, false); callbacks->OnConnectionState(ConnectionState::DISCONNECTED, remote_bda); @@ -2094,7 +2140,7 @@ void HearingAid::SetVolume(int8_t volume) { } void HearingAid::AddFromStorage(const HearingDevice& dev_info, - uint16_t is_acceptlisted) { + bool is_acceptlisted) { if (!instance) { LOG_ERROR("Not initialized yet"); } diff --git a/system/bta/hearing_aid/hearing_aid_audio_source.cc b/system/bta/hearing_aid/hearing_aid_audio_source.cc index e347f872ac8cf2473f0f6a9bba9374cc5046f599..7a284e97ccfa72e67643ed60acd8155c30fcc236 100644 --- a/system/bta/hearing_aid/hearing_aid_audio_source.cc +++ b/system/bta/hearing_aid/hearing_aid_audio_source.cc @@ -31,7 +31,7 @@ #include "common/time_util.h" #include "osi/include/log.h" #include "osi/include/wakelock.h" -#include "stack/include/btu.h" // get_main_thread +#include "stack/include/main_thread.h" #include "udrv/include/uipc.h" using base::FilePath; diff --git a/system/bta/hf_client/bta_hf_client_act.cc b/system/bta/hf_client/bta_hf_client_act.cc index 175f703f6550a93037dc25bef52c5f4787e74d5e..2bd622cea3a368b09784996f0d0580befb40d09d 100644 --- a/system/bta/hf_client/bta_hf_client_act.cc +++ b/system/bta/hf_client/bta_hf_client_act.cc @@ -23,16 +23,14 @@ * ******************************************************************************/ -#include "bt_trace.h" // Legacy trace logging - #include "bta/hf_client/bta_hf_client_int.h" #include "bta/include/bta_dm_api.h" +#include "os/log.h" #include "stack/include/l2c_api.h" #include "stack/include/port_api.h" +#include "stack/include/sdp_status.h" #include "types/raw_address.h" -#include - /***************************************************************************** * Constants ****************************************************************************/ @@ -54,8 +52,8 @@ void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: wrong handle to control block %d", __func__, + p_data->hdr.layer_specific); return; } @@ -88,8 +86,8 @@ void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: wrong handle to control block %d", __func__, + p_data->hdr.layer_specific); return; } @@ -127,12 +125,12 @@ void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA* p_data) { * ******************************************************************************/ void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -153,25 +151,25 @@ void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA* p_data) { * ******************************************************************************/ void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } /* set role */ client_cb->role = BTA_HF_CLIENT_ACP; - APPL_TRACE_DEBUG("%s: conn_handle %d", __func__, client_cb->conn_handle); + LOG_VERBOSE("%s: conn_handle %d", __func__, client_cb->conn_handle); /* get bd addr of peer */ uint16_t lcid = 0; RawAddress dev_addr = RawAddress::kEmpty; int status = PORT_CheckConnection(client_cb->conn_handle, &dev_addr, &lcid); if (status != PORT_SUCCESS) { - LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status; + LOG_ERROR("PORT_CheckConnection returned status:%d", status); } /* Collision Handling */ @@ -211,8 +209,8 @@ void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -241,8 +239,8 @@ void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } } @@ -261,8 +259,8 @@ void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } } @@ -281,8 +279,8 @@ void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -324,12 +322,12 @@ void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA* p_data) { void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA* p_data) { uint16_t event = BTA_HF_CLIENT_DISC_FAIL_EVT; - APPL_TRACE_DEBUG("%s: Status: %d", __func__, p_data->disc_result.status); + LOG_VERBOSE("%s: Status: %d", __func__, p_data->disc_result.status); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -363,8 +361,8 @@ void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -393,8 +391,8 @@ void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -429,12 +427,12 @@ void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA* p_data) { * ******************************************************************************/ void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } diff --git a/system/bta/hf_client/bta_hf_client_api.cc b/system/bta/hf_client/bta_hf_client_api.cc index 0cbaac12cbb9d6f35d0969cc4cda81804495f9f0..62092bd0f159b9de98e0b11f84ee7e0c87a0163c 100644 --- a/system/bta/hf_client/bta_hf_client_api.cc +++ b/system/bta/hf_client/bta_hf_client_api.cc @@ -26,19 +26,16 @@ #include "bta/include/bta_hf_client_api.h" -#include +#include -#ifdef __ANDROID__ -#include -#endif +#include -#include "bt_trace.h" // Legacy trace logging #include "bta/hf_client/bta_hf_client_int.h" #include "bta/sys/bta_sys.h" +#include "internal_include/bt_trace.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "types/raw_address.h" /***************************************************************************** @@ -88,12 +85,12 @@ void BTA_HfClientDisable(void) { bta_hf_client_api_disable(); } * ******************************************************************************/ bt_status_t BTA_HfClientOpen(const RawAddress& bd_addr, uint16_t* p_handle) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_API_OPEN* p_buf = (tBTA_HF_CLIENT_API_OPEN*)osi_malloc(sizeof(tBTA_HF_CLIENT_API_OPEN)); if (!bta_hf_client_allocate_handle(bd_addr, p_handle)) { - APPL_TRACE_ERROR("%s: could not allocate handle", __func__); + LOG_ERROR("%s: could not allocate handle", __func__); return BT_STATUS_FAIL; } @@ -225,12 +222,5 @@ int get_default_hf_client_features() { BTA_HF_CLIENT_FEAT_CLI | BTA_HF_CLIENT_FEAT_VREC | BTA_HF_CLIENT_FEAT_VOL | \ BTA_HF_CLIENT_FEAT_ECS | BTA_HF_CLIENT_FEAT_ECC | BTA_HF_CLIENT_FEAT_CODEC) -#ifdef __ANDROID__ - static const int features = - android::sysprop::bluetooth::Hfp::hf_client_features().value_or( - DEFAULT_BTIF_HF_CLIENT_FEATURES); - return features; -#else - return DEFAULT_BTIF_HF_CLIENT_FEATURES; -#endif + return GET_SYSPROP(Hfp, hf_client_features, DEFAULT_BTIF_HF_CLIENT_FEATURES); } diff --git a/system/bta/hf_client/bta_hf_client_at.cc b/system/bta/hf_client/bta_hf_client_at.cc index da37a07cade2a3a8afdb786a61b9b80ce18771e3..64bc1ed18b7df052291097c3443c24c2c48adea7 100644 --- a/system/bta/hf_client/bta_hf_client_at.cc +++ b/system/bta/hf_client/bta_hf_client_at.cc @@ -19,8 +19,8 @@ #define LOG_TAG "bt_hf_client" -#include "bt_trace.h" // Legacy trace logging #include "bta/hf_client/bta_hf_client_int.h" +#include "internal_include/bt_trace.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "osi/include/log.h" @@ -40,6 +40,9 @@ /* timeout (in milliseconds) for AT hold timer */ #define BTA_HF_CLIENT_AT_HOLD_TIMEOUT 41 +static constexpr char kPropertyEnhancedDrivingIndicatorEnabled[] = + "bluetooth.headset_client.indicator.enhanced_driver_safety.enabled"; + /****************************************************************************** * SUPPORTED EVENT MESSAGES ******************************************************************************/ @@ -125,7 +128,7 @@ static void bta_hf_client_queue_at(tBTA_HF_CLIENT_CB* client_cb, tBTA_HF_CLIENT_AT_QCMD* new_cmd = (tBTA_HF_CLIENT_AT_QCMD*)osi_malloc(sizeof(tBTA_HF_CLIENT_AT_QCMD)); - APPL_TRACE_DEBUG("%s: cmd:%d", __func__, (int)cmd); + LOG_VERBOSE("%s: cmd:%d", __func__, (int)cmd); new_cmd->cmd = cmd; new_cmd->buf_len = buf_len; @@ -150,7 +153,7 @@ static void bta_hf_client_at_resp_timer_cback(void* data) { __func__); bta_hf_client_handle_ok(client_cb); } else { - APPL_TRACE_ERROR("HFPClient: AT response timeout, disconnecting"); + LOG_ERROR("HFPClient: AT response timeout, disconnecting"); tBTA_HF_CLIENT_DATA msg = {}; msg.hdr.layer_specific = client_cb->handle; @@ -170,27 +173,27 @@ static void bta_hf_client_stop_at_resp_timer(tBTA_HF_CLIENT_CB* client_cb) { static void bta_hf_client_send_at(tBTA_HF_CLIENT_CB* client_cb, tBTA_HF_CLIENT_AT_CMD cmd, const char* buf, uint16_t buf_len) { - APPL_TRACE_DEBUG("%s %d", __func__, cmd); + LOG_VERBOSE("%s %d", __func__, cmd); if ((client_cb->at_cb.current_cmd == BTA_HF_CLIENT_AT_NONE || !client_cb->svc_conn) && !alarm_is_scheduled(client_cb->at_cb.hold_timer)) { uint16_t len; #ifdef BTA_HF_CLIENT_AT_DUMP - APPL_TRACE_DEBUG("%s: %.*s", __func__, buf_len - 1, buf); + LOG_VERBOSE("%s: %.*s", __func__, buf_len - 1, buf); #endif client_cb->at_cb.current_cmd = cmd; /* Generate fake responses for these because they won't reliably work */ if (!service_availability && (cmd == BTA_HF_CLIENT_AT_CNUM || cmd == BTA_HF_CLIENT_AT_COPS)) { - APPL_TRACE_WARNING("%s: No service, skipping %d command", __func__, cmd); + LOG_WARN("%s: No service, skipping %d command", __func__, cmd); bta_hf_client_handle_ok(client_cb); return; } - APPL_TRACE_DEBUG("%s: writing port data to %d", __func__, - client_cb->conn_handle); + LOG_VERBOSE("%s: writing port data to %d", __func__, + client_cb->conn_handle); PORT_WriteData(client_cb->conn_handle, buf, buf_len, &len); bta_hf_client_start_at_resp_timer(client_cb); @@ -198,14 +201,14 @@ static void bta_hf_client_send_at(tBTA_HF_CLIENT_CB* client_cb, return; } - APPL_TRACE_DEBUG("%s: busy! queued: %d", __func__, cmd); + LOG_VERBOSE("%s: busy! queued: %d", __func__, cmd); bta_hf_client_queue_at(client_cb, cmd, buf, buf_len); } static void bta_hf_client_send_queued_at(tBTA_HF_CLIENT_CB* client_cb) { tBTA_HF_CLIENT_AT_QCMD* cur = client_cb->at_cb.queued_cmd; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (cur != NULL) { client_cb->at_cb.queued_cmd = cur->next; @@ -218,17 +221,17 @@ static void bta_hf_client_send_queued_at(tBTA_HF_CLIENT_CB* client_cb) { static void bta_hf_client_at_hold_timer_cback(void* data) { tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_hf_client_send_queued_at(client_cb); } static void bta_hf_client_stop_at_hold_timer(tBTA_HF_CLIENT_CB* client_cb) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); alarm_cancel(client_cb->at_cb.hold_timer); } static void bta_hf_client_start_at_hold_timer(tBTA_HF_CLIENT_CB* client_cb) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); alarm_set_on_mloop(client_cb->at_cb.hold_timer, BTA_HF_CLIENT_AT_HOLD_TIMEOUT, bta_hf_client_at_hold_timer_cback, (void*)client_cb); } @@ -242,8 +245,7 @@ static void bta_hf_client_start_at_hold_timer(tBTA_HF_CLIENT_CB* client_cb) { ******************************************************************************/ static void bta_hf_client_handle_ok(tBTA_HF_CLIENT_CB* client_cb) { - APPL_TRACE_DEBUG("%s: current_cmd:%d", __func__, - client_cb->at_cb.current_cmd); + LOG_VERBOSE("%s: current_cmd:%d", __func__, client_cb->at_cb.current_cmd); bta_hf_client_stop_at_resp_timer(client_cb); @@ -287,8 +289,8 @@ static void bta_hf_client_handle_ok(tBTA_HF_CLIENT_CB* client_cb) { static void bta_hf_client_handle_error(tBTA_HF_CLIENT_CB* client_cb, tBTA_HF_CLIENT_AT_RESULT_TYPE type, uint16_t cme) { - APPL_TRACE_DEBUG("%s: type:%u cme:%u current_cmd:%d", __func__, type, cme, - client_cb->at_cb.current_cmd); + LOG_VERBOSE("%s: type:%u cme:%u current_cmd:%d", __func__, type, cme, + client_cb->at_cb.current_cmd); bta_hf_client_stop_at_resp_timer(client_cb); @@ -325,7 +327,7 @@ static void bta_hf_client_handle_error(tBTA_HF_CLIENT_CB* client_cb, } static void bta_hf_client_handle_ring(tBTA_HF_CLIENT_CB* client_cb) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); const bool exit_sniff_while_ring = osi_property_get_bool( "bluetooth.headset_client.exit_sniff_while_ring", false); @@ -344,7 +346,7 @@ static void bta_hf_client_handle_ring(tBTA_HF_CLIENT_CB* client_cb) { static void bta_hf_client_handle_brsf(tBTA_HF_CLIENT_CB* client_cb, uint32_t value) { - APPL_TRACE_DEBUG("%s: 0x%x", __func__, value); + LOG_VERBOSE("%s: 0x%x", __func__, value); client_cb->peer_features = value; } @@ -355,7 +357,8 @@ static void bta_hf_client_handle_cind_list_item(tBTA_HF_CLIENT_CB* client_cb, uint32_t max, uint32_t index) { uint8_t i = 0; - APPL_TRACE_DEBUG("%s: %lu.%s <%lu:%lu>", __func__, index, name, min, max); + LOG_VERBOSE("%s: %" PRIu32 ".%s <%" PRIu32 ":%" PRIu32 ">", __func__, index, + name, min, max); if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT) { return; @@ -386,7 +389,7 @@ static void bta_hf_client_handle_cind_list_item(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_cind_value(tBTA_HF_CLIENT_CB* client_cb, uint32_t index, uint32_t value) { - APPL_TRACE_DEBUG("%s: index: %u value: %u", __func__, index, value); + LOG_VERBOSE("%s: index: %u value: %u", __func__, index, value); if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT) { return; @@ -418,21 +421,21 @@ static void bta_hf_client_handle_cind_value(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_chld(tBTA_HF_CLIENT_CB* client_cb, uint32_t mask) { - APPL_TRACE_DEBUG("%s: 0x%x", __func__, mask); + LOG_VERBOSE("%s: 0x%x", __func__, mask); client_cb->chld_features |= mask; } static void bta_hf_client_handle_bind_read_supported_ind( tBTA_HF_CLIENT_CB* client_cb, int indicator_id) { - APPL_TRACE_DEBUG("%s: %d", __func__, indicator_id); + LOG_VERBOSE("%s: %d", __func__, indicator_id); client_cb->peer_hf_indicators.insert(indicator_id); } static void bta_hf_client_handle_bind_read_enabled_ind( tBTA_HF_CLIENT_CB* client_cb, int indicator_id, bool enable) { - APPL_TRACE_DEBUG("%s: %d", __func__, indicator_id); + LOG_VERBOSE("%s: %d", __func__, indicator_id); if (enable) { client_cb->enabled_hf_indicators.insert(indicator_id); @@ -445,7 +448,7 @@ static void bta_hf_client_handle_ciev(tBTA_HF_CLIENT_CB* client_cb, uint32_t index, uint32_t value) { int8_t realind = -1; - APPL_TRACE_DEBUG("%s: index: %u value: %u", __func__, index, value); + LOG_VERBOSE("%s: index: %u value: %u", __func__, index, value); if (index == 0 || index > BTA_HF_CLIENT_AT_INDICATOR_COUNT) { return; @@ -481,10 +484,24 @@ static void bta_hf_client_handle_ciev(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_bcs(tBTA_HF_CLIENT_CB* client_cb, uint32_t codec) { - APPL_TRACE_DEBUG("%s: codec: %u sco listen state: %d", __func__, codec, - client_cb->sco_state); - if (codec == BTM_SCO_CODEC_CVSD || codec == BTM_SCO_CODEC_MSBC) { - client_cb->negotiated_codec = codec; + LOG_VERBOSE("%s: codec: %u sco listen state: %d", __func__, codec, + client_cb->sco_state); + if (codec == UUID_CODEC_CVSD || codec == UUID_CODEC_MSBC || + (bta_hf_client_cb_arr.is_support_lc3 && codec == UUID_CODEC_LC3)) { + switch (codec) { + case UUID_CODEC_CVSD: + client_cb->negotiated_codec = BTM_SCO_CODEC_CVSD; + break; + case UUID_CODEC_MSBC: + client_cb->negotiated_codec = BTM_SCO_CODEC_MSBC; + break; + case UUID_CODEC_LC3: + client_cb->negotiated_codec = BTM_SCO_CODEC_LC3; + break; + default: + client_cb->negotiated_codec = BTM_SCO_CODEC_CVSD; + break; + } bta_hf_client_send_at_bcs(client_cb, codec); } else { client_cb->negotiated_codec = BTM_SCO_CODEC_CVSD; @@ -494,7 +511,7 @@ static void bta_hf_client_handle_bcs(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_bsir(tBTA_HF_CLIENT_CB* client_cb, uint32_t provided) { - APPL_TRACE_DEBUG("%s: %u", __func__, provided); + LOG_VERBOSE("%s: %" PRIu32, __func__, provided); bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_BSIR_EVT, provided); } @@ -506,7 +523,7 @@ static void bta_hf_client_handle_cmeerror(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_vgm(tBTA_HF_CLIENT_CB* client_cb, uint32_t value) { - APPL_TRACE_DEBUG("%s: %lu", __func__, value); + LOG_VERBOSE("%s: %" PRIu32, __func__, value); if (value <= BTA_HF_CLIENT_VGM_MAX) { bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_MIC_EVT, value); @@ -515,7 +532,7 @@ static void bta_hf_client_handle_vgm(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_vgs(tBTA_HF_CLIENT_CB* client_cb, uint32_t value) { - APPL_TRACE_DEBUG("%s: %lu", __func__, value); + LOG_VERBOSE("%s: %" PRIu32, __func__, value); if (value <= BTA_HF_CLIENT_VGS_MAX) { bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_SPK_EVT, value); @@ -524,7 +541,7 @@ static void bta_hf_client_handle_vgs(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_bvra(tBTA_HF_CLIENT_CB* client_cb, uint32_t value) { - APPL_TRACE_DEBUG("%s: %lu", __func__, value); + LOG_VERBOSE("%s: %" PRIu32, __func__, value); if (value > 1) { return; @@ -535,28 +552,28 @@ static void bta_hf_client_handle_bvra(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_clip(tBTA_HF_CLIENT_CB* client_cb, char* numstr, uint32_t type) { - APPL_TRACE_DEBUG("%s: %u %s", __func__, type, numstr); + LOG_VERBOSE("%s: %u %s", __func__, type, numstr); bta_hf_client_clip(client_cb, numstr); } static void bta_hf_client_handle_ccwa(tBTA_HF_CLIENT_CB* client_cb, char* numstr, uint32_t type) { - APPL_TRACE_DEBUG("%s: %u %s", __func__, type, numstr); + LOG_VERBOSE("%s: %u %s", __func__, type, numstr); bta_hf_client_ccwa(client_cb, numstr); } static void bta_hf_client_handle_cops(tBTA_HF_CLIENT_CB* client_cb, char* opstr, uint32_t mode) { - APPL_TRACE_DEBUG("%s: %u %s", __func__, mode, opstr); + LOG_VERBOSE("%s: %u %s", __func__, mode, opstr); bta_hf_client_operator_name(client_cb, opstr); } static void bta_hf_client_handle_binp(tBTA_HF_CLIENT_CB* client_cb, char* numstr) { - APPL_TRACE_DEBUG("%s: %s", __func__, numstr); + LOG_VERBOSE("%s: %s", __func__, numstr); bta_hf_client_binp(client_cb, numstr); } @@ -566,11 +583,11 @@ static void bta_hf_client_handle_clcc(tBTA_HF_CLIENT_CB* client_cb, uint16_t status, uint16_t mode, uint16_t mpty, char* numstr, uint16_t type) { - APPL_TRACE_DEBUG("%s: idx: %u dir: %u status: %u mode: %u mpty: %u", __func__, - idx, dir, status, mode, mpty); + LOG_VERBOSE("%s: idx: %u dir: %u status: %u mode: %u mpty: %u", __func__, idx, + dir, status, mode, mpty); if (numstr) { - APPL_TRACE_DEBUG("%s: number: %s type: %u", __func__, numstr, type); + LOG_VERBOSE("%s: number: %s type: %u", __func__, numstr, type); } bta_hf_client_clcc(client_cb, idx, dir, status, mpty, numstr); @@ -579,8 +596,8 @@ static void bta_hf_client_handle_clcc(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_cnum(tBTA_HF_CLIENT_CB* client_cb, char* numstr, uint16_t type, uint16_t service) { - APPL_TRACE_DEBUG("%s: number: %s type: %u service: %u", __func__, numstr, - type, service); + LOG_VERBOSE("%s: number: %s type: %u service: %u", __func__, numstr, type, + service); /* TODO: should number be modified according to type? */ bta_hf_client_cnum(client_cb, numstr, service); @@ -588,7 +605,7 @@ static void bta_hf_client_handle_cnum(tBTA_HF_CLIENT_CB* client_cb, static void bta_hf_client_handle_btrh(tBTA_HF_CLIENT_CB* client_cb, uint16_t code) { - APPL_TRACE_DEBUG("%s: %lu", __func__, code); + LOG_VERBOSE("%s: %" PRIu32, __func__, code); bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_BTRH_EVT, code); } @@ -786,8 +803,8 @@ void bta_hf_client_unknown_response(tBTA_HF_CLIENT_CB* client_cb, tBTA_HF_CLIENT evt = {}; strlcpy(evt.unknown.event_string, evt_buffer, - BTA_HF_CLIENT_UNKOWN_EVENT_LEN + 1); - evt.unknown.event_string[BTA_HF_CLIENT_UNKOWN_EVENT_LEN] = '\0'; + BTA_HF_CLIENT_UNKNOWN_EVENT_LEN + 1); + evt.unknown.event_string[BTA_HF_CLIENT_UNKNOWN_EVENT_LEN] = '\0'; evt.unknown.bd_addr = client_cb->peer_addr; bta_hf_client_app_callback(BTA_HF_CLIENT_UNKNOWN_EVT, &evt); @@ -830,13 +847,13 @@ void bta_hf_client_binp(tBTA_HF_CLIENT_CB* client_cb, char* number) { } while (0) /* check for and forward buffer if match */ -#define AT_CHECK_RN(buf) \ - do { \ - if (strncmp("\r\n", buf, sizeof("\r\n") - 1) != 0) { \ - APPL_TRACE_DEBUG("%s: missing end ", __func__); \ - return NULL; \ - } \ - (buf) += sizeof("\r\n") - 1; \ +#define AT_CHECK_RN(buf) \ + do { \ + if (strncmp("\r\n", buf, sizeof("\r\n") - 1) != 0) { \ + LOG_VERBOSE("%s: missing end ", __func__); \ + return NULL; \ + } \ + (buf) += sizeof("\r\n") - 1; \ } while (0) /* skip rest of AT string up to */ @@ -948,7 +965,7 @@ static char* bta_hf_client_parse_cind_list(tBTA_HF_CLIENT_CB* client_cb, &max, &offset)) > 2) { bta_hf_client_handle_cind_list_item(client_cb, name, min, max, index); if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1087,7 +1104,7 @@ static char* bta_hf_client_parse_ciev(tBTA_HF_CLIENT_CB* client_cb, } if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1180,7 +1197,7 @@ static char* bta_hf_client_parse_clip(tBTA_HF_CLIENT_CB* client_cb, } if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1212,7 +1229,7 @@ static char* bta_hf_client_parse_ccwa(tBTA_HF_CLIENT_CB* client_cb, } if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1244,7 +1261,7 @@ static char* bta_hf_client_parse_cops(tBTA_HF_CLIENT_CB* client_cb, } /* Abort in case offset not set because of format error */ if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1281,7 +1298,7 @@ static char* bta_hf_client_parse_binp(tBTA_HF_CLIENT_CB* client_cb, /* Abort in case offset not set because of format error */ if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1321,7 +1338,7 @@ static char* bta_hf_client_parse_clcc(tBTA_HF_CLIENT_CB* client_cb, /* Abort in case offset not set because of format error */ if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1346,7 +1363,7 @@ static char* bta_hf_client_parse_clcc(tBTA_HF_CLIENT_CB* client_cb, res += res2; /* Abort in case offset not set because of format error */ if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1409,7 +1426,7 @@ static char* bta_hf_client_parse_cnum(tBTA_HF_CLIENT_CB* client_cb, /* Abort in case offset not set because of format error */ if (offset == 0) { - APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer); + LOG_ERROR("%s: Format Error %s", __func__, buffer); return NULL; } @@ -1529,7 +1546,7 @@ static char* bta_hf_client_skip_unknown(tBTA_HF_CLIENT_CB* client_cb, buffer = tmp + 2; - APPL_TRACE_DEBUG("%s: %.*s", __func__, buffer - start - 2, start); + LOG_VERBOSE("%s: %.*s", __func__, (int)(buffer - start - 2), start); return buffer; } @@ -1549,17 +1566,17 @@ static char* bta_hf_client_process_unknown(tBTA_HF_CLIENT_CB* client_cb, int evt_size = end - start + 1; - char tmp_buf[BTA_HF_CLIENT_UNKOWN_EVENT_LEN]; - if (evt_size < BTA_HF_CLIENT_UNKOWN_EVENT_LEN) { + char tmp_buf[BTA_HF_CLIENT_UNKNOWN_EVENT_LEN]; + if (evt_size < BTA_HF_CLIENT_UNKNOWN_EVENT_LEN) { strlcpy(tmp_buf, start, evt_size); bta_hf_client_unknown_response(client_cb, tmp_buf); AT_CHECK_RN(end); } else { - APPL_TRACE_ERROR("%s: exceed event buffer size. (%d, %d)", __func__, - evt_size, BTA_HF_CLIENT_UNKOWN_EVENT_LEN); + LOG_ERROR("%s: exceed event buffer size. (%d, %d)", __func__, evt_size, + BTA_HF_CLIENT_UNKNOWN_EVENT_LEN); } - APPL_TRACE_DEBUG("%s: %s", __func__, buffer); + LOG_VERBOSE("%s: %s", __func__, buffer); return end; } @@ -1620,14 +1637,14 @@ static void bta_hf_client_dump_at(tBTA_HF_CLIENT_CB* client_cb) { *p2 = '\0'; - APPL_TRACE_DEBUG("%s: %s", __func__, dump); + LOG_VERBOSE("%s: %s", __func__, dump); } #endif static void bta_hf_client_at_parse_start(tBTA_HF_CLIENT_CB* client_cb) { char* buf = client_cb->at_cb.buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); #ifdef BTA_HF_CLIENT_AT_DUMP bta_hf_client_dump_at(client_cb); @@ -1640,7 +1657,7 @@ static void bta_hf_client_at_parse_start(tBTA_HF_CLIENT_CB* client_cb) { for (i = 0; i < bta_hf_client_parser_cb_count; i++) { tmp = bta_hf_client_parser_cb[i](client_cb, buf); if (tmp == NULL) { - APPL_TRACE_ERROR("HFPCient: AT event/reply parsing failed, skipping"); + LOG_ERROR("HFPCient: AT event/reply parsing failed, skipping"); tmp = bta_hf_client_skip_unknown(client_cb, buf); break; } @@ -1655,8 +1672,7 @@ static void bta_hf_client_at_parse_start(tBTA_HF_CLIENT_CB* client_cb) { /* could not skip unknown (received garbage?)... disconnect */ if (tmp == NULL) { - APPL_TRACE_ERROR( - "HFPCient: could not skip unknown AT event, disconnecting"); + LOG_ERROR("HFPCient: could not skip unknown AT event, disconnecting"); bta_hf_client_at_reset(client_cb); tBTA_HF_CLIENT_DATA msg = {}; @@ -1680,7 +1696,7 @@ static bool bta_hf_client_check_at_complete(tBTA_HF_CLIENT_CB* client_cb) { } } - APPL_TRACE_DEBUG("%s: %d", __func__, ret); + LOG_VERBOSE("%s: %d", __func__, ret); return ret; } @@ -1698,8 +1714,7 @@ static void bta_hf_client_at_clear_buf(tBTA_HF_CLIENT_CB* client_cb) { ******************************************************************************/ void bta_hf_client_at_parse(tBTA_HF_CLIENT_CB* client_cb, char* buf, unsigned int len) { - APPL_TRACE_DEBUG("%s: offset: %u len: %u", __func__, client_cb->at_cb.offset, - len); + LOG_VERBOSE("%s: offset: %u len: %u", __func__, client_cb->at_cb.offset, len); if (len + client_cb->at_cb.offset > BTA_HF_CLIENT_AT_PARSER_MAX_LEN) { char tmp_buff[BTA_HF_CLIENT_AT_PARSER_MAX_LEN]; @@ -1707,7 +1722,7 @@ void bta_hf_client_at_parse(tBTA_HF_CLIENT_CB* client_cb, char* buf, unsigned int space_left = BTA_HF_CLIENT_AT_PARSER_MAX_LEN - client_cb->at_cb.offset; - APPL_TRACE_DEBUG("%s: overrun, trying to recover", __func__); + LOG_VERBOSE("%s: overrun, trying to recover", __func__); /* fill up parser buffer */ memcpy(client_cb->at_cb.buf + client_cb->at_cb.offset, buf, space_left); @@ -1718,7 +1733,7 @@ void bta_hf_client_at_parse(tBTA_HF_CLIENT_CB* client_cb, char* buf, /* find end of last complete command before proceeding */ while (!bta_hf_client_check_at_complete(client_cb)) { if (client_cb->at_cb.offset == 0) { - APPL_TRACE_ERROR("HFPClient: AT parser buffer overrun, disconnecting"); + LOG_ERROR("HFPClient: AT parser buffer overrun, disconnecting"); bta_hf_client_at_reset(client_cb); @@ -1766,11 +1781,11 @@ void bta_hf_client_send_at_brsf(tBTA_HF_CLIENT_CB* client_cb, char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); at_len = snprintf(buf, sizeof(buf), "AT+BRSF=%u\r", features); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -1780,9 +1795,13 @@ void bta_hf_client_send_at_brsf(tBTA_HF_CLIENT_CB* client_cb, void bta_hf_client_send_at_bac(tBTA_HF_CLIENT_CB* client_cb) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); - buf = "AT+BAC=1,2\r"; + if (bta_hf_client_cb_arr.is_support_lc3) { + buf = "AT+BAC=1,2,3\r"; + } else { + buf = "AT+BAC=1,2\r"; + } bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BAC, buf, strlen(buf)); } @@ -1791,11 +1810,11 @@ void bta_hf_client_send_at_bcs(tBTA_HF_CLIENT_CB* client_cb, uint32_t codec) { char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); at_len = snprintf(buf, sizeof(buf), "AT+BCS=%u\r", codec); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -1806,7 +1825,7 @@ void bta_hf_client_send_at_cind(tBTA_HF_CLIENT_CB* client_cb, bool status) { const char* buf; tBTA_HF_CLIENT_AT_CMD cmd; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (status) { buf = "AT+CIND?\r"; @@ -1822,7 +1841,7 @@ void bta_hf_client_send_at_cind(tBTA_HF_CLIENT_CB* client_cb, bool status) { void bta_hf_client_send_at_cmer(tBTA_HF_CLIENT_CB* client_cb, bool activate) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (activate) buf = "AT+CMER=3,0,0,1\r"; @@ -1837,7 +1856,7 @@ void bta_hf_client_send_at_chld(tBTA_HF_CLIENT_CB* client_cb, char cmd, char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (idx > 0) at_len = snprintf(buf, sizeof(buf), "AT+CHLD=%c%u\r", cmd, idx); @@ -1845,7 +1864,7 @@ void bta_hf_client_send_at_chld(tBTA_HF_CLIENT_CB* client_cb, char cmd, at_len = snprintf(buf, sizeof(buf), "AT+CHLD=%c\r", cmd); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -1856,12 +1875,16 @@ void bta_hf_client_send_at_bind(tBTA_HF_CLIENT_CB* client_cb, int step) { std::string buf; tBTA_HF_CLIENT_AT_CMD cmd = BTA_HF_CLIENT_AT_BIND_SET_IND; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); switch (step) { case 0: // List HF supported indicators - // TODO: Add flags to determine enabled HF features - buf = "AT+BIND=1,2\r"; + if (osi_property_get_bool(kPropertyEnhancedDrivingIndicatorEnabled, + false)) { + buf = "AT+BIND=1,2\r"; + } else { + buf = "AT+BIND=2\r"; + } cmd = BTA_HF_CLIENT_AT_BIND_SET_IND; break; case 1: // Read AG supported indicators @@ -1884,16 +1907,16 @@ void bta_hf_client_send_at_biev(tBTA_HF_CLIENT_CB* client_cb, int indicator_id, tBTA_HF_CLIENT_AT_CMD cmd = BTA_HF_CLIENT_AT_BIEV; if ((client_cb->peer_features & BTA_HF_CLIENT_FEAT_HF_IND) == 0) { - APPL_TRACE_ERROR("%s peer does not support HF Indicators", __func__); + LOG_ERROR("%s peer does not support HF Indicators", __func__); return; } if (client_cb->enabled_hf_indicators.count(indicator_id) <= 0) { - APPL_TRACE_ERROR("%s HF indicators %d is disabled", __func__, indicator_id); + LOG_ERROR("%s HF indicators %d is disabled", __func__, indicator_id); return; } - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); int len = sprintf(buf, "AT+BIEV=%d,%d\r", indicator_id, indicator_value); @@ -1903,7 +1926,7 @@ void bta_hf_client_send_at_biev(tBTA_HF_CLIENT_CB* client_cb, int indicator_id, void bta_hf_client_send_at_clip(tBTA_HF_CLIENT_CB* client_cb, bool activate) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (activate) buf = "AT+CLIP=1\r"; @@ -1916,7 +1939,7 @@ void bta_hf_client_send_at_clip(tBTA_HF_CLIENT_CB* client_cb, bool activate) { void bta_hf_client_send_at_ccwa(tBTA_HF_CLIENT_CB* client_cb, bool activate) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (activate) buf = "AT+CCWA=1\r"; @@ -1929,7 +1952,7 @@ void bta_hf_client_send_at_ccwa(tBTA_HF_CLIENT_CB* client_cb, bool activate) { void bta_hf_client_send_at_cmee(tBTA_HF_CLIENT_CB* client_cb, bool activate) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (activate) buf = "AT+CMEE=1\r"; @@ -1942,7 +1965,7 @@ void bta_hf_client_send_at_cmee(tBTA_HF_CLIENT_CB* client_cb, bool activate) { void bta_hf_client_send_at_cops(tBTA_HF_CLIENT_CB* client_cb, bool query) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (query) buf = "AT+COPS?\r"; @@ -1955,7 +1978,7 @@ void bta_hf_client_send_at_cops(tBTA_HF_CLIENT_CB* client_cb, bool query) { void bta_hf_client_send_at_clcc(tBTA_HF_CLIENT_CB* client_cb) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); buf = "AT+CLCC\r"; @@ -1965,7 +1988,7 @@ void bta_hf_client_send_at_clcc(tBTA_HF_CLIENT_CB* client_cb) { void bta_hf_client_send_at_bvra(tBTA_HF_CLIENT_CB* client_cb, bool enable) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (enable) buf = "AT+BVRA=1\r"; @@ -1979,11 +2002,11 @@ void bta_hf_client_send_at_vgs(tBTA_HF_CLIENT_CB* client_cb, uint32_t volume) { char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); at_len = snprintf(buf, sizeof(buf), "AT+VGS=%u\r", volume); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -1994,11 +2017,11 @@ void bta_hf_client_send_at_vgm(tBTA_HF_CLIENT_CB* client_cb, uint32_t volume) { char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); at_len = snprintf(buf, sizeof(buf), "AT+VGM=%u\r", volume); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -2010,7 +2033,7 @@ void bta_hf_client_send_at_atd(tBTA_HF_CLIENT_CB* client_cb, char* number, char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (number[0] != '\0') { at_len = snprintf(buf, sizeof(buf), "ATD%s;\r", number); @@ -2019,14 +2042,14 @@ void bta_hf_client_send_at_atd(tBTA_HF_CLIENT_CB* client_cb, char* number, } if (at_len < 0) { - APPL_TRACE_ERROR("%s: error preparing ATD command", __func__); + LOG_ERROR("%s: error preparing ATD command", __func__); return; } at_len = MIN((size_t)at_len, sizeof(buf)); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_ATD, buf, at_len); @@ -2035,7 +2058,7 @@ void bta_hf_client_send_at_atd(tBTA_HF_CLIENT_CB* client_cb, char* number, void bta_hf_client_send_at_bldn(tBTA_HF_CLIENT_CB* client_cb) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); buf = "AT+BLDN\r"; @@ -2045,7 +2068,7 @@ void bta_hf_client_send_at_bldn(tBTA_HF_CLIENT_CB* client_cb) { void bta_hf_client_send_at_ata(tBTA_HF_CLIENT_CB* client_cb) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); buf = "ATA\r"; @@ -2055,7 +2078,7 @@ void bta_hf_client_send_at_ata(tBTA_HF_CLIENT_CB* client_cb) { void bta_hf_client_send_at_chup(tBTA_HF_CLIENT_CB* client_cb) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); buf = "AT+CHUP\r"; @@ -2067,7 +2090,7 @@ void bta_hf_client_send_at_btrh(tBTA_HF_CLIENT_CB* client_cb, bool query, char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (query) { at_len = snprintf(buf, sizeof(buf), "AT+BTRH?\r"); @@ -2076,7 +2099,7 @@ void bta_hf_client_send_at_btrh(tBTA_HF_CLIENT_CB* client_cb, bool query, } if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -2087,12 +2110,12 @@ void bta_hf_client_send_at_vts(tBTA_HF_CLIENT_CB* client_cb, char code) { char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); at_len = snprintf(buf, sizeof(buf), "AT+VTS=%c\r", code); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -2102,7 +2125,7 @@ void bta_hf_client_send_at_vts(tBTA_HF_CLIENT_CB* client_cb, char code) { void bta_hf_client_send_at_bcc(tBTA_HF_CLIENT_CB* client_cb) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); buf = "AT+BCC\r"; @@ -2112,7 +2135,7 @@ void bta_hf_client_send_at_bcc(tBTA_HF_CLIENT_CB* client_cb) { void bta_hf_client_send_at_cnum(tBTA_HF_CLIENT_CB* client_cb) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); buf = "AT+CNUM\r"; @@ -2122,10 +2145,10 @@ void bta_hf_client_send_at_cnum(tBTA_HF_CLIENT_CB* client_cb) { void bta_hf_client_send_at_nrec(tBTA_HF_CLIENT_CB* client_cb) { const char* buf; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!(client_cb->peer_features & BTA_HF_CLIENT_PEER_FEAT_ECNR)) { - APPL_TRACE_ERROR("%s: Remote does not support NREC.", __func__); + LOG_ERROR("%s: Remote does not support NREC.", __func__); return; } @@ -2138,12 +2161,12 @@ void bta_hf_client_send_at_binp(tBTA_HF_CLIENT_CB* client_cb, uint32_t action) { char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); at_len = snprintf(buf, sizeof(buf), "AT+BINP=%u\r", action); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -2155,9 +2178,9 @@ void bta_hf_client_send_at_bia(tBTA_HF_CLIENT_CB* client_cb) { int at_len; int i; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (client_cb->peer_version < HFP_VERSION_1_6) { - APPL_TRACE_DEBUG("Remote does not Support AT+BIA"); + LOG_VERBOSE("Remote does not Support AT+BIA"); return; } @@ -2183,7 +2206,7 @@ void bta_hf_client_send_at_bia(tBTA_HF_CLIENT_CB* client_cb) { buf[at_len - 1] = '\r'; if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -2194,12 +2217,12 @@ void bta_hf_client_send_at_vendor_specific_cmd(tBTA_HF_CLIENT_CB* client_cb, const char* str) { char buf[BTA_HF_CLIENT_AT_MAX_LEN]; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); int at_len = snprintf(buf, sizeof(buf), "AT%s", str); if (at_len < 1) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -2214,11 +2237,11 @@ void bta_hf_client_send_at_android(tBTA_HF_CLIENT_CB* client_cb, char buf[BTA_HF_CLIENT_AT_MAX_LEN]; int at_len; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); at_len = snprintf(buf, sizeof(buf), "AT%s\r", str); if (at_len < 0) { - APPL_TRACE_ERROR("%s: AT command Framing error", __func__); + LOG_ERROR("%s: AT command Framing error", __func__); return; } @@ -2255,15 +2278,15 @@ void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (!client_cb) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } tBTA_HF_CLIENT_DATA_VAL* p_val = (tBTA_HF_CLIENT_DATA_VAL*)p_data; char buf[BTA_HF_CLIENT_AT_MAX_LEN]; - APPL_TRACE_DEBUG("%s: at cmd: %d", __func__, p_val->uint8_val); + LOG_VERBOSE("%s: at cmd: %d", __func__, p_val->uint8_val); switch (p_val->uint8_val) { case BTA_HF_CLIENT_AT_CMD_VTS: bta_hf_client_send_at_vts(client_cb, (char)p_val->uint32_val1); @@ -2328,11 +2351,11 @@ void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA* p_data) { bta_hf_client_send_at_android(client_cb, p_val->str); break; default: - APPL_TRACE_ERROR("Default case"); + LOG_ERROR("Default case"); snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN, "Cmd %d 1st arg %u 2nd arg %u string arg %s", p_val->uint8_val, p_val->uint32_val1, p_val->uint32_val2, p_val->str); - APPL_TRACE_ERROR("%s: AT buffer: %s ", __func__, buf); + LOG_ERROR("%s: AT buffer: %s ", __func__, buf); break; } } diff --git a/system/bta/hf_client/bta_hf_client_int.h b/system/bta/hf_client/bta_hf_client_int.h index a66b27e5221a49139934274f57016ef832c8ed32..4d75f7e0e99968557463a8f163bb380677f15b1a 100644 --- a/system/bta/hf_client/bta_hf_client_int.h +++ b/system/bta/hf_client/bta_hf_client_int.h @@ -25,7 +25,7 @@ #include "bta/sys/bta_sys.h" #include "osi/include/alarm.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" +#include "stack/sdp/sdp_discovery_db.h" #include "types/raw_address.h" /***************************************************************************** @@ -202,6 +202,7 @@ typedef struct { tBTA_HF_CLIENT_FEAT features; /* features registered by application */ uint16_t serv_handle; /* RFCOMM server handle */ bool deregister; /* true if service shutting down */ + bool is_support_lc3; /* true if enable lc3 codec support (HFP1.9) */ // Maximum number of control blocks supported by the BTA layer. tBTA_HF_CLIENT_CB cb[HF_CLIENT_MAX_DEVICES]; @@ -218,13 +219,13 @@ tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_handle(uint16_t handle); tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_bda(const RawAddress& bd_addr); tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_rfc_handle(uint16_t handle); tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_sco_handle(uint16_t handle); -bool bta_hf_client_hdl_event(BT_HDR_RIGID* p_msg); +bool bta_hf_client_hdl_event(const BT_HDR_RIGID* p_msg); void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data); void bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB* client_cb, bool error); bool bta_hf_client_allocate_handle(const RawAddress& bd_addr, uint16_t* p_handle); void bta_hf_client_app_callback(uint16_t event, tBTA_HF_CLIENT* data); -void bta_hf_client_collision_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, +void bta_hf_client_collision_cback(tBTA_SYS_CONN_STATUS status, tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr); void bta_hf_client_resume_open(tBTA_HF_CLIENT_CB* client_cb); tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback, diff --git a/system/bta/hf_client/bta_hf_client_main.cc b/system/bta/hf_client/bta_hf_client_main.cc index cae579822f6f394aa3c6c1ad876607e2dfc54b4e..ad6f241e4e36bcb2115916cc67e2e0c01f1e4d7a 100644 --- a/system/bta/hf_client/bta_hf_client_main.cc +++ b/system/bta/hf_client/bta_hf_client_main.cc @@ -17,18 +17,22 @@ * ******************************************************************************/ +#include + #include #include #include "bta/hf_client/bta_hf_client_int.h" #include "bta/include/utl.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" #include "stack/include/btm_api.h" +#include "stack/include/sdp_api.h" #include "types/raw_address.h" -#include +using namespace bluetooth::legacy::stack::sdp; static const char* bta_hf_client_evt_str(uint16_t event); static const char* bta_hf_client_state_str(uint8_t state); @@ -296,7 +300,7 @@ void bta_hf_client_cb_arr_init() { * ******************************************************************************/ void bta_hf_client_cb_init(tBTA_HF_CLIENT_CB* client_cb, uint16_t handle) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); // Free any memory we need to explicity release alarm_free(client_cb->collision_timer); @@ -326,7 +330,7 @@ void bta_hf_client_cb_init(tBTA_HF_CLIENT_CB* client_cb, uint16_t handle) { * ******************************************************************************/ void bta_hf_client_resume_open(tBTA_HF_CLIENT_CB* client_cb) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* resume opening process. */ if (client_cb->state == BTA_HF_CLIENT_INIT_ST) { @@ -349,7 +353,7 @@ void bta_hf_client_resume_open(tBTA_HF_CLIENT_CB* client_cb) { * ******************************************************************************/ static void bta_hf_client_collision_timer_cback(void* data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data; /* If the peer haven't opened connection, restart opening process */ @@ -367,25 +371,26 @@ static void bta_hf_client_collision_timer_cback(void* data) { * ******************************************************************************/ void bta_hf_client_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, - uint8_t id, UNUSED_ATTR uint8_t app_id, + tBTA_SYS_ID id, UNUSED_ATTR uint8_t app_id, const RawAddress& peer_addr) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_bda(peer_addr); if (client_cb != NULL && client_cb->state == BTA_HF_CLIENT_OPENING_ST) { if (id == BTA_ID_SYS) /* ACL collision */ { - APPL_TRACE_WARNING("HF Client found collision (ACL) ..."); + LOG_WARN("HF Client found collision (ACL) ..."); } else if (id == BTA_ID_HS) /* RFCOMM collision */ { - APPL_TRACE_WARNING("HF Client found collision (RFCOMM) ..."); + LOG_WARN("HF Client found collision (RFCOMM) ..."); } else { - APPL_TRACE_WARNING("HF Client found collision (\?\?\?) ..."); + LOG_WARN("HF Client found collision (\?\?\?) ..."); } client_cb->state = BTA_HF_CLIENT_INIT_ST; /* Cancel SDP if it had been started. */ if (client_cb->p_disc_db) { - (void)SDP_CancelServiceSearch(client_cb->p_disc_db); + get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch( + client_cb->p_disc_db); osi_free_and_reset((void**)&client_cb->p_disc_db); } @@ -415,7 +420,7 @@ tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback, const char* p_service_name) { /* If already registered then return error */ if (bta_sys_is_register(BTA_ID_HS)) { - APPL_TRACE_ERROR("BTA HF Client is already enabled, ignoring ..."); + LOG_ERROR("BTA HF Client is already enabled, ignoring ..."); return BTA_FAILURE; } @@ -427,6 +432,7 @@ tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback, bta_hf_client_cb_arr.p_cback = p_cback; bta_hf_client_cb_arr.features = features; + bta_hf_client_cb_arr.is_support_lc3 = features & BTA_HF_CLIENT_FEAT_SWB; /* create SDP records */ bta_hf_client_create_record(&bta_hf_client_cb_arr, p_service_name); @@ -466,8 +472,8 @@ tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback, tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_handle(uint16_t handle) { // Handles are limited from 1 through HF_CLIENT_MAX_DEVICES if (handle < 1 || handle > HF_CLIENT_MAX_DEVICES) { - APPL_TRACE_ERROR("%s: handle out of range (%d, %d) %d", __func__, 1, - HF_CLIENT_MAX_DEVICES, handle); + LOG_ERROR("%s: handle out of range (%d, %d) %d", __func__, 1, + HF_CLIENT_MAX_DEVICES, handle); return NULL; } @@ -475,7 +481,7 @@ tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_handle(uint16_t handle) { if (bta_hf_client_cb_arr.cb[handle - 1].is_allocated) return &(bta_hf_client_cb_arr.cb[handle - 1]); - APPL_TRACE_ERROR("%s: block not found for handle %d", __func__, handle); + LOG_ERROR("%s: block not found for handle %d", __func__, handle); return NULL; } @@ -500,11 +506,11 @@ tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_bda(const RawAddress& peer_addr) { if (client_cb->is_allocated && peer_addr == client_cb->peer_addr) { return client_cb; } else { - APPL_TRACE_WARNING("%s: bdaddr mismatch for handle %d alloc %d", __func__, - i, client_cb->is_allocated); + LOG_WARN("%s: bdaddr mismatch for handle %d alloc %d", __func__, i, + client_cb->is_allocated); } } - APPL_TRACE_ERROR("%s: block not found", __func__); + LOG_ERROR("%s: block not found", __func__); return NULL; } @@ -527,18 +533,18 @@ tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_rfc_handle(uint16_t handle) { bool is_allocated = client_cb->is_allocated; uint16_t conn_handle = client_cb->conn_handle; - APPL_TRACE_DEBUG("%s: cb rfc_handle %d alloc %d conn_handle %d", __func__, - handle, is_allocated, conn_handle); + LOG_VERBOSE("%s: cb rfc_handle %d alloc %d conn_handle %d", __func__, + handle, is_allocated, conn_handle); if (is_allocated && conn_handle == handle) { return client_cb; } - APPL_TRACE_WARNING("%s: no cb yet %d alloc %d conn_handle %d", __func__, - handle, is_allocated, conn_handle); + LOG_WARN("%s: no cb yet %d alloc %d conn_handle %d", __func__, handle, + is_allocated, conn_handle); } - APPL_TRACE_ERROR("%s: no cb found for rfc handle %d", __func__, handle); + LOG_ERROR("%s: no cb found for rfc handle %d", __func__, handle); return NULL; } @@ -562,7 +568,7 @@ tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_sco_handle(uint16_t handle) { return client_cb; } } - APPL_TRACE_ERROR("%s: block not found for handle %d", __func__, handle); + LOG_ERROR("%s: block not found for handle %d", __func__, handle); return NULL; } @@ -587,8 +593,8 @@ bool bta_hf_client_allocate_handle(const RawAddress& bd_addr, uint16_t* p_handle) { tBTA_HF_CLIENT_CB* existing_cb = bta_hf_client_find_cb_by_bda(bd_addr); if (existing_cb != NULL) { - BTIF_TRACE_ERROR("%s: cannot allocate handle since BDADDR already exists", - __func__); + LOG_ERROR("%s: cannot allocate handle since BDADDR already exists", + __func__); return false; } /* Check that we do not have a request to for same device in the control @@ -596,8 +602,7 @@ bool bta_hf_client_allocate_handle(const RawAddress& bd_addr, for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) { tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i]; if (client_cb->is_allocated) { - APPL_TRACE_WARNING("%s: control block already used index %d", __func__, - i); + LOG_WARN("%s: control block already used index %d", __func__, i); continue; } @@ -605,8 +610,8 @@ bool bta_hf_client_allocate_handle(const RawAddress& bd_addr, bta_hf_client_cb_init(client_cb, client_cb->handle); *p_handle = client_cb->handle; - APPL_TRACE_DEBUG("%s: marking CB handle %d to true", __func__, - client_cb->handle); + LOG_VERBOSE("%s: marking CB handle %d to true", __func__, + client_cb->handle); client_cb->is_allocated = true; client_cb->peer_addr = bd_addr; @@ -615,7 +620,7 @@ bool bta_hf_client_allocate_handle(const RawAddress& bd_addr, } return false; - APPL_TRACE_ERROR("%s: all control blocks in use!", __func__); + LOG_ERROR("%s: all control blocks in use!", __func__); } /******************************************************************************* @@ -646,7 +651,7 @@ void bta_hf_client_app_callback(uint16_t event, tBTA_HF_CLIENT* data) { ******************************************************************************/ void bta_hf_client_api_disable() { if (!bta_sys_is_register(BTA_ID_HS)) { - APPL_TRACE_WARNING("BTA HF Client is already disabled, ignoring ..."); + LOG_WARN("BTA HF Client is already disabled, ignoring ..."); return; } @@ -682,9 +687,9 @@ void bta_hf_client_api_disable() { * Returns bool * ******************************************************************************/ -bool bta_hf_client_hdl_event(BT_HDR_RIGID* p_msg) { - APPL_TRACE_DEBUG("%s: %s (0x%x)", __func__, - bta_hf_client_evt_str(p_msg->event), p_msg->event); +bool bta_hf_client_hdl_event(const BT_HDR_RIGID* p_msg) { + LOG_VERBOSE("%s: %s (0x%x)", __func__, bta_hf_client_evt_str(p_msg->event), + p_msg->event); bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA*)p_msg); return true; } @@ -703,8 +708,8 @@ void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -718,15 +723,14 @@ void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) { /* Ignore displaying of AT results when not connected (Ignored in state * machine) */ if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) { - APPL_TRACE_EVENT("HF Client evt : State %d (%s), Event 0x%04x (%s)", - client_cb->state, - bta_hf_client_state_str(client_cb->state), event, - bta_hf_client_evt_str(event)); + LOG_VERBOSE("HF Client evt : State %d (%s), Event 0x%04x (%s)", + client_cb->state, bta_hf_client_state_str(client_cb->state), + event, bta_hf_client_evt_str(event)); } event &= 0x00FF; if (event >= (BTA_HF_CLIENT_MAX_EVT & 0x00FF)) { - APPL_TRACE_ERROR("HF Client evt out of range, ignoring..."); + LOG_ERROR("HF Client evt out of range, ignoring..."); return; } @@ -755,7 +759,8 @@ void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) { evt.bd_addr = client_cb->peer_addr; if (client_cb->state == BTA_HF_CLIENT_INIT_ST) { bta_hf_client_app_callback(BTA_HF_CLIENT_CLOSE_EVT, &evt); - APPL_TRACE_DEBUG("%s: marking CB handle %d to false", __func__, client_cb->handle); + LOG_VERBOSE("%s: marking CB handle %d to false", __func__, + client_cb->handle); client_cb->is_allocated = false; } else if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) { evt.open.handle = client_cb->handle; @@ -794,12 +799,11 @@ static void send_post_slc_cmd(tBTA_HF_CLIENT_CB* client_cb) { * ******************************************************************************/ void bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB* client_cb, bool error) { - APPL_TRACE_DEBUG("bta_hf_client_slc_seq cmd: %u", - client_cb->at_cb.current_cmd); + LOG_VERBOSE("bta_hf_client_slc_seq cmd: %u", client_cb->at_cb.current_cmd); if (error) { /* SLC establishment error, sent close rfcomm event */ - APPL_TRACE_ERROR( + LOG_ERROR( "HFPClient: Failed to create SLC due to AT error, disconnecting (%u)", client_cb->at_cb.current_cmd); @@ -810,8 +814,8 @@ void bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB* client_cb, bool error) { } if (client_cb->svc_conn) { - APPL_TRACE_WARNING("%s: SLC already connected for CB handle %d", __func__, - client_cb->handle); + LOG_WARN("%s: SLC already connected for CB handle %d", __func__, + client_cb->handle); return; } @@ -886,7 +890,7 @@ void bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB* client_cb, bool error) { default: { /* If happen there is a bug in SLC creation procedure... */ - APPL_TRACE_ERROR( + LOG_ERROR( "HFPClient: Failed to create SLCdue to unexpected AT command, " "disconnecting (%u)", client_cb->at_cb.current_cmd); diff --git a/system/bta/hf_client/bta_hf_client_rfc.cc b/system/bta/hf_client/bta_hf_client_rfc.cc index 2999eb9ed1d434acc1f96a2df69b488cc604cc5d..1ead6ba3bf3086da488b7276019623e6f04ef187 100644 --- a/system/bta/hf_client/bta_hf_client_rfc.cc +++ b/system/bta/hf_client/bta_hf_client_rfc.cc @@ -24,16 +24,20 @@ * ******************************************************************************/ +#include + #include #include "bta/hf_client/bta_hf_client_int.h" +#include "bta/include/bta_sec_api.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" // UNUSED_ATTR +#include "stack/include/bt_uuid16.h" #include "stack/include/port_api.h" #include "stack/include/sdp_api.h" #include "types/raw_address.h" -#include +using namespace bluetooth::legacy::stack::sdp; /******************************************************************************* * @@ -52,7 +56,7 @@ static void bta_hf_client_port_cback(UNUSED_ATTR uint32_t code, tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_rfc_handle(port_handle); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, port_handle); + LOG_ERROR("%s: cb not found for handle %d", __func__, port_handle); return; } @@ -77,14 +81,13 @@ static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_rfc_handle(port_handle); - APPL_TRACE_DEBUG("%s: code = %d, port_handle = %d serv = %d", __func__, code, - port_handle, bta_hf_client_cb_arr.serv_handle); + LOG_VERBOSE("%s: code = %d, port_handle = %d serv = %d", __func__, code, + port_handle, bta_hf_client_cb_arr.serv_handle); /* ignore close event for port handles other than connected handle */ if (code != PORT_SUCCESS && client_cb != NULL && port_handle != client_cb->conn_handle) { - APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback ignoring handle:%d", - port_handle); + LOG_VERBOSE("bta_hf_client_mgmt_cback ignoring handle:%d", port_handle); return; } @@ -97,8 +100,7 @@ static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) { } else if (port_handle == bta_hf_client_cb_arr.serv_handle) { p_buf->hdr.event = BTA_HF_CLIENT_RFC_OPEN_EVT; - APPL_TRACE_DEBUG("%s: allocating a new CB for incoming connection", - __func__); + LOG_VERBOSE("%s: allocating a new CB for incoming connection", __func__); // Find the BDADDR of the peer device RawAddress peer_addr = RawAddress::kEmpty; uint16_t lcid = 0; @@ -114,7 +116,7 @@ static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) { // If allocation fails then we abort. if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: error allocating a new handle", __func__); + LOG_ERROR("%s: error allocating a new handle", __func__); p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT; RFCOMM_RemoveConnection(port_handle); } else { @@ -128,8 +130,8 @@ static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) { bta_hf_client_start_server(); } } else { - APPL_TRACE_ERROR("%s: PORT_SUCCESS, ignoring handle = %d", __func__, - port_handle); + LOG_ERROR("%s: PORT_SUCCESS, ignoring handle = %d", __func__, + port_handle); osi_free(p_buf); return; } @@ -179,8 +181,8 @@ void bta_hf_client_start_server() { int port_status; if (bta_hf_client_cb_arr.serv_handle > 0) { - APPL_TRACE_DEBUG("%s: already started, handle: %d", __func__, - bta_hf_client_cb_arr.serv_handle); + LOG_VERBOSE("%s: already started, handle: %d", __func__, + bta_hf_client_cb_arr.serv_handle); return; } @@ -189,14 +191,14 @@ void bta_hf_client_start_server() { BTA_HF_CLIENT_MTU, RawAddress::kAny, &(bta_hf_client_cb_arr.serv_handle), bta_hf_client_mgmt_cback, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); - APPL_TRACE_DEBUG("%s: started rfcomm server with handle %d", __func__, - bta_hf_client_cb_arr.serv_handle); + LOG_VERBOSE("%s: started rfcomm server with handle %d", __func__, + bta_hf_client_cb_arr.serv_handle); if (port_status == PORT_SUCCESS) { bta_hf_client_setup_port(bta_hf_client_cb_arr.serv_handle); } else { - APPL_TRACE_DEBUG("%s: RFCOMM_CreateConnection returned error:%d", __func__, - port_status); + LOG_VERBOSE("%s: RFCOMM_CreateConnection returned error:%d", __func__, + port_status); } } @@ -211,10 +213,10 @@ void bta_hf_client_start_server() { * ******************************************************************************/ void bta_hf_client_close_server() { - APPL_TRACE_DEBUG("%s: %d", __func__, bta_hf_client_cb_arr.serv_handle); + LOG_VERBOSE("%s: %d", __func__, bta_hf_client_cb_arr.serv_handle); if (bta_hf_client_cb_arr.serv_handle == 0) { - APPL_TRACE_DEBUG("%s: already stopped", __func__); + LOG_VERBOSE("%s: already stopped", __func__); return; } @@ -236,8 +238,8 @@ void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -247,8 +249,8 @@ void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data) { bta_hf_client_mgmt_cback, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT) == PORT_SUCCESS) { bta_hf_client_setup_port(client_cb->conn_handle); - APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d", - client_cb->conn_handle); + LOG_VERBOSE("bta_hf_client_rfc_do_open : conn_handle = %d", + client_cb->conn_handle); } /* RFCOMM create connection failed; send ourselves RFCOMM close event */ else { @@ -270,8 +272,8 @@ void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } @@ -288,7 +290,8 @@ void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA* p_data) { /* Cancel SDP if it had been started. */ if (client_cb->p_disc_db) { - (void)SDP_CancelServiceSearch(client_cb->p_disc_db); + (void)get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch( + client_cb->p_disc_db); osi_free_and_reset((void**)&client_cb->p_disc_db); } } diff --git a/system/bta/hf_client/bta_hf_client_sco.cc b/system/bta/hf_client/bta_hf_client_sco.cc index a1b6aad1c0d0baa047d92d92125ade4a47efcb1f..e7d7ec3b64c8548195abc3cb9dacd004cd087a23 100644 --- a/system/bta/hf_client/bta_hf_client_sco.cc +++ b/system/bta/hf_client/bta_hf_client_sco.cc @@ -51,13 +51,13 @@ static bool bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB* client_cb) { bool removed_started = false; tBTM_STATUS status; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) { status = BTM_RemoveSco(client_cb->sco_idx); - APPL_TRACE_DEBUG("%s: idx 0x%04x, status:0x%x", __func__, - client_cb->sco_idx, status); + LOG_VERBOSE("%s: idx 0x%04x, status:0x%x", __func__, client_cb->sco_idx, + status); if (status == BTM_CMD_STARTED) { removed_started = true; @@ -105,12 +105,15 @@ static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb, enh_esco_params_t resp; uint8_t hci_status = HCI_SUCCESS; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (client_cb->sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) { if (p_data->link_type == BTM_LINK_TYPE_SCO) { // SCO resp = esco_parameters_for_codec(SCO_CODEC_CVSD_D1, true); + } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_LC3) { + // eSCO LC3, HFP 1.9 + resp = esco_parameters_for_codec(ESCO_CODEC_LC3_T2, true); } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) { // eSCO mSBC resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2, true); @@ -143,13 +146,13 @@ static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb, ******************************************************************************/ static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA* p_data) { - APPL_TRACE_DEBUG("%s: %d", __func__, event); + LOG_VERBOSE("%s: %d", __func__, event); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(p_data->conn_evt.sco_inx); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__, - p_data->conn_evt.sco_inx); + LOG_ERROR("%s: wrong SCO handle to control block %d", __func__, + p_data->conn_evt.sco_inx); return; } @@ -173,12 +176,11 @@ static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event, * ******************************************************************************/ static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) { - APPL_TRACE_DEBUG("%s: %d", __func__, sco_idx); + LOG_VERBOSE("%s: %d", __func__, sco_idx); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__, - sco_idx); + LOG_ERROR("%s: wrong SCO handle to control block %d", __func__, sco_idx); return; } @@ -199,11 +201,11 @@ static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) { * ******************************************************************************/ static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) { - APPL_TRACE_DEBUG("%s: sco_idx %d", __func__, sco_idx); + LOG_VERBOSE("%s: sco_idx %d", __func__, sco_idx); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, sco_idx); + LOG_ERROR("%s: wrong handle to control block %d", __func__, sco_idx); return; } @@ -227,12 +229,11 @@ static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb, bool is_orig) { tBTM_STATUS status; - APPL_TRACE_DEBUG("%s: %d", __func__, is_orig); + LOG_VERBOSE("%s: %d", __func__, is_orig); /* Make sure this SCO handle is not already in use */ if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) { - APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __func__, - client_cb->sco_idx); + LOG_WARN("%s: Index 0x%04x already in use", __func__, client_cb->sco_idx); return; } @@ -263,12 +264,12 @@ static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb, if (status == BTM_CMD_STARTED && !is_orig) { if (!BTM_RegForEScoEvts(client_cb->sco_idx, bta_hf_client_esco_connreq_cback)) - APPL_TRACE_DEBUG("%s: SCO registration success", __func__); + LOG_VERBOSE("%s: SCO registration success", __func__); } - APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x", - __func__, is_orig, client_cb->sco_idx, status, - params.packet_types); + LOG_VERBOSE("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x", + __func__, is_orig, client_cb->sco_idx, status, + params.packet_types); } /******************************************************************************* @@ -283,8 +284,8 @@ static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb, ******************************************************************************/ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) { - APPL_TRACE_DEBUG("%s: before state: %d event: %d", __func__, - client_cb->sco_state, event); + LOG_VERBOSE("%s: before state: %d event: %d", __func__, client_cb->sco_state, + event); switch (client_cb->sco_state) { case BTA_HF_CLIENT_SCO_SHUTDOWN_ST: @@ -309,8 +310,7 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; default: - APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d", - event); + LOG_WARN("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d", event); break; } break; @@ -345,9 +345,8 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; default: - APPL_TRACE_WARNING( - "%s: BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", __func__, - event); + LOG_WARN("%s: BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", + __func__, event); break; } break; @@ -373,8 +372,7 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; default: - APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d", - event); + LOG_WARN("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d", event); break; } break; @@ -403,8 +401,7 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; default: - APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d", - event); + LOG_WARN("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d", event); break; } break; @@ -431,8 +428,7 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; default: - APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d", - event); + LOG_WARN("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d", event); break; } break; @@ -454,8 +450,7 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; default: - APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d", - event); + LOG_WARN("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d", event); break; } break; @@ -477,8 +472,7 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; default: - APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d", - event); + LOG_WARN("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d", event); break; } break; @@ -499,8 +493,7 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; default: - APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d", - event); + LOG_WARN("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d", event); break; } break; @@ -509,7 +502,7 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, break; } - APPL_TRACE_DEBUG("%s: after state: %d", __func__, client_cb->sco_state); + LOG_VERBOSE("%s: after state: %d", __func__, client_cb->sco_state); } /******************************************************************************* @@ -523,13 +516,13 @@ static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, * ******************************************************************************/ void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: wrong handle to control block %d", __func__, + p_data->hdr.layer_specific); return; } @@ -547,7 +540,7 @@ void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) { * ******************************************************************************/ void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E); } @@ -563,13 +556,13 @@ void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) { * ******************************************************************************/ void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: wrong handle to control block %d", __func__, + p_data->hdr.layer_specific); return; } @@ -577,7 +570,9 @@ void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) { bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr); - if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) { + if (client_cb->negotiated_codec == BTM_SCO_CODEC_LC3) { + bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_LC3_OPEN_EVT); + } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) { bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT); } else { bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT); @@ -595,13 +590,13 @@ void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) { * ******************************************************************************/ void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: wrong handle to control block %d", __func__, + p_data->hdr.layer_specific); return; } @@ -634,13 +629,13 @@ void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) { * ******************************************************************************/ void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: wrong handle to control block %d", __func__, + p_data->hdr.layer_specific); return; } @@ -661,12 +656,12 @@ void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: wrong handle to control block %d", __func__, + p_data->hdr.layer_specific); return; } - APPL_TRACE_DEBUG("%s: sco_idx 0x%x", __func__, client_cb->sco_idx); + LOG_VERBOSE("%s: sco_idx 0x%x", __func__, client_cb->sco_idx); if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) { bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E); diff --git a/system/bta/hf_client/bta_hf_client_sdp.cc b/system/bta/hf_client/bta_hf_client_sdp.cc index 8b9feca45941cc9a7450880b52f24eae84ddaf2d..2abd0f60c748d4ddf3b9561938f1fe7688585a2d 100644 --- a/system/bta/hf_client/bta_hf_client_sdp.cc +++ b/system/bta/hf_client/bta_hf_client_sdp.cc @@ -27,18 +27,21 @@ #include #include "bta/hf_client/bta_hf_client_int.h" -#include "bta/include/bta_ag_api.h" #include "bta/include/bta_hf_client_api.h" +#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 "osi/include/properties.h" -#include "stack/btm/btm_sec.h" -#include "stack/include/btm_api.h" -#include "stack/include/port_api.h" +#include "osi/include/osi.h" // UNUSED_ATTR +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/sdp_api.h" #include "stack/include/sdpdefs.h" #include "types/bluetooth/uuid.h" using bluetooth::Uuid; +using namespace bluetooth::legacy::stack::sdp; /* Number of protocol elements in protocol element list. */ #define BTA_HF_CLIENT_NUM_PROTO_ELEMS 2 @@ -56,12 +59,13 @@ using bluetooth::Uuid; * Returns void * ******************************************************************************/ -static void bta_hf_client_sdp_cback(tSDP_STATUS status, const void* data) { +static void bta_hf_client_sdp_cback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status, const void* data) { uint16_t event; tBTA_HF_CLIENT_DISC_RESULT* p_buf = (tBTA_HF_CLIENT_DISC_RESULT*)osi_malloc( sizeof(tBTA_HF_CLIENT_DISC_RESULT)); - APPL_TRACE_DEBUG("bta_hf_client_sdp_cback status:0x%x", status); + LOG_VERBOSE("bta_hf_client_sdp_cback status:0x%x", status); tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data; /* set event according to int/acp */ @@ -84,7 +88,8 @@ static void bta_hf_client_sdp_cback(tSDP_STATUS status, const void* data) { * Description This function is called by a server application to add * HFP Client information to an SDP record. Prior to * calling this function the application must call - * SDP_CreateRecord() to create an SDP record. + * get_legacy_stack_sdp_api()->handle.SDP_CreateRecord() to + * create an SDP record. * * Returns true if function execution succeeded, * false if function execution failed. @@ -102,7 +107,8 @@ bool bta_hf_client_add_record(const char* p_service_name, uint8_t scn, uint8_t buf[2]; uint16_t sdp_features = 0; - APPL_TRACE_DEBUG("bta_hf_client_add_record"); + LOG_VERBOSE("bta_hf_client_add_record"); + LOG_INFO("features: %d", features); memset(proto_elem_list, 0, BTA_HF_CLIENT_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM)); @@ -113,24 +119,25 @@ bool bta_hf_client_add_record(const char* p_service_name, uint8_t scn, proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; proto_elem_list[1].num_params = 1; proto_elem_list[1].params[0] = scn; - result &= SDP_AddProtocolList(sdp_handle, BTA_HF_CLIENT_NUM_PROTO_ELEMS, - proto_elem_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList( + sdp_handle, BTA_HF_CLIENT_NUM_PROTO_ELEMS, proto_elem_list); /* add service class id list */ svc_class_id_list[0] = UUID_SERVCLASS_HF_HANDSFREE; svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO; - result &= SDP_AddServiceClassIdList(sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS, - svc_class_id_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList( + sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS, svc_class_id_list); /* add profile descriptor list */ profile_uuid = UUID_SERVCLASS_HF_HANDSFREE; version = get_default_hfp_version(); - result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList( + sdp_handle, profile_uuid, version); /* add service name */ if (p_service_name != NULL && p_service_name[0] != 0) { - result &= SDP_AddAttribute( + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name); } @@ -150,15 +157,20 @@ bool bta_hf_client_add_record(const char* p_service_name, uint8_t scn, if (features & BTA_HF_CLIENT_FEAT_VOL) sdp_features |= BTA_HF_CLIENT_FEAT_VOL; /* Codec bit position is different in SDP (bit 5) and in BRSF (bit 7) */ - if (features & BTA_HF_CLIENT_FEAT_CODEC) sdp_features |= 0x0020; + if (features & BTA_HF_CLIENT_FEAT_CODEC) + sdp_features |= BTA_HF_CLIENT_WBS_SUPPORT; + + /* Support swb */ + if (features & BTA_HF_CLIENT_FEAT_SWB) + features |= BTA_HF_CLIENT_FEAT_SWB_SUPPORT; UINT16_TO_BE_FIELD(buf, sdp_features); - result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, - UINT_DESC_TYPE, 2, buf); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf); /* add browse group list */ - result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, - browse_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence( + sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); return result; } @@ -177,8 +189,9 @@ void bta_hf_client_create_record(tBTA_HF_CLIENT_CB_ARR* client_cb_arr, const char* p_service_name) { /* add sdp record if not already registered */ if (client_cb_arr->sdp_handle == 0) { - client_cb_arr->sdp_handle = SDP_CreateRecord(); - client_cb_arr->scn = BTM_AllocateSCN(); + client_cb_arr->sdp_handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); + client_cb_arr->scn = BTA_AllocateSCN(); bta_hf_client_add_record(p_service_name, client_cb_arr->scn, client_cb_arr->features, client_cb_arr->sdp_handle); @@ -198,12 +211,12 @@ void bta_hf_client_create_record(tBTA_HF_CLIENT_CB_ARR* client_cb_arr, * ******************************************************************************/ void bta_hf_client_del_record(tBTA_HF_CLIENT_CB_ARR* client_cb) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (client_cb->sdp_handle != 0) { - SDP_DeleteRecord(client_cb->sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(client_cb->sdp_handle); client_cb->sdp_handle = 0; - BTM_FreeSCN(client_cb->scn); + BTA_FreeSCN(client_cb->scn); bta_sys_remove_uuid(UUID_SERVCLASS_HF_HANDSFREE); } } @@ -229,15 +242,16 @@ bool bta_hf_client_sdp_find_attr(tBTA_HF_CLIENT_CB* client_cb) { /* loop through all records we found */ while (true) { /* get next record; if none found, we're done */ - p_rec = SDP_FindServiceInDb(client_cb->p_disc_db, - UUID_SERVCLASS_AG_HANDSFREE, p_rec); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + client_cb->p_disc_db, UUID_SERVCLASS_AG_HANDSFREE, p_rec); if (p_rec == NULL) { break; } /* get scn from proto desc list if initiator */ if (client_cb->role == BTA_HF_CLIENT_INT) { - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { client_cb->peer_scn = (uint8_t)pe.params[0]; } else { continue; @@ -245,11 +259,12 @@ bool bta_hf_client_sdp_find_attr(tBTA_HF_CLIENT_CB* client_cb) { } /* get profile version (if failure, version parameter is not updated) */ - SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE, - &client_cb->peer_version); + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_HF_HANDSFREE, &client_cb->peer_version); /* get features */ - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SUPPORTED_FEATURES); if (p_attr != NULL && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -266,7 +281,8 @@ bool bta_hf_client_sdp_find_attr(tBTA_HF_CLIENT_CB* client_cb) { } /* get network for ability to reject calls */ - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_NETWORK); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_NETWORK); if (p_attr != NULL && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -282,8 +298,8 @@ bool bta_hf_client_sdp_find_attr(tBTA_HF_CLIENT_CB* client_cb) { break; } - APPL_TRACE_DEBUG("%s: peer_version=0x%x peer_features=0x%x", __func__, - client_cb->peer_version, client_cb->peer_features); + LOG_VERBOSE("%s: peer_version=0x%x peer_features=0x%x", __func__, + client_cb->peer_version, client_cb->peer_features); return result; } @@ -327,14 +343,16 @@ void bta_hf_client_do_disc(tBTA_HF_CLIENT_CB* client_cb) { client_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE); /* set up service discovery database; attr happens to be attr_list len */ - db_inited = SDP_InitDiscoveryDb(client_cb->p_disc_db, BT_DEFAULT_BUFFER_SIZE, - num_uuid, uuid_list, num_attr, attr_list); + db_inited = get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + client_cb->p_disc_db, BT_DEFAULT_BUFFER_SIZE, num_uuid, uuid_list, + num_attr, attr_list); if (db_inited) { /*Service discovery not initiated */ - db_inited = SDP_ServiceSearchAttributeRequest2( - client_cb->peer_addr, client_cb->p_disc_db, bta_hf_client_sdp_cback, - (void*)client_cb); + db_inited = + get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest2( + client_cb->peer_addr, client_cb->p_disc_db, bta_hf_client_sdp_cback, + (void*)client_cb); } if (!db_inited) { @@ -362,8 +380,8 @@ void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA* p_data) { tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific); if (client_cb == NULL) { - APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, - p_data->hdr.layer_specific); + LOG_ERROR("%s: cb not found for handle %d", __func__, + p_data->hdr.layer_specific); return; } diff --git a/system/bta/hfp/bta_hfp_api.cc b/system/bta/hfp/bta_hfp_api.cc index 42c9170d7d48f1b5ad304df32b27eb221c1b5285..25eb726a3ae0b115c43ccf2b833897de768887bd 100644 --- a/system/bta/hfp/bta_hfp_api.cc +++ b/system/bta/hfp/bta_hfp_api.cc @@ -16,19 +16,8 @@ #include "bta_hfp_api.h" -#ifdef __ANDROID__ -#include -#endif - -#define DEFAULT_BTA_HFP_VERSION HFP_VERSION_1_7 +#include int get_default_hfp_version() { -#ifdef __ANDROID__ - static const int version = - android::sysprop::bluetooth::Hfp::version().value_or( - DEFAULT_BTA_HFP_VERSION); - return version; -#else - return DEFAULT_BTA_HFP_VERSION; -#endif + return GET_SYSPROP(Hfp, version, HFP_VERSION_1_7); } diff --git a/system/bta/hh/bta_hh_act.cc b/system/bta/hh/bta_hh_act.cc index 500da6a05e1263c6f18b70411f680aff7e7c89aa..61afe29ec1e029b9d7671c8f113f1060574c3374 100644 --- a/system/bta/hh/bta_hh_act.cc +++ b/system/bta/hh/bta_hh_act.cc @@ -24,27 +24,29 @@ #define LOG_TAG "bluetooth" -// BTA_HH_INCLUDED #include #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/hh/bta_hh_int.h" #include "bta/include/bta_hh_api.h" #include "bta/include/bta_hh_co.h" #include "bta/sys/bta_sys.h" #include "btif/include/btif_storage.h" -#include "main/shim/dumpsys.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/btm_log_history.h" #include "stack/include/hiddefs.h" #include "stack/include/hidh_api.h" +#include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + /***************************************************************************** * Constants ****************************************************************************/ @@ -202,8 +204,8 @@ static void bta_hh_sdp_cback(uint16_t result, uint16_t attr_mask, /* security is required for the connection, add attr_mask bit*/ attr_mask |= HID_SEC_REQUIRED; - APPL_TRACE_EVENT("%s: p_cb: %d result 0x%02x, attr_mask 0x%02x, handle %x", - __func__, p_cb, result, attr_mask, p_cb->hid_handle); + LOG_VERBOSE("%s: p_cb: %p result 0x%02x, attr_mask 0x%02x, handle %x", + __func__, p_cb, result, attr_mask, p_cb->hid_handle); /* check to see type of device is supported , and should not been added * before */ @@ -258,12 +260,13 @@ static void bta_hh_sdp_cback(uint16_t result, uint16_t attr_mask, * Returns void * ******************************************************************************/ -static void bta_hh_di_sdp_cback(tSDP_RESULT result) { +static void bta_hh_di_sdp_cback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_RESULT result) { tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur; tBTA_HH_STATUS status = BTA_HH_ERR_SDP; tSDP_DI_GET_RECORD di_rec; tHID_STATUS ret; - APPL_TRACE_EVENT("%s: p_cb: %d result 0x%02x", __func__, p_cb, result); + LOG_VERBOSE("%s: p_cb: %p result 0x%02x", __func__, p_cb, result); /* if DI record does not exist on remote device, vendor_id in * tBTA_HH_DEV_DSCP_INFO will be set to 0xffff and we will allow the @@ -274,9 +277,11 @@ static void bta_hh_di_sdp_cback(tSDP_RESULT result) { if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) && (p_cb != NULL)) { if (result == SDP_SUCCESS && - SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) { + get_legacy_stack_sdp_api()->device_id.SDP_GetNumDiRecords( + bta_hh_cb.p_disc_db) != 0) { /* always update information with primary DI record */ - if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS) { + if (get_legacy_stack_sdp_api()->device_id.SDP_GetDiRecord( + 1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS) { bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version, 0, 0); } @@ -291,8 +296,8 @@ static void bta_hh_di_sdp_cback(tSDP_RESULT result) { if (ret == HID_SUCCESS) { status = BTA_HH_OK; } else { - APPL_TRACE_DEBUG("%s: HID_HostGetSDPRecord failed: Status 0x%2x", - __func__, ret); + LOG_VERBOSE("%s: HID_HostGetSDPRecord failed: Status 0x%2x", __func__, + ret); } } @@ -324,9 +329,9 @@ static void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { (tSDP_DISCOVERY_DB*)osi_malloc(p_bta_hh_cfg->sdp_db_size); /* Do DI discovery first */ - if (SDP_DiDiscover(p_data->api_conn.bd_addr, bta_hh_cb.p_disc_db, - p_bta_hh_cfg->sdp_db_size, - bta_hh_di_sdp_cback) == SDP_SUCCESS) { + if (get_legacy_stack_sdp_api()->device_id.SDP_DiDiscover( + p_data->api_conn.bd_addr, bta_hh_cb.p_disc_db, + p_bta_hh_cfg->sdp_db_size, bta_hh_di_sdp_cback) == SDP_SUCCESS) { /* SDP search started successfully * Connection will be triggered at the end of successful SDP search */ @@ -367,7 +372,7 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { tBTA_HH_CONN conn_dat; tBTA_HH_STATUS status = p_data->status; - APPL_TRACE_DEBUG("%s: status 0x%2X", __func__, p_data->status); + LOG_VERBOSE("%s: status 0x%2X", __func__, p_data->status); /* initialize call back data */ memset((void*)&conn_dat, 0, sizeof(tBTA_HH_CONN)); @@ -382,18 +387,17 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { /* open HID connection */ ret = HID_HostOpenDev(p_cb->hid_handle); - APPL_TRACE_DEBUG("%s: HID_HostOpenDev returned=%d", __func__, ret); + LOG_VERBOSE("%s: HID_HostOpenDev returned=%d", __func__, ret); if (ret == HID_SUCCESS || ret == HID_ERR_ALREADY_CONN) { status = BTA_HH_OK; } else if (ret == HID_ERR_CONN_IN_PROCESS) { /* Connection already in progress, return from here, SDP * will be performed after connection is completed. */ - APPL_TRACE_DEBUG("%s: connection already in progress", __func__); + LOG_VERBOSE("%s: connection already in progress", __func__); return; } else { - APPL_TRACE_DEBUG("%s: HID_HostOpenDev failed: Status 0x%2X", __func__, - ret); + LOG_VERBOSE("%s: HID_HostOpenDev failed: Status 0x%2X", __func__, ret); /* open fail, remove device from management device list */ HID_HostRemoveDev(p_cb->hid_handle); status = BTA_HH_ERR; @@ -412,8 +416,8 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { */ if ((status == BTA_HH_ERR_SDP) && (p_cb->incoming_conn) && (p_cb->app_id == 0)) { - APPL_TRACE_ERROR("%s: SDP failed for incoming conn hndl: %d", __func__, - p_cb->incoming_hid_handle); + LOG_ERROR("%s: SDP failed for incoming conn hndl: %d", __func__, + p_cb->incoming_hid_handle); HID_HostRemoveDev(p_cb->incoming_hid_handle); } conn_dat.status = status; @@ -453,7 +457,7 @@ static void bta_hh_bredr_conn(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) tBTA_HH_DATA bta_hh_data; bta_hh_data.status = BTA_HH_OK; - APPL_TRACE_DEBUG("%s: skip SDP for known devices", __func__); + LOG_VERBOSE("%s: skip SDP for known devices", __func__); if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) { uint8_t hdl; @@ -669,7 +673,7 @@ void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { uint8_t dev_handle = p_data ? (uint8_t)p_data->hid_cback.hdr.layer_specific : p_cb->hid_handle; - APPL_TRACE_EVENT("%s: Device[%d] connected", __func__, dev_handle); + LOG_VERBOSE("%s: Device[%d] connected", __func__, dev_handle); /* SDP has been done */ if (p_cb->app_id != 0) { @@ -724,8 +728,8 @@ void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { * ******************************************************************************/ void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { - APPL_TRACE_DEBUG("HANDSHAKE received for: event = %s data= %d", - bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data); + LOG_VERBOSE("HANDSHAKE received for: event = %s data= %d", + bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data); tBTA_HH bta_hh; memset(&bta_hh, 0, sizeof(tBTA_HH)); @@ -770,7 +774,7 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { default: /* unknow transaction handshake response */ - APPL_TRACE_DEBUG("unknown transaction type"); + LOG_VERBOSE("unknown transaction type"); break; } @@ -793,8 +797,8 @@ void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { uint8_t* data = (uint8_t*)(pdata + 1) + pdata->offset; tBTA_HH_HSDATA hs_data; - APPL_TRACE_DEBUG("Ctrl DATA received w4: event[%s]", - bta_hh_get_w4_event(p_cb->w4_evt)); + LOG_VERBOSE("Ctrl DATA received w4: event[%s]", + bta_hh_get_w4_event(p_cb->w4_evt)); if (pdata->len == 0) { p_cb->w4_evt = 0; osi_free_and_reset((void**)&pdata); @@ -815,10 +819,10 @@ void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { hs_data.rsp_data.proto_mode = ((*data) == HID_PAR_PROTOCOL_REPORT) ? BTA_HH_PROTO_RPT_MODE : BTA_HH_PROTO_BOOT_MODE; - APPL_TRACE_DEBUG("GET_PROTOCOL Mode = [%s]", - (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE) - ? "Report" - : "Boot"); + LOG_VERBOSE("GET_PROTOCOL Mode = [%s]", + (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE) + ? "Report" + : "Boot"); break; /* should not expect control DATA for SET_ transaction */ case BTA_HH_SET_PROTO_EVT: @@ -828,8 +832,8 @@ void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { case BTA_HH_SET_IDLE_EVT: FALLTHROUGH_INTENDED; /* FALLTHROUGH */ default: - APPL_TRACE_DEBUG("invalid transaction type for DATA payload: 4_evt[%s]", - bta_hh_get_w4_event(p_cb->w4_evt)); + LOG_VERBOSE("invalid transaction type for DATA payload: 4_evt[%s]", + bta_hh_get_w4_event(p_cb->w4_evt)); break; } @@ -894,7 +898,6 @@ void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { * ******************************************************************************/ void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { - tBTA_HH_CONN conn_dat; tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0}; uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */ @@ -919,47 +922,23 @@ void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { hid_status_text(hid_status).c_str(), overlay_fail.c_str())); - /* Check reason for closing */ - if ((reason & (HID_L2CAP_CONN_FAIL | - HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection - (page timeout or l2cap error) */ - (reason == - HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */ - (reason == HID_ERR_L2CAP_FAILED)) /* Failure creating l2cap connection */ - { - /* Failure in opening connection */ - conn_dat.handle = p_cb->hid_handle; - conn_dat.status = - (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR; - conn_dat.bda = p_cb->addr; - HID_HostCloseDev(p_cb->hid_handle); - - /* Report OPEN fail event */ - (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat); - - bta_hh_trace_dev_db(); - return; - } - /* otherwise report CLOSE/VC_UNPLUG event */ - else { - /* inform role manager */ - bta_sys_conn_close(BTA_ID_HH, p_cb->app_id, p_cb->addr); - /* update total conn number */ - bta_hh_cb.cnt_num--; - - if (disc_dat.status) disc_dat.status = BTA_HH_ERR; + /* inform role manager */ + bta_sys_conn_close(BTA_ID_HH, p_cb->app_id, p_cb->addr); + /* update total conn number */ + bta_hh_cb.cnt_num--; - (*bta_hh_cb.p_cback)(event, (tBTA_HH*)&disc_dat); + if (disc_dat.status) disc_dat.status = BTA_HH_ERR; - /* if virtually unplug, remove device */ - if (p_cb->vp) { - HID_HostRemoveDev(p_cb->hid_handle); - bta_hh_clean_up_kdev(p_cb); - } + (*bta_hh_cb.p_cback)(event, (tBTA_HH*)&disc_dat); - bta_hh_trace_dev_db(); + /* if virtually unplug, remove device */ + if (p_cb->vp) { + HID_HostRemoveDev(p_cb->hid_handle); + bta_hh_clean_up_kdev(p_cb); } + bta_hh_trace_dev_db(); + /* clean up control block, but retain SDP info and device handle */ p_cb->vp = false; p_cb->w4_evt = 0; @@ -1073,7 +1052,7 @@ void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { break; default: - APPL_TRACE_DEBUG("invalid command"); + LOG_VERBOSE("invalid command"); break; } @@ -1177,8 +1156,7 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { /* currently not expected */ case HID_TRANS_DATAC: default: - APPL_TRACE_DEBUG("%s: cmd type = %d", __func__, - p_data->api_sndcmd.t_type); + LOG_VERBOSE("%s: cmd type = %d", __func__, p_data->api_sndcmd.t_type); break; } @@ -1215,8 +1193,7 @@ static void bta_hh_cback(uint8_t dev_handle, const RawAddress& addr, uint16_t sm_event = BTA_HH_INVALID_EVT; uint8_t xx = 0; - APPL_TRACE_DEBUG("%s::HID_event [%s]", __func__, - bta_hh_hid_event_name(event)); + LOG_VERBOSE("%s::HID_event [%s]", __func__, bta_hh_hid_event_name(event)); switch (event) { case HID_HDEV_EVT_OPEN: diff --git a/system/bta/hh/bta_hh_api.cc b/system/bta/hh/bta_hh_api.cc index d1dd859fe61bb3807d7b783f59586ee1347dbf3b..660aca11ae0ab57c68f38b40c041a2952af19a91 100644 --- a/system/bta/hh/bta_hh_api.cc +++ b/system/bta/hh/bta_hh_api.cc @@ -32,7 +32,7 @@ #include "osi/include/allocator.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" /***************************************************************************** @@ -259,7 +259,7 @@ void BTA_HhSendCtrl(uint8_t dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type) { void BTA_HhSendData(uint8_t dev_handle, UNUSED_ATTR const RawAddress& dev_bda, BT_HDR* p_data) { if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT) { - APPL_TRACE_ERROR( + LOG_ERROR( "ERROR! Wrong report type! Write Command only valid for output " "report!"); return; diff --git a/system/bta/hh/bta_hh_cfg.cc b/system/bta/hh/bta_hh_cfg.cc index 483ce1c9ed9d0cee55e1a1467394930cff701ec6..caecb4a6d55c6f2cfd19daaaa2f1b5330ab8e704 100644 --- a/system/bta/hh/bta_hh_cfg.cc +++ b/system/bta/hh/bta_hh_cfg.cc @@ -23,9 +23,8 @@ * ******************************************************************************/ -#include "bt_target.h" // Must be first to define build configuration - #include "bta/include/bta_hh_api.h" +#include "internal_include/bt_target.h" /* max number of device types supported by BTA */ #define BTA_HH_MAX_DEVT_SPT 9 diff --git a/system/bta/hh/bta_hh_int.h b/system/bta/hh/bta_hh_int.h index b39a9cb506eb6cf3bfb0c07df1e9791acfff027c..de9f3cf2157a77554db952f1e3e64255c6be5b76 100644 --- a/system/bta/hh/bta_hh_int.h +++ b/system/bta/hh/bta_hh_int.h @@ -32,7 +32,6 @@ #include "bta/include/bta_hh_api.h" #include "bta/sys/bta_sys.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "types/raw_address.h" /* state machine events, these events are handled by the state machine */ @@ -247,7 +246,7 @@ extern tBTA_HH_CFG* p_bta_hh_cfg; /***************************************************************************** * Function prototypes ****************************************************************************/ -bool bta_hh_hdl_event(BT_HDR_RIGID* p_msg); +bool bta_hh_hdl_event(const BT_HDR_RIGID* p_msg); void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event, const tBTA_HH_DATA* p_data); diff --git a/system/bta/hh/bta_hh_le.cc b/system/bta/hh/bta_hh_le.cc index 11ea9305a0f0ae2ab2249899f3a2ea5b37ebbc05..9acf55cce7a82558260bf36622f9b39ad8eff03e 100644 --- a/system/bta/hh/bta_hh_le.cc +++ b/system/bta/hh/bta_hh_le.cc @@ -28,16 +28,15 @@ #include "bta/include/bta_gatt_queue.h" #include "bta/include/bta_hh_co.h" #include "device/include/interop.h" -#include "main/shim/dumpsys.h" -#include "main/shim/shim.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // ARRAY_SIZE #include "stack/btm/btm_sec.h" // BTM_ #include "stack/include/bt_hdr.h" -#include "stack/include/bt_octets.h" -#include "stack/include/btu.h" // post_on_bt_main -#include "stack/include/l2c_api.h" // L2CA_ +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/btm_log_history.h" +#include "stack/include/l2c_api.h" // L2CA_ +#include "stack/include/main_thread.h" #include "stack/include/srvc_api.h" // tDIS_VALUE #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -76,7 +75,7 @@ static const uint16_t bta_hh_uuid_to_rtp_type[BTA_LE_HID_RTP_UUID_MAX][2] = { {GATT_UUID_BATTERY_LEVEL, BTA_HH_RPTT_INPUT}}; static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data); -static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB* p_cb, bool check_bond); +static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB* p_cb); static void bta_hh_process_cache_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_CACHE_ENTRY* p_rpt_cache, uint8_t num_rpt); @@ -95,7 +94,7 @@ static const char* bta_hh_le_rpt_name[4] = {"UNKNOWN", "INPUT", "OUTPUT", * ******************************************************************************/ static void bta_hh_le_hid_report_dbg(tBTA_HH_DEV_CB* p_cb) { - APPL_TRACE_DEBUG("%s: HID Report DB", __func__); + LOG_VERBOSE("%s: HID Report DB", __func__); if (p_cb->hid_srvc.state < BTA_HH_SERVICE_DISCOVERED) return; @@ -111,7 +110,7 @@ static void bta_hh_le_hid_report_dbg(tBTA_HH_DEV_CB* p_cb) { if (p_rpt->uuid == GATT_UUID_HID_BT_KB_OUTPUT) rpt_name = "Boot KB Output"; if (p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) rpt_name = "Boot MI Input"; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "\t\t [%s- 0x%04x] [Type: %s], [ReportID: %d] [srvc_inst_id: %d] " "[char_inst_id: %d] [Clt_cfg: %d]", rpt_name, p_rpt->uuid, @@ -360,8 +359,8 @@ static tBTA_HH_LE_RPT* bta_hh_le_find_rpt_by_idtype(tBTA_HH_LE_RPT* p_head, tBTA_HH_LE_RPT* p_rpt = p_head; uint8_t i; - APPL_TRACE_DEBUG("bta_hh_le_find_rpt_by_idtype: r_type: %d rpt_id: %d", - r_type, rpt_id); + LOG_VERBOSE("bta_hh_le_find_rpt_by_idtype: r_type: %d rpt_id: %d", r_type, + rpt_id); for (i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) { if (p_rpt->in_use && p_rpt->rpt_id == rpt_id && r_type == p_rpt->rpt_type) { @@ -504,7 +503,7 @@ static void bta_hh_le_save_report_ref(tBTA_HH_DEV_CB* p_dev_cb, if (p_rpt->rpt_type > BTA_HH_RPTT_FEATURE) /* invalid report type */ p_rpt->rpt_type = BTA_HH_RPTT_RESRV; - APPL_TRACE_DEBUG("%s: report ID: %d", __func__, p_rpt->rpt_id); + LOG_VERBOSE("%s: report ID: %d", __func__, p_rpt->rpt_id); tBTA_HH_RPT_CACHE_ENTRY rpt_entry; rpt_entry.rpt_id = p_rpt->rpt_id; rpt_entry.rpt_type = p_rpt->rpt_type; @@ -536,8 +535,8 @@ static void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB* p_dev_cb, bool register_ba) { tBTA_HH_LE_RPT* p_rpt = &p_dev_cb->hid_srvc.report[0]; - APPL_TRACE_DEBUG("%s: bta_hh_le_register_input_notif mode: %d", __func__, - proto_mode); + LOG_VERBOSE("%s: bta_hh_le_register_input_notif mode: %d", __func__, + proto_mode); for (int i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) { if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) { @@ -549,16 +548,16 @@ static void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB* p_dev_cb, else if (proto_mode == BTA_HH_PROTO_BOOT_MODE) { if (p_rpt->uuid == GATT_UUID_HID_REPORT && p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) { - APPL_TRACE_DEBUG("%s ---> Deregister Report ID: %d", __func__, - p_rpt->rpt_id); + LOG_VERBOSE("%s ---> Deregister Report ID: %d", __func__, + p_rpt->rpt_id); BTA_GATTC_DeregisterForNotifications( bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id); } /* register boot reports notification */ else if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT || p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) { - APPL_TRACE_DEBUG("%s <--- Register Boot Report ID: %d", __func__, - p_rpt->rpt_id); + LOG_VERBOSE("%s <--- Register Boot Report ID: %d", __func__, + p_rpt->rpt_id); BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id); } @@ -566,14 +565,14 @@ static void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB* p_dev_cb, if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT || p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) && p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) { - APPL_TRACE_DEBUG("%s ---> Deregister Boot Report ID: %d", __func__, - p_rpt->rpt_id); + LOG_VERBOSE("%s ---> Deregister Boot Report ID: %d", __func__, + p_rpt->rpt_id); BTA_GATTC_DeregisterForNotifications( bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id); } else if (p_rpt->uuid == GATT_UUID_HID_REPORT && p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) { - APPL_TRACE_DEBUG("%s <--- Register Report ID: %d", __func__, - p_rpt->rpt_id); + LOG_VERBOSE("%s <--- Register Report ID: %d", __func__, + p_rpt->rpt_id); BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id); } @@ -598,15 +597,15 @@ static void bta_hh_le_deregister_input_notif(tBTA_HH_DEV_CB* p_dev_cb) { if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) { if (p_rpt->uuid == GATT_UUID_HID_REPORT && p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) { - APPL_TRACE_DEBUG("%s ---> Deregister Report ID: %d", __func__, - p_rpt->rpt_id); + LOG_VERBOSE("%s ---> Deregister Report ID: %d", __func__, + p_rpt->rpt_id); BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id); } else if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT || p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) && p_rpt->client_cfg_value == GATT_CLT_CONFIG_NOTIFICATION) { - APPL_TRACE_DEBUG("%s ---> Deregister Boot Report ID: %d", __func__, - p_rpt->rpt_id); + LOG_VERBOSE("%s ---> Deregister Boot Report ID: %d", __func__, + p_rpt->rpt_id); BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id); } @@ -628,7 +627,7 @@ static void bta_hh_le_open_cmpl(tBTA_HH_DEV_CB* p_cb) { bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL); if (kBTA_HH_LE_RECONN && p_cb->status == BTA_HH_OK) { - bta_hh_le_add_dev_bg_conn(p_cb, true); + bta_hh_le_add_dev_bg_conn(p_cb); } } } @@ -685,7 +684,7 @@ static void write_rpt_ctl_cfg_cb(uint16_t conn_id, tGATT_STATUS status, break; default: - APPL_TRACE_ERROR("Unknown char ID clt cfg: 0x%04x", char_uuid); + LOG_ERROR("Unknown char ID clt cfg: 0x%04x", char_uuid); } } /******************************************************************************* @@ -763,8 +762,8 @@ static bool bta_hh_le_set_protocol_mode(tBTA_HH_DEV_CB* p_cb, tBTA_HH_PROTO_MODE mode) { tBTA_HH_CBDATA cback_data; - APPL_TRACE_DEBUG("%s attempt mode: %s", __func__, - (mode == BTA_HH_PROTO_RPT_MODE) ? "Report" : "Boot"); + LOG_VERBOSE("%s attempt mode: %s", __func__, + (mode == BTA_HH_PROTO_RPT_MODE) ? "Report" : "Boot"); cback_data.handle = p_cb->hid_handle; /* boot mode is not supported in the remote device */ @@ -772,7 +771,7 @@ static bool bta_hh_le_set_protocol_mode(tBTA_HH_DEV_CB* p_cb, p_cb->mode = BTA_HH_PROTO_RPT_MODE; if (mode == BTA_HH_PROTO_BOOT_MODE) { - APPL_TRACE_ERROR("Set Boot Mode failed!! No PROTO_MODE Char!"); + LOG_ERROR("Set Boot Mode failed!! No PROTO_MODE Char!"); cback_data.status = BTA_HH_ERR; } else { /* if set to report mode, need to de-register all input report @@ -830,10 +829,9 @@ static void get_protocol_mode_cb(uint16_t conn_id, tGATT_STATUS status, p_dev_cb->mode = hs_data.rsp_data.proto_mode; } - APPL_TRACE_DEBUG("LE GET_PROTOCOL Mode = [%s]", - (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE) - ? "Report" - : "Boot"); + LOG_VERBOSE("LE GET_PROTOCOL Mode = [%s]", + (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE) ? "Report" + : "Boot"); p_dev_cb->w4_evt = 0; (*bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH*)&hs_data); @@ -897,7 +895,7 @@ static void bta_hh_le_dis_cback(const RawAddress& addr, p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS; /* plug in the PnP info for this device */ if (p_dis_value->attr_mask & DIS_ATTR_PNP_ID_BIT) { - APPL_TRACE_DEBUG( + LOG_VERBOSE( "Plug in PnP info: product_id = %02x, vendor_id = %04x, version = %04x", p_dis_value->pnp_id.product_id, p_dis_value->pnp_id.vendor_id, p_dis_value->pnp_id.product_version); @@ -925,7 +923,7 @@ static void bta_hh_le_pri_service_discovery(tBTA_HH_DEV_CB* p_cb) { /* read DIS info */ if (!DIS_ReadDISInfo(p_cb->addr, bta_hh_le_dis_cback, DIS_ATTR_PNP_ID_BIT)) { - APPL_TRACE_ERROR("read DIS failed"); + LOG_ERROR("read DIS failed"); p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS; } @@ -975,23 +973,25 @@ static void bta_hh_le_encrypt_cback(const RawAddress* bd_addr, ******************************************************************************/ void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb, UNUSED_ATTR const tBTA_HH_DATA* p_buf) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (p_cb->status == BTA_HH_OK) { if (p_cb->hid_srvc.state < BTA_HH_SERVICE_DISCOVERED) { - APPL_TRACE_DEBUG("bta_hh_security_cmpl no reports loaded, try to load"); + LOG_DEBUG("No reports loaded, try to load"); /* start loading the cache if not in stack */ tBTA_HH_RPT_CACHE_ENTRY* p_rpt_cache; uint8_t num_rpt = 0; if ((p_rpt_cache = bta_hh_le_co_cache_load(p_cb->addr, &num_rpt, p_cb->app_id)) != NULL) { + LOG_DEBUG("Cache found, no need to perform service discovery"); bta_hh_process_cache_rpt(p_cb, p_rpt_cache, num_rpt); } } + /* discovery has been done for HID service */ if (p_cb->app_id != 0 && p_cb->hid_srvc.state >= BTA_HH_SERVICE_DISCOVERED) { - APPL_TRACE_DEBUG("%s: discovery has been done for HID service", __func__); + LOG_VERBOSE("%s: discovery has been done for HID service", __func__); /* configure protocol mode */ if (!bta_hh_le_set_protocol_mode(p_cb, p_cb->mode)) { bta_hh_le_open_cmpl(p_cb); @@ -999,7 +999,7 @@ void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb, } /* start primary service discovery for HID service */ else { - APPL_TRACE_DEBUG("%s: Starting service discovery", __func__); + LOG_VERBOSE("%s: Starting service discovery", __func__); bta_hh_le_pri_service_discovery(p_cb); } } @@ -1014,7 +1014,8 @@ void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb, btm_status_text(p_cb->btm_status).c_str()); if (!(p_cb->status == BTA_HH_ERR_SEC && (p_cb->btm_status == BTM_ERR_PROCESSING || - p_cb->btm_status == BTM_FAILED_ON_SECURITY))) + p_cb->btm_status == BTM_FAILED_ON_SECURITY || + p_cb->btm_status == BTM_WRONG_MODE))) bta_hh_le_api_disc_act(p_cb); } } @@ -1113,10 +1114,9 @@ void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_buf) { p2 = p_data->remote_bda.address; - APPL_TRACE_DEBUG( - "bta_hh_gatt_open BTA_GATTC_OPEN_EVT bda= [%08x%04x] status =%d", - ((p2[0]) << 24) + ((p2[1]) << 16) + ((p2[2]) << 8) + (p2[3]), - ((p2[4]) << 8) + p2[5], p_data->status); + LOG_VERBOSE("bta_hh_gatt_open BTA_GATTC_OPEN_EVT bda= [%08x%04x] status =%d", + ((p2[0]) << 24) + ((p2[1]) << 16) + ((p2[2]) << 8) + (p2[3]), + ((p2[4]) << 8) + p2[5], p_data->status); if (p_data->status == GATT_SUCCESS) { p_cb->hid_handle = bta_hh_le_get_le_dev_hdl(p_cb->index); @@ -1133,8 +1133,8 @@ void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_buf) { BtaGattQueue::Clean(p_cb->conn_id); - APPL_TRACE_DEBUG("hid_handle = %2x conn_id = %04x cb_index = %d", - p_cb->hid_handle, p_cb->conn_id, p_cb->index); + LOG_VERBOSE("hid_handle = %2x conn_id = %04x cb_index = %d", + p_cb->hid_handle, p_cb->conn_id, p_cb->index); bta_hh_sm_execute(p_cb, BTA_HH_START_ENC_EVT, NULL); @@ -1176,14 +1176,14 @@ static void bta_hh_le_close(const tBTA_GATTC_CLOSE& gattc_data) { const tBTA_HH_DATA data = { .le_close = { - .conn_id = gattc_data.conn_id, - .reason = gattc_data.reason, .hdr = { .event = BTA_HH_GATT_CLOSE_EVT, .layer_specific = static_cast(p_cb->hid_handle), }, + .conn_id = gattc_data.conn_id, + .reason = gattc_data.reason, }, }; bta_hh_sm_execute(p_cb, BTA_HH_GATT_CLOSE_EVT, &data); @@ -1201,7 +1201,7 @@ static void bta_hh_le_close(const tBTA_GATTC_CLOSE& gattc_data) { ******************************************************************************/ static void bta_hh_le_gatt_disc_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_STATUS status) { - APPL_TRACE_DEBUG("bta_hh_le_gatt_disc_cmpl "); + LOG_VERBOSE("bta_hh_le_gatt_disc_cmpl "); /* if open sucessful or protocol mode not desired, keep the connection open * but inform app */ @@ -1223,12 +1223,12 @@ static void read_hid_info_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data) { if (status != GATT_SUCCESS) { - APPL_TRACE_ERROR("%s: error: %d", __func__, status); + LOG_ERROR("%s: error: %d", __func__, status); return; } if (len != 4) { - APPL_TRACE_ERROR("%s: wrong length: %d", __func__, len); + LOG_ERROR("%s: wrong length: %d", __func__, len); return; } @@ -1244,7 +1244,7 @@ static void read_hid_report_map_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data) { if (status != GATT_SUCCESS) { - APPL_TRACE_ERROR("%s: error reading characteristic: %d", __func__, status); + LOG_ERROR("%s: error reading characteristic: %d", __func__, status); return; } @@ -1267,14 +1267,14 @@ static void read_ext_rpt_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data) { if (status != GATT_SUCCESS) { - APPL_TRACE_ERROR("%s: error: %d", __func__, status); + LOG_ERROR("%s: error: %d", __func__, status); return; } /* if the length of the descriptor value is right, parse it assume it's a 16 * bits UUID */ if (len != Uuid::kNumBytes16) { - APPL_TRACE_ERROR("%s: we support only 16bit UUID: %d", __func__, len); + LOG_ERROR("%s: we support only 16bit UUID: %d", __func__, len); return; } @@ -1283,15 +1283,15 @@ static void read_ext_rpt_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status, STREAM_TO_UINT16(p_dev_cb->hid_srvc.ext_rpt_ref, pp); - APPL_TRACE_DEBUG("%s: External Report Reference UUID 0x%04x", __func__, - p_dev_cb->hid_srvc.ext_rpt_ref); + LOG_VERBOSE("%s: External Report Reference UUID 0x%04x", __func__, + p_dev_cb->hid_srvc.ext_rpt_ref); } static void read_report_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data) { if (status != GATT_SUCCESS) { - APPL_TRACE_ERROR("%s: error: %d", __func__, status); + LOG_ERROR("%s: error: %d", __func__, status); return; } @@ -1299,7 +1299,7 @@ static void read_report_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status, const gatt::Descriptor* p_desc = BTA_GATTC_GetDescriptor(conn_id, handle); if (!p_desc) { - APPL_TRACE_ERROR("%s: error: descriptor is null!", __func__); + LOG_ERROR("%s: error: descriptor is null!", __func__); return; } @@ -1319,12 +1319,12 @@ static void read_pref_conn_params_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len, uint8_t* value, void* data) { if (status != GATT_SUCCESS) { - APPL_TRACE_ERROR("%s: error: %d", __func__, status); + LOG_ERROR("%s: error: %d", __func__, status); return; } if (len != 8) { - APPL_TRACE_ERROR("%s: we support only 16bit UUID: %d", __func__, len); + LOG_ERROR("%s: we support only 16bit UUID: %d", __func__, len); return; } @@ -1352,7 +1352,7 @@ static void read_pref_conn_params_cb(uint16_t conn_id, tGATT_STATUS status, latency > BTM_BLE_CONN_LATENCY_MAX || timeout < BTM_BLE_CONN_SUP_TOUT_MIN || timeout > BTM_BLE_CONN_SUP_TOUT_MAX || max_interval < min_interval) { - APPL_TRACE_ERROR( + LOG_ERROR( "%s: Invalid connection parameters. min=%d, max=%d, latency=%d, " "timeout=%d", __func__, min_interval, max_interval, latency, timeout); @@ -1417,7 +1417,7 @@ static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB* p_dev_cb, p_dev_cb, p_dev_cb->hid_srvc.srvc_inst_id, GATT_UUID_HID_REPORT, charac.value_handle); if (p_rpt == NULL) { - APPL_TRACE_ERROR("%s: Add report entry failed !!!", __func__); + LOG_ERROR("%s: Add report entry failed !!!", __func__); break; } @@ -1434,13 +1434,13 @@ static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB* p_dev_cb, case GATT_UUID_HID_BT_KB_INPUT: if (bta_hh_le_find_alloc_report_entry(p_dev_cb, service->handle, uuid16, charac.value_handle) == NULL) - APPL_TRACE_ERROR("%s: Add report entry failed !!!", __func__); + LOG_ERROR("%s: Add report entry failed !!!", __func__); break; default: - APPL_TRACE_DEBUG("%s: not processing %s 0x%04d", __func__, - bta_hh_uuid_to_str(uuid16), uuid16); + LOG_VERBOSE("%s: not processing %s 0x%04d", __func__, + bta_hh_uuid_to_str(uuid16), uuid16); } } @@ -1494,8 +1494,8 @@ static void bta_hh_le_srvc_search_cmpl(tBTA_GATTC_SEARCH_CMPL* p_data) { bta_hh_le_search_hid_chars(p_dev_cb, &service); - APPL_TRACE_DEBUG("%s: have HID service inst_id= %d", __func__, - p_dev_cb->hid_srvc.srvc_inst_id); + LOG_VERBOSE("%s: have HID service inst_id= %d", __func__, + p_dev_cb->hid_srvc.srvc_inst_id); } else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_SCAN_PARAM)) { scp_service = &service; } else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) { @@ -1554,16 +1554,15 @@ static void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY* p_data) { tBTA_HH_LE_RPT* p_rpt; if (p_dev_cb == NULL) { - APPL_TRACE_ERROR( - "%s: notification received from Unknown device, conn_id: 0x%04x", - __func__, p_data->conn_id); + LOG_ERROR("%s: notification received from Unknown device, conn_id: 0x%04x", + __func__, p_data->conn_id); return; } const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id, p_data->handle); if (p_char == NULL) { - APPL_TRACE_ERROR( + LOG_ERROR( "%s: notification received for Unknown Characteristic, conn_id: " "0x%04x, handle: 0x%04x", __func__, p_dev_cb->conn_id, p_data->handle); @@ -1578,7 +1577,7 @@ static void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY* p_data) { p_rpt = bta_hh_le_find_report_entry( p_dev_cb, p_svc->handle, p_char->uuid.As16Bit(), p_char->value_handle); if (p_rpt == NULL) { - APPL_TRACE_ERROR( + LOG_ERROR( "%s: notification received for Unknown Report, uuid: %s, handle: " "0x%04x", __func__, p_char->uuid.ToString().c_str(), p_char->value_handle); @@ -1590,7 +1589,7 @@ static void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY* p_data) { else if (p_char->uuid == Uuid::From16Bit(GATT_UUID_HID_BT_KB_INPUT)) app_id = BTA_HH_APP_ID_KB; - APPL_TRACE_DEBUG("Notification received on report ID: %d", p_rpt->rpt_id); + LOG_VERBOSE("Notification received on report ID: %d", p_rpt->rpt_id); /* need to append report ID to the head of data */ if (p_rpt->rpt_id != 0) { @@ -1637,8 +1636,7 @@ void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { LOG_DEBUG("gd_acl: Re-adding HID device to acceptlist"); // gd removes from bg list after failed connection // Correct the cached state to allow re-add to acceptlist. - p_cb->in_bg_conn = false; - bta_hh_le_add_dev_bg_conn(p_cb, false); + bta_hh_le_add_dev_bg_conn(p_cb); } p_cb->disc_active = BTA_HH_LE_DISC_NONE; @@ -1646,12 +1644,12 @@ void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { tBTA_HH data = { .conn = { - .handle = p_cb->hid_handle, .bda = p_cb->addr, - .le_hid = true, - .scps_supported = p_cb->scps_supported, .status = (le_close->reason != GATT_CONN_OK) ? BTA_HH_ERR : p_cb->status, + .handle = p_cb->hid_handle, + .le_hid = true, + .scps_supported = p_cb->scps_supported, }, }; @@ -1703,8 +1701,7 @@ void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { gatt_disconnection_reason_text(le_close->reason).c_str()); // gd removes from bg list after successful connection // Correct the cached state to allow re-add to acceptlist. - p_cb->in_bg_conn = false; - bta_hh_le_add_dev_bg_conn(p_cb, false); + bta_hh_le_add_dev_bg_conn(p_cb); break; case BTA_GATT_CONN_NONE: @@ -1832,7 +1829,7 @@ static void bta_hh_le_get_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id); if (p_rpt == NULL) { - APPL_TRACE_ERROR("%s: no matching report", __func__); + LOG_ERROR("%s: no matching report", __func__); return; } @@ -1850,7 +1847,7 @@ static void write_report_cb(uint16_t conn_id, tGATT_STATUS status, if (cb_evt == 0) return; - APPL_TRACE_DEBUG("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt); + LOG_VERBOSE("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt); const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(conn_id, handle); @@ -1885,7 +1882,7 @@ static void bta_hh_le_write_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, uint8_t rpt_id; if (p_buf == NULL || p_buf->len == 0) { - APPL_TRACE_ERROR("%s: Illegal data", __func__); + LOG_ERROR("%s: Illegal data", __func__); return; } @@ -1897,7 +1894,7 @@ static void bta_hh_le_write_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id); if (p_rpt == NULL) { - APPL_TRACE_ERROR("%s: no matching report", __func__); + LOG_ERROR("%s: no matching report", __func__); osi_free(p_buf); return; } @@ -1981,8 +1978,8 @@ void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { break; default: - APPL_TRACE_ERROR("%s unsupported transaction for BLE HID device: %d", - __func__, p_data->api_sndcmd.t_type); + LOG_ERROR("%s unsupported transaction for BLE HID device: %d", __func__, + p_data->api_sndcmd.t_type); break; } } @@ -1998,8 +1995,12 @@ void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) { ******************************************************************************/ void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB* p_cb) { if (p_cb->hid_srvc.state >= BTA_HH_SERVICE_DISCOVERED) { - p_cb->dscp_info.descriptor.dl_len = p_cb->hid_srvc.descriptor.dl_len; - p_cb->dscp_info.descriptor.dsc_list = p_cb->hid_srvc.descriptor.dsc_list; + if (p_cb->hid_srvc.descriptor.dl_len != 0) { + p_cb->dscp_info.descriptor.dl_len = p_cb->hid_srvc.descriptor.dl_len; + p_cb->dscp_info.descriptor.dsc_list = p_cb->hid_srvc.descriptor.dsc_list; + } else { + LOG_WARN("hid_srvc.descriptor.dl_len is 0"); + } (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH*)&p_cb->dscp_info); } @@ -2015,26 +2016,11 @@ void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB* p_cb) { * Returns void * ******************************************************************************/ -static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB* p_cb, bool check_bond) { - bool to_add = true; - - if (check_bond) { - /* start reconnection if remote is a bonded device */ - if (!BTM_IsLinkKeyKnown(p_cb->addr, BT_TRANSPORT_LE)) to_add = false; - } - - if (!p_cb->in_bg_conn && to_add) { - /* add device into BG connection to accept remote initiated connection */ - BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, - BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); - p_cb->in_bg_conn = true; - } else { - // Let the lower layers manage acceptlist and do not cache - // at the higher layer - p_cb->in_bg_conn = true; - BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, - BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); - } +static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB* p_cb) { + /* Add device into BG connection to accept remote initiated connection */ + BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, + BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); + p_cb->in_bg_conn = true; } /******************************************************************************* @@ -2067,7 +2053,7 @@ uint8_t bta_hh_le_add_device(tBTA_HH_DEV_CB* p_cb, p_dev_info->dscp_info.ssr_max_latency, p_dev_info->dscp_info.ssr_min_tout, p_dev_info->app_id); - bta_hh_le_add_dev_bg_conn(p_cb, false); + bta_hh_le_add_dev_bg_conn(p_cb); return p_cb->hid_handle; } @@ -2116,13 +2102,13 @@ static void bta_hh_le_service_changed(RawAddress remote_bda) { const tBTA_HH_DATA data = { .le_close = { - .conn_id = p_cb->conn_id, - .reason = GATT_CONN_OK, .hdr = { .event = BTA_HH_GATT_CLOSE_EVT, .layer_specific = static_cast(p_cb->hid_handle), }, + .conn_id = p_cb->conn_id, + .reason = GATT_CONN_OK, }, }; bta_hh_sm_execute(p_cb, BTA_HH_GATT_CLOSE_EVT, &data); @@ -2165,8 +2151,8 @@ static void bta_hh_le_service_discovery_done(RawAddress remote_bda) { ******************************************************************************/ static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) { tBTA_HH_DEV_CB* p_dev_cb; - APPL_TRACE_DEBUG("bta_hh_gattc_callback event:%s", - gatt_client_event_text(event).c_str()); + LOG_VERBOSE("bta_hh_gattc_callback event:%s", + gatt_client_event_text(event).c_str()); if (p_data == NULL) return; switch (event) { @@ -2233,7 +2219,7 @@ static void bta_hh_process_cache_rpt(tBTA_HH_DEV_CB* p_cb, if (num_rpt != 0) /* no cache is found */ { - p_cb->hid_srvc.state = BTA_HH_SERVICE_UNKNOWN; + p_cb->hid_srvc.state = BTA_HH_SERVICE_DISCOVERED; /* set the descriptor info */ p_cb->hid_srvc.descriptor.dl_len = p_cb->dscp_info.descriptor.dl_len; @@ -2243,8 +2229,7 @@ static void bta_hh_process_cache_rpt(tBTA_HH_DEV_CB* p_cb, if ((p_rpt = bta_hh_le_find_alloc_report_entry( p_cb, p_rpt_cache->srvc_inst_id, p_rpt_cache->rpt_uuid, p_rpt_cache->char_inst_id)) == NULL) { - APPL_TRACE_ERROR( - "bta_hh_process_cache_rpt: allocation report entry failure"); + LOG_ERROR("bta_hh_process_cache_rpt: allocation report entry failure"); break; } else { p_rpt->rpt_type = p_rpt_cache->rpt_type; diff --git a/system/bta/hh/bta_hh_main.cc b/system/bta/hh/bta_hh_main.cc index e8caf74d29b2b2dc40fd2fa47ee7b134c7f1d854..f28d6ba06429765db1ac583ae4a383d8d7398ca5 100644 --- a/system/bta/hh/bta_hh_main.cc +++ b/system/bta/hh/bta_hh_main.cc @@ -56,7 +56,7 @@ static void bta_hh_better_state_machine(tBTA_HH_DEV_CB* p_cb, uint16_t event, bta_hh_open_act(p_cb, p_data); break; case BTA_HH_INT_CLOSE_EVT: - bta_hh_close_act(p_cb, p_data); + bta_hh_open_failure(p_cb, p_data); break; case BTA_HH_API_MAINT_DEV_EVT: bta_hh_maint_dev_act(p_cb, p_data); @@ -255,8 +255,7 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event, default: /* invalid handle, call bad API event */ - APPL_TRACE_ERROR("wrong device handle: [%d]", - p_data->hdr.layer_specific); + LOG_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific); /* Free the callback buffer now */ if (p_data != NULL) osi_free_and_reset((void**)&p_data->hid_cback.p_data); @@ -268,14 +267,12 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event, /* corresponding CB is found, go to state machine */ else { in_state = p_cb->state; - APPL_TRACE_EVENT("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]", - in_state, bta_hh_state_code(in_state), - bta_hh_evt_code(debug_event)); + LOG_VERBOSE("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]", in_state, + bta_hh_state_code(in_state), bta_hh_evt_code(debug_event)); if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST)) { - APPL_TRACE_ERROR( - "bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d", - p_cb->state, event); + LOG_ERROR("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d", + p_cb->state, event); return; } @@ -299,7 +296,7 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event, * Returns void * ******************************************************************************/ -bool bta_hh_hdl_event(BT_HDR_RIGID* p_msg) { +bool bta_hh_hdl_event(const BT_HDR_RIGID* p_msg) { uint8_t index = BTA_HH_IDX_INVALID; tBTA_HH_DEV_CB* p_cb = NULL; @@ -335,7 +332,8 @@ bool bta_hh_hdl_event(BT_HDR_RIGID* p_msg) { if (index != BTA_HH_IDX_INVALID) p_cb = &bta_hh_cb.kdev[index]; - APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index); + LOG_VERBOSE("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", + p_msg->layer_specific, index); bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA*)p_msg); return (true); diff --git a/system/bta/hh/bta_hh_utils.cc b/system/bta/hh/bta_hh_utils.cc index ce4858c35810cb1ad31d89f1181f65e9e8c3e66d..c0220b98aa49bb0124f1e079e05b945004bcbf1a 100644 --- a/system/bta/hh/bta_hh_utils.cc +++ b/system/bta/hh/bta_hh_utils.cc @@ -19,17 +19,17 @@ #include -#include "bt_target.h" // Must be first to define build configuration -#include "bt_trace.h" // Legacy trace logging #include "bta/hh/bta_hh_int.h" #include "btif/include/btif_storage.h" #include "device/include/interop.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" -#include "osi/include/osi.h" -#include "stack/include/acl_api.h" #include "stack/include/btm_client_interface.h" +#include "stack/include/sdp_api.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + /* if SSR max latency is not defined by remote device, set the default value as half of the link supervision timeout */ #define BTA_HH_GET_DEF_SSR_MAX_LAT(x) ((x) >> 1) @@ -62,16 +62,16 @@ uint8_t bta_hh_find_cb(const RawAddress& bda) { /* check if any active/known devices is a match */ if ((bda == bta_hh_cb.kdev[xx].addr && !bda.IsEmpty())) { #if (BTA_HH_DEBUG == TRUE) - APPL_TRACE_DEBUG("found kdev_cb[%d] hid_handle = %d ", xx, - bta_hh_cb.kdev[xx].hid_handle) + LOG_VERBOSE("found kdev_cb[%d] hid_handle = %d ", xx, + bta_hh_cb.kdev[xx].hid_handle); #endif return xx; } #if (BTA_HH_DEBUG == TRUE) else - APPL_TRACE_DEBUG("in_use ? [%d] kdev[%d].hid_handle = %d state = [%d]", - bta_hh_cb.kdev[xx].in_use, xx, - bta_hh_cb.kdev[xx].hid_handle, bta_hh_cb.kdev[xx].state); + LOG_VERBOSE("in_use ? [%d] kdev[%d].hid_handle = %d state = [%d]", + bta_hh_cb.kdev[xx].in_use, xx, bta_hh_cb.kdev[xx].hid_handle, + bta_hh_cb.kdev[xx].state); #endif } @@ -84,8 +84,8 @@ uint8_t bta_hh_find_cb(const RawAddress& bda) { } /* If device list full, report BTA_HH_IDX_INVALID */ #if (BTA_HH_DEBUG == TRUE) - APPL_TRACE_DEBUG("bta_hh_find_cb:: index = %d while max = %d", xx, - BTA_HH_MAX_DEVICE); + LOG_VERBOSE("bta_hh_find_cb:: index = %d while max = %d", xx, + BTA_HH_MAX_DEVICE); #endif if (xx == BTA_HH_MAX_DEVICE) xx = BTA_HH_IDX_INVALID; @@ -114,12 +114,19 @@ tBTA_HH_DEV_CB* bta_hh_get_cb(const RawAddress& bda) { void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb) { uint8_t index; - if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE) { - if (p_cb->is_le_device) - bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = - BTA_HH_IDX_INVALID; - else + if (p_cb->is_le_device) { + uint8_t le_hid_handle = BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle); + if (le_hid_handle >= BTA_HH_LE_MAX_KNOWN) { + LOG_WARN("Invalid LE hid_handle %d", p_cb->hid_handle); + } else { + bta_hh_cb.le_cb_index[le_hid_handle] = BTA_HH_IDX_INVALID; + } + } else { + if (p_cb->hid_handle >= BTA_HH_MAX_KNOWN) { + LOG_WARN("Invalid hid_handle %d", p_cb->hid_handle); + } else { bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_IDX_INVALID; + } } /* reset device control block */ @@ -147,8 +154,8 @@ void bta_hh_update_di_info(tBTA_HH_DEV_CB* p_cb, uint16_t vendor_id, uint16_t product_id, uint16_t version, uint8_t flag, uint8_t ctry_code) { #if (BTA_HH_DEBUG == TRUE) - APPL_TRACE_DEBUG("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x", - vendor_id, product_id, version); + LOG_VERBOSE("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x", vendor_id, + product_id, version); #endif p_cb->dscp_info.vendor_id = vendor_id; p_cb->dscp_info.product_id = product_id; @@ -171,7 +178,7 @@ void bta_hh_add_device_to_list(tBTA_HH_DEV_CB* p_cb, uint8_t handle, uint8_t sub_class, uint16_t ssr_max_latency, uint16_t ssr_min_tout, uint8_t app_id) { #if (BTA_HH_DEBUG == TRUE) - APPL_TRACE_DEBUG("subclass = 0x%2x", sub_class); + LOG_VERBOSE("subclass = 0x%2x", sub_class); #endif p_cb->hid_handle = handle; @@ -215,13 +222,13 @@ bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class) { if (cod == (uint8_t)p_bta_hh_cfg->p_devt_list[xx].tod) { p_cb->app_id = p_bta_hh_cfg->p_devt_list[xx].app_id; #if (BTA_HH_DEBUG == TRUE) - APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x supported", sub_class); + LOG_VERBOSE("bta_hh_tod_spt sub_class:0x%x supported", sub_class); #endif return true; } } #if (BTA_HH_DEBUG == TRUE) - APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class); + LOG_VERBOSE("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class); #endif return false; } @@ -308,7 +315,8 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status) { if (bta_hh_cb.p_disc_db) { /* Cancel SDP if it had been started. */ - (void)SDP_CancelServiceSearch (bta_hh_cb.p_disc_db); + (void)get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch( + bta_hh_cb.p_disc_db); osi_free_and_reset((void**)&bta_hh_cb.p_disc_db); } @@ -339,8 +347,8 @@ uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) { if (BTA_HH_IS_LE_DEV_HDL_VALID(dev_handle)) index = bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(dev_handle)]; #if (BTA_HH_DEBUG == TRUE) - APPL_TRACE_DEBUG("bta_hh_dev_handle_to_cb_idx dev_handle = %d index = %d", - dev_handle, index); + LOG_VERBOSE("bta_hh_dev_handle_to_cb_idx dev_handle = %d index = %d", + dev_handle, index); #endif } else /* regular HID device checking */ @@ -362,17 +370,16 @@ uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) { void bta_hh_trace_dev_db(void) { uint8_t xx; - APPL_TRACE_DEBUG("bta_hh_trace_dev_db:: Device DB list********************"); + LOG_VERBOSE("bta_hh_trace_dev_db:: Device DB list********************"); for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { - APPL_TRACE_DEBUG("kdev[%d] in_use[%d] handle[%d] ", xx, - bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle); + LOG_VERBOSE("kdev[%d] in_use[%d] handle[%d] ", xx, + bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle); - APPL_TRACE_DEBUG( - "\t\t\t attr_mask[%04x] state [%d] sub_class[%02x] index = %d", - bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state, - bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index); + LOG_VERBOSE("\t\t\t attr_mask[%04x] state [%d] sub_class[%02x] index = %d", + bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state, + bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index); } - APPL_TRACE_DEBUG("*********************************************************"); + LOG_VERBOSE("*********************************************************"); } #endif diff --git a/system/bta/include/OWNERS b/system/bta/include/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..9dfb8422a1218d4222564d335179b53179783055 --- /dev/null +++ b/system/bta/include/OWNERS @@ -0,0 +1 @@ +per-file bta_hearing_aid_api.h=file:/OWNERS_hearingaid diff --git a/system/bta/include/bta_ag_api.h b/system/bta/include/bta_ag_api.h index 5e58c8f9c08e9f2805fd377f2c491ac31eeaa90a..569e16aaf4ffd4d3bc3ab1b6e44882514d1b9837 100644 --- a/system/bta/include/bta_ag_api.h +++ b/system/bta/include/bta_ag_api.h @@ -25,14 +25,14 @@ #ifndef BTA_AG_API_H #define BTA_AG_API_H -#include "bta_api.h" -#include "bta_hfp_api.h" - #include #include #include "bta/include/bta_ag_api.h" #include "bta/include/bta_api.h" +#include "bta_api.h" +#include "bta_hfp_api.h" +#include "macros.h" #include "types/raw_address.h" /***************************************************************************** @@ -52,7 +52,7 @@ #define BTA_AG_FEAT_ECC 0x00000080 /* Enhanced Call Control */ #define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */ #define BTA_AG_FEAT_CODEC 0x00000200 /* Codec Negotiation */ -#define BTA_AG_FEAT_SWB 0x00000400 /* Super Wide Band */ +#define BTA_AG_FEAT_SWB 0x00001000 /* Super Wide Band */ /* AG SDP feature masks */ #define BTA_AG_FEAT_WBS_SUPPORT 0x0020 /* Supports WBS */ @@ -108,10 +108,6 @@ typedef uint8_t tBTA_AG_STATUS; #define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - typedef enum : uint8_t { /* AG result codes used with BTA_AgResult */ BTA_AG_SPK_RES = 0, /* Update speaker volume */ @@ -296,6 +292,17 @@ typedef uint16_t tBTA_AG_PEER_CODEC; #define BTA_AG_AT_MAX_LEN 256 #endif +// Define hfp offload config structure +namespace hfp { + +struct offload_config { + tBTA_AG_PEER_CODEC sco_codec; + int32_t connection_handle; + bool is_controller_codec; + bool is_nrec; +}; + +} // namespace hfp /* data associated with BTA_AG_IND_RES */ typedef struct { uint16_t id; @@ -570,14 +577,16 @@ void BTA_AgClose(uint16_t handle); * Function BTA_AgAudioOpen * * Description Opens an audio connection to the currently connected - * headset or handsfree. Specifying force_cvsd to true to - * force the stack to use CVSD even if mSBC is supported. + * headset or handsfree. Specify `disabled_codecs` to + * force the stack to avoid using certain codecs. + * + * Note that CVSD is a mandatory codec and cannot be disabled. * * * Returns void * ******************************************************************************/ -void BTA_AgAudioOpen(uint16_t handle, bool force_cvsd); +void BTA_AgAudioOpen(uint16_t handle, tBTA_AG_PEER_CODEC disabled_codecs); /******************************************************************************* * diff --git a/system/bta/include/bta_ag_swb_aptx.h b/system/bta/include/bta_ag_swb_aptx.h new file mode 100644 index 0000000000000000000000000000000000000000..b6a8f71ed9229d96733c333e212e0cdfc5dd39aa --- /dev/null +++ b/system/bta/include/bta_ag_swb_aptx.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BTA_AG_SWB_H_ +#define _BTA_AG_SWB_H_ + +#include "bta/ag/bta_ag_int.h" +#include "device/include/esco_parameters.h" +#include "include/hardware/bt_hf.h" + +/* Events originated from HF side */ +#define BTA_AG_AT_QAC_EVT 253 +#define BTA_AG_AT_QCS_EVT 254 +#define BTA_AG_LOCAL_RES_QAC 0x108 +#define BTA_AG_LOCAL_RES_QCS 0x109 + +#define SWB_CODECS_SUPPORTED "0,4,6,7" +#define SWB_CODECS_UNSUPPORTED "0xFFFF" +#define SWB_CODECS_NUMBER 4 + +bool is_hfp_aptx_voice_enabled(); + +void bta_ag_swb_handle_vs_at_events(tBTA_AG_SCB* p_scb, uint16_t cmd, + int16_t int_arg, tBTA_AG_VAL* val); +tBTA_AG_PEER_CODEC bta_ag_parse_qac(char* p_s); + +#endif //_BTA_AG_SWB_H_ diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h index 1f3e28bef49bf3b0ab219bf42831ba7e58adfd76..062fe11841aa2399f0678f951ce621739f1299e6 100644 --- a/system/bta/include/bta_api.h +++ b/system/bta/include/bta_api.h @@ -25,60 +25,27 @@ #ifndef BTA_API_H #define BTA_API_H -#include #include +#include #include #include -#include "bt_target.h" // Must be first to define build configuration -#include "osi/include/log.h" -#include "stack/include/bt_octets.h" -#include "stack/include/bt_types.h" +#include "bta_api_data_types.h" +#include "internal_include/bt_target.h" +#include "macros.h" +#include "os/log.h" +#include "stack/btm/power_mode.h" +#include "stack/include/bt_name.h" #include "stack/include/btm_api_types.h" #include "stack/include/btm_ble_api_types.h" #include "stack/include/hci_error_code.h" -#include "stack/include/sdp_api.h" +#include "stack/include/sdp_device_id.h" #include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" -/***************************************************************************** - * Constants and data types - ****************************************************************************/ - -/* Status Return Value */ -typedef enum : uint8_t { - BTA_SUCCESS = 0, /* Successful operation. */ - BTA_FAILURE = 1, /* Generic failure. */ - BTA_PENDING = 2, /* API cannot be completed right now */ - BTA_BUSY = 3, - BTA_NO_RESOURCES = 4, - BTA_WRONG_MODE = 5, -} tBTA_STATUS; - -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - -inline std::string bta_status_text(const tBTA_STATUS& status) { - switch (status) { - CASE_RETURN_TEXT(BTA_SUCCESS); - CASE_RETURN_TEXT(BTA_FAILURE); - CASE_RETURN_TEXT(BTA_PENDING); - CASE_RETURN_TEXT(BTA_BUSY); - CASE_RETURN_TEXT(BTA_NO_RESOURCES); - CASE_RETURN_TEXT(BTA_WRONG_MODE); - default: - return base::StringPrintf("UNKNOWN[%d]", status); - } -} - -#undef CASE_RETURN_TEXT - /* * Service ID */ @@ -121,15 +88,6 @@ typedef uint8_t tBTA_SERVICE_ID; typedef uint32_t tBTA_SERVICE_MASK; -/* Security Setting Mask */ -#define BTA_SEC_AUTHENTICATE \ - (BTM_SEC_IN_AUTHENTICATE | \ - BTM_SEC_OUT_AUTHENTICATE) /* Authentication required. */ -#define BTA_SEC_ENCRYPT \ - (BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT) /* Encryption required. */ - -typedef uint16_t tBTA_SEC; - #define BTA_APP_ID_PAN_MULTI 0xFE /* app id for pan multiple connection */ #define BTA_ALL_APP_ID 0xFF @@ -166,10 +124,6 @@ inline tBTA_PREF_ROLES toBTA_PREF_ROLES(uint8_t role) { return static_cast(role); } -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string preferred_role_text(const tBTA_PREF_ROLES& role) { switch (role) { CASE_RETURN_TEXT(BTA_ANY_ROLE); @@ -180,7 +134,6 @@ inline std::string preferred_role_text(const tBTA_PREF_ROLES& role) { return base::StringPrintf("UNKNOWN[%hhu]", role); } } -#undef CASE_RETURN_TEXT enum { @@ -217,120 +170,12 @@ typedef struct { typedef uint8_t tBTA_DM_BLE_RSSI_ALERT_TYPE; -typedef enum : uint8_t { - /* Security Callback Events */ - BTA_DM_PIN_REQ_EVT = 2, /* PIN request. */ - BTA_DM_AUTH_CMPL_EVT = 3, /* Authentication complete indication. */ - BTA_DM_AUTHORIZE_EVT = 4, /* Authorization request. */ +typedef enum: uint8_t { BTA_DM_LINK_UP_EVT = 5, /* Connection UP event */ BTA_DM_LINK_DOWN_EVT = 6, /* Connection DOWN event */ - BTA_DM_BOND_CANCEL_CMPL_EVT = 9, /* Bond cancel complete indication */ - BTA_DM_SP_CFM_REQ_EVT = 10, /* Simple Pairing User Confirmation request. \ - */ - BTA_DM_SP_KEY_NOTIF_EVT = 11, /* Simple Pairing Passkey Notification */ - BTA_DM_BLE_KEY_EVT = 15, /* BLE SMP key event for peer device keys */ - BTA_DM_BLE_SEC_REQ_EVT = 16, /* BLE SMP security request */ - BTA_DM_BLE_PASSKEY_NOTIF_EVT = 17, /* SMP passkey notification event */ - BTA_DM_BLE_PASSKEY_REQ_EVT = 18, /* SMP passkey request event */ - BTA_DM_BLE_OOB_REQ_EVT = 19, /* SMP OOB request event */ - BTA_DM_BLE_LOCAL_IR_EVT = 20, /* BLE local IR event */ - BTA_DM_BLE_LOCAL_ER_EVT = 21, /* BLE local ER event */ - BTA_DM_BLE_NC_REQ_EVT = 22, /* SMP Numeric Comparison request event */ - BTA_DM_SP_RMT_OOB_EXT_EVT = - 23, /* Simple Pairing Remote OOB Extended Data request. */ - BTA_DM_BLE_AUTH_CMPL_EVT = 24, /* BLE Auth complete */ - BTA_DM_DEV_UNPAIRED_EVT = 25, - BTA_DM_LE_FEATURES_READ = 27, /* Cotroller specific LE features are read \ - */ - BTA_DM_ENER_INFO_READ = 28, /* Energy info read */ - BTA_DM_BLE_SC_OOB_REQ_EVT = 29, /* SMP SC OOB request event */ - BTA_DM_BLE_CONSENT_REQ_EVT = 30, /* SMP consent request event */ - BTA_DM_BLE_SC_CR_LOC_OOB_EVT = 31, /* SMP SC Create Local OOB request event */ - BTA_DM_REPORT_BONDING_EVT = 32, /*handle for pin or key missing*/ - BTA_DM_LE_ADDR_ASSOC_EVT = 33, /* identity address association event */ + BTA_DM_LE_FEATURES_READ = 27, /* Cotroller specific LE features are read */ BTA_DM_LINK_UP_FAILED_EVT = 34, /* Create connection failed event */ -} tBTA_DM_SEC_EVT; - -/* Structure associated with BTA_DM_PIN_REQ_EVT */ -typedef struct { - /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in - * order */ - RawAddress bd_addr; /* BD address peer device. */ - DEV_CLASS dev_class; /* Class of Device */ - BD_NAME bd_name; /* Name of peer device. */ - bool min_16_digit; /* true if the pin returned must be at least 16 digits */ -} tBTA_DM_PIN_REQ; - -/* BLE related definition */ - -#define BTA_DM_AUTH_FAIL_BASE (HCI_ERR_MAX_ERR + 10) - -/* Converts SMP error codes defined in smp_api.h to SMP auth fail reasons below. - */ -#define BTA_DM_AUTH_CONVERT_SMP_CODE(x) (BTA_DM_AUTH_FAIL_BASE + (x)) - -#define BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL \ - (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_AUTH_FAIL) -#define BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL \ - (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_VALUE_ERR) -#define BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT \ - (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_NOT_SUPPORT) -#define BTA_DM_AUTH_SMP_UNKNOWN_ERR \ - (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_FAIL_UNKNOWN) -#define BTA_DM_AUTH_SMP_CONN_TOUT (BTA_DM_AUTH_FAIL_BASE + SMP_CONN_TOUT) - -typedef uint8_t tBTA_LE_KEY_TYPE; /* can be used as a bit mask */ - -typedef union { - tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */ - tBTM_LE_PCSRK_KEYS psrk_key; /* received peer device SRK */ - tBTM_LE_PID_KEYS pid_key; /* peer device ID key */ - tBTM_LE_LENC_KEYS - lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ - tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ - tBTM_LE_PID_KEYS lid_key; /* local device ID key for the particular remote */ -} tBTA_LE_KEY_VALUE; - -#define BTA_BLE_LOCAL_KEY_TYPE_ID 1 -#define BTA_BLE_LOCAL_KEY_TYPE_ER 2 -typedef uint8_t tBTA_DM_BLE_LOCAL_KEY_MASK; - -typedef struct { - Octet16 ir; - Octet16 irk; - Octet16 dhk; -} tBTA_BLE_LOCAL_ID_KEYS; - -#define BTA_DM_SEC_GRANTED BTA_SUCCESS -#define BTA_DM_SEC_PAIR_NOT_SPT BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT -typedef uint8_t tBTA_DM_BLE_SEC_GRANT; - -/* Structure associated with BTA_DM_BLE_SEC_REQ_EVT */ -typedef struct { - RawAddress bd_addr; /* peer address */ - BD_NAME bd_name; /* peer device name */ -} tBTA_DM_BLE_SEC_REQ; - -typedef struct { - RawAddress bd_addr; /* peer address */ - tBTM_LE_KEY_TYPE key_type; - tBTM_LE_KEY_VALUE* p_key_value; -} tBTA_DM_BLE_KEY; - -/* Structure associated with BTA_DM_AUTH_CMPL_EVT */ -typedef struct { - RawAddress bd_addr; /* BD address peer device. */ - BD_NAME bd_name; /* Name of peer device. */ - bool key_present; /* Valid link key value in key element */ - LinkKey key; /* Link key associated with peer device. */ - uint8_t key_type; /* The type of Link Key */ - bool success; /* true of authentication succeeded, false if failed. */ - tHCI_REASON - fail_reason; /* The HCI reason/error code for when success=false */ - tBLE_ADDR_TYPE addr_type; /* Peer device address type */ - tBT_DEVICE_TYPE dev_type; - bool is_ctkd; /* True if key is derived using CTKD procedure */ -} tBTA_DM_AUTH_CMPL; +} tBTA_DM_ACL_EVT; /* Structure associated with BTA_DM_LINK_UP_EVT */ typedef struct { @@ -353,99 +198,13 @@ typedef struct { tHCI_STATUS status; } tBTA_DM_LINK_DOWN; -#define BTA_AUTH_SP_YES \ - BTM_AUTH_SP_YES /* 1 MITM Protection Required - Single Profile/non-bonding \ - Use IO Capabilities to determine authentication procedure \ - */ - -#define BTA_AUTH_DD_BOND \ - BTM_AUTH_DD_BOND /* 2 this bit is set for dedicated bonding */ -#define BTA_AUTH_GEN_BOND \ - BTM_AUTH_SPGB_NO /* 4 this bit is set for general bonding */ -#define BTA_AUTH_BONDS \ - BTM_AUTH_BONDS /* 6 the general/dedicated bonding bits */ - -#define BTA_LE_AUTH_REQ_SC_MITM_BOND BTM_LE_AUTH_REQ_SC_MITM_BOND /* 1101 */ - -/* Structure associated with BTA_DM_SP_CFM_REQ_EVT */ -typedef struct { - /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in - * order */ - RawAddress bd_addr; /* peer address */ - DEV_CLASS dev_class; /* peer CoD */ - BD_NAME bd_name; /* peer device name */ - uint32_t num_val; /* the numeric value for comparison. If just_works, do not - show this number to UI */ - bool just_works; /* true, if "Just Works" association model */ - tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */ - tBTM_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */ - tBTM_IO_CAP loc_io_caps; /* IO Capabilities of local device */ - tBTM_AUTH_REQ rmt_io_caps; /* IO Capabilities of remote device */ -} tBTA_DM_SP_CFM_REQ; - -/* Structure associated with BTA_DM_SP_KEY_NOTIF_EVT */ -typedef struct { - /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in - * order */ - RawAddress bd_addr; /* peer address */ - DEV_CLASS dev_class; /* peer CoD */ - BD_NAME bd_name; /* peer device name */ - uint32_t passkey; /* the numeric value for comparison. If just_works, do not - show this number to UI */ -} tBTA_DM_SP_KEY_NOTIF; - -/* Structure associated with BTA_DM_SP_RMT_OOB_EVT */ -typedef struct { - /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in - * order */ - RawAddress bd_addr; /* peer address */ - DEV_CLASS dev_class; /* peer CoD */ - BD_NAME bd_name; /* peer device name */ -} tBTA_DM_SP_RMT_OOB; - -/* Structure associated with BTA_DM_BOND_CANCEL_CMPL_EVT */ -typedef struct { - tBTA_STATUS result; /* true of bond cancel succeeded, false if failed. */ -} tBTA_DM_BOND_CANCEL_CMPL; - -/* Add to remove bond of key missing RC */ -typedef struct { - RawAddress bd_addr; -} tBTA_DM_RC_UNPAIR; - -typedef struct { - Octet16 local_oob_c; /* Local OOB Data Confirmation/Commitment */ - Octet16 local_oob_r; /* Local OOB Data Randomizer */ -} tBTA_DM_LOC_OOB_DATA; - -typedef struct { - RawAddress pairing_bda; - RawAddress id_addr; -} tBTA_DM_PROC_ID_ADDR; - -/* Union of all security callback structures */ typedef union { - tBTA_DM_PIN_REQ pin_req; /* PIN request. */ - tBTA_DM_AUTH_CMPL auth_cmpl; /* Authentication complete indication. */ tBTA_DM_LINK_UP link_up; /* ACL connection up event */ tBTA_DM_LINK_UP_FAILED link_up_failed; /* ACL connection up failure event */ tBTA_DM_LINK_DOWN link_down; /* ACL connection down event */ - tBTA_DM_SP_CFM_REQ cfm_req; /* user confirm request */ - tBTA_DM_SP_KEY_NOTIF key_notif; /* passkey notification */ - tBTA_DM_SP_RMT_OOB rmt_oob; /* remote oob */ - tBTA_DM_BOND_CANCEL_CMPL - bond_cancel_cmpl; /* Bond Cancel Complete indication */ - tBTA_DM_BLE_SEC_REQ ble_req; /* BLE SMP related request */ - tBTA_DM_BLE_KEY ble_key; /* BLE SMP keys used when pairing */ - tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */ - Octet16 ble_er; /* ER event data */ - tBTA_DM_LOC_OOB_DATA local_oob_data; /* Local OOB data generated by us */ - tBTA_DM_RC_UNPAIR delete_key_RC_to_unpair; - tBTA_DM_PROC_ID_ADDR proc_id_addr; /* Identity address event */ -} tBTA_DM_SEC; - -/* Security callback */ -typedef void(tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data); +} tBTA_DM_ACL; + +typedef void(tBTA_DM_ACL_CBACK)(tBTA_DM_ACL_EVT event, tBTA_DM_ACL* p_data); #define BTA_DM_BLE_PF_LIST_LOGIC_OR 1 #define BTA_DM_BLE_PF_FILT_LOGIC_OR 0 @@ -454,21 +213,16 @@ typedef void(tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data); typedef enum : uint8_t { BTA_DM_INQ_RES_EVT = 0, /* Inquiry result for a peer device. */ BTA_DM_INQ_CMPL_EVT = 1, /* Inquiry complete. */ - BTA_DM_DISC_RES_EVT = 2, /* Discovery result for a peer device. */ + BTA_DM_DISC_RES_EVT = 2, /* Service Discovery result for a peer device. */ BTA_DM_GATT_OVER_LE_RES_EVT = 3, /* GATT services over LE transport discovered */ BTA_DM_DISC_CMPL_EVT = 4, /* Discovery complete. */ BTA_DM_SEARCH_CANCEL_CMPL_EVT = 5, /* Search cancelled */ BTA_DM_DID_RES_EVT = 6, /* Vendor/Product ID search result */ BTA_DM_GATT_OVER_SDP_RES_EVT = 7, /* GATT services over SDP discovered */ + BTA_DM_NAME_READ_EVT = 8, /* Name read complete. */ } tBTA_DM_SEARCH_EVT; -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string bta_dm_search_evt_text(const tBTA_DM_SEARCH_EVT& event) { switch (event) { CASE_RETURN_TEXT(BTA_DM_INQ_RES_EVT); @@ -479,13 +233,12 @@ inline std::string bta_dm_search_evt_text(const tBTA_DM_SEARCH_EVT& event) { CASE_RETURN_TEXT(BTA_DM_SEARCH_CANCEL_CMPL_EVT); CASE_RETURN_TEXT(BTA_DM_DID_RES_EVT); CASE_RETURN_TEXT(BTA_DM_GATT_OVER_SDP_RES_EVT); + CASE_RETURN_TEXT(BTA_DM_NAME_READ_EVT); default: return base::StringPrintf("UNKNOWN[%hhu]", event); } } -#undef CASE_RETURN_TEXT - /* Structure associated with BTA_DM_INQ_RES_EVT */ typedef struct { RawAddress bd_addr; /* BD address peer device. */ @@ -511,6 +264,7 @@ typedef struct { bool include_rsi; /* true, if ADV contains RSI data */ RawAddress original_bda; /* original address to pass up to GattService#onScanResult */ + uint16_t clock_offset; } tBTA_DM_INQ_RES; /* Structure associated with BTA_DM_INQ_CMPL_EVT */ @@ -741,6 +495,18 @@ enum { void BTA_dm_init(); +/******************************************************************************* + * + * Function BTA_EnableTestMode + * + * Description Enables bluetooth device under test mode + * + * + * Returns tBTA_STATUS + * + ******************************************************************************/ +extern void BTA_EnableTestMode(void); + /******************************************************************************* * * Function BTA_DmSetDeviceName @@ -825,107 +591,6 @@ void BTA_DmDiscover(const RawAddress& bd_addr, tBTA_DM_SEARCH_CBACK* p_cback, tBTA_STATUS BTA_DmGetCachedRemoteName(const RawAddress& remote_device, uint8_t** pp_cached_name); -/******************************************************************************* - * - * Function BTA_DmBond - * - * Description This function initiates a bonding procedure with a peer - * device by designated transport. The bonding procedure - * enables authentication and optionally encryption on the - * Bluetooth link. - * - * - * Returns void - * - ******************************************************************************/ -void BTA_DmBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type); - -/******************************************************************************* - * - * Function BTA_DmBondCancel - * - * Description This function cancels a bonding procedure with a peer - * device. - * - * - * Returns void - * - ******************************************************************************/ -void BTA_DmBondCancel(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTA_DmPinReply - * - * Description This function provides a PIN when one is requested by DM - * during a bonding procedure. The application should call - * this function after the security callback is called with - * a BTA_DM_PIN_REQ_EVT. - * - * - * Returns void - * - ******************************************************************************/ -void BTA_DmPinReply(const RawAddress& bd_addr, bool accept, uint8_t pin_len, - uint8_t* p_pin); - -/******************************************************************************* - * - * Function BTA_DmLocalOob - * - * Description This function retrieves the OOB data from local controller. - * The result is reported by bta_dm_co_loc_oob(). - * - * Returns void - * - ******************************************************************************/ -void BTA_DmLocalOob(void); - -/******************************************************************************* - * - * Function BTA_DmConfirm - * - * Description This function accepts or rejects the numerical value of the - * Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT - * - * Returns void - * - ******************************************************************************/ -void BTA_DmConfirm(const RawAddress& bd_addr, bool accept); - -/******************************************************************************* - * - * Function BTA_DmAddDevice - * - * Description This function adds a device to the security database list - * of peer devices. This function would typically be called - * at system startup to initialize the security database with - * known peer devices. This is a direct execution function - * that may lock task scheduling on some platforms. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, - const LinkKey& link_key, uint8_t key_type, - uint8_t pin_length); - -/******************************************************************************* - * - * Function BTA_DmRemoveDevice - * - * Description This function removes a device from the security database. - * This is a direct execution function that may lock task - * scheduling on some platforms. - * - * - * Returns BTA_SUCCESS if successful. - * BTA_FAIL if operation failed. - * - ******************************************************************************/ -tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr); - /******************************************************************************* * * Function BTA_GetEirService @@ -985,90 +650,6 @@ tBTA_STATUS BTA_DmSetLocalDiRecord(tSDP_DI_RECORD* p_device_info, void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev, tBT_TRANSPORT transport); -/* BLE related API functions */ -/******************************************************************************* - * - * Function BTA_DmBleSecurityGrant - * - * Description Grant security request access. - * - * Parameters: bd_addr - BD address of the peer - * res - security grant status. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmBleSecurityGrant(const RawAddress& bd_addr, - tBTA_DM_BLE_SEC_GRANT res); - -/******************************************************************************* - * - * Function BTA_DmBlePasskeyReply - * - * Description Send BLE SMP passkey reply. - * - * Parameters: bd_addr - BD address of the peer - * accept - passkey entry sucessful or declined. - * passkey - passkey value, must be a 6 digit number, - * can be lead by 0. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmBlePasskeyReply(const RawAddress& bd_addr, bool accept, - uint32_t passkey); - -/******************************************************************************* - * - * Function BTA_DmBleConfirmReply - * - * Description Send BLE SMP SC user confirmation reply. - * - * Parameters: bd_addr - BD address of the peer - * accept - numbers to compare are the same or - * different. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmBleConfirmReply(const RawAddress& bd_addr, bool accept); - -/******************************************************************************* - * - * Function BTA_DmAddBleDevice - * - * Description Add a BLE device. This function will be normally called - * during host startup to restore all required information - * for a LE device stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * dev_type - Remote device's device type. - * addr_type - LE device address type. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmAddBleDevice(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_DEVICE_TYPE dev_type); - -/******************************************************************************* - * - * Function BTA_DmAddBleKey - * - * Description Add/modify LE device information. This function will be - * normally called during host startup to restore all required - * information stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * p_le_key - LE key values. - * key_type - LE SMP key type. - * - * Returns void - * - ******************************************************************************/ -void BTA_DmAddBleKey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type); - /******************************************************************************* * * Function BTA_DmSetBlePrefConnParams @@ -1091,33 +672,6 @@ void BTA_DmSetBlePrefConnParams(const RawAddress& bd_addr, uint16_t peripheral_latency, uint16_t supervision_tout); -/******************************************************************************* - * - * Function BTA_DmSetEncryption - * - * Description This function is called to ensure that connection is - * encrypted. Should be called only on an open connection. - * Typically only needed for connections that first want to - * bring up unencrypted links, then later encrypt them. - * - * Parameters: bd_addr - Address of the peer device - * transport - transport of the link to be encruypted - * p_callback - Pointer to callback function to indicat the - * link encryption status - * sec_act - This is the security action to indicate - * what kind of BLE security level is required - * for the BLE link if BLE is supported - * Note: This parameter is ignored for - * BR/EDR or if BLE is not supported. - * - * Returns void - * - * - ******************************************************************************/ -void BTA_DmSetEncryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, - tBTA_DM_ENCRYPT_CBACK* p_callback, - tBTM_BLE_SEC_ACT sec_act); - /******************************************************************************* * * Function BTA_DmBleObserve @@ -1298,7 +852,7 @@ void BTA_DmDisconnectAllAcls(void); ******************************************************************************/ void BTA_DmClearFilterAcceptList(void); -using LeRandCallback = base::Callback; +using LeRandCallback = base::OnceCallback; /******************************************************************************* * * Function BTA_DmLeRand diff --git a/system/bta/include/bta_api_data_types.h b/system/bta/include/bta_api_data_types.h new file mode 100644 index 0000000000000000000000000000000000000000..94c852d22ff19a9fd81e3277ac65bffa6dc6fb37 --- /dev/null +++ b/system/bta/include/bta_api_data_types.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#pragma once + +#include + +#include +#include + +#include "macros.h" +#include "types/raw_address.h" + +/***************************************************************************** + * Constants and data types + ****************************************************************************/ + +/* Status Return Value */ +typedef enum : uint8_t { + BTA_SUCCESS = 0, /* Successful operation. */ + BTA_FAILURE = 1, /* Generic failure. */ + BTA_PENDING = 2, /* API cannot be completed right now */ + BTA_BUSY = 3, + BTA_NO_RESOURCES = 4, + BTA_WRONG_MODE = 5, +} tBTA_STATUS; + +inline std::string bta_status_text(const tBTA_STATUS& status) { + switch (status) { + CASE_RETURN_TEXT(BTA_SUCCESS); + CASE_RETURN_TEXT(BTA_FAILURE); + CASE_RETURN_TEXT(BTA_PENDING); + CASE_RETURN_TEXT(BTA_BUSY); + CASE_RETURN_TEXT(BTA_NO_RESOURCES); + CASE_RETURN_TEXT(BTA_WRONG_MODE); + default: + return base::StringPrintf("UNKNOWN[%d]", status); + } +} + +typedef struct { + RawAddress pairing_bda; + RawAddress id_addr; +} tBTA_DM_PROC_ID_ADDR; + diff --git a/system/bta/include/bta_ar_api.h b/system/bta/include/bta_ar_api.h index c6807d884b40cede21b0caff1dc079b8af0d89b6..f71d58d0040416c90857032536f6fb212b3951fe 100644 --- a/system/bta/include/bta_ar_api.h +++ b/system/bta/include/bta_ar_api.h @@ -134,4 +134,20 @@ void bta_ar_reg_avrc(uint16_t service_uuid, const char* p_service_name, *****************************************************************************/ void bta_ar_dereg_avrc(uint16_t service_uuid); +/****************************************************************************** + * + * Function bta_ar_reg_avrc_for_src_sink_coexist + * + * Description This function is called to register an SDP record for AVRCP. + * Add sys_id to distinguish src or sink role and add also save + *tg_categories + * + * Returns void + * + *****************************************************************************/ +extern void bta_ar_reg_avrc_for_src_sink_coexist( + uint16_t service_uuid, const char* service_name, const char* provider_name, + uint16_t categories, tBTA_SYS_ID sys_id, bool browse_supported, + uint16_t profile_version); + #endif /* BTA_AR_API_H */ diff --git a/system/bta/include/bta_av_api.h b/system/bta/include/bta_av_api.h index 686f59da14cf21e6587600c1185605e9c645e9f9..df133e6c787a6bce684b16122dd3d305ca44dd9c 100644 --- a/system/bta/include/bta_av_api.h +++ b/system/bta/include/bta_av_api.h @@ -31,7 +31,6 @@ #include "bta/include/bta_api.h" #include "stack/include/avrc_defs.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "types/raw_address.h" /***************************************************************************** @@ -75,6 +74,9 @@ typedef uint8_t tBTA_AV_STATUS; #define BTA_AV_FEAT_NO_SCO_SSPD \ 0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */ +/* it indicates the feature is for source */ +#define BTA_AV_FEAT_SRC 0x4000 + typedef uint16_t tBTA_AV_FEAT; /* AV channel values */ @@ -167,6 +169,7 @@ typedef struct { tBTA_AV_HNDL hndl; /* Handle associated with the stream. */ uint8_t app_id; /* ID associated with call to BTA_AvRegister() */ tBTA_AV_STATUS status; + uint8_t peer_sep; /* peer sep type */ } tBTA_AV_REGISTER; /* data associated with BTA_AV_OPEN_EVT */ @@ -236,6 +239,8 @@ typedef struct { uint8_t rc_handle; uint16_t cover_art_psm; tBTA_AV_FEAT peer_features; + tBTA_AV_FEAT peer_ct_features; + tBTA_AV_FEAT peer_tg_features; RawAddress peer_addr; tBTA_AV_STATUS status; } tBTA_AV_RC_OPEN; @@ -263,6 +268,8 @@ typedef struct { typedef struct { uint8_t rc_handle; tBTA_AV_FEAT peer_features; + tBTA_AV_FEAT peer_ct_features; + tBTA_AV_FEAT peer_tg_features; RawAddress peer_addr; } tBTA_AV_RC_FEAT; @@ -330,7 +337,7 @@ typedef struct { typedef union { tBTA_AV_CHNL chnl; tBTA_AV_ENABLE enable; - tBTA_AV_REGISTER registr; + tBTA_AV_REGISTER reg; tBTA_AV_OPEN open; tBTA_AV_CLOSE close; tBTA_AV_START start; @@ -730,4 +737,14 @@ int BTA_AvObtainPeerChannelIndex(const RawAddress& peer_address); */ void bta_debug_av_dump(int fd); +/** + * Set peer sep in order to delete wrong avrcp handle + * there are may be two avrcp handle at start, delete the wrong when a2dp + * connected + * + * @param peer_address the peer address + * @param sep the peer sep + */ +void BTA_AvSetPeerSep(const RawAddress& bdaddr, uint8_t sep); + #endif /* BTA_AV_API_H */ diff --git a/system/bta/include/bta_dm_acl.h b/system/bta/include/bta_dm_acl.h index ec724851452bc85f537a57d1053ad688db15b86a..44cf3cf73bac8748851258d4bf48cd6a6fd2f5d0 100644 --- a/system/bta/include/bta_dm_acl.h +++ b/system/bta/include/bta_dm_acl.h @@ -18,7 +18,6 @@ #include -#include "stack/include/bt_types.h" #include "stack/include/hci_error_code.h" #include "types/bt_transport.h" #include "types/hci_role.h" diff --git a/system/bta/include/bta_dm_ci.h b/system/bta/include/bta_dm_ci.h index 2109e414396e72d5cbeeebe41753f00717fd5084..3989eb061ef5b1245e2d98d3d5f1f21c6885f66d 100644 --- a/system/bta/include/bta_dm_ci.h +++ b/system/bta/include/bta_dm_ci.h @@ -26,7 +26,7 @@ #include -#include "stack/include/bt_types.h" +#include "stack/include/bt_octets.h" #include "types/raw_address.h" /***************************************************************************** diff --git a/system/bta/include/bta_dm_co.h b/system/bta/include/bta_dm_co.h deleted file mode 100644 index 016c7a1f61056cfca7901a81f8f26f94d549d293..0000000000000000000000000000000000000000 --- a/system/bta/include/bta_dm_co.h +++ /dev/null @@ -1,201 +0,0 @@ -/****************************************************************************** - * - * Copyright 2006-2012 Broadcom Corporation - * - * 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. - * - ******************************************************************************/ - -/****************************************************************************** - * - * This is the interface file for device mananger callout functions. - * - ******************************************************************************/ -#ifndef BTA_DM_CO_H -#define BTA_DM_CO_H - -#include "bta/include/bta_api.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" -#include "stack/include/btm_api_types.h" -#include "types/raw_address.h" - -#ifndef BTA_SCO_OUT_PKT_SIZE -#define BTA_SCO_OUT_PKT_SIZE BTM_SCO_DATA_SIZE_MAX -#endif - -/***************************************************************************** - * Function Declarations - ****************************************************************************/ - -/******************************************************************************* - * - * Function bta_dm_co_io_req - * - * Description This callout function is executed by DM to get IO - * capabilities of the local device for the Simple Pairing - * process - * - * Parameters bd_addr - The peer device - * *p_io_cap - The local Input/Output capabilities - * *p_oob_data - true, if OOB data is available for the peer - * device. - * *p_auth_req - true, if MITM protection is required. - * - * Returns void. - * - ******************************************************************************/ -void bta_dm_co_io_req(const RawAddress& bd_addr, tBTM_IO_CAP* p_io_cap, - tBTM_OOB_DATA* p_oob_data, tBTM_AUTH_REQ* p_auth_req, - bool is_orig); - -/******************************************************************************* - * - * Function bta_dm_co_io_rsp - * - * Description This callout function is executed by DM to report IO - * capabilities of the peer device for the Simple Pairing - * process - * - * Parameters bd_addr - The peer device - * io_cap - The remote Input/Output capabilities - * oob_data - true, if OOB data is available for the peer - * device. - * auth_req - true, if MITM protection is required. - * - * Returns void. - * - ******************************************************************************/ -void bta_dm_co_io_rsp(const RawAddress& bd_addr, tBTM_IO_CAP io_cap, - tBTM_OOB_DATA oob_data, tBTM_AUTH_REQ auth_req); - -/******************************************************************************* - * - * Function bta_dm_co_loc_oob - * - * Description This callout function is executed by DM to report the OOB - * data of the local device for the Simple Pairing process - * - * Parameters valid - true, if the local OOB data is retrieved from LM - * c - Simple Pairing Hash C - * r - Simple Pairing Randomnizer R - * - * Returns void. - * - ******************************************************************************/ -void bta_dm_co_loc_oob(bool valid, const Octet16& c, const Octet16& r); - -/******************************************************************************* - * - * Function bta_dm_co_rmt_oob - * - * Description This callout function is executed by DM to request the OOB - * data for the remote device for the Simple Pairing process - * - * Parameters bd_addr - The peer device - * - * Returns void. - * - ******************************************************************************/ -void bta_dm_co_rmt_oob(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function bta_dm_sco_co_open - * - * Description This function is executed when a SCO connection is open. - * - * - * Returns void - * - ******************************************************************************/ -void bta_dm_sco_co_open(uint16_t handle, uint8_t pkt_size, uint16_t event); - -/******************************************************************************* - * - * Function bta_dm_sco_co_close - * - * Description This function is called when a SCO connection is closed - * - * - * Returns void - * - ******************************************************************************/ -void bta_dm_sco_co_close(void); - -/******************************************************************************* - * - * Function bta_dm_sco_co_out_data - * - * Description This function is called to send SCO data over HCI. - * - * Returns void - * - ******************************************************************************/ -void bta_dm_sco_co_out_data(BT_HDR** p_buf); - -/******************************************************************************* - * - * Function bta_dm_sco_co_in_data - * - * Description This function is called to send incoming SCO data to - * application. - * - * Returns void - * - ******************************************************************************/ -void bta_dm_sco_co_in_data(BT_HDR* p_buf, tBTM_SCO_DATA_FLAG status); - -/******************************************************************************* - * - * Function bta_dm_co_ble_io_req - * - * Description This callout function is executed by DM to get BLE IO - * capabilities before SMP pairing gets going. - * - * Parameters bd_addr - The peer device - * *p_io_cap - The local Input/Output capabilities - * *p_oob_data - true, if OOB data is available for the peer - * device. - * *p_auth_req - Auth request setting (Bonding and MITM - * required or not) - * *p_max_key_size - max key size local device supported. - * *p_init_key - initiator keys. - * *p_resp_key - responder keys. - * - * Returns void. - * - ******************************************************************************/ -void bta_dm_co_ble_io_req(const RawAddress& bd_addr, tBTM_IO_CAP* p_io_cap, - tBTM_OOB_DATA* p_oob_data, - tBTM_LE_AUTH_REQ* p_auth_req, uint8_t* p_max_key_size, - tBTM_LE_KEY_TYPE* p_init_key, - tBTM_LE_KEY_TYPE* p_resp_key); - -/******************************************************************************* - * - * Function bta_dm_co_ble_local_key_reload - * - * Description This callout function is to load the local BLE keys if - * available on the device. - * - * Parameters none - * - * Returns void. - * - ******************************************************************************/ -void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, - Octet16* p_er, - tBTA_BLE_LOCAL_ID_KEYS* p_id_keys); - -#endif /* BTA_DM_CO_H */ diff --git a/system/bta/include/bta_gatt_api.h b/system/bta/include/bta_gatt_api.h index f93d3f9c16940b63c738666aee7a9c82759ddb33..01d53fdf49ee11717d3399842f8e5aacfb1810f1 100644 --- a/system/bta/include/bta_gatt_api.h +++ b/system/bta/include/bta_gatt_api.h @@ -33,6 +33,8 @@ #include #include "bta/gatt/database.h" +#include "hardware/bt_gatt_types.h" +#include "macros.h" #include "stack/include/gatt_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -74,10 +76,6 @@ typedef enum : uint8_t { BTA_GATTC_SUBRATE_CHG_EVT = 27, /* Subrate Change event */ } tBTA_GATTC_EVT; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string gatt_client_event_text(const tBTA_GATTC_EVT& event) { switch (event) { CASE_RETURN_TEXT(BTA_GATTC_DEREG_EVT); @@ -101,7 +99,6 @@ inline std::string gatt_client_event_text(const tBTA_GATTC_EVT& event) { return base::StringPrintf("UNKNOWN[%hhu]", event); } } -#undef CASE_RETURN_TEXT typedef struct { uint16_t unit; /* as UUIUD defined by SIG */ @@ -620,7 +617,9 @@ typedef void (*GATT_WRITE_OP_CB)(uint16_t conn_id, tGATT_STATUS status, const uint8_t* value, void* data); typedef void (*GATT_CONFIGURE_MTU_OP_CB)(uint16_t conn_id, tGATT_STATUS status, void* data); - +typedef void (*GATT_READ_MULTI_OP_CB)(uint16_t conn_id, tGATT_STATUS status, + tBTA_GATTC_MULTI& handles, uint16_t len, + uint8_t* value, void* data); /******************************************************************************* * * Function BTA_GATTC_ReadCharacteristic @@ -792,13 +791,16 @@ void BTA_GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute); * characteristic descriptors. * * Parameters conn_id - connectino ID. - * p_read_multi - read multiple parameters. + * p_read_multi - read multiple parameters. + * variable_len - whether "read multi variable length" variant + * shall be used. * * Returns None * ******************************************************************************/ -void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI* p_read_multi, - tGATT_AUTH_REQ auth_req); +void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, + bool variable_len, tGATT_AUTH_REQ auth_req, + GATT_READ_MULTI_OP_CB callback, void* cb_data); /******************************************************************************* * diff --git a/system/bta/include/bta_gatt_queue.h b/system/bta/include/bta_gatt_queue.h index 0c55b2cf41f9bd6420056f8c51ea6e0a42834c8d..bf6a52ef661bcb1ac37ccb2b16a4cdcf9d296614 100644 --- a/system/bta/include/bta_gatt_queue.h +++ b/system/bta/include/bta_gatt_queue.h @@ -49,12 +49,19 @@ class BtaGattQueue { tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data); static void ConfigureMtu(uint16_t conn_id, uint16_t mtu); + static void ReadMultiCharacteristic(uint16_t conn_id, + tBTA_GATTC_MULTI& p_read_multi, + bool variable_len, + GATT_READ_MULTI_OP_CB cb, void* cb_data); /* Holds pending GATT operations */ struct gatt_operation { uint8_t type; uint16_t handle; + tBTA_GATTC_MULTI handles; + bool variable_len; /* whether read multi variable len is used*/ GATT_READ_OP_CB read_cb; + GATT_READ_MULTI_OP_CB read_multi_cb; void* read_cb_data; GATT_WRITE_OP_CB write_cb; void* write_cb_data; @@ -77,7 +84,10 @@ class BtaGattQueue { const uint8_t* value, void* data); static void gatt_configure_mtu_op_finished(uint16_t conn_id, tGATT_STATUS status, void* data); - + static void gatt_read_multi_op_finished(uint16_t conn_id, tGATT_STATUS status, + tBTA_GATTC_MULTI& handle, + uint16_t len, uint8_t* value, + void* data); // maps connection id to operations waiting for execution static std::unordered_map> gatt_op_queue; // contain connection ids that currently execute operations diff --git a/system/bta/include/bta_hearing_aid_api.h b/system/bta/include/bta_hearing_aid_api.h index 9bda9e6e337f4390300042fb7fa52180d5d1aed1..c220631e87cc518073c395ff2e9ebd89184a4907 100644 --- a/system/bta/include/bta_hearing_aid_api.h +++ b/system/bta/include/bta_hearing_aid_api.h @@ -36,7 +36,8 @@ constexpr uint16_t HA_INTERVAL_20_MS = 20; // Masks for checking capability support constexpr uint8_t CAPABILITY_SIDE = 0x01; constexpr uint8_t CAPABILITY_BINAURAL = 0x02; -constexpr uint8_t CAPABILITY_RESERVED = 0xFC; +constexpr uint8_t CAPABILITY_CSIS = 0x04; +constexpr uint8_t CAPABILITY_RESERVED = 0xF8; // Number of retry for phy update. This targets to reduce phy update collision. const static uint8_t PHY_UPDATE_RETRY_LIMIT = @@ -113,9 +114,11 @@ struct HearingDevice { bool service_changed_rcvd; /* we are making active attempt to connect to this device, 'direct connect'. - * This is true only during initial phase of first connection. */ + */ bool connecting_actively; + bool switch_to_background_connection_after_failure; + /* For two hearing aids, you must update their parameters one after another, * not simulteanously, to ensure start of connection events for both devices * are far from each other. This status tracks whether this device is waiting @@ -175,6 +178,7 @@ struct HearingDevice { first_connection(false), service_changed_rcvd(false), connecting_actively(false), + switch_to_background_connection_after_failure(false), connection_update_status(NONE), accepting_audio(false), conn_id(0), @@ -201,6 +205,7 @@ struct HearingDevice { first_connection(first_connection), service_changed_rcvd(false), connecting_actively(first_connection), + switch_to_background_connection_after_failure(false), connection_update_status(NONE), accepting_audio(false), conn_id(0), @@ -238,7 +243,7 @@ class HearingAid { static void DebugDump(int fd); static void AddFromStorage(const HearingDevice& dev_info, - uint16_t is_acceptlisted); + bool is_acceptlisted); static int GetDeviceCount(); diff --git a/system/bta/include/bta_hf_client_api.h b/system/bta/include/bta_hf_client_api.h index fe0728e1d4dffc73388fd15dc6365287041d8997..035a128786c20b5f8446727bc07723a608f40c8c 100644 --- a/system/bta/include/bta_hf_client_api.h +++ b/system/bta/include/bta_hf_client_api.h @@ -68,6 +68,11 @@ typedef uint16_t tBTA_HF_CLIENT_PEER_FEAT; #define BTA_HF_CLIENT_FEAT_CODEC 0x00000080 /* Codec Negotiation */ #define BTA_HF_CLIENT_FEAT_HF_IND 0x00000100 /* HF Indicators */ #define BTA_HF_CLIENT_FEAT_ESCO_S4 0x00000200 /* ESCO S4 link setting */ +#define BTA_HF_CLIENT_FEAT_SWB 0x00000400 /* SWB feature (HFP 1.9) */ + +/* FP SDP feature masks */ +#define BTA_HF_CLIENT_WBS_SUPPORT 0x0020 /* Supports WBS */ +#define BTA_HF_CLIENT_FEAT_SWB_SUPPORT 0x0100 /* Supports SWB */ /* HFP HF extended call handling - masks not related to any spec */ #define BTA_HF_CLIENT_CHLD_REL \ @@ -129,7 +134,8 @@ typedef uint8_t tBTA_HF_CLIENT_AT_RESULT_TYPE; #define BTA_HF_CLIENT_RING_INDICATION 21 /* HF Client ring indication */ #define BTA_HF_CLIENT_UNKNOWN_EVT 22 /* Unknown or vendor specific Event */ - +#define BTA_HF_CLIENT_AUDIO_LC3_OPEN_EVT \ + 23 /* Audio connection with LC3 codec open */ #define BTA_HF_CLIENT_DISABLE_EVT 30 /* HF Client disabled */ typedef uint8_t tBTA_HF_CLIENT_EVT; @@ -249,10 +255,10 @@ typedef struct { } tBTA_HF_CLIENT_VAL; /* data associated with BTA_HF_CLIENT_UNKNOWN_EVT event */ -#define BTA_HF_CLIENT_UNKOWN_EVENT_LEN 32 +#define BTA_HF_CLIENT_UNKNOWN_EVENT_LEN 32 typedef struct { RawAddress bd_addr; - char event_string[BTA_HF_CLIENT_UNKOWN_EVENT_LEN + 1]; + char event_string[BTA_HF_CLIENT_UNKNOWN_EVENT_LEN + 1]; } tBTA_HF_CLIENT_UNKNOWN; /* union of data associated with AG callback */ diff --git a/system/bta/include/bta_hh_api.h b/system/bta/include/bta_hh_api.h index 12655243143f0d61060d2037d1b5184ec003fb81..1f62c9e1bbe06bad4b590874a3e2b690df3dc3d5 100644 --- a/system/bta/include/bta_hh_api.h +++ b/system/bta/include/bta_hh_api.h @@ -24,6 +24,7 @@ #include #include "bta/include/bta_api.h" +#include "macros.h" #include "stack/include/bt_hdr.h" #include "stack/include/hiddefs.h" #include "types/raw_address.h" @@ -43,12 +44,6 @@ #define BTA_HH_SSR_MIN_TOUT_DEF 2 #endif -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - /* BTA HID Host callback events */ #define BTA_HH_ENABLE_EVT 0 /* HH enabled */ #define BTA_HH_DISABLE_EVT 1 /* HH disabled */ diff --git a/system/bta/include/bta_jv_api.h b/system/bta/include/bta_jv_api.h index 035710d0f6c2117c7e3b99456193bd3eaf658659..604519d37b8c01f0f7031ac77400e6bc477c9780 100644 --- a/system/bta/include/bta_jv_api.h +++ b/system/bta/include/bta_jv_api.h @@ -29,6 +29,7 @@ #include "bt_target.h" // Must be first to define build configuration #include "bta/include/bta_api.h" +#include "bta_sec_api.h" #include "stack/include/bt_hdr.h" #include "stack/include/l2c_api.h" #include "types/bluetooth/uuid.h" @@ -72,8 +73,6 @@ typedef uint8_t tBTA_JV_L2CAP_REASON; #define BTA_JV_MAX_L2C_CONN \ GAP_MAX_CONNECTIONS /* GAP handle is used as index, hence do not change this \ value */ -#define BTA_JV_MAX_SCN \ - PORT_MAX_RFC_PORTS /* same as BTM_MAX_SCN (in btm_int.h) */ #define BTA_JV_MAX_RFC_CONN MAX_RFC_PORTS #ifndef BTA_JV_DEF_RFC_MTU @@ -126,7 +125,7 @@ typedef uint8_t tBTA_JV_PM_ID; /* define maximum number of registered PM entities. should be in sync with bta * pm! */ #ifndef BTA_JV_PM_MAX_NUM -#define BTA_JV_PM_MAX_NUM 5 +#define BTA_JV_PM_MAX_NUM 12 #endif /* JV pm connection states */ diff --git a/system/bta/include/bta_jv_co.h b/system/bta/include/bta_jv_co.h index 35562dd0a0f42ccdb699d2a5764e4cbf81d2e40a..e170f2fb9685fee7d2c14b1f7e3f7e07f06fb3cf 100644 --- a/system/bta/include/bta_jv_co.h +++ b/system/bta/include/bta_jv_co.h @@ -27,7 +27,6 @@ #include #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" /***************************************************************************** * Function Declarations diff --git a/system/bta/include/bta_le_audio_api.h b/system/bta/include/bta_le_audio_api.h index f2252e64a3c75c872ab879d70cb4a52d93f5cfe6..c5e4cef53d8afb200b9c00b352ab206a6b044ad0 100644 --- a/system/bta/include/bta_le_audio_api.h +++ b/system/bta/include/bta_le_audio_api.h @@ -29,6 +29,7 @@ class LeAudioHalVerifier { static bool SupportsLeAudio(); static bool SupportsLeAudioHardwareOffload(); static bool SupportsLeAudioBroadcast(); + static bool SupportsStreamActiveApi(); }; /* Interface class */ @@ -41,7 +42,7 @@ class LeAudioClient { base::Closure initCb, base::Callback hal_2_1_verifier, const std::vector& offloading_preference); - static void Cleanup(base::Callback cleanupCb); + static void Cleanup(void); static LeAudioClient* Get(void); static void DebugDump(int fd); @@ -62,6 +63,10 @@ class LeAudioClient { bluetooth::le_audio::btle_audio_codec_config_t output_codec_config) = 0; virtual void SetCcidInformation(int ccid, int context_type) = 0; virtual void SetInCall(bool in_call) = 0; + virtual bool IsInCall() = 0; + virtual void SetInVoipCall(bool in_call) = 0; + virtual void SetUnicastMonitorMode(uint8_t direction, bool enable) = 0; + virtual bool IsInVoipCall() = 0; virtual void SendAudioProfilePreferences( const int group_id, bool is_output_preference_le_audio, bool is_duplex_preference_le_audio) = 0; @@ -86,7 +91,4 @@ class LeAudioClient { static bool GetAsesForStorage(const RawAddress& addr, std::vector& out); static bool IsLeAudioClientRunning(); - - static void InitializeAudioSetConfigurationProvider(void); - static void CleanupAudioSetConfigurationProvider(void); }; diff --git a/system/stack/btm/btm_scn.h b/system/bta/include/bta_rfcomm_scn.h similarity index 85% rename from system/stack/btm/btm_scn.h rename to system/bta/include/bta_rfcomm_scn.h index fe9dcb7ad689045aa0ae60919d6a0b507cd369f8..a43f3290f183553d371786f62feb94f48dbc61b8 100644 --- a/system/stack/btm/btm_scn.h +++ b/system/bta/include/bta_rfcomm_scn.h @@ -18,6 +18,6 @@ #include -bool BTM_FreeSCN(uint8_t scn); -bool BTM_TryAllocateSCN(uint8_t scn); -bool BTM_TryAllocateSCN(uint8_t scn); +uint8_t BTA_AllocateSCN(void); +bool BTA_FreeSCN(uint8_t scn); +bool BTA_TryAllocateSCN(uint8_t scn); diff --git a/system/bta/include/bta_sdp_api.h b/system/bta/include/bta_sdp_api.h index 7731cc135457a4a20149f9702cc777da4999a618..25352bfa3931e6c88ceba1d4c4ebe149cd681674 100644 --- a/system/bta/include/bta_sdp_api.h +++ b/system/bta/include/bta_sdp_api.h @@ -29,10 +29,9 @@ #include #include -#include "bt_target.h" // Must be first to define build configuration -#include "bta/include/bta_api.h" -#include "bta/include/bta_sdp_api.h" #include "include/hardware/bt_sdp.h" // bluetooth_sdp_record +#include "macros.h" +#include "stack/sdp/sdp_discovery_db.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -45,12 +44,6 @@ typedef enum : uint8_t { BTA_SDP_BUSY = 2, /* Temporarily can not handle this request. */ } tBTA_SDP_STATUS; -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string bta_sdp_status_text(const tBTA_SDP_STATUS& status) { switch (status) { CASE_RETURN_TEXT(BTA_SDP_SUCCESS); @@ -61,8 +54,6 @@ inline std::string bta_sdp_status_text(const tBTA_SDP_STATUS& status) { } } -#undef CASE_RETURN_TEXT - /* SDP I/F callback events */ /* events received by tBTA_SDP_DM_CBACK */ #define BTA_SDP_ENABLE_EVT 0 /* SDP service i/f enabled*/ diff --git a/system/bta/include/bta_sec_api.h b/system/bta/include/bta_sec_api.h new file mode 100644 index 0000000000000000000000000000000000000000..958ecfd5fbe40fb39af59bf4bf7c3a2e67496cb3 --- /dev/null +++ b/system/bta/include/bta_sec_api.h @@ -0,0 +1,495 @@ +/****************************************************************************** + * + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#pragma once + +#include +#include + +#include +#include + +#include "bt_target.h" // Must be first to define build configuration +#include "bta_api_data_types.h" +#include "stack/include/bt_name.h" +#include "stack/include/bt_octets.h" +#include "stack/include/btm_ble_sec_api_types.h" +#include "stack/include/btm_sec_api_types.h" +#include "stack/include/hci_error_code.h" +#include "types/ble_address_with_type.h" +#include "types/bt_transport.h" +#include "types/raw_address.h" + +/* Security Setting Mask */ +#define BTA_SEC_AUTHENTICATE \ + (BTM_SEC_IN_AUTHENTICATE | \ + BTM_SEC_OUT_AUTHENTICATE) /* Authentication required. */ +#define BTA_SEC_ENCRYPT \ + (BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT) /* Encryption required. */ + +typedef uint16_t tBTA_SEC; + +typedef enum : uint8_t { + /* Security Callback Events */ + BTA_DM_PIN_REQ_EVT = 2, /* PIN request. */ + BTA_DM_AUTH_CMPL_EVT = 3, /* Authentication complete indication. */ + BTA_DM_AUTHORIZE_EVT = 4, /* Authorization request. */ + BTA_DM_BOND_CANCEL_CMPL_EVT = 9, /* Bond cancel complete indication */ + BTA_DM_SP_CFM_REQ_EVT = 10, /* Simple Pairing User Confirmation request */ + BTA_DM_SP_KEY_NOTIF_EVT = 11, /* Simple Pairing Passkey Notification */ + BTA_DM_BLE_KEY_EVT = 15, /* BLE SMP key event for peer device keys */ + BTA_DM_BLE_SEC_REQ_EVT = 16, /* BLE SMP security request */ + BTA_DM_BLE_PASSKEY_NOTIF_EVT = 17, /* SMP passkey notification event */ + BTA_DM_BLE_PASSKEY_REQ_EVT = 18, /* SMP passkey request event */ + BTA_DM_BLE_OOB_REQ_EVT = 19, /* SMP OOB request event */ + BTA_DM_BLE_LOCAL_IR_EVT = 20, /* BLE local IR event */ + BTA_DM_BLE_LOCAL_ER_EVT = 21, /* BLE local ER event */ + BTA_DM_BLE_NC_REQ_EVT = 22, /* SMP Numeric Comparison request event */ + BTA_DM_SP_RMT_OOB_EXT_EVT = + 23, /* Simple Pairing Remote OOB Extended Data request. */ + BTA_DM_BLE_AUTH_CMPL_EVT = 24, /* BLE Auth complete */ + BTA_DM_DEV_UNPAIRED_EVT = 25, + BTA_DM_ENER_INFO_READ = 28, /* Energy info read */ + BTA_DM_BLE_SC_OOB_REQ_EVT = 29, /* SMP SC OOB request event */ + BTA_DM_BLE_CONSENT_REQ_EVT = 30, /* SMP consent request event */ + BTA_DM_BLE_SC_CR_LOC_OOB_EVT = 31, /* SMP SC Create Local OOB request event */ + BTA_DM_REPORT_BONDING_EVT = 32, /*handle for pin or key missing*/ + BTA_DM_LE_ADDR_ASSOC_EVT = 33, /* identity address association event */ + BTA_DM_SIRK_VERIFICATION_REQ_EVT = 35, +} tBTA_DM_SEC_EVT; + +/* Structure associated with BTA_DM_PIN_REQ_EVT */ +typedef struct { + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in + * order */ + RawAddress bd_addr; /* BD address peer device. */ + DEV_CLASS dev_class; /* Class of Device */ + BD_NAME bd_name; /* Name of peer device. */ + bool min_16_digit; /* true if the pin returned must be at least 16 digits */ +} tBTA_DM_PIN_REQ; + +/* BLE related definition */ + +#define BTA_DM_AUTH_FAIL_BASE (HCI_ERR_MAX_ERR + 10) + +/* Converts SMP error codes defined in smp_api.h to SMP auth fail reasons below. + */ +#define BTA_DM_AUTH_CONVERT_SMP_CODE(x) (BTA_DM_AUTH_FAIL_BASE + (x)) + +#define BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL \ + (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_AUTH_FAIL) +#define BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL \ + (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_VALUE_ERR) +#define BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT \ + (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_NOT_SUPPORT) +#define BTA_DM_AUTH_SMP_UNKNOWN_ERR \ + (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_FAIL_UNKNOWN) +#define BTA_DM_AUTH_SMP_CONN_TOUT (BTA_DM_AUTH_FAIL_BASE + SMP_CONN_TOUT) + +typedef uint8_t tBTA_LE_KEY_TYPE; /* can be used as a bit mask */ + +typedef union { + tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */ + tBTM_LE_PCSRK_KEYS psrk_key; /* received peer device SRK */ + tBTM_LE_PID_KEYS pid_key; /* peer device ID key */ + tBTM_LE_LENC_KEYS + lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ + tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ + tBTM_LE_PID_KEYS lid_key; /* local device ID key for the particular remote */ +} tBTA_LE_KEY_VALUE; + +#define BTA_BLE_LOCAL_KEY_TYPE_ID 1 +#define BTA_BLE_LOCAL_KEY_TYPE_ER 2 +typedef uint8_t tBTA_DM_BLE_LOCAL_KEY_MASK; + +typedef struct { + Octet16 ir; + Octet16 irk; + Octet16 dhk; +} tBTA_BLE_LOCAL_ID_KEYS; + +#define BTA_DM_SEC_GRANTED BTA_SUCCESS +#define BTA_DM_SEC_PAIR_NOT_SPT BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT +typedef uint8_t tBTA_DM_BLE_SEC_GRANT; + +/* Structure associated with BTA_DM_BLE_SEC_REQ_EVT */ +typedef struct { + RawAddress bd_addr; /* peer address */ + BD_NAME bd_name; /* peer device name */ +} tBTA_DM_BLE_SEC_REQ; + +typedef struct { + RawAddress bd_addr; /* peer address */ + tBTM_LE_KEY_TYPE key_type; + tBTM_LE_KEY_VALUE* p_key_value; +} tBTA_DM_BLE_KEY; + +/* Structure associated with BTA_DM_AUTH_CMPL_EVT */ +typedef struct { + RawAddress bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + bool key_present; /* Valid link key value in key element */ + LinkKey key; /* Link key associated with peer device. */ + uint8_t key_type; /* The type of Link Key */ + bool success; /* true of authentication succeeded, false if failed. */ + tHCI_REASON + fail_reason; /* The HCI reason/error code for when success=false */ + tBLE_ADDR_TYPE addr_type; /* Peer device address type */ + tBT_DEVICE_TYPE dev_type; + bool is_ctkd; /* True if key is derived using CTKD procedure */ +} tBTA_DM_AUTH_CMPL; + +/* Structure associated with BTA_DM_DEV_UNPAIRED_EVT */ +typedef struct { + RawAddress bd_addr; /* BD address peer device. */ + tBT_TRANSPORT transport_link_type; +} tBTA_DM_UNPAIR; + +#define BTA_AUTH_SP_YES \ + BTM_AUTH_SP_YES /* 1 MITM Protection Required - Single Profile/non-bonding \ + Use IO Capabilities to determine authentication procedure \ + */ + +#define BTA_AUTH_DD_BOND \ + BTM_AUTH_DD_BOND /* 2 this bit is set for dedicated bonding */ +#define BTA_AUTH_GEN_BOND \ + BTM_AUTH_SPGB_NO /* 4 this bit is set for general bonding */ +#define BTA_AUTH_BONDS \ + BTM_AUTH_BONDS /* 6 the general/dedicated bonding bits */ + +#define BTA_LE_AUTH_REQ_SC_MITM_BOND BTM_LE_AUTH_REQ_SC_MITM_BOND /* 1101 */ + +/* Structure associated with BTA_DM_SP_CFM_REQ_EVT */ +typedef struct { + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in + * order */ + RawAddress bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ + uint32_t num_val; /* the numeric value for comparison. If just_works, do not + show this number to UI */ + bool just_works; /* true, if "Just Works" association model */ + tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */ + tBTM_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */ + tBTM_IO_CAP loc_io_caps; /* IO Capabilities of local device */ + tBTM_IO_CAP rmt_io_caps; // IO Capabilities of remote device +} tBTA_DM_SP_CFM_REQ; + +/* Structure associated with BTA_DM_SP_KEY_NOTIF_EVT */ +typedef struct { + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in + * order */ + RawAddress bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ + uint32_t passkey; /* the numeric value for comparison. If just_works, do not + show this number to UI */ +} tBTA_DM_SP_KEY_NOTIF; + +/* Structure associated with BTA_DM_SP_RMT_OOB_EVT */ +typedef struct { + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in + * order */ + RawAddress bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ +} tBTA_DM_SP_RMT_OOB; + +/* Structure associated with BTA_DM_BOND_CANCEL_CMPL_EVT */ +typedef struct { + tBTA_STATUS result; /* true of bond cancel succeeded, false if failed. */ +} tBTA_DM_BOND_CANCEL_CMPL; + +/* Add to remove bond of key missing RC */ +typedef struct { + RawAddress bd_addr; +} tBTA_DM_RC_UNPAIR; + +typedef struct { + Octet16 local_oob_c; /* Local OOB Data Confirmation/Commitment */ + Octet16 local_oob_r; /* Local OOB Data Randomizer */ +} tBTA_DM_LOC_OOB_DATA; + +/* Union of all security callback structures */ +typedef union { + tBTA_DM_PIN_REQ pin_req; /* PIN request. */ + tBTA_DM_AUTH_CMPL auth_cmpl; /* Authentication complete indication. */ + tBTA_DM_UNPAIR dev_unpair; /* Remove bonding complete indication */ + tBTA_DM_SP_CFM_REQ cfm_req; /* user confirm request */ + tBTA_DM_SP_KEY_NOTIF key_notif; /* passkey notification */ + tBTA_DM_SP_RMT_OOB rmt_oob; /* remote oob */ + tBTA_DM_BOND_CANCEL_CMPL + bond_cancel_cmpl; /* Bond Cancel Complete indication */ + tBTA_DM_BLE_SEC_REQ ble_req; /* BLE SMP related request */ + tBTA_DM_BLE_KEY ble_key; /* BLE SMP keys used when pairing */ + tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */ + Octet16 ble_er; /* ER event data */ + tBTA_DM_LOC_OOB_DATA local_oob_data; /* Local OOB data generated by us */ + tBTA_DM_RC_UNPAIR delete_key_RC_to_unpair; + tBTA_DM_PROC_ID_ADDR proc_id_addr; /* Identity address event */ +} tBTA_DM_SEC; + +/* Security callback */ +typedef void(tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data); + +/* Encryption callback*/ +typedef void(tBTA_DM_ENCRYPT_CBACK)(const RawAddress& bd_addr, + tBT_TRANSPORT transport, + tBTA_STATUS result); + +/******************************************************************************* + * + * Function BTA_DmBond + * + * Description This function initiates a bonding procedure with a peer + * device by designated transport. The bonding procedure + * enables authentication and optionally encryption on the + * Bluetooth link. + * + * + * Returns void + * + ******************************************************************************/ +void BTA_DmBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type); + +/******************************************************************************* + * + * Function BTA_DmBondCancel + * + * Description This function cancels a bonding procedure with a peer + * device. + * + * + * Returns void + * + ******************************************************************************/ +void BTA_DmBondCancel(const RawAddress& bd_addr); + +/******************************************************************************* + * + * Function BTA_DmPinReply + * + * Description This function provides a PIN when one is requested by DM + * during a bonding procedure. The application should call + * this function after the security callback is called with + * a BTA_DM_PIN_REQ_EVT. + * + * + * Returns void + * + ******************************************************************************/ +void BTA_DmPinReply(const RawAddress& bd_addr, bool accept, uint8_t pin_len, + uint8_t* p_pin); + +/******************************************************************************* + * + * Function BTA_DmLocalOob + * + * Description This function retrieves the OOB data from local controller. + * The result is reported by bta_dm_co_loc_oob(). + * + * Returns void + * + ******************************************************************************/ +void BTA_DmLocalOob(void); + +/******************************************************************************* + * + * Function BTA_DmConfirm + * + * Description This function accepts or rejects the numerical value of the + * Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT + * + * Returns void + * + ******************************************************************************/ +void BTA_DmConfirm(const RawAddress& bd_addr, bool accept); + +/******************************************************************************* + * + * Function BTA_DmAddDevice + * + * Description This function adds a device to the security database list + * of peer devices. This function would typically be called + * at system startup to initialize the security database with + * known peer devices. This is a direct execution function + * that may lock task scheduling on some platforms. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, + const LinkKey& link_key, uint8_t key_type, + uint8_t pin_length); + +/******************************************************************************* + * + * Function BTA_DmRemoveDevice + * + * Description This function removes a device from the security database. + * This is a direct execution function that may lock task + * scheduling on some platforms. + * + * + * Returns BTA_SUCCESS if successful. + * BTA_FAIL if operation failed. + * + ******************************************************************************/ +tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr); + + +/* BLE related API functions */ +/******************************************************************************* + * + * Function BTA_DmBleSecurityGrant + * + * Description Grant security request access. + * + * Parameters: bd_addr - BD address of the peer + * res - security grant status. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmBleSecurityGrant(const RawAddress& bd_addr, + tBTA_DM_BLE_SEC_GRANT res); + +/******************************************************************************* + * + * Function BTA_DmBlePasskeyReply + * + * Description Send BLE SMP passkey reply. + * + * Parameters: bd_addr - BD address of the peer + * accept - passkey entry successful or declined. + * passkey - passkey value, must be a 6 digit number, + * can be lead by 0. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmBlePasskeyReply(const RawAddress& bd_addr, bool accept, + uint32_t passkey); + +/******************************************************************************* + * + * Function BTA_DmBleConfirmReply + * + * Description Send BLE SMP SC user confirmation reply. + * + * Parameters: bd_addr - BD address of the peer + * accept - numbers to compare are the same or + * different. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmBleConfirmReply(const RawAddress& bd_addr, bool accept); + +/******************************************************************************* + * + * Function BTA_DmAddBleDevice + * + * Description Add a BLE device. This function will be normally called + * during host startup to restore all required information + * for a LE device stored in the NVRAM. + * + * Parameters: bd_addr - BD address of the peer + * dev_type - Remote device's device type. + * addr_type - LE device address type. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmAddBleDevice(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_DEVICE_TYPE dev_type); + +/******************************************************************************* + * + * Function BTA_DmAddBleKey + * + * Description Add/modify LE device information. This function will be + * normally called during host startup to restore all required + * information stored in the NVRAM. + * + * Parameters: bd_addr - BD address of the peer + * p_le_key - LE key values. + * key_type - LE SMP key type. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmAddBleKey(const RawAddress& bd_addr, tBTA_LE_KEY_VALUE* p_le_key, + tBTM_LE_KEY_TYPE key_type); + +/******************************************************************************* + * + * Function BTA_DmSetEncryption + * + * Description This function is called to ensure that connection is + * encrypted. Should be called only on an open connection. + * Typically only needed for connections that first want to + * bring up unencrypted links, then later encrypt them. + * + * Parameters: bd_addr - Address of the peer device + * transport - transport of the link to be encruypted + * p_callback - Pointer to callback function to indicat the + * link encryption status + * sec_act - This is the security action to indicate + * what kind of BLE security level is required + * for the BLE link if BLE is supported + * Note: This parameter is ignored for + * BR/EDR or if BLE is not supported. + * + * Returns void + * + * + ******************************************************************************/ +void BTA_DmSetEncryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, + tBTA_DM_ENCRYPT_CBACK* p_callback, + tBTM_BLE_SEC_ACT sec_act); + +/******************************************************************************* + * + * Function BTA_DmSirkSecCbRegister + * + * Description This procedure registeres in requested a callback for + * verification by CSIS potential set member. + * + * Parameters p_cback - callback to member verificator + * + * Returns void + * + ******************************************************************************/ +void BTA_DmSirkSecCbRegister(tBTA_DM_SEC_CBACK* p_cback); + +/******************************************************************************* + * + * Function BTA_DmSirkConfirmDeviceReply + * + * Description This procedure confirms requested to validate set device. + * + * Parameters bd_addr - BD address of the peer + * accept - True if device is authorized by CSIS, false + * otherwise. + * + * Returns void + * + ******************************************************************************/ +void BTA_DmSirkConfirmDeviceReply(const RawAddress& bd_addr, bool accept); diff --git a/system/bta/include/bta_vc_api.h b/system/bta/include/bta_vc_api.h index 3b2db1b4ff18fadf28e651481d01cdf1e179aea9..55046a6791f8d9bf46969e1dce8a6e68c4af1414 100644 --- a/system/bta/include/bta_vc_api.h +++ b/system/bta/include/bta_vc_api.h @@ -25,18 +25,20 @@ class VolumeControl { public: virtual ~VolumeControl() = default; - static void Initialize(bluetooth::vc::VolumeControlCallbacks* callbacks); + static void Initialize(bluetooth::vc::VolumeControlCallbacks* callbacks, + const base::Closure& initCb); static void CleanUp(); static VolumeControl* Get(); static void DebugDump(int fd); - static void AddFromStorage(const RawAddress& address, bool auto_connect); + static void AddFromStorage(const RawAddress& address); static bool IsVolumeControlRunning(); /* Volume Control Server (VCS) */ virtual void Connect(const RawAddress& address) = 0; virtual void Disconnect(const RawAddress& address) = 0; + virtual void Remove(const RawAddress& address) = 0; virtual void SetVolume(std::variant addr_or_group_id, uint8_t volume) = 0; virtual void Mute(std::variant addr_or_group_id) = 0; diff --git a/system/bta/jv/bta_jv_act.cc b/system/bta/jv/bta_jv_act.cc index d8d593dabd8e88d539f2baaccf369b078d1c0d0e..0f7748526081b83c30055d9700f5136a8ac6b68c 100644 --- a/system/bta/jv/bta_jv_act.cc +++ b/system/bta/jv/bta_jv_act.cc @@ -29,15 +29,22 @@ #include #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/include/bta_jv_co.h" +#include "bta/include/bta_rfcomm_scn.h" #include "bta/jv/bta_jv_int.h" #include "bta/sys/bta_sys.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" #include "osi/include/allocator.h" +#include "osi/include/osi.h" // UNUSED_ATTR +#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" +#include "stack/include/bt_uuid16.h" #include "stack/include/gap_api.h" #include "stack/include/l2cdefs.h" #include "stack/include/port_api.h" @@ -45,7 +52,7 @@ #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -using bluetooth::Uuid; +using namespace bluetooth::legacy::stack::sdp; tBTA_JV_CB bta_jv_cb; std::unordered_set used_l2cap_classic_dynamic_psm; @@ -633,6 +640,8 @@ void bta_jv_enable(tBTA_JV_DM_CBACK* p_cback) { bta_jv.status = status; bta_jv_cb.p_dm_cback(BTA_JV_ENABLE_EVT, &bta_jv, 0); memset(bta_jv_cb.free_psm_list, 0, sizeof(bta_jv_cb.free_psm_list)); + memset(bta_jv_cb.scn_in_use, 0, sizeof(bta_jv_cb.scn_in_use)); + bta_jv_cb.scn_search_index = 1; } /** Disables the BT device manager free the resources used by java */ @@ -714,22 +723,17 @@ void bta_jv_get_channel_id( case BTA_JV_CONN_TYPE_RFCOMM: { uint8_t scn = 0; if (channel > 0) { - if (!BTM_TryAllocateSCN(channel)) { - LOG(ERROR) << "rfc channel=" << channel - << " already in use or invalid"; - channel = 0; + if (BTA_TryAllocateSCN(channel)) { + scn = static_cast(channel); + } else { + LOG_ERROR("rfc channel %u already in use or invalid", channel); } } else { - channel = BTM_AllocateSCN(); - if (channel == 0) { - LOG(ERROR) << "run out of rfc channels"; - channel = 0; + scn = BTA_AllocateSCN(); + if (scn == 0) { + LOG_ERROR("out of rfc channels"); } } - if (channel != 0) { - bta_jv_cb.scn[channel - 1] = true; - scn = (uint8_t)channel; - } if (bta_jv_cb.p_dm_cback) { tBTA_JV bta_jv; bta_jv.scn = scn; @@ -765,14 +769,9 @@ void bta_jv_get_channel_id( void bta_jv_free_scn(int32_t type /* One of BTA_JV_CONN_TYPE_ */, uint16_t scn) { switch (type) { - case BTA_JV_CONN_TYPE_RFCOMM: { - if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn - 1]) { - /* this scn is used by JV */ - bta_jv_cb.scn[scn - 1] = false; - BTM_FreeSCN(scn); - } + case BTA_JV_CONN_TYPE_RFCOMM: + BTA_FreeSCN(scn); break; - } case BTA_JV_CONN_TYPE_L2CAP: bta_jv_set_free_psm(scn); break; @@ -794,7 +793,8 @@ void bta_jv_free_scn(int32_t type /* One of BTA_JV_CONN_TYPE_ */, * Returns void * ******************************************************************************/ -static void bta_jv_start_discovery_cback(tSDP_RESULT result, +static void bta_jv_start_discovery_cback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_RESULT result, const void* user_data) { tBTA_JV_STATUS status; uint32_t* p_rfcomm_slot_id = @@ -811,11 +811,12 @@ static void bta_jv_start_discovery_cback(tSDP_RESULT result, tSDP_DISC_REC* p_sdp_rec = NULL; tSDP_PROTOCOL_ELEM pe; VLOG(2) << __func__ << ": bta_jv_cb.uuid=" << bta_jv_cb.uuid; - p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, - bta_jv_cb.uuid, p_sdp_rec); + p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceUUIDInDb( + p_bta_jv_cfg->p_sdp_db, bta_jv_cb.uuid, p_sdp_rec); VLOG(2) << __func__ << ": p_sdp_rec=" << p_sdp_rec; if (p_sdp_rec && - SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) { dcomp.scn = (uint8_t)pe.params[0]; status = BTA_JV_SUCCESS; } @@ -848,8 +849,9 @@ void bta_jv_start_discovery(const RawAddress& bd_addr, uint16_t num_uuid, /* init the database/set up the filter */ VLOG(2) << __func__ << ": call SDP_InitDiscoveryDb, num_uuid=" << num_uuid; - SDP_InitDiscoveryDb(p_bta_jv_cfg->p_sdp_db, p_bta_jv_cfg->sdp_db_size, - num_uuid, uuid_list, 0, NULL); + get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + p_bta_jv_cfg->p_sdp_db, p_bta_jv_cfg->sdp_db_size, num_uuid, uuid_list, 0, + NULL); /* tell SDP to keep the raw data */ p_bta_jv_cfg->p_sdp_db->raw_data = p_bta_jv_cfg->p_sdp_raw_data; @@ -863,9 +865,9 @@ void bta_jv_start_discovery(const RawAddress& bd_addr, uint16_t num_uuid, uint32_t* rfcomm_slot_id_copy = (uint32_t*)osi_malloc(sizeof(uint32_t)); *rfcomm_slot_id_copy = rfcomm_slot_id; - if (!SDP_ServiceSearchAttributeRequest2(bd_addr, p_bta_jv_cfg->p_sdp_db, - bta_jv_start_discovery_cback, - (void*)rfcomm_slot_id_copy)) { + if (!get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest2( + bd_addr, p_bta_jv_cfg->p_sdp_db, bta_jv_start_discovery_cback, + (void*)rfcomm_slot_id_copy)) { bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE; /* failed to start SDP. report the failure right away */ if (bta_jv_cb.p_dm_cback) { @@ -895,7 +897,7 @@ void bta_jv_create_record(uint32_t rfcomm_slot_id) { void bta_jv_delete_record(uint32_t handle) { if (handle) { /* this is a record created by btif layer*/ - SDP_DeleteRecord(handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(handle); } } @@ -1255,6 +1257,11 @@ static int bta_jv_port_data_co_cback(uint16_t port_handle, uint8_t* buf, if (p_pcb != NULL) { switch (type) { case DATA_CO_CALLBACK_TYPE_INCOMING: + // Exit sniff mode when receiving data by sysproxy + if (osi_property_get_bool("bluetooth.rfcomm.sysproxy.rx.exit_sniff", + false)) { + bta_jv_pm_conn_busy(p_pcb->p_pm_cb); + } return bta_co_rfc_data_incoming(p_pcb->rfcomm_slot_id, (BT_HDR*)buf); case DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE: return bta_co_rfc_data_outgoing_size(p_pcb->rfcomm_slot_id, (int*)buf); @@ -1489,9 +1496,14 @@ static void bta_jv_port_mgmt_sr_cback(uint32_t code, uint16_t port_handle) { evt_data.rfc_srv_open.new_listen_handle = p_pcb_new_listen->handle; p_pcb_new_listen->rfcomm_slot_id = p_cb->p_cback(BTA_JV_RFCOMM_SRV_OPEN_EVT, &evt_data, rfcomm_slot_id); - VLOG(2) << __func__ << ": curr_sess=" << p_cb->curr_sess - << ", max_sess=" << p_cb->max_sess; - failed = false; + if (p_pcb_new_listen->rfcomm_slot_id == 0) { + LOG(ERROR) << __func__ << ": rfcomm_slot_id == " + << p_pcb_new_listen->rfcomm_slot_id; + } else { + VLOG(2) << __func__ << ": curr_sess=" << p_cb->curr_sess + << ", max_sess=" << p_cb->max_sess; + failed = false; + } } else LOG(ERROR) << __func__ << ": failed to create new listen port"; } @@ -1806,9 +1818,9 @@ static void bta_jv_pm_conn_busy(tBTA_JV_PM_CB* p_cb) { /******************************************************************************* * - * Function bta_jv_pm_conn_busy + * Function bta_jv_pm_conn_idle * - * Description set pm connection busy state (input param safe) + * Description set pm connection idle state (input param safe) * * Params p_cb: pm control block of jv connection * diff --git a/system/bta/jv/bta_jv_api.cc b/system/bta/jv/bta_jv_api.cc index 2c1df7a31494f031749bc7df927f1427afc60fcc..4bae932f7e3e0964192d9cf1f5fab89fbcc26635 100644 --- a/system/bta/jv/bta_jv_api.cc +++ b/system/bta/jv/bta_jv_api.cc @@ -32,10 +32,11 @@ #include "bt_target.h" // Must be first to define build configuration #include "bta/jv/bta_jv_int.h" +#include "internal_include/bt_trace.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" // do_in_main_thread #include "stack/include/gap_api.h" +#include "stack/include/main_thread.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" diff --git a/system/bta/jv/bta_jv_int.h b/system/bta/jv/bta_jv_int.h index 476baf5f37f901baada1a1baef1d7249cdf355ae..d8a5061397ae55f2c36241bb9d80c1beeea814e9 100644 --- a/system/bta/jv/bta_jv_int.h +++ b/system/bta/jv/bta_jv_int.h @@ -28,6 +28,8 @@ #include #include "bta/include/bta_jv_api.h" +#include "bta/include/bta_sec_api.h" +#include "internal_include/bt_target.h" #include "stack/include/bt_hdr.h" #include "stack/include/rfcdefs.h" #include "types/bluetooth/uuid.h" @@ -120,9 +122,11 @@ typedef struct { tBTA_JV_PCB port_cb[MAX_RFC_PORTS]; /* index of this array is the port_handle, */ uint8_t sec_id[BTA_JV_NUM_SERVICE_ID]; /* service ID */ - bool scn[BTA_JV_MAX_SCN]; /* SCN allocated by java */ uint16_t free_psm_list[BTA_JV_MAX_L2C_CONN]; /* PSMs freed by java (can be reused) */ + bool scn_in_use[RFCOMM_MAX_SCN]; + uint8_t scn_search_index; /* used to search for free scns */ + uint8_t sdp_active; /* see BTA_JV_SDP_ACT_* */ bluetooth::Uuid uuid; /* current uuid of sdp discovery*/ tBTA_JV_PM_CB pm_cb[BTA_JV_PM_MAX_NUM]; /* PM on a per JV handle bases */ diff --git a/system/bta/le_audio/OWNERS b/system/bta/le_audio/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..a7d77894ba202f88cd38f1c942915fe274e14369 --- /dev/null +++ b/system/bta/le_audio/OWNERS @@ -0,0 +1 @@ +include /OWNERS_leaudio diff --git a/system/tools/hci/Android.mk.disabled b/system/bta/le_audio/audio_hal_client/asrc_butter.py old mode 100644 new mode 100755 similarity index 50% rename from system/tools/hci/Android.mk.disabled rename to system/bta/le_audio/audio_hal_client/asrc_butter.py index 9244f45a9d8c03015bb389852556434d261ebf42..ebf89de4c667f7a445a32e6d9cfc58961f21b1b7 --- a/system/tools/hci/Android.mk.disabled +++ b/system/bta/le_audio/audio_hal_client/asrc_butter.py @@ -1,11 +1,12 @@ +#!/usr/bin/env python3 # -# Copyright 2014 The Android Open Source Project +# Copyright 2023 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,20 +15,9 @@ # limitations under the License. # -LOCAL_PATH := $(call my-dir) +import numpy as np +import scipy.signal as signal -# Bluetooth HCI tools for target -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := net_hci - -LOCAL_SRC_FILES := main.c -LOCAL_STATIC_LIBRARIES := libosi -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../ - -LOCAL_CFLAGS += $(bluetooth_CFLAGS) -LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS) -LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS) - -include $(BUILD_EXECUTABLE) +b, a = signal.butter(2, 1. / 60) +print(('a:' + ' {:17.10e}' * 2).format(*a[1:])) +print(('b:' + ' {:17.10e}' * 3).format(*b)) diff --git a/system/bta/le_audio/audio_hal_client/asrc_resampler_test.cc b/system/bta/le_audio/audio_hal_client/asrc_resampler_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..72af3e3b3e047db33eb42fc75e008190d4ffaca9 --- /dev/null +++ b/system/bta/le_audio/audio_hal_client/asrc_resampler_test.cc @@ -0,0 +1,80 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "audio_source_hal_asrc.cc" + +namespace bluetooth::hal { +void NocpIsoClocker::Register(NocpIsoHandler*) {} +void NocpIsoClocker::Unregister() {} +} // namespace bluetooth::hal + +namespace le_audio { + +class SourceAudioHalAsrcTest : public SourceAudioHalAsrc { + public: + SourceAudioHalAsrcTest(int channels, int bitdepth) + : SourceAudioHalAsrc(channels, 48000, bitdepth, 10000) {} + + template + void Resample(double ratio, const T* in, size_t in_length, size_t* in_count, + T* out, size_t out_length, size_t* out_count) { + auto resamplers = *resamplers_; + auto channels = resamplers.size(); + unsigned sub_q26; + + for (auto& r : resamplers) + r.Resample(round(ldexp(ratio, 26)), in, channels, in_length / channels, + in_count, out, channels, out_length / channels, out_count, + &sub_q26); + } +}; + +extern "C" void resample_i16(int channels, int bitdepth, double ratio, + const int16_t* in, size_t in_length, int16_t* out, + size_t out_length) { + size_t in_count, out_count; + + SourceAudioHalAsrcTest(channels, bitdepth) + .Resample(ratio, in, in_length, &in_count, out, out_length, + &out_count); + + if (out_count < out_length) + fprintf(stderr, "wrong output size: %zd:%zd %zd:%zd\n", in_length, in_count, + out_length, out_count); + + return; +} + +extern "C" void resample_i32(int channels, int bitdepth, double ratio, + const int32_t* in, size_t in_length, int32_t* out, + size_t out_length) { + size_t in_count, out_count; + + SourceAudioHalAsrcTest(channels, bitdepth) + .Resample(ratio, in, in_length, &in_count, out, out_length, + &out_count); + + if (out_count < out_length) + fprintf(stderr, "wrong output size: %zd:%zd %zd:%zd\n", in_length, in_count, + out_length, out_count); + + return; +} + +} // namespace le_audio diff --git a/system/bta/le_audio/audio_hal_client/asrc_resampler_test.config b/system/bta/le_audio/audio_hal_client/asrc_resampler_test.config new file mode 100644 index 0000000000000000000000000000000000000000..504efe6ad7ea01544aa43481ab4830b7a11eb5ff --- /dev/null +++ b/system/bta/le_audio/audio_hal_client/asrc_resampler_test.config @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/system/bta/le_audio/audio_hal_client/asrc_resampler_test.py b/system/bta/le_audio/audio_hal_client/asrc_resampler_test.py new file mode 100755 index 0000000000000000000000000000000000000000..633c9afe2aceb7fa4f0a0047b6ec9ac8d7535dad --- /dev/null +++ b/system/bta/le_audio/audio_hal_client/asrc_resampler_test.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import ctypes +import numpy as np +from scipy import signal +from mobly import test_runner, base_test +from mobly.asserts import assert_greater +import sys +import os + + +class CResampler: + + def __init__(self, lib, channels, bitdepth): + + self.lib = lib + self.channels = channels + self.bitdepth = bitdepth + + def resample(self, xs, ratio): + + c_int = ctypes.c_int + c_size_t = ctypes.c_size_t + c_double = ctypes.c_double + c_int16_p = ctypes.POINTER(ctypes.c_int16) + c_int32_p = ctypes.POINTER(ctypes.c_int32) + + channels = self.channels + bitdepth = self.bitdepth + + xs_min = -(2**(bitdepth - 1)) + xs_max = (2**(bitdepth - 1) - 1) + xs_int = np.rint(np.clip(np.ldexp(xs, bitdepth-1), xs_min, xs_max)).\ + astype([np.int16, np.int32][bitdepth > 16], 'C') + + ys_int = np.empty(int(np.ceil(len(xs) / ratio)), dtype=xs_int.dtype) + + if bitdepth <= 16: + lib.resample_i16(c_int(channels), c_int(bitdepth), c_double(ratio), xs_int.ctypes.data_as(c_int16_p), + c_size_t(len(xs_int)), ys_int.ctypes.data_as(c_int16_p), c_size_t(len(ys_int))) + else: + lib.resample_i32(c_int(channels), c_int(bitdepth), c_double(ratio), xs_int.ctypes.data_as(c_int32_p), + c_size_t(len(xs_int)), ys_int.ctypes.data_as(c_int32_p), c_size_t(len(ys_int))) + + return np.ldexp(ys_int, 1 - bitdepth) + + +FS = 48e3 + + +def snr(x, fs=FS): + + f, p = signal.periodogram(x, fs=fs, scaling='spectrum', window=('kaiser', 38)) + + k = np.argmax(p) + s = np.sum(p[k - 19:k + 20]) + n = np.sum(p[20:k - 19]) + np.sum(p[k + 20:]) + + return 10 * np.log10(s / n) + + +def mean_snr(resampler, ratio): + N = 8192 + xt = np.arange(2 * N + 128) / FS + + frequencies = [] + values = [] + + for f in range(200, 20000, 99): + xs = np.sin(2 * np.pi * xt * f) + + frequencies += [f] + result = resampler.resample(xs, ratio) + values += [snr(result[128:128 + N])] + + k = np.argmin(np.abs(np.array(frequencies) - 18e3)) + return np.mean(values[:k]) + + +root = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) +lib = ctypes.cdll.LoadLibrary(os.path.join(root, "libasrc_resampler_test.so")) + +cresampler_16 = CResampler(lib, 1, 16) +cresampler_24 = CResampler(lib, 1, 24) + + +class SnrTest(base_test.BaseTestClass): + + def test_16bit_48000_to_44100(self): + assert_greater(mean_snr(cresampler_16, 44.1 / 48.0), 94) + + def test_16bit_44100_to_48000(self): + assert_greater(mean_snr(cresampler_16, 48.0 / 44.1), 94) + + def test_24bit_48000_to_44100(self): + assert_greater(mean_snr(cresampler_24, 44.1 / 48.0), 114) + + def test_24bit_44100_to_48000(self): + assert_greater(mean_snr(cresampler_24, 48.0 / 44.1), 114) + + +if __name__ == '__main__': + index = sys.argv.index('--') + sys.argv = sys.argv[:1] + sys.argv[index + 1:] + test_runner.main() diff --git a/system/bta/le_audio/audio_hal_client/asrc_tables.cc b/system/bta/le_audio/audio_hal_client/asrc_tables.cc new file mode 100644 index 0000000000000000000000000000000000000000..06eb501edc0e9d78ddf6496cf9feb356fbff863e --- /dev/null +++ b/system/bta/le_audio/audio_hal_client/asrc_tables.cc @@ -0,0 +1,3622 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file is auto-generated using "./asrc_tables.py". DO NOT EDIT. */ + +#include "asrc_tables.h" + +namespace le_audio::asrc { + +// clang-format off +const ResamplerTables resampler_tables = { + + .h = { + + { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2147483647, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 }, + { -140, 688, -2315, 6266, -14637, 30640, -58875, 105625, + -179317, 291594, -460083, 716145, -1129337, 1906742, -4088753, 2147469981, + 4105509, -1911174, 1131440, -717386, 460885, -292128, 179671, -105854, + 59017, -30723, 14682, -6289, 2325, -692, 141 }, + { -278, 1373, -4620, 12510, -29227, 61195, -117607, 211017, + -358273, 582643, -919347, 1431024, -2256533, 3808993, -8160693, 2147428980, + 8227714, -3826721, 2264944, -1435988, 922556, -584781, 359691, -211933, + 118175, -61527, 29408, -12599, 4659, -1387, 282 }, + { -415, 2054, -6915, 18731, -43772, 91666, -176193, 316172, + -536862, 873137, -1377777, 2144612, -3381548, 5706692, -12215763, 2147360646, + 12366558, -5746580, 3400474, -2155779, 1384996, -877947, 540052, -318234, + 177470, -92413, 44179, -18932, 7003, -2087, 425 }, + { -552, 2731, -9200, 24928, -58270, 122050, -234630, 421087, + -715077, 1163066, -1835356, 2856883, -4504345, 7599782, -16253904, 2147264981, + 16521980, -7670691, 4537989, -2876736, 1848189, -1171616, 720749, -424753, + 236900, -123378, 58993, -25287, 9357, -2789, 568 }, + { -687, 3404, -11474, 31103, -72722, 152348, -292918, 525759, + -892913, 1452419, -2292067, 3567813, -5624884, 9488202, -20275062, 2147141986, + 20693920, -9598992, 5677450, -3598831, 2312118, -1465777, 901775, -531486, + 296465, -154422, 73850, -31663, 11721, -3496, 713 }, + { -821, 4074, -13739, 37255, -87126, 182557, -351055, 630184, + -1070363, 1741187, -2747896, 4277377, -6743128, 11371896, -24279180, 2146991666, + 24882319, -11531423, 6818819, -4322040, 2776767, -1760421, 1083123, -638430, + 356161, -185544, 88751, -38061, 14094, -4206, 859 }, + { -955, 4740, -15994, 43382, -101482, 212677, -409037, 734357, + -1247421, 2029359, -3202825, 4985550, -7859040, 13250804, -28266203, 2146814023, + 29087114, -13467923, 7962054, -5046336, 3242118, -2055537, 1264788, -745580, + 415987, -216743, 103693, -44480, 16477, -4919, 1006 }, + { -1087, 5402, -18238, 49487, -115789, 242708, -466864, 838276, + -1424081, 2316925, -3656839, 5692308, -8972580, 15124869, -32236076, 2146609061, + 33308246, -15408430, 9107118, -5771694, 3708156, -2351113, 1446762, -852934, + 475941, -248018, 118678, -50920, 18869, -5637, 1154 }, + { -1218, 6060, -20472, 55567, -130048, 272648, -524533, 941938, + -1600337, 2603875, -4109922, 6397625, -10083711, 16994033, -36188744, 2146376785, + 37545650, -17352882, 10253969, -6498088, 4174863, -2647140, 1629040, -960486, + 536020, -279367, 133704, -57381, 21270, -6357, 1302 }, + { -1348, 6715, -22695, 61623, -144258, 302495, -582042, 1045337, + -1776183, 2890199, -4562058, 7101477, -11192397, 18858239, -40124154, 2146117201, + 41799266, -19301218, 11402568, -7225491, 4642223, -2943606, 1811614, -1068235, + 596223, -310790, 148770, -63863, 23680, -7081, 1452 }, + { -1477, 7366, -24908, 67656, -158418, 332250, -639390, 1148472, + -1951612, 3175887, -5013231, 7803841, -12298598, 20717430, -44042253, 2145830315, + 46069030, -21253374, 12552874, -7953879, 5110218, -3240501, 1994478, -1176174, + 656546, -342285, 163877, -70365, 26100, -7809, 1603 }, + { -1605, 8013, -27111, 73663, -172528, 361911, -696575, 1251338, + -2126618, 3460929, -5463425, 8504691, -13402279, 22571549, -47942988, 2145516133, + 50354879, -23209287, 13704847, -8683223, 5578832, -3537815, 2177625, -1284301, + 716989, -373852, 179024, -76887, 28529, -8540, 1755 }, + { -1732, 8656, -29303, 79647, -186587, 391477, -753595, 1353933, + -2301196, 3745316, -5912626, 9204003, -14503403, 24420541, -51826306, 2145174663, + 54656748, -25168896, 14858447, -9413499, 6048048, -3835536, 2361049, -1392612, + 777549, -405490, 194210, -83429, 30967, -9275, 1908 }, + { -1858, 9295, -31484, 85605, -200596, 420948, -810447, 1456252, + -2475340, 4029037, -6360817, 9901754, -15601931, 26264348, -55692156, 2144805912, + 58974573, -27132137, 16013633, -10144680, 6517848, -4133653, 2544744, -1501103, + 838224, -437196, 209435, -89992, 33414, -10013, 2062 }, + { -1982, 9931, -33655, 91539, -214553, 450322, -867130, 1558292, + -2649044, 4312082, -6807983, 10597920, -16697829, 28102916, -59540487, 2144409890, + 63308290, -29098946, 17170364, -10876739, 6988216, -4432156, 2728702, -1609770, + 899012, -468971, 224698, -96573, 35870, -10755, 2217 }, + { -2106, 10562, -35815, 97448, -228458, 479598, -923643, 1660049, + -2822301, 4594443, -7254108, 11292475, -17791058, 29936188, -63371247, 2143986605, + 67657832, -31069260, 18328599, -11609650, 7459134, -4731034, 2912917, -1718609, + 959910, -500813, 239999, -103175, 38335, -11500, 2373 }, + { -2229, 11190, -37964, 103331, -242311, 508776, -979983, 1761522, + -2995106, 4876108, -7699177, 11985398, -18881583, 31764111, -67184388, 2143536068, + 72023133, -33043014, 19488299, -12343387, 7930585, -5030275, 3097382, -1827617, + 1020916, -532720, 255338, -109795, 40808, -12248, 2530 }, + { -2351, 11814, -40102, 109189, -256112, 537855, -1036148, 1862705, + -3167453, 5157070, -8143174, 12676663, -19969368, 33586628, -70979859, 2143058289, + 76404128, -35020145, 20649420, -13077922, 8402552, -5329870, 3282090, -1936788, + 1082029, -564693, 270713, -116435, 43291, -13000, 2689 }, + { -2471, 12434, -42230, 115022, -269860, 566833, -1092138, 1963595, + -3339336, 5437317, -8586085, 13366248, -21054376, 35403685, -74757612, 2142553278, + 80800749, -37000587, 21811922, -13813229, 8875018, -5629806, 3467036, -2046120, + 1143246, -596729, 286124, -123093, 45782, -13756, 2848 }, + { -2591, 13050, -44347, 120829, -283554, 595710, -1147949, 2064190, + -3510749, 5716840, -9027895, 14054129, -22136572, 37215229, -78517597, 2142021049, + 85212929, -38984277, 22975765, -14549281, 9347964, -5930074, 3652211, -2155609, + 1204565, -628828, 301571, -129770, 48281, -14514, 3008 }, + { -2709, 13662, -46452, 126610, -297194, 624485, -1203580, 2164486, + -3681687, 5995631, -9468587, 14740283, -23215919, 39021205, -82259766, 2141461613, + 89640600, -40971148, 24140905, -15286052, 9821375, -6230661, 3837609, -2265249, + 1265984, -660989, 317053, -136465, 50789, -15276, 3169 }, + { -2827, 14271, -48547, 132365, -310780, 653157, -1259029, 2264479, + -3852144, 6273678, -9908147, 15424686, -24292383, 40821559, -85984073, 2140874983, + 94083693, -42961136, 25307302, -16023513, 10295232, -6531557, 4023224, -2375038, + 1327500, -693210, 332570, -143178, 53306, -16041, 3331 }, + { -2943, 14875, -50631, 138094, -324312, 681726, -1314295, 2364167, + -4022114, 6550974, -10346561, 16107315, -25365928, 42616239, -89690470, 2140261173, + 98542140, -44954175, 26474914, -16761639, 10769517, -6832750, 4209048, -2484972, + 1389111, -725490, 348121, -149910, 55830, -16810, 3494 }, + { -3059, 15476, -52703, 143797, -337789, 710189, -1369376, 2463546, + -4191591, 6827508, -10783812, 16788147, -26436519, 44405192, -93378911, 2139620197, + 103015870, -46950199, 27643699, -17500402, 11244214, -7134230, 4395074, -2595046, + 1450816, -757828, 363706, -156659, 58363, -17582, 3659 }, + { -3173, 16072, -54765, 149473, -351210, 738547, -1424270, 2562612, + -4360570, 7103271, -11219887, 17467159, -27504121, 46188364, -97049350, 2138952071, + 107504815, -48949143, 28813615, -18239775, 11719304, -7435986, 4581297, -2705256, + 1512611, -790223, 379324, -163425, 60905, -18357, 3824 }, + { -3286, 16665, -56815, 155123, -364576, 766798, -1478975, 2661363, + -4529046, 7378255, -11654771, 18144329, -28568698, 47965704, -100701741, 2138256809, + 112008904, -50950939, 29984619, -18979731, 12194771, -7738005, 4767708, -2815598, + 1574494, -822674, 394974, -170209, 63454, -19135, 3990 }, + { -3399, 17253, -58854, 160746, -377885, 794942, -1533489, 2759796, + -4697011, 7652448, -12088448, 18819633, -29630217, 49737160, -104336040, 2137534429, + 116528065, -52955522, 31156670, -19720242, 12670595, -8040277, 4954301, -2926068, + 1636464, -855179, 410656, -177009, 66011, -19916, 4157 }, + { -3510, 17838, -60882, 166343, -391138, 822979, -1587812, 2857907, + -4864462, 7925844, -12520905, 19493049, -30688643, 51502679, -107952202, 2136784946, + 121062229, -54962824, 32329726, -20461281, 13146760, -8342790, 5141069, -3036663, + 1698518, -887738, 426370, -183827, 68576, -20701, 4325 }, + { -3620, 18419, -62899, 171912, -404334, 850906, -1641941, 2955692, + -5031393, 8198432, -12952127, 20164555, -31743941, 53262211, -111550184, 2136008379, + 125611322, -56972778, 33503743, -21202820, 13623248, -8645534, 5328005, -3147377, + 1760654, -920349, 442114, -190661, 71150, -21489, 4495 }, + { -3729, 18995, -64904, 177454, -417473, 878723, -1695874, 3053150, + -5197797, 8470202, -13382098, 20834128, -32796078, 55015705, -115129943, 2135204746, + 130175273, -58985318, 34678680, -21944833, 14100041, -8948497, 5515102, -3258207, + 1822869, -953011, 457889, -197511, 73731, -22280, 4665 }, + { -3837, 19568, -66897, 182969, -430554, 906429, -1749610, 3150276, + -5363670, 8741148, -13810806, 21501746, -33845019, 56763109, -118691435, 2134374064, + 134754009, -61000375, 35854493, -22687291, 14577121, -9251667, 5702353, -3369150, + 1885162, -985723, 473693, -204377, 76319, -23074, 4836 }, + { -3944, 20137, -68880, 188456, -443577, 934024, -1803147, 3247068, + -5529006, 9011258, -14238235, 22167386, -34890731, 58504374, -122234619, 2133516355, + 139347456, -63017882, 37031139, -23430166, 15054471, -9555033, 5889751, -3480199, + 1947529, -1018483, 489527, -211260, 78915, -23871, 5008 }, + { -4050, 20702, -70851, 193916, -456542, 961507, -1856483, 3343523, + -5693799, 9280524, -14664371, 22831027, -35933179, 60239449, -125759453, 2132631636, + 143955541, -65037771, 38208577, -24173432, 15532071, -9858583, 6077289, -3591352, + 2009969, -1051292, 505389, -218158, 81519, -24672, 5181 }, + { -4155, 21262, -72810, 199348, -469448, 988877, -1909617, 3439637, + -5858045, 9548938, -15089201, 23492647, -36972332, 61968284, -129265895, 2131719931, + 148578190, -67059973, 39386762, -24917060, 16009905, -10162307, 6264960, -3702605, + 2072479, -1084146, 521280, -225071, 84130, -25475, 5355 }, + { -4259, 21819, -74758, 204753, -482295, 1016133, -1962548, 3535407, + -6021738, 9816490, -15512709, 24152223, -38008155, 63690831, -132753906, 2130781258, + 153215328, -69084421, 40565652, -25661023, 16487953, -10466193, 6452756, -3813952, + 2135057, -1117046, 537198, -231999, 86749, -26282, 5531 }, + { -4362, 22372, -76694, 210129, -495083, 1043274, -2015273, 3630831, + -6184873, 10083172, -15934883, 24809735, -39040615, 65407040, -136223446, 2129815641, + 157866881, -71111044, 41745204, -26405292, 16966199, -10770229, 6640672, -3925391, + 2197701, -1149989, 553143, -238943, 89375, -27091, 5707 }, + { -4464, 22921, -78619, 215478, -507811, 1070299, -2067791, 3725905, + -6347443, 10348975, -16355707, 25465160, -40069680, 67116863, -139674474, 2128823102, + 162532772, -73139775, 42925374, -27149840, 17444625, -11074403, 6828699, -4036916, + 2260407, -1182975, 569114, -245901, 92008, -27903, 5884 }, + { -4565, 23465, -80531, 220798, -520479, 1097209, -2120100, 3820627, + -6509446, 10613890, -16775169, 26118477, -41095316, 68820250, -143106953, 2127803664, + 167212925, -75170544, 44106118, -27894638, 17923210, -11378705, 7016830, -4148524, + 2323175, -1216003, 585111, -252873, 94648, -28719, 6062 }, + { -4664, 24006, -82433, 226090, -533087, 1124001, -2172199, 3914992, + -6670874, 10877908, -17193253, 26769665, -42117492, 70517154, -146520843, 2126757350, + 171907264, -77203282, 45287394, -28639659, 18401939, -11683122, 7205059, -4260210, + 2386002, -1249071, 601133, -259860, 97295, -29537, 6241 }, + { -4763, 24543, -84322, 231353, -545634, 1150676, -2224087, 4009000, + -6831722, 11141021, -17609948, 27418702, -43136176, 72207528, -149916107, 2125684186, + 176615712, -79237919, 46469156, -29384875, 18880792, -11987643, 7393378, -4371970, + 2448884, -1282178, 617179, -266860, 99950, -30358, 6421 }, + { -4861, 25075, -86200, 236588, -558120, 1177232, -2275761, 4102646, + -6991987, 11403221, -18025238, 28065568, -44151334, 73891323, -153292707, 2124584196, + 181338192, -81274386, 47651363, -30130256, 19359752, -12292256, 7581779, -4483800, + 2511820, -1315322, 633250, -273875, 102611, -31183, 6601 }, + { -4958, 25604, -88066, 241794, -570544, 1203669, -2327220, 4195927, + -7151662, 11664499, -18439111, 28710241, -45162935, 75568493, -156650607, 2123457406, + 186074626, -83312611, 48833970, -30875776, 19838799, -12596950, 7770257, -4595696, + 2574808, -1348503, 649344, -280902, 105278, -32010, 6783 }, + { -5053, 26128, -89920, 246971, -582907, 1229986, -2378463, 4288842, + -7310742, 11924846, -18851553, 29352700, -46170948, 77238990, -159989771, 2122303842, + 190824935, -85352525, 50016933, -31621405, 20317916, -12901713, 7958803, -4707652, + 2637845, -1381720, 665461, -287943, 107953, -32840, 6966 }, + { -5148, 26649, -91762, 252120, -595207, 1256181, -2429488, 4381386, + -7469223, 12184254, -19262550, 29992925, -47175341, 78902770, -163310163, 2121123531, + 195589041, -87394058, 51200207, -32367116, 20797084, -13206533, 8147410, -4819666, + 2700928, -1414970, 681601, -294997, 110634, -33672, 7150 }, + { -5242, 27165, -93592, 257239, -607446, 1282256, -2480293, 4473557, + -7627099, 12442714, -19672089, 30630895, -48176082, 80559784, -166611747, 2119916500, + 200366864, -89437138, 52383750, -33112880, 21276285, -13511399, 8336071, -4931733, + 2764056, -1448254, 697761, -302063, 113321, -34508, 7335 }, + { -5334, 27677, -95411, 262329, -619621, 1308208, -2530878, 4565352, + -7784366, 12700219, -20080158, 31266590, -49173140, 82209988, -169894489, 2118682778, + 205158325, -91481695, 53567516, -33858668, 21755501, -13816298, 8524779, -5043847, + 2827226, -1481569, 713943, -309142, 116015, -35346, 7520 }, + { -5426, 28185, -97217, 267390, -631734, 1334037, -2581240, 4656769, + -7941018, 12956761, -20486742, 31899988, -50166485, 83853337, -173158356, 2117422394, + 209963344, -93527657, 54751461, -34604452, 22234712, -14121219, 8713526, -5156006, + 2890435, -1514914, 730146, -316233, 118716, -36187, 7707 }, + { -5516, 28690, -99012, 272422, -643783, 1359743, -2631378, 4747805, + -8097051, 13212330, -20891829, 32531071, -51156085, 85489784, -176403313, 2116135376, + 214781840, -95574954, 55935542, -35350204, 22713901, -14426151, 8902306, -5268205, + 2953681, -1548288, 746368, -323336, 121422, -37031, 7894 }, + { -5606, 29190, -100794, 277424, -655769, 1385324, -2681291, 4838456, + -8252459, 13466919, -21295405, 33159817, -52141911, 87119286, -179629328, 2114821754, + 219613732, -97623513, 57119713, -36095894, 23193049, -14731080, 9091110, -5380439, + 3016961, -1581690, 762609, -330451, 124134, -37877, 8083 }, + { -5694, 29686, -102564, 282396, -667691, 1410780, -2730977, 4928720, + -8407239, 13720519, -21697458, 33786206, -53123931, 88741798, -182836369, 2113481560, + 224458939, -99673263, 58303930, -36841495, 23672137, -15035996, 9279932, -5492704, + 3080274, -1615118, 778869, -337577, 126853, -38727, 8272 }, + { -5782, 30178, -104323, 287339, -679549, 1436111, -2780435, 5018595, + -8561384, 13973124, -22097975, 34410219, -54102116, 90357277, -186024402, 2112114824, + 229317379, -101724131, 59488148, -37586978, 24151148, -15340887, 9468764, -5604996, + 3143616, -1648572, 795148, -344714, 129578, -39578, 8462 }, + { -5869, 30666, -106069, 292252, -691342, 1461315, -2829663, 5108078, + -8714890, 14224724, -22496943, 35031837, -55076436, 91965677, -189193398, 2110721579, + 234188969, -103776046, 60672322, -38332313, 24630061, -15645741, 9657598, -5717310, + 3206986, -1682049, 811443, -351862, 132308, -40433, 8653 }, + { -5954, 31149, -107803, 297135, -703071, 1486392, -2878660, 5197165, + -8867754, 14475312, -22894349, 35651038, -56046860, 93566957, -192343325, 2109301856, + 239073627, -105828936, 61856409, -39077472, 25108859, -15950545, 9846429, -5829642, + 3270380, -1715549, 827755, -359021, 135044, -41290, 8845 }, + { -6039, 31629, -109525, 301989, -714734, 1511341, -2927425, 5285855, + -9019969, 14724879, -23290181, 36267804, -57013359, 95161072, -195474154, 2107855690, + 243971269, -107882726, 63040362, -39822427, 25587523, -16255288, 10035247, -5941988, + 3333797, -1749070, 844084, -366190, 137786, -42149, 9038 }, + { -6122, 32105, -111235, 306812, -726332, 1536161, -2975956, 5374145, + -9171531, 14973419, -23684427, 36882115, -57975905, 96747981, -198585854, 2106383112, + 248881812, -109937346, 64224137, -40567148, 26066034, -16559958, 10224045, -6054343, + 3397233, -1782612, 860428, -373369, 140533, -43011, 9232 }, + { -6205, 32576, -112932, 311604, -737865, 1560853, -3024251, 5462032, + -9322436, 15220923, -24077073, 37493953, -58934467, 98327641, -201678396, 2104884159, + 253805172, -111992721, 65407689, -41311606, 26544374, -16864544, 10412817, -6166702, + 3460687, -1816172, 876786, -380558, 143285, -43876, 9427 }, + { -6286, 33044, -114618, 316367, -749332, 1585415, -3072310, 5549513, + -9472678, 15467384, -24468108, 38103297, -59889016, 99900010, -204751752, 2103358864, + 258741265, -114048779, 66590973, -42055773, 27022523, -17169032, 10601555, -6279062, + 3524155, -1849749, 893160, -387756, 146043, -44743, 9622 }, + { -6367, 33507, -116291, 321099, -760732, 1609846, -3120132, 5636587, + -9622254, 15712794, -24857519, 38710129, -60839525, 101465046, -207805893, 2101807263, + 263690004, -116105447, 67773944, -42799620, 27500464, -17473411, 10790250, -6391418, + 3587636, -1883343, 909546, -394964, 148807, -45612, 9819 }, + { -6446, 33966, -117952, 325801, -772067, 1634146, -3167714, 5723250, + -9771159, 15957145, -25245294, 39314430, -61785964, 103022708, -210840793, 2100229392, + 268651306, -118162649, 68956555, -43543117, 27978177, -17777669, 10978897, -6503765, + 3651127, -1916952, 925946, -402180, 151575, -46484, 10016 }, + { -6525, 34421, -119600, 330472, -783334, 1658315, -3215055, 5809500, + -9919389, 16200430, -25631421, 39916181, -62728305, 104572956, -213856425, 2098625289, + 273625084, -120220314, 70138763, -44286236, 28455643, -18081794, 11167487, -6616100, + 3714626, -1950573, 942358, -409406, 154349, -47358, 10215 }, + { -6602, 34872, -121236, 335112, -794535, 1682352, -3262155, 5895334, + -10066938, 16442641, -26015887, 40515364, -63666520, 106115748, -216852761, 2096994989, + 278611252, -122278367, 71320521, -45028947, 28932843, -18385774, 11356013, -6728416, + 3778129, -1984207, 958782, -416639, 157127, -48235, 10414 }, + { -6679, 35319, -122860, 339722, -805668, 1706255, -3309011, 5980750, + -10213803, 16683772, -26398682, 41111959, -64600581, 107651045, -219829776, 2095338532, + 283609724, -124336734, 72501784, -45771221, 29409760, -18689597, 11544467, -6840711, + 3841634, -2017852, 975217, -423881, 159910, -49114, 10614 }, + { -6754, 35762, -124472, 344301, -816735, 1730025, -3355623, 6065745, + -10359978, 16923814, -26779793, 41705949, -65530460, 109178806, -222787445, 2093655956, + 288620412, -126395340, 73682507, -46513030, 29886373, -18993251, 11732842, -6952980, + 3905139, -2051507, 991663, -431131, 162698, -49995, 10815 }, + { -6829, 36201, -126071, 348849, -827733, 1753661, -3401990, 6150318, + -10505461, 17162760, -27159208, 42297316, -66456129, 110698992, -225725743, 2091947299, + 293643229, -128454111, 74862644, -47254344, 30362664, -19296723, 11921131, -7065217, + 3968642, -2085169, 1008118, -438389, 165491, -50879, 11016 }, + { -6903, 36636, -127658, 353366, -838663, 1777163, -3448109, 6234465, + -10650246, 17400603, -27536916, 42886041, -67377562, 112211564, -228644645, 2090212602, + 298678087, -130512973, 76042149, -47995133, 30838614, -19600002, 12109325, -7177420, + 4032139, -2118839, 1024583, -445654, 168288, -51765, 11219 }, + { -6975, 37066, -129232, 357852, -849526, 1800529, -3493981, 6318185, + -10794329, 17637335, -27912905, 43472106, -68294731, 113716483, -231544129, 2088451906, + 303724899, -132571850, 77220976, -48735369, 31314204, -19903076, 12297418, -7289582, + 4095628, -2152514, 1041056, -452926, 171089, -52653, 11422 }, + { -7047, 37493, -130794, 362306, -860320, 1823759, -3539603, 6401474, + -10937706, 17872951, -28287164, 44055494, -69207609, 115213710, -234424171, 2086665250, + 308783574, -134630668, 78399081, -49475022, 31789415, -20205931, 12485401, -7401700, + 4159107, -2186193, 1057537, -460204, 173895, -53543, 11626 }, + { -7118, 37915, -132343, 366730, -871045, 1846853, -3584974, 6484331, + -11080373, 18107442, -28659681, 44636186, -70116170, 116703208, -237284748, 2084852676, + 313854024, -136689351, 79576416, -50214063, 32264229, -20508557, 12673267, -7513769, + 4222574, -2219874, 1074025, -467489, 176705, -54435, 11831 }, + { -7187, 38334, -133880, 371122, -881702, 1869810, -3630093, 6566753, + -11222326, 18340801, -29030444, 45214165, -71020386, 118184939, -240125839, 2083014227, + 318936160, -138747824, 80752936, -50952463, 32738625, -20810941, 12861009, -7625785, + 4286024, -2253558, 1090519, -474781, 179520, -55329, 12037 }, + { -7256, 38748, -135405, 375483, -892289, 1892629, -3674960, 6648738, + -11363560, 18573022, -29399443, 45789414, -71920233, 119658865, -242947422, 2081149946, + 324029892, -140806012, 81928596, -51690192, 33212585, -21113071, 13048619, -7737743, + 4349457, -2287241, 1107020, -482078, 182338, -56226, 12244 }, + { -7324, 39158, -136917, 379812, -902807, 1915311, -3719572, 6730284, + -11504071, 18804097, -29766667, 46361915, -72815683, 121124949, -245749476, 2079259875, + 329135129, -142863839, 83103348, -52427221, 33686091, -21414934, 13236090, -7849638, + 4412869, -2320923, 1123526, -489381, 185160, -57124, 12451 }, + { -7391, 39564, -138417, 384110, -913256, 1937854, -3763929, 6811387, + -11643856, 19034020, -30132104, 46931652, -73706710, 122583155, -248531980, 2077344058, + 334251781, -144921228, 84277148, -53163520, 34159122, -21716518, 13423413, -7961467, + 4476258, -2354603, 1140036, -496689, 187986, -58025, 12660 }, + { -7457, 39966, -139904, 388376, -923634, 1960257, -3808029, 6892048, + -11782909, 19262784, -30495743, 47498606, -74593290, 124033446, -251294915, 2075402541, + 339379757, -146978105, 85449948, -53899061, 34631661, -22017812, 13610581, -8073224, + 4539621, -2388278, 1156550, -504002, 190815, -58927, 12869 }, + { -7522, 40364, -141378, 392611, -933943, 1982521, -3851872, 6972261, + -11921228, 19490382, -30857574, 48062762, -75475396, 125475786, -254038262, 2073435368, + 344518965, -149034393, 86621703, -54633813, 35103687, -22318803, 13797587, -8184904, + 4602956, -2421948, 1173068, -511320, 193648, -59832, 13079 }, + { -7586, 40758, -142840, 396813, -944182, 2004645, -3895456, 7052027, + -12058809, 19716808, -31217585, 48624102, -76353004, 126910140, -256762002, 2071442585, + 349669313, -151090015, 87792367, -55367747, 35575182, -22619479, 13984423, -8296504, + 4666260, -2455611, 1189588, -518643, 196485, -60738, 13289 }, + { -7649, 41148, -144290, 400984, -954350, 2026628, -3938780, 7131342, + -12195647, 19942055, -31575767, 49182610, -77226089, 128336472, -259466116, 2069424238, + 354830709, -153144895, 88961893, -56100833, 36046127, -22919827, 14171082, -8408019, + 4729531, -2489267, 1206110, -525969, 199325, -61647, 13501 }, + { -7711, 41534, -145726, 405123, -964448, 2048470, -3981843, 7210205, + -12331738, 20166115, -31932108, 49738269, -78094624, 129754747, -262150588, 2067380374, + 360003060, -155198957, 90130235, -56833043, 36516503, -23219835, 14357555, -8519444, + 4792765, -2522912, 1222634, -533300, 202168, -62557, 13713 }, + { -7772, 41915, -147151, 409231, -974475, 2070170, -4024645, 7288613, + -12467079, 20388984, -32286597, 50291062, -78958587, 131164932, -264815399, 2065311041, + 365186274, -157252124, 91297347, -57564347, 36986290, -23519492, 14543835, -8630775, + 4855961, -2556547, 1239157, -540634, 205014, -63469, 13926 }, + { -7832, 42293, -148562, 413306, -984431, 2091728, -4067183, 7366564, + -12601666, 20610653, -32639226, 50840975, -79817953, 132566991, -267460534, 2063216286, + 370380256, -159304318, 92463182, -58294714, 37455469, -23818784, 14729914, -8742006, + 4919115, -2590170, 1255681, -547971, 207864, -64383, 14140 }, + { -7892, 42666, -149961, 417349, -994316, 2113143, -4109457, 7444056, + -12735495, 20831118, -32989982, 51387990, -80672696, 133960892, -270085976, 2061096159, + 375584914, -161355463, 93627694, -59024117, 37924022, -24117700, 14915785, -8853134, + 4982226, -2623779, 1272204, -555312, 210716, -65298, 14354 }, + { -7950, 43036, -151348, 421360, -1004130, 2134415, -4151465, 7521087, + -12868562, 21050371, -33338855, 51932092, -81522795, 135346599, -272691710, 2058950708, + 380800152, -163405482, 94790836, -59752524, 38391928, -24416226, 15101440, -8964154, + 5045289, -2657373, 1288726, -562655, 213571, -66215, 14569 }, + { -8007, 43401, -152722, 425339, -1013872, 2155544, -4193208, 7597656, + -13000864, 21268406, -33685837, 52473264, -82368224, 136724081, -275277721, 2056779983, + 386025876, -165454297, 95952563, -60479906, 38859170, -24714352, 15286872, -9075061, + 5108304, -2690950, 1305245, -570000, 216428, -67134, 14785 }, + { -8064, 43762, -154083, 429286, -1023543, 2176528, -4234683, 7673759, + -13132398, 21485217, -34030916, 53011491, -83208960, 138093305, -277843995, 2054584035, + 391261992, -167501830, 97112827, -61206234, 39325727, -25012064, 15472072, -9185851, + 5171267, -2724510, 1321761, -577348, 219288, -68055, 15002 }, + { -8120, 44120, -155432, 433201, -1033141, 2197368, -4275890, 7749395, + -13263158, 21700798, -34374082, 53546758, -84044981, 139454238, -280390518, 2052362915, + 396508404, -169548005, 98271581, -61931478, 39791581, -25309351, 15657033, -9296518, + 5234176, -2758050, 1338274, -584697, 222151, -68977, 15219 }, + { -8174, 44473, -156768, 437083, -1042668, 2218063, -4316827, 7824563, + -13393143, 21915143, -34715326, 54079049, -84876262, 140806849, -282917276, 2050116673, + 401765016, -171592743, 99428780, -62655609, 40256712, -25606200, 15841748, -9407059, + 5297027, -2791570, 1354783, -592048, 225016, -69901, 15437 }, + { -8228, 44822, -158091, 440933, -1052122, 2238612, -4357495, 7899259, + -13522348, 22128246, -35054638, 54608349, -85702782, 142151105, -285424257, 2047845363, + 407031733, -173635966, 100584377, -63378597, 40721101, -25902598, 16026208, -9517469, + 5359819, -2825068, 1371287, -599400, 227883, -70826, 15656 }, + { -8281, 45167, -159402, 444750, -1061504, 2259016, -4397891, 7973483, + -13650769, 22340100, -35392008, 55134643, -86524516, 143486975, -287911449, 2045549037, + 412308457, -175677597, 101738325, -64100412, 41184730, -26198533, 16210406, -9627743, + 5422548, -2858542, 1387785, -606753, 230752, -71753, 15876 }, + { -8333, 45509, -160700, 448535, -1070813, 2279273, -4438015, 8047232, + -13778404, 22550700, -35727426, 55657915, -87341444, 144814429, -290378839, 2043227747, + 417595092, -177717557, 102890577, -64821025, 41647578, -26493994, 16394334, -9737876, + 5485213, -2891991, 1404277, -614106, 233624, -72681, 16096 }, + { -8384, 45846, -161986, 452288, -1080050, 2299384, -4477866, 8120504, + -13905250, 22760040, -36060884, 56178151, -88153543, 146133435, -292826418, 2040881549, + 422891541, -179755768, 104041086, -65540406, 42109627, -26788967, 16577985, -9847864, + 5547810, -2925415, 1420762, -621460, 236497, -73610, 16317 }, + { -8434, 46179, -163258, 456008, -1089214, 2319347, -4517443, 8193298, + -14031301, 22968114, -36392370, 56695337, -88960790, 147443965, -295254174, 2038510496, + 428197707, -181792152, 105189807, -66258525, 42570857, -27083441, 16761351, -9957702, + 5610337, -2958810, 1437239, -628813, 239372, -74542, 16539 }, + { -8483, 46508, -164519, 459695, -1098305, 2339163, -4556745, 8265612, + -14156556, 23174917, -36721877, 57209457, -89763165, 148745987, -297662098, 2036114644, + 433513491, -183826630, 106336692, -66975353, 43031250, -27377403, 16944423, -10067386, + 5672790, -2992176, 1453708, -636167, 242248, -75474, 16761 }, + { -8531, 46833, -165766, 463350, -1107322, 2358831, -4595771, 8337444, + -14281011, 23380442, -37049395, 57720498, -90560645, 150039472, -300050179, 2033694047, + 438838795, -185859123, 107481694, -67690859, 43490785, -27670840, 17127195, -10176911, + 5735169, -3025512, 1470168, -643519, 245126, -76408, 16984 }, + { -8579, 47154, -167001, 466972, -1116267, 2378351, -4634520, 8408792, + -14404662, 23584684, -37374915, 58228444, -91353209, 151324392, -302418410, 2031248762, + 444173521, -187889553, 108624767, -68405016, 43949445, -27963741, 17309658, -10286272, + 5797468, -3058816, 1486618, -650871, 248005, -77343, 17207 }, + { -8626, 47471, -168223, 470561, -1125138, 2397722, -4672992, 8479654, + -14527507, 23787638, -37698427, 58733282, -92140836, 152600718, -304766781, 2028778846, + 449517569, -189917841, 109765864, -69117792, 44407209, -28256093, 17491806, -10395464, + 5859688, -3092086, 1503057, -658221, 250886, -78279, 17432 }, + { -8671, 47784, -169433, 474118, -1133935, 2416944, -4711185, 8550030, + -14649542, 23989297, -38019923, 59234998, -92923506, 153868420, -307095284, 2026284356, + 454870841, -191943908, 110904938, -69829158, 44864059, -28547884, 17673629, -10504484, + 5921823, -3125322, 1519485, -665570, 253768, -79216, 17656 }, + { -8716, 48093, -170630, 477642, -1142659, 2436016, -4749100, 8619916, + -14770764, 24189657, -38339393, 59733579, -93701197, 155127472, -309403914, 2023765349, + 460233237, -193967675, 112041943, -70539085, 45319975, -28839101, 17855121, -10613326, + 5983872, -3158521, 1535902, -672917, 256650, -80155, 17882 }, + { -8760, 48398, -171814, 481133, -1151308, 2454939, -4786734, 8689311, + -14891170, 24388713, -38656830, 60229009, -94473890, 156377846, -311692662, 2021221885, + 465604657, -195989062, 113176830, -71247542, 45774938, -29129732, 18036274, -10721985, + 6045833, -3191683, 1552305, -680261, 259534, -81095, 18108 }, + { -8803, 48700, -172985, 484592, -1159884, 2473711, -4824087, 8758214, + -15010756, 24586458, -38972224, 60721276, -95241563, 157619514, -313961522, 2018654021, + 470985001, -198007990, 114309555, -71954501, 46228929, -29419765, 18217079, -10830458, + 6107702, -3224805, 1568696, -687603, 262418, -82036, 18335 }, + { -8845, 48997, -174144, 488017, -1168386, 2492333, -4861158, 8826623, + -15129521, 24782887, -39285566, 61210367, -96004198, 158852449, -316210490, 2016061817, + 476374167, -200024381, 115440069, -72659931, 46681929, -29709187, 18397530, -10938738, + 6169476, -3257887, 1585072, -694942, 265303, -82978, 18562 }, + { -8887, 49290, -175291, 491410, -1176814, 2510805, -4897947, 8894537, + -15247460, 24977996, -39596849, 61696267, -96761773, 160076625, -318439559, 2013445334, + 481772056, -202038153, 116568326, -73363803, 47133919, -29997986, 18577618, -11046822, + 6231154, -3290927, 1601434, -702278, 268189, -83921, 18790 }, + { -8927, 49579, -176424, 494770, -1185167, 2529124, -4934452, 8961953, + -15364571, 25171779, -39906064, 62178965, -97514271, 161292016, -320648725, 2010804631, + 487178565, -204049229, 117694280, -74066087, 47584879, -30286150, 18757336, -11154706, + 6292732, -3323924, 1617780, -709610, 271075, -84865, 19019 }, + { -8967, 49865, -177545, 498097, -1193446, 2547293, -4970674, 9028871, + -15480851, 25364232, -40213202, 62658446, -98261671, 162498596, -322837984, 2008139771, + 492593593, -206057527, 118817882, -74766755, 48034790, -30573666, 18936676, -11262383, + 6354207, -3356876, 1634110, -716939, 273961, -85809, 19248 }, + { -9005, 50146, -178654, 501391, -1201650, 2565309, -5006610, 9095288, + -15596297, 25555348, -40518255, 63134699, -99003954, 163696339, -325007333, 2005450814, + 498017039, -208062969, 119939087, -75465775, 48483633, -30860522, 19115630, -11369850, + 6415578, -3389781, 1650423, -724263, 276848, -86755, 19477 }, + { -9043, 50423, -179749, 504652, -1209780, 2583174, -5042261, 9161203, + -15710906, 25745124, -40821216, 63607710, -99741102, 164885221, -327156768, 2002737822, + 503448799, -210065474, 121057848, -76163119, 48931389, -31146706, 19294191, -11477102, + 6476841, -3422639, 1666718, -731583, 279734, -87702, 19708 }, + { -9080, 50697, -180833, 507880, -1217834, 2600886, -5077626, 9226615, + -15824676, 25933554, -41122075, 64077467, -100473096, 166065217, -329286288, 2000000860, + 508888771, -212064963, 122174117, -76858756, 49378039, -31432206, 19472350, -11584134, + 6537994, -3455447, 1682995, -738898, 282620, -88649, 19938 }, + { -9117, 50966, -181903, 511075, -1225814, 2618445, -5112704, 9291522, + -15937603, 26120633, -41420826, 64543957, -101199917, 167236302, -331395889, 1997239989, + 514336853, -214061355, 123287848, -77552658, 49823564, -31717008, 19650100, -11690942, + 6599034, -3488205, 1699253, -746208, 285506, -89597, 20170 }, + { -9152, 51232, -182961, 514237, -1233719, 2635851, -5147494, 9355923, + -16049685, 26306357, -41717460, 65007169, -101921548, 168398453, -333485572, 1994455274, + 519792940, -216054571, 124398993, -78244795, 50267944, -32001102, 19827434, -11797520, + 6659958, -3520910, 1715492, -753512, 288392, -90546, 20402 }, + { -9187, 51494, -184006, 517365, -1241549, 2653104, -5181995, 9419817, + -16160919, 26490721, -42011969, 65467090, -102637970, 169551645, -335555334, 1991646778, + 525256930, -218044529, 125507508, -78935138, 50711161, -32284474, 20004343, -11903865, + 6720763, -3553562, 1731709, -760811, 291277, -91496, 20634 }, + { -9220, 51752, -185039, 520461, -1249304, 2670203, -5216208, 9483201, + -16271302, 26673720, -42304347, 65923708, -103349165, 170695856, -337605176, 1988814568, + 530728719, -220031150, 126613343, -79623656, 51153195, -32567112, 20180821, -12009971, + 6781448, -3586159, 1747906, -768103, 294162, -92446, 20867 }, + { -9253, 52006, -186059, 523524, -1256984, 2687149, -5250131, 9546074, + -16380833, 26855350, -42594584, 66377011, -104055117, 171831064, -339635098, 1985958708, + 536208202, -222014353, 127716453, -80310320, 51594027, -32849004, 20356858, -12115834, + 6842008, -3618699, 1764080, -775390, 297046, -93397, 21100 }, + { -9285, 52256, -187066, 526554, -1264588, 2703940, -5283763, 9608436, + -16489507, 27035606, -42882675, 66826988, -104755808, 172957244, -341645100, 1983079265, + 541695274, -223994059, 128816790, -80995101, 52033639, -33130137, 20532447, -12221449, + 6902442, -3651182, 1780232, -782669, 299929, -94348, 21334 }, + { -9317, 52502, -188061, 529551, -1272117, 2720577, -5317104, 9670285, + -16597324, 27214483, -43168611, 67273627, -105451221, 174074376, -343635185, 1980176304, + 547189832, -225970185, 129914309, -81677970, 52472011, -33410500, 20707581, -12326812, + 6962747, -3683605, 1796360, -789941, 302811, -95300, 21569 }, + { -9347, 52745, -189044, 532514, -1279571, 2737059, -5350154, 9731619, + -16704279, 27391979, -43452386, 67716917, -106141339, 175182437, -345605353, 1977249893, + 552691770, -227942653, 131008962, -82358897, 52909124, -33690081, 20882253, -12431917, + 7022920, -3715967, 1812464, -797206, 305692, -96253, 21803 }, + { -9377, 52983, -190013, 535445, -1286949, 2753386, -5382912, 9792437, + -16810372, 27568087, -43733991, 68156847, -106826145, 176281407, -347555607, 1974300099, + 558200982, -229911380, 132100702, -83037852, 53344959, -33968866, 21056453, -12536761, + 7082958, -3748267, 1828544, -804463, 308571, -97206, 22039 }, + { -9406, 53218, -190971, 538342, -1294252, 2769559, -5415377, 9852738, + -16915599, 27742803, -44013421, 68593405, -107505624, 177371263, -349485950, 1971326992, + 563717363, -231876287, 133189482, -83714806, 53779498, -34246843, 21230175, -12641337, + 7142859, -3780502, 1844597, -811712, 311450, -98159, 22275 }, + { -9434, 53449, -191915, 541207, -1301478, 2785576, -5447548, 9912521, + -17019957, 27916125, -44290668, 69026581, -108179758, 178451987, -351396386, 1968330638, + 569240807, -233837292, 134275257, -84389731, 54212720, -34524001, 21403410, -12745643, + 7202620, -3812673, 1860625, -818953, 314326, -99113, 22511 }, + { -9461, 53676, -192848, 544038, -1308629, 2801437, -5479426, 9971785, + -17123446, 28088046, -44565724, 69456363, -108848533, 179523556, -353286917, 1965311107, + 574771207, -235794316, 135357979, -85062595, 54644608, -34800327, 21576152, -12849673, + 7262238, -3844777, 1876625, -826185, 317201, -100067, 22748 }, + { -9488, 53899, -193767, 546836, -1315705, 2817142, -5511008, 10030528, + -17226061, 28258564, -44838584, 69882742, -109511933, 180585952, -355157550, 1962268470, + 580308458, -237747275, 136437602, -85733371, 55075142, -35075809, 21748392, -12953421, + 7321711, -3876813, 1892597, -833407, 320075, -101021, 22985 }, + { -9513, 54119, -194675, 549601, -1322704, 2832692, -5542296, 10088748, + -17327802, 28427674, -45109241, 70305706, -110169941, 181639155, -357008289, 1959202795, + 585852451, -239696091, 137514078, -86402029, 55504304, -35350435, 21920123, -13056885, + 7381035, -3908779, 1908541, -840621, 322946, -101975, 23222 }, + { -9538, 54335, -195569, 552333, -1329628, 2848085, -5573289, 10146446, + -17428665, 28595372, -45377688, 70725246, -110822543, 182683145, -358839138, 1956114154, + 591403080, -241640682, 138587362, -87068540, 55932073, -35624192, 22091336, -13160059, + 7440209, -3940674, 1924456, -847824, 325815, -102930, 23460 }, + { -9562, 54546, -196452, 555032, -1336475, 2863322, -5603985, 10203620, + -17528649, 28761655, -45643919, 71141351, -111469724, 183717904, -360650105, 1953002619, + 596960238, -243580966, 139657407, -87732874, 56358433, -35897069, 22262025, -13262938, + 7499229, -3972496, 1940340, -855018, 328682, -103885, 23699 }, + { -9586, 54755, -197321, 557698, -1343247, 2878403, -5634384, 10260268, + -17627752, 28926518, -45907926, 71554011, -112111470, 184743414, -362441196, 1949868260, + 602523817, -245516863, 140724166, -88395002, 56783363, -36169052, 22432182, -13365517, + 7558093, -4004244, 1956194, -862201, 331547, -104840, 23937 }, + { -9608, 54959, -198179, 560330, -1349943, 2893326, -5664487, 10316390, + -17725971, 29089958, -46169705, 71963216, -112747765, 185759656, -364212419, 1946711150, + 608093708, -247448291, 141787593, -89054896, 57206844, -36440131, 22601798, -13467793, + 7616798, -4035917, 1972016, -869373, 334409, -105795, 24177 }, + { -9630, 55160, -199024, 562930, -1356563, 2908093, -5694292, 10371985, + -17823304, 29251971, -46429248, 72368957, -113378595, 186766613, -365963779, 1943531362, + 613669804, -249375170, 142847641, -89712525, 57628859, -36710293, 22770867, -13569760, + 7675341, -4067512, 1987806, -876534, 337269, -106750, 24416 }, + { -9651, 55356, -199856, 565496, -1363106, 2922702, -5723799, 10427051, + -17919750, 29412553, -46686550, 72771223, -114003947, 187764267, -367695287, 1940328969, + 619251996, -251297417, 143904264, -90367862, 58049388, -36979525, 22939381, -13671413, + 7733720, -4099030, 2003563, -883684, 340126, -107705, 24656 }, + { -9672, 55550, -200676, 568030, -1369574, 2937155, -5753007, 10481588, + -18015305, 29571701, -46941605, 73170006, -114623806, 188752602, -369406949, 1937104044, + 624840175, -253214952, 144957415, -91020876, 58468413, -37247816, 23107331, -13772749, + 7791932, -4130467, 2019286, -890822, 342980, -108660, 24896 }, + { -9691, 55739, -201484, 570530, -1375965, 2951450, -5781917, 10535595, + -18109970, 29729411, -47194406, 73565296, -115238159, 189731601, -371098777, 1933856663, + 630434233, -255127694, 146007049, -91671540, 58885914, -37515153, 23274711, -13873762, + 7849974, -4161822, 2034974, -897947, 345831, -109614, 25137 }, + { -9710, 55925, -202280, 572998, -1382280, 2965587, -5810527, 10589070, + -18203740, 29885680, -47444948, 73957084, -115846993, 190701247, -372770778, 1930586899, + 636034059, -257035560, 147053118, -92319823, 59301873, -37781525, 23441512, -13974447, + 7907843, -4193095, 2050628, -905061, 348679, -110569, 25378 }, + { -9728, 56107, -203063, 575432, -1388519, 2979567, -5838838, 10642012, + -18296615, 30040504, -47693225, 74345361, -116450294, 191661525, -374422964, 1927294828, + 641639544, -258938471, 148095577, -92965698, 59716272, -38046919, 23607727, -14074801, + 7965537, -4224283, 2066245, -912161, 351524, -111523, 25619 }, + { -9745, 56285, -203834, 577834, -1394682, 2993389, -5866848, 10694422, + -18388592, 30193881, -47939232, 74730119, -117048050, 192612420, -376055346, 1923980526, + 647250579, -260836343, 149134379, -93609134, 60129091, -38311324, 23773349, -14174818, + 8023054, -4255386, 2081826, -919249, 354365, -112477, 25860 }, + { -9762, 56460, -204592, 580202, -1400768, 3007053, -5894558, 10746297, + -18479671, 30345806, -48182962, 75111347, -117640248, 193553915, -377667934, 1920644069, + 652867053, -262729096, 150169478, -94250104, 60540312, -38574727, 23938370, -14274493, + 8080390, -4286401, 2097369, -926323, 357203, -113431, 26102 }, + { -9778, 56631, -205338, 582538, -1406778, 3020559, -5921967, 10797637, + -18569849, 30496277, -48424412, 75489039, -118226875, 194485998, -379260740, 1917285534, + 658488855, -264616649, 151200828, -94888579, 60949917, -38837116, 24102782, -14373823, + 8137542, -4317327, 2112874, -933383, 360037, -114384, 26344 }, + { -9793, 56798, -206072, 584840, -1412712, 3033907, -5949075, 10848442, + -18659124, 30645290, -48663574, 75863185, -118807919, 195408652, -380833776, 1913904997, + 664115876, -266498919, 152228383, -95524530, 61357887, -39098479, 24266577, -14472802, + 8194509, -4348163, 2128340, -940429, 362868, -115337, 26586 }, + { -9807, 56962, -206794, 587110, -1418570, 3047096, -5975882, 10898709, + -18747494, 30792842, -48900445, 76233778, -119383368, 196321865, -382387056, 1910502538, + 669748005, -268375826, 153252097, -96157927, 61764202, -39358805, 24429748, -14571426, + 8251287, -4378907, 2143766, -947460, 365694, -116290, 26829 }, + { -9821, 57122, -207504, 589347, -1424352, 3060128, -6002386, 10948440, + -18834959, 30938931, -49135018, 76600809, -119953212, 197225622, -383920593, 1907078233, + 675385130, -270247287, 154271923, -96788743, 62168846, -39618081, 24592288, -14669690, + 8307873, -4409557, 2159152, -954476, 368516, -117242, 27072 }, + { -9834, 57278, -208201, 591551, -1430057, 3073000, -6028588, 10997632, + -18921516, 31083553, -49367290, 76964270, -120517437, 198119910, -385434400, 1903632161, + 681027140, -272113222, 155287817, -97416949, 62571799, -39876295, 24754189, -14767590, + 8364265, -4440114, 2174496, -961478, 371334, -118194, 27315 }, + { -9846, 57431, -208886, 593722, -1435686, 3085714, -6054488, 11046285, + -19007164, 31226705, -49597254, 77324153, -121076032, 199004717, -386928491, 1900164403, + 686673924, -273973548, 156299732, -98042517, 62973043, -40133436, 24915443, -14865121, + 8420461, -4470573, 2189799, -968463, 374148, -119145, 27558 }, + { -9858, 57581, -209559, 595860, -1441239, 3098270, -6080085, 11094398, + -19091902, 31368385, -49824906, 77680451, -121628988, 199880029, -388402882, 1896675037, + 692325369, -275828184, 157307622, -98665417, 63372559, -40389491, 25076043, -14962278, + 8476457, -4500935, 2205059, -975433, 376957, -120095, 27802 }, + { -9869, 57726, -210220, 597966, -1446715, 3110667, -6105379, 11141971, + -19175727, 31508590, -50050242, 78033157, -122176292, 200745836, -389857588, 1893164143, + 697981364, -277677049, 158311442, -99285621, 63770330, -40644449, 25235981, -15059057, + 8532251, -4531198, 2220275, -982387, 379761, -121045, 28046 }, + { -9879, 57868, -210869, 600039, -1452116, 3122905, -6130369, 11189003, + -19258639, 31647317, -50273256, 78382262, -122717935, 201602123, -391292625, 1889631802, + 703641796, -279520061, 159311145, -99903102, 64166336, -40898298, 25395250, -15155452, + 8587840, -4561361, 2235447, -989324, 382561, -121993, 28289 }, + { -9889, 58007, -211505, 602079, -1457440, 3134984, -6155056, 11235492, + -19340636, 31784563, -50493945, 78727760, -123253905, 202448882, -392708009, 1886078096, + 709306553, -281357138, 160306688, -100517830, 64560560, -41151026, 25553842, -15251461, + 8643221, -4591421, 2250574, -996244, 385355, -122942, 28534 }, + { -9898, 58142, -212130, 604086, -1462688, 3146905, -6179439, 11281440, + -19421716, 31920326, -50712303, 79069644, -123784194, 203286099, -394103757, 1882503105, + 714975522, -283188199, 161298022, -101129777, 64952983, -41402621, 25711750, -15347077, + 8698393, -4621377, 2265655, -1003147, 388145, -123889, 28778 }, + { -9906, 58273, -212743, 606061, -1467859, 3158666, -6203518, 11326844, + -19501879, 32054604, -50928327, 79407907, -124308790, 204113765, -395479886, 1878906912, + 720648590, -285013163, 162285105, -101738916, 65343587, -41653071, 25868967, -15442296, + 8753351, -4651229, 2280690, -1010032, 390929, -124835, 29022 }, + { -9913, 58401, -213343, 608003, -1472955, 3170269, -6227292, 11371705, + -19581122, 32187393, -51142012, 79742542, -124827684, 204931870, -396836415, 1875289599, + 726325645, -286831947, 163267889, -102345218, 65732354, -41902365, 26025483, -15537115, + 8808094, -4680974, 2295678, -1016899, 393708, -125781, 29267 }, + { -9920, 58526, -213932, 609912, -1477975, 3181713, -6250763, 11416022, + -19659446, 32318692, -51353354, 80073543, -125340868, 205740402, -398173360, 1871651249, + 732006572, -288644470, 164246330, -102948654, 66119265, -42150491, 26181294, -15631527, + 8862619, -4710611, 2310618, -1023748, 396482, -126725, 29511 }, + { -9926, 58647, -214509, 611789, -1482918, 3192998, -6273928, 11459794, + -19736848, 32448498, -51562349, 80400902, -125848331, 206539354, -399490743, 1867991946, + 737691259, -290450651, 165220382, -103549197, 66504303, -42397437, 26336390, -15725529, + 8916922, -4740138, 2325509, -1030578, 399249, -127669, 29756 }, + { -9932, 58764, -215073, 613634, -1487786, 3204123, -6296789, 11503020, + -19813328, 32576809, -51768993, 80724614, -126350064, 207328714, -400788581, 1864311772, + 743379590, -292250408, 166190000, -104146819, 66887450, -42643191, 26490765, -15819117, + 8971002, -4769554, 2340350, -1037389, 402011, -128611, 30001 }, + { -9937, 58878, -215626, 615446, -1492577, 3215090, -6319344, 11545701, + -19888883, 32703622, -51973282, 81044673, -126846060, 208108475, -402066894, 1860610814, + 749071454, -294043660, 167155140, -104741492, 67268687, -42887743, 26644410, -15912284, + 9024856, -4798858, 2355141, -1044181, 404767, -129553, 30246 }, + { -9941, 58989, -216167, 617225, -1497293, 3225898, -6341595, 11587836, + -19963514, 32828936, -52175212, 81361072, -127336309, 208878628, -403325704, 1856889155, + 754766734, -295830325, 168115755, -105333188, 67647996, -43131079, 26797320, -16005028, + 9078481, -4828048, 2369882, -1050953, 407517, -130493, 30491 }, + { -9944, 59096, -216696, 618973, -1501932, 3236546, -6363540, 11629424, + -20037219, 32952749, -52374780, 81673807, -127820803, 209639165, -404565031, 1853146881, + 760465317, -297610321, 169071802, -105921879, 68025361, -43373189, 26949485, -16097343, + 9131874, -4857123, 2384570, -1057704, 410261, -131432, 30736 }, + { -9947, 59200, -217214, 620687, -1506496, 3247036, -6385180, 11670464, + -20109997, 33075058, -52571982, 81982870, -128299534, 210390078, -405784895, 1849384077, + 766167088, -299383568, 170023235, -106507538, 68400761, -43614061, 27100900, -16189225, + 9185033, -4886081, 2399206, -1064436, 412999, -132370, 30981 }, + { -9950, 59300, -217719, 622370, -1510984, 3257367, -6406514, 11710958, + -20181847, 33195861, -52766815, 82288257, -128772495, 211131359, -406985320, 1845600829, + 771871933, -301149983, 170970009, -107090137, 68774181, -43853683, 27251556, -16280669, + 9237955, -4914920, 2413789, -1071147, 415729, -133306, 31227 }, + { -9951, 59397, -218213, 624020, -1515396, 3267538, -6427543, 11750903, + -20252768, 33315157, -52959275, 82589962, -129239677, 211863002, -408166327, 1841797224, + 777579736, -302909486, 171912081, -107669647, 69145602, -44092044, 27401446, -16371671, + 9290638, -4943640, 2428317, -1077836, 418454, -134241, 31472 }, + { -9952, 59491, -218695, 625639, -1519733, 3277551, -6448266, 11790300, + -20322760, 33432943, -53149359, 82887980, -129701074, 212584999, -409327939, 1837973349, + 783290382, -304661994, 172849404, -108246043, 69515006, -44329133, 27550563, -16462226, + 9343078, -4972238, 2442791, -1084504, 421171, -135175, 31717 }, + { -9953, 59581, -219165, 627225, -1523994, 3287405, -6468683, 11829148, + -20391820, 33549219, -53337064, 83182306, -130156678, 213297345, -410470179, 1834129292, + 789003756, -306407428, 173781936, -108819295, 69882376, -44564937, 27698900, -16552330, + 9395274, -5000714, 2457209, -1091150, 423882, -136107, 31963 }, + { -9952, 59668, -219624, 628779, -1528179, 3297100, -6488795, 11867447, + -20459950, 33663981, -53522387, 83472934, -130606482, 214000033, -411593072, 1830265140, + 794719743, -308145704, 174709631, -109389378, 70247693, -44799446, 27846449, -16641979, + 9447222, -5029065, 2471572, -1097774, 426585, -137037, 32208 }, + { -9952, 59751, -220071, 630301, -1532289, 3306636, -6508600, 11905198, + -20527147, 33777229, -53705325, 83759861, -131050480, 214693057, -412696641, 1826380981, + 800438226, -309876743, 175632445, -109956263, 70610941, -45032648, 27993203, -16731167, + 9498920, -5057291, 2485877, -1104376, 429281, -137966, 32453 }, + { -9950, 59831, -220506, 631790, -1536324, 3316014, -6528100, 11942398, + -20593411, 33888962, -53885875, 84043081, -131488665, 215376414, -413780912, 1822476905, + 806159090, -311600463, 176550333, -110519924, 70972102, -45264532, 28139154, -16819891, + 9550365, -5085390, 2500124, -1110954, 431970, -138894, 32698 }, + { -9948, 59908, -220930, 633248, -1540283, 3325233, -6547293, 11979049, + -20658741, 33999176, -54064033, 84322590, -131921032, 216050096, -414845909, 1818553000, + 811882219, -313316783, 177463253, -111080332, 71331158, -45495085, 28284297, -16908146, + 9601554, -5113360, 2514313, -1117509, 434651, -139820, 32943 }, + { -9945, 59982, -221343, 634675, -1544166, 3334293, -6566181, 12015150, + -20723137, 34107872, -54239799, 84598384, -132347573, 216714101, -415891658, 1814609356, + 817607496, -315025621, 178371159, -111637462, 71688092, -45724298, 28428622, -16995927, + 9652486, -5141200, 2528442, -1124041, 437324, -140744, 33189 }, + { -9942, 60052, -221743, 636069, -1547975, 3343194, -6584762, 12050700, + -20786598, 34215047, -54413168, 84870458, -132768284, 217368423, -416918185, 1810646063, + 823334805, -316726897, 179274007, -112191286, 72042886, -45952158, 28572124, -17083230, + 9703157, -5168909, 2542511, -1130549, 439990, -141666, 33434 }, + { -9938, 60119, -222133, 637431, -1551708, 3351937, -6603038, 12085701, + -20849123, 34320701, -54584139, 85138809, -133183158, 218013059, -417925518, 1806663212, + 829064029, -318420530, 180171755, -112741776, 72395523, -46178655, 28714794, -17170051, + 9753565, -5196484, 2556520, -1137032, 442648, -142587, 33679 }, + { -9934, 60183, -222510, 638762, -1555367, 3360522, -6621008, 12120150, + -20910712, 34424831, -54752708, 85403432, -133592191, 218648005, -418913683, 1802660893, + 834795053, -320106438, 181064358, -113288908, 72745986, -46403777, 28856627, -17256385, + 9803707, -5223925, 2570467, -1143491, 445297, -143505, 33923 }, + { -9929, 60243, -222877, 640061, -1558950, 3368948, -6638672, 12154049, + -20971364, 34527438, -54918874, 85664324, -133995378, 219273259, -419882709, 1798639198, + 840527758, -321784541, 181951773, -113832652, 73094258, -46627513, 28997614, -17342227, + 9853580, -5251231, 2584352, -1149925, 447939, -144422, 34168 }, + { -9923, 60300, -223232, 641329, -1562459, 3377217, -6656030, 12187397, + -21031080, 34628518, -55082635, 85921481, -134392713, 219888817, -420832622, 1794598218, + 846262028, -323454758, 182833955, -114372984, 73440320, -46849852, 29137748, -17427574, + 9903182, -5278399, 2598174, -1156333, 450571, -145337, 34413 }, + { -9917, 60354, -223576, 642565, -1565893, 3385327, -6673082, 12220195, + -21089857, 34728073, -55243989, 86174899, -134784193, 220494677, -421763451, 1790538046, + 851997746, -325117008, 183710863, -114909876, 73784157, -47070783, 29277023, -17512421, + 9952511, -5305428, 2611932, -1162715, 453196, -146249, 34657 }, + { -9911, 60405, -223908, 643770, -1569252, 3393279, -6689829, 12252441, + -21147696, 34826100, -55402932, 86424576, -135169812, 221090836, -422675227, 1786458774, + 857734794, -326771210, 184582451, -115443301, 74125752, -47290294, 29415431, -17596764, + 10001563, -5332318, 2625625, -1169072, 455811, -147160, 34901 }, + { -9903, 60453, -224229, 644943, -1572536, 3401073, -6706270, 12284136, + -21204597, 34922598, -55559464, 86670509, -135549567, 221677294, -423567978, 1782360494, + 863473054, -328417284, 185448679, -115973234, 74465086, -47508375, 29552965, -17680598, + 10050337, -5359065, 2639253, -1175402, 458418, -148068, 35146 }, + { -9896, 60498, -224539, 646085, -1575746, 3408710, -6722405, 12315280, + -21260560, 35017568, -55713583, 86912693, -135923453, 222254049, -424441734, 1778243301, + 869212410, -330055149, 186309501, -116499648, 74802143, -47725014, 29689619, -17763918, + 10098829, -5385669, 2652815, -1181705, 461016, -148975, 35390 }, + { -9887, 60539, -224838, 647195, -1578882, 3416189, -6738235, 12345874, + -21315583, 35111006, -55865287, 87151127, -136291467, 222821099, -425296525, 1774107287, + 874952744, -331684725, 187164875, -117022516, 75136907, -47940201, 29825384, -17846721, + 10147037, -5412129, 2666311, -1187981, 463604, -149879, 35633 }, + { -9878, 60577, -225125, 648275, -1581943, 3423510, -6753760, 12375916, + -21369666, 35202914, -56014574, 87385808, -136653606, 223378444, -426132383, 1769952548, + 880693936, -333305932, 188014759, -117541813, 75469360, -48153925, 29960255, -17929002, + 10194959, -5438443, 2679739, -1194230, 466184, -150781, 35877 }, + { -9869, 60612, -225402, 649323, -1584931, 3430674, -6768980, 12405407, + -21422811, 35293291, -56161443, 87616733, -137009866, 223926085, -426949340, 1765779177, + 886435871, -334918688, 188859110, -118057513, 75799485, -48366174, 30094224, -18010757, + 10242591, -5464610, 2693098, -1200451, 468753, -151680, 36120 }, + { -9859, 60644, -225667, 650341, -1587844, 3437681, -6783894, 12434347, + -21475015, 35382135, -56305893, 87843900, -137360245, 224464019, -427747426, 1761587270, + 892178428, -336522913, 189697885, -118569589, 76127267, -48576939, 30227285, -18091982, + 10289932, -5490628, 2706389, -1206643, 471314, -152577, 36363 }, + { -9849, 60673, -225921, 651327, -1590683, 3444531, -6798504, 12462736, + -21526280, 35469445, -56447921, 88067306, -137704739, 224992249, -428526674, 1757376921, + 897921490, -338118528, 190531042, -119078015, 76452687, -48786207, 30359429, -18172671, + 10336978, -5516495, 2719609, -1212807, 473864, -153472, 36606 }, + { -9837, 60699, -226164, 652282, -1593448, 3451224, -6812809, 12490575, + -21576605, 35555223, -56587528, 88286949, -138043345, 225510775, -429287118, 1753148227, + 903664939, -339705453, 191358538, -119582767, 76775731, -48993969, 30490651, -18252822, + 10383728, -5542211, 2732759, -1218942, 476405, -154364, 36848 }, + { -9826, 60722, -226397, 653207, -1596140, 3457761, -6826810, 12517863, + -21625989, 35639466, -56724711, 88502828, -138376063, 226019598, -430028789, 1748901284, + 909408656, -341283606, 192180331, -120083817, 77096380, -49200213, 30620944, -18332429, + 10430178, -5567774, 2745838, -1225048, 478935, -155253, 37091 }, + { -9814, 60742, -226618, 654101, -1598758, 3464141, -6840507, 12544600, + -21674434, 35722175, -56859470, 88714941, -138702889, 226518719, -430751723, 1744636188, + 915152522, -342852909, 192996379, -120581141, 77414619, -49404929, 30750300, -18411488, + 10476326, -5593182, 2758845, -1231124, 481455, -156140, 37333 }, + { -9801, 60759, -226828, 654964, -1601303, 3470364, -6853899, 12570787, + -21721938, 35803349, -56991803, 88923286, -139023822, 227008140, -431455953, 1740353035, + 920896419, -344413282, 193806641, -121074713, 77730431, -49608106, 30878713, -18489996, + 10522170, -5618434, 2771780, -1237171, 483965, -157025, 37574 }, + { -9788, 60772, -227028, 655796, -1603774, 3476431, -6866987, 12596424, + -21768503, 35882989, -57121711, 89127861, -139338859, 227487864, -432141513, 1736051923, + 926640227, -345964644, 194611074, -121564507, 78043800, -49809734, 31006175, -18567948, + 10567707, -5643529, 2784640, -1243187, 486465, -157906, 37816 }, + { -9775, 60783, -227216, 656598, -1606173, 3482343, -6879772, 12621511, + -21814127, 35961093, -57249191, 89328665, -139648000, 227957892, -432808439, 1731732951, + 932383828, -347506917, 195409636, -122050498, 78354710, -50009801, 31132682, -18645339, + 10612935, -5668465, 2797427, -1249172, 488954, -158785, 38057 }, + { -9761, 60791, -227394, 657370, -1608498, 3488098, -6892254, 12646049, + -21858812, 36037661, -57374244, 89525696, -139951244, 228418228, -433456766, 1727396214, + 938127103, -349040020, 196202287, -122532662, 78663144, -50208298, 31258224, -18722165, + 10657850, -5693241, 2810138, -1255126, 491432, -159661, 38297 }, + { -9746, 60796, -227561, 658111, -1610750, 3493698, -6904432, 12670037, + -21902557, 36112694, -57496869, 89718955, -140248589, 228868874, -434086531, 1723041813, + 943869931, -350563875, 196988985, -123010972, 78969086, -50405214, 31382796, -18798423, + 10702451, -5717855, 2822774, -1261049, 493899, -160534, 38537 }, + { -9731, 60798, -227718, 658822, -1612930, 3499143, -6916308, 12693475, + -21945362, 36186191, -57617066, 89908439, -140540035, 229309834, -434697769, 1718669846, + 949612195, -352078401, 197769688, -123485405, 79272521, -50600538, 31506392, -18874108, + 10746735, -5742307, 2835334, -1266940, 496355, -161404, 38777 }, + { -9715, 60797, -227864, 659502, -1615036, 3504432, -6927881, 12716365, + -21987228, 36258153, -57734833, 90094149, -140825581, 229741112, -435290518, 1714280411, + 955353774, -353583520, 198544355, -123955934, 79573432, -50794261, 31629003, -18949216, + 10790700, -5766593, 2847816, -1272799, 498799, -162271, 39017 }, + { -9699, 60793, -227999, 660153, -1617071, 3509567, -6939151, 12738707, + -22028155, 36328579, -57850172, 90276083, -141105226, 230162713, -435864814, 1709873608, + 961094550, -355079152, 199312946, -124422536, 79871803, -50986371, 31750624, -19023742, + 10834343, -5790714, 2860220, -1278625, 501233, -163136, 39256 }, + { -9683, 60786, -228123, 660773, -1619033, 3514547, -6950120, 12760500, + -22068144, 36397470, -57963081, 90454241, -141378971, 230574640, -436420696, 1705449538, + 966834401, -356565219, 200075420, -124885185, 80167618, -51176858, 31871248, -19097683, + 10877661, -5814668, 2872546, -1284419, 503654, -163997, 39494 }, + { -9666, 60776, -228237, 661364, -1620923, 3519372, -6960787, 12781745, + -22107194, 36464825, -58073560, 90628622, -141646817, 230976898, -436958201, 1701008299, + 972573210, -358041642, 200831735, -125343857, 80460862, -51365712, 31990869, -19171034, + 10920653, -5838454, 2884792, -1290179, 506064, -164855, 39732 }, + { -9649, 60764, -228341, 661925, -1622740, 3524043, -6971152, 12802443, + -22145306, 36530646, -58181610, 90799227, -141908762, 231369493, -437477369, 1696549993, + 978310855, -359508342, 201581852, -125798527, 80751519, -51552924, 32109479, -19243792, + 10963315, -5862069, 2896958, -1295906, 508463, -165709, 39970 }, + { -9631, 60748, -228434, 662455, -1624486, 3528560, -6981217, 12822594, + -22182480, 36594932, -58287231, 90966055, -142164808, 231752431, -437978238, 1692074721, + 984047218, -360965240, 202325730, -126249172, 81039573, -51738481, 32227072, -19315952, + 11005645, -5885513, 2909044, -1301600, 510849, -166561, 40207 }, + { -9612, 60730, -228516, 662957, -1626161, 3532923, -6990981, 12842199, + -22218718, 36657683, -58390422, 91129106, -142414956, 232125716, -438460847, 1687582583, + 989782177, -362412257, 203063328, -126695766, 81325008, -51922376, 32343642, -19387511, + 11047641, -5908784, 2921047, -1307258, 513223, -167409, 40444 }, + { -9594, 60709, -228589, 663428, -1627763, 3537133, -7000444, 12861257, + -22254018, 36718901, -58491185, 91288381, -142659207, 232489356, -438925238, 1683073682, + 995515614, -363849317, 203794607, -127138286, 81607810, -52104596, 32459183, -19458463, + 11089301, -5931881, 2932969, -1312883, 515585, -168254, 40680 }, + { -9574, 60685, -228651, 663870, -1629294, 3541190, -7009608, 12879769, + -22288383, 36778585, -58589519, 91443880, -142897561, 232843356, -439371449, 1678548118, + 1001247409, -365276339, 204519527, -127576707, 81887963, -52285133, 32573687, -19528805, + 11130621, -5954802, 2944807, -1318472, 517934, -169095, 40916 }, + { -9555, 60659, -228702, 664283, -1630754, 3545093, -7018472, 12897736, + -22321811, 36836736, -58685425, 91595603, -143130020, 233187724, -439799522, 1674005995, + 1006977440, -366693246, 205238047, -128011007, 82165451, -52463977, 32687148, -19598533, + 11171600, -5977547, 2956562, -1324027, 520270, -169933, 41151 }, + { -9535, 60629, -228744, 664666, -1632143, 3548844, -7027036, 12915159, + -22354305, 36893356, -58778904, 91743552, -143356587, 233522467, -440209499, 1669447414, + 1012705588, -368099960, 205950129, -128441160, 82440259, -52641116, 32799560, -19667644, + 11212235, -6000113, 2968232, -1329545, 522594, -170768, 41385 }, + { -9514, 60597, -228775, 665020, -1633461, 3552443, -7035302, 12932037, + -22385865, 36948443, -58869955, 91887726, -143577263, 233847593, -440601420, 1664872479, + 1018431732, -369496404, 206655733, -128867143, 82712372, -52816543, 32910917, -19736132, + 11252524, -6022500, 2979818, -1335028, 524905, -171598, 41619 }, + { -9493, 60562, -228796, 665345, -1634708, 3555889, -7043270, 12948372, + -22416490, 37002000, -58958581, 92028128, -143792049, 234163108, -440975327, 1660281294, + 1024155752, -370882499, 207354820, -129288933, 82981775, -52990245, 33021212, -19803994, + 11292464, -6044706, 2991317, -1340474, 527203, -172425, 41853 }, + { -9472, 60525, -228807, 665641, -1635885, 3559183, -7050940, 12964163, + -22446183, 37054027, -59044782, 92164757, -144000949, 234469022, -441331264, 1655673960, + 1029877529, -372258167, 208047350, -129706506, 83248452, -53162215, 33130438, -19871227, + 11332052, -6066729, 3002729, -1345884, 529488, -173249, 42085 }, + { -9450, 60485, -228807, 665908, -1636992, 3562326, -7058312, 12979412, + -22474943, 37104524, -59128558, 92297616, -144203965, 234765344, -441669273, 1651050583, + 1035596941, -373623333, 208733284, -130119839, 83512390, -53332441, 33238591, -19937825, + 11371288, -6088569, 3014055, -1351257, 531760, -174069, 42318 }, + { -9428, 60442, -228798, 666146, -1638028, 3565318, -7065387, 12994120, + -22502772, 37153493, -59209911, 92426705, -144401100, 235052081, -441989397, 1646411267, + 1041313867, -374977917, 209412584, -130528909, 83773572, -53500915, 33345662, -20003786, + 11410167, -6110223, 3025292, -1356592, 534017, -174885, 42549 }, + { -9405, 60396, -228779, 666355, -1638994, 3568158, -7072166, 13008286, + -22529670, 37200935, -59288842, 92552027, -144592356, 235329243, -442291680, 1641756115, + 1047028188, -376321843, 210085212, -130933692, 84031985, -53667627, 33451646, -20069105, + 11448689, -6131692, 3036440, -1361890, 536262, -175697, 42780 }, + { -9382, 60348, -228750, 666536, -1639890, 3570848, -7078648, 13021911, + -22555638, 37246850, -59365352, 92673582, -144777737, 235596840, -442576167, 1637085234, + 1052739783, -377655035, 210751127, -131334166, 84287612, -53832567, 33556537, -20133778, + 11486849, -6152972, 3047499, -1367149, 538492, -176505, 43010 }, + { -9359, 60297, -228711, 666688, -1640717, 3573388, -7084835, 13034997, + -22580677, 37291240, -59439442, 92791373, -144957247, 235854881, -442842901, 1632398727, + 1058448531, -378977415, 211410294, -131730307, 84540441, -53995725, 33660329, -20197801, + 11524647, -6174064, 3058468, -1372370, 540709, -177309, 43240 }, + { -9335, 60244, -228662, 666812, -1641474, 3575777, -7090726, 13047543, + -22604788, 37334106, -59511115, 92905402, -145130888, 236103377, -443091928, 1627696701, + 1064154311, -380288906, 212062672, -132122094, 84790456, -54157092, 33763015, -20261171, + 11562080, -6194965, 3069345, -1377553, 542911, -178109, 43469 }, + { -9311, 60188, -228603, 666907, -1642162, 3578017, -7096323, 13059551, + -22627972, 37375448, -59580370, 93015670, -145298665, 236342337, -443323294, 1622979262, + 1069857003, -381589432, 212708225, -132509503, 85037643, -54316659, 33864589, -20323884, + 11599145, -6215674, 3080131, -1382696, 545099, -178905, 43697 }, + { -9286, 60129, -228535, 666974, -1642781, 3580108, -7101626, 13071020, + -22650229, 37415269, -59647211, 93122180, -145460582, 236571774, -443537043, 1618246514, + 1075556486, -382878918, 213346914, -132892511, 85281987, -54474416, 33965046, -20385936, + 11635840, -6236191, 3090825, -1387800, 547273, -179697, 43924 }, + { -9261, 60068, -228457, 667013, -1643331, 3582049, -7106635, 13081953, + -22671561, 37453570, -59711638, 93224934, -145616643, 236791698, -443733222, 1613498565, + 1081252640, -384157285, 213978702, -133271098, 85523474, -54630354, 34064379, -20447323, + 11672163, -6256513, 3101426, -1392864, 549432, -180485, 44151 }, + { -9236, 60005, -228369, 667023, -1643812, 3583842, -7111351, 13092350, + -22691969, 37490351, -59773653, 93323935, -145766853, 237002120, -443911878, 1608735522, + 1086945343, -385424460, 214603551, -133645239, 85762090, -54784464, 34162582, -20508041, + 11708111, -6276639, 3111933, -1397889, 551576, -181268, 44377 }, + { -9210, 59938, -228272, 667006, -1644225, 3585486, -7115774, 13102211, + -22711454, 37525615, -59833259, 93419185, -145911216, 237203053, -444073058, 1603957490, + 1092634475, -386680365, 215221425, -134014914, 85997821, -54936736, 34259649, -20568086, + 11743683, -6296568, 3122346, -1402872, 553706, -182047, 44602 }, + { -9184, 59870, -228165, 666961, -1644569, 3586983, -7119906, 13111538, + -22730017, 37559362, -59890456, 93510688, -146049738, 237394508, -444216809, 1599164579, + 1098319914, -387924925, 215832287, -134380101, 86230653, -55087161, 34355574, -20627456, + 11778876, -6316299, 3132663, -1407815, 555820, -182822, 44826 }, + { -9158, 59799, -228049, 666888, -1644846, 3588331, -7123746, 13120330, + -22747660, 37591595, -59945248, 93598445, -146182423, 237576498, -444343179, 1594356894, + 1104001541, -389158065, 216436098, -134740776, 86460571, -55235730, 34450352, -20686145, + 11813687, -6335831, 3142885, -1412717, 557920, -183593, 45049 }, + { -9131, 59725, -227923, 666788, -1645054, 3589533, -7127295, 13128590, + -22764382, 37622315, -59997636, 93682461, -146309276, 237749036, -444452217, 1589534544, + 1109679235, -390379709, 217032824, -135096920, 86687562, -55382434, 34543977, -20744151, + 11848115, -6355161, 3153010, -1417577, 560004, -184358, 45272 }, + { -9104, 59649, -227787, 666660, -1645195, 3590587, -7130553, 13136318, + -22780186, 37651523, -60047622, 93762738, -146430304, 237912134, -444543969, 1584697637, + 1115352874, -391589782, 217622426, -135448510, 86911613, -55527264, 34636442, -20801469, + 11882157, -6374290, 3163038, -1422395, 562072, -185120, 45494 }, + { -9077, 59571, -227643, 666505, -1645269, 3591495, -7133522, 13143514, + -22795073, 37679222, -60095210, 93839280, -146545511, 238065806, -444618487, 1579846282, + 1121022337, -392788209, 218204870, -135795525, 87132708, -55670211, 34727741, -20858096, + 11915811, -6393215, 3172968, -1427171, 564125, -185877, 45715 }, + { -9049, 59490, -227489, 666322, -1645275, 3592257, -7136202, 13150180, + -22809044, 37705412, -60140400, 93912090, -146654905, 238210066, -444675818, 1574980586, + 1126687504, -393974916, 218780119, -136137943, 87350836, -55811266, 34817870, -20914029, + 11949075, -6411935, 3182800, -1431905, 566163, -186629, 45935 }, + { -9021, 59406, -227325, 666112, -1645214, 3592873, -7138594, 13156317, + -22822101, 37730096, -60183196, 93981172, -146758491, 238344927, -444716014, 1570100660, + 1132348255, -395149827, 219348137, -136475744, 87565982, -55950421, 34906822, -20969263, + 11981946, -6430449, 3192532, -1436596, 568184, -187376, 46154 }, + { -8992, 59321, -227153, 665875, -1645087, 3593344, -7140698, 13161925, + -22834244, 37753276, -60223601, 94046529, -146856275, 238470405, -444739123, 1565206612, + 1138004467, -396312870, 219908888, -136808906, 87778133, -56087666, 34994592, -21023795, + 12014422, -6448756, 3202164, -1441243, 570189, -188119, 46372 }, + { -8964, 59233, -226971, 665611, -1644893, 3593669, -7142514, 13167005, + -22845475, 37774954, -60261616, 94108166, -146948265, 238586513, -444745197, 1560298551, + 1143656021, -397463968, 220462336, -137137408, 87987275, -56222992, 35081174, -21077622, + 12046502, -6466854, 3211696, -1445848, 572178, -188857, 46590 }, + { -8935, 59142, -226780, 665320, -1644632, 3593850, -7144044, 13171559, + -22855796, 37795131, -60297245, 94166086, -147034466, 238693266, -444734286, 1555376588, + 1149302795, -398603049, 221008448, -137461231, 88193396, -56356392, 35166562, -21130739, + 12078183, -6484743, 3221126, -1450408, 574151, -189590, 46806 }, + { -8905, 59050, -226580, 665003, -1644306, 3593887, -7145288, 13175588, + -22865208, 37813809, -60330490, 94220294, -147114886, 238790681, -444706442, 1550440833, + 1154944668, -399730038, 221547186, -137780352, 88396482, -56487857, 35250750, -21183144, + 12109462, -6502421, 3230454, -1454924, 576107, -190318, 47021 }, + { -8875, 58955, -226372, 664659, -1643913, 3593780, -7146247, 13179092, + -22873713, 37830991, -60361355, 94270794, -147189533, 238878772, -444661716, 1545491395, + 1160581521, -400844862, 222078518, -138094753, 88596521, -56617378, 35333734, -21234833, + 12140339, -6519886, 3239680, -1459396, 578047, -191041, 47236 }, + { -8845, 58857, -226154, 664288, -1643455, 3593529, -7146921, 13182073, + -22881311, 37846679, -60389842, 94317590, -147258413, 238957555, -444600161, 1540528385, + 1166213232, -401947447, 222602407, -138404411, 88793498, -56744946, 35415507, -21285801, + 12170809, -6537137, 3248802, -1463822, 579970, -191759, 47449 }, + { -8815, 58758, -225927, 663891, -1642932, 3593136, -7147311, 13184531, + -22888006, 37860875, -60415955, 94360687, -147321534, 239027046, -444521828, 1535551915, + 1171839680, -403037721, 223118819, -138709309, 88987402, -56870553, 35496064, -21336047, + 12200872, -6554174, 3257820, -1468204, 581876, -192472, 47662 }, + { -8784, 58656, -225691, 663468, -1642343, 3592600, -7147418, 13186468, + -22893797, 37873582, -60439696, 94400090, -147378904, 239087262, -444426771, 1530562094, + 1177460745, -404115611, 223627720, -139009424, 89178220, -56994191, 35575400, -21385565, + 12230525, -6570995, 3266734, -1472540, 583764, -193180, 47873 }, + { -8753, 58552, -225447, 663018, -1641689, 3591922, -7147243, 13187885, + -22898687, 37884800, -60461069, 94435803, -147430531, 239138220, -444315043, 1525559035, + 1183076306, -405181043, 224129077, -139304738, 89365939, -57115851, 35653509, -21434354, + 12259767, -6587598, 3275542, -1476830, 585636, -193882, 48083 }, + { -8722, 58446, -225193, 662542, -1640971, 3591102, -7146786, 13188782, + -22902677, 37894534, -60480077, 94467831, -147476424, 239179937, -444186697, 1520542849, + 1188686242, -406233945, 224622854, -139595231, 89550546, -57235526, 35730386, -21482409, + 12288594, -6603984, 3284244, -1481074, 587490, -194580, 48293 }, + { -8691, 58338, -224931, 662041, -1640188, 3590141, -7146048, 13189162, + -22905770, 37902785, -60496724, 94496180, -147516590, 239212429, -444041787, 1515513647, + 1194290433, -407274244, 225109019, -139880882, 89732029, -57353207, 35806026, -21529727, + 12317005, -6620149, 3292840, -1485271, 589327, -195272, 48501 }, + { -8659, 58227, -224661, 661514, -1639340, 3589038, -7145029, 13189025, + -22907966, 37909556, -60511014, 94520854, -147551038, 239235716, -443880367, 1510471543, + 1199888758, -408301870, 225587537, -140161674, 89910376, -57468886, 35880423, -21576304, + 12344998, -6636093, 3301328, -1489422, 591145, -195958, 48708 }, + { -8627, 58114, -224382, 660961, -1638429, 3587796, -7143731, 13188372, + -22909268, 37914849, -60522949, 94541860, -147579778, 239249814, -443702493, 1505416646, + 1205481096, -409316749, 226058377, -140437586, 90085574, -57582554, 35953572, -21622138, + 12372571, -6651816, 3309708, -1493525, 592946, -196639, 48914 }, + { -8595, 57999, -224094, 660382, -1637454, 3586414, -7142154, 13187205, + -22909677, 37918666, -60532534, 94559202, -147602817, 239254742, -443508218, 1500349072, + 1211067328, -410318810, 226521504, -140708599, 90257611, -57694205, 36025467, -21667225, + 12399722, -6667315, 3317980, -1497581, 594730, -197315, 49118 }, + { -8562, 57882, -223797, 659778, -1636416, 3584892, -7140299, 13185524, + -22909195, 37921012, -60539772, 94572887, -147620166, 239250518, -443297599, 1495268931, + 1216647333, -411307981, 226976886, -140974695, 90426476, -57803830, 36096104, -21711561, + 12426448, -6682590, 3326142, -1501589, 596495, -197985, 49322 }, + { -8529, 57763, -223493, 659148, -1635314, 3583231, -7138167, 13183331, + -22907824, 37921887, -60544667, 94582919, -147631834, 239237162, -443070691, 1490176337, + 1222220990, -412284192, 227424490, -141235854, 90592156, -57911420, 36165478, -21755144, + 12452748, -6697638, 3334194, -1505549, 598241, -198650, 49525 }, + { -8496, 57642, -223179, 658494, -1634149, 3581431, -7135758, 13180628, + -22905567, 37921296, -60547223, 94589305, -147637831, 239214692, -442827550, 1485071404, + 1227788179, -413247372, 227864284, -141492058, 90754639, -58016970, 36233582, -21797970, + 12478620, -6712461, 3342136, -1509461, 599969, -199309, 49726 }, + { -8463, 57519, -222858, 657814, -1632922, 3579493, -7133074, 13177415, + -22902423, 37919240, -60547445, 94592051, -147638165, 239183129, -442568232, 1479954244, + 1233348780, -414197449, 228296236, -141743288, 90913914, -58120470, 36300413, -21840035, + 12504061, -6727055, 3349966, -1513323, 601679, -199962, 49926 }, + { -8429, 57394, -222528, 657109, -1631631, 3577418, -7130114, 13173694, + -22898397, 37915722, -60545336, 94591163, -147632848, 239142491, -442292794, 1474824971, + 1238902672, -415134353, 228720314, -141989527, 91069968, -58221913, 36365966, -21881337, + 12529070, -6741419, 3357685, -1517137, 603370, -200609, 50125 }, + { -8395, 57266, -222190, 656380, -1630279, 3575206, -7126881, 13169465, + -22893489, 37910746, -60540900, 94586648, -147621889, 239092799, -442001294, 1469683699, + 1244449736, -416058014, 229136486, -142230755, 91222791, -58321291, 36430234, -21921872, + 12553645, -6755554, 3365291, -1520901, 605042, -201251, 50323 }, + { -8361, 57137, -221843, 655626, -1628865, 3572856, -7123374, 13164731, + -22887701, 37904314, -60534142, 94578511, -147605300, 239034073, -441693788, 1464530542, + 1249989852, -416968361, 229544721, -142466955, 91372371, -58418598, 36493214, -21961638, + 12577783, -6769457, 3372784, -1524615, 606695, -201886, 50519 }, + { -8327, 57005, -221489, 654847, -1627389, 3570371, -7119595, 13159493, + -22881037, 37896429, -60525066, 94566759, -147583089, 238966334, -441370334, 1459365614, + 1255522899, -417865326, 229944988, -142698109, 91518697, -58513824, 36554900, -22000631, + 12601483, -6783127, 3380164, -1528279, 608329, -202516, 50714 }, + { -8292, 56872, -221126, 654044, -1625851, 3567750, -7115544, 13153752, + -22873497, 37887095, -60513677, 94551399, -147555270, 238889602, -441030991, 1454189029, + 1261048757, -418748839, 230337255, -142924199, 91661757, -58606964, 36615288, -22038847, + 12624743, -6796564, 3387428, -1531893, 609944, -203140, 50908 }, + { -8257, 56737, -220756, 653216, -1624252, 3564993, -7111222, 13147509, + -22865084, 37876314, -60499979, 94532438, -147521851, 238803899, -440675817, 1449000903, + 1266567307, -419618829, 230721491, -143145208, 91801541, -58698010, 36674372, -22076285, + 12647561, -6809766, 3394578, -1535456, 611539, -203758, 51100 }, + { -8222, 56600, -220377, 652364, -1622593, 3562102, -7106631, 13140766, + -22855799, 37864090, -60483976, 94509882, -147482845, 238709246, -440304871, 1443801350, + 1272078429, -420475228, 231097667, -143361118, 91938036, -58786954, 36732149, -22112940, + 12669935, -6822731, 3401613, -1538969, 613115, -204369, 51291 }, + { -8187, 56460, -219991, 651488, -1620872, 3559077, -7101770, 13133523, + -22845646, 37850426, -60465674, 94483739, -147438263, 238605665, -439918212, 1438590484, + 1277582004, -421317968, 231465752, -143571913, 92071233, -58873790, 36788612, -22148809, + 12691863, -6835460, 3408531, -1542429, 614671, -204975, 51481 }, + { -8151, 56319, -219596, 650588, -1619091, 3555918, -7096642, 13125784, + -22834626, 37835324, -60445077, 94454015, -147388116, 238493179, -439515898, 1433368422, + 1283077911, -422146980, 231825716, -143777574, 92201121, -58958510, 36843758, -22183891, + 12713343, -6847950, 3415332, -1545839, 616207, -205574, 51670 }, + { -8116, 56176, -219194, 649665, -1617250, 3552625, -7091245, 13117548, + -22822741, 37818789, -60422190, 94420719, -147332416, 238371808, -439097991, 1428135278, + 1288566031, -422962195, 232177529, -143978085, 92327688, -59041107, 36897582, -22218181, + 12734373, -6860201, 3422015, -1549196, 617723, -206167, 51857 }, + { -8080, 56032, -218784, 648717, -1615350, 3549200, -7085583, 13108818, + -22809994, 37800823, -60397018, 94383857, -147271176, 238241577, -438664550, 1422891169, + 1294046246, -423763546, 232521161, -144173430, 92450925, -59121574, 36950080, -22251677, + 12754952, -6872211, 3428581, -1552501, 619219, -206753, 52042 }, + { -8044, 55885, -218366, 647746, -1613389, 3545643, -7079655, 13099595, + -22796387, 37781431, -60369566, 94343437, -147204406, 238102507, -438215636, 1417636210, + 1299518435, -424550964, 232856583, -144363591, 92570820, -59199905, 37001246, -22284375, + 12775078, -6883980, 3435028, -1555753, 620695, -207333, 52227 }, + { -8007, 55736, -217941, 646752, -1611369, 3541954, -7073462, 13089880, + -22781922, 37760614, -60339839, 94299467, -147132121, 237954622, -437751309, 1412370516, + 1304982479, -425324382, 233183766, -144548553, 92687364, -59276092, 37051076, -22316273, + 12794748, -6895506, 3441355, -1558952, 622150, -207907, 52409 }, + { -7971, 55586, -217508, 645734, -1609290, 3538134, -7067006, 13079674, + -22766602, 37738378, -60307842, 94251955, -147054331, 237797945, -437271630, 1407094204, + 1310438260, -426083734, 233502682, -144728299, 92800546, -59350129, 37099566, -22347369, + 12813961, -6906788, 3447563, -1562098, 623585, -208474, 52591 }, + { -7934, 55434, -217067, 644693, -1607153, 3534183, -7060287, 13068981, + -22750428, 37714726, -60273581, 94200907, -146971050, 237632500, -436776661, 1401807391, + 1315885658, -426828951, 233813300, -144902813, 92910357, -59422010, 37146712, -22377658, + 12832716, -6917826, 3453650, -1565191, 624999, -209035, 52771 }, + { -7897, 55280, -216619, 643630, -1604957, 3530102, -7053306, 13057800, + -22733404, 37689660, -60237060, 94146333, -146882291, 237458312, -436266463, 1396510193, + 1321324555, -427559968, 234115594, -145072079, 93016785, -59491726, 37192508, -22407138, + 12851010, -6928617, 3459616, -1568230, 626392, -209589, 52949 }, + { -7860, 55124, -216163, 642543, -1602702, 3525892, -7046064, 13046133, + -22715531, 37663185, -60198286, 94088241, -146788067, 237275403, -435741099, 1391202725, + 1326754831, -428276718, 234409535, -145236081, 93119821, -59559273, 37236951, -22435807, + 12868842, -6939162, 3465460, -1571215, 627764, -210136, 53126 }, + { -7823, 54967, -215701, 641433, -1600390, 3521552, -7038562, 13033982, + -22696813, 37635305, -60157264, 94026638, -146688390, 237083799, -435200630, 1385885106, + 1332176369, -428979135, 234695096, -145394805, 93219456, -59624643, 37280036, -22463661, + 12886209, -6949459, 3471182, -1574145, 629115, -210677, 53301 }, + { -7786, 54808, -215230, 640301, -1598020, 3517084, -7030801, 13021349, + -22677251, 37606022, -60113998, 93961533, -146583275, 236883525, -434645120, 1380557452, + 1337589049, -429667152, 234972247, -145548234, 93315679, -59687830, 37321760, -22490698, + 12903111, -6959507, 3476782, -1577021, 630445, -211211, 53475 }, + { -7748, 54647, -214753, 639146, -1595593, 3512488, -7022782, 13008235, + -22656848, 37575342, -60068496, 93892936, -146472735, 236674605, -434074631, 1375219881, + 1342992754, -430340705, 235240963, -145696353, 93408482, -59748827, 37362117, -22516915, + 12919545, -6969304, 3482258, -1579841, 631754, -211738, 53647 }, + { -7710, 54485, -214268, 637969, -1593109, 3507765, -7014506, 12994642, + -22635607, 37543267, -60020762, 93820853, -146356783, 236457064, -433489226, 1369872509, + 1348387365, -430999729, 235501216, -145839147, 93497854, -59807630, 37401104, -22542310, + 12935510, -6978851, 3487609, -1582607, 633040, -212258, 53818 }, + { -7672, 54320, -213776, 636770, -1590568, 3502915, -7005974, 12980572, + -22613530, 37509802, -59970803, 93745295, -146235434, 236230929, -432888970, 1364515453, + 1353772764, -431644157, 235752979, -145976602, 93583786, -59864230, 37438716, -22566879, + 12951004, -6988145, 3492837, -1585316, 634306, -212771, 53987 }, + { -7634, 54155, -213277, 635549, -1587970, 3497939, -6997187, 12966025, + -22590620, 37474950, -59918623, 93666270, -146108703, 235996225, -432273925, 1359148832, + 1359148832, -432273925, 235996225, -146108703, 93666270, -59918623, 37474950, -22590620, + 12966025, -6997187, 3497939, -1587970, 635549, -213277, 54155 }, + { -7596, 53987, -212771, 634306, -1585316, 3492837, -6988145, 12951004, + -22566879, 37438716, -59864230, 93583786, -145976602, 235752979, -431644157, 1353772764, + 1364515453, -432888970, 236230929, -146235434, 93745295, -59970803, 37509802, -22613530, + 12980572, -7005974, 3502915, -1590568, 636770, -213776, 54320 }, + { -7558, 53818, -212258, 633040, -1582607, 3487609, -6978851, 12935510, + -22542310, 37401104, -59807630, 93497854, -145839147, 235501216, -430999729, 1348387365, + 1369872509, -433489226, 236457064, -146356783, 93820853, -60020762, 37543267, -22635607, + 12994642, -7014506, 3507765, -1593109, 637969, -214268, 54485 }, + { -7519, 53647, -211738, 631754, -1579841, 3482258, -6969304, 12919545, + -22516915, 37362117, -59748827, 93408482, -145696353, 235240963, -430340705, 1342992754, + 1375219881, -434074631, 236674605, -146472735, 93892936, -60068496, 37575342, -22656848, + 13008235, -7022782, 3512488, -1595593, 639146, -214753, 54647 }, + { -7481, 53475, -211211, 630445, -1577021, 3476782, -6959507, 12903111, + -22490698, 37321760, -59687830, 93315679, -145548234, 234972247, -429667152, 1337589049, + 1380557452, -434645120, 236883525, -146583275, 93961533, -60113998, 37606022, -22677251, + 13021349, -7030801, 3517084, -1598020, 640301, -215230, 54808 }, + { -7442, 53301, -210677, 629115, -1574145, 3471182, -6949459, 12886209, + -22463661, 37280036, -59624643, 93219456, -145394805, 234695096, -428979135, 1332176369, + 1385885106, -435200630, 237083799, -146688390, 94026638, -60157264, 37635305, -22696813, + 13033982, -7038562, 3521552, -1600390, 641433, -215701, 54967 }, + { -7403, 53126, -210136, 627764, -1571215, 3465460, -6939162, 12868842, + -22435807, 37236951, -59559273, 93119821, -145236081, 234409535, -428276718, 1326754831, + 1391202725, -435741099, 237275403, -146788067, 94088241, -60198286, 37663185, -22715531, + 13046133, -7046064, 3525892, -1602702, 642543, -216163, 55124 }, + { -7364, 52949, -209589, 626392, -1568230, 3459616, -6928617, 12851010, + -22407138, 37192508, -59491726, 93016785, -145072079, 234115594, -427559968, 1321324555, + 1396510193, -436266463, 237458312, -146882291, 94146333, -60237060, 37689660, -22733404, + 13057800, -7053306, 3530102, -1604957, 643630, -216619, 55280 }, + { -7325, 52771, -209035, 624999, -1565191, 3453650, -6917826, 12832716, + -22377658, 37146712, -59422010, 92910357, -144902813, 233813300, -426828951, 1315885658, + 1401807391, -436776661, 237632500, -146971050, 94200907, -60273581, 37714726, -22750428, + 13068981, -7060287, 3534183, -1607153, 644693, -217067, 55434 }, + { -7285, 52591, -208474, 623585, -1562098, 3447563, -6906788, 12813961, + -22347369, 37099566, -59350129, 92800546, -144728299, 233502682, -426083734, 1310438260, + 1407094204, -437271630, 237797945, -147054331, 94251955, -60307842, 37738378, -22766602, + 13079674, -7067006, 3538134, -1609290, 645734, -217508, 55586 }, + { -7246, 52409, -207907, 622150, -1558952, 3441355, -6895506, 12794748, + -22316273, 37051076, -59276092, 92687364, -144548553, 233183766, -425324382, 1304982479, + 1412370516, -437751309, 237954622, -147132121, 94299467, -60339839, 37760614, -22781922, + 13089880, -7073462, 3541954, -1611369, 646752, -217941, 55736 }, + { -7206, 52227, -207333, 620695, -1555753, 3435028, -6883980, 12775078, + -22284375, 37001246, -59199905, 92570820, -144363591, 232856583, -424550964, 1299518435, + 1417636210, -438215636, 238102507, -147204406, 94343437, -60369566, 37781431, -22796387, + 13099595, -7079655, 3545643, -1613389, 647746, -218366, 55885 }, + { -7167, 52042, -206753, 619219, -1552501, 3428581, -6872211, 12754952, + -22251677, 36950080, -59121574, 92450925, -144173430, 232521161, -423763546, 1294046246, + 1422891169, -438664550, 238241577, -147271176, 94383857, -60397018, 37800823, -22809994, + 13108818, -7085583, 3549200, -1615350, 648717, -218784, 56032 }, + { -7127, 51857, -206167, 617723, -1549196, 3422015, -6860201, 12734373, + -22218181, 36897582, -59041107, 92327688, -143978085, 232177529, -422962195, 1288566031, + 1428135278, -439097991, 238371808, -147332416, 94420719, -60422190, 37818789, -22822741, + 13117548, -7091245, 3552625, -1617250, 649665, -219194, 56176 }, + { -7087, 51670, -205574, 616207, -1545839, 3415332, -6847950, 12713343, + -22183891, 36843758, -58958510, 92201121, -143777574, 231825716, -422146980, 1283077911, + 1433368422, -439515898, 238493179, -147388116, 94454015, -60445077, 37835324, -22834626, + 13125784, -7096642, 3555918, -1619091, 650588, -219596, 56319 }, + { -7047, 51481, -204975, 614671, -1542429, 3408531, -6835460, 12691863, + -22148809, 36788612, -58873790, 92071233, -143571913, 231465752, -421317968, 1277582004, + 1438590484, -439918212, 238605665, -147438263, 94483739, -60465674, 37850426, -22845646, + 13133523, -7101770, 3559077, -1620872, 651488, -219991, 56460 }, + { -7007, 51291, -204369, 613115, -1538969, 3401613, -6822731, 12669935, + -22112940, 36732149, -58786954, 91938036, -143361118, 231097667, -420475228, 1272078429, + 1443801350, -440304871, 238709246, -147482845, 94509882, -60483976, 37864090, -22855799, + 13140766, -7106631, 3562102, -1622593, 652364, -220377, 56600 }, + { -6967, 51100, -203758, 611539, -1535456, 3394578, -6809766, 12647561, + -22076285, 36674372, -58698010, 91801541, -143145208, 230721491, -419618829, 1266567307, + 1449000903, -440675817, 238803899, -147521851, 94532438, -60499979, 37876314, -22865084, + 13147509, -7111222, 3564993, -1624252, 653216, -220756, 56737 }, + { -6927, 50908, -203140, 609944, -1531893, 3387428, -6796564, 12624743, + -22038847, 36615288, -58606964, 91661757, -142924199, 230337255, -418748839, 1261048757, + 1454189029, -441030991, 238889602, -147555270, 94551399, -60513677, 37887095, -22873497, + 13153752, -7115544, 3567750, -1625851, 654044, -221126, 56872 }, + { -6886, 50714, -202516, 608329, -1528279, 3380164, -6783127, 12601483, + -22000631, 36554900, -58513824, 91518697, -142698109, 229944988, -417865326, 1255522899, + 1459365614, -441370334, 238966334, -147583089, 94566759, -60525066, 37896429, -22881037, + 13159493, -7119595, 3570371, -1627389, 654847, -221489, 57005 }, + { -6846, 50519, -201886, 606695, -1524615, 3372784, -6769457, 12577783, + -21961638, 36493214, -58418598, 91372371, -142466955, 229544721, -416968361, 1249989852, + 1464530542, -441693788, 239034073, -147605300, 94578511, -60534142, 37904314, -22887701, + 13164731, -7123374, 3572856, -1628865, 655626, -221843, 57137 }, + { -6805, 50323, -201251, 605042, -1520901, 3365291, -6755554, 12553645, + -21921872, 36430234, -58321291, 91222791, -142230755, 229136486, -416058014, 1244449736, + 1469683699, -442001294, 239092799, -147621889, 94586648, -60540900, 37910746, -22893489, + 13169465, -7126881, 3575206, -1630279, 656380, -222190, 57266 }, + { -6765, 50125, -200609, 603370, -1517137, 3357685, -6741419, 12529070, + -21881337, 36365966, -58221913, 91069968, -141989527, 228720314, -415134353, 1238902672, + 1474824971, -442292794, 239142491, -147632848, 94591163, -60545336, 37915722, -22898397, + 13173694, -7130114, 3577418, -1631631, 657109, -222528, 57394 }, + { -6724, 49926, -199962, 601679, -1513323, 3349966, -6727055, 12504061, + -21840035, 36300413, -58120470, 90913914, -141743288, 228296236, -414197449, 1233348780, + 1479954244, -442568232, 239183129, -147638165, 94592051, -60547445, 37919240, -22902423, + 13177415, -7133074, 3579493, -1632922, 657814, -222858, 57519 }, + { -6684, 49726, -199309, 599969, -1509461, 3342136, -6712461, 12478620, + -21797970, 36233582, -58016970, 90754639, -141492058, 227864284, -413247372, 1227788179, + 1485071404, -442827550, 239214692, -147637831, 94589305, -60547223, 37921296, -22905567, + 13180628, -7135758, 3581431, -1634149, 658494, -223179, 57642 }, + { -6643, 49525, -198650, 598241, -1505549, 3334194, -6697638, 12452748, + -21755144, 36165478, -57911420, 90592156, -141235854, 227424490, -412284192, 1222220990, + 1490176337, -443070691, 239237162, -147631834, 94582919, -60544667, 37921887, -22907824, + 13183331, -7138167, 3583231, -1635314, 659148, -223493, 57763 }, + { -6602, 49322, -197985, 596495, -1501589, 3326142, -6682590, 12426448, + -21711561, 36096104, -57803830, 90426476, -140974695, 226976886, -411307981, 1216647333, + 1495268931, -443297599, 239250518, -147620166, 94572887, -60539772, 37921012, -22909195, + 13185524, -7140299, 3584892, -1636416, 659778, -223797, 57882 }, + { -6561, 49118, -197315, 594730, -1497581, 3317980, -6667315, 12399722, + -21667225, 36025467, -57694205, 90257611, -140708599, 226521504, -410318810, 1211067328, + 1500349072, -443508218, 239254742, -147602817, 94559202, -60532534, 37918666, -22909677, + 13187205, -7142154, 3586414, -1637454, 660382, -224094, 57999 }, + { -6520, 48914, -196639, 592946, -1493525, 3309708, -6651816, 12372571, + -21622138, 35953572, -57582554, 90085574, -140437586, 226058377, -409316749, 1205481096, + 1505416646, -443702493, 239249814, -147579778, 94541860, -60522949, 37914849, -22909268, + 13188372, -7143731, 3587796, -1638429, 660961, -224382, 58114 }, + { -6479, 48708, -195958, 591145, -1489422, 3301328, -6636093, 12344998, + -21576304, 35880423, -57468886, 89910376, -140161674, 225587537, -408301870, 1199888758, + 1510471543, -443880367, 239235716, -147551038, 94520854, -60511014, 37909556, -22907966, + 13189025, -7145029, 3589038, -1639340, 661514, -224661, 58227 }, + { -6438, 48501, -195272, 589327, -1485271, 3292840, -6620149, 12317005, + -21529727, 35806026, -57353207, 89732029, -139880882, 225109019, -407274244, 1194290433, + 1515513647, -444041787, 239212429, -147516590, 94496180, -60496724, 37902785, -22905770, + 13189162, -7146048, 3590141, -1640188, 662041, -224931, 58338 }, + { -6397, 48293, -194580, 587490, -1481074, 3284244, -6603984, 12288594, + -21482409, 35730386, -57235526, 89550546, -139595231, 224622854, -406233945, 1188686242, + 1520542849, -444186697, 239179937, -147476424, 94467831, -60480077, 37894534, -22902677, + 13188782, -7146786, 3591102, -1640971, 662542, -225193, 58446 }, + { -6356, 48083, -193882, 585636, -1476830, 3275542, -6587598, 12259767, + -21434354, 35653509, -57115851, 89365939, -139304738, 224129077, -405181043, 1183076306, + 1525559035, -444315043, 239138220, -147430531, 94435803, -60461069, 37884800, -22898687, + 13187885, -7147243, 3591922, -1641689, 663018, -225447, 58552 }, + { -6315, 47873, -193180, 583764, -1472540, 3266734, -6570995, 12230525, + -21385565, 35575400, -56994191, 89178220, -139009424, 223627720, -404115611, 1177460745, + 1530562094, -444426771, 239087262, -147378904, 94400090, -60439696, 37873582, -22893797, + 13186468, -7147418, 3592600, -1642343, 663468, -225691, 58656 }, + { -6273, 47662, -192472, 581876, -1468204, 3257820, -6554174, 12200872, + -21336047, 35496064, -56870553, 88987402, -138709309, 223118819, -403037721, 1171839680, + 1535551915, -444521828, 239027046, -147321534, 94360687, -60415955, 37860875, -22888006, + 13184531, -7147311, 3593136, -1642932, 663891, -225927, 58758 }, + { -6232, 47449, -191759, 579970, -1463822, 3248802, -6537137, 12170809, + -21285801, 35415507, -56744946, 88793498, -138404411, 222602407, -401947447, 1166213232, + 1540528385, -444600161, 238957555, -147258413, 94317590, -60389842, 37846679, -22881311, + 13182073, -7146921, 3593529, -1643455, 664288, -226154, 58857 }, + { -6191, 47236, -191041, 578047, -1459396, 3239680, -6519886, 12140339, + -21234833, 35333734, -56617378, 88596521, -138094753, 222078518, -400844862, 1160581521, + 1545491395, -444661716, 238878772, -147189533, 94270794, -60361355, 37830991, -22873713, + 13179092, -7146247, 3593780, -1643913, 664659, -226372, 58955 }, + { -6150, 47021, -190318, 576107, -1454924, 3230454, -6502421, 12109462, + -21183144, 35250750, -56487857, 88396482, -137780352, 221547186, -399730038, 1154944668, + 1550440833, -444706442, 238790681, -147114886, 94220294, -60330490, 37813809, -22865208, + 13175588, -7145288, 3593887, -1644306, 665003, -226580, 59050 }, + { -6108, 46806, -189590, 574151, -1450408, 3221126, -6484743, 12078183, + -21130739, 35166562, -56356392, 88193396, -137461231, 221008448, -398603049, 1149302795, + 1555376588, -444734286, 238693266, -147034466, 94166086, -60297245, 37795131, -22855796, + 13171559, -7144044, 3593850, -1644632, 665320, -226780, 59142 }, + { -6067, 46590, -188857, 572178, -1445848, 3211696, -6466854, 12046502, + -21077622, 35081174, -56222992, 87987275, -137137408, 220462336, -397463968, 1143656021, + 1560298551, -444745197, 238586513, -146948265, 94108166, -60261616, 37774954, -22845475, + 13167005, -7142514, 3593669, -1644893, 665611, -226971, 59233 }, + { -6026, 46372, -188119, 570189, -1441243, 3202164, -6448756, 12014422, + -21023795, 34994592, -56087666, 87778133, -136808906, 219908888, -396312870, 1138004467, + 1565206612, -444739123, 238470405, -146856275, 94046529, -60223601, 37753276, -22834244, + 13161925, -7140698, 3593344, -1645087, 665875, -227153, 59321 }, + { -5984, 46154, -187376, 568184, -1436596, 3192532, -6430449, 11981946, + -20969263, 34906822, -55950421, 87565982, -136475744, 219348137, -395149827, 1132348255, + 1570100660, -444716014, 238344927, -146758491, 93981172, -60183196, 37730096, -22822101, + 13156317, -7138594, 3592873, -1645214, 666112, -227325, 59406 }, + { -5943, 45935, -186629, 566163, -1431905, 3182800, -6411935, 11949075, + -20914029, 34817870, -55811266, 87350836, -136137943, 218780119, -393974916, 1126687504, + 1574980586, -444675818, 238210066, -146654905, 93912090, -60140400, 37705412, -22809044, + 13150180, -7136202, 3592257, -1645275, 666322, -227489, 59490 }, + { -5902, 45715, -185877, 564125, -1427171, 3172968, -6393215, 11915811, + -20858096, 34727741, -55670211, 87132708, -135795525, 218204870, -392788209, 1121022337, + 1579846282, -444618487, 238065806, -146545511, 93839280, -60095210, 37679222, -22795073, + 13143514, -7133522, 3591495, -1645269, 666505, -227643, 59571 }, + { -5860, 45494, -185120, 562072, -1422395, 3163038, -6374290, 11882157, + -20801469, 34636442, -55527264, 86911613, -135448510, 217622426, -391589782, 1115352874, + 1584697637, -444543969, 237912134, -146430304, 93762738, -60047622, 37651523, -22780186, + 13136318, -7130553, 3590587, -1645195, 666660, -227787, 59649 }, + { -5819, 45272, -184358, 560004, -1417577, 3153010, -6355161, 11848115, + -20744151, 34543977, -55382434, 86687562, -135096920, 217032824, -390379709, 1109679235, + 1589534544, -444452217, 237749036, -146309276, 93682461, -59997636, 37622315, -22764382, + 13128590, -7127295, 3589533, -1645054, 666788, -227923, 59725 }, + { -5777, 45049, -183593, 557920, -1412717, 3142885, -6335831, 11813687, + -20686145, 34450352, -55235730, 86460571, -134740776, 216436098, -389158065, 1104001541, + 1594356894, -444343179, 237576498, -146182423, 93598445, -59945248, 37591595, -22747660, + 13120330, -7123746, 3588331, -1644846, 666888, -228049, 59799 }, + { -5736, 44826, -182822, 555820, -1407815, 3132663, -6316299, 11778876, + -20627456, 34355574, -55087161, 86230653, -134380101, 215832287, -387924925, 1098319914, + 1599164579, -444216809, 237394508, -146049738, 93510688, -59890456, 37559362, -22730017, + 13111538, -7119906, 3586983, -1644569, 666961, -228165, 59870 }, + { -5695, 44602, -182047, 553706, -1402872, 3122346, -6296568, 11743683, + -20568086, 34259649, -54936736, 85997821, -134014914, 215221425, -386680365, 1092634475, + 1603957490, -444073058, 237203053, -145911216, 93419185, -59833259, 37525615, -22711454, + 13102211, -7115774, 3585486, -1644225, 667006, -228272, 59938 }, + { -5653, 44377, -181268, 551576, -1397889, 3111933, -6276639, 11708111, + -20508041, 34162582, -54784464, 85762090, -133645239, 214603551, -385424460, 1086945343, + 1608735522, -443911878, 237002120, -145766853, 93323935, -59773653, 37490351, -22691969, + 13092350, -7111351, 3583842, -1643812, 667023, -228369, 60005 }, + { -5612, 44151, -180485, 549432, -1392864, 3101426, -6256513, 11672163, + -20447323, 34064379, -54630354, 85523474, -133271098, 213978702, -384157285, 1081252640, + 1613498565, -443733222, 236791698, -145616643, 93224934, -59711638, 37453570, -22671561, + 13081953, -7106635, 3582049, -1643331, 667013, -228457, 60068 }, + { -5571, 43924, -179697, 547273, -1387800, 3090825, -6236191, 11635840, + -20385936, 33965046, -54474416, 85281987, -132892511, 213346914, -382878918, 1075556486, + 1618246514, -443537043, 236571774, -145460582, 93122180, -59647211, 37415269, -22650229, + 13071020, -7101626, 3580108, -1642781, 666974, -228535, 60129 }, + { -5530, 43697, -178905, 545099, -1382696, 3080131, -6215674, 11599145, + -20323884, 33864589, -54316659, 85037643, -132509503, 212708225, -381589432, 1069857003, + 1622979262, -443323294, 236342337, -145298665, 93015670, -59580370, 37375448, -22627972, + 13059551, -7096323, 3578017, -1642162, 666907, -228603, 60188 }, + { -5488, 43469, -178109, 542911, -1377553, 3069345, -6194965, 11562080, + -20261171, 33763015, -54157092, 84790456, -132122094, 212062672, -380288906, 1064154311, + 1627696701, -443091928, 236103377, -145130888, 92905402, -59511115, 37334106, -22604788, + 13047543, -7090726, 3575777, -1641474, 666812, -228662, 60244 }, + { -5447, 43240, -177309, 540709, -1372370, 3058468, -6174064, 11524647, + -20197801, 33660329, -53995725, 84540441, -131730307, 211410294, -378977415, 1058448531, + 1632398727, -442842901, 235854881, -144957247, 92791373, -59439442, 37291240, -22580677, + 13034997, -7084835, 3573388, -1640717, 666688, -228711, 60297 }, + { -5406, 43010, -176505, 538492, -1367149, 3047499, -6152972, 11486849, + -20133778, 33556537, -53832567, 84287612, -131334166, 210751127, -377655035, 1052739783, + 1637085234, -442576167, 235596840, -144777737, 92673582, -59365352, 37246850, -22555638, + 13021911, -7078648, 3570848, -1639890, 666536, -228750, 60348 }, + { -5365, 42780, -175697, 536262, -1361890, 3036440, -6131692, 11448689, + -20069105, 33451646, -53667627, 84031985, -130933692, 210085212, -376321843, 1047028188, + 1641756115, -442291680, 235329243, -144592356, 92552027, -59288842, 37200935, -22529670, + 13008286, -7072166, 3568158, -1638994, 666355, -228779, 60396 }, + { -5324, 42549, -174885, 534017, -1356592, 3025292, -6110223, 11410167, + -20003786, 33345662, -53500915, 83773572, -130528909, 209412584, -374977917, 1041313867, + 1646411267, -441989397, 235052081, -144401100, 92426705, -59209911, 37153493, -22502772, + 12994120, -7065387, 3565318, -1638028, 666146, -228798, 60442 }, + { -5282, 42318, -174069, 531760, -1351257, 3014055, -6088569, 11371288, + -19937825, 33238591, -53332441, 83512390, -130119839, 208733284, -373623333, 1035596941, + 1651050583, -441669273, 234765344, -144203965, 92297616, -59128558, 37104524, -22474943, + 12979412, -7058312, 3562326, -1636992, 665908, -228807, 60485 }, + { -5241, 42085, -173249, 529488, -1345884, 3002729, -6066729, 11332052, + -19871227, 33130438, -53162215, 83248452, -129706506, 208047350, -372258167, 1029877529, + 1655673960, -441331264, 234469022, -144000949, 92164757, -59044782, 37054027, -22446183, + 12964163, -7050940, 3559183, -1635885, 665641, -228807, 60525 }, + { -5200, 41853, -172425, 527203, -1340474, 2991317, -6044706, 11292464, + -19803994, 33021212, -52990245, 82981775, -129288933, 207354820, -370882499, 1024155752, + 1660281294, -440975327, 234163108, -143792049, 92028128, -58958581, 37002000, -22416490, + 12948372, -7043270, 3555889, -1634708, 665345, -228796, 60562 }, + { -5159, 41619, -171598, 524905, -1335028, 2979818, -6022500, 11252524, + -19736132, 32910917, -52816543, 82712372, -128867143, 206655733, -369496404, 1018431732, + 1664872479, -440601420, 233847593, -143577263, 91887726, -58869955, 36948443, -22385865, + 12932037, -7035302, 3552443, -1633461, 665020, -228775, 60597 }, + { -5119, 41385, -170768, 522594, -1329545, 2968232, -6000113, 11212235, + -19667644, 32799560, -52641116, 82440259, -128441160, 205950129, -368099960, 1012705588, + 1669447414, -440209499, 233522467, -143356587, 91743552, -58778904, 36893356, -22354305, + 12915159, -7027036, 3548844, -1632143, 664666, -228744, 60629 }, + { -5078, 41151, -169933, 520270, -1324027, 2956562, -5977547, 11171600, + -19598533, 32687148, -52463977, 82165451, -128011007, 205238047, -366693246, 1006977440, + 1674005995, -439799522, 233187724, -143130020, 91595603, -58685425, 36836736, -22321811, + 12897736, -7018472, 3545093, -1630754, 664283, -228702, 60659 }, + { -5037, 40916, -169095, 517934, -1318472, 2944807, -5954802, 11130621, + -19528805, 32573687, -52285133, 81887963, -127576707, 204519527, -365276339, 1001247409, + 1678548118, -439371449, 232843356, -142897561, 91443880, -58589519, 36778585, -22288383, + 12879769, -7009608, 3541190, -1629294, 663870, -228651, 60685 }, + { -4996, 40680, -168254, 515585, -1312883, 2932969, -5931881, 11089301, + -19458463, 32459183, -52104596, 81607810, -127138286, 203794607, -363849317, 995515614, + 1683073682, -438925238, 232489356, -142659207, 91288381, -58491185, 36718901, -22254018, + 12861257, -7000444, 3537133, -1627763, 663428, -228589, 60709 }, + { -4955, 40444, -167409, 513223, -1307258, 2921047, -5908784, 11047641, + -19387511, 32343642, -51922376, 81325008, -126695766, 203063328, -362412257, 989782177, + 1687582583, -438460847, 232125716, -142414956, 91129106, -58390422, 36657683, -22218718, + 12842199, -6990981, 3532923, -1626161, 662957, -228516, 60730 }, + { -4915, 40207, -166561, 510849, -1301600, 2909044, -5885513, 11005645, + -19315952, 32227072, -51738481, 81039573, -126249172, 202325730, -360965240, 984047218, + 1692074721, -437978238, 231752431, -142164808, 90966055, -58287231, 36594932, -22182480, + 12822594, -6981217, 3528560, -1624486, 662455, -228434, 60748 }, + { -4874, 39970, -165709, 508463, -1295906, 2896958, -5862069, 10963315, + -19243792, 32109479, -51552924, 80751519, -125798527, 201581852, -359508342, 978310855, + 1696549993, -437477369, 231369493, -141908762, 90799227, -58181610, 36530646, -22145306, + 12802443, -6971152, 3524043, -1622740, 661925, -228341, 60764 }, + { -4834, 39732, -164855, 506064, -1290179, 2884792, -5838454, 10920653, + -19171034, 31990869, -51365712, 80460862, -125343857, 200831735, -358041642, 972573210, + 1701008299, -436958201, 230976898, -141646817, 90628622, -58073560, 36464825, -22107194, + 12781745, -6960787, 3519372, -1620923, 661364, -228237, 60776 }, + { -4793, 39494, -163997, 503654, -1284419, 2872546, -5814668, 10877661, + -19097683, 31871248, -51176858, 80167618, -124885185, 200075420, -356565219, 966834401, + 1705449538, -436420696, 230574640, -141378971, 90454241, -57963081, 36397470, -22068144, + 12760500, -6950120, 3514547, -1619033, 660773, -228123, 60786 }, + { -4753, 39256, -163136, 501233, -1278625, 2860220, -5790714, 10834343, + -19023742, 31750624, -50986371, 79871803, -124422536, 199312946, -355079152, 961094550, + 1709873608, -435864814, 230162713, -141105226, 90276083, -57850172, 36328579, -22028155, + 12738707, -6939151, 3509567, -1617071, 660153, -227999, 60793 }, + { -4713, 39017, -162271, 498799, -1272799, 2847816, -5766593, 10790700, + -18949216, 31629003, -50794261, 79573432, -123955934, 198544355, -353583520, 955353774, + 1714280411, -435290518, 229741112, -140825581, 90094149, -57734833, 36258153, -21987228, + 12716365, -6927881, 3504432, -1615036, 659502, -227864, 60797 }, + { -4672, 38777, -161404, 496355, -1266940, 2835334, -5742307, 10746735, + -18874108, 31506392, -50600538, 79272521, -123485405, 197769688, -352078401, 949612195, + 1718669846, -434697769, 229309834, -140540035, 89908439, -57617066, 36186191, -21945362, + 12693475, -6916308, 3499143, -1612930, 658822, -227718, 60798 }, + { -4632, 38537, -160534, 493899, -1261049, 2822774, -5717855, 10702451, + -18798423, 31382796, -50405214, 78969086, -123010972, 196988985, -350563875, 943869931, + 1723041813, -434086531, 228868874, -140248589, 89718955, -57496869, 36112694, -21902557, + 12670037, -6904432, 3493698, -1610750, 658111, -227561, 60796 }, + { -4592, 38297, -159661, 491432, -1255126, 2810138, -5693241, 10657850, + -18722165, 31258224, -50208298, 78663144, -122532662, 196202287, -349040020, 938127103, + 1727396214, -433456766, 228418228, -139951244, 89525696, -57374244, 36037661, -21858812, + 12646049, -6892254, 3488098, -1608498, 657370, -227394, 60791 }, + { -4552, 38057, -158785, 488954, -1249172, 2797427, -5668465, 10612935, + -18645339, 31132682, -50009801, 78354710, -122050498, 195409636, -347506917, 932383828, + 1731732951, -432808439, 227957892, -139648000, 89328665, -57249191, 35961093, -21814127, + 12621511, -6879772, 3482343, -1606173, 656598, -227216, 60783 }, + { -4512, 37816, -157906, 486465, -1243187, 2784640, -5643529, 10567707, + -18567948, 31006175, -49809734, 78043800, -121564507, 194611074, -345964644, 926640227, + 1736051923, -432141513, 227487864, -139338859, 89127861, -57121711, 35882989, -21768503, + 12596424, -6866987, 3476431, -1603774, 655796, -227028, 60772 }, + { -4473, 37574, -157025, 483965, -1237171, 2771780, -5618434, 10522170, + -18489996, 30878713, -49608106, 77730431, -121074713, 193806641, -344413282, 920896419, + 1740353035, -431455953, 227008140, -139023822, 88923286, -56991803, 35803349, -21721938, + 12570787, -6853899, 3470364, -1601303, 654964, -226828, 60759 }, + { -4433, 37333, -156140, 481455, -1231124, 2758845, -5593182, 10476326, + -18411488, 30750300, -49404929, 77414619, -120581141, 192996379, -342852909, 915152522, + 1744636188, -430751723, 226518719, -138702889, 88714941, -56859470, 35722175, -21674434, + 12544600, -6840507, 3464141, -1598758, 654101, -226618, 60742 }, + { -4393, 37091, -155253, 478935, -1225048, 2745838, -5567774, 10430178, + -18332429, 30620944, -49200213, 77096380, -120083817, 192180331, -341283606, 909408656, + 1748901284, -430028789, 226019598, -138376063, 88502828, -56724711, 35639466, -21625989, + 12517863, -6826810, 3457761, -1596140, 653207, -226397, 60722 }, + { -4354, 36848, -154364, 476405, -1218942, 2732759, -5542211, 10383728, + -18252822, 30490651, -48993969, 76775731, -119582767, 191358538, -339705453, 903664939, + 1753148227, -429287118, 225510775, -138043345, 88286949, -56587528, 35555223, -21576605, + 12490575, -6812809, 3451224, -1593448, 652282, -226164, 60699 }, + { -4314, 36606, -153472, 473864, -1212807, 2719609, -5516495, 10336978, + -18172671, 30359429, -48786207, 76452687, -119078015, 190531042, -338118528, 897921490, + 1757376921, -428526674, 224992249, -137704739, 88067306, -56447921, 35469445, -21526280, + 12462736, -6798504, 3444531, -1590683, 651327, -225921, 60673 }, + { -4275, 36363, -152577, 471314, -1206643, 2706389, -5490628, 10289932, + -18091982, 30227285, -48576939, 76127267, -118569589, 189697885, -336522913, 892178428, + 1761587270, -427747426, 224464019, -137360245, 87843900, -56305893, 35382135, -21475015, + 12434347, -6783894, 3437681, -1587844, 650341, -225667, 60644 }, + { -4236, 36120, -151680, 468753, -1200451, 2693098, -5464610, 10242591, + -18010757, 30094224, -48366174, 75799485, -118057513, 188859110, -334918688, 886435871, + 1765779177, -426949340, 223926085, -137009866, 87616733, -56161443, 35293291, -21422811, + 12405407, -6768980, 3430674, -1584931, 649323, -225402, 60612 }, + { -4197, 35877, -150781, 466184, -1194230, 2679739, -5438443, 10194959, + -17929002, 29960255, -48153925, 75469360, -117541813, 188014759, -333305932, 880693936, + 1769952548, -426132383, 223378444, -136653606, 87385808, -56014574, 35202914, -21369666, + 12375916, -6753760, 3423510, -1581943, 648275, -225125, 60577 }, + { -4158, 35633, -149879, 463604, -1187981, 2666311, -5412129, 10147037, + -17846721, 29825384, -47940201, 75136907, -117022516, 187164875, -331684725, 874952744, + 1774107287, -425296525, 222821099, -136291467, 87151127, -55865287, 35111006, -21315583, + 12345874, -6738235, 3416189, -1578882, 647195, -224838, 60539 }, + { -4119, 35390, -148975, 461016, -1181705, 2652815, -5385669, 10098829, + -17763918, 29689619, -47725014, 74802143, -116499648, 186309501, -330055149, 869212410, + 1778243301, -424441734, 222254049, -135923453, 86912693, -55713583, 35017568, -21260560, + 12315280, -6722405, 3408710, -1575746, 646085, -224539, 60498 }, + { -4080, 35146, -148068, 458418, -1175402, 2639253, -5359065, 10050337, + -17680598, 29552965, -47508375, 74465086, -115973234, 185448679, -328417284, 863473054, + 1782360494, -423567978, 221677294, -135549567, 86670509, -55559464, 34922598, -21204597, + 12284136, -6706270, 3401073, -1572536, 644943, -224229, 60453 }, + { -4041, 34901, -147160, 455811, -1169072, 2625625, -5332318, 10001563, + -17596764, 29415431, -47290294, 74125752, -115443301, 184582451, -326771210, 857734794, + 1786458774, -422675227, 221090836, -135169812, 86424576, -55402932, 34826100, -21147696, + 12252441, -6689829, 3393279, -1569252, 643770, -223908, 60405 }, + { -4003, 34657, -146249, 453196, -1162715, 2611932, -5305428, 9952511, + -17512421, 29277023, -47070783, 73784157, -114909876, 183710863, -325117008, 851997746, + 1790538046, -421763451, 220494677, -134784193, 86174899, -55243989, 34728073, -21089857, + 12220195, -6673082, 3385327, -1565893, 642565, -223576, 60354 }, + { -3964, 34413, -145337, 450571, -1156333, 2598174, -5278399, 9903182, + -17427574, 29137748, -46849852, 73440320, -114372984, 182833955, -323454758, 846262028, + 1794598218, -420832622, 219888817, -134392713, 85921481, -55082635, 34628518, -21031080, + 12187397, -6656030, 3377217, -1562459, 641329, -223232, 60300 }, + { -3926, 34168, -144422, 447939, -1149925, 2584352, -5251231, 9853580, + -17342227, 28997614, -46627513, 73094258, -113832652, 181951773, -321784541, 840527758, + 1798639198, -419882709, 219273259, -133995378, 85664324, -54918874, 34527438, -20971364, + 12154049, -6638672, 3368948, -1558950, 640061, -222877, 60243 }, + { -3888, 33923, -143505, 445297, -1143491, 2570467, -5223925, 9803707, + -17256385, 28856627, -46403777, 72745986, -113288908, 181064358, -320106438, 834795053, + 1802660893, -418913683, 218648005, -133592191, 85403432, -54752708, 34424831, -20910712, + 12120150, -6621008, 3360522, -1555367, 638762, -222510, 60183 }, + { -3850, 33679, -142587, 442648, -1137032, 2556520, -5196484, 9753565, + -17170051, 28714794, -46178655, 72395523, -112741776, 180171755, -318420530, 829064029, + 1806663212, -417925518, 218013059, -133183158, 85138809, -54584139, 34320701, -20849123, + 12085701, -6603038, 3351937, -1551708, 637431, -222133, 60119 }, + { -3812, 33434, -141666, 439990, -1130549, 2542511, -5168909, 9703157, + -17083230, 28572124, -45952158, 72042886, -112191286, 179274007, -316726897, 823334805, + 1810646063, -416918185, 217368423, -132768284, 84870458, -54413168, 34215047, -20786598, + 12050700, -6584762, 3343194, -1547975, 636069, -221743, 60052 }, + { -3774, 33189, -140744, 437324, -1124041, 2528442, -5141200, 9652486, + -16995927, 28428622, -45724298, 71688092, -111637462, 178371159, -315025621, 817607496, + 1814609356, -415891658, 216714101, -132347573, 84598384, -54239799, 34107872, -20723137, + 12015150, -6566181, 3334293, -1544166, 634675, -221343, 59982 }, + { -3736, 32943, -139820, 434651, -1117509, 2514313, -5113360, 9601554, + -16908146, 28284297, -45495085, 71331158, -111080332, 177463253, -313316783, 811882219, + 1818553000, -414845909, 216050096, -131921032, 84322590, -54064033, 33999176, -20658741, + 11979049, -6547293, 3325233, -1540283, 633248, -220930, 59908 }, + { -3699, 32698, -138894, 431970, -1110954, 2500124, -5085390, 9550365, + -16819891, 28139154, -45264532, 70972102, -110519924, 176550333, -311600463, 806159090, + 1822476905, -413780912, 215376414, -131488665, 84043081, -53885875, 33888962, -20593411, + 11942398, -6528100, 3316014, -1536324, 631790, -220506, 59831 }, + { -3661, 32453, -137966, 429281, -1104376, 2485877, -5057291, 9498920, + -16731167, 27993203, -45032648, 70610941, -109956263, 175632445, -309876743, 800438226, + 1826380981, -412696641, 214693057, -131050480, 83759861, -53705325, 33777229, -20527147, + 11905198, -6508600, 3306636, -1532289, 630301, -220071, 59751 }, + { -3624, 32208, -137037, 426585, -1097774, 2471572, -5029065, 9447222, + -16641979, 27846449, -44799446, 70247693, -109389378, 174709631, -308145704, 794719743, + 1830265140, -411593072, 214000033, -130606482, 83472934, -53522387, 33663981, -20459950, + 11867447, -6488795, 3297100, -1528179, 628779, -219624, 59668 }, + { -3587, 31963, -136107, 423882, -1091150, 2457209, -5000714, 9395274, + -16552330, 27698900, -44564937, 69882376, -108819295, 173781936, -306407428, 789003756, + 1834129292, -410470179, 213297345, -130156678, 83182306, -53337064, 33549219, -20391820, + 11829148, -6468683, 3287405, -1523994, 627225, -219165, 59581 }, + { -3550, 31717, -135175, 421171, -1084504, 2442791, -4972238, 9343078, + -16462226, 27550563, -44329133, 69515006, -108246043, 172849404, -304661994, 783290382, + 1837973349, -409327939, 212584999, -129701074, 82887980, -53149359, 33432943, -20322760, + 11790300, -6448266, 3277551, -1519733, 625639, -218695, 59491 }, + { -3513, 31472, -134241, 418454, -1077836, 2428317, -4943640, 9290638, + -16371671, 27401446, -44092044, 69145602, -107669647, 171912081, -302909486, 777579736, + 1841797224, -408166327, 211863002, -129239677, 82589962, -52959275, 33315157, -20252768, + 11750903, -6427543, 3267538, -1515396, 624020, -218213, 59397 }, + { -3476, 31227, -133306, 415729, -1071147, 2413789, -4914920, 9237955, + -16280669, 27251556, -43853683, 68774181, -107090137, 170970009, -301149983, 771871933, + 1845600829, -406985320, 211131359, -128772495, 82288257, -52766815, 33195861, -20181847, + 11710958, -6406514, 3257367, -1510984, 622370, -217719, 59300 }, + { -3439, 30981, -132370, 412999, -1064436, 2399206, -4886081, 9185033, + -16189225, 27100900, -43614061, 68400761, -106507538, 170023235, -299383568, 766167088, + 1849384077, -405784895, 210390078, -128299534, 81982870, -52571982, 33075058, -20109997, + 11670464, -6385180, 3247036, -1506496, 620687, -217214, 59200 }, + { -3403, 30736, -131432, 410261, -1057704, 2384570, -4857123, 9131874, + -16097343, 26949485, -43373189, 68025361, -105921879, 169071802, -297610321, 760465317, + 1853146881, -404565031, 209639165, -127820803, 81673807, -52374780, 32952749, -20037219, + 11629424, -6363540, 3236546, -1501932, 618973, -216696, 59096 }, + { -3367, 30491, -130493, 407517, -1050953, 2369882, -4828048, 9078481, + -16005028, 26797320, -43131079, 67647996, -105333188, 168115755, -295830325, 754766734, + 1856889155, -403325704, 208878628, -127336309, 81361072, -52175212, 32828936, -19963514, + 11587836, -6341595, 3225898, -1497293, 617225, -216167, 58989 }, + { -3330, 30246, -129553, 404767, -1044181, 2355141, -4798858, 9024856, + -15912284, 26644410, -42887743, 67268687, -104741492, 167155140, -294043660, 749071454, + 1860610814, -402066894, 208108475, -126846060, 81044673, -51973282, 32703622, -19888883, + 11545701, -6319344, 3215090, -1492577, 615446, -215626, 58878 }, + { -3294, 30001, -128611, 402011, -1037389, 2340350, -4769554, 8971002, + -15819117, 26490765, -42643191, 66887450, -104146819, 166190000, -292250408, 743379590, + 1864311772, -400788581, 207328714, -126350064, 80724614, -51768993, 32576809, -19813328, + 11503020, -6296789, 3204123, -1487786, 613634, -215073, 58764 }, + { -3258, 29756, -127669, 399249, -1030578, 2325509, -4740138, 8916922, + -15725529, 26336390, -42397437, 66504303, -103549197, 165220382, -290450651, 737691259, + 1867991946, -399490743, 206539354, -125848331, 80400902, -51562349, 32448498, -19736848, + 11459794, -6273928, 3192998, -1482918, 611789, -214509, 58647 }, + { -3223, 29511, -126725, 396482, -1023748, 2310618, -4710611, 8862619, + -15631527, 26181294, -42150491, 66119265, -102948654, 164246330, -288644470, 732006572, + 1871651249, -398173360, 205740402, -125340868, 80073543, -51353354, 32318692, -19659446, + 11416022, -6250763, 3181713, -1477975, 609912, -213932, 58526 }, + { -3187, 29267, -125781, 393708, -1016899, 2295678, -4680974, 8808094, + -15537115, 26025483, -41902365, 65732354, -102345218, 163267889, -286831947, 726325645, + 1875289599, -396836415, 204931870, -124827684, 79742542, -51142012, 32187393, -19581122, + 11371705, -6227292, 3170269, -1472955, 608003, -213343, 58401 }, + { -3152, 29022, -124835, 390929, -1010032, 2280690, -4651229, 8753351, + -15442296, 25868967, -41653071, 65343587, -101738916, 162285105, -285013163, 720648590, + 1878906912, -395479886, 204113765, -124308790, 79407907, -50928327, 32054604, -19501879, + 11326844, -6203518, 3158666, -1467859, 606061, -212743, 58273 }, + { -3116, 28778, -123889, 388145, -1003147, 2265655, -4621377, 8698393, + -15347077, 25711750, -41402621, 64952983, -101129777, 161298022, -283188199, 714975522, + 1882503105, -394103757, 203286099, -123784194, 79069644, -50712303, 31920326, -19421716, + 11281440, -6179439, 3146905, -1462688, 604086, -212130, 58142 }, + { -3081, 28534, -122942, 385355, -996244, 2250574, -4591421, 8643221, + -15251461, 25553842, -41151026, 64560560, -100517830, 160306688, -281357138, 709306553, + 1886078096, -392708009, 202448882, -123253905, 78727760, -50493945, 31784563, -19340636, + 11235492, -6155056, 3134984, -1457440, 602079, -211505, 58007 }, + { -3046, 28289, -121993, 382561, -989324, 2235447, -4561361, 8587840, + -15155452, 25395250, -40898298, 64166336, -99903102, 159311145, -279520061, 703641796, + 1889631802, -391292625, 201602123, -122717935, 78382262, -50273256, 31647317, -19258639, + 11189003, -6130369, 3122905, -1452116, 600039, -210869, 57868 }, + { -3011, 28046, -121045, 379761, -982387, 2220275, -4531198, 8532251, + -15059057, 25235981, -40644449, 63770330, -99285621, 158311442, -277677049, 697981364, + 1893164143, -389857588, 200745836, -122176292, 78033157, -50050242, 31508590, -19175727, + 11141971, -6105379, 3110667, -1446715, 597966, -210220, 57726 }, + { -2977, 27802, -120095, 376957, -975433, 2205059, -4500935, 8476457, + -14962278, 25076043, -40389491, 63372559, -98665417, 157307622, -275828184, 692325369, + 1896675037, -388402882, 199880029, -121628988, 77680451, -49824906, 31368385, -19091902, + 11094398, -6080085, 3098270, -1441239, 595860, -209559, 57581 }, + { -2942, 27558, -119145, 374148, -968463, 2189799, -4470573, 8420461, + -14865121, 24915443, -40133436, 62973043, -98042517, 156299732, -273973548, 686673924, + 1900164403, -386928491, 199004717, -121076032, 77324153, -49597254, 31226705, -19007164, + 11046285, -6054488, 3085714, -1435686, 593722, -208886, 57431 }, + { -2908, 27315, -118194, 371334, -961478, 2174496, -4440114, 8364265, + -14767590, 24754189, -39876295, 62571799, -97416949, 155287817, -272113222, 681027140, + 1903632161, -385434400, 198119910, -120517437, 76964270, -49367290, 31083553, -18921516, + 10997632, -6028588, 3073000, -1430057, 591551, -208201, 57278 }, + { -2874, 27072, -117242, 368516, -954476, 2159152, -4409557, 8307873, + -14669690, 24592288, -39618081, 62168846, -96788743, 154271923, -270247287, 675385130, + 1907078233, -383920593, 197225622, -119953212, 76600809, -49135018, 30938931, -18834959, + 10948440, -6002386, 3060128, -1424352, 589347, -207504, 57122 }, + { -2840, 26829, -116290, 365694, -947460, 2143766, -4378907, 8251287, + -14571426, 24429748, -39358805, 61764202, -96157927, 153252097, -268375826, 669748005, + 1910502538, -382387056, 196321865, -119383368, 76233778, -48900445, 30792842, -18747494, + 10898709, -5975882, 3047096, -1418570, 587110, -206794, 56962 }, + { -2806, 26586, -115337, 362868, -940429, 2128340, -4348163, 8194509, + -14472802, 24266577, -39098479, 61357887, -95524530, 152228383, -266498919, 664115876, + 1913904997, -380833776, 195408652, -118807919, 75863185, -48663574, 30645290, -18659124, + 10848442, -5949075, 3033907, -1412712, 584840, -206072, 56798 }, + { -2772, 26344, -114384, 360037, -933383, 2112874, -4317327, 8137542, + -14373823, 24102782, -38837116, 60949917, -94888579, 151200828, -264616649, 658488855, + 1917285534, -379260740, 194485998, -118226875, 75489039, -48424412, 30496277, -18569849, + 10797637, -5921967, 3020559, -1406778, 582538, -205338, 56631 }, + { -2739, 26102, -113431, 357203, -926323, 2097369, -4286401, 8080390, + -14274493, 23938370, -38574727, 60540312, -94250104, 150169478, -262729096, 652867053, + 1920644069, -377667934, 193553915, -117640248, 75111347, -48182962, 30345806, -18479671, + 10746297, -5894558, 3007053, -1400768, 580202, -204592, 56460 }, + { -2705, 25860, -112477, 354365, -919249, 2081826, -4255386, 8023054, + -14174818, 23773349, -38311324, 60129091, -93609134, 149134379, -260836343, 647250579, + 1923980526, -376055346, 192612420, -117048050, 74730119, -47939232, 30193881, -18388592, + 10694422, -5866848, 2993389, -1394682, 577834, -203834, 56285 }, + { -2672, 25619, -111523, 351524, -912161, 2066245, -4224283, 7965537, + -14074801, 23607727, -38046919, 59716272, -92965698, 148095577, -258938471, 641639544, + 1927294828, -374422964, 191661525, -116450294, 74345361, -47693225, 30040504, -18296615, + 10642012, -5838838, 2979567, -1388519, 575432, -203063, 56107 }, + { -2639, 25378, -110569, 348679, -905061, 2050628, -4193095, 7907843, + -13974447, 23441512, -37781525, 59301873, -92319823, 147053118, -257035560, 636034059, + 1930586899, -372770778, 190701247, -115846993, 73957084, -47444948, 29885680, -18203740, + 10589070, -5810527, 2965587, -1382280, 572998, -202280, 55925 }, + { -2606, 25137, -109614, 345831, -897947, 2034974, -4161822, 7849974, + -13873762, 23274711, -37515153, 58885914, -91671540, 146007049, -255127694, 630434233, + 1933856663, -371098777, 189731601, -115238159, 73565296, -47194406, 29729411, -18109970, + 10535595, -5781917, 2951450, -1375965, 570530, -201484, 55739 }, + { -2574, 24896, -108660, 342980, -890822, 2019286, -4130467, 7791932, + -13772749, 23107331, -37247816, 58468413, -91020876, 144957415, -253214952, 624840175, + 1937104044, -369406949, 188752602, -114623806, 73170006, -46941605, 29571701, -18015305, + 10481588, -5753007, 2937155, -1369574, 568030, -200676, 55550 }, + { -2541, 24656, -107705, 340126, -883684, 2003563, -4099030, 7733720, + -13671413, 22939381, -36979525, 58049388, -90367862, 143904264, -251297417, 619251996, + 1940328969, -367695287, 187764267, -114003947, 72771223, -46686550, 29412553, -17919750, + 10427051, -5723799, 2922702, -1363106, 565496, -199856, 55356 }, + { -2509, 24416, -106750, 337269, -876534, 1987806, -4067512, 7675341, + -13569760, 22770867, -36710293, 57628859, -89712525, 142847641, -249375170, 613669804, + 1943531362, -365963779, 186766613, -113378595, 72368957, -46429248, 29251971, -17823304, + 10371985, -5694292, 2908093, -1356563, 562930, -199024, 55160 }, + { -2477, 24177, -105795, 334409, -869373, 1972016, -4035917, 7616798, + -13467793, 22601798, -36440131, 57206844, -89054896, 141787593, -247448291, 608093708, + 1946711150, -364212419, 185759656, -112747765, 71963216, -46169705, 29089958, -17725971, + 10316390, -5664487, 2893326, -1349943, 560330, -198179, 54959 }, + { -2445, 23937, -104840, 331547, -862201, 1956194, -4004244, 7558093, + -13365517, 22432182, -36169052, 56783363, -88395002, 140724166, -245516863, 602523817, + 1949868260, -362441196, 184743414, -112111470, 71554011, -45907926, 28926518, -17627752, + 10260268, -5634384, 2878403, -1343247, 557698, -197321, 54755 }, + { -2413, 23699, -103885, 328682, -855018, 1940340, -3972496, 7499229, + -13262938, 22262025, -35897069, 56358433, -87732874, 139657407, -243580966, 596960238, + 1953002619, -360650105, 183717904, -111469724, 71141351, -45643919, 28761655, -17528649, + 10203620, -5603985, 2863322, -1336475, 555032, -196452, 54546 }, + { -2381, 23460, -102930, 325815, -847824, 1924456, -3940674, 7440209, + -13160059, 22091336, -35624192, 55932073, -87068540, 138587362, -241640682, 591403080, + 1956114154, -358839138, 182683145, -110822543, 70725246, -45377688, 28595372, -17428665, + 10146446, -5573289, 2848085, -1329628, 552333, -195569, 54335 }, + { -2350, 23222, -101975, 322946, -840621, 1908541, -3908779, 7381035, + -13056885, 21920123, -35350435, 55504304, -86402029, 137514078, -239696091, 585852451, + 1959202795, -357008289, 181639155, -110169941, 70305706, -45109241, 28427674, -17327802, + 10088748, -5542296, 2832692, -1322704, 549601, -194675, 54119 }, + { -2319, 22985, -101021, 320075, -833407, 1892597, -3876813, 7321711, + -12953421, 21748392, -35075809, 55075142, -85733371, 136437602, -237747275, 580308458, + 1962268470, -355157550, 180585952, -109511933, 69882742, -44838584, 28258564, -17226061, + 10030528, -5511008, 2817142, -1315705, 546836, -193767, 53899 }, + { -2288, 22748, -100067, 317201, -826185, 1876625, -3844777, 7262238, + -12849673, 21576152, -34800327, 54644608, -85062595, 135357979, -235794316, 574771207, + 1965311107, -353286917, 179523556, -108848533, 69456363, -44565724, 28088046, -17123446, + 9971785, -5479426, 2801437, -1308629, 544038, -192848, 53676 }, + { -2257, 22511, -99113, 314326, -818953, 1860625, -3812673, 7202620, + -12745643, 21403410, -34524001, 54212720, -84389731, 134275257, -233837292, 569240807, + 1968330638, -351396386, 178451987, -108179758, 69026581, -44290668, 27916125, -17019957, + 9912521, -5447548, 2785576, -1301478, 541207, -191915, 53449 }, + { -2226, 22275, -98159, 311450, -811712, 1844597, -3780502, 7142859, + -12641337, 21230175, -34246843, 53779498, -83714806, 133189482, -231876287, 563717363, + 1971326992, -349485950, 177371263, -107505624, 68593405, -44013421, 27742803, -16915599, + 9852738, -5415377, 2769559, -1294252, 538342, -190971, 53218 }, + { -2196, 22039, -97206, 308571, -804463, 1828544, -3748267, 7082958, + -12536761, 21056453, -33968866, 53344959, -83037852, 132100702, -229911380, 558200982, + 1974300099, -347555607, 176281407, -106826145, 68156847, -43733991, 27568087, -16810372, + 9792437, -5382912, 2753386, -1286949, 535445, -190013, 52983 }, + { -2165, 21803, -96253, 305692, -797206, 1812464, -3715967, 7022920, + -12431917, 20882253, -33690081, 52909124, -82358897, 131008962, -227942653, 552691770, + 1977249893, -345605353, 175182437, -106141339, 67716917, -43452386, 27391979, -16704279, + 9731619, -5350154, 2737059, -1279571, 532514, -189044, 52745 }, + { -2135, 21569, -95300, 302811, -789941, 1796360, -3683605, 6962747, + -12326812, 20707581, -33410500, 52472011, -81677970, 129914309, -225970185, 547189832, + 1980176304, -343635185, 174074376, -105451221, 67273627, -43168611, 27214483, -16597324, + 9670285, -5317104, 2720577, -1272117, 529551, -188061, 52502 }, + { -2105, 21334, -94348, 299929, -782669, 1780232, -3651182, 6902442, + -12221449, 20532447, -33130137, 52033639, -80995101, 128816790, -223994059, 541695274, + 1983079265, -341645100, 172957244, -104755808, 66826988, -42882675, 27035606, -16489507, + 9608436, -5283763, 2703940, -1264588, 526554, -187066, 52256 }, + { -2076, 21100, -93397, 297046, -775390, 1764080, -3618699, 6842008, + -12115834, 20356858, -32849004, 51594027, -80310320, 127716453, -222014353, 536208202, + 1985958708, -339635098, 171831064, -104055117, 66377011, -42594584, 26855350, -16380833, + 9546074, -5250131, 2687149, -1256984, 523524, -186059, 52006 }, + { -2046, 20867, -92446, 294162, -768103, 1747906, -3586159, 6781448, + -12009971, 20180821, -32567112, 51153195, -79623656, 126613343, -220031150, 530728719, + 1988814568, -337605176, 170695856, -103349165, 65923708, -42304347, 26673720, -16271302, + 9483201, -5216208, 2670203, -1249304, 520461, -185039, 51752 }, + { -2017, 20634, -91496, 291277, -760811, 1731709, -3553562, 6720763, + -11903865, 20004343, -32284474, 50711161, -78935138, 125507508, -218044529, 525256930, + 1991646778, -335555334, 169551645, -102637970, 65467090, -42011969, 26490721, -16160919, + 9419817, -5181995, 2653104, -1241549, 517365, -184006, 51494 }, + { -1988, 20402, -90546, 288392, -753512, 1715492, -3520910, 6659958, + -11797520, 19827434, -32001102, 50267944, -78244795, 124398993, -216054571, 519792940, + 1994455274, -333485572, 168398453, -101921548, 65007169, -41717460, 26306357, -16049685, + 9355923, -5147494, 2635851, -1233719, 514237, -182961, 51232 }, + { -1959, 20170, -89597, 285506, -746208, 1699253, -3488205, 6599034, + -11690942, 19650100, -31717008, 49823564, -77552658, 123287848, -214061355, 514336853, + 1997239989, -331395889, 167236302, -101199917, 64543957, -41420826, 26120633, -15937603, + 9291522, -5112704, 2618445, -1225814, 511075, -181903, 50966 }, + { -1930, 19938, -88649, 282620, -738898, 1682995, -3455447, 6537994, + -11584134, 19472350, -31432206, 49378039, -76858756, 122174117, -212064963, 508888771, + 2000000860, -329286288, 166065217, -100473096, 64077467, -41122075, 25933554, -15824676, + 9226615, -5077626, 2600886, -1217834, 507880, -180833, 50697 }, + { -1901, 19708, -87702, 279734, -731583, 1666718, -3422639, 6476841, + -11477102, 19294191, -31146706, 48931389, -76163119, 121057848, -210065474, 503448799, + 2002737822, -327156768, 164885221, -99741102, 63607710, -40821216, 25745124, -15710906, + 9161203, -5042261, 2583174, -1209780, 504652, -179749, 50423 }, + { -1873, 19477, -86755, 276848, -724263, 1650423, -3389781, 6415578, + -11369850, 19115630, -30860522, 48483633, -75465775, 119939087, -208062969, 498017039, + 2005450814, -325007333, 163696339, -99003954, 63134699, -40518255, 25555348, -15596297, + 9095288, -5006610, 2565309, -1201650, 501391, -178654, 50146 }, + { -1845, 19248, -85809, 273961, -716939, 1634110, -3356876, 6354207, + -11262383, 18936676, -30573666, 48034790, -74766755, 118817882, -206057527, 492593593, + 2008139771, -322837984, 162498596, -98261671, 62658446, -40213202, 25364232, -15480851, + 9028871, -4970674, 2547293, -1193446, 498097, -177545, 49865 }, + { -1817, 19019, -84865, 271075, -709610, 1617780, -3323924, 6292732, + -11154706, 18757336, -30286150, 47584879, -74066087, 117694280, -204049229, 487178565, + 2010804631, -320648725, 161292016, -97514271, 62178965, -39906064, 25171779, -15364571, + 8961953, -4934452, 2529124, -1185167, 494770, -176424, 49579 }, + { -1789, 18790, -83921, 268189, -702278, 1601434, -3290927, 6231154, + -11046822, 18577618, -29997986, 47133919, -73363803, 116568326, -202038153, 481772056, + 2013445334, -318439559, 160076625, -96761773, 61696267, -39596849, 24977996, -15247460, + 8894537, -4897947, 2510805, -1176814, 491410, -175291, 49290 }, + { -1761, 18562, -82978, 265303, -694942, 1585072, -3257887, 6169476, + -10938738, 18397530, -29709187, 46681929, -72659931, 115440069, -200024381, 476374167, + 2016061817, -316210490, 158852449, -96004198, 61210367, -39285566, 24782887, -15129521, + 8826623, -4861158, 2492333, -1168386, 488017, -174144, 48997 }, + { -1734, 18335, -82036, 262418, -687603, 1568696, -3224805, 6107702, + -10830458, 18217079, -29419765, 46228929, -71954501, 114309555, -198007990, 470985001, + 2018654021, -313961522, 157619514, -95241563, 60721276, -38972224, 24586458, -15010756, + 8758214, -4824087, 2473711, -1159884, 484592, -172985, 48700 }, + { -1706, 18108, -81095, 259534, -680261, 1552305, -3191683, 6045833, + -10721985, 18036274, -29129732, 45774938, -71247542, 113176830, -195989062, 465604657, + 2021221885, -311692662, 156377846, -94473890, 60229009, -38656830, 24388713, -14891170, + 8689311, -4786734, 2454939, -1151308, 481133, -171814, 48398 }, + { -1679, 17882, -80155, 256650, -672917, 1535902, -3158521, 5983872, + -10613326, 17855121, -28839101, 45319975, -70539085, 112041943, -193967675, 460233237, + 2023765349, -309403914, 155127472, -93701197, 59733579, -38339393, 24189657, -14770764, + 8619916, -4749100, 2436016, -1142659, 477642, -170630, 48093 }, + { -1653, 17656, -79216, 253768, -665570, 1519485, -3125322, 5921823, + -10504484, 17673629, -28547884, 44864059, -69829158, 110904938, -191943908, 454870841, + 2026284356, -307095284, 153868420, -92923506, 59234998, -38019923, 23989297, -14649542, + 8550030, -4711185, 2416944, -1133935, 474118, -169433, 47784 }, + { -1626, 17432, -78279, 250886, -658221, 1503057, -3092086, 5859688, + -10395464, 17491806, -28256093, 44407209, -69117792, 109765864, -189917841, 449517569, + 2028778846, -304766781, 152600718, -92140836, 58733282, -37698427, 23787638, -14527507, + 8479654, -4672992, 2397722, -1125138, 470561, -168223, 47471 }, + { -1599, 17207, -77343, 248005, -650871, 1486618, -3058816, 5797468, + -10286272, 17309658, -27963741, 43949445, -68405016, 108624767, -187889553, 444173521, + 2031248762, -302418410, 151324392, -91353209, 58228444, -37374915, 23584684, -14404662, + 8408792, -4634520, 2378351, -1116267, 466972, -167001, 47154 }, + { -1573, 16984, -76408, 245126, -643519, 1470168, -3025512, 5735169, + -10176911, 17127195, -27670840, 43490785, -67690859, 107481694, -185859123, 438838795, + 2033694047, -300050179, 150039472, -90560645, 57720498, -37049395, 23380442, -14281011, + 8337444, -4595771, 2358831, -1107322, 463350, -165766, 46833 }, + { -1547, 16761, -75474, 242248, -636167, 1453708, -2992176, 5672790, + -10067386, 16944423, -27377403, 43031250, -66975353, 106336692, -183826630, 433513491, + 2036114644, -297662098, 148745987, -89763165, 57209457, -36721877, 23174917, -14156556, + 8265612, -4556745, 2339163, -1098305, 459695, -164519, 46508 }, + { -1521, 16539, -74542, 239372, -628813, 1437239, -2958810, 5610337, + -9957702, 16761351, -27083441, 42570857, -66258525, 105189807, -181792152, 428197707, + 2038510496, -295254174, 147443965, -88960790, 56695337, -36392370, 22968114, -14031301, + 8193298, -4517443, 2319347, -1089214, 456008, -163258, 46179 }, + { -1496, 16317, -73610, 236497, -621460, 1420762, -2925415, 5547810, + -9847864, 16577985, -26788967, 42109627, -65540406, 104041086, -179755768, 422891541, + 2040881549, -292826418, 146133435, -88153543, 56178151, -36060884, 22760040, -13905250, + 8120504, -4477866, 2299384, -1080050, 452288, -161986, 45846 }, + { -1470, 16096, -72681, 233624, -614106, 1404277, -2891991, 5485213, + -9737876, 16394334, -26493994, 41647578, -64821025, 102890577, -177717557, 417595092, + 2043227747, -290378839, 144814429, -87341444, 55657915, -35727426, 22550700, -13778404, + 8047232, -4438015, 2279273, -1070813, 448535, -160700, 45509 }, + { -1445, 15876, -71753, 230752, -606753, 1387785, -2858542, 5422548, + -9627743, 16210406, -26198533, 41184730, -64100412, 101738325, -175677597, 412308457, + 2045549037, -287911449, 143486975, -86524516, 55134643, -35392008, 22340100, -13650769, + 7973483, -4397891, 2259016, -1061504, 444750, -159402, 45167 }, + { -1420, 15656, -70826, 227883, -599400, 1371287, -2825068, 5359819, + -9517469, 16026208, -25902598, 40721101, -63378597, 100584377, -173635966, 407031733, + 2047845363, -285424257, 142151105, -85702782, 54608349, -35054638, 22128246, -13522348, + 7899259, -4357495, 2238612, -1052122, 440933, -158091, 44822 }, + { -1395, 15437, -69901, 225016, -592048, 1354783, -2791570, 5297027, + -9407059, 15841748, -25606200, 40256712, -62655609, 99428780, -171592743, 401765016, + 2050116673, -282917276, 140806849, -84876262, 54079049, -34715326, 21915143, -13393143, + 7824563, -4316827, 2218063, -1042668, 437083, -156768, 44473 }, + { -1370, 15219, -68977, 222151, -584697, 1338274, -2758050, 5234176, + -9296518, 15657033, -25309351, 39791581, -61931478, 98271581, -169548005, 396508404, + 2052362915, -280390518, 139454238, -84044981, 53546758, -34374082, 21700798, -13263158, + 7749395, -4275890, 2197368, -1033141, 433201, -155432, 44120 }, + { -1346, 15002, -68055, 219288, -577348, 1321761, -2724510, 5171267, + -9185851, 15472072, -25012064, 39325727, -61206234, 97112827, -167501830, 391261992, + 2054584035, -277843995, 138093305, -83208960, 53011491, -34030916, 21485217, -13132398, + 7673759, -4234683, 2176528, -1023543, 429286, -154083, 43762 }, + { -1322, 14785, -67134, 216428, -570000, 1305245, -2690950, 5108304, + -9075061, 15286872, -24714352, 38859170, -60479906, 95952563, -165454297, 386025876, + 2056779983, -275277721, 136724081, -82368224, 52473264, -33685837, 21268406, -13000864, + 7597656, -4193208, 2155544, -1013872, 425339, -152722, 43401 }, + { -1298, 14569, -66215, 213571, -562655, 1288726, -2657373, 5045289, + -8964154, 15101440, -24416226, 38391928, -59752524, 94790836, -163405482, 380800152, + 2058950708, -272691710, 135346599, -81522795, 51932092, -33338855, 21050371, -12868562, + 7521087, -4151465, 2134415, -1004130, 421360, -151348, 43036 }, + { -1274, 14354, -65298, 210716, -555312, 1272204, -2623779, 4982226, + -8853134, 14915785, -24117700, 37924022, -59024117, 93627694, -161355463, 375584914, + 2061096159, -270085976, 133960892, -80672696, 51387990, -32989982, 20831118, -12735495, + 7444056, -4109457, 2113143, -994316, 417349, -149961, 42666 }, + { -1250, 14140, -64383, 207864, -547971, 1255681, -2590170, 4919115, + -8742006, 14729914, -23818784, 37455469, -58294714, 92463182, -159304318, 370380256, + 2063216286, -267460534, 132566991, -79817953, 50840975, -32639226, 20610653, -12601666, + 7366564, -4067183, 2091728, -984431, 413306, -148562, 42293 }, + { -1227, 13926, -63469, 205014, -540634, 1239157, -2556547, 4855961, + -8630775, 14543835, -23519492, 36986290, -57564347, 91297347, -157252124, 365186274, + 2065311041, -264815399, 131164932, -78958587, 50291062, -32286597, 20388984, -12467079, + 7288613, -4024645, 2070170, -974475, 409231, -147151, 41915 }, + { -1203, 13713, -62557, 202168, -533300, 1222634, -2522912, 4792765, + -8519444, 14357555, -23219835, 36516503, -56833043, 90130235, -155198957, 360003060, + 2067380374, -262150588, 129754747, -78094624, 49738269, -31932108, 20166115, -12331738, + 7210205, -3981843, 2048470, -964448, 405123, -145726, 41534 }, + { -1180, 13501, -61647, 199325, -525969, 1206110, -2489267, 4729531, + -8408019, 14171082, -22919827, 36046127, -56100833, 88961893, -153144895, 354830709, + 2069424238, -259466116, 128336472, -77226089, 49182610, -31575767, 19942055, -12195647, + 7131342, -3938780, 2026628, -954350, 400984, -144290, 41148 }, + { -1157, 13289, -60738, 196485, -518643, 1189588, -2455611, 4666260, + -8296504, 13984423, -22619479, 35575182, -55367747, 87792367, -151090015, 349669313, + 2071442585, -256762002, 126910140, -76353004, 48624102, -31217585, 19716808, -12058809, + 7052027, -3895456, 2004645, -944182, 396813, -142840, 40758 }, + { -1135, 13079, -59832, 193648, -511320, 1173068, -2421948, 4602956, + -8184904, 13797587, -22318803, 35103687, -54633813, 86621703, -149034393, 344518965, + 2073435368, -254038262, 125475786, -75475396, 48062762, -30857574, 19490382, -11921228, + 6972261, -3851872, 1982521, -933943, 392611, -141378, 40364 }, + { -1112, 12869, -58927, 190815, -504002, 1156550, -2388278, 4539621, + -8073224, 13610581, -22017812, 34631661, -53899061, 85449948, -146978105, 339379757, + 2075402541, -251294915, 124033446, -74593290, 47498606, -30495743, 19262784, -11782909, + 6892048, -3808029, 1960257, -923634, 388376, -139904, 39966 }, + { -1090, 12660, -58025, 187986, -496689, 1140036, -2354603, 4476258, + -7961467, 13423413, -21716518, 34159122, -53163520, 84277148, -144921228, 334251781, + 2077344058, -248531980, 122583155, -73706710, 46931652, -30132104, 19034020, -11643856, + 6811387, -3763929, 1937854, -913256, 384110, -138417, 39564 }, + { -1068, 12451, -57124, 185160, -489381, 1123526, -2320923, 4412869, + -7849638, 13236090, -21414934, 33686091, -52427221, 83103348, -142863839, 329135129, + 2079259875, -245749476, 121124949, -72815683, 46361915, -29766667, 18804097, -11504071, + 6730284, -3719572, 1915311, -902807, 379812, -136917, 39158 }, + { -1046, 12244, -56226, 182338, -482078, 1107020, -2287241, 4349457, + -7737743, 13048619, -21113071, 33212585, -51690192, 81928596, -140806012, 324029892, + 2081149946, -242947422, 119658865, -71920233, 45789414, -29399443, 18573022, -11363560, + 6648738, -3674960, 1892629, -892289, 375483, -135405, 38748 }, + { -1024, 12037, -55329, 179520, -474781, 1090519, -2253558, 4286024, + -7625785, 12861009, -20810941, 32738625, -50952463, 80752936, -138747824, 318936160, + 2083014227, -240125839, 118184939, -71020386, 45214165, -29030444, 18340801, -11222326, + 6566753, -3630093, 1869810, -881702, 371122, -133880, 38334 }, + { -1003, 11831, -54435, 176705, -467489, 1074025, -2219874, 4222574, + -7513769, 12673267, -20508557, 32264229, -50214063, 79576416, -136689351, 313854024, + 2084852676, -237284748, 116703208, -70116170, 44636186, -28659681, 18107442, -11080373, + 6484331, -3584974, 1846853, -871045, 366730, -132343, 37915 }, + { -982, 11626, -53543, 173895, -460204, 1057537, -2186193, 4159107, + -7401700, 12485401, -20205931, 31789415, -49475022, 78399081, -134630668, 308783574, + 2086665250, -234424171, 115213710, -69207609, 44055494, -28287164, 17872951, -10937706, + 6401474, -3539603, 1823759, -860320, 362306, -130794, 37493 }, + { -961, 11422, -52653, 171089, -452926, 1041056, -2152514, 4095628, + -7289582, 12297418, -19903076, 31314204, -48735369, 77220976, -132571850, 303724899, + 2088451906, -231544129, 113716483, -68294731, 43472106, -27912905, 17637335, -10794329, + 6318185, -3493981, 1800529, -849526, 357852, -129232, 37066 }, + { -940, 11219, -51765, 168288, -445654, 1024583, -2118839, 4032139, + -7177420, 12109325, -19600002, 30838614, -47995133, 76042149, -130512973, 298678087, + 2090212602, -228644645, 112211564, -67377562, 42886041, -27536916, 17400603, -10650246, + 6234465, -3448109, 1777163, -838663, 353366, -127658, 36636 }, + { -919, 11016, -50879, 165491, -438389, 1008118, -2085169, 3968642, + -7065217, 11921131, -19296723, 30362664, -47254344, 74862644, -128454111, 293643229, + 2091947299, -225725743, 110698992, -66456129, 42297316, -27159208, 17162760, -10505461, + 6150318, -3401990, 1753661, -827733, 348849, -126071, 36201 }, + { -899, 10815, -49995, 162698, -431131, 991663, -2051507, 3905139, + -6952980, 11732842, -18993251, 29886373, -46513030, 73682507, -126395340, 288620412, + 2093655956, -222787445, 109178806, -65530460, 41705949, -26779793, 16923814, -10359978, + 6065745, -3355623, 1730025, -816735, 344301, -124472, 35762 }, + { -879, 10614, -49114, 159910, -423881, 975217, -2017852, 3841634, + -6840711, 11544467, -18689597, 29409760, -45771221, 72501784, -124336734, 283609724, + 2095338532, -219829776, 107651045, -64600581, 41111959, -26398682, 16683772, -10213803, + 5980750, -3309011, 1706255, -805668, 339722, -122860, 35319 }, + { -859, 10414, -48235, 157127, -416639, 958782, -1984207, 3778129, + -6728416, 11356013, -18385774, 28932843, -45028947, 71320521, -122278367, 278611252, + 2096994989, -216852761, 106115748, -63666520, 40515364, -26015887, 16442641, -10066938, + 5895334, -3262155, 1682352, -794535, 335112, -121236, 34872 }, + { -839, 10215, -47358, 154349, -409406, 942358, -1950573, 3714626, + -6616100, 11167487, -18081794, 28455643, -44286236, 70138763, -120220314, 273625084, + 2098625289, -213856425, 104572956, -62728305, 39916181, -25631421, 16200430, -9919389, + 5809500, -3215055, 1658315, -783334, 330472, -119600, 34421 }, + { -819, 10016, -46484, 151575, -402180, 925946, -1916952, 3651127, + -6503765, 10978897, -17777669, 27978177, -43543117, 68956555, -118162649, 268651306, + 2100229392, -210840793, 103022708, -61785964, 39314430, -25245294, 15957145, -9771159, + 5723250, -3167714, 1634146, -772067, 325801, -117952, 33966 }, + { -800, 9819, -45612, 148807, -394964, 909546, -1883343, 3587636, + -6391418, 10790250, -17473411, 27500464, -42799620, 67773944, -116105447, 263690004, + 2101807263, -207805893, 101465046, -60839525, 38710129, -24857519, 15712794, -9622254, + 5636587, -3120132, 1609846, -760732, 321099, -116291, 33507 }, + { -780, 9622, -44743, 146043, -387756, 893160, -1849749, 3524155, + -6279062, 10601555, -17169032, 27022523, -42055773, 66590973, -114048779, 258741265, + 2103358864, -204751752, 99900010, -59889016, 38103297, -24468108, 15467384, -9472678, + 5549513, -3072310, 1585415, -749332, 316367, -114618, 33044 }, + { -761, 9427, -43876, 143285, -380558, 876786, -1816172, 3460687, + -6166702, 10412817, -16864544, 26544374, -41311606, 65407689, -111992721, 253805172, + 2104884159, -201678396, 98327641, -58934467, 37493953, -24077073, 15220923, -9322436, + 5462032, -3024251, 1560853, -737865, 311604, -112932, 32576 }, + { -742, 9232, -43011, 140533, -373369, 860428, -1782612, 3397233, + -6054343, 10224045, -16559958, 26066034, -40567148, 64224137, -109937346, 248881812, + 2106383112, -198585854, 96747981, -57975905, 36882115, -23684427, 14973419, -9171531, + 5374145, -2975956, 1536161, -726332, 306812, -111235, 32105 }, + { -724, 9038, -42149, 137786, -366190, 844084, -1749070, 3333797, + -5941988, 10035247, -16255288, 25587523, -39822427, 63040362, -107882726, 243971269, + 2107855690, -195474154, 95161072, -57013359, 36267804, -23290181, 14724879, -9019969, + 5285855, -2927425, 1511341, -714734, 301989, -109525, 31629 }, + { -705, 8845, -41290, 135044, -359021, 827755, -1715549, 3270380, + -5829642, 9846429, -15950545, 25108859, -39077472, 61856409, -105828936, 239073627, + 2109301856, -192343325, 93566957, -56046860, 35651038, -22894349, 14475312, -8867754, + 5197165, -2878660, 1486392, -703071, 297135, -107803, 31149 }, + { -687, 8653, -40433, 132308, -351862, 811443, -1682049, 3206986, + -5717310, 9657598, -15645741, 24630061, -38332313, 60672322, -103776046, 234188969, + 2110721579, -189193398, 91965677, -55076436, 35031837, -22496943, 14224724, -8714890, + 5108078, -2829663, 1461315, -691342, 292252, -106069, 30666 }, + { -669, 8462, -39578, 129578, -344714, 795148, -1648572, 3143616, + -5604996, 9468764, -15340887, 24151148, -37586978, 59488148, -101724131, 229317379, + 2112114824, -186024402, 90357277, -54102116, 34410219, -22097975, 13973124, -8561384, + 5018595, -2780435, 1436111, -679549, 287339, -104323, 30178 }, + { -651, 8272, -38727, 126853, -337577, 778869, -1615118, 3080274, + -5492704, 9279932, -15035996, 23672137, -36841495, 58303930, -99673263, 224458939, + 2113481560, -182836369, 88741798, -53123931, 33786206, -21697458, 13720519, -8407239, + 4928720, -2730977, 1410780, -667691, 282396, -102564, 29686 }, + { -634, 8083, -37877, 124134, -330451, 762609, -1581690, 3016961, + -5380439, 9091110, -14731080, 23193049, -36095894, 57119713, -97623513, 219613732, + 2114821754, -179629328, 87119286, -52141911, 33159817, -21295405, 13466919, -8252459, + 4838456, -2681291, 1385324, -655769, 277424, -100794, 29190 }, + { -616, 7894, -37031, 121422, -323336, 746368, -1548288, 2953681, + -5268205, 8902306, -14426151, 22713901, -35350204, 55935542, -95574954, 214781840, + 2116135376, -176403313, 85489784, -51156085, 32531071, -20891829, 13212330, -8097051, + 4747805, -2631378, 1359743, -643783, 272422, -99012, 28690 }, + { -599, 7707, -36187, 118716, -316233, 730146, -1514914, 2890435, + -5156006, 8713526, -14121219, 22234712, -34604452, 54751461, -93527657, 209963344, + 2117422394, -173158356, 83853337, -50166485, 31899988, -20486742, 12956761, -7941018, + 4656769, -2581240, 1334037, -631734, 267390, -97217, 28185 }, + { -582, 7520, -35346, 116015, -309142, 713943, -1481569, 2827226, + -5043847, 8524779, -13816298, 21755501, -33858668, 53567516, -91481695, 205158325, + 2118682778, -169894489, 82209988, -49173140, 31266590, -20080158, 12700219, -7784366, + 4565352, -2530878, 1308208, -619621, 262329, -95411, 27677 }, + { -565, 7335, -34508, 113321, -302063, 697761, -1448254, 2764056, + -4931733, 8336071, -13511399, 21276285, -33112880, 52383750, -89437138, 200366864, + 2119916500, -166611747, 80559784, -48176082, 30630895, -19672089, 12442714, -7627099, + 4473557, -2480293, 1282256, -607446, 257239, -93592, 27165 }, + { -548, 7150, -33672, 110634, -294997, 681601, -1414970, 2700928, + -4819666, 8147410, -13206533, 20797084, -32367116, 51200207, -87394058, 195589041, + 2121123531, -163310163, 78902770, -47175341, 29992925, -19262550, 12184254, -7469223, + 4381386, -2429488, 1256181, -595207, 252120, -91762, 26649 }, + { -532, 6966, -32840, 107953, -287943, 665461, -1381720, 2637845, + -4707652, 7958803, -12901713, 20317916, -31621405, 50016933, -85352525, 190824935, + 2122303842, -159989771, 77238990, -46170948, 29352700, -18851553, 11924846, -7310742, + 4288842, -2378463, 1229986, -582907, 246971, -89920, 26128 }, + { -516, 6783, -32010, 105278, -280902, 649344, -1348503, 2574808, + -4595696, 7770257, -12596950, 19838799, -30875776, 48833970, -83312611, 186074626, + 2123457406, -156650607, 75568493, -45162935, 28710241, -18439111, 11664499, -7151662, + 4195927, -2327220, 1203669, -570544, 241794, -88066, 25604 }, + { -499, 6601, -31183, 102611, -273875, 633250, -1315322, 2511820, + -4483800, 7581779, -12292256, 19359752, -30130256, 47651363, -81274386, 181338192, + 2124584196, -153292707, 73891323, -44151334, 28065568, -18025238, 11403221, -6991987, + 4102646, -2275761, 1177232, -558120, 236588, -86200, 25075 }, + { -484, 6421, -30358, 99950, -266860, 617179, -1282178, 2448884, + -4371970, 7393378, -11987643, 18880792, -29384875, 46469156, -79237919, 176615712, + 2125684186, -149916107, 72207528, -43136176, 27418702, -17609948, 11141021, -6831722, + 4009000, -2224087, 1150676, -545634, 231353, -84322, 24543 }, + { -468, 6241, -29537, 97295, -259860, 601133, -1249071, 2386002, + -4260210, 7205059, -11683122, 18401939, -28639659, 45287394, -77203282, 171907264, + 2126757350, -146520843, 70517154, -42117492, 26769665, -17193253, 10877908, -6670874, + 3914992, -2172199, 1124001, -533087, 226090, -82433, 24006 }, + { -452, 6062, -28719, 94648, -252873, 585111, -1216003, 2323175, + -4148524, 7016830, -11378705, 17923210, -27894638, 44106118, -75170544, 167212925, + 2127803664, -143106953, 68820250, -41095316, 26118477, -16775169, 10613890, -6509446, + 3820627, -2120100, 1097209, -520479, 220798, -80531, 23465 }, + { -437, 5884, -27903, 92008, -245901, 569114, -1182975, 2260407, + -4036916, 6828699, -11074403, 17444625, -27149840, 42925374, -73139775, 162532772, + 2128823102, -139674474, 67116863, -40069680, 25465160, -16355707, 10348975, -6347443, + 3725905, -2067791, 1070299, -507811, 215478, -78619, 22921 }, + { -422, 5707, -27091, 89375, -238943, 553143, -1149989, 2197701, + -3925391, 6640672, -10770229, 16966199, -26405292, 41745204, -71111044, 157866881, + 2129815641, -136223446, 65407040, -39040615, 24809735, -15934883, 10083172, -6184873, + 3630831, -2015273, 1043274, -495083, 210129, -76694, 22372 }, + { -407, 5531, -26282, 86749, -231999, 537198, -1117046, 2135057, + -3813952, 6452756, -10466193, 16487953, -25661023, 40565652, -69084421, 153215328, + 2130781258, -132753906, 63690831, -38008155, 24152223, -15512709, 9816490, -6021738, + 3535407, -1962548, 1016133, -482295, 204753, -74758, 21819 }, + { -392, 5355, -25475, 84130, -225071, 521280, -1084146, 2072479, + -3702605, 6264960, -10162307, 16009905, -24917060, 39386762, -67059973, 148578190, + 2131719931, -129265895, 61968284, -36972332, 23492647, -15089201, 9548938, -5858045, + 3439637, -1909617, 988877, -469448, 199348, -72810, 21262 }, + { -378, 5181, -24672, 81519, -218158, 505389, -1051292, 2009969, + -3591352, 6077289, -9858583, 15532071, -24173432, 38208577, -65037771, 143955541, + 2132631636, -125759453, 60239449, -35933179, 22831027, -14664371, 9280524, -5693799, + 3343523, -1856483, 961507, -456542, 193916, -70851, 20702 }, + { -363, 5008, -23871, 78915, -211260, 489527, -1018483, 1947529, + -3480199, 5889751, -9555033, 15054471, -23430166, 37031139, -63017882, 139347456, + 2133516355, -122234619, 58504374, -34890731, 22167386, -14238235, 9011258, -5529006, + 3247068, -1803147, 934024, -443577, 188456, -68880, 20137 }, + { -349, 4836, -23074, 76319, -204377, 473693, -985723, 1885162, + -3369150, 5702353, -9251667, 14577121, -22687291, 35854493, -61000375, 134754009, + 2134374064, -118691435, 56763109, -33845019, 21501746, -13810806, 8741148, -5363670, + 3150276, -1749610, 906429, -430554, 182969, -66897, 19568 }, + { -335, 4665, -22280, 73731, -197511, 457889, -953011, 1822869, + -3258207, 5515102, -8948497, 14100041, -21944833, 34678680, -58985318, 130175273, + 2135204746, -115129943, 55015705, -32796078, 20834128, -13382098, 8470202, -5197797, + 3053150, -1695874, 878723, -417473, 177454, -64904, 18995 }, + { -321, 4495, -21489, 71150, -190661, 442114, -920349, 1760654, + -3147377, 5328005, -8645534, 13623248, -21202820, 33503743, -56972778, 125611322, + 2136008379, -111550184, 53262211, -31743941, 20164555, -12952127, 8198432, -5031393, + 2955692, -1641941, 850906, -404334, 171912, -62899, 18419 }, + { -308, 4325, -20701, 68576, -183827, 426370, -887738, 1698518, + -3036663, 5141069, -8342790, 13146760, -20461281, 32329726, -54962824, 121062229, + 2136784946, -107952202, 51502679, -30688643, 19493049, -12520905, 7925844, -4864462, + 2857907, -1587812, 822979, -391138, 166343, -60882, 17838 }, + { -294, 4157, -19916, 66011, -177009, 410656, -855179, 1636464, + -2926068, 4954301, -8040277, 12670595, -19720242, 31156670, -52955522, 116528065, + 2137534429, -104336040, 49737160, -29630217, 18819633, -12088448, 7652448, -4697011, + 2759796, -1533489, 794942, -377885, 160746, -58854, 17253 }, + { -281, 3990, -19135, 63454, -170209, 394974, -822674, 1574494, + -2815598, 4767708, -7738005, 12194771, -18979731, 29984619, -50950939, 112008904, + 2138256809, -100701741, 47965704, -28568698, 18144329, -11654771, 7378255, -4529046, + 2661363, -1478975, 766798, -364576, 155123, -56815, 16665 }, + { -268, 3824, -18357, 60905, -163425, 379324, -790223, 1512611, + -2705256, 4581297, -7435986, 11719304, -18239775, 28813615, -48949143, 107504815, + 2138952071, -97049350, 46188364, -27504121, 17467159, -11219887, 7103271, -4360570, + 2562612, -1424270, 738547, -351210, 149473, -54765, 16072 }, + { -255, 3659, -17582, 58363, -156659, 363706, -757828, 1450816, + -2595046, 4395074, -7134230, 11244214, -17500402, 27643699, -46950199, 103015870, + 2139620197, -93378911, 44405192, -26436519, 16788147, -10783812, 6827508, -4191591, + 2463546, -1369376, 710189, -337789, 143797, -52703, 15476 }, + { -243, 3494, -16810, 55830, -149910, 348121, -725490, 1389111, + -2484972, 4209048, -6832750, 10769517, -16761639, 26474914, -44954175, 98542140, + 2140261173, -89690470, 42616239, -25365928, 16107315, -10346561, 6550974, -4022114, + 2364167, -1314295, 681726, -324312, 138094, -50631, 14875 }, + { -230, 3331, -16041, 53306, -143178, 332570, -693210, 1327500, + -2375038, 4023224, -6531557, 10295232, -16023513, 25307302, -42961136, 94083693, + 2140874983, -85984073, 40821559, -24292383, 15424686, -9908147, 6273678, -3852144, + 2264479, -1259029, 653157, -310780, 132365, -48547, 14271 }, + { -218, 3169, -15276, 50789, -136465, 317053, -660989, 1265984, + -2265249, 3837609, -6230661, 9821375, -15286052, 24140905, -40971148, 89640600, + 2141461613, -82259766, 39021205, -23215919, 14740283, -9468587, 5995631, -3681687, + 2164486, -1203580, 624485, -297194, 126610, -46452, 13662 }, + { -206, 3008, -14514, 48281, -129770, 301571, -628828, 1204565, + -2155609, 3652211, -5930074, 9347964, -14549281, 22975765, -38984277, 85212929, + 2142021049, -78517597, 37215229, -22136572, 14054129, -9027895, 5716840, -3510749, + 2064190, -1147949, 595710, -283554, 120829, -44347, 13050 }, + { -194, 2848, -13756, 45782, -123093, 286124, -596729, 1143246, + -2046120, 3467036, -5629806, 8875018, -13813229, 21811922, -37000587, 80800749, + 2142553278, -74757612, 35403685, -21054376, 13366248, -8586085, 5437317, -3339336, + 1963595, -1092138, 566833, -269860, 115022, -42230, 12434 }, + { -182, 2689, -13000, 43291, -116435, 270713, -564693, 1082029, + -1936788, 3282090, -5329870, 8402552, -13077922, 20649420, -35020145, 76404128, + 2143058289, -70979859, 33586628, -19969368, 12676663, -8143174, 5157070, -3167453, + 1862705, -1036148, 537855, -256112, 109189, -40102, 11814 }, + { -170, 2530, -12248, 40808, -109795, 255338, -532720, 1020916, + -1827617, 3097382, -5030275, 7930585, -12343387, 19488299, -33043014, 72023133, + 2143536068, -67184388, 31764111, -18881583, 11985398, -7699177, 4876108, -2995106, + 1761522, -979983, 508776, -242311, 103331, -37964, 11190 }, + { -159, 2373, -11500, 38335, -103175, 239999, -500813, 959910, + -1718609, 2912917, -4731034, 7459134, -11609650, 18328599, -31069260, 67657832, + 2143986605, -63371247, 29936188, -17791058, 11292475, -7254108, 4594443, -2822301, + 1660049, -923643, 479598, -228458, 97448, -35815, 10562 }, + { -148, 2217, -10755, 35870, -96573, 224698, -468971, 899012, + -1609770, 2728702, -4432156, 6988216, -10876739, 17170364, -29098946, 63308290, + 2144409890, -59540487, 28102916, -16697829, 10597920, -6807983, 4312082, -2649044, + 1558292, -867130, 450322, -214553, 91539, -33655, 9931 }, + { -137, 2062, -10013, 33414, -89992, 209435, -437196, 838224, + -1501103, 2544744, -4133653, 6517848, -10144680, 16013633, -27132137, 58974573, + 2144805912, -55692156, 26264348, -15601931, 9901754, -6360817, 4029037, -2475340, + 1456252, -810447, 420948, -200596, 85605, -31484, 9295 }, + { -126, 1908, -9275, 30967, -83429, 194210, -405490, 777549, + -1392612, 2361049, -3835536, 6048048, -9413499, 14858447, -25168896, 54656748, + 2145174663, -51826306, 24420541, -14503403, 9204003, -5912626, 3745316, -2301196, + 1353933, -753595, 391477, -186587, 79647, -29303, 8656 }, + { -115, 1755, -8540, 28529, -76887, 179024, -373852, 716989, + -1284301, 2177625, -3537815, 5578832, -8683223, 13704847, -23209287, 50354879, + 2145516133, -47942988, 22571549, -13402279, 8504691, -5463425, 3460929, -2126618, + 1251338, -696575, 361911, -172528, 73663, -27111, 8013 }, + { -104, 1603, -7809, 26100, -70365, 163877, -342285, 656546, + -1176174, 1994478, -3240501, 5110218, -7953879, 12552874, -21253374, 46069030, + 2145830315, -44042253, 20717430, -12298598, 7803841, -5013231, 3175887, -1951612, + 1148472, -639390, 332250, -158418, 67656, -24908, 7366 }, + { -94, 1452, -7081, 23680, -63863, 148770, -310790, 596223, + -1068235, 1811614, -2943606, 4642223, -7225491, 11402568, -19301218, 41799266, + 2146117201, -40124154, 18858239, -11192397, 7101477, -4562058, 2890199, -1776183, + 1045337, -582042, 302495, -144258, 61623, -22695, 6715 }, + { -84, 1302, -6357, 21270, -57381, 133704, -279367, 536020, + -960486, 1629040, -2647140, 4174863, -6498088, 10253969, -17352882, 37545650, + 2146376785, -36188744, 16994033, -10083711, 6397625, -4109922, 2603875, -1600337, + 941938, -524533, 272648, -130048, 55567, -20472, 6060 }, + { -74, 1154, -5637, 18869, -50920, 118678, -248018, 475941, + -852934, 1446762, -2351113, 3708156, -5771694, 9107118, -15408430, 33308246, + 2146609061, -32236076, 15124869, -8972580, 5692308, -3656839, 2316925, -1424081, + 838276, -466864, 242708, -115789, 49487, -18238, 5402 }, + { -64, 1006, -4919, 16477, -44480, 103693, -216743, 415987, + -745580, 1264788, -2055537, 3242118, -5046336, 7962054, -13467923, 29087114, + 2146814023, -28266203, 13250804, -7859040, 4985550, -3202825, 2029359, -1247421, + 734357, -409037, 212677, -101482, 43382, -15994, 4740 }, + { -54, 859, -4206, 14094, -38061, 88751, -185544, 356161, + -638430, 1083123, -1760421, 2776767, -4322040, 6818819, -11531423, 24882319, + 2146991666, -24279180, 11371896, -6743128, 4277377, -2747896, 1741187, -1070363, + 630184, -351055, 182557, -87126, 37255, -13739, 4074 }, + { -45, 713, -3496, 11721, -31663, 73850, -154422, 296465, + -531486, 901775, -1465777, 2312118, -3598831, 5677450, -9598992, 20693920, + 2147141986, -20275062, 9488202, -5624884, 3567813, -2292067, 1452419, -892913, + 525759, -292918, 152348, -72722, 31103, -11474, 3404 }, + { -36, 568, -2789, 9357, -25287, 58993, -123378, 236900, + -424753, 720749, -1171616, 1848189, -2876736, 4537989, -7670691, 16521980, + 2147264981, -16253904, 7599782, -4504345, 2856883, -1835356, 1163066, -715077, + 421087, -234630, 122050, -58270, 24928, -9200, 2731 }, + { -26, 425, -2087, 7003, -18932, 44179, -92413, 177470, + -318234, 540052, -877947, 1384996, -2155779, 3400474, -5746580, 12366558, + 2147360646, -12215763, 5706692, -3381548, 2144612, -1377777, 873137, -536862, + 316172, -176193, 91666, -43772, 18731, -6915, 2054 }, + { -17, 282, -1387, 4659, -12599, 29408, -61527, 118175, + -211933, 359691, -584781, 922556, -1435988, 2264944, -3826721, 8227714, + 2147428980, -8160693, 3808993, -2256533, 1431024, -919347, 582643, -358273, + 211017, -117607, 61195, -29227, 12510, -4620, 1373 }, + { -9, 141, -692, 2325, -6289, 14682, -30723, 59017, + -105854, 179671, -292128, 460885, -717386, 1131440, -1911174, 4105509, + 2147469981, -4088753, 1906742, -1129337, 716145, -460083, 291594, -179317, + 105625, -58875, 30640, -14637, 6266, -2315, 688 }, + + }, + + .d = { + + { -1, 3, -9, 24, -57, 120, -230, 413, -700, 1139, + -1797, 2797, -4411, 7448, -15972, -53, 16037, -7466, 4420, -2802, + 1800, -1141, 702, -413, 231, -120, 57, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -57, 119, -229, 412, -699, 1137, + -1794, 2792, -4403, 7431, -15906, -160, 16102, -7483, 4428, -2807, + 1803, -1143, 703, -414, 231, -120, 58, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -57, 119, -229, 411, -698, 1135, + -1791, 2787, -4395, 7413, -15840, -267, 16167, -7499, 4436, -2812, + 1806, -1145, 705, -415, 232, -121, 58, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -57, 119, -228, 410, -696, 1133, + -1787, 2782, -4386, 7395, -15774, -374, 16232, -7516, 4443, -2816, + 1809, -1147, 706, -416, 232, -121, 58, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -56, 118, -228, 409, -695, 1130, + -1784, 2777, -4377, 7377, -15708, -480, 16297, -7532, 4451, -2821, + 1812, -1149, 707, -417, 233, -121, 58, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -56, 118, -227, 408, -693, 1128, + -1781, 2772, -4368, 7358, -15641, -587, 16361, -7549, 4458, -2825, + 1815, -1151, 708, -418, 233, -122, 58, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -56, 118, -226, 407, -692, 1126, + -1777, 2766, -4359, 7339, -15574, -694, 16425, -7564, 4466, -2829, + 1818, -1153, 710, -419, 234, -122, 58, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -56, 117, -226, 406, -690, 1123, + -1773, 2761, -4350, 7321, -15507, -801, 16489, -7580, 4473, -2833, + 1820, -1155, 711, -419, 234, -122, 59, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -56, 117, -225, 405, -688, 1121, + -1770, 2755, -4340, 7301, -15440, -907, 16552, -7596, 4480, -2837, + 1823, -1156, 712, -420, 235, -122, 59, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -56, 117, -225, 404, -687, 1118, + -1766, 2749, -4331, 7282, -15373, -1014, 16616, -7611, 4487, -2841, + 1826, -1158, 713, -421, 235, -123, 59, -25, 9, -3, 1 }, + { -1, 3, -9, 24, -55, 116, -224, 403, -685, 1116, + -1762, 2744, -4321, 7262, -15305, -1121, 16679, -7626, 4493, -2845, + 1828, -1160, 714, -422, 236, -123, 59, -25, 9, -3, 1 }, + { 0, 3, -9, 23, -55, 116, -223, 402, -684, 1113, + -1759, 2738, -4311, 7243, -15237, -1227, 16742, -7640, 4500, -2849, + 1831, -1161, 715, -422, 236, -123, 59, -25, 9, -3, 1 }, + { 0, 3, -9, 23, -55, 115, -223, 401, -682, 1111, + -1755, 2732, -4301, 7223, -15169, -1334, 16804, -7655, 4506, -2853, + 1833, -1163, 717, -423, 237, -124, 59, -26, 10, -3, 1 }, + { 0, 2, -9, 23, -55, 115, -222, 400, -680, 1108, + -1751, 2726, -4291, 7202, -15101, -1440, 16867, -7669, 4512, -2856, + 1835, -1165, 718, -424, 237, -124, 59, -26, 10, -3, 1 }, + { 0, 2, -8, 23, -55, 115, -221, 399, -679, 1106, + -1747, 2719, -4281, 7182, -15033, -1547, 16929, -7683, 4518, -2860, + 1837, -1166, 719, -424, 237, -124, 60, -26, 10, -3, 1 }, + { 0, 2, -8, 23, -54, 114, -221, 397, -677, 1103, + -1743, 2713, -4270, 7161, -14964, -1653, 16990, -7697, 4524, -2863, + 1840, -1167, 720, -425, 238, -124, 60, -26, 10, -3, 1 }, + { 0, 2, -8, 23, -54, 114, -220, 396, -675, 1100, + -1739, 2707, -4260, 7140, -14895, -1760, 17052, -7710, 4530, -2866, + 1842, -1169, 721, -426, 238, -125, 60, -26, 10, -3, 1 }, + { 0, 2, -8, 23, -54, 114, -219, 395, -673, 1098, + -1734, 2700, -4249, 7119, -14826, -1866, 17113, -7723, 4536, -2869, + 1844, -1170, 722, -426, 239, -125, 60, -26, 10, -3, 1 }, + { 0, 2, -8, 23, -54, 113, -219, 394, -671, 1095, + -1730, 2694, -4238, 7098, -14757, -1973, 17174, -7736, 4541, -2872, + 1846, -1172, 722, -427, 239, -125, 60, -26, 10, -3, 1 }, + { 0, 2, -8, 23, -53, 113, -218, 393, -670, 1092, + -1726, 2687, -4227, 7076, -14687, -2079, 17235, -7749, 4546, -2875, + 1847, -1173, 723, -428, 240, -125, 60, -26, 10, -3, 1 }, + { 0, 2, -8, 23, -53, 112, -217, 392, -668, 1089, + -1721, 2680, -4216, 7055, -14618, -2185, 17296, -7761, 4551, -2878, + 1849, -1174, 724, -428, 240, -126, 60, -26, 10, -3, 1 }, + { 0, 2, -8, 22, -53, 112, -217, 391, -666, 1086, + -1717, 2673, -4205, 7033, -14548, -2292, 17356, -7773, 4556, -2881, + 1851, -1175, 725, -429, 240, -126, 61, -26, 10, -3, 1 }, + { 0, 2, -8, 22, -53, 112, -216, 389, -664, 1083, + -1713, 2667, -4194, 7010, -14478, -2398, 17416, -7785, 4561, -2883, + 1853, -1177, 726, -429, 241, -126, 61, -26, 10, -3, 1 }, + { 0, 2, -8, 22, -53, 111, -215, 388, -662, 1080, + -1708, 2660, -4182, 6988, -14408, -2504, 17476, -7797, 4566, -2886, + 1854, -1178, 727, -430, 241, -126, 61, -26, 10, -3, 1 }, + { 0, 2, -8, 22, -52, 111, -214, 387, -660, 1077, + -1703, 2652, -4170, 6966, -14338, -2610, 17535, -7808, 4570, -2888, + 1856, -1179, 727, -431, 241, -127, 61, -26, 10, -3, 1 }, + { 0, 2, -8, 22, -52, 110, -214, 386, -658, 1074, + -1699, 2645, -4159, 6943, -14267, -2716, 17594, -7820, 4574, -2890, + 1857, -1180, 728, -431, 242, -127, 61, -26, 10, -3, 1 }, + { 0, 2, -8, 22, -52, 110, -213, 385, -656, 1071, + -1694, 2638, -4147, 6920, -14196, -2822, 17653, -7830, 4578, -2893, + 1859, -1181, 729, -432, 242, -127, 61, -27, 10, -3, 1 }, + { 0, 2, -8, 22, -52, 110, -212, 383, -654, 1068, + -1689, 2631, -4134, 6897, -14126, -2928, 17712, -7841, 4582, -2895, + 1860, -1182, 730, -432, 242, -127, 61, -27, 10, -3, 1 }, + { 0, 2, -8, 22, -52, 109, -211, 382, -652, 1065, + -1684, 2623, -4122, 6873, -14055, -3033, 17770, -7851, 4586, -2897, + 1861, -1183, 730, -432, 243, -127, 62, -27, 10, -3, 1 }, + { 0, 2, -8, 22, -51, 109, -211, 381, -650, 1062, + -1680, 2616, -4110, 6850, -13983, -3139, 17828, -7861, 4590, -2898, + 1862, -1183, 731, -433, 243, -128, 62, -27, 10, -3, 1 }, + { 0, 2, -8, 22, -51, 108, -210, 379, -648, 1058, + -1675, 2608, -4097, 6826, -13912, -3245, 17886, -7871, 4593, -2900, + 1864, -1184, 731, -433, 243, -128, 62, -27, 10, -3, 1 }, + { 0, 2, -8, 21, -51, 108, -209, 378, -646, 1055, + -1670, 2600, -4085, 6802, -13841, -3350, 17943, -7881, 4596, -2902, + 1865, -1185, 732, -434, 244, -128, 62, -27, 10, -3, 1 }, + { 0, 2, -8, 21, -51, 107, -208, 377, -644, 1052, + -1665, 2592, -4072, 6778, -13769, -3456, 18000, -7890, 4599, -2903, + 1866, -1186, 733, -434, 244, -128, 62, -27, 10, -3, 1 }, + { 0, 2, -8, 21, -50, 107, -208, 375, -642, 1048, + -1659, 2584, -4059, 6753, -13697, -3561, 18057, -7899, 4602, -2905, + 1867, -1186, 733, -435, 244, -128, 62, -27, 10, -3, 1 }, + { 0, 2, -8, 21, -50, 106, -207, 374, -639, 1045, + -1654, 2576, -4046, 6729, -13625, -3667, 18114, -7908, 4605, -2906, + 1867, -1187, 734, -435, 244, -129, 62, -27, 10, -3, 1 }, + { 0, 2, -8, 21, -50, 106, -206, 373, -637, 1042, + -1649, 2568, -4033, 6704, -13553, -3772, 18170, -7916, 4608, -2907, + 1868, -1188, 734, -435, 245, -129, 62, -27, 10, -3, 1 }, + { 0, 2, -8, 21, -50, 106, -205, 371, -635, 1038, + -1644, 2560, -4020, 6679, -13481, -3877, 18226, -7925, 4610, -2908, + 1869, -1188, 734, -436, 245, -129, 62, -27, 10, -3, 1 }, + { 0, 2, -7, 21, -49, 105, -204, 370, -633, 1035, + -1639, 2552, -4006, 6654, -13408, -3982, 18282, -7933, 4612, -2909, + 1869, -1189, 735, -436, 245, -129, 62, -27, 10, -3, 1 }, + { 0, 2, -7, 21, -49, 105, -204, 369, -631, 1031, + -1633, 2544, -3993, 6629, -13336, -4087, 18337, -7940, 4614, -2910, + 1870, -1189, 735, -436, 245, -129, 63, -27, 10, -3, 1 }, + { 0, 2, -7, 21, -49, 104, -203, 367, -628, 1028, + -1628, 2535, -3979, 6603, -13263, -4192, 18392, -7948, 4616, -2911, + 1871, -1190, 736, -437, 246, -129, 63, -27, 10, -3, 1 }, + { 0, 2, -7, 20, -49, 104, -202, 366, -626, 1024, + -1622, 2527, -3965, 6577, -13190, -4297, 18447, -7955, 4618, -2912, + 1871, -1190, 736, -437, 246, -129, 63, -27, 10, -3, 1 }, + { 0, 2, -7, 20, -49, 103, -201, 364, -624, 1021, + -1617, 2518, -3952, 6551, -13117, -4402, 18502, -7962, 4620, -2912, + 1871, -1190, 736, -437, 246, -130, 63, -27, 10, -3, 1 }, + { 0, 2, -7, 20, -48, 103, -200, 363, -621, 1017, + -1611, 2510, -3938, 6525, -13044, -4506, 18556, -7968, 4621, -2913, + 1872, -1190, 737, -437, 246, -130, 63, -28, 10, -3, 1 }, + { 0, 2, -7, 20, -48, 102, -199, 362, -619, 1013, + -1605, 2501, -3923, 6499, -12970, -4611, 18610, -7975, 4622, -2913, + 1872, -1191, 737, -438, 246, -130, 63, -28, 10, -3, 1 }, + { 0, 2, -7, 20, -48, 102, -198, 360, -617, 1010, + -1600, 2492, -3909, 6473, -12897, -4715, 18663, -7981, 4623, -2913, + 1872, -1191, 737, -438, 247, -130, 63, -28, 10, -3, 1 }, + { 0, 2, -7, 20, -48, 101, -198, 359, -614, 1006, + -1594, 2483, -3895, 6446, -12823, -4819, 18717, -7987, 4624, -2913, + 1872, -1191, 737, -438, 247, -130, 63, -28, 11, -3, 1 }, + { 0, 2, -7, 20, -47, 101, -197, 357, -612, 1002, + -1588, 2474, -3880, 6419, -12749, -4923, 18770, -7992, 4625, -2913, + 1872, -1191, 737, -438, 247, -130, 63, -28, 11, -3, 1 }, + { 0, 2, -7, 20, -47, 100, -196, 356, -610, 998, + -1582, 2465, -3866, 6392, -12676, -5027, 18822, -7997, 4625, -2913, + 1872, -1191, 737, -438, 247, -130, 63, -28, 11, -3, 1 }, + { 0, 2, -7, 20, -47, 100, -195, 354, -607, 994, + -1576, 2456, -3851, 6365, -12602, -5131, 18875, -8002, 4626, -2913, + 1872, -1191, 738, -438, 247, -130, 63, -28, 11, -3, 1 }, + { 0, 2, -7, 19, -47, 99, -194, 353, -605, 991, + -1571, 2447, -3836, 6338, -12528, -5235, 18927, -8007, 4626, -2913, + 1871, -1191, 738, -439, 247, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -7, 19, -46, 99, -193, 351, -602, 987, + -1565, 2438, -3821, 6310, -12453, -5339, 18978, -8011, 4626, -2912, + 1871, -1191, 738, -439, 247, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -7, 19, -46, 98, -192, 350, -600, 983, + -1558, 2428, -3806, 6283, -12379, -5442, 19030, -8015, 4626, -2911, + 1871, -1191, 738, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -7, 19, -46, 98, -191, 348, -597, 979, + -1552, 2419, -3791, 6255, -12304, -5546, 19081, -8019, 4625, -2911, + 1870, -1191, 738, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -7, 19, -46, 97, -190, 346, -595, 975, + -1546, 2409, -3775, 6227, -12230, -5649, 19131, -8023, 4625, -2910, + 1870, -1190, 738, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -7, 19, -45, 97, -190, 345, -592, 971, + -1540, 2400, -3760, 6199, -12155, -5752, 19182, -8026, 4624, -2909, + 1869, -1190, 737, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -7, 19, -45, 96, -189, 343, -589, 967, + -1534, 2390, -3744, 6171, -12080, -5855, 19232, -8029, 4623, -2908, + 1869, -1190, 737, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -7, 19, -45, 96, -188, 342, -587, 963, + -1527, 2380, -3729, 6142, -12005, -5958, 19282, -8031, 4622, -2907, + 1868, -1189, 737, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -7, 18, -45, 95, -187, 340, -584, 959, + -1521, 2370, -3713, 6113, -11930, -6061, 19331, -8034, 4621, -2906, + 1867, -1189, 737, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 18, -44, 95, -186, 339, -582, 954, + -1515, 2361, -3697, 6085, -11855, -6164, 19380, -8036, 4620, -2904, + 1866, -1189, 737, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 18, -44, 94, -185, 337, -579, 950, + -1508, 2351, -3681, 6056, -11780, -6266, 19429, -8038, 4618, -2903, + 1865, -1188, 737, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 18, -44, 94, -184, 335, -576, 946, + -1502, 2341, -3665, 6027, -11704, -6368, 19477, -8039, 4616, -2901, + 1864, -1187, 736, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 18, -43, 93, -183, 334, -574, 942, + -1495, 2330, -3649, 5997, -11629, -6471, 19525, -8040, 4614, -2900, + 1863, -1187, 736, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 18, -43, 93, -182, 332, -571, 938, + -1489, 2320, -3632, 5968, -11553, -6573, 19573, -8041, 4612, -2898, + 1862, -1186, 736, -439, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 18, -43, 92, -181, 330, -568, 933, + -1482, 2310, -3616, 5938, -11478, -6674, 19620, -8042, 4610, -2896, + 1861, -1185, 736, -438, 248, -131, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 18, -43, 92, -180, 329, -566, 929, + -1475, 2300, -3599, 5908, -11402, -6776, 19667, -8042, 4607, -2894, + 1859, -1185, 735, -438, 248, -132, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 18, -42, 91, -179, 327, -563, 925, + -1469, 2289, -3583, 5879, -11326, -6878, 19714, -8042, 4605, -2892, + 1858, -1184, 735, -438, 248, -132, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 17, -42, 91, -178, 325, -560, 920, + -1462, 2279, -3566, 5849, -11250, -6979, 19760, -8042, 4602, -2889, + 1856, -1183, 734, -438, 248, -132, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 17, -42, 90, -177, 324, -557, 916, + -1455, 2268, -3549, 5818, -11174, -7080, 19806, -8042, 4599, -2887, + 1855, -1182, 734, -438, 248, -132, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 17, -42, 90, -176, 322, -555, 912, + -1448, 2258, -3532, 5788, -11098, -7181, 19852, -8041, 4596, -2884, + 1853, -1181, 733, -438, 248, -132, 64, -28, 11, -3, 1 }, + { 0, 2, -6, 17, -41, 89, -175, 320, -552, 907, + -1441, 2247, -3515, 5758, -11022, -7282, 19897, -8040, 4592, -2882, + 1851, -1180, 733, -437, 248, -132, 64, -29, 11, -4, 1 }, + { 0, 2, -6, 17, -41, 89, -174, 319, -549, 903, + -1434, 2236, -3498, 5727, -10946, -7383, 19942, -8038, 4589, -2879, + 1850, -1179, 732, -437, 248, -132, 64, -29, 11, -4, 1 }, + { 0, 2, -6, 17, -41, 88, -173, 317, -546, 898, + -1427, 2226, -3481, 5696, -10869, -7484, 19987, -8037, 4585, -2876, + 1848, -1178, 732, -437, 248, -132, 64, -29, 11, -4, 1 }, + { 0, 2, -6, 17, -41, 88, -172, 315, -543, 894, + -1420, 2215, -3463, 5665, -10793, -7584, 20031, -8035, 4581, -2873, + 1846, -1177, 731, -437, 248, -132, 65, -29, 11, -4, 1 }, + { 0, 2, -6, 17, -40, 87, -171, 313, -540, 889, + -1413, 2204, -3446, 5634, -10716, -7684, 20075, -8032, 4577, -2870, + 1844, -1176, 730, -436, 247, -132, 65, -29, 11, -4, 1 }, + { 0, 2, -6, 16, -40, 86, -170, 312, -537, 884, + -1406, 2193, -3428, 5603, -10640, -7784, 20119, -8030, 4573, -2867, + 1842, -1175, 730, -436, 247, -131, 65, -29, 11, -4, 1 }, + { 0, 2, -6, 16, -40, 86, -169, 310, -535, 880, + -1399, 2182, -3410, 5572, -10563, -7884, 20162, -8027, 4568, -2864, + 1840, -1173, 729, -436, 247, -131, 65, -29, 11, -4, 1 }, + { 0, 2, -6, 16, -39, 85, -168, 308, -532, 875, + -1392, 2171, -3393, 5540, -10486, -7984, 20204, -8024, 4564, -2860, + 1837, -1172, 728, -435, 247, -131, 65, -29, 11, -4, 1 }, + { 0, 1, -6, 16, -39, 85, -167, 306, -529, 871, + -1385, 2159, -3375, 5509, -10409, -8083, 20247, -8020, 4559, -2857, + 1835, -1171, 728, -435, 247, -131, 65, -29, 11, -4, 1 }, + { 0, 1, -6, 16, -39, 84, -166, 304, -526, 866, + -1377, 2148, -3357, 5477, -10333, -8183, 20289, -8016, 4554, -2853, + 1833, -1169, 727, -434, 247, -131, 65, -29, 11, -4, 1 }, + { 0, 1, -5, 16, -39, 84, -165, 303, -523, 861, + -1370, 2137, -3339, 5445, -10256, -8282, 20331, -8012, 4549, -2849, + 1830, -1168, 726, -434, 247, -131, 65, -29, 11, -4, 1 }, + { 0, 1, -5, 16, -38, 83, -164, 301, -520, 856, + -1363, 2125, -3321, 5413, -10179, -8381, 20372, -8008, 4544, -2845, + 1828, -1166, 725, -434, 246, -131, 65, -29, 11, -4, 1 }, + { 0, 1, -5, 16, -38, 83, -163, 299, -517, 852, + -1355, 2114, -3302, 5381, -10102, -8479, 20413, -8003, 4538, -2841, + 1825, -1165, 724, -433, 246, -131, 65, -29, 11, -4, 1 }, + { 0, 1, -5, 15, -38, 82, -162, 297, -514, 847, + -1348, 2102, -3284, 5349, -10025, -8578, 20454, -7998, 4532, -2837, + 1822, -1163, 723, -433, 246, -131, 65, -29, 11, -4, 1 }, + { 0, 1, -5, 15, -37, 81, -161, 295, -511, 842, + -1340, 2091, -3266, 5316, -9947, -8676, 20494, -7993, 4526, -2833, + 1820, -1161, 723, -432, 246, -131, 65, -29, 11, -4, 1 }, + { 0, 1, -5, 15, -37, 81, -160, 294, -508, 837, + -1333, 2079, -3247, 5284, -9870, -8774, 20534, -7987, 4520, -2829, + 1817, -1160, 722, -432, 246, -131, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 15, -37, 80, -159, 292, -505, 832, + -1325, 2068, -3229, 5251, -9793, -8872, 20573, -7981, 4514, -2824, + 1814, -1158, 721, -431, 245, -131, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 15, -37, 80, -158, 290, -502, 828, + -1318, 2056, -3210, 5218, -9716, -8970, 20612, -7975, 4508, -2820, + 1811, -1156, 720, -431, 245, -131, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 15, -36, 79, -157, 288, -499, 823, + -1310, 2044, -3191, 5185, -9638, -9068, 20651, -7969, 4501, -2815, + 1808, -1154, 718, -430, 245, -131, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 15, -36, 79, -156, 286, -495, 818, + -1303, 2032, -3172, 5152, -9561, -9165, 20689, -7962, 4494, -2810, + 1805, -1152, 717, -430, 245, -131, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 15, -36, 78, -155, 284, -492, 813, + -1295, 2020, -3153, 5119, -9483, -9262, 20727, -7955, 4487, -2805, + 1802, -1150, 716, -429, 244, -130, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 14, -36, 77, -154, 282, -489, 808, + -1287, 2008, -3134, 5086, -9406, -9359, 20765, -7947, 4480, -2800, + 1798, -1148, 715, -428, 244, -130, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 14, -35, 77, -152, 281, -486, 803, + -1279, 1996, -3115, 5053, -9328, -9455, 20802, -7939, 4473, -2795, + 1795, -1146, 714, -428, 244, -130, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 14, -35, 76, -151, 279, -483, 798, + -1272, 1984, -3096, 5019, -9251, -9552, 20839, -7931, 4465, -2790, + 1792, -1144, 713, -427, 243, -130, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 14, -35, 76, -150, 277, -480, 793, + -1264, 1972, -3077, 4986, -9173, -9648, 20875, -7923, 4457, -2784, + 1788, -1142, 712, -427, 243, -130, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 14, -34, 75, -149, 275, -477, 788, + -1256, 1960, -3057, 4952, -9096, -9744, 20911, -7914, 4450, -2779, + 1785, -1140, 710, -426, 243, -130, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 14, -34, 75, -148, 273, -474, 783, + -1248, 1948, -3038, 4918, -9018, -9840, 20947, -7905, 4441, -2773, + 1781, -1138, 709, -425, 242, -130, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 14, -34, 74, -147, 271, -470, 778, + -1240, 1935, -3018, 4884, -8940, -9935, 20982, -7896, 4433, -2767, + 1777, -1135, 708, -424, 242, -130, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 14, -33, 73, -146, 269, -467, 772, + -1232, 1923, -2999, 4850, -8863, -10031, 21017, -7886, 4425, -2762, + 1773, -1133, 706, -424, 242, -129, 64, -29, 11, -4, 1 }, + { 0, 1, -5, 13, -33, 73, -145, 267, -464, 767, + -1224, 1911, -2979, 4816, -8785, -10126, 21051, -7877, 4416, -2756, + 1770, -1131, 705, -423, 241, -129, 64, -29, 11, -4, 1 }, + { 0, 1, -4, 13, -33, 72, -144, 265, -461, 762, + -1216, 1898, -2959, 4782, -8707, -10221, 21086, -7866, 4407, -2750, + 1766, -1128, 703, -422, 241, -129, 64, -29, 11, -4, 1 }, + { 0, 1, -4, 13, -33, 72, -143, 263, -457, 757, + -1208, 1886, -2939, 4748, -8630, -10315, 21119, -7856, 4398, -2743, + 1762, -1126, 702, -421, 241, -129, 64, -29, 11, -4, 1 }, + { 0, 1, -4, 13, -32, 71, -141, 261, -454, 752, + -1200, 1873, -2920, 4713, -8552, -10410, 21152, -7845, 4389, -2737, + 1757, -1123, 701, -421, 240, -129, 64, -29, 11, -4, 1 }, + { 0, 1, -4, 13, -32, 70, -140, 259, -451, 747, + -1192, 1860, -2900, 4679, -8474, -10504, 21185, -7834, 4380, -2731, + 1753, -1121, 699, -420, 240, -129, 64, -29, 11, -4, 1 }, + { 0, 1, -4, 13, -32, 70, -139, 257, -448, 741, + -1183, 1848, -2879, 4644, -8396, -10598, 21218, -7822, 4370, -2724, + 1749, -1118, 698, -419, 239, -128, 64, -29, 11, -4, 1 }, + { 0, 1, -4, 13, -31, 69, -138, 256, -444, 736, + -1175, 1835, -2859, 4609, -8318, -10691, 21250, -7811, 4360, -2717, + 1745, -1115, 696, -418, 239, -128, 64, -29, 11, -4, 1 }, + { 0, 1, -4, 12, -31, 69, -137, 254, -441, 731, + -1167, 1822, -2839, 4575, -8241, -10785, 21282, -7798, 4351, -2711, + 1740, -1113, 694, -417, 238, -128, 64, -29, 11, -4, 1 }, + { 0, 1, -4, 12, -31, 68, -136, 252, -438, 725, + -1159, 1809, -2819, 4540, -8163, -10878, 21313, -7786, 4340, -2704, + 1736, -1110, 693, -416, 238, -128, 63, -29, 11, -4, 1 }, + { 0, 1, -4, 12, -31, 67, -135, 250, -435, 720, + -1150, 1797, -2799, 4505, -8085, -10971, 21344, -7773, 4330, -2697, + 1731, -1107, 691, -415, 238, -128, 63, -29, 11, -4, 1 }, + { 0, 1, -4, 12, -30, 67, -134, 248, -431, 715, + -1142, 1784, -2778, 4470, -8007, -11063, 21374, -7760, 4320, -2690, + 1727, -1104, 689, -414, 237, -127, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 12, -30, 66, -133, 246, -428, 709, + -1134, 1771, -2758, 4434, -7929, -11156, 21404, -7747, 4309, -2682, + 1722, -1101, 688, -414, 237, -127, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 12, -30, 66, -131, 244, -425, 704, + -1125, 1758, -2737, 4399, -7852, -11248, 21434, -7733, 4298, -2675, + 1717, -1098, 686, -413, 236, -127, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 12, -29, 65, -130, 242, -421, 699, + -1117, 1745, -2716, 4364, -7774, -11340, 21463, -7719, 4287, -2667, + 1712, -1095, 684, -412, 236, -127, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 12, -29, 64, -129, 240, -418, 693, + -1108, 1732, -2696, 4328, -7696, -11431, 21492, -7705, 4276, -2660, + 1707, -1092, 682, -411, 235, -126, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 11, -29, 64, -128, 238, -414, 688, + -1100, 1718, -2675, 4293, -7618, -11523, 21520, -7690, 4265, -2652, + 1702, -1089, 680, -410, 235, -126, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 11, -29, 63, -127, 236, -411, 682, + -1092, 1705, -2654, 4257, -7540, -11614, 21548, -7675, 4253, -2644, + 1697, -1086, 679, -409, 234, -126, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 11, -28, 63, -126, 234, -408, 677, + -1083, 1692, -2633, 4222, -7463, -11705, 21576, -7660, 4241, -2636, + 1692, -1083, 677, -407, 233, -126, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 11, -28, 62, -125, 231, -404, 672, + -1074, 1679, -2612, 4186, -7385, -11795, 21603, -7645, 4229, -2628, + 1687, -1079, 675, -406, 233, -125, 63, -28, 11, -4, 1 }, + { 0, 1, -4, 11, -28, 61, -123, 229, -401, 666, + -1066, 1666, -2591, 4150, -7307, -11885, 21630, -7629, 4217, -2620, + 1682, -1076, 673, -405, 232, -125, 62, -28, 11, -4, 1 }, + { 0, 1, -4, 11, -27, 61, -122, 227, -397, 661, + -1057, 1652, -2570, 4114, -7229, -11975, 21656, -7613, 4205, -2612, + 1676, -1073, 671, -404, 232, -125, 62, -28, 11, -4, 1 }, + { 0, 1, -3, 11, -27, 60, -121, 225, -394, 655, + -1049, 1639, -2549, 4078, -7152, -12065, 21682, -7596, 4193, -2604, + 1671, -1069, 669, -403, 231, -125, 62, -28, 11, -4, 1 }, + { 0, 1, -3, 11, -27, 60, -120, 223, -391, 650, + -1040, 1625, -2528, 4042, -7074, -12154, 21708, -7579, 4180, -2595, + 1665, -1066, 667, -402, 231, -124, 62, -28, 11, -4, 1 }, + { 0, 1, -3, 10, -26, 59, -119, 221, -387, 644, + -1031, 1612, -2507, 4006, -6996, -12244, 21733, -7562, 4167, -2586, + 1660, -1062, 665, -401, 230, -124, 62, -28, 11, -4, 1 }, + { 0, 1, -3, 10, -26, 58, -118, 219, -384, 638, + -1023, 1598, -2486, 3970, -6919, -12332, 21757, -7545, 4154, -2578, + 1654, -1059, 663, -400, 229, -124, 62, -28, 11, -4, 1 }, + { 0, 1, -3, 10, -26, 58, -116, 217, -380, 633, + -1014, 1585, -2464, 3933, -6841, -12421, 21782, -7527, 4141, -2569, + 1648, -1055, 660, -398, 229, -123, 62, -28, 11, -4, 1 }, + { 0, 1, -3, 10, -26, 57, -115, 215, -377, 627, + -1005, 1571, -2443, 3897, -6764, -12509, 21805, -7509, 4127, -2560, + 1643, -1052, 658, -397, 228, -123, 62, -28, 11, -4, 1 }, + { 0, 1, -3, 10, -25, 56, -114, 213, -373, 622, + -996, 1558, -2421, 3861, -6686, -12597, 21829, -7490, 4114, -2551, + 1637, -1048, 656, -396, 227, -123, 61, -28, 11, -4, 1 }, + { 0, 1, -3, 10, -25, 56, -113, 211, -370, 616, + -988, 1544, -2400, 3824, -6609, -12685, 21852, -7472, 4100, -2542, + 1631, -1044, 654, -395, 227, -122, 61, -28, 11, -4, 1 }, + { 0, 1, -3, 10, -25, 55, -112, 209, -366, 610, + -979, 1530, -2378, 3788, -6531, -12773, 21874, -7453, 4086, -2532, + 1625, -1041, 652, -393, 226, -122, 61, -28, 11, -4, 1 }, + { 0, 1, -3, 10, -24, 55, -111, 207, -363, 605, + -970, 1517, -2357, 3751, -6454, -12860, 21896, -7433, 4072, -2523, + 1619, -1037, 649, -392, 225, -122, 61, -28, 11, -4, 1 }, + { 0, 1, -3, 9, -24, 54, -109, 205, -359, 599, + -961, 1503, -2335, 3714, -6376, -12946, 21918, -7414, 4058, -2513, + 1613, -1033, 647, -391, 225, -121, 61, -28, 11, -4, 1 }, + { 0, 1, -3, 9, -24, 53, -108, 203, -356, 593, + -952, 1489, -2313, 3678, -6299, -13033, 21939, -7394, 4043, -2504, + 1606, -1029, 645, -389, 224, -121, 61, -28, 11, -4, 1 }, + { 0, 1, -3, 9, -23, 53, -107, 201, -352, 588, + -943, 1475, -2292, 3641, -6222, -13119, 21960, -7373, 4029, -2494, + 1600, -1025, 642, -388, 223, -121, 61, -28, 11, -4, 1 }, + { 0, 1, -3, 9, -23, 52, -106, 198, -349, 582, + -934, 1462, -2270, 3604, -6145, -13205, 21981, -7353, 4014, -2484, + 1594, -1021, 640, -387, 223, -120, 60, -28, 11, -4, 1 }, + { 0, 1, -3, 9, -23, 52, -105, 196, -345, 576, + -925, 1448, -2248, 3567, -6067, -13291, 22001, -7332, 3999, -2474, + 1587, -1017, 637, -385, 222, -120, 60, -27, 11, -4, 1 }, + { 0, 1, -3, 9, -23, 51, -104, 194, -342, 571, + -916, 1434, -2226, 3530, -5990, -13376, 22020, -7310, 3984, -2464, + 1581, -1013, 635, -384, 221, -120, 60, -27, 11, -4, 1 }, + { 0, 1, -3, 9, -22, 50, -102, 192, -338, 565, + -907, 1420, -2204, 3493, -5913, -13461, 22039, -7289, 3968, -2454, + 1574, -1009, 632, -382, 220, -119, 60, -27, 11, -4, 1 }, + { 0, 1, -3, 8, -22, 50, -101, 190, -335, 559, + -898, 1406, -2182, 3456, -5836, -13546, 22058, -7267, 3953, -2444, + 1567, -1004, 630, -381, 220, -119, 60, -27, 11, -4, 1 }, + { 0, 1, -3, 8, -22, 49, -100, 188, -331, 553, + -889, 1392, -2160, 3419, -5759, -13630, 22076, -7245, 3937, -2433, + 1561, -1000, 627, -380, 219, -119, 60, -27, 11, -4, 1 }, + { 0, 1, -3, 8, -21, 48, -99, 186, -327, 548, + -880, 1378, -2138, 3382, -5682, -13714, 22094, -7222, 3921, -2423, + 1554, -996, 625, -378, 218, -118, 59, -27, 11, -4, 1 }, + { 0, 1, -3, 8, -21, 48, -98, 184, -324, 542, + -871, 1364, -2116, 3345, -5606, -13798, 22111, -7199, 3905, -2412, + 1547, -992, 622, -377, 217, -118, 59, -27, 11, -4, 1 }, + { 0, 1, -2, 8, -21, 47, -96, 182, -320, 536, + -862, 1350, -2094, 3308, -5529, -13882, 22128, -7176, 3889, -2401, + 1540, -987, 620, -375, 216, -117, 59, -27, 11, -4, 1 }, + { 0, 1, -2, 8, -20, 47, -95, 179, -317, 530, + -853, 1335, -2071, 3270, -5452, -13965, 22144, -7153, 3872, -2390, + 1533, -983, 617, -374, 216, -117, 59, -27, 11, -4, 1 }, + { 0, 1, -2, 8, -20, 46, -94, 177, -313, 525, + -844, 1321, -2049, 3233, -5376, -14048, 22160, -7129, 3856, -2379, + 1526, -978, 614, -372, 215, -117, 59, -27, 11, -4, 1 }, + { 0, 0, -2, 8, -20, 45, -93, 175, -310, 519, + -835, 1307, -2027, 3196, -5299, -14130, 22176, -7105, 3839, -2368, + 1519, -974, 611, -370, 214, -116, 59, -27, 11, -4, 1 }, + { 0, 0, -2, 7, -20, 45, -92, 173, -306, 513, + -826, 1293, -2005, 3158, -5222, -14212, 22191, -7080, 3822, -2357, + 1511, -969, 609, -369, 213, -116, 58, -27, 11, -4, 1 }, + { 0, 0, -2, 7, -19, 44, -90, 171, -302, 507, + -816, 1279, -1982, 3121, -5146, -14294, 22206, -7055, 3805, -2346, + 1504, -965, 606, -367, 212, -115, 58, -27, 11, -4, 1 }, + { 0, 0, -2, 7, -19, 43, -89, 169, -299, 501, + -807, 1265, -1960, 3083, -5070, -14376, 22220, -7030, 3788, -2334, + 1497, -960, 603, -366, 211, -115, 58, -27, 11, -4, 1 }, + { 0, 0, -2, 7, -19, 43, -88, 167, -295, 495, + -798, 1250, -1937, 3046, -4993, -14457, 22234, -7005, 3770, -2323, + 1489, -955, 600, -364, 210, -114, 58, -27, 11, -4, 1 }, + { 0, 0, -2, 7, -18, 42, -87, 165, -292, 490, + -789, 1236, -1915, 3008, -4917, -14538, 22247, -6979, 3752, -2311, + 1482, -951, 597, -362, 209, -114, 58, -26, 11, -4, 1 }, + { 0, 0, -2, 7, -18, 42, -86, 162, -288, 484, + -780, 1222, -1893, 2971, -4841, -14618, 22260, -6953, 3735, -2300, + 1474, -946, 594, -361, 209, -114, 57, -26, 11, -4, 1 }, + { 0, 0, -2, 7, -18, 41, -85, 160, -284, 478, + -770, 1207, -1870, 2933, -4765, -14698, 22273, -6927, 3717, -2288, + 1466, -941, 591, -359, 208, -113, 57, -26, 11, -4, 1 }, + { 0, 0, -2, 7, -18, 40, -83, 158, -281, 472, + -761, 1193, -1848, 2896, -4689, -14778, 22285, -6900, 3698, -2276, + 1459, -936, 589, -357, 207, -113, 57, -26, 11, -4, 1 }, + { 0, 0, -2, 6, -17, 40, -82, 156, -277, 466, + -752, 1179, -1825, 2858, -4613, -14858, 22296, -6873, 3680, -2264, + 1451, -931, 586, -355, 206, -112, 57, -26, 11, -4, 1 }, + { 0, 0, -2, 6, -17, 39, -81, 154, -273, 460, + -743, 1164, -1802, 2820, -4538, -14937, 22307, -6846, 3661, -2252, + 1443, -926, 582, -354, 205, -112, 57, -26, 11, -4, 1 }, + { 0, 0, -2, 6, -17, 38, -80, 152, -270, 454, + -733, 1150, -1780, 2783, -4462, -15016, 22318, -6818, 3643, -2239, + 1435, -921, 579, -352, 204, -111, 56, -26, 11, -4, 1 }, + { 0, 0, -2, 6, -16, 38, -79, 150, -266, 448, + -724, 1135, -1757, 2745, -4386, -15094, 22328, -6790, 3624, -2227, + 1427, -916, 576, -350, 203, -111, 56, -26, 11, -4, 1 }, + { 0, 0, -2, 6, -16, 37, -77, 147, -262, 442, + -715, 1121, -1734, 2707, -4311, -15172, 22338, -6762, 3605, -2214, + 1419, -911, 573, -348, 202, -110, 56, -26, 11, -4, 1 }, + { 0, 0, -2, 6, -16, 37, -76, 145, -259, 436, + -705, 1106, -1712, 2669, -4235, -15250, 22347, -6733, 3586, -2202, + 1411, -906, 570, -347, 201, -110, 56, -26, 11, -4, 1 }, + { 0, 0, -2, 6, -15, 36, -75, 143, -255, 431, + -696, 1092, -1689, 2632, -4160, -15328, 22356, -6704, 3566, -2189, + 1403, -901, 567, -345, 200, -109, 55, -26, 10, -4, 1 }, + { 0, 0, -2, 6, -15, 35, -74, 141, -252, 425, + -687, 1077, -1666, 2594, -4085, -15405, 22364, -6675, 3547, -2176, + 1394, -895, 564, -343, 199, -109, 55, -26, 10, -4, 1 }, + { 0, 0, -2, 5, -15, 35, -73, 139, -248, 419, + -677, 1063, -1643, 2556, -4010, -15482, 22372, -6646, 3527, -2163, + 1386, -890, 561, -341, 198, -108, 55, -25, 10, -4, 1 }, + { 0, 0, -2, 5, -15, 34, -71, 137, -244, 413, + -668, 1048, -1621, 2518, -3935, -15558, 22380, -6616, 3507, -2150, + 1377, -885, 557, -339, 197, -108, 55, -25, 10, -4, 1 }, + { 0, 0, -1, 5, -14, 34, -70, 135, -241, 407, + -658, 1034, -1598, 2480, -3860, -15634, 22387, -6586, 3487, -2137, + 1369, -879, 554, -337, 196, -107, 54, -25, 10, -4, 1 }, + { 0, 0, -1, 5, -14, 33, -69, 132, -237, 401, + -649, 1019, -1575, 2442, -3785, -15710, 22393, -6555, 3466, -2124, + 1360, -874, 551, -335, 195, -107, 54, -25, 10, -4, 1 }, + { 0, 0, -1, 5, -14, 32, -68, 130, -233, 395, + -640, 1005, -1552, 2405, -3711, -15785, 22399, -6524, 3446, -2111, + 1352, -869, 547, -333, 194, -106, 54, -25, 10, -4, 1 }, + { 0, 0, -1, 5, -13, 32, -67, 128, -230, 389, + -630, 990, -1529, 2367, -3636, -15860, 22405, -6493, 3425, -2097, + 1343, -863, 544, -331, 193, -106, 54, -25, 10, -4, 1 }, + { 0, 0, -1, 5, -13, 31, -65, 126, -226, 383, + -621, 975, -1506, 2329, -3562, -15935, 22410, -6462, 3405, -2084, + 1334, -857, 541, -329, 192, -105, 53, -25, 10, -4, 1 }, + { 0, 0, -1, 5, -13, 30, -64, 124, -222, 377, + -611, 961, -1483, 2291, -3487, -16009, 22415, -6430, 3384, -2070, + 1326, -852, 537, -327, 191, -104, 53, -25, 10, -4, 1 }, + { 0, 0, -1, 4, -13, 30, -63, 122, -219, 371, + -602, 946, -1460, 2253, -3413, -16083, 22419, -6398, 3363, -2056, + 1317, -846, 534, -325, 189, -104, 53, -25, 10, -4, 1 }, + { 0, 0, -1, 4, -12, 29, -62, 120, -215, 365, + -593, 931, -1438, 2215, -3339, -16156, 22423, -6366, 3341, -2042, + 1308, -841, 530, -323, 188, -103, 53, -25, 10, -4, 1 }, + { 0, 0, -1, 4, -12, 29, -61, 117, -211, 359, + -583, 917, -1415, 2177, -3265, -16229, 22427, -6333, 3320, -2029, + 1299, -835, 527, -321, 187, -103, 52, -24, 10, -4, 1 }, + { 0, 0, -1, 4, -12, 28, -59, 115, -208, 353, + -574, 902, -1392, 2139, -3191, -16302, 22429, -6300, 3298, -2014, + 1290, -829, 523, -319, 186, -102, 52, -24, 10, -4, 1 }, + { 0, 0, -1, 4, -11, 27, -58, 113, -204, 347, + -564, 887, -1369, 2101, -3118, -16375, 22432, -6267, 3276, -2000, + 1280, -823, 520, -317, 185, -102, 52, -24, 10, -4, 1 }, + { 0, 0, -1, 4, -11, 27, -57, 111, -200, 341, + -555, 873, -1346, 2063, -3044, -16447, 22434, -6233, 3255, -1986, + 1271, -817, 516, -315, 184, -101, 52, -24, 10, -3, 1 }, + { 0, 0, -1, 4, -11, 26, -56, 109, -197, 335, + -545, 858, -1323, 2025, -2970, -16518, 22435, -6199, 3232, -1972, + 1262, -812, 513, -313, 183, -100, 51, -24, 10, -3, 1 }, + { 0, 0, -1, 4, -11, 26, -55, 107, -193, 329, + -536, 843, -1300, 1988, -2897, -16590, 22436, -6165, 3210, -1957, + 1253, -806, 509, -311, 181, -100, 51, -24, 10, -3, 1 }, + { 0, 0, -1, 3, -10, 25, -54, 104, -189, 323, + -526, 829, -1277, 1950, -2824, -16661, 22437, -6130, 3188, -1943, + 1243, -800, 505, -309, 180, -99, 51, -24, 10, -3, 1 }, + { 0, 0, -1, 3, -10, 24, -52, 102, -186, 317, + -517, 814, -1254, 1912, -2751, -16731, 22437, -6095, 3165, -1928, + 1234, -794, 502, -307, 179, -99, 51, -24, 10, -3, 1 }, + { 0, 0, -1, 3, -10, 24, -51, 100, -182, 311, + -507, 799, -1231, 1874, -2678, -16801, 22437, -6060, 3142, -1913, + 1224, -788, 498, -304, 178, -98, 50, -23, 10, -3, 1 }, + { 0, 0, -1, 3, -9, 23, -50, 98, -178, 305, + -498, 784, -1208, 1836, -2605, -16871, 22436, -6025, 3119, -1898, + 1214, -782, 494, -302, 177, -97, 50, -23, 10, -3, 1 }, + { 0, 0, -1, 3, -9, 22, -49, 96, -175, 299, + -488, 770, -1185, 1798, -2533, -16940, 22435, -5989, 3096, -1883, + 1205, -775, 490, -300, 175, -97, 50, -23, 10, -3, 1 }, + { 0, 0, -1, 3, -9, 22, -48, 94, -171, 293, + -479, 755, -1162, 1760, -2460, -17009, 22433, -5953, 3073, -1868, + 1195, -769, 487, -298, 174, -96, 49, -23, 10, -3, 1 }, + { 0, 0, -1, 3, -9, 21, -46, 92, -167, 287, + -470, 740, -1138, 1723, -2388, -17078, 22431, -5916, 3050, -1853, + 1185, -763, 483, -296, 173, -96, 49, -23, 10, -3, 1 }, + { 0, 0, -1, 3, -8, 21, -45, 89, -164, 281, + -460, 725, -1115, 1685, -2315, -17146, 22428, -5879, 3026, -1838, + 1175, -757, 479, -293, 172, -95, 49, -23, 10, -3, 1 }, + { 0, 0, -1, 3, -8, 20, -44, 87, -160, 275, + -451, 711, -1092, 1647, -2243, -17214, 22425, -5842, 3002, -1823, + 1166, -750, 475, -291, 170, -94, 48, -23, 10, -3, 1 }, + { 0, 0, 0, 2, -8, 19, -43, 85, -156, 269, + -441, 696, -1069, 1609, -2171, -17282, 22421, -5805, 2978, -1807, + 1156, -744, 471, -289, 169, -94, 48, -23, 9, -3, 1 }, + { 0, 0, 0, 2, -7, 19, -42, 83, -153, 263, + -432, 681, -1046, 1571, -2100, -17349, 22417, -5767, 2954, -1792, + 1145, -738, 467, -287, 168, -93, 48, -23, 9, -3, 1 }, + { 0, 0, 0, 2, -7, 18, -40, 81, -149, 257, + -422, 666, -1023, 1534, -2028, -17415, 22413, -5729, 2930, -1776, + 1135, -731, 463, -284, 167, -92, 48, -22, 9, -3, 1 }, + { 0, 0, 0, 2, -7, 18, -39, 79, -145, 251, + -413, 652, -1000, 1496, -1957, -17482, 22408, -5691, 2906, -1760, + 1125, -725, 459, -282, 165, -92, 47, -22, 9, -3, 1 }, + { 0, 0, 0, 2, -7, 17, -38, 77, -142, 245, + -403, 637, -977, 1458, -1885, -17547, 22402, -5652, 2881, -1745, + 1115, -718, 455, -280, 164, -91, 47, -22, 9, -3, 1 }, + { 0, 0, 0, 2, -6, 16, -37, 74, -138, 239, + -394, 622, -954, 1420, -1814, -17613, 22396, -5614, 2857, -1729, + 1105, -712, 451, -277, 163, -90, 47, -22, 9, -3, 1 }, + { 0, 0, 0, 2, -6, 16, -36, 72, -134, 233, + -384, 607, -931, 1383, -1743, -17678, 22390, -5574, 2832, -1713, + 1094, -705, 447, -275, 161, -90, 46, -22, 9, -3, 1 }, + { 0, 0, 0, 2, -6, 15, -35, 70, -131, 227, + -375, 593, -908, 1345, -1672, -17743, 22383, -5535, 2807, -1696, + 1084, -699, 443, -272, 160, -89, 46, -22, 9, -3, 1 }, + { 0, 0, 0, 1, -5, 15, -33, 68, -127, 221, + -365, 578, -885, 1308, -1601, -17807, 22376, -5495, 2782, -1680, + 1073, -692, 439, -270, 159, -88, 46, -22, 9, -3, 1 }, + { 0, 0, 0, 1, -5, 14, -32, 66, -123, 215, + -356, 563, -862, 1270, -1531, -17871, 22368, -5455, 2756, -1664, + 1063, -685, 435, -268, 157, -87, 45, -21, 9, -3, 1 }, + { 0, 0, 0, 1, -5, 13, -31, 64, -120, 209, + -346, 548, -839, 1232, -1461, -17934, 22359, -5414, 2731, -1648, + 1052, -679, 431, -265, 156, -87, 45, -21, 9, -3, 1 }, + { 0, 0, 0, 1, -5, 13, -30, 62, -116, 203, + -337, 534, -816, 1195, -1390, -17997, 22351, -5374, 2705, -1631, + 1042, -672, 427, -263, 155, -86, 45, -21, 9, -3, 1 }, + { 0, 0, 0, 1, -4, 12, -29, 60, -112, 197, + -327, 519, -793, 1158, -1320, -18060, 22341, -5333, 2679, -1615, + 1031, -665, 422, -260, 153, -85, 44, -21, 9, -3, 1 }, + { 0, 0, 0, 1, -4, 12, -28, 57, -109, 191, + -318, 504, -770, 1120, -1250, -18122, 22332, -5291, 2654, -1598, + 1020, -658, 418, -258, 152, -85, 44, -21, 9, -3, 1 }, + { 0, 0, 0, 1, -4, 11, -26, 55, -105, 185, + -308, 490, -747, 1083, -1181, -18184, 22322, -5250, 2627, -1581, + 1009, -651, 414, -255, 150, -84, 44, -21, 9, -3, 1 }, + { 0, 0, 0, 1, -4, 11, -25, 53, -101, 179, + -299, 475, -724, 1045, -1111, -18246, 22311, -5208, 2601, -1564, + 999, -644, 410, -253, 149, -83, 43, -21, 9, -3, 1 }, + { 0, 0, 0, 1, -3, 10, -24, 51, -98, 173, + -289, 460, -701, 1008, -1042, -18307, 22300, -5166, 2575, -1547, + 988, -637, 405, -250, 148, -82, 43, -20, 9, -3, 1 }, + { 0, 0, 0, 0, -3, 9, -23, 49, -94, 167, + -280, 445, -678, 971, -973, -18367, 22288, -5123, 2548, -1530, + 977, -630, 401, -248, 146, -82, 42, -20, 9, -3, 1 }, + { 0, 0, 0, 0, -3, 9, -22, 47, -91, 161, + -271, 431, -655, 933, -904, -18427, 22276, -5080, 2522, -1513, + 966, -623, 397, -245, 145, -81, 42, -20, 9, -3, 1 }, + { 0, 0, 0, 0, -2, 8, -21, 45, -87, 156, + -261, 416, -632, 896, -835, -18487, 22264, -5037, 2495, -1496, + 954, -616, 392, -242, 143, -80, 42, -20, 8, -3, 1 }, + { 0, 0, 0, 0, -2, 8, -20, 43, -83, 150, + -252, 401, -610, 859, -766, -18547, 22251, -4994, 2468, -1479, + 943, -609, 388, -240, 142, -79, 41, -20, 8, -3, 1 }, + { 0, 0, 0, 0, -2, 7, -18, 41, -80, 144, + -242, 387, -587, 822, -698, -18606, 22237, -4950, 2441, -1461, + 932, -602, 384, -237, 140, -79, 41, -20, 8, -3, 1 }, + { 0, 0, 0, 0, -2, 6, -17, 39, -76, 138, + -233, 372, -564, 785, -630, -18664, 22223, -4906, 2414, -1444, + 921, -595, 379, -235, 139, -78, 41, -19, 8, -3, 1 }, + { 0, 0, 0, 0, -1, 6, -16, 36, -73, 132, + -223, 357, -541, 748, -562, -18722, 22209, -4862, 2386, -1427, + 909, -588, 375, -232, 137, -77, 40, -19, 8, -3, 1 }, + { 0, 0, 0, 0, -1, 5, -15, 34, -69, 126, + -214, 343, -518, 711, -494, -18780, 22194, -4817, 2359, -1409, + 898, -580, 370, -229, 136, -76, 40, -19, 8, -3, 1 }, + { 0, 0, 0, 0, -1, 5, -14, 32, -65, 120, + -205, 328, -496, 674, -426, -18837, 22178, -4772, 2331, -1391, + 887, -573, 366, -227, 134, -76, 40, -19, 8, -3, 1 }, + { 0, 0, 1, 0, -1, 4, -13, 30, -62, 114, + -195, 314, -473, 637, -358, -18894, 22163, -4727, 2303, -1373, + 875, -566, 361, -224, 133, -75, 39, -19, 8, -3, 1 }, + { 0, 0, 1, -1, 0, 4, -12, 28, -58, 108, + -186, 299, -450, 600, -291, -18951, 22146, -4681, 2275, -1356, + 864, -558, 357, -221, 131, -74, 39, -19, 8, -3, 1 }, + { 0, 0, 1, -1, 0, 3, -10, 26, -55, 102, + -177, 284, -427, 564, -224, -19007, 22130, -4636, 2247, -1338, + 852, -551, 352, -218, 130, -73, 38, -18, 8, -3, 1 }, + { 0, 0, 1, -1, 0, 2, -9, 24, -51, 96, + -167, 270, -405, 527, -157, -19062, 22112, -4589, 2219, -1320, + 840, -544, 347, -216, 128, -72, 38, -18, 8, -3, 1 }, + { 0, 0, 1, -1, 0, 2, -8, 22, -47, 91, + -158, 255, -382, 490, -90, -19117, 22095, -4543, 2190, -1301, + 829, -536, 343, -213, 127, -72, 38, -18, 8, -3, 1 }, + { 0, 0, 1, -1, 1, 1, -7, 20, -44, 85, + -148, 241, -359, 454, -24, -19172, 22076, -4496, 2162, -1283, + 817, -529, 338, -210, 125, -71, 37, -18, 8, -3, 1 }, + { 0, 0, 1, -1, 1, 1, -6, 18, -40, 79, + -139, 226, -337, 417, 43, -19226, 22058, -4450, 2133, -1265, + 805, -521, 334, -207, 124, -70, 37, -18, 8, -3, 1 }, + { 0, 0, 1, -1, 1, 0, -5, 16, -37, 73, + -130, 212, -314, 381, 109, -19280, 22039, -4402, 2104, -1247, + 793, -514, 329, -205, 122, -69, 36, -18, 8, -3, 1 }, + { 0, 0, 1, -1, 2, 0, -4, 14, -33, 67, + -121, 197, -292, 344, 175, -19334, 22019, -4355, 2076, -1228, + 781, -506, 324, -202, 121, -68, 36, -17, 8, -3, 1 }, + { 0, 0, 1, -1, 2, -1, -3, 12, -30, 61, + -111, 183, -269, 308, 240, -19387, 21999, -4307, 2046, -1210, + 769, -498, 319, -199, 119, -67, 36, -17, 8, -3, 1 }, + { 0, 0, 1, -2, 2, -2, -2, 10, -26, 55, + -102, 168, -247, 271, 306, -19439, 21978, -4259, 2017, -1191, + 757, -491, 315, -196, 117, -67, 35, -17, 7, -3, 1 }, + { 0, 0, 1, -2, 2, -2, 0, 8, -23, 50, + -93, 154, -224, 235, 371, -19491, 21957, -4211, 1988, -1172, + 745, -483, 310, -193, 116, -66, 35, -17, 7, -3, 1 }, + { 0, 0, 1, -2, 3, -3, 1, 6, -19, 44, + -83, 140, -202, 199, 436, -19543, 21936, -4162, 1958, -1154, + 733, -475, 305, -191, 114, -65, 34, -17, 7, -3, 1 }, + { 0, 0, 1, -2, 3, -3, 2, 4, -16, 38, + -74, 125, -179, 163, 501, -19594, 21914, -4113, 1929, -1135, + 721, -467, 300, -188, 113, -64, 34, -17, 7, -3, 1 }, + { 0, 0, 1, -2, 3, -4, 3, 1, -12, 32, + -65, 111, -157, 127, 566, -19645, 21891, -4064, 1899, -1116, + 709, -460, 295, -185, 111, -63, 34, -16, 7, -3, 1 }, + { 0, 0, 1, -2, 3, -4, 4, -1, -9, 26, + -56, 96, -135, 91, 631, -19696, 21868, -4014, 1869, -1097, + 697, -452, 291, -182, 109, -62, 33, -16, 7, -3, 1 }, + { 0, 0, 1, -2, 4, -5, 5, -3, -5, 21, + -47, 82, -112, 55, 695, -19746, 21845, -3964, 1839, -1078, + 684, -444, 286, -179, 108, -61, 33, -16, 7, -3, 1 }, + { 0, 0, 1, -2, 4, -5, 6, -5, -2, 15, + -37, 68, -90, 19, 759, -19795, 21821, -3914, 1809, -1059, + 672, -436, 281, -176, 106, -61, 32, -16, 7, -3, 1 }, + { 0, 0, 1, -2, 4, -6, 7, -7, 2, 9, + -28, 53, -68, -16, 823, -19844, 21797, -3864, 1779, -1039, + 660, -428, 276, -173, 104, -60, 32, -16, 7, -3, 1 }, + { 0, 0, 1, -2, 4, -6, 8, -9, 5, 3, + -19, 39, -46, -52, 886, -19893, 21772, -3813, 1748, -1020, + 647, -420, 271, -170, 103, -59, 31, -15, 7, -3, 1 }, + { 0, 0, 1, -3, 5, -7, 9, -11, 9, -2, + -10, 25, -23, -88, 950, -19941, 21747, -3762, 1718, -1001, + 635, -412, 266, -167, 101, -58, 31, -15, 7, -3, 1 }, + { 0, 0, 1, -3, 5, -8, 10, -13, 12, -8, + -1, 11, -1, -123, 1013, -19989, 21721, -3711, 1687, -981, + 622, -404, 261, -164, 99, -57, 31, -15, 7, -3, 1 }, + { 0, 0, 1, -3, 5, -8, 12, -15, 16, -14, + 8, -3, 21, -159, 1076, -20036, 21695, -3660, 1657, -962, + 610, -396, 256, -161, 98, -56, 30, -15, 7, -3, 1 }, + { 0, 0, 1, -3, 5, -9, 13, -17, 19, -19, + 17, -18, 43, -194, 1139, -20083, 21668, -3608, 1626, -942, + 597, -388, 251, -158, 96, -55, 30, -15, 7, -3, 1 }, + { 0, -1, 1, -3, 6, -9, 14, -18, 23, -25, + 26, -32, 65, -229, 1201, -20130, 21641, -3556, 1595, -923, + 584, -380, 246, -155, 94, -54, 29, -15, 6, -2, 1 }, + { 0, -1, 1, -3, 6, -10, 15, -20, 26, -31, + 35, -46, 87, -265, 1263, -20176, 21613, -3504, 1564, -903, + 572, -372, 241, -152, 93, -53, 29, -14, 6, -2, 1 }, + { 0, -1, 1, -3, 6, -10, 16, -22, 29, -36, + 44, -60, 109, -300, 1326, -20221, 21585, -3451, 1532, -883, + 559, -364, 236, -149, 91, -52, 28, -14, 6, -2, 1 }, + { 0, -1, 1, -3, 6, -11, 17, -24, 33, -42, + 54, -74, 131, -335, 1387, -20266, 21557, -3398, 1501, -863, + 546, -356, 231, -146, 89, -52, 28, -14, 6, -2, 1 }, + { 0, -1, 1, -3, 6, -11, 18, -26, 36, -48, + 63, -88, 152, -370, 1449, -20311, 21528, -3345, 1469, -843, + 533, -347, 226, -143, 87, -51, 27, -14, 6, -2, 1 }, + { 0, -1, 2, -3, 7, -12, 19, -28, 40, -53, + 71, -102, 174, -405, 1510, -20355, 21498, -3292, 1438, -823, + 520, -339, 221, -140, 86, -50, 27, -14, 6, -2, 1 }, + { 0, -1, 2, -4, 7, -12, 20, -30, 43, -59, + 80, -116, 196, -439, 1572, -20399, 21468, -3238, 1406, -803, + 507, -331, 215, -137, 84, -49, 27, -13, 6, -2, 1 }, + { 0, -1, 2, -4, 7, -13, 21, -32, 46, -65, + 89, -130, 218, -474, 1632, -20442, 21438, -3184, 1374, -783, + 494, -323, 210, -134, 82, -48, 26, -13, 6, -2, 1 }, + { 0, -1, 2, -4, 7, -13, 22, -34, 50, -70, + 98, -144, 239, -509, 1693, -20485, 21407, -3130, 1342, -763, + 481, -314, 205, -131, 80, -47, 26, -13, 6, -2, 1 }, + { 0, -1, 2, -4, 8, -14, 23, -36, 53, -76, + 107, -158, 261, -543, 1754, -20527, 21376, -3076, 1310, -743, + 468, -306, 200, -128, 79, -46, 25, -13, 6, -2, 1 }, + { 0, -1, 2, -4, 8, -14, 24, -38, 57, -81, + 116, -172, 282, -578, 1814, -20569, 21344, -3021, 1278, -723, + 455, -298, 195, -125, 77, -45, 25, -12, 6, -2, 1 }, + { 0, -1, 2, -4, 8, -15, 25, -40, 60, -87, + 125, -186, 304, -612, 1874, -20611, 21312, -2966, 1246, -702, + 442, -289, 189, -121, 75, -44, 24, -12, 6, -2, 1 }, + { 0, -1, 2, -4, 8, -15, 26, -42, 63, -92, + 134, -199, 325, -646, 1933, -20652, 21279, -2911, 1213, -682, + 429, -281, 184, -118, 73, -43, 24, -12, 6, -2, 1 }, + { 0, -1, 2, -4, 9, -16, 27, -44, 67, -98, + 143, -213, 347, -680, 1993, -20692, 21246, -2856, 1181, -661, + 416, -272, 179, -115, 71, -42, 23, -12, 5, -2, 1 }, + { 0, -1, 2, -4, 9, -16, 28, -46, 70, -103, + 151, -227, 368, -714, 2052, -20732, 21212, -2800, 1148, -641, + 402, -264, 174, -112, 70, -41, 23, -12, 5, -2, 1 }, + { 0, -1, 2, -4, 9, -17, 29, -47, 73, -109, + 160, -241, 389, -748, 2111, -20772, 21178, -2744, 1115, -620, + 389, -255, 168, -109, 68, -40, 22, -11, 5, -2, 1 }, + { 0, -1, 2, -4, 9, -17, 30, -49, 76, -114, + 169, -254, 411, -782, 2170, -20811, 21143, -2688, 1083, -599, + 376, -247, 163, -106, 66, -39, 22, -11, 5, -2, 1 }, + { 0, -1, 2, -5, 9, -18, 31, -51, 80, -120, + 178, -268, 432, -816, 2228, -20850, 21108, -2631, 1050, -579, + 363, -238, 158, -102, 64, -38, 21, -11, 5, -2, 1 }, + { 0, -1, 2, -5, 10, -18, 32, -53, 83, -125, + 186, -282, 453, -850, 2287, -20888, 21073, -2574, 1017, -558, + 349, -230, 152, -99, 62, -37, 21, -11, 5, -2, 1 }, + { 0, -1, 2, -5, 10, -19, 33, -55, 86, -131, + 195, -295, 474, -883, 2345, -20926, 21037, -2517, 983, -537, + 336, -221, 147, -96, 61, -36, 20, -11, 5, -2, 1 }, + { 0, -1, 2, -5, 10, -19, 34, -57, 89, -136, + 204, -309, 495, -917, 2403, -20963, 21000, -2460, 950, -516, + 322, -212, 142, -93, 59, -35, 20, -10, 5, -2, 1 }, + { 0, -1, 2, -5, 10, -20, 35, -59, 93, -142, + 212, -322, 516, -950, 2460, -21000, 20963, -2403, 917, -495, + 309, -204, 136, -89, 57, -34, 19, -10, 5, -2, 1 }, + { 0, -1, 2, -5, 11, -20, 36, -61, 96, -147, + 221, -336, 537, -983, 2517, -21037, 20926, -2345, 883, -474, + 295, -195, 131, -86, 55, -33, 19, -10, 5, -2, 1 }, + { 0, -1, 2, -5, 11, -21, 37, -62, 99, -152, + 230, -349, 558, -1017, 2574, -21073, 20888, -2287, 850, -453, + 282, -186, 125, -83, 53, -32, 18, -10, 5, -2, 1 }, + { 0, -1, 2, -5, 11, -21, 38, -64, 102, -158, + 238, -363, 579, -1050, 2631, -21108, 20850, -2228, 816, -432, + 268, -178, 120, -80, 51, -31, 18, -9, 5, -2, 1 }, + { 0, -1, 2, -5, 11, -22, 39, -66, 106, -163, + 247, -376, 599, -1083, 2688, -21143, 20811, -2170, 782, -411, + 254, -169, 114, -76, 49, -30, 17, -9, 4, -2, 1 }, + { 0, -1, 2, -5, 11, -22, 40, -68, 109, -168, + 255, -389, 620, -1115, 2744, -21178, 20772, -2111, 748, -389, + 241, -160, 109, -73, 47, -29, 17, -9, 4, -2, 1 }, + { 0, -1, 2, -5, 12, -23, 41, -70, 112, -174, + 264, -402, 641, -1148, 2800, -21212, 20732, -2052, 714, -368, + 227, -151, 103, -70, 46, -28, 16, -9, 4, -2, 1 }, + { 0, -1, 2, -5, 12, -23, 42, -71, 115, -179, + 272, -416, 661, -1181, 2856, -21246, 20692, -1993, 680, -347, + 213, -143, 98, -67, 44, -27, 16, -9, 4, -2, 1 }, + { 0, -1, 2, -6, 12, -24, 43, -73, 118, -184, + 281, -429, 682, -1213, 2911, -21279, 20652, -1933, 646, -325, + 199, -134, 92, -63, 42, -26, 15, -8, 4, -2, 1 }, + { 0, -1, 2, -6, 12, -24, 44, -75, 121, -189, + 289, -442, 702, -1246, 2966, -21312, 20611, -1874, 612, -304, + 186, -125, 87, -60, 40, -25, 15, -8, 4, -2, 1 }, + { 0, -1, 2, -6, 12, -25, 45, -77, 125, -195, + 298, -455, 723, -1278, 3021, -21344, 20569, -1814, 578, -282, + 172, -116, 81, -57, 38, -24, 14, -8, 4, -2, 1 }, + { 0, -1, 2, -6, 13, -25, 46, -79, 128, -200, + 306, -468, 743, -1310, 3076, -21376, 20527, -1754, 543, -261, + 158, -107, 76, -53, 36, -23, 14, -8, 4, -2, 1 }, + { 0, -1, 2, -6, 13, -26, 47, -80, 131, -205, + 314, -481, 763, -1342, 3130, -21407, 20485, -1693, 509, -239, + 144, -98, 70, -50, 34, -22, 13, -7, 4, -2, 1 }, + { 0, -1, 2, -6, 13, -26, 48, -82, 134, -210, + 323, -494, 783, -1374, 3184, -21438, 20442, -1632, 474, -218, + 130, -89, 65, -46, 32, -21, 13, -7, 4, -2, 1 }, + { 0, -1, 2, -6, 13, -27, 49, -84, 137, -215, + 331, -507, 803, -1406, 3238, -21468, 20399, -1572, 439, -196, + 116, -80, 59, -43, 30, -20, 12, -7, 4, -2, 1 }, + { 0, -1, 2, -6, 14, -27, 50, -86, 140, -221, + 339, -520, 823, -1438, 3292, -21498, 20355, -1510, 405, -174, + 102, -71, 53, -40, 28, -19, 12, -7, 3, -2, 1 }, + { 0, -1, 2, -6, 14, -27, 51, -87, 143, -226, + 347, -533, 843, -1469, 3345, -21528, 20311, -1449, 370, -152, + 88, -63, 48, -36, 26, -18, 11, -6, 3, -1, 1 }, + { 0, -1, 2, -6, 14, -28, 52, -89, 146, -231, + 356, -546, 863, -1501, 3398, -21557, 20266, -1387, 335, -131, + 74, -54, 42, -33, 24, -17, 11, -6, 3, -1, 1 }, + { 0, -1, 2, -6, 14, -28, 52, -91, 149, -236, + 364, -559, 883, -1532, 3451, -21585, 20221, -1326, 300, -109, + 60, -44, 36, -29, 22, -16, 10, -6, 3, -1, 1 }, + { 0, -1, 2, -6, 14, -29, 53, -93, 152, -241, + 372, -572, 903, -1564, 3504, -21613, 20176, -1263, 265, -87, + 46, -35, 31, -26, 20, -15, 10, -6, 3, -1, 1 }, + { 0, -1, 2, -6, 15, -29, 54, -94, 155, -246, + 380, -584, 923, -1595, 3556, -21641, 20130, -1201, 229, -65, + 32, -26, 25, -23, 18, -14, 9, -6, 3, -1, 1 }, + { 0, -1, 3, -7, 15, -30, 55, -96, 158, -251, + 388, -597, 942, -1626, 3608, -21668, 20083, -1139, 194, -43, + 18, -17, 19, -19, 17, -13, 9, -5, 3, -1, 0 }, + { 0, -1, 3, -7, 15, -30, 56, -98, 161, -256, + 396, -610, 962, -1657, 3660, -21695, 20036, -1076, 159, -21, + 3, -8, 14, -16, 15, -12, 8, -5, 3, -1, 0 }, + { 0, -1, 3, -7, 15, -31, 57, -99, 164, -261, + 404, -622, 981, -1687, 3711, -21721, 19989, -1013, 123, 1, + -11, 1, 8, -12, 13, -10, 8, -5, 3, -1, 0 }, + { 0, -1, 3, -7, 15, -31, 58, -101, 167, -266, + 412, -635, 1001, -1718, 3762, -21747, 19941, -950, 88, 23, + -25, 10, 2, -9, 11, -9, 7, -5, 3, -1, 0 }, + { 0, -1, 3, -7, 15, -31, 59, -103, 170, -271, + 420, -647, 1020, -1748, 3813, -21772, 19893, -886, 52, 46, + -39, 19, -3, -5, 9, -8, 6, -4, 2, -1, 0 }, + { 0, -1, 3, -7, 16, -32, 60, -104, 173, -276, + 428, -660, 1039, -1779, 3864, -21797, 19844, -823, 16, 68, + -53, 28, -9, -2, 7, -7, 6, -4, 2, -1, 0 }, + { 0, -1, 3, -7, 16, -32, 61, -106, 176, -281, + 436, -672, 1059, -1809, 3914, -21821, 19795, -759, -19, 90, + -68, 37, -15, 2, 5, -6, 5, -4, 2, -1, 0 }, + { 0, -1, 3, -7, 16, -33, 61, -108, 179, -286, + 444, -684, 1078, -1839, 3964, -21845, 19746, -695, -55, 112, + -82, 47, -21, 5, 3, -5, 5, -4, 2, -1, 0 }, + { 0, -1, 3, -7, 16, -33, 62, -109, 182, -291, + 452, -697, 1097, -1869, 4014, -21868, 19696, -631, -91, 135, + -96, 56, -26, 9, 1, -4, 4, -3, 2, -1, 0 }, + { 0, -1, 3, -7, 16, -34, 63, -111, 185, -295, + 460, -709, 1116, -1899, 4064, -21891, 19645, -566, -127, 157, + -111, 65, -32, 12, -1, -3, 4, -3, 2, -1, 0 }, + { 0, -1, 3, -7, 17, -34, 64, -113, 188, -300, + 467, -721, 1135, -1929, 4113, -21914, 19594, -501, -163, 179, + -125, 74, -38, 16, -4, -2, 3, -3, 2, -1, 0 }, + { 0, -1, 3, -7, 17, -34, 65, -114, 191, -305, + 475, -733, 1154, -1958, 4162, -21936, 19543, -436, -199, 202, + -140, 83, -44, 19, -6, -1, 3, -3, 2, -1, 0 }, + { 0, -1, 3, -7, 17, -35, 66, -116, 193, -310, + 483, -745, 1172, -1988, 4211, -21957, 19491, -371, -235, 224, + -154, 93, -50, 23, -8, 0, 2, -2, 2, -1, 0 }, + { 0, -1, 3, -7, 17, -35, 67, -117, 196, -315, + 491, -757, 1191, -2017, 4259, -21978, 19439, -306, -271, 247, + -168, 102, -55, 26, -10, 2, 2, -2, 2, -1, 0 }, + { 0, -1, 3, -8, 17, -36, 67, -119, 199, -319, + 498, -769, 1210, -2046, 4307, -21999, 19387, -240, -308, 269, + -183, 111, -61, 30, -12, 3, 1, -2, 1, -1, 0 }, + { 0, -1, 3, -8, 17, -36, 68, -121, 202, -324, + 506, -781, 1228, -2076, 4355, -22019, 19334, -175, -344, 292, + -197, 121, -67, 33, -14, 4, 0, -2, 1, -1, 0 }, + { 0, -1, 3, -8, 18, -36, 69, -122, 205, -329, + 514, -793, 1247, -2104, 4402, -22039, 19280, -109, -381, 314, + -212, 130, -73, 37, -16, 5, 0, -1, 1, -1, 0 }, + { 0, -1, 3, -8, 18, -37, 70, -124, 207, -334, + 521, -805, 1265, -2133, 4450, -22058, 19226, -43, -417, 337, + -226, 139, -79, 40, -18, 6, -1, -1, 1, -1, 0 }, + { 0, -1, 3, -8, 18, -37, 71, -125, 210, -338, + 529, -817, 1283, -2162, 4496, -22076, 19172, 24, -454, 359, + -241, 148, -85, 44, -20, 7, -1, -1, 1, -1, 0 }, + { 0, -1, 3, -8, 18, -38, 72, -127, 213, -343, + 536, -829, 1301, -2190, 4543, -22095, 19117, 90, -490, 382, + -255, 158, -91, 47, -22, 8, -2, 0, 1, -1, 0 }, + { 0, -1, 3, -8, 18, -38, 72, -128, 216, -347, + 544, -840, 1320, -2219, 4589, -22112, 19062, 157, -527, 405, + -270, 167, -96, 51, -24, 9, -2, 0, 1, -1, 0 }, + { 0, -1, 3, -8, 18, -38, 73, -130, 218, -352, + 551, -852, 1338, -2247, 4636, -22130, 19007, 224, -564, 427, + -284, 177, -102, 55, -26, 10, -3, 0, 1, -1, 0 }, + { 0, -1, 3, -8, 19, -39, 74, -131, 221, -357, + 558, -864, 1356, -2275, 4681, -22146, 18951, 291, -600, 450, + -299, 186, -108, 58, -28, 12, -4, 0, 1, -1, 0 }, + { 0, -1, 3, -8, 19, -39, 75, -133, 224, -361, + 566, -875, 1373, -2303, 4727, -22163, 18894, 358, -637, 473, + -314, 195, -114, 62, -30, 13, -4, 1, 0, -1, 0 }, + { 0, -1, 3, -8, 19, -40, 76, -134, 227, -366, + 573, -887, 1391, -2331, 4772, -22178, 18837, 426, -674, 496, + -328, 205, -120, 65, -32, 14, -5, 1, 0, 0, 0 }, + { 0, -1, 3, -8, 19, -40, 76, -136, 229, -370, + 580, -898, 1409, -2359, 4817, -22194, 18780, 494, -711, 518, + -343, 214, -126, 69, -34, 15, -5, 1, 0, 0, 0 }, + { 0, -1, 3, -8, 19, -40, 77, -137, 232, -375, + 588, -909, 1427, -2386, 4862, -22209, 18722, 562, -748, 541, + -357, 223, -132, 73, -36, 16, -6, 1, 0, 0, 0 }, + { 0, -1, 3, -8, 19, -41, 78, -139, 235, -379, + 595, -921, 1444, -2414, 4906, -22223, 18664, 630, -785, 564, + -372, 233, -138, 76, -39, 17, -6, 2, 0, 0, 0 }, + { 0, -1, 3, -8, 20, -41, 79, -140, 237, -384, + 602, -932, 1461, -2441, 4950, -22237, 18606, 698, -822, 587, + -387, 242, -144, 80, -41, 18, -7, 2, 0, 0, 0 }, + { 0, -1, 3, -8, 20, -41, 79, -142, 240, -388, + 609, -943, 1479, -2468, 4994, -22251, 18547, 766, -859, 610, + -401, 252, -150, 83, -43, 20, -8, 2, 0, 0, 0 }, + { 0, -1, 3, -8, 20, -42, 80, -143, 242, -392, + 616, -954, 1496, -2495, 5037, -22264, 18487, 835, -896, 632, + -416, 261, -156, 87, -45, 21, -8, 2, 0, 0, 0 }, + { 0, -1, 3, -9, 20, -42, 81, -145, 245, -397, + 623, -966, 1513, -2522, 5080, -22276, 18427, 904, -933, 655, + -431, 271, -161, 91, -47, 22, -9, 3, 0, 0, 0 }, + { 0, -1, 3, -9, 20, -42, 82, -146, 248, -401, + 630, -977, 1530, -2548, 5123, -22288, 18367, 973, -971, 678, + -445, 280, -167, 94, -49, 23, -9, 3, 0, 0, 0 }, + { 0, -1, 3, -9, 20, -43, 82, -148, 250, -405, + 637, -988, 1547, -2575, 5166, -22300, 18307, 1042, -1008, 701, + -460, 289, -173, 98, -51, 24, -10, 3, -1, 0, 0 }, + { 0, -1, 3, -9, 21, -43, 83, -149, 253, -410, + 644, -999, 1564, -2601, 5208, -22311, 18246, 1111, -1045, 724, + -475, 299, -179, 101, -53, 25, -11, 4, -1, 0, 0 }, + { 0, -1, 3, -9, 21, -44, 84, -150, 255, -414, + 651, -1009, 1581, -2627, 5250, -22322, 18184, 1181, -1083, 747, + -490, 308, -185, 105, -55, 26, -11, 4, -1, 0, 0 }, + { 0, -1, 3, -9, 21, -44, 85, -152, 258, -418, + 658, -1020, 1598, -2654, 5291, -22332, 18122, 1250, -1120, 770, + -504, 318, -191, 109, -57, 28, -12, 4, -1, 0, 0 }, + { 0, -1, 3, -9, 21, -44, 85, -153, 260, -422, + 665, -1031, 1615, -2679, 5333, -22341, 18060, 1320, -1158, 793, + -519, 327, -197, 112, -60, 29, -12, 4, -1, 0, 0 }, + { 0, -1, 3, -9, 21, -45, 86, -155, 263, -427, + 672, -1042, 1631, -2705, 5374, -22351, 17997, 1390, -1195, 816, + -534, 337, -203, 116, -62, 30, -13, 5, -1, 0, 0 }, + { 0, -1, 3, -9, 21, -45, 87, -156, 265, -431, + 679, -1052, 1648, -2731, 5414, -22359, 17934, 1461, -1232, 839, + -548, 346, -209, 120, -64, 31, -13, 5, -1, 0, 0 }, + { 0, -1, 3, -9, 21, -45, 87, -157, 268, -435, + 685, -1063, 1664, -2756, 5455, -22368, 17871, 1531, -1270, 862, + -563, 356, -215, 123, -66, 32, -14, 5, -1, 0, 0 }, + { 0, -1, 3, -9, 22, -46, 88, -159, 270, -439, + 692, -1073, 1680, -2782, 5495, -22376, 17807, 1601, -1308, 885, + -578, 365, -221, 127, -68, 33, -15, 5, -1, 0, 0 }, + { 0, -1, 3, -9, 22, -46, 89, -160, 272, -443, + 699, -1084, 1696, -2807, 5535, -22383, 17743, 1672, -1345, 908, + -593, 375, -227, 131, -70, 35, -15, 6, -2, 0, 0 }, + { 0, -1, 3, -9, 22, -46, 90, -161, 275, -447, + 705, -1094, 1713, -2832, 5574, -22390, 17678, 1743, -1383, 931, + -607, 384, -233, 134, -72, 36, -16, 6, -2, 0, 0 }, + { 0, -1, 3, -9, 22, -47, 90, -163, 277, -451, + 712, -1105, 1729, -2857, 5614, -22396, 17613, 1814, -1420, 954, + -622, 394, -239, 138, -74, 37, -16, 6, -2, 0, 0 }, + { 0, -1, 3, -9, 22, -47, 91, -164, 280, -455, + 718, -1115, 1745, -2881, 5652, -22402, 17547, 1885, -1458, 977, + -637, 403, -245, 142, -77, 38, -17, 7, -2, 0, 0 }, + { 0, -1, 3, -9, 22, -47, 92, -165, 282, -459, + 725, -1125, 1760, -2906, 5691, -22408, 17482, 1957, -1496, 1000, + -652, 413, -251, 145, -79, 39, -18, 7, -2, 0, 0 }, + { 0, -1, 3, -9, 22, -48, 92, -167, 284, -463, + 731, -1135, 1776, -2930, 5729, -22413, 17415, 2028, -1534, 1023, + -666, 422, -257, 149, -81, 40, -18, 7, -2, 0, 0 }, + { 0, -1, 3, -9, 23, -48, 93, -168, 287, -467, + 738, -1145, 1792, -2954, 5767, -22417, 17349, 2100, -1571, 1046, + -681, 432, -263, 153, -83, 42, -19, 7, -2, 0, 0 }, + { 0, -1, 3, -9, 23, -48, 94, -169, 289, -471, + 744, -1156, 1807, -2978, 5805, -22421, 17282, 2171, -1609, 1069, + -696, 441, -269, 156, -85, 43, -19, 8, -2, 0, 0 }, + { 0, -1, 3, -10, 23, -48, 94, -170, 291, -475, + 750, -1166, 1823, -3002, 5842, -22425, 17214, 2243, -1647, 1092, + -711, 451, -275, 160, -87, 44, -20, 8, -3, 1, 0 }, + { 0, -1, 3, -10, 23, -49, 95, -172, 293, -479, + 757, -1175, 1838, -3026, 5879, -22428, 17146, 2315, -1685, 1115, + -725, 460, -281, 164, -89, 45, -21, 8, -3, 1, 0 }, + { 0, -1, 3, -10, 23, -49, 96, -173, 296, -483, + 763, -1185, 1853, -3050, 5916, -22431, 17078, 2388, -1723, 1138, + -740, 470, -287, 167, -92, 46, -21, 9, -3, 1, 0 }, + { 0, -1, 3, -10, 23, -49, 96, -174, 298, -487, + 769, -1195, 1868, -3073, 5953, -22433, 17009, 2460, -1760, 1162, + -755, 479, -293, 171, -94, 48, -22, 9, -3, 1, 0 }, + { 0, -1, 3, -10, 23, -50, 97, -175, 300, -490, + 775, -1205, 1883, -3096, 5989, -22435, 16940, 2533, -1798, 1185, + -770, 488, -299, 175, -96, 49, -22, 9, -3, 1, 0 }, + { 0, -1, 3, -10, 23, -50, 97, -177, 302, -494, + 782, -1214, 1898, -3119, 6025, -22436, 16871, 2605, -1836, 1208, + -784, 498, -305, 178, -98, 50, -23, 9, -3, 1, 0 }, + { 0, -1, 3, -10, 23, -50, 98, -178, 304, -498, + 788, -1224, 1913, -3142, 6060, -22437, 16801, 2678, -1874, 1231, + -799, 507, -311, 182, -100, 51, -24, 10, -3, 1, 0 }, + { 0, -1, 3, -10, 24, -51, 99, -179, 307, -502, + 794, -1234, 1928, -3165, 6095, -22437, 16731, 2751, -1912, 1254, + -814, 517, -317, 186, -102, 52, -24, 10, -3, 1, 0 }, + { 0, -1, 3, -10, 24, -51, 99, -180, 309, -505, + 800, -1243, 1943, -3188, 6130, -22437, 16661, 2824, -1950, 1277, + -829, 526, -323, 189, -104, 54, -25, 10, -3, 1, 0 }, + { 0, -1, 3, -10, 24, -51, 100, -181, 311, -509, + 806, -1253, 1957, -3210, 6165, -22436, 16590, 2897, -1988, 1300, + -843, 536, -329, 193, -107, 55, -26, 11, -4, 1, 0 }, + { 0, -1, 3, -10, 24, -51, 100, -183, 313, -513, + 812, -1262, 1972, -3232, 6199, -22435, 16518, 2970, -2025, 1323, + -858, 545, -335, 197, -109, 56, -26, 11, -4, 1, 0 }, + { 0, -1, 3, -10, 24, -52, 101, -184, 315, -516, + 817, -1271, 1986, -3255, 6233, -22434, 16447, 3044, -2063, 1346, + -873, 555, -341, 200, -111, 57, -27, 11, -4, 1, 0 }, + { 0, -1, 4, -10, 24, -52, 102, -185, 317, -520, + 823, -1280, 2000, -3276, 6267, -22432, 16375, 3118, -2101, 1369, + -887, 564, -347, 204, -113, 58, -27, 11, -4, 1, 0 }, + { 0, -1, 4, -10, 24, -52, 102, -186, 319, -523, + 829, -1290, 2014, -3298, 6300, -22429, 16302, 3191, -2139, 1392, + -902, 574, -353, 208, -115, 59, -28, 12, -4, 1, 0 }, + { 0, -1, 4, -10, 24, -52, 103, -187, 321, -527, + 835, -1299, 2029, -3320, 6333, -22427, 16229, 3265, -2177, 1415, + -917, 583, -359, 211, -117, 61, -29, 12, -4, 1, 0 }, + { 0, -1, 4, -10, 25, -53, 103, -188, 323, -530, + 841, -1308, 2042, -3341, 6366, -22423, 16156, 3339, -2215, 1438, + -931, 593, -365, 215, -120, 62, -29, 12, -4, 1, 0 }, + { 0, -1, 4, -10, 25, -53, 104, -189, 325, -534, + 846, -1317, 2056, -3363, 6398, -22419, 16083, 3413, -2253, 1460, + -946, 602, -371, 219, -122, 63, -30, 13, -4, 1, 0 }, + { 0, -1, 4, -10, 25, -53, 104, -191, 327, -537, + 852, -1326, 2070, -3384, 6430, -22415, 16009, 3487, -2291, 1483, + -961, 611, -377, 222, -124, 64, -30, 13, -5, 1, 0 }, + { 0, -1, 4, -10, 25, -53, 105, -192, 329, -541, + 857, -1334, 2084, -3405, 6462, -22410, 15935, 3562, -2329, 1506, + -975, 621, -383, 226, -126, 65, -31, 13, -5, 1, 0 }, + { 0, -1, 4, -10, 25, -54, 106, -193, 331, -544, + 863, -1343, 2097, -3425, 6493, -22405, 15860, 3636, -2367, 1529, + -990, 630, -389, 230, -128, 67, -32, 13, -5, 1, 0 }, + { 0, -1, 4, -10, 25, -54, 106, -194, 333, -547, + 869, -1352, 2111, -3446, 6524, -22399, 15785, 3711, -2405, 1552, + -1005, 640, -395, 233, -130, 68, -32, 14, -5, 1, 0 }, + { 0, -1, 4, -10, 25, -54, 107, -195, 335, -551, + 874, -1360, 2124, -3466, 6555, -22393, 15710, 3785, -2442, 1575, + -1019, 649, -401, 237, -132, 69, -33, 14, -5, 1, 0 }, + { 0, -1, 4, -10, 25, -54, 107, -196, 337, -554, + 879, -1369, 2137, -3487, 6586, -22387, 15634, 3860, -2480, 1598, + -1034, 658, -407, 241, -135, 70, -34, 14, -5, 1, 0 }, + { 0, -1, 4, -10, 25, -55, 108, -197, 339, -557, + 885, -1377, 2150, -3507, 6616, -22380, 15558, 3935, -2518, 1621, + -1048, 668, -413, 244, -137, 71, -34, 15, -5, 2, 0 }, + { 0, -1, 4, -10, 25, -55, 108, -198, 341, -561, + 890, -1386, 2163, -3527, 6646, -22372, 15482, 4010, -2556, 1643, + -1063, 677, -419, 248, -139, 73, -35, 15, -5, 2, 0 }, + { 0, -1, 4, -10, 26, -55, 109, -199, 343, -564, + 895, -1394, 2176, -3547, 6675, -22364, 15405, 4085, -2594, 1666, + -1077, 687, -425, 252, -141, 74, -35, 15, -6, 2, 0 }, + { 0, -1, 4, -10, 26, -55, 109, -200, 345, -567, + 901, -1403, 2189, -3566, 6704, -22356, 15328, 4160, -2632, 1689, + -1092, 696, -431, 255, -143, 75, -36, 15, -6, 2, 0 }, + { 0, -1, 4, -11, 26, -56, 110, -201, 347, -570, + 906, -1411, 2202, -3586, 6733, -22347, 15250, 4235, -2669, 1712, + -1106, 705, -436, 259, -145, 76, -37, 16, -6, 2, 0 }, + { 0, -1, 4, -11, 26, -56, 110, -202, 348, -573, + 911, -1419, 2214, -3605, 6762, -22338, 15172, 4311, -2707, 1734, + -1121, 715, -442, 262, -147, 77, -37, 16, -6, 2, 0 }, + { 0, -1, 4, -11, 26, -56, 111, -203, 350, -576, + 916, -1427, 2227, -3624, 6790, -22328, 15094, 4386, -2745, 1757, + -1135, 724, -448, 266, -150, 79, -38, 16, -6, 2, 0 }, + { 0, -1, 4, -11, 26, -56, 111, -204, 352, -579, + 921, -1435, 2239, -3643, 6818, -22318, 15016, 4462, -2783, 1780, + -1150, 733, -454, 270, -152, 80, -38, 17, -6, 2, 0 }, + { 0, -1, 4, -11, 26, -57, 112, -205, 354, -582, + 926, -1443, 2252, -3661, 6846, -22307, 14937, 4538, -2820, 1802, + -1164, 743, -460, 273, -154, 81, -39, 17, -6, 2, 0 }, + { 0, -1, 4, -11, 26, -57, 112, -206, 355, -586, + 931, -1451, 2264, -3680, 6873, -22296, 14858, 4613, -2858, 1825, + -1179, 752, -466, 277, -156, 82, -40, 17, -6, 2, 0 }, + { 0, -1, 4, -11, 26, -57, 113, -207, 357, -589, + 936, -1459, 2276, -3698, 6900, -22285, 14778, 4689, -2896, 1848, + -1193, 761, -472, 281, -158, 83, -40, 18, -7, 2, 0 }, + { 0, -1, 4, -11, 26, -57, 113, -208, 359, -591, + 941, -1466, 2288, -3717, 6927, -22273, 14698, 4765, -2933, 1870, + -1207, 770, -478, 284, -160, 85, -41, 18, -7, 2, 0 }, + { 0, -1, 4, -11, 26, -57, 114, -209, 361, -594, + 946, -1474, 2300, -3735, 6953, -22260, 14618, 4841, -2971, 1893, + -1222, 780, -484, 288, -162, 86, -42, 18, -7, 2, 0 }, + { 0, -1, 4, -11, 26, -58, 114, -209, 362, -597, + 951, -1482, 2311, -3752, 6979, -22247, 14538, 4917, -3008, 1915, + -1236, 789, -490, 292, -165, 87, -42, 18, -7, 2, 0 }, + { 0, -1, 4, -11, 27, -58, 114, -210, 364, -600, + 955, -1489, 2323, -3770, 7005, -22234, 14457, 4993, -3046, 1937, + -1250, 798, -495, 295, -167, 88, -43, 19, -7, 2, 0 }, + { 0, -1, 4, -11, 27, -58, 115, -211, 366, -603, + 960, -1497, 2334, -3788, 7030, -22220, 14376, 5070, -3083, 1960, + -1265, 807, -501, 299, -169, 89, -43, 19, -7, 2, 0 }, + { 0, -1, 4, -11, 27, -58, 115, -212, 367, -606, + 965, -1504, 2346, -3805, 7055, -22206, 14294, 5146, -3121, 1982, + -1279, 816, -507, 302, -171, 90, -44, 19, -7, 2, 0 }, + { 0, -1, 4, -11, 27, -58, 116, -213, 369, -609, + 969, -1511, 2357, -3822, 7080, -22191, 14212, 5222, -3158, 2005, + -1293, 826, -513, 306, -173, 92, -45, 20, -7, 2, 0 }, + { 0, -1, 4, -11, 27, -59, 116, -214, 370, -611, + 974, -1519, 2368, -3839, 7105, -22176, 14130, 5299, -3196, 2027, + -1307, 835, -519, 310, -175, 93, -45, 20, -8, 2, 0 }, + { 0, -1, 4, -11, 27, -59, 117, -215, 372, -614, + 978, -1526, 2379, -3856, 7129, -22160, 14048, 5376, -3233, 2049, + -1321, 844, -525, 313, -177, 94, -46, 20, -8, 2, -1 }, + { 0, -1, 4, -11, 27, -59, 117, -216, 374, -617, + 983, -1533, 2390, -3872, 7153, -22144, 13965, 5452, -3270, 2071, + -1335, 853, -530, 317, -179, 95, -47, 20, -8, 2, -1 }, + { 0, -1, 4, -11, 27, -59, 117, -216, 375, -620, + 987, -1540, 2401, -3889, 7176, -22128, 13882, 5529, -3308, 2094, + -1350, 862, -536, 320, -182, 96, -47, 21, -8, 2, -1 }, + { 0, -1, 4, -11, 27, -59, 118, -217, 377, -622, + 992, -1547, 2412, -3905, 7199, -22111, 13798, 5606, -3345, 2116, + -1364, 871, -542, 324, -184, 98, -48, 21, -8, 3, -1 }, + { 0, -1, 4, -11, 27, -59, 118, -218, 378, -625, + 996, -1554, 2423, -3921, 7222, -22094, 13714, 5682, -3382, 2138, + -1378, 880, -548, 327, -186, 99, -48, 21, -8, 3, -1 }, + { 0, -1, 4, -11, 27, -60, 119, -219, 380, -627, + 1000, -1561, 2433, -3937, 7245, -22076, 13630, 5759, -3419, 2160, + -1392, 889, -553, 331, -188, 100, -49, 22, -8, 3, -1 }, + { 0, -1, 4, -11, 27, -60, 119, -220, 381, -630, + 1004, -1567, 2444, -3953, 7267, -22058, 13546, 5836, -3456, 2182, + -1406, 898, -559, 335, -190, 101, -50, 22, -8, 3, -1 }, + { 0, -1, 4, -11, 27, -60, 119, -220, 382, -632, + 1009, -1574, 2454, -3968, 7289, -22039, 13461, 5913, -3493, 2204, + -1420, 907, -565, 338, -192, 102, -50, 22, -9, 3, -1 }, + { 0, -1, 4, -11, 27, -60, 120, -221, 384, -635, + 1013, -1581, 2464, -3984, 7310, -22020, 13376, 5990, -3530, 2226, + -1434, 916, -571, 342, -194, 104, -51, 23, -9, 3, -1 }, + { 0, -1, 4, -11, 27, -60, 120, -222, 385, -637, + 1017, -1587, 2474, -3999, 7332, -22001, 13291, 6067, -3567, 2248, + -1448, 925, -576, 345, -196, 105, -52, 23, -9, 3, -1 }, + { 0, -1, 4, -11, 28, -60, 120, -223, 387, -640, + 1021, -1594, 2484, -4014, 7353, -21981, 13205, 6145, -3604, 2270, + -1462, 934, -582, 349, -198, 106, -52, 23, -9, 3, -1 }, + { 0, -1, 4, -11, 28, -61, 121, -223, 388, -642, + 1025, -1600, 2494, -4029, 7373, -21960, 13119, 6222, -3641, 2292, + -1475, 943, -588, 352, -201, 107, -53, 23, -9, 3, -1 }, + { 0, -1, 4, -11, 28, -61, 121, -224, 389, -645, + 1029, -1606, 2504, -4043, 7394, -21939, 13033, 6299, -3678, 2313, + -1489, 952, -593, 356, -203, 108, -53, 24, -9, 3, -1 }, + { 0, -1, 4, -11, 28, -61, 121, -225, 391, -647, + 1033, -1613, 2513, -4058, 7414, -21918, 12946, 6376, -3714, 2335, + -1503, 961, -599, 359, -205, 109, -54, 24, -9, 3, -1 }, + { 0, -1, 4, -11, 28, -61, 122, -225, 392, -649, + 1037, -1619, 2523, -4072, 7433, -21896, 12860, 6454, -3751, 2357, + -1517, 970, -605, 363, -207, 111, -55, 24, -10, 3, -1 }, + { 0, -1, 4, -11, 28, -61, 122, -226, 393, -652, + 1041, -1625, 2532, -4086, 7453, -21874, 12773, 6531, -3788, 2378, + -1530, 979, -610, 366, -209, 112, -55, 25, -10, 3, -1 }, + { 0, -1, 4, -11, 28, -61, 122, -227, 395, -654, + 1044, -1631, 2542, -4100, 7472, -21852, 12685, 6609, -3824, 2400, + -1544, 988, -616, 370, -211, 113, -56, 25, -10, 3, -1 }, + { 0, -1, 4, -11, 28, -61, 123, -227, 396, -656, + 1048, -1637, 2551, -4114, 7490, -21829, 12597, 6686, -3861, 2421, + -1558, 996, -622, 373, -213, 114, -56, 25, -10, 3, -1 }, + { 0, -1, 4, -11, 28, -62, 123, -228, 397, -658, + 1052, -1643, 2560, -4127, 7509, -21805, 12509, 6764, -3897, 2443, + -1571, 1005, -627, 377, -215, 115, -57, 26, -10, 3, -1 }, + { 0, -1, 4, -11, 28, -62, 123, -229, 398, -660, + 1055, -1648, 2569, -4141, 7527, -21782, 12421, 6841, -3933, 2464, + -1585, 1014, -633, 380, -217, 116, -58, 26, -10, 3, -1 }, + { 0, -1, 4, -11, 28, -62, 124, -229, 400, -663, + 1059, -1654, 2578, -4154, 7545, -21757, 12332, 6919, -3970, 2486, + -1598, 1023, -638, 384, -219, 118, -58, 26, -10, 3, -1 }, + { 0, -1, 4, -11, 28, -62, 124, -230, 401, -665, + 1062, -1660, 2586, -4167, 7562, -21733, 12244, 6996, -4006, 2507, + -1612, 1031, -644, 387, -221, 119, -59, 26, -10, 3, -1 }, + { 0, -1, 4, -11, 28, -62, 124, -231, 402, -667, + 1066, -1665, 2595, -4180, 7579, -21708, 12154, 7074, -4042, 2528, + -1625, 1040, -650, 391, -223, 120, -60, 27, -11, 3, -1 }, + { 0, -1, 4, -11, 28, -62, 125, -231, 403, -669, + 1069, -1671, 2604, -4193, 7596, -21682, 12065, 7152, -4078, 2549, + -1639, 1049, -655, 394, -225, 121, -60, 27, -11, 3, -1 }, + { 0, -1, 4, -11, 28, -62, 125, -232, 404, -671, + 1073, -1676, 2612, -4205, 7613, -21656, 11975, 7229, -4114, 2570, + -1652, 1057, -661, 397, -227, 122, -61, 27, -11, 4, -1 }, + { 0, -1, 4, -11, 28, -62, 125, -232, 405, -673, + 1076, -1682, 2620, -4217, 7629, -21630, 11885, 7307, -4150, 2591, + -1666, 1066, -666, 401, -229, 123, -61, 28, -11, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 125, -233, 406, -675, + 1079, -1687, 2628, -4229, 7645, -21603, 11795, 7385, -4186, 2612, + -1679, 1074, -672, 404, -231, 125, -62, 28, -11, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 126, -233, 407, -677, + 1083, -1692, 2636, -4241, 7660, -21576, 11705, 7463, -4222, 2633, + -1692, 1083, -677, 408, -234, 126, -63, 28, -11, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 126, -234, 409, -679, + 1086, -1697, 2644, -4253, 7675, -21548, 11614, 7540, -4257, 2654, + -1705, 1092, -682, 411, -236, 127, -63, 29, -11, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 126, -235, 410, -680, + 1089, -1702, 2652, -4265, 7690, -21520, 11523, 7618, -4293, 2675, + -1718, 1100, -688, 414, -238, 128, -64, 29, -11, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 126, -235, 411, -682, + 1092, -1707, 2660, -4276, 7705, -21492, 11431, 7696, -4328, 2696, + -1732, 1108, -693, 418, -240, 129, -64, 29, -12, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 127, -236, 412, -684, + 1095, -1712, 2667, -4287, 7719, -21463, 11340, 7774, -4364, 2716, + -1745, 1117, -699, 421, -242, 130, -65, 29, -12, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 127, -236, 413, -686, + 1098, -1717, 2675, -4298, 7733, -21434, 11248, 7852, -4399, 2737, + -1758, 1125, -704, 425, -244, 131, -66, 30, -12, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 127, -237, 414, -688, + 1101, -1722, 2682, -4309, 7747, -21404, 11156, 7929, -4434, 2758, + -1771, 1134, -709, 428, -246, 133, -66, 30, -12, 4, -1 }, + { 0, -1, 4, -11, 28, -63, 127, -237, 414, -689, + 1104, -1727, 2690, -4320, 7760, -21374, 11063, 8007, -4470, 2778, + -1784, 1142, -715, 431, -248, 134, -67, 30, -12, 4, -1 }, + { 0, -1, 4, -11, 29, -63, 128, -238, 415, -691, + 1107, -1731, 2697, -4330, 7773, -21344, 10971, 8085, -4505, 2799, + -1797, 1150, -720, 435, -250, 135, -67, 31, -12, 4, -1 }, + { 0, -1, 4, -11, 29, -63, 128, -238, 416, -693, + 1110, -1736, 2704, -4340, 7786, -21313, 10878, 8163, -4540, 2819, + -1809, 1159, -725, 438, -252, 136, -68, 31, -12, 4, -1 }, + { 0, -1, 4, -11, 29, -64, 128, -238, 417, -694, + 1113, -1740, 2711, -4351, 7798, -21282, 10785, 8241, -4575, 2839, + -1822, 1167, -731, 441, -254, 137, -69, 31, -12, 4, -1 }, + { 0, -1, 4, -11, 29, -64, 128, -239, 418, -696, + 1115, -1745, 2717, -4360, 7811, -21250, 10691, 8318, -4609, 2859, + -1835, 1175, -736, 444, -256, 138, -69, 31, -13, 4, -1 }, + { 0, -1, 4, -11, 29, -64, 128, -239, 419, -698, + 1118, -1749, 2724, -4370, 7822, -21218, 10598, 8396, -4644, 2879, + -1848, 1183, -741, 448, -257, 139, -70, 32, -13, 4, -1 }, + { 0, -1, 4, -11, 29, -64, 129, -240, 420, -699, + 1121, -1753, 2731, -4380, 7834, -21185, 10504, 8474, -4679, 2900, + -1860, 1192, -747, 451, -259, 140, -70, 32, -13, 4, -1 }, + { 0, -1, 4, -11, 29, -64, 129, -240, 421, -701, + 1123, -1757, 2737, -4389, 7845, -21152, 10410, 8552, -4713, 2920, + -1873, 1200, -752, 454, -261, 141, -71, 32, -13, 4, -1 }, + { 0, -1, 4, -11, 29, -64, 129, -241, 421, -702, + 1126, -1762, 2743, -4398, 7856, -21119, 10315, 8630, -4748, 2939, + -1886, 1208, -757, 457, -263, 143, -72, 33, -13, 4, -1 }, + { 0, -1, 4, -11, 29, -64, 129, -241, 422, -703, + 1128, -1766, 2750, -4407, 7866, -21086, 10221, 8707, -4782, 2959, + -1898, 1216, -762, 461, -265, 144, -72, 33, -13, 4, -1 }, + { 0, -1, 4, -11, 29, -64, 129, -241, 423, -705, + 1131, -1770, 2756, -4416, 7877, -21051, 10126, 8785, -4816, 2979, + -1911, 1224, -767, 464, -267, 145, -73, 33, -13, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 129, -242, 424, -706, + 1133, -1773, 2762, -4425, 7886, -21017, 10031, 8863, -4850, 2999, + -1923, 1232, -772, 467, -269, 146, -73, 33, -14, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 130, -242, 424, -708, + 1135, -1777, 2767, -4433, 7896, -20982, 9935, 8940, -4884, 3018, + -1935, 1240, -778, 470, -271, 147, -74, 34, -14, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 130, -242, 425, -709, + 1138, -1781, 2773, -4441, 7905, -20947, 9840, 9018, -4918, 3038, + -1948, 1248, -783, 474, -273, 148, -75, 34, -14, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 130, -243, 426, -710, + 1140, -1785, 2779, -4450, 7914, -20911, 9744, 9096, -4952, 3057, + -1960, 1256, -788, 477, -275, 149, -75, 34, -14, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 130, -243, 427, -712, + 1142, -1788, 2784, -4457, 7923, -20875, 9648, 9173, -4986, 3077, + -1972, 1264, -793, 480, -277, 150, -76, 35, -14, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 130, -243, 427, -713, + 1144, -1792, 2790, -4465, 7931, -20839, 9552, 9251, -5019, 3096, + -1984, 1272, -798, 483, -279, 151, -76, 35, -14, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 130, -244, 428, -714, + 1146, -1795, 2795, -4473, 7939, -20802, 9455, 9328, -5053, 3115, + -1996, 1279, -803, 486, -281, 152, -77, 35, -14, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 130, -244, 428, -715, + 1148, -1798, 2800, -4480, 7947, -20765, 9359, 9406, -5086, 3134, + -2008, 1287, -808, 489, -282, 154, -77, 36, -14, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 130, -244, 429, -716, + 1150, -1802, 2805, -4487, 7955, -20727, 9262, 9483, -5119, 3153, + -2020, 1295, -813, 492, -284, 155, -78, 36, -15, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 131, -245, 430, -717, + 1152, -1805, 2810, -4494, 7962, -20689, 9165, 9561, -5152, 3172, + -2032, 1303, -818, 495, -286, 156, -79, 36, -15, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 131, -245, 430, -718, + 1154, -1808, 2815, -4501, 7969, -20651, 9068, 9638, -5185, 3191, + -2044, 1310, -823, 499, -288, 157, -79, 36, -15, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 131, -245, 431, -720, + 1156, -1811, 2820, -4508, 7975, -20612, 8970, 9716, -5218, 3210, + -2056, 1318, -828, 502, -290, 158, -80, 37, -15, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 131, -245, 431, -721, + 1158, -1814, 2824, -4514, 7981, -20573, 8872, 9793, -5251, 3229, + -2068, 1325, -832, 505, -292, 159, -80, 37, -15, 5, -1 }, + { 0, -1, 4, -11, 29, -64, 131, -246, 432, -722, + 1160, -1817, 2829, -4520, 7987, -20534, 8774, 9870, -5284, 3247, + -2079, 1333, -837, 508, -294, 160, -81, 37, -15, 5, -1 }, + { 0, -1, 4, -11, 29, -65, 131, -246, 432, -723, + 1161, -1820, 2833, -4526, 7993, -20494, 8676, 9947, -5316, 3266, + -2091, 1340, -842, 511, -295, 161, -81, 37, -15, 5, -1 }, + { 0, -1, 4, -11, 29, -65, 131, -246, 433, -723, + 1163, -1822, 2837, -4532, 7998, -20454, 8578, 10025, -5349, 3284, + -2102, 1348, -847, 514, -297, 162, -82, 38, -15, 5, -1 }, + { 0, -1, 4, -11, 29, -65, 131, -246, 433, -724, + 1165, -1825, 2841, -4538, 8003, -20413, 8479, 10102, -5381, 3302, + -2114, 1355, -852, 517, -299, 163, -83, 38, -16, 5, -1 }, + { 0, -1, 4, -11, 29, -65, 131, -246, 434, -725, + 1166, -1828, 2845, -4544, 8008, -20372, 8381, 10179, -5413, 3321, + -2125, 1363, -856, 520, -301, 164, -83, 38, -16, 5, -1 }, + { 0, -1, 4, -11, 29, -65, 131, -247, 434, -726, + 1168, -1830, 2849, -4549, 8012, -20331, 8282, 10256, -5445, 3339, + -2137, 1370, -861, 523, -303, 165, -84, 39, -16, 5, -1 }, + { 0, -1, 4, -11, 29, -65, 131, -247, 434, -727, + 1169, -1833, 2853, -4554, 8016, -20289, 8183, 10333, -5477, 3357, + -2148, 1377, -866, 526, -304, 166, -84, 39, -16, 6, -1 }, + { 0, -1, 4, -11, 29, -65, 131, -247, 435, -728, + 1171, -1835, 2857, -4559, 8020, -20247, 8083, 10409, -5509, 3375, + -2159, 1385, -871, 529, -306, 167, -85, 39, -16, 6, -1 }, + { 0, -1, 4, -11, 29, -65, 131, -247, 435, -728, + 1172, -1837, 2860, -4564, 8024, -20204, 7984, 10486, -5540, 3393, + -2171, 1392, -875, 532, -308, 168, -85, 39, -16, 6, -2 }, + { 0, -1, 4, -11, 29, -65, 131, -247, 436, -729, + 1173, -1840, 2864, -4568, 8027, -20162, 7884, 10563, -5572, 3410, + -2182, 1399, -880, 535, -310, 169, -86, 40, -16, 6, -2 }, + { 0, -1, 4, -11, 29, -65, 131, -247, 436, -730, + 1175, -1842, 2867, -4573, 8030, -20119, 7784, 10640, -5603, 3428, + -2193, 1406, -884, 537, -312, 170, -86, 40, -16, 6, -2 }, + { 0, -1, 4, -11, 29, -65, 132, -247, 436, -730, + 1176, -1844, 2870, -4577, 8032, -20075, 7684, 10716, -5634, 3446, + -2204, 1413, -889, 540, -313, 171, -87, 40, -17, 6, -2 }, + { 0, -1, 4, -11, 29, -65, 132, -248, 437, -731, + 1177, -1846, 2873, -4581, 8035, -20031, 7584, 10793, -5665, 3463, + -2215, 1420, -894, 543, -315, 172, -88, 41, -17, 6, -2 }, + { 0, -1, 4, -11, 29, -64, 132, -248, 437, -732, + 1178, -1848, 2876, -4585, 8037, -19987, 7484, 10869, -5696, 3481, + -2226, 1427, -898, 546, -317, 173, -88, 41, -17, 6, -2 }, + { 0, -1, 4, -11, 29, -64, 132, -248, 437, -732, + 1179, -1850, 2879, -4589, 8038, -19942, 7383, 10946, -5727, 3498, + -2236, 1434, -903, 549, -319, 174, -89, 41, -17, 6, -2 }, + { 0, -1, 4, -11, 29, -64, 132, -248, 437, -733, + 1180, -1851, 2882, -4592, 8040, -19897, 7282, 11022, -5758, 3515, + -2247, 1441, -907, 552, -320, 175, -89, 41, -17, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 132, -248, 438, -733, + 1181, -1853, 2884, -4596, 8041, -19852, 7181, 11098, -5788, 3532, + -2258, 1448, -912, 555, -322, 176, -90, 42, -17, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 132, -248, 438, -734, + 1182, -1855, 2887, -4599, 8042, -19806, 7080, 11174, -5818, 3549, + -2268, 1455, -916, 557, -324, 177, -90, 42, -17, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 132, -248, 438, -734, + 1183, -1856, 2889, -4602, 8042, -19760, 6979, 11250, -5849, 3566, + -2279, 1462, -920, 560, -325, 178, -91, 42, -17, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 132, -248, 438, -735, + 1184, -1858, 2892, -4605, 8042, -19714, 6878, 11326, -5879, 3583, + -2289, 1469, -925, 563, -327, 179, -91, 42, -18, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 132, -248, 438, -735, + 1185, -1859, 2894, -4607, 8042, -19667, 6776, 11402, -5908, 3599, + -2300, 1475, -929, 566, -329, 180, -92, 43, -18, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 438, -736, + 1185, -1861, 2896, -4610, 8042, -19620, 6674, 11478, -5938, 3616, + -2310, 1482, -933, 568, -330, 181, -92, 43, -18, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -736, + 1186, -1862, 2898, -4612, 8041, -19573, 6573, 11553, -5968, 3632, + -2320, 1489, -938, 571, -332, 182, -93, 43, -18, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -736, + 1187, -1863, 2900, -4614, 8040, -19525, 6471, 11629, -5997, 3649, + -2330, 1495, -942, 574, -334, 183, -93, 43, -18, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -736, + 1187, -1864, 2901, -4616, 8039, -19477, 6368, 11704, -6027, 3665, + -2341, 1502, -946, 576, -335, 184, -94, 44, -18, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -737, + 1188, -1865, 2903, -4618, 8038, -19429, 6266, 11780, -6056, 3681, + -2351, 1508, -950, 579, -337, 185, -94, 44, -18, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -737, + 1189, -1866, 2904, -4620, 8036, -19380, 6164, 11855, -6085, 3697, + -2361, 1515, -954, 582, -339, 186, -95, 44, -18, 6, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -737, + 1189, -1867, 2906, -4621, 8034, -19331, 6061, 11930, -6113, 3713, + -2370, 1521, -959, 584, -340, 187, -95, 45, -18, 7, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -737, + 1189, -1868, 2907, -4622, 8031, -19282, 5958, 12005, -6142, 3729, + -2380, 1527, -963, 587, -342, 188, -96, 45, -19, 7, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -737, + 1190, -1869, 2908, -4623, 8029, -19232, 5855, 12080, -6171, 3744, + -2390, 1534, -967, 589, -343, 189, -96, 45, -19, 7, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -737, + 1190, -1869, 2909, -4624, 8026, -19182, 5752, 12155, -6199, 3760, + -2400, 1540, -971, 592, -345, 190, -97, 45, -19, 7, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -738, + 1190, -1870, 2910, -4625, 8023, -19131, 5649, 12230, -6227, 3775, + -2409, 1546, -975, 595, -346, 190, -97, 46, -19, 7, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -738, + 1191, -1870, 2911, -4625, 8019, -19081, 5546, 12304, -6255, 3791, + -2419, 1552, -979, 597, -348, 191, -98, 46, -19, 7, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -248, 439, -738, + 1191, -1871, 2911, -4626, 8015, -19030, 5442, 12379, -6283, 3806, + -2428, 1558, -983, 600, -350, 192, -98, 46, -19, 7, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -247, 439, -738, + 1191, -1871, 2912, -4626, 8011, -18978, 5339, 12453, -6310, 3821, + -2438, 1565, -987, 602, -351, 193, -99, 46, -19, 7, -2 }, + { 0, -1, 3, -11, 28, -64, 131, -247, 439, -738, + 1191, -1871, 2913, -4626, 8007, -18927, 5235, 12528, -6338, 3836, + -2447, 1571, -991, 605, -353, 194, -99, 47, -19, 7, -2 }, + { 0, -1, 3, -11, 28, -63, 130, -247, 438, -738, + 1191, -1872, 2913, -4626, 8002, -18875, 5131, 12602, -6365, 3851, + -2456, 1576, -994, 607, -354, 195, -100, 47, -20, 7, -2 }, + { 0, -1, 3, -11, 28, -63, 130, -247, 438, -737, + 1191, -1872, 2913, -4625, 7997, -18822, 5027, 12676, -6392, 3866, + -2465, 1582, -998, 610, -356, 196, -100, 47, -20, 7, -2 }, + { 0, -1, 3, -11, 28, -63, 130, -247, 438, -737, + 1191, -1872, 2913, -4625, 7992, -18770, 4923, 12749, -6419, 3880, + -2474, 1588, -1002, 612, -357, 197, -101, 47, -20, 7, -2 }, + { 0, -1, 3, -11, 28, -63, 130, -247, 438, -737, + 1191, -1872, 2913, -4624, 7987, -18717, 4819, 12823, -6446, 3895, + -2483, 1594, -1006, 614, -359, 198, -101, 48, -20, 7, -2 }, + { 0, -1, 3, -10, 28, -63, 130, -247, 438, -737, + 1191, -1872, 2913, -4623, 7981, -18663, 4715, 12897, -6473, 3909, + -2492, 1600, -1010, 617, -360, 198, -102, 48, -20, 7, -2 }, + { 0, -1, 3, -10, 28, -63, 130, -246, 438, -737, + 1191, -1872, 2913, -4622, 7975, -18610, 4611, 12970, -6499, 3923, + -2501, 1605, -1013, 619, -362, 199, -102, 48, -20, 7, -2 }, + { 0, -1, 3, -10, 28, -63, 130, -246, 437, -737, + 1190, -1872, 2913, -4621, 7968, -18556, 4506, 13044, -6525, 3938, + -2510, 1611, -1017, 621, -363, 200, -103, 48, -20, 7, -2 }, + { 0, -1, 3, -10, 27, -63, 130, -246, 437, -736, + 1190, -1871, 2912, -4620, 7962, -18502, 4402, 13117, -6551, 3952, + -2518, 1617, -1021, 624, -364, 201, -103, 49, -20, 7, -2 }, + { 0, -1, 3, -10, 27, -63, 129, -246, 437, -736, + 1190, -1871, 2912, -4618, 7955, -18447, 4297, 13190, -6577, 3965, + -2527, 1622, -1024, 626, -366, 202, -104, 49, -20, 7, -2 }, + { 0, -1, 3, -10, 27, -63, 129, -246, 437, -736, + 1190, -1871, 2911, -4616, 7948, -18392, 4192, 13263, -6603, 3979, + -2535, 1628, -1028, 628, -367, 203, -104, 49, -21, 7, -2 }, + { 0, -1, 3, -10, 27, -63, 129, -245, 436, -735, + 1189, -1870, 2910, -4614, 7940, -18337, 4087, 13336, -6629, 3993, + -2544, 1633, -1031, 631, -369, 204, -105, 49, -21, 7, -2 }, + { 0, -1, 3, -10, 27, -62, 129, -245, 436, -735, + 1189, -1869, 2909, -4612, 7933, -18282, 3982, 13408, -6654, 4006, + -2552, 1639, -1035, 633, -370, 204, -105, 49, -21, 7, -2 }, + { 0, -1, 3, -10, 27, -62, 129, -245, 436, -734, + 1188, -1869, 2908, -4610, 7925, -18226, 3877, 13481, -6679, 4020, + -2560, 1644, -1038, 635, -371, 205, -106, 50, -21, 8, -2 }, + { 0, -1, 3, -10, 27, -62, 129, -245, 435, -734, + 1188, -1868, 2907, -4608, 7916, -18170, 3772, 13553, -6704, 4033, + -2568, 1649, -1042, 637, -373, 206, -106, 50, -21, 8, -2 }, + { 0, -1, 3, -10, 27, -62, 129, -244, 435, -734, + 1187, -1867, 2906, -4605, 7908, -18114, 3667, 13625, -6729, 4046, + -2576, 1654, -1045, 639, -374, 207, -106, 50, -21, 8, -2 }, + { 0, -1, 3, -10, 27, -62, 128, -244, 435, -733, + 1186, -1867, 2905, -4602, 7899, -18057, 3561, 13697, -6753, 4059, + -2584, 1659, -1048, 642, -375, 208, -107, 50, -21, 8, -2 }, + { 0, -1, 3, -10, 27, -62, 128, -244, 434, -733, + 1186, -1866, 2903, -4599, 7890, -18000, 3456, 13769, -6778, 4072, + -2592, 1665, -1052, 644, -377, 208, -107, 51, -21, 8, -2 }, + { 0, -1, 3, -10, 27, -62, 128, -244, 434, -732, + 1185, -1865, 2902, -4596, 7881, -17943, 3350, 13841, -6802, 4085, + -2600, 1670, -1055, 646, -378, 209, -108, 51, -21, 8, -2 }, + { 0, -1, 3, -10, 27, -62, 128, -243, 433, -731, + 1184, -1864, 2900, -4593, 7871, -17886, 3245, 13912, -6826, 4097, + -2608, 1675, -1058, 648, -379, 210, -108, 51, -22, 8, -2 }, + { 0, -1, 3, -10, 27, -62, 128, -243, 433, -731, + 1183, -1862, 2898, -4590, 7861, -17828, 3139, 13983, -6850, 4110, + -2616, 1680, -1062, 650, -381, 211, -109, 51, -22, 8, -2 }, + { 0, -1, 3, -10, 27, -62, 127, -243, 432, -730, + 1183, -1861, 2897, -4586, 7851, -17770, 3033, 14055, -6873, 4122, + -2623, 1684, -1065, 652, -382, 211, -109, 52, -22, 8, -2 }, + { 0, -1, 3, -10, 27, -61, 127, -242, 432, -730, + 1182, -1860, 2895, -4582, 7841, -17712, 2928, 14126, -6897, 4134, + -2631, 1689, -1068, 654, -383, 212, -110, 52, -22, 8, -2 }, + { 0, -1, 3, -10, 27, -61, 127, -242, 432, -729, + 1181, -1859, 2893, -4578, 7830, -17653, 2822, 14196, -6920, 4147, + -2638, 1694, -1071, 656, -385, 213, -110, 52, -22, 8, -2 }, + { 0, -1, 3, -10, 26, -61, 127, -242, 431, -728, + 1180, -1857, 2890, -4574, 7820, -17594, 2716, 14267, -6943, 4159, + -2645, 1699, -1074, 658, -386, 214, -110, 52, -22, 8, -2 }, + { 0, -1, 3, -10, 26, -61, 127, -241, 431, -727, + 1179, -1856, 2888, -4570, 7808, -17535, 2610, 14338, -6966, 4170, + -2652, 1703, -1077, 660, -387, 214, -111, 52, -22, 8, -2 }, + { 0, -1, 3, -10, 26, -61, 126, -241, 430, -727, + 1178, -1854, 2886, -4566, 7797, -17476, 2504, 14408, -6988, 4182, + -2660, 1708, -1080, 662, -388, 215, -111, 53, -22, 8, -2 }, + { 0, -1, 3, -10, 26, -61, 126, -241, 429, -726, + 1177, -1853, 2883, -4561, 7785, -17416, 2398, 14478, -7010, 4194, + -2667, 1713, -1083, 664, -389, 216, -112, 53, -22, 8, -2 }, + { 0, -1, 3, -10, 26, -61, 126, -240, 429, -725, + 1175, -1851, 2881, -4556, 7773, -17356, 2292, 14548, -7033, 4205, + -2673, 1717, -1086, 666, -391, 217, -112, 53, -22, 8, -2 }, + { 0, -1, 3, -10, 26, -60, 126, -240, 428, -724, + 1174, -1849, 2878, -4551, 7761, -17296, 2185, 14618, -7055, 4216, + -2680, 1721, -1089, 668, -392, 217, -112, 53, -23, 8, -2 }, + { 0, -1, 3, -10, 26, -60, 125, -240, 428, -723, + 1173, -1847, 2875, -4546, 7749, -17235, 2079, 14687, -7076, 4227, + -2687, 1726, -1092, 670, -393, 218, -113, 53, -23, 8, -2 }, + { 0, -1, 3, -10, 26, -60, 125, -239, 427, -722, + 1172, -1846, 2872, -4541, 7736, -17174, 1973, 14757, -7098, 4238, + -2694, 1730, -1095, 671, -394, 219, -113, 54, -23, 8, -2 }, + { 0, -1, 3, -10, 26, -60, 125, -239, 426, -722, + 1170, -1844, 2869, -4536, 7723, -17113, 1866, 14826, -7119, 4249, + -2700, 1734, -1098, 673, -395, 219, -114, 54, -23, 8, -2 }, + { 0, -1, 3, -10, 26, -60, 125, -238, 426, -721, + 1169, -1842, 2866, -4530, 7710, -17052, 1760, 14895, -7140, 4260, + -2707, 1739, -1100, 675, -396, 220, -114, 54, -23, 8, -2 }, + { 0, -1, 3, -10, 26, -60, 124, -238, 425, -720, + 1167, -1840, 2863, -4524, 7697, -16990, 1653, 14964, -7161, 4270, + -2713, 1743, -1103, 677, -397, 221, -114, 54, -23, 8, -2 }, + { 0, -1, 3, -10, 26, -60, 124, -237, 424, -719, + 1166, -1837, 2860, -4518, 7683, -16929, 1547, 15033, -7182, 4281, + -2719, 1747, -1106, 679, -399, 221, -115, 55, -23, 8, -2 }, + { 0, -1, 3, -10, 26, -59, 124, -237, 424, -718, + 1165, -1835, 2856, -4512, 7669, -16867, 1440, 15101, -7202, 4291, + -2726, 1751, -1108, 680, -400, 222, -115, 55, -23, 9, -2 }, + { 0, -1, 3, -10, 26, -59, 124, -237, 423, -717, + 1163, -1833, 2853, -4506, 7655, -16804, 1334, 15169, -7223, 4301, + -2732, 1755, -1111, 682, -401, 223, -115, 55, -23, 9, -3 }, + { 0, -1, 3, -9, 25, -59, 123, -236, 422, -715, + 1161, -1831, 2849, -4500, 7640, -16742, 1227, 15237, -7243, 4311, + -2738, 1759, -1113, 684, -402, 223, -116, 55, -23, 9, -3 }, + { 0, -1, 3, -9, 25, -59, 123, -236, 422, -714, + 1160, -1828, 2845, -4493, 7626, -16679, 1121, 15305, -7262, 4321, + -2744, 1762, -1116, 685, -403, 224, -116, 55, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -59, 123, -235, 421, -713, + 1158, -1826, 2841, -4487, 7611, -16616, 1014, 15373, -7282, 4331, + -2749, 1766, -1118, 687, -404, 225, -117, 56, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -59, 122, -235, 420, -712, + 1156, -1823, 2837, -4480, 7596, -16552, 907, 15440, -7301, 4340, + -2755, 1770, -1121, 688, -405, 225, -117, 56, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -59, 122, -234, 419, -711, + 1155, -1820, 2833, -4473, 7580, -16489, 801, 15507, -7321, 4350, + -2761, 1773, -1123, 690, -406, 226, -117, 56, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -58, 122, -234, 419, -710, + 1153, -1818, 2829, -4466, 7564, -16425, 694, 15574, -7339, 4359, + -2766, 1777, -1126, 692, -407, 226, -118, 56, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -58, 122, -233, 418, -708, + 1151, -1815, 2825, -4458, 7549, -16361, 587, 15641, -7358, 4368, + -2772, 1781, -1128, 693, -408, 227, -118, 56, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -58, 121, -233, 417, -707, + 1149, -1812, 2821, -4451, 7532, -16297, 480, 15708, -7377, 4377, + -2777, 1784, -1130, 695, -409, 228, -118, 56, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -58, 121, -232, 416, -706, + 1147, -1809, 2816, -4443, 7516, -16232, 374, 15774, -7395, 4386, + -2782, 1787, -1133, 696, -410, 228, -119, 57, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -58, 121, -232, 415, -705, + 1145, -1806, 2812, -4436, 7499, -16167, 267, 15840, -7413, 4395, + -2787, 1791, -1135, 698, -411, 229, -119, 57, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -58, 120, -231, 414, -703, + 1143, -1803, 2807, -4428, 7483, -16102, 160, 15906, -7431, 4403, + -2792, 1794, -1137, 699, -412, 229, -119, 57, -24, 9, -3 }, + { 0, -1, 3, -9, 25, -57, 120, -231, 413, -702, + 1141, -1800, 2802, -4420, 7466, -16037, 53, 15972, -7448, 4411, + -2797, 1797, -1139, 700, -413, 230, -120, 57, -24, 9, -3 }, + + } +}; +// clang-format off + +} // namespace le_audio::asrc diff --git a/system/bta/le_audio/audio_hal_client/asrc_tables.h b/system/bta/le_audio/audio_hal_client/asrc_tables.h new file mode 100644 index 0000000000000000000000000000000000000000..ab13da249ed76a678b9e30beeddb8b8381c38c9d --- /dev/null +++ b/system/bta/le_audio/audio_hal_client/asrc_tables.h @@ -0,0 +1,34 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace le_audio::asrc { + +extern const struct ResamplerTables { + static const int KERNEL_Q = 512; + static const int KERNEL_A = 16; + + const int32_t h alignas(2 * KERNEL_A * + sizeof(int32_t))[KERNEL_Q][2 * KERNEL_A]; + const int16_t d alignas(2 * KERNEL_A * + sizeof(int16_t))[KERNEL_Q][2 * KERNEL_A]; + +} resampler_tables; + +} // namespace le_audio::asrc diff --git a/system/bta/le_audio/audio_hal_client/asrc_tables.py b/system/bta/le_audio/audio_hal_client/asrc_tables.py new file mode 100755 index 0000000000000000000000000000000000000000..e3dd208c2190895512f037019318464c469e8cd3 --- /dev/null +++ b/system/bta/le_audio/audio_hal_client/asrc_tables.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +# +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import numpy as np +from scipy import signal +import sys + +KERNEL_Q = 512 +KERNEL_A = 16 + +KAISER_BETA = 12.5 + +# +# Transfer function +# + +a = KERNEL_A +q = KERNEL_Q +beta = KAISER_BETA + +w = signal.kaiser(2 * a * q + 1, beta) +k = np.sinc(np.linspace(-a, a, 2 * a * q + 1)) * w + +h = k[:-1].reshape((2 * a, q)).T +h = np.append(h, [np.roll(h[0], -1)], axis=0) +h = np.flip(h, axis=0) + +d = h[1:] - h[:-1] + +# +# File header +# + +print("""\ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file is auto-generated using "{}". DO NOT EDIT. */ + +#include "asrc_tables.h" + +namespace le_audio::asrc {{ +""".format(sys.argv[0])) + +# +# 32 bits tables +# + +h32 = np.clip(np.rint(h * 2**31), -(1 << 31), (1 << 31) - 1).astype(np.int32) +d32 = np.clip(np.rint(d * 2**23), -(1 << 23), (1 << 23) - 1).astype(np.int16) + +print("""\ +// clang-format off +const ResamplerTables resampler_tables = { + + .h = { +""") +for q in range(len(h) - 1): + layout = " {{" + " {:10d}," * 8 + "\n" + \ + " " + " {:10d}," * 8 + "\n" + \ + " " + " {:10d}," * 8 + "\n" + \ + " " + " {:10d}," * 6 + " {:10d} }}," + print(layout.format(*h32[q])) +print(""" + }, +""") + +print("""\ + .d = { +""") +for q in range(len(h) - 1): + layout = " {{" + " {:6d}," * 10 + "\n" + \ + " " + " {:6d}," * 10 + "\n" + \ + " " + " {:6d}," * 10 + " {:2d} }}," + print(layout.format(*d32[q])) +print(""" + } +}; +// clang-format off""") + +# +# File footer +# + +print(""" +} // namespace le_audio::asrc""") diff --git a/system/bta/le_audio/audio_hal_client/audio_hal_client.h b/system/bta/le_audio/audio_hal_client/audio_hal_client.h index d24ab7e67dc7bc5e589d14b5182e4e2311f0bb51..645b4f0a1b6cc93a2b03f857d3ea5b4aee2c5c6d 100644 --- a/system/bta/le_audio/audio_hal_client/audio_hal_client.h +++ b/system/bta/le_audio/audio_hal_client/audio_hal_client.h @@ -88,7 +88,7 @@ struct LeAudioCodecConfiguration { (data_interval_us == other.data_interval_us)); } - bool IsInvalid() { + bool IsInvalid() const { return (num_channels == 0) || (sample_rate == 0) || (bits_per_sample == 0) || (data_interval_us == 0); } @@ -101,16 +101,19 @@ class LeAudioSinkAudioHalClient { public: class Callbacks { public: + Callbacks() = default; virtual ~Callbacks() = default; - virtual void OnAudioSuspend(std::promise do_suspend_promise) = 0; + virtual void OnAudioSuspend(void) = 0; virtual void OnAudioResume(void) = 0; - virtual void OnAudioMetadataUpdate( - std::vector sink_metadata) = 0; + virtual void OnAudioMetadataUpdate(sink_metadata_v7 sink_metadata) = 0; + + base::WeakPtrFactory weak_factory_{this}; }; virtual ~LeAudioSinkAudioHalClient() = default; virtual bool Start(const LeAudioCodecConfiguration& codecConfiguration, - Callbacks* audioReceiver) = 0; + Callbacks* audioReceiver, + DsaModes dsa_modes = {DsaMode::DISABLED}) = 0; virtual void Stop() = 0; virtual size_t SendData(uint8_t* data, uint16_t size) = 0; @@ -137,17 +140,21 @@ class LeAudioSourceAudioHalClient { public: class Callbacks { public: + Callbacks() = default; virtual ~Callbacks() = default; virtual void OnAudioDataReady(const std::vector& data) = 0; - virtual void OnAudioSuspend(std::promise do_suspend_promise) = 0; + virtual void OnAudioSuspend(void) = 0; virtual void OnAudioResume(void) = 0; - virtual void OnAudioMetadataUpdate( - std::vector source_metadata) = 0; + virtual void OnAudioMetadataUpdate(source_metadata_v7 source_metadata, + DsaMode dsa_mode) = 0; + + base::WeakPtrFactory weak_factory_{this}; }; virtual ~LeAudioSourceAudioHalClient() = default; virtual bool Start(const LeAudioCodecConfiguration& codecConfiguration, - Callbacks* audioReceiver) = 0; + Callbacks* audioReceiver, + DsaModes dsa_modes = {DsaMode::DISABLED}) = 0; virtual void Stop() = 0; virtual size_t SendData(uint8_t* data, uint16_t size) { return 0; } virtual void ConfirmStreamingRequest() = 0; diff --git a/system/bta/le_audio/audio_hal_client/audio_hal_client_test.cc b/system/bta/le_audio/audio_hal_client/audio_hal_client_test.cc index 5a6729299cb942a08892c2258f9ba96393ddceb7..7f0abebd95c522b08bd5897f8d6dbd7b14526fc2 100644 --- a/system/bta/le_audio/audio_hal_client/audio_hal_client_test.cc +++ b/system/bta/le_audio/audio_hal_client/audio_hal_client_test.cc @@ -42,6 +42,8 @@ using ::testing::ReturnPointee; using ::testing::SaveArg; using std::chrono_literals::operator""ms; +using le_audio::DsaMode; +using le_audio::DsaModes; using le_audio::LeAudioCodecConfiguration; using le_audio::LeAudioSinkAudioHalClient; using le_audio::LeAudioSourceAudioHalClient; @@ -128,6 +130,8 @@ class MockLeAudioClientInterface : public LeAudioClientInterface { MOCK_METHOD((Source*), GetSource, (bluetooth::audio::le_audio::StreamCallbacks stream_cb, bluetooth::common::MessageLoopThread* message_loop)); + + MOCK_METHOD((void), SetAllowedDsaModes, (DsaModes dsa_modes)); }; LeAudioClientInterface* mockInterface; @@ -163,6 +167,8 @@ bool LeAudioClientInterface::ReleaseSource( return true; } +void LeAudioClientInterface::SetAllowedDsaModes(DsaModes dsa_modes) { return; } + void LeAudioClientInterface::Sink::Cleanup() {} void LeAudioClientInterface::Sink::SetPcmParameters( const PcmParameters& params) {} @@ -208,22 +214,19 @@ class MockLeAudioClientAudioSinkEventReceiver public: MOCK_METHOD((void), OnAudioDataReady, (const std::vector& data), (override)); - MOCK_METHOD((void), OnAudioSuspend, (std::promise do_suspend_promise), - (override)); + MOCK_METHOD((void), OnAudioSuspend, (), (override)); MOCK_METHOD((void), OnAudioResume, (), (override)); MOCK_METHOD((void), OnAudioMetadataUpdate, - (std::vector source_metadata), + (source_metadata_v7 source_metadata, DsaMode dsa_mode), (override)); }; class MockAudioHalClientEventReceiver : public LeAudioSinkAudioHalClient::Callbacks { public: - MOCK_METHOD((void), OnAudioSuspend, (std::promise do_suspend_promise), - (override)); + MOCK_METHOD((void), OnAudioSuspend, (), (override)); MOCK_METHOD((void), OnAudioResume, (), (override)); - MOCK_METHOD((void), OnAudioMetadataUpdate, - (std::vector sink_metadata), + MOCK_METHOD((void), OnAudioMetadataUpdate, (sink_metadata_v7 sink_metadata), (override)); }; @@ -237,7 +240,7 @@ class LeAudioClientAudioTest : public ::testing::Test { // Init sink Audio HAL mock is_sink_audio_hal_acquired = false; - sink_audio_hal_stream_cb = {.on_suspend_ = nullptr, .on_resume_ = nullptr}; + sink_audio_hal_stream_cb = {.on_resume_ = nullptr, .on_suspend_ = nullptr}; ON_CALL(mock_client_interface_, GetSink(_, _, _)) .WillByDefault(DoAll(SaveArg<0>(&sink_audio_hal_stream_cb), @@ -248,8 +251,8 @@ class LeAudioClientAudioTest : public ::testing::Test { // Init source Audio HAL mock is_source_audio_hal_acquired = false; - source_audio_hal_stream_cb = {.on_suspend_ = nullptr, - .on_resume_ = nullptr}; + source_audio_hal_stream_cb = {.on_resume_ = nullptr, + .on_suspend_ = nullptr}; ON_CALL(mock_client_interface_, GetSource(_, _)) .WillByDefault(DoAll(SaveArg<0>(&source_audio_hal_stream_cb), @@ -413,7 +416,7 @@ TEST_F(LeAudioClientAudioTest, testLeAudioClientAudioSinkSuspend) { /* Expect LeAudio registered event listener to get called when HAL calls the * audio_hal_client's internal suspend callback. */ - EXPECT_CALL(mock_hal_source_event_receiver_, OnAudioSuspend(_)).Times(1); + EXPECT_CALL(mock_hal_source_event_receiver_, OnAudioSuspend()).Times(1); ASSERT_TRUE(source_audio_hal_stream_cb.on_suspend_()); } @@ -427,7 +430,7 @@ TEST_F(LeAudioClientAudioTest, testAudioHalClientSuspend) { /* Expect LeAudio registered event listener to get called when HAL calls the * audio_hal_client's internal suspend callback. */ - EXPECT_CALL(mock_hal_sink_event_receiver_, OnAudioSuspend(_)).Times(1); + EXPECT_CALL(mock_hal_sink_event_receiver_, OnAudioSuspend()).Times(1); ASSERT_TRUE(sink_audio_hal_stream_cb.on_suspend_()); } 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 8d435901dca416273bb46dc6c75a3fb1894bd77b..f44218ebc0204b57d2fc707c795a033924097ee5 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 @@ -21,10 +21,10 @@ #include "audio_hal_client.h" #include "audio_hal_interface/le_audio_software.h" #include "bta/le_audio/codec_manager.h" -#include "btu.h" #include "common/time_util.h" #include "osi/include/log.h" #include "osi/include/wakelock.h" +#include "stack/include/main_thread.h" using bluetooth::audio::le_audio::LeAudioClientInterface; @@ -41,7 +41,8 @@ class SinkImpl : public LeAudioSinkAudioHalClient { public: // Interface implementation bool Start(const LeAudioCodecConfiguration& codecConfiguration, - LeAudioSinkAudioHalClient::Callbacks* audioReceiver) override; + LeAudioSinkAudioHalClient::Callbacks* audioReceiver, + DsaModes dsa_modes) override; void Stop(); size_t SendData(uint8_t* data, uint16_t size) override; void ConfirmStreamingRequest() override; @@ -60,7 +61,7 @@ class SinkImpl : public LeAudioSinkAudioHalClient { bool OnResumeReq(bool start_media_task); bool OnSuspendReq(); - bool OnMetadataUpdateReq(const sink_metadata_t& sink_metadata); + bool OnMetadataUpdateReq(const sink_metadata_v7_t& sink_metadata); bool Acquire(); void Release(); @@ -128,7 +129,7 @@ bool SinkImpl::OnResumeReq(bool start_media_task) { bt_status_t status = do_in_main_thread( FROM_HERE, base::BindOnce(&LeAudioSinkAudioHalClient::Callbacks::OnAudioResume, - base::Unretained(audioSinkCallbacks_))); + audioSinkCallbacks_->weak_factory_.GetWeakPtr())); if (status == BT_STATUS_SUCCESS) { return true; } @@ -143,16 +144,11 @@ bool SinkImpl::OnSuspendReq() { return false; } - std::promise do_suspend_promise; - std::future do_suspend_future = do_suspend_promise.get_future(); - bt_status_t status = do_in_main_thread( FROM_HERE, base::BindOnce(&LeAudioSinkAudioHalClient::Callbacks::OnAudioSuspend, - base::Unretained(audioSinkCallbacks_), - std::move(do_suspend_promise))); + audioSinkCallbacks_->weak_factory_.GetWeakPtr())); if (status == BT_STATUS_SUCCESS) { - do_suspend_future.wait(); return true; } @@ -160,22 +156,17 @@ bool SinkImpl::OnSuspendReq() { return false; } -bool SinkImpl::OnMetadataUpdateReq(const sink_metadata_t& sink_metadata) { +bool SinkImpl::OnMetadataUpdateReq(const sink_metadata_v7_t& sink_metadata) { if (audioSinkCallbacks_ == nullptr) { LOG_ERROR("audioSinkCallbacks_ not set"); return false; } - std::vector metadata; - for (size_t i = 0; i < sink_metadata.track_count; i++) { - metadata.push_back(sink_metadata.tracks[i]); - } - bt_status_t status = do_in_main_thread( FROM_HERE, base::BindOnce( &LeAudioSinkAudioHalClient::Callbacks::OnAudioMetadataUpdate, - base::Unretained(audioSinkCallbacks_), metadata)); + audioSinkCallbacks_->weak_factory_.GetWeakPtr(), sink_metadata)); if (status == BT_STATUS_SUCCESS) { return true; } @@ -185,7 +176,8 @@ bool SinkImpl::OnMetadataUpdateReq(const sink_metadata_t& sink_metadata) { } bool SinkImpl::Start(const LeAudioCodecConfiguration& codec_configuration, - LeAudioSinkAudioHalClient::Callbacks* audioReceiver) { + LeAudioSinkAudioHalClient::Callbacks* audioReceiver, + DsaModes dsa_modes) { if (!halSourceInterface_) { LOG_ERROR("Audio HAL Audio source interface not acquired"); return false; @@ -208,6 +200,7 @@ bool SinkImpl::Start(const LeAudioCodecConfiguration& codec_configuration, .channels_count = codec_configuration.num_channels}; halSourceInterface_->SetPcmParameters(pcmParameters); + LeAudioClientInterface::Get()->SetAllowedDsaModes(dsa_modes); halSourceInterface_->StartSession(); audioSinkCallbacks_ = audioReceiver; diff --git a/system/bta/le_audio/audio_hal_client/audio_source_hal_asrc.cc b/system/bta/le_audio/audio_hal_client/audio_source_hal_asrc.cc new file mode 100644 index 0000000000000000000000000000000000000000..43b5e8f4df4104b882ed8acb25c4f02ca0537fbe --- /dev/null +++ b/system/bta/le_audio/audio_hal_client/audio_source_hal_asrc.cc @@ -0,0 +1,624 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "audio_source_hal_asrc.h" + +#include +#include + +#include +#include + +#include "asrc_tables.h" +#include "gd/hal/nocp_iso_clocker.h" + +namespace le_audio { + +class SourceAudioHalAsrc::ClockRecovery : ::bluetooth::hal::NocpIsoHandler { + const int interval_; + + std::mutex mutex_; + + unsigned num_produced_; + unsigned num_completed_; + int min_buffer_level_; + int max_buffer_level_; + + enum class StateId { RESET, WARMUP, RUNNING }; + + struct { + StateId id; + + uint32_t t0; + uint32_t local_time; + uint32_t stream_time; + + uint32_t decim_t0; + int decim_dt[2]; + + double butter_drift; + double butter_s[2]; + } state_; + + struct { + uint32_t local_time; + uint32_t stream_time; + double drift; + } reference_timing_; + + struct { + double sample_rate; + int drift_us; + } output_stats_; + + __attribute__((no_sanitize("integer"))) void OnEvent( + uint32_t timestamp_us, int num_completed) override { + auto& state = state_; + + // Setup the start point of the streaming + + if (state.id == StateId::RESET) { + state.t0 = timestamp_us; + state.local_time = state.stream_time = state.t0; + + state.decim_t0 = state.t0; + state.decim_dt[1] = INT_MAX; + state.id = StateId::WARMUP; + } + + // Update buffering level measure + + { + const std::lock_guard lock(mutex_); + + num_completed_ += num_completed; + min_buffer_level_ = + std::min(min_buffer_level_, int(num_produced_ - num_completed_)); + } + + // Update timing informations, and compute the minimum deviation + // in the interval of the decimation (1 second). + + state.local_time += num_completed * interval_; + state.stream_time += num_completed * interval_; + + int dt_current = int(timestamp_us - state.local_time); + state.decim_dt[1] = std::min(state.decim_dt[1], dt_current); + + if (state.local_time - state.decim_t0 < 1000 * 1000) return; + + state.decim_t0 += 1000 * 1000; + + // The first decimation interval is used to adjust the start point. + // The deviation between local time and stream time in this interval can be + // ignored. + + if (state.id == StateId::WARMUP) { + state.decim_t0 += state.decim_dt[1]; + state.local_time += state.decim_dt[1]; + state.stream_time += state.decim_dt[1]; + + state.decim_dt[0] = 0; + state.decim_dt[1] = INT_MAX; + state.id = StateId::RUNNING; + return; + } + + // Deduct the derive of the deviation, from the difference between + // the two consecutives decimated deviations. + + int drift = state.decim_dt[1] - state.decim_dt[0]; + state.decim_dt[0] = state.decim_dt[1]; + state.decim_dt[1] = INT_MAX; + + // Let's filter the derive, with a low-pass Butterworth filter. + // The cut-off frequency is set to 1/60th seconds. + + const double a1 = -1.9259839697e+00, a2 = 9.2862708612e-01; + const double b0 = 6.6077909823e-04, b1 = 1.3215581965e-03, b2 = b0; + + state.butter_drift = drift * b0 + state.butter_s[0]; + state.butter_s[0] = + state.butter_s[1] + drift * b1 - state.butter_drift * a1; + state.butter_s[1] = drift * b2 - state.butter_drift * a2; + + // The stream time is adjusted with the filtered drift, and the error is + // caught up with a gain of 2^-8 (~1/250us). The error is deducted from + // the difference between the instant stream time, and the local time + // corrected by the decimated deviation. + + int err = state.stream_time - (state.local_time + state.decim_dt[0]); + state.stream_time += + (int(ldexpf(state.butter_drift, 8)) - err + (1 << 7)) >> 8; + + // Update recovered timing information, and sample the output statistics. + + decltype(output_stats_) output_stats; + int min_buffer_level; + + { + const std::lock_guard lock(mutex_); + + auto& ref = reference_timing_; + ref.local_time = state.local_time - state.t0; + ref.stream_time = state.stream_time - state.t0; + ref.drift = state.butter_drift * 1e-6; + + output_stats = output_stats_; + min_buffer_level = min_buffer_level_; + min_buffer_level_ = INT_MAX; + max_buffer_level_ = INT_MIN; + } + + LOG(INFO) << base::StringPrintf("Deviation: %6d us (%3.0f ppm)", + state.stream_time - state.local_time, + state.butter_drift) + << " | " + << base::StringPrintf("Output Fs: %5.2f Hz drift: %2d us", + output_stats.sample_rate, + output_stats.drift_us) + << " | " + << base::StringPrintf("Buffer level: %d", min_buffer_level) + << std::endl; + } + + public: + ClockRecovery(unsigned interval_us) + : interval_(interval_us), + num_produced_(0), + num_completed_(0), + min_buffer_level_(INT_MAX), + max_buffer_level_(INT_MIN), + state_{.id = StateId::RESET}, + reference_timing_{0, 0, 0} { + ::bluetooth::hal::NocpIsoClocker::Register(this); + } + + ~ClockRecovery() override { ::bluetooth::hal::NocpIsoClocker::Unregister(); } + + __attribute__((no_sanitize("integer"))) uint32_t Convert( + uint32_t stream_time) { + // Compute the difference between the stream time and the sampled time + // of the clock recovery, and adjust according to the drift. + // Then return the sampled local time, modified by this converted gap. + + const std::lock_guard lock(mutex_); + const auto& ref = reference_timing_; + + int stream_dt = int(stream_time - ref.stream_time); + int local_dt_us = int(round(stream_dt * (1 + ref.drift))); + return ref.local_time + local_dt_us; + } + + void UpdateOutputStats(unsigned out_count, double sample_rate, int drift_us) { + // Atomically update the output statistics, + // this should be used for logging. + + const std::lock_guard lock(mutex_); + + num_produced_ += out_count; + max_buffer_level_ = + std::max(max_buffer_level_, int(num_produced_ - num_completed_)); + + output_stats_ = {sample_rate, drift_us}; + } +}; + +class SourceAudioHalAsrc::Resampler { + static const int KERNEL_Q = asrc::ResamplerTables::KERNEL_Q; + static const int KERNEL_A = asrc::ResamplerTables::KERNEL_A; + + const int32_t (*h_)[2 * KERNEL_A]; + const int16_t (*d_)[2 * KERNEL_A]; + + static const unsigned WSIZE = 64; + + int32_t win_[2][WSIZE]; + unsigned out_pos_, in_pos_; + const int32_t pcm_min_, pcm_max_; + + // Apply the transfer coefficients `h`, corrected by linear interpolation, + // given fraction position `mu` weigthed by `d` values. + + inline int32_t Filter(const int32_t* in, const int32_t* h, int16_t mu, + const int16_t* d); + + // Upsampling loop, the ratio is less than 1.0 in Q26 format, + // more output samples are produced compared to input. + + template + __attribute__((no_sanitize("integer"))) void Upsample( + unsigned ratio, const T* in, int in_stride, size_t in_len, + size_t* in_count, T* out, int out_stride, size_t out_len, + size_t* out_count) { + int nin = in_len, nout = out_len; + + while (nin > 0 && nout > 0) { + unsigned idx = (in_pos_ >> 26); + unsigned phy = (in_pos_ >> 17) & 0x1ff; + int16_t mu = (in_pos_ >> 2) & 0x7fff; + + unsigned wbuf = idx < WSIZE / 2 || idx >= WSIZE + WSIZE / 2; + auto w = win_[wbuf] + ((idx + wbuf * WSIZE / 2) % WSIZE) - WSIZE / 2; + + *out = Filter(w, h_[phy], mu, d_[phy]); + out += out_stride; + nout--; + in_pos_ += ratio; + + if (in_pos_ - (out_pos_ << 26) >= (1u << 26)) { + win_[0][(out_pos_ + WSIZE / 2) % WSIZE] = win_[1][(out_pos_)] = *in; + + in += in_stride; + nin--; + out_pos_ = (out_pos_ + 1) % WSIZE; + } + } + + *in_count = in_len - nin; + *out_count = out_len - nout; + } + + // Downsample loop, the ratio is greater than 1.0 in Q26 format, + // less output samples are produced compared to input. + + template + __attribute__((no_sanitize("integer"))) void Downsample( + unsigned ratio, const T* in, int in_stride, size_t in_len, + size_t* in_count, T* out, int out_stride, size_t out_len, + size_t* out_count) { + size_t nin = in_len, nout = out_len; + + while (nin > 0 && nout > 0) { + if (in_pos_ - (out_pos_ << 26) < (1u << 26)) { + unsigned idx = (in_pos_ >> 26); + unsigned phy = (in_pos_ >> 17) & 0x1ff; + int16_t mu = (in_pos_ >> 2) & 0x7fff; + + unsigned wbuf = idx < WSIZE / 2 || idx >= WSIZE + WSIZE / 2; + auto w = win_[wbuf] + ((idx + wbuf * WSIZE / 2) % WSIZE) - WSIZE / 2; + + *out = Filter(w, h_[phy], mu, d_[phy]); + out += out_stride; + nout--; + in_pos_ += ratio; + } + + win_[0][(out_pos_ + WSIZE / 2) % WSIZE] = win_[1][(out_pos_)] = *in; + + in += in_stride; + nin--; + out_pos_ = (out_pos_ + 1) % WSIZE; + } + + *in_count = in_len - nin; + *out_count = out_len - nout; + } + + public: + Resampler(int bit_depth) + : h_(asrc::resampler_tables.h), + d_(asrc::resampler_tables.d), + win_{{0}, {0}}, + out_pos_(0), + in_pos_(0), + pcm_min_(-(int32_t(1) << (bit_depth - 1))), + pcm_max_((int32_t(1) << (bit_depth - 1)) - 1) {} + + // Resample from `in` buffer to `out` buffer, until the end of any of + // the two buffers. `in_count` returns the number of consumed samples, + // and `out_count` the number produced. `in_sub` returns the phase in + // the input stream, in Q26 format. + + template + void Resample(unsigned ratio_q26, const T* in, int in_stride, size_t in_len, + size_t* in_count, T* out, int out_stride, size_t out_len, + size_t* out_count, unsigned* in_sub_q26) { + auto fn = ratio_q26 < (1u << 26) ? &Resampler::Upsample + : &Resampler::Downsample; + + (this->*fn)(ratio_q26, in, in_stride, in_len, in_count, out, out_stride, + out_len, out_count); + + *in_sub_q26 = in_pos_ & ((1u << 26) - 1); + } +}; + +// +// ARM AArch 64 Neon Resampler Filtering +// + +#if __ARM_NEON && __ARM_ARCH_ISA_A64 + +#include + +static inline int32x4_t vmull_low_s16(int16x8_t a, int16x8_t b) { + return vmull_s16(vget_low_s16(a), vget_low_s16(b)); +} + +static inline int64x2_t vmull_low_s32(int32x4_t a, int32x4_t b) { + return vmull_s32(vget_low_s32(a), vget_low_s32(b)); +} + +static inline int64x2_t vmlal_low_s32(int64x2_t r, int32x4_t a, int32x4_t b) { + return vmlal_s32(r, vget_low_s32(a), vget_low_s32(b)); +} + +inline int32_t SourceAudioHalAsrc::Resampler::Filter(const int32_t* x, + const int32_t* h, + int16_t _mu, + const int16_t* d) { + int64x2_t sx; + + int16x8_t mu = vdupq_n_s16(_mu); + + int16x8_t d0 = vld1q_s16(d + 0); + int32x4_t h0 = vld1q_s32(h + 0), h4 = vld1q_s32(h + 4); + int32x4_t x0 = vld1q_s32(x + 0), x4 = vld1q_s32(x + 4); + + h0 = vaddq_s32(h0, vrshrq_n_s32(vmull_low_s16(d0, mu), 7)); + h4 = vaddq_s32(h4, vrshrq_n_s32(vmull_high_s16(d0, mu), 7)); + + sx = vmull_low_s32(x0, h0); + sx = vmlal_high_s32(sx, x0, h0); + sx = vmlal_low_s32(sx, x4, h4); + sx = vmlal_high_s32(sx, x4, h4); + + for (int i = 8; i < 32; i += 8) { + int16x8_t d8 = vld1q_s16(d + i); + int32x4_t h8 = vld1q_s32(h + i), h12 = vld1q_s32(h + i + 4); + int32x4_t x8 = vld1q_s32(x + i), x12 = vld1q_s32(x + i + 4); + + h8 = vaddq_s32(h8, vrshrq_n_s32(vmull_low_s16(d8, mu), 7)); + h12 = vaddq_s32(h12, vrshrq_n_s32(vmull_high_s16(d8, mu), 7)); + + sx = vmlal_low_s32(sx, x8, h8); + sx = vmlal_high_s32(sx, x8, h8); + sx = vmlal_low_s32(sx, x12, h12); + sx = vmlal_high_s32(sx, x12, h12); + } + + int64_t s = (vaddvq_s64(sx) + (1 << 30)) >> 31; + return std::clamp(s, int64_t(pcm_min_), int64_t(pcm_max_)); +} + +// +// Generic Resampler Filtering +// + +#else + +inline int32_t SourceAudioHalAsrc::Resampler::Filter(const int32_t* in, + const int32_t* h, + int16_t mu, + const int16_t* d) { + int64_t s = 0; + for (int i = 0; i < 2 * KERNEL_A - 1; i++) + s += int64_t(in[i]) * (h[i] + ((mu * d[i] + (1 << 6)) >> 7)); + + s = (s + (1 << 30)) >> 31; + return std::clamp(s, int64_t(pcm_min_), int64_t(pcm_max_)); +} + +#endif + +SourceAudioHalAsrc::SourceAudioHalAsrc(int channels, int sample_rate, + int bit_depth, int interval_us, + int num_burst_buffers, + int burst_delay_ms) + : sample_rate_(sample_rate), + bit_depth_(bit_depth), + interval_us_(interval_us), + stream_us_(0), + drift_us_(0), + out_counter_(0), + resampler_pos_{0, 0} { + buffers_size_ = 0; + + // Check parameters + + auto check_bounds = [](int v, int min, int max) { + return v >= min && v <= max; + }; + + if (!check_bounds(channels, 1, 8) || + !check_bounds(sample_rate, 1 * 1000, 100 * 1000) || + !check_bounds(bit_depth, 8, 32) || + !check_bounds(interval_us, 1 * 1000, 100 * 1000) || + !check_bounds(num_burst_buffers, 0, 10) || + !check_bounds(burst_delay_ms, 0, 1000)) { + LOG(ERROR) << "Bad parameters:" + << " channels: " << channels << " sample_rate: " << sample_rate + << " bit_depth: " << bit_depth << " interval_us: " << interval_us + << " num_burst_buffers: " << num_burst_buffers + << " burst_delay_ms: " << burst_delay_ms << std::endl; + + return; + } + + // Compute filter constants + + const double drift_release_sec = 3; + drift_z0_ = 1. - exp(-3. / (1e6 / interval_us_) / drift_release_sec); + + // Setup modules, the 32 bits resampler is choosed over the 16 bits resampler + // when the PCM bit_depth is higher than 16 bits. + + clock_recovery_ = std::make_unique(interval_us_); + resamplers_ = std::make_unique>(channels, bit_depth_); + + // Deduct from the PCM stream characteristics, the size of the pool buffers + // It needs 3 buffers (one almost full, an entire one, and a last which can be + // started). + + auto& buffers = buffers_; + + int num_interval_samples = + channels * (interval_us_ * sample_rate_) / (1000 * 1000); + buffers_size_ = num_interval_samples * + (bit_depth_ <= 16 ? sizeof(int16_t) : sizeof(int32_t)); + + for (auto& b : buffers.pool) b.resize(buffers_size_); + buffers.index = 0; + buffers.offset = 0; + + // Setup the burst buffers to silence + + auto silence_buffer = &buffers_.pool[0]; + std::fill(silence_buffer->begin(), silence_buffer->end(), 0); + + burst_buffers_.resize(num_burst_buffers); + for (auto& b : burst_buffers_) b = silence_buffer; + + burst_delay_us_ = burst_delay_ms * 1000; +} + +SourceAudioHalAsrc::~SourceAudioHalAsrc() {} + +template +__attribute__((no_sanitize("integer"))) void SourceAudioHalAsrc::Resample( + double ratio, const std::vector& in, + std::vector*>* out, uint32_t* output_us) { + auto& resamplers = *resamplers_; + auto& buffers = buffers_; + auto channels = resamplers.size(); + + // Convert the resampling ration in fixed Q16, + // then loop until the input buffer is consumed. + + auto in_size = in.size() / sizeof(T); + auto in_length = in_size / channels; + + unsigned ratio_q26 = round(ldexp(ratio, 26)); + unsigned sub_q26; + + while (in_length > 0) { + auto in_data = (const T*)in.data() + (in_size - in_length * channels); + + // Load from the context the current output buffer, the offset + // and deduct the remaning size. Let's resample the interleaved + // PCM stream, a separate reampler is used for each channel. + + auto buffer = &buffers.pool[buffers.index]; + auto out_data = (T*)buffer->data() + buffers.offset; + auto out_size = buffer->size() / sizeof(T); + auto out_length = (out_size - buffers.offset) / channels; + + size_t in_count, out_count; + + for (auto& r : resamplers) + r.Resample(ratio_q26, in_data++, channels, in_length, &in_count, + out_data++, channels, out_length, &out_count, &sub_q26); + + in_length -= in_count; + buffers.offset += out_count * channels; + + // Update the resampler position, expressed in seconds + // and a number of samples in a second. The `sub_q26` variable + // returned by the resampler, adds the sub-sample information. + + resampler_pos_.samples += out_count; + for (; resampler_pos_.samples >= sample_rate_; + resampler_pos_.samples -= sample_rate_) + resampler_pos_.seconds++; + + // An output buffer has been fulfilled, + // select a new buffer in the pool, used as a ring. + + if (out_count >= out_length) { + buffers.index = (buffers.index + 1) % buffers.pool.size(); + buffers.offset = 0; + out->push_back(buffer); + } + } + + // Let's convert the resampler position, in a micro-seconds timestamp. + // The samples count within a seconds, and sub-sample position, are + // converted, then add the number of seconds modulo 2^32. + + int64_t output_samples_q26 = (int64_t(resampler_pos_.samples) << 26) - + ((int64_t(sub_q26) << 26) / ratio_q26); + + *output_us = resampler_pos_.seconds * (1000 * 1000) + + uint32_t((output_samples_q26 * 1000 * 1000) / + (int64_t(sample_rate_) << 26)); +} + +__attribute__((no_sanitize("integer"))) std::vector*> +SourceAudioHalAsrc::Run(const std::vector& in) { + std::vector*> out; + + if (in.size() != buffers_size_) { + LOG(ERROR) << "Inconsistent input buffer size: " << in.size() << " (" + << buffers_size_ << " expected)" << std::endl; + return out; + } + + // The burst delay has expired, let's generate the burst. + + if (burst_buffers_.size() && stream_us_ >= burst_delay_us_) { + for (size_t i = 0; i < burst_buffers_.size(); i++) + out.push_back(burst_buffers_[(out_counter_ + i) % burst_buffers_.size()]); + + burst_buffers_.clear(); + } + + // Convert the stream position to a local time, + // and catch up the drift within the next second. + + stream_us_ += interval_us_; + uint32_t local_us = clock_recovery_->Convert(stream_us_); + + double ratio = 1e6 / (1e6 - drift_us_); + + // Let's run the resampler, + // and update the drift according the output position returned. + + uint32_t output_us; + + if (bit_depth_ <= 16) + Resample(ratio, in, &out, &output_us); + else + Resample(ratio, in, &out, &output_us); + + drift_us_ += drift_z0_ * (int(output_us - local_us) - drift_us_); + + // Delay the stream, in order to generate a burst when + // the associated delay has expired. + + if (burst_buffers_.size()) { + for (size_t i = 0; i < out.size(); i++) + std::exchange*>( + out[i], burst_buffers_[(out_counter_ + i) % burst_buffers_.size()]); + } + + // Return the output statistics to the clock recovery module + + out_counter_ += out.size(); + clock_recovery_->UpdateOutputStats(out.size(), ratio * sample_rate_, + int(output_us - local_us)); + + if (0) + LOG(INFO) << base::StringPrintf( + "[%6u.%06u] Fs: %.2f Hz drift: %d us", + output_us / (1000 * 1000), output_us % (1000 * 1000), + ratio * sample_rate_, int(output_us - local_us)) + << std::endl; + + return out; +} + +} // namespace le_audio diff --git a/system/bta/le_audio/audio_hal_client/audio_source_hal_asrc.h b/system/bta/le_audio/audio_hal_client/audio_source_hal_asrc.h new file mode 100644 index 0000000000000000000000000000000000000000..f5595390a43650f950590e489e2a50116584d9a6 --- /dev/null +++ b/system/bta/le_audio/audio_hal_client/audio_source_hal_asrc.h @@ -0,0 +1,92 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace le_audio { + +class SourceAudioHalAsrc { + public: + // The Asynchronous Sample Rate Conversion (ASRC) is set up from the PCM + // stream characteristics and the length, expressed in us, of the buffers. + // + // A transmission `burst` is proposed, to fulfill the audio pipeline + // buffering. After an initial delay of `burst_delay_ms`, a burst of + // `num_burst_buffers` is generated. By experience, it looks like some + // controllers discard and acknowledge the first packets without following + // transmission intervals. This behavior leads to dumping initial buffers. The + // `burst_delay_ms` helps to ensure that the synchronization with the + // transmission intervals is done. + + SourceAudioHalAsrc(int channels, int sample_rate, int bit_depth, + int interval_us, int num_burst_buffers = 2, + int burst_delay_ms = 500); + + ~SourceAudioHalAsrc(); + + // Takes an input buffer, and returns a list of resamples buffers locked to + // the cadence of the transmission. The input and output buffers have a fixed + // size, deducted from the PCM characteristics, given to the constructor. + // + // The data of `in` mest be aligned to `int16_t` or `int32_t` for respectively + // bit depth less or equal to 16, or greater. + // + + std::vector*> Run(const std::vector& in); + + private: + const int sample_rate_; + const int bit_depth_; + const int interval_us_; + + unsigned burst_delay_us_; + std::vector*> burst_buffers_; + + unsigned stream_us_; + double drift_z0_, drift_us_; + unsigned out_counter_; + + size_t buffers_size_; + + struct { + std::array, 3> pool; + int initial_buffering; + int index, offset; + } buffers_; + + class ClockRecovery; + std::unique_ptr clock_recovery_; + + class Resampler; + std::unique_ptr> resamplers_; + struct { + unsigned seconds; + int samples; + } resampler_pos_; + + template + void Resample(double, const std::vector&, + std::vector*>*, uint32_t*); + + friend class SourceAudioHalAsrcTest; +}; + +} // namespace le_audio 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 38156929f2b80572b86afe4c1eb14d0cb060e0cf..dedaeba5827a05b50bd44c02a99a115a3298e34b 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 @@ -18,25 +18,22 @@ * ******************************************************************************/ +#include +#include + #include "audio_hal_client.h" #include "audio_hal_interface/le_audio_software.h" +#include "audio_source_hal_asrc.h" #include "bta/le_audio/codec_manager.h" -#include "btu.h" #include "common/time_util.h" #include "osi/include/log.h" #include "osi/include/wakelock.h" +#include "stack/include/main_thread.h" using bluetooth::audio::le_audio::LeAudioClientInterface; namespace le_audio { namespace { -// TODO: HAL state should be in the HAL implementation -enum { - HAL_UNINITIALIZED, - HAL_STOPPED, - HAL_STARTED, -} le_audio_sink_hal_state; - struct AudioHalStats { size_t media_read_total_underflow_bytes; size_t media_read_total_underflow_count; @@ -52,10 +49,17 @@ struct AudioHalStats { } sStats; class SourceImpl : public LeAudioSourceAudioHalClient { + enum LeAudioSinkHalState { + HAL_UNINITIALIZED, + HAL_STOPPED, + HAL_STARTED, + } le_audio_sink_hal_state_; + public: // Interface implementation bool Start(const LeAudioCodecConfiguration& codec_configuration, - LeAudioSourceAudioHalClient::Callbacks* audioReceiver) override; + LeAudioSourceAudioHalClient::Callbacks* audioReceiver, + DsaModes dsa_modes) override; void Stop() override; void ConfirmStreamingRequest() override; void CancelStreamingRequest() override; @@ -68,14 +72,17 @@ class SourceImpl : public LeAudioSourceAudioHalClient { void ReconfigurationComplete() override; // Internal functionality - SourceImpl(bool is_broadcaster) : is_broadcaster_(is_broadcaster){}; + SourceImpl(bool is_broadcaster) + : le_audio_sink_hal_state_(HAL_UNINITIALIZED), + is_broadcaster_(is_broadcaster){}; ~SourceImpl() override { - if (le_audio_sink_hal_state != HAL_UNINITIALIZED) Release(); + if (le_audio_sink_hal_state_ != HAL_UNINITIALIZED) Release(); } bool OnResumeReq(bool start_media_task); bool OnSuspendReq(); - bool OnMetadataUpdateReq(const source_metadata_t& source_metadata); + bool OnMetadataUpdateReq(const source_metadata_v7_t& source_metadata, + DsaMode latency_mode); bool Acquire(); void Release(); bool InitAudioSinkThread(); @@ -93,6 +100,7 @@ class SourceImpl : public LeAudioSourceAudioHalClient { nullptr; LeAudioSourceAudioHalClient::Callbacks* audioSourceCallbacks_ = nullptr; std::mutex audioSourceCallbacksMutex_; + std::unique_ptr asrc_; }; bool SourceImpl::Acquire() { @@ -100,10 +108,11 @@ bool SourceImpl::Acquire() { .on_resume_ = std::bind(&SourceImpl::OnResumeReq, this, std::placeholders::_1), .on_suspend_ = std::bind(&SourceImpl::OnSuspendReq, this), - .on_metadata_update_ = std::bind(&SourceImpl::OnMetadataUpdateReq, this, - std::placeholders::_1), + .on_metadata_update_ = + std::bind(&SourceImpl::OnMetadataUpdateReq, this, + std::placeholders::_1, std::placeholders::_2), .on_sink_metadata_update_ = - [](const sink_metadata_t& sink_metadata) { + [](const sink_metadata_v7_t& sink_metadata) { // TODO: update microphone configuration based on sink metadata return true; }, @@ -125,12 +134,12 @@ bool SourceImpl::Acquire() { } LOG_INFO(); - le_audio_sink_hal_state = HAL_STOPPED; + le_audio_sink_hal_state_ = HAL_STOPPED; return this->InitAudioSinkThread(); } void SourceImpl::Release() { - if (le_audio_sink_hal_state == HAL_UNINITIALIZED) { + if (le_audio_sink_hal_state_ == HAL_UNINITIALIZED) { LOG_WARN("Audio HAL Audio sink is not running"); return; } @@ -148,7 +157,7 @@ void SourceImpl::Release() { LOG_ERROR("Can't get LE Audio HAL interface"); } - le_audio_sink_hal_state = HAL_UNINITIALIZED; + le_audio_sink_hal_state_ = HAL_UNINITIALIZED; halSinkInterface_ = nullptr; } } @@ -162,7 +171,7 @@ bool SourceImpl::OnResumeReq(bool start_media_task) { bt_status_t status = do_in_main_thread( FROM_HERE, base::BindOnce(&LeAudioSourceAudioHalClient::Callbacks::OnAudioResume, - base::Unretained(audioSourceCallbacks_))); + audioSourceCallbacks_->weak_factory_.GetWeakPtr())); if (status == BT_STATUS_SUCCESS) { return true; } @@ -195,9 +204,20 @@ void SourceImpl::SendAudioData() { bluetooth::common::time_get_os_boottime_us(); } - std::lock_guard guard(audioSourceCallbacksMutex_); - if (audioSourceCallbacks_ != nullptr) { - audioSourceCallbacks_->OnAudioDataReady(data); + if (IS_FLAG_ENABLED(leaudio_hal_client_asrc)) { + auto asrc_buffers = asrc_->Run(data); + + std::lock_guard guard(audioSourceCallbacksMutex_); + for (auto buffer : asrc_buffers) { + if (audioSourceCallbacks_ != nullptr) { + audioSourceCallbacks_->OnAudioDataReady(*buffer); + } + } + } else { + std::lock_guard guard(audioSourceCallbacksMutex_); + if (audioSourceCallbacks_ != nullptr) { + audioSourceCallbacks_->OnAudioDataReady(data); + } } } @@ -225,6 +245,12 @@ bool SourceImpl::InitAudioSinkThread() { void SourceImpl::StartAudioTicks() { wakelock_acquire(); + if (IS_FLAG_ENABLED(leaudio_hal_client_asrc)) { + asrc_ = std::make_unique( + source_codec_config_.num_channels, source_codec_config_.sample_rate, + source_codec_config_.bits_per_sample, + source_codec_config_.data_interval_us); + } audio_timer_.SchedulePeriodic( worker_thread_->GetWeakPtr(), FROM_HERE, base::Bind(&SourceImpl::SendAudioData, base::Unretained(this)), @@ -237,6 +263,7 @@ void SourceImpl::StartAudioTicks() { void SourceImpl::StopAudioTicks() { audio_timer_.CancelAndWait(); + asrc_.reset(nullptr); wakelock_release(); } @@ -252,16 +279,11 @@ bool SourceImpl::OnSuspendReq() { return false; } - // Call OnAudioSuspend and block till it returns. - std::promise do_suspend_promise; - std::future do_suspend_future = do_suspend_promise.get_future(); bt_status_t status = do_in_main_thread( FROM_HERE, base::BindOnce(&LeAudioSourceAudioHalClient::Callbacks::OnAudioSuspend, - base::Unretained(audioSourceCallbacks_), - std::move(do_suspend_promise))); + audioSourceCallbacks_->weak_factory_.GetWeakPtr())); if (status == BT_STATUS_SUCCESS) { - do_suspend_future.wait(); return true; } @@ -269,23 +291,20 @@ bool SourceImpl::OnSuspendReq() { return false; } -bool SourceImpl::OnMetadataUpdateReq(const source_metadata_t& source_metadata) { +bool SourceImpl::OnMetadataUpdateReq( + const source_metadata_v7_t& source_metadata, DsaMode dsa_mode) { std::lock_guard guard(audioSourceCallbacksMutex_); if (audioSourceCallbacks_ == nullptr) { LOG(ERROR) << __func__ << ", audio receiver not started"; return false; } - std::vector metadata; - for (size_t i = 0; i < source_metadata.track_count; i++) { - metadata.push_back(source_metadata.tracks[i]); - } - bt_status_t status = do_in_main_thread( FROM_HERE, base::BindOnce( &LeAudioSourceAudioHalClient::Callbacks::OnAudioMetadataUpdate, - base::Unretained(audioSourceCallbacks_), metadata)); + audioSourceCallbacks_->weak_factory_.GetWeakPtr(), source_metadata, + dsa_mode)); if (status == BT_STATUS_SUCCESS) { return true; } @@ -295,13 +314,14 @@ bool SourceImpl::OnMetadataUpdateReq(const source_metadata_t& source_metadata) { } bool SourceImpl::Start(const LeAudioCodecConfiguration& codec_configuration, - LeAudioSourceAudioHalClient::Callbacks* audioReceiver) { + LeAudioSourceAudioHalClient::Callbacks* audioReceiver, + DsaModes dsa_modes) { if (!halSinkInterface_) { LOG_ERROR("Audio HAL Audio sink interface not acquired"); return false; } - if (le_audio_sink_hal_state == HAL_STARTED) { + if (le_audio_sink_hal_state_ == HAL_STARTED) { LOG_ERROR("Audio HAL Audio sink is already in use"); return false; } @@ -322,11 +342,12 @@ bool SourceImpl::Start(const LeAudioCodecConfiguration& codec_configuration, .channels_count = codec_configuration.num_channels}; halSinkInterface_->SetPcmParameters(pcmParameters); + LeAudioClientInterface::Get()->SetAllowedDsaModes(dsa_modes); halSinkInterface_->StartSession(); std::lock_guard guard(audioSourceCallbacksMutex_); audioSourceCallbacks_ = audioReceiver; - le_audio_sink_hal_state = HAL_STARTED; + le_audio_sink_hal_state_ = HAL_STARTED; return true; } @@ -336,7 +357,7 @@ void SourceImpl::Stop() { return; } - if (le_audio_sink_hal_state != HAL_STARTED) { + if (le_audio_sink_hal_state_ != HAL_STARTED) { LOG_ERROR("Audio HAL Audio sink was not started!"); return; } @@ -344,7 +365,7 @@ void SourceImpl::Stop() { LOG_INFO(); halSinkInterface_->StopSession(); - le_audio_sink_hal_state = HAL_STOPPED; + le_audio_sink_hal_state_ = HAL_STOPPED; if (CodecManager::GetInstance()->GetCodecLocation() == types::CodecLocation::HOST) { @@ -357,7 +378,7 @@ void SourceImpl::Stop() { void SourceImpl::ConfirmStreamingRequest() { if ((halSinkInterface_ == nullptr) || - (le_audio_sink_hal_state != HAL_STARTED)) { + (le_audio_sink_hal_state_ != HAL_STARTED)) { LOG_ERROR("Audio HAL Audio sink was not started!"); return; } @@ -373,7 +394,7 @@ void SourceImpl::ConfirmStreamingRequest() { void SourceImpl::SuspendedForReconfiguration() { if ((halSinkInterface_ == nullptr) || - (le_audio_sink_hal_state != HAL_STARTED)) { + (le_audio_sink_hal_state_ != HAL_STARTED)) { LOG_ERROR("Audio HAL Audio sink was not started!"); return; } @@ -384,7 +405,7 @@ void SourceImpl::SuspendedForReconfiguration() { void SourceImpl::ReconfigurationComplete() { if ((halSinkInterface_ == nullptr) || - (le_audio_sink_hal_state != HAL_STARTED)) { + (le_audio_sink_hal_state_ != HAL_STARTED)) { LOG_ERROR("Audio HAL Audio sink was not started!"); return; } @@ -395,7 +416,7 @@ void SourceImpl::ReconfigurationComplete() { void SourceImpl::CancelStreamingRequest() { if ((halSinkInterface_ == nullptr) || - (le_audio_sink_hal_state != HAL_STARTED)) { + (le_audio_sink_hal_state_ != HAL_STARTED)) { LOG_ERROR("Audio HAL Audio sink was not started!"); return; } @@ -406,7 +427,7 @@ void SourceImpl::CancelStreamingRequest() { void SourceImpl::UpdateRemoteDelay(uint16_t remote_delay_ms) { if ((halSinkInterface_ == nullptr) || - (le_audio_sink_hal_state != HAL_STARTED)) { + (le_audio_sink_hal_state_ != HAL_STARTED)) { LOG_ERROR("Audio HAL Audio sink was not started!"); return; } @@ -418,7 +439,7 @@ void SourceImpl::UpdateRemoteDelay(uint16_t remote_delay_ms) { void SourceImpl::UpdateAudioConfigToHal( const ::le_audio::offload_config& config) { if ((halSinkInterface_ == nullptr) || - (le_audio_sink_hal_state != HAL_STARTED)) { + (le_audio_sink_hal_state_ != HAL_STARTED)) { LOG_ERROR("Audio HAL Audio sink was not started!"); return; } diff --git a/system/bta/le_audio/audio_set_scenarios.json b/system/bta/le_audio/audio_set_scenarios.json index 519e00131a8fe4cfa7a64d0f36aa8eacc206fa1f..9fa3409e3d855419095bb3d7342f23595cba3ca1 100644 --- a/system/bta/le_audio/audio_set_scenarios.json +++ b/system/bta/le_audio/audio_set_scenarios.json @@ -8,52 +8,52 @@ { "name": "Conversational", "configurations": [ + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_2", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_2", - "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", - "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", - "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", - "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1", + "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Low_Latency", "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1", "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Low_Latency", "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1", - "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_Low_Latency", - "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_2", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_2", - "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", - "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", - "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability", "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability", "SingleDev_OneChanMonoSrc_48_4_Balanced_Reliability", @@ -153,14 +153,15 @@ { "name": "Game", "configurations": [ + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", - "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", - "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", @@ -168,12 +169,13 @@ "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1", "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1", "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", - "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", "DualDev_OneChanStereoSnk_48_2_Low_Latency", "DualDev_OneChanStereoSnk_48_3_Low_Latency", "DualDev_OneChanStereoSnk_48_1_Low_Latency", @@ -206,32 +208,32 @@ { "name": "VoiceAssistants", "configurations": [ + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1", - "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", - "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability", "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1", - "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", - "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2_Balanced_Reliability", "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2_Balanced_Reliability", "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2_Balanced_Reliability", @@ -260,32 +262,38 @@ "configurations": [ "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1", "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", + "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency", "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1", - "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency", - "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1", "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability", "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", + "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency", "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1", - "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency", - "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency", + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", + "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency", "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency", - "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1", "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability", "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability", "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability", diff --git a/system/bta/le_audio/broadcaster/broadcaster.cc b/system/bta/le_audio/broadcaster/broadcaster.cc index d5d8ec81f7d8db274a8d6828a37f8b5e73398b8f..ec295fd240b602eb13cdeee35b9e3a1793e5bf71 100644 --- a/system/bta/le_audio/broadcaster/broadcaster.cc +++ b/system/bta/le_audio/broadcaster/broadcaster.cc @@ -16,22 +16,24 @@ */ #include +#include +#include #include -#include "bta/include/bta_le_audio_api.h" #include "bta/include/bta_le_audio_broadcaster_api.h" #include "bta/le_audio/broadcaster/state_machine.h" +#include "bta/le_audio/codec_interface.h" #include "bta/le_audio/content_control_id_keeper.h" #include "bta/le_audio/le_audio_types.h" #include "bta/le_audio/le_audio_utils.h" #include "bta/le_audio/metrics_collector.h" +#include "common/strings.h" #include "device/include/controller.h" -#include "embdrv/lc3/include/lc3.h" -#include "gd/common/strings.h" #include "internal_include/stack_config.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/properties.h" +#include "stack/include/bt_types.h" #include "stack/include/btm_api_types.h" #include "stack/include/btm_iso_api.h" @@ -46,6 +48,7 @@ using bluetooth::le_audio::BroadcastId; using bluetooth::le_audio::PublicBroadcastAnnouncementData; using le_audio::CodecManager; using le_audio::ContentControlIdKeeper; +using le_audio::DsaMode; using le_audio::LeAudioCodecConfiguration; using le_audio::LeAudioSourceAudioHalClient; using le_audio::broadcaster::BigConfig; @@ -59,7 +62,7 @@ using le_audio::types::CodecLocation; using le_audio::types::kLeAudioCodingFormatLC3; using le_audio::types::LeAudioContextType; using le_audio::types::LeAudioLtvMap; -using le_audio::utils::GetAllowedAudioContextsFromSourceMetadata; +using le_audio::utils::GetAudioContextsFromSourceMetadata; namespace { class LeAudioBroadcasterImpl; @@ -91,7 +94,8 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { LOG_INFO(); /* Register State machine callbacks */ - BroadcastStateMachine::Initialize(&state_machine_callbacks_); + BroadcastStateMachine::Initialize(&state_machine_callbacks_, + &state_machine_adv_callbacks_); GenerateBroadcastIds(); } @@ -153,7 +157,7 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { BasicAudioAnnouncementData announcement; /* Prepare the announcement */ - announcement.presentation_delay = 0x004E20; /* TODO: Use the proper value */ + announcement.presentation_delay_us = 40000; /* us */ auto const& codec_id = codec_config.GetLeAudioCodecId(); @@ -370,6 +374,18 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { LeAudioLtvMap public_ltv; std::vector subgroup_ltvs; + if (queued_broadcast_.IsQueuedBroadcast()) { + LOG_ERROR("Not processed yet queued broadcast"); + return; + } + + if (!queued_broadcast_.CanCreateBroadcast()) { + queued_broadcast_.SetQueuedBroadcast(is_public, broadcast_name, + broadcast_code, public_metadata, + subgroup_quality, subgroup_metadata); + return; + } + if (is_public) { // Prepare public broadcast announcement format bool is_metadata_valid; @@ -476,14 +492,14 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { .sample_rate = offload_config->sampling_rate, .bits_per_sample = offload_config->bits_per_sample, .data_interval_us = offload_config->frame_duration}, - offload_config->codec_bitrate, offload_config->octets_per_frame); + offload_config->octets_per_frame); BroadcastQosConfig qos_config(offload_config->retransmission_number, offload_config->max_transport_latency); BroadcastStateMachineConfig msg = { .is_public = is_public, - .broadcast_name = broadcast_name, .broadcast_id = broadcast_id, + .broadcast_name = broadcast_name, .streaming_phy = GetStreamingPhy(), .codec_wrapper = codec_config, .qos_config = qos_config, @@ -500,8 +516,8 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { le_audio::broadcaster::getStreamConfigForContext(context_type); BroadcastStateMachineConfig msg = { .is_public = is_public, - .broadcast_name = broadcast_name, .broadcast_id = broadcast_id, + .broadcast_name = broadcast_name, .streaming_phy = GetStreamingPhy(), .codec_wrapper = codec_qos_pair.first, .qos_config = codec_qos_pair.second, @@ -728,6 +744,18 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { } } + void IsoTrafficEventCb(bool is_active) { + if (is_active) { + queued_broadcast_.SetIsoTrafficFlag(); + } else { + queued_broadcast_.ResetIsoTrafficFlag(); + + if (!queued_broadcast_.IsQueuedBroadcast()) return; + + queued_broadcast_.CreateAudioBroadcast(); + } + } + void Dump(int fd) { std::stringstream stream; @@ -851,6 +879,93 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { } } state_machine_callbacks_; + static class BroadcastAdvertisingCallbacks : public AdvertisingCallbacks { + void OnAdvertisingSetStarted(int reg_id, uint8_t advertiser_id, + int8_t tx_power, uint8_t status) { + if (!instance) return; + + if (reg_id == BroadcastStateMachine::kLeAudioBroadcastRegId && + !instance->pending_broadcasts_.empty()) { + instance->pending_broadcasts_.back()->OnCreateAnnouncement( + advertiser_id, tx_power, status); + } else { + LOG_WARN( + "Ignored OnAdvertisingSetStarted callback reg_id:%d " + "advertiser_id:%d", + reg_id, advertiser_id); + } + } + + void OnAdvertisingEnabled(uint8_t advertiser_id, bool enable, + uint8_t status) { + if (!instance) return; + + auto const& iter = std::find_if( + instance->broadcasts_.cbegin(), instance->broadcasts_.cend(), + [advertiser_id](auto const& sm) { + return sm.second->GetAdvertisingSid() == advertiser_id; + }); + if (iter != instance->broadcasts_.cend()) { + iter->second->OnEnableAnnouncement(enable, status); + } else { + LOG_WARN("Ignored OnAdvertisingEnabled callback advertiser_id:%d", + advertiser_id); + } + } + + void OnAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) { + LOG_WARN( + "Not being used, ignored OnAdvertisingDataSet callback " + "advertiser_id:%d", + advertiser_id); + } + + void OnScanResponseDataSet(uint8_t advertiser_id, uint8_t status) { + LOG_WARN( + "Not being used, ignored OnScanResponseDataSet callback " + "advertiser_id:%d", + advertiser_id); + } + + void OnAdvertisingParametersUpdated(uint8_t advertiser_id, int8_t tx_power, + uint8_t status) { + LOG_WARN( + "Not being used, ignored OnAdvertisingParametersUpdated callback " + "advertiser_id:%d", + advertiser_id); + } + + void OnPeriodicAdvertisingParametersUpdated(uint8_t advertiser_id, + uint8_t status) { + LOG_WARN( + "Not being used, ignored OnPeriodicAdvertisingParametersUpdated " + "callback advertiser_id:%d", + advertiser_id); + } + + void OnPeriodicAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) { + LOG_WARN( + "Not being used, ignored OnPeriodicAdvertisingDataSet callback " + "advertiser_id:%d", + advertiser_id); + } + + void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool enable, + uint8_t status) { + LOG_WARN( + "Not being used, ignored OnPeriodicAdvertisingEnabled callback " + "advertiser_id:%d", + advertiser_id); + } + + void OnOwnAddressRead(uint8_t advertiser_id, uint8_t address_type, + RawAddress address) { + LOG_WARN( + "Not being used, ignored OnOwnAddressRead callback advertiser_id:%d", + advertiser_id); + } + } state_machine_adv_callbacks_; + static class LeAudioSourceCallbacksImpl : public LeAudioSourceAudioHalClient::Callbacks { public: @@ -861,31 +976,21 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { void CheckAndReconfigureEncoders() { auto const& codec_id = codec_wrapper_.GetLeAudioCodecId(); - if (codec_id.coding_format != kLeAudioCodingFormatLC3) { - LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id.coding_format, - codec_id.vendor_company_id, codec_id.vendor_codec_id); - return; - } - - if (enc_audio_buffers_.size() != codec_wrapper_.GetNumChannels()) { - enc_audio_buffers_.resize(codec_wrapper_.GetNumChannels()); - } - - const int dt_us = codec_wrapper_.GetDataIntervalUs(); - const int sr_hz = codec_wrapper_.GetSampleRate(); - const auto encoder_bytes = lc3_encoder_size(dt_us, sr_hz); - const auto channel_bytes = codec_wrapper_.GetMaxSduSizePerChannel(); - /* TODO: We should act smart and reuse current configurations */ - encoders_.clear(); - encoders_mem_.clear(); - while (encoders_.size() < codec_wrapper_.GetNumChannels()) { - auto& encoder_buf = enc_audio_buffers_.at(encoders_.size()); - encoder_buf.resize(channel_bytes); - - encoders_mem_.emplace_back(malloc(encoder_bytes), &std::free); - encoders_.emplace_back( - lc3_setup_encoder(dt_us, sr_hz, 0, encoders_mem_.back().get())); + sw_enc_.clear(); + while (sw_enc_.size() != codec_wrapper_.GetNumChannels()) { + auto codec = le_audio::CodecInterface::CreateInstance(codec_id); + + auto codec_status = + codec->InitEncoder(codec_wrapper_.GetLeAudioCodecConfiguration(), + codec_wrapper_.GetLeAudioCodecConfiguration()); + if (codec_status != le_audio::CodecInterface::Status::STATUS_OK) { + LOG_ERROR("Channel %d codec setup failed with err: %d", + (uint32_t)sw_enc_.size(), codec_status); + return; + } + + sw_enc_.emplace_back(std::move(codec)); } } @@ -897,23 +1002,9 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { codec_wrapper_ = config; } - void encodeLc3Channel(lc3_encoder_t encoder, - std::vector& out_buffer, - const std::vector& data, - int initial_channel_offset, int pitch_samples, - int num_channels) { - auto encoder_status = - lc3_encode(encoder, LC3_PCM_FORMAT_S16, - (int16_t*)(data.data() + initial_channel_offset), - pitch_samples, out_buffer.size(), out_buffer.data()); - if (encoder_status != 0) { - LOG_ERROR("Encoding error=%d", encoder_status); - } - } - static void sendBroadcastData( const std::unique_ptr& broadcast, - std::vector>& encoded_channels) { + std::vector>& encoders) { auto const& config = broadcast->GetBigConfig(); if (config == std::nullopt) { LOG_ERROR( @@ -924,15 +1015,16 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { return; } - if (config->connection_handles.size() < encoded_channels.size()) { + if (config->connection_handles.size() < encoders.size()) { LOG_ERROR("Not enough BIS'es to broadcast all channels!"); return; } - for (uint8_t chan = 0; chan < encoded_channels.size(); ++chan) { - IsoManager::GetInstance()->SendIsoData(config->connection_handles[chan], - encoded_channels[chan].data(), - encoded_channels[chan].size()); + for (uint8_t chan = 0; chan < encoders.size(); ++chan) { + IsoManager::GetInstance()->SendIsoData( + config->connection_handles[chan], + (const uint8_t*)encoders[chan]->GetDecodedSamples().data(), + encoders[chan]->GetDecodedSamples().size() * 2); } } @@ -947,9 +1039,10 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { /* Prepare encoded data for all channels */ for (uint8_t chan = 0; chan < num_channels; ++chan) { - /* TODO: Use encoder agnostic wrapper */ - encodeLc3Channel(encoders_[chan], enc_audio_buffers_[chan], data, - chan * bytes_per_sample, num_channels, num_channels); + auto initial_channel_offset = chan * bytes_per_sample; + sw_enc_[chan]->Encode(data.data() + initial_channel_offset, + num_channels, + codec_wrapper_.GetOctetsPerCodecFrame()); } /* Currently there is no way to broadcast multiple distinct streams. @@ -961,16 +1054,14 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { if ((broadcast->GetState() == BroadcastStateMachine::State::STREAMING) && !broadcast->IsMuted()) - sendBroadcastData(broadcast, enc_audio_buffers_); + sendBroadcastData(broadcast, sw_enc_); } LOG_VERBOSE("All data sent."); } - virtual void OnAudioSuspend( - std::promise do_suspend_promise) override { + virtual void OnAudioSuspend(void) override { LOG_INFO(); /* TODO: Should we suspend all broadcasts - remove BIGs? */ - do_suspend_promise.set_value(); if (instance) instance->audio_data_path_state_ = AudioDataPathState::SUSPENDED; } @@ -990,15 +1081,13 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { instance->le_audio_source_hal_client_->ConfirmStreamingRequest(); } - virtual void OnAudioMetadataUpdate( - std::vector source_metadata) override { + virtual void OnAudioMetadataUpdate(source_metadata_v7 source_metadata, + DsaMode dsa_mode) override { LOG_INFO(); if (!instance) return; /* TODO: Should we take supported contexts from ASCS? */ - auto supported_context_types = le_audio::types::kLeAudioContextAllTypes; - auto contexts = GetAllowedAudioContextsFromSourceMetadata( - source_metadata, supported_context_types); + auto contexts = GetAudioContextsFromSourceMetadata(source_metadata); if (contexts.any()) { /* NOTICE: We probably don't want to change the stream configuration * on each metadata change, so just update the context type metadata. @@ -1012,11 +1101,84 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { private: BroadcastCodecWrapper codec_wrapper_; - std::vector encoders_; - std::vector> encoders_mem_; - std::vector> enc_audio_buffers_; + std::vector> sw_enc_; } audio_receiver_; + static class QueuedBroadcast { + public: + bool IsQueuedBroadcast() { + LOG_INFO(""); + + return is_queued_; + } + + void SetQueuedBroadcast( + bool is_public, const std::string& broadcast_name, + const std::optional& broadcast_code, + const std::vector& public_metadata, + const std::vector& subgroup_quality, + const std::vector>& subgroup_metadata) { + LOG_INFO(); + + is_public_ = is_public; + broadcast_name_ = broadcast_name; + broadcast_code_ = broadcast_code; + public_metadata_ = public_metadata; + subgroup_quality_ = subgroup_quality; + subgroup_metadata_ = subgroup_metadata; + + is_queued_ = true; + } + + void CreateAudioBroadcast() { + if (!instance || !CanCreateBroadcast()) return; + + LOG_INFO("Create queued broadcast"); + + is_queued_ = false; + + instance->CreateAudioBroadcast(is_public_, broadcast_name_, + broadcast_code_, public_metadata_, + subgroup_quality_, subgroup_metadata_); + } + + void ClearQueuedBroadcast() { + LOG_INFO(); + + is_queued_ = false; + } + + void SetIsoTrafficFlag() { + LOG_INFO(); + + is_iso_running_ = true; + } + + void ResetIsoTrafficFlag() { + LOG_INFO(); + + is_iso_running_ = false; + } + + bool CanCreateBroadcast() { + LOG_INFO("%d", is_iso_running_ == false); + + return is_iso_running_ == false; + } + + private: + /* Queued broadcast data */ + bool is_public_; + std::string broadcast_name_; + std::optional broadcast_code_; + std::vector public_metadata_; + std::vector subgroup_quality_; + std::vector> subgroup_metadata_; + + bool is_iso_running_; + bool is_queued_; + } queued_broadcast_; + bluetooth::le_audio::LeAudioBroadcasterCallbacks* callbacks_; std::map> broadcasts_; std::vector> pending_broadcasts_; @@ -1033,7 +1195,10 @@ LeAudioBroadcasterImpl::BroadcastStateMachineCallbacks LeAudioBroadcasterImpl::state_machine_callbacks_; LeAudioBroadcasterImpl::LeAudioSourceCallbacksImpl LeAudioBroadcasterImpl::audio_receiver_; - +LeAudioBroadcasterImpl::BroadcastAdvertisingCallbacks + LeAudioBroadcasterImpl::state_machine_adv_callbacks_; +LeAudioBroadcasterImpl::QueuedBroadcast + LeAudioBroadcasterImpl::queued_broadcast_; } /* namespace */ void LeAudioBroadcaster::Initialize( @@ -1061,6 +1226,14 @@ void LeAudioBroadcaster::Initialize( instance = new LeAudioBroadcasterImpl(callbacks); /* Register HCI event handlers */ IsoManager::GetInstance()->RegisterBigCallbacks(instance); + /* Register for active traffic */ + IsoManager::GetInstance()->RegisterOnIsoTrafficActiveCallback( + [](bool is_active) { + if (!instance) { + return; + } + instance->IsoTrafficEventCb(is_active); + }); } bool LeAudioBroadcaster::IsLeAudioBroadcasterRunning() { return instance; } diff --git a/system/bta/le_audio/broadcaster/broadcaster_test.cc b/system/bta/le_audio/broadcaster/broadcaster_test.cc index 060583129e59c0ff4f16ae3ae51195da64106f16..1d92c1fc875ab68ddd53a9b9218b9ea253b8034d 100644 --- a/system/bta/le_audio/broadcaster/broadcaster_test.cc +++ b/system/bta/le_audio/broadcaster/broadcaster_test.cc @@ -50,6 +50,7 @@ using testing::Test; using namespace bluetooth::le_audio; +using le_audio::DsaMode; using le_audio::LeAudioCodecConfiguration; using le_audio::LeAudioSourceAudioHalClient; using le_audio::broadcaster::BigConfig; @@ -118,6 +119,7 @@ namespace le_audio { class MockAudioHalClientEndpoint; MockAudioHalClientEndpoint* mock_audio_source_; bool is_audio_hal_acquired; +void (*iso_active_callback)(bool); std::unique_ptr LeAudioSourceAudioHalClient::AcquireBroadcast() { @@ -179,7 +181,8 @@ class MockAudioHalClientEndpoint : public LeAudioSourceAudioHalClient { MockAudioHalClientEndpoint() = default; MOCK_METHOD((bool), Start, (const LeAudioCodecConfiguration& codecConfiguration, - LeAudioSourceAudioHalClient::Callbacks* audioReceiver), + LeAudioSourceAudioHalClient::Callbacks* audioReceiver, + ::le_audio::DsaModes dsa_modes), (override)); MOCK_METHOD((void), Stop, (), (override)); MOCK_METHOD((void), ConfirmStreamingRequest, (), (override)); @@ -218,6 +221,10 @@ class BroadcasterTest : public Test { is_audio_hal_acquired = false; }); + EXPECT_CALL(*MockIsoManager::GetInstance(), + RegisterOnIsoTrafficActiveCallbacks) + .WillOnce(SaveArg<0>(&iso_active_callback)); + ASSERT_FALSE(LeAudioBroadcaster::IsLeAudioBroadcasterRunning()); LeAudioBroadcaster::Initialize(&mock_broadcaster_callbacks_, base::Bind([]() -> bool { return true; })); @@ -243,6 +250,9 @@ class BroadcasterTest : public Test { LeAudioBroadcaster::Cleanup(); ASSERT_FALSE(LeAudioBroadcaster::IsLeAudioBroadcasterRunning()); + ContentControlIdKeeper::GetInstance()->Stop(); + + iso_active_callback = nullptr; iso_manager_->Stop(); controller::SetMockControllerInterface(nullptr); @@ -251,10 +261,12 @@ class BroadcasterTest : public Test { uint32_t InstantiateBroadcast( std::vector metadata = default_metadata, BroadcastCode code = default_code, - uint8_t num_of_groups = default_num_of_groups) { + uint8_t num_of_groups = default_num_of_groups, bool is_queued = false) { uint32_t broadcast_id = LeAudioBroadcaster::kInstanceIdUndefined; - EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true)) - .WillOnce(SaveArg<0>(&broadcast_id)); + if (!is_queued) { + EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true)) + .WillOnce(SaveArg<0>(&broadcast_id)); + } std::vector quality_array; std::vector> metadata_array; @@ -502,7 +514,7 @@ static BasicAudioAnnouncementData prepareAnnouncement( std::map> metadata) { BasicAudioAnnouncementData announcement; - announcement.presentation_delay = 0x004E20; + announcement.presentation_delay_us = 40000; auto const& codec_id = codec_config.GetLeAudioCodecId(); announcement.subgroup_configs = {{ @@ -569,7 +581,7 @@ TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) { .sample_rate = LeAudioCodecConfiguration::kSampleRate16000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, - 32000, 40); + 40); auto announcement = prepareAnnouncement(codec_config, meta); ON_CALL(*sm, GetBroadcastAnnouncement()) @@ -582,7 +594,25 @@ TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) { 0}, {AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}}}; - audio_receiver->OnAudioMetadataUpdate(multitrack_source_metadata); + std::vector tracks_vec; + tracks_vec.reserve(multitrack_source_metadata.size()); + for (const auto& track : multitrack_source_metadata) { + playback_track_metadata_v7 desc_track = { + .base = + { + .usage = static_cast(track.usage), + .content_type = + static_cast(track.content_type), + .gain = track.gain, + }, + }; + tracks_vec.push_back(desc_track); + } + + const source_metadata_v7_t source_metadata = { + .track_count = tracks_vec.size(), .tracks = tracks_vec.data()}; + + audio_receiver->OnAudioMetadataUpdate(source_metadata, DsaMode::DISABLED); // Verify ccid ASSERT_NE(ccid_list.size(), 0u); @@ -617,7 +647,7 @@ TEST_F(BroadcasterTest, GetMetadata) { .sample_rate = LeAudioCodecConfiguration::kSampleRate16000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, - 32000, 40); + 40); auto announcement = prepareAnnouncement(codec_config, meta); bool is_public_metadata_valid; @@ -706,4 +736,41 @@ TEST_F(BroadcasterTest, StreamParamsMedia) { // Note: Num of bises at IsoManager level is verified by state machine tests } +TEST_F(BroadcasterTest, QueuedBroadcast) { + uint32_t broadcast_id = LeAudioBroadcaster::kInstanceIdUndefined; + + iso_active_callback(true); + + EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true)) + .WillOnce(SaveArg<0>(&broadcast_id)); + + /* Trigger broadcast create but due to active ISO, queue request */ + InstantiateBroadcast(default_metadata, default_code, default_num_of_groups, + true); + + /* Notify about ISO being free, check if broadcast would be created */ + iso_active_callback(false); + ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined); + ASSERT_EQ(broadcast_id, + MockBroadcastStateMachine::GetLastInstance()->GetBroadcastId()); + + auto& instance_config = MockBroadcastStateMachine::GetLastInstance()->cfg; + ASSERT_EQ(instance_config.broadcast_code, default_code); + for (auto& subgroup : instance_config.announcement.subgroup_configs) { + ASSERT_EQ(types::LeAudioLtvMap(subgroup.metadata).RawPacket(), + default_metadata); + } +} + +TEST_F(BroadcasterTest, QueuedBroadcastBusyIso) { + iso_active_callback(true); + + EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true)) + .Times(0); + + /* Trigger broadcast create but due to active ISO, queue request */ + InstantiateBroadcast(default_metadata, default_code, default_num_of_groups, + true); +} + } // namespace le_audio diff --git a/system/bta/le_audio/broadcaster/broadcaster_types.cc b/system/bta/le_audio/broadcaster/broadcaster_types.cc index e2a5dc8ca45bdd220c03425915e079cb56cae7d2..297f9ede49ab9046f32c36eedd3e3daae1a2796c 100644 --- a/system/bta/le_audio/broadcaster/broadcaster_types.cc +++ b/system/bta/le_audio/broadcaster/broadcaster_types.cc @@ -17,14 +17,15 @@ #include "broadcaster_types.h" +#include + #include -#include "bt_types.h" #include "bta_le_audio_broadcaster_api.h" #include "btm_ble_api_types.h" -#include "embdrv/lc3/include/lc3.h" #include "internal_include/stack_config.h" #include "osi/include/properties.h" +#include "stack/include/bt_types.h" using bluetooth::le_audio::BasicAudioAnnouncementBisConfig; using bluetooth::le_audio::BasicAudioAnnouncementCodecConfig; @@ -43,7 +44,7 @@ static void EmitHeader(const BasicAudioAnnouncementData& announcement_data, // Set the cursor behind the old data uint8_t* p_value = data.data() + old_size; - UINT24_TO_STREAM(p_value, announcement_data.presentation_delay); + UINT24_TO_STREAM(p_value, announcement_data.presentation_delay_us); } static void EmitCodecConfiguration( @@ -237,8 +238,6 @@ static const BroadcastCodecWrapper lc3_mono_16_2 = BroadcastCodecWrapper( .sample_rate = LeAudioCodecConfiguration::kSampleRate16000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, - // Bitrate - 32000, // Frame len. 40); @@ -249,8 +248,6 @@ static const BroadcastCodecWrapper lc3_stereo_16_2 = BroadcastCodecWrapper( .sample_rate = LeAudioCodecConfiguration::kSampleRate16000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, - // Bitrate - 32000, // Frame len. 40); @@ -261,8 +258,6 @@ static const BroadcastCodecWrapper lc3_stereo_24_2 = BroadcastCodecWrapper( .sample_rate = LeAudioCodecConfiguration::kSampleRate24000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, - // Bitrate - 48000, // Frame len. 60); @@ -273,8 +268,6 @@ static const BroadcastCodecWrapper lc3_stereo_48_1 = BroadcastCodecWrapper( .sample_rate = LeAudioCodecConfiguration::kSampleRate48000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval7500Us}, - // Bitrate - 80000, // Frame len. 75); @@ -285,8 +278,6 @@ static const BroadcastCodecWrapper lc3_stereo_48_2 = BroadcastCodecWrapper( .sample_rate = LeAudioCodecConfiguration::kSampleRate48000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, - // Bitrate - 80000, // Frame len. 100); @@ -297,8 +288,6 @@ static const BroadcastCodecWrapper lc3_stereo_48_3 = BroadcastCodecWrapper( .sample_rate = LeAudioCodecConfiguration::kSampleRate48000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval7500Us}, - // Bitrate - 96000, // Frame len. 90); @@ -309,8 +298,6 @@ static const BroadcastCodecWrapper lc3_stereo_48_4 = BroadcastCodecWrapper( .sample_rate = LeAudioCodecConfiguration::kSampleRate48000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, - // Bitrate - 96000, // Frame len. 120); @@ -331,9 +318,9 @@ const std::map sample_rate_to_sampling_freq_map = { const std::map data_interval_ms_to_frame_duration = { {LeAudioCodecConfiguration::kInterval7500Us, - codec_spec_conf::kLeAudioCodecLC3FrameDur7500us}, + codec_spec_conf::kLeAudioCodecFrameDur7500us}, {LeAudioCodecConfiguration::kInterval10000Us, - codec_spec_conf::kLeAudioCodecLC3FrameDur10000us}, + codec_spec_conf::kLeAudioCodecFrameDur10000us}, }; types::LeAudioLtvMap BroadcastCodecWrapper::GetBisCodecSpecData( @@ -344,11 +331,11 @@ types::LeAudioLtvMap BroadcastCodecWrapper::GetBisCodecSpecData( switch (bis_idx) { case 1: return types::LeAudioLtvMap( - {{codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation, + {{codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation, UINT32_TO_VEC_UINT8(codec_spec_conf::kLeAudioLocationFrontLeft)}}); case 2: return types::LeAudioLtvMap( - {{codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation, + {{codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation, UINT32_TO_VEC_UINT8(codec_spec_conf::kLeAudioLocationFrontRight)}}); break; default: @@ -365,25 +352,22 @@ types::LeAudioLtvMap BroadcastCodecWrapper::GetSubgroupCodecSpecData() const { << "Invalid data_interval"; std::map> codec_spec_ltvs = { - {codec_spec_conf::kLeAudioCodecLC3TypeSamplingFreq, + {codec_spec_conf::kLeAudioLtvTypeSamplingFreq, UINT8_TO_VEC_UINT8(sample_rate_to_sampling_freq_map.at( source_codec_config.sample_rate))}, - {codec_spec_conf::kLeAudioCodecLC3TypeFrameDuration, + {codec_spec_conf::kLeAudioLtvTypeFrameDuration, UINT8_TO_VEC_UINT8(data_interval_ms_to_frame_duration.at( source_codec_config.data_interval_us))}, }; if (codec_id.coding_format == kLeAudioCodecIdLc3.coding_format) { - uint16_t bc = - lc3_frame_bytes(source_codec_config.data_interval_us, codec_bitrate); - codec_spec_ltvs[codec_spec_conf::kLeAudioCodecLC3TypeOctetPerFrame] = - UINT16_TO_VEC_UINT8(bc); + codec_spec_ltvs[codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame] = + UINT16_TO_VEC_UINT8(octets_per_codec_frame); } if (source_codec_config.num_channels == 1) { - codec_spec_ltvs - [codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation] = - UINT32_TO_VEC_UINT8(codec_spec_conf::kLeAudioLocationFrontCenter); + codec_spec_ltvs[codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation] = + UINT32_TO_VEC_UINT8(codec_spec_conf::kLeAudioLocationFrontCenter); } return types::LeAudioLtvMap(codec_spec_ltvs); @@ -402,7 +386,6 @@ std::ostream& operator<<( << ", SampleRate=" << +config.GetSampleRate() << ", BitsPerSample=" << +config.GetBitsPerSample() << ", DataIntervalUs=" << +config.GetDataIntervalUs() << "}"; - os << ", Bitrate=" << +config.GetBitrate(); os << "]"; return os; } @@ -504,7 +487,7 @@ static bool isMetadataSame(std::map> m1, bool operator==(const BasicAudioAnnouncementData& lhs, const BasicAudioAnnouncementData& rhs) { - if (lhs.presentation_delay != rhs.presentation_delay) return false; + if (lhs.presentation_delay_us != rhs.presentation_delay_us) return false; if (lhs.subgroup_configs.size() != rhs.subgroup_configs.size()) return false; diff --git a/system/bta/le_audio/broadcaster/broadcaster_types.h b/system/bta/le_audio/broadcaster/broadcaster_types.h index 392c77d11fe34e228958c094a9b4f72c9c1c8a24..06d44b114b06ec5751161833e9337ea549416a19 100644 --- a/system/bta/le_audio/broadcaster/broadcaster_types.h +++ b/system/bta/le_audio/broadcaster/broadcaster_types.h @@ -17,6 +17,8 @@ #pragma once +#include + #include #include "bta/le_audio/audio_hal_client/audio_hal_client.h" @@ -52,12 +54,11 @@ void PreparePeriodicData( struct BroadcastCodecWrapper { BroadcastCodecWrapper(types::LeAudioCodecId codec_id, LeAudioCodecConfiguration source_codec_config, - uint32_t codec_bitrate, uint32_t codec_frame_len, + uint32_t octets_per_codec_frame, uint8_t blocks_per_sdu = 1) : codec_id(codec_id), source_codec_config(source_codec_config), - codec_bitrate(codec_bitrate), - codec_frame_len(codec_frame_len), + octets_per_codec_frame(octets_per_codec_frame), blocks_per_sdu(blocks_per_sdu) { if (codec_id.coding_format != types::kLeAudioCodingFormatLC3) LOG(ERROR) << "Unsupported coding format!"; @@ -70,8 +71,7 @@ struct BroadcastCodecWrapper { BroadcastCodecWrapper& operator=(const BroadcastCodecWrapper& other) { codec_id = other.codec_id; source_codec_config = other.source_codec_config; - codec_bitrate = other.codec_bitrate; - codec_frame_len = other.codec_frame_len; + octets_per_codec_frame = other.octets_per_codec_frame; blocks_per_sdu = other.blocks_per_sdu; return *this; }; @@ -81,7 +81,7 @@ struct BroadcastCodecWrapper { uint16_t GetMaxSduSizePerChannel() const { if (codec_id.coding_format == types::kLeAudioCodingFormatLC3) { - return GetFrameLen() * blocks_per_sdu; + return GetOctetsPerCodecFrame() * blocks_per_sdu; } LOG(ERROR) << "Invalid codec ID: " @@ -103,9 +103,7 @@ struct BroadcastCodecWrapper { uint8_t GetNumChannels() const { return source_codec_config.num_channels; } - uint32_t GetBitrate() const { return codec_bitrate; } - - uint32_t GetFrameLen() const { return codec_frame_len; } + uint32_t GetOctetsPerCodecFrame() const { return octets_per_codec_frame; } uint8_t GetBitsPerSample() const { return source_codec_config.bits_per_sample; @@ -125,8 +123,7 @@ struct BroadcastCodecWrapper { private: types::LeAudioCodecId codec_id; LeAudioCodecConfiguration source_codec_config; - uint32_t codec_bitrate; - uint32_t codec_frame_len; + uint32_t octets_per_codec_frame; uint8_t blocks_per_sdu; }; diff --git a/system/bta/le_audio/broadcaster/mock_ble_advertising_manager.cc b/system/bta/le_audio/broadcaster/mock_ble_advertising_manager.cc index 0bf07adce4ece228104b82c70581d883eb41ef2c..baeecc23c6f47a15fce90adb51eff588f995389c 100644 --- a/system/bta/le_audio/broadcaster/mock_ble_advertising_manager.cc +++ b/system/bta/le_audio/broadcaster/mock_ble_advertising_manager.cc @@ -19,28 +19,27 @@ #include -#include "ble_advertiser_hci_interface.h" +#include "main/shim/le_advertising_manager.h" namespace { -BleAdvertisingManager* instance; -base::WeakPtr instance_weakptr; +MockBleAdvertisingManager* bt_le_advertiser_instance; } // namespace -void BleAdvertisingManager::Initialize(BleAdvertiserHciInterface* interface) { - MockBleAdvertisingManager* manager = new MockBleAdvertisingManager(); - manager->SetBleAdvertiserHciInterfaceForTesting(interface); - - instance = manager; - instance_weakptr = ((MockBleAdvertisingManager*)instance)->GetWeakPtr(); +void MockBleAdvertisingManager::Initialize() { + if (bt_le_advertiser_instance == nullptr) { + bt_le_advertiser_instance = new MockBleAdvertisingManager(); + } } -void BleAdvertisingManager::CleanUp() { - delete instance; - instance = nullptr; +void MockBleAdvertisingManager::CleanUp() { + delete bt_le_advertiser_instance; + bt_le_advertiser_instance = nullptr; } -bool BleAdvertisingManager::IsInitialized() { return instance; } +MockBleAdvertisingManager* MockBleAdvertisingManager::Get() { + return bt_le_advertiser_instance; +} -base::WeakPtr BleAdvertisingManager::Get() { - return instance_weakptr; +BleAdvertiserInterface* bluetooth::shim::get_ble_advertiser_instance() { + return static_cast(bt_le_advertiser_instance); } diff --git a/system/bta/le_audio/broadcaster/mock_ble_advertising_manager.h b/system/bta/le_audio/broadcaster/mock_ble_advertising_manager.h index 0dfae21207757358b78048f21c703f0cc532b4e5..9b555ece5ad2e11b74ae0a586c11112019ac1b83 100644 --- a/system/bta/le_audio/broadcaster/mock_ble_advertising_manager.h +++ b/system/bta/le_audio/broadcaster/mock_ble_advertising_manager.h @@ -22,9 +22,9 @@ #include #include -#include "ble_advertiser.h" +#include "include/hardware/ble_advertiser.h" -class MockBleAdvertisingManager : public BleAdvertisingManager { +class MockBleAdvertisingManager : public BleAdvertiserInterface { public: MockBleAdvertisingManager() = default; MockBleAdvertisingManager(const MockBleAdvertisingManager&) = delete; @@ -33,77 +33,56 @@ class MockBleAdvertisingManager : public BleAdvertisingManager { ~MockBleAdvertisingManager() override = default; - /* Allows getting and setting BleAdvertiserHciInterface dependency */ - BleAdvertiserHciInterface* GetBleAdvertiserHciInterface() { - return ble_adv_hci_interface_; - } - void SetBleAdvertiserHciInterfaceForTesting( - BleAdvertiserHciInterface* interface) { - ble_adv_hci_interface_ = interface; - } - - base::WeakPtr GetWeakPtr() { - return weak_factory_.GetWeakPtr(); - } + static void Initialize(); + static void CleanUp(); + static MockBleAdvertisingManager* Get(); MOCK_METHOD((void), StartAdvertising, - (uint8_t advertiser_id, MultiAdvCb cb, - tBTM_BLE_ADV_PARAMS* params, std::vector advertise_data, - std::vector scan_response_data, int duration, - MultiAdvCb timeout_cb), + (uint8_t advertiser_id, StatusCallback cb, + AdvertiseParameters params, std::vector advertise_data, + std::vector scan_response_data, int timeout_s, + StatusCallback timeout_cb), (override)); MOCK_METHOD((void), StartAdvertisingSet, - (base::Callback - cb, - tBTM_BLE_ADV_PARAMS* params, std::vector advertise_data, + (uint8_t client_id, int reg_id, + IdTxPowerStatusCallback register_cb, AdvertiseParameters params, + std::vector advertise_data, std::vector scan_response_data, - tBLE_PERIODIC_ADV_PARAMS* periodic_params, + PeriodicAdvertisingParameters periodic_params, std::vector periodic_data, uint16_t duration, - uint8_t maxExtAdvEvents, - base::Callback - timeout_cb), - (override)); - MOCK_METHOD((void), RegisterAdvertiser, - (base::Callback), + uint8_t maxExtAdvEvents, IdStatusCallback timeout_cb), (override)); + MOCK_METHOD((void), RegisterAdvertiser, (IdStatusCallback cb), (override)); MOCK_METHOD((void), Enable, - (uint8_t inst_id, bool enable, MultiAdvCb cb, uint16_t duration, - uint8_t maxExtAdvEvents, MultiAdvCb timeout_cb), + (uint8_t advertiser_id, bool enable, StatusCallback cb, + uint16_t duration, uint8_t maxExtAdvEvents, + StatusCallback timeout_cb), (override)); MOCK_METHOD((void), SetParameters, - (uint8_t inst_id, tBTM_BLE_ADV_PARAMS* p_params, ParametersCb cb), + (uint8_t advertiser_id, AdvertiseParameters params, + ParametersCallback cb), (override)); MOCK_METHOD((void), SetData, - (uint8_t inst_id, bool is_scan_rsp, std::vector data, - MultiAdvCb cb), + (int advertiser_id, bool set_scan_rsp, std::vector data, + StatusCallback cb), (override)); MOCK_METHOD((void), SetPeriodicAdvertisingParameters, - (uint8_t inst_id, tBLE_PERIODIC_ADV_PARAMS* params, - MultiAdvCb cb), + (int advertiser_id, PeriodicAdvertisingParameters periodic_params, + StatusCallback cb), (override)); MOCK_METHOD((void), SetPeriodicAdvertisingData, - (uint8_t inst_id, std::vector data, MultiAdvCb cb), + (int advertiser_id, std::vector data, StatusCallback cb), (override)); MOCK_METHOD((void), SetPeriodicAdvertisingEnable, - (uint8_t inst_id, bool enable, bool include_adi, MultiAdvCb cb), + (int advertiser_id, bool enable, bool include_adi, + StatusCallback cb), (override)); - MOCK_METHOD((void), Unregister, (uint8_t inst_id), (override)); - MOCK_METHOD((void), Suspend, (), (override)); - MOCK_METHOD((void), Resume, (), (override)); - MOCK_METHOD((void), OnAdvertisingSetTerminated, - (uint8_t status, uint8_t advertising_handle, - uint16_t connection_handle, - uint8_t num_completed_extended_adv_events), + MOCK_METHOD((void), Unregister, (uint8_t advertiser_id), (override)); + MOCK_METHOD((void), GetOwnAddress, + (uint8_t advertiser_id, GetAddressCallback cb), (override)); + MOCK_METHOD((void), RegisterCallbacks, (AdvertisingCallbacks * callbacks), + (override)); + MOCK_METHOD((void), RegisterCallbacksNative, + (AdvertisingCallbacks * callbacks, uint8_t client_id), (override)); - MOCK_METHOD( - (void), GetOwnAddress, - (uint8_t inst_id, - base::Callback - cb), - (override)); - - private: - base::WeakPtrFactory weak_factory_{this}; - BleAdvertiserHciInterface* ble_adv_hci_interface_; }; diff --git a/system/bta/le_audio/broadcaster/mock_state_machine.cc b/system/bta/le_audio/broadcaster/mock_state_machine.cc index 239ca0bb8ef9bb3043780de2a3914307d3aa1ddf..eb9c8e2053129f3d853b673db125eb8436e13cf5 100644 --- a/system/bta/le_audio/broadcaster/mock_state_machine.cc +++ b/system/bta/le_audio/broadcaster/mock_state_machine.cc @@ -20,14 +20,17 @@ using namespace le_audio::broadcaster; IBroadcastStateMachineCallbacks* callbacks; -void BroadcastStateMachine::Initialize(IBroadcastStateMachineCallbacks* cb) { +AdvertisingCallbacks* adv_callbacks; +void BroadcastStateMachine::Initialize(IBroadcastStateMachineCallbacks* cb, + AdvertisingCallbacks* adv_cb) { callbacks = cb; + adv_callbacks = adv_cb; } std::unique_ptr BroadcastStateMachine::CreateInstance( BroadcastStateMachineConfig msg) { - auto instance = - std::make_unique(std::move(msg), callbacks); + auto instance = std::make_unique( + std::move(msg), callbacks, adv_callbacks); MockBroadcastStateMachine::last_instance_ = instance.get(); return std::move(instance); } diff --git a/system/bta/le_audio/broadcaster/mock_state_machine.h b/system/bta/le_audio/broadcaster/mock_state_machine.h index 4d7b26fde2b06c34f46c43b1d5d972cb72859ca8..b62474caa7237d5d6069a94d79a3d343ce1b9241 100644 --- a/system/bta/le_audio/broadcaster/mock_state_machine.h +++ b/system/bta/le_audio/broadcaster/mock_state_machine.h @@ -26,8 +26,9 @@ class MockBroadcastStateMachine public: MockBroadcastStateMachine( le_audio::broadcaster::BroadcastStateMachineConfig cfg, - le_audio::broadcaster::IBroadcastStateMachineCallbacks* cb) - : cfg(cfg), cb(cb) { + le_audio::broadcaster::IBroadcastStateMachineCallbacks* cb, + AdvertisingCallbacks* adv_cb) + : cfg(cfg), cb(cb), adv_cb(adv_cb) { advertising_sid_ = ++instance_counter_; ON_CALL(*this, Initialize).WillByDefault([this]() { @@ -149,11 +150,17 @@ class MockBroadcastStateMachine const void* data), (override)); MOCK_METHOD((uint8_t), GetAdvertisingSid, (), (const override)); + MOCK_METHOD((void), OnCreateAnnouncement, + (uint8_t advertising_sid, int8_t tx_power, uint8_t status), + (override)); + MOCK_METHOD((void), OnEnableAnnouncement, (bool enable, uint8_t status), + (override)); bool result_ = true; std::optional big_config_ = std::nullopt; le_audio::broadcaster::BroadcastStateMachineConfig cfg; le_audio::broadcaster::IBroadcastStateMachineCallbacks* cb; + AdvertisingCallbacks* adv_cb; void SetExpectedState(BroadcastStateMachine::State state) { SetState(state); } void SetExpectedResult(bool result) { result_ = result; } void SetExpectedBigConfig( diff --git a/system/bta/le_audio/broadcaster/state_machine.cc b/system/bta/le_audio/broadcaster/state_machine.cc index 0c95af5cf4e58564860546d5c49c9bb0a4530dd9..64effcbeb4b4ee26e454267f220a0ba14fce79ec 100644 --- a/system/bta/le_audio/broadcaster/state_machine.cc +++ b/system/bta/le_audio/broadcaster/state_machine.cc @@ -17,7 +17,7 @@ #include "bta/le_audio/broadcaster/state_machine.h" -#include +#include #include #include @@ -27,12 +27,11 @@ #include "base/logging.h" #include "bta/le_audio/broadcaster/broadcaster_types.h" #include "bta/le_audio/le_audio_types.h" -#include "gd/common/strings.h" +#include "common/strings.h" +#include "hci/le_advertising_manager.h" #include "osi/include/log.h" #include "osi/include/properties.h" -#include "stack/include/ble_advertiser.h" #include "stack/include/btm_iso_api.h" -#include "stack/include/btu.h" using bluetooth::common::ToString; using bluetooth::hci::IsoManager; @@ -111,15 +110,9 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { base::Unretained(this->callbacks_), broadcast_id)); } - RawAddress GetOwnAddress() override { - LOG_INFO(); - return addr_; - } + RawAddress GetOwnAddress() override { return addr_; } - uint8_t GetOwnAddressType() override { - LOG_INFO(); - return addr_type_; - } + uint8_t GetOwnAddressType() override { return addr_type_; } bluetooth::le_audio::BroadcastId GetBroadcastId() const override { return sm_config_.broadcast_id; @@ -144,6 +137,64 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { return sm_config_.public_announcement; } + void OnCreateAnnouncement(uint8_t advertising_sid, int8_t tx_power, + uint8_t status) { + LOG_INFO("advertising_sid=%d tx_power=%d status=%d", advertising_sid, + tx_power, status); + + /* If this callback gets called the advertising_sid is valid even though the + * status can be other than SUCCESS. + */ + advertising_sid_ = advertising_sid; + + if (status != + bluetooth::hci::AdvertisingCallback::AdvertisingStatus::SUCCESS) { + LOG_ERROR("Creating Announcement failed"); + callbacks_->OnStateMachineCreateStatus(GetBroadcastId(), false); + return; + } + + /* Ext. advertisings are already on */ + SetState(State::CONFIGURED); + + callbacks_->OnStateMachineCreateStatus(GetBroadcastId(), true); + callbacks_->OnStateMachineEvent(GetBroadcastId(), State::CONFIGURED); + + advertiser_if_->GetOwnAddress( + advertising_sid, + base::Bind(&BroadcastStateMachineImpl::OnAddressResponse, + base::Unretained(this))); + } + + void OnEnableAnnouncement(bool enable, uint8_t status) { + LOG_INFO("operation=%s, broadcast_id=%d, status=%d", + (enable ? "enable" : "disable"), GetBroadcastId(), status); + + if (status == + bluetooth::hci::AdvertisingCallback::AdvertisingStatus::SUCCESS) { + /* Periodic is enabled but without BIGInfo. Stream is suspended. */ + if (enable) { + SetState(State::CONFIGURED); + /* Target state is always STREAMING state - start it now. */ + ProcessMessage(Message::START); + } else { + /* User wanted to stop the announcement - report target state reached */ + SetState(State::STOPPED); + callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); + } + } else { + // Handle error case + if (enable) { + /* Error on enabling */ + SetState(State::STOPPED); + } else { + /* Error on disabling */ + SetState(State::CONFIGURED); + } + callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); + } + } + void UpdatePublicBroadcastAnnouncement( uint32_t broadcast_id, const std::string& broadcast_name, const bluetooth::le_audio::PublicBroadcastAnnouncementData& announcement) @@ -185,7 +236,7 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { } static IBroadcastStateMachineCallbacks* callbacks_; - static base::WeakPtr advertiser_if_; + static BleAdvertiserInterface* advertiser_if_; private: std::optional active_config_; @@ -271,40 +322,6 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { addr_type_ = addr_type; } - void CreateAnnouncementCb(uint8_t advertising_sid, int8_t tx_power, - uint8_t status) { - LOG_INFO("advertising_sid=%d tx_power=%d status=%d", advertising_sid, - tx_power, status); - - /* If this callback gets called the advertising_sid is valid even though the - * status can be other than BTM_BLE_MULTI_ADV_SUCCESS. - */ - advertising_sid_ = advertising_sid; - - if (status != BTM_BLE_MULTI_ADV_SUCCESS) { - LOG_ERROR("Creating Announcement failed"); - callbacks_->OnStateMachineCreateStatus(GetBroadcastId(), false); - return; - } - - /* Ext. advertisings are already on */ - SetState(State::CONFIGURED); - - callbacks_->OnStateMachineCreateStatus(GetBroadcastId(), true); - callbacks_->OnStateMachineEvent(GetBroadcastId(), State::CONFIGURED); - - advertiser_if_->GetOwnAddress( - advertising_sid, - base::Bind(&BroadcastStateMachineImpl::OnAddressResponse, - base::Unretained(this))); - } - - void CreateAnnouncementTimeoutCb(uint8_t advertising_sid, uint8_t status) { - LOG_INFO("advertising_sid=%d status=%d", advertising_sid, status); - advertising_sid_ = advertising_sid; - callbacks_->OnStateMachineCreateStatus(GetBroadcastId(), false); - } - void CreateBroadcastAnnouncement( bool is_public, const std::string& broadcast_name, bluetooth::le_audio::BroadcastId& broadcast_id, @@ -316,8 +333,8 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { (is_public ? "public" : "non-public"), broadcast_name.c_str(), public_announcement.features); if (advertiser_if_ != nullptr) { - tBTM_BLE_ADV_PARAMS adv_params; - tBLE_PERIODIC_ADV_PARAMS periodic_params; + AdvertiseParameters adv_params; + PeriodicAdvertisingParameters periodic_params; std::vector adv_data; std::vector periodic_data; @@ -325,80 +342,43 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { public_announcement, adv_data); PreparePeriodicData(announcement, periodic_data); - adv_params.adv_int_min = 0x00A0; /* 160 * 0,625 = 100ms */ - adv_params.adv_int_max = 0x0140; /* 320 * 0,625 = 200ms */ + adv_params.min_interval = 0x00A0; /* 160 * 0,625 = 100ms */ + adv_params.max_interval = 0x0140; /* 320 * 0,625 = 200ms */ adv_params.advertising_event_properties = 0; adv_params.channel_map = kAdvertisingChannelAll; - adv_params.adv_filter_policy = 0; adv_params.tx_power = 8; adv_params.primary_advertising_phy = PHY_LE_1M; adv_params.secondary_advertising_phy = streaming_phy; adv_params.scan_request_notification_enable = 0; - adv_params.own_address_type = BLE_ADDR_RANDOM; + adv_params.own_address_type = kBroadcastAdvertisingType; periodic_params.max_interval = BroadcastStateMachine::kPaIntervalMax; periodic_params.min_interval = BroadcastStateMachine::kPaIntervalMin; periodic_params.periodic_advertising_properties = 0; periodic_params.enable = true; - /* Callback returns the status and handle which we use later in - * CreateBIG command. + /* Status and timeout callbacks are handled by OnAdvertisingSetStarted() + * which returns the status and handle to be used later in CreateBIG + * command. */ advertiser_if_->StartAdvertisingSet( - base::Bind(&BroadcastStateMachineImpl::CreateAnnouncementCb, - base::Unretained(this)), - &adv_params, adv_data, std::vector(), &periodic_params, + kAdvertiserClientIdLeAudio, kLeAudioBroadcastRegId, base::DoNothing(), + adv_params, adv_data, std::vector(), periodic_params, periodic_data, 0 /* duration */, 0 /* maxExtAdvEvents */, - base::Bind(&BroadcastStateMachineImpl::CreateAnnouncementTimeoutCb, - base::Unretained(this))); + base::DoNothing()); } } void DestroyBroadcastAnnouncement() { - if (BleAdvertisingManager::IsInitialized()) - advertiser_if_->Unregister(GetAdvertisingSid()); - } - - void EnableAnnouncementCb(bool enable, uint8_t status) { - LOG_INFO("operation=%s, broadcast_id=%d, status=%d", - (enable ? "enable" : "disable"), GetBroadcastId(), status); - - if (status == BTM_BLE_MULTI_ADV_SUCCESS) { - /* Periodic is enabled but without BIGInfo. Stream is suspended. */ - if (enable) { - SetState(State::CONFIGURED); - /* Target state is always STREAMING state - start it now. */ - ProcessMessage(Message::START); - } else { - /* User wanted to stop the announcement - report target state reached */ - SetState(State::STOPPED); - callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); - } - } - } - - void EnableAnnouncementTimeoutCb(bool enable, uint8_t status) { - LOG_INFO("operation=%s, broadcast_id=%d, status=%d", - (enable ? "enable" : "disable"), GetBroadcastId(), status); - if (enable) { - /* Timeout on enabling */ - SetState(State::STOPPED); - } else { - /* Timeout on disabling */ - SetState(State::CONFIGURED); - } - callbacks_->OnStateMachineEvent(GetBroadcastId(), GetState()); + advertiser_if_->Unregister(GetAdvertisingSid()); } void EnableAnnouncement() { LOG_INFO("broadcast_id=%d", GetBroadcastId()); - advertiser_if_->Enable( - GetAdvertisingSid(), true, - base::Bind(&BroadcastStateMachineImpl::EnableAnnouncementCb, - base::Unretained(this), true), - 0, 0, /* Enable until stopped */ - base::Bind(&BroadcastStateMachineImpl::EnableAnnouncementTimeoutCb, - base::Unretained(this), true)); + // Callback is handled by OnAdvertisingEnabled() which returns the status + advertiser_if_->Enable(GetAdvertisingSid(), true, base::DoNothing(), 0, + 0, /* Enable until stopped */ + base::DoNothing()); } void CreateBig(void) { @@ -425,13 +405,9 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { void DisableAnnouncement(void) { LOG_INFO("broadcast_id=%d", GetBroadcastId()); - advertiser_if_->Enable( - GetAdvertisingSid(), false, - base::Bind(&BroadcastStateMachineImpl::EnableAnnouncementCb, - base::Unretained(this), false), - 0, 0, - base::Bind(&BroadcastStateMachineImpl::EnableAnnouncementTimeoutCb, - base::Unretained(this), false)); + // Callback is handled by OnAdvertisingEnabled() which returns the status + advertiser_if_->Enable(GetAdvertisingSid(), false, base::DoNothing(), 0, 0, + base::DoNothing()); } void TerminateBig() { @@ -632,7 +608,7 @@ class BroadcastStateMachineImpl : public BroadcastStateMachine { IBroadcastStateMachineCallbacks* BroadcastStateMachineImpl::callbacks_ = nullptr; -base::WeakPtr BroadcastStateMachineImpl::advertiser_if_; +BleAdvertiserInterface* BroadcastStateMachineImpl::advertiser_if_ = nullptr; } /* namespace */ std::unique_ptr BroadcastStateMachine::CreateInstance( @@ -641,14 +617,18 @@ std::unique_ptr BroadcastStateMachine::CreateInstance( } void BroadcastStateMachine::Initialize( - IBroadcastStateMachineCallbacks* callbacks) { + IBroadcastStateMachineCallbacks* callbacks, + AdvertisingCallbacks* adv_callbacks) { BroadcastStateMachineImpl::callbacks_ = callbacks; - /* Get BLE advertiser interface */ - if (BleAdvertisingManager::IsInitialized()) { - LOG_INFO("BleAdvertisingManager acquired"); - BroadcastStateMachineImpl::advertiser_if_ = BleAdvertisingManager::Get(); + /* Get gd le advertiser interface */ + BroadcastStateMachineImpl::advertiser_if_ = + bluetooth::shim::get_ble_advertiser_instance(); + if (BroadcastStateMachineImpl::advertiser_if_ != nullptr) { + LOG_INFO("Advertiser_instance acquired"); + BroadcastStateMachineImpl::advertiser_if_->RegisterCallbacksNative( + adv_callbacks, kAdvertiserClientIdLeAudio); } else { - LOG_INFO("Could not acquire BleAdvertisingManager!"); + LOG_ERROR("Could not acquire advertiser_instance!"); BroadcastStateMachineImpl::advertiser_if_ = nullptr; } } diff --git a/system/bta/le_audio/broadcaster/state_machine.h b/system/bta/le_audio/broadcaster/state_machine.h index 2b28f4f0f7c0ef41cad9ba4be59c03e5b10856b9..b3a40ce067d2e3e5c3d161c0f990720957a1d404 100644 --- a/system/bta/le_audio/broadcaster/state_machine.h +++ b/system/bta/le_audio/broadcaster/state_machine.h @@ -25,6 +25,7 @@ #include "base/functional/callback.h" #include "broadcaster_types.h" #include "bta_le_audio_broadcaster_api.h" +#include "main/shim/le_advertising_manager.h" namespace { template @@ -110,8 +111,17 @@ class BroadcastStateMachine : public StateMachine<5> { static constexpr uint8_t kAdvSidUndefined = 0xFF; static constexpr uint8_t kPaIntervalMax = 0xA0; /* 160 * 0.625 = 100ms */ static constexpr uint8_t kPaIntervalMin = 0x50; /* 80 * 0.625 = 50ms */ - - static void Initialize(IBroadcastStateMachineCallbacks*); + // LEA broadcast assigned register id, use positive number 0x1 + // this should not matter since + // le_advertising_manager will maintain the reg_id together with client_id + // and java/jni is using negative number + static constexpr uint8_t kLeAudioBroadcastRegId = 0x1; + // Matching the ADDRESS_TYPE_* enums from Java + // ADDRESS_TYPE_RANDOM_NON_RESOLVABLE = 2 + static constexpr int8_t kBroadcastAdvertisingType = 0x2; + + static void Initialize(IBroadcastStateMachineCallbacks*, + AdvertisingCallbacks* adv_callbacks); static std::unique_ptr CreateInstance( BroadcastStateMachineConfig msg); @@ -165,6 +175,9 @@ class BroadcastStateMachine : public StateMachine<5> { uint32_t broadcast_id, const std::string& broadcast_name, const bluetooth::le_audio::PublicBroadcastAnnouncementData& announcement) = 0; + virtual void OnCreateAnnouncement(uint8_t advertising_sid, int8_t tx_power, + uint8_t status) = 0; + virtual void OnEnableAnnouncement(bool enable, uint8_t status) = 0; void SetMuted(bool muted) { is_muted_ = muted; }; bool IsMuted() const { return is_muted_; }; diff --git a/system/bta/le_audio/broadcaster/state_machine_test.cc b/system/bta/le_audio/broadcaster/state_machine_test.cc index d51efebd0d71a7fba78107c312c00544c05754fa..527c12b35e977d1436aece3d98987407f5117156 100644 --- a/system/bta/le_audio/broadcaster/state_machine_test.cc +++ b/system/bta/le_audio/broadcaster/state_machine_test.cc @@ -21,11 +21,10 @@ #include #include "../le_audio_types.h" -#include "ble_advertiser.h" #include "btm_iso_api.h" #include "mock_ble_advertising_manager.h" #include "mock_iso_manager.h" -#include "stack/include/ble_advertiser.h" +#include "stack/include/btm_ble_api_types.h" #include "state_machine.h" #include "test/common/mock_functions.h" @@ -80,46 +79,86 @@ class MockBroadcastStatMachineCallbacks (override)); }; +class MockBroadcastAdvertisingCallbacks : public AdvertisingCallbacks { + public: + MockBroadcastAdvertisingCallbacks() = default; + MockBroadcastAdvertisingCallbacks(const MockBroadcastAdvertisingCallbacks&) = + delete; + MockBroadcastAdvertisingCallbacks& operator=( + const MockBroadcastAdvertisingCallbacks&) = delete; + + ~MockBroadcastAdvertisingCallbacks() override = default; + + MOCK_METHOD((void), OnAdvertisingSetStarted, + (int reg_id, uint8_t advertiser_id, int8_t tx_power, + uint8_t status), + (override)); + MOCK_METHOD((void), OnAdvertisingEnabled, + (uint8_t advertiser_id, bool enable, uint8_t status), (override)); + MOCK_METHOD((void), OnAdvertisingDataSet, + (uint8_t advertiser_id, uint8_t status), (override)); + MOCK_METHOD((void), OnScanResponseDataSet, + (uint8_t advertiser_id, uint8_t status), (override)); + MOCK_METHOD((void), OnAdvertisingParametersUpdated, + (uint8_t advertiser_id, int8_t tx_power, uint8_t status), + (override)); + MOCK_METHOD((void), OnPeriodicAdvertisingParametersUpdated, + (uint8_t advertiser_id, uint8_t status), (override)); + MOCK_METHOD((void), OnPeriodicAdvertisingDataSet, + (uint8_t advertiser_id, uint8_t status), (override)); + MOCK_METHOD((void), OnPeriodicAdvertisingEnabled, + (uint8_t advertiser_id, bool enable, uint8_t status), (override)); + MOCK_METHOD((void), OnOwnAddressRead, + (uint8_t advertiser_id, uint8_t address_type, RawAddress address), + (override)); +}; + class StateMachineTest : public Test { protected: void SetUp() override { reset_mock_function_count_map(); - BleAdvertisingManager::Initialize(nullptr); + MockBleAdvertisingManager::Initialize(); - ble_advertising_manager_ = BleAdvertisingManager::Get(); - mock_ble_advertising_manager_ = - static_cast(ble_advertising_manager_.get()); + mock_ble_advertising_manager_ = MockBleAdvertisingManager::Get(); sm_callbacks_.reset(new MockBroadcastStatMachineCallbacks()); - BroadcastStateMachine::Initialize(sm_callbacks_.get()); + adv_callbacks_.reset(new MockBroadcastAdvertisingCallbacks()); + BroadcastStateMachine::Initialize(sm_callbacks_.get(), + adv_callbacks_.get()); ON_CALL(*mock_ble_advertising_manager_, StartAdvertisingSet) - .WillByDefault([](base::Callback cb, - tBTM_BLE_ADV_PARAMS* params, - std::vector advertise_data, - std::vector scan_response_data, - tBLE_PERIODIC_ADV_PARAMS* periodic_params, - std::vector periodic_data, uint16_t duration, - uint8_t maxExtAdvEvents, - base::Callback timeout_cb) { - static uint8_t advertiser_id = 1; - uint8_t tx_power = 32; - uint8_t status = 0; - cb.Run(advertiser_id++, tx_power, status); - }); + .WillByDefault( + [this](uint8_t client_id, int reg_id, + BleAdvertiserInterface::IdTxPowerStatusCallback register_cb, + AdvertiseParameters params, + std::vector advertise_data, + std::vector scan_response_data, + PeriodicAdvertisingParameters periodic_params, + std::vector periodic_data, uint16_t duration, + uint8_t maxExtAdvEvents, + BleAdvertiserInterface::IdStatusCallback timeout_cb) { + static uint8_t advertiser_id = 1; + uint8_t tx_power = 32; + uint8_t status = 0; + this->adv_callbacks_->OnAdvertisingSetStarted( + BroadcastStateMachine::kLeAudioBroadcastRegId, + advertiser_id++, tx_power, status); + }); ON_CALL(*mock_ble_advertising_manager_, Enable) .WillByDefault( - [](uint8_t advertiser_id, bool enable, - base::Callback cb, uint16_t duration, - uint8_t maxExtAdvEvents, - base::Callback timeout_cb) { - cb.Run(0); + [this](uint8_t advertiser_id, bool enable, + BleAdvertiserInterface::StatusCallback cb, uint16_t duration, + uint8_t maxExtAdvEvents, + BleAdvertiserInterface::StatusCallback timeout_cb) { + uint8_t status = 0; + this->adv_callbacks_->OnAdvertisingEnabled(advertiser_id, enable, + status); }); ON_CALL(*mock_ble_advertising_manager_, GetOwnAddress) .WillByDefault( - [](uint8_t inst_id, BleAdvertisingManager::GetAddressCallback cb) { + [](uint8_t inst_id, BleAdvertiserInterface::GetAddressCallback cb) { uint8_t address_type = 0x02; RawAddress address; const uint8_t addr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; @@ -150,6 +189,25 @@ class StateMachineTest : public Test { } }); + ON_CALL(*(adv_callbacks_.get()), OnAdvertisingSetStarted) + .WillByDefault([this](int reg_id, uint8_t advertiser_id, + int8_t tx_power, uint8_t status) { + pending_broadcasts_.back()->OnCreateAnnouncement(advertiser_id, + tx_power, status); + }); + + ON_CALL(*(adv_callbacks_.get()), OnAdvertisingEnabled) + .WillByDefault( + [this](uint8_t advertiser_id, bool enable, uint8_t status) { + auto const& iter = std::find_if( + broadcasts_.cbegin(), broadcasts_.cend(), + [advertiser_id](auto const& sm) { + return sm.second->GetAdvertisingSid() == advertiser_id; + }); + if (iter != broadcasts_.cend()) { + iter->second->OnEnableAnnouncement(enable, status); + } + }); ConfigureIsoManagerMock(); } @@ -232,9 +290,16 @@ class StateMachineTest : public Test { void TearDown() override { iso_manager_->Stop(); mock_iso_manager_ = nullptr; + Mock::VerifyAndClearExpectations(sm_callbacks_.get()); + Mock::VerifyAndClearExpectations(adv_callbacks_.get()); + pending_broadcasts_.clear(); broadcasts_.clear(); sm_callbacks_.reset(); + adv_callbacks_.reset(); + + MockBleAdvertisingManager::CleanUp(); + mock_ble_advertising_manager_ = nullptr; } uint32_t InstantiateStateMachine( @@ -253,8 +318,8 @@ class StateMachineTest : public Test { auto broadcast_id = broadcast_id_lsb++; pending_broadcasts_.push_back(BroadcastStateMachine::CreateInstance({ .is_public = true, - .broadcast_name = test_broadcast_name, .broadcast_id = broadcast_id, + .broadcast_name = test_broadcast_name, // .streaming_phy = , .codec_wrapper = codec_qos_pair.first, .qos_config = codec_qos_pair.second, @@ -265,8 +330,6 @@ class StateMachineTest : public Test { return instance_future.get(); } - base::WeakPtr ble_advertising_manager_; - MockBleAdvertisingManager* mock_ble_advertising_manager_; IsoManager* iso_manager_; MockIsoManager* mock_iso_manager_; @@ -274,49 +337,30 @@ class StateMachineTest : public Test { std::map> broadcasts_; std::vector> pending_broadcasts_; std::unique_ptr sm_callbacks_; + std::unique_ptr adv_callbacks_; std::promise instance_creation_promise_; std::promise instance_destruction_promise_; }; TEST_F(StateMachineTest, CreateInstanceFailed) { EXPECT_CALL(*mock_ble_advertising_manager_, StartAdvertisingSet) - .WillOnce([](base::Callback cb, - tBTM_BLE_ADV_PARAMS* params, - std::vector advertise_data, - std::vector scan_response_data, - tBLE_PERIODIC_ADV_PARAMS* periodic_params, - std::vector periodic_data, uint16_t duration, - uint8_t maxExtAdvEvents, - base::Callback timeout_cb) { - uint8_t advertiser_id = 1; - uint8_t tx_power = 0; - uint8_t status = 1; - cb.Run(advertiser_id, tx_power, status); - }); - - EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, false)) - .Times(1); - - auto broadcast_id = InstantiateStateMachine(); - ASSERT_NE(broadcast_id, BroadcastStateMachine::kAdvSidUndefined); - ASSERT_TRUE(pending_broadcasts_.empty()); - ASSERT_TRUE(broadcasts_.empty()); -} - -TEST_F(StateMachineTest, CreateInstanceTimeout) { - EXPECT_CALL(*mock_ble_advertising_manager_, StartAdvertisingSet) - .WillOnce([](base::Callback cb, - tBTM_BLE_ADV_PARAMS* params, - std::vector advertise_data, - std::vector scan_response_data, - tBLE_PERIODIC_ADV_PARAMS* periodic_params, - std::vector periodic_data, uint16_t duration, - uint8_t maxExtAdvEvents, - base::Callback timeout_cb) { - uint8_t advertiser_id = 1; - uint8_t status = 1; - timeout_cb.Run(advertiser_id, status); - }); + .WillOnce( + [this](uint8_t client_id, int reg_id, + BleAdvertiserInterface::IdTxPowerStatusCallback register_cb, + AdvertiseParameters params, + std::vector advertise_data, + std::vector scan_response_data, + PeriodicAdvertisingParameters periodic_params, + std::vector periodic_data, uint16_t duration, + uint8_t maxExtAdvEvents, + BleAdvertiserInterface::IdStatusCallback timeout_cb) { + uint8_t advertiser_id = 1; + uint8_t tx_power = 0; + uint8_t status = 1; + this->adv_callbacks_->OnAdvertisingSetStarted( + BroadcastStateMachine::kLeAudioBroadcastRegId, advertiser_id, + tx_power, status); + }); EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, false)) .Times(1); @@ -386,7 +430,7 @@ static BasicAudioAnnouncementData prepareAnnouncement( std::map> metadata) { BasicAudioAnnouncementData announcement; - announcement.presentation_delay = 0x004E20; + announcement.presentation_delay_us = 40000; auto const& codec_id = codec_config.GetLeAudioCodecId(); announcement.subgroup_configs = {{ @@ -898,20 +942,21 @@ TEST_F(StateMachineTest, GetPublicBroadcastAnnouncement) { } TEST_F(StateMachineTest, AnnouncementTest) { - tBTM_BLE_ADV_PARAMS adv_params; + AdvertiseParameters adv_params; std::vector a_data; std::vector p_data; EXPECT_CALL(*mock_ble_advertising_manager_, StartAdvertisingSet) - .WillOnce([&p_data, &a_data, &adv_params]( - base::Callback cb, - tBTM_BLE_ADV_PARAMS* params, + .WillOnce([this, &p_data, &a_data, &adv_params]( + uint8_t client_id, int reg_id, + BleAdvertiserInterface::IdTxPowerStatusCallback register_cb, + AdvertiseParameters params, std::vector advertise_data, std::vector scan_response_data, - tBLE_PERIODIC_ADV_PARAMS* periodic_params, + PeriodicAdvertisingParameters periodic_params, std::vector periodic_data, uint16_t duration, uint8_t maxExtAdvEvents, - base::Callback timeout_cb) { + BleAdvertiserInterface::IdStatusCallback timeout_cb) { uint8_t advertiser_id = 1; uint8_t tx_power = 0; uint8_t status = 0; @@ -921,9 +966,11 @@ TEST_F(StateMachineTest, AnnouncementTest) { a_data = std::move(advertise_data); p_data = std::move(periodic_data); - adv_params = *params; + adv_params = params; - cb.Run(advertiser_id, tx_power, status); + this->adv_callbacks_->OnAdvertisingSetStarted( + BroadcastStateMachine::kLeAudioBroadcastRegId, advertiser_id, + tx_power, status); }); EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)) @@ -955,7 +1002,8 @@ TEST_F(StateMachineTest, AnnouncementTest) { ASSERT_EQ(p_data[3], ((kBasicAudioAnnouncementServiceUuid >> 8) & 0x00FF)); // Check advertising parameters - ASSERT_EQ(adv_params.own_address_type, BLE_ADDR_RANDOM); + ASSERT_EQ(adv_params.own_address_type, + BroadcastStateMachine::kBroadcastAdvertisingType); } } // namespace diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc index b1c69f29af08694aad5b6db46cbf823a4b50262d..7ca3cd48554a3cfcd3579fbb4ce189c2179bccec 100644 --- a/system/bta/le_audio/client.cc +++ b/system/bta/le_audio/client.cc @@ -15,18 +15,18 @@ * limitations under the License. */ +#include #include #include +#include #include #include #include -#include "advertise_data_parser.h" #include "audio_hal_client/audio_hal_client.h" #include "audio_hal_interface/le_audio_software.h" #include "bta/csis/csis_types.h" -#include "bta_api.h" #include "bta_gatt_api.h" #include "bta_gatt_queue.h" #include "bta_groups.h" @@ -34,24 +34,25 @@ #include "btif_profile_storage.h" #include "btm_iso_api.h" #include "client_parser.h" +#include "codec_interface.h" #include "codec_manager.h" #include "common/time_util.h" #include "content_control_id_keeper.h" #include "device/include/controller.h" #include "devices.h" -#include "embdrv/lc3/include/lc3.h" -#include "gatt/bta_gattc_int.h" #include "gd/common/strings.h" #include "internal_include/stack_config.h" +#include "le_audio_health_status.h" #include "le_audio_set_configuration_provider.h" #include "le_audio_types.h" #include "le_audio_utils.h" #include "metrics_collector.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/osi.h" #include "osi/include/properties.h" #include "stack/btm/btm_sec.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/bt_types.h" +#include "stack/include/main_thread.h" #include "state_machine.h" #include "storage_helper.h" @@ -68,35 +69,40 @@ using bluetooth::le_audio::ConnectionState; using bluetooth::le_audio::GroupNodeStatus; using bluetooth::le_audio::GroupStatus; using bluetooth::le_audio::GroupStreamStatus; +using bluetooth::le_audio::LeAudioHealthBasedAction; +using bluetooth::le_audio::UnicastMonitorModeStatus; using le_audio::CodecManager; using le_audio::ContentControlIdKeeper; using le_audio::DeviceConnectState; +using le_audio::DsaMode; +using le_audio::DsaModes; using le_audio::LeAudioCodecConfiguration; using le_audio::LeAudioDevice; using le_audio::LeAudioDeviceGroup; using le_audio::LeAudioDeviceGroups; using le_audio::LeAudioDevices; using le_audio::LeAudioGroupStateMachine; +using le_audio::LeAudioHealthDeviceStatType; +using le_audio::LeAudioHealthGroupStatType; +using le_audio::LeAudioHealthStatus; +using le_audio::LeAudioRecommendationActionCb; using le_audio::LeAudioSinkAudioHalClient; using le_audio::LeAudioSourceAudioHalClient; using le_audio::types::ase; using le_audio::types::AseState; using le_audio::types::AudioContexts; using le_audio::types::AudioLocations; -using le_audio::types::AudioStreamDataPathState; using le_audio::types::BidirectionalPair; +using le_audio::types::DataPathState; using le_audio::types::hdl_pair; using le_audio::types::kDefaultScanDurationS; +using le_audio::types::kLeAudioContextAllBidir; +using le_audio::types::kLeAudioContextAllRemoteSinkOnly; +using le_audio::types::kLeAudioContextAllRemoteSource; +using le_audio::types::kLeAudioContextAllTypesArray; using le_audio::types::LeAudioContextType; -using le_audio::utils::GetAllowedAudioContextsFromSinkMetadata; -using le_audio::utils::GetAllowedAudioContextsFromSourceMetadata; -using le_audio::utils::IsContextForAudioSource; - -using le_audio::client_parser::ascs:: - kCtpResponseCodeInvalidConfigurationParameterValue; -using le_audio::client_parser::ascs::kCtpResponseCodeSuccess; -using le_audio::client_parser::ascs::kCtpResponseInvalidAseCisMapping; -using le_audio::client_parser::ascs::kCtpResponseNoReason; +using le_audio::utils::GetAudioContextsFromSinkMetadata; +using le_audio::utils::GetAudioContextsFromSourceMetadata; /* Enums */ enum class AudioReconfigurationResult { @@ -159,22 +165,9 @@ std::ostream& operator<<(std::ostream& os, const AudioState& audio_state) { namespace { void le_audio_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data); -inline uint8_t bits_to_bytes_per_sample(uint8_t bits_per_sample) { - // 24 bit audio stream is sent as unpacked, each sample takes 4 bytes. - if (bits_per_sample == 24) return 4; - - return bits_per_sample / 8; -} - -inline lc3_pcm_format bits_to_lc3_bits(uint8_t bits_per_sample) { - if (bits_per_sample == 16) return LC3_PCM_FORMAT_S16; - - if (bits_per_sample == 24) return LC3_PCM_FORMAT_S24; - - LOG_ALWAYS_FATAL("Encoder/decoder don't know how to handle %d", - bits_per_sample); - return LC3_PCM_FORMAT_S16; -} +static void le_audio_health_status_callback(const RawAddress& addr, + int group_id, + LeAudioHealthBasedAction action); class LeAudioClientImpl; LeAudioClientImpl* instance; @@ -231,21 +224,18 @@ class LeAudioClientImpl : public LeAudioClient { callbacks_(callbacks_), active_group_id_(bluetooth::groups::kGroupUnknown), configuration_context_type_(LeAudioContextType::UNINITIALIZED), - metadata_context_types_( - {sink : AudioContexts(), source : AudioContexts()}), + local_metadata_context_types_( + {.sink = AudioContexts(), .source = AudioContexts()}), stream_setup_start_timestamp_(0), stream_setup_end_timestamp_(0), audio_receiver_state_(AudioState::IDLE), audio_sender_state_(AudioState::IDLE), in_call_(false), + in_voip_call_(false), + sink_monitor_mode_(false), + sink_monitor_notified_status_(std::nullopt), current_source_codec_config({0, 0, 0, 0}), current_sink_codec_config({0, 0, 0, 0}), - lc3_encoder_left_mem(nullptr), - lc3_encoder_right_mem(nullptr), - lc3_decoder_left_mem(nullptr), - lc3_decoder_right_mem(nullptr), - lc3_decoder_left(nullptr), - lc3_decoder_right(nullptr), le_audio_source_hal_client_(nullptr), le_audio_sink_hal_client_(nullptr), close_vbc_timeout_(alarm_new("LeAudioCloseVbcTimeout")), @@ -263,6 +253,13 @@ class LeAudioClientImpl : public LeAudioClient { reconnection_mode_ = BTM_BLE_BKG_CONNECT_ALLOW_LIST; } + if (IS_FLAG_ENABLED(leaudio_enable_health_based_actions)) { + LOG_INFO("Loading health status module"); + leAudioHealthStatus_ = LeAudioHealthStatus::Get(); + leAudioHealthStatus_->RegisterCallback( + base::BindRepeating(le_audio_health_status_callback)); + } + BTA_GATTC_AppRegister( le_audio_gattc_callback, base::Bind( @@ -284,6 +281,10 @@ class LeAudioClientImpl : public LeAudioClient { void ReconfigureAfterVbcClose() { LOG_DEBUG("VBC close timeout"); + if (IsInVoipCall()) { + SetInVoipCall(false); + } + auto group = aseGroups_.FindById(active_group_id_); if (!group) { LOG_ERROR("Invalid group: %d", active_group_id_); @@ -304,19 +305,23 @@ class LeAudioClientImpl : public LeAudioClient { } /* Test the existing metadata against the recent availability */ - metadata_context_types_.sink &= group->GetAvailableContexts(); - if (metadata_context_types_.sink.none()) { + local_metadata_context_types_.source &= + group->GetAvailableContexts(le_audio::types::kLeAudioDirectionSink); + if (local_metadata_context_types_.source.none()) { LOG_WARN("invalid/unknown context metadata, using 'MEDIA' instead"); - metadata_context_types_.sink = AudioContexts(LeAudioContextType::MEDIA); + local_metadata_context_types_.source = + AudioContexts(LeAudioContextType::MEDIA); } /* Choose the right configuration context */ auto new_configuration_context = - ChooseConfigurationContextType(metadata_context_types_.sink); + ChooseConfigurationContextType(local_metadata_context_types_.source); LOG_DEBUG("new_configuration_context= %s", ToString(new_configuration_context).c_str()); - ReconfigureOrUpdateMetadata(group, new_configuration_context); + ReconfigureOrUpdateMetadata(group, new_configuration_context, + {.sink = local_metadata_context_types_.source, + .source = local_metadata_context_types_.sink}); } void StartVbcCloseTimeout() { @@ -390,7 +395,8 @@ class LeAudioClientImpl : public LeAudioClient { */ void SetDeviceAsRemovePendingAndStopGroup(LeAudioDevice* leAudioDevice) { LOG_INFO("device %s", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - leAudioDevice->SetConnectionState(DeviceConnectState::PENDING_REMOVAL); + leAudioDevice->SetConnectionState(DeviceConnectState::REMOVING); + leAudioDevice->closing_stream_for_disconnection_ = true; GroupStop(leAudioDevice->group_id_); } @@ -412,6 +418,11 @@ class LeAudioClientImpl : public LeAudioClient { return; } + if (leAudioHealthStatus_) { + leAudioHealthStatus_->AddStatisticForDevice( + leAudioDevice, LeAudioHealthDeviceStatType::VALID_CSIS); + } + group_add_node(group_id, address); } @@ -436,6 +447,10 @@ class LeAudioClientImpl : public LeAudioClient { return; } + if (leAudioHealthStatus_) { + leAudioHealthStatus_->RemoveStatistics(address, group->group_id_); + } + if (leAudioDevice->HaveActiveAse()) { SetDeviceAsRemovePendingAndStopGroup(leAudioDevice); return; @@ -455,13 +470,21 @@ class LeAudioClientImpl : public LeAudioClient { return; } + bool check_if_recovery_needed = + group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; + + if (leAudioHealthStatus_) { + leAudioHealthStatus_->AddStatisticForGroup( + group, LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED); + } + LOG_ERROR( " State not achieved on time for group: group id %d, current state %s, " - "target state: %s", + "target state: %s, check_if_recovery_needed: %d", group_id, ToString(group->GetState()).c_str(), - ToString(group->GetTargetState()).c_str()); + ToString(group->GetTargetState()).c_str(), check_if_recovery_needed); group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); - group->CigClearCis(); + group->ClearAllCises(); group->PrintDebugState(); /* There is an issue with a setting up stream or any other operation which @@ -479,28 +502,45 @@ class LeAudioClientImpl : public LeAudioClient { } } + /* If Timeout happens on stream close and stream is closing just for the + * purpose of device disconnection, do not bother with recovery mode + */ + bool recovery = true; + if (check_if_recovery_needed) { + for (auto tmpDevice = leAudioDevice; tmpDevice != nullptr; + tmpDevice = group->GetNextActiveDevice(tmpDevice)) { + if (tmpDevice->closing_stream_for_disconnection_) { + recovery = false; + break; + } + } + } + do { - if (instance) instance->DisconnectDevice(leAudioDevice, true); + DisconnectDevice(leAudioDevice, true, recovery); leAudioDevice = group->GetNextActiveDevice(leAudioDevice); } while (leAudioDevice); - } - void UpdateContextAndLocations(LeAudioDeviceGroup* group, - LeAudioDevice* leAudioDevice) { - if (leAudioDevice->GetConnectionState() != DeviceConnectState::CONNECTED) { - LOG_DEBUG("%s not yet connected ", - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - return; + if (recovery) { + /* Both devices will be disconnected soon. Notify upper layer that group + * is inactive */ + groupSetAndNotifyInactive(); } + } - /* Make sure location and direction are updated for the group. */ - auto location_update = group->ReloadAudioLocations(); - group->ReloadAudioDirections(); - - auto contexts_updated = group->UpdateAudioContextTypeAvailability( - leAudioDevice->GetAvailableContexts()); + void OnDeviceAutonomousStateTransitionTimeout(LeAudioDevice* leAudioDevice) { + LOG_ERROR("Device %s, failed to complete autonomous transition", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + DisconnectDevice(leAudioDevice, true); + } - if (contexts_updated || location_update) { + void UpdateLocationsAndContextsAvailability(LeAudioDeviceGroup* group) { + bool group_conf_changed = group->ReloadAudioLocations(); + group_conf_changed |= group->ReloadAudioDirections(); + group_conf_changed |= group->UpdateAudioContextAvailability(); + if (group_conf_changed) { + /* All the configurations should be recalculated for the new conditions */ + group->InvalidateCachedConfigurations(); callbacks_->OnAudioConf(group->audio_directions_, group->group_id_, group->snk_audio_locations_.to_ulong(), group->src_audio_locations_.to_ulong(), @@ -508,6 +548,13 @@ class LeAudioClientImpl : public LeAudioClient { } } + void UpdateLocationsAndContextsAvailability(int group_id) { + LeAudioDeviceGroup* group = aseGroups_.FindById(group_id); + if (group) { + UpdateLocationsAndContextsAvailability(group); + } + } + void SuspendedForReconfiguration() { if (audio_sender_state_ > AudioState::IDLE) { LeAudioLogHistory::Get()->AddLogHistory( @@ -580,28 +627,6 @@ class LeAudioClientImpl : public LeAudioClient { } } - void ControlPointNotificationHandler( - struct le_audio::client_parser::ascs::ctp_ntf& ntf) { - for (auto& entry : ntf.entries) { - switch (entry.response_code) { - case kCtpResponseCodeInvalidConfigurationParameterValue: - switch (entry.reason) { - case kCtpResponseInvalidAseCisMapping: - CancelStreamingRequest(); - break; - case kCtpResponseNoReason: - default: - break; - } - break; - case kCtpResponseCodeSuccess: - FALLTHROUGH; - default: - break; - } - } - } - void group_add_node(const int group_id, const RawAddress& address, bool update_group_module = false) { LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address); @@ -673,25 +698,14 @@ class LeAudioClientImpl : public LeAudioClient { if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID) AseInitialStateReadRequest(leAudioDevice); - /* Group may be destroyed once moved its last node to new group */ - if (aseGroups_.FindById(old_group_id) != nullptr) { - /* Removing node from group may touch its context integrity */ - auto contexts_updated = old_group->UpdateAudioContextTypeAvailability( - old_group->GetAvailableContexts()); - - bool group_conf_changed = old_group->ReloadAudioLocations(); - group_conf_changed |= old_group->ReloadAudioDirections(); - group_conf_changed |= contexts_updated; - - if (group_conf_changed) { - callbacks_->OnAudioConf(old_group->audio_directions_, old_group_id, - old_group->snk_audio_locations_.to_ulong(), - old_group->src_audio_locations_.to_ulong(), - old_group->GetAvailableContexts().value()); - } - } + /* Group may be destroyed once moved its last node to new group, so don't + * use `old_group` pointer anymore. + * Removing node from group requires updating group context availability */ + UpdateLocationsAndContextsAvailability(old_group_id); - UpdateContextAndLocations(new_group, leAudioDevice); + if (leAudioDevice->GetConnectionState() == DeviceConnectState::CONNECTED) { + UpdateLocationsAndContextsAvailability(new_group); + } } void GroupAddNode(const int group_id, const RawAddress& address) override { @@ -714,9 +728,9 @@ class LeAudioClientImpl : public LeAudioClient { } LOG_DEBUG("Group %p, id: %d, size: %d, is cig_state %s", group, group->group_id_, group->Size(), - ToString(group->cig_state_).c_str()); + ToString(group->cig.GetState()).c_str()); if (group->IsEmpty() && - (group->cig_state_ == le_audio::types::CigState::NONE)) { + (group->cig.GetState() == le_audio::types::CigState::NONE)) { aseGroups_.Remove(group->group_id_); } } @@ -742,19 +756,8 @@ class LeAudioClientImpl : public LeAudioClient { return; } - /* Removing node from group touch its context integrity */ - bool contexts_updated = group->UpdateAudioContextTypeAvailability( - group->GetAvailableContexts()); - - bool group_conf_changed = group->ReloadAudioLocations(); - group_conf_changed |= group->ReloadAudioDirections(); - group_conf_changed |= contexts_updated; - - if (group_conf_changed) - callbacks_->OnAudioConf(group->audio_directions_, group->group_id_, - group->snk_audio_locations_.to_ulong(), - group->src_audio_locations_.to_ulong(), - group->GetAvailableContexts().value()); + /* Removing node from group requires updating group context availability */ + UpdateLocationsAndContextsAvailability(group); } void GroupRemoveNode(const int group_id, const RawAddress& address) override { @@ -835,16 +838,18 @@ class LeAudioClientImpl : public LeAudioClient { return AudioContexts(LeAudioContextType::UNSPECIFIED); } - bool GroupStream( - const int group_id, LeAudioContextType context_type, - const BidirectionalPair& metadata_context_types) { + /* Return true if stream is started */ + bool GroupStream(int group_id, LeAudioContextType configuration_context_type, + BidirectionalPair remote_contexts) { LeAudioDeviceGroup* group = aseGroups_.FindById(group_id); - auto final_context_type = context_type; + + LOG_DEBUG("configuration_context_type= %s", + ToString(configuration_context_type).c_str()); DLOG(INFO) << __func__; - if (context_type >= LeAudioContextType::RFU) { + if (configuration_context_type >= LeAudioContextType::RFU) { LOG(ERROR) << __func__ << ", stream context type is not supported: " - << ToHexString(context_type); + << ToHexString(configuration_context_type); return false; } @@ -857,12 +862,6 @@ class LeAudioClientImpl : public LeAudioClient { ToString(group->GetState()).c_str(), ToString(group->GetTargetState()).c_str()); - if (!group->GetAvailableContexts().test(context_type)) { - LOG(ERROR) << " Unsupported context type by remote device: " - << ToHexString(context_type) << ". Switching to unspecified"; - final_context_type = LeAudioContextType::UNSPECIFIED; - } - if (!group->IsAnyDeviceConnected()) { LOG(ERROR) << __func__ << ", group " << group_id << " is not connected "; return false; @@ -882,29 +881,41 @@ class LeAudioClientImpl : public LeAudioClient { return false; } - if (group->IsPendingConfiguration()) { - LOG_WARN("Group %d is reconfiguring right now. Drop the update", - group->group_id_); - return false; + /* Make sure we do not take the local sink metadata when only the local + * source scenario is about to be started (e.g. MEDIA). + */ + if (!kLeAudioContextAllBidir.test(configuration_context_type)) { + remote_contexts.source.clear(); } - if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - stream_setup_start_timestamp_ = - bluetooth::common::time_get_os_boottime_us(); + /* Do not put the TBS CCID when not using Telecom for the VoIP calls. */ + auto ccid_contexts = remote_contexts; + if (IsInVoipCall() && !IsInCall()) { + ccid_contexts.sink.unset(LeAudioContextType::CONVERSATIONAL); + ccid_contexts.source.unset(LeAudioContextType::CONVERSATIONAL); } BidirectionalPair> ccids = { .sink = ContentControlIdKeeper::GetInstance()->GetAllCcids( - metadata_context_types.sink), + ccid_contexts.sink), .source = ContentControlIdKeeper::GetInstance()->GetAllCcids( - metadata_context_types.source)}; + ccid_contexts.source)}; + if (group->IsPendingConfiguration()) { + return groupStateMachine_->ConfigureStream( + group, configuration_context_type_, remote_contexts, ccids); + } else if (group->GetState() != + AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { + stream_setup_start_timestamp_ = + bluetooth::common::time_get_os_boottime_us(); + } + bool result = groupStateMachine_->StartStream( - group, final_context_type, metadata_context_types, ccids); + group, configuration_context_type, remote_contexts, ccids); return result; } - void GroupStream(const int group_id, const uint16_t context_type) override { + void GroupStream(const int group_id, uint16_t context_type) override { BidirectionalPair initial_contexts = { AudioContexts(context_type), AudioContexts(context_type)}; GroupStream(group_id, LeAudioContextType(context_type), initial_contexts); @@ -953,9 +964,14 @@ class LeAudioClientImpl : public LeAudioClient { } if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { - LOG_ERROR(", group already stopped: %s", - ToString(group->GetState()).c_str()); - + if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { + LOG_WARN(" group %d was about to stream, but got canceled: %s", + group_id, ToString(group->GetTargetState()).c_str()); + group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + } else { + LOG_WARN(", group %d already stopped: %s", group_id, + ToString(group->GetState()).c_str()); + } return; } @@ -999,6 +1015,40 @@ class LeAudioClientImpl : public LeAudioClient { in_call_ = in_call; } + bool IsInCall() override { return in_call_; } + + void SetInVoipCall(bool in_call) override { + LOG_DEBUG("in_voip_call: %d", in_call); + in_voip_call_ = in_call; + } + + bool IsInVoipCall() override { return in_voip_call_; } + + void SetUnicastMonitorMode(uint8_t direction, bool enable) override { + if (!IS_FLAG_ENABLED(leaudio_broadcast_audio_handover_policies)) { + LOG_WARN("Monitor mode is disabled, Set Unicast Monitor mode is ignored"); + return; + } + + if (direction == le_audio::types::kLeAudioDirectionSink) { + /* Cleanup Sink HAL client interface if listening mode is toggled off + * before group activation (active group context would take care of + * Sink HAL client cleanup). + */ + if (sink_monitor_mode_ && !enable && le_audio_sink_hal_client_ && + active_group_id_ == bluetooth::groups::kGroupUnknown) { + local_metadata_context_types_.sink.clear(); + le_audio_sink_hal_client_->Stop(); + le_audio_sink_hal_client_.reset(); + } + + LOG_DEBUG("enable: %d", enable); + sink_monitor_mode_ = enable; + } else { + LOG_ERROR("invalid direction: 0x%02x monitor mode set", direction); + } + } + void SendAudioProfilePreferences( const int group_id, bool is_output_preference_le_audio, bool is_duplex_preference_le_audio) override { @@ -1021,8 +1071,8 @@ class LeAudioClientImpl : public LeAudioClient { } void StartAudioSession(LeAudioDeviceGroup* group, - LeAudioCodecConfiguration* source_config, - LeAudioCodecConfiguration* sink_config) { + const LeAudioCodecConfiguration* source_config, + const LeAudioCodecConfiguration* sink_config) { /* This function is called when group is not yet set to active. * This is why we don't have to check if session is started already. * Just check if it is acquired. @@ -1032,6 +1082,11 @@ class LeAudioClientImpl : public LeAudioClient { ASSERT_LOG(le_audio_source_hal_client_, "Source session not acquired"); ASSERT_LOG(le_audio_sink_hal_client_, "Sink session not acquired"); + DsaModes dsa_modes = {DsaMode::DISABLED}; + if (IS_FLAG_ENABLED(leaudio_dynamic_spatial_audio)) { + dsa_modes = group->GetAllowedDsaModes(); + } + /* We assume that peer device always use same frame duration */ uint32_t frame_duration_us = 0; if (!source_config->IsInvalid()) { @@ -1044,7 +1099,7 @@ class LeAudioClientImpl : public LeAudioClient { audio_framework_source_config.data_interval_us = frame_duration_us; le_audio_source_hal_client_->Start(audio_framework_source_config, - audioSinkReceiver); + audioSinkReceiver, dsa_modes); /* We use same frame duration for sink/source */ audio_framework_sink_config.data_interval_us = frame_duration_us; @@ -1063,7 +1118,7 @@ class LeAudioClientImpl : public LeAudioClient { } le_audio_sink_hal_client_->Start(audio_framework_sink_config, - audioSourceReceiver); + audioSourceReceiver, dsa_modes); } bool isOutputPreferenceLeAudio(const RawAddress& address) { @@ -1102,6 +1157,22 @@ class LeAudioClientImpl : public LeAudioClient { return group->is_duplex_preference_le_audio; } + void groupSetAndNotifyInactive(void) { + if (active_group_id_ == bluetooth::groups::kGroupUnknown) { + return; + } + auto group_id_to_close = active_group_id_; + active_group_id_ = bluetooth::groups::kGroupUnknown; + sink_monitor_notified_status_ = std::nullopt; + + LOG_INFO("Group id: %d", group_id_to_close); + if (alarm_is_scheduled(suspend_timeout_)) alarm_cancel(suspend_timeout_); + + StopAudio(); + ClientAudioInterfaceRelease(); + callbacks_->OnGroupStatus(group_id_to_close, GroupStatus::INACTIVE); + } + void GroupSetActive(const int group_id) override { LOG_INFO(" group_id: %d", group_id); @@ -1113,15 +1184,9 @@ class LeAudioClientImpl : public LeAudioClient { LOG_INFO("Active group_id changed %d -> %d", active_group_id_, group_id); auto group_id_to_close = active_group_id_; - active_group_id_ = bluetooth::groups::kGroupUnknown; - - if (alarm_is_scheduled(suspend_timeout_)) alarm_cancel(suspend_timeout_); - - StopAudio(); - ClientAudioIntefraceRelease(); - + groupSetAndNotifyInactive(); GroupStop(group_id_to_close); - callbacks_->OnGroupStatus(group_id_to_close, GroupStatus::INACTIVE); + return; } @@ -1164,13 +1229,14 @@ class LeAudioClientImpl : public LeAudioClient { * If most recent scenario is not supported, try to find first supported. */ LeAudioContextType default_context_type = configuration_context_type_; - if (!group->IsContextSupported(default_context_type)) { - if (group->IsContextSupported(LeAudioContextType::MEDIA)) { - default_context_type = LeAudioContextType::MEDIA; + if (!group->IsAudioSetConfigurationAvailable(default_context_type)) { + if (group->IsAudioSetConfigurationAvailable( + LeAudioContextType::UNSPECIFIED)) { + default_context_type = LeAudioContextType::UNSPECIFIED; + default_context_type = LeAudioContextType::UNSPECIFIED; } else { - for (LeAudioContextType context_type : - le_audio::types::kLeAudioContextAllTypesArray) { - if (group->IsContextSupported(context_type)) { + for (LeAudioContextType context_type : kLeAudioContextAllTypesArray) { + if (group->IsAudioSetConfigurationAvailable(context_type)) { default_context_type = context_type; break; } @@ -1181,23 +1247,32 @@ class LeAudioClientImpl : public LeAudioClient { default_context_type); if (current_source_codec_config.IsInvalid() && current_sink_codec_config.IsInvalid()) { - LOG(WARNING) << __func__ << ", unsupported device configurations"; + LOG_ERROR("Unsupported device configurations"); return; } - if (active_group_id_ == bluetooth::groups::kGroupUnknown) { + auto previous_active_group = active_group_id_; + LOG_INFO("Active group_id changed %d -> %d", previous_active_group, + group_id); + + if (previous_active_group == bluetooth::groups::kGroupUnknown) { /* Expose audio sessions if there was no previous active group */ StartAudioSession(group, ¤t_source_codec_config, ¤t_sink_codec_config); + active_group_id_ = group_id; } else { - /* In case there was an active group. Stop the stream */ - GroupStop(active_group_id_); - callbacks_->OnGroupStatus(active_group_id_, GroupStatus::INACTIVE); + /* In case there was an active group. Stop the stream, but before that, set + * the new group so the group change is correctly handled in OnStateMachineStatusReportCb + */ + active_group_id_ = group_id; + GroupStop(previous_active_group); + callbacks_->OnGroupStatus(previous_active_group, GroupStatus::INACTIVE); } - LOG_INFO("Active group_id changed %d -> %d", active_group_id_, group_id); - active_group_id_ = group_id; + /* Reset sink listener notified status */ + sink_monitor_notified_status_ = std::nullopt; callbacks_->OnGroupStatus(active_group_id_, GroupStatus::ACTIVE); + SendAudioGroupSelectableCodecConfigChanged(group); } void SetEnableState(const RawAddress& address, bool enabled) override { @@ -1240,7 +1315,6 @@ class LeAudioClientImpl : public LeAudioClient { auto connection_state = leAudioDevice->GetConnectionState(); switch (connection_state) { case DeviceConnectState::REMOVING: - case DeviceConnectState::PENDING_REMOVAL: /* Just return, and let device disconnect */ return; case DeviceConnectState::CONNECTED: @@ -1376,28 +1450,35 @@ class LeAudioClientImpl : public LeAudioClient { le_audio::types::kLeAudioDirectionSource; } - leAudioDevice->SetSupportedContexts( - AudioContexts(sink_supported_context_types), - AudioContexts(source_supported_context_types)); + BidirectionalPair supported_contexts = { + .sink = AudioContexts(sink_supported_context_types), + .source = AudioContexts(source_supported_context_types), + }; + + leAudioDevice->SetSupportedContexts(supported_contexts); - /* Use same as or supported ones for now. */ - leAudioDevice->SetAvailableContexts( - AudioContexts(sink_supported_context_types), - AudioContexts(source_supported_context_types)); + /* Use same as supported ones for now. */ + leAudioDevice->SetAvailableContexts(supported_contexts); if (!DeserializeHandles(leAudioDevice, handles)) { LOG_WARN("Could not load Handles"); } if (!DeserializeSinkPacs(leAudioDevice, sink_pacs)) { + /* If PACs are invalid, just say whole cache is invalid */ + leAudioDevice->known_service_handles_ = false; LOG_WARN("Could not load sink pacs"); } if (!DeserializeSourcePacs(leAudioDevice, source_pacs)) { + /* If PACs are invalid, just say whole cache is invalid */ + leAudioDevice->known_service_handles_ = false; LOG_WARN("Could not load source pacs"); } if (!DeserializeAses(leAudioDevice, ases)) { + /* If ASEs are invalid, just say whole cache is invalid */ + leAudioDevice->known_service_handles_ = false; LOG_WARN("Could not load ases"); } @@ -1433,30 +1514,12 @@ class LeAudioClientImpl : public LeAudioClient { } void BackgroundConnectIfNeeded(LeAudioDevice* leAudioDevice) { - auto group = GetGroupIfEnabled(leAudioDevice->group_id_); - if (group == nullptr) { - LOG_INFO(" Device %s is not yet part of the group %d. ", - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), - leAudioDevice->group_id_); - return; - } - - if (!leAudioDevice->autoconnect_flag_ && !group->IsAnyDeviceConnected()) { + if (!leAudioDevice->autoconnect_flag_) { LOG_DEBUG("Device %s not in the background connect", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); return; } - - LOG_INFO( - "Add %s added to background connect. autoconnect flag: %d " - "group_connected: %d", - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), - leAudioDevice->group_id_, group->IsAnyDeviceConnected()); - - leAudioDevice->SetConnectionState( - DeviceConnectState::CONNECTING_AUTOCONNECT); - BTA_GATTC_Open(gatt_if_, leAudioDevice->address_, reconnection_mode_, - false); + AddToBackgroundConnectCheckGroupConnected(leAudioDevice); } void Disconnect(const RawAddress& address) override { @@ -1480,7 +1543,11 @@ class LeAudioClientImpl : public LeAudioClient { * Cancel just direct connection and keep background if it is there. */ BTA_GATTC_CancelOpen(gatt_if_, address, true); - break; + /* If this is a device which is a part of the group which is connected, + * lets start backgroup connect + */ + BackgroundConnectIfNeeded(leAudioDevice); + return; case DeviceConnectState::CONNECTED: { /* User is disconnecting the device, we shall remove the autoconnect * flag for this device and all others if not TA is used @@ -1500,30 +1567,36 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->autoconnect_flag_ = false; } + /* Make sure ACL is disconnected to avoid reconnecting immediately + * when autoconnect with TA reconnection mechanism is used. + */ + bool force_acl_disconnect = leAudioDevice->autoconnect_flag_; + auto group = aseGroups_.FindById(leAudioDevice->group_id_); - if (group && remove_from_autoconnect) { + if (group) { /* Remove devices from auto connect mode */ for (auto dev = group->GetFirstDevice(); dev; dev = group->GetNextDevice(dev)) { - if (dev->GetConnectionState() == - DeviceConnectState::CONNECTING_AUTOCONNECT) { - btif_storage_set_leaudio_autoconnect(address, false); + if (remove_from_autoconnect && + (dev->GetConnectionState() == + DeviceConnectState::CONNECTING_AUTOCONNECT)) { + btif_storage_set_leaudio_autoconnect(dev->address_, false); dev->autoconnect_flag_ = false; - BTA_GATTC_CancelOpen(gatt_if_, address, false); + BTA_GATTC_CancelOpen(gatt_if_, dev->address_, false); dev->SetConnectionState(DeviceConnectState::DISCONNECTED); } } + if (group->IsStreaming() || !group->IsReleasingOrIdle()) { + leAudioDevice->closing_stream_for_disconnection_ = true; + groupStateMachine_->StopStream(group); + return; + } + force_acl_disconnect &= group->IsEnabled(); } - if (group && - group->GetState() == - le_audio::types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - leAudioDevice->closing_stream_for_disconnection_ = true; - groupStateMachine_->StopStream(group); - return; - } + DisconnectDevice(leAudioDevice, force_acl_disconnect); } - [[fallthrough]]; + return; case DeviceConnectState::CONNECTED_BY_USER_GETTING_READY: /* Timeout happen on the Java layer before native got ready with the * device */ @@ -1540,21 +1613,16 @@ class LeAudioClientImpl : public LeAudioClient { case DeviceConnectState::DISCONNECTING: case DeviceConnectState::DISCONNECTING_AND_RECOVER: case DeviceConnectState::CONNECTING_AUTOCONNECT: - case DeviceConnectState::PENDING_REMOVAL: case DeviceConnectState::REMOVING: LOG_WARN("%s, invalid state %s", ADDRESS_TO_LOGGABLE_CSTR(address), bluetooth::common::ToString(connection_state).c_str()); - break; + return; } - - /* If this is a device which is a part of the group which is connected, - * lets start backgroup connect - */ - BackgroundConnectIfNeeded(leAudioDevice); } void DisconnectDevice(LeAudioDevice* leAudioDevice, - bool acl_force_disconnect = false) { + bool acl_force_disconnect = false, + bool recover = false) { if (leAudioDevice->conn_id_ == GATT_INVALID_CONN_ID) { return; } @@ -1568,8 +1636,10 @@ class LeAudioClientImpl : public LeAudioClient { /* Remote in bad state, force ACL Disconnection. */ if (acl_force_disconnect) { leAudioDevice->DisconnectAcl(); - leAudioDevice->SetConnectionState( - DeviceConnectState::DISCONNECTING_AND_RECOVER); + if (recover) { + leAudioDevice->SetConnectionState( + DeviceConnectState::DISCONNECTING_AND_RECOVER); + } } else { BTA_GATTC_Close(leAudioDevice->conn_id_); } @@ -1627,8 +1697,8 @@ class LeAudioClientImpl : public LeAudioClient { ase = leAudioDevice->GetAseByValHandle(hdl); + LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); if (ase) { - LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); groupStateMachine_->ProcessGattNotifEvent(value, len, ase, leAudioDevice, group); @@ -1648,20 +1718,11 @@ class LeAudioClientImpl : public LeAudioClient { LOG(INFO) << __func__ << ", Registering sink PACs"; leAudioDevice->RegisterPACs(&std::get<1>(*snk_pac_ent), &pac_recs); - /* Update supported context types including internal capabilities */ - LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); - - /* Available context map should be considered to be updated in response to - * PACs update. - * Read of available context during initial attribute discovery. - * Group would be assigned once service search is completed. + /* Cached audio set configurations should be considered invalid when + * PACs are updated. */ - if (group && group->UpdateAudioContextTypeAvailability( - leAudioDevice->GetAvailableContexts())) { - callbacks_->OnAudioConf(group->audio_directions_, group->group_id_, - group->snk_audio_locations_.to_ulong(), - group->src_audio_locations_.to_ulong(), - group->GetAvailableContexts().value()); + if (group) { + group->InvalidateCachedConfigurations(); } if (notify) { btif_storage_leaudio_update_pacs_bin(leAudioDevice->address_); @@ -1682,22 +1743,12 @@ class LeAudioClientImpl : public LeAudioClient { LOG(INFO) << __func__ << ", Registering source PACs"; leAudioDevice->RegisterPACs(&std::get<1>(*src_pac_ent), &pac_recs); - /* Update supported context types including internal capabilities */ - LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); - - /* Available context map should be considered to be updated in response to - * PACs update. - * Read of available context during initial attribute discovery. - * Group would be assigned once service search is completed. + /* Cached audio set configurations should be considered invalid when + * PACs are updated. */ - if (group && group->UpdateAudioContextTypeAvailability( - leAudioDevice->GetAvailableContexts())) { - callbacks_->OnAudioConf(group->audio_directions_, group->group_id_, - group->snk_audio_locations_.to_ulong(), - group->src_audio_locations_.to_ulong(), - group->GetAvailableContexts().value()); + if (group) { + group->InvalidateCachedConfigurations(); } - if (notify) { btif_storage_leaudio_update_pacs_bin(leAudioDevice->address_); } @@ -1723,7 +1774,6 @@ class LeAudioClientImpl : public LeAudioClient { le_audio::types::kLeAudioDirectionSink; leAudioDevice->snk_audio_locations_ = snk_audio_locations; - LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); callbacks_->OnSinkAudioLocationAvailable(leAudioDevice->address_, snk_audio_locations.to_ulong()); @@ -1732,21 +1782,9 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->address_, leAudioDevice->snk_audio_locations_.to_ulong(), leAudioDevice->src_audio_locations_.to_ulong()); - } - - /* Read of source audio locations during initial attribute discovery. - * Group would be assigned once service search is completed. - */ - if (!group) return; - - bool group_conf_changed = group->ReloadAudioLocations(); - group_conf_changed |= group->ReloadAudioDirections(); - - if (group_conf_changed) { - callbacks_->OnAudioConf(group->audio_directions_, group->group_id_, - group->snk_audio_locations_.to_ulong(), - group->src_audio_locations_.to_ulong(), - group->GetAvailableContexts().value()); + if (group && group->IsReleasingOrIdle()) { + UpdateLocationsAndContextsAvailability(leAudioDevice->group_id_); + } } } else if (hdl == leAudioDevice->src_audio_locations_hdls_.val_hdl) { AudioLocations src_audio_locations; @@ -1767,87 +1805,67 @@ class LeAudioClientImpl : public LeAudioClient { le_audio::types::kLeAudioDirectionSource; leAudioDevice->src_audio_locations_ = src_audio_locations; - LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); - if (notify) { btif_storage_set_leaudio_audio_location( leAudioDevice->address_, leAudioDevice->snk_audio_locations_.to_ulong(), leAudioDevice->src_audio_locations_.to_ulong()); + if (group && group->IsReleasingOrIdle()) { + UpdateLocationsAndContextsAvailability(leAudioDevice->group_id_); + } + } + } else if (hdl == leAudioDevice->audio_avail_hdls_.val_hdl) { + BidirectionalPair contexts; + if (!le_audio::client_parser::pacs::ParseAvailableAudioContexts( + contexts, len, value)) { + return; } - /* Read of source audio locations during initial attribute discovery. - * Group would be assigned once service search is completed. - */ - if (!group) return; + leAudioDevice->SetAvailableContexts(contexts); - bool group_conf_changed = group->ReloadAudioLocations(); - group_conf_changed |= group->ReloadAudioDirections(); + if (!group) { + return; + } - if (group_conf_changed) { - callbacks_->OnAudioConf(group->audio_directions_, group->group_id_, - group->snk_audio_locations_.to_ulong(), - group->src_audio_locations_.to_ulong(), - group->GetAvailableContexts().value()); + if (group->IsReleasingOrIdle()) { + /* Group is not streaming. Device does not have to be attach to the + * stream, and we can update context availability for the group + */ + UpdateLocationsAndContextsAvailability(group); + return; } - } else if (hdl == leAudioDevice->audio_avail_hdls_.val_hdl) { - le_audio::client_parser::pacs::acs_available_audio_contexts - avail_audio_contexts; - le_audio::client_parser::pacs::ParseAvailableAudioContexts( - avail_audio_contexts, len, value); - auto updated_avail_contexts = leAudioDevice->SetAvailableContexts( - avail_audio_contexts.snk_avail_cont, - avail_audio_contexts.src_avail_cont); + if (group->IsInTransition()) { + /* Group is in transition, do not take any actions now.*/ + return; + } - if (updated_avail_contexts.any()) { - /* Update scenario map considering changed available context types */ - LeAudioDeviceGroup* group = - aseGroups_.FindById(leAudioDevice->group_id_); - /* Read of available context during initial attribute discovery. - * Group would be assigned once service search is completed. - */ - if (group) { - /* Update of available context may happen during state transition - * or while streaming. Don't bother current transition or streaming - * process. Update configuration once group became idle. - */ - if (group->IsInTransition() || - (group->GetState() == - AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) { - group->SetPendingAvailableContextsChange(updated_avail_contexts); - return; - } + if (leAudioDevice->HaveActiveAse()) { + /* Do nothing, device is streaming */ + return; + } - auto contexts_updated = - group->UpdateAudioContextTypeAvailability(updated_avail_contexts); - if (contexts_updated) { - callbacks_->OnAudioConf(group->audio_directions_, group->group_id_, - group->snk_audio_locations_.to_ulong(), - group->src_audio_locations_.to_ulong(), - group->GetAvailableContexts().value()); - } - } + if (leAudioDevice->GetConnectionState() != + DeviceConnectState::CONNECTED) { + /* Do nothing, wait until device is connected */ + return; } - } else if (hdl == leAudioDevice->audio_supp_cont_hdls_.val_hdl) { - le_audio::client_parser::pacs::acs_supported_audio_contexts - supp_audio_contexts; - le_audio::client_parser::pacs::ParseSupportedAudioContexts( - supp_audio_contexts, len, value); - /* Just store if for now */ - leAudioDevice->SetSupportedContexts(supp_audio_contexts.snk_supp_cont, - supp_audio_contexts.src_supp_cont); - - btif_storage_set_leaudio_supported_context_types( - leAudioDevice->address_, supp_audio_contexts.snk_supp_cont.value(), - supp_audio_contexts.src_supp_cont.value()); - } else if (hdl == leAudioDevice->ctp_hdls_.val_hdl) { - auto ntf = - std::make_unique(); + AttachToStreamingGroupIfNeeded(leAudioDevice); - if (ParseAseCtpNotification(*ntf, len, value)) - ControlPointNotificationHandler(*ntf); + } else if (hdl == leAudioDevice->audio_supp_cont_hdls_.val_hdl) { + BidirectionalPair supp_audio_contexts; + if (le_audio::client_parser::pacs::ParseSupportedAudioContexts( + supp_audio_contexts, len, value)) { + /* Just store if for now */ + leAudioDevice->SetSupportedContexts(supp_audio_contexts); + + btif_storage_set_leaudio_supported_context_types( + leAudioDevice->address_, supp_audio_contexts.sink.value(), + supp_audio_contexts.source.value()); + } + } else if (hdl == leAudioDevice->ctp_hdls_.val_hdl) { + groupStateMachine_->ProcessGattCtpNotification(group, value, len); } else if (hdl == leAudioDevice->tmap_role_hdl_) { le_audio::client_parser::tmap::ParseTmapRole(leAudioDevice->tmap_role_, len, value); @@ -1878,12 +1896,19 @@ class LeAudioClientImpl : public LeAudioClient { /* If device belongs to streaming group, add it on allow list */ auto address = leAudioDevice->address_; auto group = GetGroupIfEnabled(leAudioDevice->group_id_); + if (group == nullptr) { + LOG_INFO("Group %d is invalid or disabled ", leAudioDevice->group_id_); + return; + } - if (group != nullptr && group->IsAnyDeviceConnected()) { + leAudioDevice->SetConnectionState( + DeviceConnectState::CONNECTING_AUTOCONNECT); + + /* Cancel previous bakcground connect */ + BTA_GATTC_CancelOpen(gatt_if_, address, false); + if (group->IsAnyDeviceConnected()) { LOG_INFO("Group %d in connected state. Adding %s to allow list ", leAudioDevice->group_id_, ADDRESS_TO_LOGGABLE_CSTR(address)); - /* Make sure TA is canceled before adding to allow list */ - BTA_GATTC_CancelOpen(gatt_if_, address, false); BTA_GATTC_Open(gatt_if_, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); } else { LOG_INFO( @@ -1899,20 +1924,35 @@ class LeAudioClientImpl : public LeAudioClient { tBT_TRANSPORT transport, uint16_t mtu) { LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address); - if (!leAudioDevice) return; + LOG_INFO("%s, conn_id=0x%04x, transport=%s, status=%s (0x%02x)", + ADDRESS_TO_LOGGABLE_CSTR(address), conn_id, + bt_transport_text(transport).c_str(), + gatt_status_text(status).c_str(), status); - LOG_INFO("%s, status 0x%02x", ADDRESS_TO_LOGGABLE_CSTR(address), status); + if (transport != BT_TRANSPORT_LE) { + LOG_WARN("Only LE connection is allowed (transport %s)", + bt_transport_text(transport).c_str()); + BTA_GATTC_Close(conn_id); + return; + } - /* Remove device from the background connect (it might be either Allow list - * or TA) and it will be added back on disconnection - */ - BTA_GATTC_CancelOpen(gatt_if_, address, false); + if (!leAudioDevice) return; + + if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID) { + LOG_DEBUG("Already connected %s, conn_id=0x%04x", + ADDRESS_TO_LOGGABLE_CSTR(address), leAudioDevice->conn_id_); + return; + } if (status != GATT_SUCCESS) { + /* Clear current connection request and let it be set again if needed */ + BTA_GATTC_CancelOpen(gatt_if_, address, false); + /* autoconnect connection failed, that's ok */ - if (leAudioDevice->GetConnectionState() == - DeviceConnectState::CONNECTING_AUTOCONNECT || - leAudioDevice->autoconnect_flag_) { + if (status != GATT_ILLEGAL_PARAMETER && + (leAudioDevice->GetConnectionState() == + DeviceConnectState::CONNECTING_AUTOCONNECT || + leAudioDevice->autoconnect_flag_)) { LOG_INFO("Device not available now, do background connect."); leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED); AddToBackgroundConnectCheckGroupConnected(leAudioDevice); @@ -1921,8 +1961,8 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED); - LOG(ERROR) << "Failed to connect to LeAudio leAudioDevice, status: " - << +status; + LOG_ERROR("Failed to connect to LeAudio leAudioDevice, status: 0x%02x", + status); callbacks_->OnConnectionState(ConnectionState::DISCONNECTED, address); le_audio::MetricsCollector::Get()->OnConnectionStateChanged( leAudioDevice->group_id_, address, ConnectionState::CONNECTED, @@ -1933,6 +1973,8 @@ class LeAudioClientImpl : public LeAudioClient { if (leAudioDevice->group_id_ != bluetooth::groups::kGroupUnknown) { auto group = GetGroupIfEnabled(leAudioDevice->group_id_); if (group == nullptr) { + BTA_GATTC_CancelOpen(gatt_if_, address, false); + LOG_WARN( "LeAudio profile is disabled for group_id: %d. %s is not connected", leAudioDevice->group_id_, ADDRESS_TO_LOGGABLE_CSTR(address)); @@ -1940,6 +1982,17 @@ class LeAudioClientImpl : public LeAudioClient { } } + leAudioDevice->conn_id_ = conn_id; + leAudioDevice->mtu_ = mtu; + + /* Remove device from the background connect (it might be either Allow list + * or TA) and add it again with reconnection_mode_. In case it is TA, we are + * sure that device will not be in the allow list for other applications + * which are using background connect. + */ + BTA_GATTC_CancelOpen(gatt_if_, address, false); + BTA_GATTC_Open(gatt_if_, address, reconnection_mode_, false); + if (controller_get_interface()->supports_ble_2m_phy()) { LOG(INFO) << ADDRESS_TO_LOGGABLE_STR(address) << " set preferred PHY to 2M"; @@ -1957,9 +2010,8 @@ class LeAudioClientImpl : public LeAudioClient { DeviceConnectState::CONNECTED_BY_USER_GETTING_READY); } - leAudioDevice->conn_id_ = conn_id; - leAudioDevice->mtu_ = mtu; - + /* Check if the device is in allow list and update the flag */ + leAudioDevice->UpdateDeviceAllowlistFlag(); if (BTM_SecIsSecurityPending(address)) { /* if security collision happened, wait for encryption done * (BTA_GATTC_ENC_CMPL_CB_EVT) */ @@ -1973,22 +2025,26 @@ class LeAudioClientImpl : public LeAudioClient { return; } - if (BTM_IsLinkKeyKnown(address, BT_TRANSPORT_LE)) { - int result = BTM_SetEncryption(address, BT_TRANSPORT_LE, nullptr, nullptr, - BTM_BLE_SEC_ENCRYPT); + int result = BTM_SetEncryption(address, BT_TRANSPORT_LE, nullptr, nullptr, + BTM_BLE_SEC_ENCRYPT); - LOG(INFO) << __func__ - << "Encryption required. Request result: " << result; - return; - } + LOG_INFO("Encryption required for %s. Request result: 0x%02x", + ADDRESS_TO_LOGGABLE_CSTR(address), result); - LOG(ERROR) << __func__ << " Encryption error"; - le_audio::MetricsCollector::Get()->OnConnectionStateChanged( - leAudioDevice->group_id_, address, ConnectionState::CONNECTED, - le_audio::ConnectionStatus::FAILED); + if (result == BTM_ERR_KEY_MISSING) { + LOG_ERROR("Link key unknown for %s, disconnect profile", + ADDRESS_TO_LOGGABLE_CSTR(address)); + le_audio::MetricsCollector::Get()->OnConnectionStateChanged( + leAudioDevice->group_id_, address, ConnectionState::CONNECTED, + le_audio::ConnectionStatus::FAILED); + + /* If link cannot be enctypted, disconnect profile */ + BTA_GATTC_Close(conn_id); + } } - void RegisterKnownNotifications(LeAudioDevice* leAudioDevice) { + void RegisterKnownNotifications(LeAudioDevice* leAudioDevice, + bool gatt_register, bool write_ccc) { LOG(INFO) << __func__ << " device: " << ADDRESS_TO_LOGGABLE_STR(leAudioDevice->address_); @@ -2002,48 +2058,50 @@ class LeAudioClientImpl : public LeAudioClient { /* GATTC will ommit not registered previously handles */ for (auto pac_tuple : leAudioDevice->snk_pacs_) { - subscribe_for_notification(leAudioDevice->conn_id_, - leAudioDevice->address_, - std::get<0>(pac_tuple)); + subscribe_for_notification( + leAudioDevice->conn_id_, leAudioDevice->address_, + std::get<0>(pac_tuple), gatt_register, write_ccc); } for (auto pac_tuple : leAudioDevice->src_pacs_) { - subscribe_for_notification(leAudioDevice->conn_id_, - leAudioDevice->address_, - std::get<0>(pac_tuple)); + subscribe_for_notification( + leAudioDevice->conn_id_, leAudioDevice->address_, + std::get<0>(pac_tuple), gatt_register, write_ccc); } if (leAudioDevice->snk_audio_locations_hdls_.val_hdl != 0) - subscribe_for_notification(leAudioDevice->conn_id_, - leAudioDevice->address_, - leAudioDevice->snk_audio_locations_hdls_); + subscribe_for_notification( + leAudioDevice->conn_id_, leAudioDevice->address_, + leAudioDevice->snk_audio_locations_hdls_, gatt_register, write_ccc); if (leAudioDevice->src_audio_locations_hdls_.val_hdl != 0) - subscribe_for_notification(leAudioDevice->conn_id_, - leAudioDevice->address_, - leAudioDevice->src_audio_locations_hdls_); + subscribe_for_notification( + leAudioDevice->conn_id_, leAudioDevice->address_, + leAudioDevice->src_audio_locations_hdls_, gatt_register, write_ccc); if (leAudioDevice->audio_avail_hdls_.val_hdl != 0) - subscribe_for_notification(leAudioDevice->conn_id_, - leAudioDevice->address_, - leAudioDevice->audio_avail_hdls_); + subscribe_for_notification( + leAudioDevice->conn_id_, leAudioDevice->address_, + leAudioDevice->audio_avail_hdls_, gatt_register, write_ccc); if (leAudioDevice->audio_supp_cont_hdls_.val_hdl != 0) - subscribe_for_notification(leAudioDevice->conn_id_, - leAudioDevice->address_, - leAudioDevice->audio_supp_cont_hdls_); + subscribe_for_notification( + leAudioDevice->conn_id_, leAudioDevice->address_, + leAudioDevice->audio_supp_cont_hdls_, gatt_register, write_ccc); for (struct ase& ase : leAudioDevice->ases_) subscribe_for_notification(leAudioDevice->conn_id_, - leAudioDevice->address_, ase.hdls); + leAudioDevice->address_, ase.hdls, + gatt_register, write_ccc); subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, - leAudioDevice->ctp_hdls_); + leAudioDevice->ctp_hdls_, gatt_register, + write_ccc); } void changeMtuIfPossible(LeAudioDevice* leAudioDevice) { if (leAudioDevice->mtu_ == GATT_DEF_BLE_MTU_SIZE) { LOG(INFO) << __func__ << ", Configure MTU"; /* Use here kBapMinimumAttMtu, because we know that GATT will request - * GATT_MAX_MTU_SIZE on ATT anyways. We also know that GATT will use this + * default ATT MTU anyways. We also know that GATT will use this * kBapMinimumAttMtu as an input for Data Length Update procedure in the controller. */ BtaGattQueue::ConfigureMtu(leAudioDevice->conn_id_, kBapMinimumAttMtu); @@ -2084,11 +2142,23 @@ class LeAudioClientImpl : public LeAudioClient { changeMtuIfPossible(leAudioDevice); + leAudioDevice->encrypted_ = true; + /* If we know services, register for notifications */ - if (leAudioDevice->known_service_handles_) - RegisterKnownNotifications(leAudioDevice); + if (leAudioDevice->known_service_handles_) { + /* This registration will do subscribtion in local GATT as we + * assume remote device keeps bonded CCC values. + */ + RegisterKnownNotifications(leAudioDevice, true, false); - leAudioDevice->encrypted_ = true; + /* Make sure remote keeps CCC values as per specification. + * We read only ctp_ccc value. If that one is good, we assume + * remote keeps CCC values correctly. + */ + BtaGattQueue::ReadCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.ccc_hdl, + OnGattCtpCccReadRspStatic, NULL); + } /* If we know services and read is not ongoing, this is reconnection and * just notify connected */ @@ -2115,8 +2185,15 @@ class LeAudioClientImpl : public LeAudioClient { * announcements) */ auto group = aseGroups_.FindById(group_id); - if (group == nullptr || !group->IsAnyDeviceConnected()) { - LOG_INFO("Group %d is not streaming", group_id); + if (group == nullptr) { + LOG_INFO("Group %d is destroyed.", group_id); + return; + } + + if (!group->IsAnyDeviceConnected()) { + LOG_INFO("Group %d is not connected", group_id); + /* Make sure all devices are in the default reconnection mode */ + group->ApplyReconnectionMode(gatt_if_, reconnection_mode_); return; } @@ -2133,7 +2210,7 @@ class LeAudioClientImpl : public LeAudioClient { FROM_HERE, base::BindOnce( &LeAudioClientImpl::checkGroupConnectionStateAfterMemberDisconnect, - base::Unretained(this), group_id), + weak_factory_.GetWeakPtr(), group_id), #if BASE_VER < 931007 base::TimeDelta::FromMilliseconds(kGroupConnectedWatchDelayMs) #else @@ -2157,8 +2234,8 @@ class LeAudioClientImpl : public LeAudioClient { LOG_INFO("Schedule auto connect %s ", ADDRESS_TO_LOGGABLE_CSTR(address)); do_in_main_thread_delayed( FROM_HERE, - base::BindOnce(&LeAudioClientImpl::autoConnect, base::Unretained(this), - address), + base::BindOnce(&LeAudioClientImpl::autoConnect, + weak_factory_.GetWeakPtr(), address), #if BASE_VER < 931007 base::TimeDelta::FromMilliseconds(kAutoConnectAfterOwnDisconnectDelayMs) #else @@ -2197,7 +2274,7 @@ class LeAudioClientImpl : public LeAudioClient { do_in_main_thread_delayed( FROM_HERE, base::BindOnce(&LeAudioClientImpl::recoveryReconnect, - base::Unretained(this), address), + weak_factory_.GetWeakPtr(), address), #if BASE_VER < 931007 base::TimeDelta::FromMilliseconds(kRecoveryReconnectDelayMs) #else @@ -2206,18 +2283,59 @@ class LeAudioClientImpl : public LeAudioClient { ); } - void OnGattDisconnected(uint16_t conn_id, tGATT_IF client_if, - RawAddress address, tGATT_DISCONN_REASON reason) { - LeAudioDevice* leAudioDevice = leAudioDevices_.FindByConnId(conn_id); + void checkIfGroupMember(RawAddress address) { + LOG_INFO("checking being a group member: %s", + ADDRESS_TO_LOGGABLE_CSTR(address)); + LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address); - if (!leAudioDevice) { - LOG(ERROR) << ", skipping unknown leAudioDevice, address: " - << ADDRESS_TO_LOGGABLE_STR(address); + if (leAudioDevice == nullptr) { + LOG_WARN("Device %s, probably removed", + ADDRESS_TO_LOGGABLE_CSTR(address)); return; } - BtaGattQueue::Clean(leAudioDevice->conn_id_); - LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); + if (leAudioDevice->group_id_ == bluetooth::groups::kGroupUnknown) { + disconnectInvalidDevice(leAudioDevice, + ", device not a valid group member", + LeAudioHealthDeviceStatType::INVALID_CSIS); + return; + } + } + + /* This is called, when CSIS native module is about to add device to the + * group once the CSIS service will be verified on the remote side. + * After some time (kCsisGroupMemberDelayMs) a checkIfGroupMember will be + * called and will verify if the remote device has a group_id properly set. + * if not, it means there is something wrong with CSIS service on the remote + * side. + */ + void scheduleGuardForCsisAdd(RawAddress& address) { + LOG_INFO("Schedule reconnecting to %s after timeout on state machine.", + ADDRESS_TO_LOGGABLE_CSTR(address)); + do_in_main_thread_delayed( + FROM_HERE, + base::BindOnce(&LeAudioClientImpl::checkIfGroupMember, + weak_factory_.GetWeakPtr(), address), +#if BASE_VER < 931007 + base::TimeDelta::FromMilliseconds(kCsisGroupMemberDelayMs) +#else + base::Milliseconds(kCsisGroupMemberDelayMs) +#endif + ); + } + + void OnGattDisconnected(uint16_t conn_id, tGATT_IF client_if, + RawAddress address, tGATT_DISCONN_REASON reason) { + LeAudioDevice* leAudioDevice = leAudioDevices_.FindByConnId(conn_id); + + if (!leAudioDevice) { + LOG(ERROR) << ", skipping unknown leAudioDevice, address: " + << ADDRESS_TO_LOGGABLE_STR(address); + return; + } + + BtaGattQueue::Clean(leAudioDevice->conn_id_); + LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); DeregisterNotifications(leAudioDevice); @@ -2259,6 +2377,8 @@ class LeAudioClientImpl : public LeAudioClient { return; } + leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED); + /* Attempt background re-connect if disconnect was not initiated locally * or if autoconnect is set and device got disconnected because of some * issues @@ -2266,7 +2386,6 @@ class LeAudioClientImpl : public LeAudioClient { if (group == nullptr || !group->IsEnabled()) { LOG_ERROR("Group id %d (%p) disabled or null", leAudioDevice->group_id_, group); - leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED); return; } @@ -2274,9 +2393,6 @@ class LeAudioClientImpl : public LeAudioClient { if (leAudioDevice->autoconnect_flag_) { /* In this case ACL might not yet been disconnected */ scheduleAutoConnect(address); - } else { - /* Just acknowledge disconnected state*/ - leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED); } return; } @@ -2294,39 +2410,42 @@ class LeAudioClientImpl : public LeAudioClient { /* In other disconnect resons we act based on the autoconnect_flag_ */ if (leAudioDevice->autoconnect_flag_) { - leAudioDevice->SetConnectionState( - DeviceConnectState::CONNECTING_AUTOCONNECT); - - BTA_GATTC_Open(gatt_if_, address, reconnection_mode_, false); if (group->IsAnyDeviceConnected()) { /* If all set is disconnecting, let's give it some time. * If not all get disconnected, and there will be group member * connected we want to put disconnected devices to allow list */ scheduleGroupConnectedCheck(leAudioDevice->group_id_); + } else { + group->ApplyReconnectionMode(gatt_if_, reconnection_mode_); } - } else { - /* Just acknowledge disconnected state*/ - leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED); } } - bool subscribe_for_notification( - uint16_t conn_id, const RawAddress& address, - struct le_audio::types::hdl_pair handle_pair) { + bool subscribe_for_notification(uint16_t conn_id, const RawAddress& address, + struct le_audio::types::hdl_pair handle_pair, + bool gatt_register = true, + bool write_ccc = true) { std::vector value(2); uint8_t* ptr = value.data(); uint16_t handle = handle_pair.val_hdl; uint16_t ccc_handle = handle_pair.ccc_hdl; - LOG_INFO("conn id %d", conn_id); - if (BTA_GATTC_RegisterForNotifications(gatt_if_, address, handle) != - GATT_SUCCESS) { + LOG_INFO("conn id %d, gatt_register: %b, write_ccc: %b", conn_id, + gatt_register, write_ccc); + if (gatt_register && BTA_GATTC_RegisterForNotifications( + gatt_if_, address, handle) != GATT_SUCCESS) { LOG(ERROR) << __func__ << ", cannot register for notification: " << static_cast(handle); return false; } + if (write_ccc == false) { + LOG_VERBOSE("CCC is not written to %s (0x%04x), handle 0x%04x", + ADDRESS_TO_LOGGABLE_CSTR(address), conn_id, ccc_handle); + return true; + } + UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION); BtaGattQueue::WriteDescriptor( @@ -2375,7 +2494,7 @@ class LeAudioClientImpl : public LeAudioClient { DeviceConnectState::CONNECTED_BY_USER_GETTING_READY); } - btif_storage_remove_leaudio(leAudioDevice->address_); + btif_storage_leaudio_clear_service_data(leAudioDevice->address_); BTA_GATTC_ServiceSearchRequest( leAudioDevice->conn_id_, @@ -2384,12 +2503,21 @@ class LeAudioClientImpl : public LeAudioClient { void OnServiceChangeEvent(const RawAddress& address) { LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address); - if (!leAudioDevice || (leAudioDevice->conn_id_ == GATT_INVALID_CONN_ID)) { + if (!leAudioDevice) { LOG_WARN("Skipping unknown leAudioDevice %s (%p)", ADDRESS_TO_LOGGABLE_CSTR(address), leAudioDevice); return; } - ClearDeviceInformationAndStartSearch(leAudioDevice); + + if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID) { + ClearDeviceInformationAndStartSearch(leAudioDevice); + return; + } + + /* If device is not connected, just clear the handle information and this + * will trigger service search onGattConnected */ + leAudioDevice->known_service_handles_ = false; + btif_storage_leaudio_clear_service_data(address); } void OnMtuChanged(uint16_t conn_id, uint16_t mtu) { @@ -2435,6 +2563,18 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->conn_id_, &le_audio::uuid::kPublishedAudioCapabilityServiceUuid); } + + void disconnectInvalidDevice(LeAudioDevice* leAudioDevice, + std::string error_string, + LeAudioHealthDeviceStatType stat) { + LOG_ERROR("%s, %s", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), + error_string.c_str()); + if (leAudioHealthStatus_) { + leAudioHealthStatus_->AddStatisticForDevice(leAudioDevice, stat); + } + DisconnectDevice(leAudioDevice); + } + /* This method is called after connection beginning to identify and initialize * a le audio device. Any missing mandatory attribute will result in reverting * and cleaning up device. @@ -2459,6 +2599,11 @@ class LeAudioClientImpl : public LeAudioClient { return; } + if (!leAudioDevice->encrypted_) { + LOG_WARN("Device not yet bonded - waiting for encryption"); + return; + } + const std::list* services = BTA_GATTC_GetServices(conn_id); const gatt::Service* pac_svc = nullptr; @@ -2470,19 +2615,23 @@ class LeAudioClientImpl : public LeAudioClient { for (const gatt::Service& tmp : *services) { if (tmp.uuid == le_audio::uuid::kPublishedAudioCapabilityServiceUuid) { - LOG(INFO) << "Found Audio Capability service, handle: " - << loghex(tmp.handle); + LOG_INFO("Found Audio Capability service, handle: 0x%04x, device: %s", + tmp.handle, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); pac_svc = &tmp; } else if (tmp.uuid == le_audio::uuid::kAudioStreamControlServiceUuid) { - LOG(INFO) << "Found Audio Stream Endpoint service, handle: " - << loghex(tmp.handle); + LOG_INFO( + "Found Audio Stream Endpoint service, handle: 0x%04x, device: %s", + tmp.handle, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); ase_svc = &tmp; } else if (tmp.uuid == bluetooth::csis::kCsisServiceUuid) { - LOG(INFO) << "Found CSIS service, handle: " << loghex(tmp.handle) - << " is primary? " << tmp.is_primary; + LOG_INFO( + "Found CSIS service, handle: 0x%04x, is primary: %d, device: %s", + tmp.handle, tmp.is_primary, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); if (tmp.is_primary) csis_primary_handles.push_back(tmp.handle); } else if (tmp.uuid == le_audio::uuid::kCapServiceUuid) { - LOG(INFO) << "Found CAP Service, handle: " << loghex(tmp.handle); + LOG_INFO("Found CAP service, handle: 0x%04x, device: %s", tmp.handle, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); /* Try to find context for CSIS instances */ for (auto& included_srvc : tmp.included_services) { @@ -2495,8 +2644,10 @@ class LeAudioClientImpl : public LeAudioClient { } } } else if (tmp.uuid == le_audio::uuid::kTelephonyMediaAudioServiceUuid) { - LOG_INFO(", Found Telephony and Media Audio service, handle: %04x", - tmp.handle); + LOG_INFO( + "Found Telephony and Media Audio service, handle: 0x%04x, device: " + "%s", + tmp.handle, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); tmas_svc = &tmp; } } @@ -2511,9 +2662,9 @@ class LeAudioClientImpl : public LeAudioClient { } if (!pac_svc || !ase_svc) { - LOG(ERROR) << "No mandatory le audio services found"; - - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice( + leAudioDevice, "No mandatory le audio services found (pacs or ascs)", + LeAudioHealthDeviceStatType::INVALID_DB); return; } @@ -2528,15 +2679,15 @@ class LeAudioClientImpl : public LeAudioClient { hdl_pair.ccc_hdl = find_ccc_handle(charac); if (hdl_pair.ccc_hdl == 0) { - LOG(ERROR) << __func__ << ", snk pac char doesn't have ccc"; - - DisconnectDevice(leAudioDevice); - return; + LOG_INFO(", Sink PACs ccc not available"); } - if (!subscribe_for_notification(conn_id, leAudioDevice->address_, + if (hdl_pair.ccc_hdl != 0 && + !subscribe_for_notification(conn_id, leAudioDevice->address_, hdl_pair)) { - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice(leAudioDevice, + ", cound not subscribe for snk pac char", + LeAudioHealthDeviceStatType::INVALID_DB); return; } @@ -2547,9 +2698,11 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->snk_pacs_.push_back(std::make_tuple( hdl_pair, std::vector())); - LOG(INFO) << "Found Sink PAC characteristic, handle: " - << loghex(charac.value_handle) - << ", ccc handle: " << loghex(hdl_pair.ccc_hdl); + LOG_INFO( + "Found Sink PAC characteristic, handle: 0x%04x, ccc handle: " + "0x%04x, addr: %s", + charac.value_handle, hdl_pair.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } else if (charac.uuid == le_audio::uuid:: kSourcePublishedAudioCapabilityCharacteristicUuid) { @@ -2558,15 +2711,15 @@ class LeAudioClientImpl : public LeAudioClient { hdl_pair.ccc_hdl = find_ccc_handle(charac); if (hdl_pair.ccc_hdl == 0) { - LOG(ERROR) << __func__ << ", src pac char doesn't have ccc"; - - DisconnectDevice(leAudioDevice); - return; + LOG_INFO(", Source PACs ccc not available"); } - if (!subscribe_for_notification(conn_id, leAudioDevice->address_, + if (hdl_pair.ccc_hdl != 0 && + !subscribe_for_notification(conn_id, leAudioDevice->address_, hdl_pair)) { - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice(leAudioDevice, + ", could not subscribe for src pac char", + LeAudioHealthDeviceStatType::INVALID_DB); return; } @@ -2577,25 +2730,28 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->src_pacs_.push_back(std::make_tuple( hdl_pair, std::vector())); - LOG(INFO) << "Found Source PAC characteristic, handle: " - << loghex(charac.value_handle) - << ", ccc handle: " << loghex(hdl_pair.ccc_hdl); + LOG_INFO( + "Found Source PAC characteristic, handle: 0x%04x, ccc handle: " + "0x%04x, addr: %s", + charac.value_handle, hdl_pair.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } else if (charac.uuid == le_audio::uuid::kSinkAudioLocationCharacteristicUuid) { leAudioDevice->snk_audio_locations_hdls_.val_hdl = charac.value_handle; leAudioDevice->snk_audio_locations_hdls_.ccc_hdl = find_ccc_handle(charac); - if (leAudioDevice->snk_audio_locations_hdls_.ccc_hdl == 0) - LOG(INFO) << __func__ - << ", snk audio locations char doesn't have" - "ccc"; + if (leAudioDevice->snk_audio_locations_hdls_.ccc_hdl == 0) { + LOG_INFO(", snk audio locations char doesn't have ccc"); + } if (leAudioDevice->snk_audio_locations_hdls_.ccc_hdl != 0 && !subscribe_for_notification( conn_id, leAudioDevice->address_, leAudioDevice->snk_audio_locations_hdls_)) { - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice( + leAudioDevice, ", could not subscribe for snk locations char", + LeAudioHealthDeviceStatType::INVALID_DB); return; } @@ -2604,25 +2760,29 @@ class LeAudioClientImpl : public LeAudioClient { conn_id, leAudioDevice->snk_audio_locations_hdls_.val_hdl, OnGattReadRspStatic, NULL); - LOG(INFO) << "Found Sink audio locations characteristic, handle: " - << loghex(charac.value_handle) << ", ccc handle: " - << loghex(leAudioDevice->snk_audio_locations_hdls_.ccc_hdl); + LOG_INFO( + "Found Sink audio locations characteristic, handle: 0x%04x, ccc " + "handle: 0x%04x, addr: %s", + charac.value_handle, + leAudioDevice->snk_audio_locations_hdls_.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } else if (charac.uuid == le_audio::uuid::kSourceAudioLocationCharacteristicUuid) { leAudioDevice->src_audio_locations_hdls_.val_hdl = charac.value_handle; leAudioDevice->src_audio_locations_hdls_.ccc_hdl = find_ccc_handle(charac); - if (leAudioDevice->src_audio_locations_hdls_.ccc_hdl == 0) - LOG(INFO) << __func__ - << ", snk audio locations char doesn't have" - "ccc"; + if (leAudioDevice->src_audio_locations_hdls_.ccc_hdl == 0) { + LOG_INFO(", src audio locations char doesn't have ccc"); + } if (leAudioDevice->src_audio_locations_hdls_.ccc_hdl != 0 && !subscribe_for_notification( conn_id, leAudioDevice->address_, leAudioDevice->src_audio_locations_hdls_)) { - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice( + leAudioDevice, ", could not subscribe for src locations char", + LeAudioHealthDeviceStatType::INVALID_DB); return; } @@ -2631,24 +2791,29 @@ class LeAudioClientImpl : public LeAudioClient { conn_id, leAudioDevice->src_audio_locations_hdls_.val_hdl, OnGattReadRspStatic, NULL); - LOG(INFO) << "Found Source audio locations characteristic, handle: " - << loghex(charac.value_handle) << ", ccc handle: " - << loghex(leAudioDevice->src_audio_locations_hdls_.ccc_hdl); + LOG_INFO( + "Found Source audio locations characteristic, handle: 0x%04x, ccc " + "handle: 0x%04x, addr: %s", + charac.value_handle, + leAudioDevice->src_audio_locations_hdls_.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } else if (charac.uuid == le_audio::uuid::kAudioContextAvailabilityCharacteristicUuid) { leAudioDevice->audio_avail_hdls_.val_hdl = charac.value_handle; leAudioDevice->audio_avail_hdls_.ccc_hdl = find_ccc_handle(charac); if (leAudioDevice->audio_avail_hdls_.ccc_hdl == 0) { - LOG(ERROR) << __func__ << ", audio avails char doesn't have ccc"; - - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice(leAudioDevice, + ", audio avails char doesn't have ccc", + LeAudioHealthDeviceStatType::INVALID_DB); return; } if (!subscribe_for_notification(conn_id, leAudioDevice->address_, leAudioDevice->audio_avail_hdls_)) { - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice(leAudioDevice, + ", could not subscribe for audio avails char", + LeAudioHealthDeviceStatType::INVALID_DB); return; } @@ -2657,21 +2822,27 @@ class LeAudioClientImpl : public LeAudioClient { conn_id, leAudioDevice->audio_avail_hdls_.val_hdl, OnGattReadRspStatic, NULL); - LOG(INFO) << "Found Audio Availability Context characteristic, handle: " - << loghex(charac.value_handle) << ", ccc handle: " - << loghex(leAudioDevice->audio_avail_hdls_.ccc_hdl); + LOG_INFO( + "Found Audio Availability Context characteristic, handle: 0x%04x, " + "ccc handle: 0x%04x, addr: %s", + charac.value_handle, leAudioDevice->audio_avail_hdls_.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } else if (charac.uuid == le_audio::uuid::kAudioSupportedContextCharacteristicUuid) { leAudioDevice->audio_supp_cont_hdls_.val_hdl = charac.value_handle; leAudioDevice->audio_supp_cont_hdls_.ccc_hdl = find_ccc_handle(charac); - if (leAudioDevice->audio_supp_cont_hdls_.ccc_hdl == 0) - LOG(INFO) << __func__ << ", audio avails char doesn't have ccc"; + if (leAudioDevice->audio_supp_cont_hdls_.ccc_hdl == 0) { + LOG_INFO(", audio supported char doesn't have ccc"); + } if (leAudioDevice->audio_supp_cont_hdls_.ccc_hdl != 0 && !subscribe_for_notification(conn_id, leAudioDevice->address_, leAudioDevice->audio_supp_cont_hdls_)) { - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice( + leAudioDevice, + ", could not subscribe for audio supported ctx char", + LeAudioHealthDeviceStatType::INVALID_DB); return; } @@ -2680,9 +2851,11 @@ class LeAudioClientImpl : public LeAudioClient { conn_id, leAudioDevice->audio_supp_cont_hdls_.val_hdl, OnGattReadRspStatic, NULL); - LOG(INFO) << "Found Audio Supported Context characteristic, handle: " - << loghex(charac.value_handle) << ", ccc handle: " - << loghex(leAudioDevice->audio_supp_cont_hdls_.ccc_hdl); + LOG_INFO( + "Found Audio Supported Context characteristic, handle: 0x%04x, ccc " + "handle: 0x%04x, addr: %s", + charac.value_handle, leAudioDevice->audio_supp_cont_hdls_.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } } @@ -2695,15 +2868,16 @@ class LeAudioClientImpl : public LeAudioClient { charac.uuid == le_audio::uuid::kSourceAudioStreamEndpointUuid) { uint16_t ccc_handle = find_ccc_handle(charac); if (ccc_handle == 0) { - LOG(ERROR) << __func__ << ", audio avails char doesn't have ccc"; - - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice(leAudioDevice, ", ASE char doesn't have ccc", + LeAudioHealthDeviceStatType::INVALID_DB); return; } struct le_audio::types::hdl_pair hdls(charac.value_handle, ccc_handle); if (!subscribe_for_notification(conn_id, leAudioDevice->address_, hdls)) { - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice(leAudioDevice, + ", could not subscribe ASE char", + LeAudioHealthDeviceStatType::INVALID_DB); return; } @@ -2715,10 +2889,11 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->ases_.emplace_back(charac.value_handle, ccc_handle, direction); - LOG(INFO) << "Found ASE characteristic, handle: " - << loghex(charac.value_handle) - << ", ccc handle: " << loghex(ccc_handle) - << ", direction: " << direction; + LOG_INFO( + "Found ASE characteristic, handle: 0x%04x, ccc handle: 0x%04x, " + "direction: %d, addr: %s", + charac.value_handle, ccc_handle, direction, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } else if (charac.uuid == le_audio::uuid:: kAudioStreamEndpointControlPointCharacteristicUuid) { @@ -2726,21 +2901,24 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->ctp_hdls_.ccc_hdl = find_ccc_handle(charac); if (leAudioDevice->ctp_hdls_.ccc_hdl == 0) { - LOG(ERROR) << __func__ << ", ase ctp doesn't have ccc"; - - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice(leAudioDevice, ", ASE ctp doesn't have ccc", + LeAudioHealthDeviceStatType::INVALID_DB); return; } if (!subscribe_for_notification(conn_id, leAudioDevice->address_, leAudioDevice->ctp_hdls_)) { - DisconnectDevice(leAudioDevice); + disconnectInvalidDevice(leAudioDevice, + ", could not subscribe ASE char", + LeAudioHealthDeviceStatType::INVALID_DB); return; } - LOG(INFO) << "Found ASE Control Point characteristic, handle: " - << loghex(charac.value_handle) << ", ccc handle: " - << loghex(leAudioDevice->ctp_hdls_.ccc_hdl); + LOG_INFO( + "Found ASE Control Point characteristic, handle: 0x%04x, " + "ccc handle: 0x%04x, addr: %s", + charac.value_handle, leAudioDevice->ctp_hdls_.ccc_hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } } @@ -2756,17 +2934,21 @@ class LeAudioClientImpl : public LeAudioClient { OnGattReadRspStatic, NULL); LOG_INFO( - ", Found Telephony and Media Profile characteristic, " - "handle: %04x", - leAudioDevice->tmap_role_hdl_); + "Found Telephony and Media Profile characteristic, handle: " + "0x%04x, " + "device: %s", + leAudioDevice->tmap_role_hdl_, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); } } } leAudioDevice->known_service_handles_ = true; - btif_storage_leaudio_update_handles_bin(leAudioDevice->address_); - leAudioDevice->notify_connected_after_read_ = true; + if (leAudioHealthStatus_) { + leAudioHealthStatus_->AddStatisticForDevice( + leAudioDevice, LeAudioHealthDeviceStatType::VALID_DB); + } /* If already known group id */ if (leAudioDevice->group_id_ != bluetooth::groups::kGroupUnknown) { @@ -2787,11 +2969,15 @@ class LeAudioClientImpl : public LeAudioClient { /* CSIS will trigger adding to group */ if (leAudioDevice->csis_member_) { - LOG(INFO) << __func__ << " waiting for CSIS to create group for device " - << ADDRESS_TO_LOGGABLE_STR(leAudioDevice->address_); + LOG_INFO(" %s, waiting for CSIS to create group for device ", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + scheduleGuardForCsisAdd(leAudioDevice->address_); return; } + LOG_INFO("%s Not a CSIS member. Create group by our own", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + /* If there is no Csis just add device by our own */ DeviceGroups::Get()->AddDevice(leAudioDevice->address_, le_audio::uuid::kCapServiceUuid); @@ -2815,8 +3001,8 @@ class LeAudioClientImpl : public LeAudioClient { } if (status == GATT_SUCCESS) { - LOG(INFO) << __func__ - << ", successfully registered on ccc: " << loghex(hdl); + LOG_INFO("Successfully registered on ccc: 0x%04x, device: %s", hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); if (leAudioDevice->ctp_hdls_.ccc_hdl == hdl && leAudioDevice->known_service_handles_ && @@ -2829,9 +3015,10 @@ class LeAudioClientImpl : public LeAudioClient { return; } - LOG(ERROR) << __func__ - << ", Failed to register for indications: " << loghex(hdl) - << ", status: " << loghex((int)(status)); + LOG_ERROR( + "Failed to register for indications: 0x%04x, device: %s, status: " + "0x%02x", + hdl, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), status); ase_it = std::find_if(leAudioDevice->ases_.begin(), leAudioDevice->ases_.end(), @@ -2840,8 +3027,8 @@ class LeAudioClientImpl : public LeAudioClient { }); if (ase_it == leAudioDevice->ases_.end()) { - LOG(ERROR) << __func__ - << ", unknown ccc handle: " << static_cast(hdl); + LOG_ERROR("Unknown ccc handle: 0x%04x, device: %s", hdl, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); return; } @@ -2856,10 +3043,20 @@ class LeAudioClientImpl : public LeAudioClient { return; } + LeAudioDeviceGroup* group = aseGroups_.FindById(active_group_id_); + + auto group_metadata_contexts = + get_bidirectional(group->GetMetadataContexts()); + auto device_available_contexts = leAudioDevice->GetAvailableContexts(); + if (!group_metadata_contexts.test_any(device_available_contexts)) { + LOG_INFO("%s does is not have required context type", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + return; + } + LOG_INFO("Attaching to group: %d", leAudioDevice->group_id_); /* Restore configuration */ - LeAudioDeviceGroup* group = aseGroups_.FindById(active_group_id_); auto* stream_conf = &group->stream_conf; if (audio_sender_state_ == AudioState::IDLE && @@ -2878,7 +3075,8 @@ class LeAudioClientImpl : public LeAudioClient { get_num_of_devices_in_configuration(stream_conf->conf); if (num_of_devices < group->NumOfConnected() && - !group->IsConfigurationSupported(leAudioDevice, stream_conf->conf)) { + !group->IsAudioSetConfigurationSupported(leAudioDevice, + stream_conf->conf)) { /* Reconfigure if newly connected member device cannot support current * codec configuration */ group->SetPendingConfiguration(); @@ -2888,7 +3086,20 @@ class LeAudioClientImpl : public LeAudioClient { return; } - if (!groupStateMachine_->AttachToStream(group, leAudioDevice)) { + /* Do not put the TBS CCID when not using Telecom for the VoIP calls. */ + auto ccid_contexts = group->GetMetadataContexts(); + if (IsInVoipCall() && !IsInCall()) { + ccid_contexts.sink.unset(LeAudioContextType::CONVERSATIONAL); + ccid_contexts.source.unset(LeAudioContextType::CONVERSATIONAL); + } + BidirectionalPair> ccids = { + .sink = ContentControlIdKeeper::GetInstance()->GetAllCcids( + ccid_contexts.sink), + .source = ContentControlIdKeeper::GetInstance()->GetAllCcids( + ccid_contexts.source)}; + + if (!groupStateMachine_->AttachToStream(group, leAudioDevice, + std::move(ccids))) { LOG_WARN("Could not add device %s to the group %d streaming. ", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), group->group_id_); @@ -2915,7 +3126,7 @@ class LeAudioClientImpl : public LeAudioClient { do_in_main_thread_delayed( FROM_HERE, base::BindOnce(&LeAudioClientImpl::restartAttachToTheStream, - base::Unretained(this), addr), + weak_factory_.GetWeakPtr(), addr), #if BASE_VER < 931007 base::TimeDelta::FromMilliseconds(kDeviceAttachDelayMs) #else @@ -2924,6 +3135,46 @@ class LeAudioClientImpl : public LeAudioClient { ); } + void SendAudioGroupSelectableCodecConfigChanged(LeAudioDeviceGroup* group) { + // This shall be called when device gets active + auto* stream_conf = &group->stream_conf; + if (stream_conf == nullptr) { + LOG_WARN("Stream configuration is not valid for group id %d", + group->group_id_); + return; + } + + auto leAudioDevice = group->GetFirstDevice(); + callbacks_->OnAudioGroupSelectableCodecConf( + group->group_id_, + le_audio::utils::GetRemoteBtLeAudioCodecConfigFromPac( + leAudioDevice->snk_pacs_), + le_audio::utils::GetRemoteBtLeAudioCodecConfigFromPac( + leAudioDevice->src_pacs_)); + } + + void SendAudioGroupCurrentCodecConfigChanged(LeAudioDeviceGroup* group) { + // This shall be called when configuration changes + auto* stream_conf = &group->stream_conf; + if (stream_conf == nullptr) { + LOG_WARN("Stream configuration is not valid for group id %d", + group->group_id_); + return; + } + + bluetooth::le_audio::btle_audio_codec_config_t input_config{}; + le_audio::utils::fillStreamParamsToBtLeAudioCodecConfig( + stream_conf->codec_id, &stream_conf->stream_params.source, + input_config); + + bluetooth::le_audio::btle_audio_codec_config_t output_config{}; + le_audio::utils::fillStreamParamsToBtLeAudioCodecConfig( + stream_conf->codec_id, &stream_conf->stream_params.sink, output_config); + + callbacks_->OnAudioGroupCurrentCodecConf(group->group_id_, input_config, + output_config); + } + void connectionReady(LeAudioDevice* leAudioDevice) { LOG_DEBUG("%s, %s", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), bluetooth::common::ToString(leAudioDevice->GetConnectionState()) @@ -2945,16 +3196,24 @@ class LeAudioClientImpl : public LeAudioClient { if (leAudioDevice->group_id_ != bluetooth::groups::kGroupUnknown) { LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_); - UpdateContextAndLocations(group, leAudioDevice); + if (group) { + UpdateLocationsAndContextsAvailability(group); + } AttachToStreamingGroupIfNeeded(leAudioDevice); + + if (reconnection_mode_ == BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS) { + /* Add other devices to allow list if there are any not yet connected + * from the group + */ + group->AddToAllowListNotConnectedGroupMembers(gatt_if_); + } } } bool IsAseAcceptingAudioData(struct ase* ase) { if (ase == nullptr) return false; if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) return false; - if (ase->data_path_state != AudioStreamDataPathState::DATA_PATH_ESTABLISHED) - return false; + if (ase->data_path_state != DataPathState::CONFIGURED) return false; return true; } @@ -2993,28 +3252,13 @@ class LeAudioClientImpl : public LeAudioClient { void PrepareAndSendToTwoCises( const std::vector& data, - struct le_audio::stream_configuration* stream_conf) { - uint16_t byte_count = stream_conf->sink_octets_per_codec_frame; + const struct le_audio::stream_parameters& stream_params) { uint16_t left_cis_handle = 0; uint16_t right_cis_handle = 0; - uint16_t number_of_required_samples_per_channel; - - int dt_us = current_source_codec_config.data_interval_us; - int af_hz = audio_framework_source_config.sample_rate; - number_of_required_samples_per_channel = lc3_frame_samples(dt_us, af_hz); - - lc3_pcm_format bits_per_sample = - bits_to_lc3_bits(audio_framework_source_config.bits_per_sample); - uint8_t bytes_per_sample = - bits_to_bytes_per_sample(audio_framework_source_config.bits_per_sample); - - for (auto [cis_handle, audio_location] : stream_conf->sink_streams) { - if (audio_location & le_audio::codec_spec_conf::kLeAudioLocationAnyLeft) - left_cis_handle = cis_handle; - if (audio_location & le_audio::codec_spec_conf::kLeAudioLocationAnyRight) - right_cis_handle = cis_handle; - } + uint16_t number_of_required_samples_per_channel = + sw_enc_left->GetNumOfSamplesPerChannel(); + uint8_t bytes_per_sample = sw_enc_left->GetNumOfBytesPerSample(); if (data.size() < bytes_per_sample * 2 /* channels */ * number_of_required_samples_per_channel) { LOG(ERROR) << __func__ << " Missing samples. Data size: " << +data.size() @@ -3024,29 +3268,28 @@ class LeAudioClientImpl : public LeAudioClient { return; } - std::vector chan_left_enc(byte_count, 0); - std::vector chan_right_enc(byte_count, 0); - - bool mono = (left_cis_handle == 0) || (right_cis_handle == 0); + for (auto [cis_handle, audio_location] : stream_params.stream_locations) { + if (audio_location & le_audio::codec_spec_conf::kLeAudioLocationAnyLeft) + left_cis_handle = cis_handle; + if (audio_location & le_audio::codec_spec_conf::kLeAudioLocationAnyRight) + right_cis_handle = cis_handle; + } - if (!mono) { - lc3_encode(lc3_encoder_left, bits_per_sample, data.data(), 2, - chan_left_enc.size(), chan_left_enc.data()); - lc3_encode(lc3_encoder_right, bits_per_sample, - data.data() + bytes_per_sample, 2, chan_right_enc.size(), - chan_right_enc.data()); - } else { + uint16_t byte_count = stream_params.octets_per_codec_frame; + bool mix_to_mono = (left_cis_handle == 0) || (right_cis_handle == 0); + if (mix_to_mono) { std::vector mono = mono_blend( data, bytes_per_sample, number_of_required_samples_per_channel); if (left_cis_handle) { - lc3_encode(lc3_encoder_left, bits_per_sample, mono.data(), 1, - chan_left_enc.size(), chan_left_enc.data()); + sw_enc_left->Encode(mono.data(), 1, byte_count); } if (right_cis_handle) { - lc3_encode(lc3_encoder_right, bits_per_sample, mono.data(), 1, - chan_right_enc.size(), chan_right_enc.data()); + sw_enc_left->Encode(mono.data(), 1, byte_count); } + } else { + sw_enc_left->Encode(data.data(), 2, byte_count); + sw_enc_right->Encode(data.data() + bytes_per_sample, 2, byte_count); } DLOG(INFO) << __func__ << " left_cis_handle: " << +left_cis_handle @@ -3054,59 +3297,50 @@ class LeAudioClientImpl : public LeAudioClient { /* Send data to the controller */ if (left_cis_handle) IsoManager::GetInstance()->SendIsoData( - left_cis_handle, chan_left_enc.data(), chan_left_enc.size()); + left_cis_handle, + (const uint8_t*)sw_enc_left->GetDecodedSamples().data(), + sw_enc_left->GetDecodedSamples().size() * 2); if (right_cis_handle) IsoManager::GetInstance()->SendIsoData( - right_cis_handle, chan_right_enc.data(), chan_right_enc.size()); + right_cis_handle, + (const uint8_t*)sw_enc_right->GetDecodedSamples().data(), + sw_enc_right->GetDecodedSamples().size() * 2); } void PrepareAndSendToSingleCis( const std::vector& data, - struct le_audio::stream_configuration* stream_conf) { - int num_channels = stream_conf->sink_num_of_channels; - uint16_t byte_count = stream_conf->sink_octets_per_codec_frame; - auto cis_handle = stream_conf->sink_streams.front().first; - uint16_t number_of_required_samples_per_channel; - - int dt_us = current_source_codec_config.data_interval_us; - int af_hz = audio_framework_source_config.sample_rate; - number_of_required_samples_per_channel = lc3_frame_samples(dt_us, af_hz); - lc3_pcm_format bits_per_sample = - bits_to_lc3_bits(audio_framework_source_config.bits_per_sample); - uint8_t bytes_per_sample = - bits_to_bytes_per_sample(audio_framework_source_config.bits_per_sample); - - if ((int)data.size() < (2 /* bytes per sample */ * num_channels * + const struct le_audio::stream_parameters& stream_params) { + uint16_t num_channels = stream_params.num_of_channels; + uint16_t cis_handle = stream_params.stream_locations.front().first; + + uint16_t number_of_required_samples_per_channel = + sw_enc_left->GetNumOfSamplesPerChannel(); + uint8_t bytes_per_sample = sw_enc_left->GetNumOfBytesPerSample(); + if ((int)data.size() < (bytes_per_sample * num_channels * number_of_required_samples_per_channel)) { LOG(ERROR) << __func__ << "Missing samples"; return; } - std::vector chan_encoded(num_channels * byte_count, 0); - if (num_channels == 1) { + uint16_t byte_count = stream_params.octets_per_codec_frame; + bool mix_to_mono = (num_channels == 1); + if (mix_to_mono) { /* Since we always get two channels from framework, lets make it mono here */ std::vector mono = mono_blend( data, bytes_per_sample, number_of_required_samples_per_channel); - - auto err = lc3_encode(lc3_encoder_left, bits_per_sample, mono.data(), 1, - byte_count, chan_encoded.data()); - - if (err < 0) { - LOG(ERROR) << " error while encoding, error code: " << +err; - } + sw_enc_left->Encode(mono.data(), 1, byte_count); } else { - lc3_encode(lc3_encoder_left, bits_per_sample, (const int16_t*)data.data(), - 2, byte_count, chan_encoded.data()); - lc3_encode(lc3_encoder_right, bits_per_sample, - (const int16_t*)data.data() + 1, 2, byte_count, - chan_encoded.data() + byte_count); + sw_enc_left->Encode((const uint8_t*)data.data(), 2, byte_count); + // Output to the left channel buffer with `byte_count` offset + sw_enc_right->Encode((const uint8_t*)data.data() + 2, 2, byte_count, + &sw_enc_left->GetDecodedSamples(), byte_count); } - /* Send data to the controller */ - IsoManager::GetInstance()->SendIsoData(cis_handle, chan_encoded.data(), - chan_encoded.size()); + IsoManager::GetInstance()->SendIsoData( + cis_handle, (const uint8_t*)sw_enc_left->GetDecodedSamples().data(), + sw_enc_left->GetDecodedSamples().size() * 2); } const struct le_audio::stream_configuration* GetStreamSinkConfiguration( @@ -3114,7 +3348,7 @@ class LeAudioClientImpl : public LeAudioClient { const struct le_audio::stream_configuration* stream_conf = &group->stream_conf; LOG_INFO("group_id: %d", group->group_id_); - if (stream_conf->sink_streams.size() == 0) { + if (stream_conf->stream_params.sink.stream_locations.size() == 0) { return nullptr; } @@ -3134,27 +3368,26 @@ class LeAudioClientImpl : public LeAudioClient { } auto stream_conf = group->stream_conf; - if ((stream_conf.sink_num_of_devices > 2) || - (stream_conf.sink_num_of_devices == 0) || - stream_conf.sink_streams.empty()) { + if ((stream_conf.stream_params.sink.num_of_devices > 2) || + (stream_conf.stream_params.sink.num_of_devices == 0) || + stream_conf.stream_params.sink.stream_locations.empty()) { LOG(ERROR) << __func__ << " Stream configufation is not valid."; return; } - if (stream_conf.sink_num_of_devices == 2) { - PrepareAndSendToTwoCises(data, &stream_conf); - } else if (stream_conf.sink_streams.size() == 2) { - /* Streaming to one device but 2 CISes */ - PrepareAndSendToTwoCises(data, &stream_conf); + if ((stream_conf.stream_params.sink.num_of_devices == 2) || + (stream_conf.stream_params.sink.stream_locations.size() == 2)) { + /* Streaming to two devices or one device with 2 CISes */ + PrepareAndSendToTwoCises(data, stream_conf.stream_params.sink); } else { - PrepareAndSendToSingleCis(data, &stream_conf); + /* Streaming to one device and 1 CIS */ + PrepareAndSendToSingleCis(data, stream_conf.stream_params.sink); } } void CleanCachedMicrophoneData() { - cached_channel_data_.clear(); cached_channel_timestamp_ = 0; - cached_channel_is_left_ = false; + cached_channel_ = nullptr; } /* Handles audio data packets coming from the controller */ @@ -3172,11 +3405,10 @@ class LeAudioClientImpl : public LeAudioClient { return; } - auto stream_conf = group->stream_conf; - uint16_t left_cis_handle = 0; uint16_t right_cis_handle = 0; - for (auto [cis_handle, audio_location] : stream_conf.source_streams) { + for (auto [cis_handle, audio_location] : + group->stream_conf.stream_params.source.stream_locations) { if (audio_location & le_audio::codec_spec_conf::kLeAudioLocationAnyLeft) { left_cis_handle = cis_handle; } @@ -3186,97 +3418,43 @@ class LeAudioClientImpl : public LeAudioClient { } } - bool is_left = true; + auto decoder = sw_dec_left.get(); if (cis_conn_hdl == left_cis_handle) { - is_left = true; + decoder = sw_dec_left.get(); } else if (cis_conn_hdl == right_cis_handle) { - is_left = false; + decoder = sw_dec_right.get(); } else { LOG_ERROR("Received data for unknown handle: %04x", cis_conn_hdl); return; } - uint16_t required_for_channel_byte_count = - stream_conf.source_octets_per_codec_frame; - - int dt_us = current_sink_codec_config.data_interval_us; - int af_hz = audio_framework_sink_config.sample_rate; - lc3_pcm_format bits_per_sample = - bits_to_lc3_bits(audio_framework_sink_config.bits_per_sample); - - int pcm_size; - if (dt_us == 10000) { - if (af_hz == 44100) - pcm_size = 480; - else - pcm_size = af_hz / 100; - } else if (dt_us == 7500) { - if (af_hz == 44100) - pcm_size = 360; - else - pcm_size = (af_hz * 3) / 400; - } else { - LOG(ERROR) << "BAD dt_us: " << dt_us; - return; - } - - std::vector pcm_data_decoded(pcm_size, 0); - - int err = 0; - - if (required_for_channel_byte_count != size) { - LOG(INFO) << "Insufficient data for decoding and send, required: " - << int(required_for_channel_byte_count) - << ", received: " << int(size) << ", will do PLC"; - size = 0; - data = nullptr; - } - - lc3_decoder_t decoder_to_use = - is_left ? lc3_decoder_left : lc3_decoder_right; - - err = lc3_decode(decoder_to_use, data, size, bits_per_sample, - pcm_data_decoded.data(), 1 /* pitch */); - - if (err < 0) { - LOG(ERROR) << " bad decoding parameters: " << static_cast(err); - return; - } - - /* AF == Audio Framework */ - bool af_is_stereo = (audio_framework_sink_config.num_channels == 2); - if (!left_cis_handle || !right_cis_handle) { /* mono or just one device connected */ - SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo, - &pcm_data_decoded, nullptr); + decoder->Decode(data, size); + SendAudioDataToAF(&decoder->GetDecodedSamples()); return; } /* both devices are connected */ - if (cached_channel_timestamp_ == 0 && cached_channel_data_.empty()) { + if (cached_channel_ == nullptr || + cached_channel_->GetDecodedSamples().empty()) { /* First packet received, cache it. We need both channel data to send it * to AF. */ - cached_channel_data_ = pcm_data_decoded; + decoder->Decode(data, size); cached_channel_timestamp_ = timestamp; - cached_channel_is_left_ = is_left; + cached_channel_ = decoder; return; } /* We received either data for the other audio channel, or another * packet for same channel */ - - if (cached_channel_is_left_ != is_left) { + if (cached_channel_ != decoder) { /* It's data for the 2nd channel */ if (timestamp == cached_channel_timestamp_) { /* Ready to mix data and send out to AF */ - if (is_left) { - SendAudioDataToAF(true /* bt_got_stereo */, af_is_stereo, - &cached_channel_data_, &pcm_data_decoded); - } else { - SendAudioDataToAF(true /* bt_got_stereo */, af_is_stereo, - &pcm_data_decoded, &cached_channel_data_); - } + decoder->Decode(data, size); + SendAudioDataToAF(&sw_dec_left->GetDecodedSamples(), + &sw_dec_right->GetDecodedSamples()); CleanCachedMicrophoneData(); return; @@ -3285,18 +3463,11 @@ class LeAudioClientImpl : public LeAudioClient { /* 2nd Channel is in the future compared to the cached data. Send the cached data to AF, and keep the new channel data in cache. This should happen only during stream setup */ + SendAudioDataToAF(&decoder->GetDecodedSamples()); - if (cached_channel_is_left_) { - SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo, - &cached_channel_data_, nullptr); - } else { - SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo, nullptr, - &cached_channel_data_); - } - - cached_channel_data_ = pcm_data_decoded; + decoder->Decode(data, size); cached_channel_timestamp_ = timestamp; - cached_channel_is_left_ = is_left; + cached_channel_ = decoder; return; } @@ -3304,25 +3475,22 @@ class LeAudioClientImpl : public LeAudioClient { * data */ /* Send the cached data out */ - if (cached_channel_is_left_) { - SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo, - &cached_channel_data_, nullptr); - } else { - SendAudioDataToAF(false /* bt_got_stereo */, af_is_stereo, nullptr, - &cached_channel_data_); - } + SendAudioDataToAF(&decoder->GetDecodedSamples()); /* Cache the data in case 2nd channel connects */ - cached_channel_data_ = pcm_data_decoded; + decoder->Decode(data, size); cached_channel_timestamp_ = timestamp; - cached_channel_is_left_ = is_left; + cached_channel_ = decoder; } - void SendAudioDataToAF(bool bt_got_stereo, bool af_is_stereo, - std::vector* left, - std::vector* right) { + void SendAudioDataToAF(std::vector* left, + std::vector* right = nullptr) { uint16_t to_write = 0; uint16_t written = 0; + + bool af_is_stereo = (audio_framework_sink_config.num_channels == 2); + bool bt_got_stereo = (left != nullptr) & (right != nullptr); + if (!af_is_stereo) { if (!bt_got_stereo) { std::vector* mono = left ? left : right; @@ -3381,7 +3549,7 @@ class LeAudioClientImpl : public LeAudioClient { audio_receiver_state_ = AudioState::STARTED; } - bool StartSendingAudio(int group_id) { + void StartSendingAudio(int group_id) { LOG(INFO) << __func__; LeAudioDeviceGroup* group = aseGroups_.FindById(group_id); @@ -3393,18 +3561,21 @@ class LeAudioClientImpl : public LeAudioClient { auto* stream_conf = GetStreamSinkConfiguration(group); if (stream_conf == nullptr) { LOG(ERROR) << __func__ << " could not get sink configuration"; - return false; + groupStateMachine_->StopStream(group); + return; } LOG_DEBUG("Sink stream config (#%d):\n", - static_cast(stream_conf->sink_streams.size())); - for (auto stream : stream_conf->sink_streams) { + static_cast( + stream_conf->stream_params.sink.stream_locations.size())); + for (auto stream : stream_conf->stream_params.sink.stream_locations) { LOG_DEBUG("Cis handle: 0x%02x, allocation 0x%04x\n", stream.first, stream.second); } LOG_DEBUG("Source stream config (#%d):\n", - static_cast(stream_conf->source_streams.size())); - for (auto stream : stream_conf->source_streams) { + static_cast( + stream_conf->stream_params.source.stream_locations.size())); + for (auto stream : stream_conf->stream_params.source.stream_locations) { LOG_DEBUG("Cis handle: 0x%02x, allocation 0x%04x\n", stream.first, stream.second); } @@ -3413,49 +3584,55 @@ class LeAudioClientImpl : public LeAudioClient { group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink); if (CodecManager::GetInstance()->GetCodecLocation() == le_audio::types::CodecLocation::HOST) { - if (lc3_encoder_left_mem) { + if (sw_enc_left || sw_enc_right) { LOG(WARNING) << " The encoder instance should have been already released."; - free(lc3_encoder_left_mem); - lc3_encoder_left_mem = nullptr; - free(lc3_encoder_right_mem); - lc3_encoder_right_mem = nullptr; } - int dt_us = current_source_codec_config.data_interval_us; - int sr_hz = current_source_codec_config.sample_rate; - int af_hz = audio_framework_source_config.sample_rate; - unsigned enc_size = lc3_encoder_size(dt_us, af_hz); - - lc3_encoder_left_mem = malloc(enc_size); - lc3_encoder_right_mem = malloc(enc_size); + sw_enc_left = + le_audio::CodecInterface::CreateInstance(stream_conf->codec_id); + auto codec_status = sw_enc_left->InitEncoder( + audio_framework_source_config, current_source_codec_config); + if (codec_status != le_audio::CodecInterface::Status::STATUS_OK) { + LOG_ERROR("Left channel codec setup failed with err: %d", codec_status); + groupStateMachine_->StopStream(group); + return; + } - lc3_encoder_left = - lc3_setup_encoder(dt_us, sr_hz, af_hz, lc3_encoder_left_mem); - lc3_encoder_right = - lc3_setup_encoder(dt_us, sr_hz, af_hz, lc3_encoder_right_mem); + sw_enc_right = + le_audio::CodecInterface::CreateInstance(stream_conf->codec_id); + codec_status = sw_enc_right->InitEncoder(audio_framework_source_config, + current_source_codec_config); + if (codec_status != le_audio::CodecInterface::Status::STATUS_OK) { + LOG_ERROR("Right channel codec setup failed with err: %d", + codec_status); + groupStateMachine_->StopStream(group); + return; + } } le_audio_source_hal_client_->UpdateRemoteDelay(remote_delay_ms); ConfirmLocalAudioSourceStreamingRequest(); - if (CodecManager::GetInstance()->GetAidlVersionInUsed() < - AIDL_VERSION_SUPPORT_STREAM_ACTIVE) { - /* We update the target audio allocation before streamStarted that the - * offloder would know how to configure offloader encoder. We should check - * if we need to update the current - * allocation here as the target allocation and the current allocation is - * different */ - updateOffloaderIfNeeded(group); + if (!LeAudioHalVerifier::SupportsStreamActiveApi()) { + /* We update the target audio allocation before streamStarted so that the + * CodecManager would know how to configure the encoder. */ + BidirectionalPair delays_pair = { + .sink = group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink), + .source = + group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource)}; + CodecManager::GetInstance()->UpdateActiveAudioConfig( + group->stream_conf.stream_params, delays_pair, + std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal, + weak_factory_.GetWeakPtr(), std::placeholders::_1, + std::placeholders::_2)); } - - return true; } const struct le_audio::stream_configuration* GetStreamSourceConfiguration( LeAudioDeviceGroup* group) { const struct le_audio::stream_configuration* stream_conf = &group->stream_conf; - if (stream_conf->source_streams.size() == 0) { + if (stream_conf->stream_params.source.stream_locations.size() == 0) { return nullptr; } LOG_INFO("configuration: %s", stream_conf->conf->name.c_str()); @@ -3471,6 +3648,7 @@ class LeAudioClientImpl : public LeAudioClient { if (!stream_conf) { LOG(WARNING) << " Could not get source configuration for group " << active_group_id_ << " probably microphone not configured"; + groupStateMachine_->StopStream(group); return; } @@ -3481,57 +3659,57 @@ class LeAudioClientImpl : public LeAudioClient { if (CodecManager::GetInstance()->GetCodecLocation() == le_audio::types::CodecLocation::HOST) { - if (lc3_decoder_left_mem) { + if (sw_dec_left.get() || sw_dec_right.get()) { LOG(WARNING) << " The decoder instance should have been already released."; - free(lc3_decoder_left_mem); - lc3_decoder_left_mem = nullptr; - free(lc3_decoder_right_mem); - lc3_decoder_right_mem = nullptr; + } + sw_dec_left = + le_audio::CodecInterface::CreateInstance(stream_conf->codec_id); + auto codec_status = sw_dec_left->InitDecoder(current_sink_codec_config, + audio_framework_sink_config); + if (codec_status != le_audio::CodecInterface::Status::STATUS_OK) { + LOG_ERROR("Left channel codec setup failed with err: %d", codec_status); + groupStateMachine_->StopStream(group); + return; } - int dt_us = current_sink_codec_config.data_interval_us; - int sr_hz = current_sink_codec_config.sample_rate; - int af_hz = audio_framework_sink_config.sample_rate; - unsigned dec_size = lc3_decoder_size(dt_us, af_hz); - lc3_decoder_left_mem = malloc(dec_size); - lc3_decoder_right_mem = malloc(dec_size); - - lc3_decoder_left = - lc3_setup_decoder(dt_us, sr_hz, af_hz, lc3_decoder_left_mem); - lc3_decoder_right = - lc3_setup_decoder(dt_us, sr_hz, af_hz, lc3_decoder_right_mem); + sw_dec_right = + le_audio::CodecInterface::CreateInstance(stream_conf->codec_id); + codec_status = sw_dec_right->InitDecoder(current_sink_codec_config, + audio_framework_sink_config); + if (codec_status != le_audio::CodecInterface::Status::STATUS_OK) { + LOG_ERROR("Right channel codec setup failed with err: %d", + codec_status); + groupStateMachine_->StopStream(group); + return; + } } le_audio_sink_hal_client_->UpdateRemoteDelay(remote_delay_ms); ConfirmLocalAudioSinkStreamingRequest(); - if (CodecManager::GetInstance()->GetAidlVersionInUsed() < - AIDL_VERSION_SUPPORT_STREAM_ACTIVE) { - /* We update the target audio allocation before streamStarted that the - * offloder would know how to configure offloader encoder. We should check - * if we need to update the current - * allocation here as the target allocation and the current allocation is - * different */ - updateOffloaderIfNeeded(group); + if (!LeAudioHalVerifier::SupportsStreamActiveApi()) { + /* We update the target audio allocation before streamStarted so that the + * CodecManager would know how to configure the encoder. */ + BidirectionalPair delays_pair = { + .sink = group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink), + .source = + group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource)}; + CodecManager::GetInstance()->UpdateActiveAudioConfig( + group->stream_conf.stream_params, delays_pair, + std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal, + weak_factory_.GetWeakPtr(), std::placeholders::_1, + std::placeholders::_2)); } } void SuspendAudio(void) { CancelStreamingRequest(); - if (lc3_encoder_left_mem) { - free(lc3_encoder_left_mem); - lc3_encoder_left_mem = nullptr; - free(lc3_encoder_right_mem); - lc3_encoder_right_mem = nullptr; - } - - if (lc3_decoder_left_mem) { - free(lc3_decoder_left_mem); - lc3_decoder_left_mem = nullptr; - free(lc3_decoder_right_mem); - lc3_decoder_right_mem = nullptr; - } + if (sw_enc_left) sw_enc_left.reset(); + if (sw_enc_right) sw_enc_right.reset(); + if (sw_dec_left) sw_dec_left.reset(); + if (sw_dec_right) sw_dec_right.reset(); + CleanCachedMicrophoneData(); } void StopAudio(void) { SuspendAudio(); } @@ -3591,11 +3769,17 @@ class LeAudioClientImpl : public LeAudioClient { dprintf(fd, " configuration: %s (0x%08hx)\n", bluetooth::common::ToString(configuration_context_type_).c_str(), configuration_context_type_); - dprintf(fd, " source metadata context type mask: %s\n", - metadata_context_types_.source.to_string().c_str()); - dprintf(fd, " sink metadata context type mask: %s\n", - metadata_context_types_.sink.to_string().c_str()); + dprintf(fd, " local source metadata context type mask: %s\n", + local_metadata_context_types_.source.to_string().c_str()); + dprintf(fd, " local sink metadata context type mask: %s\n", + local_metadata_context_types_.sink.to_string().c_str()); dprintf(fd, " TBS state: %s\n", in_call_ ? " In call" : "No calls"); + dprintf(fd, " Sink listening mode: %s\n", + sink_monitor_mode_ ? "true" : "false"); + if (sink_monitor_notified_status_) { + dprintf(fd, " Local sink notified state: %d\n", + sink_monitor_notified_status_.value()); + } dprintf(fd, " Start time: "); for (auto t : stream_start_history_queue_) { dprintf(fd, ", %d ms", static_cast(t)); @@ -3607,23 +3791,35 @@ class LeAudioClientImpl : public LeAudioClient { aseGroups_.Dump(fd, active_group_id_); dprintf(fd, "\n Not grouped devices:\n"); leAudioDevices_.Dump(fd, bluetooth::groups::kGroupUnknown); + + if (leAudioHealthStatus_) { + leAudioHealthStatus_->DebugDump(fd); + } } - void Cleanup(base::Callback cleanupCb) { + void Cleanup() { StopVbcCloseTimeout(); if (alarm_is_scheduled(suspend_timeout_)) alarm_cancel(suspend_timeout_); if (active_group_id_ != bluetooth::groups::kGroupUnknown) { /* Bluetooth turned off while streaming */ StopAudio(); - ClientAudioIntefraceRelease(); + SetUnicastMonitorMode(le_audio::types::kLeAudioDirectionSink, false); + ClientAudioInterfaceRelease(); + } else { + /* There may be not stopped Sink HAL client due to set Listening mode */ + if (sink_monitor_mode_) { + SetUnicastMonitorMode(le_audio::types::kLeAudioDirectionSink, false); + } } groupStateMachine_->Cleanup(); aseGroups_.Cleanup(); leAudioDevices_.Cleanup(gatt_if_); if (gatt_if_) BTA_GATTC_AppDeregister(gatt_if_); - std::move(cleanupCb).Run(); + if (leAudioHealthStatus_) { + leAudioHealthStatus_->Cleanup(); + } } AudioReconfigurationResult UpdateConfigAndCheckIfReconfigurationIsNeeded( @@ -3684,6 +3880,13 @@ class LeAudioClientImpl : public LeAudioClient { sink_cfg_available, source_cfg_available); if (!reconfiguration_needed) { + // Assign the new configuration context as it reprents the current + // use case even when it eventually ends up being the exact same + // codec and qos configuration. + if (configuration_context_type_ != context_type) { + configuration_context_type_ = context_type; + group->SetConfigurationContextType(context_type); + } return AudioReconfigurationResult::RECONFIGURATION_NOT_NEEDED; } @@ -3698,12 +3901,29 @@ class LeAudioClientImpl : public LeAudioClient { return AudioReconfigurationResult::RECONFIGURATION_NEEDED; } - bool OnAudioResume(LeAudioDeviceGroup* group) { - if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - return true; + /* Returns true if stream is started */ + bool OnAudioResume(LeAudioDeviceGroup* group, int local_direction) { + auto remote_direction = + (local_direction == le_audio::types::kLeAudioDirectionSink + ? le_audio::types::kLeAudioDirectionSource + : le_audio::types::kLeAudioDirectionSink); + + auto remote_contexts = + DirectionalRealignMetadataAudioContexts(group, remote_direction); + ApplyRemoteMetadataAudioContextPolicy(group, remote_contexts, + remote_direction); + + if (!remote_contexts.sink.any() && !remote_contexts.source.any()) { + LOG_WARN("Requested context type not available on the remote side"); + if (leAudioHealthStatus_) { + leAudioHealthStatus_->AddStatisticForGroup( + group, LeAudioHealthGroupStatType::STREAM_CONTEXT_NOT_AVAILABLE); + } + return false; } + return GroupStream(active_group_id_, configuration_context_type_, - metadata_context_types_); + remote_contexts); } void OnAudioSuspend() { @@ -3820,7 +4040,7 @@ class LeAudioClientImpl : public LeAudioClient { return; } - /* Check if the device resume is expected */ + /* Check if the device resume is allowed */ if (!group->GetCodecConfigurationByDirection( configuration_context_type_, le_audio::types::kLeAudioDirectionSink)) { @@ -3846,7 +4066,8 @@ class LeAudioClientImpl : public LeAudioClient { switch (audio_receiver_state_) { case AudioState::IDLE: /* Stream is not started. Try to do it.*/ - if (OnAudioResume(group)) { + if (OnAudioResume(group, + le_audio::types::kLeAudioDirectionSource)) { audio_sender_state_ = AudioState::READY_TO_START; } else { CancelLocalAudioSourceStreamingRequest(); @@ -3948,7 +4169,8 @@ class LeAudioClientImpl : public LeAudioClient { break; case AudioState::READY_TO_START: LOG_ERROR( - " called in wrong state. \n audio_receiver_state: %s \n" + "called in wrong state, ignoring double start request. \n " + "audio_receiver_state: %s \n" "audio_sender_state: %s \n isPendingConfiguration: %s \n " "Reconfiguring to %s", ToString(audio_receiver_state_).c_str(), @@ -3956,7 +4178,6 @@ class LeAudioClientImpl : public LeAudioClient { (group->IsPendingConfiguration() ? "true" : "false"), ToString(configuration_context_type_).c_str()); group->PrintDebugState(); - CancelStreamingRequest(); break; case AudioState::READY_TO_RELEASE: switch (audio_receiver_state_) { @@ -4036,11 +4257,21 @@ class LeAudioClientImpl : public LeAudioClient { inline bool IsDirectionAvailableForCurrentConfiguration( const LeAudioDeviceGroup* group, uint8_t direction) const { return group - ->GetCodecConfigurationByDirection(configuration_context_type_, - direction) + ->GetCachedCodecConfigurationByDirection(configuration_context_type_, + direction) .has_value(); } + void notifyAudioLocalSink(UnicastMonitorModeStatus status) { + if (sink_monitor_notified_status_ != status) { + LOG_INFO("Stram monitoring status changed to: %d", + static_cast(status)); + sink_monitor_notified_status_ = status; + callbacks_->OnUnicastMonitorModeStatus( + le_audio::types::kLeAudioDirectionSink, status); + } + } + void OnLocalAudioSinkResume() { LOG_INFO( "active group_id: %d IN: audio_receiver_state_: %s, " @@ -4053,6 +4284,15 @@ class LeAudioClientImpl : public LeAudioClient { "r_state: " + ToString(audio_receiver_state_) + ", s_state: " + ToString(audio_sender_state_)); + if (sink_monitor_mode_ && + active_group_id_ == bluetooth::groups::kGroupUnknown) { + if (!sink_monitor_notified_status_) { + notifyAudioLocalSink(UnicastMonitorModeStatus::STREAMING_REQUESTED); + } + CancelLocalAudioSinkStreamingRequest(); + return; + } + /* Stop the VBC close watchdog if needed */ StopVbcCloseTimeout(); @@ -4071,10 +4311,11 @@ class LeAudioClientImpl : public LeAudioClient { * further. */ if (audio_receiver_state_ == AudioState::IDLE) { - ReconfigureOrUpdateRemoteSource(group); + ReconfigureOrUpdateRemote(group, + le_audio::types::kLeAudioDirectionSource); } - /* Check if the device resume is expected */ + /* Check if the device resume is allowed */ if (!group->GetCodecConfigurationByDirection( configuration_context_type_, le_audio::types::kLeAudioDirectionSource)) { @@ -4098,7 +4339,7 @@ class LeAudioClientImpl : public LeAudioClient { case AudioState::IDLE: switch (audio_sender_state_) { case AudioState::IDLE: - if (OnAudioResume(group)) { + if (OnAudioResume(group, le_audio::types::kLeAudioDirectionSink)) { audio_receiver_state_ = AudioState::READY_TO_START; } else { CancelLocalAudioSinkStreamingRequest(); @@ -4201,7 +4442,8 @@ class LeAudioClientImpl : public LeAudioClient { break; case AudioState::READY_TO_START: LOG_ERROR( - " called in wrong state. \n audio_receiver_state: %s \n" + " Double resume request, just ignore it.. \n audio_receiver_state: " + "%s \n" "audio_sender_state: %s \n isPendingConfiguration: %s \n " "Reconfiguring to %s", ToString(audio_receiver_state_).c_str(), @@ -4209,7 +4451,6 @@ class LeAudioClientImpl : public LeAudioClient { (group->IsPendingConfiguration() ? "true" : "false"), ToString(configuration_context_type_).c_str()); group->PrintDebugState(); - CancelStreamingRequest(); break; case AudioState::READY_TO_RELEASE: switch (audio_sender_state_) { @@ -4245,7 +4486,7 @@ class LeAudioClientImpl : public LeAudioClient { bluetooth::common::ToString(available_remote_contexts).c_str(), bluetooth::common::ToString(configuration_context_type_).c_str()); - if (in_call_) { + if (IsInCall()) { LOG_DEBUG(" In Call preference used."); return LeAudioContextType::CONVERSATIONAL; } @@ -4257,10 +4498,10 @@ class LeAudioClientImpl : public LeAudioClient { LeAudioContextType context_priority_list[] = { /* Highest priority first */ LeAudioContextType::CONVERSATIONAL, - /* Skip the RINGTONE to avoid reconfigurations when adjusting - * call volume slider while not in a call. - * LeAudioContextType::RINGTONE, + /* Handling RINGTONE will cause the ringtone volume slider to trigger + * reconfiguration. This will be fixed in b/283349711. */ + LeAudioContextType::RINGTONE, LeAudioContextType::LIVE, LeAudioContextType::VOICEASSISTANTS, LeAudioContextType::GAME, @@ -4329,8 +4570,8 @@ class LeAudioClientImpl : public LeAudioClient { return true; } - void OnLocalAudioSourceMetadataUpdate( - std::vector source_metadata) { + void OnLocalAudioSourceMetadataUpdate(source_metadata_v7 source_metadata, + DsaMode dsa_mode) { if (active_group_id_ == bluetooth::groups::kGroupUnknown) { LOG(WARNING) << ", cannot start streaming if no active group set"; return; @@ -4356,236 +4597,132 @@ class LeAudioClientImpl : public LeAudioClient { ToString(audio_receiver_state_).c_str(), ToString(audio_sender_state_).c_str()); - /* When a certain context became unavailable while it was already in - * an active stream, it means that it is unavailable to other clients - * but we can keep using it. - */ - auto current_available_contexts = group->GetAvailableContexts(); - if ((audio_sender_state_ == AudioState::STARTED) || - (audio_sender_state_ == AudioState::READY_TO_START)) { - current_available_contexts |= metadata_context_types_.sink; - } + group->dsa_mode_ = dsa_mode; /* Set the remote sink metadata context from the playback tracks metadata */ - metadata_context_types_.sink = GetAllowedAudioContextsFromSourceMetadata( - source_metadata, current_available_contexts); + local_metadata_context_types_.source = + GetAudioContextsFromSourceMetadata(source_metadata); - /* Make sure we have CONVERSATIONAL when in a call */ - if (in_call_) { - LOG_DEBUG(" In Call preference used."); - metadata_context_types_.sink |= - AudioContexts(LeAudioContextType::CONVERSATIONAL); - metadata_context_types_.source |= - AudioContexts(LeAudioContextType::CONVERSATIONAL); - } - - metadata_context_types_.sink = - ChooseMetadataContextType(metadata_context_types_.sink); + local_metadata_context_types_.sink = + ChooseMetadataContextType(local_metadata_context_types_.sink); + local_metadata_context_types_.source = + ChooseMetadataContextType(local_metadata_context_types_.source); - ReconfigureOrUpdateRemoteSink(group); + ReconfigureOrUpdateRemote(group, le_audio::types::kLeAudioDirectionSink); } - void ReconfigureOrUpdateRemoteSink(LeAudioDeviceGroup* group) { - if (stack_config_get_interface() - ->get_pts_force_le_audio_multiple_contexts_metadata()) { - // Use common audio stream contexts exposed by the PTS - metadata_context_types_.sink = AudioContexts(0xFFFF); - for (auto device = group->GetFirstDevice(); device != nullptr; - device = group->GetNextDevice(device)) { - metadata_context_types_.sink &= device->GetAvailableContexts(); - } - if (metadata_context_types_.sink.value() == 0xFFFF) { - metadata_context_types_.sink = - AudioContexts(LeAudioContextType::UNSPECIFIED); - } - LOG_WARN("Overriding metadata_context_types_ with: %s", - metadata_context_types_.sink.to_string().c_str()); - - /* Choose the right configuration context */ - auto new_configuration_context = - ChooseConfigurationContextType(metadata_context_types_.sink); - - LOG_DEBUG("new_configuration_context= %s.", - ToString(new_configuration_context).c_str()); - GroupStream(active_group_id_, new_configuration_context, - metadata_context_types_); - return; - } - - /* Start with only this direction context metadata */ - auto configuration_context_candidates = metadata_context_types_.sink; - - /* Mixed contexts in the voiceback channel scenarios can confuse the remote - * on how to configure each channel. We should align both direction - * metadata. - */ - auto bidir_contexts = LeAudioContextType::GAME | LeAudioContextType::LIVE | - LeAudioContextType::CONVERSATIONAL | - LeAudioContextType::VOICEASSISTANTS; - if (metadata_context_types_.sink.test_any(bidir_contexts)) { - if (osi_property_get_bool(kAllowMultipleContextsInMetadata, true)) { - LOG_DEBUG("Aligning remote source metadata to add the sink context"); - metadata_context_types_.source = - metadata_context_types_.source | metadata_context_types_.sink; - } else { - LOG_DEBUG("Replacing remote source metadata to match the sink context"); - metadata_context_types_.source = metadata_context_types_.sink; - } - } - - /* If the local sink is started, ready to start or any direction is - * reconfiguring when the remote sink configuration is active, then take - * into the account current context type for this direction when - * configuration context is selected. - */ - auto is_releasing_for_reconfiguration = - (((audio_receiver_state_ == AudioState::RELEASING) || - (audio_sender_state_ == AudioState::RELEASING)) && - group->IsPendingConfiguration() && - IsDirectionAvailableForCurrentConfiguration( - group, le_audio::types::kLeAudioDirectionSource)); - if (is_releasing_for_reconfiguration || - (audio_receiver_state_ == AudioState::STARTED) || - (audio_receiver_state_ == AudioState::READY_TO_START)) { - LOG_DEBUG("Other direction is streaming. Taking its contexts %s", - ToString(metadata_context_types_.source).c_str()); - // If current direction has no valid context or we are in the - // bidirectional scenario, take the other direction context - if ((metadata_context_types_.sink.none() && - metadata_context_types_.source.any()) || - metadata_context_types_.source.test_any(bidir_contexts)) { - if (osi_property_get_bool(kAllowMultipleContextsInMetadata, true)) { - LOG_DEBUG("Aligning remote sink metadata to add the source context"); - metadata_context_types_.sink = - metadata_context_types_.sink | metadata_context_types_.source; - } else { - LOG_DEBUG( - "Replacing remote sink metadata to match the source context"); - metadata_context_types_.sink = metadata_context_types_.source; - } - } - - configuration_context_candidates = - ChooseMetadataContextType(get_bidirectional(metadata_context_types_)); - } - LOG_DEBUG("configuration_context_candidates= %s", - ToString(configuration_context_candidates).c_str()); - - RealignMetadataAudioContextsIfNeeded( - le_audio::types::kLeAudioDirectionSink); - - /* Choose the right configuration context */ - auto new_configuration_context = - ChooseConfigurationContextType(configuration_context_candidates); - LOG_DEBUG("new_configuration_context= %s", - ToString(new_configuration_context).c_str()); - - /* For the following contexts we don't actually need HQ audio: - * LeAudioContextType::NOTIFICATIONS - * LeAudioContextType::SOUNDEFFECTS - * LeAudioContextType::INSTRUCTIONAL - * LeAudioContextType::ALERTS - * LeAudioContextType::EMERGENCYALARM - * LeAudioContextType::UNSPECIFIED - * So do not reconfigure if the remote sink is already available at any - * quality and these are the only contributors to the current audio stream. - */ - auto no_reconfigure_contexts = - LeAudioContextType::NOTIFICATIONS | LeAudioContextType::SOUNDEFFECTS | - LeAudioContextType::INSTRUCTIONAL | LeAudioContextType::ALERTS | - LeAudioContextType::EMERGENCYALARM | LeAudioContextType::UNSPECIFIED; - if (configuration_context_candidates.any() && - (configuration_context_candidates & ~no_reconfigure_contexts).none() && - (configuration_context_type_ != LeAudioContextType::UNINITIALIZED) && - IsDirectionAvailableForCurrentConfiguration( - group, le_audio::types::kLeAudioDirectionSink)) { - LOG_INFO( - "There is no need to reconfigure for the sonification events, " - "staying with the existing configuration context of %s", - ToString(configuration_context_type_).c_str()); - new_configuration_context = configuration_context_type_; - } - - LOG_DEBUG("metadata_context_types_.sink= %s", - ToString(metadata_context_types_.sink).c_str()); - LOG_DEBUG("metadata_context_types_.source= %s", - ToString(metadata_context_types_.source).c_str()); - ReconfigureOrUpdateMetadata(group, new_configuration_context); - } - - void RealignMetadataAudioContextsIfNeeded(int remote_dir) { + /* Applies some predefined policy on the audio context metadata, including + * special handling of UNSPECIFIED context, which also involves checking + * context support and availability. + */ + void ApplyRemoteMetadataAudioContextPolicy( + LeAudioDeviceGroup* group, + BidirectionalPair& contexts_pair, int remote_dir) { // We expect at least some context when this direction gets enabled - if (metadata_context_types_.get(remote_dir).none()) { + if (contexts_pair.get(remote_dir).none()) { LOG_WARN( "invalid/unknown %s context metadata, using 'UNSPECIFIED' instead", (remote_dir == le_audio::types::kLeAudioDirectionSink) ? "sink" : "source"); - metadata_context_types_.get_ref(remote_dir) = + contexts_pair.get(remote_dir) = AudioContexts(LeAudioContextType::UNSPECIFIED); } - /* Don't mix UNSPECIFIED with any other context */ - if (metadata_context_types_.sink.test(LeAudioContextType::UNSPECIFIED)) { - /* Try to use the other direction context if not UNSPECIFIED and active */ - if (metadata_context_types_.sink == - AudioContexts(LeAudioContextType::UNSPECIFIED)) { - auto is_other_direction_streaming = - (audio_receiver_state_ == AudioState::STARTED) || - (audio_receiver_state_ == AudioState::READY_TO_START); - if (is_other_direction_streaming && - (metadata_context_types_.source != - AudioContexts(LeAudioContextType::UNSPECIFIED))) { - LOG_INFO( - "Other direction is streaming. Aligning remote sink metadata to " - "match the source context: %s", - ToString(metadata_context_types_.source).c_str()); - metadata_context_types_.sink = metadata_context_types_.source; - } else { - LOG_INFO( - "Other direction is not streaming. Replacing the existing remote " - "sink context: %s with UNSPECIFIED", - ToString(metadata_context_types_.source).c_str()); - metadata_context_types_.source = - AudioContexts(LeAudioContextType::UNSPECIFIED); - } + std::tuple remote_directions[] = { + {le_audio::types::kLeAudioDirectionSink, + le_audio::types::kLeAudioDirectionSource, &audio_sender_state_}, + {le_audio::types::kLeAudioDirectionSource, + le_audio::types::kLeAudioDirectionSink, &audio_receiver_state_}, + }; + + /* Align with the context availability */ + for (auto entry : remote_directions) { + int dir, other_dir; + AudioState* local_hal_state; + std::tie(dir, other_dir, local_hal_state) = entry; + + /* When a certain context became unavailable while it was already in + * an active stream, it means that it is unavailable to other clients + * but we can keep using it. + */ + auto group_available_contexts = group->GetAvailableContexts(dir); + if ((*local_hal_state == AudioState::STARTED) || + (*local_hal_state == AudioState::READY_TO_START)) { + group_available_contexts |= group->GetMetadataContexts().get(dir); + } + + LOG_DEBUG("Checking contexts: %s, against the available contexts: %s", + ToString(contexts_pair.get(dir)).c_str(), + ToString(group_available_contexts).c_str()); + auto unavail_contexts = + contexts_pair.get(dir) & ~group_available_contexts; + if (unavail_contexts.none()) continue; + + contexts_pair.get(dir) &= group_available_contexts; + auto unavail_but_supported = + (unavail_contexts & group->GetSupportedContexts(dir)); + if (unavail_but_supported.none() && + group_available_contexts.test(LeAudioContextType::UNSPECIFIED)) { + LOG_DEBUG("Replaced the unsupported contexts: %s with UNSPECIFIED", + ToString(unavail_contexts).c_str()); + /* All unavailable are also unsupported - replace with UNSPECIFIED if + * available + */ + contexts_pair.get(dir).set(LeAudioContextType::UNSPECIFIED); } else { - LOG_DEBUG("Removing UNSPECIFIED from the remote sink context: %s", - ToString(metadata_context_types_.source).c_str()); - metadata_context_types_.sink.unset(LeAudioContextType::UNSPECIFIED); + LOG_DEBUG("Some contexts are supported but currently unavailable: %s!", + ToString(unavail_but_supported).c_str()); + /* Some of the streamed contexts are support but not available and they + * were erased from the metadata. + * TODO: Either filter out these contexts from the stream or do not + * stream at all if the unavail_but_supported contexts are the only + * streamed contexts. + */ } } - if (metadata_context_types_.source.test(LeAudioContextType::UNSPECIFIED)) { - /* Try to use the other direction context if not UNSPECIFIED and active */ - if (metadata_context_types_.source == - AudioContexts(LeAudioContextType::UNSPECIFIED)) { - auto is_other_direction_streaming = - (audio_sender_state_ == AudioState::STARTED) || - (audio_sender_state_ == AudioState::READY_TO_START); - if (is_other_direction_streaming && - (metadata_context_types_.sink != - AudioContexts(LeAudioContextType::UNSPECIFIED))) { - LOG_DEBUG( - "Other direction is streaming. Aligning remote source metadata " - "to " - "match the sink context: %s", - ToString(metadata_context_types_.sink).c_str()); - metadata_context_types_.source = metadata_context_types_.sink; + /* Don't mix UNSPECIFIED with any other context + * Note: This has to be in a separate loop - do not merge it with the above. + */ + for (auto entry : remote_directions) { + int dir, other_dir; + AudioState* local_hal_state; + std::tie(dir, other_dir, local_hal_state) = entry; + + if (contexts_pair.get(dir).test(LeAudioContextType::UNSPECIFIED)) { + /* Try to use the other direction context if not UNSPECIFIED and active + */ + if (contexts_pair.get(dir) == + AudioContexts(LeAudioContextType::UNSPECIFIED)) { + auto is_other_direction_streaming = + (*local_hal_state == AudioState::STARTED) || + (*local_hal_state == AudioState::READY_TO_START); + if (is_other_direction_streaming && + (contexts_pair.get(other_dir) != + AudioContexts(LeAudioContextType::UNSPECIFIED))) { + LOG_INFO( + "Other direction is streaming. Aligning other direction" + " metadata to match the current direciton context: %s", + ToString(contexts_pair.get(other_dir)).c_str()); + contexts_pair.get(dir) = contexts_pair.get(other_dir); + } + } else { + LOG_DEBUG("Removing UNSPECIFIED from the remote sink context: %s", + ToString(contexts_pair.get(other_dir)).c_str()); + contexts_pair.get(dir).unset(LeAudioContextType::UNSPECIFIED); } - } else { - LOG_DEBUG("Removing UNSPECIFIED from the remote source context: %s", - ToString(metadata_context_types_.source).c_str()); - metadata_context_types_.source.unset(LeAudioContextType::UNSPECIFIED); } } - LOG_DEBUG("Metadata audio context: sink=%s, source=%s", - ToString(metadata_context_types_.sink).c_str(), - ToString(metadata_context_types_.source).c_str()); + contexts_pair.sink = ChooseMetadataContextType(contexts_pair.sink); + contexts_pair.source = ChooseMetadataContextType(contexts_pair.source); + + LOG_DEBUG("Aligned remote metadata audio context: sink=%s, source=%s", + ToString(contexts_pair.sink).c_str(), + ToString(contexts_pair.source).c_str()); } - void OnLocalAudioSinkMetadataUpdate( - std::vector sink_metadata) { + void OnLocalAudioSinkMetadataUpdate(sink_metadata_v7 sink_metadata) { if (active_group_id_ == bluetooth::groups::kGroupUnknown) { LOG(WARNING) << ", cannot start streaming if no active group set"; return; @@ -4606,198 +4743,368 @@ class LeAudioClientImpl : public LeAudioClient { ToString(audio_receiver_state_).c_str(), ToString(audio_sender_state_).c_str()); - /* When a certain context became unavailable while it was already in - * an active stream, it means that it is unavailable to other clients - * but we can keep using it. - */ - auto current_available_contexts = group->GetAvailableContexts(); - if ((audio_receiver_state_ == AudioState::STARTED) || - (audio_receiver_state_ == AudioState::READY_TO_START)) { - current_available_contexts |= metadata_context_types_.source; - } - /* Set remote source metadata context from the recording tracks metadata */ - metadata_context_types_.source = GetAllowedAudioContextsFromSinkMetadata( - sink_metadata, current_available_contexts); + local_metadata_context_types_.sink = + GetAudioContextsFromSinkMetadata(sink_metadata); - /* Make sure we have CONVERSATIONAL when in a call */ - if (in_call_) { - LOG_INFO(" In Call preference used."); - metadata_context_types_.sink |= - AudioContexts(LeAudioContextType::CONVERSATIONAL); - metadata_context_types_.source |= - AudioContexts(LeAudioContextType::CONVERSATIONAL); - } - - metadata_context_types_.source = - ChooseMetadataContextType(metadata_context_types_.source); + local_metadata_context_types_.sink = + ChooseMetadataContextType(local_metadata_context_types_.sink); + local_metadata_context_types_.source = + ChooseMetadataContextType(local_metadata_context_types_.source); /* Reconfigure or update only if the stream is already started * otherwise wait for the local sink to resume. */ if (audio_receiver_state_ == AudioState::STARTED) { - ReconfigureOrUpdateRemoteSource(group); + ReconfigureOrUpdateRemote(group, + le_audio::types::kLeAudioDirectionSource); + } + } + + BidirectionalPair DirectionalRealignMetadataAudioContexts( + LeAudioDeviceGroup* group, int remote_direction) { + auto remote_other_direction = + (remote_direction == le_audio::types::kLeAudioDirectionSink + ? le_audio::types::kLeAudioDirectionSource + : le_audio::types::kLeAudioDirectionSink); + auto other_direction_hal = + (remote_other_direction == le_audio::types::kLeAudioDirectionSource + ? audio_receiver_state_ + : audio_sender_state_); + auto is_streaming_other_direction = + (other_direction_hal == AudioState::STARTED) || + (other_direction_hal == AudioState::READY_TO_START); + auto is_releasing_for_reconfiguration = + (((audio_receiver_state_ == AudioState::RELEASING) || + (audio_sender_state_ == AudioState::RELEASING)) && + group->IsPendingConfiguration() && + IsDirectionAvailableForCurrentConfiguration(group, + remote_other_direction)); + + // Inject conversational when ringtone is played - this is required for all + // the VoIP applications which are not using the telecom API. + constexpr AudioContexts possible_voip_contexts = + LeAudioContextType::RINGTONE | LeAudioContextType::CONVERSATIONAL; + if (local_metadata_context_types_.source.test_any(possible_voip_contexts) && + ((remote_direction == le_audio::types::kLeAudioDirectionSink) || + (remote_direction == le_audio::types::kLeAudioDirectionSource && + is_streaming_other_direction))) { + /* Simulate, we are already in the call. Sending RINGTONE when there is + * no incoming call to accept or reject on TBS could confuse the remote + * device and interrupt the stream establish procedure. + */ + if (!IsInCall()) { + SetInVoipCall(true); + } + } else if (IsInVoipCall()) { + SetInVoipCall(false); + } + + /* Make sure we have CONVERSATIONAL when in a call and it is not mixed + * with any other bidirectional context + */ + if (IsInCall() || IsInVoipCall()) { + LOG_DEBUG(" In Call preference used: %s, voip call: %s", + (IsInCall() ? "true" : "false"), + (IsInVoipCall() ? "true" : "false")); + local_metadata_context_types_.sink.unset_all(kLeAudioContextAllBidir); + local_metadata_context_types_.source.unset_all(kLeAudioContextAllBidir); + local_metadata_context_types_.sink.set( + LeAudioContextType::CONVERSATIONAL); + local_metadata_context_types_.source.set( + LeAudioContextType::CONVERSATIONAL); + } + + BidirectionalPair remote_metadata = { + .sink = local_metadata_context_types_.source, + .source = local_metadata_context_types_.sink}; + + if (IsInVoipCall()) { + LOG_DEBUG("Unsetting RINGTONE from remote sink "); + remote_metadata.sink.unset(LeAudioContextType::RINGTONE); + } + + auto is_ongoing_call_on_other_direction = + is_streaming_other_direction && (IsInVoipCall() || IsInCall()); + + LOG_DEBUG("local_metadata_context_types_.source= %s", + ToString(local_metadata_context_types_.source).c_str()); + LOG_DEBUG("local_metadata_context_types_.sink= %s", + ToString(local_metadata_context_types_.sink).c_str()); + LOG_DEBUG("remote_metadata.source= %s", + ToString(remote_metadata.source).c_str()); + LOG_DEBUG("remote_metadata.sink= %s", + ToString(remote_metadata.sink).c_str()); + LOG_DEBUG("remote_direction= %s", + (remote_direction == le_audio::types::kLeAudioDirectionSource + ? "Source" + : "Sink")); + LOG_DEBUG("is_streaming_other_direction= %s", + (is_streaming_other_direction ? "True" : "False")); + LOG_DEBUG("is_releasing_for_reconfiguration= %s", + (is_releasing_for_reconfiguration ? "True" : "False")); + LOG_DEBUG("is_ongoing_call_on_other_direction=%s", + (is_ongoing_call_on_other_direction ? "True" : "False")); + + if (remote_metadata.get(remote_other_direction) + .test_any(kLeAudioContextAllBidir) && + !is_streaming_other_direction) { + LOG_DEBUG( + "The other direction is not streaming bidirectional, ignore that " + "context."); + remote_metadata.get(remote_other_direction).clear(); + } + + /* Mixed contexts in the voiceback channel scenarios can confuse the remote + * on how to configure each channel. We should align the other direction + * metadata for the remote device. + */ + if (remote_metadata.get(remote_direction) + .test_any(kLeAudioContextAllBidir)) { + LOG_DEBUG( + "Aligning the other direction remote metadata to add this direction " + "context"); + + if (is_ongoing_call_on_other_direction) { + /* Other direction is streaming and is in call */ + remote_metadata.get(remote_direction) + .unset_all(kLeAudioContextAllBidir); + remote_metadata.get(remote_direction) + .set(LeAudioContextType::CONVERSATIONAL); + } else { + if (!is_streaming_other_direction) { + // Do not take the obsolete metadata + remote_metadata.get(remote_other_direction).clear(); + } + remote_metadata.get(remote_other_direction) + .unset_all(kLeAudioContextAllBidir); + remote_metadata.get(remote_other_direction) + .unset_all(kLeAudioContextAllRemoteSinkOnly); + remote_metadata.get(remote_other_direction) + .set_all(remote_metadata.get(remote_direction) & + ~kLeAudioContextAllRemoteSinkOnly); + } } + LOG_DEBUG("remote_metadata.source= %s", + ToString(remote_metadata.source).c_str()); + LOG_DEBUG("remote_metadata.sink= %s", + ToString(remote_metadata.sink).c_str()); + + if (is_releasing_for_reconfiguration || is_streaming_other_direction) { + LOG_DEBUG("Other direction is streaming. Taking its contexts %s", + ToString(remote_metadata.get(remote_other_direction)).c_str()); + /* If current direction has no valid context or the other direction is + * bidirectional scenario, take the other direction context as well + */ + if ((remote_metadata.get(remote_direction).none() && + remote_metadata.get(remote_other_direction).any()) || + remote_metadata.get(remote_other_direction) + .test_any(kLeAudioContextAllBidir)) { + LOG_DEBUG( + "Aligning this direction remote metadata to add the other " + "direction context"); + /* Turn off bidirectional contexts on this direction to avoid mixing + * with the other direction bidirectional context + */ + remote_metadata.get(remote_direction) + .unset_all(kLeAudioContextAllBidir); + remote_metadata.get(remote_direction) + .set_all(remote_metadata.get(remote_other_direction)); + } + } + + /* Make sure that after alignment no sink only context leaks into the other + * direction. */ + remote_metadata.source.unset_all(kLeAudioContextAllRemoteSinkOnly); + + LOG_DEBUG("remote_metadata.source= %s", + ToString(remote_metadata.source).c_str()); + LOG_DEBUG("remote_metadata.sink= %s", + ToString(remote_metadata.sink).c_str()); + return remote_metadata; } - void ReconfigureOrUpdateRemoteSource(LeAudioDeviceGroup* group) { + /* Return true if stream is started */ + bool ReconfigureOrUpdateRemote(LeAudioDeviceGroup* group, + int remote_direction) { if (stack_config_get_interface() ->get_pts_force_le_audio_multiple_contexts_metadata()) { // Use common audio stream contexts exposed by the PTS - metadata_context_types_.source = AudioContexts(0xFFFF); + auto override_contexts = AudioContexts(0xFFFF); for (auto device = group->GetFirstDevice(); device != nullptr; device = group->GetNextDevice(device)) { - metadata_context_types_.source &= device->GetAvailableContexts(); + override_contexts &= device->GetAvailableContexts(); } - if (metadata_context_types_.source.value() == 0xFFFF) { - metadata_context_types_.source = - AudioContexts(LeAudioContextType::UNSPECIFIED); + if (override_contexts.value() == 0xFFFF) { + override_contexts = AudioContexts(LeAudioContextType::UNSPECIFIED); } - LOG_WARN("Overriding metadata_context_types_.source with: %su", - metadata_context_types_.source.to_string().c_str()); + LOG_WARN("Overriding local_metadata_context_types_: %s with: %s", + local_metadata_context_types_.source.to_string().c_str(), + override_contexts.to_string().c_str()); /* Choose the right configuration context */ - const auto new_configuration_context = - ChooseConfigurationContextType(metadata_context_types_.source); + auto new_configuration_context = + ChooseConfigurationContextType(override_contexts); LOG_DEBUG("new_configuration_context= %s.", ToString(new_configuration_context).c_str()); - metadata_context_types_.source.set(new_configuration_context); - } - - /* Start with only this direction context metadata */ - auto configuration_context_candidates = metadata_context_types_.source; - - /* Mixed contexts in the voiceback channel scenarios can confuse the remote - * on how to configure each channel. We should align both direction - * metadata. - */ - auto bidir_contexts = LeAudioContextType::GAME | LeAudioContextType::LIVE | - LeAudioContextType::CONVERSATIONAL | - LeAudioContextType::VOICEASSISTANTS; - if (metadata_context_types_.source.test_any(bidir_contexts)) { - if (osi_property_get_bool(kAllowMultipleContextsInMetadata, true)) { - LOG_DEBUG("Aligning remote sink metadata to add the source context"); - metadata_context_types_.sink = - metadata_context_types_.sink | metadata_context_types_.source; - } else { - LOG_DEBUG("Replacing remote sink metadata to match the source context"); - metadata_context_types_.sink = metadata_context_types_.source; - } + BidirectionalPair remote_contexts = { + .sink = override_contexts, .source = override_contexts}; + return GroupStream(active_group_id_, new_configuration_context, + remote_contexts); } - /* If the local source is started, ready to start or any direction is - * reconfiguring when the remote sink configuration is active, then take - * into the account current context type for this direction when - * configuration context is selected. + /* When the local sink and source update their metadata, we need to come up + * with a coherent set of contexts for either one or both directions, + * especially when bidirectional scenarios can be triggered be either sink + * or source metadata update event. */ - auto is_releasing_for_reconfiguration = - (((audio_receiver_state_ == AudioState::RELEASING) || - (audio_sender_state_ == AudioState::RELEASING)) && - group->IsPendingConfiguration() && - IsDirectionAvailableForCurrentConfiguration( - group, le_audio::types::kLeAudioDirectionSink)); - if (is_releasing_for_reconfiguration || - (audio_sender_state_ == AudioState::STARTED) || - (audio_sender_state_ == AudioState::READY_TO_START)) { - LOG_DEBUG("Other direction is streaming. Taking its contexts %s", - ToString(metadata_context_types_.sink).c_str()); - - // If current direction has no valid context take the other direction - // context - if (metadata_context_types_.source.none()) { - if (metadata_context_types_.sink.any()) { - LOG_DEBUG( - "Aligning remote source metadata to match the sink context"); - metadata_context_types_.source = metadata_context_types_.sink; - } - } - - configuration_context_candidates = - ChooseMetadataContextType(get_bidirectional(metadata_context_types_)); - } - LOG_DEBUG("configuration_context_candidates= %s", - ToString(configuration_context_candidates).c_str()); - - RealignMetadataAudioContextsIfNeeded( - le_audio::types::kLeAudioDirectionSource); + auto remote_metadata = + DirectionalRealignMetadataAudioContexts(group, remote_direction); /* Choose the right configuration context */ - auto new_configuration_context = - ChooseConfigurationContextType(configuration_context_candidates); + auto config_context_candids = get_bidirectional(remote_metadata); + auto new_config_context = + ChooseConfigurationContextType(config_context_candids); + LOG_DEBUG("config_context_candids= %s, new_config_context= %s", + ToString(config_context_candids).c_str(), + ToString(new_config_context).c_str()); - /* Do nothing if audio source is not valid for the new configuration */ - const auto is_audio_source_context = - IsContextForAudioSource(new_configuration_context); - if (!is_audio_source_context) { - LOG_WARN( - "No valid remote audio source configuration context in %s, staying " - "with the existing configuration context of %s", - ToString(new_configuration_context).c_str(), + /* For the following contexts we don't actually need HQ audio: + * LeAudioContextType::NOTIFICATIONS + * LeAudioContextType::SOUNDEFFECTS + * LeAudioContextType::INSTRUCTIONAL + * LeAudioContextType::ALERTS + * LeAudioContextType::EMERGENCYALARM + * LeAudioContextType::UNSPECIFIED + * So do not reconfigure if the remote sink is already available at any + * quality and these are the only contributors to the current audio stream. + */ + auto no_reconfigure_contexts = + LeAudioContextType::NOTIFICATIONS | LeAudioContextType::SOUNDEFFECTS | + LeAudioContextType::INSTRUCTIONAL | LeAudioContextType::ALERTS | + LeAudioContextType::EMERGENCYALARM | LeAudioContextType::UNSPECIFIED; + if (config_context_candids.any() && + (config_context_candids & ~no_reconfigure_contexts).none() && + (configuration_context_type_ != LeAudioContextType::UNINITIALIZED) && + (configuration_context_type_ != LeAudioContextType::UNSPECIFIED) && + IsDirectionAvailableForCurrentConfiguration( + group, le_audio::types::kLeAudioDirectionSink)) { + LOG_INFO( + "There is no need to reconfigure for the sonification events, " + "staying with the existing configuration context of %s", ToString(configuration_context_type_).c_str()); - return; + new_config_context = configuration_context_type_; } - /* Do nothing if group already has Voiceback channel configured. + /* Do not configure the Voiceback channel if it is already configured. * WARNING: This eliminates additional reconfigurations but can * lead to unsatisfying audio quality when that direction was * already configured with a lower quality. */ - const auto has_audio_source_configured = - IsDirectionAvailableForCurrentConfiguration( - group, le_audio::types::kLeAudioDirectionSource) && - (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - if (has_audio_source_configured) { - LOG_DEBUG( - "Audio source is already available in the current configuration " - "context in %s. Not switching to %s right now.", - ToString(configuration_context_type_).c_str(), - ToString(new_configuration_context).c_str()); - new_configuration_context = configuration_context_type_; + if (remote_direction == le_audio::types::kLeAudioDirectionSource) { + const auto has_audio_source_configured = + IsDirectionAvailableForCurrentConfiguration( + group, le_audio::types::kLeAudioDirectionSource) && + (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + if (has_audio_source_configured) { + LOG_INFO( + "Audio source is already available in the current configuration " + "context in %s. Not switching to %s right now.", + ToString(configuration_context_type_).c_str(), + ToString(new_config_context).c_str()); + new_config_context = configuration_context_type_; + } } - LOG_DEBUG("metadata_context_types_.sink= %s", - ToString(metadata_context_types_.sink).c_str()); - LOG_DEBUG("metadata_context_types_.source= %s", - ToString(metadata_context_types_.source).c_str()); - ReconfigureOrUpdateMetadata(group, new_configuration_context); + /* Note that the remote device metadata was so far unfiltered when it comes + * to group context availability, or multiple contexts support flag, so that + * we could choose the correct configuration for the use case. Now we can + * align it to meet the metadata usage. + */ + ApplyRemoteMetadataAudioContextPolicy(group, remote_metadata, + remote_direction); + return ReconfigureOrUpdateMetadata(group, new_config_context, + remote_metadata); } - void ReconfigureOrUpdateMetadata( - LeAudioDeviceGroup* group, LeAudioContextType new_configuration_context) { + /* Return true if stream is started */ + bool ReconfigureOrUpdateMetadata( + LeAudioDeviceGroup* group, LeAudioContextType new_configuration_context, + BidirectionalPair remote_contexts) { if (new_configuration_context != configuration_context_type_) { - LOG_DEBUG("Changing configuration context from %s to %s", - ToString(configuration_context_type_).c_str(), - ToString(new_configuration_context).c_str()); + LOG_INFO("Checking whether to change configuration context from %s to %s", + ToString(configuration_context_type_).c_str(), + ToString(new_configuration_context).c_str()); LeAudioLogHistory::Get()->AddLogHistory( kLogAfCallBt, active_group_id_, RawAddress::kEmpty, kLogAfMetadataUpdate + "Reconfigure", ToString(configuration_context_type_) + "->" + ToString(new_configuration_context)); - - if (SetConfigurationAndStopStreamWhenNeeded(group, - new_configuration_context)) { - return; + auto is_stopping = SetConfigurationAndStopStreamWhenNeeded( + group, new_configuration_context); + if (is_stopping) { + return false; } } if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - LOG_DEBUG( + LOG_INFO( "The %s configuration did not change. Updating the metadata to " "sink=%s, source=%s", ToString(configuration_context_type_).c_str(), - ToString(metadata_context_types_.sink).c_str(), - ToString(metadata_context_types_.source).c_str()); + ToString(remote_contexts.sink).c_str(), + ToString(remote_contexts.source).c_str()); LeAudioLogHistory::Get()->AddLogHistory( kLogAfCallBt, active_group_id_, RawAddress::kEmpty, kLogAfMetadataUpdate + "Updating...", - "Sink: " + ToString(metadata_context_types_.sink) + - "Source: " + ToString(metadata_context_types_.source)); + "Sink: " + ToString(remote_contexts.sink) + + "Source: " + ToString(remote_contexts.source)); + + return GroupStream(group->group_id_, configuration_context_type_, + remote_contexts); + } + return false; + } + + static void OnGattCtpCccReadRspStatic(uint16_t conn_id, tGATT_STATUS status, + uint16_t hdl, uint16_t len, + uint8_t* value, void* data) { + if (!instance) return; + + LOG_DEBUG("conn_id: 0x%04x, status: 0x%02x", conn_id, status); + + LeAudioDevice* leAudioDevice = + instance->leAudioDevices_.FindByConnId(conn_id); + + if (!leAudioDevice) { + LOG_ERROR("LeAudioDevice not found"); + return; + } + + if (status == GATT_DATABASE_OUT_OF_SYNC) { + LOG_INFO("Database out of sync for %s, re-discovering", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + instance->ClearDeviceInformationAndStartSearch(leAudioDevice); + return; + } + + if (status != GATT_SUCCESS || len != 2) { + LOG_ERROR("Could not read CCC for %s, disconnecting", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + instance->Disconnect(leAudioDevice->address_); + return; + } - GroupStream(group->group_id_, configuration_context_type_, - metadata_context_types_); + uint16_t val = *(uint16_t*)value; + if (val == 0) { + LOG_INFO("%s forgot CCC values. Re-subscribing", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + instance->RegisterKnownNotifications(leAudioDevice, false, true); + } else { + instance->connectionReady(leAudioDevice); } } @@ -4814,13 +5121,18 @@ class LeAudioClientImpl : public LeAudioClient { } else if (status == GATT_DATABASE_OUT_OF_SYNC) { instance->ClearDeviceInformationAndStartSearch(leAudioDevice); return; + } else { + LOG_ERROR("Failed to read attribute, hdl: 0x%04x, status: 0x%02x", hdl, + static_cast(status)); + return; } /* We use data to keep notify connected flag. */ if (data && !!PTR_TO_INT(data)) { leAudioDevice->notify_connected_after_read_ = false; - /* Update PACs and ASEs when all is read.*/ + /* Update handles, PACs and ASEs when all is read.*/ + btif_storage_leaudio_update_handles_bin(leAudioDevice->address_); btif_storage_leaudio_update_pacs_bin(leAudioDevice->address_); btif_storage_leaudio_update_ase_bin(leAudioDevice->address_); @@ -4833,6 +5145,22 @@ class LeAudioClientImpl : public LeAudioClient { } } + void LeAudioHealthSendRecommendation(const RawAddress& address, int group_id, + LeAudioHealthBasedAction action) { + LOG_DEBUG("%s, %d, %s", ADDRESS_TO_LOGGABLE_CSTR(address), group_id, + ToString(action).c_str()); + + if (address != RawAddress::kEmpty && + leAudioDevices_.FindByAddress(address)) { + callbacks_->OnHealthBasedRecommendationAction(address, action); + } + + if (group_id != bluetooth::groups::kGroupUnknown && + aseGroups_.FindById(group_id)) { + callbacks_->OnHealthBasedGroupRecommendationAction(group_id, action); + } + } + void IsoCigEventsCb(uint16_t event_type, void* data) { switch (event_type) { case bluetooth::hci::iso_manager::kIsoEventCigOnCreateCmpl: { @@ -4892,6 +5220,11 @@ class LeAudioClientImpl : public LeAudioClient { group->SetTransportLatency(le_audio::types::kLeAudioDirectionSource, event->trans_lat_stom); + if (leAudioHealthStatus_ && (event->status != HCI_SUCCESS)) { + leAudioHealthStatus_->AddStatisticForGroup( + group, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + } + groupStateMachine_->ProcessHciNotifCisEstablished(group, leAudioDevice, event); } break; @@ -4977,32 +5310,17 @@ class LeAudioClientImpl : public LeAudioClient { rxUnreceivedPackets, duplicatePackets); } - void HandlePendingAvailableContextsChange(LeAudioDeviceGroup* group) { - if (!group) return; - - /* Update group configuration with pending available context change */ - auto contexts = group->GetPendingAvailableContextsChange(); - if (contexts.any()) { - auto success = group->UpdateAudioContextTypeAvailability(contexts); - if (success) { - callbacks_->OnAudioConf(group->audio_directions_, group->group_id_, - group->snk_audio_locations_.to_ulong(), - group->src_audio_locations_.to_ulong(), - group->GetAvailableContexts().value()); - } - group->ClearPendingAvailableContextsChange(); - } - } - void HandlePendingDeviceRemove(LeAudioDeviceGroup* group) { for (auto device = group->GetFirstDevice(); device != nullptr; device = group->GetNextDevice(device)) { - if (device->GetConnectionState() == DeviceConnectState::PENDING_REMOVAL) { + if (device->GetConnectionState() == DeviceConnectState::REMOVING) { if (device->closing_stream_for_disconnection_) { device->closing_stream_for_disconnection_ = false; LOG_INFO("Disconnecting group id: %d, address: %s", group->group_id_, ADDRESS_TO_LOGGABLE_CSTR(device->address_)); - DisconnectDevice(device); + bool force_acl_disconnect = + device->autoconnect_flag_ && group->IsEnabled(); + DisconnectDevice(device, force_acl_disconnect); } group_remove_node(group, device->address_, true); } @@ -5017,43 +5335,23 @@ class LeAudioClientImpl : public LeAudioClient { leAudioDevice->closing_stream_for_disconnection_ = false; LOG_DEBUG("Disconnecting group id: %d, address: %s", group->group_id_, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - DisconnectDevice(leAudioDevice); + bool force_acl_disconnect = + leAudioDevice->autoconnect_flag_ && group->IsEnabled(); + DisconnectDevice(leAudioDevice, force_acl_disconnect); } leAudioDevice = group->GetNextDevice(leAudioDevice); } } - void updateOffloaderIfNeeded(LeAudioDeviceGroup* group) { - if (CodecManager::GetInstance()->GetCodecLocation() != - le_audio::types::CodecLocation::ADSP) { - return; + void UpdateAudioConfigToHal(const ::le_audio::offload_config& config, + uint8_t remote_direction) { + if ((remote_direction & le_audio::types::kLeAudioDirectionSink) && + le_audio_source_hal_client_) { + le_audio_source_hal_client_->UpdateAudioConfigToHal(config); } - - LOG_INFO("Group %p, group_id %d", group, group->group_id_); - - const auto* stream_conf = &group->stream_conf; - - if (stream_conf->sink_offloader_changed || stream_conf->sink_is_initial) { - LOG_INFO("Update sink offloader streams"); - uint16_t remote_delay_ms = - group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink); - CodecManager::GetInstance()->UpdateActiveSourceAudioConfig( - *stream_conf, remote_delay_ms, - std::bind(&LeAudioSourceAudioHalClient::UpdateAudioConfigToHal, - le_audio_source_hal_client_.get(), std::placeholders::_1)); - group->StreamOffloaderUpdated(le_audio::types::kLeAudioDirectionSink); - } - - if (stream_conf->source_offloader_changed || - stream_conf->source_is_initial) { - LOG_INFO("Update source offloader streams"); - uint16_t remote_delay_ms = - group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSource); - CodecManager::GetInstance()->UpdateActiveSinkAudioConfig( - *stream_conf, remote_delay_ms, - std::bind(&LeAudioSinkAudioHalClient::UpdateAudioConfigToHal, - le_audio_sink_hal_client_.get(), std::placeholders::_1)); - group->StreamOffloaderUpdated(le_audio::types::kLeAudioDirectionSource); + if ((remote_direction & le_audio::types::kLeAudioDirectionSource) && + le_audio_sink_hal_client_) { + le_audio_sink_hal_client_->UpdateAudioConfigToHal(config); } } @@ -5062,11 +5360,13 @@ class LeAudioClientImpl : public LeAudioClient { false)) { return; } + /* If group is inactive, phone is in call and Group is not having CIS * connected, notify upper layer about it, so it can decide to create SCO if * it is in the handover case */ - if (in_call_ && active_group_id_ == bluetooth::groups::kGroupUnknown) { + if ((IsInCall() || IsInVoipCall()) && + active_group_id_ == bluetooth::groups::kGroupUnknown) { callbacks_->OnGroupStatus(group_id, GroupStatus::TURNED_IDLE_DURING_CALL); } } @@ -5097,16 +5397,43 @@ class LeAudioClientImpl : public LeAudioClient { bluetooth::common::ToString(audio_receiver_state_).c_str()); LeAudioDeviceGroup* group = aseGroups_.FindById(group_id); switch (status) { - case GroupStreamStatus::STREAMING: + case GroupStreamStatus::STREAMING: { ASSERT_LOG(group_id == active_group_id_, "invalid group id %d!=%d", group_id, active_group_id_); + take_stream_time(); + + le_audio::MetricsCollector::Get()->OnStreamStarted( + active_group_id_, configuration_context_type_); + + if (leAudioHealthStatus_) { + leAudioHealthStatus_->AddStatisticForGroup( + group, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); + } + + if (!group) { + LOG_ERROR("Group %d does not exist anymore. This shall not happen ", + group_id); + return; + } + + if ((audio_sender_state_ == AudioState::IDLE) && + (audio_receiver_state_ == AudioState::IDLE)) { + /* Audio Framework is not interested in the stream anymore. + * Just stop streaming + */ + LOG_WARN("Stopping stream for group %d as AF not interested.", + group_id); + groupStateMachine_->StopStream(group); + return; + } + /* It might happen that the configuration has already changed, while * the group was in the ongoing reconfiguration. We should stop the * stream and reconfigure once again. */ - if (group && group->GetConfigurationContextType() != - configuration_context_type_) { + if (group->GetConfigurationContextType() != + configuration_context_type_) { LOG_DEBUG( "The configuration %s is no longer valid. Stopping the stream to" " reconfigure to %s", @@ -5119,24 +5446,25 @@ class LeAudioClientImpl : public LeAudioClient { return; } - if (group) { - updateOffloaderIfNeeded(group); - if (reconnection_mode_ == - BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS) { - group->AddToAllowListNotConnectedGroupMembers(gatt_if_); - } - } + BidirectionalPair delays_pair = { + .sink = + group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink), + .source = group->GetRemoteDelay( + le_audio::types::kLeAudioDirectionSource)}; + CodecManager::GetInstance()->UpdateActiveAudioConfig( + group->stream_conf.stream_params, delays_pair, + std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal, + weak_factory_.GetWeakPtr(), std::placeholders::_1, + std::placeholders::_2)); if (audio_sender_state_ == AudioState::READY_TO_START) StartSendingAudio(group_id); if (audio_receiver_state_ == AudioState::READY_TO_START) StartReceivingAudio(group_id); - take_stream_time(); - - le_audio::MetricsCollector::Get()->OnStreamStarted( - active_group_id_, configuration_context_type_); + SendAudioGroupCurrentCodecConfigChanged(group); break; + } case GroupStreamStatus::SUSPENDED: stream_setup_end_timestamp_ = 0; stream_setup_start_timestamp_ = 0; @@ -5160,7 +5488,6 @@ class LeAudioClientImpl : public LeAudioClient { * so Audio HAL can Resume again. */ CancelStreamingRequest(); - HandlePendingAvailableContextsChange(group); ReconfigurationComplete(previously_active_directions); } break; case GroupStreamStatus::CONFIGURED_AUTONOMOUS: @@ -5169,31 +5496,48 @@ class LeAudioClientImpl : public LeAudioClient { * STREAMING. Peer device uses cache. For the moment * it is handled same as IDLE */ - FALLTHROUGH; case GroupStreamStatus::IDLE: { - if (group && group->IsPendingConfiguration()) { - SuspendedForReconfiguration(); - BidirectionalPair> ccids = { - .sink = ContentControlIdKeeper::GetInstance()->GetAllCcids( - metadata_context_types_.sink), - .source = ContentControlIdKeeper::GetInstance()->GetAllCcids( - metadata_context_types_.source)}; - if (groupStateMachine_->ConfigureStream( - group, configuration_context_type_, metadata_context_types_, - ccids)) { - /* If configuration succeed wait for new status. */ - return; + if (sw_enc_left) sw_enc_left.reset(); + if (sw_enc_right) sw_enc_right.reset(); + if (sw_dec_left) sw_dec_left.reset(); + if (sw_dec_right) sw_dec_right.reset(); + CleanCachedMicrophoneData(); + + if (group) { + UpdateLocationsAndContextsAvailability(group->group_id_); + if (group->IsPendingConfiguration()) { + SuspendedForReconfiguration(); + auto remote_direction = + kLeAudioContextAllRemoteSource.test(configuration_context_type_) + ? le_audio::types::kLeAudioDirectionSource + : le_audio::types::kLeAudioDirectionSink; + auto remote_contexts = + DirectionalRealignMetadataAudioContexts(group, remote_direction); + ApplyRemoteMetadataAudioContextPolicy(group, remote_contexts, + remote_direction); + if (GroupStream(group->group_id_, configuration_context_type_, + remote_contexts)) { + /* If configuration succeed wait for new status. */ + return; + } + LOG_INFO("Clear pending configuration flag for group %d", + group->group_id_); + group->ClearPendingConfiguration(); + } else { + if (sink_monitor_mode_) { + callbacks_->OnUnicastMonitorModeStatus( + le_audio::types::kLeAudioDirectionSink, + UnicastMonitorModeStatus::STREAMING_SUSPENDED); + } } - LOG_INFO("Clear pending configuration flag for group %d", - group->group_id_); - group->ClearPendingConfiguration(); } + stream_setup_end_timestamp_ = 0; stream_setup_start_timestamp_ = 0; CancelStreamingRequest(); + if (group) { NotifyUpperLayerGroupTurnedIdleDuringCall(group->group_id_); - HandlePendingAvailableContextsChange(group); HandlePendingDeviceRemove(group); HandlePendingDeviceDisconnection(group); } @@ -5201,6 +5545,21 @@ class LeAudioClientImpl : public LeAudioClient { } case GroupStreamStatus::RELEASING: case GroupStreamStatus::SUSPENDING: + if (active_group_id_ != bluetooth::groups::kGroupUnknown && + (active_group_id_ == group->group_id_) && + !group->IsPendingConfiguration() && + (audio_sender_state_ == AudioState::STARTED || + audio_receiver_state_ == AudioState::STARTED)) { + /* If releasing state is happening but it was not initiated either by + * reconfiguration or Audio Framework actions either by the Active group change, + * it means that it is some internal state machine error. This is very unlikely and + * for now just Inactivate the group. + */ + LOG_ERROR("Internal state machine error"); + group->PrintDebugState(); + groupSetAndNotifyInactive(); + } + if (audio_sender_state_ != AudioState::IDLE) audio_sender_state_ = AudioState::RELEASING; @@ -5213,6 +5572,15 @@ class LeAudioClientImpl : public LeAudioClient { } } + void OnUpdatedCisConfiguration(int group_id, uint8_t direction) { + LeAudioDeviceGroup* group = aseGroups_.FindById(group_id); + if (!group) { + LOG_ERROR("Invalid group_id: %d", group_id); + return; + } + group->UpdateCisConfiguration(direction); + } + private: tGATT_IF gatt_if_; bluetooth::le_audio::LeAudioClientCallbacks* callbacks_; @@ -5223,7 +5591,7 @@ class LeAudioClientImpl : public LeAudioClient { LeAudioContextType configuration_context_type_; static constexpr char kAllowMultipleContextsInMetadata[] = "persist.bluetooth.leaudio.allow.multiple.contexts"; - BidirectionalPair metadata_context_types_; + BidirectionalPair local_metadata_context_types_; uint64_t stream_setup_start_timestamp_; uint64_t stream_setup_end_timestamp_; std::deque stream_start_history_queue_; @@ -5234,12 +5602,21 @@ class LeAudioClientImpl : public LeAudioClient { AudioState audio_sender_state_; /* Keep in call state. */ bool in_call_; + bool in_voip_call_; + /* Listen for streaming status on Sink stream */ + bool sink_monitor_mode_; + /* Status which has been notified to Service */ + std::optional sink_monitor_notified_status_; /* Reconnection mode */ tBTM_BLE_CONN_TYPE reconnection_mode_; static constexpr uint64_t kGroupConnectedWatchDelayMs = 3000; static constexpr uint64_t kRecoveryReconnectDelayMs = 2000; static constexpr uint64_t kAutoConnectAfterOwnDisconnectDelayMs = 1000; + static constexpr uint64_t kCsisGroupMemberDelayMs = 5000; + + /* LeAudioHealthStatus */ + LeAudioHealthStatus* leAudioHealthStatus_ = nullptr; static constexpr char kNotifyUpperLayerAboutGroupBeingInIdleDuringCall[] = "persist.bluetooth.leaudio.notify.idle.during.call"; @@ -5267,17 +5644,11 @@ class LeAudioClientImpl : public LeAudioClient { .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us, }; - void* lc3_encoder_left_mem; - void* lc3_encoder_right_mem; - - lc3_encoder_t lc3_encoder_left; - lc3_encoder_t lc3_encoder_right; + std::unique_ptr sw_enc_left; + std::unique_ptr sw_enc_right; - void* lc3_decoder_left_mem; - void* lc3_decoder_right_mem; - - lc3_decoder_t lc3_decoder_left; - lc3_decoder_t lc3_decoder_right; + std::unique_ptr sw_dec_left; + std::unique_ptr sw_dec_right; std::vector encoded_data; std::unique_ptr le_audio_source_hal_client_; @@ -5291,24 +5662,44 @@ class LeAudioClientImpl : public LeAudioClient { alarm_t* disable_timer_; static constexpr uint64_t kDeviceAttachDelayMs = 500; - std::vector cached_channel_data_; uint32_t cached_channel_timestamp_ = 0; - uint32_t cached_channel_is_left_; + le_audio::CodecInterface* cached_channel_ = nullptr; + + base::WeakPtrFactory weak_factory_{this}; - void ClientAudioIntefraceRelease() { + void ClientAudioInterfaceRelease() { if (le_audio_source_hal_client_) { le_audio_source_hal_client_->Stop(); le_audio_source_hal_client_.reset(); } if (le_audio_sink_hal_client_) { - le_audio_sink_hal_client_->Stop(); - le_audio_sink_hal_client_.reset(); + /* Keep session set up to monitor streaming request. This is required if + * there is another LE Audio device streaming (e.g. Broadcast) and via + * the session callbacks special action from this Module would be + * required e.g. to Unicast handover. + */ + if (!sink_monitor_mode_) { + local_metadata_context_types_.sink.clear(); + le_audio_sink_hal_client_->Stop(); + le_audio_sink_hal_client_.reset(); + } } + local_metadata_context_types_.source.clear(); + configuration_context_type_ = LeAudioContextType::UNINITIALIZED; + le_audio::MetricsCollector::Get()->OnStreamEnded(active_group_id_); } }; +static void le_audio_health_status_callback(const RawAddress& addr, + int group_id, + LeAudioHealthBasedAction action) { + if (instance) { + instance->LeAudioHealthSendRecommendation(addr, group_id, action); + } +} + /* This is a generic callback method for gatt client which handles every client * application events. */ @@ -5419,6 +5810,16 @@ class CallbacksImpl : public LeAudioGroupStateMachine::Callbacks { void OnStateTransitionTimeout(int group_id) override { if (instance) instance->OnLeAudioDeviceSetStateTimeout(group_id); } + + void OnDeviceAutonomousStateTransitionTimeout( + LeAudioDevice* leAudioDevice) override { + if (instance) + instance->OnDeviceAutonomousStateTransitionTimeout(leAudioDevice); + } + + void OnUpdatedCisConfiguration(int group_id, uint8_t direction) { + if (instance) instance->OnUpdatedCisConfiguration(group_id, direction); + } }; CallbacksImpl stateMachineCallbacksImpl; @@ -5428,34 +5829,32 @@ class SourceCallbacksImpl : public LeAudioSourceAudioHalClient::Callbacks { void OnAudioDataReady(const std::vector& data) override { if (instance) instance->OnAudioDataReady(data); } - void OnAudioSuspend(std::promise do_suspend_promise) override { + void OnAudioSuspend(void) override { if (instance) instance->OnLocalAudioSourceSuspend(); - do_suspend_promise.set_value(); } void OnAudioResume(void) override { if (instance) instance->OnLocalAudioSourceResume(); } - void OnAudioMetadataUpdate( - std::vector source_metadata) override { + void OnAudioMetadataUpdate(source_metadata_v7 source_metadata, + DsaMode dsa_mode) override { if (instance) - instance->OnLocalAudioSourceMetadataUpdate(std::move(source_metadata)); + instance->OnLocalAudioSourceMetadataUpdate(std::move(source_metadata), + dsa_mode); } }; class SinkCallbacksImpl : public LeAudioSinkAudioHalClient::Callbacks { public: - void OnAudioSuspend(std::promise do_suspend_promise) override { + void OnAudioSuspend(void) override { if (instance) instance->OnLocalAudioSinkSuspend(); - do_suspend_promise.set_value(); } void OnAudioResume(void) override { if (instance) instance->OnLocalAudioSinkResume(); } - void OnAudioMetadataUpdate( - std::vector sink_metadata) override { + void OnAudioMetadataUpdate(sink_metadata_v7 sink_metadata) override { if (instance) instance->OnLocalAudioSinkMetadataUpdate(std::move(sink_metadata)); } @@ -5594,6 +5993,10 @@ void LeAudioClient::Initialize( ContentControlIdKeeper::GetInstance()->Start(); callbacks_->OnInitialized(); + + auto cm = CodecManager::GetInstance(); + callbacks_->OnAudioLocalCodecCapabilities(cm->GetLocalAudioInputCodecCapa(), + cm->GetLocalAudioOutputCodecCapa()); } void LeAudioClient::DebugDump(int fd) { @@ -5614,7 +6017,7 @@ void LeAudioClient::DebugDump(int fd) { dprintf(fd, "\n"); } -void LeAudioClient::Cleanup(base::Callback cleanupCb) { +void LeAudioClient::Cleanup(void) { std::scoped_lock lock(instance_mutex); if (!instance) { LOG(ERROR) << "Not initialized"; @@ -5623,7 +6026,7 @@ void LeAudioClient::Cleanup(base::Callback cleanupCb) { LeAudioClientImpl* ptr = instance; instance = nullptr; - ptr->Cleanup(cleanupCb); + ptr->Cleanup(); delete ptr; ptr = nullptr; diff --git a/system/bta/le_audio/client_linux.cc b/system/bta/le_audio/client_linux.cc index 4cc133f1e5019d4eb1ef03278c21578c08cb4480..f905add422fab2d4c5212dbc89c8e180d99c982a 100644 --- a/system/bta/le_audio/client_linux.cc +++ b/system/bta/le_audio/client_linux.cc @@ -50,7 +50,7 @@ void LeAudioClient::Initialize( base::Closure initCb, base::Callback hal_2_1_verifier, const std::vector& offloading_preference) {} -void LeAudioClient::Cleanup(base::Callback cleanupCb) {} +void LeAudioClient::Cleanup(void) {} LeAudioClient* LeAudioClient::Get(void) { return nullptr; } void LeAudioClient::DebugDump(int fd) {} void LeAudioClient::AddFromStorage(const RawAddress& addr, bool autoconnect, @@ -79,5 +79,3 @@ bool LeAudioClient::GetAsesForStorage(const RawAddress& addr, return false; } bool LeAudioClient::IsLeAudioClientRunning() { return false; } -void LeAudioClient::InitializeAudioSetConfigurationProvider(void) {} -void LeAudioClient::CleanupAudioSetConfigurationProvider(void) {} diff --git a/system/bta/le_audio/client_parser.cc b/system/bta/le_audio/client_parser.cc index 7e3f61dd7c8ac1af321b30dda20a4eb60dd843d4..64937af92cfd5665092678a2293929eba67f4798 100644 --- a/system/bta/le_audio/client_parser.cc +++ b/system/bta/le_audio/client_parser.cc @@ -21,21 +21,19 @@ #include "client_parser.h" +#include #include #include #include +#include #include -#include #include -#include "bta_le_audio_api.h" -#include "gap_api.h" -#include "gatt_api.h" -#include "gd/common/strings.h" +#include "internal_include/bt_trace.h" #include "le_audio_types.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" +#include "os/log.h" +#include "stack/include/bt_types.h" using le_audio::types::acs_ac_record; @@ -321,15 +319,14 @@ bool PrepareAseCtpCodecConfig(const std::vector& confs, confs.begin(), confs.end(), confs.size() * kCtpCodecConfMinLen + kAseNumSize + kCtpOpSize, [&conf_ents_str](size_t cur_len, auto const& conf) { - auto ltv_map = conf.codec_config.GetAsLtvMap(); - for (const auto& [type, value] : ltv_map.Values()) { + for (const auto& [type, value] : conf.codec_config.Values()) { conf_ents_str += "\ttype: " + std::to_string(type) + "\tlen: " + std::to_string(value.size()) + "\tdata: " + base::HexEncode(value.data(), value.size()) + "\n"; }; - return cur_len + ltv_map.RawPacketSize(); + return cur_len + conf.codec_config.RawPacketSize(); }); value.resize(msg_len); @@ -345,11 +342,10 @@ bool PrepareAseCtpCodecConfig(const std::vector& confs, UINT16_TO_STREAM(msg, conf.codec_id.vendor_company_id); UINT16_TO_STREAM(msg, conf.codec_id.vendor_codec_id); - auto ltv_map = conf.codec_config.GetAsLtvMap(); - auto codec_spec_conf_len = ltv_map.RawPacketSize(); + auto codec_spec_conf_len = conf.codec_config.RawPacketSize(); UINT8_TO_STREAM(msg, codec_spec_conf_len); - msg = ltv_map.RawPacket(msg); + msg = conf.codec_config.RawPacket(msg); LOG(INFO) << __func__ << ", Codec configuration" << "\n\tAse id: " << loghex(conf.ase_id) @@ -661,40 +657,38 @@ bool ParseAudioLocations(types::AudioLocations& audio_locations, uint16_t len, return true; } -bool ParseSupportedAudioContexts(struct acs_supported_audio_contexts& contexts, - uint16_t len, const uint8_t* value) { +bool ParseSupportedAudioContexts( + types::BidirectionalPair& contexts, uint16_t len, + const uint8_t* value) { if (len != kAseAudioSuppContRspMinLen) { LOG(ERROR) << "Wrong len of Audio Supported Context characteristic"; return false; } - STREAM_TO_UINT16(contexts.snk_supp_cont.value_ref(), value); - STREAM_TO_UINT16(contexts.src_supp_cont.value_ref(), value); + STREAM_TO_UINT16(contexts.sink.value_ref(), value); + STREAM_TO_UINT16(contexts.source.value_ref(), value); LOG(INFO) << "Supported Audio Contexts: " - << "\n\tSupported Sink Contexts: " - << contexts.snk_supp_cont.to_string() - << "\n\tSupported Source Contexts: " - << contexts.src_supp_cont.to_string(); + << "\n\tSupported Sink Contexts: " << contexts.sink.to_string() + << "\n\tSupported Source Contexts: " << contexts.source.to_string(); return true; } -bool ParseAvailableAudioContexts(struct acs_available_audio_contexts& contexts, - uint16_t len, const uint8_t* value) { +bool ParseAvailableAudioContexts( + types::BidirectionalPair& contexts, uint16_t len, + const uint8_t* value) { if (len != kAseAudioAvailRspMinLen) { LOG(ERROR) << "Wrong len of Audio Availability characteristic"; return false; } - STREAM_TO_UINT16(contexts.snk_avail_cont.value_ref(), value); - STREAM_TO_UINT16(contexts.src_avail_cont.value_ref(), value); + STREAM_TO_UINT16(contexts.sink.value_ref(), value); + STREAM_TO_UINT16(contexts.source.value_ref(), value); LOG(INFO) << "Available Audio Contexts: " - << "\n\tAvailable Sink Contexts: " - << contexts.snk_avail_cont.to_string() - << "\n\tAvailable Source Contexts: " - << contexts.src_avail_cont.to_string(); + << "\n\tAvailable Sink Contexts: " << contexts.sink.to_string() + << "\n\tAvailable Source Contexts: " << contexts.source.to_string(); return true; } diff --git a/system/bta/le_audio/client_parser.h b/system/bta/le_audio/client_parser.h index f0918e1ab8198ebce73f11aa2aca05c3aa7fb324..38a7ec1b31c8f052a1c91f18a5c612c23d960b89 100644 --- a/system/bta/le_audio/client_parser.h +++ b/system/bta/le_audio/client_parser.h @@ -161,7 +161,7 @@ struct ctp_codec_conf { uint8_t target_latency; uint8_t target_phy; types::LeAudioCodecId codec_id; - types::LeAudioLc3Config codec_config; + types::LeAudioLtvMap codec_config; }; constexpr uint16_t kCtpQosConfMinLen = 16; @@ -230,16 +230,8 @@ constexpr uint16_t kAcsPacDiscoverRspMinLen = 1; constexpr uint16_t kAudioLocationsRspMinLen = 4; constexpr uint16_t kAseAudioAvailRspMinLen = 4; -struct acs_available_audio_contexts { - types::AudioContexts snk_avail_cont; - types::AudioContexts src_avail_cont; -}; constexpr uint16_t kAseAudioSuppContRspMinLen = 4; -struct acs_supported_audio_contexts { - types::AudioContexts snk_supp_cont; - types::AudioContexts src_supp_cont; -}; int ParseSinglePac(std::vector& pac_recs, uint16_t len, const uint8_t* value); @@ -247,10 +239,12 @@ bool ParsePacs(std::vector& pac_recs, uint16_t len, const uint8_t* value); bool ParseAudioLocations(types::AudioLocations& audio_locations, uint16_t len, const uint8_t* value); -bool ParseAvailableAudioContexts(struct acs_available_audio_contexts& rsp, - uint16_t len, const uint8_t* value); -bool ParseSupportedAudioContexts(struct acs_supported_audio_contexts& rsp, - uint16_t len, const uint8_t* value); +bool ParseAvailableAudioContexts( + types::BidirectionalPair& rsp, uint16_t len, + const uint8_t* value); +bool ParseSupportedAudioContexts( + types::BidirectionalPair& rsp, uint16_t len, + const uint8_t* value); } // namespace pacs namespace tmap { diff --git a/system/bta/le_audio/client_parser_test.cc b/system/bta/le_audio/client_parser_test.cc index 7396702d16d9291a7f0dd765c09d62c39d954747..c9ef3c62625c990b5ef5f0340594b22a04075f5d 100644 --- a/system/bta/le_audio/client_parser_test.cc +++ b/system/bta/le_audio/client_parser_test.cc @@ -522,7 +522,7 @@ TEST(LeAudioClientParserTest, testParseAudioLocations) { } TEST(LeAudioClientParserTest, testParseAvailableAudioContextsInvalidLength) { - acs_available_audio_contexts avail_contexts; + types::BidirectionalPair avail_contexts; const uint8_t value1[] = { // Sink available contexts 0x01, 0x02, @@ -530,12 +530,12 @@ TEST(LeAudioClientParserTest, testParseAvailableAudioContextsInvalidLength) { }; ParseAvailableAudioContexts(avail_contexts, sizeof(value1), value1); - ASSERT_EQ(avail_contexts.snk_avail_cont.value(), 0u); - ASSERT_EQ(avail_contexts.src_avail_cont.value(), 0u); + ASSERT_EQ(avail_contexts.sink.value(), 0u); + ASSERT_EQ(avail_contexts.source.value(), 0u); } TEST(LeAudioClientParserTest, testParseAvailableAudioContexts) { - acs_available_audio_contexts avail_contexts; + types::BidirectionalPair avail_contexts; const uint8_t value1[] = { // Sink available contexts 0x01, @@ -546,12 +546,12 @@ TEST(LeAudioClientParserTest, testParseAvailableAudioContexts) { }; ParseAvailableAudioContexts(avail_contexts, sizeof(value1), value1); - ASSERT_EQ(avail_contexts.snk_avail_cont.value(), 0x0201u); - ASSERT_EQ(avail_contexts.src_avail_cont.value(), 0x0403u); + ASSERT_EQ(avail_contexts.sink.value(), 0x0201u); + ASSERT_EQ(avail_contexts.source.value(), 0x0403u); } TEST(LeAudioClientParserTest, testParseSupportedAudioContextsInvalidLength) { - acs_supported_audio_contexts supp_contexts; + types::BidirectionalPair supp_contexts; const uint8_t value1[] = { // Sink supported contexts 0x01, 0x02, @@ -559,12 +559,12 @@ TEST(LeAudioClientParserTest, testParseSupportedAudioContextsInvalidLength) { }; ParseSupportedAudioContexts(supp_contexts, sizeof(value1), value1); - ASSERT_EQ(supp_contexts.snk_supp_cont.value(), 0u); - ASSERT_EQ(supp_contexts.src_supp_cont.value(), 0u); + ASSERT_EQ(supp_contexts.sink.value(), 0u); + ASSERT_EQ(supp_contexts.source.value(), 0u); } TEST(LeAudioClientParserTest, testParseSupportedAudioContexts) { - acs_supported_audio_contexts supp_contexts; + types::BidirectionalPair supp_contexts; const uint8_t value1[] = { // Sink supported contexts 0x01, @@ -575,8 +575,8 @@ TEST(LeAudioClientParserTest, testParseSupportedAudioContexts) { }; ParseSupportedAudioContexts(supp_contexts, sizeof(value1), value1); - ASSERT_EQ(supp_contexts.snk_supp_cont.value(), 0x0201u); - ASSERT_EQ(supp_contexts.src_supp_cont.value(), 0x0403u); + ASSERT_EQ(supp_contexts.sink.value(), 0x0201u); + ASSERT_EQ(supp_contexts.source.value(), 0x0403u); } } // namespace pacs @@ -1112,10 +1112,14 @@ TEST(LeAudioClientParserTest, testPrepareAseCtpCodecConfigSingle) { types::LeAudioCodecId codec_id{.coding_format = 0x06, .vendor_company_id = 0x0203, .vendor_codec_id = 0x0405}; - types::LeAudioLc3Config codec_conf{.sampling_frequency = 0x10, - .frame_duration = 0x03, - .audio_channel_allocation = 0x04050607, - .octets_per_codec_frame = 0x0203}; + types::LeAudioLtvMap codec_conf = + types::LeAudioLtvMap() + .Add(codec_spec_conf::kLeAudioLtvTypeSamplingFreq, (uint8_t)0x10) + .Add(codec_spec_conf::kLeAudioLtvTypeFrameDuration, (uint8_t)0x03) + .Add(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation, + (uint32_t)0x04050607) + .Add(codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame, + (uint16_t)0x0203); confs.push_back(ctp_codec_conf{ .ase_id = 0x05, @@ -1168,10 +1172,14 @@ TEST(LeAudioClientParserTest, testPrepareAseCtpCodecConfigMultiple) { types::LeAudioCodecId codec_id{.coding_format = 0x06, .vendor_company_id = 0x0203, .vendor_codec_id = 0x0405}; - types::LeAudioLc3Config codec_conf{.sampling_frequency = 0x10, - .frame_duration = 0x03, - .audio_channel_allocation = 0x04050607, - .octets_per_codec_frame = 0x0203}; + types::LeAudioLtvMap codec_conf = + types::LeAudioLtvMap() + .Add(codec_spec_conf::kLeAudioLtvTypeSamplingFreq, (uint8_t)0x10) + .Add(codec_spec_conf::kLeAudioLtvTypeFrameDuration, (uint8_t)0x03) + .Add(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation, + (uint32_t)0x04050607) + .Add(codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame, + (uint16_t)0x0203); confs.push_back(ctp_codec_conf{ .ase_id = 0x05, @@ -1219,10 +1227,14 @@ TEST(LeAudioClientParserTest, testPrepareAseCtpCodecConfigMultiple) { types::LeAudioCodecId codec_id2{.coding_format = 0x16, .vendor_company_id = 0x1213, .vendor_codec_id = 0x1415}; - types::LeAudioLc3Config codec_conf2{.sampling_frequency = 0x11, - .frame_duration = 0x13, - .audio_channel_allocation = 0x14151617, - .octets_per_codec_frame = 0x1213}; + types::LeAudioLtvMap codec_conf2 = + types::LeAudioLtvMap() + .Add(codec_spec_conf::kLeAudioLtvTypeSamplingFreq, (uint8_t)0x11) + .Add(codec_spec_conf::kLeAudioLtvTypeFrameDuration, (uint8_t)0x13) + .Add(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation, + (uint32_t)0x14151617) + .Add(codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame, + (uint16_t)0x1213); confs.push_back(ctp_codec_conf{ .ase_id = 0x15, diff --git a/system/bta/le_audio/codec_interface.cc b/system/bta/le_audio/codec_interface.cc new file mode 100644 index 0000000000000000000000000000000000000000..5a0baf3d5a30fcb88ed07962d85b37d4f7db2813 --- /dev/null +++ b/system/bta/le_audio/codec_interface.cc @@ -0,0 +1,298 @@ +/****************************************************************************** + * + * Copyright (c) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "codec_interface.h" + +#include +#include + +#include +#include +#include + +#include "osi/include/log.h" + +namespace le_audio { + +struct CodecInterface::Impl { + Impl(const types::LeAudioCodecId& codec_id) : codec_id_(codec_id) {} + ~Impl() { Cleanup(); } + + bool IsReady() { return pcm_config_.has_value(); }; + + CodecInterface::Status InitEncoder( + const LeAudioCodecConfiguration& pcm_config, + const LeAudioCodecConfiguration& codec_config) { + // Output codec configuration + bt_codec_config_ = codec_config; + + // TODO: For now only blocks_per_sdu = 1 is supported + if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) { + if (pcm_config_.has_value()) { + Cleanup(); + } + pcm_config_ = pcm_config; + + lc3_.pcm_format_ = (pcm_config_->bits_per_sample == 24) + ? LC3_PCM_FORMAT_S24 + : LC3_PCM_FORMAT_S16; + + // Prepare the encoder + const auto encoder_size = lc3_encoder_size( + bt_codec_config_.data_interval_us, pcm_config_->sample_rate); + lc3_.codec_mem_.reset(malloc(encoder_size)); + lc3_.encoder_ = lc3_setup_encoder( + bt_codec_config_.data_interval_us, bt_codec_config_.sample_rate, + pcm_config_->sample_rate, lc3_.codec_mem_.get()); + + return Status::STATUS_OK; + } + + LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id_.coding_format, + codec_id_.vendor_company_id, codec_id_.vendor_codec_id); + return Status::STATUS_ERR_INVALID_CODEC_ID; + } + + CodecInterface::Status InitDecoder( + const LeAudioCodecConfiguration& codec_config, + const LeAudioCodecConfiguration& pcm_config) { + // Input codec configuration + bt_codec_config_ = codec_config; + + // TODO: For now only blocks_per_sdu = 1 is supported + if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) { + if (pcm_config_.has_value()) { + Cleanup(); + } + pcm_config_ = pcm_config; + + lc3_.pcm_format_ = (pcm_config_->bits_per_sample == 24) + ? LC3_PCM_FORMAT_S24 + : LC3_PCM_FORMAT_S16; + + // Prepare the decoded output buffer + output_channel_samples_ = lc3_frame_samples( + bt_codec_config_.data_interval_us, pcm_config_->sample_rate); + adjustOutputBufferSizeIfNeeded(&output_channel_data_); + + // Prepare the decoder + const auto decoder_size = lc3_decoder_size( + bt_codec_config_.data_interval_us, pcm_config_->sample_rate); + lc3_.codec_mem_.reset(malloc(decoder_size)); + lc3_.decoder_ = lc3_setup_decoder( + bt_codec_config_.data_interval_us, bt_codec_config_.sample_rate, + pcm_config_->sample_rate, lc3_.codec_mem_.get()); + + return Status::STATUS_OK; + } + + LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id_.coding_format, + codec_id_.vendor_company_id, codec_id_.vendor_codec_id); + return Status::STATUS_ERR_INVALID_CODEC_ID; + } + + std::vector& GetDecodedSamples() { return output_channel_data_; } + CodecInterface::Status Decode(uint8_t* data, uint16_t size) { + if (!IsReady()) { + LOG_ERROR("decoder not ready"); + return Status::STATUS_ERR_CODEC_NOT_READY; + } + + // For now only LC3 is supported + if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) { + adjustOutputBufferSizeIfNeeded(&output_channel_data_); + auto err = lc3_decode(lc3_.decoder_, data, size, lc3_.pcm_format_, + output_channel_data_.data(), 1 /* stride */); + if (err < 0) { + LOG(ERROR) << " bad decoding parameters: " << static_cast(err); + return Status::STATUS_ERR_CODING_ERROR; + } + + return Status::STATUS_OK; + } + + LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id_.coding_format, + codec_id_.vendor_company_id, codec_id_.vendor_codec_id); + return Status::STATUS_ERR_INVALID_CODEC_ID; + } + + CodecInterface::Status Encode(const uint8_t* data, int stride, + uint16_t out_size, + std::vector* out_buffer = nullptr, + uint16_t out_offset = 0) { + if (!IsReady()) { + LOG_ERROR("decoder not ready"); + return Status::STATUS_ERR_CODEC_NOT_READY; + } + + if (out_size == 0) { + LOG_ERROR("out_size cannot be 0"); + return Status::STATUS_ERR_CODING_ERROR; + } + + // For now only LC3 is supported + if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) { + // Prepare the encoded output buffer + if (out_buffer == nullptr) { + out_buffer = &output_channel_data_; + } + + // We have two bytes per sample in the buffer, while out_size and + // out_offset are in bytes + size_t channel_samples = (out_offset + out_size) / 2; + if (output_channel_samples_ < channel_samples) { + output_channel_samples_ = channel_samples; + } + adjustOutputBufferSizeIfNeeded(out_buffer); + + // Encode + auto err = + lc3_encode(lc3_.encoder_, lc3_.pcm_format_, data, stride, out_size, + ((uint8_t*)out_buffer->data()) + out_offset); + if (err < 0) { + LOG(ERROR) << " bad encoding parameters: " << static_cast(err); + return Status::STATUS_ERR_CODING_ERROR; + } + + return Status::STATUS_OK; + } + + LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id_.coding_format, + codec_id_.vendor_company_id, codec_id_.vendor_codec_id); + return Status::STATUS_ERR_INVALID_CODEC_ID; + } + + void Cleanup() { + pcm_config_ = std::nullopt; + if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) { + lc3_.Cleanup(); + } + output_channel_data_.clear(); + output_channel_samples_ = 0; + } + + uint16_t GetNumOfSamplesPerChannel() { + if (!IsReady()) { + LOG_ERROR("decoder not ready"); + return 0; + } + + if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) { + return lc3_frame_samples(bt_codec_config_.data_interval_us, + pcm_config_->sample_rate); + } + + LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id_.coding_format, + codec_id_.vendor_company_id, codec_id_.vendor_codec_id); + return 0; + } + + uint8_t GetNumOfBytesPerSample() { + if (codec_id_.coding_format == types::kLeAudioCodingFormatLC3) { + return lc3_.bits_to_bytes_per_sample(bt_codec_config_.bits_per_sample); + } + + LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id_.coding_format, + codec_id_.vendor_company_id, codec_id_.vendor_codec_id); + return 0; + } + + private: + inline void adjustOutputBufferSizeIfNeeded(std::vector* out_buffer) { + if (out_buffer->size() < output_channel_samples_) { + out_buffer->resize(output_channel_samples_); + } + } + + // BT codec params set when codec is initialized + types::LeAudioCodecId codec_id_; + LeAudioCodecConfiguration bt_codec_config_; + std::optional pcm_config_; + + // Output buffer + std::vector output_channel_data_; + size_t output_channel_samples_ = 0; + + // LC3 + struct lc3_t { + static inline uint8_t bits_to_bytes_per_sample(uint8_t bits_per_sample) { + // 24 bit audio stream is sent as unpacked, each sample takes 4 bytes. + if (bits_per_sample == 24) return 4; + return bits_per_sample / 8; + } + + void Cleanup() { + decoder_ = nullptr; + encoder_ = nullptr; + codec_mem_.reset(); + } + + lc3_t() : codec_mem_(nullptr, &std::free) {} + lc3_pcm_format pcm_format_; + union { + lc3_decoder_t decoder_; + lc3_encoder_t encoder_; + }; + std::unique_ptr codec_mem_; + } lc3_; +}; + +CodecInterface::CodecInterface(const types::LeAudioCodecId& codec_id) { + if (codec_id.coding_format == types::kLeAudioCodingFormatLC3) { + impl = new Impl(codec_id); + } else { + LOG_ERROR("Invalid codec ID: [%d:%d:%d]", codec_id.coding_format, + codec_id.vendor_company_id, codec_id.vendor_codec_id); + } +} + +CodecInterface::~CodecInterface() { delete impl; } + +bool CodecInterface::IsReady() { return impl->IsReady(); }; +CodecInterface::Status CodecInterface::InitEncoder( + const LeAudioCodecConfiguration& pcm_config, + const LeAudioCodecConfiguration& codec_config) { + return impl->InitEncoder(pcm_config, codec_config); +} +CodecInterface::Status CodecInterface::InitDecoder( + const LeAudioCodecConfiguration& codec_config, + const LeAudioCodecConfiguration& pcm_config) { + return impl->InitDecoder(codec_config, pcm_config); +} +std::vector& CodecInterface::GetDecodedSamples() { + return impl->GetDecodedSamples(); +} +CodecInterface::Status CodecInterface::Decode(uint8_t* data, uint16_t size) { + return impl->Decode(data, size); +} +CodecInterface::Status CodecInterface::Encode(const uint8_t* data, int stride, + uint16_t out_size, + std::vector* out_buffer, + uint16_t out_offset) { + return impl->Encode(data, stride, out_size, out_buffer, out_offset); +} +void CodecInterface::Cleanup() { return impl->Cleanup(); } + +uint16_t CodecInterface::GetNumOfSamplesPerChannel() { + return impl->GetNumOfSamplesPerChannel(); +}; +uint8_t CodecInterface::GetNumOfBytesPerSample() { + return impl->GetNumOfBytesPerSample(); +}; + +} // namespace le_audio diff --git a/system/bta/le_audio/codec_interface.h b/system/bta/le_audio/codec_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..cd2cca98c604d30eff5d6a54f02f28930a691e2c --- /dev/null +++ b/system/bta/le_audio/codec_interface.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * + * Copyright (c) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#pragma once + +#include + +#include "audio_hal_client/audio_hal_client.h" +#include "le_audio_types.h" + +namespace le_audio { + +/* CodecInterface provides a thin abstraction layer above the codec instance. It + * manages the output buffers internally and resizes them automatically when + * needed. + * Multi-channel stream encoding requires multiple CodecInterface instances, but + * even then it is still possible to encode the stream data into a single output + * buffer. Thanks to the optional parameters to the encode() method, the + * internal buffer of the first instance can be used as an output buffer by the + * second instance, as long as equal life time of both instances is guaranteed. + * + */ +class CodecInterface { + public: + enum class Status { + STATUS_ERR_CODEC_NOT_READY = -128, + STATUS_ERR_INVALID_CODEC_ID = -127, + STATUS_ERR_CODING_ERROR = -1, + STATUS_OK = 0, + }; + + CodecInterface(const types::LeAudioCodecId& codec_id); + virtual ~CodecInterface(); + static std::unique_ptr CreateInstance( + const types::LeAudioCodecId& codec_id) { + return std::make_unique(codec_id); + } + virtual CodecInterface::Status InitEncoder( + const LeAudioCodecConfiguration& pcm_config, + const LeAudioCodecConfiguration& codec_config); + virtual CodecInterface::Status InitDecoder( + const LeAudioCodecConfiguration& codec_config, + const LeAudioCodecConfiguration& pcm_config); + virtual CodecInterface::Status Encode( + const uint8_t* data, int stride, uint16_t out_size, + std::vector* out_buffer = nullptr, uint16_t out_offset = 0); + virtual CodecInterface::Status Decode(uint8_t* data, uint16_t size); + virtual void Cleanup(); + virtual bool IsReady(); + virtual uint16_t GetNumOfSamplesPerChannel(); + virtual uint8_t GetNumOfBytesPerSample(); + virtual std::vector& GetDecodedSamples(); + + private: + struct Impl; + Impl* impl; +}; +} // namespace le_audio diff --git a/system/bta/le_audio/codec_manager.cc b/system/bta/le_audio/codec_manager.cc index 56424822c0153becfe51af5b3d54d0425f1c8d34..ecd18aa6375a4f0a42510faf37105a1f600a62e7 100644 --- a/system/bta/le_audio/codec_manager.cc +++ b/system/bta/le_audio/codec_manager.cc @@ -20,15 +20,16 @@ #include "broadcaster/broadcaster_types.h" #include "device/include/controller.h" #include "le_audio_set_configuration_provider.h" +#include "le_audio_utils.h" #include "osi/include/log.h" #include "osi/include/properties.h" -#include "stack/acl/acl.h" -#include "stack/include/acl_api.h" +#include "stack/include/hcimsgs.h" namespace { using bluetooth::hci::iso_manager::kIsoDataPathHci; using bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault; +using bluetooth::legacy::hci::GetInterface; using le_audio::CodecManager; using le_audio::types::CodecLocation; @@ -39,9 +40,24 @@ using le_audio::set_configurations::AudioSetConfiguration; using le_audio::set_configurations::AudioSetConfigurations; using le_audio::set_configurations::SetConfiguration; +typedef struct offloader_stream_maps { + std::vector streams_map_target; + std::vector streams_map_current; + bool has_changed; + bool is_initial; +} offloader_stream_maps_t; } // namespace namespace le_audio { +template <> +offloader_stream_maps_t& types::BidirectionalPair::get( + uint8_t direction) { + ASSERT_LOG(direction < types::kLeAudioDirectionBoth, + "Unsupported complex direction. Reference to a single complex" + " direction value is not supported."); + return (direction == types::kLeAudioDirectionSink) ? sink : source; +} + // The mapping for sampling rate, frame duration, and the QoS config static std::unordered_map< int, std::unordered_map> @@ -69,8 +85,7 @@ static std::unordered_map< struct codec_manager_impl { public: - codec_manager_impl( - const std::vector& offloading_preference) { + codec_manager_impl() { offload_enable_ = osi_property_get_bool( "ro.bluetooth.leaudio_offload.supported", false) && !osi_property_get_bool( @@ -91,76 +106,87 @@ struct codec_manager_impl { } LOG_INFO("LeAudioCodecManagerImpl: configure_data_path for encode"); - btm_configure_data_path(btm_data_direction::HOST_TO_CONTROLLER, - kIsoDataPathPlatformDefault, {}); - btm_configure_data_path(btm_data_direction::CONTROLLER_TO_HOST, - kIsoDataPathPlatformDefault, {}); - UpdateOffloadCapability(offloading_preference); + GetInterface().ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, + kIsoDataPathPlatformDefault, {}); + GetInterface().ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, + kIsoDataPathPlatformDefault, {}); SetCodecLocation(CodecLocation::ADSP); - SetAidlVersionInUsed(); + } + void start( + const std::vector& offloading_preference) { + le_audio::AudioSetConfigurationProvider::Initialize(GetCodecLocation()); + UpdateOffloadCapability(offloading_preference); } ~codec_manager_impl() { if (GetCodecLocation() != CodecLocation::HOST) { - btm_configure_data_path(btm_data_direction::HOST_TO_CONTROLLER, - kIsoDataPathHci, {}); - btm_configure_data_path(btm_data_direction::CONTROLLER_TO_HOST, - kIsoDataPathHci, {}); + GetInterface().ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, + kIsoDataPathHci, {}); + GetInterface().ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, + kIsoDataPathHci, {}); } + le_audio::AudioSetConfigurationProvider::Cleanup(); } CodecLocation GetCodecLocation(void) const { return codec_location_; } - void UpdateActiveSourceAudioConfig( - const le_audio::stream_configuration& stream_conf, uint16_t delay_ms, - std::function + bool IsOffloadDualBiDirSwbSupported(void) const { + return offload_dual_bidirection_swb_supported_; + } + + std::vector + GetLocalAudioOutputCodecCapa() { + return codec_output_capa; + } + + std::vector + GetLocalAudioInputCodecCapa() { + return codec_input_capa; + } + + void UpdateActiveAudioConfig( + const types::BidirectionalPair& stream_params, + types::BidirectionalPair delays_ms, + std::function update_receiver) { - if (stream_conf.sink_streams.empty()) return; - - if (stream_conf.sink_is_initial || aidl_version_ >= 3) { - sink_config.stream_map = - stream_conf.sink_offloader_streams_target_allocation; - } else { - sink_config.stream_map = - stream_conf.sink_offloader_streams_current_allocation; + if (GetCodecLocation() != le_audio::types::CodecLocation::ADSP) { + return; } - // TODO: set the default value 16 for now, would change it if we support - // mode bits_per_sample - sink_config.bits_per_sample = 16; - sink_config.sampling_rate = stream_conf.sink_sample_frequency_hz; - sink_config.frame_duration = stream_conf.sink_frame_duration_us; - sink_config.octets_per_frame = stream_conf.sink_octets_per_codec_frame; - sink_config.blocks_per_sdu = stream_conf.sink_codec_frames_blocks_per_sdu; - sink_config.peer_delay_ms = delay_ms; - update_receiver(sink_config); - } - - void UpdateActiveSinkAudioConfig( - const le_audio::stream_configuration& stream_conf, uint16_t delay_ms, - std::function - update_receiver) { - if (stream_conf.source_streams.empty()) return; - - if (stream_conf.source_is_initial || aidl_version_ >= 3) { - source_config.stream_map = - stream_conf.source_offloader_streams_target_allocation; - } else { - source_config.stream_map = - stream_conf.source_offloader_streams_current_allocation; + + for (auto direction : {le_audio::types::kLeAudioDirectionSink, + le_audio::types::kLeAudioDirectionSource}) { + auto& stream_map = offloader_stream_maps.get(direction); + if (!stream_map.has_changed && !stream_map.is_initial) { + continue; + } + if (stream_params.get(direction).stream_locations.empty()) { + continue; + } + + le_audio::offload_config unicast_cfg = { + .stream_map = (stream_map.is_initial || + LeAudioHalVerifier::SupportsStreamActiveApi()) + ? stream_map.streams_map_target + : stream_map.streams_map_current, + // TODO: set the default value 16 for now, would change it if we + // support mode bits_per_sample + .bits_per_sample = 16, + .sampling_rate = stream_params.get(direction).sample_frequency_hz, + .frame_duration = stream_params.get(direction).frame_duration_us, + .octets_per_frame = + stream_params.get(direction).octets_per_codec_frame, + .blocks_per_sdu = + stream_params.get(direction).codec_frames_blocks_per_sdu, + .peer_delay_ms = delays_ms.get(direction), + }; + update_receiver(unicast_cfg, direction); + stream_map.is_initial = false; } - // TODO: set the default value 16 for now, would change it if we support - // mode bits_per_sample - source_config.bits_per_sample = 16; - source_config.sampling_rate = stream_conf.source_sample_frequency_hz; - source_config.frame_duration = stream_conf.source_frame_duration_us; - source_config.octets_per_frame = stream_conf.source_octets_per_codec_frame; - source_config.blocks_per_sdu = - stream_conf.source_codec_frames_blocks_per_sdu; - source_config.peer_delay_ms = delay_ms; - update_receiver(source_config); } const AudioSetConfigurations* GetOffloadCodecConfig( types::LeAudioContextType ctx_type) { - return &context_type_offload_config_map_[ctx_type]; + return context_type_offload_config_map_.count(ctx_type) + ? &context_type_offload_config_map_[ctx_type] + : nullptr; } void UpdateSupportedBroadcastConfig( @@ -173,21 +199,18 @@ struct codec_manager_impl { continue; } auto& adsp_config = adsp_audio_set_conf.confs[0]; - const types::LeAudioLc3Config lc3_config = - std::get(adsp_config.codec.config); + + const types::LeAudioCoreCodecConfig core_config = + adsp_config.codec.params.GetAsCoreCodecConfig(); le_audio::broadcast_offload_config broadcast_config; - broadcast_config.stream_map.resize(lc3_config.channel_count); + broadcast_config.stream_map.resize( + core_config.GetChannelCountPerIsoStream()); broadcast_config.bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16; - broadcast_config.sampling_rate = lc3_config.GetSamplingFrequencyHz(); - broadcast_config.frame_duration = lc3_config.GetFrameDurationUs(); - broadcast_config.octets_per_frame = *(lc3_config.octets_per_codec_frame); + broadcast_config.sampling_rate = core_config.GetSamplingFrequencyHz(); + broadcast_config.frame_duration = core_config.GetFrameDurationUs(); + broadcast_config.octets_per_frame = *(core_config.octets_per_codec_frame); broadcast_config.blocks_per_sdu = 1; - // Per LC3 spec, bitrate = (8000 * nbytes) / (frame duration in - // milliseconds) - broadcast_config.codec_bitrate = - (8000 * broadcast_config.octets_per_frame) / - (broadcast_config.frame_duration / 1000); int sample_rate = broadcast_config.sampling_rate; int frame_duration = broadcast_config.frame_duration; @@ -220,14 +243,13 @@ struct codec_manager_impl { LOG_INFO( "stream_map.size(): %zu, sampling_rate: %d, frame_duration(us): %d, " - "octets_per_frame: %d, blocks_per_sdu %d, codec_bitrate: %d, " + "octets_per_frame: %d, blocks_per_sdu %d, " "retransmission_number: %d, max_transport_latency: %d", supported_broadcast_config[0].stream_map.size(), supported_broadcast_config[0].sampling_rate, supported_broadcast_config[0].frame_duration, supported_broadcast_config[0].octets_per_frame, (int)supported_broadcast_config[0].blocks_per_sdu, - (int)supported_broadcast_config[0].codec_bitrate, (int)supported_broadcast_config[0].retransmission_number, supported_broadcast_config[0].max_transport_latency); @@ -256,7 +278,118 @@ struct codec_manager_impl { update_receiver(broadcast_config); } - int GetAidlVersionInUsed(void) const { return aidl_version_; } + void ClearCisConfiguration(uint8_t direction) { + if (GetCodecLocation() != le_audio::types::CodecLocation::ADSP) { + return; + } + + auto& stream_map = offloader_stream_maps.get(direction); + stream_map.streams_map_target.clear(); + stream_map.streams_map_current.clear(); + } + + static uint32_t AdjustAllocationForOffloader(uint32_t allocation) { + if ((allocation & codec_spec_conf::kLeAudioLocationAnyLeft) && + (allocation & codec_spec_conf::kLeAudioLocationAnyRight)) { + return codec_spec_conf::kLeAudioLocationStereo; + } + if (allocation & codec_spec_conf::kLeAudioLocationAnyLeft) { + return codec_spec_conf::kLeAudioLocationFrontLeft; + } + if (allocation & codec_spec_conf::kLeAudioLocationAnyRight) { + return codec_spec_conf::kLeAudioLocationFrontRight; + } + return 0; + } + + void UpdateCisConfiguration(const std::vector& cises, + const stream_parameters& stream_params, + uint8_t direction) { + if (GetCodecLocation() != le_audio::types::CodecLocation::ADSP) { + return; + } + + auto available_allocations = + AdjustAllocationForOffloader(stream_params.audio_channel_allocation); + if (available_allocations == 0) { + LOG_ERROR("There is no CIS connected"); + return; + } + + auto& stream_map = offloader_stream_maps.get(direction); + if (stream_map.streams_map_target.empty()) { + stream_map.is_initial = true; + } else if (stream_map.is_initial || + LeAudioHalVerifier::SupportsStreamActiveApi()) { + /* As multiple CISes phone call case, the target_allocation already have + * the previous data, but the is_initial flag not be cleared. We need to + * clear here to avoid make duplicated target allocation stream map. */ + stream_map.streams_map_target.clear(); + } + + stream_map.streams_map_current.clear(); + stream_map.has_changed = true; + bool all_cises_connected = + (available_allocations == codec_spec_conf::kLeAudioLocationStereo); + + /* If all the cises are connected as stream started, reset changed_flag that + * the bt stack wouldn't send another audio configuration for the connection + * status. */ + if (stream_map.is_initial && all_cises_connected) { + stream_map.has_changed = false; + } + + const std::string tag = types::BidirectionalPair( + {.sink = "Sink", .source = "Source"}) + .get(direction); + + constexpr types::BidirectionalPair cis_types = { + .sink = types::CisType::CIS_TYPE_UNIDIRECTIONAL_SINK, + .source = types::CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE}; + auto cis_type = cis_types.get(direction); + + for (auto const& cis_entry : cises) { + if ((cis_entry.type == types::CisType::CIS_TYPE_BIDIRECTIONAL || + cis_entry.type == cis_type) && + cis_entry.conn_handle != 0) { + uint32_t target_allocation = 0; + uint32_t current_allocation = 0; + bool is_active = false; + for (const auto& s : stream_params.stream_locations) { + if (s.first == cis_entry.conn_handle) { + is_active = true; + target_allocation = AdjustAllocationForOffloader(s.second); + current_allocation = target_allocation; + if (!all_cises_connected) { + /* Tell offloader to mix on this CIS.*/ + current_allocation = codec_spec_conf::kLeAudioLocationStereo; + } + break; + } + } + + if (target_allocation == 0) { + /* Take missing allocation for that one .*/ + target_allocation = + codec_spec_conf::kLeAudioLocationStereo & ~available_allocations; + } + + LOG_INFO( + "%s: Cis handle 0x%04x, target allocation 0x%08x, current " + "allocation 0x%08x, active: %d", + tag.c_str(), cis_entry.conn_handle, target_allocation, + current_allocation, is_active); + + if (stream_map.is_initial || + LeAudioHalVerifier::SupportsStreamActiveApi()) { + stream_map.streams_map_target.emplace_back(stream_map_info( + cis_entry.conn_handle, target_allocation, is_active)); + } + stream_map.streams_map_current.emplace_back(stream_map_info( + cis_entry.conn_handle, current_allocation, is_active)); + } + } + } private: void SetCodecLocation(CodecLocation location) { @@ -264,28 +397,24 @@ struct codec_manager_impl { codec_location_ = location; } - void SetAidlVersionInUsed() { - aidl_version_ = ::bluetooth::audio::le_audio::GetAidlInterfaceVersion(); - LOG(INFO) << __func__ << ": current aidl version: " << aidl_version_; - } - bool IsLc3ConfigMatched( - const set_configurations::CodecCapabilitySetting& adsp_config, - const set_configurations::CodecCapabilitySetting& target_config) { + const set_configurations::CodecConfigSetting& target_config, + const set_configurations::CodecConfigSetting& adsp_config) { if (adsp_config.id.coding_format != types::kLeAudioCodingFormatLC3 || target_config.id.coding_format != types::kLeAudioCodingFormatLC3) { return false; } - const types::LeAudioLc3Config adsp_lc3_config = - std::get(adsp_config.config); - const types::LeAudioLc3Config target_lc3_config = - std::get(target_config.config); + const types::LeAudioCoreCodecConfig adsp_lc3_config = + adsp_config.params.GetAsCoreCodecConfig(); + const types::LeAudioCoreCodecConfig target_lc3_config = + target_config.params.GetAsCoreCodecConfig(); if (adsp_lc3_config.sampling_frequency != target_lc3_config.sampling_frequency || adsp_lc3_config.frame_duration != target_lc3_config.frame_duration || - adsp_lc3_config.channel_count != target_lc3_config.channel_count || + adsp_config.GetChannelCountPerIsoStream() != + target_config.GetChannelCountPerIsoStream() || adsp_lc3_config.octets_per_codec_frame != target_lc3_config.octets_per_codec_frame) { return false; @@ -354,13 +483,104 @@ struct codec_manager_impl { return false; } + std::string getStrategyString(types::LeAudioConfigurationStrategy strategy) { + switch (strategy) { + case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: + return "MONO_ONE_CIS_PER_DEVICE"; + case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: + return "STEREO_TWO_CISES_PER_DEVICE"; + case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE: + return "STEREO_ONE_CIS_PER_DEVICE"; + default: + return "RFU"; + } + } + + uint8_t sampleFreqToBluetoothSigBitMask(int sample_freq) { + switch (sample_freq) { + case 8000: + return le_audio::codec_spec_caps::kLeAudioSamplingFreq8000Hz; + case 16000: + return le_audio::codec_spec_caps::kLeAudioSamplingFreq16000Hz; + case 24000: + return le_audio::codec_spec_caps::kLeAudioSamplingFreq24000Hz; + case 32000: + return le_audio::codec_spec_caps::kLeAudioSamplingFreq32000Hz; + case 44100: + return le_audio::codec_spec_caps::kLeAudioSamplingFreq44100Hz; + case 48000: + return le_audio::codec_spec_caps::kLeAudioSamplingFreq48000Hz; + } + return le_audio::codec_spec_caps::kLeAudioSamplingFreq8000Hz; + } + + void storeLocalCapa( + std::vector<::le_audio::set_configurations::AudioSetConfiguration>& + adsp_capabilities, + const std::vector& offload_preference_set) { + LOG_DEBUG(" Print adsp_capabilities:"); + + for (auto adsp : adsp_capabilities) { + LOG_DEBUG("%s, number of confs %d", adsp.name.c_str(), + (int)(adsp.confs.size())); + for (auto conf : adsp.confs) { + LOG_DEBUG( + "codecId: %d dir: %s, dev_cnt: %d ase_cnt: %d, strategy: %s, " + "sample_freq: %d, interval %d, channel_cnt: %d", + conf.codec.id.coding_format, + (conf.direction == types::kLeAudioDirectionSink ? "sink" + : "source"), + conf.device_cnt, conf.ase_cnt, + getStrategyString(conf.strategy).c_str(), + conf.codec.GetSamplingFrequencyHz(), conf.codec.GetDataIntervalUs(), + conf.codec.GetChannelCountPerIsoStream()); + + /* TODO: How to get bits_per_sample ? */ + btle_audio_codec_config_t capa_to_add = { + .sample_rate = utils::translateToBtLeAudioCodecConfigSampleRate( + conf.codec.GetSamplingFrequencyHz()), + .bits_per_sample = + utils::translateToBtLeAudioCodecConfigBitPerSample(16), + .channel_count = utils::translateToBtLeAudioCodecConfigChannelCount( + conf.codec.GetChannelCountPerIsoStream()), + .frame_duration = + utils::translateToBtLeAudioCodecConfigFrameDuration( + conf.codec.GetDataIntervalUs()), + }; + + if (conf.direction == types::kLeAudioDirectionSink) { + LOG_DEBUG("Adding output capa %d", + static_cast(codec_output_capa.size())); + codec_output_capa.push_back(capa_to_add); + } else { + LOG_DEBUG("Adding input capa %d", + static_cast(codec_input_capa.size())); + codec_input_capa.push_back(capa_to_add); + } + } + } + + LOG_DEBUG("Output capa: %d, Input capa: %d", + static_cast(codec_output_capa.size()), + static_cast(codec_input_capa.size())); + + LOG_DEBUG(" Print offload_preference_set: %d ", + (int)(offload_preference_set.size())); + + int i = 0; + for (auto set : offload_preference_set) { + LOG_DEBUG("set %d, %s ", i++, set.ToString().c_str()); + } + } + void UpdateOffloadCapability( const std::vector& offloading_preference) { LOG(INFO) << __func__; std::unordered_set offload_preference_set; if (AudioSetConfigurationProvider::Get() == nullptr) { - LOG(ERROR) << __func__ << " Audio set configuration provider is not available."; + LOG(ERROR) << __func__ + << " Audio set configuration provider is not available."; return; } @@ -368,6 +588,8 @@ struct codec_manager_impl { adsp_capabilities = ::bluetooth::audio::le_audio::get_offload_capabilities(); + storeLocalCapa(adsp_capabilities, offloading_preference); + for (auto codec : offloading_preference) { auto it = btle_audio_codec_type_map_.find(codec.codec_type); @@ -389,6 +611,11 @@ struct codec_manager_impl { adsp_capabilities)) { LOG(INFO) << "Offload supported conf, context type: " << (int)ctx_type << ", settings -> " << software_audio_set_conf->name; + if (AudioSetConfigurationProvider::Get() + ->CheckConfigurationIsDualBiDirSwb( + *software_audio_set_conf)) { + offload_dual_bidirection_swb_supported_ = true; + } context_type_offload_config_map_[ctx_type].push_back( software_audio_set_conf); } @@ -400,8 +627,8 @@ struct codec_manager_impl { CodecLocation codec_location_ = CodecLocation::HOST; bool offload_enable_ = false; - le_audio::offload_config sink_config; - le_audio::offload_config source_config; + bool offload_dual_bidirection_swb_supported_ = false; + types::BidirectionalPair offloader_stream_maps; std::vector supported_broadcast_config; std::unordered_map context_type_offload_config_map_; @@ -409,8 +636,10 @@ struct codec_manager_impl { btle_audio_codec_type_map_ = { {::bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3, types::kLeAudioCodingFormatLC3}}; - int aidl_version_ = -1; -}; + + std::vector codec_input_capa = {}; + std::vector codec_output_capa = {}; +}; // namespace le_audio struct CodecManager::impl { impl(const CodecManager& codec_manager) : codec_manager_(codec_manager) {} @@ -418,8 +647,8 @@ struct CodecManager::impl { void Start( const std::vector& offloading_preference) { LOG_ASSERT(!codec_manager_impl_); - codec_manager_impl_ = - std::make_unique(offloading_preference); + codec_manager_impl_ = std::make_unique(); + codec_manager_impl_->start(offloading_preference); } void Stop() { @@ -452,30 +681,41 @@ types::CodecLocation CodecManager::GetCodecLocation(void) const { return pimpl_->codec_manager_impl_->GetCodecLocation(); } -int CodecManager::GetAidlVersionInUsed(void) const { +bool CodecManager::IsOffloadDualBiDirSwbSupported(void) const { if (!pimpl_->IsRunning()) { - return -1; + return false; } - return pimpl_->codec_manager_impl_->GetAidlVersionInUsed(); + return pimpl_->codec_manager_impl_->IsOffloadDualBiDirSwbSupported(); } -void CodecManager::UpdateActiveSourceAudioConfig( - const stream_configuration& stream_conf, uint16_t delay_ms, - std::function - update_receiver) { - if (pimpl_->IsRunning()) - pimpl_->codec_manager_impl_->UpdateActiveSourceAudioConfig( - stream_conf, delay_ms, update_receiver); +std::vector +CodecManager::GetLocalAudioOutputCodecCapa() { + if (pimpl_->IsRunning()) { + return pimpl_->codec_manager_impl_->GetLocalAudioOutputCodecCapa(); + } + + std::vector empty{}; + return empty; +} + +std::vector +CodecManager::GetLocalAudioInputCodecCapa() { + if (pimpl_->IsRunning()) { + return pimpl_->codec_manager_impl_->GetLocalAudioOutputCodecCapa(); + } + std::vector empty{}; + return empty; } -void CodecManager::UpdateActiveSinkAudioConfig( - const stream_configuration& stream_conf, uint16_t delay_ms, - std::function +void CodecManager::UpdateActiveAudioConfig( + const types::BidirectionalPair& stream_params, + types::BidirectionalPair delays_ms, + std::function update_receiver) { if (pimpl_->IsRunning()) - pimpl_->codec_manager_impl_->UpdateActiveSinkAudioConfig( - stream_conf, delay_ms, update_receiver); + pimpl_->codec_manager_impl_->UpdateActiveAudioConfig( + stream_params, delays_ms, update_receiver); } const AudioSetConfigurations* CodecManager::GetOffloadCodecConfig( @@ -506,4 +746,19 @@ void CodecManager::UpdateBroadcastConnHandle( } } +void CodecManager::UpdateCisConfiguration( + const std::vector& cises, + const stream_parameters& stream_params, uint8_t direction) { + if (pimpl_->IsRunning()) { + return pimpl_->codec_manager_impl_->UpdateCisConfiguration( + cises, stream_params, direction); + } +} + +void CodecManager::ClearCisConfiguration(uint8_t direction) { + if (pimpl_->IsRunning()) { + return pimpl_->codec_manager_impl_->ClearCisConfiguration(direction); + } +} + } // namespace le_audio diff --git a/system/bta/le_audio/codec_manager.h b/system/bta/le_audio/codec_manager.h index 6bff36ce7c7c8356c05517091f605318ab13b522..6d758bc3d5041667543133eccf591f1e16469597 100644 --- a/system/bta/le_audio/codec_manager.h +++ b/system/bta/le_audio/codec_manager.h @@ -16,11 +16,22 @@ #pragma once +#include "hardware/bt_le_audio.h" #include "le_audio_types.h" -#define AIDL_VERSION_SUPPORT_STREAM_ACTIVE 3 namespace le_audio { +struct stream_map_info { + stream_map_info(uint16_t stream_handle, uint32_t audio_channel_allocation, + bool is_stream_active) + : stream_handle(stream_handle), + audio_channel_allocation(audio_channel_allocation), + is_stream_active(is_stream_active) {} + uint16_t stream_handle; + uint32_t audio_channel_allocation; + bool is_stream_active; +}; + struct offload_config { std::vector stream_map; uint8_t bits_per_sample; @@ -38,14 +49,12 @@ struct broadcast_offload_config { uint32_t frame_duration; uint16_t octets_per_frame; uint8_t blocks_per_sdu; - uint32_t codec_bitrate; uint8_t retransmission_number; uint16_t max_transport_latency; }; class CodecManager { public: - CodecManager(); virtual ~CodecManager() = default; static CodecManager* GetInstance(void) { static CodecManager* instance = new CodecManager(); @@ -55,13 +64,15 @@ class CodecManager { offloading_preference); void Stop(void); virtual types::CodecLocation GetCodecLocation(void) const; - virtual void UpdateActiveSourceAudioConfig( - const stream_configuration& stream_conf, uint16_t delay_ms, - std::function - update_receiver); - virtual void UpdateActiveSinkAudioConfig( - const stream_configuration& stream_conf, uint16_t delay_ms, - std::function + virtual bool IsOffloadDualBiDirSwbSupported(void) const; + virtual void UpdateCisConfiguration( + const std::vector& cises, + const stream_parameters& stream_params, uint8_t direction); + virtual void ClearCisConfiguration(uint8_t direction); + virtual void UpdateActiveAudioConfig( + const types::BidirectionalPair& stream_params, + types::BidirectionalPair delays_ms, + std::function update_receiver); virtual const ::le_audio::set_configurations::AudioSetConfigurations* GetOffloadCodecConfig(::le_audio::types::LeAudioContextType ctx_type); @@ -71,9 +82,13 @@ class CodecManager { const std::vector& conn_handle, std::function update_receiver); - virtual int GetAidlVersionInUsed(void) const; + virtual std::vector + GetLocalAudioOutputCodecCapa(); + virtual std::vector + GetLocalAudioInputCodecCapa(); private: + CodecManager(); struct impl; std::unique_ptr pimpl_; }; diff --git a/system/bta/le_audio/codec_manager_test.cc b/system/bta/le_audio/codec_manager_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..45d12b46295227241916e4560a89db1c2435874b --- /dev/null +++ b/system/bta/le_audio/codec_manager_test.cc @@ -0,0 +1,373 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "codec_manager.h" + +#include +#include + +#include "gd/common/init_flags.h" +#include "le_audio_set_configuration_provider.h" +#include "mock_controller.h" +#include "test/mock/mock_legacy_hci_interface.h" + +using ::testing::_; +using ::testing::Mock; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::Test; + +using bluetooth::hci::iso_manager::kIsoDataPathHci; +using bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault; +using le_audio::set_configurations::AudioSetConfiguration; +using le_audio::types::CodecLocation; +using le_audio::types::kLeAudioDirectionSink; +using le_audio::types::kLeAudioDirectionSource; + +void osi_property_set_bool(const char* key, bool value); + +template +T& le_audio::types::BidirectionalPair::get(uint8_t direction) { + return (direction == le_audio::types::kLeAudioDirectionSink) ? sink : source; +} + +static const std::vector offload_capabilities_none(0); + +const std::vector* offload_capabilities = + &offload_capabilities_none; + +const char* test_flags[] = { + "INIT_default_log_level_str=LOG_VERBOSE", +}; + +namespace bluetooth { +namespace audio { +namespace le_audio { +std::vector get_offload_capabilities() { + return *offload_capabilities; +} +} // namespace le_audio +} // namespace audio +} // namespace bluetooth + +namespace le_audio { +namespace { + +void set_mock_offload_capabilities( + const std::vector& caps) { + offload_capabilities = ∩︀ +} + +static constexpr char kPropLeAudioOffloadSupported[] = + "ro.bluetooth.leaudio_offload.supported"; +static constexpr char kPropLeAudioOffloadDisabled[] = + "persist.bluetooth.leaudio_offload.disabled"; + +class CodecManagerTestBase : public Test { + public: + virtual void SetUp() override { + bluetooth::common::InitFlags::Load(test_flags); + set_mock_offload_capabilities(offload_capabilities_none); + + ON_CALL(controller_interface, SupportsBleIsochronousBroadcaster) + .WillByDefault(Return(true)); + ON_CALL(controller_interface, SupportsConfigureDataPath) + .WillByDefault(Return(true)); + + controller::SetMockControllerInterface(&controller_interface); + bluetooth::legacy::hci::testing::SetMock(legacy_hci_mock_); + + codec_manager = CodecManager::GetInstance(); + } + + virtual void TearDown() override { + codec_manager->Stop(); + + controller::SetMockControllerInterface(nullptr); + } + + NiceMock controller_interface; + CodecManager* codec_manager; + bluetooth::legacy::hci::testing::MockInterface legacy_hci_mock_; +}; + +/*----------------- ADSP codec manager tests ------------------*/ +class CodecManagerTestAdsp : public CodecManagerTestBase { + public: + virtual void SetUp() override { + // Enable the HW offloader + osi_property_set_bool(kPropLeAudioOffloadSupported, true); + osi_property_set_bool(kPropLeAudioOffloadDisabled, false); + + CodecManagerTestBase::SetUp(); + } +}; + +TEST_F(CodecManagerTestAdsp, test_init) { + ASSERT_EQ(codec_manager, CodecManager::GetInstance()); +} + +TEST_F(CodecManagerTestAdsp, test_start) { + EXPECT_CALL(legacy_hci_mock_, + ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, + kIsoDataPathPlatformDefault, _)) + .Times(1); + EXPECT_CALL(legacy_hci_mock_, + ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, + kIsoDataPathPlatformDefault, _)) + .Times(1); + + // Verify data path is reset on Stop() + EXPECT_CALL(legacy_hci_mock_, + ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, + kIsoDataPathHci, _)) + .Times(1); + EXPECT_CALL(legacy_hci_mock_, + ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, + kIsoDataPathHci, _)) + .Times(1); + + const std::vector + offloading_preference(0); + codec_manager->Start(offloading_preference); + + ASSERT_EQ(codec_manager->GetCodecLocation(), CodecLocation::ADSP); +} + +TEST_F(CodecManagerTestAdsp, testStreamConfigurationAdspDownMix) { + const std::vector + offloading_preference(0); + codec_manager->Start(offloading_preference); + + // Current CIS configuration for two earbuds + std::vector cises{ + { + .id = 0x00, + .type = types::CisType::CIS_TYPE_BIDIRECTIONAL, + .conn_handle = 96, + }, + { + .id = 0x01, + .type = types::CisType::CIS_TYPE_BIDIRECTIONAL, + .conn_handle = 97, + }, + }; + + // Stream parameters + types::BidirectionalPair stream_params{ + .sink = + { + .sample_frequency_hz = 16000, + .frame_duration_us = 10000, + .octets_per_codec_frame = 40, + .audio_channel_allocation = + codec_spec_conf::kLeAudioLocationFrontLeft, + .codec_frames_blocks_per_sdu = 1, + .num_of_channels = 1, + .num_of_devices = 1, + .stream_locations = + { + std::pair{ + 97 /*conn_handle*/, + codec_spec_conf::kLeAudioLocationFrontLeft}, + }, + }, + .source = + { + .sample_frequency_hz = 16000, + .frame_duration_us = 10000, + .octets_per_codec_frame = 40, + .audio_channel_allocation = + codec_spec_conf::kLeAudioLocationFrontLeft, + .codec_frames_blocks_per_sdu = 1, + .num_of_channels = 1, + .num_of_devices = 1, + { + std::pair{ + 97 /*conn_handle*/, + codec_spec_conf::kLeAudioLocationBackLeft}, + }, + }, + }; + + codec_manager->UpdateCisConfiguration(cises, stream_params.sink, + kLeAudioDirectionSink); + codec_manager->UpdateCisConfiguration(cises, stream_params.source, + kLeAudioDirectionSource); + + // Verify the offloader config content + types::BidirectionalPair> out_offload_configs; + codec_manager->UpdateActiveAudioConfig( + stream_params, {.sink = 44, .source = 44}, + [&out_offload_configs](const offload_config& config, uint8_t direction) { + out_offload_configs.get(direction) = config; + }); + + // Expect the same configuration for sink and source + ASSERT_TRUE(out_offload_configs.sink.has_value()); + ASSERT_TRUE(out_offload_configs.source.has_value()); + for (auto direction : {le_audio::types::kLeAudioDirectionSink, + le_audio::types::kLeAudioDirectionSource}) { + uint32_t allocation = 0; + auto& config = out_offload_configs.get(direction).value(); + ASSERT_EQ(2lu, config.stream_map.size()); + for (const auto& info : config.stream_map) { + if (info.stream_handle == 96) { + ASSERT_EQ(codec_spec_conf::kLeAudioLocationFrontRight, + info.audio_channel_allocation); + // The disconnected should be inactive + ASSERT_FALSE(info.is_stream_active); + + } else if (info.stream_handle == 97) { + ASSERT_EQ(codec_spec_conf::kLeAudioLocationFrontLeft, + info.audio_channel_allocation); + // The connected should be active + ASSERT_TRUE(info.is_stream_active); + + } else { + ASSERT_EQ(97, info.stream_handle); + } + allocation |= info.audio_channel_allocation; + } + + ASSERT_EQ(16, config.bits_per_sample); + ASSERT_EQ(16000u, config.sampling_rate); + ASSERT_EQ(10000u, config.frame_duration); + ASSERT_EQ(40u, config.octets_per_frame); + ASSERT_EQ(1, config.blocks_per_sdu); + ASSERT_EQ(44, config.peer_delay_ms); + ASSERT_EQ(codec_spec_conf::kLeAudioLocationStereo, allocation); + } + + // Clear the CIS configuration map (no active CISes). + codec_manager->ClearCisConfiguration(kLeAudioDirectionSink); + codec_manager->ClearCisConfiguration(kLeAudioDirectionSource); + out_offload_configs.sink = std::nullopt; + out_offload_configs.source = std::nullopt; + codec_manager->UpdateActiveAudioConfig( + stream_params, {.sink = 44, .source = 44}, + [&out_offload_configs](const offload_config& config, uint8_t direction) { + out_offload_configs.get(direction) = config; + }); + + // Expect sink & source configurations with empty CIS channel allocation map. + ASSERT_TRUE(out_offload_configs.sink.has_value()); + ASSERT_TRUE(out_offload_configs.source.has_value()); + for (auto direction : {le_audio::types::kLeAudioDirectionSink, + le_audio::types::kLeAudioDirectionSource}) { + auto& config = out_offload_configs.get(direction).value(); + ASSERT_EQ(0lu, config.stream_map.size()); + ASSERT_EQ(16, config.bits_per_sample); + ASSERT_EQ(16000u, config.sampling_rate); + ASSERT_EQ(10000u, config.frame_duration); + ASSERT_EQ(40u, config.octets_per_frame); + ASSERT_EQ(1, config.blocks_per_sdu); + ASSERT_EQ(44, config.peer_delay_ms); + } +} + +TEST_F(CodecManagerTestAdsp, test_capabilities_none) { + const std::vector + offloading_preference(0); + codec_manager->Start(offloading_preference); + + // Verify every context + for (::le_audio::types::LeAudioContextType ctx_type : + ::le_audio::types::kLeAudioContextAllTypesArray) { + ASSERT_EQ(nullptr, codec_manager->GetOffloadCodecConfig(ctx_type)); + } +} + +TEST_F(CodecManagerTestAdsp, test_capabilities) { + for (auto test_context : ::le_audio::types::kLeAudioContextAllTypesArray) { + // Build the offloader capabilities vector using the configuration provider + // in HOST mode to get all the .json filce configuration entries. + std::vector offload_capabilities; + AudioSetConfigurationProvider::Initialize( + le_audio::types::CodecLocation::HOST); + for (auto& cap : *AudioSetConfigurationProvider::Get()->GetConfigurations( + test_context)) { + offload_capabilities.push_back(*cap); + } + ASSERT_NE(0u, offload_capabilities.size()); + set_mock_offload_capabilities(offload_capabilities); + // Clean up before the codec manager starts it in ADSP mode. + AudioSetConfigurationProvider::Cleanup(); + + const std::vector + offloading_preference = { + {.codec_type = + bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}}; + codec_manager->Start(offloading_preference); + + auto cfg = codec_manager->GetOffloadCodecConfig(test_context); + ASSERT_NE(nullptr, cfg); + ASSERT_EQ(offload_capabilities.size(), cfg->size()); + + // Clean up the before testing any other offload capabilities. + codec_manager->Stop(); + } +} + +// TODO: Add the unit tests for: +// GetBroadcastOffloadConfig +// UpdateBroadcastConnHandle + +/*----------------- HOST codec manager tests ------------------*/ +class CodecManagerTestHost : public CodecManagerTestBase { + public: + virtual void SetUp() override { + // Enable the HW offloader + osi_property_set_bool(kPropLeAudioOffloadSupported, false); + osi_property_set_bool(kPropLeAudioOffloadDisabled, false); + + CodecManagerTestBase::SetUp(); + } +}; + +TEST_F(CodecManagerTestHost, test_init) { + ASSERT_EQ(codec_manager, CodecManager::GetInstance()); +} + +TEST_F(CodecManagerTestHost, test_start) { + EXPECT_CALL(legacy_hci_mock_, + ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, + kIsoDataPathPlatformDefault, _)) + .Times(0); + EXPECT_CALL(legacy_hci_mock_, + ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, + kIsoDataPathPlatformDefault, _)) + .Times(0); + + // Verify data path is NOT reset on Stop() for the Host encoding session + EXPECT_CALL(legacy_hci_mock_, + ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, + kIsoDataPathHci, _)) + .Times(0); + EXPECT_CALL(legacy_hci_mock_, + ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, + kIsoDataPathHci, _)) + .Times(0); + + const std::vector + offloading_preference(0); + codec_manager->Start(offloading_preference); + + ASSERT_EQ(codec_manager->GetCodecLocation(), CodecLocation::HOST); +} + +} // namespace +} // namespace 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 c1d0a874a93c4c10235366d771a5116aaa6582f0..a1df761d8a7bfe51d3f0dfff0c92cd926889c279 100644 --- a/system/bta/le_audio/content_control_id_keeper.cc +++ b/system/bta/le_audio/content_control_id_keeper.cc @@ -16,6 +16,8 @@ #include "content_control_id_keeper.h" +#include + #include #include diff --git a/system/bta/le_audio/device_groups.cc b/system/bta/le_audio/device_groups.cc new file mode 100644 index 0000000000000000000000000000000000000000..48ce4ad225593c63d643768c1f2c53654cff52dd --- /dev/null +++ b/system/bta/le_audio/device_groups.cc @@ -0,0 +1,2109 @@ +/* + * Copyright 2023 The Android Open Source Project + * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA + * - www.ehima.com + * + * 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 "device_groups.h" + +#include "bta_csis_api.h" +#include "btif_storage.h" +#include "btm_iso_api.h" +#include "device/include/controller.h" +#include "dm/bta_dm_gatt_client.h" +#include "le_audio_set_configuration_provider.h" +#include "metrics_collector.h" + +namespace le_audio { + +using le_audio::types::ase; +using types::AseState; +using types::AudioContexts; +using types::AudioLocations; +using types::BidirectionalPair; +using types::CisState; +using types::CisType; +using types::DataPathState; +using types::LeAudioContextType; +using types::LeAudioCoreCodecConfig; + +/* LeAudioDeviceGroup Class methods implementation */ +void LeAudioDeviceGroup::AddNode( + const std::shared_ptr& leAudioDevice) { + leAudioDevice->group_id_ = group_id_; + leAudioDevices_.push_back(std::weak_ptr(leAudioDevice)); + MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size()); +} + +void LeAudioDeviceGroup::RemoveNode( + const std::shared_ptr& leAudioDevice) { + /* Group information cleaning in the device. */ + leAudioDevice->group_id_ = bluetooth::groups::kGroupUnknown; + for (auto ase : leAudioDevice->ases_) { + ase.active = false; + ase.cis_conn_hdl = 0; + } + + leAudioDevices_.erase( + std::remove_if( + leAudioDevices_.begin(), leAudioDevices_.end(), + [&leAudioDevice](auto& d) { return d.lock() == leAudioDevice; }), + leAudioDevices_.end()); + MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size()); +} + +bool LeAudioDeviceGroup::IsEmpty(void) const { + return leAudioDevices_.size() == 0; +} + +bool LeAudioDeviceGroup::IsAnyDeviceConnected(void) const { + return (NumOfConnected() != 0); +} + +int LeAudioDeviceGroup::Size(void) const { return leAudioDevices_.size(); } + +int LeAudioDeviceGroup::NumOfConnected(LeAudioContextType context_type) const { + if (leAudioDevices_.empty()) return 0; + + bool check_context_type = (context_type != LeAudioContextType::RFU); + AudioContexts type_set(context_type); + + /* return number of connected devices from the set*/ + return std::count_if( + leAudioDevices_.begin(), leAudioDevices_.end(), + [type_set, check_context_type](auto& iter) { + auto dev = iter.lock(); + if (dev) { + if (dev->conn_id_ == GATT_INVALID_CONN_ID) return false; + if (dev->GetConnectionState() != DeviceConnectState::CONNECTED) + return false; + if (!check_context_type) return true; + return dev->GetSupportedContexts().test_any(type_set); + } + return false; + }); +} + +void LeAudioDeviceGroup::ClearSinksFromConfiguration(void) { + LOG_INFO("Group %p, group_id %d", this, group_id_); + + auto direction = types::kLeAudioDirectionSink; + stream_conf.stream_params.get(direction).clear(); + CodecManager::GetInstance()->ClearCisConfiguration(direction); +} + +void LeAudioDeviceGroup::ClearSourcesFromConfiguration(void) { + LOG_INFO("Group %p, group_id %d", this, group_id_); + + auto direction = types::kLeAudioDirectionSource; + stream_conf.stream_params.get(direction).clear(); + CodecManager::GetInstance()->ClearCisConfiguration(direction); +} + +void LeAudioDeviceGroup::ClearAllCises(void) { + LOG_INFO("group_id: %d", group_id_); + cig.cises.clear(); + ClearSinksFromConfiguration(); + ClearSourcesFromConfiguration(); +} + +void LeAudioDeviceGroup::UpdateCisConfiguration(uint8_t direction) { + CodecManager::GetInstance()->UpdateCisConfiguration( + cig.cises, stream_conf.stream_params.get(direction), direction); +} + +void LeAudioDeviceGroup::Cleanup(void) { + /* Bluetooth is off while streaming - disconnect CISes and remove CIG */ + if (GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { + auto& sink_stream_locations = + stream_conf.stream_params.sink.stream_locations; + auto& source_stream_locations = + stream_conf.stream_params.source.stream_locations; + + if (!sink_stream_locations.empty()) { + for (const auto kv_pair : sink_stream_locations) { + auto cis_handle = kv_pair.first; + bluetooth::hci::IsoManager::GetInstance()->DisconnectCis( + cis_handle, HCI_ERR_PEER_USER); + + /* Check the other direction if disconnecting bidirectional CIS */ + if (source_stream_locations.empty()) { + continue; + } + source_stream_locations.erase( + std::remove_if( + source_stream_locations.begin(), source_stream_locations.end(), + [&cis_handle](auto& pair) { return pair.first == cis_handle; }), + source_stream_locations.end()); + } + } + + /* Take care of the non-bidirectional CISes */ + if (!source_stream_locations.empty()) { + for (auto [cis_handle, _] : source_stream_locations) { + bluetooth::hci::IsoManager::GetInstance()->DisconnectCis( + cis_handle, HCI_ERR_PEER_USER); + } + } + } + + /* Note: CIG will stay in the controller. We cannot remove it here, because + * Cises are not yet disconnected. + * When user start Bluetooth, HCI Reset should remove it + */ + + leAudioDevices_.clear(); + ClearAllCises(); +} + +void LeAudioDeviceGroup::Deactivate(void) { + for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice; + leAudioDevice = GetNextActiveDevice(leAudioDevice)) { + for (auto* ase = leAudioDevice->GetFirstActiveAse(); ase; + ase = leAudioDevice->GetNextActiveAse(ase)) { + ase->active = false; + } + } +} + +bool LeAudioDeviceGroup::Activate( + LeAudioContextType context_type, + const BidirectionalPair& metadata_context_types, + BidirectionalPair> ccid_lists) { + bool is_activate = false; + for (auto leAudioDevice : leAudioDevices_) { + if (leAudioDevice.expired()) continue; + + bool activated = leAudioDevice.lock()->ActivateConfiguredAses( + context_type, metadata_context_types, ccid_lists); + LOG_INFO("Device %s is %s", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice.lock().get()->address_), + activated ? "activated" : " not activated"); + if (activated) { + if (!cig.AssignCisIds(leAudioDevice.lock().get())) { + return false; + } + is_activate = true; + } + } + return is_activate; +} + +AudioContexts LeAudioDeviceGroup::GetSupportedContexts(int direction) const { + AudioContexts context; + for (auto& device : leAudioDevices_) { + auto shared_dev = device.lock(); + if (shared_dev) { + context |= shared_dev->GetSupportedContexts(direction); + } + } + return context; +} + +LeAudioDevice* LeAudioDeviceGroup::GetFirstDevice(void) const { + auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), + [](auto& iter) { return !iter.expired(); }); + + if (iter == leAudioDevices_.end()) return nullptr; + + return (iter->lock()).get(); +} + +LeAudioDevice* LeAudioDeviceGroup::GetFirstDeviceWithAvailableContext( + LeAudioContextType context_type) const { + auto iter = std::find_if( + leAudioDevices_.begin(), leAudioDevices_.end(), + [&context_type](auto& iter) { + if (iter.expired()) return false; + return iter.lock()->GetAvailableContexts().test(context_type); + }); + + if ((iter == leAudioDevices_.end()) || (iter->expired())) return nullptr; + + return (iter->lock()).get(); +} + +LeAudioDevice* LeAudioDeviceGroup::GetNextDevice( + LeAudioDevice* leAudioDevice) const { + auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), + [&leAudioDevice](auto& d) { + if (d.expired()) + return false; + else + return (d.lock()).get() == leAudioDevice; + }); + + /* If reference device not found */ + if (iter == leAudioDevices_.end()) return nullptr; + + std::advance(iter, 1); + /* If reference device is last in group */ + if (iter == leAudioDevices_.end()) return nullptr; + + if (iter->expired()) return nullptr; + + return (iter->lock()).get(); +} + +LeAudioDevice* LeAudioDeviceGroup::GetNextDeviceWithAvailableContext( + LeAudioDevice* leAudioDevice, LeAudioContextType context_type) const { + auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), + [&leAudioDevice](auto& d) { + if (d.expired()) + return false; + else + return (d.lock()).get() == leAudioDevice; + }); + + /* If reference device not found */ + if (iter == leAudioDevices_.end()) return nullptr; + + std::advance(iter, 1); + /* If reference device is last in group */ + if (iter == leAudioDevices_.end()) return nullptr; + + iter = std::find_if(iter, leAudioDevices_.end(), [&context_type](auto& d) { + if (d.expired()) + return false; + else + return d.lock()->GetAvailableContexts().test(context_type); + ; + }); + + return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get(); +} + +bool LeAudioDeviceGroup::IsDeviceInTheGroup( + LeAudioDevice* leAudioDevice) const { + auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), + [&leAudioDevice](auto& d) { + if (d.expired()) + return false; + else + return (d.lock()).get() == leAudioDevice; + }); + + if ((iter == leAudioDevices_.end()) || (iter->expired())) return false; + + return true; +} + +bool LeAudioDeviceGroup::IsGroupReadyToCreateStream(void) const { + auto iter = + std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { + if (d.expired()) + return false; + else + return !(((d.lock()).get())->IsReadyToCreateStream()); + }); + + return iter == leAudioDevices_.end(); +} + +bool LeAudioDeviceGroup::IsGroupReadyToSuspendStream(void) const { + auto iter = + std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { + if (d.expired()) + return false; + else + return !(((d.lock()).get())->IsReadyToSuspendStream()); + }); + + return iter == leAudioDevices_.end(); +} + +bool LeAudioDeviceGroup::HaveAnyActiveDeviceInUnconfiguredState() const { + auto iter = + std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { + if (d.expired()) + return false; + else + return (((d.lock()).get())->HaveAnyUnconfiguredAses()); + }); + + return iter != leAudioDevices_.end(); +} + +bool LeAudioDeviceGroup::HaveAllActiveDevicesAsesTheSameState( + AseState state) const { + auto iter = std::find_if( + leAudioDevices_.begin(), leAudioDevices_.end(), [&state](auto& d) { + if (d.expired()) + return false; + else + return !(((d.lock()).get())->HaveAllActiveAsesSameState(state)); + }); + + return iter == leAudioDevices_.end(); +} + +LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDevice(void) const { + auto iter = + std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { + if (d.expired()) + return false; + else + return ((d.lock()).get())->HaveActiveAse(); + }); + + if (iter == leAudioDevices_.end() || iter->expired()) return nullptr; + + return (iter->lock()).get(); +} + +LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDevice( + LeAudioDevice* leAudioDevice) const { + auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), + [&leAudioDevice](auto& d) { + if (d.expired()) + return false; + else + return (d.lock()).get() == leAudioDevice; + }); + + if (iter == leAudioDevices_.end() || + std::distance(iter, leAudioDevices_.end()) < 1) + return nullptr; + + iter = std::find_if(std::next(iter, 1), leAudioDevices_.end(), [](auto& d) { + if (d.expired()) + return false; + else + return ((d.lock()).get())->HaveActiveAse(); + }); + + return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get(); +} + +LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDeviceByCisAndDataPathState( + CisState cis_state, DataPathState data_path_state) const { + auto iter = + std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), + [&data_path_state, &cis_state](auto& d) { + if (d.expired()) { + return false; + } + + return (((d.lock()).get()) + ->GetFirstActiveAseByCisAndDataPathState( + cis_state, data_path_state) != nullptr); + }); + + if (iter == leAudioDevices_.end()) { + return nullptr; + } + + return iter->lock().get(); +} + +LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByCisAndDataPathState( + LeAudioDevice* leAudioDevice, CisState cis_state, + DataPathState data_path_state) const { + auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), + [&leAudioDevice](auto& d) { + if (d.expired()) { + return false; + } + + return d.lock().get() == leAudioDevice; + }); + + if (std::distance(iter, leAudioDevices_.end()) < 1) { + return nullptr; + } + + iter = std::find_if(std::next(iter, 1), leAudioDevices_.end(), + [&cis_state, &data_path_state](auto& d) { + if (d.expired()) { + return false; + } + + return (((d.lock()).get()) + ->GetFirstActiveAseByCisAndDataPathState( + cis_state, data_path_state) != nullptr); + }); + + if (iter == leAudioDevices_.end()) { + return nullptr; + } + + return iter->lock().get(); +} + +uint32_t LeAudioDeviceGroup::GetSduInterval(uint8_t direction) const { + for (LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); + leAudioDevice != nullptr; + leAudioDevice = GetNextActiveDevice(leAudioDevice)) { + struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); + if (!ase) continue; + + return ase->codec_config.GetAsCoreCodecConfig().GetFrameDurationUs(); + } + + return 0; +} + +uint8_t LeAudioDeviceGroup::GetSCA(void) const { + uint8_t sca = bluetooth::hci::iso_manager::kIsoSca0To20Ppm; + + for (const auto& leAudioDevice : leAudioDevices_) { + uint8_t dev_sca = + BTM_GetPeerSCA(leAudioDevice.lock()->address_, BT_TRANSPORT_LE); + + /* If we could not read SCA from the peer device or sca is 0, + * then there is no reason to continue. + */ + if ((dev_sca == 0xFF) || (dev_sca == 0)) return 0; + + /* The Slaves_Clock_Accuracy parameter shall be the worst-case sleep clock + *accuracy of all the slaves that will participate in the CIG. + */ + if (dev_sca < sca) { + sca = dev_sca; + } + } + + return sca; +} + +uint8_t LeAudioDeviceGroup::GetPacking(void) const { + /* TODO: Decide about packing */ + return bluetooth::hci::kIsoCigPackingSequential; +} + +uint8_t LeAudioDeviceGroup::GetFraming(void) const { + LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); + LOG_ASSERT(leAudioDevice) + << __func__ << " Shouldn't be called without an active device."; + + do { + struct ase* ase = leAudioDevice->GetFirstActiveAse(); + if (!ase) continue; + + do { + if (ase->framing == types::kFramingUnframedPduUnsupported) + return bluetooth::hci::kIsoCigFramingFramed; + } while ((ase = leAudioDevice->GetNextActiveAse(ase))); + } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); + + return bluetooth::hci::kIsoCigFramingUnframed; +} + +/* TODO: Preferred parameter may be other than minimum */ +static uint16_t find_max_transport_latency(const LeAudioDeviceGroup* group, + uint8_t direction) { + uint16_t max_transport_latency = 0; + + for (LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice(); + leAudioDevice != nullptr; + leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) { + for (ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); + ase != nullptr; + ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)) { + if (!ase) break; + + if (max_transport_latency == 0) { + // first assignment + max_transport_latency = ase->max_transport_latency; + } else if (ase->max_transport_latency < max_transport_latency) { + if (ase->max_transport_latency != 0) { + max_transport_latency = ase->max_transport_latency; + } else { + LOG_WARN("Trying to set latency back to 0, ASE ID %d", ase->id); + } + } + } + } + + if (max_transport_latency < types::kMaxTransportLatencyMin) { + max_transport_latency = types::kMaxTransportLatencyMin; + } else if (max_transport_latency > types::kMaxTransportLatencyMax) { + max_transport_latency = types::kMaxTransportLatencyMax; + } + + return max_transport_latency; +} + +uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyStom(void) const { + return find_max_transport_latency(this, types::kLeAudioDirectionSource); +} + +uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyMtos(void) const { + return find_max_transport_latency(this, types::kLeAudioDirectionSink); +} + +uint32_t LeAudioDeviceGroup::GetTransportLatencyUs(uint8_t direction) const { + if (direction == types::kLeAudioDirectionSink) { + return transport_latency_mtos_us_; + } else if (direction == types::kLeAudioDirectionSource) { + return transport_latency_stom_us_; + } else { + LOG(ERROR) << __func__ << ", invalid direction"; + return 0; + } +} + +void LeAudioDeviceGroup::SetTransportLatency( + uint8_t direction, uint32_t new_transport_latency_us) { + uint32_t* transport_latency_us; + + if (direction == types::kLeAudioDirectionSink) { + transport_latency_us = &transport_latency_mtos_us_; + } else if (direction == types::kLeAudioDirectionSource) { + transport_latency_us = &transport_latency_stom_us_; + } else { + LOG(ERROR) << __func__ << ", invalid direction"; + return; + } + + if (*transport_latency_us == new_transport_latency_us) return; + + if ((*transport_latency_us != 0) && + (*transport_latency_us != new_transport_latency_us)) { + LOG(WARNING) << __func__ << ", Different transport latency for group: " + << " old: " << static_cast(*transport_latency_us) + << " [us], new: " << static_cast(new_transport_latency_us) + << " [us]"; + return; + } + + LOG(INFO) << __func__ << ", updated group " << static_cast(group_id_) + << " transport latency: " + << static_cast(new_transport_latency_us) << " [us]"; + *transport_latency_us = new_transport_latency_us; +} + +uint8_t LeAudioDeviceGroup::GetRtn(uint8_t direction, uint8_t cis_id) const { + LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); + LOG_ASSERT(leAudioDevice) + << __func__ << " Shouldn't be called without an active device."; + + do { + auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id); + + if (ases_pair.sink && direction == types::kLeAudioDirectionSink) { + return ases_pair.sink->retrans_nb; + } else if (ases_pair.source && + direction == types::kLeAudioDirectionSource) { + return ases_pair.source->retrans_nb; + } + } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); + + return 0; +} + +uint16_t LeAudioDeviceGroup::GetMaxSduSize(uint8_t direction, + uint8_t cis_id) const { + LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); + LOG_ASSERT(leAudioDevice) + << __func__ << " Shouldn't be called without an active device."; + + do { + auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id); + + if (ases_pair.sink && direction == types::kLeAudioDirectionSink) { + return ases_pair.sink->max_sdu_size; + } else if (ases_pair.source && + direction == types::kLeAudioDirectionSource) { + return ases_pair.source->max_sdu_size; + } + } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); + + return 0; +} + +uint8_t LeAudioDeviceGroup::GetPhyBitmask(uint8_t direction) const { + LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); + LOG_ASSERT(leAudioDevice) + << __func__ << " Shouldn't be called without an active device."; + + // local supported PHY's + uint8_t phy_bitfield = bluetooth::hci::kIsoCigPhy1M; + if (controller_get_interface()->supports_ble_2m_phy()) + phy_bitfield |= bluetooth::hci::kIsoCigPhy2M; + + if (!leAudioDevice) { + LOG(ERROR) << "No active leaudio device for direction?: " << +direction; + return phy_bitfield; + } + + do { + struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); + if (!ase) return phy_bitfield; + + do { + if (direction == ase->direction) { + phy_bitfield &= leAudioDevice->GetPhyBitmask(); + + // A value of 0x00 denotes no preference + if (ase->preferred_phy && (phy_bitfield & ase->preferred_phy)) { + phy_bitfield &= ase->preferred_phy; + LOG_DEBUG("Using ASE preferred phy 0x%02x", + static_cast(phy_bitfield)); + } else { + LOG_WARN( + "ASE preferred 0x%02x has nothing common with phy_bitfield " + "0x%02x ", + static_cast(ase->preferred_phy), + static_cast(phy_bitfield)); + } + } + } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase))); + } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); + + return phy_bitfield; +} + +uint8_t LeAudioDeviceGroup::GetTargetPhy(uint8_t direction) const { + uint8_t phy_bitfield = GetPhyBitmask(direction); + + // prefer to use 2M if supported + if (phy_bitfield & bluetooth::hci::kIsoCigPhy2M) + return types::kTargetPhy2M; + else if (phy_bitfield & bluetooth::hci::kIsoCigPhy1M) + return types::kTargetPhy1M; + else + return 0; +} + +bool LeAudioDeviceGroup::GetPresentationDelay(uint32_t* delay, + uint8_t direction) const { + uint32_t delay_min = 0; + uint32_t delay_max = UINT32_MAX; + uint32_t preferred_delay_min = delay_min; + uint32_t preferred_delay_max = delay_max; + + LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); + LOG_ASSERT(leAudioDevice) + << __func__ << " Shouldn't be called without an active device."; + + do { + struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); + if (!ase) continue; // device has no active ASEs in this direction + + do { + /* No common range check */ + if (ase->pres_delay_min > delay_max || ase->pres_delay_max < delay_min) + return false; + + if (ase->pres_delay_min > delay_min) delay_min = ase->pres_delay_min; + if (ase->pres_delay_max < delay_max) delay_max = ase->pres_delay_max; + if (ase->preferred_pres_delay_min > preferred_delay_min) + preferred_delay_min = ase->preferred_pres_delay_min; + if (ase->preferred_pres_delay_max < preferred_delay_max && + ase->preferred_pres_delay_max != types::kPresDelayNoPreference) + preferred_delay_max = ase->preferred_pres_delay_max; + } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase))); + } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); + + if (preferred_delay_min <= preferred_delay_max && + preferred_delay_min > delay_min && preferred_delay_min < delay_max) { + *delay = preferred_delay_min; + } else { + *delay = delay_min; + } + + return true; +} + +uint16_t LeAudioDeviceGroup::GetRemoteDelay(uint8_t direction) const { + uint16_t remote_delay_ms = 0; + uint32_t presentation_delay; + + if (!GetPresentationDelay(&presentation_delay, direction)) { + /* This should never happens at stream request time but to be safe return + * some sample value to not break streaming + */ + return 100; + } + + /* us to ms */ + remote_delay_ms = presentation_delay / 1000; + remote_delay_ms += GetTransportLatencyUs(direction) / 1000; + + return remote_delay_ms; +} + +bool LeAudioDeviceGroup::UpdateAudioContextAvailability(void) { + LOG_DEBUG("%d", group_id_); + auto old_contexts = GetAvailableContexts(); + SetAvailableContexts(GetLatestAvailableContexts()); + return old_contexts != GetAvailableContexts(); +} + +bool LeAudioDeviceGroup::UpdateAudioSetConfigurationCache( + LeAudioContextType ctx_type) { + const le_audio::set_configurations::AudioSetConfiguration* new_conf = + FindFirstSupportedConfiguration(ctx_type); + auto update_config = true; + + if (context_to_configuration_cache_map.count(ctx_type) != 0) { + auto [is_valid, existing_conf] = + context_to_configuration_cache_map.at(ctx_type); + update_config = (new_conf != existing_conf); + /* Just mark it as still valid */ + if (!update_config && !is_valid) { + context_to_configuration_cache_map.at(ctx_type).first = true; + return false; + } + } + + if (update_config) { + context_to_configuration_cache_map[ctx_type] = std::pair(true, new_conf); + LOG_DEBUG("config: %s -> %s", ToHexString(ctx_type).c_str(), + (new_conf ? new_conf->name.c_str() : "(none)")); + } + return update_config; +} + +void LeAudioDeviceGroup::InvalidateCachedConfigurations(void) { + context_to_configuration_cache_map.clear(); +} + +types::BidirectionalPair +LeAudioDeviceGroup::GetLatestAvailableContexts() const { + types::BidirectionalPair contexts; + for (const auto& device : leAudioDevices_) { + auto shared_ptr = device.lock(); + if (shared_ptr && + shared_ptr->GetConnectionState() == DeviceConnectState::CONNECTED) { + contexts.sink |= + shared_ptr->GetAvailableContexts(types::kLeAudioDirectionSink); + contexts.source |= + shared_ptr->GetAvailableContexts(types::kLeAudioDirectionSource); + } + } + return contexts; +} + +bool LeAudioDeviceGroup::ReloadAudioLocations(void) { + AudioLocations updated_snk_audio_locations_ = + codec_spec_conf::kLeAudioLocationNotAllowed; + AudioLocations updated_src_audio_locations_ = + codec_spec_conf::kLeAudioLocationNotAllowed; + + for (const auto& device : leAudioDevices_) { + if (device.expired() || (device.lock().get()->GetConnectionState() != + DeviceConnectState::CONNECTED)) + continue; + updated_snk_audio_locations_ |= device.lock().get()->snk_audio_locations_; + updated_src_audio_locations_ |= device.lock().get()->src_audio_locations_; + } + + /* Nothing has changed */ + if ((updated_snk_audio_locations_ == snk_audio_locations_) && + (updated_src_audio_locations_ == src_audio_locations_)) + return false; + + snk_audio_locations_ = updated_snk_audio_locations_; + src_audio_locations_ = updated_src_audio_locations_; + + return true; +} + +bool LeAudioDeviceGroup::ReloadAudioDirections(void) { + uint8_t updated_audio_directions = 0x00; + + for (const auto& device : leAudioDevices_) { + if (device.expired() || (device.lock().get()->GetConnectionState() != + DeviceConnectState::CONNECTED)) + continue; + updated_audio_directions |= device.lock().get()->audio_directions_; + } + + /* Nothing has changed */ + if (updated_audio_directions == audio_directions_) return false; + + audio_directions_ = updated_audio_directions; + + return true; +} + +bool LeAudioDeviceGroup::IsInTransition(void) const { + return target_state_ != current_state_; +} + +bool LeAudioDeviceGroup::IsStreaming(void) const { + return current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING; +} + +bool LeAudioDeviceGroup::IsReleasingOrIdle(void) const { + return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) || + (current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); +} + +bool LeAudioDeviceGroup::IsGroupStreamReady(void) const { + bool is_device_ready = false; + + /* All connected devices must be ready */ + for (auto& weak : leAudioDevices_) { + auto dev = weak.lock(); + if (!dev) return false; + + /* We are interested here in devices which are connected on profile level + * and devices which are configured (meaning, have actived ASE(s))*/ + if (dev->GetConnectionState() == DeviceConnectState::CONNECTED && + dev->HaveActiveAse()) { + if (!dev->IsReadyToStream()) { + return false; + } + is_device_ready = true; + } + } + return is_device_ready; +} + +bool LeAudioDeviceGroup::HaveAllCisesDisconnected(void) const { + for (auto const dev : leAudioDevices_) { + if (dev.expired()) continue; + if (dev.lock().get()->HaveAnyCisConnected()) return false; + } + return true; +} + +uint8_t LeAudioDeviceGroup::CigConfiguration::GetFirstFreeCisId( + CisType cis_type) const { + LOG_INFO("Group: %p, group_id: %d cis_type: %d", group_, group_->group_id_, + static_cast(cis_type)); + for (size_t id = 0; id < cises.size(); id++) { + if (cises[id].addr.IsEmpty() && cises[id].type == cis_type) { + return id; + } + } + return kInvalidCisId; +} + +types::LeAudioConfigurationStrategy LeAudioDeviceGroup::GetGroupStrategy( + int expected_group_size) const { + /* Simple strategy picker */ + LOG_DEBUG(" Group %d size %d", group_id_, expected_group_size); + if (expected_group_size > 1) { + return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE; + } + + LOG_DEBUG("audio location 0x%04lx", snk_audio_locations_.to_ulong()); + if (!(snk_audio_locations_.to_ulong() & + codec_spec_conf::kLeAudioLocationAnyLeft) || + !(snk_audio_locations_.to_ulong() & + codec_spec_conf::kLeAudioLocationAnyRight)) { + return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE; + } + + auto device = GetFirstDevice(); + auto channel_count_bitmap = + device->GetSupportedAudioChannelCounts(types::kLeAudioDirectionSink); + LOG_DEBUG("Supported channel counts for group %d (device %s) is %d", + group_id_, ADDRESS_TO_LOGGABLE_CSTR(device->address_), + channel_count_bitmap); + if (channel_count_bitmap == 1) { + return types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE; + } + + return types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE; +} + +int LeAudioDeviceGroup::GetAseCount(uint8_t direction) const { + int result = 0; + for (const auto& device_iter : leAudioDevices_) { + result += device_iter.lock()->GetAseCount(direction); + } + + return result; +} + +void LeAudioDeviceGroup::CigConfiguration::GenerateCisIds( + LeAudioContextType context_type) { + LOG_INFO("Group %p, group_id: %d, context_type: %s", group_, + group_->group_id_, + bluetooth::common::ToString(context_type).c_str()); + + if (cises.size() > 0) { + LOG_INFO("CIS IDs already generated"); + return; + } + + const set_configurations::AudioSetConfigurations* confs = + AudioSetConfigurationProvider::Get()->GetConfigurations(context_type); + + uint8_t cis_count_bidir = 0; + uint8_t cis_count_unidir_sink = 0; + uint8_t cis_count_unidir_source = 0; + int csis_group_size = 0; + + if (bluetooth::csis::CsisClient::IsCsisClientRunning()) { + csis_group_size = + bluetooth::csis::CsisClient::Get()->GetDesiredSize(group_->group_id_); + } + /* If this is CSIS group, the csis_group_size will be > 0, otherwise -1. + * If the last happen it means, group size is 1 */ + int group_size = csis_group_size > 0 ? csis_group_size : 1; + + get_cis_count(*confs, group_size, group_->GetGroupStrategy(group_size), + group_->GetAseCount(types::kLeAudioDirectionSink), + group_->GetAseCount(types::kLeAudioDirectionSource), + cis_count_bidir, cis_count_unidir_sink, + cis_count_unidir_source); + + uint8_t idx = 0; + while (cis_count_bidir > 0) { + struct le_audio::types::cis cis_entry = { + .id = idx, + .type = CisType::CIS_TYPE_BIDIRECTIONAL, + .conn_handle = 0, + .addr = RawAddress::kEmpty, + }; + cises.push_back(cis_entry); + cis_count_bidir--; + idx++; + } + + while (cis_count_unidir_sink > 0) { + struct le_audio::types::cis cis_entry = { + .id = idx, + .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK, + .conn_handle = 0, + .addr = RawAddress::kEmpty, + }; + cises.push_back(cis_entry); + cis_count_unidir_sink--; + idx++; + } + + while (cis_count_unidir_source > 0) { + struct le_audio::types::cis cis_entry = { + .id = idx, + .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE, + .conn_handle = 0, + .addr = RawAddress::kEmpty, + }; + cises.push_back(cis_entry); + cis_count_unidir_source--; + idx++; + } +} + +bool LeAudioDeviceGroup::CigConfiguration::AssignCisIds( + LeAudioDevice* leAudioDevice) { + ASSERT_LOG(leAudioDevice, "invalid device"); + LOG_INFO("device: %s", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + + struct ase* ase = leAudioDevice->GetFirstActiveAse(); + if (!ase) { + LOG_ERROR(" Device %s shouldn't be called without an active ASE", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + return false; + } + + for (; ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) { + uint8_t cis_id = kInvalidCisId; + /* CIS ID already set */ + if (ase->cis_id != kInvalidCisId) { + LOG_INFO("ASE ID: %d, is already assigned CIS ID: %d, type %d", ase->id, + ase->cis_id, cises[ase->cis_id].type); + if (!cises[ase->cis_id].addr.IsEmpty()) { + LOG_INFO("Bi-Directional CIS already assigned"); + continue; + } + /* Reuse existing CIS ID if available*/ + cis_id = ase->cis_id; + } + + /* First check if we have bidirectional ASEs. If so, assign same CIS ID.*/ + struct ase* matching_bidir_ase = + leAudioDevice->GetNextActiveAseWithDifferentDirection(ase); + + for (; matching_bidir_ase != nullptr; + matching_bidir_ase = leAudioDevice->GetNextActiveAseWithSameDirection( + matching_bidir_ase)) { + if ((matching_bidir_ase->cis_id != kInvalidCisId) && + (matching_bidir_ase->cis_id != cis_id)) { + LOG_INFO("Bi-Directional CIS is already used. ASE Id: %d cis_id=%d", + matching_bidir_ase->id, matching_bidir_ase->cis_id); + continue; + } + break; + } + + if (matching_bidir_ase) { + if (cis_id == kInvalidCisId) { + cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL); + } + + if (cis_id != kInvalidCisId) { + ase->cis_id = cis_id; + matching_bidir_ase->cis_id = cis_id; + cises[cis_id].addr = leAudioDevice->address_; + + LOG_INFO( + " ASE ID: %d and ASE ID: %d, assigned Bi-Directional CIS ID: %d", + +ase->id, +matching_bidir_ase->id, +ase->cis_id); + continue; + } + + LOG_WARN( + " ASE ID: %d, unable to get free Bi-Directional CIS ID but maybe " + "thats fine. Try using unidirectional.", + ase->id); + } + + if (ase->direction == types::kLeAudioDirectionSink) { + if (cis_id == kInvalidCisId) { + cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SINK); + } + + if (cis_id == kInvalidCisId) { + LOG_WARN( + " Unable to get free Uni-Directional Sink CIS ID - maybe there is " + "bi-directional available"); + /* This could happen when scenarios for given context type allows for + * Sink and Source configuration but also only Sink configuration. + */ + cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL); + if (cis_id == kInvalidCisId) { + LOG_ERROR("Unable to get free Uni-Directional Sink CIS ID"); + return false; + } + } + + ase->cis_id = cis_id; + cises[cis_id].addr = leAudioDevice->address_; + LOG_INFO("ASE ID: %d, assigned Uni-Directional Sink CIS ID: %d", ase->id, + ase->cis_id); + continue; + } + + /* Source direction */ + ASSERT_LOG(ase->direction == types::kLeAudioDirectionSource, + "Expected Source direction, actual=%d", ase->direction); + + if (cis_id == kInvalidCisId) { + cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE); + } + + if (cis_id == kInvalidCisId) { + /* This could happen when scenarios for given context type allows for + * Sink and Source configuration but also only Sink configuration. + */ + LOG_WARN( + "Unable to get free Uni-Directional Source CIS ID - maybe there " + "is bi-directional available"); + cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL); + if (cis_id == kInvalidCisId) { + LOG_ERROR("Unable to get free Uni-Directional Source CIS ID"); + return false; + } + } + + ase->cis_id = cis_id; + cises[cis_id].addr = leAudioDevice->address_; + LOG_INFO("ASE ID: %d, assigned Uni-Directional Source CIS ID: %d", ase->id, + ase->cis_id); + } + + return true; +} + +void LeAudioDeviceGroup::CigConfiguration::AssignCisConnHandles( + const std::vector& conn_handles) { + LOG_INFO("num of cis handles %d", static_cast(conn_handles.size())); + for (size_t i = 0; i < cises.size(); i++) { + cises[i].conn_handle = conn_handles[i]; + LOG_INFO("assigning cis[%d] conn_handle: %d", cises[i].id, + cises[i].conn_handle); + } +} + +void LeAudioDeviceGroup::AssignCisConnHandlesToAses( + LeAudioDevice* leAudioDevice) { + ASSERT_LOG(leAudioDevice, "Invalid device"); + LOG_INFO("group: %p, group_id: %d, device: %s", this, group_id_, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + + /* Assign all CIS connection handles to ases */ + struct le_audio::types::ase* ase = + leAudioDevice->GetFirstActiveAseByCisAndDataPathState( + CisState::IDLE, DataPathState::IDLE); + if (!ase) { + LOG_WARN("No active ASE with Cis and Data path state set to IDLE"); + return; + } + + for (; ase != nullptr; + ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState( + CisState::IDLE, DataPathState::IDLE)) { + auto ases_pair = leAudioDevice->GetAsesByCisId(ase->cis_id); + + if (ases_pair.sink && ases_pair.sink->active) { + ases_pair.sink->cis_conn_hdl = cig.cises[ase->cis_id].conn_handle; + ases_pair.sink->cis_state = CisState::ASSIGNED; + } + if (ases_pair.source && ases_pair.source->active) { + ases_pair.source->cis_conn_hdl = cig.cises[ase->cis_id].conn_handle; + ases_pair.source->cis_state = CisState::ASSIGNED; + } + } +} + +void LeAudioDeviceGroup::AssignCisConnHandlesToAses(void) { + LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); + ASSERT_LOG(leAudioDevice, "Shouldn't be called without an active device."); + + LOG_INFO("Group %p, group_id %d", this, group_id_); + + /* Assign all CIS connection handles to ases */ + for (; leAudioDevice != nullptr; + leAudioDevice = GetNextActiveDevice(leAudioDevice)) { + AssignCisConnHandlesToAses(leAudioDevice); + } +} + +void LeAudioDeviceGroup::CigConfiguration::UnassignCis( + LeAudioDevice* leAudioDevice) { + ASSERT_LOG(leAudioDevice, "Invalid device"); + + LOG_INFO("Group %p, group_id %d, device: %s", group_, group_->group_id_, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + + for (struct le_audio::types::cis& cis_entry : cises) { + if (cis_entry.addr == leAudioDevice->address_) { + cis_entry.addr = RawAddress::kEmpty; + } + } +} + +bool CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy, + const set_configurations::SetConfiguration& conf, + const LeAudioDevice& device) { + /* Check direction and if audio location allows to create more cises to a + * single device. + */ + types::AudioLocations audio_locations = + (conf.direction == types::kLeAudioDirectionSink) + ? device.snk_audio_locations_ + : device.src_audio_locations_; + + LOG_DEBUG("strategy: %d, locations: %lu", (int)strategy, + audio_locations.to_ulong()); + + switch (strategy) { + case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: + return audio_locations.any(); + case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: + if ((audio_locations.to_ulong() & + codec_spec_conf::kLeAudioLocationAnyLeft) && + (audio_locations.to_ulong() & + codec_spec_conf::kLeAudioLocationAnyRight)) + return true; + else + return false; + case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE: { + if (!(audio_locations.to_ulong() & + codec_spec_conf::kLeAudioLocationAnyLeft) || + !(audio_locations.to_ulong() & + codec_spec_conf::kLeAudioLocationAnyRight)) + return false; + + auto channel_count_mask = + device.GetSupportedAudioChannelCounts(conf.direction); + auto requested_channel_count = conf.codec.params.GetAsCoreCodecConfig() + .GetChannelCountPerIsoStream(); + LOG_DEBUG("Requested channel count: %d, supp. channel counts: %s", + requested_channel_count, loghex(channel_count_mask).c_str()); + + /* Return true if requested channel count is set in the supported channel + * counts. In the channel_count_mask, bit 0 is set when 1 channel is + * supported. + */ + return ((1 << (requested_channel_count - 1)) & channel_count_mask); + } + default: + return false; + } + + return false; +} + +/* This method check if group support given audio configuration + * requirement for connected devices in the group and available ASEs + * (no matter on the ASE state) and for given context type + */ +bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported( + const set_configurations::AudioSetConfiguration* audio_set_conf, + LeAudioContextType context_type, + types::LeAudioConfigurationStrategy required_snk_strategy) const { + /* When at least one device supports the configuration context, configure + * for these devices only. Otherwise configure for all devices - we will + * not put this context into the metadata if not supported. + */ + auto num_of_connected = NumOfConnected(context_type); + if (num_of_connected == 0) { + num_of_connected = NumOfConnected(); + } + if (!set_configurations::check_if_may_cover_scenario(audio_set_conf, + num_of_connected)) { + LOG_DEBUG(" cannot cover scenario %s, num. of connected: %d", + bluetooth::common::ToString(context_type).c_str(), + +num_of_connected); + return false; + } + + /* TODO For now: set ase if matching with first pac. + * 1) We assume as well that devices will match requirements in order + * e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc. + * 2) ASEs should be active only if best (according to priority list) full + * scenarion will be covered. + * 3) ASEs should be filled according to performance profile. + */ + for (const auto& ent : (*audio_set_conf).confs) { + LOG_DEBUG(" Looking for configuration: %s - %s", + audio_set_conf->name.c_str(), + (ent.direction == types::kLeAudioDirectionSink ? "snk" : "src")); + + uint8_t required_device_cnt = ent.device_cnt; + uint8_t max_required_ase_per_dev = + ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); + uint8_t active_ase_num = 0; + auto strategy = ent.strategy; + + LOG_DEBUG( + " Number of devices: %d, number of ASEs: %d, Max ASE per device: %d " + "strategy: %d", + +required_device_cnt, +ent.ase_cnt, +max_required_ase_per_dev, + static_cast(strategy)); + + if (ent.direction == types::kLeAudioDirectionSink && + strategy != required_snk_strategy) { + LOG_DEBUG(" Sink strategy mismatch group!=cfg.entry (%d!=%d)", + static_cast(required_snk_strategy), + static_cast(strategy)); + return false; + } + + for (auto* device = GetFirstDevice(); + device != nullptr && required_device_cnt > 0; + device = GetNextDevice(device)) { + /* Skip if device has ASE configured in this direction already */ + + if (device->ases_.empty()) continue; + + if (!device->GetCodecConfigurationSupportedPac(ent.direction, + ent.codec)) { + LOG_DEBUG("Insufficient PAC"); + continue; + } + + int needed_ase = std::min(static_cast(max_required_ase_per_dev), + static_cast(ent.ase_cnt - active_ase_num)); + + if (!CheckIfStrategySupported(strategy, ent, *device)) { + LOG_DEBUG("Strategy not supported"); + continue; + } + + for (auto& ase : device->ases_) { + if (ase.direction != ent.direction) continue; + + active_ase_num++; + needed_ase--; + + if (needed_ase == 0) break; + } + + if (needed_ase > 0) { + LOG_DEBUG("Device has too less ASEs. Still needed ases %d", needed_ase); + return false; + } + + required_device_cnt--; + } + + if (required_device_cnt > 0) { + /* Don't left any active devices if requirements are not met */ + LOG_DEBUG(" could not configure all the devices"); + return false; + } + } + + /* when disabling 32k dual mic, for later join case, we need to + * make sure the device is always choosing the config that its + * sampling rate matches with the sampling rate which is used + * when all devices in the group are connected. + */ + bool dual_bidirection_swb_supported_ = + AudioSetConfigurationProvider::Get()->IsDualBiDirSwbSupported(); + if (Size() > 1 && + AudioSetConfigurationProvider::Get()->CheckConfigurationIsBiDirSwb( + *audio_set_conf)) { + if (!dual_bidirection_swb_supported_ || + (CodecManager::GetInstance()->GetCodecLocation() == + types::CodecLocation::ADSP && + !CodecManager::GetInstance()->IsOffloadDualBiDirSwbSupported())) { + /* two conditions + * 1) dual bidirection swb is not supported for both software/offload + * 2) offload not supported + */ + return false; + } + } + + LOG_DEBUG("Chosen ASE Configuration for group: %d, configuration: %s", + this->group_id_, audio_set_conf->name.c_str()); + return true; +} + +/* This method should choose aproperiate ASEs to be active and set a cached + * configuration for codec and qos. + */ +bool LeAudioDeviceGroup::ConfigureAses( + const set_configurations::AudioSetConfiguration* audio_set_conf, + LeAudioContextType context_type, + const types::BidirectionalPair& metadata_context_types, + const types::BidirectionalPair>& ccid_lists) { + /* When at least one device supports the configuration context, configure + * for these devices only. Otherwise configure for all devices - we will + * not put this context into the metadata if not supported. + */ + auto num_of_connected = NumOfConnected(context_type); + if (num_of_connected == 0) { + num_of_connected = NumOfConnected(); + } + if (!set_configurations::check_if_may_cover_scenario(audio_set_conf, + num_of_connected)) { + return false; + } + + bool reuse_cis_id = + GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; + + /* TODO For now: set ase if matching with first pac. + * 1) We assume as well that devices will match requirements in order + * e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc. + * 2) ASEs should be active only if best (according to priority list) full + * scenarion will be covered. + * 3) ASEs should be filled according to performance profile. + */ + + // WARNING: This may look like the results stored here are unused, but it + // actually shares the intermediate values between the multiple + // configuration calls within the configuration loop. + BidirectionalPair group_audio_locations_memo = { + .sink = 0, .source = 0}; + + for (const auto& ent : (*audio_set_conf).confs) { + LOG_DEBUG(" Looking for requirements: %s, - %s", + audio_set_conf->name.c_str(), + (ent.direction == 1 ? "snk" : "src")); + + uint8_t required_device_cnt = ent.device_cnt; + uint8_t max_required_ase_per_dev = + ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); + uint8_t active_ase_num = 0; + le_audio::types::LeAudioConfigurationStrategy strategy = ent.strategy; + + LOG_DEBUG( + "Number of devices: %d number of ASEs: %d, Max ASE per device: %d " + "strategy: %d", + required_device_cnt, ent.ase_cnt, max_required_ase_per_dev, + (int)strategy); + + auto configuration_closure = [&](LeAudioDevice* dev) -> void { + /* For the moment, we configure only connected devices and when it is + * ready to stream i.e. All ASEs are discovered and dev is reported as + * connected + */ + if (dev->GetConnectionState() != DeviceConnectState::CONNECTED) { + LOG_WARN( + "Device %s, in the state %s", + ADDRESS_TO_LOGGABLE_CSTR(dev->address_), + bluetooth::common::ToString(dev->GetConnectionState()).c_str()); + return; + } + + if (!dev->ConfigureAses(ent, context_type, &active_ase_num, + group_audio_locations_memo, + metadata_context_types, ccid_lists, reuse_cis_id)) + return; + + required_device_cnt--; + }; + + // First use the devices claiming proper support + for (auto* device = GetFirstDeviceWithAvailableContext(context_type); + device != nullptr && required_device_cnt > 0; + device = GetNextDeviceWithAvailableContext(device, context_type)) { + configuration_closure(device); + } + // In case some devices do not support this scenario - us them anyway if + // they are required for the scenario - we will not put this context into + // their metadata anyway + if (required_device_cnt > 0) { + for (auto* device = GetFirstDevice(); + device != nullptr && required_device_cnt > 0; + device = GetNextDevice(device)) { + configuration_closure(device); + } + } + + if (required_device_cnt > 0) { + /* Don't left any active devices if requirements are not met */ + LOG_ERROR(" could not configure all the devices"); + Deactivate(); + return false; + } + } + + LOG_INFO("Choosed ASE Configuration for group: %d, configuration: %s", + group_id_, audio_set_conf->name.c_str()); + + configuration_context_type_ = context_type; + metadata_context_type_ = metadata_context_types; + return true; +} + +const set_configurations::AudioSetConfiguration* +LeAudioDeviceGroup::GetCachedConfiguration( + LeAudioContextType context_type) const { + if (context_to_configuration_cache_map.count(context_type) != 0) { + return context_to_configuration_cache_map.at(context_type).second; + } + return nullptr; +} + +const set_configurations::AudioSetConfiguration* +LeAudioDeviceGroup::GetActiveConfiguration(void) const { + return GetCachedConfiguration(configuration_context_type_); +} + +const set_configurations::AudioSetConfiguration* +LeAudioDeviceGroup::GetConfiguration(LeAudioContextType context_type) { + if (context_type == LeAudioContextType::UNINITIALIZED) { + return nullptr; + } + + const set_configurations::AudioSetConfiguration* conf = nullptr; + bool is_valid = false; + + /* Refresh the cache if there is no valid configuration */ + if (context_to_configuration_cache_map.count(context_type) != 0) { + std::tie(is_valid, conf) = + context_to_configuration_cache_map.at(context_type); + } + if (!is_valid || (conf == nullptr)) { + UpdateAudioSetConfigurationCache(context_type); + } + + return GetCachedConfiguration(context_type); +} + +std::optional +LeAudioDeviceGroup::GetCachedCodecConfigurationByDirection( + LeAudioContextType context_type, uint8_t direction) const { + const set_configurations::AudioSetConfiguration* audio_set_conf = + GetCachedConfiguration(context_type); + if (!audio_set_conf) return std::nullopt; + + LeAudioCodecConfiguration group_config = {0, 0, 0, 0}; + for (const auto& conf : audio_set_conf->confs) { + if (conf.direction != direction) continue; + + if (group_config.sample_rate != 0 && + conf.codec.GetSamplingFrequencyHz() != group_config.sample_rate) { + LOG(WARNING) << __func__ + << ", stream configuration could not be " + "determined (sampling frequency differs) for direction: " + << loghex(direction); + return std::nullopt; + } + group_config.sample_rate = conf.codec.GetSamplingFrequencyHz(); + + if (group_config.data_interval_us != 0 && + conf.codec.GetDataIntervalUs() != group_config.data_interval_us) { + LOG(WARNING) << __func__ + << ", stream configuration could not be " + "determined (data interval differs) for direction: " + << loghex(direction); + return std::nullopt; + } + group_config.data_interval_us = conf.codec.GetDataIntervalUs(); + + if (group_config.bits_per_sample != 0 && + conf.codec.GetBitsPerSample() != group_config.bits_per_sample) { + LOG(WARNING) << __func__ + << ", stream configuration could not be " + "determined (bits per sample differs) for direction: " + << loghex(direction); + return std::nullopt; + } + group_config.bits_per_sample = conf.codec.GetBitsPerSample(); + + group_config.num_channels += + conf.codec.GetChannelCountPerIsoStream() * conf.device_cnt; + } + + if (group_config.IsInvalid()) return std::nullopt; + + return group_config; +} + +std::optional +LeAudioDeviceGroup::GetCodecConfigurationByDirection( + LeAudioContextType context_type, uint8_t direction) { + const set_configurations::AudioSetConfiguration* conf = nullptr; + bool is_valid = false; + + /* Refresh the cache if there is no valid configuration */ + if (context_to_configuration_cache_map.count(context_type) != 0) { + std::tie(is_valid, conf) = + context_to_configuration_cache_map.at(context_type); + } + if (!is_valid || (conf == nullptr)) { + UpdateAudioSetConfigurationCache(context_type); + } + + /* Return the cached value */ + return GetCachedCodecConfigurationByDirection(context_type, direction); +} + +bool LeAudioDeviceGroup::IsAudioSetConfigurationAvailable( + LeAudioContextType group_context_type) { + return GetConfiguration(group_context_type) != nullptr; +} + +bool LeAudioDeviceGroup::IsMetadataChanged( + const BidirectionalPair& context_types, + const BidirectionalPair>& ccid_lists) const { + for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice; + leAudioDevice = GetNextActiveDevice(leAudioDevice)) { + if (leAudioDevice->IsMetadataChanged(context_types, ccid_lists)) + return true; + } + + return false; +} + +bool LeAudioDeviceGroup::IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) const { + auto& sink_stream_locations = stream_conf.stream_params.sink.stream_locations; + auto iter = std::find_if( + sink_stream_locations.begin(), sink_stream_locations.end(), + [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); + + if (iter != sink_stream_locations.end()) return true; + + auto& source_stream_locations = + stream_conf.stream_params.source.stream_locations; + iter = std::find_if( + source_stream_locations.begin(), source_stream_locations.end(), + [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); + + return (iter != source_stream_locations.end()); +} + +void LeAudioDeviceGroup::RemoveCisFromStreamIfNeeded( + LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl) { + LOG_INFO(" CIS Connection Handle: %d", cis_conn_hdl); + + if (!IsCisPartOfCurrentStream(cis_conn_hdl)) return; + + /* Cache the old values for comparison */ + auto old_sink_channels = stream_conf.stream_params.sink.num_of_channels; + auto old_source_channels = stream_conf.stream_params.source.num_of_channels; + + for (auto dir : + {types::kLeAudioDirectionSink, types::kLeAudioDirectionSource}) { + auto& params = stream_conf.stream_params.get(dir); + params.stream_locations.erase( + std::remove_if( + params.stream_locations.begin(), params.stream_locations.end(), + [leAudioDevice, &cis_conn_hdl, ¶ms, dir](auto& pair) { + if (!cis_conn_hdl) { + cis_conn_hdl = pair.first; + } + auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); + if (ases_pair.get(dir) && cis_conn_hdl == pair.first) { + params.num_of_devices--; + params.num_of_channels -= + ases_pair.get(dir) + ->codec_config.GetAsCoreCodecConfig() + .GetChannelCountPerIsoStream(); + params.audio_channel_allocation &= ~pair.second; + } + return (ases_pair.get(dir) && cis_conn_hdl == pair.first); + }), + params.stream_locations.end()); + } + + LOG_INFO( + " Sink Number Of Devices: %d" + ", Sink Number Of Channels: %d" + ", Source Number Of Devices: %d" + ", Source Number Of Channels: %d", + stream_conf.stream_params.sink.num_of_devices, + stream_conf.stream_params.sink.num_of_channels, + stream_conf.stream_params.source.num_of_devices, + stream_conf.stream_params.source.num_of_channels); + + if (stream_conf.stream_params.sink.num_of_channels == 0) { + ClearSinksFromConfiguration(); + } + + if (stream_conf.stream_params.source.num_of_channels == 0) { + ClearSourcesFromConfiguration(); + } + + /* Update CodecManager CIS configuration */ + if (old_sink_channels > stream_conf.stream_params.sink.num_of_channels) { + CodecManager::GetInstance()->UpdateCisConfiguration( + cig.cises, + stream_conf.stream_params.get(le_audio::types::kLeAudioDirectionSink), + le_audio::types::kLeAudioDirectionSink); + } + if (old_source_channels > stream_conf.stream_params.source.num_of_channels) { + CodecManager::GetInstance()->UpdateCisConfiguration( + cig.cises, + stream_conf.stream_params.get(le_audio::types::kLeAudioDirectionSource), + le_audio::types::kLeAudioDirectionSource); + } + + cig.UnassignCis(leAudioDevice); +} + +bool LeAudioDeviceGroup::IsPendingConfiguration(void) const { + return stream_conf.pending_configuration; +} + +void LeAudioDeviceGroup::SetPendingConfiguration(void) { + stream_conf.pending_configuration = true; +} + +void LeAudioDeviceGroup::ClearPendingConfiguration(void) { + stream_conf.pending_configuration = false; +} + +void LeAudioDeviceGroup::Disable(int gatt_if) { + is_enabled_ = false; + + for (auto& device_iter : leAudioDevices_) { + if (!device_iter.lock()->autoconnect_flag_) { + continue; + } + + auto connection_state = device_iter.lock()->GetConnectionState(); + auto address = device_iter.lock()->address_; + + btif_storage_set_leaudio_autoconnect(address, false); + device_iter.lock()->autoconnect_flag_ = false; + + LOG_INFO("Group %d in state %s. Removing %s from background connect", + group_id_, bluetooth::common::ToString(GetState()).c_str(), + ADDRESS_TO_LOGGABLE_CSTR(address)); + + BTA_GATTC_CancelOpen(gatt_if, address, false); + + if (connection_state == DeviceConnectState::CONNECTING_AUTOCONNECT) { + device_iter.lock()->SetConnectionState(DeviceConnectState::DISCONNECTED); + } + } +} + +void LeAudioDeviceGroup::Enable(int gatt_if, + tBTM_BLE_CONN_TYPE reconnection_mode) { + is_enabled_ = true; + for (auto& device_iter : leAudioDevices_) { + if (device_iter.lock()->autoconnect_flag_) { + continue; + } + + auto address = device_iter.lock()->address_; + auto connection_state = device_iter.lock()->GetConnectionState(); + + btif_storage_set_leaudio_autoconnect(address, true); + device_iter.lock()->autoconnect_flag_ = true; + + LOG_INFO("Group %d in state %s. Adding %s from background connect", + group_id_, bluetooth::common::ToString(GetState()).c_str(), + ADDRESS_TO_LOGGABLE_CSTR(address)); + + if (connection_state == DeviceConnectState::DISCONNECTED) { + BTA_GATTC_Open(gatt_if, address, reconnection_mode, false); + device_iter.lock()->SetConnectionState( + DeviceConnectState::CONNECTING_AUTOCONNECT); + } + } +} + +bool LeAudioDeviceGroup::IsEnabled(void) const { return is_enabled_; }; + +void LeAudioDeviceGroup::AddToAllowListNotConnectedGroupMembers(int gatt_if) { + for (const auto& device_iter : leAudioDevices_) { + auto connection_state = device_iter.lock()->GetConnectionState(); + if (connection_state == DeviceConnectState::CONNECTED || + connection_state == DeviceConnectState::CONNECTING_BY_USER || + connection_state == + DeviceConnectState::CONNECTED_BY_USER_GETTING_READY || + connection_state == + DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY) { + continue; + } + + auto address = device_iter.lock()->address_; + LOG_INFO("Group %d in state %s. Adding %s to allow list ", group_id_, + bluetooth::common::ToString(GetState()).c_str(), + ADDRESS_TO_LOGGABLE_CSTR(address)); + + /* When adding set members to allow list, let use direct connect first. + * When it fails (i.e. device is not advertising), it will go to background + * connect. We are doing that because for background connect, stack is using + * slow scan parameters for connection which might delay connecting + * available members. + */ + BTA_GATTC_CancelOpen(gatt_if, address, false); + BTA_GATTC_Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, false); + device_iter.lock()->SetConnectionState( + DeviceConnectState::CONNECTING_AUTOCONNECT); + } +} + +void LeAudioDeviceGroup::ApplyReconnectionMode( + int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode) { + for (const auto& device_iter : leAudioDevices_) { + BTA_GATTC_CancelOpen(gatt_if, device_iter.lock()->address_, false); + BTA_GATTC_Open(gatt_if, device_iter.lock()->address_, reconnection_mode, + false); + LOG_INFO("Group %d in state %s. Adding %s to default reconnection mode ", + group_id_, bluetooth::common::ToString(GetState()).c_str(), + ADDRESS_TO_LOGGABLE_CSTR(device_iter.lock()->address_)); + device_iter.lock()->SetConnectionState( + DeviceConnectState::CONNECTING_AUTOCONNECT); + } +} + +bool LeAudioDeviceGroup::IsConfiguredForContext( + LeAudioContextType context_type) const { + /* Check if all connected group members are configured */ + if (GetConfigurationContextType() != context_type) { + return false; + } + + /* Check if used configuration is same as the active one.*/ + return (stream_conf.conf == GetActiveConfiguration()); +} + +bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported( + LeAudioDevice* leAudioDevice, + const set_configurations::AudioSetConfiguration* audio_set_conf) const { + for (const auto& ent : (*audio_set_conf).confs) { + LOG_INFO("Looking for requirements: %s - %s", audio_set_conf->name.c_str(), + (ent.direction == 1 ? "snk" : "src")); + auto pac = leAudioDevice->GetCodecConfigurationSupportedPac(ent.direction, + ent.codec); + if (pac != nullptr) { + LOG_INFO("Configuration is supported by device %s", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + return true; + } + } + + LOG_INFO("Configuration is NOT supported by device %s", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + return false; +} + +const set_configurations::AudioSetConfiguration* +LeAudioDeviceGroup::FindFirstSupportedConfiguration( + LeAudioContextType context_type) const { + const set_configurations::AudioSetConfigurations* confs = + AudioSetConfigurationProvider::Get()->GetConfigurations(context_type); + + LOG_DEBUG("context type: %s, number of connected devices: %d", + bluetooth::common::ToString(context_type).c_str(), + +NumOfConnected()); + + auto num_of_connected = NumOfConnected(context_type); + if (num_of_connected == 0) { + num_of_connected = NumOfConnected(); + } + /* Filter out device set for all scenarios */ + if (!set_configurations::check_if_may_cover_scenario(confs, + num_of_connected)) { + LOG_DEBUG(", group is unable to cover scenario"); + return nullptr; + } + + /* Filter out device set for each end every scenario */ + + auto required_snk_strategy = GetGroupStrategy(Size()); + for (const auto& conf : *confs) { + if (IsAudioSetConfigurationSupported(conf, context_type, + required_snk_strategy)) { + LOG_DEBUG("found: %s", conf->name.c_str()); + return conf; + } + } + + return nullptr; +} + +/* This method should choose aproperiate ASEs to be active and set a cached + * configuration for codec and qos. + */ +bool LeAudioDeviceGroup::Configure( + LeAudioContextType context_type, + const types::BidirectionalPair& metadata_context_types, + types::BidirectionalPair> ccid_lists) { + auto conf = GetConfiguration(context_type); + if (!conf) { + LOG_ERROR( + ", requested context type: %s , is in mismatch with cached available " + "contexts ", + bluetooth::common::ToString(context_type).c_str()); + return false; + } + + LOG_DEBUG(" setting context type: %s", + bluetooth::common::ToString(context_type).c_str()); + + if (!ConfigureAses(conf, context_type, metadata_context_types, ccid_lists)) { + LOG_ERROR( + ", requested context type: %s , is in mismatch with cached available " + "contexts", + bluetooth::common::ToString(context_type).c_str()); + return false; + } + + /* Store selected configuration at once it is chosen. + * It might happen it will get unavailable in some point of time + */ + stream_conf.conf = conf; + return true; +} + +LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); } + +void LeAudioDeviceGroup::PrintDebugState(void) const { + auto* active_conf = GetActiveConfiguration(); + std::stringstream debug_str; + + debug_str << "\n Groupd id: " << group_id_ + << (is_enabled_ ? " enabled" : " disabled") + << ", state: " << bluetooth::common::ToString(GetState()) + << ", target state: " + << bluetooth::common::ToString(GetTargetState()) + << ", cig state: " << bluetooth::common::ToString(cig.GetState()) + << ", \n group supported contexts: " + << bluetooth::common::ToString(GetSupportedContexts()) + << ", \n group available contexts: " + << bluetooth::common::ToString(GetAvailableContexts()) + << ", \n configuration context type: " + << bluetooth::common::ToString(GetConfigurationContextType()) + << ", \n active configuration name: " + << (active_conf ? active_conf->name : " not set"); + + if (cig.cises.size() > 0) { + LOG_INFO("\n Allocated CISes: %d", static_cast(cig.cises.size())); + for (auto cis : cig.cises) { + LOG_INFO("\n cis id: %d, type: %d, conn_handle %d, addr: %s", cis.id, + cis.type, cis.conn_handle, cis.addr.ToString().c_str()); + } + } + + if (GetFirstActiveDevice() != nullptr) { + uint32_t sink_delay = 0; + uint32_t source_delay = 0; + GetPresentationDelay(&sink_delay, le_audio::types::kLeAudioDirectionSink); + GetPresentationDelay(&source_delay, + le_audio::types::kLeAudioDirectionSource); + auto phy_mtos = GetPhyBitmask(le_audio::types::kLeAudioDirectionSink); + auto phy_stom = GetPhyBitmask(le_audio::types::kLeAudioDirectionSource); + auto max_transport_latency_mtos = GetMaxTransportLatencyMtos(); + auto max_transport_latency_stom = GetMaxTransportLatencyStom(); + auto sdu_mts = GetSduInterval(le_audio::types::kLeAudioDirectionSink); + auto sdu_stom = GetSduInterval(le_audio::types::kLeAudioDirectionSource); + + debug_str << "\n presentation_delay for sink (speaker): " << +sink_delay + << " us, presentation_delay for source (microphone): " + << +source_delay << "us, \n MtoS transport latency: " + << +max_transport_latency_mtos + << ", StoM transport latency: " << +max_transport_latency_stom + << ", \n MtoS Phy: " << loghex(phy_mtos) + << ", MtoS sdu: " << loghex(phy_stom) + << " \n MtoS sdu: " << +sdu_mts << ", StoM sdu: " << +sdu_stom; + } + + LOG_INFO("%s", debug_str.str().c_str()); + + for (const auto& device_iter : leAudioDevices_) { + device_iter.lock()->PrintDebugState(); + } +} + +void LeAudioDeviceGroup::Dump(int fd, int active_group_id) const { + bool is_active = (group_id_ == active_group_id); + std::stringstream stream, stream_pacs; + auto* active_conf = GetActiveConfiguration(); + + stream << "\n == Group id: " << group_id_ + << (is_enabled_ ? " enabled" : " disabled") + << " == " << (is_active ? ",\tActive\n" : ",\tInactive\n") + << " state: " << GetState() + << ",\ttarget state: " << GetTargetState() + << ",\tcig state: " << cig.GetState() << "\n" + << " group supported contexts: " << GetSupportedContexts() << "\n" + << " group available contexts: " << GetAvailableContexts() << "\n" + << " configuration context type: " + << bluetooth::common::ToString(GetConfigurationContextType()).c_str() + << "\n" + << " active configuration name: " + << (active_conf ? active_conf->name : " not set") << "\n" + << " stream configuration: " + << (stream_conf.conf != nullptr ? stream_conf.conf->name : " unknown ") + << "\n" + << " codec id: " << +(stream_conf.codec_id.coding_format) + << ",\tpending_configuration: " << stream_conf.pending_configuration + << "\n" + << " num of devices(connected): " << Size() << "(" + << NumOfConnected() << ")\n" + << ", num of sinks(connected): " + << stream_conf.stream_params.sink.num_of_devices << "(" + << stream_conf.stream_params.sink.stream_locations.size() << ")\n" + << " num of sources(connected): " + << stream_conf.stream_params.source.num_of_devices << "(" + << stream_conf.stream_params.source.stream_locations.size() << ")\n" + << " allocated CISes: " << static_cast(cig.cises.size()); + + if (cig.cises.size() > 0) { + stream << "\n\t == CISes == "; + for (auto cis : cig.cises) { + stream << "\n\t cis id: " << static_cast(cis.id) + << ",\ttype: " << static_cast(cis.type) + << ",\tconn_handle: " << static_cast(cis.conn_handle) + << ",\taddr: " << ADDRESS_TO_LOGGABLE_STR(cis.addr); + } + stream << "\n\t ===="; + } + + if (GetFirstActiveDevice() != nullptr) { + uint32_t sink_delay; + if (GetPresentationDelay(&sink_delay, + le_audio::types::kLeAudioDirectionSink)) { + stream << "\n presentation_delay for sink (speaker): " << sink_delay + << " us"; + } + + uint32_t source_delay; + if (GetPresentationDelay(&source_delay, + le_audio::types::kLeAudioDirectionSource)) { + stream << "\n presentation_delay for source (microphone): " + << source_delay << " us"; + } + } + + stream << "\n == devices: =="; + + dprintf(fd, "%s", stream.str().c_str()); + + for (const auto& device_iter : leAudioDevices_) { + device_iter.lock()->Dump(fd); + } + + for (const auto& device_iter : leAudioDevices_) { + auto device = device_iter.lock(); + stream_pacs << "\n\taddress: " << device->address_; + device->DumpPacsDebugState(stream_pacs); + } + dprintf(fd, "%s", stream_pacs.str().c_str()); +} + +LeAudioDeviceGroup* LeAudioDeviceGroups::Add(int group_id) { + /* Get first free group id */ + if (FindById(group_id)) { + LOG(ERROR) << __func__ + << ", group already exists, id: " << loghex(group_id); + return nullptr; + } + + return (groups_.emplace_back(std::make_unique(group_id))) + .get(); +} + +void LeAudioDeviceGroups::Remove(int group_id) { + auto iter = std::find_if( + groups_.begin(), groups_.end(), + [&group_id](auto const& group) { return group->group_id_ == group_id; }); + + if (iter == groups_.end()) { + LOG(ERROR) << __func__ << ", no such group_id: " << group_id; + return; + } + + groups_.erase(iter); +} + +LeAudioDeviceGroup* LeAudioDeviceGroups::FindById(int group_id) const { + auto iter = std::find_if( + groups_.begin(), groups_.end(), + [&group_id](auto const& group) { return group->group_id_ == group_id; }); + + return (iter == groups_.end()) ? nullptr : iter->get(); +} + +void LeAudioDeviceGroups::Cleanup(void) { + for (auto& g : groups_) { + g->Cleanup(); + } + + groups_.clear(); +} + +void LeAudioDeviceGroups::Dump(int fd, int active_group_id) const { + /* Dump first active group */ + for (auto& g : groups_) { + if (g->group_id_ == active_group_id) { + g->Dump(fd, active_group_id); + break; + } + } + + /* Dump non active group */ + for (auto& g : groups_) { + if (g->group_id_ != active_group_id) { + g->Dump(fd, active_group_id); + } + } +} + +bool LeAudioDeviceGroups::IsAnyInTransition(void) const { + for (auto& g : groups_) { + if (g->IsInTransition()) { + DLOG(INFO) << __func__ << " group: " << g->group_id_ + << " is in transition"; + return true; + } + } + return false; +} + +size_t LeAudioDeviceGroups::Size() const { return (groups_.size()); } + +std::vector LeAudioDeviceGroups::GetGroupsIds(void) const { + std::vector result; + + for (auto const& group : groups_) { + result.push_back(group->group_id_); + } + + return result; +} + +} // namespace le_audio diff --git a/system/bta/le_audio/device_groups.h b/system/bta/le_audio/device_groups.h new file mode 100644 index 0000000000000000000000000000000000000000..7bc4a257fd392398753bb844eed3249528ac09df --- /dev/null +++ b/system/bta/le_audio/device_groups.h @@ -0,0 +1,421 @@ +/* + * Copyright 2023 The Android Open Source Project + * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA + * - www.ehima.com + * + * 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. + */ + +/* LeAudioDeviceGroup class represents group of LeAudioDevices and allows to + * perform operations on them. Group states are ASE states due to nature of + * group which operates finally of ASEs. + * + * Group is created after adding a node to new group id (which is not on list). + */ + +#pragma once + +#include +#include +#include +#include // for std::pair +#include + +#ifdef __ANDROID__ +#include +#endif + +#include + +#include "devices.h" +#include "le_audio_types.h" + +namespace le_audio { + +class LeAudioDeviceGroup { + public: + const int group_id_; + + class CigConfiguration { + public: + CigConfiguration() = delete; + CigConfiguration(LeAudioDeviceGroup* group) + : group_(group), state_(types::CigState::NONE) {} + + types::CigState GetState(void) const { return state_; } + void SetState(le_audio::types::CigState state) { + LOG_VERBOSE("%s -> %s", bluetooth::common::ToString(state_).c_str(), + bluetooth::common::ToString(state).c_str()); + state_ = state; + } + + void GenerateCisIds(types::LeAudioContextType context_type); + bool AssignCisIds(LeAudioDevice* leAudioDevice); + void AssignCisConnHandles(const std::vector& conn_handles); + void UnassignCis(LeAudioDevice* leAudioDevice); + + std::vector cises; + + private: + uint8_t GetFirstFreeCisId(types::CisType cis_type) const; + + LeAudioDeviceGroup* group_; + types::CigState state_; + } cig; + + /* Current audio stream configuration */ + struct stream_configuration stream_conf; + bool notify_streaming_when_cises_are_ready_; + + uint8_t audio_directions_; + types::AudioLocations snk_audio_locations_; + types::AudioLocations src_audio_locations_; + + /* Whether LE Audio is preferred for OUTPUT_ONLY and DUPLEX cases */ + bool is_output_preference_le_audio; + bool is_duplex_preference_le_audio; + DsaMode dsa_mode_; + bool asymmetric_phy_for_unidirectional_cis_supported; + + explicit LeAudioDeviceGroup(const int group_id) + : group_id_(group_id), + cig(this), + stream_conf({}), + notify_streaming_when_cises_are_ready_(false), + audio_directions_(0), + dsa_mode_(DsaMode::DISABLED), + is_enabled_(true), + transport_latency_mtos_us_(0), + transport_latency_stom_us_(0), + configuration_context_type_(types::LeAudioContextType::UNINITIALIZED), + metadata_context_type_({.sink = types::AudioContexts( + types::LeAudioContextType::UNINITIALIZED), + .source = types::AudioContexts( + types::LeAudioContextType::UNINITIALIZED)}), + group_available_contexts_( + {.sink = + types::AudioContexts(types::LeAudioContextType::UNINITIALIZED), + .source = types::AudioContexts( + types::LeAudioContextType::UNINITIALIZED)}), + pending_group_available_contexts_change_( + types::LeAudioContextType::UNINITIALIZED), + target_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), + current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { +#ifdef __ANDROID__ + // 22 maps to BluetoothProfile#LE_AUDIO + is_output_preference_le_audio = android::sysprop::BluetoothProperties:: + getDefaultOutputOnlyAudioProfile() == + LE_AUDIO_PROFILE_CONSTANT; + is_duplex_preference_le_audio = + android::sysprop::BluetoothProperties::getDefaultDuplexAudioProfile() == + LE_AUDIO_PROFILE_CONSTANT; +#else + is_output_preference_le_audio = true; + is_duplex_preference_le_audio = true; +#endif + asymmetric_phy_for_unidirectional_cis_supported = + IS_FLAG_ENABLED(asymmetric_phy_for_unidirectional_cis); + } + ~LeAudioDeviceGroup(void); + + void AddNode(const std::shared_ptr& leAudioDevice); + void RemoveNode(const std::shared_ptr& leAudioDevice); + bool IsEmpty(void) const; + bool IsAnyDeviceConnected(void) const; + int Size(void) const; + int NumOfConnected(types::LeAudioContextType context_type = + types::LeAudioContextType::RFU) const; + bool Activate(types::LeAudioContextType context_type, + const types::BidirectionalPair& + metadata_context_types, + types::BidirectionalPair> ccid_lists); + void Deactivate(void); + void ClearSinksFromConfiguration(void); + void ClearSourcesFromConfiguration(void); + void Cleanup(void); + LeAudioDevice* GetFirstDevice(void) const; + LeAudioDevice* GetFirstDeviceWithAvailableContext( + types::LeAudioContextType context_type) const; + le_audio::types::LeAudioConfigurationStrategy GetGroupStrategy( + int expected_group_size) const; + int GetAseCount(uint8_t direction) const; + LeAudioDevice* GetNextDevice(LeAudioDevice* leAudioDevice) const; + LeAudioDevice* GetNextDeviceWithAvailableContext( + LeAudioDevice* leAudioDevice, + types::LeAudioContextType context_type) const; + LeAudioDevice* GetFirstActiveDevice(void) const; + LeAudioDevice* GetNextActiveDevice(LeAudioDevice* leAudioDevice) const; + LeAudioDevice* GetFirstActiveDeviceByCisAndDataPathState( + types::CisState cis_state, types::DataPathState data_path_state) const; + LeAudioDevice* GetNextActiveDeviceByCisAndDataPathState( + LeAudioDevice* leAudioDevice, types::CisState cis_state, + types::DataPathState data_path_state) const; + bool IsDeviceInTheGroup(LeAudioDevice* leAudioDevice) const; + bool HaveAllActiveDevicesAsesTheSameState(types::AseState state) const; + bool HaveAnyActiveDeviceInUnconfiguredState() const; + bool IsGroupStreamReady(void) const; + bool IsGroupReadyToCreateStream(void) const; + bool IsGroupReadyToSuspendStream(void) const; + bool HaveAllCisesDisconnected(void) const; + void ClearAllCises(void); + void UpdateCisConfiguration(uint8_t direction); + void AssignCisConnHandlesToAses(LeAudioDevice* leAudioDevice); + void AssignCisConnHandlesToAses(void); + bool Configure(types::LeAudioContextType context_type, + const types::BidirectionalPair& + metadata_context_types, + types::BidirectionalPair> ccid_lists = { + .sink = {}, .source = {}}); + uint32_t GetSduInterval(uint8_t direction) const; + uint8_t GetSCA(void) const; + uint8_t GetPacking(void) const; + uint8_t GetFraming(void) const; + uint16_t GetMaxTransportLatencyStom(void) const; + uint16_t GetMaxTransportLatencyMtos(void) const; + void SetTransportLatency(uint8_t direction, uint32_t transport_latency_us); + uint8_t GetRtn(uint8_t direction, uint8_t cis_id) const; + uint16_t GetMaxSduSize(uint8_t direction, uint8_t cis_id) const; + uint8_t GetPhyBitmask(uint8_t direction) const; + uint8_t GetTargetPhy(uint8_t direction) const; + bool GetPresentationDelay(uint32_t* delay, uint8_t direction) const; + uint16_t GetRemoteDelay(uint8_t direction) const; + bool UpdateAudioContextAvailability(void); + bool UpdateAudioSetConfigurationCache(types::LeAudioContextType ctx_type); + bool ReloadAudioLocations(void); + bool ReloadAudioDirections(void); + const set_configurations::AudioSetConfiguration* GetActiveConfiguration( + void) const; + bool IsPendingConfiguration(void) const; + const set_configurations::AudioSetConfiguration* GetConfiguration( + types::LeAudioContextType ctx_type); + const set_configurations::AudioSetConfiguration* GetCachedConfiguration( + types::LeAudioContextType ctx_type) const; + void InvalidateCachedConfigurations(void); + void SetPendingConfiguration(void); + void ClearPendingConfiguration(void); + void AddToAllowListNotConnectedGroupMembers(int gatt_if); + void ApplyReconnectionMode(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode); + void Disable(int gatt_if); + void Enable(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode); + bool IsEnabled(void) const; + bool IsAudioSetConfigurationSupported( + LeAudioDevice* leAudioDevice, + const set_configurations::AudioSetConfiguration* audio_set_conf) const; + std::optional GetCodecConfigurationByDirection( + types::LeAudioContextType group_context_type, uint8_t direction); + std::optional + GetCachedCodecConfigurationByDirection( + types::LeAudioContextType group_context_type, uint8_t direction) const; + bool IsAudioSetConfigurationAvailable( + types::LeAudioContextType group_context_type); + bool IsMetadataChanged( + const types::BidirectionalPair& context_types, + const types::BidirectionalPair>& ccid_lists) const; + bool IsConfiguredForContext(types::LeAudioContextType context_type) const; + void RemoveCisFromStreamIfNeeded(LeAudioDevice* leAudioDevice, + uint16_t cis_conn_hdl); + + inline types::AseState GetState(void) const { return current_state_; } + void SetState(types::AseState state) { + LOG(INFO) << __func__ << " current state: " << current_state_ + << " new state: " << state; + LeAudioLogHistory::Get()->AddLogHistory( + kLogStateMachineTag, group_id_, RawAddress::kEmpty, kLogStateChangedOp, + bluetooth::common::ToString(current_state_) + "->" + + bluetooth::common::ToString(state)); + current_state_ = state; + } + + inline types::AseState GetTargetState(void) const { return target_state_; } + inline void SetNotifyStreamingWhenCisesAreReadyFlag(bool value) { + notify_streaming_when_cises_are_ready_ = value; + } + inline bool GetNotifyStreamingWhenCisesAreReadyFlag(void) { + return notify_streaming_when_cises_are_ready_; + } + void SetTargetState(types::AseState state) { + LOG(INFO) << __func__ << " target state: " << target_state_ + << " new target state: " << state; + LeAudioLogHistory::Get()->AddLogHistory( + kLogStateMachineTag, group_id_, RawAddress::kEmpty, + kLogTargetStateChangedOp, + bluetooth::common::ToString(target_state_) + "->" + + bluetooth::common::ToString(state)); + target_state_ = state; + } + + /* Returns context types for which support was recently added or removed */ + inline types::AudioContexts GetPendingAvailableContextsChange() const { + return pending_group_available_contexts_change_; + } + + /* Set which context types were recently added or removed */ + inline void SetPendingAvailableContextsChange( + types::AudioContexts audio_contexts) { + pending_group_available_contexts_change_ = audio_contexts; + } + + inline void ClearPendingAvailableContextsChange() { + pending_group_available_contexts_change_.clear(); + } + + inline void SetConfigurationContextType( + types::LeAudioContextType context_type) { + configuration_context_type_ = context_type; + } + + inline types::LeAudioContextType GetConfigurationContextType(void) const { + return configuration_context_type_; + } + + inline types::BidirectionalPair GetMetadataContexts() + const { + return metadata_context_type_; + } + + inline void SetAvailableContexts( + types::BidirectionalPair new_contexts) { + group_available_contexts_ = new_contexts; + LOG_DEBUG( + " group id: %d, available contexts sink: %s, available contexts " + "source: " + "%s", + group_id_, group_available_contexts_.sink.to_string().c_str(), + group_available_contexts_.source.to_string().c_str()); + } + + types::AudioContexts GetAvailableContexts( + int direction = types::kLeAudioDirectionBoth) const { + ASSERT_LOG(direction <= (types::kLeAudioDirectionBoth), + "Invalid direction used."); + if (direction < types::kLeAudioDirectionBoth) { + LOG_DEBUG( + " group id: %d, available contexts sink: %s, available contexts " + "source: " + "%s", + group_id_, group_available_contexts_.sink.to_string().c_str(), + group_available_contexts_.source.to_string().c_str()); + return group_available_contexts_.get(direction); + } else { + return types::get_bidirectional(group_available_contexts_); + } + } + + types::AudioContexts GetSupportedContexts( + int direction = types::kLeAudioDirectionBoth) const; + + DsaModes GetAllowedDsaModes() { + DsaModes dsa_modes = {}; + for (auto leAudioDevice : leAudioDevices_) { + if (leAudioDevice.expired()) continue; + + dsa_modes.insert(dsa_modes.end(), + leAudioDevice.lock()->GetDsaModes().begin(), + leAudioDevice.lock()->GetDsaModes().end()); + } + return dsa_modes; + } + + std::vector GetAllowedDsaModesList() { + std::vector dsa_modes_list = {}; + for (auto leAudioDevice : leAudioDevices_) { + DsaModes dsa_modes = {}; + + if (!leAudioDevice.expired()) { + dsa_modes = leAudioDevice.lock()->GetDsaModes(); + } + dsa_modes_list.push_back(dsa_modes); + } + return dsa_modes_list; + } + + types::BidirectionalPair GetLatestAvailableContexts( + void) const; + + bool IsInTransition(void) const; + bool IsStreaming(void) const; + bool IsReleasingOrIdle(void) const; + + void PrintDebugState(void) const; + void Dump(int fd, int active_group_id) const; + + private: + bool is_enabled_; + + uint32_t transport_latency_mtos_us_; + uint32_t transport_latency_stom_us_; + + const set_configurations::AudioSetConfiguration* + FindFirstSupportedConfiguration(types::LeAudioContextType context_type) const; + bool ConfigureAses( + const set_configurations::AudioSetConfiguration* audio_set_conf, + types::LeAudioContextType context_type, + const types::BidirectionalPair& + metadata_context_types, + const types::BidirectionalPair>& ccid_lists); + bool IsAudioSetConfigurationSupported( + const set_configurations::AudioSetConfiguration* audio_set_configuration, + types::LeAudioContextType context_type, + types::LeAudioConfigurationStrategy required_snk_strategy) const; + uint32_t GetTransportLatencyUs(uint8_t direction) const; + bool IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) const; + + /* Current configuration and metadata context types */ + types::LeAudioContextType configuration_context_type_; + types::BidirectionalPair metadata_context_type_; + + /* Mask of contexts that the whole group can handle at its current state + * It's being updated each time group members connect, disconnect or their + * individual available audio contexts are changed. + */ + types::BidirectionalPair group_available_contexts_; + + /* A temporary mask for bits which were either added or removed when the + * group available context type changes. It usually means we should refresh + * our group configuration capabilities to clear this. + */ + types::AudioContexts pending_group_available_contexts_change_; + + /* Possible configuration cache - refreshed on each group context availability + * change. Stored as a pair of (is_valid_cache, configuration*). `pair.first` + * being `false` means that the cached value should be refreshed. + */ + std::map> + context_to_configuration_cache_map; + + types::AseState target_state_; + types::AseState current_state_; + std::vector> leAudioDevices_; +}; + +/* LeAudioDeviceGroup class represents a wraper helper over all device groups in + * le audio implementation. It allows to operate on device group from a list + * (vector container) using determinants like id. + */ +class LeAudioDeviceGroups { + public: + LeAudioDeviceGroup* Add(int group_id); + void Remove(const int group_id); + LeAudioDeviceGroup* FindById(int group_id) const; + std::vector GetGroupsIds(void) const; + size_t Size() const; + bool IsAnyInTransition() const; + void Cleanup(void); + void Dump(int fd, int active_group_id) const; + + private: + std::vector> groups_; +}; + +} // namespace le_audio diff --git a/system/bta/le_audio/devices.cc b/system/bta/le_audio/devices.cc index 80c65951b9c659b605bc99e0ecc72ba5f7b9012e..88b5060cc98a54fa7994dff815623e515954f7ac 100644 --- a/system/bta/le_audio/devices.cc +++ b/system/bta/le_audio/devices.cc @@ -19,44 +19,24 @@ #include -#include - -#include "audio_hal_client/audio_hal_client.h" -#include "bta_csis_api.h" +#include "acl_api.h" +#include "android_bluetooth_flags.h" #include "bta_gatt_queue.h" -#include "bta_groups.h" -#include "bta_le_audio_api.h" #include "btif_storage.h" -#include "btm_iso_api.h" -#include "btm_iso_api_types.h" -#include "device/include/controller.h" -#include "gd/common/strings.h" -#include "le_audio_log_history.h" -#include "le_audio_set_configuration_provider.h" -#include "metrics_collector.h" -#include "osi/include/log.h" -#include "stack/include/acl_api.h" - -using bluetooth::hci::kIsoCigFramingFramed; -using bluetooth::hci::kIsoCigFramingUnframed; -using bluetooth::hci::kIsoCigPackingSequential; + using bluetooth::hci::kIsoCigPhy1M; using bluetooth::hci::kIsoCigPhy2M; -using bluetooth::hci::iso_manager::kIsoSca0To20Ppm; -using le_audio::AudioSetConfigurationProvider; using le_audio::DeviceConnectState; -using le_audio::set_configurations::CodecCapabilitySetting; +using le_audio::set_configurations::CodecConfigSetting; using le_audio::types::ase; using le_audio::types::AseState; using le_audio::types::AudioContexts; using le_audio::types::AudioLocations; -using le_audio::types::AudioStreamDataPathState; -using le_audio::types::BidirectAsesPair; using le_audio::types::BidirectionalPair; -using le_audio::types::CisType; -using le_audio::types::LeAudioCodecId; +using le_audio::types::CisState; +using le_audio::types::DataPathState; using le_audio::types::LeAudioContextType; -using le_audio::types::LeAudioLc3Config; +using le_audio::types::LeAudioCoreCodecConfig; namespace le_audio { std::ostream& operator<<(std::ostream& os, const DeviceConnectState& state) { @@ -78,9 +58,6 @@ std::ostream& operator<<(std::ostream& os, const DeviceConnectState& state) { case DeviceConnectState::DISCONNECTING_AND_RECOVER: char_value_ = "DISCONNECTING_AND_RECOVER"; break; - case DeviceConnectState::PENDING_REMOVAL: - char_value_ = "PENDING_REMOVAL"; - break; case DeviceConnectState::CONNECTING_BY_USER: char_value_ = "CONNECTING_BY_USER"; break; @@ -101,2149 +78,243 @@ std::ostream& operator<<(std::ostream& os, const DeviceConnectState& state) { return os; } -/* LeAudioDeviceGroup Class methods implementation */ -void LeAudioDeviceGroup::AddNode( - const std::shared_ptr& leAudioDevice) { - leAudioDevice->group_id_ = group_id_; - leAudioDevices_.push_back(std::weak_ptr(leAudioDevice)); - MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size()); -} - -void LeAudioDeviceGroup::RemoveNode( - const std::shared_ptr& leAudioDevice) { - /* Group information cleaning in the device. */ - leAudioDevice->group_id_ = bluetooth::groups::kGroupUnknown; - for (auto ase : leAudioDevice->ases_) { - ase.active = false; - ase.cis_conn_hdl = 0; - } - - leAudioDevices_.erase( - std::remove_if( - leAudioDevices_.begin(), leAudioDevices_.end(), - [&leAudioDevice](auto& d) { return d.lock() == leAudioDevice; }), - leAudioDevices_.end()); - MetricsCollector::Get()->OnGroupSizeUpdate(group_id_, leAudioDevices_.size()); -} - -bool LeAudioDeviceGroup::IsEmpty(void) { return leAudioDevices_.size() == 0; } - -bool LeAudioDeviceGroup::IsAnyDeviceConnected(void) { - return (NumOfConnected() != 0); -} - -int LeAudioDeviceGroup::Size(void) { return leAudioDevices_.size(); } - -int LeAudioDeviceGroup::NumOfConnected(types::LeAudioContextType context_type) { - if (leAudioDevices_.empty()) return 0; - - bool check_context_type = (context_type != LeAudioContextType::RFU); - AudioContexts type_set(context_type); - - /* return number of connected devices from the set*/ - return std::count_if( - leAudioDevices_.begin(), leAudioDevices_.end(), - [type_set, check_context_type](auto& iter) { - if (iter.expired()) return false; - if (iter.lock()->conn_id_ == GATT_INVALID_CONN_ID) return false; - if (iter.lock()->GetConnectionState() != DeviceConnectState::CONNECTED) - return false; - - if (!check_context_type) return true; - - return iter.lock()->GetAvailableContexts().test_any(type_set); - }); -} - -void LeAudioDeviceGroup::ClearSinksFromConfiguration(void) { - LOG_INFO("Group %p, group_id %d", this, group_id_); - stream_conf.sink_streams.clear(); - stream_conf.sink_offloader_streams_target_allocation.clear(); - stream_conf.sink_offloader_streams_current_allocation.clear(); - stream_conf.sink_audio_channel_allocation = 0; - stream_conf.sink_num_of_channels = 0; - stream_conf.sink_num_of_devices = 0; - stream_conf.sink_sample_frequency_hz = 0; - stream_conf.sink_codec_frames_blocks_per_sdu = 0; - stream_conf.sink_octets_per_codec_frame = 0; - stream_conf.sink_frame_duration_us = 0; -} - -void LeAudioDeviceGroup::ClearSourcesFromConfiguration(void) { - LOG_INFO("Group %p, group_id %d", this, group_id_); - stream_conf.source_streams.clear(); - stream_conf.source_offloader_streams_target_allocation.clear(); - stream_conf.source_offloader_streams_current_allocation.clear(); - stream_conf.source_audio_channel_allocation = 0; - stream_conf.source_num_of_channels = 0; - stream_conf.source_num_of_devices = 0; - stream_conf.source_sample_frequency_hz = 0; - stream_conf.source_codec_frames_blocks_per_sdu = 0; - stream_conf.source_octets_per_codec_frame = 0; - stream_conf.source_frame_duration_us = 0; -} - -void LeAudioDeviceGroup::CigClearCis(void) { - LOG_INFO("group_id: %d", group_id_); - cises_.clear(); - ClearSinksFromConfiguration(); - ClearSourcesFromConfiguration(); -} - -void LeAudioDeviceGroup::Cleanup(void) { - /* Bluetooth is off while streaming - disconnect CISes and remove CIG */ - if (GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - if (!stream_conf.sink_streams.empty()) { - for (auto [cis_handle, audio_location] : stream_conf.sink_streams) { - bluetooth::hci::IsoManager::GetInstance()->DisconnectCis( - cis_handle, HCI_ERR_PEER_USER); - - if (stream_conf.source_streams.empty()) { - continue; - } - uint16_t cis_hdl = cis_handle; - stream_conf.source_streams.erase( - std::remove_if( - stream_conf.source_streams.begin(), - stream_conf.source_streams.end(), - [cis_hdl](auto& pair) { return pair.first == cis_hdl; }), - stream_conf.source_streams.end()); - } - } - - if (!stream_conf.source_streams.empty()) { - for (auto [cis_handle, audio_location] : stream_conf.source_streams) { - bluetooth::hci::IsoManager::GetInstance()->DisconnectCis( - cis_handle, HCI_ERR_PEER_USER); - } - } - } - - /* Note: CIG will stay in the controller. We cannot remove it here, because - * Cises are not yet disconnected. - * When user start Bluetooth, HCI Reset should remove it - */ - - leAudioDevices_.clear(); - this->CigClearCis(); -} - -void LeAudioDeviceGroup::Deactivate(void) { - for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice; - leAudioDevice = GetNextActiveDevice(leAudioDevice)) { - for (auto* ase = leAudioDevice->GetFirstActiveAse(); ase; - ase = leAudioDevice->GetNextActiveAse(ase)) { - ase->active = false; - } - } -} - -le_audio::types::CigState LeAudioDeviceGroup::GetCigState(void) { - return cig_state_; -} - -void LeAudioDeviceGroup::SetCigState(le_audio::types::CigState state) { - LOG_VERBOSE("%s -> %s", bluetooth::common::ToString(cig_state_).c_str(), - bluetooth::common::ToString(state).c_str()); - cig_state_ = state; -} - -bool LeAudioDeviceGroup::Activate(LeAudioContextType context_type) { - bool is_activate = false; - for (auto leAudioDevice : leAudioDevices_) { - if (leAudioDevice.expired()) continue; - - bool activated = leAudioDevice.lock()->ActivateConfiguredAses(context_type); - LOG_INFO("Device %s is %s", - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice.lock().get()->address_), - activated ? "activated" : " not activated"); - if (activated) { - if (!CigAssignCisIds(leAudioDevice.lock().get())) { - return false; - } - is_activate = true; - } - } - return is_activate; -} - -LeAudioDevice* LeAudioDeviceGroup::GetFirstDevice(void) { - auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), - [](auto& iter) { return !iter.expired(); }); - - if (iter == leAudioDevices_.end()) return nullptr; - - return (iter->lock()).get(); -} - -LeAudioDevice* LeAudioDeviceGroup::GetFirstDeviceWithActiveContext( - types::LeAudioContextType context_type) { - auto iter = std::find_if( - leAudioDevices_.begin(), leAudioDevices_.end(), - [&context_type](auto& iter) { - if (iter.expired()) return false; - return iter.lock()->GetAvailableContexts().test(context_type); - }); - - if ((iter == leAudioDevices_.end()) || (iter->expired())) return nullptr; - - return (iter->lock()).get(); -} - -LeAudioDevice* LeAudioDeviceGroup::GetNextDevice(LeAudioDevice* leAudioDevice) { - auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), - [&leAudioDevice](auto& d) { - if (d.expired()) - return false; - else - return (d.lock()).get() == leAudioDevice; - }); - - /* If reference device not found */ - if (iter == leAudioDevices_.end()) return nullptr; - - std::advance(iter, 1); - /* If reference device is last in group */ - if (iter == leAudioDevices_.end()) return nullptr; - - if (iter->expired()) return nullptr; - - return (iter->lock()).get(); -} - -LeAudioDevice* LeAudioDeviceGroup::GetNextDeviceWithActiveContext( - LeAudioDevice* leAudioDevice, types::LeAudioContextType context_type) { - auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), - [&leAudioDevice](auto& d) { - if (d.expired()) - return false; - else - return (d.lock()).get() == leAudioDevice; - }); - - /* If reference device not found */ - if (iter == leAudioDevices_.end()) return nullptr; - - std::advance(iter, 1); - /* If reference device is last in group */ - if (iter == leAudioDevices_.end()) return nullptr; - - iter = std::find_if(iter, leAudioDevices_.end(), [&context_type](auto& d) { - if (d.expired()) - return false; - else - return d.lock()->GetAvailableContexts().test(context_type); - ; - }); - - return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get(); -} - -bool LeAudioDeviceGroup::IsDeviceInTheGroup(LeAudioDevice* leAudioDevice) { - auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), - [&leAudioDevice](auto& d) { - if (d.expired()) - return false; - else - return (d.lock()).get() == leAudioDevice; - }); - - if ((iter == leAudioDevices_.end()) || (iter->expired())) return false; - - return true; -} - -bool LeAudioDeviceGroup::IsGroupReadyToCreateStream(void) { - auto iter = - std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { - if (d.expired()) - return false; - else - return !(((d.lock()).get())->IsReadyToCreateStream()); - }); - - return iter == leAudioDevices_.end(); -} - -bool LeAudioDeviceGroup::IsGroupReadyToSuspendStream(void) { - auto iter = - std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { - if (d.expired()) - return false; - else - return !(((d.lock()).get())->IsReadyToSuspendStream()); - }); - - return iter == leAudioDevices_.end(); -} - -bool LeAudioDeviceGroup::HaveAnyActiveDeviceInUnconfiguredState() { - auto iter = - std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { - if (d.expired()) - return false; - else - return (((d.lock()).get())->HaveAnyUnconfiguredAses()); - }); - - return iter != leAudioDevices_.end(); -} - -bool LeAudioDeviceGroup::HaveAllActiveDevicesAsesTheSameState(AseState state) { - auto iter = std::find_if( - leAudioDevices_.begin(), leAudioDevices_.end(), [&state](auto& d) { - if (d.expired()) - return false; - else - return !(((d.lock()).get())->HaveAllActiveAsesSameState(state)); - }); - - return iter == leAudioDevices_.end(); -} - -LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDevice(void) { - auto iter = - std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { - if (d.expired()) - return false; - else - return ((d.lock()).get())->HaveActiveAse(); - }); - - if (iter == leAudioDevices_.end() || iter->expired()) return nullptr; - - return (iter->lock()).get(); -} - -LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDevice( - LeAudioDevice* leAudioDevice) { - auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), - [&leAudioDevice](auto& d) { - if (d.expired()) - return false; - else - return (d.lock()).get() == leAudioDevice; - }); - - if (iter == leAudioDevices_.end() || - std::distance(iter, leAudioDevices_.end()) < 1) - return nullptr; - - iter = std::find_if(std::next(iter, 1), leAudioDevices_.end(), [](auto& d) { - if (d.expired()) - return false; - else - return ((d.lock()).get())->HaveActiveAse(); - }); - - return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get(); -} - -LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDeviceByDataPathState( - AudioStreamDataPathState data_path_state) { - auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), - [&data_path_state](auto& d) { - if (d.expired()) { - return false; - } - - return (((d.lock()).get()) - ->GetFirstActiveAseByDataPathState( - data_path_state) != nullptr); - }); - - if (iter == leAudioDevices_.end()) { - return nullptr; - } - - return iter->lock().get(); -} - -LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByDataPathState( - LeAudioDevice* leAudioDevice, AudioStreamDataPathState data_path_state) { - auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), - [&leAudioDevice](auto& d) { - if (d.expired()) { - return false; - } - - return d.lock().get() == leAudioDevice; - }); - - if (std::distance(iter, leAudioDevices_.end()) < 1) { - return nullptr; - } - - iter = std::find_if( - std::next(iter, 1), leAudioDevices_.end(), [&data_path_state](auto& d) { - if (d.expired()) { - return false; - } - - return (((d.lock()).get()) - ->GetFirstActiveAseByDataPathState(data_path_state) != - nullptr); - }); - - if (iter == leAudioDevices_.end()) { - return nullptr; - } - - return iter->lock().get(); -} - -uint32_t LeAudioDeviceGroup::GetSduInterval(uint8_t direction) { - for (LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); - leAudioDevice != nullptr; - leAudioDevice = GetNextActiveDevice(leAudioDevice)) { - struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); - if (!ase) continue; - - return ase->codec_config.GetFrameDurationUs(); - } - - return 0; -} - -uint8_t LeAudioDeviceGroup::GetSCA(void) { - uint8_t sca = kIsoSca0To20Ppm; - - for (const auto& leAudioDevice : leAudioDevices_) { - uint8_t dev_sca = - BTM_GetPeerSCA(leAudioDevice.lock()->address_, BT_TRANSPORT_LE); - - /* If we could not read SCA from the peer device or sca is 0, - * then there is no reason to continue. - */ - if ((dev_sca == 0xFF) || (dev_sca == 0)) return 0; - - /* The Slaves_Clock_Accuracy parameter shall be the worst-case sleep clock - *accuracy of all the slaves that will participate in the CIG. - */ - if (dev_sca < sca) { - sca = dev_sca; - } - } - - return sca; -} - -uint8_t LeAudioDeviceGroup::GetPacking(void) { - /* TODO: Decide about packing */ - return kIsoCigPackingSequential; -} - -uint8_t LeAudioDeviceGroup::GetFraming(void) { - LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); - LOG_ASSERT(leAudioDevice) - << __func__ << " Shouldn't be called without an active device."; - - do { - struct ase* ase = leAudioDevice->GetFirstActiveAse(); - if (!ase) continue; - - do { - if (ase->framing == types::kFramingUnframedPduUnsupported) - return kIsoCigFramingFramed; - } while ((ase = leAudioDevice->GetNextActiveAse(ase))); - } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); - - return kIsoCigFramingUnframed; -} - -/* TODO: Preferred parameter may be other than minimum */ -static uint16_t find_max_transport_latency(LeAudioDeviceGroup* group, - uint8_t direction) { - uint16_t max_transport_latency = 0; - - for (LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice(); - leAudioDevice != nullptr; - leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) { - for (ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); - ase != nullptr; - ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase)) { - if (!ase) break; - - if (!max_transport_latency) - // first assignment - max_transport_latency = ase->max_transport_latency; - else if (ase->max_transport_latency < max_transport_latency) - max_transport_latency = ase->max_transport_latency; - } - } - - if (max_transport_latency < types::kMaxTransportLatencyMin) - max_transport_latency = types::kMaxTransportLatencyMin; - else if (max_transport_latency > types::kMaxTransportLatencyMax) - max_transport_latency = types::kMaxTransportLatencyMax; - - return max_transport_latency; -} - -uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyStom(void) { - return find_max_transport_latency(this, types::kLeAudioDirectionSource); -} - -uint16_t LeAudioDeviceGroup::GetMaxTransportLatencyMtos(void) { - return find_max_transport_latency(this, types::kLeAudioDirectionSink); -} - -uint32_t LeAudioDeviceGroup::GetTransportLatencyUs(uint8_t direction) { - if (direction == types::kLeAudioDirectionSink) { - return transport_latency_mtos_us_; - } else if (direction == types::kLeAudioDirectionSource) { - return transport_latency_stom_us_ ; - } else { - LOG(ERROR) << __func__ << ", invalid direction"; - return 0; - } -} - -void LeAudioDeviceGroup::SetTransportLatency(uint8_t direction, - uint32_t new_transport_latency_us) { - uint32_t* transport_latency_us; - - if (direction == types::kLeAudioDirectionSink) { - transport_latency_us = &transport_latency_mtos_us_; - } else if (direction == types::kLeAudioDirectionSource) { - transport_latency_us = &transport_latency_stom_us_; - } else { - LOG(ERROR) << __func__ << ", invalid direction"; - return; - } +static uint32_t GetFirstLeft(const AudioLocations& audio_locations) { + uint32_t audio_location_ulong = audio_locations.to_ulong(); - if (*transport_latency_us == new_transport_latency_us) return; + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeft) + return codec_spec_conf::kLeAudioLocationFrontLeft; - if ((*transport_latency_us != 0) && - (*transport_latency_us != new_transport_latency_us)) { - LOG(WARNING) << __func__ << ", Different transport latency for group: " - << " old: " << static_cast(*transport_latency_us) - << " [us], new: " << static_cast(new_transport_latency_us) - << " [us]"; - return; - } + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBackLeft) + return codec_spec_conf::kLeAudioLocationBackLeft; - LOG(INFO) << __func__ << ", updated group " << static_cast(group_id_) - << " transport latency: " << static_cast(new_transport_latency_us) - << " [us]"; - *transport_latency_us = new_transport_latency_us; -} + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeftOfCenter) + return codec_spec_conf::kLeAudioLocationFrontLeftOfCenter; -uint8_t LeAudioDeviceGroup::GetRtn(uint8_t direction, uint8_t cis_id) { - LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); - LOG_ASSERT(leAudioDevice) - << __func__ << " Shouldn't be called without an active device."; + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationSideLeft) + return codec_spec_conf::kLeAudioLocationSideLeft; - do { - auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id); + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopFrontLeft) + return codec_spec_conf::kLeAudioLocationTopFrontLeft; - if (ases_pair.sink && direction == types::kLeAudioDirectionSink) { - return ases_pair.sink->retrans_nb; - } else if (ases_pair.source && - direction == types::kLeAudioDirectionSource) { - return ases_pair.source->retrans_nb; - } - } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopBackLeft) + return codec_spec_conf::kLeAudioLocationTopBackLeft; - return 0; -} + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopSideLeft) + return codec_spec_conf::kLeAudioLocationTopSideLeft; -uint16_t LeAudioDeviceGroup::GetMaxSduSize(uint8_t direction, uint8_t cis_id) { - LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); - LOG_ASSERT(leAudioDevice) - << __func__ << " Shouldn't be called without an active device."; + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBottomFrontLeft) + return codec_spec_conf::kLeAudioLocationBottomFrontLeft; - do { - auto ases_pair = leAudioDevice->GetAsesByCisId(cis_id); + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeftWide) + return codec_spec_conf::kLeAudioLocationFrontLeftWide; - if (ases_pair.sink && direction == types::kLeAudioDirectionSink) { - return ases_pair.sink->max_sdu_size; - } else if (ases_pair.source && - direction == types::kLeAudioDirectionSource) { - return ases_pair.source->max_sdu_size; - } - } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround) + return codec_spec_conf::kLeAudioLocationLeftSurround; return 0; } -uint8_t LeAudioDeviceGroup::GetPhyBitmask(uint8_t direction) { - LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); - LOG_ASSERT(leAudioDevice) - << __func__ << " Shouldn't be called without an active device."; - - // local supported PHY's - uint8_t phy_bitfield = kIsoCigPhy1M; - if (controller_get_interface()->supports_ble_2m_phy()) - phy_bitfield |= kIsoCigPhy2M; - - if (!leAudioDevice) { - LOG(ERROR) << "No active leaudio device for direction?: " << +direction; - return phy_bitfield; - } - - do { - struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); - if (!ase) return phy_bitfield; - - do { - if (direction == ase->direction) { - phy_bitfield &= leAudioDevice->GetPhyBitmask(); - - // A value of 0x00 denotes no preference - if (ase->preferred_phy && (phy_bitfield & ase->preferred_phy)) { - phy_bitfield &= ase->preferred_phy; - LOG_DEBUG("Using ASE preferred phy 0x%02x", - static_cast(phy_bitfield)); - } else { - LOG_WARN( - "ASE preferred 0x%02x has nothing common with phy_bitfield " - "0x%02x ", - static_cast(ase->preferred_phy), - static_cast(phy_bitfield)); - } - } - } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase))); - } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); - - return phy_bitfield; -} - -uint8_t LeAudioDeviceGroup::GetTargetPhy(uint8_t direction) { - uint8_t phy_bitfield = GetPhyBitmask(direction); - - // prefer to use 2M if supported - if (phy_bitfield & kIsoCigPhy2M) - return types::kTargetPhy2M; - else if (phy_bitfield & kIsoCigPhy1M) - return types::kTargetPhy1M; - else - return 0; -} - -bool LeAudioDeviceGroup::GetPresentationDelay(uint32_t* delay, - uint8_t direction) { - uint32_t delay_min = 0; - uint32_t delay_max = UINT32_MAX; - uint32_t preferred_delay_min = delay_min; - uint32_t preferred_delay_max = delay_max; - - LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); - LOG_ASSERT(leAudioDevice) - << __func__ << " Shouldn't be called without an active device."; - - do { - struct ase* ase = leAudioDevice->GetFirstActiveAseByDirection(direction); - if (!ase) continue; // device has no active ASEs in this direction - - do { - /* No common range check */ - if (ase->pres_delay_min > delay_max || ase->pres_delay_max < delay_min) - return false; - - if (ase->pres_delay_min > delay_min) delay_min = ase->pres_delay_min; - if (ase->pres_delay_max < delay_max) delay_max = ase->pres_delay_max; - if (ase->preferred_pres_delay_min > preferred_delay_min) - preferred_delay_min = ase->preferred_pres_delay_min; - if (ase->preferred_pres_delay_max < preferred_delay_max && - ase->preferred_pres_delay_max != types::kPresDelayNoPreference) - preferred_delay_max = ase->preferred_pres_delay_max; - } while ((ase = leAudioDevice->GetNextActiveAseWithSameDirection(ase))); - } while ((leAudioDevice = GetNextActiveDevice(leAudioDevice))); - - if (preferred_delay_min <= preferred_delay_max && - preferred_delay_min > delay_min && preferred_delay_min < delay_max) { - *delay = preferred_delay_min; - } else { - *delay = delay_min; - } - - return true; -} - -uint16_t LeAudioDeviceGroup::GetRemoteDelay(uint8_t direction) { - uint16_t remote_delay_ms = 0; - uint32_t presentation_delay; - - if (!GetPresentationDelay(&presentation_delay, direction)) { - /* This should never happens at stream request time but to be safe return - * some sample value to not break streaming - */ - return 100; - } - - /* us to ms */ - remote_delay_ms = presentation_delay / 1000; - remote_delay_ms += GetTransportLatencyUs(direction) / 1000; - - return remote_delay_ms; -} - -void LeAudioDeviceGroup::UpdateAudioContextTypeAvailability(void) { - LOG_DEBUG(" group id: %d, available contexts: %s", group_id_, - group_available_contexts_.to_string().c_str()); - UpdateAudioContextTypeAvailability(group_available_contexts_); -} - -/* Returns true if support for any type in the whole group has changed, - * otherwise false. */ -bool LeAudioDeviceGroup::UpdateAudioContextTypeAvailability( - AudioContexts update_contexts) { - auto new_contexts = AudioContexts(); - bool active_contexts_has_been_modified = false; - - if (update_contexts.none()) { - LOG_DEBUG("No context updated"); - return false; - } - - LOG_DEBUG("Updated context: %s", update_contexts.to_string().c_str()); - - for (LeAudioContextType ctx_type : types::kLeAudioContextAllTypesArray) { - LOG_DEBUG("Checking context: %s", ToHexString(ctx_type).c_str()); - - if (!update_contexts.test(ctx_type)) { - LOG_DEBUG("Configuration not in updated context"); - /* Fill context bitset for possible returned value if updated */ - if (available_context_to_configuration_map.count(ctx_type) > 0) - new_contexts.set(ctx_type); - - continue; - } - - auto new_conf = FindFirstSupportedConfiguration(ctx_type); - - bool ctx_previously_not_supported = - (available_context_to_configuration_map.count(ctx_type) == 0 || - available_context_to_configuration_map[ctx_type] == nullptr); - /* Check if support for context type has changed */ - if (ctx_previously_not_supported) { - /* Current configuration for context type is empty */ - if (new_conf == nullptr) { - /* Configuration remains empty */ - continue; - } else { - /* Configuration changes from empty to some */ - new_contexts.set(ctx_type); - active_contexts_has_been_modified = true; - } - } else { - /* Current configuration for context type is not empty */ - if (new_conf == nullptr) { - /* Configuration changed to empty */ - new_contexts.unset(ctx_type); - active_contexts_has_been_modified = true; - } else if (new_conf != available_context_to_configuration_map[ctx_type]) { - /* Configuration changed to any other */ - new_contexts.set(ctx_type); - active_contexts_has_been_modified = true; - } else { - /* Configuration is the same */ - new_contexts.set(ctx_type); - continue; - } - } - - LOG_INFO( - "%s(%s), %s -> %s", types::contextTypeToStr(ctx_type).c_str(), - ToHexString(ctx_type).c_str(), - (ctx_previously_not_supported - ? "empty" - : available_context_to_configuration_map[ctx_type]->name.c_str()), - (new_conf != nullptr ? new_conf->name.c_str() : "empty")); - - available_context_to_configuration_map[ctx_type] = new_conf; - } - - /* Some contexts have changed, return new available context bitset */ - if (active_contexts_has_been_modified) { - group_available_contexts_ = new_contexts; - } - - return active_contexts_has_been_modified; -} - -bool LeAudioDeviceGroup::ReloadAudioLocations(void) { - AudioLocations updated_snk_audio_locations_ = - codec_spec_conf::kLeAudioLocationNotAllowed; - AudioLocations updated_src_audio_locations_ = - codec_spec_conf::kLeAudioLocationNotAllowed; - - for (const auto& device : leAudioDevices_) { - if (device.expired() || (device.lock().get()->GetConnectionState() != - DeviceConnectState::CONNECTED)) - continue; - updated_snk_audio_locations_ |= device.lock().get()->snk_audio_locations_; - updated_src_audio_locations_ |= device.lock().get()->src_audio_locations_; - } - - /* Nothing has changed */ - if ((updated_snk_audio_locations_ == snk_audio_locations_) && - (updated_src_audio_locations_ == src_audio_locations_)) - return false; - - snk_audio_locations_ = updated_snk_audio_locations_; - src_audio_locations_ = updated_src_audio_locations_; - - return true; -} - -bool LeAudioDeviceGroup::ReloadAudioDirections(void) { - uint8_t updated_audio_directions = 0x00; - - for (const auto& device : leAudioDevices_) { - if (device.expired() || (device.lock().get()->GetConnectionState() != - DeviceConnectState::CONNECTED)) - continue; - updated_audio_directions |= device.lock().get()->audio_directions_; - } - - /* Nothing has changed */ - if (updated_audio_directions == audio_directions_) return false; - - audio_directions_ = updated_audio_directions; - - return true; -} - -bool LeAudioDeviceGroup::IsInTransition(void) { - return target_state_ != current_state_; -} - -bool LeAudioDeviceGroup::IsStreaming(void) { - return current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING; -} - -bool LeAudioDeviceGroup::IsReleasingOrIdle(void) { - return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) || - (current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); -} - -bool LeAudioDeviceGroup::IsGroupStreamReady(void) { - auto iter = - std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [](auto& d) { - if (d.expired()) - return false; - else - return !(((d.lock()).get())->HaveAllActiveAsesCisEst()); - }); - - return iter == leAudioDevices_.end(); -} - -bool LeAudioDeviceGroup::HaveAllCisesDisconnected(void) { - for (auto const dev : leAudioDevices_) { - if (dev.expired()) continue; - if (dev.lock().get()->HaveAnyCisConnected()) return false; - } - return true; -} - -uint8_t LeAudioDeviceGroup::GetFirstFreeCisId(void) { - for (uint8_t id = 0; id < UINT8_MAX; id++) { - auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), - [id](auto& d) { - if (d.expired()) - return false; - else - return ((d.lock()).get())->HasCisId(id); - }); - - if (iter == leAudioDevices_.end()) return id; - } - - return kInvalidCisId; -} - -uint8_t LeAudioDeviceGroup::GetFirstFreeCisId(CisType cis_type) { - LOG_INFO("Group: %p, group_id: %d cis_type: %d", this, group_id_, - static_cast(cis_type)); - for (size_t id = 0; id < cises_.size(); id++) { - if (cises_[id].addr.IsEmpty() && cises_[id].type == cis_type) { - return id; - } - } - return kInvalidCisId; -} - -types::LeAudioConfigurationStrategy LeAudioDeviceGroup::GetGroupStrategy( - int expected_group_size) { - /* Simple strategy picker */ - LOG_DEBUG(" Group %d size %d", group_id_, expected_group_size); - if (expected_group_size > 1) { - return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE; - } - - LOG_DEBUG("audio location 0x%04lx", snk_audio_locations_.to_ulong()); - if (!(snk_audio_locations_.to_ulong() & - codec_spec_conf::kLeAudioLocationAnyLeft) || - !(snk_audio_locations_.to_ulong() & - codec_spec_conf::kLeAudioLocationAnyRight)) { - return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE; - } - - auto device = GetFirstDevice(); - auto channel_cnt = - device->GetLc3SupportedChannelCount(types::kLeAudioDirectionSink); - LOG_DEBUG("Channel count for group %d is %d (device %s)", group_id_, - channel_cnt, ADDRESS_TO_LOGGABLE_CSTR(device->address_)); - if (channel_cnt == 1) { - return types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE; - } - - return types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE; -} - -int LeAudioDeviceGroup::GetAseCount(uint8_t direction) { - int result = 0; - for (const auto& device_iter : leAudioDevices_) { - result += device_iter.lock()->GetAseCount(direction); - } - - return result; -} - -void LeAudioDeviceGroup::CigGenerateCisIds( - types::LeAudioContextType context_type) { - LOG_INFO("Group %p, group_id: %d, context_type: %s", this, group_id_, - bluetooth::common::ToString(context_type).c_str()); - - if (cises_.size() > 0) { - LOG_INFO("CIS IDs already generated"); - return; - } - - const set_configurations::AudioSetConfigurations* confs = - AudioSetConfigurationProvider::Get()->GetConfigurations(context_type); - - uint8_t cis_count_bidir = 0; - uint8_t cis_count_unidir_sink = 0; - uint8_t cis_count_unidir_source = 0; - int csis_group_size = - bluetooth::csis::CsisClient::Get()->GetDesiredSize(group_id_); - /* If this is CSIS group, the csis_group_size will be > 0, otherwise -1. - * If the last happen it means, group size is 1 */ - int group_size = csis_group_size > 0 ? csis_group_size : 1; - - get_cis_count(*confs, group_size, GetGroupStrategy(group_size), - GetAseCount(types::kLeAudioDirectionSink), - GetAseCount(types::kLeAudioDirectionSource), cis_count_bidir, - cis_count_unidir_sink, cis_count_unidir_source); - - uint8_t idx = 0; - while (cis_count_bidir > 0) { - struct le_audio::types::cis cis_entry = { - .id = idx, - .addr = RawAddress::kEmpty, - .type = CisType::CIS_TYPE_BIDIRECTIONAL, - .conn_handle = 0, - }; - cises_.push_back(cis_entry); - cis_count_bidir--; - idx++; - } - - while (cis_count_unidir_sink > 0) { - struct le_audio::types::cis cis_entry = { - .id = idx, - .addr = RawAddress::kEmpty, - .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK, - .conn_handle = 0, - }; - cises_.push_back(cis_entry); - cis_count_unidir_sink--; - idx++; - } - - while (cis_count_unidir_source > 0) { - struct le_audio::types::cis cis_entry = { - .id = idx, - .addr = RawAddress::kEmpty, - .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE, - .conn_handle = 0, - }; - cises_.push_back(cis_entry); - cis_count_unidir_source--; - idx++; - } -} - -bool LeAudioDeviceGroup::CigAssignCisIds(LeAudioDevice* leAudioDevice) { - ASSERT_LOG(leAudioDevice, "invalid device"); - LOG_INFO("device: %s", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - - struct ase* ase = leAudioDevice->GetFirstActiveAse(); - if (!ase) { - LOG_ERROR(" Device %s shouldn't be called without an active ASE", - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - return false; - } - - for (; ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) { - uint8_t cis_id = kInvalidCisId; - /* CIS ID already set */ - if (ase->cis_id != kInvalidCisId) { - LOG_INFO("ASE ID: %d, is already assigned CIS ID: %d, type %d", ase->id, - ase->cis_id, cises_[ase->cis_id].type); - if (!cises_[ase->cis_id].addr.IsEmpty()) { - LOG_INFO("Bi-Directional CIS already assigned"); - continue; - } - /* Reuse existing CIS ID if available*/ - cis_id = ase->cis_id; - } - - /* First check if we have bidirectional ASEs. If so, assign same CIS ID.*/ - struct ase* matching_bidir_ase = - leAudioDevice->GetNextActiveAseWithDifferentDirection(ase); - - for (; matching_bidir_ase != nullptr; - matching_bidir_ase = leAudioDevice->GetNextActiveAseWithSameDirection( - matching_bidir_ase)) { - if ((matching_bidir_ase->cis_id != kInvalidCisId) && - (matching_bidir_ase->cis_id != cis_id)) { - LOG_INFO("Bi-Directional CIS is already used. ASE Id: %d cis_id=%d", - matching_bidir_ase->id, matching_bidir_ase->cis_id); - continue; - } - break; - } - - if (matching_bidir_ase) { - if (cis_id == kInvalidCisId) { - cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL); - } - - if (cis_id != kInvalidCisId) { - ase->cis_id = cis_id; - matching_bidir_ase->cis_id = cis_id; - cises_[cis_id].addr = leAudioDevice->address_; - - LOG_INFO( - " ASE ID: %d and ASE ID: %d, assigned Bi-Directional CIS ID: %d", - +ase->id, +matching_bidir_ase->id, +ase->cis_id); - continue; - } - - LOG_WARN( - " ASE ID: %d, unable to get free Bi-Directional CIS ID but maybe " - "thats fine. Try using unidirectional.", - ase->id); - } - - if (ase->direction == types::kLeAudioDirectionSink) { - if (cis_id == kInvalidCisId) { - cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SINK); - } - - if (cis_id == kInvalidCisId) { - LOG_WARN( - " Unable to get free Uni-Directional Sink CIS ID - maybe there is " - "bi-directional available"); - /* This could happen when scenarios for given context type allows for - * Sink and Source configuration but also only Sink configuration. - */ - cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL); - if (cis_id == kInvalidCisId) { - LOG_ERROR("Unable to get free Uni-Directional Sink CIS ID"); - return false; - } - } - - ase->cis_id = cis_id; - cises_[cis_id].addr = leAudioDevice->address_; - LOG_INFO("ASE ID: %d, assigned Uni-Directional Sink CIS ID: %d", ase->id, - ase->cis_id); - continue; - } - - /* Source direction */ - ASSERT_LOG(ase->direction == types::kLeAudioDirectionSource, - "Expected Source direction, actual=%d", ase->direction); - - if (cis_id == kInvalidCisId) { - cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE); - } - - if (cis_id == kInvalidCisId) { - /* This could happen when scenarios for given context type allows for - * Sink and Source configuration but also only Sink configuration. - */ - LOG_WARN( - "Unable to get free Uni-Directional Source CIS ID - maybe there " - "is bi-directional available"); - cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL); - if (cis_id == kInvalidCisId) { - LOG_ERROR("Unable to get free Uni-Directional Source CIS ID"); - return false; - } - } - - ase->cis_id = cis_id; - cises_[cis_id].addr = leAudioDevice->address_; - LOG_INFO("ASE ID: %d, assigned Uni-Directional Source CIS ID: %d", ase->id, - ase->cis_id); - } - - return true; -} - -void LeAudioDeviceGroup::CigAssignCisConnHandles( - const std::vector& conn_handles) { - LOG_INFO("num of cis handles %d", static_cast(conn_handles.size())); - for (size_t i = 0; i < cises_.size(); i++) { - cises_[i].conn_handle = conn_handles[i]; - LOG_INFO("assigning cis[%d] conn_handle: %d", cises_[i].id, - cises_[i].conn_handle); - } -} - -void LeAudioDeviceGroup::CigAssignCisConnHandlesToAses( - LeAudioDevice* leAudioDevice) { - ASSERT_LOG(leAudioDevice, "Invalid device"); - LOG_INFO("group: %p, group_id: %d, device: %s", this, group_id_, - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - - /* Assign all CIS connection handles to ases */ - struct le_audio::types::ase* ase = - leAudioDevice->GetFirstActiveAseByDataPathState( - AudioStreamDataPathState::IDLE); - if (!ase) { - LOG_WARN("No active ASE with AudioStreamDataPathState IDLE"); - return; - } - - for (; ase != nullptr; ase = leAudioDevice->GetFirstActiveAseByDataPathState( - AudioStreamDataPathState::IDLE)) { - auto ases_pair = leAudioDevice->GetAsesByCisId(ase->cis_id); - - if (ases_pair.sink && ases_pair.sink->active) { - ases_pair.sink->cis_conn_hdl = cises_[ase->cis_id].conn_handle; - ases_pair.sink->data_path_state = AudioStreamDataPathState::CIS_ASSIGNED; - } - if (ases_pair.source && ases_pair.source->active) { - ases_pair.source->cis_conn_hdl = cises_[ase->cis_id].conn_handle; - ases_pair.source->data_path_state = - AudioStreamDataPathState::CIS_ASSIGNED; - } - } -} - -void LeAudioDeviceGroup::CigAssignCisConnHandlesToAses(void) { - LeAudioDevice* leAudioDevice = GetFirstActiveDevice(); - ASSERT_LOG(leAudioDevice, "Shouldn't be called without an active device."); - - LOG_INFO("Group %p, group_id %d", this, group_id_); - - /* Assign all CIS connection handles to ases */ - for (; leAudioDevice != nullptr; - leAudioDevice = GetNextActiveDevice(leAudioDevice)) { - CigAssignCisConnHandlesToAses(leAudioDevice); - } -} - -void LeAudioDeviceGroup::CigUnassignCis(LeAudioDevice* leAudioDevice) { - ASSERT_LOG(leAudioDevice, "Invalid device"); - - LOG_INFO("Group %p, group_id %d, device: %s", this, group_id_, - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - - for (struct le_audio::types::cis& cis_entry : cises_) { - if (cis_entry.addr == leAudioDevice->address_) { - cis_entry.addr = RawAddress::kEmpty; - } - } -} - -bool CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy, - types::AudioLocations audio_locations, - uint8_t requested_channel_count, - uint8_t channel_count_mask) { - DLOG(INFO) << __func__ << " strategy: " << (int)strategy - << " locations: " << +audio_locations.to_ulong(); - - switch (strategy) { - case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: - return audio_locations.any(); - case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: - if ((audio_locations.to_ulong() & - codec_spec_conf::kLeAudioLocationAnyLeft) && - (audio_locations.to_ulong() & - codec_spec_conf::kLeAudioLocationAnyRight)) - return true; - else - return false; - case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE: - if (!(audio_locations.to_ulong() & - codec_spec_conf::kLeAudioLocationAnyLeft) || - !(audio_locations.to_ulong() & - codec_spec_conf::kLeAudioLocationAnyRight)) - return false; - - DLOG(INFO) << __func__ << " requested chan cnt " - << +requested_channel_count - << " chan mask: " << loghex(channel_count_mask); - - /* Return true if requested channel count is set in the channel count - * mask. In the channel_count_mask, bit0 is set when 1 channel is - * supported. - */ - return ((1 << (requested_channel_count - 1)) & channel_count_mask); - default: - return false; - } - - return false; -} - -/* This method check if group support given audio configuration - * requirement for connected devices in the group and available ASEs - * (no matter on the ASE state) and for given context type - */ -bool LeAudioDeviceGroup::IsConfigurationSupported( - const set_configurations::AudioSetConfiguration* audio_set_conf, - types::LeAudioContextType context_type, - types::LeAudioConfigurationStrategy required_snk_strategy) { - if (!set_configurations::check_if_may_cover_scenario( - audio_set_conf, NumOfConnected(context_type))) { - LOG_DEBUG(" cannot cover scenario %s: size of for context type %d", - bluetooth::common::ToString(context_type).c_str(), - +NumOfConnected(context_type)); - return false; - } - - /* TODO For now: set ase if matching with first pac. - * 1) We assume as well that devices will match requirements in order - * e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc. - * 2) ASEs should be active only if best (according to priority list) full - * scenarion will be covered. - * 3) ASEs should be filled according to performance profile. - */ - for (const auto& ent : (*audio_set_conf).confs) { - LOG_DEBUG(" Looking for configuration: %s - %s", - audio_set_conf->name.c_str(), - (ent.direction == types::kLeAudioDirectionSink ? "snk" : "src")); - - uint8_t required_device_cnt = ent.device_cnt; - uint8_t max_required_ase_per_dev = - ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); - uint8_t active_ase_num = 0; - auto strategy = ent.strategy; - - LOG_DEBUG( - " Number of devices: %d, number of ASEs: %d, Max ASE per device: %d " - "strategy: %d", - +required_device_cnt, +ent.ase_cnt, +max_required_ase_per_dev, - static_cast(strategy)); - - if (ent.direction == types::kLeAudioDirectionSink && - strategy != required_snk_strategy) { - LOG_DEBUG(" Sink strategy mismatch group!=cfg.entry (%d!=%d)", - static_cast(required_snk_strategy), - static_cast(strategy)); - return false; - } - - for (auto* device = GetFirstDeviceWithActiveContext(context_type); - device != nullptr && required_device_cnt > 0; - device = GetNextDeviceWithActiveContext(device, context_type)) { - /* Skip if device has ASE configured in this direction already */ - - if (device->ases_.empty()) continue; - - if (!device->GetCodecConfigurationSupportedPac(ent.direction, ent.codec)) - continue; - - int needed_ase = std::min(static_cast(max_required_ase_per_dev), - static_cast(ent.ase_cnt - active_ase_num)); - - /* If we required more ASEs per device which means we would like to - * create more CISes to one device, we should also check the allocation - * if it allows us to do this. - */ - - types::AudioLocations audio_locations = 0; - /* Check direction and if audio location allows to create more cise */ - if (ent.direction == types::kLeAudioDirectionSink) - audio_locations = device->snk_audio_locations_; - else - audio_locations = device->src_audio_locations_; - - /* TODO Make it no Lc3 specific */ - if (!CheckIfStrategySupported( - strategy, audio_locations, - std::get(ent.codec.config).GetChannelCount(), - device->GetLc3SupportedChannelCount(ent.direction))) { - LOG_DEBUG(" insufficient device audio allocation: %lu", - audio_locations.to_ulong()); - continue; - } - - for (auto& ase : device->ases_) { - if (ase.direction != ent.direction) continue; - - active_ase_num++; - needed_ase--; - - if (needed_ase == 0) break; - } - - if (needed_ase > 0) { - LOG_DEBUG("Device has too less ASEs. Still needed ases %d", needed_ase); - return false; - } - - required_device_cnt--; - } - - if (required_device_cnt > 0) { - /* Don't left any active devices if requirements are not met */ - LOG_DEBUG(" could not configure all the devices"); - return false; - } - } - - LOG_DEBUG("Chosen ASE Configuration for group: %d, configuration: %s", - this->group_id_, audio_set_conf->name.c_str()); - return true; -} - -static uint32_t GetFirstLeft(const types::AudioLocations& audio_locations) { - uint32_t audio_location_ulong = audio_locations.to_ulong(); - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeft) - return codec_spec_conf::kLeAudioLocationFrontLeft; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBackLeft) - return codec_spec_conf::kLeAudioLocationBackLeft; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeftOfCenter) - return codec_spec_conf::kLeAudioLocationFrontLeftOfCenter; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationSideLeft) - return codec_spec_conf::kLeAudioLocationSideLeft; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopFrontLeft) - return codec_spec_conf::kLeAudioLocationTopFrontLeft; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopBackLeft) - return codec_spec_conf::kLeAudioLocationTopBackLeft; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopSideLeft) - return codec_spec_conf::kLeAudioLocationTopSideLeft; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBottomFrontLeft) - return codec_spec_conf::kLeAudioLocationBottomFrontLeft; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeftWide) - return codec_spec_conf::kLeAudioLocationFrontLeftWide; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround) - return codec_spec_conf::kLeAudioLocationLeftSurround; - - return 0; -} - -static uint32_t GetFirstRight(const types::AudioLocations& audio_locations) { - uint32_t audio_location_ulong = audio_locations.to_ulong(); - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRight) - return codec_spec_conf::kLeAudioLocationFrontRight; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBackRight) - return codec_spec_conf::kLeAudioLocationBackRight; - - if (audio_location_ulong & - codec_spec_conf::kLeAudioLocationFrontRightOfCenter) - return codec_spec_conf::kLeAudioLocationFrontRightOfCenter; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationSideRight) - return codec_spec_conf::kLeAudioLocationSideRight; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopFrontRight) - return codec_spec_conf::kLeAudioLocationTopFrontRight; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopBackRight) - return codec_spec_conf::kLeAudioLocationTopBackRight; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopSideRight) - return codec_spec_conf::kLeAudioLocationTopSideRight; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBottomFrontRight) - return codec_spec_conf::kLeAudioLocationBottomFrontRight; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRightWide) - return codec_spec_conf::kLeAudioLocationFrontRightWide; - - if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround) - return codec_spec_conf::kLeAudioLocationRightSurround; - - return 0; -} - -uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy, - const types::AudioLocations& device_locations, - types::AudioLocations& group_locations) { - LOG_DEBUG("strategy: %d, locations: 0x%lx, input group locations: 0x%lx", - (int)strategy, device_locations.to_ulong(), - group_locations.to_ulong()); - - auto is_left_not_yet_assigned = - !(group_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft); - auto is_right_not_yet_assigned = - !(group_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyRight); - uint32_t left_device_loc = GetFirstLeft(device_locations); - uint32_t right_device_loc = GetFirstRight(device_locations); - - if (left_device_loc == 0 && right_device_loc == 0) { - LOG_WARN("Can't find device able to render left and right audio channel"); - } - - switch (strategy) { - case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: - case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: - if (left_device_loc && is_left_not_yet_assigned) { - group_locations |= left_device_loc; - return left_device_loc; - } - - if (right_device_loc && is_right_not_yet_assigned) { - group_locations |= right_device_loc; - return right_device_loc; - } - break; - - case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE: - if (left_device_loc && right_device_loc) { - group_locations |= left_device_loc | right_device_loc; - return left_device_loc | right_device_loc; - } - break; - default: - LOG_ALWAYS_FATAL("%s: Unknown strategy: %hhu", __func__, strategy); - return 0; - } - - LOG_ERROR( - "Can't find device for left/right channel. Strategy: %hhu, " - "device_locations: %lx, output group_locations: %lx.", - strategy, device_locations.to_ulong(), group_locations.to_ulong()); - - /* Return either any left or any right audio location. It might result with - * multiple devices within the group having the same location. - */ - return left_device_loc ? left_device_loc : right_device_loc; -} - -bool LeAudioDevice::ConfigureAses( - const le_audio::set_configurations::SetConfiguration& ent, - types::LeAudioContextType context_type, - uint8_t* number_of_already_active_group_ase, - BidirectionalPair& group_audio_locations_memo, - const BidirectionalPair& metadata_context_types, - const BidirectionalPair>& ccid_lists, - bool reuse_cis_id) { - /* First try to use the already configured ASE */ - auto ase = GetFirstActiveAseByDirection(ent.direction); - if (ase) { - LOG_INFO("Using an already active ASE id=%d", ase->id); - } else { - ase = GetFirstInactiveAse(ent.direction, reuse_cis_id); - } - - if (!ase) { - LOG_ERROR("Unable to find an ASE to configure"); - return false; - } - - /* The number_of_already_active_group_ase keeps all the active ases - * in other devices in the group. - * This function counts active ases only for this device, and we count here - * new active ases and already active ases which we want to reuse in the - * scenario - */ - uint8_t active_ases = *number_of_already_active_group_ase; - uint8_t max_required_ase_per_dev = - ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); - le_audio::types::LeAudioConfigurationStrategy strategy = ent.strategy; - - auto pac = GetCodecConfigurationSupportedPac(ent.direction, ent.codec); - if (!pac) return false; - - int needed_ase = std::min((int)(max_required_ase_per_dev), - (int)(ent.ase_cnt - active_ases)); - - types::AudioLocations audio_locations = 0; - - /* Check direction and if audio location allows to create more cise */ - if (ent.direction == types::kLeAudioDirectionSink) { - audio_locations = snk_audio_locations_; - } else { - audio_locations = src_audio_locations_; - } - - for (; needed_ase && ase; needed_ase--) { - ase->active = true; - ase->configured_for_context_type = context_type; - active_ases++; - - /* In case of late connect, we could be here for STREAMING ase. - * in such case, it is needed to mark ase as known active ase which - * is important to validate scenario and is done already few lines above. - * Nothing more to do is needed here. - */ - if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) - ase->reconfigure = true; - - ase->target_latency = ent.qos.target_latency; - ase->codec_id = ent.codec.id; - /* TODO: find better way to not use LC3 explicitly */ - ase->codec_config = std::get(ent.codec.config); - - /*Let's choose audio channel allocation if not set */ - ase->codec_config.audio_channel_allocation = - PickAudioLocation(strategy, audio_locations, - group_audio_locations_memo.get_ref(ent.direction)); - - /* Get default value if no requirement for specific frame blocks per sdu - */ - if (!ase->codec_config.codec_frames_blocks_per_sdu) { - ase->codec_config.codec_frames_blocks_per_sdu = - GetMaxCodecFramesPerSduFromPac(pac); - } - ase->max_sdu_size = codec_spec_caps::GetAudioChannelCounts( - *ase->codec_config.audio_channel_allocation) * - *ase->codec_config.octets_per_codec_frame * - *ase->codec_config.codec_frames_blocks_per_sdu; - - ase->retrans_nb = ent.qos.retransmission_number; - ase->max_transport_latency = ent.qos.max_transport_latency; - - /* Filter multidirectional audio context for each ase direction */ - auto directional_audio_context = - metadata_context_types.get(ase->direction) & - GetAvailableContexts(ase->direction); - if (directional_audio_context.any()) { - ase->metadata = GetMetadata(directional_audio_context, - ccid_lists.get(ase->direction)); - } else { - ase->metadata = - GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED), - std::vector()); - } - } - - LOG_DEBUG( - "device=%s, activated ASE id=%d, direction=%s, max_sdu_size=%d, " - "cis_id=%d, target_latency=%d", - ADDRESS_TO_LOGGABLE_CSTR(address_), ase->id, - (ent.direction == 1 ? "snk" : "src"), ase->max_sdu_size, ase->cis_id, - ent.qos.target_latency); - - /* Try to use the already active ASE */ - ase = GetNextActiveAseWithSameDirection(ase); - if (ase == nullptr) { - ase = GetFirstInactiveAse(ent.direction, reuse_cis_id); - } - } - - *number_of_already_active_group_ase = active_ases; - return true; -} - -/* This method should choose aproperiate ASEs to be active and set a cached - * configuration for codec and qos. - */ -bool LeAudioDeviceGroup::ConfigureAses( - const set_configurations::AudioSetConfiguration* audio_set_conf, - types::LeAudioContextType context_type, - const types::BidirectionalPair& metadata_context_types, - const types::BidirectionalPair>& ccid_lists) { - if (!set_configurations::check_if_may_cover_scenario( - audio_set_conf, NumOfConnected(context_type))) - return false; - - bool reuse_cis_id = - GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; - - /* TODO For now: set ase if matching with first pac. - * 1) We assume as well that devices will match requirements in order - * e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc. - * 2) ASEs should be active only if best (according to priority list) full - * scenarion will be covered. - * 3) ASEs should be filled according to performance profile. - */ - - // WARNING: This may look like the results stored here are unused, but it - // actually shares the intermediate values between the multiple - // configuration calls within the configuration loop. - BidirectionalPair group_audio_locations_memo = { - .sink = 0, .source = 0}; - - for (const auto& ent : (*audio_set_conf).confs) { - LOG_DEBUG(" Looking for requirements: %s, - %s", - audio_set_conf->name.c_str(), - (ent.direction == 1 ? "snk" : "src")); - - uint8_t required_device_cnt = ent.device_cnt; - uint8_t max_required_ase_per_dev = - ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); - uint8_t active_ase_num = 0; - le_audio::types::LeAudioConfigurationStrategy strategy = ent.strategy; - - LOG_DEBUG( - "Number of devices: %d number of ASEs: %d, Max ASE per device: %d " - "strategy: %d", - required_device_cnt, ent.ase_cnt, max_required_ase_per_dev, - (int)strategy); - - for (auto* device = GetFirstDeviceWithActiveContext(context_type); - device != nullptr && required_device_cnt > 0; - device = GetNextDeviceWithActiveContext(device, context_type)) { - /* For the moment, we configure only connected devices and when it is - * ready to stream i.e. All ASEs are discovered and device is reported as - * connected - */ - if (device->GetConnectionState() != DeviceConnectState::CONNECTED) { - LOG_WARN( - "Device %s, in the state %s", - ADDRESS_TO_LOGGABLE_CSTR(device->address_), - bluetooth::common::ToString(device->GetConnectionState()).c_str()); - continue; - } - - if (!device->ConfigureAses( - ent, context_type, &active_ase_num, group_audio_locations_memo, - metadata_context_types, ccid_lists, reuse_cis_id)) - continue; - - required_device_cnt--; - } - - if (required_device_cnt > 0) { - /* Don't left any active devices if requirements are not met */ - LOG_ERROR(" could not configure all the devices"); - Deactivate(); - return false; - } - } - - LOG_INFO("Choosed ASE Configuration for group: %d, configuration: %s", - group_id_, audio_set_conf->name.c_str()); - - configuration_context_type_ = context_type; - metadata_context_type_ = metadata_context_types; - return true; -} - -const set_configurations::AudioSetConfiguration* -LeAudioDeviceGroup::GetActiveConfiguration(void) { - return available_context_to_configuration_map[configuration_context_type_]; -} - -std::optional -LeAudioDeviceGroup::GetCodecConfigurationByDirection( - types::LeAudioContextType group_context_type, uint8_t direction) const { - if (available_context_to_configuration_map.count(group_context_type) == 0) { - LOG_DEBUG("Context type %s, not supported", - bluetooth::common::ToString(group_context_type).c_str()); - return std::nullopt; - } - - const set_configurations::AudioSetConfiguration* audio_set_conf = - available_context_to_configuration_map.at(group_context_type); - LeAudioCodecConfiguration group_config = {0, 0, 0, 0}; - if (!audio_set_conf) return std::nullopt; - - for (const auto& conf : audio_set_conf->confs) { - if (conf.direction != direction) continue; - - if (group_config.sample_rate != 0 && - conf.codec.GetConfigSamplingFrequency() != group_config.sample_rate) { - LOG(WARNING) << __func__ - << ", stream configuration could not be " - "determined (sampling frequency differs) for direction: " - << loghex(direction); - return std::nullopt; - } - group_config.sample_rate = conf.codec.GetConfigSamplingFrequency(); - - if (group_config.data_interval_us != 0 && - conf.codec.GetConfigDataIntervalUs() != group_config.data_interval_us) { - LOG(WARNING) << __func__ - << ", stream configuration could not be " - "determined (data interval differs) for direction: " - << loghex(direction); - return std::nullopt; - } - group_config.data_interval_us = conf.codec.GetConfigDataIntervalUs(); - - if (group_config.bits_per_sample != 0 && - conf.codec.GetConfigBitsPerSample() != group_config.bits_per_sample) { - LOG(WARNING) << __func__ - << ", stream configuration could not be " - "determined (bits per sample differs) for direction: " - << loghex(direction); - return std::nullopt; - } - group_config.bits_per_sample = conf.codec.GetConfigBitsPerSample(); - - group_config.num_channels += - conf.codec.GetConfigChannelCount() * conf.device_cnt; - } - - if (group_config.IsInvalid()) return std::nullopt; - - return group_config; -} - -bool LeAudioDeviceGroup::IsContextSupported( - types::LeAudioContextType group_context_type) { - auto iter = available_context_to_configuration_map.find(group_context_type); - if (iter == available_context_to_configuration_map.end()) return false; - - return available_context_to_configuration_map[group_context_type] != nullptr; -} - -bool LeAudioDeviceGroup::IsMetadataChanged( - const BidirectionalPair& context_types, - const BidirectionalPair>& ccid_lists) { - for (auto* leAudioDevice = GetFirstActiveDevice(); leAudioDevice; - leAudioDevice = GetNextActiveDevice(leAudioDevice)) { - if (leAudioDevice->IsMetadataChanged(context_types, ccid_lists)) - return true; - } - - return false; -} - -void LeAudioDeviceGroup::StreamOffloaderUpdated(uint8_t direction) { - if (direction == le_audio::types::kLeAudioDirectionSource) { - stream_conf.source_is_initial = false; - } else { - stream_conf.sink_is_initial = false; - } -} - -void LeAudioDeviceGroup::CreateStreamVectorForOffloader(uint8_t direction) { - if (CodecManager::GetInstance()->GetCodecLocation() != - le_audio::types::CodecLocation::ADSP) { - return; - } - - CisType cis_type; - std::vector>* streams; - std::vector* offloader_streams_target_allocation; - std::vector* offloader_streams_current_allocation; - std::string tag; - uint32_t available_allocations = 0; - bool* changed_flag; - bool* is_initial; - if (direction == le_audio::types::kLeAudioDirectionSource) { - changed_flag = &stream_conf.source_offloader_changed; - is_initial = &stream_conf.source_is_initial; - cis_type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE; - streams = &stream_conf.source_streams; - offloader_streams_target_allocation = - &stream_conf.source_offloader_streams_target_allocation; - offloader_streams_current_allocation = - &stream_conf.source_offloader_streams_current_allocation; - tag = "Source"; - available_allocations = AdjustAllocationForOffloader( - stream_conf.source_audio_channel_allocation); - } else { - changed_flag = &stream_conf.sink_offloader_changed; - is_initial = &stream_conf.sink_is_initial; - cis_type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK; - streams = &stream_conf.sink_streams; - offloader_streams_target_allocation = - &stream_conf.sink_offloader_streams_target_allocation; - offloader_streams_current_allocation = - &stream_conf.sink_offloader_streams_current_allocation; - tag = "Sink"; - available_allocations = - AdjustAllocationForOffloader(stream_conf.sink_audio_channel_allocation); - } - - if (available_allocations == 0) { - LOG_ERROR("There is no CIS connected"); - return; - } - - if (offloader_streams_target_allocation->size() == 0) { - *is_initial = true; - } else if (*is_initial || - CodecManager::GetInstance()->GetAidlVersionInUsed() >= - AIDL_VERSION_SUPPORT_STREAM_ACTIVE) { - // As multiple CISes phone call case, the target_allocation already have the - // previous data, but the is_initial flag not be cleared. We need to clear - // here to avoid make duplicated target allocation stream map. - offloader_streams_target_allocation->clear(); - } - - offloader_streams_current_allocation->clear(); - *changed_flag = true; - bool not_all_cises_connected = false; - if (available_allocations != codec_spec_conf::kLeAudioLocationStereo) { - not_all_cises_connected = true; - } - - /* If the all cises are connected as stream started, reset changed_flag that - * the bt stack wouldn't send another audio configuration for the connection - * status */ - if (*is_initial && !not_all_cises_connected) { - *changed_flag = false; - } - for (auto& cis_entry : cises_) { - if ((cis_entry.type == CisType::CIS_TYPE_BIDIRECTIONAL || - cis_entry.type == cis_type) && - cis_entry.conn_handle != 0) { - uint32_t target_allocation = 0; - uint32_t current_allocation = 0; - bool is_active = false; - for (const auto& s : *streams) { - if (s.first == cis_entry.conn_handle) { - is_active = true; - target_allocation = AdjustAllocationForOffloader(s.second); - current_allocation = target_allocation; - if (not_all_cises_connected) { - /* Tell offloader to mix on this CIS.*/ - current_allocation = codec_spec_conf::kLeAudioLocationStereo; - } - break; - } - } - - if (target_allocation == 0) { - /* Take missing allocation for that one .*/ - target_allocation = - codec_spec_conf::kLeAudioLocationStereo & ~available_allocations; - } - - LOG_INFO( - "%s: Cis handle 0x%04x, target allocation 0x%08x, current " - "allocation 0x%08x, active: %d", - tag.c_str(), cis_entry.conn_handle, target_allocation, - current_allocation, is_active); - - if (*is_initial || CodecManager::GetInstance()->GetAidlVersionInUsed() >= - AIDL_VERSION_SUPPORT_STREAM_ACTIVE) { - offloader_streams_target_allocation->emplace_back(stream_map_info( - cis_entry.conn_handle, target_allocation, is_active)); - } - offloader_streams_current_allocation->emplace_back(stream_map_info( - cis_entry.conn_handle, current_allocation, is_active)); - } - } -} - -bool LeAudioDeviceGroup::IsPendingConfiguration(void) { - return stream_conf.pending_configuration; -} - -void LeAudioDeviceGroup::SetPendingConfiguration(void) { - stream_conf.pending_configuration = true; -} - -void LeAudioDeviceGroup::ClearPendingConfiguration(void) { - stream_conf.pending_configuration = false; -} - -void LeAudioDeviceGroup::Disable(int gatt_if) { - enabled_ = false; - - for (auto& device_iter : leAudioDevices_) { - if (!device_iter.lock()->autoconnect_flag_) { - continue; - } - - auto connection_state = device_iter.lock()->GetConnectionState(); - auto address = device_iter.lock()->address_; - - btif_storage_set_leaudio_autoconnect(address, false); - device_iter.lock()->autoconnect_flag_ = false; - - LOG_INFO("Group %d in state %s. Removing %s from background connect", - group_id_, bluetooth::common::ToString(GetState()).c_str(), - ADDRESS_TO_LOGGABLE_CSTR(address)); - - BTA_GATTC_CancelOpen(gatt_if, address, false); +static uint32_t GetFirstRight(const AudioLocations& audio_locations) { + uint32_t audio_location_ulong = audio_locations.to_ulong(); - if (connection_state == DeviceConnectState::CONNECTING_AUTOCONNECT) { - device_iter.lock()->SetConnectionState(DeviceConnectState::DISCONNECTED); - } - } -} + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRight) + return codec_spec_conf::kLeAudioLocationFrontRight; -void LeAudioDeviceGroup::Enable(int gatt_if, - tBTM_BLE_CONN_TYPE reconnection_mode) { - enabled_ = true; - for (auto& device_iter : leAudioDevices_) { - if (device_iter.lock()->autoconnect_flag_) { - continue; - } + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBackRight) + return codec_spec_conf::kLeAudioLocationBackRight; - auto address = device_iter.lock()->address_; - auto connection_state = device_iter.lock()->GetConnectionState(); + if (audio_location_ulong & + codec_spec_conf::kLeAudioLocationFrontRightOfCenter) + return codec_spec_conf::kLeAudioLocationFrontRightOfCenter; - btif_storage_set_leaudio_autoconnect(address, true); - device_iter.lock()->autoconnect_flag_ = true; + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationSideRight) + return codec_spec_conf::kLeAudioLocationSideRight; - LOG_INFO("Group %d in state %s. Adding %s from background connect", - group_id_, bluetooth::common::ToString(GetState()).c_str(), - ADDRESS_TO_LOGGABLE_CSTR(address)); + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopFrontRight) + return codec_spec_conf::kLeAudioLocationTopFrontRight; - if (connection_state == DeviceConnectState::DISCONNECTED) { - BTA_GATTC_Open(gatt_if, address, reconnection_mode, false); - device_iter.lock()->SetConnectionState( - DeviceConnectState::CONNECTING_AUTOCONNECT); - } - } -} + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopBackRight) + return codec_spec_conf::kLeAudioLocationTopBackRight; -bool LeAudioDeviceGroup::IsEnabled(void) { return enabled_; }; - -void LeAudioDeviceGroup::AddToAllowListNotConnectedGroupMembers(int gatt_if) { - for (const auto& device_iter : leAudioDevices_) { - auto connection_state = device_iter.lock()->GetConnectionState(); - if (connection_state == DeviceConnectState::CONNECTED || - connection_state == DeviceConnectState::CONNECTING_BY_USER || - connection_state == - DeviceConnectState::CONNECTED_BY_USER_GETTING_READY || - connection_state == - DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY) { - continue; - } + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationTopSideRight) + return codec_spec_conf::kLeAudioLocationTopSideRight; - auto address = device_iter.lock()->address_; - LOG_INFO("Group %d in state %s. Adding %s to allow list ", group_id_, - bluetooth::common::ToString(GetState()).c_str(), - ADDRESS_TO_LOGGABLE_CSTR(address)); + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationBottomFrontRight) + return codec_spec_conf::kLeAudioLocationBottomFrontRight; - BTA_GATTC_CancelOpen(gatt_if, address, false); - BTA_GATTC_Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); - device_iter.lock()->SetConnectionState( - DeviceConnectState::CONNECTING_AUTOCONNECT); - } -} + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRightWide) + return codec_spec_conf::kLeAudioLocationFrontRightWide; -bool LeAudioDeviceGroup::IsConfigurationSupported( - LeAudioDevice* leAudioDevice, - const set_configurations::AudioSetConfiguration* audio_set_conf) { - for (const auto& ent : (*audio_set_conf).confs) { - LOG_INFO("Looking for requirements: %s - %s", audio_set_conf->name.c_str(), - (ent.direction == 1 ? "snk" : "src")); - auto pac = leAudioDevice->GetCodecConfigurationSupportedPac(ent.direction, - ent.codec); - if (pac != nullptr) { - LOG_INFO("Configuration is supported by device %s", - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - return true; - } - } + if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround) + return codec_spec_conf::kLeAudioLocationRightSurround; - LOG_INFO("Configuration is NOT supported by device %s", - ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); - return false; + return 0; } -const set_configurations::AudioSetConfiguration* -LeAudioDeviceGroup::FindFirstSupportedConfiguration( - LeAudioContextType context_type) { - const set_configurations::AudioSetConfigurations* confs = - AudioSetConfigurationProvider::Get()->GetConfigurations(context_type); +uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy, + const AudioLocations& device_locations, + AudioLocations& group_locations) { + LOG_DEBUG("strategy: %d, locations: 0x%lx, input group locations: 0x%lx", + (int)strategy, device_locations.to_ulong(), + group_locations.to_ulong()); - LOG_DEBUG("context type: %s, number of connected devices: %d", - bluetooth::common::ToString(context_type).c_str(), - +NumOfConnected()); + auto is_left_not_yet_assigned = + !(group_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft); + auto is_right_not_yet_assigned = + !(group_locations.to_ulong() & codec_spec_conf::kLeAudioLocationAnyRight); + uint32_t left_device_loc = GetFirstLeft(device_locations); + uint32_t right_device_loc = GetFirstRight(device_locations); - /* Filter out device set for all scenarios */ - if (!set_configurations::check_if_may_cover_scenario(confs, - NumOfConnected())) { - LOG_DEBUG(", group is unable to cover scenario"); - return nullptr; + if (left_device_loc == 0 && right_device_loc == 0) { + LOG_WARN("Can't find device able to render left and right audio channel"); } - /* Filter out device set for each end every scenario */ + switch (strategy) { + case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: + case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: + if (left_device_loc && is_left_not_yet_assigned) { + group_locations |= left_device_loc; + return left_device_loc; + } - auto required_snk_strategy = GetGroupStrategy(Size()); - for (const auto& conf : *confs) { - if (IsConfigurationSupported(conf, context_type, required_snk_strategy)) { - LOG_DEBUG("found: %s", conf->name.c_str()); - return conf; - } + if (right_device_loc && is_right_not_yet_assigned) { + group_locations |= right_device_loc; + return right_device_loc; + } + break; + + case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE: + if (left_device_loc && right_device_loc) { + group_locations |= left_device_loc | right_device_loc; + return left_device_loc | right_device_loc; + } + break; + default: + LOG_ALWAYS_FATAL("%s: Unknown strategy: %hhu", __func__, strategy); + return 0; } - return nullptr; + LOG_ERROR( + "Can't find device for left/right channel. Strategy: %hhu, " + "device_locations: %lx, output group_locations: %lx.", + strategy, device_locations.to_ulong(), group_locations.to_ulong()); + + /* Return either any left or any right audio location. It might result with + * multiple devices within the group having the same location. + */ + return left_device_loc ? left_device_loc : right_device_loc; } -/* This method should choose aproperiate ASEs to be active and set a cached - * configuration for codec and qos. - */ -bool LeAudioDeviceGroup::Configure( +bool LeAudioDevice::ConfigureAses( + const le_audio::set_configurations::SetConfiguration& ent, LeAudioContextType context_type, - const types::BidirectionalPair& metadata_context_types, - types::BidirectionalPair> ccid_lists) { - const set_configurations::AudioSetConfiguration* conf = - available_context_to_configuration_map[context_type]; - - if (!conf) { - LOG_ERROR( - ", requested context type: %s , is in mismatch with cached available " - "contexts ", - bluetooth::common::ToString(context_type).c_str()); - return false; + uint8_t* number_of_already_active_group_ase, + BidirectionalPair& group_audio_locations_memo, + const BidirectionalPair& metadata_context_types, + const BidirectionalPair>& ccid_lists, + bool reuse_cis_id) { + /* First try to use the already configured ASE */ + auto ase = GetFirstActiveAseByDirection(ent.direction); + if (ase) { + LOG_INFO("Using an already active ASE id=%d", ase->id); + } else { + ase = GetFirstInactiveAse(ent.direction, reuse_cis_id); } - LOG_DEBUG(" setting context type: %s", - bluetooth::common::ToString(context_type).c_str()); - - if (!ConfigureAses(conf, context_type, metadata_context_types, ccid_lists)) { - LOG_ERROR( - ", requested context type: %s , is in mismatch with cached available " - "contexts", - bluetooth::common::ToString(context_type).c_str()); + if (!ase) { + LOG_ERROR("Unable to find an ASE to configure"); return false; } - /* Store selected configuration at once it is chosen. - * It might happen it will get unavailable in some point of time + /* The number_of_already_active_group_ase keeps all the active ases + * in other devices in the group. + * This function counts active ases only for this device, and we count here + * new active ases and already active ases which we want to reuse in the + * scenario */ - stream_conf.conf = conf; - return true; -} + uint8_t active_ases = *number_of_already_active_group_ase; + uint8_t max_required_ase_per_dev = + ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); + le_audio::types::LeAudioConfigurationStrategy strategy = ent.strategy; -LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); } + auto pac = GetCodecConfigurationSupportedPac(ent.direction, ent.codec); + if (!pac) return false; -void LeAudioDeviceGroup::PrintDebugState(void) { - auto* active_conf = GetActiveConfiguration(); - std::stringstream debug_str; + int needed_ase = std::min((int)(max_required_ase_per_dev), + (int)(ent.ase_cnt - active_ases)); - debug_str << "\n Groupd id: " << group_id_ - << (enabled_ ? " enabled" : " disabled") - << ", state: " << bluetooth::common::ToString(GetState()) - << ", target state: " - << bluetooth::common::ToString(GetTargetState()) - << ", cig state: " << bluetooth::common::ToString(cig_state_) - << ", \n group available contexts: " - << bluetooth::common::ToString(GetAvailableContexts()) - << ", \n configuration context type: " - << bluetooth::common::ToString(GetConfigurationContextType()) - << ", \n active configuration name: " - << (active_conf ? active_conf->name : " not set"); - - if (cises_.size() > 0) { - LOG_INFO("\n Allocated CISes: %d", static_cast(cises_.size())); - for (auto cis : cises_) { - LOG_INFO("\n cis id: %d, type: %d, conn_handle %d, addr: %s", cis.id, - cis.type, cis.conn_handle, cis.addr.ToString().c_str()); - } - } + AudioLocations audio_locations = 0; - if (GetFirstActiveDevice() != nullptr) { - uint32_t sink_delay = 0; - uint32_t source_delay = 0; - GetPresentationDelay(&sink_delay, le_audio::types::kLeAudioDirectionSink); - GetPresentationDelay(&source_delay, - le_audio::types::kLeAudioDirectionSource); - auto phy_mtos = GetPhyBitmask(le_audio::types::kLeAudioDirectionSink); - auto phy_stom = GetPhyBitmask(le_audio::types::kLeAudioDirectionSource); - auto max_transport_latency_mtos = GetMaxTransportLatencyMtos(); - auto max_transport_latency_stom = GetMaxTransportLatencyStom(); - auto sdu_mts = GetSduInterval(le_audio::types::kLeAudioDirectionSink); - auto sdu_stom = GetSduInterval(le_audio::types::kLeAudioDirectionSource); - - debug_str << "\n presentation_delay for sink (speaker): " << +sink_delay - << " us, presentation_delay for source (microphone): " - << +source_delay << "us, \n MtoS transport latency: " - << +max_transport_latency_mtos - << ", StoM transport latency: " << +max_transport_latency_stom - << ", \n MtoS Phy: " << loghex(phy_mtos) - << ", MtoS sdu: " << loghex(phy_stom) - << " \n MtoS sdu: " << +sdu_mts << ", StoM sdu: " << +sdu_stom; + /* Check direction and if audio location allows to create more cise */ + if (ent.direction == types::kLeAudioDirectionSink) { + audio_locations = snk_audio_locations_; + } else { + audio_locations = src_audio_locations_; } - LOG_INFO("%s", debug_str.str().c_str()); + for (; needed_ase && ase; needed_ase--) { + ase->active = true; + ase->configured_for_context_type = context_type; + ase->is_codec_in_controller = ent.is_codec_in_controller; + ase->data_path_id = ent.data_path_id; + active_ases++; - for (const auto& device_iter : leAudioDevices_) { - device_iter.lock()->PrintDebugState(); - } -} + /* In case of late connect, we could be here for STREAMING ase. + * in such case, it is needed to mark ase as known active ase which + * is important to validate scenario and is done already few lines above. + * Nothing more to do is needed here. + */ + if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { + if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) + ase->reconfigure = true; -void LeAudioDeviceGroup::Dump(int fd, int active_group_id) { - bool is_active = (group_id_ == active_group_id); - std::stringstream stream, stream_pacs; - auto* active_conf = GetActiveConfiguration(); - - stream << "\n == Group id: " << group_id_ - << (enabled_ ? " enabled" : " disabled") - << " == " << (is_active ? ",\tActive\n" : ",\tInactive\n") - << " state: " << GetState() - << ",\ttarget state: " << GetTargetState() - << ",\tcig state: " << cig_state_ << "\n" - << " group available contexts: " << GetAvailableContexts() << "\n" - << " configuration context type: " - << bluetooth::common::ToString(GetConfigurationContextType()).c_str() - << "\n" - << " active configuration name: " - << (active_conf ? active_conf->name : " not set") << "\n" - << " stream configuration: " - << (stream_conf.conf != nullptr ? stream_conf.conf->name : " unknown ") - << "\n" - << " codec id: " << +(stream_conf.id.coding_format) - << ",\tpending_configuration: " << stream_conf.pending_configuration - << "\n" - << " num of devices(connected): " << Size() << "(" - << NumOfConnected() << ")\n" - << ", num of sinks(connected): " << stream_conf.sink_num_of_devices - << "(" << stream_conf.sink_streams.size() << ")\n" - << " num of sources(connected): " - << stream_conf.source_num_of_devices << "(" - << stream_conf.source_streams.size() << ")\n" - << " allocated CISes: " << static_cast(cises_.size()); - - if (cises_.size() > 0) { - stream << "\n\t == CISes == "; - for (auto cis : cises_) { - stream << "\n\t cis id: " << static_cast(cis.id) - << ",\ttype: " << static_cast(cis.type) - << ",\tconn_handle: " << static_cast(cis.conn_handle) - << ",\taddr: " << ADDRESS_TO_LOGGABLE_STR(cis.addr); - } - stream << "\n\t ===="; - } + ase->target_latency = ent.qos.target_latency; + ase->codec_id = ent.codec.id; + ase->codec_config = ent.codec.params; - if (GetFirstActiveDevice() != nullptr) { - uint32_t sink_delay; - if (GetPresentationDelay(&sink_delay, - le_audio::types::kLeAudioDirectionSink)) { - stream << "\n presentation_delay for sink (speaker): " << sink_delay - << " us"; - } + /* Let's choose audio channel allocation if not set */ + ase->codec_config.Add( + codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation, + PickAudioLocation(strategy, audio_locations, + group_audio_locations_memo.get(ent.direction))); - uint32_t source_delay; - if (GetPresentationDelay(&source_delay, - le_audio::types::kLeAudioDirectionSource)) { - stream << "\n presentation_delay for source (microphone): " - << source_delay << " us"; - } - } + /* Get default value if no requirement for specific frame blocks per sdu + */ + if (!ase->codec_config.Find( + codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu)) { + ase->codec_config.Add( + codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu, + GetMaxCodecFramesPerSduFromPac(pac)); + } - stream << "\n == devices: =="; + /* Recalculate Max SDU size */ + auto core_config = ent.codec.params.GetAsCoreCodecConfig(); + ase->max_sdu_size = core_config.GetChannelCountPerIsoStream() * + core_config.octets_per_codec_frame.value_or(0) * + core_config.codec_frames_blocks_per_sdu.value_or(1); - dprintf(fd, "%s", stream.str().c_str()); + ase->retrans_nb = ent.qos.retransmission_number; + ase->max_transport_latency = ent.qos.max_transport_latency; - for (const auto& device_iter : leAudioDevices_) { - device_iter.lock()->Dump(fd); - } + SetMetadataToAse(ase, metadata_context_types, ccid_lists); + } + + LOG_DEBUG( + "device=%s, activated ASE id=%d, direction=%s, max_sdu_size=%d, " + "cis_id=%d, target_latency=%d", + ADDRESS_TO_LOGGABLE_CSTR(address_), ase->id, + (ent.direction == 1 ? "snk" : "src"), ase->max_sdu_size, ase->cis_id, + ent.qos.target_latency); - for (const auto& device_iter : leAudioDevices_) { - auto device = device_iter.lock(); - stream_pacs << "\n\taddress: " << device->address_; - device->DumpPacsDebugState(stream_pacs); + /* Try to use the already active ASE */ + ase = GetNextActiveAseWithSameDirection(ase); + if (ase == nullptr) { + ase = GetFirstInactiveAse(ent.direction, reuse_cis_id); + } } - dprintf(fd, "%s", stream_pacs.str().c_str()); + + *number_of_already_active_group_ase = active_ases; + return true; } /* LeAudioDevice Class methods implementation */ @@ -2269,6 +340,9 @@ void LeAudioDevice::ClearPACs(void) { LeAudioDevice::~LeAudioDevice(void) { alarm_free(link_quality_timer); + for (auto& ase : ases_) { + alarm_free(ase.autonomous_operation_timer_); + } this->ClearPACs(); } @@ -2281,6 +355,8 @@ void LeAudioDevice::RegisterPACs( pac_db->clear(); } + dsa_modes_ = {DsaMode::DISABLED}; + /* TODO wrap this logging part with debug flag */ for (const struct types::acs_ac_record& pac : *pac_recs) { LOG(INFO) << "Registering PAC" @@ -2293,6 +369,18 @@ void LeAudioDevice::RegisterPACs( types::CodecCapabilitiesLtvFormat) << "\n\tMetadata: " << base::HexEncode(pac.metadata.data(), pac.metadata.size()); + + if (IS_FLAG_ENABLED(leaudio_dynamic_spatial_audio)) { + if (pac.codec_id == types::kLeAudioCodecHeadtracking) { + /* Todo: Set DSA modes according to the codec configuration */ + dsa_modes_ = { + DsaMode::DISABLED, + DsaMode::ISO_SW, + DsaMode::ISO_HW, + }; + /* Todo: Remove the headtracking codec from the list */ + } + } } pac_db->insert(pac_db->begin(), pac_recs->begin(), pac_recs->end()); @@ -2378,12 +466,14 @@ struct ase* LeAudioDevice::GetNextActiveAseWithDifferentDirection( return &(*iter); } -struct ase* LeAudioDevice::GetFirstActiveAseByDataPathState( - types::AudioStreamDataPathState state) { - auto iter = - std::find_if(ases_.begin(), ases_.end(), [state](const auto& ase) { - return (ase.active && (ase.data_path_state == state)); - }); +struct ase* LeAudioDevice::GetFirstActiveAseByCisAndDataPathState( + CisState cis_state, DataPathState data_path_state) { + auto iter = std::find_if(ases_.begin(), ases_.end(), + [cis_state, data_path_state](const auto& ase) { + return (ase.active && + (ase.data_path_state == data_path_state) && + (ase.cis_state == cis_state)); + }); return (iter == ases_.end()) ? nullptr : &(*iter); } @@ -2440,8 +530,9 @@ struct ase* LeAudioDevice::GetAseToMatchBidirectionCis(struct ase* base_ase) { return (iter == ases_.end()) ? nullptr : &(*iter); } -BidirectAsesPair LeAudioDevice::GetAsesByCisConnHdl(uint16_t conn_hdl) { - BidirectAsesPair ases = {nullptr, nullptr}; +BidirectionalPair LeAudioDevice::GetAsesByCisConnHdl( + uint16_t conn_hdl) { + BidirectionalPair ases = {nullptr, nullptr}; for (auto& ase : ases_) { if (ase.cis_conn_hdl == conn_hdl) { @@ -2456,8 +547,8 @@ BidirectAsesPair LeAudioDevice::GetAsesByCisConnHdl(uint16_t conn_hdl) { return ases; } -BidirectAsesPair LeAudioDevice::GetAsesByCisId(uint8_t cis_id) { - BidirectAsesPair ases = {nullptr, nullptr}; +BidirectionalPair LeAudioDevice::GetAsesByCisId(uint8_t cis_id) { + BidirectionalPair ases = {nullptr, nullptr}; for (auto& ase : ases_) { if (ase.cis_id == cis_id) { @@ -2496,9 +587,24 @@ bool LeAudioDevice::HaveAnyUnconfiguredAses(void) { } bool LeAudioDevice::HaveAllActiveAsesSameState(AseState state) { - auto iter = std::find_if( - ases_.begin(), ases_.end(), - [&state](const auto& ase) { return ase.active && (ase.state != state); }); + auto iter = + std::find_if(ases_.begin(), ases_.end(), [&state](const auto& ase) { + LOG_VERBOSE("ASE id: %d, active: %d, state: %s", ase.id, ase.active, + bluetooth::common::ToString(ase.state).c_str()); + return ase.active && (ase.state != state); + }); + + return iter == ases_.end(); +} + +bool LeAudioDevice::HaveAllActiveAsesSameDataPathState( + types::DataPathState state) const { + auto iter = + std::find_if(ases_.begin(), ases_.end(), [&state](const auto& ase) { + LOG_VERBOSE("ASE id: %d, active: %d, state: %s", ase.id, ase.active, + bluetooth::common::ToString(ase.data_path_state).c_str()); + return ase.active && (ase.data_path_state != state); + }); return iter == ases_.end(); } @@ -2507,6 +613,8 @@ bool LeAudioDevice::IsReadyToCreateStream(void) { auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { if (!ase.active) return false; + LOG_VERBOSE("ASE id: %d, state: %s, direction: %d", ase.id, + bluetooth::common::ToString(ase.state).c_str(), ase.direction); if (ase.direction == types::kLeAudioDirectionSink && (ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING && ase.state != AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING)) @@ -2540,70 +648,43 @@ bool LeAudioDevice::IsReadyToSuspendStream(void) { return iter == ases_.end(); } -bool LeAudioDevice::HaveAllActiveAsesCisEst(void) { +bool LeAudioDevice::HaveAllActiveAsesCisEst(void) const { if (ases_.empty()) { LOG_WARN("No ases for device %s", ADDRESS_TO_LOGGABLE_CSTR(address_)); - return false; + /* If there is no ASEs at all, it means we are good here - meaning, it is + * not waiting for any CIS to be established. + */ + return true; } - auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { - return ase.active && - (ase.data_path_state != AudioStreamDataPathState::CIS_ESTABLISHED); + bool has_active_ase = false; + auto iter = std::find_if(ases_.begin(), ases_.end(), [&](const auto& ase) { + if (!has_active_ase && ase.active) { + has_active_ase = true; + } + LOG_VERBOSE("ASE id: %d, cis_state: %s, direction: %d", ase.id, + bluetooth::common::ToString(ase.cis_state).c_str(), + ase.direction); + + return ase.active && (ase.cis_state != CisState::CONNECTED); }); - return iter == ases_.end(); + return iter == ases_.end() && has_active_ase; } bool LeAudioDevice::HaveAnyCisConnected(void) { /* Pending and Disconnecting is considered as connected in this function */ for (auto const ase : ases_) { - if (ase.data_path_state != AudioStreamDataPathState::CIS_ASSIGNED && - ase.data_path_state != AudioStreamDataPathState::IDLE) { + if (ase.cis_state == CisState::CONNECTED || + ase.cis_state == CisState::CONNECTING || + ase.cis_state == CisState::DISCONNECTING) { return true; } } return false; } -bool LeAudioDevice::HasCisId(uint8_t id) { - struct ase* ase = GetFirstActiveAse(); - - while (ase) { - if (ase->cis_id == id) return true; - ase = GetNextActiveAse(ase); - } - - return false; -} - -uint8_t LeAudioDevice::GetMatchingBidirectionCisId( - const struct types::ase* base_ase) { - for (auto& ase : ases_) { - auto& cis = ase.cis_id; - if (!ase.active) continue; - - int num_cises = - std::count_if(ases_.begin(), ases_.end(), [&cis](const auto& iter_ase) { - return iter_ase.active && iter_ase.cis_id == cis; - }); - - /* - * If there is only one ASE for device with unique CIS ID and opposite to - * direction - it may be bi-directional/completive. - */ - if (num_cises == 1 && - ((base_ase->direction == types::kLeAudioDirectionSink && - ase.direction == types::kLeAudioDirectionSource) || - (base_ase->direction == types::kLeAudioDirectionSource && - ase.direction == types::kLeAudioDirectionSink))) { - return ase.cis_id; - } - } - - return kInvalidCisId; -} - -uint8_t LeAudioDevice::GetLc3SupportedChannelCount(uint8_t direction) { +uint8_t LeAudioDevice::GetSupportedAudioChannelCounts(uint8_t direction) const { auto& pacs = direction == types::kLeAudioDirectionSink ? snk_pacs_ : src_pacs_; @@ -2621,7 +702,7 @@ uint8_t LeAudioDevice::GetLc3SupportedChannelCount(uint8_t direction) { continue; auto supported_channel_count_ltv = pac.codec_spec_caps.Find( - codec_spec_caps::kLeAudioCodecLC3TypeAudioChannelCounts); + codec_spec_caps::kLeAudioLtvTypeSupportedAudioChannelCounts); if (supported_channel_count_ltv == std::nullopt || supported_channel_count_ltv->size() == 0L) { @@ -2637,7 +718,7 @@ uint8_t LeAudioDevice::GetLc3SupportedChannelCount(uint8_t direction) { const struct types::acs_ac_record* LeAudioDevice::GetCodecConfigurationSupportedPac( - uint8_t direction, const CodecCapabilitySetting& codec_capability_setting) { + uint8_t direction, const CodecConfigSetting& codec_capability_setting) { auto& pacs = direction == types::kLeAudioDirectionSink ? snk_pacs_ : src_pacs_; @@ -2653,7 +734,7 @@ LeAudioDevice::GetCodecConfigurationSupportedPac( auto& pac_recs = std::get<1>(pac_tuple); for (const auto& pac : pac_recs) { - if (!IsCodecCapabilitySettingSupported(pac, codec_capability_setting)) + if (!IsCodecConfigSettingSupported(pac, codec_capability_setting)) continue; return &pac; @@ -2676,12 +757,6 @@ uint8_t LeAudioDevice::GetPhyBitmask(void) { return phy_bitfield; } -void LeAudioDevice::SetSupportedContexts(AudioContexts snk_contexts, - AudioContexts src_contexts) { - supp_contexts_.sink = snk_contexts; - supp_contexts_.source = src_contexts; -} - void LeAudioDevice::PrintDebugState(void) { std::stringstream debug_str; @@ -2698,7 +773,9 @@ void LeAudioDevice::PrintDebugState(void) { << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source") << ", cis_id: " << +ase.cis_id - << ", cis_handle: " << +ase.cis_conn_hdl << ", state: " + << ", cis_handle: " << +ase.cis_conn_hdl + << ", state: " << bluetooth::common::ToString(ase.cis_state) + << ", data_path_state: " << bluetooth::common::ToString(ase.data_path_state) << "\n ase max_latency: " << +ase.max_transport_latency << ", rtn: " << +ase.retrans_nb @@ -2773,8 +850,8 @@ void LeAudioDevice::Dump(int fd) { if (ases_.size() > 0) { stream << "\n\t== ASEs == \n\t"; - stream - << "id active dir cis_id cis_handle sdu latency rtn state"; + stream << "id active dir cis_id cis_handle sdu latency rtn " + "cis_state data_path_state"; for (auto& ase : ases_) { stream << std::setfill('\x20') << "\n\t" << std::left << std::setw(4) << static_cast(ase.id) << std::left << std::setw(7) @@ -2785,7 +862,8 @@ void LeAudioDevice::Dump(int fd) { << std::left << std::setw(12) << ase.cis_conn_hdl << std::left << std::setw(5) << ase.max_sdu_size << std::left << std::setw(8) << ase.max_transport_latency << std::left << std::setw(5) - << static_cast(ase.retrans_nb) << std::left << std::setw(12) + << static_cast(ase.retrans_nb) << std::left << std::setw(10) + << bluetooth::common::ToString(ase.cis_state) << std::setw(12) << bluetooth::common::ToString(ase.data_path_state); } } @@ -2806,29 +884,40 @@ void LeAudioDevice::DisconnectAcl(void) { } } -/* Returns XOR of updated sink and source bitset context types */ -AudioContexts LeAudioDevice::SetAvailableContexts(AudioContexts snk_contexts, - AudioContexts src_contexts) { - AudioContexts updated_contexts; - - updated_contexts = snk_contexts ^ avail_contexts_.sink; - updated_contexts |= src_contexts ^ avail_contexts_.source; - +void LeAudioDevice::SetAvailableContexts( + BidirectionalPair contexts) { LOG_DEBUG( - "\n\t avail_contexts_.sink: %s \n\t avail_contexts_.source: %s \n\t " - "snk_contexts: %s \n\t src_contexts: %s \n\t updated_contexts: %s", + "\n\t previous_contexts_.sink: %s \n\t previous_contexts_.source: %s " + "\n\t " + "new_contexts.sink: %s \n\t new_contexts.source: %s \n\t ", avail_contexts_.sink.to_string().c_str(), avail_contexts_.source.to_string().c_str(), - snk_contexts.to_string().c_str(), src_contexts.to_string().c_str(), - updated_contexts.to_string().c_str()); + contexts.sink.to_string().c_str(), contexts.source.to_string().c_str()); - avail_contexts_.sink = snk_contexts; - avail_contexts_.source = src_contexts; + avail_contexts_.sink = contexts.sink; + avail_contexts_.source = contexts.source; +} - return updated_contexts; +void LeAudioDevice::SetMetadataToAse( + struct types::ase* ase, + const BidirectionalPair& metadata_context_types, + BidirectionalPair> ccid_lists) { + /* Filter multidirectional audio context for each ase direction */ + auto directional_audio_context = metadata_context_types.get(ase->direction) & + GetAvailableContexts(ase->direction); + if (directional_audio_context.any()) { + ase->metadata = + GetMetadata(directional_audio_context, ccid_lists.get(ase->direction)); + } else { + ase->metadata = GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED), + std::vector()); + } } -bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) { +bool LeAudioDevice::ActivateConfiguredAses( + LeAudioContextType context_type, + const BidirectionalPair& metadata_context_types, + BidirectionalPair> ccid_lists) { if (conn_id_ == GATT_INVALID_CONN_ID) { LOG_WARN(" Device %s is not connected ", ADDRESS_TO_LOGGABLE_CSTR(address_)); @@ -2846,6 +935,8 @@ bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) { conn_id_, ase.id, ase.cis_id, ase.cis_conn_hdl); ase.active = true; ret = true; + /* update metadata */ + SetMetadataToAse(&ase, metadata_context_types, ccid_lists); } } @@ -2854,17 +945,23 @@ bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) { void LeAudioDevice::DeactivateAllAses(void) { for (auto& ase : ases_) { - if (ase.active == false && - ase.data_path_state != AudioStreamDataPathState::IDLE) { + if (ase.active == false && ase.cis_state != CisState::IDLE && + ase.data_path_state != DataPathState::IDLE) { LOG_WARN( " %s, ase_id: %d, ase.cis_id: %d, cis_handle: 0x%02x, " - "ase.data_path=%s", + "ase.cis_state=%s, ase.data_path_state=%s", ADDRESS_TO_LOGGABLE_CSTR(address_), ase.id, ase.cis_id, - ase.cis_conn_hdl, + ase.cis_conn_hdl, bluetooth::common::ToString(ase.cis_state).c_str(), bluetooth::common::ToString(ase.data_path_state).c_str()); } + if (alarm_is_scheduled(ase.autonomous_operation_timer_)) { + alarm_free(ase.autonomous_operation_timer_); + ase.autonomous_operation_timer_ = NULL; + ase.autonomous_target_state_ = AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; + } ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; - ase.data_path_state = AudioStreamDataPathState::IDLE; + ase.cis_state = CisState::IDLE; + ase.data_path_state = DataPathState::IDLE; ase.active = false; ase.cis_id = le_audio::kInvalidCisId; ase.cis_conn_hdl = 0; @@ -2894,86 +991,38 @@ bool LeAudioDevice::IsMetadataChanged( return false; } -LeAudioDeviceGroup* LeAudioDeviceGroups::Add(int group_id) { - /* Get first free group id */ - if (FindById(group_id)) { - LOG(ERROR) << __func__ - << ", group already exists, id: " << loghex(group_id); - return nullptr; +void LeAudioDevice::GetDeviceModelName(void) { + bt_property_t prop_name; + bt_bdname_t prop_value = {0}; + // Retrieve model name from storage + BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_REMOTE_MODEL_NUM, + sizeof(bt_bdname_t), &prop_value); + if (btif_storage_get_remote_device_property(&address_, &prop_name) == + BT_STATUS_SUCCESS) { + model_name_.assign((char*)prop_value.name); } - - return (groups_.emplace_back(std::make_unique(group_id))) - .get(); } -void LeAudioDeviceGroups::Remove(int group_id) { - auto iter = std::find_if( - groups_.begin(), groups_.end(), - [&group_id](auto const& group) { return group->group_id_ == group_id; }); - - if (iter == groups_.end()) { - LOG(ERROR) << __func__ << ", no such group_id: " << group_id; +void LeAudioDevice::UpdateDeviceAllowlistFlag(void) { + char allow_list[PROPERTY_VALUE_MAX] = {0}; + GetDeviceModelName(); + osi_property_get(kLeAudioDeviceAllowListProp, allow_list, ""); + if (allow_list[0] == '\0' || model_name_ == "") { + // if device allow list is empty or no remote model name available + // return allowlist_flag_ as default false return; } - groups_.erase(iter); -} - -LeAudioDeviceGroup* LeAudioDeviceGroups::FindById(int group_id) { - auto iter = std::find_if( - groups_.begin(), groups_.end(), - [&group_id](auto const& group) { return group->group_id_ == group_id; }); - - return (iter == groups_.end()) ? nullptr : iter->get(); -} - -void LeAudioDeviceGroups::Cleanup(void) { - for (auto& g : groups_) { - g->Cleanup(); - } - - groups_.clear(); -} - -void LeAudioDeviceGroups::Dump(int fd, int active_group_id) { - /* Dump first active group */ - for (auto& g : groups_) { - if (g->group_id_ == active_group_id) { - g->Dump(fd, active_group_id); - break; - } - } - - /* Dump non active group */ - for (auto& g : groups_) { - if (g->group_id_ != active_group_id) { - g->Dump(fd, active_group_id); - } - } -} - -bool LeAudioDeviceGroups::IsAnyInTransition(void) { - for (auto& g : groups_) { - if (g->IsInTransition()) { - DLOG(INFO) << __func__ << " group: " << g->group_id_ - << " is in transition"; - return true; + std::istringstream stream(allow_list); + std::string token; + while (std::getline(stream, token, ',')) { + if (token.compare(model_name_) == 0) { + allowlist_flag_ = true; + return; } } - return false; -} - -size_t LeAudioDeviceGroups::Size() { return (groups_.size()); } - -std::vector LeAudioDeviceGroups::GetGroupsIds(void) { - std::vector result; - - for (auto const& group : groups_) { - result.push_back(group->group_id_); - } - - return result; } +DsaModes LeAudioDevice::GetDsaModes(void) { return dsa_modes_; } /* LeAudioDevices Class methods implementation */ void LeAudioDevices::Add(const RawAddress& address, DeviceConnectState state, @@ -3004,7 +1053,7 @@ void LeAudioDevices::Remove(const RawAddress& address) { leAudioDevices_.erase(iter); } -LeAudioDevice* LeAudioDevices::FindByAddress(const RawAddress& address) { +LeAudioDevice* LeAudioDevices::FindByAddress(const RawAddress& address) const { auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&address](auto const& leAudioDevice) { return leAudioDevice->address_ == address; @@ -3014,7 +1063,7 @@ LeAudioDevice* LeAudioDevices::FindByAddress(const RawAddress& address) { } std::shared_ptr LeAudioDevices::GetByAddress( - const RawAddress& address) { + const RawAddress& address) const { auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&address](auto const& leAudioDevice) { return leAudioDevice->address_ == address; @@ -3023,7 +1072,7 @@ std::shared_ptr LeAudioDevices::GetByAddress( return (iter == leAudioDevices_.end()) ? nullptr : *iter; } -LeAudioDevice* LeAudioDevices::FindByConnId(uint16_t conn_id) { +LeAudioDevice* LeAudioDevices::FindByConnId(uint16_t conn_id) const { auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&conn_id](auto const& leAudioDevice) { return leAudioDevice->conn_id_ == conn_id; @@ -3033,11 +1082,11 @@ LeAudioDevice* LeAudioDevices::FindByConnId(uint16_t conn_id) { } LeAudioDevice* LeAudioDevices::FindByCisConnHdl(uint8_t cig_id, - uint16_t conn_hdl) { + uint16_t conn_hdl) const { auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(), [&conn_hdl, &cig_id](auto& d) { LeAudioDevice* dev; - BidirectAsesPair ases; + BidirectionalPair ases; dev = d.get(); if (dev->group_id_ != cig_id) { @@ -3095,9 +1144,9 @@ void LeAudioDevices::SetInitialGroupAutoconnectState( } } -size_t LeAudioDevices::Size() { return (leAudioDevices_.size()); } +size_t LeAudioDevices::Size() const { return (leAudioDevices_.size()); } -void LeAudioDevices::Dump(int fd, int group_id) { +void LeAudioDevices::Dump(int fd, int group_id) const { std::stringstream stream, stream_pacs; for (auto const& device : leAudioDevices_) { @@ -3114,7 +1163,8 @@ void LeAudioDevices::Dump(int fd, int group_id) { void LeAudioDevices::Cleanup(tGATT_IF client_if) { for (auto const& device : leAudioDevices_) { auto connection_state = device->GetConnectionState(); - if (connection_state == DeviceConnectState::DISCONNECTED) { + if (connection_state == DeviceConnectState::DISCONNECTED || + connection_state == DeviceConnectState::DISCONNECTING) { continue; } diff --git a/system/bta/le_audio/devices.h b/system/bta/le_audio/devices.h index aba75a521f282f13dd4c973675b115aa9bc3af9a..7d3f6f118d9beaa6631bb465cd61ac1d98e41c94 100644 --- a/system/bta/le_audio/devices.h +++ b/system/bta/le_audio/devices.h @@ -17,10 +17,13 @@ #pragma once +#include + #include #include #include #include +#include // for std::pair #include #ifdef __ANDROID__ @@ -28,7 +31,6 @@ #endif #include "audio_hal_client/audio_hal_client.h" -#include "bt_types.h" #include "bta_groups.h" #include "btm_iso_api_types.h" #include "gatt_api.h" @@ -36,6 +38,7 @@ #include "le_audio_log_history.h" #include "le_audio_types.h" #include "osi/include/alarm.h" +#include "osi/include/log.h" #include "osi/include/properties.h" #include "raw_address.h" @@ -58,10 +61,6 @@ enum class DeviceConnectState : uint8_t { /* Disconnecting for recover - after that we want direct connect to be initiated */ DISCONNECTING_AND_RECOVER, - /* Device will be removed after scheduled action is finished: One of such - * action is taking Stream to IDLE - */ - PENDING_REMOVAL, /* 2 states below are used when user creates connection. Connect API is called. */ CONNECTING_BY_USER, @@ -101,6 +100,7 @@ class LeAudioDevice { bool encrypted_; int group_id_; bool csis_member_; + int cis_failed_to_be_established_retry_cnt_; std::bitset<16> tmap_role_; uint8_t audio_directions_; @@ -117,6 +117,8 @@ class LeAudioDevice { std::vector ases_; struct types::hdl_pair ctp_hdls_; uint16_t tmap_role_hdl_; + std::string model_name_; + bool allowlist_flag_; alarm_t* link_quality_timer; uint16_t link_quality_timer_data; @@ -134,8 +136,12 @@ class LeAudioDevice { encrypted_(false), group_id_(group_id), csis_member_(false), + cis_failed_to_be_established_retry_cnt_(0), audio_directions_(0), - link_quality_timer(nullptr) {} + model_name_(""), + allowlist_flag_(false), + link_quality_timer(nullptr), + dsa_modes_({DsaMode::DISABLED}) {} ~LeAudioDevice(void); void SetConnectionState(DeviceConnectState state); @@ -151,29 +157,33 @@ class LeAudioDevice { struct types::ase* base_ase); struct types::ase* GetNextActiveAseWithDifferentDirection( struct types::ase* base_ase); - struct types::ase* GetFirstActiveAseByDataPathState( - types::AudioStreamDataPathState state); + struct types::ase* GetFirstActiveAseByCisAndDataPathState( + types::CisState cis_state, types::DataPathState data_path_state); struct types::ase* GetFirstInactiveAse(uint8_t direction, bool reconnect = false); struct types::ase* GetFirstAseWithState(uint8_t direction, types::AseState state); struct types::ase* GetNextActiveAse(struct types::ase* ase); struct types::ase* GetAseToMatchBidirectionCis(struct types::ase* ase); - types::BidirectAsesPair GetAsesByCisConnHdl(uint16_t conn_hdl); - types::BidirectAsesPair GetAsesByCisId(uint8_t cis_id); + types::BidirectionalPair GetAsesByCisConnHdl( + uint16_t conn_hdl); + types::BidirectionalPair GetAsesByCisId(uint8_t cis_id); bool HaveActiveAse(void); bool HaveAllActiveAsesSameState(types::AseState state); + bool HaveAllActiveAsesSameDataPathState(types::DataPathState state) const; bool HaveAnyUnconfiguredAses(void); bool IsReadyToCreateStream(void); + bool IsReadyToStream(void) const { + return HaveAllActiveAsesCisEst() && + HaveAllActiveAsesSameDataPathState(types::DataPathState::CONFIGURED); + } bool IsReadyToSuspendStream(void); - bool HaveAllActiveAsesCisEst(void); + bool HaveAllActiveAsesCisEst(void) const; bool HaveAnyCisConnected(void); - bool HasCisId(uint8_t id); - uint8_t GetMatchingBidirectionCisId(const struct types::ase* base_ase); const struct types::acs_ac_record* GetCodecConfigurationSupportedPac( - uint8_t direction, const set_configurations::CodecCapabilitySetting& - codec_capability_setting); - uint8_t GetLc3SupportedChannelCount(uint8_t direction); + uint8_t direction, + const set_configurations::CodecConfigSetting& codec_capability_setting); + uint8_t GetSupportedAudioChannelCounts(uint8_t direction) const; uint8_t GetPhyBitmask(void); bool ConfigureAses( const le_audio::set_configurations::SetConfiguration& ent, @@ -185,17 +195,46 @@ class LeAudioDevice { metadata_context_types, const types::BidirectionalPair>& ccid_lists, bool reuse_cis_id); - void SetSupportedContexts(types::AudioContexts snk_contexts, - types::AudioContexts src_contexts); + + inline types::AudioContexts GetSupportedContexts( + int direction = types::kLeAudioDirectionBoth) const { + ASSERT_LOG(direction <= (types::kLeAudioDirectionBoth), + "Invalid direction used."); + + if (direction < types::kLeAudioDirectionBoth) + return supp_contexts_.get(direction); + else + return types::get_bidirectional(supp_contexts_); + } + inline void SetSupportedContexts( + types::BidirectionalPair contexts) { + supp_contexts_ = contexts; + } + inline types::AudioContexts GetAvailableContexts( - int direction = (types::kLeAudioDirectionSink | - types::kLeAudioDirectionSource)) { - return avail_contexts_.get(direction); + int direction = types::kLeAudioDirectionBoth) const { + ASSERT_LOG(direction <= (types::kLeAudioDirectionBoth), + "Invalid direction used."); + + if (direction < types::kLeAudioDirectionBoth) + return avail_contexts_.get(direction); + else + return types::get_bidirectional(avail_contexts_); } - types::AudioContexts SetAvailableContexts(types::AudioContexts snk_cont_val, - types::AudioContexts src_cont_val); + void SetAvailableContexts( + types::BidirectionalPair cont_val); + void DeactivateAllAses(void); - bool ActivateConfiguredAses(types::LeAudioContextType context_type); + bool ActivateConfiguredAses( + types::LeAudioContextType context_type, + const types::BidirectionalPair& + metadata_context_types, + types::BidirectionalPair> ccid_lists); + void SetMetadataToAse( + struct types::ase* ase, + const types::BidirectionalPair& + metadata_context_types, + types::BidirectionalPair> ccid_lists); void PrintDebugState(void); void DumpPacsDebugState(std::stringstream& stream); @@ -208,9 +247,16 @@ class LeAudioDevice { const types::BidirectionalPair& context_types, const types::BidirectionalPair>& ccid_lists); + void GetDeviceModelName(void); + void UpdateDeviceAllowlistFlag(void); + DsaModes GetDsaModes(void); + private: types::BidirectionalPair avail_contexts_; types::BidirectionalPair supp_contexts_; + DsaModes dsa_modes_; + static constexpr char kLeAudioDeviceAllowListProp[] = + "persist.bluetooth.leaudio.allow_list"; void DumpPacsDebugState(std::stringstream& stream, types::PublishedAudioCapabilities pacs); @@ -225,286 +271,19 @@ class LeAudioDevices { void Add(const RawAddress& address, le_audio::DeviceConnectState state, int group_id = bluetooth::groups::kGroupUnknown); void Remove(const RawAddress& address); - LeAudioDevice* FindByAddress(const RawAddress& address); - std::shared_ptr GetByAddress(const RawAddress& address); - LeAudioDevice* FindByConnId(uint16_t conn_id); - LeAudioDevice* FindByCisConnHdl(uint8_t cig_id, uint16_t conn_hdl); + LeAudioDevice* FindByAddress(const RawAddress& address) const; + std::shared_ptr GetByAddress(const RawAddress& address) const; + LeAudioDevice* FindByConnId(uint16_t conn_id) const; + LeAudioDevice* FindByCisConnHdl(uint8_t cig_id, uint16_t conn_hdl) const; void SetInitialGroupAutoconnectState(int group_id, int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode, bool current_dev_autoconnect_flag); - size_t Size(void); - void Dump(int fd, int group_id); + size_t Size(void) const; + void Dump(int fd, int group_id) const; void Cleanup(tGATT_IF client_if); private: std::vector> leAudioDevices_; }; -/* LeAudioDeviceGroup class represents group of LeAudioDevices and allows to - * perform operations on them. Group states are ASE states due to nature of - * group which operates finally of ASEs. - * - * Group is created after adding a node to new group id (which is not on list). - */ - -class LeAudioDeviceGroup { - public: - const int group_id_; - bool enabled_; - types::CigState cig_state_; - - struct stream_configuration stream_conf; - - uint8_t audio_directions_; - types::AudioLocations snk_audio_locations_; - types::AudioLocations src_audio_locations_; - - /* Whether LE Audio is preferred for OUTPUT_ONLY and DUPLEX cases */ - bool is_output_preference_le_audio; - bool is_duplex_preference_le_audio; - - std::vector cises_; - explicit LeAudioDeviceGroup(const int group_id) - : group_id_(group_id), - enabled_(true), - cig_state_(types::CigState::NONE), - stream_conf({}), - audio_directions_(0), - transport_latency_mtos_us_(0), - transport_latency_stom_us_(0), - configuration_context_type_(types::LeAudioContextType::UNINITIALIZED), - metadata_context_type_({.sink = types::AudioContexts( - types::LeAudioContextType::UNINITIALIZED), - .source = types::AudioContexts( - types::LeAudioContextType::UNINITIALIZED)}), - group_available_contexts_(types::LeAudioContextType::UNINITIALIZED), - pending_group_available_contexts_change_( - types::LeAudioContextType::UNINITIALIZED), - target_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), - current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { -#ifdef __ANDROID__ - // 22 maps to BluetoothProfile#LE_AUDIO - is_output_preference_le_audio = android::sysprop::BluetoothProperties:: - getDefaultOutputOnlyAudioProfile() == - LE_AUDIO_PROFILE_CONSTANT; - is_duplex_preference_le_audio = - android::sysprop::BluetoothProperties::getDefaultDuplexAudioProfile() == - LE_AUDIO_PROFILE_CONSTANT; -#else - is_output_preference_le_audio = true; - is_duplex_preference_le_audio = true; -#endif - } - ~LeAudioDeviceGroup(void); - - void AddNode(const std::shared_ptr& leAudioDevice); - void RemoveNode(const std::shared_ptr& leAudioDevice); - bool IsEmpty(void); - bool IsAnyDeviceConnected(void); - int Size(void); - int NumOfConnected( - types::LeAudioContextType context_type = types::LeAudioContextType::RFU); - bool Activate(types::LeAudioContextType context_type); - void Deactivate(void); - types::CigState GetCigState(void); - void SetCigState(le_audio::types::CigState state); - void CigClearCis(void); - void ClearSinksFromConfiguration(void); - void ClearSourcesFromConfiguration(void); - void Cleanup(void); - LeAudioDevice* GetFirstDevice(void); - LeAudioDevice* GetFirstDeviceWithActiveContext( - types::LeAudioContextType context_type); - le_audio::types::LeAudioConfigurationStrategy GetGroupStrategy( - int expected_group_size); - int GetAseCount(uint8_t direction); - LeAudioDevice* GetNextDevice(LeAudioDevice* leAudioDevice); - LeAudioDevice* GetNextDeviceWithActiveContext( - LeAudioDevice* leAudioDevice, types::LeAudioContextType context_type); - LeAudioDevice* GetFirstActiveDevice(void); - LeAudioDevice* GetNextActiveDevice(LeAudioDevice* leAudioDevice); - LeAudioDevice* GetFirstActiveDeviceByDataPathState( - types::AudioStreamDataPathState data_path_state); - LeAudioDevice* GetNextActiveDeviceByDataPathState( - LeAudioDevice* leAudioDevice, - types::AudioStreamDataPathState data_path_state); - bool IsDeviceInTheGroup(LeAudioDevice* leAudioDevice); - bool HaveAllActiveDevicesAsesTheSameState(types::AseState state); - bool HaveAnyActiveDeviceInUnconfiguredState(); - bool IsGroupStreamReady(void); - bool IsGroupReadyToCreateStream(void); - bool IsGroupReadyToSuspendStream(void); - bool HaveAllCisesDisconnected(void); - uint8_t GetFirstFreeCisId(void); - uint8_t GetFirstFreeCisId(types::CisType cis_type); - void CigGenerateCisIds(types::LeAudioContextType context_type); - bool CigAssignCisIds(LeAudioDevice* leAudioDevice); - void CigAssignCisConnHandles(const std::vector& conn_handles); - void CigAssignCisConnHandlesToAses(LeAudioDevice* leAudioDevice); - void CigAssignCisConnHandlesToAses(void); - void CigUnassignCis(LeAudioDevice* leAudioDevice); - bool Configure(types::LeAudioContextType context_type, - const types::BidirectionalPair& - metadata_context_types, - types::BidirectionalPair> ccid_lists = { - .sink = {}, .source = {}}); - uint32_t GetSduInterval(uint8_t direction); - uint8_t GetSCA(void); - uint8_t GetPacking(void); - uint8_t GetFraming(void); - uint16_t GetMaxTransportLatencyStom(void); - uint16_t GetMaxTransportLatencyMtos(void); - void SetTransportLatency(uint8_t direction, uint32_t transport_latency_us); - uint8_t GetRtn(uint8_t direction, uint8_t cis_id); - uint16_t GetMaxSduSize(uint8_t direction, uint8_t cis_id); - uint8_t GetPhyBitmask(uint8_t direction); - uint8_t GetTargetPhy(uint8_t direction); - bool GetPresentationDelay(uint32_t* delay, uint8_t direction); - uint16_t GetRemoteDelay(uint8_t direction); - bool UpdateAudioContextTypeAvailability(types::AudioContexts contexts); - void UpdateAudioContextTypeAvailability(void); - bool ReloadAudioLocations(void); - bool ReloadAudioDirections(void); - const set_configurations::AudioSetConfiguration* GetActiveConfiguration(void); - bool IsPendingConfiguration(void); - void SetPendingConfiguration(void); - void ClearPendingConfiguration(void); - void AddToAllowListNotConnectedGroupMembers(int gatt_if); - void Disable(int gatt_if); - void Enable(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode); - bool IsEnabled(void); - bool IsConfigurationSupported( - LeAudioDevice* leAudioDevice, - const set_configurations::AudioSetConfiguration* audio_set_conf); - std::optional GetCodecConfigurationByDirection( - types::LeAudioContextType group_context_type, uint8_t direction) const; - bool IsContextSupported(types::LeAudioContextType group_context_type); - bool IsMetadataChanged( - const types::BidirectionalPair& context_types, - const types::BidirectionalPair>& ccid_lists); - void CreateStreamVectorForOffloader(uint8_t direction); - void StreamOffloaderUpdated(uint8_t direction); - - inline types::AseState GetState(void) const { return current_state_; } - void SetState(types::AseState state) { - LOG(INFO) << __func__ << " current state: " << current_state_ - << " new state: " << state; - LeAudioLogHistory::Get()->AddLogHistory( - kLogStateMachineTag, group_id_, RawAddress::kEmpty, kLogStateChangedOp, - bluetooth::common::ToString(current_state_) + "->" + - bluetooth::common::ToString(state)); - current_state_ = state; - } - - inline types::AseState GetTargetState(void) const { return target_state_; } - void SetTargetState(types::AseState state) { - LOG(INFO) << __func__ << " target state: " << target_state_ - << " new target state: " << state; - LeAudioLogHistory::Get()->AddLogHistory( - kLogStateMachineTag, group_id_, RawAddress::kEmpty, - kLogTargetStateChangedOp, - bluetooth::common::ToString(target_state_) + "->" + - bluetooth::common::ToString(state)); - target_state_ = state; - } - - /* Returns context types for which support was recently added or removed */ - inline types::AudioContexts GetPendingAvailableContextsChange() const { - return pending_group_available_contexts_change_; - } - - /* Set which context types were recently added or removed */ - inline void SetPendingAvailableContextsChange( - types::AudioContexts audio_contexts) { - pending_group_available_contexts_change_ = audio_contexts; - } - - inline void ClearPendingAvailableContextsChange() { - pending_group_available_contexts_change_.clear(); - } - - inline types::LeAudioContextType GetConfigurationContextType(void) const { - return configuration_context_type_; - } - - inline types::BidirectionalPair GetMetadataContexts() - const { - return metadata_context_type_; - } - - inline types::AudioContexts GetAvailableContexts(void) { - return group_available_contexts_; - } - - bool IsInTransition(void); - bool IsStreaming(void); - bool IsReleasingOrIdle(void); - - void PrintDebugState(void); - void Dump(int fd, int active_group_id); - - private: - uint32_t transport_latency_mtos_us_; - uint32_t transport_latency_stom_us_; - - const set_configurations::AudioSetConfiguration* - FindFirstSupportedConfiguration(types::LeAudioContextType context_type); - bool ConfigureAses( - const set_configurations::AudioSetConfiguration* audio_set_conf, - types::LeAudioContextType context_type, - const types::BidirectionalPair& - metadata_context_types, - const types::BidirectionalPair>& ccid_lists); - bool IsConfigurationSupported( - const set_configurations::AudioSetConfiguration* audio_set_configuration, - types::LeAudioContextType context_type, - types::LeAudioConfigurationStrategy required_snk_strategy); - uint32_t GetTransportLatencyUs(uint8_t direction); - - /* Current configuration and metadata context types */ - types::LeAudioContextType configuration_context_type_; - types::BidirectionalPair metadata_context_type_; - - /* Mask of contexts that the whole group can handle at it's current state - * It's being updated each time group members connect, disconnect or their - * individual available audio contexts are changed. - */ - types::AudioContexts group_available_contexts_; - - /* A temporary mask for bits which were either added or removed when the - * group available context type changes. It usually means we should refresh - * our group configuration capabilities to clear this. - */ - types::AudioContexts pending_group_available_contexts_change_; - - /* Possible configuration cache - refreshed on each group context availability - * change - */ - std::map - available_context_to_configuration_map; - - types::AseState target_state_; - types::AseState current_state_; - std::vector> leAudioDevices_; -}; - -/* LeAudioDeviceGroup class represents a wraper helper over all device groups in - * le audio implementation. It allows to operate on device group from a list - * (vector container) using determinants like id. - */ -class LeAudioDeviceGroups { - public: - LeAudioDeviceGroup* Add(int group_id); - void Remove(const int group_id); - LeAudioDeviceGroup* FindById(int group_id); - std::vector GetGroupsIds(void); - size_t Size(); - bool IsAnyInTransition(); - void Cleanup(void); - void Dump(int fd, int active_group_id); - - private: - std::vector> groups_; -}; } // namespace le_audio diff --git a/system/bta/le_audio/devices_test.cc b/system/bta/le_audio/devices_test.cc index 3af51a3295a677bfb24089a285ae5a2b6088ebc7..d7407c59beac6cdd1b4d73235ab4b93eb291cdea 100644 --- a/system/bta/le_audio/devices_test.cc +++ b/system/bta/le_audio/devices_test.cc @@ -20,7 +20,9 @@ #include #include +#include "btif_storage_mock.h" #include "btm_api_mock.h" +#include "device_groups.h" #include "le_audio_set_configuration_provider.h" #include "le_audio_types.h" #include "mock_controller.h" @@ -65,17 +67,20 @@ class LeAudioDevicesTest : public Test { devices_ = new LeAudioDevices(); bluetooth::manager::SetMockBtmInterface(&btm_interface); controller::SetMockControllerInterface(&controller_interface_); + bluetooth::storage::SetMockBtifStorageInterface(&mock_btif_storage_); } void TearDown() override { controller::SetMockControllerInterface(nullptr); bluetooth::manager::SetMockBtmInterface(nullptr); + bluetooth::storage::SetMockBtifStorageInterface(nullptr); delete devices_; } LeAudioDevices* devices_ = nullptr; bluetooth::manager::MockBtmInterface btm_interface; controller::MockControllerInterface controller_interface_; + bluetooth::storage::MockBtifStorageInterface mock_btif_storage_; }; TEST_F(LeAudioDevicesTest, test_add) { @@ -168,6 +173,32 @@ TEST_F(LeAudioDevicesTest, test_find_by_conn_id_failed) { ASSERT_EQ(nullptr, devices_->FindByConnId(0x0006)); } +TEST_F(LeAudioDevicesTest, test_get_device_model_name_success) { + RawAddress test_address_0 = GetTestAddress(0); + devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER); + std::shared_ptr device = + devices_->GetByAddress(test_address_0); + ASSERT_NE(nullptr, device); + device->model_name_ = "Test"; + ON_CALL(mock_btif_storage_, GetRemoteDeviceProperty(_, _)) + .WillByDefault(Return(BT_STATUS_SUCCESS)); + device->GetDeviceModelName(); + ASSERT_EQ("", device->model_name_); +} + +TEST_F(LeAudioDevicesTest, test_get_device_model_name_failed) { + RawAddress test_address_0 = GetTestAddress(0); + devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER); + std::shared_ptr device = + devices_->GetByAddress(test_address_0); + ASSERT_NE(nullptr, device); + device->model_name_ = "Test"; + ON_CALL(mock_btif_storage_, GetRemoteDeviceProperty(_, _)) + .WillByDefault(Return(BT_STATUS_FAIL)); + device->GetDeviceModelName(); + ASSERT_EQ("Test", device->model_name_); +} + /* TODO: Add FindByCisConnHdl test cases (ASE) */ } // namespace @@ -273,7 +304,7 @@ uint8_t GetSamplingFrequency(Lc3SettingId id) { } } -static constexpr uint8_t kLeAudioCodecLC3FrameDurRfu = 0x02; +static constexpr uint8_t kLeAudioCodecFrameDurRfu = 0x02; uint8_t GetFrameDuration(Lc3SettingId id) { switch (id) { case Lc3SettingId::LC3_8_1: @@ -284,7 +315,7 @@ uint8_t GetFrameDuration(Lc3SettingId id) { case Lc3SettingId::LC3_48_1: case Lc3SettingId::LC3_48_3: case Lc3SettingId::LC3_48_5: - return ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameDur7500us; + return ::le_audio::codec_spec_conf::kLeAudioCodecFrameDur7500us; case Lc3SettingId::LC3_8_2: case Lc3SettingId::LC3_16_2: case Lc3SettingId::LC3_24_2: @@ -294,9 +325,9 @@ uint8_t GetFrameDuration(Lc3SettingId id) { case Lc3SettingId::LC3_48_4: case Lc3SettingId::LC3_48_6: case Lc3SettingId::LC3_VND_1: - return ::le_audio::codec_spec_conf::kLeAudioCodecLC3FrameDur10000us; + return ::le_audio::codec_spec_conf::kLeAudioCodecFrameDur10000us; case Lc3SettingId::UNSUPPORTED: - return kLeAudioCodecLC3FrameDurRfu; + return kLeAudioCodecFrameDurRfu; } } @@ -357,15 +388,15 @@ class PublishedAudioCapabilitiesBuilder { pac_records_.push_back( acs_ac_record({.codec_id = codec_id, .codec_spec_caps = LeAudioLtvMap({ - {kLeAudioCodecLC3TypeSamplingFreq, + {kLeAudioLtvTypeSupportedSamplingFrequencies, UINT16_TO_VEC_UINT8(sampling_frequencies)}, - {kLeAudioCodecLC3TypeFrameDuration, + {kLeAudioLtvTypeSupportedFrameDurations, UINT8_TO_VEC_UINT8(frame_durations)}, - {kLeAudioCodecLC3TypeAudioChannelCounts, + {kLeAudioLtvTypeSupportedAudioChannelCounts, UINT8_TO_VEC_UINT8(audio_channel_counts)}, - {kLeAudioCodecLC3TypeOctetPerFrame, + {kLeAudioLtvTypeSupportedOctetsPerCodecFrame, UINT32_TO_VEC_UINT8(octets_per_frame_range)}, - {kLeAudioCodecLC3TypeMaxCodecFramesPerSdu, + {kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu, UINT8_TO_VEC_UINT8(max_codec_frames_per_sdu)}, }), .metadata = std::vector(0)})); @@ -381,28 +412,28 @@ class PublishedAudioCapabilitiesBuilder { pac_records_.push_back( acs_ac_record({.codec_id = codec_id, .codec_spec_caps = LeAudioLtvMap({ - {kLeAudioCodecLC3TypeSamplingFreq, + {kLeAudioLtvTypeSupportedSamplingFrequencies, UINT16_TO_VEC_UINT8(capa_sampling_frequency)}, - {kLeAudioCodecLC3TypeFrameDuration, + {kLeAudioLtvTypeSupportedFrameDurations, UINT8_TO_VEC_UINT8(capa_frame_duration)}, - {kLeAudioCodecLC3TypeAudioChannelCounts, + {kLeAudioLtvTypeSupportedAudioChannelCounts, UINT8_TO_VEC_UINT8(audio_channel_counts)}, - {kLeAudioCodecLC3TypeOctetPerFrame, + {kLeAudioLtvTypeSupportedOctetsPerCodecFrame, UINT32_TO_VEC_UINT8(octets_per_frame_range)}, - {kLeAudioCodecLC3TypeMaxCodecFramesPerSdu, + {kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu, UINT8_TO_VEC_UINT8(codec_frames_per_sdu)}, }), .metadata = std::vector(0)})); } - void Add(const CodecCapabilitySetting& setting, - uint8_t audio_channel_counts) { + void Add(const CodecConfigSetting& setting, uint8_t audio_channel_counts) { if (setting.id != LeAudioCodecIdLc3) return; - const LeAudioLc3Config config = std::get(setting.config); - - Add(setting.id, *config.sampling_frequency, *config.frame_duration, - audio_channel_counts, *config.octets_per_codec_frame); + const LeAudioCoreCodecConfig core_config = + setting.params.GetAsCoreCodecConfig(); + Add(setting.id, *core_config.sampling_frequency, + *core_config.frame_duration, audio_channel_counts, + *core_config.octets_per_codec_frame); } void Reset() { pac_records_.clear(); } @@ -431,7 +462,8 @@ class LeAudioAseConfigurationTest : public Test { group_ = new LeAudioDeviceGroup(group_id_); bluetooth::manager::SetMockBtmInterface(&btm_interface_); controller::SetMockControllerInterface(&controller_interface_); - ::le_audio::AudioSetConfigurationProvider::Initialize(); + ::le_audio::AudioSetConfigurationProvider::Initialize( + ::le_audio::types::CodecLocation::ADSP); MockCsisClient::SetMockInstanceForTesting(&mock_csis_client_module_); ON_CALL(mock_csis_client_module_, Get()) .WillByDefault(Return(&mock_csis_client_module_)); @@ -511,10 +543,12 @@ class LeAudioAseConfigurationTest : public Test { device->ases_.push_back(ase); } - device->SetSupportedContexts(AudioContexts(kLeAudioContextAllTypes), - AudioContexts(kLeAudioContextAllTypes)); - device->SetAvailableContexts(AudioContexts(kLeAudioContextAllTypes), - AudioContexts(kLeAudioContextAllTypes)); + device->SetSupportedContexts( + {.sink = AudioContexts(kLeAudioContextAllTypes), + .source = AudioContexts(kLeAudioContextAllTypes)}); + device->SetAvailableContexts( + {.sink = AudioContexts(kLeAudioContextAllTypes), + .source = AudioContexts(kLeAudioContextAllTypes)}); device->snk_audio_locations_ = ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft | ::le_audio::codec_spec_conf::kLeAudioLocationFrontRight; @@ -541,12 +575,12 @@ class LeAudioAseConfigurationTest : public Test { for (ase* ase = data.device->GetFirstActiveAse(); ase; ase = data.device->GetNextActiveAse(ase)) { + auto core_config = ase->codec_config.GetAsCoreCodecConfig(); + if (ase->direction == kLeAudioDirectionSink) - active_channel_num_snk += - GetAudioChannelCounts(*ase->codec_config.audio_channel_allocation); + active_channel_num_snk += core_config.GetChannelCountPerIsoStream(); else - active_channel_num_src += - GetAudioChannelCounts(*ase->codec_config.audio_channel_allocation); + active_channel_num_src += core_config.GetChannelCountPerIsoStream(); } bool result = true; @@ -610,7 +644,8 @@ class LeAudioAseConfigurationTest : public Test { .source = AudioContexts(context_type)}; /* Stimulate update of available context map */ - group_->UpdateAudioContextTypeAvailability(AudioContexts(context_type)); + group_->UpdateAudioContextAvailability(); + ASSERT_EQ(success_expected, group_->Configure(context_type, group_audio_locations)); @@ -701,7 +736,9 @@ class LeAudioAseConfigurationTest : public Test { .source = AudioContexts(context_type)}; /* Stimulate update of available context map */ - group_->UpdateAudioContextTypeAvailability(AudioContexts(context_type)); + group_->UpdateAudioContextAvailability(); + group_->UpdateAudioSetConfigurationCache(context_type); + auto configuration_result = group_->Configure(context_type, group_audio_locations); @@ -721,6 +758,7 @@ class LeAudioAseConfigurationTest : public Test { if (matching_conf) num_of_matching_configurations++; } group_->Deactivate(); + TestAsesInactive(); } @@ -747,9 +785,10 @@ class LeAudioAseConfigurationTest : public Test { /* FIXME: Validate other codec parameters than LC3 if any */ ASSERT_EQ(ase.codec_id, LeAudioCodecIdLc3); if (ase.codec_id == LeAudioCodecIdLc3) { - ASSERT_EQ(ase.codec_config.sampling_frequency, sampling_frequency); - ASSERT_EQ(ase.codec_config.frame_duration, frame_duration); - ASSERT_EQ(ase.codec_config.octets_per_codec_frame, octets_per_frame); + auto core_config = ase.codec_config.GetAsCoreCodecConfig(); + ASSERT_EQ(core_config.sampling_frequency, sampling_frequency); + ASSERT_EQ(core_config.frame_duration, frame_duration); + ASSERT_EQ(core_config.octets_per_codec_frame, octets_per_frame); } } } @@ -802,8 +841,8 @@ class LeAudioAseConfigurationTest : public Test { PublishedAudioCapabilitiesBuilder pac_builder; pac_builder.Add(LeAudioCodecIdLc3, sampling_frequency, frame_duration, - kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel, octets_per_frame); for (auto& device : devices_) { /* For simplicity configure both PACs with the same @@ -821,8 +860,8 @@ class LeAudioAseConfigurationTest : public Test { } /* Stimulate update of available context map */ - group_->UpdateAudioContextTypeAvailability( - AudioContexts(context_type)); + group_->UpdateAudioContextAvailability(); + group_->UpdateAudioSetConfigurationCache(context_type); BidirectionalPair group_audio_locations = { .sink = AudioContexts(context_type), .source = AudioContexts(context_type)}; @@ -862,11 +901,226 @@ class LeAudioAseConfigurationTest : public Test { MockCsisClient mock_csis_client_module_; }; +/* Helper */ +const AudioSetConfiguration* getSpecificConfiguration( + const char* config_name, LeAudioContextType context) { + auto all_configurations = + ::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations( + context); + + if (all_configurations == nullptr) return nullptr; + if (all_configurations->end() == all_configurations->begin()) return nullptr; + + auto iter = + std::find_if(all_configurations->begin(), all_configurations->end(), + [config_name](auto& configuration) { + return configuration->name == config_name; + }); + if (iter == all_configurations->end()) return nullptr; + return *iter; +} + +TEST_F(LeAudioAseConfigurationTest, test_context_update) { + LeAudioDevice* left = AddTestDevice(1, 1); + LeAudioDevice* right = AddTestDevice(1, 1); + ASSERT_EQ(2, group_->Size()); + + /* Change locations */ + left->snk_audio_locations_ = + ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft; + left->src_audio_locations_ = + ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft; + right->snk_audio_locations_ = + ::le_audio::codec_spec_conf::kLeAudioLocationFrontRight; + right->src_audio_locations_ = + ::le_audio::codec_spec_conf::kLeAudioLocationFrontRight; + group_->ReloadAudioLocations(); + + /* Put the PACS */ + auto conversational_configuration = getSpecificConfiguration( + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + LeAudioContextType::CONVERSATIONAL); + auto media_configuration = getSpecificConfiguration( + "SingleDev_TwoChanStereoSnk_48_4_High_Reliability", + LeAudioContextType::MEDIA); + ASSERT_NE(nullptr, conversational_configuration); + ASSERT_NE(nullptr, media_configuration); + + /* Create PACs for conversational and media scenarios */ + PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder; + for (const auto& entry : (*conversational_configuration).confs) { + if (entry.direction == kLeAudioDirectionSink) { + snk_pac_builder.Add(entry.codec, 1); + } else { + src_pac_builder.Add(entry.codec, 1); + } + } + for (const auto& entry : (*media_configuration).confs) { + if (entry.direction == kLeAudioDirectionSink) { + snk_pac_builder.Add(entry.codec, 2); + } + } + left->snk_pacs_ = snk_pac_builder.Get(); + left->src_pacs_ = src_pac_builder.Get(); + right->snk_pacs_ = snk_pac_builder.Get(); + right->src_pacs_ = src_pac_builder.Get(); + + /* UNSPECIFIED must be supported, MEDIA is on the remote sink only... */ + auto remote_snk_supp_contexts = AudioContexts( + LeAudioContextType::MEDIA | LeAudioContextType::CONVERSATIONAL | + LeAudioContextType::SOUNDEFFECTS | LeAudioContextType::UNSPECIFIED); + auto remote_src_supp_contexts = AudioContexts( + LeAudioContextType::CONVERSATIONAL | LeAudioContextType::UNSPECIFIED); + + left->SetSupportedContexts( + {.sink = remote_snk_supp_contexts, .source = remote_src_supp_contexts}); + + auto right_bud_only_context = LeAudioContextType::ALERTS; + right->SetSupportedContexts( + {.sink = remote_snk_supp_contexts | right_bud_only_context, + .source = remote_src_supp_contexts | right_bud_only_context}); + + /* ...but UNSPECIFIED and SOUNDEFFECTS are unavailable */ + auto remote_snk_avail_contexts = AudioContexts( + LeAudioContextType::MEDIA | LeAudioContextType::CONVERSATIONAL); + auto remote_src_avail_contexts = + AudioContexts(LeAudioContextType::CONVERSATIONAL); + + left->SetAvailableContexts( + {.sink = remote_snk_avail_contexts, .source = remote_src_avail_contexts}); + ASSERT_EQ(left->GetAvailableContexts(), + remote_snk_avail_contexts | remote_src_avail_contexts); + + // Make an additional context available on the right earbud sink + right->SetAvailableContexts( + {.sink = remote_snk_avail_contexts | right_bud_only_context, + .source = remote_src_avail_contexts}); + ASSERT_EQ(right->GetAvailableContexts(), remote_snk_avail_contexts | + remote_src_avail_contexts | + right_bud_only_context); + + /* Now add the right earbud contexts - mind the extra context on that bud */ + group_->UpdateAudioContextAvailability(); + ASSERT_NE(group_->GetAvailableContexts(), left->GetAvailableContexts()); + ASSERT_EQ(group_->GetAvailableContexts(), + left->GetAvailableContexts() | right->GetAvailableContexts()); + + /* Since no device is being added or removed from the group this should not + * change the configuration set. + */ + group_->UpdateAudioContextAvailability(); + ASSERT_EQ(group_->GetAvailableContexts(), + left->GetAvailableContexts() | right->GetAvailableContexts()); + + /* MEDIA Available on remote sink direction only */ + ASSERT_TRUE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::MEDIA, + ::le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_FALSE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::MEDIA, + ::le_audio::types::kLeAudioDirectionSource) + .has_value()); + + /* CONVERSATIONAL Available on both directions */ + ASSERT_TRUE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::CONVERSATIONAL, + ::le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_TRUE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::CONVERSATIONAL, + ::le_audio::types::kLeAudioDirectionSource) + .has_value()); + + /* UNSPECIFIED Unavailable yet supported */ + ASSERT_TRUE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::UNSPECIFIED, + ::le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_FALSE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::UNSPECIFIED, + ::le_audio::types::kLeAudioDirectionSource) + .has_value()); + + /* SOUNDEFFECTS Unavailable yet supported on sink only */ + ASSERT_TRUE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::SOUNDEFFECTS, + ::le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_FALSE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::SOUNDEFFECTS, + ::le_audio::types::kLeAudioDirectionSource) + .has_value()); + + /* INSTRUCTIONAL Unavailable and not supported but scenario is supported */ + ASSERT_TRUE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::INSTRUCTIONAL, + ::le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_FALSE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::INSTRUCTIONAL, + ::le_audio::types::kLeAudioDirectionSource) + .has_value()); + + /* ALERTS on sink only */ + ASSERT_TRUE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::ALERTS, + ::le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_FALSE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::ALERTS, + ::le_audio::types::kLeAudioDirectionSource) + .has_value()); + + /* We should get the config for ALERTS for a single channel as only one earbud + * has it. */ + auto config = group_->GetCodecConfigurationByDirection( + LeAudioContextType::ALERTS, ::le_audio::types::kLeAudioDirectionSink); + ASSERT_TRUE(config.has_value()); + ASSERT_EQ(config->num_channels, + ::le_audio::LeAudioCodecConfiguration::kChannelNumberMono); + ASSERT_TRUE( + group_->IsAudioSetConfigurationAvailable(LeAudioContextType::ALERTS)); + + /* Turn off the ALERTS context */ + right->SetAvailableContexts( + {.sink = right->GetAvailableContexts( + ::le_audio::types::kLeAudioDirectionSink) & + ~AudioContexts(LeAudioContextType::ALERTS), + .source = right->GetAvailableContexts( + ::le_audio::types::kLeAudioDirectionSource)}); + + /* Right one was changed but the config exist, just not available */ + group_->UpdateAudioContextAvailability(); + ASSERT_EQ(group_->GetAvailableContexts(), + left->GetAvailableContexts() | right->GetAvailableContexts()); + ASSERT_FALSE(group_->GetAvailableContexts().test(LeAudioContextType::ALERTS)); + ASSERT_TRUE(group_ + ->GetCodecConfigurationByDirection( + LeAudioContextType::ALERTS, + ::le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_TRUE( + group_->IsAudioSetConfigurationAvailable(LeAudioContextType::ALERTS)); +} + TEST_F(LeAudioAseConfigurationTest, test_mono_speaker_ringtone) { LeAudioDevice* mono_speaker = AddTestDevice(1, 0); TestGroupAseConfigurationData data( - {mono_speaker, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 0}); + {mono_speaker, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 0}); /* mono, change location as by default it is stereo */ mono_speaker->snk_audio_locations_ = @@ -874,6 +1128,7 @@ TEST_F(LeAudioAseConfigurationTest, test_mono_speaker_ringtone) { group_->ReloadAudioLocations(); uint8_t direction_to_verify = kLeAudioDirectionSink; + TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1, direction_to_verify); } @@ -881,8 +1136,8 @@ TEST_F(LeAudioAseConfigurationTest, test_mono_speaker_ringtone) { TEST_F(LeAudioAseConfigurationTest, test_mono_speaker_conversational) { LeAudioDevice* mono_speaker = AddTestDevice(1, 0); TestGroupAseConfigurationData data({mono_speaker, - kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountNone, 1, 0}); + kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountNone, 1, 0}); /* mono, change location as by default it is stereo */ mono_speaker->snk_audio_locations_ = @@ -898,8 +1153,8 @@ TEST_F(LeAudioAseConfigurationTest, test_mono_speaker_conversational) { TEST_F(LeAudioAseConfigurationTest, test_mono_speaker_media) { LeAudioDevice* mono_speaker = AddTestDevice(1, 0); TestGroupAseConfigurationData data({mono_speaker, - kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountNone, 1, 0}); + kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountNone, 1, 0}); /* mono, change location as by default it is stereo */ mono_speaker->snk_audio_locations_ = @@ -914,19 +1169,19 @@ TEST_F(LeAudioAseConfigurationTest, test_mono_speaker_media) { TEST_F(LeAudioAseConfigurationTest, test_bounded_headphones_ringtone) { LeAudioDevice* bounded_headphones = AddTestDevice(2, 0); TestGroupAseConfigurationData data( - {bounded_headphones, kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 0}); + {bounded_headphones, kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, 0}); uint8_t direction_to_verify = kLeAudioDirectionSink; TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1, direction_to_verify); } -TEST_F(LeAudioAseConfigurationTest, test_bounded_headphones_conversional) { +TEST_F(LeAudioAseConfigurationTest, test_bounded_headphones_conversational) { LeAudioDevice* bounded_headphones = AddTestDevice(2, 0); TestGroupAseConfigurationData data({bounded_headphones, - kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountNone, 2, 0}); + kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountNone, 2, 0}); uint8_t direction_to_verify = kLeAudioDirectionSink; TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1, @@ -936,8 +1191,8 @@ TEST_F(LeAudioAseConfigurationTest, test_bounded_headphones_conversional) { TEST_F(LeAudioAseConfigurationTest, test_bounded_headphones_media) { LeAudioDevice* bounded_headphones = AddTestDevice(2, 0); TestGroupAseConfigurationData data({bounded_headphones, - kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountNone, 2, 0}); + kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountNone, 2, 0}); uint8_t direction_to_verify = kLeAudioDirectionSink; TestGroupAseConfiguration(LeAudioContextType::MEDIA, &data, 1, @@ -948,8 +1203,8 @@ TEST_F(LeAudioAseConfigurationTest, test_bounded_headset_ringtone_mono_microphone) { LeAudioDevice* bounded_headset = AddTestDevice(2, 1); TestGroupAseConfigurationData data( - {bounded_headset, kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 1}); + {bounded_headset, kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, 1}); /* mono, change location as by default it is stereo */ bounded_headset->src_audio_locations_ = @@ -962,22 +1217,21 @@ TEST_F(LeAudioAseConfigurationTest, TEST_F(LeAudioAseConfigurationTest, test_bounded_headset_ringtone_stereo_microphone) { LeAudioDevice* bounded_headset = AddTestDevice(2, 2); - TestGroupAseConfigurationData data( - {bounded_headset, - kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel, - 2, 2}); + TestGroupAseConfigurationData data({bounded_headset, + kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel, + 2, 2}); TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1); } -TEST_F(LeAudioAseConfigurationTest, test_bounded_headset_conversional) { +TEST_F(LeAudioAseConfigurationTest, test_bounded_headset_conversational) { LeAudioDevice* bounded_headset = AddTestDevice(2, 1); TestGroupAseConfigurationData data( - {bounded_headset, kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 1}); + {bounded_headset, kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, 1}); TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1); } @@ -985,8 +1239,8 @@ TEST_F(LeAudioAseConfigurationTest, test_bounded_headset_conversional) { TEST_F(LeAudioAseConfigurationTest, test_bounded_headset_media) { LeAudioDevice* bounded_headset = AddTestDevice(2, 1); TestGroupAseConfigurationData data( - {bounded_headset, kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 0}); + {bounded_headset, kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, 0}); uint8_t directions_to_verify = kLeAudioDirectionSink; TestGroupAseConfiguration(LeAudioContextType::MEDIA, &data, 1, @@ -997,10 +1251,10 @@ TEST_F(LeAudioAseConfigurationTest, test_earbuds_ringtone) { LeAudioDevice* left = AddTestDevice(1, 1); LeAudioDevice* right = AddTestDevice(1, 1); TestGroupAseConfigurationData data[] = { - {left, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 1}, - {right, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 1}}; + {left, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 1}, + {right, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 1}}; /* Change location as by default it is stereo */ left->snk_audio_locations_ = @@ -1016,14 +1270,14 @@ TEST_F(LeAudioAseConfigurationTest, test_earbuds_ringtone) { TestGroupAseConfiguration(LeAudioContextType::RINGTONE, data, 2); } -TEST_F(LeAudioAseConfigurationTest, test_earbuds_conversional) { +TEST_F(LeAudioAseConfigurationTest, test_earbuds_conversational) { LeAudioDevice* left = AddTestDevice(1, 1); LeAudioDevice* right = AddTestDevice(1, 1); TestGroupAseConfigurationData data[] = { - {left, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 1}, - {right, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 1}}; + {left, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 1}, + {right, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 1}}; /* Change location as by default it is stereo */ left->snk_audio_locations_ = @@ -1043,10 +1297,10 @@ TEST_F(LeAudioAseConfigurationTest, test_earbuds_media) { LeAudioDevice* left = AddTestDevice(1, 1); LeAudioDevice* right = AddTestDevice(1, 1); TestGroupAseConfigurationData data[] = { - {left, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 0}, - {right, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 0}}; + {left, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 0}, + {right, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 0}}; /* Change location as by default it is stereo */ left->snk_audio_locations_ = @@ -1067,8 +1321,8 @@ TEST_F(LeAudioAseConfigurationTest, test_earbuds_media) { TEST_F(LeAudioAseConfigurationTest, test_handsfree_mono_ringtone) { LeAudioDevice* handsfree = AddTestDevice(1, 1); TestGroupAseConfigurationData data( - {handsfree, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 1}); + {handsfree, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 1}); handsfree->snk_audio_locations_ = ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft; @@ -1081,20 +1335,20 @@ TEST_F(LeAudioAseConfigurationTest, test_handsfree_mono_ringtone) { TEST_F(LeAudioAseConfigurationTest, test_handsfree_stereo_ringtone) { LeAudioDevice* handsfree = AddTestDevice(1, 1); - TestGroupAseConfigurationData data( - {handsfree, - kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 1}); + TestGroupAseConfigurationData data({handsfree, + kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, + 1}); TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1); } -TEST_F(LeAudioAseConfigurationTest, test_handsfree_mono_conversional) { +TEST_F(LeAudioAseConfigurationTest, test_handsfree_mono_conversational) { LeAudioDevice* handsfree = AddTestDevice(1, 1); TestGroupAseConfigurationData data( - {handsfree, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 1}); + {handsfree, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 1}); handsfree->snk_audio_locations_ = ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft; @@ -1105,36 +1359,36 @@ TEST_F(LeAudioAseConfigurationTest, test_handsfree_mono_conversional) { TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1); } -TEST_F(LeAudioAseConfigurationTest, test_handsfree_stereo_conversional) { +TEST_F(LeAudioAseConfigurationTest, test_handsfree_stereo_conversational) { LeAudioDevice* handsfree = AddTestDevice(1, 1); - TestGroupAseConfigurationData data( - {handsfree, - kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 1}); + TestGroupAseConfigurationData data({handsfree, + kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, + 1}); TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1); } -TEST_F(LeAudioAseConfigurationTest, test_handsfree_full_cached_conversional) { +TEST_F(LeAudioAseConfigurationTest, test_handsfree_full_cached_conversational) { LeAudioDevice* handsfree = AddTestDevice(0, 0, 1, 1); - TestGroupAseConfigurationData data( - {handsfree, - kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 1}); + TestGroupAseConfigurationData data({handsfree, + kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, + 1}); TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1); } TEST_F(LeAudioAseConfigurationTest, - test_handsfree_partial_cached_conversional) { + test_handsfree_partial_cached_conversational) { LeAudioDevice* handsfree = AddTestDevice(1, 0, 0, 1); - TestGroupAseConfigurationData data( - {handsfree, - kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 1}); + TestGroupAseConfigurationData data({handsfree, + kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, + 1}); TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1); } @@ -1142,11 +1396,11 @@ TEST_F(LeAudioAseConfigurationTest, TEST_F(LeAudioAseConfigurationTest, test_handsfree_media_two_channels_allocation_stereo) { LeAudioDevice* handsfree = AddTestDevice(1, 1); - TestGroupAseConfigurationData data( - {handsfree, - kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 2, 0}); + TestGroupAseConfigurationData data({handsfree, + kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel, + kLeAudioCodecChannelCountSingleChannel, 2, + 0}); uint8_t directions_to_verify = kLeAudioDirectionSink; TestGroupAseConfiguration(LeAudioContextType::MEDIA, &data, 1, @@ -1159,7 +1413,7 @@ TEST_F(LeAudioAseConfigurationTest, test_lc3_config_ringtone) { TestLc3CodecConfig(LeAudioContextType::RINGTONE); } -TEST_F(LeAudioAseConfigurationTest, test_lc3_config_conversional) { +TEST_F(LeAudioAseConfigurationTest, test_lc3_config_conversational) { AddTestDevice(1, 1); TestLc3CodecConfig(LeAudioContextType::CONVERSATIONAL); @@ -1184,7 +1438,7 @@ TEST_F(LeAudioAseConfigurationTest, test_unsupported_codec) { pac_builder.Add(UnsupportedCodecId, GetSamplingFrequency(Lc3SettingId::LC3_16_2), GetFrameDuration(Lc3SettingId::LC3_16_2), - kLeAudioCodecLC3ChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, GetOctetsPerCodecFrame(Lc3SettingId::LC3_16_2)); device->snk_pacs_ = pac_builder.Get(); device->src_pacs_ = pac_builder.Get(); @@ -1212,10 +1466,10 @@ TEST_F(LeAudioAseConfigurationTest, test_reconnection_media) { group_->ReloadAudioLocations(); TestGroupAseConfigurationData data[] = { - {left, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 0}, - {right, kLeAudioCodecLC3ChannelCountSingleChannel, - kLeAudioCodecLC3ChannelCountSingleChannel, 1, 0}}; + {left, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 0}, + {right, kLeAudioCodecChannelCountSingleChannel, + kLeAudioCodecChannelCountSingleChannel, 1, 0}}; auto all_configurations = ::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations( @@ -1229,27 +1483,29 @@ TEST_F(LeAudioAseConfigurationTest, test_reconnection_media) { direction_to_verify); /* Generate CISes, symulate CIG creation and assign cis handles to ASEs.*/ - group_->CigGenerateCisIds(LeAudioContextType::MEDIA); + group_->cig.GenerateCisIds(LeAudioContextType::MEDIA); std::vector handles = {0x0012, 0x0013}; - group_->CigAssignCisConnHandles(handles); - group_->CigAssignCisIds(left); - group_->CigAssignCisIds(right); + group_->cig.AssignCisConnHandles(handles); + group_->cig.AssignCisIds(left); + group_->cig.AssignCisIds(right); TestActiveAses(); /* Left got disconnected */ left->DeactivateAllAses(); /* Unassign from the group*/ - group_->CigUnassignCis(left); + group_->cig.UnassignCis(left); TestAsesInactivated(left); /* Prepare reconfiguration */ uint8_t number_of_active_ases = 1; // Right one auto* ase = right->GetFirstActiveAseByDirection(kLeAudioDirectionSink); + + auto core_config = ase->codec_config.GetAsCoreCodecConfig(); BidirectionalPair group_audio_locations = { - .sink = *ase->codec_config.audio_channel_allocation, - .source = *ase->codec_config.audio_channel_allocation}; + .sink = *core_config.audio_channel_allocation, + .source = *core_config.audio_channel_allocation}; /* Get entry for the sink direction and use it to set configuration */ BidirectionalPair> ccid_lists = {{}, {}}; @@ -1274,8 +1530,8 @@ TEST_F(LeAudioAseConfigurationTest, test_reconnection_media) { /* Before device is rejoining, and group already exist, cis handles are * assigned before sending codec config */ - group_->CigAssignCisIds(left); - group_->CigAssignCisConnHandlesToAses(left); + group_->cig.AssignCisIds(left); + group_->AssignCisConnHandlesToAses(left); TestActiveAses(); } @@ -1307,23 +1563,10 @@ TEST_F(LeAudioAseConfigurationTest, test_reactivation_conversational) { ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft; group_->ReloadAudioLocations(); - auto all_configurations = - ::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations( - LeAudioContextType::CONVERSATIONAL); - ASSERT_NE(nullptr, all_configurations); - ASSERT_NE(all_configurations->end(), all_configurations->begin()); - - /* Pick TWS configuration for conversational */ - auto iter = std::find_if(all_configurations->begin(), - all_configurations->end(), [](auto& configuration) { - return configuration->name == - "SingleDev_OneChanStereoSnk_OneChanMonoSrc_" - "16_2_Low_Latency"; - }); - - ASSERT_NE(iter, all_configurations->end()); - - auto conversational_configuration = *iter; + auto conversational_configuration = getSpecificConfiguration( + "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency", + LeAudioContextType::CONVERSATIONAL); + ASSERT_NE(nullptr, conversational_configuration); // Build PACs for device PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder; @@ -1366,14 +1609,14 @@ TEST_F(LeAudioAseConfigurationTest, test_reactivation_conversational) { /* Generate CISes, simulate CIG creation and assign cis handles to ASEs.*/ std::vector handles = {0x0012, 0x0013}; - group_->CigGenerateCisIds(LeAudioContextType::CONVERSATIONAL); - group_->CigAssignCisConnHandles(handles); - group_->CigAssignCisIds(tws_headset); + group_->cig.GenerateCisIds(LeAudioContextType::CONVERSATIONAL); + group_->cig.AssignCisConnHandles(handles); + group_->cig.AssignCisIds(tws_headset); TestActiveAses(); /* Simulate stopping stream with caching codec configuration in ASEs */ - group_->CigUnassignCis(tws_headset); + group_->cig.UnassignCis(tws_headset); SetAsesToCachedConfiguration(tws_headset, LeAudioContextType::CONVERSATIONAL, kLeAudioDirectionSink | kLeAudioDirectionSource); @@ -1381,14 +1624,15 @@ TEST_F(LeAudioAseConfigurationTest, test_reactivation_conversational) { * the same CIS ID can be used. This would lead to only activating group * without reconfiguring CIG. */ - group_->Activate(LeAudioContextType::CONVERSATIONAL); + group_->Activate(LeAudioContextType::CONVERSATIONAL, audio_contexts, + ccid_lists); TestActiveAses(); /* Verify ASEs assigned CISes by counting assigned to bi-directional CISes */ int bi_dir_ases_count = std::count_if( tws_headset->ases_.begin(), tws_headset->ases_.end(), [=](auto& ase) { - return this->group_->cises_[ase.cis_id].type == + return this->group_->cig.cises[ase.cis_id].type == CisType::CIS_TYPE_BIDIRECTIONAL; }); @@ -1430,23 +1674,10 @@ TEST_F(LeAudioAseConfigurationTest, test_getting_cis_count) { right->snk_audio_locations_ = kChannelAllocationStereo; group_->ReloadAudioLocations(); - auto all_configurations = - ::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations( - LeAudioContextType::MEDIA); - ASSERT_NE(nullptr, all_configurations); - ASSERT_NE(all_configurations->end(), all_configurations->begin()); - - /* Pick configuration for media */ - auto iter = std::find_if(all_configurations->begin(), - all_configurations->end(), [](auto& configuration) { - return configuration->name == - "SingleDev_TwoChanStereoSnk_48_4_High_" - "Reliability"; - }); - - ASSERT_NE(iter, all_configurations->end()); - - auto media_configuration = *iter; + auto media_configuration = getSpecificConfiguration( + "SingleDev_TwoChanStereoSnk_48_4_High_Reliability", + LeAudioContextType::MEDIA); + ASSERT_NE(nullptr, media_configuration); // Build PACs for device PublishedAudioCapabilitiesBuilder snk_pac_builder; @@ -1485,13 +1716,14 @@ TEST_F(LeAudioAseConfigurationTest, test_getting_cis_count) { /* Generate CIS, simulate CIG creation and assign cis handles to ASEs.*/ std::vector handles = {0x0012}; - group_->CigGenerateCisIds(LeAudioContextType::MEDIA); + group_->cig.GenerateCisIds(LeAudioContextType::MEDIA); /* Verify prepared CISes by counting generated entries */ - int snk_cis_count = std::count_if( - this->group_->cises_.begin(), this->group_->cises_.end(), [](auto& cis) { - return cis.type == CisType::CIS_TYPE_UNIDIRECTIONAL_SINK; - }); + int snk_cis_count = + std::count_if(this->group_->cig.cises.begin(), + this->group_->cig.cises.end(), [](auto& cis) { + return cis.type == CisType::CIS_TYPE_UNIDIRECTIONAL_SINK; + }); /* Two CIS should be prepared for dual dev expected set */ ASSERT_EQ(snk_cis_count, 2); diff --git a/system/bta/le_audio/hal_verifier.cc b/system/bta/le_audio/hal_verifier.cc index 2367593a4559c84193e61b6b1924a94e063f26c5..96cc3ad93f4c698df9cc5275e38566790c1ea7ca 100644 --- a/system/bta/le_audio/hal_verifier.cc +++ b/system/bta/le_audio/hal_verifier.cc @@ -18,8 +18,10 @@ #include "bta_le_audio_api.h" bool LeAudioHalVerifier::SupportsLeAudio() { - return bluetooth::audio::HalVersionManager::GetHalVersion() >= - bluetooth::audio::BluetoothAudioHalVersion::VERSION_2_1; + return bluetooth::audio::HalVersionManager::GetHalTransport() == + bluetooth::audio::BluetoothAudioHalTransport::AIDL || + bluetooth::audio::HalVersionManager::GetHalVersion() >= + bluetooth::audio::BluetoothAudioHalVersion::VERSION_2_1; } bool LeAudioHalVerifier::SupportsLeAudioHardwareOffload() { @@ -31,3 +33,8 @@ bool LeAudioHalVerifier::SupportsLeAudioBroadcast() { return bluetooth::audio::HalVersionManager::GetHalTransport() == bluetooth::audio::BluetoothAudioHalTransport::AIDL; } + +bool LeAudioHalVerifier::SupportsStreamActiveApi() { + return bluetooth::audio::HalVersionManager::GetHalVersion() >= + bluetooth::audio::BluetoothAudioHalVersion::VERSION_AIDL_V3; +} diff --git a/system/bta/le_audio/hal_verifier_linux.cc b/system/bta/le_audio/hal_verifier_linux.cc index 3318291eb97bda18daa5c02395ccb0ee599a4800..480f2fbc1dbe248ae651e661a1e2c9ed62ed2f4e 100644 --- a/system/bta/le_audio/hal_verifier_linux.cc +++ b/system/bta/le_audio/hal_verifier_linux.cc @@ -19,3 +19,4 @@ bool LeAudioHalVerifier::SupportsLeAudio() { return false; } bool LeAudioHalVerifier::SupportsLeAudioHardwareOffload() { return false; } bool LeAudioHalVerifier::SupportsLeAudioBroadcast() { return false; } +bool LeAudioHalVerifier::SupportsStreamActiveApi() { return false; } diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc index 31be98c36df0912a818ddce8689d61875a9effdd..c4595201e49bf2957fcaf34165627c74da98d3cc 100644 --- a/system/bta/le_audio/le_audio_client_test.cc +++ b/system/bta/le_audio/le_audio_client_test.cc @@ -15,6 +15,8 @@ * limitations under the License. */ +#include +#include #include #include @@ -34,8 +36,10 @@ #include "gatt/database_builder.h" #include "hardware/bt_gatt_types.h" #include "internal_include/stack_config.h" +#include "le_audio_health_status.h" #include "le_audio_set_configuration_provider.h" #include "le_audio_types.h" +#include "mock_codec_manager.h" #include "mock_controller.h" #include "mock_csis_client.h" #include "mock_device_groups.h" @@ -44,6 +48,8 @@ #include "osi/include/log.h" #include "test/common/mock_functions.h" +#define TEST_BT com::android::bluetooth::flags + using testing::_; using testing::AnyNumber; using testing::AtLeast; @@ -67,18 +73,37 @@ using bluetooth::Uuid; using namespace bluetooth::le_audio; using le_audio::LeAudioCodecConfiguration; +using le_audio::LeAudioDeviceGroup; +using le_audio::LeAudioHealthStatus; using le_audio::LeAudioSinkAudioHalClient; using le_audio::LeAudioSourceAudioHalClient; +using le_audio::DsaMode; +using le_audio::DsaModes; +using le_audio::types::AudioContexts; +using le_audio::types::BidirectionalPair; +using le_audio::types::LeAudioContextType; + extern struct fake_osi_alarm_set_on_mloop fake_osi_alarm_set_on_mloop_; constexpr int max_num_of_ases = 5; +constexpr le_audio::types::LeAudioContextType + kLeAudioDefaultConfigurationContext = + le_audio::types::LeAudioContextType::UNSPECIFIED; static constexpr char kNotifyUpperLayerAboutGroupBeingInIdleDuringCall[] = "persist.bluetooth.leaudio.notify.idle.during.call"; const char* test_flags[] = { "INIT_logging_debug_enabled_for_all=true", "INIT_leaudio_targeted_announcement_reconnection_mode=true", + "INIT_leaudio_enable_health_based_actions=false", + nullptr, +}; + +const char* test_flags_with_health_status[] = { + "INIT_logging_debug_enabled_for_all=true", + "INIT_leaudio_targeted_announcement_reconnection_mode=true", + "INIT_leaudio_enable_health_based_actions=true", nullptr, }; @@ -90,12 +115,16 @@ extern "C" const char* __asan_default_options() { } std::atomic num_async_tasks; +static base::MessageLoop* message_loop_; bluetooth::common::MessageLoopThread message_loop_thread("test message loop"); bluetooth::common::MessageLoopThread* get_main_thread() { return &message_loop_thread; } + bt_status_t do_in_main_thread(const base::Location& from_here, base::OnceClosure task) { + if (!message_loop_) return BT_STATUS_FAIL; + // Wrap the task with task counter so we could later know if there are // any callbacks scheduled and we should wait before performing some actions if (!message_loop_thread.DoInThread( @@ -120,7 +149,6 @@ bt_status_t do_in_main_thread_delayed(const base::Location& from_here, return do_in_main_thread(from_here, std::move(task)); } -static base::MessageLoop* message_loop_; base::MessageLoop* get_main_message_loop() { return message_loop_; } static void init_message_loop_thread() { @@ -146,7 +174,6 @@ void invoke_switch_codec_cb(bool is_low_latency_buffer_size) {} void invoke_switch_buffer_size_cb(bool is_low_latency_buffer_size) {} const std::string kSmpOptions("mock smp options"); -bool get_trace_config_enabled(void) { return false; } bool get_pts_avrcp_test(void) { return false; } bool get_pts_secure_only_mode(void) { return false; } bool get_pts_conn_updates_disabled(void) { return false; } @@ -163,7 +190,6 @@ bool get_pts_le_audio_disable_ases_before_stopping(void) { return false; } config_t* get_all(void) { return nullptr; } stack_config_t mock_stack_config{ - .get_trace_config_enabled = get_trace_config_enabled, .get_pts_avrcp_test = get_pts_avrcp_test, .get_pts_secure_only_mode = get_pts_secure_only_mode, .get_pts_conn_updates_disabled = get_pts_conn_updates_disabled, @@ -243,13 +269,23 @@ class MockAudioHalClientCallbacks (std::vector local_input_capa_codec_conf, std::vector local_output_capa_codec_conf), (override)); + MOCK_METHOD((void), OnAudioGroupCurrentCodecConf, + (int group_id, btle_audio_codec_config_t input_codec_conf, + btle_audio_codec_config_t output_codec_conf), + (override)); MOCK_METHOD( - (void), OnAudioGroupCodecConf, - (int group_id, btle_audio_codec_config_t input_codec_conf, - btle_audio_codec_config_t output_codec_conf, + (void), OnAudioGroupSelectableCodecConf, + (int group_id, std::vector input_selectable_codec_conf, std::vector output_selectable_codec_conf), (override)); + MOCK_METHOD((void), OnHealthBasedRecommendationAction, + (const RawAddress& address, LeAudioHealthBasedAction action), + (override)); + MOCK_METHOD((void), OnHealthBasedGroupRecommendationAction, + (int group_id, LeAudioHealthBasedAction action), (override)); + MOCK_METHOD((void), OnUnicastMonitorModeStatus, + (uint8_t direction, UnicastMonitorModeStatus status)); }; class MockLeAudioSinkHalClient : public LeAudioSinkAudioHalClient { @@ -257,7 +293,8 @@ class MockLeAudioSinkHalClient : public LeAudioSinkAudioHalClient { MockLeAudioSinkHalClient() = default; MOCK_METHOD((bool), Start, (const LeAudioCodecConfiguration& codecConfiguration, - LeAudioSinkAudioHalClient::Callbacks* audioReceiver), + LeAudioSinkAudioHalClient::Callbacks* audioReceiver, + DsaModes dsa_modes), (override)); MOCK_METHOD((void), Stop, (), (override)); MOCK_METHOD((size_t), SendData, (uint8_t * data, uint16_t size), (override)); @@ -278,7 +315,8 @@ class MockLeAudioSourceHalClient : public LeAudioSourceAudioHalClient { MockLeAudioSourceHalClient() = default; MOCK_METHOD((bool), Start, (const LeAudioCodecConfiguration& codecConfiguration, - LeAudioSourceAudioHalClient::Callbacks* audioReceiver), + LeAudioSourceAudioHalClient::Callbacks* audioReceiver, + DsaModes dsa_modes), (override)); MOCK_METHOD((void), Stop, (), (override)); MOCK_METHOD((void), ConfirmStreamingRequest, (), (override)); @@ -296,15 +334,23 @@ class MockLeAudioSourceHalClient : public LeAudioSourceAudioHalClient { }; class UnicastTestNoInit : public Test { + public: + bool use_health_status = false; + protected: void SetUpMockAudioHal() { - bluetooth::common::InitFlags::Load(test_flags); + if (use_health_status) { + bluetooth::common::InitFlags::Load(test_flags_with_health_status); + } else { + bluetooth::common::InitFlags::Load(test_flags); + } /* Since these are returned by the Acquire() methods as unique_ptrs, we * will not free them manually. */ - owned_mock_le_audio_sink_hal_client_.reset(new NiceMock()); + owned_mock_le_audio_sink_hal_client_.reset( + new NiceMock()); mock_le_audio_sink_hal_client_ = (MockLeAudioSinkHalClient*)owned_mock_le_audio_sink_hal_client_.get(); @@ -315,10 +361,11 @@ class UnicastTestNoInit : public Test { owned_mock_le_audio_source_hal_client_.get(); is_audio_unicast_source_acquired = false; - ON_CALL(*mock_le_audio_source_hal_client_, Start(_, _)) + ON_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)) .WillByDefault( [this](const LeAudioCodecConfiguration& codec_configuration, - LeAudioSourceAudioHalClient::Callbacks* audioReceiver) { + LeAudioSourceAudioHalClient::Callbacks* audioReceiver, + DsaModes dsa_modes) { unicast_source_hal_cb_ = audioReceiver; return true; }); @@ -328,10 +375,11 @@ class UnicastTestNoInit : public Test { }); is_audio_unicast_sink_acquired = false; - ON_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)) + ON_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)) .WillByDefault( [this](const LeAudioCodecConfiguration& codec_configuration, - LeAudioSinkAudioHalClient::Callbacks* audioReceiver) { + LeAudioSinkAudioHalClient::Callbacks* audioReceiver, + DsaModes dsa_modes) { unicast_sink_hal_cb_ = audioReceiver; return true; }); @@ -378,6 +426,20 @@ class UnicastTestNoInit : public Test { first_device)); } + void InjectServiceChangedEvent(const RawAddress& address, uint16_t conn_id) { + tBTA_GATTC_SERVICE_CHANGED event_data = {.remote_bda = address, + .conn_id = conn_id}; + + do_in_main_thread(FROM_HERE, + base::BindOnce( + [](tBTA_GATTC_CBACK* gatt_callback, + tBTA_GATTC_SERVICE_CHANGED event_data) { + gatt_callback(BTA_GATTC_SRVC_CHG_EVT, + (tBTA_GATTC*)&event_data); + }, + base::Unretained(this->gatt_callback), event_data)); + } + void InjectConnectedEvent(const RawAddress& address, uint16_t conn_id, tGATT_STATUS status = GATT_SUCCESS) { ASSERT_NE(conn_id, GATT_INVALID_CONN_ID); @@ -404,6 +466,22 @@ class UnicastTestNoInit : public Test { base::Unretained(this->gatt_callback), event_data)); } + void InjectEncryptionChangedEvent(const RawAddress& address) { + tBTA_GATTC_ENC_CMPL_CB event_data = { + .client_if = gatt_if, + .remote_bda = address, + }; + + do_in_main_thread(FROM_HERE, + base::BindOnce( + [](tBTA_GATTC_CBACK* gatt_callback, + tBTA_GATTC_ENC_CMPL_CB event_data) { + gatt_callback(BTA_GATTC_ENC_CMPL_CB_EVT, + (tBTA_GATTC*)&event_data); + }, + base::Unretained(this->gatt_callback), event_data)); + } + void InjectDisconnectedEvent( uint16_t conn_id, tGATT_DISCONN_REASON reason = GATT_CONN_TERMINATE_LOCAL_HOST) { @@ -411,8 +489,8 @@ class UnicastTestNoInit : public Test { ASSERT_NE(peer_devices.count(conn_id), 0u); tBTA_GATTC_CLOSE event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, .client_if = gatt_if, .remote_bda = peer_devices.at(conn_id)->addr, .reason = reason, @@ -431,8 +509,8 @@ class UnicastTestNoInit : public Test { void InjectSearchCompleteEvent(uint16_t conn_id) { ASSERT_NE(conn_id, GATT_INVALID_CONN_ID); tBTA_GATTC_SEARCH_CMPL event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, }; do_in_main_thread(FROM_HERE, @@ -466,6 +544,32 @@ class UnicastTestNoInit : public Test { base::Unretained(this->gatt_callback), event_data)); } + void InjectContextTypes(const RawAddress& test_address, uint16_t conn_id, + uint16_t handle, AudioContexts sink_ctxs, + AudioContexts source_ctxs) { + std::vector contexts = { + (uint8_t)(sink_ctxs.value()), (uint8_t)(sink_ctxs.value() >> 8), + (uint8_t)(source_ctxs.value()), (uint8_t)(source_ctxs.value() >> 8)}; + + InjectNotificationEvent(test_address, conn_id, handle, contexts); + } + + void InjectSupportedContextTypes(const RawAddress& test_address, + uint16_t conn_id, AudioContexts sink_ctxs, + AudioContexts source_ctxs) { + /* 0x0077 pacs->supp_contexts_char + 1 */ + InjectContextTypes(test_address, conn_id, 0x0077, sink_ctxs, source_ctxs); + SyncOnMainLoop(); + } + + void InjectAvailableContextTypes(const RawAddress& test_address, + uint16_t conn_id, AudioContexts sink_ctxs, + AudioContexts source_ctxs) { + /* 0x0074 is pacs->avail_contexts_char + 1 */ + InjectContextTypes(test_address, conn_id, 0x0074, sink_ctxs, source_ctxs); + SyncOnMainLoop(); + } + void SetUpMockGatt() { // default action for GetCharacteristic function call ON_CALL(mock_gatt_interface_, GetCharacteristic(_, _)) @@ -522,10 +626,29 @@ class UnicastTestNoInit : public Test { // default action for WriteDescriptor function call ON_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)) - .WillByDefault(Invoke([](uint16_t conn_id, uint16_t handle, - std::vector value, - tGATT_WRITE_TYPE write_type, - GATT_WRITE_OP_CB cb, void* cb_data) -> void { + .WillByDefault(Invoke([this](uint16_t conn_id, uint16_t handle, + std::vector value, + tGATT_WRITE_TYPE write_type, + GATT_WRITE_OP_CB cb, + void* cb_data) -> void { + auto& ascs = peer_devices.at(conn_id)->ascs; + uint8_t idx; + + if (handle == ascs->ctp_ccc) { + value = UINT16_TO_VEC_UINT8(ascs->ctp_ccc_val); + } else { + for (idx = 0; idx < max_num_of_ases; idx++) { + if (handle == ascs->sink_ase_ccc[idx] + 1) { + value = UINT16_TO_VEC_UINT8(ascs->sink_ase_ccc_val[idx]); + break; + } + if (handle == ascs->source_ase_char[idx] + 1) { + value = UINT16_TO_VEC_UINT8(ascs->source_ase_ccc_val[idx]); + break; + } + } + } + if (cb) do_in_main_thread( FROM_HERE, @@ -546,8 +669,10 @@ class UnicastTestNoInit : public Test { })); ON_CALL(mock_gatt_interface_, Close(_)) - .WillByDefault(Invoke( - [&](uint16_t conn_id) { InjectDisconnectedEvent(conn_id); })); + .WillByDefault(Invoke([&](uint16_t conn_id) { + ASSERT_NE(conn_id, GATT_INVALID_CONN_ID); + InjectDisconnectedEvent(conn_id); + })); // default Characteristic read handler dispatches requests to service mocks ON_CALL(mock_gatt_queue_, ReadCharacteristic(_, _, _, _)) @@ -556,7 +681,8 @@ class UnicastTestNoInit : public Test { do_in_main_thread( FROM_HERE, base::BindOnce( - [](std::map>>* + [](std::map>>* peer_devices, uint16_t conn_id, uint16_t handle, GATT_READ_OP_CB cb, void* cb_data) -> void { @@ -669,7 +795,7 @@ class UnicastTestNoInit : public Test { } leAudioDevice = group->GetNextDevice(leAudioDevice); } - group->CigClearCis(); + group->ClearAllCises(); /* end */ if (!group->Configure(context_type, metadata_context_types, @@ -681,12 +807,13 @@ class UnicastTestNoInit : public Test { return false; } - group->CigGenerateCisIds(context_type); + group->cig.GenerateCisIds(context_type); for (LeAudioDevice* device = group->GetFirstDevice(); device != nullptr; device = group->GetNextDevice(device)) { for (auto& ase : device->ases_) { - ase.data_path_state = types::AudioStreamDataPathState::IDLE; + ase.cis_state = types::CisState::IDLE; + ase.data_path_state = types::DataPathState::IDLE; ase.active = false; ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; @@ -712,18 +839,20 @@ class UnicastTestNoInit : public Test { return true; }); - ON_CALL(mock_state_machine_, AttachToStream(_, _)) + ON_CALL(mock_state_machine_, AttachToStream(_, _, _)) .WillByDefault([](LeAudioDeviceGroup* group, - LeAudioDevice* leAudioDevice) { + LeAudioDevice* leAudioDevice, + types::BidirectionalPair> + ccids) { if (group->GetState() != types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { return false; } group->Configure(group->GetConfigurationContextType(), - group->GetMetadataContexts()); - if (!group->CigAssignCisIds(leAudioDevice)) return false; - group->CigAssignCisConnHandlesToAses(leAudioDevice); + group->GetMetadataContexts(), ccids); + if (!group->cig.AssignCisIds(leAudioDevice)) return false; + group->AssignCisConnHandlesToAses(leAudioDevice); auto* stream_conf = &group->stream_conf; @@ -732,28 +861,31 @@ class UnicastTestNoInit : public Test { // And also skip the ase establishment procedure which should // be tested as part of the state machine unit tests - ase.data_path_state = - types::AudioStreamDataPathState::DATA_PATH_ESTABLISHED; + ase.cis_state = types::CisState::CONNECTED; + ase.data_path_state = types::DataPathState::CONFIGURED; ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING; uint16_t cis_conn_hdl = ase.cis_conn_hdl; + auto core_config = ase.codec_config.GetAsCoreCodecConfig(); /* Copied from state_machine.cc ProcessHciNotifSetupIsoDataPath */ if (ase.direction == le_audio::types::kLeAudioDirectionSource) { - auto iter = std::find_if(stream_conf->source_streams.begin(), - stream_conf->source_streams.end(), - [cis_conn_hdl](auto& pair) { - return cis_conn_hdl == pair.first; - }); - - if (iter == stream_conf->source_streams.end()) { - stream_conf->source_streams.emplace_back( + auto iter = std::find_if( + stream_conf->stream_params.source.stream_locations.begin(), + stream_conf->stream_params.source.stream_locations.end(), + [cis_conn_hdl](auto& pair) { + return cis_conn_hdl == pair.first; + }); + + if (iter == + stream_conf->stream_params.source.stream_locations.end()) { + stream_conf->stream_params.source.stream_locations.emplace_back( std::make_pair(ase.cis_conn_hdl, - *ase.codec_config.audio_channel_allocation)); + *core_config.audio_channel_allocation)); - stream_conf->source_num_of_devices++; - stream_conf->source_num_of_channels += - ase.codec_config.channel_count; + stream_conf->stream_params.source.num_of_devices++; + stream_conf->stream_params.source.num_of_channels += + core_config.GetChannelCountPerIsoStream(); LOG_INFO( " Added Source Stream Configuration. CIS Connection " @@ -761,26 +893,27 @@ class UnicastTestNoInit : public Test { ", Audio Channel Allocation: %d" ", Source Number Of Devices: %d" ", Source Number Of Channels: %d", - +ase.cis_conn_hdl, - +(*ase.codec_config.audio_channel_allocation), - +stream_conf->source_num_of_devices, - +stream_conf->source_num_of_channels); + +ase.cis_conn_hdl, +(*core_config.audio_channel_allocation), + +stream_conf->stream_params.source.num_of_devices, + +stream_conf->stream_params.source.num_of_channels); } } else { - auto iter = std::find_if(stream_conf->sink_streams.begin(), - stream_conf->sink_streams.end(), - [cis_conn_hdl](auto& pair) { - return cis_conn_hdl == pair.first; - }); - - if (iter == stream_conf->sink_streams.end()) { - stream_conf->sink_streams.emplace_back( + auto iter = std::find_if( + stream_conf->stream_params.sink.stream_locations.begin(), + stream_conf->stream_params.sink.stream_locations.end(), + [cis_conn_hdl](auto& pair) { + return cis_conn_hdl == pair.first; + }); + + if (iter == + stream_conf->stream_params.sink.stream_locations.end()) { + stream_conf->stream_params.sink.stream_locations.emplace_back( std::make_pair(ase.cis_conn_hdl, - *ase.codec_config.audio_channel_allocation)); + *core_config.audio_channel_allocation)); - stream_conf->sink_num_of_devices++; - stream_conf->sink_num_of_channels += - ase.codec_config.channel_count; + stream_conf->stream_params.sink.num_of_devices++; + stream_conf->stream_params.sink.num_of_channels += + core_config.GetChannelCountPerIsoStream(); LOG_INFO( " Added Sink Stream Configuration. CIS Connection Handle: " @@ -788,10 +921,9 @@ class UnicastTestNoInit : public Test { ", Audio Channel Allocation: %d" ", Sink Number Of Devices: %d" ", Sink Number Of Channels: %d", - +ase.cis_conn_hdl, - +(*ase.codec_config.audio_channel_allocation), - +stream_conf->sink_num_of_devices, - +stream_conf->sink_num_of_channels); + +ase.cis_conn_hdl, +(*core_config.audio_channel_allocation), + +stream_conf->stream_params.sink.num_of_devices, + +stream_conf->stream_params.sink.num_of_channels); } } } @@ -822,7 +954,7 @@ class UnicastTestNoInit : public Test { } leAudioDevice = group->GetNextDevice(leAudioDevice); } - group->CigClearCis(); + group->ClearAllCises(); /* end */ if (!group->Configure(context_type, metadata_context_types, @@ -833,18 +965,18 @@ class UnicastTestNoInit : public Test { if (group->GetState() == types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { - group->CigGenerateCisIds(context_type); + group->cig.GenerateCisIds(context_type); std::vector conn_handles; - for (uint8_t i = 0; i < (uint8_t)(group->cises_.size()); i++) { + for (uint8_t i = 0; i < (uint8_t)(group->cig.cises.size()); i++) { conn_handles.push_back(iso_con_counter_++); } - group->CigAssignCisConnHandles(conn_handles); + group->cig.AssignCisConnHandles(conn_handles); for (LeAudioDevice* device = group->GetFirstActiveDevice(); device != nullptr; device = group->GetNextActiveDevice(device)) { - if (!group->CigAssignCisIds(device)) return false; - group->CigAssignCisConnHandlesToAses(device); + if (!group->cig.AssignCisIds(device)) return false; + group->AssignCisConnHandlesToAses(device); } } @@ -858,63 +990,79 @@ class UnicastTestNoInit : public Test { // And also skip the ase establishment procedure which should // be tested as part of the state machine unit tests - ase.data_path_state = - types::AudioStreamDataPathState::DATA_PATH_ESTABLISHED; + ase.cis_state = types::CisState::CONNECTED; + ase.data_path_state = types::DataPathState::CONFIGURED; ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING; + ase.pres_delay_min = 2500; + ase.pres_delay_max = 2500; + ase.preferred_pres_delay_min = 2500; + ase.preferred_pres_delay_max = 2500; + auto core_config = ase.codec_config.GetAsCoreCodecConfig(); uint16_t cis_conn_hdl = ase.cis_conn_hdl; /* Copied from state_machine.cc ProcessHciNotifSetupIsoDataPath */ if (ase.direction == le_audio::types::kLeAudioDirectionSource) { - auto iter = std::find_if(stream_conf->source_streams.begin(), - stream_conf->source_streams.end(), - [cis_conn_hdl](auto& pair) { - return cis_conn_hdl == pair.first; - }); - - if (iter == stream_conf->source_streams.end()) { - stream_conf->source_streams.emplace_back(std::make_pair( - ase.cis_conn_hdl, - *ase.codec_config.audio_channel_allocation)); - - stream_conf->source_num_of_devices++; - stream_conf->source_num_of_channels += - ase.codec_config.channel_count; - stream_conf->source_audio_channel_allocation |= - *ase.codec_config.audio_channel_allocation; - - if (stream_conf->source_sample_frequency_hz == 0) { - stream_conf->source_sample_frequency_hz = - ase.codec_config.GetSamplingFrequencyHz(); + auto iter = std::find_if( + stream_conf->stream_params.source.stream_locations.begin(), + stream_conf->stream_params.source.stream_locations.end(), + [cis_conn_hdl](auto& pair) { + return cis_conn_hdl == pair.first; + }); + + if (iter == + stream_conf->stream_params.source.stream_locations.end()) { + stream_conf->stream_params.source.stream_locations + .emplace_back(std::make_pair( + ase.cis_conn_hdl, + *core_config.audio_channel_allocation)); + + stream_conf->stream_params.source.num_of_devices++; + stream_conf->stream_params.source.num_of_channels += + core_config.GetChannelCountPerIsoStream(); + stream_conf->stream_params.source.audio_channel_allocation |= + *core_config.audio_channel_allocation; + + if (stream_conf->stream_params.source.sample_frequency_hz == + 0) { + stream_conf->stream_params.source.sample_frequency_hz = + core_config.GetSamplingFrequencyHz(); } else { - ASSERT_LOG(stream_conf->source_sample_frequency_hz == - ase.codec_config.GetSamplingFrequencyHz(), - "sample freq mismatch: %d!=%d", - stream_conf->source_sample_frequency_hz, - ase.codec_config.GetSamplingFrequencyHz()); + ASSERT_LOG( + stream_conf->stream_params.source.sample_frequency_hz == + core_config.GetSamplingFrequencyHz(), + "sample freq mismatch: %d!=%d", + stream_conf->stream_params.source.sample_frequency_hz, + core_config.GetSamplingFrequencyHz()); } - if (stream_conf->source_octets_per_codec_frame == 0) { - stream_conf->source_octets_per_codec_frame = - *ase.codec_config.octets_per_codec_frame; + if (stream_conf->stream_params.source + .octets_per_codec_frame == 0) { + stream_conf->stream_params.source.octets_per_codec_frame = + *core_config.octets_per_codec_frame; } else { - ASSERT_LOG(stream_conf->source_octets_per_codec_frame == - *ase.codec_config.octets_per_codec_frame, + ASSERT_LOG(stream_conf->stream_params.source + .octets_per_codec_frame == + *core_config.octets_per_codec_frame, "octets per frame mismatch: %d!=%d", - stream_conf->source_octets_per_codec_frame, - *ase.codec_config.octets_per_codec_frame); + stream_conf->stream_params.source + .octets_per_codec_frame, + *core_config.octets_per_codec_frame); } - if (stream_conf->source_codec_frames_blocks_per_sdu == 0) { - stream_conf->source_codec_frames_blocks_per_sdu = - *ase.codec_config.codec_frames_blocks_per_sdu; + if (stream_conf->stream_params.source + .codec_frames_blocks_per_sdu == 0) { + stream_conf->stream_params.source + .codec_frames_blocks_per_sdu = + *core_config.codec_frames_blocks_per_sdu; } else { - ASSERT_LOG( - stream_conf->source_codec_frames_blocks_per_sdu == - *ase.codec_config.codec_frames_blocks_per_sdu, - "codec_frames_blocks_per_sdu: %d!=%d", - stream_conf->source_codec_frames_blocks_per_sdu, - *ase.codec_config.codec_frames_blocks_per_sdu); + ASSERT_LOG(stream_conf->stream_params.source + .codec_frames_blocks_per_sdu == + *core_config.codec_frames_blocks_per_sdu, + "codec_frames_blocks_per_sdu: %d!=%d", + stream_conf->stream_params.source + .codec_frames_blocks_per_sdu, + *core_config.codec_frames_blocks_per_sdu); } LOG_INFO( @@ -924,61 +1072,71 @@ class UnicastTestNoInit : public Test { ", Source Number Of Devices: %d" ", Source Number Of Channels: %d", +ase.cis_conn_hdl, - +(*ase.codec_config.audio_channel_allocation), - +stream_conf->source_num_of_devices, - +stream_conf->source_num_of_channels); + +(*core_config.audio_channel_allocation), + +stream_conf->stream_params.source.num_of_devices, + +stream_conf->stream_params.source.num_of_channels); } } else { - auto iter = std::find_if(stream_conf->sink_streams.begin(), - stream_conf->sink_streams.end(), - [cis_conn_hdl](auto& pair) { - return cis_conn_hdl == pair.first; - }); - - if (iter == stream_conf->sink_streams.end()) { - stream_conf->sink_streams.emplace_back(std::make_pair( - ase.cis_conn_hdl, - *ase.codec_config.audio_channel_allocation)); - - stream_conf->sink_num_of_devices++; - stream_conf->sink_num_of_channels += - ase.codec_config.channel_count; - - stream_conf->sink_audio_channel_allocation |= - *ase.codec_config.audio_channel_allocation; - - if (stream_conf->sink_sample_frequency_hz == 0) { - stream_conf->sink_sample_frequency_hz = - ase.codec_config.GetSamplingFrequencyHz(); + auto iter = std::find_if( + stream_conf->stream_params.sink.stream_locations.begin(), + stream_conf->stream_params.sink.stream_locations.end(), + [cis_conn_hdl](auto& pair) { + return cis_conn_hdl == pair.first; + }); + + if (iter == + stream_conf->stream_params.sink.stream_locations.end()) { + stream_conf->stream_params.sink.stream_locations.emplace_back( + std::make_pair(ase.cis_conn_hdl, + *core_config.audio_channel_allocation)); + + stream_conf->stream_params.sink.num_of_devices++; + stream_conf->stream_params.sink.num_of_channels += + core_config.GetChannelCountPerIsoStream(); + + stream_conf->stream_params.sink.audio_channel_allocation |= + *core_config.audio_channel_allocation; + + if (stream_conf->stream_params.sink.sample_frequency_hz == + 0) { + stream_conf->stream_params.sink.sample_frequency_hz = + core_config.GetSamplingFrequencyHz(); } else { - ASSERT_LOG(stream_conf->sink_sample_frequency_hz == - ase.codec_config.GetSamplingFrequencyHz(), - "sample freq mismatch: %d!=%d", - stream_conf->sink_sample_frequency_hz, - ase.codec_config.GetSamplingFrequencyHz()); + ASSERT_LOG( + stream_conf->stream_params.sink.sample_frequency_hz == + core_config.GetSamplingFrequencyHz(), + "sample freq mismatch: %d!=%d", + stream_conf->stream_params.sink.sample_frequency_hz, + core_config.GetSamplingFrequencyHz()); } - if (stream_conf->sink_octets_per_codec_frame == 0) { - stream_conf->sink_octets_per_codec_frame = - *ase.codec_config.octets_per_codec_frame; + if (stream_conf->stream_params.sink.octets_per_codec_frame == + 0) { + stream_conf->stream_params.sink.octets_per_codec_frame = + *core_config.octets_per_codec_frame; } else { - ASSERT_LOG(stream_conf->sink_octets_per_codec_frame == - *ase.codec_config.octets_per_codec_frame, - "octets per frame mismatch: %d!=%d", - stream_conf->sink_octets_per_codec_frame, - *ase.codec_config.octets_per_codec_frame); + ASSERT_LOG( + stream_conf->stream_params.sink + .octets_per_codec_frame == + *core_config.octets_per_codec_frame, + "octets per frame mismatch: %d!=%d", + stream_conf->stream_params.sink.octets_per_codec_frame, + *core_config.octets_per_codec_frame); } - if (stream_conf->sink_codec_frames_blocks_per_sdu == 0) { - stream_conf->sink_codec_frames_blocks_per_sdu = - *ase.codec_config.codec_frames_blocks_per_sdu; + if (stream_conf->stream_params.sink + .codec_frames_blocks_per_sdu == 0) { + stream_conf->stream_params.sink + .codec_frames_blocks_per_sdu = + *core_config.codec_frames_blocks_per_sdu; } else { - ASSERT_LOG( - stream_conf->sink_codec_frames_blocks_per_sdu == - *ase.codec_config.codec_frames_blocks_per_sdu, - "codec_frames_blocks_per_sdu: %d!=%d", - stream_conf->sink_codec_frames_blocks_per_sdu, - *ase.codec_config.codec_frames_blocks_per_sdu); + ASSERT_LOG(stream_conf->stream_params.sink + .codec_frames_blocks_per_sdu == + *core_config.codec_frames_blocks_per_sdu, + "codec_frames_blocks_per_sdu: %d!=%d", + stream_conf->stream_params.sink + .codec_frames_blocks_per_sdu, + *core_config.codec_frames_blocks_per_sdu); } LOG_INFO( @@ -988,9 +1146,9 @@ class UnicastTestNoInit : public Test { ", Sink Number Of Devices: %d" ", Sink Number Of Channels: %d", +ase.cis_conn_hdl, - +(*ase.codec_config.audio_channel_allocation), - +stream_conf->sink_num_of_devices, - +stream_conf->sink_num_of_channels); + +(*core_config.audio_channel_allocation), + +stream_conf->stream_params.sink.num_of_devices, + +stream_conf->stream_params.sink.num_of_channels); } } } @@ -1003,7 +1161,9 @@ class UnicastTestNoInit : public Test { streaming_groups[group->group_id_] = group; /* Assume CIG is created */ - group->cig_state_ = le_audio::types::CigState::CREATED; + group->cig.SetState(le_audio::types::CigState::CREATED); + + if (block_streaming_state_callback) return true; do_in_main_thread( FROM_HERE, base::BindOnce( @@ -1024,8 +1184,7 @@ class UnicastTestNoInit : public Test { for (LeAudioDevice* device = group->GetFirstDevice(); device != nullptr; device = group->GetNextDevice(device)) { for (auto& ase : device->ases_) { - ase.data_path_state = - types::AudioStreamDataPathState::CIS_ESTABLISHED; + ase.cis_state = types::CisState::CONNECTED; ase.active = false; ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED; @@ -1045,137 +1204,142 @@ class UnicastTestNoInit : public Test { LeAudioDevice* leAudioDevice) { if (!group) return; auto* stream_conf = &group->stream_conf; - if (!stream_conf->sink_streams.empty() || - !stream_conf->source_streams.empty()) { - stream_conf->sink_streams.erase( - std::remove_if(stream_conf->sink_streams.begin(), - stream_conf->sink_streams.end(), - [leAudioDevice, &stream_conf](auto& pair) { - auto ases = leAudioDevice->GetAsesByCisConnHdl( - pair.first); - if (ases.sink) { - stream_conf->sink_num_of_devices--; - stream_conf->sink_num_of_channels -= - ases.sink->codec_config.channel_count; - - LOG_INFO( - ", Source Number Of Devices: %d" - ", Source Number Of Channels: %d", - +stream_conf->source_num_of_devices, - +stream_conf->source_num_of_channels); - } - return ases.sink; - }), - stream_conf->sink_streams.end()); - - stream_conf->source_streams.erase( - std::remove_if(stream_conf->source_streams.begin(), - stream_conf->source_streams.end(), - [leAudioDevice, &stream_conf](auto& pair) { - auto ases = leAudioDevice->GetAsesByCisConnHdl( - pair.first); - if (ases.source) { - stream_conf->source_num_of_devices--; - stream_conf->source_num_of_channels -= - ases.source->codec_config.channel_count; - - LOG_INFO( - ", Source Number Of Devices: %d" - ", Source Number Of Channels: %d", - +stream_conf->source_num_of_devices, - +stream_conf->source_num_of_channels); - } - return ases.source; - }), - stream_conf->source_streams.end()); + if (!stream_conf->stream_params.sink.stream_locations.empty() || + !stream_conf->stream_params.source.stream_locations.empty()) { + stream_conf->stream_params.sink.stream_locations.erase( + std::remove_if( + stream_conf->stream_params.sink.stream_locations.begin(), + stream_conf->stream_params.sink.stream_locations.end(), + [leAudioDevice, &stream_conf](auto& pair) { + auto ases = + leAudioDevice->GetAsesByCisConnHdl(pair.first); + if (ases.sink) { + stream_conf->stream_params.sink.num_of_devices--; + stream_conf->stream_params.sink.num_of_channels -= + ases.sink->codec_config.GetAsCoreCodecConfig() + .GetChannelCountPerIsoStream(); + + LOG_INFO( + ", Source Number Of Devices: %d" + ", Source Number Of Channels: %d", + +stream_conf->stream_params.source.num_of_devices, + +stream_conf->stream_params.source.num_of_channels); + } + return ases.sink; + }), + stream_conf->stream_params.sink.stream_locations.end()); + + stream_conf->stream_params.source.stream_locations.erase( + std::remove_if( + stream_conf->stream_params.source.stream_locations.begin(), + stream_conf->stream_params.source.stream_locations.end(), + [leAudioDevice, &stream_conf](auto& pair) { + auto ases = + leAudioDevice->GetAsesByCisConnHdl(pair.first); + if (ases.source) { + stream_conf->stream_params.source.num_of_devices--; + stream_conf->stream_params.source.num_of_channels -= + ases.source->codec_config.GetAsCoreCodecConfig() + .GetChannelCountPerIsoStream(); + + LOG_INFO( + ", Source Number Of Devices: %d" + ", Source Number Of Channels: %d", + +stream_conf->stream_params.source.num_of_devices, + +stream_conf->stream_params.source.num_of_channels); + } + return ases.source; + }), + stream_conf->stream_params.source.stream_locations.end()); } - group->CigUnassignCis(leAudioDevice); + group->cig.UnassignCis(leAudioDevice); if (group->IsEmpty()) { - group->cig_state_ = le_audio::types::CigState::NONE; + group->cig.SetState(le_audio::types::CigState::NONE); InjectCigRemoved(group->group_id_); } }); ON_CALL(mock_state_machine_, ProcessHciNotifCisDisconnected(_, _, _)) - .WillByDefault( - [](LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, - const bluetooth::hci::iso_manager::cis_disconnected_evt* event) { - if (!group) return; - auto ases_pair = - leAudioDevice->GetAsesByCisConnHdl(event->cis_conn_hdl); - if (ases_pair.sink) { - ases_pair.sink->data_path_state = - types::AudioStreamDataPathState::CIS_ASSIGNED; - ases_pair.sink->active = false; - } - if (ases_pair.source) { - ases_pair.source->active = false; - ases_pair.source->data_path_state = - types::AudioStreamDataPathState::CIS_ASSIGNED; - } - /* Invalidate stream configuration if needed */ - auto* stream_conf = &group->stream_conf; - if (!stream_conf->sink_streams.empty() || - !stream_conf->source_streams.empty()) { - stream_conf->sink_streams.erase( - std::remove_if( - stream_conf->sink_streams.begin(), - stream_conf->sink_streams.end(), - [leAudioDevice, &stream_conf](auto& pair) { - auto ases = - leAudioDevice->GetAsesByCisConnHdl(pair.first); + .WillByDefault([](LeAudioDeviceGroup* group, + LeAudioDevice* leAudioDevice, + const bluetooth::hci::iso_manager:: + cis_disconnected_evt* event) { + if (!group) return; + auto ases_pair = + leAudioDevice->GetAsesByCisConnHdl(event->cis_conn_hdl); + if (ases_pair.sink) { + ases_pair.sink->cis_state = types::CisState::ASSIGNED; + ases_pair.sink->active = false; + } + if (ases_pair.source) { + ases_pair.source->active = false; + ases_pair.source->cis_state = types::CisState::ASSIGNED; + } + /* Invalidate stream configuration if needed */ + auto* stream_conf = &group->stream_conf; + if (!stream_conf->stream_params.sink.stream_locations.empty() || + !stream_conf->stream_params.source.stream_locations.empty()) { + stream_conf->stream_params.sink.stream_locations.erase( + std::remove_if( + stream_conf->stream_params.sink.stream_locations.begin(), + stream_conf->stream_params.sink.stream_locations.end(), + [leAudioDevice, &stream_conf](auto& pair) { + auto ases = + leAudioDevice->GetAsesByCisConnHdl(pair.first); + + LOG_INFO( + ", sink ase to delete. Cis handle: %d" + ", ase pointer: %p", + +(int)(pair.first), +ases.sink); + if (ases.sink) { + stream_conf->stream_params.sink.num_of_devices--; + stream_conf->stream_params.sink.num_of_channels -= + ases.sink->codec_config.GetAsCoreCodecConfig() + .GetChannelCountPerIsoStream(); - LOG_INFO( - ", sink ase to delete. Cis handle: %d" - ", ase pointer: %p", - +(int)(pair.first), +ases.sink); - if (ases.sink) { - stream_conf->sink_num_of_devices--; - stream_conf->sink_num_of_channels -= - ases.sink->codec_config.channel_count; - - LOG_INFO( - " Sink Number Of Devices: %d" - ", Sink Number Of Channels: %d", - +stream_conf->sink_num_of_devices, - +stream_conf->sink_num_of_channels); - } - return ases.sink; - }), - stream_conf->sink_streams.end()); - - stream_conf->source_streams.erase( - std::remove_if( - stream_conf->source_streams.begin(), - stream_conf->source_streams.end(), - [leAudioDevice, &stream_conf](auto& pair) { - auto ases = - leAudioDevice->GetAsesByCisConnHdl(pair.first); + LOG_INFO( + " Sink Number Of Devices: %d" + ", Sink Number Of Channels: %d", + +stream_conf->stream_params.sink.num_of_devices, + +stream_conf->stream_params.sink.num_of_channels); + } + return ases.sink; + }), + stream_conf->stream_params.sink.stream_locations.end()); + + stream_conf->stream_params.source.stream_locations.erase( + std::remove_if( + stream_conf->stream_params.source.stream_locations.begin(), + stream_conf->stream_params.source.stream_locations.end(), + [leAudioDevice, &stream_conf](auto& pair) { + auto ases = + leAudioDevice->GetAsesByCisConnHdl(pair.first); + + LOG_INFO( + ", source to delete. Cis handle: %d" + ", ase pointer: %p", + +(int)(pair.first), ases.source); + if (ases.source) { + stream_conf->stream_params.source.num_of_devices--; + stream_conf->stream_params.source.num_of_channels -= + ases.source->codec_config.GetAsCoreCodecConfig() + .GetChannelCountPerIsoStream(); - LOG_INFO( - ", source to delete. Cis handle: %d" - ", ase pointer: %p", - +(int)(pair.first), ases.source); - if (ases.source) { - stream_conf->source_num_of_devices--; - stream_conf->source_num_of_channels -= - ases.source->codec_config.channel_count; - - LOG_INFO( - ", Source Number Of Devices: %d" - ", Source Number Of Channels: %d", - +stream_conf->source_num_of_devices, - +stream_conf->source_num_of_channels); - } - return ases.source; - }), - stream_conf->source_streams.end()); - } + LOG_INFO( + ", Source Number Of Devices: %d" + ", Source Number Of Channels: %d", + +stream_conf->stream_params.source.num_of_devices, + +stream_conf->stream_params.source.num_of_channels); + } + return ases.source; + }), + stream_conf->stream_params.source.stream_locations.end()); + } - group->CigUnassignCis(leAudioDevice); - }); + group->cig.UnassignCis(leAudioDevice); + }); ON_CALL(mock_state_machine_, StopStream(_)) .WillByDefault([this](LeAudioDeviceGroup* group) { @@ -1183,38 +1347,40 @@ class UnicastTestNoInit : public Test { device != nullptr; device = group->GetNextDevice(device)) { /* Invalidate stream configuration if needed */ auto* stream_conf = &group->stream_conf; - if (!stream_conf->sink_streams.empty() || - !stream_conf->source_streams.empty()) { - stream_conf->sink_streams.erase( - std::remove_if(stream_conf->sink_streams.begin(), - stream_conf->sink_streams.end(), - [device, &stream_conf](auto& pair) { - auto ases = - device->GetAsesByCisConnHdl(pair.first); - - LOG_INFO( - ", sink ase to delete. Cis handle: %d" - ", ase pointer: %p", - +(int)(pair.first), +ases.sink); - if (ases.sink) { - stream_conf->sink_num_of_devices--; - stream_conf->sink_num_of_channels -= - ases.sink->codec_config.channel_count; - - LOG_INFO( - " Sink Number Of Devices: %d" - ", Sink Number Of Channels: %d", - +stream_conf->sink_num_of_devices, - +stream_conf->sink_num_of_channels); - } - return ases.sink; - }), - stream_conf->sink_streams.end()); - - stream_conf->source_streams.erase( + if (!stream_conf->stream_params.sink.stream_locations.empty() || + !stream_conf->stream_params.source.stream_locations.empty()) { + stream_conf->stream_params.sink.stream_locations.erase( + std::remove_if( + stream_conf->stream_params.sink.stream_locations.begin(), + stream_conf->stream_params.sink.stream_locations.end(), + [device, &stream_conf](auto& pair) { + auto ases = device->GetAsesByCisConnHdl(pair.first); + + LOG_INFO( + ", sink ase to delete. Cis handle: %d" + ", ase pointer: %p", + +(int)(pair.first), +ases.sink); + if (ases.sink) { + stream_conf->stream_params.sink.num_of_devices--; + stream_conf->stream_params.sink.num_of_channels -= + ases.sink->codec_config.GetAsCoreCodecConfig() + .GetChannelCountPerIsoStream(); + + LOG_INFO( + " Sink Number Of Devices: %d" + ", Sink Number Of Channels: %d", + +stream_conf->stream_params.sink.num_of_devices, + +stream_conf->stream_params.sink.num_of_channels); + } + return ases.sink; + }), + stream_conf->stream_params.sink.stream_locations.end()); + + stream_conf->stream_params.source.stream_locations.erase( std::remove_if( - stream_conf->source_streams.begin(), - stream_conf->source_streams.end(), + stream_conf->stream_params.source.stream_locations + .begin(), + stream_conf->stream_params.source.stream_locations.end(), [device, &stream_conf](auto& pair) { auto ases = device->GetAsesByCisConnHdl(pair.first); @@ -1223,25 +1389,28 @@ class UnicastTestNoInit : public Test { ", ase pointer: %p", +(int)(pair.first), +ases.source); if (ases.source) { - stream_conf->source_num_of_devices--; - stream_conf->source_num_of_channels -= - ases.source->codec_config.channel_count; + stream_conf->stream_params.source.num_of_devices--; + stream_conf->stream_params.source.num_of_channels -= + ases.source->codec_config.GetAsCoreCodecConfig() + .GetChannelCountPerIsoStream(); LOG_INFO( ", Source Number Of Devices: %d" ", Source Number Of Channels: %d", - +stream_conf->source_num_of_devices, - +stream_conf->source_num_of_channels); + +stream_conf->stream_params.source.num_of_devices, + +stream_conf->stream_params.source + .num_of_channels); } return ases.source; }), - stream_conf->source_streams.end()); + stream_conf->stream_params.source.stream_locations.end()); } - group->CigUnassignCis(device); + group->cig.UnassignCis(device); for (auto& ase : device->ases_) { - ase.data_path_state = types::AudioStreamDataPathState::IDLE; + ase.cis_state = types::CisState::IDLE; + ase.data_path_state = types::DataPathState::IDLE; ase.active = false; ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; ase.cis_id = 0; @@ -1288,16 +1457,38 @@ class UnicastTestNoInit : public Test { ON_CALL(*mock_iso_manager_, RegisterCigCallbacks(_)) .WillByDefault(SaveArg<0>(&cig_callbacks_)); + // Required since we call OnAudioDataReady() + const auto codec_location = ::le_audio::types::CodecLocation::HOST; + SetUpMockAudioHal(); SetUpMockGroups(); SetUpMockGatt(); + SetUpMockCodecManager(codec_location); + + block_streaming_state_callback = false; + available_snk_context_types_ = 0xffff; + available_src_context_types_ = 0xffff; supported_snk_context_types_ = 0xffff; supported_src_context_types_ = 0xffff; - le_audio::AudioSetConfigurationProvider::Initialize(); + + le_audio::AudioSetConfigurationProvider::Initialize(codec_location); ASSERT_FALSE(LeAudioClient::IsLeAudioClientRunning()); } + void SetUpMockCodecManager(types::CodecLocation location) { + codec_manager_ = le_audio::CodecManager::GetInstance(); + ASSERT_NE(codec_manager_, nullptr); + std::vector + mock_offloading_preference(0); + codec_manager_->Start(mock_offloading_preference); + mock_codec_manager_ = MockCodecManager::GetInstance(); + ASSERT_NE((void*)mock_codec_manager_, (void*)codec_manager_); + ASSERT_NE(mock_codec_manager_, nullptr); + ON_CALL(*mock_codec_manager_, GetCodecLocation()) + .WillByDefault(Return(location)); + } + void TearDown() override { if (is_audio_unicast_source_acquired) { if (unicast_source_hal_cb_ != nullptr) { @@ -1324,7 +1515,7 @@ class UnicastTestNoInit : public Test { if (LeAudioClient::IsLeAudioClientRunning()) { EXPECT_CALL(mock_gatt_interface_, AppDeregister(gatt_if)).Times(1); - LeAudioClient::Cleanup(base::DoNothing()); + LeAudioClient::Cleanup(); ASSERT_FALSE(LeAudioClient::IsLeAudioClientRunning()); } @@ -1422,10 +1613,13 @@ class UnicastTestNoInit : public Test { uint16_t start = 0; uint16_t sink_ase_char[max_num_of_ases] = {0}; uint16_t sink_ase_ccc[max_num_of_ases] = {0}; + uint16_t sink_ase_ccc_val[max_num_of_ases] = {0}; uint16_t source_ase_char[max_num_of_ases] = {0}; uint16_t source_ase_ccc[max_num_of_ases] = {0}; + uint16_t source_ase_ccc_val[max_num_of_ases] = {0}; uint16_t ctp_char = 0; uint16_t ctp_ccc = 0; + uint16_t ctp_ccc_val = 0; uint16_t end = 0; MOCK_METHOD((void), OnReadCharacteristic, @@ -1438,11 +1632,12 @@ class UnicastTestNoInit : public Test { (override)); }; - MockDeviceWrapper(RawAddress addr, const std::list& services, - std::unique_ptr> csis, - std::unique_ptr> cas, - std::unique_ptr> ascs, - std::unique_ptr> pacs) + MockDeviceWrapper( + RawAddress addr, const std::list& services, + std::unique_ptr> csis, + std::unique_ptr> cas, + std::unique_ptr> ascs, + std::unique_ptr> pacs) : addr(addr) { this->services = services; this->csis = std::move(csis); @@ -1476,32 +1671,102 @@ class UnicastTestNoInit : public Test { ; } - void ConnectLeAudio(const RawAddress& address, bool isEncrypted = true) { + void ConnectLeAudio(const RawAddress& address, bool isEncrypted = true, + bool expect_connected_event = true) { // by default indicate link as encrypted ON_CALL(mock_btm_interface_, BTM_IsEncrypted(address, _)) .WillByDefault(DoAll(Return(isEncrypted))); + ON_CALL(mock_btm_interface_, IsLinkKeyKnown(address, _)) + .WillByDefault(DoAll(Return(true))); + EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, _)) .Times(1); + /* If connected event is not expected to arrive, don't test those two below + */ + if (expect_connected_event) { + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, address, false)); + EXPECT_CALL( + mock_gatt_interface_, + Open(gatt_if, address, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + } + do_in_main_thread( - FROM_HERE, base::Bind(&LeAudioClient::Connect, - base::Unretained(LeAudioClient::Get()), address)); + FROM_HERE, + base::BindOnce(&LeAudioClient::Connect, + base::Unretained(LeAudioClient::Get()), address)); SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_btm_interface_); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); } - void DisconnectLeAudio(const RawAddress& address, uint16_t conn_id) { - SyncOnMainLoop(); + void DisconnectLeAudioWithGattClose( + const RawAddress& address, uint16_t conn_id, + tGATT_DISCONN_REASON reason = GATT_CONN_TERMINATE_LOCAL_HOST) { + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, address)) + .Times(1); + + // For test purpose use the acl handle same as conn_id + ON_CALL(mock_btm_interface_, GetHCIConnHandle(address, _)) + .WillByDefault([conn_id](RawAddress const& bd_addr, + tBT_TRANSPORT transport) { return conn_id; }); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(conn_id, _)) + .Times(0); EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1); + + do_in_main_thread( + FROM_HERE, base::Bind(&LeAudioClient::Disconnect, + base::Unretained(LeAudioClient::Get()), address)); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_btm_interface_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + } + + void DisconnectLeAudioWithAclClose( + const RawAddress& address, uint16_t conn_id, + tGATT_DISCONN_REASON reason = GATT_CONN_TERMINATE_LOCAL_HOST) { EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::DISCONNECTED, address)) .Times(1); + + // For test purpose use the acl handle same as conn_id + ON_CALL(mock_btm_interface_, GetHCIConnHandle(address, _)) + .WillByDefault([conn_id](RawAddress const& bd_addr, + tBT_TRANSPORT transport) { return conn_id; }); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(conn_id, _)) + .WillOnce([this, &reason](uint16_t handle, tHCI_STATUS rs) { + InjectDisconnectedEvent(handle, reason); + }); + EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(0); + do_in_main_thread( FROM_HERE, base::Bind(&LeAudioClient::Disconnect, base::Unretained(LeAudioClient::Get()), address)); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_btm_interface_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + } + + void DisconnectLeAudioNoDisconnectedEvtExpected(const RawAddress& address, + uint16_t conn_id) { + EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(0); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(conn_id, _)) + .Times(1); + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::Disconnect, + base::Unretained(LeAudioClient::Get()), address)); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_btm_interface_); } void ConnectCsisDevice(const RawAddress& addr, uint16_t conn_id, @@ -1531,10 +1796,10 @@ class UnicastTestNoInit : public Test { if (connect_through_csis) { // Add it the way CSIS would do: add to group and then connect - do_in_main_thread( - FROM_HERE, - base::Bind(&LeAudioClient::GroupAddNode, - base::Unretained(LeAudioClient::Get()), group_id, addr)); + do_in_main_thread(FROM_HERE, + base::BindOnce(&LeAudioClient::GroupAddNode, + base::Unretained(LeAudioClient::Get()), + group_id, addr)); ConnectLeAudio(addr); } else { // The usual connect @@ -1563,15 +1828,33 @@ class UnicastTestNoInit : public Test { ConnectLeAudio(addr); } - void UpdateMetadata(audio_usage_t usage, audio_content_type_t content_type, - bool reconfigure_existing_stream = false) { - std::vector source_metadata = { - {{AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}, - {AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}}}; + void UpdateLocalSourceMetadata( + std::vector tracks, + bool reconfigure_existing_stream = false) { + std::vector tracks_vec; + tracks_vec.reserve(tracks.size()); + for (const auto& track : tracks) { + playback_track_metadata_v7 desc_track = { + .base = + { + .usage = static_cast(track.usage), + .content_type = + static_cast(track.content_type), + .gain = track.gain, + }, + }; + if (test_tags_ptr_) { + memcpy(desc_track.tags, test_tags_ptr_, strlen(test_tags_ptr_)); + } + + tracks_vec.push_back(desc_track); + } - source_metadata[0].usage = usage; - source_metadata[0].content_type = content_type; + const source_metadata_v7_t source_metadata = { + .track_count = tracks_vec.size(), .tracks = tracks_vec.data()}; + ASSERT_NE(nullptr, mock_le_audio_source_hal_client_); + /* Local Source may reconfigure once the metadata is updated */ if (reconfigure_existing_stream) { Expectation reconfigure = EXPECT_CALL(*mock_le_audio_source_hal_client_, SuspendedForReconfiguration()) @@ -1590,22 +1873,73 @@ class UnicastTestNoInit : public Test { } ASSERT_NE(unicast_source_hal_cb_, nullptr); - unicast_source_hal_cb_->OnAudioMetadataUpdate(source_metadata); + unicast_source_hal_cb_->OnAudioMetadataUpdate(source_metadata, + DsaMode::DISABLED); + } + + void UpdateLocalSourceMetadata(audio_usage_t usage, + audio_content_type_t content_type, + bool reconfigure_existing_stream = false) { + std::vector tracks = { + {{AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}, + {AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}}}; + + tracks[0].usage = usage; + tracks[0].content_type = content_type; + UpdateLocalSourceMetadata(tracks, reconfigure_existing_stream); } - void UpdateSourceMetadata(audio_source_t audio_source) { - std::vector sink_metadata = { + void UpdateLocalSinkMetadata(audio_source_t audio_source) { + std::vector tracks = { {{AUDIO_SOURCE_INVALID, 0.5, AUDIO_DEVICE_NONE, "00:11:22:33:44:55"}, {AUDIO_SOURCE_MIC, 0.7, AUDIO_DEVICE_OUT_BLE_HEADSET, "AA:BB:CC:DD:EE:FF"}}}; - sink_metadata[1].source = audio_source; + tracks[1].source = audio_source; + + std::vector tracks_vec; + tracks_vec.reserve(tracks.size()); + for (const auto& track : tracks) { + record_track_metadata_v7 desc_track = { + .base = + { + .source = static_cast(track.source), + .gain = track.gain, + .dest_device = + static_cast(track.dest_device), + }, + }; + + strcpy(desc_track.base.dest_device_address, track.dest_device_address); + tracks_vec.push_back(desc_track); + } + + const sink_metadata_v7_t sink_metadata = {.track_count = tracks_vec.size(), + .tracks = tracks_vec.data()}; + + ASSERT_NE(nullptr, unicast_sink_hal_cb_); unicast_sink_hal_cb_->OnAudioMetadataUpdate(sink_metadata); } - void SinkAudioResume(void) { - EXPECT_CALL(*mock_le_audio_source_hal_client_, ConfirmStreamingRequest()) - .Times(1); + void LocalAudioSourceSuspend(void) { + ASSERT_NE(unicast_source_hal_cb_, nullptr); + unicast_source_hal_cb_->OnAudioSuspend(); + SyncOnMainLoop(); + } + + void LocalAudioSourceResume(bool expected_confirmation = true, + bool expected_cancel = false) { + ASSERT_NE(nullptr, mock_le_audio_source_hal_client_); + if (expected_confirmation) { + EXPECT_CALL(*mock_le_audio_source_hal_client_, ConfirmStreamingRequest()) + .Times(1); + } + + if (expected_cancel) { + EXPECT_CALL(*mock_le_audio_source_hal_client_, CancelStreamingRequest()) + .Times(1); + } + do_in_main_thread(FROM_HERE, base::BindOnce( [](LeAudioSourceAudioHalClient::Callbacks* cb) { @@ -1617,21 +1951,41 @@ class UnicastTestNoInit : public Test { Mock::VerifyAndClearExpectations(&*mock_le_audio_source_hal_client_); } + void LocalAudioSinkSuspend(void) { + ASSERT_NE(unicast_sink_hal_cb_, nullptr); + unicast_sink_hal_cb_->OnAudioSuspend(); + SyncOnMainLoop(); + } + + void LocalAudioSinkResume(void) { + ASSERT_NE(unicast_sink_hal_cb_, nullptr); + do_in_main_thread(FROM_HERE, + base::BindOnce( + [](LeAudioSinkAudioHalClient::Callbacks* cb) { + cb->OnAudioResume(); + }, + unicast_sink_hal_cb_)); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&*mock_le_audio_sink_hal_client_); + } + void StartStreaming(audio_usage_t usage, audio_content_type_t content_type, int group_id, audio_source_t audio_source = AUDIO_SOURCE_INVALID, - bool reconfigure_existing_stream = false) { + bool reconfigure_existing_stream = false, + bool expected_resume_confirmation = true) { ASSERT_NE(unicast_source_hal_cb_, nullptr); - UpdateMetadata(usage, content_type, reconfigure_existing_stream); + UpdateLocalSourceMetadata(usage, content_type, reconfigure_existing_stream); if (audio_source != AUDIO_SOURCE_INVALID) { - UpdateSourceMetadata(audio_source); + UpdateLocalSinkMetadata(audio_source); } - /* Stream has been automatically restarted on UpdateMetadata */ + /* Stream has been automatically restarted on UpdateLocalSourceMetadata */ if (reconfigure_existing_stream) return; - SinkAudioResume(); + LocalAudioSourceResume(expected_resume_confirmation); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_state_machine_); @@ -1645,6 +1999,7 @@ class UnicastTestNoInit : public Test { }, unicast_sink_hal_cb_)); } + SyncOnMainLoop(); } void StopStreaming(int group_id, bool suspend_source = false) { @@ -1654,8 +2009,6 @@ class UnicastTestNoInit : public Test { * might have different state that it is in the le_audio code - as tearing * down CISes might take some time */ - std::promise do_suspend_sink_promise; - auto do_suspend_sink_future = do_suspend_sink_promise.get_future(); /* It's enough to call only one resume even if it'll be bi-directional * streaming. First suspend will trigger GroupStop. * @@ -1663,24 +2016,21 @@ class UnicastTestNoInit : public Test { * If there will be such test oriented scenario, such resume choose logic * should be applied. */ - unicast_source_hal_cb_->OnAudioSuspend(std::move(do_suspend_sink_promise)); - do_suspend_sink_future.wait(); + unicast_source_hal_cb_->OnAudioSuspend(); if (suspend_source) { ASSERT_NE(unicast_sink_hal_cb_, nullptr); - std::promise do_suspend_source_promise; - auto do_suspend_source_future = do_suspend_source_promise.get_future(); - unicast_sink_hal_cb_->OnAudioSuspend( - std::move(do_suspend_source_promise)); - do_suspend_source_future.wait(); + unicast_sink_hal_cb_->OnAudioSuspend(); } + SyncOnMainLoop(); } - void set_sample_database(uint16_t conn_id, RawAddress addr, - std::unique_ptr> csis, - std::unique_ptr> cas, - std::unique_ptr> ascs, - std::unique_ptr> pacs) { + void set_sample_database( + uint16_t conn_id, RawAddress addr, + std::unique_ptr> csis, + std::unique_ptr> cas, + std::unique_ptr> ascs, + std::unique_ptr> pacs) { gatt::DatabaseBuilder bob; /* Generic Access Service */ @@ -1865,7 +2215,8 @@ class UnicastTestNoInit : public Test { uint32_t source_audio_allocation, uint8_t sink_channel_cnt = 0x03, uint8_t source_channel_cnt = 0x03, uint16_t sample_freq_mask = 0x0004, bool add_csis = true, bool add_cas = true, bool add_pacs = true, - int add_ascs_cnt = 1, uint8_t set_size = 2, uint8_t rank = 1) { + int add_ascs_cnt = 1, uint8_t set_size = 2, uint8_t rank = 1, + GattStatus gatt_status = GATT_SUCCESS) { auto csis = std::make_unique>(); if (add_csis) { // attribute handles @@ -1963,207 +2314,235 @@ class UnicastTestNoInit : public Test { // Set pacs default read values ON_CALL(*peer_devices.at(conn_id)->pacs, OnReadCharacteristic(_, _, _)) - .WillByDefault( - [this, conn_id, snk_allocation, src_allocation, sample_freq, - sink_channel_cnt, source_channel_cnt]( - uint16_t handle, GATT_READ_OP_CB cb, void* cb_data) { - auto& pacs = peer_devices.at(conn_id)->pacs; - std::vector value; - if (handle == pacs->sink_pac_char + 1) { - value = { - // Num records - 0x02, - // Codec_ID - 0x06, - 0x00, - 0x00, - 0x00, - 0x00, - // Codec Spec. Caps. Len - 0x10, - 0x03, /* sample freq */ - 0x01, - sample_freq[0], - sample_freq[1], - 0x02, - 0x02, /* frame duration */ - 0x03, - 0x02, /* channel count */ - 0x03, - sink_channel_cnt, - 0x05, - 0x04, - 0x1E, - 0x00, - 0x78, - 0x00, - // Metadata Length - 0x00, - // Codec_ID - 0x06, - 0x00, - 0x00, - 0x00, - 0x00, - // Codec Spec. Caps. Len - 0x10, - 0x03, /* sample freq */ - 0x01, - 0x80, /* 48kHz */ - 0x00, - 0x02, /* frame duration */ - 0x02, - 0x03, - 0x02, /* channel count */ - 0x03, - sink_channel_cnt, - 0x05, /* octects per frame */ - 0x04, - 0x78, - 0x00, - 0x78, - 0x00, - // Metadata Length - 0x00, - }; - } else if (handle == pacs->sink_audio_loc_char + 1) { - value = { - // Audio Locations - snk_allocation[0], - snk_allocation[1], - snk_allocation[2], - snk_allocation[3], - }; - } else if (handle == pacs->source_pac_char + 1) { - value = { - // Num records - 0x02, - // Codec_ID - 0x06, - 0x00, - 0x00, - 0x00, - 0x00, - // Codec Spec. Caps. Len - 0x10, - 0x03, - 0x01, - sample_freq[0], - sample_freq[1], - 0x02, - 0x02, - 0x03, - 0x02, - 0x03, - source_channel_cnt, - 0x05, - 0x04, - 0x1E, - 0x00, - 0x78, - 0x00, - // Metadata Length - 0x00, - // Codec_ID - 0x06, - 0x00, - 0x00, - 0x00, - 0x00, - // Codec Spec. Caps. Len - 0x10, - 0x03, - 0x01, - 0x24, - 0x00, - 0x02, - 0x02, - 0x03, - 0x02, - 0x03, - source_channel_cnt, - 0x05, - 0x04, - 0x1E, - 0x00, - 0x50, - 0x00, - // Metadata Length - 0x00, - }; - } else if (handle == pacs->source_audio_loc_char + 1) { - value = { - // Audio Locations - src_allocation[0], - src_allocation[1], - src_allocation[2], - src_allocation[3], - }; - } else if (handle == pacs->avail_contexts_char + 1) { - value = { - // Sink Avail Contexts - (uint8_t)(supported_snk_context_types_), - (uint8_t)(supported_snk_context_types_ >> 8), - // Source Avail Contexts - (uint8_t)(supported_src_context_types_), - (uint8_t)(supported_src_context_types_ >> 8), - }; - } else if (handle == pacs->supp_contexts_char + 1) { - value = { - // Sink Avail Contexts - (uint8_t)(supported_snk_context_types_), - (uint8_t)(supported_snk_context_types_ >> 8), - // Source Avail Contexts - (uint8_t)(supported_src_context_types_), - (uint8_t)(supported_src_context_types_ >> 8), - }; - } - cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), - cb_data); - }); + .WillByDefault([this, conn_id, snk_allocation, src_allocation, + sample_freq, sink_channel_cnt, source_channel_cnt, + gatt_status](uint16_t handle, GATT_READ_OP_CB cb, + void* cb_data) { + auto& pacs = peer_devices.at(conn_id)->pacs; + std::vector value; + if (gatt_status == GATT_SUCCESS) { + if (handle == pacs->sink_pac_char + 1) { + value = { + // Num records + 0x02, + // Codec_ID + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + // Codec Spec. Caps. Len + 0x10, + 0x03, /* sample freq */ + 0x01, + sample_freq[0], + sample_freq[1], + 0x02, + 0x02, /* frame duration */ + 0x03, + 0x02, /* channel count */ + 0x03, + sink_channel_cnt, + 0x05, + 0x04, + 0x1E, + 0x00, + 0x78, + 0x00, + // Metadata Length + 0x00, + // Codec_ID + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + // Codec Spec. Caps. Len + 0x10, + 0x03, /* sample freq */ + 0x01, + 0x80, /* 48kHz */ + 0x00, + 0x02, /* frame duration */ + 0x02, + 0x03, + 0x02, /* channel count */ + 0x03, + sink_channel_cnt, + 0x05, /* octects per frame */ + 0x04, + 0x78, + 0x00, + 0x78, + 0x00, + // Metadata Length + 0x00, + }; + } else if (handle == pacs->sink_audio_loc_char + 1) { + value = { + // Audio Locations + snk_allocation[0], + snk_allocation[1], + snk_allocation[2], + snk_allocation[3], + }; + } else if (handle == pacs->source_pac_char + 1) { + value = { + // Num records + 0x02, + // Codec_ID + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + // Codec Spec. Caps. Len + 0x10, + 0x03, + 0x01, + sample_freq[0], + sample_freq[1], + 0x02, + 0x02, + 0x03, + 0x02, + 0x03, + source_channel_cnt, + 0x05, + 0x04, + 0x1E, + 0x00, + 0x78, + 0x00, + // Metadata Length + 0x00, + // Codec_ID + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + // Codec Spec. Caps. Len + 0x10, + 0x03, + 0x01, + 0x24, + 0x00, + 0x02, + 0x02, + 0x03, + 0x02, + 0x03, + source_channel_cnt, + 0x05, + 0x04, + 0x1E, + 0x00, + 0x50, + 0x00, + // Metadata Length + 0x00, + }; + } else if (handle == pacs->source_audio_loc_char + 1) { + value = { + // Audio Locations + src_allocation[0], + src_allocation[1], + src_allocation[2], + src_allocation[3], + }; + } else if (handle == pacs->avail_contexts_char + 1) { + value = { + // Sink Avail Contexts + (uint8_t)(available_snk_context_types_), + (uint8_t)(available_snk_context_types_ >> 8), + // Source Avail Contexts + (uint8_t)(available_src_context_types_), + (uint8_t)(available_src_context_types_ >> 8), + }; + } else if (handle == pacs->supp_contexts_char + 1) { + value = { + // Sink Supp Contexts + (uint8_t)(supported_snk_context_types_), + (uint8_t)(supported_snk_context_types_ >> 8), + // Source Supp Contexts + (uint8_t)(supported_src_context_types_), + (uint8_t)(supported_src_context_types_ >> 8), + }; + } + } + cb(conn_id, gatt_status, handle, value.size(), value.data(), + cb_data); + }); } if (add_ascs_cnt > 0) { // Set ascs default read values ON_CALL(*peer_devices.at(conn_id)->ascs, OnReadCharacteristic(_, _, _)) - .WillByDefault([this, conn_id](uint16_t handle, GATT_READ_OP_CB cb, - void* cb_data) { + .WillByDefault([this, conn_id, gatt_status](uint16_t handle, + GATT_READ_OP_CB cb, + void* cb_data) { auto& ascs = peer_devices.at(conn_id)->ascs; std::vector value; bool is_ase_sink_request = false; bool is_ase_src_request = false; uint8_t idx; - for (idx = 0; idx < max_num_of_ases; idx++) { - if (handle == ascs->sink_ase_char[idx] + 1) { - is_ase_sink_request = true; - break; + + if (handle == ascs->ctp_ccc && ccc_stored_byte_val_.has_value()) { + value = {*ccc_stored_byte_val_, 00}; + cb(conn_id, gatt_read_ctp_ccc_status_, handle, value.size(), + value.data(), cb_data); + return; + } + + if (gatt_status == GATT_SUCCESS) { + if (handle == ascs->ctp_ccc) { + value = UINT16_TO_VEC_UINT8(ascs->ctp_ccc_val); + } else { + for (idx = 0; idx < max_num_of_ases; idx++) { + if (handle == ascs->sink_ase_ccc[idx] + 1) { + value = UINT16_TO_VEC_UINT8(ascs->sink_ase_ccc_val[idx]); + break; + } + if (handle == ascs->source_ase_char[idx] + 1) { + value = UINT16_TO_VEC_UINT8(ascs->source_ase_ccc_val[idx]); + break; + } + } } - if (handle == ascs->source_ase_char[idx] + 1) { - is_ase_src_request = true; - break; + + for (idx = 0; idx < max_num_of_ases; idx++) { + if (handle == ascs->sink_ase_char[idx] + 1) { + is_ase_sink_request = true; + break; + } + if (handle == ascs->source_ase_char[idx] + 1) { + is_ase_src_request = true; + break; + } } - } - if (is_ase_sink_request) { - value = { - // ASE ID - static_cast(idx + 1), - // State - static_cast( - le_audio::types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), - // No Additional ASE params for IDLE state - }; - } else if (is_ase_src_request) { - value = { - // ASE ID - static_cast(idx + 6), - // State - static_cast( - le_audio::types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), - // No Additional ASE params for IDLE state - }; + if (is_ase_sink_request) { + value = { + // ASE ID + static_cast(idx + 1), + // State + static_cast( + le_audio::types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), + // No Additional ASE params for IDLE state + }; + } else if (is_ase_src_request) { + value = { + // ASE ID + static_cast(idx + 6), + // State + static_cast( + le_audio::types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), + // No Additional ASE params for IDLE state + }; + } } - cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), + cb(conn_id, gatt_status, handle, value.size(), value.data(), cb_data); }); } @@ -2171,8 +2550,10 @@ class UnicastTestNoInit : public Test { void TestAudioDataTransfer(int group_id, uint8_t cis_count_out, uint8_t cis_count_in, int data_len, - int in_data_len = 40) { + int in_data_len = 40, + uint16_t decoded_in_data_len = 0) { ASSERT_NE(unicast_source_hal_cb_, nullptr); + ASSERT_NE(mock_le_audio_sink_hal_client_, nullptr); // Expect two channels ISO Data to be sent std::vector handles; @@ -2185,8 +2566,14 @@ class UnicastTestNoInit : public Test { unicast_source_hal_cb_->OnAudioDataReady(data); // Inject microphone data from group - EXPECT_CALL(*mock_le_audio_sink_hal_client_, SendData(_, _)) - .Times(cis_count_in > 0 ? 1 : 0); + if (decoded_in_data_len) { + EXPECT_CALL(*mock_le_audio_sink_hal_client_, + SendData(_, decoded_in_data_len)) + .Times(cis_count_in > 0 ? 1 : 0); + } else { + EXPECT_CALL(*mock_le_audio_sink_hal_client_, SendData(_, _)) + .Times(cis_count_in > 0 ? 1 : 0); + } ASSERT_EQ(streaming_groups.count(group_id), 1u); if (cis_count_in) { @@ -2280,12 +2667,18 @@ class UnicastTestNoInit : public Test { uint16_t global_conn_id = 1; le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_; std::map streaming_groups; + bool block_streaming_state_callback = false; bluetooth::hci::IsoManager* iso_manager_; MockIsoManager* mock_iso_manager_; bluetooth::hci::iso_manager::CigCallbacks* cig_callbacks_ = nullptr; uint16_t iso_con_counter_ = 1; + le_audio::CodecManager* codec_manager_; + MockCodecManager* mock_codec_manager_; + + uint16_t available_snk_context_types_ = 0xffff; + uint16_t available_src_context_types_ = 0xffff; uint16_t supported_snk_context_types_ = 0xffff; uint16_t supported_src_context_types_ = 0xffff; @@ -2294,6 +2687,13 @@ class UnicastTestNoInit : public Test { std::map>> peer_devices; std::list group_locks; std::map groups; + + /* CCC descriptor data */ + tGATT_STATUS gatt_read_ctp_ccc_status_ = GATT_SUCCESS; + std::optional ccc_stored_byte_val_ = std::nullopt; + + /* Audio track metadata */ + char* test_tags_ptr_ = nullptr; }; class UnicastTest : public UnicastTestNoInit { @@ -2304,6 +2704,23 @@ class UnicastTest : public UnicastTestNoInit { EXPECT_CALL(mock_hal_2_1_verifier, Call()).Times(1); EXPECT_CALL(mock_storage_load, Call()).Times(1); + ON_CALL(mock_btm_interface_, GetHCIConnHandle(_, _)) + .WillByDefault([this](RawAddress const& bd_addr, + tBT_TRANSPORT transport) -> uint16_t { + for (auto const& [conn_id, dev_wrapper] : peer_devices) { + if (dev_wrapper->addr == bd_addr) { + return conn_id; + } + } + LOG_ERROR("GetHCIConnHandle Mock: not a valid test device!"); + return 0x00FE; + }); + ON_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)) + .WillByDefault([this](uint16_t handle, tHCI_STATUS rs) { + ASSERT_NE(handle, GATT_INVALID_CONN_ID); + InjectDisconnectedEvent(handle, GATT_CONN_TERMINATE_LOCAL_HOST); + }); + std::vector<::bluetooth::le_audio::btle_audio_codec_config_t> framework_encode_preference; BtaAppRegisterCallback app_register_callback; @@ -2327,11 +2744,32 @@ class UnicastTest : public UnicastTestNoInit { } void TearDown() override { + // Clear the default actions before the parent class teardown is called + Mock::VerifyAndClear(&mock_btm_interface_); + Mock::VerifyAndClear(&mock_gatt_interface_); + Mock::VerifyAndClear(&mock_audio_hal_client_callbacks_); groups.clear(); UnicastTestNoInit::TearDown(); } }; +class UnicastTestHealthStatus : public UnicastTest { + protected: + void SetUp() override { + use_health_status = true; + UnicastTest::SetUp(); + group_ = new LeAudioDeviceGroup(group_id_); + } + + void TearDown() override { + delete group_; + UnicastTest::TearDown(); + } + + const int group_id_ = 0; + LeAudioDeviceGroup* group_ = nullptr; +}; + RawAddress GetTestAddress(uint8_t index) { CHECK_LT(index, UINT8_MAX); RawAddress result = {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, index}}; @@ -2448,362 +2886,608 @@ TEST_F(UnicastTest, ConnectOneEarbudNoCsis) { ConnectLeAudio(test_address0); } -TEST_F(UnicastTest, ConnectDisconnectOneEarbud) { +TEST_F(UnicastTest, ConnectOneEarbudWithInvalidCsis) { const RawAddress test_address0 = GetTestAddress(0); - SetSampleDatabaseEarbudsValid(1, test_address0, - codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt /*add_ascs*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::CONNECTED, test_address0)) + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); + EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(1); + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + /* Make sure Group has not knowledge about the device */ + ON_CALL(mock_groups_module_, GetGroupId(_, _)) + .WillByDefault([](const RawAddress& addr, bluetooth::Uuid uuid) { + return bluetooth::groups::kGroupUnknown; + }); + ConnectLeAudio(test_address0); - DisconnectLeAudio(test_address0, 1); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); } -/* same as above case except the disconnect is initiated by remote */ -TEST_F(UnicastTest, ConnectRemoteDisconnectOneEarbud) { +TEST_F_WITH_FLAGS(UnicastTestHealthStatus, + ConnectOneEarbudEmpty_withHealthStatus, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( + TEST_BT, leaudio_enable_health_based_actions))) { const RawAddress test_address0 = GetTestAddress(0); - SetSampleDatabaseEarbudsValid(1, test_address0, - codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo); + SetSampleDatabaseEmpty(1, test_address0); EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::CONNECTED, test_address0)) + OnHealthBasedRecommendationAction( + test_address0, LeAudioHealthBasedAction::DISABLE)) .Times(1); - ConnectLeAudio(test_address0); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); - /* For remote disconnection, expect stack to try background re-connect */ - EXPECT_CALL(mock_gatt_interface_, - Open(gatt_if, test_address0, - BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) - .Times(1); + EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(1); + ConnectLeAudio(test_address0); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + LeAudioHealthStatus::Get()->RemoveStatistics( + test_address0, bluetooth::groups::kGroupUnknown); +} +TEST_F_WITH_FLAGS(UnicastTestHealthStatus, + ConnectOneEarbudNoPacs_withHealthStatus, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( + TEST_BT, leaudio_enable_health_based_actions))) { + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + false, /*add_pacs*/ + default_ase_cnt /*add_ascs*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::CONNECTED, test_address0)) + OnHealthBasedRecommendationAction( + test_address0, LeAudioHealthBasedAction::DISABLE)) .Times(1); - InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(1); + ConnectLeAudio(test_address0); SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); - /* For background connect, test needs to Inject Connected Event */ - InjectConnectedEvent(test_address0, 1); - SyncOnMainLoop(); + LeAudioHealthStatus::Get()->RemoveStatistics( + test_address0, bluetooth::groups::kGroupUnknown); } -/* same as above case except the disconnect is initiated by remote */ -TEST_F(UnicastTest, ConnectRemoteDisconnectOnTimeoutOneEarbud) { +TEST_F_WITH_FLAGS(UnicastTestHealthStatus, + ConnectOneEarbudNoAscs_withHealthStatus, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( + TEST_BT, leaudio_enable_health_based_actions))) { const RawAddress test_address0 = GetTestAddress(0); - SetSampleDatabaseEarbudsValid(1, test_address0, - codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + 0 /*add_ascs*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::CONNECTED, test_address0)) + OnHealthBasedRecommendationAction( + test_address0, LeAudioHealthBasedAction::DISABLE)) .Times(1); - ConnectLeAudio(test_address0); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); + EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(1); + ConnectLeAudio(test_address0); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); - /* Remove default action on the direct connect */ - ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)) - .WillByDefault(Return()); + LeAudioHealthStatus::Get()->RemoveStatistics( + test_address0, bluetooth::groups::kGroupUnknown); +} - /* For remote disconnection, expect stack to try background re-connect */ - EXPECT_CALL(mock_gatt_interface_, - Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) - .Times(1); +TEST_F(UnicastTestHealthStatus, ConnectOneEarbudNoCas_withHealthStatus) { + const RawAddress test_address0 = GetTestAddress(0); + uint16_t conn_id = 1; + SetSampleDatabaseEarbudsValid( + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + false, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt /*add_ascs*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnHealthBasedRecommendationAction( + test_address0, LeAudioHealthBasedAction::DISABLE)) + .Times(0); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); - InjectDisconnectedEvent(1, GATT_CONN_TIMEOUT); + ConnectLeAudio(test_address0); SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - /* For background connect, test needs to Inject Connected Event */ - InjectConnectedEvent(test_address0, 1); - SyncOnMainLoop(); + LeAudioHealthStatus::Get()->RemoveStatistics( + test_address0, bluetooth::groups::kGroupUnknown); } -TEST_F(UnicastTest, ConnectTwoEarbudsCsisGrouped) { - uint8_t group_size = 2; - int group_id = 2; +TEST_F(UnicastTestHealthStatus, ConnectOneEarbudNoCsis_withHealthStatus) { + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ false, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt /*add_ascs*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnHealthBasedRecommendationAction( + test_address0, LeAudioHealthBasedAction::DISABLE)) + .Times(0); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + ConnectLeAudio(test_address0); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - // Report working CSIS - ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) - .WillByDefault(Return(true)); + LeAudioHealthStatus::Get()->RemoveStatistics( + test_address0, bluetooth::groups::kGroupUnknown); +} - // First earbud +TEST_F_WITH_FLAGS(UnicastTestHealthStatus, + ConnectOneEarbudWithInvalidCsis_withHealthStatus, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( + TEST_BT, leaudio_enable_health_based_actions))) { const RawAddress test_address0 = GetTestAddress(0); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt /*add_ascs*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); - ConnectCsisDevice(test_address0, 1 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft, group_size, - group_id, 1 /* rank*/); - - // Second earbud - const RawAddress test_address1 = GetTestAddress(1); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnHealthBasedRecommendationAction( + test_address0, LeAudioHealthBasedAction::DISABLE)) .Times(1); - ConnectCsisDevice(test_address1, 2 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, group_size, - group_id, 2 /* rank*/, true /*connect_through_csis*/); - - Mock::VerifyAndClearExpectations(&mock_btif_storage_); - - /* for Target announcements AutoConnect is always there, until - * device is removed - */ - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, false)) - .Times(0); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) - .Times(0); - - // Verify grouping information - std::vector devs = - LeAudioClient::Get()->GetGroupDevices(group_id); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); - - DisconnectLeAudio(test_address0, 1); - DisconnectLeAudio(test_address1, 2); -} -TEST_F(UnicastTest, ConnectTwoEarbudsCsisGroupUnknownAtConnect) { - uint8_t group_size = 2; - uint8_t group_id = 2; + EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(1); // Report working CSIS ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) .WillByDefault(Return(true)); - // First earbud connects without known grouping + /* Make sure Group has not knowledge about the device */ + ON_CALL(mock_groups_module_, GetGroupId(_, _)) + .WillByDefault([](const RawAddress& addr, bluetooth::Uuid uuid) { + return bluetooth::groups::kGroupUnknown; + }); + + ConnectLeAudio(test_address0); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + LeAudioHealthStatus::Get()->RemoveStatistics( + test_address0, bluetooth::groups::kGroupUnknown); +} + +TEST_F_WITH_FLAGS(UnicastTestHealthStatus, + ConnectOneEarbudDisable_withHealthStatus, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( + TEST_BT, leaudio_enable_health_based_actions))) { const RawAddress test_address0 = GetTestAddress(0); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) - .Times(1); - ConnectCsisDevice(test_address0, 1 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft, group_size, - group_id, 1 /* rank*/); + int conn_id = 1; - // Second earbud - const RawAddress test_address1 = GetTestAddress(1); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + SetSampleDatabaseEarbudsValid( + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, false); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); - ConnectCsisDevice(test_address1, 2 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, group_size, - group_id, 2 /* rank*/, true /*connect_through_csis*/); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); + ConnectLeAudio(test_address0); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - // Verify grouping information - std::vector devs = - LeAudioClient::Get()->GetGroupDevices(group_id); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + LeAudioClient::Get()->GroupSetActive(group_id_); + auto device = std::make_shared( + test_address0, DeviceConnectState::DISCONNECTED); + group_->AddNode(device); + SyncOnMainLoop(); - /* for Target announcements AutoConnect is always there, until - * device is removed - */ - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, false)) - .Times(0); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) - .Times(0); - DisconnectLeAudio(test_address0, 1); - DisconnectLeAudio(test_address1, 2); -} + auto health_status = LeAudioHealthStatus::Get(); -TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGrouped) { - // Prepare two devices - uint8_t group_size = 2; - uint8_t group_id = 2; + /* Inject stream error */ + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnHealthBasedGroupRecommendationAction( + group_id_, LeAudioHealthBasedAction::DISABLE)) + .Times(1); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); - /* Prepare mock to not inject connect event so the device can stay in - * CONNECTING state*/ - ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, false)) + /* Do not act on disconnect */ + ON_CALL(mock_gatt_interface_, Close(_)).WillByDefault(DoAll(Return())); + ON_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)) .WillByDefault(DoAll(Return())); + state_machine_callbacks_->OnStateTransitionTimeout(group_id_); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnHealthBasedGroupRecommendationAction( + group_id_, LeAudioHealthBasedAction::DISABLE)) + .Times(0); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); +} + +TEST_F_WITH_FLAGS(UnicastTestHealthStatus, + ConnectOneEarbudConsiderDisabling_withHealthStatus, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( + TEST_BT, leaudio_enable_health_based_actions))) { const RawAddress test_address0 = GetTestAddress(0); - SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ true, /*add_csis*/ - true, /*add_cas*/ - true, /*add_pacs*/ - default_ase_cnt, /*add_ascs_cnt*/ - group_size, 1); + int conn_id = 1; - const RawAddress test_address1 = GetTestAddress(1); SetSampleDatabaseEarbudsValid( - 2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ true, /*add_csis*/ - true, /*add_cas*/ - true, /*add_pacs*/ - default_ase_cnt, /*add_ascs_cnt*/ - group_size, 2); + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, false); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); - // Load devices from the storage when storage API is called - bool autoconnect = true; + ConnectLeAudio(test_address0); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - /* Common storage values */ - std::vector handles; - LeAudioClient::GetHandlesForStorage(test_address0, handles); + LeAudioClient::Get()->GroupSetActive(group_id_); + auto device = std::make_shared( + test_address0, DeviceConnectState::DISCONNECTED); + group_->AddNode(device); + SyncOnMainLoop(); - std::vector ases; - LeAudioClient::GetAsesForStorage(test_address0, ases); + auto health_status = LeAudioHealthStatus::Get(); - std::vector src_pacs; - LeAudioClient::GetSourcePacsForStorage(test_address0, src_pacs); + /* Inject stream success and error */ + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnHealthBasedGroupRecommendationAction( + group_id_, LeAudioHealthBasedAction::CONSIDER_DISABLING)) + .Times(1); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + + /* Do not act on disconnect */ + ON_CALL(mock_gatt_interface_, Close(_)).WillByDefault(DoAll(Return())); + ON_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)) + .WillByDefault(DoAll(Return())); - std::vector snk_pacs; - LeAudioClient::GetSinkPacsForStorage(test_address0, snk_pacs); + state_machine_callbacks_->OnStateTransitionTimeout(group_id_); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - EXPECT_CALL(mock_storage_load, Call()).WillOnce([&]() { - do_in_main_thread( - FROM_HERE, - base::Bind(&LeAudioClient::AddFromStorage, test_address0, autoconnect, - codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft, 0xff, 0xff, - std::move(handles), std::move(snk_pacs), std::move(src_pacs), - std::move(ases))); - do_in_main_thread( - FROM_HERE, - base::Bind(&LeAudioClient::AddFromStorage, test_address1, autoconnect, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, 0xff, 0xff, - std::move(handles), std::move(snk_pacs), std::move(src_pacs), - std::move(ases))); - }); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnHealthBasedGroupRecommendationAction( + 1, LeAudioHealthBasedAction::CONSIDER_DISABLING)) + .Times(0); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + health_status->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); +} - // Expect stored device0 to connect automatically (first directed connection ) - EXPECT_CALL(mock_gatt_interface_, - Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) +TEST_F(UnicastTest, ConnectDisconnectOneEarbud) { + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid(1, test_address0, + codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); + ConnectLeAudio(test_address0); + DisconnectLeAudioWithAclClose(test_address0, 1); +} - // Expect stored device1 to connect automatically (first direct connection) - EXPECT_CALL(mock_gatt_interface_, - Open(gatt_if, test_address1, BTM_BLE_DIRECT_CONNECTION, _)) - .Times(1); +TEST_F(UnicastTest, ConnectRemoteServiceDiscoveryCompleteBeforeEncryption) { + const RawAddress test_address0 = GetTestAddress(0); + uint16_t conn_id = 1; + SetSampleDatabaseEarbudsValid(conn_id, test_address0, + codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(0); + ConnectLeAudio(test_address0, false); + InjectSearchCompleteEvent(conn_id); - ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address1, _)) - .WillByDefault(DoAll(Return(true))); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) .WillByDefault(DoAll(Return(true))); + InjectEncryptionChangedEvent(test_address0); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); +} - ON_CALL(mock_groups_module_, GetGroupId(_, _)) - .WillByDefault(DoAll(Return(group_id))); +TEST_F(UnicastTest, DisconnectWhenLinkKeyIsGone) { + const RawAddress test_address0 = GetTestAddress(0); + uint16_t conn_id = 1; + SetSampleDatabaseEarbudsValid(conn_id, test_address0, + codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); - ON_CALL(mock_btm_interface_, - GetSecurityFlagsByTransport(test_address0, NotNull(), _)) - .WillByDefault( - DoAll(SetArgPointee<1>(BTM_SEC_FLAG_ENCRYPTED), Return(true))); + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) + .WillByDefault(DoAll(Return(false))); - std::vector<::bluetooth::le_audio::btle_audio_codec_config_t> - framework_encode_preference; + ON_CALL(mock_btm_interface_, SetEncryption(test_address0, _, _, _, _)) + .WillByDefault(Return(BTM_ERR_KEY_MISSING)); - // Initialize - BtaAppRegisterCallback app_register_callback; - ON_CALL(mock_gatt_interface_, AppRegister(_, _, _)) - .WillByDefault(DoAll(SaveArg<0>(&gatt_callback), - SaveArg<1>(&app_register_callback))); - LeAudioClient::Initialize( - &mock_audio_hal_client_callbacks_, - base::Bind([](MockFunction* foo) { foo->Call(); }, - &mock_storage_load), - base::Bind([](MockFunction* foo) { return foo->Call(); }, - &mock_hal_2_1_verifier), - framework_encode_preference); - if (app_register_callback) app_register_callback.Run(gatt_if, GATT_SUCCESS); + EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1); + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::Connect, + base::Unretained(LeAudioClient::Get()), test_address0)); - // We need to wait for the storage callback before verifying stuff SyncOnMainLoop(); - ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning()); + Mock::VerifyAndClearExpectations(&mock_btm_interface_); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} - // Simulate devices are not there and phone fallbacks to targeted - // announcements +/* same as above case except the disconnect is initiated by remote */ +TEST_F(UnicastTest, ConnectRemoteDisconnectOneEarbud) { + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid(1, test_address0, + codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + ConnectLeAudio(test_address0); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); + /* Make sure when remote device disconnects us, TA is used */ + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)) + .Times(1); EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) .Times(1); + InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + + /* When reconnected, we always remove background connect, as we do not track + * which type (allow list or TA) was used and then make sure the TA is used. + */ + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)) + .Times(1); EXPECT_CALL(mock_gatt_interface_, - Open(gatt_if, test_address1, + Open(gatt_if, test_address0, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) .Times(1); - // Devices not found - InjectConnectedEvent(test_address0, 0, GATT_ERROR); - InjectConnectedEvent(test_address1, 0, GATT_ERROR); - + /* For background connect, test needs to Inject Connected Event */ + InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} +/* same as above case except the disconnect is initiated by remote */ +TEST_F(UnicastTest, ConnectRemoteDisconnectOnTimeoutOneEarbud) { + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid(1, test_address0, + codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); + ConnectLeAudio(test_address0); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); + + /* Remove default action on the direct connect */ + ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(Return()); + + /* For remote disconnection, expect stack to try background re-connect */ + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + + InjectDisconnectedEvent(1, GATT_CONN_TIMEOUT); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::CONNECTED, test_address1)) + OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); /* For background connect, test needs to Inject Connected Event */ InjectConnectedEvent(test_address0, 1); - InjectConnectedEvent(test_address1, 2); + SyncOnMainLoop(); +} - // Verify if all went well and we got the proper group +TEST_F(UnicastTest, ConnectTwoEarbudsCsisGrouped) { + uint8_t group_size = 2; + int group_id = 2; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + + /* for Target announcements AutoConnect is always there, until + * device is removed + */ + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, false)) + .Times(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) + .Times(0); + + // Verify grouping information std::vector devs = LeAudioClient::Get()->GetGroupDevices(group_id); ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); - DisconnectLeAudio(test_address0, 1); - DisconnectLeAudio(test_address1, 2); + DisconnectLeAudioWithAclClose(test_address0, 1); + DisconnectLeAudioWithAclClose(test_address1, 2); } -TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) { - // Prepare two devices - uint8_t group_size = 1; +TEST_F(UnicastTest, ConnectTwoEarbudsCsisGroupUnknownAtConnect) { + uint8_t group_size = 2; + uint8_t group_id = 2; - // Device 0 - uint8_t group_id0 = 2; - bool autoconnect0 = true; - const RawAddress test_address0 = GetTestAddress(0); - SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft, 0x0004, - /* source sample freq 16khz */ true, /*add_csis*/ - true, /*add_cas*/ - true, /*add_pacs*/ - true, /*add_ascs*/ - group_size, 1); + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); - ON_CALL(mock_groups_module_, GetGroupId(test_address0, _)) - .WillByDefault(DoAll(Return(group_id0))); + // First earbud connects without known grouping + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - // Device 1 - uint8_t group_id1 = 3; - bool autoconnect1 = false; + // Second earbud const RawAddress test_address1 = GetTestAddress(1); - SetSampleDatabaseEarbudsValid( - 2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ true, /*add_csis*/ - true, /*add_cas*/ - true, /*add_pacs*/ - default_ase_cnt, /*add_ascs_cnt*/ - group_size, 2); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); - ON_CALL(mock_groups_module_, GetGroupId(test_address1, _)) - .WillByDefault(DoAll(Return(group_id1))); + Mock::VerifyAndClearExpectations(&mock_btif_storage_); - /* Commont storage values */ + // Verify grouping information + std::vector devs = + LeAudioClient::Get()->GetGroupDevices(group_id); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + + /* for Target announcements AutoConnect is always there, until + * device is removed + */ + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, false)) + .Times(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) + .Times(0); + DisconnectLeAudioWithAclClose(test_address0, 1); + DisconnectLeAudioWithAclClose(test_address1, 2); +} + +TEST_F(UnicastTestNoInit, ConnectFailedDueToInvalidParameters) { + // Prepare two devices + uint8_t group_size = 2; + uint8_t group_id = 2; + + /* Prepare mock to not inject connect event so the device can stay in + * CONNECTING state*/ + ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, false)) + .WillByDefault(DoAll(Return())); + + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 1); + + const RawAddress test_address1 = GetTestAddress(1); + SetSampleDatabaseEarbudsValid( + 2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 2); + + // Load devices from the storage when storage API is called + bool autoconnect = true; + + /* Common storage values */ std::vector handles; LeAudioClient::GetHandlesForStorage(test_address0, handles); @@ -2816,51 +3500,54 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) { std::vector snk_pacs; LeAudioClient::GetSinkPacsForStorage(test_address0, snk_pacs); - // Load devices from the storage when storage API is called EXPECT_CALL(mock_storage_load, Call()).WillOnce([&]() { do_in_main_thread( FROM_HERE, - base::Bind(&LeAudioClient::AddFromStorage, test_address0, autoconnect0, + base::Bind(&LeAudioClient::AddFromStorage, test_address0, autoconnect, codec_spec_conf::kLeAudioLocationFrontLeft, codec_spec_conf::kLeAudioLocationFrontLeft, 0xff, 0xff, std::move(handles), std::move(snk_pacs), std::move(src_pacs), std::move(ases))); do_in_main_thread( FROM_HERE, - base::Bind(&LeAudioClient::AddFromStorage, test_address1, autoconnect1, + base::Bind(&LeAudioClient::AddFromStorage, test_address1, autoconnect, codec_spec_conf::kLeAudioLocationFrontRight, codec_spec_conf::kLeAudioLocationFrontRight, 0xff, 0xff, std::move(handles), std::move(snk_pacs), std::move(src_pacs), std::move(ases))); }); - // Expect stored device0 to connect automatically - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::CONNECTED, test_address0)) - .Times(1); - ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) - .WillByDefault(DoAll(Return(true))); + // Expect stored device0 to connect automatically (first directed connection ) EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) .Times(1); - // Expect stored device1 to NOT connect automatically - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::CONNECTED, test_address1)) - .Times(0); - ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address1, _)) - .WillByDefault(DoAll(Return(true))); + // Expect stored device1 to connect automatically (first direct connection) EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address1, BTM_BLE_DIRECT_CONNECTION, _)) - .Times(0); + .Times(1); + + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address1, _)) + .WillByDefault(DoAll(Return(true))); + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) + .WillByDefault(DoAll(Return(true))); + + ON_CALL(mock_groups_module_, GetGroupId(_, _)) + .WillByDefault(DoAll(Return(group_id))); + + ON_CALL(mock_btm_interface_, + GetSecurityFlagsByTransport(test_address0, NotNull(), _)) + .WillByDefault( + DoAll(SetArgPointee<1>(BTM_SEC_FLAG_ENCRYPTED), Return(true))); + + std::vector<::bluetooth::le_audio::btle_audio_codec_config_t> + framework_encode_preference; // Initialize BtaAppRegisterCallback app_register_callback; ON_CALL(mock_gatt_interface_, AppRegister(_, _, _)) .WillByDefault(DoAll(SaveArg<0>(&gatt_callback), SaveArg<1>(&app_register_callback))); - std::vector<::bluetooth::le_audio::btle_audio_codec_config_t> - framework_encode_preference; LeAudioClient::Initialize( &mock_audio_hal_client_callbacks_, base::Bind([](MockFunction* foo) { foo->Call(); }, @@ -2875,714 +3562,2869 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) { ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning()); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); - // Simulate device is not there and phone fallbacks to targeted announcements + // Simulate connect parameters are invalid and phone does not fallback + // to background connect. EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) - .Times(1); + .Times(0); + + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address1, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(0); // Devices not found - InjectConnectedEvent(test_address0, 0, GATT_ERROR); + InjectConnectedEvent(test_address0, 0, GATT_ILLEGAL_PARAMETER); + InjectConnectedEvent(test_address1, 0, GATT_ILLEGAL_PARAMETER); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} - /* For background connect, test needs to Inject Connected Event */ - InjectConnectedEvent(test_address0, 1); +TEST_F(UnicastTestNoInit, LoadStoredEarbudsBroakenStorage) { + // Prepare two devices + uint8_t group_size = 2; + uint8_t group_id = 2; + /* If the storage has been broken, make sure device will be rediscovered after + * reconnection + */ - // We need to wait for the storage callback before verifying stuff - SyncOnMainLoop(); - ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning()); + /* Prepare mock to not inject connect event so the device can stay in + * CONNECTING state*/ + ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, false)) + .WillByDefault(DoAll(Return())); - std::vector devs = - LeAudioClient::Get()->GetGroupDevices(group_id0); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); - ASSERT_EQ(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 1); - devs = LeAudioClient::Get()->GetGroupDevices(group_id1); - ASSERT_EQ(std::find(devs.begin(), devs.end(), test_address0), devs.end()); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + const RawAddress test_address1 = GetTestAddress(1); + SetSampleDatabaseEarbudsValid( + 2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 2); - DisconnectLeAudio(test_address0, 1); -} + // Load devices from the storage when storage API is called + bool autoconnect = true; + std::vector empty_buf; -TEST_F(UnicastTest, GroupingAddRemove) { - // Earbud connects without known grouping - uint8_t group_id0 = bluetooth::groups::kGroupUnknown; - const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_storage_load, Call()).WillOnce([&]() { + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::AddFromStorage, test_address0, + autoconnect, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, 0xff, 0xff, + std::move(empty_buf), std::move(empty_buf), + std::move(empty_buf), std::move(empty_buf))); + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::AddFromStorage, test_address1, + autoconnect, codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, 0xff, 0xff, + std::move(empty_buf), std::move(empty_buf), + std::move(empty_buf), std::move(empty_buf))); + SyncOnMainLoop(); + }); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + // Expect stored device0 to connect automatically (first directed connection ) + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) .Times(1); - ConnectNonCsisDevice(test_address0, 1 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft); - - group_id0 = MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address0); - // Earbud connects without known grouping - uint8_t group_id1 = bluetooth::groups::kGroupUnknown; - const RawAddress test_address1 = GetTestAddress(1); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + // Expect stored device1 to connect automatically (first direct connection) + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address1, BTM_BLE_DIRECT_CONNECTION, _)) .Times(1); - ConnectNonCsisDevice(test_address1, 2 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight); - group_id1 = MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address1); + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address1, _)) + .WillByDefault(DoAll(Return(true))); + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) + .WillByDefault(DoAll(Return(true))); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); + ON_CALL(mock_groups_module_, GetGroupId(_, _)) + .WillByDefault(DoAll(Return(group_id))); - // Verify individual groups - ASSERT_NE(group_id0, bluetooth::groups::kGroupUnknown); - ASSERT_NE(group_id1, bluetooth::groups::kGroupUnknown); - ASSERT_NE(group_id0, group_id1); - ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id0).size(), 1u); - ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id1).size(), 1u); + ON_CALL(mock_btm_interface_, + GetSecurityFlagsByTransport(test_address0, NotNull(), _)) + .WillByDefault( + DoAll(SetArgPointee<1>(BTM_SEC_FLAG_ENCRYPTED), Return(true))); - // Expectations on reassigning second earbud to the first group - int dev1_storage_group = bluetooth::groups::kGroupUnknown; - int dev1_new_group = bluetooth::groups::kGroupUnknown; + std::vector<::bluetooth::le_audio::btle_audio_codec_config_t> + framework_encode_preference; - EXPECT_CALL( - mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address1, group_id1, GroupNodeStatus::REMOVED)) - .Times(AtLeast(1)); - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address1, _, GroupNodeStatus::ADDED)) - .WillRepeatedly(SaveArg<1>(&dev1_new_group)); - EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address1, group_id1)) - .Times(AtLeast(1)); - EXPECT_CALL(mock_groups_module_, AddDevice(test_address1, _, _)) - .Times(AnyNumber()); + // Initialize + BtaAppRegisterCallback app_register_callback; + ON_CALL(mock_gatt_interface_, AppRegister(_, _, _)) + .WillByDefault(DoAll(SaveArg<0>(&gatt_callback), + SaveArg<1>(&app_register_callback))); + LeAudioClient::Initialize( + &mock_audio_hal_client_callbacks_, + base::Bind([](MockFunction* foo) { foo->Call(); }, + &mock_storage_load), + base::Bind([](MockFunction* foo) { return foo->Call(); }, + &mock_hal_2_1_verifier), + framework_encode_preference); + if (app_register_callback) app_register_callback.Run(gatt_if, GATT_SUCCESS); - LeAudioClient::Get()->GroupRemoveNode(group_id1, test_address1); + // We need to wait for the storage callback before verifying stuff SyncOnMainLoop(); + ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning()); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); - Mock::VerifyAndClearExpectations(&mock_groups_module_); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); + // Simulate devices are not there and phone fallbacks to targeted + // announcements + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); - EXPECT_CALL(mock_groups_module_, AddDevice(test_address1, _, group_id0)) + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address1, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) .Times(1); - LeAudioClient::Get()->GroupAddNode(group_id0, test_address1); + // Devices not found + InjectConnectedEvent(test_address0, 0, GATT_ERROR); + InjectConnectedEvent(test_address1, 0, GATT_ERROR); + SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_groups_module_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); - dev1_storage_group = - MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address1); + /* Stack should rediscover services as storage is broken */ + EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(2, _)).Times(1); + EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(1, _)).Times(1); - // Verify regrouping results - EXPECT_EQ(dev1_new_group, group_id0); - EXPECT_EQ(dev1_new_group, dev1_storage_group); - ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id1).size(), 0u); - ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id0).size(), 2u); - std::vector devs = - LeAudioClient::Get()->GetGroupDevices(group_id0); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); -} + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address1)) + .Times(1); + + /* For background connect, test needs to Inject Connected Event */ + InjectConnectedEvent(test_address0, 1); + InjectConnectedEvent(test_address1, 2); + SyncOnMainLoop(); + + // Verify if all went well and we got the proper group + std::vector devs = + LeAudioClient::Get()->GetGroupDevices(group_id); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + + DisconnectLeAudioWithAclClose(test_address0, 1); + DisconnectLeAudioWithAclClose(test_address1, 2); +} + +TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGrouped) { + // Prepare two devices + uint8_t group_size = 2; + uint8_t group_id = 2; + + /* Prepare mock to not inject connect event so the device can stay in + * CONNECTING state*/ + ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, false)) + .WillByDefault(DoAll(Return())); + + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 1); + + const RawAddress test_address1 = GetTestAddress(1); + SetSampleDatabaseEarbudsValid( + 2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 2); + + // Load devices from the storage when storage API is called + bool autoconnect = true; + + /* Common storage values */ + std::vector handles; + LeAudioClient::GetHandlesForStorage(test_address0, handles); + + std::vector ases; + LeAudioClient::GetAsesForStorage(test_address0, ases); + + std::vector src_pacs; + LeAudioClient::GetSourcePacsForStorage(test_address0, src_pacs); + + std::vector snk_pacs; + LeAudioClient::GetSinkPacsForStorage(test_address0, snk_pacs); + + EXPECT_CALL(mock_storage_load, Call()).WillOnce([&]() { + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::AddFromStorage, test_address0, + autoconnect, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, 0xff, 0xff, + std::move(handles), std::move(snk_pacs), + std::move(src_pacs), std::move(ases))); + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::AddFromStorage, test_address1, + autoconnect, codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, 0xff, 0xff, + std::move(handles), std::move(snk_pacs), + std::move(src_pacs), std::move(ases))); + SyncOnMainLoop(); + }); + + // Expect stored device0 to connect automatically (first directed connection ) + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + + // Expect stored device1 to connect automatically (first direct connection) + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address1, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address1, _)) + .WillByDefault(DoAll(Return(true))); + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) + .WillByDefault(DoAll(Return(true))); + + ON_CALL(mock_groups_module_, GetGroupId(_, _)) + .WillByDefault(DoAll(Return(group_id))); + + ON_CALL(mock_btm_interface_, + GetSecurityFlagsByTransport(test_address0, NotNull(), _)) + .WillByDefault( + DoAll(SetArgPointee<1>(BTM_SEC_FLAG_ENCRYPTED), Return(true))); + + std::vector<::bluetooth::le_audio::btle_audio_codec_config_t> + framework_encode_preference; + + // Initialize + BtaAppRegisterCallback app_register_callback; + ON_CALL(mock_gatt_interface_, AppRegister(_, _, _)) + .WillByDefault(DoAll(SaveArg<0>(&gatt_callback), + SaveArg<1>(&app_register_callback))); + LeAudioClient::Initialize( + &mock_audio_hal_client_callbacks_, + base::Bind([](MockFunction* foo) { foo->Call(); }, + &mock_storage_load), + base::Bind([](MockFunction* foo) { return foo->Call(); }, + &mock_hal_2_1_verifier), + framework_encode_preference); + if (app_register_callback) app_register_callback.Run(gatt_if, GATT_SUCCESS); + + // We need to wait for the storage callback before verifying stuff + SyncOnMainLoop(); + ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning()); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + // Simulate devices are not there and phone fallbacks to targeted + // announcements + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address1, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + + // Devices not found + InjectConnectedEvent(test_address0, 0, GATT_ERROR); + InjectConnectedEvent(test_address1, 0, GATT_ERROR); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address1)) + .Times(1); + + /* For background connect, test needs to Inject Connected Event */ + InjectConnectedEvent(test_address0, 1); + InjectConnectedEvent(test_address1, 2); + SyncOnMainLoop(); + + // Verify if all went well and we got the proper group + std::vector devs = + LeAudioClient::Get()->GetGroupDevices(group_id); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + + DisconnectLeAudioWithAclClose(test_address0, 1); + DisconnectLeAudioWithAclClose(test_address1, 2); +} + +TEST_F(UnicastTestNoInit, ServiceChangedBeforeServiceIsConnected) { + // Prepare two devices + uint8_t group_size = 2; + uint8_t group_id = 2; + + /* Prepare mock to not inject connect event so the device can stay in + * CONNECTING state*/ + ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, false)) + .WillByDefault(DoAll(Return())); + + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 1); + + const RawAddress test_address1 = GetTestAddress(1); + SetSampleDatabaseEarbudsValid( + 2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 2); + + // Load devices from the storage when storage API is called + bool autoconnect = true; + + /* Common storage values */ + std::vector handles; + LeAudioClient::GetHandlesForStorage(test_address0, handles); + + std::vector ases; + LeAudioClient::GetAsesForStorage(test_address0, ases); + + std::vector src_pacs; + LeAudioClient::GetSourcePacsForStorage(test_address0, src_pacs); + + std::vector snk_pacs; + LeAudioClient::GetSinkPacsForStorage(test_address0, snk_pacs); + + EXPECT_CALL(mock_storage_load, Call()).WillOnce([&]() { + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::AddFromStorage, test_address0, + autoconnect, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, 0xff, 0xff, + std::move(handles), std::move(snk_pacs), + std::move(src_pacs), std::move(ases))); + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::AddFromStorage, test_address1, + autoconnect, codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, 0xff, 0xff, + std::move(handles), std::move(snk_pacs), + std::move(src_pacs), std::move(ases))); + SyncOnMainLoop(); + }); + + // Expect stored device0 to connect automatically (first directed connection ) + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + + // Expect stored device1 to connect automatically (first direct connection) + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address1, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address1, _)) + .WillByDefault(DoAll(Return(true))); + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) + .WillByDefault(DoAll(Return(true))); + + ON_CALL(mock_groups_module_, GetGroupId(_, _)) + .WillByDefault(DoAll(Return(group_id))); + + ON_CALL(mock_btm_interface_, + GetSecurityFlagsByTransport(test_address0, NotNull(), _)) + .WillByDefault( + DoAll(SetArgPointee<1>(BTM_SEC_FLAG_ENCRYPTED), Return(true))); + + std::vector<::bluetooth::le_audio::btle_audio_codec_config_t> + framework_encode_preference; + + // Initialize + BtaAppRegisterCallback app_register_callback; + ON_CALL(mock_gatt_interface_, AppRegister(_, _, _)) + .WillByDefault(DoAll(SaveArg<0>(&gatt_callback), + SaveArg<1>(&app_register_callback))); + LeAudioClient::Initialize( + &mock_audio_hal_client_callbacks_, + base::Bind([](MockFunction* foo) { foo->Call(); }, + &mock_storage_load), + base::Bind([](MockFunction* foo) { return foo->Call(); }, + &mock_hal_2_1_verifier), + framework_encode_preference); + if (app_register_callback) app_register_callback.Run(gatt_if, GATT_SUCCESS); + + // We need to wait for the storage callback before verifying stuff + SyncOnMainLoop(); + ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning()); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + /* Inject Service Changed */ + InjectServiceChangedEvent(test_address1, 0xffff); + SyncOnMainLoop(); + InjectServiceChangedEvent(test_address0, 0xffff); + SyncOnMainLoop(); + /* Stack should rediscover services as storage is broken */ + EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(2, _)).Times(1); + EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(1, _)).Times(1); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address1)) + .Times(1); + + /* For background connect, test needs to Inject Connected Event */ + InjectConnectedEvent(test_address0, 1); + InjectConnectedEvent(test_address1, 2); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); +} + +TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) { + // Prepare two devices + uint8_t group_size = 1; + + // Device 0 + uint8_t group_id0 = 2; + bool autoconnect0 = true; + const RawAddress test_address0 = GetTestAddress(0); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + true, /*add_ascs*/ + group_size, 1); + + ON_CALL(mock_groups_module_, GetGroupId(test_address0, _)) + .WillByDefault(DoAll(Return(group_id0))); + + // Device 1 + uint8_t group_id1 = 3; + bool autoconnect1 = false; + const RawAddress test_address1 = GetTestAddress(1); + SetSampleDatabaseEarbudsValid( + 2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt, /*add_ascs_cnt*/ + group_size, 2); + + ON_CALL(mock_groups_module_, GetGroupId(test_address1, _)) + .WillByDefault(DoAll(Return(group_id1))); + + /* Commont storage values */ + std::vector handles; + LeAudioClient::GetHandlesForStorage(test_address0, handles); + + std::vector ases; + LeAudioClient::GetAsesForStorage(test_address0, ases); + + std::vector src_pacs; + LeAudioClient::GetSourcePacsForStorage(test_address0, src_pacs); + + std::vector snk_pacs; + LeAudioClient::GetSinkPacsForStorage(test_address0, snk_pacs); + + // Load devices from the storage when storage API is called + EXPECT_CALL(mock_storage_load, Call()).WillOnce([&]() { + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::AddFromStorage, test_address0, + autoconnect0, codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, 0xff, 0xff, + std::move(handles), std::move(snk_pacs), + std::move(src_pacs), std::move(ases))); + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::AddFromStorage, test_address1, + autoconnect1, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, 0xff, 0xff, + std::move(handles), std::move(snk_pacs), + std::move(src_pacs), std::move(ases))); + }); + + // Expect stored device0 to connect automatically + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) + .WillByDefault(DoAll(Return(true))); + + // First device will got connected + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + + // Expect stored device1 to NOT connect automatically + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address1)) + .Times(0); + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address1, _)) + .WillByDefault(DoAll(Return(true))); + + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address1, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(0); + + // Initialize + BtaAppRegisterCallback app_register_callback; + ON_CALL(mock_gatt_interface_, AppRegister(_, _, _)) + .WillByDefault(DoAll(SaveArg<0>(&gatt_callback), + SaveArg<1>(&app_register_callback))); + std::vector<::bluetooth::le_audio::btle_audio_codec_config_t> + framework_encode_preference; + LeAudioClient::Initialize( + &mock_audio_hal_client_callbacks_, + base::Bind([](MockFunction* foo) { foo->Call(); }, + &mock_storage_load), + base::Bind([](MockFunction* foo) { return foo->Call(); }, + &mock_hal_2_1_verifier), + framework_encode_preference); + if (app_register_callback) app_register_callback.Run(gatt_if, GATT_SUCCESS); + + // We need to wait for the storage callback before verifying stuff + SyncOnMainLoop(); + ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning()); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + // Simulate device is not there and phone fallbacks to targeted announcements + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + + // Devices 0 is connected. Disconnect it + InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + + /* Keep device in Getting Ready state */ + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) + .WillByDefault(DoAll(Return(false))); + ON_CALL(mock_btm_interface_, SetEncryption(test_address0, _, _, _, _)) + .WillByDefault(Return(BTM_SUCCESS)); + + /* For background connect, test needs to Inject Connected Event */ + InjectConnectedEvent(test_address0, 1); + + // We need to wait for the storage callback before verifying stuff + SyncOnMainLoop(); + ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning()); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + std::vector devs = + LeAudioClient::Get()->GetGroupDevices(group_id0); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); + ASSERT_EQ(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + + devs = LeAudioClient::Get()->GetGroupDevices(group_id1); + ASSERT_EQ(std::find(devs.begin(), devs.end(), test_address0), devs.end()); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + + /* Disconnects while being in getting ready state */ + DisconnectLeAudioWithGattClose(test_address0, 1); +} + +TEST_F(UnicastTest, GroupingAddRemove) { + // Earbud connects without known grouping + uint8_t group_id0 = bluetooth::groups::kGroupUnknown; + const RawAddress test_address0 = GetTestAddress(0); + + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectNonCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft); + + group_id0 = MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address0); + + // Earbud connects without known grouping + uint8_t group_id1 = bluetooth::groups::kGroupUnknown; + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectNonCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight); + + group_id1 = MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address1); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + + // Verify individual groups + ASSERT_NE(group_id0, bluetooth::groups::kGroupUnknown); + ASSERT_NE(group_id1, bluetooth::groups::kGroupUnknown); + ASSERT_NE(group_id0, group_id1); + ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id0).size(), 1u); + ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id1).size(), 1u); + + // Expectations on reassigning second earbud to the first group + int dev1_storage_group = bluetooth::groups::kGroupUnknown; + int dev1_new_group = bluetooth::groups::kGroupUnknown; + + EXPECT_CALL( + mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address1, group_id1, GroupNodeStatus::REMOVED)) + .Times(AtLeast(1)); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address1, _, GroupNodeStatus::ADDED)) + .WillRepeatedly(SaveArg<1>(&dev1_new_group)); + EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address1, group_id1)) + .Times(AtLeast(1)); + EXPECT_CALL(mock_groups_module_, AddDevice(test_address1, _, _)) + .Times(AnyNumber()); + + LeAudioClient::Get()->GroupRemoveNode(group_id1, test_address1); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_groups_module_); + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + + EXPECT_CALL(mock_groups_module_, AddDevice(test_address1, _, group_id0)) + .Times(1); + + LeAudioClient::Get()->GroupAddNode(group_id0, test_address1); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_groups_module_); + + dev1_storage_group = + MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address1); + + // Verify regrouping results + EXPECT_EQ(dev1_new_group, group_id0); + EXPECT_EQ(dev1_new_group, dev1_storage_group); + ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id1).size(), 0u); + ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id0).size(), 2u); + std::vector devs = + LeAudioClient::Get()->GetGroupDevices(group_id0); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); +} + +TEST_F(UnicastTest, DoubleResumeFromAF) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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); + + constexpr int gmcs_ccid = 1; + constexpr int gtbs_ccid = 2; + + // Audio sessions are started only when device gets active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + + block_streaming_state_callback = true; + + UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC); + LocalAudioSourceResume(false); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Additional resume shall be ignored. + LocalAudioSourceResume(false, false); + + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); + + do_in_main_thread( + FROM_HERE, + base::BindOnce( + [](int group_id, le_audio::LeAudioGroupStateMachine::Callbacks* + state_machine_callbacks) { + state_machine_callbacks->StatusReportCb( + group_id, GroupStreamStatus::STREAMING); + }, + group_id, base::Unretained(state_machine_callbacks_))); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + + // Verify Data transfer on one audio source cis + constexpr uint8_t cis_count_out = 1; + constexpr uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); +} + +TEST_F(UnicastTest, DoubleResumeFromAFOnLocalSink) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + default_channel_cnt = 1; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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(); + + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1); + + block_streaming_state_callback = true; + + UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC); + LocalAudioSinkResume(); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + EXPECT_CALL(*mock_le_audio_sink_hal_client_, CancelStreamingRequest()) + .Times(0); + + // Actuall test here: send additional resume which shall be ignored. + LocalAudioSinkResume(); + + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); + + do_in_main_thread( + FROM_HERE, + base::BindOnce( + [](int group_id, le_audio::LeAudioGroupStateMachine::Callbacks* + state_machine_callbacks) { + state_machine_callbacks->StatusReportCb( + group_id, GroupStreamStatus::STREAMING); + }, + group_id, base::Unretained(state_machine_callbacks_))); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + + // Verify Data transfer on local audio sink which is started + constexpr uint8_t cis_count_out = 0; + constexpr uint8_t cis_count_in = 1; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 0, 40); +} + +TEST_F(UnicastTest, HandleResumeWithoutMetadataUpdateOnLocalSink) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + /** + * In this test we want to make sure that if MetadataUpdate is + * not called before Resume, but the context type is supported, + * stream should be created + */ + + default_channel_cnt = 1; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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(); + + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1); + + UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC); + LocalAudioSinkResume(); + + 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 local audio sink which is started + constexpr uint8_t cis_count_out = 0; + constexpr uint8_t cis_count_in = 1; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 0, 40); + + SyncOnMainLoop(); + /* Clear cache by changing context types, this is required for the test + * as setting active device actually generate cache + */ + auto sink_available_context = types::kLeAudioContextAllRemoteSinkOnly; + auto source_available_context = types::kLeAudioContextAllRemoteSource; + InjectAvailableContextTypes(test_address0, 1, sink_available_context, + source_available_context); + + StopStreaming(group_id, true); + SyncOnMainLoop(); + + // simulate suspend timeout passed, alarm executing + fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); + SyncOnMainLoop(); + + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1); + + // Resume without metadata update while cached configuration is cleared + LocalAudioSinkResume(); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); +} + +TEST_F(UnicastTest, RemoveNodeWhileStreaming) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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); + + // Start streaming + constexpr uint8_t cis_count_out = 1; + constexpr uint8_t cis_count_in = 0; + + constexpr int gmcs_ccid = 1; + constexpr int gtbs_ccid = 2; + + // Audio sessions are started only when device gets active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + SyncOnMainLoop(); + + // Verify Data transfer on one audio source cis + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address0, group_id)) + .Times(1); + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); + EXPECT_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _)) + .Times(1); + EXPECT_CALL( + mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, group_id, GroupNodeStatus::REMOVED)); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); + + LeAudioClient::Get()->GroupRemoveNode(group_id, test_address0); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_groups_module_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); +} + +TEST_F(UnicastTest, InactiveDeviceOnInternalStateMachineError) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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); + + // Start streaming + constexpr uint8_t cis_count_out = 1; + constexpr uint8_t cis_count_in = 0; + + constexpr int gmcs_ccid = 1; + constexpr int gtbs_ccid = 2; + + // Audio sessions are started only when device gets active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + SyncOnMainLoop(); + + // Verify Data transfer on one audio source cis + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupStatus(group_id, GroupStatus::INACTIVE)) + .Times(1); + + /* This is internal error of the state machine */ + state_machine_callbacks_->StatusReportCb(group_id, + GroupStreamStatus::RELEASING); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); +} + +TEST_F(UnicastTest, GroupingAddTwiceNoRemove) { + // Earbud connects without known grouping + uint8_t group_id0 = bluetooth::groups::kGroupUnknown; + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .WillOnce(Return()) + .RetiresOnSaturation(); + ConnectNonCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft); + + group_id0 = MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address0); + + // Earbud connects without known grouping + uint8_t group_id1 = bluetooth::groups::kGroupUnknown; + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .WillOnce(Return()) + .RetiresOnSaturation(); + ConnectNonCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + + group_id1 = MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address1); + // Verify individual groups + ASSERT_NE(group_id0, bluetooth::groups::kGroupUnknown); + ASSERT_NE(group_id1, bluetooth::groups::kGroupUnknown); + ASSERT_NE(group_id0, group_id1); + ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id0).size(), 1u); + ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id1).size(), 1u); + + // Expectations on reassigning second earbud to the first group + int dev1_storage_group = bluetooth::groups::kGroupUnknown; + int dev1_new_group = bluetooth::groups::kGroupUnknown; + + EXPECT_CALL( + mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address1, group_id1, GroupNodeStatus::REMOVED)) + .Times(AtLeast(1)); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address1, _, GroupNodeStatus::ADDED)) + .WillRepeatedly(SaveArg<1>(&dev1_new_group)); + + // FIXME: We should expect removal with group_id context. No such API exists. + EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address1, group_id1)) + .Times(AtLeast(1)); + EXPECT_CALL(mock_groups_module_, AddDevice(test_address1, _, _)) + .Times(AnyNumber()); + EXPECT_CALL(mock_groups_module_, AddDevice(test_address1, _, group_id0)) + .Times(1); + + // Regroup device: assign new group without removing it from the first one + LeAudioClient::Get()->GroupAddNode(group_id0, test_address1); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_groups_module_); + + dev1_storage_group = + MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address1); + + // Verify regrouping results + EXPECT_EQ(dev1_new_group, group_id0); + EXPECT_EQ(dev1_new_group, dev1_storage_group); + ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id1).size(), 0u); + ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id0).size(), 2u); + std::vector devs = + LeAudioClient::Get()->GetGroupDevices(group_id0); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); +} + +TEST_F(UnicastTest, RemoveTwoEarbudsCsisGrouped) { + uint8_t group_size = 2; + int group_id0 = 2; + int group_id1 = 3; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First group - First earbud + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id0, 1 /* rank*/); + + // First group - Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id0, 2 /* rank*/, true /*connect_through_csis*/); + + // Second group - First earbud + const RawAddress test_address2 = GetTestAddress(2); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address2, true)) + .Times(1); + ConnectCsisDevice(test_address2, 3 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id1, 1 /* rank*/); + + // Second group - Second earbud + const RawAddress test_address3 = GetTestAddress(3); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address3, true)) + .Times(1); + ConnectCsisDevice(test_address3, 4 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id1, 2 /* rank*/, true /*connect_through_csis*/); + + // First group - verify grouping information + std::vector group0_devs = + LeAudioClient::Get()->GetGroupDevices(group_id0); + ASSERT_NE(std::find(group0_devs.begin(), group0_devs.end(), test_address0), + group0_devs.end()); + ASSERT_NE(std::find(group0_devs.begin(), group0_devs.end(), test_address1), + group0_devs.end()); + + // Second group - verify grouping information + std::vector group1_devs = + LeAudioClient::Get()->GetGroupDevices(group_id1); + ASSERT_NE(std::find(group1_devs.begin(), group1_devs.end(), test_address2), + group1_devs.end()); + ASSERT_NE(std::find(group1_devs.begin(), group1_devs.end(), test_address3), + group1_devs.end()); + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + + // Expect one of the groups to be dropped and devices to be disconnected + EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address0, group_id0)) + .Times(1); + EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address1, group_id0)) + .Times(1); + EXPECT_CALL( + mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, group_id0, GroupNodeStatus::REMOVED)); + EXPECT_CALL( + mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address1, group_id0, GroupNodeStatus::REMOVED)); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address1)) + .Times(1); + + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(1, _)).Times(1); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(2, _)).Times(1); + + // Expect the other groups to be left as is + EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupStatus(group_id1, _)) + .Times(0); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address2)) + .Times(0); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address3)) + .Times(0); + + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(3, _)).Times(0); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(4, _)).Times(0); + + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::GroupDestroy, + base::Unretained(LeAudioClient::Get()), group_id0)); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + Mock::VerifyAndClearExpectations(&mock_btm_interface_); +} + +TEST_F(UnicastTest, RemoveDeviceWhenConnected) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + uint16_t conn_id = 1; + + SetSampleDatabaseEarbudsValid( + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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))); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectLeAudio(test_address0); + ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) + .Times(1); + EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1)); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(1, _)).Times(1); + + /* + * StopStream will put calls on main_loop so to keep the correct order + * of operations and to avoid races we put the test command on main_loop as + * well. + */ + do_in_main_thread(FROM_HERE, base::BindOnce( + [](LeAudioClient* client, + const RawAddress& test_address0) { + client->RemoveDevice(test_address0); + }, + LeAudioClient::Get(), test_address0)); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + Mock::VerifyAndClearExpectations(&mock_gatt_queue_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} + +TEST_F(UnicastTest, RemoveDeviceWhenConnecting) { + const RawAddress test_address0 = GetTestAddress(0); + uint16_t conn_id = 1; + + /* Prepare mock to not inject connect event so the device can stay in + * CONNECTING state*/ + ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(DoAll(Return())); + + SetSampleDatabaseEarbudsValid( + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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(0); + ConnectLeAudio(test_address0, true, false); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, _, _)) + .Times(0); + + /* + * StopStream will put calls on main_loop so to keep the correct order + * of operations and to avoid races we put the test command on main_loop as + * well. + */ + do_in_main_thread(FROM_HERE, base::BindOnce( + [](LeAudioClient* client, + const RawAddress& test_address0) { + client->RemoveDevice(test_address0); + }, + LeAudioClient::Get(), test_address0)); + + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} + +TEST_F(UnicastTest, RemoveDeviceWhenGettingConnectionReady) { + const RawAddress test_address0 = GetTestAddress(0); + uint16_t conn_id = 1; + + /* Prepare mock to not inject Service Search Complete*/ + ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)) + .WillByDefault(DoAll(Return())); + + SetSampleDatabaseEarbudsValid( + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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(0); + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) + .Times(0); + ConnectLeAudio(test_address0); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1)); + EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1); + + /* Cancel should be called in RemoveDevice */ + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, _, _)) + .Times(0); + + /* + * StopStream will put calls on main_loop so to keep the correct order + * of operations and to avoid races we put the test command on main_loop as + * well. + */ + do_in_main_thread(FROM_HERE, base::BindOnce( + [](LeAudioClient* client, + const RawAddress& test_address0) { + client->RemoveDevice(test_address0); + }, + LeAudioClient::Get(), test_address0)); + + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} + +TEST_F(UnicastTest, DisconnectDeviceWhenConnected) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + uint16_t conn_id = 1; + + SetSampleDatabaseEarbudsValid( + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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))); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectLeAudio(test_address0); + ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + /* for Target announcements AutoConnect is always there, until + * device is removed + */ + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) + .Times(0); + EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1)); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(1, _)).Times(1); + + LeAudioClient::Get()->Disconnect(test_address0); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + Mock::VerifyAndClearExpectations(&mock_gatt_queue_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} + +TEST_F(UnicastTest, DisconnectDeviceWhenConnecting) { + const RawAddress test_address0 = GetTestAddress(0); + uint16_t conn_id = 1; + + /* Prepare mock to not inject connect event so the device can stay in + * CONNECTING state*/ + ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(DoAll(Return())); + + SetSampleDatabaseEarbudsValid( + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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(0); + ConnectLeAudio(test_address0, true, false); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + /* Prepare on call mock on Close - to not trigger Inject Disconnection, as it + * is done in default mock. + */ + ON_CALL(mock_gatt_interface_, Close(_)).WillByDefault(DoAll(Return())); + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, _, _)) + .Times(0); + + LeAudioClient::Get()->Disconnect(test_address0); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} + +TEST_F(UnicastTest, DisconnectDeviceWhenGettingConnectionReady) { + const RawAddress test_address0 = GetTestAddress(0); + uint16_t conn_id = global_conn_id; + + /* Prepare mock to not inject Service Search Complete*/ + ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)) + .WillByDefault(DoAll(Return())); + + SetSampleDatabaseEarbudsValid( + conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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(0); + ConnectLeAudio(test_address0); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + /* TA reconnect is enabled in ConnectLeAudio. Make sure this is not removed */ + EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1)); + EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1); + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)) + .Times(0); + EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, _, _)) + .Times(0); + + LeAudioClient::Get()->Disconnect(test_address0); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_gatt_queue_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} + +TEST_F(UnicastTest, RemoveWhileStreaming) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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); + + // Start streaming + constexpr uint8_t cis_count_out = 1; + constexpr uint8_t cis_count_in = 0; + + constexpr int gmcs_ccid = 1; + constexpr int gtbs_ccid = 2; + + // Audio sessions are started only when device gets active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + SyncOnMainLoop(); + + // Verify Data transfer on one audio source cis + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address0, group_id)) + .Times(1); + + LeAudioDeviceGroup* group = nullptr; + EXPECT_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _)) + .WillOnce(DoAll(SaveArg<0>(&group))); + EXPECT_CALL( + mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, group_id, GroupNodeStatus::REMOVED)); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); + + /* + * StopStream will put calls on main_loop so to keep the correct order + * of operations and to avoid races we put the test command on main_loop as + * well. + */ + do_in_main_thread(FROM_HERE, base::BindOnce( + [](LeAudioClient* client, + const RawAddress& test_address0) { + client->RemoveDevice(test_address0); + }, + LeAudioClient::Get(), test_address0)); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_groups_module_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + ASSERT_EQ(group, nullptr); +} + +TEST_F(UnicastTest, DisconnecteWhileAlmostStreaming) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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); + + constexpr int gmcs_ccid = 1; + constexpr int gtbs_ccid = 2; + + // Audio sessions are started only when device gets active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + + /* We want here to CIS be established but device not being yet in streaming + * state + */ + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + SyncOnMainLoop(); + + /* This is test code, which will change the group state to the one which + * is required by test + */ + auto group_inject = streaming_groups.at(group_id); + group_inject->SetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING); + + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); + + LeAudioDeviceGroup* group = nullptr; + EXPECT_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _)) + .WillOnce(DoAll(SaveArg<0>(&group))); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); + + /* + * StopStream will put calls on main_loop so to keep the correct order + * of operations and to avoid races we put the test command on main_loop as + * well. + */ + do_in_main_thread(FROM_HERE, base::BindOnce( + [](LeAudioClient* client, + const RawAddress& test_address0) { + client->Disconnect(test_address0); + }, + LeAudioClient::Get(), test_address0)); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_groups_module_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); +} + +TEST_F(UnicastTest, EarbudsTwsStyleStreaming) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, 0x01, 0x01, 0x0004, + /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, + true /*add_pacs*/, 2 /*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); + + // Start streaming + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + + // 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(); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); + + // Verify Data transfer on one audio source cis + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + // Suspend + /*TODO Need a way to verify STOP */ + LeAudioClient::Get()->GroupSuspend(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Resume + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Stop + StopStreaming(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + // Release + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); + LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); +} + +TEST_F(UnicastTest, SpeakerFailedConversationalStreaming) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + available_src_context_types_ = 0; + supported_src_context_types_ = + available_src_context_types_ | + types::AudioContexts(types::LeAudioContextType::UNSPECIFIED).value(); + available_snk_context_types_ = 0x0004; + supported_snk_context_types_ = + available_snk_context_types_ | + types::AudioContexts(types::LeAudioContextType::UNSPECIFIED).value(); + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, 0, + default_channel_cnt, default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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 + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + /* Nothing to do - expect no crash */ +} + +TEST_F(UnicastTest, SpeakerStreaming) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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); + + // Start streaming + uint8_t cis_count_out = 1; + uint8_t cis_count_in = 0; + + // 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(); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Verify Data transfer on one audio source cis + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + // Suspend + /*TODO Need a way to verify STOP */ + LeAudioClient::Get()->GroupSuspend(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Resume + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Stop + StopStreaming(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + // Release + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); + LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); +} + +TEST_F(UnicastTest, SpeakerStreamingNonDefault) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + /** + * Scenario test steps + * 1. Set group active and stream VOICEASSISTANT + * 2. Suspend group and resume with VOICEASSISTANT + * 3. Stop Stream and make group inactive + * 4. Start stream without setting metadata. + * 5. Verify that UNSPECIFIED context type is used. + */ + + available_snk_context_types_ = (types::LeAudioContextType::VOICEASSISTANTS | + types::LeAudioContextType::MEDIA | + types::LeAudioContextType::UNSPECIFIED) + .value(); + supported_snk_context_types_ = available_snk_context_types_; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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); + + // Start streaming + uint8_t cis_count_out = 1; + uint8_t cis_count_in = 0; + + // 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(); + + StartStreaming(AUDIO_USAGE_ASSISTANT, AUDIO_CONTENT_TYPE_UNKNOWN, group_id); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); + + // Verify Data transfer on one audio source cis + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + // Suspend + /*TODO Need a way to verify STOP */ + LeAudioClient::Get()->GroupSuspend(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Resume + StartStreaming(AUDIO_USAGE_ASSISTANT, AUDIO_CONTENT_TYPE_UNKNOWN, group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Stop + StopStreaming(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + // Release + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); + LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + /* When session is closed, the hal client mocks are freed - get new ones */ + SetUpMockAudioHal(); + /* Expect the previous release to clear the old audio session metadata */ + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + EXPECT_CALL(mock_state_machine_, + StartStream(_, types::LeAudioContextType::VOICEASSISTANTS, _, _)) + .Times(0); + EXPECT_CALL(mock_state_machine_, + StartStream(_, kLeAudioDefaultConfigurationContext, _, _)) + .Times(1); + LocalAudioSourceResume(); +} + +TEST_F(UnicastTest, SpeakerStreamingAutonomousRelease) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, + /* source sample freq 16khz */ 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); + + // Start streaming + 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(); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); + + // Verify Data transfer on one audio source cis + TestAudioDataTransfer(group_id, 1 /* cis_count_out */, 0 /* cis_count_in */, + 1920); + + // Inject the IDLE state as if an autonomous release happened + auto group = streaming_groups.at(group_id); + ASSERT_NE(group, nullptr); + for (LeAudioDevice* device = group->GetFirstDevice(); device != nullptr; + device = group->GetNextDevice(device)) { + for (auto& ase : device->ases_) { + ase.cis_state = types::CisState::IDLE; + ase.data_path_state = types::DataPathState::IDLE; + ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; + InjectCisDisconnected(group_id, ase.cis_conn_hdl); + } + } + + // Verify no Data transfer after the autonomous release + TestAudioDataTransfer(group_id, 0 /* cis_count_out */, 0 /* cis_count_in */, + 1920); +} + +TEST_F(UnicastTest, TwoEarbudsStreaming) { + uint8_t group_size = 2; + int group_id = 2; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + // Start streaming + 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(); + + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH, + group_id); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); + + // Verify Data transfer on two peer sinks and one source + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 2; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); + + // Suspend + LeAudioClient::Get()->GroupSuspend(group_id); + SyncOnMainLoop(); + + // Resume + StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH, + group_id); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Verify Data transfer still works + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); + + auto group = streaming_groups.at(group_id); + + // Stop + StopStreaming(group_id, true); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + // Check if cache configuration is still present + ASSERT_TRUE(group + ->GetCachedCodecConfigurationByDirection( + types::LeAudioContextType::CONVERSATIONAL, + le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_TRUE(group + ->GetCachedCodecConfigurationByDirection( + types::LeAudioContextType::CONVERSATIONAL, + le_audio::types::kLeAudioDirectionSource) + .has_value()); + + // Release + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Stop()).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); + LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Setting group inactive, shall not change cached configuration + ASSERT_TRUE(group + ->GetCachedCodecConfigurationByDirection( + types::LeAudioContextType::CONVERSATIONAL, + le_audio::types::kLeAudioDirectionSink) + .has_value()); + ASSERT_TRUE(group + ->GetCachedCodecConfigurationByDirection( + types::LeAudioContextType::CONVERSATIONAL, + le_audio::types::kLeAudioDirectionSource) + .has_value()); +} + +TEST_F(UnicastTest, StreamingVxAospSampleSound) { + uint8_t group_size = 2; + int group_id = 2; + + /* Test to verify that tag VX_AOSP_SAMPLESOUND is always mapped to + * LeAudioContextType::SOUNDEFFECTS + */ + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + // Start streaming + 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(); + + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Set a test TAG + char test_tag[] = "TEST_TAG2;VX_AOSP_SAMPLESOUND;TEST_TAG1"; + + test_tags_ptr_ = test_tag; + + auto initial_context = types::LeAudioContextType::SOUNDEFFECTS; + types::BidirectionalPair> ccids = {.sink = {}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, initial_context, _, ccids)) + .Times(1); + StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH, + group_id); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); + + // Verify Data transfer on two peer sinks and one source + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 0); +} + +TEST_F(UnicastTest, UpdateActiveAudioConfigForLocalSinkSource) { + uint8_t group_size = 2; + int group_id = 2; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + // Set group as active + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->GroupSetActive(group_id); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Start streaming + EXPECT_CALL(*mock_le_audio_sink_hal_client_, UpdateAudioConfigToHal(_)) + .Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, UpdateAudioConfigToHal(_)) + .Times(1); + EXPECT_CALL(*mock_codec_manager_, UpdateActiveAudioConfig(_, _, _)) + .Times(1) + .WillOnce( + [](const types::BidirectionalPair& stream_params, + types::BidirectionalPair delays_ms, + std::function + update_receiver) { + le_audio::offload_config unicast_cfg; + if (delays_ms.sink != 0) { + update_receiver(unicast_cfg, + le_audio::types::kLeAudioDirectionSink); + } + if (delays_ms.source != 0) { + update_receiver(unicast_cfg, + le_audio::types::kLeAudioDirectionSource); + } + }); + StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH, + group_id); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_le_audio_sink_hal_client_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_codec_manager_); -TEST_F(UnicastTest, RemoveNodeWhileStreaming) { + // Verify Data transfer on two peer sinks and two sources + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 2; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); + + // Suspend + LeAudioClient::Get()->GroupSuspend(group_id); + SyncOnMainLoop(); +} + +TEST_F(UnicastTest, UpdateActiveAudioConfigForLocalSource) { + uint8_t group_size = 2; + int group_id = 2; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud const RawAddress test_address0 = GetTestAddress(0); - int group_id = bluetooth::groups::kGroupUnknown; + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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)) + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) .Times(1); - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) - .WillOnce(DoAll(SaveArg<1>(&group_id))); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); - ConnectLeAudio(test_address0); - ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + // Set group as active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->GroupSetActive(group_id); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); // Start streaming - constexpr uint8_t cis_count_out = 1; - constexpr uint8_t cis_count_in = 0; + EXPECT_CALL(*mock_le_audio_source_hal_client_, UpdateAudioConfigToHal(_)) + .Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, UpdateAudioConfigToHal(_)) + .Times(0); + EXPECT_CALL(*mock_codec_manager_, UpdateActiveAudioConfig(_, _, _)) + .Times(1) + .WillOnce( + [](const types::BidirectionalPair& stream_params, + types::BidirectionalPair delays_ms, + std::function + update_receiver) { + le_audio::offload_config unicast_cfg; + if (delays_ms.sink != 0) { + update_receiver(unicast_cfg, + le_audio::types::kLeAudioDirectionSink); + } + if (delays_ms.source != 0) { + update_receiver(unicast_cfg, + le_audio::types::kLeAudioDirectionSource); + } + }); + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); - constexpr int gmcs_ccid = 1; - constexpr int gtbs_ccid = 2; + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_codec_manager_); - // Audio sessions are started only when device gets active - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1); - LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); - LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + // Verify Data transfer on two peer sinks and no source + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); + + // Suspend + LeAudioClient::Get()->GroupSuspend(group_id); + SyncOnMainLoop(); +} + +TEST_F(UnicastTest, TwoEarbudsStreamingContextSwitchNoReconfigure) { + uint8_t group_size = 2; + int group_id = 2; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + // Start streaming + 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(); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, - .source = {}}; - EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + // Start streaming with new metadata, there was no previous stream so start + // with this new configuration + auto initial_context = types::LeAudioContextType::NOTIFICATIONS; + types::BidirectionalPair contexts = { + .sink = types::AudioContexts(initial_context), + .source = types::AudioContexts()}; + EXPECT_CALL(mock_state_machine_, StartStream(_, initial_context, contexts, _)) + .Times(1); - StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + StartStreaming(AUDIO_USAGE_NOTIFICATION, AUDIO_CONTENT_TYPE_UNKNOWN, + group_id); SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - Mock::VerifyAndClearExpectations(&mock_state_machine_); + + // Do a metadata content switch to ALERTS but stay on previous configuration + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(0); + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop).Times(0); + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start).Times(0); + contexts = {.sink = types::AudioContexts(types::LeAudioContextType::ALERTS), + .source = types::AudioContexts()}; + EXPECT_CALL(mock_state_machine_, StartStream(_, initial_context, contexts, _)) + .Times(1); + UpdateLocalSourceMetadata(AUDIO_USAGE_ALARM, AUDIO_CONTENT_TYPE_UNKNOWN); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - // Verify Data transfer on one audio source cis - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + // Do a metadata content switch to EMERGENCY but stay on previous + // configuration + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(0); + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop).Times(0); + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start).Times(0); - EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address0, group_id)) + contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::EMERGENCYALARM), + .source = types::AudioContexts()}; + EXPECT_CALL(mock_state_machine_, StartStream(_, initial_context, contexts, _)) .Times(1); - EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); - EXPECT_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _)) - .Times(0); - EXPECT_CALL( - mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address0, group_id, GroupNodeStatus::REMOVED)); - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) - .Times(0); + UpdateLocalSourceMetadata(AUDIO_USAGE_EMERGENCY, AUDIO_CONTENT_TYPE_UNKNOWN); - LeAudioClient::Get()->GroupRemoveNode(group_id, test_address0); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Do a metadata content switch to INSTRUCTIONAL but stay on previous + // configuration + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(0); + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop).Times(0); + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start).Times(0); + contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::INSTRUCTIONAL), + .source = types::AudioContexts()}; + EXPECT_CALL(mock_state_machine_, StartStream(_, initial_context, contexts, _)) + .Times(1); + UpdateLocalSourceMetadata(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, + AUDIO_CONTENT_TYPE_UNKNOWN); SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_groups_module_); - Mock::VerifyAndClearExpectations(&mock_state_machine_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); } -TEST_F(UnicastTest, GroupingAddTwiceNoRemove) { - // Earbud connects without known grouping - uint8_t group_id0 = bluetooth::groups::kGroupUnknown; +TEST_F(UnicastTest, TwoEarbudsStreamingContextSwitchReconfigure) { + uint8_t group_size = 2; + int group_id = 2; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud const RawAddress test_address0 = GetTestAddress(0); EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) - .WillOnce(Return()) - .RetiresOnSaturation(); - ConnectNonCsisDevice(test_address0, 1 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft); - - group_id0 = MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address0); + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - // Earbud connects without known grouping - uint8_t group_id1 = bluetooth::groups::kGroupUnknown; + // Second earbud const RawAddress test_address1 = GetTestAddress(1); EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) - .WillOnce(Return()) - .RetiresOnSaturation(); - ConnectNonCsisDevice(test_address1, 2 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight); + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); + constexpr int gmcs_ccid = 1; + constexpr int gtbs_ccid = 2; - group_id1 = MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address1); - // Verify individual groups - ASSERT_NE(group_id0, bluetooth::groups::kGroupUnknown); - ASSERT_NE(group_id1, bluetooth::groups::kGroupUnknown); - ASSERT_NE(group_id0, group_id1); - ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id0).size(), 1u); - ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id1).size(), 1u); + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); - // Expectations on reassigning second earbud to the first group - int dev1_storage_group = bluetooth::groups::kGroupUnknown; - int dev1_new_group = bluetooth::groups::kGroupUnknown; + // Start streaming MEDIA + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); - EXPECT_CALL( - mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address1, group_id1, GroupNodeStatus::REMOVED)) - .Times(AtLeast(1)); - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address1, _, GroupNodeStatus::ADDED)) - .WillRepeatedly(SaveArg<1>(&dev1_new_group)); + types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); - // FIXME: We should expect removal with group_id context. No such API exists. - EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address1, group_id1)) + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Verify Data transfer on two peer sinks + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + // Stop + StopStreaming(group_id); + // simulate suspend timeout passed, alarm executing + fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + // SetInCall is used by GTBS - and only then we can expect CCID to be set. + LeAudioClient::Get()->SetInCall(true); + + // Conversational is a bidirectional scenario so expect GTBS CCID + // in the metadata for both directions. Can be called twice when one + // direction resume after the other and metadata is updated. + ccids = {.sink = {gtbs_ccid}, .source = {gtbs_ccid}}; + EXPECT_CALL( + mock_state_machine_, + StartStream(_, types::LeAudioContextType::CONVERSATIONAL, _, ccids)) .Times(AtLeast(1)); - EXPECT_CALL(mock_groups_module_, AddDevice(test_address1, _, _)) - .Times(AnyNumber()); - EXPECT_CALL(mock_groups_module_, AddDevice(test_address1, _, group_id0)) - .Times(1); + StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH, + group_id); - // Regroup device: assign new group without removing it from the first one - LeAudioClient::Get()->GroupAddNode(group_id0, test_address1); SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_groups_module_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - dev1_storage_group = - MockDeviceGroups::DeviceGroups::Get()->GetGroupId(test_address1); + // Verify Data transfer on two peer sinks and one source + cis_count_out = 2; + cis_count_in = 2; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); - // Verify regrouping results - EXPECT_EQ(dev1_new_group, group_id0); - EXPECT_EQ(dev1_new_group, dev1_storage_group); - ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id1).size(), 0u); - ASSERT_EQ(LeAudioClient::Get()->GetGroupDevices(group_id0).size(), 2u); - std::vector devs = - LeAudioClient::Get()->GetGroupDevices(group_id0); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); - ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + LeAudioClient::Get()->SetInCall(false); + // Stop + StopStreaming(group_id, true); + + // Switch back to MEDIA + ccids = {.sink = {gmcs_ccid}, .source = {}}; + types::BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::MEDIA), + .source = types::AudioContexts()}; + EXPECT_CALL(mock_state_machine_, + ConfigureStream(_, le_audio::types::LeAudioContextType::MEDIA, + contexts, ccids)) + .Times(1); + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, + AUDIO_SOURCE_INVALID, true); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); } -TEST_F(UnicastTest, RemoveTwoEarbudsCsisGrouped) { +TEST_F(UnicastTest, TwoEarbudsVoipStreamingVerifyMetadataUpdate) { uint8_t group_size = 2; - int group_id0 = 2; - int group_id1 = 3; + int group_id = 2; + + /* + * Scenario + * 1. Configure stream for the VOIP + * 2. Verify CONVERSATIONAL metadata and context is used. + * 3. Resume LocalSink + * 4. Make sure there is no change of the metadata and context + */ // Report working CSIS ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) .WillByDefault(Return(true)); - // First group - First earbud + // First earbud const RawAddress test_address0 = GetTestAddress(0); EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) .Times(1); ConnectCsisDevice(test_address0, 1 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontLeft, codec_spec_conf::kLeAudioLocationFrontLeft, group_size, - group_id0, 1 /* rank*/); + group_id, 1 /* rank*/); - // First group - Second earbud + // Second earbud const RawAddress test_address1 = GetTestAddress(1); EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) .Times(1); ConnectCsisDevice(test_address1, 2 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontRight, codec_spec_conf::kLeAudioLocationFrontRight, group_size, - group_id0, 2 /* rank*/, true /*connect_through_csis*/); - - // Second group - First earbud - const RawAddress test_address2 = GetTestAddress(2); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address2, true)) - .Times(1); - ConnectCsisDevice(test_address2, 3 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft, group_size, - group_id1, 1 /* rank*/); - - // Second group - Second earbud - const RawAddress test_address3 = GetTestAddress(3); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address3, true)) - .Times(1); - ConnectCsisDevice(test_address3, 4 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, group_size, - group_id1, 2 /* rank*/, true /*connect_through_csis*/); + group_id, 2 /* rank*/, true /*connect_through_csis*/); - // First group - verify grouping information - std::vector group0_devs = - LeAudioClient::Get()->GetGroupDevices(group_id0); - ASSERT_NE(std::find(group0_devs.begin(), group0_devs.end(), test_address0), - group0_devs.end()); - ASSERT_NE(std::find(group0_devs.begin(), group0_devs.end(), test_address1), - group0_devs.end()); + constexpr int gtbs_ccid = 2; - // Second group - verify grouping information - std::vector group1_devs = - LeAudioClient::Get()->GetGroupDevices(group_id1); - ASSERT_NE(std::find(group1_devs.begin(), group1_devs.end(), test_address2), - group1_devs.end()); - ASSERT_NE(std::find(group1_devs.begin(), group1_devs.end(), test_address3), - group1_devs.end()); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); - // Expect one of the groups to be dropped and devices to be disconnected - EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address0, group_id0)) - .Times(1); - EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address1, group_id0)) - .Times(1); - EXPECT_CALL( - mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address0, group_id0, GroupNodeStatus::REMOVED)); + // VOIP not using Telecom API has no ccids. + types::BidirectionalPair> ccids = {.sink = {}, + .source = {}}; EXPECT_CALL( - mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address1, group_id0, GroupNodeStatus::REMOVED)); - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) - .Times(1); - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::DISCONNECTED, test_address1)) - .Times(1); + mock_state_machine_, + StartStream(_, types::LeAudioContextType::CONVERSATIONAL, _, ccids)) + .Times(AtLeast(1)); - // Expect the other groups to be left as is - EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupStatus(group_id1, _)) - .Times(0); - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::DISCONNECTED, test_address2)) - .Times(0); - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::DISCONNECTED, test_address3)) - .Times(0); + UpdateLocalSourceMetadata(AUDIO_USAGE_VOICE_COMMUNICATION, + AUDIO_CONTENT_TYPE_SPEECH); + UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC); - do_in_main_thread( - FROM_HERE, base::Bind(&LeAudioClient::GroupDestroy, - base::Unretained(LeAudioClient::Get()), group_id0)); + LocalAudioSourceResume(); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); -} + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); -TEST_F(UnicastTest, RemoveDeviceWhenConnected) { - const RawAddress test_address0 = GetTestAddress(0); - int group_id = bluetooth::groups::kGroupUnknown; - uint16_t conn_id = 1; + // Verify Data transfer are sending. The LocalSink is not yet resumed. + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 0); - SetSampleDatabaseEarbudsValid( - conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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))); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) - .Times(1); - ConnectLeAudio(test_address0); - ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + types::BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL), + .source = + types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL)}; + EXPECT_CALL(mock_state_machine_, + StartStream(_, types::LeAudioContextType::CONVERSATIONAL, + contexts, ccids)) + .Times(AtLeast(1)); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + LocalAudioSinkResume(); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); +} - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) - .Times(1); - EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1)); - EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1); +TEST_F(UnicastTest, TwoReconfigureAndVerifyEnableContextType) { + uint8_t group_size = 2; + int group_id = 2; - /* - * StopStream will put calls on main_loop so to keep the correct order - * of operations and to avoid races we put the test command on main_loop as - * well. + /* Scenario + * 1. Earbuds streaming MEDIA + * 2. Reconfigure to VOIP + * 3. Check if Metadata in Enable command are set to CONVERSATIONAL */ - do_in_main_thread(FROM_HERE, base::BindOnce( - [](LeAudioClient* client, - const RawAddress& test_address0) { - client->RemoveDevice(test_address0); - }, - LeAudioClient::Get(), test_address0)); - SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); - Mock::VerifyAndClearExpectations(&mock_gatt_queue_); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); -} + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); -TEST_F(UnicastTest, RemoveDeviceWhenConnecting) { + // First earbud const RawAddress test_address0 = GetTestAddress(0); - uint16_t conn_id = 1; + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - /* Prepare mock to not inject connect event so the device can stay in - * CONNECTING state*/ - ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)) - .WillByDefault(DoAll(Return())); + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); - SetSampleDatabaseEarbudsValid( - conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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(0); - ConnectLeAudio(test_address0); + constexpr int gmcs_ccid = 1; + constexpr int gtbs_ccid = 2; - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); - EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true)) - .Times(1); - EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) - .Times(1); + // Start streaming MEDIA + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); - /* - * StopStream will put calls on main_loop so to keep the correct order - * of operations and to avoid races we put the test command on main_loop as - * well. - */ - do_in_main_thread(FROM_HERE, base::BindOnce( - [](LeAudioClient* client, - const RawAddress& test_address0) { - client->RemoveDevice(test_address0); - }, - LeAudioClient::Get(), test_address0)); + // Update metadata on local audio sink + UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC); + + types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); -} + // Verify Data transfer on two peer sinks + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); -TEST_F(UnicastTest, RemoveDeviceWhenGettingConnectionReady) { - const RawAddress test_address0 = GetTestAddress(0); - uint16_t conn_id = 1; + // Conversational is a bidirectional scenario so expect GTBS CCID + // in the metadata for both directions. Can be called twice when one + // direction resume after the other and metadata is updated. + ccids = {.sink = {gtbs_ccid}, .source = {gtbs_ccid}}; + types::BidirectionalPair conversiational_contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL), + .source = + types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL)}; - /* Prepare mock to not inject Service Search Complete*/ - ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)) - .WillByDefault(DoAll(Return())); + EXPECT_CALL( + mock_state_machine_, + ConfigureStream(_, types::LeAudioContextType::CONVERSATIONAL, _, _)) + .Times(AtLeast(1)); - SetSampleDatabaseEarbudsValid( - conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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(0); - ConnectLeAudio(test_address0); + // Update metadata and resume + UpdateLocalSourceMetadata(AUDIO_USAGE_VOICE_COMMUNICATION, + AUDIO_CONTENT_TYPE_SPEECH, true); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1)); - EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1); - EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) - .Times(1); + EXPECT_CALL(mock_state_machine_, + StartStream(_, types::LeAudioContextType::CONVERSATIONAL, + conversiational_contexts, ccids)) + .Times(AtLeast(1)); - /* - * StopStream will put calls on main_loop so to keep the correct order - * of operations and to avoid races we put the test command on main_loop as - * well. - */ - do_in_main_thread(FROM_HERE, base::BindOnce( - [](LeAudioClient* client, - const RawAddress& test_address0) { - client->RemoveDevice(test_address0); - }, - LeAudioClient::Get(), test_address0)); + LeAudioClient::Get()->SetInCall(true); + LocalAudioSourceResume(true); SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); } -TEST_F(UnicastTest, DisconnectDeviceWhenConnected) { - const RawAddress test_address0 = GetTestAddress(0); - int group_id = bluetooth::groups::kGroupUnknown; - uint16_t conn_id = 1; +TEST_F(UnicastTest, TwoEarbuds2ndLateConnect) { + uint8_t group_size = 2; + int group_id = 2; - SetSampleDatabaseEarbudsValid( - conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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))); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) - .Times(1); - ConnectLeAudio(test_address0); - ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + const RawAddress test_address0 = GetTestAddress(0); + const RawAddress test_address1 = GetTestAddress(1); - /* for Target announcements AutoConnect is always there, until - * device is removed - */ - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) - .Times(0); - EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1)); - EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1); + // First earbud + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - LeAudioClient::Get()->Disconnect(test_address0); + // Start streaming + 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(); - Mock::VerifyAndClearExpectations(&mock_btif_storage_); - Mock::VerifyAndClearExpectations(&mock_gatt_queue_); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); -} + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); -TEST_F(UnicastTest, DisconnectDeviceWhenConnecting) { - const RawAddress test_address0 = GetTestAddress(0); - uint16_t conn_id = 1; + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); - /* Prepare mock to not inject connect event so the device can stay in - * CONNECTING state*/ - ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)) - .WillByDefault(DoAll(Return())); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); - SetSampleDatabaseEarbudsValid( - conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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(0); - ConnectLeAudio(test_address0); + // Expect one iso channel to be fed with data + uint8_t cis_count_out = 1; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + // Second earbud connects during stream + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); - /* Prepare on call mock on Close - to not trigger Inject Disconnection, as it - * is done in default mock. - */ - ON_CALL(mock_gatt_interface_, Close(_)).WillByDefault(DoAll(Return())); - EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true)) - .Times(1); + cis_count_out = 2; + cis_count_in = 0; - LeAudioClient::Get()->Disconnect(test_address0); + /* The above will trigger reconfiguration. After that Audio Hal action + * is needed to restart the stream */ + LocalAudioSourceResume(); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); } -TEST_F(UnicastTest, DisconnectDeviceWhenGettingConnectionReady) { - const RawAddress test_address0 = GetTestAddress(0); - uint16_t conn_id = global_conn_id; +TEST_F(UnicastTest, + ReconnectedDeviceNotAttachedToStreamBecauseOfNotAvailableContext) { + uint8_t group_size = 2; + int group_id = 2; - /* Prepare mock to not inject Service Search Complete*/ - ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)) - .WillByDefault(DoAll(Return())); + /* Scenario + * 1. Two devices A and B are streaming + * 2. Device A Release ASE and removes all available context types + * 3. Device B keeps streaming + * 4. Device A disconnectes + * 5. Device A reconnect and should not be attached to the stream + */ - SetSampleDatabaseEarbudsValid( - conn_id, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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(0); - ConnectLeAudio(test_address0); + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + const RawAddress test_address0 = GetTestAddress(0); + const RawAddress test_address1 = GetTestAddress(1); - EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1)); - EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1); - EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) - .Times(0); + // First earbud connects + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - LeAudioClient::Get()->Disconnect(test_address0); + // Second earbud connects + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + // Start streaming + 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(); - Mock::VerifyAndClearExpectations(&mock_gatt_queue_); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); -} + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); -TEST_F(UnicastTest, RemoveWhileStreaming) { - const RawAddress test_address0 = GetTestAddress(0); - int group_id = bluetooth::groups::kGroupUnknown; + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); - SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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))); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); - ConnectLeAudio(test_address0); - ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + // Expect two iso channel to be fed with data + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); - // Start streaming - constexpr uint8_t cis_count_out = 1; - constexpr uint8_t cis_count_in = 0; + /* Get group and Device A */ + auto group = streaming_groups.at(group_id); + ASSERT_NE(group, nullptr); + auto device = group->GetFirstDevice(); - constexpr int gmcs_ccid = 1; - constexpr int gtbs_ccid = 2; + /* Simulate available context type being cleared */ + InjectAvailableContextTypes(device->address_, device->conn_id_, + types::AudioContexts(0), types::AudioContexts(0)); - // Audio sessions are started only when device gets active - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1); - LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); - LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); - LeAudioClient::Get()->GroupSetActive(group_id); + /* Simulate ASE releasing and CIS Disconnection */ + for (auto& ase : device->ases_) { + /* Releasing state */ + if (!ase.active) { + continue; + } - types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, - .source = {}}; - EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + std::vector releasing_state = { + ase.id, static_cast( + types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)}; + InjectNotificationEvent(device->address_, device->conn_id_, + ase.hdls.val_hdl, releasing_state); + SyncOnMainLoop(); + InjectCisDisconnected(group_id, ase.cis_conn_hdl); + SyncOnMainLoop(); + } - StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + cis_count_out = 1; + cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + /* Device A will disconnect, and do not reconnect automatically */ + ON_CALL(mock_gatt_interface_, + Open(_, device->address_, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(Return()); + + /* Disconnect first device */ + auto conn_id = device->conn_id_; + InjectDisconnectedEvent(conn_id, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - Mock::VerifyAndClearExpectations(&mock_state_machine_); + + /* For background connect, test needs to Inject Connected Event */ + InjectConnectedEvent(device->address_, conn_id); SyncOnMainLoop(); - // Verify Data transfer on one audio source cis + /* Check single device is streaming */ + cis_count_out = 1; + cis_count_in = 0; TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); +} - EXPECT_CALL(mock_groups_module_, RemoveDevice(test_address0, group_id)) - .Times(1); - - LeAudioDeviceGroup* group = nullptr; - EXPECT_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _)) - .WillOnce(DoAll(SaveArg<0>(&group))); - EXPECT_CALL( - mock_audio_hal_client_callbacks_, - OnGroupNodeStatus(test_address0, group_id, GroupNodeStatus::REMOVED)); - - EXPECT_CALL(mock_audio_hal_client_callbacks_, - OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) - .Times(1); +TEST_F(UnicastTest, TwoEarbuds2ndReleaseAseRemoveAvailableContextAndBack) { + uint8_t group_size = 2; + int group_id = 2; - /* - * StopStream will put calls on main_loop so to keep the correct order - * of operations and to avoid races we put the test command on main_loop as - * well. + /* Scenario + * 1. Two devices A and B are streaming + * 2. Device A Release ASE and removes all available context types + * 3. Device B keeps streaming + * 4. Device A sets available context types + * 5. Device A should be attached to the stream */ - do_in_main_thread(FROM_HERE, base::BindOnce( - [](LeAudioClient* client, - const RawAddress& test_address0) { - client->RemoveDevice(test_address0); - }, - LeAudioClient::Get(), test_address0)); - - SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_groups_module_); - Mock::VerifyAndClearExpectations(&mock_state_machine_); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - ASSERT_NE(group, nullptr); -} + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); -TEST_F(UnicastTest, EarbudsTwsStyleStreaming) { const RawAddress test_address0 = GetTestAddress(0); - int group_id = bluetooth::groups::kGroupUnknown; + const RawAddress test_address1 = GetTestAddress(1); - SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, 0x01, 0x01, 0x0004, - /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, - true /*add_pacs*/, 2 /*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))); + // First earbud connects + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - ConnectLeAudio(test_address0); - ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + // Second earbud connects + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); // Start streaming - uint8_t cis_count_out = 2; - uint8_t cis_count_in = 0; - - // 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); + 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(); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); @@ -3590,358 +6432,627 @@ TEST_F(UnicastTest, EarbudsTwsStyleStreaming) { Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); - // Verify Data transfer on one audio source cis + // Expect two iso channel to be fed with data + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); - // Suspend - /*TODO Need a way to verify STOP */ - LeAudioClient::Get()->GroupSuspend(group_id); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + /* Get group and Device A */ + auto group = streaming_groups.at(group_id); + ASSERT_NE(group, nullptr); + auto device = group->GetFirstDevice(); - // Resume - StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + /* Simulate available context type being cleared */ + InjectAvailableContextTypes(device->address_, device->conn_id_, + types::AudioContexts(0), types::AudioContexts(0)); - // Stop - StopStreaming(group_id); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + /* Simulate ASE releasing and CIS Disconnection */ + for (auto& ase : device->ases_) { + /* Releasing state */ + if (!ase.active) { + continue; + } - // Release - EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); - EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); - LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); -} + std::vector releasing_state = { + ase.id, static_cast( + types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)}; + InjectNotificationEvent(device->address_, device->conn_id_, + ase.hdls.val_hdl, releasing_state); + SyncOnMainLoop(); + InjectCisDisconnected(group_id, ase.cis_conn_hdl); + SyncOnMainLoop(); + } -TEST_F(UnicastTest, SpeakerFailedConversationalStreaming) { - const RawAddress test_address0 = GetTestAddress(0); - int group_id = bluetooth::groups::kGroupUnknown; + cis_count_out = 1; + cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); - supported_src_context_types_ = 0; - supported_snk_context_types_ = 0x0004; + /* Bring back available context types */ + InjectAvailableContextTypes(device->address_, device->conn_id_, + types::kLeAudioContextAllTypes, + types::kLeAudioContextAllTypes); - SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, - 0, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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))); + /* Check both devices are streaming */ + cis_count_out = 2; + cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); +} - ConnectLeAudio(test_address0); - ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); +TEST_F(UnicastTest, StartStream_AvailableContextTypeNotifiedLater) { + uint8_t group_size = 2; + int group_id = 2; - // Audio sessions are started only when device gets active - LeAudioClient::Get()->GroupSetActive(group_id); + available_snk_context_types_ = 0; - /* Nothing to do - expect no crash */ -} + /* Scenario (Devices A and B called "Remote") + * 1. Remote does supports all the context types, but has NO available + * contexts at the beginning + * 2. After connection Remote add Available context types + * 3. Android start stream with MEDIA + * 4. Make sure stream will be started + */ + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); -TEST_F(UnicastTest, SpeakerStreaming) { const RawAddress test_address0 = GetTestAddress(0); - int group_id = bluetooth::groups::kGroupUnknown; + const RawAddress test_address1 = GetTestAddress(1); - SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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))); + // First earbud connects + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - ConnectLeAudio(test_address0); - ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + // Second earbud connects + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); - // Start streaming - uint8_t cis_count_out = 1; - uint8_t cis_count_in = 0; + // Inject Supported and available context types + auto sink_available_contexts = types::kLeAudioContextAllRemoteSinkOnly; + auto source_available_contexts = types::kLeAudioContextAllRemoteSource; - // 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); + InjectAvailableContextTypes(test_address0, 1, sink_available_contexts, + source_available_contexts); + InjectAvailableContextTypes(test_address1, 2, sink_available_contexts, + source_available_contexts); + // Start streaming + 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); - - StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); - - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); - // Verify Data transfer on one audio source cis - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); - // Suspend - /*TODO Need a way to verify STOP */ - LeAudioClient::Get()->GroupSuspend(group_id); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::MEDIA), + .source = types::AudioContexts()}; + + EXPECT_CALL( + mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::MEDIA, contexts, _)) + .Times(1); - // Resume StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - // Stop - StopStreaming(group_id); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - - // Release - EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); - EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); - LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + // Expect two iso channel to be fed with data + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); } -TEST_F(UnicastTest, SpeakerStreamingAutonomousRelease) { +TEST_F(UnicastTest, ModifyContextTypeOnDeviceA_WhileDeviceB_IsDisconnected) { + uint8_t group_size = 2; + int group_id = 2; + + /* Scenario (Device A and B called Remote) + * 1. Remote set does supports all the context types and make them available + * 2. Android start stream with MEDIA, verify it works. + * 3. Android stops the stream + * 4. Device B disconnects + * 5. Device A removes Media from Available Contexts + * 6. Android start stream with MEDIA, verify it will not be started + */ + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + const RawAddress test_address0 = GetTestAddress(0); - int group_id = bluetooth::groups::kGroupUnknown; + const RawAddress test_address1 = GetTestAddress(1); - SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, - default_channel_cnt, 0x0004, - /* source sample freq 16khz */ 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))); + // First earbud connects + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); - ConnectLeAudio(test_address0); - ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + // Second earbud connects + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); // Start streaming - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1); + 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(); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::MEDIA), + .source = types::AudioContexts()}; + + EXPECT_CALL( + mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::MEDIA, contexts, _)) + .Times(1); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + // Expect two iso channel to be fed with data + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + // Stop + StopStreaming(group_id); + // simulate suspend timeout passed, alarm executing + fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Device B got disconnected and will not reconnect. + ON_CALL(mock_gatt_interface_, + Open(_, test_address1, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(Return()); + InjectDisconnectedEvent(2, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); - // Verify Data transfer on one audio source cis - TestAudioDataTransfer(group_id, 1 /* cis_count_out */, 0 /* cis_count_in */, - 1920); + // Device A changes available context type + // Inject Supported and available context types + auto sink_supported_context = types::kLeAudioContextAllRemoteSinkOnly; + sink_supported_context.unset(LeAudioContextType::MEDIA); + sink_supported_context.set(LeAudioContextType::UNSPECIFIED); - // Inject the IDLE state as if an autonomous release happened - auto group = streaming_groups.at(group_id); - ASSERT_NE(group, nullptr); - for (LeAudioDevice* device = group->GetFirstDevice(); device != nullptr; - device = group->GetNextDevice(device)) { - for (auto& ase : device->ases_) { - ase.data_path_state = types::AudioStreamDataPathState::IDLE; - ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; - InjectCisDisconnected(group_id, ase.cis_conn_hdl); - } - } + auto source_supported_context = types::kLeAudioContextAllRemoteSource; + source_supported_context.set(LeAudioContextType::UNSPECIFIED); - // Verify no Data transfer after the autonomous release - TestAudioDataTransfer(group_id, 0 /* cis_count_out */, 0 /* cis_count_in */, - 1920); + InjectSupportedContextTypes(test_address0, 1, sink_supported_context, + source_supported_context); + InjectAvailableContextTypes(test_address0, 1, sink_supported_context, + source_supported_context); + + /* Android starts stream. */ + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(0); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, + AUDIO_SOURCE_INVALID, false, false); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_state_machine_); } -TEST_F(UnicastTest, TwoEarbudsStreaming) { +TEST_F(UnicastTest, StartStreamToUnsupportedContextTypeUsingUnspecified) { uint8_t group_size = 2; int group_id = 2; + /* Scenario (Devices A and B called "Remote") + * 1. Remote does supports all the context types and make them available + * 2. Remote removes SoundEffect from the supported and available context + * types + * 3. Android start stream with SoundEffects + * 4. Make sure stream will be started with Unspecified context type + */ + // Report working CSIS ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) .WillByDefault(Return(true)); - // First earbud const RawAddress test_address0 = GetTestAddress(0); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) - .Times(1); + const RawAddress test_address1 = GetTestAddress(1); + + // First earbud connects ConnectCsisDevice(test_address0, 1 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontLeft, codec_spec_conf::kLeAudioLocationFrontLeft, group_size, group_id, 1 /* rank*/); - // Second earbud - const RawAddress test_address1 = GetTestAddress(1); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) - .Times(1); + // Second earbud connects ConnectCsisDevice(test_address1, 2 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontRight, codec_spec_conf::kLeAudioLocationFrontRight, group_size, group_id, 2 /* rank*/, true /*connect_through_csis*/); + // Inject Supported and available context types + auto sink_supported_context = types::kLeAudioContextAllRemoteSinkOnly; + sink_supported_context.unset(LeAudioContextType::SOUNDEFFECTS); + sink_supported_context.set(LeAudioContextType::UNSPECIFIED); + + auto source_supported_context = types::kLeAudioContextAllRemoteSource; + source_supported_context.set(LeAudioContextType::UNSPECIFIED); + + InjectSupportedContextTypes(test_address0, 1, sink_supported_context, + source_supported_context); + InjectAvailableContextTypes(test_address0, 1, sink_supported_context, + source_supported_context); + InjectSupportedContextTypes(test_address1, 2, sink_supported_context, + source_supported_context); + InjectAvailableContextTypes(test_address1, 2, sink_supported_context, + source_supported_context); + // Start streaming + 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(); + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) .WillByDefault(Invoke([&](int group_id) { return 2; })); - // Start streaming - 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); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED), + .source = types::AudioContexts(0)}; - StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH, - group_id); + EXPECT_CALL(mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::SOUNDEFFECTS, + contexts, _)) + .Times(1); + + StartStreaming(AUDIO_USAGE_ASSISTANCE_SONIFICATION, + AUDIO_CONTENT_TYPE_SONIFICATION, group_id); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); - // Verify Data transfer on two peer sinks and one source + // Expect two iso channel to be fed with data uint8_t cis_count_out = 2; - uint8_t cis_count_in = 2; - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); +} - // Suspend - LeAudioClient::Get()->GroupSuspend(group_id); - SyncOnMainLoop(); +TEST_F(UnicastTest, + StartStreamToUnsupportedContextTypeUnspecifiedNotSupported) { + uint8_t group_size = 2; + int group_id = 2; - // Resume - StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH, - group_id); + /* Scenario (Device A and B called Remote) + * 1. Remote does supports all the context types and make them available + * 2. Remote removes SoundEffect from the Available Context Types + * 3. Remote also removes UNSPECIFIED from the Available Context Types. + * 4. Android start stream with SoundEffects + * 5. Make sure stream will be NOT be started + */ + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + const RawAddress test_address0 = GetTestAddress(0); + const RawAddress test_address1 = GetTestAddress(1); + + // First earbud connects + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + // Second earbud connects + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + // Inject Supported and available context types + auto sink_supported_context = types::kLeAudioContextAllRemoteSinkOnly; + sink_supported_context.unset(LeAudioContextType::SOUNDEFFECTS); + sink_supported_context.set(LeAudioContextType::UNSPECIFIED); + + auto source_supported_context = types::kLeAudioContextAllRemoteSource; + source_supported_context.set(LeAudioContextType::UNSPECIFIED); + + InjectSupportedContextTypes(test_address0, 1, sink_supported_context, + source_supported_context); + InjectSupportedContextTypes(test_address1, 2, sink_supported_context, + source_supported_context); + + auto sink_available_context = sink_supported_context; + sink_available_context.unset(LeAudioContextType::UNSPECIFIED); + + auto source_available_context = source_supported_context; + source_available_context.unset(LeAudioContextType::UNSPECIFIED); + + InjectAvailableContextTypes(test_address0, 1, sink_available_context, + source_available_context); + InjectAvailableContextTypes(test_address1, 2, sink_available_context, + source_available_context); + // Start streaming + 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(); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - // Verify Data transfer still works - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); - // Stop - StopStreaming(group_id, true); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED), + .source = types::AudioContexts()}; - // Release - EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); - EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, Stop()).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); - LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); + EXPECT_CALL(mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::SOUNDEFFECTS, + contexts, _)) + .Times(0); + + StartStreaming(AUDIO_USAGE_ASSISTANCE_SONIFICATION, + AUDIO_CONTENT_TYPE_SONIFICATION, group_id, + AUDIO_SOURCE_INVALID, false, false); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); } -TEST_F(UnicastTest, TwoEarbudsStreamingContextSwitchNoReconfigure) { +TEST_F(UnicastTest, StartStreamToSupportedContextTypeThenMixUnavailable) { uint8_t group_size = 2; int group_id = 2; + /* Scenario (Device A and B called Remote) + * 1. Remote set does supports all the context types and make them available + * 2. Abdriud start stream with MEDIA, verify it works. + * 3. Stream becomes to be mixed with Soundeffect and Media - verify metadata + * update + * 4. Android Stop stream. + * 5. Remote removes SoundEffect from the supported and available context + * types + * 6. Android start stream with MEDIA, verify it works. + * 7. Stream becomes to be mixed with Soundeffect and Media + * 8. Make sure metadata updated does not contain unavailable context + * note: eventually, Audio framework should not give us unwanted context + * types + */ + // Report working CSIS ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) .WillByDefault(Return(true)); - // First earbud const RawAddress test_address0 = GetTestAddress(0); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) - .Times(1); + const RawAddress test_address1 = GetTestAddress(1); + + // First earbud connects ConnectCsisDevice(test_address0, 1 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontLeft, codec_spec_conf::kLeAudioLocationFrontLeft, group_size, group_id, 1 /* rank*/); - // Second earbud - const RawAddress test_address1 = GetTestAddress(1); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) - .Times(1); + // Second earbud connects ConnectCsisDevice(test_address1, 2 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontRight, codec_spec_conf::kLeAudioLocationFrontRight, group_size, group_id, 2 /* rank*/, true /*connect_through_csis*/); - ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) - .WillByDefault(Invoke([&](int group_id) { return 2; })); - // Start streaming - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1); + 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(); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - // Start streaming with new metadata, but use the existing configuration - types::BidirectionalPair contexts = { - .sink = types::AudioContexts(types::LeAudioContextType::NOTIFICATIONS), + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::MEDIA), .source = types::AudioContexts()}; - EXPECT_CALL(mock_state_machine_, - StartStream(_, types::LeAudioContextType::MEDIA, contexts, _)) + + EXPECT_CALL( + mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::MEDIA, contexts, _)) .Times(1); - StartStreaming(AUDIO_USAGE_NOTIFICATION, AUDIO_CONTENT_TYPE_UNKNOWN, - group_id); + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_state_machine_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - // Do a metadata content switch to ALERTS but stay on MEDIA configuration - EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(0); - EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop).Times(0); - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start).Times(0); - contexts = {.sink = types::AudioContexts(types::LeAudioContextType::ALERTS), - .source = types::AudioContexts()}; + auto group = streaming_groups.at(group_id); + + // Expect two iso channel to be fed with data + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + contexts.sink = types::AudioContexts(types::LeAudioContextType::MEDIA | + types::LeAudioContextType::SOUNDEFFECTS); EXPECT_CALL( mock_state_machine_, StartStream(_, le_audio::types::LeAudioContextType::MEDIA, contexts, _)) .Times(1); - UpdateMetadata(AUDIO_USAGE_ALARM, AUDIO_CONTENT_TYPE_UNKNOWN); + /* Simulate metadata update, expect upadate , metadata */ + std::vector tracks = { + {{AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, 0}, + {AUDIO_USAGE_ASSISTANCE_SONIFICATION, AUDIO_CONTENT_TYPE_SONIFICATION, + 0}}}; + UpdateLocalSourceMetadata(tracks); SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - // Do a metadata content switch to EMERGENCY but stay on MEDIA configuration - EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(0); - EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop).Times(0); - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start).Times(0); + /* Stop stream */ + StopStreaming(group_id); + // simulate suspend timeout passed, alarm executing + fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); + SyncOnMainLoop(); - contexts = { - .sink = types::AudioContexts(types::LeAudioContextType::EMERGENCYALARM), - .source = types::AudioContexts()}; + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + // Inject Supported and available context types + auto sink_supported_context = types::kLeAudioContextAllRemoteSinkOnly; + sink_supported_context.unset(LeAudioContextType::SOUNDEFFECTS); + sink_supported_context.set(LeAudioContextType::UNSPECIFIED); + + auto source_supported_context = types::kLeAudioContextAllRemoteSource; + source_supported_context.set(LeAudioContextType::UNSPECIFIED); + + InjectSupportedContextTypes(test_address0, 1, sink_supported_context, + source_supported_context); + InjectAvailableContextTypes(test_address0, 1, sink_supported_context, + source_supported_context); + InjectSupportedContextTypes(test_address1, 2, sink_supported_context, + source_supported_context); + InjectAvailableContextTypes(test_address1, 2, sink_supported_context, + source_supported_context); + + // Verify cache has been removed due to available context change + ASSERT_FALSE(group + ->GetCachedCodecConfigurationByDirection( + types::LeAudioContextType::MEDIA, + le_audio::types::kLeAudioDirectionSink) + .has_value()); + /* Start Media again */ + contexts.sink = types::AudioContexts(types::LeAudioContextType::MEDIA); EXPECT_CALL( mock_state_machine_, StartStream(_, le_audio::types::LeAudioContextType::MEDIA, contexts, _)) .Times(1); - UpdateMetadata(AUDIO_USAGE_EMERGENCY, AUDIO_CONTENT_TYPE_UNKNOWN); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); SyncOnMainLoop(); + + ASSERT_TRUE(group + ->GetCachedCodecConfigurationByDirection( + types::LeAudioContextType::MEDIA, + le_audio::types::kLeAudioDirectionSink) + .has_value()); + + Mock::VerifyAndClearExpectations(&mock_state_machine_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - // Do a metadata content switch to INSTRUCTIONAL but stay on MEDIA - // configuration - EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(0); - EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop).Times(0); - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start).Times(0); - contexts = { - .sink = types::AudioContexts(types::LeAudioContextType::INSTRUCTIONAL), - .source = types::AudioContexts()}; + // Expect two iso channel to be fed with data + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + /* Update metadata, and do not expect new context type*/ EXPECT_CALL( mock_state_machine_, StartStream(_, le_audio::types::LeAudioContextType::MEDIA, contexts, _)) .Times(1); - UpdateMetadata(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, - AUDIO_CONTENT_TYPE_UNKNOWN); + /* Simulate metadata update */ + UpdateLocalSourceMetadata(tracks); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); +} + +TEST_F(UnicastTest, TwoEarbuds2ndDisconnected) { + uint8_t group_size = 2; + int group_id = 2; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud + const RawAddress test_address0 = GetTestAddress(0); + ConnectCsisDevice(test_address0, 1 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + // Audio sessions are started only when device gets active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + auto group = streaming_groups.at(group_id); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); + ASSERT_EQ(2, group->NumOfConnected()); + + // Expect two iso channels to be fed with data + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + // Disconnect one device and expect the group to keep on streaming + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); + auto device = group->GetFirstDevice(); + for (auto& ase : device->ases_) { + InjectCisDisconnected(group_id, ase.cis_conn_hdl); + } + + /* Disconnect ACL and do not reconnect. */ + ON_CALL(mock_gatt_interface_, + Open(_, device->address_, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(Return()); + EXPECT_CALL(mock_gatt_interface_, + Open(_, device->address_, BTM_BLE_DIRECT_CONNECTION, false)) + .Times(1); + + // Record NumOfConnected when groupStateMachine_ gets notified about the + // disconnection + int num_of_connected = 0; + ON_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _)) + .WillByDefault([&num_of_connected](LeAudioDeviceGroup* group, + LeAudioDevice* leAudioDevice) { + num_of_connected = group->NumOfConnected(); + }); + + auto conn_id = device->conn_id_; + InjectDisconnectedEvent(device->conn_id_, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); + + // Make sure the state machine knows about the disconnected device + ASSERT_EQ(1, num_of_connected); + + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Expect one channel ISO Data to be sent + cis_count_out = 1; + cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + InjectConnectedEvent(device->address_, conn_id); + SyncOnMainLoop(); + + // Expect two iso channels to be fed with data + cis_count_out = 2; + cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); } -TEST_F(UnicastTest, TwoEarbudsStreamingContextSwitchReconfigure) { +TEST_F(UnicastTest, TwoEarbudsStreamingProfileDisconnect) { uint8_t group_size = 2; int group_id = 2; @@ -3951,8 +7062,6 @@ TEST_F(UnicastTest, TwoEarbudsStreamingContextSwitchReconfigure) { // First earbud const RawAddress test_address0 = GetTestAddress(0); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) - .Times(1); ConnectCsisDevice(test_address0, 1 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontLeft, codec_spec_conf::kLeAudioLocationFrontLeft, group_size, @@ -3960,68 +7069,56 @@ TEST_F(UnicastTest, TwoEarbudsStreamingContextSwitchReconfigure) { // Second earbud const RawAddress test_address1 = GetTestAddress(1); - EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) - .Times(1); ConnectCsisDevice(test_address1, 2 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontRight, codec_spec_conf::kLeAudioLocationFrontRight, group_size, group_id, 2 /* rank*/, true /*connect_through_csis*/); - constexpr int gmcs_ccid = 1; - constexpr int gtbs_ccid = 2; - ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) .WillByDefault(Invoke([&](int group_id) { return 2; })); - // Start streaming MEDIA - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1); - LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); - LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + // 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(); - types::BidirectionalPair> ccids = {.sink = {gmcs_ccid}, - .source = {}}; - EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); - SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + SyncOnMainLoop(); - // Verify Data transfer on two peer sinks + // Expect two iso channels to be fed with data uint8_t cis_count_out = 2; uint8_t cis_count_in = 0; TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); - // Stop - StopStreaming(group_id); - // simulate suspend timeout passed, alarm executing - fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); - // Conversational is a bidirectional scenario so expect GTBS CCID - // in the metadata for both directions. Can be called twice when one - // direction resume after the other and metadata is updated. - ccids = {.sink = {gtbs_ccid}, .source = {gtbs_ccid}}; - EXPECT_CALL( - mock_state_machine_, - StartStream(_, types::LeAudioContextType::CONVERSATIONAL, _, ccids)) - .Times(AtLeast(1)); - StartStreaming(AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_CONTENT_TYPE_SPEECH, - group_id); + /* Do not inject OPEN_EVENT by default */ + ON_CALL(mock_gatt_interface_, Open(_, _, _, _)) + .WillByDefault(DoAll(Return())); + ON_CALL(mock_gatt_interface_, Close(_)).WillByDefault(DoAll(Return())); + ON_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)) + .WillByDefault(DoAll(Return())); - SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + DisconnectLeAudioNoDisconnectedEvtExpected(test_address0, 1); + DisconnectLeAudioNoDisconnectedEvtExpected(test_address1, 2); - // Verify Data transfer on two peer sinks and one source - cis_count_out = 2; - cis_count_in = 2; - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); + EXPECT_CALL(mock_gatt_interface_, + Open(_, _, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(2); + + InjectDisconnectedEvent(1); + InjectDisconnectedEvent(2); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); } -TEST_F(UnicastTest, TwoEarbuds2ndLateConnect) { +TEST_F(UnicastTest, TwoEarbudsStreamingProfileDisconnectStreamStopTimeout) { uint8_t group_size = 2; int group_id = 2; @@ -4029,238 +7126,588 @@ TEST_F(UnicastTest, TwoEarbuds2ndLateConnect) { ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) .WillByDefault(Return(true)); - const RawAddress test_address0 = GetTestAddress(0); - const RawAddress test_address1 = GetTestAddress(1); - // First earbud + const RawAddress test_address0 = GetTestAddress(0); ConnectCsisDevice(test_address0, 1 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontLeft, codec_spec_conf::kLeAudioLocationFrontLeft, group_size, group_id, 1 /* rank*/); - // Start streaming - 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); + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) .WillByDefault(Invoke([&](int group_id) { return 2; })); + // Audio sessions are started only when device gets active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); - // Expect one iso channel to be fed with data + // Expect two iso channels to be fed with data + uint8_t cis_count_out = 2; + uint8_t cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + // Expect StopStream to be called before Close or ACL Disconnect is called. + ON_CALL(mock_state_machine_, StopStream(_)) + .WillByDefault([](LeAudioDeviceGroup* group) { + /* Stub the process of stopping stream, just set the target state. + * this simulates issue with stopping the stream + */ + group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + }); + + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(2); + EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(0); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)).Times(0); + + do_in_main_thread( + FROM_HERE, + base::Bind(&LeAudioClient::Disconnect, + base::Unretained(LeAudioClient::Get()), test_address0)); + do_in_main_thread( + FROM_HERE, + base::Bind(&LeAudioClient::Disconnect, + base::Unretained(LeAudioClient::Get()), test_address1)); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_btm_interface_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + + /* Now stream is trying to be stopped and devices are about to be + * disconnected. Simulate stop stream failure and timeout fired. Make sure + * code will not try to do recovery connect + */ + ON_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)) + .WillByDefault(DoAll(Return())); + EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(0); + EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)).Times(2); + + auto group = streaming_groups.at(group_id); + ASSERT_TRUE(group != nullptr); + ASSERT_TRUE(group->NumOfConnected() > 0); + + state_machine_callbacks_->OnStateTransitionTimeout(group_id); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_btm_interface_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + auto device = group->GetFirstDevice(); + ASSERT_TRUE(device != nullptr); + ASSERT_NE(device->GetConnectionState(), + DeviceConnectState::DISCONNECTING_AND_RECOVER); + device = group->GetNextDevice(device); + ASSERT_TRUE(device != nullptr); + ASSERT_NE(device->GetConnectionState(), + DeviceConnectState::DISCONNECTING_AND_RECOVER); +} + +TEST_F(UnicastTest, EarbudsWithStereoSinkMonoSourceSupporting32kHz) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = 0; + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt, + default_channel_cnt, 0x0024, + /* source sample freq 32/16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt /*add_ascs_cnt*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + ConnectLeAudio(test_address0); + + // LeAudioCodecConfiguration received_af_sink_config; + const LeAudioCodecConfiguration expected_af_sink_config = { + .num_channels = 2, + .sample_rate = bluetooth::audio::le_audio::kSampleRate32000, + .bits_per_sample = bluetooth::audio::le_audio::kBitsPerSample16, + .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us, + }; + + // 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(expected_af_sink_config, _, _)) + .Times(1); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); +} + +TEST_F(UnicastTest, TwoEarbudsWithSourceSupporting32kHz) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = 0; + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0024, + /* source sample freq 32/16khz */ true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + default_ase_cnt /*add_ascs_cnt*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + ConnectLeAudio(test_address0); + + // LeAudioCodecConfiguration received_af_sink_config; + const LeAudioCodecConfiguration expected_af_sink_config = { + .num_channels = 2, + .sample_rate = bluetooth::audio::le_audio::kSampleRate32000, + .bits_per_sample = bluetooth::audio::le_audio::kBitsPerSample16, + .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us, + }; + + // 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(expected_af_sink_config, _, _)) + .Times(1); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); +} + +TEST_F(UnicastTest, MicrophoneAttachToCurrentMediaScenario) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, 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(_, le_audio::types::LeAudioContextType::MEDIA, _, _)) + .Times(1); + + StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, + AUDIO_SOURCE_INVALID); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + // Verify Data transfer on one audio source cis uint8_t cis_count_out = 1; uint8_t cis_count_in = 0; TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); - // Second earbud connects during stream - ConnectCsisDevice(test_address1, 2 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, group_size, - group_id, 2 /* rank*/, true /*connect_through_csis*/); + // When the local audio sink resumes we should reconfigure + EXPECT_CALL( + mock_state_machine_, + ConfigureStream(_, le_audio::types::LeAudioContextType::LIVE, _, _)) + .Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, ReconfigurationComplete()) + .Times(1); + + // Update metadata on local audio sink + UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC); + + // Resume on local audio sink + ASSERT_NE(unicast_sink_hal_cb_, nullptr); + do_in_main_thread( + FROM_HERE, + base::BindOnce( + [](LeAudioSinkAudioHalClient::Callbacks* cb) { cb->OnAudioResume(); }, + unicast_sink_hal_cb_)); + + /* The above will trigger reconfiguration. After that Audio Hal action + * is needed to restart the stream */ + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + + LocalAudioSourceResume(); + do_in_main_thread( + FROM_HERE, + base::BindOnce( + [](LeAudioSinkAudioHalClient::Callbacks* cb) { cb->OnAudioResume(); }, + unicast_sink_hal_cb_)); + SyncOnMainLoop(); - cis_count_out = 2; - cis_count_in = 0; + // Verify Data transfer on one audio source and sink cis + cis_count_out = 1; + cis_count_in = 1; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 60); - /* The above will trigger reconfiguration. After that Audio Hal action - * is needed to restart the stream */ - SinkAudioResume(); + // Stop + StopStreaming(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + // Release + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); + do_in_main_thread( + FROM_HERE, base::BindOnce( + [](LeAudioClient* client) { + client->GroupSetActive(bluetooth::groups::kGroupUnknown); + }, + LeAudioClient::Get())); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); } -TEST_F(UnicastTest, TwoEarbuds2ndDisconnected) { - uint8_t group_size = 2; - int group_id = 2; +/* 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 + * What we can do now is to keep streaming (and reconfigure if needed for the + * use case). + */ +TEST_F(UnicastTest, UpdateNotSupportedContextTypeUnspecifiedAvailable) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; - // Report working CSIS - ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) - .WillByDefault(Return(true)); + available_snk_context_types_ = (types::LeAudioContextType::RINGTONE | + types::LeAudioContextType::CONVERSATIONAL | + types::LeAudioContextType::UNSPECIFIED | + types::LeAudioContextType::MEDIA) + .value(); + supported_snk_context_types_ = available_snk_context_types_; + available_src_context_types_ = available_snk_context_types_; + supported_src_context_types_ = available_src_context_types_; - // First earbud - const RawAddress test_address0 = GetTestAddress(0); - ConnectCsisDevice(test_address0, 1 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft, group_size, - group_id, 1 /* rank*/); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, false /*add_csis*/, true /*add_cas*/, + true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, + 0 /*rank*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) + .WillOnce(DoAll(SaveArg<1>(&group_id))); - // Second earbud - const RawAddress test_address1 = GetTestAddress(1); - ConnectCsisDevice(test_address1, 2 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, group_size, - group_id, 2 /* rank*/, true /*connect_through_csis*/); + ConnectLeAudio(test_address0); + ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); - ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) - .WillByDefault(Invoke([&](int group_id) { return 2; })); + // Start streaming + uint8_t cis_count_out = 1; + uint8_t cis_count_in = 0; + + LeAudioClient::Get()->SetInCall(true); // 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); + 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(); - StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); - auto group = streaming_groups.at(group_id); + StartStreaming(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE, + AUDIO_CONTENT_TYPE_UNKNOWN, group_id); + LocalAudioSourceResume(); + LocalAudioSinkResume(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); - ASSERT_EQ(2, group->NumOfConnected()); - // Expect two iso channels to be fed with data - uint8_t cis_count_out = 2; - uint8_t cis_count_in = 0; + // Verify Data transfer on one audio source cis TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); - // Disconnect one device and expect the group to keep on streaming - EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); - auto device = group->GetFirstDevice(); - for (auto& ase : device->ases_) { - InjectCisDisconnected(group_id, ase.cis_conn_hdl); - } + LeAudioClient::Get()->SetInCall(false); + LocalAudioSinkSuspend(); - /* It is called twice. Once with BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, - * and then after delay with BTM_BLE_BKG_CONNECT_ALLOW_LIST + /* We should use GAME configuration, but do not send the GAME context type, as + * it is not available on the remote device. */ - EXPECT_CALL(mock_gatt_interface_, Open(_, device->address_, _, false)) - .Times(2); - - // Record NumOfConnected when groupStateMachine_ gets notified about the - // disconnection - int num_of_connected = 0; - ON_CALL(mock_state_machine_, ProcessHciNotifAclDisconnected(_, _)) - .WillByDefault([&num_of_connected](LeAudioDeviceGroup* group, - LeAudioDevice* leAudioDevice) { - num_of_connected = group->NumOfConnected(); - }); - - auto conn_id = device->conn_id_; - InjectDisconnectedEvent(device->conn_id_, GATT_CONN_TERMINATE_PEER_USER); + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); + types::BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED), + .source = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED)}; + EXPECT_CALL(mock_state_machine_, + StartStream(_, types::LeAudioContextType::GAME, contexts, _)) + .Times(1); + UpdateLocalSourceMetadata(AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_UNKNOWN, + false); SyncOnMainLoop(); +} - // Make sure the state machine knows about the disconnected device - ASSERT_EQ(1, num_of_connected); +/* Some bidirectional scenarios are triggered by the local sink, local source + * metadata or the In Call preference callback call. Since each call invalidates + * previous context source, make sure that getting all of these in a sequence, + * always results with one bidirectional context, so that the remote device + * is not confused about our intentions. + */ +TEST_F(UnicastTest, UpdateMultipleBidirContextTypes) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; - Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + available_snk_context_types_ = + (types::LeAudioContextType::CONVERSATIONAL | + types::LeAudioContextType::GAME | types::LeAudioContextType::LIVE) + .value(); + supported_snk_context_types_ = + available_snk_context_types_ | + types::AudioContexts(types::LeAudioContextType::UNSPECIFIED).value(); + available_src_context_types_ = available_snk_context_types_; + supported_src_context_types_ = + available_src_context_types_ | + types::AudioContexts(types::LeAudioContextType::UNSPECIFIED).value(); - // Expect one channel ISO Data to be sent - cis_count_out = 1; - cis_count_in = 0; - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationAnyLeft, + codec_spec_conf::kLeAudioLocationStereo, 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))); - InjectConnectedEvent(device->address_, conn_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(); - // Expect two iso channels to be fed with data - cis_count_out = 2; - cis_count_in = 0; - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); -} + // When the local audio sink resumes expect only LIVE context + types::BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::LIVE), + .source = types::AudioContexts(types::LeAudioContextType::LIVE)}; + EXPECT_CALL( + mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::LIVE, contexts, _)) + .Times(1); -TEST_F(UnicastTest, TwoEarbudsStreamingProfileDisconnect) { - uint8_t group_size = 2; - int group_id = 2; + // 1) Start the recording. Sink resume will trigger the reconfiguration + // --------------------------------------------------------------------- + ASSERT_NE(nullptr, unicast_sink_hal_cb_); + UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC); + LocalAudioSinkResume(); - // Report working CSIS - ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) - .WillByDefault(Return(true)); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_le_audio_sink_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); - // First earbud - const RawAddress test_address0 = GetTestAddress(0); - ConnectCsisDevice(test_address0, 1 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontLeft, - codec_spec_conf::kLeAudioLocationFrontLeft, group_size, - group_id, 1 /* rank*/); + /* After the reconfiguration the local Audio Sink HAL has to resume again */ + LocalAudioSourceResume(); + LocalAudioSinkResume(); - // Second earbud - const RawAddress test_address1 = GetTestAddress(1); - ConnectCsisDevice(test_address1, 2 /*conn_id*/, - codec_spec_conf::kLeAudioLocationFrontRight, - codec_spec_conf::kLeAudioLocationFrontRight, group_size, - group_id, 2 /* rank*/, true /*connect_through_csis*/); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_le_audio_sink_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); - ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) - .WillByDefault(Invoke([&](int group_id) { return 2; })); + // Verify Data transfer on one audio source and sink cis + uint8_t cis_count_out = 1; + uint8_t cis_count_in = 1; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); - // 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); + // Stop + StopStreaming(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); + // 2) Now set in call preference to get CONVERSATIONAL into the mix + // ----------------------------------------------------------------- + LeAudioClient::Get()->SetInCall(true); + + // Verify that we only got CONVERSATIONAL context and no LIVE + contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL), + .source = + types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL)}; + EXPECT_CALL( + mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::CONVERSATIONAL, + contexts, _)) + .Times(1); + + // Start with ringtone on local source + ASSERT_NE(nullptr, unicast_sink_hal_cb_); + StartStreaming(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE, + AUDIO_CONTENT_TYPE_UNKNOWN, group_id); + + // Resume both directions + LocalAudioSourceResume(); + LocalAudioSinkResume(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); - // Expect two iso channels to be fed with data - uint8_t cis_count_out = 2; - uint8_t cis_count_in = 0; - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + // Verify Data transfer on one audio source cis + cis_count_out = 1; + cis_count_in = 1; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); - EXPECT_CALL(mock_gatt_interface_, - Open(_, _, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + // 3) Disable call so we could go to GAME + // --------------------------------------- + LeAudioClient::Get()->SetInCall(false); + + /* Start the game on local source - expect no previous sink (LIVE) metadata */ + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); + contexts = {.sink = types::AudioContexts(types::LeAudioContextType::GAME), + .source = types::AudioContexts(types::LeAudioContextType::GAME)}; + EXPECT_CALL(mock_state_machine_, + StartStream(_, types::LeAudioContextType::GAME, contexts, _)) .Times(1); - EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); + UpdateLocalSourceMetadata(AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_UNKNOWN, + false); - DisconnectLeAudio(test_address0, 1); - SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + /* If the above triggers reconfiguration, Audio Hal action is needed to + * restart the stream. + */ + LocalAudioSourceResume(); + LocalAudioSinkResume(); Mock::VerifyAndClearExpectations(&mock_state_machine_); - EXPECT_CALL(mock_gatt_interface_, - Open(_, _, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) - .Times(1); - - DisconnectLeAudio(test_address1, 2); + // 4) Stop streaming + // ------------------ + StopStreaming(group_id); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + // Release + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); + do_in_main_thread( + FROM_HERE, base::BindOnce( + [](LeAudioClient* client) { + client->GroupSetActive(bluetooth::groups::kGroupUnknown); + }, + LeAudioClient::Get())); SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); } -TEST_F(UnicastTest, EarbudsWithStereoSinkMonoSourceSupporting32kHz) { +TEST_F(UnicastTest, UpdateDisableLocalAudioSinkOnGame) { const RawAddress test_address0 = GetTestAddress(0); - int group_id = 0; + int group_id = bluetooth::groups::kGroupUnknown; + + available_snk_context_types_ = + (types::LeAudioContextType::CONVERSATIONAL | + types::LeAudioContextType::GAME | types::LeAudioContextType::LIVE) + .value(); + supported_snk_context_types_ = + available_snk_context_types_ | + types::AudioContexts(types::LeAudioContextType::UNSPECIFIED).value(); + available_src_context_types_ = available_snk_context_types_; + supported_src_context_types_ = + available_src_context_types_ | + types::AudioContexts(types::LeAudioContextType::UNSPECIFIED).value(); + SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, - codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt, - default_channel_cnt, 0x0024, - /* source sample freq 32/16khz */ true, /*add_csis*/ - true, /*add_cas*/ - true, /*add_pacs*/ - default_ase_cnt /*add_ascs_cnt*/); + 1, test_address0, codec_spec_conf::kLeAudioLocationAnyLeft, + codec_spec_conf::kLeAudioLocationStereo, 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); - ConnectLeAudio(test_address0); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) + .WillOnce(DoAll(SaveArg<1>(&group_id))); - // LeAudioCodecConfiguration received_af_sink_config; - const LeAudioCodecConfiguration expected_af_sink_config = { - .num_channels = 2, - .sample_rate = bluetooth::audio::le_audio::kSampleRate32000, - .bits_per_sample = bluetooth::audio::le_audio::kBitsPerSample16, - .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us, - }; + 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(expected_af_sink_config, _)) - .Times(1); + 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(); + + // Start GAME stream + types::BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::GAME), + .source = types::AudioContexts(types::LeAudioContextType::GAME)}; + EXPECT_CALL( + mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::GAME, contexts, _)) + .Times(1); + + // 1) Start the recording. Sink resume will trigger the reconfiguration + // --------------------------------------------------------------------- + StartStreaming(AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_MUSIC, group_id, + AUDIO_SOURCE_MIC); + + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_le_audio_sink_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + + // Verify Data transfer on one audio source and sink cis + uint8_t cis_count_out = 1; + uint8_t cis_count_in = 1; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); + + SyncOnMainLoop(); + + // 2) Now Lets suspend MIC and do not expect reconfiguration + // ----------------------------------------------------------------- + + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); + LocalAudioSinkSuspend(); + // simulate suspend timeout passed, alarm executing + fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); } -TEST_F(UnicastTest, MicrophoneAttachToCurrentMediaScenario) { +/* Start music when in a call, end the call, continue with music only */ +TEST_F(UnicastTest, MusicDuringCallContextTypes) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; + available_snk_context_types_ = + (types::LeAudioContextType::CONVERSATIONAL | + types::LeAudioContextType::RINGTONE | types::LeAudioContextType::GAME | + types::LeAudioContextType::MEDIA | types::LeAudioContextType::LIVE) + .value(); + supported_snk_context_types_ = + available_snk_context_types_ | + types::AudioContexts(types::LeAudioContextType::UNSPECIFIED).value(); + available_src_context_types_ = available_snk_context_types_; + supported_src_context_types_ = + available_src_context_types_ | + types::AudioContexts(types::LeAudioContextType::UNSPECIFIED).value(); + SetSampleDatabaseEarbudsValid( - 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + 1, test_address0, codec_spec_conf::kLeAudioLocationAnyLeft, codec_spec_conf::kLeAudioLocationStereo, 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*/, @@ -4276,67 +7723,109 @@ TEST_F(UnicastTest, MicrophoneAttachToCurrentMediaScenario) { 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); + 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(_, le_audio::types::LeAudioContextType::MEDIA, _, _)) + // 1) Start with the call first + // ----------------------------- + // CONVERSATIONAL is from In Call preference, and RINGTONE is from metadata + LeAudioClient::Get()->SetInCall(true); + types::BidirectionalPair contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::RINGTONE | + types::LeAudioContextType::CONVERSATIONAL), + .source = + types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL)}; + EXPECT_CALL( + mock_state_machine_, + StartStream(_, le_audio::types::LeAudioContextType::CONVERSATIONAL, + contexts, _)) .Times(1); + StartStreaming(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE, + AUDIO_CONTENT_TYPE_UNKNOWN, group_id); + LocalAudioSourceResume(); + LocalAudioSinkResume(); - StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, - AUDIO_SOURCE_INVALID); - SyncOnMainLoop(); - + // Verify 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 + // Verify Data transfer uint8_t cis_count_out = 1; - uint8_t cis_count_in = 0; - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + uint8_t cis_count_in = 1; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 40); - // When the local audio sink resumes we should reconfigure + // 2) Start MEDIA during the call, expect MEDIA only on the remote sink + contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL | + types::LeAudioContextType::MEDIA), + .source = + types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL)}; EXPECT_CALL( mock_state_machine_, - ConfigureStream(_, le_audio::types::LeAudioContextType::LIVE, _, _)) - .Times(1); - EXPECT_CALL(*mock_le_audio_source_hal_client_, ReconfigurationComplete()) + StartStream(_, le_audio::types::LeAudioContextType::CONVERSATIONAL, + contexts, _)) .Times(1); + UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, false); + SyncOnMainLoop(); - // Update metadata on local audio sink - UpdateSourceMetadata(AUDIO_SOURCE_MIC); - - // Resume on local audio sink - ASSERT_NE(unicast_sink_hal_cb_, nullptr); - do_in_main_thread( - FROM_HERE, - base::BindOnce( - [](LeAudioSinkAudioHalClient::Callbacks* cb) { cb->OnAudioResume(); }, - unicast_sink_hal_cb_)); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_le_audio_sink_hal_client_); - /* The above will trigger reconfiguration. After that Audio Hal action - * is needed to restart the stream */ - SyncOnMainLoop(); + // 2) Disable In Call preference but do not suspend the local sink + // We should stay in CONVERSATIONAL until the local sink suspends + // --------------------------------------- + LeAudioClient::Get()->SetInCall(false); + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); + contexts = { + .sink = types::AudioContexts(types::LeAudioContextType::MEDIA | + types::LeAudioContextType::CONVERSATIONAL), + .source = + types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL)}; + EXPECT_CALL( + mock_state_machine_, + StartStream(_, types::LeAudioContextType::CONVERSATIONAL, contexts, _)) + .Times(1); + UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, + /*reconfigure=*/false); + Mock::VerifyAndClearExpectations(&mock_state_machine_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_le_audio_sink_hal_client_); + + // 3) Disable call so we could go back to MEDIA + // --------------------------------------- + // Suspend should stop the stream + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); + LocalAudioSourceSuspend(); + LocalAudioSinkSuspend(); + // simulate suspend timeout passed, alarm executing + fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); Mock::VerifyAndClearExpectations(&mock_state_machine_); - SinkAudioResume(); - do_in_main_thread( - FROM_HERE, - base::BindOnce( - [](LeAudioSinkAudioHalClient::Callbacks* cb) { cb->OnAudioResume(); }, - unicast_sink_hal_cb_)); - SyncOnMainLoop(); + // Restart the stream with MEDIA + contexts = {.sink = types::AudioContexts(types::LeAudioContextType::MEDIA), + .source = types::AudioContexts()}; + EXPECT_CALL(mock_state_machine_, + StartStream(_, types::LeAudioContextType::MEDIA, contexts, _)) + .Times(1); + UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, + /*reconfigure=*/false); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_le_audio_sink_hal_client_); - // Verify Data transfer on one audio source and sink cis - cis_count_out = 1; - cis_count_in = 1; - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 60); + /* The source needs to resume to reconfigure to MEDIA */ + LocalAudioSourceResume(/*expect_confirm=*/false); + LocalAudioSourceResume(/*expect_confirm=*/true); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_le_audio_sink_hal_client_); - // Stop + // 4) Stop streaming + // ------------------ StopStreaming(group_id); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); @@ -4350,21 +7839,31 @@ TEST_F(UnicastTest, MicrophoneAttachToCurrentMediaScenario) { client->GroupSetActive(bluetooth::groups::kGroupUnknown); }, LeAudioClient::Get())); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - SyncOnMainLoop(); } -TEST_F(UnicastTest, UpdateNotSupportedContextType) { +/* When a certain context is unavailable but supported we should not stream that + * context - either stop the stream or eliminate this strim from the mix + * This could be na IOP issue so continue streaming (and reconfigure if needed + * for that use case). + * Since the unavailable context is supported, do not put this context into + * the metadata, and do not replace it with UNSPECIFIED. + */ +TEST_F(UnicastTest, StartNotAvailableSupportedContextType) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; - supported_snk_context_types_ = (types::LeAudioContextType::RINGTONE | + // EMERGENCYALARM is not available, but supported + available_snk_context_types_ = (types::LeAudioContextType::RINGTONE | types::LeAudioContextType::CONVERSATIONAL | types::LeAudioContextType::UNSPECIFIED | types::LeAudioContextType::MEDIA) .value(); - supported_src_context_types_ = supported_snk_context_types_; + available_src_context_types_ = available_snk_context_types_; + supported_snk_context_types_ = types::kLeAudioContextAllTypes.value(); + supported_src_context_types_ = (types::kLeAudioContextAllRemoteSource | + types::LeAudioContextType::UNSPECIFIED) + .value(); SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, @@ -4382,58 +7881,105 @@ TEST_F(UnicastTest, UpdateNotSupportedContextType) { ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); - // Start streaming - uint8_t cis_count_out = 1; - uint8_t cis_count_in = 0; - - LeAudioClient::Get()->SetInCall(true); + // Expect configuring to (or staying with) the right configuration but the + // metadata should not get the EMERGENCYALARM context, nor the UNSPECIFIED + // Since the initial config is UNSPECIFIED, then even for sonification events + // we should reconfigure to less generic EMERGENCYALARM scenario + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + types::BidirectionalPair metadata = { + .sink = types::AudioContexts(), .source = types::AudioContexts()}; + EXPECT_CALL( + mock_state_machine_, + StartStream(_, types::LeAudioContextType::EMERGENCYALARM, metadata, _)) + .Times(0); - // 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(); - StartStreaming(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE, - AUDIO_CONTENT_TYPE_UNKNOWN, group_id); + StartStreaming(AUDIO_USAGE_EMERGENCY, AUDIO_CONTENT_TYPE_UNKNOWN, group_id, + AUDIO_SOURCE_INVALID, false, false); + SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - SyncOnMainLoop(); +} - // Verify Data transfer on one audio source cis - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); +/* When a certain context is unavailable and not supported and the UNSPECIFIED + * is not available we should stop the stream. + * For now, stream will not be started in such a case. + * In future we should be able to eliminate this context from the track mix. + */ +TEST_F(UnicastTest, StartNotAvailableUnsupportedContextTypeUnspecifiedUnavail) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; - LeAudioClient::Get()->SetInCall(false); + // EMERGENCYALARM is not available, nor supported + available_snk_context_types_ = (types::LeAudioContextType::RINGTONE | + types::LeAudioContextType::CONVERSATIONAL | + types::LeAudioContextType::MEDIA) + .value(); + available_src_context_types_ = available_snk_context_types_; + supported_snk_context_types_ = + (available_snk_context_types_ | types::LeAudioContextType::UNSPECIFIED) + .value(); + supported_src_context_types_ = + (available_src_context_types_ | types::LeAudioContextType::UNSPECIFIED) + .value(); - /* We should stay on the existing configuration as there is no GAME - * context available on the remote device. - */ - EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); - types::BidirectionalPair contexts = { - .sink = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED), - .source = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED)}; + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, false /*add_csis*/, true /*add_cas*/, + true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, + 0 /*rank*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) + .WillOnce(DoAll(SaveArg<1>(&group_id))); + + ConnectLeAudio(test_address0); + ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + + // Expect configuring to the default config since the EMERGENCYALARM is + // not on the list of supported contexts and UNSPECIFIED should not be + // in the metadata as it is unavailable. + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + types::BidirectionalPair metadata = { + .sink = types::AudioContexts(), .source = types::AudioContexts()}; EXPECT_CALL( mock_state_machine_, - StartStream(_, types::LeAudioContextType::CONVERSATIONAL, contexts, _)) - .Times(1); - UpdateMetadata(AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_UNKNOWN, false); + StartStream(_, types::LeAudioContextType::EMERGENCYALARM, metadata, _)) + .Times(0); - /* If the above triggers reconfiguration, Audio Hal action is needed to - * restart the stream. - */ - SinkAudioResume(); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + StartStreaming(AUDIO_USAGE_EMERGENCY, AUDIO_CONTENT_TYPE_UNKNOWN, group_id, + AUDIO_SOURCE_INVALID, false, false); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); } -TEST_F(UnicastTest, StartNotSupportedContextType) { +/* This test verifies if we use UNSPCIFIED context when another context is + * unavailable and not supported but UNSPCIFIED is in available audio contexts. + */ +TEST_F(UnicastTest, StartNotAvailableUnsupportedContextTypeUnspecifiedAvail) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; - supported_snk_context_types_ = (types::LeAudioContextType::RINGTONE | + // EMERGENCYALARM is not available, nor supported + available_snk_context_types_ = (types::LeAudioContextType::RINGTONE | types::LeAudioContextType::CONVERSATIONAL | types::LeAudioContextType::UNSPECIFIED | types::LeAudioContextType::MEDIA) .value(); - supported_src_context_types_ = supported_snk_context_types_; + available_src_context_types_ = available_snk_context_types_; + supported_snk_context_types_ = available_snk_context_types_; + supported_src_context_types_ = available_src_context_types_; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, @@ -4454,15 +8000,17 @@ TEST_F(UnicastTest, StartNotSupportedContextType) { // Expect configuring to the default config since the EMERGENCYALARM is // not on the list of supported contexts and UNSPECIFIED will be used in // the metadata. - auto default_config = types::LeAudioContextType::MEDIA; - EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); types::BidirectionalPair metadata = { .sink = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED), - .source = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED)}; - EXPECT_CALL(mock_state_machine_, StartStream(_, default_config, metadata, _)) + .source = types::AudioContexts()}; + EXPECT_CALL( + mock_state_machine_, + StartStream(_, types::LeAudioContextType::EMERGENCYALARM, metadata, _)) .Times(1); LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); StartStreaming(AUDIO_USAGE_EMERGENCY, AUDIO_CONTENT_TYPE_UNKNOWN, group_id); @@ -4505,9 +8053,10 @@ TEST_F(UnicastTest, NotifyAboutGroupTunrnedIdleEnabled) { LeAudioClient::Get()->SetInCall(true); // 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); + 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(); StartStreaming(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE, AUDIO_CONTENT_TYPE_UNKNOWN, group_id); @@ -4574,9 +8123,10 @@ TEST_F(UnicastTest, NotifyAboutGroupTunrnedIdleDisabled) { LeAudioClient::Get()->SetInCall(true); // 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); + 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(); StartStreaming(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE, AUDIO_CONTENT_TYPE_UNKNOWN, group_id); @@ -4585,35 +8135,126 @@ TEST_F(UnicastTest, NotifyAboutGroupTunrnedIdleDisabled) { Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); - // Verify Data transfer on one audio source cis - TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + // Verify Data transfer on one audio source cis + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); + + // Release + + /* To be called once only + * 1. GroupStatus::INACTIVE + */ + EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupStatus(group_id, _)) + .Times(1); + + EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); + EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); + + do_in_main_thread( + FROM_HERE, base::BindOnce( + [](LeAudioClient* client) { + client->GroupSetActive(bluetooth::groups::kGroupUnknown); + }, + LeAudioClient::Get())); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); + + LeAudioClient::Get()->SetInCall(false); +} + +TEST_F(UnicastTest, HandleDatabaseOutOfSync) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, false /*add_csis*/, true /*add_cas*/, + true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, + 0 /*rank*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) + .WillOnce(DoAll(SaveArg<1>(&group_id))); + + ConnectLeAudio(test_address0); + ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) + .Times(1); + InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + /* Simulate DATABASE OUT OF SYNC */ + ccc_stored_byte_val_ = 0x01; + gatt_read_ctp_ccc_status_ = GATT_DATABASE_OUT_OF_SYNC; + + EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)).Times(0); + ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)) + .WillByDefault(Return()); + EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)); + + InjectConnectedEvent(test_address0, 1); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_gatt_queue_); +} + +TEST_F(UnicastTest, TestRemoteDeviceKeepCccValues) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SetSampleDatabaseEarbudsValid( + 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, + default_channel_cnt, 0x0004, false /*add_csis*/, true /*add_cas*/, + true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, + 0 /*rank*/); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) + .WillOnce(DoAll(SaveArg<1>(&group_id))); + + ConnectLeAudio(test_address0); + ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); - // Release + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); - /* To be called once only - * 1. GroupStatus::INACTIVE - */ - EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupStatus(group_id, _)) + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); + InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_gatt_queue_); - EXPECT_CALL(*mock_le_audio_source_hal_client_, Stop()).Times(1); - EXPECT_CALL(*mock_le_audio_source_hal_client_, OnDestroyed()).Times(1); - EXPECT_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed()).Times(1); + /* Simulate remote cache is good */ + ccc_stored_byte_val_ = 0x01; - do_in_main_thread( - FROM_HERE, base::BindOnce( - [](LeAudioClient* client) { - client->GroupSetActive(bluetooth::groups::kGroupUnknown); - }, - LeAudioClient::Get())); + EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); - - LeAudioClient::Get()->SetInCall(false); + Mock::VerifyAndClearExpectations(&mock_gatt_queue_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); } -TEST_F(UnicastTest, HandleDatabaseOutOfSync) { +TEST_F(UnicastTest, TestRemoteDeviceForgetsCccValues) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; @@ -4642,32 +8283,20 @@ TEST_F(UnicastTest, HandleDatabaseOutOfSync) { InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(&mock_gatt_queue_); - // default action for WriteDescriptor function call - ON_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)) - .WillByDefault(Invoke([](uint16_t conn_id, uint16_t handle, - std::vector value, - tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, - void* cb_data) -> void { - if (cb) - do_in_main_thread( - FROM_HERE, - base::BindOnce( - [](GATT_WRITE_OP_CB cb, uint16_t conn_id, uint16_t handle, - uint16_t len, uint8_t* value, void* cb_data) { - cb(conn_id, GATT_DATABASE_OUT_OF_SYNC, handle, len, value, - cb_data); - }, - cb, conn_id, handle, value.size(), value.data(), cb_data)); - })); - - ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)) - .WillByDefault(Return()); - EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)); + /* Simulate remote cache is broken */ + ccc_stored_byte_val_ = 0; + EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)) + .Times(AtLeast(1)); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); - Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_gatt_queue_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); } TEST_F(UnicastTest, SpeakerStreamingTimeout) { @@ -4696,9 +8325,10 @@ TEST_F(UnicastTest, SpeakerStreamingTimeout) { uint8_t cis_count_in = 0; // 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); + 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(); StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id); @@ -4718,6 +8348,287 @@ TEST_F(UnicastTest, SpeakerStreamingTimeout) { /* No assigned cises should remain when transition remains in IDLE state */ auto group = streaming_groups.at(group_id); - ASSERT_EQ(0, static_cast(group->cises_.size())); + ASSERT_EQ(0, static_cast(group->cig.cises.size())); +} + +TEST_F(UnicastTest, AddMemberToAllowListWhenOneDeviceConnected) { + uint8_t group_size = 2; + int group_id = 2; + int conn_id_dev_0 = 1; + int conn_id_dev_1 = 2; + + /*Scenario to test + * 1. Connect Device A and disconnect + * 2. Connect Device B + * 3. verify Device B is in the allow list with direct connect. + */ + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + + ConnectCsisDevice(test_address0, conn_id_dev_0, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + SyncOnMainLoop(); + + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + + InjectDisconnectedEvent(conn_id_dev_0); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + + /* Do not connect first device but expect Open will arrive.*/ + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + ON_CALL(mock_gatt_interface_, + Open(_, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(Return()); + + ConnectCsisDevice(test_address1, conn_id_dev_1, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} + +TEST_F(UnicastTest, ResetToDefaultReconnectionMode) { + uint8_t group_size = 2; + int group_id = 2; + int conn_id_dev_0 = 1; + int conn_id_dev_1 = 2; + + /*Scenario to test + * 1. Connect Device A and disconnect + * 2. Connect Device B + * 3. verify Device B is in the allow list. + * 4. Disconnect B device + * 5, Verify A and B device are back in targeted announcement reconnection + * mode + */ + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + // First earbud + const RawAddress test_address0 = GetTestAddress(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true)) + .Times(1); + + ConnectCsisDevice(test_address0, conn_id_dev_0, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, group_size, + group_id, 1 /* rank*/); + + SyncOnMainLoop(); + + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + + InjectDisconnectedEvent(conn_id_dev_0); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + // Second earbud + const RawAddress test_address1 = GetTestAddress(1); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + + /* Verify first earbud will start doing direct connect first */ + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) + .Times(1); + ON_CALL(mock_gatt_interface_, + Open(_, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(Return()); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + + ConnectCsisDevice(test_address1, conn_id_dev_1, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id)) + .WillByDefault(Invoke([&](int group_id) { return 2; })); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + + // Disconnect Device B, expect default reconnection mode for Device A. + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address1, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address1, false)) + .Times(1); + + InjectDisconnectedEvent(conn_id_dev_1, GATT_CONN_TERMINATE_PEER_USER); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); +} + +TEST_F(UnicastTest, DisconnectAclBeforeGettingReadResponses) { + uint8_t group_size = 2; + int group_id = 2; + + // Report working CSIS + ON_CALL(mock_csis_client_module_, IsCsisClientRunning()) + .WillByDefault(Return(true)); + + const RawAddress test_address0 = GetTestAddress(0); + const RawAddress test_address1 = GetTestAddress(1); + + /* Due to imitated problems with GATT read operations (status != GATT_SUCCESS) + * a CONNECTED state should not be propagated together with audio location + */ + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(0); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnSinkAudioLocationAvailable( + test_address0, codec_spec_conf::kLeAudioLocationFrontLeft)) + .Times(0); + + // First earbud initial connection + SetSampleDatabaseEarbudsValid(1 /* conn_id */, test_address0, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, + default_channel_cnt, default_channel_cnt, + 0x0004, /* source sample freq 16khz */ + true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + true, /*add_ascs*/ + group_size, 1 /* rank */, GATT_INTERNAL_ERROR); + groups[test_address0] = group_id; + // by default indicate link as encrypted + ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _)) + .WillByDefault(DoAll(Return(true))); + + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _)) + .Times(1); + /* When connected it will got to TA */ + EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)) + .Times(1); + EXPECT_CALL(mock_gatt_interface_, + Open(gatt_if, test_address0, + BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _)) + .Times(1); + + do_in_main_thread( + FROM_HERE, + base::BindOnce(&LeAudioClient::Connect, + base::Unretained(LeAudioClient::Get()), test_address0)); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_btm_interface_); + Mock::VerifyAndClearExpectations(&mock_gatt_interface_); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + InjectGroupDeviceAdded(test_address0, group_id); + + // Second earbud initial connection + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnSinkAudioLocationAvailable( + test_address1, codec_spec_conf::kLeAudioLocationFrontRight)) + .Times(1); + + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true)) + .Times(1); + ConnectCsisDevice(test_address1, 2 /*conn_id*/, + codec_spec_conf::kLeAudioLocationFrontRight, + codec_spec_conf::kLeAudioLocationFrontRight, group_size, + group_id, 2 /* rank*/, true /*connect_through_csis*/); + + Mock::VerifyAndClearExpectations(&mock_btif_storage_); + + /* for Target announcements AutoConnect is always there, until + * device is removed + */ + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, false)) + .Times(0); + EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, false)) + .Times(0); + + // Verify grouping information + std::vector devs = + LeAudioClient::Get()->GetGroupDevices(group_id); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address0), devs.end()); + ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); + + /* Remove default action on the direct connect */ + ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)) + .WillByDefault(Return()); + + /* Initiate disconnection with timeout reason, the possible reason why GATT + * read attribute operation may be not handled + */ + InjectDisconnectedEvent(1, GATT_CONN_TIMEOUT); + SyncOnMainLoop(); + + /* After reconnection a sink audio location callback with connection state + * should be propagated. + */ + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnSinkAudioLocationAvailable( + test_address0, codec_spec_conf::kLeAudioLocationFrontLeft)) + .Times(1); + + /* Prepare valid GATT status responsing attributes */ + SetSampleDatabaseEarbudsValid(1 /* conn_id */, test_address0, + codec_spec_conf::kLeAudioLocationFrontLeft, + codec_spec_conf::kLeAudioLocationFrontLeft, + default_channel_cnt, default_channel_cnt, + 0x0004, /* source sample freq 16khz */ + true, /*add_csis*/ + true, /*add_cas*/ + true, /*add_pacs*/ + true, /*add_ascs*/ + group_size, 1 /* rank */); + + /* For background connect, test needs to Inject Connected Event */ + InjectConnectedEvent(test_address0, 1); + SyncOnMainLoop(); } + } // namespace le_audio diff --git a/system/bta/le_audio/le_audio_health_status.cc b/system/bta/le_audio/le_audio_health_status.cc new file mode 100644 index 0000000000000000000000000000000000000000..233a80e7c555e54c125c5ef2ec1260cad2cc50fd --- /dev/null +++ b/system/bta/le_audio/le_audio_health_status.cc @@ -0,0 +1,417 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "le_audio_health_status.h" + +#include + +#include "bta/include/bta_groups.h" +#include "gd/common/strings.h" +#include "main/shim/metrics_api.h" +#include "osi/include/log.h" +#include "osi/include/properties.h" + +using bluetooth::common::ToString; +using bluetooth::groups::kGroupUnknown; +using le_audio::LeAudioDevice; +using le_audio::LeAudioHealthStatus; +using le_audio::LeAudioRecommendationActionCb; + +namespace le_audio { +class LeAudioHealthStatusImpl; +LeAudioHealthStatusImpl* instance; + +class LeAudioHealthStatusImpl : public LeAudioHealthStatus { + public: + LeAudioHealthStatusImpl(void) { LOG_DEBUG(" Initiated"); } + + ~LeAudioHealthStatusImpl(void) { clear_module(); } + + void RegisterCallback(LeAudioRecommendationActionCb cb) override { + register_callback(std::move(cb)); + } + + void RemoveStatistics(const RawAddress& address, int group_id) override { + LOG_DEBUG("%s, group_id: %d", ADDRESS_TO_LOGGABLE_CSTR(address), group_id); + remove_device(address); + remove_group(group_id); + } + + void AddStatisticForDevice(const LeAudioDevice* device, + LeAudioHealthDeviceStatType type) override { + if (device == nullptr) { + LOG_ERROR("device is null"); + return; + } + + const RawAddress& address = device->address_; + LOG_DEBUG("%s, %s", ADDRESS_TO_LOGGABLE_CSTR(address), + ToString(type).c_str()); + + auto dev = find_device(address); + if (dev == nullptr) { + add_device(address); + dev = find_device(address); + if (dev == nullptr) { + LOG_ERROR("Could not add device %s", ADDRESS_TO_LOGGABLE_CSTR(address)); + return; + } + } + // log counter metrics + log_counter_metrics_for_device(type, device->allowlist_flag_); + + LeAudioHealthBasedAction action; + switch (type) { + case LeAudioHealthDeviceStatType::VALID_DB: + dev->is_valid_service_ = true; + action = LeAudioHealthBasedAction::NONE; + break; + case LeAudioHealthDeviceStatType::INVALID_DB: + dev->is_valid_service_ = false; + action = LeAudioHealthBasedAction::DISABLE; + break; + case LeAudioHealthDeviceStatType::INVALID_CSIS: + dev->is_valid_group_member_ = false; + action = LeAudioHealthBasedAction::DISABLE; + break; + case LeAudioHealthDeviceStatType::VALID_CSIS: + dev->is_valid_group_member_ = true; + action = LeAudioHealthBasedAction::NONE; + break; + } + + if (dev->latest_recommendation_ != action) { + dev->latest_recommendation_ = action; + send_recommendation_for_device(address, action); + return; + } + } + + void AddStatisticForGroup(const LeAudioDeviceGroup* device_group, + LeAudioHealthGroupStatType type) override { + if (device_group == nullptr) { + LOG_ERROR("device_group is null"); + return; + } + + int group_id = device_group->group_id_; + LOG_DEBUG("group_id: %d, %s", group_id, ToString(type).c_str()); + + auto group = find_group(group_id); + if (group == nullptr) { + add_group(group_id); + group = find_group(group_id); + if (group == nullptr) { + LOG_ERROR("Could not add group %d", group_id); + return; + } + } + + LeAudioDevice* device = device_group->GetFirstDevice(); + if (device == nullptr) { + LOG_ERROR("Front device is null. Number of devices: %d", + device_group->Size()); + return; + } + // log counter metrics + log_counter_metrics_for_group(type, device->allowlist_flag_); + + switch (type) { + case LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS: + group->stream_success_cnt_++; + if (group->latest_recommendation_ == LeAudioHealthBasedAction::NONE) { + return; + } + break; + case LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED: + group->stream_cis_failures_cnt_++; + group->stream_failures_cnt_++; + break; + case LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED: + group->stream_signaling_failures_cnt_++; + group->stream_failures_cnt_++; + break; + case LeAudioHealthGroupStatType::STREAM_CONTEXT_NOT_AVAILABLE: + group->stream_context_not_avail_cnt_++; + break; + } + + LeAudioHealthBasedAction action = LeAudioHealthBasedAction::NONE; + if (group->stream_success_cnt_ == 0) { + /* Never succeed in stream creation */ + if ((group->stream_failures_cnt_ >= + MAX_ALLOWED_FAILURES_IN_A_ROW_WITHOUT_SUCCESS)) { + action = LeAudioHealthBasedAction::DISABLE; + } else if (group->stream_context_not_avail_cnt_ >= + MAX_ALLOWED_FAILURES_IN_A_ROW_WITHOUT_SUCCESS) { + action = LeAudioHealthBasedAction::INACTIVATE_GROUP; + group->stream_context_not_avail_cnt_ = 0; + } + } else { + /* Had some success before */ + if ((100 * group->stream_failures_cnt_ / group->stream_success_cnt_) >= + THRESHOLD_FOR_DISABLE_CONSIDERATION) { + action = LeAudioHealthBasedAction::CONSIDER_DISABLING; + } else if (group->stream_context_not_avail_cnt_ >= + MAX_ALLOWED_FAILURES_IN_A_ROW_WITHOUT_SUCCESS) { + action = LeAudioHealthBasedAction::INACTIVATE_GROUP; + group->stream_context_not_avail_cnt_ = 0; + } + } + + if (group->latest_recommendation_ != action) { + group->latest_recommendation_ = action; + send_recommendation_for_group(group_id, action); + } + } + + void Dump(int fd) { + dprintf(fd, " LeAudioHealthStats: \n groups:"); + for (const auto& g : group_stats_) { + dumpsys_group(fd, g); + } + dprintf(fd, "\n devices: "); + for (const auto& dev : devices_stats_) { + dumpsys_dev(fd, dev); + } + dprintf(fd, "\n"); + } + + private: + static constexpr int MAX_ALLOWED_FAILURES_IN_A_ROW_WITHOUT_SUCCESS = 3; + static constexpr int THRESHOLD_FOR_DISABLE_CONSIDERATION = 70; + + std::vector callbacks_; + std::vector devices_stats_; + std::vector group_stats_; + + void dumpsys_group(int fd, const group_stats& group) { + std::stringstream stream; + + stream << "\n group_id: " << group.group_id_ << ": " + << group.latest_recommendation_ + << ", success: " << group.stream_success_cnt_ + << ", fail total: " << group.stream_failures_cnt_ + << ", fail cis: " << group.stream_cis_failures_cnt_ + << ", fail signaling: " << group.stream_signaling_failures_cnt_ + << ", context not avail: " << group.stream_context_not_avail_cnt_; + + dprintf(fd, "%s", stream.str().c_str()); + } + + void dumpsys_dev(int fd, const device_stats& dev) { + std::stringstream stream; + + stream << "\n " << ADDRESS_TO_LOGGABLE_STR(dev.address_) << ": " + << dev.latest_recommendation_ + << (dev.is_valid_service_ ? " service: OK" : " service : NOK") + << (dev.is_valid_group_member_ ? " csis: OK" : " csis : NOK"); + + dprintf(fd, "%s", stream.str().c_str()); + } + + void clear_module(void) { + devices_stats_.clear(); + group_stats_.clear(); + callbacks_.clear(); + } + + void send_recommendation_for_device(const RawAddress& address, + LeAudioHealthBasedAction recommendation) { + LOG_DEBUG("%s, %s", ADDRESS_TO_LOGGABLE_CSTR(address), + ToString(recommendation).c_str()); + /* Notify new user about known groups */ + for (auto& cb : callbacks_) { + cb.Run(address, kGroupUnknown, recommendation); + } + } + + void send_recommendation_for_group( + int group_id, const LeAudioHealthBasedAction recommendation) { + LOG_DEBUG("group_id: %d, %s", group_id, ToString(recommendation).c_str()); + /* Notify new user about known groups */ + for (auto& cb : callbacks_) { + cb.Run(RawAddress::kEmpty, group_id, recommendation); + } + } + + void add_device(const RawAddress& address) { + devices_stats_.emplace_back(device_stats(address)); + } + + void add_group(int group_id) { + group_stats_.emplace_back(group_stats(group_id)); + } + + void remove_group(int group_id) { + if (group_id == kGroupUnknown) { + return; + } + auto iter = std::find_if( + group_stats_.begin(), group_stats_.end(), + [group_id](const auto& g) { return g.group_id_ == group_id; }); + if (iter != group_stats_.end()) { + group_stats_.erase(iter); + } + } + + void remove_device(const RawAddress& address) { + auto iter = std::find_if( + devices_stats_.begin(), devices_stats_.end(), + [address](const auto& d) { return d.address_ == address; }); + if (iter != devices_stats_.end()) { + devices_stats_.erase(iter); + } + } + + void register_callback(LeAudioRecommendationActionCb cb) { + callbacks_.push_back(std::move(cb)); + } + + device_stats* find_device(const RawAddress& address) { + auto iter = std::find_if( + devices_stats_.begin(), devices_stats_.end(), + [address](const auto& d) { return d.address_ == address; }); + if (iter == devices_stats_.end()) return nullptr; + + return &(*iter); + } + + group_stats* find_group(int group_id) { + auto iter = std::find_if( + group_stats_.begin(), group_stats_.end(), + [group_id](const auto& g) { return g.group_id_ == group_id; }); + if (iter == group_stats_.end()) return nullptr; + + return &(*iter); + } + + void log_counter_metrics_for_device(LeAudioHealthDeviceStatType type, + bool in_allowlist) { + LOG_DEBUG("in_allowlist: %d, type: %s", in_allowlist, + ToString(type).c_str()); + android::bluetooth::CodePathCounterKeyEnum key; + if (in_allowlist) { + switch (type) { + case LeAudioHealthDeviceStatType::VALID_DB: + case LeAudioHealthDeviceStatType::VALID_CSIS: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_ALLOWLIST_DEVICE_HEALTH_STATUS_GOOD; + break; + case LeAudioHealthDeviceStatType::INVALID_DB: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_ALLOWLIST_DEVICE_HEALTH_STATUS_BAD_INVALID_DB; + break; + case LeAudioHealthDeviceStatType::INVALID_CSIS: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_ALLOWLIST_DEVICE_HEALTH_STATUS_BAD_INVALID_CSIS; + break; + default: + LOG_ERROR("Metric unhandled %d", type); + return; + } + } else { + switch (type) { + case LeAudioHealthDeviceStatType::VALID_DB: + case LeAudioHealthDeviceStatType::VALID_CSIS: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_NONALLOWLIST_DEVICE_HEALTH_STATUS_GOOD; + break; + case LeAudioHealthDeviceStatType::INVALID_DB: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_NONALLOWLIST_DEVICE_HEALTH_STATUS_BAD_INVALID_DB; + break; + case LeAudioHealthDeviceStatType::INVALID_CSIS: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_NONALLOWLIST_DEVICE_HEALTH_STATUS_BAD_INVALID_CSIS; + break; + default: + LOG_ERROR("Metric unhandled %d", type); + return; + } + } + bluetooth::shim::CountCounterMetrics(key, 1); + } + + void log_counter_metrics_for_group(LeAudioHealthGroupStatType type, + bool in_allowlist) { + LOG_DEBUG("in_allowlist: %d, type: %s", in_allowlist, + ToString(type).c_str()); + android::bluetooth::CodePathCounterKeyEnum key; + if (in_allowlist) { + switch (type) { + case LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_ALLOWLIST_GROUP_HEALTH_STATUS_GOOD; + break; + case LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_ALLOWLIST_GROUP_HEALTH_STATUS_BAD_ONCE_CIS_FAILED; + break; + case LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_ALLOWLIST_GROUP_HEALTH_STATUS_BAD_ONCE_SIGNALING_FAILED; + break; + default: + LOG_ERROR("Metric unhandled %d", type); + return; + } + } else { + switch (type) { + case LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_NONALLOWLIST_GROUP_HEALTH_STATUS_GOOD; + break; + case LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_NONALLOWLIST_GROUP_HEALTH_STATUS_BAD_ONCE_CIS_FAILED; + break; + case LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED: + key = android::bluetooth::CodePathCounterKeyEnum:: + LE_AUDIO_NONALLOWLIST_GROUP_HEALTH_STATUS_BAD_ONCE_SIGNALING_FAILED; + break; + default: + LOG_ERROR("Metric unhandled %d", type); + return; + } + } + bluetooth::shim::CountCounterMetrics(key, 1); + } +}; +} // namespace le_audio + +LeAudioHealthStatus* LeAudioHealthStatus::Get(void) { + if (instance) { + return instance; + } + instance = new LeAudioHealthStatusImpl(); + return instance; +} + +void LeAudioHealthStatus::DebugDump(int fd) { + if (instance) { + instance->Dump(fd); + } +} + +void LeAudioHealthStatus::Cleanup(void) { + if (!instance) { + return; + } + auto ptr = instance; + instance = nullptr; + delete ptr; +} diff --git a/system/bta/le_audio/le_audio_health_status.h b/system/bta/le_audio/le_audio_health_status.h new file mode 100644 index 0000000000000000000000000000000000000000..d3df5cff4c2297728033768c508e12b42553bda0 --- /dev/null +++ b/system/bta/le_audio/le_audio_health_status.h @@ -0,0 +1,160 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +#include "device_groups.h" +#include "devices.h" +#include "hardware/bt_le_audio.h" +#include "types/raw_address.h" + +using bluetooth::le_audio::LeAudioHealthBasedAction; + +namespace le_audio { +using LeAudioRecommendationActionCb = base::RepeatingCallback; + +/* This should be set by the client of this module to provide information about + * basic LeAudio support of the device which is exposing ASCS UUIDs. Should be + * used with AddStatisticForDevice API + */ +enum class LeAudioHealthDeviceStatType { + /* Should be used whenever LeAudio device has invalid GATT Database structure. + * e.g. missing mandatory services or characteristics. */ + INVALID_DB = 0, + /* Should be used when LeAudio devie GATT DB contains at least mandatory + * services and characteristics. */ + VALID_DB, + /* Should be used when device expose CSIS support but service is not valid. */ + INVALID_CSIS, + /* Should be used when device expose CSIS and Group ID has been + * successfully assigned to device. */ + VALID_CSIS, +}; + +/* When LeAudio device (s) are ready to use, we look at those as a group. + * Using Group stats we measure how good we are in creating streams. + * Should be used with AddStatisticForGroup API + */ +enum class LeAudioHealthGroupStatType { + /* Whenever stream is successfully established. */ + STREAM_CREATE_SUCCESS, + /* Whenever stream creation failes due to CIS failures */ + STREAM_CREATE_CIS_FAILED, + /* Whenever stream creation failes due to ASCS signaling failures + * e.g. ASE does not go to the proper State on time + */ + STREAM_CREATE_SIGNALING_FAILED, + /* Context stream not available */ + STREAM_CONTEXT_NOT_AVAILABLE, +}; + +class LeAudioHealthStatus { + public: + virtual ~LeAudioHealthStatus(void) = default; + static LeAudioHealthStatus* Get(void); + static void Cleanup(void); + static void DebugDump(int fd); + + virtual void RegisterCallback(LeAudioRecommendationActionCb cb) = 0; + virtual void AddStatisticForDevice(const LeAudioDevice* device, + LeAudioHealthDeviceStatType type) = 0; + virtual void AddStatisticForGroup(const LeAudioDeviceGroup* group, + LeAudioHealthGroupStatType type) = 0; + virtual void RemoveStatistics(const RawAddress& address, int group) = 0; + + struct group_stats { + group_stats(int group_id) + : group_id_(group_id), + latest_recommendation_(LeAudioHealthBasedAction::NONE), + stream_success_cnt_(0), + stream_failures_cnt_(0), + stream_cis_failures_cnt_(0), + stream_signaling_failures_cnt_(0), + stream_context_not_avail_cnt_(0){}; + + int group_id_; + LeAudioHealthBasedAction latest_recommendation_; + + int stream_success_cnt_; + int stream_failures_cnt_; + int stream_cis_failures_cnt_; + int stream_signaling_failures_cnt_; + int stream_context_not_avail_cnt_; + }; + + struct device_stats { + device_stats(RawAddress address) + : address_(address), + latest_recommendation_(LeAudioHealthBasedAction::NONE), + is_valid_service_(true), + is_valid_group_member_(true){}; + RawAddress address_; + LeAudioHealthBasedAction latest_recommendation_; + + bool is_valid_service_; + bool is_valid_group_member_; + }; +}; + +inline std::ostream& operator<<( + std::ostream& os, const le_audio::LeAudioHealthGroupStatType& stat) { + switch (stat) { + case le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS: + os << "STREAM_CREATE_SUCCESS"; + break; + case le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED: + os << "STREAM_CREATE_CIS_FAILED"; + break; + case le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED: + os << "STREAM_CREATE_SIGNALING_FAILED"; + break; + case le_audio::LeAudioHealthGroupStatType::STREAM_CONTEXT_NOT_AVAILABLE: + os << "STREAM_CONTEXT_NOT_AVAILABLE"; + break; + default: + os << "UNKNOWN"; + break; + } + return os; +} + +inline std::ostream& operator<<( + std::ostream& os, const le_audio::LeAudioHealthDeviceStatType& stat) { + switch (stat) { + case le_audio::LeAudioHealthDeviceStatType::INVALID_DB: + os << "INVALID_DB"; + break; + case le_audio::LeAudioHealthDeviceStatType::VALID_DB: + os << "VALID_DB"; + break; + case le_audio::LeAudioHealthDeviceStatType::INVALID_CSIS: + os << "INVALID_CSIS"; + break; + case le_audio::LeAudioHealthDeviceStatType::VALID_CSIS: + os << "VALID_CSIS"; + break; + default: + os << "UNKNOWN"; + break; + } + return os; +} +} // namespace le_audio \ No newline at end of file diff --git a/system/bta/le_audio/le_audio_health_status_test.cc b/system/bta/le_audio/le_audio_health_status_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..48cfcde303f00b326b6c4b8970c0d4d49dd21c77 --- /dev/null +++ b/system/bta/le_audio/le_audio_health_status_test.cc @@ -0,0 +1,241 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "le_audio_health_status.h" + +#include +#include +#include +#include +#include +#include + +#include "bta/include/bta_groups.h" +#include "gd/common/init_flags.h" +#include "test/common/mock_functions.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +using bluetooth::groups::kGroupUnknown; +using bluetooth::le_audio::LeAudioHealthBasedAction; +using le_audio::DeviceConnectState; +using le_audio::LeAudioDevice; +using le_audio::LeAudioDeviceGroup; +using le_audio::LeAudioHealthDeviceStatType; +using le_audio::LeAudioHealthGroupStatType; +using le_audio::LeAudioHealthStatus; + +static const char* test_flags[] = { + "INIT_logging_debug_enabled_for_all=true", + nullptr, +}; + +LeAudioHealthBasedAction recommendation_in_callback = + LeAudioHealthBasedAction::NONE; +RawAddress address_in_callback = RawAddress::kEmpty; +int group_id_in_callback = kGroupUnknown; + +static void healthCallback(const RawAddress& address, int group_id, + LeAudioHealthBasedAction recommendation) { + address_in_callback = address; + group_id_in_callback = group_id; + recommendation_in_callback = recommendation; +} + +class LeAudioHealthStatusTest : public ::testing::Test { + protected: + void SetUp() override { + reset_mock_function_count_map(); + group_ = new LeAudioDeviceGroup(group_id_); + bluetooth::common::InitFlags::Load(test_flags); + le_audio_health_status_instance_ = LeAudioHealthStatus::Get(); + le_audio_health_status_instance_->RegisterCallback( + base::BindRepeating(healthCallback)); + } + + void TearDown() override { + le_audio_health_status_instance_->Cleanup(); + delete group_; + recommendation_in_callback = LeAudioHealthBasedAction::NONE; + address_in_callback = RawAddress::kEmpty; + } + + LeAudioHealthStatus* le_audio_health_status_instance_; + const int group_id_ = 0; + LeAudioDeviceGroup* group_ = nullptr; +}; + +RawAddress GetTestAddress(uint8_t index) { + CHECK_LT(index, UINT8_MAX); + RawAddress result = {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, index}}; + return result; +} + +TEST_F(LeAudioHealthStatusTest, test_initialize) { + ASSERT_TRUE(le_audio_health_status_instance_ != nullptr); +} + +TEST_F(LeAudioHealthStatusTest, test_invalid_db) { + const RawAddress test_address0 = GetTestAddress(0); + auto device = std::make_shared( + test_address0, DeviceConnectState::DISCONNECTED); + le_audio_health_status_instance_->AddStatisticForDevice( + device.get(), LeAudioHealthDeviceStatType::INVALID_DB); + ASSERT_TRUE(address_in_callback == test_address0); + ASSERT_TRUE(recommendation_in_callback == LeAudioHealthBasedAction::DISABLE); +} + +TEST_F(LeAudioHealthStatusTest, test_invalid_csis_member) { + const RawAddress test_address0 = GetTestAddress(0); + auto device = std::make_shared( + test_address0, DeviceConnectState::DISCONNECTED); + le_audio_health_status_instance_->AddStatisticForDevice( + device.get(), LeAudioHealthDeviceStatType::INVALID_CSIS); + ASSERT_TRUE(address_in_callback == test_address0); + ASSERT_TRUE(recommendation_in_callback == LeAudioHealthBasedAction::DISABLE); +} + +TEST_F(LeAudioHealthStatusTest, test_remove_statistic) { + const RawAddress test_address0 = GetTestAddress(0); + auto device = std::make_shared( + test_address0, DeviceConnectState::DISCONNECTED); + group_->AddNode(device); + le_audio_health_status_instance_->AddStatisticForDevice( + device.get(), LeAudioHealthDeviceStatType::INVALID_CSIS); + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); + le_audio_health_status_instance_->RemoveStatistics(test_address0, group_id_); +} + +TEST_F(LeAudioHealthStatusTest, test_all_is_good) { + for (int i = 0; i < 100; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); + } + + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + ASSERT_TRUE(group_id_in_callback == kGroupUnknown); +} + +TEST_F(LeAudioHealthStatusTest, test_disable_cis_no_stream_creation) { + const RawAddress test_address0 = GetTestAddress(0); + auto device = std::make_shared(test_address0, + DeviceConnectState::CONNECTED); + group_->AddNode(device); + for (int i = 0; i < 3; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + } + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + ASSERT_TRUE(group_id_in_callback == group_id_); + ASSERT_TRUE(recommendation_in_callback == LeAudioHealthBasedAction::DISABLE); +} + +TEST_F(LeAudioHealthStatusTest, test_disable_signaling_no_stream_creation) { + const RawAddress test_address0 = GetTestAddress(0); + auto device = std::make_shared(test_address0, + DeviceConnectState::CONNECTED); + group_->AddNode(device); + for (int i = 0; i < 3; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED); + } + /* No recommendation shall be sent */ + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + ASSERT_TRUE(group_id_in_callback == group_id_); + ASSERT_TRUE(recommendation_in_callback == LeAudioHealthBasedAction::DISABLE); +} + +TEST_F(LeAudioHealthStatusTest, test_disable_signaling_cis_no_stream_creation) { + const RawAddress test_address0 = GetTestAddress(0); + auto device = std::make_shared(test_address0, + DeviceConnectState::CONNECTED); + group_->AddNode(device); + for (int i = 0; i < 2; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED); + } + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + + /* No recommendation shall be sent */ + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + ASSERT_TRUE(group_id_in_callback == group_id_); + ASSERT_TRUE(recommendation_in_callback == LeAudioHealthBasedAction::DISABLE); +} + +TEST_F(LeAudioHealthStatusTest, test_consider_disabling) { + const RawAddress test_address0 = GetTestAddress(0); + auto device = std::make_shared(test_address0, + DeviceConnectState::CONNECTED); + group_->AddNode(device); + for (int i = 0; i < 10; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); + } + + for (int i = 0; i < 2; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + } + + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + + for (int i = 0; i < 2; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED); + } + + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + + for (int i = 0; i < 3; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED); + } + + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + ASSERT_TRUE(group_id_in_callback == group_id_); + ASSERT_TRUE(recommendation_in_callback == + LeAudioHealthBasedAction::CONSIDER_DISABLING); +} + +TEST_F(LeAudioHealthStatusTest, test_inactivate_group) { + const RawAddress test_address0 = GetTestAddress(0); + auto device = std::make_shared(test_address0, + DeviceConnectState::CONNECTED); + group_->AddNode(device); + for (int i = 0; i < 10; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); + } + + for (int i = 0; i < 2; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CONTEXT_NOT_AVAILABLE); + } + + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + + for (int i = 0; i < 1; i++) { + le_audio_health_status_instance_->AddStatisticForGroup( + group_, LeAudioHealthGroupStatType::STREAM_CONTEXT_NOT_AVAILABLE); + } + + ASSERT_TRUE(address_in_callback == RawAddress::kEmpty); + ASSERT_TRUE(group_id_in_callback == group_id_); + ASSERT_TRUE(recommendation_in_callback == + LeAudioHealthBasedAction::INACTIVATE_GROUP); +} \ No newline at end of file diff --git a/system/bta/le_audio/le_audio_log_history.cc b/system/bta/le_audio/le_audio_log_history.cc index ce3378d978470ac24c39c63ed20c9def890f7eae..d4568cbaa09a1336fe5373607568edd01bfa45ee 100644 --- a/system/bta/le_audio/le_audio_log_history.cc +++ b/system/bta/le_audio/le_audio_log_history.cc @@ -17,6 +17,7 @@ #include "le_audio_log_history.h" #include +#include #include #include @@ -144,4 +145,4 @@ void LeAudioLogHistory::Cleanup(void) { auto ptr = instance; instance = nullptr; delete ptr; -} \ No newline at end of file +} diff --git a/system/bta/le_audio/le_audio_set_configuration_provider.cc b/system/bta/le_audio/le_audio_set_configuration_provider.cc deleted file mode 100644 index 1ffc04253065317544d6f33fcba6902ad9d1f990..0000000000000000000000000000000000000000 --- a/system/bta/le_audio/le_audio_set_configuration_provider.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include "le_audio_set_configuration_provider.h" - -#include "bta_le_audio_api.h" - -void LeAudioClient::InitializeAudioSetConfigurationProvider(void) { - le_audio::AudioSetConfigurationProvider::Initialize(); -} - -void LeAudioClient::CleanupAudioSetConfigurationProvider(void) { - le_audio::AudioSetConfigurationProvider::Cleanup(); -} diff --git a/system/bta/le_audio/le_audio_set_configuration_provider.h b/system/bta/le_audio/le_audio_set_configuration_provider.h index 7310868d68bae4046fbb1fe744d5cfcf6f10b188..c4a18f43680f8f3bcb46b84498145e484a7570a5 100644 --- a/system/bta/le_audio/le_audio_set_configuration_provider.h +++ b/system/bta/le_audio/le_audio_set_configuration_provider.h @@ -27,11 +27,16 @@ class AudioSetConfigurationProvider { AudioSetConfigurationProvider(); virtual ~AudioSetConfigurationProvider() = default; static AudioSetConfigurationProvider* Get(); - static void Initialize(); + static void Initialize(types::CodecLocation location); static void DebugDump(int fd); static void Cleanup(); virtual const set_configurations::AudioSetConfigurations* GetConfigurations( ::le_audio::types::LeAudioContextType content_type) const; + virtual bool IsDualBiDirSwbSupported(void) const; + virtual bool CheckConfigurationIsBiDirSwb( + const set_configurations::AudioSetConfiguration& set_configuration) const; + virtual bool CheckConfigurationIsDualBiDirSwb( + const set_configurations::AudioSetConfiguration& set_configuration) const; private: struct impl; 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 c6ce195c569f26f17bcd349757e691aff8ae03be..d3338202809e0f8b9b3dfe61f9d0f48eba06d954 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 @@ -15,10 +15,13 @@ * */ +#include + #include #include #include +#include "audio_hal_client/audio_hal_client.h" #include "audio_set_configurations_generated.h" #include "audio_set_scenarios_generated.h" #include "codec_manager.h" @@ -27,10 +30,11 @@ #include "le_audio_set_configuration_provider.h" #include "osi/include/log.h" #include "osi/include/osi.h" +#include "osi/include/properties.h" using le_audio::set_configurations::AudioSetConfiguration; using le_audio::set_configurations::AudioSetConfigurations; -using le_audio::set_configurations::CodecCapabilitySetting; +using le_audio::set_configurations::CodecConfigSetting; using le_audio::set_configurations::LeAudioCodecIdLc3; using le_audio::set_configurations::QosConfigSetting; using le_audio::set_configurations::SetConfiguration; @@ -53,6 +57,17 @@ static const std::vector< "le_audio/audio_set_scenarios.bfbs", "/apex/com.android.btservices/etc/bluetooth/" "le_audio/audio_set_scenarios.json"}}; +#elif defined(TARGET_FLOSS) +static const std::vector< + std::pair> + kLeAudioSetConfigs = { + {"/etc/bluetooth/le_audio/audio_set_configurations.bfbs", + "/etc/bluetooth/le_audio/audio_set_configurations.json"}}; +static const std::vector< + std::pair> + kLeAudioSetScenarios = { + {"/etc/bluetooth/le_audio/audio_set_scenarios.bfbs", + "/etc/bluetooth/le_audio/audio_set_scenarios.json"}}; #else static const std::vector< std::pair> @@ -68,8 +83,10 @@ static const std::vector< struct AudioSetConfigurationProviderJson { static constexpr auto kDefaultScenario = "Media"; - AudioSetConfigurationProviderJson() { - ASSERT_LOG(LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios), + AudioSetConfigurationProviderJson(types::CodecLocation location) { + dual_bidirection_swb_supported_ = osi_property_get_bool( + "bluetooth.leaudio.dual_bidirection_swb.supported", false); + ASSERT_LOG(LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios, location), ": Unable to load le audio set configuration files."); } @@ -150,6 +167,10 @@ struct AudioSetConfigurationProviderJson { return nullptr; }; + bool IsDualBiDirSwbSupported(void) const { + return dual_bidirection_swb_supported_; + } + private: /* Codec configurations */ std::map configurations_; @@ -158,6 +179,11 @@ struct AudioSetConfigurationProviderJson { std::map<::le_audio::types::LeAudioContextType, AudioSetConfigurations> context_configurations_; + /* property to check if bidirectional sampling frequency >= 32k dual mic is + * supported or not + */ + bool dual_bidirection_swb_supported_; + static const bluetooth::le_audio::CodecSpecificConfiguration* LookupCodecSpecificParam( const flatbuffers::Vector< @@ -171,12 +197,12 @@ struct AudioSetConfigurationProviderJson { return (it != flat_codec_specific_params->cend()) ? *it : nullptr; } - static CodecCapabilitySetting CodecCapabilitySettingFromFlat( + static CodecConfigSetting CodecConfigSettingFromFlat( const bluetooth::le_audio::CodecId* flat_codec_id, const flatbuffers::Vector< flatbuffers::Offset>* flat_codec_specific_params) { - CodecCapabilitySetting codec; + CodecConfigSetting codec; /* Cache the le_audio::types::CodecId type value */ codec.id = types::LeAudioCodecId({ @@ -185,88 +211,37 @@ struct AudioSetConfigurationProviderJson { .vendor_codec_id = flat_codec_id->vendor_codec_id(), }); - /* Cache the types::LeAudioLc3Config type value */ - uint8_t sampling_frequency = 0; - uint8_t frame_duration = 0; - uint32_t audio_channel_allocation = 0; - uint16_t octets_per_codec_frame = 0; - uint8_t codec_frames_blocks_per_sdu = 0; - - auto param = LookupCodecSpecificParam( - flat_codec_specific_params, - bluetooth::le_audio:: - CodecSpecificLtvGenericTypes_SUPPORTED_SAMPLING_FREQUENCY); - if (param) { - ASSERT_LOG((param->compound_value()->value()->size() == 1), - " Invalid compound value length: %d", - param->compound_value()->value()->size()); - auto ptr = param->compound_value()->value()->data(); - STREAM_TO_UINT8(sampling_frequency, ptr); - } - - param = LookupCodecSpecificParam( - flat_codec_specific_params, - bluetooth::le_audio:: - CodecSpecificLtvGenericTypes_SUPPORTED_FRAME_DURATION); - if (param) { - LOG_ASSERT(param->compound_value()->value()->size() == 1) - << " Invalid compound value length: " - << param->compound_value()->value()->size(); - auto ptr = param->compound_value()->value()->data(); - STREAM_TO_UINT8(frame_duration, ptr); + /* Cache all the codec specific parameters */ + for (auto const& param : *flat_codec_specific_params) { + auto const value = param->compound_value()->value(); + codec.params.Add( + param->type(), + std::vector(value->data(), value->data() + value->size())); } - param = LookupCodecSpecificParam( - flat_codec_specific_params, + auto param = codec.params.Find( bluetooth::le_audio:: CodecSpecificLtvGenericTypes_SUPPORTED_AUDIO_CHANNEL_ALLOCATION); if (param) { - ASSERT_LOG((param->compound_value()->value()->size() == 4), - " Invalid compound value length %d", - param->compound_value()->value()->size()); - auto ptr = param->compound_value()->value()->data(); - STREAM_TO_UINT32(audio_channel_allocation, ptr); - } - - param = LookupCodecSpecificParam( - flat_codec_specific_params, - bluetooth::le_audio:: - CodecSpecificLtvGenericTypes_SUPPORTED_OCTETS_PER_CODEC_FRAME); - if (param) { - ASSERT_LOG((param->compound_value()->value()->size() == 2), - " Invalid compound value length %d", - param->compound_value()->value()->size()); - auto ptr = param->compound_value()->value()->data(); - STREAM_TO_UINT16(octets_per_codec_frame, ptr); - } + auto ptr = param->data(); + uint32_t audio_channel_allocation; - param = LookupCodecSpecificParam( - flat_codec_specific_params, - bluetooth::le_audio:: - CodecSpecificLtvGenericTypes_SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU); - if (param) { - ASSERT_LOG((param->compound_value()->value()->size() == 1), - " Invalid compound value length %d", - param->compound_value()->value()->size()); - auto ptr = param->compound_value()->value()->data(); - STREAM_TO_UINT8(codec_frames_blocks_per_sdu, ptr); + ASSERT_LOG((param->size() == sizeof(audio_channel_allocation)), + "invalid channel allocation value %d", (int)param->size()); + STREAM_TO_UINT32(audio_channel_allocation, ptr); + codec.channel_count_per_iso_stream = + std::bitset<32>(audio_channel_allocation).count(); + } else { + // TODO: Add support for channel count in the json configurations file, + // keeping support for the allocations for compatibility. } - codec.config = types::LeAudioLc3Config({ - .sampling_frequency = sampling_frequency, - .frame_duration = frame_duration, - .octets_per_codec_frame = octets_per_codec_frame, - .codec_frames_blocks_per_sdu = codec_frames_blocks_per_sdu, - .channel_count = - (uint8_t)std::bitset<32>(audio_channel_allocation).count(), - .audio_channel_allocation = audio_channel_allocation, - }); return codec; } SetConfiguration SetConfigurationFromFlatSubconfig( const bluetooth::le_audio::AudioSetSubConfiguration* flat_subconfig, - QosConfigSetting qos) { + QosConfigSetting qos, types::CodecLocation location) { auto strategy_int = static_cast(flat_subconfig->configuration_strategy()); @@ -280,12 +255,32 @@ struct AudioSetConfigurationProviderJson { ? static_cast(strategy_int) : types::LeAudioConfigurationStrategy::RFU; - return SetConfiguration( + auto config = SetConfiguration( flat_subconfig->direction(), flat_subconfig->device_cnt(), flat_subconfig->ase_cnt(), - CodecCapabilitySettingFromFlat(flat_subconfig->codec_id(), - flat_subconfig->codec_configuration()), + CodecConfigSettingFromFlat(flat_subconfig->codec_id(), + flat_subconfig->codec_configuration()), qos, strategy); + + // Note that these parameters are set here since for now, we are using the + // common configuration source for all the codec locations. + switch (location) { + case types::CodecLocation::ADSP: + config.is_codec_in_controller = false; + config.data_path_id = + bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault; + break; + case types::CodecLocation::HOST: + config.is_codec_in_controller = false; + config.data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci; + break; + case types::CodecLocation::CONTROLLER: + config.is_codec_in_controller = true; + config.data_path_id = + bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault; + break; + } + return config; } static uint8_t ValidateTargetLatency(int flat_target_latency) { @@ -303,7 +298,8 @@ struct AudioSetConfigurationProviderJson { AudioSetConfiguration AudioSetConfigurationFromFlat( const bluetooth::le_audio::AudioSetConfiguration* flat_cfg, std::vector* codec_cfgs, - std::vector* qos_cfgs) { + std::vector* qos_cfgs, + types::CodecLocation location) { ASSERT_LOG(flat_cfg != nullptr, "flat_cfg cannot be null"); std::string codec_config_key = flat_cfg->codec_config_name()->str(); auto* qos_config_key_array = flat_cfg->qos_config_name(); @@ -375,15 +371,23 @@ struct AudioSetConfigurationProviderJson { } std::vector subconfigs; + + bool dual_dev_one_chan_stereo_sink_swb = false; + bool dual_dev_one_chan_stereo_source_swb = false; + bool single_dev_one_chan_stereo_sink_swb = false; + bool single_dev_one_chan_stereo_source_swb = false; + if (codec_cfg != nullptr && codec_cfg->subconfigurations()) { /* Load subconfigurations */ for (auto subconfig : *codec_cfg->subconfigurations()) { if (subconfig->direction() == le_audio::types::kLeAudioDirectionSink) { - subconfigs.push_back( - SetConfigurationFromFlatSubconfig(subconfig, qos_sink)); + processSubconfig( + *subconfig, qos_sink, dual_dev_one_chan_stereo_sink_swb, + single_dev_one_chan_stereo_sink_swb, subconfigs, location); } else { - subconfigs.push_back( - SetConfigurationFromFlatSubconfig(subconfig, qos_source)); + processSubconfig( + *subconfig, qos_source, dual_dev_one_chan_stereo_source_swb, + single_dev_one_chan_stereo_source_swb, subconfigs, location); } } } else { @@ -396,11 +400,43 @@ struct AudioSetConfigurationProviderJson { } } + if (!dual_bidirection_swb_supported_) { + if ((dual_dev_one_chan_stereo_sink_swb && + dual_dev_one_chan_stereo_source_swb) || + (single_dev_one_chan_stereo_sink_swb && + single_dev_one_chan_stereo_source_swb)) { + return AudioSetConfiguration({flat_cfg->name()->c_str(), {}}); + } + } + return AudioSetConfiguration({flat_cfg->name()->c_str(), subconfigs}); } + void processSubconfig( + const bluetooth::le_audio::AudioSetSubConfiguration& subconfig, + const QosConfigSetting& qos_setting, bool& dual_dev_one_chan_stereo_swb, + bool& single_dev_one_chan_stereo_swb, + std::vector& subconfigs, + types::CodecLocation location) { + subconfigs.push_back( + SetConfigurationFromFlatSubconfig(&subconfig, qos_setting, location)); + + if (subconfigs.back().codec.GetSamplingFrequencyHz() < + le_audio::LeAudioCodecConfiguration::kSampleRate32000) { + return; + } + + if (subconfigs.back().device_cnt == 2 && subconfigs.back().ase_cnt == 2) { + dual_dev_one_chan_stereo_swb |= true; + } + if (subconfigs.back().device_cnt == 1 && subconfigs.back().ase_cnt == 2) { + single_dev_one_chan_stereo_swb |= true; + } + } + bool LoadConfigurationsFromFiles(const char* schema_file, - const char* content_file) { + const char* content_file, + types::CodecLocation location) { flatbuffers::Parser configurations_parser_; std::string configurations_schema_binary_content; bool ok = flatbuffers::LoadFile(schema_file, true, @@ -454,9 +490,11 @@ struct AudioSetConfigurationProviderJson { LOG_DEBUG(": Updating %d config entries.", flat_configs->size()); for (auto const& flat_cfg : *flat_configs) { - configurations_.insert( - {flat_cfg->name()->str(), - AudioSetConfigurationFromFlat(flat_cfg, &codec_cfgs, &qos_cfgs)}); + auto configuration = AudioSetConfigurationFromFlat(flat_cfg, &codec_cfgs, + &qos_cfgs, location); + if (!configuration.confs.empty()) { + configurations_.insert({flat_cfg->name()->str(), configuration}); + } } return true; @@ -532,9 +570,10 @@ struct AudioSetConfigurationProviderJson { std::vector> config_files, std::vector> - scenario_files) { + scenario_files, + types::CodecLocation location) { for (auto [schema, content] : config_files) { - if (!LoadConfigurationsFromFiles(schema, content)) return false; + if (!LoadConfigurationsFromFiles(schema, content, location)) return false; } for (auto [schema, content] : scenario_files) { @@ -548,10 +587,10 @@ struct AudioSetConfigurationProvider::impl { impl(const AudioSetConfigurationProvider& config_provider) : config_provider_(config_provider) {} - void Initialize() { + void Initialize(types::CodecLocation location) { ASSERT_LOG(!config_provider_impl_, " Config provider not available."); config_provider_impl_ = - std::make_unique(); + std::make_unique(location); } void Cleanup() { @@ -585,8 +624,8 @@ struct AudioSetConfigurationProvider::impl { << +ent.qos.retransmission_number << " \n" << " qos->max_transport_latency: " << +ent.qos.max_transport_latency << " \n" - << " channel count: " - << +ent.codec.GetConfigChannelCount() << "\n"; + << " channel count per ISO stream: " + << +ent.codec.GetChannelCountPerIsoStream() << "\n"; } } } @@ -604,13 +643,13 @@ std::mutex instance_mutex; AudioSetConfigurationProvider::AudioSetConfigurationProvider() : pimpl_(std::make_unique(*this)) {} -void AudioSetConfigurationProvider::Initialize() { +void AudioSetConfigurationProvider::Initialize(types::CodecLocation location) { std::scoped_lock lock(instance_mutex); if (!config_provider) config_provider = std::make_unique(); if (!config_provider->pimpl_->IsRunning()) - config_provider->pimpl_->Initialize(); + config_provider->pimpl_->Initialize(location); } void AudioSetConfigurationProvider::DebugDump(int fd) { @@ -668,4 +707,46 @@ AudioSetConfigurationProvider::GetConfigurations( return nullptr; } +bool AudioSetConfigurationProvider::CheckConfigurationIsBiDirSwb( + const set_configurations::AudioSetConfiguration& set_configuration) const { + uint8_t dir = 0; + + for (const auto& conf : set_configuration.confs) { + if (conf.codec.GetSamplingFrequencyHz() >= + le_audio::LeAudioCodecConfiguration::kSampleRate32000) { + dir |= conf.direction; + } + } + return dir == le_audio::types::kLeAudioDirectionBoth; +} + +bool AudioSetConfigurationProvider::CheckConfigurationIsDualBiDirSwb( + const set_configurations::AudioSetConfiguration& set_configuration) const { + uint8_t single_dev_dual_bidir_swb = 0; + uint8_t dual_dev_dual_bidir_swb = 0; + + for (const auto& conf : set_configuration.confs) { + if (conf.codec.GetSamplingFrequencyHz() < + le_audio::LeAudioCodecConfiguration::kSampleRate32000) { + return false; + } + if (conf.device_cnt == 1 && conf.ase_cnt == 2) { + single_dev_dual_bidir_swb |= conf.direction; + } else if (conf.device_cnt == 2 && conf.ase_cnt == 2) { + dual_dev_dual_bidir_swb |= conf.direction; + } + } + + return single_dev_dual_bidir_swb == le_audio::types::kLeAudioDirectionBoth || + dual_dev_dual_bidir_swb == le_audio::types::kLeAudioDirectionBoth; +} + +bool AudioSetConfigurationProvider::IsDualBiDirSwbSupported(void) const { + if (pimpl_->IsRunning()) { + return pimpl_->config_provider_impl_->IsDualBiDirSwbSupported(); + } + + return false; +} + } // namespace le_audio diff --git a/system/bta/le_audio/le_audio_types.cc b/system/bta/le_audio/le_audio_types.cc index ef780f2ae1c1c032ec457416b524fc13fbb24beb..a3d2fbb6ee45a220213ca370ca431301c5d856cd 100644 --- a/system/bta/le_audio/le_audio_types.cc +++ b/system/bta/le_audio/le_audio_types.cc @@ -22,26 +22,27 @@ #include "le_audio_types.h" +#include #include #include "audio_hal_client/audio_hal_client.h" -#include "bt_types.h" #include "bta_api.h" #include "bta_le_audio_api.h" #include "client_parser.h" #include "gd/common/strings.h" +#include "stack/include/bt_types.h" namespace le_audio { using types::acs_ac_record; using types::LeAudioContextType; namespace set_configurations { -using set_configurations::CodecCapabilitySetting; +using set_configurations::CodecConfigSetting; using types::CodecLocation; using types::kLeAudioCodingFormatLC3; using types::kLeAudioDirectionSink; using types::kLeAudioDirectionSource; -using types::LeAudioLc3Config; +using types::LeAudioCoreCodecConfig; static uint8_t min_req_devices_cnt( const AudioSetConfiguration* audio_set_conf) { @@ -245,128 +246,74 @@ uint8_t get_num_of_devices_in_configuration( return min_req_devices_cnt(audio_set_conf); } -static bool IsCodecConfigurationSupported(const types::LeAudioLtvMap& pacs, - const LeAudioLc3Config& lc3_config) { - const auto& reqs = lc3_config.GetAsLtvMap(); - uint8_t u8_req_val, u8_pac_val; - uint16_t u16_req_val, u16_pac_val; +static bool IsCodecConfigCoreSupported(const types::LeAudioLtvMap& pacs, + const types::LeAudioLtvMap& reqs) { + auto caps = pacs.GetAsCoreCodecCapabilities(); + auto config = reqs.GetAsCoreCodecConfig(); /* Sampling frequency */ - auto req = reqs.Find(codec_spec_conf::kLeAudioCodecLC3TypeSamplingFreq); - auto pac = pacs.Find(codec_spec_caps::kLeAudioCodecLC3TypeSamplingFreq); - if (!req || !pac) { - LOG_DEBUG(", lack of sampling frequency fields"); + if (!caps.HasSupportedSamplingFrequencies() || !config.sampling_frequency) { + LOG_DEBUG("Missing supported sampling frequencies capability"); return false; } - - u8_req_val = VEC_UINT8_TO_UINT8(req.value()); - u16_pac_val = VEC_UINT8_TO_UINT16(pac.value()); - - /* TODO: Integrate with codec capabilities */ - if (!(u16_pac_val & - codec_spec_caps::SamplingFreqConfig2Capability(u8_req_val))) { - /* - * Note: Requirements are in the codec configuration specification which - * are values coming from Assigned Numbers: Codec_Specific_Configuration - */ - LOG_DEBUG( - " Req:SamplFreq= 0x%04x (Assigned Numbers: " - "Codec_Specific_Configuration)", - u8_req_val); - /* NOTE: Below is Codec specific cababilities comes from Assigned Numbers: - * Codec_Specific_Capabilities - */ - LOG_DEBUG( - " Pac:SamplFreq= 0x%04x (Assigned numbers: " - "Codec_Specific_Capabilities - bitfield)", - u16_pac_val); - - LOG_DEBUG(", sampling frequency not supported"); + if (!caps.IsSamplingFrequencyConfigSupported( + config.sampling_frequency.value())) { + LOG_DEBUG("Cfg: SamplingFrequency= 0x%04x", + config.sampling_frequency.value()); + LOG_DEBUG("Cap: SupportedSamplingFrequencies= 0x%04x", + caps.supported_sampling_frequencies.value()); + LOG_DEBUG("Sampling frequency not supported"); return false; } - /* Frame duration */ - req = reqs.Find(codec_spec_conf::kLeAudioCodecLC3TypeFrameDuration); - pac = pacs.Find(codec_spec_caps::kLeAudioCodecLC3TypeFrameDuration); - if (!req || !pac) { - LOG_DEBUG(", lack of frame duration fields"); + /* Channel counts */ + if (!caps.IsAudioChannelCountsSupported( + config.GetChannelCountPerIsoStream())) { + LOG_DEBUG("Cfg: Allocated channel count= 0x%04x", + config.GetChannelCountPerIsoStream()); + LOG_DEBUG("Cap: Supported channel counts= 0x%04x", + caps.supported_audio_channel_counts.value_or(1)); + LOG_DEBUG("Channel count not supported"); return false; } - u8_req_val = VEC_UINT8_TO_UINT8(req.value()); - u8_pac_val = VEC_UINT8_TO_UINT8(pac.value()); - - if ((u8_req_val != codec_spec_conf::kLeAudioCodecLC3FrameDur7500us && - u8_req_val != codec_spec_conf::kLeAudioCodecLC3FrameDur10000us) || - !(u8_pac_val & - (codec_spec_caps::FrameDurationConfig2Capability(u8_req_val)))) { - LOG_DEBUG(" Req:FrameDur=0x%04x", u8_req_val); - LOG_DEBUG(" Pac:FrameDur=0x%04x", u8_pac_val); - LOG_DEBUG(", frame duration not supported"); + /* Frame duration */ + if (!caps.HasSupportedFrameDurations() || !config.frame_duration) { + LOG_DEBUG("Missing supported frame durations capability"); return false; } - - uint8_t required_audio_chan_num = lc3_config.GetChannelCount(); - pac = pacs.Find(codec_spec_caps::kLeAudioCodecLC3TypeAudioChannelCounts); - - /* - * BAP_Validation_r07 1.9.2 Audio channel support requirements - * "The Unicast Server shall support an Audio_Channel_Counts value of 0x01 - * (0b00000001 = one channel) and may support other values defined by an - * implementation or by a higher-layer specification." - * - * Thus if Audio_Channel_Counts is not present in PAC LTV structure, we assume - * the Unicast Server supports mandatory one channel. - */ - if (!pac) { - LOG_DEBUG(", no Audio_Channel_Counts field in PAC, using default 0x01"); - u8_pac_val = 0x01; - } else { - u8_pac_val = VEC_UINT8_TO_UINT8(pac.value()); - } - - if (!((1 << (required_audio_chan_num - 1)) & u8_pac_val)) { - LOG_DEBUG(" Req:AudioChanCnt=0x%04x", 1 << (required_audio_chan_num - 1)); - LOG_DEBUG(" Pac:AudioChanCnt=0x%04x", u8_pac_val); - LOG_DEBUG(", channel count warning"); + if (!caps.IsFrameDurationConfigSupported(config.frame_duration.value())) { + LOG_DEBUG("Cfg: FrameDuration= 0x%04x", config.frame_duration.value()); + LOG_DEBUG("Cap: SupportedFrameDurations= 0x%04x", + caps.supported_frame_durations.value()); + LOG_DEBUG("Frame duration not supported"); return false; } /* Octets per frame */ - req = reqs.Find(codec_spec_conf::kLeAudioCodecLC3TypeOctetPerFrame); - pac = pacs.Find(codec_spec_caps::kLeAudioCodecLC3TypeOctetPerFrame); - - if (!req || !pac) { - LOG_DEBUG(", lack of octet per frame fields"); - return false; - } - - u16_req_val = VEC_UINT8_TO_UINT16(req.value()); - /* Minimal value 0-1 byte */ - u16_pac_val = VEC_UINT8_TO_UINT16(pac.value()); - if (u16_req_val < u16_pac_val) { - LOG_DEBUG(" Req:OctetsPerFrame=%d", int(u16_req_val)); - LOG_DEBUG(" Pac:MinOctetsPerFrame=%d", int(u16_pac_val)); - LOG_DEBUG(", octet per frame below minimum"); + if (!caps.HasSupportedOctetsPerCodecFrame() || + !config.octets_per_codec_frame) { + LOG_DEBUG("Missing supported octets per codec frame"); return false; } - - /* Maximal value 2-3 byte */ - u16_pac_val = OFF_VEC_UINT8_TO_UINT16(pac.value(), 2); - if (u16_req_val > u16_pac_val) { - LOG_DEBUG(" Req:MaxOctetsPerFrame=%d", int(u16_req_val)); - LOG_DEBUG(" Pac:MaxOctetsPerFrame=%d", int(u16_pac_val)); - LOG_DEBUG(", octet per frame above maximum"); + if (!caps.IsOctetsPerCodecFrameConfigSupported( + config.octets_per_codec_frame.value())) { + LOG_DEBUG("Cfg: Octets per frame=%d", + config.octets_per_codec_frame.value()); + LOG_DEBUG("Cap: Min octets per frame=%d", + caps.supported_min_octets_per_codec_frame.value()); + LOG_DEBUG("Cap: Max octets per frame=%d", + caps.supported_max_octets_per_codec_frame.value()); + LOG_DEBUG("Octets per codec frame outside the capabilities"); return false; } return true; } -bool IsCodecCapabilitySettingSupported( - const acs_ac_record& pac, - const CodecCapabilitySetting& codec_capability_setting) { - const auto& codec_id = codec_capability_setting.id; +bool IsCodecConfigSettingSupported( + const acs_ac_record& pac, const CodecConfigSetting& codec_config_setting) { + const auto& codec_id = codec_config_setting.id; if (codec_id != pac.codec_id) return false; @@ -374,35 +321,34 @@ bool IsCodecCapabilitySettingSupported( switch (codec_id.coding_format) { case kLeAudioCodingFormatLC3: - return IsCodecConfigurationSupported( - pac.codec_spec_caps, - std::get(codec_capability_setting.config)); + return IsCodecConfigCoreSupported(pac.codec_spec_caps, + codec_config_setting.params); default: return false; } } -uint32_t CodecCapabilitySetting::GetConfigSamplingFrequency() const { +uint32_t CodecConfigSetting::GetSamplingFrequencyHz() const { switch (id.coding_format) { case kLeAudioCodingFormatLC3: - return std::get(config).GetSamplingFrequencyHz(); + return params.GetAsCoreCodecConfig().GetSamplingFrequencyHz(); default: LOG_WARN(", invalid codec id: 0x%02x", id.coding_format); return 0; } }; -uint32_t CodecCapabilitySetting::GetConfigDataIntervalUs() const { +uint32_t CodecConfigSetting::GetDataIntervalUs() const { switch (id.coding_format) { case kLeAudioCodingFormatLC3: - return std::get(config).GetFrameDurationUs(); + return params.GetAsCoreCodecConfig().GetFrameDurationUs(); default: LOG_WARN(", invalid codec id: 0x%02x", id.coding_format); return 0; } }; -uint8_t CodecCapabilitySetting::GetConfigBitsPerSample() const { +uint8_t CodecConfigSetting::GetBitsPerSample() const { switch (id.coding_format) { case kLeAudioCodingFormatLC3: /* XXX LC3 supports 16, 24, 32 */ @@ -412,24 +358,11 @@ uint8_t CodecCapabilitySetting::GetConfigBitsPerSample() const { return 0; } }; - -uint8_t CodecCapabilitySetting::GetConfigChannelCount() const { - switch (id.coding_format) { - case kLeAudioCodingFormatLC3: - LOG_DEBUG("count = %d", - static_cast( - std::get(config).channel_count)); - return std::get(config).channel_count; - default: - LOG_WARN(", invalid codec id: 0x%02x", id.coding_format); - return 0; - } -} } // namespace set_configurations namespace types { /* Helper map for matching various frequency notations */ -const std::map LeAudioLc3Config::sampling_freq_map = { +const std::map LeAudioCoreCodecConfig::sampling_freq_map = { {codec_spec_conf::kLeAudioSamplingFreq8000Hz, LeAudioCodecConfiguration::kSampleRate8000}, {codec_spec_conf::kLeAudioSamplingFreq16000Hz, @@ -444,23 +377,23 @@ const std::map LeAudioLc3Config::sampling_freq_map = { LeAudioCodecConfiguration::kSampleRate48000}}; /* Helper map for matching various frame durations notations */ -const std::map LeAudioLc3Config::frame_duration_map = { - {codec_spec_conf::kLeAudioCodecLC3FrameDur7500us, +const std::map LeAudioCoreCodecConfig::frame_duration_map = { + {codec_spec_conf::kLeAudioCodecFrameDur7500us, LeAudioCodecConfiguration::kInterval7500Us}, - {codec_spec_conf::kLeAudioCodecLC3FrameDur10000us, + {codec_spec_conf::kLeAudioCodecFrameDur10000us, LeAudioCodecConfiguration::kInterval10000Us}}; std::string CapabilityTypeToStr(const uint8_t& type) { switch (type) { - case codec_spec_caps::kLeAudioCodecLC3TypeSamplingFreq: + case codec_spec_caps::kLeAudioLtvTypeSupportedSamplingFrequencies: return "Supported Sampling Frequencies"; - case codec_spec_caps::kLeAudioCodecLC3TypeFrameDuration: + case codec_spec_caps::kLeAudioLtvTypeSupportedFrameDurations: return "Supported Frame Durations"; - case codec_spec_caps::kLeAudioCodecLC3TypeAudioChannelCounts: + case codec_spec_caps::kLeAudioLtvTypeSupportedAudioChannelCounts: return "Supported Audio Channel Count"; - case codec_spec_caps::kLeAudioCodecLC3TypeOctetPerFrame: + case codec_spec_caps::kLeAudioLtvTypeSupportedOctetsPerCodecFrame: return "Supported Octets Per Codec Frame"; - case codec_spec_caps::kLeAudioCodecLC3TypeMaxCodecFramesPerSdu: + case codec_spec_caps::kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu: return "Supported Max Codec Frames Per SDU"; default: return "Unknown"; @@ -472,7 +405,7 @@ std::string CapabilityValueToStr(const uint8_t& type, std::string string = ""; switch (type) { - case codec_spec_conf::kLeAudioCodecLC3TypeSamplingFreq: { + case codec_spec_conf::kLeAudioLtvTypeSamplingFreq: { if (value.size() != 2) { return "Invalid size"; } @@ -521,66 +454,66 @@ std::string CapabilityValueToStr(const uint8_t& type, return string += " [kHz]\n"; } - case codec_spec_conf::kLeAudioCodecLC3TypeFrameDuration: { + case codec_spec_conf::kLeAudioLtvTypeFrameDuration: { if (value.size() != 1) { return "Invalid size"; } uint8_t u8_val = VEC_UINT8_TO_UINT8(value); - if (u8_val & codec_spec_caps::kLeAudioCodecLC3FrameDur7500us) { + if (u8_val & codec_spec_caps::kLeAudioCodecFrameDur7500us) { string += "7.5"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3FrameDur10000us) { + if (u8_val & codec_spec_caps::kLeAudioCodecFrameDur10000us) { string += std::string((string.empty() ? "" : "|")) + "10"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3FrameDurPrefer7500us) { + if (u8_val & codec_spec_caps::kLeAudioCodecFrameDurPrefer7500us) { string += std::string((string.empty() ? "" : "|")) + "7.5 preferred"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3FrameDurPrefer10000us) { + if (u8_val & codec_spec_caps::kLeAudioCodecFrameDurPrefer10000us) { string += std::string((string.empty() ? "" : "|")) + "10 preferred"; } return string += " [ms]\n"; } - case codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation: { + case codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation: { if (value.size() != 1) { return "Invalid size"; } uint8_t u8_val = VEC_UINT8_TO_UINT8(value); - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountNone) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountNone) { string += "0"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountSingleChannel) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSingleChannel) { string += std::string((string.empty() ? "" : "|")) + "1"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountTwoChannel) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountTwoChannel) { string += std::string((string.empty() ? "" : "|")) + "2"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountThreeChannel) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountThreeChannel) { string += std::string((string.empty() ? "" : "|")) + "3"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountFourChannel) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountFourChannel) { string += std::string((string.empty() ? "" : "|")) + "4"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountFiveChannel) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountFiveChannel) { string += std::string((string.empty() ? "" : "|")) + "5"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountSixChannel) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSixChannel) { string += std::string((string.empty() ? "" : "|")) + "6"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountSevenChannel) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountSevenChannel) { string += std::string((string.empty() ? "" : "|")) + "7"; } - if (u8_val & codec_spec_caps::kLeAudioCodecLC3ChannelCountEightChannel) { + if (u8_val & codec_spec_caps::kLeAudioCodecChannelCountEightChannel) { string += std::string((string.empty() ? "" : "|")) + "8"; } return string += " channel/s\n"; } - case codec_spec_conf::kLeAudioCodecLC3TypeOctetPerFrame: { + case codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame: { if (value.size() != 4) { return "Invalid size"; } @@ -594,7 +527,7 @@ std::string CapabilityValueToStr(const uint8_t& type, return string; } - case codec_spec_conf::kLeAudioCodecLC3TypeCodecFrameBlocksPerSdu: { + case codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu: { if (value.size() != 1) { return "Invalid size"; } @@ -724,6 +657,26 @@ std::string LeAudioLtvMap::ToString( return debug_str; } +const struct LeAudioCoreCodecConfig& LeAudioLtvMap::GetAsCoreCodecConfig() + const { + ASSERT_LOG(!core_capabilities, "LTVs were already parsed for capabilities!"); + + if (!core_config) { + core_config = LtvMapToCoreCodecConfig(*this); + } + return *core_config; +} + +const struct LeAudioCoreCodecCapabilities& +LeAudioLtvMap::GetAsCoreCodecCapabilities() const { + ASSERT_LOG(!core_config, "LTVs were already parsed for configurations!"); + + if (!core_capabilities) { + core_capabilities = LtvMapToCoreCodecCapabilities(*this); + } + return *core_capabilities; +} + } // namespace types void AppendMetadataLtvEntryForCcidList(std::vector& metadata, @@ -762,34 +715,26 @@ void AppendMetadataLtvEntryForStreamingContext( uint8_t GetMaxCodecFramesPerSduFromPac(const acs_ac_record* pac) { auto tlv_ent = pac->codec_spec_caps.Find( - codec_spec_caps::kLeAudioCodecLC3TypeMaxCodecFramesPerSdu); + codec_spec_caps::kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu); if (tlv_ent) return VEC_UINT8_TO_UINT8(tlv_ent.value()); return 1; } -uint32_t AdjustAllocationForOffloader(uint32_t allocation) { - if ((allocation & codec_spec_conf::kLeAudioLocationAnyLeft) && - (allocation & codec_spec_conf::kLeAudioLocationAnyRight)) { - return codec_spec_conf::kLeAudioLocationStereo; - } - if (allocation & codec_spec_conf::kLeAudioLocationAnyLeft) { - return codec_spec_conf::kLeAudioLocationFrontLeft; - } +namespace types { +std::ostream& operator<<(std::ostream& os, const CisState& state) { + static const char* char_value_[5] = {"IDLE", "ASSIGNED", "CONNECTING", + "CONNECTED", "DISCONNECTING"}; - if (allocation & codec_spec_conf::kLeAudioLocationAnyRight) { - return codec_spec_conf::kLeAudioLocationFrontRight; - } - return 0; + os << char_value_[static_cast(state)] << " (" + << "0x" << std::setfill('0') << std::setw(2) << static_cast(state) + << ")"; + return os; } - -namespace types { -std::ostream& operator<<(std::ostream& os, - const AudioStreamDataPathState& state) { - static const char* char_value_[6] = { - "IDLE", "CIS_DISCONNECTING", "CIS_ASSIGNED", - "CIS_PENDING", "CIS_ESTABLISHED", "DATA_PATH_ESTABLISHED"}; +std::ostream& operator<<(std::ostream& os, const DataPathState& state) { + static const char* char_value_[4] = {"IDLE", "CONFIGURING", "CONFIGURED", + "REMOVING"}; os << char_value_[static_cast(state)] << " (" << "0x" << std::setfill('0') << std::setw(2) << static_cast(state) @@ -818,8 +763,9 @@ std::ostream& operator<<(std::ostream& os, const types::AseState& state) { } std::ostream& operator<<(std::ostream& os, - const types::LeAudioLc3Config& config) { - os << " LeAudioLc3Config(SamplFreq=" << loghex(*config.sampling_frequency) + const types::LeAudioCoreCodecConfig& config) { + os << " LeAudioCoreCodecConfig(SamplFreq=" + << loghex(*config.sampling_frequency) << ", FrameDur=" << loghex(*config.frame_duration) << ", OctetsPerFrame=" << int(*config.octets_per_codec_frame) << ", CodecFramesBlocksPerSDU=" << int(*config.codec_frames_blocks_per_sdu) @@ -903,6 +849,23 @@ std::ostream& operator<<(std::ostream& os, const AudioContexts& contexts) { return os; } +template +const T& BidirectionalPair::get(uint8_t direction) const { + ASSERT_LOG( + direction < types::kLeAudioDirectionBoth, + "Unsupported complex direction. Consider using get_bidirectional<>() " + "instead."); + return (direction == types::kLeAudioDirectionSink) ? sink : source; +} + +template +T& BidirectionalPair::get(uint8_t direction) { + ASSERT_LOG(direction < types::kLeAudioDirectionBoth, + "Unsupported complex direction. Reference to a single complex" + " direction value is not supported."); + return (direction == types::kLeAudioDirectionSink) ? sink : source; +} + /* Bidirectional getter trait for AudioContexts bidirectional pair */ template <> AudioContexts get_bidirectional(BidirectionalPair p) { @@ -924,7 +887,13 @@ AudioLocations get_bidirectional(BidirectionalPair bidir) { template struct BidirectionalPair; template struct BidirectionalPair; +template struct BidirectionalPair; +template struct BidirectionalPair; +template struct BidirectionalPair; template struct BidirectionalPair>; +template struct BidirectionalPair; +template struct BidirectionalPair; +template struct BidirectionalPair; } // namespace types } // namespace le_audio diff --git a/system/bta/le_audio/le_audio_types.h b/system/bta/le_audio/le_audio_types.h index 88ce002fe9fa7e205d8bc4dc6445a848508d1d32..eea6b4403c3b4c09bd935a56c34b3129355a7b7f 100644 --- a/system/bta/le_audio/le_audio_types.h +++ b/system/bta/le_audio/le_audio_types.h @@ -31,19 +31,20 @@ #include #include -#include "bta_groups.h" -#include "bta_le_audio_api.h" +#include "bluetooth/uuid.h" #include "bta_le_audio_uuids.h" #include "btm_iso_api_types.h" +#include "osi/include/alarm.h" +#include "stack/include/bt_types.h" namespace le_audio { #define UINT8_TO_VEC_UINT8(u8) \ std::vector { u8 } #define UINT16_TO_VEC_UINT8(u16) \ - std::vector((uint8_t*)&u16, (uint8_t*)&u16 + sizeof(u16)) + std::vector((uint8_t*)&u16, (uint8_t*)&u16 + sizeof(uint16_t)) #define UINT32_TO_VEC_UINT8(u32) \ - std::vector((uint8_t*)&u32, (uint8_t*)&u32 + sizeof(u32)) + std::vector((uint8_t*)&u32, (uint8_t*)&u32 + sizeof(uint32_t)) #define VEC_UINT8_TO_UINT8(vec) vec.data()[0] #define VEC_UINT8_TO_UINT16(vec) ((vec.data()[1] << 8) + vec.data()[0]) @@ -53,6 +54,9 @@ namespace le_audio { ((vec.data()[3] << 24) + (vec.data()[2] << 16) + (vec.data()[1] << 8) + \ vec.data()[0]) +enum class DsaMode { DISABLED = 0, ACL, ISO_SW, ISO_HW }; +typedef std::vector DsaModes; + namespace uuid { /* CAP service * This service is used to identify peer role (which we are not using for now) @@ -103,11 +107,11 @@ static const bluetooth::Uuid kTelephonyMediaAudioProfileRoleCharacteristicUuid = namespace codec_spec_conf { /* LTV Types */ -constexpr uint8_t kLeAudioCodecLC3TypeSamplingFreq = 0x01; -constexpr uint8_t kLeAudioCodecLC3TypeFrameDuration = 0x02; -constexpr uint8_t kLeAudioCodecLC3TypeAudioChannelAllocation = 0x03; -constexpr uint8_t kLeAudioCodecLC3TypeOctetPerFrame = 0x04; -constexpr uint8_t kLeAudioCodecLC3TypeCodecFrameBlocksPerSdu = 0x05; +constexpr uint8_t kLeAudioLtvTypeSamplingFreq = 0x01; +constexpr uint8_t kLeAudioLtvTypeFrameDuration = 0x02; +constexpr uint8_t kLeAudioLtvTypeAudioChannelAllocation = 0x03; +constexpr uint8_t kLeAudioLtvTypeOctetsPerCodecFrame = 0x04; +constexpr uint8_t kLeAudioLtvTypeCodecFrameBlocksPerSdu = 0x05; /* Sampling Frequencies */ constexpr uint8_t kLeAudioSamplingFreq8000Hz = 0x01; @@ -125,8 +129,8 @@ constexpr uint8_t kLeAudioSamplingFreq192000Hz = 0x0C; constexpr uint8_t kLeAudioSamplingFreq384000Hz = 0x0D; /* Frame Durations */ -constexpr uint8_t kLeAudioCodecLC3FrameDur7500us = 0x00; -constexpr uint8_t kLeAudioCodecLC3FrameDur10000us = 0x01; +constexpr uint8_t kLeAudioCodecFrameDur7500us = 0x00; +constexpr uint8_t kLeAudioCodecFrameDur10000us = 0x01; /* Audio Allocations */ constexpr uint32_t kLeAudioLocationNotAllowed = 0x00000000; @@ -177,11 +181,12 @@ constexpr uint32_t kLeAudioLocationStereo = kLeAudioLocationFrontLeft | kLeAudioLocationFrontRight; /* Octets Per Frame */ -constexpr uint16_t kLeAudioCodecLC3FrameLen30 = 30; -constexpr uint16_t kLeAudioCodecLC3FrameLen40 = 40; -constexpr uint16_t kLeAudioCodecLC3FrameLen60 = 60; -constexpr uint16_t kLeAudioCodecLC3FrameLen80 = 80; -constexpr uint16_t kLeAudioCodecLC3FrameLen120 = 120; +constexpr uint16_t kLeAudioCodecFrameLen30 = 30; +constexpr uint16_t kLeAudioCodecFrameLen40 = 40; +constexpr uint16_t kLeAudioCodecFrameLen60 = 60; +constexpr uint16_t kLeAudioCodecFrameLen80 = 80; +constexpr uint16_t kLeAudioCodecFrameLen100 = 100; +constexpr uint16_t kLeAudioCodecFrameLen120 = 120; } // namespace codec_spec_conf @@ -196,32 +201,19 @@ uint8_t constexpr FrameDurationConfig2Capability(uint8_t conf) { return (0x01 << (conf)); } -inline uint8_t GetAudioChannelCounts(std::bitset<32> allocation) { - /* - * BAP d09r07 B4.2.3 Audio_Channel_Allocation - * "(...) Audio_Channel_Allocation bitmap value of all zeros or the - * absence of the Audio_Channel_Allocation LTV structure within a - * Codec_Specific_Configuration field shall be interpreted as defining a - * single audio channel of Mono audio (a single channel of no specified - * Audio Location). - */ - uint8_t audio_channel_counts = allocation.count() ?: 1; - return (0x01 << (audio_channel_counts - 1)); -} - /* LTV Types - same values as in Codec Specific Configurations but 0x03 is * named differently. */ -constexpr uint8_t kLeAudioCodecLC3TypeSamplingFreq = - codec_spec_conf::kLeAudioCodecLC3TypeSamplingFreq; -constexpr uint8_t kLeAudioCodecLC3TypeFrameDuration = - codec_spec_conf::kLeAudioCodecLC3TypeFrameDuration; -constexpr uint8_t kLeAudioCodecLC3TypeAudioChannelCounts = - codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation; -constexpr uint8_t kLeAudioCodecLC3TypeOctetPerFrame = - codec_spec_conf::kLeAudioCodecLC3TypeOctetPerFrame; -constexpr uint8_t kLeAudioCodecLC3TypeMaxCodecFramesPerSdu = - codec_spec_conf::kLeAudioCodecLC3TypeCodecFrameBlocksPerSdu; +constexpr uint8_t kLeAudioLtvTypeSupportedSamplingFrequencies = + codec_spec_conf::kLeAudioLtvTypeSamplingFreq; +constexpr uint8_t kLeAudioLtvTypeSupportedFrameDurations = + codec_spec_conf::kLeAudioLtvTypeFrameDuration; +constexpr uint8_t kLeAudioLtvTypeSupportedAudioChannelCounts = + codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation; +constexpr uint8_t kLeAudioLtvTypeSupportedOctetsPerCodecFrame = + codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame; +constexpr uint8_t kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu = + codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu; /* Sampling Frequencies */ constexpr uint16_t kLeAudioSamplingFreq8000Hz = @@ -252,38 +244,38 @@ constexpr uint16_t kLeAudioSamplingFreq384000Hz = SamplingFreqConfig2Capability( codec_spec_conf::kLeAudioSamplingFreq384000Hz); /* Frame Durations */ -constexpr uint8_t kLeAudioCodecLC3FrameDur7500us = - FrameDurationConfig2Capability( - codec_spec_conf::kLeAudioCodecLC3FrameDur7500us); -constexpr uint8_t kLeAudioCodecLC3FrameDur10000us = - FrameDurationConfig2Capability( - codec_spec_conf::kLeAudioCodecLC3FrameDur10000us); -constexpr uint8_t kLeAudioCodecLC3FrameDurPrefer7500us = 0x10; -constexpr uint8_t kLeAudioCodecLC3FrameDurPrefer10000us = 0x20; +constexpr uint8_t kLeAudioCodecFrameDur7500us = FrameDurationConfig2Capability( + codec_spec_conf::kLeAudioCodecFrameDur7500us); +constexpr uint8_t kLeAudioCodecFrameDur10000us = FrameDurationConfig2Capability( + codec_spec_conf::kLeAudioCodecFrameDur10000us); +constexpr uint8_t kLeAudioCodecFrameDurPrefer7500us = 0x10; +constexpr uint8_t kLeAudioCodecFrameDurPrefer10000us = 0x20; /* Audio Channel Counts */ /* Each bit represents support for additional channel: bit 0 - one channel, * bit 1 - two, bit 3 - four channels. Multiple bits can be enabled at once. */ -constexpr uint8_t kLeAudioCodecLC3ChannelCountNone = 0x00; -constexpr uint8_t kLeAudioCodecLC3ChannelCountSingleChannel = 0x01; -constexpr uint8_t kLeAudioCodecLC3ChannelCountTwoChannel = 0x02; -constexpr uint8_t kLeAudioCodecLC3ChannelCountThreeChannel = 0x04; -constexpr uint8_t kLeAudioCodecLC3ChannelCountFourChannel = 0x08; -constexpr uint8_t kLeAudioCodecLC3ChannelCountFiveChannel = 0x10; -constexpr uint8_t kLeAudioCodecLC3ChannelCountSixChannel = 0x20; -constexpr uint8_t kLeAudioCodecLC3ChannelCountSevenChannel = 0x40; -constexpr uint8_t kLeAudioCodecLC3ChannelCountEightChannel = 0x40; - -/* Octets Per Frame - same as in Codec Specific Configurations but in - * capabilities we get two values: min and max. - */ -constexpr uint16_t kLeAudioCodecLC3FrameLen30 = - codec_spec_conf::kLeAudioCodecLC3FrameLen30; -constexpr uint16_t kLeAudioCodecLC3FrameLen40 = - codec_spec_conf::kLeAudioCodecLC3FrameLen40; -constexpr uint16_t kLeAudioCodecLC3FrameLen120 = - codec_spec_conf::kLeAudioCodecLC3FrameLen120; +constexpr uint8_t kLeAudioCodecChannelCountNone = 0x00; +constexpr uint8_t kLeAudioCodecChannelCountSingleChannel = 0x01; +constexpr uint8_t kLeAudioCodecChannelCountTwoChannel = 0x02; +constexpr uint8_t kLeAudioCodecChannelCountThreeChannel = 0x04; +constexpr uint8_t kLeAudioCodecChannelCountFourChannel = 0x08; +constexpr uint8_t kLeAudioCodecChannelCountFiveChannel = 0x10; +constexpr uint8_t kLeAudioCodecChannelCountSixChannel = 0x20; +constexpr uint8_t kLeAudioCodecChannelCountSevenChannel = 0x40; +constexpr uint8_t kLeAudioCodecChannelCountEightChannel = 0x40; + +/* Octets Per Frame */ +constexpr uint16_t kLeAudioCodecFrameLen30 = + codec_spec_conf::kLeAudioCodecFrameLen30; +constexpr uint16_t kLeAudioCodecFrameLen40 = + codec_spec_conf::kLeAudioCodecFrameLen40; +constexpr uint16_t kLeAudioCodecFrameLen60 = + codec_spec_conf::kLeAudioCodecFrameLen60; +constexpr uint16_t kLeAudioCodecFrameLen80 = + codec_spec_conf::kLeAudioCodecFrameLen80; +constexpr uint16_t kLeAudioCodecFrameLen120 = + codec_spec_conf::kLeAudioCodecFrameLen120; }; // namespace codec_spec_caps @@ -294,6 +286,10 @@ constexpr uint8_t kLeAudioCodingFormatVendorSpecific = constexpr uint16_t kLeAudioVendorCompanyIdUndefined = 0x00; constexpr uint16_t kLeAudioVendorCodecIdUndefined = 0x00; +constexpr uint16_t kLeAudioVendorCompanyIdGoogle = 0x00E0; +/* Todo: Temporary value */ +constexpr uint16_t kLeAudioVendorCodecIdHeadtracking = 0x0001; + /* Metadata types from Assigned Numbers */ constexpr uint8_t kLeAudioMetadataTypePreferredAudioContext = 0x01; constexpr uint8_t kLeAudioMetadataTypeStreamingAudioContext = 0x02; @@ -312,6 +308,8 @@ constexpr uint8_t kDefaultCsisSetSize = 2; constexpr uint8_t kLeAudioDirectionSink = 0x01; constexpr uint8_t kLeAudioDirectionSource = 0x02; +constexpr uint8_t kLeAudioDirectionBoth = + kLeAudioDirectionSink | kLeAudioDirectionSource; /* Audio stream config types */ constexpr uint8_t kFramingUnframedPduSupported = 0x00; @@ -343,13 +341,19 @@ enum class AseState : uint8_t { BTA_LE_AUDIO_ASE_STATE_RELEASING = 0x06, }; -enum class AudioStreamDataPathState { +enum class CisState { + IDLE, + ASSIGNED, + CONNECTING, + CONNECTED, + DISCONNECTING, +}; + +enum class DataPathState { IDLE, - CIS_DISCONNECTING, - CIS_ASSIGNED, - CIS_PENDING, - CIS_ESTABLISHED, - DATA_PATH_ESTABLISHED, + CONFIGURING, + CONFIGURED, + REMOVING, }; enum class CisType { @@ -409,8 +413,10 @@ class AudioContexts { } bool any() const { return !none(); } - void set(LeAudioContextType const& v) { mValue |= static_cast(v); } + void set(const LeAudioContextType& v) { mValue |= static_cast(v); } + void set_all(const AudioContexts& v) { mValue |= v.value(); } void unset(const LeAudioContextType& v) { mValue &= ~static_cast(v); } + void unset_all(const AudioContexts& v) { mValue &= ~v.value(); } bool test(const LeAudioContextType& v) const { return (mValue & static_cast(v)) != 0; @@ -474,31 +480,21 @@ struct BidirectionalPair { T sink; T source; - T get(uint8_t direction) const { - if (direction == - (types::kLeAudioDirectionSink | types::kLeAudioDirectionSource)) { - return get_bidirectional(*this); - } else if (direction == types::kLeAudioDirectionSink) { - return sink; - } - return source; - } - T& get_ref(uint8_t direction) { - return (direction == types::kLeAudioDirectionSink) ? sink : source; - } + const T& get(uint8_t direction) const; + T& get(uint8_t direction); BidirectionalPair& operator=(const BidirectionalPair&) = default; - bool operator==(const BidirectionalPair& other) const { - return (sink == other.sink) && (source == other.source); - }; - bool operator!=(const BidirectionalPair& other) const { - return (sink != other.sink) || (source != other.source); - }; }; template T get_bidirectional(BidirectionalPair p); +template +bool operator==(const types::BidirectionalPair& lhs, + const types::BidirectionalPair& rhs) { + return (lhs.sink == rhs.sink) && (lhs.source == rhs.source); +} + /* Configuration strategy */ enum class LeAudioConfigurationStrategy : uint8_t { MONO_ONE_CIS_PER_DEVICE = 0x00, /* Common true wireless speakers */ @@ -525,42 +521,30 @@ constexpr AudioContexts kLeAudioContextAllTypes = LeAudioContextType::NOTIFICATIONS | LeAudioContextType::RINGTONE | LeAudioContextType::ALERTS | LeAudioContextType::EMERGENCYALARM; +constexpr AudioContexts kLeAudioContextAllBidir = + LeAudioContextType::GAME | LeAudioContextType::LIVE | + LeAudioContextType::CONVERSATIONAL | LeAudioContextType::VOICEASSISTANTS; + +constexpr AudioContexts kLeAudioContextAllRemoteSource = + LeAudioContextType::GAME | LeAudioContextType::LIVE | + LeAudioContextType::CONVERSATIONAL | LeAudioContextType::VOICEASSISTANTS; + +constexpr AudioContexts kLeAudioContextAllRemoteSinkOnly = + LeAudioContextType::MEDIA | LeAudioContextType::INSTRUCTIONAL | + LeAudioContextType::SOUNDEFFECTS | LeAudioContextType::NOTIFICATIONS | + LeAudioContextType::RINGTONE | LeAudioContextType::ALERTS | + LeAudioContextType::EMERGENCYALARM; + /* Print formaters for LTV data */ std::string CodecCapabilitiesLtvFormat(const uint8_t& type, const std::vector& value); /* Structures */ -class LeAudioLtvMap { - public: - LeAudioLtvMap() {} - LeAudioLtvMap(std::map> values) - : values(std::move(values)) {} - - std::optional> Find(uint8_t type) const; - void Add(uint8_t type, std::vector value) { - values.insert_or_assign(type, std::move(value)); - } - void Remove(uint8_t type) { values.erase(type); } - bool IsEmpty() const { return values.empty(); } - void Clear() { values.clear(); } - size_t Size() const { return values.size(); } - const std::map>& Values() const { - return values; - } - std::string ToString( - const std::string& indent_string, - std::string (*format)(const uint8_t&, const std::vector&)) const; - size_t RawPacketSize() const; - uint8_t* RawPacket(uint8_t* p_buf) const; - std::vector RawPacket() const; - static LeAudioLtvMap Parse(const uint8_t* value, uint8_t len, bool& success); - void Append(const LeAudioLtvMap& other); - - private: - std::map> values; -}; - -struct LeAudioLc3Config { +/** LE Audio ASE codec configuration parameters, built from LTV types defined + * in the BT Assigned Numbers. + * NOTE: This base structure does not support the vendor specific parameters. + */ +struct LeAudioCoreCodecConfig { static const std::map sampling_freq_map; static const std::map frame_duration_map; @@ -570,7 +554,19 @@ struct LeAudioLc3Config { std::optional octets_per_codec_frame; std::optional codec_frames_blocks_per_sdu; - uint8_t channel_count; + uint8_t allocated_channel_count = 1; + + static uint32_t GetSamplingFrequencyHz(uint8_t sample_freq) { + return sampling_freq_map.count(sample_freq) + ? sampling_freq_map.at(sample_freq) + : 0; + } + + static uint32_t GetFrameDurationUs(uint8_t framn_dur) { + return frame_duration_map.count(framn_dur) + ? frame_duration_map.at(framn_dur) + : 0; + } /** Returns the sampling frequency representation in Hz */ uint32_t GetSamplingFrequencyHz() const { @@ -591,42 +587,242 @@ struct LeAudioLc3Config { return 0; } - uint8_t GetChannelCount(void) const { - if (channel_count) return channel_count; + /** Channel count per CIS or BIS */ + uint8_t GetChannelCountPerIsoStream(void) const { + return allocated_channel_count; + } +}; - return 0; +struct LeAudioCoreCodecCapabilities { + bool HasSupportedSamplingFrequencies() const { + return supported_sampling_frequencies.has_value(); + } + bool HasSupportedFrameDurations() const { + return supported_frame_durations.has_value(); + } + bool HasSupportedOctetsPerCodecFrame() const { + return supported_min_octets_per_codec_frame.has_value() && + supported_max_octets_per_codec_frame.has_value(); + } + bool HasSupportedAudioChannelCounts() const { + return supported_audio_channel_counts.has_value(); + } + bool HasSupportedMaxCodecFramesPerSdu() const { + return supported_max_codec_frames_per_sdu.has_value(); } - LeAudioLtvMap GetAsLtvMap() const { - std::map> values; + bool IsSamplingFrequencyConfigSupported(uint8_t value) const { + return supported_sampling_frequencies.value_or(0) & + codec_spec_caps::SamplingFreqConfig2Capability(value); + } + bool IsFrameDurationConfigSupported(uint8_t value) const { + return supported_frame_durations.value_or(0) & + codec_spec_caps::FrameDurationConfig2Capability(value); + } + bool IsAudioChannelCountsSupported(uint8_t value) const { + if (value > 0) + return supported_audio_channel_counts.value_or(0) & (0b1 << (value - 1)); + + return false; + } + bool IsOctetsPerCodecFrameConfigSupported(uint16_t value) const { + return (value >= supported_min_octets_per_codec_frame.value_or(0)) && + (value <= supported_max_octets_per_codec_frame.value_or(0)); + } + bool IsCodecFramesPerSduSupported(uint8_t value) const { + return value <= supported_max_codec_frames_per_sdu.value_or(1); + } + + std::optional supported_sampling_frequencies; + std::optional supported_frame_durations; + std::optional supported_audio_channel_counts; + std::optional supported_min_octets_per_codec_frame; + std::optional supported_max_octets_per_codec_frame; + std::optional supported_max_codec_frames_per_sdu; +}; - if (sampling_frequency) { - values[codec_spec_conf::kLeAudioCodecLC3TypeSamplingFreq] = - UINT8_TO_VEC_UINT8(*sampling_frequency); +class LeAudioLtvMap { + public: + LeAudioLtvMap() {} + LeAudioLtvMap(std::map> values) + : values(std::move(values)), core_config(std::nullopt) {} + + std::optional> Find(uint8_t type) const; + LeAudioLtvMap& Add(uint8_t type, std::vector value) { + values.insert_or_assign(type, std::move(value)); + core_config = std::nullopt; + return *this; + } + LeAudioLtvMap& Add(uint8_t type, uint8_t value) { + std::vector v(sizeof(value)); + auto ptr = v.data(); + + UINT8_TO_STREAM(ptr, value); + values.insert_or_assign(type, v); + core_config = std::nullopt; + return *this; + } + LeAudioLtvMap& Add(uint8_t type, uint16_t value) { + std::vector v(sizeof(value)); + auto ptr = v.data(); + + UINT16_TO_STREAM(ptr, value); + values.insert_or_assign(type, std::move(v)); + core_config = std::nullopt; + return *this; + } + LeAudioLtvMap& Add(uint8_t type, uint32_t value) { + std::vector v(sizeof(value)); + auto ptr = v.data(); + + UINT32_TO_STREAM(ptr, value); + values.insert_or_assign(type, std::move(v)); + core_config = std::nullopt; + return *this; + } + void Remove(uint8_t type) { values.erase(type); } + bool IsEmpty() const { return values.empty(); } + void Clear() { values.clear(); } + size_t Size() const { return values.size(); } + const std::map>& Values() const { + return values; + } + + const struct LeAudioCoreCodecConfig& GetAsCoreCodecConfig() const; + const struct LeAudioCoreCodecCapabilities& GetAsCoreCodecCapabilities() const; + + std::string ToString( + const std::string& indent_string, + std::string (*format)(const uint8_t&, const std::vector&)) const; + size_t RawPacketSize() const; + uint8_t* RawPacket(uint8_t* p_buf) const; + std::vector RawPacket() const; + static LeAudioLtvMap Parse(const uint8_t* value, uint8_t len, bool& success); + void Append(const LeAudioLtvMap& other); + + private: + static LeAudioCoreCodecConfig LtvMapToCoreCodecConfig(LeAudioLtvMap ltvs) { + LeAudioCoreCodecConfig core; + + auto vec_opt = ltvs.Find(codec_spec_conf::kLeAudioLtvTypeSamplingFreq); + if (vec_opt && (vec_opt->size() == + sizeof(decltype(core.sampling_frequency)::value_type))) { + auto ptr = vec_opt->data(); + STREAM_TO_UINT8(core.sampling_frequency, ptr); + } + + vec_opt = ltvs.Find(codec_spec_conf::kLeAudioLtvTypeFrameDuration); + if (vec_opt && (vec_opt->size() == + sizeof(decltype(core.frame_duration)::value_type))) { + auto ptr = vec_opt->data(); + STREAM_TO_UINT8(core.frame_duration, ptr); + } + + vec_opt = ltvs.Find(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation); + if (vec_opt && + (vec_opt->size() == + sizeof(decltype(core.audio_channel_allocation)::value_type))) { + auto ptr = vec_opt->data(); + STREAM_TO_UINT32(core.audio_channel_allocation, ptr); + core.allocated_channel_count = + std::bitset<32>(core.audio_channel_allocation.value()).count(); + } else { + core.allocated_channel_count = 1; + } + + vec_opt = ltvs.Find(codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame); + if (vec_opt && + (vec_opt->size() == + sizeof(decltype(core.octets_per_codec_frame)::value_type))) { + auto ptr = vec_opt->data(); + STREAM_TO_UINT16(core.octets_per_codec_frame, ptr); } - if (frame_duration) { - values[codec_spec_conf::kLeAudioCodecLC3TypeFrameDuration] = - UINT8_TO_VEC_UINT8(*frame_duration); + vec_opt = ltvs.Find(codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu); + if (vec_opt && + (vec_opt->size() == + sizeof(decltype(core.codec_frames_blocks_per_sdu)::value_type))) { + auto ptr = vec_opt->data(); + STREAM_TO_UINT8(core.codec_frames_blocks_per_sdu, ptr); } - if (audio_channel_allocation) { - values[codec_spec_conf::kLeAudioCodecLC3TypeAudioChannelAllocation] = - UINT32_TO_VEC_UINT8(*audio_channel_allocation); + return core; + } + + static LeAudioCoreCodecCapabilities LtvMapToCoreCodecCapabilities( + LeAudioLtvMap pacs) { + LeAudioCoreCodecCapabilities core; + + auto pac = + pacs.Find(codec_spec_caps::kLeAudioLtvTypeSupportedSamplingFrequencies); + if (pac && + (pac.value().size() == + sizeof(decltype(core.supported_sampling_frequencies)::value_type))) { + core.supported_sampling_frequencies = VEC_UINT8_TO_UINT16(pac.value()); + } + + pac = pacs.Find(codec_spec_caps::kLeAudioLtvTypeSupportedFrameDurations); + if (pac && (pac.value().size() == + sizeof(decltype(core.supported_frame_durations)::value_type))) { + core.supported_frame_durations = VEC_UINT8_TO_UINT8(pac.value()); } - if (octets_per_codec_frame) { - values[codec_spec_conf::kLeAudioCodecLC3TypeOctetPerFrame] = - UINT16_TO_VEC_UINT8(*octets_per_codec_frame); + pac = + pacs.Find(codec_spec_caps::kLeAudioLtvTypeSupportedOctetsPerCodecFrame); + if (pac && + (pac.value().size() == + (sizeof( + decltype(core.supported_min_octets_per_codec_frame)::value_type) + + sizeof(decltype(core.supported_max_octets_per_codec_frame):: + value_type)))) { + core.supported_min_octets_per_codec_frame = + VEC_UINT8_TO_UINT16(pac.value()); + core.supported_max_octets_per_codec_frame = OFF_VEC_UINT8_TO_UINT16( + pac.value(), + sizeof( + decltype(core.supported_min_octets_per_codec_frame)::value_type)); } - if (codec_frames_blocks_per_sdu) { - values[codec_spec_conf::kLeAudioCodecLC3TypeCodecFrameBlocksPerSdu] = - UINT8_TO_VEC_UINT8(*codec_frames_blocks_per_sdu); + /* + * BAP_1.0.1 4.3.1 Codec_Specific_Capabilities LTV requirements: + * The absence of the Supported_Audio_Channel_Counts LTV structure shall be + * interpreted as equivalent to a Supported_Audio_Channel_Counts value of + * 0x01 (one Audio Channel supported). + */ + pac = + pacs.Find(codec_spec_caps::kLeAudioLtvTypeSupportedAudioChannelCounts); + if (pac && + (pac.value().size() == + sizeof(decltype(core.supported_audio_channel_counts)::value_type))) { + core.supported_audio_channel_counts = VEC_UINT8_TO_UINT8(pac.value()); + } else { + core.supported_audio_channel_counts = 0b1; } - return LeAudioLtvMap(values); + /* + * BAP_1.0.1 4.3.1 Codec_Specific_Capabilities LTV requirements: + * The absence of the Supported_Max_Codec_Frames_Per_SDU LTV structure shall + * be interpreted as equivalent to a Supported_Max_Codec_Frames_Per_SDU + * value of 1 codec frame per Audio Channel per SDU maximum. + */ + pac = pacs.Find( + codec_spec_caps::kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu); + if (pac && + (pac.value().size() == + sizeof( + decltype(core.supported_max_codec_frames_per_sdu)::value_type))) { + core.supported_max_codec_frames_per_sdu = VEC_UINT8_TO_UINT8(pac.value()); + } else { + core.supported_max_codec_frames_per_sdu = 1; + } + + return core; } + + std::map> values; + // Lazy-constructed views of the LTV data + mutable std::optional core_config; + mutable std::optional core_capabilities; }; struct LeAudioCodecId { @@ -650,6 +846,11 @@ struct LeAudioCodecId { } }; +/* Google vendor specific codec for Headtracking */ +constexpr LeAudioCodecId kLeAudioCodecHeadtracking = { + kLeAudioCodingFormatVendorSpecific, kLeAudioVendorCompanyIdGoogle, + kLeAudioVendorCodecIdHeadtracking}; + struct hdl_pair { hdl_pair() = default; hdl_pair(uint16_t val_hdl, uint16_t ccc_hdl) @@ -671,9 +872,12 @@ struct ase { target_latency(types::kTargetLatencyBalancedLatencyReliability), active(false), reconfigure(false), - data_path_state(AudioStreamDataPathState::IDLE), + cis_state(CisState::IDLE), + data_path_state(DataPathState::IDLE), configured_for_context_type(LeAudioContextType::UNINITIALIZED), preferred_phy(0), + is_codec_in_controller(false), + data_path_id(bluetooth::hci::iso_manager::kIsoDataPathDisabled), max_sdu_size(0), retrans_nb(0), max_transport_latency(0), @@ -681,6 +885,8 @@ struct ase { pres_delay_max(0), preferred_pres_delay_min(0), preferred_pres_delay_max(0), + autonomous_operation_timer_(nullptr), + autonomous_target_state_(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), state(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {} struct hdl_pair hdls; @@ -692,15 +898,24 @@ struct ase { bool active; bool reconfigure; - AudioStreamDataPathState data_path_state; + CisState cis_state; + DataPathState data_path_state; LeAudioContextType configured_for_context_type; /* Codec configuration */ LeAudioCodecId codec_id; - LeAudioLc3Config codec_config; + LeAudioLtvMap codec_config; + uint8_t framing; uint8_t preferred_phy; + /* Set to true, if the codec is implemented in BT controller, false if it's + * implemented in host, or in separate DSP + */ + bool is_codec_in_controller; + /* Datapath ID used to configure an ISO channel for these ASEs */ + uint8_t data_path_id; + /* Qos configuration */ uint16_t max_sdu_size; uint8_t retrans_nb; @@ -712,12 +927,11 @@ struct ase { std::vector metadata; - AseState state; -}; + /* Autonomous change data */ + alarm_t* autonomous_operation_timer_; + types::AseState autonomous_target_state_; -struct BidirectAsesPair { - struct ase* sink; - struct ase* source; + AseState state; }; struct acs_ac_record { @@ -732,30 +946,41 @@ using AudioLocations = std::bitset<32>; std::ostream& operator<<(std::ostream& os, const AseState& state); std::ostream& operator<<(std::ostream& os, const CigState& state); -std::ostream& operator<<(std::ostream& os, const LeAudioLc3Config& config); +std::ostream& operator<<(std::ostream& os, + const LeAudioCoreCodecConfig& config); std::string contextTypeToStr(const LeAudioContextType& context); std::ostream& operator<<(std::ostream& os, const LeAudioContextType& context); -std::ostream& operator<<(std::ostream& os, - const AudioStreamDataPathState& state); +std::ostream& operator<<(std::ostream& os, const DataPathState& state); +std::ostream& operator<<(std::ostream& os, const CisState& state); std::ostream& operator<<(std::ostream& os, const AudioContexts& contexts); } // namespace types namespace set_configurations { -struct CodecCapabilitySetting { +struct CodecConfigSetting { + /* Codec identifier */ types::LeAudioCodecId id; - /* Codec Specific Configuration variant */ - std::variant config; + /* Codec Specific Configuration */ + types::LeAudioLtvMap params; + + /* Channel count per device */ + uint8_t channel_count_per_iso_stream; /* Sampling freqency requested for codec */ - uint32_t GetConfigSamplingFrequency() const; + uint32_t GetSamplingFrequencyHz() const; /* Data fetch/feed interval for codec in microseconds */ - uint32_t GetConfigDataIntervalUs() const; + uint32_t GetDataIntervalUs() const; /* Audio bit depth required for codec */ - uint8_t GetConfigBitsPerSample() const; - /* Audio channels number for stream */ - uint8_t GetConfigChannelCount() const; + uint8_t GetBitsPerSample() const; + /* Audio channels number for a device */ + uint8_t GetChannelCountPerIsoStream() const { + return channel_count_per_iso_stream; + } + + /* TODO: Add vendor parameter or Ltv map viewers for + * vendor specific LTV types. + */ }; struct QosConfigSetting { @@ -766,7 +991,7 @@ struct QosConfigSetting { struct SetConfiguration { SetConfiguration(uint8_t direction, uint8_t device_cnt, uint8_t ase_cnt, - CodecCapabilitySetting codec, + CodecConfigSetting codec, QosConfigSetting qos = {.retransmission_number = 0, .max_transport_latency = 0}, le_audio::types::LeAudioConfigurationStrategy strategy = @@ -782,7 +1007,13 @@ struct SetConfiguration { uint8_t direction; /* Direction of set */ uint8_t device_cnt; /* How many devices must be in set */ uint8_t ase_cnt; /* How many ASE we need in configuration */ - CodecCapabilitySetting codec; + + /* Whether the codec location is transparent to the controller */ + bool is_codec_in_controller = false; + /* Datapath ID used to configure an ISO channel for these ASEs */ + uint8_t data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci; + + CodecConfigSetting codec; QosConfigSetting qos; types::LeAudioConfigurationStrategy strategy; }; @@ -815,70 +1046,51 @@ bool check_if_may_cover_scenario( const AudioSetConfigurations* audio_set_configurations, uint8_t group_size); bool check_if_may_cover_scenario( const AudioSetConfiguration* audio_set_configuration, uint8_t group_size); -bool IsCodecCapabilitySettingSupported( +bool IsCodecConfigSettingSupported( const types::acs_ac_record& pac_record, - const CodecCapabilitySetting& codec_capability_setting); + const CodecConfigSetting& codec_capability_setting); uint8_t get_num_of_devices_in_configuration( const AudioSetConfiguration* audio_set_configuration); } // namespace set_configurations -struct stream_map_info { - stream_map_info(uint16_t stream_handle, uint32_t audio_channel_allocation, - bool is_stream_active) - : stream_handle(stream_handle), - audio_channel_allocation(audio_channel_allocation), - is_stream_active(is_stream_active) {} - uint16_t stream_handle; +struct stream_parameters { + /* For now we have always same frequency for all the channels */ + uint32_t sample_frequency_hz; + uint32_t frame_duration_us; + uint16_t octets_per_codec_frame; uint32_t audio_channel_allocation; - bool is_stream_active; + uint8_t codec_frames_blocks_per_sdu; + + /* Total number of channels we request from the audio framework */ + uint8_t num_of_channels; + int num_of_devices; + /* cis_handle, audio location*/ + std::vector> stream_locations; + + void clear() { + sample_frequency_hz = 0; + frame_duration_us = 0; + octets_per_codec_frame = 0; + audio_channel_allocation = 0; + codec_frames_blocks_per_sdu = 0; + num_of_channels = 0; + num_of_devices = 0; + stream_locations.clear(); + } }; struct stream_configuration { + /* Whether the group should be reconfigured once the streaming stops */ bool pending_configuration; - types::LeAudioCodecId id; - - /* Pointer to chosen req */ + /* Currently selected remote device set configuration */ const le_audio::set_configurations::AudioSetConfiguration* conf; - /* Sink configuration */ - /* For now we have always same frequency for all the channels */ - uint32_t sink_sample_frequency_hz; - uint32_t sink_frame_duration_us; - uint16_t sink_octets_per_codec_frame; - uint32_t sink_audio_channel_allocation; - uint8_t sink_codec_frames_blocks_per_sdu; - /* Number of channels is what we will request from audio framework */ - uint8_t sink_num_of_channels; - int sink_num_of_devices; - /* cis_handle, audio location*/ - std::vector> sink_streams; - /* cis_handle, target allocation, stream active state */ - std::vector sink_offloader_streams_target_allocation; - /* cis_handle, current allocation, stream active state */ - std::vector sink_offloader_streams_current_allocation; - bool sink_offloader_changed; - bool sink_is_initial; - - /* Source configuration */ - /* For now we have always same frequency for all the channels */ - uint32_t source_sample_frequency_hz; - uint32_t source_frame_duration_us; - uint16_t source_octets_per_codec_frame; - uint32_t source_audio_channel_allocation; - uint8_t source_codec_frames_blocks_per_sdu; - /* Number of channels is what we will request from audio framework */ - uint8_t source_num_of_channels; - int source_num_of_devices; - /* cis_handle, audio location*/ - std::vector> source_streams; - /* cis_handle, target allocation, stream active state */ - std::vector source_offloader_streams_target_allocation; - /* cis_handle, current allocation, stream active state */ - std::vector source_offloader_streams_current_allocation; - bool source_offloader_changed; - bool source_is_initial; - bool is_active; + /* Currently selected local audio codec */ + types::LeAudioCodecId codec_id; + + /* Currently selected local Sink & Source configuration */ + types::BidirectionalPair stream_params; }; void AppendMetadataLtvEntryForCcidList(std::vector& metadata, @@ -886,5 +1098,4 @@ void AppendMetadataLtvEntryForCcidList(std::vector& metadata, void AppendMetadataLtvEntryForStreamingContext( std::vector& metadata, types::AudioContexts context_type); uint8_t GetMaxCodecFramesPerSduFromPac(const types::acs_ac_record* pac_record); -uint32_t AdjustAllocationForOffloader(uint32_t allocation); } // namespace le_audio \ No newline at end of file diff --git a/system/bta/le_audio/le_audio_types_test.cc b/system/bta/le_audio/le_audio_types_test.cc index 23066d9790a91364f4c30c9221557b0b3760d552..d39fecd3970cd1491061d8e6239a05b155dca030 100644 --- a/system/bta/le_audio/le_audio_types_test.cc +++ b/system/bta/le_audio/le_audio_types_test.cc @@ -88,6 +88,22 @@ TEST(LeAudioLtvMapTest, test_serialization) { ASSERT_THAT(ltv_map2.RawPacket(), ElementsAreArray(ltv_test_vec2)); } +TEST(LeAudioLtvMapTest, test_serialization_macros) { + uint64_t value = 0x08090A0B0C0D0E0F; + + auto u16vec = UINT16_TO_VEC_UINT8(value); + ASSERT_EQ(sizeof(uint16_t), u16vec.size()); + ASSERT_EQ(0x0F, u16vec[0]); + ASSERT_EQ(0x0E, u16vec[1]); + + auto u32vec = UINT32_TO_VEC_UINT8(value); + ASSERT_EQ(sizeof(uint32_t), u32vec.size()); + ASSERT_EQ(0x0F, u32vec[0]); + ASSERT_EQ(0x0E, u32vec[1]); + ASSERT_EQ(0x0D, u32vec[2]); + ASSERT_EQ(0x0C, u32vec[3]); +} + TEST(LeAudioLtvMapTest, test_serialization_ltv_len_is_zero) { // clang-format off const std::vector ltv_test_vec{ @@ -182,5 +198,177 @@ TEST(LeAudioLtvMapTest, test_serialization_ltv_len_is_invalid) { ASSERT_FALSE(success); } +TEST(LeAudioLtvMapTest, test_configuration_valid) { + // clang-format off + const std::vector config_ltv_vec{ + // SamplingFreq = 48000 + 0x02, 0x01, 0x08, + // FrameDuration = 10000us + 0x02, 0x02, 0x01, + // AudioChannelAllocation = kLeAudioLocationFrontLeft | + // kLeAudioLocationFrontRight + 0x05, 0x03, 0x03, 0x00, 0x00, 0x00, + // OctetsPerCodecFrame = 40 + 0x03, 0x04, 40, 0x00, + // Unknown type entry to ignore + 0x05, 0x06, 0x11, 0x22, 0x33, 0x44, + // CodecFrameBlocksPerSdu = 1 + 0x02, 0x05, 1, + }; + // clang-format on + + // Parse + bool success = true; + LeAudioLtvMap ltv_map = LeAudioLtvMap::Parse(config_ltv_vec.data(), + config_ltv_vec.size(), success); + ASSERT_TRUE(success); + + // Verify the codec configuration values + auto config = ltv_map.GetAsCoreCodecConfig(); + + // SamplingFreq = 48000 + ASSERT_TRUE(config.sampling_frequency.has_value()); + ASSERT_EQ(0x08, config.sampling_frequency.value()); + ASSERT_EQ(48000u, config.GetSamplingFrequencyHz()); + + // FrameDuration = 10000us + ASSERT_TRUE(config.frame_duration.has_value()); + ASSERT_EQ(0x01, config.frame_duration.value()); + ASSERT_EQ(10000u, config.GetFrameDurationUs()); + + // AudioChannelAllocation = kLeAudioLocationFrontLeft | + // kLeAudioLocationFrontRight + ASSERT_TRUE(config.audio_channel_allocation.has_value()); + ASSERT_EQ(0x00000003u, config.audio_channel_allocation.value()); + // Check if allocated channel count matches the number of allocation bits + ASSERT_EQ(2u, config.GetChannelCountPerIsoStream()); + + // OctetsPerCodecFrame = 40 + ASSERT_TRUE(config.octets_per_codec_frame.has_value()); + ASSERT_EQ(0x0028u, config.octets_per_codec_frame.value()); + + // CodecFrameBlocksPerSdu = 1 + ASSERT_TRUE(config.codec_frames_blocks_per_sdu.has_value()); + ASSERT_EQ(0x01u, config.codec_frames_blocks_per_sdu.value()); +} + +TEST(LeAudioLtvMapTest, test_capabilities_valid) { + // clang-format off + const std::vector capabilities_ltv_vec{ + // SupportedSamplingFrequencies = 96000 and 16000 + 0x03, 0x01, + (uint8_t)(codec_spec_caps::kLeAudioSamplingFreq16000Hz) | + (uint8_t)(codec_spec_caps::kLeAudioSamplingFreq96000Hz), + (uint8_t)(codec_spec_caps::kLeAudioSamplingFreq16000Hz >> 8) | + (uint8_t)(codec_spec_caps::kLeAudioSamplingFreq96000Hz >> 8), + // SupportedFrameDurations = 10ms, 7.5ms, 10ms preferred + 0x02, 0x02, codec_spec_caps::kLeAudioCodecFrameDur7500us | + codec_spec_caps::kLeAudioCodecFrameDur10000us | + codec_spec_caps::kLeAudioCodecFrameDurPrefer10000us, + // SupportedAudioChannelCounts = 0b1 | 0b2 (one and two channels) + 0x02, 0x03, 0b01 | 0b10, + // SupportedOctetsPerCodecFrame = min:40, max:80 + 0x05, 0x04, 40, 00, 80, 00, + // Unknown type entry to ignore + 0x05, 0x06, 0x11, 0x22, 0x33, 0x44, + // SupportedMaxCodecFramesPerSdu = 2 + 0x02, 0x05, 0x02, + }; + // clang-format on + + // Parse + bool success = true; + LeAudioLtvMap ltv_map = LeAudioLtvMap::Parse( + capabilities_ltv_vec.data(), capabilities_ltv_vec.size(), success); + ASSERT_TRUE(success); + + // Verify the codec capabilities values + auto caps = ltv_map.GetAsCoreCodecCapabilities(); + + // SupportedSamplingFrequencies = 96000 and 16000 + ASSERT_TRUE(caps.HasSupportedSamplingFrequencies()); + ASSERT_EQ(codec_spec_caps::kLeAudioSamplingFreq16000Hz | + codec_spec_caps::kLeAudioSamplingFreq96000Hz, + caps.supported_sampling_frequencies.value()); + // Check config values agains the capabilities + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq8000Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq11025Hz)); + ASSERT_TRUE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq16000Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq22050Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq24000Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq32000Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq44100Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq48000Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq88200Hz)); + ASSERT_TRUE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq96000Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq176400Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq192000Hz)); + ASSERT_FALSE(caps.IsSamplingFrequencyConfigSupported( + codec_spec_conf::kLeAudioSamplingFreq384000Hz)); + + // SupportedFrameDurations = 10ms, 7.5ms, 10ms preferred + ASSERT_TRUE(caps.HasSupportedFrameDurations()); + ASSERT_EQ(codec_spec_caps::kLeAudioCodecFrameDur7500us | + codec_spec_caps::kLeAudioCodecFrameDur10000us | + codec_spec_caps::kLeAudioCodecFrameDurPrefer10000us, + caps.supported_frame_durations.value()); + // Check config values agains the capabilities + ASSERT_TRUE(caps.IsFrameDurationConfigSupported( + codec_spec_conf::kLeAudioCodecFrameDur7500us)); + ASSERT_TRUE(caps.IsFrameDurationConfigSupported( + codec_spec_conf::kLeAudioCodecFrameDur10000us)); + + // SupportedAudioChannelCounts = 0b1 | 0b2 (one and two channels) + ASSERT_TRUE(caps.HasSupportedAudioChannelCounts()); + ASSERT_EQ(codec_spec_caps::kLeAudioCodecChannelCountSingleChannel | + codec_spec_caps::kLeAudioCodecChannelCountTwoChannel, + caps.supported_audio_channel_counts.value()); + // Check config values agains the capabilities + ASSERT_TRUE(caps.IsAudioChannelCountsSupported(1)); + ASSERT_TRUE(caps.IsAudioChannelCountsSupported(2)); + for (uint8_t i = 3; i < 8; ++i) { + ASSERT_FALSE(caps.IsAudioChannelCountsSupported(i)); + } + + // SupportedOctetsPerCodecFrame = min:40, max:80 + ASSERT_TRUE(caps.HasSupportedOctetsPerCodecFrame()); + ASSERT_EQ(codec_spec_caps::kLeAudioCodecFrameLen40, + caps.supported_min_octets_per_codec_frame.value()); + ASSERT_EQ(codec_spec_caps::kLeAudioCodecFrameLen80, + caps.supported_max_octets_per_codec_frame.value()); + // Check config values agains the capabilities + ASSERT_FALSE(caps.IsOctetsPerCodecFrameConfigSupported( + codec_spec_conf::kLeAudioCodecFrameLen30)); + ASSERT_TRUE(caps.IsOctetsPerCodecFrameConfigSupported( + codec_spec_conf::kLeAudioCodecFrameLen40)); + // Supported since: 40(min) < 60 < 80(max) + ASSERT_TRUE(caps.IsOctetsPerCodecFrameConfigSupported( + codec_spec_conf::kLeAudioCodecFrameLen60)); + ASSERT_TRUE(caps.IsOctetsPerCodecFrameConfigSupported( + codec_spec_conf::kLeAudioCodecFrameLen80)); + ASSERT_FALSE(caps.IsOctetsPerCodecFrameConfigSupported( + codec_spec_conf::kLeAudioCodecFrameLen120)); + + // SupportedMaxCodecFramesPerSdu = 2 + ASSERT_TRUE(caps.HasSupportedMaxCodecFramesPerSdu()); + ASSERT_EQ(2, caps.supported_max_codec_frames_per_sdu.value()); + // Check config values agains the capabilities: {1,2} <= 2(max) + ASSERT_TRUE(caps.IsCodecFramesPerSduSupported(1)); + ASSERT_TRUE(caps.IsCodecFramesPerSduSupported(2)); + ASSERT_FALSE(caps.IsCodecFramesPerSduSupported(3)); +} + } // namespace types } // namespace le_audio diff --git a/system/bta/le_audio/le_audio_utils.cc b/system/bta/le_audio/le_audio_utils.cc index 0fe7128f4557fae1a63c6207cb9335bb7cbfcfc2..579945972f65e5514d94cdfc1ce866e4ee6ae69b 100644 --- a/system/bta/le_audio/le_audio_utils.cc +++ b/system/bta/le_audio/le_audio_utils.cc @@ -150,53 +150,63 @@ static const char* audioSourceToStr(audio_source_t source) { return "UNKNOWN"; } -AudioContexts GetAllowedAudioContextsFromSourceMetadata( - const std::vector& source_metadata, - AudioContexts allowed_contexts) { +static bool isMetadataTagPresent(const char* tags, const char* tag) { + std::istringstream iss(tags); + std::string t; + while (std::getline(iss, t, AUDIO_ATTRIBUTES_TAGS_SEPARATOR)) { + LOG_VERBOSE("Tag %s", t.c_str()); + if (t.compare(tag) == 0) { + return true; + } + } + return false; +} + +AudioContexts GetAudioContextsFromSourceMetadata( + const source_metadata_v7& source_metadata) { AudioContexts track_contexts; - for (auto& track : source_metadata) { + for (size_t i = 0; i < source_metadata.track_count; i++) { + auto track = source_metadata.tracks[i].base; if (track.content_type == 0 && track.usage == 0) continue; - LOG_INFO("%s: usage=%s(%d), content_type=%s(%d), gain=%f", __func__, + LOG_INFO("%s: usage=%s(%d), content_type=%s(%d), gain=%f, tag:%s", __func__, usageToString(track.usage).c_str(), track.usage, contentTypeToString(track.content_type).c_str(), - track.content_type, track.gain); + track.content_type, track.gain, source_metadata.tracks[i].tags); - track_contexts.set( - AudioContentToLeAudioContext(track.content_type, track.usage)); + if (isMetadataTagPresent(source_metadata.tracks[i].tags, + "VX_AOSP_SAMPLESOUND")) { + track_contexts.set(LeAudioContextType::SOUNDEFFECTS); + } else { + track_contexts.set( + AudioContentToLeAudioContext(track.content_type, track.usage)); + } } - track_contexts &= allowed_contexts; - LOG_INFO("%s: allowed context= %s", __func__, - track_contexts.to_string().c_str()); - return track_contexts; } -AudioContexts GetAllowedAudioContextsFromSinkMetadata( - const std::vector& sink_metadata, - AudioContexts allowed_contexts) { +AudioContexts GetAudioContextsFromSinkMetadata( + const sink_metadata_v7& sink_metadata) { AudioContexts all_track_contexts; - for (auto& track : sink_metadata) { + for (size_t i = 0; i < sink_metadata.track_count; i++) { + auto track = sink_metadata.tracks[i].base; if (track.source == AUDIO_SOURCE_INVALID) continue; LeAudioContextType track_context; LOG_DEBUG( "source=%s(0x%02x), gain=%f, destination device=0x%08x, destination " - "device address=%.32s, allowed_contexts=%s", + "device address=%.32s", audioSourceToStr(track.source), track.source, track.gain, - track.dest_device, track.dest_device_address, - bluetooth::common::ToString(allowed_contexts).c_str()); + track.dest_device, track.dest_device_address); - if ((track.source == AUDIO_SOURCE_MIC) && - (allowed_contexts.test(LeAudioContextType::LIVE))) { + if (track.source == AUDIO_SOURCE_MIC) { track_context = LeAudioContextType::LIVE; - } else if ((track.source == AUDIO_SOURCE_VOICE_COMMUNICATION) && - (allowed_contexts.test(LeAudioContextType::CONVERSATIONAL))) { + } else if (track.source == AUDIO_SOURCE_VOICE_COMMUNICATION) { track_context = LeAudioContextType::CONVERSATIONAL; - } else if (allowed_contexts.test(LeAudioContextType::VOICEASSISTANTS)) { + } else { /* Fallback to voice assistant * This will handle also a case when the device is * AUDIO_SOURCE_VOICE_RECOGNITION @@ -220,11 +230,159 @@ AudioContexts GetAllowedAudioContextsFromSinkMetadata( "sink device. This may result in voice back channel malfunction."); } - LOG_DEBUG("Allowed contexts from sink metadata: %s (0x%08hx)", - bluetooth::common::ToString(all_track_contexts).c_str(), - all_track_contexts.value()); + LOG_INFO("Allowed contexts from sink metadata: %s (0x%08hx)", + bluetooth::common::ToString(all_track_contexts).c_str(), + all_track_contexts.value()); return all_track_contexts; } +bluetooth::le_audio::btle_audio_codec_index_t +translateBluetoothCodecFormatToCodecType(uint8_t codec_format) { + switch (codec_format) { + case types::kLeAudioCodingFormatLC3: + return bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3; + } + return bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_INVALID; +} + +bluetooth::le_audio::btle_audio_sample_rate_index_t +translateToBtLeAudioCodecConfigSampleRate(uint32_t sample_rate_capa) { + LOG_INFO("%d", sample_rate_capa); + return (bluetooth::le_audio::btle_audio_sample_rate_index_t)( + sample_rate_capa); +} + +bluetooth::le_audio::btle_audio_bits_per_sample_index_t +translateToBtLeAudioCodecConfigBitPerSample(uint8_t bits_per_sample) { + switch (bits_per_sample) { + case 16: + return bluetooth::le_audio::LE_AUDIO_BITS_PER_SAMPLE_INDEX_16; + case 24: + return bluetooth::le_audio::LE_AUDIO_BITS_PER_SAMPLE_INDEX_24; + case 32: + return bluetooth::le_audio::LE_AUDIO_BITS_PER_SAMPLE_INDEX_32; + } + return bluetooth::le_audio::LE_AUDIO_BITS_PER_SAMPLE_INDEX_NONE; +} + +bluetooth::le_audio::btle_audio_channel_count_index_t +translateToBtLeAudioCodecConfigChannelCount(uint8_t channel_count) { + switch (channel_count) { + case 1: + return bluetooth::le_audio::LE_AUDIO_CHANNEL_COUNT_INDEX_1; + case 2: + return bluetooth::le_audio::LE_AUDIO_CHANNEL_COUNT_INDEX_2; + } + return bluetooth::le_audio::LE_AUDIO_CHANNEL_COUNT_INDEX_NONE; +} + +bluetooth::le_audio::btle_audio_frame_duration_index_t +translateToBtLeAudioCodecConfigFrameDuration(int frame_duration) { + switch (frame_duration) { + case 7500: + return bluetooth::le_audio::LE_AUDIO_FRAME_DURATION_INDEX_7500US; + case 10000: + return bluetooth::le_audio::LE_AUDIO_FRAME_DURATION_INDEX_10000US; + } + return bluetooth::le_audio::LE_AUDIO_FRAME_DURATION_INDEX_NONE; +} + +void fillStreamParamsToBtLeAudioCodecConfig( + types::LeAudioCodecId codec_id, const stream_parameters* stream_params, + bluetooth::le_audio::btle_audio_codec_config_t& out_config) { + if (stream_params == nullptr) { + LOG_WARN("Stream params are null"); + return; + } + + out_config.codec_type = + translateBluetoothCodecFormatToCodecType(codec_id.coding_format); + if (out_config.codec_type != + bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3) { + return; + } + + out_config.sample_rate = translateToBtLeAudioCodecConfigSampleRate( + stream_params->sample_frequency_hz); + out_config.channel_count = translateToBtLeAudioCodecConfigChannelCount( + stream_params->num_of_channels); + out_config.bits_per_sample = translateToBtLeAudioCodecConfigBitPerSample(16); + out_config.frame_duration = translateToBtLeAudioCodecConfigFrameDuration( + stream_params->frame_duration_us); + out_config.octets_per_frame = stream_params->octets_per_codec_frame; +} + +static bool is_known_codec(const types::LeAudioCodecId& codec_id) { + switch (codec_id.coding_format) { + case types::kLeAudioCodingFormatLC3: + return true; + } + return false; +} + +static void fillRemotePacsCapabitiliesToBtLeAudioCodecConfig( + const struct types::acs_ac_record& record, + std::vector& vec) { + const struct types::LeAudioCoreCodecCapabilities capa = + record.codec_spec_caps.GetAsCoreCodecCapabilities(); + for (uint8_t freq_bit = codec_spec_conf::kLeAudioSamplingFreq8000Hz; + freq_bit <= codec_spec_conf::kLeAudioSamplingFreq384000Hz; freq_bit++) { + if (!capa.IsSamplingFrequencyConfigSupported(freq_bit)) continue; + for (uint8_t fd_bit = codec_spec_conf::kLeAudioCodecFrameDur7500us; + fd_bit <= codec_spec_conf::kLeAudioCodecFrameDur10000us; fd_bit++) { + if (!capa.IsFrameDurationConfigSupported(fd_bit)) continue; + if (!capa.HasSupportedAudioChannelCounts()) { + bluetooth::le_audio::btle_audio_codec_config_t config = { + .sample_rate = utils::translateToBtLeAudioCodecConfigSampleRate( + types::LeAudioCoreCodecConfig::GetSamplingFrequencyHz( + freq_bit)), + .bits_per_sample = + utils::translateToBtLeAudioCodecConfigBitPerSample(16), + .channel_count = + utils::translateToBtLeAudioCodecConfigChannelCount(1), + .frame_duration = + utils::translateToBtLeAudioCodecConfigFrameDuration( + types::LeAudioCoreCodecConfig::GetFrameDurationUs(fd_bit)), + }; + vec.push_back(config); + } else { + for (int chan_bit = 1; chan_bit <= 2; chan_bit++) { + if (!capa.IsAudioChannelCountsSupported(chan_bit)) continue; + + bluetooth::le_audio::btle_audio_codec_config_t config = { + .sample_rate = utils::translateToBtLeAudioCodecConfigSampleRate( + types::LeAudioCoreCodecConfig::GetSamplingFrequencyHz( + freq_bit)), + .bits_per_sample = + utils::translateToBtLeAudioCodecConfigBitPerSample(16), + .channel_count = + utils::translateToBtLeAudioCodecConfigChannelCount(chan_bit), + .frame_duration = + utils::translateToBtLeAudioCodecConfigFrameDuration( + types::LeAudioCoreCodecConfig::GetFrameDurationUs( + fd_bit)), + }; + vec.push_back(config); + } + } + } + } +} + +std::vector +GetRemoteBtLeAudioCodecConfigFromPac( + const types::PublishedAudioCapabilities& group_pacs) { + std::vector vec; + + for (auto& [handles, pacs_record] : group_pacs) { + for (auto& pac : pacs_record) { + if (!is_known_codec(pac.codec_id)) continue; + + fillRemotePacsCapabitiliesToBtLeAudioCodecConfig(pac, vec); + } + } + return vec; +} + } // namespace utils } // namespace le_audio diff --git a/system/bta/le_audio/le_audio_utils.h b/system/bta/le_audio/le_audio_utils.h index b6db4e06a17e937d96e387dded1eaf31fbb6b369..c15e655f9772881cb596fd1a352dd8379f8ca6a3 100644 --- a/system/bta/le_audio/le_audio_utils.h +++ b/system/bta/le_audio/le_audio_utils.h @@ -16,7 +16,13 @@ #pragma once +#ifdef TARGET_FLOSS +#include +#else #include +#endif + +#include #include #include @@ -27,22 +33,29 @@ namespace le_audio { namespace utils { types::LeAudioContextType AudioContentToLeAudioContext( audio_content_type_t content_type, audio_usage_t usage); -types::AudioContexts GetAllowedAudioContextsFromSourceMetadata( - const std::vector& source_metadata, - types::AudioContexts allowed_contexts); -types::AudioContexts GetAllowedAudioContextsFromSinkMetadata( - const std::vector& source_metadata, - types::AudioContexts allowed_contexts); - -static inline bool IsContextForAudioSource(types::LeAudioContextType c) { - if (c == types::LeAudioContextType::CONVERSATIONAL || - c == types::LeAudioContextType::VOICEASSISTANTS || - c == types::LeAudioContextType::LIVE || - c == types::LeAudioContextType::GAME) { - return true; - } - return false; -} +types::AudioContexts GetAudioContextsFromSourceMetadata( + const source_metadata_v7& source_metadata); +types::AudioContexts GetAudioContextsFromSinkMetadata( + const sink_metadata_v7& sink_metadata); + +/* Helpers to get btle_audio_codec_config_t for Java */ +bluetooth::le_audio::btle_audio_codec_index_t +translateBluetoothCodecFormatToCodecType(uint8_t codec_format); + +bluetooth::le_audio::btle_audio_sample_rate_index_t +translateToBtLeAudioCodecConfigSampleRate(uint32_t sample_rate_capa); +bluetooth::le_audio::btle_audio_bits_per_sample_index_t +translateToBtLeAudioCodecConfigBitPerSample(uint8_t bits_per_sample); +bluetooth::le_audio::btle_audio_channel_count_index_t +translateToBtLeAudioCodecConfigChannelCount(uint8_t channel_count); +bluetooth::le_audio::btle_audio_frame_duration_index_t +translateToBtLeAudioCodecConfigFrameDuration(int frame_duration); +void fillStreamParamsToBtLeAudioCodecConfig( + types::LeAudioCodecId codec_id, const stream_parameters* stream_params, + bluetooth::le_audio::btle_audio_codec_config_t& out_config); +std::vector +GetRemoteBtLeAudioCodecConfigFromPac( + const types::PublishedAudioCapabilities& group_pacs); } // namespace utils } // namespace le_audio diff --git a/system/bta/le_audio/metrics_collector.cc b/system/bta/le_audio/metrics_collector.cc index aed66c006e444634c235d2dab806a0621c23f01c..1f982a6690b4425e2e64726ef72ac835200b9e9e 100644 --- a/system/bta/le_audio/metrics_collector.cc +++ b/system/bta/le_audio/metrics_collector.cc @@ -16,6 +16,8 @@ #include "metrics_collector.h" +#include + #include #include diff --git a/system/bta/le_audio/mock_codec_interface.cc b/system/bta/le_audio/mock_codec_interface.cc new file mode 100644 index 0000000000000000000000000000000000000000..c16aae7b723ace89a5bb98328b55900af8af711a --- /dev/null +++ b/system/bta/le_audio/mock_codec_interface.cc @@ -0,0 +1,67 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mock_codec_interface.h" + +namespace le_audio { + +struct CodecInterface::Impl : public MockCodecInterface { + public: + Impl(const types::LeAudioCodecId& codec_id) { + output_channel_data_.resize(1); + }; + ~Impl() = default; + + std::vector& GetDecodedSamples() { return output_channel_data_; } + std::vector output_channel_data_; +}; + +CodecInterface::CodecInterface(const types::LeAudioCodecId& codec_id) { + impl = new Impl(codec_id); +} +CodecInterface::~CodecInterface() { delete impl; } +bool CodecInterface::IsReady() { return impl->IsReady(); }; +CodecInterface::Status CodecInterface::InitEncoder( + const LeAudioCodecConfiguration& pcm_config, + const LeAudioCodecConfiguration& codec_config) { + return impl->InitEncoder(pcm_config, codec_config); +} +CodecInterface::Status CodecInterface::InitDecoder( + const LeAudioCodecConfiguration& codec_config, + const LeAudioCodecConfiguration& pcm_config) { + return impl->InitDecoder(codec_config, pcm_config); +} +std::vector& CodecInterface::GetDecodedSamples() { + return impl->GetDecodedSamples(); +} +CodecInterface::Status CodecInterface::Decode(uint8_t* data, uint16_t size) { + return impl->Decode(data, size); +} +CodecInterface::Status CodecInterface::Encode(const uint8_t* data, int stride, + uint16_t out_size, + std::vector* out_buffer, + uint16_t out_offset) { + return impl->Encode(data, stride, out_size, out_buffer, out_offset); +} +void CodecInterface::Cleanup() { return impl->Cleanup(); } + +uint16_t CodecInterface::GetNumOfSamplesPerChannel() { + return impl->GetNumOfSamplesPerChannel(); +}; +uint8_t CodecInterface::GetNumOfBytesPerSample() { + return impl->GetNumOfBytesPerSample(); +}; +} // namespace le_audio diff --git a/system/bta/le_audio/mock_codec_interface.h b/system/bta/le_audio/mock_codec_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..d2acda6f61e531fe3db74f13ca6f81d92fa1d0ff --- /dev/null +++ b/system/bta/le_audio/mock_codec_interface.h @@ -0,0 +1,47 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "codec_interface.h" + +class MockCodecInterface { + public: + MockCodecInterface() = default; + MockCodecInterface(const MockCodecInterface&) = delete; + MockCodecInterface& operator=(const MockCodecInterface&) = delete; + + virtual ~MockCodecInterface() = default; + + MOCK_METHOD((le_audio::CodecInterface::Status), InitEncoder, + (const le_audio::LeAudioCodecConfiguration& pcm_config, + const le_audio::LeAudioCodecConfiguration& codec_config)); + MOCK_METHOD(le_audio::CodecInterface::Status, InitDecoder, + (const le_audio::LeAudioCodecConfiguration& codec_config, + const le_audio::LeAudioCodecConfiguration& pcm_config)); + MOCK_METHOD(le_audio::CodecInterface::Status, Encode, + (const uint8_t* data, int stride, uint16_t out_size, + std::vector* out_buffer, uint16_t out_offset)); + MOCK_METHOD(le_audio::CodecInterface::Status, Decode, + (uint8_t * data, uint16_t size)); + MOCK_METHOD((void), Cleanup, ()); + MOCK_METHOD((bool), IsReady, ()); + MOCK_METHOD((uint16_t), GetNumOfSamplesPerChannel, ()); + MOCK_METHOD((uint8_t), GetNumOfBytesPerSample, ()); + MOCK_METHOD((std::vector&), GetDecodedSamples, ()); +}; diff --git a/system/bta/le_audio/mock_codec_manager.cc b/system/bta/le_audio/mock_codec_manager.cc index 81060f1d35d0b609c43e5fce4f885ebb39377313..2198c03326d6dde3e3a43de9161d4b7efbc0a448 100644 --- a/system/bta/le_audio/mock_codec_manager.cc +++ b/system/bta/le_audio/mock_codec_manager.cc @@ -37,22 +37,23 @@ types::CodecLocation CodecManager::GetCodecLocation() const { return pimpl_->GetCodecLocation(); } -void CodecManager::UpdateActiveSourceAudioConfig( - const stream_configuration& stream_conf, uint16_t delay_ms, - std::function - update_receiver) { - if (pimpl_) - return pimpl_->UpdateActiveSourceAudioConfig(stream_conf, delay_ms, - update_receiver); +bool CodecManager::IsOffloadDualBiDirSwbSupported(void) const { + if (!pimpl_) { + return false; + } + + return pimpl_->IsOffloadDualBiDirSwbSupported(); } -void CodecManager::UpdateActiveSinkAudioConfig( - const stream_configuration& stream_conf, uint16_t delay_ms, - std::function +void CodecManager::UpdateActiveAudioConfig( + const types::BidirectionalPair& stream_params, + types::BidirectionalPair delays_ms, + std::function update_receiver) { if (pimpl_) - return pimpl_->UpdateActiveSinkAudioConfig(stream_conf, delay_ms, - update_receiver); + return pimpl_->UpdateActiveAudioConfig(stream_params, delays_ms, + update_receiver); } const set_configurations::AudioSetConfigurations* @@ -67,6 +68,20 @@ CodecManager::GetBroadcastOffloadConfig() { return pimpl_->GetBroadcastOffloadConfig(); } +std::vector +CodecManager::GetLocalAudioOutputCodecCapa() { + if (!pimpl_) + return std::vector{}; + return pimpl_->GetLocalAudioOutputCodecCapa(); +} + +std::vector +CodecManager::GetLocalAudioInputCodecCapa() { + if (!pimpl_) + return std::vector{}; + return pimpl_->GetLocalAudioInputCodecCapa(); +} + void CodecManager::UpdateBroadcastConnHandle( const std::vector& conn_handle, std::function @@ -75,11 +90,6 @@ void CodecManager::UpdateBroadcastConnHandle( return pimpl_->UpdateBroadcastConnHandle(conn_handle, update_receiver); } -int CodecManager::GetAidlVersionInUsed() const { - if (!pimpl_) return -1; - return pimpl_->GetAidlVersionInUsed(); -} - void CodecManager::Start( const std::vector& offloading_preference) { @@ -104,6 +114,17 @@ void CodecManager::Stop() { mock_codec_manager_pimpl_ = nullptr; } +void CodecManager::UpdateCisConfiguration( + const std::vector& cises, + const stream_parameters& stream_params, uint8_t direction) { + if (pimpl_) + return pimpl_->UpdateCisConfiguration(cises, stream_params, direction); +} + +void CodecManager::ClearCisConfiguration(uint8_t direction) { + if (pimpl_) return pimpl_->ClearCisConfiguration(direction); +} + // CodecManager::~CodecManager() = default; } // namespace le_audio diff --git a/system/bta/le_audio/mock_codec_manager.h b/system/bta/le_audio/mock_codec_manager.h index eccd9baf28e0ace519fb6e531ba0fa6c26aa19d0..0025b13245787199d1b3433045ff04cc94181e78 100644 --- a/system/bta/le_audio/mock_codec_manager.h +++ b/system/bta/le_audio/mock_codec_manager.h @@ -31,27 +31,34 @@ class MockCodecManager { virtual ~MockCodecManager() = default; MOCK_METHOD((le_audio::types::CodecLocation), GetCodecLocation, (), (const)); - MOCK_METHOD((void), UpdateActiveSourceAudioConfig, - (const le_audio::stream_configuration& stream_conf, - uint16_t delay, - std::function - update_receiver)); - MOCK_METHOD((void), UpdateActiveSinkAudioConfig, - (const le_audio::stream_configuration& stream_conf, - uint16_t delay, - std::function + MOCK_METHOD((bool), IsOffloadDualBiDirSwbSupported, (), (const)); + MOCK_METHOD((void), UpdateActiveAudioConfig, + (const le_audio::types::BidirectionalPair< + le_audio::stream_parameters>& stream_params, + le_audio::types::BidirectionalPair delays_ms, + std::function update_receiver)); MOCK_METHOD((le_audio::set_configurations::AudioSetConfigurations*), GetOffloadCodecConfig, (le_audio::types::LeAudioContextType ctx_type), (const)); MOCK_METHOD((le_audio::broadcast_offload_config*), GetBroadcastOffloadConfig, (), (const)); + MOCK_METHOD((std::vector), + GetLocalAudioOutputCodecCapa, ()); + MOCK_METHOD((std::vector), + GetLocalAudioInputCodecCapa, ()); MOCK_METHOD( (void), UpdateBroadcastConnHandle, (const std::vector& conn_handle, std::function update_receiver)); - MOCK_METHOD((int), GetAidlVersionInUsed, (), (const)); + MOCK_METHOD((void), UpdateCisConfiguration, + (const std::vector& cises, + const le_audio::stream_parameters& stream_params, + uint8_t direction), + (const)); + MOCK_METHOD((void), ClearCisConfiguration, (uint8_t direction)); MOCK_METHOD((void), Start, ()); MOCK_METHOD((void), Stop, ()); diff --git a/system/bta/le_audio/mock_state_machine.h b/system/bta/le_audio/mock_state_machine.h index 02bad5f30ada7dcf7afcf26052be2e6d43e79ae4..9b561367f852b4faafd9231aea2b5131b5f7432b 100644 --- a/system/bta/le_audio/mock_state_machine.h +++ b/system/bta/le_audio/mock_state_machine.h @@ -33,7 +33,8 @@ class MockLeAudioGroupStateMachine : public le_audio::LeAudioGroupStateMachine { (override)); MOCK_METHOD((bool), AttachToStream, (le_audio::LeAudioDeviceGroup * group, - le_audio::LeAudioDevice* leAudioDevice), + le_audio::LeAudioDevice* leAudioDevice, + le_audio::types::BidirectionalPair> ccids), (override)); MOCK_METHOD((void), SuspendStream, (le_audio::LeAudioDeviceGroup * group), (override)); @@ -53,6 +54,10 @@ class MockLeAudioGroupStateMachine : public le_audio::LeAudioGroupStateMachine { le_audio::LeAudioDeviceGroup* group), (override)); + MOCK_METHOD((void), ProcessGattCtpNotification, + (le_audio::LeAudioDeviceGroup * group, uint8_t* value, + uint16_t len), + (override)); MOCK_METHOD((void), ProcessHciNotifOnCigCreate, (le_audio::LeAudioDeviceGroup * group, uint8_t status, uint8_t cig_id, std::vector conn_handles), diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc index 91e346a0dd02cfccd84873d611ca348b402365c7..85443d777b613d1b18dd0c4e7ecae60dbac8f086 100644 --- a/system/bta/le_audio/state_machine.cc +++ b/system/bta/le_audio/state_machine.cc @@ -17,26 +17,24 @@ #include "state_machine.h" +#include #include #include #include -#include - -#include "bt_types.h" #include "bta_gatt_queue.h" -#include "bta_le_audio_api.h" #include "btm_iso_api.h" #include "client_parser.h" #include "codec_manager.h" -#include "content_control_id_keeper.h" #include "devices.h" #include "gd/common/strings.h" +#include "hci/hci_packets.h" #include "hcimsgs.h" +#include "le_audio_health_status.h" #include "le_audio_log_history.h" #include "le_audio_types.h" +#include "os/log.h" #include "osi/include/alarm.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "osi/include/properties.h" @@ -99,18 +97,26 @@ using le_audio::LeAudioDevice; using le_audio::LeAudioDeviceGroup; using le_audio::LeAudioGroupStateMachine; +using bluetooth::hci::ErrorCode; +using bluetooth::hci::ErrorCodeText; +using le_audio::DsaMode; +using le_audio::DsaModes; using le_audio::types::ase; using le_audio::types::AseState; using le_audio::types::AudioContexts; -using le_audio::types::AudioStreamDataPathState; using le_audio::types::BidirectionalPair; using le_audio::types::CigState; +using le_audio::types::CisState; using le_audio::types::CodecLocation; +using le_audio::types::DataPathState; using le_audio::types::LeAudioContextType; +using le_audio::types::LeAudioCoreCodecConfig; namespace { constexpr int linkQualityCheckInterval = 4000; +constexpr int kAutonomousTransitionTimeoutMs = 5000; +constexpr int kNumberOfCisRetries = 2; static void link_quality_cb(void* data) { // very ugly, but we need to pass just two bytes @@ -137,8 +143,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { log_history_ = nullptr; } - bool AttachToStream(LeAudioDeviceGroup* group, - LeAudioDevice* leAudioDevice) override { + bool AttachToStream(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, + BidirectionalPair> ccids) override { LOG(INFO) << __func__ << " group id: " << group->group_id_ << " device: " << ADDRESS_TO_LOGGABLE_STR(leAudioDevice->address_); @@ -146,17 +152,25 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { * Limitation here is that device should be previously in the streaming * group and just got reconnected. */ - if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - LOG_ERROR(" group not in the streaming state: %s", - ToString(group->GetState()).c_str()); + if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING || + group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { + LOG_ERROR( + " group %d no in correct streaming state: %s or target state: %s", + group->group_id_, ToString(group->GetState()).c_str(), + ToString(group->GetTargetState()).c_str()); + return false; + } + + /* This is cautious - mostly needed for unit test only */ + auto group_metadata_contexts = + get_bidirectional(group->GetMetadataContexts()); + auto device_available_contexts = leAudioDevice->GetAvailableContexts(); + if (!group_metadata_contexts.test_any(device_available_contexts)) { + LOG_INFO("%s does is not have required context type", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); return false; } - BidirectionalPair> ccids = { - .sink = le_audio::ContentControlIdKeeper::GetInstance()->GetAllCcids( - group->GetMetadataContexts().sink), - .source = le_audio::ContentControlIdKeeper::GetInstance()->GetAllCcids( - group->GetMetadataContexts().source)}; if (!group->Configure(group->GetConfigurationContextType(), group->GetMetadataContexts(), ccids)) { LOG_ERROR(" failed to set ASE configuration"); @@ -175,9 +189,11 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { switch (group->GetState()) { case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED: - if (group->GetConfigurationContextType() == context_type) { - if (group->Activate(context_type)) { + if (group->IsConfiguredForContext(context_type)) { + if (group->Activate(context_type, metadata_context_types, + ccid_lists)) { SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + if (CigCreate(group)) { return true; } @@ -196,7 +212,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { ReleaseCisIds(group); /* If configuration is needed */ - FALLTHROUGH; + FALLTHROUGH_INTENDED; case AseState::BTA_LE_AUDIO_ASE_STATE_IDLE: if (!group->Configure(context_type, metadata_context_types, ccid_lists)) { @@ -204,7 +220,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return false; } - group->CigGenerateCisIds(context_type); + group->cig.GenerateCisIds(context_type); /* All ASEs should aim to achieve target state */ SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); if (!PrepareAndSendCodecConfigToTheGroup(group)) { @@ -278,7 +294,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return false; } - group->CigGenerateCisIds(context_type); + group->cig.GenerateCisIds(context_type); SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); return PrepareAndSendCodecConfigToTheGroup(group); } @@ -304,6 +320,79 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { state_machine_callbacks_->StatusReportCb(group->group_id_, status); } + void notifyLeAudioHealth(LeAudioDeviceGroup* group, + le_audio::LeAudioHealthGroupStatType stat) { + if (!IS_FLAG_ENABLED(leaudio_enable_health_based_actions)) { + return; + } + + auto leAudioHealthStatus = le_audio::LeAudioHealthStatus::Get(); + if (leAudioHealthStatus) { + leAudioHealthStatus->AddStatisticForGroup(group, stat); + } + } + + void ProcessGattCtpNotification(LeAudioDeviceGroup* group, uint8_t* value, + uint16_t len) { + auto ntf = + std::make_unique(); + + bool valid_notification = ParseAseCtpNotification(*ntf, len, value); + if (group == nullptr) { + LOG_WARN("Notification received to invalid group"); + return; + } + + /* State machine looks on ASE state and base on it take decisions. + * If ASE state is not achieve on time, timeout is reported and upper + * layer mostlikely drops ACL considers that remote is in bad state. + * However, it might happen that remote device rejects ASE configuration for + * some reason and ASCS specification defines tones of different reasons. + * Maybe in the future we will be able to handle all of them but for now it + * seems to be important to allow remote device to reject ASE configuration + * when stream is creating. e.g. Allow remote to reject Enable on unwanted + * context type. + */ + + auto target_state = group->GetTargetState(); + auto in_transition = group->IsInTransition(); + if (!in_transition || + target_state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { + LOG_DEBUG( + "Not interested in ctp result for group %d inTransistion: %d , " + "targetState: %s", + group->group_id_, in_transition, ToString(target_state).c_str()); + return; + } + + if (!valid_notification) { + /* Do nothing, just allow guard timer to fire */ + LOG_ERROR("Invalid CTP notification for group %d", group->group_id_); + return; + } + + for (auto& entry : ntf->entries) { + if (entry.response_code != + le_audio::client_parser::ascs::kCtpResponseCodeSuccess) { + /* Gracefully stop the stream */ + LOG_ERROR( + "Stoping stream due to control point error for ase: %d, error: " + "0x%02x, reason: 0x%02x", + entry.ase_id, entry.response_code, entry.reason); + + notifyLeAudioHealth(group, le_audio::LeAudioHealthGroupStatType:: + STREAM_CREATE_SIGNALING_FAILED); + StopStream(group); + return; + } + } + + LOG_DEBUG( + "Ctp result OK for group %d inTransistion: %d , " + "targetState: %s", + group->group_id_, in_transition, ToString(target_state).c_str()); + } + void ProcessGattNotifEvent(uint8_t* value, uint16_t len, struct ase* ase, LeAudioDevice* leAudioDevice, LeAudioDeviceGroup* group) override { @@ -382,32 +471,32 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { * Reseted, which creates the issue. Lets remove CIG and try to create * it again. */ - group->SetCigState(CigState::RECOVERING); + group->cig.SetState(CigState::RECOVERING); IsoManager::GetInstance()->RemoveCig(group->group_id_, true); return; } - group->SetCigState(CigState::NONE); + group->cig.SetState(CigState::NONE); LOG_ERROR(", failed to create CIG, reason: 0x%02x, new cig state: %s", - +status, ToString(group->cig_state_).c_str()); + +status, ToString(group->cig.GetState()).c_str()); StopStream(group); return; } - ASSERT_LOG(group->GetCigState() == CigState::CREATING, + ASSERT_LOG(group->cig.GetState() == CigState::CREATING, "Unexpected CIG creation group id: %d, cig state: %s", - group->group_id_, ToString(group->cig_state_).c_str()); + group->group_id_, ToString(group->cig.GetState()).c_str()); - group->SetCigState(CigState::CREATED); + group->cig.SetState(CigState::CREATED); LOG_INFO("Group: %p, id: %d cig state: %s, number of cis handles: %d", - group, group->group_id_, ToString(group->cig_state_).c_str(), + group, group->group_id_, ToString(group->cig.GetState()).c_str(), static_cast(conn_handles.size())); - /* Assign all connection handles to cis ids */ - group->CigAssignCisConnHandles(conn_handles); + /* Assign all connection handles to CIS ids of the CIG */ + group->cig.AssignCisConnHandles(conn_handles); - /* Assign all connection handles to ases */ - group->CigAssignCisConnHandlesToAses(); + /* Assign all connection handles to multiple device ASEs */ + group->AssignCisConnHandlesToAses(); /* Last node configured, process group to codec configured state */ group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); @@ -432,7 +521,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { void ProcessHciNotifyOnCigRemoveRecovering(uint8_t status, LeAudioDeviceGroup* group) { - group->SetCigState(CigState::NONE); + group->cig.SetState(CigState::NONE); log_history_->AddLogHistory(kLogHciEvent, group->group_id_, RawAddress::kEmpty, @@ -455,7 +544,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { void ProcessHciNotifOnCigRemove(uint8_t status, LeAudioDeviceGroup* group) override { - if (group->GetCigState() == CigState::RECOVERING) { + if (group->cig.GetState() == CigState::RECOVERING) { ProcessHciNotifyOnCigRemoveRecovering(status, group); return; } @@ -465,18 +554,18 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { kLogCigRemoveOp + " STATUS=" + loghex(status)); if (status != HCI_SUCCESS) { - group->SetCigState(CigState::CREATED); + group->cig.SetState(CigState::CREATED); LOG_ERROR( "failed to remove cig, id: %d, status 0x%02x, new cig state: %s", - group->group_id_, +status, ToString(group->GetCigState()).c_str()); + group->group_id_, +status, ToString(group->cig.GetState()).c_str()); return; } - ASSERT_LOG(group->GetCigState() == CigState::REMOVING, + ASSERT_LOG(group->cig.GetState() == CigState::REMOVING, "Unexpected CIG remove group id: %d, cig state %s", - group->group_id_, ToString(group->GetCigState()).c_str()); + group->group_id_, ToString(group->cig.GetState()).c_str()); - group->SetCigState(CigState::NONE); + group->cig.SetState(CigState::NONE); LeAudioDevice* leAudioDevice = group->GetFirstDevice(); if (!leAudioDevice) return; @@ -485,7 +574,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { FreeLinkQualityReports(leAudioDevice); for (auto& ase : leAudioDevice->ases_) { - ase.data_path_state = AudioStreamDataPathState::IDLE; + ase.cis_state = CisState::IDLE; + ase.data_path_state = DataPathState::IDLE; } } while ((leAudioDevice = group->GetNextDevice(leAudioDevice))); } @@ -507,15 +597,15 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } /* Update state for the given cis.*/ - auto ase = leAudioDevice->GetFirstActiveAseByDataPathState( - AudioStreamDataPathState::CIS_ESTABLISHED); + auto ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState( + CisState::CONNECTED, DataPathState::CONFIGURING); if (!ase || ase->cis_conn_hdl != conn_handle) { LOG(ERROR) << __func__ << " Cannot find ase by handle " << +conn_handle; return; } - ase->data_path_state = AudioStreamDataPathState::DATA_PATH_ESTABLISHED; + ase->data_path_state = DataPathState::CONFIGURED; if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { LOG(WARNING) << __func__ << " Group " << group->group_id_ @@ -525,24 +615,25 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { AddCisToStreamConfiguration(group, ase); - ase = leAudioDevice->GetFirstActiveAseByDataPathState( - AudioStreamDataPathState::CIS_ESTABLISHED); - if (!ase) { - leAudioDevice = group->GetNextActiveDeviceByDataPathState( - leAudioDevice, AudioStreamDataPathState::CIS_ESTABLISHED); - - if (!leAudioDevice) { - state_machine_callbacks_->StatusReportCb(group->group_id_, - GroupStreamStatus::STREAMING); - return; - } - - ase = leAudioDevice->GetFirstActiveAseByDataPathState( - AudioStreamDataPathState::CIS_ESTABLISHED); + if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING && + !group->GetFirstActiveDeviceByCisAndDataPathState( + CisState::CONNECTED, DataPathState::IDLE)) { + /* No more transition for group. Here we are for the late join device + * scenario */ + cancel_watchdog_if_needed(group->group_id_); } - ASSERT_LOG(ase, "shouldn't be called without an active ASE"); - PrepareDataPath(group->group_id_, ase); + if (group->GetNotifyStreamingWhenCisesAreReadyFlag() && + group->IsGroupStreamReady()) { + group->SetNotifyStreamingWhenCisesAreReadyFlag(false); + LOG_INFO("Ready to notify Group Streaming."); + cancel_watchdog_if_needed(group->group_id_); + if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { + group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + } + state_machine_callbacks_->StatusReportCb(group->group_id_, + GroupStreamStatus::STREAMING); + }; } void ProcessHciNotifRemoveIsoDataPath(LeAudioDeviceGroup* group, @@ -564,23 +655,28 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { bool do_disconnect = false; auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(conn_hdl); - if (ases_pair.sink && (ases_pair.sink->data_path_state == - AudioStreamDataPathState::DATA_PATH_ESTABLISHED)) { - ases_pair.sink->data_path_state = - AudioStreamDataPathState::CIS_DISCONNECTING; - do_disconnect = true; + if (ases_pair.sink && + (ases_pair.sink->data_path_state == DataPathState::REMOVING)) { + ases_pair.sink->data_path_state = DataPathState::IDLE; + + if (ases_pair.sink->cis_state == CisState::CONNECTED) { + ases_pair.sink->cis_state = CisState::DISCONNECTING; + do_disconnect = true; + } } if (ases_pair.source && - ases_pair.source->data_path_state == - AudioStreamDataPathState::DATA_PATH_ESTABLISHED) { - ases_pair.source->data_path_state = - AudioStreamDataPathState::CIS_DISCONNECTING; - do_disconnect = true; + (ases_pair.source->data_path_state == DataPathState::REMOVING)) { + ases_pair.source->data_path_state = DataPathState::IDLE; + + if (ases_pair.source->cis_state == CisState::CONNECTED) { + ases_pair.source->cis_state = CisState::DISCONNECTING; + do_disconnect = true; + } } if (do_disconnect) { - RemoveCisFromStreamConfiguration(group, leAudioDevice, conn_hdl); + group->RemoveCisFromStreamIfNeeded(leAudioDevice, conn_hdl); IsoManager::GetInstance()->DisconnectCis(conn_hdl, HCI_ERR_PEER_USER); log_history_->AddLogHistory( @@ -621,22 +717,22 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { leAudioDevice = group->GetNextDevice(leAudioDevice); } - group->CigClearCis(); + group->ClearAllCises(); } void RemoveCigForGroup(LeAudioDeviceGroup* group) { LOG_DEBUG("Group: %p, id: %d cig state: %s", group, group->group_id_, - ToString(group->cig_state_).c_str()); - if (group->GetCigState() != CigState::CREATED) { + ToString(group->cig.GetState()).c_str()); + if (group->cig.GetState() != CigState::CREATED) { LOG_WARN("Group: %p, id: %d cig state: %s cannot be removed", group, - group->group_id_, ToString(group->cig_state_).c_str()); + group->group_id_, ToString(group->cig.GetState()).c_str()); return; } - group->SetCigState(CigState::REMOVING); + group->cig.SetState(CigState::REMOVING); IsoManager::GetInstance()->RemoveCig(group->group_id_); LOG_DEBUG("Group: %p, id: %d cig state: %s", group, group->group_id_, - ToString(group->cig_state_).c_str()); + ToString(group->cig.GetState()).c_str()); log_history_->AddLogHistory(kLogStateMachineTag, group->group_id_, RawAddress::kEmpty, kLogCigRemoveOp); } @@ -644,17 +740,32 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { void ProcessHciNotifAclDisconnected(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) { FreeLinkQualityReports(leAudioDevice); - /* mark ASEs as not used. */ - leAudioDevice->DeactivateAllAses(); - if (!group) { LOG(ERROR) << __func__ << " group is null for device: " << ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_) << " group_id: " << leAudioDevice->group_id_; + /* mark ASEs as not used. */ + leAudioDevice->DeactivateAllAses(); return; } + /* It is possible that ACL disconnection came before CIS disconnect event */ + for (auto& ase : leAudioDevice->ases_) { + group->RemoveCisFromStreamIfNeeded(leAudioDevice, ase.cis_conn_hdl); + } + + /* mark ASEs as not used. */ + leAudioDevice->DeactivateAllAses(); + + /* Update the current group audio context availability which could change + * due to disconnected group member. + */ + group->ReloadAudioLocations(); + group->ReloadAudioDirections(); + group->UpdateAudioContextAvailability(); + group->InvalidateCachedConfigurations(); + /* If group is in Idle and not transitioning, update the current group * audio context availability which could change due to disconnected group * member. @@ -662,7 +773,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { if ((group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) && !group->IsInTransition()) { LOG_INFO("group: %d is in IDLE", group->group_id_); - group->UpdateAudioContextTypeAvailability(); /* When OnLeAudioDeviceSetStateTimeout happens, group will transition * to IDLE, and after that an ACL disconnect will be triggered. We need @@ -670,7 +780,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { * again after reconnect. Otherwise we will get Command Disallowed on CIG * Create when starting stream. */ - if (group->GetCigState() == CigState::CREATED) { + if (group->cig.GetState() == CigState::CREATED) { LOG_INFO("CIG is in CREATED state so removing CIG for Group %d", group->group_id_); RemoveCigForGroup(group); @@ -683,28 +793,31 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), group->IsAnyDeviceConnected(), group->HaveAllCisesDisconnected()); - /* Update the current group audio context availability which could change - * due to disconnected group member. - */ - group->UpdateAudioContextTypeAvailability(); - if (group->IsAnyDeviceConnected()) { /* * ACL of one of the device has been dropped. If number of CISes has - * changed notify upper layer so the offloader can be updated with CIS + * changed notify upper layer so the CodecManager can be updated with CIS * information. */ - if (!group->HaveAllCisesDisconnected() && - (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) && - (group->GetTargetState() == - AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) { - /* We keep streaming but want others to let know user that it might be - * need to update offloader with new CIS configuration - */ - state_machine_callbacks_->StatusReportCb(group->group_id_, - GroupStreamStatus::STREAMING); + if (!group->HaveAllCisesDisconnected()) { + /* some CISes are connected */ + + if ((group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) && + (group->GetTargetState() == + AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) { + /* We keep streaming but want others to let know user that it might + * be need to update CodecManager with new CIS configuration + */ + state_machine_callbacks_->StatusReportCb( + group->group_id_, GroupStreamStatus::STREAMING); + } else { + LOG_WARN("group_id %d not in streaming, CISes are still there", + group->group_id_); + group->PrintDebugState(); + } + + return; } - return; } /* Group is not connected and all the CISes are down. @@ -732,13 +845,35 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { kLogCisEstablishedOp + "cis_h:" + loghex(event->cis_conn_hdl) + " STATUS=" + loghex(event->status)); - if (event->status) { - if (ases_pair.sink) - ases_pair.sink->data_path_state = - AudioStreamDataPathState::CIS_ASSIGNED; - if (ases_pair.source) - ases_pair.source->data_path_state = - AudioStreamDataPathState::CIS_ASSIGNED; + if (event->status != HCI_SUCCESS) { + if (ases_pair.sink) ases_pair.sink->cis_state = CisState::ASSIGNED; + if (ases_pair.source) ases_pair.source->cis_state = CisState::ASSIGNED; + + LOG_WARN("%s: failed to create CIS 0x%04x, status: %s (0x%02x)", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), + event->cis_conn_hdl, + ErrorCodeText((ErrorCode)event->status).c_str(), event->status); + + if (event->status == HCI_ERR_CONN_FAILED_ESTABLISHMENT && + ((leAudioDevice->cis_failed_to_be_established_retry_cnt_++) < + kNumberOfCisRetries) && + (CisCreateForDevice(group, leAudioDevice))) { + LOG_INFO("Retrying (%d) to create CIS for %s ", + leAudioDevice->cis_failed_to_be_established_retry_cnt_, + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + return; + } + + if (event->status == HCI_ERR_UNSUPPORTED_REM_FEATURE && + group->asymmetric_phy_for_unidirectional_cis_supported == true && + group->GetSduInterval(le_audio::types::kLeAudioDirectionSource) == + 0) { + group->asymmetric_phy_for_unidirectional_cis_supported = false; + } + + LOG_ERROR("CIS creation failed %d times, stopping the stream", + leAudioDevice->cis_failed_to_be_established_retry_cnt_); + leAudioDevice->cis_failed_to_be_established_retry_cnt_ = 0; /* CIS establishment failed. Remove CIG if no other CIS is already created * or pending. If CIS is established, this will be handled in disconnected @@ -748,27 +883,34 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { RemoveCigForGroup(group); } - LOG(ERROR) << __func__ - << ", failed to create CIS, status: " << loghex(event->status); - StopStream(group); return; } + if (leAudioDevice->cis_failed_to_be_established_retry_cnt_ > 0) { + /* Reset retry counter */ + leAudioDevice->cis_failed_to_be_established_retry_cnt_ = 0; + } + if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - LOG(ERROR) << __func__ - << ", Unintended CIS establishement event came for group id:" - << group->group_id_; + LOG_ERROR("Unintended CIS establishement event came for group id: %d", + group->group_id_); StopStream(group); return; } - if (ases_pair.sink) - ases_pair.sink->data_path_state = - AudioStreamDataPathState::CIS_ESTABLISHED; - if (ases_pair.source) - ases_pair.source->data_path_state = - AudioStreamDataPathState::CIS_ESTABLISHED; + if (ases_pair.sink) ases_pair.sink->cis_state = CisState::CONNECTED; + if (ases_pair.source) ases_pair.source->cis_state = CisState::CONNECTED; + + if (ases_pair.sink && + (ases_pair.sink->data_path_state == DataPathState::IDLE)) { + PrepareDataPath(group->group_id_, ases_pair.sink); + } + + if (ases_pair.source && + (ases_pair.source->data_path_state == DataPathState::IDLE)) { + PrepareDataPath(group->group_id_, ases_pair.source); + } if (osi_property_get_bool("persist.bluetooth.iso_link_quality_report", false)) { @@ -804,16 +946,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { event->cis_conn_hdl); PrepareAndSendReceiverStartReady(leAudioDevice, ase); - - /* Cis establishment may came after setting group state to streaming, e.g. - * for autonomous scenario when ase is sink */ - if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING && - group->GetFirstActiveDeviceByDataPathState( - AudioStreamDataPathState::CIS_ESTABLISHED)) { - /* No more transition for group */ - cancel_watchdog_if_needed(group->group_id_); - PrepareDataPath(group); - } } static void WriteToControlPoint(LeAudioDevice* leAudioDevice, @@ -841,15 +973,16 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); uint8_t value = 0; - if (ases_pair.sink && ases_pair.sink->data_path_state == - AudioStreamDataPathState::DATA_PATH_ESTABLISHED) { + if (ases_pair.sink && + ases_pair.sink->data_path_state == DataPathState::CONFIGURED) { value |= bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput; + ases_pair.sink->data_path_state = DataPathState::REMOVING; } if (ases_pair.source && - ases_pair.source->data_path_state == - AudioStreamDataPathState::DATA_PATH_ESTABLISHED) { + ases_pair.source->data_path_state == DataPathState::CONFIGURED) { value |= bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput; + ases_pair.source->data_path_state = DataPathState::REMOVING; } if (value == 0) { @@ -878,31 +1011,31 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { kLogCisDisconnectedOp + "cis_h:" + loghex(event->cis_conn_hdl) + " REASON=" + loghex(event->reason)); + if (ases_pair.sink) { + ases_pair.sink->cis_state = CisState::ASSIGNED; + } + if (ases_pair.source) { + ases_pair.source->cis_state = CisState::ASSIGNED; + } + + RemoveDataPathByCisHandle(leAudioDevice, event->cis_conn_hdl); + /* If this is peer disconnecting CIS, make sure to clear data path */ if (event->reason != HCI_ERR_CONN_CAUSE_LOCAL_HOST) { - RemoveDataPathByCisHandle(leAudioDevice, event->cis_conn_hdl); // Make sure we won't stay in STREAMING state if (ases_pair.sink && ases_pair.sink->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - ases_pair.sink->state = - AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; + SetAseState(leAudioDevice, ases_pair.sink, + AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); } if (ases_pair.source && ases_pair.source->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - ases_pair.source->state = - AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; + SetAseState(leAudioDevice, ases_pair.source, + AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); } } - if (ases_pair.sink) { - ases_pair.sink->data_path_state = AudioStreamDataPathState::CIS_ASSIGNED; - } - if (ases_pair.source) { - ases_pair.source->data_path_state = - AudioStreamDataPathState::CIS_ASSIGNED; - } - - RemoveCisFromStreamConfiguration(group, leAudioDevice, event->cis_conn_hdl); + group->RemoveCisFromStreamIfNeeded(leAudioDevice, event->cis_conn_hdl); auto target_state = group->GetTargetState(); switch (target_state) { @@ -920,7 +1053,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } LOG_INFO("Lost all members from the group %d", group->group_id_); - group->cises_.clear(); + group->cig.cises.clear(); RemoveCigForGroup(group); group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); @@ -985,18 +1118,12 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { "state, reconfig=%d.", group->group_id_, reconfig); - if (reconfig) { - group->ClearPendingConfiguration(); + /* This is Autonomous change if both, target and current state + * is CODEC_CONFIGURED + */ + if (target_state == current_group_state) { state_machine_callbacks_->StatusReportCb( - group->group_id_, GroupStreamStatus::CONFIGURED_BY_USER); - } else { - /* This is Autonomous change if both, target and current state - * is CODEC_CONFIGURED - */ - if (target_state == current_group_state) { - state_machine_callbacks_->StatusReportCb( - group->group_id_, GroupStreamStatus::CONFIGURED_AUTONOMOUS); - } + group->group_id_, GroupStreamStatus::CONFIGURED_AUTONOMOUS); } } RemoveCigForGroup(group); @@ -1022,8 +1149,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } /* Tear down CIS's data paths within the group */ - struct ase* ase = leAudioDevice->GetFirstActiveAseByDataPathState( - AudioStreamDataPathState::DATA_PATH_ESTABLISHED); + struct ase* ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState( + CisState::CONNECTED, DataPathState::CONFIGURED); if (!ase) { leAudioDevice = group->GetNextActiveDevice(leAudioDevice); /* No more ASEs to disconnect their CISes */ @@ -1033,8 +1160,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } LOG_ASSERT(ase) << __func__ << " shouldn't be called without an active ASE"; - if (ase->data_path_state == - AudioStreamDataPathState::DATA_PATH_ESTABLISHED) { + if (ase->data_path_state == DataPathState::CONFIGURED) { RemoveDataPathByCisHandle(leAudioDevice, ase->cis_conn_hdl); } } @@ -1083,237 +1209,145 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { void AddCisToStreamConfiguration(LeAudioDeviceGroup* group, const struct ase* ase) { - uint16_t cis_conn_hdl = ase->cis_conn_hdl; + group->stream_conf.codec_id = ase->codec_id; + + auto cis_conn_hdl = ase->cis_conn_hdl; + auto& params = group->stream_conf.stream_params.get(ase->direction); LOG_INFO("Adding cis handle 0x%04x (%s) to stream list", cis_conn_hdl, ase->direction == le_audio::types::kLeAudioDirectionSink ? "sink" : "source"); - auto* stream_conf = &group->stream_conf; - if (ase->direction == le_audio::types::kLeAudioDirectionSink) { - auto iter = std::find_if( - stream_conf->sink_streams.begin(), stream_conf->sink_streams.end(), - [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); - ASSERT_LOG(iter == stream_conf->sink_streams.end(), - "Stream is already there 0x%04x", cis_conn_hdl); + auto iter = std::find_if( + params.stream_locations.begin(), params.stream_locations.end(), + [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); + ASSERT_LOG(iter == params.stream_locations.end(), + "Stream is already there 0x%04x", cis_conn_hdl); - stream_conf->sink_streams.emplace_back(std::make_pair( - ase->cis_conn_hdl, *ase->codec_config.audio_channel_allocation)); + auto core_config = ase->codec_config.GetAsCoreCodecConfig(); - stream_conf->sink_num_of_devices++; - stream_conf->sink_num_of_channels += ase->codec_config.channel_count; - stream_conf->sink_audio_channel_allocation |= - *ase->codec_config.audio_channel_allocation; + params.num_of_devices++; + params.num_of_channels += core_config.GetChannelCountPerIsoStream(); - if (stream_conf->sink_sample_frequency_hz == 0) { - stream_conf->sink_sample_frequency_hz = - ase->codec_config.GetSamplingFrequencyHz(); - } else { - ASSERT_LOG(stream_conf->sink_sample_frequency_hz == - ase->codec_config.GetSamplingFrequencyHz(), - "sample freq mismatch: %d!=%d", - stream_conf->sink_sample_frequency_hz, - ase->codec_config.GetSamplingFrequencyHz()); - } - - if (stream_conf->sink_octets_per_codec_frame == 0) { - stream_conf->sink_octets_per_codec_frame = - *ase->codec_config.octets_per_codec_frame; - } else { - ASSERT_LOG(stream_conf->sink_octets_per_codec_frame == - *ase->codec_config.octets_per_codec_frame, - "octets per frame mismatch: %d!=%d", - stream_conf->sink_octets_per_codec_frame, - *ase->codec_config.octets_per_codec_frame); - } - - if (stream_conf->sink_codec_frames_blocks_per_sdu == 0) { - stream_conf->sink_codec_frames_blocks_per_sdu = - *ase->codec_config.codec_frames_blocks_per_sdu; - } else { - ASSERT_LOG(stream_conf->sink_codec_frames_blocks_per_sdu == - *ase->codec_config.codec_frames_blocks_per_sdu, - "codec_frames_blocks_per_sdu: %d!=%d", - stream_conf->sink_codec_frames_blocks_per_sdu, - *ase->codec_config.codec_frames_blocks_per_sdu); - } + if (!core_config.audio_channel_allocation.has_value()) { + LOG_WARN("ASE has invalid audio location"); + } + auto ase_audio_channel_allocation = + core_config.audio_channel_allocation.value_or(0); + params.audio_channel_allocation |= ase_audio_channel_allocation; + params.stream_locations.emplace_back( + std::make_pair(ase->cis_conn_hdl, ase_audio_channel_allocation)); - if (stream_conf->sink_frame_duration_us == 0) { - stream_conf->sink_frame_duration_us = - ase->codec_config.GetFrameDurationUs(); - } else { - ASSERT_LOG(stream_conf->sink_frame_duration_us == - ase->codec_config.GetFrameDurationUs(), - "frame_duration_us: %d!=%d", - stream_conf->sink_frame_duration_us, - ase->codec_config.GetFrameDurationUs()); - } + if (params.sample_frequency_hz == 0) { + params.sample_frequency_hz = core_config.GetSamplingFrequencyHz(); + } else { + ASSERT_LOG( + params.sample_frequency_hz == core_config.GetSamplingFrequencyHz(), + "sample freq mismatch: %d!=%d", params.sample_frequency_hz, + core_config.GetSamplingFrequencyHz()); + } - LOG_INFO( - " Added Sink Stream Configuration. CIS Connection Handle: %d" - ", Audio Channel Allocation: %d" - ", Sink Number Of Devices: %d" - ", Sink Number Of Channels: %d", - ase->cis_conn_hdl, *ase->codec_config.audio_channel_allocation, - stream_conf->sink_num_of_devices, stream_conf->sink_num_of_channels); + if (params.octets_per_codec_frame == 0) { + params.octets_per_codec_frame = *core_config.octets_per_codec_frame; + } else { + ASSERT_LOG( + params.octets_per_codec_frame == *core_config.octets_per_codec_frame, + "octets per frame mismatch: %d!=%d", params.octets_per_codec_frame, + *core_config.octets_per_codec_frame); + } + if (params.codec_frames_blocks_per_sdu == 0) { + params.codec_frames_blocks_per_sdu = + *core_config.codec_frames_blocks_per_sdu; } else { - /* Source case */ - auto iter = std::find_if( - stream_conf->source_streams.begin(), - stream_conf->source_streams.end(), - [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); - - ASSERT_LOG(iter == stream_conf->source_streams.end(), - "Stream is already there 0x%04x", cis_conn_hdl); - - stream_conf->source_streams.emplace_back(std::make_pair( - ase->cis_conn_hdl, *ase->codec_config.audio_channel_allocation)); - - stream_conf->source_num_of_devices++; - stream_conf->source_num_of_channels += ase->codec_config.channel_count; - stream_conf->source_audio_channel_allocation |= - *ase->codec_config.audio_channel_allocation; - - if (stream_conf->source_sample_frequency_hz == 0) { - stream_conf->source_sample_frequency_hz = - ase->codec_config.GetSamplingFrequencyHz(); - } else { - ASSERT_LOG(stream_conf->source_sample_frequency_hz == - ase->codec_config.GetSamplingFrequencyHz(), - "sample freq mismatch: %d!=%d", - stream_conf->source_sample_frequency_hz, - ase->codec_config.GetSamplingFrequencyHz()); - } + ASSERT_LOG(params.codec_frames_blocks_per_sdu == + *core_config.codec_frames_blocks_per_sdu, + "codec_frames_blocks_per_sdu: %d!=%d", + params.codec_frames_blocks_per_sdu, + *core_config.codec_frames_blocks_per_sdu); + } - if (stream_conf->source_octets_per_codec_frame == 0) { - stream_conf->source_octets_per_codec_frame = - *ase->codec_config.octets_per_codec_frame; - } else { - ASSERT_LOG(stream_conf->source_octets_per_codec_frame == - *ase->codec_config.octets_per_codec_frame, - "octets per frame mismatch: %d!=%d", - stream_conf->source_octets_per_codec_frame, - *ase->codec_config.octets_per_codec_frame); - } + if (params.frame_duration_us == 0) { + params.frame_duration_us = core_config.GetFrameDurationUs(); + } else { + ASSERT_LOG(params.frame_duration_us == core_config.GetFrameDurationUs(), + "frame_duration_us: %d!=%d", params.frame_duration_us, + core_config.GetFrameDurationUs()); + } + + LOG_INFO( + " Added %s Stream Configuration. CIS Connection Handle: %d" + ", Audio Channel Allocation: %d" + ", Number Of Devices: %d" + ", Number Of Channels: %d", + (ase->direction == le_audio::types::kLeAudioDirectionSink ? "Sink" + : "Source"), + cis_conn_hdl, ase_audio_channel_allocation, params.num_of_devices, + params.num_of_channels); + + /* Update CodecManager stream configuration */ + state_machine_callbacks_->OnUpdatedCisConfiguration(group->group_id_, + ase->direction); + } - if (stream_conf->source_codec_frames_blocks_per_sdu == 0) { - stream_conf->source_codec_frames_blocks_per_sdu = - *ase->codec_config.codec_frames_blocks_per_sdu; - } else { - ASSERT_LOG(stream_conf->source_codec_frames_blocks_per_sdu == - *ase->codec_config.codec_frames_blocks_per_sdu, - "codec_frames_blocks_per_sdu: %d!=%d", - stream_conf->source_codec_frames_blocks_per_sdu, - *ase->codec_config.codec_frames_blocks_per_sdu); - } + static bool isIntervalAndLatencyProperlySet(uint32_t sdu_interval_us, + uint16_t max_latency_ms) { + LOG_VERBOSE("sdu_interval_us: %d, max_latency_ms: %d", sdu_interval_us, + max_latency_ms); - if (stream_conf->source_frame_duration_us == 0) { - stream_conf->source_frame_duration_us = - ase->codec_config.GetFrameDurationUs(); - } else { - ASSERT_LOG(stream_conf->source_frame_duration_us == - ase->codec_config.GetFrameDurationUs(), - "frame_duration_us: %d!=%d", - stream_conf->source_frame_duration_us, - ase->codec_config.GetFrameDurationUs()); - } + if (sdu_interval_us == 0) { + return max_latency_ms == le_audio::types::kMaxTransportLatencyMin; + } + return ((1000 * max_latency_ms) >= sdu_interval_us); + } - LOG_INFO( - " Added Source Stream Configuration. CIS Connection Handle: %d" - ", Audio Channel Allocation: %d" - ", Source Number Of Devices: %d" - ", Source Number Of Channels: %d", - ase->cis_conn_hdl, *ase->codec_config.audio_channel_allocation, - stream_conf->source_num_of_devices, - stream_conf->source_num_of_channels); + void ApplyDsaParams(LeAudioDeviceGroup* group, + bluetooth::hci::iso_manager::cig_create_params& param) { + if (!IS_FLAG_ENABLED(leaudio_dynamic_spatial_audio)) { + return; } - /* Update offloader streams */ - group->CreateStreamVectorForOffloader(ase->direction); - } + LOG_INFO("DSA mode selected: %d", (int)group->dsa_mode_); - void RemoveCisFromStreamConfiguration(LeAudioDeviceGroup* group, - LeAudioDevice* leAudioDevice, - uint16_t cis_conn_hdl) { - auto* stream_conf = &group->stream_conf; - - LOG_INFO(" CIS Connection Handle: %d", cis_conn_hdl); - - auto sink_channels = stream_conf->sink_num_of_channels; - auto source_channels = stream_conf->source_num_of_channels; - - if (!stream_conf->sink_streams.empty() || - !stream_conf->source_streams.empty()) { - stream_conf->sink_streams.erase( - std::remove_if( - stream_conf->sink_streams.begin(), - stream_conf->sink_streams.end(), - [leAudioDevice, &cis_conn_hdl, &stream_conf](auto& pair) { - if (!cis_conn_hdl) { - cis_conn_hdl = pair.first; - } - auto ases_pair = - leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); - if (ases_pair.sink && cis_conn_hdl == pair.first) { - stream_conf->sink_num_of_devices--; - stream_conf->sink_num_of_channels -= - ases_pair.sink->codec_config.channel_count; - stream_conf->sink_audio_channel_allocation &= ~pair.second; - } - return (ases_pair.sink && cis_conn_hdl == pair.first); - }), - stream_conf->sink_streams.end()); - - stream_conf->source_streams.erase( - std::remove_if( - stream_conf->source_streams.begin(), - stream_conf->source_streams.end(), - [leAudioDevice, &cis_conn_hdl, &stream_conf](auto& pair) { - if (!cis_conn_hdl) { - cis_conn_hdl = pair.first; - } - auto ases_pair = - leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); - if (ases_pair.source && cis_conn_hdl == pair.first) { - stream_conf->source_num_of_devices--; - stream_conf->source_num_of_channels -= - ases_pair.source->codec_config.channel_count; - stream_conf->source_audio_channel_allocation &= ~pair.second; - } - return (ases_pair.source && cis_conn_hdl == pair.first); - }), - stream_conf->source_streams.end()); - - LOG_INFO( - " Sink Number Of Devices: %d" - ", Sink Number Of Channels: %d" - ", Source Number Of Devices: %d" - ", Source Number Of Channels: %d", - stream_conf->sink_num_of_devices, stream_conf->sink_num_of_channels, - stream_conf->source_num_of_devices, - stream_conf->source_num_of_channels); - } - - if (stream_conf->sink_num_of_channels == 0) { - group->ClearSinksFromConfiguration(); - } - - if (stream_conf->source_num_of_channels == 0) { - group->ClearSourcesFromConfiguration(); - } - - /* Update offloader streams if needed */ - if (sink_channels > stream_conf->sink_num_of_channels) { - group->CreateStreamVectorForOffloader( - le_audio::types::kLeAudioDirectionSink); - } - if (source_channels > stream_conf->source_num_of_channels) { - group->CreateStreamVectorForOffloader( - le_audio::types::kLeAudioDirectionSource); - } - - group->CigUnassignCis(leAudioDevice); + /* Unidirectional streaming */ + if (param.sdu_itv_stom != 0) { + LOG_INFO("Media streaming, apply DSA parameters"); + + switch (group->dsa_mode_) { + case DsaMode::ISO_HW: + case DsaMode::ISO_SW: { + auto& cis_cfgs = param.cis_cfgs; + auto it = cis_cfgs.begin(); + + for (auto dsa_modes : group->GetAllowedDsaModesList()) { + if (!dsa_modes.empty() && it != cis_cfgs.end()) { + if (std::find(dsa_modes.begin(), dsa_modes.end(), + group->dsa_mode_) != dsa_modes.end()) { + LOG_INFO("Device found with support for selected DsaMode"); + + param.sdu_itv_stom = 20000; + param.max_trans_lat_stom = 10; + it->max_sdu_size_stom = 15; + it->rtn_stom = 2; + + it++; + } + } + } + } break; + + case DsaMode::ACL: + /* Todo: Prioritize the ACL */ + break; + + case DsaMode::DISABLED: + default: + /* No need to change ISO parameters */ + break; + } + } else { + LOG_DEBUG("Bidirection streaming, ignore DSA mode"); + } } bool CigCreate(LeAudioDeviceGroup* group) { @@ -1323,11 +1357,11 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { std::vector cis_cfgs; LOG_DEBUG("Group: %p, id: %d cig state: %s", group, group->group_id_, - ToString(group->cig_state_).c_str()); + ToString(group->cig.GetState()).c_str()); - if (group->GetCigState() != CigState::NONE) { + if (group->cig.GetState() != CigState::NONE) { LOG_WARN(" Group %p, id: %d has invalid cig state: %s ", group, - group->group_id_, ToString(group->cig_state_).c_str()); + group->group_id_, ToString(group->cig.GetState()).c_str()); return false; } @@ -1347,6 +1381,25 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { group->GetPhyBitmask(le_audio::types::kLeAudioDirectionSink); uint8_t phy_stom = group->GetPhyBitmask(le_audio::types::kLeAudioDirectionSource); + + if (!isIntervalAndLatencyProperlySet(sdu_interval_mtos, + max_trans_lat_mtos) || + !isIntervalAndLatencyProperlySet(sdu_interval_stom, + max_trans_lat_stom)) { + LOG_ERROR("Latency and interval not properly set"); + group->PrintDebugState(); + return false; + } + + // Use 1M Phy for the ACK packet from remote device to phone for better + // sensitivity + if (group->asymmetric_phy_for_unidirectional_cis_supported && + sdu_interval_stom == 0 && + (phy_stom & bluetooth::hci::kIsoCigPhy1M) != 0) { + LOG_INFO("Use asymmetric PHY for unidirectional CIS"); + phy_stom = bluetooth::hci::kIsoCigPhy1M; + } + uint8_t rtn_mtos = 0; uint8_t rtn_stom = 0; @@ -1359,7 +1412,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { * later, with active device/ASE(s), check if current configuration is * supported or not, if not, reconfigure CIG. */ - for (struct le_audio::types::cis& cis : group->cises_) { + for (struct le_audio::types::cis& cis : group->cig.cises) { uint16_t max_sdu_size_mtos_temp = group->GetMaxSduSize(le_audio::types::kLeAudioDirectionSink, cis.id); uint16_t max_sdu_size_stom_temp = group->GetMaxSduSize( @@ -1377,7 +1430,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { rtn_stom = rtn_stom_temp ? rtn_stom_temp : rtn_stom; } - for (struct le_audio::types::cis& cis : group->cises_) { + for (struct le_audio::types::cis& cis : group->cig.cises) { EXT_CIS_CFG cis_cfg = {}; cis_cfg.cis_id = cis.id; @@ -1425,14 +1478,16 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { .cis_cfgs = std::move(cis_cfgs), }; + ApplyDsaParams(group, param); + log_history_->AddLogHistory( kLogStateMachineTag, group->group_id_, RawAddress::kEmpty, kLogCigCreateOp + "#CIS: " + std::to_string(param.cis_cfgs.size())); - group->SetCigState(CigState::CREATING); + group->cig.SetState(CigState::CREATING); IsoManager::GetInstance()->CreateCig(group->group_id_, std::move(param)); LOG_DEBUG("Group: %p, id: %d cig state: %s", group, group->group_id_, - ToString(group->cig_state_).c_str()); + ToString(group->cig.GetState()).c_str()); return true; } @@ -1442,7 +1497,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { struct ase* ase = leAudioDevice->GetFirstActiveAse(); /* Make sure CIG is there */ - if (group->GetCigState() != CigState::CREATED) { + if (group->cig.GetState() != CigState::CREATED) { LOG_ERROR("CIG is not created for group_id %d ", group->group_id_); group->PrintDebugState(); return false; @@ -1453,15 +1508,14 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { /* First in ase pair is Sink, second Source */ auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(ase->cis_conn_hdl); - /* Already in pending state - bi-directional CIS */ - if (ase->data_path_state == AudioStreamDataPathState::CIS_PENDING) + /* Already in pending state - bi-directional CIS or seconde CIS to same + * device */ + if (ase->cis_state == CisState::CONNECTING || + ase->cis_state == CisState::CONNECTED) continue; - if (ases_pair.sink) - ases_pair.sink->data_path_state = AudioStreamDataPathState::CIS_PENDING; - if (ases_pair.source) - ases_pair.source->data_path_state = - AudioStreamDataPathState::CIS_PENDING; + if (ases_pair.sink) ases_pair.sink->cis_state = CisState::CONNECTING; + if (ases_pair.source) ases_pair.source->cis_state = CisState::CONNECTING; uint16_t acl_handle = BTM_GetHCIConnHandle(leAudioDevice->address_, BT_TRANSPORT_LE); @@ -1493,7 +1547,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { << __func__ << " Shouldn't be called without an active device."; /* Make sure CIG is there */ - if (group->GetCigState() != CigState::CREATED) { + if (group->cig.GetState() != CigState::CREATED) { LOG_ERROR("CIG is not created for group_id %d ", group->group_id_); group->PrintDebugState(); return false; @@ -1508,15 +1562,11 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(ase->cis_conn_hdl); /* Already in pending state - bi-directional CIS */ - if (ase->data_path_state == AudioStreamDataPathState::CIS_PENDING) - continue; + if (ase->cis_state == CisState::CONNECTING) continue; - if (ases_pair.sink) - ases_pair.sink->data_path_state = - AudioStreamDataPathState::CIS_PENDING; + if (ases_pair.sink) ases_pair.sink->cis_state = CisState::CONNECTING; if (ases_pair.source) - ases_pair.source->data_path_state = - AudioStreamDataPathState::CIS_PENDING; + ases_pair.source->cis_state = CisState::CONNECTING; uint16_t acl_handle = BTM_GetHCIConnHandle(leAudioDevice->address_, BT_TRANSPORT_LE); @@ -1534,23 +1584,16 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return true; } - static void PrepareDataPath(int group_id, const struct ase* ase) { - /* TODO: Handle HW offloading decode as we handle here, force to use SW - * decode for now */ - auto data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci; - if (CodecManager::GetInstance()->GetCodecLocation() != - CodecLocation::HOST) { - data_path_id = bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault; - } - /* TODO: Need to set coding_format when we support the codec location inside - * the controller, force to use transparent for now */ + static void PrepareDataPath(int group_id, struct ase* ase) { bluetooth::hci::iso_manager::iso_data_path_params param = { .data_path_dir = ase->direction == le_audio::types::kLeAudioDirectionSink ? bluetooth::hci::iso_manager::kIsoDataPathDirectionIn : bluetooth::hci::iso_manager::kIsoDataPathDirectionOut, - .data_path_id = data_path_id, - .codec_id_format = bluetooth::hci::kIsoCodingFormatTransparent, + .data_path_id = ase->data_path_id, + .codec_id_format = ase->is_codec_in_controller + ? ase->codec_id.coding_format + : bluetooth::hci::kIsoCodingFormatTransparent, .codec_id_company = ase->codec_id.vendor_company_id, .codec_id_vendor = ase->codec_id.vendor_codec_id, .controller_delay = 0x00000000, @@ -1562,29 +1605,18 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { kLogSetDataPathOp + "cis_h:" + loghex(ase->cis_conn_hdl), "direction: " + loghex(param.data_path_dir)); + ase->data_path_state = DataPathState::CONFIGURING; IsoManager::GetInstance()->SetupIsoDataPath(ase->cis_conn_hdl, std::move(param)); } - static inline void PrepareDataPath(LeAudioDeviceGroup* group) { - auto* leAudioDevice = group->GetFirstActiveDeviceByDataPathState( - AudioStreamDataPathState::CIS_ESTABLISHED); - LOG_ASSERT(leAudioDevice) - << __func__ << " Shouldn't be called without an active device."; - - auto* ase = leAudioDevice->GetFirstActiveAseByDataPathState( - AudioStreamDataPathState::CIS_ESTABLISHED); - LOG_ASSERT(ase) << __func__ << " shouldn't be called without an active ASE"; - PrepareDataPath(group->group_id_, ase); - } - static void ReleaseDataPath(LeAudioDeviceGroup* group) { LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice(); LOG_ASSERT(leAudioDevice) << __func__ << " Shouldn't be called without an active device."; - auto ase = leAudioDevice->GetFirstActiveAseByDataPathState( - AudioStreamDataPathState::DATA_PATH_ESTABLISHED); + auto ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState( + CisState::CONNECTED, DataPathState::CONFIGURED); LOG_ASSERT(ase) << __func__ << " Shouldn't be called without an active ASE."; RemoveDataPathByCisHandle(leAudioDevice, ase->cis_conn_hdl); @@ -1717,14 +1749,14 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { std::stringstream msg_stream; std::stringstream extra_stream; - if (!group->CigAssignCisIds(leAudioDevice)) { + if (!group->cig.AssignCisIds(leAudioDevice)) { LOG_ERROR(" unable to assign CIS IDs"); StopStream(group); return; } - if (group->GetCigState() == CigState::CREATED) - group->CigAssignCisConnHandlesToAses(leAudioDevice); + if (group->cig.GetState() == CigState::CREATED) + group->AssignCisConnHandlesToAses(leAudioDevice); msg_stream << kLogAseConfigOp; @@ -1850,7 +1882,19 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { /* We are here because of the reconnection of the single device. */ - PrepareAndSendConfigQos(group, leAudioDevice); + /* Make sure that device is ready to be configured as we could also + * get here triggered by the remote device. If device is not connected + * yet, we should wait for the stack to trigger adding device to the + * stream */ + if (leAudioDevice->GetConnectionState() == + le_audio::DeviceConnectState::CONNECTED) { + PrepareAndSendConfigQos(group, leAudioDevice); + } else { + LOG_DEBUG( + "Device %s initiated configured state but it is not yet ready " + "to be configured", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + } return; } @@ -1949,7 +1993,19 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { /* We are here because of the reconnection of the single device. */ - PrepareAndSendConfigQos(group, leAudioDevice); + /* Make sure that device is ready to be configured as we could also + * get here triggered by the remote device. If device is not connected + * yet, we should wait for the stack to trigger adding device to the + * stream */ + if (leAudioDevice->GetConnectionState() == + le_audio::DeviceConnectState::CONNECTED) { + PrepareAndSendConfigQos(group, leAudioDevice); + } else { + LOG_DEBUG( + "Device %s initiated configured state but it is not yet ready " + "to be configured", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); + } return; } @@ -1996,7 +2052,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { /* TODO: Config Codec */ break; case AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING: - LeAudioDevice* leAudioDeviceNext; SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); ase->active = false; @@ -2019,35 +2074,38 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } - leAudioDeviceNext = group->GetNextActiveDevice(leAudioDevice); - - /* Configure ASEs for next device in group */ - if (leAudioDeviceNext) { - PrepareAndSendRelease(leAudioDeviceNext); - } else { - /* Last node is in releasing state*/ - - group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); - /* Remote device has cache and keep staying in configured state after - * release. Therefore, we assume this is a target state requested by - * remote device. - */ - group->SetTargetState(group->GetState()); - - if (!group->HaveAllCisesDisconnected()) { - LOG_WARN( - "Not all CISes removed before going to IDLE for group %d, " - "waiting...", - group->group_id_); - group->PrintDebugState(); + { + auto activeDevice = group->GetFirstActiveDevice(); + if (activeDevice) { + LOG_DEBUG( + "There is at least one active device %s, wait to become " + "inactive", + ADDRESS_TO_LOGGABLE_CSTR(activeDevice->address_)); return; } + } - cancel_watchdog_if_needed(group->group_id_); + /* Last node is in releasing state*/ + group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); + /* Remote device has cache and keep staying in configured state after + * release. Therefore, we assume this is a target state requested by + * remote device. + */ + group->SetTargetState(group->GetState()); - state_machine_callbacks_->StatusReportCb( - group->group_id_, GroupStreamStatus::CONFIGURED_AUTONOMOUS); + if (!group->HaveAllCisesDisconnected()) { + LOG_WARN( + "Not all CISes removed before going to IDLE for group %d, " + "waiting...", + group->group_id_); + group->PrintDebugState(); + return; } + + cancel_watchdog_if_needed(group->group_id_); + + state_machine_callbacks_->StatusReportCb( + group->group_id_, GroupStreamStatus::CONFIGURED_AUTONOMOUS); break; default: LOG(ERROR) << __func__ << ", invalid state transition, from: " @@ -2113,6 +2171,12 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); + /* Remote may autonomously bring ASEs to QoS configured state */ + if (group->GetTargetState() != + AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) { + ProcessAutonomousDisable(leAudioDevice, ase); + } + /* Process the Disable Transition of the rest of group members if no * more ASE notifications has to come from this device. */ if (leAudioDevice->IsReadyToSuspendStream()) ProcessGroupDisable(group); @@ -2451,15 +2515,24 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { auto directional_audio_context = context_types.get(ase->direction) & leAudioDevice->GetAvailableContexts(ase->direction); + + std::vector new_metadata; if (directional_audio_context.any()) { - ase->metadata = leAudioDevice->GetMetadata( + new_metadata = leAudioDevice->GetMetadata( directional_audio_context, ccid_lists.get(ase->direction)); } else { - ase->metadata = leAudioDevice->GetMetadata( + new_metadata = leAudioDevice->GetMetadata( AudioContexts(LeAudioContextType::UNSPECIFIED), std::vector()); } + /* Do not update if metadata did not changed. */ + if (ase->metadata == new_metadata) { + continue; + } + + ase->metadata = new_metadata; + struct le_audio::client_parser::ascs::ctp_update_metadata conf; conf.ase_id = ase->id; @@ -2527,7 +2600,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING); if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - if (ase->data_path_state < AudioStreamDataPathState::CIS_PENDING) { + if (ase->cis_state < CisState::CONNECTING) { /* We are here because of the reconnection of the single device. */ if (!CisCreateForDevice(group, leAudioDevice)) { StopStream(group); @@ -2589,35 +2662,12 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { switch (ase->state) { case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED: - /* As per ASCS 1.0 : - * If a CIS has been established and the server is acting as Audio Sink - * for the ASE, and if the server is ready to receive audio data - * transmitted by the client, the server may autonomously initiate the - * Receiver Start Ready, as defined in Section 5.4, without first - * sending a notification of the ASE characteristic value in the - * Enabling state. - */ - if (ase->direction != le_audio::types::kLeAudioDirectionSink) { - LOG(ERROR) << __func__ << ", invalid state transition, from: " - << static_cast(ase->state) << ", to: " - << static_cast( - AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - StopStream(group); - return; - } - - SetAseState(leAudioDevice, ase, - AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - - if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - /* We are here because of the reconnection of the single device. */ - PrepareDataPath(group); - return; - } - - if (leAudioDevice->IsReadyToCreateStream()) - ProcessGroupEnable(group); - + LOG_ERROR( + "%s, ase_id: %d, moving from QoS Configured to Streaming is " + "impossible.", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), ase->id); + group->PrintDebugState(); + StopStream(group); break; case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING: { @@ -2630,46 +2680,45 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) { /* More ASEs notification form this device has to come for this group */ - return; } - /* This case may happen because of the reconnection device. */ if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { - /* Not all CISes establish evens came */ - if (group->GetFirstActiveDeviceByDataPathState( - AudioStreamDataPathState::CIS_PENDING)) - return; - - /* Streaming status notification came after setting data path */ - if (!group->GetFirstActiveDeviceByDataPathState( - AudioStreamDataPathState::CIS_ESTABLISHED)) - return; - PrepareDataPath(group); + /* We are here because of the reconnection of the single device */ + LOG_INFO("%s, Ase id: %d, ase state: %s", + ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), ase->id, + bluetooth::common::ToString(ase->state).c_str()); + cancel_watchdog_if_needed(group->group_id_); + state_machine_callbacks_->StatusReportCb( + group->group_id_, GroupStreamStatus::STREAMING); return; } - /* Last node is in streaming state */ - group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - - /* Not all CISes establish evens came */ - if (!group->IsGroupStreamReady()) return; + /* Not all CISes establish events will came */ + if (!group->IsGroupStreamReady()) { + LOG_INFO("CISes are not yet ready, wait for it."); + group->SetNotifyStreamingWhenCisesAreReadyFlag(true); + return; + } if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { /* No more transition for group */ cancel_watchdog_if_needed(group->group_id_); - PrepareDataPath(group); - return; - } else { - LOG_ERROR(", invalid state transition, from: %s, to: %s", - ToString(group->GetState()).c_str(), - ToString(group->GetTargetState()).c_str()); - StopStream(group); + /* Last node is in streaming state */ + group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + state_machine_callbacks_->StatusReportCb( + group->group_id_, GroupStreamStatus::STREAMING); return; } + LOG_ERROR(", invalid state transition, from: %s, to: %s", + ToString(group->GetState()).c_str(), + ToString(group->GetTargetState()).c_str()); + StopStream(group); + break; } case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING: { @@ -2699,6 +2748,22 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } } + void ScheduleAutonomousOperationTimer(AseState target_state, + LeAudioDevice* leAudioDevice, + struct ase* ase) { + ase->autonomous_target_state_ = target_state; + ase->autonomous_operation_timer_ = + alarm_new("LeAudioAutonomousOperationTimeout"); + alarm_set_on_mloop( + ase->autonomous_operation_timer_, kAutonomousTransitionTimeoutMs, + [](void* data) { + LeAudioDevice* leAudioDevice = static_cast(data); + instance->state_machine_callbacks_ + ->OnDeviceAutonomousStateTransitionTimeout(leAudioDevice); + }, + leAudioDevice); + } + void AseStateMachineProcessDisabling( struct le_audio::client_parser::ascs::ase_rsp_hdr& arh, struct ase* ase, LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) { @@ -2725,10 +2790,15 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING); + /* Remote may autonomously bring ASEs to QoS configured state */ + if (group->GetTargetState() != + AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) { + ProcessAutonomousDisable(leAudioDevice, ase); + } + /* Process the Disable Transition of the rest of group members if no * more ASE notifications has to come from this device. */ - if (leAudioDevice->IsReadyToSuspendStream()) - ProcessGroupDisable(group); + if (leAudioDevice->IsReadyToSuspendStream()) ProcessGroupDisable(group); break; @@ -2746,17 +2816,17 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { LeAudioDevice* leAudioDevice, struct ase* ase) { LOG_DEBUG( "Group id: %d, %s, ase id: %d, cis_handle: 0x%04x, direction: %s, " - "data_path_state: %s", + "data_path_state: %s, cis_state: %s", group->group_id_, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), ase->id, ase->cis_conn_hdl, ase->direction == le_audio::types::kLeAudioDirectionSink ? "sink" : "source", - bluetooth::common::ToString(ase->data_path_state).c_str()); + bluetooth::common::ToString(ase->data_path_state).c_str(), + bluetooth::common::ToString(ase->cis_state).c_str()); auto bidirection_ase = leAudioDevice->GetAseToMatchBidirectionCis(ase); if (bidirection_ase != nullptr && - bidirection_ase->data_path_state == - AudioStreamDataPathState::CIS_ESTABLISHED && + bidirection_ase->cis_state == CisState::CONNECTED && (bidirection_ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING || bidirection_ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING)) { LOG_INFO("Still waiting for the bidirectional ase %d to be released (%s)", @@ -2765,7 +2835,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } - RemoveCisFromStreamConfiguration(group, leAudioDevice, ase->cis_conn_hdl); + group->RemoveCisFromStreamIfNeeded(leAudioDevice, ase->cis_conn_hdl); IsoManager::GetInstance()->DisconnectCis(ase->cis_conn_hdl, HCI_ERR_PEER_USER); log_history_->AddLogHistory( @@ -2803,22 +2873,47 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { break; - case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING: + case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING: { + SetAseState(leAudioDevice, ase, + AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); + + bool remove_cig = true; + + /* Happens when bi-directional completive ASE releasing state came */ + if (ase->cis_state == CisState::DISCONNECTING) break; + if ((ase->cis_state == CisState::CONNECTED || + ase->cis_state == CisState::CONNECTING) && + ase->data_path_state == DataPathState::IDLE) { + DisconnectCisIfNeeded(group, leAudioDevice, ase); + /* CISes are still there. CIG will be removed when CIS is down. */ + remove_cig = false; + } + + if (!group->HaveAllActiveDevicesAsesTheSameState( + AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)) { + return; + } + group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); + + if (remove_cig) { + /* In the ENABLING state most probably there was no CISes created. + * Make sure group is destroyed here */ + RemoveCigForGroup(group); + } + break; + } case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING: { SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); /* Happens when bi-directional completive ASE releasing state came */ - if (ase->data_path_state == AudioStreamDataPathState::CIS_DISCONNECTING) - break; + if (ase->cis_state == CisState::DISCONNECTING) break; - if (ase->data_path_state == - AudioStreamDataPathState::DATA_PATH_ESTABLISHED) { + if (ase->data_path_state == DataPathState::CONFIGURED) { RemoveDataPathByCisHandle(leAudioDevice, ase->cis_conn_hdl); - } else if (ase->data_path_state == - AudioStreamDataPathState::CIS_ESTABLISHED || - ase->data_path_state == - AudioStreamDataPathState::CIS_PENDING) { + } else if ((ase->cis_state == CisState::CONNECTED || + ase->cis_state == CisState::CONNECTING) && + ase->data_path_state == DataPathState::IDLE) { DisconnectCisIfNeeded(group, leAudioDevice, ase); } else { DLOG(INFO) << __func__ << ", Nothing to do ase data path state: " @@ -2837,6 +2932,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { void ProcessGroupEnable(LeAudioDeviceGroup* group) { if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING) { + /* Check if the group is ready to create stream. If not, keep waiting. */ if (!group->IsGroupReadyToCreateStream()) { LOG_DEBUG( "Waiting for more ASEs to be in enabling or directly in streaming " @@ -2844,18 +2940,11 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } + /* Group can move to Enabling state now. */ group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING); } - /* At this point all of the active ASEs within group are enabled. The server - * might perform autonomous state transition for Sink ASE and skip Enabling - * state notification and transit to Streaming directly. So check the group - * state, because we might be ready to create CIS. */ - if (group->HaveAllActiveDevicesAsesTheSameState( - AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) { - group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - } - + /* If Target State is not streaming, then something is wrong. */ if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { LOG_ERROR(", invalid state transition, from: %s , to: %s ", ToString(group->GetState()).c_str(), @@ -2864,6 +2953,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } + /* Try to create CISes for the group */ if (!CisCreate(group)) { StopStream(group); } @@ -2899,6 +2989,34 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { StopStream(group); } } + + void ProcessAutonomousDisable(LeAudioDevice* leAudioDevice, struct ase* ase) { + auto bidirection_ase = leAudioDevice->GetAseToMatchBidirectionCis(ase); + + /* ASE is not a part of bi-directional CIS */ + if (!bidirection_ase) return; + + /* ASE is already disabled */ + if (bidirection_ase->state == + AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) { + /* Bi-direction ASEs are now disabled */ + if ((ase->autonomous_target_state_ == + AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) && + alarm_is_scheduled(ase->autonomous_operation_timer_)) { + alarm_free(ase->autonomous_operation_timer_); + ase->autonomous_operation_timer_ = NULL; + ase->autonomous_target_state_ = AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; + } + return; + } + + /* Schedule alarm if first ASE is autonomously disabling */ + if (!alarm_is_scheduled(bidirection_ase->autonomous_operation_timer_)) { + ScheduleAutonomousOperationTimer( + AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED, leAudioDevice, + bidirection_ase); + } + } }; } // namespace diff --git a/system/bta/le_audio/state_machine.h b/system/bta/le_audio/state_machine.h index e4d92e8af073b37c9162158c76fe7483531f2769..0eaf3bbc0ec480be5784ffaf5fbeef40ebe3e46b 100644 --- a/system/bta/le_audio/state_machine.h +++ b/system/bta/le_audio/state_machine.h @@ -21,6 +21,7 @@ #include "btm_iso_api.h" #include "btm_iso_api_types.h" +#include "device_groups.h" #include "devices.h" #include "hardware/bt_le_audio.h" #include "le_audio_types.h" @@ -37,6 +38,9 @@ class LeAudioGroupStateMachine { virtual void StatusReportCb( int group_id, bluetooth::le_audio::GroupStreamStatus status) = 0; virtual void OnStateTransitionTimeout(int group_id) = 0; + virtual void OnUpdatedCisConfiguration(int group_id, uint8_t direction) = 0; + virtual void OnDeviceAutonomousStateTransitionTimeout( + LeAudioDevice* leAudioDevice) = 0; }; virtual ~LeAudioGroupStateMachine() = default; @@ -45,8 +49,9 @@ class LeAudioGroupStateMachine { static void Cleanup(void); static LeAudioGroupStateMachine* Get(void); - virtual bool AttachToStream(LeAudioDeviceGroup* group, - LeAudioDevice* leAudioDevice) = 0; + virtual bool AttachToStream( + LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, + types::BidirectionalPair> ccids) = 0; virtual bool StartStream( LeAudioDeviceGroup* group, types::LeAudioContextType context_type, const types::BidirectionalPair& @@ -61,6 +66,8 @@ class LeAudioGroupStateMachine { types::BidirectionalPair> ccid_lists = { .sink = {}, .source = {}}) = 0; virtual void StopStream(LeAudioDeviceGroup* group) = 0; + virtual void ProcessGattCtpNotification(LeAudioDeviceGroup* group, + uint8_t* value, uint16_t len) = 0; virtual void ProcessGattNotifEvent(uint8_t* value, uint16_t len, struct types::ase* ase, LeAudioDevice* leAudioDevice, diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc index 59bc9e06e19329d20c67368cdb3208c23308e529..e88c75c01b7ea56e05e77e67fa8ef7033e8d8428 100644 --- a/system/bta/le_audio/state_machine_test.cc +++ b/system/bta/le_audio/state_machine_test.cc @@ -34,12 +34,13 @@ #include "mock_controller.h" #include "mock_csis_client.h" #include "mock_iso_manager.h" +#include "stack/include/bt_types.h" #include "test/common/mock_functions.h" #include "types/bt_transport.h" using ::le_audio::DeviceConnectState; -using ::le_audio::codec_spec_caps::kLeAudioCodecLC3ChannelCountSingleChannel; -using ::le_audio::codec_spec_caps::kLeAudioCodecLC3ChannelCountTwoChannel; +using ::le_audio::codec_spec_caps::kLeAudioCodecChannelCountSingleChannel; +using ::le_audio::codec_spec_caps::kLeAudioCodecChannelCountTwoChannel; using ::le_audio::types::LeAudioContextType; using ::testing::_; using ::testing::AnyNumber; @@ -135,15 +136,7 @@ constexpr uint8_t kAseParamFramingUnframedSupported = 0x00; // constexpr uint8_t kAseParamPreferredPhy2M = 0x02; // constexpr uint8_t kAseParamPreferredPhyCoded = 0x04; -constexpr uint8_t kAseCtpOpcodeConfigureCodec = 0x01; -constexpr uint8_t kAseCtpOpcodeConfigureQos = 0x02; -constexpr uint8_t kAseCtpOpcodeEnable = 0x03; -constexpr uint8_t kAseCtpOpcodeReceiverStartReady = 0x04; -constexpr uint8_t kAseCtpOpcodeDisable = 0x05; -constexpr uint8_t kAseCtpOpcodeReceiverStopReady = 0x06; -// constexpr uint8_t kAseCtpOpcodeUpdateMetadata = 0x07; -constexpr uint8_t kAseCtpOpcodeRelease = 0x08; -constexpr uint8_t kAseCtpOpcodeMaxVal = kAseCtpOpcodeRelease; +constexpr uint8_t kAseCtpOpcodeMaxVal = client_parser::ascs::kCtpOpcodeRelease; } // namespace ascs @@ -165,23 +158,67 @@ class MockLeAudioGroupStateMachineCallbacks (int group_id, bluetooth::le_audio::GroupStreamStatus status), (override)); MOCK_METHOD((void), OnStateTransitionTimeout, (int group_id), (override)); + MOCK_METHOD((void), OnUpdatedCisConfiguration, + (int group_id, uint8_t direction), (override)); + MOCK_METHOD((void), OnDeviceAutonomousStateTransitionTimeout, + (LeAudioDevice * leAudioDevice), (override)); }; -class StateMachineTest : public Test { +class MockAseRemoteStateMachine { + public: + MockAseRemoteStateMachine() = default; + MockAseRemoteStateMachine& operator=(const MockAseRemoteStateMachine&) = + delete; + ~MockAseRemoteStateMachine() = default; + MOCK_METHOD((void), AseCtpConfigureCodecHandler, + (LeAudioDevice * device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data)); + MOCK_METHOD((void), AseCtpConfigureQosHandler, + (LeAudioDevice * device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data)); + MOCK_METHOD((void), AseCtpEnableHandler, + (LeAudioDevice * device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data)); + MOCK_METHOD((void), AseCtpReceiverStartReadyHandler, + (LeAudioDevice * device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data)); + MOCK_METHOD((void), AseCtpDisableHandler, + (LeAudioDevice * device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data)); + MOCK_METHOD((void), AseCtpReceiverStopReadyHandler, + (LeAudioDevice * device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data)); + MOCK_METHOD((void), AseCtpUpdateMetadataHandler, + (LeAudioDevice * device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data)); + MOCK_METHOD((void), AseCtpReleaseHandler, + (LeAudioDevice * device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data)); +}; + +class StateMachineTestBase : public Test { protected: uint8_t ase_id_last_assigned = types::ase::kAseIdInvalid; uint8_t additional_snk_ases = 0; uint8_t additional_src_ases = 0; - uint8_t channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel; + uint8_t channel_count_ = kLeAudioCodecChannelCountSingleChannel; uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz; /* Use to simulated error status on Cis creation */ bool overwrite_cis_status_; + bool use_cis_retry_cnt_; + int retry_cis_established_cnt_; bool do_not_send_cis_establish_event_; uint8_t overwrite_cis_status_idx_; std::vector cis_status_; - void SetUp() override { + /* Keep ASE in releasing state */ + bool stay_in_releasing_state_; + + /* Use for single test to simulate late ASE notifications */ + bool stop_inject_configured_ase_after_first_ase_configured_; + + virtual void SetUp() override { bluetooth::common::InitFlags::Load(test_flags); reset_mock_function_count_map(); controller::SetMockControllerInterface(&mock_controller_); @@ -190,11 +227,14 @@ class StateMachineTest : public Test { gatt::SetMockBtaGattQueue(&gatt_queue); overwrite_cis_status_idx_ = 0; + use_cis_retry_cnt_ = false; + retry_cis_established_cnt_ = 0; overwrite_cis_status_ = false; do_not_send_cis_establish_event_ = false; + stay_in_releasing_state_ = false; + stop_inject_configured_ase_after_first_ase_configured_ = false; cis_status_.clear(); - ::le_audio::AudioSetConfigurationProvider::Initialize(); LeAudioGroupStateMachine::Initialize(&mock_callbacks_); ContentControlIdKeeper::GetInstance()->Start(); @@ -243,7 +283,6 @@ class StateMachineTest : public Test { })); ConfigureIsoManagerMock(); - ConfigCodecManagerMock(); } void HandleCtpOperation(LeAudioDevice* device, std::vector value, @@ -254,8 +293,42 @@ class StateMachineTest : public Test { ASSERT_LT(opcode, ascs::kAseCtpOpcodeMaxVal + 1); ASSERT_NE(opcode, 0); - if (ase_ctp_handlers[opcode]) - ase_ctp_handlers[opcode](device, std::move(value), cb, cb_data); + switch (opcode) { + case client_parser::ascs::kCtpOpcodeCodecConfiguration: + ase_ctp_handler.AseCtpConfigureCodecHandler(device, std::move(value), + cb, cb_data); + break; + case client_parser::ascs::kCtpOpcodeQosConfiguration: + ase_ctp_handler.AseCtpConfigureQosHandler(device, std::move(value), cb, + cb_data); + break; + case client_parser::ascs::kCtpOpcodeEnable: + ase_ctp_handler.AseCtpEnableHandler(device, std::move(value), cb, + cb_data); + break; + case client_parser::ascs::kCtpOpcodeReceiverStartReady: + ase_ctp_handler.AseCtpReceiverStartReadyHandler( + device, std::move(value), cb, cb_data); + break; + case client_parser::ascs::kCtpOpcodeDisable: + ase_ctp_handler.AseCtpDisableHandler(device, std::move(value), cb, + cb_data); + break; + case client_parser::ascs::kCtpOpcodeReceiverStopReady: + ase_ctp_handler.AseCtpReceiverStopReadyHandler(device, std::move(value), + cb, cb_data); + break; + case client_parser::ascs::kCtpOpcodeUpdateMetadata: + ase_ctp_handler.AseCtpUpdateMetadataHandler(device, std::move(value), + cb, cb_data); + break; + case client_parser::ascs::kCtpOpcodeRelease: + ase_ctp_handler.AseCtpReleaseHandler(device, std::move(value), cb, + cb_data); + break; + default: + break; + }; } /* Helper function to make a deterministic (and unique on the entire device) @@ -387,8 +460,19 @@ class StateMachineTest : public Test { bluetooth::hci::iso_manager::cis_establish_cmpl_evt evt; // Fill proper values if needed - if (overwrite_cis_status_) { + if (use_cis_retry_cnt_) { + if (retry_cis_established_cnt_ > 0) { + evt.status = HCI_ERR_CONN_FAILED_ESTABLISHMENT; + retry_cis_established_cnt_--; + } else { + evt.status = 0; + } + } else if (overwrite_cis_status_) { evt.status = cis_status_[overwrite_cis_status_idx_++]; + /* Reset the index */ + if (cis_status_.size() == overwrite_cis_status_idx_) { + overwrite_cis_status_idx_ = 0; + } } else { evt.status = 0; } @@ -455,7 +539,7 @@ class StateMachineTest : public Test { }); } - void ConfigCodecManagerMock() { + void ConfigCodecManagerMock(types::CodecLocation location) { codec_manager_ = le_audio::CodecManager::GetInstance(); ASSERT_NE(codec_manager_, nullptr); std::vector @@ -464,7 +548,7 @@ class StateMachineTest : public Test { mock_codec_manager_ = MockCodecManager::GetInstance(); ASSERT_NE(mock_codec_manager_, nullptr); ON_CALL(*mock_codec_manager_, GetCodecLocation()) - .WillByDefault(Return(types::CodecLocation::HOST)); + .WillByDefault(Return(location)); } void TearDown() override { @@ -483,13 +567,12 @@ class StateMachineTest : public Test { bluetooth::manager::SetMockBtmInterface(nullptr); controller::SetMockControllerInterface(nullptr); - for (auto i = 0u; i <= ascs::kAseCtpOpcodeMaxVal; ++i) - ase_ctp_handlers[i] = nullptr; - le_audio_devices_.clear(); addresses_.clear(); cached_codec_configuration_map_.clear(); + cached_qos_configuration_map_.clear(); cached_ase_to_cis_id_map_.clear(); + cached_remote_qos_configuration_for_ase_.clear(); LeAudioGroupStateMachine::Cleanup(); ::le_audio::AudioSetConfigurationProvider::Cleanup(); } @@ -625,6 +708,8 @@ class StateMachineTest : public Test { UINT16_TO_STREAM(p, conf->max_transport_latency); UINT24_TO_STREAM(p, conf->pres_delay); + cached_remote_qos_configuration_for_ase_[ase] = notif_value; + LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent( notif_value.data(), notif_value.size(), ase, device, group); } break; @@ -727,7 +812,8 @@ class StateMachineTest : public Test { LeAudioContextType context_type, uint16_t device_cnt, types::AudioContexts update_contexts, - bool insert_default_pac_records = true) { + bool insert_default_pac_records = true, + bool second_device_0_ases = false) { // Prepare fake connected device group DeviceConnectState initial_connect_state = DeviceConnectState::CONNECTING_BY_USER; @@ -762,8 +848,15 @@ class StateMachineTest : public Test { } while (device_cnt) { - auto leAudioDevice = PrepareConnectedDevice( - device_cnt--, initial_connect_state, num_ase_snk, num_ase_src); + std::shared_ptr leAudioDevice; + + if (device_cnt == 2 && second_device_0_ases == true) { + leAudioDevice = + PrepareConnectedDevice(device_cnt--, initial_connect_state, 0, 0); + } else { + leAudioDevice = PrepareConnectedDevice( + device_cnt--, initial_connect_state, num_ase_snk, num_ase_src); + } if (insert_default_pac_records) { uint16_t attr_handle = ATTR_HANDLE_PACS_POOL_START; @@ -824,8 +917,10 @@ class StateMachineTest : public Test { ::le_audio::codec_spec_conf::kLeAudioLocationFrontRight; } - leAudioDevice->SetSupportedContexts(snk_context_type, src_context_type); - leAudioDevice->SetAvailableContexts(snk_context_type, src_context_type); + leAudioDevice->SetSupportedContexts( + {.sink = snk_context_type, .source = src_context_type}); + leAudioDevice->SetAvailableContexts( + {.sink = snk_context_type, .source = src_context_type}); } group = GroupTheDevice(leaudio_group_id, std::move(leAudioDevice)); @@ -834,10 +929,9 @@ class StateMachineTest : public Test { group->ReloadAudioDirections(); } - /* Stimulate update of available context map */ - auto types_set = update_contexts.any() ? context_type | update_contexts - : types::AudioContexts(context_type); - group->UpdateAudioContextTypeAvailability(types_set); + /* Stimulate update of available context map and configuration cache */ + group->UpdateAudioContextAvailability(); + group->UpdateAudioSetConfigurationCache(context_type); ASSERT_NE(group, nullptr); ASSERT_EQ(group->Size(), total_devices); @@ -846,9 +940,10 @@ class StateMachineTest : public Test { LeAudioDeviceGroup* PrepareSingleTestDeviceGroup( int leaudio_group_id, LeAudioContextType context_type, uint16_t device_cnt = 1, - types::AudioContexts update_contexts = types::AudioContexts()) { + types::AudioContexts update_contexts = types::AudioContexts(), + bool second_device_0_ases = false) { MultipleTestDevicePrepare(leaudio_group_id, context_type, device_cnt, - update_contexts); + update_contexts, true, second_device_0_ases); return le_audio_device_groups_.count(leaudio_group_id) ? le_audio_device_groups_[leaudio_group_id].get() : nullptr; @@ -857,10 +952,11 @@ class StateMachineTest : public Test { void PrepareConfigureCodecHandler(LeAudioDeviceGroup* group, int verify_ase_count = 0, bool caching = false) { - ase_ctp_handlers[ascs::kAseCtpOpcodeConfigureCodec] = - [group, verify_ase_count, caching, this]( - LeAudioDevice* device, std::vector value, - GATT_WRITE_OP_CB cb, void* cb_data) { + ON_CALL(ase_ctp_handler, AseCtpConfigureCodecHandler) + .WillByDefault(Invoke([group, verify_ase_count, caching, this]( + LeAudioDevice* device, + std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data) { auto num_ase = value[1]; // Verify ase count if needed @@ -918,17 +1014,22 @@ class StateMachineTest : public Test { InjectAseStateNotification(ase, device, group, ascs::kAseStateCodecConfigured, &codec_configured_state_params); + + if (stop_inject_configured_ase_after_first_ase_configured_) { + return; + } } - }; + })); } void PrepareConfigureQosHandler(LeAudioDeviceGroup* group, int verify_ase_count = 0, bool caching = false) { - ase_ctp_handlers[ascs::kAseCtpOpcodeConfigureQos] = - [group, verify_ase_count, caching, this]( - LeAudioDevice* device, std::vector value, - GATT_WRITE_OP_CB cb, void* cb_data) { + ON_CALL(ase_ctp_handler, AseCtpConfigureQosHandler) + .WillByDefault(Invoke([group, verify_ase_count, caching, this]( + LeAudioDevice* device, + std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data) { auto num_ase = value[1]; // Verify ase count if needed @@ -987,21 +1088,105 @@ class StateMachineTest : public Test { cached_ase_to_cis_id_map_[device->address_] = ase_map; } + cached_qos_configuration_map_[ase_id] = + qos_configured_state_params; } InjectAseStateNotification(ase, device, group, ascs::kAseStateQoSConfigured, &qos_configured_state_params); } - }; + })); + } + + void PrepareCtpNotificationError(LeAudioDeviceGroup* group, uint8_t opcode, + uint8_t response_code, uint8_t reason) { + auto foo = [group, opcode, response_code, reason]( + LeAudioDevice* device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data) { + auto num_ase = value[1]; + std::vector notif_value( + 2 + num_ase * sizeof(struct client_parser::ascs::ctp_ase_entry)); + auto* p = notif_value.data(); + + UINT8_TO_STREAM(p, opcode); + UINT8_TO_STREAM(p, num_ase); + + auto* ase_p = &value[2]; + for (auto i = 0u; i < num_ase; ++i) { + /* Check if this is a valid ASE ID */ + auto ase_id = *ase_p++; + auto it = + std::find_if(device->ases_.begin(), device->ases_.end(), + [ase_id](auto& ase) { return (ase.id == ase_id); }); + ASSERT_NE(it, device->ases_.end()); + + auto meta_len = *ase_p++; + auto num_handled_bytes = ase_p - value.data(); + ase_p += meta_len; + + client_parser::ascs::ase_transient_state_params enable_params = { + .metadata = std::vector( + value.begin() + num_handled_bytes, + value.begin() + num_handled_bytes + meta_len)}; + + // Inject error response + UINT8_TO_STREAM(p, ase_id); + UINT8_TO_STREAM(p, response_code); + UINT8_TO_STREAM(p, reason); + } + + LeAudioGroupStateMachine::Get()->ProcessGattCtpNotification( + group, notif_value.data(), notif_value.size()); + }; + + switch (opcode) { + case client_parser::ascs::kCtpOpcodeCodecConfiguration: + ON_CALL(ase_ctp_handler, AseCtpConfigureCodecHandler) + .WillByDefault(Invoke(foo)); + break; + case client_parser::ascs::kCtpOpcodeQosConfiguration: + ON_CALL(ase_ctp_handler, AseCtpConfigureQosHandler) + .WillByDefault(Invoke(foo)); + break; + case client_parser::ascs::kCtpOpcodeEnable: + ON_CALL(ase_ctp_handler, AseCtpEnableHandler) + .WillByDefault(Invoke(foo)); + break; + case client_parser::ascs::kCtpOpcodeReceiverStartReady: + ON_CALL(ase_ctp_handler, AseCtpReceiverStartReadyHandler) + .WillByDefault(Invoke(foo)); + break; + case client_parser::ascs::kCtpOpcodeDisable: + ON_CALL(ase_ctp_handler, AseCtpDisableHandler) + .WillByDefault(Invoke(foo)); + break; + case client_parser::ascs::kCtpOpcodeReceiverStopReady: + ON_CALL(ase_ctp_handler, AseCtpReceiverStopReadyHandler) + .WillByDefault(Invoke(foo)); + break; + case client_parser::ascs::kCtpOpcodeUpdateMetadata: + ON_CALL(ase_ctp_handler, AseCtpUpdateMetadataHandler) + .WillByDefault(Invoke(foo)); + break; + case client_parser::ascs::kCtpOpcodeRelease: + ON_CALL(ase_ctp_handler, AseCtpReleaseHandler) + .WillByDefault(Invoke(foo)); + break; + default: + break; + }; } void PrepareEnableHandler(LeAudioDeviceGroup* group, int verify_ase_count = 0, - bool inject_enabling = true) { - ase_ctp_handlers[ascs::kAseCtpOpcodeEnable] = - [group, verify_ase_count, inject_enabling, this]( - LeAudioDevice* device, std::vector value, - GATT_WRITE_OP_CB cb, void* cb_data) { + bool inject_enabling = true, + bool incject_streaming = true) { + ON_CALL(ase_ctp_handler, AseCtpEnableHandler) + .WillByDefault(Invoke([group, verify_ase_count, inject_enabling, + incject_streaming, + this](LeAudioDevice* device, + std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data) { auto num_ase = value[1]; // Verify ase count if needed @@ -1034,22 +1219,26 @@ class StateMachineTest : public Test { InjectAseStateNotification(ase, device, group, ascs::kAseStateEnabling, &enable_params); - InjectAseStateNotification( - ase, device, group, ascs::kAseStateStreaming, &enable_params); + if (incject_streaming) { + InjectAseStateNotification(ase, device, group, + ascs::kAseStateStreaming, + &enable_params); + } } else { InjectAseStateNotification( ase, device, group, ascs::kAseStateEnabling, &enable_params); } } - }; + })); } void PrepareDisableHandler(LeAudioDeviceGroup* group, int verify_ase_count = 0) { - ase_ctp_handlers[ascs::kAseCtpOpcodeDisable] = - [group, verify_ase_count, this](LeAudioDevice* device, - std::vector value, - GATT_WRITE_OP_CB cb, void* cb_data) { + ON_CALL(ase_ctp_handler, AseCtpDisableHandler) + .WillByDefault(Invoke([group, verify_ase_count, this]( + LeAudioDevice* device, + std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data) { auto num_ase = value[1]; // Verify ase count if needed @@ -1087,15 +1276,16 @@ class StateMachineTest : public Test { &qos_configured_state_params); } } - }; + })); } - void PrepareReceiverStartReady(LeAudioDeviceGroup* group, - int verify_ase_count = 0) { - ase_ctp_handlers[ascs::kAseCtpOpcodeReceiverStartReady] = - [group, verify_ase_count, this](LeAudioDevice* device, - std::vector value, - GATT_WRITE_OP_CB cb, void* cb_data) { + void PrepareReceiverStartReadyHandler(LeAudioDeviceGroup* group, + int verify_ase_count = 0) { + ON_CALL(ase_ctp_handler, AseCtpReceiverStartReadyHandler) + .WillByDefault(Invoke([group, verify_ase_count, this]( + LeAudioDevice* device, + std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data) { auto num_ase = value[1]; // Verify ase count if needed @@ -1120,86 +1310,100 @@ class StateMachineTest : public Test { ascs::kAseStateStreaming, &streaming_params); } - }; + })); } void PrepareReceiverStopReady(LeAudioDeviceGroup* group, int verify_ase_count = 0) { - ase_ctp_handlers[ascs::kAseCtpOpcodeReceiverStopReady] = - [group, verify_ase_count, this](LeAudioDevice* device, - std::vector value, - GATT_WRITE_OP_CB cb, void* cb_data) { - auto num_ase = value[1]; - - // Verify ase count if needed - if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase); - - // Inject QoS configured ASE state notification for each Source ASE - auto* ase_p = &value[2]; - for (auto i = 0u; i < num_ase; ++i) { - /* Check if this is a valid ASE ID */ - auto ase_id = *ase_p++; - auto it = std::find_if( - device->ases_.begin(), device->ases_.end(), - [ase_id](auto& ase) { return (ase.id == ase_id); }); - ASSERT_NE(it, device->ases_.end()); - - const auto& ase = &(*it); - - // FIXME: For now our fake peer does not remember qos params - client_parser::ascs::ase_qos_configured_state_params - qos_configured_state_params; - InjectAseStateNotification(ase, device, group, - ascs::kAseStateQoSConfigured, - &qos_configured_state_params); - } - }; + ON_CALL(ase_ctp_handler, AseCtpReceiverStopReadyHandler) + .WillByDefault( + Invoke([group, verify_ase_count, this]( + LeAudioDevice* device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data) { + auto num_ase = value[1]; + + // Verify ase count if needed + if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase); + + // Inject QoS configured ASE state notification for each Source + // ASE + auto* ase_p = &value[2]; + for (auto i = 0u; i < num_ase; ++i) { + /* Check if this is a valid ASE ID */ + auto ase_id = *ase_p++; + auto it = std::find_if( + device->ases_.begin(), device->ases_.end(), + [ase_id](auto& ase) { return (ase.id == ase_id); }); + ASSERT_NE(it, device->ases_.end()); + + const auto& ase = &(*it); + + // FIXME: For now our fake peer does not remember qos params + client_parser::ascs::ase_qos_configured_state_params + qos_configured_state_params; + InjectAseStateNotification(ase, device, group, + ascs::kAseStateQoSConfigured, + &qos_configured_state_params); + } + })); } void PrepareReleaseHandler(LeAudioDeviceGroup* group, int verify_ase_count = 0, - bool inject_disconnect_device = false) { - ase_ctp_handlers[ascs::kAseCtpOpcodeRelease] = - [group, verify_ase_count, inject_disconnect_device, this]( - LeAudioDevice* device, std::vector value, - GATT_WRITE_OP_CB cb, void* cb_data) { - auto num_ase = value[1]; + bool inject_disconnect_device = false, + LeAudioDevice* dev = nullptr) { + ON_CALL(ase_ctp_handler, AseCtpReleaseHandler) + .WillByDefault( + Invoke([group, verify_ase_count, inject_disconnect_device, dev, + this](LeAudioDevice* device, std::vector value, + GATT_WRITE_OP_CB cb, void* cb_data) { + if (dev != nullptr && device != dev) { + LOG_INFO("Do nothing for %s", + ADDRESS_TO_LOGGABLE_CSTR(dev->address_)); + return; + } - // Verify ase count if needed - if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase); - ASSERT_EQ(value.size(), 2ul + num_ase); + auto num_ase = value[1]; - if (inject_disconnect_device) { - InjectAclDisconnected(group, device); - return; - } + // Verify ase count if needed + if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase); + ASSERT_EQ(value.size(), 2ul + num_ase); - // Inject Releasing & Idle ASE state notification for each ASE - auto* ase_p = &value[2]; - for (auto i = 0u; i < num_ase; ++i) { - /* Check if this is a valid ASE ID */ - auto ase_id = *ase_p++; - auto it = std::find_if( - device->ases_.begin(), device->ases_.end(), - [ase_id](auto& ase) { return (ase.id == ase_id); }); - ASSERT_NE(it, device->ases_.end()); - const auto ase = &(*it); + if (inject_disconnect_device) { + InjectAclDisconnected(group, device); + return; + } - InjectAseStateNotification(ase, device, group, - ascs::kAseStateReleasing, nullptr); + // Inject Releasing & Idle ASE state notification for each ASE + auto* ase_p = &value[2]; + for (auto i = 0u; i < num_ase; ++i) { + /* Check if this is a valid ASE ID */ + auto ase_id = *ase_p++; + auto it = std::find_if( + device->ases_.begin(), device->ases_.end(), + [ase_id](auto& ase) { return (ase.id == ase_id); }); + ASSERT_NE(it, device->ases_.end()); + const auto ase = &(*it); - /* Check if codec configuration is cached */ - if (cached_codec_configuration_map_.count(ase_id) > 0) { - InjectAseStateNotification( - ase, device, group, ascs::kAseStateCodecConfigured, - &cached_codec_configuration_map_[ase_id]); - } else { - // Release - no caching - InjectAseStateNotification(ase, device, group, - ascs::kAseStateIdle, nullptr); - } - } - }; + InjectAseStateNotification(ase, device, group, + ascs::kAseStateReleasing, nullptr); + + if (stay_in_releasing_state_) { + continue; + } + + /* Check if codec configuration is cached */ + if (cached_codec_configuration_map_.count(ase_id) > 0) { + InjectAseStateNotification( + ase, device, group, ascs::kAseStateCodecConfigured, + &cached_codec_configuration_map_[ase_id]); + } else { + // Release - no caching + InjectAseStateNotification(ase, device, group, + ascs::kAseStateIdle, nullptr); + } + } + })); } MockCsisClient mock_csis_client_module_; @@ -1213,13 +1417,15 @@ class StateMachineTest : public Test { le_audio::CodecManager* codec_manager_; MockCodecManager* mock_codec_manager_; - std::function value, - GATT_WRITE_OP_CB cb, void* cb_data)> - ase_ctp_handlers[ascs::kAseCtpOpcodeMaxVal + 1] = {nullptr}; + MockAseRemoteStateMachine ase_ctp_handler; std::map cached_codec_configuration_map_; + std::map + cached_qos_configuration_map_; std::map> cached_ase_to_cis_id_map_; + std::map> + cached_remote_qos_configuration_for_ase_; MockLeAudioGroupStateMachineCallbacks mock_callbacks_; std::vector> le_audio_devices_; @@ -1229,6 +1435,24 @@ class StateMachineTest : public Test { bool group_create_command_disallowed_ = false; }; +class StateMachineTest : public StateMachineTestBase { + void SetUp() override { + ConfigCodecManagerMock(types::CodecLocation::HOST); + ::le_audio::AudioSetConfigurationProvider::Initialize( + ::le_audio::types::CodecLocation::HOST); + StateMachineTestBase::SetUp(); + } +}; + +class StateMachineTestAdsp : public StateMachineTestBase { + void SetUp() override { + ConfigCodecManagerMock(types::CodecLocation::ADSP); + ::le_audio::AudioSetConfigurationProvider::Initialize( + ::le_audio::types::CodecLocation::ADSP); + StateMachineTestBase::SetUp(); + } +}; + TEST_F(StateMachineTest, testInit) { ASSERT_NE(LeAudioGroupStateMachine::Get(), nullptr); } @@ -1245,8 +1469,8 @@ TEST_F(StateMachineTest, testConfigureCodecSingle) { */ const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 2; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); @@ -1471,14 +1695,14 @@ TEST_F(StateMachineTest, testConfigureQosMultiple) { ASSERT_EQ(0, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testStreamSingle) { +TEST_F(StateMachineTest, testStreamCreationError) { /* Device is banded headphones with 1x snk + 0x src ase * (1xunidirectional CIS) with channel count 2 (for stereo */ const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); @@ -1488,20 +1712,31 @@ TEST_F(StateMachineTest, testStreamSingle) { */ PrepareConfigureCodecHandler(group, 1); PrepareConfigureQosHandler(group, 1); - PrepareEnableHandler(group, 1); + PrepareCtpNotificationError( + group, client_parser::ascs::kCtpOpcodeEnable, + client_parser::ascs::kCtpResponseCodeUnspecifiedError, + client_parser::ascs::kCtpResponseNoReason); + PrepareReleaseHandler(group); auto* leAudioDevice = group->GetFirstDevice(); + + /* + * 1 - Configure ASE + * 2 - QoS ASE + * 3 - Enable ASE + * 4 - Release ASE + */ EXPECT_CALL(gatt_queue, WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(3); + .Times(4); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); @@ -1509,7 +1744,10 @@ TEST_F(StateMachineTest, testStreamSingle) { EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)); // Start the configuration and stream Media content ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( @@ -1518,27 +1756,28 @@ TEST_F(StateMachineTest, testStreamSingle) { .source = types::AudioContexts(context_type)})); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(2, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testStreamSkipEnablingSink) { - /* Device is banded headphones with 2x snk + none src ase - * (2x unidirectional CIS) +TEST_F(StateMachineTest, testStreamSingle) { + /* Device is banded headphones with 1x snk + 0x src ase + * (1xunidirectional CIS) with channel count 2 (for stereo */ - const auto context_type = kContextTypeMedia; + const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - /* For Media context type with channel count 1 and two ASEs, - * there should have be 2 Ases configured configured. + /* Ringtone with channel count 1 for single device and 1 ASE sink will + * end up with 1 Sink ASE being configured. */ - PrepareConfigureCodecHandler(group, 2); - PrepareConfigureQosHandler(group, 2); - PrepareEnableHandler(group, 2, false); + PrepareConfigureCodecHandler(group, 1); + PrepareConfigureQosHandler(group, 1); + PrepareEnableHandler(group, 1); auto* leAudioDevice = group->GetFirstDevice(); EXPECT_CALL(gatt_queue, @@ -1548,7 +1787,7 @@ TEST_F(StateMachineTest, testStreamSkipEnablingSink) { EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); @@ -1570,29 +1809,31 @@ TEST_F(StateMachineTest, testStreamSkipEnablingSink) { // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testStreamSkipEnablingSinkSource) { - /* Device is banded headphones with 2x snk + 1x src ase - * (1x bidirectional CIS) +TEST_F(StateMachineTest, testStreamSingleRetryCisFailure) { + /* Device is banded headphones with 1x snk + 0x src ase + * (1xunidirectional CIS) with channel count 2 (for stereo */ - const auto context_type = kContextTypeConversational; + const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; - - additional_snk_ases = 1; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - /* Since we prepared device with Conversional context in mind, - * 2 Sink ASEs and 1 Source ASE should have been configured. + /* Ringtone with channel count 1 for single device and 1 ASE sink will + * end up with 1 Sink ASE being configured. */ - PrepareConfigureCodecHandler(group, 3); - PrepareConfigureQosHandler(group, 3); - PrepareEnableHandler(group, 3, false); - PrepareReceiverStartReady(group, 1); + PrepareConfigureCodecHandler(group, 1); + PrepareConfigureQosHandler(group, 1); + PrepareEnableHandler(group, 1); + PrepareReleaseHandler(group); + + use_cis_retry_cnt_ = true; + retry_cis_established_cnt_ = 4; auto* leAudioDevice = group->GetFirstDevice(); EXPECT_CALL(gatt_queue, @@ -1601,11 +1842,11 @@ TEST_F(StateMachineTest, testStreamSkipEnablingSinkSource) { .Times(4); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(3); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); @@ -1613,7 +1854,10 @@ TEST_F(StateMachineTest, testStreamSkipEnablingSinkSource) { EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)); // Start the configuration and stream Media content ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( @@ -1622,48 +1866,47 @@ TEST_F(StateMachineTest, testStreamSkipEnablingSinkSource) { .source = types::AudioContexts(context_type)})); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(2, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testStreamMultipleConversational) { - const auto context_type = kContextTypeConversational; - const auto leaudio_group_id = 4; - const auto num_devices = 2; +TEST_F(StateMachineTest, testStreamSingleRetryCisSuccess) { + /* Device is banded headphones with 1x snk + 0x src ase + * (1xunidirectional CIS) with channel count 2 (for stereo + */ + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; - // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); - ASSERT_EQ(group->Size(), num_devices); + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - PrepareConfigureCodecHandler(group); - PrepareConfigureQosHandler(group); - PrepareEnableHandler(group); - PrepareReceiverStartReady(group); + /* Ringtone with channel count 1 for single device and 1 ASE sink will + * end up with 1 Sink ASE being configured. + */ + PrepareConfigureCodecHandler(group, 1); + PrepareConfigureQosHandler(group, 1); + PrepareEnableHandler(group, 1); + + use_cis_retry_cnt_ = true; + retry_cis_established_cnt_ = 2; + + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(3); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(3); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); - auto* leAudioDevice = group->GetFirstDevice(); - auto expected_devices_written = 0; - while (leAudioDevice) { - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(4); - expected_devices_written++; - leAudioDevice = group->GetNextDevice(leAudioDevice); - } - ASSERT_EQ(expected_devices_written, num_devices); - // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, @@ -1682,71 +1925,121 @@ TEST_F(StateMachineTest, testStreamMultipleConversational) { ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testFailedStreamMultipleConversational) { - /* Testing here CIS Failed to be established */ - const auto context_type = kContextTypeConversational; - const auto leaudio_group_id = 4; - const auto num_devices = 2; - overwrite_cis_status_ = true; +TEST_F(StateMachineTest, testStreamSkipEnablingSink) { + /* Device is banded headphones with 2x snk + none src ase + * (2x unidirectional CIS) + */ - cis_status_.resize(2); - cis_status_[0] = 0x00; - cis_status_[1] = 0x0e; // Failed to be established + /* Not, that when remote device skip Enabling it is considered as an error and + * group will not be able to go to Streaming state. + * It is because, Android is not creating CISes before all ASEs gets into + * Enabling state, therefore it is impossible to remote device to skip + * Enabling state. + */ + const auto context_type = kContextTypeMedia; + const int leaudio_group_id = 4; - // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); - ASSERT_EQ(group->Size(), num_devices); + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - PrepareConfigureCodecHandler(group); - PrepareConfigureQosHandler(group); - PrepareEnableHandler(group); - PrepareReceiverStartReady(group); - PrepareReleaseHandler(group); + /* For Media context type with channel count 1 and two ASEs, + * there should have be 2 Ases configured configured. + */ + PrepareConfigureCodecHandler(group, 2); + PrepareConfigureQosHandler(group, 2); + PrepareEnableHandler(group, 2, false); + + /* + * 1. Configure + * 2. QoS Config + * 3. Enable + * 4. Release + */ + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(4); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); - - /* This check is the major one in this test, as we want to make sure, - * it will not be called twice but only once (when both bidirectional ASEs are - * not in the STREAMING or ENABLING state) - */ - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); - + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); - auto* leAudioDevice = group->GetFirstDevice(); + // Validate GroupStreamStatus + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(0); - /* First device Control Point actions - * Codec Config - * QoS Config - * Enable - * Receiver ready - * Release + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)) + .Times(1); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); +} + +TEST_F(StateMachineTest, testStreamSkipEnablingSinkSource) { + /* Device is banded headphones with 2x snk + 1x src ase + * (1x bidirectional CIS) */ - EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, - _, GATT_WRITE_NO_RSP, _, _)) - .Times(5); - leAudioDevice = group->GetNextDevice(leAudioDevice); + const auto context_type = kContextTypeConversational; + const int leaudio_group_id = 4; - /* Second device Control Point actions - * Codec Config - * QoS Config - * Enable (failed on CIS established - therefore no Receiver Ready) - * Release + additional_snk_ases = 1; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Conversional context in mind, + * 2 Sink ASEs and 1 Source ASE should have been configured. */ - EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, - _, GATT_WRITE_NO_RSP, _, _)) + PrepareConfigureCodecHandler(group, 3); + PrepareConfigureQosHandler(group, 3); + PrepareEnableHandler(group, 3, false); + PrepareReceiverStartReadyHandler(group, 1); + + /* + * 1. Codec Config + * 2. Qos Config + * 3. Enable + * 4. Release + */ + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) .Times(4); - /* Prepare DisconnectCis mock to not symulate CisDisconnection */ - ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + + InjectInitialIdleNotification(group); + + // Validate GroupStreamStatus + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(0); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)) + .Times(1); // Start the configuration and stream Media content ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( @@ -1754,47 +2047,66 @@ TEST_F(StateMachineTest, testFailedStreamMultipleConversational) { {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)})); - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testStreamMultiple) { +TEST_F(StateMachineTest, testStreamMultipleMedia_OneMemberHasNoAses) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 4; const auto num_devices = 2; - // Prepare multiple fake connected devices in a group + // Prepare multiple fake connected devices in a group. This time one device + // has 0 Ases auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices, + types::AudioContexts(), true); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); + PrepareReceiverStartReadyHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); + /* Check there are two devices*/ auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice = nullptr; + /* + * First set member has no ASEs, no operations on control point are expected + * 0 + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(0); + auto expected_devices_written = 0; while (leAudioDevice) { - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); expected_devices_written++; + lastDevice = leAudioDevice; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); + /* + * Second device will be configured for Streaming. Expecting 3 operations: + * 1. Codec Config + * 2. QoS Config + * 3. Enable + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(3); + // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, @@ -1813,42 +2125,67 @@ TEST_F(StateMachineTest, testStreamMultiple) { ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testUpdateMetadataMultiple) { +TEST_F(StateMachineTest, + testStreamMultipleMedia_OneMemberHasNoAsesAndNotConnected) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 4; const auto num_devices = 2; - // Prepare multiple fake connected devices in a group + // Prepare multiple fake connected devices in a group. This time one device + // has 0 Ases auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices, + types::AudioContexts(), true); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); + PrepareReceiverStartReadyHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); + /* Check there are two devices*/ auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice = nullptr; + /* + * First set member has no ASEs, no operations on control point are expected + * 0 + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(0); + + /* Device with 0 Ases is disconnected */ + InjectAclDisconnected(group, leAudioDevice); + auto expected_devices_written = 0; while (leAudioDevice) { - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); expected_devices_written++; + lastDevice = leAudioDevice; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); + /* + * Second device will be configured for Streaming. Expecting 3 operations: + * 1. Codec Config + * 2. QoS Config + * 3. Enable + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(3); + // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, @@ -1861,119 +2198,222 @@ TEST_F(StateMachineTest, testUpdateMetadataMultiple) { {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)})); - testing::Mock::VerifyAndClearExpectations(&gatt_queue); - // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); +} - // Make sure all devices get the metadata update - leAudioDevice = group->GetFirstDevice(); - expected_devices_written = 0; +TEST_F(StateMachineTest, testStreamMultipleConversational) { + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 4; + const auto num_devices = 2; + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareReceiverStartReadyHandler(group); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + + InjectInitialIdleNotification(group); + + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; while (leAudioDevice) { EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(1); + .Times(4); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); - const auto metadata_context_type = - kContextTypeMedia | kContextTypeSoundEffects; + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); + + // Start the configuration and stream Media content ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, - {.sink = metadata_context_type, .source = metadata_context_type})); + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); - /* This is just update metadata - watchdog is not used */ - ASSERT_EQ(0, get_func_call_count("alarm_cancel")); + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testDisableSingle) { - /* Device is banded headphones with 2x snk + 0x src ase - * (2xunidirectional CIS) - */ - additional_snk_ases = 1; - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; +MATCHER_P(dataPathDirIsEq, expected, "") { + return (arg.data_path_dir == expected); +} - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); +TEST_F(StateMachineTest, testFailedStreamMultipleConversational) { + /* Testing here CIS Failed to be established */ + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 4; + const auto num_devices = 2; + overwrite_cis_status_ = true; - /* Ringtone context plus additional ASE with channel count 1 - * gives us 2 ASE which should have been configured. - */ - PrepareConfigureCodecHandler(group, 2); - PrepareConfigureQosHandler(group, 2); - PrepareEnableHandler(group, 2); - PrepareDisableHandler(group, 2); + cis_status_.resize(2); + cis_status_[0] = 0x00; + cis_status_[1] = 0x0e; // Failed to be established - auto* leAudioDevice = group->GetFirstDevice(); - EXPECT_CALL(gatt_queue, - WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(4); + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareReceiverStartReadyHandler(group); + PrepareReleaseHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); + + /* Bidirectional CIS data path is configured in tw ocalls and removed for both + * directions with a single call. + */ + EXPECT_CALL(*mock_iso_manager_, + SetupIsoDataPath( + _, dataPathDirIsEq( + bluetooth::hci::iso_manager::kIsoDataPathDirectionIn))) + .Times(1); + EXPECT_CALL( + *mock_iso_manager_, + SetupIsoDataPath( + _, dataPathDirIsEq( + bluetooth::hci::iso_manager::kIsoDataPathDirectionOut))) + .Times(1); EXPECT_CALL( *mock_iso_manager_, RemoveIsoDataPath( - _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput)) - .Times(2); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput | + bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput)) + .Times(1); + + /* This check is the major one in this test, as we want to make sure, + * it will not be called twice but only once (when both bidirectional ASEs are + * not in the STREAMING or ENABLING state) + */ + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); + + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); + auto* leAudioDevice = group->GetFirstDevice(); + + /* First device Control Point actions + * Codec Config + * QoS Config + * Enable + * Receiver ready + * Release + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(5); + leAudioDevice = group->GetNextDevice(leAudioDevice); + + /* Second device Control Point actions + * Codec Config + * QoS Config + * Enable (failed on CIS established - therefore no Receiver Ready) + * Release + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(4); + + /* Prepare DisconnectCis mock to not symulate CisDisconnection */ + ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + .source = types::AudioContexts(context_type)})); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); + /* Called twice. One when change target state from Streaming to IDLE, + * and second time, when state machine entered IDLE. + */ + ASSERT_EQ(2, get_func_call_count("alarm_cancel")); +} - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::SUSPENDING)); - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::SUSPENDED)); +TEST_F(StateMachineTest, testAttachToStreamWhileFirstDeviceIsStartingStream) { + /* Testing here CIS Failed to be established */ + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 4; + const auto num_devices = 2; - // Suspend the stream - LeAudioGroupStateMachine::Get()->SuspendStream(group); + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); - // Check if group has transition to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group, 0, true /* inject enabling */, + false /* inject streaming*/); + PrepareReleaseHandler(group); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + InjectInitialIdleNotification(group); + auto firstDevice = group->GetFirstDevice(); + auto lastDevice = group->GetNextDevice(firstDevice); + + /* Disconnect first device */ + InjectAclDisconnected(group, firstDevice); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + // Now, group is not yet in the streaming state. Let's simulated the other + // device got connected + firstDevice->conn_id_ = 1; + firstDevice->SetConnectionState(DeviceConnectState::CONNECTED); + + for (auto& ase : lastDevice->ases_) { + std::vector params{}; + if (ase.active) { + InjectAseStateNotification(&ase, lastDevice, group, + ascs::kAseStateStreaming, ¶ms); + } + } + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); } -TEST_F(StateMachineTest, testDisableMultiple) { - const auto context_type = kContextTypeMedia; +TEST_F(StateMachineTest, testFailedStreamCreation) { + /* Testing here different error than CIS Failed to be established */ + const auto context_type = kContextTypeConversational; const auto leaudio_group_id = 4; const auto num_devices = 2; @@ -1984,297 +2424,237 @@ TEST_F(StateMachineTest, testDisableMultiple) { PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); - PrepareEnableHandler(group); - PrepareDisableHandler(group); - - auto* leAudioDevice = group->GetFirstDevice(); - auto expected_devices_written = 0; - while (leAudioDevice) { - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(4)); - expected_devices_written++; - leAudioDevice = group->GetNextDevice(leAudioDevice); - } - ASSERT_EQ(expected_devices_written, num_devices); + PrepareEnableHandler(group, 0, true /* inject enabling */, + false /* inject streaming*/); + PrepareReleaseHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); - EXPECT_CALL( - *mock_iso_manager_, - RemoveIsoDataPath( - _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput)) - .Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + + /* Prepare DisconnectCis mock to not symulate CisDisconnection */ + ON_CALL(*mock_iso_manager_, EstablishCis).WillByDefault(Return()); InjectInitialIdleNotification(group); + auto* leAudioDevice = group->GetFirstDevice(); + + /* First device Control Point actions + * Codec Config + * QoS Config + * Enable + * Release + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(4); + leAudioDevice = group->GetNextDevice(leAudioDevice); + + /* Second device Control Point actions + * Codec Config + * QoS Config + * Enable (failed on CIS established - therefore no Receiver Ready) + * Release + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(4); + // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); - - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); + .source = types::AudioContexts(context_type)})); - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::SUSPENDING)); - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::SUSPENDED)); + bluetooth::hci::iso_manager::cis_establish_cmpl_evt evt; + evt.status = HCI_ERR_LMP_RESPONSE_TIMEOUT; - // Suspend the stream - LeAudioGroupStateMachine::Get()->SuspendStream(group); + LeAudioGroupStateMachine::Get()->ProcessHciNotifCisEstablished( + group, leAudioDevice, &evt); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); -} + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); -TEST_F(StateMachineTest, testDisableBidirectional) { - /* Device is banded headphones with 2x snk + 1x src ase - * (1x bidirectional + 1xunidirectional CIS) + /* Called twice. One when change target state from Streaming to IDLE, + * and second time, when state machine entered IDLE. */ - additional_snk_ases = 1; - const auto context_type = kContextTypeConversational; - const int leaudio_group_id = 4; + ASSERT_EQ(2, get_func_call_count("alarm_cancel")); +} - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); +TEST_F(StateMachineTest, remoteRejectsEnable) { + /* Testing here CIS Failed to be established */ + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 4; + const auto num_devices = 2; - /* Since we prepared device with Conversional context in mind, Sink and Source - * ASEs should have been configured. - */ - PrepareConfigureCodecHandler(group, 3); - PrepareConfigureQosHandler(group, 3); - PrepareEnableHandler(group, 3); - PrepareDisableHandler(group, 3); - PrepareReceiverStartReady(group, 1); - PrepareReceiverStopReady(group, 1); + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); - auto* leAudioDevice = group->GetFirstDevice(); - EXPECT_CALL(gatt_queue, - WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(4)); + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareCtpNotificationError( + group, client_parser::ascs::kCtpOpcodeEnable, + client_parser::ascs::kCtpResponseCodeUnspecifiedError, + client_parser::ascs::kCtpResponseNoReason); + PrepareReleaseHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); - bool removed_bidirectional = false; - bool removed_unidirectional = false; + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); - /* Check data path removal */ - ON_CALL(*mock_iso_manager_, RemoveIsoDataPath) - .WillByDefault(Invoke([&removed_bidirectional, &removed_unidirectional, - this](uint16_t conn_handle, - uint8_t data_path_dir) { - /* Set flags for verification */ - if (data_path_dir == - (bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput | - bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput)) { - removed_bidirectional = true; - } else if (data_path_dir == bluetooth::hci::iso_manager:: - kRemoveIsoDataPathDirectionInput) { - removed_unidirectional = true; - } + InjectInitialIdleNotification(group); - /* Copied from default handler of RemoveIsoDataPath*/ - auto dev_it = - std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(), - [&conn_handle](auto& dev) { - auto ases = dev->GetAsesByCisConnHdl(conn_handle); - return (ases.sink || ases.source); - }); - if (dev_it == le_audio_devices_.end()) { - return; - } + auto* leAudioDevice = group->GetFirstDevice(); - for (auto& kv_pair : le_audio_device_groups_) { - auto& group = kv_pair.second; - if (group->IsDeviceInTheGroup(dev_it->get())) { - LeAudioGroupStateMachine::Get()->ProcessHciNotifRemoveIsoDataPath( - group.get(), dev_it->get(), 0, conn_handle); - return; - } - } - /* End of copy */ - })); + /* First device Control Point actions + * Codec Config + * QoS Config + * Enable + * Release + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(4); + leAudioDevice = group->GetNextDevice(leAudioDevice); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + /* Second device Control Point actions + * Codec Config + * QoS Config + * Release + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(3); // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); - - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); - - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::SUSPENDING)); - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::SUSPENDED)); - - // Suspend the stream - LeAudioGroupStateMachine::Get()->SuspendStream(group); + .source = types::AudioContexts(context_type)})); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); - ASSERT_EQ(removed_bidirectional, true); - ASSERT_EQ(removed_unidirectional, true); - - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(2, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testReleaseSingle) { - /* Device is banded headphones with 1x snk + 0x src ase - * (1xunidirectional CIS) with channel count 2 (for stereo) - */ - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; - - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); +TEST_F(StateMachineTest, testStreamMultiple) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 4; + const auto num_devices = 2; - /* Since we prepared device with Ringtone context in mind, only one ASE - * should have been configured. - */ - PrepareConfigureCodecHandler(group, 1); - PrepareConfigureQosHandler(group, 1); - PrepareEnableHandler(group, 1); - PrepareDisableHandler(group, 1); - PrepareReleaseHandler(group, 1); + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); - auto* leAudioDevice = group->GetFirstDevice(); - EXPECT_CALL(gatt_queue, - WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(4); + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::IDLE)); + bluetooth::le_audio::GroupStreamStatus::STREAMING)); - // Stop the stream - LeAudioGroupStateMachine::Get()->StopStream(group); + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testReleaseCachingSingle) { - /* Device is banded headphones with 1x snk + 0x src ase - * (1xunidirectional CIS) - */ - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; +TEST_F(StateMachineTest, testUpdateMetadataMultiple) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 4; + const auto num_devices = 2; - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + auto supported_contexts = + types::AudioContexts(kContextTypeMedia | kContextTypeSoundEffects); - /* Since we prepared device with Ringtone context in mind, only one ASE - * should have been configured. - */ - PrepareConfigureCodecHandler(group, 1, true); - PrepareConfigureQosHandler(group, 1); - PrepareEnableHandler(group, 1); - PrepareDisableHandler(group, 1); - PrepareReleaseHandler(group, 1); + // Prepare multiple fake connected devices in a group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, + num_devices, supported_contexts); + ASSERT_EQ(group->Size(), num_devices); - auto* leAudioDevice = group->GetFirstDevice(); - EXPECT_CALL(gatt_queue, - WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(4); + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); - EXPECT_CALL( - mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + .source = types::AudioContexts(context_type)})); + + testing::Mock::VerifyAndClearExpectations(&gatt_queue); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), @@ -2283,81 +2663,82 @@ TEST_F(StateMachineTest, testReleaseCachingSingle) { ASSERT_EQ(1, get_func_call_count("alarm_cancel")); reset_mock_function_count_map(); - // Stop the stream - LeAudioGroupStateMachine::Get()->StopStream(group); + // Make sure all devices get the metadata update + leAudioDevice = group->GetFirstDevice(); + expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(1); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); + const auto metadata_context_type = + kContextTypeMedia | kContextTypeSoundEffects; + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = metadata_context_type, .source = metadata_context_type})); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + /* This is just update metadata - watchdog is not used */ + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, - testStreamCaching_NoReconfigurationNeeded_SingleDevice) { - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; +TEST_F(StateMachineTest, testUpdateMetadataMultiple_NoUpdatesOnKeyTouch) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 4; + const auto num_devices = 2; - additional_snk_ases = 2; - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + /* Only Media is supported and available, */ + auto supported_contexts = types::AudioContexts(kContextTypeMedia); - /* Since we prepared device with Ringtone context in mind and with no Source - * ASEs, therefor only one ASE should have been configured. - */ - PrepareConfigureCodecHandler(group, 1, true); - PrepareConfigureQosHandler(group, 1, true); - PrepareEnableHandler(group, 1); - PrepareDisableHandler(group, 1); - PrepareReleaseHandler(group, 1); + // Prepare multiple fake connected devices in a group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, + num_devices, supported_contexts); + ASSERT_EQ(group->Size(), num_devices); - /* Ctp messages we expect: - * 1. Codec Config - * 2. QoS Config - * 3. Enable - * 4. Release - * 5. QoS Config (because device stays in Configured state) - * 6. Enable - */ - auto* leAudioDevice = group->GetFirstDevice(); - EXPECT_CALL(gatt_queue, - WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(6); + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); - EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); - - EXPECT_CALL( - mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); - - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)) - .Times(2); + bluetooth::le_audio::GroupStreamStatus::STREAMING)); - // Start the configuration and stream Ringtone content - LeAudioGroupStateMachine::Get()->StartStream( + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + .source = types::AudioContexts(context_type)})); + + testing::Mock::VerifyAndClearExpectations(&gatt_queue); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), @@ -2366,105 +2747,74 @@ TEST_F(StateMachineTest, ASSERT_EQ(1, get_func_call_count("alarm_cancel")); reset_mock_function_count_map(); - // Stop the stream - LeAudioGroupStateMachine::Get()->StopStream(group); - - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); - - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); + // Make sure all devices get the metadata update + leAudioDevice = group->GetFirstDevice(); + expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(0); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + const auto metadata_context_type = + kContextTypeMedia | kContextTypeSoundEffects; + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); - - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + {.sink = metadata_context_type, .source = metadata_context_type})); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); + /* This is just update metadata - watchdog is not used */ + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, - test_StreamCaching_ReconfigureForContextChange_SingleDevice) { - auto context_type = kContextTypeConversational; +TEST_F(StateMachineTest, testDisableSingle) { + /* Device is banded headphones with 2x snk + 0x src ase + * (2xunidirectional CIS) + */ + additional_snk_ases = 1; + const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; - additional_snk_ases = 2; - /* Prepare fake connected device group with update of Media and Conversational - * contexts - */ - auto* group = PrepareSingleTestDeviceGroup( - leaudio_group_id, context_type, 1, - kContextTypeConversational | kContextTypeMedia); + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - /* Don't validate ASE here, as after reconfiguration different ASE number - * will be used. - * For the first configuration (CONVERSTATIONAL) there will be 2 ASEs (Sink - * and Source) After reconfiguration (MEDIA) there will be single ASE. + /* Ringtone context plus additional ASE with channel count 1 + * gives us 2 ASE which should have been configured. */ - PrepareConfigureCodecHandler(group, 0, true); - PrepareConfigureQosHandler(group, 0, true); - PrepareEnableHandler(group); - PrepareReceiverStartReady(group); - PrepareReleaseHandler(group); + PrepareConfigureCodecHandler(group, 2); + PrepareConfigureQosHandler(group, 2); + PrepareEnableHandler(group, 2); + PrepareDisableHandler(group, 2); - /* Ctp messages we expect: - * 1. Codec Config - * 2. QoS Config - * 3. Enable - * 4. Release - * 5. Codec Config - * 6. QoS Config - * 7. Enable - */ auto* leAudioDevice = group->GetFirstDevice(); EXPECT_CALL(gatt_queue, WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(8); - - EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); - - /* 2 times for first configuration (1 Sink, 1 Source), 1 time for second - * configuration (1 Sink)*/ - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); + .Times(4); - uint8_t value = - bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput | - bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput; - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, value)).Times(1); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL( + *mock_iso_manager_, + RemoveIsoDataPath( + _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput)) + .Times(2); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); - // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); - - EXPECT_CALL( - mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); - - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)) - .Times(2); + bluetooth::le_audio::GroupStreamStatus::STREAMING)); - // Start the configuration and stream Conversational content + // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), @@ -2474,35 +2824,34 @@ TEST_F(StateMachineTest, ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); reset_mock_function_count_map(); - // Stop the stream - LeAudioGroupStateMachine::Get()->StopStream(group); - - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); - - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::SUSPENDING)); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::SUSPENDED)); - // Start the configuration and stream Media content - context_type = kContextTypeMedia; - LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + // Suspend the stream + LeAudioGroupStateMachine::Get()->SuspendStream(group); - // Check if group has transitioned to a proper state + // Check if group has transition to a proper state ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); + + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testReleaseMultiple) { +TEST_F(StateMachineTest, testDisableMultiple) { const auto context_type = kContextTypeMedia; - const auto leaudio_group_id = 6; + const auto leaudio_group_id = 4; const auto num_devices = 2; // Prepare multiple fake connected devices in a group @@ -2514,7 +2863,6 @@ TEST_F(StateMachineTest, testReleaseMultiple) { PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); - PrepareReleaseHandler(group); auto* leAudioDevice = group->GetFirstDevice(); auto expected_devices_written = 0; @@ -2532,17 +2880,16 @@ TEST_F(StateMachineTest, testReleaseMultiple) { EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); + EXPECT_CALL( + *mock_iso_manager_, + RemoveIsoDataPath( + _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput)) + .Times(2); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)) - .Times(1); - // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream( group, context_type, @@ -2552,7 +2899,6 @@ TEST_F(StateMachineTest, testReleaseMultiple) { // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); reset_mock_function_count_map(); @@ -2560,67 +2906,94 @@ TEST_F(StateMachineTest, testReleaseMultiple) { EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::IDLE)); - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)) - .Times(0); + bluetooth::le_audio::GroupStreamStatus::SUSPENDING)); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::SUSPENDED)); - // Stop the stream - LeAudioGroupStateMachine::Get()->StopStream(group); + // Suspend the stream + LeAudioGroupStateMachine::Get()->SuspendStream(group); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testReleaseMultiple_DeviceDisconnectedDuringRelease) { - const auto context_type = kContextTypeMedia; - const auto leaudio_group_id = 6; - const auto num_devices = 2; - - // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); - ASSERT_EQ(group->Size(), num_devices); +TEST_F(StateMachineTest, testDisableBidirectional) { + /* Device is banded headphones with 2x snk + 1x src ase + * (1x bidirectional + 1xunidirectional CIS) + */ + additional_snk_ases = 1; + const auto context_type = kContextTypeConversational; + const int leaudio_group_id = 4; - PrepareConfigureCodecHandler(group); - PrepareConfigureQosHandler(group); - PrepareEnableHandler(group); - PrepareDisableHandler(group); + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - /* Here we inject device disconnection during release */ - PrepareReleaseHandler(group, 0, true); + /* Since we prepared device with Conversional context in mind, Sink and Source + * ASEs should have been configured. + */ + PrepareConfigureCodecHandler(group, 3); + PrepareConfigureQosHandler(group, 3); + PrepareEnableHandler(group, 3); + PrepareDisableHandler(group, 3); + PrepareReceiverStartReadyHandler(group, 1); + PrepareReceiverStopReady(group, 1); auto* leAudioDevice = group->GetFirstDevice(); - auto expected_devices_written = 0; - while (leAudioDevice) { - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(4)); - expected_devices_written++; - leAudioDevice = group->GetNextDevice(leAudioDevice); - } - ASSERT_EQ(expected_devices_written, num_devices); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(4)); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); + bool removed_bidirectional = false; + bool removed_unidirectional = false; - InjectInitialIdleNotification(group); + /* Check data path removal */ + ON_CALL(*mock_iso_manager_, RemoveIsoDataPath) + .WillByDefault(Invoke([&removed_bidirectional, &removed_unidirectional, + this](uint16_t conn_handle, + uint8_t data_path_dir) { + /* Set flags for verification */ + if (data_path_dir == + (bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput | + bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput)) { + removed_bidirectional = true; + } else if (data_path_dir == bluetooth::hci::iso_manager:: + kRemoveIsoDataPathDirectionInput) { + removed_unidirectional = true; + } - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)) - .Times(1); + /* Copied from default handler of RemoveIsoDataPath*/ + auto dev_it = + std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(), + [&conn_handle](auto& dev) { + auto ases = dev->GetAsesByCisConnHdl(conn_handle); + return (ases.sink || ases.source); + }); + if (dev_it == le_audio_devices_.end()) { + return; + } + + for (auto& kv_pair : le_audio_device_groups_) { + auto& group = kv_pair.second; + if (group->IsDeviceInTheGroup(dev_it->get())) { + LeAudioGroupStateMachine::Get()->ProcessHciNotifRemoveIsoDataPath( + group.get(), dev_it->get(), 0, conn_handle); + return; + } + } + /* End of copy */ + })); + + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream( @@ -2635,63 +3008,61 @@ TEST_F(StateMachineTest, testReleaseMultiple_DeviceDisconnectedDuringRelease) { ASSERT_EQ(1, get_func_call_count("alarm_cancel")); reset_mock_function_count_map(); - testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::IDLE)); - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)) - .Times(0); - - // Stop the stream - LeAudioGroupStateMachine::Get()->StopStream(group); + bluetooth::le_audio::GroupStreamStatus::SUSPENDING)); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::SUSPENDED)); - testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + // Suspend the stream + LeAudioGroupStateMachine::Get()->SuspendStream(group); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); + ASSERT_EQ(removed_bidirectional, true); + ASSERT_EQ(removed_unidirectional, true); + + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testReleaseBidirectional) { - /* Device is banded headphones with 2x snk + 1x src ase - * (1x bidirectional + 1xunidirectional CIS) +TEST_F(StateMachineTest, testReleaseSingle) { + /* Device is banded headphones with 1x snk + 0x src ase + * (1xunidirectional CIS) with channel count 2 (for stereo) */ - additional_snk_ases = 1; - const auto context_type = kContextTypeConversational; - const auto leaudio_group_id = 6; + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - /* Since we prepared device with Conversional context in mind, Sink and Source - * ASEs should have been configured. + /* Since we prepared device with Ringtone context in mind, only one ASE + * should have been configured. */ - PrepareConfigureCodecHandler(group, 3); - PrepareConfigureQosHandler(group, 3); - PrepareEnableHandler(group, 3); - PrepareDisableHandler(group, 3); - PrepareReceiverStartReady(group, 1); - PrepareReleaseHandler(group, 3); + PrepareConfigureCodecHandler(group, 1); + PrepareConfigureQosHandler(group, 1); + PrepareEnableHandler(group, 1); + PrepareDisableHandler(group, 1); + PrepareReleaseHandler(group, 1); auto* leAudioDevice = group->GetFirstDevice(); EXPECT_CALL(gatt_queue, WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(4)); + .Times(4); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); @@ -2705,9 +3076,16 @@ TEST_F(StateMachineTest, testReleaseBidirectional) { // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); reset_mock_function_count_map(); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)); // Stop the stream LeAudioGroupStateMachine::Get()->StopStream(group); @@ -2715,682 +3093,2467 @@ TEST_F(StateMachineTest, testReleaseBidirectional) { // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); } -TEST_F(StateMachineTest, testDisableAndReleaseBidirectional) { - /* Device is banded headphones with 2x snk + 1x src ase - * (1x bidirectional + 1xunidirectional CIS) +TEST_F(StateMachineTest, testReleaseCachingSingle) { + /* Device is banded headphones with 1x snk + 0x src ase + * (1xunidirectional CIS) */ - additional_snk_ases = 1; - const auto context_type = kContextTypeConversational; + const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - /* Since we prepared device with Conversional context in mind, Sink and Source - * ASEs should have been configured. + /* Since we prepared device with Ringtone context in mind, only one ASE + * should have been configured. */ - PrepareConfigureCodecHandler(group, 3); - PrepareConfigureQosHandler(group, 3); - PrepareEnableHandler(group, 3); - PrepareDisableHandler(group, 3); - PrepareReceiverStartReady(group, 1); - PrepareReceiverStopReady(group, 1); - PrepareReleaseHandler(group, 3); + PrepareConfigureCodecHandler(group, 1, true); + PrepareConfigureQosHandler(group, 1); + PrepareEnableHandler(group, 1); + PrepareDisableHandler(group, 1); + PrepareReleaseHandler(group, 1); auto* leAudioDevice = group->GetFirstDevice(); EXPECT_CALL(gatt_queue, WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(4)); + .Times(4); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + InjectInitialIdleNotification(group); + + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); + // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)}); - // Suspend the stream - LeAudioGroupStateMachine::Get()->SuspendStream(group); + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); // Stop the stream LeAudioGroupStateMachine::Get()->StopStream(group); // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); -} + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); +} + +TEST_F(StateMachineTest, + testStreamCaching_NoReconfigurationNeeded_SingleDevice) { + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; + + additional_snk_ases = 2; + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Ringtone context in mind and with no Source + * ASEs, therefor only one ASE should have been configured. + */ + PrepareConfigureCodecHandler(group, 1, true); + PrepareConfigureQosHandler(group, 1, true); + PrepareEnableHandler(group, 1); + PrepareDisableHandler(group, 1); + PrepareReleaseHandler(group, 1); + + /* Ctp messages we expect: + * 1. Codec Config + * 2. QoS Config + * 3. Enable + * 4. Release + * 5. QoS Config (because device stays in Configured state) + * 6. Enable + */ + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(6); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + + InjectInitialIdleNotification(group); + + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(2); + + // Start the configuration and stream Ringtone content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); +} + +TEST_F(StateMachineTest, + test_StreamCaching_ReconfigureForContextChange_SingleDevice) { + auto context_type = kContextTypeConversational; + const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; + + additional_snk_ases = 2; + /* Prepare fake connected device group with update of Media and Conversational + * contexts + */ + auto* group = PrepareSingleTestDeviceGroup( + leaudio_group_id, context_type, 1, + kContextTypeConversational | kContextTypeMedia); + + /* Don't validate ASE here, as after reconfiguration different ASE number + * will be used. + * For the first configuration (CONVERSTATIONAL) there will be 2 ASEs (Sink + * and Source) After reconfiguration (MEDIA) there will be single ASE. + */ + PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureQosHandler(group, 0, true); + PrepareEnableHandler(group); + PrepareReceiverStartReadyHandler(group); + PrepareReleaseHandler(group); + + /* Ctp messages we expect: + * 1. Codec Config + * 2. QoS Config + * 3. Enable + * 4. Release + * 5. Codec Config + * 6. QoS Config + * 7. Enable + */ + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(8); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); + + /* 2 times for first configuration (1 Sink, 1 Source), 1 time for second + * configuration (1 Sink)*/ + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); + + uint8_t value = + bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput | + bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput; + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, value)).Times(1); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + + InjectInitialIdleNotification(group); + + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(2); + + // Start the configuration and stream Conversational content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + // Start the configuration and stream Media content + context_type = kContextTypeMedia; + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); +} + +TEST_F(StateMachineTest, testReleaseMultiple) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(4)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + + InjectInitialIdleNotification(group); + + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(1); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(0); + + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); +} + +TEST_F(StateMachineTest, testReleaseMultiple_DeviceDisconnectedDuringRelease) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + + /* Here we inject device disconnection during release */ + PrepareReleaseHandler(group, 0, true); + + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(4)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + + InjectInitialIdleNotification(group); + + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(1); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(0); + + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); + + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); +} + +TEST_F(StateMachineTest, testReleaseBidirectional) { + /* Device is banded headphones with 2x snk + 1x src ase + * (1x bidirectional + 1xunidirectional CIS) + */ + additional_snk_ases = 1; + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 6; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Conversional context in mind, Sink and Source + * ASEs should have been configured. + */ + PrepareConfigureCodecHandler(group, 3); + PrepareConfigureQosHandler(group, 3); + PrepareEnableHandler(group, 3); + PrepareDisableHandler(group, 3); + PrepareReceiverStartReadyHandler(group, 1); + PrepareReleaseHandler(group, 3); + + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(4)); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); +} + +TEST_F(StateMachineTest, testDisableAndReleaseBidirectional) { + /* Device is banded headphones with 2x snk + 1x src ase + * (1x bidirectional + 1xunidirectional CIS) + */ + additional_snk_ases = 1; + const auto context_type = kContextTypeConversational; + const int leaudio_group_id = 4; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Conversional context in mind, Sink and Source + * ASEs should have been configured. + */ + PrepareConfigureCodecHandler(group, 3); + PrepareConfigureQosHandler(group, 3); + PrepareEnableHandler(group, 3); + PrepareDisableHandler(group, 3); + PrepareReceiverStartReadyHandler(group, 1); + PrepareReceiverStopReady(group, 1); + PrepareReleaseHandler(group, 3); + + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(4)); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Suspend the stream + LeAudioGroupStateMachine::Get()->SuspendStream(group); + + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); +} TEST_F(StateMachineTest, testAseIdAssignmentIdle) { const auto context_type = kContextTypeConversational; const auto leaudio_group_id = 6; - const auto num_devices = 1; + const auto num_devices = 1; + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + // Should not trigger any action on our side + EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + + for (auto* device = group->GetFirstDevice(); device != nullptr; + device = group->GetNextDevice(device)) { + for (auto& ase : device->ases_) { + ASSERT_EQ(ase.id, le_audio::types::ase::kAseIdInvalid); + InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, + nullptr); + ASSERT_EQ(ase.id, ase_id_last_assigned); + } + } +} + +TEST_F(StateMachineTest, testAseIdAssignmentCodecConfigured) { + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 6; + const auto num_devices = 1; + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + // Should not trigger any action on our side + EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + + for (auto* device = group->GetFirstDevice(); device != nullptr; + device = group->GetNextDevice(device)) { + for (auto& ase : device->ases_) { + client_parser::ascs::ase_codec_configured_state_params + codec_configured_state_params; + + ASSERT_EQ(ase.id, le_audio::types::ase::kAseIdInvalid); + InjectAseStateNotification(&ase, device, group, + ascs::kAseStateCodecConfigured, + &codec_configured_state_params); + ASSERT_EQ(ase.id, ase_id_last_assigned); + } + } +} + +TEST_F(StateMachineTest, testAseAutonomousRelease) { + /* Device is banded headphones with 2x snk + 1x src ase + * (1x bidirectional + 1xunidirectional CIS) + */ + additional_snk_ases = 1; + const auto context_type = kContextTypeConversational; + const int leaudio_group_id = 4; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Conversional context in mind, Sink and Source + * ASEs should have been configured. + */ + PrepareConfigureCodecHandler(group, 3); + PrepareConfigureQosHandler(group, 3); + PrepareEnableHandler(group, 3); + PrepareDisableHandler(group, 3); + PrepareReceiverStartReadyHandler(group, 1); + PrepareReceiverStopReady(group, 1); + PrepareReleaseHandler(group, 3); + + InjectInitialIdleNotification(group); + + // Validate initial GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + // Validate new GroupStreamStatus + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)) + .Times(AtLeast(1)); + + /* Single disconnect as it is bidirectional Cis*/ + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + for (auto* device = group->GetFirstDevice(); device != nullptr; + device = group->GetNextDevice(device)) { + for (auto& ase : device->ases_) { + client_parser::ascs::ase_codec_configured_state_params + codec_configured_state_params; + + ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Each one does the autonomous release + InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, + &codec_configured_state_params); + InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, + &codec_configured_state_params); + } + } + + // Verify we've handled the release and updated all states + for (auto* device = group->GetFirstDevice(); device != nullptr; + device = group->GetNextDevice(device)) { + for (auto& ase : device->ases_) { + ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + } + } + + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); +} + +TEST_F(StateMachineTest, testAseAutonomousRelease2Devices) { + const auto context_type = kContextTypeConversational; + const int leaudio_group_id = 4; + const int num_of_devices = 2; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, + num_of_devices); + + /* Since we prepared device with Conversional context in mind, Sink and Source + * ASEs should have been configured. + */ + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReceiverStartReadyHandler(group); + PrepareReceiverStopReady(group); + PrepareReleaseHandler(group); + + InjectInitialIdleNotification(group); + + // Validate initial GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + // Check streaming will continue + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)) + .Times(0); + + /* Single disconnect as it is bidirectional Cis*/ + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); + + auto device = group->GetFirstDevice(); + for (auto& ase : device->ases_) { + client_parser::ascs::ase_codec_configured_state_params + codec_configured_state_params; + + ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Simulate autonomus release for one device. + InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, + &codec_configured_state_params); + InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, + &codec_configured_state_params); + } +} + +TEST_F(StateMachineTest, testHandlingCachedCodecConfig2Devices) { + const auto context_type = kContextTypeConversational; + const int leaudio_group_id = 4; + const int num_of_devices = 2; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, + num_of_devices); + + auto* firstDevice = group->GetFirstDevice(); + auto* secondDevice = group->GetNextDevice(firstDevice); + + /* Since we prepared device with Conversional context in mind, Sink and Source + * ASEs should have been configured. + */ + PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReceiverStartReadyHandler(group); + PrepareReceiverStopReady(group); + PrepareReleaseHandler(group); + + stay_in_releasing_state_ = true; + + /* Number of control point calls + * 1. Codec Config + * 2. QoS Config + * 3. Enable + * 4. Receiver Start Ready + * 5. Release*/ + EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_, + firstDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(5); + + EXPECT_CALL(gatt_queue, WriteCharacteristic(secondDevice->conn_id_, + secondDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(5); + + InjectInitialIdleNotification(group); + + // Validate initial GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + + /* Two disconnect as it is two bidirectional Cises */ + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); + + // Validate initial GroupStreamStatus + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)) + .Times(1); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)) + .Times(0); + + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); + + for (auto& ase : firstDevice->ases_) { + LOG_DEBUG("%s , %d, %s", ADDRESS_TO_LOGGABLE_CSTR(firstDevice->address_), + ase.id, bluetooth::common::ToString(ase.state).c_str()); + ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); + // Simulate autonomus configured state. + InjectAseStateNotification(&ase, firstDevice, group, + ascs::kAseStateCodecConfigured, + &cached_codec_configuration_map_[ase.id]); + } + + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + + /* When ALL devices got inactive, we should got the proper group status */ + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)) + .Times(1); + for (auto& ase : secondDevice->ases_) { + LOG_DEBUG("%s , %d, %s", ADDRESS_TO_LOGGABLE_CSTR(firstDevice->address_), + ase.id, bluetooth::common::ToString(ase.state).c_str()); + ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); + // Simulate autonomus configured state. + InjectAseStateNotification(&ase, secondDevice, group, + ascs::kAseStateCodecConfigured, + &cached_codec_configuration_map_[ase.id]); + } + + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); +} + +TEST_F(StateMachineTest, testStateTransitionTimeoutOnIdleState) { + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(1); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + // Disconnect device + // in client.cc before this function is called, state of device is changed. + leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED); + LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected( + group, leAudioDevice); + + // Make sure timeout is cleared + ASSERT_TRUE(fake_osi_alarm_set_on_mloop_.cb == nullptr); +} + +TEST_F(StateMachineTest, testStateIdleNotifyAclDisconnectedRemoveCig) { + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 4; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + group->cig.SetState(types::CigState::CREATED); + + // Assert current state + ASSERT_TRUE(group->GetState() == + types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_FALSE(group->IsInTransition()); + ASSERT_TRUE(group->cig.GetState() == types::CigState::CREATED); + + // Expect RemoveCig to be called + EXPECT_CALL(*mock_iso_manager_, RemoveCig(group->group_id_, _)).Times(1); + + // Disconnect device + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected( + group, leAudioDevice); + + // Assert Cig state transition to NONE after REMOVING + ASSERT_TRUE(group->cig.GetState() == types::CigState::NONE); +} + +TEST_F(StateMachineTest, testStateTransitionTimeout) { + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Ringtone context in mind, only one ASE + * should have been configured. + */ + PrepareConfigureCodecHandler(group, 1); + PrepareConfigureQosHandler(group, 1); + + auto* leAudioDevice = group->GetFirstDevice(); + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(3); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + // Check if timeout is fired + EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id)); + + // simulate timeout seconds passed, alarm executing + fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); + ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); +} + +MATCHER_P(dataPathIsEq, expected, "") { return (arg.data_path_id == expected); } + +TEST_F(StateMachineTest, testConfigureDataPathForHost) { + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; + + /* Can be called for every context when fetching the configuration from the + * AudioSetConfigurationProvider. + */ + EXPECT_CALL(*mock_codec_manager_, GetCodecLocation()).Times(AtLeast(1)); + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Ringtone context in mind, only one ASE + * should have been configured. + */ + PrepareConfigureCodecHandler(group, 1); + PrepareConfigureQosHandler(group, 1); + PrepareEnableHandler(group, 1); + + EXPECT_CALL( + *mock_iso_manager_, + SetupIsoDataPath( + _, dataPathIsEq(bluetooth::hci::iso_manager::kIsoDataPathHci))) + .Times(1); + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); +} + +TEST_F(StateMachineTestAdsp, testConfigureDataPathForAdsp) { + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 4; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; + + /* Can be called for every context when fetching the configuration from the + * AudioSetConfigurationProvider. + */ + EXPECT_CALL(*mock_codec_manager_, GetCodecLocation()).Times(AtLeast(1)); + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Ringtone context in mind, only one ASE + * should have been configured. + */ + PrepareConfigureCodecHandler(group, 1); + PrepareConfigureQosHandler(group, 1); + PrepareEnableHandler(group, 1); + + EXPECT_CALL( + *mock_iso_manager_, + SetupIsoDataPath( + _, dataPathIsEq( + bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault))) + .Times(1); + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); +} + +TEST_F(StateMachineTestAdsp, testStreamConfigurationAdspDownMix) { + const auto context_type = kContextTypeConversational; + const int leaudio_group_id = 4; + const int num_devices = 2; + + // Prepare fake connected device group + auto* group = PrepareSingleTestDeviceGroup( + leaudio_group_id, context_type, num_devices, + types::AudioContexts(kContextTypeConversational)); + + EXPECT_CALL(mock_callbacks_, + OnUpdatedCisConfiguration(group->group_id_, + le_audio::types::kLeAudioDirectionSink)) + .Times(1); + EXPECT_CALL(mock_callbacks_, + OnUpdatedCisConfiguration( + group->group_id_, le_audio::types::kLeAudioDirectionSource)) + .Times(1); + + /* Can be called for every context when fetching the configuration from + * the AudioSetConfigurationProvider. + */ + EXPECT_CALL(*mock_codec_manager_, GetCodecLocation()).Times(AtLeast(1)); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareReceiverStartReadyHandler(group); + + InjectInitialIdleNotification(group); + + auto* leAudioDevice = group->GetFirstDevice(); + InjectAclDisconnected(group, leAudioDevice); + + // Start the configuration and stream Media content + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Note: The actual channel mixing is verified by the CodecManager unit tests. +} + +static void InjectCisDisconnected(LeAudioDeviceGroup* group, + LeAudioDevice* leAudioDevice, uint8_t reason, + bool first_cis_disconnect_only = false) { + bluetooth::hci::iso_manager::cis_disconnected_evt event; + + for (auto const ase : leAudioDevice->ases_) { + if (ase.cis_state != types::CisState::ASSIGNED && + ase.cis_state != types::CisState::IDLE) { + event.reason = reason; + event.cig_id = group->group_id_; + event.cis_conn_hdl = ase.cis_conn_hdl; + LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected( + group, leAudioDevice, &event); + if (first_cis_disconnect_only) break; + } + } +} + +TEST_F(StateMachineTest, testAttachDeviceToTheStream) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + LeAudioDevice* fistDevice = leAudioDevice; + + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + InjectAclDisconnected(group, lastDevice); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + lastDevice->conn_id_ = 3; + lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); + + // Make sure ASE with disconnected CIS are not left in STREAMING + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSink, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSource, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + LeAudioGroupStateMachine::Get()->AttachToStream( + group, lastDevice, {.sink = {media_ccid}, .source = {}}); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Verify that the joining device receives the right CCID list + auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; + bool parsedOk = false; + auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), + lastMeta.size(), parsedOk); + ASSERT_TRUE(parsedOk); + + auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); + ASSERT_TRUE(ccids.has_value()); + ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); + + /* Verify that ASE of first device are still good*/ + auto ase = fistDevice->GetFirstActiveAse(); + ASSERT_NE(ase->max_transport_latency, 0); + ASSERT_NE(ase->retrans_nb, 0); +} + +TEST_F(StateMachineTest, testAttachDeviceToTheStreamDeviceNoAvailableContext) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + InjectAclDisconnected(group, lastDevice); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Connect the disconnected device BUT remove MEDIA from available Contex + // Types + lastDevice->conn_id_ = 3; + auto test_context_type = kContextTypeUnspecified | kContextTypeConversational; + lastDevice->SetAvailableContexts( + {.sink = test_context_type, .source = test_context_type}); + lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); + + // Make sure ASE with disconnected CIS are not left in STREAMING + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSink, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSource, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(0)); + + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); + ASSERT_EQ(LeAudioGroupStateMachine::Get()->AttachToStream( + group, lastDevice, {.sink = {media_ccid}, .source = {}}), + false); + + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); +} + +TEST_F(StateMachineTest, testAutonomousConfiguredAndAttachToStream) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + /* Scenario + * 1. Start streaming + * 2. Stop stream on one device + * 3. Reconnect + * 4. Autonomous Configured state + * 5. Make sure QoS Configure is not send out + * 6. Trigger attach the stream + * 7. Make sure stream is up + */ + + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + LeAudioDevice* fistDevice = leAudioDevice; + + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + InjectAclDisconnected(group, lastDevice); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + /* Set device is getting ready for the connection */ + lastDevice->conn_id_ = 3; + lastDevice->SetConnectionState( + DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY); + + // Make sure ASE with disconnected CIS are not left in STREAMING + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSink, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSource, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + + // Symulate remote autonomous CONFIGURE state + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(0); + + int num_of_notifications = 0; + for (auto& ase : lastDevice->ases_) { + if (ase.id == le_audio::types::ase::kAseIdInvalid) { + continue; + } + LOG_ERROR("ID : %d, status %s", ase.id, + bluetooth::common::ToString(ase.state).c_str()); + num_of_notifications++; + InjectAseStateNotification(&ase, lastDevice, group, + ascs::kAseStateCodecConfigured, + &cached_codec_configuration_map_[ase.id]); + break; + } + ASSERT_EQ(num_of_notifications, 1); + + testing::Mock::VerifyAndClearExpectations(&gatt_queue); + // Now device is connected. Attach it to the stream + + lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); + + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + LeAudioGroupStateMachine::Get()->AttachToStream( + group, lastDevice, {.sink = {media_ccid}, .source = {}}); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Verify that the joining device receives the right CCID list + auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; + bool parsedOk = false; + auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), + lastMeta.size(), parsedOk); + ASSERT_TRUE(parsedOk); + + auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); + ASSERT_TRUE(ccids.has_value()); + ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); + + /* Verify that ASE of first device are still good*/ + auto ase = fistDevice->GetFirstActiveAse(); + ASSERT_NE(ase->max_transport_latency, 0); + ASSERT_NE(ase->retrans_nb, 0); +} + +TEST_F(StateMachineTest, + testAttachDeviceToTheStream_autonomusQoSConfiguredState) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + LeAudioDevice* fistDevice = leAudioDevice; + + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}, + {.sink = std::vector(1, media_ccid), + .source = std::vector(1, media_ccid)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Make sure ASE with disconnected CIS are not left in STREAMING + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSink, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSource, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(1); + + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + + for (auto& ase : lastDevice->ases_) { + if (cached_remote_qos_configuration_for_ase_.count(&ase) > 0) { + InjectAseStateNotification( + &ase, lastDevice, group, ascs::kAseStateQoSConfigured, + &(cached_remote_qos_configuration_for_ase_[&ase])); + } + } + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Verify that the joining device receives the right CCID list + auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; + bool parsedOk = false; + auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), + lastMeta.size(), parsedOk); + ASSERT_TRUE(parsedOk); + + auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); + ASSERT_TRUE(ccids.has_value()); + ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); + + /* Verify that ASE of first device are still good*/ + auto ase = fistDevice->GetFirstActiveAse(); + ASSERT_NE(ase->max_transport_latency, 0); + ASSERT_NE(ase->retrans_nb, 0); +} + +TEST_F(StateMachineTest, testAttachDeviceToTheStreamDoNotAttach) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + + while (leAudioDevice) { + lastDevice = leAudioDevice; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + + InjectInitialIdleNotification(group); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + InjectAclDisconnected(group, lastDevice); + + // Start the configuration and stream Media content + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + lastDevice->conn_id_ = 3; + lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); + + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + LeAudioGroupStateMachine::Get()->StopStream(group); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + + ASSERT_FALSE(LeAudioGroupStateMachine::Get()->AttachToStream( + group, lastDevice, {.sink = {}, .source = {}})); +} + +TEST_F(StateMachineTest, testReconfigureAfterLateDeviceAttached) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + LeAudioDevice* fistDevice = leAudioDevice; + + while (leAudioDevice) { + lastDevice = leAudioDevice; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + + InjectInitialIdleNotification(group); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + InjectAclDisconnected(group, lastDevice); + + /* First device connected. Configure it to stream media */ + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + + types::BidirectionalPair> ccids_list = { + .sink = {media_ccid}, .source = {media_ccid}}; + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}, + ccids_list); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + /* Stop the stream and let first device to stay in configured state (caching + * is on)*/ + LeAudioGroupStateMachine::Get()->StopStream(group); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + + /* Verify state in the configured state */ + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); + + /* Now when stream is stopped, connect second device. */ + lastDevice->conn_id_ = 3; + lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); + + group->UpdateAudioContextAvailability(); + group->UpdateAudioSetConfigurationCache(context_type); + + /* Start stream, make sure 2 devices are started. */ + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}, + ccids_list); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Verify that both devicse receives the right CCID list and both are + // streaming + auto ase = lastDevice->GetFirstActiveAse(); + + // FIXME: No ASE was activated - that's bad + ASSERT_NE(nullptr, ase); + auto lastMeta = ase->metadata; + bool parsedOk = false; + auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), + lastMeta.size(), parsedOk); + ASSERT_TRUE(parsedOk); + + auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); + ASSERT_TRUE(ccids.has_value()); + ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); + + /* Verify that ASE of first device are still good*/ + ase = fistDevice->GetFirstActiveAse(); + ASSERT_NE(nullptr, ase); + ASSERT_NE(ase->max_transport_latency, 0); + ASSERT_NE(ase->retrans_nb, 0); +} + +TEST_F(StateMachineTest, testStreamToGettingReadyDevice) { + const auto context_type = kContextTypeLive; + const auto leaudio_group_id = 666; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + + // Simulate the 2nd device still getting ready + auto* firstDevice = group->GetFirstDevice(); + auto* secondDevice = group->GetNextDevice(firstDevice); + secondDevice->SetConnectionState( + DeviceConnectState::CONNECTED_BY_USER_GETTING_READY); + + group->UpdateAudioContextAvailability(); + group->UpdateAudioSetConfigurationCache(context_type); + + ASSERT_EQ(group->Size(), num_devices); + ASSERT_EQ(1, group->NumOfConnected()); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareReceiverStartReadyHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + // Expect actions only on the already prepared device + EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_, + firstDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + InjectInitialIdleNotification(group); + + // Start the configuration and the stream + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state with one device still + // being in the `CONNECTED_BY_USER_GETTING_READY` state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); +} + +TEST_F(StateMachineTest, testAttachDeviceToTheConversationalStream) { + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareReceiverStartReadyHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + LeAudioDevice* firstDevice = leAudioDevice; + + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + ASSERT_NE(nullptr, firstDevice); + ASSERT_NE(nullptr, lastDevice); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + + EXPECT_CALL(*mock_iso_manager_, + SetupIsoDataPath( + _, dataPathDirIsEq( + bluetooth::hci::iso_manager::kIsoDataPathDirectionIn))) + .Times(2); + + // Make sure the Out data path is set before we declare that we are ready + { + ::testing::InSequence seq; + EXPECT_CALL(*mock_iso_manager_, + SetupIsoDataPath( + UNIQUE_CIS_CONN_HANDLE(leaudio_group_id, 0), + dataPathDirIsEq( + bluetooth::hci::iso_manager::kIsoDataPathDirectionOut))) + .Times(1); + EXPECT_CALL(ase_ctp_handler, + AseCtpReceiverStartReadyHandler(firstDevice, _, _, _)) + .Times(1); + } + { + ::testing::InSequence seq; + EXPECT_CALL(*mock_iso_manager_, + SetupIsoDataPath( + UNIQUE_CIS_CONN_HANDLE(leaudio_group_id, 1), + dataPathDirIsEq( + bluetooth::hci::iso_manager::kIsoDataPathDirectionOut))) + .Times(1); + EXPECT_CALL(ase_ctp_handler, + AseCtpReceiverStartReadyHandler(lastDevice, _, _, _)) + .Times(1); + } + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Conversational content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Verify data path removal on the second bidirectional CIS + EXPECT_CALL( + *mock_iso_manager_, + RemoveIsoDataPath( + UNIQUE_CIS_CONN_HANDLE(leaudio_group_id, 1), + bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput | + bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput)) + .Times(1); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + InjectAclDisconnected(group, lastDevice); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + lastDevice->conn_id_ = 3; + lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); + + // Make sure ASE with disconnected CIS are not left in STREAMING + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSink, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSource, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, + SetupIsoDataPath( + _, dataPathDirIsEq( + bluetooth::hci::iso_manager::kIsoDataPathDirectionIn))) + .Times(1); + // Make sure the Out data path is set before we declare that we are ready + { + ::testing::InSequence seq; + EXPECT_CALL(*mock_iso_manager_, + SetupIsoDataPath( + UNIQUE_CIS_CONN_HANDLE(leaudio_group_id, 1), + dataPathDirIsEq( + bluetooth::hci::iso_manager::kIsoDataPathDirectionOut))) + .Times(1); + EXPECT_CALL(ase_ctp_handler, + AseCtpReceiverStartReadyHandler(lastDevice, _, _, _)) + .Times(1); + } - // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); - ASSERT_EQ(group->Size(), num_devices); + LeAudioGroupStateMachine::Get()->AttachToStream( + group, lastDevice, {.sink = {call_ccid}, .source = {call_ccid}}); - // Should not trigger any action on our side - EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - for (auto* device = group->GetFirstDevice(); device != nullptr; - device = group->GetNextDevice(device)) { - for (auto& ase : device->ases_) { - ASSERT_EQ(ase.id, le_audio::types::ase::kAseIdInvalid); - InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, - nullptr); - ASSERT_EQ(ase.id, ase_id_last_assigned); - } - } + // Verify that the joining device receives the right CCID list + auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; + bool parsedOk = false; + auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), + lastMeta.size(), parsedOk); + ASSERT_TRUE(parsedOk); + + auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); + ASSERT_TRUE(ccids.has_value()); + ASSERT_NE(std::find(ccids->begin(), ccids->end(), call_ccid), ccids->end()); + + /* Verify that ASE of first device are still good*/ + auto ase = firstDevice->GetFirstActiveAse(); + ASSERT_NE(ase->max_transport_latency, 0); + ASSERT_NE(ase->retrans_nb, 0); + + // Make sure ASEs with reconnected CIS are in STREAMING state + ASSERT_TRUE(lastDevice->HaveAllActiveAsesSameState( + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)); } -TEST_F(StateMachineTest, testAseIdAssignmentCodecConfigured) { - const auto context_type = kContextTypeConversational; +TEST_F(StateMachineTest, StartStreamAfterConfigure) { + const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; - const auto num_devices = 1; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); ASSERT_EQ(group->Size(), num_devices); - // Should not trigger any action on our side - EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); - for (auto* device = group->GetFirstDevice(); device != nullptr; - device = group->GetNextDevice(device)) { - for (auto& ase : device->ases_) { - client_parser::ascs::ase_codec_configured_state_params - codec_configured_state_params; + InjectInitialIdleNotification(group); - ASSERT_EQ(ase.id, le_audio::types::ase::kAseIdInvalid); - InjectAseStateNotification(&ase, device, group, - ascs::kAseStateCodecConfigured, - &codec_configured_state_params); - ASSERT_EQ(ase.id, ase_id_last_assigned); - } + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1. Codec configure + * 2: Codec QoS + * 3: Enabling + */ + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(3); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); } -} - -TEST_F(StateMachineTest, testAseAutonomousRelease) { - /* Device is banded headphones with 2x snk + 1x src ase - * (1x bidirectional + 1xunidirectional CIS) - */ - additional_snk_ases = 1; - const auto context_type = kContextTypeConversational; - const int leaudio_group_id = 4; + ASSERT_EQ(expected_devices_written, num_devices); - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + // Validate GroupStreamStatus + EXPECT_CALL(mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER)); - /* Since we prepared device with Conversional context in mind, Sink and Source - * ASEs should have been configured. - */ - PrepareConfigureCodecHandler(group, 3); - PrepareConfigureQosHandler(group, 3); - PrepareEnableHandler(group, 3); - PrepareDisableHandler(group, 3); - PrepareReceiverStartReady(group, 1); - PrepareReceiverStopReady(group, 1); - PrepareReleaseHandler(group, 3); + // Start the configuration and stream Media content + group->SetPendingConfiguration(); + LeAudioGroupStateMachine::Get()->ConfigureStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); - InjectInitialIdleNotification(group); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - // Validate initial GroupStreamStatus + group->ClearPendingConfiguration(); + // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); - - // Validate new GroupStreamStatus - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::IDLE)) - .Times(AtLeast(1)); - - /* Single disconnect as it is bidirectional Cis*/ - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); - - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); - - for (auto* device = group->GetFirstDevice(); device != nullptr; - device = group->GetNextDevice(device)) { - for (auto& ase : device->ases_) { - client_parser::ascs::ase_codec_configured_state_params - codec_configured_state_params; - - ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - - // Each one does the autonomous release - InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, - &codec_configured_state_params); - InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, - &codec_configured_state_params); - } - } - - // Verify we've handled the release and updated all states - for (auto* device = group->GetFirstDevice(); device != nullptr; - device = group->GetNextDevice(device)) { - for (auto& ase : device->ases_) { - ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); - } - } + .source = types::AudioContexts(context_type)}); - ASSERT_EQ(0, get_func_call_count("alarm_cancel")); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); } -TEST_F(StateMachineTest, testAseAutonomousRelease2Devices) { - const auto context_type = kContextTypeConversational; - const int leaudio_group_id = 4; - const int num_of_devices = 2; +TEST_F(StateMachineTest, StartStreamCachedConfig) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, - num_of_devices); + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); - /* Since we prepared device with Conversional context in mind, Sink and Source - * ASEs should have been configured. - */ - PrepareConfigureCodecHandler(group); + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); - PrepareReceiverStartReady(group); - PrepareReceiverStopReady(group); PrepareReleaseHandler(group); InjectInitialIdleNotification(group); - // Validate initial GroupStreamStatus + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1: Codec config + * 2: Codec QoS (+1 after restart) + * 3: Enabling (+1 after restart) + * 4: Release (1) + */ + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(6); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); - - // Check streaming will continue - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::IDLE)) - .Times(0); - - /* Single disconnect as it is bidirectional Cis*/ - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); + .source = types::AudioContexts(context_type)}); - auto device = group->GetFirstDevice(); - for (auto& ase : device->ases_) { - client_parser::ascs::ase_codec_configured_state_params - codec_configured_state_params; + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); - // Simulate autonomus release for one device. - InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, - &codec_configured_state_params); - InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, - &codec_configured_state_params); - } -} + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); -TEST_F(StateMachineTest, testStateTransitionTimeoutOnIdleState) { - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StopStream(group); - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - auto* leAudioDevice = group->GetFirstDevice(); - EXPECT_CALL(gatt_queue, - WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(1); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + // Restart stream + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); - - // Disconnect device - // in client.cc before this function is called, state of device is changed. - leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED); - LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected( - group, leAudioDevice); + .source = types::AudioContexts(context_type)}); - // Make sure timeout is cleared - ASSERT_TRUE(fake_osi_alarm_set_on_mloop_.cb == nullptr); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testStateIdleNotifyAclDisconnectedRemoveCig) { - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; +TEST_F(StateMachineTest, StartStreamCachedConfigReconfigInvalidBehavior) { + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 6; + const auto num_devices = 1; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; + + /* Scenario + * 1. Start stream and stop stream so ASEs stays in Configured State + * 2. Reconfigure ASEs localy, so the QoS parameters are zeroed + * 3. Inject one ASE 2 to be in Releasing state + * 4. Start stream and Incject ASE 1 to go into Codec Configured state + * 5. IN such case CIG shall not be created and fallback to Release and + * Configure stream should happen. Before fix CigCreate with invalid + * parameters were called */ + ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); - group->SetCigState(types::CigState::CREATED); + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); - // Assert current state - ASSERT_TRUE(group->GetState() == - types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); - ASSERT_FALSE(group->IsInTransition()); - ASSERT_TRUE(group->GetCigState() == types::CigState::CREATED); + PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReceiverStartReadyHandler(group); + PrepareReleaseHandler(group); - // Expect RemoveCig to be called - EXPECT_CALL(*mock_iso_manager_, RemoveCig(group->group_id_, _)).Times(1); + InjectInitialIdleNotification(group); - // Disconnect device - auto* leAudioDevice = group->GetFirstDevice(); - LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected( - group, leAudioDevice); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); - // Assert Cig state transition to NONE after REMOVING - ASSERT_TRUE(group->GetCigState() == types::CigState::NONE); -} + EXPECT_CALL(*mock_iso_manager_, CreateCig).Times(1); -TEST_F(StateMachineTest, testStateTransitionTimeout) { - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; + // Start the configuration and stream call content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - /* Since we prepared device with Ringtone context in mind, only one ASE - * should have been configured. - */ - PrepareConfigureCodecHandler(group, 1); - PrepareConfigureQosHandler(group, 1); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); - auto* leAudioDevice = group->GetFirstDevice(); - EXPECT_CALL(gatt_queue, - WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(3); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); // Start the configuration and stream Media content - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); - - // Check if timeout is fired - EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id)); + LeAudioGroupStateMachine::Get()->StopStream(group); - // simulate timeout seconds passed, alarm executing - fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); - ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); -} + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); -MATCHER_P(dataPathIsEq, expected, "") { return (arg.data_path_id == expected); } + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); -TEST_F(StateMachineTest, testConfigureDataPathForHost) { - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; - - /* Should be called 3 times because - * 1 - calling GetConfigurations just after connection - * (UpdateAudioContextTypeAvailability) - * 2 - when doing configuration of the context type - * 3 - AddCisToStreamConfiguration -> CreateStreamVectorForOffloader - * 4 - Data Path - */ - EXPECT_CALL(*mock_codec_manager_, GetCodecLocation()) - .Times(4) - .WillRepeatedly(Return(types::CodecLocation::HOST)); + stop_inject_configured_ase_after_first_ase_configured_ = true; - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + auto device = group->GetFirstDevice(); + int i = 0; + for (auto& ase : device->ases_) { + if (i++ == 0) continue; - /* Since we prepared device with Ringtone context in mind, only one ASE - * should have been configured. - */ - PrepareConfigureCodecHandler(group, 1); - PrepareConfigureQosHandler(group, 1); - PrepareEnableHandler(group, 1); + // Simulate autonomus release for one ASE - this is invalid behaviour + InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, + nullptr); + } - EXPECT_CALL( - *mock_iso_manager_, - SetupIsoDataPath( - _, dataPathIsEq(bluetooth::hci::iso_manager::kIsoDataPathHci))) + // Restart stream and expect it will not be created. + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)) + .Times(0); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)) .Times(1); - InjectInitialIdleNotification(group); - - // Start the configuration and stream Media content - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); -} -TEST_F(StateMachineTest, testConfigureDataPathForAdsp) { - const auto context_type = kContextTypeRingtone; - const int leaudio_group_id = 4; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; - - /* Should be called 3 times because - * 1 - calling GetConfigurations just after connection - * (UpdateAudioContextTypeAvailability) - * 2 - when doing configuration of the context type - * 3 - AddCisToStreamConfiguration -> CreateStreamVectorForOffloader - * 4 - data path - */ - EXPECT_CALL(*mock_codec_manager_, GetCodecLocation()) - .Times(4) - .WillRepeatedly(Return(types::CodecLocation::ADSP)); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0); - // Prepare fake connected device group - auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + // Block the fallback Release which will happen when CreateCig will faile + stay_in_releasing_state_ = true; - /* Since we prepared device with Ringtone context in mind, only one ASE - * should have been configured. - */ - PrepareConfigureCodecHandler(group, 1); - PrepareConfigureQosHandler(group, 1); - PrepareEnableHandler(group, 1); + // Start the configuration and stream Live content + LeAudioGroupStateMachine::Get()->StartStream( + group, kContextTypeLive, + {.sink = types::AudioContexts(kContextTypeLive), + .source = types::AudioContexts(kContextTypeLive)}); - EXPECT_CALL( - *mock_iso_manager_, - SetupIsoDataPath( - _, dataPathIsEq( - bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault))) - .Times(1); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); +} - InjectInitialIdleNotification(group); +TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_2) { + const auto initial_context_type = kContextTypeConversational; + const auto new_context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 1; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; - // Start the configuration and stream Media content - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); -} + sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz | + codec_specific::kCapSamplingFrequency32000Hz; + additional_snk_ases = 3; + additional_src_ases = 1; -TEST_F(StateMachineTest, testStreamConfigurationAdspDownMix) { - const auto context_type = kContextTypeConversational; - const int leaudio_group_id = 4; - const int num_devices = 2; + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); - // Prepare fake connected device group + // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup( - leaudio_group_id, context_type, num_devices, - types::AudioContexts(kContextTypeConversational)); - - /* Should be called 5 times because - * 1 - calling GetConfigurations just after connection - * (UpdateAudioContextTypeAvailability), - * 2 - when doing configuration of the context type - * 3 - AddCisToStreamConfiguration -> CreateStreamVectorForOffloader (sink) - * 4 - AddCisToStreamConfiguration -> CreateStreamVectorForOffloader (source) - * 5,6 - Data Path - */ - EXPECT_CALL(*mock_codec_manager_, GetCodecLocation()) - .Times(6) - .WillRepeatedly(Return(types::CodecLocation::ADSP)); + leaudio_group_id, initial_context_type, num_devices, + kContextTypeConversational | kContextTypeMedia); + ASSERT_EQ(group->Size(), num_devices); - PrepareConfigureCodecHandler(group); + PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); - PrepareReceiverStartReady(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + PrepareReceiverStartReadyHandler(group); InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); - InjectAclDisconnected(group, leAudioDevice); + auto expected_devices_written = 0; + while (leAudioDevice) { + /* 8 Writes: + * 1: Codec config (+1 after reconfig) + * 2: Codec QoS (+1 after reconfig) + * 3: Enabling (+1 after reconfig) + * 4: ReceiverStartReady (only for conversational) + * 5: Release + */ + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(8); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); - // Start the configuration and stream Media content - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); - ASSERT_EQ( - static_cast( - group->stream_conf.sink_offloader_streams_target_allocation.size()), - 2); - ASSERT_EQ( - static_cast( - group->stream_conf.source_offloader_streams_target_allocation.size()), - 2); + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, initial_context_type, + {.sink = types::AudioContexts(initial_context_type), + .source = types::AudioContexts(initial_context_type)}); - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - uint32_t allocation = 0; - for (const auto& s : - group->stream_conf.sink_offloader_streams_target_allocation) { - allocation |= s.audio_channel_allocation; - ASSERT_FALSE(allocation == 0); - } - ASSERT_TRUE(allocation == codec_spec_conf::kLeAudioLocationStereo); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); - allocation = 0; - for (const auto& s : - group->stream_conf.source_offloader_streams_target_allocation) { - allocation |= s.audio_channel_allocation; - ASSERT_FALSE(allocation == 0); - } - ASSERT_TRUE(allocation == codec_spec_conf::kLeAudioLocationStereo); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StopStream(group); - for (const auto& s : - group->stream_conf.sink_offloader_streams_target_allocation) { - ASSERT_TRUE((s.audio_channel_allocation != 0) && - (s.audio_channel_allocation != - codec_spec_conf::kLeAudioLocationStereo)); - } + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - for (const auto& s : - group->stream_conf.source_offloader_streams_target_allocation) { - ASSERT_TRUE((s.audio_channel_allocation != 0) && - (s.audio_channel_allocation != - codec_spec_conf::kLeAudioLocationStereo)); - } -} + // Restart stream + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); -static void InjectCisDisconnected(LeAudioDeviceGroup* group, - LeAudioDevice* leAudioDevice, - uint8_t reason) { - bluetooth::hci::iso_manager::cis_disconnected_evt event; + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, new_context_type, + {.sink = types::AudioContexts(new_context_type), + .source = types::AudioContexts(new_context_type)}); - for (auto const ase : leAudioDevice->ases_) { - if (ase.data_path_state != types::AudioStreamDataPathState::CIS_ASSIGNED && - ase.data_path_state != types::AudioStreamDataPathState::IDLE) { - event.reason = reason; - event.cig_id = group->group_id_; - event.cis_conn_hdl = ase.cis_conn_hdl; - LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected( - group, leAudioDevice, &event); - } - } + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); } -TEST_F(StateMachineTest, testAttachDeviceToTheStream) { - const auto context_type = kContextTypeMedia; +TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_1) { + const auto initial_context_type = kContextTypeConversational; + const auto new_context_type = kContextTypeMedia; const auto leaudio_group_id = 6; - const auto num_devices = 2; + const auto num_devices = 1; + channel_count_ = kLeAudioCodecChannelCountSingleChannel; + + sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz | + codec_specific::kCapSamplingFrequency32000Hz; + additional_snk_ases = 3; + additional_src_ases = 1; ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); - // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + // Prepare one fake connected devices in a group + auto* group = PrepareSingleTestDeviceGroup( + leaudio_group_id, initial_context_type, num_devices, + kContextTypeConversational | kContextTypeMedia); ASSERT_EQ(group->Size(), num_devices); - PrepareConfigureCodecHandler(group); + // Cannot verify here as we will change the number of ases on reconfigure + PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReleaseHandler(group); + PrepareReceiverStartReadyHandler(group); - auto* leAudioDevice = group->GetFirstDevice(); - LeAudioDevice* lastDevice; - LeAudioDevice* fistDevice = leAudioDevice; + InjectInitialIdleNotification(group); + auto* leAudioDevice = group->GetFirstDevice(); auto expected_devices_written = 0; while (leAudioDevice) { - /* Three Writes: - * 1: Codec Config - * 2: Codec QoS - * 3: Enabling + /* 8 Writes: + * 1: Codec config (+1 after reconfig) + * 2: Codec QoS (+1 after reconfig) + * 3: Enabling (+1 after reconfig) + * 4: ReceiverStartReady (only for conversational) + * 5: Release */ - lastDevice = leAudioDevice; EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); + .Times(8); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); - EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); - - InjectInitialIdleNotification(group); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); - - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - - // Inject CIS and ACL disconnection of first device - InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); - InjectAclDisconnected(group, lastDevice); - - // Check if group keeps streaming - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - - lastDevice->conn_id_ = 3; - lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); + group, initial_context_type, + {.sink = types::AudioContexts(initial_context_type), + .source = types::AudioContexts(initial_context_type)}); - group->UpdateAudioContextTypeAvailability(); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - // Make sure ASE with disconnected CIS are not left in STREAMING - ASSERT_EQ(lastDevice->GetFirstAseWithState( - ::le_audio::types::kLeAudioDirectionSink, - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), - nullptr); - ASSERT_EQ(lastDevice->GetFirstAseWithState( - ::le_audio::types::kLeAudioDirectionSource, - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), - nullptr); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); - EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, - lastDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); - LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StopStream(group); - // Check if group keeps streaming - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); - // Verify that the joining device receives the right CCID list - auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; - bool parsedOk = false; - auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), - lastMeta.size(), parsedOk); - ASSERT_TRUE(parsedOk); + // Restart stream + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::STREAMING)); - auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); - ASSERT_TRUE(ccids.has_value()); - ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, new_context_type, + {.sink = types::AudioContexts(new_context_type), + .source = types::AudioContexts(new_context_type)}); - /* Verify that ASE of first device are still good*/ - auto ase = fistDevice->GetFirstActiveAse(); - ASSERT_NE(ase->max_transport_latency, 0); - ASSERT_NE(ase->retrans_nb, 0); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testStreamToGettingReadyDevice) { - const auto context_type = kContextTypeLive; - const auto leaudio_group_id = 666; - const auto num_devices = 2; +TEST_F(StateMachineTest, lateCisDisconnectedEvent_DuringReconfiguration) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 1; - ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); - - // Simulate the 2nd device still getting ready - auto* firstDevice = group->GetFirstDevice(); - auto* secondDevice = group->GetNextDevice(firstDevice); - secondDevice->SetConnectionState( - DeviceConnectState::CONNECTED_BY_USER_GETTING_READY); - group->UpdateAudioContextTypeAvailability(); - ASSERT_EQ(group->Size(), num_devices); - ASSERT_EQ(1, group->NumOfConnected()); - PrepareConfigureCodecHandler(group); + PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); - PrepareReceiverStartReady(group); PrepareDisableHandler(group); PrepareReleaseHandler(group); + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + /* Three Writes: * 1: Codec Config * 2: Codec QoS * 3: Enabling */ - // Expect actions only on the already prepared device - EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_, - firstDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) .Times(AtLeast(3)); + expected_devices_written++; + + ASSERT_EQ(expected_devices_written, num_devices); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); @@ -3398,67 +5561,97 @@ TEST_F(StateMachineTest, testStreamToGettingReadyDevice) { InjectInitialIdleNotification(group); - // Start the configuration and the stream + // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)}); - // Check if group has transitioned to a proper state with one device still - // being in the `CONNECTED_BY_USER_GETTING_READY` state + // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + /* Prepare DisconnectCis mock to not symulate CisDisconnection */ + ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); + + /* Do reconfiguration */ + group->SetPendingConfiguration(); + + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); + + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)) + .Times(0); + LeAudioGroupStateMachine::Get()->StopStream(group); + + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); + + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, testAttachDeviceToTheConversationalStream) { - const auto context_type = kContextTypeConversational; +TEST_F(StateMachineTest, lateCisDisconnectedEvent_AutonomousConfigured) { + const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; - const auto num_devices = 2; + const auto num_devices = 1; - ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); ASSERT_EQ(group->Size(), num_devices); - PrepareConfigureCodecHandler(group); + PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); - PrepareReceiverStartReady(group); PrepareDisableHandler(group); PrepareReleaseHandler(group); auto* leAudioDevice = group->GetFirstDevice(); - LeAudioDevice* lastDevice; - LeAudioDevice* fistDevice = leAudioDevice; + auto expected_devices_written = 0; + + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; - auto expected_devices_written = 0; - while (leAudioDevice) { - /* Three Writes: - * 1: Codec Config - * 2: Codec QoS - * 3: Enabling - */ - lastDevice = leAudioDevice; - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); - expected_devices_written++; - leAudioDevice = group->GetNextDevice(leAudioDevice); - } ASSERT_EQ(expected_devices_written, num_devices); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); InjectInitialIdleNotification(group); - // Start the configuration and stream Conversational content + // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), @@ -3469,67 +5662,52 @@ TEST_F(StateMachineTest, testAttachDeviceToTheConversationalStream) { types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - // Inject CIS and ACL disconnection of first device - InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); - InjectAclDisconnected(group, lastDevice); - - // Check if group keeps streaming - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - - lastDevice->conn_id_ = 3; - lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); - group->UpdateAudioContextTypeAvailability(); + /* Prepare DisconnectCis mock to not symulate CisDisconnection */ + ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); - // Make sure ASE with disconnected CIS are not left in STREAMING - ASSERT_EQ(lastDevice->GetFirstAseWithState( - ::le_audio::types::kLeAudioDirectionSink, - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), - nullptr); - ASSERT_EQ(lastDevice->GetFirstAseWithState( - ::le_audio::types::kLeAudioDirectionSource, - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), - nullptr); + // Validate GroupStreamStatus + EXPECT_CALL( + mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::RELEASING)); - EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, - lastDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)) + .Times(0); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); - LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice); + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); - // Check if group keeps streaming + // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); - // Verify that the joining device receives the right CCID list - auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; - bool parsedOk = false; - auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), - lastMeta.size(), parsedOk); - ASSERT_TRUE(parsedOk); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); - ASSERT_TRUE(ccids.has_value()); - ASSERT_NE(std::find(ccids->begin(), ccids->end(), call_ccid), ccids->end()); + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); - /* Verify that ASE of first device are still good*/ - auto ase = fistDevice->GetFirstActiveAse(); - ASSERT_NE(ase->max_transport_latency, 0); - ASSERT_NE(ase->retrans_nb, 0); + EXPECT_CALL( + mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); - // Make sure ASEs with reconnected CIS are in STREAMING state - ASSERT_TRUE(lastDevice->HaveAllActiveAsesSameState( - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)); + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, StartStreamAfterConfigure) { +TEST_F(StateMachineTest, lateCisDisconnectedEvent_Idle) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; - const auto num_devices = 2; + const auto num_devices = 1; ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); @@ -3538,97 +5716,116 @@ TEST_F(StateMachineTest, StartStreamAfterConfigure) { PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); ASSERT_EQ(group->Size(), num_devices); - PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReleaseHandler(group); - InjectInitialIdleNotification(group); - auto* leAudioDevice = group->GetFirstDevice(); auto expected_devices_written = 0; - while (leAudioDevice) { - /* Three Writes: - * 1. Codec configure - * 2: Codec QoS - * 3: Enabling - */ - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(3); - expected_devices_written++; - leAudioDevice = group->GetNextDevice(leAudioDevice); - } + + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, + _, GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + ASSERT_EQ(expected_devices_written, num_devices); - // Validate GroupStreamStatus - EXPECT_CALL(mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER)); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + InjectInitialIdleNotification(group); // Start the configuration and stream Media content - group->SetPendingConfiguration(); - LeAudioGroupStateMachine::Get()->ConfigureStream( + LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)}); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + /* Prepare DisconnectCis mock to not symulate CisDisconnection */ + ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); - group->ClearPendingConfiguration(); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); + bluetooth::le_audio::GroupStreamStatus::RELEASING)); - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)) + .Times(0); + + // Stop the stream + LeAudioGroupStateMachine::Get()->StopStream(group); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); + + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)); + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, StartStreamCachedConfig) { - const auto context_type = kContextTypeMedia; - const auto leaudio_group_id = 6; +TEST_F(StateMachineTest, StreamReconfigureAfterCisLostTwoDevices) { + auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 4; const auto num_devices = 2; - ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); - // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + auto* group = PrepareSingleTestDeviceGroup( + leaudio_group_id, context_type, num_devices, + kContextTypeConversational | kContextTypeMedia); ASSERT_EQ(group->Size(), num_devices); - PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); - PrepareDisableHandler(group); - PrepareReleaseHandler(group); + PrepareReceiverStartReadyHandler(group); + + /* Prepare DisconnectCis mock to not symulate CisDisconnection */ + ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(6); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); auto expected_devices_written = 0; while (leAudioDevice) { - /* Three Writes: - * 1: Codec config - * 2: Codec QoS (+1 after restart) - * 3: Enabling (+1 after restart) - * 4: Release (1) - */ EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(6); + .Times(3); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } @@ -3641,101 +5838,122 @@ TEST_F(StateMachineTest, StartStreamCachedConfig) { bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + context_type = kContextTypeMedia; + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + .source = types::AudioContexts(context_type)})); + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + testing::Mock::VerifyAndClearExpectations(&gatt_queue); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); + // Device disconnects due to timeout of CIS + leAudioDevice = group->GetFirstDevice(); + while (leAudioDevice) { + InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); + // Disconnect device + LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected( + group, leAudioDevice); - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + + group->ReloadAudioLocations(); + group->ReloadAudioDirections(); + + // Start conversational scenario + leAudioDevice = group->GetFirstDevice(); + int device_cnt = num_devices; + while (leAudioDevice) { + leAudioDevice->conn_id_ = device_cnt--; + leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED); + leAudioDevice = group->GetNextDevice(leAudioDevice); + } - EXPECT_CALL( - mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StopStream(group); + InjectInitialIdleNotification(group); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + group->ReloadAudioLocations(); + group->ReloadAudioDirections(); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); + leAudioDevice = group->GetFirstDevice(); + expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(4); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); - // Restart stream + // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + // Start the configuration and stream Conversational content + context_type = kContextTypeConversational; + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + .source = types::AudioContexts(context_type)})); + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + ASSERT_EQ(2, get_func_call_count("alarm_cancel")); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + testing::Mock::VerifyAndClearExpectations(&gatt_queue); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_2) { - const auto initial_context_type = kContextTypeConversational; - const auto new_context_type = kContextTypeMedia; - const auto leaudio_group_id = 6; - const auto num_devices = 1; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel | - kLeAudioCodecLC3ChannelCountTwoChannel; - - sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz | - codec_specific::kCapSamplingFrequency32000Hz; - additional_snk_ases = 3; - additional_src_ases = 1; +TEST_F(StateMachineTest, StreamClearAfterReleaseAndConnectionTimeout) { + auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 4; + const auto num_devices = 2; - ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); - ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); + /* Scenario + 1. Streaming to 2 device + 2. Stream suspend + 3. One device got to IDLE + 4. Second device Connection Timeout + */ // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup( - leaudio_group_id, initial_context_type, num_devices, + leaudio_group_id, context_type, num_devices, kContextTypeConversational | kContextTypeMedia); ASSERT_EQ(group->Size(), num_devices); - PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); - PrepareDisableHandler(group); - PrepareReleaseHandler(group); - PrepareReceiverStartReady(group); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); - auto expected_devices_written = 0; + auto* firstDevice = leAudioDevice; + auto* lastDevice = leAudioDevice; + while (leAudioDevice) { - /* 8 Writes: - * 1: Codec config (+1 after reconfig) - * 2: Codec QoS (+1 after reconfig) - * 3: Enabling (+1 after reconfig) - * 4: ReceiverStartReady (only for conversational) - * 5: Release - */ - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(8); - expected_devices_written++; + lastDevice = leAudioDevice; leAudioDevice = group->GetNextDevice(leAudioDevice); } - ASSERT_EQ(expected_devices_written, num_devices); // Validate GroupStreamStatus EXPECT_CALL( @@ -3744,94 +5962,79 @@ TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_2) { bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( - group, initial_context_type, - {.sink = types::AudioContexts(initial_context_type), - .source = types::AudioContexts(initial_context_type)}); + context_type = kContextTypeMedia; + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING)); + EXPECT_CALL(mock_callbacks_, + StatusReportCb(leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::IDLE)); - EXPECT_CALL( - mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); - // Start the configuration and stream Media content + /* Prepare release handler only for first device. */ + PrepareReleaseHandler(group, 0, false, firstDevice); LeAudioGroupStateMachine::Get()->StopStream(group); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - - // Restart stream - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); - - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( - group, new_context_type, - {.sink = types::AudioContexts(new_context_type), - .source = types::AudioContexts(new_context_type)}); + /* Second device will disconnect because of timeout. Do not bother + * with remove data path response from the controller. In test we are doing it + * in a test thread which breaks things. */ + ON_CALL(*mock_iso_manager_, RemoveIsoDataPath).WillByDefault(Return()); + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + InjectAclDisconnected(group, lastDevice); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); } -TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_1) { - const auto initial_context_type = kContextTypeConversational; - const auto new_context_type = kContextTypeMedia; - const auto leaudio_group_id = 6; +TEST_F(StateMachineTest, VerifyThereIsNoDoubleDataPathRemoval) { + auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 4; const auto num_devices = 1; - channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel; - sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz | - codec_specific::kCapSamplingFrequency32000Hz; - additional_snk_ases = 3; - additional_src_ases = 1; + /* Symulate banded headphonse */ + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; - ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); - ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid); + /* Scenario + 1. Phone call to 1 device + 2. Stop the stream + 3. Get both ASE sink and Source to releasing + 4. Verify only 1 RemoveDataPath is called + */ - // Prepare one fake connected devices in a group + // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup( - leaudio_group_id, initial_context_type, num_devices, + leaudio_group_id, context_type, num_devices, kContextTypeConversational | kContextTypeMedia); ASSERT_EQ(group->Size(), num_devices); - // Cannot verify here as we will change the number of ases on reconfigure - PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); - PrepareDisableHandler(group); PrepareReleaseHandler(group); - PrepareReceiverStartReady(group); + PrepareReceiverStartReadyHandler(group); - InjectInitialIdleNotification(group); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); - auto* leAudioDevice = group->GetFirstDevice(); - auto expected_devices_written = 0; - while (leAudioDevice) { - /* 8 Writes: - * 1: Codec config (+1 after reconfig) - * 2: Codec QoS (+1 after reconfig) - * 3: Enabling (+1 after reconfig) - * 4: ReceiverStartReady (only for conversational) - * 5: Release - */ - EXPECT_CALL(gatt_queue, - WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(8); - expected_devices_written++; - leAudioDevice = group->GetNextDevice(leAudioDevice); - } - ASSERT_EQ(expected_devices_written, num_devices); + /*Test ends before full clean*/ + EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); + EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); + + InjectInitialIdleNotification(group); // Validate GroupStreamStatus EXPECT_CALL( @@ -3839,61 +6042,42 @@ TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_1) { StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( - group, initial_context_type, - {.sink = types::AudioContexts(initial_context_type), - .source = types::AudioContexts(initial_context_type)}); - - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING)); - EXPECT_CALL( - mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StopStream(group); - - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); - - // Restart stream - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); + /* Do not trigger any action on removeIsoData path.*/ + ON_CALL(*mock_iso_manager_, RemoveIsoDataPath).WillByDefault(Return()); - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( - group, new_context_type, - {.sink = types::AudioContexts(new_context_type), - .source = types::AudioContexts(new_context_type)}); + LeAudioGroupStateMachine::Get()->StopStream(group); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); } -TEST_F(StateMachineTest, lateCisDisconnectedEvent_ConfiguredByUser) { - const auto context_type = kContextTypeMedia; +TEST_F(StateMachineTest, StreamStartWithDifferentContextFromConfiguredState) { + auto context_type = kContextTypeConversational; const auto leaudio_group_id = 6; - const auto num_devices = 1; + const auto num_devices = 2; ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + auto* group = PrepareSingleTestDeviceGroup( + leaudio_group_id, context_type, num_devices, + kContextTypeConversational | kContextTypeMedia); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group, 0, true); @@ -3901,87 +6085,72 @@ TEST_F(StateMachineTest, lateCisDisconnectedEvent_ConfiguredByUser) { PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReleaseHandler(group); + PrepareReceiverStartReadyHandler(group); + + InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1. Codec configure + * 2: Codec QoS + * 3: Enabling + */ + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(4); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); - /* Three Writes: - * 1: Codec Config - * 2: Codec QoS - * 3: Enabling - */ - EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, - _, GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); - expected_devices_written++; - - ASSERT_EQ(expected_devices_written, num_devices); - - EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); - - InjectInitialIdleNotification(group); + // Validate GroupStreamStatus + EXPECT_CALL(mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER)); // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + group->SetPendingConfiguration(); + LeAudioGroupStateMachine::Get()->ConfigureStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)}); - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); - - /* Prepare DisconnectCis mock to not symulate CisDisconnection */ - ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); - - /* Do reconfiguration */ - group->SetPendingConfiguration(); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + group->ClearPendingConfiguration(); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); - - EXPECT_CALL(mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER)) - .Times(0); - LeAudioGroupStateMachine::Get()->StopStream(group); - - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - - ASSERT_EQ(0, get_func_call_count("alarm_cancel")); + bluetooth::le_audio::GroupStreamStatus::STREAMING)); - EXPECT_CALL(mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER)); + context_type = kContextTypeMedia; + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}); - // Inject CIS and ACL disconnection of first device - InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } -TEST_F(StateMachineTest, lateCisDisconnectedEvent_AutonomousConfigured) { - const auto context_type = kContextTypeMedia; +TEST_F(StateMachineTest, + StreamStartWithSameContextFromConfiguredStateButNewMetadata) { + auto context_type = kContextTypeConversational; const auto leaudio_group_id = 6; - const auto num_devices = 1; + const auto num_devices = 2; ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + auto* group = PrepareSingleTestDeviceGroup( + leaudio_group_id, context_type, num_devices, + kContextTypeConversational | kContextTypeLive); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group, 0, true); @@ -3989,86 +6158,80 @@ TEST_F(StateMachineTest, lateCisDisconnectedEvent_AutonomousConfigured) { PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReleaseHandler(group); + PrepareReceiverStartReadyHandler(group); + + InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* firstActiveDevice = leAudioDevice; auto expected_devices_written = 0; - - /* Three Writes: - * 1: Codec Config - * 2: Codec QoS - * 3: Enabling - */ - EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, - _, GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); - expected_devices_written++; - + while (leAudioDevice) { + /* Three Writes: + * 1. Codec configure + * 2: Codec QoS + * 3: Enabling + */ + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(4); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } ASSERT_EQ(expected_devices_written, num_devices); - EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); - - InjectInitialIdleNotification(group); + // Validate GroupStreamStatus + EXPECT_CALL(mock_callbacks_, + StatusReportCb( + leaudio_group_id, + bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER)); // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( + group->SetPendingConfiguration(); + LeAudioGroupStateMachine::Get()->ConfigureStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)}); - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); - - /* Prepare DisconnectCis mock to not symulate CisDisconnection */ - ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); + testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + group->ClearPendingConfiguration(); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); - - EXPECT_CALL( - mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)) - .Times(0); + bluetooth::le_audio::GroupStreamStatus::STREAMING)); - // Stop the stream - LeAudioGroupStateMachine::Get()->StopStream(group); + auto metadata_context_type = kContextTypeLive; + types::BidirectionalPair> ccid_lists = { + .sink = {media_ccid}, .source = {media_ccid}}; - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(metadata_context_type), + .source = types::AudioContexts(metadata_context_type)}, + ccid_lists); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(0, get_func_call_count("alarm_cancel")); - - EXPECT_CALL( - mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); + // Verify that the joining device receives the right CCID list + auto lastMeta = firstActiveDevice->GetFirstActiveAse()->metadata; + bool parsedOk = false; + auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), + lastMeta.size(), parsedOk); + ASSERT_TRUE(parsedOk); - // Inject CIS and ACL disconnection of first device - InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); + ASSERT_TRUE(ccids.has_value()); + ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); } -TEST_F(StateMachineTest, lateCisDisconnectedEvent_Idle) { +TEST_F(StateMachineTest, testAttachDeviceToTheStreamCisFailure) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; - const auto num_devices = 1; + const auto num_devices = 2; ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); @@ -4084,19 +6247,25 @@ TEST_F(StateMachineTest, lateCisDisconnectedEvent_Idle) { PrepareReleaseHandler(group); auto* leAudioDevice = group->GetFirstDevice(); - auto expected_devices_written = 0; - - /* Three Writes: - * 1: Codec Config - * 2: Codec QoS - * 3: Enabling - */ - EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, - leAudioDevice->ctp_hdls_.val_hdl, - _, GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); - expected_devices_written++; + LeAudioDevice* lastDevice; + LeAudioDevice* fistDevice = leAudioDevice; + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } ASSERT_EQ(expected_devices_written, num_devices); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); @@ -4116,243 +6285,315 @@ TEST_F(StateMachineTest, lateCisDisconnectedEvent_Idle) { types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - reset_mock_function_count_map(); - /* Prepare DisconnectCis mock to not symulate CisDisconnection */ - ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + InjectAclDisconnected(group, lastDevice); - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::RELEASING)); + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::IDLE)) - .Times(0); + lastDevice->conn_id_ = 3; + lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); - // Stop the stream - LeAudioGroupStateMachine::Get()->StopStream(group); + // Make sure ASE with disconnected CIS are not left in STREAMING + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSink, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSource, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); - // Check if group has transitioned to a proper state - ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); - ASSERT_EQ(0, get_func_call_count("alarm_cancel")); + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + do_not_send_cis_establish_event_ = true; - EXPECT_CALL(mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::IDLE)); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); + LeAudioGroupStateMachine::Get()->AttachToStream( + group, lastDevice, {.sink = {media_ccid}, .source = {}}); - // Inject CIS and ACL disconnection of first device - InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); -} + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); -TEST_F(StateMachineTest, StreamReconfigureAfterCisLostTwoDevices) { - auto context_type = kContextTypeConversational; - const auto leaudio_group_id = 4; + // Verify that the joining device receives the right CCID list + auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; + bool parsedOk = false; + auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), + lastMeta.size(), parsedOk); + ASSERT_TRUE(parsedOk); + + auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); + ASSERT_TRUE(ccids.has_value()); + ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); + + /* Verify that ASE of first device are still good*/ + auto ase = fistDevice->GetFirstActiveAse(); + ASSERT_NE(ase->max_transport_latency, 0); + ASSERT_NE(ase->retrans_nb, 0); +} + +TEST_F(StateMachineTest, testAclDropWithoutApriorCisDisconnection) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; const auto num_devices = 2; + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + // Prepare multiple fake connected devices in a group - auto* group = PrepareSingleTestDeviceGroup( - leaudio_group_id, context_type, num_devices, - kContextTypeConversational | kContextTypeMedia); + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); - PrepareReceiverStartReady(group); - - /* Prepare DisconnectCis mock to not symulate CisDisconnection */ - ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); - - EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(6); - EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); - EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); - - InjectInitialIdleNotification(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* firstDevice = leAudioDevice; + LeAudioDevice* lastDevice = leAudioDevice; + auto expected_devices_written = 0; while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(3); + .Times(AtLeast(3)); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + InjectInitialIdleNotification(group); // Start the configuration and stream Media content - context_type = kContextTypeMedia; - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); + .source = types::AudioContexts(context_type)}); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(1, get_func_call_count("alarm_cancel")); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - testing::Mock::VerifyAndClearExpectations(&gatt_queue); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); - // Device disconnects due to timeout of CIS - leAudioDevice = group->GetFirstDevice(); - while (leAudioDevice) { - InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); - // Disconnect device - LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected( - group, leAudioDevice); + /* Separate CIS for dual CIS device is treated as sink device */ + ASSERT_EQ(group->stream_conf.stream_params.sink.num_of_devices, 2); + ASSERT_EQ(group->stream_conf.stream_params.sink.num_of_channels, 2); - leAudioDevice = group->GetNextDevice(leAudioDevice); - } + // Inject CIS and ACL disconnection of first device + InjectAclDisconnected(group, firstDevice); - group->ReloadAudioLocations(); - group->ReloadAudioDirections(); - group->UpdateAudioContextTypeAvailability(); + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); + InjectAclDisconnected(group, lastDevice); - // Start conversational scenario - leAudioDevice = group->GetFirstDevice(); - int device_cnt = num_devices; - while (leAudioDevice) { - leAudioDevice->conn_id_ = device_cnt--; - leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED); - leAudioDevice = group->GetNextDevice(leAudioDevice); - } + ASSERT_EQ(group->stream_conf.stream_params.sink.num_of_devices, 0); + ASSERT_EQ(group->stream_conf.stream_params.sink.num_of_channels, 0); +} - InjectInitialIdleNotification(group); +TEST_F(StateMachineTest, testAutonomousDisableTimeout) { + const auto context_type = kContextTypeConversational; + const auto leaudio_group_id = 6; + const auto num_devices = 2; - group->ReloadAudioLocations(); - group->ReloadAudioDirections(); - group->UpdateAudioContextTypeAvailability(kContextTypeConversational | - kContextTypeMedia); + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); - leAudioDevice = group->GetFirstDevice(); - expected_devices_written = 0; + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + PrepareReceiverStartReadyHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + // LeAudioDevice* fistDevice = leAudioDevice; + + auto expected_devices_written = 0; while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(4); + .Times(AtLeast(3)); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4); + + InjectInitialIdleNotification(group); // Start the configuration and stream Conversational content - context_type = kContextTypeConversational; - ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)})); + .source = types::AudioContexts(context_type)}); + + /* First timer started for transition to streaming state */ + ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - ASSERT_EQ(2, get_func_call_count("alarm_cancel")); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - testing::Mock::VerifyAndClearExpectations(&gatt_queue); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + + /* First timer finished when group achieves streaming state */ + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + + /* Remote initiates autonomous Disable operation */ + auto ase = lastDevice->GetFirstActiveAseByDirection( + ::le_audio::types::kLeAudioDirectionSink); + + InjectAseStateNotification(ase, lastDevice, group, + ascs::kAseStateQoSConfigured, + &cached_qos_configuration_map_[ase->id]); + + /* Second timer started for autonomous transition to disabled state */ + ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); + + // Inject CIS disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + + // Check if timeout is fired + EXPECT_CALL(mock_callbacks_, + OnDeviceAutonomousStateTransitionTimeout(lastDevice)); + + fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data); } -TEST_F(StateMachineTest, StreamStartWithDifferentContextFromConfiguredState) { - auto context_type = kContextTypeConversational; +TEST_F(StateMachineTest, testAutonomousDisableSuccess) { + const auto context_type = kContextTypeConversational; const auto leaudio_group_id = 6; const auto num_devices = 2; ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); // Prepare multiple fake connected devices in a group - auto* group = PrepareSingleTestDeviceGroup( - leaudio_group_id, context_type, num_devices, - kContextTypeConversational | kContextTypeMedia); + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); ASSERT_EQ(group->Size(), num_devices); - PrepareConfigureCodecHandler(group, 0, true); + PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReleaseHandler(group); - PrepareReceiverStartReady(group); - - InjectInitialIdleNotification(group); + PrepareReceiverStartReadyHandler(group); auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + auto expected_devices_written = 0; while (leAudioDevice) { /* Three Writes: - * 1. Codec configure + * 1: Codec Config * 2: Codec QoS * 3: Enabling */ + lastDevice = leAudioDevice; EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) - .Times(4); + .Times(AtLeast(3)); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); - // Validate GroupStreamStatus - EXPECT_CALL(mock_callbacks_, - StatusReportCb( - leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER)); + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4); - // Start the configuration and stream Media content - group->SetPendingConfiguration(); - LeAudioGroupStateMachine::Get()->ConfigureStream( + InjectInitialIdleNotification(group); + + // Start the configuration and stream Conversational content + LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)}); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + /* First timer started for transition to streaming state */ + ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); - group->ClearPendingConfiguration(); - // Validate GroupStreamStatus - EXPECT_CALL( - mock_callbacks_, - StatusReportCb(leaudio_group_id, - bluetooth::le_audio::GroupStreamStatus::STREAMING)); + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - context_type = kContextTypeMedia; - // Start the configuration and stream Media content - LeAudioGroupStateMachine::Get()->StartStream( - group, context_type, - {.sink = types::AudioContexts(context_type), - .source = types::AudioContexts(context_type)}); + /* Remote initiates autonomous Disable operation */ + auto ase_sink = lastDevice->GetFirstActiveAseByDirection( + ::le_audio::types::kLeAudioDirectionSink); - testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); + InjectAseStateNotification(ase_sink, lastDevice, group, + ascs::kAseStateQoSConfigured, + &cached_qos_configuration_map_[ase_sink->id]); + + /* Check if autonomous operation timer is not canceled */ + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + /* Second timer started for autonomous transition to disabled state */ + ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); + + auto ase_source = lastDevice->GetFirstActiveAseByDirection( + ::le_audio::types::kLeAudioDirectionSource); + + client_parser::ascs::ase_transient_state_params disabling_params = { + .metadata = {}}; + InjectAseStateNotification(ase_source, lastDevice, group, + ascs::kAseStateDisabling, &disabling_params); + InjectAseStateNotification(ase_source, lastDevice, group, + ascs::kAseStateQoSConfigured, + &cached_qos_configuration_map_[ase_source->id]); + + /* Inject CIS disconnection of first device, disconenct only first CIS because + * while processing first disconnection test will try to bring up this ASEs + * to STREAMING state and connect CISes again. + */ + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT, true); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + /* Check if autonomous operation timer is freed */ + ASSERT_EQ(1, get_func_call_count("alarm_free")); } -TEST_F(StateMachineTest, testAttachDeviceToTheStreamCisFailure) { - const auto context_type = kContextTypeMedia; +TEST_F(StateMachineTest, testAutonomousDisableCancelOnDisconnect) { + const auto context_type = kContextTypeConversational; const auto leaudio_group_id = 6; const auto num_devices = 2; @@ -4368,10 +6609,10 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStreamCisFailure) { PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReleaseHandler(group); + PrepareReceiverStartReadyHandler(group); auto* leAudioDevice = group->GetFirstDevice(); LeAudioDevice* lastDevice; - LeAudioDevice* fistDevice = leAudioDevice; auto expected_devices_written = 0; while (leAudioDevice) { @@ -4393,74 +6634,43 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStreamCisFailure) { EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4); InjectInitialIdleNotification(group); - // Start the configuration and stream Media content + // Start the configuration and stream Conversational content LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)}); + /* First timer started for transition to streaming state */ + ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); + // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); - // Inject CIS and ACL disconnection of first device - InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); - InjectAclDisconnected(group, lastDevice); - - // Check if group keeps streaming - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); - - lastDevice->conn_id_ = 3; - lastDevice->SetConnectionState(DeviceConnectState::CONNECTED); - - group->UpdateAudioContextTypeAvailability(); - - // Make sure ASE with disconnected CIS are not left in STREAMING - ASSERT_EQ(lastDevice->GetFirstAseWithState( - ::le_audio::types::kLeAudioDirectionSink, - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), - nullptr); - ASSERT_EQ(lastDevice->GetFirstAseWithState( - ::le_audio::types::kLeAudioDirectionSource, - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), - nullptr); - - EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, - lastDevice->ctp_hdls_.val_hdl, _, - GATT_WRITE_NO_RSP, _, _)) - .Times(AtLeast(3)); - - do_not_send_cis_establish_event_ = true; + /* First timer finished when group achieves streaming state */ + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); - EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); - EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); - LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice); + /* Remote initiates autonomous Disable operation */ + auto ase = lastDevice->GetFirstActiveAseByDirection( + ::le_audio::types::kLeAudioDirectionSink); - // Check if group keeps streaming - ASSERT_EQ(group->GetState(), - types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + InjectAseStateNotification(ase, lastDevice, group, + ascs::kAseStateQoSConfigured, + &cached_qos_configuration_map_[ase->id]); - // Verify that the joining device receives the right CCID list - auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; - bool parsedOk = false; - auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), - lastMeta.size(), parsedOk); - ASSERT_TRUE(parsedOk); + /* Second timer started for autonomous transition to disabled state */ + ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); - auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); - ASSERT_TRUE(ccids.has_value()); - ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); + // Inject ACL disconnection of first device + InjectAclDisconnected(group, lastDevice); - /* Verify that ASE of first device are still good*/ - auto ase = fistDevice->GetFirstActiveAse(); - ASSERT_NE(ase->max_transport_latency, 0); - ASSERT_NE(ase->retrans_nb, 0); + /* Check if autonomous operation timer is freed on ASEs deactivation */ + ASSERT_EQ(2, get_func_call_count("alarm_free")); } } // namespace internal diff --git a/system/bta/le_audio/storage_helper.cc b/system/bta/le_audio/storage_helper.cc index ede095ed64a7001609a1948de4b5d19d90547b42..ccb25998a4f4a07149945962b8950526d844b050 100644 --- a/system/bta/le_audio/storage_helper.cc +++ b/system/bta/le_audio/storage_helper.cc @@ -22,6 +22,7 @@ #include "gd/common/strings.h" #include "le_audio_types.h" #include "osi/include/log.h" +#include "stack/include/bt_types.h" using le_audio::types::hdl_pair; @@ -464,4 +465,4 @@ bool DeserializeHandles(LeAudioDevice* leAudioDevice, leAudioDevice->known_service_handles_ = true; return true; } -} // namespace le_audio \ No newline at end of file +} // namespace le_audio diff --git a/system/bta/pan/bta_pan_act.cc b/system/bta/pan/bta_pan_act.cc index 4ffce806d7d10f37333aeea837ee861e264c3e7b..a47c284b7610e1367dbbf1c40eb0b9eb7520a765 100644 --- a/system/bta/pan/bta_pan_act.cc +++ b/system/bta/pan/bta_pan_act.cc @@ -26,23 +26,18 @@ #include -// PAN_INCLUDED -#include "bt_target.h" // Must be first to define build configuration -#if (PAN_INCLUDED == TRUE) - #include "bta/include/bta_pan_co.h" #include "bta/pan/bta_pan_int.h" -#include "main/shim/dumpsys.h" +#include "internal_include/bt_target.h" // PAN_INCLUDED #include "osi/include/allocator.h" #include "osi/include/fixed_queue.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" -#include "stack/include/btu.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/pan_api.h" #include "types/raw_address.h" +#if (PAN_INCLUDED == TRUE) void bta_pan_sm_execute(tBTA_PAN_SCB* p_scb, uint16_t event, tBTA_PAN_DATA* p_data); @@ -182,8 +177,7 @@ static void bta_pan_data_buf_ind_cback(uint16_t handle, const RawAddress& src, if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len > PAN_BUF_SIZE) { - APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__, - p_buf->len); + LOG_ERROR("%s: received buffer length too large: %d", __func__, p_buf->len); return; } @@ -336,9 +330,9 @@ void bta_pan_set_role(tBTA_PAN_DATA* p_data) { tBTA_PAN bta_pan = { .set_role = { - .role = p_data->api_set_role.role, .status = (status == PAN_SUCCESS) ? BTA_PAN_SUCCESS : BTA_PAN_FAIL, + .role = p_data->api_set_role.role, }, }; @@ -416,7 +410,7 @@ void bta_pan_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) { status = PAN_Connect(p_data->api_open.bd_addr, p_data->api_open.local_role, p_data->api_open.peer_role, &p_scb->handle); - APPL_TRACE_DEBUG("%s pan connect status: %d", __func__, status); + LOG_VERBOSE("%s pan connect status: %d", __func__, status); if (status == PAN_SUCCESS) { p_scb->bd_addr = p_data->api_open.bd_addr; @@ -474,8 +468,7 @@ void bta_pan_api_close(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) { void bta_pan_conn_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) { tBTA_PAN bta_pan; - APPL_TRACE_DEBUG("%s pan connection result: %d", __func__, - p_data->conn.result); + LOG_VERBOSE("%s pan connection result: %d", __func__, p_data->conn.result); bta_pan.open.bd_addr = p_scb->bd_addr; bta_pan.open.handle = p_scb->handle; diff --git a/system/bta/pan/bta_pan_api.cc b/system/bta/pan/bta_pan_api.cc index 96ab7094b323f22019aa25fc2463baa2eab77914..1d338869e9a5a18efa9b1a894a960991a3f690c7 100644 --- a/system/bta/pan/bta_pan_api.cc +++ b/system/bta/pan/bta_pan_api.cc @@ -31,7 +31,7 @@ #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" static const tBTA_SYS_REG bta_pan_reg = {bta_pan_hdl_event, BTA_PanDisable}; @@ -116,9 +116,9 @@ void BTA_PanSetRole(tBTA_PAN_ROLE role, const tBTA_PAN_ROLE_INFO user_info, { .event = BTA_PAN_API_SET_ROLE_EVT, }, - .role = role, .user_name = {}, .nap_name = {}, + .role = role, }, }; if (role & BTA_PAN_ROLE_PANU) { diff --git a/system/bta/pan/bta_pan_ci.cc b/system/bta/pan/bta_pan_ci.cc index 9afe539fa9ab1b680da3f39437f48c924fb48946..3c3804f859fe44f84acd39a2ac44929b9c7693b1 100644 --- a/system/bta/pan/bta_pan_ci.cc +++ b/system/bta/pan/bta_pan_ci.cc @@ -22,11 +22,10 @@ * ******************************************************************************/ -#include "bt_target.h" // Must be first to define build configuration #include "bta/pan/bta_pan_int.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" #include "types/raw_address.h" void bta_pan_sm_execute(tBTA_PAN_SCB* p_scb, uint16_t event, diff --git a/system/bta/pan/bta_pan_int.h b/system/bta/pan/bta_pan_int.h index 50eb5be59e356017be21e4d4cfc0d1bc751ac0b5..8bd7d057f2d3489089d31065c6f043c332a282ba 100644 --- a/system/bta/pan/bta_pan_int.h +++ b/system/bta/pan/bta_pan_int.h @@ -27,6 +27,7 @@ #include #include "bta/include/bta_api.h" +#include "bta/include/bta_sec_api.h" #include "bta/include/bta_pan_api.h" #include "bta/sys/bta_sys.h" #include "osi/include/fixed_queue.h" @@ -166,7 +167,7 @@ tBTA_PAN_SCB* bta_pan_scb_alloc(void); void bta_pan_scb_dealloc(tBTA_PAN_SCB* p_scb); uint8_t bta_pan_scb_to_idx(tBTA_PAN_SCB* p_scb); tBTA_PAN_SCB* bta_pan_scb_by_handle(uint16_t handle); -bool bta_pan_hdl_event(BT_HDR_RIGID* p_msg); +bool bta_pan_hdl_event(const BT_HDR_RIGID* p_msg); /* action functions */ void bta_pan_enable(tBTA_PAN_DATA* p_data); diff --git a/system/bta/pan/bta_pan_main.cc b/system/bta/pan/bta_pan_main.cc index 26941e6ce9febe7bfb8259f26a6a095056835854..8e1f383b48988b8591570a28408891ce978c6efa 100644 --- a/system/bta/pan/bta_pan_main.cc +++ b/system/bta/pan/bta_pan_main.cc @@ -134,7 +134,7 @@ tBTA_PAN_SCB* bta_pan_scb_alloc(void) { for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) { if (!p_scb->in_use) { p_scb->in_use = true; - APPL_TRACE_DEBUG("bta_pan_scb_alloc %d", i); + LOG_VERBOSE("bta_pan_scb_alloc %d", i); break; } } @@ -142,7 +142,7 @@ tBTA_PAN_SCB* bta_pan_scb_alloc(void) { if (i == BTA_PAN_NUM_CONN) { /* out of scbs */ p_scb = NULL; - APPL_TRACE_WARNING("Out of scbs"); + LOG_WARN("Out of scbs"); } return p_scb; } @@ -163,8 +163,8 @@ void bta_pan_sm_execute(tBTA_PAN_SCB* p_scb, uint16_t event, uint8_t action; int i; - APPL_TRACE_EVENT("PAN scb=%d event=0x%x state=%d", bta_pan_scb_to_idx(p_scb), - event, p_scb->state); + LOG_VERBOSE("PAN scb=%d event=0x%x state=%d", bta_pan_scb_to_idx(p_scb), + event, p_scb->state); /* look up the state table for the current state */ state_table = bta_pan_st_tbl[p_scb->state]; @@ -251,7 +251,7 @@ void bta_pan_api_open(tBTA_PAN_DATA* p_data) { * ******************************************************************************/ void bta_pan_scb_dealloc(tBTA_PAN_SCB* p_scb) { - APPL_TRACE_DEBUG("bta_pan_scb_dealloc %d", bta_pan_scb_to_idx(p_scb)); + LOG_VERBOSE("bta_pan_scb_dealloc %d", bta_pan_scb_to_idx(p_scb)); fixed_queue_free(p_scb->data_queue, NULL); memset(p_scb, 0, sizeof(tBTA_PAN_SCB)); } @@ -291,7 +291,7 @@ tBTA_PAN_SCB* bta_pan_scb_by_handle(uint16_t handle) { } } - APPL_TRACE_WARNING("No scb for handle %d", handle); + LOG_WARN("No scb for handle %d", handle); return NULL; } @@ -306,7 +306,7 @@ tBTA_PAN_SCB* bta_pan_scb_by_handle(uint16_t handle) { * Returns void * ******************************************************************************/ -bool bta_pan_hdl_event(BT_HDR_RIGID* p_msg) { +bool bta_pan_hdl_event(const BT_HDR_RIGID* p_msg) { tBTA_PAN_SCB* p_scb; bool freebuf = true; diff --git a/system/bta/rfcomm/bta_rfcomm_scn.cc b/system/bta/rfcomm/bta_rfcomm_scn.cc new file mode 100644 index 0000000000000000000000000000000000000000..c303e79cba68c0bcfaf5b2851dab740e6ac50dcd --- /dev/null +++ b/system/bta/rfcomm/bta_rfcomm_scn.cc @@ -0,0 +1,115 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bta/include/bta_rfcomm_scn.h" + +#define LOG_TAG "bta" + +#include + +#include "bta/jv/bta_jv_int.h" // tBTA_JV_CB +#include "stack/include/rfcdefs.h" // RFCOMM_MAX_SCN + +extern tBTA_JV_CB bta_jv_cb; + +/******************************************************************************* + * + * Function BTM_AllocateSCN + * + * Description Look through the Server Channel Numbers for a free one. + * + * Returns Allocated SCN number or 0 if none. + * + ******************************************************************************/ +uint8_t BTA_AllocateSCN(void) { + // SCN can be allocated in the range of [1, RFCOMM_MAX_SCN] + // btm_scn uses indexes 0 to RFCOMM_MAX_SCN-1 to track RFC ports + for (uint8_t i = bta_jv_cb.scn_search_index; i < RFCOMM_MAX_SCN; ++i) { + if (!bta_jv_cb.scn_in_use[i]) { + bta_jv_cb.scn_in_use[i] = true; + bta_jv_cb.scn_search_index = (i + 1); + LOG_DEBUG("Allocating scn: %u", i + 1); + return (i + 1); // allocated scn is index + 1 + } + } + + // In order to avoid OOB, btm_available_index must be no more than + // RFCOMM_MAX_SCN. + bta_jv_cb.scn_search_index = + std::min(bta_jv_cb.scn_search_index, (uint8_t)(RFCOMM_MAX_SCN)); + + // Start from index 1 because index 0 (scn 1) is reserved for HFP + // If there's no empty SCN from _last_index to BTM_MAX_SCN. + for (uint8_t i = 1; i < bta_jv_cb.scn_search_index; ++i) { + if (!bta_jv_cb.scn_in_use[i]) { + bta_jv_cb.scn_in_use[i] = true; + bta_jv_cb.scn_search_index = (i + 1); + LOG_DEBUG("Allocating scn: %u", i + 1); + return (i + 1); // allocated scn is index + 1 + } + } + LOG_DEBUG("Unable to allocate an scn"); + return (0); /* No free ports */ +} + +/******************************************************************************* + * + * Function BTM_TryAllocateSCN + * + * Description Try to allocate a fixed server channel + * + * Returns Returns true if server channel was available + * + ******************************************************************************/ + +bool BTA_TryAllocateSCN(uint8_t scn) { + /* Make sure we don't exceed max scn range. + * Stack reserves scn 1 for HFP and HSP + */ + if ((scn > RFCOMM_MAX_SCN) || (scn == 1) || (scn == 0)) return false; + + /* check if this scn is available */ + if (!bta_jv_cb.scn_in_use[scn - 1]) { + bta_jv_cb.scn_in_use[scn - 1] = true; + LOG_DEBUG("Allocating scn: %u", scn); + return true; + } + LOG_DEBUG("Unable to allocate scn %u", scn); + return (false); /* scn was busy */ +} + +/******************************************************************************* + * + * Function BTM_FreeSCN + * + * Description Free the specified SCN. + * + * Returns true or false + * + ******************************************************************************/ +bool BTA_FreeSCN(uint8_t scn) { + /* Since this isn't used by HFP, this function will only free valid SCNs + * that aren't reserved for HFP, which is range [2, RFCOMM_MAX_SCN]. + */ + if (scn < RFCOMM_MAX_SCN && scn > 1) { + bta_jv_cb.scn_in_use[scn - 1] = false; + LOG_DEBUG("Freed SCN: %u", scn); + return (true); + } else { + LOG_WARN("Invalid SCN: %u", scn); + return (false); /* Illegal SCN passed in */ + } +} diff --git a/system/bta/sdp/bta_sdp_act.cc b/system/bta/sdp/bta_sdp_act.cc index 1ace9b2dce8b1ef0481740f717006883aedbf0cb..9c1d5bd62611613c6fe97d362c4912536bc015a6 100644 --- a/system/bta/sdp/bta_sdp_act.cc +++ b/system/bta/sdp/bta_sdp_act.cc @@ -29,12 +29,19 @@ #include "bta/sdp/bta_sdp_int.h" #include "btif/include/btif_profile_storage.h" #include "btif/include/btif_sock_sdp.h" +#include "common/init_flags.h" #include "main/shim/metrics_api.h" +#include "os/log.h" #include "osi/include/allocator.h" +#include "osi/include/osi.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/sdp_api.h" +#include "stack/include/sdpdefs.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + static void bta_create_mns_sdp_record(bluetooth_sdp_record* record, tSDP_DISC_REC* p_rec) { tSDP_DISC_ATTR* p_attr; @@ -48,7 +55,8 @@ static void bta_create_mns_sdp_record(bluetooth_sdp_record* record, record->mns.hdr.profile_version = 0; record->mns.supported_features = 0x0000001F; // default value if not found - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 4) { @@ -60,7 +68,8 @@ static void bta_create_mns_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_MAP_SUPPORTED_FEATURES attr not found!!"); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_NAME); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { record->mns.hdr.service_name_length = @@ -73,16 +82,18 @@ static void bta_create_mns_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_SERVICE_NAME attr not found!!"); } - if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_MAP_PROFILE, - &pversion)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_MAP_PROFILE, &pversion)) { record->mns.hdr.profile_version = pversion; } - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { record->mns.hdr.rfcomm_channel_number = pe.params[0]; } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_GOEP_L2CAP_PSM); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -111,7 +122,8 @@ static void bta_create_mas_sdp_record(bluetooth_sdp_record* record, record->mas.supported_features = 0x0000001F; record->mas.supported_message_types = 0; - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAS_INSTANCE_ID); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_MAS_INSTANCE_ID); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) { @@ -123,7 +135,8 @@ static void bta_create_mas_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_MAS_INSTANCE_ID attr not found!!"); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_MSG_TYPE); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SUPPORTED_MSG_TYPE); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) { @@ -135,7 +148,8 @@ static void bta_create_mas_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_SUPPORTED_MSG_TYPE attr not found!!"); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 4) { @@ -147,7 +161,8 @@ static void bta_create_mas_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_MAP_SUPPORTED_FEATURES attr not found!!"); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_NAME); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { record->mas.hdr.service_name_length = @@ -160,16 +175,18 @@ static void bta_create_mas_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_SERVICE_NAME attr not found!!"); } - if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_MAP_PROFILE, - &pversion)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_MAP_PROFILE, &pversion)) { record->mas.hdr.profile_version = pversion; } - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { record->mas.hdr.rfcomm_channel_number = pe.params[0]; } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_GOEP_L2CAP_PSM); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -197,7 +214,8 @@ static void bta_create_pse_sdp_record(bluetooth_sdp_record* record, record->pse.supported_features = 0x00000003; record->pse.supported_repositories = 0; - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_REPOSITORIES); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SUPPORTED_REPOSITORIES); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) { @@ -208,7 +226,8 @@ static void bta_create_pse_sdp_record(bluetooth_sdp_record* record, } else { LOG_ERROR("ATTR_ID_SUPPORTED_REPOSITORIES attr not found!!"); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PBAP_SUPPORTED_FEATURES); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_PBAP_SUPPORTED_FEATURES); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 4) { @@ -220,7 +239,8 @@ static void bta_create_pse_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_PBAP_SUPPORTED_FEATURES attr not found!!"); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_NAME); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { record->pse.hdr.service_name_length = @@ -234,16 +254,18 @@ static void bta_create_pse_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_SERVICE_NAME attr not found!!"); } - if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_PHONE_ACCESS, - &pversion)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_PHONE_ACCESS, &pversion)) { record->pse.hdr.profile_version = pversion; } - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { record->pse.hdr.rfcomm_channel_number = pe.params[0]; } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_GOEP_L2CAP_PSM); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -270,7 +292,8 @@ static void bta_create_ops_sdp_record(bluetooth_sdp_record* record, record->ops.hdr.profile_version = 0; record->ops.supported_formats_list_len = 0; - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_NAME); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { record->ops.hdr.service_name_length = @@ -283,16 +306,18 @@ static void bta_create_ops_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_SERVICE_NAME attr not found!!"); } - if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_OBEX_OBJECT_PUSH, - &pversion)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_OBEX_OBJECT_PUSH, &pversion)) { record->ops.hdr.profile_version = pversion; } - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { record->ops.hdr.rfcomm_channel_number = pe.params[0]; } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_GOEP_L2CAP_PSM); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -304,12 +329,13 @@ static void bta_create_ops_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_GOEP_L2CAP_PSM attr not found!!"); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FORMATS_LIST); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SUPPORTED_FORMATS_LIST); if (p_attr != NULL) { /* Safety check - each entry should itself be a sequence */ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) { record->ops.supported_formats_list_len = 0; - APPL_TRACE_ERROR( + LOG_ERROR( "%s() - supported_formats_list - wrong attribute length/type:" " 0x%02x - expected 0x06", __func__, p_attr->attr_len_type); @@ -325,7 +351,7 @@ static void bta_create_ops_sdp_record(bluetooth_sdp_record* record, if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) >= 1)) { if (count == sizeof(record->ops.supported_formats_list)) { - APPL_TRACE_ERROR( + LOG_ERROR( "%s() - supported_formats_list - count overflow - " "too many sub attributes!!", __func__); @@ -336,7 +362,7 @@ static void bta_create_ops_sdp_record(bluetooth_sdp_record* record, record->ops.supported_formats_list[count] = p_sattr->attr_value.v.u8; count++; } else { - APPL_TRACE_ERROR( + LOG_ERROR( "%s() - supported_formats_list - wrong sub attribute " "length/type: 0x%02x - expected 0x80", __func__, p_sattr->attr_len_type); @@ -344,7 +370,7 @@ static void bta_create_ops_sdp_record(bluetooth_sdp_record* record, } } if (record->ops.supported_formats_list_len != count) { - APPL_TRACE_WARNING( + LOG_WARN( "%s() - supported_formats_list - Length of attribute different " "from the actual number of sub-attributes in the sequence " "att-length: %d - number of elements: %d", @@ -368,7 +394,8 @@ static void bta_create_sap_sdp_record(bluetooth_sdp_record* record, record->sap.hdr.l2cap_psm = -1; record->sap.hdr.profile_version = 0; - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_NAME); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { record->sap.hdr.service_name_length = @@ -381,11 +408,13 @@ static void bta_create_sap_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_SERVICE_NAME attr not found!!"); } - if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_SAP, &pversion)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_SAP, &pversion)) { record->sap.hdr.profile_version = pversion; } - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { record->sap.hdr.rfcomm_channel_number = pe.params[0]; } } @@ -394,7 +423,7 @@ static void bta_create_dip_sdp_record(bluetooth_sdp_record* record, tSDP_DISC_REC* p_rec) { tSDP_DISC_ATTR* p_attr; - APPL_TRACE_DEBUG("%s()", __func__); + LOG_VERBOSE("%s()", __func__); /* hdr is redundancy in dip */ record->dip.hdr.type = SDP_TYPE_DIP; @@ -404,8 +433,8 @@ static void bta_create_dip_sdp_record(bluetooth_sdp_record* record, record->dip.hdr.l2cap_psm = -1; record->dip.hdr.profile_version = 0; - p_attr = - SDP_FindAttributeInRec(p_rec, ATTR_ID_SPECIFICATION_ID); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SPECIFICATION_ID); if (p_attr != nullptr) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -414,10 +443,11 @@ static void bta_create_dip_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_SPECIFICATION_ID attr type or len wrong!!"); } } else { - APPL_TRACE_ERROR("%s() ATTR_ID_SPECIFICATION_ID not found", __func__); + LOG_ERROR("%s() ATTR_ID_SPECIFICATION_ID not found", __func__); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_VENDOR_ID); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_VENDOR_ID); if (p_attr != nullptr) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -426,11 +456,11 @@ static void bta_create_dip_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_VENDOR_ID attr type or len wrong!!"); } } else { - APPL_TRACE_ERROR("%s() ATTR_ID_VENDOR_ID not found", __func__); + LOG_ERROR("%s() ATTR_ID_VENDOR_ID not found", __func__); } - p_attr = - SDP_FindAttributeInRec(p_rec, ATTR_ID_VENDOR_ID_SOURCE); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_VENDOR_ID_SOURCE); if (p_attr != nullptr) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -439,10 +469,11 @@ static void bta_create_dip_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_VENDOR_ID_SOURCE attr type or len wrong!!"); } } else { - APPL_TRACE_ERROR("%s() ATTR_ID_VENDOR_ID_SOURCE not found", __func__); + LOG_ERROR("%s() ATTR_ID_VENDOR_ID_SOURCE not found", __func__); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PRODUCT_ID); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_PRODUCT_ID); if (p_attr != nullptr) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -451,12 +482,11 @@ static void bta_create_dip_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_PRODUCT_ID attr type or len wrong!!"); } } else { - APPL_TRACE_ERROR("%s() ATTR_ID_PRODUCT_ID not found", __func__); + LOG_ERROR("%s() ATTR_ID_PRODUCT_ID not found", __func__); } - p_attr = - SDP_FindAttributeInRec(p_rec, ATTR_ID_PRODUCT_VERSION); - + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_PRODUCT_VERSION); if (p_attr != nullptr) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -465,10 +495,11 @@ static void bta_create_dip_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_PRODUCT_VERSION attr type or len wrong!!"); } } else { - APPL_TRACE_ERROR("%s() ATTR_ID_PRODUCT_VERSION not found", __func__); + LOG_ERROR("%s() ATTR_ID_PRODUCT_VERSION not found", __func__); } - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PRIMARY_RECORD); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_PRIMARY_RECORD); if (p_attr != nullptr) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) { @@ -477,7 +508,7 @@ static void bta_create_dip_sdp_record(bluetooth_sdp_record* record, LOG_ERROR("ATTR_ID_PRIMARY_RECORD attr type or len wrong!!"); } } else { - APPL_TRACE_ERROR("%s() ATTR_ID_PRIMARY_RECORD not found", __func__); + LOG_ERROR("%s() ATTR_ID_PRIMARY_RECORD not found", __func__); } } @@ -494,7 +525,8 @@ static void bta_create_raw_sdp_record(bluetooth_sdp_record* record, record->hdr.profile_version = -1; /* Try to extract a service name */ - p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME); + p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_NAME); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { record->pse.hdr.service_name_length = @@ -508,7 +540,8 @@ static void bta_create_raw_sdp_record(bluetooth_sdp_record* record, } /* Try to extract an RFCOMM channel */ - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { record->pse.hdr.rfcomm_channel_number = pe.params[0]; } record->hdr.user1_ptr_len = p_bta_sdp_cfg->p_sdp_db->raw_size; @@ -516,10 +549,11 @@ static void bta_create_raw_sdp_record(bluetooth_sdp_record* record, } /** Callback from btm after search is completed */ -static void bta_sdp_search_cback(tSDP_RESULT result, const void* user_data) { +static void bta_sdp_search_cback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_RESULT result, const void* user_data) { tBTA_SDP_STATUS status = BTA_SDP_FAILURE; int count = 0; - APPL_TRACE_DEBUG("%s() - res: 0x%x", __func__, result); + LOG_VERBOSE("%s() - res: 0x%x", __func__, result); bta_sdp_cb.sdp_active = false; @@ -535,51 +569,50 @@ static void bta_sdp_search_cback(tSDP_RESULT result, const void* user_data) { if (result == SDP_SUCCESS || result == SDP_DB_FULL) { tSDP_DISC_REC* p_rec = NULL; do { - p_rec = SDP_FindServiceUUIDInDb(p_bta_sdp_cfg->p_sdp_db, uuid, p_rec); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceUUIDInDb( + p_bta_sdp_cfg->p_sdp_db, uuid, p_rec); /* generate the matching record data pointer */ if (!p_rec) { - APPL_TRACE_DEBUG("%s() - UUID not found", __func__); + LOG_VERBOSE("%s() - UUID not found", __func__); continue; } status = BTA_SDP_SUCCESS; if (uuid == UUID_MAP_MAS) { - APPL_TRACE_DEBUG("%s() - found MAP (MAS) uuid", __func__); + LOG_VERBOSE("%s() - found MAP (MAS) uuid", __func__); bta_create_mas_sdp_record(&evt_data.records[count], p_rec); } else if (uuid == UUID_MAP_MNS) { - APPL_TRACE_DEBUG("%s() - found MAP (MNS) uuid", __func__); + LOG_VERBOSE("%s() - found MAP (MNS) uuid", __func__); bta_create_mns_sdp_record(&evt_data.records[count], p_rec); } else if (uuid == UUID_PBAP_PSE) { - APPL_TRACE_DEBUG("%s() - found PBAP (PSE) uuid", __func__); + LOG_VERBOSE("%s() - found PBAP (PSE) uuid", __func__); bta_create_pse_sdp_record(&evt_data.records[count], p_rec); } else if (uuid == UUID_OBEX_OBJECT_PUSH) { - APPL_TRACE_DEBUG("%s() - found Object Push Server (OPS) uuid", - __func__); + LOG_VERBOSE("%s() - found Object Push Server (OPS) uuid", __func__); bta_create_ops_sdp_record(&evt_data.records[count], p_rec); } else if (uuid == UUID_SAP) { - APPL_TRACE_DEBUG("%s() - found SAP uuid", __func__); + LOG_VERBOSE("%s() - found SAP uuid", __func__); bta_create_sap_sdp_record(&evt_data.records[count], p_rec); } else if (uuid == UUID_PBAP_PCE) { - APPL_TRACE_DEBUG("%s() - found PBAP (PCE) uuid", __func__); + LOG_VERBOSE("%s() - found PBAP (PCE) uuid", __func__); if (p_rec != NULL) { uint16_t peer_pce_version = 0; - SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_PHONE_ACCESS, - &peer_pce_version); + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, UUID_SERVCLASS_PHONE_ACCESS, &peer_pce_version); if (peer_pce_version != 0) { btif_storage_set_pce_profile_version(p_rec->remote_bd_addr, peer_pce_version); } } else { - APPL_TRACE_DEBUG("%s() - PCE Record is null", __func__); + LOG_VERBOSE("%s() - PCE Record is null", __func__); } } else if (uuid == UUID_DIP) { - APPL_TRACE_DEBUG("%s() - found DIP uuid", __func__); + LOG_VERBOSE("%s() - found DIP uuid", __func__); bta_create_dip_sdp_record(&evt_data.records[count], p_rec); } else { /* we do not have specific structure for this */ - APPL_TRACE_DEBUG("%s() - profile not identified. using raw data", - __func__); + LOG_VERBOSE("%s() - profile not identified. using raw data", __func__); bta_create_raw_sdp_record(&evt_data.records[count], p_rec); p_rec = NULL; // Terminate loop /* For raw, we only extract the first entry, and then return the @@ -614,7 +647,7 @@ static void bta_sdp_search_cback(tSDP_RESULT result, const void* user_data) { * ******************************************************************************/ void bta_sdp_enable(tBTA_SDP_DM_CBACK* p_cback) { - APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active); + LOG_VERBOSE("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active); tBTA_SDP_STATUS status = BTA_SDP_SUCCESS; bta_sdp_cb.p_dm_cback = p_cback; tBTA_SDP bta_sdp; @@ -634,7 +667,7 @@ void bta_sdp_enable(tBTA_SDP_DM_CBACK* p_cback) { void bta_sdp_search(const RawAddress bd_addr, const bluetooth::Uuid uuid) { tBTA_SDP_STATUS status = BTA_SDP_FAILURE; - APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active); + LOG_VERBOSE("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active); if (bta_sdp_cb.sdp_active) { /* SDP is still in progress */ @@ -656,16 +689,16 @@ void bta_sdp_search(const RawAddress bd_addr, const bluetooth::Uuid uuid) { bta_sdp_cb.remote_addr = bd_addr; /* initialize the search for the uuid */ - APPL_TRACE_DEBUG("%s init discovery with UUID: %s", __func__, - uuid.ToString().c_str()); - SDP_InitDiscoveryDb(p_bta_sdp_cfg->p_sdp_db, p_bta_sdp_cfg->sdp_db_size, 1, - &uuid, 0, NULL); + LOG_VERBOSE("%s init discovery with UUID: %s", __func__, + uuid.ToString().c_str()); + get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + p_bta_sdp_cfg->p_sdp_db, p_bta_sdp_cfg->sdp_db_size, 1, &uuid, 0, NULL); Uuid* bta_sdp_search_uuid = (Uuid*)osi_malloc(sizeof(Uuid)); *bta_sdp_search_uuid = uuid; - if (!SDP_ServiceSearchAttributeRequest2(bd_addr, p_bta_sdp_cfg->p_sdp_db, - bta_sdp_search_cback, - (void*)bta_sdp_search_uuid)) { + if (!get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest2( + bd_addr, p_bta_sdp_cfg->p_sdp_db, bta_sdp_search_cback, + (void*)bta_sdp_search_uuid)) { bta_sdp_cb.sdp_active = false; /* failed to start SDP. report the failure right away */ @@ -714,3 +747,19 @@ void bta_sdp_remove_record(void* user_data) { if (bta_sdp_cb.p_dm_cback) bta_sdp_cb.p_dm_cback(BTA_SDP_REMOVE_RECORD_USER_EVT, NULL, user_data); } + +namespace bluetooth { +namespace testing { + +void bta_create_dip_sdp_record(bluetooth_sdp_record* record, + tSDP_DISC_REC* p_rec) { + ::bta_create_dip_sdp_record(record, p_rec); +} + +void bta_sdp_search_cback(const RawAddress& bd_addr, tSDP_RESULT result, + const void* user_data) { + ::bta_sdp_search_cback(bd_addr, result, user_data); +} + +} // namespace testing +} // namespace bluetooth diff --git a/system/bta/sdp/bta_sdp_api.cc b/system/bta/sdp/bta_sdp_api.cc index a7e88d32e93d9594a8398afd5c7558fd69ce74a2..c77a6efe9b192ca84de8bc540eaacb3564904cf7 100644 --- a/system/bta/sdp/bta_sdp_api.cc +++ b/system/bta/sdp/bta_sdp_api.cc @@ -29,7 +29,7 @@ #include "bt_target.h" // Must be first to define build configuration #include "bta/sdp/bta_sdp_int.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -57,7 +57,7 @@ tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK* p_cback) { } memset(&bta_sdp_cb, 0, sizeof(tBTA_SDP_CB)); - do_in_main_thread(FROM_HERE, base::Bind(bta_sdp_enable, p_cback)); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_sdp_enable, p_cback)); return BTA_SDP_SUCCESS; } @@ -76,7 +76,7 @@ tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK* p_cback) { ******************************************************************************/ tBTA_SDP_STATUS BTA_SdpSearch(const RawAddress& bd_addr, const bluetooth::Uuid& uuid) { - do_in_main_thread(FROM_HERE, base::Bind(bta_sdp_search, bd_addr, uuid)); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_sdp_search, bd_addr, uuid)); return BTA_SDP_SUCCESS; } @@ -93,7 +93,8 @@ tBTA_SDP_STATUS BTA_SdpSearch(const RawAddress& bd_addr, * ******************************************************************************/ tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data) { - do_in_main_thread(FROM_HERE, base::Bind(bta_sdp_create_record, user_data)); + do_in_main_thread(FROM_HERE, + base::BindOnce(bta_sdp_create_record, user_data)); return BTA_SDP_SUCCESS; } @@ -110,6 +111,7 @@ tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data) { * ******************************************************************************/ tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void* user_data) { - do_in_main_thread(FROM_HERE, base::Bind(bta_sdp_remove_record, user_data)); + do_in_main_thread(FROM_HERE, + base::BindOnce(bta_sdp_remove_record, user_data)); return BTA_SDP_SUCCESS; } diff --git a/system/bta/sys/bta_sys.h b/system/bta/sys/bta_sys.h index 522b3b225386ac13b161379cfdbaaec61c774556..0e791a23d6a013ea564b9f455411011ee63ef990 100644 --- a/system/bta/sys/bta_sys.h +++ b/system/bta/sys/bta_sys.h @@ -24,11 +24,14 @@ #ifndef BTA_SYS_H #define BTA_SYS_H +#include #include #include +#include -#include "bt_target.h" // Must be first to define build configuration +#include "internal_include/bt_target.h" +#include "macros.h" #include "osi/include/alarm.h" #include "stack/include/bt_hdr.h" #include "stack/include/hci_error_code.h" @@ -44,7 +47,7 @@ typedef bool(tBTA_SYS_VS_EVT_HDLR)(uint16_t evt, void* p); /* event handler function type */ -typedef bool(tBTA_SYS_EVT_HDLR)(BT_HDR_RIGID* p_msg); +typedef bool(tBTA_SYS_EVT_HDLR)(const BT_HDR_RIGID* p_msg); static_assert( sizeof(BT_HDR) == sizeof(BT_HDR_RIGID), "Rigid replacement should be same size struct with flexible member"); @@ -61,66 +64,85 @@ inline const T* Specialize(U* u) { #define BTA_DM_NUM_JV_ID 2 #endif -/* SW sub-systems */ -#define BTA_ID_SYS 0 /* system manager */ -/* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */ -#define BTA_ID_DM_SEARCH 2 /* device manager search */ -#define BTA_ID_DM_SEC 3 /* device manager security */ -#define BTA_ID_DG 4 /* data gateway */ -#define BTA_ID_AG 5 /* audio gateway */ -#define BTA_ID_OPC 6 /* object push client */ -#define BTA_ID_OPS 7 /* object push server */ -#define BTA_ID_FTS 8 /* file transfer server */ -#define BTA_ID_CT 9 /* cordless telephony terminal */ -#define BTA_ID_FTC 10 /* file transfer client */ -#define BTA_ID_SS 11 /* synchronization server */ -#define BTA_ID_PR 12 /* Printer client */ -#define BTA_ID_BIC 13 /* Basic Imaging Client */ -#define BTA_ID_PAN 14 /* Personal Area Networking */ -#define BTA_ID_BIS 15 /* Basic Imaging Server */ -#define BTA_ID_ACC 16 /* Advanced Camera Client */ -#define BTA_ID_SC 17 /* SIM Card Access server */ -#define BTA_ID_AV 18 /* Advanced audio/video */ -#define BTA_ID_HD 20 /* HID Device */ -#define BTA_ID_CG 21 /* Cordless Gateway */ -#define BTA_ID_BP 22 /* Basic Printing Client */ -#define BTA_ID_HH 23 /* Human Interface Device Host */ -#define BTA_ID_PBS 24 /* Phone Book Access Server */ -#define BTA_ID_PBC 25 /* Phone Book Access Client */ -#define BTA_ID_JV 26 /* Java */ -#define BTA_ID_HS 27 /* Headset */ -#define BTA_ID_MSE 28 /* Message Server Equipment */ -#define BTA_ID_MCE 29 /* Message Client Equipment */ -#define BTA_ID_HL 30 /* Health Device Profile*/ -#define BTA_ID_GATTC 31 /* GATT Client */ -#define BTA_ID_GATTS 32 /* GATT Client */ -#define BTA_ID_SDP 33 /* SDP Client */ -#define BTA_ID_BLUETOOTH_MAX 34 /* last BT profile */ - -#define BTA_ID_MAX (44 + BTA_DM_NUM_JV_ID) - -typedef uint8_t tBTA_SYS_ID; - -inline std::string BtaIdSysText(tBTA_SYS_ID sys_id) { +typedef enum : uint8_t { + /* SW sub-systems */ + BTA_ID_SYS = 0, /* system manager */ + /* BLUETOOTH PART - from = 0, to BTA_ID_BLUETOOTH_MAX */ + BTA_ID_DM_SEARCH = 2, /* device manager search */ + BTA_ID_DM_SEC = 3, /* device manager security */ + BTA_ID_DG = 4, /* data gateway */ + BTA_ID_AG = 5, /* audio gateway */ + BTA_ID_OPC = 6, /* object push client */ + BTA_ID_OPS = 7, /* object push server */ + BTA_ID_FTS = 8, /* file transfer server */ + BTA_ID_CT = 9, /* cordless telephony terminal */ + BTA_ID_FTC = 10, /* file transfer client */ + BTA_ID_SS = 11, /* synchronization server */ + BTA_ID_PR = 12, /* Printer client */ + BTA_ID_BIC = 13, /* Basic Imaging Client */ + BTA_ID_PAN = 14, /* Personal Area Networking */ + BTA_ID_BIS = 15, /* Basic Imaging Server */ + BTA_ID_ACC = 16, /* Advanced Camera Client */ + BTA_ID_SC = 17, /* SIM Card Access server */ + BTA_ID_AV = 18, /* Advanced audio/video */ + BTA_ID_AVK = 19, /* Audio/video sink */ + BTA_ID_HD = 20, /* HID Device */ + BTA_ID_CG = 21, /* Cordless Gateway */ + BTA_ID_BP = 22, /* Basic Printing Client */ + BTA_ID_HH = 23, /* Human Interface Device Host */ + BTA_ID_PBS = 24, /* Phone Book Access Server */ + BTA_ID_PBC = 25, /* Phone Book Access Client */ + BTA_ID_JV = 26, /* Java */ + BTA_ID_HS = 27, /* Headset */ + BTA_ID_MSE = 28, /* Message Server Equipment */ + BTA_ID_MCE = 29, /* Message Client Equipment */ + BTA_ID_HL = 30, /* Health Device Profile*/ + BTA_ID_GATTC = 31, /* GATT Client */ + BTA_ID_GATTS = 32, /* GATT Client */ + BTA_ID_SDP = 33, /* SDP Client */ + BTA_ID_BLUETOOTH_MAX = 34, /* last BT profile */ + + BTA_ID_MAX = (44 + BTA_DM_NUM_JV_ID), +} tBTA_SYS_ID; + +inline std::string BtaIdSysText(const tBTA_SYS_ID& sys_id) { switch (sys_id) { - case BTA_ID_DM_SEARCH: // 2 - return std::string("Scanner"); - case BTA_ID_AG: // 5 - return std::string("Audio gateway"); - case BTA_ID_PAN: // 14 - return std::string("PAN Personal area network"); - case BTA_ID_AV: // 18 - return std::string("Advanced audio/video"); - case BTA_ID_HD: // 20 - return std::string("HID Human interface device"); - case BTA_ID_HH: // 23 - return std::string("HID Human interface host"); - case BTA_ID_GATTC: // 31 - return std::string("GATT client"); - case BTA_ID_GATTS: // 32 - return std::string("GATT server"); + CASE_RETURN_TEXT(BTA_ID_SYS); + CASE_RETURN_TEXT(BTA_ID_DM_SEARCH); + CASE_RETURN_TEXT(BTA_ID_DM_SEC); + CASE_RETURN_TEXT(BTA_ID_DG); + CASE_RETURN_TEXT(BTA_ID_AG); + CASE_RETURN_TEXT(BTA_ID_OPC); + CASE_RETURN_TEXT(BTA_ID_OPS); + CASE_RETURN_TEXT(BTA_ID_FTS); + CASE_RETURN_TEXT(BTA_ID_CT); + CASE_RETURN_TEXT(BTA_ID_FTC); + CASE_RETURN_TEXT(BTA_ID_SS); + CASE_RETURN_TEXT(BTA_ID_PR); + CASE_RETURN_TEXT(BTA_ID_BIC); + CASE_RETURN_TEXT(BTA_ID_PAN); + CASE_RETURN_TEXT(BTA_ID_BIS); + CASE_RETURN_TEXT(BTA_ID_ACC); + CASE_RETURN_TEXT(BTA_ID_SC); + CASE_RETURN_TEXT(BTA_ID_AV); + CASE_RETURN_TEXT(BTA_ID_AVK); + CASE_RETURN_TEXT(BTA_ID_HD); + CASE_RETURN_TEXT(BTA_ID_CG); + CASE_RETURN_TEXT(BTA_ID_BP); + CASE_RETURN_TEXT(BTA_ID_HH); + CASE_RETURN_TEXT(BTA_ID_PBS); + CASE_RETURN_TEXT(BTA_ID_PBC); + CASE_RETURN_TEXT(BTA_ID_JV); + CASE_RETURN_TEXT(BTA_ID_HS); + CASE_RETURN_TEXT(BTA_ID_MSE); + CASE_RETURN_TEXT(BTA_ID_MCE); + CASE_RETURN_TEXT(BTA_ID_HL); + CASE_RETURN_TEXT(BTA_ID_GATTC); + CASE_RETURN_TEXT(BTA_ID_GATTS); + CASE_RETURN_TEXT(BTA_ID_SDP); + CASE_RETURN_TEXT(BTA_ID_BLUETOOTH_MAX); default: - return std::string("Unknown"); + return base::StringPrintf("Unknown[%hhu]", sys_id); } } @@ -161,11 +183,20 @@ inline std::string bta_sys_conn_status_text(tBTA_SYS_CONN_STATUS status) { } } -/* conn callback for role / low power manager*/ -typedef void(tBTA_SYS_CONN_CBACK)(tBTA_SYS_CONN_STATUS status, uint8_t id, - uint8_t app_id, const RawAddress& peer_addr); - -/* conn callback for role / low power manager*/ +/* conn callback for power mode manager */ +typedef void(tBTA_SYS_CONN_CBACK)(tBTA_SYS_CONN_STATUS status, + const tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr); +/* conn callback for sco change */ +typedef void(tBTA_SYS_CONN_SCO_CBACK)(tBTA_SYS_CONN_STATUS status, + uint8_t num_sco_links, uint8_t app_id, + const RawAddress& peer_addr); +/* callback for role switch */ +typedef void(tBTA_SYS_ROLE_SWITCH_CBACK)(tBTA_SYS_CONN_STATUS status, + tHCI_ROLE new_role, + tHCI_STATUS hci_status, + const RawAddress& peer_addr); +/* callback for sniff subrating updates */ typedef void(tBTA_SYS_SSR_CFG_CBACK)(uint8_t id, uint8_t app_id, uint16_t latency, uint16_t tout); @@ -186,13 +217,6 @@ typedef struct { tBTA_SYS_DISABLE* disable; } tBTA_SYS_REG; -/***************************************************************************** - * Global data - ****************************************************************************/ - -/* trace level */ -extern uint8_t appl_trace_level; - /***************************************************************************** * Macros ****************************************************************************/ @@ -218,28 +242,36 @@ void bta_sys_disable(); void bta_sys_rm_register(tBTA_SYS_CONN_CBACK* p_cback); void bta_sys_pm_register(tBTA_SYS_CONN_CBACK* p_cback); -void bta_sys_sco_register(tBTA_SYS_CONN_CBACK* p_cback); +void bta_sys_sco_register(tBTA_SYS_CONN_SCO_CBACK* p_cback); -void bta_sys_conn_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_conn_close(uint8_t id, uint8_t app_id, +void bta_sys_conn_open(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr); +void bta_sys_conn_close(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_app_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_app_close(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_sco_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_sco_close(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_sco_use(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_sco_unuse(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_idle(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); -void bta_sys_busy(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); +void bta_sys_app_open(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr); +void bta_sys_app_close(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr); +void bta_sys_sco_open(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr); +void bta_sys_sco_close(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr); +void bta_sys_sco_use(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr); +void bta_sys_sco_unuse(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr); +void bta_sys_idle(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr); +void bta_sys_busy(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr); void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK* p_cback); -void bta_sys_chg_ssr_config(uint8_t id, uint8_t app_id, uint16_t max_latency, - uint16_t min_tout); +void bta_sys_chg_ssr_config(tBTA_SYS_ID id, uint8_t app_id, + uint16_t max_latency, uint16_t min_tout); -void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK* p_cback); +void bta_sys_role_chg_register(tBTA_SYS_ROLE_SWITCH_CBACK* p_cback); void bta_sys_notify_role_chg(const RawAddress& peer_addr, tHCI_ROLE new_role, tHCI_STATUS hci_status); -void bta_sys_collision_register(uint8_t bta_id, tBTA_SYS_CONN_CBACK* p_cback); +void bta_sys_collision_register(tBTA_SYS_ID bta_id, + tBTA_SYS_CONN_CBACK* p_cback); void bta_sys_notify_collision(const RawAddress& peer_addr); #if (BTA_EIR_CANNED_UUID_LIST != TRUE) diff --git a/system/bta/sys/bta_sys_conn.cc b/system/bta/sys/bta_sys_conn.cc index 28cab0af05e7769603e2192d776ec585ff63b18b..49422cc90c7bcd7a131640c1dccdade8d11f0c7a 100644 --- a/system/bta/sys/bta_sys_conn.cc +++ b/system/bta/sys/bta_sys_conn.cc @@ -24,10 +24,9 @@ #include -#include "bt_target.h" // Must be first to define build configuration - #include "bta/sys/bta_sys.h" #include "bta/sys/bta_sys_int.h" +#include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" #include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR @@ -59,7 +58,7 @@ void bta_sys_rm_register(tBTA_SYS_CONN_CBACK* p_cback) { * Returns void * ******************************************************************************/ -void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK* p_cback) { +void bta_sys_role_chg_register(tBTA_SYS_ROLE_SWITCH_CBACK* p_cback) { bta_sys_cb.p_role_cb = p_cback; } /******************************************************************************* @@ -106,7 +105,8 @@ void bta_sys_notify_role_chg(const RawAddress& peer_addr, tHCI_ROLE new_role, * Returns void * ******************************************************************************/ -void bta_sys_collision_register(uint8_t bta_id, tBTA_SYS_CONN_CBACK* p_cback) { +void bta_sys_collision_register(tBTA_SYS_ID bta_id, + tBTA_SYS_CONN_CBACK* p_cback) { uint8_t index; for (index = 0; index < MAX_COLLISION_REG; index++) { @@ -151,7 +151,7 @@ void bta_sys_notify_collision(const RawAddress& peer_addr) { * Returns void * ******************************************************************************/ -void bta_sys_sco_register(tBTA_SYS_CONN_CBACK* p_cback) { +void bta_sys_sco_register(tBTA_SYS_CONN_SCO_CBACK* p_cback) { bta_sys_cb.p_sco_cb = p_cback; } @@ -180,7 +180,7 @@ void bta_sys_pm_register(tBTA_SYS_CONN_CBACK* p_cback) { * Returns void * ******************************************************************************/ -void bta_sys_conn_open(uint8_t id, uint8_t app_id, +void bta_sys_conn_open(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { if (bta_sys_cb.prm_cb) { bta_sys_cb.prm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr); @@ -202,7 +202,7 @@ void bta_sys_conn_open(uint8_t id, uint8_t app_id, * Returns void * ******************************************************************************/ -void bta_sys_conn_close(uint8_t id, uint8_t app_id, +void bta_sys_conn_close(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { if (bta_sys_cb.prm_cb) { bta_sys_cb.prm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr); @@ -224,7 +224,8 @@ void bta_sys_conn_close(uint8_t id, uint8_t app_id, * Returns void * ******************************************************************************/ -void bta_sys_app_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { +void bta_sys_app_open(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr) { if (bta_sys_cb.ppm_cb) { bta_sys_cb.ppm_cb(BTA_SYS_APP_OPEN, id, app_id, peer_addr); } @@ -240,7 +241,7 @@ void bta_sys_app_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { * Returns void * ******************************************************************************/ -void bta_sys_app_close(uint8_t id, uint8_t app_id, +void bta_sys_app_close(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { if (bta_sys_cb.ppm_cb) { bta_sys_cb.ppm_cb(BTA_SYS_APP_CLOSE, id, app_id, peer_addr); @@ -257,11 +258,12 @@ void bta_sys_app_close(uint8_t id, uint8_t app_id, * Returns void * ******************************************************************************/ -void bta_sys_sco_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { +void bta_sys_sco_open(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr) { /* AG triggers p_sco_cb by bta_sys_sco_use. */ if ((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) { /* without querying BTM_GetNumScoLinks() */ - bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr); + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, id, app_id, peer_addr); } if (bta_sys_cb.ppm_cb) { @@ -279,7 +281,7 @@ void bta_sys_sco_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { * Returns void * ******************************************************************************/ -void bta_sys_sco_close(uint8_t id, uint8_t app_id, +void bta_sys_sco_close(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { uint8_t num_sco_links; @@ -303,7 +305,7 @@ void bta_sys_sco_close(uint8_t id, uint8_t app_id, * Returns void * ******************************************************************************/ -void bta_sys_sco_use(UNUSED_ATTR uint8_t id, uint8_t app_id, +void bta_sys_sco_use(UNUSED_ATTR tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { /* AV streaming need to be suspended before SCO is connected. */ if (bta_sys_cb.p_sco_cb) { @@ -322,7 +324,7 @@ void bta_sys_sco_use(UNUSED_ATTR uint8_t id, uint8_t app_id, * Returns void * ******************************************************************************/ -void bta_sys_sco_unuse(uint8_t id, uint8_t app_id, +void bta_sys_sco_unuse(UNUSED_ATTR tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { if ((bta_sys_cb.p_sco_cb)) { uint8_t num_sco_links = BTM_GetNumScoLinks(); @@ -356,7 +358,7 @@ void bta_sys_chg_ssr_config(uint8_t id, uint8_t app_id, uint16_t max_latency, * Returns void * ******************************************************************************/ -void bta_sys_idle(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { +void bta_sys_idle(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { if (bta_sys_cb.prm_cb) { bta_sys_cb.prm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr); } @@ -376,7 +378,7 @@ void bta_sys_idle(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { * Returns void * ******************************************************************************/ -void bta_sys_busy(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { +void bta_sys_busy(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { if (bta_sys_cb.prm_cb) { bta_sys_cb.prm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr); } diff --git a/system/bta/sys/bta_sys_int.h b/system/bta/sys/bta_sys_int.h index 7487f4d5d9f85ab438b8b88da47023a4edb5c329..464fb72fddcb91a5f41caed8d81ab66eca956e12 100644 --- a/system/bta/sys/bta_sys_int.h +++ b/system/bta/sys/bta_sys_int.h @@ -25,8 +25,9 @@ #define BTA_SYS_INT_H #include -#include "bta/sys/bta_sys.h" +#include "bta/sys/bta_sys.h" +#include "internal_include/bt_target.h" /***************************************************************************** * Constants and data types ****************************************************************************/ @@ -39,7 +40,7 @@ #define MAX_COLLISION_REG 5 typedef struct { - uint8_t id[MAX_COLLISION_REG]; + tBTA_SYS_ID id[MAX_COLLISION_REG]; tBTA_SYS_CONN_CBACK* p_coll_cback[MAX_COLLISION_REG]; } tBTA_SYS_COLLISION; @@ -53,9 +54,10 @@ typedef struct { tBTA_SYS_CONN_CBACK* prm_cb; /* role management callback registered by DM */ tBTA_SYS_CONN_CBACK* ppm_cb; /* low power management callback registered by DM */ - tBTA_SYS_CONN_CBACK* + tBTA_SYS_CONN_SCO_CBACK* p_sco_cb; /* SCO connection change callback registered by AV */ - tBTA_SYS_CONN_CBACK* p_role_cb; /* role change callback registered by AV */ + tBTA_SYS_ROLE_SWITCH_CBACK* + p_role_cb; /* role change callback registered by AV */ tBTA_SYS_COLLISION colli_reg; /* collision handling module */ #if (BTA_EIR_CANNED_UUID_LIST != TRUE) tBTA_SYS_EIR_CBACK* eir_cb; /* add/remove UUID into EIR */ diff --git a/system/bta/sys/bta_sys_main.cc b/system/bta/sys/bta_sys_main.cc index e48f0abe9d67b1b7001b8b452009e33f2226c38f..614deb3a4c5b06f89f7ca3b21d95761a4b94e008 100644 --- a/system/bta/sys/bta_sys_main.cc +++ b/system/bta/sys/bta_sys_main.cc @@ -37,19 +37,13 @@ #include "osi/include/allocator.h" #include "osi/include/log.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" void BTIF_dm_on_hw_error(); /* system manager control block definition */ tBTA_SYS_CB bta_sys_cb; -/* trace level */ -/* TODO Hard-coded trace levels - Needs to be configurable */ -uint8_t appl_trace_level = APPL_INITIAL_TRACE_LEVEL; -uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING; - /******************************************************************************* * * Function bta_sys_init @@ -85,20 +79,19 @@ void BTA_sys_signal_hw_error() { * ******************************************************************************/ static void bta_sys_event(BT_HDR_RIGID* p_msg) { - uint8_t id; bool freebuf = true; - APPL_TRACE_EVENT("%s: Event 0x%x", __func__, p_msg->event); + LOG_VERBOSE("%s: Event 0x%x", __func__, p_msg->event); /* get subsystem id from event */ - id = (uint8_t)(p_msg->event >> 8); + uint8_t id = (uint8_t)(p_msg->event >> 8); /* verify id and call subsystem event handler */ if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) { freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg); } else { - LOG_INFO("Ignoring receipt of unregistered event id:%s", - BtaIdSysText(id).c_str()); + LOG_INFO("Ignoring receipt of unregistered event id:%s[%hhu]", + BtaIdSysText(static_cast(id)).c_str(), id); } if (freebuf) { @@ -166,7 +159,7 @@ bool bta_sys_is_register(uint8_t id) { return bta_sys_cb.is_reg[id]; } void bta_sys_sendmsg(void* p_msg) { if (do_in_main_thread( FROM_HERE, - base::Bind(&bta_sys_event, static_cast(p_msg))) != + base::BindOnce(&bta_sys_event, static_cast(p_msg))) != BT_STATUS_SUCCESS) { LOG(ERROR) << __func__ << ": do_in_main_thread failed"; } diff --git a/system/bta/test/bta_ag_sco_test.cc b/system/bta/test/bta_ag_sco_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..2ef8abb828c1ef36bb81497299f6d90bce5969f1 --- /dev/null +++ b/system/bta/test/bta_ag_sco_test.cc @@ -0,0 +1,113 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "bta/ag/bta_ag_int.h" +#include "bta/include/bta_le_audio_api.h" +#include "stack/btm/btm_int_types.h" +#include "test/mock/mock_device_esco_parameters.h" + +bool btm_peer_supports_esco_ev3(const RawAddress& remote_bda) { return true; } +tBTM_CB btm_cb; +LeAudioClient* LeAudioClient::Get() { return nullptr; } + +const RawAddress kRawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); + +class BtaAgScoParameterSelectionTest + : public ::testing::TestWithParam< + std::tuple> { + protected: + void SetUp() override { + test::mock::device_esco_parameters::esco_parameters_for_codec.body = + [this](esco_codec_t codec) { + this->codec = codec; + return enh_esco_params_t{}; + }; + } + void TearDown() override { + test::mock::device_esco_parameters::esco_parameters_for_codec = {}; + } + esco_codec_t codec; +}; + +TEST_P(BtaAgScoParameterSelectionTest, create_sco_cvsd) { + bta_ag_api_set_active_device(kRawAddress); + + const auto [feature, peer_feature, is_local] = GetParam(); + tBTA_AG_SCB scb{ + .peer_addr = kRawAddress, + .features = feature, + .peer_features = peer_feature, + .sco_idx = BTM_INVALID_SCO_INDEX, + .inuse_codec = UUID_CODEC_CVSD, + }; + + this->codec = ESCO_CODEC_UNKNOWN; + bta_ag_create_sco(&scb, is_local); + if ((scb.features & BTA_AG_FEAT_ESCO_S4) && + (scb.peer_features & BTA_AG_PEER_FEAT_ESCO_S4)) { + ASSERT_EQ(this->codec, ESCO_CODEC_CVSD_S4); + } else { + ASSERT_EQ(this->codec, ESCO_CODEC_CVSD_S3); + } +} + +TEST_P(BtaAgScoParameterSelectionTest, create_pending_sco_cvsd) { + bta_ag_api_set_active_device(kRawAddress); + + const auto [feature, peer_feature, is_local] = GetParam(); + tBTA_AG_SCB scb{ + .peer_addr = kRawAddress, + .features = feature, + .peer_features = peer_feature, + .sco_idx = BTM_INVALID_SCO_INDEX, + .inuse_codec = UUID_CODEC_CVSD, + }; + + this->codec = ESCO_CODEC_UNKNOWN; + bta_ag_create_pending_sco(&scb, is_local); + if ((scb.features & BTA_AG_FEAT_ESCO_S4) && + (scb.peer_features & BTA_AG_PEER_FEAT_ESCO_S4)) { + ASSERT_EQ(this->codec, ESCO_CODEC_CVSD_S4); + } else { + ASSERT_EQ(this->codec, ESCO_CODEC_CVSD_S3); + } +} + +std::vector> +BtaAgScoParameterSelectionTestParameters() { + tBTA_AG_FEAT features[] = {0, BTA_AG_FEAT_ESCO_S4}; + tBTA_AG_PEER_FEAT peer_features[] = {0, BTA_AG_PEER_FEAT_ESCO_S4}; + bool is_local_or_orig[] = {false, true}; + std::vector> params; + + for (auto i : features) { + for (auto j : peer_features) { + for (auto k : is_local_or_orig) { + params.push_back({i, j, k}); + } + } + } + return params; +} + +INSTANTIATE_TEST_SUITE_P( + BtaAgScoParameterSelectionTests, BtaAgScoParameterSelectionTest, + ::testing::ValuesIn(BtaAgScoParameterSelectionTestParameters())); diff --git a/system/bta/test/bta_ag_test.cc b/system/bta/test/bta_ag_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..f405288346cf947bf2bfded9dd6036d5b42ff239 --- /dev/null +++ b/system/bta/test/bta_ag_test.cc @@ -0,0 +1,316 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "bta/ag/bta_ag_int.h" +#include "bta/include/bta_ag_swb_aptx.h" +#include "bta/include/bta_api.h" +#include "bta/include/bta_dm_api.h" +#include "bta/include/bta_hf_client_api.h" +#include "bta/include/bta_le_audio_api.h" +#include "btif/include/stack_manager.h" +#include "common/message_loop_thread.h" +#include "os/system_properties.h" +#include "osi/include/compat.h" +#include "stack/btm/btm_int_types.h" +#include "stack/include/bt_device_type.h" +#include "stack/include/bt_name.h" +#include "stack/include/btm_status.h" +#include "test/common/main_handler.h" +#include "test/common/mock_functions.h" +#include "test/fake/fake_osi.h" +#include "test/mock/mock_bta_sys_main.h" +#include "test/mock/mock_device_esco_parameters.h" +#include "test/mock/mock_osi_alarm.h" +#include "test/mock/mock_stack_acl.h" + +#define TEST_BT com::android::bluetooth::flags + +namespace { + +bool bta_ag_hdl_event(const BT_HDR_RIGID* p_msg) { return true; }; +void BTA_AgDisable() { bta_sys_deregister(BTA_ID_AG); } + +const tBTA_SYS_REG bta_ag_reg = {bta_ag_hdl_event, BTA_AgDisable}; + +} // namespace + +const std::string kBtCodecAptxVoiceEnabled = + "bluetooth.hfp.codec_aptx_voice.enabled"; + +static bool enable_aptx_voice_property(bool enable) { + const std::string value = enable ? "true" : "false"; + bool result = + bluetooth::os::SetSystemProperty(kBtCodecAptxVoiceEnabled, value); + auto codec_aptx_voice_enabled = + bluetooth::os::GetSystemProperty(kBtCodecAptxVoiceEnabled); + return result && codec_aptx_voice_enabled && + (codec_aptx_voice_enabled.value() == value); +} + +class BtaAgTest : public testing::Test { + protected: + void SetUp() override { + reset_mock_function_count_map(); + fake_osi_ = std::make_unique(); + + main_thread_start_up(); + post_on_bt_main([]() { LOG_INFO("Main thread started up"); }); + + bta_sys_register(BTA_ID_AG, &bta_ag_reg); + + bta_ag_cb.p_cback = [](tBTA_AG_EVT event, tBTA_AG* p_data) {}; + RawAddress::FromString("00:11:22:33:44:55", addr); + test::mock::device_esco_parameters::esco_parameters_for_codec.body = + [this](esco_codec_t codec) { + this->codec = codec; + return enh_esco_params_t{}; + }; + } + void TearDown() override { + test::mock::device_esco_parameters::esco_parameters_for_codec = {}; + bta_sys_deregister(BTA_ID_AG); + post_on_bt_main([]() { LOG_INFO("Main thread shutting down"); }); + main_thread_shut_down(); + } + + std::unique_ptr fake_osi_; + const char test_strings[5][13] = {"0,4,6,7", "4,6,7", "test,0,4", "9,8,7", + "4,6,7,test"}; + uint32_t tmp_num = 0xFFFF; + RawAddress addr; + esco_codec_t codec; +}; + +TEST_F_WITH_FLAGS(BtaAgTest, nop, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + bool status = true; + ASSERT_EQ(true, status); +} + +class BtaAgSwbTest : public BtaAgTest { + protected: + void SetUp() override { BtaAgTest::SetUp(); } + void TearDown() override { BtaAgTest::TearDown(); } +}; + +TEST_F_WITH_FLAGS(BtaAgSwbTest, parse_qac_at_command, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + tBTA_AG_PEER_CODEC codec = bta_ag_parse_qac((char*)test_strings[0]); + codec = bta_ag_parse_qac((char*)test_strings[0]); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK); + + codec = bta_ag_parse_qac((char*)test_strings[1]); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK); + + codec = bta_ag_parse_qac((char*)test_strings[2]); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK); + + codec = bta_ag_parse_qac((char*)test_strings[3]); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK); + + codec = bta_ag_parse_qac((char*)test_strings[4]); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK); + ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK); +} + +class BtaAgActTest : public BtaAgTest { + protected: + void SetUp() override { BtaAgTest::SetUp(); } + void TearDown() override { BtaAgTest::TearDown(); } +}; + +TEST_F_WITH_FLAGS(BtaAgActTest, set_codec_q0_success, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0]; + const tBTA_AG_DATA data = {.api_setcodec.codec = + BTA_AG_SCO_APTX_SWB_SETTINGS_Q0}; + + bta_ag_cb.p_cback = [](tBTA_AG_EVT event, tBTA_AG* p_data) { + tBTA_AG_VAL* val = (tBTA_AG_VAL*)p_data; + ASSERT_EQ(val->num, BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + ASSERT_EQ(val->hdr.status, BTA_AG_SUCCESS); + }; + + p_scb->peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + p_scb->sco_codec = BTM_SCO_CODEC_NONE; + p_scb->codec_updated = false; + + bta_ag_setcodec(p_scb, data); + ASSERT_EQ(p_scb->sco_codec, BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + ASSERT_TRUE( + bluetooth::os::SetSystemProperty(kBtCodecAptxVoiceEnabled, "false")); +} + +TEST_F_WITH_FLAGS(BtaAgActTest, set_codec_q1_fail_unsupported, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0]; + const tBTA_AG_DATA data = {.api_setcodec.codec = + BTA_AG_SCO_APTX_SWB_SETTINGS_Q1}; + + ASSERT_TRUE(enable_aptx_voice_property(true)); + + bta_ag_cb.p_cback = [](tBTA_AG_EVT event, tBTA_AG* p_data) { + tBTA_AG_VAL* val = (tBTA_AG_VAL*)p_data; + ASSERT_EQ(val->num, BTA_AG_SCO_APTX_SWB_SETTINGS_Q1); + ASSERT_EQ(val->hdr.status, BTA_AG_FAIL_RESOURCES); + }; + + p_scb->peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0; + p_scb->sco_codec = BTM_SCO_CODEC_NONE; + p_scb->codec_updated = false; + + bta_ag_setcodec(p_scb, data); + ASSERT_TRUE(enable_aptx_voice_property(false)); +} + +class BtaAgCmdTest : public BtaAgTest { + protected: + void SetUp() override { BtaAgTest::SetUp(); } + void TearDown() override { BtaAgTest::TearDown(); } +}; + +TEST_F_WITH_FLAGS(BtaAgCmdTest, at_hfp_cback__qac_ev_codec_disabled, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + tBTA_AG_SCB p_scb = { + .peer_addr = addr, + .app_id = 0, + }; + + ASSERT_TRUE(enable_aptx_voice_property(false)); + + bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QAC_EVT, 0, (char*)&test_strings[0][0], + (char*)&test_strings[0][12], + BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + ASSERT_FALSE(p_scb.codec_updated); + ASSERT_FALSE(p_scb.is_aptx_swb_codec); + ASSERT_EQ(1, get_func_call_count("PORT_WriteData")); +} + +TEST_F_WITH_FLAGS(BtaAgCmdTest, at_hfp_cback__qac_ev_codec_enabled, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + tBTA_AG_SCB p_scb = {.peer_addr = addr, + .app_id = 0, + .peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK}; + + ASSERT_TRUE(enable_aptx_voice_property(true)); + + bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QAC_EVT, 0, (char*)&test_strings[0][0], + (char*)&test_strings[0][12], + BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + ASSERT_TRUE(p_scb.codec_updated); + ASSERT_TRUE(p_scb.is_aptx_swb_codec); + ASSERT_EQ(2, get_func_call_count("PORT_WriteData")); + ASSERT_EQ(p_scb.sco_codec, BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + ASSERT_TRUE(enable_aptx_voice_property(false)); +} + +TEST_F_WITH_FLAGS(BtaAgCmdTest, at_hfp_cback__qcs_ev_codec_disabled, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + tBTA_AG_SCB p_scb = { + .peer_addr = addr, + .app_id = 0, + }; + + ASSERT_TRUE(enable_aptx_voice_property(false)); + + bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QCS_EVT, 0, (char*)&test_strings[0][0], + (char*)&test_strings[0][12], + BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + ASSERT_FALSE(p_scb.codec_updated); + ASSERT_FALSE(p_scb.is_aptx_swb_codec); + ASSERT_EQ(1, get_func_call_count("PORT_WriteData")); +} + +TEST_F_WITH_FLAGS(BtaAgCmdTest, at_hfp_cback__qcs_ev_codec_q0_enabled, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + tBTA_AG_SCB p_scb = {.peer_addr = addr, + .sco_idx = BTM_INVALID_SCO_INDEX, + .app_id = 0, + .sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0, + .is_aptx_swb_codec = true}; + + ASSERT_TRUE(enable_aptx_voice_property(true)); + + bta_ag_cb.sco.state = BTA_AG_SCO_CODEC_ST; + bta_ag_api_set_active_device(addr); + ASSERT_EQ(addr, bta_ag_get_active_device()); + + bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QCS_EVT, 0, (char*)&test_strings[0][0], + (char*)&test_strings[0][12], + BTA_AG_SCO_APTX_SWB_SETTINGS_Q0); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + ASSERT_EQ(2, get_func_call_count("esco_parameters_for_codec")); + ASSERT_EQ(1, get_func_call_count("BTM_SetEScoMode")); + ASSERT_EQ(1, get_func_call_count("BTM_CreateSco")); + ASSERT_EQ(this->codec, ESCO_CODEC_SWB_Q0); +} + +TEST_F_WITH_FLAGS(BtaAgCmdTest, + handle_swb_at_event__qcs_ev_codec_q1_fallback_to_q0, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, + hfp_codec_aptx_voice))) { + tBTA_AG_SCB p_scb = {.peer_addr = addr, + .sco_idx = BTM_INVALID_SCO_INDEX, + .app_id = 0, + .sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q1, + .codec_fallback = false, + .is_aptx_swb_codec = true}; + + ASSERT_TRUE(enable_aptx_voice_property(true)); + + bta_ag_cb.sco.state = BTA_AG_SCO_CODEC_ST; + bta_ag_api_set_active_device(addr); + ASSERT_EQ(addr, bta_ag_get_active_device()); + + bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QCS_EVT, 0, (char*)&test_strings[0][0], + (char*)&test_strings[0][12], + BTA_AG_SCO_APTX_SWB_SETTINGS_Q1); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + ASSERT_EQ(2, get_func_call_count("esco_parameters_for_codec")); + ASSERT_EQ(1, get_func_call_count("BTM_SetEScoMode")); + ASSERT_EQ(1, get_func_call_count("BTM_CreateSco")); + ASSERT_EQ(this->codec, ESCO_CODEC_SWB_Q0); + ASSERT_TRUE(enable_aptx_voice_property(false)); +} diff --git a/system/bta/test/bta_api_test.cc b/system/bta/test/bta_api_test.cc index 38134f5e48bb72b97007162b571b53c830578656..37f2e882530045c6f21b3e356efa9c8965abada6 100644 --- a/system/bta/test/bta_api_test.cc +++ b/system/bta/test/bta_api_test.cc @@ -20,12 +20,11 @@ #include #include -#include #include #include #include -#include "bta/sys/bta_sys.h" +#include "common/init_flags.h" #include "test/common/mock_functions.h" using namespace std::chrono_literals; diff --git a/system/bta/test/bta_av_test.cc b/system/bta/test/bta_av_test.cc index 617cf5c0fa83777fd448bf5799e5273d0d2e3415..7bbf6c5881bc87bd3b87aec9e011df0434a16b98 100644 --- a/system/bta/test/bta_av_test.cc +++ b/system/bta/test/bta_av_test.cc @@ -18,48 +18,33 @@ #include #include -#include - #include "bta/av/bta_av_int.h" -#include "bta/dm/bta_dm_int.h" #include "bta/hf_client/bta_hf_client_int.h" -#include "bta/include/bta_api.h" -#include "bta/include/bta_dm_api.h" -#include "bta/include/bta_hf_client_api.h" -#include "btif/include/stack_manager.h" -#include "common/message_loop_thread.h" -#include "osi/include/log.h" -#include "stack/include/btm_status.h" +#include "common/init_flags.h" #include "test/common/mock_functions.h" #include "test/mock/mock_osi_alarm.h" #include "test/mock/mock_stack_acl.h" -#include "test/mock/mock_stack_btm_sec.h" using namespace std::chrono_literals; +bool btif_av_both_enable(void) { return true; } + namespace { const RawAddress kRawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); } // namespace -// TODO move into mock -void BTM_block_role_switch_and_sniff_mode_for(const RawAddress& peer_addr) {} - struct alarm_t { alarm_t(const char* name){}; int any_value; }; -extern uint8_t appl_trace_level; - class BtaAvTest : public testing::Test { protected: void SetUp() override { reset_mock_function_count_map(); bluetooth::common::InitFlags::SetAllForTesting(); - appl_trace_level = BT_TRACE_LEVEL_VERBOSE; } void TearDown() override { - LOG_INFO("appl_trace_level:%hhu", appl_trace_level); } }; diff --git a/system/bta/test/bta_base_test.h b/system/bta/test/bta_base_test.h new file mode 100644 index 0000000000000000000000000000000000000000..74c1b2e5b26237be997650fa476758ad842e9d3e --- /dev/null +++ b/system/bta/test/bta_base_test.h @@ -0,0 +1,37 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "btm_client_interface.h" +#include "test/common/mock_functions.h" +#include "test/fake/fake_osi.h" +#include "test/mock/mock_stack_btm_interface.h" + +class BtaBaseTest : public testing::Test { + protected: + void SetUp() override { + reset_mock_function_count_map(); + reset_mock_btm_client_interface(); + fake_osi_ = std::make_unique(); + ASSERT_NE(get_btm_client_interface().lifecycle.btm_init, nullptr); + ASSERT_NE(get_btm_client_interface().lifecycle.btm_free, nullptr); + } + + void TearDown() override {} + + std::unique_ptr fake_osi_; +}; diff --git a/system/bta/test/bta_dip_test.cc b/system/bta/test/bta_dip_test.cc index 0f11e79a1841e548031b38bd05f4d9a40371f5ea..3ad0f1213b3500971b7f9eef9888a68f31fa5270 100644 --- a/system/bta/test/bta_dip_test.cc +++ b/system/bta/test/bta_dip_test.cc @@ -18,9 +18,11 @@ #include -#include "bta/sdp/bta_sdp_act.cc" +#include "bta/sdp/bta_sdp_int.h" +#include "btif/include/btif_sock_sdp.h" #include "main/shim/metrics_api.h" -#include "stack/sdp/sdp_api.cc" +#include "stack/include/sdpdefs.h" +#include "test/mock/mock_stack_sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -28,8 +30,7 @@ namespace { const RawAddress bdaddr({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); } // namespace -extern tBTA_SDP_CB bta_sdp_cb; -extern tBTA_SDP_CFG* p_bta_sdp_cfg; +tBTA_SDP_CB bta_sdp_cb; static tSDP_DISC_ATTR g_attr_service_class_id_list; static tSDP_DISC_ATTR g_sub_attr; @@ -41,19 +42,11 @@ static tSDP_DISC_ATTR g_attr_vendor_product_version; static tSDP_DISC_ATTR g_attr_vendor_product_primary_record; static tSDP_DISC_REC g_rec; -bool sdpu_compare_uuid_with_attr(const Uuid& uuid, tSDP_DISC_ATTR* p_attr) { - return true; -} - static void sdp_dm_cback(tBTA_SDP_EVT event, tBTA_SDP* p_data, void* user_data) { return; } -bool bluetooth::shim::CountCounterMetrics(int32_t key, int64_t count) { - return true; -} - class BtaDipTest : public ::testing::Test { protected: void SetUp() override { @@ -109,11 +102,22 @@ class BtaDipTest : public ::testing::Test { void TearDown() override {} }; +namespace bluetooth { +namespace testing { + +void bta_create_dip_sdp_record(bluetooth_sdp_record* record, + tSDP_DISC_REC* p_rec); +void bta_sdp_search_cback(const RawAddress& bd_addr, tSDP_RESULT result, + const void* user_data); + +} // namespace testing +} // namespace bluetooth + // Test that bta_create_dip_sdp_record can parse sdp record to bluetooth_sdp_record correctly TEST_F(BtaDipTest, test_bta_create_dip_sdp_record) { bluetooth_sdp_record record; - bta_create_dip_sdp_record(&record, &g_rec); + bluetooth::testing::bta_create_dip_sdp_record(&record, &g_rec); ASSERT_EQ(record.dip.spec_id, 0x0103); ASSERT_EQ(record.dip.vendor, 0x18d1); @@ -147,7 +151,7 @@ TEST_F(BtaDipTest, test_invalid_type_checks) { g_attr_vendor_product_primary_record.attr_len_type = (UINT_DESC_TYPE<<12)|1; g_attr_vendor_product_primary_record.attr_value.v.u8 = 1; - bta_create_dip_sdp_record(&record, &g_rec); + bluetooth::testing::bta_create_dip_sdp_record(&record, &g_rec); ASSERT_EQ(record.dip.spec_id, 0); ASSERT_EQ(record.dip.vendor, 0); @@ -182,7 +186,7 @@ TEST_F(BtaDipTest, test_invalid_size_checks) { g_attr_vendor_product_primary_record.attr_len_type = (BOOLEAN_DESC_TYPE<<12)|2; g_attr_vendor_product_primary_record.attr_value.v.u8 = 1; - bta_create_dip_sdp_record(&record, &g_rec); + bluetooth::testing::bta_create_dip_sdp_record(&record, &g_rec); ASSERT_EQ(record.dip.spec_id, 0); ASSERT_EQ(record.dip.vendor, 0); @@ -197,6 +201,6 @@ TEST_F(BtaDipTest, test_bta_sdp_search_cback) { Uuid* userdata = (Uuid*)malloc(sizeof(Uuid)); memcpy(userdata, &UUID_DIP, sizeof(UUID_DIP)); - bta_sdp_search_cback(SDP_SUCCESS, userdata); + bluetooth::testing::bta_sdp_search_cback(RawAddress::kEmpty, SDP_SUCCESS, + userdata); } - diff --git a/system/bta/test/bta_disc_test.cc b/system/bta/test/bta_disc_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..2dbac0af0d44755dca52b10d89206980af5b27b4 --- /dev/null +++ b/system/bta/test/bta_disc_test.cc @@ -0,0 +1,296 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include + +#include "bta/dm/bta_dm_disc.h" +#include "bta/dm/bta_dm_disc_int.h" +#include "stack/btm/neighbor_inquiry.h" +#include "stack/include/gatt_api.h" +#include "test/common/main_handler.h" +#include "test/fake/fake_osi.h" +#include "types/bt_transport.h" + +namespace { + +const RawAddress kRawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); + +} + +// Test hooks +namespace bluetooth { +namespace legacy { +namespace testing { + +void bta_dm_disc_init_search_cb(tBTA_DM_SEARCH_CB& bta_dm_search_cb); +bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, + tBT_TRANSPORT transport); +const tBTA_DM_SEARCH_CB& bta_dm_disc_search_cb(); +tBTA_DM_SEARCH_CB bta_dm_disc_get_search_cb(); +void bta_dm_disc_search_cb(const tBTA_DM_SEARCH_CB& search_cb); +void bta_dm_discover_next_device(); +void bta_dm_execute_queued_request(); +void bta_dm_find_services(const RawAddress& bd_addr); +void bta_dm_inq_cmpl(uint8_t num); +void bta_dm_inq_cmpl_cb(void* p_result); +void bta_dm_observe_cmpl_cb(void* p_result); +void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, + uint16_t eir_len); +void bta_dm_opportunistic_observe_results_cb(tBTM_INQ_RESULTS* p_inq, + const uint8_t* p_eir, + uint16_t eir_len); +void bta_dm_queue_search(tBTA_DM_MSG* p_data); +void bta_dm_sdp_result(tBTA_DM_MSG* p_data); +void bta_dm_search_result(tBTA_DM_MSG* p_data); +void bta_dm_search_timer_cback(void* data); +void bta_dm_service_search_remname_cback(const RawAddress& bd_addr, + DEV_CLASS dc, tBTM_BD_NAME bd_name); +void bta_dm_start_scan(uint8_t duration_sec, bool low_latency_scan = false); +void store_avrcp_profile_feature(tSDP_DISC_REC* sdp_rec); + +} // namespace testing +} // namespace legacy +} // namespace bluetooth + +class BtaDiscTest : public testing::Test { + protected: + void SetUp() override { + fake_osi_ = std::make_unique(); + main_thread_start_up(); + } + + void TearDown() override { + sync_main_handler(); + main_thread_shut_down(); + } + + std::unique_ptr fake_osi_; +}; + +TEST_F(BtaDiscTest, nop) {} + +TEST_F(BtaDiscTest, DumpsysBtaDmDisc) { + std::FILE* file = std::tmpfile(); + DumpsysBtaDmDisc(fileno(file)); +} + +TEST_F(BtaDiscTest, bta_dm_ble_csis_observe) { + bta_dm_ble_csis_observe(true, [](tBTA_DM_SEARCH_EVT, tBTA_DM_SEARCH*) {}); +}; + +TEST_F(BtaDiscTest, bta_dm_ble_csis_observe__false) { + bta_dm_ble_csis_observe(false, [](tBTA_DM_SEARCH_EVT, tBTA_DM_SEARCH*) {}); +}; + +TEST_F(BtaDiscTest, bta_dm_ble_scan) { + // bool start, uint8_t duration_sec, bool low_latency_scan + constexpr bool kStartLeScan = true; + constexpr bool kStopLeScan = false; + const uint8_t duration_in_seconds = 5; + constexpr bool kLowLatencyScan = true; + constexpr bool kHighLatencyScan = false; + + bta_dm_ble_scan(kStartLeScan, duration_in_seconds, kLowLatencyScan); + bta_dm_ble_scan(kStopLeScan, duration_in_seconds, kLowLatencyScan); + + bta_dm_ble_scan(kStartLeScan, duration_in_seconds, kHighLatencyScan); + bta_dm_ble_scan(kStopLeScan, duration_in_seconds, kHighLatencyScan); +} + +TEST_F(BtaDiscTest, bta_dm_disc_discover_next_device) { + bta_dm_disc_discover_next_device(); +} + +TEST_F(BtaDiscTest, bta_dm_disc_remove_device) { + bta_dm_disc_remove_device(kRawAddress); +} + +TEST_F(BtaDiscTest, bta_dm_discover_next_device) { + bluetooth::legacy::testing::bta_dm_discover_next_device(); +} + +TEST_F(BtaDiscTest, bta_dm_execute_queued_request) { + bluetooth::legacy::testing::bta_dm_execute_queued_request(); +} + +TEST_F(BtaDiscTest, bta_dm_find_services) { + bluetooth::legacy::testing::bta_dm_find_services(kRawAddress); +} + +TEST_F(BtaDiscTest, bta_dm_inq_cmpl) { + bluetooth::legacy::testing::bta_dm_inq_cmpl(0); + bluetooth::legacy::testing::bta_dm_inq_cmpl(1); + bluetooth::legacy::testing::bta_dm_inq_cmpl(2); + bluetooth::legacy::testing::bta_dm_inq_cmpl(255); +} + +TEST_F(BtaDiscTest, bta_dm_inq_cmpl_cb) { + tBTM_INQUIRY_CMPL complete; + bluetooth::legacy::testing::bta_dm_inq_cmpl_cb(&complete); +} + +TEST_F(BtaDiscTest, bta_dm_observe_cmpl_cb) { + tBTM_INQUIRY_CMPL complete; + bluetooth::legacy::testing::bta_dm_observe_cmpl_cb(&complete); +} +TEST_F(BtaDiscTest, bta_dm_observe_results_cb) { + tBTM_INQ_RESULTS result; + const uint8_t p_eir[] = {0x0, 0x1, 0x2, 0x3}; + uint16_t eir_len = sizeof(p_eir); + bluetooth::legacy::testing::bta_dm_observe_results_cb(&result, p_eir, + eir_len); +} + +TEST_F(BtaDiscTest, bta_dm_opportunistic_observe_results_cb) { + tBTM_INQ_RESULTS result; + const uint8_t p_eir[] = {0x0, 0x1, 0x2, 0x3}; + uint16_t eir_len = sizeof(p_eir); + bluetooth::legacy::testing::bta_dm_opportunistic_observe_results_cb( + &result, p_eir, eir_len); +} + +TEST_F(BtaDiscTest, bta_dm_queue_search) { + tBTA_DM_MSG msg = { + .search = {}, + }; + bluetooth::legacy::testing::bta_dm_queue_search(&msg); + + // Release the queued search + bta_dm_disc_stop(); +} + +TEST_F(BtaDiscTest, bta_dm_read_remote_device_name) { + bluetooth::legacy::testing::bta_dm_read_remote_device_name( + kRawAddress, BT_TRANSPORT_BR_EDR); +} + +TEST_F(BtaDiscTest, bta_dm_search_result) { + tBTA_DM_MSG msg = { + .disc_result = {}, + }; + bluetooth::legacy::testing::bta_dm_search_result(&msg); +} + +TEST_F(BtaDiscTest, bta_dm_search_sm_execute) { + BT_HDR_RIGID bt_hdr = {}; + bta_dm_search_sm_execute(&bt_hdr); +} + +TEST_F(BtaDiscTest, bta_dm_search_timer_cback) { + constexpr void* kUnusedPointer = nullptr; + bluetooth::legacy::testing::bta_dm_search_timer_cback(kUnusedPointer); +} + +TEST_F(BtaDiscTest, bta_dm_service_search_remname_cback__expected_name) { + DEV_CLASS dc; + tBTM_BD_NAME bd_name; + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.peer_bdaddr = kRawAddress, + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); + bluetooth::legacy::testing::bta_dm_service_search_remname_cback(kRawAddress, + dc, bd_name); +} + +TEST_F(BtaDiscTest, bta_dm_service_search_remname_cback__unexpected_name) { + DEV_CLASS dc; + tBTM_BD_NAME bd_name; + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.peer_bdaddr = RawAddress::kAny; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); + bluetooth::legacy::testing::bta_dm_service_search_remname_cback(kRawAddress, + dc, bd_name); +} + +TEST_F(BtaDiscTest, bta_dm_start_scan) { + constexpr bool kLowLatencyScan = true; + constexpr bool kHighLatencyScan = false; + const uint8_t duration_sec = 5; + bluetooth::legacy::testing::bta_dm_start_scan(duration_sec, kLowLatencyScan); + bluetooth::legacy::testing::bta_dm_start_scan(duration_sec, kHighLatencyScan); +} + +TEST_F(BtaDiscTest, store_avrcp_profile_feature) { + tSDP_DISC_REC sdp_rec = {}; + bluetooth::legacy::testing::store_avrcp_profile_feature(&sdp_rec); +} + +TEST_F(BtaDiscTest, bta_dm_disc_start_device_discovery) { + bta_dm_disc_start_device_discovery( + [](tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) {}); +} + +TEST_F(BtaDiscTest, bta_dm_disc_stop_device_discovery) { + bta_dm_disc_stop_device_discovery(); +} + +TEST_F(BtaDiscTest, bta_dm_disc_start_service_discovery__BT_TRANSPORT_AUTO) { + bta_dm_disc_start_service_discovery( + [](tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) {}, kRawAddress, + BT_TRANSPORT_AUTO); +} + +TEST_F(BtaDiscTest, bta_dm_disc_start_service_discovery__BT_TRANSPORT_BR_EDR) { + bta_dm_disc_start_service_discovery( + [](tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) {}, kRawAddress, + BT_TRANSPORT_BR_EDR); +} + +TEST_F(BtaDiscTest, bta_dm_disc_start_service_discovery__BT_TRANSPORT_LE) { + bta_dm_disc_start_service_discovery( + [](tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) {}, kRawAddress, + BT_TRANSPORT_LE); +} + +TEST_F(BtaDiscTest, bta_dm_disc_stop_service_discovery__BT_TRANSPORT_AUTO) { + bta_dm_disc_stop_service_discovery(kRawAddress, BT_TRANSPORT_AUTO); +} + +TEST_F(BtaDiscTest, bta_dm_disc_stop_service_discovery__BT_TRANSPORT_BR_EDR) { + bta_dm_disc_stop_service_discovery(kRawAddress, BT_TRANSPORT_BR_EDR); +} + +TEST_F(BtaDiscTest, bta_dm_disc_stop_service_discovery__BT_TRANSPORT_LE) { + bta_dm_disc_stop_service_discovery(kRawAddress, BT_TRANSPORT_LE); +} + +TEST_F(BtaDiscTest, init_bta_dm_search_cb__conn_id) { + constexpr uint16_t kConnId = 123; + + // Set the global search block target field to some non-reset value + tBTA_DM_SEARCH_CB search_cb = {}; + search_cb.conn_id = kConnId; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); + // Get the global search block and ensure it is still intact + search_cb = bluetooth::legacy::testing::bta_dm_disc_search_cb(); + ASSERT_EQ(kConnId, search_cb.conn_id); + + // Initialize *this* global search block + bluetooth::legacy::testing::bta_dm_disc_init_search_cb(search_cb); + + // Verify *this* global search block field reset value is correct + ASSERT_EQ(search_cb.conn_id, GATT_INVALID_CONN_ID); + + // Get the global search block and ensure it is still intact + search_cb = bluetooth::legacy::testing::bta_dm_disc_search_cb(); + ASSERT_EQ(kConnId, search_cb.conn_id); +} diff --git a/system/bta/test/bta_dm_cust_uuid_test.cc b/system/bta/test/bta_dm_cust_uuid_test.cc index a0cdcb565704dd6f87a6bf4e7cc63d2ceff7a11a..9f47e734dfa5c6ca546811226f34b624fb20d66d 100644 --- a/system/bta/test/bta_dm_cust_uuid_test.cc +++ b/system/bta/test/bta_dm_cust_uuid_test.cc @@ -19,14 +19,39 @@ #include #include "bta/dm/bta_dm_int.h" +#include "bta/test/bta_base_test.h" +#include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" +#include "stack/include/btm_status.h" +#include "test/mock/mock_stack_btm_interface.h" #include "types/bluetooth/uuid.h" using bluetooth::Uuid; -class BtaCustUuid : public testing::Test { +class BtaCustUuid : public BtaBaseTest { protected: - void SetUp() override { bta_dm_cb = {}; } + void SetUp() override { + BtaBaseTest::SetUp(); + bta_dm_cb = {}; + mock_btm_client_interface.eir.BTM_WriteEIR = + [](BT_HDR* p_buf) -> tBTM_STATUS { + osi_free(p_buf); + return BTM_SUCCESS; + }; + mock_btm_client_interface.eir.BTM_GetEirSupportedServices = + [](uint32_t* p_eir_uuid, uint8_t** p, uint8_t max_num_uuid16, + uint8_t* p_num_uuid16) -> uint8_t { return 0; }; + mock_btm_client_interface.eir.BTM_WriteEIR = + [](BT_HDR* p_buf) -> tBTM_STATUS { + osi_free(p_buf); + return BTM_SUCCESS; + }; + mock_btm_client_interface.local.BTM_ReadLocalDeviceNameFromController = + [](tBTM_CMPL_CB* cb) -> tBTM_STATUS { return BTM_CMD_STARTED; }; + mock_btm_client_interface.security.BTM_SecRegister = + [](const tBTM_APPL_INFO* p_cb_info) -> bool { return true; }; + } + void TearDown() override { BtaBaseTest::TearDown(); } }; namespace { diff --git a/system/bta/test/bta_dm_test.cc b/system/bta/test/bta_dm_test.cc index c7e6b16b9db7f639cbe495c3eeac481c89ecd074..64453338ee2679ac2571b9c6de97b339f6e8d134 100644 --- a/system/bta/test/bta_dm_test.cc +++ b/system/bta/test/bta_dm_test.cc @@ -16,46 +16,38 @@ #include #include +#include #include -#include +#include +#include "bta/dm/bta_dm_disc.h" +#include "bta/dm/bta_dm_disc_int.h" #include "bta/dm/bta_dm_int.h" +#include "bta/dm/bta_dm_sec_int.h" #include "bta/hf_client/bta_hf_client_int.h" #include "bta/include/bta_api.h" -#include "bta/include/bta_dm_api.h" -#include "bta/include/bta_hf_client_api.h" -#include "btif/include/stack_manager.h" -#include "common/message_loop_thread.h" +#include "bta/test/bta_base_test.h" #include "osi/include/compat.h" +#include "osi/include/osi.h" #include "stack/include/btm_status.h" #include "test/common/main_handler.h" #include "test/common/mock_functions.h" #include "test/mock/mock_osi_alarm.h" #include "test/mock/mock_osi_allocator.h" #include "test/mock/mock_stack_acl.h" -#include "test/mock/mock_stack_btm_sec.h" +#include "test/mock/mock_stack_btm_interface.h" using namespace std::chrono_literals; -extern struct btm_client_interface_t btm_client_interface; - -namespace base { -class MessageLoop; -} // namespace base - namespace { constexpr uint8_t kUnusedTimer = BTA_ID_MAX; const RawAddress kRawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); const RawAddress kRawAddress2({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}); -constexpr char kRemoteName[] = "TheRemoteName"; -const char* test_flags[] = { - "INIT_logging_debug_enabled_for_all=true", - nullptr, -}; +constexpr char kRemoteName[] = "TheRemoteName"; -bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg) { return true; } +bool bta_dm_search_sm_execute(const BT_HDR_RIGID* p_msg) { return true; } void bta_dm_search_sm_disable() { bta_sys_deregister(BTA_ID_DM_SEARCH); } const tBTA_SYS_REG bta_dm_search_reg = {bta_dm_search_sm_execute, @@ -63,39 +55,31 @@ const tBTA_SYS_REG bta_dm_search_reg = {bta_dm_search_sm_execute, } // namespace -struct alarm_t { - alarm_t(const char* name){}; - int any_value; -}; +namespace bluetooth { +namespace legacy { +namespace testing { -class BtaDmTest : public testing::Test { +const tBTA_DM_SEARCH_CB& bta_dm_disc_search_cb(); +tBTA_DM_SEARCH_CB bta_dm_disc_get_search_cb(); +void bta_dm_deinit_cb(); +void bta_dm_disc_search_cb(const tBTA_DM_SEARCH_CB& search_cb); +void bta_dm_init_cb(); +void bta_dm_remote_name_cmpl(const tBTA_DM_MSG* p_data); +void bta_dm_sdp_result(tBTA_DM_MSG* p_data); + +} // namespace testing +} // namespace legacy +} // namespace bluetooth + +class BtaDmTest : public BtaBaseTest { protected: void SetUp() override { - reset_mock_function_count_map(); - bluetooth::common::InitFlags::Load(test_flags); - test::mock::osi_alarm::alarm_new.body = [](const char* name) -> alarm_t* { - return new alarm_t(name); - }; - test::mock::osi_alarm::alarm_free.body = [](alarm_t* alarm) { - delete alarm; - }; - test::mock::osi_allocator::osi_malloc.body = [](size_t size) { - return malloc(size); - }; - test::mock::osi_allocator::osi_calloc.body = [](size_t size) { - return calloc(1UL, size); - }; - test::mock::osi_allocator::osi_free.body = [](void* ptr) { free(ptr); }; - test::mock::osi_allocator::osi_free_and_reset.body = [](void** ptr) { - free(*ptr); - *ptr = nullptr; - }; - + BtaBaseTest::SetUp(); main_thread_start_up(); post_on_bt_main([]() { LOG_INFO("Main thread started up"); }); bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg); - bta_dm_init_cb(); + bluetooth::legacy::testing::bta_dm_init_cb(); for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) { for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) { @@ -105,17 +89,31 @@ class BtaDmTest : public testing::Test { } void TearDown() override { bta_sys_deregister(BTA_ID_DM_SEARCH); - bta_dm_deinit_cb(); + bluetooth::legacy::testing::bta_dm_deinit_cb(); post_on_bt_main([]() { LOG_INFO("Main thread shutting down"); }); main_thread_shut_down(); + BtaBaseTest::TearDown(); + } +}; - test::mock::osi_alarm::alarm_new = {}; - test::mock::osi_alarm::alarm_free = {}; - test::mock::osi_allocator::osi_malloc = {}; - test::mock::osi_allocator::osi_calloc = {}; - test::mock::osi_allocator::osi_free = {}; - test::mock::osi_allocator::osi_free_and_reset = {}; +class BtaDmCustomAlarmTest : public BtaDmTest { + protected: + void SetUp() override { + BtaDmTest::SetUp(); + test::mock::osi_alarm::alarm_set_on_mloop.body = + [this](alarm_t* alarm, uint64_t interval_ms, alarm_callback_t cb, + void* data) { + ASSERT_TRUE(alarm != nullptr); + this->alarm_callback = cb; + this->alarm_data = data; + }; } + void TearDown() override { + test::mock::osi_alarm::alarm_set_on_mloop = {}; + BtaDmTest::TearDown(); + } + alarm_callback_t alarm_callback; + void* alarm_data{nullptr}; }; TEST_F(BtaDmTest, nop) { @@ -123,86 +121,47 @@ TEST_F(BtaDmTest, nop) { ASSERT_EQ(true, status); } -TEST_F(BtaDmTest, disable_no_acl_links) { +TEST_F(BtaDmCustomAlarmTest, disable_no_acl_links) { bta_dm_cb.disabling = true; - alarm_callback_t alarm_callback; - void* alarm_data{nullptr}; - test::mock::osi_alarm::alarm_set_on_mloop.body = - [&alarm_callback, &alarm_data](alarm_t* alarm, uint64_t interval_ms, - alarm_callback_t cb, void* data) { - ASSERT_TRUE(alarm != nullptr); - alarm_callback = cb; - alarm_data = data; - }; - bta_dm_disable(); // Waiting for all ACL connections to drain ASSERT_EQ(0, get_func_call_count("btm_remove_acl")); ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); // Execute timer callback - alarm_callback(alarm_data); + alarm_callback(this->alarm_data); ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(0, get_func_call_count("BTIF_dm_disable")); ASSERT_EQ(1, get_func_call_count("future_ready")); ASSERT_TRUE(!bta_dm_cb.disabling); - - test::mock::osi_alarm::alarm_set_on_mloop = {}; } -TEST_F(BtaDmTest, disable_first_pass_with_acl_links) { - uint16_t links_up = 1; - test::mock::stack_acl::BTM_GetNumAclLinks.body = [&links_up]() { - return links_up; - }; +TEST_F(BtaDmCustomAlarmTest, disable_first_pass_with_acl_links) { + test::mock::stack_acl::BTM_GetNumAclLinks.body = []() { return 1; }; bta_dm_cb.disabling = true; // ACL link is open bta_dm_cb.device_list.count = 1; - alarm_callback_t alarm_callback; - void* alarm_data{nullptr}; - test::mock::osi_alarm::alarm_set_on_mloop.body = - [&alarm_callback, &alarm_data](alarm_t* alarm, uint64_t interval_ms, - alarm_callback_t cb, void* data) { - ASSERT_TRUE(alarm != nullptr); - alarm_callback = cb; - alarm_data = data; - }; - bta_dm_disable(); // Waiting for all ACL connections to drain ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(0, get_func_call_count("BTIF_dm_disable")); - links_up = 0; + test::mock::stack_acl::BTM_GetNumAclLinks.body = []() { return 0; }; // First disable pass - alarm_callback(alarm_data); + alarm_callback(this->alarm_data); ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(1, get_func_call_count("BTIF_dm_disable")); ASSERT_TRUE(!bta_dm_cb.disabling); test::mock::stack_acl::BTM_GetNumAclLinks = {}; - test::mock::osi_alarm::alarm_set_on_mloop = {}; } -TEST_F(BtaDmTest, disable_second_pass_with_acl_links) { - uint16_t links_up = 1; - test::mock::stack_acl::BTM_GetNumAclLinks.body = [&links_up]() { - return links_up; - }; +TEST_F(BtaDmCustomAlarmTest, disable_second_pass_with_acl_links) { + test::mock::stack_acl::BTM_GetNumAclLinks.body = []() { return 1; }; bta_dm_cb.disabling = true; // ACL link is open bta_dm_cb.device_list.count = 1; - alarm_callback_t alarm_callback; - void* alarm_data{nullptr}; - test::mock::osi_alarm::alarm_set_on_mloop.body = - [&alarm_callback, &alarm_data](alarm_t* alarm, uint64_t interval_ms, - alarm_callback_t cb, void* data) { - ASSERT_TRUE(alarm != nullptr); - alarm_callback = cb; - alarm_data = data; - }; - bta_dm_disable(); // Waiting for all ACL connections to drain ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(0, get_func_call_count("BTIF_dm_disable")); @@ -219,7 +178,6 @@ TEST_F(BtaDmTest, disable_second_pass_with_acl_links) { ASSERT_TRUE(!bta_dm_cb.disabling); test::mock::stack_acl::BTM_GetNumAclLinks = {}; - test::mock::osi_alarm::alarm_set_on_mloop = {}; } namespace { @@ -250,24 +208,27 @@ void bta_dm_remname_cback(const tBTM_REMOTE_DEV_NAME* p); tBT_TRANSPORT bta_dm_determine_discovery_transport( const RawAddress& remote_bd_addr); +void btm_set_local_io_caps(uint8_t io_caps); + +tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data); + } // namespace testing } // namespace legacy } // namespace bluetooth TEST_F(BtaDmTest, bta_dm_set_encryption) { - const RawAddress bd_addr{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; const tBT_TRANSPORT transport{BT_TRANSPORT_LE}; const tBTM_BLE_SEC_ACT sec_act{BTM_BLE_SEC_NONE}; // Callback not provided - bta_dm_set_encryption(bd_addr, transport, nullptr, sec_act); + bta_dm_set_encryption(kRawAddress, transport, nullptr, sec_act); // Device connection does not exist - bta_dm_set_encryption(bd_addr, transport, BTA_DM_ENCRYPT_CBACK, sec_act); + bta_dm_set_encryption(kRawAddress, transport, BTA_DM_ENCRYPT_CBACK, sec_act); // Setup a connected device tBTA_DM_PEER_DEVICE* device = - bluetooth::legacy::testing::allocate_device_for(bd_addr, transport); + bluetooth::legacy::testing::allocate_device_for(kRawAddress, transport); ASSERT_TRUE(device != nullptr); device->conn_state = BTA_DM_CONNECTED; device->p_encrypt_cback = nullptr; @@ -275,7 +236,7 @@ TEST_F(BtaDmTest, bta_dm_set_encryption) { // Setup a device that is busy with another encryption // Fake indication that the encryption is in progress with non-null callback device->p_encrypt_cback = BTA_DM_ENCRYPT_CBACK; - bta_dm_set_encryption(bd_addr, transport, BTA_DM_ENCRYPT_CBACK, sec_act); + bta_dm_set_encryption(kRawAddress, transport, BTA_DM_ENCRYPT_CBACK, sec_act); ASSERT_EQ(0, get_func_call_count("BTM_SetEncryption")); ASSERT_EQ(1UL, BTA_DM_ENCRYPT_CBACK_queue.size()); auto params = BTA_DM_ENCRYPT_CBACK_queue.front(); @@ -284,30 +245,33 @@ TEST_F(BtaDmTest, bta_dm_set_encryption) { device->p_encrypt_cback = nullptr; // Setup a device that fails encryption - test::mock::stack_btm_sec::BTM_SetEncryption.body = + mock_btm_client_interface.security.BTM_SetEncryption = [](const RawAddress& bd_addr, tBT_TRANSPORT transport, tBTM_SEC_CALLBACK* p_callback, void* p_ref_data, tBTM_BLE_SEC_ACT sec_act) -> tBTM_STATUS { + inc_func_call_count("BTM_SetEncryption"); return BTM_MODE_UNSUPPORTED; }; - bta_dm_set_encryption(bd_addr, transport, BTA_DM_ENCRYPT_CBACK, sec_act); + bta_dm_set_encryption(kRawAddress, transport, BTA_DM_ENCRYPT_CBACK, sec_act); ASSERT_EQ(1, get_func_call_count("BTM_SetEncryption")); ASSERT_EQ(0UL, BTA_DM_ENCRYPT_CBACK_queue.size()); device->p_encrypt_cback = nullptr; // Setup a device that successfully starts encryption - test::mock::stack_btm_sec::BTM_SetEncryption.body = + mock_btm_client_interface.security.BTM_SetEncryption = [](const RawAddress& bd_addr, tBT_TRANSPORT transport, tBTM_SEC_CALLBACK* p_callback, void* p_ref_data, - tBTM_BLE_SEC_ACT sec_act) -> tBTM_STATUS { return BTM_CMD_STARTED; }; + tBTM_BLE_SEC_ACT sec_act) -> tBTM_STATUS { + inc_func_call_count("BTM_SetEncryption"); + return BTM_CMD_STARTED; + }; - bta_dm_set_encryption(bd_addr, transport, BTA_DM_ENCRYPT_CBACK, sec_act); + bta_dm_set_encryption(kRawAddress, transport, BTA_DM_ENCRYPT_CBACK, sec_act); ASSERT_EQ(2, get_func_call_count("BTM_SetEncryption")); ASSERT_EQ(0UL, BTA_DM_ENCRYPT_CBACK_queue.size()); ASSERT_NE(nullptr, device->p_encrypt_cback); - test::mock::stack_btm_sec::BTM_SetEncryption = {}; BTA_DM_ENCRYPT_CBACK_queue = {}; } @@ -315,31 +279,30 @@ void bta_dm_encrypt_cback(const RawAddress* bd_addr, tBT_TRANSPORT transport, UNUSED_ATTR void* p_ref_data, tBTM_STATUS result); TEST_F(BtaDmTest, bta_dm_encrypt_cback) { - const RawAddress bd_addr{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; const tBT_TRANSPORT transport{BT_TRANSPORT_LE}; // Setup a connected device tBTA_DM_PEER_DEVICE* device = - bluetooth::legacy::testing::allocate_device_for(bd_addr, transport); + bluetooth::legacy::testing::allocate_device_for(kRawAddress, transport); ASSERT_TRUE(device != nullptr); device->conn_state = BTA_DM_CONNECTED; // Encryption with no callback set device->p_encrypt_cback = nullptr; - bta_dm_encrypt_cback(&bd_addr, transport, nullptr, BTM_SUCCESS); + bta_dm_encrypt_cback(&kRawAddress, transport, nullptr, BTM_SUCCESS); ASSERT_EQ(0UL, BTA_DM_ENCRYPT_CBACK_queue.size()); // Encryption with callback device->p_encrypt_cback = BTA_DM_ENCRYPT_CBACK; - bta_dm_encrypt_cback(&bd_addr, transport, nullptr, BTM_SUCCESS); + bta_dm_encrypt_cback(&kRawAddress, transport, nullptr, BTM_SUCCESS); device->p_encrypt_cback = BTA_DM_ENCRYPT_CBACK; - bta_dm_encrypt_cback(&bd_addr, transport, nullptr, BTM_WRONG_MODE); + bta_dm_encrypt_cback(&kRawAddress, transport, nullptr, BTM_WRONG_MODE); device->p_encrypt_cback = BTA_DM_ENCRYPT_CBACK; - bta_dm_encrypt_cback(&bd_addr, transport, nullptr, BTM_NO_RESOURCES); + bta_dm_encrypt_cback(&kRawAddress, transport, nullptr, BTM_NO_RESOURCES); device->p_encrypt_cback = BTA_DM_ENCRYPT_CBACK; - bta_dm_encrypt_cback(&bd_addr, transport, nullptr, BTM_BUSY); + bta_dm_encrypt_cback(&kRawAddress, transport, nullptr, BTM_BUSY); device->p_encrypt_cback = BTA_DM_ENCRYPT_CBACK; - bta_dm_encrypt_cback(&bd_addr, transport, nullptr, BTM_ILLEGAL_VALUE); + bta_dm_encrypt_cback(&kRawAddress, transport, nullptr, BTM_ILLEGAL_VALUE); ASSERT_EQ(5UL, BTA_DM_ENCRYPT_CBACK_queue.size()); @@ -402,10 +365,10 @@ TEST_F(BtaDmTest, bta_dm_state_text) { } TEST_F(BtaDmTest, bta_dm_remname_cback__typical) { - bta_dm_search_cb = { - .name_discover_done = false, - .peer_bdaddr = kRawAddress, - }; + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.peer_bdaddr = kRawAddress, search_cb.name_discover_done = false, + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); tBTM_REMOTE_DEV_NAME name = { .status = BTM_SUCCESS, @@ -417,19 +380,27 @@ TEST_F(BtaDmTest, bta_dm_remname_cback__typical) { strlcpy(reinterpret_cast(&name.remote_bd_name), kRemoteName, strlen(kRemoteName)); + mock_btm_client_interface.security.BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK*) -> bool { + inc_func_call_count("BTM_SecDeleteRmtNameNotifyCallback"); + return true; + }; bluetooth::legacy::testing::bta_dm_remname_cback(&name); sync_main_handler(); ASSERT_EQ(1, get_func_call_count("BTM_SecDeleteRmtNameNotifyCallback")); - ASSERT_TRUE(bta_dm_search_cb.name_discover_done); + ASSERT_TRUE( + bluetooth::legacy::testing::bta_dm_disc_search_cb().name_discover_done); } TEST_F(BtaDmTest, bta_dm_remname_cback__wrong_address) { - bta_dm_search_cb = { - .name_discover_done = false, - .peer_bdaddr = kRawAddress, - }; + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.p_search_cback = nullptr; + search_cb.peer_bdaddr = kRawAddress; + search_cb.name_discover_done = false; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); tBTM_REMOTE_DEV_NAME name = { .status = BTM_SUCCESS, @@ -441,19 +412,23 @@ TEST_F(BtaDmTest, bta_dm_remname_cback__wrong_address) { strlcpy(reinterpret_cast(&name.remote_bd_name), kRemoteName, strlen(kRemoteName)); + mock_btm_client_interface.security.BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK*) -> bool { + inc_func_call_count("BTM_SecDeleteRmtNameNotifyCallback"); + return true; + }; bluetooth::legacy::testing::bta_dm_remname_cback(&name); sync_main_handler(); ASSERT_EQ(0, get_func_call_count("BTM_SecDeleteRmtNameNotifyCallback")); - ASSERT_FALSE(bta_dm_search_cb.name_discover_done); } TEST_F(BtaDmTest, bta_dm_remname_cback__HCI_ERR_CONNECTION_EXISTS) { - bta_dm_search_cb = { - .name_discover_done = false, - .peer_bdaddr = kRawAddress, - }; + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.peer_bdaddr = kRawAddress; + search_cb.name_discover_done = false; tBTM_REMOTE_DEV_NAME name = { .status = BTM_SUCCESS, @@ -465,39 +440,97 @@ TEST_F(BtaDmTest, bta_dm_remname_cback__HCI_ERR_CONNECTION_EXISTS) { strlcpy(reinterpret_cast(&name.remote_bd_name), kRemoteName, strlen(kRemoteName)); + mock_btm_client_interface.security.BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK*) -> bool { + inc_func_call_count("BTM_SecDeleteRmtNameNotifyCallback"); + return true; + }; bluetooth::legacy::testing::bta_dm_remname_cback(&name); sync_main_handler(); ASSERT_EQ(1, get_func_call_count("BTM_SecDeleteRmtNameNotifyCallback")); - ASSERT_TRUE(bta_dm_search_cb.name_discover_done); + ASSERT_TRUE( + bluetooth::legacy::testing::bta_dm_disc_search_cb().name_discover_done); } TEST_F(BtaDmTest, bta_dm_determine_discovery_transport__BT_TRANSPORT_BR_EDR) { - const RawAddress bd_addr{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; - bta_dm_search_cb.transport = BT_TRANSPORT_BR_EDR; + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.transport = BT_TRANSPORT_BR_EDR; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); ASSERT_EQ(BT_TRANSPORT_BR_EDR, bluetooth::legacy::testing::bta_dm_determine_discovery_transport( - bd_addr)); + kRawAddress)); } TEST_F(BtaDmTest, bta_dm_determine_discovery_transport__BT_TRANSPORT_LE) { - const RawAddress bd_addr{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; - bta_dm_search_cb.transport = BT_TRANSPORT_LE; + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.transport = BT_TRANSPORT_LE; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); + + ASSERT_EQ(BT_TRANSPORT_LE, + bluetooth::legacy::testing::bta_dm_determine_discovery_transport( + kRawAddress)); +} + +TEST_F(BtaDmTest, + bta_dm_determine_discovery_transport__BT_TRANSPORT_AUTO__BR_EDR) { + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.transport = BT_TRANSPORT_AUTO; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); + + mock_btm_client_interface.peer.BTM_ReadDevInfo = + [](const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, + tBLE_ADDR_TYPE* p_addr_type) { + *p_dev_type = BT_DEVICE_TYPE_BREDR; + *p_addr_type = BLE_ADDR_PUBLIC; + }; + + ASSERT_EQ(BT_TRANSPORT_BR_EDR, + bluetooth::legacy::testing::bta_dm_determine_discovery_transport( + kRawAddress)); +} + +TEST_F(BtaDmTest, + bta_dm_determine_discovery_transport__BT_TRANSPORT_AUTO__BLE__PUBLIC) { + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.transport = BT_TRANSPORT_AUTO; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); + + mock_btm_client_interface.peer.BTM_ReadDevInfo = + [](const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, + tBLE_ADDR_TYPE* p_addr_type) { + *p_dev_type = BT_DEVICE_TYPE_BLE; + *p_addr_type = BLE_ADDR_PUBLIC; + }; ASSERT_EQ(BT_TRANSPORT_LE, bluetooth::legacy::testing::bta_dm_determine_discovery_transport( - bd_addr)); + kRawAddress)); } -TEST_F(BtaDmTest, bta_dm_determine_discovery_transport__BT_TRANSPORT_AUTO) { - const RawAddress bd_addr{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; - bta_dm_search_cb.transport = BT_TRANSPORT_AUTO; +TEST_F(BtaDmTest, + bta_dm_determine_discovery_transport__BT_TRANSPORT_AUTO__DUMO) { + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.transport = BT_TRANSPORT_AUTO; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); + + mock_btm_client_interface.peer.BTM_ReadDevInfo = + [](const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, + tBLE_ADDR_TYPE* p_addr_type) { + *p_dev_type = BT_DEVICE_TYPE_DUMO; + *p_addr_type = BLE_ADDR_PUBLIC; + }; ASSERT_EQ(BT_TRANSPORT_BR_EDR, bluetooth::legacy::testing::bta_dm_determine_discovery_transport( - bd_addr)); + kRawAddress)); } TEST_F(BtaDmTest, bta_dm_search_evt_text) { @@ -513,6 +546,7 @@ TEST_F(BtaDmTest, bta_dm_search_evt_text) { std::make_pair(BTA_DM_DID_RES_EVT, "BTA_DM_DID_RES_EVT"), std::make_pair(BTA_DM_GATT_OVER_SDP_RES_EVT, "BTA_DM_GATT_OVER_SDP_RES_EVT"), + std::make_pair(BTA_DM_NAME_READ_EVT, "BTA_DM_NAME_READ_EVT"), }; for (const auto& event : events) { ASSERT_STREQ(event.second.c_str(), @@ -525,3 +559,23 @@ TEST_F(BtaDmTest, bta_dm_search_evt_text) { static_cast(std::numeric_limits::max())) .c_str()); } + +TEST_F(BtaDmTest, bta_dm_remote_name_cmpl) { + tBTA_DM_MSG msg = { + .remote_name_msg = + { + // tBTA_DM_REMOTE_NAME + .hdr = {}, + .bd_addr = kRawAddress, + .bd_name = {0}, + .hci_status = HCI_SUCCESS, + }, + }; + bluetooth::legacy::testing::bta_dm_remote_name_cmpl(&msg); + ASSERT_EQ(1, get_func_call_count("BTM_InqDbRead")); +} + +TEST_F(BtaDmTest, bta_dm_disc_start__true) { bta_dm_disc_start(true); } +TEST_F(BtaDmTest, bta_dm_disc_start__false) { bta_dm_disc_start(false); } + +TEST_F(BtaDmTest, bta_dm_disc_stop) { bta_dm_disc_stop(); } diff --git a/system/bta/test/bta_gatt_client_test.cc b/system/bta/test/bta_gatt_client_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..ef92ed70483966712e838032f0dad248d29c1b4a --- /dev/null +++ b/system/bta/test/bta_gatt_client_test.cc @@ -0,0 +1,70 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include + +#include "bta/dm/bta_dm_gatt_client.h" +#include "gd/common/circular_buffer.h" +#include "stack/btm/btm_int_types.h" + +using namespace bluetooth::common; + +// Test hooks +namespace bluetooth { +namespace legacy { +namespace testing { + +std::vector> PullCopyOfGattHistory(); + +} // namespace testing +} // namespace legacy +} // namespace bluetooth + +class BtaDiscTest : public testing::Test { + protected: + void SetUp() override {} + + void TearDown() override {} +}; + +TEST_F(BtaDiscTest, nop) {} + +TEST_F(BtaDiscTest, gatt_history_callback) { + std::array a = { + "ThisIsATest 0", + "ThisIsATest 1", + "ThisIsATest 2", + }; + + // C string + gatt_history_callback(base::StringPrintf("%s", a[0].c_str())); + // Cpp string + gatt_history_callback(a[1]); + // Third entry for "fun" + gatt_history_callback(base::StringPrintf("%s", a[2].c_str())); + + std::vector> history = + bluetooth::legacy::testing::PullCopyOfGattHistory(); + ASSERT_EQ(3UL, history.size()); + ASSERT_STREQ(a[0].c_str(), history[0].entry.c_str()); + ASSERT_STREQ(a[1].c_str(), history[1].entry.c_str()); + ASSERT_STREQ(a[2].c_str(), history[2].entry.c_str()); +} diff --git a/system/bta/test/bta_gatt_test.cc b/system/bta/test/bta_gatt_test.cc index 5c2c73d7c8e6209dc248ec009b00f8de7bfc48d8..97181b2022338eb591c5ead7ca34ad2442e3fed8 100644 --- a/system/bta/test/bta_gatt_test.cc +++ b/system/bta/test/bta_gatt_test.cc @@ -121,9 +121,9 @@ class BtaGattTest : public ::testing::Test { .conn_id = 1, .handle = 2, .offset = 3, + .len = 4, // length of value below .auth_req = GATT_AUTH_REQ_NONE, .value = {10, 11, 12, 13}, - .len = 4, // length of value above }, }; @@ -133,10 +133,10 @@ class BtaGattTest : public ::testing::Test { tBTA_GATTC_DATA command_queue; tBTA_GATTC_CLCB client_channel_control_block = { - .p_q_cmd = &command_queue, + .bta_conn_id = 456, .p_rcb = &app_control_block, .p_srcb = &service_control_block, - .bta_conn_id = 456, + .p_q_cmd = &command_queue, }; }; diff --git a/system/bta/test/bta_hf_client_add_record_test.cc b/system/bta/test/bta_hf_client_add_record_test.cc index 4b16cd5221af86893087b4a4e030ce3dbba1f264..5af46688ac2099b92ffbfc69ef0dd7afde66e27f 100644 --- a/system/bta/test/bta_hf_client_add_record_test.cc +++ b/system/bta/test/bta_hf_client_add_record_test.cc @@ -19,42 +19,18 @@ #include #include -#include "bta/hf_client/bta_hf_client_sdp.cc" -#include "bta/include/bta_hf_client_api.h" -#include "btif/src/btif_hf_client.cc" -#include "types/bluetooth/uuid.h" - -static uint16_t gVersion; +#include -bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem, - tSDP_PROTOCOL_ELEM* p_elem_list) { - return false; -} -bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services, - uint16_t* p_service_uuids) { - return false; -} -bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid, - uint16_t version) { - gVersion = version; - return false; -} -bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, - uint32_t attr_len, uint8_t* p_val) { - return false; -} -bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids, - uint16_t* p_uuids) { - return false; -} +#include "bta/hf_client/bta_hf_client_int.h" +#include "bta/include/bta_hf_client_api.h" +#include "test/fake/fake_osi.h" class BtaHfClientAddRecordTest : public ::testing::Test { protected: - void SetUp() override { - gVersion = 0; - } + void SetUp() override { fake_osi_ = std::make_unique(); } void TearDown() override {} + std::unique_ptr fake_osi_; }; TEST_F(BtaHfClientAddRecordTest, test_hf_client_add_record) { @@ -63,6 +39,6 @@ TEST_F(BtaHfClientAddRecordTest, test_hf_client_add_record) { uint8_t scn = 0; bta_hf_client_add_record("Handsfree", scn, features, sdp_handle); - ASSERT_EQ(gVersion, get_default_hfp_version()); + ASSERT_EQ(HFP_VERSION_1_7, get_default_hfp_version()); } diff --git a/system/bta/test/bta_hf_client_test.cc b/system/bta/test/bta_hf_client_test.cc index ca45b44890fb194e70771982549dc96c8d599fe6..0c795c0008c2d375f4e34d905296382a96086718 100644 --- a/system/bta/test/bta_hf_client_test.cc +++ b/system/bta/test/bta_hf_client_test.cc @@ -18,17 +18,12 @@ #include +#include + #include "bta/hf_client/bta_hf_client_int.h" -#include "bta/include/bta_hf_client_api.h" -#include "common/message_loop_thread.h" +#include "test/fake/fake_osi.h" #include "types/raw_address.h" -namespace base { -class MessageLoop; -} // namespace base - -bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; } - namespace { const RawAddress bdaddr1({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); const RawAddress bdaddr2({0x66, 0x55, 0x44, 0x33, 0x22, 0x11}); @@ -37,10 +32,12 @@ const RawAddress bdaddr2({0x66, 0x55, 0x44, 0x33, 0x22, 0x11}); class BtaHfClientTest : public testing::Test { protected: void SetUp() override { + fake_osi_ = std::make_unique(); // Reset the memory block, this is the state on which the allocate handle // would start operating bta_hf_client_cb_arr_init(); } + std::unique_ptr fake_osi_; }; // Test that when we can allocate a device on the block and then check diff --git a/system/bta/test/bta_hh_test.cc b/system/bta/test/bta_hh_test.cc index 618f56507b74b7473291d7580fee1f6b26e0b4f0..b9b2b552c1c5055582c23c5c5190a2a7f58b478d 100644 --- a/system/bta/test/bta_hh_test.cc +++ b/system/bta/test/bta_hh_test.cc @@ -25,9 +25,6 @@ #include "test/common/mock_functions.h" #include "test/mock/mock_osi_allocator.h" -uint8_t appl_trace_level = 0; -uint8_t btif_trace_level = BT_TRACE_LEVEL_DEBUG; - namespace { std::array data32 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, diff --git a/system/bta/test/bta_pan_test.cc b/system/bta/test/bta_pan_test.cc index d65c462c53c79e279db41e9e06f4b23fba5e7dde..146f2dd12fef96cc4052b1d28e07ff4a42daa835 100644 --- a/system/bta/test/bta_pan_test.cc +++ b/system/bta/test/bta_pan_test.cc @@ -96,7 +96,22 @@ class BtaPanTest : public ::testing::Test { std::deque uuids; }; -TEST_F(BtaPanTest, BTA_PanSetRole_Null) { +class BtaPanRegisteredTest : public BtaPanTest { + protected: + void SetUp() { + BtaPanTest::SetUp(); + bta_sys_eir_register(BTA_SYS_EIR_CBACK); + } + + void TearDown() { + bta_sys_eir_unregister(); + BtaPanTest::TearDown(); + } +}; + +TEST_F(BtaPanTest, nop) {} + +TEST_F(BtaPanRegisteredTest, BTA_PanSetRole_Null) { tBTA_PAN_ROLE role = BTA_PAN_ROLE_PANU | BTA_PAN_ROLE_NAP; tBTA_PAN_ROLE_INFO user_info = { .p_srv_name = std::string(), @@ -108,7 +123,6 @@ TEST_F(BtaPanTest, BTA_PanSetRole_Null) { .app_id = 34, }; - bta_sys_eir_register(BTA_SYS_EIR_CBACK); BTA_PanSetRole(role, user_info, nap_info); // Wait for main thread to complete @@ -125,7 +139,7 @@ TEST_F(BtaPanTest, BTA_PanSetRole_Null) { ASSERT_EQ(true, uuids[1].adding); } -TEST_F(BtaPanTest, BTA_PanSetRole_WithNames) { +TEST_F(BtaPanRegisteredTest, BTA_PanSetRole_WithNames) { tBTA_PAN_ROLE role = BTA_PAN_ROLE_PANU | BTA_PAN_ROLE_NAP; tBTA_PAN_ROLE_INFO user_info = { .p_srv_name = "TestPanUser", @@ -172,7 +186,7 @@ TEST_F(BtaPanTest, BTA_PanSetRole_WithNames) { constexpr size_t kBtaServiceNameLen = static_cast(BTA_SERVICE_NAME_LEN); -TEST_F(BtaPanTest, BTA_PanSetRole_WithLongNames) { +TEST_F(BtaPanRegisteredTest, BTA_PanSetRole_WithLongNames) { tBTA_PAN_ROLE role = BTA_PAN_ROLE_PANU | BTA_PAN_ROLE_NAP; tBTA_PAN_ROLE_INFO user_info = { .p_srv_name = std::string(200, 'A'), diff --git a/system/bta/test/bta_rfcomm_scn_test.cc b/system/bta/test/bta_rfcomm_scn_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..26e85ce9a6021cb5e83239cf8176fc1bf43629e2 --- /dev/null +++ b/system/bta/test/bta_rfcomm_scn_test.cc @@ -0,0 +1,82 @@ +/* + * + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "bta_rfcomm_scn.h" + +#include + +#include "bta/jv/bta_jv_int.h" // tBTA_JV_CB +#include "stack/include/rfcdefs.h" // RFCOMM_MAX_SCN + +using testing::Test; + +class BtaRfcommScnTest : public Test { + public: + protected: + void SetUp() override { + tBTA_JV_DM_CBACK* p_cback = [](tBTA_JV_EVT, tBTA_JV*, uint32_t) {}; + bta_jv_enable(p_cback); + } + + void TearDown() override {} +}; + +TEST_F(BtaRfcommScnTest, scn_available_after_available_index) { + ASSERT_EQ(BTA_AllocateSCN(), 2); + ASSERT_EQ(BTA_AllocateSCN(), 3); + ASSERT_TRUE(BTA_TryAllocateSCN(4)); + ASSERT_TRUE(BTA_TryAllocateSCN(5)); + + // Available index should be 3, and the next available scn is 6 + ASSERT_EQ(BTA_AllocateSCN(), 6); +} + +TEST_F(BtaRfcommScnTest, scn_available_before_available_index) { + for (uint8_t scn = 2; scn <= RFCOMM_MAX_SCN; scn++) { + ASSERT_TRUE(BTA_TryAllocateSCN(scn)); + } + ASSERT_TRUE(BTA_FreeSCN(28)); + ASSERT_EQ(BTA_AllocateSCN(), 28); + ASSERT_TRUE(BTA_FreeSCN(2)); + + // Available index is 27, and the available scn is 2 + ASSERT_EQ(BTA_AllocateSCN(), 2); +} + +TEST_F(BtaRfcommScnTest, can_allocate_all_scns) { + for (uint8_t scn = 2; scn <= RFCOMM_MAX_SCN; scn++) { + ASSERT_EQ(BTA_AllocateSCN(), scn); + } +} + +TEST_F(BtaRfcommScnTest, only_last_scn_available) { + // Fill all relevant SCN except the last + for (uint8_t scn = 2; scn < RFCOMM_MAX_SCN; scn++) { + ASSERT_EQ(BTA_AllocateSCN(), scn); + } + + ASSERT_EQ(BTA_AllocateSCN(), RFCOMM_MAX_SCN); +} + +TEST_F(BtaRfcommScnTest, no_scn_available) { + for (uint8_t scn = 2; scn <= RFCOMM_MAX_SCN; scn++) { + ASSERT_EQ(BTA_AllocateSCN(), scn); + } + + ASSERT_EQ(BTA_AllocateSCN(), 0); +} diff --git a/system/bta/test/bta_sdp_test.cc b/system/bta/test/bta_sdp_test.cc index abc10db3ee1d0b77b5fddc36a5b10e091a9c59dc..7a8c036c149e3911cfb777f8d8f4726b56b4f0dd 100644 --- a/system/bta/test/bta_sdp_test.cc +++ b/system/bta/test/bta_sdp_test.cc @@ -16,40 +16,55 @@ #include #include -#include #include -#include "bta/dm/bta_dm_int.h" +#include "bta/dm/bta_dm_disc_int.h" +#include "bta/test/bta_base_test.h" +#include "osi/include/allocator.h" #include "test/common/main_handler.h" -#include "test/mock/mock_osi_alarm.h" -#include "test/mock/mock_osi_allocator.h" +#include "test/mock/mock_stack_btm_interface.h" #include "test/mock/mock_stack_gatt_api.h" void BTA_dm_on_hw_on(); void BTA_dm_on_hw_off(); -struct alarm_t { - alarm_t(const char* name){}; - int any_value; -}; +namespace { +const char kName[] = "Hello"; +} + +namespace bluetooth { +namespace legacy { +namespace testing { + +const tBTA_DM_SEARCH_CB& bta_dm_disc_search_cb(); +tBTA_DM_SEARCH_CB bta_dm_disc_get_search_cb(); +void bta_dm_disc_search_cb(const tBTA_DM_SEARCH_CB& search_cb); +void bta_dm_sdp_result(tBTA_DM_MSG* p_data); + +} // namespace testing +} // namespace legacy +} // namespace bluetooth -class BtaSdpTest : public testing::Test { +class BtaSdpTest : public BtaBaseTest { protected: void SetUp() override { - test::mock::osi_allocator::osi_calloc.body = [](size_t size) -> void* { - return calloc(1, size); - }; - test::mock::osi_allocator::osi_free.body = [](void* ptr) { free(ptr); }; - test::mock::osi_alarm::alarm_new.body = [](const char* name) -> alarm_t* { - return new alarm_t(name); - }; - test::mock::osi_alarm::alarm_free.body = [](alarm_t* alarm) { - delete alarm; - }; + BtaBaseTest::SetUp(); test::mock::stack_gatt_api::GATT_Register.body = [](const bluetooth::Uuid& p_app_uuid128, const std::string name, tGATT_CBACK* p_cb_info, bool eatt_support) { return 5; }; + mock_btm_client_interface.eir.BTM_GetEirSupportedServices = + [](uint32_t* p_eir_uuid, uint8_t** p, uint8_t max_num_uuid16, + uint8_t* p_num_uuid16) -> uint8_t { return 0; }; + mock_btm_client_interface.eir.BTM_WriteEIR = + [](BT_HDR* p_buf) -> tBTM_STATUS { + osi_free(p_buf); + return BTM_SUCCESS; + }; + mock_btm_client_interface.local.BTM_ReadLocalDeviceNameFromController = + [](tBTM_CMPL_CB* cb) -> tBTM_STATUS { return BTM_CMD_STARTED; }; + mock_btm_client_interface.security.BTM_SecRegister = + [](const tBTM_APPL_INFO* p_cb_info) -> bool { return true; }; main_thread_start_up(); sync_main_handler(); @@ -64,10 +79,7 @@ class BtaSdpTest : public testing::Test { main_thread_shut_down(); test::mock::stack_gatt_api::GATT_Register = {}; - test::mock::osi_allocator::osi_calloc = {}; - test::mock::osi_allocator::osi_free = {}; - test::mock::osi_alarm::alarm_new = {}; - test::mock::osi_alarm::alarm_free = {}; + BtaBaseTest::TearDown(); } }; @@ -84,8 +96,8 @@ class BtaSdpRegisteredTest : public BtaSdpTest { } tBTA_SYS_REG bta_sys_reg = { - .evt_hdlr = [](BT_HDR_RIGID* p_msg) -> bool { - osi_free(p_msg); + .evt_hdlr = [](const BT_HDR_RIGID* p_msg) -> bool { + osi_free((void*)p_msg); return false; }, .disable = []() {}, @@ -95,13 +107,21 @@ class BtaSdpRegisteredTest : public BtaSdpTest { TEST_F(BtaSdpTest, nop) {} TEST_F(BtaSdpRegisteredTest, bta_dm_sdp_result_SDP_SUCCESS) { - bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID; + tBTA_DM_SEARCH_CB search_cb = + bluetooth::legacy::testing::bta_dm_disc_get_search_cb(); + search_cb.service_index = BTA_MAX_SERVICE_ID; + bluetooth::legacy::testing::bta_dm_disc_search_cb(search_cb); tBTA_DM_MSG msg = { .sdp_event = { + .hdr = {}, .sdp_result = SDP_SUCCESS, }, }; - bta_dm_sdp_result(&msg); + mock_btm_client_interface.security.BTM_SecReadDevName = + [](const RawAddress& bd_addr) -> const char* { return kName; }; + mock_btm_client_interface.security.BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK*) -> bool { return true; }; + bluetooth::legacy::testing::bta_dm_sdp_result(&msg); } diff --git a/system/bta/test/bta_sec_test.cc b/system/bta/test/bta_sec_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..55ce9bb51ffc8e193ff5793b6b7f71e3a3f7ffbc --- /dev/null +++ b/system/bta/test/bta_sec_test.cc @@ -0,0 +1,237 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "bta/dm/bta_dm_sec_int.h" +#include "bta/test/bta_base_test.h" +#include "test/mock/mock_stack_btm_inq.h" +#include "test/mock/mock_stack_btm_interface.h" +#include "types/raw_address.h" + +using ::testing::ElementsAre; + +namespace { +const RawAddress kRawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); +const RawAddress kRawAddress2({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}); +const DEV_CLASS kDeviceClass = {0x11, 0x22, 0x33}; + +constexpr char kRemoteName[] = "TheRemoteName"; + +} // namespace + +// Test hooks +namespace bluetooth { +namespace legacy { +namespace testing { + +tBTM_STATUS bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data); +void btm_set_local_io_caps(uint8_t io_caps); + +} // namespace testing +} // namespace legacy +} // namespace bluetooth + +class BtaSecTest : public BtaBaseTest { + protected: + void SetUp() override { BtaBaseTest::SetUp(); } + + void TearDown() override { BtaBaseTest::TearDown(); } +}; + +TEST_F(BtaSecTest, bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithName) { + constexpr uint32_t kNumVal = 1234; + static bool callback_sent = false; + mock_btm_client_interface.peer.BTM_ReadRemoteDeviceName = + [](const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb, + tBT_TRANSPORT transport) -> tBTM_STATUS { return BTM_CMD_STARTED; }; + + static tBTA_DM_SP_CFM_REQ cfm_req{}; + bta_dm_sec_enable([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { + callback_sent = true; + cfm_req = p_data->cfm_req; + }); + + bluetooth::legacy::testing::btm_set_local_io_caps(0xff); + + tBTM_SP_EVT_DATA data = { + .cfm_req = + { + // tBTM_SP_CFM_REQ + .bd_addr = kRawAddress, + .dev_class = {}, + .bd_name = {}, + .num_val = kNumVal, + .just_works = false, + .loc_auth_req = BTM_AUTH_SP_YES, + .rmt_auth_req = BTM_AUTH_SP_YES, + .loc_io_caps = BTM_IO_CAP_NONE, + .rmt_io_caps = BTM_IO_CAP_NONE, + }, + }; + dev_class_copy(data.cfm_req.dev_class, kDeviceClass); + bd_name_copy(data.cfm_req.bd_name, kRemoteName); + + ASSERT_EQ(btm_status_text(BTM_CMD_STARTED), + btm_status_text(bluetooth::legacy::testing::bta_dm_sp_cback( + BTM_SP_CFM_REQ_EVT, &data))); + ASSERT_EQ(kNumVal, bta_dm_sec_cb.num_val); + ASSERT_TRUE(callback_sent); + + ASSERT_EQ(kRawAddress, cfm_req.bd_addr); + ASSERT_THAT(cfm_req.dev_class, + ElementsAre(kDeviceClass[0], kDeviceClass[1], kDeviceClass[2])); + ASSERT_STREQ(kRemoteName, reinterpret_cast(cfm_req.bd_name)); + ASSERT_EQ(kNumVal, cfm_req.num_val); + ASSERT_EQ(false, cfm_req.just_works); + ASSERT_EQ(BTM_AUTH_SP_YES, cfm_req.loc_auth_req); + ASSERT_EQ(BTM_AUTH_SP_YES, cfm_req.rmt_auth_req); + ASSERT_EQ(BTM_IO_CAP_NONE, cfm_req.loc_io_caps); + ASSERT_EQ(BTM_IO_CAP_NONE, cfm_req.rmt_io_caps); +} + +TEST_F(BtaSecTest, bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithoutName_RNRSuccess) { + constexpr uint32_t kNumVal = 1234; + static bool callback_sent = false; + test::mock::stack_btm_inq::BTM_ReadRemoteDeviceName.body = + [](const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb, + tBT_TRANSPORT transport) -> tBTM_STATUS { return BTM_CMD_STARTED; }; + + static tBTA_DM_SP_CFM_REQ cfm_req{}; + bta_dm_sec_enable([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { + callback_sent = true; + cfm_req = p_data->cfm_req; + }); + + bluetooth::legacy::testing::btm_set_local_io_caps(0xff); + + tBTM_SP_EVT_DATA data = { + .cfm_req = + { + // tBTM_SP_CFM_REQ + .bd_addr = kRawAddress, + .dev_class = {}, + .bd_name = {0}, // No name available + .num_val = kNumVal, + .just_works = false, + .loc_auth_req = BTM_AUTH_SP_YES, + .rmt_auth_req = BTM_AUTH_SP_YES, + .loc_io_caps = BTM_IO_CAP_NONE, + .rmt_io_caps = BTM_IO_CAP_NONE, + }, + }; + dev_class_copy(data.cfm_req.dev_class, kDeviceClass); + + ASSERT_EQ(btm_status_text(BTM_CMD_STARTED), + btm_status_text(bluetooth::legacy::testing::bta_dm_sp_cback( + BTM_SP_CFM_REQ_EVT, &data))); + ASSERT_EQ(kNumVal, bta_dm_sec_cb.num_val); + ASSERT_FALSE(callback_sent); + + test::mock::stack_btm_inq::BTM_ReadRemoteDeviceName = {}; +} + +TEST_F(BtaSecTest, bta_dm_sp_cback__BTM_SP_CFM_REQ_EVT_WithoutName_RNRFail) { + constexpr uint32_t kNumVal = 1234; + static bool callback_sent = false; + mock_btm_client_interface.peer.BTM_ReadRemoteDeviceName = + [](const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb, + tBT_TRANSPORT transport) -> tBTM_STATUS { return BTM_SUCCESS; }; + + static tBTA_DM_SP_CFM_REQ cfm_req{}; + bta_dm_sec_enable([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { + callback_sent = true; + cfm_req = p_data->cfm_req; + }); + + bluetooth::legacy::testing::btm_set_local_io_caps(0xff); + + tBTM_SP_EVT_DATA data = { + .cfm_req = + { + // tBTM_SP_CFM_REQ + .bd_addr = kRawAddress, + .dev_class = {}, + .bd_name = {0}, + .num_val = kNumVal, + .just_works = false, + .loc_auth_req = BTM_AUTH_SP_YES, + .rmt_auth_req = BTM_AUTH_SP_YES, + .loc_io_caps = BTM_IO_CAP_NONE, + .rmt_io_caps = BTM_IO_CAP_NONE, + }, + }; + dev_class_copy(data.cfm_req.dev_class, kDeviceClass); + + ASSERT_EQ(btm_status_text(BTM_CMD_STARTED), + btm_status_text(bluetooth::legacy::testing::bta_dm_sp_cback( + BTM_SP_CFM_REQ_EVT, &data))); + ASSERT_EQ(kNumVal, bta_dm_sec_cb.num_val); + ASSERT_TRUE(callback_sent); + + ASSERT_EQ(kRawAddress, cfm_req.bd_addr); + ASSERT_THAT(cfm_req.dev_class, + ElementsAre(kDeviceClass[0], kDeviceClass[1], kDeviceClass[2])); + ASSERT_EQ(kNumVal, cfm_req.num_val); + ASSERT_EQ(false, cfm_req.just_works); + ASSERT_EQ(BTM_AUTH_SP_YES, cfm_req.loc_auth_req); + ASSERT_EQ(BTM_AUTH_SP_YES, cfm_req.rmt_auth_req); + ASSERT_EQ(BTM_IO_CAP_NONE, cfm_req.loc_io_caps); + ASSERT_EQ(BTM_IO_CAP_NONE, cfm_req.rmt_io_caps); +} + +TEST_F(BtaSecTest, bta_dm_sp_cback__BTM_SP_KEY_NOTIF_EVT) { + constexpr uint32_t kPassKey = 1234; + static bool callback_sent = false; + mock_btm_client_interface.peer.BTM_ReadRemoteDeviceName = + [](const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb, + tBT_TRANSPORT transport) -> tBTM_STATUS { return BTM_CMD_STARTED; }; + + static tBTA_DM_SP_KEY_NOTIF key_notif{}; + bta_dm_sec_enable([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { + callback_sent = true; + key_notif = p_data->key_notif; + }); + bluetooth::legacy::testing::btm_set_local_io_caps(0xff); + + tBTM_SP_EVT_DATA data = { + .key_notif = + { + // tBTM_SP_KEY_NOTIF + .bd_addr = kRawAddress, + .dev_class = {}, + .bd_name = {}, + .passkey = kPassKey, + }, + }; + dev_class_copy(data.key_notif.dev_class, kDeviceClass); + bd_name_copy(data.key_notif.bd_name, kRemoteName); + + ASSERT_EQ(btm_status_text(BTM_CMD_STARTED), + btm_status_text(bluetooth::legacy::testing::bta_dm_sp_cback( + BTM_SP_KEY_NOTIF_EVT, &data))); + ASSERT_EQ(kPassKey, bta_dm_sec_cb.num_val); + ASSERT_TRUE(callback_sent); + + ASSERT_EQ(kRawAddress, key_notif.bd_addr); + ASSERT_THAT(key_notif.dev_class, + ElementsAre(kDeviceClass[0], kDeviceClass[1], kDeviceClass[2])); + ASSERT_STREQ(kRemoteName, reinterpret_cast(key_notif.bd_name)); + ASSERT_EQ(kPassKey, key_notif.passkey); +} diff --git a/system/bta/test/common/bta_dm_api_mock.cc b/system/bta/test/common/bta_dm_api_mock.cc index e0c9941e3ff6eab6b11183bec3a9ea6dd7ea712f..ef61b5244bfabf84574729116240ea4f5a39cdee 100644 --- a/system/bta/test/common/bta_dm_api_mock.cc +++ b/system/bta/test/common/bta_dm_api_mock.cc @@ -32,3 +32,13 @@ void BTA_DmBleCsisObserve(bool observe, tBTA_DM_SEARCH_CBACK* p_results_cb) { LOG_ASSERT(dm_interface) << "Mock BTA DM interface not set!"; return dm_interface->BTA_DmBleCsisObserve(observe, p_results_cb); } + +void BTA_DmSirkSecCbRegister(tBTA_DM_SEC_CBACK* p_cback) { + LOG_ASSERT(dm_interface) << "Mock BTA DM interface not set!"; + return dm_interface->BTA_DmSirkSecCbRegister(p_cback); +} + +void BTA_DmSirkConfirmDeviceReply(const RawAddress& bd_addr, bool accept) { + LOG_ASSERT(dm_interface) << "Mock BTA DM interface not set!"; + return dm_interface->BTA_DmSirkConfirmDeviceReply(bd_addr, accept); +} diff --git a/system/bta/test/common/bta_dm_api_mock.h b/system/bta/test/common/bta_dm_api_mock.h index 9093bd3b296ca1ace2468cd8483e6d773bf2a725..005a24ab7c550f941a47d84ebe2dd2cd7c337c8a 100644 --- a/system/bta/test/common/bta_dm_api_mock.h +++ b/system/bta/test/common/bta_dm_api_mock.h @@ -20,6 +20,7 @@ #include #include "bta_api.h" +#include "bta_sec_api.h" #include "bta_dm_api.h" namespace dm { @@ -30,6 +31,9 @@ class BtaDmInterface { bool low_latency_scan) = 0; virtual void BTA_DmBleCsisObserve(bool observe, tBTA_DM_SEARCH_CBACK* p_results_cb) = 0; + virtual void BTA_DmSirkSecCbRegister(tBTA_DM_SEC_CBACK* p_cback) = 0; + virtual void BTA_DmSirkConfirmDeviceReply(const RawAddress& bd_addr, + bool accept) = 0; virtual ~BtaDmInterface() = default; }; @@ -39,6 +43,9 @@ class MockBtaDmInterface : public BtaDmInterface { (bool start, uint8_t duration, bool low_latency_scan)); MOCK_METHOD((void), BTA_DmBleCsisObserve, (bool observe, tBTA_DM_SEARCH_CBACK* p_results_cb)); + MOCK_METHOD((void), BTA_DmSirkSecCbRegister, (tBTA_DM_SEC_CBACK * p_cback)); + MOCK_METHOD((void), BTA_DmSirkConfirmDeviceReply, + (const RawAddress& bd_addr, bool accept)); }; /** diff --git a/system/bta/test/common/bta_gatt_queue_mock.cc b/system/bta/test/common/bta_gatt_queue_mock.cc index 151fba3b1da61891f29b116da41e3deae8e62f3d..c22fd34082458f71d76520daec30db10e99f8f85 100644 --- a/system/bta/test/common/bta_gatt_queue_mock.cc +++ b/system/bta/test/common/bta_gatt_queue_mock.cc @@ -49,3 +49,13 @@ void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) { LOG_ASSERT(gatt_queue) << "Mock GATT queue not set!"; gatt_queue->ConfigureMtu(conn_id, mtu); } + +void BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id, + tBTA_GATTC_MULTI& p_read_multi, + bool variable_len, + GATT_READ_MULTI_OP_CB cb, + void* cb_data) { + LOG_ASSERT(gatt_queue) << "Mock GATT queue not set!"; + gatt_queue->ReadMultiCharacteristic(conn_id, p_read_multi, variable_len, cb, + cb_data); +} diff --git a/system/bta/test/common/bta_gatt_queue_mock.h b/system/bta/test/common/bta_gatt_queue_mock.h index 3ae62abd76878d3a6f32f7a7fa474413ec66b927..8c3d3bd3c1d54a4bcc63a3ab3ba8285debd8863a 100644 --- a/system/bta/test/common/bta_gatt_queue_mock.h +++ b/system/bta/test/common/bta_gatt_queue_mock.h @@ -38,6 +38,9 @@ class MockBtaGattQueue { tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data)); MOCK_METHOD((void), ConfigureMtu, (uint16_t conn_id, uint16_t mtu)); + MOCK_METHOD((void), ReadMultiCharacteristic, + (uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi, + bool variable_len, GATT_READ_MULTI_OP_CB cb, void* cb_data)); }; /** diff --git a/system/bta/test/common/btif_storage_mock.cc b/system/bta/test/common/btif_storage_mock.cc index 9440394ad7ff4eef4df27d5ef049fe6704e15a54..5a0b8dd18d22ef66a8a9885888e979e72d0f272b 100644 --- a/system/bta/test/common/btif_storage_mock.cc +++ b/system/bta/test/common/btif_storage_mock.cc @@ -64,6 +64,11 @@ void btif_storage_set_leaudio_supported_context_types( source_supported_context_type); } +void btif_storage_leaudio_clear_service_data(RawAddress const& addr) { + LOG_ASSERT(btif_storage_interface) << "Mock storage module not set!"; + btif_storage_interface->ClearLeAudioServiceData(addr); +} + void btif_storage_remove_leaudio(RawAddress const& addr) { LOG_ASSERT(btif_storage_interface) << "Mock storage module not set!"; btif_storage_interface->RemoveLeaudio(addr); @@ -115,4 +120,10 @@ void btif_storage_set_leaudio_has_active_preset(const RawAddress& address, void btif_storage_remove_leaudio_has(const RawAddress& address) { LOG_ASSERT(btif_storage_interface) << "Mock storage module not set!"; btif_storage_interface->RemoveLeaudioHas(address); +} + +bt_status_t btif_storage_get_remote_device_property(const RawAddress* address, + bt_property_t* property) { + LOG_ASSERT(btif_storage_interface) << "Mock storage module not set!"; + return btif_storage_interface->GetRemoteDeviceProperty(address, property); } \ No newline at end of file diff --git a/system/bta/test/common/btif_storage_mock.h b/system/bta/test/common/btif_storage_mock.h index 77fb91d680c9ab6a00c7427abf4de57536c65414..6b2a020b85b1d14cffe5eecf51d5fdca01ba9728 100644 --- a/system/bta/test/common/btif_storage_mock.h +++ b/system/bta/test/common/btif_storage_mock.h @@ -18,6 +18,7 @@ #include +#include "include/hardware/bluetooth.h" #include "types/raw_address.h" namespace bluetooth { @@ -35,6 +36,7 @@ class BtifStorageInterface { uint32_t source_location) = 0; virtual void SetLeAudioContexts(RawAddress const& addr, uint16_t sink_context, uint16_t source_context) = 0; + virtual void ClearLeAudioServiceData(RawAddress const& addr) = 0; virtual void RemoveLeaudio(RawAddress const& addr) = 0; virtual void AddLeaudioHasDevice(const RawAddress& address, std::vector presets_bin, @@ -51,6 +53,8 @@ class BtifStorageInterface { std::vector& presets_bin, uint8_t& active_preset) = 0; virtual void RemoveLeaudioHas(const RawAddress& address) = 0; + virtual bt_status_t GetRemoteDeviceProperty(const RawAddress* address, + bt_property_t* property) = 0; virtual ~BtifStorageInterface() = default; }; @@ -71,6 +75,8 @@ class MockBtifStorageInterface : public BtifStorageInterface { (RawAddress const& addr, uint16_t sink_context, uint16_t source_context), (override)); + MOCK_METHOD((void), ClearLeAudioServiceData, (RawAddress const& addr), + (override)); MOCK_METHOD((void), RemoveLeaudio, (RawAddress const& addr), (override)); MOCK_METHOD((void), AddLeaudioHasDevice, (const RawAddress& address, std::vector presets_bin, @@ -91,6 +97,8 @@ class MockBtifStorageInterface : public BtifStorageInterface { (const RawAddress& address, uint8_t active_preset), (override)); MOCK_METHOD((void), RemoveLeaudioHas, (const RawAddress& address), (override)); + MOCK_METHOD((bt_status_t), GetRemoteDeviceProperty, + (const RawAddress* address, bt_property_t* property), (override)); }; /** diff --git a/system/bta/test/common/btm_api_mock.cc b/system/bta/test/common/btm_api_mock.cc index 935a93030b9ed6cbc57a4bb1cf246eb154e5d583..05599ab5a2a2733b9f63c32ec2708d4873474049 100644 --- a/system/bta/test/common/btm_api_mock.cc +++ b/system/bta/test/common/btm_api_mock.cc @@ -17,6 +17,10 @@ #include "btm_api_mock.h" +#include + +#include "bt_octets.h" +#include "stack/include/btm_ble_sec_api.h" #include "types/raw_address.h" static bluetooth::manager::MockBtmInterface* btm_interface = nullptr; @@ -26,14 +30,6 @@ void bluetooth::manager::SetMockBtmInterface( btm_interface = mock_btm_interface; } -bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr, - uint8_t* p_sec_flags, - tBT_TRANSPORT transport) { - LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; - return btm_interface->GetSecurityFlagsByTransport(bd_addr, p_sec_flags, - transport); -} - bool BTM_IsLinkKeyKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) { LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; return btm_interface->IsLinkKeyKnown(bd_addr, transport); @@ -95,12 +91,6 @@ void acl_disconnect_from_handle(uint16_t handle, tHCI_STATUS reason, return btm_interface->AclDisconnectFromHandle(handle, reason); } -void btm_configure_data_path(uint8_t direction, uint8_t path_id, - std::vector vendor_config) { - LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; - return btm_interface->ConfigureDataPath(direction, path_id, vendor_config); -} - tBTM_INQ_INFO* BTM_InqDbFirst(void) { LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; return btm_interface->BTM_InqDbFirst(); @@ -108,4 +98,25 @@ tBTM_INQ_INFO* BTM_InqDbFirst(void) { tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur) { LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; return btm_interface->BTM_InqDbNext(p_cur); -} \ No newline at end of file +} + +std::optional BTM_BleGetPeerLTK(const RawAddress address) { + LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; + return btm_interface->BTM_BleGetPeerLTK(address); +} + +std::optional BTM_BleGetPeerIRK(const RawAddress address) { + LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; + return btm_interface->BTM_BleGetPeerIRK(address); +} + +bool BTM_BleIsLinkKeyKnown(const RawAddress address) { + LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; + return btm_interface->BTM_BleIsLinkKeyKnown(address); +} + +std::optional BTM_BleGetIdentityAddress( + const RawAddress address) { + LOG_ASSERT(btm_interface) << "Mock btm interface not set!"; + return btm_interface->BTM_BleGetIdentityAddress(address); +} diff --git a/system/bta/test/common/btm_api_mock.h b/system/bta/test/common/btm_api_mock.h index 90c00e1f8c282ff98ef30a537333aee324916d48..f134c62a3c16cef5ecbacf9eee8d3cacbbd1c04e 100644 --- a/system/bta/test/common/btm_api_mock.h +++ b/system/bta/test/common/btm_api_mock.h @@ -18,8 +18,12 @@ #include +#include + +#include "bt_octets.h" #include "btm_api.h" #include "stack/btm/security_device_record.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" namespace bluetooth { @@ -52,10 +56,17 @@ class BtmInterface { virtual uint16_t GetHCIConnHandle(RawAddress const& bd_addr, tBT_TRANSPORT transport) = 0; virtual void AclDisconnectFromHandle(uint16_t handle, tHCI_STATUS reason) = 0; - virtual void ConfigureDataPath(uint8_t direction, uint8_t path_id, - std::vector vendor_config) = 0; virtual tBTM_INQ_INFO* BTM_InqDbFirst() = 0; virtual tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur) = 0; + virtual std::optional BTM_BleGetPeerLTK( + const RawAddress address) = 0; + virtual std::optional BTM_BleGetPeerIRK( + const RawAddress address) = 0; + + virtual bool BTM_BleIsLinkKeyKnown(const RawAddress address) = 0; + virtual std::optional BTM_BleGetIdentityAddress( + const RawAddress address) = 0; + virtual ~BtmInterface() = default; }; @@ -94,13 +105,18 @@ class MockBtmInterface : public BtmInterface { (RawAddress const& bd_addr, tBT_TRANSPORT transport), (override)); MOCK_METHOD((void), AclDisconnectFromHandle, (uint16_t handle, tHCI_STATUS reason), (override)); - MOCK_METHOD((void), ConfigureDataPath, - (uint8_t direction, uint8_t path_id, - std::vector vendor_config), - (override)); MOCK_METHOD((tBTM_INQ_INFO*), BTM_InqDbFirst, (), (override)); MOCK_METHOD((tBTM_INQ_INFO*), BTM_InqDbNext, (tBTM_INQ_INFO * p_cur), (override)); + MOCK_METHOD((std::optional), BTM_BleGetPeerLTK, + (const RawAddress address), (override)); + MOCK_METHOD((std::optional), BTM_BleGetPeerIRK, + (const RawAddress address), (override)); + + MOCK_METHOD((bool), BTM_BleIsLinkKeyKnown, (const RawAddress address), + (override)); + MOCK_METHOD((std::optional), BTM_BleGetIdentityAddress, + (const RawAddress address), (override)); }; /** diff --git a/system/bta/test/common/mock_controller.cc b/system/bta/test/common/mock_controller.cc index 7cf28651c80bfdb998781c6228ec7ebef305a93f..1aeb5527b21cce0b6d4e290f66442f427701f666 100644 --- a/system/bta/test/common/mock_controller.cc +++ b/system/bta/test/common/mock_controller.cc @@ -57,6 +57,11 @@ bool supports_ble_connected_isochronous_stream_peripheral(void) { ->SupportsBleConnectedIsochronousStreamPeripheral(); } +bool supports_configure_data_path(void) { + LOG_ASSERT(controller_interface) << "Mock controller not set!"; + return controller_interface->SupportsConfigureDataPath(); +} + const controller_t* controller_get_interface() { static controller_t* controller_instance = new controller_t(); @@ -69,6 +74,8 @@ const controller_t* controller_get_interface() { &supports_ble_connected_isochronous_stream_central; controller_instance->supports_ble_connected_isochronous_stream_peripheral = &supports_ble_connected_isochronous_stream_peripheral; + controller_instance->supports_configure_data_path = + &supports_configure_data_path; return controller_instance; } diff --git a/system/bta/test/common/mock_controller.h b/system/bta/test/common/mock_controller.h index 6d27a18e72c4832837107438a49c999584301d3f..d655aa63db5df52fe7895e63ee03af4327248ab8 100644 --- a/system/bta/test/common/mock_controller.h +++ b/system/bta/test/common/mock_controller.h @@ -19,8 +19,6 @@ #include #include -#include "hcimsgs.h" - namespace controller { class ControllerInterface { public: @@ -30,6 +28,7 @@ class ControllerInterface { virtual bool SupportsBleConnectedIsochronousStreamPeripheral(void) = 0; virtual bool SupportsBleIsochronousBroadcaster(void) = 0; virtual bool SupportsBle2mPhy(void) = 0; + virtual bool SupportsConfigureDataPath(void) = 0; virtual ~ControllerInterface() = default; }; @@ -44,6 +43,7 @@ class MockControllerInterface : public ControllerInterface { (override)); MOCK_METHOD((bool), SupportsBleIsochronousBroadcaster, (), (override)); MOCK_METHOD((bool), SupportsBle2mPhy, (), (override)); + MOCK_METHOD((bool), SupportsConfigureDataPath, (), (override)); }; void SetMockControllerInterface( diff --git a/system/bta/test/gatt/database_test.cc b/system/bta/test/gatt/database_test.cc index 77aa57dc8a560a666e815a4a0774b7124d8ff731..16265f3ea5c708c4ae4bbad668240cd61655171d 100644 --- a/system/bta/test/gatt/database_test.cc +++ b/system/bta/test/gatt/database_test.cc @@ -278,7 +278,7 @@ TEST(GattCacheTest, constexpr size_t len = sizeof(StoredAttribute); // clang-format off - uint8_t binary_form[len] = { + std::vector binary_form { /*handle */ 0x03, 0x00, /* type */ 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB, /* characteristic extended properties */ 0x01, 0x00, @@ -288,6 +288,268 @@ TEST(GattCacheTest, // useful for debugging: // LOG(ERROR) << " " << base::HexEncode(&attr, len); - EXPECT_EQ(memcmp(binary_form, &attr, len), 0); + EXPECT_EQ(memcmp(binary_form.data(), &attr, len), 0); + + // Don't use memcmp, for better error messages. + std::vector copied(len, 0); + memcpy(copied.data(), &attr, StoredAttribute::kSizeOnDisk); + + EXPECT_EQ(binary_form, copied); +} + +/* This test makes sure that Descriptor represented in StoredAttribute have + * proper binary format. */ +TEST( + GattCacheTest, + stored_attribute_serialized_to_binary_characteristic_extended_properties_test) { + StoredAttribute attr; + + attr = {.handle = 0x0003, + .type = Uuid::FromString("2900"), + .value = {.characteristic_extended_properties = 0x0001}}; + + constexpr size_t len = StoredAttribute::kSizeOnDisk; + std::vector serialized; + StoredAttribute::SerializeStoredAttribute(attr, serialized); + + // clang-format off + std::vector binary_form { + /*handle */ 0x03, 0x00, + /* type */ 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB, + /* characteristic extended properties */ 0x01, 0x00, + /* clear padding */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + // clang-format on + + EXPECT_EQ(binary_form.size(), len); + EXPECT_EQ(binary_form.size(), serialized.size()); + EXPECT_EQ(binary_form, serialized); +} + +/* This test makes sure that Descriptor represented in StoredAttribute have + * proper binary format. */ +TEST(GattCacheTest, stored_attributes_serialized_to_binary_test) { + // Allocate enough space so that no matter the layout, we don't overflow. + uint8_t attr_bytes[StoredAttribute::kSizeOnDisk * 2]; + // This is the attribute we fill from a binary representation + StoredAttribute attr; + + /* + // Characteristic extended property + attr = {.handle = 0x0003, + .type = Uuid::FromString("2900"), + .value.characteristic_extended_properties = 0x1234}; + LOG(ERROR) << " " << base::HexEncode(&attr, StoredAttribute::kSizeOnDisk); + */ + + memcpy( + attr_bytes, + "\x03\x00" // handle + "\x00\x00\x29\x00\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB" // Uuid + "\x34\x12" /* extended property */ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00", + StoredAttribute::kSizeOnDisk); + attr = *(StoredAttribute*)attr_bytes; + + std::vector serialized; + StoredAttribute::SerializeStoredAttribute(attr, serialized); + std::vector copied(StoredAttribute::kSizeOnDisk, 0); + memcpy(copied.data(), &attr, StoredAttribute::kSizeOnDisk); + + EXPECT_EQ(serialized, copied); + serialized.clear(); + copied = std::vector(StoredAttribute::kSizeOnDisk, 0); + /* + // Primary Service + attr = { + .handle = 0x0203, + .type = Uuid::FromString("2800"), + .value.service = + { + .uuid = Uuid::FromString("4203"), + .end_handle = 0x1203, + }, + }; + LOG(ERROR) << " " << base::HexEncode(&attr, StoredAttribute::kSizeOnDisk); + */ + memcpy( + attr_bytes, + "\x03\x02" // handle + "\x00\x00\x28\x00\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB" // Type + "\x00\x00\x42\x03\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB" // Uuid + "\x03\x12" // end_handle + "\x00\x00", + StoredAttribute::kSizeOnDisk); + attr = *(StoredAttribute*)attr_bytes; + + StoredAttribute::SerializeStoredAttribute(attr, serialized); + memcpy(copied.data(), &attr, StoredAttribute::kSizeOnDisk); + EXPECT_EQ(serialized, copied); + serialized.clear(); + copied = std::vector(StoredAttribute::kSizeOnDisk, 0); + + /* + // Secondary Service + attr = { + .handle = 0x0304, + .type = Uuid::FromString("2801"), + .value.service = + { + .uuid = Uuid::FromString("4303"), + .end_handle = 0x1203, + }, + }; + + LOG(ERROR) << " " << base::HexEncode(&attr, StoredAttribute::kSizeOnDisk); + */ + memcpy( + attr_bytes, + "\x04\x03" // handle + "\x00\x00\x28\x01\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB" // type + "\x00\x00\x43\x03\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB" // UUID + "\x03\x12" // end_handle + "\x00\x000", + StoredAttribute::kSizeOnDisk); + attr = *(StoredAttribute*)attr_bytes; + + StoredAttribute::SerializeStoredAttribute(attr, serialized); + memcpy(copied.data(), &attr, StoredAttribute::kSizeOnDisk); + EXPECT_EQ(serialized, copied); + serialized.clear(); + copied = std::vector(StoredAttribute::kSizeOnDisk, 0); + + /* + // Included Service + attr = { + .handle = 0x0103, + .type = Uuid::FromString("2802"), + .value.included_service = + { + .handle = 0x0134, + .end_handle = 0x0138, + .uuid = Uuid::FromString("3456"), + }, + }; + LOG(ERROR) << " " << base::HexEncode(&attr, StoredAttribute::kSizeOnDisk); + */ + + memcpy( + attr_bytes, + "\x03\x01" // handle + "\x00\x00\x28\x02\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB" // type + "\x34\x01" // handle + "\x38\x01" // end_handle + "\x00\x00\x34\x56\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB", // Uuid + StoredAttribute::kSizeOnDisk); + attr = *(StoredAttribute*)attr_bytes; + + StoredAttribute::SerializeStoredAttribute(attr, serialized); + memcpy(copied.data(), &attr, StoredAttribute::kSizeOnDisk); + EXPECT_EQ(serialized, copied); + serialized.clear(); + copied = std::vector(StoredAttribute::kSizeOnDisk, 0); + + /* + // characteristic definition + attr = { + .handle = 0x0103, + .type = Uuid::FromString("2803"), + .value.characteristic = {.properties = 4, + .value_handle = 0x302, + .uuid = Uuid::FromString("3456")}, + }; + LOG(ERROR) << " " << base::HexEncode(&attr, StoredAttribute::kSizeOnDisk); + */ + memcpy( + attr_bytes, + "\x03\x01" // handle + "\x00\x00\x28\x03\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB" // type + "\x04" // properties + "\x00" // padding + "\x02\x03" // value_handle + "\x00\x00\x34\x56\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB", // uuid + StoredAttribute::kSizeOnDisk); + attr = *(StoredAttribute*)attr_bytes; + + StoredAttribute::SerializeStoredAttribute(attr, serialized); + memcpy(copied.data(), &attr, StoredAttribute::kSizeOnDisk); + EXPECT_EQ(serialized, copied); + serialized.clear(); + copied = std::vector(StoredAttribute::kSizeOnDisk, 0); + + /* + // Unknown Uuid + attr = { + .handle = 0x0103, + .type = Uuid::FromString("4444"), + .value.characteristic = {}, + }; + LOG(ERROR) << " " << base::HexEncode(&attr, StoredAttribute::kSizeOnDisk); + */ + memcpy( + attr_bytes, + "\x03\x01" // handle + "\x00\x00\x44\x44\x00\x00\x10\x00\x80\x00\x00\x80\x5F\x9B\x34\xFB" // type + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00", + StoredAttribute::kSizeOnDisk); + attr = *(StoredAttribute*)attr_bytes; + + StoredAttribute::SerializeStoredAttribute(attr, serialized); + memcpy(copied.data(), &attr, StoredAttribute::kSizeOnDisk); + + EXPECT_EQ(serialized, copied); + serialized.clear(); + copied = std::vector(StoredAttribute::kSizeOnDisk, 0); +} + +// Example from Bluetooth SPEC V5.2, Vol 3, Part G, APPENDIX B +TEST(GattDatabaseTest, serialized_hash_test) { + DatabaseBuilder builder; + builder.AddService(0x0001, 0x0005, Uuid::From16Bit(0x1800), true); + builder.AddService(0x0006, 0x000D, Uuid::From16Bit(0x1801), true); + builder.AddService(0x000E, 0x0013, Uuid::From16Bit(0x1808), true); + builder.AddService(0x0014, 0xFFFF, Uuid::From16Bit(0x180F), false); + + builder.AddCharacteristic(0x0002, 0x0003, Uuid::From16Bit(0x2A00), 0x0A); + builder.AddCharacteristic(0x0004, 0x0005, Uuid::From16Bit(0x2A01), 0x02); + + builder.AddCharacteristic(0x0007, 0x0008, Uuid::From16Bit(0x2A05), 0x20); + builder.AddDescriptor(0x0009, Uuid::From16Bit(0x2902)); + builder.AddCharacteristic(0x000A, 0x000B, Uuid::From16Bit(0x2B29), 0x0A); + builder.AddCharacteristic(0x000C, 0x000D, Uuid::From16Bit(0x2B2A), 0x02); + + builder.AddIncludedService(0x000F, Uuid::From16Bit(0x180F), 0x0014, 0x0016); + builder.AddCharacteristic(0x0010, 0x0011, Uuid::From16Bit(0x2A18), 0xA2); + builder.AddDescriptor(0x0012, Uuid::From16Bit(0x2902)); + builder.AddDescriptor(0x0013, Uuid::From16Bit(0x2900)); + + builder.AddCharacteristic(0x0015, 0x0016, Uuid::From16Bit(0x2A19), 0x02); + + // set characteristic extended properties descriptor values + std::vector descriptorValues = {0x0000}; + builder.SetValueOfDescriptors(descriptorValues); + + Database db = builder.Build(); + + auto serialized = db.Serialize(); + std::vector bytes; + for (auto attr : serialized) { + StoredAttribute::SerializeStoredAttribute(attr, bytes); + } + std::vector attr_from_disk(serialized.size()); + std::copy(bytes.cbegin(), bytes.cend(), (uint8_t*)attr_from_disk.data()); + bool is_successful = false; + Database db_from_disk = + gatt::Database::Deserialize(attr_from_disk, &is_successful); + ASSERT_TRUE(is_successful); + is_successful = false; + Database db_from_serialized = + gatt::Database::Deserialize(serialized, &is_successful); + ASSERT_TRUE(is_successful); + + EXPECT_EQ(db_from_disk.Hash(), db_from_serialized.Hash()); } + } // namespace gatt diff --git a/system/bta/vc/device.cc b/system/bta/vc/device.cc index 7c1cb7cf5075603251db62d524257af9a23f84f4..38611f9ec757325ccf52295ece3c44d3dff1596f 100644 --- a/system/bta/vc/device.cc +++ b/system/bta/vc/device.cc @@ -15,6 +15,8 @@ * limitations under the License. */ +#include + #include #include @@ -22,11 +24,12 @@ #include "bta_gatt_queue.h" #include "devices.h" #include "gatt_api.h" +#include "os/log.h" +#include "os/logging/log_adapter.h" #include "stack/btm/btm_sec.h" +#include "stack/include/bt_types.h" #include "types/bluetooth/uuid.h" -#include - using namespace bluetooth::vc::internal; void VolumeControlDevice::DeregisterNotifications(tGATT_IF gatt_if) { @@ -53,8 +56,6 @@ void VolumeControlDevice::Disconnect(tGATT_IF gatt_if) { BtaGattQueue::Clean(connection_id); BTA_GATTC_Close(connection_id); connection_id = GATT_INVALID_CONN_ID; - } else { - BTA_GATTC_CancelOpen(gatt_if, address, false); } device_ready = false; @@ -418,8 +419,10 @@ bool VolumeControlDevice::IsEncryptionEnabled() { return BTM_IsEncrypted(address, BT_TRANSPORT_LE); } -void VolumeControlDevice::EnableEncryption() { +bool VolumeControlDevice::EnableEncryption() { int result = BTM_SetEncryption(address, BT_TRANSPORT_LE, nullptr, nullptr, BTM_BLE_SEC_ENCRYPT); - LOG(INFO) << __func__ << ": result=" << +result; + LOG_INFO("%s: result=0x%02x", ADDRESS_TO_LOGGABLE_CSTR(address), result); + + return result != BTM_ERR_KEY_MISSING; } diff --git a/system/bta/vc/devices.h b/system/bta/vc/devices.h index 107d00c06307d08912dc3f9051baa4dcf5d5399a..7fe871b14ac86bf7037c082fdc68d17e9f4dc5c8 100644 --- a/system/bta/vc/devices.h +++ b/system/bta/vc/devices.h @@ -137,7 +137,7 @@ class VolumeControlDevice : public bluetooth::common::IRedactableLoggable { GATT_WRITE_OP_CB cb, void* cb_data); bool IsEncryptionEnabled(); - void EnableEncryption(); + bool EnableEncryption(); bool EnqueueInitialRequests(tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb, GATT_WRITE_OP_CB cccd_write_cb); diff --git a/system/bta/vc/devices_test.cc b/system/bta/vc/devices_test.cc index f19c6e1424438d789a21860c17516435e13d6a29..aa2ab5cd7b4375c9d61fff3d2f2c68f227d4b505 100644 --- a/system/bta/vc/devices_test.cc +++ b/system/bta/vc/devices_test.cc @@ -26,6 +26,7 @@ #include "bta_gatt_queue_mock.h" #include "btm_api_mock.h" #include "gatt/database_builder.h" +#include "stack/include/bt_uuid16.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -130,7 +131,6 @@ TEST_F(VolumeControlDevicesTest, test_disconnect) { test_device_0->connection_id = 0x0005; tGATT_IF gatt_if = 8; EXPECT_CALL(gatt_interface, Close(test_device_0->connection_id)); - EXPECT_CALL(gatt_interface, CancelOpen(gatt_if, test_address_1, _)); devices_->Disconnect(gatt_if); } diff --git a/system/bta/vc/vc.cc b/system/bta/vc/vc.cc index 637f56ed595e61f24a258ecb6927641bbd89dcb7..5a112b1981d716a35dafea5cdf0fc9168c6b7071 100644 --- a/system/bta/vc/vc.cc +++ b/system/bta/vc/vc.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,7 @@ #include "osi/include/log.h" #include "osi/include/osi.h" #include "stack/btm/btm_sec.h" +#include "stack/include/bt_types.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -81,23 +83,35 @@ class VolumeControlImpl : public VolumeControl { public: ~VolumeControlImpl() override = default; - VolumeControlImpl(bluetooth::vc::VolumeControlCallbacks* callbacks) + VolumeControlImpl(bluetooth::vc::VolumeControlCallbacks* callbacks, + const base::Closure& initCb) : gatt_if_(0), callbacks_(callbacks), latest_operation_id_(0) { BTA_GATTC_AppRegister( gattc_callback_static, - base::Bind([](uint8_t client_id, uint8_t status) { - if (status != GATT_SUCCESS) { - LOG(ERROR) << "Can't start Volume Control profile - no gatt " - "clients left!"; - return; - } - instance->gatt_if_ = client_id; - }), + base::Bind( + [](const base::Closure& initCb, uint8_t client_id, uint8_t status) { + if (status != GATT_SUCCESS) { + LOG(ERROR) << "Can't start Volume Control profile - no gatt " + "clients left!"; + return; + } + instance->gatt_if_ = client_id; + initCb.Run(); + }, + initCb), true); } + void StartOpportunisticConnect(const RawAddress& address) { + /* Oportunistic works only for direct connect, + * but in fact this is background connect + */ + LOG_INFO(": %s ", ADDRESS_TO_LOGGABLE_CSTR(address)); + BTA_GATTC_Open(gatt_if_, address, BTM_BLE_DIRECT_CONNECTION, true); + } + void Connect(const RawAddress& address) override { - LOG(INFO) << __func__ << " " << ADDRESS_TO_LOGGABLE_STR(address); + LOG_INFO(": %s ", ADDRESS_TO_LOGGABLE_CSTR(address)); auto device = volume_control_devices_.FindByAddress(address); if (!device) { @@ -121,26 +135,29 @@ class VolumeControlImpl : public VolumeControl { } } - BTA_GATTC_Open(gatt_if_, address, BTM_BLE_DIRECT_CONNECTION, false); + StartOpportunisticConnect(address); } - void AddFromStorage(const RawAddress& address, bool auto_connect) { - LOG(INFO) << __func__ << " " << ADDRESS_TO_LOGGABLE_STR(address) - << ", auto_connect=" << auto_connect; - - if (auto_connect) { - volume_control_devices_.Add(address, false); - - /* Add device into BG connection to accept remote initiated connection */ - BTA_GATTC_Open(gatt_if_, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false); - } + void AddFromStorage(const RawAddress& address) { + LOG_INFO("%s ", ADDRESS_TO_LOGGABLE_CSTR(address)); + volume_control_devices_.Add(address, false); + StartOpportunisticConnect(address); } void OnGattConnected(tGATT_STATUS status, uint16_t connection_id, tGATT_IF /*client_if*/, RawAddress address, - tBT_TRANSPORT /*transport*/, uint16_t /*mtu*/) { - LOG(INFO) << __func__ << ": address=" << ADDRESS_TO_LOGGABLE_STR(address) - << ", connection_id=" << connection_id; + tBT_TRANSPORT transport, uint16_t /*mtu*/) { + LOG_INFO("%s, conn_id=0x%04x, transport=%s, status=%s(0x%02x)", + ADDRESS_TO_LOGGABLE_CSTR(address), connection_id, + bt_transport_text(transport).c_str(), + gatt_status_text(status).c_str(), status); + + if (transport != BT_TRANSPORT_LE) { + LOG_WARN("Only LE connection is allowed (transport %s)", + bt_transport_text(transport).c_str()); + BTA_GATTC_Close(connection_id); + return; + } VolumeControlDevice* device = volume_control_devices_.FindByAddress(address); @@ -158,12 +175,21 @@ class VolumeControlImpl : public VolumeControl { device->connection_id = connection_id; + /* Make sure to remove device from background connect. + * It will be added back if needed, when device got disconnected + */ + BTA_GATTC_CancelOpen(gatt_if_, address, false); + if (device->IsEncryptionEnabled()) { OnEncryptionComplete(address, BTM_SUCCESS); return; } - device->EnableEncryption(); + if (!device->EnableEncryption()) { + LOG_ERROR("Link key is not known for %s, disconnect profile", + ADDRESS_TO_LOGGABLE_CSTR(address)); + device->Disconnect(gatt_if_); + } } void OnEncryptionComplete(const RawAddress& address, uint8_t success) { @@ -265,6 +291,11 @@ class VolumeControlImpl : public VolumeControl { return; } + if (!device->IsEncryptionEnabled()) { + LOG_WARN("Device not yet bonded - waiting for encryption"); + return; + } + bool success = device->UpdateHandles(); if (!success) { LOG(ERROR) << "Incomplete service database"; @@ -604,8 +635,8 @@ class VolumeControlImpl : public VolumeControl { return; } - LOG(INFO) << __func__ - << "Successfully register for indications: " << loghex(handle); + LOG_INFO("Successfully registered on ccc: 0x%04x, device: %s", handle, + ADDRESS_TO_LOGGABLE_CSTR(device->address)); verify_device_ready(device, handle); } @@ -627,6 +658,8 @@ class VolumeControlImpl : public VolumeControl { } void Disconnect(const RawAddress& address) override { + LOG_INFO(": %s ", ADDRESS_TO_LOGGABLE_CSTR(address)); + VolumeControlDevice* device = volume_control_devices_.FindByAddress(address); if (!device) { @@ -642,6 +675,15 @@ class VolumeControlImpl : public VolumeControl { device_cleanup_helper(device, true); } + void Remove(const RawAddress& address) override { + LOG_INFO(": %s", ADDRESS_TO_LOGGABLE_CSTR(address)); + + /* Removes all registrations for connection. */ + BTA_GATTC_CancelOpen(gatt_if_, address, false); + + Disconnect(address); + } + void OnGattDisconnected(uint16_t connection_id, tGATT_IF /*client_if*/, RawAddress remote_bda, tGATT_DISCONN_REASON reason) { VolumeControlDevice* device = @@ -661,13 +703,12 @@ class VolumeControlImpl : public VolumeControl { return; } - device_cleanup_helper(device, device->connecting_actively); + bool notify = device->IsReady() || device->connecting_actively; + device_cleanup_helper(device, notify); if (reason != GATT_CONN_TERMINATE_LOCAL_HOST && device->connecting_actively) { - /* Add device into BG connection to accept remote initiated connection */ - BTA_GATTC_Open(gatt_if_, remote_bda, BTM_BLE_BKG_CONNECT_ALLOW_LIST, - false); + StartOpportunisticConnect(remote_bda); } } @@ -798,28 +839,6 @@ class VolumeControlImpl : public VolumeControl { StartQueueOperation(); } - void ProceedVolumeOperation(int operation_id) { - auto op = find_if(ongoing_operations_.begin(), ongoing_operations_.end(), - [operation_id](auto& operation) { - return operation.operation_id_ == operation_id; - }); - - DLOG(INFO) << __func__ << " operation_id: " << operation_id; - - if (op == ongoing_operations_.end()) { - LOG(ERROR) << __func__ - << " Could not find operation_id: " << operation_id; - return; - } - - DLOG(INFO) << __func__ << " procedure continued for operation_id: " - << op->operation_id_; - - alarm_set_on_mloop(op->operation_timeout_, 3000, operation_callback, - INT_TO_PTR(op->operation_id_)); - devices_control_point_helper(op->devices_, op->opcode_, &(op->arguments_)); - } - void PrepareVolumeControlOperation(std::vector devices, int group_id, bool is_autonomous, uint8_t opcode, @@ -883,18 +902,36 @@ class VolumeControlImpl : public VolumeControl { } auto devices = csis_api->GetDeviceList(group_id); + if (devices.empty()) { + LOG_ERROR("group id: %d has no devices", group_id); + return; + } + + bool muteNotChanged = false; + bool deviceNotReady = false; + for (auto it = devices.begin(); it != devices.end();) { auto dev = volume_control_devices_.FindByAddress(*it); - if (!dev || !dev->IsReady() || (dev->mute == mute)) { + if (!dev) { it = devices.erase(it); - } else { - it++; + continue; + } + + if (!dev->IsReady() || (dev->mute == mute)) { + it = devices.erase(it); + muteNotChanged = + muteNotChanged ? muteNotChanged : (dev->mute == mute); + deviceNotReady = deviceNotReady ? deviceNotReady : !dev->IsReady(); + continue; } + it++; } if (devices.empty()) { - LOG(ERROR) << __func__ << " group id : " << group_id - << " is not connected? "; + LOG_DEBUG( + "No need to update mute for group id: %d . muteNotChanged: %d, " + "deviceNotReady: %d", + group_id, muteNotChanged, deviceNotReady); return; } @@ -949,18 +986,37 @@ class VolumeControlImpl : public VolumeControl { } auto devices = csis_api->GetDeviceList(group_id); + if (devices.empty()) { + LOG_ERROR("group id: %d has no devices", group_id); + return; + } + + bool volumeNotChanged = false; + bool deviceNotReady = false; + for (auto it = devices.begin(); it != devices.end();) { auto dev = volume_control_devices_.FindByAddress(*it); - if (!dev || !dev->IsReady() || (dev->volume == volume)) { + if (!dev) { it = devices.erase(it); - } else { - it++; + continue; } + + if (!dev->IsReady() || (dev->volume == volume)) { + it = devices.erase(it); + volumeNotChanged = + volumeNotChanged ? volumeNotChanged : (dev->volume == volume); + deviceNotReady = deviceNotReady ? deviceNotReady : !dev->IsReady(); + continue; + } + + it++; } if (devices.empty()) { - LOG(ERROR) << __func__ << " group id : " << group_id - << " is not connected? "; + LOG_DEBUG( + "No need to update volume for group id: %d . volumeNotChanged: %d, " + "deviceNotReady: %d", + group_id, volumeNotChanged, deviceNotReady); return; } @@ -1203,15 +1259,15 @@ class VolumeControlImpl : public VolumeControl { }; } // namespace -void VolumeControl::Initialize( - bluetooth::vc::VolumeControlCallbacks* callbacks) { +void VolumeControl::Initialize(bluetooth::vc::VolumeControlCallbacks* callbacks, + const base::Closure& initCb) { std::scoped_lock lock(instance_mutex); if (instance) { LOG(ERROR) << "Already initialized!"; return; } - instance = new VolumeControlImpl(callbacks); + instance = new VolumeControlImpl(callbacks, initCb); } bool VolumeControl::IsVolumeControlRunning() { return instance; } @@ -1221,14 +1277,13 @@ VolumeControl* VolumeControl::Get(void) { return instance; }; -void VolumeControl::AddFromStorage(const RawAddress& address, - bool auto_connect) { +void VolumeControl::AddFromStorage(const RawAddress& address) { if (!instance) { LOG(ERROR) << "Not initialized yet"; return; } - instance->AddFromStorage(address, auto_connect); + instance->AddFromStorage(address); }; void VolumeControl::CleanUp() { diff --git a/system/bta/vc/vc_test.cc b/system/bta/vc/vc_test.cc index d095437ae75056f982f0fca2880d7cff034d71a3..761d7b50fcd843eadad3e2b6f625d2be45dcedc7 100644 --- a/system/bta/vc/vc_test.cc +++ b/system/bta/vc/vc_test.cc @@ -27,7 +27,7 @@ #include "gatt/database_builder.h" #include "hardware/bt_gatt_types.h" #include "mock_csis_client.h" -#include "test/common/mock_functions.h" +#include "stack/include/bt_uuid16.h" #include "types.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -317,7 +317,7 @@ class VolumeControlTest : public ::testing::Test { EXPECT_CALL(gatt_interface, AppRegister(_, _, _)) .WillOnce(DoAll(SaveArg<0>(&gatt_callback), SaveArg<1>(&app_register_callback))); - VolumeControl::Initialize(callbacks.get()); + VolumeControl::Initialize(callbacks.get(), base::DoNothing()); ASSERT_TRUE(gatt_callback); ASSERT_TRUE(app_register_callback); app_register_callback.Run(gatt_if, GATT_SUCCESS); @@ -337,33 +337,40 @@ class VolumeControlTest : public ::testing::Test { .WillByDefault(DoAll(Return(true))); EXPECT_CALL(gatt_interface, - Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, _)); + Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, true)); VolumeControl::Get()->Connect(address); Mock::VerifyAndClearExpectations(&gatt_interface); } + void TestRemove(const RawAddress& address, uint16_t conn_id) { + EXPECT_CALL(gatt_interface, CancelOpen(gatt_if, address, false)); + if (conn_id) { + EXPECT_CALL(gatt_interface, Close(conn_id)); + } else { + EXPECT_CALL(gatt_interface, Close(conn_id)).Times(0); + } + VolumeControl::Get()->Remove(address); + Mock::VerifyAndClearExpectations(&gatt_interface); + } + void TestDisconnect(const RawAddress& address, uint16_t conn_id) { if (conn_id) { EXPECT_CALL(gatt_interface, Close(conn_id)); } else { - EXPECT_CALL(gatt_interface, CancelOpen(gatt_if, address, _)); + EXPECT_CALL(gatt_interface, Close(conn_id)).Times(0); } VolumeControl::Get()->Disconnect(address); Mock::VerifyAndClearExpectations(&gatt_interface); } - void TestAddFromStorage(const RawAddress& address, bool auto_connect) { + void TestAddFromStorage(const RawAddress& address) { // by default indicate link as encrypted ON_CALL(btm_interface, BTM_IsEncrypted(address, _)) .WillByDefault(DoAll(Return(true))); - if (auto_connect) { - EXPECT_CALL(gatt_interface, - Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, _)); - } else { - EXPECT_CALL(gatt_interface, Open(gatt_if, address, _, _)).Times(0); - } - VolumeControl::Get()->AddFromStorage(address, auto_connect); + EXPECT_CALL(gatt_interface, + Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, true)); + VolumeControl::Get()->AddFromStorage(address); } void TestSubscribeNotifications(const RawAddress& address, uint16_t conn_id, @@ -425,8 +432,8 @@ class VolumeControlTest : public ::testing::Test { void GetDisconnectedEvent(const RawAddress& address, uint16_t conn_id) { tBTA_GATTC_CLOSE event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, .client_if = gatt_if, .remote_bda = address, .reason = GATT_CONN_TERMINATE_PEER_USER, @@ -437,8 +444,8 @@ class VolumeControlTest : public ::testing::Test { void GetSearchCompleteEvent(uint16_t conn_id) { tBTA_GATTC_SEARCH_CMPL event_data = { - .status = GATT_SUCCESS, .conn_id = conn_id, + .status = GATT_SUCCESS, }; gatt_callback(BTA_GATTC_SEARCH_CMPL_EVT, (tBTA_GATTC*)&event_data); @@ -455,6 +462,8 @@ class VolumeControlTest : public ::testing::Test { void SetEncryptionResult(const RawAddress& address, bool success) { ON_CALL(btm_interface, BTM_IsEncrypted(address, _)) .WillByDefault(DoAll(Return(false))); + ON_CALL(btm_interface, IsLinkKeyKnown(address, _)) + .WillByDefault(DoAll(Return(true))); ON_CALL(btm_interface, SetEncryption(address, _, _, _, BTM_BLE_SEC_ENCRYPT)) .WillByDefault(Invoke( [&success, this](const RawAddress& bd_addr, tBT_TRANSPORT transport, @@ -511,21 +520,34 @@ TEST_F(VolumeControlTest, test_get_uninitialized) { } TEST_F(VolumeControlTest, test_initialize) { - VolumeControl::Initialize(callbacks.get()); + bool init_cb_called = false; + BtaAppRegisterCallback app_register_callback; + EXPECT_CALL(gatt_interface, AppRegister(_, _, _)) + .WillOnce(DoAll(SaveArg<0>(&gatt_callback), + SaveArg<1>(&app_register_callback))); + VolumeControl::Initialize( + callbacks.get(), + base::Bind([](bool* init_cb_called) { *init_cb_called = true; }, + &init_cb_called)); + ASSERT_TRUE(gatt_callback); + ASSERT_TRUE(app_register_callback); + app_register_callback.Run(gatt_if, GATT_SUCCESS); + ASSERT_TRUE(init_cb_called); + ASSERT_TRUE(VolumeControl::IsVolumeControlRunning()); VolumeControl::CleanUp(); } TEST_F(VolumeControlTest, test_initialize_twice) { - VolumeControl::Initialize(callbacks.get()); + VolumeControl::Initialize(callbacks.get(), base::DoNothing()); VolumeControl* volume_control_p = VolumeControl::Get(); - VolumeControl::Initialize(callbacks.get()); + VolumeControl::Initialize(callbacks.get(), base::DoNothing()); ASSERT_EQ(volume_control_p, VolumeControl::Get()); VolumeControl::CleanUp(); } TEST_F(VolumeControlTest, test_cleanup_initialized) { - VolumeControl::Initialize(callbacks.get()); + VolumeControl::Initialize(callbacks.get(), base::DoNothing()); VolumeControl::CleanUp(); ASSERT_FALSE(VolumeControl::IsVolumeControlRunning()); } @@ -595,10 +617,74 @@ TEST_F(VolumeControlTest, test_reconnect_after_interrupted_discovery) { TestAppUnregister(); } +TEST_F(VolumeControlTest, test_reconnect_after_timeout) { + const RawAddress address = GetTestAddress(0); + + // Initial connection + SetSampleDatabaseVOCS(1); + TestAppRegister(); + + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::CONNECTED, address)) + .Times(0); + TestConnect(address); + + // Disconnect not connected device - upper layer times out and needs a + // disconnection event to leave the transient Connecting state + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::DISCONNECTED, address)); + EXPECT_CALL(gatt_interface, CancelOpen(gatt_if, address, false)).Times(0); + TestDisconnect(address, 0); + + // Above the device was not connected and we got Disconnect request from the + // upper layer - it means it has timed-out but still wants to connect, thus + // native is still doing background or opportunistic connect. Let the remote + // device reconnect now. + ON_CALL(gatt_interface, ServiceSearchRequest(_, _)) + .WillByDefault(Invoke( + [&](uint16_t conn_id, const bluetooth::Uuid* p_srvc_uuid) -> void { + if (*p_srvc_uuid == kVolumeControlUuid) + GetSearchCompleteEvent(conn_id); + })); + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::CONNECTED, address)); + EXPECT_CALL(*callbacks, OnDeviceAvailable(address, 2)); + GetConnectedEvent(address, 1); + Mock::VerifyAndClearExpectations(callbacks.get()); + + // Make sure that the upper layer gets the disconnection event even if not + // connecting actively anymore due to the mentioned time-out mechanism. + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::DISCONNECTED, address)); + GetDisconnectedEvent(address, 1); + Mock::VerifyAndClearExpectations(callbacks.get()); + TestAppUnregister(); +} + TEST_F(VolumeControlTest, test_add_from_storage) { TestAppRegister(); - TestAddFromStorage(GetTestAddress(0), true); - TestAddFromStorage(GetTestAddress(1), false); + TestAddFromStorage(GetTestAddress(0)); + TestAppUnregister(); +} + +TEST_F(VolumeControlTest, test_remove_non_connected) { + const RawAddress test_address = GetTestAddress(0); + TestAppRegister(); + TestConnect(test_address); + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::DISCONNECTED, test_address)); + TestRemove(test_address, 0); + TestAppUnregister(); +} + +TEST_F(VolumeControlTest, test_remove_connected) { + const RawAddress test_address = GetTestAddress(0); + TestAppRegister(); + TestConnect(test_address); + GetConnectedEvent(test_address, 1); + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::DISCONNECTED, test_address)); + TestDisconnect(test_address, 1); TestAppUnregister(); } @@ -637,7 +723,7 @@ TEST_F(VolumeControlTest, test_disconnected) { TEST_F(VolumeControlTest, test_disconnected_while_autoconnect) { const RawAddress test_address = GetTestAddress(0); TestAppRegister(); - TestAddFromStorage(test_address, true); + TestAddFromStorage(test_address); GetConnectedEvent(test_address, 1); // autoconnect - don't indicate disconnection EXPECT_CALL(*callbacks, @@ -647,10 +733,31 @@ TEST_F(VolumeControlTest, test_disconnected_while_autoconnect) { TestAppUnregister(); } +TEST_F(VolumeControlTest, test_disconnect_when_link_key_gone) { + const RawAddress test_address = GetTestAddress(0); + TestAppRegister(); + TestAddFromStorage(test_address); + + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)) + .WillByDefault(DoAll(Return(false))); + ON_CALL(btm_interface, + SetEncryption(test_address, _, _, _, BTM_BLE_SEC_ENCRYPT)) + .WillByDefault(Return(BTM_ERR_KEY_MISSING)); + + // autoconnect - don't indicate disconnection + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::DISCONNECTED, test_address)) + .Times(0); + EXPECT_CALL(gatt_interface, Close(1)); + GetConnectedEvent(test_address, 1); + Mock::VerifyAndClearExpectations(&btm_interface); + TestAppUnregister(); +} + TEST_F(VolumeControlTest, test_reconnect_after_encryption_failed) { const RawAddress test_address = GetTestAddress(0); TestAppRegister(); - TestAddFromStorage(test_address, true); + TestAddFromStorage(test_address); SetEncryptionResult(test_address, false); // autoconnect - don't indicate disconnection EXPECT_CALL(*callbacks, @@ -663,6 +770,45 @@ TEST_F(VolumeControlTest, test_reconnect_after_encryption_failed) { TestAppUnregister(); } +TEST_F(VolumeControlTest, test_service_discovery_completed_before_encryption) { + const RawAddress test_address = GetTestAddress(0); + SetSampleDatabaseVCS(1); + TestAppRegister(); + TestConnect(test_address); + + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)) + .WillByDefault(DoAll(Return(false))); + ON_CALL(btm_interface, IsLinkKeyKnown(test_address, _)) + .WillByDefault(DoAll(Return(true))); + ON_CALL(btm_interface, SetEncryption(test_address, _, _, _, _)) + .WillByDefault(Return(BTM_SUCCESS)); + + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::CONNECTED, test_address)) + .Times(0); + uint16_t conn_id = 1; + GetConnectedEvent(test_address, conn_id); + GetSearchCompleteEvent(conn_id); + Mock::VerifyAndClearExpectations(&btm_interface); + Mock::VerifyAndClearExpectations(callbacks.get()); + + EXPECT_CALL(*callbacks, + OnConnectionState(ConnectionState::CONNECTED, test_address)) + .Times(1); + + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)) + .WillByDefault(DoAll(Return(true))); + EXPECT_CALL(gatt_interface, ServiceSearchRequest(_, _)); + + GetEncryptionCompleteEvt(test_address); + GetSearchCompleteEvent(conn_id); + + Mock::VerifyAndClearExpectations(callbacks.get()); + Mock::VerifyAndClearExpectations(&gatt_interface); + + TestAppUnregister(); +} + TEST_F(VolumeControlTest, test_discovery_vcs_found) { const RawAddress test_address = GetTestAddress(0); SetSampleDatabaseVCS(1); diff --git a/system/btcore/Android.bp b/system/btcore/Android.bp index b3b7d45dbcebe2906d5e50efe29a8fe32a814fcc..02e25de69e9643b98d17422630f51c538a2502a8 100644 --- a/system/btcore/Android.bp +++ b/system/btcore/Android.bp @@ -10,7 +10,7 @@ package { cc_defaults { name: "libbtcore_defaults", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], local_include_dirs: ["include"], include_dirs: [ "packages/modules/Bluetooth/system", @@ -36,7 +36,7 @@ cc_defaults { cc_library_static { name: "libbthalutils", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], srcs: [ "src/hal_util.cc", ], @@ -55,6 +55,7 @@ cc_library_static { cflags: ["-D_GNU_SOURCE"], }, }, + static_libs: ["libbt_shim_bridge"], } cc_library_static { @@ -65,11 +66,11 @@ cc_library_static { ], defaults: ["libbtcore_defaults"], min_sdk_version: "Tiramisu", + static_libs: ["libbt_shim_bridge"], } cc_library_headers { name: "libbtcore_headers", - defaults: ["libchrome_support_defaults"], export_include_dirs: ["./"], vendor_available: true, host_supported: true, @@ -85,9 +86,8 @@ cc_library_headers { // libbtcore unit tests for target and host cc_test { name: "net_test_btcore", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -101,13 +101,17 @@ cc_test { "liblog", ], static_libs: [ + "libbluetooth-types", "libbtcore", "libchrome", "libosi", - "libosi-AllocationTestHarness", ], host_supported: true, test_options: { unit_test: true, }, + sanitize: { + address: true, + }, + header_libs: ["libbluetooth_headers"], } diff --git a/system/btcore/BUILD.gn b/system/btcore/BUILD.gn index 4fbe806a203841082da4ff2769def3133e14e847..56485846032061e512f7a02a25b519e10da5f43c 100644 --- a/system/btcore/BUILD.gn +++ b/system/btcore/BUILD.gn @@ -17,6 +17,7 @@ static_library("btcore") { sources = [ "src/device_class.cc", + "src/hal_util.cc", "src/module.cc", "src/osi_module.cc", "src/property.cc", @@ -38,7 +39,6 @@ static_library("btcore") { if (use.test) { executable("net_test_btcore") { sources = [ - "//bt/system/osi/test/AllocationTestHarness.cc", "test/device_class_test.cc", "test/property_test.cc", ] diff --git a/system/btcore/fuzzer/Android.bp b/system/btcore/fuzzer/Android.bp index 03713fe8a82d78d2ee7419f2f1fc450d5c771b74..34305eeb23406c2e11508c25b41a90621d736a93 100644 --- a/system/btcore/fuzzer/Android.bp +++ b/system/btcore/fuzzer/Android.bp @@ -25,13 +25,8 @@ package { cc_defaults { name: "btcore_fuzz_defaults", - cflags: [ - // http://b/264549607 - "-Wno-deprecated-builtins", - // http://b/267867903 - "-Wno-deprecated-declarations", - ], shared_libs: [ + "android.hardware.bluetooth.audio-V2-ndk", "android.hardware.bluetooth@1.0", "android.hardware.bluetooth@1.1", "libcrypto", @@ -41,6 +36,7 @@ cc_defaults { "libbase", "libbluetooth-protos", "libbluetooth-types", + "libbluetooth_crypto_toolbox", "libbluetooth_rust_interop", "libbt-common", "libbt_shim_bridge", @@ -56,7 +52,6 @@ cc_defaults { ], include_dirs: [ "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/gd/rust/shim", ], header_libs: [ "libbluetooth_headers", @@ -64,6 +59,14 @@ cc_defaults { fuzz_config: { cc: ["android-bluetooth-security@google.com"], componentid: 27441, + hotlists: [ + "4593311", + ], + description: "The fuzzer targets the APIs of libbtcore", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped", }, } diff --git a/system/btcore/include/device_class.h b/system/btcore/include/device_class.h index 0bfbf3f4d31eba1615e6d1363ef2ede70f4c22dc..0b65cc8d9907f15b25309f746e14f9d7cd017546 100644 --- a/system/btcore/include/device_class.h +++ b/system/btcore/include/device_class.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include // Provides Class Of Device primitive as specified in the bluetooth spec. diff --git a/system/btcore/src/hal_util.cc b/system/btcore/src/hal_util.cc index ab1a3b40690071ab793fe6d162b234afba74a7b1..18c069930b5c4b1808a313e24a3ff1055a293d90 100644 --- a/system/btcore/src/hal_util.cc +++ b/system/btcore/src/hal_util.cc @@ -16,16 +16,12 @@ #define LOG_TAG "hal_util" +#include "btcore/include/hal_util.h" + #include #include -#include - #include -#include -#include - -#include "btcore/include/hal_util.h" -#include "osi/include/log.h" +#include using base::StringPrintf; diff --git a/system/btcore/src/module.cc b/system/btcore/src/module.cc index f0d643d63fecd10b47c53e9e6e5f4d63110ec2f7..5c73fa5297c12d0705b00f314484b0d34183205e 100644 --- a/system/btcore/src/module.cc +++ b/system/btcore/src/module.cc @@ -27,11 +27,8 @@ #include #include -#include "check.h" #include "common/message_loop_thread.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "os/log.h" using bluetooth::common::MessageLoopThread; diff --git a/system/btcore/test/device_class_test.cc b/system/btcore/test/device_class_test.cc index cc1a1fed522d1e9adc5d6a4858cc035b040e1e6c..64d93e65150f139e706881ae365111e552466328 100644 --- a/system/btcore/test/device_class_test.cc +++ b/system/btcore/test/device_class_test.cc @@ -16,11 +16,10 @@ * ******************************************************************************/ +#include "btcore/include/device_class.h" + #include #include -#include "osi/test/AllocationTestHarness.h" - -#include "btcore/include/device_class.h" ::testing::AssertionResult check_bitfield(const char* m_expr, const char* n_expr, int m, int n) { @@ -41,7 +40,7 @@ << " )"; } -class DeviceClassTest : public AllocationTestHarness {}; +class DeviceClassTest : public ::testing::Test {}; TEST_F(DeviceClassTest, cod_sizeof) { uint8_t dc_stream[] = {0x00, 0x00, 0x00, 0x00}; diff --git a/system/btcore/test/property_test.cc b/system/btcore/test/property_test.cc index 4e24e0d0a1084f86e202f1311ffe58237e598416..e39816c1457564f62e2f20151a74ded1e84fe453 100644 --- a/system/btcore/test/property_test.cc +++ b/system/btcore/test/property_test.cc @@ -21,13 +21,12 @@ #include #include -#include "osi/test/AllocationTestHarness.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" using bluetooth::Uuid; -class PropertyTest : public AllocationTestHarness {}; +class PropertyTest : public ::testing::Test {}; TEST_F(PropertyTest, addr) { RawAddress addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}}; diff --git a/system/btif/Android.bp b/system/btif/Android.bp index 3964ea00112b87ec8f108e244107a507078c2d76..096ba480e65711d471b89f3ee5188bc13603aca8 100644 --- a/system/btif/Android.bp +++ b/system/btif/Android.bp @@ -10,38 +10,21 @@ package { btifCommonIncludes = [ "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/bta/dm", "packages/modules/Bluetooth/system/bta/include", - "packages/modules/Bluetooth/system/bta/sys", - "packages/modules/Bluetooth/system/btif/avrcp", - "packages/modules/Bluetooth/system/btif/co", "packages/modules/Bluetooth/system/btif/include", - "packages/modules/Bluetooth/system/device/include", - "packages/modules/Bluetooth/system/embdrv/sbc/decoder/include", - "packages/modules/Bluetooth/system/embdrv/sbc/encoder/include", "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/include", "packages/modules/Bluetooth/system/internal_include", - "packages/modules/Bluetooth/system/stack/a2dp", - "packages/modules/Bluetooth/system/stack/avdt", - "packages/modules/Bluetooth/system/stack/btm", "packages/modules/Bluetooth/system/stack/include", - "packages/modules/Bluetooth/system/stack/l2cap", - "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/include", - "system/libhwbinder/include", ] cc_library { name: "libstatslog_bt", - defaults: ["fluoride_common_options"], + defaults: ["bluetooth_cflags"], host_supported: true, generated_sources: ["statslog_bt.cpp"], generated_headers: ["statslog_bt.h"], export_generated_headers: ["statslog_bt.h"], - shared_libs: [ - "libcutils", - ], apex_available: [ "com.android.btservices", ], @@ -57,6 +40,7 @@ cc_library { }, host: { static_libs: [ + "libbase", "libstatssocket", ], export_static_lib_headers: [ @@ -69,6 +53,31 @@ cc_library { }, } +cc_library_static { + name: "libbt-jni-thread", + 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/stack/include", + "packages/modules/Bluetooth/system/types", + ], + srcs: ["src/btif_jni_task.cc"], + static_libs: [ + "libbt_shim_bridge", + "libosi", + ], + shared_libs: [ + "libchrome", + ], + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "Tiramisu", +} + genrule { name: "statslog_bt.h", tools: ["stats-log-api-gen"], @@ -89,7 +98,7 @@ genrule { cc_library_static { name: "libbtif", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], include_dirs: btifCommonIncludes, srcs: [ // AVRCP Target Service @@ -121,18 +130,20 @@ cc_library_static { "src/btif_profile_storage.cc", "src/btif_rc.cc", "src/btif_vc.cc", - "src/profile_log_levels.cc", ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], local_include_dirs: [ "include", ], target: { android: { + whole_static_libs: [ + "libPlatformProperties", + ], srcs: ["src/btif_avrcp_audio_track.cc"], + shared_libs: ["libaaudio"], }, host: { srcs: [ @@ -147,13 +158,23 @@ cc_library_static { "lib-bt-packets-avrcp", "lib-bt-packets-base", "libaudio-a2dp-hw-utils", + "libbluetooth-types", "libbt-audio-hal-interface", + "libbt-platform-protos-lite", "libbt-stack", "libbt-stack-core", + "libbt_shim_bridge", "libbtif-core", ], + shared_libs: [ + "android.hardware.bluetooth.audio@2.1", + ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", + ], + apex_available: [ + "com.android.btservices", ], host_supported: true, min_sdk_version: "Tiramisu", @@ -161,15 +182,13 @@ cc_library_static { cc_library_static { name: "libbtif-core", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], include_dirs: btifCommonIncludes, srcs: [ // Callouts "co/bta_dm_co.cc", "co/bta_gatts_co.cc", // BTIF implementation - "src/btif_activity_attribution.cc", - "src/btif_ble_advertiser.cc", "src/btif_ble_scanner.cc", "src/btif_bqr.cc", "src/btif_config.cc", @@ -183,6 +202,7 @@ cc_library_static { "src/btif_gatt_test.cc", "src/btif_gatt_util.cc", "src/btif_iot_config.cc", + "src/btif_jni_task.cc", "src/btif_keystore.cc", "src/btif_metrics_logging.cc", "src/btif_profile_queue.cc", @@ -202,7 +222,6 @@ cc_library_static { ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], target: { android: { @@ -210,6 +229,7 @@ cc_library_static { "libPlatformProperties", ], srcs: ["src/btif_avrcp_audio_track.cc"], + shared_libs: ["libaaudio"], }, host: { srcs: [ @@ -222,85 +242,113 @@ cc_library_static { "lib-bt-packets", "lib-bt-packets-base", "libaudio-a2dp-hw-utils", + "libbluetooth_crypto_toolbox", "libbt-audio-hal-interface", + "libbt-platform-protos-lite", "libbt-stack-core", + "libbt_shim_bridge", + "libstatslog_bt", + ], + whole_static_libs: [ + "bluetooth_flags_c_lib", + ], + shared_libs: [ + "libcrypto", ], cflags: [ - /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/ "-DBUILDCFG", + "-Wno-unused-parameter", + /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/ "-fvisibility=default", ], + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", + header_libs: ["libbluetooth_headers"], } -// btif unit tests for target cc_test { name: "net_test_btif", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", + "latest_android_hardware_audio_common_ndk_static", + "latest_android_hardware_bluetooth_audio_ndk_static", + "latest_android_media_audio_common_types_ndk_static", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], + host_supported: true, include_dirs: btifCommonIncludes, srcs: [ + "test/btif_dm_test.cc", "test/btif_storage_test.cc", ], header_libs: ["libbluetooth_headers"], shared_libs: [ - "android.hardware.bluetooth.audio@2.0", - "android.hardware.bluetooth.audio@2.1", - "libaaudio", "libbinder_ndk", "libcrypto", + "libcutils", "libfmq", "libhidlbase", + "liblog", + "libutils", + "server_configurable_flags", ], static_libs: [ - "android.hardware.bluetooth.a2dp@1.0", - "android.hardware.audio.common-V2-ndk", - "android.hardware.bluetooth.audio-V3-ndk", - "android.hardware.bluetooth@1.0", - "android.hardware.bluetooth@1.1", - "android.hardware.common-V2-ndk", - "android.hardware.common.fmq-V1-ndk", - "android.media.audio.common.types-V2-ndk", - "android.system.suspend.control-V1-ndk", "libFraunhoferAAC", + "libbase", + "libbluetooth-dumpsys", + "libbluetooth-for-tests", "libbluetooth-types", "libbluetooth_core_rs", + "libbluetooth_crypto_toolbox", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", + "libbt-btu-main-thread", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", "libbt-stack-core", + "libbt_shim_bridge", "libbtcore", "libbtdevice", "libbtif", "libbtif-core", "libchrome", + "libcom.android.sysprop.bluetooth.wrapped", + "libevent", + "libflatbuffers-cpp", "libg722codec", + "libgmock", "liblc3", "libopus", "libosi", "libprotobuf-cpp-lite", + "libstatslog_bt", "libudrv-uipc", ], - whole_static_libs: [ - "libbluetooth-dumpsys", - "libbluetooth-for-tests", - ], target: { android: { shared_libs: [ + "android.hardware.bluetooth.audio@2.0", + "android.hardware.bluetooth.audio@2.1", "libPlatformProperties", "libbinder_ndk", + "libstatssocket", + ], + static_libs: [ + "android.hardware.bluetooth.a2dp@1.0", + "android.hardware.bluetooth@1.0", + "android.hardware.bluetooth@1.1", + "android.hardware.common-V2-ndk", + "android.hardware.common.fmq-V1-ndk", + "android.system.suspend.control-V1-ndk", + "libaaudio", ], }, }, @@ -314,11 +362,10 @@ cc_test { cc_test { name: "net_test_btif_profile_queue", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], include_dirs: btifCommonIncludes, srcs: [ "src/btif_profile_queue.cc", @@ -327,26 +374,31 @@ cc_test { header_libs: ["libbluetooth_headers"], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", - "libflatbuffers-cpp", "libosi", ], - cflags: ["-DBUILDCFG"], + cflags: [ + "-DBUILDCFG", + "-Wno-unused-parameter", + ], + shared_libs: ["liblog"], } // btif avrcp audio track unit tests cc_test { name: "net_test_btif_avrcp_audio_track", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], + host_supported: true, include_dirs: btifCommonIncludes + [ "frameworks/av/media/libaaudio/include", ], @@ -359,33 +411,42 @@ cc_test { header_libs: ["libbluetooth_headers"], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], static_libs: [ "libbluetooth-types", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", - "libflatbuffers-cpp", "libosi", ], - cflags: ["-DBUILDCFG"], + shared_libs: [ + "liblog", + ], + cflags: [ + "-DBUILDCFG", + "-Wno-unused-parameter", + ], } // btif rc unit tests for target cc_test { name: "net_test_btif_rc", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, }, include_dirs: btifCommonIncludes, srcs: [ - ":TestCommonLogMsg", + ":TestCommonMockFunctions", + ":TestMockBtaAv", + ":TestMockOsi", + ":TestMockStackAvrc", + "src/btif_util.cc", "test/btif_rc_test.cc", ], header_libs: ["libbluetooth_headers"], @@ -396,14 +457,24 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", - "libosi", - "libosi-AllocationTestHarness", ], - cflags: ["-DBUILDCFG"], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + }, + cflags: [ + "-DBUILDCFG", + "-Wno-unused-parameter", + ], sanitize: { address: true, cfi: true, @@ -415,11 +486,10 @@ cc_test { cc_test { name: "net_test_btif_config_cache", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, @@ -438,6 +508,8 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbt_shim_bridge", "libc++fs", "libchrome", "libgmock", @@ -457,14 +529,15 @@ cc_test { cc_test { name: "net_test_btif_hf_client_service", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], include_dirs: btifCommonIncludes, srcs: [ - ":TestCommonLogMsg", + ":TestCommonMockFunctions", + ":TestFakeOsi", + ":TestMockStack", "test/btif_hf_client_service_test.cc", ], header_libs: ["libbluetooth_headers"], @@ -474,54 +547,38 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", - "libcom.android.sysprop.bluetooth", - "libosi", + "libcom.android.sysprop.bluetooth.wrapped", + ], + cflags: [ + "-DBUILDCFG", + "-Wno-unused-parameter", ], - cflags: ["-DBUILDCFG"], } cc_test { name: "net_test_btif_hh", host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", + "latest_android_hardware_audio_common_ndk_static", + "latest_android_hardware_bluetooth_audio_ndk_static", + "latest_android_media_audio_common_types_ndk_static", "mts_defaults", ], - test_suites: ["device-tests"], - include_dirs: [ - "frameworks/av/media/libaaudio/include", - "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/bta/dm", - "packages/modules/Bluetooth/system/bta/include", - "packages/modules/Bluetooth/system/bta/sys", - "packages/modules/Bluetooth/system/btif/avrcp", - "packages/modules/Bluetooth/system/btif/co", - "packages/modules/Bluetooth/system/btif/include", - "packages/modules/Bluetooth/system/device/include", - "packages/modules/Bluetooth/system/embdrv/sbc/decoder/include", - "packages/modules/Bluetooth/system/embdrv/sbc/encoder/include", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/internal_include", - "packages/modules/Bluetooth/system/stack/a2dp", - "packages/modules/Bluetooth/system/stack/avdt", - "packages/modules/Bluetooth/system/stack/btm", - "packages/modules/Bluetooth/system/stack/include", - "packages/modules/Bluetooth/system/stack/l2cap", - "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/include", - "system/libfmq/include", - "system/libhwbinder/include", - ], + test_suites: ["general-tests"], + include_dirs: btifCommonIncludes + + ["frameworks/av/media/libaaudio/include"], srcs: [ ":BtaDmSources", ":LibBluetoothSources", + ":OsiCompatSources", ":TestCommonCoreInterface", ":TestCommonMainHandler", ":TestCommonMockFunctions", - ":TestMockAndroidHardware", ":TestMockBtaAg", ":TestMockBtaAr", ":TestMockBtaAv", @@ -537,70 +594,80 @@ cc_test { ":TestMockBtaLeAudio", ":TestMockBtaLeAudioHalVerifier", ":TestMockBtaPan", + ":TestMockBtaScn", ":TestMockBtaSdp", ":TestMockBtaSys", ":TestMockBtaVc", ":TestMockBtcore", ":TestMockBtu", - ":TestMockCommon", - ":TestMockFrameworks", ":TestMockHci", ":TestMockMainShim", - ":TestMockOsi", ":TestMockStack", - ":TestMockSystemLibfmq", ":TestMockUdrv", - ":TestMockUtils", "test/btif_hh_test.cc", ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], header_libs: ["libbluetooth_headers"], shared_libs: [ - "android.hardware.bluetooth.audio@2.0", - "android.hardware.bluetooth.audio@2.1", + "libbase", "libcrypto", "libcutils", + "libfmq", "libhidlbase", "liblog", + "libutils", + "server_configurable_flags", ], static_libs: [ "android.hardware.bluetooth.a2dp@1.0", "avrcp-target-service", + "bluetooth_flags_c_lib", "lib-bt-packets", "lib-bt-packets-avrcp", "lib-bt-packets-base", "libaudio-a2dp-hw-utils", "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-audio-hal-interface", + "libbt-common", + "libbt-platform-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", "libbt-stack-core", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libbtif", "libbtif-core", "libc++fs", "libchrome", - "libcom.android.sysprop.bluetooth", + "libcom.android.sysprop.bluetooth.wrapped", "libevent", - "libflatbuffers-cpp", "libgmock", + "libosi", + "libprotobuf-cpp-lite", + "libstatslog_bt", + ], + cflags: [ + "-DBUILDCFG", + "-Wno-unused-parameter", ], - cflags: ["-DBUILDCFG"], target: { android: { static_libs: [ - "android.hardware.audio.common-V2-ndk", - "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", - "android.media.audio.common.types-V2-ndk", ], shared_libs: [ + "android.hardware.bluetooth.audio@2.0", + "android.hardware.bluetooth.audio@2.1", + "libaaudio", "libbinder_ndk", + "libstatssocket", ], }, }, @@ -616,36 +683,15 @@ cc_test { name: "net_test_btif_stack", host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", + "latest_android_hardware_audio_common_ndk_static", + "latest_android_hardware_bluetooth_audio_ndk_static", + "latest_android_media_audio_common_types_ndk_static", "mts_defaults", ], - test_suites: ["device-tests"], - include_dirs: [ - "frameworks/av/media/libaaudio/include", - "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/bta/dm", - "packages/modules/Bluetooth/system/bta/include", - "packages/modules/Bluetooth/system/bta/sys", - "packages/modules/Bluetooth/system/btif/avrcp", - "packages/modules/Bluetooth/system/btif/co", - "packages/modules/Bluetooth/system/btif/include", - "packages/modules/Bluetooth/system/device/include", - "packages/modules/Bluetooth/system/embdrv/sbc/decoder/include", - "packages/modules/Bluetooth/system/embdrv/sbc/encoder/include", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/internal_include", - "packages/modules/Bluetooth/system/stack/a2dp", - "packages/modules/Bluetooth/system/stack/avdt", - "packages/modules/Bluetooth/system/stack/btm", - "packages/modules/Bluetooth/system/stack/include", - "packages/modules/Bluetooth/system/stack/l2cap", - "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/include", - "system/libfmq/include", - "system/libhwbinder/include", - ], + test_suites: ["general-tests"], + include_dirs: btifCommonIncludes + + ["frameworks/av/media/libaaudio/include"], srcs: [ ":BtaDmSources", ":LibBluetoothSources", @@ -653,7 +699,7 @@ cc_test { ":TestCommonCoreInterface", ":TestCommonMainHandler", ":TestCommonMockFunctions", - ":TestMockAndroidHardware", + ":TestFakeOsi", ":TestMockBtaAg", ":TestMockBtaAr", ":TestMockBtaAv", @@ -669,68 +715,76 @@ cc_test { ":TestMockBtaLeAudio", ":TestMockBtaLeAudioHalVerifier", ":TestMockBtaPan", + ":TestMockBtaScn", ":TestMockBtaSdp", ":TestMockBtaSys", ":TestMockBtaVc", ":TestMockBtcore", ":TestMockBtu", - ":TestMockCommon", - ":TestMockFrameworks", ":TestMockHci", ":TestMockMainShim", - ":TestMockOsi", ":TestMockStack", - ":TestMockSystemLibfmq", ":TestMockUdrv", - ":TestMockUtils", "test/btif_core_test.cc", ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], header_libs: ["libbluetooth_headers"], shared_libs: [ - "android.hardware.bluetooth.audio@2.0", - "android.hardware.bluetooth.audio@2.1", + "libbase", "libcrypto", "libcutils", + "libfmq", "libhidlbase", "liblog", + "libutils", + "server_configurable_flags", ], static_libs: [ - "android.hardware.bluetooth.a2dp@1.0", "avrcp-target-service", + "bluetooth_flags_c_lib", "lib-bt-packets", "lib-bt-packets-avrcp", "lib-bt-packets-base", "libaudio-a2dp-hw-utils", "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-audio-hal-interface", + "libbt-common", + "libbt-platform-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libbtif", "libbtif-core", "libc++fs", "libchrome", - "libcom.android.sysprop.bluetooth", + "libcom.android.sysprop.bluetooth.wrapped", "libevent", - "libflatbuffers-cpp", "libgmock", + "libprotobuf-cpp-lite", + "libstatslog_bt", + ], + cflags: [ + "-DBUILDCFG", + "-Wno-unused-parameter", ], - cflags: ["-DBUILDCFG"], target: { android: { static_libs: [ - "android.hardware.audio.common-V2-ndk", - "android.hardware.bluetooth.audio-V3-ndk", + "android.hardware.bluetooth.a2dp@1.0", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", - "android.media.audio.common.types-V2-ndk", ], shared_libs: [ + "android.hardware.bluetooth.audio@2.0", + "android.hardware.bluetooth.audio@2.1", "libbinder_ndk", + "libstatssocket", ], }, }, diff --git a/system/btif/BUILD.gn b/system/btif/BUILD.gn index 483f93979ea8848fc15a420190045dc9a29afa4a..466ef9476e9c0c5d086dde3149a880d09737b2d0 100644 --- a/system/btif/BUILD.gn +++ b/system/btif/BUILD.gn @@ -33,22 +33,17 @@ static_library("btif") { # HAL layer "src/bluetooth.cc", - # Initializing core library - "src/profile_log_levels.cc", - # BTIF implementation "src/btif_a2dp.cc", "src/btif_a2dp_control.cc", "src/btif_a2dp_sink.cc", "src/btif_a2dp_source.cc", - "src/btif_activity_attribution.cc", "src/btif_av.cc", # TODO(abps) - Move this abstraction elsewhere # "src/btif_avrcp_audio_track.cc", "src/btif_avrcp_audio_track_linux.cc", - "src/btif_ble_advertiser.cc", "src/btif_ble_scanner.cc", "src/btif_bqr.cc", "src/btif_csis_client.cc", @@ -64,13 +59,14 @@ static_library("btif") { "src/btif_gatt_util.cc", "src/btif_hd.cc", "src/btif_vc.cc", - #"src/btif_le_audio_broadcaster.cc", - #"src/btif_has_client.cc", + "src/btif_le_audio_broadcaster.cc", + "src/btif_has_client.cc", "src/btif_hearing_aid.cc", "src/btif_hf.cc", "src/btif_hf_client.cc", "src/btif_hh.cc", "src/btif_iot_config.cc", + "src/btif_jni_task.cc", "src/btif_keystore.cc", "src/btif_le_audio.cc", "src/btif_metrics_logging.cc", @@ -90,7 +86,6 @@ static_library("btif") { "src/btif_storage.cc", "src/btif_uid.cc", "src/btif_util.cc", - "src/profile_log_levels.cc", "src/stack_manager.cc", ] diff --git a/system/btif/avrcp/avrcp_service.cc b/system/btif/avrcp/avrcp_service.cc index a960298d163c1533b40b3711fdce66e70ea2f09b..9ec35a3779b753f587eeaefc4fb30e98ee22662d 100644 --- a/system/btif/avrcp/avrcp_service.cc +++ b/system/btif/avrcp/avrcp_service.cc @@ -24,14 +24,13 @@ #include #include -#include "abstract_message_loop.h" #include "bta/sys/bta_sys.h" #include "btif_av.h" #include "btif_common.h" -#include "btif_dm.h" #include "device.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/main_thread.h" #include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -109,7 +108,7 @@ class AvrcpInterfaceImpl : public AvrcpInterface { uint16_t MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR* p_pkt) override { - return AVRC_MsgReq(handle, label, ctype, p_pkt); + return AVRC_MsgReq(handle, label, ctype, p_pkt, true); } void SaveControllerVersion(const RawAddress& bdaddr, @@ -163,7 +162,7 @@ class MediaInterfaceWrapper : public MediaInterface { void GetSongInfo(SongInfoCallback info_cb) override { auto cb_lambda = [](SongInfoCallback cb, SongInfo data) { - do_in_main_thread(FROM_HERE, base::Bind(cb, data)); + do_in_main_thread(FROM_HERE, base::BindOnce(cb, data)); }; auto bound_cb = base::Bind(cb_lambda, info_cb); @@ -174,7 +173,7 @@ class MediaInterfaceWrapper : public MediaInterface { void GetPlayStatus(PlayStatusCallback status_cb) override { auto cb_lambda = [](PlayStatusCallback cb, PlayStatus status) { - do_in_main_thread(FROM_HERE, base::Bind(cb, status)); + do_in_main_thread(FROM_HERE, base::BindOnce(cb, status)); }; auto bound_cb = base::Bind(cb_lambda, status_cb); @@ -186,8 +185,8 @@ class MediaInterfaceWrapper : public MediaInterface { void GetNowPlayingList(NowPlayingCallback now_playing_cb) override { auto cb_lambda = [](NowPlayingCallback cb, std::string curr_media_id, std::vector song_list) { - do_in_main_thread(FROM_HERE, - base::Bind(cb, curr_media_id, std::move(song_list))); + do_in_main_thread( + FROM_HERE, base::BindOnce(cb, curr_media_id, std::move(song_list))); }; auto bound_cb = base::Bind(cb_lambda, now_playing_cb); @@ -199,8 +198,8 @@ class MediaInterfaceWrapper : public MediaInterface { void GetMediaPlayerList(MediaListCallback list_cb) override { auto cb_lambda = [](MediaListCallback cb, uint16_t curr_player, std::vector player_list) { - do_in_main_thread(FROM_HERE, - base::Bind(cb, curr_player, std::move(player_list))); + do_in_main_thread( + FROM_HERE, base::BindOnce(cb, curr_player, std::move(player_list))); }; auto bound_cb = base::Bind(cb_lambda, list_cb); @@ -213,7 +212,7 @@ class MediaInterfaceWrapper : public MediaInterface { FolderItemsCallback folder_cb) override { auto cb_lambda = [](FolderItemsCallback cb, std::vector item_list) { - do_in_main_thread(FROM_HERE, base::Bind(cb, std::move(item_list))); + do_in_main_thread(FROM_HERE, base::BindOnce(cb, std::move(item_list))); }; auto bound_cb = base::Bind(cb_lambda, folder_cb); @@ -227,7 +226,8 @@ class MediaInterfaceWrapper : public MediaInterface { SetBrowsedPlayerCallback browse_cb) override { auto cb_lambda = [](SetBrowsedPlayerCallback cb, bool success, std::string root_id, uint32_t num_items) { - do_in_main_thread(FROM_HERE, base::Bind(cb, success, root_id, num_items)); + do_in_main_thread(FROM_HERE, + base::BindOnce(cb, success, root_id, num_items)); }; auto bound_cb = base::Bind(cb_lambda, browse_cb); @@ -276,7 +276,7 @@ class VolumeInterfaceWrapper : public VolumeInterface { void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) override { auto cb_lambda = [](VolumeChangedCb cb, int8_t volume) { - do_in_main_thread(FROM_HERE, base::Bind(cb, volume)); + do_in_main_thread(FROM_HERE, base::BindOnce(cb, volume)); }; auto bound_cb = base::Bind(cb_lambda, cb); @@ -311,7 +311,7 @@ class PlayerSettingsInterfaceWrapper : public PlayerSettingsInterface { void ListPlayerSettings(ListPlayerSettingsCallback cb) override { auto cb_lambda = [](const ListPlayerSettingsCallback& cb, std::vector attributes) { - do_in_main_thread(FROM_HERE, base::Bind(cb, std::move(attributes))); + do_in_main_thread(FROM_HERE, base::BindOnce(cb, std::move(attributes))); }; auto bound_cb = base::Bind(cb_lambda, cb); @@ -324,7 +324,8 @@ class PlayerSettingsInterfaceWrapper : public PlayerSettingsInterface { ListPlayerSettingValuesCallback cb) override { auto cb_lambda = [](const ListPlayerSettingValuesCallback& cb, PlayerAttribute setting, std::vector values) { - do_in_main_thread(FROM_HERE, base::Bind(cb, setting, std::move(values))); + do_in_main_thread(FROM_HERE, + base::BindOnce(cb, setting, std::move(values))); }; auto bound_cb = base::Bind(cb_lambda, cb); @@ -340,8 +341,8 @@ class PlayerSettingsInterfaceWrapper : public PlayerSettingsInterface { auto cb_lambda = [](const GetCurrentPlayerSettingValueCallback& cb, std::vector attributes, std::vector values) { - do_in_main_thread( - FROM_HERE, base::Bind(cb, std::move(attributes), std::move(values))); + do_in_main_thread(FROM_HERE, base::BindOnce(cb, std::move(attributes), + std::move(values))); }; auto bound_cb = base::Bind(cb_lambda, cb); @@ -355,7 +356,7 @@ class PlayerSettingsInterfaceWrapper : public PlayerSettingsInterface { std::vector values, SetPlayerSettingValueCallback cb) override { auto cb_lambda = [](const SetPlayerSettingValueCallback& cb, bool success) { - do_in_main_thread(FROM_HERE, base::Bind(cb, success)); + do_in_main_thread(FROM_HERE, base::BindOnce(cb, success)); }; auto bound_cb = base::Bind(cb_lambda, cb); @@ -521,8 +522,9 @@ void AvrcpService::SendMediaUpdate(bool track_changed, bool play_state, // device update happens on the main thread. for (const auto& device : instance_->connection_handler_->GetListOfDevices()) { - do_in_main_thread(FROM_HERE, - base::Bind(&Device::SendMediaUpdate, device.get()->Get(), track_changed, play_state, queue)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&Device::SendMediaUpdate, device.get()->Get(), + track_changed, play_state, queue)); } } @@ -536,8 +538,10 @@ void AvrcpService::SendFolderUpdate(bool available_players, // Ensure that the update is posted to the correct thread for (const auto& device : instance_->connection_handler_->GetListOfDevices()) { - do_in_main_thread(FROM_HERE, base::Bind(&Device::SendFolderUpdate, device.get()->Get(), available_players, - addressed_players, uids)); + do_in_main_thread( + FROM_HERE, + base::BindOnce(&Device::SendFolderUpdate, device.get()->Get(), + available_players, addressed_players, uids)); } } @@ -568,8 +572,8 @@ void AvrcpService::SendPlayerSettingsChanged( for (const auto& device : instance_->connection_handler_->GetListOfDevices()) { do_in_main_thread(FROM_HERE, - base::Bind(&Device::HandlePlayerSettingChanged, - device.get()->Get(), attributes, values)); + base::BindOnce(&Device::HandlePlayerSettingChanged, + device.get()->Get(), attributes, values)); } } @@ -596,31 +600,34 @@ void AvrcpService::ServiceInterfaceImpl::Init( instance_ = new AvrcpService(); do_in_main_thread( - FROM_HERE, - base::Bind(&AvrcpService::Init, base::Unretained(instance_), - media_interface, volume_interface, player_settings_interface)); + FROM_HERE, base::BindOnce(&AvrcpService::Init, + base::Unretained(instance_), media_interface, + volume_interface, player_settings_interface)); } void AvrcpService::ServiceInterfaceImpl::RegisterBipServer(int psm) { std::lock_guard lock(service_interface_lock_); CHECK(instance_ != nullptr); - do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::RegisterBipServer, - base::Unretained(instance_), psm)); + do_in_main_thread(FROM_HERE, + base::BindOnce(&AvrcpService::RegisterBipServer, + base::Unretained(instance_), psm)); } void AvrcpService::ServiceInterfaceImpl::UnregisterBipServer() { std::lock_guard lock(service_interface_lock_); CHECK(instance_ != nullptr); - do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::UnregisterBipServer, - base::Unretained(instance_))); + do_in_main_thread(FROM_HERE, + base::BindOnce(&AvrcpService::UnregisterBipServer, + base::Unretained(instance_))); } bool AvrcpService::ServiceInterfaceImpl::ConnectDevice( const RawAddress& bdaddr) { std::lock_guard lock(service_interface_lock_); CHECK(instance_ != nullptr); - do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::ConnectDevice, - base::Unretained(instance_), bdaddr)); + do_in_main_thread(FROM_HERE, + base::BindOnce(&AvrcpService::ConnectDevice, + base::Unretained(instance_), bdaddr)); return true; } @@ -628,8 +635,9 @@ bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice( const RawAddress& bdaddr) { std::lock_guard lock(service_interface_lock_); CHECK(instance_ != nullptr); - do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::DisconnectDevice, - base::Unretained(instance_), bdaddr)); + do_in_main_thread(FROM_HERE, + base::BindOnce(&AvrcpService::DisconnectDevice, + base::Unretained(instance_), bdaddr)); return true; } @@ -637,9 +645,9 @@ void AvrcpService::ServiceInterfaceImpl::SetBipClientStatus( const RawAddress& bdaddr, bool connected) { std::lock_guard lock(service_interface_lock_); CHECK(instance_ != nullptr); - do_in_main_thread(FROM_HERE, base::Bind(&AvrcpService::SetBipClientStatus, - base::Unretained(instance_), bdaddr, - connected)); + do_in_main_thread(FROM_HERE, base::BindOnce(&AvrcpService::SetBipClientStatus, + base::Unretained(instance_), + bdaddr, connected)); } bool AvrcpService::ServiceInterfaceImpl::Cleanup() { @@ -647,8 +655,8 @@ bool AvrcpService::ServiceInterfaceImpl::Cleanup() { if (instance_ == nullptr) return false; - do_in_main_thread(FROM_HERE, - base::Bind(&AvrcpService::Cleanup, base::Owned(instance_))); + do_in_main_thread(FROM_HERE, base::BindOnce(&AvrcpService::Cleanup, + base::Owned(instance_))); // Setting instance to nullptr here is fine since it will be deleted on the // other thread. @@ -674,15 +682,20 @@ void AvrcpService::DebugDump(int fd) { device_list.size()); std::stringstream stream; - { - ScopedIndent indent(stream); - for (const auto& device : device_list) { - stream << *device << std::endl; - } + for (const auto& device : device_list) { + stream << " " << *device << std::endl; } dprintf(fd, "%s", stream.str().c_str()); } +/** when a2dp connected, btif will start register vol changed, so we need a + * interface for it. */ +void AvrcpService::RegisterVolChanged(const RawAddress& bdaddr) { + LOG(INFO) << ": address=" << ADDRESS_TO_LOGGABLE_STR(bdaddr); + + connection_handler_->RegisterVolChanged(bdaddr); +} + } // namespace avrcp } // namespace bluetooth diff --git a/system/btif/avrcp/avrcp_service.h b/system/btif/avrcp/avrcp_service.h index 20a35444fba3b578feae47157ae99c0c43025185..7bd9081e00fb5f7bacfbce35c3d171556f03c69c 100644 --- a/system/btif/avrcp/avrcp_service.h +++ b/system/btif/avrcp/avrcp_service.h @@ -76,6 +76,10 @@ class AvrcpService : public MediaCallbacks { void SendPlayerSettingsChanged(std::vector attributes, std::vector values) override; + /** when a2dp connected, btif will start register vol changed, so we need a + * interface for it. */ + void RegisterVolChanged(const RawAddress& bdaddr); + class ServiceInterfaceImpl : public ServiceInterface { public: void Init(MediaInterface* media_interface, diff --git a/system/btif/co/bta_av_co.cc b/system/btif/co/bta_av_co.cc index 08a86eb5f89c60d6ec6b363d5557f9a63eef1de0..2a290cc10b048e20c1795b2d703f6553c55dd4d3 100644 --- a/system/btif/co/bta_av_co.cc +++ b/system/btif/co/bta_av_co.cc @@ -28,20 +28,21 @@ #include #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/include/bta_av_api.h" #include "bta/include/bta_av_ci.h" #include "btif/include/btif_a2dp_source.h" #include "btif/include/btif_av.h" #include "device/include/device_iot_config.h" #include "include/hardware/bt_av.h" +#include "internal_include/bt_trace.h" +#include "osi/include/allocator.h" #include "osi/include/osi.h" // UNUSED_ATTR -#include "osi/include/allocator.h" // UNUSED_ATTR #include "stack/include/a2dp_codec_api.h" #include "stack/include/a2dp_error_codes.h" #include "stack/include/avdt_api.h" #include "stack/include/bt_hdr.h" -#include "types/bluetooth/uuid.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "types/raw_address.h" // Macro to retrieve the number of elements in a statically allocated array @@ -389,6 +390,13 @@ class BtaAvCo { */ bool SetActivePeer(const RawAddress& peer_address); + /** + * Save the reconfig codec + * + * @param new_codec_config the new codec config + */ + void SaveCodec(const uint8_t* new_codec_config); + /** * Get the encoder parameters for a peer. * @@ -405,13 +413,6 @@ class BtaAvCo { */ const tA2DP_ENCODER_INTERFACE* GetSourceEncoderInterface(); - /** - * Get the Sink decoder interface for the current codec. - * - * @return the Sink decoder interface for the current codec - */ - const tA2DP_DECODER_INTERFACE* GetSinkDecoderInterface(); - /** * Set the codec user configuration. * @@ -705,11 +706,7 @@ class BtaAvCo { const uint8_t bta_av_co_cp_scmst[AVDT_CP_INFO_LEN] = {0x02, 0x02, 0x00}; // Control block instance -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -static const bool kContentProtectEnabled = true; -#else static const bool kContentProtectEnabled = false; -#endif static BtaAvCo bta_av_co_cb(kContentProtectEnabled); void BtaAvCoPeer::Init( @@ -755,7 +752,7 @@ void BtaAvCoPeer::Reset(tBTA_AV_HNDL bta_av_handle) { void BtaAvCo::Init( const std::vector& codec_priorities) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); std::lock_guard lock(codec_lock_); @@ -792,7 +789,10 @@ bool BtaAvCo::IsSupportedCodec(btav_a2dp_codec_index_t codec_index) { // All peer state is initialized with the same local codec config, // hence we check only the first peer. A2dpCodecs* codecs = peers_[0].GetCodecs(); - CHECK(codecs != nullptr); + if (codecs == nullptr) { + LOG_ERROR("Peer codecs is set to null"); + return false; + } return codecs->isSupportedCodec(codec_index); } @@ -830,14 +830,13 @@ BtaAvCoPeer* BtaAvCo::FindPeer(tBTA_AV_HNDL bta_av_handle) { index = BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle); - APPL_TRACE_DEBUG("%s: bta_av_handle = 0x%x index = %d", __func__, - bta_av_handle, index); + LOG_VERBOSE("%s: bta_av_handle = 0x%x index = %d", __func__, bta_av_handle, + index); // Sanity check if (index >= BTA_AV_CO_NUM_ELEMENTS(peers_)) { - APPL_TRACE_ERROR( - "%s: peer index %d for BTA AV handle 0x%x is out of bounds", __func__, - index, bta_av_handle); + LOG_ERROR("%s: peer index %d for BTA AV handle 0x%x is out of bounds", + __func__, index, bta_av_handle); return nullptr; } @@ -846,20 +845,19 @@ BtaAvCoPeer* BtaAvCo::FindPeer(tBTA_AV_HNDL bta_av_handle) { BtaAvCoPeer* BtaAvCo::FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address) { - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle = 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); + LOG_VERBOSE("%s: peer %s bta_av_handle = 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); BtaAvCoPeer* p_peer = FindPeer(bta_av_handle); if (p_peer == nullptr) { - APPL_TRACE_ERROR("%s: peer entry for BTA AV handle 0x%x peer %s not found", - __func__, bta_av_handle, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: peer entry for BTA AV handle 0x%x peer %s not found", + __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return nullptr; } - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle = 0x%x previous address %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), - bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: peer %s bta_av_handle = 0x%x previous address %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); p_peer->addr = peer_address; return p_peer; } @@ -876,7 +874,7 @@ void BtaAvCo::ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, uint8_t num_seps, uint8_t num_sinks, uint8_t num_sources, uint16_t uuid_local) { - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer %s bta_av_handle:0x%x num_seps:%d num_sinks:%d num_sources:%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, num_seps, num_sinks, num_sources); @@ -884,16 +882,15 @@ void BtaAvCo::ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle, // Find the peer BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { - APPL_TRACE_ERROR( - "%s: could not find peer entry for bta_av_handle 0x%x peer %s", - __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: could not find peer entry for bta_av_handle 0x%x peer %s", + __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return; } /* Sanity check : this should never happen */ if (p_peer->opened) { - APPL_TRACE_ERROR("%s: peer %s already opened", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: peer %s already opened", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); } /* Copy the discovery results */ @@ -918,26 +915,25 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, uint8_t* p_codec_info, uint8_t* p_sep_info_idx, uint8_t seid, uint8_t* p_num_protect, uint8_t* p_protect_info) { - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle:0x%x codec:%s seid:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, - A2DP_CodecName(p_codec_info), seid); - APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", - __func__, *p_num_protect, p_protect_info[0], - p_protect_info[1], p_protect_info[2]); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_codec_info).c_str()); + LOG_VERBOSE("%s: peer %s bta_av_handle:0x%x codec:%s seid:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, + A2DP_CodecName(p_codec_info), seid); + LOG_VERBOSE("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", __func__, + *p_num_protect, p_protect_info[0], p_protect_info[1], + p_protect_info[2]); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_codec_info).c_str()); // Find the peer BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { - APPL_TRACE_ERROR( - "%s: could not find peer entry for bta_av_handle 0x%x peer %s", - __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: could not find peer entry for bta_av_handle 0x%x peer %s", + __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return A2DP_FAIL; } - APPL_TRACE_DEBUG("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)", - __func__, p_peer->opened, p_peer->num_sinks, - p_peer->num_rx_sinks, p_peer->num_sup_sinks); + LOG_VERBOSE("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)", + __func__, p_peer->opened, p_peer->num_sinks, p_peer->num_rx_sinks, + p_peer->num_sup_sinks); p_peer->num_rx_sinks++; @@ -947,9 +943,9 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( if (p_peer->num_sup_sinks < BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks)) { BtaAvCoSep* p_sink = &p_peer->sinks[p_peer->num_sup_sinks++]; - APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__, - p_codec_info[1], p_codec_info[2], p_codec_info[3], - p_codec_info[4], p_codec_info[5], p_codec_info[6]); + LOG_VERBOSE("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__, + p_codec_info[1], p_codec_info[2], p_codec_info[3], + p_codec_info[4], p_codec_info[5], p_codec_info[6]); memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE); p_sink->sep_info_idx = *p_sep_info_idx; @@ -957,8 +953,8 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( p_sink->num_protect = *p_num_protect; memcpy(p_sink->protect_info, p_protect_info, AVDT_CP_INFO_LEN); } else { - APPL_TRACE_ERROR("%s: peer %s : no more room for Sink info", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: peer %s : no more room for Sink info", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); } } @@ -968,9 +964,9 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) { return A2DP_FAIL; } - APPL_TRACE_DEBUG("%s: last Sink codec reached for peer %s (local %s)", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), - p_peer->acceptor ? "acceptor" : "initiator"); + LOG_VERBOSE("%s: last Sink codec reached for peer %s (local %s)", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), + p_peer->acceptor ? "acceptor" : "initiator"); bta_av_co_store_peer_codectype(p_peer); @@ -985,8 +981,8 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( } p_sink = p_peer->p_sink; if (p_sink == nullptr) { - APPL_TRACE_ERROR("%s: cannot find the selected codec for peer %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: cannot find the selected codec for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); return A2DP_FAIL; } } else { @@ -994,8 +990,8 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( // Apply user preferred codec directly before first codec selected. p_sink = FindPeerSink(p_peer, BTAV_A2DP_CODEC_INDEX_SOURCE_SBC); if (p_sink != nullptr) { - APPL_TRACE_API("%s: mandatory codec preferred for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: mandatory codec preferred for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); btav_a2dp_codec_config_t high_priority_mandatory{ .codec_type = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, .codec_priority = BTAV_A2DP_CODEC_PRIORITY_HIGHEST, @@ -1012,14 +1008,14 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( result_codec_config, &restart_input, &restart_output, &config_updated); } else { - APPL_TRACE_WARNING("%s: mandatory codec not found for peer %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_WARN("%s: mandatory codec not found for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); } } p_sink = SelectSourceCodec(p_peer); if (p_sink == nullptr) { - APPL_TRACE_ERROR("%s: cannot set up codec for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: cannot set up codec for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); return A2DP_FAIL; } } @@ -1033,14 +1029,14 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( // If acceptor -> reconfig otherwise reply for configuration *p_sep_info_idx = p_sink->sep_info_idx; - APPL_TRACE_EVENT("%s: peer %s acceptor:%s reconfig_needed:%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), - (p_peer->acceptor) ? "true" : "false", - (p_peer->reconfig_needed) ? "true" : "false"); + LOG_VERBOSE("%s: peer %s acceptor:%s reconfig_needed:%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), + (p_peer->acceptor) ? "true" : "false", + (p_peer->reconfig_needed) ? "true" : "false"); if (p_peer->acceptor) { if (p_peer->reconfig_needed) { - APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__, - bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__, + bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); BTA_AvReconfig(bta_av_handle, true, p_sink->sep_info_idx, p_peer->codec_config, *p_num_protect, bta_av_co_cp_scmst); } @@ -1064,24 +1060,23 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, uint8_t* p_protect_info) { std::lock_guard lock(codec_lock_); - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle:0x%x codec:%s seid:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, - A2DP_CodecName(p_codec_info), seid); - APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", - __func__, *p_num_protect, p_protect_info[0], - p_protect_info[1], p_protect_info[2]); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_codec_info).c_str()); + LOG_VERBOSE("%s: peer %s bta_av_handle:0x%x codec:%s seid:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, + A2DP_CodecName(p_codec_info), seid); + LOG_VERBOSE("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", __func__, + *p_num_protect, p_protect_info[0], p_protect_info[1], + p_protect_info[2]); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_codec_info).c_str()); // Find the peer BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { - APPL_TRACE_ERROR( - "%s: could not find peer entry for bta_av_handle 0x%x peer %s", - __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: could not find peer entry for bta_av_handle 0x%x peer %s", + __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return A2DP_FAIL; } - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer %s found (o=%d, n_sources=%d, n_rx_sources=%d, " "n_sup_sources=%d)", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), p_peer->opened, @@ -1095,9 +1090,9 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, if (p_peer->num_sup_sources < BTA_AV_CO_NUM_ELEMENTS(p_peer->sources)) { BtaAvCoSep* p_source = &p_peer->sources[p_peer->num_sup_sources++]; - APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__, - p_codec_info[1], p_codec_info[2], p_codec_info[3], - p_codec_info[4], p_codec_info[5], p_codec_info[6]); + LOG_VERBOSE("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__, + p_codec_info[1], p_codec_info[2], p_codec_info[3], + p_codec_info[4], p_codec_info[5], p_codec_info[6]); memcpy(p_source->codec_caps, p_codec_info, AVDT_CODEC_SIZE); p_source->sep_info_idx = *p_sep_info_idx; @@ -1105,8 +1100,8 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, p_source->num_protect = *p_num_protect; memcpy(p_source->protect_info, p_protect_info, AVDT_CP_INFO_LEN); } else { - APPL_TRACE_ERROR("%s: peer %s : no more room for Source info", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: peer %s : no more room for Source info", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); } } @@ -1116,8 +1111,8 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, (p_peer->num_sup_sources != BTA_AV_CO_NUM_ELEMENTS(p_peer->sources))) { return A2DP_FAIL; } - APPL_TRACE_DEBUG("%s: last Source codec reached for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: last Source codec reached for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); // Select the Sink codec const BtaAvCoSep* p_source = nullptr; @@ -1130,15 +1125,15 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, } p_source = p_peer->p_source; if (p_source == nullptr) { - APPL_TRACE_ERROR("%s: cannot find the selected codec for peer %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: cannot find the selected codec for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); return A2DP_FAIL; } } else { p_source = SelectSinkCodec(p_peer); if (p_source == nullptr) { - APPL_TRACE_ERROR("%s: cannot set up codec for the peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: cannot set up codec for the peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); return A2DP_FAIL; } } @@ -1152,14 +1147,14 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, // If acceptor -> reconfig otherwise reply for configuration *p_sep_info_idx = p_source->sep_info_idx; - APPL_TRACE_EVENT("%s: peer %s acceptor:%s reconfig_needed:%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), - (p_peer->acceptor) ? "true" : "false", - (p_peer->reconfig_needed) ? "true" : "false"); + LOG_VERBOSE("%s: peer %s acceptor:%s reconfig_needed:%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), + (p_peer->acceptor) ? "true" : "false", + (p_peer->reconfig_needed) ? "true" : "false"); if (p_peer->acceptor) { if (p_peer->reconfig_needed) { - APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__, - bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__, + bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); BTA_AvReconfig(bta_av_handle, true, p_source->sep_info_idx, p_peer->codec_config, *p_num_protect, bta_av_co_cp_scmst); } @@ -1180,33 +1175,32 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, uint8_t category = A2DP_SUCCESS; bool reconfig_needed = false; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: bta_av_handle=0x%x peer_address=%s seid=%d " "num_protect=%d t_local_sep=%d avdt_handle=%d", __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address), seid, num_protect, t_local_sep, avdt_handle); - APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__, - p_codec_info[1], p_codec_info[2], p_codec_info[3], - p_codec_info[4], p_codec_info[5], p_codec_info[6]); - APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", - __func__, num_protect, p_protect_info[0], p_protect_info[1], - p_protect_info[2]); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_codec_info).c_str()); + LOG_VERBOSE("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__, p_codec_info[1], + p_codec_info[2], p_codec_info[3], p_codec_info[4], + p_codec_info[5], p_codec_info[6]); + LOG_VERBOSE("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", __func__, + num_protect, p_protect_info[0], p_protect_info[1], + p_protect_info[2]); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_codec_info).c_str()); // Find the peer BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { - APPL_TRACE_ERROR( - "%s: could not find peer entry for bta_av_handle 0x%x peer %s", - __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: could not find peer entry for bta_av_handle 0x%x peer %s", + __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); // Call call-in rejecting the configuration bta_av_ci_setconfig(bta_av_handle, A2DP_BUSY, AVDT_ASC_CODEC, 0, nullptr, false, avdt_handle); return; } - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer %s found (o=%d, n_sinks=%d, n_rx_sinks=%d, " "n_sup_sinks=%d)", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), p_peer->opened, @@ -1214,23 +1208,23 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, // Sanity check: should not be opened at this point if (p_peer->opened) { - APPL_TRACE_ERROR("%s: peer %s already in use", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: peer %s already in use", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); } if (num_protect != 0) { if (ContentProtectEnabled()) { if ((num_protect != 1) || !BtaAvCo::ContentProtectIsScmst(p_protect_info)) { - APPL_TRACE_ERROR("%s: wrong CP configuration for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: wrong CP configuration for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); status = A2DP_BAD_CP_TYPE; category = AVDT_ASC_PROTECT; } } else { // Do not support content protection for the time being - APPL_TRACE_ERROR("%s: wrong CP configuration for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: wrong CP configuration for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); status = A2DP_BAD_CP_TYPE; category = AVDT_ASC_PROTECT; } @@ -1240,8 +1234,8 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, bool codec_config_supported = false; if (t_local_sep == AVDT_TSEP_SNK) { - APPL_TRACE_DEBUG("%s: peer %s is A2DP Source", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: peer %s is A2DP Source", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); codec_config_supported = A2DP_IsSinkCodecSupported(p_codec_info); if (codec_config_supported) { // If Peer is Source, and our config subset matches with what is @@ -1250,17 +1244,17 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, } } if (t_local_sep == AVDT_TSEP_SRC) { - APPL_TRACE_DEBUG("%s: peer %s is A2DP SINK", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: peer %s is A2DP SINK", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); // Ignore the restart_output flag: accepting the remote device's // codec selection should not trigger codec reconfiguration. bool dummy_restart_output = false; if ((p_peer->GetCodecs() == nullptr) || !SetCodecOtaConfig(p_peer, p_codec_info, num_protect, p_protect_info, &dummy_restart_output)) { - APPL_TRACE_ERROR("%s: cannot set source codec %s for peer %s", __func__, - A2DP_CodecName(p_codec_info), - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_ERROR("%s: cannot set source codec %s for peer %s", __func__, + A2DP_CodecName(p_codec_info), + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); } else { codec_config_supported = true; // Check if reconfiguration is needed @@ -1278,8 +1272,8 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, } if (status != A2DP_SUCCESS) { - APPL_TRACE_DEBUG("%s: peer %s reject s=%d c=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), status, category); + LOG_VERBOSE("%s: peer %s reject s=%d c=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), status, category); // Call call-in rejecting the configuration bta_av_ci_setconfig(bta_av_handle, status, category, 0, nullptr, false, avdt_handle); @@ -1289,8 +1283,8 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, // Mark that this is an acceptor peer p_peer->acceptor = true; p_peer->reconfig_needed = reconfig_needed; - APPL_TRACE_DEBUG("%s: peer %s accept reconf=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), reconfig_needed); + LOG_VERBOSE("%s: peer %s accept reconf=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), reconfig_needed); // Call call-in accepting the configuration bta_av_ci_setconfig(bta_av_handle, A2DP_SUCCESS, A2DP_SUCCESS, 0, nullptr, reconfig_needed, avdt_handle); @@ -1298,15 +1292,14 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, void BtaAvCo::ProcessOpen(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, uint16_t mtu) { - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x mtu:%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, mtu); + LOG_VERBOSE("%s: peer %s bta_av_handle: 0x%x mtu:%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, mtu); // Find the peer BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { - APPL_TRACE_ERROR( - "%s: could not find peer entry for bta_av_handle 0x%x peer %s", - __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: could not find peer entry for bta_av_handle 0x%x peer %s", + __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return; } p_peer->opened = true; @@ -1320,16 +1313,15 @@ void BtaAvCo::ProcessOpen(tBTA_AV_HNDL bta_av_handle, void BtaAvCo::ProcessClose(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address) { - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); + LOG_VERBOSE("%s: peer %s bta_av_handle: 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); btif_av_reset_audio_delay(); // Find the peer BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { - APPL_TRACE_ERROR( - "%s: could not find peer entry for bta_av_handle 0x%x peer %s", - __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: could not find peer entry for bta_av_handle 0x%x peer %s", + __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return; } // Reset the active peer @@ -1343,30 +1335,29 @@ void BtaAvCo::ProcessClose(tBTA_AV_HNDL bta_av_handle, void BtaAvCo::ProcessStart(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, const uint8_t* p_codec_info, bool* p_no_rtp_header) { - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); + LOG_VERBOSE("%s: peer %s bta_av_handle: 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); // Find the peer BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { - APPL_TRACE_ERROR( - "%s: could not find peer entry for bta_av_handle 0x%x peer %s", - __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: could not find peer entry for bta_av_handle 0x%x peer %s", + __func__, bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return; } bool add_rtp_header = A2DP_UsesRtpHeader(p_peer->ContentProtectActive(), p_codec_info); - APPL_TRACE_DEBUG("%s: bta_av_handle: 0x%x add_rtp_header: %s", __func__, - bta_av_handle, add_rtp_header ? "true" : "false"); + LOG_VERBOSE("%s: bta_av_handle: 0x%x add_rtp_header: %s", __func__, + bta_av_handle, add_rtp_header ? "true" : "false"); *p_no_rtp_header = !add_rtp_header; } void BtaAvCo::ProcessStop(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address) { - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); + LOG_VERBOSE("%s: peer %s bta_av_handle: 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); // Nothing to do } @@ -1374,14 +1365,14 @@ BT_HDR* BtaAvCo::GetNextSourceDataPacket(const uint8_t* p_codec_info, uint32_t* p_timestamp) { BT_HDR* p_buf; - APPL_TRACE_DEBUG("%s: codec: %s", __func__, A2DP_CodecName(p_codec_info)); + LOG_VERBOSE("%s: codec: %s", __func__, A2DP_CodecName(p_codec_info)); p_buf = btif_a2dp_source_audio_readbuf(); if (p_buf == nullptr) return nullptr; if (p_buf->offset < 4) { osi_free(p_buf); - APPL_TRACE_ERROR("No space for timestamp in packet, dropped"); + LOG_ERROR("No space for timestamp in packet, dropped"); return nullptr; } /* @@ -1395,8 +1386,8 @@ BT_HDR* BtaAvCo::GetNextSourceDataPacket(const uint8_t* p_codec_info, if (!A2DP_GetPacketTimestamp(p_codec_info, (const uint8_t*)(p_buf + 1), p_timestamp) || !A2DP_BuildCodecHeader(p_codec_info, p_buf, p_buf->layer_specific)) { - APPL_TRACE_ERROR("%s: unsupported codec type (%d)", __func__, - A2DP_GetCodecType(p_codec_info)); + LOG_ERROR("%s: unsupported codec type (%d)", __func__, + A2DP_GetCodecType(p_codec_info)); osi_free(p_buf); return nullptr; } @@ -1416,16 +1407,15 @@ BT_HDR* BtaAvCo::GetNextSourceDataPacket(const uint8_t* p_codec_info, void BtaAvCo::DataPacketWasDropped(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address) { - APPL_TRACE_ERROR("%s: peer %s dropped audio packet on handle 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); + LOG_ERROR("%s: peer %s dropped audio packet on handle 0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); } void BtaAvCo::ProcessAudioDelay(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, uint16_t delay) { - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x delay:0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, - delay); + LOG_VERBOSE("%s: peer %s bta_av_handle: 0x%x delay:0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, delay); btif_av_set_audio_delay(peer_address, delay); } @@ -1447,8 +1437,8 @@ void BtaAvCo::UpdateMtu(tBTA_AV_HNDL bta_av_handle, } bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) { - VLOG(1) << __func__ << ": peer_address=" - << ADDRESS_TO_LOGGABLE_STR(peer_address); + LOG(INFO) << __func__ + << ": peer_address=" << ADDRESS_TO_LOGGABLE_STR(peer_address); std::lock_guard lock(codec_lock_); @@ -1473,6 +1463,10 @@ bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) { return true; } +void BtaAvCo::SaveCodec(const uint8_t* new_codec_config) { + memcpy(codec_config_, new_codec_config, sizeof(codec_config_)); +} + void BtaAvCo::GetPeerEncoderParameters( const RawAddress& peer_address, tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) { @@ -1493,7 +1487,7 @@ void BtaAvCo::GetPeerEncoderParameters( p_peer_params->is_peer_edr = btif_av_is_peer_edr(peer_address); p_peer_params->peer_supports_3mbps = btif_av_peer_supports_3mbps(peer_address); - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer_address=%s peer_mtu=%d is_peer_edr=%s peer_supports_3mbps=%s", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), p_peer_params->peer_mtu, logbool(p_peer_params->is_peer_edr).c_str(), @@ -1506,12 +1500,6 @@ const tA2DP_ENCODER_INTERFACE* BtaAvCo::GetSourceEncoderInterface() { return A2DP_GetEncoderInterface(codec_config_); } -const tA2DP_DECODER_INTERFACE* BtaAvCo::GetSinkDecoderInterface() { - std::lock_guard lock(codec_lock_); - - return A2DP_GetDecoderInterface(codec_config_); -} - bool BtaAvCo::SetCodecUserConfig( const RawAddress& peer_address, const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output) { @@ -1703,7 +1691,10 @@ bool BtaAvCo::ReportSourceCodecState(BtaAvCoPeer* p_peer) { VLOG(1) << __func__ << ": peer_address=" << ADDRESS_TO_LOGGABLE_STR(p_peer->addr); A2dpCodecs* codecs = p_peer->GetCodecs(); - CHECK(codecs != nullptr); + if (codecs == nullptr) { + LOG_ERROR("Peer codecs is set to null"); + return false; + } if (!codecs->getCodecConfigAndCapabilities(&codec_config, &codecs_local_capabilities, &codecs_selectable_capabilities)) { @@ -1723,8 +1714,8 @@ bool BtaAvCo::ReportSourceCodecState(BtaAvCoPeer* p_peer) { } bool BtaAvCo::ReportSinkCodecState(BtaAvCoPeer* p_peer) { - APPL_TRACE_DEBUG("%s: peer_address=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: peer_address=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); // Nothing to do (for now) return true; } @@ -1742,8 +1733,6 @@ void BtaAvCo::DebugDump(int fd) { } } - if (appl_trace_level < BT_TRACE_LEVEL_DEBUG) return; - dprintf(fd, "\nA2DP Peers State:\n"); dprintf(fd, " Active peer: %s\n", (active_peer_ != nullptr) @@ -1774,14 +1763,14 @@ void BtaAvCo::DebugDump(int fd) { } bool BtaAvCo::ContentProtectIsScmst(const uint8_t* p_protect_info) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (*p_protect_info >= AVDT_CP_LOSC) { uint16_t cp_id; p_protect_info++; STREAM_TO_UINT16(cp_id, p_protect_info); if (cp_id == AVDT_CP_SCMS_T_ID) { - APPL_TRACE_DEBUG("%s: SCMS-T found", __func__); + LOG_VERBOSE("%s: SCMS-T found", __func__); return true; } } @@ -1790,18 +1779,18 @@ bool BtaAvCo::ContentProtectIsScmst(const uint8_t* p_protect_info) { bool BtaAvCo::AudioProtectHasScmst(uint8_t num_protect, const uint8_t* p_protect_info) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); while (num_protect--) { if (BtaAvCo::ContentProtectIsScmst(p_protect_info)) return true; // Move to the next Content Protect schema p_protect_info += *p_protect_info + 1; } - APPL_TRACE_DEBUG("%s: SCMS-T not found", __func__); + LOG_VERBOSE("%s: SCMS-T not found", __func__); return false; } bool BtaAvCo::AudioSepHasContentProtection(const BtaAvCoSep* p_sep) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); // Check if content protection is enabled for this stream if (ContentProtectFlag() != AVDT_CP_SCMS_COPY_FREE) { @@ -1809,7 +1798,7 @@ bool BtaAvCo::AudioSepHasContentProtection(const BtaAvCoSep* p_sep) { p_sep->protect_info); } - APPL_TRACE_DEBUG("%s: not required", __func__); + LOG_VERBOSE("%s: not required", __func__); return true; } @@ -1844,13 +1833,13 @@ const BtaAvCoSep* BtaAvCo::SelectSinkCodec(BtaAvCoPeer* p_peer) { // Select the codec for (const auto& iter : p_peer->GetCodecs()->orderedSinkCodecs()) { - APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str()); + LOG_VERBOSE("%s: trying codec %s", __func__, iter->name().c_str()); p_source = AttemptSinkCodecSelection(*iter, p_peer); if (p_source != nullptr) { - APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str()); + LOG_VERBOSE("%s: selected codec %s", __func__, iter->name().c_str()); break; } - APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str()); + LOG_VERBOSE("%s: cannot use codec %s", __func__, iter->name().c_str()); } // NOTE: Unconditionally dispatch the event to make sure a callback with @@ -1863,8 +1852,8 @@ const BtaAvCoSep* BtaAvCo::SelectSinkCodec(BtaAvCoPeer* p_peer) { BtaAvCoSep* BtaAvCo::FindPeerSink(BtaAvCoPeer* p_peer, btav_a2dp_codec_index_t codec_index) { if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) { - APPL_TRACE_WARNING("%s: invalid codec index for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_WARN("%s: invalid codec index for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); return nullptr; } @@ -1877,7 +1866,7 @@ BtaAvCoSep* BtaAvCo::FindPeerSink(BtaAvCoPeer* p_peer, continue; } if (!AudioSepHasContentProtection(p_sink)) { - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer Sink for codec %s does not support " "Content Protection", __func__, A2DP_CodecIndexStr(codec_index)); @@ -1891,8 +1880,8 @@ BtaAvCoSep* BtaAvCo::FindPeerSink(BtaAvCoPeer* p_peer, BtaAvCoSep* BtaAvCo::FindPeerSource(BtaAvCoPeer* p_peer, btav_a2dp_codec_index_t codec_index) { if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) { - APPL_TRACE_WARNING("%s: invalid codec index for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_WARN("%s: invalid codec index for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); return nullptr; } @@ -1905,7 +1894,7 @@ BtaAvCoSep* BtaAvCo::FindPeerSource(BtaAvCoPeer* p_peer, continue; } if (!AudioSepHasContentProtection(p_source)) { - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: peer Source for codec %s does not support " "Content Protection", __func__, A2DP_CodecIndexStr(codec_index)); @@ -1920,20 +1909,20 @@ const BtaAvCoSep* BtaAvCo::AttemptSourceCodecSelection( const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) { uint8_t new_codec_config[AVDT_CODEC_SIZE]; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); // Find the peer Sink for the codec BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex()); if (p_sink == nullptr) { - APPL_TRACE_DEBUG("%s: peer Sink for codec %s not found", __func__, - codec_config.name().c_str()); + LOG_VERBOSE("%s: peer Sink for codec %s not found", __func__, + codec_config.name().c_str()); return nullptr; } if (!p_peer->GetCodecs()->setCodecConfig( p_sink->codec_caps, true /* is_capability */, new_codec_config, true /* select_current_codec */)) { - APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__, - codec_config.name().c_str()); + LOG_VERBOSE("%s: cannot set source codec %s", __func__, + codec_config.name().c_str()); return nullptr; } p_peer->p_sink = p_sink; @@ -1948,20 +1937,20 @@ const BtaAvCoSep* BtaAvCo::AttemptSinkCodecSelection( const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) { uint8_t new_codec_config[AVDT_CODEC_SIZE]; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); // Find the peer Source for the codec BtaAvCoSep* p_source = FindPeerSource(p_peer, codec_config.codecIndex()); if (p_source == nullptr) { - APPL_TRACE_DEBUG("%s: peer Source for codec %s not found", __func__, - codec_config.name().c_str()); + LOG_VERBOSE("%s: peer Source for codec %s not found", __func__, + codec_config.name().c_str()); return nullptr; } if (!p_peer->GetCodecs()->setSinkCodecConfig( p_source->codec_caps, true /* is_capability */, new_codec_config, true /* select_current_codec */)) { - APPL_TRACE_DEBUG("%s: cannot set sink codec %s", __func__, - codec_config.name().c_str()); + LOG_VERBOSE("%s: cannot set sink codec %s", __func__, + codec_config.name().c_str()); return nullptr; } p_peer->p_source = p_source; @@ -1973,13 +1962,12 @@ const BtaAvCoSep* BtaAvCo::AttemptSinkCodecSelection( } size_t BtaAvCo::UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer) { - APPL_TRACE_DEBUG("%s: peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); size_t updated_codecs = 0; for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) { - APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__, - iter->name().c_str()); + LOG_VERBOSE("%s: updating selectable codec %s", __func__, + iter->name().c_str()); if (UpdateSelectableSourceCodec(*iter, p_peer)) { updated_codecs++; } @@ -1989,8 +1977,7 @@ size_t BtaAvCo::UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer) { bool BtaAvCo::UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) { - APPL_TRACE_DEBUG("%s: peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); // Find the peer Sink for the codec const BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex()); @@ -1999,22 +1986,21 @@ bool BtaAvCo::UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config, return false; } if (!p_peer->GetCodecs()->setPeerSinkCodecCapabilities(p_sink->codec_caps)) { - APPL_TRACE_WARNING("%s: cannot update peer %s codec capabilities for %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), - A2DP_CodecName(p_sink->codec_caps)); + LOG_WARN("%s: cannot update peer %s codec capabilities for %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), + A2DP_CodecName(p_sink->codec_caps)); return false; } return true; } size_t BtaAvCo::UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer) { - APPL_TRACE_DEBUG("%s: peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); size_t updated_codecs = 0; for (const auto& iter : p_peer->GetCodecs()->orderedSinkCodecs()) { - APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__, - iter->name().c_str()); + LOG_VERBOSE("%s: updating selectable codec %s", __func__, + iter->name().c_str()); if (UpdateSelectableSinkCodec(*iter, p_peer)) { updated_codecs++; } @@ -2024,8 +2010,7 @@ size_t BtaAvCo::UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer) { bool BtaAvCo::UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) { - APPL_TRACE_DEBUG("%s: peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); // Find the peer Source for the codec const BtaAvCoSep* p_source = @@ -2036,9 +2021,9 @@ bool BtaAvCo::UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config, } if (!p_peer->GetCodecs()->setPeerSourceCodecCapabilities( p_source->codec_caps)) { - APPL_TRACE_WARNING("%s: cannot update peer %s codec capabilities for %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), - A2DP_CodecName(p_source->codec_caps)); + LOG_WARN("%s: cannot update peer %s codec capabilities for %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr), + A2DP_CodecName(p_source->codec_caps)); return false; } return true; @@ -2048,10 +2033,9 @@ void BtaAvCo::SaveNewCodecConfig(BtaAvCoPeer* p_peer, const uint8_t* new_codec_config, uint8_t num_protect, const uint8_t* p_protect_info) { - APPL_TRACE_DEBUG("%s: peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); - APPL_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(new_codec_config).c_str()); + LOG_VERBOSE("%s: peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(new_codec_config).c_str()); std::lock_guard lock(codec_lock_); @@ -2158,7 +2142,7 @@ void bta_av_co_audio_disc_res(tBTA_AV_HNDL bta_av_handle, static void bta_av_co_store_peer_codectype(const BtaAvCoPeer* p_peer) { int index, peer_codec_type = 0; const BtaAvCoSep* p_sink; - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); for (index = 0; index < p_peer->num_sup_sinks; index++) { p_sink = &p_peer->sinks[index]; peer_codec_type |= A2DP_IotGetPeerSinkCodecType(p_sink->codec_caps); @@ -2176,9 +2160,8 @@ tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL bta_av_handle, uint8_t* p_protect_info) { uint16_t peer_uuid = bta_av_co_cb.FindPeerUuid(bta_av_handle); - APPL_TRACE_DEBUG("%s: peer %s bta_av_handle=0x%x peer_uuid=0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, - peer_uuid); + LOG_VERBOSE("%s: peer %s bta_av_handle=0x%x peer_uuid=0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, peer_uuid); switch (peer_uuid) { case UUID_SERVCLASS_AUDIO_SOURCE: @@ -2192,9 +2175,9 @@ tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL bta_av_handle, default: break; } - APPL_TRACE_ERROR( - "%s: peer %s : Invalid peer UUID: 0x%x for bta_av_handle 0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), peer_uuid, bta_av_handle); + LOG_ERROR("%s: peer %s : Invalid peer UUID: 0x%x for bta_av_handle 0x%x", + __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), peer_uuid, + bta_av_handle); return A2DP_FAIL; } @@ -2255,6 +2238,10 @@ bool bta_av_co_set_active_peer(const RawAddress& peer_address) { return bta_av_co_cb.SetActivePeer(peer_address); } +void bta_av_co_save_codec(const uint8_t* new_codec_config) { + return bta_av_co_cb.SaveCodec(new_codec_config); +} + void bta_av_co_get_peer_params(const RawAddress& peer_address, tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) { bta_av_co_cb.GetPeerEncoderParameters(peer_address, p_peer_params); @@ -2264,10 +2251,6 @@ const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) { return bta_av_co_cb.GetSourceEncoderInterface(); } -const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) { - return bta_av_co_cb.GetSinkDecoderInterface(); -} - bool bta_av_co_set_codec_user_config( const RawAddress& peer_address, const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output) { diff --git a/system/btif/co/bta_dm_co.cc b/system/btif/co/bta_dm_co.cc index f034fc6d577bbd826fc62776a1ad2cdc87a5bf4e..4f60e2bce968facd2103930c22c38fe1f20d9921 100644 --- a/system/btif/co/bta_dm_co.cc +++ b/system/btif/co/bta_dm_co.cc @@ -15,40 +15,12 @@ * limitations under the License. * ******************************************************************************/ -#include "bta_dm_co.h" - -#include -#include - -#include "bta_api.h" -#include "bta_dm_ci.h" -#include "bta_sys.h" -#include "bte_appl.h" -#include "btif_dm.h" -#include "osi/include/osi.h" +#include "bta/include/bta_api.h" +#include "bta/include/bta_sec_api.h" +#include "internal_include/bte_appl.h" +#include "stack/include/btm_api_types.h" tBTE_APPL_CFG bte_appl_cfg = { BTA_LE_AUTH_REQ_SC_MITM_BOND, // Authentication requirements BTM_IO_CAP_KBDISP, BTM_BLE_INITIATOR_KEY_SIZE, BTM_BLE_RESPONDER_KEY_SIZE, BTM_BLE_MAX_KEY_SIZE}; - -/******************************************************************************* - * - * Function bta_dm_co_get_compress_memory - * - * Description This callout function is executed by DM to get memory for - compression - - * Parameters id - BTA SYS ID - * memory_p - memory return by callout - * memory_size - memory size - * - * Returns true for success, false for fail. - * - ******************************************************************************/ -bool bta_dm_co_get_compress_memory(UNUSED_ATTR tBTA_SYS_ID id, - UNUSED_ATTR uint8_t** memory_p, - UNUSED_ATTR uint32_t* memory_size) { - return true; -} - diff --git a/system/btif/co/bta_hh_co.cc b/system/btif/co/bta_hh_co.cc index e3779c36ace97053ab7c4449ad4226a87be39e82..b8fc689e2a38ff4b38f04614d141480c9938aac6 100644 --- a/system/btif/co/bta_hh_co.cc +++ b/system/btif/co/bta_hh_co.cc @@ -19,8 +19,6 @@ #include "bta_hh_co.h" #include -#include -#include #include #include #include @@ -30,10 +28,11 @@ #include #include +#include + #include "bta_api.h" #include "bta_hh_api.h" #include "btif_hh.h" -#include "btif_util.h" #include "device/include/controller.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" @@ -60,14 +59,13 @@ static void* btif_hh_poll_event_thread(void* arg); void uhid_set_non_blocking(int fd) { int opts = fcntl(fd, F_GETFL); if (opts < 0) - APPL_TRACE_ERROR("%s() Getting flags failed (%s)", __func__, - strerror(errno)); + LOG_ERROR("%s() Getting flags failed (%s)", __func__, strerror(errno)); opts |= O_NONBLOCK; if (fcntl(fd, F_SETFL, opts) < 0) - APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__, - strerror(errno)); + LOG_VERBOSE("%s() Setting non-blocking flag failed (%s)", __func__, + strerror(errno)); } static bool uhid_feature_req_handler(btif_hh_device_t* p_dev, @@ -133,11 +131,11 @@ static int uhid_write(int fd, const struct uhid_event* ev) { if (ret < 0) { int rtn = -errno; - APPL_TRACE_ERROR("%s: Cannot write to uhid:%s", __func__, strerror(errno)); + LOG_ERROR("%s: Cannot write to uhid:%s", __func__, strerror(errno)); return rtn; } else if (ret != (ssize_t)sizeof(*ev)) { - APPL_TRACE_ERROR("%s: Wrong size written to uhid: %zd != %zu", __func__, - ret, sizeof(*ev)); + LOG_ERROR("%s: Wrong size written to uhid: %zd != %zu", __func__, ret, + sizeof(*ev)); return -EFAULT; } @@ -155,40 +153,39 @@ static int uhid_read_event(btif_hh_device_t* p_dev) { OSI_NO_INTR(ret = read(p_dev->fd, &ev, sizeof(ev))); if (ret == 0) { - APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __func__, strerror(errno)); + LOG_ERROR("%s: Read HUP on uhid-cdev %s", __func__, strerror(errno)); return -EFAULT; } else if (ret < 0) { - APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __func__, - strerror(errno)); + LOG_ERROR("%s: Cannot read uhid-cdev: %s", __func__, strerror(errno)); return -errno; } switch (ev.type) { case UHID_START: - APPL_TRACE_DEBUG("UHID_START from uhid-dev\n"); + LOG_VERBOSE("UHID_START from uhid-dev\n"); p_dev->ready_for_data = true; break; case UHID_STOP: - APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n"); + LOG_VERBOSE("UHID_STOP from uhid-dev\n"); p_dev->ready_for_data = false; break; case UHID_OPEN: - APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n"); + LOG_VERBOSE("UHID_OPEN from uhid-dev\n"); p_dev->ready_for_data = true; break; case UHID_CLOSE: - APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n"); + LOG_VERBOSE("UHID_CLOSE from uhid-dev\n"); p_dev->ready_for_data = false; break; case UHID_OUTPUT: if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) { - APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu", - __func__, ret, sizeof(ev.type) + sizeof(ev.u.output)); + LOG_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu", __func__, + ret, sizeof(ev.type) + sizeof(ev.u.output)); return -EFAULT; } - APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d", - ev.u.output.rtype, ev.u.output.size); + LOG_VERBOSE("UHID_OUTPUT: Report type = %d, report_size = %d", + ev.u.output.rtype, ev.u.output.size); // Send SET_REPORT with feature report if the report type in output event // is FEATURE if (ev.u.output.rtype == UHID_FEATURE_REPORT) @@ -197,17 +194,16 @@ static int uhid_read_event(btif_hh_device_t* p_dev) { else if (ev.u.output.rtype == UHID_OUTPUT_REPORT) btif_hh_senddata(p_dev, ev.u.output.size, ev.u.output.data); else - APPL_TRACE_ERROR("%s: UHID_OUTPUT: Invalid report type = %d", __func__, - ev.u.output.rtype); + LOG_ERROR("%s: UHID_OUTPUT: Invalid report type = %d", __func__, + ev.u.output.rtype); break; case UHID_OUTPUT_EV: if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output_ev))) { - APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu", - __func__, ret, - sizeof(ev.type) + sizeof(ev.u.output_ev)); + LOG_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu", __func__, + ret, sizeof(ev.type) + sizeof(ev.u.output_ev)); return -EFAULT; } - APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n"); + LOG_VERBOSE("UHID_OUTPUT_EV from uhid-dev\n"); break; case UHID_FEATURE: // UHID_GET_REPORT @@ -256,17 +252,17 @@ static int uhid_read_event(btif_hh_device_t* p_dev) { ******************************************************************************/ static inline pthread_t create_thread(void* (*start_routine)(void*), void* arg) { - APPL_TRACE_DEBUG("create_thread: entered"); + LOG_VERBOSE("create_thread: entered"); pthread_attr_t thread_attr; pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE); pthread_t thread_id = -1; if (pthread_create(&thread_id, &thread_attr, start_routine, arg) != 0) { - APPL_TRACE_ERROR("pthread_create : %s", strerror(errno)); + LOG_ERROR("pthread_create : %s", strerror(errno)); return -1; } - APPL_TRACE_DEBUG("create_thread: thread created successfully"); + LOG_VERBOSE("create_thread: thread created successfully"); return thread_id; } @@ -353,7 +349,7 @@ static void* btif_hh_poll_event_thread(void* arg) { break; } if (pfds[0].revents & POLLIN) { - APPL_TRACE_DEBUG("%s: POLLIN", __func__); + LOG_VERBOSE("%s: POLLIN", __func__); ret = uhid_read_event(p_dev); if (ret != 0) { LOG_ERROR("Unhandled UHID event"); @@ -372,14 +368,14 @@ static void* btif_hh_poll_event_thread(void* arg) { } int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) { - APPL_TRACE_VERBOSE("%s: UHID write %d", __func__, len); + LOG_VERBOSE("%s: UHID write %d", __func__, len); struct uhid_event ev; memset(&ev, 0, sizeof(ev)); ev.type = UHID_INPUT; ev.u.input.size = len; if (len > sizeof(ev.u.input.data)) { - APPL_TRACE_WARNING("%s: Report size greater than allowed size", __func__); + LOG_WARN("%s: Report size greater than allowed size", __func__); return -1; } memcpy(ev.u.input.data, rpt, len); @@ -523,15 +519,14 @@ void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len, uint8_t app_id) { btif_hh_device_t* p_dev; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: dev_handle = %d, subclass = 0x%02X, mode = %d, " "ctry_code = %d, app_id = %d", __func__, dev_handle, sub_class, mode, ctry_code, app_id); p_dev = btif_hh_find_connected_dev_by_handle(dev_handle); if (p_dev == NULL) { - APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__, - dev_handle); + LOG_WARN("%s: Error: unknown HID device handle %d", __func__, dev_handle); return; } @@ -549,8 +544,8 @@ void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len, if ((p_dev->fd >= 0) && p_dev->ready_for_data) { bta_hh_co_write(p_dev->fd, p_rpt, len); } else { - APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __func__, - p_dev->fd, p_dev->ready_for_data, len); + LOG_WARN("%s: Error: fd = %d, ready %d, len = %d", __func__, p_dev->fd, + p_dev->ready_for_data, len); } } @@ -575,14 +570,14 @@ void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name, struct uhid_event ev; if (p_dev->fd < 0) { - APPL_TRACE_WARNING("%s: Error: fd = %d, dscp_len = %d", __func__, p_dev->fd, - dscp_len); + LOG_WARN("%s: Error: fd = %d, dscp_len = %d", __func__, p_dev->fd, + dscp_len); return; } - APPL_TRACE_WARNING("%s: fd = %d, name = [%s], dscp_len = %d", __func__, - p_dev->fd, dev_name, dscp_len); - APPL_TRACE_WARNING( + LOG_WARN("%s: fd = %d, name = [%s], dscp_len = %d", __func__, p_dev->fd, + dev_name, dscp_len); + LOG_WARN( "%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x," "ctry_code=0x%02x", __func__, vendor_id, product_id, version, ctry_code); @@ -611,13 +606,11 @@ void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name, ev.u.create.country = ctry_code; result = uhid_write(p_dev->fd, &ev); - APPL_TRACE_WARNING( - "%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __func__, - p_dev->fd, dscp_len, result); + LOG_WARN("%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", + __func__, p_dev->fd, dscp_len, result); if (result) { - APPL_TRACE_WARNING("%s: Error: failed to send DSCP, result = %d", __func__, - result); + LOG_WARN("%s: Error: failed to send DSCP, result = %d", __func__, result); /* The HID report descriptor is corrupted. Close the driver. */ close(p_dev->fd); @@ -776,8 +769,8 @@ void bta_hh_le_co_rpt_info(const RawAddress& remote_bda, btif_config_set_bin(bdstr, "HidReport", (const uint8_t*)sReportCache, idx * sizeof(tBTA_HH_RPT_CACHE_ENTRY)); btif_config_set_int(bdstr, "HidReportVersion", BTA_HH_CACHE_REPORT_VERSION); - BTIF_TRACE_DEBUG("%s() - Saving report; dev=%s, idx=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(remote_bda), idx); + LOG_VERBOSE("%s() - Saving report; dev=%s, idx=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(remote_bda), idx); } } @@ -819,8 +812,8 @@ tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(const RawAddress& remote_bda, *p_num_rpt = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY); - BTIF_TRACE_DEBUG("%s() - Loaded %d reports; dev=%s", __func__, *p_num_rpt, - ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); + LOG_VERBOSE("%s() - Loaded %d reports; dev=%s", __func__, *p_num_rpt, + ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); return sReportCache; } @@ -843,6 +836,6 @@ void bta_hh_le_co_reset_rpt_cache(const RawAddress& remote_bda, btif_config_remove(bdstr, "HidReport"); btif_config_remove(bdstr, "HidReportVersion"); - BTIF_TRACE_DEBUG("%s() - Reset cache for bda %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); + LOG_VERBOSE("%s() - Reset cache for bda %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); } diff --git a/system/btif/co/bta_pan_co.cc b/system/btif/co/bta_pan_co.cc index 959671ee3b26b59d961caec0bcc79050c19ad118..dd8a0b231b6217307da8ac4bcab40e75e6dcef46 100644 --- a/system/btif/co/bta_pan_co.cc +++ b/system/btif/co/bta_pan_co.cc @@ -55,7 +55,7 @@ * ******************************************************************************/ uint8_t bta_pan_co_init(uint8_t* q_level) { - BTIF_TRACE_API("bta_pan_co_init"); + LOG_VERBOSE("bta_pan_co_init"); /* set the q_level to 30 buffers */ *q_level = 30; @@ -76,10 +76,10 @@ uint8_t bta_pan_co_init(uint8_t* q_level) { * ******************************************************************************/ void bta_pan_co_close(uint16_t handle, uint8_t app_id) { - BTIF_TRACE_API("bta_pan_co_close:app_id:%d, handle:%d", app_id, handle); + LOG_VERBOSE("bta_pan_co_close:app_id:%d, handle:%d", app_id, handle); btpan_conn_t* conn = btpan_find_conn_handle(handle); if (conn && conn->state == PAN_STATE_OPEN) { - BTIF_TRACE_DEBUG("bta_pan_co_close"); + LOG_VERBOSE("bta_pan_co_close"); // let bta close event reset this handle as it needs // the handle to find the connection upon CLOSE @@ -119,15 +119,15 @@ void bta_pan_co_tx_path(uint16_t handle, uint8_t app_id) { bool ext; bool forward; - BTIF_TRACE_API("%s, handle:%d, app_id:%d", __func__, handle, app_id); + LOG_VERBOSE("%s, handle:%d, app_id:%d", __func__, handle, app_id); btpan_conn_t* conn = btpan_find_conn_handle(handle); if (!conn) { - BTIF_TRACE_ERROR("%s: cannot find pan connection", __func__); + LOG_ERROR("%s: cannot find pan connection", __func__); return; } else if (conn->state != PAN_STATE_OPEN) { - BTIF_TRACE_ERROR("%s: conn is not opened, conn:%p, conn->state:%d", - __func__, conn, conn->state); + LOG_ERROR("%s: conn is not opened, conn:%p, conn->state:%d", __func__, conn, + conn->state); return; } @@ -135,7 +135,7 @@ void bta_pan_co_tx_path(uint16_t handle, uint8_t app_id) { /* read next data buffer from pan */ p_buf = bta_pan_ci_readbuf(handle, src, dst, &protocol, &ext, &forward); if (p_buf) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s, calling btapp_tap_send, " "p_buf->len:%d, offset:%d", __func__, p_buf->len, p_buf->offset); @@ -168,7 +168,7 @@ void bta_pan_co_tx_path(uint16_t handle, uint8_t app_id) { ******************************************************************************/ void bta_pan_co_rx_path(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id) { - BTIF_TRACE_API("bta_pan_co_rx_path not used"); + LOG_VERBOSE("bta_pan_co_rx_path not used"); } /******************************************************************************* @@ -187,7 +187,7 @@ void bta_pan_co_rx_path(UNUSED_ATTR uint16_t handle, ******************************************************************************/ void bta_pan_co_rx_flow(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id, UNUSED_ATTR bool enable) { - BTIF_TRACE_API("bta_pan_co_rx_flow, enabled:%d, not used", enable); + LOG_VERBOSE("bta_pan_co_rx_flow, enabled:%d, not used", enable); btpan_conn_t* conn = btpan_find_conn_handle(handle); if (!conn || conn->state != PAN_STATE_OPEN) return; btpan_set_flow_control(enable); @@ -207,7 +207,7 @@ void bta_pan_co_pfilt_ind(UNUSED_ATTR uint16_t handle, UNUSED_ATTR tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len, UNUSED_ATTR uint8_t* p_filters) { - BTIF_TRACE_API("bta_pan_co_pfilt_ind"); + LOG_VERBOSE("bta_pan_co_pfilt_ind"); } /******************************************************************************* @@ -224,5 +224,5 @@ void bta_pan_co_mfilt_ind(UNUSED_ATTR uint16_t handle, UNUSED_ATTR tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len, UNUSED_ATTR uint8_t* p_filters) { - BTIF_TRACE_API("bta_pan_co_mfilt_ind"); + LOG_VERBOSE("bta_pan_co_mfilt_ind"); } diff --git a/system/btif/include/btif_a2dp.h b/system/btif/include/btif_a2dp.h index c4d95618b06aa775b20c8c5a5d5f43e18b414a77..d9c44d11753251681db865f5f56a546cf76f2b8f 100644 --- a/system/btif/include/btif_a2dp.h +++ b/system/btif/include/btif_a2dp.h @@ -26,7 +26,7 @@ #include "types/raw_address.h" // Process 'idle' request from the BTIF state machine during initialization. -void btif_a2dp_on_idle(void); +void btif_a2dp_on_idle(const RawAddress& peer_addr); // Process 'start' request from the BTIF state machine to prepare for A2DP // streaming. diff --git a/system/btif/include/btif_a2dp_sink.h b/system/btif/include/btif_a2dp_sink.h index af98b9c5fd672ba3af3772984a1af10297f9dfc8..8875eed850d84f9b7ca3a417f3d7243f7da3024e 100644 --- a/system/btif/include/btif_a2dp_sink.h +++ b/system/btif/include/btif_a2dp_sink.h @@ -138,4 +138,7 @@ void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state); // |gain| is the audio track gain value to use. void btif_a2dp_sink_set_audio_track_gain(float gain); +// Get audio track handle +void * btif_a2dp_sink_get_audio_track(void); + #endif /* BTIF_A2DP_SINK_H */ diff --git a/system/btif/include/btif_api.h b/system/btif/include/btif_api.h index 55b9da1ac658b4d0797fb7af95aa7f659870fa9d..2a7df05a7277bccaeb0c176562b2da59eb5d14bc 100644 --- a/system/btif/include/btif_api.h +++ b/system/btif/include/btif_api.h @@ -272,7 +272,7 @@ void btif_dm_remove_bond(const RawAddress bd_addr); * Returns 0 if not connected * ******************************************************************************/ -uint16_t btif_dm_get_connection_state(const RawAddress* bd_addr); +uint16_t btif_dm_get_connection_state(const RawAddress& bd_addr); /******************************************************************************* * @@ -329,6 +329,33 @@ bt_status_t btif_dm_get_adapter_property(bt_property_t* prop); ******************************************************************************/ void btif_dm_get_remote_services(const RawAddress remote_addr, int transport); +/******************************************************************************* + * + * Function btif_dut_mode_configure + * + * Description Configure Test Mode - 'enable' to 1 puts the device in test + * mode and 0 exits test mode + * + ******************************************************************************/ +void btif_dut_mode_configure(uint8_t enable); + +bool btif_is_dut_mode(); + +/******************************************************************************* + * + * Function btif_dut_mode_send + * + * Description Sends a HCI Vendor specific command to the controller + * + ******************************************************************************/ +void btif_dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len); + +void btif_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len, + uint8_t packet_payload); + +void btif_ble_receiver_test(uint8_t rx_freq); +void btif_ble_test_end(); + /******************************************************************************* * * Function btif_dm_read_energy_info diff --git a/system/btif/include/btif_av.h b/system/btif/include/btif_av.h index 09c0e2721c2bfe02d6daf6267d851fbe595b13ec..f85656c063a7ae6b3c4dcb568986de53df0c32b7 100644 --- a/system/btif/include/btif_av.h +++ b/system/btif/include/btif_av.h @@ -46,6 +46,11 @@ RawAddress btif_av_sink_active_peer(void); */ bool btif_av_is_sink_enabled(void); +/** + * Check whether A2DP Source is enabled. + */ +bool btif_av_is_source_enabled(void); + /** * Start streaming. */ @@ -226,6 +231,14 @@ bool btif_av_is_a2dp_offload_running(void); */ bool btif_av_is_peer_silenced(const RawAddress& peer_address); +/** + * check the a2dp connect status + * + * @param address : checked device address + * + */ +bool btif_av_is_connected_addr(const RawAddress& peer_address); + /** * Set the dynamic audio buffer size * @@ -240,4 +253,16 @@ void btif_av_set_dynamic_audio_buffer_size(uint8_t dynamic_audio_buffer_size); */ void btif_av_set_low_latency(bool is_low_latency); +/** + * Check whether A2DP Source is enabled. + */ +extern bool btif_av_is_source_enabled(void); +extern bool btif_av_both_enable(void); +extern bool btif_av_src_sink_coexist_enabled(void); +extern bool btif_av_is_sink_enabled(void); +extern bool btif_av_is_connected_addr(const RawAddress& peer_address); +extern bool btif_av_peer_is_connected_sink(const RawAddress& peer_address); +extern bool btif_av_peer_is_connected_source(const RawAddress& peer_address); +extern bool btif_av_peer_is_sink(const RawAddress& peer_address); +extern bool btif_av_peer_is_source(const RawAddress& peer_address); #endif /* BTIF_AV_H */ diff --git a/system/btif/include/btif_av_co.h b/system/btif/include/btif_av_co.h index 1ce810f5e3f7a68529e413f9f41bb29c02a41b64..9b32b15f406ad95547e04909c3ead1b49257b4d9 100644 --- a/system/btif/include/btif_av_co.h +++ b/system/btif/include/btif_av_co.h @@ -27,6 +27,8 @@ // Returns true on success, otherwise false. bool bta_av_co_set_active_peer(const RawAddress& peer_addr); +void bta_av_co_save_codec(const uint8_t* new_codec_config); + // Gets the A2DP peer parameters that are used to initialize the encoder. // The peer address is |peer_addr|. // The parameters are stored in |p_peer_params|. @@ -40,12 +42,6 @@ void bta_av_co_get_peer_params(const RawAddress& peer_addr, // otherwise NULL. const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void); -// Gets the current A2DP decoder interface that can be used to decode received -// A2DP packets - see |tA2DP_DECODER_INTERFACE|. -// Returns the A2DP decoder interface if the current codec is setup, otherwise -// NULL. -const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void); - // Sets the user preferred codec configuration. // The peer address is |peer_addr|. // |codec_user_config| contains the preferred codec configuration. diff --git a/system/btif/include/btif_bqr.h b/system/btif/include/btif_bqr.h index 43d5943265f3e05c5e0a87a7bd67c699d58307a5..374a387782e914b66a10ef572e6849a6d1b2c259 100644 --- a/system/btif/include/btif_bqr.h +++ b/system/btif/include/btif_bqr.h @@ -108,7 +108,7 @@ static constexpr uint16_t kMinReportIntervalMaxMs = 0xFFFF; static constexpr uint16_t kLogDumpEventPerFile = 0x00FF; // Total length of all parameters of the link Quality related event except // Vendor Specific Parameters. -static constexpr uint8_t kLinkQualityParamTotalLen = 55; +static constexpr uint8_t kLinkQualityParamTotalLen = 48; // 7.8.116 LE Read ISO Link Quality command static constexpr uint8_t kISOLinkQualityParamTotalLen = 24; // Total length of all parameters of the ROOT_INFLAMMATION event except Vendor @@ -117,6 +117,9 @@ static constexpr uint8_t kRootInflammationParamTotalLen = 3; // Total length of all parameters of the Log Dump related event except Vendor // Specific Parameters. static constexpr uint8_t kLogDumpParamTotalLen = 3; +// Remote address and calibration failure count parameters len +// Added in BQR V5.0 +static constexpr uint8_t kVersion5_0ParamsTotalLen = 7; // Warning criteria of the RSSI value. static constexpr int8_t kCriWarnRssi = -80; // Warning criteria of the unused AFH channel count. @@ -166,6 +169,9 @@ static uint16_t BtSchedulingTraceCounter = 0; static constexpr uint16_t kBqrIsoVersion = 0x101; // The version supports vendor quality and trace log starting v1.02(258) static constexpr uint16_t kBqrVndLogVersion = 0x102; +// The version supports remote address info and calibration failure count +// start from v1.03(259) +static constexpr uint16_t kBqrVersion5_0 = 0x103; // Action definition // diff --git a/system/btif/include/btif_common.h b/system/btif/include/btif_common.h index 32488b78b2fbd64fec49dc2443d4e14fb83eed00..5f863e6d3603ed5eb99838ab607e8e112a08cc19 100644 --- a/system/btif/include/btif_common.h +++ b/system/btif/include/btif_common.h @@ -81,7 +81,7 @@ #define HAL_CBACK(P_CB, P_CBACK, ...) \ do { \ if ((P_CB) && (P_CB)->P_CBACK) { \ - BTIF_TRACE_API("%s: HAL %s->%s", __func__, #P_CB, #P_CBACK); \ + LOG_VERBOSE("%s: HAL %s->%s", __func__, #P_CB, #P_CBACK); \ (P_CB)->P_CBACK(__VA_ARGS__); \ } else { \ ASSERTC(0, "Callback is NULL", 0); \ @@ -156,7 +156,6 @@ bt_status_t do_in_jni_thread(base::OnceClosure task); bt_status_t do_in_jni_thread(const base::Location& from_here, base::OnceClosure task); bool is_on_jni_thread(); -btbase::AbstractMessageLoop* get_jni_message_loop(); using BtJniClosure = std::function; void post_on_bt_jni(BtJniClosure closure); @@ -172,7 +171,7 @@ base::Callback jni_thread_wrapper(const base::Location& from_here, [](const base::Location& from_here, base::Callback cb, Args... args) { do_in_jni_thread(from_here, - base::Bind(cb, std::forward(args)...)); + base::BindOnce(cb, std::forward(args)...)); }, from_here, std::move(cb)); } @@ -192,7 +191,6 @@ void btif_remote_properties_evt(bt_status_t status, RawAddress* remote_addr, uint32_t num_props, bt_property_t* p_props); void bte_load_did_conf(const char* p_path); -void bte_main_init(void); bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event, char* p_params, int param_len, @@ -228,6 +226,7 @@ void invoke_acl_state_changed_cb(bt_status_t status, RawAddress bd_addr, bt_conn_direction_t direction, uint16_t acl_handle); void invoke_thread_evt_cb(bt_cb_thread_evt event); +void invoke_le_test_mode_cb(bt_status_t status, uint16_t count); void invoke_energy_info_cb(bt_activity_energy_info energy_info, bt_uid_traffic_t* uid_data); void invoke_link_quality_report_cb( diff --git a/system/btif/include/btif_config.h b/system/btif/include/btif_config.h index 185eae7d69c5fd8108c37b6f0d43fb55e81d5e54..7bb0659bbde54ed95f469a2593ecb4c8d082a855 100644 --- a/system/btif/include/btif_config.h +++ b/system/btif/include/btif_config.h @@ -64,6 +64,8 @@ bool btif_config_set_bin(const std::string& section, const std::string& key, const uint8_t* value, size_t length); bool btif_config_remove(const std::string& section, const std::string& key); +void btif_config_remove_device(const std::string& section); + size_t btif_config_get_bin_length(const std::string& section, const std::string& key); @@ -71,3 +73,5 @@ std::vector btif_config_get_paired_devices(); bool btif_config_clear(void); void btif_debug_config_dump(int fd); +bool btif_get_device_clockoffset(const RawAddress& bda, int* p_clock_offset); +bool btif_set_device_clockoffset(const RawAddress& bda, int clock_offset); diff --git a/system/btif/include/btif_dm.h b/system/btif/include/btif_dm.h index 1586151ad8c6b195321bc95af0c4b579f7b6b911..246d1445dbcfb2aaf8def00372c97fa1784f3e80 100644 --- a/system/btif/include/btif_dm.h +++ b/system/btif/include/btif_dm.h @@ -20,8 +20,10 @@ #define BTIF_DM_H #include "bta/include/bta_api.h" -#include "bte_appl.h" +#include "bta/include/bta_sec_api.h" #include "btif_uid.h" +#include "internal_include/bt_target.h" +#include "internal_include/bte_appl.h" #include "types/raw_address.h" /******************************************************************************* @@ -35,6 +37,7 @@ #define COD_HID_POINTING 0x0580 #define COD_HID_COMBO 0x05C0 #define COD_HID_MAJOR 0x0500 +#define COD_HID_SUB_MAJOR 0x00C0 #define COD_HID_MASK 0x0700 #define COD_AV_HEADSETS 0x0404 #define COD_AV_HANDSFREE 0x0408 @@ -50,9 +53,14 @@ void btif_dm_init(uid_set_t* set); void btif_dm_cleanup(void); /** - * BTIF callback to switch context from bte to btif + * BTIF callback for security events */ -void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data); +void btif_dm_sec_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data); + +/** + * BTIF callback for ACL up/down and address consolidation events + */ +void btif_dm_acl_evt(tBTA_DM_ACL_EVT event, tBTA_DM_ACL* p_data); /** * Notify BT disable being initiated. DM may chose to abort @@ -143,5 +151,6 @@ void btif_dm_update_ble_remote_properties(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type); bool check_cod_hid(const RawAddress& bd_addr); +bool check_cod_hid_major(const RawAddress& bd_addr, uint32_t cod); bool is_device_le_audio_capable(const RawAddress bd_addr); #endif diff --git a/system/btif/include/btif_gatt.h b/system/btif/include/btif_gatt.h index 7391e6dbe782a76b1cfc1299b05086195409c289..986873eadf63db55fffc32ba19810eeee48e2b3b 100644 --- a/system/btif/include/btif_gatt.h +++ b/system/btif/include/btif_gatt.h @@ -32,6 +32,5 @@ extern const btgatt_client_interface_t btgattClientInterface; extern const btgatt_server_interface_t btgattServerInterface; -BleAdvertiserInterface* get_ble_advertiser_instance(); BleScannerInterface* get_ble_scanner_instance(); #endif diff --git a/system/btif/include/btif_hh.h b/system/btif/include/btif_hh.h index d5246871499c7567e31b8a0d666556ba7d0d1049..c69cc485b604f465347c673172fa213f91ecf3f8 100644 --- a/system/btif/include/btif_hh.h +++ b/system/btif/include/btif_hh.h @@ -26,6 +26,7 @@ #include #include "bta/include/bta_hh_api.h" +#include "macros.h" #include "osi/include/alarm.h" #include "osi/include/fixed_queue.h" #include "types/raw_address.h" @@ -67,10 +68,6 @@ typedef enum : unsigned { BTIF_HH_DEV_DISCONNECTED } BTIF_HH_STATUS; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string btif_hh_status_text(const BTIF_HH_STATUS& status) { switch (status) { CASE_RETURN_TEXT(BTIF_HH_DISABLED); @@ -84,7 +81,6 @@ inline std::string btif_hh_status_text(const BTIF_HH_STATUS& status) { return base::StringPrintf("UNKNOWN[%u]", status); } } -#undef CASE_RETURN_TEXT // Shared with uhid polling thread typedef struct { diff --git a/system/btif/include/btif_jni_task.h b/system/btif/include/btif_jni_task.h new file mode 100644 index 0000000000000000000000000000000000000000..e2771db2a4f04cbff5ddba3794ab3fe98a9423cf --- /dev/null +++ b/system/btif/include/btif_jni_task.h @@ -0,0 +1,57 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "btif/include/btif_common.h" +#include "include/hardware/bluetooth.h" + +void jni_thread_startup(); +void jni_thread_shutdown(); + +/******************************************************************************* + * + * Function btif_transfer_context + * + * Description This function switches context to btif task + * + * p_cback : callback used to process message in btif context + * event : event id of message + * p_params : parameter area passed to callback (copied) + * param_len : length of parameter area + * p_copy_cback : If set this function will be invoked for deep + * copy + * + * Returns void + * + ******************************************************************************/ + +bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event, + char* p_params, int param_len, + tBTIF_COPY_CBACK* p_copy_cback); + +/** + * This function posts a task into the btif message loop, that executes it in + * the JNI message loop. + **/ +bt_status_t do_in_jni_thread(const base::Location& from_here, + base::OnceClosure task); + +bt_status_t do_in_jni_thread(base::OnceClosure task); + +bool is_on_jni_thread(); + +void post_on_bt_jni(BtJniClosure closure); diff --git a/system/btif/include/btif_pan_internal.h b/system/btif/include/btif_pan_internal.h index e601a6c0a5092db89f15ffc2b4ba0013774b36fe..0491041078d4a41b5fce5d6abfd92ed55e502d00 100644 --- a/system/btif/include/btif_pan_internal.h +++ b/system/btif/include/btif_pan_internal.h @@ -27,7 +27,7 @@ #ifndef BTIF_PAN_INTERNAL_H #define BTIF_PAN_INTERNAL_H -#include "btif_pan.h" +#include "internal_include/bt_target.h" #include "types/raw_address.h" /******************************************************************************* diff --git a/system/btif/include/btif_profile_storage.h b/system/btif/include/btif_profile_storage.h index 58b5f114fe2989a556ad46abc4b612814e4100bf..55d6c27874f91051ee93ff5028bc174672a25add 100644 --- a/system/btif/include/btif_profile_storage.h +++ b/system/btif/include/btif_profile_storage.h @@ -23,6 +23,7 @@ #include "bt_target.h" #include "btif_storage.h" +#include "stack/include/btm_sec_api_types.h" #include "stack/include/bt_device_type.h" #include "stack/include/bt_octets.h" #include "types/ble_address_with_type.h" @@ -122,6 +123,9 @@ void btif_storage_set_leaudio_supported_context_types( const RawAddress& addr, uint16_t sink_supported_context_type, uint16_t source_supported_context_type); +/** Remove Le Audio device service data */ +void btif_storage_leaudio_clear_service_data(const RawAddress& address); + /** Remove Le Audio device from the storage */ void btif_storage_remove_leaudio(const RawAddress& address); @@ -148,6 +152,7 @@ void btif_storage_update_csis_info(const RawAddress& addr); void btif_storage_load_bonded_csis_devices(); void btif_storage_remove_csis_device(const RawAddress& address); +void btif_storage_load_bonded_volume_control_devices(void); /******************************************************************************* * Function btif_storage_load_hidd * diff --git a/system/btif/include/btif_sock.h b/system/btif/include/btif_sock.h index 494782eda42795edfbe9a7da92cac629911a1bd7..d938a188777c335fe84242c7397070fd3fa06497 100644 --- a/system/btif/include/btif_sock.h +++ b/system/btif/include/btif_sock.h @@ -48,5 +48,6 @@ const btsock_interface_t* btif_sock_get_interface(void); bt_status_t btif_sock_init(uid_set_t* uid_set); void btif_sock_cleanup(void); -void btif_sock_connection_logger(int state, int role, const RawAddress& addr); +void btif_sock_connection_logger(int state, int role, const RawAddress& addr, + int channel, const char* server_name); void btif_sock_dump(int fd); diff --git a/system/btif/include/btif_sock_l2cap.h b/system/btif/include/btif_sock_l2cap.h index 5aadeb812924bf791ec906c01b18e0e294b6ad4e..d43d837f1052da7bcde16c871e88fc0bea519825 100644 --- a/system/btif/include/btif_sock_l2cap.h +++ b/system/btif/include/btif_sock_l2cap.h @@ -18,5 +18,6 @@ bt_status_t btsock_l2cap_connect(const RawAddress* bd_addr, int channel, int* sock_fd, int flags, int app_uid); void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id); void on_l2cap_psm_assigned(int id, int psm); +bt_status_t btsock_l2cap_disconnect(const RawAddress* bd_addr); #endif diff --git a/system/btif/include/btif_sock_rfc.h b/system/btif/include/btif_sock_rfc.h index dc75fe2fbbc0fce6cd765c3e942565b63e5825cf..ae52e23d73af1a6f11551c1cd4b53507bab4de95 100644 --- a/system/btif/include/btif_sock_rfc.h +++ b/system/btif/include/btif_sock_rfc.h @@ -43,5 +43,6 @@ bt_status_t btsock_rfc_connect(const RawAddress* bd_addr, const bluetooth::Uuid* uuid, int channel, int* sock_fd, int flags, int app_uid); void btsock_rfc_signaled(int fd, int flags, uint32_t user_id); +bt_status_t btsock_rfc_disconnect(const RawAddress* bd_addr); #endif diff --git a/system/btif/include/btif_storage.h b/system/btif/include/btif_storage.h index a8bf67eac158c483d2a4144ef0179203f1c7a8c1..dbf8d26488f11ff551fa6b64bcfe110e848b7834 100644 --- a/system/btif/include/btif_storage.h +++ b/system/btif/include/btif_storage.h @@ -22,9 +22,10 @@ #include #include -#include "bt_target.h" +#include "internal_include/bt_target.h" #include "stack/include/bt_device_type.h" #include "stack/include/bt_octets.h" +#include "stack/include/btm_sec_api_types.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" @@ -142,7 +143,7 @@ bt_status_t btif_storage_set_remote_device_property( * returns BTM_LOCAL_IO_CAPS. * ******************************************************************************/ -uint8_t btif_storage_get_local_io_caps(); +tBTM_IO_CAP btif_storage_get_local_io_caps(); /******************************************************************************* * @@ -322,6 +323,9 @@ void btif_storage_set_leaudio_supported_context_types( const RawAddress& addr, uint16_t sink_supported_context_type, uint16_t source_supported_context_type); +/** Remove Le Audio device service data */ +void btif_storage_leaudio_clear_service_data(const RawAddress& address); + /** Remove Le Audio device from the storage */ void btif_storage_remove_leaudio(const RawAddress& address); diff --git a/system/btif/include/core_callbacks.h b/system/btif/include/core_callbacks.h index 79b42188dde956a8d995c1ffd6608e5382e70c5d..d212f9c2ac0cae60ca27b1a3b37e26e32bc75151 100644 --- a/system/btif/include/core_callbacks.h +++ b/system/btif/include/core_callbacks.h @@ -58,6 +58,7 @@ struct EventCallbacks { bt_conn_direction_t direction, uint16_t acl_handle); void (*invoke_thread_evt_cb)(bt_cb_thread_evt event); + void (*invoke_le_test_mode_cb)(bt_status_t status, uint16_t count); void (*invoke_energy_info_cb)(bt_activity_energy_info energy_info, bt_uid_traffic_t* uid_data); void (*invoke_link_quality_report_cb)(uint64_t timestamp, int report_id, @@ -66,7 +67,6 @@ struct EventCallbacks { int packets_not_receive_count, int negative_acknowledgement_count); - EventCallbacks(const EventCallbacks&) = delete; EventCallbacks& operator=(const EventCallbacks&) = delete; }; @@ -125,7 +125,6 @@ struct HACK_ProfileInterface { // AVRCP hacks uint16_t (*AVRC_GetProfileVersion)(); - HACK_ProfileInterface(const HACK_ProfileInterface&) = delete; HACK_ProfileInterface& operator=(const HACK_ProfileInterface&) = delete; }; @@ -137,6 +136,7 @@ struct CoreInterface { // codecs CodecInterface* msbcCodec; + CodecInterface* lc3Codec; // DO NOT add any more methods here HACK_ProfileInterface* profileSpecific_HACK; @@ -149,10 +149,12 @@ struct CoreInterface { CoreInterface(EventCallbacks* eventCallbacks, ConfigInterface* configInterface, CodecInterface* msbcCodec, + CodecInterface* lc3Codec, HACK_ProfileInterface* profileSpecific_HACK) : events{eventCallbacks}, config{configInterface}, msbcCodec{msbcCodec}, + lc3Codec{lc3Codec}, profileSpecific_HACK{profileSpecific_HACK} {}; CoreInterface(const CoreInterface&) = delete; diff --git a/system/btif/include/mock_core_callbacks.h b/system/btif/include/mock_core_callbacks.h new file mode 100644 index 0000000000000000000000000000000000000000..5e88fe3b3190fb558998f5d3596804d40e57a615 --- /dev/null +++ b/system/btif/include/mock_core_callbacks.h @@ -0,0 +1,134 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "btif/include/core_callbacks.h" +#include "include/hardware/bluetooth.h" +#include "types/raw_address.h" + +namespace bluetooth { +namespace core { +namespace testing { + +// These callbacks are not profile specific (e.g. connection complete, bond +// complete, etc) and are what go to the Java layer. +EventCallbacks mock_event_callbacks = { + .invoke_adapter_state_changed_cb = [](bt_state_t /* state */) {}, + .invoke_adapter_properties_cb = [](bt_status_t /* status */, + int /* num_properties */, + bt_property_t* /* properties */) {}, + .invoke_remote_device_properties_cb = + [](bt_status_t /* status */, RawAddress /* bd_addr */, + int /* num_properties */, bt_property_t* /* properties */) {}, + .invoke_device_found_cb = [](int /* num_properties */, + bt_property_t* /* properties */) {}, + .invoke_discovery_state_changed_cb = + [](bt_discovery_state_t /* state */) {}, + .invoke_pin_request_cb = [](RawAddress /* bd_addr */, + bt_bdname_t /* bd_name */, uint32_t /* cod */, + bool /* min_16_digit */) {}, + .invoke_ssp_request_cb = [](RawAddress /* bd_addr */, + bt_bdname_t /* bd_name */, uint32_t /* cod */, + bt_ssp_variant_t /* pairing_variant */, + uint32_t /* pass_key */) {}, + .invoke_oob_data_request_cb = [](tBT_TRANSPORT /* t */, bool /* valid */, + Octet16 /* c */, Octet16 /* r */, + RawAddress /* raw_address */, + uint8_t /* address_type */) {}, + .invoke_bond_state_changed_cb = + [](bt_status_t /* status */, RawAddress /* bd_addr */, + bt_bond_state_t /* state */, int /* fail_reason */) {}, + .invoke_address_consolidate_cb = [](RawAddress /* main_bd_addr */, + RawAddress /* secondary_bd_addr */) {}, + .invoke_le_address_associate_cb = [](RawAddress /* main_bd_addr */, + RawAddress /* secondary_bd_addr */) {}, + .invoke_acl_state_changed_cb = + [](bt_status_t /* status */, RawAddress /* bd_addr */, + bt_acl_state_t /* state */, int /* transport_link_type */, + bt_hci_error_code_t /* hci_reason */, + bt_conn_direction_t /* direction */, uint16_t /* acl_handle */) {}, + .invoke_thread_evt_cb = [](bt_cb_thread_evt /* event */) {}, + .invoke_le_test_mode_cb = [](bt_status_t /* status */, + uint16_t /* count */) {}, + .invoke_energy_info_cb = [](bt_activity_energy_info /* energy_info */, + bt_uid_traffic_t* /* uid_data */) {}, + .invoke_link_quality_report_cb = + [](uint64_t /* timestamp */, int /* report_id */, int /* rssi */, + int /* snr */, int /* retransmission_count */, + int /* packets_not_receive_count */, + int /* negative_acknowledgement_count */) {}, +}; + +// This interface lets us query for configuration properties of the stack that +// could change at runtime +struct MockConfigInterface : public ConfigInterface { + MOCK_METHOD((bool), isA2DPOffloadEnabled, (), ()); + MOCK_METHOD((bool), isAndroidTVDevice, (), ()); + MOCK_METHOD((bool), isRestrictedMode, (), ()); +}; +MockConfigInterface mock_config_interface; + +// This interface lets us communicate with encoders used in profiles +struct MockCodecInterface : public CodecInterface { + MOCK_METHOD((void), initialize, (), ()); + MOCK_METHOD((void), cleanup, (), ()); + MOCK_METHOD((uint32_t), encodePacket, (int16_t * input, uint8_t* output), ()); + MOCK_METHOD((bool), decodePacket, + (const uint8_t* i_buf, int16_t* o_buf, size_t out_len), ()); +}; +MockCodecInterface mock_codec_msbcCodec; +MockCodecInterface mock_codec_lc3Codec; + +HACK_ProfileInterface mock_HACK_profile_interface = { + .btif_hh_connect = [](const RawAddress* /* bd_addr */) -> bt_status_t { + return BT_STATUS_SUCCESS; + }, + .btif_hh_virtual_unplug = [](const RawAddress* /* bd_addr */) + -> bt_status_t { return BT_STATUS_SUCCESS; }, + .bta_hh_read_ssr_param = + [](const RawAddress& /* bd_addr */, uint16_t* /* p_max_ssr_lat */, + uint16_t* /* p_min_ssr_tout */) -> tBTA_HH_STATUS { + return BTA_HH_OK; + }, + + .btif_av_set_dynamic_audio_buffer_size = + [](uint8_t /* dynamic_audio_buffer_size */) {}, + .GetHearingAidDeviceCount = []() -> int { return 0; }, + .IsLeAudioClientRunning = []() -> bool { return false; }, + .AVRC_GetProfileVersion = []() -> uint16_t { return 0; }, +}; + +// This class defines the overall interface expected by bluetooth::core. +struct MockCoreInterface : public CoreInterface { + MockCoreInterface() + : CoreInterface(&mock_event_callbacks, &mock_config_interface, + &mock_codec_msbcCodec, &mock_codec_lc3Codec, + &mock_HACK_profile_interface) {} + + MOCK_METHOD((void), onBluetoothEnabled, (), ()); + MOCK_METHOD((bt_status_t), toggleProfile, + (tBTA_SERVICE_ID service_id, bool enable), ()); + MOCK_METHOD((void), removeDeviceFromProfiles, (const RawAddress& bd_addr), + ()); + MOCK_METHOD((void), onLinkDown, (const RawAddress& bd_addr), ()); +}; + +} // namespace testing +} // namespace core +} // namespace bluetooth diff --git a/system/btif/src/OWNERS b/system/btif/src/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..e495e167d42861a41b5e241c56db9c415b018a13 --- /dev/null +++ b/system/btif/src/OWNERS @@ -0,0 +1 @@ +per-file btif_hearing_aid.cc=file:/OWNERS_hearingaid diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc index 4bea7174393b053f20d814b767d00bc9af3e2d04..a0905c04f2a7f7476321f97a42da5b2546867697 100644 --- a/system/btif/src/bluetooth.cc +++ b/system/btif/src/bluetooth.cc @@ -65,7 +65,6 @@ #include "btif/include/core_callbacks.h" #include "btif/include/stack_manager.h" #include "btif_a2dp.h" -#include "btif_activity_attribution.h" #include "btif_api.h" #include "btif_av.h" #include "btif_bqr.h" @@ -83,7 +82,6 @@ #include "btif_sock.h" #include "btif_storage.h" #include "common/address_obfuscator.h" -#include "common/metric_id_allocator.h" #include "common/metrics.h" #include "common/os_utils.h" #include "device/include/device_iot_config.h" @@ -91,35 +89,32 @@ #include "device/include/interop_config.h" #include "gd/common/init_flags.h" #include "gd/os/parameter_provider.h" +#include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" -#include "main/shim/shim.h" +#include "os/log.h" #include "osi/include/alarm.h" -#include "osi/include/allocation_tracker.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "osi/include/stack_power_telemetry.h" #include "osi/include/wakelock.h" -#include "profile_log_levels.h" #include "stack/btm/btm_sco_hfp_hal.h" #include "stack/gatt/connection_manager.h" #include "stack/include/a2dp_api.h" #include "stack/include/avdt_api.h" #include "stack/include/btm_api.h" -#include "stack/include/btu.h" +#include "stack/include/hfp_lc3_decoder.h" +#include "stack/include/hfp_lc3_encoder.h" #include "stack/include/hfp_msbc_decoder.h" #include "stack/include/hfp_msbc_encoder.h" #include "stack/include/hidh_api.h" +#include "stack/include/main_thread.h" #include "stack/include/pan_api.h" -#include "stack_config.h" #include "types/raw_address.h" using bluetooth::csis::CsisClientInterface; using bluetooth::has::HasClientInterface; using bluetooth::hearing_aid::HearingAidInterface; -#ifndef TARGET_FLOSS using bluetooth::le_audio::LeAudioBroadcasterInterface; using bluetooth::le_audio::LeAudioClientInterface; -#endif using bluetooth::vc::VolumeControlInterface; /******************************************************************************* @@ -162,14 +157,12 @@ extern const btrc_ctrl_interface_t* btif_rc_ctrl_get_interface(); extern const btsdp_interface_t* btif_sdp_get_interface(); /*Hearing Aid client*/ extern HearingAidInterface* btif_hearing_aid_get_interface(); -#ifndef TARGET_FLOSS /* Hearing Access client */ extern HasClientInterface* btif_has_client_get_interface(); /* LeAudio testi client */ extern LeAudioClientInterface* btif_le_audio_get_interface(); /* LeAudio Broadcaster */ extern LeAudioBroadcasterInterface* btif_le_audio_broadcaster_get_interface(); -#endif /* Coordinated Set Service Client */ extern CsisClientInterface* btif_csis_client_get_interface(); /* Volume Control client */ @@ -200,7 +193,7 @@ struct ConfigInterfaceImpl : bluetooth::core::ConfigInterface { "false"); auto a2dp_offload_enabled = (strcmp(value_sup, "true") == 0) && (strcmp(value_dis, "false") == 0); - BTIF_TRACE_DEBUG("a2dp_offload.enable = %d", a2dp_offload_enabled); + LOG_VERBOSE("a2dp_offload.enable = %d", a2dp_offload_enabled); return a2dp_offload_enabled; } @@ -231,6 +224,28 @@ struct MSBCCodec : bluetooth::core::CodecInterface { } }; +struct LC3Codec : bluetooth::core::CodecInterface { + LC3Codec() : bluetooth::core::CodecInterface(){}; + + void initialize() override { + hfp_lc3_decoder_init(); + hfp_lc3_encoder_init(); + } + + void cleanup() override { + hfp_lc3_encoder_cleanup(); + hfp_lc3_decoder_cleanup(); + } + + uint32_t encodePacket(int16_t* input, uint8_t* output) { + return hfp_lc3_encode_frames(input, output); + } + + bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) { + return hfp_lc3_decoder_decode_packet(i_buf, o_buf, out_len); + } +}; + struct CoreInterfaceImpl : bluetooth::core::CoreInterface { using bluetooth::core::CoreInterface::CoreInterface; @@ -276,8 +291,8 @@ struct CoreInterfaceImpl : bluetooth::core::CoreInterface { */ } break; default: - BTIF_TRACE_ERROR("%s: Unknown service %d being %s", __func__, - service_id, (enable) ? "enabled" : "disabled"); + LOG_ERROR("%s: Unknown service %d being %s", __func__, service_id, + (enable) ? "enabled" : "disabled"); return BT_STATUS_FAIL; } return BT_STATUS_SUCCESS; @@ -293,7 +308,6 @@ struct CoreInterfaceImpl : bluetooth::core::CoreInterface { #endif btif_hearing_aid_get_interface()->RemoveDevice(bd_addr); -#ifndef TARGET_FLOSS if (bluetooth::csis::CsisClient::IsCsisClientRunning()) btif_csis_client_get_interface()->RemoveDevice(bd_addr); @@ -303,7 +317,6 @@ struct CoreInterfaceImpl : bluetooth::core::CoreInterface { if (VolumeControl::IsVolumeControlRunning()) { btif_volume_control_get_interface()->RemoveDevice(bd_addr); } -#endif } void onLinkDown(const RawAddress& bd_addr) override { @@ -312,7 +325,7 @@ struct CoreInterfaceImpl : bluetooth::core::CoreInterface { }; static bluetooth::core::CoreInterface* CreateInterfaceToProfiles() { - static auto eventCallbacks = bluetooth::core::EventCallbacks{ + static bluetooth::core::EventCallbacks eventCallbacks{ .invoke_adapter_state_changed_cb = invoke_adapter_state_changed_cb, .invoke_adapter_properties_cb = invoke_adapter_properties_cb, .invoke_remote_device_properties_cb = invoke_remote_device_properties_cb, @@ -326,11 +339,11 @@ static bluetooth::core::CoreInterface* CreateInterfaceToProfiles() { .invoke_le_address_associate_cb = invoke_le_address_associate_cb, .invoke_acl_state_changed_cb = invoke_acl_state_changed_cb, .invoke_thread_evt_cb = invoke_thread_evt_cb, + .invoke_le_test_mode_cb = invoke_le_test_mode_cb, .invoke_energy_info_cb = invoke_energy_info_cb, - .invoke_link_quality_report_cb = invoke_link_quality_report_cb}; - static auto configInterface = ConfigInterfaceImpl(); - static auto msbcCodecInterface = MSBCCodec(); - static auto profileInterface = bluetooth::core::HACK_ProfileInterface{ + .invoke_link_quality_report_cb = invoke_link_quality_report_cb, + }; + static bluetooth::core::HACK_ProfileInterface profileInterface{ // HID .btif_hh_connect = btif_hh_connect, .btif_hh_virtual_unplug = btif_hh_virtual_unplug, @@ -347,11 +360,16 @@ static bluetooth::core::CoreInterface* CreateInterfaceToProfiles() { .IsLeAudioClientRunning = LeAudioClient::IsLeAudioClientRunning, // AVRCP - .AVRC_GetProfileVersion = AVRC_GetProfileVersion}; + .AVRC_GetProfileVersion = AVRC_GetProfileVersion, + }; + + static auto configInterface = ConfigInterfaceImpl(); + static auto msbcCodecInterface = MSBCCodec(); + static auto lc3CodecInterface = LC3Codec(); static auto interfaceForCore = CoreInterfaceImpl(&eventCallbacks, &configInterface, &msbcCodecInterface, - &profileInterface); + &lc3CodecInterface, &profileInterface); return &interfaceForCore; } @@ -389,10 +407,6 @@ static int init(bt_callbacks_t* callbacks, bool start_restricted, if (interface_ready()) return BT_STATUS_DONE; -#ifdef BLUEDROID_DEBUG - allocation_tracker_init(); -#endif - set_hal_cbacks(callbacks); restricted_mode = start_restricted; @@ -428,12 +442,6 @@ static void start_profiles() { HID_HostInit(); #endif bta_ar_init(); - - // initialize profile-specific logging levels - const auto stack_config = stack_config_get_interface(); - if (stack_config->get_trace_config_enabled()) { - load_levels_from_config(stack_config->get_all()); - } } static void stop_profiles() { @@ -621,8 +629,11 @@ static int cancel_bond(const RawAddress* bd_addr) { } static int remove_bond(const RawAddress* bd_addr) { - if (is_restricted_mode() && !btif_storage_is_restricted_device(bd_addr)) + if (is_restricted_mode() && !btif_storage_is_restricted_device(bd_addr)) { + LOG_INFO("%s cannot be removed in restricted mode", + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_SUCCESS; + } if (!interface_ready()) return BT_STATUS_NOT_READY; @@ -633,7 +644,9 @@ static int remove_bond(const RawAddress* bd_addr) { static int get_connection_state(const RawAddress* bd_addr) { if (!interface_ready()) return 0; - return btif_dm_get_connection_state(bd_addr); + if (bd_addr == nullptr) return 0; + + return btif_dm_get_connection_state(*bd_addr); } static int pin_reply(const RawAddress* bd_addr, uint8_t accept, uint8_t pin_len, @@ -713,7 +726,8 @@ static int le_rand() { if (!interface_ready()) return BT_STATUS_NOT_READY; do_in_main_thread( - FROM_HERE, base::BindOnce(btif_dm_le_rand, base::Bind(&le_rand_btif_cb))); + FROM_HERE, + base::BindOnce(btif_dm_le_rand, base::BindOnce(&le_rand_btif_cb))); return BT_STATUS_SUCCESS; } @@ -780,24 +794,20 @@ static void dump(int fd, const char** arguments) { device_debug_iot_config_dump(fd); BTA_HfClientDumpStatistics(fd); wakelock_debug_dump(fd); - osi_allocator_debug_dump(fd); alarm_debug_dump(fd); bluetooth::csis::CsisClient::DebugDump(fd); -#ifndef TARGET_FLOSS le_audio::has::HasClient::DebugDump(fd); -#endif HearingAid::DebugDump(fd); -#ifndef TARGET_FLOSS LeAudioClient::DebugDump(fd); LeAudioBroadcaster::DebugDump(fd); VolumeControl::DebugDump(fd); -#endif connection_manager::dump(fd); bluetooth::bqr::DebugDump(fd); PAN_Dumpsys(fd); DumpsysHid(fd); DumpsysBtaDm(fd); bluetooth::shim::Dump(fd, arguments); + power_telemetry::GetInstance().Dumpsys(fd); } static void dumpMetrics(std::string* output) { @@ -871,25 +881,17 @@ static const void* get_profile_interface(const char* profile_id) { if (is_profile(profile_id, BT_PROFILE_HEARING_AID_ID)) return btif_hearing_aid_get_interface(); -#ifndef TARGET_FLOSS if (is_profile(profile_id, BT_PROFILE_HAP_CLIENT_ID)) return btif_has_client_get_interface(); -#endif if (is_profile(profile_id, BT_KEYSTORE_ID)) return bluetooth::bluetooth_keystore::getBluetoothKeystoreInterface(); - if (is_profile(profile_id, BT_ACTIVITY_ATTRIBUTION_ID)) { - return bluetooth::activity_attribution::get_activity_attribution_instance(); - } - -#ifndef TARGET_FLOSS if (is_profile(profile_id, BT_PROFILE_LE_AUDIO_ID)) return btif_le_audio_get_interface(); if (is_profile(profile_id, BT_PROFILE_LE_AUDIO_BROADCASTER_ID)) return btif_le_audio_broadcaster_get_interface(); -#endif if (is_profile(profile_id, BT_PROFILE_VC_ID)) return btif_volume_control_get_interface(); @@ -907,25 +909,75 @@ static const void* get_profile_interface(const char* profile_id) { return NULL; } +int dut_mode_configure(uint8_t enable) { + if (!interface_ready()) return BT_STATUS_NOT_READY; + if (!stack_manager_get_interface()->get_stack_is_running()) + return BT_STATUS_NOT_READY; + + do_in_main_thread(FROM_HERE, base::BindOnce(btif_dut_mode_configure, enable)); + return BT_STATUS_SUCCESS; +} + +int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) { + if (!interface_ready()) return BT_STATUS_NOT_READY; + if (!btif_is_dut_mode()) return BT_STATUS_FAIL; + + uint8_t* copy = (uint8_t*)osi_calloc(len); + memcpy(copy, buf, len); + + do_in_main_thread(FROM_HERE, + base::BindOnce( + [](uint16_t opcode, uint8_t* buf, uint8_t len) { + btif_dut_mode_send(opcode, buf, len); + osi_free(buf); + }, + opcode, copy, len)); + return BT_STATUS_SUCCESS; +} + +int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) { + if (!interface_ready()) return BT_STATUS_NOT_READY; + + switch (opcode) { + case HCI_BLE_TRANSMITTER_TEST: + if (len != 3) return BT_STATUS_PARM_INVALID; + do_in_main_thread(FROM_HERE, base::BindOnce(btif_ble_transmitter_test, + buf[0], buf[1], buf[2])); + break; + case HCI_BLE_RECEIVER_TEST: + if (len != 1) return BT_STATUS_PARM_INVALID; + do_in_main_thread(FROM_HERE, + base::BindOnce(btif_ble_receiver_test, buf[0])); + break; + case HCI_BLE_TEST_END: + do_in_main_thread(FROM_HERE, base::BindOnce(btif_ble_test_end)); + break; + default: + return BT_STATUS_UNSUPPORTED; + } + return BT_STATUS_SUCCESS; +} + static bt_os_callouts_t* wakelock_os_callouts_saved = nullptr; static int acquire_wake_lock_cb(const char* lock_name) { return do_in_jni_thread( - FROM_HERE, base::Bind(base::IgnoreResult( - wakelock_os_callouts_saved->acquire_wake_lock), - lock_name)); + FROM_HERE, + base::BindOnce( + base::IgnoreResult(wakelock_os_callouts_saved->acquire_wake_lock), + lock_name)); } static int release_wake_lock_cb(const char* lock_name) { return do_in_jni_thread( - FROM_HERE, base::Bind(base::IgnoreResult( - wakelock_os_callouts_saved->release_wake_lock), - lock_name)); + FROM_HERE, + base::BindOnce( + base::IgnoreResult(wakelock_os_callouts_saved->release_wake_lock), + lock_name)); } static bt_os_callouts_t wakelock_os_callouts_jni = { sizeof(wakelock_os_callouts_jni), - nullptr /* not used */, acquire_wake_lock_cb, release_wake_lock_cb, }; @@ -995,7 +1047,7 @@ static bool interop_match_addr(const char* feature_name, int feature = interop_feature_name_to_feature_id(feature_name); if (feature == -1) { - BTIF_TRACE_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); + LOG_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); return false; } @@ -1009,7 +1061,7 @@ static bool interop_match_name(const char* feature_name, const char* name) { int feature = interop_feature_name_to_feature_id(feature_name); if (feature == -1) { - BTIF_TRACE_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); + LOG_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); return false; } @@ -1024,7 +1076,7 @@ static bool interop_match_addr_or_name(const char* feature_name, int feature = interop_feature_name_to_feature_id(feature_name); if (feature == -1) { - BTIF_TRACE_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); + LOG_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); return false; } @@ -1042,7 +1094,7 @@ static void interop_database_add_remove_addr(bool do_add, int feature = interop_feature_name_to_feature_id(feature_name); if (feature == -1) { - BTIF_TRACE_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); + LOG_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); return; } @@ -1062,7 +1114,7 @@ static void interop_database_add_remove_name(bool do_add, int feature = interop_feature_name_to_feature_id(feature_name); if (feature == -1) { - BTIF_TRACE_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); + LOG_ERROR("%s: feature doesn't exist: %s", __func__, feature_name); return; } @@ -1098,6 +1150,9 @@ EXPORT_SYMBOL bt_interface_t bluetoothInterface = { .pin_reply = pin_reply, .ssp_reply = ssp_reply, .get_profile_interface = get_profile_interface, + .dut_mode_configure = dut_mode_configure, + .dut_mode_send = dut_mode_send, + .le_test_mode = le_test_mode, .set_os_callouts = set_os_callouts, .read_energy_info = read_energy_info, .dump = dump, @@ -1370,6 +1425,15 @@ void invoke_thread_evt_cb(bt_cb_thread_evt event) { event)); } +void invoke_le_test_mode_cb(bt_status_t status, uint16_t count) { + do_in_jni_thread(FROM_HERE, base::BindOnce( + [](bt_status_t status, uint16_t count) { + HAL_CBACK(bt_hal_cbacks, le_test_mode_cb, + status, count); + }, + status, count)); +} + // takes ownership of |uid_data| void invoke_energy_info_cb(bt_activity_energy_info energy_info, bt_uid_traffic_t* uid_data) { diff --git a/system/btif/src/btif_a2dp.cc b/system/btif/src/btif_a2dp.cc index 9e469ce14419dd2bf0f04dcb9df6369a99f87ff6..58076fa8d9490a2fdd282f64f57979e70d7a7598 100644 --- a/system/btif/src/btif_a2dp.cc +++ b/system/btif/src/btif_a2dp.cc @@ -38,9 +38,21 @@ #include -void btif_a2dp_on_idle(void) { +void btif_a2dp_on_idle(const RawAddress& peer_addr) { LOG_VERBOSE("Peer stream endpoint type:%s", peer_stream_endpoint_text(btif_av_get_peer_sep()).c_str()); + if (btif_av_src_sink_coexist_enabled()) { + bool is_sink = btif_av_peer_is_sink(peer_addr); + bool is_source = btif_av_peer_is_source(peer_addr); + LOG_INFO("## ON A2DP IDLE ## is_sink:%d is_source:%d", is_sink, is_source); + if (is_sink) { + btif_a2dp_source_on_idle(); + } else if (is_source) { + btif_a2dp_sink_on_idle(); + } + return; + } + if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) { btif_a2dp_source_on_idle(); } else if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) { diff --git a/system/btif/src/btif_a2dp_control.cc b/system/btif/src/btif_a2dp_control.cc index bca37f9d32d7153b8ccf1b83a7e694dca6aff575..0707135259f0919d184eb305e0f60ccdaa2bc68d 100644 --- a/system/btif/src/btif_a2dp_control.cc +++ b/system/btif/src/btif_a2dp_control.cc @@ -34,7 +34,7 @@ #include "btif_hf.h" #include "osi/include/osi.h" #include "types/raw_address.h" -#include "uipc.h" +#include "udrv/include/uipc.h" #define A2DP_DATA_READ_POLL_MS 10 @@ -65,9 +65,8 @@ void btif_a2dp_control_cleanup(void) { static tA2DP_CTRL_ACK btif_a2dp_control_on_check_ready() { if (btif_a2dp_source_media_task_is_shutting_down()) { - APPL_TRACE_WARNING( - "%s: A2DP command check ready while media task shutting down", - __func__); + LOG_WARN("%s: A2DP command check ready while media task shutting down", + __func__); return A2DP_CTRL_ACK_FAILURE; } @@ -75,8 +74,8 @@ static tA2DP_CTRL_ACK btif_a2dp_control_on_check_ready() { if (btif_av_stream_ready() || btif_av_stream_started_ready()) { return A2DP_CTRL_ACK_SUCCESS; } else { - APPL_TRACE_WARNING( - "%s: A2DP command check ready while AV stream is not ready", __func__); + LOG_WARN("%s: A2DP command check ready while AV stream is not ready", + __func__); return A2DP_CTRL_ACK_FAILURE; } } @@ -88,8 +87,7 @@ static tA2DP_CTRL_ACK btif_a2dp_control_on_start() { * while in a call, and respond with BAD_STATE. */ if (!bluetooth::headset::IsCallIdle()) { - APPL_TRACE_WARNING("%s: A2DP command start while call state is busy", - __func__); + LOG_WARN("%s: A2DP command start while call state is busy", __func__); return A2DP_CTRL_ACK_INCALL_FAILURE; } @@ -116,8 +114,7 @@ static tA2DP_CTRL_ACK btif_a2dp_control_on_start() { A2DP_DATA_PATH); return A2DP_CTRL_ACK_SUCCESS; } - APPL_TRACE_WARNING("%s: A2DP command start while AV stream is not ready", - __func__); + LOG_WARN("%s: A2DP command start while AV stream is not ready", __func__); return A2DP_CTRL_ACK_FAILURE; } @@ -203,25 +200,24 @@ static void btif_a2dp_control_on_set_output_audio_config() { reinterpret_cast(&codec_config.sample_rate), sizeof(btav_a2dp_codec_sample_rate_t)) != sizeof(btav_a2dp_codec_sample_rate_t)) { - APPL_TRACE_ERROR("%s: Error reading sample rate from audio HAL", __func__); + LOG_ERROR("%s: Error reading sample rate from audio HAL", __func__); return; } if (UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, reinterpret_cast(&codec_config.bits_per_sample), sizeof(btav_a2dp_codec_bits_per_sample_t)) != sizeof(btav_a2dp_codec_bits_per_sample_t)) { - APPL_TRACE_ERROR("%s: Error reading bits per sample from audio HAL", - __func__); + LOG_ERROR("%s: Error reading bits per sample from audio HAL", __func__); return; } if (UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, reinterpret_cast(&codec_config.channel_mode), sizeof(btav_a2dp_codec_channel_mode_t)) != sizeof(btav_a2dp_codec_channel_mode_t)) { - APPL_TRACE_ERROR("%s: Error reading channel mode from audio HAL", __func__); + LOG_ERROR("%s: Error reading channel mode from audio HAL", __func__); return; } - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG: " "sample_rate=0x%x bits_per_sample=0x%x " "channel_mode=0x%x", @@ -256,7 +252,7 @@ static void btif_a2dp_recv_ctrl_data(void) { /* detach on ctrl channel means audioflinger process was terminated */ if (n == 0) { - APPL_TRACE_WARNING("%s: CTRL CH DETACHED", __func__); + LOG_WARN("%s: CTRL CH DETACHED", __func__); UIPC_Close(*a2dp_uipc, UIPC_CH_ID_AV_CTRL); return; } @@ -264,11 +260,11 @@ static void btif_a2dp_recv_ctrl_data(void) { // Don't log A2DP_CTRL_GET_PRESENTATION_POSITION by default, because it // could be very chatty when audio is streaming. if (cmd == A2DP_CTRL_GET_PRESENTATION_POSITION) { - APPL_TRACE_DEBUG("%s: a2dp-ctrl-cmd : %s", __func__, - audio_a2dp_hw_dump_ctrl_event(cmd)); + LOG_VERBOSE("%s: a2dp-ctrl-cmd : %s", __func__, + audio_a2dp_hw_dump_ctrl_event(cmd)); } else { - APPL_TRACE_WARNING("%s: a2dp-ctrl-cmd : %s", __func__, - audio_a2dp_hw_dump_ctrl_event(cmd)); + LOG_WARN("%s: a2dp-ctrl-cmd : %s", __func__, + audio_a2dp_hw_dump_ctrl_event(cmd)); } a2dp_cmd_pending = cmd; @@ -306,7 +302,7 @@ static void btif_a2dp_recv_ctrl_data(void) { break; default: - APPL_TRACE_ERROR("%s: UNSUPPORTED CMD (%d)", __func__, cmd); + LOG_ERROR("%s: UNSUPPORTED CMD (%d)", __func__, cmd); btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE); break; } @@ -314,11 +310,11 @@ static void btif_a2dp_recv_ctrl_data(void) { // Don't log A2DP_CTRL_GET_PRESENTATION_POSITION by default, because it // could be very chatty when audio is streaming. if (cmd == A2DP_CTRL_GET_PRESENTATION_POSITION) { - APPL_TRACE_DEBUG("%s: a2dp-ctrl-cmd : %s DONE", __func__, - audio_a2dp_hw_dump_ctrl_event(cmd)); + LOG_VERBOSE("%s: a2dp-ctrl-cmd : %s DONE", __func__, + audio_a2dp_hw_dump_ctrl_event(cmd)); } else { - APPL_TRACE_WARNING("%s: a2dp-ctrl-cmd : %s DONE", __func__, - audio_a2dp_hw_dump_ctrl_event(cmd)); + LOG_WARN("%s: a2dp-ctrl-cmd : %s DONE", __func__, + audio_a2dp_hw_dump_ctrl_event(cmd)); } } @@ -327,11 +323,11 @@ static void btif_a2dp_ctrl_cb(UNUSED_ATTR tUIPC_CH_ID ch_id, // Don't log UIPC_RX_DATA_READY_EVT by default, because it // could be very chatty when audio is streaming. if (event == UIPC_RX_DATA_READY_EVT) { - APPL_TRACE_DEBUG("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__, - dump_uipc_event(event)); + LOG_VERBOSE("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__, + dump_uipc_event(event)); } else { - APPL_TRACE_WARNING("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__, - dump_uipc_event(event)); + LOG_WARN("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__, + dump_uipc_event(event)); } switch (event) { @@ -350,16 +346,16 @@ static void btif_a2dp_ctrl_cb(UNUSED_ATTR tUIPC_CH_ID ch_id, break; default: - APPL_TRACE_ERROR("%s: ### A2DP-CTRL-CHANNEL EVENT %d NOT HANDLED ###", - __func__, event); + LOG_ERROR("%s: ### A2DP-CTRL-CHANNEL EVENT %d NOT HANDLED ###", __func__, + event); break; } } static void btif_a2dp_data_cb(UNUSED_ATTR tUIPC_CH_ID ch_id, tUIPC_EVENT event) { - APPL_TRACE_WARNING("%s: BTIF MEDIA (A2DP-DATA) EVENT %s", __func__, - dump_uipc_event(event)); + LOG_WARN("%s: BTIF MEDIA (A2DP-DATA) EVENT %s", __func__, + dump_uipc_event(event)); switch (event) { case UIPC_OPEN_EVT: @@ -381,15 +377,14 @@ static void btif_a2dp_data_cb(UNUSED_ATTR tUIPC_CH_ID ch_id, break; case UIPC_CLOSE_EVT: - APPL_TRACE_EVENT("%s: ## AUDIO PATH DETACHED ##", __func__); + LOG_VERBOSE("%s: ## AUDIO PATH DETACHED ##", __func__); btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS); /* Post stop event and wait for audio path to stop */ btif_av_stream_stop(RawAddress::kEmpty); break; default: - APPL_TRACE_ERROR("%s: ### A2DP-DATA EVENT %d NOT HANDLED ###", __func__, - event); + LOG_ERROR("%s: ### A2DP-DATA EVENT %d NOT HANDLED ###", __func__, event); break; } } @@ -400,16 +395,16 @@ void btif_a2dp_command_ack(tA2DP_CTRL_ACK status) { // Don't log A2DP_CTRL_GET_PRESENTATION_POSITION by default, because it // could be very chatty when audio is streaming. if (a2dp_cmd_pending == A2DP_CTRL_GET_PRESENTATION_POSITION) { - APPL_TRACE_DEBUG("%s: ## a2dp ack : %s, status %d ##", __func__, - audio_a2dp_hw_dump_ctrl_event(a2dp_cmd_pending), status); + LOG_VERBOSE("%s: ## a2dp ack : %s, status %d ##", __func__, + audio_a2dp_hw_dump_ctrl_event(a2dp_cmd_pending), status); } else { - APPL_TRACE_WARNING("%s: ## a2dp ack : %s, status %d ##", __func__, - audio_a2dp_hw_dump_ctrl_event(a2dp_cmd_pending), status); + LOG_WARN("%s: ## a2dp ack : %s, status %d ##", __func__, + audio_a2dp_hw_dump_ctrl_event(a2dp_cmd_pending), status); } /* Sanity check */ if (a2dp_cmd_pending == A2DP_CTRL_CMD_NONE) { - APPL_TRACE_ERROR("%s: warning : no command pending, ignore ack", __func__); + LOG_ERROR("%s: warning : no command pending, ignore ack", __func__); return; } @@ -428,12 +423,12 @@ void btif_a2dp_control_log_bytes_read(uint32_t bytes_read) { } void btif_a2dp_control_set_audio_delay(uint16_t delay) { - APPL_TRACE_DEBUG("%s: DELAY: %.1f ms", __func__, (float)delay / 10); + LOG_VERBOSE("%s: DELAY: %.1f ms", __func__, (float)delay / 10); delay_report_stats.audio_delay = delay; } void btif_a2dp_control_reset_audio_delay(void) { - APPL_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); delay_report_stats.audio_delay = 0; delay_report_stats.total_bytes_read = 0; delay_report_stats.timestamp = {}; diff --git a/system/btif/src/btif_a2dp_sink.cc b/system/btif/src/btif_a2dp_sink.cc index fb7e8f3607c19dd5265e5e369db359cced6b280b..be2098788ec494c616a340661c128972965bb749 100644 --- a/system/btif/src/btif_a2dp_sink.cc +++ b/system/btif/src/btif_a2dp_sink.cc @@ -40,7 +40,6 @@ #include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "types/raw_address.h" using bluetooth::common::MessageLoopThread; @@ -400,9 +399,9 @@ void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info) { reinterpret_cast( osi_malloc(sizeof(tBTIF_MEDIA_SINK_DECODER_UPDATE))); - APPL_TRACE_EVENT("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__, - p_codec_info[1], p_codec_info[2], p_codec_info[3], - p_codec_info[4], p_codec_info[5], p_codec_info[6]); + LOG_VERBOSE("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__, p_codec_info[1], + p_codec_info[2], p_codec_info[3], p_codec_info[4], + p_codec_info[5], p_codec_info[6]); memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE); p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE; @@ -533,7 +532,7 @@ static void btif_a2dp_sink_on_decode_complete(uint8_t* data, uint32_t len) { static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg) { if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) || (btif_a2dp_sink_cb.rx_flush)) { - APPL_TRACE_DEBUG("%s: state changed happened in this tick", __func__); + LOG_VERBOSE("%s: state changed happened in this tick", __func__); return; } @@ -548,14 +547,13 @@ static void btif_a2dp_sink_avk_handle_timer() { BT_HDR* p_msg; if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) { - APPL_TRACE_DEBUG("%s: empty queue", __func__); + LOG_VERBOSE("%s: empty queue", __func__); return; } /* Don't do anything in case of focus not granted */ if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) { - APPL_TRACE_DEBUG("%s: skipping frames since focus is not present", - __func__); + LOG_VERBOSE("%s: skipping frames since focus is not present", __func__); return; } /* Play only in BTIF_A2DP_SINK_FOCUS_GRANTED case */ @@ -564,20 +562,20 @@ static void btif_a2dp_sink_avk_handle_timer() { return; } - APPL_TRACE_DEBUG("%s: process frames begin", __func__); + LOG_VERBOSE("%s: process frames begin", __func__); while (true) { p_msg = (BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue); if (p_msg == NULL) { break; } - APPL_TRACE_DEBUG("%s: number of packets in queue %zu", __func__, - fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue)); + LOG_VERBOSE("%s: number of packets in queue %zu", __func__, + fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue)); /* Queue packet has less frames */ btif_a2dp_sink_handle_inc_media(p_msg); osi_free(p_msg); } - APPL_TRACE_DEBUG("%s: process frames end", __func__); + LOG_VERBOSE("%s: process frames end", __func__); } /* when true media task discards any rx frames */ @@ -599,10 +597,9 @@ static void btif_a2dp_sink_decoder_update_event( tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) { LOG_INFO("%s", __func__); LockGuard lock(g_mutex); - APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__, - p_buf->codec_info[1], p_buf->codec_info[2], - p_buf->codec_info[3], p_buf->codec_info[4], - p_buf->codec_info[5], p_buf->codec_info[6]); + LOG_VERBOSE("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__, + p_buf->codec_info[1], p_buf->codec_info[2], p_buf->codec_info[3], + p_buf->codec_info[4], p_buf->codec_info[5], p_buf->codec_info[6]); int sample_rate = A2DP_GetTrackSampleRate(p_buf->codec_info); if (sample_rate == -1) { @@ -629,9 +626,13 @@ static void btif_a2dp_sink_decoder_update_event( btif_a2dp_sink_cb.channel_count = channel_count; btif_a2dp_sink_cb.rx_flush = false; - APPL_TRACE_DEBUG("%s: reset to Sink role", __func__); + LOG_VERBOSE("%s: reset to Sink role", __func__); + + bta_av_co_save_codec(p_buf->codec_info); + + btif_a2dp_sink_cb.decoder_interface = + A2DP_GetDecoderInterface(p_buf->codec_info); - btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface(); if (btif_a2dp_sink_cb.decoder_interface == nullptr) { LOG_ERROR("%s: cannot stream audio: no source decoder interface", __func__); return; @@ -647,7 +648,7 @@ static void btif_a2dp_sink_decoder_update_event( btif_a2dp_sink_cb.decoder_interface->decoder_configure(p_buf->codec_info); } - APPL_TRACE_DEBUG("%s: create audio track", __func__); + LOG_VERBOSE("%s: create audio track", __func__); btif_a2dp_sink_cb.audio_track = #ifdef __ANDROID__ BtifAvrcpAudioTrackCreate(sample_rate, bits_per_sample, channel_count); @@ -665,14 +666,7 @@ uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) { if (btif_a2dp_sink_cb.rx_flush) /* Flush enabled, do not enqueue */ return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue); - if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) == - MAX_INPUT_A2DP_FRAME_QUEUE_SZ) { - uint8_t ret = fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue); - osi_free(fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue)); - return ret; - } - - BTIF_TRACE_VERBOSE("%s +", __func__); + LOG_VERBOSE("%s +", __func__); /* Allocate and queue this buffer */ BT_HDR* p_msg = reinterpret_cast(osi_malloc(sizeof(*p_msg) + p_pkt->len)); @@ -680,10 +674,20 @@ uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) { p_msg->offset = 0; memcpy(p_msg->data, p_pkt->data + p_pkt->offset, p_pkt->len); fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg); + if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) == - MAX_A2DP_DELAYED_START_FRAME_COUNT) { - BTIF_TRACE_DEBUG("%s: Initiate decoding. Current focus state:%d", __func__, - btif_a2dp_sink_cb.rx_focus_state); + MAX_INPUT_A2DP_FRAME_QUEUE_SZ) { + osi_free(fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue)); + uint8_t ret = fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue); + return ret; + } + + // Avoid other checks if alarm has already been initialized. + if (btif_a2dp_sink_cb.decode_alarm == nullptr && + fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) >= + MAX_A2DP_DELAYED_START_FRAME_COUNT) { + LOG_VERBOSE("%s: Initiate decoding. Current focus state:%d", __func__, + btif_a2dp_sink_cb.rx_focus_state); if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_GRANTED) { btif_a2dp_sink_audio_handle_start_decoding(); } @@ -727,7 +731,7 @@ static void btif_a2dp_sink_set_focus_state_event( LOG_INFO("%s: state=%d", __func__, state); LockGuard lock(g_mutex); - APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state); + LOG_VERBOSE("%s: setting focus state to %d", __func__, state); btif_a2dp_sink_cb.rx_focus_state = state; if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) { fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free); @@ -746,6 +750,11 @@ void btif_a2dp_sink_set_audio_track_gain(float gain) { #endif } +void * btif_a2dp_sink_get_audio_track(void) +{ + return btif_a2dp_sink_cb.audio_track; +} + static void btif_a2dp_sink_clear_track_event_req() { LOG_INFO("%s", __func__); BT_HDR_RIGID* p_buf = diff --git a/system/btif/src/btif_a2dp_source.cc b/system/btif/src/btif_a2dp_source.cc index 2a538390fba517f37d95b1bbaf08085d15332c1c..c0cb38fd08487feddfb8bf978d46da969dd5df1d 100644 --- a/system/btif/src/btif_a2dp_source.cc +++ b/system/btif/src/btif_a2dp_source.cc @@ -55,7 +55,7 @@ #include "stack/include/acl_api_types.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" -#include "uipc.h" +#include "udrv/include/uipc.h" using bluetooth::common::A2dpSessionMetrics; using bluetooth::common::BluetoothMetricsLogger; @@ -185,6 +185,7 @@ class BtifA2dpSource { BtifA2dpSource() : tx_audio_queue(nullptr), tx_flush(false), + sw_audio_is_encoding(false), encoder_interface(nullptr), encoder_interval_ms(0), state_(kStateOff) {} @@ -220,6 +221,7 @@ class BtifA2dpSource { fixed_queue_t* tx_audio_queue; bool tx_flush; /* Discards any outgoing data when true */ + bool sw_audio_is_encoding; RepeatingTimer media_alarm; const tA2DP_ENCODER_INTERFACE* encoder_interface; uint64_t encoder_interval_ms; /* Local copy of the encoder interval */ @@ -723,6 +725,8 @@ void btif_a2dp_source_on_idle(void) { void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) { LOG_INFO("%s: state=%s", __func__, btif_a2dp_source_cb.StateStr().c_str()); + btif_a2dp_source_cb.sw_audio_is_encoding = false; + // allow using this API for other (acknowledgement and stopping media task) // than suspend if (p_av_suspend != nullptr && p_av_suspend->status != BTA_AV_SUCCESS) { @@ -805,9 +809,8 @@ static void btif_a2dp_source_audio_tx_start_event(void) { CHECK(btif_a2dp_source_cb.encoder_interface != nullptr); btif_a2dp_source_cb.encoder_interface->feeding_reset(); - APPL_TRACE_EVENT( - "%s: starting timer %" PRIu64 " ms", __func__, - btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms()); + LOG_VERBOSE("%s: starting timer %" PRIu64 " ms", __func__, + btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms()); /* audio engine starting, reset tx suspended flag */ btif_a2dp_source_cb.tx_flush = false; @@ -822,6 +825,7 @@ static void btif_a2dp_source_audio_tx_start_event(void) { base::Milliseconds( #endif 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 @@ -941,7 +945,7 @@ static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) { bytes_read = UIPC_Read(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, p_buf, len); } - if (bytes_read < len) { + if (btif_a2dp_source_cb.sw_audio_is_encoding && bytes_read < len) { LOG_WARN("%s: UNDERFLOW: ONLY READ %d BYTES OUT OF %d", __func__, bytes_read, len); btif_a2dp_source_cb.stats.media_read_total_underflow_bytes += @@ -1013,13 +1017,6 @@ static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n, btif_av_source_active_peer(), btif_a2dp_source_cb.encoder_interval_ms, drop_n, num_dropped_encoded_frames, num_dropped_encoded_bytes); - // Intel controllers don't handle ReadRSSI, ReadFailedContactCounter, and - // ReadTxPower very well, it sends back Hardware Error event which will - // crash the daemon. So temporarily disable this for Floss. - // TODO(b/249876976): Intel controllers to handle this command correctly. - // And if the need for disabling metrics-related HCI call grows, consider - // creating a framework to avoid ifdefs. -#ifndef TARGET_FLOSS // Request additional debug info if we had to flush buffers RawAddress peer_bda = btif_av_source_active_peer(); tBTM_STATUS status = BTM_ReadRSSI(peer_bda, btm_read_rssi_cb); @@ -1027,19 +1024,26 @@ static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n, LOG_WARN("%s: Cannot read RSSI: status %d", __func__, status); } + // Intel controllers don't handle ReadFailedContactCounter very well, it + // sends back Hardware Error event which will crash the daemon. So + // temporarily disable this for Floss. + // TODO(b/249876976): Intel controllers to handle this command correctly. + // And if the need for disabling metrics-related HCI call grows, consider + // creating a framework to avoid ifdefs. +#ifndef TARGET_FLOSS status = BTM_ReadFailedContactCounter(peer_bda, btm_read_failed_contact_counter_cb); if (status != BTM_CMD_STARTED) { LOG_WARN("%s: Cannot read Failed Contact Counter: status %d", __func__, status); } +#endif status = BTM_ReadTxPower(peer_bda, BT_TRANSPORT_BR_EDR, btm_read_tx_power_cb); if (status != BTM_CMD_STARTED) { LOG_WARN("%s: Cannot read Tx Power: status %d", __func__, status); } -#endif } /* Update the statistics */ @@ -1099,10 +1103,9 @@ BT_HDR* btif_a2dp_source_audio_readbuf(void) { static void log_tstamps_us(const char* comment, uint64_t timestamp_us) { static uint64_t prev_us = 0; - APPL_TRACE_DEBUG("%s: [%s] ts %08" PRIu64 ", diff : %08" PRIu64 - ", queue sz %zu", - __func__, comment, timestamp_us, timestamp_us - prev_us, - fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue)); + LOG_VERBOSE("%s: [%s] ts %08" PRIu64 ", diff : %08" PRIu64 ", queue sz %zu", + __func__, comment, timestamp_us, timestamp_us - prev_us, + fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue)); prev_us = timestamp_us; } diff --git a/system/btif/src/btif_activity_attribution.cc b/system/btif/src/btif_activity_attribution.cc deleted file mode 100644 index 9f161cc915ef789e7186222db6e95df56fc5aeca..0000000000000000000000000000000000000000 --- a/system/btif/src/btif_activity_attribution.cc +++ /dev/null @@ -1,36 +0,0 @@ -/****************************************************************************** - * - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#define LOG_TAG "bt_btif_activity_attribution" - -#include "btif_activity_attribution.h" -#include "main/shim/activity_attribution.h" -#include "main/shim/shim.h" - -using base::Bind; -using base::Unretained; - -namespace bluetooth { -namespace activity_attribution { - -ActivityAttributionInterface* get_activity_attribution_instance() { - return bluetooth::shim::get_activity_attribution_instance(); -} - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc index 019162cada29771596688d08f1c124d9ddee78cb..eabf30ea9513bdda65653a2bf1da56f23cc7cd26 100644 --- a/system/btif/src/btif_av.cc +++ b/system/btif/src/btif_av.cc @@ -20,6 +20,7 @@ #include "btif/include/btif_av.h" +#include #include #include #include @@ -29,12 +30,10 @@ #include #include #include -#include #include #include #include "audio_hal_interface/a2dp_encoding.h" -#include "bta/av/bta_av_int.h" #include "btif/include/btif_a2dp.h" #include "btif/include/btif_a2dp_control.h" #include "btif/include/btif_a2dp_sink.h" @@ -47,19 +46,18 @@ #include "btif/include/btif_util.h" #include "btif/include/stack_manager.h" #include "btif_metrics_logging.h" -#include "common/metrics.h" #include "common/state_machine.h" #include "device/include/device_iot_config.h" #include "hardware/bt_av.h" #include "include/hardware/bt_rc.h" -#include "main/shim/dumpsys.h" +#include "internal_include/bt_trace.h" +#include "osi/include/alarm.h" #include "osi/include/allocator.h" -#include "osi/include/properties.h" #include "stack/include/avrc_api.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_api.h" -#include "stack/include/btu.h" // do_in_main_thread -#include "types/bluetooth/uuid.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/btm_log_history.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" /***************************************************************************** @@ -137,6 +135,9 @@ class BtifAvEvent { class BtifAvPeer; static bt_status_t sink_set_active_device(const RawAddress& peer_address); +static void btif_av_sink_delete_active_peer(void); +static void btif_av_source_delete_active_peer(void); + // Should not need dedicated Suspend state as actual actions are no // different than Open state. Suspend flags are needed however to prevent // media task from trying to restart stream during remote Suspend or while @@ -279,6 +280,7 @@ class BtifAvPeer { bool IsSource() const { return (peer_sep_ == AVDT_TSEP_SRC); } bool IsSink() const { return (peer_sep_ == AVDT_TSEP_SNK); } uint8_t PeerSep() const { return peer_sep_; } + void SetSep(uint8_t sep_type) { peer_sep_ = sep_type; } /** * Get the local device's Service Class UUID * @@ -360,7 +362,7 @@ class BtifAvPeer { private: const RawAddress peer_address_; - const uint8_t peer_sep_; // SEP type of peer device + uint8_t peer_sep_; // SEP type of peer device tBTA_AV_HNDL bta_handle_; const uint8_t peer_id_; BtifAvStateMachine state_machine_; @@ -384,6 +386,7 @@ class BtifAvSource { : callbacks_(nullptr), enabled_(false), a2dp_offload_enabled_(false), + invalid_peer_check_(false), max_connected_peers_(kDefaultMaxConnectedAudioDevices) {} ~BtifAvSource(); @@ -396,7 +399,9 @@ class BtifAvSource { btav_source_callbacks_t* Callbacks() { return callbacks_; } bool Enabled() const { return enabled_; } bool A2dpOffloadEnabled() const { return a2dp_offload_enabled_; } - + void SetInvalidPeerCheck(bool invalid_peer_check) { + invalid_peer_check_ = invalid_peer_check; + } BtifAvPeer* FindPeer(const RawAddress& peer_address); BtifAvPeer* FindPeerByHandle(tBTA_AV_HNDL bta_handle); BtifAvPeer* FindPeerByPeerId(uint8_t peer_id); @@ -445,11 +450,11 @@ class BtifAvSource { } BtifAvPeer* peer = FindPeer(peer_address); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: peer is null", __func__); + LOG_WARN("%s: peer is null", __func__); return false; } if (!peer->IsConnected()) { - BTIF_TRACE_WARNING("%s: peer is not connected", __func__); + LOG_WARN("%s: peer is not connected", __func__); return false; } return peer->IsInSilenceMode(); @@ -470,11 +475,11 @@ class BtifAvSource { ADDRESS_TO_LOGGABLE_CSTR(peer_address)); BtifAvPeer* peer = FindPeer(peer_address); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: peer is null", __func__); + LOG_WARN("%s: peer is null", __func__); return false; } if (!peer->IsConnected()) { - BTIF_TRACE_WARNING("%s: peer is not connected", __func__); + LOG_WARN("%s: peer is not connected", __func__); return false; } peer->SetSilence(silence); @@ -498,12 +503,17 @@ class BtifAvSource { return true; // Nothing has changed } if (peer_address.IsEmpty()) { - BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the Audio source", - __func__); - if (!bta_av_co_set_active_peer(peer_address)) { - LOG(WARNING) << __func__ - << ": unable to set active peer to empty in BtaAvCo"; + LOG_VERBOSE("%s: peer address is empty, shutdown the Audio source", + __func__); + if (!btif_av_src_sink_coexist_enabled() || + (btif_av_src_sink_coexist_enabled() && + btif_av_sink_active_peer().IsEmpty())) { + if (!bta_av_co_set_active_peer(peer_address)) { + LOG(WARNING) << __func__ + << ": unable to set active peer to empty in BtaAvCo"; + } } + btif_a2dp_source_end_session(active_peer_); std::promise shutdown_complete_promise; std::future shutdown_complete_future = @@ -519,6 +529,7 @@ class BtifAvSource { return true; } + if (btif_av_src_sink_coexist_enabled()) btif_av_sink_delete_active_peer(); BtifAvPeer* peer = FindPeer(peer_address); if (peer == nullptr || !peer->IsConnected()) { LOG(ERROR) << __func__ << ": Error setting " @@ -537,6 +548,22 @@ class BtifAvSource { return true; } + void DeleteActivePeer(void) { + std::promise shutdown_complete_promise; + LOG_VERBOSE("%s", __func__); + if (btif_av_sink_active_peer().IsEmpty()) { + if (!bta_av_co_set_active_peer(RawAddress::kEmpty)) { + LOG_WARN("%s : unable to set active peer to empty in BtaAvCo", + __func__); + } + } else { + LOG_WARN("%s : there is an active peer as source role", __func__); + } + btif_a2dp_source_end_session(active_peer_); + btif_a2dp_source_shutdown(std::move(shutdown_complete_promise)); + active_peer_ = RawAddress::kEmpty; + } + /** * Update source codec configuration for a peer. * @@ -561,6 +588,8 @@ class BtifAvSource { void RegisterAllBtaHandles(); void DeregisterAllBtaHandles(); void BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle); + BtifAvPeer* popPeer(const RawAddress& peer_address); + void AddPeer(BtifAvPeer* peer); private: void CleanupAllPeers(); @@ -568,11 +597,15 @@ class BtifAvSource { btav_source_callbacks_t* callbacks_; bool enabled_; bool a2dp_offload_enabled_; + bool invalid_peer_check_; // pending to check at BTA_AV_OPEN_EVT int max_connected_peers_; std::map peers_; std::set silenced_peers_; RawAddress active_peer_; std::map peer_id2bta_handle_; + std::mutex mutex_; + // protect for BtifAvSource::peers_ + std::recursive_mutex btifavsource_peer_lock_; }; class BtifAvSink { @@ -584,6 +617,7 @@ class BtifAvSink { BtifAvSink() : callbacks_(nullptr), enabled_(false), + invalid_peer_check_(false), max_connected_peers_(kDefaultMaxConnectedAudioDevices) {} ~BtifAvSink(); @@ -594,6 +628,9 @@ class BtifAvSink { btav_sink_callbacks_t* Callbacks() { return callbacks_; } bool Enabled() const { return enabled_; } + void SetInvalidPeerCheck(bool invalid_peer_check) { + invalid_peer_check_ = invalid_peer_check; + } BtifAvPeer* FindPeer(const RawAddress& peer_address); BtifAvPeer* FindPeerByHandle(tBTA_AV_HNDL bta_handle); BtifAvPeer* FindPeerByPeerId(uint8_t peer_id); @@ -647,12 +684,17 @@ class BtifAvSink { return true; // Nothing has changed } if (peer_address.IsEmpty()) { - BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the Audio sink", - __func__); - if (!bta_av_co_set_active_peer(peer_address)) { - LOG(WARNING) << __func__ - << ": unable to set active peer to empty in BtaAvCo"; + LOG_VERBOSE("%s: peer address is empty, shutdown the Audio sink", + __func__); + if (!btif_av_src_sink_coexist_enabled() || + (btif_av_src_sink_coexist_enabled() && + btif_av_source_active_peer().IsEmpty())) { + if (!bta_av_co_set_active_peer(peer_address)) { + LOG(WARNING) << __func__ + << ": unable to set active peer to empty in BtaAvCo"; + } } + btif_a2dp_sink_end_session(active_peer_); btif_a2dp_sink_shutdown(); active_peer_ = peer_address; @@ -660,6 +702,9 @@ class BtifAvSink { return true; } + if (btif_av_src_sink_coexist_enabled()) { + btif_av_source_delete_active_peer(); + } BtifAvPeer* peer = FindPeer(peer_address); if (peer == nullptr || !peer->IsConnected()) { LOG(ERROR) << __func__ << ": Error setting " @@ -674,21 +719,41 @@ class BtifAvSink { // cannot set promise but need to be handled within restart_session return false; } + LOG(INFO) << "Setting the active peer to peer address %s" + << ADDRESS_TO_LOGGABLE_STR(peer_address); active_peer_ = peer_address; return true; } + void DeleteActivePeer(void) { + LOG_VERBOSE("%s", __func__); + if (btif_av_source_active_peer().IsEmpty()) { + if (!bta_av_co_set_active_peer(RawAddress::kEmpty)) { + LOG(WARNING) << __func__ + << ": unable to set active peer to empty in BtaAvCo"; + } + } else { + LOG(WARNING) << __func__ << ": there is an active peer as sink role"; + } + btif_a2dp_sink_end_session(active_peer_); + btif_a2dp_sink_shutdown(); + active_peer_ = RawAddress::kEmpty; + } + const std::map& Peers() const { return peers_; } void RegisterAllBtaHandles(); void DeregisterAllBtaHandles(); void BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle); + BtifAvPeer* popPeer(const RawAddress& peer_address); + void AddPeer(BtifAvPeer* peer); private: void CleanupAllPeers(); btav_sink_callbacks_t* callbacks_; bool enabled_; + bool invalid_peer_check_; // pending to check at BTA_AV_OPEN_EVT int max_connected_peers_; std::map peers_; RawAddress active_peer_; @@ -741,6 +806,11 @@ static void btif_av_sink_initiate_av_open_timer_timeout(void* data); static void bta_av_sink_media_callback(const RawAddress& peer_address, tBTA_AV_EVT event, tBTA_AV_MEDIA* p_data); +extern bool btif_av_both_enable(void); +extern bool btif_av_is_connected_addr(const RawAddress& peer_address); +extern bool btif_av_peer_is_sink(const RawAddress& peer_address); +extern void btif_rc_check_pending_cmd(const RawAddress& peer_address); +extern void btif_rc_get_addr_by_handle(uint8_t handle, RawAddress& rc_addr); static BtifAvPeer* btif_av_source_find_peer(const RawAddress& peer_address) { return btif_av_source.FindPeer(peer_address); @@ -749,11 +819,27 @@ static BtifAvPeer* btif_av_sink_find_peer(const RawAddress& peer_address) { return btif_av_sink.FindPeer(peer_address); } static BtifAvPeer* btif_av_find_peer(const RawAddress& peer_address) { + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + BtifAvPeer* peer = nullptr; + peer = btif_av_source_find_peer(peer_address); + if (nullptr == peer) { + return btif_av_sink_find_peer(peer_address); + } + return peer; + } if (btif_av_source.Enabled()) return btif_av_source_find_peer(peer_address); if (btif_av_sink.Enabled()) return btif_av_sink_find_peer(peer_address); return nullptr; } static BtifAvPeer* btif_av_find_active_peer() { + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + BtifAvPeer* peer = nullptr; + peer = btif_av_source_find_peer(btif_av_source.ActivePeer()); + if (nullptr == peer) { + return btif_av_sink_find_peer(btif_av_sink.ActivePeer()); + } + return peer; + } if (btif_av_source.Enabled()) return btif_av_source_find_peer(btif_av_source.ActivePeer()); if (btif_av_sink.Enabled()) @@ -761,6 +847,26 @@ static BtifAvPeer* btif_av_find_active_peer() { return nullptr; } +const RawAddress& btif_av_find_by_handle(tBTA_AV_HNDL bta_handle) { + BtifAvPeer* peer = nullptr; + if (btif_av_both_enable()) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + if (peer == nullptr) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } + if (peer == nullptr) return RawAddress::kEmpty; + + return peer->PeerAddress(); + } + if (btif_av_source.Enabled()) + peer = btif_av_source.FindPeerByHandle(bta_handle); + if (btif_av_sink.Enabled()) peer = btif_av_sink.FindPeerByHandle(bta_handle); + + if (peer == nullptr) return RawAddress::kEmpty; + + return peer->PeerAddress(); +} + /***************************************************************************** * Local helper functions *****************************************************************************/ @@ -985,6 +1091,18 @@ const RawAddress& BtifAvPeer::ActivePeerAddress() const { if (IsSink()) { return btif_av_source.ActivePeer(); } + + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + RawAddress addr = btif_av_sink.ActivePeer(); + if (RawAddress::kEmpty == addr) { + LOG(WARNING) << __PRETTY_FUNCTION__ << ": A2DP peer " + << btif_av_source.ActivePeer() << " is Sink"; + return btif_av_source.ActivePeer(); + } + LOG(WARNING) << __PRETTY_FUNCTION__ << ": A2DP peer " + << btif_av_sink.ActivePeer() << " is Source"; + return btif_av_sink.ActivePeer(); + } LOG(FATAL) << __PRETTY_FUNCTION__ << ": A2DP peer " << ADDRESS_TO_LOGGABLE_STR(PeerAddress()) << " is neither Source nor Sink"; @@ -1017,7 +1135,7 @@ bt_status_t BtifAvSource::Init( /* A2DP OFFLOAD */ a2dp_offload_enabled_ = GetInterfaceToProfiles()->config->isA2DPOffloadEnabled(); - BTIF_TRACE_DEBUG("a2dp_offload.enable = %d", a2dp_offload_enabled_); + LOG_VERBOSE("a2dp_offload.enable = %d", a2dp_offload_enabled_); callbacks_ = callbacks; if (a2dp_offload_enabled_) { @@ -1029,14 +1147,15 @@ bt_status_t BtifAvSource::Init( if (!btif_a2dp_source_init()) { return BT_STATUS_FAIL; } - btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID); enabled_ = true; + btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID); return BT_STATUS_SUCCESS; } void BtifAvSource::Cleanup() { LOG_INFO("%s", __PRETTY_FUNCTION__); if (!enabled_) return; + enabled_ = false; btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SOURCE); @@ -1046,13 +1165,12 @@ void BtifAvSource::Cleanup() { base::BindOnce(base::IgnoreResult(&BtifAvSource::SetActivePeer), base::Unretained(&btif_av_source), RawAddress::kEmpty, std::move(peer_ready_promise))); - do_in_main_thread(FROM_HERE, base::Bind(&btif_a2dp_source_cleanup)); + do_in_main_thread(FROM_HERE, base::BindOnce(&btif_a2dp_source_cleanup)); btif_disable_service(BTA_A2DP_SOURCE_SERVICE_ID); CleanupAllPeers(); callbacks_ = nullptr; - enabled_ = false; } BtifAvPeer* BtifAvSource::FindPeer(const RawAddress& peer_address) { @@ -1083,8 +1201,9 @@ BtifAvPeer* BtifAvSource::FindPeerByPeerId(uint8_t peer_id) { BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address, tBTA_AV_HNDL bta_handle) { - BTIF_TRACE_DEBUG("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle); + std::unique_lock lock1(mutex_); + LOG_VERBOSE("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle); BtifAvPeer* peer = FindPeer(peer_address); if (peer != nullptr) return peer; @@ -1092,10 +1211,17 @@ BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address, // Find next availabie Peer ID to use uint8_t peer_id; for (peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) { - if (FindPeerByPeerId(peer_id) == nullptr) break; + /* because the peer id may be in source cb and we cannot use it */ + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + if (FindPeerByPeerId(peer_id) == nullptr && + btif_av_sink.FindPeerByPeerId(peer_id) == nullptr) + break; + } else { + if (FindPeerByPeerId(peer_id) == nullptr) break; + } } if (peer_id == kPeerIdMax) { - BTIF_TRACE_ERROR( + LOG_ERROR( "%s: Cannot create peer for peer_address=%s : " "cannot allocate unique Peer ID", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -1106,7 +1232,7 @@ BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address, if (bta_handle == kBtaHandleUnknown) { auto it = peer_id2bta_handle_.find(peer_id); if (it == peer_id2bta_handle_.end() || it->second == kBtaHandleUnknown) { - BTIF_TRACE_ERROR( + LOG_ERROR( "%s: Cannot create peer for peer_address=%s : " "cannot convert Peer ID=%d to unique BTA Handle", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), peer_id); @@ -1126,6 +1252,12 @@ BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address, bool BtifAvSource::AllowedToConnect(const RawAddress& peer_address) const { int connected = 0; + if (btif_av_src_sink_coexist_enabled() && invalid_peer_check_) { + LOG_INFO( + "invalid_peer_check_ so allow to connect here, when" + " BTA_AV_OPEN_EVT coming, would check again!"); + return true; + } // Count peers that are in the process of connecting or already connected for (auto it : peers_) { @@ -1135,6 +1267,10 @@ bool BtifAvSource::AllowedToConnect(const RawAddress& peer_address) const { case BtifAvStateMachine::kStateOpened: case BtifAvStateMachine::kStateStarted: if (peer->PeerAddress() == peer_address) { + /* we should check if another role is used */ + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) + break; + return true; // Already connected or accounted for } connected++; @@ -1143,6 +1279,18 @@ bool BtifAvSource::AllowedToConnect(const RawAddress& peer_address) const { break; } } + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + LOG_INFO("%s: connected=%d, max_connected_peers_=%d, sink_peers=%d", + __PRETTY_FUNCTION__, connected, max_connected_peers_, + (int)btif_av_sink.Peers().size()); + /* if source device connected, don't connect sink device */ + + if (connected >= max_connected_peers_ || !btif_av_sink.Peers().empty()) { + return false; + } else { + return true; + } + } return (connected < max_connected_peers_); } @@ -1202,12 +1350,12 @@ void BtifAvSource::BtaHandleRegistered(uint8_t peer_id, BtifAvPeer* peer = FindPeerByPeerId(peer_id); if (peer != nullptr && peer->BtaHandle() != bta_handle) { if (peer->BtaHandle() == kBtaHandleUnknown) { - BTIF_TRACE_EVENT( - "%s: Assign peer: peer_address=%s bta_handle=0x%x peer_id=%d", - __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), - bta_handle, peer_id); + LOG_VERBOSE("%s: Assign peer: peer_address=%s bta_handle=0x%x peer_id=%d", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), bta_handle, + peer_id); } else { - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Correct peer: peer_address=%s bta_handle=0x%x->0x%x peer_id=%d", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), peer->BtaHandle(), bta_handle, peer_id); @@ -1216,6 +1364,23 @@ void BtifAvSource::BtaHandleRegistered(uint8_t peer_id, } } +BtifAvPeer* BtifAvSource::popPeer(const RawAddress& peer_address) { + auto it = peers_.find(peer_address); + if (it == peers_.end()) return nullptr; + BtifAvPeer* peer = it->second; + peers_.erase(it); + LOG_INFO("%s: peer_address=%s, state=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->StateMachine().StateId()); + return peer; +} + +void BtifAvSource::AddPeer(BtifAvPeer* peer) { + LOG_INFO("%s: peer_address=%s, state=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->StateMachine().StateId()); + peers_.insert(std::make_pair(peer->PeerAddress(), peer)); +} BtifAvSink::~BtifAvSink() { CleanupAllPeers(); } bt_status_t BtifAvSink::Init(btav_sink_callbacks_t* callbacks, @@ -1228,20 +1393,26 @@ bt_status_t BtifAvSink::Init(btav_sink_callbacks_t* callbacks, max_connected_peers_ = max_connected_audio_devices; callbacks_ = callbacks; - std::vector codec_priorities; // Default priorities - bta_av_co_init(codec_priorities); + /** source will have this configuration, but sink don't have, so don't + * overwrite it. */ + if (!btif_av_source.Enabled()) { + std::vector + codec_priorities; // Default priorities + bta_av_co_init(codec_priorities); + } if (!btif_a2dp_sink_init()) { return BT_STATUS_FAIL; } - btif_enable_service(BTA_A2DP_SINK_SERVICE_ID); enabled_ = true; + btif_enable_service(BTA_A2DP_SINK_SERVICE_ID); return BT_STATUS_SUCCESS; } void BtifAvSink::Cleanup() { LOG_INFO("%s", __PRETTY_FUNCTION__); if (!enabled_) return; + enabled_ = false; btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SINK); @@ -1251,13 +1422,12 @@ void BtifAvSink::Cleanup() { base::BindOnce(base::IgnoreResult(&BtifAvSink::SetActivePeer), base::Unretained(&btif_av_sink), RawAddress::kEmpty, std::move(peer_ready_promise))); - do_in_main_thread(FROM_HERE, base::Bind(&btif_a2dp_sink_cleanup)); + do_in_main_thread(FROM_HERE, base::BindOnce(&btif_a2dp_sink_cleanup)); btif_disable_service(BTA_A2DP_SINK_SERVICE_ID); CleanupAllPeers(); callbacks_ = nullptr; - enabled_ = false; } BtifAvPeer* BtifAvSink::FindPeer(const RawAddress& peer_address) { @@ -1288,8 +1458,8 @@ BtifAvPeer* BtifAvSink::FindPeerByPeerId(uint8_t peer_id) { BtifAvPeer* BtifAvSink::FindOrCreatePeer(const RawAddress& peer_address, tBTA_AV_HNDL bta_handle) { - BTIF_TRACE_DEBUG("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle); + LOG_VERBOSE("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle); BtifAvPeer* peer = FindPeer(peer_address); if (peer != nullptr) return peer; @@ -1297,10 +1467,18 @@ BtifAvPeer* BtifAvSink::FindOrCreatePeer(const RawAddress& peer_address, // Find next availabie Peer ID to use uint8_t peer_id; for (peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) { - if (FindPeerByPeerId(peer_id) == nullptr) break; + /* because the peer id may be in source cb and we cannot use it */ + if (btif_av_both_enable()) { + if (FindPeerByPeerId(peer_id) == nullptr && + btif_av_source.FindPeerByPeerId(peer_id) == nullptr) + break; + + } else { + if (FindPeerByPeerId(peer_id) == nullptr) break; + } } if (peer_id == kPeerIdMax) { - BTIF_TRACE_ERROR( + LOG_ERROR( "%s: Cannot create peer for peer_address=%s : " "cannot allocate unique Peer ID", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -1311,7 +1489,7 @@ BtifAvPeer* BtifAvSink::FindOrCreatePeer(const RawAddress& peer_address, if (bta_handle == kBtaHandleUnknown) { auto it = peer_id2bta_handle_.find(peer_id); if (it == peer_id2bta_handle_.end() || it->second == kBtaHandleUnknown) { - BTIF_TRACE_ERROR( + LOG_ERROR( "%s: Cannot create peer for peer_address=%s : " "cannot convert Peer ID=%d to unique BTA Handle", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), peer_id); @@ -1326,15 +1504,18 @@ BtifAvPeer* BtifAvSink::FindOrCreatePeer(const RawAddress& peer_address, peer = new BtifAvPeer(peer_address, AVDT_TSEP_SRC, bta_handle, peer_id); peers_.insert(std::make_pair(peer_address, peer)); peer->Init(); - if (active_peer_.IsEmpty()) { - active_peer_ = peer_address; - } return peer; } bool BtifAvSink::AllowedToConnect(const RawAddress& peer_address) const { int connected = 0; + if (btif_av_src_sink_coexist_enabled() && invalid_peer_check_) { + LOG_INFO( + "invalid_peer_check_ so allow to connect here, when" + " BTA_AV_OPEN_EVT coming, would check again!"); + return true; + } // Count peers that are in the process of connecting or already connected for (auto it : peers_) { const BtifAvPeer* peer = it.second; @@ -1343,14 +1524,35 @@ bool BtifAvSink::AllowedToConnect(const RawAddress& peer_address) const { case BtifAvStateMachine::kStateOpened: case BtifAvStateMachine::kStateStarted: if (peer->PeerAddress() == peer_address) { + /* we should check if another role is used */ + if (btif_av_both_enable()) break; return true; // Already connected or accounted for } connected++; break; + case BtifAvStateMachine::kStateClosing: + case BtifAvStateMachine::kStateIdle: + if ((btif_a2dp_sink_get_audio_track() != nullptr) && + (peer->PeerAddress() != peer_address)) { + LOG_INFO("%s: there is another peer with audio track(%p), another=%s, peer=%s", + __PRETTY_FUNCTION__, btif_a2dp_sink_get_audio_track(), + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + connected++; + } + break; default: break; } } + if (btif_av_both_enable()) { + LOG_INFO("connected=%d, max_connected_peers_=%d, source_peers=%d", + connected, max_connected_peers_, + (int)btif_av_source.Peers().size()); + /* if source device connected, don't connect sink device */ + return (connected < max_connected_peers_) && btif_av_source.Peers().empty(); + } + return (connected < max_connected_peers_); } @@ -1409,12 +1611,12 @@ void BtifAvSink::BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle) { BtifAvPeer* peer = FindPeerByPeerId(peer_id); if (peer != nullptr && peer->BtaHandle() != bta_handle) { if (peer->BtaHandle() == kBtaHandleUnknown) { - BTIF_TRACE_EVENT( - "%s: Assign peer: peer_address=%s bta_handle=0x%x peer_id=%d", - __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), - bta_handle, peer_id); + LOG_VERBOSE("%s: Assign peer: peer_address=%s bta_handle=0x%x peer_id=%d", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), bta_handle, + peer_id); } else { - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Correct peer: peer_address=%s bta_handle=0x%x->0x%x peer_id=%d", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), peer->BtaHandle(), bta_handle, peer_id); @@ -1423,16 +1625,34 @@ void BtifAvSink::BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle) { } } +BtifAvPeer* BtifAvSink::popPeer(const RawAddress& peer_address) { + auto it = peers_.find(peer_address); + if (it == peers_.end()) return nullptr; + BtifAvPeer* peer = it->second; + peers_.erase(it); + LOG_INFO("%s: peer_address=%s, state=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->StateMachine().StateId()); + return peer; +} + +void BtifAvSink::AddPeer(BtifAvPeer* peer) { + LOG_INFO("%s: peer_address=%s, state=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->StateMachine().StateId()); + peers_.insert(std::make_pair(peer->PeerAddress(), peer)); +} + void BtifAvStateMachine::StateIdle::OnEnter() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); peer_.SetEdr(0); peer_.ClearAllFlags(); // Stop A2DP if this is the active peer if (peer_.IsActivePeer() || peer_.ActivePeerAddress().IsEmpty()) { - btif_a2dp_on_idle(); + btif_a2dp_on_idle(peer_.PeerAddress()); } // Reset the active peer if this was the active peer and @@ -1450,21 +1670,23 @@ void BtifAvStateMachine::StateIdle::OnEnter() { // Delete peers that are re-entering the Idle state if (peer_.IsSink()) { - do_in_main_thread(FROM_HERE, base::Bind(&BtifAvSource::DeleteIdlePeers, - base::Unretained(&btif_av_source))); + do_in_main_thread(FROM_HERE, + base::BindOnce(&BtifAvSource::DeleteIdlePeers, + base::Unretained(&btif_av_source))); } else if (peer_.IsSource()) { - do_in_main_thread(FROM_HERE, base::Bind(&BtifAvSink::DeleteIdlePeers, - base::Unretained(&btif_av_sink))); + do_in_main_thread(FROM_HERE, + base::BindOnce(&BtifAvSink::DeleteIdlePeers, + base::Unretained(&btif_av_sink))); } } void BtifAvStateMachine::StateIdle::OnExit() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); } bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Peer %s : event=%s flags=%s active_peer=%s", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), BtifAvEvent::EventName(event).c_str(), peer_.FlagsToString().c_str(), @@ -1505,7 +1727,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { if (!can_connect) sink_disconnect_src(peer_.PeerAddress()); } if (!can_connect) { - BTIF_TRACE_ERROR( + LOG_ERROR( "%s: Cannot connect to peer %s: too many connected " "peers", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); @@ -1542,35 +1764,58 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { // connection first and then immediately initiate the AV connection // // TODO: We may need to do this only on an AVRCP Play. FixMe - BTIF_TRACE_WARNING("%s: Peer %s : event=%s received without AV", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_WARN("%s: Peer %s : event=%s received without AV", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); bool can_connect = true; // Check whether connection is allowed if (peer_.IsSink()) { can_connect = btif_av_source.AllowedToConnect(peer_.PeerAddress()); - if (!can_connect) src_disconnect_sink(peer_.PeerAddress()); + if (!can_connect) { + if (btif_av_src_sink_coexist_enabled()) + BTA_AvCloseRc(((tBTA_AV*)p_data)->rc_open.rc_handle); + else + src_disconnect_sink(peer_.PeerAddress()); + } } else if (peer_.IsSource()) { can_connect = btif_av_sink.AllowedToConnect(peer_.PeerAddress()); - if (!can_connect) sink_disconnect_src(peer_.PeerAddress()); + if (!can_connect) { + if (btif_av_src_sink_coexist_enabled()) + BTA_AvCloseRc(((tBTA_AV*)p_data)->rc_open.rc_handle); + else + sink_disconnect_src(peer_.PeerAddress()); + } } if (!can_connect) { - BTIF_TRACE_ERROR( + LOG_ERROR( "%s: Cannot connect to peer %s: too many connected " "peers", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); break; } - if (btif_av_source.Enabled()) { - alarm_set_on_mloop( - peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, - btif_av_source_initiate_av_open_timer_timeout, &peer_); - } else if (btif_av_sink.Enabled()) { - alarm_set_on_mloop(peer_.AvOpenOnRcTimer(), - BtifAvPeer::kTimeoutAvOpenOnRcMs, - btif_av_sink_initiate_av_open_timer_timeout, &peer_); + /* if peer is source, then start timer for sink connect to src */ + if (btif_av_src_sink_coexist_enabled()) { + if (peer_.IsSource()) { + alarm_set_on_mloop( + peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, + btif_av_sink_initiate_av_open_timer_timeout, &peer_); + } else { + alarm_set_on_mloop( + peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, + btif_av_source_initiate_av_open_timer_timeout, &peer_); + } + } else { + if (btif_av_source.Enabled()) { + alarm_set_on_mloop( + peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, + btif_av_source_initiate_av_open_timer_timeout, &peer_); + } else if (btif_av_sink.Enabled()) { + alarm_set_on_mloop( + peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, + btif_av_sink_initiate_av_open_timer_timeout, &peer_); + } } if (event == BTA_AV_RC_OPEN_EVT) { btif_rc_handler(event, (tBTA_AV*)p_data); @@ -1610,6 +1855,43 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { if (p_bta_data->open.status == BTA_AV_SUCCESS) { peer_.SetEdr(p_bta_data->open.edr); + if (btif_av_src_sink_coexist_enabled()) { + LOG_VERBOSE("%s: Peer %s sep=%d, open_sep=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + peer_.PeerSep(), p_bta_data->open.sep); + /* if peer is wrong sep type, move it to BtifAvSxxx */ + if (peer_.PeerSep() == AVDT_TSEP_SNK) { + LOG_VERBOSE("set source invalid_peer_check as false"); + btif_av_source.SetInvalidPeerCheck(false); + } else { + LOG_VERBOSE("set sink invalid_peer_check as false"); + btif_av_sink.SetInvalidPeerCheck(false); + } + if (peer_.PeerSep() != p_bta_data->open.sep) { + BtifAvPeer* tmp_peer = nullptr; + if (peer_.PeerSep() == AVDT_TSEP_SNK) { + tmp_peer = btif_av_source.popPeer(peer_.PeerAddress()); + + if (peer_.PeerAddress() != tmp_peer->PeerAddress()) + LOG_ERROR("error, not same peer"); + + btif_av_sink.AddPeer(tmp_peer); + } else { + tmp_peer = btif_av_sink.popPeer(peer_.PeerAddress()); + + if (peer_.PeerAddress() != tmp_peer->PeerAddress()) + LOG_ERROR("error, not same peer"); + + btif_av_source.AddPeer(tmp_peer); + } + peer_.SetSep(p_bta_data->open.sep); + } + if (btif_rc_is_connected_peer(peer_.PeerAddress())) { + LOG_VERBOSE("%s, AVRCP connected, update avrc sep", __func__); + BTA_AvSetPeerSep(peer_.PeerAddress(), peer_.PeerSep()); + } + btif_rc_check_pending_cmd(p_bta_data->open.bd_addr); + } CHECK(peer_.PeerSep() == p_bta_data->open.sep); can_connect = peer_.IsSink() @@ -1617,7 +1899,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { : btif_av_sink.AllowedToConnect(peer_.PeerAddress()); if (!can_connect) { - BTIF_TRACE_ERROR( + LOG_ERROR( "%s: Cannot connect to peer %s: too many connected " "peers", __PRETTY_FUNCTION__, @@ -1671,10 +1953,10 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { case BTIF_AV_AVRCP_CLOSE_EVT: case BTA_AV_RC_CLOSE_EVT: { - BTIF_TRACE_DEBUG("%s: Peer %s : event=%s : Stopping AV timer", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_VERBOSE("%s: Peer %s : event=%s : Stopping AV timer", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); alarm_cancel(peer_.AvOpenOnRcTimer()); if (event == BTA_AV_RC_CLOSE_EVT) { @@ -1683,18 +1965,17 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { } break; case BTIF_AV_OFFLOAD_START_REQ_EVT: - BTIF_TRACE_ERROR("%s: Peer %s : event=%s: stream is not Opened", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_ERROR("%s: Peer %s : event=%s: stream is not Opened", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL); break; default: - BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_WARN("%s: Peer %s : Unhandled event=%s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); return false; } @@ -1702,23 +1983,27 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { } void BtifAvStateMachine::StateOpening::OnEnter() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); // Inform the application that we are entering connecting state + if (btif_av_both_enable()) { + /* if peer connect to us, don't know which role it is */ + if (!peer_.SelfInitiatedConnection()) return; + } btif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_CONNECTING, bt_status_t::BT_STATUS_SUCCESS, BTA_AV_SUCCESS); } void BtifAvStateMachine::StateOpening::OnExit() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); } bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Peer %s : event=%s flags=%s active_peer=%s", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), BtifAvEvent::EventName(event).c_str(), peer_.FlagsToString().c_str(), @@ -1733,7 +2018,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, // ACL Disconnected needs to be handled only in Opening state, because // it is in an intermediate state. In other states we can handle // incoming/outgoing connect/disconnect requests. - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Peer %s : event=%s: transitioning to Idle due to ACL " "Disconnect", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), @@ -1750,10 +2035,10 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, } break; case BTA_AV_REJECT_EVT: - BTIF_TRACE_WARNING("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str(), - peer_.FlagsToString().c_str()); + LOG_WARN("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str(), + peer_.FlagsToString().c_str()); log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum:: A2DP_CONNECTION_REJECT_EVT, 1); @@ -1781,7 +2066,62 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, if (p_bta_data->open.status == BTA_AV_SUCCESS) { av_state = BtifAvStateMachine::kStateOpened; peer_.SetEdr(p_bta_data->open.edr); + if (btif_av_src_sink_coexist_enabled()) { + LOG_VERBOSE("%s: Peer %s sep=%d, open_sep=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + peer_.PeerSep(), p_bta_data->open.sep); + /* if peer is wrong sep type, move it to BtifAvSxxx */ + if (peer_.PeerSep() == AVDT_TSEP_SNK) { + LOG_VERBOSE("set source invalid_peer_check as false"); + btif_av_source.SetInvalidPeerCheck(false); + } else { + LOG_VERBOSE("set sink invalid_peer_check as false"); + btif_av_sink.SetInvalidPeerCheck(false); + } + if (peer_.PeerSep() != p_bta_data->open.sep) { + BtifAvPeer* tmp_peer = nullptr; + if (peer_.PeerSep() == AVDT_TSEP_SNK) { + tmp_peer = btif_av_source.popPeer(peer_.PeerAddress()); + + if (peer_.PeerAddress() != tmp_peer->PeerAddress()) + LOG_ERROR("error, not same peer"); + + btif_av_sink.AddPeer(tmp_peer); + } else { + tmp_peer = btif_av_sink.popPeer(peer_.PeerAddress()); + + if (peer_.PeerAddress() != tmp_peer->PeerAddress()) + LOG_ERROR("error, not same peer"); + + btif_av_source.AddPeer(tmp_peer); + } + peer_.SetSep(p_bta_data->open.sep); + } + if (btif_rc_is_connected_peer(peer_.PeerAddress())) { + LOG_VERBOSE("%s, AVRCP connected, update avrc sep", __func__); + BTA_AvSetPeerSep(peer_.PeerAddress(), peer_.PeerSep()); + } + btif_rc_check_pending_cmd(p_bta_data->open.bd_addr); + } CHECK(peer_.PeerSep() == p_bta_data->open.sep); + /** normally it can be checked in IDLE PENDING/CONNECT_REQ, in case: + * 1 speacker connected to DUT and phone connect DUT, because + * default + * connect req is as SINK peer. only at here, we can know which + * role + * it is.@{ */ + if (btif_av_src_sink_coexist_enabled()) { + bool can_connect = true; + if (peer_.IsSink()) { + can_connect = btif_av_source.AllowedToConnect(peer_.PeerAddress()); + if (!can_connect) src_disconnect_sink(peer_.PeerAddress()); + } else if (peer_.IsSource()) { + can_connect = btif_av_sink.AllowedToConnect(peer_.PeerAddress()); + if (!can_connect) sink_disconnect_src(peer_.PeerAddress()); + } + } + /** @} */ + // Report the connection state to the application btif_report_connection_state( peer_.PeerAddress(), BTAV_CONNECTION_STATE_CONNECTED, @@ -1793,9 +2133,8 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, if (btif_rc_is_connected_peer(peer_.PeerAddress())) { // Disconnect the AVRCP connection, in case the A2DP connectiton // failed for any reason. - BTIF_TRACE_WARNING("%s: Peer %s : Disconnecting AVRCP", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_WARN("%s: Peer %s : Disconnecting AVRCP", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); uint8_t peer_handle = btif_rc_get_connected_peer_handle(peer_.PeerAddress()); if (peer_handle != BTRC_HANDLE_NONE) { @@ -1824,7 +2163,9 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, } else if (peer_.IsSource() && (p_bta_data->open.status == BTA_AV_SUCCESS)) { // Bring up AVRCP connection as well - BTA_AvOpenRc(peer_.BtaHandle()); + if (btif_av_src_sink_coexist_enabled() && + btif_av_sink.AllowedToConnect(peer_.PeerAddress())) + BTA_AvOpenRc(peer_.BtaHandle()); } if (peer_.SelfInitiatedConnection()) { btif_queue_advance(); @@ -1834,6 +2175,13 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, case BTIF_AV_SINK_CONFIG_REQ_EVT: { const btif_av_sink_config_req_t* p_config_req = static_cast(p_data); + /* before this point, we don't know it's role, actually peer is source */ + if (btif_av_both_enable()) { + btif_av_report_sink_audio_config_state(p_config_req->peer_address, + p_config_req->sample_rate, + p_config_req->channel_count); + break; + } if (peer_.IsSource()) { btif_av_report_sink_audio_config_state(p_config_req->peer_address, p_config_req->sample_rate, @@ -1844,7 +2192,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, case BTIF_AV_CONNECT_REQ_EVT: { // The device has moved already to Opening, hence don't report the // connection state. - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Peer %s : event=%s : device is already connecting, " "ignore Connect request", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), @@ -1858,7 +2206,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, case BTA_AV_PENDING_EVT: { // The device has moved already to Opening, hence don't report the // connection state. - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Peer %s : event=%s : device is already connecting, " "ignore incoming request", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), @@ -1869,10 +2217,10 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, } break; case BTIF_AV_OFFLOAD_START_REQ_EVT: - BTIF_TRACE_ERROR("%s: Peer %s : event=%s: stream is not Opened", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_ERROR("%s: Peer %s : event=%s: stream is not Opened", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL); log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum:: A2DP_OFFLOAD_START_REQ_FAILURE, @@ -1916,18 +2264,17 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum:: A2DP_CONNECTION_UNKNOWN_EVENT, 1); - BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_WARN("%s: Peer %s : Unhandled event=%s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); return false; } return true; } void BtifAvStateMachine::StateOpened::OnEnter() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending | BtifAvPeer::kFlagPendingStart | @@ -1942,15 +2289,15 @@ void BtifAvStateMachine::StateOpened::OnEnter() { std::promise peer_ready_promise; if (!btif_av_sink.SetActivePeer(peer_.PeerAddress(), std::move(peer_ready_promise))) { - BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_ERROR("%s: Error setting %s as active Source peer", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); } } } void BtifAvStateMachine::StateOpened::OnExit() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); peer_.ClearFlags(BtifAvPeer::kFlagPendingStart); } @@ -1959,7 +2306,7 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, void* p_data) { tBTA_AV* p_av = (tBTA_AV*)p_data; - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Peer %s : event=%s flags=%s active_peer=%s", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), BtifAvEvent::EventName(event).c_str(), peer_.FlagsToString().c_str(), @@ -1968,9 +2315,9 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, if ((event == BTA_AV_REMOTE_CMD_EVT) && peer_.CheckFlags(BtifAvPeer::kFlagRemoteSuspend) && (p_av->remote_cmd.rc_id == AVRC_ID_PLAY)) { - BTIF_TRACE_EVENT("%s: Peer %s : Resetting remote suspend flag on RC PLAY", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s : Resetting remote suspend flag on RC PLAY", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend); } @@ -2075,9 +2422,9 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, bt_status_t::BT_STATUS_SUCCESS, BTA_AV_SUCCESS); // Change state to Idle, send acknowledgement if start is pending if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) { - BTIF_TRACE_WARNING("%s: Peer %s : failed pending start request", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_WARN("%s: Peer %s : failed pending start request", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); tBTA_AV_START av_start = {.chnl = p_av->close.chnl, .hndl = p_av->close.hndl, .status = BTA_AV_FAIL_STREAM, @@ -2135,26 +2482,25 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, break; case BTIF_AV_CONNECT_REQ_EVT: { - BTIF_TRACE_WARNING("%s: Peer %s : Ignore %s for same device", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_WARN("%s: Peer %s : Ignore %s for same device", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); btif_queue_advance(); } break; case BTIF_AV_OFFLOAD_START_REQ_EVT: - BTIF_TRACE_ERROR("%s: Peer %s : event=%s: stream is not Started", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_ERROR("%s: Peer %s : event=%s: stream is not Started", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL); break; case BTIF_AV_AVRCP_REMOTE_PLAY_EVT: if (peer_.CheckFlags(BtifAvPeer::kFlagRemoteSuspend)) { - BTIF_TRACE_EVENT( - "%s: Peer %s : Resetting remote suspend flag on RC PLAY", - __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s : Resetting remote suspend flag on RC PLAY", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend); } break; @@ -2174,18 +2520,17 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, } break; default: - BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_WARN("%s: Peer %s : Unhandled event=%s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); return false; } return true; } void BtifAvStateMachine::StateStarted::OnEnter() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); // We are again in started state, clear any remote suspend flags peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend); @@ -2198,15 +2543,15 @@ void BtifAvStateMachine::StateStarted::OnEnter() { } void BtifAvStateMachine::StateStarted::OnExit() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); } bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event, void* p_data) { tBTA_AV* p_av = (tBTA_AV*)p_data; - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Peer %s : event=%s flags=%s active_peer=%s", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), BtifAvEvent::EventName(event).c_str(), peer_.FlagsToString().c_str(), @@ -2232,6 +2577,12 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), BtifAvEvent::EventName(event).c_str(), peer_.FlagsToString().c_str()); + + // There is a pending LocalSuspend already, ignore. + if (peer_.CheckFlags(BtifAvPeer::kFlagLocalSuspendPending)) { + break; + } + // Set pending flag to ensure the BTIF task is not trying to restart // the stream while suspend is in progress. peer_.SetFlags(BtifAvPeer::kFlagLocalSuspendPending); @@ -2399,10 +2750,9 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event, CHECK_RC_EVENT(event, (tBTA_AV*)p_data); default: - BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_WARN("%s: Peer %s : Unhandled event=%s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); return false; } @@ -2410,8 +2760,8 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event, } void BtifAvStateMachine::StateClosing::OnEnter() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); if (peer_.IsActivePeer()) { if (peer_.IsSink()) { @@ -2425,13 +2775,13 @@ void BtifAvStateMachine::StateClosing::OnEnter() { } void BtifAvStateMachine::StateClosing::OnExit() { - BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); } bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event, void* p_data) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Peer %s : event=%s flags=%s active_peer=%s", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), BtifAvEvent::EventName(event).c_str(), peer_.FlagsToString().c_str(), @@ -2469,27 +2819,25 @@ bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event, break; case BTIF_AV_OFFLOAD_START_REQ_EVT: - BTIF_TRACE_ERROR("%s: Peer %s : event=%s: stream is not Opened", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_ERROR("%s: Peer %s : event=%s: stream is not Opened", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL); break; case BTIF_AV_CONNECT_REQ_EVT: - BTIF_TRACE_WARNING("%s: Peer %s : Ignore %s in StateClosing", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_WARN("%s: Peer %s : Ignore %s in StateClosing", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); btif_queue_advance(); peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle); break; default: - BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s", - __PRETTY_FUNCTION__, - ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), - BtifAvEvent::EventName(event).c_str()); + LOG_WARN("%s: Peer %s : Unhandled event=%s", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + BtifAvEvent::EventName(event).c_str()); return false; } return true; @@ -2503,21 +2851,21 @@ bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event, static void btif_av_source_initiate_av_open_timer_timeout(void* data) { BtifAvPeer* peer = (BtifAvPeer*)data; - BTIF_TRACE_DEBUG("%s: Peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); // Check if AVRCP is connected to the peer if (!btif_rc_is_connected_peer(peer->PeerAddress())) { - BTIF_TRACE_ERROR("%s: AVRCP peer %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); + LOG_ERROR("%s: AVRCP peer %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); return; } // Connect to the AVRCP peer if (btif_av_source.Enabled() && btif_av_source.FindPeer(peer->PeerAddress()) == peer) { - BTIF_TRACE_DEBUG("%s: Connecting to AVRCP peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); + LOG_VERBOSE("%s: Connecting to AVRCP peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); btif_av_source_dispatch_sm_event(peer->PeerAddress(), BTIF_AV_CONNECT_REQ_EVT); } @@ -2530,21 +2878,21 @@ static void btif_av_source_initiate_av_open_timer_timeout(void* data) { static void btif_av_sink_initiate_av_open_timer_timeout(void* data) { BtifAvPeer* peer = (BtifAvPeer*)data; - BTIF_TRACE_DEBUG("%s: Peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); + LOG_VERBOSE("%s: Peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); // Check if AVRCP is connected to the peer if (!btif_rc_is_connected_peer(peer->PeerAddress())) { - BTIF_TRACE_ERROR("%s: AVRCP peer %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); + LOG_ERROR("%s: AVRCP peer %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); return; } // Connect to the AVRCP peer if (btif_av_sink.Enabled() && btif_av_sink.FindPeer(peer->PeerAddress()) == peer) { - BTIF_TRACE_DEBUG("%s: Connecting to AVRCP peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); + LOG_VERBOSE("%s: Connecting to AVRCP peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress())); btif_av_sink_dispatch_sm_event(peer->PeerAddress(), BTIF_AV_CONNECT_REQ_EVT); } @@ -2562,19 +2910,39 @@ static void btif_report_connection_state(const RawAddress& peer_address, uint8_t error_code) { LOG_INFO("%s: peer_address=%s state=%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), state); + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer == nullptr) { + LOG_ERROR("%s: peer is null", __func__); + return; + } + + if (peer->IsSink()) { + do_in_jni_thread( + FROM_HERE, + base::BindOnce(btif_av_source.Callbacks()->connection_state_cb, + peer_address, state, btav_error_t{})); + } else if (peer->IsSource()) { + do_in_jni_thread( + FROM_HERE, + base::BindOnce(btif_av_sink.Callbacks()->connection_state_cb, + peer_address, state, btav_error_t{})); + } + return; + } if (btif_av_source.Enabled()) { do_in_jni_thread( FROM_HERE, - base::Bind(btif_av_source.Callbacks()->connection_state_cb, - peer_address, state, - btav_error_t{.status = status, .error_code = error_code})); + base::BindOnce( + btif_av_source.Callbacks()->connection_state_cb, peer_address, + state, btav_error_t{.status = status, .error_code = error_code})); } else if (btif_av_sink.Enabled()) { do_in_jni_thread( FROM_HERE, - base::Bind(btif_av_sink.Callbacks()->connection_state_cb, peer_address, - state, - btav_error_t{.status = status, .error_code = error_code})); + base::BindOnce( + btif_av_sink.Callbacks()->connection_state_cb, peer_address, state, + btav_error_t{.status = status, .error_code = error_code})); } } @@ -2592,14 +2960,27 @@ static void btif_report_audio_state(const RawAddress& peer_address, LOG_INFO("%s: peer_address=%s state=%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), state); + if (btif_av_both_enable()) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer->IsSink()) { + do_in_jni_thread( + FROM_HERE, base::BindOnce(btif_av_source.Callbacks()->audio_state_cb, + peer_address, state)); + } else if (peer->IsSource()) { + do_in_jni_thread(FROM_HERE, + base::BindOnce(btif_av_sink.Callbacks()->audio_state_cb, + peer_address, state)); + } + return; + } if (btif_av_source.Enabled()) { do_in_jni_thread(FROM_HERE, - base::Bind(btif_av_source.Callbacks()->audio_state_cb, - peer_address, state)); + base::BindOnce(btif_av_source.Callbacks()->audio_state_cb, + peer_address, state)); } else if (btif_av_sink.Enabled()) { do_in_jni_thread(FROM_HERE, - base::Bind(btif_av_sink.Callbacks()->audio_state_cb, - peer_address, state)); + base::BindOnce(btif_av_sink.Callbacks()->audio_state_cb, + peer_address, state)); } using android::bluetooth::a2dp::AudioCodingModeEnum; @@ -2629,14 +3010,14 @@ void btif_av_report_source_codec_state( const std::vector& codecs_local_capabilities, const std::vector& codecs_selectable_capabilities) { - BTIF_TRACE_EVENT("%s: peer_address=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_VERBOSE("%s: peer_address=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); if (btif_av_source.Enabled()) { do_in_jni_thread( FROM_HERE, - base::Bind(btif_av_source.Callbacks()->audio_config_cb, peer_address, - codec_config, codecs_local_capabilities, - codecs_selectable_capabilities)); + base::BindOnce(btif_av_source.Callbacks()->audio_config_cb, + peer_address, codec_config, codecs_local_capabilities, + codecs_selectable_capabilities)); } } @@ -2653,8 +3034,8 @@ static void btif_av_report_sink_audio_config_state( ADDRESS_TO_LOGGABLE_CSTR(peer_address), sample_rate, channel_count); if (btif_av_sink.Enabled()) { do_in_jni_thread(FROM_HERE, - base::Bind(btif_av_sink.Callbacks()->audio_config_cb, - peer_address, sample_rate, channel_count)); + base::BindOnce(btif_av_sink.Callbacks()->audio_config_cb, + peer_address, sample_rate, channel_count)); } } @@ -2678,8 +3059,7 @@ static void btif_av_query_mandatory_codec_priority( auto apply_priority = [](const RawAddress& peer_address, bool preferred) { BtifAvPeer* peer = btif_av_find_peer(peer_address); if (peer == nullptr) { - BTIF_TRACE_WARNING( - "btif_av_query_mandatory_codec_priority: peer is null"); + LOG_WARN("btif_av_query_mandatory_codec_priority: peer is null"); return; } peer->SetMandatoryCodecPreferred(preferred); @@ -2693,6 +3073,82 @@ static void btif_av_query_mandatory_codec_priority( } } +static BtifAvPeer* btif_av_handle_both_peer(uint8_t peer_sep, + const RawAddress& peer_address, + tBTA_AV_HNDL bta_handle) { + BtifAvPeer* peer = nullptr; + + if (peer_address != RawAddress::kEmpty) { + if (btif_av_both_enable()) { + peer = btif_av_find_peer(peer_address); + /* if no this peer, default it's sink device */ + if (peer == nullptr) { + if (peer_sep == AVDT_TSEP_SRC) { + LOG_VERBOSE("%s: peer_sep(%d), create a new source peer", __func__, + peer_sep); + peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); + } else if (peer_sep == AVDT_TSEP_SNK) { + LOG_VERBOSE("%s: peer_sep(%d), create a new sink peer", __func__, + peer_sep); + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } else { + btif_av_source.SetInvalidPeerCheck(true); + if (!btif_av_source.Peers().empty()) { + LOG_VERBOSE( + "%s: peer_sep invalid, and already has sink peer," + " so try create a new sink peer", + __func__); + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } else if (!btif_av_sink.Peers().empty()) { + LOG_VERBOSE( + "%s: peer_sep invalid, and already has source peer," + " so try create a new source peer", + __func__); + peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); + } else { + LOG_VERBOSE( + "%s: peer_sep invalid, and no active peer," + " so try create a new sink peer", + __func__); + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } + } + } + } else { + if (peer_sep == AVDT_TSEP_SNK) { + LOG_VERBOSE("%s: peer_sep(%d), only init src create a new source peer", + __func__, peer_sep); + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + LOG_VERBOSE("%s: peer_sep(%d), only init sink create a new source peer", + __func__, peer_sep); + peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); + } + } + if (peer == NULL && bta_handle != 0) { + if (peer_sep == AVDT_TSEP_SNK) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } + LOG_VERBOSE("%s:peer is check 3", __func__); + } + } else if (bta_handle != 0) { + if (peer_sep == AVDT_TSEP_INVALID) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + /* if no this peer, default it's sink device */ + if (peer == nullptr) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } + } else if (peer_sep == AVDT_TSEP_SNK) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } + } + return peer; +} + /** * Process BTIF or BTA AV or BTA AVRCP events. The processing is done on the * JNI thread. @@ -2714,17 +3170,21 @@ static void btif_av_handle_event(uint8_t peer_sep, BtifAvPeer* peer = nullptr; // Find the peer - if (peer_address != RawAddress::kEmpty) { - if (peer_sep == AVDT_TSEP_SNK) { - peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); - } else if (peer_sep == AVDT_TSEP_SRC) { - peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); - } - } else if (bta_handle != kBtaHandleUnknown) { - if (peer_sep == AVDT_TSEP_SNK) { - peer = btif_av_source.FindPeerByHandle(bta_handle); - } else if (peer_sep == AVDT_TSEP_SRC) { - peer = btif_av_sink.FindPeerByHandle(bta_handle); + if (btif_av_src_sink_coexist_enabled()) { + peer = btif_av_handle_both_peer(peer_sep, peer_address, bta_handle); + } else { + if (peer_address != RawAddress::kEmpty) { + if (peer_sep == AVDT_TSEP_SNK) { + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); + } + } else if (bta_handle != kBtaHandleUnknown) { + if (peer_sep == AVDT_TSEP_SNK) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } } } if (peer == nullptr) { @@ -2769,11 +3229,18 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep, return; // Nothing to do } case BTA_AV_REGISTER_EVT: { - const tBTA_AV_REGISTER& registr = p_data->registr; - bta_handle = registr.hndl; - uint8_t peer_id = registr.app_id; // The PeerId is used as AppId - LOG_DEBUG("Register bta_handle=0x%x app_id=%d", bta_handle, - registr.app_id); + const tBTA_AV_REGISTER& reg = p_data->reg; + bta_handle = reg.hndl; + uint8_t peer_id = reg.app_id; // The PeerId is used as AppId + LOG_DEBUG("Register bta_handle=0x%x app_id=%d", bta_handle, reg.app_id); + if (btif_av_src_sink_coexist_enabled()) { + if (peer_sep == AVDT_TSEP_INVALID) { + if (reg.peer_sep == AVDT_TSEP_SNK) + peer_sep = AVDT_TSEP_SNK; + else + peer_sep = AVDT_TSEP_SRC; + } + } if (peer_sep == AVDT_TSEP_SNK) { btif_av_source.BtaHandleRegistered(peer_id, bta_handle); } else if (peer_sep == AVDT_TSEP_SRC) { @@ -2841,7 +3308,26 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep, case BTA_AV_REMOTE_RSP_EVT: case BTA_AV_VENDOR_CMD_EVT: case BTA_AV_VENDOR_RSP_EVT: - case BTA_AV_META_MSG_EVT: + case BTA_AV_META_MSG_EVT: { + if (btif_av_src_sink_coexist_enabled()) { + if (peer_sep == AVDT_TSEP_INVALID) { + const tBTA_AV_REMOTE_CMD& rc_rmt_cmd = p_data->remote_cmd; + btif_rc_get_addr_by_handle(rc_rmt_cmd.rc_handle, peer_address); + if (peer_address == RawAddress::kEmpty) { + peer_address = btif_av_source.ActivePeer(); + if (peer_address == RawAddress::kEmpty) { + peer_address = btif_av_sink.ActivePeer(); + } + } + } else if (peer_sep == AVDT_TSEP_SNK) { + peer_address = btif_av_source.ActivePeer(); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer_address = btif_av_sink.ActivePeer(); + } + break; + } else + FALLTHROUGH_INTENDED; + } case BTA_AV_OFFLOAD_START_RSP_EVT: { // TODO: Might be wrong - this code will be removed once those // events are received from the AVRCP module. @@ -2889,27 +3375,52 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep, btif_av_handle_event(peer_sep, peer_address, bta_handle, btif_av_event); } +bool btif_av_both_enable(void) { + return (btif_av_sink.Enabled() && btif_av_source.Enabled()); +} + +bool btif_av_src_sink_coexist_enabled(void) { + return GET_SYSPROP(A2dp, src_sink_coexist, false); +} + static void bta_av_source_callback(tBTA_AV_EVT event, tBTA_AV* p_data) { BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV)); - BTIF_TRACE_EVENT("%s: event=%s", __func__, btif_av_event.ToString().c_str()); + LOG_VERBOSE("%s: event=%s", __func__, btif_av_event.ToString().c_str()); - do_in_main_thread(FROM_HERE, - base::Bind(&btif_av_handle_bta_av_event, - AVDT_TSEP_SNK /* peer_sep */, btif_av_event)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&btif_av_handle_bta_av_event, + AVDT_TSEP_SNK /* peer_sep */, btif_av_event)); } static void bta_av_sink_callback(tBTA_AV_EVT event, tBTA_AV* p_data) { BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV)); - do_in_main_thread(FROM_HERE, - base::Bind(&btif_av_handle_bta_av_event, - AVDT_TSEP_SRC /* peer_sep */, btif_av_event)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&btif_av_handle_bta_av_event, + AVDT_TSEP_SRC /* peer_sep */, btif_av_event)); +} + +static void bta_av_event_callback(tBTA_AV_EVT event, tBTA_AV* p_data) { + if (btif_av_both_enable()) { + BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV)); + do_in_main_thread( + FROM_HERE, + base::BindOnce(&btif_av_handle_bta_av_event, + AVDT_TSEP_INVALID /* peer_sep */, btif_av_event)); + return; + } + + if (btif_av_is_sink_enabled()) { + return bta_av_sink_callback(event, p_data); + } + + return bta_av_source_callback(event, p_data); } // TODO: All processing should be done on the JNI thread static void bta_av_sink_media_callback(const RawAddress& peer_address, tBTA_AV_EVT event, tBTA_AV_MEDIA* p_data) { - BTIF_TRACE_EVENT("%s: event=%d", __func__, event); + LOG_VERBOSE("%s: event=%d", __func__, event); switch (event) { case BTA_AV_SINK_MEDIA_DATA_EVT: { @@ -2919,7 +3430,7 @@ static void bta_av_sink_media_callback(const RawAddress& peer_address, if ((state == BtifAvStateMachine::kStateStarted) || (state == BtifAvStateMachine::kStateOpened)) { uint8_t queue_len = btif_a2dp_sink_enqueue_buf((BT_HDR*)p_data); - BTIF_TRACE_DEBUG("%s: Packets in Sink queue %d", __func__, queue_len); + LOG_VERBOSE("%s: Packets in Sink queue %d", __func__, queue_len); } } break; @@ -2927,8 +3438,8 @@ static void bta_av_sink_media_callback(const RawAddress& peer_address, case BTA_AV_SINK_MEDIA_CFG_EVT: { btif_av_sink_config_req_t config_req; - BTIF_TRACE_EVENT("%s: address=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_data->avk_config.bd_addr)); + LOG_VERBOSE("%s: address=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_data->avk_config.bd_addr)); // Update the codec info of the A2DP Sink decoder btif_a2dp_sink_update_decoder((uint8_t*)(p_data->avk_config.codec_info)); @@ -2936,23 +3447,23 @@ static void bta_av_sink_media_callback(const RawAddress& peer_address, config_req.sample_rate = A2DP_GetTrackSampleRate(p_data->avk_config.codec_info); if (config_req.sample_rate == -1) { - APPL_TRACE_ERROR("%s: Cannot get the track frequency", __func__); + LOG_ERROR("%s: Cannot get the track frequency", __func__); break; } config_req.channel_count = A2DP_GetTrackChannelCount(p_data->avk_config.codec_info); if (config_req.channel_count == -1) { - APPL_TRACE_ERROR("%s: Cannot get the channel count", __func__); + LOG_ERROR("%s: Cannot get the channel count", __func__); break; } config_req.peer_address = p_data->avk_config.bd_addr; BtifAvEvent btif_av_event(BTIF_AV_SINK_CONFIG_REQ_EVT, &config_req, sizeof(config_req)); - do_in_main_thread(FROM_HERE, - base::Bind(&btif_av_handle_event, - AVDT_TSEP_SRC, // peer_sep - config_req.peer_address, kBtaHandleUnknown, - btif_av_event)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&btif_av_handle_event, + AVDT_TSEP_SRC, // peer_sep + config_req.peer_address, kBtaHandleUnknown, + btif_av_event)); break; } default: @@ -2965,7 +3476,7 @@ static bt_status_t init_src( btav_source_callbacks_t* callbacks, int max_connected_audio_devices, const std::vector& codec_priorities, const std::vector& offloading_preference) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); return btif_av_source.Init(callbacks, max_connected_audio_devices, codec_priorities, offloading_preference); } @@ -2973,26 +3484,35 @@ static bt_status_t init_src( // Initializes the AV interface for sink mode static bt_status_t init_sink(btav_sink_callbacks_t* callbacks, int max_connected_audio_devices) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); return btif_av_sink.Init(callbacks, max_connected_audio_devices); } // Updates the final focus state reported by components calling this module static void update_audio_focus_state(int state) { - BTIF_TRACE_DEBUG("%s: state=%d", __func__, state); + LOG_VERBOSE("%s: state=%d", __func__, state); btif_a2dp_sink_set_focus_state_req((btif_a2dp_sink_focus_state_t)state); } // Updates the track gain (used for ducking). static void update_audio_track_gain(float gain) { - BTIF_TRACE_DEBUG("%s: gain=%f", __func__, gain); + LOG_VERBOSE("%s: gain=%f", __func__, gain); btif_a2dp_sink_set_audio_track_gain(gain); } // Establishes the AV signalling channel with the remote headset static bt_status_t connect_int(RawAddress* peer_address, uint16_t uuid) { - BTIF_TRACE_EVENT("%s: peer_address=%s uuid=0x%x", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*peer_address), uuid); + LOG_VERBOSE("%s: peer_address=%s uuid=0x%x", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*peer_address), uuid); + if (btif_av_both_enable()) { + const RawAddress tmp = *peer_address; + if (uuid == UUID_SERVCLASS_AUDIO_SOURCE) { + btif_av_source_dispatch_sm_event(tmp, BTIF_AV_CONNECT_REQ_EVT); + } else if (uuid == UUID_SERVCLASS_AUDIO_SINK) { + btif_av_sink_dispatch_sm_event(tmp, BTIF_AV_CONNECT_REQ_EVT); + } + return BT_STATUS_SUCCESS; + } auto connection_task = [](RawAddress* peer_address, uint16_t uuid) { BtifAvPeer* peer = nullptr; @@ -3017,12 +3537,12 @@ static bt_status_t connect_int(RawAddress* peer_address, uint16_t uuid) { static void set_source_silence_peer_int(const RawAddress& peer_address, bool silence) { - BTIF_TRACE_EVENT("%s: peer_address=%s, silence=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), - silence ? "true" : "false"); + LOG_VERBOSE("%s: peer_address=%s, silence=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), + silence ? "true" : "false"); if (!btif_av_source.SetSilencePeer(peer_address, silence)) { - BTIF_TRACE_ERROR("%s: Error setting silence state to %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_ERROR("%s: Error setting silence state to %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); } } @@ -3030,31 +3550,36 @@ static void set_source_silence_peer_int(const RawAddress& peer_address, static void set_active_peer_int(uint8_t peer_sep, const RawAddress& peer_address, std::promise peer_ready_promise) { - BTIF_TRACE_EVENT("%s: peer_sep=%s (%d) peer_address=%s", __func__, - (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_VERBOSE("%s: peer_sep=%s (%d) peer_address=%s", __func__, + (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); BtifAvPeer* peer = nullptr; if (peer_sep == AVDT_TSEP_SNK) { - if (!btif_av_source.SetActivePeer(peer_address, - std::move(peer_ready_promise))) { - BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + if (!btif_av_src_sink_coexist_enabled() || (btif_av_src_sink_coexist_enabled() && + btif_av_both_enable() && (btif_av_sink.FindPeer(peer_address) == nullptr))) { + btif_av_source.SetActivePeer(peer_address, + std::move(peer_ready_promise)); + LOG_ERROR("%s: Error setting %s as active Sink peer", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); } return; } if (peer_sep == AVDT_TSEP_SRC) { - if (!btif_av_sink.SetActivePeer(peer_address, - std::move(peer_ready_promise))) { - BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + if (!btif_av_src_sink_coexist_enabled() || (btif_av_src_sink_coexist_enabled() && + btif_av_both_enable() && (btif_av_source.FindPeer(peer_address) == nullptr))) { + if (!btif_av_sink.SetActivePeer(peer_address, + std::move(peer_ready_promise))) { + LOG_ERROR("%s: Error setting %s as active Source peer", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + } } return; } // If reached here, we could not set the active peer - BTIF_TRACE_ERROR("%s: Cannot set active %s peer to %s: peer not %s", __func__, - (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", - ADDRESS_TO_LOGGABLE_CSTR(peer_address), - (peer == nullptr) ? "found" : "connected"); + LOG_ERROR("%s: Cannot set active %s peer to %s: peer not %s", __func__, + (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", + ADDRESS_TO_LOGGABLE_CSTR(peer_address), + (peer == nullptr) ? "found" : "connected"); peer_ready_promise.set_value(); } @@ -3076,7 +3601,7 @@ static bt_status_t sink_connect_src(const RawAddress& peer_address) { LOG_INFO("%s: Peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); if (!btif_av_sink.Enabled()) { - BTIF_TRACE_WARNING("%s: BTIF AV Sink is not enabled", __func__); + LOG_WARN("%s: BTIF AV Sink is not enabled", __func__); return BT_STATUS_NOT_READY; } @@ -3089,37 +3614,38 @@ static bt_status_t src_disconnect_sink(const RawAddress& peer_address) { LOG_INFO("%s: Peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); if (!btif_av_source.Enabled()) { - BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__); + LOG_WARN("%s: BTIF AV Source is not enabled", __func__); return BT_STATUS_NOT_READY; } BtifAvEvent btif_av_event(BTIF_AV_DISCONNECT_REQ_EVT, &peer_address, sizeof(peer_address)); return do_in_main_thread( - FROM_HERE, base::Bind(&btif_av_handle_event, - AVDT_TSEP_SNK, // peer_sep - peer_address, kBtaHandleUnknown, btif_av_event)); + FROM_HERE, + base::BindOnce(&btif_av_handle_event, + AVDT_TSEP_SNK, // peer_sep + peer_address, kBtaHandleUnknown, btif_av_event)); } static bt_status_t sink_disconnect_src(const RawAddress& peer_address) { LOG_INFO("%s: Peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); if (!btif_av_sink.Enabled()) { - BTIF_TRACE_WARNING("%s: BTIF AV Sink is not enabled", __func__); + LOG_WARN("%s: BTIF AV Sink is not enabled", __func__); return BT_STATUS_NOT_READY; } BtifAvEvent btif_av_event(BTIF_AV_DISCONNECT_REQ_EVT, &peer_address, sizeof(peer_address)); return do_in_main_thread( - FROM_HERE, base::Bind(&btif_av_handle_event, - AVDT_TSEP_SRC, // peer_sep - peer_address, kBtaHandleUnknown, btif_av_event)); + FROM_HERE, + base::BindOnce(&btif_av_handle_event, + AVDT_TSEP_SRC, // peer_sep + peer_address, kBtaHandleUnknown, btif_av_event)); } static bt_status_t sink_set_active_device(const RawAddress& peer_address) { - BTIF_TRACE_EVENT("%s: Peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_VERBOSE("%s: Peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); if (!btif_av_sink.Enabled()) { LOG(WARNING) << __func__ << ": BTIF AV Source is not enabled"; @@ -3142,20 +3668,19 @@ static bt_status_t sink_set_active_device(const RawAddress& peer_address) { static bt_status_t src_set_silence_sink(const RawAddress& peer_address, bool silence) { - BTIF_TRACE_EVENT("%s: Peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_VERBOSE("%s: Peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); if (!btif_av_source.Enabled()) { - BTIF_TRACE_WARNING("%s: BTIF AV Source is not enabled", __func__); + LOG_WARN("%s: BTIF AV Source is not enabled", __func__); return BT_STATUS_NOT_READY; } - return do_in_main_thread(FROM_HERE, base::Bind(&set_source_silence_peer_int, - peer_address, silence)); + return do_in_main_thread( + FROM_HERE, + base::BindOnce(&set_source_silence_peer_int, peer_address, silence)); } static bt_status_t src_set_active_sink(const RawAddress& peer_address) { - BTIF_TRACE_EVENT("%s: Peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_VERBOSE("%s: Peer %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); if (!btif_av_source.Enabled()) { LOG(WARNING) << __func__ << ": BTIF AV Source is not enabled"; @@ -3179,7 +3704,7 @@ static bt_status_t src_set_active_sink(const RawAddress& peer_address) { static bt_status_t codec_config_src( const RawAddress& peer_address, std::vector codec_preferences) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!btif_av_source.Enabled()) { LOG(WARNING) << __func__ << ": BTIF AV Source is not enabled"; @@ -3207,15 +3732,16 @@ static bt_status_t codec_config_src( } static void cleanup_src(void) { - BTIF_TRACE_EVENT("%s", __func__); - do_in_main_thread(FROM_HERE, base::Bind(&BtifAvSource::Cleanup, - base::Unretained(&btif_av_source))); + LOG_VERBOSE("%s", __func__); + do_in_main_thread(FROM_HERE, + base::BindOnce(&BtifAvSource::Cleanup, + base::Unretained(&btif_av_source))); } static void cleanup_sink(void) { - BTIF_TRACE_EVENT("%s", __func__); - do_in_main_thread(FROM_HERE, base::Bind(&BtifAvSink::Cleanup, - base::Unretained(&btif_av_sink))); + LOG_VERBOSE("%s", __func__); + do_in_main_thread(FROM_HERE, base::BindOnce(&BtifAvSink::Cleanup, + base::Unretained(&btif_av_sink))); } static const btav_source_interface_t bt_av_src_interface = { @@ -3246,6 +3772,8 @@ RawAddress btif_av_sink_active_peer(void) { return btif_av_sink.ActivePeer(); } bool btif_av_is_sink_enabled(void) { return btif_av_sink.Enabled(); } +bool btif_av_is_source_enabled(void) { return btif_av_source.Enabled(); } + void btif_av_stream_start(void) { LOG_INFO("%s", __func__); btif_av_source_dispatch_sm_event(btif_av_source_active_peer(), @@ -3264,10 +3792,11 @@ void btif_av_stream_start_with_latency(bool use_latency_mode) { btif_av_event.ToString().c_str(), use_latency_mode ? "true" : "false"); - do_in_main_thread(FROM_HERE, base::Bind(&btif_av_handle_event, - AVDT_TSEP_SNK, // peer_sep - btif_av_source_active_peer(), - kBtaHandleUnknown, btif_av_event)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&btif_av_handle_event, + AVDT_TSEP_SNK, // peer_sep + btif_av_source_active_peer(), kBtaHandleUnknown, + btif_av_event)); } void src_do_suspend_in_main_thread(btif_av_sm_event_t event) { @@ -3288,7 +3817,7 @@ void src_do_suspend_in_main_thread(btif_av_sm_event_t event) { } }; // switch to main thread to prevent a race condition of accessing peers - do_in_main_thread(FROM_HERE, base::Bind(src_do_stream_suspend, event)); + do_in_main_thread(FROM_HERE, base::BindOnce(src_do_stream_suspend, event)); } void btif_av_stream_stop(const RawAddress& peer_address) { @@ -3325,13 +3854,13 @@ void btif_av_src_disconnect_sink(const RawAddress& peer_address) { bool btif_av_stream_ready(void) { // Make sure the main adapter is enabled if (btif_is_enabled() == 0) { - BTIF_TRACE_EVENT("%s: Main adapter is not enabled", __func__); + LOG_VERBOSE("%s: Main adapter is not enabled", __func__); return false; } BtifAvPeer* peer = btif_av_find_active_peer(); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: No active peer found", __func__); + LOG_WARN("%s: No active peer found", __func__); return false; } @@ -3351,7 +3880,7 @@ bool btif_av_stream_ready(void) { bool btif_av_stream_started_ready(void) { BtifAvPeer* peer = btif_av_find_active_peer(); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: No active peer found", __func__); + LOG_WARN("%s: No active peer found", __func__); return false; } @@ -3375,32 +3904,32 @@ bool btif_av_stream_started_ready(void) { static void btif_av_source_dispatch_sm_event(const RawAddress& peer_address, btif_av_sm_event_t event) { BtifAvEvent btif_av_event(event, nullptr, 0); - BTIF_TRACE_EVENT("%s: peer_address=%s event=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), - btif_av_event.ToString().c_str()); - - do_in_main_thread(FROM_HERE, - base::Bind(&btif_av_handle_event, - AVDT_TSEP_SNK, // peer_sep - peer_address, kBtaHandleUnknown, btif_av_event)); + LOG_VERBOSE("%s: peer_address=%s event=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), + btif_av_event.ToString().c_str()); + + do_in_main_thread(FROM_HERE, base::BindOnce(&btif_av_handle_event, + AVDT_TSEP_SNK, // peer_sep + peer_address, kBtaHandleUnknown, + btif_av_event)); } static void btif_av_sink_dispatch_sm_event(const RawAddress& peer_address, btif_av_sm_event_t event) { BtifAvEvent btif_av_event(event, nullptr, 0); - BTIF_TRACE_EVENT("%s: peer_address=%s event=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), - btif_av_event.ToString().c_str()); - - do_in_main_thread(FROM_HERE, - base::Bind(&btif_av_handle_event, - AVDT_TSEP_SRC, // peer_sep - peer_address, kBtaHandleUnknown, btif_av_event)); + LOG_VERBOSE("%s: peer_address=%s event=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), + btif_av_event.ToString().c_str()); + + do_in_main_thread(FROM_HERE, base::BindOnce(&btif_av_handle_event, + AVDT_TSEP_SRC, // peer_sep + peer_address, kBtaHandleUnknown, + btif_av_event)); } bt_status_t btif_av_source_execute_service(bool enable) { - BTIF_TRACE_EVENT("%s: Source service: %s", __func__, - (enable) ? "enable" : "disable"); + LOG_VERBOSE("%s: Source service: %s", __func__, + (enable) ? "enable" : "disable"); if (enable) { // Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not @@ -3419,7 +3948,12 @@ bt_status_t btif_av_source_execute_service(bool enable) { features |= BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_BROWSE; } - BTA_AvEnable(features, bta_av_source_callback); + if (btif_av_src_sink_coexist_enabled()) { + features |= BTA_AV_FEAT_SRC; + BTA_AvEnable(features, bta_av_event_callback); + } else { + BTA_AvEnable(features, bta_av_source_callback); + } btif_av_source.RegisterAllBtaHandles(); return BT_STATUS_SUCCESS; } @@ -3431,8 +3965,8 @@ bt_status_t btif_av_source_execute_service(bool enable) { } bt_status_t btif_av_sink_execute_service(bool enable) { - BTIF_TRACE_EVENT("%s: Sink service: %s", __func__, - (enable) ? "enable" : "disable"); + LOG_VERBOSE("%s: Sink service: %s", __func__, + (enable) ? "enable" : "disable"); if (enable) { // Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not @@ -3447,7 +3981,10 @@ bt_status_t btif_av_sink_execute_service(bool enable) { features |= BTA_AV_FEAT_DELAY_RPT; } - BTA_AvEnable(features, bta_av_sink_callback); + if (btif_av_src_sink_coexist_enabled()) + BTA_AvEnable(features, bta_av_event_callback); + else + BTA_AvEnable(features, bta_av_sink_callback); btif_av_sink.RegisterAllBtaHandles(); return BT_STATUS_SUCCESS; } @@ -3460,27 +3997,27 @@ bt_status_t btif_av_sink_execute_service(bool enable) { // Get the AV callback interface for A2DP source profile const btav_source_interface_t* btif_av_get_src_interface(void) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); return &bt_av_src_interface; } // Get the AV callback interface for A2DP sink profile const btav_sink_interface_t* btif_av_get_sink_interface(void) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); return &bt_av_sink_interface; } bool btif_av_is_connected(void) { BtifAvPeer* peer = btif_av_find_active_peer(); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: No active peer found", __func__); + LOG_WARN("%s: No active peer found", __func__); return false; } bool connected = peer->IsConnected(); - BTIF_TRACE_DEBUG("%s: Peer %s is %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), - (connected) ? "connected" : "not connected"); + LOG_VERBOSE("%s: Peer %s is %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (connected) ? "connected" : "not connected"); return connected; } @@ -3492,9 +4029,9 @@ uint8_t btif_av_get_peer_sep(void) { } uint8_t peer_sep = peer->PeerSep(); - LOG_INFO("Peer %s SEP is %s (%d)", - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), - (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep); + LOG_VERBOSE("Peer %s SEP is %s (%d)", + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep); return peer_sep; } @@ -3502,58 +4039,57 @@ void btif_av_clear_remote_suspend_flag(void) { auto clear_remote_suspend_flag = []() { BtifAvPeer* peer = btif_av_find_active_peer(); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: No active peer found", __func__); + LOG_WARN("%s: No active peer found", __func__); return; } - BTIF_TRACE_DEBUG("%s: Peer %s : flags=%s are cleared", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), - peer->FlagsToString().c_str()); + LOG_VERBOSE("%s: Peer %s : flags=%s are cleared", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->FlagsToString().c_str()); peer->ClearFlags(BtifAvPeer::kFlagRemoteSuspend); }; // switch to main thread to prevent a race condition of accessing peers - do_in_main_thread(FROM_HERE, base::Bind(clear_remote_suspend_flag)); + do_in_main_thread(FROM_HERE, base::BindOnce(clear_remote_suspend_flag)); } bool btif_av_is_peer_edr(const RawAddress& peer_address) { BtifAvPeer* peer = btif_av_find_peer(peer_address); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: No peer found for peer_address=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_WARN("%s: No peer found for peer_address=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return false; } if (!peer->IsConnected()) { - BTIF_TRACE_WARNING("%s: Peer %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_WARN("%s: Peer %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return false; } bool is_edr = peer->IsEdr(); - BTIF_TRACE_DEBUG("%s: Peer %s : is_edr=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), is_edr); + LOG_VERBOSE("%s: Peer %s : is_edr=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), is_edr); return is_edr; } bool btif_av_peer_supports_3mbps(const RawAddress& peer_address) { BtifAvPeer* peer = btif_av_find_peer(peer_address); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: No peer found for peer_address=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_WARN("%s: No peer found for peer_address=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return false; } bool is3mbps = peer->Is3Mbps(); bool is_connected = peer->IsConnected(); - BTIF_TRACE_DEBUG("%s: Peer %s : connected=%d, edr_3mbps=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address), is_connected, - is3mbps); + LOG_VERBOSE("%s: Peer %s : connected=%d, edr_3mbps=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address), is_connected, is3mbps); return (is_connected && is3mbps); } bool btif_av_peer_prefers_mandatory_codec(const RawAddress& peer_address) { BtifAvPeer* peer = btif_av_find_peer(peer_address); if (peer == nullptr) { - BTIF_TRACE_WARNING("%s: No peer found for peer_address=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + LOG_WARN("%s: No peer found for peer_address=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer_address)); return false; } return peer->IsMandatoryCodecPreferred(); @@ -3563,6 +4099,18 @@ void btif_av_acl_disconnected(const RawAddress& peer_address) { // Inform the application that ACL is disconnected and move to idle state LOG_INFO("%s: Peer %s : ACL Disconnected", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + if (btif_av_both_enable()) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer != nullptr) { + if (peer->IsSource()) { + btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_ACL_DISCONNECTED); + } else { + btif_av_source_dispatch_sm_event(peer_address, + BTIF_AV_ACL_DISCONNECTED); + } + } + return; + } if (btif_av_source.Enabled()) { btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_ACL_DISCONNECTED); @@ -3704,8 +4252,79 @@ void btif_av_set_low_latency(bool is_low_latency) { LOG_INFO("peer_address=%s event=%s", ADDRESS_TO_LOGGABLE_CSTR(btif_av_source_active_peer()), btif_av_event.ToString().c_str()); - do_in_main_thread(FROM_HERE, base::Bind(&btif_av_handle_event, - AVDT_TSEP_SNK, // peer_sep - btif_av_source_active_peer(), - kBtaHandleUnknown, btif_av_event)); + do_in_main_thread( + FROM_HERE, base::BindOnce(&btif_av_handle_event, + AVDT_TSEP_SNK, // peer_sep + btif_av_source_active_peer(), kBtaHandleUnknown, + btif_av_event)); +} + +static void btif_av_sink_delete_active_peer(void) { + btif_av_sink.DeleteActivePeer(); +} + +static void btif_av_source_delete_active_peer(void) { + btif_av_source.DeleteActivePeer(); +} + +bool btif_av_is_connected_addr(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer == nullptr) { + LOG_WARN("%s: No active peer found", __func__); + return false; + } + + bool connected = peer->IsConnected(); + LOG_VERBOSE("%s: Peer %s is %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (connected) ? "connected" : "not connected"); + return connected; +} + +bool btif_av_peer_is_connected_sink(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_source_find_peer(peer_address); + if (peer == nullptr) { + LOG_WARN("%s: No active peer found", __func__); + return false; + } + + bool connected = peer->IsConnected(); + LOG_VERBOSE("%s: Peer %s is %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (connected) ? "connected" : "not connected"); + return connected; +} + +bool btif_av_peer_is_connected_source(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_sink_find_peer(peer_address); + if (peer == nullptr) { + LOG_WARN("%s: No active peer found", __func__); + return false; + } + + bool connected = peer->IsConnected(); + LOG_VERBOSE("%s: Peer %s is %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (connected) ? "connected" : "not connected"); + return connected; +} + +bool btif_av_peer_is_sink(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_source_find_peer(peer_address); + if (peer == nullptr) { + LOG_WARN("%s: No active peer found", __func__); + return false; + } + + return true; +} + +bool btif_av_peer_is_source(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_sink_find_peer(peer_address); + if (peer == nullptr) { + LOG_WARN("%s: No active peer found", __func__); + return false; + } + + return true; } diff --git a/system/btif/src/btif_avrcp_audio_track.cc b/system/btif/src/btif_avrcp_audio_track.cc index a14f97ff8585d9b612d2d676ea70d1708f6690e0..e18befc36919d10a8942f029bacc0b6d9451eb78 100644 --- a/system/btif/src/btif_avrcp_audio_track.cc +++ b/system/btif/src/btif_avrcp_audio_track.cc @@ -19,14 +19,19 @@ #include "btif_avrcp_audio_track.h" +#ifndef __INTRODUCED_IN +#define __INTRODUCED_IN(x) +#endif + #include #include #include #include +#include -#include "bt_target.h" -#include "osi/include/log.h" +#include "internal_include/bt_target.h" +#include "os/log.h" using namespace android; @@ -49,10 +54,54 @@ constexpr float kMaxTrackGain = 1.0f; // Minimum track gain that can be set. constexpr float kMinTrackGain = 0.0f; +struct AudioEngine { + int trackFreq = 0; + int channelCount = 0; + std::thread *thread = nullptr; + void* trackHandle = nullptr; +} s_AudioEngine; + +void ErrorCallback(AAudioStream* stream, void* userdata, aaudio_result_t error); + +void BtifAvrcpAudioErrorHandle() { + AAudioStreamBuilder* builder; + AAudioStream* stream; + + aaudio_result_t result = AAudio_createStreamBuilder(&builder); + AAudioStreamBuilder_setSampleRate(builder, s_AudioEngine.trackFreq); + AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_FLOAT); + AAudioStreamBuilder_setChannelCount(builder, s_AudioEngine.channelCount); + AAudioStreamBuilder_setSessionId(builder, AAUDIO_SESSION_ID_ALLOCATE); + AAudioStreamBuilder_setPerformanceMode(builder, + AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); + AAudioStreamBuilder_setErrorCallback(builder, ErrorCallback, nullptr); + result = AAudioStreamBuilder_openStream(builder, &stream); + CHECK(result == AAUDIO_OK); + AAudioStreamBuilder_delete(builder); + + BtifAvrcpAudioTrack* trackHolder = static_cast(s_AudioEngine.trackHandle); + + trackHolder->stream = stream; + + if (trackHolder != NULL && trackHolder->stream != NULL) { + LOG_DEBUG("%s AAudio Error handle: restart A2dp Sink AudioTrack", __func__); + AAudioStream_requestStart(trackHolder->stream); + } + s_AudioEngine.thread = nullptr; +} + +void ErrorCallback(AAudioStream* stream, + void* userdata, + aaudio_result_t error) { + if (error == AAUDIO_ERROR_DISCONNECTED) + if (s_AudioEngine.thread == nullptr) + s_AudioEngine.thread = new std::thread(BtifAvrcpAudioErrorHandle); +} + void* BtifAvrcpAudioTrackCreate(int trackFreq, int bitsPerSample, int channelCount) { - LOG_VERBOSE("%s Track.cpp: btCreateTrack freq %d bps %d channel %d ", - __func__, trackFreq, bitsPerSample, channelCount); + LOG_INFO("%s Track.cpp: btCreateTrack freq %d bps %d channel %d ", __func__, + trackFreq, bitsPerSample, channelCount); AAudioStreamBuilder* builder; AAudioStream* stream; @@ -63,6 +112,7 @@ void* BtifAvrcpAudioTrackCreate(int trackFreq, int bitsPerSample, AAudioStreamBuilder_setSessionId(builder, AAUDIO_SESSION_ID_ALLOCATE); AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); + AAudioStreamBuilder_setErrorCallback(builder, ErrorCallback, nullptr); result = AAudioStreamBuilder_openStream(builder, &stream); CHECK(result == AAUDIO_OK); AAudioStreamBuilder_delete(builder); @@ -80,6 +130,10 @@ void* BtifAvrcpAudioTrackCreate(int trackFreq, int bitsPerSample, #if (DUMP_PCM_DATA == TRUE) outputPcmSampleFile = fopen(outputFilename, "ab"); #endif + s_AudioEngine.trackFreq = trackFreq; + s_AudioEngine.channelCount = channelCount; + s_AudioEngine.trackHandle = (void*)trackHolder; + return (void*)trackHolder; } @@ -102,7 +156,7 @@ void BtifAvrcpAudioTrackStop(void* handle) { } BtifAvrcpAudioTrack* trackHolder = static_cast(handle); if (trackHolder != NULL && trackHolder->stream != NULL) { - LOG_VERBOSE("%s Track.cpp: btStartTrack", __func__); + LOG_VERBOSE("%s Track.cpp: btStopTrack", __func__); AAudioStream_requestStop(trackHolder->stream); } } diff --git a/system/btif/src/btif_ble_advertiser.cc b/system/btif/src/btif_ble_advertiser.cc deleted file mode 100644 index 79bf2b0f2fc9b9a31be36af435a72534f9bcee7f..0000000000000000000000000000000000000000 --- a/system/btif/src/btif_ble_advertiser.cc +++ /dev/null @@ -1,273 +0,0 @@ -/****************************************************************************** - * - * Copyright 2016 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. - * - ******************************************************************************/ - -#define LOG_TAG "bt_btif_ble_advertiser" - -#include -#include - -#include -#include -#include - -#include "ble_advertiser.h" -#include "btif_common.h" -#include "main/shim/le_advertising_manager.h" -#include "main/shim/shim.h" -#include "osi/include/properties.h" -#include "stack/include/btu.h" - -using base::Bind; -using base::Owned; -using std::vector; - -namespace { - -template -class OwnedArrayWrapper { - public: - explicit OwnedArrayWrapper(T* o) : ptr_(o) {} - ~OwnedArrayWrapper() { delete[] ptr_; } - T* get() const { return ptr_; } - OwnedArrayWrapper(OwnedArrayWrapper&& other) noexcept { - ptr_ = other.ptr_; - other.ptr_ = NULL; - } - - private: - mutable T* ptr_; -}; - -template -T* Unwrap(const OwnedArrayWrapper& o) { - return o.get(); -} - -template -static inline OwnedArrayWrapper OwnedArray(T* o) { - return OwnedArrayWrapper(o); -} - -void parseParams(tBTM_BLE_ADV_PARAMS* p_params, - const AdvertiseParameters& params) { - // By default use all channels, but have property for tweaking. - int channel_map = osi_property_get_int32( - "persist.bluetooth.advertising_channel_map", params.channel_map); - - p_params->advertising_event_properties = params.advertising_event_properties; - p_params->adv_int_min = params.min_interval; - p_params->adv_int_max = params.max_interval; - p_params->channel_map = channel_map; - p_params->adv_filter_policy = 0; - p_params->tx_power = params.tx_power; - p_params->primary_advertising_phy = params.primary_advertising_phy; - p_params->secondary_advertising_phy = params.secondary_advertising_phy; - p_params->scan_request_notification_enable = - params.scan_request_notification_enable; - p_params->own_address_type = params.own_address_type; -} - -void parsePeriodicParams(tBLE_PERIODIC_ADV_PARAMS* p_periodic_params, - PeriodicAdvertisingParameters periodic_params) { - p_periodic_params->enable = periodic_params.enable; - p_periodic_params->include_adi = periodic_params.include_adi; - p_periodic_params->min_interval = periodic_params.min_interval; - p_periodic_params->max_interval = periodic_params.max_interval; - p_periodic_params->periodic_advertising_properties = - periodic_params.periodic_advertising_properties; -} - -class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface { - ~BleAdvertiserInterfaceImpl() override{}; - - void RegisterAdvertiserCb(IdStatusCallback cb, uint8_t advertiser_id, - uint8_t status) { - LOG(INFO) << __func__ << " status: " << +status - << " , adveriser_id: " << +advertiser_id; - do_in_jni_thread(Bind(cb, advertiser_id, status)); - } - - void RegisterAdvertiser(IdStatusCallback cb) override { - do_in_main_thread( - FROM_HERE, Bind(&BleAdvertisingManager::RegisterAdvertiser, - BleAdvertisingManager::Get(), - Bind(&BleAdvertiserInterfaceImpl::RegisterAdvertiserCb, - base::Unretained(this), cb))); - } - - void Unregister(uint8_t advertiser_id) override { - do_in_main_thread( - FROM_HERE, - Bind( - [](uint8_t advertiser_id) { - if (!BleAdvertisingManager::IsInitialized()) { - LOG(WARNING) << "Stack already shutdown"; - return; - } - BleAdvertisingManager::Get()->Unregister(advertiser_id); - }, - advertiser_id)); - } - - void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) override { - if (!BleAdvertisingManager::IsInitialized()) return; - do_in_main_thread(FROM_HERE, - Bind(&BleAdvertisingManager::GetOwnAddress, - BleAdvertisingManager::Get(), advertiser_id, - jni_thread_wrapper(FROM_HERE, cb))); - } - - void SetParameters(uint8_t advertiser_id, AdvertiseParameters params, - ParametersCallback cb) override { - VLOG(1) << __func__; - - if (!BleAdvertisingManager::IsInitialized()) return; - tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS; - parseParams(p_params, params); - - do_in_main_thread(FROM_HERE, Bind(&BleAdvertisingManager::SetParameters, - BleAdvertisingManager::Get(), - advertiser_id, base::Owned(p_params), - jni_thread_wrapper(FROM_HERE, cb))); - } - - void SetData(int advertiser_id, bool set_scan_rsp, vector data, - StatusCallback cb) override { - if (!BleAdvertisingManager::IsInitialized()) return; - do_in_main_thread( - FROM_HERE, - Bind(&BleAdvertisingManager::SetData, BleAdvertisingManager::Get(), - advertiser_id, set_scan_rsp, std::move(data), - jni_thread_wrapper(FROM_HERE, cb))); - } - - void Enable(uint8_t advertiser_id, bool enable, StatusCallback cb, - uint16_t duration, uint8_t maxExtAdvEvents, - StatusCallback timeout_cb) override { - VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id - << " ,enable: " << enable; - - if (!BleAdvertisingManager::IsInitialized()) return; - do_in_main_thread( - FROM_HERE, - Bind(&BleAdvertisingManager::Enable, BleAdvertisingManager::Get(), - advertiser_id, enable, jni_thread_wrapper(FROM_HERE, cb), duration, - maxExtAdvEvents, jni_thread_wrapper(FROM_HERE, timeout_cb))); - } - - void StartAdvertising(uint8_t advertiser_id, StatusCallback cb, - AdvertiseParameters params, - std::vector advertise_data, - std::vector scan_response_data, int timeout_s, - MultiAdvCb timeout_cb) override { - VLOG(1) << __func__; - - if (!BleAdvertisingManager::IsInitialized()) return; - tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS; - parseParams(p_params, params); - - do_in_main_thread( - FROM_HERE, - Bind(&BleAdvertisingManager::StartAdvertising, - BleAdvertisingManager::Get(), advertiser_id, - jni_thread_wrapper(FROM_HERE, cb), base::Owned(p_params), - std::move(advertise_data), std::move(scan_response_data), - timeout_s * 100, jni_thread_wrapper(FROM_HERE, timeout_cb))); - } - - void StartAdvertisingSet(int reg_id, IdTxPowerStatusCallback cb, - AdvertiseParameters params, - std::vector advertise_data, - std::vector scan_response_data, - PeriodicAdvertisingParameters periodic_params, - std::vector periodic_data, - uint16_t duration, uint8_t maxExtAdvEvents, - IdStatusCallback timeout_cb) override { - VLOG(1) << __func__; - - if (!BleAdvertisingManager::IsInitialized()) return; - tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS; - parseParams(p_params, params); - - tBLE_PERIODIC_ADV_PARAMS* p_periodic_params = new tBLE_PERIODIC_ADV_PARAMS; - parsePeriodicParams(p_periodic_params, periodic_params); - - do_in_main_thread( - FROM_HERE, - Bind(&BleAdvertisingManager::StartAdvertisingSet, - BleAdvertisingManager::Get(), jni_thread_wrapper(FROM_HERE, cb), - base::Owned(p_params), std::move(advertise_data), - std::move(scan_response_data), base::Owned(p_periodic_params), - std::move(periodic_data), duration, maxExtAdvEvents, - jni_thread_wrapper(FROM_HERE, timeout_cb))); - - return; - } - - void SetPeriodicAdvertisingParameters( - int advertiser_id, PeriodicAdvertisingParameters periodic_params, - StatusCallback cb) override { - VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id; - - if (!BleAdvertisingManager::IsInitialized()) return; - tBLE_PERIODIC_ADV_PARAMS* p_periodic_params = new tBLE_PERIODIC_ADV_PARAMS; - parsePeriodicParams(p_periodic_params, periodic_params); - - do_in_main_thread( - FROM_HERE, - Bind(&BleAdvertisingManager::SetPeriodicAdvertisingParameters, - BleAdvertisingManager::Get(), advertiser_id, - base::Owned(p_periodic_params), - jni_thread_wrapper(FROM_HERE, cb))); - } - - void SetPeriodicAdvertisingData(int advertiser_id, std::vector data, - StatusCallback cb) override { - VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id; - - if (!BleAdvertisingManager::IsInitialized()) return; - do_in_main_thread(FROM_HERE, - Bind(&BleAdvertisingManager::SetPeriodicAdvertisingData, - BleAdvertisingManager::Get(), advertiser_id, - std::move(data), jni_thread_wrapper(FROM_HERE, cb))); - } - - void SetPeriodicAdvertisingEnable(int advertiser_id, bool enable, - bool include_adi, - StatusCallback cb) override { - VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id - << " ,enable: " << enable; - - if (!BleAdvertisingManager::IsInitialized()) return; - do_in_main_thread(FROM_HERE, - Bind(&BleAdvertisingManager::SetPeriodicAdvertisingEnable, - BleAdvertisingManager::Get(), advertiser_id, enable, - include_adi, jni_thread_wrapper(FROM_HERE, cb))); - } - - void RegisterCallbacks(AdvertisingCallbacks* callbacks) { - // For GD only - } -}; - -} // namespace - -BleAdvertiserInterface* get_ble_advertiser_instance() { - LOG(INFO) << __func__ << " use gd le advertiser"; - return bluetooth::shim::get_ble_advertiser_instance(); -} diff --git a/system/btif/src/btif_bqr.cc b/system/btif/src/btif_bqr.cc index 0d5b7552e9782c4c091894b2bd0055f442c41f3c..9f0fca859d9c14dfac7a60dbef1dbfe8ab7204b4 100644 --- a/system/btif/src/btif_bqr.cc +++ b/system/btif/src/btif_bqr.cc @@ -15,7 +15,6 @@ */ #include -#include #include #ifdef __ANDROID__ #include @@ -23,6 +22,8 @@ #include #include +#include + #include "btif/include/stack_manager.h" #include "btif_bqr.h" #include "btif_common.h" @@ -35,6 +36,7 @@ #include "osi/include/properties.h" #include "raw_address.h" #include "stack/btm/btm_dev.h" +#include "stack/include/bt_types.h" namespace bluetooth { namespace bqr { @@ -83,8 +85,27 @@ void BqrVseSubEvt::ParseBqrLinkQualityEvt(uint8_t length, STREAM_TO_UINT32(bqr_link_quality_event_.last_flow_on_timestamp, p_param_buf); STREAM_TO_UINT32(bqr_link_quality_event_.buffer_overflow_bytes, p_param_buf); STREAM_TO_UINT32(bqr_link_quality_event_.buffer_underflow_bytes, p_param_buf); - STREAM_TO_BDADDR(bqr_link_quality_event_.bdaddr, p_param_buf); - STREAM_TO_UINT8(bqr_link_quality_event_.cal_failed_item_count, p_param_buf); + + if (vendor_cap_supported_version >= kBqrVersion5_0) { + if (length < kLinkQualityParamTotalLen + kISOLinkQualityParamTotalLen + + kVersion5_0ParamsTotalLen) { + LOG(WARNING) << __func__ + << ": Parameter total length: " << std::to_string(length) + << " is abnormal. " + << "vendor_cap_supported_version: " + << vendor_cap_supported_version << " " + << " (>= " + << "kBqrVersion5_0=" << kBqrVersion5_0 << "), " + << "It should not be shorter than: " + << std::to_string(kLinkQualityParamTotalLen + + kISOLinkQualityParamTotalLen + + kVersion5_0ParamsTotalLen); + } else { + STREAM_TO_BDADDR(bqr_link_quality_event_.bdaddr, p_param_buf); + STREAM_TO_UINT8(bqr_link_quality_event_.cal_failed_item_count, + p_param_buf); + } + } if (vendor_cap_supported_version >= kBqrIsoVersion) { if (length < kLinkQualityParamTotalLen + kISOLinkQualityParamTotalLen) { @@ -180,12 +201,13 @@ std::string BqrVseSubEvt::ToString() const { << ", OverFlow: " << std::to_string(bqr_link_quality_event_.buffer_overflow_bytes) << ", UndFlow: " - << std::to_string(bqr_link_quality_event_.buffer_underflow_bytes) - << ", RemoteDevAddr: " - << bqr_link_quality_event_.bdaddr.ToColonSepHexString() - << ", CalFailedItems: " - << std::to_string(bqr_link_quality_event_.cal_failed_item_count); - + << std::to_string(bqr_link_quality_event_.buffer_underflow_bytes); + if (vendor_cap_supported_version >= kBqrVersion5_0) { + ss << ", RemoteDevAddr: " + << bqr_link_quality_event_.bdaddr.ToColonSepHexString() + << ", CalFailedItems: " + << std::to_string(bqr_link_quality_event_.cal_failed_item_count); + } if (vendor_cap_supported_version >= kBqrIsoVersion) { ss << ", TxTotal: " << std::to_string(bqr_link_quality_event_.tx_total_packets) @@ -587,13 +609,20 @@ void AddLinkQualityEventToQueue(uint8_t length, if (bqrItf != NULL) { bd_addr = p_bqr_event->bqr_link_quality_event_.bdaddr; + if (bd_addr.IsEmpty()) { + tBTM_SEC_DEV_REC* dev = btm_find_dev_by_handle( + p_bqr_event->bqr_link_quality_event_.connection_handle); + if (dev != NULL) { + bd_addr = dev->RemoteAddress(); + } + } if (!bd_addr.IsEmpty()) { bqrItf->bqr_delivery_event(bd_addr, (uint8_t*)p_link_quality_event, length); } else { LOG(WARNING) << __func__ << ": failed to deliver BQR, " - << "bdaddr is empty, no address in packet"; + << "bdaddr is empty"; } } else { LOG(WARNING) << __func__ << ": failed to deliver BQR, bqrItf is NULL"; @@ -752,6 +781,18 @@ class BluetoothQualityReportInterfaceImpl raw_data.insert(raw_data.begin(), bqr_raw_data, bqr_raw_data + bqr_raw_data_len); + if (vendor_cap_supported_version < kBqrVersion5_0 && + bqr_raw_data_len < + kLinkQualityParamTotalLen + kVersion5_0ParamsTotalLen) { + std::vector::iterator it = + raw_data.begin() + kLinkQualityParamTotalLen; + /** + * Insert zeros as remote address and calibration count + * for BQR 5.0 incompatible devices + */ + raw_data.insert(it, kVersion5_0ParamsTotalLen, 0); + } + uint8_t lmp_ver = 0; uint16_t lmp_subver = 0; uint16_t manufacturer_id = 0; @@ -769,10 +810,10 @@ class BluetoothQualityReportInterfaceImpl do_in_jni_thread( FROM_HERE, - base::Bind(&bluetooth::bqr::BluetoothQualityReportCallbacks:: - bqr_delivery_callback, - base::Unretained(callbacks), bd_addr, lmp_ver, lmp_subver, - manufacturer_id, std::move(raw_data))); + base::BindOnce(&bluetooth::bqr::BluetoothQualityReportCallbacks:: + bqr_delivery_callback, + base::Unretained(callbacks), bd_addr, lmp_ver, + lmp_subver, manufacturer_id, std::move(raw_data))); } private: diff --git a/system/btif/src/btif_config.cc b/system/btif/src/btif_config.cc index 3e6e4e37407260e11bceaca1a32f534c47eced69..4958023573c5eb8a25c753ef802c4263a2ff5019 100644 --- a/system/btif/src/btif_config.cc +++ b/system/btif/src/btif_config.cc @@ -209,6 +209,31 @@ EXPORT_SYMBOL module_t btif_config_module = {.name = BTIF_CONFIG_MODULE, .shut_down = shut_down, .clean_up = clean_up}; +bool btif_get_device_clockoffset(const RawAddress& bda, int* p_clock_offset) { + if (p_clock_offset == NULL) return false; + + std::string addrstr = bda.ToString(); + const char* bd_addr_str = addrstr.c_str(); + + if (!btif_config_get_int(bd_addr_str, "ClockOffset", p_clock_offset)) return false; + + LOG_DEBUG("%s: Device [%s] clock_offset %d", __func__, bd_addr_str, + *p_clock_offset); + return true; +} + +bool btif_set_device_clockoffset(const RawAddress& bda, int clock_offset) { + + std::string addrstr = bda.ToString(); + const char* bd_addr_str = addrstr.c_str(); + + if (!btif_config_set_int(bd_addr_str, "ClockOffset", clock_offset)) return false; + + LOG_DEBUG("%s: Device [%s] clock_offset %d", __func__, bd_addr_str, + clock_offset); + return true; +} + bool btif_config_exist(const std::string& section, const std::string& key) { CHECK(bluetooth::shim::is_gd_stack_started_up()); return bluetooth::shim::BtifConfigInterface::HasProperty(section, key); @@ -312,6 +337,11 @@ bool btif_config_remove(const std::string& section, const std::string& key) { return bluetooth::shim::BtifConfigInterface::RemoveProperty(section, key); } +void btif_config_remove_device(const std::string& section) { + CHECK(bluetooth::shim::is_gd_stack_started_up()); + bluetooth::shim::BtifConfigInterface::RemoveSection(section); +} + bool btif_config_clear(void) { CHECK(bluetooth::shim::is_gd_stack_started_up()); bluetooth::shim::BtifConfigInterface::Clear(); diff --git a/system/btif/src/btif_core.cc b/system/btif/src/btif_core.cc index deb95ad3f29c236a2ba99eff298a069f405d7ac7..33e278c084443b15a50851fda704af635f1dffc2 100644 --- a/system/btif/src/btif_core.cc +++ b/system/btif/src/btif_core.cc @@ -37,12 +37,10 @@ #include -#include "bt_target.h" // Must be first to define build configuration -#include "btif/include/btif_av.h" #include "btif/include/btif_common.h" #include "btif/include/btif_config.h" #include "btif/include/btif_dm.h" -#include "btif/include/btif_pan.h" +#include "btif/include/btif_jni_task.h" #include "btif/include/btif_profile_queue.h" #include "btif/include/btif_sock.h" #include "btif/include/btif_storage.h" @@ -51,11 +49,13 @@ #include "common/message_loop_thread.h" #include "device/include/controller.h" #include "device/include/device_iot_config.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/future.h" -#include "osi/include/log.h" #include "osi/include/properties.h" #include "stack/include/a2dp_api.h" +#include "stack/include/bt_types.h" #include "stack/include/btm_api.h" #include "stack/include/btm_ble_api.h" #include "types/bluetooth/uuid.h" @@ -65,8 +65,6 @@ using base::PlatformThread; using bluetooth::Uuid; using bluetooth::common::MessageLoopThread; -static void bt_jni_msg_ready(void* context); - /******************************************************************************* * Constants & Macros ******************************************************************************/ @@ -94,7 +92,14 @@ static void bt_jni_msg_ready(void* context); static tBTA_SERVICE_MASK btif_enabled_services = 0; -static MessageLoopThread jni_thread("bt_jni_thread"); +/* + * This variable should be set to 1, if the Bluedroid+BTIF libraries are to + * function in DUT mode. + * + * To set this, the btif_init_bluetooth needs to be called with argument as 1 + */ +static uint8_t btif_dut_mode = 0; + static base::AtExitManager* exit_manager; static uid_set_t* uid_set; @@ -108,78 +113,15 @@ void btif_dm_load_local_oob(void); /******************************************************************************* * - * Function btif_transfer_context - * - * Description This function switches context to btif task + * Function btif_is_dut_mode * - * p_cback : callback used to process message in btif context - * event : event id of message - * p_params : parameter area passed to callback (copied) - * param_len : length of parameter area - * p_copy_cback : If set this function will be invoked for deep - * copy + * Description checks if BTIF is currently in DUT mode * - * Returns void + * Returns true if test mode, otherwise false * ******************************************************************************/ -bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event, - char* p_params, int param_len, - tBTIF_COPY_CBACK* p_copy_cback) { - tBTIF_CONTEXT_SWITCH_CBACK* p_msg = (tBTIF_CONTEXT_SWITCH_CBACK*)osi_malloc( - sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len); - - BTIF_TRACE_VERBOSE("btif_transfer_context event %d, len %d", event, - param_len); - - /* allocate and send message that will be executed in btif context */ - p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */ - p_msg->p_cb = p_cback; - - p_msg->event = event; /* callback event */ - - /* check if caller has provided a copy callback to do the deep copy */ - if (p_copy_cback) { - p_copy_cback(event, p_msg->p_param, p_params); - } else if (p_params) { - memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */ - } - - return do_in_jni_thread(base::Bind(&bt_jni_msg_ready, p_msg)); -} - -/** - * This function posts a task into the btif message loop, that executes it in - * the JNI message loop. - **/ -bt_status_t do_in_jni_thread(const base::Location& from_here, - base::OnceClosure task) { - if (!jni_thread.DoInThread(from_here, std::move(task))) { - LOG(ERROR) << __func__ << ": Post task to task runner failed!"; - return BT_STATUS_FAIL; - } - return BT_STATUS_SUCCESS; -} - -bt_status_t do_in_jni_thread(base::OnceClosure task) { - return do_in_jni_thread(FROM_HERE, std::move(task)); -} - -bool is_on_jni_thread() { - return jni_thread.GetThreadId() == PlatformThread::CurrentId(); -} - -btbase::AbstractMessageLoop* get_jni_message_loop() { - return jni_thread.message_loop(); -} - -static void do_post_on_bt_jni(BtJniClosure closure) { closure(); } - -void post_on_bt_jni(BtJniClosure closure) { - ASSERT(do_in_jni_thread(FROM_HERE, - base::Bind(do_post_on_bt_jni, std::move(closure))) == - BT_STATUS_SUCCESS); -} +bool btif_is_dut_mode() { return btif_dut_mode == 1; } /******************************************************************************* * @@ -192,29 +134,14 @@ void post_on_bt_jni(BtJniClosure closure) { ******************************************************************************/ int btif_is_enabled(void) { - return (stack_manager_get_interface()->get_stack_is_running()); + return ((!btif_is_dut_mode()) && + (stack_manager_get_interface()->get_stack_is_running())); } void btif_init_ok() { btif_dm_load_ble_local_keys(); } -/******************************************************************************* - * - * Function btif_task - * - * Description BTIF task handler managing all messages being passed - * Bluetooth HAL and BTA. - * - * Returns void - * - ******************************************************************************/ -static void bt_jni_msg_ready(void* context) { - tBTIF_CONTEXT_SWITCH_CBACK* p = (tBTIF_CONTEXT_SWITCH_CBACK*)context; - if (p->p_cb) p->p_cb(p->event, p->p_param); - osi_free(p); -} - /******************************************************************************* * * Function btif_init_bluetooth @@ -227,7 +154,7 @@ static void bt_jni_msg_ready(void* context) { bt_status_t btif_init_bluetooth() { LOG_INFO("%s entered", __func__); exit_manager = new base::AtExitManager(); - jni_thread.StartUp(); + jni_thread_startup(); GetInterfaceToProfiles()->events->invoke_thread_evt_cb(ASSOCIATE_JVM); LOG_INFO("%s finished", __func__); return BT_STATUS_SUCCESS; @@ -309,13 +236,60 @@ bt_status_t btif_cleanup_bluetooth() { btif_dm_cleanup(); GetInterfaceToProfiles()->events->invoke_thread_evt_cb(DISASSOCIATE_JVM); btif_queue_release(); - jni_thread.ShutDown(); + jni_thread_shutdown(); delete exit_manager; exit_manager = nullptr; + btif_dut_mode = 0; LOG_INFO("%s finished", __func__); return BT_STATUS_SUCCESS; } +/******************************************************************************* + * + * Function btif_dut_mode_cback + * + * Description Callback invoked on completion of vendor specific test mode + * command + * + * Returns None + * + ******************************************************************************/ +static void btif_dut_mode_cback(UNUSED_ATTR tBTM_VSC_CMPL* p) { + /* For now nothing to be done. */ +} + +/******************************************************************************* + * + * Function btif_dut_mode_configure + * + * Description Configure Test Mode - 'enable' to 1 puts the device in test + * mode and 0 exits test mode + * + ******************************************************************************/ +void btif_dut_mode_configure(uint8_t enable) { + LOG_VERBOSE("%s", __func__); + + btif_dut_mode = enable; + if (enable == 1) { + BTA_EnableTestMode(); + } else { + // Can't do in process reset anyways - just quit + kill(getpid(), SIGKILL); + } +} + +/******************************************************************************* + * + * Function btif_dut_mode_send + * + * Description Sends a HCI Vendor specific command to the controller + * + ******************************************************************************/ +void btif_dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) { + LOG_VERBOSE("%s", __func__); + BTM_VendorSpecificCommand(opcode, len, buf, btif_dut_mode_cback); +} + /***************************************************************************** * * btif api adapter property functions @@ -438,7 +412,7 @@ static bt_status_t btif_in_get_remote_device_properties(RawAddress* bd_addr) { } static void btif_core_storage_adapter_write(bt_property_t* prop) { - BTIF_TRACE_EVENT("type: %d, len %d, 0x%x", prop->type, prop->len, prop->val); + LOG_VERBOSE("type: %d, len %d, 0x%p", prop->type, prop->len, prop->val); bt_status_t status = btif_storage_set_adapter_property(prop); GetInterfaceToProfiles()->events->invoke_adapter_properties_cb(status, 1, prop); @@ -464,7 +438,7 @@ void btif_remote_properties_evt(bt_status_t status, RawAddress* remote_addr, ******************************************************************************/ void btif_get_adapter_properties(void) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_in_get_adapter_properties(); } @@ -478,7 +452,7 @@ void btif_get_adapter_properties(void) { ******************************************************************************/ void btif_get_adapter_property(bt_property_type_t type) { - BTIF_TRACE_EVENT("%s %d", __func__, type); + LOG_VERBOSE("%s %d", __func__, type); bt_status_t status = BT_STATUS_SUCCESS; char buf[512]; @@ -555,8 +529,7 @@ void btif_get_adapter_property(bt_property_type_t type) { prop.len = sizeof(bt_dynamic_audio_buffer_item_t); if (GetInterfaceToProfiles()->config->isA2DPOffloadEnabled() == false) { - BTIF_TRACE_DEBUG("%s Get buffer millis for A2DP software encoding", - __func__); + LOG_VERBOSE("%s Get buffer millis for A2DP software encoding", __func__); for (int i = 0; i < CODEC_TYPE_NUMBER; i++) { dynamic_audio_buffer_item.dab_item[i] = { .default_buffer_time = DEFAULT_BUFFER_TIME, @@ -566,7 +539,7 @@ void btif_get_adapter_property(bt_property_type_t type) { memcpy(prop.val, &dynamic_audio_buffer_item, prop.len); } else { if (cmn_vsc_cb.dynamic_audio_buffer_support != 0) { - BTIF_TRACE_DEBUG("%s Get buffer millis for A2DP Offload", __func__); + LOG_VERBOSE("%s Get buffer millis for A2DP Offload", __func__); tBTM_BT_DYNAMIC_AUDIO_BUFFER_CB bt_dynamic_audio_buffer_cb[CODEC_TYPE_NUMBER]; BTM_BleGetDynamicAudioBuffer(bt_dynamic_audio_buffer_cb); @@ -582,7 +555,7 @@ void btif_get_adapter_property(bt_property_type_t type) { } memcpy(prop.val, &dynamic_audio_buffer_item, prop.len); } else { - BTIF_TRACE_DEBUG("%s Don't support Dynamic Audio Buffer", __func__); + LOG_VERBOSE("%s Don't support Dynamic Audio Buffer", __func__); } } } else { @@ -614,8 +587,8 @@ bt_property_t* property_deep_copy(const bt_property_t* prop) { ******************************************************************************/ void btif_set_adapter_property(bt_property_t* property) { - BTIF_TRACE_EVENT("btif_set_adapter_property type: %d, len %d, 0x%x", - property->type, property->len, property->val); + LOG_VERBOSE("btif_set_adapter_property type: %d, len %d, 0x%p", + property->type, property->len, property->val); switch (property->type) { case BT_PROPERTY_BDNAME: { @@ -626,7 +599,7 @@ void btif_set_adapter_property(bt_property_t* property) { memcpy(bd_name, property->val, name_len); bd_name[name_len] = '\0'; - BTIF_TRACE_EVENT("set property name : %s", (char*)bd_name); + LOG_VERBOSE("set property name : %s", (char*)bd_name); BTA_DmSetDeviceName((const char*)bd_name); @@ -635,7 +608,7 @@ void btif_set_adapter_property(bt_property_t* property) { case BT_PROPERTY_ADAPTER_SCAN_MODE: { bt_scan_mode_t mode = *(bt_scan_mode_t*)property->val; - BTIF_TRACE_EVENT("set property scan mode : %x", mode); + LOG_VERBOSE("set property scan mode : %x", mode); if (BTA_DmSetVisibility(mode)) { btif_core_storage_adapter_write(property); @@ -730,8 +703,7 @@ tBTA_SERVICE_MASK btif_get_enabled_services_mask(void) { void btif_enable_service(tBTA_SERVICE_ID service_id) { btif_enabled_services |= (1 << service_id); - BTIF_TRACE_DEBUG("%s: current services:0x%x", __func__, - btif_enabled_services); + LOG_VERBOSE("%s: current services:0x%x", __func__, btif_enabled_services); if (btif_is_enabled()) { btif_dm_enable_service(service_id, true); @@ -749,8 +721,7 @@ void btif_enable_service(tBTA_SERVICE_ID service_id) { void btif_disable_service(tBTA_SERVICE_ID service_id) { btif_enabled_services &= (tBTA_SERVICE_MASK)(~(1 << service_id)); - BTIF_TRACE_DEBUG("%s: Current Services:0x%x", __func__, - btif_enabled_services); + LOG_VERBOSE("%s: Current Services:0x%x", __func__, btif_enabled_services); if (btif_is_enabled()) { btif_dm_enable_service(service_id, false); @@ -800,21 +771,20 @@ void DynamicAudiobufferSizeCompleteCallback(tBTM_VSC_CMPL* p_vsc_cmpl_params) { } bt_status_t btif_set_dynamic_audio_buffer_size(int codec, int size) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); tBTM_BLE_VSC_CB cmn_vsc_cb; BTM_BleGetVendorCapabilities(&cmn_vsc_cb); if (!GetInterfaceToProfiles()->config->isA2DPOffloadEnabled()) { - BTIF_TRACE_DEBUG("%s Set buffer size (%d) for A2DP software encoding", - __func__, size); + LOG_VERBOSE("%s Set buffer size (%d) for A2DP software encoding", __func__, + size); GetInterfaceToProfiles() ->profileSpecific_HACK->btif_av_set_dynamic_audio_buffer_size( uint8_t(size)); } else { if (cmn_vsc_cb.dynamic_audio_buffer_support != 0) { - BTIF_TRACE_DEBUG("%s Set buffer size (%d) for A2DP offload", __func__, - size); + LOG_VERBOSE("%s Set buffer size (%d) for A2DP offload", __func__, size); uint16_t firmware_tx_buffer_length_byte; uint8_t param[3] = {0}; uint8_t* p_param = param; diff --git a/system/btif/src/btif_csis_client.cc b/system/btif/src/btif_csis_client.cc index 34ffe3935f9011591139b9f091e35f496cfbde98..70271286d129da5641a47622111a4468f1d26518 100644 --- a/system/btif/src/btif_csis_client.cc +++ b/system/btif/src/btif_csis_client.cc @@ -25,7 +25,7 @@ #include "bta_csis_api.h" #include "btif_common.h" #include "btif_profile_storage.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" using base::Bind; using base::Owned; @@ -47,7 +47,6 @@ class CsipSetCoordinatorServiceInterfaceImpl : public CsisClientInterface, ~CsipSetCoordinatorServiceInterfaceImpl() override = default; void Init(CsisClientCallbacks* callbacks) override { - DVLOG(2) << __func__; this->callbacks_ = callbacks; do_in_main_thread( @@ -63,42 +62,39 @@ class CsipSetCoordinatorServiceInterfaceImpl : public CsisClientInterface, void Connect(const RawAddress& addr) override { if (!initialized || !CsisClient::IsCsisClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr); do_in_main_thread(FROM_HERE, Bind(&CsisClient::Connect, Unretained(CsisClient::Get()), addr)); } void Disconnect(const RawAddress& addr) override { if (!initialized || !CsisClient::IsCsisClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr); do_in_main_thread(FROM_HERE, Bind(&CsisClient::Disconnect, Unretained(CsisClient::Get()), addr)); } void RemoveDevice(const RawAddress& addr) override { if (!initialized || !CsisClient::IsCsisClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not ready"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not ready"; /* Clear storage */ do_in_jni_thread(FROM_HERE, Bind(&btif_storage_remove_csis_device, addr)); return; } - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr); do_in_main_thread(FROM_HERE, Bind(&CsisClient::RemoveDevice, Unretained(CsisClient::Get()), addr)); /* Clear storage */ @@ -107,13 +103,12 @@ class CsipSetCoordinatorServiceInterfaceImpl : public CsisClientInterface, void LockGroup(int group_id, bool lock) override { if (!initialized || !CsisClient::IsCsisClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } - DVLOG(2) << __func__ << " group id: " << group_id << " lock: " << lock; do_in_main_thread( FROM_HERE, Bind(&CsisClient::LockGroup, Unretained(CsisClient::Get()), group_id, lock, base::DoNothing())); @@ -121,38 +116,30 @@ class CsipSetCoordinatorServiceInterfaceImpl : public CsisClientInterface, void Cleanup(void) override { if (!initialized || !CsisClient::IsCsisClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } - DVLOG(2) << __func__; initialized = false; do_in_main_thread(FROM_HERE, Bind(&CsisClient::CleanUp)); } void OnConnectionState(const RawAddress& addr, ConnectionState state) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr); do_in_jni_thread(FROM_HERE, Bind(&CsisClientCallbacks::OnConnectionState, Unretained(callbacks_), addr, state)); } void OnDeviceAvailable(const RawAddress& addr, int group_id, int group_size, int rank, const bluetooth::Uuid& uuid) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr) - << " group_id: " << group_id; - do_in_jni_thread(FROM_HERE, Bind(&CsisClientCallbacks::OnDeviceAvailable, Unretained(callbacks_), addr, group_id, group_size, rank, uuid)); } void OnSetMemberAvailable(const RawAddress& addr, int group_id) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr) - << " group id: " << group_id; - do_in_jni_thread(FROM_HERE, Bind(&CsisClientCallbacks::OnSetMemberAvailable, Unretained(callbacks_), addr, group_id)); } @@ -160,9 +147,6 @@ class CsipSetCoordinatorServiceInterfaceImpl : public CsisClientInterface, /* Callback for lock changed in the group */ virtual void OnGroupLockChanged(int group_id, bool locked, CsisGroupLockStatus status) override { - DVLOG(2) << __func__ << " group id: " << group_id << " lock: " << locked - << " status: " << int(status); - do_in_jni_thread(FROM_HERE, Bind(&CsisClientCallbacks::OnGroupLockChanged, Unretained(callbacks_), group_id, locked, status)); diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc index 73a57fbc9b9d9de88ba389f7d402df45f5720ead..47188844557646da9fc8d6eb2179e1eb38f93fdd 100644 --- a/system/btif/src/btif_dm.cc +++ b/system/btif/src/btif_dm.cc @@ -51,48 +51,51 @@ #include #include "advertise_data_parser.h" +#include "bta/dm/bta_dm_disc.h" #include "bta/include/bta_api.h" -#include "bta_csis_api.h" -#include "bta_dm_int.h" -#include "bta_gatt_api.h" -#include "bta_le_audio_api.h" -#include "bta_vc_api.h" #include "btif/include/stack_manager.h" #include "btif_api.h" -#include "btif_av.h" #include "btif_bqr.h" #include "btif_config.h" #include "btif_dm.h" -#include "btif_gatt.h" -#include "btif_hd.h" -#include "btif_hf.h" -#include "btif_hh.h" #include "btif_metrics_logging.h" #include "btif_profile_storage.h" -#include "btif_sdp.h" #include "btif_storage.h" #include "btif_util.h" -#include "common/lru.h" #include "common/metrics.h" #include "device/include/controller.h" -#include "device/include/device_iot_config.h" #include "device/include/interop.h" #include "gd/common/lru_cache.h" +#include "internal_include/bt_target.h" #include "internal_include/stack_config.h" -#include "main/shim/dumpsys.h" -#include "main/shim/shim.h" +#include "main/shim/le_advertising_manager.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "osi/include/properties.h" +#include "osi/include/stack_power_telemetry.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" +#include "stack/include/acl_api.h" +#include "stack/include/acl_api_types.h" #include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/btm_ble_api.h" +#include "stack/include/btm_ble_sec_api.h" +#include "stack/include/btm_ble_sec_api_types.h" +#include "stack/include/btm_client_interface.h" #include "stack/include/btm_log_history.h" +#include "stack/include/btm_sec_api.h" +#include "stack/include/btm_sec_api_types.h" +#include "stack/include/smp_api.h" #include "stack/sdp/sdpint.h" -#include "stack_config.h" #include "types/raw_address.h" +#ifdef __ANDROID__ +#include +#endif + bool btif_get_device_type(const RawAddress& bda, int* p_device_type); using bluetooth::Uuid; @@ -147,7 +150,7 @@ struct btif_dm_pairing_cb_t { bt_bond_state_t state; RawAddress static_bdaddr; RawAddress bd_addr; - tBTM_SEC_DEV_REC::tBTM_BOND_TYPE bond_type; + tBTM_BOND_TYPE bond_type; uint8_t pin_code_len; uint8_t is_ssp; uint8_t auth_req; @@ -308,7 +311,7 @@ void btif_dm_cleanup(void) { bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id, bool b_enable) { - BTIF_TRACE_DEBUG("%s service_id: %d", __func__, service_id); + LOG_VERBOSE("service_id:%d", service_id); if (service_id == BTA_SDP_SERVICE_ID) { btif_sdp_execute_service(b_enable); @@ -485,7 +488,7 @@ static uint32_t get_cod(const RawAddress* remote_bdaddr) { sizeof(uint32_t), &remote_cod); if (btif_storage_get_remote_device_property( (RawAddress*)remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS) { - LOG_INFO("%s remote_cod = 0x%08x", __func__, remote_cod); + LOG_INFO("remote_cod=0x%08x", remote_cod); return remote_cod; } @@ -504,6 +507,12 @@ bool check_cod_hid(const RawAddress& bd_addr) { return (get_cod(&bd_addr) & COD_HID_MASK) == COD_HID_MAJOR; } +bool check_cod_hid_major(const RawAddress& bd_addr, uint32_t cod) { + uint32_t remote_cod = get_cod(&bd_addr); + return (remote_cod & COD_HID_MASK) == COD_HID_MAJOR && + (remote_cod & COD_HID_SUB_MAJOR) == (cod & COD_HID_SUB_MAJOR); +} + bool check_cod_le_audio(const RawAddress& bd_addr) { return (get_cod(&bd_addr) & COD_CLASS_LE_AUDIO) == COD_CLASS_LE_AUDIO; } @@ -560,13 +569,13 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr, return; } - if (pairing_cb.bond_type == tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY) { + if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) { state = BT_BOND_STATE_NONE; } LOG_INFO( - "Bond state changed to state=%d [0:none, 1:bonding, 2:bonded]," - " prev_state=%d, sdp_attempts = %d", + "Bond state changed to state=%d[0:none, 1:bonding, 2:bonded]," + "prev_state=%d, sdp_attempts=%d", state, pairing_cb.state, pairing_cb.sdp_attempts); if (state == BT_BOND_STATE_NONE) { @@ -581,8 +590,8 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr, } else if (state == BT_BOND_STATE_BONDED) { allocate_metric_id_from_metric_id_allocator(bd_addr); if (!save_metric_id_from_metric_id_allocator(bd_addr)) { - LOG(FATAL) << __func__ << ": Fail to save metric id for device " - << bd_addr; + LOG_ERROR("Fail to save metric id for device:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } } BTM_LogHistory( @@ -595,11 +604,6 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr, GetInterfaceToProfiles()->events->invoke_bond_state_changed_cb( status, bd_addr, state, pairing_cb.fail_reason); - int dev_type; - if (!btif_get_device_type(bd_addr, &dev_type)) { - dev_type = BT_DEVICE_TYPE_BREDR; - } - if ((state == BT_BOND_STATE_NONE) && (pairing_cb.bd_addr != bd_addr) && is_bonding_or_sdp()) { LOG_WARN("Ignoring bond state changed for unexpected device: %s pairing: %s", @@ -616,7 +620,7 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr, pairing_cb.state = state; pairing_cb.bd_addr = bd_addr; } else { - LOG_INFO("clearing btif pairing_cb"); + LOG_DEBUG("clearing btif pairing_cb"); pairing_cb = {}; } } @@ -636,9 +640,9 @@ static void btif_update_remote_version_property(RawAddress* p_bd) { const bool version_info_valid = BTM_ReadRemoteVersion(*p_bd, &lmp_ver, &mfct_set, &lmp_subver); - LOG_INFO("Remote version info valid:%s [%s]: %x, %x, %x", - logbool(version_info_valid).c_str(), ADDRESS_TO_LOGGABLE_CSTR((*p_bd)), - lmp_ver, mfct_set, lmp_subver); + LOG_INFO("Remote version info valid:%s [%s]:0x%x,0x%x,0x%x", + logbool(version_info_valid).c_str(), + ADDRESS_TO_LOGGABLE_CSTR((*p_bd)), lmp_ver, mfct_set, lmp_subver); if (version_info_valid) { // Always update cache to ensure we have availability whenever BTM API is @@ -661,7 +665,7 @@ static void btif_update_remote_properties(const RawAddress& bdaddr, bt_property_t properties[3]; bt_status_t status = BT_STATUS_UNHANDLED; uint32_t cod; - bt_device_type_t dev_type; + uint32_t dev_type; memset(properties, 0, sizeof(properties)); @@ -705,14 +709,14 @@ static void btif_update_remote_properties(const RawAddress& bdaddr, /* device type */ bt_property_t prop_name; - uint8_t remote_dev_type; + uint32_t remote_dev_type; BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_TYPE_OF_DEVICE, - sizeof(uint8_t), &remote_dev_type); + sizeof(uint32_t), &remote_dev_type); if (btif_storage_get_remote_device_property(&bdaddr, &prop_name) == BT_STATUS_SUCCESS) { - dev_type = (bt_device_type_t)(remote_dev_type | device_type); + dev_type = remote_dev_type | device_type; } else { - dev_type = (bt_device_type_t)device_type; + dev_type = device_type; } BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], @@ -790,11 +794,11 @@ bool is_le_audio_capable_during_service_discovery(const RawAddress& bd_addr) { ******************************************************************************/ static void btif_dm_cb_create_bond(const RawAddress bd_addr, tBT_TRANSPORT transport) { - bool is_hid = check_cod(&bd_addr, COD_HID_POINTING); + bool is_hid = check_cod_hid_major(bd_addr, COD_HID_POINTING); bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING); if (transport == BT_TRANSPORT_AUTO && is_device_le_audio_capable(bd_addr)) { - LOG_INFO("LE Audio capable, forcing LE transport for Bonding"); + LOG_DEBUG("LE Audio capable, forcing LE transport for Bonding"); transport = BT_TRANSPORT_LE; } @@ -871,18 +875,27 @@ static void btif_dm_cb_create_bond_le(const RawAddress bd_addr, * encrypted * ******************************************************************************/ -uint16_t btif_dm_get_connection_state(const RawAddress* bd_addr) { - uint16_t rc = BTA_DmGetConnectionState(*bd_addr); - - if (rc != 0) { - if (BTM_IsEncrypted(*bd_addr, BT_TRANSPORT_BR_EDR)) { +uint16_t btif_dm_get_connection_state(const RawAddress& bd_addr) { + uint16_t rc = 0; + if (BTA_DmGetConnectionState(bd_addr)) { + rc = (uint16_t) true; + if (BTM_IsEncrypted(bd_addr, BT_TRANSPORT_BR_EDR)) { rc |= ENCRYPTED_BREDR; } - if (BTM_IsEncrypted(*bd_addr, BT_TRANSPORT_LE)) { + if (BTM_IsEncrypted(bd_addr, BT_TRANSPORT_LE)) { rc |= ENCRYPTED_LE; } + } else { + LOG_INFO("Acl is not connected to peer:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } + BTM_LogHistory( + kBtmLogTag, bd_addr, "Get connection state", + base::StringPrintf("connected:%c classic_encrypted:%c le_encrypted:%c", + (rc & (int)true) ? 'T' : 'F', + (rc & ENCRYPTED_BREDR) ? 'T' : 'F', + (rc & ENCRYPTED_LE) ? 'T' : 'F')); return rc; } @@ -925,8 +938,7 @@ static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ* p_pin_req) { if (pairing_cb.state == BT_BOND_STATE_BONDING && bd_addr != pairing_cb.bd_addr) { - BTIF_TRACE_WARNING("%s(): already in bonding state, reject request", - __FUNCTION__); + LOG_WARN("already in bonding state, reject request"); return; } @@ -935,7 +947,7 @@ static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ* p_pin_req) { cod = devclass2uint(p_pin_req->dev_class); if (cod == 0) { - BTIF_TRACE_DEBUG("%s cod is 0, set as unclassified", __func__); + LOG_WARN("cod is 0, set as unclassified"); cod = COD_UNCLASSIFIED; } @@ -946,13 +958,13 @@ static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ* p_pin_req) { check_cod(&bd_addr, COD_AV_HEADPHONES) || check_cod(&bd_addr, COD_AV_PORTABLE_AUDIO) || check_cod(&bd_addr, COD_AV_HIFI_AUDIO) || - check_cod(&bd_addr, COD_HID_POINTING)) { + check_cod_hid_major(bd_addr, COD_HID_POINTING)) { /* Check if this device can be auto paired */ if (!interop_match_addr(INTEROP_DISABLE_AUTO_PAIRING, &bd_addr) && !interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, (const char*)bd_name.name) && (pairing_cb.autopair_attempts == 0)) { - BTIF_TRACE_DEBUG("%s() Attempting auto pair", __func__); + LOG_DEBUG("Attempting auto pair w/ IOP"); pin_code.pin[0] = 0x30; pin_code.pin[1] = 0x30; pin_code.pin[2] = 0x30; @@ -962,12 +974,12 @@ static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ* p_pin_req) { BTA_DmPinReply(bd_addr, true, 4, pin_code.pin); return; } - } else if (check_cod(&bd_addr, COD_HID_KEYBOARD) || - check_cod(&bd_addr, COD_HID_COMBO)) { + } else if (check_cod_hid_major(bd_addr, COD_HID_KEYBOARD) || + check_cod_hid_major(bd_addr, COD_HID_COMBO)) { if ((interop_match_addr(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN, &bd_addr) == true) && (pairing_cb.autopair_attempts == 0)) { - BTIF_TRACE_DEBUG("%s() Attempting auto pair", __func__); + LOG_DEBUG("Attempting auto pair w/ IOP"); pin_code.pin[0] = 0x30; pin_code.pin[1] = 0x30; pin_code.pin[2] = 0x30; @@ -1002,8 +1014,10 @@ static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ* p_ssp_cfm_req) { uint32_t cod; int dev_type; - BTIF_TRACE_DEBUG("%s", __func__); - + LOG_VERBOSE("addr:%s, just_works:%d, loc_auth_req=%d, rmt_auth_req=%d", + ADDRESS_TO_LOGGABLE_CSTR(p_ssp_cfm_req->bd_addr), + p_ssp_cfm_req->just_works, p_ssp_cfm_req->loc_auth_req, + p_ssp_cfm_req->rmt_auth_req); /* Remote properties update */ if (BTM_GetPeerDeviceTypeFromFeatures(p_ssp_cfm_req->bd_addr) == BT_DEVICE_TYPE_DUMO) { @@ -1021,8 +1035,7 @@ static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ* p_ssp_cfm_req) { if (pairing_cb.state == BT_BOND_STATE_BONDING && bd_addr != pairing_cb.bd_addr) { - BTIF_TRACE_WARNING("%s(): already in bonding state, reject request", - __FUNCTION__); + LOG_WARN("already in bonding state, reject request"); btif_dm_ssp_reply(bd_addr, BT_SSP_VARIANT_PASSKEY_CONFIRMATION, 0); return; } @@ -1031,18 +1044,14 @@ static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ* p_ssp_cfm_req) { */ bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING); - BTIF_TRACE_EVENT("%s: just_works:%d, loc_auth_req=%d, rmt_auth_req=%d", - __func__, p_ssp_cfm_req->just_works, - p_ssp_cfm_req->loc_auth_req, p_ssp_cfm_req->rmt_auth_req); - /* if just_works and bonding bit is not set treat this as temporary */ if (p_ssp_cfm_req->just_works && !(p_ssp_cfm_req->loc_auth_req & BTM_AUTH_BONDS) && !(p_ssp_cfm_req->rmt_auth_req & BTM_AUTH_BONDS) && - !(check_cod((RawAddress*)&p_ssp_cfm_req->bd_addr, COD_HID_POINTING))) - pairing_cb.bond_type = tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY; + !(check_cod_hid_major(p_ssp_cfm_req->bd_addr, COD_HID_POINTING))) + pairing_cb.bond_type = BOND_TYPE_TEMPORARY; else - pairing_cb.bond_type = tBTM_SEC_DEV_REC::BOND_TYPE_PERSISTENT; + pairing_cb.bond_type = BOND_TYPE_PERSISTENT; btm_set_bond_type_dev(p_ssp_cfm_req->bd_addr, pairing_cb.bond_type); @@ -1051,12 +1060,10 @@ static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ* p_ssp_cfm_req) { /* If JustWorks auto-accept */ if (p_ssp_cfm_req->just_works) { /* Pairing consent for JustWorks NOT needed if: - * 1. Incoming temporary pairing is detected + * Incoming temporary pairing is detected */ - if (is_incoming && - pairing_cb.bond_type == tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY) { - BTIF_TRACE_EVENT( - "%s: Auto-accept JustWorks pairing for temporary incoming", __func__); + if (is_incoming && pairing_cb.bond_type == BOND_TYPE_TEMPORARY) { + LOG_DEBUG("Auto-accept JustWorks incoming pairing for temporary bonding"); btif_dm_ssp_reply(bd_addr, BT_SSP_VARIANT_CONSENT, true); return; } @@ -1065,7 +1072,7 @@ static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ* p_ssp_cfm_req) { cod = devclass2uint(p_ssp_cfm_req->dev_class); if (cod == 0) { - LOG_INFO("%s cod is 0, set as unclassified", __func__); + LOG_WARN("cod is 0, set as unclassified"); cod = COD_UNCLASSIFIED; } @@ -1087,7 +1094,7 @@ static void btif_dm_ssp_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) { uint32_t cod; int dev_type; - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_ssp_key_notif->bd_addr)); /* Remote properties update */ if (BTM_GetPeerDeviceTypeFromFeatures(p_ssp_key_notif->bd_addr) == @@ -1110,13 +1117,13 @@ static void btif_dm_ssp_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) { cod = devclass2uint(p_ssp_key_notif->dev_class); if (cod == 0) { - LOG_INFO("%s cod is 0, set as unclassified", __func__); + LOG_WARN("cod is 0, set as unclassified"); cod = COD_UNCLASSIFIED; } BTM_LogHistory( kBtmLogTagCallback, bd_addr, "Ssp request", - base::StringPrintf("name:\"%s\" passkey:%u", PRIVATE_NAME(bd_name.name), + base::StringPrintf("name:'%s' passkey:%u", PRIVATE_NAME(bd_name.name), p_ssp_key_notif->passkey)); GetInterfaceToProfiles()->events->invoke_ssp_request_cb( bd_addr, bd_name, cod, BT_SSP_VARIANT_PASSKEY_NOTIFICATION, @@ -1137,9 +1144,8 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { bt_bond_state_t state = BT_BOND_STATE_NONE; bool skip_sdp = false; - BTIF_TRACE_DEBUG("%s: bond state=%d, success=%d, key_present=%d", __func__, - pairing_cb.state, p_auth_cmpl->success, - p_auth_cmpl->key_present); + LOG_INFO("bond state=%d, success=%d, key_present=%d", pairing_cb.state, + p_auth_cmpl->success, p_auth_cmpl->key_present); pairing_cb.fail_reason = p_auth_cmpl->fail_reason; @@ -1150,11 +1156,12 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) || (p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) || (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB_P_256) || - pairing_cb.bond_type == tBTM_SEC_DEV_REC::BOND_TYPE_PERSISTENT) { + pairing_cb.bond_type == BOND_TYPE_PERSISTENT) { bt_status_t ret; - BTIF_TRACE_DEBUG("%s: Storing link key. key_type=0x%x, bond_type=%d", - __func__, p_auth_cmpl->key_type, pairing_cb.bond_type); + if (!bd_addr.IsEmpty()) { + LOG_DEBUG("Storing link key. key_type=0x%x, bond_type=%d", + p_auth_cmpl->key_type, pairing_cb.bond_type); ret = btif_storage_add_bonded_device(&bd_addr, p_auth_cmpl->key, p_auth_cmpl->key_type, pairing_cb.pin_code_len); @@ -1164,12 +1171,10 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { } ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret); } else { - BTIF_TRACE_DEBUG( - "%s: Temporary key. Not storing. key_type=0x%x, bond_type=%d", - __func__, p_auth_cmpl->key_type, pairing_cb.bond_type); - if (pairing_cb.bond_type == tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY) { - BTIF_TRACE_DEBUG("%s: sending BT_BOND_STATE_NONE for Temp pairing", - __func__); + LOG_DEBUG("Temporary key. Not storing. key_type=0x%x, bond_type=%d", + p_auth_cmpl->key_type, pairing_cb.bond_type); + if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) { + LOG_DEBUG("sending BT_BOND_STATE_NONE for Temp pairing"); btif_storage_remove_bonded_device(&bd_addr); bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_NONE); return; @@ -1190,9 +1195,8 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { // the derived link key. if (p_auth_cmpl->bd_addr != pairing_cb.bd_addr && (!pairing_cb.ble.is_penc_key_rcvd)) { - LOG(INFO) << __func__ - << " skipping SDP since we did not initiate pairing to " - << p_auth_cmpl->bd_addr; + LOG_WARN("skipping SDP for unknown device %s", + ADDRESS_TO_LOGGABLE_CSTR(p_auth_cmpl->bd_addr)); return; } @@ -1207,7 +1211,7 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { bool is_crosskey = false; if (pairing_cb.state == BT_BOND_STATE_BONDING && p_auth_cmpl->is_ctkd) { - LOG_INFO("bonding initiated due to cross key pairing"); + LOG_DEBUG("bonding initiated due to cross key pairing"); is_crosskey = true; } @@ -1222,13 +1226,13 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { bd_addr = p_auth_cmpl->bd_addr; if (check_sdp_bl(&bd_addr) && check_cod_hid(&bd_addr)) { - LOG_WARN("%s:skip SDP", __func__); + LOG_WARN("skip SDP"); skip_sdp = true; } if (!pairing_cb.is_local_initiated && skip_sdp) { bond_state_changed(status, bd_addr, state); - LOG_WARN("%s: Incoming HID Connection", __func__); + LOG_WARN("Incoming HID Connection"); bt_property_t prop; Uuid uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE); @@ -1241,9 +1245,7 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { } else { /* If bonded due to cross-key, save the static address too*/ if (is_crosskey) { - BTIF_TRACE_DEBUG( - "%s: bonding initiated due to cross key, adding static address", - __func__); + LOG_DEBUG("bonding initiated due to cross key, adding static address"); pairing_cb.static_bdaddr = bd_addr; } if (!is_crosskey || @@ -1279,6 +1281,8 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { // Do not call bond_state_changed_cb yet. Wait until remote service // discovery is complete } else { + LOG_WARN("Bonding failed with failure reason:%s", + hci_reason_code_text(p_auth_cmpl->fail_reason).c_str()); bool is_bonded_device_removed = false; // Map the HCI fail reason to bt status switch (p_auth_cmpl->fail_reason) { @@ -1286,8 +1290,8 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { case HCI_ERR_LMP_RESPONSE_TIMEOUT: if (interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &bd_addr) && pairing_cb.timeout_retries) { - BTIF_TRACE_WARNING("%s() - Pairing timeout; retrying (%d) ...", - __func__, pairing_cb.timeout_retries); + LOG_WARN("Pairing timeout; retrying (%d) ...", + pairing_cb.timeout_retries); --pairing_cb.timeout_retries; if (addr_type == BLE_ADDR_RANDOM) { btif_dm_cb_create_bond_le(bd_addr, addr_type); @@ -1318,12 +1322,11 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { case HCI_ERR_INSUFFCIENT_SECURITY: case HCI_ERR_PEER_USER: case HCI_ERR_UNSPECIFIED: - BTIF_TRACE_DEBUG(" %s() Authentication fail reason %d", __func__, - p_auth_cmpl->fail_reason); + LOG_WARN("Authentication fail:%s", + hci_reason_code_text(p_auth_cmpl->fail_reason).c_str()); if (pairing_cb.autopair_attempts == 1) { /* Create the Bond once again */ - BTIF_TRACE_WARNING("%s() auto pair failed. Reinitiate Bond", - __func__); + LOG_WARN("auto pair failed. Reinitiate Bond"); if (addr_type == BLE_ADDR_RANDOM) { btif_dm_cb_create_bond_le(bd_addr, addr_type); } else { @@ -1340,10 +1343,9 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { status = BT_STATUS_FAIL; } /* Special Handling for HID Devices */ - if (check_cod(&bd_addr, COD_HID_POINTING)) { + if (check_cod_hid_major(bd_addr, COD_HID_POINTING)) { /* Remove Device as bonded in nvram as authentication failed */ - BTIF_TRACE_DEBUG("%s(): removing hid pointing device from nvram", - __func__); + LOG_VERBOSE("removing hid pointing device from nvram"); is_bonded_device_removed = false; } // Report bond state change to java only if we are bonding to a device or @@ -1365,10 +1367,10 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { *****************************************************************************/ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_search_data) { - BTIF_TRACE_EVENT("%s event=%s", __func__, dump_dm_search_event(event)); + LOG_VERBOSE("event=%s", dump_dm_search_event(event)); switch (event) { - case BTA_DM_DISC_RES_EVT: { + case BTA_DM_NAME_READ_EVT: { /* Remote name update */ if (strlen((const char*)p_search_data->disc_res.bd_name)) { /** Fix inquiry time too long @{ */ @@ -1393,15 +1395,15 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, BTIF_STORAGE_FILL_PROPERTY(&properties[2], BT_PROPERTY_CLASS_OF_DEVICE, sizeof(uint32_t), &cod); if (btif_storage_get_remote_device_property( &bdaddr, &properties[2]) == BT_STATUS_SUCCESS) { - BTIF_TRACE_DEBUG("%s, BTA_DM_DISC_RES_EVT, cod in storage = 0x%08x", __func__, cod); + LOG_VERBOSE("BTA_DM_NAME_READ_EVT, cod in storage=0x%08x", cod); } else { - BTIF_TRACE_DEBUG("%s, BTA_DM_DISC_RES_EVT, no cod in storage", __func__); + LOG_DEBUG("BTA_DM_NAME_READ_EVT, no cod in storage"); cod = 0; } if (cod != 0) { BTIF_STORAGE_FILL_PROPERTY(&properties[1], BT_PROPERTY_BDADDR, sizeof(bdaddr), &bdaddr); BTIF_STORAGE_FILL_PROPERTY(&properties[2], BT_PROPERTY_CLASS_OF_DEVICE, sizeof(uint32_t), &cod); - BTIF_TRACE_DEBUG("%s: Now we have name and cod, report to JNI", __func__); + LOG_DEBUG("report new device to JNI"); GetInterfaceToProfiles()->events->invoke_device_found_cb(3, properties); } /** @} */ @@ -1422,9 +1424,8 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, } RawAddress& bdaddr = p_search_data->inq_res.bd_addr; - BTIF_TRACE_DEBUG("%s() %s device_type = 0x%x\n", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bdaddr), - p_search_data->inq_res.device_type); + LOG_VERBOSE("addr:%s device_type=0x%x", ADDRESS_TO_LOGGABLE_CSTR(bdaddr), + p_search_data->inq_res.device_type); bdname.name[0] = 0; if (!check_eir_remote_name(p_search_data, bdname.name, &remote_name_len)) @@ -1439,7 +1440,7 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, { bt_property_t properties[10]; // increase when properties are added - bt_device_type_t dev_type; + uint32_t dev_type; uint32_t num_properties = 0; bt_status_t status; tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC; @@ -1460,7 +1461,7 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, /* DEV_CLASS */ uint32_t cod = devclass2uint(p_search_data->inq_res.dev_class); - BTIF_TRACE_DEBUG("%s cod is 0x%06x", __func__, cod); + LOG_VERBOSE("cod is 0x%06x", cod); if (cod != 0) { BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), @@ -1468,6 +1469,12 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, num_properties++; } + LOG_VERBOSE("clock_offset is 0x%x", + p_search_data->inq_res.clock_offset); + if (p_search_data->inq_res.clock_offset & BTM_CLOCK_OFFSET_VALID) { + btif_set_device_clockoffset(bdaddr, (int)p_search_data->inq_res.clock_offset); + } + /* DEV_TYPE */ /* FixMe: Assumption is that bluetooth.h and BTE enums match */ @@ -1588,8 +1595,8 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, if (restrict_report && p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE && !(p_search_data->inq_res.ble_evt_type & BTM_BLE_CONNECTABLE_MASK)) { - LOG_INFO("%s: Ble device is not connectable", - ADDRESS_TO_LOGGABLE_CSTR(bdaddr)); + LOG_DEBUG("Ble device %s is not connectable", + ADDRESS_TO_LOGGABLE_CSTR(bdaddr)); break; } @@ -1759,9 +1766,8 @@ static void btif_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, pairing_cb.sdp_attempts = 0; // Send UUIDs discovered through EIR to Java to unblock pairing intent - // when SDP failed or no UUID is discovered - if (p_data->disc_res.result != BTA_SUCCESS || - p_data->disc_res.num_uuids == 0) { + // when SDP failed + if (p_data->disc_res.result != BTA_SUCCESS) { auto uuids_iter = eir_uuids_cache.find(bd_addr); if (uuids_iter != eir_uuids_cache.end()) { num_eir_uuids = uuids_iter->second.size(); @@ -1788,7 +1794,7 @@ static void btif_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, // Both SDP and bonding are done, clear pairing control block in case // it is not already cleared pairing_cb = {}; - LOG_INFO("clearing btif pairing_cb"); + LOG_DEBUG("clearing btif pairing_cb"); } } @@ -1864,13 +1870,13 @@ static void btif_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED) { // Both SDP and bonding are either done, or not scheduled, // we are safe to clear the service discovery part of CB. - LOG_INFO("clearing pairing_cb"); + LOG_DEBUG("clearing pairing_cb"); pairing_cb = {}; } } } else { - LOG_INFO("New GATT over SDP UUIDs for %s:", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_DEBUG("New GATT over SDP UUIDs for %s:", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); BTM_LogHistory(kBtmLogTag, bd_addr, "Discovered GATT services using SDP transport"); } @@ -1916,24 +1922,40 @@ static void btif_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, } Uuid existing_uuids[BT_MAX_NUM_UUIDS] = {}; + + // Look up UUIDs using pseudo address (either RPA or static address) bt_status_t existing_lookup_result = btif_get_existing_uuids(&bd_addr, existing_uuids); - if (existing_lookup_result == BT_STATUS_FAIL && - bd_addr != static_addr_copy) { + + if (existing_lookup_result != BT_STATUS_FAIL) { + LOG_INFO("Got some existing UUIDs by address %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + + for (int i = 0; i < BT_MAX_NUM_UUIDS; i++) { + Uuid uuid = existing_uuids[i]; + if (uuid.IsEmpty()) { + continue; + } + uuids.insert(uuid); + } + } + + if (bd_addr != static_addr_copy) { + // Look up UUID using static address, if different than sudo address existing_lookup_result = btif_get_existing_uuids(&static_addr_copy, existing_uuids); if (existing_lookup_result != BT_STATUS_FAIL) { LOG_INFO("Got some existing UUIDs by static address %s", ADDRESS_TO_LOGGABLE_CSTR(static_addr_copy)); + for (int i = 0; i < BT_MAX_NUM_UUIDS; i++) { + Uuid uuid = existing_uuids[i]; + if (uuid.IsEmpty()) { + continue; + } + uuids.insert(uuid); + } } } - for (int i = 0; i < BT_MAX_NUM_UUIDS; i++) { - Uuid uuid = existing_uuids[i]; - if (uuid.IsEmpty()) { - continue; - } - uuids.insert(uuid); - } for (auto& uuid : uuids) { auto uuid_128bit = uuid.To128BitBE(); @@ -1997,6 +2019,10 @@ static void btif_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, BT_STATUS_SUCCESS, bd_addr, 1, &prop_did); } break; + case BTA_DM_NAME_READ_EVT: { + LOG_INFO("Skipping name read event - called on bad callback."); + } break; + default: { ASSERTC(0, "unhandled search services event", event); } break; @@ -2057,7 +2083,7 @@ void BTIF_dm_report_inquiry_status_change(tBTM_STATUS status) { } void BTIF_dm_on_hw_error() { - BTIF_TRACE_ERROR("Received H/W Error. "); + LOG_ERROR("Received H/W Error"); usleep(100000); /* 100milliseconds */ /* Killing the process to force a restart as part of fault tolerance */ kill(getpid(), SIGKILL); @@ -2086,7 +2112,7 @@ void BTIF_dm_enable() { bool ble_privacy_enabled = osi_property_get_bool(PROPERTY_BLE_PRIVACY_ENABLED, /*default=*/true); - LOG_INFO("%s BLE Privacy: %d", __func__, ble_privacy_enabled); + LOG_INFO("Local BLE Privacy enabled:%d", ble_privacy_enabled); BTA_DmBleConfigLocalPrivacy(ble_privacy_enabled); /* for each of the enabled services in the mask, trigger the profile @@ -2099,7 +2125,7 @@ void BTIF_dm_enable() { } /* clear control blocks */ pairing_cb = {}; - pairing_cb.bond_type = tBTM_SEC_DEV_REC::BOND_TYPE_PERSISTENT; + pairing_cb.bond_type = BOND_TYPE_PERSISTENT; // Enable address consolidation. btif_storage_load_le_devices(); @@ -2129,18 +2155,17 @@ void BTIF_dm_disable() { /******************************************************************************* * - * Function btif_dm_upstreams_cback + * Function btif_dm_sec_evt * - * Description Executes UPSTREAMS events in btif context + * Description Executes security related events * * Returns void * ******************************************************************************/ -static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { - tBTA_DM_SEC* p_data = (tBTA_DM_SEC*)p_param; +void btif_dm_sec_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { RawAddress bd_addr; - BTIF_TRACE_EVENT("%s: ev: %s", __func__, dump_dm_event(event)); + LOG_VERBOSE("ev:%s", dump_dm_event(event)); switch (event) { case BTA_DM_PIN_REQ_EVT: @@ -2154,8 +2179,7 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { case BTA_DM_BOND_CANCEL_CMPL_EVT: if (is_bonding_or_sdp()) { bd_addr = pairing_cb.bd_addr; - btm_set_bond_type_dev(pairing_cb.bd_addr, - tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN); + btm_set_bond_type_dev(pairing_cb.bd_addr, BOND_TYPE_UNKNOWN); bond_state_changed((bt_status_t)p_data->bond_cancel_cmpl.result, bd_addr, BT_BOND_STATE_NONE); } @@ -2169,79 +2193,17 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_DM_DEV_UNPAIRED_EVT: - bd_addr = p_data->link_down.bd_addr; - btm_set_bond_type_dev(p_data->link_down.bd_addr, - tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN); + bd_addr = p_data->dev_unpair.bd_addr; + btm_set_bond_type_dev(p_data->dev_unpair.bd_addr, BOND_TYPE_UNKNOWN); GetInterfaceToProfiles()->removeDeviceFromProfiles(bd_addr); btif_storage_remove_bonded_device(&bd_addr); bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_NONE); break; - case BTA_DM_LINK_UP_EVT: - bd_addr = p_data->link_up.bd_addr; - BTIF_TRACE_DEBUG("BTA_DM_LINK_UP_EVT. Sending BT_ACL_STATE_CONNECTED"); - - btif_update_remote_version_property(&bd_addr); - - GetInterfaceToProfiles()->events->invoke_acl_state_changed_cb( - BT_STATUS_SUCCESS, bd_addr, BT_ACL_STATE_CONNECTED, - (int)p_data->link_up.transport_link_type, HCI_SUCCESS, - btm_is_acl_locally_initiated() - ? bt_conn_direction_t::BT_CONN_DIRECTION_OUTGOING - : bt_conn_direction_t::BT_CONN_DIRECTION_INCOMING, - p_data->link_up.acl_handle); - break; - - case BTA_DM_LINK_UP_FAILED_EVT: - GetInterfaceToProfiles()->events->invoke_acl_state_changed_cb( - BT_STATUS_FAIL, p_data->link_up_failed.bd_addr, - BT_ACL_STATE_DISCONNECTED, p_data->link_up_failed.transport_link_type, - p_data->link_up_failed.status, - btm_is_acl_locally_initiated() - ? bt_conn_direction_t::BT_CONN_DIRECTION_OUTGOING - : bt_conn_direction_t::BT_CONN_DIRECTION_INCOMING, - INVALID_ACL_HANDLE); - break; - - case BTA_DM_LINK_DOWN_EVT: { - bd_addr = p_data->link_down.bd_addr; - btm_set_bond_type_dev(p_data->link_down.bd_addr, - tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN); - GetInterfaceToProfiles()->onLinkDown(bd_addr); - - bt_conn_direction_t direction; - switch (btm_get_acl_disc_reason_code()) { - case HCI_ERR_PEER_USER: - case HCI_ERR_REMOTE_LOW_RESOURCE: - case HCI_ERR_REMOTE_POWER_OFF: - direction = bt_conn_direction_t::BT_CONN_DIRECTION_INCOMING; - break; - case HCI_ERR_CONN_CAUSE_LOCAL_HOST: - case HCI_ERR_HOST_REJECT_SECURITY: - direction = bt_conn_direction_t::BT_CONN_DIRECTION_OUTGOING; - break; - default: - direction = bt_conn_direction_t::BT_CONN_DIRECTION_UNKNOWN; - } - - GetInterfaceToProfiles()->events->invoke_acl_state_changed_cb( - BT_STATUS_SUCCESS, bd_addr, BT_ACL_STATE_DISCONNECTED, - (int)p_data->link_down.transport_link_type, - static_cast(btm_get_acl_disc_reason_code()), - direction, INVALID_ACL_HANDLE); - LOG_DEBUG( - "Sent BT_ACL_STATE_DISCONNECTED upward as ACL link down event " - "device:%s reason:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), - hci_reason_code_text( - static_cast(btm_get_acl_disc_reason_code())) - .c_str()); - } break; - case BTA_DM_BLE_KEY_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_KEY_EVT key_type=0x%02x ", - p_data->ble_key.key_type); + LOG_VERBOSE("BTA_DM_BLE_KEY_EVT key_type=0x%02x ", + p_data->ble_key.key_type); /* If this pairing is by-product of local initiated GATT client Read or Write, @@ -2250,95 +2212,93 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { have setup properly. Setup pairing_cb and notify App about Bonding state now*/ if (pairing_cb.state != BT_BOND_STATE_BONDING) { - BTIF_TRACE_DEBUG( - "Bond state not sent to App so far.Notify the app now"); + LOG_VERBOSE("Bond state not sent to App so far.Notify the app now"); bond_state_changed(BT_STATUS_SUCCESS, p_data->ble_key.bd_addr, BT_BOND_STATE_BONDING); } else if (pairing_cb.bd_addr != p_data->ble_key.bd_addr) { - BTIF_TRACE_ERROR("BD mismatch discard BLE key_type=%d ", - p_data->ble_key.key_type); + LOG_ERROR("BD mismatch discard BLE key_type=%d ", + p_data->ble_key.key_type); break; } switch (p_data->ble_key.key_type) { case BTM_LE_KEY_PENC: - BTIF_TRACE_DEBUG("Rcv BTM_LE_KEY_PENC"); + LOG_VERBOSE("Rcv BTM_LE_KEY_PENC"); pairing_cb.ble.is_penc_key_rcvd = true; pairing_cb.ble.penc_key = p_data->ble_key.p_key_value->penc_key; break; case BTM_LE_KEY_PID: - BTIF_TRACE_DEBUG("Rcv BTM_LE_KEY_PID"); + LOG_VERBOSE("Rcv BTM_LE_KEY_PID"); pairing_cb.ble.is_pid_key_rcvd = true; pairing_cb.ble.pid_key = p_data->ble_key.p_key_value->pid_key; break; case BTM_LE_KEY_PCSRK: - BTIF_TRACE_DEBUG("Rcv BTM_LE_KEY_PCSRK"); + LOG_VERBOSE("Rcv BTM_LE_KEY_PCSRK"); pairing_cb.ble.is_pcsrk_key_rcvd = true; pairing_cb.ble.pcsrk_key = p_data->ble_key.p_key_value->pcsrk_key; break; case BTM_LE_KEY_LENC: - BTIF_TRACE_DEBUG("Rcv BTM_LE_KEY_LENC"); + LOG_VERBOSE("Rcv BTM_LE_KEY_LENC"); pairing_cb.ble.is_lenc_key_rcvd = true; pairing_cb.ble.lenc_key = p_data->ble_key.p_key_value->lenc_key; break; case BTM_LE_KEY_LCSRK: - BTIF_TRACE_DEBUG("Rcv BTM_LE_KEY_LCSRK"); + LOG_VERBOSE("Rcv BTM_LE_KEY_LCSRK"); pairing_cb.ble.is_lcsrk_key_rcvd = true; pairing_cb.ble.lcsrk_key = p_data->ble_key.p_key_value->lcsrk_key; break; case BTM_LE_KEY_LID: - BTIF_TRACE_DEBUG("Rcv BTM_LE_KEY_LID"); + LOG_VERBOSE("Rcv BTM_LE_KEY_LID"); pairing_cb.ble.is_lidk_key_rcvd = true; break; default: - BTIF_TRACE_ERROR("unknown BLE key type (0x%02x)", - p_data->ble_key.key_type); + LOG_ERROR("unknown BLE key type (0x%02x)", p_data->ble_key.key_type); break; } break; case BTA_DM_BLE_CONSENT_REQ_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_CONSENT_REQ_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_CONSENT_REQ_EVT"); btif_dm_ble_sec_req_evt(&p_data->ble_req, true); break; case BTA_DM_BLE_SEC_REQ_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_SEC_REQ_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_SEC_REQ_EVT"); btif_dm_ble_sec_req_evt(&p_data->ble_req, false); break; case BTA_DM_BLE_PASSKEY_NOTIF_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_NOTIF_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_PASSKEY_NOTIF_EVT"); btif_dm_ble_key_notif_evt(&p_data->key_notif); break; case BTA_DM_BLE_PASSKEY_REQ_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_REQ_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_PASSKEY_REQ_EVT"); btif_dm_ble_passkey_req_evt(&p_data->pin_req); break; case BTA_DM_BLE_NC_REQ_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_REQ_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_PASSKEY_REQ_EVT"); btif_dm_ble_key_nc_req_evt(&p_data->key_notif); break; case BTA_DM_BLE_OOB_REQ_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_OOB_REQ_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_OOB_REQ_EVT"); btif_dm_ble_oob_req_evt(&p_data->rmt_oob); break; case BTA_DM_BLE_SC_OOB_REQ_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_SC_OOB_REQ_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_SC_OOB_REQ_EVT"); btif_dm_ble_sc_oob_req_evt(&p_data->rmt_oob); break; case BTA_DM_BLE_SC_CR_LOC_OOB_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_SC_CR_LOC_OOB_EVT"); + LOG_VERBOSE("BTA_DM_BLE_SC_CR_LOC_OOB_EVT"); btif_dm_proc_loc_oob(BT_TRANSPORT_LE, true, p_data->local_oob_data.local_oob_c, p_data->local_oob_data.local_oob_r); break; case BTA_DM_BLE_LOCAL_IR_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_IR_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_LOCAL_IR_EVT"); ble_local_key_cb.is_id_keys_rcvd = true; ble_local_key_cb.id_keys.irk = p_data->ble_id_keys.irk; ble_local_key_cb.id_keys.ir = p_data->ble_id_keys.ir; @@ -2351,7 +2311,7 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { BTIF_DM_LE_LOCAL_KEY_DHK); break; case BTA_DM_BLE_LOCAL_ER_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_ER_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_LOCAL_ER_EVT"); ble_local_key_cb.is_er_rcvd = true; ble_local_key_cb.er = p_data->ble_er; btif_storage_add_ble_local_key(ble_local_key_cb.er, @@ -2359,37 +2319,107 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_DM_BLE_AUTH_CMPL_EVT: - BTIF_TRACE_DEBUG("BTA_DM_BLE_AUTH_CMPL_EVT. "); + LOG_VERBOSE("BTA_DM_BLE_AUTH_CMPL_EVT"); btif_dm_ble_auth_cmpl_evt(&p_data->auth_cmpl); break; - case BTA_DM_LE_FEATURES_READ: - btif_get_adapter_property(BT_PROPERTY_LOCAL_LE_FEATURES); + case BTA_DM_LE_ADDR_ASSOC_EVT: + GetInterfaceToProfiles()->events->invoke_le_address_associate_cb( + p_data->proc_id_addr.pairing_bda, p_data->proc_id_addr.id_addr); break; - case BTA_DM_LE_ADDR_ASSOC_EVT: + case BTA_DM_SIRK_VERIFICATION_REQ_EVT: GetInterfaceToProfiles()->events->invoke_le_address_associate_cb( p_data->proc_id_addr.pairing_bda, p_data->proc_id_addr.id_addr); break; default: - BTIF_TRACE_WARNING("%s: unhandled event (%d)", __func__, event); + LOG_WARN("unhandled event(%d)", event); break; } } /******************************************************************************* * - * Function bte_dm_evt + * Function bte_dm_acl_evt * - * Description Switches context from BTE to BTIF for all DM events + * Description BTIF handler for ACL up/down, identity address report events * * Returns void * ******************************************************************************/ +void btif_dm_acl_evt(tBTA_DM_ACL_EVT event, tBTA_DM_ACL* p_data) { + RawAddress bd_addr; + + switch (event) { + case BTA_DM_LINK_UP_EVT: + bd_addr = p_data->link_up.bd_addr; + LOG_VERBOSE("BTA_DM_LINK_UP_EVT. Sending BT_ACL_STATE_CONNECTED"); + + btif_update_remote_version_property(&bd_addr); + + GetInterfaceToProfiles()->events->invoke_acl_state_changed_cb( + BT_STATUS_SUCCESS, bd_addr, BT_ACL_STATE_CONNECTED, + (int)p_data->link_up.transport_link_type, HCI_SUCCESS, + btm_is_acl_locally_initiated() + ? bt_conn_direction_t::BT_CONN_DIRECTION_OUTGOING + : bt_conn_direction_t::BT_CONN_DIRECTION_INCOMING, + p_data->link_up.acl_handle); + break; + + case BTA_DM_LINK_UP_FAILED_EVT: + GetInterfaceToProfiles()->events->invoke_acl_state_changed_cb( + BT_STATUS_FAIL, p_data->link_up_failed.bd_addr, + BT_ACL_STATE_DISCONNECTED, p_data->link_up_failed.transport_link_type, + p_data->link_up_failed.status, + btm_is_acl_locally_initiated() + ? bt_conn_direction_t::BT_CONN_DIRECTION_OUTGOING + : bt_conn_direction_t::BT_CONN_DIRECTION_INCOMING, + INVALID_ACL_HANDLE); + break; -void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { - btif_dm_upstreams_evt(event, (char*)p_data); + case BTA_DM_LINK_DOWN_EVT: { + bd_addr = p_data->link_down.bd_addr; + btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN); + GetInterfaceToProfiles()->onLinkDown(bd_addr); + + bt_conn_direction_t direction; + switch (btm_get_acl_disc_reason_code()) { + case HCI_ERR_PEER_USER: + case HCI_ERR_REMOTE_LOW_RESOURCE: + case HCI_ERR_REMOTE_POWER_OFF: + direction = bt_conn_direction_t::BT_CONN_DIRECTION_INCOMING; + break; + case HCI_ERR_CONN_CAUSE_LOCAL_HOST: + case HCI_ERR_HOST_REJECT_SECURITY: + direction = bt_conn_direction_t::BT_CONN_DIRECTION_OUTGOING; + break; + default: + direction = bt_conn_direction_t::BT_CONN_DIRECTION_UNKNOWN; + } + GetInterfaceToProfiles()->events->invoke_acl_state_changed_cb( + BT_STATUS_SUCCESS, bd_addr, BT_ACL_STATE_DISCONNECTED, + (int)p_data->link_down.transport_link_type, + static_cast(btm_get_acl_disc_reason_code()), + direction, INVALID_ACL_HANDLE); + LOG_DEBUG( + "Sent BT_ACL_STATE_DISCONNECTED upward as ACL link down event " + "device:%s reason:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + hci_reason_code_text( + static_cast(btm_get_acl_disc_reason_code())) + .c_str()); + } break; + case BTA_DM_LE_FEATURES_READ: + btif_get_adapter_property(BT_PROPERTY_LOCAL_LE_FEATURES); + break; + + + default: { + LOG_ERROR("Unexpected tBTA_DM_ACL_EVT:%d", event); + } break; + + } } /******************************************************************************* @@ -2407,21 +2437,25 @@ static void bta_energy_info_cb(tBTM_BLE_TX_TIME_MS tx_time, tBTM_BLE_ENERGY_USED energy_used, tBTM_CONTRL_STATE ctrl_state, tBTA_STATUS status) { - BTIF_TRACE_DEBUG( - "energy_info_cb-Status:%d,state=%d,tx_t=%ld, rx_t=%ld, " - "idle_time=%ld,used=%ld", + LOG_VERBOSE( + "energy_info_cb-Status:%d,state=%d,tx_t=%u, rx_t=%u, " + "idle_time=%u,used=%u", status, ctrl_state, tx_time, rx_time, idle_time, energy_used); - bt_activity_energy_info energy_info; - energy_info.status = status; - energy_info.ctrl_state = ctrl_state; - energy_info.rx_time = rx_time; - energy_info.tx_time = tx_time; - energy_info.idle_time = idle_time; - energy_info.energy_used = energy_used; - - bt_uid_traffic_t* data = uid_set_read_and_clear(uid_set); - GetInterfaceToProfiles()->events->invoke_energy_info_cb(energy_info, data); + if (uid_set != nullptr) { + bt_activity_energy_info energy_info; + energy_info.status = status; + energy_info.ctrl_state = ctrl_state; + energy_info.rx_time = rx_time; + energy_info.tx_time = tx_time; + energy_info.idle_time = idle_time; + energy_info.energy_used = energy_used; + + bt_uid_traffic_t* data = uid_set_read_and_clear(uid_set); + GetInterfaceToProfiles()->events->invoke_energy_info_cb(energy_info, data); + } else { + LOG_WARN("Energy info event dropped as module is inactive"); + } } /***************************************************************************** @@ -2438,7 +2472,7 @@ static void bta_energy_info_cb(tBTM_BLE_TX_TIME_MS tx_time, * ******************************************************************************/ void btif_dm_start_discovery(void) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("start device discover/inquiry"); BTM_LogHistory( kBtmLogTag, RawAddress::kEmpty, "Device discovery", @@ -2447,8 +2481,7 @@ void btif_dm_start_discovery(void) { /* no race here because we're guaranteed to be in the main thread */ if (bta_dm_is_search_request_queued()) { - LOG_INFO("%s skipping start discovery because a request is queued", - __func__); + LOG_INFO("skipping start discovery because a request is queued"); return; } @@ -2456,6 +2489,7 @@ void btif_dm_start_discovery(void) { btif_dm_inquiry_in_progress = false; /* find nearby devices */ BTA_DmSearch(btif_dm_search_devices_evt); + power_telemetry::GetInstance().LogScanStarted(); } /******************************************************************************* @@ -2484,8 +2518,8 @@ bool btif_dm_pairing_is_busy() { * ******************************************************************************/ void btif_dm_create_bond(const RawAddress bd_addr, int transport) { - BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), transport); + LOG_VERBOSE("bd_addr=%s, transport=%d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + transport); BTM_LogHistory( kBtmLogTag, bd_addr, "Create bond", @@ -2507,8 +2541,8 @@ void btif_dm_create_bond(const RawAddress bd_addr, int transport) { ******************************************************************************/ void btif_dm_create_bond_le(const RawAddress bd_addr, tBLE_ADDR_TYPE addr_type) { - BTIF_TRACE_EVENT("%s: bd_addr=%s, addr_type=%d, transport=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), addr_type); + LOG_VERBOSE("bd_addr=%s, addr_type=%d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + addr_type); const tBLE_BD_ADDR ble_bd_addr{ .type = addr_type, .bda = bd_addr, @@ -2586,7 +2620,7 @@ void btif_dm_create_bond_out_of_band(const RawAddress bd_addr, BT_BOND_STATE_NONE); return; default: - LOG_ERROR("Invalid data present for controller: %d", + LOG_ERROR("Invalid data present for controller:%d", oob_cb.data_present); bond_state_changed(BT_STATUS_PARM_INVALID, bd_addr, BT_BOND_STATE_NONE); @@ -2623,7 +2657,8 @@ void btif_dm_create_bond_out_of_band(const RawAddress bd_addr, break; } pairing_cb.is_local_initiated = true; - BTM_SecAddBleDevice(bd_addr, BT_DEVICE_TYPE_BLE, address_type); + get_btm_client_interface().security.BTM_SecAddBleDevice( + bd_addr, BT_DEVICE_TYPE_BLE, address_type); BTA_DmBond(bd_addr, address_type, transport, BT_DEVICE_TYPE_BLE); break; } @@ -2642,8 +2677,7 @@ void btif_dm_create_bond_out_of_band(const RawAddress bd_addr, * ******************************************************************************/ void btif_dm_cancel_bond(const RawAddress bd_addr) { - BTIF_TRACE_EVENT("%s: bd_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("bd_addr=%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); BTM_LogHistory(kBtmLogTag, bd_addr, "Cancel bond"); @@ -2702,8 +2736,7 @@ void btif_dm_hh_open_failed(RawAddress* bdaddr) { ******************************************************************************/ void btif_dm_remove_bond(const RawAddress bd_addr) { - BTIF_TRACE_EVENT("%s: bd_addr=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("bd_addr=%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); BTM_LogHistory(kBtmLogTag, bd_addr, "Remove bond"); @@ -2719,7 +2752,7 @@ void btif_dm_remove_bond(const RawAddress bd_addr) { &bd_addr) != BT_STATUS_SUCCESS) #endif { - BTIF_TRACE_DEBUG("%s: Removing HH device", __func__); + LOG_DEBUG("Removing HH device"); BTA_DmRemoveDevice(bd_addr); } } @@ -2734,7 +2767,7 @@ void btif_dm_remove_bond(const RawAddress bd_addr) { void btif_dm_pin_reply(const RawAddress bd_addr, uint8_t accept, uint8_t pin_len, bt_pin_code_t pin_code) { - BTIF_TRACE_EVENT("%s: accept=%d", __func__, accept); + LOG_VERBOSE("accept=%d", accept); if (pairing_cb.is_le_only) { int i; @@ -2745,7 +2778,7 @@ void btif_dm_pin_reply(const RawAddress bd_addr, uint8_t accept, } // TODO: // FIXME: should we hide part of passkey here? - BTIF_TRACE_DEBUG("btif_dm_pin_reply: passkey: %d", passkey); + LOG_VERBOSE("btif_dm_pin_reply: passkey: %d", passkey); BTA_DmBlePasskeyReply(bd_addr, accept, passkey); } else { @@ -2764,7 +2797,7 @@ void btif_dm_pin_reply(const RawAddress bd_addr, uint8_t accept, ******************************************************************************/ void btif_dm_ssp_reply(const RawAddress bd_addr, bt_ssp_variant_t variant, uint8_t accept) { - BTIF_TRACE_EVENT("%s: accept=%d", __func__, accept); + LOG_VERBOSE("accept=%d", accept); BTM_LogHistory( kBtmLogTag, bd_addr, "Ssp reply", base::StringPrintf( @@ -2820,7 +2853,7 @@ void btif_dm_get_local_class_of_device(DEV_CLASS device_class) { // If the property is empty, use the default if (prop_cod[0] == '\0') { - LOG_ERROR("%s: COD property is empty", __func__); + LOG_ERROR("COD property is empty"); return; } @@ -2837,7 +2870,7 @@ void btif_dm_get_local_class_of_device(DEV_CLASS device_class) { prop_cod[i] != '\0') { char c = prop_cod[i++]; if (!std::isdigit(c)) { - LOG_ERROR("%s: COD malformed, '%c' is a non-digit", __func__, c); + LOG_ERROR("COD malformed, '%c' is a non-digit", c); return; } value += c; @@ -2845,22 +2878,20 @@ void btif_dm_get_local_class_of_device(DEV_CLASS device_class) { // If we hit the end and it wasn't null terminated then return the default if (i == PROPERTY_VALUE_MAX && prop_cod[PROPERTY_VALUE_MAX - 1] != '\0') { - LOG_ERROR("%s: COD malformed, value was truncated", __func__); + LOG_ERROR("COD malformed, value was truncated"); return; } // Each number in the list must be one byte, meaning 0 (0x00) -> 255 (0xFF) if (value.size() > 3 || value.size() == 0) { - LOG_ERROR("%s: COD malformed, '%s' must be between [0, 255]", __func__, - value.c_str()); + LOG_ERROR("COD malformed, '%s' must be between [0, 255]", value.c_str()); return; } // Grab the value. If it's too large, then return the default uint32_t uint32_val = static_cast(std::stoul(value.c_str())); if (uint32_val > 0xFF) { - LOG_ERROR("%s: COD malformed, '%s' must be between [0, 255]", __func__, - value.c_str()); + LOG_ERROR("COD malformed, '%s' must be between [0, 255]", value.c_str()); return; } @@ -2870,7 +2901,7 @@ void btif_dm_get_local_class_of_device(DEV_CLASS device_class) { // If we've reached 3 numbers then make sure we're at a null terminator if (j >= 3) { if (prop_cod[i] != '\0') { - LOG_ERROR("%s: COD malformed, more than three numbers", __func__); + LOG_ERROR("COD malformed, more than three numbers"); return; } break; @@ -2891,11 +2922,34 @@ void btif_dm_get_local_class_of_device(DEV_CLASS device_class) { device_class[1] = temp_device_class[1]; device_class[2] = temp_device_class[2]; } else { - LOG_ERROR("%s: COD malformed, fewer than three numbers", __func__); + LOG_ERROR("COD malformed, fewer than three numbers"); } - LOG_DEBUG("%s: Using class of device '0x%x, 0x%x, 0x%x'", __func__, + LOG_DEBUG("Using class of device '0x%x, 0x%x, 0x%x' from CoD system property", device_class[0], device_class[1], device_class[2]); + +#ifdef __ANDROID__ + // Per BAP 1.0.1, 8.2.3. Device discovery, the stack needs to set Class of + // Device (CoD) field Major Service Class bit 14 to 0b1 when Unicast Server, + // Unicast Client, Broadcast Source, Broadcast Sink, Scan Delegator, or + // Broadcast Assistant is supported on this device + if (android::sysprop::BluetoothProperties::isProfileBapUnicastClientEnabled() + .value_or(false) || + android::sysprop::BluetoothProperties:: + isProfileBapBroadcastAssistEnabled() + .value_or(false) || + android::sysprop::BluetoothProperties:: + isProfileBapBroadcastSourceEnabled() + .value_or(false)) { + device_class[1] |= 0x01 << 6; + } else { + device_class[1] &= ~(0x01 << 6); + } + LOG_DEBUG( + "Check LE audio enabled status, update class of device to '0x%x, 0x%x, " + "0x%x'", + device_class[0], device_class[1], device_class[2]); +#endif } /******************************************************************************* @@ -2908,7 +2962,7 @@ void btif_dm_get_local_class_of_device(DEV_CLASS device_class) { * ******************************************************************************/ bt_status_t btif_dm_get_adapter_property(bt_property_t* prop) { - BTIF_TRACE_EVENT("%s: type=0x%x", __func__, prop->type); + LOG_VERBOSE("type=0x%x", prop->type); switch (prop->type) { case BT_PROPERTY_BDNAME: { bt_bdname_t* bd_name = (bt_bdname_t*)prop->val; @@ -2959,8 +3013,9 @@ bt_status_t btif_dm_get_adapter_property(bt_property_t* prop) { * ******************************************************************************/ void btif_dm_get_remote_services(RawAddress remote_addr, const int transport) { - BTIF_TRACE_EVENT("%s: transport=%d, remote_addr=%s", __func__, transport, - ADDRESS_TO_LOGGABLE_CSTR(remote_addr)); + LOG_VERBOSE("transport=%s, remote_addr=%s", + bt_transport_text(transport).c_str(), + ADDRESS_TO_LOGGABLE_CSTR(remote_addr)); BTM_LogHistory( kBtmLogTag, remote_addr, "Service discovery", @@ -2996,7 +3051,7 @@ void btif_dm_proc_io_req(tBTM_AUTH_REQ* p_auth_req, bool is_orig) { ** as a fallback set MITM+GB if peer had MITM set */ - BTIF_TRACE_DEBUG("+%s: p_auth_req=%d", __func__, *p_auth_req); + LOG_VERBOSE("original p_auth_req=%d", *p_auth_req); if (pairing_cb.is_local_initiated) { /* if initing/responding to a dedicated bonding, use dedicate bonding bit */ *p_auth_req = BTA_AUTH_DD_BOND | BTA_AUTH_SP_YES; @@ -3004,8 +3059,8 @@ void btif_dm_proc_io_req(tBTM_AUTH_REQ* p_auth_req, bool is_orig) { /* peer initiated paring. They probably know what they want. ** Copy the mitm from peer device. */ - BTIF_TRACE_DEBUG("%s: setting p_auth_req to peer's: %d", __func__, - pairing_cb.auth_req); + LOG_DEBUG("peer initiated, setting p_auth_req to peer's: %d", + pairing_cb.auth_req); *p_auth_req = (pairing_cb.auth_req & BTA_AUTH_BONDS); /* copy over the MITM bit as well. In addition if the peer has DisplayYesNo, @@ -3016,14 +3071,14 @@ void btif_dm_proc_io_req(tBTM_AUTH_REQ* p_auth_req, bool is_orig) { /* set the general bonding bit for stored device */ *p_auth_req = BTA_AUTH_GEN_BOND | yes_no_bit; } - BTIF_TRACE_DEBUG("-%s: p_auth_req=%d", __func__, *p_auth_req); + LOG_VERBOSE("updated p_auth_req=%d", *p_auth_req); } void btif_dm_proc_io_rsp(UNUSED_ATTR const RawAddress& bd_addr, tBTM_IO_CAP io_cap, UNUSED_ATTR tBTM_OOB_DATA oob_data, tBTM_AUTH_REQ auth_req) { if (auth_req & BTA_AUTH_BONDS) { - BTIF_TRACE_DEBUG("%s auth_req:%d", __func__, auth_req); + LOG_DEBUG("auth_req:%d", auth_req); pairing_cb.auth_req = auth_req; pairing_cb.io_cap = io_cap; } @@ -3035,7 +3090,7 @@ void btif_dm_set_oob_for_io_req(tBTM_OOB_DATA* p_has_oob_data) { } else { *p_has_oob_data = true; } - BTIF_TRACE_DEBUG("%s: *p_has_oob_data=%d", __func__, *p_has_oob_data); + LOG_VERBOSE("*p_has_oob_data=%d", *p_has_oob_data); } void btif_dm_set_oob_for_le_io_req(const RawAddress& bd_addr, @@ -3105,17 +3160,17 @@ void btif_dm_set_oob_for_le_io_req(const RawAddress& bd_addr, } break; } - BTIF_TRACE_DEBUG("%s *p_has_oob_data=%d", __func__, *p_has_oob_data); + LOG_VERBOSE("*p_has_oob_data=%d", *p_has_oob_data); } #ifdef BTIF_DM_OOB_TEST void btif_dm_load_local_oob(void) { char prop_oob[PROPERTY_VALUE_MAX]; osi_property_get("service.brcm.bt.oob", prop_oob, "3"); - BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob); + LOG_VERBOSE("prop_oob = %s", prop_oob); if (prop_oob[0] != '3') { if (is_empty_128bit(oob_cb.p192_data.c)) { - BTIF_TRACE_DEBUG("%s: read OOB, call BTA_DmLocalOob()", __func__); + LOG_VERBOSE("read OOB, call BTA_DmLocalOob()"); BTA_DmLocalOob(); } } @@ -3126,7 +3181,7 @@ static std::optional oob_advertiser_id_; static void stop_oob_advertiser() { // For chasing an advertising bug b/237023051 LOG_DEBUG("oob_advertiser_id: %d", oob_advertiser_id_.value()); - auto advertiser = get_ble_advertiser_instance(); + auto advertiser = bluetooth::shim::get_ble_advertiser_instance(); advertiser->Unregister(oob_advertiser_id_.value()); oob_advertiser_id_ = {}; } @@ -3190,7 +3245,7 @@ static void start_advertising_callback(uint8_t id, tBT_TRANSPORT transport, return; } LOG_DEBUG("OOB advertiser with id %hhd", id); - auto advertiser = get_ble_advertiser_instance(); + auto advertiser = bluetooth::shim::get_ble_advertiser_instance(); advertiser->GetOwnAddress( id, base::Bind(&get_address_callback, transport, is_valid, c, r)); } @@ -3198,7 +3253,7 @@ static void start_advertising_callback(uint8_t id, tBT_TRANSPORT transport, static void timeout_cb(uint8_t id, tBTM_STATUS status) { LOG_INFO("OOB advertiser with id %hhd timed out with status %hhd", id, status); - auto advertiser = get_ble_advertiser_instance(); + auto advertiser = bluetooth::shim::get_ble_advertiser_instance(); advertiser->Unregister(id); SMP_ClearLocScOobData(); waiting_on_oob_advertiser_start = false; @@ -3222,7 +3277,7 @@ static void id_status_callback(tBT_TRANSPORT transport, bool is_valid, oob_advertiser_id_ = id; LOG_INFO("oob_advertiser_id: %d", id); - auto advertiser = get_ble_advertiser_instance(); + auto advertiser = bluetooth::shim::get_ble_advertiser_instance(); AdvertiseParameters parameters{}; parameters.advertising_event_properties = 0x0045 /* connectable, discoverable, tx power */; @@ -3249,7 +3304,7 @@ static void id_status_callback(tBT_TRANSPORT transport, bool is_valid, // Step One: Start the advertiser static void start_oob_advertiser(tBT_TRANSPORT transport, bool is_valid, const Octet16& c, const Octet16& r) { - auto advertiser = get_ble_advertiser_instance(); + auto advertiser = bluetooth::shim::get_ble_advertiser_instance(); advertiser->RegisterAdvertiser( base::Bind(&id_status_callback, transport, is_valid, c, r)); } @@ -3292,7 +3347,7 @@ void btif_dm_proc_loc_oob(tBT_TRANSPORT transport, bool is_valid, bool btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) { const std::string* recv = stack_config_get_interface()->get_pts_smp_options(); if (!recv) { - LOG_DEBUG("SMP pairing options not found in stack configuration"); + LOG_WARN("SMP pairing options not found in stack configuration"); return false; } @@ -3343,23 +3398,23 @@ bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, Octet16* p_c, const char* path = NULL; char prop_oob[PROPERTY_VALUE_MAX]; osi_property_get("service.brcm.bt.oob", prop_oob, "3"); - BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob); + LOG_DEBUG("prop_oob = %s", prop_oob); if (prop_oob[0] == '1') path = path_b; else if (prop_oob[0] == '2') path = path_a; if (!path) { - BTIF_TRACE_DEBUG("%s: can't open path!", __func__); + LOG_DEBUG("can't open path!"); return false; } FILE* fp = fopen(path, "rb"); if (fp == NULL) { - BTIF_TRACE_DEBUG("%s: failed to read OOB keys from %s", __func__, path); + LOG_DEBUG("failed to read OOB keys from %s", path); return false; } - BTIF_TRACE_DEBUG("%s: read OOB data from %s", __func__, path); + LOG_VERBOSE("read OOB data from %s", path); (void)fread(p_c->data(), 1, OCTET16_LEN, fp); (void)fread(p_r->data(), 1, OCTET16_LEN, fp); fclose(fp); @@ -3375,7 +3430,7 @@ static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) { uint32_t cod; int dev_type; - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_ssp_key_notif->bd_addr)); /* Remote name update */ if (!btif_get_device_type(p_ssp_key_notif->bd_addr, &dev_type)) { @@ -3394,7 +3449,7 @@ static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) { BTM_LogHistory( kBtmLogTagCallback, bd_addr, "Ssp request", - base::StringPrintf("name:\"%s\" passkey:%u", PRIVATE_NAME(bd_name.name), + base::StringPrintf("name:'%s' passkey:%u", PRIVATE_NAME(bd_name.name), p_ssp_key_notif->passkey)); GetInterfaceToProfiles()->events->invoke_ssp_request_cb( @@ -3434,10 +3489,8 @@ static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { btif_storage_set_remote_addr_type(&bd_addr, p_auth_cmpl->addr_type); /* Test for temporary bonding */ - if (btm_get_bond_type_dev(bd_addr) == - tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY) { - BTIF_TRACE_DEBUG("%s: sending BT_BOND_STATE_NONE for Temp pairing", - __func__); + if (btm_get_bond_type_dev(bd_addr) == BOND_TYPE_TEMPORARY) { + LOG_DEBUG("sending BT_BOND_STATE_NONE for Temp pairing"); btif_storage_remove_bonded_device(&bd_addr); state = BT_BOND_STATE_NONE; } else { @@ -3458,9 +3511,11 @@ static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { } } } else { - /*Map the HCI fail reason to bt status */ + /* Map the HCI fail reason to bt status */ // TODO This is not a proper use of the type uint8_t fail_reason = static_cast(p_auth_cmpl->fail_reason); + LOG_ERROR("LE authentication for %s failed with reason %d", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), p_auth_cmpl->fail_reason); switch (fail_reason) { case BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL: case BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL: @@ -3471,9 +3526,9 @@ static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) { case BTA_DM_AUTH_SMP_CONN_TOUT: { if (!p_auth_cmpl->is_ctkd && btm_sec_is_a_bonded_dev(bd_addr)) { - LOG(INFO) << __func__ << " Bonded device addr=" - << ADDRESS_TO_LOGGABLE_STR(bd_addr) - << " timed out - will not remove the keys"; + LOG_WARN( + "Bonded device addr=%s, timed out - will not remove the keys", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); // Don't send state change to upper layers - otherwise Java think we // unbonded, and will disconnect HID profile. return; @@ -3510,7 +3565,7 @@ void btif_dm_load_ble_local_keys(void) { if (btif_storage_get_ble_local_key( BTIF_DM_LE_LOCAL_KEY_ER, &ble_local_key_cb.er) == BT_STATUS_SUCCESS) { ble_local_key_cb.is_er_rcvd = true; - BTIF_TRACE_DEBUG("%s BLE ER key loaded", __func__); + LOG_VERBOSE("BLE ER key loaded"); } if ((btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IR, @@ -3523,7 +3578,7 @@ void btif_dm_load_ble_local_keys(void) { &ble_local_key_cb.id_keys.dhk) == BT_STATUS_SUCCESS)) { ble_local_key_cb.is_id_keys_rcvd = true; - BTIF_TRACE_DEBUG("%s BLE ID keys loaded", __func__); + LOG_VERBOSE("BLE ID keys loaded"); } } void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, @@ -3543,11 +3598,11 @@ void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, p_id_keys->dhk = ble_local_key_cb.id_keys.dhk; *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ID; } - BTIF_TRACE_DEBUG("%s *p_key_mask=0x%02x", __func__, *p_key_mask); + LOG_VERBOSE("*p_key_mask=0x%02x", *p_key_mask); } static void btif_dm_save_ble_bonding_keys(RawAddress& bd_addr) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); if (bd_addr.IsEmpty()) { LOG_WARN("bd_addr is empty"); @@ -3591,7 +3646,7 @@ static void btif_dm_save_ble_bonding_keys(RawAddress& bd_addr) { } static void btif_dm_remove_ble_bonding_keys(void) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("removing ble bonding keys"); RawAddress bd_addr = pairing_cb.bd_addr; btif_storage_remove_ble_bonding_keys(&bd_addr); @@ -3612,10 +3667,10 @@ static void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req, uint32_t cod; int dev_type; - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_ble_req->bd_addr)); if (!is_consent && pairing_cb.state == BT_BOND_STATE_BONDING) { - BTIF_TRACE_DEBUG("%s Discard security request", __func__); + LOG_WARN("Discard security request"); return; } @@ -3633,7 +3688,7 @@ static void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req, bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING); - pairing_cb.bond_type = tBTM_SEC_DEV_REC::BOND_TYPE_PERSISTENT; + pairing_cb.bond_type = BOND_TYPE_PERSISTENT; pairing_cb.is_le_only = true; pairing_cb.is_le_nc = false; pairing_cb.is_ssp = true; @@ -3642,7 +3697,7 @@ static void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req, cod = COD_UNCLASSIFIED; BTM_LogHistory(kBtmLogTagCallback, bd_addr, "SSP ble request", - base::StringPrintf("name:\"%s\" BT_SSP_VARIANT_CONSENT", + base::StringPrintf("name:'%s' BT_SSP_VARIANT_CONSENT", PRIVATE_NAME(bd_name.name))); GetInterfaceToProfiles()->events->invoke_ssp_request_cb( @@ -3681,14 +3736,14 @@ static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ* p_pin_req) { cod = COD_UNCLASSIFIED; BTM_LogHistory(kBtmLogTagCallback, bd_addr, "PIN request", - base::StringPrintf("name:\"%s\"", PRIVATE_NAME(bd_name.name))); + base::StringPrintf("name:'%s'", PRIVATE_NAME(bd_name.name))); GetInterfaceToProfiles()->events->invoke_pin_request_cb(bd_addr, bd_name, cod, false); } static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF* p_notif_req) { /* TODO implement key notification for numeric comparison */ - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_notif_req->bd_addr)); /* Remote name update */ btif_update_remote_properties(p_notif_req->bd_addr, p_notif_req->bd_name, @@ -3707,7 +3762,7 @@ static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF* p_notif_req) { BTM_LogHistory( kBtmLogTagCallback, bd_addr, "Ssp request", - base::StringPrintf("name:\"%s\" passkey:%u", PRIVATE_NAME(bd_name.name), + base::StringPrintf("name:'%s' passkey:%u", PRIVATE_NAME(bd_name.name), p_notif_req->passkey)); GetInterfaceToProfiles()->events->invoke_ssp_request_cb( @@ -3716,7 +3771,7 @@ static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF* p_notif_req) { } static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(req_oob_type->bd_addr)); RawAddress bd_addr = req_oob_type->bd_addr; /* We already checked if OOB data is present in @@ -3729,8 +3784,7 @@ static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type) { /* make sure OOB data is for this particular device */ if (req_oob_type->bd_addr != oob_cb.bdaddr) { - BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address", - __func__); + LOG_WARN("remote address didn't match OOB data address"); return; } @@ -3747,13 +3801,9 @@ static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type) { } static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type) { - BTIF_TRACE_DEBUG("%s", __func__); - RawAddress bd_addr = req_oob_type->bd_addr; - BTIF_TRACE_DEBUG("%s: bd_addr: %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - BTIF_TRACE_DEBUG("%s: oob_cb.bdaddr: %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(oob_cb.bdaddr)); + LOG_VERBOSE("bd_addr: %s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("oob_cb.bdaddr: %s", ADDRESS_TO_LOGGABLE_CSTR(oob_cb.bdaddr)); /* make sure OOB data is for this particular device */ if (req_oob_type->bd_addr != oob_cb.bdaddr) { @@ -3811,10 +3861,48 @@ void btif_dm_update_ble_remote_properties(const RawAddress& bd_addr, btif_update_remote_properties(bd_addr, bd_name, dev_class, dev_type); } +static void btif_dm_ble_tx_test_cback(void* p) { + char* p_param = (char*)p; + uint8_t status; + STREAM_TO_UINT8(status, p_param); + GetInterfaceToProfiles()->events->invoke_le_test_mode_cb( + (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, 0); +} + +static void btif_dm_ble_rx_test_cback(void* p) { + char* p_param = (char*)p; + uint8_t status; + STREAM_TO_UINT8(status, p_param); + GetInterfaceToProfiles()->events->invoke_le_test_mode_cb( + (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, 0); +} + +static void btif_dm_ble_test_end_cback(void* p) { + char* p_param = (char*)p; + uint8_t status; + uint16_t count = 0; + STREAM_TO_UINT8(status, p_param); + if (status == 0) STREAM_TO_UINT16(count, p_param); + GetInterfaceToProfiles()->events->invoke_le_test_mode_cb( + (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, count); +} + +void btif_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len, + uint8_t packet_payload) { + BTM_BleTransmitterTest(tx_freq, test_data_len, packet_payload, + btif_dm_ble_tx_test_cback); +} + +void btif_ble_receiver_test(uint8_t rx_freq) { + BTM_BleReceiverTest(rx_freq, btif_dm_ble_rx_test_cback); +} + +void btif_ble_test_end() { BTM_BleTestEnd(btif_dm_ble_test_end_cback); } + void btif_dm_on_disable() { /* cancel any pending pairing requests */ if (is_bonding_or_sdp()) { - BTIF_TRACE_DEBUG("%s: Cancel pending pairing request", __func__); + LOG_VERBOSE("Cancel pending pairing request"); btif_dm_cancel_bond(pairing_cb.bd_addr); } } @@ -3958,7 +4046,7 @@ bool btif_get_device_type(const RawAddress& bda, int* p_device_type) { if (!btif_config_get_int(bd_addr_str, "DevType", p_device_type)) return false; tBT_DEVICE_TYPE device_type = static_cast(*p_device_type); - LOG_DEBUG(" bd_addr:%s device_type:%s", ADDRESS_TO_LOGGABLE_CSTR(bda), + LOG_DEBUG("bd_addr:%s device_type:%s", ADDRESS_TO_LOGGABLE_CSTR(bda), DeviceTypeText(device_type).c_str()); return true; @@ -3973,34 +4061,21 @@ bool btif_get_address_type(const RawAddress& bda, tBLE_ADDR_TYPE* p_addr_type) { int val = 0; if (!btif_config_get_int(bd_addr_str, "AddrType", &val)) return false; *p_addr_type = static_cast(val); - LOG_DEBUG(" bd_addr:%s[%s]", ADDRESS_TO_LOGGABLE_CSTR(bda), + LOG_DEBUG("bd_addr:%s[%s]", ADDRESS_TO_LOGGABLE_CSTR(bda), AddressTypeText(*p_addr_type).c_str()); return true; } -void btif_dm_clear_event_filter() { - LOG_VERBOSE("%s: called", __func__); - BTA_DmClearEventFilter(); -} +void btif_dm_clear_event_filter() { BTA_DmClearEventFilter(); } -void btif_dm_clear_event_mask() { - LOG_VERBOSE("%s: called", __func__); - BTA_DmClearEventMask(); -} +void btif_dm_clear_event_mask() { BTA_DmClearEventMask(); } -void btif_dm_clear_filter_accept_list() { - LOG_VERBOSE("%s: called", __func__); - BTA_DmClearFilterAcceptList(); -} +void btif_dm_clear_filter_accept_list() { BTA_DmClearFilterAcceptList(); } -void btif_dm_disconnect_all_acls() { - LOG_VERBOSE("%s: called", __func__); - BTA_DmDisconnectAllAcls(); -} +void btif_dm_disconnect_all_acls() { BTA_DmDisconnectAllAcls(); } void btif_dm_le_rand(LeRandCallback callback) { - LOG_VERBOSE("%s: called", __func__); - BTA_DmLeRand(callback); + BTA_DmLeRand(std::move(callback)); } void btif_dm_set_event_filter_connection_setup_all_devices() { @@ -4039,3 +4114,20 @@ void btif_dm_metadata_changed(const RawAddress& remote_bd_addr, int key, metadata_cb.le_audio_cache.insert_or_assign(remote_bd_addr, value); } } + +namespace bluetooth { +namespace legacy { +namespace testing { + +void bta_energy_info_cb(tBTM_BLE_TX_TIME_MS tx_time, + tBTM_BLE_RX_TIME_MS rx_time, + tBTM_BLE_IDLE_TIME_MS idle_time, + tBTM_BLE_ENERGY_USED energy_used, + tBTM_CONTRL_STATE ctrl_state, tBTA_STATUS status) { + ::bta_energy_info_cb(tx_time, rx_time, idle_time, energy_used, ctrl_state, + status); +} + +} // namespace testing +} // namespace legacy +} // namespace bluetooth diff --git a/system/btif/src/btif_gatt.cc b/system/btif/src/btif_gatt.cc index 2d44b837ccff9446dfd8e3575ab03aa7c4423003..1bd57673285702fdfa9305a81b50941ad7ab0fde 100644 --- a/system/btif/src/btif_gatt.cc +++ b/system/btif/src/btif_gatt.cc @@ -28,20 +28,15 @@ #include "btif_gatt.h" -#include #include #include #include #include #include -#include "bta_api.h" #include "bta_gatt_api.h" -#include "btif_common.h" -#include "btif_gatt_util.h" -#include "btif_storage.h" -#include "btif_util.h" #include "main/shim/distance_measurement_manager.h" +#include "main/shim/le_advertising_manager.h" const btgatt_callbacks_t* bt_gatt_callbacks = NULL; @@ -102,7 +97,7 @@ const btgatt_interface_t* btif_gatt_get_interface() { // structure cause explosion of dependencies. It must be initialized here // until those dependencies are properly abstracted for tests. btgattInterface.scanner = get_ble_scanner_instance(); - btgattInterface.advertiser = get_ble_advertiser_instance(); + btgattInterface.advertiser = bluetooth::shim::get_ble_advertiser_instance(); btgattInterface.distance_measurement_manager = bluetooth::shim::get_distance_measurement_instance(); return &btgattInterface; diff --git a/system/btif/src/btif_gatt_client.cc b/system/btif/src/btif_gatt_client.cc index a0054692dddaf540ff495160c29c8337f040bdae..5e5c9c3f728db719af38a1640bfd07d8d8ef35c9 100644 --- a/system/btif/src/btif_gatt_client.cc +++ b/system/btif/src/btif_gatt_client.cc @@ -30,31 +30,29 @@ #include #include #include -#include #include #include +#include #include +#include "bta/include/bta_sec_api.h" #include "bta_api.h" #include "bta_gatt_api.h" #include "btif_common.h" #include "btif_config.h" -#include "btif_dm.h" #include "btif_gatt.h" #include "btif_gatt_util.h" -#include "btif_storage.h" -#include "btif_util.h" #include "device/include/controller.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/include/acl_api.h" #include "stack/include/acl_api_types.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" +#include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" -#include "vendor_api.h" using base::Bind; using base::Owned; @@ -71,20 +69,20 @@ extern const btgatt_callbacks_t* bt_gatt_callbacks; /******************************************************************************* * Constants & Macros ******************************************************************************/ -#define CLI_CBACK_WRAP_IN_JNI(P_CBACK, P_CBACK_WRAP) \ - do { \ - if (bt_gatt_callbacks && bt_gatt_callbacks->client->P_CBACK) { \ - BTIF_TRACE_API("HAL bt_gatt_callbacks->client->%s", #P_CBACK); \ - do_in_jni_thread(P_CBACK_WRAP); \ - } else { \ - ASSERTC(0, "Callback is NULL", 0); \ - } \ +#define CLI_CBACK_WRAP_IN_JNI(P_CBACK, P_CBACK_WRAP) \ + do { \ + if (bt_gatt_callbacks && bt_gatt_callbacks->client->P_CBACK) { \ + LOG_VERBOSE("HAL bt_gatt_callbacks->client->%s", #P_CBACK); \ + do_in_jni_thread(P_CBACK_WRAP); \ + } else { \ + ASSERTC(0, "Callback is NULL", 0); \ + } \ } while (0) #define CLI_CBACK_IN_JNI(P_CBACK, ...) \ do { \ if (bt_gatt_callbacks && bt_gatt_callbacks->client->P_CBACK) { \ - BTIF_TRACE_API("HAL bt_gatt_callbacks->client->%s", #P_CBACK); \ + LOG_VERBOSE("HAL bt_gatt_callbacks->client->%s", #P_CBACK); \ do_in_jni_thread(Bind(bt_gatt_callbacks->client->P_CBACK, __VA_ARGS__)); \ } else { \ ASSERTC(0, "Callback is NULL", 0); \ @@ -421,7 +419,7 @@ void read_char_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, params->status = status; params->handle = handle; params->value.len = len; - CHECK(len <= BTGATT_MAX_ATTR_LEN); + CHECK(len <= GATT_MAX_ATTR_LEN); if (len > 0) memcpy(params->value.value, value, len); // clang-tidy analyzer complains about |params| is leaked. It doesn't know @@ -445,7 +443,7 @@ void read_using_char_uuid_cb(uint16_t conn_id, tGATT_STATUS status, params->status = status; params->handle = handle; params->value.len = len; - CHECK(len <= BTGATT_MAX_ATTR_LEN); + CHECK(len <= GATT_MAX_ATTR_LEN); if (len > 0) memcpy(params->value.value, value, len); // clang-tidy analyzer complains about |params| is leaked. It doesn't know @@ -472,7 +470,7 @@ void read_desc_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle, params.status = status; params.handle = handle; params.value.len = len; - CHECK(len <= BTGATT_MAX_ATTR_LEN); + CHECK(len <= GATT_MAX_ATTR_LEN); if (len > 0) memcpy(params.value.value, value, len); CLI_CBACK_IN_JNI(read_descriptor_cb, conn_id, status, params); @@ -507,7 +505,7 @@ static bt_status_t btif_gattc_write_char(int conn_id, uint16_t handle, std::vector value(val, val + len); - if (value.size() > BTGATT_MAX_ATTR_LEN) value.resize(BTGATT_MAX_ATTR_LEN); + if (value.size() > GATT_MAX_ATTR_LEN) value.resize(GATT_MAX_ATTR_LEN); return do_in_jni_thread(Bind(&BTA_GATTC_WriteCharValue, conn_id, handle, write_type, std::move(value), auth_req, @@ -537,7 +535,7 @@ static bt_status_t btif_gattc_write_char_descr(int conn_id, uint16_t handle, std::vector value(val, val + len); - if (value.size() > BTGATT_MAX_ATTR_LEN) value.resize(BTGATT_MAX_ATTR_LEN); + if (value.size() > GATT_MAX_ATTR_LEN) value.resize(GATT_MAX_ATTR_LEN); return do_in_jni_thread(Bind(&BTA_GATTC_WriteCharDescr, conn_id, handle, std::move(value), auth_req, write_descr_cb, diff --git a/system/btif/src/btif_gatt_server.cc b/system/btif/src/btif_gatt_server.cc index 441e0fac53e0df5da9b80b8e25d9ef716b113b34..7f4ecdb58f1232f30d509fbeb8f0d10fb9637f58 100644 --- a/system/btif/src/btif_gatt_server.cc +++ b/system/btif/src/btif_gatt_server.cc @@ -27,25 +27,22 @@ #define LOG_TAG "bt_btif_gatt" #include -#include #include #include +#include #include #include #include -#include "bta_api.h" +#include "bta/include/bta_sec_api.h" #include "bta_gatt_api.h" #include "btif_common.h" -#include "btif_config.h" -#include "btif_dm.h" #include "btif_gatt.h" #include "btif_gatt_util.h" -#include "btif_storage.h" -#include "btif_util.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "stack/include/btu.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/main_thread.h" +#include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -54,7 +51,6 @@ bool btif_get_address_type(const RawAddress& bda, tBLE_ADDR_TYPE* p_addr_type); bool btif_get_device_type(const RawAddress& bda, int* p_device_type); using base::Bind; -using base::Owned; using bluetooth::Uuid; using std::vector; @@ -403,7 +399,7 @@ static bt_status_t btif_gatts_send_indication(int server_if, size_t length) { CHECK_BTGATT_INIT(); - if (length > BTGATT_MAX_ATTR_LEN) length = BTGATT_MAX_ATTR_LEN; + if (length > GATT_MAX_ATTR_LEN) length = GATT_MAX_ATTR_LEN; return do_in_jni_thread(Bind(&BTA_GATTS_HandleValueIndication, conn_id, attribute_handle, diff --git a/system/btif/src/btif_gatt_test.cc b/system/btif/src/btif_gatt_test.cc index e01083be79dee340a48b2e211abb08bde33d7b12..d423c6a6655c54e801f0ad6e83be4e42745045d8 100644 --- a/system/btif/src/btif_gatt_test.cc +++ b/system/btif/src/btif_gatt_test.cc @@ -18,25 +18,18 @@ #define LOG_TAG "bt_btif_gatt" -#include "btif_gatt.h" - -#include #include #include #include #include #include -#include "bta_gatt_api.h" -#include "bte_appl.h" -#include "btif_common.h" -#include "btif_dm.h" -#include "btif_gatt_util.h" -#include "btif_storage.h" -#include "btif_util.h" #include "gatt_api.h" -#include "osi/include/log.h" +#include "internal_include/bte_appl.h" +#include "os/log.h" #include "osi/include/osi.h" +#include "stack/include/btm_ble_sec_api.h" +#include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" diff --git a/system/btif/src/btif_gatt_util.cc b/system/btif/src/btif_gatt_util.cc index db4d045087e2dc339f1b6819acd07f94dfa48a0d..36365316bf69f153dba82fe8f40064f2c28a6c35 100644 --- a/system/btif/src/btif_gatt_util.cc +++ b/system/btif/src/btif_gatt_util.cc @@ -22,26 +22,23 @@ #include "btif_gatt_util.h" -#include #include #include #include #include #include -#include "bta_api.h" -#include "bta_gatt_api.h" -#include "bta_jv_api.h" -#include "btif_common.h" -#include "btif_config.h" -#include "btif_dm.h" -#include "btif_gatt.h" +#include "bta/include/bta_api_data_types.h" +#include "bta/include/bta_sec_api.h" #include "btif_storage.h" -#include "btif_util.h" +#include "common/init_flags.h" #include "gd/os/system_properties.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "stack/btm/btm_sec.h" +#include "stack/include/acl_api.h" +#include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -72,12 +69,21 @@ static void btif_gatt_set_encryption_cb(UNUSED_ATTR const RawAddress& bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, tBTA_STATUS result) { if (result != BTA_SUCCESS && result != BTA_BUSY) { - BTIF_TRACE_WARNING("%s() - Encryption failed (%d)", __func__, result); + LOG_WARN("%s() - Encryption failed (%d)", __func__, result); } } void btif_gatt_check_encrypted_link(RawAddress bd_addr, tBT_TRANSPORT transport_link) { + RawAddress raw_local_addr; + tBLE_ADDR_TYPE local_addr_type; + BTM_ReadConnectionAddr(bd_addr, raw_local_addr, &local_addr_type); + tBLE_BD_ADDR local_addr{local_addr_type, raw_local_addr}; + if (!local_addr.IsPublic() && !local_addr.IsAddressResolvable()) { + LOG_DEBUG("Not establishing encryption since address type is NRPA"); + return; + } + static const bool check_encrypted = bluetooth::os::GetSystemPropertyBool( "bluetooth.gatt.check_encrypted_link.enabled", true); if (!check_encrypted) { diff --git a/system/btif/src/btif_has_client.cc b/system/btif/src/btif_has_client.cc index c62eb0926ce09d87b3d7cf437852f65fc1ed0743..da42920e751301aa0e96207710c9a6a71edcf5b2 100644 --- a/system/btif/src/btif_has_client.cc +++ b/system/btif/src/btif_has_client.cc @@ -15,7 +15,6 @@ * limitations under the License. */ -#include #include #include #include @@ -29,7 +28,7 @@ #include "bta_has_api.h" #include "btif_common.h" #include "btif_profile_storage.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" using base::Bind; using base::Owned; @@ -52,7 +51,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, ~HearingAaccessClientServiceInterfaceImpl() override = default; void Init(HasClientCallbacks* callbacks) override { - DVLOG(2) << __func__; this->callbacks_ = callbacks; do_in_main_thread( @@ -64,7 +62,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, } void Connect(const RawAddress& addr) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr); do_in_main_thread(FROM_HERE, Bind(&HasClient::Connect, Unretained(HasClient::Get()), addr)); @@ -73,7 +70,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, } void Disconnect(const RawAddress& addr) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr); do_in_main_thread(FROM_HERE, Bind(&HasClient::Disconnect, Unretained(HasClient::Get()), addr)); @@ -83,8 +79,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, void SelectActivePreset(std::variant addr_or_group_id, uint8_t preset_index) override { - DVLOG(2) << __func__ << " preset_index: " << preset_index; - do_in_main_thread( FROM_HERE, Bind(&HasClient::SelectActivePreset, Unretained(HasClient::Get()), @@ -93,8 +87,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, void NextActivePreset( std::variant addr_or_group_id) override { - DVLOG(2) << __func__; - do_in_main_thread(FROM_HERE, Bind(&HasClient::NextActivePreset, Unretained(HasClient::Get()), std::move(addr_or_group_id))); @@ -102,17 +94,12 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, void PreviousActivePreset( std::variant addr_or_group_id) override { - DVLOG(2) << __func__; - do_in_main_thread(FROM_HERE, Bind(&HasClient::PreviousActivePreset, Unretained(HasClient::Get()), std::move(addr_or_group_id))); } void GetPresetInfo(const RawAddress& addr, uint8_t preset_index) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr) - << " preset_index: " << preset_index; - do_in_main_thread( FROM_HERE, Bind(&HasClient::GetPresetInfo, Unretained(HasClient::Get()), addr, preset_index)); @@ -120,9 +107,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, void SetPresetName(std::variant addr_or_group_id, uint8_t preset_index, std::string preset_name) override { - DVLOG(2) << __func__ << " preset_index: " << preset_index - << " preset_name: " << preset_name; - do_in_main_thread( FROM_HERE, Bind(&HasClient::SetPresetName, Unretained(HasClient::Get()), std::move(addr_or_group_id), preset_index, @@ -130,8 +114,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, } void RemoveDevice(const RawAddress& addr) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr); - /* RemoveDevice can be called on devices that don't have BAS enabled */ if (HasClient::IsHasClientRunning()) { do_in_main_thread(FROM_HERE, Bind(&HasClient::Disconnect, @@ -142,37 +124,27 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, } void Cleanup(void) override { - DVLOG(2) << __func__; do_in_main_thread(FROM_HERE, Bind(&HasClient::CleanUp)); } void OnConnectionState(ConnectionState state, const RawAddress& addr) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr); do_in_jni_thread(FROM_HERE, Bind(&HasClientCallbacks::OnConnectionState, Unretained(callbacks_), state, addr)); } void OnDeviceAvailable(const RawAddress& addr, uint8_t features) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr) - << " features: " << features; - do_in_jni_thread(FROM_HERE, Bind(&HasClientCallbacks::OnDeviceAvailable, Unretained(callbacks_), addr, features)); } void OnFeaturesUpdate(const RawAddress& addr, uint8_t features) override { - DVLOG(2) << __func__ << " addr: " << ADDRESS_TO_LOGGABLE_STR(addr) - << " ha_features: " << std::bitset<8>(features); - do_in_jni_thread(FROM_HERE, Bind(&HasClientCallbacks::OnFeaturesUpdate, Unretained(callbacks_), addr, features)); } void OnActivePresetSelected(std::variant addr_or_group_id, uint8_t preset_index) override { - DVLOG(2) << __func__ << " preset_index: " << preset_index; - do_in_jni_thread(FROM_HERE, Bind(&HasClientCallbacks::OnActivePresetSelected, Unretained(callbacks_), std::move(addr_or_group_id), @@ -181,9 +153,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, void OnActivePresetSelectError(std::variant addr_or_group_id, ErrorCode result_code) override { - DVLOG(2) << __func__ << " result_code: " - << static_cast::type>(result_code); - do_in_jni_thread( FROM_HERE, Bind(&HasClientCallbacks::OnActivePresetSelectError, @@ -193,15 +162,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, void OnPresetInfo(std::variant addr_or_group_id, PresetInfoReason change_id, std::vector detail_records) override { - DVLOG(2) << __func__; - for (const auto& rec : detail_records) { - DVLOG(2) << "\t index: " << +rec.preset_index << ", change_id: " - << (std::underlying_type::type)change_id - << ", writable: " << rec.writable - << ", available: " << rec.available - << ", name: " << rec.preset_name; - } - do_in_jni_thread(FROM_HERE, Bind(&HasClientCallbacks::OnPresetInfo, Unretained(callbacks_), std::move(addr_or_group_id), @@ -210,9 +170,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, void OnPresetInfoError(std::variant addr_or_group_id, uint8_t preset_index, ErrorCode result_code) override { - DVLOG(2) << __func__ << " result_code: " - << static_cast::type>(result_code); - do_in_jni_thread( FROM_HERE, Bind(&HasClientCallbacks::OnPresetInfoError, Unretained(callbacks_), @@ -222,9 +179,6 @@ class HearingAaccessClientServiceInterfaceImpl : public HasClientInterface, void OnSetPresetNameError(std::variant addr_or_group_id, uint8_t preset_index, ErrorCode result_code) override { - DVLOG(2) << __func__ << " result_code: " - << static_cast::type>(result_code); - do_in_jni_thread( FROM_HERE, Bind(&HasClientCallbacks::OnSetPresetNameError, Unretained(callbacks_), diff --git a/system/btif/src/btif_hd.cc b/system/btif/src/btif_hd.cc index 5509d44b5153a2d6ed1073a673567a0d23767718..53d0a463a33ec985de6555fe346795c1f39f9dd3 100644 --- a/system/btif/src/btif_hd.cc +++ b/system/btif/src/btif_hd.cc @@ -33,6 +33,7 @@ #include "bt_target.h" // Must be first to define build configuration #include "bta/include/bta_hd_api.h" +#include "bta_sec_api.h" #include "bta/sys/bta_sys.h" #include "btif/include/btif_common.h" #include "btif/include/btif_profile_storage.h" @@ -141,11 +142,11 @@ void btif_hd_remove_device(RawAddress bd_addr) { static void btif_hd_upstreams_evt(uint16_t event, char* p_param) { tBTA_HD* p_data = (tBTA_HD*)p_param; - BTIF_TRACE_API("%s: event=%s", __func__, dump_hd_event(event)); + LOG_VERBOSE("%s: event=%s", __func__, dump_hd_event(event)); switch (event) { case BTA_HD_ENABLE_EVT: - BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status); + LOG_VERBOSE("%s: status=%d", __func__, p_data->status); if (p_data->status == BTA_HD_OK) { btif_storage_load_hidd(); btif_hd_cb.status = BTIF_HD_ENABLED; @@ -156,16 +157,16 @@ static void btif_hd_upstreams_evt(uint16_t event, char* p_param) { } } else { btif_hd_cb.status = BTIF_HD_DISABLED; - BTIF_TRACE_WARNING("Failed to enable BT-HD, status=%d", p_data->status); + LOG_WARN("Failed to enable BT-HD, status=%d", p_data->status); } break; case BTA_HD_DISABLE_EVT: - BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status); + LOG_VERBOSE("%s: status=%d", __func__, p_data->status); btif_hd_cb.status = BTIF_HD_DISABLED; if (btif_hd_cb.service_dereg_active) { bta_sys_deregister(BTA_ID_HD); - BTIF_TRACE_WARNING("registering hid host now"); + LOG_WARN("registering hid host now"); btif_hh_service_registration(TRUE); btif_hd_cb.service_dereg_active = FALSE; } @@ -173,8 +174,7 @@ static void btif_hd_upstreams_evt(uint16_t event, char* p_param) { if (p_data->status == BTA_HD_OK) memset(&btif_hd_cb, 0, sizeof(btif_hd_cb)); else - BTIF_TRACE_WARNING("Failed to disable BT-HD, status=%d", - p_data->status); + LOG_WARN("Failed to disable BT-HD, status=%d", p_data->status); break; case BTA_HD_REGISTER_APP_EVT: { @@ -195,7 +195,7 @@ static void btif_hd_upstreams_evt(uint16_t event, char* p_param) { HAL_CBACK(bt_hd_callbacks, application_state_cb, NULL, BTHD_APP_STATE_NOT_REGISTERED); if (btif_hd_cb.service_dereg_active) { - BTIF_TRACE_WARNING("disabling hid device service now"); + LOG_WARN("disabling hid device service now"); if (!bluetooth::common::init_flags:: delay_hidh_cleanup_until_hidh_ready_start_is_enabled()) { btif_hd_free_buf(); @@ -206,12 +206,11 @@ static void btif_hd_upstreams_evt(uint16_t event, char* p_param) { case BTA_HD_OPEN_EVT: { RawAddress* addr = (RawAddress*)&p_data->conn.bda; - BTIF_TRACE_WARNING("BTA_HD_OPEN_EVT, address=%s", - ADDRESS_TO_LOGGABLE_CSTR(*addr)); + LOG_WARN("BTA_HD_OPEN_EVT, address=%s", ADDRESS_TO_LOGGABLE_CSTR(*addr)); /* Check if the connection is from hid host and not hid device */ if (check_cod_hid(addr)) { /* Incoming connection from hid device, reject it */ - BTIF_TRACE_WARNING("remote device is not hid host, disconnecting"); + LOG_WARN("remote device is not hid host, disconnecting"); btif_hd_cb.forced_disc = TRUE; BTA_HdDisconnect(); break; @@ -225,7 +224,7 @@ static void btif_hd_upstreams_evt(uint16_t event, char* p_param) { case BTA_HD_CLOSE_EVT: if (btif_hd_cb.forced_disc) { RawAddress* addr = (RawAddress*)&p_data->conn.bda; - BTIF_TRACE_WARNING("remote device was forcefully disconnected"); + LOG_WARN("remote device was forcefully disconnected"); btif_hd_remove_device(*addr); btif_hd_cb.forced_disc = FALSE; break; @@ -258,12 +257,12 @@ static void btif_hd_upstreams_evt(uint16_t event, char* p_param) { HAL_CBACK(bt_hd_callbacks, connection_state_cb, (RawAddress*)&p_data->conn.bda, BTHD_CONN_STATE_DISCONNECTED); if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) { - BTIF_TRACE_DEBUG("%s: Removing bonding as only HID profile connected", - __func__); + LOG_VERBOSE("%s: Removing bonding as only HID profile connected", + __func__); BTA_DmRemoveDevice(p_data->conn.bda); } else { RawAddress* bd_addr = (RawAddress*)&p_data->conn.bda; - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Only removing HID data as some other profiles " "connected", __func__); @@ -279,7 +278,7 @@ static void btif_hd_upstreams_evt(uint16_t event, char* p_param) { break; default: - BTIF_TRACE_WARNING("%s: unknown event (%d)", __func__, event); + LOG_WARN("%s: unknown event (%d)", __func__, event); break; } } @@ -299,7 +298,7 @@ static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD* p_data) { int param_len = 0; tBTIF_COPY_CBACK* p_copy_cback = NULL; - BTIF_TRACE_API("%s event=%d", __func__, event); + LOG_VERBOSE("%s event=%d", __func__, event); switch (event) { case BTA_HD_ENABLE_EVT: @@ -354,7 +353,7 @@ static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD* p_data) { * ******************************************************************************/ static bt_status_t init(bthd_callbacks_t* callbacks) { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); bt_hd_callbacks = callbacks; memset(&btif_hd_cb, 0, sizeof(btif_hd_cb)); @@ -374,7 +373,7 @@ static bt_status_t init(bthd_callbacks_t* callbacks) { * ******************************************************************************/ static void cleanup(void) { - BTIF_TRACE_API("hd:%s", __func__); + LOG_VERBOSE("hd:%s", __func__); if (bt_hd_callbacks) { /* update flag, not to enable hid host service now as BT is switching off */ @@ -396,10 +395,10 @@ static void cleanup(void) { static bt_status_t register_app(bthd_app_param_t* p_app_param, bthd_qos_param_t* p_in_qos, bthd_qos_param_t* p_out_qos) { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (btif_hd_cb.app_registered) { - BTIF_TRACE_WARNING("%s: application already registered", __func__); + LOG_WARN("%s: application already registered", __func__); return BT_STATUS_DONE; } @@ -448,21 +447,20 @@ static bt_status_t register_app(bthd_app_param_t* p_app_param, * ******************************************************************************/ static bt_status_t unregister_app(void) { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!btif_hd_cb.app_registered) { - BTIF_TRACE_WARNING("%s: application not yet registered", __func__); + LOG_WARN("%s: application not yet registered", __func__); return BT_STATUS_NOT_READY; } if (btif_hd_cb.status != BTIF_HD_ENABLED) { - BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__, - btif_hd_cb.status); + LOG_WARN("%s: BT-HD not enabled, status=%d", __func__, btif_hd_cb.status); return BT_STATUS_NOT_READY; } if (btif_hd_cb.service_dereg_active) { - BTIF_TRACE_WARNING("%s: BT-HD deregistering in progress", __func__); + LOG_WARN("%s: BT-HD deregistering in progress", __func__); return BT_STATUS_BUSY; } @@ -482,16 +480,15 @@ static bt_status_t unregister_app(void) { * ******************************************************************************/ static bt_status_t connect(RawAddress* bd_addr) { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!btif_hd_cb.app_registered) { - BTIF_TRACE_WARNING("%s: application not yet registered", __func__); + LOG_WARN("%s: application not yet registered", __func__); return BT_STATUS_NOT_READY; } if (btif_hd_cb.status != BTIF_HD_ENABLED) { - BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__, - btif_hd_cb.status); + LOG_WARN("%s: BT-HD not enabled, status=%d", __func__, btif_hd_cb.status); return BT_STATUS_NOT_READY; } @@ -510,16 +507,15 @@ static bt_status_t connect(RawAddress* bd_addr) { * ******************************************************************************/ static bt_status_t disconnect(void) { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!btif_hd_cb.app_registered) { - BTIF_TRACE_WARNING("%s: application not yet registered", __func__); + LOG_WARN("%s: application not yet registered", __func__); return BT_STATUS_NOT_READY; } if (btif_hd_cb.status != BTIF_HD_ENABLED) { - BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__, - btif_hd_cb.status); + LOG_WARN("%s: BT-HD not enabled, status=%d", __func__, btif_hd_cb.status); return BT_STATUS_NOT_READY; } @@ -541,16 +537,15 @@ static bt_status_t send_report(bthd_report_type_t type, uint8_t id, uint16_t len, uint8_t* p_data) { tBTA_HD_REPORT report; - APPL_TRACE_VERBOSE("%s: type=%d id=%d len=%d", __func__, type, id, len); + LOG_VERBOSE("%s: type=%d id=%d len=%d", __func__, type, id, len); if (!btif_hd_cb.app_registered) { - BTIF_TRACE_WARNING("%s: application not yet registered", __func__); + LOG_WARN("%s: application not yet registered", __func__); return BT_STATUS_NOT_READY; } if (btif_hd_cb.status != BTIF_HD_ENABLED) { - BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__, - btif_hd_cb.status); + LOG_WARN("%s: BT-HD not enabled, status=%d", __func__, btif_hd_cb.status); return BT_STATUS_NOT_READY; } @@ -581,16 +576,15 @@ static bt_status_t send_report(bthd_report_type_t type, uint8_t id, * ******************************************************************************/ static bt_status_t report_error(uint8_t error) { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!btif_hd_cb.app_registered) { - BTIF_TRACE_WARNING("%s: application not yet registered", __func__); + LOG_WARN("%s: application not yet registered", __func__); return BT_STATUS_NOT_READY; } if (btif_hd_cb.status != BTIF_HD_ENABLED) { - BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__, - btif_hd_cb.status); + LOG_WARN("%s: BT-HD not enabled, status=%d", __func__, btif_hd_cb.status); return BT_STATUS_NOT_READY; } @@ -609,16 +603,15 @@ static bt_status_t report_error(uint8_t error) { * ******************************************************************************/ static bt_status_t virtual_cable_unplug(void) { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!btif_hd_cb.app_registered) { - BTIF_TRACE_WARNING("%s: application not yet registered", __func__); + LOG_WARN("%s: application not yet registered", __func__); return BT_STATUS_NOT_READY; } if (btif_hd_cb.status != BTIF_HD_ENABLED) { - BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__, - btif_hd_cb.status); + LOG_WARN("%s: BT-HD not enabled, status=%d", __func__, btif_hd_cb.status); return BT_STATUS_NOT_READY; } @@ -650,7 +643,7 @@ static const bthd_interface_t bthdInterface = { * ******************************************************************************/ bt_status_t btif_hd_execute_service(bool b_enable) { - BTIF_TRACE_API("%s: b_enable=%d", __func__, b_enable); + LOG_VERBOSE("%s: b_enable=%d", __func__, b_enable); if (!b_enable) BTA_HdDisable(); @@ -667,7 +660,7 @@ bt_status_t btif_hd_execute_service(bool b_enable) { * ******************************************************************************/ const bthd_interface_t* btif_hd_get_interface() { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return &bthdInterface; } @@ -681,7 +674,7 @@ const bthd_interface_t* btif_hd_get_interface() { * ******************************************************************************/ void btif_hd_service_registration() { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* enable HD */ if (bt_hd_callbacks != NULL) { BTA_HdEnable(bte_hd_evt); diff --git a/system/btif/src/btif_hearing_aid.cc b/system/btif/src/btif_hearing_aid.cc index 1fdd46029e217047dbde26980cee89203a0d1f4e..d8ed4ab89f1832941f0eb7931708aeba9e23c81a 100644 --- a/system/btif/src/btif_hearing_aid.cc +++ b/system/btif/src/btif_hearing_aid.cc @@ -27,7 +27,7 @@ #include "bta_hearing_aid_api.h" #include "btif_common.h" #include "btif_profile_storage.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" using base::Bind; @@ -57,7 +57,6 @@ class HearingAidInterfaceImpl ~HearingAidInterfaceImpl() override = default; void Init(HearingAidCallbacks* callbacks) override { - DVLOG(2) << __func__; this->callbacks = callbacks; do_in_main_thread( FROM_HERE, @@ -68,48 +67,38 @@ class HearingAidInterfaceImpl void OnConnectionState(ConnectionState state, const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address); do_in_jni_thread(FROM_HERE, Bind(&HearingAidCallbacks::OnConnectionState, Unretained(callbacks), state, address)); } void OnDeviceAvailable(uint8_t capabilities, uint64_t hiSyncId, const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address) - << ", hiSyncId: " << loghex(hiSyncId) - << ", capabilities: " << loghex(capabilities); do_in_jni_thread(FROM_HERE, Bind(&HearingAidCallbacks::OnDeviceAvailable, Unretained(callbacks), capabilities, hiSyncId, address)); } void Connect(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address); do_in_main_thread(FROM_HERE, Bind(&HearingAid::Connect, address)); } void Disconnect(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address); do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect, address)); do_in_jni_thread(FROM_HERE, Bind(&btif_storage_set_hearing_aid_acceptlist, address, false)); } void AddToAcceptlist(const RawAddress& address) override { - VLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address); do_in_main_thread(FROM_HERE, Bind(&HearingAid::AddToAcceptlist, address)); do_in_jni_thread(FROM_HERE, Bind(&btif_storage_set_hearing_aid_acceptlist, address, true)); } void SetVolume(int8_t volume) override { - DVLOG(2) << __func__ << " volume: " << +volume; do_in_main_thread(FROM_HERE, Bind(&HearingAid::SetVolume, volume)); } void RemoveDevice(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address); - // RemoveDevice can be called on devices that don't have HA enabled if (HearingAid::IsHearingAidRunning()) { do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect, address)); @@ -120,7 +109,6 @@ class HearingAidInterfaceImpl } void Cleanup(void) override { - DVLOG(2) << __func__; do_in_main_thread(FROM_HERE, Bind(&HearingAid::CleanUp)); } diff --git a/system/btif/src/btif_hf.cc b/system/btif/src/btif_hf.cc index 33b9f5d337da489c9bc651c9e1b4e8d1a784b080..1fec690400072b5679ace3fc9a453629afbf8ed2 100644 --- a/system/btif/src/btif_hf.cc +++ b/system/btif/src/btif_hf.cc @@ -26,19 +26,19 @@ ******************************************************************************/ #define LOG_TAG "bt_btif_hf" + +#include +#include #include #include #include -#ifdef __ANDROID__ -#include -#endif - #include #include #include "bta/include/bta_ag_api.h" #include "bta/include/utl.h" +#include "bta_ag_swb_aptx.h" #include "btif/include/btif_common.h" #include "btif/include/btif_metrics_logging.h" #include "btif/include/btif_profile_queue.h" @@ -48,10 +48,11 @@ #include "include/hardware/bluetooth_headset_callbacks.h" #include "include/hardware/bluetooth_headset_interface.h" #include "include/hardware/bt_hf.h" -#include "main/shim/dumpsys.h" -#include "osi/include/log.h" +#include "internal_include/bt_target.h" #include "stack/btm/btm_sco_hfp_hal.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_api.h" +#include "stack/include/btm_log_history.h" #include "types/raw_address.h" namespace { @@ -92,14 +93,14 @@ static RawAddress active_bda = {}; ******************************************************************************/ static Callbacks* bt_hf_callbacks = nullptr; -#define CHECK_BTHF_INIT() \ - do { \ - if (!bt_hf_callbacks) { \ - BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized", __func__); \ - return BT_STATUS_NOT_READY; \ - } else { \ - BTIF_TRACE_EVENT("BTHF: %s", __func__); \ - } \ +#define CHECK_BTHF_INIT() \ + do { \ + if (!bt_hf_callbacks) { \ + LOG_WARN("BTHF: %s: BTHF not initialized", __func__); \ + return BT_STATUS_NOT_READY; \ + } else { \ + LOG_VERBOSE("BTHF: %s", __func__); \ + } \ } while (false) /* BTIF-HF control block to map bdaddr to BTA handle */ @@ -143,33 +144,25 @@ static bool is_active_device(const RawAddress& bd_addr) { } static tBTA_SERVICE_MASK get_BTIF_HF_SERVICES() { -#ifdef __ANDROID__ - static const tBTA_SERVICE_MASK hf_services = - android::sysprop::bluetooth::Hfp::hf_services().value_or( - BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK); - return hf_services; -#else - return BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK; -#endif + return GET_SYSPROP(Hfp, hf_services, + BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK); } /* HF features supported at runtime */ static uint32_t get_hf_features() { +#if TARGET_FLOSS +#define DEFAULT_BTIF_HF_FEATURES \ + (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECS | BTA_AG_FEAT_CODEC | BTA_AG_FEAT_UNAT | \ + BTA_AG_FEAT_HF_IND) +#else #define DEFAULT_BTIF_HF_FEATURES \ (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_REJECT | \ BTA_AG_FEAT_ECS | BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_VREC | \ BTA_AG_FEAT_CODEC | BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO_S4 | \ BTA_AG_FEAT_UNAT) -#ifdef __ANDROID__ - static const uint32_t hf_features = - android::sysprop::bluetooth::Hfp::hf_features().value_or( - DEFAULT_BTIF_HF_FEATURES); - return hf_features; -#elif TARGET_FLOSS - return BTA_AG_FEAT_ECS | BTA_AG_FEAT_CODEC; -#else - return DEFAULT_BTIF_HF_FEATURES; #endif + + return GET_SYSPROP(Hfp, hf_features, DEFAULT_BTIF_HF_FEATURES); } /******************************************************************************* @@ -576,28 +569,47 @@ static void btif_hf_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_AG_CODEC_EVT: - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "BTA_AG_CODEC_EVT Set codec status %d codec %d 1=CVSD 2=MSBC 4=LC3", p_data->val.hdr.status, p_data->val.num); if (p_data->val.num == BTM_SCO_CODEC_CVSD) { bt_hf_callbacks->WbsCallback(BTHF_WBS_NO, &btif_hf_cb[idx].connected_bda); - bt_hf_callbacks->SwbCallback(BTHF_SWB_NO, + bt_hf_callbacks->SwbCallback(BTHF_SWB_CODEC_LC3, BTHF_SWB_NO, &btif_hf_cb[idx].connected_bda); } else if (p_data->val.num == BTM_SCO_CODEC_MSBC) { bt_hf_callbacks->WbsCallback(BTHF_WBS_YES, &btif_hf_cb[idx].connected_bda); - bt_hf_callbacks->SwbCallback(BTHF_SWB_NO, + bt_hf_callbacks->SwbCallback(BTHF_SWB_CODEC_LC3, BTHF_SWB_NO, &btif_hf_cb[idx].connected_bda); } else if (p_data->val.num == BTM_SCO_CODEC_LC3) { bt_hf_callbacks->WbsCallback(BTHF_WBS_NO, &btif_hf_cb[idx].connected_bda); - bt_hf_callbacks->SwbCallback(BTHF_SWB_YES, + bt_hf_callbacks->SwbCallback(BTHF_SWB_CODEC_LC3, BTHF_SWB_YES, &btif_hf_cb[idx].connected_bda); } else { bt_hf_callbacks->WbsCallback(BTHF_WBS_NONE, &btif_hf_cb[idx].connected_bda); - bt_hf_callbacks->SwbCallback(BTHF_SWB_NONE, + + bthf_swb_codec_t codec = BTHF_SWB_CODEC_LC3; + bthf_swb_config_t config = BTHF_SWB_NONE; + + if (is_hfp_aptx_voice_enabled()) { + codec = BTHF_SWB_CODEC_VENDOR_APTX; + + LOG_VERBOSE( + "AG final selected SWB codec is 0x%02x 0=Q0 4=Q1 6=Q2 7=Q3", + p_data->val.num); + if (p_data->val.num == BTA_AG_SCO_APTX_SWB_SETTINGS_Q0 || + p_data->val.num == BTA_AG_SCO_APTX_SWB_SETTINGS_Q1 || + p_data->val.num == BTA_AG_SCO_APTX_SWB_SETTINGS_Q2 || + p_data->val.num == BTA_AG_SCO_APTX_SWB_SETTINGS_Q3) { + config = BTHF_SWB_YES; + } else { + config = BTHF_SWB_NO; + } + } + bt_hf_callbacks->SwbCallback(codec, config, &btif_hf_cb[idx].connected_bda); } break; @@ -632,36 +644,34 @@ static void btif_hf_upstreams_evt(uint16_t event, char* p_param) { send_at_result(BTA_AG_OK_ERROR, BTA_AG_ERR_OP_NOT_SUPPORTED, idx); break; case BTA_AG_AT_BAC_EVT: - BTIF_TRACE_DEBUG("AG Bitmap of peer-codecs %d", p_data->val.num); + LOG_VERBOSE("AG Bitmap of peer-codecs %d", p_data->val.num); /* If the peer supports mSBC and the BTIF preferred codec is also mSBC, * then we should set the BTA AG Codec to mSBC. This would trigger a +BCS * to mSBC at the time of SCO connection establishment */ if (hfp_hal_interface::get_swb_supported() && (p_data->val.num & BTM_SCO_CODEC_LC3)) { - BTIF_TRACE_EVENT("%s: btif_hf override-Preferred Codec to LC3", - __func__); + LOG_VERBOSE("%s: btif_hf override-Preferred Codec to LC3", __func__); BTA_AgSetCodec(btif_hf_cb[idx].handle, BTM_SCO_CODEC_LC3); } else if (hfp_hal_interface::get_wbs_supported() && (p_data->val.num & BTM_SCO_CODEC_MSBC)) { - BTIF_TRACE_EVENT("%s: btif_hf override-Preferred Codec to mSBC", - __func__); + LOG_VERBOSE("%s: btif_hf override-Preferred Codec to mSBC", __func__); BTA_AgSetCodec(btif_hf_cb[idx].handle, BTM_SCO_CODEC_MSBC); } else { - BTIF_TRACE_EVENT("%s btif_hf override-Preferred Codec to CVSD", - __func__); + LOG_VERBOSE("%s btif_hf override-Preferred Codec to CVSD", __func__); BTA_AgSetCodec(btif_hf_cb[idx].handle, BTM_SCO_CODEC_CVSD); } break; case BTA_AG_AT_BCS_EVT: - BTIF_TRACE_DEBUG("%s: AG final selected codec is 0x%02x 1=CVSD 2=MSBC", - __func__, p_data->val.num); + LOG_VERBOSE("AG final selected codec is 0x%02x 1=CVSD 2=MSBC", + p_data->val.num); /* No BTHF_WBS_NONE case, because HF1.6 supported device can send BCS */ /* Only CVSD is considered narrow band speech */ bt_hf_callbacks->WbsCallback( (p_data->val.num == BTM_SCO_CODEC_MSBC) ? BTHF_WBS_YES : BTHF_WBS_NO, &btif_hf_cb[idx].connected_bda); bt_hf_callbacks->SwbCallback( + BTHF_SWB_CODEC_LC3, (p_data->val.num == BTM_SCO_CODEC_LC3) ? BTHF_SWB_YES : BTHF_SWB_NO, &btif_hf_cb[idx].connected_bda); break; @@ -691,6 +701,23 @@ static void btif_hf_upstreams_evt(uint16_t event, char* p_param) { &btif_hf_cb[idx].connected_bda); } break; + + case BTA_AG_AT_QCS_EVT: + if (!is_hfp_aptx_voice_enabled()) { + LOG(WARNING) << __func__ << ": unhandled event " << event + << ". Aptx codec is not enabled"; + break; + } + + LOG_INFO("AG final selected SWB codec is %#02x 0=Q0 4=Q1 6=Q2 7=Q3", + p_data->val.num); + bt_hf_callbacks->SwbCallback( + BTHF_SWB_CODEC_VENDOR_APTX, + p_data->val.num <= BTA_AG_SCO_APTX_SWB_SETTINGS_Q3 ? BTHF_SWB_YES + : BTHF_SWB_NO, + &btif_hf_cb[idx].connected_bda); + break; + default: LOG(WARNING) << __func__ << ": unhandled event " << event; break; @@ -746,8 +773,8 @@ static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG* p_data) { static bt_status_t connect_int(RawAddress* bd_addr, uint16_t uuid) { CHECK_BTHF_INIT(); if (is_connected(bd_addr)) { - BTIF_TRACE_WARNING("%s: device %s is already connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_WARN("%s: device %s is already connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_DONE; } btif_hf_cb_t* hf_cb = nullptr; @@ -767,9 +794,8 @@ static bt_status_t connect_int(RawAddress* bd_addr, uint16_t uuid) { } } if (hf_cb == nullptr) { - BTIF_TRACE_WARNING( - "%s: Cannot connect %s: maximum %d clients already connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr), btif_max_hf_clients); + LOG_WARN("%s: Cannot connect %s: maximum %d clients already connected", + __func__, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr), btif_max_hf_clients); return BT_STATUS_BUSY; } hf_cb->state = BTHF_CONNECTION_STATE_CONNECTING; @@ -823,7 +849,7 @@ class HeadsetInterface : Interface { bool inband_ringing_enabled) override; bt_status_t Connect(RawAddress* bd_addr) override; bt_status_t Disconnect(RawAddress* bd_addr) override; - bt_status_t ConnectAudio(RawAddress* bd_addr, bool force_cvsd) override; + bt_status_t ConnectAudio(RawAddress* bd_addr, int disabled_codecs) override; bt_status_t DisconnectAudio(RawAddress* bd_addr) override; bt_status_t isNoiseReductionSupported(RawAddress* bd_addr) override; bt_status_t isVoiceRecognitionSupported(RawAddress* bd_addr) override; @@ -859,6 +885,7 @@ class HeadsetInterface : Interface { bt_status_t SetScoAllowed(bool value) override; bt_status_t SendBsir(bool value, RawAddress* bd_addr) override; bt_status_t SetActiveDevice(RawAddress* active_device_addr) override; + bt_status_t DebugDump() override; }; bt_status_t HeadsetInterface::Init(Callbacks* callbacks, int max_hf_clients, @@ -874,9 +901,10 @@ bt_status_t HeadsetInterface::Init(Callbacks* callbacks, int max_hf_clients, " maximum is " << BTA_AG_MAX_NUM_CLIENTS << " was given " << max_hf_clients; btif_max_hf_clients = max_hf_clients; - BTIF_TRACE_DEBUG( - "%s: btif_hf_features=%zu, max_hf_clients=%d, inband_ringing_enabled=%d", - __func__, btif_hf_features, btif_max_hf_clients, inband_ringing_enabled); + LOG_VERBOSE("%s: btif_hf_features=%" PRIu32 + ", max_hf_clients=%d, inband_ringing_enabled=%d", + __func__, btif_hf_features, btif_max_hf_clients, + inband_ringing_enabled); bt_hf_callbacks = callbacks; for (btif_hf_cb_t& hf_cb : btif_hf_cb) { reset_control_block(&hf_cb); @@ -903,12 +931,12 @@ bt_status_t HeadsetInterface::Disconnect(RawAddress* bd_addr) { CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } BTA_AgClose(btif_hf_cb[idx].handle); @@ -916,11 +944,11 @@ bt_status_t HeadsetInterface::Disconnect(RawAddress* bd_addr) { } bt_status_t HeadsetInterface::ConnectAudio(RawAddress* bd_addr, - bool force_cvsd) { + int disabled_codecs) { CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } /* Check if SLC is connected */ @@ -929,12 +957,12 @@ bt_status_t HeadsetInterface::ConnectAudio(RawAddress* bd_addr, << ADDRESS_TO_LOGGABLE_STR(*bd_addr); return BT_STATUS_NOT_READY; } - do_in_jni_thread(base::Bind(&Callbacks::AudioStateCallback, - // Manual pointer management for now - base::Unretained(bt_hf_callbacks), - BTHF_AUDIO_STATE_CONNECTING, - &btif_hf_cb[idx].connected_bda)); - BTA_AgAudioOpen(btif_hf_cb[idx].handle, force_cvsd); + do_in_jni_thread(base::BindOnce(&Callbacks::AudioStateCallback, + // Manual pointer management for now + base::Unretained(bt_hf_callbacks), + BTHF_AUDIO_STATE_CONNECTING, + &btif_hf_cb[idx].connected_bda)); + BTA_AgAudioOpen(btif_hf_cb[idx].handle, disabled_codecs); DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(*bd_addr, IOT_CONF_KEY_HFP_SCO_CONN_COUNT); @@ -945,12 +973,12 @@ bt_status_t HeadsetInterface::DisconnectAudio(RawAddress* bd_addr) { CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } BTA_AgAudioClose(btif_hf_cb[idx].handle); @@ -961,7 +989,7 @@ bt_status_t HeadsetInterface::isNoiseReductionSupported(RawAddress* bd_addr) { CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!(btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_ECNR)) { @@ -974,7 +1002,7 @@ bt_status_t HeadsetInterface::isVoiceRecognitionSupported(RawAddress* bd_addr) { CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!(btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)) { @@ -987,17 +1015,17 @@ bt_status_t HeadsetInterface::StartVoiceRecognition(RawAddress* bd_addr) { CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_NOT_READY; } if (!(btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)) { - BTIF_TRACE_ERROR("%s: voice recognition not supported, features=0x%x", - __func__, btif_hf_cb[idx].peer_feat); + LOG_ERROR("%s: voice recognition not supported, features=0x%x", __func__, + btif_hf_cb[idx].peer_feat); return BT_STATUS_UNSUPPORTED; } tBTA_AG_RES_DATA ag_res = {}; @@ -1011,17 +1039,17 @@ bt_status_t HeadsetInterface::StopVoiceRecognition(RawAddress* bd_addr) { int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_NOT_READY; } if (!(btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)) { - BTIF_TRACE_ERROR("%s: voice recognition not supported, features=0x%x", - __func__, btif_hf_cb[idx].peer_feat); + LOG_ERROR("%s: voice recognition not supported, features=0x%x", __func__, + btif_hf_cb[idx].peer_feat); return BT_STATUS_UNSUPPORTED; } tBTA_AG_RES_DATA ag_res = {}; @@ -1035,12 +1063,12 @@ bt_status_t HeadsetInterface::VolumeControl(bthf_volume_type_t type, int volume, CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } tBTA_AG_RES_DATA ag_res = {}; @@ -1056,13 +1084,13 @@ bt_status_t HeadsetInterface::DeviceStatusNotification( int batt_chg, RawAddress* bd_addr) { CHECK_BTHF_INIT(); if (!bd_addr) { - BTIF_TRACE_WARNING("%s: bd_addr is null", __func__); + LOG_WARN("%s: bd_addr is null", __func__); return BT_STATUS_FAIL; } int idx = btif_hf_idx_by_bdaddr(bd_addr); if (idx < 0 || idx > BTA_AG_MAX_NUM_CLIENTS) { - BTIF_TRACE_WARNING("%s: invalid index %d for %s", __func__, idx, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_WARN("%s: invalid index %d for %s", __func__, idx, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } const btif_hf_cb_t& control_block = btif_hf_cb[idx]; @@ -1085,12 +1113,12 @@ bt_status_t HeadsetInterface::CopsResponse(const char* cops, CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } tBTA_AG_RES_DATA ag_res = {}; @@ -1109,12 +1137,12 @@ bt_status_t HeadsetInterface::CindResponse(int svc, int num_active, CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } tBTA_AG_RES_DATA ag_res = {}; @@ -1139,12 +1167,12 @@ bt_status_t HeadsetInterface::FormattedAtResponse(const char* rsp, tBTA_AG_RES_DATA ag_res = {}; int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } /* Format the response and send */ @@ -1158,12 +1186,12 @@ bt_status_t HeadsetInterface::AtResponse(bthf_at_response_t response_code, CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } send_at_result( @@ -1179,12 +1207,12 @@ bt_status_t HeadsetInterface::ClccResponse( CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx); + LOG_ERROR("%s: Invalid index %d", __func__, idx); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s is not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s is not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } tBTA_AG_RES_DATA ag_res = {}; @@ -1193,7 +1221,7 @@ bt_status_t HeadsetInterface::ClccResponse( ag_res.ok_flag = BTA_AG_OK_DONE; } else { std::string cell_number(number ? number : ""); - BTIF_TRACE_EVENT( + LOG_VERBOSE( "clcc_response: [%d] dir %d state %d mode %d number = %s type = %d", index, dir, state, mode, PRIVATE_CELL(cell_number), type); int res_strlen = snprintf(ag_res.str, sizeof(ag_res.str), "%d,%d,%d,%d,%d", @@ -1301,7 +1329,7 @@ bt_status_t HeadsetInterface::PhoneStateChange( (control_block.num_held == 0) && (control_block.call_setup_state == BTHF_CALL_STATE_IDLE)) { tBTA_AG_RES_DATA ag_res = {}; - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Active/Held call notification received without call setup " "update", __func__); @@ -1323,9 +1351,9 @@ bt_status_t HeadsetInterface::PhoneStateChange( if (call_setup_state != control_block.call_setup_state) { tBTA_AG_RES_DATA ag_res = {}; ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE; - BTIF_TRACE_DEBUG("%s: Call setup states changed. old: %s new: %s", __func__, - dump_hf_call_state(control_block.call_setup_state), - dump_hf_call_state(call_setup_state)); + LOG_VERBOSE("%s: Call setup states changed. old: %s new: %s", __func__, + dump_hf_call_state(control_block.call_setup_state), + dump_hf_call_state(call_setup_state)); switch (call_setup_state) { case BTHF_CALL_STATE_IDLE: { switch (control_block.call_setup_state) { @@ -1348,9 +1376,8 @@ bt_status_t HeadsetInterface::PhoneStateChange( res = BTA_AG_CALL_CANCEL_RES; break; default: - BTIF_TRACE_ERROR("%s: Incorrect call state prev=%d, now=%d", - __func__, control_block.call_setup_state, - call_setup_state); + LOG_ERROR("%s: Incorrect call state prev=%d, now=%d", __func__, + control_block.call_setup_state, call_setup_state); status = BT_STATUS_PARM_INVALID; break; } @@ -1437,13 +1464,13 @@ bt_status_t HeadsetInterface::PhoneStateChange( res = BTA_AG_OUT_CALL_ALERT_RES; break; default: - BTIF_TRACE_ERROR("%s: Incorrect call state prev=%d, now=%d", __func__, - control_block.call_setup_state, call_setup_state); + LOG_ERROR("%s: Incorrect call state prev=%d, now=%d", __func__, + control_block.call_setup_state, call_setup_state); status = BT_STATUS_PARM_INVALID; break; } - BTIF_TRACE_DEBUG("%s: Call setup state changed. res=%d, audio_handle=%d", - __func__, res, ag_res.audio_handle); + LOG_VERBOSE("%s: Call setup state changed. res=%d, audio_handle=%d", + __func__, res, ag_res.audio_handle); if (res != 0xFF) { BTA_AgResult(control_block.handle, res, ag_res); @@ -1484,8 +1511,8 @@ bt_status_t HeadsetInterface::PhoneStateChange( /* Held Changed? */ if (num_held != control_block.num_held || ((num_active == 0) && ((num_held + control_block.num_held) > 1))) { - BTIF_TRACE_DEBUG("%s: Held call states changed. old: %d new: %d", __func__, - control_block.num_held, num_held); + LOG_VERBOSE("%s: Held call states changed. old: %d new: %d", __func__, + control_block.num_held, num_held); send_indicator_update(control_block, BTA_AG_IND_CALLHELD, ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1))); } @@ -1494,7 +1521,7 @@ bt_status_t HeadsetInterface::PhoneStateChange( if ((call_setup_state == control_block.call_setup_state) && (num_active && num_held) && (num_active == control_block.num_active) && (num_held == control_block.num_held)) { - BTIF_TRACE_DEBUG("%s: Calls swapped", __func__); + LOG_VERBOSE("%s: Calls swapped", __func__); send_indicator_update(control_block, BTA_AG_IND_CALLHELD, 1); } @@ -1521,7 +1548,7 @@ bt_status_t HeadsetInterface::PhoneStateChange( } void HeadsetInterface::Cleanup() { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_queue_cleanup(UUID_SERVCLASS_AG_HANDSFREE); @@ -1536,7 +1563,8 @@ void HeadsetInterface::Cleanup() { } } - do_in_jni_thread(FROM_HERE, base::Bind([]() { bt_hf_callbacks = nullptr; })); + do_in_jni_thread(FROM_HERE, + base::BindOnce([]() { bt_hf_callbacks = nullptr; })); } bt_status_t HeadsetInterface::SetScoOffloadEnabled(bool value) { @@ -1555,13 +1583,13 @@ bt_status_t HeadsetInterface::SendBsir(bool value, RawAddress* bd_addr) { CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { - BTIF_TRACE_ERROR("%s: Invalid index %d for %s", __func__, idx, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: Invalid index %d for %s", __func__, idx, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } if (!is_connected(bd_addr)) { - BTIF_TRACE_ERROR("%s: %s not connected", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: %s not connected", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } tBTA_AG_RES_DATA ag_result = {}; @@ -1577,6 +1605,19 @@ bt_status_t HeadsetInterface::SetActiveDevice(RawAddress* active_device_addr) { return BT_STATUS_SUCCESS; } +bt_status_t HeadsetInterface::DebugDump() { + CHECK_BTHF_INIT(); + tBTM_SCO_DEBUG_DUMP debug_dump = BTM_GetScoDebugDump(); + bt_hf_callbacks->DebugDumpCallback( + debug_dump.is_active, debug_dump.codec_id, + debug_dump.total_num_decoded_frames, debug_dump.pkt_loss_ratio, + debug_dump.latest_data.begin_ts_raw_us, + debug_dump.latest_data.end_ts_raw_us, + debug_dump.latest_data.status_in_hex.c_str(), + debug_dump.latest_data.status_in_binary.c_str()); + return BT_STATUS_SUCCESS; +} + /******************************************************************************* * * Function btif_hf_execute_service diff --git a/system/btif/src/btif_hf_client.cc b/system/btif/src/btif_hf_client.cc index 42a2c07d5744ff6f961826bd9840cdabe2c18a2e..16b3ed777664a71a7b23f05b5f7eddb003dd9fdf 100644 --- a/system/btif/src/btif_hf_client.cc +++ b/system/btif/src/btif_hf_client.cc @@ -46,6 +46,7 @@ #define LOG_TAG "bt_btif_hfc" #endif +#include #include #include #include @@ -56,10 +57,10 @@ #include "btif_util.h" #include "osi/include/osi.h" #include "osi/include/properties.h" +#include "stack/btm/btm_sco_hfp_hal.h" +#include "stack/include/bt_uuid16.h" #include "types/raw_address.h" -#include - /******************************************************************************* * Constants & Macros ******************************************************************************/ @@ -112,27 +113,27 @@ static const char* dump_hf_client_conn_state(uint16_t event) { } } -#define CHECK_BTHF_CLIENT_INIT() \ - do { \ - if (bt_hf_client_callbacks == NULL) { \ - BTIF_TRACE_WARNING("BTHF CLIENT: %s: not initialized", __func__); \ - return BT_STATUS_NOT_READY; \ - } else { \ - BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__); \ - } \ +#define CHECK_BTHF_CLIENT_INIT() \ + do { \ + if (bt_hf_client_callbacks == NULL) { \ + LOG_WARN("BTHF CLIENT: %s: not initialized", __func__); \ + return BT_STATUS_NOT_READY; \ + } else { \ + LOG_VERBOSE("BTHF CLIENT: %s", __func__); \ + } \ } while (0) #define CHECK_BTHF_CLIENT_SLC_CONNECTED(cb) \ do { \ if (bt_hf_client_callbacks == NULL) { \ - BTIF_TRACE_WARNING("BTHF CLIENT: %s: not initialized", __func__); \ + LOG_WARN("BTHF CLIENT: %s: not initialized", __func__); \ return BT_STATUS_NOT_READY; \ } else if ((cb)->state != BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) { \ - BTIF_TRACE_WARNING("BTHF CLIENT: %s: SLC connection not up. state=%s", \ - __func__, dump_hf_client_conn_state((cb)->state)); \ + LOG_WARN("BTHF CLIENT: %s: SLC connection not up. state=%s", __func__, \ + dump_hf_client_conn_state((cb)->state)); \ return BT_STATUS_NOT_READY; \ } else { \ - BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__); \ + LOG_VERBOSE("BTHF CLIENT: %s", __func__); \ } \ } while (0) @@ -154,22 +155,22 @@ static btif_hf_client_cb_arr_t btif_hf_client_cb_arr; * ******************************************************************************/ static void btif_in_hf_client_generic_evt(uint16_t event, char* p_param) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); RawAddress* bd_addr = (RawAddress*)p_param; btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(*bd_addr); if (cb == NULL || !is_connected(cb)) { - BTIF_TRACE_ERROR("%s: failed to find block for bda", __func__); + LOG_ERROR("%s: failed to find block for bda", __func__); return; } - BTIF_TRACE_EVENT("%s: event=%d", __func__, event); + LOG_VERBOSE("%s: event=%d", __func__, event); switch (event) { case BTIF_HF_CLIENT_CB_AUDIO_CONNECTING: { HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda, (bthf_client_audio_state_t)BTHF_CLIENT_AUDIO_STATE_CONNECTING); } break; default: { - BTIF_TRACE_WARNING("%s: : Unknown event 0x%x", __func__, event); + LOG_WARN("%s: : Unknown event 0x%x", __func__, event); } break; } } @@ -182,7 +183,7 @@ bool is_connected(const btif_hf_client_cb_t* cb) { (cb->state == BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED)) return true; - BTIF_TRACE_ERROR("%s: not connected!", __func__); + LOG_ERROR("%s: not connected!", __func__); return false; } @@ -196,7 +197,7 @@ bool is_connected(const btif_hf_client_cb_t* cb) { * ******************************************************************************/ btif_hf_client_cb_t* btif_hf_client_get_cb_by_handle(uint16_t handle) { - BTIF_TRACE_DEBUG("%s: cb by handle %d", __func__, handle); + LOG_VERBOSE("%s: cb by handle %d", __func__, handle); for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) { // Block is valid only if it is allocated i.e. state is not DISCONNECTED if (btif_hf_client_cb_arr.cb[i].state != @@ -205,7 +206,7 @@ btif_hf_client_cb_t* btif_hf_client_get_cb_by_handle(uint16_t handle) { return &btif_hf_client_cb_arr.cb[i]; } } - BTIF_TRACE_ERROR("%s: could not find block for handle %d", __func__, handle); + LOG_ERROR("%s: could not find block for handle %d", __func__, handle); return NULL; } @@ -229,7 +230,7 @@ btif_hf_client_cb_t* btif_hf_client_get_cb_by_bda(const RawAddress& bd_addr) { return &btif_hf_client_cb_arr.cb[i]; } } - BTIF_TRACE_ERROR("%s: could not find block for bdaddr", __func__); + LOG_ERROR("%s: could not find block for bdaddr", __func__); return NULL; } @@ -249,7 +250,7 @@ btif_hf_client_cb_t* btif_hf_client_allocate_cb() { return cb; } } - BTIF_TRACE_ERROR("%s: unable to allocate control block", __func__); + LOG_ERROR("%s: unable to allocate control block", __func__); return NULL; } @@ -269,7 +270,7 @@ btif_hf_client_cb_t* btif_hf_client_allocate_cb() { * ******************************************************************************/ static bt_status_t init(bthf_client_callbacks_t* callbacks) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); bt_hf_client_callbacks = callbacks; @@ -292,7 +293,7 @@ static bt_status_t init(bthf_client_callbacks_t* callbacks) { static bt_status_t connect_int(RawAddress* bd_addr, uint16_t uuid) { btif_hf_client_cb_t* cb = btif_hf_client_allocate_cb(); if (cb == NULL) { - BTIF_TRACE_ERROR("%s: could not allocate block!", __func__); + LOG_ERROR("%s: could not allocate block!", __func__); return BT_STATUS_BUSY; } @@ -310,7 +311,7 @@ static bt_status_t connect_int(RawAddress* bd_addr, uint16_t uuid) { } static bt_status_t connect(const RawAddress* bd_addr) { - BTIF_TRACE_EVENT("HFP Client version is %s", btif_hf_client_version); + LOG_VERBOSE("HFP Client version is %s", btif_hf_client_version); CHECK_BTHF_CLIENT_INIT(); return btif_queue_connect(UUID_SERVCLASS_HF_HANDSFREE, bd_addr, connect_int); } @@ -704,7 +705,7 @@ static bt_status_t request_last_voice_tag_number(const RawAddress* bd_addr) { * ******************************************************************************/ static void cleanup(void) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_queue_cleanup(UUID_SERVCLASS_HF_HANDSFREE); if (bt_hf_client_callbacks) { @@ -729,8 +730,8 @@ static bt_status_t send_at_cmd(const RawAddress* bd_addr, int cmd, int val1, CHECK_BTHF_CLIENT_SLC_CONNECTED(cb); - BTIF_TRACE_EVENT("%s: Cmd %d val1 %d val2 %d arg %s", __func__, cmd, val1, - val2, (arg != NULL) ? arg : ""); + LOG_VERBOSE("%s: Cmd %d val1 %d val2 %d arg %s", __func__, cmd, val1, val2, + (arg != NULL) ? arg : ""); BTA_HfClientSendAT(cb->handle, cmd, val1, val2, arg); return BT_STATUS_SUCCESS; @@ -751,7 +752,7 @@ static bt_status_t send_android_at(const RawAddress* bd_addr, const char* arg) { CHECK_BTHF_CLIENT_SLC_CONNECTED(cb); - BTIF_TRACE_EVENT("%s: val1 %s", __func__, arg); + LOG_VERBOSE("%s: val1 %s", __func__, arg); BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_ANDROID, 0, 0, arg); return BT_STATUS_SUCCESS; @@ -781,7 +782,7 @@ static const bthf_client_interface_t bthfClientInterface = { }; static void process_ind_evt(tBTA_HF_CLIENT_IND* ind) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(ind->bd_addr); if (cb == NULL || !is_connected(cb)) return; @@ -840,24 +841,23 @@ static void btif_hf_client_upstreams_evt(uint16_t event, char* p_param) { btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(p_data->bd_addr); if (cb == NULL && event == BTA_HF_CLIENT_OPEN_EVT) { - BTIF_TRACE_DEBUG("%s: event BTA_HF_CLIENT_OPEN_EVT allocating block", - __func__); + LOG_VERBOSE("%s: event BTA_HF_CLIENT_OPEN_EVT allocating block", __func__); cb = btif_hf_client_allocate_cb(); if (cb == NULL) { - BTIF_TRACE_ERROR("%s: event BTA_HF_CLIENT_OPEN_EVT failed to allocate cb", - __func__, event); + LOG_ERROR("%s: event BTA_HF_CLIENT_OPEN_EVT failed to allocate cb", + __func__); return; } cb->handle = p_data->open.handle; cb->peer_bda = p_data->open.bd_addr; } else if (cb == NULL) { - BTIF_TRACE_ERROR("%s: event %d but not allocating block: cb not found", - __func__, event); + LOG_ERROR("%s: event %d but not allocating block: cb not found", __func__, + event); return; } - BTIF_TRACE_DEBUG("%s: event=%s (%u)", __func__, dump_hf_client_event(event), - event); + LOG_VERBOSE("%s: event=%s (%u)", __func__, dump_hf_client_event(event), + event); switch (event) { case BTA_HF_CLIENT_OPEN_EVT: @@ -869,7 +869,7 @@ static void btif_hf_client_upstreams_evt(uint16_t event, char* p_param) { } else if (cb->state == BTHF_CLIENT_CONNECTION_STATE_CONNECTING) { cb->state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED; } else { - BTIF_TRACE_WARNING( + LOG_WARN( "%s: HF CLient open failed, but another device connected. " "status=%d state=%d connected device=%s", __func__, p_data->open.status, cb->state, @@ -1025,7 +1025,10 @@ static void btif_hf_client_upstreams_evt(uint16_t event, char* p_param) { HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda, BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC); break; - + case BTA_HF_CLIENT_AUDIO_LC3_OPEN_EVT: + HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda, + BTHF_CLIENT_AUDIO_STATE_CONNECTED_LC3); + break; case BTA_HF_CLIENT_AUDIO_CLOSE_EVT: HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda, BTHF_CLIENT_AUDIO_STATE_DISCONNECTED); @@ -1038,7 +1041,7 @@ static void btif_hf_client_upstreams_evt(uint16_t event, char* p_param) { p_data->unknown.event_string); break; default: - BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event); + LOG_WARN("%s: Unhandled event: %d", __func__, event); break; } } @@ -1076,18 +1079,21 @@ static void bta_hf_client_evt(tBTA_HF_CLIENT_EVT event, * ******************************************************************************/ bt_status_t btif_hf_client_execute_service(bool b_enable) { - BTIF_TRACE_EVENT("%s: enable: %d", __func__, b_enable); + LOG_VERBOSE("%s: enable: %d", __func__, b_enable); tBTA_HF_CLIENT_FEAT features = get_default_hf_client_features(); uint16_t hfp_version = get_default_hfp_version(); + if (hfp_version >= HFP_VERSION_1_9 && + hfp_hal_interface::get_swb_supported()) { + features |= BTA_HF_CLIENT_FEAT_SWB; + } if (hfp_version >= HFP_VERSION_1_7) { features |= BTA_HF_CLIENT_FEAT_ESCO_S4; } if (b_enable) { /* Enable and register with BTA-HFClient */ - BTIF_TRACE_EVENT("%s: support codec negotiation %d ", __func__, - features); + LOG_VERBOSE("%s: support codec negotiation %d ", __func__, features); BTA_HfClientEnable(bta_hf_client_evt, features, BTIF_HF_CLIENT_SERVICE_NAME); } else { @@ -1106,6 +1112,6 @@ bt_status_t btif_hf_client_execute_service(bool b_enable) { * ******************************************************************************/ const bthf_client_interface_t* btif_hf_client_get_interface(void) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); return &bthfClientInterface; } diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index fea75ef0cbbb1d7b303f3de8975a0157520daa9c..e476c18fbdaf262c6871e2b70f5ed8dda9b0bfc2 100644 --- a/system/btif/src/btif_hh.cc +++ b/system/btif/src/btif_hh.cc @@ -33,6 +33,7 @@ #include +#include "bta_sec_api.h" #include "bta_hh_co.h" #include "btif/include/btif_common.h" #include "btif/include/btif_profile_storage.h" @@ -102,12 +103,12 @@ static tHID_KB_LIST hid_kb_numlock_on_list[] = {{LOGITECH_KB_MX5500_PRODUCT_ID, LOGITECH_KB_MX5500_VENDOR_ID, "Logitech MX5500 Keyboard"}}; -#define CHECK_BTHH_INIT() \ - do { \ - if (bt_hh_callbacks == NULL) { \ - BTIF_TRACE_WARNING("BTHH: %s: BTHH not initialized", __func__); \ - return BT_STATUS_NOT_READY; \ - } \ +#define CHECK_BTHH_INIT() \ + do { \ + if (bt_hh_callbacks == NULL) { \ + LOG_WARN("BTHH: %s: BTHH not initialized", __func__); \ + return BT_STATUS_NOT_READY; \ + } \ } while (0) /******************************************************************************* @@ -119,13 +120,14 @@ static tHID_KB_LIST hid_kb_numlock_on_list[] = {{LOGITECH_KB_MX5500_PRODUCT_ID, ******************************************************************************/ bool check_cod(const RawAddress* remote_bdaddr, uint32_t cod); bool check_cod_hid(const RawAddress* remote_bdaddr); +bool check_cod_hid_major(const RawAddress& bd_addr, uint32_t cod); void bta_hh_co_close(btif_hh_device_t* p_dev); void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name, uint16_t vendor_id, uint16_t product_id, uint16_t version, uint8_t ctry_code, int dscp_len, uint8_t* p_dscp); void bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len); -void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data); +static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data); void btif_dm_hh_open_failed(RawAddress* bdaddr); void btif_hd_service_registration(); void btif_hh_timer_timeout(void* data); @@ -158,8 +160,8 @@ static void set_keylockstate(int keymask, bool isSet) { ******************************************************************************/ static void toggle_os_keylockstates(int fd, int changedlockstates) { - BTIF_TRACE_EVENT("%s: fd = %d, changedlockstates = 0x%x", __func__, fd, - changedlockstates); + LOG_VERBOSE("%s: fd = %d, changedlockstates = 0x%x", __func__, fd, + changedlockstates); uint8_t hidreport[9]; int reportIndex; memset(hidreport, 0, 9); @@ -167,40 +169,40 @@ static void toggle_os_keylockstates(int fd, int changedlockstates) { reportIndex = 4; if (changedlockstates & BTIF_HH_KEYSTATE_MASK_CAPSLOCK) { - BTIF_TRACE_DEBUG("%s Setting CAPSLOCK", __func__); + LOG_VERBOSE("%s Setting CAPSLOCK", __func__); hidreport[reportIndex++] = (uint8_t)HID_REPORT_CAPSLOCK; } if (changedlockstates & BTIF_HH_KEYSTATE_MASK_NUMLOCK) { - BTIF_TRACE_DEBUG("%s Setting NUMLOCK", __func__); + LOG_VERBOSE("%s Setting NUMLOCK", __func__); hidreport[reportIndex++] = (uint8_t)HID_REPORT_NUMLOCK; } if (changedlockstates & BTIF_HH_KEYSTATE_MASK_SCROLLLOCK) { - BTIF_TRACE_DEBUG("%s Setting SCROLLLOCK", __func__); + LOG_VERBOSE("%s Setting SCROLLLOCK", __func__); hidreport[reportIndex++] = (uint8_t)HID_REPORT_SCROLLLOCK; } - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "Writing hidreport #1 to os: " "%s: %x %x %x", __func__, hidreport[0], hidreport[1], hidreport[2]); - BTIF_TRACE_DEBUG("%s: %x %x %x", __func__, hidreport[3], hidreport[4], - hidreport[5]); - BTIF_TRACE_DEBUG("%s: %x %x %x", __func__, hidreport[6], hidreport[7], - hidreport[8]); + LOG_VERBOSE("%s: %x %x %x", __func__, hidreport[3], hidreport[4], + hidreport[5]); + LOG_VERBOSE("%s: %x %x %x", __func__, hidreport[6], hidreport[7], + hidreport[8]); bta_hh_co_write(fd, hidreport, sizeof(hidreport)); usleep(200000); memset(hidreport, 0, 9); hidreport[0] = 1; - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "Writing hidreport #2 to os: " "%s: %x %x %x", __func__, hidreport[0], hidreport[1], hidreport[2]); - BTIF_TRACE_DEBUG("%s: %x %x %x", __func__, hidreport[3], hidreport[4], - hidreport[5]); - BTIF_TRACE_DEBUG("%s: %x %x %x ", __func__, hidreport[6], hidreport[7], - hidreport[8]); + LOG_VERBOSE("%s: %x %x %x", __func__, hidreport[3], hidreport[4], + hidreport[5]); + LOG_VERBOSE("%s: %x %x %x ", __func__, hidreport[6], hidreport[7], + hidreport[8]); bta_hh_co_write(fd, hidreport, sizeof(hidreport)); } @@ -239,8 +241,8 @@ static void update_keyboard_lockstates(btif_hh_device_t* p_dev) { static_cast(btif_hh_keylockstates)}; /* keystate */ /* Set report for other keyboards */ - BTIF_TRACE_EVENT("%s: setting report on dev_handle %d to 0x%x", __func__, - p_dev->dev_handle, btif_hh_keylockstates); + LOG_VERBOSE("%s: setting report on dev_handle %d to 0x%x", __func__, + p_dev->dev_handle, btif_hh_keylockstates); /* Get SetReport buffer */ p_buf = create_pbuf(len, data); @@ -263,7 +265,7 @@ static void update_keyboard_lockstates(btif_hh_device_t* p_dev) { static void sync_lockstate_on_connect(btif_hh_device_t* p_dev) { int keylockstates; - BTIF_TRACE_EVENT( + LOG_VERBOSE( "%s: Syncing keyboard lock states after " "reconnect...", __func__); @@ -275,14 +277,14 @@ static void sync_lockstate_on_connect(btif_hh_device_t* p_dev) { so the lockstate is in sync */ keylockstates = get_keylockstates(); if (keylockstates) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Sending hid report to kernel " "indicating lock key state 0x%x", __func__, keylockstates); usleep(200000); toggle_os_keylockstates(p_dev->fd, keylockstates); } else { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: NOT sending hid report to kernel " "indicating lock key state 0x%x", __func__, keylockstates); @@ -361,7 +363,7 @@ static void btif_hh_stop_vup_timer(RawAddress* bd_addr) { btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(*bd_addr); if (p_dev != NULL) { - BTIF_TRACE_DEBUG("stop VUP timer"); + LOG_VERBOSE("stop VUP timer"); alarm_free(p_dev->vup_timer); p_dev->vup_timer = NULL; } @@ -375,7 +377,7 @@ static void btif_hh_stop_vup_timer(RawAddress* bd_addr) { * Returns void ******************************************************************************/ static void btif_hh_start_vup_timer(const RawAddress* bd_addr) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(*bd_addr); CHECK(p_dev != NULL); @@ -439,8 +441,8 @@ static void hh_open_handler(tBTA_HH_CONN& conn) { p_dev->dev_status = BTHH_CONN_STATE_CONNECTED; hh_connect_complete(conn.handle, conn.bda, BTIF_HH_DEV_CONNECTED); // Send set_idle if the peer_device is a keyboard - if (check_cod(&conn.bda, COD_HID_KEYBOARD) || - check_cod(&conn.bda, COD_HID_COMBO)) { + if (check_cod_hid_major(conn.bda, COD_HID_KEYBOARD) || + check_cod_hid_major(conn.bda, COD_HID_COMBO)) { BTA_HhSetIdle(conn.handle, 0); } BTA_HhGetDscpInfo(conn.handle); @@ -472,7 +474,7 @@ bool btif_hh_add_added_dev(const RawAddress& bda, tBTA_HH_ATTR_MASK attr_mask) { } } - BTIF_TRACE_WARNING("%s: Error, out of space to add device", __func__); + LOG_WARN("%s: Error, out of space to add device", __func__); return false; } @@ -525,7 +527,7 @@ void btif_hh_remove_device(RawAddress bd_addr) { if (btif_hh_cb.device_num > 0) { btif_hh_cb.device_num--; } else { - BTIF_TRACE_WARNING("%s: device_num = 0", __func__); + LOG_WARN("%s: device_num = 0", __func__); } bta_hh_co_close(p_dev); @@ -562,13 +564,13 @@ bool btif_hh_copy_hid_info(tBTA_HH_DEV_DSCP_INFO* dest, ******************************************************************************/ bt_status_t btif_hh_virtual_unplug(const RawAddress* bd_addr) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_hh_device_t* p_dev; p_dev = btif_hh_find_dev_by_bda(*bd_addr); if ((p_dev != NULL) && (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED) && (p_dev->attr_mask & HID_VIRTUAL_CABLE)) { - BTIF_TRACE_DEBUG("%s: Sending BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG for: %s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_VERBOSE("%s: Sending BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG for: %s", + __func__, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); /* start the timer */ btif_hh_start_vup_timer(bd_addr); p_dev->local_vup = true; @@ -576,17 +578,16 @@ bt_status_t btif_hh_virtual_unplug(const RawAddress* bd_addr) { return BT_STATUS_SUCCESS; } else if ((p_dev != NULL) && (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED)) { - BTIF_TRACE_ERROR( - "%s: Virtual unplug not supported, disconnecting device: %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: Virtual unplug not supported, disconnecting device: %s", + __func__, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); /* start the timer */ btif_hh_start_vup_timer(bd_addr); p_dev->local_vup = true; BTA_HhClose(p_dev->dev_handle); return BT_STATUS_SUCCESS; } else { - BTIF_TRACE_ERROR("%s: Error, device %s not opened, status = %d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr), btif_hh_cb.status); + LOG_ERROR("%s: Error, device %s not opened, status = %d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr), btif_hh_cb.status); if ((btif_hh_cb.pending_conn_address == *bd_addr) && (btif_hh_cb.status == BTIF_HH_DEV_CONNECTING)) { btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED; @@ -618,13 +619,12 @@ bt_status_t btif_hh_virtual_unplug(const RawAddress* bd_addr) { bt_status_t btif_hh_connect(const RawAddress* bd_addr) { btif_hh_added_device_t* added_dev = NULL; CHECK_BTHH_INIT(); - BTIF_TRACE_EVENT("BTHH: %s", __func__); + LOG_VERBOSE("BTHH: %s", __func__); btif_hh_device_t* dev = btif_hh_find_dev_by_bda(*bd_addr); if (!dev && btif_hh_cb.device_num >= BTIF_HH_MAX_HID) { // No space for more HID device now. - BTIF_TRACE_WARNING( - "%s: Error, exceeded the maximum supported HID device number %d", - __func__, BTIF_HH_MAX_HID); + LOG_WARN("%s: Error, exceeded the maximum supported HID device number %d", + __func__, BTIF_HH_MAX_HID); return BT_STATUS_NOMEM; } @@ -708,8 +708,8 @@ void btif_hh_setreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type, uint16_t size, uint8_t* report) { BT_HDR* p_buf = create_pbuf(size, report); if (p_buf == NULL) { - APPL_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, size = %d", - __func__, size); + LOG_ERROR("%s: Error, failed to allocate RPT buffer, size = %d", __func__, + size); return; } BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf); @@ -727,8 +727,8 @@ void btif_hh_setreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type, void btif_hh_senddata(btif_hh_device_t* p_dev, uint16_t size, uint8_t* report) { BT_HDR* p_buf = create_pbuf(size, report); if (p_buf == NULL) { - APPL_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, size = %d", - __func__, size); + LOG_ERROR("%s: Error, failed to allocate RPT buffer, size = %d", __func__, + size); return; } p_buf->layer_specific = BTA_HH_RPTT_OUTPUT; @@ -745,9 +745,9 @@ void btif_hh_senddata(btif_hh_device_t* p_dev, uint16_t size, uint8_t* report) { * ******************************************************************************/ void btif_hh_service_registration(bool enable) { - BTIF_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); - BTIF_TRACE_API("enable = %d", enable); + LOG_VERBOSE("enable = %d", enable); if (bt_hh_callbacks == NULL) { // The HID Host service was never initialized (it is either disabled or not // available in this build). We should proceed directly to changing the HID @@ -804,23 +804,22 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { int i; int len, tmplen; - BTIF_TRACE_DEBUG("%s: event=%s dereg = %d", __func__, dump_hh_event(event), - btif_hh_cb.service_dereg_active); + LOG_VERBOSE("%s: event=%s dereg = %d", __func__, dump_hh_event(event), + btif_hh_cb.service_dereg_active); switch (event) { case BTA_HH_ENABLE_EVT: - BTIF_TRACE_DEBUG("%s: BTA_HH_ENABLE_EVT: status =%d", __func__, - p_data->status); + LOG_VERBOSE("%s: BTA_HH_ENABLE_EVT: status =%d", __func__, + p_data->status); if (p_data->status == BTA_HH_OK) { btif_hh_cb.status = BTIF_HH_ENABLED; - BTIF_TRACE_DEBUG("%s--Loading added devices", __func__); + LOG_VERBOSE("%s--Loading added devices", __func__); /* Add hid descriptors for already bonded hid devices*/ btif_storage_load_bonded_hid_info(); } else { btif_hh_cb.status = BTIF_HH_DISABLED; - BTIF_TRACE_WARNING( - "BTA_HH_ENABLE_EVT: Error, HH enabling failed, status = %d", - p_data->status); + LOG_WARN("BTA_HH_ENABLE_EVT: Error, HH enabling failed, status = %d", + p_data->status); } break; @@ -831,7 +830,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { btif_hh_cb.status = BTIF_HH_DISABLED; if (btif_hh_cb.service_dereg_active) { - BTIF_TRACE_DEBUG("BTA_HH_DISABLE_EVT: enabling HID Device service"); + LOG_VERBOSE("BTA_HH_DISABLE_EVT: enabling HID Device service"); btif_hd_service_registration(); btif_hh_cb.service_dereg_active = FALSE; } @@ -846,9 +845,8 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN; } } else - BTIF_TRACE_WARNING( - "BTA_HH_DISABLE_EVT: Error, HH disabling failed, status = %d", - p_data->status); + LOG_WARN("BTA_HH_DISABLE_EVT: Error, HH disabling failed, status = %d", + p_data->status); break; case BTA_HH_OPEN_EVT: @@ -856,14 +854,14 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_HH_CLOSE_EVT: - BTIF_TRACE_DEBUG("BTA_HH_CLOSE_EVT: status = %d, handle = %d", - p_data->dev_status.status, p_data->dev_status.handle); + LOG_VERBOSE("BTA_HH_CLOSE_EVT: status = %d, handle = %d", + p_data->dev_status.status, p_data->dev_status.handle); p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle); if (p_dev != NULL) { HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr), BTHH_CONN_STATE_DISCONNECTING); - BTIF_TRACE_DEBUG("%s: uhid fd=%d local_vup=%d", __func__, p_dev->fd, - p_dev->local_vup); + LOG_VERBOSE("%s: uhid fd=%d local_vup=%d", __func__, p_dev->fd, + p_dev->local_vup); btif_hh_stop_vup_timer(&(p_dev->bd_addr)); /* If this is a locally initiated VUP, remove the bond as ACL got * disconnected while VUP being processed. @@ -887,14 +885,14 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr), p_dev->dev_status); } else { - BTIF_TRACE_WARNING("Error: cannot find device with handle %d", - p_data->dev_status.handle); + LOG_WARN("Error: cannot find device with handle %d", + p_data->dev_status.handle); } break; case BTA_HH_GET_RPT_EVT: { - BTIF_TRACE_DEBUG("BTA_HH_GET_RPT_EVT: status = %d, handle = %d", - p_data->hs_data.status, p_data->hs_data.handle); + LOG_VERBOSE("BTA_HH_GET_RPT_EVT: status = %d, handle = %d", + p_data->hs_data.status, p_data->hs_data.handle); p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle); if (p_dev) { BT_HDR* hdr = p_data->hs_data.rsp_data.p_rpt_data; @@ -915,15 +913,15 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { (bthh_status_t)p_data->hs_data.status); } } else { - BTIF_TRACE_WARNING("Error: cannot find device with handle %d", - p_data->hs_data.handle); + LOG_WARN("Error: cannot find device with handle %d", + p_data->hs_data.handle); } break; } case BTA_HH_SET_RPT_EVT: - BTIF_TRACE_DEBUG("BTA_HH_SET_RPT_EVT: status = %d, handle = %d", - p_data->dev_status.status, p_data->dev_status.handle); + LOG_VERBOSE("BTA_HH_SET_RPT_EVT: status = %d, handle = %d", + p_data->dev_status.status, p_data->dev_status.handle); p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle); if (p_dev != NULL) { HAL_CBACK(bt_hh_callbacks, handshake_cb, (RawAddress*)&(p_dev->bd_addr), @@ -936,12 +934,12 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { case BTA_HH_GET_PROTO_EVT: p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle); if (p_dev == NULL) { - BTIF_TRACE_WARNING( + LOG_WARN( "BTA_HH_GET_PROTO_EVT: Error, cannot find device with handle %d", p_data->hs_data.handle); return; } - BTIF_TRACE_WARNING( + LOG_WARN( "BTA_HH_GET_PROTO_EVT: status = %d, handle = %d, proto = [%d], %s", p_data->hs_data.status, p_data->hs_data.handle, p_data->hs_data.rsp_data.proto_mode, @@ -962,8 +960,8 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_HH_SET_PROTO_EVT: - BTIF_TRACE_DEBUG("BTA_HH_SET_PROTO_EVT: status = %d, handle = %d", - p_data->dev_status.status, p_data->dev_status.handle); + LOG_VERBOSE("BTA_HH_SET_PROTO_EVT: status = %d, handle = %d", + p_data->dev_status.status, p_data->dev_status.handle); p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle); if (p_dev) { HAL_CBACK(bt_hh_callbacks, handshake_cb, (RawAddress*)&(p_dev->bd_addr), @@ -972,10 +970,9 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_HH_GET_IDLE_EVT: - BTIF_TRACE_DEBUG( - "BTA_HH_GET_IDLE_EVT: handle = %d, status = %d, rate = %d", - p_data->hs_data.handle, p_data->hs_data.status, - p_data->hs_data.rsp_data.idle_rate); + LOG_VERBOSE("BTA_HH_GET_IDLE_EVT: handle = %d, status = %d, rate = %d", + p_data->hs_data.handle, p_data->hs_data.status, + p_data->hs_data.rsp_data.idle_rate); p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle); if (p_dev) { HAL_CBACK(bt_hh_callbacks, idle_time_cb, (RawAddress*)&(p_dev->bd_addr), @@ -985,18 +982,17 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_HH_SET_IDLE_EVT: - BTIF_TRACE_DEBUG("BTA_HH_SET_IDLE_EVT: status = %d, handle = %d", - p_data->dev_status.status, p_data->dev_status.handle); + LOG_VERBOSE("BTA_HH_SET_IDLE_EVT: status = %d, handle = %d", + p_data->dev_status.status, p_data->dev_status.handle); break; case BTA_HH_GET_DSCP_EVT: len = p_data->dscp_info.descriptor.dl_len; - BTIF_TRACE_DEBUG("BTA_HH_GET_DSCP_EVT: len = %d", len); + LOG_VERBOSE("BTA_HH_GET_DSCP_EVT: len = %d", len); p_dev = btif_hh_find_connected_dev_by_handle(p_data->dscp_info.hid_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR( - "BTA_HH_GET_DSCP_EVT: No HID device is currently connected"); + LOG_ERROR("BTA_HH_GET_DSCP_EVT: No HID device is currently connected"); p_data->dscp_info.hid_handle = BTA_HH_INVALID_HANDLE; return; } @@ -1019,7 +1015,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { cached_name = "Bluetooth HID"; } - BTIF_TRACE_WARNING("%s: name = %s", __func__, cached_name); + LOG_WARN("%s: name = %s", __func__, cached_name); bta_hh_co_send_hid_info(p_dev, cached_name, p_data->dscp_info.vendor_id, p_data->dscp_info.product_id, p_data->dscp_info.version, @@ -1043,7 +1039,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { p_data->dscp_info.descriptor.dsc_list); ASSERTC(ret == BT_STATUS_SUCCESS, "storing hid info failed", ret); - BTIF_TRACE_WARNING("BTA_HH_GET_DSCP_EVT: Called add device"); + LOG_WARN("BTA_HH_GET_DSCP_EVT: Called add device"); // Free buffer created for dscp_info; if (dscp_info.descriptor.dl_len > 0 && @@ -1053,7 +1049,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { } } else { // Device already added. - BTIF_TRACE_WARNING("%s: Device already added ", __func__); + LOG_WARN("%s: Device already added ", __func__); } /*Sync HID Keyboard lockstates */ tmplen = sizeof(hid_kb_numlock_on_list) / sizeof(tHID_KB_LIST); @@ -1062,7 +1058,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { hid_kb_numlock_on_list[i].version_id && p_data->dscp_info.product_id == hid_kb_numlock_on_list[i].product_id) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s() idx[%d] Enabling " "NUMLOCK for device :: %s", __func__, i, hid_kb_numlock_on_list[i].kb_name); @@ -1078,8 +1074,8 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { break; case BTA_HH_ADD_DEV_EVT: - BTIF_TRACE_WARNING("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d", - p_data->dev_info.status, p_data->dev_info.handle); + LOG_WARN("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d", + p_data->dev_info.status, p_data->dev_info.handle); int i; for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) { if (btif_hh_cb.added_devices[i].bd_addr == p_data->dev_info.bda) { @@ -1094,14 +1090,14 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { } break; case BTA_HH_RMV_DEV_EVT: - BTIF_TRACE_DEBUG("BTA_HH_RMV_DEV_EVT: status = %d, handle = %d", - p_data->dev_info.status, p_data->dev_info.handle); + LOG_VERBOSE("BTA_HH_RMV_DEV_EVT: status = %d, handle = %d", + p_data->dev_info.status, p_data->dev_info.handle); VLOG(1) << "BTA_HH_RMV_DEV_EVT:bda = " << p_data->dev_info.bda; break; case BTA_HH_VC_UNPLUG_EVT: - BTIF_TRACE_DEBUG("BTA_HH_VC_UNPLUG_EVT: status = %d, handle = %d", - p_data->dev_status.status, p_data->dev_status.handle); + LOG_VERBOSE("BTA_HH_VC_UNPLUG_EVT: status = %d, handle = %d", + p_data->dev_status.status, p_data->dev_status.handle); p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle); btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED; if (p_dev != NULL) { @@ -1110,10 +1106,10 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { /* Stop the VUP timer */ btif_hh_stop_vup_timer(&(p_dev->bd_addr)); p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED; - BTIF_TRACE_DEBUG("%s---Sending connection state change", __func__); + LOG_VERBOSE("%s---Sending connection state change", __func__); HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr), p_dev->dev_status); - BTIF_TRACE_DEBUG("%s---Removing HID bond", __func__); + LOG_VERBOSE("%s---Removing HID bond", __func__); /* If it is locally initiated VUP or remote device has its major COD as Peripheral removed the bond.*/ if (p_dev->local_vup || check_cod_hid(&(p_dev->bd_addr))) { @@ -1131,7 +1127,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { break; default: - BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event); + LOG_WARN("%s: Unhandled event: %d", __func__, event); break; } } @@ -1153,7 +1149,7 @@ static void btif_hh_hsdata_rpt_copy_cb(uint16_t event, char* p_dest, BT_HDR* hdr; if (!p_src) { - BTIF_TRACE_ERROR("%s: Nothing to copy", __func__); + LOG_ERROR("%s: Nothing to copy", __func__); return; } @@ -1178,7 +1174,7 @@ static void btif_hh_hsdata_rpt_copy_cb(uint16_t event, char* p_dest, * ******************************************************************************/ -void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) { +static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) { bt_status_t status; int param_len = 0; tBTIF_COPY_CBACK* p_copy_cback = NULL; @@ -1282,7 +1278,7 @@ void btif_hh_timer_timeout(void* data) { tBTA_HH p_data; int param_len = sizeof(tBTA_HH_CBDATA); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (p_dev->dev_status != BTHH_CONN_STATE_CONNECTED) return; memset(&p_data, 0, sizeof(tBTA_HH)); @@ -1305,7 +1301,7 @@ void btif_hh_timer_timeout(void* data) { ******************************************************************************/ static bt_status_t init(bthh_callbacks_t* callbacks) { uint32_t i; - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); bt_hh_callbacks = callbacks; memset(&btif_hh_cb, 0, sizeof(btif_hh_cb)); @@ -1331,13 +1327,11 @@ static bt_status_t connect(RawAddress* bd_addr) { btif_hh_device_t* p_dev; if (btif_hh_cb.status == BTIF_HH_DEV_CONNECTING) { - BTIF_TRACE_WARNING("%s: Error, HH status = %d", __func__, - btif_hh_cb.status); + LOG_WARN("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_BUSY; } else if (btif_hh_cb.status == BTIF_HH_DISABLED || btif_hh_cb.status == BTIF_HH_DISABLING) { - BTIF_TRACE_WARNING("%s: Error, HH status = %d", __func__, - btif_hh_cb.status); + LOG_WARN("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_NOT_READY; } @@ -1345,12 +1339,12 @@ static bt_status_t connect(RawAddress* bd_addr) { if (p_dev) { if (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED || p_dev->dev_status == BTHH_CONN_STATE_CONNECTING) { - BTIF_TRACE_ERROR("%s: Error, device %s already connected.", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: Error, device %s already connected.", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_DONE; } else if (p_dev->dev_status == BTHH_CONN_STATE_DISCONNECTING) { - BTIF_TRACE_ERROR("%s: Error, device %s is busy with (dis)connecting.", - __func__, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: Error, device %s is busy with (dis)connecting.", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_BUSY; } } @@ -1370,31 +1364,30 @@ static bt_status_t connect(RawAddress* bd_addr) { ******************************************************************************/ static bt_status_t disconnect(RawAddress* bd_addr) { CHECK_BTHH_INIT(); - BTIF_TRACE_EVENT("BTHH: %s", __func__); + LOG_VERBOSE("BTHH: %s", __func__); btif_hh_device_t* p_dev; if (btif_hh_cb.status == BTIF_HH_DISABLED || btif_hh_cb.status == BTIF_HH_DISABLING) { - BTIF_TRACE_WARNING("%s: Error, HH status = %d", __func__, - btif_hh_cb.status); + LOG_WARN("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_UNHANDLED; } p_dev = btif_hh_find_connected_dev_by_bda(*bd_addr); if (!p_dev) { - BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: Error, device %s not opened.", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_UNHANDLED; } if (p_dev->dev_status == BTHH_CONN_STATE_DISCONNECTED || p_dev->dev_status == BTHH_CONN_STATE_DISCONNECTING) { - BTIF_TRACE_ERROR("%s: Error, device %s already disconnected.", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: Error, device %s already disconnected.", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_DONE; } else if (p_dev->dev_status == BTHH_CONN_STATE_CONNECTING) { - BTIF_TRACE_ERROR("%s: Error, device %s is busy with (dis)connecting.", - __func__, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: Error, device %s is busy with (dis)connecting.", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_BUSY; } @@ -1413,16 +1406,16 @@ static bt_status_t disconnect(RawAddress* bd_addr) { ******************************************************************************/ static bt_status_t virtual_unplug(RawAddress* bd_addr) { CHECK_BTHH_INIT(); - BTIF_TRACE_EVENT("BTHH: %s", __func__); + LOG_VERBOSE("BTHH: %s", __func__); btif_hh_device_t* p_dev; if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } p_dev = btif_hh_find_dev_by_bda(*bd_addr); if (!p_dev) { - BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_ERROR("%s: Error, device %s not opened.", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } btif_transfer_context(btif_hh_handle_evt, BTIF_HH_VUP_REQ_EVT, (char*)bd_addr, @@ -1442,11 +1435,10 @@ static bt_status_t virtual_unplug(RawAddress* bd_addr) { static bt_status_t get_idle_time(RawAddress* bd_addr) { CHECK_BTHH_INIT(); - BTIF_TRACE_DEBUG("%s: addr = %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_VERBOSE("%s: addr = %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } @@ -1469,18 +1461,18 @@ static bt_status_t get_idle_time(RawAddress* bd_addr) { static bt_status_t set_idle_time(RawAddress* bd_addr, uint8_t idle_time) { CHECK_BTHH_INIT(); - BTIF_TRACE_DEBUG("%s: addr = %s, idle time = %d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr), idle_time); + LOG_VERBOSE("%s: addr = %s, idle time = %d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr), idle_time); if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(*bd_addr); if (p_dev == NULL) { - BTIF_TRACE_WARNING("%s: addr = %s not opened", __func__, - ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + LOG_WARN("%s: addr = %s not opened", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); return BT_STATUS_FAIL; } @@ -1502,14 +1494,14 @@ static bt_status_t set_info(RawAddress* bd_addr, bthh_hid_info_t hid_info) { tBTA_HH_DEV_DSCP_INFO dscp_info; VLOG(1) << __func__ << " BTHH: addr = " << *bd_addr; - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "BTHH: %s: sub_class = 0x%02x, app_id = %d, vendor_id = 0x%04x, " "product_id = 0x%04x, version= 0x%04x", __func__, hid_info.sub_class, hid_info.app_id, hid_info.vendor_id, hid_info.product_id, hid_info.version); if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } @@ -1550,7 +1542,7 @@ static bt_status_t get_protocol(RawAddress* bd_addr, VLOG(1) << __func__ << " BTHH: addr = " << ADDRESS_TO_LOGGABLE_STR(*bd_addr); if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } @@ -1580,7 +1572,7 @@ static bt_status_t set_protocol(RawAddress* bd_addr, << " addr = " << *bd_addr; if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } @@ -1590,8 +1582,7 @@ static bt_status_t set_protocol(RawAddress* bd_addr, return BT_STATUS_FAIL; } else if (protocolMode != BTA_HH_PROTO_RPT_MODE && protocolMode != BTA_HH_PROTO_BOOT_MODE) { - BTIF_TRACE_WARNING("%s: Error, device proto_mode = %d.", __func__, - proto_mode); + LOG_WARN("%s: Error, device proto_mode = %d.", __func__, proto_mode); return BT_STATUS_FAIL; } else { BTA_HhSetProtoMode(p_dev->dev_handle, protocolMode); @@ -1620,7 +1611,7 @@ static bt_status_t get_report(RawAddress* bd_addr, << " addr = " << ADDRESS_TO_LOGGABLE_STR(*bd_addr); if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } @@ -1656,7 +1647,7 @@ static bt_status_t get_report_reply(RawAddress* bd_addr, bthh_status_t status, VLOG(1) << __func__ << " BTHH: addr=" << ADDRESS_TO_LOGGABLE_STR(*bd_addr); if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } @@ -1689,7 +1680,7 @@ static bt_status_t set_report(RawAddress* bd_addr, << " addr=" << ADDRESS_TO_LOGGABLE_STR(*bd_addr); if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } @@ -1713,8 +1704,8 @@ static bt_status_t set_report(RawAddress* bd_addr, if (hex_bytes_filled) { BT_HDR* p_buf = create_pbuf(hex_bytes_filled, hexbuf); if (p_buf == NULL) { - BTIF_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, len = %d", - __func__, hex_bytes_filled); + LOG_ERROR("%s: Error, failed to allocate RPT buffer, len = %d", + __func__, hex_bytes_filled); osi_free(hexbuf); return BT_STATUS_FAIL; } @@ -1743,7 +1734,7 @@ static bt_status_t send_data(RawAddress* bd_addr, char* data) { VLOG(1) << __func__ << " addr=" << ADDRESS_TO_LOGGABLE_STR(*bd_addr); if (btif_hh_cb.status == BTIF_HH_DISABLED) { - BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); + LOG_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status); return BT_STATUS_FAIL; } @@ -1761,14 +1752,13 @@ static bt_status_t send_data(RawAddress* bd_addr, char* data) { /* Build a SendData data buffer */ hex_bytes_filled = ascii_2_hex(data, len, hexbuf); - BTIF_TRACE_ERROR("Hex bytes filled, hex value: %d, %d", hex_bytes_filled, - len); + LOG_ERROR("Hex bytes filled, hex value: %d, %zu", hex_bytes_filled, len); if (hex_bytes_filled) { BT_HDR* p_buf = create_pbuf(hex_bytes_filled, hexbuf); if (p_buf == NULL) { - BTIF_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, len = %d", - __func__, hex_bytes_filled); + LOG_ERROR("%s: Error, failed to allocate RPT buffer, len = %d", + __func__, hex_bytes_filled); osi_free(hexbuf); return BT_STATUS_FAIL; } @@ -1792,13 +1782,13 @@ static bt_status_t send_data(RawAddress* bd_addr, char* data) { * ******************************************************************************/ static void cleanup(void) { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_hh_device_t* p_dev; int i; if (btif_hh_cb.status == BTIF_HH_DISABLED || btif_hh_cb.status == BTIF_HH_DISABLING) { - BTIF_TRACE_WARNING("%s: HH disabling or disabled already, status = %d", - __func__, btif_hh_cb.status); + LOG_WARN("%s: HH disabling or disabled already, status = %d", __func__, + btif_hh_cb.status); return; } if (bt_hh_callbacks) { @@ -1811,7 +1801,7 @@ static void cleanup(void) { for (i = 0; i < BTIF_HH_MAX_HID; i++) { p_dev = &btif_hh_cb.devices[i]; if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->fd >= 0) { - BTIF_TRACE_DEBUG("%s: Closing uhid fd = %d", __func__, p_dev->fd); + LOG_VERBOSE("%s: Closing uhid fd = %d", __func__, p_dev->fd); bta_hh_co_close(p_dev); } } @@ -1882,7 +1872,7 @@ bt_status_t btif_hh_execute_service(bool b_enable) { * ******************************************************************************/ const bthh_interface_t* btif_hh_get_interface() { - BTIF_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); return &bthhInterface; } @@ -1910,4 +1900,17 @@ void DumpsysHid(int fd) { } } } + +namespace bluetooth { +namespace legacy { +namespace testing { + +void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) { + ::bte_hh_evt(event, p_data); +} + +} // namespace testing +} // namespace legacy +} // namespace bluetooth + #undef DUMPSYS_TAG diff --git a/system/btif/src/btif_iot_config.cc b/system/btif/src/btif_iot_config.cc index a44794040fd3790b0427212ed7b16ed5da99a100..967df79eadd1f977bfcc96cff0defdd4d70d68dd 100644 --- a/system/btif/src/btif_iot_config.cc +++ b/system/btif/src/btif_iot_config.cc @@ -16,10 +16,11 @@ * ******************************************************************************/ -#include "bt_target.h" -#include "bta_api.h" +#include "bta_sec_api.h" #include "btif_storage.h" #include "device/include/device_iot_config.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "stack/include/btm_ble_api.h" /******************************************************************************* @@ -99,9 +100,9 @@ void btif_iot_update_remote_info(tBTA_DM_AUTH_CMPL* p_auth_cmpl, bool is_ble, if (btif_storage_get_remote_device_property(&p_auth_cmpl->bd_addr, &properties[num_properties]) == BT_STATUS_SUCCESS) - BTIF_TRACE_DEBUG("%s cod retrieved from storage is 0x%06x", __func__, cod); + LOG_VERBOSE("%s cod retrieved from storage is 0x%06x", __func__, cod); if (cod == 0) { - BTIF_TRACE_DEBUG("%s cod is 0, set as unclassified", __func__); + LOG_VERBOSE("%s cod is 0, set as unclassified", __func__); cod = COD_UNCLASSIFIED; } DEVICE_IOT_CONFIG_ADDR_SET_INT(p_auth_cmpl->bd_addr, IOT_CONF_KEY_DEVCLASS, @@ -110,14 +111,14 @@ void btif_iot_update_remote_info(tBTA_DM_AUTH_CMPL* p_auth_cmpl, bool is_ble, // save remote dev type to iot conf file bt_device_type_t dev_type; - uint8_t remote_dev_type; + uint32_t remote_dev_type; BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], - BT_PROPERTY_TYPE_OF_DEVICE, sizeof(uint8_t), + BT_PROPERTY_TYPE_OF_DEVICE, sizeof(uint32_t), &remote_dev_type); if (btif_storage_get_remote_device_property(&p_auth_cmpl->bd_addr, &properties[num_properties]) == BT_STATUS_SUCCESS) { - BTIF_TRACE_DEBUG("%s retrieve dev type from storage", __func__); + LOG_VERBOSE("%s retrieve dev type from storage", __func__); dev_type = (bt_device_type_t)(remote_dev_type | p_auth_cmpl->dev_type); } else { dev_type = (bt_device_type_t)(p_auth_cmpl->dev_type); diff --git a/system/btif/src/btif_jni_task.cc b/system/btif/src/btif_jni_task.cc new file mode 100644 index 0000000000000000000000000000000000000000..7d41efa6a5eef1bb46ff4defa3ba7ae838ae38c3 --- /dev/null +++ b/system/btif/src/btif_jni_task.cc @@ -0,0 +1,124 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "btif/include/btif_jni_task.h" + +#include +#include +#include +#include + +#include +#include + +#include "common/message_loop_thread.h" +#include "include/hardware/bluetooth.h" +#include "osi/include/allocator.h" +#include "stack/include/bt_types.h" + +using base::PlatformThread; + +static bluetooth::common::MessageLoopThread jni_thread("bt_jni_thread"); + +void jni_thread_startup() { jni_thread.StartUp(); } + +void jni_thread_shutdown() { jni_thread.ShutDown(); } + +/******************************************************************************* + * + * Function btif_task + * + * Description BTIF task handler managing all messages being passed + * Bluetooth HAL and BTA. + * + * Returns void + * + ******************************************************************************/ +static void bt_jni_msg_ready(void* context) { + tBTIF_CONTEXT_SWITCH_CBACK* p = (tBTIF_CONTEXT_SWITCH_CBACK*)context; + if (p->p_cb) p->p_cb(p->event, p->p_param); + osi_free(p); +} + +/******************************************************************************* + * + * Function btif_transfer_context + * + * Description This function switches context to btif task + * + * p_cback : callback used to process message in btif context + * event : event id of message + * p_params : parameter area passed to callback (copied) + * param_len : length of parameter area + * p_copy_cback : If set this function will be invoked for deep + * copy + * + * Returns void + * + ******************************************************************************/ + +bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event, + char* p_params, int param_len, + tBTIF_COPY_CBACK* p_copy_cback) { + tBTIF_CONTEXT_SWITCH_CBACK* p_msg = (tBTIF_CONTEXT_SWITCH_CBACK*)osi_malloc( + sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len); + + LOG_VERBOSE("btif_transfer_context event %d, len %d", event, param_len); + + /* allocate and send message that will be executed in btif context */ + p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */ + p_msg->p_cb = p_cback; + + p_msg->event = event; /* callback event */ + + /* check if caller has provided a copy callback to do the deep copy */ + if (p_copy_cback) { + p_copy_cback(event, p_msg->p_param, p_params); + } else if (p_params) { + memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */ + } + + return do_in_jni_thread(base::BindOnce(&bt_jni_msg_ready, p_msg)); +} + +/** + * This function posts a task into the btif message loop, that executes it in + * the JNI message loop. + **/ +bt_status_t do_in_jni_thread(const base::Location& from_here, + base::OnceClosure task) { + if (!jni_thread.DoInThread(from_here, std::move(task))) { + LOG(ERROR) << __func__ << ": Post task to task runner failed!"; + return BT_STATUS_FAIL; + } + return BT_STATUS_SUCCESS; +} + +bt_status_t do_in_jni_thread(base::OnceClosure task) { + return do_in_jni_thread(FROM_HERE, std::move(task)); +} + +bool is_on_jni_thread() { + return jni_thread.GetThreadId() == PlatformThread::CurrentId(); +} + +static void do_post_on_bt_jni(BtJniClosure closure) { closure(); } + +void post_on_bt_jni(BtJniClosure closure) { + ASSERT(do_in_jni_thread(FROM_HERE, base::BindOnce(do_post_on_bt_jni, + std::move(closure))) == + BT_STATUS_SUCCESS); +} diff --git a/system/btif/src/btif_keystore.cc b/system/btif/src/btif_keystore.cc index a0796e7f9c01a31eb1af9bb9ca3f92ebc4d1fee9..022c78bdc13dff4fe3a6a0bc91497e24fa21102d 100644 --- a/system/btif/src/btif_keystore.cc +++ b/system/btif/src/btif_keystore.cc @@ -62,7 +62,7 @@ class BluetoothKeystoreInterfaceImpl return; } do_in_jni_thread( - FROM_HERE, base::Bind([]() { + FROM_HERE, base::BindOnce([]() { shim::BtifConfigInterface::ConvertEncryptOrDecryptKeyIfNeeded(); })); } @@ -79,10 +79,10 @@ class BluetoothKeystoreInterfaceImpl // Save the value into a map. key_map[prefix] = decryptedString; - do_in_jni_thread( - base::Bind(&bluetooth::bluetooth_keystore::BluetoothKeystoreCallbacks:: - set_encrypt_key_or_remove_key, - base::Unretained(callbacks), prefix, decryptedString)); + do_in_jni_thread(base::BindOnce( + &bluetooth::bluetooth_keystore::BluetoothKeystoreCallbacks:: + set_encrypt_key_or_remove_key, + base::Unretained(callbacks), prefix, decryptedString)); return true; } diff --git a/system/btif/src/btif_le_audio.cc b/system/btif/src/btif_le_audio.cc index 0a804d2721894e3cd83137a1e8e7e74bfa161b9f..90931d2dfabb719e077335d5dc8fee1d6b8f7d8d 100644 --- a/system/btif/src/btif_le_audio.cc +++ b/system/btif/src/btif_le_audio.cc @@ -24,7 +24,7 @@ #include "bta_le_audio_api.h" #include "btif_common.h" #include "btif_profile_storage.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" using base::Bind; using base::Unretained; @@ -34,6 +34,7 @@ using bluetooth::le_audio::GroupNodeStatus; using bluetooth::le_audio::GroupStatus; using bluetooth::le_audio::LeAudioClientCallbacks; using bluetooth::le_audio::LeAudioClientInterface; +using bluetooth::le_audio::UnicastMonitorModeStatus; namespace { class LeAudioClientInterfaceImpl; @@ -93,17 +94,50 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, local_output_capa_codec_conf)); } - void OnAudioGroupCodecConf( + void OnAudioGroupCurrentCodecConf( int group_id, btle_audio_codec_config_t input_codec_conf, - btle_audio_codec_config_t output_codec_conf, + btle_audio_codec_config_t output_codec_conf) override { + do_in_jni_thread(FROM_HERE, + Bind(&LeAudioClientCallbacks::OnAudioGroupCurrentCodecConf, + Unretained(callbacks), group_id, input_codec_conf, + output_codec_conf)); + } + + void OnAudioGroupSelectableCodecConf( + int group_id, std::vector input_selectable_codec_conf, std::vector output_selectable_codec_conf) override { + do_in_jni_thread( + FROM_HERE, + Bind(&LeAudioClientCallbacks::OnAudioGroupSelectableCodecConf, + Unretained(callbacks), group_id, input_selectable_codec_conf, + output_selectable_codec_conf)); + } + + void OnHealthBasedRecommendationAction( + const RawAddress& address, + bluetooth::le_audio::LeAudioHealthBasedAction action) override { + do_in_jni_thread( + FROM_HERE, + Bind(&LeAudioClientCallbacks::OnHealthBasedRecommendationAction, + Unretained(callbacks), address, action)); + } + + void OnHealthBasedGroupRecommendationAction( + int group_id, + bluetooth::le_audio::LeAudioHealthBasedAction action) override { + do_in_jni_thread( + FROM_HERE, + Bind(&LeAudioClientCallbacks::OnHealthBasedGroupRecommendationAction, + Unretained(callbacks), group_id, action)); + } + + void OnUnicastMonitorModeStatus(uint8_t direction, + UnicastMonitorModeStatus status) override { do_in_jni_thread(FROM_HERE, - Bind(&LeAudioClientCallbacks::OnAudioGroupCodecConf, - Unretained(callbacks), group_id, input_codec_conf, - output_codec_conf, input_selectable_codec_conf, - output_selectable_codec_conf)); + Bind(&LeAudioClientCallbacks::OnUnicastMonitorModeStatus, + Unretained(callbacks), direction, status)); } void Initialize(LeAudioClientCallbacks* callbacks, @@ -115,7 +149,6 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, LOG_INFO("supported codec: %s", codec.ToString().c_str()); } - LeAudioClient::InitializeAudioSetConfigurationProvider(); do_in_main_thread( FROM_HERE, Bind(&LeAudioClient::Initialize, this, jni_thread_wrapper( @@ -132,31 +165,23 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void Cleanup(void) override { - DVLOG(2) << __func__; if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } initialized = false; - do_in_main_thread( - FROM_HERE, - Bind(&LeAudioClient::Cleanup, - jni_thread_wrapper( - FROM_HERE, - Bind(&LeAudioClient::CleanupAudioSetConfigurationProvider)))); + do_in_main_thread(FROM_HERE, Bind(&LeAudioClient::Cleanup)); } void RemoveDevice(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address); - if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; do_in_jni_thread(FROM_HERE, Bind(&btif_storage_remove_leaudio, address)); return; @@ -170,12 +195,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void Connect(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address); - if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -185,12 +208,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void Disconnect(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << ADDRESS_TO_LOGGABLE_STR(address); - if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -200,12 +221,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void SetEnableState(const RawAddress& address, bool enabled) override { - DVLOG(2) << __func__ << " address: " << address << ", enabled: " << enabled; - if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -215,13 +234,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void GroupAddNode(const int group_id, const RawAddress& address) override { - DVLOG(2) << __func__ << " group_id: " << group_id - << " address: " << ADDRESS_TO_LOGGABLE_STR(address); - if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -231,12 +247,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void GroupRemoveNode(const int group_id, const RawAddress& address) override { - DVLOG(2) << __func__ << " group_id: " << group_id - << " address: " << ADDRESS_TO_LOGGABLE_STR(address); if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -246,11 +260,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void GroupSetActive(const int group_id) override { - DVLOG(2) << __func__ << " group_id: " << group_id; if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -262,11 +275,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, void SetCodecConfigPreference(int group_id, btle_audio_codec_config_t input_codec_config, btle_audio_codec_config_t output_codec_config) { - DVLOG(2) << __func__ << " group_id: " << group_id; if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } do_in_main_thread(FROM_HERE, @@ -276,12 +288,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void SetCcidInformation(int ccid, int context_type) { - DVLOG(2) << __func__ << " ccid: " << ccid << " context_type" - << context_type; if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -291,11 +301,10 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, } void SetInCall(bool in_call) { - DVLOG(2) << __func__ << " in_call: " << in_call; if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -304,18 +313,27 @@ class LeAudioClientInterfaceImpl : public LeAudioClientInterface, Unretained(LeAudioClient::Get()), in_call)); } + void SetUnicastMonitorMode(uint8_t direction, bool enable) { + DVLOG(2) << __func__ << " enable: " << enable; + if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { + DVLOG(2) << __func__ + << " Unicast monitoring mode set ignored, due to already" + " started cleanup procedure or service being not read"; + return; + } + + do_in_main_thread( + FROM_HERE, Bind(&LeAudioClient::SetUnicastMonitorMode, + Unretained(LeAudioClient::Get()), direction, enable)); + } + void SendAudioProfilePreferences(int group_id, bool is_output_preference_le_audio, bool is_duplex_preference_le_audio) { - DVLOG(2) << __func__ << " group_id: " << group_id - << ", is_output_preference_le_audio: " - << is_output_preference_le_audio - << ", is_duplex_preference_le_audio: " - << is_duplex_preference_le_audio; if (!initialized || !LeAudioClient::IsLeAudioClientRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } diff --git a/system/btif/src/btif_le_audio_broadcaster.cc b/system/btif/src/btif_le_audio_broadcaster.cc index 95ce01cd2e77e32e4d202d02b6baf4a817db41aa..f4db4e13be1f66d8f06b6dd35256fed0545aff83 100644 --- a/system/btif/src/btif_le_audio_broadcaster.cc +++ b/system/btif/src/btif_le_audio_broadcaster.cc @@ -20,11 +20,10 @@ #include #include -#include "audio_hal_interface/hal_version_manager.h" #include "bta_le_audio_api.h" #include "bta_le_audio_broadcaster_api.h" #include "btif_common.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" using base::Bind; using base::Unretained; @@ -56,7 +55,6 @@ class LeAudioBroadcasterInterfaceImpl : public LeAudioBroadcasterInterface, std::vector public_metadata, std::vector subgroup_quality, std::vector> subgroup_metadata) override { - DVLOG(2) << __func__; do_in_main_thread(FROM_HERE, Bind(&LeAudioBroadcaster::CreateAudioBroadcast, Unretained(LeAudioBroadcaster::Get()), is_public, broadcast_name, broadcast_code, @@ -69,7 +67,6 @@ class LeAudioBroadcasterInterfaceImpl : public LeAudioBroadcasterInterface, uint32_t broadcast_id, std::string broadcast_name, std::vector public_metadata, std::vector> subgroup_metadata) override { - DVLOG(2) << __func__; do_in_main_thread(FROM_HERE, Bind(&LeAudioBroadcaster::UpdateMetadata, Unretained(LeAudioBroadcaster::Get()), broadcast_id, @@ -78,49 +75,42 @@ class LeAudioBroadcasterInterfaceImpl : public LeAudioBroadcasterInterface, } void StartBroadcast(uint32_t broadcast_id) override { - DVLOG(2) << __func__; do_in_main_thread( FROM_HERE, Bind(&LeAudioBroadcaster::StartAudioBroadcast, Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } void StopBroadcast(uint32_t broadcast_id) override { - DVLOG(2) << __func__; do_in_main_thread( FROM_HERE, Bind(&LeAudioBroadcaster::StopAudioBroadcast, Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } void PauseBroadcast(uint32_t broadcast_id) override { - DVLOG(2) << __func__; do_in_main_thread( FROM_HERE, Bind(&LeAudioBroadcaster::SuspendAudioBroadcast, Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } void DestroyBroadcast(uint32_t broadcast_id) override { - DVLOG(2) << __func__; do_in_main_thread( FROM_HERE, Bind(&LeAudioBroadcaster::DestroyAudioBroadcast, Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } void GetBroadcastMetadata(uint32_t broadcast_id) override { - DVLOG(2) << __func__; do_in_main_thread( FROM_HERE, Bind(&LeAudioBroadcaster::GetBroadcastMetadata, Unretained(LeAudioBroadcaster::Get()), broadcast_id)); } void OnBroadcastCreated(uint32_t broadcast_id, bool success) override { - DVLOG(2) << __func__; do_in_jni_thread(FROM_HERE, Bind(&LeAudioBroadcasterCallbacks::OnBroadcastCreated, Unretained(callbacks_), broadcast_id, success)); } void OnBroadcastDestroyed(uint32_t broadcast_id) override { - DVLOG(2) << __func__; do_in_jni_thread(FROM_HERE, Bind(&LeAudioBroadcasterCallbacks::OnBroadcastDestroyed, Unretained(callbacks_), broadcast_id)); @@ -128,7 +118,6 @@ class LeAudioBroadcasterInterfaceImpl : public LeAudioBroadcasterInterface, void OnBroadcastStateChanged(uint32_t broadcast_id, BroadcastState state) override { - DVLOG(2) << __func__; do_in_jni_thread(FROM_HERE, Bind(&LeAudioBroadcasterCallbacks::OnBroadcastStateChanged, Unretained(callbacks_), broadcast_id, state)); @@ -137,7 +126,6 @@ class LeAudioBroadcasterInterfaceImpl : public LeAudioBroadcasterInterface, void OnBroadcastMetadataChanged(uint32_t broadcast_id, const bluetooth::le_audio::BroadcastMetadata& broadcast_metadata) override { - DVLOG(2) << __func__; do_in_jni_thread( FROM_HERE, Bind(&LeAudioBroadcasterCallbacks::OnBroadcastMetadataChanged, diff --git a/system/btif/src/btif_pan.cc b/system/btif/src/btif_pan.cc index 47c72c84f61358ad3f6f78b79253023882b35ea7..e2c5b1a21e8f16ce4c83eb79d1d8db97f353884b 100644 --- a/system/btif/src/btif_pan.cc +++ b/system/btif/src/btif_pan.cc @@ -27,6 +27,7 @@ #define LOG_TAG "bt_btif_pan" +#include #include #include #include @@ -34,39 +35,40 @@ #include #include #include -#ifdef __ANDROID__ -#include -#endif #include #include #include -#include "bt_target.h" // Must be first to define build configuration #include "bta/include/bta_pan_api.h" #include "btif/include/btif_common.h" #include "btif/include/btif_pan_internal.h" #include "btif/include/btif_sock_thread.h" #include "device/include/controller.h" #include "include/hardware/bt_pan.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" #include "stack/include/pan_api.h" #include "types/raw_address.h" +#ifdef __ANDROID__ +#include +#endif + #define FORWARD_IGNORE 1 #define FORWARD_SUCCESS 0 #define FORWARD_FAILURE (-1) #define FORWARD_CONGEST (-2) -#define asrt(s) \ - do { \ - if (!(s)) \ - BTIF_TRACE_ERROR("btif_pan: ## %s assert %s failed at line:%d ##", \ - __func__, #s, __LINE__) \ +#define asrt(s) \ + do { \ + if (!(s)) \ + LOG_ERROR("btif_pan: ## %s assert %s failed at line:%d ##", __func__, \ + #s, __LINE__); \ } while (0) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) @@ -96,16 +98,6 @@ static btpan_interface_t pan_if = { const btpan_interface_t* btif_pan_get_interface() { return &pan_if; } -static bool pan_nap_is_enabled() { -#ifdef __ANDROID__ - // replace build time config PAN_NAP_DISABLED with runtime - static const bool nap_is_enabled = - android::sysprop::bluetooth::Pan::nap().value_or(true); - return nap_is_enabled; -#else - return true; -#endif -} /******************************************************************************* ** ** Function btif_pan_init @@ -116,12 +108,12 @@ static bool pan_nap_is_enabled() { ** ******************************************************************************/ void btif_pan_init() { - BTIF_TRACE_DEBUG("jni_initialized = %d, btpan_cb.enabled:%d", jni_initialized, - btpan_cb.enabled); + LOG_VERBOSE("jni_initialized = %d, btpan_cb.enabled:%d", jni_initialized, + btpan_cb.enabled); stack_initialized = true; if (jni_initialized && !btpan_cb.enabled) { - BTIF_TRACE_DEBUG("Enabling PAN...."); + LOG_VERBOSE("Enabling PAN...."); memset(&btpan_cb, 0, sizeof(btpan_cb)); btpan_cb.tap_fd = INVALID_FD; btpan_cb.flow = 1; @@ -131,12 +123,13 @@ void btif_pan_init() { btpan_cb.enabled = 1; int role = BTPAN_ROLE_NONE; - if (pan_nap_is_enabled()) { +#ifdef __ANDROID__ + if (android::sysprop::BluetoothProperties::isProfilePanNapEnabled() + .value_or(false)) { role |= BTPAN_ROLE_PANNAP; } -#if PANU_DISABLED == FALSE - role |= BTPAN_ROLE_PANU; #endif + role |= BTPAN_ROLE_PANU; btpan_enable(role); } } @@ -165,8 +158,8 @@ void btif_pan_cleanup() { static btpan_callbacks_t callback; static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks) { - BTIF_TRACE_DEBUG("stack_initialized = %d, btpan_cb.enabled:%d", - stack_initialized, btpan_cb.enabled); + LOG_VERBOSE("stack_initialized = %d, btpan_cb.enabled:%d", stack_initialized, + btpan_cb.enabled); callback = *callbacks; jni_initialized = true; if (stack_initialized && !btpan_cb.enabled) btif_pan_init(); @@ -218,7 +211,7 @@ static bt_status_t btpan_connect(const RawAddress* bd_addr, int local_role, } static void btif_in_pan_generic_evt(uint16_t event, char* p_param) { - BTIF_TRACE_EVENT("%s: event=%d", __func__, event); + LOG_VERBOSE("%s: event=%d", __func__, event); switch (event) { case BTIF_PAN_CB_DISCONNECTING: { RawAddress* bd_addr = (RawAddress*)p_param; @@ -235,7 +228,7 @@ static void btif_in_pan_generic_evt(uint16_t event, char* p_param) { } } break; default: { - BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event); + LOG_WARN("%s : Unknown event 0x%x", __func__, event); } break; } } @@ -279,9 +272,8 @@ static int tap_if_up(const char* devname, const RawAddress* addr) { strlcpy(ifr.ifr_name, devname, IFNAMSIZ); err = ioctl(sk, SIOCGIFHWADDR, &ifr); if (err < 0) { - BTIF_TRACE_ERROR( - "Could not get network hardware for interface:%s, errno:%s", devname, - strerror(errno)); + LOG_ERROR("Could not get network hardware for interface:%s, errno:%s", + devname, strerror(errno)); close(sk); return -1; } @@ -298,16 +290,15 @@ static int tap_if_up(const char* devname, const RawAddress* addr) { * Mask this bit to avoid any issue with auto generated address. */ if (ifr.ifr_hwaddr.sa_data[0] & 0x01) { - BTIF_TRACE_WARNING( - "Not a unicast MAC address, force multicast bit flipping"); + LOG_WARN("Not a unicast MAC address, force multicast bit flipping"); ifr.ifr_hwaddr.sa_data[0] &= ~0x01; } err = ioctl(sk, SIOCSIFHWADDR, (caddr_t)&ifr); if (err < 0) { - BTIF_TRACE_ERROR("Could not set bt address for interface:%s, errno:%s", - devname, strerror(errno)); + LOG_ERROR("Could not set bt address for interface:%s, errno:%s", devname, + strerror(errno)); close(sk); return -1; } @@ -322,13 +313,13 @@ static int tap_if_up(const char* devname, const RawAddress* addr) { err = ioctl(sk, SIOCSIFFLAGS, (caddr_t)&ifr); if (err < 0) { - BTIF_TRACE_ERROR("Could not bring up network interface:%s, errno:%d", - devname, errno); + LOG_ERROR("Could not bring up network interface:%s, errno:%d", devname, + errno); close(sk); return -1; } close(sk); - BTIF_TRACE_DEBUG("network interface: %s is up", devname); + LOG_VERBOSE("network interface: %s is up", devname); return 0; } @@ -358,7 +349,7 @@ void btpan_set_flow_control(bool enable) { if (enable) { btsock_thread_add_fd(pan_pth, btpan_cb.tap_fd, 0, SOCK_THREAD_FD_RD, 0); do_in_main_thread(FROM_HERE, - base::Bind(btu_exec_tap_fd_read, btpan_cb.tap_fd)); + base::BindOnce(btu_exec_tap_fd_read, btpan_cb.tap_fd)); } } @@ -371,7 +362,7 @@ int btpan_tap_open() { fd = open(clonedev, O_RDWR); if (fd < 0) { - BTIF_TRACE_DEBUG("could not open %s, err:%d", clonedev, errno); + LOG_VERBOSE("could not open %s, err:%d", clonedev, errno); return fd; } @@ -383,7 +374,7 @@ int btpan_tap_open() { /* try to create the device */ err = ioctl(fd, TUNSETIFF, (void*)&ifr); if (err < 0) { - BTIF_TRACE_DEBUG("ioctl error:%d, errno:%s", err, strerror(errno)); + LOG_VERBOSE("ioctl error:%d, errno:%s", err, strerror(errno)); close(fd); return err; } @@ -392,7 +383,7 @@ int btpan_tap_open() { fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; } - BTIF_TRACE_ERROR("can not bring up tap interface:%s", TAP_IF_NAME); + LOG_ERROR("can not bring up tap interface:%s", TAP_IF_NAME); close(fd); return INVALID_FD; } @@ -416,7 +407,7 @@ int btpan_tap_send(int tap_fd, const RawAddress& src, const RawAddress& dst, /* Send data to network interface */ ssize_t ret; OSI_NO_INTR(ret = write(tap_fd, packet, len + sizeof(tETH_HDR))); - BTIF_TRACE_DEBUG("ret:%d", ret); + LOG_VERBOSE("ret:%zd", ret); return (int)ret; } return -1; @@ -443,7 +434,7 @@ btpan_conn_t* btpan_find_conn_addr(const RawAddress& addr) { } static void btpan_open_conn(btpan_conn_t* conn, tBTA_PAN* p_data) { - BTIF_TRACE_API( + LOG_VERBOSE( "btpan_open_conn: local_role:%d, peer_role: %d, handle:%d, conn: %p", p_data->open.local_role, p_data->open.peer_role, p_data->open.handle, conn); @@ -452,7 +443,7 @@ static void btpan_open_conn(btpan_conn_t* conn, tBTA_PAN* p_data) { conn = btpan_new_conn(p_data->open.handle, p_data->open.bd_addr, p_data->open.local_role, p_data->open.peer_role); if (conn) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "btpan_open_conn:tap_fd:%d, open_count:%d, " "conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d", btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, p_data->open.handle, @@ -473,10 +464,10 @@ static void btpan_open_conn(btpan_conn_t* conn, tBTA_PAN* p_data) { } static void btpan_close_conn(btpan_conn_t* conn) { - BTIF_TRACE_API("btpan_close_conn: %p", conn); + LOG_VERBOSE("btpan_close_conn: %p", conn); if (conn && conn->state == PAN_STATE_OPEN) { - BTIF_TRACE_DEBUG("btpan_close_conn: PAN_STATE_OPEN"); + LOG_VERBOSE("btpan_close_conn: PAN_STATE_OPEN"); conn->state = PAN_STATE_CLOSE; btpan_cb.open_count--; @@ -522,7 +513,7 @@ btpan_conn_t* btpan_new_conn(int handle, const RawAddress& addr, } void btpan_close_handle(btpan_conn_t* p) { - BTIF_TRACE_DEBUG("btpan_close_handle : close handle %d", p->handle); + LOG_VERBOSE("btpan_close_handle : close handle %d", p->handle); p->handle = -1; p->local_role = -1; p->remote_role = -1; @@ -533,7 +524,7 @@ static inline bool should_forward(tETH_HDR* hdr) { uint16_t proto = ntohs(hdr->h_proto); if (proto == ETH_P_IP || proto == ETH_P_ARP || proto == ETH_P_IPV6) return true; - BTIF_TRACE_DEBUG("unknown proto:%x", proto); + LOG_VERBOSE("unknown proto:%x", proto); return false; } @@ -567,7 +558,7 @@ static void bta_pan_callback_transfer(uint16_t event, char* p_param) { switch (event) { case BTA_PAN_ENABLE_EVT: - BTIF_TRACE_DEBUG("BTA_PAN_ENABLE_EVT"); + LOG_VERBOSE("BTA_PAN_ENABLE_EVT"); break; case BTA_PAN_SET_ROLE_EVT: { int btpan_role = bta_role_to_btpan(p_data->set_role.role); @@ -580,9 +571,9 @@ static void bta_pan_callback_transfer(uint16_t event, char* p_param) { } case BTA_PAN_OPENING_EVT: { btpan_conn_t* conn; - BTIF_TRACE_DEBUG("BTA_PAN_OPENING_EVT handle %d, addr: %s", - p_data->opening.handle, - ADDRESS_TO_LOGGABLE_CSTR(p_data->opening.bd_addr)); + LOG_VERBOSE("BTA_PAN_OPENING_EVT handle %d, addr: %s", + p_data->opening.handle, + ADDRESS_TO_LOGGABLE_CSTR(p_data->opening.bd_addr)); conn = btpan_find_conn_addr(p_data->opening.bd_addr); asrt(conn != NULL); @@ -594,7 +585,7 @@ static void bta_pan_callback_transfer(uint16_t event, char* p_param) { &p_data->opening.bd_addr, btpan_conn_local_role, btpan_remote_role); } else - BTIF_TRACE_ERROR("connection not found"); + LOG_ERROR("connection not found"); break; } case BTA_PAN_OPEN_EVT: { @@ -637,11 +628,11 @@ static void bta_pan_callback_transfer(uint16_t event, char* p_param) { btpan_remote_role); btpan_cleanup_conn(conn); } else - BTIF_TRACE_ERROR("pan handle not found (%d)", p_data->close.handle); + LOG_ERROR("pan handle not found (%d)", p_data->close.handle); break; } default: - BTIF_TRACE_WARNING("Unknown pan event %d", event); + LOG_WARN("Unknown pan event %d", event); break; } } @@ -678,14 +669,14 @@ static void btu_exec_tap_fd_read(int fd) { sizeof(btpan_cb.congest_packet))); switch (ret) { case -1: - BTIF_TRACE_ERROR("%s unable to read from driver: %s", __func__, - strerror(errno)); + LOG_ERROR("%s unable to read from driver: %s", __func__, + strerror(errno)); osi_free(buffer); // add fd back to monitor thread to try it again later btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0); return; case 0: - BTIF_TRACE_WARNING("%s end of file reached.", __func__); + LOG_WARN("%s end of file reached.", __func__); osi_free(buffer); // add fd back to monitor thread to process the exception btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0); @@ -714,8 +705,7 @@ static void btu_exec_tap_fd_read(int fd) { if (forward_bnep(&hdr, buffer) != FORWARD_CONGEST) btpan_cb.congest_packet_size = 0; } else { - BTIF_TRACE_WARNING("%s dropping packet of length %d", __func__, - buffer->len); + LOG_WARN("%s dropping packet of length %d", __func__, buffer->len); btpan_cb.congest_packet_size = 0; osi_free(buffer); } @@ -749,8 +739,8 @@ static void btpan_tap_fd_signaled(int fd, int type, int flags, CHECK(btpan_cb.tap_fd == INVALID_FD || btpan_cb.tap_fd == fd); if (btpan_cb.tap_fd != fd) { - BTIF_TRACE_WARNING("%s Signaled on mismatched fds exp:%d act:%d\n", - __func__, btpan_cb.tap_fd, fd); + LOG_WARN("%s Signaled on mismatched fds exp:%d act:%d\n", __func__, + btpan_cb.tap_fd, fd); return; } @@ -759,6 +749,6 @@ static void btpan_tap_fd_signaled(int fd, int type, int flags, btpan_tap_close(fd); btif_pan_close_all_conns(); } else if (flags & SOCK_THREAD_FD_RD) { - do_in_main_thread(FROM_HERE, base::Bind(btu_exec_tap_fd_read, fd)); + do_in_main_thread(FROM_HERE, base::BindOnce(btu_exec_tap_fd_read, fd)); } } diff --git a/system/btif/src/btif_profile_queue.cc b/system/btif/src/btif_profile_queue.cc index 16f74a3d0bdc278df7b3caa59fccfa128817a46a..32417f783dd32e763138ebbb0f7f8d28abeb61ff 100644 --- a/system/btif/src/btif_profile_queue.cc +++ b/system/btif/src/btif_profile_queue.cc @@ -152,8 +152,8 @@ static void queue_int_release() { connect_queue.clear(); } ******************************************************************************/ bt_status_t btif_queue_connect(uint16_t uuid, const RawAddress* bda, btif_connect_cb_t connect_cb) { - return do_in_jni_thread(FROM_HERE, - base::Bind(&queue_int_add, uuid, *bda, connect_cb)); + return do_in_jni_thread( + FROM_HERE, base::BindOnce(&queue_int_add, uuid, *bda, connect_cb)); } /******************************************************************************* @@ -166,7 +166,7 @@ bt_status_t btif_queue_connect(uint16_t uuid, const RawAddress* bda, * ******************************************************************************/ void btif_queue_cleanup(uint16_t uuid) { - do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_cleanup, uuid)); + do_in_jni_thread(FROM_HERE, base::BindOnce(&queue_int_cleanup, uuid)); } /******************************************************************************* @@ -180,7 +180,7 @@ void btif_queue_cleanup(uint16_t uuid) { * ******************************************************************************/ void btif_queue_advance() { - do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_advance)); + do_in_jni_thread(FROM_HERE, base::BindOnce(&queue_int_advance)); } bt_status_t btif_queue_connect_next(void) { @@ -215,7 +215,7 @@ bt_status_t btif_queue_connect_next(void) { ******************************************************************************/ void btif_queue_release() { LOG_INFO("%s", __func__); - if (do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_release)) != + if (do_in_jni_thread(FROM_HERE, base::BindOnce(&queue_int_release)) != BT_STATUS_SUCCESS) { LOG(FATAL) << __func__ << ": Failed to schedule on JNI thread"; } diff --git a/system/btif/src/btif_profile_storage.cc b/system/btif/src/btif_profile_storage.cc index eb423ba06da515a4c72762589795002ec7835553..568b827b7dad7fd85621954ba4933ba07ef9641c 100644 --- a/system/btif/src/btif_profile_storage.cc +++ b/system/btif/src/btif_profile_storage.cc @@ -21,12 +21,10 @@ #include #include -#include #include #include #include -#include #include #include "bta_csis_api.h" @@ -36,23 +34,14 @@ #include "bta_hearing_aid_api.h" #include "bta_hh_api.h" #include "bta_le_audio_api.h" -#include "btif_api.h" +#include "bta_vc_api.h" +#include "btif/include/btif_dm.h" +#include "btif/include/btif_jni_task.h" #include "btif_config.h" -#include "btif_hd.h" #include "btif_hh.h" #include "btif_storage.h" -#include "btif_util.h" -#include "core_callbacks.h" -#include "device/include/controller.h" -#include "gd/common/init_flags.h" -#include "osi/include/allocator.h" -#include "osi/include/compat.h" -#include "osi/include/config.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "stack/include/bt_octets.h" -#include "stack/include/btu.h" -#include "stack_manager.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/main_thread.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -121,7 +110,7 @@ bt_status_t btif_storage_add_hid_device_info( uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version, uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout, uint16_t dl_len, uint8_t* dsc_list) { - BTIF_TRACE_DEBUG("btif_storage_add_hid_device_info:"); + LOG_VERBOSE("btif_storage_add_hid_device_info:"); std::string bdstr = remote_bd_addr->ToString(); btif_config_set_int(bdstr, "HidAttrMask", attr_mask); btif_config_set_int(bdstr, "HidSubClass", sub_class); @@ -150,7 +139,7 @@ bt_status_t btif_storage_load_bonded_hid_info(void) { for (const auto& bd_addr : btif_config_get_paired_devices()) { auto name = bd_addr.ToString(); - BTIF_TRACE_DEBUG("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); int value; if (!btif_config_get_int(name, "HidAttrMask", &value)) continue; @@ -177,7 +166,7 @@ bt_status_t btif_storage_load_bonded_hid_info(void) { dscp_info.product_id = (uint16_t)value; btif_config_get_int(name, "HidVersion", &value); - dscp_info.version = (uint8_t)value; + dscp_info.version = (uint16_t)value; btif_config_get_int(name, "HidCountryCode", &value); dscp_info.ctry_code = (uint8_t)value; @@ -231,6 +220,8 @@ bt_status_t btif_storage_remove_hid_info(const RawAddress& remote_bd_addr) { btif_config_remove(bdstr, "HidSSRMaxLatency"); btif_config_remove(bdstr, "HidSSRMinTimeout"); btif_config_remove(bdstr, "HidDescriptor"); + btif_config_remove(bdstr, "HidReport"); + btif_config_remove(bdstr, "HidReportVersion"); return BT_STATUS_SUCCESS; } @@ -396,7 +387,7 @@ void btif_storage_load_bonded_hearing_aids() { continue; } - BTIF_TRACE_DEBUG("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); if (btif_in_fetch_bonded_device(name) != BT_STATUS_SUCCESS) { btif_storage_remove_hearing_aid(bd_addr); @@ -449,7 +440,7 @@ void btif_storage_load_bonded_hearing_aids() { if (btif_config_get_int(name, HEARING_AID_PREPARATION_DELAY, &value)) preparation_delay = value; - uint16_t is_acceptlisted = 0; + bool is_acceptlisted = false; if (btif_config_get_int(name, HEARING_AID_IS_ACCEPTLISTED, &value)) is_acceptlisted = value; @@ -677,7 +668,7 @@ void btif_storage_load_bonded_leaudio() { continue; } - BTIF_TRACE_DEBUG("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); int value; bool autoconnect = false; @@ -746,6 +737,13 @@ void btif_storage_load_bonded_leaudio() { } } +void btif_storage_leaudio_clear_service_data(const RawAddress& address) { + auto bdstr = address.ToString(); + btif_config_remove(bdstr, BTIF_STORAGE_LEAUDIO_HANDLES_BIN); + btif_config_remove(bdstr, BTIF_STORAGE_LEAUDIO_SINK_PACS_BIN); + btif_config_remove(bdstr, BTIF_STORAGE_LEAUDIO_ASES_BIN); +} + /** Remove the Le Audio device from storage */ void btif_storage_remove_leaudio(const RawAddress& address) { std::string addrstr = address.ToString(); @@ -917,7 +915,7 @@ void btif_storage_load_bonded_groups(void) { btif_config_get_bin_length(name, BTIF_STORAGE_DEVICE_GROUP_BIN); if (buffer_size == 0) continue; - BTIF_TRACE_DEBUG("Grouped device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("Grouped device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); std::vector in(buffer_size); if (btif_config_get_bin(name, BTIF_STORAGE_DEVICE_GROUP_BIN, in.data(), @@ -928,6 +926,18 @@ void btif_storage_load_bonded_groups(void) { } } +/** Loads information about bonded group devices */ +void btif_storage_load_bonded_volume_control_devices(void) { + for (const auto& bd_addr : btif_config_get_paired_devices()) { + auto device = bd_addr.ToString(); + if (btif_device_supports_profile( + device, Uuid::From16Bit(UUID_SERVCLASS_VOLUME_CONTROL_SERVER))) { + do_in_main_thread(FROM_HERE, + Bind(&VolumeControl::AddFromStorage, bd_addr)); + } + } +} + void btif_storage_set_csis_autoconnect(const RawAddress& addr, bool autoconnect) { do_in_jni_thread(FROM_HERE, Bind( @@ -964,8 +974,7 @@ void btif_storage_load_bonded_csis_devices(void) { for (const auto& bd_addr : btif_config_get_paired_devices()) { auto name = bd_addr.ToString(); - BTIF_TRACE_DEBUG("Loading CSIS device:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("Loading CSIS device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); int value; bool autoconnect = false; @@ -1004,7 +1013,7 @@ bt_status_t btif_storage_load_hidd(void) { for (const auto& bd_addr : btif_config_get_paired_devices()) { auto name = bd_addr.ToString(); - BTIF_TRACE_DEBUG("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); int value; if (btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS) { if (btif_config_get_int(name, "HidDeviceCabled", &value)) { @@ -1066,14 +1075,14 @@ bt_status_t btif_storage_remove_hidd(RawAddress* remote_bd_addr) { ******************************************************************************/ void btif_storage_set_pce_profile_version(const RawAddress& remote_bd_addr, uint16_t peer_pce_version) { - BTIF_TRACE_DEBUG("peer_pce_version : 0x%x", peer_pce_version); + LOG_VERBOSE("peer_pce_version : 0x%x", peer_pce_version); if (btif_config_set_bin( remote_bd_addr.ToString(), BT_CONFIG_KEY_PBAP_PCE_VERSION, (const uint8_t*)&peer_pce_version, sizeof(peer_pce_version))) { } else { - BTIF_TRACE_WARNING("Failed to store peer_pce_version for %s", - ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); + LOG_WARN("Failed to store peer_pce_version for %s", + ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); } } @@ -1095,8 +1104,8 @@ bool btif_storage_is_pce_version_102(const RawAddress& remote_bd_addr) { if (!btif_config_get_bin(remote_bd_addr.ToString(), BT_CONFIG_KEY_PBAP_PCE_VERSION, (uint8_t*)&pce_version, &version_value_size)) { - BTIF_TRACE_DEBUG("Failed to read cached peer PCE version for %s", - ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); + LOG_VERBOSE("Failed to read cached peer PCE version for %s", + ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); return entry_found; } @@ -1104,8 +1113,8 @@ bool btif_storage_is_pce_version_102(const RawAddress& remote_bd_addr) { entry_found = true; } - BTIF_TRACE_DEBUG("read cached peer PCE version 0x%04x for %s", pce_version, - ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); + LOG_VERBOSE("read cached peer PCE version 0x%04x for %s", pce_version, + ADDRESS_TO_LOGGABLE_CSTR(remote_bd_addr)); return entry_found; } diff --git a/system/btif/src/btif_rc.cc b/system/btif/src/btif_rc.cc index e3812edc8286fcda42352e4f2442f6f5ab3174ad..82d9c9f2c79ed51762a25b03db4d40cdcad0fe6e 100644 --- a/system/btif/src/btif_rc.cc +++ b/system/btif/src/btif_rc.cc @@ -26,7 +26,7 @@ #include "btif_rc.h" -#include +#include #include #include #include @@ -35,27 +35,28 @@ #include #include +#include #include -#include "avrc_defs.h" -#include "bta_api.h" -#include "bta_av_api.h" +#include "bta/include/bta_api.h" +#include "bta/include/bta_av_api.h" +#include "btif/avrcp/avrcp_service.h" #include "btif_av.h" #include "btif_common.h" #include "btif_util.h" #include "device/include/interop.h" +#include "os/log.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "osi/include/list.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "osi/include/osi.h" // UNUSED_ATTR #include "osi/include/properties.h" #include "stack/include/avrc_api.h" +#include "stack/include/avrc_defs.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" #include "types/raw_address.h" -#include - #define RC_INVALID_TRACK_ID (0xFFFFFFFFFFFFFFFFULL) /***************************************************************************** @@ -94,20 +95,20 @@ #define PLAY_STATUS_PLAYING 1 #define BTIF_RC_NUM_CONN BT_RC_NUM_APP -#define CHECK_RC_CONNECTED(p_dev) \ - do { \ - if ((p_dev) == NULL || !(p_dev)->rc_connected) { \ - BTIF_TRACE_WARNING("%s: called when RC is not connected", __func__); \ - return BT_STATUS_NOT_READY; \ - } \ +#define CHECK_RC_CONNECTED(p_dev) \ + do { \ + if ((p_dev) == NULL || !(p_dev)->rc_connected) { \ + LOG_WARN("%s: called when RC is not connected", __func__); \ + return BT_STATUS_NOT_READY; \ + } \ } while (0) -#define CHECK_BR_CONNECTED(p_dev) \ - do { \ - if ((p_dev) == NULL || !(p_dev)->br_connected) { \ - BTIF_TRACE_WARNING("%s: called when BR is not connected", __func__); \ - return BT_STATUS_NOT_READY; \ - } \ +#define CHECK_BR_CONNECTED(p_dev) \ + do { \ + if ((p_dev) == NULL || !(p_dev)->br_connected) { \ + LOG_WARN("%s: called when BR is not connected", __func__); \ + return BT_STATUS_NOT_READY; \ + } \ } while (0) /***************************************************************************** @@ -220,8 +221,15 @@ typedef struct { uint64_t rc_playing_uid; bool rc_procedure_complete; rc_transaction_set_t transaction_set; + tBTA_AV_FEAT peer_ct_features; + tBTA_AV_FEAT peer_tg_features; + uint8_t launch_cmd_pending; /* true: getcap/regvolume */ } btif_rc_device_cb_t; +#define RC_PENDING_ACT_GET_CAP (1 << 0) +#define RC_PENDING_ACT_REG_VOL (1 << 1) +#define RC_PENDING_ACT_REPORT_CONN (1 << 2) + typedef struct { std::mutex lock; btif_rc_device_cb_t rc_multi_cb[BTIF_RC_NUM_CONN]; @@ -402,6 +410,23 @@ static const uint8_t media_attr_list_no_cover_art_size = *****************************************************************************/ bool check_cod(const RawAddress& remote_bdaddr, uint32_t cod); +void btif_rc_get_addr_by_handle(uint8_t handle, RawAddress& rc_addr) { + LOG_VERBOSE("%s: handle: 0x%x", __func__, handle); + for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) { + if ((btif_rc_cb.rc_multi_cb[idx].rc_state != + BTRC_CONNECTION_STATE_DISCONNECTED) && + (btif_rc_cb.rc_multi_cb[idx].rc_handle == handle)) { + LOG_VERBOSE("%s: btif_rc_cb.rc_multi_cb[idx].rc_handle: 0x%x", __func__, + btif_rc_cb.rc_multi_cb[idx].rc_handle); + rc_addr = btif_rc_cb.rc_multi_cb[idx].rc_addr; + return; + } + } + LOG_ERROR("%s: returning NULL", __func__); + rc_addr = RawAddress::kEmpty; + return; +} + /***************************************************************************** * Functions *****************************************************************************/ @@ -442,6 +467,9 @@ void initialize_device(btif_rc_device_cb_t* p_dev) { p_dev->rc_features_processed = false; p_dev->rc_playing_uid = 0; p_dev->rc_procedure_complete = false; + p_dev->peer_ct_features = 0; + p_dev->peer_tg_features = 0; + p_dev->launch_cmd_pending = 0; // Leaving the value of the default constructor for the lbllock mutex is fine // but we still need to clear out the transaction label set @@ -451,15 +479,15 @@ void initialize_device(btif_rc_device_cb_t* p_dev) { } static btif_rc_device_cb_t* get_connected_device(int index) { - BTIF_TRACE_DEBUG("%s: index: %d", __func__, index); + LOG_VERBOSE("%s: index: %d", __func__, index); if (index >= BTIF_RC_NUM_CONN) { - BTIF_TRACE_ERROR("%s: can't support more than %d connections", __func__, - BTIF_RC_NUM_CONN); + LOG_ERROR("%s: can't support more than %d connections", __func__, + BTIF_RC_NUM_CONN); return NULL; } if (btif_rc_cb.rc_multi_cb[index].rc_state != BTRC_CONNECTION_STATE_CONNECTED) { - BTIF_TRACE_ERROR("%s: returning NULL", __func__); + LOG_ERROR("%s: returning NULL", __func__); return NULL; } return (&btif_rc_cb.rc_multi_cb[index]); @@ -475,22 +503,22 @@ btif_rc_device_cb_t* btif_rc_get_device_by_bda(const RawAddress& bd_addr) { return (&btif_rc_cb.rc_multi_cb[idx]); } } - BTIF_TRACE_ERROR("%s: device not found, returning NULL!", __func__); + LOG_ERROR("%s: device not found, returning NULL!", __func__); return NULL; } btif_rc_device_cb_t* btif_rc_get_device_by_handle(uint8_t handle) { - BTIF_TRACE_DEBUG("%s: handle: 0x%x", __func__, handle); + LOG_VERBOSE("%s: handle: 0x%x", __func__, handle); for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) { if ((btif_rc_cb.rc_multi_cb[idx].rc_state != BTRC_CONNECTION_STATE_DISCONNECTED) && (btif_rc_cb.rc_multi_cb[idx].rc_handle == handle)) { - BTIF_TRACE_DEBUG("%s: btif_rc_cb.rc_multi_cb[idx].rc_handle: 0x%x", - __func__, btif_rc_cb.rc_multi_cb[idx].rc_handle); + LOG_VERBOSE("%s: btif_rc_cb.rc_multi_cb[idx].rc_handle: 0x%x", __func__, + btif_rc_cb.rc_multi_cb[idx].rc_handle); return (&btif_rc_cb.rc_multi_cb[idx]); } } - BTIF_TRACE_ERROR("%s: returning NULL", __func__); + LOG_ERROR("%s: returning NULL", __func__); return NULL; } @@ -521,17 +549,88 @@ void fill_avrc_attr_entry(tAVRC_ATTR_ENTRY* attr_vals, int num_attrs, attr_vals[attr_cnt].name.str_len = (uint16_t)strlen((char*)p_attrs[attr_cnt].text); attr_vals[attr_cnt].name.p_str = p_attrs[attr_cnt].text; - BTIF_TRACE_DEBUG( - "%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", __func__, - (unsigned int)attr_vals[attr_cnt].attr_id, - attr_vals[attr_cnt].name.charset_id, attr_vals[attr_cnt].name.str_len, - attr_vals[attr_cnt].name.p_str); + LOG_VERBOSE("%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", + __func__, (unsigned int)attr_vals[attr_cnt].attr_id, + attr_vals[attr_cnt].name.charset_id, + attr_vals[attr_cnt].name.str_len, + attr_vals[attr_cnt].name.p_str); } } -void rc_cleanup_sent_cmd(void* p_data) { BTIF_TRACE_DEBUG("%s: ", __func__); } +void rc_cleanup_sent_cmd(void* p_data) { LOG_VERBOSE("%s: ", __func__); } + +void handle_rc_ctrl_features_all(btif_rc_device_cb_t* p_dev) { + if (!(p_dev->peer_tg_features & BTA_AV_FEAT_RCTG) && + (!(p_dev->peer_tg_features & BTA_AV_FEAT_RCCT) || + !(p_dev->peer_tg_features & BTA_AV_FEAT_ADV_CTRL))) { + return; + } + + int rc_features = 0; + + LOG_VERBOSE( + "%s: peer_tg_features: 0x%x, rc_features_processed=%d, connected=%d, " + "peer_is_src:%d", + __func__, p_dev->peer_tg_features, p_dev->rc_features_processed, + btif_av_is_connected_addr(p_dev->rc_addr), + btif_av_peer_is_source(p_dev->rc_addr)); + + if ((p_dev->peer_tg_features & BTA_AV_FEAT_ADV_CTRL) && + (p_dev->peer_tg_features & BTA_AV_FEAT_RCCT)) { + rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME; + } + + if ((p_dev->peer_tg_features & BTA_AV_FEAT_METADATA) && + (p_dev->peer_tg_features & BTA_AV_FEAT_VENDOR) && + (p_dev->rc_features_processed != true)) { + rc_features |= BTRC_FEAT_METADATA; + + /* Mark rc features processed to avoid repeating + * the AVRCP procedure every time on receiving this + * update. + */ + p_dev->rc_features_processed = true; + } + + if (btif_av_is_connected_addr(p_dev->rc_addr)) { + if (btif_av_peer_is_source(p_dev->rc_addr)) { + p_dev->rc_features = p_dev->peer_tg_features; + if ((p_dev->peer_tg_features & BTA_AV_FEAT_METADATA) && + (p_dev->peer_tg_features & BTA_AV_FEAT_VENDOR)) { + getcapabilities_cmd(AVRC_CAP_COMPANY_ID, p_dev); + } + } + } else { + LOG_VERBOSE("%s: %s is not connected, pending", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr)); + p_dev->launch_cmd_pending |= + (RC_PENDING_ACT_GET_CAP | RC_PENDING_ACT_REG_VOL); + } + + /* Add browsing feature capability */ + if (p_dev->peer_tg_features & BTA_AV_FEAT_BROWSE) { + rc_features |= BTRC_FEAT_BROWSE; + } + + /* Add cover art feature capability */ + if (p_dev->peer_tg_features & BTA_AV_FEAT_COVER_ARTWORK) { + rc_features |= BTRC_FEAT_COVER_ARTWORK; + } + + if (bt_rc_ctrl_callbacks != NULL) { + LOG_VERBOSE("%s: Update rc features to CTRL: %d", __func__, rc_features); + do_in_jni_thread(FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->getrcfeatures_cb, + p_dev->rc_addr, rc_features)); + } +} void handle_rc_ctrl_features(btif_rc_device_cb_t* p_dev) { + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + handle_rc_ctrl_features_all(p_dev); + return; + } + if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG) && (!(p_dev->rc_features & BTA_AV_FEAT_RCCT) || !(p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL))) { @@ -571,18 +670,57 @@ void handle_rc_ctrl_features(btif_rc_device_cb_t* p_dev) { rc_features |= BTRC_FEAT_COVER_ARTWORK; } - BTIF_TRACE_DEBUG("%s: Update rc features to CTRL: %d", __func__, rc_features); - do_in_jni_thread(FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->getrcfeatures_cb, - p_dev->rc_addr, rc_features)); + LOG_VERBOSE("%s: Update rc features to CTRL: %d", __func__, rc_features); + do_in_jni_thread(FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->getrcfeatures_cb, + p_dev->rc_addr, rc_features)); +} +void btif_rc_check_pending_cmd(const RawAddress& peer_address) { + btif_rc_device_cb_t* p_dev = NULL; + p_dev = btif_rc_get_device_by_bda(peer_address); + if (p_dev == NULL) { + LOG_ERROR("%s: p_dev NULL", __func__); + return; + } + + LOG_VERBOSE( + "%s: launch_cmd_pending=%d, rc_connected=%d, peer_ct_features=0x%x, " + "peer_tg_features=0x%x", + __FUNCTION__, p_dev->launch_cmd_pending, p_dev->rc_connected, + p_dev->peer_ct_features, p_dev->peer_tg_features); + if (p_dev->launch_cmd_pending && p_dev->rc_connected) { + if ((p_dev->launch_cmd_pending & RC_PENDING_ACT_REG_VOL) && + btif_av_peer_is_sink(p_dev->rc_addr)) { + if (bluetooth::avrcp::AvrcpService::Get() != nullptr) { + bluetooth::avrcp::AvrcpService::Get()->RegisterVolChanged(peer_address); + } + } + if ((p_dev->launch_cmd_pending & RC_PENDING_ACT_GET_CAP) && + btif_av_peer_is_source(p_dev->rc_addr)) { + p_dev->rc_features = p_dev->peer_tg_features; + getcapabilities_cmd(AVRC_CAP_COMPANY_ID, p_dev); + } + if ((p_dev->launch_cmd_pending & RC_PENDING_ACT_REPORT_CONN) && + btif_av_peer_is_source(p_dev->rc_addr)) { + if (bt_rc_ctrl_callbacks != NULL) { + do_in_jni_thread( + FROM_HERE, base::BindOnce(bt_rc_ctrl_callbacks->connection_state_cb, + true, false, p_dev->rc_addr)); + } + } + } + p_dev->launch_cmd_pending = 0; } void handle_rc_ctrl_psm(btif_rc_device_cb_t* p_dev) { uint16_t cover_art_psm = p_dev->rc_cover_art_psm; - BTIF_TRACE_DEBUG("%s: Update rc cover art psm to CTRL: %d", __func__, - cover_art_psm); - do_in_jni_thread(FROM_HERE, base::Bind( - bt_rc_ctrl_callbacks->get_cover_art_psm_cb, - p_dev->rc_addr, cover_art_psm)); + LOG_VERBOSE("%s: Update rc cover art psm to CTRL: %d", __func__, + cover_art_psm); + if (bt_rc_ctrl_callbacks != NULL) { + do_in_jni_thread(FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->get_cover_art_psm_cb, + p_dev->rc_addr, cover_art_psm)); + } } void handle_rc_features(btif_rc_device_cb_t* p_dev) { @@ -593,7 +731,7 @@ void handle_rc_features(btif_rc_device_cb_t* p_dev) { RawAddress avdtp_source_active_peer_addr = btif_av_source_active_peer(); RawAddress avdtp_sink_active_peer_addr = btif_av_sink_active_peer(); - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: AVDTP Source Active Peer Address: %s " "AVDTP Sink Active Peer Address: %s " "AVCTP address: %s", @@ -626,10 +764,10 @@ void handle_rc_features(btif_rc_device_cb_t* p_dev) { (btrc_remote_features_t)(rc_features | BTRC_FEAT_ABSOLUTE_VOLUME); } - BTIF_TRACE_DEBUG("%s: rc_features: 0x%x", __func__, rc_features); + LOG_VERBOSE("%s: rc_features: 0x%x", __func__, rc_features); HAL_CBACK(bt_rc_callbacks, remote_features_cb, p_dev->rc_addr, rc_features); - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Checking for feature flags in btif_rc_handler with label: %d", __func__, p_dev->rc_vol_label); // Register for volume change on connect @@ -640,7 +778,7 @@ void handle_rc_features(btif_rc_device_cb_t* p_dev) { } /*************************************************************************** - * Function handle_rc_connect + * Function handle_rc_browse_connect * * - Argument: tBTA_AV_RC_OPEN browse RC open data structure * @@ -648,13 +786,13 @@ void handle_rc_features(btif_rc_device_cb_t* p_dev) { * ***************************************************************************/ void handle_rc_browse_connect(tBTA_AV_RC_BROWSE_OPEN* p_rc_br_open) { - BTIF_TRACE_DEBUG("%s: rc_handle %d status %d", __func__, - p_rc_br_open->rc_handle, p_rc_br_open->status); + LOG_VERBOSE("%s: rc_handle %d status %d", __func__, p_rc_br_open->rc_handle, + p_rc_br_open->status); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_handle(p_rc_br_open->rc_handle); if (!p_dev) { - BTIF_TRACE_ERROR("%s p_dev is null", __func__); + LOG_ERROR("%s p_dev is null", __func__); return; } @@ -663,9 +801,28 @@ void handle_rc_browse_connect(tBTA_AV_RC_BROWSE_OPEN* p_rc_br_open) { * probably not preferred anyways. */ if (p_rc_br_open->status == BTA_AV_SUCCESS) { p_dev->br_connected = true; - do_in_jni_thread(FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, true, - true, p_dev->rc_addr)); + if (btif_av_src_sink_coexist_enabled()) { + if (btif_av_peer_is_connected_source(p_dev->rc_addr)) { + if (bt_rc_ctrl_callbacks != NULL) { + do_in_jni_thread( + FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->connection_state_cb, true, + true, p_dev->rc_addr)); + } + } else { + p_dev->launch_cmd_pending |= RC_PENDING_ACT_REPORT_CONN; + LOG_VERBOSE("%s: pending rc browse connection event", __func__); + } + } else { + if (bt_rc_ctrl_callbacks != NULL) { + do_in_jni_thread( + FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->connection_state_cb, true, + true, p_dev->rc_addr)); + } else { + LOG_WARN("%s: bt_rc_ctrl_callbacks is null.", __func__); + } + } } } @@ -678,58 +835,75 @@ void handle_rc_browse_connect(tBTA_AV_RC_BROWSE_OPEN* p_rc_br_open) { * ***************************************************************************/ void handle_rc_connect(tBTA_AV_RC_OPEN* p_rc_open) { - BTIF_TRACE_DEBUG("%s: rc_handle: %d", __func__, p_rc_open->rc_handle); + LOG_VERBOSE("%s: rc_handle: %d", __func__, p_rc_open->rc_handle); btif_rc_device_cb_t* p_dev = alloc_device(); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev is NULL", __func__); + LOG_ERROR("%s: p_dev is NULL", __func__); return; } if (!(p_rc_open->status == BTA_AV_SUCCESS)) { - BTIF_TRACE_ERROR("%s: Connect failed with error code: %d", __func__, - p_rc_open->status); + LOG_ERROR("%s: Connect failed with error code: %d", __func__, + p_rc_open->status); p_dev->rc_connected = false; + BTA_AvCloseRc(p_rc_open->rc_handle); + p_dev->rc_handle = 0; + p_dev->rc_state = BTRC_CONNECTION_STATE_DISCONNECTED; + p_dev->rc_features = 0; + p_dev->peer_ct_features = 0; + p_dev->peer_tg_features = 0; + p_dev->launch_cmd_pending = 0; + p_dev->rc_vol_label = MAX_LABEL; + p_dev->rc_volume = MAX_VOLUME; + p_dev->rc_addr = RawAddress::kEmpty; return; } // check if already some RC is connected if (p_dev->rc_connected) { - BTIF_TRACE_ERROR( + LOG_ERROR( "%s: Got RC OPEN in connected state, Connected RC: %d \ and Current RC: %d", __func__, p_dev->rc_handle, p_rc_open->rc_handle); if (p_dev->rc_handle != p_rc_open->rc_handle && p_dev->rc_addr != p_rc_open->peer_addr) { - BTIF_TRACE_DEBUG("%s: Got RC connected for some other handle", __func__); + LOG_VERBOSE("%s: Got RC connected for some other handle", __func__); BTA_AvCloseRc(p_rc_open->rc_handle); return; } } p_dev->rc_addr = p_rc_open->peer_addr; p_dev->rc_features = p_rc_open->peer_features; - BTIF_TRACE_DEBUG("%s: handle_rc_connect in features: 0x%x out features 0x%x", - __func__, p_rc_open->peer_features, p_dev->rc_features); + p_dev->peer_ct_features = p_rc_open->peer_ct_features; + p_dev->peer_tg_features = p_rc_open->peer_tg_features; p_dev->rc_cover_art_psm = p_rc_open->cover_art_psm; - BTIF_TRACE_DEBUG("%s: cover art psm: 0x%x", - __func__, p_dev->rc_cover_art_psm); p_dev->rc_vol_label = MAX_LABEL; p_dev->rc_volume = MAX_VOLUME; + LOG_VERBOSE( + "%s: handle_rc_connect in features=%#x, out features=%#x, " + "ct_feature=%#x, tg_feature=%#x, cover art psm=%#x", + __func__, p_rc_open->peer_features, p_dev->rc_features, + p_dev->peer_ct_features, p_dev->peer_tg_features, + p_dev->rc_cover_art_psm); + p_dev->rc_connected = true; p_dev->rc_handle = p_rc_open->rc_handle; p_dev->rc_state = BTRC_CONNECTION_STATE_CONNECTED; - /* on locally initiated connection we will get remote features as part of - * connect */ - if (p_dev->rc_features != 0 && bt_rc_callbacks != NULL) { - handle_rc_features(p_dev); - } p_dev->rc_playing_uid = RC_INVALID_TRACK_ID; + + if (btif_av_src_sink_coexist_enabled() && + !btif_av_peer_is_connected_source(p_dev->rc_addr)) { + p_dev->launch_cmd_pending |= RC_PENDING_ACT_REPORT_CONN; + LOG_VERBOSE("%s: pending rc connection event", __func__); + return; + } if (bt_rc_ctrl_callbacks != NULL) { do_in_jni_thread(FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, true, - false, p_dev->rc_addr)); + base::BindOnce(bt_rc_ctrl_callbacks->connection_state_cb, + true, false, p_dev->rc_addr)); /* report connection state if remote device is AVRCP target */ handle_rc_ctrl_features(p_dev); @@ -748,25 +922,25 @@ void handle_rc_connect(tBTA_AV_RC_OPEN* p_rc_open) { ***************************************************************************/ void handle_rc_disconnect(tBTA_AV_RC_CLOSE* p_rc_close) { btif_rc_device_cb_t* p_dev = NULL; - BTIF_TRACE_DEBUG("%s: rc_handle: %d", __func__, p_rc_close->rc_handle); + LOG_VERBOSE("%s: rc_handle: %d", __func__, p_rc_close->rc_handle); p_dev = btif_rc_get_device_by_handle(p_rc_close->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: Got disconnect from invalid rc handle", __func__); + LOG_ERROR("%s: Got disconnect from invalid rc handle", __func__); return; } if (p_rc_close->rc_handle != p_dev->rc_handle && p_dev->rc_addr != p_rc_close->peer_addr) { - BTIF_TRACE_ERROR("Got disconnect of unknown device"); + LOG_ERROR("Got disconnect of unknown device"); return; } /* Report connection state if device is AVRCP target */ if (bt_rc_ctrl_callbacks != NULL) { - do_in_jni_thread( - FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, false, - false, p_dev->rc_addr)); + do_in_jni_thread(FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->connection_state_cb, + false, false, p_dev->rc_addr)); } // We'll re-initialize the device state back to what it looked like before @@ -785,28 +959,24 @@ void handle_rc_disconnect(tBTA_AV_RC_CLOSE* p_rc_close) { ***************************************************************************/ void handle_rc_passthrough_cmd(tBTA_AV_REMOTE_CMD* p_remote_cmd) { if (p_remote_cmd == NULL) { - BTIF_TRACE_ERROR("%s: No remote command!", __func__); + LOG_ERROR("%s: No remote command!", __func__); return; } btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_handle(p_remote_cmd->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: Got passthrough command from invalid rc handle", - __func__); + LOG_ERROR("%s: Got passthrough command from invalid rc handle", __func__); return; } - - BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id: %d", __func__, - p_remote_cmd->rc_id); + LOG_VERBOSE("%s: p_remote_cmd->rc_id: %d", __func__, p_remote_cmd->rc_id); /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up * this PLAY */ if ((p_remote_cmd->rc_id == AVRC_ID_PLAY) && (!btif_av_is_connected())) { if (p_remote_cmd->key_state == AVRC_STATE_PRESS) { - APPL_TRACE_WARNING("%s: AVDT not open, queuing the PLAY command", - __func__); + LOG_WARN("%s: AVDT not open, queuing the PLAY command", __func__); p_dev->rc_pending_play = true; } return; @@ -814,23 +984,22 @@ void handle_rc_passthrough_cmd(tBTA_AV_REMOTE_CMD* p_remote_cmd) { /* If we previously queued a play and we get a PAUSE, clear it. */ if ((p_remote_cmd->rc_id == AVRC_ID_PAUSE) && (p_dev->rc_pending_play)) { - APPL_TRACE_WARNING("%s: Clear the pending PLAY on PAUSE received", - __func__); + LOG_WARN("%s: Clear the pending PLAY on PAUSE received", __func__); p_dev->rc_pending_play = false; return; } if ((p_remote_cmd->rc_id == AVRC_ID_STOP) && (!btif_av_stream_started_ready())) { - APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd", __func__); + LOG_WARN("%s: Stream suspended, ignore STOP cmd", __func__); return; } int pressed = (p_remote_cmd->key_state == AVRC_STATE_PRESS) ? 1 : 0; /* pass all commands up */ - BTIF_TRACE_DEBUG("%s: rc_features: %d, cmd->rc_id: %d, pressed: %d", __func__, - p_dev->rc_features, p_remote_cmd->rc_id, pressed); + LOG_VERBOSE("%s: rc_features: %d, cmd->rc_id: %d, pressed: %d", __func__, + p_dev->rc_features, p_remote_cmd->rc_id, pressed); HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed, p_dev->rc_addr); } @@ -848,28 +1017,25 @@ void handle_rc_passthrough_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) { p_dev = btif_rc_get_device_by_handle(p_remote_rsp->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: passthrough response for Invalid rc handle", - __func__); + LOG_ERROR("%s: passthrough response for Invalid rc handle", __func__); return; } if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG)) { - BTIF_TRACE_ERROR("%s: DUT does not support AVRCP controller role", - __func__); + LOG_ERROR("%s: DUT does not support AVRCP controller role", __func__); return; } const char* status = (p_remote_rsp->key_state == 1) ? "released" : "pressed"; - BTIF_TRACE_DEBUG("%s: rc_id: %d state: %s", __func__, p_remote_rsp->rc_id, - status); + LOG_VERBOSE("%s: rc_id: %d state: %s", __func__, p_remote_rsp->rc_id, status); release_transaction(p_dev, p_remote_rsp->label); if (bt_rc_ctrl_callbacks != NULL) { do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->passthrough_rsp_cb, p_dev->rc_addr, - p_remote_rsp->rc_id, p_remote_rsp->key_state)); + base::BindOnce(bt_rc_ctrl_callbacks->passthrough_rsp_cb, p_dev->rc_addr, + p_remote_rsp->rc_id, p_remote_rsp->key_state)); } } @@ -888,8 +1054,7 @@ void handle_rc_vendorunique_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) { p_dev = btif_rc_get_device_by_handle(p_remote_rsp->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: Got vendorunique rsp from invalid rc handle", - __func__); + LOG_ERROR("%s: Got vendorunique rsp from invalid rc handle", __func__); return; } @@ -903,20 +1068,19 @@ void handle_rc_vendorunique_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) { key_state = 0; } - if (p_remote_rsp->len > 0) { + if (p_remote_rsp->len > 0 && p_remote_rsp->p_data != NULL) { if (p_remote_rsp->len >= AVRC_PASS_THRU_GROUP_LEN) vendor_id = p_remote_rsp->p_data[AVRC_PASS_THRU_GROUP_LEN - 1]; osi_free_and_reset((void**)&p_remote_rsp->p_data); } - BTIF_TRACE_DEBUG("%s: vendor_id: %d status: %s", __func__, vendor_id, - status); + LOG_VERBOSE("%s: vendor_id: %d status: %s", __func__, vendor_id, status); release_transaction(p_dev, p_remote_rsp->label); - do_in_jni_thread(FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->groupnavigation_rsp_cb, - vendor_id, key_state)); + do_in_jni_thread( + FROM_HERE, base::BindOnce(bt_rc_ctrl_callbacks->groupnavigation_rsp_cb, + vendor_id, key_state)); } else { - BTIF_TRACE_ERROR("%s: Remote does not support AVRCP TG role", __func__); + LOG_ERROR("%s: Remote does not support AVRCP TG role", __func__); } } @@ -937,33 +1101,33 @@ void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { btif_rc_device_cb_t* p_dev = NULL; if (NULL == pmeta_msg) { - BTIF_TRACE_EVENT("%s: Exiting as pmeta_msg is NULL", __func__); + LOG_VERBOSE("%s: Exiting as pmeta_msg is NULL", __func__); return; } if (NULL == pmeta_msg->p_msg) { - BTIF_TRACE_EVENT("%s: Exiting as pmeta_msg->p_msg is NULL", __func__); + LOG_VERBOSE("%s: Exiting as pmeta_msg->p_msg is NULL", __func__); return; } - BTIF_TRACE_EVENT("%s: pmeta_msg: opcode: %x, code: %x", __func__, - pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code); + LOG_VERBOSE("%s: pmeta_msg: opcode: %x, code: %x", __func__, + pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code); p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: Meta msg event for Invalid rc handle", __func__); + LOG_ERROR("%s: Meta msg event for Invalid rc handle", __func__); return; } if (pmeta_msg->p_msg->hdr.opcode != AVRC_OP_VENDOR && pmeta_msg->p_msg->hdr.opcode != AVRC_OP_BROWSE) { - BTIF_TRACE_WARNING("Invalid opcode: %x", pmeta_msg->p_msg->hdr.opcode); + LOG_WARN("Invalid opcode: %x", pmeta_msg->p_msg->hdr.opcode); return; } if (pmeta_msg->len < 3) { - BTIF_TRACE_WARNING("%s: Invalid length. opcode: 0x%x, len: 0x%x", __func__, - pmeta_msg->p_msg->hdr.opcode, pmeta_msg->len); + LOG_WARN("%s: Invalid length. opcode: 0x%x, len: 0x%x", __func__, + pmeta_msg->p_msg->hdr.opcode, pmeta_msg->len); return; } @@ -974,9 +1138,8 @@ void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { if (transaction != NULL) { handle_rc_metamsg_rsp(pmeta_msg, p_dev); } else { - BTIF_TRACE_DEBUG( - "%s: Discard vendor dependent rsp. code: %d label: %d.", __func__, - pmeta_msg->code, pmeta_msg->label); + LOG_VERBOSE("%s: Discard vendor dependent rsp. code: %d label: %d.", + __func__, pmeta_msg->code, pmeta_msg->label); } return; } @@ -984,15 +1147,14 @@ void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { status = AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf, sizeof(scratch_buf)); - BTIF_TRACE_DEBUG("%s: Received vendor command.code,PDU and label: %d, %d, %d", - __func__, pmeta_msg->code, avrc_command.cmd.pdu, - pmeta_msg->label); + LOG_VERBOSE("%s: Received vendor command.code,PDU and label: %d, %d, %d", + __func__, pmeta_msg->code, avrc_command.cmd.pdu, + pmeta_msg->label); if (status != AVRC_STS_NO_ERROR) { /* return error */ - BTIF_TRACE_WARNING( - "%s: Error in parsing received metamsg command. status: 0x%02x", - __func__, status); + LOG_WARN("%s: Error in parsing received metamsg command. status: 0x%02x", + __func__, status); send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_command.pdu, status, pmeta_msg->p_msg->hdr.opcode); @@ -1002,17 +1164,26 @@ void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { if (avrc_command.cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION) { uint8_t event_id = avrc_command.reg_notif.event_id; - BTIF_TRACE_EVENT( + LOG_VERBOSE( "%s: New register notification received.event_id: %s, label: 0x%x, " "code: %x", __func__, dump_rc_notification_event_id(event_id), pmeta_msg->label, pmeta_msg->code); p_dev->rc_notif[event_id - 1].bNotify = true; p_dev->rc_notif[event_id - 1].label = pmeta_msg->label; + /* this is sink(tg) feature, so it should not handle here */ + if (btif_av_both_enable() && event_id == AVRC_EVT_VOLUME_CHANGE) { + return; + } } - BTIF_TRACE_EVENT("%s: Passing received metamsg command to app. pdu: %s", - __func__, dump_rc_pdu(avrc_command.cmd.pdu)); + /* this is sink(tg) feature, so it should not handle here */ + if (btif_av_both_enable() && + avrc_command.cmd.pdu == AVRC_PDU_SET_ABSOLUTE_VOLUME) { + return; + } + LOG_VERBOSE("%s: Passing received metamsg command to app. pdu: %s", + __func__, dump_rc_pdu(avrc_command.cmd.pdu)); /* Since handle_rc_metamsg_cmd() itself is called from *btif context, no context switching is required. Invoke @@ -1030,13 +1201,12 @@ void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { ** ***************************************************************************/ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) { - BTIF_TRACE_DEBUG("%s: event: %s", __func__, dump_rc_event(event)); + LOG_VERBOSE("%s: event: %s", __func__, dump_rc_event(event)); btif_rc_device_cb_t* p_dev = NULL; switch (event) { case BTA_AV_RC_OPEN_EVT: { - BTIF_TRACE_DEBUG("%s: Peer_features: 0x%x Cover Art PSM: 0x%x", __func__, - p_data->rc_open.peer_features, - p_data->rc_open.cover_art_psm); + LOG_VERBOSE("%s: Peer_features: 0x%x Cover Art PSM: 0x%x", __func__, + p_data->rc_open.peer_features, p_data->rc_open.cover_art_psm); handle_rc_connect(&(p_data->rc_open)); } break; @@ -1051,24 +1221,23 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) { } break; case BTA_AV_RC_BROWSE_CLOSE_EVT: { - BTIF_TRACE_DEBUG("%s: BTA_AV_RC_BROWSE_CLOSE_EVT", __func__); + LOG_VERBOSE("%s: BTA_AV_RC_BROWSE_CLOSE_EVT", __func__); } break; case BTA_AV_REMOTE_CMD_EVT: { if (bt_rc_callbacks != NULL) { - BTIF_TRACE_DEBUG("%s: rc_id: 0x%x key_state: %d", __func__, - p_data->remote_cmd.rc_id, - p_data->remote_cmd.key_state); + LOG_VERBOSE("%s: rc_id: 0x%x key_state: %d", __func__, + p_data->remote_cmd.rc_id, p_data->remote_cmd.key_state); handle_rc_passthrough_cmd((&p_data->remote_cmd)); } else { - BTIF_TRACE_ERROR("%s: AVRCP TG role not up, drop passthrough commands", - __func__); + LOG_ERROR("%s: AVRCP TG role not up, drop passthrough commands", + __func__); } } break; case BTA_AV_REMOTE_RSP_EVT: { - BTIF_TRACE_DEBUG("%s: RSP: rc_id: 0x%x key_state: %d", __func__, - p_data->remote_rsp.rc_id, p_data->remote_rsp.key_state); + LOG_VERBOSE("%s: RSP: rc_id: 0x%x key_state: %d", __func__, + p_data->remote_rsp.rc_id, p_data->remote_rsp.key_state); if (p_data->remote_rsp.rc_id == AVRC_ID_VENDOR) { handle_rc_vendorunique_rsp((&p_data->remote_rsp)); @@ -1078,15 +1247,26 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) { } break; case BTA_AV_RC_FEAT_EVT: { - BTIF_TRACE_DEBUG("%s: Peer_features: %x", __func__, - p_data->rc_feat.peer_features); + LOG_VERBOSE("%s: Peer_features: %x", __func__, + p_data->rc_feat.peer_features); p_dev = btif_rc_get_device_by_handle(p_data->rc_feat.rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: RC Feature event for Invalid rc handle", - __func__); + LOG_ERROR("%s: RC Feature event for Invalid rc handle", __func__); + break; + } + LOG_VERBOSE("%s peer_ct_features:0x%x, peer_tg_features=0x%x", __func__, + p_data->rc_feat.peer_ct_features, + p_data->rc_feat.peer_tg_features); + if (btif_av_src_sink_coexist_enabled() && + (p_dev->peer_ct_features == p_data->rc_feat.peer_ct_features) && + (p_dev->peer_tg_features == p_data->rc_feat.peer_tg_features)) { + LOG_ERROR( + "do SDP twice, no need callback rc_feature to framework again"); break; } + p_dev->peer_ct_features = p_data->rc_feat.peer_ct_features; + p_dev->peer_tg_features = p_data->rc_feat.peer_tg_features; p_dev->rc_features = p_data->rc_feat.peer_features; if (bt_rc_callbacks != NULL) { handle_rc_features(p_dev); @@ -1098,12 +1278,11 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) { } break; case BTA_AV_RC_PSM_EVT: { - BTIF_TRACE_DEBUG("%s: Peer cover art PSM: %x", __func__, - p_data->rc_cover_art_psm.cover_art_psm); + LOG_VERBOSE("%s: Peer cover art PSM: %x", __func__, + p_data->rc_cover_art_psm.cover_art_psm); p_dev = btif_rc_get_device_by_handle(p_data->rc_cover_art_psm.rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: RC PSM event for Invalid rc handle", - __func__); + LOG_ERROR("%s: RC PSM event for Invalid rc handle", __func__); break; } @@ -1115,11 +1294,11 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) { case BTA_AV_META_MSG_EVT: { if (bt_rc_callbacks != NULL) { - BTIF_TRACE_DEBUG("%s: BTA_AV_META_MSG_EVT code: %d label: %d", __func__, - p_data->meta_msg.code, p_data->meta_msg.label); - BTIF_TRACE_DEBUG("%s: company_id: 0x%x len: %d handle: %d", __func__, - p_data->meta_msg.company_id, p_data->meta_msg.len, - p_data->meta_msg.rc_handle); + LOG_VERBOSE("%s: BTA_AV_META_MSG_EVT code: %d label: %d", __func__, + p_data->meta_msg.code, p_data->meta_msg.label); + LOG_VERBOSE("%s: company_id: 0x%x len: %d handle: %d", __func__, + p_data->meta_msg.company_id, p_data->meta_msg.len, + p_data->meta_msg.rc_handle); /* handle the metamsg command */ handle_rc_metamsg_cmd(&(p_data->meta_msg)); @@ -1127,14 +1306,14 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) { /* Free the Memory allocated for tAVRC_MSG */ } else if (bt_rc_ctrl_callbacks != NULL) { /* This is case of Sink + CT + TG(for abs vol)) */ - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s BTA_AV_META_MSG_EVT code:%d label:%d opcode %d ctype %d", __func__, p_data->meta_msg.code, p_data->meta_msg.label, p_data->meta_msg.p_msg->hdr.opcode, p_data->meta_msg.p_msg->hdr.ctype); - BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d", __func__, - p_data->meta_msg.company_id, p_data->meta_msg.len, - p_data->meta_msg.rc_handle); + LOG_VERBOSE("%s company_id:0x%x len:%d handle:%d", __func__, + p_data->meta_msg.company_id, p_data->meta_msg.len, + p_data->meta_msg.rc_handle); switch (p_data->meta_msg.p_msg->hdr.opcode) { case AVRC_OP_VENDOR: if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL) && @@ -1156,12 +1335,12 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) { break; } } else { - BTIF_TRACE_ERROR("Neither CTRL, nor TG is up, drop meta commands"); + LOG_ERROR("Neither CTRL, nor TG is up, drop meta commands"); } } break; default: - BTIF_TRACE_DEBUG("%s: Unhandled RC event : 0x%x", __func__, event); + LOG_VERBOSE("%s: Unhandled RC event : 0x%x", __func__, event); } } @@ -1188,7 +1367,7 @@ uint8_t btif_rc_get_connected_peer_handle(const RawAddress& peer_addr) { p_dev = btif_rc_get_device_by_bda(peer_addr); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return BTRC_HANDLE_NONE; } return p_dev->rc_handle; @@ -1210,15 +1389,15 @@ void btif_rc_check_handle_pending_play(const RawAddress& peer_addr, p_dev = btif_rc_get_device_by_bda(peer_addr); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } - BTIF_TRACE_DEBUG("%s: bSendToApp: %d", __func__, bSendToApp); + LOG_VERBOSE("%s: bSendToApp: %d", __func__, bSendToApp); if (p_dev->rc_pending_play) { if (bSendToApp) { tBTA_AV_REMOTE_CMD remote_cmd; - APPL_TRACE_DEBUG("%s: Sending queued PLAYED event to app", __func__); + LOG_VERBOSE("%s: Sending queued PLAYED event to app", __func__); memset(&remote_cmd, 0, sizeof(tBTA_AV_REMOTE_CMD)); remote_cmd.rc_handle = p_dev->rc_handle; @@ -1259,11 +1438,11 @@ static void send_reject_response(uint8_t rc_handle, uint8_t label, uint8_t pdu, status = AVRC_BldResponse(rc_handle, &avrc_rsp, &p_msg); if (status != AVRC_STS_NO_ERROR) { - BTIF_TRACE_ERROR("%s: status not AVRC_STS_NO_ERROR", __func__); + LOG_ERROR("%s: status not AVRC_STS_NO_ERROR", __func__); return; } - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Sending error notification to handle: %d. pdu: %s,status: 0x%02x", __func__, rc_handle, dump_rc_pdu(pdu), status); BTA_AvMetaRsp(rc_handle, label, ctype, p_msg); @@ -1312,23 +1491,21 @@ static void send_metamsg_rsp(btif_rc_device_cb_t* p_dev, int index, uint8_t ctype; if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } if (pmetamsg_resp == NULL) { - BTIF_TRACE_WARNING("%s: Invalid response received from application", - __func__); + LOG_WARN("%s: Invalid response received from application", __func__); return; } - BTIF_TRACE_EVENT( - "%s: rc_handle: %d, index: %d, label: %d, code: 0x%02x, pdu: %s", - __func__, p_dev->rc_handle, index, label, code, - dump_rc_pdu(pmetamsg_resp->rsp.pdu)); + LOG_VERBOSE("%s: rc_handle: %d, index: %d, label: %d, code: 0x%02x, pdu: %s", + __func__, p_dev->rc_handle, index, label, code, + dump_rc_pdu(pmetamsg_resp->rsp.pdu)); if (index >= 0 && !p_dev->rc_pdu_info[index].is_rsp_pending) { - BTIF_TRACE_ERROR("%s: is_rsp_pending false, returning", __func__); + LOG_ERROR("%s: is_rsp_pending false, returning", __func__); return; } @@ -1345,29 +1522,28 @@ static void send_metamsg_rsp(btif_rc_device_cb_t* p_dev, int index, /* de-register this notification for a CHANGED response */ p_dev->rc_notif[event_id - 1].bNotify = false; - BTIF_TRACE_DEBUG("%s: rc_handle: %d. event_id: 0x%02d bNotify: %u", - __func__, p_dev->rc_handle, event_id, bNotify); + LOG_VERBOSE("%s: rc_handle: %d. event_id: 0x%02d bNotify: %u", __func__, + p_dev->rc_handle, event_id, bNotify); if (bNotify) { BT_HDR* p_msg = NULL; tAVRC_STS status; if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse( p_dev->rc_handle, pmetamsg_resp, &p_msg))) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Sending notification to rc_handle: %d. event_id: 0x%02d", __func__, p_dev->rc_handle, event_id); bSent = true; BTA_AvMetaRsp(p_dev->rc_handle, p_dev->rc_notif[event_id - 1].label, ctype, p_msg); } else { - BTIF_TRACE_WARNING( - "%s: failed to build metamsg response. status: 0x%02x", __func__, - status); + LOG_WARN("%s: failed to build metamsg response. status: 0x%02x", + __func__, status); } } if (!bSent) { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Notification not sent, as there are no RC connections or the \ CT has not subscribed for event_id: %s", __func__, dump_rc_notification_event_id(event_id)); @@ -1383,8 +1559,8 @@ static void send_metamsg_rsp(btif_rc_device_cb_t* p_dev, int index, if (status == AVRC_STS_NO_ERROR) { BTA_AvMetaRsp(p_dev->rc_handle, label, ctype, p_msg); } else { - BTIF_TRACE_ERROR("%s: failed to build metamsg response. status: 0x%02x", - __func__, status); + LOG_ERROR("%s: failed to build metamsg response. status: 0x%02x", + __func__, status); } } @@ -1493,9 +1669,9 @@ static uint8_t fill_attribute_id_array( static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd, uint8_t ctype, uint8_t label, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_EVENT("%s: pdu: %s handle: 0x%x ctype: %x label: %x event ID: %x", - __func__, dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle, - ctype, label, pavrc_cmd->reg_notif.event_id); + LOG_VERBOSE("%s: pdu: %s handle: 0x%x ctype: %x label: %x event ID: %x", + __func__, dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle, ctype, + label, pavrc_cmd->reg_notif.event_id); switch (event) { case AVRC_PDU_GET_PLAY_STATUS: { @@ -1518,9 +1694,8 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd, pavrc_cmd->get_elem_attrs.num_attr, pavrc_cmd->get_elem_attrs.attrs, BTRC_MAX_ELEM_ATTR_SIZE, element_attrs); if (num_attr == 0) { - BTIF_TRACE_ERROR( - "%s: No valid attributes requested in GET_ELEMENT_ATTRIBUTES", - __func__); + LOG_ERROR("%s: No valid attributes requested in GET_ELEMENT_ATTRIBUTES", + __func__); send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode); return; @@ -1532,7 +1707,7 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd, case AVRC_PDU_REGISTER_NOTIFICATION: { if (pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED && pavrc_cmd->reg_notif.param == 0) { - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Device registering position changed with illegal param 0.", __func__); send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu, @@ -1547,7 +1722,7 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd, } break; case AVRC_PDU_INFORM_DISPLAY_CHARSET: { tAVRC_RESPONSE avrc_rsp; - BTIF_TRACE_EVENT("%s: AVRC_PDU_INFORM_DISPLAY_CHARSET", __func__); + LOG_VERBOSE("%s: AVRC_PDU_INFORM_DISPLAY_CHARSET", __func__); if (p_dev->rc_connected) { memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP)); avrc_rsp.inform_charset.opcode = @@ -1563,7 +1738,7 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd, uint8_t num_attr; num_attr = pavrc_cmd->get_items.attr_count; - BTIF_TRACE_EVENT( + LOG_VERBOSE( "%s: AVRC_PDU_GET_FOLDER_ITEMS num_attr: %d, start_item [%d] \ end_item [%d]", __func__, num_attr, pavrc_cmd->get_items.start_item, @@ -1607,8 +1782,8 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd, } break; case AVRC_PDU_REQUEST_CONTINUATION_RSP: { - BTIF_TRACE_EVENT("%s() REQUEST CONTINUATION: target_pdu: 0x%02d", - __func__, pavrc_cmd->continu.target_pdu); + LOG_VERBOSE("%s() REQUEST CONTINUATION: target_pdu: 0x%02d", __func__, + pavrc_cmd->continu.target_pdu); tAVRC_RESPONSE avrc_rsp; if (p_dev->rc_connected == TRUE) { memset(&(avrc_rsp.continu), 0, sizeof(tAVRC_NEXT_RSP)); @@ -1622,8 +1797,8 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd, } break; case AVRC_PDU_ABORT_CONTINUATION_RSP: { - BTIF_TRACE_EVENT("%s() ABORT CONTINUATION: target_pdu: 0x%02d", __func__, - pavrc_cmd->abort.target_pdu); + LOG_VERBOSE("%s() ABORT CONTINUATION: target_pdu: 0x%02d", __func__, + pavrc_cmd->abort.target_pdu); tAVRC_RESPONSE avrc_rsp; if (p_dev->rc_connected == TRUE) { memset(&(avrc_rsp.abort), 0, sizeof(tAVRC_NEXT_RSP)); @@ -1655,16 +1830,14 @@ static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd, pavrc_cmd->get_attrs.attr_count, pavrc_cmd->get_attrs.p_attr_list, BTRC_MAX_ELEM_ATTR_SIZE, item_attrs); if (num_attr == 0) { - BTIF_TRACE_ERROR( - "%s: No valid attributes requested in GET_ITEM_ATTRIBUTES", - __func__); + LOG_ERROR("%s: No valid attributes requested in GET_ITEM_ATTRIBUTES", + __func__); send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode); return; } fill_pdu_queue(IDX_GET_ITEM_ATTR_RSP, ctype, label, true, p_dev); - BTIF_TRACE_DEBUG("%s: GET_ITEM_ATTRIBUTES: num_attr: %d", __func__, - num_attr); + LOG_VERBOSE("%s: GET_ITEM_ATTRIBUTES: num_attr: %d", __func__, num_attr); HAL_CBACK(bt_rc_callbacks, get_item_attr_cb, pavrc_cmd->get_attrs.scope, pavrc_cmd->get_attrs.uid, pavrc_cmd->get_attrs.uid_counter, num_attr, item_attrs, p_dev->rc_addr); @@ -1711,21 +1884,21 @@ static void btif_rc_ctrl_upstreams_rsp_cmd(uint8_t event, tAVRC_COMMAND* pavrc_cmd, uint8_t label, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: pdu: %s: handle: 0x%x", __func__, - dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle); + LOG_VERBOSE("%s: pdu: %s: handle: 0x%x", __func__, + dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle); switch (event) { case AVRC_PDU_SET_ABSOLUTE_VOLUME: do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->setabsvol_cmd_cb, p_dev->rc_addr, - pavrc_cmd->volume.volume, label)); + base::BindOnce(bt_rc_ctrl_callbacks->setabsvol_cmd_cb, p_dev->rc_addr, + pavrc_cmd->volume.volume, label)); break; case AVRC_PDU_REGISTER_NOTIFICATION: if (pavrc_cmd->reg_notif.event_id == AVRC_EVT_VOLUME_CHANGE) { do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->registernotification_absvol_cb, - p_dev->rc_addr, label)); + base::BindOnce(bt_rc_ctrl_callbacks->registernotification_absvol_cb, + p_dev->rc_addr, label)); } break; } @@ -1744,9 +1917,8 @@ static void btif_rc_upstreams_rsp_evt(uint16_t event, tAVRC_RESPONSE* pavrc_resp, uint8_t ctype, uint8_t label, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_EVENT("%s: pdu: %s: handle: 0x%x ctype: %x label: %x", __func__, - dump_rc_pdu(pavrc_resp->pdu), p_dev->rc_handle, ctype, - label); + LOG_VERBOSE("%s: pdu: %s: handle: 0x%x ctype: %x label: %x", __func__, + dump_rc_pdu(pavrc_resp->pdu), p_dev->rc_handle, ctype, label); switch (event) { case AVRC_PDU_REGISTER_NOTIFICATION: { @@ -1757,7 +1929,7 @@ static void btif_rc_upstreams_rsp_evt(uint16_t event, } break; case AVRC_PDU_SET_ABSOLUTE_VOLUME: { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Set absolute volume change event received: volume: %d, ctype: " "%d", __func__, pavrc_resp->volume.volume, ctype); @@ -1786,12 +1958,14 @@ static void btif_rc_upstreams_rsp_evt(uint16_t event, * ******************************************************************************/ static bt_status_t init(btrc_callbacks_t* callbacks) { - BTIF_TRACE_EVENT("%s: ", __func__); + LOG_VERBOSE("%s: ", __func__); bt_status_t result = BT_STATUS_SUCCESS; if (bt_rc_callbacks) return BT_STATUS_DONE; bt_rc_callbacks = callbacks; + if (bt_rc_ctrl_callbacks) return BT_STATUS_SUCCESS; + for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) { initialize_device(&btif_rc_cb.rc_multi_cb[idx]); } @@ -1809,12 +1983,14 @@ static bt_status_t init(btrc_callbacks_t* callbacks) { * ******************************************************************************/ static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks) { - BTIF_TRACE_EVENT("%s: ", __func__); + LOG_VERBOSE("%s: ", __func__); bt_status_t result = BT_STATUS_SUCCESS; if (bt_rc_ctrl_callbacks) return BT_STATUS_DONE; bt_rc_ctrl_callbacks = callbacks; + if (bt_rc_callbacks) return BT_STATUS_SUCCESS; + for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) { initialize_device(&btif_rc_cb.rc_multi_cb[idx]); } @@ -1824,7 +2000,7 @@ static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks) { static void rc_ctrl_procedure_complete(btif_rc_device_cb_t* p_dev) { if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } @@ -1854,7 +2030,7 @@ static bt_status_t get_play_status_rsp(const RawAddress& bd_addr, tAVRC_RESPONSE avrc_rsp; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s: song len %d song pos %d", __func__, song_len, song_pos); + LOG_VERBOSE("%s: song len %d song pos %d", __func__, song_len, song_pos); CHECK_RC_CONNECTED(p_dev); memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP)); @@ -1896,7 +2072,7 @@ static bt_status_t get_element_attr_rsp(const RawAddress& bd_addr, tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE]; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); if (num_attr > BTRC_MAX_ELEM_ATTR_SIZE) { @@ -1916,11 +2092,10 @@ static bt_status_t get_element_attr_rsp(const RawAddress& bd_addr, element_attrs[i].name.str_len = (uint16_t)strnlen((char*)p_attrs[i].text, BTRC_MAX_ATTR_STR_LEN); element_attrs[i].name.p_str = p_attrs[i].text; - BTIF_TRACE_DEBUG( - "%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", __func__, - (unsigned int)element_attrs[i].attr_id, - element_attrs[i].name.charset_id, element_attrs[i].name.str_len, - element_attrs[i].name.p_str); + LOG_VERBOSE("%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", + __func__, (unsigned int)element_attrs[i].attr_id, + element_attrs[i].name.charset_id, + element_attrs[i].name.str_len, element_attrs[i].name.p_str); } avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR; } @@ -1951,12 +2126,12 @@ static bt_status_t register_notification_rsp( btrc_event_id_t event_id, btrc_notification_type_t type, btrc_register_notification_t* p_param) { tAVRC_RESPONSE avrc_rsp; - BTIF_TRACE_EVENT("%s: event_id: %s", __func__, - dump_rc_notification_event_id(event_id)); + LOG_VERBOSE("%s: event_id: %s", __func__, + dump_rc_notification_event_id(event_id)); std::unique_lock lock(btif_rc_cb.lock); if (event_id > MAX_RC_NOTIFICATIONS) { - BTIF_TRACE_ERROR("Invalid event id"); + LOG_ERROR("Invalid event id"); return BT_STATUS_PARM_INVALID; } @@ -1971,21 +2146,20 @@ static bt_status_t register_notification_rsp( memset(&(avrc_rsp.reg_notif.param), 0, sizeof(tAVRC_NOTIF_RSP_PARAM)); if (!(btif_rc_cb.rc_multi_cb[idx].rc_connected)) { - BTIF_TRACE_ERROR("%s: Avrcp device is not connected, handle: 0x%x", - __func__, btif_rc_cb.rc_multi_cb[idx].rc_handle); + LOG_ERROR("%s: Avrcp device is not connected, handle: 0x%x", __func__, + btif_rc_cb.rc_multi_cb[idx].rc_handle); continue; } if (!btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].bNotify) { - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Avrcp Event id is not registered: event_id: %x, handle: 0x%x", __func__, event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle); continue; } - BTIF_TRACE_DEBUG( - "%s: Avrcp Event id is registered: event_id: %x handle: 0x%x", __func__, - event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle); + LOG_VERBOSE("%s: Avrcp Event id is registered: event_id: %x handle: 0x%x", + __func__, event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle); switch (event_id) { case BTRC_EVT_PLAY_STATUS_CHANGED: @@ -2016,7 +2190,7 @@ static bt_status_t register_notification_rsp( break; default: - BTIF_TRACE_WARNING("%s: Unhandled event ID: 0x%x", __func__, event_id); + LOG_WARN("%s: Unhandled event ID: 0x%x", __func__, event_id); return BT_STATUS_UNHANDLED; } @@ -2060,14 +2234,13 @@ static bt_status_t get_folder_items_list_rsp(const RawAddress& bd_addr, btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); btrc_folder_items_t* cur_item = NULL; - BTIF_TRACE_DEBUG("%s: uid_counter %d num_items %d", __func__, uid_counter, - num_items); + LOG_VERBOSE("%s: uid_counter %d num_items %d", __func__, uid_counter, + num_items); CHECK_RC_CONNECTED(p_dev); /* check if rsp to previous cmd was completed */ if (!p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending) { - BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered", - __func__); + LOG_WARN("%s: Not sending response as no PDU was registered", __func__); return BT_STATUS_UNHANDLED; } @@ -2079,7 +2252,7 @@ static bt_status_t get_folder_items_list_rsp(const RawAddress& bd_addr, avrc_rsp.get_items.status = status_code_map[rsp_status]; if (avrc_rsp.get_items.status != AVRC_STS_NO_ERROR) { - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Error in parsing the received getfolderitems cmd. status: 0x%02x", __func__, avrc_rsp.get_items.status); status = avrc_rsp.get_items.status; @@ -2140,8 +2313,8 @@ static bt_status_t get_folder_items_list_rsp(const RawAddress& bd_addr, } break; default: { - BTIF_TRACE_ERROR("%s: Unknown item_type: %d. Internal Error", - __func__, p_items->item_type); + LOG_ERROR("%s: Unknown item_type: %d. Internal Error", __func__, + p_items->item_type); status = AVRC_STS_INTERNAL_ERR; } break; } @@ -2157,11 +2330,10 @@ static bt_status_t get_folder_items_list_rsp(const RawAddress& bd_addr, } int len_before = p_msg ? p_msg->len : 0; - BTIF_TRACE_DEBUG("%s: item_cnt: %d len: %d", __func__, item_cnt, - len_before); + LOG_VERBOSE("%s: item_cnt: %d len: %d", __func__, item_cnt, len_before); status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg); - BTIF_TRACE_DEBUG("%s: Build rsp status: %d len: %d", __func__, status, - (p_msg ? p_msg->len : 0)); + LOG_VERBOSE("%s: Build rsp status: %d len: %d", __func__, status, + (p_msg ? p_msg->len : 0)); int len_after = p_msg ? p_msg->len : 0; if (status != AVRC_STS_NO_ERROR || len_before == len_after) { /* Error occured in build response or we ran out of buffer so break the @@ -2183,8 +2355,8 @@ static bt_status_t get_folder_items_list_rsp(const RawAddress& bd_addr, p_msg); } else /* Error occured, send reject response */ { - BTIF_TRACE_ERROR("%s: Error status: 0x%02X. Sending reject rsp", __func__, - avrc_rsp.rsp.status); + LOG_ERROR("%s: Error status: 0x%02X. Sending reject rsp", __func__, + avrc_rsp.rsp.status); send_reject_response( p_dev->rc_handle, p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label, avrc_rsp.pdu, avrc_rsp.get_items.status, avrc_rsp.get_items.opcode); @@ -2215,7 +2387,7 @@ static bt_status_t set_addressed_player_rsp(const RawAddress& bd_addr, tAVRC_RESPONSE avrc_rsp; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); avrc_rsp.addr_player.pdu = AVRC_PDU_SET_ADDRESSED_PLAYER; @@ -2272,13 +2444,12 @@ static bt_status_t set_browsed_player_rsp(const RawAddress& bd_addr, avrc_rsp.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER; avrc_rsp.br_player.opcode = opcode_from_pdu(AVRC_PDU_SET_BROWSED_PLAYER); - BTIF_TRACE_DEBUG("%s: rsp_status: 0x%02X avrc_rsp.br_player.status: 0x%02X", - __func__, rsp_status, avrc_rsp.br_player.status); + LOG_VERBOSE("%s: rsp_status: 0x%02X avrc_rsp.br_player.status: 0x%02X", + __func__, rsp_status, avrc_rsp.br_player.status); /* check if rsp to previous cmd was completed */ if (!p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending) { - BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered", - __func__); + LOG_WARN("%s: Not sending response as no PDU was registered", __func__); return BT_STATUS_UNHANDLED; } @@ -2288,15 +2459,15 @@ static bt_status_t set_browsed_player_rsp(const RawAddress& bd_addr, avrc_rsp.br_player.folder_depth = folder_depth; avrc_rsp.br_player.p_folders = (tAVRC_NAME*)p_folders; - BTIF_TRACE_DEBUG("%s: folder_depth: 0x%02X num_items: %d", __func__, - folder_depth, num_items); + LOG_VERBOSE("%s: folder_depth: 0x%02X num_items: %d", __func__, + folder_depth, num_items); if (folder_depth > 0) { /* Iteratively build response for all folders across folder depth upto * current path */ avrc_rsp.br_player.folder_depth = 1; for (item_cnt = 0; item_cnt < folder_depth; item_cnt++) { - BTIF_TRACE_DEBUG("%s: iteration: %d", __func__, item_cnt); + LOG_VERBOSE("%s: iteration: %d", __func__, item_cnt); item.str_len = p_folders[item_cnt].str_len; item.p_str = p_folders[item_cnt].p_str; avrc_rsp.br_player.p_folders = &item; @@ -2304,7 +2475,7 @@ static bt_status_t set_browsed_player_rsp(const RawAddress& bd_addr, /* Add current item to buffer and build response */ status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg); if (AVRC_STS_NO_ERROR != status) { - BTIF_TRACE_WARNING("%s: Build rsp status: %d", __func__, status); + LOG_WARN("%s: Build rsp status: %d", __func__, status); /* if the build fails, it is likely that we ran out of buffer. so if * we have * some items to send, reset this error to no error for sending what we @@ -2324,7 +2495,7 @@ static bt_status_t set_browsed_player_rsp(const RawAddress& bd_addr, avrc_rsp.br_player.status = status; } else /* error received from above layer */ { - BTIF_TRACE_WARNING( + LOG_WARN( "%s: Error in parsing the received setbrowsed command. status: 0x%02x", __func__, avrc_rsp.br_player.status); status = avrc_rsp.br_player.status; @@ -2339,8 +2510,8 @@ static bt_status_t set_browsed_player_rsp(const RawAddress& bd_addr, p_msg); } else /* Error occured, send reject response */ { - BTIF_TRACE_ERROR("%s: Error status: 0x%02X. Sending reject rsp", __func__, - avrc_rsp.br_player.status); + LOG_ERROR("%s: Error status: 0x%02X. Sending reject rsp", __func__, + avrc_rsp.br_player.status); send_reject_response( p_dev->rc_handle, p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label, avrc_rsp.pdu, avrc_rsp.br_player.status, avrc_rsp.get_items.opcode); @@ -2372,7 +2543,7 @@ static bt_status_t change_path_rsp(const RawAddress& bd_addr, tAVRC_RESPONSE avrc_rsp; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); avrc_rsp.chg_path.pdu = AVRC_PDU_CHANGE_PATH; @@ -2405,7 +2576,7 @@ static bt_status_t search_rsp(const RawAddress& bd_addr, tAVRC_RESPONSE avrc_rsp; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); avrc_rsp.search.pdu = AVRC_PDU_SEARCH; @@ -2440,7 +2611,7 @@ static bt_status_t get_item_attr_rsp(const RawAddress& bd_addr, tAVRC_ATTR_ENTRY item_attrs[BTRC_MAX_ELEM_ATTR_SIZE]; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); memset(item_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr); @@ -2480,7 +2651,7 @@ static bt_status_t add_to_now_playing_rsp(const RawAddress& bd_addr, tAVRC_RESPONSE avrc_rsp; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); avrc_rsp.add_to_play.pdu = AVRC_PDU_ADD_TO_NOW_PLAYING; @@ -2512,7 +2683,7 @@ static bt_status_t play_item_rsp(const RawAddress& bd_addr, tAVRC_RESPONSE avrc_rsp; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); avrc_rsp.play_item.pdu = AVRC_PDU_PLAY_ITEM; @@ -2546,7 +2717,7 @@ static bt_status_t get_total_num_of_items_rsp(const RawAddress& bd_addr, tAVRC_RESPONSE avrc_rsp; btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); avrc_rsp.get_num_of_items.pdu = AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS; @@ -2580,7 +2751,7 @@ static bt_status_t get_total_num_of_items_rsp(const RawAddress& bd_addr, * **************************************************************************/ static bt_status_t set_volume(uint8_t volume) { - BTIF_TRACE_DEBUG("%s: volume: %d", __func__, volume); + LOG_VERBOSE("%s: volume: %d", __func__, volume); tAVRC_STS status = BT_STATUS_UNSUPPORTED; for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) { @@ -2589,8 +2760,8 @@ static bt_status_t set_volume(uint8_t volume) { if (p_dev->rc_volume == volume) { status = BT_STATUS_DONE; - BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x", __func__, - volume); + LOG_ERROR("%s: volume value already set earlier: 0x%02x", __func__, + volume); continue; } @@ -2608,8 +2779,8 @@ static bt_status_t set_volume(uint8_t volume) { if (!(p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL)) continue; - BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d", - __func__, volume); + LOG_VERBOSE("%s: Peer supports absolute volume. newVolume: %d", __func__, + volume); tAVRC_COMMAND avrc_cmd = {.volume = {.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME, .status = AVRC_STS_NO_ERROR, @@ -2618,9 +2789,8 @@ static bt_status_t set_volume(uint8_t volume) { BT_HDR* p_msg = NULL; if (AVRC_BldCommand(&avrc_cmd, &p_msg) != AVRC_STS_NO_ERROR) { - BTIF_TRACE_ERROR( - "%s: failed to build absolute volume command. status: 0x%02x", - __func__, status); + LOG_ERROR("%s: failed to build absolute volume command. status: 0x%02x", + __func__, status); status = BT_STATUS_FAIL; continue; } @@ -2636,14 +2806,14 @@ static bt_status_t set_volume(uint8_t volume) { if (tran_status != BT_STATUS_SUCCESS || !p_transaction) { osi_free_and_reset((void**)&p_msg); - BTIF_TRACE_ERROR("%s: failed to get label, pdu_id=%s, status=0x%02x", - __func__, dump_rc_pdu(avrc_cmd.pdu), tran_status); + LOG_ERROR("%s: failed to get label, pdu_id=%s, status=0x%02x", __func__, + dump_rc_pdu(avrc_cmd.pdu), tran_status); status = BT_STATUS_FAIL; continue; } - BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__, - p_transaction->label); + LOG_VERBOSE("%s: msgreq being sent out with label: %d", __func__, + p_transaction->label); BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->label, AVRC_CMD_CTRL, p_msg); status = BT_STATUS_SUCCESS; start_transaction_timer(p_dev, p_transaction->label, BTIF_RC_TIMEOUT_MS); @@ -2663,7 +2833,7 @@ static bt_status_t set_volume(uint8_t volume) { static void register_volumechange(btif_rc_device_cb_t* p_dev) { if (p_dev == nullptr) { - BTIF_TRACE_ERROR("%s: device was null", __func__); + LOG_ERROR("%s: device was null", __func__); return; } @@ -2684,8 +2854,8 @@ static void register_volumechange(btif_rc_device_cb_t* p_dev) { } else { p_transaction = get_transaction_by_lbl(p_dev, p_dev->rc_vol_label); if (NULL != p_transaction) { - BTIF_TRACE_DEBUG("%s: already in progress for label: %d", __func__, - p_dev->rc_vol_label); + LOG_VERBOSE("%s: already in progress for label: %d", __func__, + p_dev->rc_vol_label); return; } status = get_transaction(p_dev, context, &p_transaction); @@ -2694,11 +2864,11 @@ static void register_volumechange(btif_rc_device_cb_t* p_dev) { if (BT_STATUS_SUCCESS == status && NULL != p_transaction) { p_dev->rc_vol_label = p_transaction->label; } else { - BTIF_TRACE_ERROR("%s: failed to get a transaction label", __func__); + LOG_ERROR("%s: failed to get a transaction label", __func__); return; } - BTIF_TRACE_DEBUG("%s: label: %d", __func__, p_dev->rc_vol_label); + LOG_VERBOSE("%s: label: %d", __func__, p_dev->rc_vol_label); avrc_cmd.cmd.opcode = 0x00; avrc_cmd.pdu = AVRC_PDU_REGISTER_NOTIFICATION; @@ -2710,9 +2880,9 @@ static void register_volumechange(btif_rc_device_cb_t* p_dev) { if (AVRC_STS_NO_ERROR == BldResp && p_msg) { BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->label, AVRC_CMD_NOTIF, p_msg); - BTIF_TRACE_DEBUG("%s: BTA_AvMetaCmd called", __func__); + LOG_VERBOSE("%s: BTA_AvMetaCmd called", __func__); } else { - BTIF_TRACE_ERROR("%s: failed to build command: %d", __func__, BldResp); + LOG_ERROR("%s: failed to build command: %d", __func__, BldResp); } } @@ -2731,7 +2901,7 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg, uint8_t scratch_buf[512] = {0}; tAVRC_STS status = BT_STATUS_UNSUPPORTED; - BTIF_TRACE_DEBUG("%s: ", __func__); + LOG_VERBOSE("%s: ", __func__); if (AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode && (AVRC_RSP_CHANGED == pmeta_msg->code || @@ -2740,7 +2910,7 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg, AVRC_RSP_NOT_IMPL == pmeta_msg->code)) { status = AVRC_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, sizeof(scratch_buf)); - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: code:%d, event ID: %d, PDU: %x, parsing status: %d, label: %d", __func__, pmeta_msg->code, avrc_response.reg_notif.event_id, avrc_response.reg_notif.pdu, status, pmeta_msg->label); @@ -2762,7 +2932,7 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg, p_dev->rc_vol_label != pmeta_msg->label) { // Just discard the message, if the device sends back with an incorrect // label - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Discarding register notification in rsp.code: %d and label: %d", __func__, pmeta_msg->code, pmeta_msg->label); return; @@ -2772,13 +2942,13 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg, AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id && (AVRC_RSP_REJ == pmeta_msg->code || AVRC_RSP_NOT_IMPL == pmeta_msg->code)) { - BTIF_TRACE_DEBUG("%s remove AbsoluteVolume feature flag.", __func__); + LOG_VERBOSE("%s remove AbsoluteVolume feature flag.", __func__); p_dev->rc_features &= ~BTA_AV_FEAT_ADV_CTRL; handle_rc_features(p_dev); return; } } else { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Received vendor dependent in adv ctrl rsp. code: %d len: %d. Not " "processing it.", __func__, pmeta_msg->code, pmeta_msg->len); @@ -2796,8 +2966,8 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg, release_transaction(p_dev, pmeta_msg->label); } - BTIF_TRACE_EVENT("%s: Passing received metamsg response to app. pdu: %s", - __func__, dump_rc_pdu(avrc_response.pdu)); + LOG_VERBOSE("%s: Passing received metamsg response to app. pdu: %s", __func__, + dump_rc_pdu(avrc_response.pdu)); btif_rc_upstreams_rsp_evt((uint16_t)avrc_response.rsp.pdu, &avrc_response, pmeta_msg->code, pmeta_msg->label, p_dev); } @@ -2838,7 +3008,7 @@ static void rc_notification_interim_timeout(btif_rc_device_cb_t* p_dev, uint8_t event_id) { /* Device disconnections clear the event list but can't free the timer */ if (p_dev == NULL || p_dev->rc_supported_event_list) { - BTIF_TRACE_WARNING("%s: timeout for null device or event list", __func__); + LOG_WARN("%s: timeout for null device or event list", __func__); return; } @@ -2893,7 +3063,7 @@ static void register_for_event_notification(btif_rc_supported_event_t* p_event, bt_status_t status = register_notification_cmd(p_event->event_id, interval_in_seconds, p_dev); if (status != BT_STATUS_SUCCESS) { - BTIF_TRACE_ERROR("%s: failed, status=%d", __func__, status); + LOG_ERROR("%s: failed, status=%d", __func__, status); return; } @@ -2930,8 +3100,8 @@ static bt_status_t build_and_send_vendor_cmd(tAVRC_COMMAND* avrc_cmd, bt_status_t tran_status = get_transaction(p_dev, context, &p_transaction); if (BT_STATUS_SUCCESS != tran_status || p_transaction == NULL) { - BTIF_TRACE_ERROR("%s: failed to get label, pdu_id=%s, status=0x%02x", - __func__, dump_rc_pdu(avrc_cmd->pdu), tran_status); + LOG_ERROR("%s: failed to get label, pdu_id=%s, status=0x%02x", __func__, + dump_rc_pdu(avrc_cmd->pdu), tran_status); return BT_STATUS_FAIL; } @@ -2939,15 +3109,14 @@ static bt_status_t build_and_send_vendor_cmd(tAVRC_COMMAND* avrc_cmd, tAVRC_STS status = AVRC_BldCommand(avrc_cmd, &p_msg); if (status == AVRC_STS_NO_ERROR && p_msg != NULL) { uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset; - BTIF_TRACE_DEBUG("%s: %s msgreq being sent out with label: %d", __func__, - dump_rc_pdu(avrc_cmd->pdu), p_transaction->label); + LOG_VERBOSE("%s: %s msgreq being sent out with label: %d", __func__, + dump_rc_pdu(avrc_cmd->pdu), p_transaction->label); BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->label, cmd_code, data_start, p_msg->len); status = BT_STATUS_SUCCESS; start_transaction_timer(p_dev, p_transaction->label, BTIF_RC_TIMEOUT_MS); } else { - BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__, - status); + LOG_ERROR("%s: failed to build command. status: 0x%02x", __func__, status); release_transaction(p_dev, p_transaction->label); } osi_free(p_msg); @@ -2977,21 +3146,21 @@ static bt_status_t build_and_send_browsing_cmd(tAVRC_COMMAND* avrc_cmd, bt_status_t tran_status = get_transaction(p_dev, context, &p_transaction); if (tran_status != BT_STATUS_SUCCESS || p_transaction == NULL) { - BTIF_TRACE_ERROR("%s: failed to get label, pdu_id=%s, status=0x%02x", - __func__, dump_rc_pdu(avrc_cmd->pdu), tran_status); + LOG_ERROR("%s: failed to get label, pdu_id=%s, status=0x%02x", __func__, + dump_rc_pdu(avrc_cmd->pdu), tran_status); return BT_STATUS_FAIL; } BT_HDR* p_msg = NULL; tAVRC_STS status = AVRC_BldCommand(avrc_cmd, &p_msg); if (status != AVRC_STS_NO_ERROR) { - BTIF_TRACE_ERROR("%s: failed to build command status %d", __func__, status); + LOG_ERROR("%s: failed to build command status %d", __func__, status); release_transaction(p_dev, p_transaction->label); return BT_STATUS_FAIL; } - BTIF_TRACE_DEBUG("%s: Send pdu_id=%s, label=%d", __func__, - dump_rc_pdu(avrc_cmd->pdu), p_transaction->label); + LOG_VERBOSE("%s: Send pdu_id=%s, label=%d", __func__, + dump_rc_pdu(avrc_cmd->pdu), p_transaction->label); BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->label, AVRC_CMD_CTRL, p_msg); start_transaction_timer(p_dev, p_transaction->label, BTIF_RC_TIMEOUT_MS); return BT_STATUS_SUCCESS; @@ -3015,8 +3184,7 @@ static void handle_get_capability_response(tBTA_AV_META_MSG* pmeta_msg, /* Todo: Do we need to retry on command timeout */ if (p_rsp->status != AVRC_STS_NO_ERROR) { - BTIF_TRACE_ERROR("%s: Error capability response: 0x%02X", __func__, - p_rsp->status); + LOG_ERROR("%s: Error capability response: 0x%02X", __func__, p_rsp->status); return; } @@ -3058,10 +3226,9 @@ static void handle_get_capability_response(tBTA_AV_META_MSG* pmeta_msg, } } else if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID) { getcapabilities_cmd(AVRC_CAP_EVENTS_SUPPORTED, p_dev); - BTIF_TRACE_EVENT("%s: AVRC_CAP_COMPANY_ID: ", __func__); + LOG_VERBOSE("%s: AVRC_CAP_COMPANY_ID: ", __func__); for (xx = 0; xx < p_rsp->count; xx++) { - BTIF_TRACE_EVENT("%s: company_id: %d", __func__, - p_rsp->param.company_id[xx]); + LOG_VERBOSE("%s: company_id: %d", __func__, p_rsp->param.company_id[xx]); } } } @@ -3101,7 +3268,16 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); + return; + } + + if (btif_av_src_sink_coexist_enabled() && + p_rsp->event_id == AVRC_EVT_VOLUME_CHANGE) { + LOG_ERROR( + "%s: legacy TG don't handle absolute volume change. leave it to new " + "avrcp", + __func__); return; } @@ -3112,15 +3288,15 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_supported_event_t* p_event; list_node_t* node; - BTIF_TRACE_DEBUG("%s: Interim response: 0x%2X ", __func__, p_rsp->event_id); + LOG_VERBOSE("%s: Interim response: 0x%2X ", __func__, p_rsp->event_id); switch (p_rsp->event_id) { case AVRC_EVT_PLAY_STATUS_CHANGE: get_play_status_cmd(p_dev); do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb, - p_dev->rc_addr, - (btrc_play_status_t)p_rsp->param.play_status)); + base::BindOnce(bt_rc_ctrl_callbacks->play_status_changed_cb, + p_dev->rc_addr, + (btrc_play_status_t)p_rsp->param.play_status)); break; case AVRC_EVT_TRACK_CHANGE: @@ -3141,28 +3317,31 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, case AVRC_EVT_NOW_PLAYING_CHANGE: do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->now_playing_contents_changed_cb, - p_dev->rc_addr)); + base::BindOnce( + bt_rc_ctrl_callbacks->now_playing_contents_changed_cb, + p_dev->rc_addr)); break; case AVRC_EVT_AVAL_PLAYERS_CHANGE: - BTIF_TRACE_DEBUG("%s: AVRC_EVT_AVAL_PLAYERS_CHANGE", __func__); + LOG_VERBOSE("%s: AVRC_EVT_AVAL_PLAYERS_CHANGE", __func__); do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->available_player_changed_cb, - p_dev->rc_addr)); + base::BindOnce(bt_rc_ctrl_callbacks->available_player_changed_cb, + p_dev->rc_addr)); break; case AVRC_EVT_ADDR_PLAYER_CHANGE: do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->addressed_player_changed_cb, - p_dev->rc_addr, p_rsp->param.addr_player.player_id)); + base::BindOnce(bt_rc_ctrl_callbacks->addressed_player_changed_cb, + p_dev->rc_addr, p_rsp->param.addr_player.player_id)); break; case AVRC_EVT_PLAY_POS_CHANGED: - do_in_jni_thread(FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->play_position_changed_cb, p_dev->rc_addr, 0, - p_rsp->param.play_pos)); + do_in_jni_thread( + FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->play_position_changed_cb, + p_dev->rc_addr, 0, p_rsp->param.play_pos)); break; case AVRC_EVT_UIDS_CHANGE: @@ -3173,8 +3352,8 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, case AVRC_EVT_BATTERY_STATUS_CHANGE: case AVRC_EVT_SYSTEM_STATUS_CHANGE: default: - BTIF_TRACE_ERROR("%s: Unhandled interim response: 0x%2X", __func__, - p_rsp->event_id); + LOG_ERROR("%s: Unhandled interim response: 0x%2X", __func__, + p_rsp->event_id); return; } @@ -3202,8 +3381,8 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, if (p_dev->rc_features & BTA_AV_FEAT_APP_SETTING) { list_player_app_setting_attrib_cmd(p_dev); } else { - BTIF_TRACE_DEBUG("%s: App setting not supported, complete procedure", - __func__); + LOG_VERBOSE("%s: App setting not supported, complete procedure", + __func__); rc_ctrl_procedure_complete(p_dev); } } @@ -3211,8 +3390,8 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_supported_event_t* p_event; list_node_t* node; - BTIF_TRACE_DEBUG("%s: Notification completed: 0x%2X ", __func__, - p_rsp->event_id); + LOG_VERBOSE("%s: Notification completed: 0x%2X ", __func__, + p_rsp->event_id); node = list_begin(p_dev->rc_supported_event_list); @@ -3233,9 +3412,9 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, */ do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb, - p_dev->rc_addr, - (btrc_play_status_t)p_rsp->param.play_status)); + base::BindOnce(bt_rc_ctrl_callbacks->play_status_changed_cb, + p_dev->rc_addr, + (btrc_play_status_t)p_rsp->param.play_status)); break; @@ -3258,7 +3437,7 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, } do_in_jni_thread( FROM_HERE, - base::Bind( + base::BindOnce( bt_rc_ctrl_callbacks->playerapplicationsetting_changed_cb, p_dev->rc_addr, app_settings)); } break; @@ -3284,8 +3463,8 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, case AVRC_EVT_BATTERY_STATUS_CHANGE: case AVRC_EVT_SYSTEM_STATUS_CHANGE: default: - BTIF_TRACE_ERROR("%s: Unhandled completion response: 0x%2X", __func__, - p_rsp->event_id); + LOG_ERROR("%s: Unhandled completion response: 0x%2X", __func__, + p_rsp->event_id); return; } } @@ -3307,8 +3486,8 @@ static void handle_app_attr_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL || p_rsp->status != AVRC_STS_NO_ERROR) { - BTIF_TRACE_ERROR("%s: Error getting Player application settings: 0x%2X", - __func__, p_rsp->status); + LOG_ERROR("%s: Error getting Player application settings: 0x%2X", __func__, + p_rsp->status); rc_ctrl_procedure_complete(p_dev); return; } @@ -3335,7 +3514,7 @@ static void handle_app_attr_response(tBTA_AV_META_MSG* pmeta_msg, list_player_app_setting_value_cmd(p_dev->rc_app_settings.attrs[0].attr_id, p_dev); } else { - BTIF_TRACE_ERROR("%s: No Player application settings found", __func__); + LOG_ERROR("%s: No Player application settings found", __func__); } } @@ -3361,8 +3540,8 @@ static void handle_app_val_response(tBTA_AV_META_MSG* pmeta_msg, /* Todo: Do we need to retry on command timeout */ if (p_dev == NULL || p_rsp->status != AVRC_STS_NO_ERROR) { - BTIF_TRACE_ERROR("%s: Error fetching attribute values: 0x%02X", __func__, - p_rsp->status); + LOG_ERROR("%s: Error fetching attribute values: 0x%02X", __func__, + p_rsp->status); return; } @@ -3391,9 +3570,9 @@ static void handle_app_val_response(tBTA_AV_META_MSG* pmeta_msg, get_player_app_setting_cmd(p_app_settings->num_attrs, attrs, p_dev); do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, - p_dev->rc_addr, p_app_settings->num_attrs, - p_app_settings->attrs, 0, nullptr)); + base::BindOnce(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, + p_dev->rc_addr, p_app_settings->num_attrs, + p_app_settings->attrs, 0, nullptr)); } } else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs) { attr_index = p_app_settings->ext_attr_index; @@ -3437,13 +3616,13 @@ static void handle_app_cur_val_response(tBTA_AV_META_MSG* pmeta_msg, /* Todo: Do we need to retry on command timeout */ if (p_rsp->status != AVRC_STS_NO_ERROR) { - BTIF_TRACE_ERROR("%s: Error fetching current settings: 0x%02X", __func__, - p_rsp->status); + LOG_ERROR("%s: Error fetching current settings: 0x%02X", __func__, + p_rsp->status); return; } p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: Error in getting Device Address", __func__); + LOG_ERROR("%s: Error in getting Device Address", __func__); osi_free_and_reset((void**)&p_rsp->p_vals); return; } @@ -3462,8 +3641,8 @@ static void handle_app_cur_val_response(tBTA_AV_META_MSG* pmeta_msg, do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_changed_cb, - p_dev->rc_addr, app_settings)); + base::BindOnce(bt_rc_ctrl_callbacks->playerapplicationsetting_changed_cb, + p_dev->rc_addr, app_settings)); /* Application settings are fetched only once for initial values * initiate anything that follows after RC procedure. * Defer it if browsing is supported till players query @@ -3492,7 +3671,7 @@ static void handle_app_attr_txt_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } @@ -3502,8 +3681,8 @@ static void handle_app_attr_txt_response(tBTA_AV_META_MSG* pmeta_msg, if (p_rsp->status != AVRC_STS_NO_ERROR) { uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE]; - BTIF_TRACE_ERROR("%s: Error fetching attribute text: 0x%02X", __func__, - p_rsp->status); + LOG_ERROR("%s: Error fetching attribute text: 0x%02X", __func__, + p_rsp->status); /* Not able to fetch Text for extended Menu, skip the process * and cleanup used memory. Proceed to get the current settings * for standard attributes. @@ -3522,9 +3701,10 @@ static void handle_app_attr_txt_response(tBTA_AV_META_MSG* pmeta_msg, } do_in_jni_thread( - FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, - p_dev->rc_addr, p_app_settings->num_attrs, - p_app_settings->attrs, 0, nullptr)); + FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, + p_dev->rc_addr, p_app_settings->num_attrs, + p_app_settings->attrs, 0, nullptr)); get_player_app_setting_cmd(xx, attrs, p_dev); return; @@ -3571,7 +3751,7 @@ static void handle_app_attr_val_txt_response( btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } @@ -3581,8 +3761,8 @@ static void handle_app_attr_val_txt_response( if (p_rsp->status != AVRC_STS_NO_ERROR) { uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE]; - BTIF_TRACE_ERROR("%s: Error fetching attribute value text: 0x%02X", - __func__, p_rsp->status); + LOG_ERROR("%s: Error fetching attribute value text: 0x%02X", __func__, + p_rsp->status); /* Not able to fetch Text for extended Menu, skip the process * and cleanup used memory. Proceed to get the current settings @@ -3606,17 +3786,18 @@ static void handle_app_attr_val_txt_response( attrs[xx] = p_app_settings->attrs[xx].attr_id; } do_in_jni_thread( - FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, - p_dev->rc_addr, p_app_settings->num_attrs, - p_app_settings->attrs, 0, nullptr)); + FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, + p_dev->rc_addr, p_app_settings->num_attrs, + p_app_settings->attrs, 0, nullptr)); get_player_app_setting_cmd(xx, attrs, p_dev); return; } if (p_app_settings->ext_val_index >= AVRC_MAX_APP_ATTR_SIZE) { - BTIF_TRACE_ERROR("ext_val_index is 0x%02x, overflow!", - p_app_settings->ext_val_index); + LOG_ERROR("ext_val_index is 0x%02x, overflow!", + p_app_settings->ext_val_index); return; } @@ -3652,17 +3833,18 @@ static void handle_app_attr_val_txt_response( } do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, - p_dev->rc_addr, p_app_settings->num_attrs, - p_app_settings->attrs, p_app_settings->num_ext_attrs, - p_app_settings->ext_attrs)); + base::BindOnce(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, + p_dev->rc_addr, p_app_settings->num_attrs, + p_app_settings->attrs, p_app_settings->num_ext_attrs, + p_app_settings->ext_attrs)); get_player_app_setting_cmd(xx + x, attrs, p_dev); /* Free the application settings information after sending to * application. */ - do_in_jni_thread(FROM_HERE, base::Bind(cleanup_app_attr_val_txt_response, - p_app_settings)); + do_in_jni_thread( + FROM_HERE, + base::BindOnce(cleanup_app_attr_val_txt_response, p_app_settings)); p_app_settings->num_attrs = 0; } } @@ -3706,7 +3888,7 @@ static void handle_set_app_attr_val_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } @@ -3717,9 +3899,10 @@ static void handle_set_app_attr_val_response(tBTA_AV_META_MSG* pmeta_msg, if (pmeta_msg && (pmeta_msg->code == AVRC_RSP_ACCEPT)) { accepted = 1; } - do_in_jni_thread(FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->setplayerappsetting_rsp_cb, - p_dev->rc_addr, accepted)); + do_in_jni_thread( + FROM_HERE, + base::BindOnce(bt_rc_ctrl_callbacks->setplayerappsetting_rsp_cb, + p_dev->rc_addr, accepted)); } /*************************************************************************** @@ -3742,7 +3925,7 @@ static void handle_get_metadata_attr_response(tBTA_AV_META_MSG* pmeta_msg, (btrc_element_attr_val_t*)osi_calloc(buf_size); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } @@ -3756,10 +3939,13 @@ static void handle_get_metadata_attr_response(tBTA_AV_META_MSG* pmeta_msg, osi_free_and_reset((void**)&p_rsp->p_attrs[i].name.p_str); } } + + osi_free_and_reset((void**)&p_rsp->p_attrs); + do_in_jni_thread(FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->track_changed_cb, - p_dev->rc_addr, p_rsp->num_attrs, p_attr)); - do_in_jni_thread(FROM_HERE, base::Bind(osi_free, p_attr)); + base::BindOnce(bt_rc_ctrl_callbacks->track_changed_cb, + p_dev->rc_addr, p_rsp->num_attrs, p_attr)); + do_in_jni_thread(FROM_HERE, base::BindOnce(osi_free, p_attr)); } else if (p_rsp->status == BTIF_RC_STS_TIMEOUT) { /* Retry for timeout case, this covers error handling * for continuation failure also. @@ -3768,8 +3954,8 @@ static void handle_get_metadata_attr_response(tBTA_AV_META_MSG* pmeta_msg, const uint8_t attr_list_size = get_requested_attributes_list_size(p_dev); get_metadata_attribute_cmd(attr_list_size, attr_list, p_dev); } else { - BTIF_TRACE_ERROR("%s: Error in get element attr procedure: %d", __func__, - p_rsp->status); + LOG_ERROR("%s: Error in get element attr procedure: %d", __func__, + p_rsp->status); } } @@ -3789,7 +3975,7 @@ static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } @@ -3797,15 +3983,15 @@ static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg, if (p_rsp->status == AVRC_STS_NO_ERROR) { do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb, p_dev->rc_addr, - (btrc_play_status_t)p_rsp->play_status)); + base::BindOnce(bt_rc_ctrl_callbacks->play_status_changed_cb, + p_dev->rc_addr, (btrc_play_status_t)p_rsp->play_status)); do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->play_position_changed_cb, - p_dev->rc_addr, p_rsp->song_len, p_rsp->song_pos)); + base::BindOnce(bt_rc_ctrl_callbacks->play_position_changed_cb, + p_dev->rc_addr, p_rsp->song_len, p_rsp->song_pos)); } else { - BTIF_TRACE_ERROR("%s: Error in get play status procedure: %d", __func__, - p_rsp->status); + LOG_ERROR("%s: Error in get play status procedure: %d", __func__, + p_rsp->status); } } @@ -3825,18 +4011,18 @@ static void handle_set_addressed_player_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } if (p_rsp->status == AVRC_STS_NO_ERROR) { - do_in_jni_thread(FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->set_addressed_player_cb, - p_dev->rc_addr, p_rsp->status)); + do_in_jni_thread( + FROM_HERE, base::BindOnce(bt_rc_ctrl_callbacks->set_addressed_player_cb, + p_dev->rc_addr, p_rsp->status)); } else { - BTIF_TRACE_ERROR("%s: Error in get play status procedure %d", __func__, - p_rsp->status); + LOG_ERROR("%s: Error in get play status procedure %d", __func__, + p_rsp->status); } } @@ -3864,11 +4050,10 @@ static void handle_get_folder_items_response(tBTA_AV_META_MSG* pmeta_msg, for (uint8_t i = 0; i < item_count; i++) { const tAVRC_ITEM* avrc_item = &(p_rsp->p_item_list[i]); btrc_folder_items_t* btrc_item = &(btrc_items[i]); - BTIF_TRACE_DEBUG("%s folder item type %d", __func__, - avrc_item->item_type); + LOG_VERBOSE("%s folder item type %d", __func__, avrc_item->item_type); switch (avrc_item->item_type) { case AVRC_ITEM_MEDIA: - BTIF_TRACE_DEBUG("%s setting type to %d", __func__, BTRC_ITEM_MEDIA); + LOG_VERBOSE("%s setting type to %d", __func__, BTRC_ITEM_MEDIA); /* Allocate Space for Attributes */ btrc_item->media.num_attrs = avrc_item->u.media.attr_count; btrc_item->media.p_attrs = (btrc_element_attr_val_t*)osi_malloc( @@ -3877,27 +4062,27 @@ static void handle_get_folder_items_response(tBTA_AV_META_MSG* pmeta_msg, break; case AVRC_ITEM_FOLDER: - BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_FOLDER", __func__); + LOG_VERBOSE("%s setting type to BTRC_ITEM_FOLDER", __func__); get_folder_item_type_folder(avrc_item, btrc_item); break; case AVRC_ITEM_PLAYER: - BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_PLAYER", __func__); + LOG_VERBOSE("%s setting type to BTRC_ITEM_PLAYER", __func__); get_folder_item_type_player(avrc_item, btrc_item); break; default: - BTIF_TRACE_ERROR("%s cannot understand folder item type %d", __func__, - avrc_item->item_type); + LOG_ERROR("%s cannot understand folder item type %d", __func__, + avrc_item->item_type); } } do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->get_folder_items_cb, p_dev->rc_addr, - BTRC_STS_NO_ERROR, - /* We want to make the ownership explicit in native */ - btrc_items, item_count)); + base::BindOnce(bt_rc_ctrl_callbacks->get_folder_items_cb, + p_dev->rc_addr, BTRC_STS_NO_ERROR, + /* We want to make the ownership explicit in native */ + btrc_items, item_count)); if (item_count > 0) { if (btrc_items[0].item_type == AVRC_ITEM_PLAYER && @@ -3908,16 +4093,16 @@ static void handle_get_folder_items_response(tBTA_AV_META_MSG* pmeta_msg, /* Release the memory block for items and attributes allocated here. * Since the executor for do_in_jni_thread is a Single Thread Task Runner it * is okay to queue up the cleanup of btrc_items */ - do_in_jni_thread(FROM_HERE, base::Bind(cleanup_btrc_folder_items, - btrc_items, item_count)); + do_in_jni_thread(FROM_HERE, base::BindOnce(cleanup_btrc_folder_items, + btrc_items, item_count)); - BTIF_TRACE_DEBUG("%s get_folder_items_cb sent to JNI thread", __func__); + LOG_VERBOSE("%s get_folder_items_cb sent to JNI thread", __func__); } else { - BTIF_TRACE_ERROR("%s: Error %d", __func__, p_rsp->status); + LOG_ERROR("%s: Error %d", __func__, p_rsp->status); do_in_jni_thread( - FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->get_folder_items_cb, p_dev->rc_addr, - (btrc_status_t)p_rsp->status, nullptr, 0)); + FROM_HERE, base::BindOnce(bt_rc_ctrl_callbacks->get_folder_items_cb, + p_dev->rc_addr, (btrc_status_t)p_rsp->status, + nullptr, 0)); } } /*************************************************************************** @@ -3941,7 +4126,7 @@ static void cleanup_btrc_folder_items(btrc_folder_items_t* btrc_items, /*Nothing to free*/ break; default: - BTIF_TRACE_WARNING("%s free unspecified type", __func__); + LOG_WARN("%s free unspecified type", __func__); } } osi_free(btrc_items); @@ -3980,8 +4165,8 @@ void get_folder_item_type_media(const tAVRC_ITEM* avrc_item, btrc_item_media->charset_id = avrc_item_media->name.charset_id; /* Copy the name */ - BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN, - avrc_item_media->name.str_len); + LOG_VERBOSE("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN, + avrc_item_media->name.str_len); memset(btrc_item_media->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t)); memcpy(btrc_item_media->name, avrc_item_media->name.p_str, sizeof(uint8_t) * (avrc_item_media->name.str_len)); @@ -3991,8 +4176,7 @@ void get_folder_item_type_media(const tAVRC_ITEM* avrc_item, btrc_element_attr_val_t* btrc_attr_pair = &(btrc_item_media->p_attrs[i]); tAVRC_ATTR_ENTRY* avrc_attr_pair = &(avrc_item_media->p_attr_list[i]); - BTIF_TRACE_DEBUG("%s media attr id 0x%x", __func__, - avrc_attr_pair->attr_id); + LOG_VERBOSE("%s media attr id 0x%x", __func__, avrc_attr_pair->attr_id); switch (avrc_attr_pair->attr_id) { case AVRC_MEDIA_ATTR_ID_TITLE: @@ -4020,8 +4204,8 @@ void get_folder_item_type_media(const tAVRC_ITEM* avrc_item, btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_COVER_ARTWORK_HANDLE; break; default: - BTIF_TRACE_ERROR("%s invalid media attr id: 0x%x", __func__, - avrc_attr_pair->attr_id); + LOG_ERROR("%s invalid media attr id: 0x%x", __func__, + avrc_attr_pair->attr_id); btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_INVALID; } @@ -4079,8 +4263,8 @@ void get_folder_item_type_folder(const tAVRC_ITEM* avrc_item, btrc_item_folder->playable = avrc_item_folder->playable; /* Copy name */ - BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN, - avrc_item_folder->name.str_len); + LOG_VERBOSE("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN, + avrc_item_folder->name.str_len); memset(btrc_item_folder->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t)); memcpy(btrc_item_folder->name, avrc_item_folder->name.p_str, avrc_item_folder->name.str_len * sizeof(uint8_t)); @@ -4135,17 +4319,17 @@ static void handle_change_path_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: Invalid rc handle", __func__); + LOG_ERROR("%s: Invalid rc handle", __func__); return; } if (p_rsp->status == AVRC_STS_NO_ERROR) { do_in_jni_thread(FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->change_folder_path_cb, - p_dev->rc_addr, p_rsp->num_items)); + base::BindOnce(bt_rc_ctrl_callbacks->change_folder_path_cb, + p_dev->rc_addr, p_rsp->num_items)); } else { - BTIF_TRACE_ERROR("%s error in handle_change_path_response %d", __func__, - p_rsp->status); + LOG_ERROR("%s error in handle_change_path_response %d", __func__, + p_rsp->status); } } @@ -4164,17 +4348,17 @@ static void handle_set_browsed_player_response(tBTA_AV_META_MSG* pmeta_msg, btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: Invalid rc handle", __func__); + LOG_ERROR("%s: Invalid rc handle", __func__); return; } if (p_rsp->status == AVRC_STS_NO_ERROR) { do_in_jni_thread( FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->set_browsed_player_cb, p_dev->rc_addr, - p_rsp->num_items, p_rsp->folder_depth)); + base::BindOnce(bt_rc_ctrl_callbacks->set_browsed_player_cb, + p_dev->rc_addr, p_rsp->num_items, p_rsp->folder_depth)); } else { - BTIF_TRACE_ERROR("%s error %d", __func__, p_rsp->status); + LOG_ERROR("%s error %d", __func__, p_rsp->status); } } @@ -4191,7 +4375,7 @@ static void clear_cmd_timeout(btif_rc_device_cb_t* p_dev, uint8_t label) { p_txn = get_transaction_by_lbl(p_dev, label); if (p_txn == NULL) { - BTIF_TRACE_ERROR("%s: Error in transaction label lookup", __func__); + LOG_ERROR("%s: Error in transaction label lookup", __func__); return; } @@ -4218,8 +4402,8 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) { tAVRC_STS status; btif_rc_device_cb_t* p_dev = NULL; - BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d ", __func__, - pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code); + LOG_VERBOSE("%s: opcode: %d rsp_code: %d ", __func__, + pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code); p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle); status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, @@ -4227,9 +4411,8 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) { if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode) && (pmeta_msg->code >= AVRC_RSP_NOT_IMPL) && (pmeta_msg->code <= AVRC_RSP_INTERIM)) { - BTIF_TRACE_DEBUG("%s parse status %d pdu = %d rsp_status = %d", __func__, - status, avrc_response.pdu, - pmeta_msg->p_msg->vendor.hdr.ctype); + LOG_VERBOSE("%s parse status %d pdu = %d rsp_status = %d", __func__, status, + avrc_response.pdu, pmeta_msg->p_msg->vendor.hdr.ctype); switch (avrc_response.pdu) { case AVRC_PDU_REGISTER_NOTIFICATION: @@ -4285,7 +4468,7 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) { break; } } else if (AVRC_OP_BROWSE == pmeta_msg->p_msg->hdr.opcode) { - BTIF_TRACE_DEBUG("%s AVRC_OP_BROWSE pdu %d", __func__, avrc_response.pdu); + LOG_VERBOSE("%s AVRC_OP_BROWSE pdu %d", __func__, avrc_response.pdu); /* check what kind of command it is for browsing */ switch (avrc_response.pdu) { case AVRC_PDU_GET_FOLDER_ITEMS: @@ -4301,16 +4484,16 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) { handle_get_metadata_attr_response(pmeta_msg, &avrc_response.get_attrs); break; default: - BTIF_TRACE_ERROR("%s cannot handle browse pdu %d", __func__, - pmeta_msg->p_msg->hdr.opcode); + LOG_ERROR("%s cannot handle browse pdu %d", __func__, + pmeta_msg->p_msg->hdr.opcode); } } else { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Invalid Vendor Command code: %d len: %d. Not processing it.", __func__, pmeta_msg->code, pmeta_msg->len); return; } - BTIF_TRACE_DEBUG("%s: release transaction %d", __func__, pmeta_msg->label); + LOG_VERBOSE("%s: release transaction %d", __func__, pmeta_msg->label); release_transaction(p_dev, pmeta_msg->label); } @@ -4328,42 +4511,48 @@ static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { tAVRC_STS status = BT_STATUS_UNSUPPORTED; btif_rc_device_cb_t* p_dev = NULL; - BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d", __func__, - pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code); + LOG_VERBOSE("%s: opcode: %d rsp_code: %d", __func__, + pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code); status = AVRC_Ctrl_ParsCommand(pmeta_msg->p_msg, &avrc_cmd); if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode) && (pmeta_msg->code <= AVRC_CMD_GEN_INQ)) { - BTIF_TRACE_DEBUG("%s Received vendor command.code %d, PDU %d label %d", - __func__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label); + LOG_VERBOSE("%s Received vendor command.code %d, PDU %d label %d", __func__, + pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label); if (status != AVRC_STS_NO_ERROR) { /* return error */ - BTIF_TRACE_WARNING( - "%s: Error in parsing received metamsg command. status: 0x%02x", - __func__, status); + LOG_WARN("%s: Error in parsing received metamsg command. status: 0x%02x", + __func__, status); + if (true == btif_av_both_enable()) { + if (AVRC_PDU_GET_CAPABILITIES == avrc_cmd.pdu || + AVRC_PDU_GET_ELEMENT_ATTR == avrc_cmd.pdu || + AVRC_PDU_GET_PLAY_STATUS == avrc_cmd.pdu || + AVRC_PDU_GET_FOLDER_ITEMS == avrc_cmd.pdu || + AVRC_PDU_GET_ITEM_ATTRIBUTES == avrc_cmd.pdu) + return; + } send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_cmd.pdu, status, pmeta_msg->p_msg->hdr.opcode); } else { p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: avk rc meta msg cmd for Invalid rc handle", - __func__); + LOG_ERROR("%s: avk rc meta msg cmd for Invalid rc handle", __func__); return; } if (avrc_cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION) { uint8_t event_id = avrc_cmd.reg_notif.event_id; - BTIF_TRACE_EVENT("%s: Register notification event_id: %s", __func__, - dump_rc_notification_event_id(event_id)); + LOG_VERBOSE("%s: Register notification event_id: %s", __func__, + dump_rc_notification_event_id(event_id)); } else if (avrc_cmd.pdu == AVRC_PDU_SET_ABSOLUTE_VOLUME) { - BTIF_TRACE_EVENT("%s: Abs Volume Cmd Recvd", __func__); + LOG_VERBOSE("%s: Abs Volume Cmd Recvd", __func__); } btif_rc_ctrl_upstreams_rsp_cmd(avrc_cmd.pdu, &avrc_cmd, pmeta_msg->label, p_dev); } } else { - BTIF_TRACE_DEBUG( + LOG_VERBOSE( "%s: Invalid Vendor Command code: %d len: %d. Not processing it.", __func__, pmeta_msg->code, pmeta_msg->len); return; @@ -4380,7 +4569,7 @@ static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { * **************************************************************************/ static void cleanup() { - BTIF_TRACE_EVENT("%s: ", __func__); + LOG_VERBOSE("%s: ", __func__); if (bt_rc_callbacks) { bt_rc_callbacks = NULL; } @@ -4391,7 +4580,7 @@ static void cleanup() { sizeof(btif_rc_cb.rc_multi_cb[idx])); } - BTIF_TRACE_EVENT("%s: completed", __func__); + LOG_VERBOSE("%s: completed", __func__); } /*************************************************************************** @@ -4404,7 +4593,7 @@ static void cleanup() { * **************************************************************************/ static void cleanup_ctrl() { - BTIF_TRACE_EVENT("%s: ", __func__); + LOG_VERBOSE("%s: ", __func__); if (bt_rc_ctrl_callbacks) { bt_rc_ctrl_callbacks = NULL; @@ -4417,7 +4606,7 @@ static void cleanup_ctrl() { } memset(&btif_rc_cb.rc_multi_cb, 0, sizeof(btif_rc_cb.rc_multi_cb)); - BTIF_TRACE_EVENT("%s: completed", __func__); + LOG_VERBOSE("%s: completed", __func__); } /*************************************************************************** @@ -4431,7 +4620,7 @@ static void cleanup_ctrl() { **************************************************************************/ static bt_status_t getcapabilities_cmd(uint8_t cap_id, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: cap_id: %d", __func__, cap_id); + LOG_VERBOSE("%s: cap_id: %d", __func__, cap_id); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; @@ -4454,7 +4643,7 @@ static bt_status_t getcapabilities_cmd(uint8_t cap_id, **************************************************************************/ static bt_status_t list_player_app_setting_attrib_cmd( btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; @@ -4476,7 +4665,7 @@ static bt_status_t list_player_app_setting_attrib_cmd( **************************************************************************/ static bt_status_t list_player_app_setting_value_cmd( uint8_t attrib_id, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: attrib_id: %d", __func__, attrib_id); + LOG_VERBOSE("%s: attrib_id: %d", __func__, attrib_id); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; @@ -4500,7 +4689,7 @@ static bt_status_t list_player_app_setting_value_cmd( static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: num_attrib: %d", __func__, num_attrib); + LOG_VERBOSE("%s: num_attrib: %d", __func__, num_attrib); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; @@ -4527,10 +4716,10 @@ static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, * **************************************************************************/ static bt_status_t get_current_metadata_cmd(const RawAddress& bd_addr) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return BT_STATUS_FAIL; } const uint32_t* attr_list = get_requested_attributes_list(p_dev); @@ -4549,7 +4738,7 @@ static bt_status_t get_current_metadata_cmd(const RawAddress& bd_addr) { * **************************************************************************/ static bt_status_t get_playback_state_cmd(const RawAddress& bd_addr) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); return get_play_status_cmd(p_dev); } @@ -4570,7 +4759,7 @@ static bt_status_t get_playback_state_cmd(const RawAddress& bd_addr) { static bt_status_t get_now_playing_list_cmd(const RawAddress& bd_addr, uint32_t start_item, uint32_t end_item) { - BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, end_item); + LOG_VERBOSE("%s start, end: (%d, %d)", __func__, start_item, end_item); return get_folder_items_cmd(bd_addr, AVRC_SCOPE_NOW_PLAYING, start_item, end_item); } @@ -4619,7 +4808,7 @@ static bt_status_t get_item_attribute_cmd(uint64_t uid, int scope, **************************************************************************/ static bt_status_t get_folder_list_cmd(const RawAddress& bd_addr, uint32_t start_item, uint32_t end_item) { - BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, end_item); + LOG_VERBOSE("%s start, end: (%d, %d)", __func__, start_item, end_item); return get_folder_items_cmd(bd_addr, AVRC_SCOPE_FILE_SYSTEM, start_item, end_item); } @@ -4639,7 +4828,7 @@ static bt_status_t get_folder_list_cmd(const RawAddress& bd_addr, **************************************************************************/ static bt_status_t get_player_list_cmd(const RawAddress& bd_addr, uint32_t start_item, uint32_t end_item) { - BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, end_item); + LOG_VERBOSE("%s start, end: (%d, %d)", __func__, start_item, end_item); return get_folder_items_cmd(bd_addr, AVRC_SCOPE_PLAYER_LIST, start_item, end_item); } @@ -4661,7 +4850,7 @@ static bt_status_t get_player_list_cmd(const RawAddress& bd_addr, **************************************************************************/ static bt_status_t change_folder_path_cmd(const RawAddress& bd_addr, uint8_t direction, uint8_t* uid) { - BTIF_TRACE_DEBUG("%s: direction %d", __func__, direction); + LOG_VERBOSE("%s: direction %d", __func__, direction); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); CHECK_RC_CONNECTED(p_dev); CHECK_BR_CONNECTED(p_dev); @@ -4694,7 +4883,7 @@ static bt_status_t change_folder_path_cmd(const RawAddress& bd_addr, **************************************************************************/ static bt_status_t set_browsed_player_cmd(const RawAddress& bd_addr, uint16_t id) { - BTIF_TRACE_DEBUG("%s: id %d", __func__, id); + LOG_VERBOSE("%s: id %d", __func__, id); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); CHECK_RC_CONNECTED(p_dev); CHECK_BR_CONNECTED(p_dev); @@ -4722,7 +4911,7 @@ static bt_status_t set_browsed_player_cmd(const RawAddress& bd_addr, ***************************************************************************/ static bt_status_t set_addressed_player_cmd(const RawAddress& bd_addr, uint16_t id) { - BTIF_TRACE_DEBUG("%s: id %d", __func__, id); + LOG_VERBOSE("%s: id %d", __func__, id); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); CHECK_RC_CONNECTED(p_dev); @@ -4758,7 +4947,7 @@ static bt_status_t get_folder_items_cmd(const RawAddress& bd_addr, uint32_t end_item) { /* Check that both avrcp and browse channel are connected. */ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); CHECK_BR_CONNECTED(p_dev); @@ -4790,7 +4979,7 @@ static bt_status_t change_player_app_setting(const RawAddress& bd_addr, uint8_t num_attrib, uint8_t* attrib_ids, uint8_t* attrib_vals) { - BTIF_TRACE_DEBUG("%s: num_attrib: %d", __func__, num_attrib); + LOG_VERBOSE("%s: num_attrib: %d", __func__, num_attrib); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); CHECK_RC_CONNECTED(p_dev); @@ -4822,7 +5011,7 @@ static bt_status_t change_player_app_setting(const RawAddress& bd_addr, **************************************************************************/ static bt_status_t play_item_cmd(const RawAddress& bd_addr, uint8_t scope, uint8_t* uid, uint16_t uid_counter) { - BTIF_TRACE_DEBUG("%s: scope %d uid_counter %d", __func__, scope, uid_counter); + LOG_VERBOSE("%s: scope %d uid_counter %d", __func__, scope, uid_counter); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); CHECK_RC_CONNECTED(p_dev); CHECK_BR_CONNECTED(p_dev); @@ -4849,7 +5038,7 @@ static bt_status_t play_item_cmd(const RawAddress& bd_addr, uint8_t scope, **************************************************************************/ static bt_status_t get_player_app_setting_attr_text_cmd( uint8_t* attrs, uint8_t num_attrs, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: num attrs: %d", __func__, num_attrs); + LOG_VERBOSE("%s: num attrs: %d", __func__, num_attrs); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; @@ -4875,7 +5064,7 @@ static bt_status_t get_player_app_setting_attr_text_cmd( **************************************************************************/ static bt_status_t get_player_app_setting_value_text_cmd( uint8_t* vals, uint8_t num_vals, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: num_vals: %d", __func__, num_vals); + LOG_VERBOSE("%s: num_vals: %d", __func__, num_vals); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; @@ -4902,8 +5091,8 @@ static bt_status_t get_player_app_setting_value_text_cmd( static bt_status_t register_notification_cmd(uint8_t event_id, uint32_t event_value, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: event_id: %d event_value %d", __func__, event_id, - event_value); + LOG_VERBOSE("%s: event_id: %d event_value %d", __func__, event_id, + event_value); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; @@ -4931,8 +5120,8 @@ static bt_status_t register_notification_cmd(uint8_t event_id, static bt_status_t get_metadata_attribute_cmd(uint8_t num_attribute, const uint32_t* p_attr_ids, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: num_attribute: %d attribute_id: %d", __func__, - num_attribute, p_attr_ids[0]); + LOG_VERBOSE("%s: num_attribute: %d attribute_id: %d", __func__, num_attribute, + p_attr_ids[0]); // If browsing is connected then send the command out that channel if (p_dev->br_connected) { @@ -4957,8 +5146,8 @@ static bt_status_t get_metadata_attribute_cmd(uint8_t num_attribute, static bt_status_t get_element_attribute_cmd(uint8_t num_attribute, const uint32_t* p_attr_ids, btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s: num_attribute: %d attribute_id: %d", __func__, - num_attribute, p_attr_ids[0]); + LOG_VERBOSE("%s: num_attribute: %d attribute_id: %d", __func__, num_attribute, + p_attr_ids[0]); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; avrc_cmd.get_elem_attrs.opcode = AVRC_OP_VENDOR; @@ -4982,7 +5171,7 @@ static bt_status_t get_element_attribute_cmd(uint8_t num_attribute, * **************************************************************************/ static bt_status_t get_play_status_cmd(btif_rc_device_cb_t* p_dev) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); CHECK_RC_CONNECTED(p_dev); tAVRC_COMMAND avrc_cmd = {0}; @@ -5011,7 +5200,7 @@ static bt_status_t set_volume_rsp(const RawAddress& bd_addr, uint8_t abs_vol, CHECK_RC_CONNECTED(p_dev); - BTIF_TRACE_DEBUG("%s: abs_vol: %d", __func__, abs_vol); + LOG_VERBOSE("%s: abs_vol: %d", __func__, abs_vol); avrc_rsp.volume.opcode = AVRC_OP_VENDOR; avrc_rsp.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME; @@ -5020,16 +5209,15 @@ static bt_status_t set_volume_rsp(const RawAddress& bd_addr, uint8_t abs_vol, status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg); if (status == AVRC_STS_NO_ERROR) { uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset; - BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__, - p_dev->rc_vol_label); + LOG_VERBOSE("%s: msgreq being sent out with label: %d", __func__, + p_dev->rc_vol_label); if (p_msg != NULL) { BTA_AvVendorRsp(p_dev->rc_handle, label, AVRC_RSP_ACCEPT, data_start, p_msg->len, 0); status = BT_STATUS_SUCCESS; } } else { - BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__, - status); + LOG_ERROR("%s: failed to build command. status: 0x%02x", __func__, status); } osi_free(p_msg); return (bt_status_t)status; @@ -5050,7 +5238,7 @@ static bt_status_t volume_change_notification_rsp( tAVRC_STS status = BT_STATUS_UNSUPPORTED; tAVRC_RESPONSE avrc_rsp; BT_HDR* p_msg = NULL; - BTIF_TRACE_DEBUG("%s: rsp_type: %d abs_vol: %d", __func__, rsp_type, abs_vol); + LOG_VERBOSE("%s: rsp_type: %d abs_vol: %d", __func__, rsp_type, abs_vol); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); @@ -5064,8 +5252,7 @@ static bt_status_t volume_change_notification_rsp( status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg); if (status == AVRC_STS_NO_ERROR) { - BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__, - label); + LOG_VERBOSE("%s: msgreq being sent out with label: %d", __func__, label); uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset; BTA_AvVendorRsp(p_dev->rc_handle, label, (rsp_type == BTRC_NOTIFICATION_TYPE_INTERIM) @@ -5074,8 +5261,7 @@ static bt_status_t volume_change_notification_rsp( data_start, p_msg->len, 0); status = BT_STATUS_SUCCESS; } else { - BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__, - status); + LOG_ERROR("%s: failed to build command. status: 0x%02x", __func__, status); } osi_free(p_msg); @@ -5096,8 +5282,7 @@ static bt_status_t send_groupnavigation_cmd(const RawAddress& bd_addr, uint8_t key_state) { tAVRC_STS status = BT_STATUS_UNSUPPORTED; rc_transaction_t* p_transaction = NULL; - BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__, key_code, - key_state); + LOG_VERBOSE("%s: key-code: %d, key-state: %d", __func__, key_code, key_state); btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr); CHECK_RC_CONNECTED(p_dev); @@ -5120,17 +5305,16 @@ static bt_status_t send_groupnavigation_cmd(const RawAddress& bd_addr, AVRC_PASS_THRU_GROUP_LEN); status = BT_STATUS_SUCCESS; start_transaction_timer(p_dev, p_transaction->label, BTIF_RC_TIMEOUT_MS); - BTIF_TRACE_DEBUG("%s: Send command, key-code=%d, key-state=%d, label=%d", - __func__, key_code, key_state, p_transaction->label); + LOG_VERBOSE("%s: Send command, key-code=%d, key-state=%d, label=%d", + __func__, key_code, key_state, p_transaction->label); } else { status = BT_STATUS_FAIL; - BTIF_TRACE_ERROR( - "%s: failed to get label, key-code=%d, key-state=%d, status=%d", - __func__, key_code, key_state, tran_status); + LOG_ERROR("%s: failed to get label, key-code=%d, key-state=%d, status=%d", + __func__, key_code, key_state, tran_status); } } else { status = BT_STATUS_FAIL; - BTIF_TRACE_DEBUG("%s: feature not supported", __func__); + LOG_VERBOSE("%s: feature not supported", __func__); } return (bt_status_t)status; } @@ -5148,14 +5332,13 @@ static bt_status_t send_passthrough_cmd(const RawAddress& bd_addr, uint8_t key_code, uint8_t key_state) { tAVRC_STS status = BT_STATUS_UNSUPPORTED; btif_rc_device_cb_t* p_dev = NULL; - BTIF_TRACE_ERROR("%s: calling btif_rc_get_device_by_bda", __func__); + LOG_ERROR("%s: calling btif_rc_get_device_by_bda", __func__); p_dev = btif_rc_get_device_by_bda(bd_addr); CHECK_RC_CONNECTED(p_dev); rc_transaction_t* p_transaction = NULL; - BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__, key_code, - key_state); + LOG_VERBOSE("%s: key-code: %d, key-state: %d", __func__, key_code, key_state); if (p_dev->rc_features & BTA_AV_FEAT_RCTG) { rc_transaction_context_t context = { .rc_addr = p_dev->rc_addr, @@ -5168,17 +5351,16 @@ static bt_status_t send_passthrough_cmd(const RawAddress& bd_addr, (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state); status = BT_STATUS_SUCCESS; start_transaction_timer(p_dev, p_transaction->label, BTIF_RC_TIMEOUT_MS); - BTIF_TRACE_DEBUG("%s: Send command, key-code=%d, key-state=%d, label=%d", - __func__, key_code, key_state, p_transaction->label); + LOG_VERBOSE("%s: Send command, key-code=%d, key-state=%d, label=%d", + __func__, key_code, key_state, p_transaction->label); } else { status = BT_STATUS_FAIL; - BTIF_TRACE_ERROR( - "%s: failed to get label, key-code=%d, key-state=%d, status=%d", - __func__, key_code, key_state, tran_status); + LOG_ERROR("%s: failed to get label, key-code=%d, key-state=%d, status=%d", + __func__, key_code, key_state, tran_status); } } else { status = BT_STATUS_FAIL; - BTIF_TRACE_DEBUG("%s: feature not supported", __func__); + LOG_VERBOSE("%s: feature not supported", __func__); } return (bt_status_t)status; } @@ -5238,7 +5420,7 @@ static const btrc_ctrl_interface_t bt_rc_ctrl_interface = { * ******************************************************************************/ const btrc_interface_t* btif_rc_get_interface(void) { - BTIF_TRACE_EVENT("%s: ", __func__); + LOG_VERBOSE("%s: ", __func__); return &bt_rc_interface; } @@ -5252,7 +5434,7 @@ const btrc_interface_t* btif_rc_get_interface(void) { * ******************************************************************************/ const btrc_ctrl_interface_t* btif_rc_ctrl_get_interface(void) { - BTIF_TRACE_EVENT("%s: ", __func__); + LOG_VERBOSE("%s: ", __func__); return &bt_rc_ctrl_interface; } @@ -5272,8 +5454,8 @@ static void initialize_transaction(btif_rc_device_cb_t* p_dev, uint8_t lbl) { clear_cmd_timeout(p_dev, lbl); } transaction_set->transaction[lbl] = { - .label = lbl, .in_use = false, + .label = lbl, .context = { .label = MAX_LABEL, @@ -5350,13 +5532,13 @@ static bt_status_t get_transaction(btif_rc_device_cb_t* p_dev, transaction_set->transaction[i].context = context; transaction_set->transaction[i].in_use = true; *ptransaction = &(transaction_set->transaction[i]); - BTIF_TRACE_DEBUG("%s: Assigned transaction=%s", __func__, - dump_transaction(*ptransaction).c_str()); + LOG_VERBOSE("%s: Assigned transaction=%s", __func__, + dump_transaction(*ptransaction).c_str()); return BT_STATUS_SUCCESS; } } - BTIF_TRACE_ERROR("%s: p_dev=%s, failed to find free transaction", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr)); + LOG_ERROR("%s: p_dev=%s, failed to find free transaction", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr)); return BT_STATUS_NOMEM; } @@ -5374,13 +5556,12 @@ static void start_transaction_timer(btif_rc_device_cb_t* p_dev, uint8_t label, uint64_t timeout_ms) { rc_transaction_t* transaction = get_transaction_by_lbl(p_dev, label); if (transaction == nullptr) { - BTIF_TRACE_ERROR("%s: transaction is null", __func__); + LOG_ERROR("%s: transaction is null", __func__); return; } if (alarm_is_scheduled(transaction->timer)) { - BTIF_TRACE_WARNING("%s: Restarting timer that's already scheduled", - __func__); + LOG_WARN("%s: Restarting timer that's already scheduled", __func__); } std::stringstream ss; @@ -5401,9 +5582,9 @@ static void start_transaction_timer(btif_rc_device_cb_t* p_dev, uint8_t label, * Returns bt_status_t ******************************************************************************/ void release_transaction(btif_rc_device_cb_t* p_dev, uint8_t lbl) { - BTIF_TRACE_DEBUG( - "%s: p_dev=%s, label=%d", __func__, - p_dev == NULL ? "null" : ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr), lbl); + LOG_VERBOSE("%s: p_dev=%s, label=%d", __func__, + p_dev == NULL ? "null" : ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr), + lbl); if (p_dev == nullptr) return; rc_transaction_set_t* transaction_set = &(p_dev->transaction_set); @@ -5476,17 +5657,17 @@ static void vendor_cmd_timeout_handler(btif_rc_device_cb_t* p_dev, uint8_t label, rc_vendor_context_t* p_context) { if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } tAVRC_RESPONSE avrc_response = {0}; tBTA_AV_META_MSG meta_msg = {.rc_handle = p_dev->rc_handle}; - BTIF_TRACE_WARNING("%s: timeout, addr=%s, label=%d, pdu_id=%s, event_id=%s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr), label, - dump_rc_pdu(p_context->pdu_id), - dump_rc_notification_event_id(p_context->event_id)); + LOG_WARN("%s: timeout, addr=%s, label=%d, pdu_id=%s, event_id=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr), label, + dump_rc_pdu(p_context->pdu_id), + dump_rc_notification_event_id(p_context->event_id)); switch (p_context->pdu_id) { case AVRC_PDU_REGISTER_NOTIFICATION: @@ -5543,8 +5724,8 @@ static void vendor_cmd_timeout_handler(btif_rc_device_cb_t* p_dev, break; default: - BTIF_TRACE_WARNING("%s: timeout for unknown pdu_id=%d", __func__, - p_context->pdu_id); + LOG_WARN("%s: timeout for unknown pdu_id=%d", __func__, + p_context->pdu_id); break; } } @@ -5561,16 +5742,24 @@ static void browse_cmd_timeout_handler(btif_rc_device_cb_t* p_dev, uint8_t label, rc_browse_context_t* p_context) { if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } tAVRC_RESPONSE avrc_response = {0}; - tBTA_AV_META_MSG meta_msg = {.rc_handle = p_dev->rc_handle}; - - BTIF_TRACE_WARNING("%s: timeout, addr=%s, label=%d, pdu_id=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr), label, - dump_rc_pdu(p_context->pdu_id)); + tBTA_AV_META_MSG meta_msg = { + .rc_handle = p_dev->rc_handle, + .len = 0, + .label = 0, + .code = 0, + .company_id = 0, + .p_data = nullptr, + .p_msg = nullptr, + }; + + LOG_WARN("%s: timeout, addr=%s, label=%d, pdu_id=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr), label, + dump_rc_pdu(p_context->pdu_id)); switch (p_context->pdu_id) { case AVRC_PDU_GET_FOLDER_ITEMS: @@ -5590,8 +5779,8 @@ static void browse_cmd_timeout_handler(btif_rc_device_cb_t* p_dev, handle_get_metadata_attr_response(&meta_msg, &avrc_response.get_attrs); break; default: - BTIF_TRACE_WARNING("%s: timeout for unknown pdu_id=%d", __func__, - p_context->pdu_id); + LOG_WARN("%s: timeout for unknown pdu_id=%d", __func__, + p_context->pdu_id); break; } } @@ -5608,13 +5797,13 @@ static void passthru_cmd_timeout_handler(btif_rc_device_cb_t* p_dev, uint8_t label, rc_passthru_context_t* p_context) { if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + LOG_ERROR("%s: p_dev NULL", __func__); return; } - BTIF_TRACE_WARNING("%s: timeout, addr=%s, label=%d, rc_id=%d, key_state=%d", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr), label, - p_context->rc_id, p_context->key_state); + LOG_WARN("%s: timeout, addr=%s, label=%d, rc_id=%d, key_state=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr), label, p_context->rc_id, + p_context->key_state); // Other requests are wrapped in a tAVRC_RESPONSE response object, but these // passthru events are not in there. As well, the upper layers don't handle @@ -5635,13 +5824,13 @@ static void btif_rc_transaction_timeout_handler(UNUSED_ATTR uint16_t event, char* data) { rc_transaction_context_t* p_context = (rc_transaction_context_t*)data; if (p_context == nullptr) { - BTIF_TRACE_ERROR("%s: p_context is null", __func__); + LOG_ERROR("%s: p_context is null", __func__); return; } btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(p_context->rc_addr); if (p_dev == NULL) { - BTIF_TRACE_ERROR("%s: p_dev is null", __func__); + LOG_ERROR("%s: p_dev is null", __func__); return; } @@ -5658,8 +5847,8 @@ static void btif_rc_transaction_timeout_handler(UNUSED_ATTR uint16_t event, &(p_context->command.passthru)); break; default: - BTIF_TRACE_WARNING("%s: received timeout for unknown opcode=", __func__, - p_context->opcode); + LOG_WARN("%s: received timeout for unknown opcode=%d", __func__, + p_context->opcode); return; } release_transaction(p_dev, label); @@ -5737,7 +5926,7 @@ static bool absolute_volume_disabled() { char volume_disabled[PROPERTY_VALUE_MAX] = {0}; osi_property_get("persist.bluetooth.disableabsvol", volume_disabled, "false"); if (strncmp(volume_disabled, "true", 4) == 0) { - BTIF_TRACE_WARNING("%s: Absolute volume disabled by property", __func__); + LOG_WARN("%s: Absolute volume disabled by property", __func__); return true; } return false; diff --git a/system/btif/src/btif_sdp.cc b/system/btif/src/btif_sdp.cc index 0be8f217b1151e414be3a769be49bbe644daaf0a..0169a7f22c63da11c1f879bf50f421f6c93bc605 100644 --- a/system/btif/src/btif_sdp.cc +++ b/system/btif/src/btif_sdp.cc @@ -33,11 +33,9 @@ #include #include +#include "bta/include/bta_sdp_api.h" #include "bta_api.h" -#include "bta_sdp_api.h" #include "btif_common.h" -#include "btif_profile_queue.h" -#include "btif_util.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -67,7 +65,7 @@ static btsdp_callbacks_t* bt_sdp_callbacks = NULL; static void btif_sdp_search_comp_evt(uint16_t event, char* p_param) { tBTA_SDP_SEARCH_COMP* evt_data = (tBTA_SDP_SEARCH_COMP*)p_param; - BTIF_TRACE_DEBUG("%s: event = %d", __func__, event); + LOG_VERBOSE("%s: event = %d", __func__, event); if (event != BTA_SDP_SEARCH_COMP_EVT) return; @@ -118,7 +116,7 @@ static void sdp_dm_cback(tBTA_SDP_EVT event, tBTA_SDP* p_data, } static bt_status_t init(btsdp_callbacks_t* callbacks) { - BTIF_TRACE_DEBUG("Sdp Search %s", __func__); + LOG_VERBOSE("Sdp Search %s", __func__); bt_sdp_callbacks = callbacks; sdp_server_init(); @@ -129,7 +127,7 @@ static bt_status_t init(btsdp_callbacks_t* callbacks) { } static bt_status_t deinit() { - BTIF_TRACE_DEBUG("Sdp Search %s", __func__); + LOG_VERBOSE("Sdp Search %s", __func__); bt_sdp_callbacks = NULL; sdp_server_cleanup(); @@ -148,7 +146,7 @@ static const btsdp_interface_t sdp_if = { remove_sdp_record}; const btsdp_interface_t* btif_sdp_get_interface(void) { - BTIF_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); return &sdp_if; } @@ -162,7 +160,7 @@ const btsdp_interface_t* btif_sdp_get_interface(void) { * ******************************************************************************/ bt_status_t btif_sdp_execute_service(bool b_enable) { - BTIF_TRACE_DEBUG("%s enable:%d", __func__, b_enable); + LOG_VERBOSE("%s enable:%d", __func__, b_enable); if (b_enable) { BTA_SdpEnable(sdp_dm_cback); diff --git a/system/btif/src/btif_sdp_server.cc b/system/btif/src/btif_sdp_server.cc index 0a24d54f969ffb1077c1a8d9ec81f2ba24d69c53..e861aeb595e9c387ab1085b0f19b6fece305f82f 100644 --- a/system/btif/src/btif_sdp_server.cc +++ b/system/btif/src/btif_sdp_server.cc @@ -36,13 +36,13 @@ #include -#include "bta_sdp_api.h" -#include "bta_sys.h" +#include "bta/include/bta_sdp_api.h" +#include "bta/sys/bta_sys.h" #include "btif_common.h" #include "btif_sock_sdp.h" -#include "btif_sock_util.h" -#include "btif_util.h" #include "osi/include/allocator.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/sdp_api.h" #include "stack/sdp/sdpint.h" #include "types/bluetooth/uuid.h" @@ -108,13 +108,13 @@ static void init_sdp_slots() { } bt_status_t sdp_server_init() { - BTIF_TRACE_DEBUG("Sdp Server %s", __func__); + LOG_VERBOSE("Sdp Server %s", __func__); init_sdp_slots(); return BT_STATUS_SUCCESS; } void sdp_server_cleanup() { - BTIF_TRACE_DEBUG("Sdp Server %s", __func__); + LOG_VERBOSE("Sdp Server %s", __func__); std::unique_lock lock(sdp_lock); int i; for (i = 0; i < MAX_SDP_SLOTS; i++) { @@ -212,7 +212,7 @@ static int alloc_sdp_slot(bluetooth_sdp_record* in_record) { } } } - APPL_TRACE_ERROR("%s() failed - no more free slots!", __func__); + LOG_ERROR("%s() failed - no more free slots!", __func__); /* Rearly the optimist is too optimistic, and cleanup is needed...*/ osi_free(record); return -1; @@ -222,7 +222,7 @@ static int free_sdp_slot(int id) { int handle = -1; bluetooth_sdp_record* record = NULL; if (id < 0 || id >= MAX_SDP_SLOTS) { - APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id); + LOG_ERROR("%s() failed - id %d is invalid", __func__, id); return handle; } @@ -252,14 +252,14 @@ static int free_sdp_slot(int id) { */ static const sdp_slot_t* start_create_sdp(int id) { if (id >= MAX_SDP_SLOTS) { - APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id); + LOG_ERROR("%s() failed - id %d is invalid", __func__, id); return NULL; } std::unique_lock lock(sdp_lock); if (sdp_slots[id].state != SDP_RECORD_ALLOCED) { /* The record have been removed before this event occurred - e.g. deinit */ - APPL_TRACE_ERROR( + LOG_ERROR( "%s() failed - state for id %d is " "sdp_slots[id].state = %d expected %d", __func__, id, sdp_slots[id].state, SDP_RECORD_ALLOCED); @@ -279,7 +279,7 @@ bt_status_t create_sdp_record(bluetooth_sdp_record* record, int handle; handle = alloc_sdp_slot(record); - BTIF_TRACE_DEBUG("%s() handle = 0x%08x", __func__, handle); + LOG_VERBOSE("%s() handle = 0x%08x", __func__, handle); if (handle < 0) return BT_STATUS_FAIL; @@ -331,16 +331,16 @@ bt_status_t remove_sdp_record(int record_id) { /* Get the Record handle, and free the slot */ handle = free_sdp_slot(record_id); - BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x", __func__, record_id, - handle); + LOG_VERBOSE("Sdp Server %s id=%d to handle=0x%08x", __func__, record_id, + handle); /* Pass the actual record handle */ if (handle > 0) { BTA_SdpRemoveRecordByUser(INT_TO_PTR(handle)); return BT_STATUS_SUCCESS; } - BTIF_TRACE_DEBUG("Sdp Server %s - record already removed - or never created", - __func__); + LOG_VERBOSE("Sdp Server %s - record already removed - or never created", + __func__); return BT_STATUS_FAIL; } @@ -356,7 +356,7 @@ void on_create_record_event(int id) { * 3) Update state on completion * 4) What to do at fail? * */ - BTIF_TRACE_DEBUG("Sdp Server %s", __func__); + LOG_VERBOSE("Sdp Server %s", __func__); const sdp_slot_t* sdp_slot = start_create_sdp(id); tBTA_SERVICE_ID service_id = -1; bluetooth_sdp_record* record; @@ -396,7 +396,7 @@ void on_create_record_event(int id) { } break; default: - BTIF_TRACE_DEBUG("Record type %d is not supported", record->hdr.type); + LOG_VERBOSE("Record type %d is not supported", record->hdr.type); break; } if (handle != -1) { @@ -418,14 +418,14 @@ void on_create_record_event(int id) { } void on_remove_record_event(int handle) { - BTIF_TRACE_DEBUG("Sdp Server %s", __func__); + LOG_VERBOSE("Sdp Server %s", __func__); // User data carries the actual SDP handle, not the ID. if (handle != -1 && handle != 0) { bool result; result = get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(handle); if (!result) { - BTIF_TRACE_ERROR(" Unable to remove handle 0x%08x", handle); + LOG_ERROR(" Unable to remove handle 0x%08x", handle); } } } @@ -509,11 +509,10 @@ static int add_maps_sdp(const bluetooth_sdp_mas_record* rec) { if (!status) { get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(sdp_handle); sdp_handle = 0; - APPL_TRACE_ERROR("%s() FAILED", __func__); + LOG_ERROR("%s() FAILED", __func__); } else { bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */ - APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__, - sdp_handle); + LOG_VERBOSE("%s(): SDP Registered (handle 0x%08x)", __func__, sdp_handle); } return sdp_handle; } @@ -582,11 +581,10 @@ static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec) { if (!status) { get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(sdp_handle); sdp_handle = 0; - APPL_TRACE_ERROR("%s() FAILED", __func__); + LOG_ERROR("%s() FAILED", __func__); } else { bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */ - APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__, - sdp_handle); + LOG_VERBOSE("%s(): SDP Registered (handle 0x%08x)", __func__, sdp_handle); } return sdp_handle; } @@ -625,12 +623,11 @@ static int add_pbapc_sdp(const bluetooth_sdp_pce_record* rec) { if (!status) { get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(sdp_handle); sdp_handle = 0; - APPL_TRACE_ERROR("%s() FAILED", __func__); + LOG_ERROR("%s() FAILED", __func__); return sdp_handle; } bta_sys_add_uuid(service); /* UUID_SERVCLASS_PBAP_PCE */ - APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__, - sdp_handle); + LOG_VERBOSE("%s(): SDP Registered (handle 0x%08x)", __func__, sdp_handle); return sdp_handle; } @@ -690,8 +687,8 @@ static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec) { status &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE, (uint32_t)1, (uint8_t*)&supported_repositories_1_1); - APPL_TRACE_DEBUG(" supported_repositories_1_1: 0x%x", - supported_repositories_1_1); + LOG_VERBOSE(" supported_repositories_1_1: 0x%x", + supported_repositories_1_1); sdp_save_local_pse_record_attributes( rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm, rec->hdr.profile_version, rec->supported_features, @@ -756,11 +753,10 @@ static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec) { if (!status) { get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(sdp_handle); sdp_handle = 0; - APPL_TRACE_ERROR("%s() FAILED", __func__); + LOG_ERROR("%s() FAILED", __func__); } else { bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */ - APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__, - sdp_handle); + LOG_VERBOSE("%s(): SDP Registered (handle 0x%08x)", __func__, sdp_handle); } return sdp_handle; } @@ -840,15 +836,14 @@ static int add_opps_sdp(const bluetooth_sdp_ops_record* rec) { if (!status) { get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(sdp_handle); sdp_handle = 0; - APPL_TRACE_ERROR("%s() FAILED", __func__); + LOG_ERROR("%s() FAILED", __func__); } else { /* set class of device */ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER; utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); bta_sys_add_uuid(service); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */ - APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__, - sdp_handle); + LOG_VERBOSE("%s(): SDP Registered (handle 0x%08x)", __func__, sdp_handle); } return sdp_handle; } @@ -902,11 +897,10 @@ static int add_saps_sdp(const bluetooth_sdp_sap_record* rec) { if (!status) { get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(sdp_handle); sdp_handle = 0; - APPL_TRACE_ERROR("%s(): FAILED deleting record", __func__); + LOG_ERROR("%s(): FAILED deleting record", __func__); } else { bta_sys_add_uuid(UUID_SERVCLASS_SAP); - APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__, - sdp_handle); + LOG_VERBOSE("%s(): SDP Registered (handle 0x%08x)", __func__, sdp_handle); } return sdp_handle; } @@ -952,11 +946,10 @@ static int add_mps_sdp(const bluetooth_sdp_mps_record* rec) { if (!status) { get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(sdp_handle); sdp_handle = 0; - APPL_TRACE_ERROR("%s() FAILED", __func__); + LOG_ERROR("%s() FAILED", __func__); return sdp_handle; } bta_sys_add_uuid(service); /* UUID_SERVCLASS_MPS_SC */ - APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__, - sdp_handle); + LOG_VERBOSE("%s(): SDP Registered (handle 0x%08x)", __func__, sdp_handle); return sdp_handle; } diff --git a/system/btif/src/btif_sock.cc b/system/btif/src/btif_sock.cc index 4b3ca3006551aa0a4de27087d6f4a592611e1327..c35c1ed3c2c39d44781686653081950bf629a775 100644 --- a/system/btif/src/btif_sock.cc +++ b/system/btif/src/btif_sock.cc @@ -29,7 +29,7 @@ #include -#include "bta_api.h" +#include "bta_sec_api.h" #include "btif_common.h" #include "btif_config.h" #include "btif_metrics_logging.h" @@ -64,6 +64,7 @@ static bt_status_t btsock_control_req(uint8_t dlci, const RawAddress& bd_addr, uint8_t break_signal_seq, bool fc); static void btsock_signaled(int fd, int type, int flags, uint32_t user_id); +static bt_status_t btsock_disconnect_all(const RawAddress* bd_addr); static std::atomic_int thread_handle{-1}; static thread_t* thread; @@ -75,6 +76,8 @@ struct SockConnectionEvent { RawAddress addr; int state; int role; + int channel; + char server_name[64]; struct timespec timestamp; void dump(const int fd); @@ -86,10 +89,9 @@ static SockConnectionEvent connection_logger[SOCK_LOGGER_SIZE_MAX]; const btsock_interface_t* btif_sock_get_interface(void) { static btsock_interface_t interface = { - sizeof(interface), btsock_listen, /* listen */ - btsock_connect, /* connect */ - btsock_request_max_tx_data_length, /* request_max_tx_data_length */ - btsock_control_req /* send_control_req */ + sizeof(interface), btsock_listen, + btsock_connect, btsock_request_max_tx_data_length, + btsock_control_req, btsock_disconnect_all, }; return &interface; @@ -156,9 +158,10 @@ void btif_sock_cleanup(void) { thread = NULL; } -void btif_sock_connection_logger(int state, int role, const RawAddress& addr) { - LOG_INFO("address=%s, role=%d, state=%d", ADDRESS_TO_LOGGABLE_CSTR(addr), - state, role); +void btif_sock_connection_logger(int state, int role, const RawAddress& addr, + int channel, const char* server_name) { + LOG_INFO("address=%s, state=%d, role=%d, server_name=%s, channel=%d", + ADDRESS_TO_LOGGABLE_CSTR(addr), state, role, server_name, channel); uint8_t index = logger_index++ % SOCK_LOGGER_SIZE_MAX; @@ -167,13 +170,20 @@ void btif_sock_connection_logger(int state, int role, const RawAddress& addr) { .addr = addr, .state = state, .role = role, + .channel = channel, + .server_name = {'\0'}, }; + + strncpy(connection_logger[index].server_name, server_name, + sizeof(connection_logger[index].server_name) - 1); clock_gettime(CLOCK_REALTIME, &connection_logger[index].timestamp); } void btif_sock_dump(int fd) { dprintf(fd, "\nSocket Events: \n"); - dprintf(fd, " Time \tAddress \tState \tRole\n"); + dprintf(fd, + " Time \tAddress \tState \tRole" + " \tChannel \tServerName\n"); const uint8_t head = logger_index.load() % SOCK_LOGGER_SIZE_MAX; @@ -234,8 +244,9 @@ void SockConnectionEvent::dump(const int fd) { break; } - dprintf(fd, " %s\t%s\t%s \t%s\n", eventtime, - ADDRESS_TO_LOGGABLE_CSTR(addr), str_state, str_role); + dprintf(fd, " %s\t%s\t%s \t%s \t%d \t%s\n", eventtime, + ADDRESS_TO_LOGGABLE_CSTR(addr), str_state, str_role, channel, + server_name); } static bt_status_t btsock_control_req(uint8_t dlci, const RawAddress& bd_addr, @@ -258,8 +269,6 @@ static bt_status_t btsock_listen(btsock_type_t type, const char* service_name, bt_status_t status = BT_STATUS_FAIL; int original_channel = channel; - btif_sock_connection_logger(SOCKET_CONNECTION_STATE_LISTENING, - SOCKET_ROLE_LISTEN, RawAddress::kEmpty); log_socket_connection_state(RawAddress::kEmpty, 0, type, android::bluetooth::SocketConnectionstateEnum:: SOCKET_CONNECTION_STATE_LISTENING, @@ -302,7 +311,8 @@ static bt_status_t btsock_listen(btsock_type_t type, const char* service_name, } if (status != BT_STATUS_SUCCESS) { btif_sock_connection_logger(SOCKET_CONNECTION_STATE_DISCONNECTED, - SOCKET_ROLE_LISTEN, RawAddress::kEmpty); + SOCKET_ROLE_LISTEN, RawAddress::kEmpty, channel, + service_name); log_socket_connection_state(RawAddress::kEmpty, 0, type, android::bluetooth::SocketConnectionstateEnum:: SOCKET_CONNECTION_STATE_DISCONNECTED, @@ -324,7 +334,8 @@ static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type, bt_status_t status = BT_STATUS_FAIL; btif_sock_connection_logger(SOCKET_CONNECTION_STATE_CONNECTING, - SOCKET_ROLE_CONNECTION, *bd_addr); + SOCKET_ROLE_CONNECTION, *bd_addr, channel, + uuid->ToString().c_str()); log_socket_connection_state(*bd_addr, 0, type, android::bluetooth::SocketConnectionstateEnum:: SOCKET_CONNECTION_STATE_CONNECTING, @@ -370,7 +381,8 @@ static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type, } if (status != BT_STATUS_SUCCESS) { btif_sock_connection_logger(SOCKET_CONNECTION_STATE_DISCONNECTED, - SOCKET_ROLE_CONNECTION, *bd_addr); + SOCKET_ROLE_CONNECTION, *bd_addr, channel, + uuid->ToString().c_str()); log_socket_connection_state(*bd_addr, 0, type, android::bluetooth::SocketConnectionstateEnum:: SOCKET_CONNECTION_STATE_DISCONNECTED, @@ -401,3 +413,20 @@ static void btsock_signaled(int fd, int type, int flags, uint32_t user_id) { break; } } + +static bt_status_t btsock_disconnect_all(const RawAddress* bd_addr) { + CHECK(bd_addr != NULL); + + bt_status_t rfc_status = btsock_rfc_disconnect(bd_addr); + bt_status_t l2cap_status = btsock_l2cap_disconnect(bd_addr); + /* SCO is disconnected via btif_hf, so is not handled here. */ + + LOG_INFO("%s: rfc status: %d, l2cap status: %d", __func__, rfc_status, + l2cap_status); + + /* Return error status, if any. */ + if (rfc_status == BT_STATUS_SUCCESS) { + return l2cap_status; + } + return rfc_status; +} diff --git a/system/btif/src/btif_sock_l2cap.cc b/system/btif/src/btif_sock_l2cap.cc index 0c2559319ecba9079fbe0a0108070e04be7108ff..8e1150f086544cedfe152ca07f6a7bd322328499 100644 --- a/system/btif/src/btif_sock_l2cap.cc +++ b/system/btif/src/btif_sock_l2cap.cc @@ -32,12 +32,10 @@ #include "btif/include/btif_uid.h" #include "include/hardware/bluetooth.h" #include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" -#include "stack/btm/security_device_record.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "types/raw_address.h" struct packet { @@ -209,7 +207,8 @@ static void btsock_l2cap_free_l(l2cap_socket* sock) { btif_sock_connection_logger( SOCKET_CONNECTION_STATE_DISCONNECTED, - sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr); + sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr, + sock->channel, sock->name); // Whenever a socket is freed, the connection must be dropped log_socket_connection_state( @@ -414,7 +413,8 @@ static void on_srv_l2cap_listen_started(tBTA_JV_L2CAP_START* p_start, btif_sock_connection_logger( SOCKET_CONNECTION_STATE_LISTENING, - sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr); + sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr, + sock->channel, sock->name); log_socket_connection_state( sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP, @@ -482,7 +482,7 @@ static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, btif_sock_connection_logger( SOCKET_CONNECTION_STATE_CONNECTED, accept_rs->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, - accept_rs->addr); + accept_rs->addr, accept_rs->channel, accept_rs->name); log_socket_connection_state( accept_rs->addr, accept_rs->id, @@ -526,7 +526,8 @@ static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, btif_sock_connection_logger( SOCKET_CONNECTION_STATE_CONNECTED, - sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr); + sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr, + sock->channel, sock->name); log_socket_connection_state( sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP, @@ -582,7 +583,8 @@ static void on_l2cap_close(tBTA_JV_L2CAP_CLOSE* p_close, uint32_t id) { btif_sock_connection_logger( SOCKET_CONNECTION_STATE_DISCONNECTING, - sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr); + sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr, + sock->channel, sock->name); log_socket_connection_state( sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP, @@ -932,7 +934,6 @@ void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) { reported total size of awaiting packets. Hence, we adjust the buffer length. */ buffer->len = count; - DVLOG(2) << __func__ << ": bytes received from socket: " << count; // will take care of freeing buffer BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, user_id); @@ -952,3 +953,21 @@ void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) { btsock_l2cap_free_l(sock); } } + +bt_status_t btsock_l2cap_disconnect(const RawAddress* bd_addr) { + if (!bd_addr) return BT_STATUS_PARM_INVALID; + if (!is_inited()) return BT_STATUS_NOT_READY; + + std::unique_lock lock(state_lock); + l2cap_socket* sock = socks; + + while (sock) { + l2cap_socket* next = sock->next; + if (sock->addr == *bd_addr) { + btsock_l2cap_free_l(sock); + } + sock = next; + } + + return BT_STATUS_SUCCESS; +} diff --git a/system/btif/src/btif_sock_rfc.cc b/system/btif/src/btif_sock_rfc.cc index 00643ee5ed807a579ec1d9331b22845f0abe6131..90cade264bb6a0264559e8ed7048d6f6341f3847 100644 --- a/system/btif/src/btif_sock_rfc.cc +++ b/system/btif/src/btif_sock_rfc.cc @@ -22,12 +22,13 @@ #include #include #include + #include #include #include "bt_target.h" // Must be first to define build configuration - #include "bta/include/bta_jv_api.h" +#include "bta/include/bta_rfcomm_scn.h" #include "btif/include/btif_metrics_logging.h" /* The JV interface can have only one user, hence we need to call a few * L2CAP functions from this file. */ @@ -106,6 +107,7 @@ static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id); static uint32_t rfcomm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t rfcomm_slot_id); static bool send_app_scn(rfc_slot_t* rs); +static void handle_discovery_comp(tBTA_JV_STATUS status, int scn, uint32_t id); static bool is_init_done(void) { return pth != -1; } @@ -155,7 +157,6 @@ static rfc_slot_t* find_rfc_slot_by_id(uint32_t id) { for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) if (rfc_slots[i].id == id) return &rfc_slots[i]; - LOG_ERROR("%s unable to find RFCOMM slot id: %u", __func__, id); return NULL; } @@ -227,6 +228,7 @@ static rfc_slot_t* alloc_rfc_slot(const RawAddress* addr, const char* name, } slot->id = rfc_slot_id; slot->f.server = server; + slot->role = server; slot->tx_bytes = 0; slot->rx_bytes = 0; return slot; @@ -411,7 +413,7 @@ static void free_rfc_slot_scn(rfc_slot_t* slot) { slot->rfc_handle = 0; } - if (slot->f.server) BTM_FreeSCN(slot->scn); + if (slot->f.server) BTA_FreeSCN(slot->scn); slot->scn = 0; } @@ -421,8 +423,10 @@ static void cleanup_rfc_slot(rfc_slot_t* slot) { close(slot->fd); btif_sock_connection_logger( SOCKET_CONNECTION_STATE_DISCONNECTED, - slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, - slot->addr); + slot->role ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->addr, + slot->scn, + slot->role ? slot->service_name + : slot->service_uuid.ToString().c_str()); log_socket_connection_state( slot->addr, slot->id, BTSOCK_RFCOMM, android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTED, @@ -487,12 +491,15 @@ static bool send_app_connect_signal(int fd, const RawAddress* addr, int channel, static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT* p_init, uint32_t id) { std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (!slot) return; - - if (p_init->status == BTA_JV_SUCCESS) { - slot->rfc_handle = p_init->handle; - } else { + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found. p_init->status=%u", id, + p_init->status); + } else if (p_init->status != BTA_JV_SUCCESS) { + LOG_WARN("INIT unsuccessful, status %u. Cleaning up slot with id %u", + p_init->status, slot->id); cleanup_rfc_slot(slot); + } else { + slot->rfc_handle = p_init->handle; } } @@ -500,24 +507,28 @@ static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START* p_start, uint32_t id) { std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (!slot) return; - - if (p_start->status == BTA_JV_SUCCESS) { - slot->rfc_handle = p_start->handle; - btif_sock_connection_logger( - SOCKET_CONNECTION_STATE_LISTENING, - slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, - slot->addr); - log_socket_connection_state( - slot->addr, slot->id, BTSOCK_RFCOMM, - android::bluetooth::SocketConnectionstateEnum:: - SOCKET_CONNECTION_STATE_LISTENING, - 0, 0, slot->app_uid, slot->scn, - slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN - : android::bluetooth::SOCKET_ROLE_CONNECTION); - } else { + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found", id); + return; + } else if (p_start->status != BTA_JV_SUCCESS) { + LOG_WARN("START unsuccessful, status %u. Cleaning up slot with id %u", + p_start->status, slot->id); cleanup_rfc_slot(slot); + return; } + + slot->rfc_handle = p_start->handle; + btif_sock_connection_logger( + SOCKET_CONNECTION_STATE_LISTENING, + slot->role ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->addr, + slot->scn, slot->service_name); + log_socket_connection_state(slot->addr, slot->id, BTSOCK_RFCOMM, + android::bluetooth::SocketConnectionstateEnum:: + SOCKET_CONNECTION_STATE_LISTENING, + 0, 0, slot->app_uid, slot->scn, + slot->f.server + ? android::bluetooth::SOCKET_ROLE_LISTEN + : android::bluetooth::SOCKET_ROLE_CONNECTION); } static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open, @@ -525,7 +536,10 @@ static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open, std::unique_lock lock(slot_lock); rfc_slot_t* accept_rs; rfc_slot_t* srv_rs = find_rfc_slot_by_id(id); - if (!srv_rs) return 0; + if (!srv_rs) { + LOG_ERROR("RFCOMM slot with id %u not found.", id); + return 0; + } accept_rs = create_srv_accept_rfc_slot( srv_rs, &p_open->rem_bda, p_open->handle, p_open->new_listen_handle); @@ -533,8 +547,8 @@ static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open, btif_sock_connection_logger( SOCKET_CONNECTION_STATE_CONNECTED, - accept_rs->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, - accept_rs->addr); + accept_rs->role ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, + accept_rs->addr, accept_rs->scn, accept_rs->service_name); log_socket_connection_state( accept_rs->addr, accept_rs->id, BTSOCK_RFCOMM, android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0, @@ -557,9 +571,14 @@ static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open, static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN* p_open, uint32_t id) { std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (!slot) return; + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found.", id); + return; + } if (p_open->status != BTA_JV_SUCCESS) { + LOG_WARN("CONNECT unsuccessful, status %u. Cleaning up slot with id %u", + p_open->status, slot->id); cleanup_rfc_slot(slot); return; } @@ -569,7 +588,8 @@ static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN* p_open, uint32_t id) { btif_sock_connection_logger( SOCKET_CONNECTION_STATE_CONNECTED, - slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->addr); + slot->role ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->addr, + slot->scn, slot->service_uuid.ToString().c_str()); log_socket_connection_state( slot->addr, slot->id, BTSOCK_RFCOMM, android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0, @@ -591,15 +611,17 @@ static void on_rfc_close(UNUSED_ATTR tBTA_JV_RFCOMM_CLOSE* p_close, // rfc_handle already closed when receiving rfcomm close event from stack. rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (slot) { - log_socket_connection_state( - slot->addr, slot->id, BTSOCK_RFCOMM, - android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0, - slot->app_uid, slot->scn, - slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN - : android::bluetooth::SOCKET_ROLE_CONNECTION); - cleanup_rfc_slot(slot); + if (!slot) { + LOG_WARN("RFCOMM slot with id %u not found.", id); + return; } + log_socket_connection_state( + slot->addr, slot->id, BTSOCK_RFCOMM, + android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0, + slot->app_uid, slot->scn, + slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN + : android::bluetooth::SOCKET_ROLE_CONNECTION); + cleanup_rfc_slot(slot); } static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE* p, uint32_t id) { @@ -613,15 +635,15 @@ static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE* p, uint32_t id) { std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (slot) { - app_uid = slot->app_uid; - if (!slot->f.outgoing_congest) { - btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, - slot->id); - } - slot->tx_bytes += p->len; + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found.", id); + return; } - + app_uid = slot->app_uid; + if (!slot->f.outgoing_congest) + btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, + slot->id); + slot->tx_bytes += p->len; uid_set_add_tx(uid_set, app_uid, p->len); } @@ -629,12 +651,15 @@ static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG* p, uint32_t id) { std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (slot) { - slot->f.outgoing_congest = p->cong ? 1 : 0; - if (!slot->f.outgoing_congest) - btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, - slot->id); + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found.", id); + return; } + + slot->f.outgoing_congest = p->cong ? 1 : 0; + if (!slot->f.outgoing_congest) + btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, + slot->id); } static uint32_t rfcomm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, @@ -663,8 +688,7 @@ static uint32_t rfcomm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, break; case BTA_JV_RFCOMM_CLOSE_EVT: - APPL_TRACE_DEBUG("BTA_JV_RFCOMM_CLOSE_EVT: rfcomm_slot_id:%d", - rfcomm_slot_id); + LOG_VERBOSE("BTA_JV_RFCOMM_CLOSE_EVT: rfcomm_slot_id:%d", rfcomm_slot_id); on_rfc_close(&p_data->rfc_close, rfcomm_slot_id); break; @@ -693,100 +717,78 @@ static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) { case BTA_JV_GET_SCN_EVT: { std::unique_lock lock(slot_lock); rfc_slot_t* rs = find_rfc_slot_by_id(id); - int new_scn = p_data->scn; - - if (rs && (new_scn != 0)) { - rs->scn = new_scn; - /* BTA_JvCreateRecordByUser will only create a record if a UUID is - * specified, - * else it just allocate a RFC channel and start the RFCOMM thread - - * needed - * for the java - * layer to get a RFCOMM channel. - * If uuid is null the create_sdp_record() will be called from Java when - * it - * has received the RFCOMM and L2CAP channel numbers through the - * sockets.*/ - - // Send channel ID to java layer - if (!send_app_scn(rs)) { - // closed - APPL_TRACE_DEBUG("send_app_scn() failed, close rs->id:%d", rs->id); - cleanup_rfc_slot(rs); - } else { - if (rs->is_service_uuid_valid) { - // We already have data for SDP record, create it (RFC-only - // profiles) - BTA_JvCreateRecordByUser(rs->id); - } else { - APPL_TRACE_DEBUG( - "is_service_uuid_valid==false - don't set SDP-record, " - "just start the RFCOMM server", - rs->id); - // now start the rfcomm server after sdp & channel # assigned - BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, - MAX_RFC_SESSION, rfcomm_cback, rs->id); - } - } - } else if (rs) { - APPL_TRACE_ERROR( - "jv_dm_cback: Error: allocate channel %d, slot found:%p", rs->scn, + if (!rs) { + LOG_ERROR("RFCOMM slot with id %u not found. event:%d", id, event); + break; + } + if (p_data->scn == 0) { + LOG_ERROR( + "Unable to allocate scn: all resources exhausted. slot found: %p", rs); cleanup_rfc_slot(rs); + break; + } + + rs->scn = p_data->scn; + // Send channel ID to java layer + if (!send_app_scn(rs)) { + LOG_DEBUG("send_app_scn() failed, closing rs->id:%d", rs->id); + cleanup_rfc_slot(rs); + break; + } + + if (rs->is_service_uuid_valid) { + // BTA_JvCreateRecordByUser will only create a record if a UUID is + // specified. RFC-only profiles + BTA_JvCreateRecordByUser(rs->id); + } else { + // If uuid is null, just allocate a RFC channel and start the RFCOMM + // thread needed for the java layer to get a RFCOMM channel. + // create_sdp_record() will be called from Java when it has received the + // RFCOMM and L2CAP channel numbers through the sockets. + LOG_DEBUG( + "Since UUID is not valid; not setting SDP-record and just starting " + "the RFCOMM server"); + // now start the rfcomm server after sdp & channel # assigned + BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, + MAX_RFC_SESSION, rfcomm_cback, rs->id); } break; } + case BTA_JV_GET_PSM_EVT: { - APPL_TRACE_DEBUG("Received PSM: 0x%04x", p_data->psm); + LOG_VERBOSE("Received PSM: 0x%04x", p_data->psm); on_l2cap_psm_assigned(id, p_data->psm); break; } + case BTA_JV_CREATE_RECORD_EVT: { std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (slot && create_server_sdp_record(slot)) { - // Start the rfcomm server after sdp & channel # assigned. - BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn, - MAX_RFC_SESSION, rfcomm_cback, slot->id); - } else if (slot) { - APPL_TRACE_ERROR("jv_dm_cback: cannot start server, slot found:%p", - slot); + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found. event:%d", id, event); + break; + } + + if (!create_server_sdp_record(slot)) { + LOG_ERROR("cannot start server, slot found: %p", slot); cleanup_rfc_slot(slot); + break; } + + // Start the rfcomm server after sdp & channel # assigned. + BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn, + MAX_RFC_SESSION, rfcomm_cback, slot->id); break; } case BTA_JV_DISCOVERY_COMP_EVT: { std::unique_lock lock(slot_lock); - rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn) { - if (slot && slot->f.doing_sdp_request) { - // Establish the connection if we successfully looked up a channel - // number to connect to. - if (BTA_JvRfcommConnect(slot->security, slot->role, - p_data->disc_comp.scn, slot->addr, - rfcomm_cback, slot->id) == BTA_JV_SUCCESS) { - slot->scn = p_data->disc_comp.scn; - slot->f.doing_sdp_request = false; - if (!send_app_scn(slot)) cleanup_rfc_slot(slot); - } else { - cleanup_rfc_slot(slot); - } - } else if (slot) { - // TODO(sharvil): this is really a logic error and we should probably - // assert. - LOG_ERROR( - "%s SDP response returned but RFCOMM slot %d did not " - "request SDP record.", - __func__, id); - } - } else if (slot) { - cleanup_rfc_slot(slot); - } - + handle_discovery_comp(p_data->disc_comp.status, p_data->disc_comp.scn, + id); // Find the next slot that needs to perform an SDP request and service it. - slot = find_rfc_slot_by_pending_sdp(); + rfc_slot_t* slot = find_rfc_slot_by_pending_sdp(); if (slot) { BTA_JvStartDiscovery(slot->addr, 1, &slot->service_uuid, slot->id); slot->f.pending_sdp_request = false; @@ -796,11 +798,55 @@ static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) { } default: - APPL_TRACE_DEBUG("unhandled event:%d, slot id:%d", event, id); + LOG_DEBUG("unhandled event:%d, slot id:%d", event, id); break; } } +static void handle_discovery_comp(tBTA_JV_STATUS status, int scn, uint32_t id) { + rfc_slot_t* slot = find_rfc_slot_by_id(id); + if (!slot) { + LOG_ERROR( + "RFCOMM slot with id %u not found. event: BTA_JV_DISCOVERY_COMP_EVT", + id); + return; + } + + if (!slot->f.doing_sdp_request) { + LOG_ERROR( + "SDP response returned but RFCOMM slot %d did not request SDP record.", + id); + return; + } + + if (status != BTA_JV_SUCCESS || !scn) { + LOG_ERROR( + "SDP service discovery completed for slot id: %u with the result " + "status: %u, scn: %d", + id, status, scn); + cleanup_rfc_slot(slot); + return; + } + + if (BTA_JvRfcommConnect(slot->security, slot->role, scn, slot->addr, + rfcomm_cback, slot->id) != BTA_JV_SUCCESS) { + LOG_WARN( + "BTA_JvRfcommConnect() returned BTA_JV_FAILURE for RFCOMM slot with " + "id: %u", + id); + cleanup_rfc_slot(slot); + return; + } + // Establish connection if successfully found channel number to connect. + slot->scn = scn; + slot->f.doing_sdp_request = false; + + if (!send_app_scn(slot)) { + cleanup_rfc_slot(slot); + return; + } +} + typedef enum { SENT_FAILED, SENT_NONE, @@ -854,18 +900,21 @@ static bool flush_incoming_que_on_wr_signal(rfc_slot_t* slot) { // app is ready to receive data, tell stack to start the data flow // fix me: need a jv flow control api to serialize the call in stack - APPL_TRACE_DEBUG( + LOG_VERBOSE( "enable data flow, rfc_handle:0x%x, rfc_port_handle:0x%x, user_id:%d", slot->rfc_handle, slot->rfc_port_handle, slot->id); PORT_FlowControl_MaxCredit(slot->rfc_port_handle, true); return true; } -void btsock_rfc_signaled(UNUSED_ATTR int fd, int flags, uint32_t user_id) { +void btsock_rfc_signaled(UNUSED_ATTR int fd, int flags, uint32_t id) { bool need_close = false; std::unique_lock lock(slot_lock); - rfc_slot_t* slot = find_rfc_slot_by_id(user_id); - if (!slot) return; + rfc_slot_t* slot = find_rfc_slot_by_id(id); + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found.", id); + return; + } // Data available from app, tell stack we have outgoing data. if (flags & SOCK_THREAD_FD_RD && !slot->f.server) { @@ -910,7 +959,10 @@ int bta_co_rfc_data_incoming(uint32_t id, BT_HDR* p_buf) { int ret = 0; std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (!slot) return 0; + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found.", id); + return 0; + } app_uid = slot->app_uid; bytes_rx = p_buf->len; @@ -948,7 +1000,10 @@ int bta_co_rfc_data_outgoing_size(uint32_t id, int* size) { *size = 0; std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (!slot) return false; + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found.", id); + return false; + } if (ioctl(slot->fd, FIONREAD, size) != 0) { LOG_ERROR("%s unable to determine bytes remaining to be read on fd %d: %s", @@ -963,7 +1018,10 @@ int bta_co_rfc_data_outgoing_size(uint32_t id, int* size) { int bta_co_rfc_data_outgoing(uint32_t id, uint8_t* buf, uint16_t size) { std::unique_lock lock(slot_lock); rfc_slot_t* slot = find_rfc_slot_by_id(id); - if (!slot) return false; + if (!slot) { + LOG_ERROR("RFCOMM slot with id %u not found.", id); + return false; + } ssize_t received; OSI_NO_INTR(received = recv(slot->fd, buf, size, 0)); @@ -977,3 +1035,17 @@ int bta_co_rfc_data_outgoing(uint32_t id, uint8_t* buf, uint16_t size) { return true; } + +bt_status_t btsock_rfc_disconnect(const RawAddress* bd_addr) { + CHECK(bd_addr != NULL); + if (!is_init_done()) return BT_STATUS_NOT_READY; + + std::unique_lock lock(slot_lock); + for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) { + if (rfc_slots[i].id && rfc_slots[i].addr == *bd_addr) { + cleanup_rfc_slot(&rfc_slots[i]); + } + } + + return BT_STATUS_SUCCESS; +} diff --git a/system/btif/src/btif_sock_sdp.cc b/system/btif/src/btif_sock_sdp.cc index 6811cc3423999b495de593cba57f4db08bf169f7..b550bf30598b13f88e45faabd00bcd92bb595a97 100644 --- a/system/btif/src/btif_sock_sdp.cc +++ b/system/btif/src/btif_sock_sdp.cc @@ -18,14 +18,16 @@ #define LOG_TAG "bt_btif_sock_sdp" -#include "bt_target.h" // Must be first to define build configuration +#include "btif/include/btif_sock_sdp.h" #include "bta/include/bta_jv_api.h" #include "bta/include/bta_op_api.h" #include "bta/include/utl.h" #include "bta/pb/bta_pbs_int.h" #include "bta/sys/bta_sys.h" -#include "btif/include/btif_sock_sdp.h" +#include "internal_include/bt_target.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/sdp_api.h" #include "stack/include/sdpdefs.h" #include "types/bluetooth/uuid.h" @@ -88,8 +90,8 @@ static const tBTA_OP_FMT bta_ops_obj_fmt[OBEX_PUSH_NUM_FORMATS] = { // Returns true if successful, otherwise false. static bool create_base_record(const uint32_t sdp_handle, const char* name, const uint16_t channel, const bool with_obex) { - APPL_TRACE_DEBUG("create_base_record: scn: %d, name: %s, with_obex: %d", - channel, name, with_obex); + LOG_VERBOSE("create_base_record: scn: %d, name: %s, with_obex: %d", channel, + name, with_obex); // Setup the protocol list and add it. tSDP_PROTOCOL_ELEM proto_list[SDP_MAX_LIST_ELEMS]; @@ -130,14 +132,14 @@ static bool create_base_record(const uint32_t sdp_handle, const char* name, sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list)) goto error; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "create_base_record: successfully created base service " "record, handle: 0x%08x, scn: %d, name: %s, with_obex: %d", sdp_handle, channel, name, with_obex); return true; error: - APPL_TRACE_ERROR( + LOG_ERROR( "create_base_record: failed to create base service " "record, stage: %s, scn: %d, name: %s, with_obex: %d", stage, channel, name, with_obex); @@ -149,14 +151,13 @@ error: // class sequence. static int add_sdp_by_uuid(const char* name, const Uuid& uuid, const uint16_t channel) { - APPL_TRACE_DEBUG("%s: uuid: %s, scn: %d, service_name: %s", __func__, - uuid.ToString().c_str(), channel, name); + LOG_VERBOSE("%s: uuid: %s, scn: %d, service_name: %s", __func__, + uuid.ToString().c_str(), channel, name); uint32_t handle = get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); if (handle == 0) { - APPL_TRACE_ERROR( - "%s: failed to create sdp record, scn: %d, service_name: %s", __func__, - channel, name); + LOG_ERROR("%s: failed to create sdp record, scn: %d, service_name: %s", + __func__, channel, name); return 0; } @@ -187,7 +188,7 @@ static int add_sdp_by_uuid(const char* name, const Uuid& uuid, &type_buf_ptr)) goto error; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "%s: service registered successfully, service_name: %s, handle: 0x%08x", __func__, name, handle); @@ -201,19 +202,19 @@ static int add_sdp_by_uuid(const char* name, const Uuid& uuid, error: get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(handle); - APPL_TRACE_ERROR("%s: failed to register service stage: %s, service_name: %s", - __func__, stage, name); + LOG_ERROR("%s: failed to register service stage: %s, service_name: %s", + __func__, stage, name); return 0; } // Registers a service with the given |name| and |channel| in the SDP // database as a PBAP protocol. static int add_pbap_sdp(const char* name, const int channel) { - APPL_TRACE_DEBUG("add_pbap_sdp: scn %d, service_name %s", channel, name); + LOG_VERBOSE("add_pbap_sdp: scn %d, service_name %s", channel, name); uint32_t handle = get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); if (handle == 0) { - APPL_TRACE_ERROR( + LOG_ERROR( "add_pbap_sdp: failed to create sdp record, " "service_name: %s", name); @@ -248,7 +249,7 @@ static int add_pbap_sdp(const char* name, const int channel) { // Notify the system that we've got a new service class UUID. bta_sys_add_uuid(UUID_SERVCLASS_PBAP_PSE); - APPL_TRACE_DEBUG( + LOG_VERBOSE( "add_pbap_sdp: service registered successfully, " "service_name: %s, handle: 0x%08x", name, handle); @@ -257,7 +258,7 @@ static int add_pbap_sdp(const char* name, const int channel) { error: get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(handle); - APPL_TRACE_ERROR( + LOG_ERROR( "add_pbap_sdp: failed to register PBAP service, stage: %s, " "service_name: %s", stage, name); @@ -266,11 +267,11 @@ error: // Registers a service with the given |name| and |channel| as an OBEX Push // protocol. static int add_ops_sdp(const char* name, const int channel) { - APPL_TRACE_DEBUG("add_ops_sdp: scn %d, service_name %s", channel, name); + LOG_VERBOSE("add_ops_sdp: scn %d, service_name %s", channel, name); uint32_t handle = get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); if (handle == 0) { - APPL_TRACE_ERROR( + LOG_ERROR( "add_ops_sdp: failed to create sdp record, " "service_name: %s", name); @@ -324,7 +325,7 @@ static int add_ops_sdp(const char* name, const int channel) { // Notify the system that we've got a new service class UUID. bta_sys_add_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH); - APPL_TRACE_DEBUG( + LOG_VERBOSE( "ad_maps_sdp: service registered successfully, " "service_name: %s, handle 0x%08x)", name, handle); @@ -333,7 +334,7 @@ static int add_ops_sdp(const char* name, const int channel) { error: get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(handle); - APPL_TRACE_ERROR( + LOG_ERROR( "add_ops_sdp: failed to register OPS service, " "stage: %s, service_name: %s", stage, name); @@ -343,11 +344,11 @@ error: // Registers a service with the given |name| and |channel| as a serial port // profile protocol. static int add_spp_sdp(const char* name, const int channel) { - APPL_TRACE_DEBUG("add_spp_sdp: scn %d, service_name %s", channel, name); + LOG_VERBOSE("add_spp_sdp: scn %d, service_name %s", channel, name); int handle = get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); if (handle == 0) { - APPL_TRACE_ERROR( + LOG_ERROR( "add_spp_sdp: failed to create sdp record, " "service_name: %s", name); @@ -371,7 +372,7 @@ static int add_spp_sdp(const char* name, const int channel) { handle, UUID_SERVCLASS_SERIAL_PORT, SPP_PROFILE_VERSION)) goto error; - APPL_TRACE_DEBUG( + LOG_VERBOSE( "add_spp_sdp: service registered successfully, " "service_name: %s, handle 0x%08x)", name, handle); @@ -380,7 +381,7 @@ static int add_spp_sdp(const char* name, const int channel) { error: get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(handle); - APPL_TRACE_ERROR( + LOG_ERROR( "add_spp_sdp: failed to register SPP service, " "stage: %s, service_name: %s", stage, name); @@ -393,8 +394,8 @@ error: // number if the |uuid| matches one of the preregistered bluez SDP records. static int add_rfc_sdp_by_uuid(const char* name, const Uuid& uuid, const int channel) { - APPL_TRACE_DEBUG("%s: uuid: %s, service_name: %s, channel: %d", __func__, - uuid.ToString().c_str(), name, channel); + LOG_VERBOSE("%s: uuid: %s, service_name: %s, channel: %d", __func__, + uuid.ToString().c_str(), name, channel); /* * Bluetooth Socket API relies on having preregistered bluez sdp records for @@ -478,7 +479,7 @@ int add_rfc_sdp_rec(const char* name, Uuid uuid, const int channel) { // Deletes an SDP record with the given |handle|. void del_rfc_sdp_rec(int handle) { - APPL_TRACE_DEBUG("del_rfc_sdp_rec: handle:0x%x", handle); + LOG_VERBOSE("del_rfc_sdp_rec: handle:0x%x", handle); if ((handle != -1) && (handle != 0)) { // Remove the custom 128-bit UUID from EIR diff --git a/system/btif/src/btif_sock_thread.cc b/system/btif/src/btif_sock_thread.cc index 8155f29da876534916f6fa6151bd361221db3577..7dbdf79cb9f07b0ff49abb297f5a82c02f805622 100644 --- a/system/btif/src/btif_sock_thread.cc +++ b/system/btif/src/btif_sock_thread.cc @@ -29,13 +29,10 @@ #include "btif_sock_thread.h" #include -#include -#include #include #include #include #include -#include #include #include #include @@ -49,20 +46,15 @@ #include #include #include -#include - -#include "bta_api.h" -#include "btif_common.h" -#include "btif_sock.h" -#include "btif_sock_util.h" -#include "btif_util.h" -#include "osi/include/socket_utils/sockets.h" - -#define asrt(s) \ - do { \ - if (!(s)) \ - APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \ - __LINE__) \ + +#include "os/log.h" +#include "osi/include/osi.h" // OSI_NO_INTR + +#define asrt(s) \ + do { \ + if (!(s)) \ + LOG_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \ + __LINE__); \ } while (0) #define MAX_THREAD 8 @@ -116,7 +108,7 @@ static inline int create_thread(void* (*start_routine)(void*), void* arg, ret = pthread_create(thread_id, &thread_attr, start_routine, arg); if (ret != 0) { - APPL_TRACE_ERROR("pthread_create : %s", strerror(errno)); + LOG_ERROR("pthread_create : %s", strerror(errno)); return ret; } /* We need to lower the priority of this thread to ensure the stack gets @@ -140,7 +132,7 @@ static int alloc_thread_slot() { return i; } } - APPL_TRACE_ERROR("execeeded max thread count"); + LOG_ERROR("execeeded max thread count"); return -1; } static void free_thread_slot(int h) { @@ -148,7 +140,7 @@ static void free_thread_slot(int h) { close_cmd_fd(h); ts[h].used = 0; } else - APPL_TRACE_ERROR("invalid thread handle:%d", h); + LOG_ERROR("invalid thread handle:%d", h); } void btsock_thread_init() { static int initialized; @@ -174,7 +166,7 @@ int btsock_thread_create(btsock_signaled_cb callback, pthread_t thread; int status = create_thread(sock_poll_thread, (void*)(uintptr_t)h, &thread); if (status) { - APPL_TRACE_ERROR("create_thread failed: %s", strerror(status)); + LOG_ERROR("create_thread failed: %s", strerror(status)); free_thread_slot(h); return -1; } @@ -190,7 +182,7 @@ int btsock_thread_create(btsock_signaled_cb callback, static inline void init_cmd_fd(int h) { asrt(ts[h].cmd_fdr == -1 && ts[h].cmd_fdw == -1); if (socketpair(AF_UNIX, SOCK_STREAM, 0, &ts[h].cmd_fdr) < 0) { - APPL_TRACE_ERROR("socketpair failed: %s", strerror(errno)); + LOG_ERROR("socketpair failed: %s", strerror(errno)); return; } // add the cmd fd for read & write @@ -215,12 +207,11 @@ typedef struct { } sock_cmd_t; int btsock_thread_add_fd(int h, int fd, int type, int flags, uint32_t user_id) { if (h < 0 || h >= MAX_THREAD) { - APPL_TRACE_ERROR("invalid bt thread handle:%d", h); + LOG_ERROR("invalid bt thread handle:%d", h); return false; } if (ts[h].cmd_fdw == -1) { - APPL_TRACE_ERROR( - "cmd socket is not created. socket thread may not initialized"); + LOG_ERROR("cmd socket is not created. socket thread may not initialized"); return false; } if (flags & SOCK_THREAD_ADD_FD_SYNC) { @@ -244,11 +235,11 @@ int btsock_thread_add_fd(int h, int fd, int type, int flags, uint32_t user_id) { bool btsock_thread_remove_fd_and_close(int thread_handle, int fd) { if (thread_handle < 0 || thread_handle >= MAX_THREAD) { - APPL_TRACE_ERROR("%s invalid thread handle: %d", __func__, thread_handle); + LOG_ERROR("%s invalid thread handle: %d", __func__, thread_handle); return false; } if (fd == -1) { - APPL_TRACE_ERROR("%s invalid file descriptor.", __func__); + LOG_ERROR("%s invalid file descriptor.", __func__); return false; } @@ -263,12 +254,11 @@ bool btsock_thread_remove_fd_and_close(int thread_handle, int fd) { int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size, uint32_t user_id) { if (h < 0 || h >= MAX_THREAD) { - APPL_TRACE_ERROR("invalid bt thread handle:%d", h); + LOG_ERROR("invalid bt thread handle:%d", h); return false; } if (ts[h].cmd_fdw == -1) { - APPL_TRACE_ERROR( - "cmd socket is not created. socket thread may not initialized"); + LOG_ERROR("cmd socket is not created. socket thread may not initialized"); return false; } sock_cmd_t cmd = {CMD_USER_PRIVATE, 0, type, size, user_id}; @@ -281,8 +271,8 @@ int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size, *cmd_send = cmd; memcpy(cmd_send + 1, data, size); } else { - APPL_TRACE_ERROR("alloca failed at h:%d, cmd type:%d, size:%d", h, type, - size_send); + LOG_ERROR("alloca failed at h:%d, cmd type:%d, size:%d", h, type, + size_send); return false; } } @@ -294,11 +284,11 @@ int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size, } int btsock_thread_wakeup(int h) { if (h < 0 || h >= MAX_THREAD) { - APPL_TRACE_ERROR("invalid bt thread handle:%d", h); + LOG_ERROR("invalid bt thread handle:%d", h); return false; } if (ts[h].cmd_fdw == -1) { - APPL_TRACE_ERROR("thread handle:%d, cmd socket is not created", h); + LOG_ERROR("thread handle:%d, cmd socket is not created", h); return false; } sock_cmd_t cmd = {CMD_WAKEUP, 0, 0, 0, 0}; @@ -310,11 +300,11 @@ int btsock_thread_wakeup(int h) { } int btsock_thread_exit(int h) { if (h < 0 || h >= MAX_THREAD) { - APPL_TRACE_ERROR("invalid bt thread slot:%d", h); + LOG_ERROR("invalid bt thread slot:%d", h); return false; } if (ts[h].cmd_fdw == -1) { - APPL_TRACE_ERROR("cmd socket is not created"); + LOG_ERROR("cmd socket is not created"); return false; } sock_cmd_t cmd = {CMD_EXIT, 0, 0, 0, 0}; @@ -357,9 +347,8 @@ static inline void set_poll(poll_slot_t* ps, int fd, int type, int flags, ps->pfd.fd = fd; ps->user_id = user_id; if (ps->type != 0 && ps->type != type) - APPL_TRACE_ERROR( - "poll socket type should not changed! type was:%d, type now:%d", - ps->type, type); + LOG_ERROR("poll socket type should not changed! type was:%d, type now:%d", + ps->type, type); ps->type = type; ps->flags = flags; ps->pfd.events = flags2pevents(flags); @@ -387,7 +376,7 @@ static inline void add_poll(int h, int fd, int type, int flags, ++ts[h].poll_count; return; } - APPL_TRACE_ERROR("exceeded max poll slot:%d!", MAX_POLL); + LOG_ERROR("exceeded max poll slot:%d!", MAX_POLL); } static inline void remove_poll(int h, poll_slot_t* ps, int flags) { if (flags == ps->flags) { @@ -483,7 +472,7 @@ static void prepare_poll_fds(int h, struct pollfd* pfds) { asrt(ts[h].poll_count <= MAX_POLL); while (count < ts[h].poll_count) { if (ps_i >= MAX_POLL) { - APPL_TRACE_ERROR( + LOG_ERROR( "exceed max poll range, ps_i:%d, MAX_POLL:%d, count:%d, " "ts[h].poll_count:%d", ps_i, MAX_POLL, count, ts[h].poll_count); @@ -508,8 +497,8 @@ static void* sock_poll_thread(void* arg) { int ret; OSI_NO_INTR(ret = poll(pfds.data(), ts[h].poll_count, -1)); if (ret == -1) { - APPL_TRACE_ERROR("poll ret -1, exit the thread, errno:%d, err:%s", errno, - strerror(errno)); + LOG_ERROR("poll ret -1, exit the thread, errno:%d, err:%s", errno, + strerror(errno)); break; } if (ret != 0) { diff --git a/system/btif/src/btif_sock_util.cc b/system/btif/src/btif_sock_util.cc index bf81522beb46b8a86a56fdc748d96304b583a072..72f7bbb9724afa40c94d34b4d68f7e8f5cb59138 100644 --- a/system/btif/src/btif_sock_util.cc +++ b/system/btif/src/btif_sock_util.cc @@ -21,7 +21,8 @@ #include "btif_sock_util.h" #include -#include +#include +#include #include #include #include @@ -33,18 +34,14 @@ #include #include -#include -#include - -#include "bt_target.h" -#include "btif_util.h" +#include "os/log.h" #include "osi/include/osi.h" -#define asrt(s) \ - do { \ - if (!(s)) \ - BTIF_TRACE_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \ - __LINE__) \ +#define asrt(s) \ + do { \ + if (!(s)) \ + LOG_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \ + __LINE__); \ } while (0) int sock_send_all(int sock_fd, const uint8_t* buf, int len) { @@ -54,7 +51,7 @@ int sock_send_all(int sock_fd, const uint8_t* buf, int len) { ssize_t ret; OSI_NO_INTR(ret = send(sock_fd, buf, s, 0)); if (ret <= 0) { - BTIF_TRACE_ERROR("sock fd:%d send errno:%d, ret:%d", sock_fd, errno, ret); + LOG_ERROR("sock fd:%d send errno:%d, ret:%zd", sock_fd, errno, ret); return -1; } buf += ret; @@ -69,7 +66,7 @@ int sock_recv_all(int sock_fd, uint8_t* buf, int len) { ssize_t ret; OSI_NO_INTR(ret = recv(sock_fd, buf, r, MSG_WAITALL)); if (ret <= 0) { - BTIF_TRACE_ERROR("sock fd:%d recv errno:%d, ret:%d", sock_fd, errno, ret); + LOG_ERROR("sock fd:%d recv errno:%d, ret:%zd", sock_fd, errno, ret); return -1; } buf += ret; @@ -112,8 +109,8 @@ int sock_send_fd(int sock_fd, const uint8_t* buf, int len, int send_fd) { ssize_t ret; OSI_NO_INTR(ret = sendmsg(sock_fd, &msg, MSG_NOSIGNAL)); if (ret < 0) { - BTIF_TRACE_ERROR("fd:%d, send_fd:%d, sendmsg ret:%d, errno:%d, %s", - sock_fd, send_fd, (int)ret, errno, strerror(errno)); + LOG_ERROR("fd:%d, send_fd:%d, sendmsg ret:%d, errno:%d, %s", sock_fd, + send_fd, (int)ret, errno, strerror(errno)); ret_len = -1; break; } @@ -124,7 +121,7 @@ int sock_send_fd(int sock_fd, const uint8_t* buf, int len, int send_fd) { // Wipes out any msg_control too memset(&msg, 0, sizeof(msg)); } - BTIF_TRACE_DEBUG("close fd:%d after sent", send_fd); + LOG_VERBOSE("close fd:%d after sent", send_fd); // TODO: This seems wrong - if the FD is not opened in JAVA before this is // called // we get a "socket closed" exception in java, when reading from the diff --git a/system/btif/src/btif_storage.cc b/system/btif/src/btif_storage.cc index 4fd1fdaf55b3777e00336f5cbfbfc000566e6203..50a90814b6f7ba6e7c9cf5b7cb34a35506742308 100644 --- a/system/btif/src/btif_storage.cc +++ b/system/btif/src/btif_storage.cc @@ -34,7 +34,6 @@ #include #include -#include #include #include #include @@ -45,20 +44,14 @@ #include "btif/include/stack_manager.h" #include "btif_api.h" #include "btif_config.h" -#include "btif_hd.h" -#include "btif_hh.h" #include "btif_storage.h" #include "btif_util.h" #include "core_callbacks.h" #include "device/include/controller.h" -#include "gd/common/init_flags.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" -#include "osi/include/compat.h" -#include "osi/include/config.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_octets.h" -#include "stack/include/btu.h" +#include "stack/include/bt_uuid16.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -72,48 +65,70 @@ using bluetooth::Uuid; // TODO(armansito): Find a better way than using a hardcoded path. #define BTIF_STORAGE_PATH_BLUEDROID "/data/misc/bluedroid" -// #define BTIF_STORAGE_PATH_ADAPTER_INFO "adapter_info" -// #define BTIF_STORAGE_PATH_REMOTE_DEVICES "remote_devices" -#define BTIF_STORAGE_PATH_REMOTE_DEVTIME "Timestamp" -#define BTIF_STORAGE_PATH_REMOTE_DEVCLASS "DevClass" -#define BTIF_STORAGE_PATH_REMOTE_DEVTYPE "DevType" -#define BTIF_STORAGE_PATH_REMOTE_NAME "Name" -#define BTIF_STORAGE_PATH_REMOTE_APPEARANCE "Appearance" - -// #define BTIF_STORAGE_PATH_REMOTE_LINKKEYS "remote_linkkeys" -#define BTIF_STORAGE_PATH_REMOTE_ALIASE "Aliase" -#define BTIF_STORAGE_KEY_ADAPTER_NAME "Name" -#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode" +#define BTIF_STORAGE_SECTION_ADAPTER "Adapter" + +#define BTIF_STORAGE_KEY_LE_LOCAL_KEY_IR "LE_LOCAL_KEY_IR" +#define BTIF_STORAGE_KEY_LE_LOCAL_KEY_IRK "LE_LOCAL_KEY_IRK" +#define BTIF_STORAGE_KEY_LE_LOCAL_KEY_DHK "LE_LOCAL_KEY_DHK" +#define BTIF_STORAGE_KEY_LE_LOCAL_KEY_ER "LE_LOCAL_KEY_ER" + +#define BTIF_STORAGE_KEY_TIMESTAMP "Timestamp" +#define BTIF_STORAGE_KEY_DEV_CLASS "DevClass" +#define BTIF_STORAGE_KEY_DEV_TYPE "DevType" +#define BTIF_STORAGE_KEY_NAME "Name" +#define BTIF_STORAGE_KEY_APPEARANCE "Appearance" +#define BTIF_STORAGE_KEY_ADDR_TYPE "AddrType" +#define BTIF_STORAGE_KEY_ALIASE "Aliase" +#define BTIF_STORAGE_KEY_SCANMODE "ScanMode" #define BTIF_STORAGE_KEY_LOCAL_IO_CAPS "LocalIOCaps" -#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout" +#define BTIF_STORAGE_KEY_DISC_TIMEOUT "DiscoveryTimeout" #define BTIF_STORAGE_KEY_GATT_CLIENT_SUPPORTED "GattClientSupportedFeatures" #define BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH "GattClientDatabaseHash" #define BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED "GattServerSupportedFeatures" - -#define BTIF_STORAGE_PATH_VENDOR_ID_SOURCE "VendorIdSource" -#define BTIF_STORAGE_PATH_VENDOR_ID "VendorId" -#define BTIF_STORAGE_PATH_PRODUCT_ID "ProductId" -#define BTIF_STORAGE_PATH_VERSION "ProductVersion" +#define BTIF_STORAGE_KEY_LINK_KEY "LinkKey" +#define BTIF_STORAGE_KEY_LINK_KEY_TYPE "LinkKeyType" +#define BTIF_STORAGE_KEY_PIN_LENGTH "PinLength" +#define BTIF_STORAGE_KEY_LE_KEY_PENC "LE_KEY_PENC" +#define BTIF_STORAGE_KEY_LE_KEY_PID "LE_KEY_PID" +#define BTIF_STORAGE_KEY_LE_KEY_PCSRK "LE_KEY_PCSRK" +#define BTIF_STORAGE_KEY_LE_KEY_LENC "LE_KEY_LENC" +#define BTIF_STORAGE_KEY_LE_KEY_LCSRK "LE_KEY_LCSRK" +#define BTIF_STORAGE_KEY_LE_KEY_LID "LE_KEY_LID" +#define BTIF_STORAGE_KEY_VENDOR_ID_SOURCE "VendorIdSource" +#define BTIF_STORAGE_KEY_VENDOR_ID "VendorId" +#define BTIF_STORAGE_KEY_PRODUCT_ID "ProductId" +#define BTIF_STORAGE_KEY_VERSION "ProductVersion" +#define BTIF_STORAGE_KEY_RESTRICTED "Restricted" +#define BTIF_STORAGE_KEY_ADDR_TYPE "AddrType" /* This is a local property to add a device found */ #define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF -/* <18 char bd addr> LIST< <36 char uuid> <;> > - */ -#define BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX \ - (STORAGE_BDADDR_STRING_SZ + 1 + \ - STORAGE_UUID_STRING_SIZE * BT_MAX_NUM_UUIDS + \ - STORAGE_PINLEN_STRING_MAX_SIZE + STORAGE_KEYTYPE_STRING_MAX_SIZE) - -#define STORAGE_REMOTE_LINKKEYS_ENTRY_SIZE (LINK_KEY_LEN * 2 + 1 + 2 + 1 + 2) - -/* currently remote services is the potentially largest entry */ -#define BTIF_STORAGE_MAX_LINE_SZ BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX - -/* check against unv max entry size at compile time */ -#if (BTIF_STORAGE_ENTRY_MAX_SIZE > UNV_MAXLINE_LENGTH) -#error "btif storage entry size exceeds unv max line size" -#endif +struct BtifStorageKey { + uint8_t type; + const std::string& name; + uint8_t size; +}; +static const BtifStorageKey BTIF_STORAGE_LE_KEYS[] = { + {BTM_LE_KEY_PENC, BTIF_STORAGE_KEY_LE_KEY_PENC, sizeof(tBTM_LE_PENC_KEYS)}, + {BTM_LE_KEY_PID, BTIF_STORAGE_KEY_LE_KEY_PID, sizeof(tBTM_LE_PID_KEYS)}, + {BTM_LE_KEY_PCSRK, BTIF_STORAGE_KEY_LE_KEY_PCSRK, + sizeof(tBTM_LE_PCSRK_KEYS)}, + {BTM_LE_KEY_LENC, BTIF_STORAGE_KEY_LE_KEY_LENC, sizeof(tBTM_LE_LENC_KEYS)}, + {BTM_LE_KEY_LCSRK, BTIF_STORAGE_KEY_LE_KEY_LCSRK, + sizeof(tBTM_LE_LCSRK_KEYS)}, + {BTM_LE_KEY_LID, BTIF_STORAGE_KEY_LE_KEY_LID, sizeof(tBTM_LE_PID_KEYS)}, +}; +static const BtifStorageKey BTIF_STORAGE_LOCAL_LE_KEYS[] = { + {BTIF_DM_LE_LOCAL_KEY_IR, BTIF_STORAGE_KEY_LE_LOCAL_KEY_IR, + sizeof(Octet16)}, + {BTIF_DM_LE_LOCAL_KEY_IRK, BTIF_STORAGE_KEY_LE_LOCAL_KEY_IRK, + sizeof(Octet16)}, + {BTIF_DM_LE_LOCAL_KEY_DHK, BTIF_STORAGE_KEY_LE_LOCAL_KEY_DHK, + sizeof(Octet16)}, + {BTIF_DM_LE_LOCAL_KEY_ER, BTIF_STORAGE_KEY_LE_LOCAL_KEY_ER, + sizeof(Octet16)}, +}; /******************************************************************************* * External functions @@ -131,7 +146,16 @@ static bool btif_has_ble_keys(const std::string& bdstr); * Static functions ******************************************************************************/ -static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) { +static void btif_storage_set_mode(RawAddress* remote_bd_addr) { + std::string bdstr = remote_bd_addr->ToString(); + if (GetInterfaceToProfiles()->config->isRestrictedMode()) { + LOG_INFO("%s will be removed exiting restricted mode", + ADDRESS_TO_LOGGABLE_CSTR(*remote_bd_addr)); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_RESTRICTED, 1); + } +} + +static bool prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) { std::string bdstr; if (remote_bd_addr) { bdstr = remote_bd_addr->ToString(); @@ -147,8 +171,7 @@ static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) { } switch (prop->type) { case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP: - btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME, - (int)time(NULL)); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_TIMESTAMP, (int)time(NULL)); break; case BT_PROPERTY_BDNAME: { int name_length = prop->len > BTM_MAX_LOC_BD_NAME_LEN @@ -157,36 +180,35 @@ static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) { strncpy(value, (char*)prop->val, name_length); value[name_length] = '\0'; if (remote_bd_addr) { - btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME, value); + btif_config_set_str(bdstr, BTIF_STORAGE_KEY_NAME, value); } else { - btif_config_set_str("Adapter", BTIF_STORAGE_KEY_ADAPTER_NAME, value); + btif_config_set_str(BTIF_STORAGE_SECTION_ADAPTER, BTIF_STORAGE_KEY_NAME, + value); } break; } case BT_PROPERTY_REMOTE_FRIENDLY_NAME: strncpy(value, (char*)prop->val, prop->len); value[prop->len] = '\0'; - btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE, value); + btif_config_set_str(bdstr, BTIF_STORAGE_KEY_ALIASE, value); break; case BT_PROPERTY_ADAPTER_SCAN_MODE: - btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE, - *(int*)prop->val); + btif_config_set_int(BTIF_STORAGE_SECTION_ADAPTER, + BTIF_STORAGE_KEY_SCANMODE, *(int*)prop->val); break; case BT_PROPERTY_LOCAL_IO_CAPS: - btif_config_set_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS, - *(int*)prop->val); + btif_config_set_int(BTIF_STORAGE_SECTION_ADAPTER, + BTIF_STORAGE_KEY_LOCAL_IO_CAPS, *(int*)prop->val); break; case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT: - btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT, - *(int*)prop->val); + btif_config_set_int(BTIF_STORAGE_SECTION_ADAPTER, + BTIF_STORAGE_KEY_DISC_TIMEOUT, *(int*)prop->val); break; case BT_PROPERTY_CLASS_OF_DEVICE: - btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVCLASS, - *(int*)prop->val); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_DEV_CLASS, *(int*)prop->val); break; case BT_PROPERTY_TYPE_OF_DEVICE: - btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE, - *(int*)prop->val); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_DEV_TYPE, *(int*)prop->val); break; case BT_PROPERTY_UUIDS: { std::string val; @@ -210,18 +232,17 @@ static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) { } break; case BT_PROPERTY_APPEARANCE: { int val = *(uint16_t*)prop->val; - btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_APPEARANCE, val); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_APPEARANCE, val); } break; case BT_PROPERTY_VENDOR_PRODUCT_INFO: { bt_vendor_product_info_t* info = (bt_vendor_product_info_t*)prop->val; if (!info) return false; - btif_config_set_int(bdstr, BTIF_STORAGE_PATH_VENDOR_ID_SOURCE, + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_VENDOR_ID_SOURCE, info->vendor_id_src); - btif_config_set_int(bdstr, BTIF_STORAGE_PATH_VENDOR_ID, info->vendor_id); - btif_config_set_int(bdstr, BTIF_STORAGE_PATH_PRODUCT_ID, - info->product_id); - btif_config_set_int(bdstr, BTIF_STORAGE_PATH_VERSION, info->version); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_VENDOR_ID, info->vendor_id); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_PRODUCT_ID, info->product_id); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_VERSION, info->version); } break; case BT_PROPERTY_REMOTE_MODEL_NUM: { strncpy(value, (char*)prop->val, prop->len); @@ -229,14 +250,14 @@ static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) { btif_config_set_str(bdstr, BT_CONFIG_KEY_DIS_MODEL_NUM, value); } break; default: - BTIF_TRACE_ERROR("Unknown prop type:%d", prop->type); + LOG_ERROR("Unknown prop type:%d", prop->type); return false; } return true; } -static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { +static bool cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { std::string bdstr; if (remote_bd_addr) { bdstr = remote_bd_addr->ToString(); @@ -246,21 +267,22 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { prop->type, prop->len); return false; } - int ret = false; + bool ret = false; switch (prop->type) { case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP: if (prop->len >= (int)sizeof(int)) - ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME, + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_TIMESTAMP, (int*)prop->val); break; case BT_PROPERTY_BDNAME: { int len = prop->len; if (remote_bd_addr) - ret = btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME, + ret = btif_config_get_str(bdstr, BTIF_STORAGE_KEY_NAME, (char*)prop->val, &len); else - ret = btif_config_get_str("Adapter", BTIF_STORAGE_KEY_ADAPTER_NAME, - (char*)prop->val, &len); + ret = + btif_config_get_str(BTIF_STORAGE_SECTION_ADAPTER, + BTIF_STORAGE_KEY_NAME, (char*)prop->val, &len); if (ret && len && len <= prop->len) prop->len = len - 1; else { @@ -271,7 +293,7 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { } case BT_PROPERTY_REMOTE_FRIENDLY_NAME: { int len = prop->len; - ret = btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE, + ret = btif_config_get_str(bdstr, BTIF_STORAGE_KEY_ALIASE, (char*)prop->val, &len); if (ret && len && len <= prop->len) prop->len = len - 1; @@ -283,28 +305,30 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { } case BT_PROPERTY_ADAPTER_SCAN_MODE: if (prop->len >= (int)sizeof(int)) - ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE, - (int*)prop->val); + ret = btif_config_get_int(BTIF_STORAGE_SECTION_ADAPTER, + BTIF_STORAGE_KEY_SCANMODE, (int*)prop->val); break; case BT_PROPERTY_LOCAL_IO_CAPS: if (prop->len >= (int)sizeof(int)) - ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_LOCAL_IO_CAPS, + ret = btif_config_get_int(BTIF_STORAGE_SECTION_ADAPTER, + BTIF_STORAGE_KEY_LOCAL_IO_CAPS, (int*)prop->val); break; case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT: if (prop->len >= (int)sizeof(int)) - ret = btif_config_get_int( - "Adapter", BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT, (int*)prop->val); + ret = + btif_config_get_int(BTIF_STORAGE_SECTION_ADAPTER, + BTIF_STORAGE_KEY_DISC_TIMEOUT, (int*)prop->val); break; case BT_PROPERTY_CLASS_OF_DEVICE: if (prop->len >= (int)sizeof(int)) - ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVCLASS, + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_DEV_CLASS, (int*)prop->val); break; case BT_PROPERTY_TYPE_OF_DEVICE: if (prop->len >= (int)sizeof(int)) - ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE, + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_DEV_TYPE, (int*)prop->val); break; case BT_PROPERTY_UUIDS: { @@ -344,8 +368,7 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { int val; if (prop->len >= (int)sizeof(uint16_t)) { - ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_APPEARANCE, - &val); + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_APPEARANCE, &val); *(uint16_t*)prop->val = (uint16_t)val; } } break; @@ -355,20 +378,20 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { int val; if (prop->len >= (int)sizeof(bt_vendor_product_info_t)) { - ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_VENDOR_ID_SOURCE, - &val); + ret = + btif_config_get_int(bdstr, BTIF_STORAGE_KEY_VENDOR_ID_SOURCE, &val); info->vendor_id_src = (uint8_t)val; if (ret) { - ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_VENDOR_ID, &val); + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_VENDOR_ID, &val); info->vendor_id = (uint16_t)val; } if (ret) { - ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_PRODUCT_ID, &val); + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_PRODUCT_ID, &val); info->product_id = (uint16_t)val; } if (ret) { - ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_VERSION, &val); + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_VERSION, &val); info->version = (uint16_t)val; } } @@ -386,8 +409,17 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) { } } break; + case BT_PROPERTY_REMOTE_ADDR_TYPE: { + int val; + + if (prop->len >= (int)sizeof(uint8_t)) { + ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_ADDR_TYPE, &val); + *(uint8_t*)prop->val = (uint8_t)val; + } + } break; + default: - BTIF_TRACE_ERROR("Unknow prop type:%d", prop->type); + LOG_ERROR("Unknown prop type:%d", prop->type); return false; } return ret; @@ -408,9 +440,11 @@ bt_status_t btif_in_fetch_bonded_device(const std::string& bdstr) { LinkKey link_key; size_t size = link_key.size(); - if (btif_config_get_bin(bdstr, "LinkKey", link_key.data(), &size)) { + if (btif_config_get_bin(bdstr, BTIF_STORAGE_KEY_LINK_KEY, link_key.data(), + &size)) { int linkkey_type; - if (btif_config_get_int(bdstr, "LinkKeyType", &linkkey_type)) { + if (btif_config_get_int(bdstr, BTIF_STORAGE_KEY_LINK_KEY_TYPE, + &linkkey_type)) { bt_linkkey_file_found = true; } else { bt_linkkey_file_found = false; @@ -444,23 +478,26 @@ static bt_status_t btif_in_fetch_bonded_devices( for (const auto& bd_addr : btif_config_get_paired_devices()) { auto name = bd_addr.ToString(); - BTIF_TRACE_DEBUG("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("Remote device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); LinkKey link_key; size_t size = sizeof(link_key); - if (btif_config_get_bin(name, "LinkKey", link_key.data(), &size)) { + if (btif_config_get_bin(name, BTIF_STORAGE_KEY_LINK_KEY, link_key.data(), + &size)) { int linkkey_type; - if (btif_config_get_int(name, "LinkKeyType", &linkkey_type)) { + if (btif_config_get_int(name, BTIF_STORAGE_KEY_LINK_KEY_TYPE, + &linkkey_type)) { if (add) { DEV_CLASS dev_class = {0, 0, 0}; int cod; int pin_length = 0; - if (btif_config_get_int(name, "DevClass", &cod)) + if (btif_config_get_int(name, BTIF_STORAGE_KEY_DEV_CLASS, &cod)) uint2devclass((uint32_t)cod, dev_class); - btif_config_get_int(name, "PinLength", &pin_length); + btif_config_get_int(name, BTIF_STORAGE_KEY_PIN_LENGTH, &pin_length); BTA_DmAddDevice(bd_addr, dev_class, link_key, (uint8_t)linkkey_type, pin_length); - if (btif_config_get_int(name, "DevType", &device_type) && + if (btif_config_get_int(name, BTIF_STORAGE_KEY_DEV_TYPE, + &device_type) && (device_type == BT_DEVICE_TYPE_DUMO)) { btif_gatts_add_bonded_dev_from_nv(bd_addr); } @@ -469,8 +506,7 @@ static bt_status_t btif_in_fetch_bonded_devices( if (p_bonded_devices->num_devices < BTM_SEC_MAX_DEVICE_RECORDS) { p_bonded_devices->devices[p_bonded_devices->num_devices++] = bd_addr; } else { - BTIF_TRACE_WARNING("%s: exceed the max number of bonded devices", - __func__); + LOG_WARN("Exceed the max number of bonded devices"); } } else { bt_linkkey_file_found = false; @@ -478,7 +514,8 @@ static bt_status_t btif_in_fetch_bonded_devices( } if (!btif_in_fetch_bonded_ble_device(name, add, p_bonded_devices) && !bt_linkkey_file_found) { - LOG_VERBOSE("No link key or ble key found for device:%s", name.c_str()); + LOG_VERBOSE("No link key or ble key found for device:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } } return BT_STATUS_SUCCESS; @@ -502,8 +539,8 @@ static void btif_read_le_key(const uint8_t key_type, const size_t key_len, *device_added = true; } - BTIF_TRACE_DEBUG("%s() Adding key type %d for %s", __func__, key_type, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("Adding key type %d for %s", key_type, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); BTA_DmAddBleKey(bd_addr, &key, key_type); } @@ -584,9 +621,9 @@ static uint8_t btif_storage_get_io_cap_property(bt_property_type_t type, * returns BTM_LOCAL_IO_CAPS. * ******************************************************************************/ -uint8_t btif_storage_get_local_io_caps() { - return btif_storage_get_io_cap_property(BT_PROPERTY_LOCAL_IO_CAPS, - BTM_LOCAL_IO_CAPS); +tBTM_IO_CAP btif_storage_get_local_io_caps() { + return static_cast(btif_storage_get_io_cap_property( + BT_PROPERTY_LOCAL_IO_CAPS, BTM_LOCAL_IO_CAPS)); } /** Helper function for fetching a bt_property of the adapter. */ @@ -618,12 +655,11 @@ bt_status_t btif_storage_get_adapter_property(bt_property_t* property) { /* Fetch the local BD ADDR */ const controller_t* controller = controller_get_interface(); if (!controller->get_is_ready()) { - LOG_ERROR("%s: Controller not ready! Unable to return Bluetooth Address", - __func__); + LOG_ERROR("Controller not ready! Unable to return Bluetooth Address"); *bd_addr = RawAddress::kEmpty; return BT_STATUS_FAIL; } else { - LOG_ERROR("%s: Controller ready!", __func__); + LOG_INFO("Controller ready!"); *bd_addr = *controller->get_address(); } property->len = RawAddress::kLength; @@ -633,10 +669,9 @@ bt_status_t btif_storage_get_adapter_property(bt_property_t* property) { btif_in_fetch_bonded_devices(&bonded_devices, 0); - BTIF_TRACE_DEBUG( - "%s: Number of bonded devices: %d " - "Property:BT_PROPERTY_ADAPTER_BONDED_DEVICES", - __func__, bonded_devices.num_devices); + LOG_VERBOSE( + "BT_PROPERTY_ADAPTER_BONDED_DEVICES: Number of bonded devices=%d", + bonded_devices.num_devices); property->len = bonded_devices.num_devices * RawAddress::kLength; memcpy(property->val, bonded_devices.devices, property->len); @@ -650,7 +685,7 @@ bt_status_t btif_storage_get_adapter_property(bt_property_t* property) { uint32_t i; tBTA_SERVICE_MASK service_mask = btif_get_enabled_services_mask(); - LOG_INFO("%s service_mask:0x%x", __func__, service_mask); + LOG_INFO("Service_mask=0x%x", service_mask); for (i = 0; i < BTA_MAX_SERVICE_ID; i++) { /* This should eventually become a function when more services are enabled */ @@ -832,17 +867,16 @@ bt_status_t btif_storage_add_bonded_device(RawAddress* remote_bd_addr, LinkKey link_key, uint8_t key_type, uint8_t pin_length) { std::string bdstr = remote_bd_addr->ToString(); - int ret = btif_config_set_int(bdstr, "LinkKeyType", (int)key_type); - ret &= btif_config_set_int(bdstr, "PinLength", (int)pin_length); + bool ret = + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_LINK_KEY_TYPE, (int)key_type); ret &= - btif_config_set_bin(bdstr, "LinkKey", link_key.data(), link_key.size()); + btif_config_set_int(bdstr, BTIF_STORAGE_KEY_PIN_LENGTH, (int)pin_length); + ret &= btif_config_set_bin(bdstr, BTIF_STORAGE_KEY_LINK_KEY, link_key.data(), + link_key.size()); - if (GetInterfaceToProfiles()->config->isRestrictedMode()) { - BTIF_TRACE_WARNING("%s: '%s' pairing will be removed if unrestricted", - __func__, ADDRESS_TO_LOGGABLE_CSTR(*remote_bd_addr)); - btif_config_set_int(bdstr, "Restricted", 1); + if (ret) { + btif_storage_set_mode(remote_bd_addr); } - return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; } @@ -859,30 +893,10 @@ bt_status_t btif_storage_add_bonded_device(RawAddress* remote_bd_addr, bt_status_t btif_storage_remove_bonded_device( const RawAddress* remote_bd_addr) { std::string bdstr = remote_bd_addr->ToString(); - LOG_INFO("Removing bonded device addr:%s", + LOG_INFO("Removing bonded device addr=%s", ADDRESS_TO_LOGGABLE_CSTR(*remote_bd_addr)); - btif_storage_remove_ble_bonding_keys(remote_bd_addr); - - int ret = 1; - if (btif_config_exist(bdstr, "LinkKeyType")) - ret &= btif_config_remove(bdstr, "LinkKeyType"); - if (btif_config_exist(bdstr, "PinLength")) - ret &= btif_config_remove(bdstr, "PinLength"); - if (btif_config_exist(bdstr, "LinkKey")) - ret &= btif_config_remove(bdstr, "LinkKey"); - if (btif_config_exist(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE)) { - ret &= btif_config_remove(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE); - } - if (btif_config_exist(bdstr, BTIF_STORAGE_KEY_GATT_CLIENT_SUPPORTED)) { - ret &= btif_config_remove(bdstr, BTIF_STORAGE_KEY_GATT_CLIENT_SUPPORTED); - } - if (btif_config_exist(bdstr, BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH)) { - ret &= btif_config_remove(bdstr, BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH); - } - if (btif_config_exist(bdstr, BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED)) { - ret &= btif_config_remove(bdstr, BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED); - } + btif_config_remove_device(bdstr); /* Check the length of the paired devices, and if 0 then reset IRK */ auto paired_devices = btif_config_get_paired_devices(); @@ -891,7 +905,7 @@ bt_status_t btif_storage_remove_bonded_device( LOG_INFO("Last paired device removed, resetting IRK"); BTA_DmBleResetId(); } - return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + return BT_STATUS_SUCCESS; } /* Some devices hardcode sample LTK value from spec, instead of generating one. @@ -919,8 +933,8 @@ static void remove_devices_with_sample_ltk() { } for (RawAddress address : bad_ltk) { - LOG(ERROR) << __func__ << ": removing bond to device using test TLK: " - << ADDRESS_TO_LOGGABLE_STR(address); + LOG_ERROR("Removing bond to device using test TLK: %s", + ADDRESS_TO_LOGGABLE_CSTR(address)); btif_storage_remove_bonded_device(&address); } @@ -954,7 +968,7 @@ void btif_storage_load_le_devices(void) { bonded_devices.devices[i], BTM_LE_KEY_PID, (uint8_t*)&key, sizeof(tBTM_LE_PID_KEYS)) == BT_STATUS_SUCCESS) { if (bonded_devices.devices[i] != key.pid_key.identity_addr) { - LOG_INFO("found device with a known identity address %s %s", + LOG_INFO("Found device with a known identity address %s %s", ADDRESS_TO_LOGGABLE_CSTR(bonded_devices.devices[i]), ADDRESS_TO_LOGGABLE_CSTR(key.pid_key.identity_addr)); @@ -1087,8 +1101,7 @@ bt_status_t btif_storage_load_bonded_devices(void) { osi_free(devices_list); } - BTIF_TRACE_EVENT("%s: %d bonded devices found", __func__, - bonded_devices.num_devices); + LOG_VERBOSE("Number of bonded devices found=%d", bonded_devices.num_devices); { for (i = 0; i < bonded_devices.num_devices; i++) { @@ -1145,6 +1158,15 @@ bt_status_t btif_storage_load_bonded_devices(void) { &remote_properties[num_props]) == BT_STATUS_SUCCESS) { num_props++; } + + // Floss needs address type for diagnosis API + uint8_t addr_type; + if (btif_storage_get_remote_prop( + p_remote_addr, BT_PROPERTY_REMOTE_ADDR_TYPE, &addr_type, + sizeof(addr_type), + &remote_properties[num_props]) == BT_STATUS_SUCCESS) { + num_props++; + } #endif btif_storage_get_remote_prop(p_remote_addr, BT_PROPERTY_REMOTE_MODEL_NUM, @@ -1172,35 +1194,24 @@ bt_status_t btif_storage_load_bonded_devices(void) { ******************************************************************************/ bt_status_t btif_storage_add_ble_bonding_key(RawAddress* remote_bd_addr, - const uint8_t* key, + const uint8_t* key_value, uint8_t key_type, uint8_t key_length) { - const char* name; - switch (key_type) { - case BTM_LE_KEY_PENC: - name = "LE_KEY_PENC"; - break; - case BTM_LE_KEY_PID: - name = "LE_KEY_PID"; - break; - case BTM_LE_KEY_PCSRK: - name = "LE_KEY_PCSRK"; - break; - case BTM_LE_KEY_LENC: - name = "LE_KEY_LENC"; - break; - case BTM_LE_KEY_LCSRK: - name = "LE_KEY_LCSRK"; - break; - case BTM_LE_KEY_LID: - name = "LE_KEY_LID"; - break; - default: - return BT_STATUS_FAIL; + for (size_t i = 0; i < std::size(BTIF_STORAGE_LE_KEYS); i++) { + auto key = BTIF_STORAGE_LE_KEYS[i]; + if (key.type == key_type) { + bool ret = btif_config_set_bin(remote_bd_addr->ToString(), key.name, + key_value, key_length); + + if (ret) { + btif_storage_set_mode(remote_bd_addr); + } + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + } } - int ret = - btif_config_set_bin(remote_bd_addr->ToString(), name, key, key_length); - return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + + LOG_WARN("Unknown LE key type: %d", key_type); + return BT_STATUS_FAIL; } /******************************************************************************* @@ -1217,33 +1228,18 @@ bt_status_t btif_storage_get_ble_bonding_key(const RawAddress& remote_bd_addr, uint8_t key_type, uint8_t* key_value, int key_length) { - const char* name; - switch (key_type) { - case BTM_LE_KEY_PENC: - name = "LE_KEY_PENC"; - break; - case BTM_LE_KEY_PID: - name = "LE_KEY_PID"; - break; - case BTM_LE_KEY_PCSRK: - name = "LE_KEY_PCSRK"; - break; - case BTM_LE_KEY_LENC: - name = "LE_KEY_LENC"; - break; - case BTM_LE_KEY_LCSRK: - name = "LE_KEY_LCSRK"; - break; - case BTM_LE_KEY_LID: - name = "LE_KEY_LID"; - break; - default: - return BT_STATUS_FAIL; + for (size_t i = 0; i < std::size(BTIF_STORAGE_LE_KEYS); i++) { + auto key = BTIF_STORAGE_LE_KEYS[i]; + if (key.type == key_type) { + size_t length = key_length; + bool ret = btif_config_get_bin(remote_bd_addr.ToString(), key.name, + key_value, &length); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + } } - size_t length = key_length; - int ret = - btif_config_get_bin(remote_bd_addr.ToString(), name, key_value, &length); - return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + + LOG_WARN("Unknown LE key type: %d", key_type); + return BT_STATUS_FAIL; } /******************************************************************************* @@ -1261,17 +1257,13 @@ bt_status_t btif_storage_remove_ble_bonding_keys( std::string bdstr = remote_bd_addr->ToString(); LOG_INFO("Removing bonding keys for bd addr:%s", ADDRESS_TO_LOGGABLE_CSTR(*remote_bd_addr)); - int ret = 1; - if (btif_config_exist(bdstr, "LE_KEY_PENC")) - ret &= btif_config_remove(bdstr, "LE_KEY_PENC"); - if (btif_config_exist(bdstr, "LE_KEY_PID")) - ret &= btif_config_remove(bdstr, "LE_KEY_PID"); - if (btif_config_exist(bdstr, "LE_KEY_PCSRK")) - ret &= btif_config_remove(bdstr, "LE_KEY_PCSRK"); - if (btif_config_exist(bdstr, "LE_KEY_LENC")) - ret &= btif_config_remove(bdstr, "LE_KEY_LENC"); - if (btif_config_exist(bdstr, "LE_KEY_LCSRK")) - ret &= btif_config_remove(bdstr, "LE_KEY_LCSRK"); + bool ret = true; + for (size_t i = 0; i < std::size(BTIF_STORAGE_LE_KEYS); i++) { + auto key_name = BTIF_STORAGE_LE_KEYS[i].name; + if (btif_config_exist(bdstr, key_name)) + ret &= btif_config_remove(bdstr, key_name); + } + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; } @@ -1285,27 +1277,19 @@ bt_status_t btif_storage_remove_ble_bonding_keys( * BT_STATUS_FAIL otherwise * ******************************************************************************/ -bt_status_t btif_storage_add_ble_local_key(const Octet16& key, +bt_status_t btif_storage_add_ble_local_key(const Octet16& key_value, uint8_t key_type) { - const char* name; - switch (key_type) { - case BTIF_DM_LE_LOCAL_KEY_IR: - name = "LE_LOCAL_KEY_IR"; - break; - case BTIF_DM_LE_LOCAL_KEY_IRK: - name = "LE_LOCAL_KEY_IRK"; - break; - case BTIF_DM_LE_LOCAL_KEY_DHK: - name = "LE_LOCAL_KEY_DHK"; - break; - case BTIF_DM_LE_LOCAL_KEY_ER: - name = "LE_LOCAL_KEY_ER"; - break; - default: - return BT_STATUS_FAIL; + for (size_t i = 0; i < std::size(BTIF_STORAGE_LOCAL_LE_KEYS); i++) { + auto key = BTIF_STORAGE_LOCAL_LE_KEYS[i]; + if (key.type == key_type) { + bool ret = btif_config_set_bin(BTIF_STORAGE_SECTION_ADAPTER, key.name, + key_value.data(), key_value.size()); + + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + } } - int ret = btif_config_set_bin("Adapter", name, key.data(), key.size()); - return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + LOG_WARN("Unknown LE key type: %d", key_type); + return BT_STATUS_FAIL; } /** Stores local key of |key_type| into |key_value| @@ -1314,26 +1298,18 @@ bt_status_t btif_storage_add_ble_local_key(const Octet16& key, */ bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, Octet16* key_value) { - const char* name; - switch (key_type) { - case BTIF_DM_LE_LOCAL_KEY_IR: - name = "LE_LOCAL_KEY_IR"; - break; - case BTIF_DM_LE_LOCAL_KEY_IRK: - name = "LE_LOCAL_KEY_IRK"; - break; - case BTIF_DM_LE_LOCAL_KEY_DHK: - name = "LE_LOCAL_KEY_DHK"; - break; - case BTIF_DM_LE_LOCAL_KEY_ER: - name = "LE_LOCAL_KEY_ER"; - break; - default: - return BT_STATUS_FAIL; + for (size_t i = 0; i < std::size(BTIF_STORAGE_LOCAL_LE_KEYS); i++) { + auto key = BTIF_STORAGE_LOCAL_LE_KEYS[i]; + if (key.type == key_type) { + size_t length = key_value->size(); + bool ret = btif_config_get_bin(BTIF_STORAGE_SECTION_ADAPTER, key.name, + key_value->data(), &length); + + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + } } - size_t length = key_value->size(); - int ret = btif_config_get_bin("Adapter", name, key_value->data(), &length); - return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + LOG_WARN("Unknown LE key type: %d", key_type); + return BT_STATUS_FAIL; } /******************************************************************************* @@ -1347,15 +1323,12 @@ bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, * ******************************************************************************/ bt_status_t btif_storage_remove_ble_local_keys(void) { - int ret = 1; - if (btif_config_exist("Adapter", "LE_LOCAL_KEY_IR")) - ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_IR"); - if (btif_config_exist("Adapter", "LE_LOCAL_KEY_IRK")) - ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_IRK"); - if (btif_config_exist("Adapter", "LE_LOCAL_KEY_DHK")) - ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_DHK"); - if (btif_config_exist("Adapter", "LE_LOCAL_KEY_ER")) - ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_ER"); + bool ret = true; + for (size_t i = 0; i < std::size(BTIF_STORAGE_LOCAL_LE_KEYS); i++) { + auto key = BTIF_STORAGE_LOCAL_LE_KEYS[i]; + if (btif_config_exist(BTIF_STORAGE_SECTION_ADAPTER, key.name)) + ret &= btif_config_remove(BTIF_STORAGE_SECTION_ADAPTER, key.name); + } return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; } @@ -1366,17 +1339,17 @@ bt_status_t btif_in_fetch_bonded_ble_device( tBLE_ADDR_TYPE addr_type; bool device_added = false; bool key_found = false; + RawAddress bd_addr; + + RawAddress::FromString(remote_bd_addr, bd_addr); - if (!btif_config_get_int(remote_bd_addr, "DevType", &device_type)) + if (!btif_config_get_int(remote_bd_addr, BTIF_STORAGE_KEY_DEV_TYPE, + &device_type)) return BT_STATUS_FAIL; if ((device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE || btif_has_ble_keys(remote_bd_addr)) { - BTIF_TRACE_DEBUG("%s Found a LE device: %s", __func__, - remote_bd_addr.c_str()); - - RawAddress bd_addr; - RawAddress::FromString(remote_bd_addr, bd_addr); + LOG_VERBOSE("Found a LE device: %s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); if (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) != BT_STATUS_SUCCESS) { @@ -1384,31 +1357,18 @@ bt_status_t btif_in_fetch_bonded_ble_device( btif_storage_set_remote_addr_type(&bd_addr, BLE_ADDR_PUBLIC); } - btif_read_le_key(BTM_LE_KEY_PENC, sizeof(tBTM_LE_PENC_KEYS), bd_addr, - addr_type, add, &device_added, &key_found); - - btif_read_le_key(BTM_LE_KEY_PID, sizeof(tBTM_LE_PID_KEYS), bd_addr, - addr_type, add, &device_added, &key_found); - - btif_read_le_key(BTM_LE_KEY_LID, sizeof(tBTM_LE_PID_KEYS), bd_addr, - addr_type, add, &device_added, &key_found); - - btif_read_le_key(BTM_LE_KEY_PCSRK, sizeof(tBTM_LE_PCSRK_KEYS), bd_addr, - addr_type, add, &device_added, &key_found); - - btif_read_le_key(BTM_LE_KEY_LENC, sizeof(tBTM_LE_LENC_KEYS), bd_addr, - addr_type, add, &device_added, &key_found); - - btif_read_le_key(BTM_LE_KEY_LCSRK, sizeof(tBTM_LE_LCSRK_KEYS), bd_addr, - addr_type, add, &device_added, &key_found); + for (size_t i = 0; i < std::size(BTIF_STORAGE_LE_KEYS); i++) { + auto key = BTIF_STORAGE_LE_KEYS[i]; + btif_read_le_key(key.type, key.size, bd_addr, addr_type, add, + &device_added, &key_found); + } // Fill in the bonded devices if (device_added) { if (p_bonded_devices->num_devices < BTM_SEC_MAX_DEVICE_RECORDS) { p_bonded_devices->devices[p_bonded_devices->num_devices++] = bd_addr; } else { - BTIF_TRACE_WARNING("%s: exceed the max number of bonded devices", - __func__); + LOG_WARN("Exceed the max number of bonded devices"); } btif_gatts_add_bonded_dev_from_nv(bd_addr); } @@ -1418,29 +1378,52 @@ bt_status_t btif_in_fetch_bonded_ble_device( return BT_STATUS_FAIL; } +void btif_storage_invoke_addr_type_update(const RawAddress& remote_bd_addr, + const tBLE_ADDR_TYPE& addr_type) { + bt_property_t prop; + prop.type = BT_PROPERTY_REMOTE_ADDR_TYPE; + prop.val = (tBLE_ADDR_TYPE*)&addr_type; + prop.len = sizeof(tBLE_ADDR_TYPE); + GetInterfaceToProfiles()->events->invoke_remote_device_properties_cb( + BT_STATUS_SUCCESS, remote_bd_addr, 1, &prop); +} + bt_status_t btif_storage_set_remote_addr_type(const RawAddress* remote_bd_addr, tBLE_ADDR_TYPE addr_type) { - int ret = btif_config_set_int(remote_bd_addr->ToString(), "AddrType", - (int)addr_type); + bool ret = btif_config_set_int(remote_bd_addr->ToString(), + BTIF_STORAGE_KEY_ADDR_TYPE, (int)addr_type); + +#if TARGET_FLOSS + // Floss needs to get address type for diagnosis API. + btif_storage_invoke_addr_type_update(*remote_bd_addr, addr_type); +#endif + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; } void btif_storage_set_remote_addr_type(const RawAddress& remote_bd_addr, const tBLE_ADDR_TYPE& addr_type) { - if (!btif_config_set_int(remote_bd_addr.ToString(), "AddrType", + if (!btif_config_set_int(remote_bd_addr.ToString(), + BTIF_STORAGE_KEY_ADDR_TYPE, static_cast(addr_type))) LOG_ERROR("Unable to set storage property"); + else { +#if TARGET_FLOSS + // Floss needs to get address type for diagnosis API. + btif_storage_invoke_addr_type_update(remote_bd_addr, addr_type); +#endif + } } void btif_storage_set_remote_device_type(const RawAddress& remote_bd_addr, const tBT_DEVICE_TYPE& device_type) { - if (!btif_config_set_int(remote_bd_addr.ToString(), "DevType", + if (!btif_config_set_int(remote_bd_addr.ToString(), BTIF_STORAGE_KEY_DEV_TYPE, static_cast(device_type))) LOG_ERROR("Unable to set storage property"); } bool btif_has_ble_keys(const std::string& bdstr) { - return btif_config_exist(bdstr, "LE_KEY_PENC"); + return btif_config_exist(bdstr, BTIF_STORAGE_KEY_LE_KEY_PENC); } /******************************************************************************* @@ -1456,7 +1439,8 @@ bool btif_has_ble_keys(const std::string& bdstr) { bt_status_t btif_storage_get_remote_addr_type(const RawAddress* remote_bd_addr, tBLE_ADDR_TYPE* addr_type) { int val; - int ret = btif_config_get_int(remote_bd_addr->ToString(), "AddrType", &val); + bool ret = btif_config_get_int(remote_bd_addr->ToString(), + BTIF_STORAGE_KEY_ADDR_TYPE, &val); *addr_type = static_cast(val); return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; } @@ -1464,8 +1448,8 @@ bt_status_t btif_storage_get_remote_addr_type(const RawAddress* remote_bd_addr, bool btif_storage_get_remote_addr_type(const RawAddress& remote_bd_addr, tBLE_ADDR_TYPE& addr_type) { int val; - const int ret = - btif_config_get_int(remote_bd_addr.ToString(), "AddrType", &val); + bool ret = btif_config_get_int(remote_bd_addr.ToString(), + BTIF_STORAGE_KEY_ADDR_TYPE, &val); addr_type = static_cast(val); return ret; } @@ -1473,8 +1457,8 @@ bool btif_storage_get_remote_addr_type(const RawAddress& remote_bd_addr, bool btif_storage_get_remote_device_type(const RawAddress& remote_bd_addr, tBT_DEVICE_TYPE& device_type) { int val; - const bool ret = - btif_config_get_int(remote_bd_addr.ToString(), "DevType", &val); + bool ret = btif_config_get_int(remote_bd_addr.ToString(), + BTIF_STORAGE_KEY_DEV_TYPE, &val); device_type = static_cast(val); return ret; } @@ -1500,8 +1484,8 @@ uint8_t btif_storage_get_sr_supp_feat(const RawAddress& bd_addr) { int value = 0; btif_config_get_int(name, BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED, &value); - BTIF_TRACE_DEBUG("Remote device: %s GATT server supported features 0x%02x", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), value); + LOG_VERBOSE("Remote device: %s GATT server supported features 0x%02x", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), value); return value; } @@ -1518,7 +1502,9 @@ uint8_t btif_storage_get_sr_supp_feat(const RawAddress& bd_addr) { * ******************************************************************************/ bool btif_storage_is_restricted_device(const RawAddress* remote_bd_addr) { - return btif_config_exist(remote_bd_addr->ToString(), "Restricted"); + int val; + return btif_config_get_int(remote_bd_addr->ToString(), + BTIF_STORAGE_KEY_RESTRICTED, &val); } int btif_storage_get_num_bonded_devices(void) { @@ -1560,8 +1546,8 @@ uint8_t btif_storage_get_gatt_cl_supp_feat(const RawAddress& bd_addr) { int value = 0; btif_config_get_int(name, BTIF_STORAGE_KEY_GATT_CLIENT_SUPPORTED, &value); - BTIF_TRACE_DEBUG("Remote device: %s GATT client supported features 0x%02x", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), value); + LOG_VERBOSE("Remote device: %s GATT client supported features 0x%02x", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), value); return value; } @@ -1629,20 +1615,18 @@ void btif_debug_linkkey_type_dump(int fd) { dprintf(fd, " %s\n", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); dprintf(fd, " BR: "); - if (btif_config_get_int(bdstr, "LinkKeyType", &linkkey_type)) { + if (btif_config_get_int(bdstr, BTIF_STORAGE_KEY_LINK_KEY_TYPE, + &linkkey_type)) { dprintf(fd, "%s", linkkey_type_text(linkkey_type).c_str()); } dprintf(fd, "\n"); dprintf(fd, " LE:"); - if (btif_config_exist(bdstr, "LE_KEY_PENC")) dprintf(fd, " PENC"); - if (btif_config_exist(bdstr, "LE_KEY_PID")) dprintf(fd, " PID"); - if (btif_config_exist(bdstr, "LE_KEY_PCSRK")) dprintf(fd, " PCSRK"); - if (btif_config_exist(bdstr, "LE_KEY_PLK")) dprintf(fd, " PLK"); - if (btif_config_exist(bdstr, "LE_KEY_LENC")) dprintf(fd, " LENC"); - if (btif_config_exist(bdstr, "LE_KEY_LCSRK")) dprintf(fd, " LCSRK"); - if (btif_config_exist(bdstr, "LE_KEY_LID")) dprintf(fd, " LID"); - if (btif_config_exist(bdstr, "LE_KEY_PLK")) dprintf(fd, " LLK"); + for (size_t i = 0; i < std::size(BTIF_STORAGE_LE_KEYS); i++) { + const std::string& key_name = BTIF_STORAGE_LE_KEYS[i].name; + if (btif_config_exist(bdstr, key_name)) + dprintf(fd, " %s", key_name.c_str()); + } dprintf(fd, "\n"); } diff --git a/system/btif/src/btif_util.cc b/system/btif/src/btif_util.cc index fb24a1ab864fe25ca48012adde57176129b6a95f..874e55561bb1612e20491b7e8069ad01b826a245 100644 --- a/system/btif/src/btif_util.cc +++ b/system/btif/src/btif_util.cc @@ -32,13 +32,12 @@ #include #include +#include #include #include #include #include -#include - #include "avrc_defs.h" #include "bta_ag_api.h" #include "bta_api.h" @@ -48,7 +47,6 @@ #include "bta_hh_api.h" #include "btif_common.h" #include "btif_dm.h" -#include "btu.h" /******************************************************************************* * Constants & Macros @@ -116,6 +114,7 @@ const char* dump_dm_search_event(uint16_t event) { CASE_RETURN_STR(BTA_DM_DISC_CMPL_EVT) CASE_RETURN_STR(BTA_DM_SEARCH_CANCEL_CMPL_EVT) CASE_RETURN_STR(BTA_DM_GATT_OVER_SDP_RES_EVT) + CASE_RETURN_STR(BTA_DM_NAME_READ_EVT) default: return "UNKNOWN MSG ID"; @@ -160,6 +159,7 @@ const char* dump_dm_event(uint16_t event) { CASE_RETURN_STR(BTA_DM_BLE_AUTH_CMPL_EVT) CASE_RETURN_STR(BTA_DM_DEV_UNPAIRED_EVT) CASE_RETURN_STR(BTA_DM_ENER_INFO_READ) + CASE_RETURN_STR(BTA_DM_SIRK_VERIFICATION_REQ_EVT) default: return "UNKNOWN DM EVENT"; @@ -216,6 +216,7 @@ const char* dump_hf_client_event(uint16_t event) { CASE_RETURN_STR(BTA_HF_CLIENT_CONN_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_OPEN_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT) + CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_LC3_OPEN_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_CLOSE_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_SPK_EVT) CASE_RETURN_STR(BTA_HF_CLIENT_MIC_EVT) diff --git a/system/btif/src/btif_vc.cc b/system/btif/src/btif_vc.cc index cd68b5a6bf67f469d22712de54673d6111d40793..21e8edc77c5aa4fbc69627f2450b126fb2ec273e 100644 --- a/system/btif/src/btif_vc.cc +++ b/system/btif/src/btif_vc.cc @@ -25,7 +25,8 @@ #include "bta_vc_api.h" #include "btif_common.h" -#include "stack/include/btu.h" +#include "btif_profile_storage.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" using base::Bind; @@ -43,9 +44,13 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, ~VolumeControlInterfaceImpl() override = default; void Init(VolumeControlCallbacks* callbacks) override { - DVLOG(2) << __func__; this->callbacks_ = callbacks; - do_in_main_thread(FROM_HERE, Bind(&VolumeControl::Initialize, this)); + do_in_main_thread( + FROM_HERE, + Bind(&VolumeControl::Initialize, this, + jni_thread_wrapper( + FROM_HERE, + Bind(&btif_storage_load_bonded_volume_control_devices)))); /* It might be not yet initialized, but setting this flag here is safe, * because other calls will check this and the native instance @@ -55,15 +60,12 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void OnConnectionState(ConnectionState state, const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << address; do_in_jni_thread(FROM_HERE, Bind(&VolumeControlCallbacks::OnConnectionState, Unretained(callbacks_), state, address)); } void OnVolumeStateChanged(const RawAddress& address, uint8_t volume, bool mute, bool isAutonomous) override { - DVLOG(2) << __func__ << " address: " << address << " volume: " << volume - << " mute: " << mute << " isAutonomous: " << isAutonomous; do_in_jni_thread( FROM_HERE, Bind(&VolumeControlCallbacks::OnVolumeStateChanged, @@ -72,8 +74,6 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void OnGroupVolumeStateChanged(int group_id, uint8_t volume, bool mute, bool isAutonomous) override { - DVLOG(2) << __func__ << " group_id: " << group_id << " volume: " << volume - << " mute: " << mute << " isAutonomous: " << isAutonomous; do_in_jni_thread( FROM_HERE, Bind(&VolumeControlCallbacks::OnGroupVolumeStateChanged, @@ -82,7 +82,6 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void OnDeviceAvailable(const RawAddress& address, uint8_t num_offset) override { - DVLOG(2) << __func__ << " address: " << address; do_in_jni_thread(FROM_HERE, Bind(&VolumeControlCallbacks::OnDeviceAvailable, Unretained(callbacks_), address, num_offset)); @@ -94,9 +93,6 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void OnExtAudioOutVolumeOffsetChanged(const RawAddress& address, uint8_t ext_output_id, int16_t offset) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id: " << ext_output_id << "offset:" << offset; - do_in_jni_thread( FROM_HERE, Bind(&VolumeControlCallbacks::OnExtAudioOutVolumeOffsetChanged, @@ -106,10 +102,6 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void OnExtAudioOutLocationChanged(const RawAddress& address, uint8_t ext_output_id, uint32_t location) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id: " << ext_output_id - << "location:" << loghex(location); - do_in_jni_thread( FROM_HERE, Bind(&VolumeControlCallbacks::OnExtAudioOutLocationChanged, @@ -119,8 +111,6 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void OnExtAudioOutDescriptionChanged(const RawAddress& address, uint8_t ext_output_id, std::string descr) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id: " << ext_output_id << "descr:" << descr; do_in_jni_thread( FROM_HERE, Bind(&VolumeControlCallbacks::OnExtAudioOutDescriptionChanged, @@ -128,12 +118,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, } void Connect(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << address; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -143,12 +131,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, } void Disconnect(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << address; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } do_in_main_thread(FROM_HERE, @@ -158,12 +144,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void SetVolume(std::variant addr_or_group_id, uint8_t volume) override { - DVLOG(2) << __func__ << " volume: " << volume; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -173,12 +157,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, } void Mute(std::variant addr_or_group_id) override { - DVLOG(2) << __func__; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -188,12 +170,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, } void Unmute(std::variant addr_or_group_id) override { - DVLOG(2) << __func__; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -203,34 +183,27 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, } void RemoveDevice(const RawAddress& address) override { - DVLOG(2) << __func__ << " address: " << address; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } /* RemoveDevice can be called on devices that don't have HA enabled */ if (VolumeControl::IsVolumeControlRunning()) { do_in_main_thread(FROM_HERE, - Bind(&VolumeControl::Disconnect, + Bind(&VolumeControl::Remove, Unretained(VolumeControl::Get()), address)); } - - /* Placeholder: Remove things from storage here */ } void GetExtAudioOutVolumeOffset(const RawAddress& address, uint8_t ext_output_id) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id:" << ext_output_id; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -243,14 +216,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void SetExtAudioOutVolumeOffset(const RawAddress& address, uint8_t ext_output_id, int16_t offset_val) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id:" << ext_output_id - << "ext_output_id:" << offset_val; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -262,13 +231,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void GetExtAudioOutLocation(const RawAddress& address, uint8_t ext_output_id) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id:" << ext_output_id; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -279,14 +245,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void SetExtAudioOutLocation(const RawAddress& address, uint8_t ext_output_id, uint32_t location) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id:" << ext_output_id - << "location:" << loghex(location); - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -297,13 +259,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void GetExtAudioOutDescription(const RawAddress& address, uint8_t ext_output_id) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id:" << ext_output_id; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -315,13 +274,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, void SetExtAudioOutDescription(const RawAddress& address, uint8_t ext_output_id, std::string descr) override { - DVLOG(2) << __func__ << " address: " << address - << "ext_output_id:" << ext_output_id << "description:" << descr; - if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } @@ -331,11 +287,10 @@ class VolumeControlInterfaceImpl : public VolumeControlInterface, } void Cleanup(void) override { - DVLOG(2) << __func__; if (!initialized || !VolumeControl::IsVolumeControlRunning()) { - DVLOG(2) << __func__ - << " call ignored, due to already started cleanup procedure or " - "service being not read"; + VLOG(1) << __func__ + << " call ignored, due to already started cleanup procedure or " + "service being not read"; return; } diff --git a/system/btif/src/profile_log_levels.cc b/system/btif/src/profile_log_levels.cc deleted file mode 100644 index 3348f650664f312c1b2e53f2c0e9b8d57e88e5a9..0000000000000000000000000000000000000000 --- a/system/btif/src/profile_log_levels.cc +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "bt_bte" - -#include -#include -#include -#include -#include -#include -#include - -#include "a2dp_api.h" -#include "avdt_api.h" -#include "avrc_api.h" -#include "bta_api.h" -#include "btm_api.h" -#include "btu.h" -#include "l2c_api.h" -#include "osi/include/config.h" -#include "osi/include/log.h" -#include "port_api.h" -#include "sdp_api.h" -#include "stack_config.h" -#if (BNEP_INCLUDED == TRUE) -#include "bnep_api.h" -#endif -#if (PAN_INCLUDED == TRUE) -#include "pan_api.h" -#endif -#if (HID_HOST_INCLUDED == TRUE) -#include "hidh_api.h" -#endif -#if (HID_DEV_INCLUDED == TRUE) -#include "hidd_api.h" -#endif - -#include "gd/common/init_flags.h" -#include "smp_api.h" - -#ifndef DEFAULT_CONF_TRACE_LEVEL -#define DEFAULT_CONF_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -static uint8_t BTAPP_SetTraceLevel(uint8_t new_level); -static uint8_t BTIF_SetTraceLevel(uint8_t new_level); -static uint8_t BTU_SetTraceLevel(uint8_t new_level); - -/* make sure list is order by increasing layer id!!! */ -static tBTTRC_FUNC_MAP bttrc_set_level_map[] = { - {BTTRC_ID_STK_BTU, BTTRC_ID_STK_HCI, BTU_SetTraceLevel, "TRC_HCI", - DEFAULT_CONF_TRACE_LEVEL}, - {BTTRC_ID_STK_L2CAP, BTTRC_ID_STK_L2CAP, L2CA_SetTraceLevel, "TRC_L2CAP", - DEFAULT_CONF_TRACE_LEVEL}, - {BTTRC_ID_STK_RFCOMM, BTTRC_ID_STK_RFCOMM_DATA, PORT_SetTraceLevel, - "TRC_RFCOMM", DEFAULT_CONF_TRACE_LEVEL}, - {BTTRC_ID_STK_AVCT, BTTRC_ID_STK_AVCT, AVCT_SetTraceLevel, "TRC_AVCT", - DEFAULT_CONF_TRACE_LEVEL}, - {BTTRC_ID_STK_AVDT, BTTRC_ID_STK_AVDT, AVDT_SetTraceLevel, "TRC_AVDT", - DEFAULT_CONF_TRACE_LEVEL}, - {BTTRC_ID_STK_AVRC, BTTRC_ID_STK_AVRC, AVRC_SetTraceLevel, "TRC_AVRC", - DEFAULT_CONF_TRACE_LEVEL}, - {BTTRC_ID_STK_A2DP, BTTRC_ID_STK_A2DP, A2DP_SetTraceLevel, "TRC_A2D", - DEFAULT_CONF_TRACE_LEVEL}, -#if (BNEP_INCLUDED == TRUE) - {BTTRC_ID_STK_BNEP, BTTRC_ID_STK_BNEP, BNEP_SetTraceLevel, "TRC_BNEP", - DEFAULT_CONF_TRACE_LEVEL}, -#endif - {BTTRC_ID_STK_BTM_ACL, BTTRC_ID_STK_BTM_SEC, BTM_SetTraceLevel, "TRC_BTM", - DEFAULT_CONF_TRACE_LEVEL}, -#if (HID_HOST_INCLUDED == TRUE) - {BTTRC_ID_STK_HID, BTTRC_ID_STK_HID, HID_HostSetTraceLevel, "TRC_HID_HOST", - DEFAULT_CONF_TRACE_LEVEL}, -#endif -#if (PAN_INCLUDED == TRUE) - {BTTRC_ID_STK_PAN, BTTRC_ID_STK_PAN, PAN_SetTraceLevel, "TRC_PAN", - DEFAULT_CONF_TRACE_LEVEL}, -#endif - {BTTRC_ID_STK_SDP, BTTRC_ID_STK_SDP, SDP_SetTraceLevel, "TRC_SDP", - DEFAULT_CONF_TRACE_LEVEL}, - {BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, SMP_SetTraceLevel, "TRC_SMP", - DEFAULT_CONF_TRACE_LEVEL}, -#if (HID_DEV_INCLUDED == TRUE) - {BTTRC_ID_STK_HIDD, BTTRC_ID_STK_HIDD, HID_DevSetTraceLevel, "TRC_HID_DEV", - DEFAULT_CONF_TRACE_LEVEL}, -#endif - - /* LayerIDs for BTA, currently everything maps onto appl_trace_level. - */ - {BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, BTAPP_SetTraceLevel, "TRC_BTAPP", - DEFAULT_CONF_TRACE_LEVEL}, - {BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, BTIF_SetTraceLevel, "TRC_BTIF", - DEFAULT_CONF_TRACE_LEVEL}, - - {0, 0, NULL, NULL, DEFAULT_CONF_TRACE_LEVEL}}; - -/* this function should go into BTAPP_DM for example */ -static uint8_t BTAPP_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) appl_trace_level = new_level; - - return appl_trace_level; -} - -static uint8_t BTIF_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) btif_trace_level = new_level; - - return btif_trace_level; -} - -static uint8_t BTU_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) btu_trace_level = new_level; - - return btu_trace_level; -} - -void load_levels_from_config(const config_t* config) { - CHECK(config != NULL); - - for (tBTTRC_FUNC_MAP* functions = &bttrc_set_level_map[0]; - functions->trc_name; ++functions) { - int value = config_get_int(*config, CONFIG_DEFAULT_SECTION, - functions->trc_name, -1); - if (value != -1) { - functions->trace_level = value; - } - if (bluetooth::common::InitFlags::GetDefaultLogLevel() >= LOG_TAG_VERBOSE) { - LOG_INFO("Enable logging for %s because all debug logs are enabled", - functions->trc_name); - functions->trace_level = BT_TRACE_LEVEL_VERBOSE; - } - LOG_INFO("BTE_InitTraceLevels -- %s : Level %d", functions->trc_name, - functions->trace_level); - if (functions->p_f) functions->p_f(functions->trace_level); - } -} diff --git a/system/btif/src/stack_manager.cc b/system/btif/src/stack_manager.cc index 2fd9e2bffd3c1949b66a69a71de4e23966181597..aafa132756edc27ec541a42445980cd779ffbeeb 100644 --- a/system/btif/src/stack_manager.cc +++ b/system/btif/src/stack_manager.cc @@ -32,11 +32,11 @@ #include "common/message_loop_thread.h" #include "core_callbacks.h" #include "main/shim/shim.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/osi.h" #include "stack/include/acl_api.h" #include "stack/include/btm_client_interface.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" // Temp includes #include "bta/sys/bta_sys.h" @@ -55,21 +55,15 @@ #if (PAN_INCLUDED == TRUE) #include "stack/include/pan_api.h" #endif -#include "stack/include/a2dp_api.h" -#include "stack/include/avrc_api.h" #if (HID_HOST_INCLUDED == TRUE) #include "stack/include/hidh_api.h" #endif -#include "bta/sys/bta_sys_int.h" -#include "bta_ar_api.h" -#include "bta_dm_int.h" -#include "btif/include/btif_pan.h" -#include "btif/include/btif_sock.h" -#include "btm_ble_int.h" +#include "bta/dm/bta_dm_int.h" #include "device/include/interop.h" #include "internal_include/stack_config.h" #include "main/shim/controller.h" #include "rust/src/core/ffi/module.h" +#include "stack/btm/btm_ble_int.h" #include "stack/include/smp_api.h" #ifndef BT_STACK_CLEANUP_WAIT_MS @@ -78,14 +72,6 @@ // Validate or respond to various conditional compilation flags -#if SDP_RAW_DATA_INCLUDED != TRUE -// Once SDP_RAW_DATA_INCLUDED is no longer exposed via bt_target.h -// this check and error statement may be removed. -#warning \ - "#define SDP_RAW_DATA_INCLUDED preprocessor compilation flag is unsupported" -#error "*** Conditional Compilation Directive error" -#endif - // Once BTA_PAN_INCLUDED is no longer exposed via bt_target.h // this check and error statement may be removed. static_assert( @@ -259,7 +245,6 @@ static void init_stack_internal(bluetooth::core::CoreInterface* interface) { module_init(get_local_module(DEVICE_IOT_CONFIG_MODULE)); module_init(get_local_module(OSI_MODULE)); - bte_main_init(); module_start_up(get_local_module(GD_SHIM_MODULE)); module_init(get_local_module(BTIF_CONFIG_MODULE)); btif_init_bluetooth(); @@ -318,7 +303,7 @@ static void event_start_up_stack(bluetooth::core::CoreInterface* interface, l2c_init(); sdp_init(); gatt_init(); - SMP_Init(); + SMP_Init(get_btm_client_interface().security.BTM_GetSecurityMode()); get_btm_client_interface().lifecycle.btm_ble_init(); RFCOMM_Init(); @@ -332,7 +317,7 @@ static void event_start_up_stack(bluetooth::core::CoreInterface* interface, btif_init_ok(); BTA_dm_init(); - bta_dm_enable(bte_dm_evt); + bta_dm_enable(btif_dm_sec_evt, btif_dm_acl_evt); bta_set_forward_hw_failures(true); btm_acl_device_down(); @@ -352,7 +337,7 @@ static void event_start_up_stack(bluetooth::core::CoreInterface* interface, stack_is_running = true; LOG_INFO("%s finished", __func__); - do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_up, nullptr)); + do_in_jni_thread(FROM_HERE, base::BindOnce(event_signal_stack_up, nullptr)); } // Synchronous function to shut down the stack @@ -369,14 +354,14 @@ static void event_shut_down_stack(ProfileStopCallback stopProfiles) { module_shut_down(get_local_module(RUST_MODULE)); - do_in_main_thread(FROM_HERE, base::Bind(&btm_ble_multi_adv_cleanup)); - - do_in_main_thread(FROM_HERE, base::Bind(&btm_ble_scanner_cleanup)); + do_in_main_thread(FROM_HERE, base::BindOnce(&btm_ble_scanner_cleanup)); btif_dm_on_disable(); stopProfiles(); - do_in_main_thread(FROM_HERE, base::Bind(bta_dm_disable)); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_dm_disable)); + + btif_dm_cleanup(); future_await(local_hack_future); local_hack_future = future_new(); @@ -401,7 +386,7 @@ static void event_shut_down_stack(ProfileStopCallback stopProfiles) { get_btm_client_interface().lifecycle.btm_free(); hack_future = future_new(); - do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_down, nullptr)); + do_in_jni_thread(FROM_HERE, base::BindOnce(event_signal_stack_down, nullptr)); future_await(hack_future); LOG_INFO("%s finished", __func__); } @@ -482,3 +467,16 @@ const stack_manager_t* stack_manager_get_interface() { } future_t* stack_manager_get_hack_future() { return hack_future; } + +namespace bluetooth { +namespace legacy { +namespace testing { + +void set_interface_to_profiles( + bluetooth::core::CoreInterface* interfaceToProfiles) { + ::interfaceToProfiles = interfaceToProfiles; +} + +} // namespace testing +} // namespace legacy +} // namespace bluetooth diff --git a/system/btif/test/btif_avrcp_audio_track_test.cc b/system/btif/test/btif_avrcp_audio_track_test.cc index 856decb0ee9614fb57e2c290e23767e95336c5bd..8f219d4bfe4d4dd0a18b08f205e088929435be9f 100644 --- a/system/btif/test/btif_avrcp_audio_track_test.cc +++ b/system/btif/test/btif_avrcp_audio_track_test.cc @@ -1,5 +1,25 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "btif/include/btif_avrcp_audio_track.h" +#ifndef __INTRODUCED_IN +#define __INTRODUCED_IN(x) +#endif + #include #include #include diff --git a/system/btif/test/btif_core_test.cc b/system/btif/test/btif_core_test.cc index 27df5e1b69724f0a20a328123a8df131ffa3e5de..e08e43f4d9c744d04daeeb40aa68f59107fdf466 100644 --- a/system/btif/test/btif_core_test.cc +++ b/system/btif/test/btif_core_test.cc @@ -31,14 +31,12 @@ #include "include/hardware/bluetooth.h" #include "include/hardware/bt_av.h" #include "test/common/core_interface.h" +#include "test/mock/mock_main_shim_controller.h" +#include "test/mock/mock_stack_btm_sec.h" #include "types/raw_address.h" void set_hal_cbacks(bt_callbacks_t* callbacks); -uint8_t appl_trace_level = BT_TRACE_LEVEL_DEBUG; -uint8_t btif_trace_level = BT_TRACE_LEVEL_DEBUG; -uint8_t btu_trace_level = BT_TRACE_LEVEL_DEBUG; - const tBTA_AG_RES_DATA tBTA_AG_RES_DATA::kEmpty = {}; module_t bt_utils_module; @@ -49,6 +47,8 @@ module_t rust_module; namespace { +const RawAddress kRawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); + auto timeout_time = std::chrono::seconds(3); std::map> callback_map_; @@ -56,41 +56,55 @@ std::map> callback_map_; if (callback_map_.find(__func__) != callback_map_.end()) \ callback_map_[__func__](); -void adapter_state_changed_callback(bt_state_t state) {} -void adapter_properties_callback(bt_status_t status, int num_properties, - bt_property_t* properties) {} -void remote_device_properties_callback(bt_status_t status, RawAddress* bd_addr, - int num_properties, - bt_property_t* properties) {} -void device_found_callback(int num_properties, bt_property_t* properties) {} -void discovery_state_changed_callback(bt_discovery_state_t state) {} -void pin_request_callback(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, - uint32_t cod, bool min_16_digit) {} -void ssp_request_callback(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, - uint32_t cod, bt_ssp_variant_t pairing_variant, - uint32_t pass_key) {} -void bond_state_changed_callback(bt_status_t status, RawAddress* remote_bd_addr, - bt_bond_state_t state, int fail_reason) {} -void address_consolidate_callback(RawAddress* main_bd_addr, - RawAddress* secondary_bd_addr) {} -void le_address_associate_callback(RawAddress* main_bd_addr, - RawAddress* secondary_bd_addr) {} -void acl_state_changed_callback(bt_status_t status, RawAddress* remote_bd_addr, - bt_acl_state_t state, int transport_link_type, - bt_hci_error_code_t hci_reason, - bt_conn_direction_t direction, - uint16_t acl_handle) {} -void link_quality_report_callback(uint64_t timestamp, int report_id, int rssi, - int snr, int retransmission_count, - int packets_not_receive_count, - int negative_acknowledgement_count) {} -void callback_thread_event(bt_cb_thread_evt evt) { TESTCB; } -void energy_info_callback(bt_activity_energy_info* energy_info, - bt_uid_traffic_t* uid_data) {} -void generate_local_oob_data_callback(tBT_TRANSPORT transport, - bt_oob_data_t oob_data) {} -void switch_buffer_size_callback(bool is_low_latency_buffer_size) {} -void switch_codec_callback(bool is_low_latency_buffer_size) {} +void adapter_state_changed_callback(bt_state_t /* state */) {} +void adapter_properties_callback(bt_status_t /* status */, + int /* num_properties */, + bt_property_t* /* properties */) {} +void remote_device_properties_callback(bt_status_t /* status */, + RawAddress* /* bd_addr */, + int /* num_properties */, + bt_property_t* /* properties */) {} +void device_found_callback(int /* num_properties */, + bt_property_t* /* properties */) {} +void discovery_state_changed_callback(bt_discovery_state_t /* state */) {} +void pin_request_callback(RawAddress* /* remote_bd_addr */, + bt_bdname_t* /* bd_name */, uint32_t /* cod */, + bool /* min_16_digit */) {} +void ssp_request_callback(RawAddress* /* remote_bd_addr */, + bt_bdname_t* /* bd_name */, uint32_t /* cod */, + bt_ssp_variant_t /* pairing_variant */, + uint32_t /* pass_key */) {} +void bond_state_changed_callback(bt_status_t /* status */, + RawAddress* /* remote_bd_addr */, + bt_bond_state_t /* state */, + int /* fail_reason */) {} +void address_consolidate_callback(RawAddress* /* main_bd_addr */, + RawAddress* /* secondary_bd_addr */) {} +void le_address_associate_callback(RawAddress* /* main_bd_addr */, + RawAddress* /* secondary_bd_addr */) {} +void acl_state_changed_callback(bt_status_t /* status */, + RawAddress* /* remote_bd_addr */, + bt_acl_state_t /* state */, + int /* transport_link_type */, + bt_hci_error_code_t /* hci_reason */, + bt_conn_direction_t /* direction */, + uint16_t /* acl_handle */) {} +void link_quality_report_callback(uint64_t /* timestamp */, int /* report_id */, + int /* rssi */, int /* snr */, + int /* retransmission_count */, + int /* packets_not_receive_count */, + int /* negative_acknowledgement_count */) {} +void callback_thread_event(bt_cb_thread_evt /* evt */) { TESTCB; } +void dut_mode_recv_callback(uint16_t /* opcode */, uint8_t* /* buf */, + uint8_t /* len */) {} +void le_test_mode_callback(bt_status_t /* status */, + uint16_t /* num_packets */) {} +void energy_info_callback(bt_activity_energy_info* /* energy_info */, + bt_uid_traffic_t* /* uid_data */) {} +void generate_local_oob_data_callback(tBT_TRANSPORT /* transport */, + bt_oob_data_t /* oob_data */) {} +void switch_buffer_size_callback(bool /* is_low_latency_buffer_size */) {} +void switch_codec_callback(bool /* is_low_latency_buffer_size */) {} #undef TESTCB bt_callbacks_t callbacks = { @@ -107,6 +121,8 @@ bt_callbacks_t callbacks = { .le_address_associate_cb = le_address_associate_callback, .acl_state_changed_cb = acl_state_changed_callback, .thread_evt_cb = callback_thread_event, + .dut_mode_recv_cb = dut_mode_recv_callback, + .le_test_mode_cb = le_test_mode_callback, .energy_info_cb = energy_info_callback, .link_quality_report_cb = link_quality_report_callback, .generate_local_oob_data_cb = generate_local_oob_data_callback, @@ -143,9 +159,30 @@ class BtifCoreTest : public ::testing::Test { } }; +namespace { +controller_t controller = {}; +} + +class BtifCoreWithControllerTest : public BtifCoreTest { + void SetUp() override { + BtifCoreTest::SetUp(); + controller.supports_sniff_subrating = []() { return true; }; + bluetooth::testing::controller = &controller; + ASSERT_TRUE(controller_get_interface() != nullptr); + } + + void TearDown() override { + bluetooth::testing::controller = nullptr; + controller = {}; + BtifCoreTest::TearDown(); + } +}; + std::promise promise0; void callback0(int val) { promise0.set_value(val); } +TEST_F(BtifCoreTest, test_nop) {} + TEST_F(BtifCoreTest, test_post_on_bt_simple0) { const int val = 123; promise0 = std::promise(); @@ -230,6 +267,7 @@ TEST_F(BtifCoreTest, dump_dm_search_event) { "BTA_DM_SEARCH_CANCEL_CMPL_EVT"), std::make_pair(BTA_DM_GATT_OVER_SDP_RES_EVT, "BTA_DM_GATT_OVER_SDP_RES_EVT"), + std::make_pair(BTA_DM_NAME_READ_EVT, "BTA_DM_NAME_READ_EVT"), }; for (const auto& event : events) { ASSERT_STREQ(event.second.c_str(), dump_dm_search_event(event.first)); @@ -356,6 +394,8 @@ TEST_F(BtifCoreTest, dump_hf_client_event) { "BTA_HF_CLIENT_AUDIO_OPEN_EVT"), std::make_pair(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT, "BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT"), + std::make_pair(BTA_HF_CLIENT_AUDIO_LC3_OPEN_EVT, + "BTA_HF_CLIENT_AUDIO_LC3_OPEN_EVT"), std::make_pair(BTA_HF_CLIENT_AUDIO_CLOSE_EVT, "BTA_HF_CLIENT_AUDIO_CLOSE_EVT"), std::make_pair(BTA_HF_CLIENT_SPK_EVT, "BTA_HF_CLIENT_SPK_EVT"), @@ -634,3 +674,82 @@ TEST_F(BtifCoreTest, dump_rc_pdu) { ASSERT_STREQ(oss.str().c_str(), dump_rc_pdu(std::numeric_limits::max())); } + +void bta_dm_acl_up(const RawAddress& bd_addr, tBT_TRANSPORT transport, + uint16_t acl_handle); + +TEST_F(BtifCoreWithControllerTest, btif_dm_get_connection_state__unconnected) { + ASSERT_EQ(0, btif_dm_get_connection_state(kRawAddress)); +} + +TEST_F(BtifCoreWithControllerTest, + btif_dm_get_connection_state__connected_no_encryption) { + bta_dm_acl_up(kRawAddress, BT_TRANSPORT_AUTO, 0x123); + + test::mock::stack_btm_sec::BTM_IsEncrypted.body = + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT transport) { + switch (transport) { + case BT_TRANSPORT_BR_EDR: + return false; + case BT_TRANSPORT_LE: + return false; + } + return false; + }; + ASSERT_EQ(1, btif_dm_get_connection_state(kRawAddress)); + test::mock::stack_btm_sec::BTM_IsEncrypted = {}; +} + +TEST_F(BtifCoreWithControllerTest, + btif_dm_get_connection_state__connected_classic_encryption) { + bta_dm_acl_up(kRawAddress, BT_TRANSPORT_AUTO, 0x123); + + test::mock::stack_btm_sec::BTM_IsEncrypted.body = + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT transport) { + switch (transport) { + case BT_TRANSPORT_BR_EDR: + return true; + case BT_TRANSPORT_LE: + return false; + } + return false; + }; + ASSERT_EQ(3, btif_dm_get_connection_state(kRawAddress)); + test::mock::stack_btm_sec::BTM_IsEncrypted = {}; +} + +TEST_F(BtifCoreWithControllerTest, + btif_dm_get_connection_state__connected_le_encryption) { + bta_dm_acl_up(kRawAddress, BT_TRANSPORT_AUTO, 0x123); + + test::mock::stack_btm_sec::BTM_IsEncrypted.body = + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT transport) { + switch (transport) { + case BT_TRANSPORT_BR_EDR: + return false; + case BT_TRANSPORT_LE: + return true; + } + return false; + }; + ASSERT_EQ(5, btif_dm_get_connection_state(kRawAddress)); + test::mock::stack_btm_sec::BTM_IsEncrypted = {}; +} + +TEST_F(BtifCoreWithControllerTest, + btif_dm_get_connection_state__connected_both_encryption) { + bta_dm_acl_up(kRawAddress, BT_TRANSPORT_AUTO, 0x123); + + test::mock::stack_btm_sec::BTM_IsEncrypted.body = + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT transport) { + switch (transport) { + case BT_TRANSPORT_BR_EDR: + return true; + case BT_TRANSPORT_LE: + return true; + } + return false; + }; + ASSERT_EQ(7, btif_dm_get_connection_state(kRawAddress)); + test::mock::stack_btm_sec::BTM_IsEncrypted = {}; +} diff --git a/system/btif/test/btif_dm_test.cc b/system/btif/test/btif_dm_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..68cff1d336c4feccd8d3916d36f9be763fa77917 --- /dev/null +++ b/system/btif/test/btif_dm_test.cc @@ -0,0 +1,107 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "btif/include/btif_dm.h" + +#include + +#include + +#include "bta/include/bta_api_data_types.h" +#include "btif/include/mock_core_callbacks.h" +#include "stack/include/btm_api_types.h" +#include "stack/include/btm_ble_api_types.h" + +using bluetooth::core::testing::MockCoreInterface; + +namespace bluetooth { +namespace legacy { +namespace testing { + +void set_interface_to_profiles( + bluetooth::core::CoreInterface* interfaceToProfiles); + +void bta_energy_info_cb(tBTM_BLE_TX_TIME_MS tx_time, + tBTM_BLE_RX_TIME_MS rx_time, + tBTM_BLE_IDLE_TIME_MS idle_time, + tBTM_BLE_ENERGY_USED energy_used, + tBTM_CONTRL_STATE ctrl_state, tBTA_STATUS status); + +} // namespace testing +} // namespace legacy +} // namespace bluetooth + +namespace { +constexpr tBTM_BLE_TX_TIME_MS tx_time = 0x12345678; +constexpr tBTM_BLE_RX_TIME_MS rx_time = 0x87654321; +constexpr tBTM_BLE_IDLE_TIME_MS idle_time = 0x2468acd0; +constexpr tBTM_BLE_ENERGY_USED energy_used = 0x13579bdf; +} // namespace + +class BtifDmTest : public ::testing::Test { + protected: + void SetUp() override { + mock_core_interface_ = std::make_unique(); + bluetooth::legacy::testing::set_interface_to_profiles( + mock_core_interface_.get()); + } + + void TearDown() override {} + + std::unique_ptr mock_core_interface_; +}; + +TEST_F(BtifDmTest, bta_energy_info_cb__with_no_uid) { + static bool invoke_energy_info_cb_entered = false; + bluetooth::core::testing::mock_event_callbacks.invoke_energy_info_cb = + [](bt_activity_energy_info /* energy_info */, + bt_uid_traffic_t* /* uid_data */) { + invoke_energy_info_cb_entered = true; + }; + + bluetooth::legacy::testing::bta_energy_info_cb( + tx_time, rx_time, idle_time, energy_used, BTM_CONTRL_UNKNOWN, + BTA_SUCCESS); + + ASSERT_FALSE(invoke_energy_info_cb_entered); +} + +class BtifDmWithUidTest : public BtifDmTest { + protected: + void SetUp() override { + BtifDmTest::SetUp(); + btif_dm_init(uid_set_create()); + } + + void TearDown() override { + void btif_dm_cleanup(); + BtifDmTest::TearDown(); + } +}; + +TEST_F(BtifDmWithUidTest, bta_energy_info_cb__with_uid) { + static bool invoke_energy_info_cb_entered = false; + bluetooth::core::testing::mock_event_callbacks.invoke_energy_info_cb = + [](bt_activity_energy_info /* energy_info */, + bt_uid_traffic_t* /* uid_data */) { + invoke_energy_info_cb_entered = true; + }; + bluetooth::legacy::testing::bta_energy_info_cb( + tx_time, rx_time, idle_time, energy_used, BTM_CONTRL_UNKNOWN, + BTA_SUCCESS); + + ASSERT_TRUE(invoke_energy_info_cb_entered); +} diff --git a/system/btif/test/btif_hf_client_service_test.cc b/system/btif/test/btif_hf_client_service_test.cc index 2798bf17fecfd07d53934f7e218dc3da78bd2c38..952e2411560cf6ca7ebbf20db6f9ee23938ee4ae 100644 --- a/system/btif/test/btif_hf_client_service_test.cc +++ b/system/btif/test/btif_hf_client_service_test.cc @@ -1,26 +1,16 @@ +#include #include #include -#include "bta_hfp_api.h" -#ifdef __ANDROID__ -#include -#endif +#include "bta_hfp_api.h" #undef LOG_TAG #include "btif/src/btif_hf_client.cc" static tBTA_HF_CLIENT_FEAT gFeatures; -#define DEFAULT_BTA_HFP_VERSION HFP_VERSION_1_7 int get_default_hfp_version() { -#ifdef __ANDROID__ - static const int version = - android::sysprop::bluetooth::Hfp::version().value_or( - DEFAULT_BTA_HFP_VERSION); - return version; -#else - return DEFAULT_BTA_HFP_VERSION; -#endif + return GET_SYSPROP(Hfp, version, HFP_VERSION_1_7); } int get_default_hf_client_features() { @@ -29,17 +19,9 @@ int get_default_hf_client_features() { BTA_HF_CLIENT_FEAT_CLI | BTA_HF_CLIENT_FEAT_VREC | BTA_HF_CLIENT_FEAT_VOL | \ BTA_HF_CLIENT_FEAT_ECS | BTA_HF_CLIENT_FEAT_ECC | BTA_HF_CLIENT_FEAT_CODEC) -#ifdef __ANDROID__ - static const int features = - android::sysprop::bluetooth::Hfp::hf_client_features().value_or( - DEFAULT_BTIF_HF_CLIENT_FEATURES); - return features; -#else - return DEFAULT_BTIF_HF_CLIENT_FEATURES; -#endif + return GET_SYSPROP(Hfp, hf_client_features, DEFAULT_BTIF_HF_CLIENT_FEATURES); } -uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING; tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK* p_cback, tBTA_HF_CLIENT_FEAT features, const char* p_service_name) { @@ -70,4 +52,7 @@ TEST_F(BtifHfClientTest, test_btif_hf_cleint_service) { btif_hf_client_execute_service(enable); ASSERT_EQ((gFeatures & BTA_HF_CLIENT_FEAT_ESCO_S4) > 0, get_default_hfp_version() >= HFP_VERSION_1_7); + + ASSERT_EQ((gFeatures & BTA_HF_CLIENT_FEAT_SWB) > 0, + get_default_hfp_version() >= HFP_VERSION_1_9); } diff --git a/system/btif/test/btif_hh_test.cc b/system/btif/test/btif_hh_test.cc index b5efa5c40b7b51380dc68339e4cb7c57d3a174ea..f064efc5e9d6d2261b1d523551f0e58eda35d088 100644 --- a/system/btif/test/btif_hh_test.cc +++ b/system/btif/test/btif_hh_test.cc @@ -23,13 +23,11 @@ #include #include -#include "bta/hh/bta_hh_int.h" #include "bta/include/bta_ag_api.h" #include "bta/include/bta_hh_api.h" #include "btcore/include/module.h" -#include "btif/include/btif_api.h" -#include "btif/include/stack_manager.h" #include "include/hardware/bt_hh.h" +#include "osi/include/allocator.h" #include "test/common/core_interface.h" #include "test/common/mock_functions.h" #include "test/mock/mock_osi_allocator.h" @@ -38,10 +36,7 @@ using namespace std::chrono_literals; void set_hal_cbacks(bt_callbacks_t* callbacks); -uint8_t appl_trace_level = BT_TRACE_LEVEL_DEBUG; -uint8_t btif_trace_level = BT_TRACE_LEVEL_DEBUG; -uint8_t btu_trace_level = BT_TRACE_LEVEL_DEBUG; - +// Used the legacy stack manager module_t bt_utils_module; module_t gd_controller_module; module_t gd_shim_module; @@ -50,43 +45,26 @@ module_t rust_module; const tBTA_AG_RES_DATA tBTA_AG_RES_DATA::kEmpty = {}; -void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data); const bthh_interface_t* btif_hh_get_interface(); bt_status_t btif_hh_connect(const RawAddress* bd_addr); bt_status_t btif_hh_virtual_unplug(const RawAddress* bd_addr); +namespace bluetooth { +namespace legacy { +namespace testing { + +void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data); + +} // namespace testing +} // namespace legacy +} // namespace bluetooth + namespace test { namespace mock { extern bool bluetooth_shim_is_gd_stack_started_up; } } // namespace test -#if __GLIBC__ -size_t strlcpy(char* dst, const char* src, size_t siz) { - char* d = dst; - const char* s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = *s++) == '\0') break; - } - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return (s - src - 1); /* count does not include NUL */ -} - -pid_t gettid(void) throw() { return syscall(SYS_gettid); } -#endif - namespace { std::array data32 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, @@ -133,6 +111,8 @@ bt_callbacks_t bt_callbacks = { .le_address_associate_cb = nullptr, // le_address_associate_callback .acl_state_changed_cb = nullptr, // acl_state_changed_callback .thread_evt_cb = nullptr, // callback_thread_event + .dut_mode_recv_cb = nullptr, // dut_mode_recv_callback + .le_test_mode_cb = nullptr, // le_test_mode_callback .energy_info_cb = nullptr, // energy_info_callback .link_quality_report_cb = nullptr, // link_quality_report_callback .generate_local_oob_data_cb = nullptr, // generate_local_oob_data_callback @@ -154,34 +134,16 @@ bthh_callbacks_t bthh_callbacks = { class BtifHhWithMockTest : public ::testing::Test { protected: - void SetUp() override { - reset_mock_function_count_map(); - test::mock::osi_allocator::osi_malloc.body = [](size_t size) { - return malloc(size); - }; - test::mock::osi_allocator::osi_calloc.body = [](size_t size) { - return calloc(1UL, size); - }; - test::mock::osi_allocator::osi_free.body = [](void* ptr) { free(ptr); }; - test::mock::osi_allocator::osi_free_and_reset.body = [](void** ptr) { - free(*ptr); - *ptr = nullptr; - }; - } + void SetUp() override { reset_mock_function_count_map(); } - void TearDown() override { - test::mock::osi_allocator::osi_malloc = {}; - test::mock::osi_allocator::osi_calloc = {}; - test::mock::osi_allocator::osi_free = {}; - test::mock::osi_allocator::osi_free_and_reset = {}; - } + void TearDown() override {} }; class BtifHhWithHalCallbacksTest : public BtifHhWithMockTest { protected: void SetUp() override { - bluetooth::common::InitFlags::SetAllForTesting(); BtifHhWithMockTest::SetUp(); + bluetooth::common::InitFlags::SetAllForTesting(); g_thread_evt_promise = std::promise(); auto future = g_thread_evt_promise.get_future(); bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) { @@ -275,7 +237,7 @@ TEST_F(BtifHhWithDevice, BTA_HH_GET_RPT_EVT) { g_bthh_callbacks_get_report_promise.set_value(report); }; - bte_hh_evt(BTA_HH_GET_RPT_EVT, &data); + bluetooth::legacy::testing::bte_hh_evt(BTA_HH_GET_RPT_EVT, &data); osi_free(data.hs_data.rsp_data.p_rpt_data); ASSERT_EQ(std::future_status::ready, future.wait_for(2s)); diff --git a/system/btif/test/btif_rc_test.cc b/system/btif/test/btif_rc_test.cc index 48f3b748ae103b58a5065b86af82e038311b6cc8..221cb4f9de4820cccfdeda855389c9fef75834ed 100644 --- a/system/btif/test/btif_rc_test.cc +++ b/system/btif/test/btif_rc_test.cc @@ -14,73 +14,74 @@ * limitations under the License. */ -#include +#undef LOG_TAG // Undefine the LOG_TAG by this compilation unit +#include "btif/src/btif_rc.cc" + #include -#include #include +#include #include "bta/include/bta_av_api.h" +#include "btif/avrcp/avrcp_service.h" #include "btif/include/btif_common.h" #include "common/message_loop_thread.h" #include "device/include/interop.h" #include "include/hardware/bt_rc.h" -#include "osi/test/AllocationTestHarness.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/btm_api_types.h" +#include "test/common/mock_functions.h" +#include "test/mock/mock_osi_alarm.h" +#include "test/mock/mock_osi_allocator.h" +#include "test/mock/mock_osi_list.h" #include "types/raw_address.h" -#undef LOG_TAG -#include "btif/src/btif_rc.cc" -void allocation_tracker_uninit(void); +namespace bluetooth { +namespace avrcp { +int VolChanged = 0; +AvrcpService* AvrcpService::instance_ = nullptr; -namespace { -int AVRC_BldResponse_ = 0; -} // namespace - -uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING; -uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING; +void AvrcpService::SendMediaUpdate(bool track_changed, bool play_state, + bool queue){}; +void AvrcpService::SendFolderUpdate(bool available_players, + bool addressed_players, bool uids){}; +void AvrcpService::SendActiveDeviceChanged(const RawAddress& address){}; +void AvrcpService::SendPlayerSettingsChanged( + std::vector attributes, std::vector values){}; +void AvrcpService::ServiceInterfaceImpl::Init( + MediaInterface* media_interface, VolumeInterface* volume_interface, + PlayerSettingsInterface* player_settings_interface){}; +void AvrcpService::ServiceInterfaceImpl::RegisterBipServer(int psm){}; +void AvrcpService::ServiceInterfaceImpl::UnregisterBipServer(){}; +bool AvrcpService::ServiceInterfaceImpl::ConnectDevice( + const RawAddress& bdaddr) { + return true; +}; +bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice( + const RawAddress& bdaddr) { + return true; +}; +void AvrcpService::ServiceInterfaceImpl::SetBipClientStatus( + const RawAddress& bdaddr, bool connected){}; +bool AvrcpService::ServiceInterfaceImpl::Cleanup() { return true; }; -bool avrcp_absolute_volume_is_enabled() { return true; } -tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { return 0; } -tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp, - BT_HDR** pp_pkt) { - AVRC_BldResponse_++; - return 0; -} -tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) { - return 0; -} -tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result, - uint8_t* p_buf, uint16_t* buf_len) { - return 0; +AvrcpService* AvrcpService::Get() { + CHECK(instance_ == nullptr); + instance_ = new AvrcpService(); + return instance_; } -tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result, - uint8_t* p_buf, uint16_t buf_len) { - return 0; -} -tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result, - UNUSED_ATTR uint8_t* p_buf, - UNUSED_ATTR uint16_t buf_len) { - return 0; + +void AvrcpService::RegisterVolChanged(const RawAddress& bdaddr) { + VolChanged++; } -void BTA_AvCloseRc(uint8_t rc_handle) {} -void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code, - BT_HDR* p_pkt) {} -void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, - BT_HDR* p_pkt) {} -void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id, - tBTA_AV_STATE key_state) {} -void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label, - tBTA_AV_STATE key_state, uint8_t* p_msg, - uint8_t buf_len) {} -void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code, - uint8_t* p_data, uint16_t len) {} -void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, - uint8_t* p_data, uint16_t len, uint32_t company_id) {} +} // namespace avrcp +} // namespace bluetooth + +namespace { +const RawAddress kDeviceAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); +} // namespace + void btif_av_clear_remote_suspend_flag(void) {} -bool btif_av_is_connected(void) { return false; } -bool btif_av_is_sink_enabled(void) { return false; } +bool btif_av_is_connected(void) { return true; } +bool btif_av_is_sink_enabled(void) { return true; } RawAddress btif_av_sink_active_peer(void) { return RawAddress(); } RawAddress btif_av_source_active_peer(void) { return RawAddress(); } bool btif_av_stream_started_ready(void) { return false; } @@ -89,12 +90,25 @@ bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event, tBTIF_COPY_CBACK* p_copy_cback) { return BT_STATUS_SUCCESS; } -const char* dump_rc_event(uint8_t event) { return nullptr; } -const char* dump_rc_notification_event_id(uint8_t event_id) { return nullptr; } -const char* dump_rc_pdu(uint8_t pdu) { return nullptr; } -const char* dump_rc_opcode(uint8_t pdu) { return nullptr; } +bool btif_av_src_sink_coexist_enabled() { return true; } +bool btif_av_is_connected_addr(const RawAddress& peer_address) { return true; } +bool btif_av_peer_is_connected_sink(const RawAddress& peer_address) { + return false; +} +bool btif_av_peer_is_connected_source(const RawAddress& peer_address) { + return true; +} +bool btif_av_peer_is_sink(const RawAddress& peer_address) { return false; } +bool btif_av_peer_is_source(const RawAddress& peer_address) { return true; } +bool btif_av_both_enable(void) { return true; } + +static bluetooth::common::MessageLoopThread jni_thread("bt_jni_thread"); bt_status_t do_in_jni_thread(const base::Location& from_here, base::OnceClosure task) { + if (!jni_thread.DoInThread(from_here, std::move(task))) { + LOG(ERROR) << __func__ << ": Post task to task runner failed!"; + return BT_STATUS_FAIL; + } return BT_STATUS_SUCCESS; } bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; } @@ -106,21 +120,14 @@ bool interop_match_addr(const interop_feature_t feature, /** * Test class to test selected functionality in hci/src/hci_layer.cc */ -class BtifRcTest : public AllocationTestHarness { +class BtifRcTest : public ::testing::Test { protected: - void SetUp() override { - AllocationTestHarness::SetUp(); - // Disable our allocation tracker to allow ASAN full range - allocation_tracker_uninit(); - } - - void TearDown() override { AllocationTestHarness::TearDown(); } + void SetUp() override { reset_mock_function_count_map(); } + void TearDown() override {} }; TEST_F(BtifRcTest, get_element_attr_rsp) { - RawAddress bd_addr; - - btif_rc_cb.rc_multi_cb[0].rc_addr = bd_addr; + btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress; btif_rc_cb.rc_multi_cb[0].rc_connected = true; btif_rc_cb.rc_multi_cb[0] .rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP] @@ -130,6 +137,336 @@ TEST_F(BtifRcTest, get_element_attr_rsp) { btrc_element_attr_val_t p_attrs[BTRC_MAX_ELEM_ATTR_SIZE]; uint8_t num_attr = BTRC_MAX_ELEM_ATTR_SIZE + 1; - CHECK(get_element_attr_rsp(bd_addr, num_attr, p_attrs) == BT_STATUS_SUCCESS); - CHECK(AVRC_BldResponse_ == 1); + CHECK(get_element_attr_rsp(kDeviceAddress, num_attr, p_attrs) == + BT_STATUS_SUCCESS); + ASSERT_EQ(1, get_func_call_count("AVRC_BldResponse")); +} + +TEST_F(BtifRcTest, btif_rc_get_addr_by_handle) { + RawAddress bd_addr; + + btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_handle = 0; + + btif_rc_get_addr_by_handle(0, bd_addr); + CHECK(kDeviceAddress == bd_addr); +} + +static btrc_ctrl_callbacks_t default_btrc_ctrl_callbacks = { + .size = sizeof(btrc_ctrl_callbacks_t), + .passthrough_rsp_cb = [](const RawAddress& /* bd_addr */, int /* id */, + int /* key_state */) { FAIL(); }, + .groupnavigation_rsp_cb = [](int /* id */, int /* key_state */) { FAIL(); }, + .connection_state_cb = [](bool /* rc_connect */, bool /* bt_connect */, + const RawAddress& /* bd_addr */) { FAIL(); }, + .getrcfeatures_cb = [](const RawAddress& /* bd_addr */, + int /* features */) { FAIL(); }, + .setplayerappsetting_rsp_cb = [](const RawAddress& /* bd_addr */, + uint8_t /* accepted */) { FAIL(); }, + .playerapplicationsetting_cb = + [](const RawAddress& /* bd_addr */, uint8_t /* num_attr */, + btrc_player_app_attr_t* /* app_attrs */, uint8_t /* num_ext_attr */, + btrc_player_app_ext_attr_t* /* ext_attrs */) { FAIL(); }, + .playerapplicationsetting_changed_cb = + [](const RawAddress& /* bd_addr */, + const btrc_player_settings_t& /* vals */) { FAIL(); }, + .setabsvol_cmd_cb = [](const RawAddress& /* bd_addr */, + uint8_t /* abs_vol */, + uint8_t /* label */) { FAIL(); }, + .registernotification_absvol_cb = [](const RawAddress& /* bd_addr */, + uint8_t /* label */) { FAIL(); }, + .track_changed_cb = [](const RawAddress& /* bd_addr */, + uint8_t /* num_attr */, + btrc_element_attr_val_t* /* p_attrs */) { FAIL(); }, + .play_position_changed_cb = [](const RawAddress& /* bd_addr */, + uint32_t /* song_len */, + uint32_t /* song_pos */) { FAIL(); }, + .play_status_changed_cb = + [](const RawAddress& /* bd_addr */, + btrc_play_status_t /* play_status */) { FAIL(); }, + .get_folder_items_cb = [](const RawAddress& /* bd_addr */, + btrc_status_t /* status */, + const btrc_folder_items_t* /* folder_items */, + uint8_t /* count */) { FAIL(); }, + .change_folder_path_cb = [](const RawAddress& /* bd_addr */, + uint32_t /* count */) { FAIL(); }, + .set_browsed_player_cb = [](const RawAddress& /* bd_addr */, + uint8_t /* num_items */, + uint8_t /* depth */) { FAIL(); }, + .set_addressed_player_cb = [](const RawAddress& /* bd_addr */, + uint8_t /* status */) { FAIL(); }, + .addressed_player_changed_cb = [](const RawAddress& /* bd_addr */, + uint16_t /* id */) { FAIL(); }, + .now_playing_contents_changed_cb = + [](const RawAddress& /* bd_addr */) { FAIL(); }, + .available_player_changed_cb = + [](const RawAddress& /* bd_addr */) { FAIL(); }, + .get_cover_art_psm_cb = [](const RawAddress& /* bd_addr */, + const uint16_t /* psm */) { FAIL(); }, +}; +static btrc_ctrl_callbacks_t btrc_ctrl_callbacks = default_btrc_ctrl_callbacks; + +struct rc_connection_state_cb_t { + bool rc_state; + bool bt_state; + RawAddress raw_address; +}; + +struct rc_feature_cb_t { + int feature; + RawAddress raw_address; +}; + +static std::promise g_btrc_connection_state_promise; +static std::promise g_btrc_feature; + +class BtifRcWithCallbacksTest : public BtifRcTest { + protected: + void SetUp() override { + BtifRcTest::SetUp(); + btrc_ctrl_callbacks = default_btrc_ctrl_callbacks; + init_ctrl(&btrc_ctrl_callbacks); + jni_thread.StartUp(); + btrc_ctrl_callbacks.getrcfeatures_cb = [](const RawAddress& bd_addr, + int features) { + rc_feature_cb_t rc_feature = { + .feature = features, + .raw_address = bd_addr, + }; + g_btrc_feature.set_value(rc_feature); + }; + } + + void TearDown() override { + jni_thread.ShutDown(); + bt_rc_ctrl_callbacks->getrcfeatures_cb = [](const RawAddress& bd_addr, + int features) {}; + btrc_ctrl_callbacks = default_btrc_ctrl_callbacks; + BtifRcTest::TearDown(); + } +}; + +TEST_F(BtifRcWithCallbacksTest, handle_rc_ctrl_features) { + g_btrc_feature = std::promise(); + std::future future = g_btrc_feature.get_future(); + btif_rc_device_cb_t p_dev; + + p_dev.peer_tg_features = + (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCCT | + BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_BROWSE | + BTA_AV_FEAT_COVER_ARTWORK); + p_dev.rc_connected = true; + + handle_rc_ctrl_features(&p_dev); + ASSERT_EQ(1, get_func_call_count("AVRC_BldCommand")); + + CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(2))); + auto res = future.get(); + LOG_INFO("FEATURES:%d", res.feature); + CHECK(res.feature == (BTRC_FEAT_ABSOLUTE_VOLUME | BTRC_FEAT_METADATA | + BTRC_FEAT_BROWSE | BTRC_FEAT_COVER_ARTWORK)); +} + +class BtifRcBrowseConnectionTest : public BtifRcTest { + protected: + void SetUp() override { + BtifRcTest::SetUp(); + init_ctrl(&btrc_ctrl_callbacks); + jni_thread.StartUp(); + btrc_ctrl_callbacks.connection_state_cb = [](bool rc_state, bool bt_state, + const RawAddress& bd_addr) { + rc_connection_state_cb_t rc_connection_state = { + .rc_state = rc_state, + .bt_state = bt_state, + .raw_address = bd_addr, + }; + g_btrc_connection_state_promise.set_value(rc_connection_state); + }; + } + + void TearDown() override { + jni_thread.ShutDown(); + bt_rc_ctrl_callbacks->connection_state_cb = + [](bool rc_state, bool bt_state, const RawAddress& bd_addr) {}; + BtifRcTest::TearDown(); + } +}; + +TEST_F(BtifRcBrowseConnectionTest, handle_rc_browse_connect) { + g_btrc_connection_state_promise = std::promise(); + std::future future = + g_btrc_connection_state_promise.get_future(); + + tBTA_AV_RC_BROWSE_OPEN browse_data = { + .rc_handle = 0, + .peer_addr = {}, + .status = BTA_AV_SUCCESS, + }; + + btif_rc_cb.rc_multi_cb[0].rc_handle = 0; + btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_connected = false; + + /* process unit test handle_rc_browse_connect */ + handle_rc_browse_connect(&browse_data); + CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(2))); + auto res = future.get(); + CHECK(res.bt_state == true); +} + +class BtifRcConnectionTest : public BtifRcTest { + protected: + void SetUp() override { + BtifRcTest::SetUp(); + init_ctrl(&btrc_ctrl_callbacks); + jni_thread.StartUp(); + g_btrc_connection_state_promise = std::promise(); + g_btrc_connection_state_future = + g_btrc_connection_state_promise.get_future(); + btrc_ctrl_callbacks.connection_state_cb = [](bool rc_state, bool bt_state, + const RawAddress& bd_addr) { + rc_connection_state_cb_t rc_connection_state = { + .rc_state = rc_state, + .bt_state = bt_state, + .raw_address = bd_addr, + }; + g_btrc_connection_state_promise.set_value(rc_connection_state); + }; + } + + void TearDown() override { + jni_thread.ShutDown(); + bt_rc_ctrl_callbacks->connection_state_cb = + [](bool rc_state, bool bt_state, const RawAddress& bd_addr) {}; + BtifRcTest::TearDown(); + } + std::future g_btrc_connection_state_future; +}; + +TEST_F(BtifRcConnectionTest, btif_rc_connection_test) {} + +TEST_F(BtifRcConnectionTest, handle_rc_browse_connect) { + tBTA_AV_RC_BROWSE_OPEN browse_data = { + .rc_handle = 0, + .peer_addr = {}, + .status = BTA_AV_SUCCESS, + }; + + btif_rc_cb.rc_multi_cb[0].rc_handle = 0; + btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_connected = false; + + /* process unit test handle_rc_browse_connect */ + handle_rc_browse_connect(&browse_data); + CHECK(std::future_status::ready == + g_btrc_connection_state_future.wait_for(std::chrono::seconds(2))); + auto res = g_btrc_connection_state_future.get(); + CHECK(res.bt_state == true); +} + +TEST_F(BtifRcConnectionTest, btif_rc_check_pending_cmd) { + btif_rc_cb.rc_multi_cb[0].rc_handle = 0xff; + btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_connected = true; + btif_rc_cb.rc_multi_cb[0].launch_cmd_pending |= + (RC_PENDING_ACT_REG_VOL | RC_PENDING_ACT_GET_CAP | + RC_PENDING_ACT_REPORT_CONN); + + btif_rc_check_pending_cmd(kDeviceAddress); + ASSERT_EQ(1, get_func_call_count("AVRC_BldCommand")); + + CHECK(std::future_status::ready == + g_btrc_connection_state_future.wait_for(std::chrono::seconds(3))); + auto res = g_btrc_connection_state_future.get(); + CHECK(res.rc_state == true); +} + +TEST_F(BtifRcConnectionTest, bt_av_rc_open_evt) { + btrc_ctrl_callbacks.get_cover_art_psm_cb = [](const RawAddress& /* bd_addr */, + const uint16_t /* psm */) {}; + btrc_ctrl_callbacks.getrcfeatures_cb = [](const RawAddress& /* bd_addr */, + int /* features */) {}; + + /* handle_rc_connect */ + tBTA_AV data = { + .rc_open = + { + .rc_handle = 0, + .cover_art_psm = 0, + .peer_features = 0, + .peer_ct_features = 0, + .peer_tg_features = (BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR | + BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT), + .peer_addr = kDeviceAddress, + .status = BTA_AV_SUCCESS, + }, + }; + btif_rc_cb.rc_multi_cb[0].rc_handle = 0; + btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_DISCONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_connected = false; + + btif_rc_handler(BTA_AV_RC_OPEN_EVT, &data); + + CHECK(btif_rc_cb.rc_multi_cb[data.rc_open.rc_handle].rc_connected == true); + CHECK(btif_rc_cb.rc_multi_cb[data.rc_open.rc_handle].rc_state == + BTRC_CONNECTION_STATE_CONNECTED); + + CHECK(std::future_status::ready == + g_btrc_connection_state_future.wait_for(std::chrono::seconds(2))); + auto res = g_btrc_connection_state_future.get(); + CHECK(res.rc_state == true); +} + +class BtifTrackChangeCBTest : public BtifRcTest { + protected: + void SetUp() override { + BtifRcTest::SetUp(); + init_ctrl(&btrc_ctrl_callbacks); + jni_thread.StartUp(); + btrc_ctrl_callbacks.track_changed_cb = [](const RawAddress& bd_addr, + uint8_t num_attr, btrc_element_attr_val_t* p_attrs) { + btif_rc_cb.rc_multi_cb[0].rc_addr = bd_addr; + }; + } + + void TearDown() override { + jni_thread.ShutDown(); + btrc_ctrl_callbacks.track_changed_cb = [](const RawAddress& bd_addr, + uint8_t num_attr, btrc_element_attr_val_t* p_attrs) {}; + BtifRcTest::TearDown(); + } +}; + +TEST_F(BtifTrackChangeCBTest, handle_get_metadata_attr_response) { + tBTA_AV_META_MSG meta_msg = { + .rc_handle = 0, + .len = 0, + .label = 0, + .code{}, + .company_id = 0, + .p_data = {}, + .p_msg = nullptr, + }; + + tAVRC_GET_ATTRS_RSP rsp = { + .pdu = 0, + .status = AVRC_STS_NO_ERROR, + .opcode = 0, + .num_attrs = 0, + .p_attrs = nullptr, + }; + + btif_rc_cb.rc_multi_cb[0].rc_handle = 0; + btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_connected = true; + + handle_get_metadata_attr_response(&meta_msg, &rsp); + + ASSERT_EQ(1, get_func_call_count("osi_free_and_reset")); } diff --git a/system/build/Android.bp b/system/build/Android.bp index 4f3b393654933ad6fbf43381502710e51526dcb0..1292920110ce48379d331e4a65cb6055b522cf72 100644 --- a/system/build/Android.bp +++ b/system/build/Android.bp @@ -8,78 +8,13 @@ package { } cc_defaults { - name: "fluoride_common_options", - cflags: [ - "-Wall", - "-Werror", - "-Wextra", - // there are too many unused parameters in all the code. - "-Wno-unused-parameter", - // http://b/264549607 - "-Wno-deprecated-builtins", - ], - include_dirs: [ - "packages/modules/Bluetooth/system/gd", - ], -} - -cc_defaults { - name: "libchrome_support_defaults", - defaults: ["fluoride_common_options"], - static_libs: [ - "libchrome", - "libevent", - "libmodpb64", - ], - shared_libs: [ - "libbase", - ], - target: { - darwin: { - enabled: false, - }, - android: { - shared_libs: [ - "libcutils", - "liblog", - ], - }, - }, -} - -// Fuzzable defaults are the subset of defaults that are used in fuzzing, which -// requires no shared libraries, and no explicit sanitization. -cc_defaults { - name: "fluoride_types_defaults_fuzzable", - defaults: ["fluoride_common_options"], + name: "fluoride_defaults", + defaults: ["bluetooth_cflags"], cflags: [ "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))", - "-DLOG_NDEBUG=1", + "-DLOG_NDEBUG=0", "-fvisibility=hidden", - // struct BT_HDR is defined as a variable-size header in a struct. - "-Wno-gnu-variable-sized-type-not-at-end", ], - conlyflags: [ - "-std=c99", - ], - product_variables: { - debuggable: { - cflags: [ - "-DBLUEDROID_DEBUG", - ], - }, - }, -} - -cc_defaults { - name: "fluoride_types_defaults", - defaults: [ - "fluoride_types_defaults_fuzzable", - ], -} - -cc_defaults { - name: "fluoride_defaults_fuzzable", target: { android: { test_config_template: ":BluetoothTestConfigTemplate", @@ -87,134 +22,5 @@ cc_defaults { misc_undefined: ["bounds"], }, }, - host: { - static_libs: [ - "libcutils", - ], - }, - }, - defaults: ["fluoride_types_defaults_fuzzable"], - header_libs: ["libbluetooth_headers"], - generated_headers: [ - "cxx-bridge-header", - ], - include_dirs: ["packages/modules/Bluetooth/system/gd/rust/shim"], - static_libs: [ - "libbluetooth-types", - "libbluetooth_rust_interop", - "libbt-platform-protos-lite", - "libbt_shim_bridge", - "libbt_shim_ffi", - ], - shared_libs: [ - "liblog", - ], - cpp_std: "c++17", - min_sdk_version: "current", -} - -cc_defaults { - name: "fluoride_test_prod_shared_defaults", - defaults: ["fluoride_defaults"], -} - -cc_defaults { - name: "fluoride_test_defaults", - defaults: ["fluoride_test_prod_shared_defaults"], - host_supported: true, - shared_libs: [ - "libcrypto", - "liblog", - ], - static_libs: [ - "libbt-common", - "libbt-protos-lite", - "libcutils", - "libgmock", - "libosi", - "libosi-AlarmTestHarness", - "libosi-AllocationTestHarness", - ], - sanitize: { - address: true, - cfi: true, - misc_undefined: ["bounds"], - }, -} - -cc_defaults { - name: "fluoride_basic_defaults", - defaults: [ - "fluoride_test_prod_shared_defaults", - ], - apex_available: [ - "//apex_available:platform", - "com.android.btservices", - ], - shared_libs: [ - "android.hardware.bluetooth.audio@2.0", - "android.hardware.bluetooth.audio@2.1", - "libbase", - "libbinder_ndk", - "libcrypto", - "libfmq", - "libnativehelper", - ], - static_libs: [ - "android.hardware.bluetooth.a2dp@1.0", - "libFraunhoferAAC", - "libbluetooth-dumpsys", - "libbt-protos-lite", - "libbt-sbc-decoder", - "libbt-sbc-encoder", - "libflatbuffers-cpp", - "libg722codec", - "liblc3", - "libopus", - "libprotobuf-cpp-lite", - "libudrv-uipc", - ], - target: { - android: { - shared_libs: [ - "android.system.suspend-V1-ndk", - "libPlatformProperties", - "libaaudio", - ], - static_libs: [ - "android.system.suspend.control-V1-ndk", - ], - }, - }, -} - -cc_defaults { - name: "fluoride_defaults", - defaults: [ - "fluoride_defaults_fuzzable", - "fluoride_types_defaults", - ], - static_libs: [ - "libbluetooth_gd", - "libstatslog_bt", - ], - shared_libs: [ - "libcutils", - "libhidlbase", - "libutils", - ], - target: { - darwin: { - // libstatslog_bt -> libbinder doesn't build on mac - enabled: false, - }, - android: { - shared_libs: [ - "libstatssocket", - ], - sanitize: { - misc_undefined: ["bounds"], - }, - }, }, } diff --git a/system/build/BUILD.gn b/system/build/BUILD.gn deleted file mode 100644 index bba89024bc964e0b4d3b320658fbaccfb64c2723..0000000000000000000000000000000000000000 --- a/system/build/BUILD.gn +++ /dev/null @@ -1,67 +0,0 @@ -# -# Copyright 2015 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. -# - -config("default_include_dirs") { - include_dirs = [ - "//include/", - "//types/", - ] -} - -config("linux") { - # TODO(keybuk): AndroidConfig.h or equivalent - - cflags = [ - #TODO(jpawlowski): uncomment once we have no warnings on linux build - # "-Wall", - # "-Werror", - "-Wno-gnu-variable-sized-type-not-at-end", - "-g", - "-O0", - "-fpic", - "-fdata-sections", - "-ffunction-sections", - "-fvisibility=hidden", - ] - - cflags_c = [ "-std=c99" ] - - cflags_cc = [ -#TODO(jpawlowski): we should use same c++ version as Android, which is c++11, -# but we use some c++14 features. Uncomment when this get fixed in code.: - "-std=c++14", - "-fno-exceptions", - "-fpermissive", - ] - - defines = [ - "_FORTIFY_SOURCE=2", - "_GNU_SOURCE", - "LOG_NDEBUG=1", - "EXPORT_SYMBOL=__attribute__((visibility(\"default\")))", - "KERNEL_MISSING_CLOCK_BOOTTIME_ALARM=TRUE", - - "FALLTHROUGH_INTENDED", - ] -} - -config("pic") { - cflags = [ "-fPIC" ] -} - -config("gc") { - ldflags = [ "-Wl,--gc-sections" ] -} diff --git a/system/build/config/BUILDCONFIG.gn b/system/build/config/BUILDCONFIG.gn deleted file mode 100644 index 765b21e2b5c1ab164423ebc938fb844c50e7145a..0000000000000000000000000000000000000000 --- a/system/build/config/BUILDCONFIG.gn +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright 2015 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. -# - -set_default_toolchain("//build/toolchain/clang") -toolchain_config="//build/toolchain/clang:clang_config" - -set_defaults("executable") { - configs = [ - "//build:linux", - "//build:gc", - "//build:default_include_dirs", - toolchain_config, - ] -} - -set_defaults("shared_library") { - configs = [ - "//build:linux", - "//build:gc", - "//build:default_include_dirs", - toolchain_config, - ] -} - -set_defaults("source_set") { - configs = [ - "//build:linux", - "//build:gc", - "//build:default_include_dirs", - toolchain_config, - ] -} - -set_defaults("static_library") { - configs = [ - "//build:linux", - "//build:gc", - "//build:default_include_dirs", - toolchain_config, - ] -} diff --git a/system/build/secondary/third_party/aac/BUILD.gn b/system/build/secondary/third_party/aac/BUILD.gn deleted file mode 100644 index 18fcf93d0134a2da6c87c1a8f4a5bea1bc9badd3..0000000000000000000000000000000000000000 --- a/system/build/secondary/third_party/aac/BUILD.gn +++ /dev/null @@ -1,230 +0,0 @@ -# -# Copyright 2017 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. -# - -config("libFraunhoferAAC_config") { - include_dirs = [ - "libAACdec/include", - "libAACenc/include", - "libArithCoding/include", - "libDRCdec/include", - "libPCMutils/include", - "libFDK/include", - "libSYS/include", - "libMpegTPDec/include", - "libMpegTPEnc/include", - "libSACenc/include", - "libSACdec/include", - "libSBRdec/include", - "libSBRenc/include", - ] -} - -#TODO(jpawlowski): this files are not build right now, but might be useful when -# arm platform linux compilation is in use: -# "libAACdec/src/arm/block_arm.cpp", -# "libFDK/src/arm/dct_arm.cpp", -# "libFDK/src/arm/fft_rad2_arm.cpp", -# "libFDK/src/arm/scale_arm.cpp", -# "libSBRdec/src/arm/lpp_tran_arm.cpp", -# "libFDK/src/mips/fft_rad2_mips.cpp", -# "libFDK/src/mips/mips_fft_twiddles.cpp", -# "libFDK/src/mips/scale_mips.cpp", - -static_library("libFraunhoferAAC") { - sources = [ - "libAACdec/src/aacdec_drc.cpp", - "libAACdec/src/aacdec_hcr_bit.cpp", - "libAACdec/src/aacdec_hcr.cpp", - "libAACdec/src/aacdec_hcrs.cpp", - "libAACdec/src/aacdecoder.cpp", - "libAACdec/src/aacdecoder_lib.cpp", - "libAACdec/src/aacdec_pns.cpp", - "libAACdec/src/aacdec_tns.cpp", - "libAACdec/src/aac_ram.cpp", - "libAACdec/src/aac_rom.cpp", - "libAACdec/src/block.cpp", - "libAACdec/src/channel.cpp", - "libAACdec/src/channelinfo.cpp", - "libAACdec/src/conceal.cpp", - "libAACdec/src/FDK_delay.cpp", - "libAACdec/src/ldfiltbank.cpp", - "libAACdec/src/pulsedata.cpp", - "libAACdec/src/rvlcbit.cpp", - "libAACdec/src/rvlcconceal.cpp", - "libAACdec/src/rvlc.cpp", - "libAACdec/src/stereo.cpp", - "libAACdec/src/usacdec_ace_d4t64.cpp", - "libAACdec/src/usacdec_acelp.cpp", - "libAACdec/src/usacdec_ace_ltp.cpp", - "libAACdec/src/usacdec_fac.cpp", - "libAACdec/src/usacdec_lpc.cpp", - "libAACdec/src/usacdec_lpd.cpp", - "libAACdec/src/usacdec_rom.cpp", - "libAACenc/src/aacenc.cpp", - "libAACenc/src/aacenc_lib.cpp", - "libAACenc/src/aacenc_pns.cpp", - "libAACenc/src/aacEnc_ram.cpp", - "libAACenc/src/aacEnc_rom.cpp", - "libAACenc/src/aacenc_tns.cpp", - "libAACenc/src/adj_thr.cpp", - "libAACenc/src/band_nrg.cpp", - "libAACenc/src/bandwidth.cpp", - "libAACenc/src/bit_cnt.cpp", - "libAACenc/src/bitenc.cpp", - "libAACenc/src/block_switch.cpp", - "libAACenc/src/channel_map.cpp", - "libAACenc/src/chaosmeasure.cpp", - "libAACenc/src/dyn_bits.cpp", - "libAACenc/src/grp_data.cpp", - "libAACenc/src/intensity.cpp", - "libAACenc/src/line_pe.cpp", - "libAACenc/src/metadata_compressor.cpp", - "libAACenc/src/metadata_main.cpp", - "libAACenc/src/mps_main.cpp", - "libAACenc/src/ms_stereo.cpp", - "libAACenc/src/noisedet.cpp", - "libAACenc/src/pnsparam.cpp", - "libAACenc/src/pre_echo_control.cpp", - "libAACenc/src/psy_configuration.cpp", - "libAACenc/src/psy_main.cpp", - "libAACenc/src/qc_main.cpp", - "libAACenc/src/quantize.cpp", - "libAACenc/src/sf_estim.cpp", - "libAACenc/src/spreading.cpp", - "libAACenc/src/tonality.cpp", - "libAACenc/src/transform.cpp", - "libArithCoding/src/ac_arith_coder.cpp", - "libDRCdec/src/drcDec_gainDecoder.cpp", - "libDRCdec/src/drcDec_reader.cpp", - "libDRCdec/src/drcDec_rom.cpp", - "libDRCdec/src/drcDec_selectionProcess.cpp", - "libDRCdec/src/drcDec_tools.cpp", - "libDRCdec/src/drcGainDec_init.cpp", - "libDRCdec/src/drcGainDec_preprocess.cpp", - "libDRCdec/src/drcGainDec_process.cpp", - "libDRCdec/src/FDK_drcDecLib.cpp", - "libFDK/src/autocorr2nd.cpp", - "libFDK/src/dct.cpp", - "libFDK/src/FDK_bitbuffer.cpp", - "libFDK/src/FDK_core.cpp", - "libFDK/src/FDK_crc.cpp", - "libFDK/src/FDK_decorrelate.cpp", - "libFDK/src/FDK_hybrid.cpp", - "libFDK/src/FDK_lpc.cpp", - "libFDK/src/FDK_matrixCalloc.cpp", - "libFDK/src/FDK_qmf_domain.cpp", - "libFDK/src/FDK_tools_rom.cpp", - "libFDK/src/FDK_trigFcts.cpp", - "libFDK/src/fft.cpp", - "libFDK/src/fft_rad2.cpp", - "libFDK/src/fixpoint_math.cpp", - "libFDK/src/huff_nodes.cpp", - "libFDK/src/mdct.cpp", - "libFDK/src/nlc_dec.cpp", - "libFDK/src/qmf.cpp", - "libFDK/src/scale.cpp", - "libMpegTPDec/src/tpdec_adif.cpp", - "libMpegTPDec/src/tpdec_adts.cpp", - "libMpegTPDec/src/tpdec_asc.cpp", - "libMpegTPDec/src/tpdec_drm.cpp", - "libMpegTPDec/src/tpdec_latm.cpp", - "libMpegTPDec/src/tpdec_lib.cpp", - "libMpegTPEnc/src/tpenc_adif.cpp", - "libMpegTPEnc/src/tpenc_adts.cpp", - "libMpegTPEnc/src/tpenc_asc.cpp", - "libMpegTPEnc/src/tpenc_latm.cpp", - "libMpegTPEnc/src/tpenc_lib.cpp", - "libPCMutils/src/limiter.cpp", - "libPCMutils/src/pcmdmx_lib.cpp", - "libPCMutils/src/pcm_utils.cpp", - "libSACdec/src/sac_bitdec.cpp", - "libSACdec/src/sac_calcM1andM2.cpp", - "libSACdec/src/sac_dec_conceal.cpp", - "libSACdec/src/sac_dec.cpp", - "libSACdec/src/sac_dec_lib.cpp", - "libSACdec/src/sac_process.cpp", - "libSACdec/src/sac_qmf.cpp", - "libSACdec/src/sac_reshapeBBEnv.cpp", - "libSACdec/src/sac_rom.cpp", - "libSACdec/src/sac_smoothing.cpp", - "libSACdec/src/sac_stp.cpp", - "libSACdec/src/sac_tsd.cpp", - "libSACenc/src/sacenc_bitstream.cpp", - "libSACenc/src/sacenc_delay.cpp", - "libSACenc/src/sacenc_dmx_tdom_enh.cpp", - "libSACenc/src/sacenc_filter.cpp", - "libSACenc/src/sacenc_framewindowing.cpp", - "libSACenc/src/sacenc_huff_tab.cpp", - "libSACenc/src/sacenc_lib.cpp", - "libSACenc/src/sacenc_nlc_enc.cpp", - "libSACenc/src/sacenc_onsetdetect.cpp", - "libSACenc/src/sacenc_paramextract.cpp", - "libSACenc/src/sacenc_staticgain.cpp", - "libSACenc/src/sacenc_tree.cpp", - "libSACenc/src/sacenc_vectorfunctions.cpp", - "libSBRdec/src/env_calc.cpp", - "libSBRdec/src/env_dec.cpp", - "libSBRdec/src/env_extr.cpp", - "libSBRdec/src/hbe.cpp", - "libSBRdec/src/HFgen_preFlat.cpp", - "libSBRdec/src/huff_dec.cpp", - "libSBRdec/src/lpp_tran.cpp", - "libSBRdec/src/psbitdec.cpp", - "libSBRdec/src/psdec.cpp", - "libSBRdec/src/psdec_drm.cpp", - "libSBRdec/src/psdecrom_drm.cpp", - "libSBRdec/src/pvc_dec.cpp", - "libSBRdec/src/sbr_crc.cpp", - "libSBRdec/src/sbr_deb.cpp", - "libSBRdec/src/sbr_dec.cpp", - "libSBRdec/src/sbrdec_drc.cpp", - "libSBRdec/src/sbrdec_freq_sca.cpp", - "libSBRdec/src/sbrdecoder.cpp", - "libSBRdec/src/sbr_ram.cpp", - "libSBRdec/src/sbr_rom.cpp", - "libSBRenc/src/bit_sbr.cpp", - "libSBRenc/src/code_env.cpp", - "libSBRenc/src/env_bit.cpp", - "libSBRenc/src/env_est.cpp", - "libSBRenc/src/fram_gen.cpp", - "libSBRenc/src/invf_est.cpp", - "libSBRenc/src/mh_det.cpp", - "libSBRenc/src/nf_est.cpp", - "libSBRenc/src/ps_bitenc.cpp", - "libSBRenc/src/ps_encode.cpp", - "libSBRenc/src/ps_main.cpp", - "libSBRenc/src/resampler.cpp", - "libSBRenc/src/sbrenc_freq_sca.cpp", - "libSBRenc/src/sbr_encoder.cpp", - "libSBRenc/src/sbrenc_ram.cpp", - "libSBRenc/src/sbrenc_rom.cpp", - "libSBRenc/src/sbr_misc.cpp", - "libSBRenc/src/ton_corr.cpp", - "libSBRenc/src/tran_det.cpp", - "libSYS/src/genericStds.cpp", - "libSYS/src/syslib_channelMapDescr.cpp", - ] - - public_configs = [ ":libFraunhoferAAC_config" ] - - cflags = [ - "-Wno-sequence-point", - "-Wno-extra", - "-Wno-#warnings", - "-Wno-constant-logical-operand", - "-Wno-self-assign", - ] -} diff --git a/system/build/secondary/third_party/googletest/BUILD.gn b/system/build/secondary/third_party/googletest/BUILD.gn deleted file mode 100644 index 54c53d7b0f594ce2957930a48a75afeeea9c19b8..0000000000000000000000000000000000000000 --- a/system/build/secondary/third_party/googletest/BUILD.gn +++ /dev/null @@ -1,91 +0,0 @@ -# -# Copyright 2016 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. -# - -config("gtest_config") { - # Gtest headers need to be able to find themselves. - include_dirs = [ "googletest/include" ] - - defines = [ "GTEST_HAS_RTTI=0" ] -} - -config("gtest_direct_config") { - visibility = [ ":*" ] - defines = [ "UNIT_TEST" ] -} - -static_library("gtest") { - testonly = true - sources = [ - "googletest/src/gtest-all.cc", - ] - - include_dirs = [ - "googletest/", - "googletest/include", - ] - - all_dependent_configs = [ ":gtest_config" ] - public_configs = [ ":gtest_direct_config" ] -} - -source_set("gtest_main") { - testonly = true - sources = [ - "googletest/src/gtest_main.cc", - ] - deps = [ - ":gtest", - ] -} - -config("gmock_config") { - # Gmock headers need to be able to find themselves. - include_dirs = [ "googlemock/include" ] -} - -static_library("gmock") { - testonly = true - sources = [ - "googlemock/src/gmock-all.cc", - ] - - # This project includes some stuff form gtest's guts. - include_dirs = [ - "googlemock", - "googlemock/include", - ] - - public_configs = [ - ":gmock_config", - ":gtest_config", - ] -} - -static_library("gmock_main") { - testonly = true - sources = [ - "googlemock/src/gmock_main.cc", - ] - deps = [ - ":gmock", - ":gtest", - ] - - public_configs = [ - ":gmock_config", - ":gtest_config", - ] -} diff --git a/system/build/secondary/third_party/libchrome/BUILD.gn b/system/build/secondary/third_party/libchrome/BUILD.gn deleted file mode 100644 index 1b0d2f0afcaaae24747b8f5323df0604d5e3eb25..0000000000000000000000000000000000000000 --- a/system/build/secondary/third_party/libchrome/BUILD.gn +++ /dev/null @@ -1,272 +0,0 @@ -# -# Copyright 2015 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. -# - -source_set("base_sources") { - sources = [ - "base/at_exit.cc", - "base/atomic_ref_count.h", - "base/atomic_sequence_num.h", - "base/atomicops.h", - "base/base64.cc", - "base/base64.h", - "base/base_export.h", - "base/base_switches.cc", - "base/build_time.cc", - "base/callback_helpers.cc", - "base/callback_internal.cc", - "base/command_line.cc", - "base/cpu.cc", - "base/debug/activity_tracker.cc", - "base/debug/alias.cc", - "base/debug/dump_without_crashing.cc", - "base/debug/debugger.cc", - "base/debug/debugger_posix.cc", - "base/debug/stack_trace.cc", - "base/debug/stack_trace_posix.cc", - "base/debug/task_annotator.cc", - "base/environment.cc", - "base/files/file.cc", - "base/files/file_descriptor_watcher_posix.cc", - "base/files/file_enumerator.cc", - "base/files/file_enumerator_posix.cc", - "base/files/file_path.cc", - "base/files/file_path_constants.cc", - "base/files/file_path_watcher.cc", - "base/files/file_path_watcher_linux.cc", - "base/files/file_posix.cc", - "base/files/file_tracing.cc", - "base/files/file_util.cc", - "base/files/file_util_linux.cc", - "base/files/file_util_posix.cc", - "base/files/important_file_writer.cc", - "base/files/scoped_file.cc", - "base/files/scoped_temp_dir.cc", - "base/guid.cc", - "base/json/json_parser.cc", - "base/json/json_reader.cc", - "base/json/json_string_value_serializer.cc", - "base/json/json_writer.cc", - "base/json/string_escape.cc", - "base/lazy_instance_helpers.cc", - "base/location.cc", - "base/logging.cc", - "base/md5.cc", - "base/memory/ref_counted.cc", - "base/memory/ref_counted_memory.cc", - "base/memory/weak_ptr.cc", - "base/message_loop/incoming_task_queue.cc", - "base/message_loop/message_loop.cc", - "base/message_loop/message_loop_current.cc", - "base/message_loop/message_loop_task_runner.cc", - "base/message_loop/message_pump.cc", - "base/message_loop/message_pump_default.cc", - "base/message_loop/message_pump_libevent.cc", - "base/message_loop/watchable_io_message_pump_posix.cc", - - # we don't want any glib dependencies. - # "base/message_loop/message_pump_glib.cc", - "base/metrics/bucket_ranges.cc", - "base/metrics/dummy_histogram.cc", - "base/metrics/field_trial.cc", - "base/metrics/field_trial_param_associator.cc", - "base/metrics/histogram.cc", - "base/metrics/histogram_base.cc", - "base/metrics/histogram_functions.cc", - "base/metrics/histogram_samples.cc", - "base/metrics/histogram_snapshot_manager.cc", - "base/metrics/metrics_hashes.cc", - "base/metrics/persistent_histogram_allocator.cc", - "base/metrics/persistent_memory_allocator.cc", - "base/metrics/persistent_sample_map.cc", - "base/metrics/sample_map.cc", - "base/metrics/sample_vector.cc", - "base/metrics/sparse_histogram.cc", - "base/metrics/statistics_recorder.cc", - "base/native_library.cc", - "base/observer_list_threadsafe.cc", - "base/path_service.cc", - "base/pending_task.cc", - "base/pickle.cc", - "base/posix/file_descriptor_shuffle.cc", - "base/posix/global_descriptors.cc", - "base/posix/safe_strerror.cc", - "base/process/internal_linux.cc", - "base/process/kill.cc", - "base/process/kill_posix.cc", - "base/process/launch.cc", - "base/process/launch_posix.cc", - "base/process/memory.cc", - "base/process/process_handle.cc", - "base/process/process_handle_linux.cc", - "base/process/process_handle_posix.cc", - "base/process/process_info_linux.cc", - "base/process/process_iterator.cc", - "base/process/process_iterator_linux.cc", - "base/process/process_metrics.cc", - "base/process/process_metrics_linux.cc", - "base/process/process_metrics_posix.cc", - "base/process/process_posix.cc", - "base/rand_util.cc", - "base/rand_util_posix.cc", - "base/run_loop.cc", - "base/sequence_checker_impl.cc", - "base/sequenced_task_runner.cc", - "base/sequence_token.cc", - "base/sha1.cc", - "base/strings/pattern.cc", - "base/strings/safe_sprintf.cc", - "base/strings/string16.cc", - "base/strings/string_number_conversions.cc", - "base/strings/string_piece.cc", - "base/strings/stringprintf.cc", - "base/strings/string_split.cc", - "base/strings/string_util.cc", - "base/strings/string_util_constants.cc", - "base/strings/sys_string_conversions_posix.cc", - "base/strings/utf_string_conversions.cc", - "base/strings/utf_string_conversion_utils.cc", - "base/synchronization/atomic_flag.cc", - "base/synchronization/condition_variable_posix.cc", - "base/synchronization/lock.cc", - "base/synchronization/lock_impl_posix.cc", - "base/synchronization/waitable_event_posix.cc", - "base/sync_socket_posix.cc", - "base/sys_info.cc", - - # TODO(armansito): For our GN builds these platform-specific implementations - # don't really make that much sense but instead of removing the line I'm - # commenting it out in case we want to re-add it later (it's included in the - # libchrome Android.mk). - #"sys_info_chromeos.cc", - "base/sys_info_linux.cc", - "base/sys_info_posix.cc", - "base/task/cancelable_task_tracker.cc", - "base/task_runner.cc", - "base/third_party/icu/icu_utf.cc", - "base/third_party/nspr/prtime.cc", - "base/threading/platform_thread_internal_posix.cc", - "base/threading/platform_thread_linux.cc", - "base/threading/platform_thread_posix.cc", - "base/threading/post_task_and_reply_impl.cc", - "base/threading/scoped_blocking_call.cc", - "base/threading/sequence_local_storage_map.cc", - "base/threading/sequence_local_storage_slot.cc", - "base/threading/sequenced_task_runner_handle.cc", - "base/threading/simple_thread.cc", - "base/threading/thread.cc", - "base/threading/thread_checker_impl.cc", - "base/threading/thread_collision_warner.cc", - "base/threading/thread_id_name_manager.cc", - "base/threading/thread_local_storage.cc", - "base/threading/thread_local_storage_posix.cc", - "base/threading/thread_restrictions.cc", - "base/threading/thread_task_runner_handle.cc", - "base/time/clock.cc", - "base/time/default_clock.cc", - "base/time/default_tick_clock.cc", - "base/time/tick_clock.cc", - "base/time/time.cc", - "base/time/time_conversion_posix.cc", - "base/time/time_exploded_posix.cc", - "base/time/time_now_posix.cc", - "base/time/time_override.cc", - "base/timer/elapsed_timer.cc", - "base/timer/timer.cc", - "base/unguessable_token.cc", - "base/value_iterators.cc", - "base/values.cc", - "base/version.cc", - "base/vlog.cc", - - "dbus/bus.cc", - "dbus/dbus_statistics.cc", - "dbus/exported_object.cc", - "dbus/message.cc", - "dbus/object_manager.cc", - "dbus/object_path.cc", - "dbus/object_proxy.cc", - "dbus/property.cc", - "dbus/scoped_dbus_error.cc", - "dbus/string_util.cc", - "dbus/util.cc", - "dbus/values_util.cc" - ] - - defines = [ - "BASE_IMPLEMENTATION", - - # trick libchrome to think we're building host code within an Android checkout - # thanks to it no glib dependency - "__ANDROID_HOST__=1", - "OS_LINUX=1", - ] - - include_dirs = [ - "//", - "//third_party/googletest/googletest/include", - "//third_party/libchrome", - "//third_party/libevent", - "//third_party/libevent/include", - "//third_party/libchrome/base", - "//third_party/libchrome/dbus", - "//third_party/modp_b64", - - # paths to dbus headers, can be obtained by "pkg-config --cflags dbus-1" - #TODO(jpawlowski) use pkg-config script like build/config/linux/pkg_config.gni - "/usr/include/dbus-1.0/", - "/usr/lib/x86_64-linux-gnu/dbus-1.0/include", - ] -} - -config("libchrome_config") { - # libchrome headers need to be able to find themselves. - include_dirs = [ - "//third_party/googletest/googletest/include", - "//third_party/libchrome", - - # paths to dbus headers, can be obtained by "pkg-config --cflags dbus-1" - #TODO(jpawlowski) use pkg-config script like build/config/linux/pkg_config.gni - "/usr/include/dbus-1.0/", - "/usr/lib/x86_64-linux-gnu/dbus-1.0/include", - ] -} - -static_library("base") { - deps = [ - ":base_sources", - ] - - cflags = [ - "-Wno-char-subscripts", - "-Wno-missing-field-initializers", - "-Wno-unused-function", - "-Wno-unused_parameter", - ] - cflags_cc = [ - "-Wno-deprecated-register", - "-Wno-non-virtual-dtor", - "-Wno-sign-promo", - ] - - libs = [ - "-levent", - "-levent_core", - "-lpthread", - "-ldbus-1", - ] - - public_configs = [ ":libchrome_config" ] -} diff --git a/system/build/toolchain/clang/BUILD.gn b/system/build/toolchain/clang/BUILD.gn deleted file mode 100644 index ee86e275f8a0b8d7124cc2ebad530fcea69593fe..0000000000000000000000000000000000000000 --- a/system/build/toolchain/clang/BUILD.gn +++ /dev/null @@ -1,116 +0,0 @@ -# -# Copyright 2016 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. -# -clang_suffix = exec_script("get_clang_suffix.py", [], "list lines") -clang_suffix = clang_suffix[0] -assert(clang_suffix != "None", - "Cannot find clang, please install clang 3.5 or above") -if (clang_suffix != "") { - clang_suffix = "-" + clang_suffix -} -clang = "clang$clang_suffix" -clangxx = "clang++$clang_suffix" - -config("clang_config") { - include_dirs = [ - "/usr/include/libcxxabi", - ] - cflags_cc = [ - "-stdlib=libc++", - ] - ldflags = [ - "-stdlib=libc++", - ] -} - -toolchain("clang") { - tool("cc") { - depfile = "{{output}}.d" - command = "$clang -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" - depsformat = "gcc" - description = "CC {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] - } - - tool("cxx") { - depfile = "{{output}}.d" - command = "$clangxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" - depsformat = "gcc" - description = "CXX {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] - } - - tool("alink") { - rspfile = "{{output}}.rsp" - command = "rm -f {{output}} && ar rcs {{output}} @$rspfile" - description = "AR {{target_output_name}}{{output_extension}}" - rspfile_content = "{{inputs}}" - outputs = [ - "{{target_out_dir}}/{{target_output_name}}{{output_extension}}", - ] - default_output_extension = ".a" - - output_prefix = "lib" - } - - tool("solink") { - soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". - rspfile = soname + ".rsp" - - command = - "$clangxx -shared {{ldflags}} -o $soname -Wl,-soname=$soname @$rspfile" - rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}" - - description = "SOLINK $soname" - - # Use this for {{output_extension}} expansions unless a target manually - # overrides it (in which case {{output_extension}} will be what the target - # specifies). - default_output_extension = ".so" - - outputs = [ - soname, - ] - link_output = soname - depend_output = soname - - output_prefix = "lib" - } - - tool("link") { - outfile = "{{target_output_name}}{{output_extension}}" - rspfile = "$outfile.rsp" - command = "$clangxx {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}" - description = "LINK $outfile" - rspfile_content = "{{inputs}}" - outputs = [ - outfile, - ] - } - - tool("stamp") { - command = "touch {{output}}" - description = "STAMP {{output}}" - } - - tool("copy") { - command = "cp -af {{source}} {{output}}" - description = "COPY {{source}} {{output}}" - } -} diff --git a/system/build/toolchain/clang/get_clang_suffix.py b/system/build/toolchain/clang/get_clang_suffix.py deleted file mode 100644 index 6bf7b9c8ba4db085d2b84a6db73b654555297d08..0000000000000000000000000000000000000000 --- a/system/build/toolchain/clang/get_clang_suffix.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -import subprocess -import re -import sys - - -def which(cmd): - for p in os.environ["PATH"].split(os.pathsep): - clang_path = os.path.join(p, cmd) - if os.path.exists(clang_path): - return clang_path - return None - - -CLANG_VERSION_REGEX = ".*version\s*([0-9]*\.[0-9]*)\.*" -clang_path = which("clang++") -clang_version_major = 0 -clang_version_minor = 0 - -if clang_path: - clang_version_out = subprocess.Popen([clang_path, "--version"], stdout=subprocess.PIPE).communicate()[0] - clang_version_match = re.search(CLANG_VERSION_REGEX, clang_version_out) - clang_version_str = clang_version_match.group(1) - clang_version_array = clang_version_str.split('.') - clang_version_major = int(clang_version_array[0]) - clang_version_minor = int(clang_version_array[1]) - -if clang_version_major >= 3 and clang_version_minor >= 5: - print "" -else: - # Loop in support clang version only - clang_version_major = 3 - clang_version_minor = 9 - while clang_version_major >= 3 and clang_version_minor >= 5: - clang_version_str = "%d.%d" % (clang_version_major, clang_version_minor) - clang_path = which("clang++-" + clang_version_str) - if clang_path: - print clang_version_str - sys.exit(0) - clang_version_minor -= 1 - if clang_version_minor < 0: - clang_version_minor = 9 - clang_version_major -= 1 - print "None" diff --git a/system/build/toolchain/gcc/BUILD.gn b/system/build/toolchain/gcc/BUILD.gn deleted file mode 100644 index 1c92d0a12565e4ef30634baf2a676a055f68b79c..0000000000000000000000000000000000000000 --- a/system/build/toolchain/gcc/BUILD.gn +++ /dev/null @@ -1,97 +0,0 @@ -# -# Copyright 2015 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. -# -cc = "gcc" -cxx = "g++" - -toolchain("gcc") { - tool("cc") { - depfile = "{{output}}.d" - command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" - depsformat = "gcc" - description = "CC {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] - } - - tool("cxx") { - depfile = "{{output}}.d" - command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" - depsformat = "gcc" - description = "CXX {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] - } - - tool("alink") { - rspfile = "{{output}}.rsp" - command = "rm -f {{output}} && ar rcs {{output}} @$rspfile" - description = "AR {{target_output_name}}{{output_extension}}" - rspfile_content = "{{inputs}}" - outputs = [ - "{{target_out_dir}}/{{target_output_name}}{{output_extension}}", - ] - default_output_extension = ".a" - - output_prefix = "lib" - } - - tool("solink") { - soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". - rspfile = soname + ".rsp" - - command = - "$cxx -shared {{ldflags}} -o $soname -Wl,-soname=$soname @$rspfile" - rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}" - - description = "SOLINK $soname" - - # Use this for {{output_extension}} expansions unless a target manually - # overrides it (in which case {{output_extension}} will be what the target - # specifies). - default_output_extension = ".so" - - outputs = [ - soname, - ] - link_output = soname - depend_output = soname - - output_prefix = "lib" - } - - tool("link") { - outfile = "{{target_output_name}}{{output_extension}}" - rspfile = "$outfile.rsp" - command = "$cxx {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}" - description = "LINK $outfile" - rspfile_content = "{{inputs}}" - outputs = [ - outfile, - ] - } - - tool("stamp") { - command = "touch {{output}}" - description = "STAMP {{output}}" - } - - tool("copy") { - command = "cp -af {{source}} {{output}}" - description = "COPY {{source}} {{output}}" - } -} diff --git a/system/common/Android.bp b/system/common/Android.bp index cbf039125c415e9b692928f5d124fa66fb7d578e..6fd7ff021d491f68623c4db78e830fd85931a45e 100644 --- a/system/common/Android.bp +++ b/system/common/Android.bp @@ -10,13 +10,12 @@ package { cc_library_static { name: "libbt-common", defaults: [ - "fluoride_basic_defaults", + "fluoride_defaults", ], host_supported: true, include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/stack/include", ], srcs: [ @@ -28,22 +27,44 @@ cc_library_static { "stop_watch_legacy.cc", "time_util.cc", ], + proto: { + type: "lite", + canonical_path_from_root: false, + export_proto_headers: true, + }, target: { android: { - srcs: ["metrics.cc"], + srcs: [ + ":bluetooth-metrics-proto", + "metrics.cc", + ], + static_libs: ["libstatslog_bt"], }, host: { srcs: ["metrics_linux.cc"], }, }, + shared_libs: [ + "libcrypto", + "libcutils", + ], + apex_available: [ + "com.android.btservices", + ], min_sdk_version: "Tiramisu", + header_libs: ["libbluetooth_headers"], + static_libs: [ + "libbluetooth_crypto_toolbox", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + ], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "bluetooth_test_common", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -54,7 +75,6 @@ cc_test { include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/stack/include", ], srcs: [ @@ -72,14 +92,19 @@ cc_test { target: { android: { srcs: ["metrics_unittest.cc"], + shared_libs: ["libstatssocket"], }, }, shared_libs: [ "libcrypto", + "liblog", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", "libchrome", "libevent", "libgmock", @@ -88,16 +113,17 @@ cc_test { sanitize: { cfi: false, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_performance", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], include_dirs: ["packages/modules/Bluetooth/system"], host_supported: true, srcs: [ @@ -113,6 +139,8 @@ cc_test { "libgmock", "libosi", ], + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_benchmark { @@ -126,7 +154,6 @@ cc_benchmark { "benchmark/thread_performance_benchmark.cc", ], shared_libs: [ - "libcrypto", "liblog", ], static_libs: [ @@ -135,4 +162,6 @@ cc_benchmark { "libevent", "libosi", ], + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/common/address_obfuscator.cc b/system/common/address_obfuscator.cc index 1803520a4d14c659976d85cc50b09c65ecebeea9..94f0afa6411deb2bef497ec0da2bfbed5b57e536 100644 --- a/system/common/address_obfuscator.cc +++ b/system/common/address_obfuscator.cc @@ -23,7 +23,7 @@ #include -#include "bt_trace.h" +#include "internal_include/bt_trace.h" #include "types/raw_address.h" namespace bluetooth { diff --git a/system/common/address_obfuscator.h b/system/common/address_obfuscator.h index b8e7dc27f9574581bf22214b02579c507bbca66b..9118b07af86f9c721d96985af472c3fe4885be04 100644 --- a/system/common/address_obfuscator.h +++ b/system/common/address_obfuscator.h @@ -18,10 +18,10 @@ #pragma once -#include #include #include +#include "gd/hci/octets.h" #include "raw_address.h" namespace bluetooth { @@ -29,8 +29,8 @@ namespace common { class AddressObfuscator { public: - static constexpr unsigned int kOctet32Length = 32; - using Octet32 = std::array; + static constexpr unsigned int kOctet32Length = hci::kOctet32Length; + using Octet32 = hci::Octet32; static AddressObfuscator* GetInstance() { static auto instance = new AddressObfuscator(); return instance; diff --git a/system/common/message_loop_thread.cc b/system/common/message_loop_thread.cc index 0d647029cfdd121744dff35b53339e3f18a41f52..e6921cc0ad7b76873c8b68a097c32faf2ca5cb4d 100644 --- a/system/common/message_loop_thread.cc +++ b/system/common/message_loop_thread.cc @@ -33,10 +33,6 @@ namespace common { static constexpr int kRealTimeFifoSchedulingPriority = 1; MessageLoopThread::MessageLoopThread(const std::string& thread_name) - : MessageLoopThread(thread_name, false) {} - -MessageLoopThread::MessageLoopThread(const std::string& thread_name, - bool is_main) : thread_name_(thread_name), message_loop_(nullptr), run_loop_(nullptr), @@ -44,8 +40,7 @@ MessageLoopThread::MessageLoopThread(const std::string& thread_name, thread_id_(-1), linux_tid_(-1), weak_ptr_factory_(this), - shutting_down_(false), - is_main_(is_main) {} + shutting_down_(false) {} MessageLoopThread::~MessageLoopThread() { ShutDown(); } @@ -143,10 +138,8 @@ void MessageLoopThread::RunThread(MessageLoopThread* thread, thread->Run(std::move(start_up_promise)); } +// This is only for use in tests. btbase::AbstractMessageLoop* MessageLoopThread::message_loop() const { - ASSERT_LOG(!is_main_, - "you are not allowed to get the main thread's message loop"); - std::lock_guard api_lock(api_mutex_); return message_loop_; } @@ -207,6 +200,10 @@ void MessageLoopThread::Run(std::promise start_up_promise) { } } +void MessageLoopThread::Post(base::OnceClosure closure) { + DoInThread(FROM_HERE, std::move(closure)); +} + } // namespace common } // namespace bluetooth diff --git a/system/common/message_loop_thread.h b/system/common/message_loop_thread.h index 9f23da54b21e0cff4b5fc8f0659d2dcd8fac2e58..2f0c5a35176082a8d9682c5af3538a3e81ef6553 100644 --- a/system/common/message_loop_thread.h +++ b/system/common/message_loop_thread.h @@ -23,11 +23,12 @@ #include #include -#include #include #include #include "abstract_message_loop.h" +#include "gd/common/contextual_callback.h" +#include "gd/common/i_postable_context.h" namespace bluetooth { @@ -36,7 +37,7 @@ namespace common { /** * An interface to various thread related functionality */ -class MessageLoopThread final { +class MessageLoopThread final : public IPostableContext { public: /** * Create a message loop thread with name. Thread won't be running until @@ -45,7 +46,6 @@ class MessageLoopThread final { * @param thread_name name of this worker thread */ explicit MessageLoopThread(const std::string& thread_name); - explicit MessageLoopThread(const std::string& thread_name, bool is_main); MessageLoopThread(const MessageLoopThread&) = delete; MessageLoopThread& operator=(const MessageLoopThread&) = delete; @@ -167,6 +167,51 @@ class MessageLoopThread final { */ bool DoInThreadDelayed(const base::Location& from_here, base::OnceClosure task, const base::TimeDelta& delay); + /** + * Wrapper around DoInThread without a location. + */ + void Post(base::OnceClosure closure) override; + + template + common::ContextualOnceCallback> + BindOnce(Functor&& functor, Args&&... args) { + return common::ContextualOnceCallback< + common::MakeUnboundRunType>( + common::BindOnce(std::forward(functor), + std::forward(args)...), + this); + } + + template + common::ContextualOnceCallback< + common::MakeUnboundRunType> + BindOnceOn(T* obj, Functor&& functor, Args&&... args) { + return common::ContextualOnceCallback< + common::MakeUnboundRunType>( + common::BindOnce(std::forward(functor), + common::Unretained(obj), std::forward(args)...), + this); + } + + template + common::ContextualCallback> Bind( + Functor&& functor, Args&&... args) { + return common::ContextualCallback< + common::MakeUnboundRunType>( + common::Bind(std::forward(functor), + std::forward(args)...), + this); + } + + template + common::ContextualCallback> + BindOn(T* obj, Functor&& functor, Args&&... args) { + return common::ContextualCallback< + common::MakeUnboundRunType>( + common::Bind(std::forward(functor), common::Unretained(obj), + std::forward(args)...), + this); + } private: /** @@ -199,7 +244,6 @@ class MessageLoopThread final { pid_t linux_tid_; base::WeakPtrFactory weak_ptr_factory_; bool shutting_down_; - bool is_main_; }; inline std::ostream& operator<<(std::ostream& os, diff --git a/system/common/message_loop_thread_unittest.cc b/system/common/message_loop_thread_unittest.cc index c61c9046a766210b13088b9d9340171657c34d50..80d64023efae13220457aded98ac0aa3116be090 100644 --- a/system/common/message_loop_thread_unittest.cc +++ b/system/common/message_loop_thread_unittest.cc @@ -328,3 +328,21 @@ TEST_F(MessageLoopThreadTest, shut_down_start_up_multi_thread) { auto thread = std::thread(&MessageLoopThread::StartUp, &message_loop_thread); thread.join(); } + +// Verify that Post executes in order +TEST_F(MessageLoopThreadTest, test_post_twice) { + std::string name = "test_thread"; + MessageLoopThread message_loop_thread(name); + int counter = 0; + message_loop_thread.StartUp(); + message_loop_thread.Post( + base::BindOnce([](MessageLoopThread* thread, + int* counter) { ASSERT_EQ((*counter)++, 0); }, + &message_loop_thread, &counter)); + message_loop_thread.Post( + base::BindOnce([](MessageLoopThread* thread, + int* counter) { ASSERT_EQ((*counter)++, 1); }, + &message_loop_thread, &counter)); + message_loop_thread.ShutDown(); + ASSERT_EQ(counter, 2); +} diff --git a/system/common/time_util_unittest.cc b/system/common/time_util_unittest.cc index eb21aee5ad04e2dcb94f3690b554e1fd5accd524..848ef0674669600bd4a5037829bc2de077495382 100644 --- a/system/common/time_util_unittest.cc +++ b/system/common/time_util_unittest.cc @@ -124,28 +124,6 @@ TEST(TimeTest, test_time_get_os_boottime_us_increases_lower_bound) { ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000); } -// -// Test that the return value of -// bluetooth::common::time_get_os_monotonic_raw_us() is increasing. -// -TEST(TimeTest, test_time_get_os_monotonic_raw_us_increases_lower_bound) { - static const uint64_t TEST_TIME_SLEEP_US = 100 * 1000; - struct timespec delay = {}; - - delay.tv_sec = TEST_TIME_SLEEP_US / (1000 * 1000); - delay.tv_nsec = 1000 * (TEST_TIME_SLEEP_US % (1000 * 1000)); - - // Take two timestamps with sleep in-between - uint64_t t1 = bluetooth::common::time_get_os_monotonic_raw_us(); - int err = nanosleep(&delay, &delay); - uint64_t t2 = bluetooth::common::time_get_os_monotonic_raw_us(); - - ASSERT_EQ(err, 0); - ASSERT_GT(t2, t1); - ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_US); - ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000); -} - // // Test that the return value of bluetooth::common::time_gettimeofday_us() is // not zero. diff --git a/system/conf/bt_stack.conf b/system/conf/bt_stack.conf index f82351bb63146608333d914c5ce2e1f7cd9693ee..f680ec32e9a31ac0c08c6f2d33d1002bce2408c5 100644 --- a/system/conf/bt_stack.conf +++ b/system/conf/bt_stack.conf @@ -1,35 +1,3 @@ -# Enable trace level reconfiguration function -# Must be present before any TRC_ trace level settings -TraceConf=true - -# Trace level configuration -# BT_TRACE_LEVEL_NONE 0 ( No trace messages to be generated ) -# BT_TRACE_LEVEL_ERROR 1 ( Error condition trace messages ) -# BT_TRACE_LEVEL_WARNING 2 ( Warning condition trace messages ) -# BT_TRACE_LEVEL_API 3 ( API traces ) -# BT_TRACE_LEVEL_EVENT 4 ( Debug messages for events ) -# BT_TRACE_LEVEL_DEBUG 5 ( Full debug messages ) -# BT_TRACE_LEVEL_VERBOSE 6 ( Verbose messages ) - Currently supported for TRC_BTAPP only. -TRC_BTM=2 -TRC_HCI=2 -TRC_L2CAP=2 -TRC_RFCOMM=2 -TRC_OBEX=2 -TRC_AVCT=2 -TRC_AVDT=2 -TRC_AVRC=2 -TRC_AVDT_SCB=2 -TRC_AVDT_CCB=2 -TRC_A2D=2 -TRC_SDP=2 -TRC_SMP=2 -TRC_BTAPP=2 -TRC_BTIF=2 -TRC_BNEP=2 -TRC_PAN=2 -TRC_HID_HOST=2 -TRC_HID_DEV=2 - # This is Log configuration for new C++ code using LOG() macros. # See libchrome/base/logging.h for description on how to configure your logs. # sample configuration: @@ -119,7 +87,6 @@ TRC_HID_DEV=2 # SMP_NUMERIC_COMPAR_FAIL = 12 #PTS_SmpFailureCase=0 - # PTS Broadcast audio configuration option # Option: # lc3_stereo_48_1_2 diff --git a/system/conf/interop_database.conf b/system/conf/interop_database.conf index c65de479a8332acca18bbac0f83a2f99041ef89b..84853bc01a883bc5ab2dd46893078131824c3a7b 100644 --- a/system/conf/interop_database.conf +++ b/system/conf/interop_database.conf @@ -844,4 +844,15 @@ d4:3f:32 = Address_Based ec:74:27 = Address_Based f0:21:e0 = Address_Based f0:b6:61 = Address_Based -fc:3f:a6 = Address_Based \ No newline at end of file +fc:3f:a6 = Address_Based + +# some device may have problem in reconnect flow, need we initiate connection after signalling timeout +[INTEROP_IGNORE_DISC_BEFORE_SIGNALLING_TIMEOUT] +00:e0:4c = Address_Based +00:9e:c8 = Address_Based + +# Certain devices have issue where they cannot handle ATT traffic during SMP key exchange. +# For those devices, queued ATT writes are delayed until after both encryption complete and +# SMP key exchange completed. +[INTEROP_SUSPEND_ATT_TRAFFIC_DURING_PAIRING] +ORN = Name_Based diff --git a/system/device/Android.bp b/system/device/Android.bp index 5ab4a2cbc0ba7701a68b468b2300ca7a5cc30eb1..5b6216d1836131c479f3b439a9f0d13ab80d7c6b 100644 --- a/system/device/Android.bp +++ b/system/device/Android.bp @@ -10,7 +10,7 @@ package { cc_library_static { name: "libbtdevice", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], host_supported: true, local_include_dirs: [ "include", @@ -28,15 +28,28 @@ cc_library_static { "src/esco_parameters.cc", "src/interop.cc", ], + apex_available: [ + "com.android.btservices", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", + ], min_sdk_version: "Tiramisu", + header_libs: ["libbluetooth_headers"], + static_libs: [ + "bluetooth_flags_c_lib", + "libbluetooth_hci_pdl", + "libbt_shim_bridge", + "libflatbuffers-cpp", + "server_configurable_flags", + ], } // Bluetooth device unit tests for target cc_test { name: "net_test_device", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -50,26 +63,29 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtcore", "libbtdevice", "libchrome", "libosi", - "libosi-AllocationTestHarness", ], + header_libs: ["libbluetooth_headers"], } // Bluetooth device unit tests for target cc_test { name: "net_test_device_iot_config", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/device/src", + "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/stack/include", ], srcs: [ @@ -83,10 +99,14 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtcore", "libbtdevice", "libchrome", "libgmock", - "libosi-AllocationTestHarness", ], + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/device/BUILD.gn b/system/device/BUILD.gn index 6d96a6b46d671e772c8993d4d163d0e8839433fa..8b1ffd45d04e8b2e43cff763dab45c4d9ffa8446 100644 --- a/system/device/BUILD.gn +++ b/system/device/BUILD.gn @@ -36,15 +36,12 @@ static_library("device") { deps = [ "//bt/system/gd/rust/shim:init_flags_bridge_header", "//bt/system/gd/rust/shim:libbluetooth_rust_interop", + "//bt/system/pdl:BluetoothGeneratedPackets_h", ] } if (use.test) { executable("net_test_device") { - sources = [ - "//bt/system/osi/test/AllocationTestHarness.cc", - ] - include_dirs = [ "//bt/system" ] deps = [ @@ -65,10 +62,6 @@ if (use.test) { ] } executable("net_test_device_iot_config") { - sources = [ - "//bt/system/osi/test/AllocationTestHarness.cc", - ] - include_dirs = [ "//bt/system", "//bt/system/stack/include", diff --git a/system/device/fuzzer/Android.bp b/system/device/fuzzer/Android.bp index 72c4aadf9f2e7715c51a14a7b5491275a7ac1314..35cf3d092dc1009c4b9388d04e11320b2a52810c 100644 --- a/system/device/fuzzer/Android.bp +++ b/system/device/fuzzer/Android.bp @@ -27,22 +27,37 @@ cc_fuzz { name: "btdevice_esco_fuzzer", defaults: ["fluoride_defaults"], srcs: [ + ":TestMockMainShimEntry", "btdevice_esco_fuzzer.cpp", ], + header_libs: [ + "libbluetooth_headers", + ], shared_libs: [ "libdl", "liblog", + "server_configurable_flags", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", ], static_libs: [ + "bluetooth_flags_c_lib", "libbluetooth-types", + "libbluetooth_gd", + "libbluetooth_hci_pdl", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtcore", "libbtdevice", "libchrome", + "libgmock", "libosi", ], include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/device/include", + "packages/modules/Bluetooth/system/gd", ], cflags: [ "-DBUILDCFG", @@ -50,5 +65,13 @@ cc_fuzz { fuzz_config: { cc: ["android-bluetooth-security@google.com"], componentid: 27441, + hotlists: [ + "4593311", + ], + description: "The fuzzer targets the APIs of libbtdevice library", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped", }, } diff --git a/system/device/fuzzer/btdevice_esco_fuzzer.cpp b/system/device/fuzzer/btdevice_esco_fuzzer.cpp index 0994e112b69fd0342a6e6dde8b07c73d682523f8..e30d027c1c74b210d659217ff35ea09bc2782166 100644 --- a/system/device/fuzzer/btdevice_esco_fuzzer.cpp +++ b/system/device/fuzzer/btdevice_esco_fuzzer.cpp @@ -18,8 +18,10 @@ #include +#include "btcore/include/module.h" #include "esco_parameters.h" #include "interop.h" +#include "interop_config.h" using namespace std; constexpr size_t kNumAddressOctets = 6; @@ -31,48 +33,249 @@ constexpr interop_feature_t kInteropFeature[] = { interop_feature_t::INTEROP_DISABLE_AUTO_PAIRING, interop_feature_t::INTEROP_KEYBOARD_REQUIRES_FIXED_PIN, interop_feature_t::INTEROP_2MBPS_LINK_ONLY, + interop_feature_t::INTEROP_DISABLE_SDP_AFTER_PAIRING, + interop_feature_t::INTEROP_REMOVE_HID_DIG_DESCRIPTOR, + interop_feature_t::INTEROP_DISABLE_SNIFF_DURING_SCO, interop_feature_t::INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S, interop_feature_t::INTEROP_GATTC_NO_SERVICE_CHANGED_IND, + interop_feature_t::INTEROP_INCREASE_AG_CONN_TIMEOUT, + interop_feature_t::INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS, + interop_feature_t::INTEROP_DISABLE_AAC_CODEC, + interop_feature_t::INTEROP_DISABLE_AAC_VBR_CODEC, + interop_feature_t::INTEROP_ENABLE_AAC_CODEC, + interop_feature_t::INTEROP_DISABLE_ROLE_SWITCH_POLICY, + interop_feature_t::INTEROP_HFP_1_7_DENYLIST, + interop_feature_t::INTEROP_HFP_1_8_DENYLIST, + interop_feature_t::INTEROP_ADV_PBAP_VER_1_1, + interop_feature_t::INTEROP_UPDATE_HID_SSR_MAX_LAT, + interop_feature_t::INTEROP_DISABLE_AUTH_FOR_HID_POINTING, interop_feature_t::INTEROP_DISABLE_AVDTP_RECONFIGURE, interop_feature_t::INTEROP_DYNAMIC_ROLE_SWITCH, + interop_feature_t::INTEROP_DISABLE_HF_INDICATOR, interop_feature_t::INTEROP_DISABLE_ROLE_SWITCH, + interop_feature_t::INTEROP_DELAY_SCO_FOR_MT_CALL, + interop_feature_t::INTEROP_DISABLE_CODEC_NEGOTIATION, + interop_feature_t::INTEROP_DISABLE_PLAYER_APPLICATION_SETTING_CMDS, + interop_feature_t::INTEROP_DISABLE_CONNECTION_AFTER_COLLISION, + interop_feature_t::INTEROP_DISABLE_LE_CONN_UPDATES, + interop_feature_t::INTEROP_ADV_PBAP_VER_1_2, + interop_feature_t::INTEROP_DISABLE_PCE_SDP_AFTER_PAIRING, + interop_feature_t::INTEROP_AVRCP_BROWSE_OPEN_CHANNEL_COLLISION, + interop_feature_t::INTEROP_DISABLE_SNIFF_LINK_DURING_SCO, + interop_feature_t::INTEROP_DISABLE_SNIFF_DURING_CALL, interop_feature_t::INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL, + interop_feature_t::INTEROP_DISABLE_REFRESH_ACCEPT_SIG_TIMER, + interop_feature_t::INTEROP_BROWSE_PLAYER_ALLOW_LIST, + interop_feature_t::INTEROP_SKIP_INCOMING_STATE, + interop_feature_t::INTEROP_NOT_UPDATE_AVRCP_PAUSED_TO_REMOTE, + interop_feature_t:: + INTEROP_PHONE_POLICY_INCREASED_DELAY_CONNECT_OTHER_PROFILES, interop_feature_t::INTEROP_DISABLE_NAME_REQUEST, interop_feature_t::INTEROP_AVRCP_1_4_ONLY, interop_feature_t::INTEROP_DISABLE_SNIFF, interop_feature_t::INTEROP_DISABLE_AVDTP_SUSPEND, interop_feature_t::INTEROP_SLC_SKIP_BIND_COMMAND, interop_feature_t::INTEROP_AVRCP_1_3_ONLY, + interop_feature_t:: + INTEROP_PHONE_POLICY_REDUCED_DELAY_CONNECT_OTHER_PROFILES, + interop_feature_t::INTEROP_HFP_FAKE_INCOMING_CALL_INDICATOR, + interop_feature_t::INTEROP_HFP_SEND_CALL_INDICATORS_BACK_TO_BACK, + interop_feature_t::INTEROP_SETUP_SCO_WITH_NO_DELAY_AFTER_SLC_DURING_CALL, + interop_feature_t::INTEROP_ENABLE_PREFERRED_CONN_PARAMETER, + interop_feature_t::INTEROP_RETRY_SCO_AFTER_REMOTE_REJECT_SCO, + interop_feature_t::INTEROP_DELAY_SCO_FOR_MO_CALL, + interop_feature_t::INTEROP_CHANGE_HID_VID_PID, + interop_feature_t::INTEROP_DISABLE_ROLE_SWITCH_DURING_CONNECTION, + interop_feature_t::INTEROP_DISABLE_ROBUST_CACHING, + interop_feature_t::INTEROP_HFP_1_7_ALLOWLIST, + interop_feature_t::INTEROP_IGNORE_DISC_BEFORE_SIGNALLING_TIMEOUT, }; constexpr esco_codec_t kEscoCodec[] = { esco_codec_t::SCO_CODEC_CVSD_D1, esco_codec_t::ESCO_CODEC_CVSD_S3, esco_codec_t::ESCO_CODEC_CVSD_S4, esco_codec_t::ESCO_CODEC_MSBC_T1, - esco_codec_t::ESCO_CODEC_MSBC_T2, + esco_codec_t::ESCO_CODEC_MSBC_T2, esco_codec_t::ESCO_CODEC_LC3_T1, + esco_codec_t::ESCO_CODEC_LC3_T2, }; +void generateString(FuzzedDataProvider& fdp, string& addressString) { + addressString.clear(); + if (fdp.ConsumeBool()) { + for (size_t i = 0; i < kNumAddressOctets; ++i) { + addressString.append(fdp.ConsumeBytesAsString(sizeof(uint8_t))); + if (i != kNumAddressOctets - 1) { + addressString.append(":"); + } + } + } else { + addressString = fdp.ConsumeRandomLengthString(kMaxStringLength); + } +} + +extern module_t interop_module; + extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider mFuzzedDataProvider = FuzzedDataProvider(data, size); RawAddress fuzzAddress; string addressString; - for (size_t i = 0; i < kNumAddressOctets; ++i) { - addressString.append( - mFuzzedDataProvider.ConsumeBytesAsString(sizeof(uint8_t))); - if (i != kNumAddressOctets - 1) { - addressString.append(":"); - } + module_init(&interop_module); + + while (mFuzzedDataProvider.remaining_bytes()) { + auto invokeBtDeviceApi = mFuzzedDataProvider.PickValueInArray< + const std::function>({ + [&]() { + generateString(mFuzzedDataProvider, addressString); + RawAddress::FromString(addressString, fuzzAddress); + interop_match_addr(mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + &fuzzAddress); + }, + [&]() { + interop_match_name( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider.ConsumeRandomLengthString(kMaxStringLength) + .c_str() /* name */ + ); + }, + [&]() { + interop_match_manufacturer( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider.ConsumeIntegral() /* manufacturer */ + ); + }, + [&]() { + interop_match_vendor_product_ids( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider.ConsumeIntegral() /* vendor_id */, + mFuzzedDataProvider.ConsumeIntegral() /* product_id */ + ); + }, + [&]() { + generateString(mFuzzedDataProvider, addressString); + RawAddress::FromString(addressString, fuzzAddress); + interop_database_add( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + &fuzzAddress, + mFuzzedDataProvider.ConsumeIntegralInRange( + 1, RawAddress::kLength - 1) /* length */ + ); + }, + [&]() { interop_database_clear(); }, + [&]() { + interop_database_match_version( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider.ConsumeIntegral() /* version */ + ); + }, + [&]() { + generateString(mFuzzedDataProvider, addressString); + RawAddress::FromString(addressString, fuzzAddress); + uint16_t max_lat = 0; + interop_match_addr_get_max_lat(mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + &fuzzAddress, &max_lat); + }, + [&]() { + generateString(mFuzzedDataProvider, addressString); + RawAddress::FromString(addressString, fuzzAddress); + interop_feature_name_to_feature_id(addressString.c_str()); + }, + [&]() { + esco_parameters_for_codec( + mFuzzedDataProvider.PickValueInArray(kEscoCodec) /* codec */, + true); + }, + [&]() { + interop_database_add_manufacturer( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider + .ConsumeIntegral() /* manufacturer */); + }, + [&]() { + interop_database_add_vndr_prdt( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider.ConsumeIntegral() /* vendor_id */, + mFuzzedDataProvider.ConsumeIntegral() /* product_id */); + }, + [&]() { + generateString(mFuzzedDataProvider, addressString); + RawAddress::FromString(addressString, fuzzAddress); + interop_database_add_addr_max_lat( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + &fuzzAddress, + mFuzzedDataProvider.ConsumeIntegral() /* max_lat */); + }, + [&]() { + interop_database_add_version( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider.ConsumeIntegral() /* version */); + }, + [&]() { + interop_database_add_addr_lmp_version( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + &fuzzAddress, + mFuzzedDataProvider.ConsumeIntegral() /* lmp_ver */, + mFuzzedDataProvider + .ConsumeIntegral() /* lmp_sub_ver */); + }, + [&]() { + uint8_t lmp_ver = 0; + uint16_t lmp_sub_ver = 0; + interop_database_match_addr_get_lmp_ver( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + &fuzzAddress, &lmp_ver, &lmp_sub_ver); + }, + [&]() { + interop_database_remove_manufacturer( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider + .ConsumeIntegral() /* manufacturer */); + }, + [&]() { + interop_database_remove_vndr_prdt( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider.ConsumeIntegral() /* vendor_id */, + mFuzzedDataProvider.ConsumeIntegral() /* product_id */); + }, + [&]() { + generateString(mFuzzedDataProvider, addressString); + RawAddress::FromString(addressString, fuzzAddress); + interop_database_remove_addr_max_lat( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + &fuzzAddress, + mFuzzedDataProvider.ConsumeIntegral() /* max_lat */); + }, + [&]() { + interop_database_remove_version( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + mFuzzedDataProvider.ConsumeIntegral() /*version*/); + }, + [&]() { + interop_database_remove_addr_lmp_version( + mFuzzedDataProvider.PickValueInArray( + kInteropFeature) /* feature */, + &fuzzAddress, + mFuzzedDataProvider.ConsumeIntegral() /* lmp_ver */, + mFuzzedDataProvider + .ConsumeIntegral() /* lmp_sub_ver */); + }, + }); + invokeBtDeviceApi(); } - RawAddress::FromString(addressString, fuzzAddress); - interop_feature_t interopFeature = - mFuzzedDataProvider.PickValueInArray(kInteropFeature); - interop_match_addr(interopFeature, &fuzzAddress); - interop_database_add(interopFeature, &fuzzAddress, - mFuzzedDataProvider.ConsumeIntegralInRange( - 1, RawAddress::kLength - 1)); - interop_database_clear(); - interop_match_name( - interopFeature, - mFuzzedDataProvider.ConsumeRandomLengthString(kMaxStringLength).c_str()); - esco_codec_t escoCodec = mFuzzedDataProvider.PickValueInArray(kEscoCodec); - esco_parameters_for_codec(escoCodec, true); + module_clean_up(&interop_module); return 0; } diff --git a/system/device/include/controller.h b/system/device/include/controller.h index 9881461bd43a55ac82d110bfc7cb7fdead7fee01..bddf06bcba202e4a9aa3f2a9b9042a969faaaafb 100644 --- a/system/device/include/controller.h +++ b/system/device/include/controller.h @@ -26,7 +26,7 @@ #include "btcore/include/version.h" #include "types/raw_address.h" -using LeRandCallback = base::Callback; +using LeRandCallback = base::OnceCallback; typedef struct controller_t { bool (*get_is_ready)(void); diff --git a/system/device/include/device_iot_config.h b/system/device/include/device_iot_config.h index df2f94c31a50c701c0ad357571a69e13091d0fc7..060b0bdd0d84442e2152bac1f0dd55cfb5f3753a 100644 --- a/system/device/include/device_iot_config.h +++ b/system/device/include/device_iot_config.h @@ -23,7 +23,6 @@ #include #include "bt_target.h" -#include "bt_types.h" #include "device_iot_conf_defs.h" #include "raw_address.h" diff --git a/system/device/include/esco_parameters.h b/system/device/include/esco_parameters.h index ed206b857c4f3e16f93639208b1898cf35f2a142..5b15ca2ff2ad6009779ea8dfc0fe3f103c34bac4 100644 --- a/system/device/include/esco_parameters.h +++ b/system/device/include/esco_parameters.h @@ -38,9 +38,15 @@ typedef enum { ESCO_CODEC_MSBC_T2, ESCO_CODEC_LC3_T1, ESCO_CODEC_LC3_T2, + ESCO_CODEC_SWB_Q0, + ESCO_CODEC_SWB_Q1, + ESCO_CODEC_SWB_Q2, + ESCO_CODEC_SWB_Q3, + ESCO_CODEC_UNKNOWN, // For testing } esco_codec_t; -#define ESCO_NUM_CODECS 7 +#define ESCO_LEGACY_NUM_CODECS 7 +#define ESCO_NUM_CODECS 11 // Coding Formats (BT 4.1 or later Assigned numbers) #define ESCO_CODING_FORMAT_ULAW ((uint8_t)0x00) /* u-Law log */ @@ -137,6 +143,8 @@ typedef struct { esco_packet_types_t packet_types; /* Packet Types */ esco_retransmission_effort_t retransmission_effort; /* 0x00-0x02, 0xFF don't care */ + esco_coding_format_t + coding_format; /* Extra field to store codec when TX/RX is transparent */ } enh_esco_params_t; // Get the enhanced eSCO configuration parameters for the provided |codec| diff --git a/system/device/include/interop.h b/system/device/include/interop.h index b97747c26a6a229e9d18f43b8636339934ddfa2a..a1c5b243afc119664184870a89b34a3bdc80a7e4 100644 --- a/system/device/include/interop.h +++ b/system/device/include/interop.h @@ -327,6 +327,22 @@ typedef enum { INTEROP_DISABLE_ROBUST_CACHING, INTEROP_HFP_1_7_ALLOWLIST, + + INTEROP_HFP_1_9_ALLOWLIST, + + // Some device may have problem in reconnect flow, + // need we initiate connection after signalling timeout + INTEROP_IGNORE_DISC_BEFORE_SIGNALLING_TIMEOUT, + + // Certain devices have issue where they cannot handle ATT traffic during SMP + // key exchange. For those devices, queued ATT writes are delayed until after + // both encryption complete and SMP key exchange completed. + INTEROP_SUSPEND_ATT_TRAFFIC_DURING_PAIRING, + + // This triggers a +CIEV command to set the call status for HFP devices. + // It is required for some devices to provide sound. + INTEROP_INSERT_CALL_WHEN_SCO_START, + END_OF_INTEROP_LIST } interop_feature_t; diff --git a/system/device/include/interop_config.h b/system/device/include/interop_config.h index 2d1bf83d66a536466d50135bbb46c2925993f890..c29a19ba6a3a576ea4f9c0bdf5e2587c6038fbe7 100644 --- a/system/device/include/interop_config.h +++ b/system/device/include/interop_config.h @@ -19,11 +19,9 @@ #pragma once -#include #include #include "device/include/interop.h" -#include "device/include/interop_database.h" typedef uint16_t UINT16; diff --git a/system/device/src/device_iot_config.cc b/system/device/src/device_iot_config.cc index 1f6060460a808f785e7f415d0a42de0836682b7e..ff0a759d30389a7c98bced43306ff686d4e55bb2 100644 --- a/system/device/src/device_iot_config.cc +++ b/system/device/src/device_iot_config.cc @@ -29,7 +29,6 @@ #include #include -#include "bt_types.h" #include "btcore/include/module.h" #include "btif/include/btif_api.h" #include "btif/include/btif_util.h" diff --git a/system/device/src/device_iot_config_int.cc b/system/device/src/device_iot_config_int.cc index 9ec0f8d986efeb9a1fa08993fa2c77ac70f8f520..c99b269d5eec274ce0027c2b9764b0a20b00540c 100644 --- a/system/device/src/device_iot_config_int.cc +++ b/system/device/src/device_iot_config_int.cc @@ -30,7 +30,6 @@ #include #include -#include "bt_types.h" #include "btcore/include/module.h" #include "btif/include/btif_api.h" #include "btif/include/btif_util.h" diff --git a/system/device/src/esco_parameters.cc b/system/device/src/esco_parameters.cc index 48607e6d54a2072fe53215f8fdf3f8b43666aa7b..684450a80bc3968e74b8919c7ad0b6213338ce52 100644 --- a/system/device/src/esco_parameters.cc +++ b/system/device/src/esco_parameters.cc @@ -16,11 +16,14 @@ * ******************************************************************************/ -#include "base/logging.h" - #include "device/include/esco_parameters.h" +#include + +#include "base/logging.h" #include "check.h" +#include "hci/controller.h" +#include "main/shim/entry.h" static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = { // CVSD D1 @@ -57,6 +60,7 @@ static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = { .packet_types = (ESCO_PKT_TYPES_MASK_HV1 | ESCO_PKT_TYPES_MASK_HV2 | ESCO_PKT_TYPES_MASK_HV3), .retransmission_effort = ESCO_RETRANSMISSION_OFF, + .coding_format = ESCO_CODING_FORMAT_CVSD, }, // CVSD S3 { @@ -96,6 +100,7 @@ static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = { ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5), .retransmission_effort = ESCO_RETRANSMISSION_POWER, + .coding_format = ESCO_CODING_FORMAT_CVSD, }, // CVSD S4 { @@ -135,6 +140,7 @@ static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = { ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5), .retransmission_effort = ESCO_RETRANSMISSION_QUALITY, + .coding_format = ESCO_CODING_FORMAT_CVSD, }, // mSBC T1 { @@ -172,6 +178,7 @@ static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = { ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5 | ESCO_PKT_TYPES_MASK_NO_2_EV3), .retransmission_effort = ESCO_RETRANSMISSION_QUALITY, + .coding_format = ESCO_CODING_FORMAT_MSBC, }, // mSBC T2 { @@ -208,6 +215,7 @@ static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = { (ESCO_PKT_TYPES_MASK_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5), .retransmission_effort = ESCO_RETRANSMISSION_QUALITY, + .coding_format = ESCO_CODING_FORMAT_MSBC, }, // LC3 T1 { @@ -245,6 +253,7 @@ static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = { ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5 | ESCO_PKT_TYPES_MASK_NO_2_EV3), .retransmission_effort = ESCO_RETRANSMISSION_QUALITY, + .coding_format = ESCO_CODING_FORMAT_LC3, }, // LC3 T2 { @@ -281,17 +290,78 @@ static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = { (ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5), .retransmission_effort = ESCO_RETRANSMISSION_QUALITY, + .coding_format = ESCO_CODING_FORMAT_LC3, }, -}; + // aptX Voice SWB + {.transmit_bandwidth = TXRX_64KBITS_RATE, + .receive_bandwidth = TXRX_64KBITS_RATE, + .transmit_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS, + .company_id = 0x000A, + .vendor_specific_codec_id = 0x0000}, + .receive_coding_format = {.coding_format = ESCO_CODING_FORMAT_VS, + .company_id = 0x000A, + .vendor_specific_codec_id = 0x0000}, + .transmit_codec_frame_size = 60, + .receive_codec_frame_size = 60, + .input_bandwidth = INPUT_OUTPUT_128K_RATE, + .output_bandwidth = INPUT_OUTPUT_128K_RATE, + .input_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR, + .company_id = 0x0000, + .vendor_specific_codec_id = 0x0000}, + .output_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR, + .company_id = 0x0000, + .vendor_specific_codec_id = 0x0000}, + .input_coded_data_size = 16, + .output_coded_data_size = 16, + .input_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP, + .output_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP, + .input_pcm_payload_msb_position = 0, + .output_pcm_payload_msb_position = 0, + .input_data_path = ESCO_DATA_PATH_PCM, + .output_data_path = ESCO_DATA_PATH_PCM, + .input_transport_unit_size = 0x00, + .output_transport_unit_size = 0x00, + .max_latency_ms = 14, + .packet_types = 0x0380, + .retransmission_effort = ESCO_RETRANSMISSION_QUALITY}}; enh_esco_params_t esco_parameters_for_codec(esco_codec_t codec, bool offload) { CHECK(codec >= 0) << "codec index " << (int)codec << "< 0"; CHECK(codec < ESCO_NUM_CODECS) << "codec index " << (int)codec << " > " << ESCO_NUM_CODECS; + + std::vector codecIds; + if (IS_FLAG_ENABLED(use_dsp_codec_when_controller_does_not_support)) { + auto controller = bluetooth::shim::GetController(); + if (controller == nullptr) { + LOG_WARN("controller is null"); + } else { + codecIds = controller->GetLocalSupportedBrEdrCodecIds(); + if (std::find(codecIds.begin(), codecIds.end(), ESCO_CODING_FORMAT_LC3) == + codecIds.end()) { + LOG_INFO("BT controller does not support LC3 codec, use DSP codec"); + if (codec == ESCO_CODEC_LC3_T1 || codec == ESCO_CODEC_LC3_T2) { + enh_esco_params_t param = default_esco_parameters[codec]; + param.input_coding_format.coding_format = ESCO_CODING_FORMAT_LC3; + param.output_coding_format.coding_format = ESCO_CODING_FORMAT_LC3; + param.input_bandwidth = TXRX_64KBITS_RATE; + param.output_bandwidth = TXRX_64KBITS_RATE; + return param; + } + } + } + } + if (offload) { + if (codec == ESCO_CODEC_SWB_Q0 || codec == ESCO_CODEC_SWB_Q1 || + codec == ESCO_CODEC_SWB_Q2 || codec == ESCO_CODEC_SWB_Q3) { + return default_esco_parameters[ESCO_CODEC_SWB_Q0]; + } return default_esco_parameters[codec]; } + CHECK(codec < ESCO_LEGACY_NUM_CODECS) + << "legacy codec index " << (int)codec << " > " << ESCO_LEGACY_NUM_CODECS; enh_esco_params_t param = default_esco_parameters[codec]; param.input_data_path = param.output_data_path = ESCO_DATA_PATH_HCI; diff --git a/system/device/src/interop.cc b/system/device/src/interop.cc index 052b121facac373aaea4a4a48763abb0eb299591..5a4700e4bd2c6c6ac1d022f5e4a16a18d20d8bb1 100644 --- a/system/device/src/interop.cc +++ b/system/device/src/interop.cc @@ -37,7 +37,6 @@ #include #include -#include "bt_types.h" #include "btcore/include/module.h" #include "btif/include/btif_storage.h" #include "check.h" @@ -56,7 +55,19 @@ static const char* INTEROP_DYNAMIC_FILE_PATH = "/data/misc/bluedroid/interop_database_dynamic.conf"; static const char* INTEROP_STATIC_FILE_PATH = "/apex/com.android.btservices/etc/bluetooth/interop_database.conf"; -#else // !__ANDROID__ +#elif TARGET_FLOSS +#include + +#include + +static const std::filesystem::path kDynamicConfigFileConfigFile = + std::filesystem::temp_directory_path() / "interop_database_dynamic.conf"; +static const char* INTEROP_DYNAMIC_FILE_PATH = + kDynamicConfigFileConfigFile.c_str(); + +static const char* INTEROP_STATIC_FILE_PATH = + "/var/lib/bluetooth/interop_database.conf"; +#else // !TARGET_FLOSS and !__ANDROID__ #include #include @@ -379,6 +390,10 @@ static const char* interop_feature_string_(const interop_feature_t feature) { CASE_RETURN_STR(INTEROP_AVRCP_1_3_ONLY) CASE_RETURN_STR(INTEROP_DISABLE_ROBUST_CACHING); CASE_RETURN_STR(INTEROP_HFP_1_7_ALLOWLIST); + CASE_RETURN_STR(INTEROP_HFP_1_9_ALLOWLIST); + CASE_RETURN_STR(INTEROP_IGNORE_DISC_BEFORE_SIGNALLING_TIMEOUT); + CASE_RETURN_STR(INTEROP_SUSPEND_ATT_TRAFFIC_DURING_PAIRING); + CASE_RETURN_STR(INTEROP_INSERT_CALL_WHEN_SCO_START); } return UNKNOWN_INTEROP_FEATURE; } @@ -891,8 +906,8 @@ static bool get_addr_lmp_ver(char* str, char* bdaddrstr, uint8_t* lmp_ver, return false; } -bool load_to_database(int feature, const char* key, const char* value, - interop_entry_type entry_type) { +static bool load_to_database(int feature, const char* key, const char* value, + interop_entry_type entry_type) { if (!strncasecmp(value, ADDR_BASED, strlen(ADDR_BASED))) { RawAddress addr; int len = 0; diff --git a/system/device/test/device_iot_config_test.cc b/system/device/test/device_iot_config_test.cc index f17bed2592ad1eea66edcd32ba164e73bf37b821..c440401860ee2c55739c5bbdd9ed0d7d677562ba 100644 --- a/system/device/test/device_iot_config_test.cc +++ b/system/device/test/device_iot_config_test.cc @@ -26,6 +26,7 @@ #include "btif/include/btif_common.h" #include "common/init_flags.h" #include "device/src/device_iot_config_int.h" +#include "test/common/mock_functions.h" #include "test/mock/mock_osi_alarm.h" #include "test/mock/mock_osi_allocator.h" #include "test/mock/mock_osi_config.h" diff --git a/system/doc/btsnoop_net.md b/system/doc/btsnoop_net.md deleted file mode 100644 index 6964a9add6eb4d3708705ab17cb23ab6ccf54ccf..0000000000000000000000000000000000000000 --- a/system/doc/btsnoop_net.md +++ /dev/null @@ -1,16 +0,0 @@ -btsnoop_net -==== -btsnoop_net exposes Bluetooth snoop logs over a local TCP socket which enables -real-time debugging of HCI data with hcidump. - -This feature is enabled by enabling "Enable Bluetooth HCI snoop log" in the -Developer options and setting BT_NET_DEBUG flag to TRUE in the btsnoop_net.cc. -Once it has been enabled and the stack restarted, the stack will listen for -incoming TCP connections on port 8872. - -To use this feature with btmon on a Linux host, you can run: - -``` - $ adb forward tcp:8872 tcp:8872 - $ nc localhost 8872 | btmon -P -r /dev/stdin -``` diff --git a/system/doc/log_tags.md b/system/doc/log_tags.md deleted file mode 100644 index fe6a3e4dba0374b482315c36acb4397b559493ee..0000000000000000000000000000000000000000 --- a/system/doc/log_tags.md +++ /dev/null @@ -1,57 +0,0 @@ -Log Tags -=== -This document lists all of the log tags used by the Bluetooth stack. - -* audio_a2dp_hw -* BTA_AG_CO: -* bta_sys_main -* bt_btif -* bt_btif_config -* bt_btif_config_transcode -* bt_classic_peer -* bte_conf -* BtGatt.btif -* BtGatt.btif_test -* bt_hci -* bt_hci_h4 -* bt_hci_inject -* bt_hci_mct -* bt_hci_packet_fragmenter -* BTIF_AV -* BTIF_CORE -* BTIF_HF -* BTIF_HF_CLIENT -* BTIF_HH -* BTIF_HL -* BTIF-MEDIA -* BTIF_PAN -* BTIF_QUEUE -* BTIF_RC -* BTIF_SM -* btif_sock -* BTIF_SOCK -* btif_sock_rfcomm -* btif_sock_sco -* BTIF_SOCK_SDP -* BTIF_STORAGE -* BTIF_UTIL -* BTLD -* bt_module -* bt_osi_alarm -* bt_osi_config -* bt_osi_data_dispatcher -* bt_osi_reactor -* bt_osi_socket -* bt_profile_manager -* bt_sdp_client -* btsnoop -* btsnoop_net -* bt_stack_config -* bt_stack_manager -* bt_task -* btu_task -* BT_UTILS -* bt_vendor -* osi_future -* osi_semaphore -* osi_thread diff --git a/system/doc/network_ports.md b/system/doc/network_ports.md deleted file mode 100644 index 03e138e0df6bee76fe058edefe51588be0f969b9..0000000000000000000000000000000000000000 --- a/system/doc/network_ports.md +++ /dev/null @@ -1,8 +0,0 @@ -Network Ports -=== -This document lists all of the network ports used by the bluetooth stack. -It should be used as a reference and as a mechanism to avoid port -namespace conflicts. - -* TCP 8872 (hci/src/btsnoop_net.cc) - read live btsnoop logs -* TCP 8873 (hci/src/hci_inject.cc) - inject HCI packets into HCI stream diff --git a/system/doc/properties.md b/system/doc/properties.md deleted file mode 100644 index c4ab97c0187ad24b20890877631dfae3b74bf586..0000000000000000000000000000000000000000 --- a/system/doc/properties.md +++ /dev/null @@ -1,20 +0,0 @@ -Properties -=== -This document describes all of the Android properties used by the Bluetooth -stack. - -Please keep the following list in alphabetical order. - -* ``` bluetooth.enable_timeout_ms ``` - Maximum amount of time Bluetooth can take to start-up, upload firmware etc. - Used in hci/src/hci_layer.cc, default 8000. - -### TODO: write descriptions of what each property means and how -it's used. - -* ``` debug.sys.noschedgroups ``` -* ``` persist.service.bdroid.bdaddr ``` -* ``` ro.bluetooth.hfp.ver ``` -* ``` ro.bt.bdaddr_path ``` -* ``` ro.product.model ``` -* ``` service.brcm.bt.oob ``` diff --git a/system/doc/pts_guide.md b/system/doc/pts_guide.md deleted file mode 100644 index 1e13b9d07b355e3deed2a3c54fde9c3334d2c8d7..0000000000000000000000000000000000000000 --- a/system/doc/pts_guide.md +++ /dev/null @@ -1,43 +0,0 @@ -# Fluoride Bluetooth Profile Tuning Suite (PTS) Test Mode - -This document provides commands to enable PTS test mode for Fluoride stack. We -need special handling for some test cases as they are not applicable for the -Fluoride stack. - -## PTS Test Mode system property - -Profile services in packages/apps/Bluetooth uses system property -`persist.bluetooth.pts` to check if the PTS test mode is enabled. To enable it: - -```sh -adb shell setprop persist.bluetooth.pts true -``` - -To disable it: - -```sh -adb shell setprop persist.bluetooth.pts false -``` - -### Current use case - -- In `newavrcp`, we send active player update to remote device only in PTS test - mode (AVRCP/TG/MPS/BV-05-C AVRCP/TG/MPS/BV-07-C). - -## PTS Helpers in stack config - -Native stack also requires some special handling, and the config is stored in -`conf/bt_stack.conf`. To enable a flag, uncomment the corresponding line and -push the config file to `/etc/bluetooth/` in IUT. - -### Current use case - -- `PTS_SecurePairOnly` enables secure connections only mode. -- `PTS_DisableConnUpdates` disables LE Connection updates. -- `PTS_DisableSDPOnLEPair` disables BR/EDR discovery after LE pairing to avoid - cross key derivation errors. -- `PTS_SmpOptions` sets SMP Pair options (formatted as hex bytes) `auth, io, - ikey, rkey, ksize`. -- `PTS_AvrcpTest` enables AVRCP test mode. The UID is set to 0xffffffffffffffff - in `TrackChangedNotificationResponse` (AVRCP/TG/NFY/BV-04-C). -- `PTS_SmpFailureCase` enables handling for various SMP failure cases. diff --git a/system/doc/supported_features.md b/system/doc/supported_features.md deleted file mode 100644 index 50ca84d0270149d0011827e12cd6d42e932b0972..0000000000000000000000000000000000000000 --- a/system/doc/supported_features.md +++ /dev/null @@ -1,19 +0,0 @@ -# Fluoride 1.1 - -Declaration ID: [D024527](https://www.bluetooth.org/tpg/QLI_viewQDL.cfm?qid=24527) -Qualified Design ID: 83953 - -Protocol / Profile | Version | Roles --------------------+---------+------- -L2CAP | 4.2 | Initiator, Acceptor, LE Central, LE Peripheral -SDP | 4.2 | Server, Client -GAP | 4.2 | BR/EDR, LE Central, LE Periperhal, LE Observer, LE Broadcaster -GATT | 4.2 | Client, Server; LE and BR/EDR -ATT | 4.2 | Client, Server; LE and BR/EDR -SM | 4.2 | Central (Initiator), Peripheral (Responder) -AVCTP | 1.4 | Controller, Target -AVDTP | 1.2 | Source, Initiator, Acceptor -BNEP | 1.0 | -GAVDP | 1.2 | Initiator, Acceptor -RFCOMM | 1.2 | -SPP | 1.2 | A, B diff --git a/system/embdrv/g722/Android.bp b/system/embdrv/g722/Android.bp index 53a7b2b140e882d9179ba4a1372d743c31baa799..63af8f58eac6f5695f662b16ffa943bb0addafe2 100644 --- a/system/embdrv/g722/Android.bp +++ b/system/embdrv/g722/Android.bp @@ -14,6 +14,7 @@ cc_library_static { defaults: ["fluoride_defaults"], cflags: [ "-DG722_SUPPORT_MALLOC", + "-Wno-unused-parameter", ], srcs: [ "g722_decode.cc", @@ -21,7 +22,6 @@ cc_library_static { ], host_supported: true, apex_available: [ - "//apex_available:platform", "com.android.btservices", ], min_sdk_version: "Tiramisu", diff --git a/system/embdrv/lc3/Android.bp b/system/embdrv/lc3/Android.bp deleted file mode 100644 index 0f6aa61417ba07c6c16b3e2bb48a84fdca59c28e..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/Android.bp +++ /dev/null @@ -1,84 +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: "liblc3", - host_supported: true, - apex_available: [ - - "com.android.btservices", - ], - defaults: ["fluoride_defaults"], - srcs: [ - "src/*.c", - ], - cflags: [ - "-O3", - "-Wmissing-braces", - "-Wno-#warnings", - "-Wno-implicit-fallthrough", - "-Wno-self-assign", - "-Wuninitialized", - "-ffast-math", - ], - target: { - android: { - sanitize: { - misc_undefined: [ - "bounds", - "signed-integer-overflow", - "unsigned-integer-overflow", - ], - cfi: true, - }, - }, - }, - export_include_dirs: [ - "include", - ], - min_sdk_version: "Tiramisu", -} - -cc_fuzz { - name: "liblc3_fuzzer", - - srcs: [ - "fuzzer/liblc3_fuzzer.cpp", - ], - - static_libs: [ - "liblc3", - ], -} - -cc_binary { - name: "lc3_encoder", - host_supported: true, - srcs: [ - "tools/elc3.c", - "tools/lc3bin.c", - "tools/wave.c", - ], - static_libs: [ - "liblc3", - ], -} - -cc_binary { - name: "lc3_decoder", - host_supported: true, - srcs: [ - "tools/dlc3.c", - "tools/lc3bin.c", - "tools/wave.c", - ], - static_libs: [ - "liblc3", - ], -} diff --git a/system/embdrv/lc3/README.md b/system/embdrv/lc3/README.md deleted file mode 100644 index 5538d86e8e9c6c3271923b535597d45ff59a0002..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# Low Complexity Communication Codec (LC3) - -The LC3 is an efficient low latency audio codec. - -[_Low Complexity Communication Codec_](https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=502107&vId=542963) - -## Overview - -The directory layout is as follows : -- include: Library interface -- src: Source files -- tools: Standalone encoder/decoder tools -- test: Python implentation, used as reference for unit testing -- build: Building outputs -- bin: Compilation output - -## How to build - -The default toolchain used is GCC. Invoke `make` to build the library. - -```sh -$ make -j -``` - -Compiled library `liblc3.a` will be found in `bin` directory. - -#### Cross compilation - -The cc, as, ld and ar can be selected with respective Makefile variables `CC`, -`AS`, `LD` and `AR`. The `AS` and `LD` selections are optionnal, and fallback -to `CC` selection when not defined. - -The `LIBC` must be set to `bionic` for android cross-compilation. This switch -prevent link with `pthread` and `rt` libraries, that is included in the -bionic libc. - -Following example build for android, using NDK toolset. - -```sh -$ make -j CC=path_to_android_ndk_prebuilt/toolchain-prefix-clang LIBC=bionic -``` - -Compiled library will be found in `bin` directory. - -## Tools - -Tools can be all compiled, while involking `make` as follows : - -```sh -$ make tools -``` - -The standalone encoder `elc3` take a `wave` file as input and encode it -according given parameter. The LC3 binary file format used is the non -standard format described by the reference encoder / decoder tools. -The standalone decoder `dlc3` do the inverse operation. - -Refer to `elc3 -h` or `dlc3 -h` for options. - -Note that `elc3` output bitstream to standard output when output file is -omitted. On the other side `dlc3` read from standard input when input output -file are omitted. -In such way you can easly test encoding / decoding loop with : - -```sh -$ ./elc3 -b | ./dlc3 > -``` - -Adding Linux `aplay` tools, you will be able to instant hear the result : - -```sh -$ ./elc3 -b | ./dlc3 | aplay -``` - -## Test - -A python implementation of the encoder is provided in `test` diretory. -The C implementation is unitary validated against this implementation and -intermediate values given in Appendix C of the specification. - -#### Prerequisite - -```sh -# apt install python3 python3-dev python3-pip -$ pip3 install scipy numpy -``` - -#### Running test suite - -```sh -$ make test -``` - - -## Conformance - -The proposed encoder and decoder implementation have been fully tested and -validated. - -For more detail on conformance, refer to [_Bluetooth Conformance -Documents and scripts_](https://www.bluetooth.com/specifications/specs/low-complexity-communication-codec-1-0/) - diff --git a/system/embdrv/lc3/fuzzer/liblc3_fuzzer.cpp b/system/embdrv/lc3/fuzzer/liblc3_fuzzer.cpp deleted file mode 100644 index 88577bd40ab84c8b95c0e369b38395f6a7e3a5f4..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/fuzzer/liblc3_fuzzer.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include "include/lc3.h" - -void TestEncoder(FuzzedDataProvider& fdp) { - enum lc3_pcm_format pcm_format = - fdp.PickValueInArray({LC3_PCM_FORMAT_S16, LC3_PCM_FORMAT_S24}); - int dt_us = fdp.PickValueInArray({10000, 7500}); - int sr_hz = - fdp.PickValueInArray({8000, 16000, 24000, 32000, /*44100,*/ 48000}); - unsigned enc_size = lc3_encoder_size(dt_us, sr_hz); - uint16_t output_byte_count = fdp.ConsumeIntegralInRange(20, 400); - uint16_t num_frames = lc3_frame_samples(dt_us, sr_hz); - uint8_t bytes_per_frame = (pcm_format == LC3_PCM_FORMAT_S16 ? 2 : 4); - - if (fdp.remaining_bytes() < num_frames * bytes_per_frame) { - return; - } - - std::vector input_frames( - num_frames / (pcm_format == LC3_PCM_FORMAT_S16 ? 2 : 1)); - fdp.ConsumeData(input_frames.data(), num_frames * bytes_per_frame); - - void* lc3_encoder_mem = nullptr; - lc3_encoder_mem = malloc(enc_size); - lc3_encoder_t lc3_encoder = - lc3_setup_encoder(dt_us, sr_hz, 0, lc3_encoder_mem); - - std::vector output(output_byte_count); - lc3_encode(lc3_encoder, pcm_format, (const int16_t*)input_frames.data(), 1, - output.size(), output.data()); - - free(lc3_encoder_mem); - lc3_encoder_mem = nullptr; - return; -} - -void TestDecoder(FuzzedDataProvider& fdp) { - enum lc3_pcm_format pcm_format = - fdp.PickValueInArray({LC3_PCM_FORMAT_S16, LC3_PCM_FORMAT_S24}); - int dt_us = fdp.PickValueInArray({10000, 7500}); - int sr_hz = - fdp.PickValueInArray({8000, 16000, 24000, 32000, /*44100,*/ 48000}); - unsigned dec_size = lc3_decoder_size(dt_us, sr_hz); - uint16_t input_byte_count = fdp.ConsumeIntegralInRange(20, 400); - uint16_t num_frames = lc3_frame_samples(dt_us, sr_hz); - - if (fdp.remaining_bytes() < input_byte_count) { - return; - } - - std::vector input(input_byte_count); - fdp.ConsumeData(input.data(), input.size()); - - void* lc3_decoder_mem = nullptr; - lc3_decoder_mem = malloc(dec_size); - lc3_decoder_t lc3_decoder = - lc3_setup_decoder(dt_us, sr_hz, 0, lc3_decoder_mem); - - std::vector output(num_frames / - (pcm_format == LC3_PCM_FORMAT_S16 ? 2 : 1)); - lc3_decode(lc3_decoder, input.data(), input.size(), pcm_format, - (int16_t*)output.data(), 1); - - /* Empty input performs PLC (packet loss concealment) */ - lc3_decode(lc3_decoder, nullptr, 0, pcm_format, (int16_t*)output.data(), 1); - - free(lc3_decoder_mem); - lc3_decoder_mem = nullptr; - return; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - FuzzedDataProvider fdp(data, size); - TestEncoder(fdp); - TestDecoder(fdp); - return 0; -} \ No newline at end of file diff --git a/system/embdrv/lc3/include/lc3.h b/system/embdrv/lc3/include/lc3.h deleted file mode 100644 index f590639db329b8353f53fdb947eade834880da47..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/include/lc3.h +++ /dev/null @@ -1,305 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * Low Complexity Communication Codec (LC3) - * - * This implementation conforms to : - * Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - * - * - * The LC3 is an efficient low latency audio codec. - * - * - Unlike most other codecs, the LC3 codec is focused on audio streaming - * in constrained (on packet sizes and interval) tranport layer. - * In this way, the LC3 does not handle : - * VBR (Variable Bitrate), based on input signal complexity - * ABR (Adaptative Bitrate). It does not rely on any bit reservoir, - * a frame will be strictly encoded in the bytes budget given by - * the user (or transport layer). - * - * However, the bitrate (bytes budget for encoding a frame) can be - * freely changed at any time. But will not rely on signal complexity, - * it can follow a temporary bandwidth increase or reduction. - * - * - Unlike classic codecs, the LC3 codecs does not run on fixed amount - * of samples as input. It operates only on fixed frame duration, for - * any supported samplerates (8 to 48 KHz). Two frames duration are - * available 7.5ms and 10ms. - * - * - * --- About 44.1 KHz samplerate --- - * - * The Bluetooth specification reference the 44.1 KHz samplerate, although - * there is no support in the core algorithm of the codec of 44.1 KHz. - * We can summarize the 44.1 KHz support by "you can put any samplerate - * around the defined base samplerates". Please mind the following items : - * - * 1. The frame size will not be 7.5 ms or 10 ms, but is scaled - * by 'supported samplerate' / 'input samplerate' - * - * 2. The bandwidth will be hard limited (to 20 KHz) if you select 48 KHz. - * The encoded bandwidth will also be affected by the above inverse - * factor of 20 KHz. - * - * Applied to 44.1 KHz, we get : - * - * 1. About 8.16 ms frame duration, instead of 7.5 ms - * About 10.88 ms frame duration, instead of 10 ms - * - * 2. The bandwidth becomes limited to 18.375 KHz - * - * - * --- How to encode / decode --- - * - * An encoder / decoder context needs to be setup. This context keeps states - * on the current stream to proceed, and samples that overlapped across - * frames. - * - * You have two ways to setup the encoder / decoder : - * - * - Using static memory allocation (this module does not rely on - * any dynamic memory allocation). The types `lc3_xxcoder_mem_16k_t`, - * and `lc3_xxcoder_mem_48k_t` have size of the memory needed for - * encoding up to 16 KHz or 48 KHz. - * - * - Using dynamic memory allocation. The `lc3_xxcoder_size()` procedure - * returns the needed memory size, for a given configuration. The memory - * space must be aligned to a pointer size. As an example, you can setup - * encoder like this : - * - * | enc = lc3_setup_encoder(frame_us, samplerate, - * | malloc(lc3_encoder_size(frame_us, samplerate))); - * | ... - * | free(enc); - * - * Note : - * - A NULL memory adress as input, will return a NULL encoder context. - * - The returned encoder handle is set at the address of the allocated - * memory space, you can directly free the handle. - * - * Next, call the `lc3_encode()` encoding procedure, for each frames. - * To handle multichannel streams (Stereo or more), you can proceed with - * interleaved channels PCM stream like this : - * - * | for(int ich = 0; ich < nch: ich++) - * | lc3_encode(encoder[ich], pcm + ich, nch, ...); - * - * with `nch` as the number of channels in the PCM stream - * - * --- - * - * Antoine SOULIER, Tempow / Google LLC - * - */ - -#ifndef __LC3_H -#define __LC3_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#include "lc3_private.h" - - -/** - * Limitations - * - On the bitrate, in bps, of a stream - * - On the size of the frames in bytes - */ - -#define LC3_MIN_BITRATE 16000 -#define LC3_MAX_BITRATE 320000 - -#define LC3_MIN_FRAME_BYTES 20 -#define LC3_MAX_FRAME_BYTES 400 - - -/** - * Parameters check - * LC3_CHECK_DT_US(us) True when frame duration in us is suitable - * LC3_CHECK_SR_HZ(sr) True when samplerate in Hz is suitable - */ - -#define LC3_CHECK_DT_US(us) \ - ( ((us) == 7500) || ((us) == 10000) ) - -#define LC3_CHECK_SR_HZ(sr) \ - ( ((sr) == 8000) || ((sr) == 16000) || ((sr) == 24000) || \ - ((sr) == 32000) || ((sr) == 48000) ) - - -/** - * PCM Sample Format - * S16 Signed 16 bits, in 16 bits words (int16_t) - * S24 Signed 24 bits, using low three bytes of 32 bits words (int32_t). - * The high byte sign extends the sample value (bits 31..24 set to b23). - */ - -enum lc3_pcm_format { - LC3_PCM_FORMAT_S16, - LC3_PCM_FORMAT_S24, -}; - - -/** - * Handle - */ - -typedef struct lc3_encoder *lc3_encoder_t; -typedef struct lc3_decoder *lc3_decoder_t; - - -/** - * Static memory of encoder context - * - * Propose types suitable for static memory allocation, supporting - * any frame duration, and maximum samplerates 16k and 48k respectively - * You can customize your type using the `LC3_ENCODER_MEM_T` or - * `LC3_DECODER_MEM_T` macro. - */ - -typedef LC3_ENCODER_MEM_T(10000, 16000) lc3_encoder_mem_16k_t; -typedef LC3_ENCODER_MEM_T(10000, 48000) lc3_encoder_mem_48k_t; - -typedef LC3_DECODER_MEM_T(10000, 16000) lc3_decoder_mem_16k_t; -typedef LC3_DECODER_MEM_T(10000, 48000) lc3_decoder_mem_48k_t; - - -/** - * Return the number of PCM samples in a frame - * dt_us Frame duration in us, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000 - * return Number of PCM samples, -1 on bad parameters - */ -int lc3_frame_samples(int dt_us, int sr_hz); - -/** - * Return the size of frames, from bitrate - * dt_us Frame duration in us, 7500 or 10000 - * bitrate Target bitrate in bit per second - * return The floor size in bytes of the frames, -1 on bad parameters - */ -int lc3_frame_bytes(int dt_us, int bitrate); - -/** - * Resolve the bitrate, from the size of frames - * dt_us Frame duration in us, 7500 or 10000 - * nbytes Size in bytes of the frames - * return The according bitrate in bps, -1 on bad parameters - */ -int lc3_resolve_bitrate(int dt_us, int nbytes); - -/** - * Return algorithmic delay, as a number of samples - * dt_us Frame duration in us, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000 - * return Number of algorithmic delay samples, -1 on bad parameters - */ -int lc3_delay_samples(int dt_us, int sr_hz); - -/** - * Return size needed for an encoder - * dt_us Frame duration in us, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000 - * return Size of then encoder in bytes, 0 on bad parameters - * - * The `sr_hz` parameter is the samplerate of the PCM input stream, - * and will match `sr_pcm_hz` of `lc3_setup_encoder()`. - */ -unsigned lc3_encoder_size(int dt_us, int sr_hz); - -/** - * Setup encoder - * dt_us Frame duration in us, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000 - * sr_pcm_hz Input samplerate, downsampling option of input, or 0 - * mem Encoder memory space, aligned to pointer type - * return Encoder as an handle, NULL on bad parameters - * - * The `sr_pcm_hz` parameter is a downsampling option of PCM input, - * the value `0` fallback to the samplerate of the encoded stream `sr_hz`. - * When used, `sr_pcm_hz` is intended to be higher or equal to the encoder - * samplerate `sr_hz`. The size of the context needed, given by - * `lc3_encoder_size()` will be set accordingly to `sr_pcm_hz`. - */ -lc3_encoder_t lc3_setup_encoder( - int dt_us, int sr_hz, int sr_pcm_hz, void *mem); - -/** - * Encode a frame - * encoder Handle of the encoder - * fmt PCM input format - * pcm, stride Input PCM samples, and count between two consecutives - * nbytes Target size, in bytes, of the frame (20 to 400) - * out Output buffer of `nbytes` size - * return 0: On success -1: Wrong parameters - */ -int lc3_encode(lc3_encoder_t encoder, enum lc3_pcm_format fmt, - const void *pcm, int stride, int nbytes, void *out); - -/** - * Return size needed for an decoder - * dt_us Frame duration in us, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000 - * return Size of then decoder in bytes, 0 on bad parameters - * - * The `sr_hz` parameter is the samplerate of the PCM output stream, - * and will match `sr_pcm_hz` of `lc3_setup_decoder()`. - */ -unsigned lc3_decoder_size(int dt_us, int sr_hz); - -/** - * Setup decoder - * dt_us Frame duration in us, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000 - * sr_pcm_hz Output samplerate, upsampling option of output (or 0) - * mem Decoder memory space, aligned to pointer type - * return Decoder as an handle, NULL on bad parameters - * - * The `sr_pcm_hz` parameter is an upsampling option of PCM output, - * the value `0` fallback to the samplerate of the decoded stream `sr_hz`. - * When used, `sr_pcm_hz` is intended to be higher or equal to the decoder - * samplerate `sr_hz`. The size of the context needed, given by - * `lc3_decoder_size()` will be set accordingly to `sr_pcm_hz`. - */ -lc3_decoder_t lc3_setup_decoder( - int dt_us, int sr_hz, int sr_pcm_hz, void *mem); - -/** - * Decode a frame - * decoder Handle of the decoder - * in, nbytes Input bitstream, and size in bytes, NULL performs PLC - * fmt PCM output format - * pcm, stride Output PCM samples, and count between two consecutives - * return 0: On success 1: PLC operated -1: Wrong parameters - */ -int lc3_decode(lc3_decoder_t decoder, const void *in, int nbytes, - enum lc3_pcm_format fmt, void *pcm, int stride); - - -#ifdef __cplusplus -} -#endif - -#endif /* __LC3_H */ diff --git a/system/embdrv/lc3/include/lc3_private.h b/system/embdrv/lc3/include/lc3_private.h deleted file mode 100644 index 467d02862169d8e7ad30c78fb2205379328d34ec..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/include/lc3_private.h +++ /dev/null @@ -1,162 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#ifndef __LC3_PRIVATE_H -#define __LC3_PRIVATE_H - -#include -#include - - -/** - * Return number of samples, delayed samples and - * encoded spectrum coefficients within a frame - * - For encoding, keep 1.25 ms of temporal winodw - * - For decoding, keep 18 ms of history, aligned on frames, and a frame - */ - -#define __LC3_NS(dt_us, sr_hz) \ - ( (dt_us * sr_hz) / 1000 / 1000 ) - -#define __LC3_ND(dt_us, sr_hz) \ - ( (dt_us) == 7500 ? 23 * __LC3_NS(dt_us, sr_hz) / 30 \ - : 5 * __LC3_NS(dt_us, sr_hz) / 8 ) - -#define __LC3_NT(sr_hz) \ - ( (5 * sr_hz) / 4000 ) - -#define __LC3_NH(dt_us, sr_hz) \ - ( ((3 - ((dt_us) >= 10000)) + 1) * __LC3_NS(dt_us, sr_hz) ) - - -/** - * Frame duration 7.5ms or 10ms - */ - -enum lc3_dt { - LC3_DT_7M5, - LC3_DT_10M, - - LC3_NUM_DT -}; - -/** - * Sampling frequency - */ - -enum lc3_srate { - LC3_SRATE_8K, - LC3_SRATE_16K, - LC3_SRATE_24K, - LC3_SRATE_32K, - LC3_SRATE_48K, - - LC3_NUM_SRATE, -}; - - -/** - * Encoder state and memory - */ - -typedef struct lc3_attdet_analysis { - int32_t en1, an1; - int p_att; -} lc3_attdet_analysis_t; - -struct lc3_ltpf_hp50_state { - int64_t s1, s2; -}; - -typedef struct lc3_ltpf_analysis { - bool active; - int pitch; - float nc[2]; - - struct lc3_ltpf_hp50_state hp50; - int16_t x_12k8[384]; - int16_t x_6k4[178]; - int tc; -} lc3_ltpf_analysis_t; - -typedef struct lc3_spec_analysis { - float nbits_off; - int nbits_spare; -} lc3_spec_analysis_t; - -struct lc3_encoder { - enum lc3_dt dt; - enum lc3_srate sr, sr_pcm; - - lc3_attdet_analysis_t attdet; - lc3_ltpf_analysis_t ltpf; - lc3_spec_analysis_t spec; - - int16_t *xt; - float *xs, *xd, s[0]; -}; - -#define LC3_ENCODER_BUFFER_COUNT(dt_us, sr_hz) \ - ( ( __LC3_NS(dt_us, sr_hz) + __LC3_NT(sr_hz) ) / 2 + \ - __LC3_NS(dt_us, sr_hz) + __LC3_ND(dt_us, sr_hz) ) - -#define LC3_ENCODER_MEM_T(dt_us, sr_hz) \ - struct { \ - struct lc3_encoder __e; \ - float __s[LC3_ENCODER_BUFFER_COUNT(dt_us, sr_hz)]; \ - } - - -/** - * Decoder state and memory - */ - -typedef struct lc3_ltpf_synthesis { - bool active; - int pitch; - float c[2*12], x[12]; -} lc3_ltpf_synthesis_t; - -typedef struct lc3_plc_state { - uint16_t seed; - int count; - float alpha; -} lc3_plc_state_t; - -struct lc3_decoder { - enum lc3_dt dt; - enum lc3_srate sr, sr_pcm; - - lc3_ltpf_synthesis_t ltpf; - lc3_plc_state_t plc; - - float *xh, *xs, *xd, *xg, s[0]; -}; - -#define LC3_DECODER_BUFFER_COUNT(dt_us, sr_hz) \ - ( __LC3_NH(dt_us, sr_hz) + __LC3_ND(dt_us, sr_hz) + \ - __LC3_NS(dt_us, sr_hz) ) - -#define LC3_DECODER_MEM_T(dt_us, sr_hz) \ - struct { \ - struct lc3_decoder __d; \ - float __s[LC3_DECODER_BUFFER_COUNT(dt_us, sr_hz)]; \ - } - - -#endif /* __LC3_PRIVATE_H */ diff --git a/system/embdrv/lc3/src/attdet.c b/system/embdrv/lc3/src/attdet.c deleted file mode 100644 index 3d1528d0721e6437294912ae25902bdfdaa743e6..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/attdet.c +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "attdet.h" - - -/** - * Time domain attack detector - */ -bool lc3_attdet_run(enum lc3_dt dt, enum lc3_srate sr, - int nbytes, struct lc3_attdet_analysis *attdet, const int16_t *x) -{ - /* --- Check enabling --- */ - - const int nbytes_ranges[LC3_NUM_DT][LC3_NUM_SRATE - LC3_SRATE_32K][2] = { - [LC3_DT_7M5] = { { 61, 149 }, { 75, 149 } }, - [LC3_DT_10M] = { { 81, INT_MAX }, { 100, INT_MAX } }, - }; - - if (sr < LC3_SRATE_32K || - nbytes < nbytes_ranges[dt][sr - LC3_SRATE_32K][0] || - nbytes > nbytes_ranges[dt][sr - LC3_SRATE_32K][1] ) - return 0; - - /* --- Filtering & Energy calculation --- */ - - int nblk = 4 - (dt == LC3_DT_7M5); - int32_t e[4]; - - for (int i = 0; i < nblk; i++) { - e[i] = 0; - - if (sr == LC3_SRATE_32K) { - int16_t xn2 = (x[-4] + x[-3]) >> 1; - int16_t xn1 = (x[-2] + x[-1]) >> 1; - int16_t xn, xf; - - for (int j = 0; j < 40; j++, x += 2, xn2 = xn1, xn1 = xn) { - xn = (x[0] + x[1]) >> 1; - xf = (3 * xn - 4 * xn1 + 1 * xn2) >> 3; - e[i] += (xf * xf) >> 5; - } - } - - else { - int16_t xn2 = (x[-6] + x[-5] + x[-4]) >> 2; - int16_t xn1 = (x[-3] + x[-2] + x[-1]) >> 2; - int16_t xn, xf; - - for (int j = 0; j < 40; j++, x += 3, xn2 = xn1, xn1 = xn) { - xn = (x[0] + x[1] + x[2]) >> 2; - xf = (3 * xn - 4 * xn1 + 1 * xn2) >> 3; - e[i] += (xf * xf) >> 5; - } - } - } - - /* --- Attack detection --- - * The attack block `p_att` is defined as the normative value + 1, - * in such way, it will be initialized to 0 */ - - int p_att = 0; - int32_t a[4]; - - for (int i = 0; i < nblk; i++) { - a[i] = LC3_MAX(attdet->an1 >> 2, attdet->en1); - attdet->en1 = e[i], attdet->an1 = a[i]; - - if ((e[i] >> 3) > a[i] + (a[i] >> 4)) - p_att = i + 1; - } - - int att = attdet->p_att >= 1 + (nblk >> 1) || p_att > 0; - attdet->p_att = p_att; - - return att; -} diff --git a/system/embdrv/lc3/src/attdet.h b/system/embdrv/lc3/src/attdet.h deleted file mode 100644 index 14073bd405584d6c24d57c8dfa760fee43a1fd46..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/attdet.h +++ /dev/null @@ -1,44 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Time domain attack detector - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_ATTDET_H -#define __LC3_ATTDET_H - -#include "common.h" - - -/** - * Time domain attack detector - * dt, sr Duration and samplerate of the frame - * nbytes Size in bytes of the frame - * attdet Context of the Attack Detector - * x [-6..-1] Previous, [0..ns-1] Current samples - * return 1: Attack detected 0: Otherwise - */ -bool lc3_attdet_run(enum lc3_dt dt, enum lc3_srate sr, - int nbytes, lc3_attdet_analysis_t *attdet, const int16_t *x); - - -#endif /* __LC3_ATTDET_H */ diff --git a/system/embdrv/lc3/src/bits.c b/system/embdrv/lc3/src/bits.c deleted file mode 100644 index 09b6da76fc08fbe63e6e37c4b55941b2c6a76277..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/bits.c +++ /dev/null @@ -1,375 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "bits.h" -#include "common.h" - - -/* ---------------------------------------------------------------------------- - * Common - * -------------------------------------------------------------------------- */ - -static inline int ac_get(struct lc3_bits_buffer *); -static inline void accu_load(struct lc3_bits_accu *, struct lc3_bits_buffer *); - -/** - * Arithmetic coder return range bits - * ac Arithmetic coder - * return 1 + log2(ac->range) - */ -static int ac_get_range_bits(const struct lc3_bits_ac *ac) -{ - int nbits = 0; - - for (unsigned r = ac->range; r; r >>= 1, nbits++); - - return nbits; -} - -/** - * Arithmetic coder return pending bits - * ac Arithmetic coder - * return Pending bits - */ -static int ac_get_pending_bits(const struct lc3_bits_ac *ac) -{ - return 26 - ac_get_range_bits(ac) + - ((ac->cache >= 0) + ac->carry_count) * 8; -} - -/** - * Return number of bits left in the bitstream - * bits Bitstream context - * return >= 0: Number of bits left < 0: Overflow - */ -static int get_bits_left(const struct lc3_bits *bits) -{ - const struct lc3_bits_buffer *buffer = &bits->buffer; - const struct lc3_bits_accu *accu = &bits->accu; - const struct lc3_bits_ac *ac = &bits->ac; - - uintptr_t end = (uintptr_t)buffer->p_bw + - (bits->mode == LC3_BITS_MODE_READ ? LC3_ACCU_BITS/8 : 0); - - uintptr_t start = (uintptr_t)buffer->p_fw - - (bits->mode == LC3_BITS_MODE_READ ? LC3_AC_BITS/8 : 0); - - int n = end > start ? (int)(end - start) : -(int)(start - end); - - return 8 * n - (accu->n + accu->nover + ac_get_pending_bits(ac)); -} - -/** - * Setup bitstream writing - */ -void lc3_setup_bits(struct lc3_bits *bits, - enum lc3_bits_mode mode, void *buffer, int len) -{ - *bits = (struct lc3_bits){ - .mode = mode, - .accu = { - .n = mode == LC3_BITS_MODE_READ ? LC3_ACCU_BITS : 0, - }, - .ac = { - .range = 0xffffff, - .cache = -1 - }, - .buffer = { - .start = (uint8_t *)buffer, .end = (uint8_t *)buffer + len, - .p_fw = (uint8_t *)buffer, .p_bw = (uint8_t *)buffer + len, - } - }; - - if (mode == LC3_BITS_MODE_READ) { - struct lc3_bits_ac *ac = &bits->ac; - struct lc3_bits_accu *accu = &bits->accu; - struct lc3_bits_buffer *buffer = &bits->buffer; - - ac->low = ac_get(buffer) << 16; - ac->low |= ac_get(buffer) << 8; - ac->low |= ac_get(buffer); - - accu_load(accu, buffer); - } -} - -/** - * Return number of bits left in the bitstream - */ -int lc3_get_bits_left(const struct lc3_bits *bits) -{ - return LC3_MAX(get_bits_left(bits), 0); -} - -/** - * Return number of bits left in the bitstream - */ -int lc3_check_bits(const struct lc3_bits *bits) -{ - const struct lc3_bits_ac *ac = &bits->ac; - - return -(get_bits_left(bits) < 0 || ac->error); -} - - -/* ---------------------------------------------------------------------------- - * Writing - * -------------------------------------------------------------------------- */ - -/** - * Flush the bits accumulator - * accu Bitstream accumulator - * buffer Bitstream buffer - */ -static inline void accu_flush( - struct lc3_bits_accu *accu, struct lc3_bits_buffer *buffer) -{ - int nbytes = LC3_MIN(accu->n >> 3, - LC3_MAX(buffer->p_bw - buffer->p_fw, 0)); - - accu->n -= 8 * nbytes; - - for ( ; nbytes; accu->v >>= 8, nbytes--) - *(--buffer->p_bw) = accu->v & 0xff; - - if (accu->n >= 8) - accu->n = 0; -} - -/** - * Arithmetic coder put byte - * buffer Bitstream buffer - * byte Byte to output - */ -static inline void ac_put(struct lc3_bits_buffer *buffer, int byte) -{ - if (buffer->p_fw < buffer->end) - *(buffer->p_fw++) = byte; -} - -/** - * Arithmetic coder range shift - * ac Arithmetic coder - * buffer Bitstream buffer - */ -LC3_HOT static inline void ac_shift( - struct lc3_bits_ac *ac, struct lc3_bits_buffer *buffer) -{ - if (ac->low < 0xff0000 || ac->carry) - { - if (ac->cache >= 0) - ac_put(buffer, ac->cache + ac->carry); - - for ( ; ac->carry_count > 0; ac->carry_count--) - ac_put(buffer, ac->carry ? 0x00 : 0xff); - - ac->cache = ac->low >> 16; - ac->carry = 0; - } - else - ac->carry_count++; - - ac->low = (ac->low << 8) & 0xffffff; -} - -/** - * Arithmetic coder termination - * ac Arithmetic coder - * buffer Bitstream buffer - * end_val/nbits End value and count of bits to terminate (1 to 8) - */ -static void ac_terminate(struct lc3_bits_ac *ac, - struct lc3_bits_buffer *buffer) -{ - int nbits = 25 - ac_get_range_bits(ac); - unsigned mask = 0xffffff >> nbits; - unsigned val = ac->low + mask; - unsigned high = ac->low + ac->range; - - bool over_val = val >> 24; - bool over_high = high >> 24; - - val = (val & 0xffffff) & ~mask; - high = (high & 0xffffff); - - if (over_val == over_high) { - - if (val + mask >= high) { - nbits++; - mask >>= 1; - val = ((ac->low + mask) & 0xffffff) & ~mask; - } - - ac->carry |= val < ac->low; - } - - ac->low = val; - - for (; nbits > 8; nbits -= 8) - ac_shift(ac, buffer); - ac_shift(ac, buffer); - - int end_val = ac->cache >> (8 - nbits); - - if (ac->carry_count) { - ac_put(buffer, ac->cache); - for ( ; ac->carry_count > 1; ac->carry_count--) - ac_put(buffer, 0xff); - - end_val = nbits < 8 ? 0 : 0xff; - } - - if (buffer->p_fw < buffer->end) { - *buffer->p_fw &= 0xff >> nbits; - *buffer->p_fw |= end_val << (8 - nbits); - } -} - -/** - * Flush and terminate bitstream - */ -void lc3_flush_bits(struct lc3_bits *bits) -{ - struct lc3_bits_ac *ac = &bits->ac; - struct lc3_bits_accu *accu = &bits->accu; - struct lc3_bits_buffer *buffer = &bits->buffer; - - int nleft = buffer->p_bw - buffer->p_fw; - for (int n = 8 * nleft - accu->n; n > 0; n -= 32) - lc3_put_bits(bits, 0, LC3_MIN(n, 32)); - - accu_flush(accu, buffer); - - ac_terminate(ac, buffer); -} - -/** - * Write from 1 to 32 bits, - * exceeding the capacity of the accumulator - */ -LC3_HOT void lc3_put_bits_generic(struct lc3_bits *bits, unsigned v, int n) -{ - struct lc3_bits_accu *accu = &bits->accu; - - /* --- Fulfill accumulator and flush -- */ - - int n1 = LC3_MIN(LC3_ACCU_BITS - accu->n, n); - if (n1) { - accu->v |= v << accu->n; - accu->n = LC3_ACCU_BITS; - } - - accu_flush(accu, &bits->buffer); - - /* --- Accumulate remaining bits -- */ - - accu->v = v >> n1; - accu->n = n - n1; -} - -/** - * Arithmetic coder renormalization - */ -LC3_HOT void lc3_ac_write_renorm(struct lc3_bits *bits) -{ - struct lc3_bits_ac *ac = &bits->ac; - - for ( ; ac->range < 0x10000; ac->range <<= 8) - ac_shift(ac, &bits->buffer); -} - - -/* ---------------------------------------------------------------------------- - * Reading - * -------------------------------------------------------------------------- */ - -/** - * Arithmetic coder get byte - * buffer Bitstream buffer - * return Byte read, 0 on overflow - */ -static inline int ac_get(struct lc3_bits_buffer *buffer) -{ - return buffer->p_fw < buffer->end ? *(buffer->p_fw++) : 0; -} - -/** - * Load the accumulator - * accu Bitstream accumulator - * buffer Bitstream buffer - */ -static inline void accu_load(struct lc3_bits_accu *accu, - struct lc3_bits_buffer *buffer) -{ - int nbytes = LC3_MIN(accu->n >> 3, buffer->p_bw - buffer->start); - - accu->n -= 8 * nbytes; - - for ( ; nbytes; nbytes--) { - accu->v >>= 8; - accu->v |= *(--buffer->p_bw) << (LC3_ACCU_BITS - 8); - } - - if (accu->n >= 8) { - accu->nover = LC3_MIN(accu->nover + accu->n, LC3_ACCU_BITS); - accu->v >>= accu->n; - accu->n = 0; - } -} - -/** - * Read from 1 to 32 bits, - * exceeding the capacity of the accumulator - */ -LC3_HOT unsigned lc3_get_bits_generic(struct lc3_bits *bits, int n) -{ - struct lc3_bits_accu *accu = &bits->accu; - struct lc3_bits_buffer *buffer = &bits->buffer; - - /* --- Fulfill accumulator and read -- */ - - accu_load(accu, buffer); - - int n1 = LC3_MIN(LC3_ACCU_BITS - accu->n, n); - unsigned v = (accu->v >> accu->n) & ((1u << n1) - 1); - accu->n += n1; - - /* --- Second round --- */ - - int n2 = n - n1; - - if (n2) { - accu_load(accu, buffer); - - v |= ((accu->v >> accu->n) & ((1u << n2) - 1)) << n1; - accu->n += n2; - } - - return v; -} - -/** - * Arithmetic coder renormalization - */ -LC3_HOT void lc3_ac_read_renorm(struct lc3_bits *bits) -{ - struct lc3_bits_ac *ac = &bits->ac; - - for ( ; ac->range < 0x10000; ac->range <<= 8) - ac->low = ((ac->low << 8) | ac_get(&bits->buffer)) & 0xffffff; -} diff --git a/system/embdrv/lc3/src/bits.h b/system/embdrv/lc3/src/bits.h deleted file mode 100644 index 5dd56cdf1899ccc3d38e0c3cad63448b7b644a10..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/bits.h +++ /dev/null @@ -1,315 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Bitstream management - * - * The bitstream is written by the 2 ends of the buffer : - * - * - Arthmetic coder put bits while increasing memory addresses - * in the buffer (forward) - * - * - Plain bits are puts starting the end of the buffer, with memeory - * addresses decreasing (backward) - * - * .---------------------------------------------------. - * | > > > > > > > > > > : : < < < < < < < < < | - * '---------------------------------------------------' - * |---------------------> - - - - - - - - - - - - - ->| - * |< - - - <-------------------| - * Arithmetic coding Plain bits - * `lc3_put_symbol()` `lc3_put_bits()` - * - * - The forward writing is protected against buffer overflow, it cannot - * write after the buffer, but can overwrite plain bits previously - * written in the buffer. - * - * - The backward writing is protected against overwrite of the arithmetic - * coder bitstream. In such way, the backward bitstream is always limited - * by the aritmetic coder bitstream, and can be overwritten by him. - * - * .---------------------------------------------------. - * | > > > > > > > > > > : : < < < < < < < < < | - * '---------------------------------------------------' - * |---------------------> - - - - - - - - - - - - - ->| - * |< - - - - - - - - - - - - - - <-------------------| - * Arithmetic coding Plain bits - * `lc3_get_symbol()` `lc3_get_bits()` - * - * - Reading is limited to read of the complementary end of the buffer. - * - * - The procedure `lc3_check_bits()` returns indication that read has been - * made crossing the other bit plane. - * - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - * - */ - -#ifndef __LC3_BITS_H -#define __LC3_BITS_H - -#include "common.h" - - -/** - * Bitstream mode - */ - -enum lc3_bits_mode { - LC3_BITS_MODE_READ, - LC3_BITS_MODE_WRITE, -}; - -/** - * Arithmetic coder symbol interval - * The model split the interval in 17 symbols - */ - -struct lc3_ac_symbol { - uint16_t low : 16; - uint16_t range : 16; -}; - -struct lc3_ac_model { - struct lc3_ac_symbol s[17]; -}; - -/** - * Bitstream context - */ - -#define LC3_ACCU_BITS (int)(8 * sizeof(unsigned)) - -struct lc3_bits_accu { - unsigned v; - int n, nover; -}; - -#define LC3_AC_BITS (int)(24) - -struct lc3_bits_ac { - unsigned low, range; - int cache, carry, carry_count; - bool error; -}; - -struct lc3_bits_buffer { - const uint8_t *start, *end; - uint8_t *p_fw, *p_bw; -}; - -typedef struct lc3_bits { - enum lc3_bits_mode mode; - struct lc3_bits_ac ac; - struct lc3_bits_accu accu; - struct lc3_bits_buffer buffer; -} lc3_bits_t; - - -/** - * Setup bitstream reading/writing - * bits Bitstream context - * mode Either READ or WRITE mode - * buffer, len Output buffer and length (in bytes) - */ -void lc3_setup_bits(lc3_bits_t *bits, - enum lc3_bits_mode mode, void *buffer, int len); - -/** - * Return number of bits left in the bitstream - * bits Bitstream context - * return Number of bits left - */ -int lc3_get_bits_left(const lc3_bits_t *bits); - -/** - * Check if error occured on bitstream reading/writing - * bits Bitstream context - * return 0: Ok -1: Bitstream overflow or AC reading error - */ -int lc3_check_bits(const lc3_bits_t *bits); - -/** - * Put a bit - * bits Bitstream context - * v Bit value, 0 or 1 - */ -static inline void lc3_put_bit(lc3_bits_t *bits, int v); - -/** - * Put from 1 to 32 bits - * bits Bitstream context - * v, n Value, in range 0 to 2^n - 1, and bits count (1 to 32) - */ -static inline void lc3_put_bits(lc3_bits_t *bits, unsigned v, int n); - -/** - * Put arithmetic coder symbol - * bits Bitstream context - * model, s Model distribution and symbol value - */ -static inline void lc3_put_symbol(lc3_bits_t *bits, - const struct lc3_ac_model *model, unsigned s); - -/** - * Flush and terminate bitstream writing - * bits Bitstream context - */ -void lc3_flush_bits(lc3_bits_t *bits); - -/** - * Get a bit - * bits Bitstream context - */ -static inline int lc3_get_bit(lc3_bits_t *bits); - -/** - * Get from 1 to 32 bits - * bits Bitstream context - * n Number of bits to read (1 to 32) - * return The value read - */ -static inline unsigned lc3_get_bits(lc3_bits_t *bits, int n); - -/** - * Get arithmetic coder symbol - * bits Bitstream context - * model Model distribution - * return The value read - */ -static inline unsigned lc3_get_symbol(lc3_bits_t *bits, - const struct lc3_ac_model *model); - - - -/* ---------------------------------------------------------------------------- - * Inline implementations - * -------------------------------------------------------------------------- */ - -void lc3_put_bits_generic(lc3_bits_t *bits, unsigned v, int n); -unsigned lc3_get_bits_generic(struct lc3_bits *bits, int n); - -void lc3_ac_read_renorm(lc3_bits_t *bits); -void lc3_ac_write_renorm(lc3_bits_t *bits); - - -/** - * Put a bit - */ -LC3_HOT static inline void lc3_put_bit(lc3_bits_t *bits, int v) -{ - lc3_put_bits(bits, v, 1); -} - -/** - * Put from 1 to 32 bits - */ -LC3_HOT static inline void lc3_put_bits( - struct lc3_bits *bits, unsigned v, int n) -{ - struct lc3_bits_accu *accu = &bits->accu; - - if (accu->n + n <= LC3_ACCU_BITS) { - accu->v |= v << accu->n; - accu->n += n; - } else { - lc3_put_bits_generic(bits, v, n); - } -} - -/** - * Get a bit - */ -LC3_HOT static inline int lc3_get_bit(lc3_bits_t *bits) -{ - return lc3_get_bits(bits, 1); -} - -/** - * Get from 1 to 32 bits - */ -LC3_HOT static inline unsigned lc3_get_bits(struct lc3_bits *bits, int n) -{ - struct lc3_bits_accu *accu = &bits->accu; - - if (accu->n + n <= LC3_ACCU_BITS) { - int v = (accu->v >> accu->n) & ((1u << n) - 1); - return (accu->n += n), v; - } - else { - return lc3_get_bits_generic(bits, n); - } -} - -/** - * Put arithmetic coder symbol - */ -LC3_HOT static inline void lc3_put_symbol( - struct lc3_bits *bits, const struct lc3_ac_model *model, unsigned s) -{ - const struct lc3_ac_symbol *symbols = model->s; - struct lc3_bits_ac *ac = &bits->ac; - unsigned range = ac->range >> 10; - - ac->low += range * symbols[s].low; - ac->range = range * symbols[s].range; - - ac->carry |= ac->low >> 24; - ac->low &= 0xffffff; - - if (ac->range < 0x10000) - lc3_ac_write_renorm(bits); -} - -/** - * Get arithmetic coder symbol - */ -LC3_HOT static inline unsigned lc3_get_symbol( - lc3_bits_t *bits, const struct lc3_ac_model *model) -{ - const struct lc3_ac_symbol *symbols = model->s; - struct lc3_bits_ac *ac = &bits->ac; - - unsigned range = (ac->range >> 10) & 0xffff; - - ac->error |= (ac->low >= (range << 10)); - if (ac->error) - ac->low = 0; - - int s = 16; - - if (ac->low < range * symbols[s].low) { - s >>= 1; - s -= ac->low < range * symbols[s].low ? 4 : -4; - s -= ac->low < range * symbols[s].low ? 2 : -2; - s -= ac->low < range * symbols[s].low ? 1 : -1; - s -= ac->low < range * symbols[s].low; - } - - ac->low -= range * symbols[s].low; - ac->range = range * symbols[s].range; - - if (ac->range < 0x10000) - lc3_ac_read_renorm(bits); - - return s; -} - -#endif /* __LC3_BITS_H */ diff --git a/system/embdrv/lc3/src/bwdet.c b/system/embdrv/lc3/src/bwdet.c deleted file mode 100644 index 8dc0f5c74131cb987d108b0175fb5b6a41b82e51..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/bwdet.c +++ /dev/null @@ -1,129 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "bwdet.h" - - -/** - * Bandwidth detector - */ -enum lc3_bandwidth lc3_bwdet_run( - enum lc3_dt dt, enum lc3_srate sr, const float *e) -{ - /* Bandwidth regions (Table 3.6) */ - - struct region { int is : 8; int ie : 8; }; - - static const struct region bws_table[LC3_NUM_DT] - [LC3_NUM_BANDWIDTH-1][LC3_NUM_BANDWIDTH-1] = { - - [LC3_DT_7M5] = { - { { 51, 63+1 } }, - { { 45, 55+1 }, { 58, 63+1 } }, - { { 42, 51+1 }, { 53, 58+1 }, { 60, 63+1 } }, - { { 40, 48+1 }, { 51, 55+1 }, { 57, 60+1 }, { 61, 63+1 } }, - }, - - [LC3_DT_10M] = { - { { 53, 63+1 } }, - { { 47, 56+1 }, { 59, 63+1 } }, - { { 44, 52+1 }, { 54, 59+1 }, { 60, 63+1 } }, - { { 41, 49+1 }, { 51, 55+1 }, { 57, 60+1 }, { 61, 63+1 } }, - }, - }; - - static const int l_table[LC3_NUM_DT][LC3_NUM_BANDWIDTH-1] = { - [LC3_DT_7M5] = { 4, 4, 3, 2 }, - [LC3_DT_10M] = { 4, 4, 3, 1 }, - }; - - /* --- Stage 1 --- - * Determine bw0 candidate */ - - enum lc3_bandwidth bw0 = LC3_BANDWIDTH_NB; - enum lc3_bandwidth bwn = (enum lc3_bandwidth)sr; - - if (bwn <= bw0) - return bwn; - - const struct region *bwr = bws_table[dt][bwn-1]; - - for (enum lc3_bandwidth bw = bw0; bw < bwn; bw++) { - int i = bwr[bw].is, ie = bwr[bw].ie; - int n = ie - i; - - float se = e[i]; - for (i++; i < ie; i++) - se += e[i]; - - if (se >= (10 << (bw == LC3_BANDWIDTH_NB)) * n) - bw0 = bw + 1; - } - - /* --- Stage 2 --- - * Detect drop above cut-off frequency. - * The Tc condition (13) is precalculated, as - * Tc[] = 10 ^ (n / 10) , n = { 15, 23, 20, 20 } */ - - int hold = bw0 >= bwn; - - if (!hold) { - int i0 = bwr[bw0].is, l = l_table[dt][bw0]; - float tc = (const float []){ - 31.62277660, 199.52623150, 100, 100 }[bw0]; - - for (int i = i0 - l + 1; !hold && i <= i0 + 1; i++) { - hold = e[i-l] > tc * e[i]; - } - - } - - return hold ? bw0 : bwn; -} - -/** - * Return number of bits coding the bandwidth value - */ -int lc3_bwdet_get_nbits(enum lc3_srate sr) -{ - return (sr > 0) + (sr > 1) + (sr > 3); -} - -/** - * Put bandwidth indication - */ -void lc3_bwdet_put_bw(lc3_bits_t *bits, - enum lc3_srate sr, enum lc3_bandwidth bw) -{ - int nbits_bw = lc3_bwdet_get_nbits(sr); - if (nbits_bw > 0) - lc3_put_bits(bits, bw, nbits_bw); -} - -/** - * Get bandwidth indication - */ -int lc3_bwdet_get_bw(lc3_bits_t *bits, - enum lc3_srate sr, enum lc3_bandwidth *bw) -{ - enum lc3_bandwidth max_bw = (enum lc3_bandwidth)sr; - int nbits_bw = lc3_bwdet_get_nbits(sr); - - *bw = nbits_bw > 0 ? lc3_get_bits(bits, nbits_bw) : LC3_BANDWIDTH_NB; - return *bw > max_bw ? (*bw = max_bw), -1 : 0; -} diff --git a/system/embdrv/lc3/src/bwdet.h b/system/embdrv/lc3/src/bwdet.h deleted file mode 100644 index 19039c78ccb28c4b274178282fcaf88cb87d3aad..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/bwdet.h +++ /dev/null @@ -1,69 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Bandwidth detector - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_BWDET_H -#define __LC3_BWDET_H - -#include "common.h" -#include "bits.h" - - -/** - * Bandwidth detector (cf. 3.3.5) - * dt, sr Duration and samplerate of the frame - * e Energy estimation per bands - * return Return detected bandwitdth - */ -enum lc3_bandwidth lc3_bwdet_run( - enum lc3_dt dt, enum lc3_srate sr, const float *e); - -/** - * Return number of bits coding the bandwidth value - * sr Samplerate of the frame - * return Number of bits coding the bandwidth value - */ -int lc3_bwdet_get_nbits(enum lc3_srate sr); - -/** - * Put bandwidth indication - * bits Bitstream context - * sr Samplerate of the frame - * bw Bandwidth detected - */ -void lc3_bwdet_put_bw(lc3_bits_t *bits, - enum lc3_srate sr, enum lc3_bandwidth bw); - -/** - * Get bandwidth indication - * bits Bitstream context - * sr Samplerate of the frame - * bw Return bandwidth indication - * return 0: Ok -1: Invalid bandwidth indication - */ -int lc3_bwdet_get_bw(lc3_bits_t *bits, - enum lc3_srate sr, enum lc3_bandwidth *bw); - - -#endif /* __LC3_BWDET_H */ diff --git a/system/embdrv/lc3/src/common.h b/system/embdrv/lc3/src/common.h deleted file mode 100644 index a9aaa0e2897e97e7d9eb494821c94af51b213f14..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/common.h +++ /dev/null @@ -1,148 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Common constants and types - */ - -#ifndef __LC3_COMMON_H -#define __LC3_COMMON_H - -#include -#include "fastmath.h" - -#include -#include -#include - -#ifdef __ARM_ARCH -#include -#endif - - -/** - * Hot Function attribute - * Selectively disable sanitizer - */ - -#ifdef __clang__ - -#define LC3_HOT \ - __attribute__((no_sanitize("bounds"))) \ - __attribute__((no_sanitize("integer"))) - -#else /* __clang__ */ - -#define LC3_HOT - -#endif /* __clang__ */ - - -/** - * Macros - * MIN/MAX Minimum and maximum between 2 values - * CLIP Clip a value between low and high limits - * SATXX Signed saturation on 'xx' bits - * ABS Return absolute value - */ - -#define LC3_MIN(a, b) ( (a) < (b) ? (a) : (b) ) -#define LC3_MAX(a, b) ( (a) > (b) ? (a) : (b) ) - -#define LC3_CLIP(v, min, max) LC3_MIN(LC3_MAX(v, min), max) -#define LC3_SAT16(v) LC3_CLIP(v, -(1 << 15), (1 << 15) - 1) -#define LC3_SAT24(v) LC3_CLIP(v, -(1 << 23), (1 << 23) - 1) - -#define LC3_ABS(v) ( (v) < 0 ? -(v) : (v) ) - - -#ifdef __ARM_FEATURE_SAT - -#undef LC3_SAT16 -#define LC3_SAT16(v) __ssat(v, 16) - -#undef LC3_SAT24 -#define LC3_SAT24(v) __ssat(v, 24) - -#endif /* __ARM_FEATURE_SAT */ - - -/** - * Convert `dt` in us and `sr` in KHz - */ - -#define LC3_DT_US(dt) \ - ( (3 + (dt)) * 2500 ) - -#define LC3_SRATE_KHZ(sr) \ - ( (1 + (sr) + ((sr) == LC3_SRATE_48K)) * 8 ) - - -/** - * Return number of samples, delayed samples and - * encoded spectrum coefficients within a frame - * - For encoding, keep 1.25 ms for temporal window - * - For decoding, keep 18 ms of history, aligned on frames, and a frame - */ - -#define LC3_NS(dt, sr) \ - ( 20 * (3 + (dt)) * (1 + (sr) + ((sr) == LC3_SRATE_48K)) ) - -#define LC3_ND(dt, sr) \ - ( (dt) == LC3_DT_7M5 ? 23 * LC3_NS(dt, sr) / 30 \ - : 5 * LC3_NS(dt, sr) / 8 ) - -#define LC3_NE(dt, sr) \ - ( 20 * (3 + (dt)) * (1 + (sr)) ) - -#define LC3_MAX_NE \ - LC3_NE(LC3_DT_10M, LC3_SRATE_48K) - -#define LC3_NT(sr_hz) \ - ( (5 * LC3_SRATE_KHZ(sr)) / 4 ) - -#define LC3_NH(dt, sr) \ - ( ((3 - dt) + 1) * LC3_NS(dt, sr) ) - - -/** - * Bandwidth, mapped to Nyquist frequency of samplerates - */ - -enum lc3_bandwidth { - LC3_BANDWIDTH_NB = LC3_SRATE_8K, - LC3_BANDWIDTH_WB = LC3_SRATE_16K, - LC3_BANDWIDTH_SSWB = LC3_SRATE_24K, - LC3_BANDWIDTH_SWB = LC3_SRATE_32K, - LC3_BANDWIDTH_FB = LC3_SRATE_48K, - - LC3_NUM_BANDWIDTH, -}; - - -/** - * Complex floating point number - */ - -struct lc3_complex -{ - float re, im; -}; - - -#endif /* __LC3_COMMON_H */ diff --git a/system/embdrv/lc3/src/energy.c b/system/embdrv/lc3/src/energy.c deleted file mode 100644 index bf86db79fbf6fb837224fe3687ffabb6300279a1..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/energy.c +++ /dev/null @@ -1,70 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "energy.h" -#include "tables.h" - - -/** - * Energy estimation per band - */ -bool lc3_energy_compute( - enum lc3_dt dt, enum lc3_srate sr, const float *x, float *e) -{ - static const int n1_table[LC3_NUM_DT][LC3_NUM_SRATE] = { - [LC3_DT_7M5] = { 56, 34, 27, 24, 22 }, - [LC3_DT_10M] = { 49, 28, 23, 20, 18 }, - }; - - /* First bands are 1 coefficient width */ - - int n1 = n1_table[dt][sr]; - float e_sum[2] = { 0, 0 }; - int iband; - - for (iband = 0; iband < n1; iband++) { - *e = x[iband] * x[iband]; - e_sum[0] += *(e++); - } - - /* Mean the square of coefficients within each band, - * note that 7.5ms 8KHz frame has more bands than samples */ - - int nb = LC3_MIN(LC3_NUM_BANDS, LC3_NS(dt, sr)); - int iband_h = nb - 2*(2 - dt); - const int *lim = lc3_band_lim[dt][sr]; - - for (int i = lim[iband]; iband < nb; iband++) { - int ie = lim[iband+1]; - int n = ie - i; - - float sx2 = x[i] * x[i]; - for (i++; i < ie; i++) - sx2 += x[i] * x[i]; - - *e = sx2 / n; - e_sum[iband >= iband_h] += *(e++); - } - - for (; iband < LC3_NUM_BANDS; iband++) - *(e++) = 0; - - /* Return the near nyquist flag */ - - return e_sum[1] > 30 * e_sum[0]; -} diff --git a/system/embdrv/lc3/src/energy.h b/system/embdrv/lc3/src/energy.h deleted file mode 100644 index 39f0124b98590408a0f831d5279dba22d24b30ac..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/energy.h +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Energy estimation per band - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_ENERGY_H -#define __LC3_ENERGY_H - -#include "common.h" - - -/** - * Energy estimation per band - * dt, sr Duration and samplerate of the frame - * x Input MDCT coefficient - * e Energy estimation per bands - * return True when high energy detected near Nyquist frequency - */ -bool lc3_energy_compute( - enum lc3_dt dt, enum lc3_srate sr, const float *x, float *e); - - -#endif /* __LC3_ENERGY_H */ diff --git a/system/embdrv/lc3/src/fastmath.h b/system/embdrv/lc3/src/fastmath.h deleted file mode 100644 index 4210f2e143594f60009de73932d1affe52c4458f..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/fastmath.h +++ /dev/null @@ -1,158 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Mathematics function approximation - */ - -#ifndef __LC3_FASTMATH_H -#define __LC3_FASTMATH_H - -#include -#include - - -/** - * Fast 2^n approximation - * x Operand, range -8 to 8 - * return 2^x approximation (max relative error ~ 7e-6) - */ -static inline float fast_exp2f(float x) -{ - float y; - - /* --- Polynomial approx in range -0.5 to 0.5 --- */ - - static const float c[] = { 1.27191277e-09, 1.47415221e-07, - 1.35510312e-05, 9.38375815e-04, 4.33216946e-02 }; - - y = ( c[0]) * x; - y = (y + c[1]) * x; - y = (y + c[2]) * x; - y = (y + c[3]) * x; - y = (y + c[4]) * x; - y = (y + 1.f); - - /* --- Raise to the power of 16 --- */ - - y = y*y; - y = y*y; - y = y*y; - y = y*y; - - return y; -} - -/** - * Fast log2(x) approximation - * x Operand, greater than 0 - * return log2(x) approximation (max absolute error ~ 1e-4) - */ -static inline float fast_log2f(float x) -{ - float y; - int e; - - /* --- Polynomial approx in range 0.5 to 1 --- */ - - static const float c[] = { - -1.29479677, 5.11769018, -8.42295281, 8.10557963, -3.50567360 }; - - x = frexpf(x, &e); - - y = ( c[0]) * x; - y = (y + c[1]) * x; - y = (y + c[2]) * x; - y = (y + c[3]) * x; - y = (y + c[4]); - - /* --- Add log2f(2^e) and return --- */ - - return e + y; -} - -/** - * Fast log10(x) approximation - * x Operand, greater than 0 - * return log10(x) approximation (max absolute error ~ 1e-4) - */ -static inline float fast_log10f(float x) -{ - return log10f(2) * fast_log2f(x); -} - -/** - * Fast `10 * log10(x)` (or dB) approximation in fixed Q16 - * x Operand, in range 2^-63 to 2^63 (1e-19 to 1e19) - * return 10 * log10(x) in fixed Q16 (-190 to 192 dB) - * - * - The 0 value is accepted and return the minimum value ~ -191dB - * - This function assumed that float 32 bits is coded IEEE 754 - */ -static inline int32_t fast_db_q16(float x) -{ - /* --- Table in Q15 --- */ - - static const uint16_t t[][2] = { - - /* [n][0] = 10 * log10(2) * log2(1 + n/32), with n = [0..15] */ - /* [n][1] = [n+1][0] - [n][0] (while defining [16][0]) */ - - { 0, 4379 }, { 4379, 4248 }, { 8627, 4125 }, { 12753, 4009 }, - { 16762, 3899 }, { 20661, 3795 }, { 24456, 3697 }, { 28153, 3603 }, - { 31755, 3514 }, { 35269, 3429 }, { 38699, 3349 }, { 42047, 3272 }, - { 45319, 3198 }, { 48517, 3128 }, { 51645, 3061 }, { 54705, 2996 }, - - /* [n][0] = 10 * log10(2) * log2(1 + n/32) - 10 * log10(2) / 2, */ - /* with n = [16..31] */ - /* [n][1] = [n+1][0] - [n][0] (while defining [32][0]) */ - - { 8381, 2934 }, { 11315, 2875 }, { 14190, 2818 }, { 17008, 2763 }, - { 19772, 2711 }, { 22482, 2660 }, { 25142, 2611 }, { 27754, 2564 }, - { 30318, 2519 }, { 32837, 2475 }, { 35312, 2433 }, { 37744, 2392 }, - { 40136, 2352 }, { 42489, 2314 }, { 44803, 2277 }, { 47080, 2241 }, - - }; - - /* --- Approximation --- - * - * 10 * log10(x^2) = 10 * log10(2) * log2(x^2) - * - * And log2(x^2) = 2 * log2( (1 + m) * 2^e ) - * = 2 * (e + log2(1 + m)) , with m in range [0..1] - * - * Split the float values in : - * e2 Double value of the exponent (2 * e + k) - * hi High 5 bits of mantissa, for precalculated result `t[hi][0]` - * lo Low 16 bits of mantissa, for linear interpolation `t[hi][1]` - * - * Two cases, from the range of the mantissa : - * 0 to 0.5 `k = 0`, use 1st part of the table - * 0.5 to 1 `k = 1`, use 2nd part of the table */ - - union { float f; uint32_t u; } x2 = { .f = x*x }; - - int e2 = (int)(x2.u >> 22) - 2*127; - int hi = (x2.u >> 18) & 0x1f; - int lo = (x2.u >> 2) & 0xffff; - - return e2 * 49321 + t[hi][0] + ((t[hi][1] * lo) >> 16); -} - - -#endif /* __LC3_FASTMATH_H */ diff --git a/system/embdrv/lc3/src/lc3.c b/system/embdrv/lc3/src/lc3.c deleted file mode 100644 index 219e381c6afe0228447e31e2e4ae0d3ec7c7c915..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/lc3.c +++ /dev/null @@ -1,603 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 - -#include "common.h" -#include "bits.h" - -#include "attdet.h" -#include "bwdet.h" -#include "ltpf.h" -#include "mdct.h" -#include "energy.h" -#include "sns.h" -#include "tns.h" -#include "spec.h" -#include "plc.h" - - -/** - * Frame side data - */ - -struct side_data { - enum lc3_bandwidth bw; - bool pitch_present; - lc3_ltpf_data_t ltpf; - lc3_sns_data_t sns; - lc3_tns_data_t tns; - lc3_spec_side_t spec; -}; - - -/* ---------------------------------------------------------------------------- - * General - * -------------------------------------------------------------------------- */ - -/** - * Resolve frame duration in us - * us Frame duration in us - * return Frame duration identifier, or LC3_NUM_DT - */ -static enum lc3_dt resolve_dt(int us) -{ - return us == 7500 ? LC3_DT_7M5 : - us == 10000 ? LC3_DT_10M : LC3_NUM_DT; -} - -/** - * Resolve samplerate in Hz - * hz Samplerate in Hz - * return Sample rate identifier, or LC3_NUM_SRATE - */ -static enum lc3_srate resolve_sr(int hz) -{ - return hz == 8000 ? LC3_SRATE_8K : hz == 16000 ? LC3_SRATE_16K : - hz == 24000 ? LC3_SRATE_24K : hz == 32000 ? LC3_SRATE_32K : - hz == 48000 ? LC3_SRATE_48K : LC3_NUM_SRATE; -} - -/** - * Return the number of PCM samples in a frame - */ -int lc3_frame_samples(int dt_us, int sr_hz) -{ - enum lc3_dt dt = resolve_dt(dt_us); - enum lc3_srate sr = resolve_sr(sr_hz); - - if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE) - return -1; - - return LC3_NS(dt, sr); -} - -/** - * Return the size of frames, from bitrate - */ -int lc3_frame_bytes(int dt_us, int bitrate) -{ - if (resolve_dt(dt_us) >= LC3_NUM_DT) - return -1; - - if (bitrate < LC3_MIN_BITRATE) - return LC3_MIN_FRAME_BYTES; - - if (bitrate > LC3_MAX_BITRATE) - return LC3_MAX_FRAME_BYTES; - - int nbytes = ((unsigned)bitrate * dt_us) / (1000*1000*8); - - return LC3_CLIP(nbytes, LC3_MIN_FRAME_BYTES, LC3_MAX_FRAME_BYTES); -} - -/** - * Resolve the bitrate, from the size of frames - */ -int lc3_resolve_bitrate(int dt_us, int nbytes) -{ - if (resolve_dt(dt_us) >= LC3_NUM_DT) - return -1; - - if (nbytes < LC3_MIN_FRAME_BYTES) - return LC3_MIN_BITRATE; - - if (nbytes > LC3_MAX_FRAME_BYTES) - return LC3_MAX_BITRATE; - - int bitrate = ((unsigned)nbytes * (1000*1000*8) + dt_us/2) / dt_us; - - return LC3_CLIP(bitrate, LC3_MIN_BITRATE, LC3_MAX_BITRATE); -} - -/** - * Return algorithmic delay, as a number of samples - */ -int lc3_delay_samples(int dt_us, int sr_hz) -{ - enum lc3_dt dt = resolve_dt(dt_us); - enum lc3_srate sr = resolve_sr(sr_hz); - - if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE) - return -1; - - return (dt == LC3_DT_7M5 ? 8 : 5) * (LC3_SRATE_KHZ(sr) / 2); -} - - -/* ---------------------------------------------------------------------------- - * Encoder - * -------------------------------------------------------------------------- */ - -/** - * Input PCM Samples from signed 16 bits - * encoder Encoder state - * pcm, stride Input PCM samples, and count between two consecutives - */ -static void load_s16( - struct lc3_encoder *encoder, const void *_pcm, int stride) -{ - const int16_t *pcm = _pcm; - - enum lc3_dt dt = encoder->dt; - enum lc3_srate sr = encoder->sr_pcm; - - int16_t *xt = encoder->xt; - float *xs = encoder->xs; - int ns = LC3_NS(dt, sr); - - for (int i = 0; i < ns; i++) { - int16_t in = pcm[i*stride]; - xt[i] = in, xs[i] = in; - } -} - -/** - * Input PCM Samples from signed 24 bits - * encoder Encoder state - * pcm, stride Input PCM samples, and count between two consecutives - */ -static void load_s24( - struct lc3_encoder *encoder, const void *_pcm, int stride) -{ - const int32_t *pcm = _pcm; - - enum lc3_dt dt = encoder->dt; - enum lc3_srate sr = encoder->sr_pcm; - - int16_t *xt = encoder->xt; - float *xs = encoder->xs; - int ns = LC3_NS(dt, sr); - - for (int i = 0; i < ns; i++) { - int32_t in = pcm[i*stride]; - - xt[i] = in >> 8; - xs[i] = ldexpf(in, -8); - } -} - -/** - * Frame Analysis - * encoder Encoder state - * nbytes Size in bytes of the frame - * side, xq Return frame data - */ -static void analyze(struct lc3_encoder *encoder, - int nbytes, struct side_data *side, uint16_t *xq) -{ - enum lc3_dt dt = encoder->dt; - enum lc3_srate sr = encoder->sr; - enum lc3_srate sr_pcm = encoder->sr_pcm; - int ns = LC3_NS(dt, sr_pcm); - int nt = LC3_NT(sr_pcm); - - int16_t *xt = encoder->xt; - float *xs = encoder->xs; - float *xd = encoder->xd; - float *xf = xs; - - /* --- Temporal --- */ - - bool att = lc3_attdet_run(dt, sr_pcm, nbytes, &encoder->attdet, xt); - - side->pitch_present = - lc3_ltpf_analyse(dt, sr_pcm, &encoder->ltpf, xt, &side->ltpf); - - memmove(xt - nt, xt + (ns-nt), nt * sizeof(*xt)); - - /* --- Spectral --- */ - - float e[LC3_NUM_BANDS]; - - lc3_mdct_forward(dt, sr_pcm, sr, xs, xd, xf); - - bool nn_flag = lc3_energy_compute(dt, sr, xf, e); - if (nn_flag) - lc3_ltpf_disable(&side->ltpf); - - side->bw = lc3_bwdet_run(dt, sr, e); - - lc3_sns_analyze(dt, sr, e, att, &side->sns, xf, xf); - - lc3_tns_analyze(dt, side->bw, nn_flag, nbytes, &side->tns, xf); - - lc3_spec_analyze(dt, sr, - nbytes, side->pitch_present, &side->tns, - &encoder->spec, xf, xq, &side->spec); -} - -/** - * Encode bitstream - * encoder Encoder state - * side, xq The frame data - * nbytes Target size of the frame (20 to 400) - * buffer Output bitstream buffer of `nbytes` size - */ -static void encode(struct lc3_encoder *encoder, - const struct side_data *side, uint16_t *xq, int nbytes, void *buffer) -{ - enum lc3_dt dt = encoder->dt; - enum lc3_srate sr = encoder->sr; - enum lc3_bandwidth bw = side->bw; - float *xf = encoder->xs; - - lc3_bits_t bits; - - lc3_setup_bits(&bits, LC3_BITS_MODE_WRITE, buffer, nbytes); - - lc3_bwdet_put_bw(&bits, sr, bw); - - lc3_spec_put_side(&bits, dt, sr, &side->spec); - - lc3_tns_put_data(&bits, &side->tns); - - lc3_put_bit(&bits, side->pitch_present); - - lc3_sns_put_data(&bits, &side->sns); - - if (side->pitch_present) - lc3_ltpf_put_data(&bits, &side->ltpf); - - lc3_spec_encode(&bits, - dt, sr, bw, nbytes, xq, &side->spec, xf); - - lc3_flush_bits(&bits); -} - -/** - * Return size needed for an encoder - */ -unsigned lc3_encoder_size(int dt_us, int sr_hz) -{ - if (resolve_dt(dt_us) >= LC3_NUM_DT || - resolve_sr(sr_hz) >= LC3_NUM_SRATE) - return 0; - - return sizeof(struct lc3_encoder) + - LC3_ENCODER_BUFFER_COUNT(dt_us, sr_hz) * sizeof(float); -} - -/** - * Setup encoder - */ -struct lc3_encoder *lc3_setup_encoder( - int dt_us, int sr_hz, int sr_pcm_hz, void *mem) -{ - if (sr_pcm_hz <= 0) - sr_pcm_hz = sr_hz; - - enum lc3_dt dt = resolve_dt(dt_us); - enum lc3_srate sr = resolve_sr(sr_hz); - enum lc3_srate sr_pcm = resolve_sr(sr_pcm_hz); - - if (dt >= LC3_NUM_DT || sr_pcm >= LC3_NUM_SRATE || sr > sr_pcm || !mem) - return NULL; - - struct lc3_encoder *encoder = mem; - int ns = LC3_NS(dt, sr_pcm); - int nt = LC3_NT(sr_pcm); - - *encoder = (struct lc3_encoder){ - .dt = dt, .sr = sr, - .sr_pcm = sr_pcm, - - .xt = (int16_t *)encoder->s + nt, - .xs = encoder->s + (nt+ns)/2, - .xd = encoder->s + (nt+ns)/2 + ns, - }; - - memset(encoder->s, 0, - LC3_ENCODER_BUFFER_COUNT(dt_us, sr_pcm_hz) * sizeof(float)); - - return encoder; -} - -/** - * Encode a frame - */ -int lc3_encode(struct lc3_encoder *encoder, enum lc3_pcm_format fmt, - const void *pcm, int stride, int nbytes, void *out) -{ - static void (* const load[])(struct lc3_encoder *, const void *, int) = { - [LC3_PCM_FORMAT_S16] = load_s16, - [LC3_PCM_FORMAT_S24] = load_s24, - }; - - /* --- Check parameters --- */ - - if (!encoder || nbytes < LC3_MIN_FRAME_BYTES - || nbytes > LC3_MAX_FRAME_BYTES) - return -1; - - /* --- Processing --- */ - - struct side_data side; - uint16_t xq[LC3_NE(encoder->dt, encoder->sr)]; - - load[fmt](encoder, pcm, stride); - - analyze(encoder, nbytes, &side, xq); - - encode(encoder, &side, xq, nbytes, out); - - return 0; -} - - -/* ---------------------------------------------------------------------------- - * Decoder - * -------------------------------------------------------------------------- */ - -/** - * Output PCM Samples to signed 16 bits - * decoder Decoder state - * pcm, stride Output PCM samples, and count between two consecutives - */ -static void store_s16( - struct lc3_decoder *decoder, void *_pcm, int stride) -{ - int16_t *pcm = _pcm; - - enum lc3_dt dt = decoder->dt; - enum lc3_srate sr = decoder->sr_pcm; - - float *xs = decoder->xs; - int ns = LC3_NS(dt, sr); - - for ( ; ns > 0; ns--, xs++, pcm += stride) { - int32_t s = *xs >= 0 ? (int)(*xs + 0.5f) : (int)(*xs - 0.5f); - *pcm = LC3_SAT16(s); - } -} - -/** - * Output PCM Samples to signed 24 bits - * decoder Decoder state - * pcm, stride Output PCM samples, and count between two consecutives - */ -static void store_s24( - struct lc3_decoder *decoder, void *_pcm, int stride) -{ - int32_t *pcm = _pcm; - - enum lc3_dt dt = decoder->dt; - enum lc3_srate sr = decoder->sr_pcm; - - float *xs = decoder->xs; - int ns = LC3_NS(dt, sr); - - for ( ; ns > 0; ns--, xs++, pcm += stride) { - int32_t s = *xs >= 0 ? (int32_t)(ldexpf(*xs, 8) + 0.5f) - : (int32_t)(ldexpf(*xs, 8) - 0.5f); - *pcm = LC3_SAT24(s); - } -} - -/** - * Decode bitstream - * decoder Decoder state - * data, nbytes Input bitstream buffer - * side Return the side data - * return 0: Ok < 0: Bitsream error detected - */ -static int decode(struct lc3_decoder *decoder, - const void *data, int nbytes, struct side_data *side) -{ - enum lc3_dt dt = decoder->dt; - enum lc3_srate sr = decoder->sr; - - float *xf = decoder->xs; - int ns = LC3_NS(dt, sr); - int ne = LC3_NE(dt, sr); - - lc3_bits_t bits; - int ret = 0; - - lc3_setup_bits(&bits, LC3_BITS_MODE_READ, (void *)data, nbytes); - - if ((ret = lc3_bwdet_get_bw(&bits, sr, &side->bw)) < 0) - return ret; - - if ((ret = lc3_spec_get_side(&bits, dt, sr, &side->spec)) < 0) - return ret; - - lc3_tns_get_data(&bits, dt, side->bw, nbytes, &side->tns); - - side->pitch_present = lc3_get_bit(&bits); - - if ((ret = lc3_sns_get_data(&bits, &side->sns)) < 0) - return ret; - - if (side->pitch_present) - lc3_ltpf_get_data(&bits, &side->ltpf); - - if ((ret = lc3_spec_decode(&bits, dt, sr, - side->bw, nbytes, &side->spec, xf)) < 0) - return ret; - - memset(xf + ne, 0, (ns - ne) * sizeof(float)); - - return lc3_check_bits(&bits); -} - -/** - * Frame synthesis - * decoder Decoder state - * side Frame data, NULL performs PLC - * nbytes Size in bytes of the frame - */ -static void synthesize(struct lc3_decoder *decoder, - const struct side_data *side, int nbytes) -{ - enum lc3_dt dt = decoder->dt; - enum lc3_srate sr = decoder->sr; - enum lc3_srate sr_pcm = decoder->sr_pcm; - - float *xf = decoder->xs; - int ns = LC3_NS(dt, sr_pcm); - int ne = LC3_NE(dt, sr); - - float *xg = decoder->xg; - float *xd = decoder->xd; - float *xs = xf; - - if (side) { - enum lc3_bandwidth bw = side->bw; - - lc3_plc_suspend(&decoder->plc); - - lc3_tns_synthesize(dt, bw, &side->tns, xf); - - lc3_sns_synthesize(dt, sr, &side->sns, xf, xg); - - lc3_mdct_inverse(dt, sr_pcm, sr, xg, xd, xs); - - } else { - lc3_plc_synthesize(dt, sr, &decoder->plc, xg, xf); - - memset(xf + ne, 0, (ns - ne) * sizeof(float)); - - lc3_mdct_inverse(dt, sr_pcm, sr, xf, xd, xs); - } - - lc3_ltpf_synthesize(dt, sr_pcm, nbytes, &decoder->ltpf, - side && side->pitch_present ? &side->ltpf : NULL, decoder->xh, xs); -} - -/** - * Update decoder state on decoding completion - * decoder Decoder state - */ -static void complete(struct lc3_decoder *decoder) -{ - enum lc3_dt dt = decoder->dt; - enum lc3_srate sr_pcm = decoder->sr_pcm; - int nh = LC3_NH(dt, sr_pcm); - int ns = LC3_NS(dt, sr_pcm); - - decoder->xs = decoder->xs - decoder->xh < nh - ns ? - decoder->xs + ns : decoder->xh; -} - -/** - * Return size needed for a decoder - */ -unsigned lc3_decoder_size(int dt_us, int sr_hz) -{ - if (resolve_dt(dt_us) >= LC3_NUM_DT || - resolve_sr(sr_hz) >= LC3_NUM_SRATE) - return 0; - - return sizeof(struct lc3_decoder) + - LC3_DECODER_BUFFER_COUNT(dt_us, sr_hz) * sizeof(float); -} - -/** - * Setup decoder - */ -struct lc3_decoder *lc3_setup_decoder( - int dt_us, int sr_hz, int sr_pcm_hz, void *mem) -{ - if (sr_pcm_hz <= 0) - sr_pcm_hz = sr_hz; - - enum lc3_dt dt = resolve_dt(dt_us); - enum lc3_srate sr = resolve_sr(sr_hz); - enum lc3_srate sr_pcm = resolve_sr(sr_pcm_hz); - - if (dt >= LC3_NUM_DT || sr_pcm >= LC3_NUM_SRATE || sr > sr_pcm || !mem) - return NULL; - - struct lc3_decoder *decoder = mem; - int nh = LC3_NH(dt, sr_pcm); - int ns = LC3_NS(dt, sr_pcm); - int nd = LC3_ND(dt, sr_pcm); - - *decoder = (struct lc3_decoder){ - .dt = dt, .sr = sr, - .sr_pcm = sr_pcm, - - .xh = decoder->s, - .xs = decoder->s + nh-ns, - .xd = decoder->s + nh, - .xg = decoder->s + nh+nd, - }; - - lc3_plc_reset(&decoder->plc); - - memset(decoder->s, 0, - LC3_DECODER_BUFFER_COUNT(dt_us, sr_pcm_hz) * sizeof(float)); - - return decoder; -} - -/** - * Decode a frame - */ -int lc3_decode(struct lc3_decoder *decoder, const void *in, int nbytes, - enum lc3_pcm_format fmt, void *pcm, int stride) -{ - static void (* const store[])(struct lc3_decoder *, void *, int) = { - [LC3_PCM_FORMAT_S16] = store_s16, - [LC3_PCM_FORMAT_S24] = store_s24, - }; - - /* --- Check parameters --- */ - - if (!decoder) - return -1; - - if (in && (nbytes < LC3_MIN_FRAME_BYTES || - nbytes > LC3_MAX_FRAME_BYTES )) - return -1; - - /* --- Processing --- */ - - struct side_data side; - - int ret = !in || (decode(decoder, in, nbytes, &side) < 0); - - synthesize(decoder, ret ? NULL : &side, nbytes); - - store[fmt](decoder, pcm, stride); - - complete(decoder); - - return ret; -} diff --git a/system/embdrv/lc3/src/ltpf.c b/system/embdrv/lc3/src/ltpf.c deleted file mode 100644 index 3d13c2031f839e1958e72694be87d17cd0fcadf4..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/ltpf.c +++ /dev/null @@ -1,893 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "ltpf.h" -#include "tables.h" - -#include "ltpf_neon.h" -#include "ltpf_arm.h" - - -/* ---------------------------------------------------------------------------- - * Resampling - * -------------------------------------------------------------------------- */ - -/** - * Resampling coefficients - * The coefficients, in fixed Q15, are reordered by phase for each source - * samplerate (coefficient matrix transposed) - */ - -#ifndef resample_8k_12k8 -static const int16_t h_8k_12k8_q15[8*10] = { - 214, 417, -1052, -4529, 26233, -4529, -1052, 417, 214, 0, - 180, 0, -1522, -2427, 24506, -5289, 0, 763, 156, -28, - 92, -323, -1361, 0, 19741, -3885, 1317, 861, 0, -61, - 0, -457, -752, 1873, 13068, 0, 2389, 598, -213, -79, - -61, -398, 0, 2686, 5997, 5997, 2686, 0, -398, -61, - -79, -213, 598, 2389, 0, 13068, 1873, -752, -457, 0, - -61, 0, 861, 1317, -3885, 19741, 0, -1361, -323, 92, - -28, 156, 763, 0, -5289, 24506, -2427, -1522, 0, 180, -}; -#endif /* resample_8k_12k8 */ - -#ifndef resample_16k_12k8 -static const int16_t h_16k_12k8_q15[4*20] = { - -61, 214, -398, 417, 0, -1052, 2686, -4529, 5997, 26233, - 5997, -4529, 2686, -1052, 0, 417, -398, 214, -61, 0, - - -79, 180, -213, 0, 598, -1522, 2389, -2427, 0, 24506, - 13068, -5289, 1873, 0, -752, 763, -457, 156, 0, -28, - - -61, 92, 0, -323, 861, -1361, 1317, 0, -3885, 19741, - 19741, -3885, 0, 1317, -1361, 861, -323, 0, 92, -61, - - -28, 0, 156, -457, 763, -752, 0, 1873, -5289, 13068, - 24506, 0, -2427, 2389, -1522, 598, 0, -213, 180, -79, -}; -#endif /* resample_16k_12k8 */ - -#ifndef resample_32k_12k8 -static const int16_t h_32k_12k8_q15[2*40] = { - -30, -31, 46, 107, 0, -199, -162, 209, 430, 0, - -681, -526, 658, 1343, 0, -2264, -1943, 2999, 9871, 13116, - 9871, 2999, -1943, -2264, 0, 1343, 658, -526, -681, 0, - 430, 209, -162, -199, 0, 107, 46, -31, -30, 0, - - -14, -39, 0, 90, 78, -106, -229, 0, 382, 299, - -376, -761, 0, 1194, 937, -1214, -2644, 0, 6534, 12253, - 12253, 6534, 0, -2644, -1214, 937, 1194, 0, -761, -376, - 299, 382, 0, -229, -106, 78, 90, 0, -39, -14, -}; -#endif /* resample_32k_12k8 */ - -#ifndef resample_24k_12k8 -static const int16_t h_24k_12k8_q15[8*30] = { - -50, 19, 143, -93, -290, 278, 485, -658, -701, 1396, - 901, -3019, -1042, 10276, 17488, 10276, -1042, -3019, 901, 1396, - -701, -658, 485, 278, -290, -93, 143, 19, -50, 0, - - -46, 0, 141, -45, -305, 185, 543, -501, -854, 1153, - 1249, -2619, -1908, 8712, 17358, 11772, 0, -3319, 480, 1593, - -504, -796, 399, 367, -261, -142, 138, 40, -52, -5, - - -41, -17, 133, 0, -304, 91, 574, -334, -959, 878, - 1516, -2143, -2590, 7118, 16971, 13161, 1202, -3495, 0, 1731, - -267, -908, 287, 445, -215, -188, 125, 62, -52, -12, - - -34, -30, 120, 41, -291, 0, 577, -164, -1015, 585, - 1697, -1618, -3084, 5534, 16337, 14406, 2544, -3526, -523, 1800, - 0, -985, 152, 509, -156, -230, 104, 83, -48, -19, - - -26, -41, 103, 76, -265, -83, 554, 0, -1023, 288, - 1791, -1070, -3393, 3998, 15474, 15474, 3998, -3393, -1070, 1791, - 288, -1023, 0, 554, -83, -265, 76, 103, -41, -26, - - -19, -48, 83, 104, -230, -156, 509, 152, -985, 0, - 1800, -523, -3526, 2544, 14406, 16337, 5534, -3084, -1618, 1697, - 585, -1015, -164, 577, 0, -291, 41, 120, -30, -34, - - -12, -52, 62, 125, -188, -215, 445, 287, -908, -267, - 1731, 0, -3495, 1202, 13161, 16971, 7118, -2590, -2143, 1516, - 878, -959, -334, 574, 91, -304, 0, 133, -17, -41, - - -5, -52, 40, 138, -142, -261, 367, 399, -796, -504, - 1593, 480, -3319, 0, 11772, 17358, 8712, -1908, -2619, 1249, - 1153, -854, -501, 543, 185, -305, -45, 141, 0, -46, -}; -#endif /* resample_24k_12k8 */ - -#ifndef resample_48k_12k8 -static const int16_t h_48k_12k8_q15[4*60] = { - -13, -25, -20, 10, 51, 71, 38, -47, -133, -145, - -42, 139, 277, 242, 0, -329, -511, -351, 144, 698, - 895, 450, -535, -1510, -1697, -521, 1999, 5138, 7737, 8744, - 7737, 5138, 1999, -521, -1697, -1510, -535, 450, 895, 698, - 144, -351, -511, -329, 0, 242, 277, 139, -42, -145, - -133, -47, 38, 71, 51, 10, -20, -25, -13, 0, - - -9, -23, -24, 0, 41, 71, 52, -23, -115, -152, - -78, 92, 254, 272, 76, -251, -493, -427, 0, 576, - 900, 624, -262, -1309, -1763, -954, 1272, 4356, 7203, 8679, - 8169, 5886, 2767, 0, -1542, -1660, -809, 240, 848, 796, - 292, -252, -507, -398, -82, 199, 288, 183, 0, -130, - -145, -71, 20, 69, 60, 20, -15, -26, -17, -3, - - -6, -20, -26, -8, 31, 67, 62, 0, -94, -152, - -108, 45, 223, 287, 143, -167, -454, -480, -134, 439, - 866, 758, 0, -1071, -1748, -1295, 601, 3559, 6580, 8485, - 8485, 6580, 3559, 601, -1295, -1748, -1071, 0, 758, 866, - 439, -134, -480, -454, -167, 143, 287, 223, 45, -108, - -152, -94, 0, 62, 67, 31, -8, -26, -20, -6, - - -3, -17, -26, -15, 20, 60, 69, 20, -71, -145, - -130, 0, 183, 288, 199, -82, -398, -507, -252, 292, - 796, 848, 240, -809, -1660, -1542, 0, 2767, 5886, 8169, - 8679, 7203, 4356, 1272, -954, -1763, -1309, -262, 624, 900, - 576, 0, -427, -493, -251, 76, 272, 254, 92, -78, - -152, -115, -23, 52, 71, 41, 0, -24, -23, -9, -}; -#endif /* resample_48k_12k8 */ - - -/** - * High-pass 50Hz filtering, at 12.8 KHz samplerate - * hp50 Biquad filter state - * xn Input sample, in fixed Q30 - * return Filtered sample, in fixed Q30 - */ -LC3_HOT static inline int32_t filter_hp50( - struct lc3_ltpf_hp50_state *hp50, int32_t xn) -{ - int32_t yn; - - const int32_t a1 = -2110217691, a2 = 1037111617; - const int32_t b1 = -2110535566, b2 = 1055267782; - - yn = (hp50->s1 + (int64_t)xn * b2) >> 30; - hp50->s1 = (hp50->s2 + (int64_t)xn * b1 - (int64_t)yn * a1); - hp50->s2 = ( (int64_t)xn * b2 - (int64_t)yn * a2); - - return yn; -} - -/** - * Resample from 8 / 16 / 32 KHz to 12.8 KHz Template - * p Resampling factor with compared to 192 KHz (8, 4 or 2) - * h Arrange by phase coefficients table - * hp50 High-Pass biquad filter state - * x [-d..-1] Previous, [0..ns-1] Current samples, Q15 - * y, n [0..n-1] Output `n` processed samples, Q14 - * - * The `x` vector is aligned on 32 bits - * The number of previous samples `d` accessed on `x` is : - * d: { 10, 20, 40 } - 1 for resampling factors 8, 4 and 2. - */ -#if !defined(resample_8k_12k8) || !defined(resample_16k_12k8) \ - || !defined(resample_32k_12k8) -LC3_HOT static inline void resample_x64k_12k8(const int p, const int16_t *h, - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - const int w = 2*(40 / p); - - x -= w - 1; - - for (int i = 0; i < 5*n; i += 5) { - const int16_t *hn = h + (i % p) * w; - const int16_t *xn = x + (i / p); - int32_t un = 0; - - for (int k = 0; k < w; k += 10) { - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - } - - int32_t yn = filter_hp50(hp50, un); - *(y++) = (yn + (1 << 15)) >> 16; - } -} -#endif - -/** - * Resample from 24 / 48 KHz to 12.8 KHz Template - * p Resampling factor with compared to 192 KHz (8 or 4) - * h Arrange by phase coefficients table - * hp50 High-Pass biquad filter state - * x [-d..-1] Previous, [0..ns-1] Current samples, Q15 - * y, n [0..n-1] Output `n` processed samples, Q14 - * - * The `x` vector is aligned on 32 bits - * The number of previous samples `d` accessed on `x` is : - * d: { 30, 60 } - 1 for resampling factors 8 and 4. - */ -#if !defined(resample_24k_12k8) || !defined(resample_48k_12k8) -LC3_HOT static inline void resample_x192k_12k8(const int p, const int16_t *h, - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - const int w = 2*(120 / p); - - x -= w - 1; - - for (int i = 0; i < 15*n; i += 15) { - const int16_t *hn = h + (i % p) * w; - const int16_t *xn = x + (i / p); - int32_t un = 0; - - for (int k = 0; k < w; k += 15) { - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - un += *(xn++) * *(hn++); - } - - int32_t yn = filter_hp50(hp50, un); - *(y++) = (yn + (1 << 15)) >> 16; - } -} -#endif - -/** - * Resample from 8 Khz to 12.8 KHz - * hp50 High-Pass biquad filter state - * x [-10..-1] Previous, [0..ns-1] Current samples, Q15 - * y, n [0..n-1] Output `n` processed samples, Q14 - * - * The `x` vector is aligned on 32 bits - */ -#ifndef resample_8k_12k8 -LC3_HOT static void resample_8k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - resample_x64k_12k8(8, h_8k_12k8_q15, hp50, x, y, n); -} -#endif /* resample_8k_12k8 */ - -/** - * Resample from 16 Khz to 12.8 KHz - * hp50 High-Pass biquad filter state - * x [-20..-1] Previous, [0..ns-1] Current samples, in fixed Q15 - * y, n [0..n-1] Output `n` processed samples, in fixed Q14 - * - * The `x` vector is aligned on 32 bits - */ -#ifndef resample_16k_12k8 -LC3_HOT static void resample_16k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - resample_x64k_12k8(4, h_16k_12k8_q15, hp50, x, y, n); -} -#endif /* resample_16k_12k8 */ - -/** - * Resample from 32 Khz to 12.8 KHz - * hp50 High-Pass biquad filter state - * x [-30..-1] Previous, [0..ns-1] Current samples, in fixed Q15 - * y, n [0..n-1] Output `n` processed samples, in fixed Q14 - * - * The `x` vector is aligned on 32 bits - */ -#ifndef resample_32k_12k8 -LC3_HOT static void resample_32k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - resample_x64k_12k8(2, h_32k_12k8_q15, hp50, x, y, n); -} -#endif /* resample_32k_12k8 */ - -/** - * Resample from 24 Khz to 12.8 KHz - * hp50 High-Pass biquad filter state - * x [-30..-1] Previous, [0..ns-1] Current samples, in fixed Q15 - * y, n [0..n-1] Output `n` processed samples, in fixed Q14 - * - * The `x` vector is aligned on 32 bits - */ -#ifndef resample_24k_12k8 -LC3_HOT static void resample_24k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - resample_x192k_12k8(8, h_24k_12k8_q15, hp50, x, y, n); -} -#endif /* resample_24k_12k8 */ - -/** - * Resample from 48 Khz to 12.8 KHz - * hp50 High-Pass biquad filter state - * x [-60..-1] Previous, [0..ns-1] Current samples, in fixed Q15 - * y, n [0..n-1] Output `n` processed samples, in fixed Q14 - * -* The `x` vector is aligned on 32 bits -*/ -#ifndef resample_48k_12k8 -LC3_HOT static void resample_48k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - resample_x192k_12k8(4, h_48k_12k8_q15, hp50, x, y, n); -} -#endif /* resample_48k_12k8 */ - -/** -* Resample to 6.4 KHz -* x [-3..-1] Previous, [0..n-1] Current samples -* y, n [0..n-1] Output `n` processed samples -* -* The `x` vector is aligned on 32 bits - */ -#ifndef resample_6k4 -LC3_HOT static void resample_6k4(const int16_t *x, int16_t *y, int n) -{ - static const int16_t h[] = { 18477, 15424, 8105 }; - const int16_t *ye = y + n; - - for (x--; y < ye; x += 2) - *(y++) = (x[0] * h[0] + (x[-1] + x[1]) * h[1] - + (x[-2] + x[2]) * h[2]) >> 16; -} -#endif /* resample_6k4 */ - -/** - * LTPF Resample to 12.8 KHz implementations for each samplerates - */ - -static void (* const resample_12k8[]) - (struct lc3_ltpf_hp50_state *, const int16_t *, int16_t *, int ) = -{ - [LC3_SRATE_8K ] = resample_8k_12k8, - [LC3_SRATE_16K] = resample_16k_12k8, - [LC3_SRATE_24K] = resample_24k_12k8, - [LC3_SRATE_32K] = resample_32k_12k8, - [LC3_SRATE_48K] = resample_48k_12k8, -}; - - -/* ---------------------------------------------------------------------------- - * Analysis - * -------------------------------------------------------------------------- */ - -/** - * Return dot product of 2 vectors - * a, b, n The 2 vectors of size `n` (> 0 and <= 128) - * return sum( a[i] * b[i] ), i = [0..n-1] - * - * The size `n` of vectors must be multiple of 16, and less or equal to 128 -*/ -#ifndef dot -LC3_HOT static inline float dot(const int16_t *a, const int16_t *b, int n) -{ - int64_t v = 0; - - for (int i = 0; i < (n >> 4); i++) - for (int j = 0; j < 16; j++) - v += *(a++) * *(b++); - - int32_t v32 = (v + (1 << 5)) >> 6; - return (float)v32; -} -#endif /* dot */ - -/** - * Return vector of correlations - * a, b, n The 2 vector of size `n` (> 0 and <= 128) - * y, nc Output the correlation vector of size `nc` - * - * The first vector `a` is aligned of 32 bits - * The size `n` of vectors is multiple of 16, and less or equal to 128 - */ -#ifndef correlate -LC3_HOT static void correlate( - const int16_t *a, const int16_t *b, int n, float *y, int nc) -{ - for (const float *ye = y + nc; y < ye; ) - *(y++) = dot(a, b--, n); -} -#endif /* correlate */ - -/** - * Search the maximum value and returns its argument - * x, n The input vector of size `n` - * x_max Return the maximum value - * return Return the argument of the maximum - */ -LC3_HOT static int argmax(const float *x, int n, float *x_max) -{ - int arg = 0; - - *x_max = x[arg = 0]; - for (int i = 1; i < n; i++) - if (*x_max < x[i]) - *x_max = x[arg = i]; - - return arg; -} - -/** - * Search the maximum weithed value and returns its argument - * x, n The input vector of size `n` - * w_incr Increment of the weight - * x_max, xw_max Return the maximum not weighted value - * return Return the argument of the weigthed maximum - */ -LC3_HOT static int argmax_weighted( - const float *x, int n, float w_incr, float *x_max) -{ - int arg; - - float xw_max = (*x_max = x[arg = 0]); - float w = 1 + w_incr; - - for (int i = 1; i < n; i++, w += w_incr) - if (xw_max < x[i] * w) - xw_max = (*x_max = x[arg = i]) * w; - - return arg; -} - -/** - * Interpolate from pitch detected value (3.3.9.8) - * x, n [-2..-1] Previous, [0..n] Current input - * d The phase of interpolation (0 to 3) - * return The interpolated vector - * - * The size `n` of vectors must be multiple of 4 - */ -LC3_HOT static void interpolate(const int16_t *x, int n, int d, int16_t *y) -{ - static const int16_t h4_q15[][4] = { - { 6877, 19121, 6877, 0 }, { 3506, 18025, 11000, 220 }, - { 1300, 15048, 15048, 1300 }, { 220, 11000, 18025, 3506 } }; - - const int16_t *h = h4_q15[d]; - int16_t x3 = x[-2], x2 = x[-1], x1, x0; - - x1 = (*x++); - for (const int16_t *ye = y + n; y < ye; ) { - int32_t yn; - - yn = (x0 = *(x++)) * h[0] + x1 * h[1] + x2 * h[2] + x3 * h[3]; - *(y++) = yn >> 15; - - yn = (x3 = *(x++)) * h[0] + x0 * h[1] + x1 * h[2] + x2 * h[3]; - *(y++) = yn >> 15; - - yn = (x2 = *(x++)) * h[0] + x3 * h[1] + x0 * h[2] + x1 * h[3]; - *(y++) = yn >> 15; - - yn = (x1 = *(x++)) * h[0] + x2 * h[1] + x3 * h[2] + x0 * h[3]; - *(y++) = yn >> 15; - } -} - -/** - * Interpolate autocorrelation (3.3.9.7) - * x [-4..-1] Previous, [0..4] Current input - * d The phase of interpolation (-3 to 3) - * return The interpolated value - */ -LC3_HOT static float interpolate_corr(const float *x, int d) -{ - static const float h4[][8] = { - { 1.53572770e-02, -4.72963246e-02, 8.35788573e-02, 8.98638285e-01, - 8.35788573e-02, -4.72963246e-02, 1.53572770e-02, }, - { 2.74547165e-03, 4.59833449e-03, -7.54404636e-02, 8.17488686e-01, - 3.30182571e-01, -1.05835916e-01, 2.86823405e-02, -2.87456116e-03 }, - { -3.00125103e-03, 2.95038503e-02, -1.30305021e-01, 6.03297008e-01, - 6.03297008e-01, -1.30305021e-01, 2.95038503e-02, -3.00125103e-03 }, - { -2.87456116e-03, 2.86823405e-02, -1.05835916e-01, 3.30182571e-01, - 8.17488686e-01, -7.54404636e-02, 4.59833449e-03, 2.74547165e-03 }, - }; - - const float *h = h4[(4+d) % 4]; - - float y = d < 0 ? x[-4] * *(h++) : - d > 0 ? x[ 4] * *(h+7) : 0; - - y += x[-3] * h[0] + x[-2] * h[1] + x[-1] * h[2] + x[0] * h[3] + - x[ 1] * h[4] + x[ 2] * h[5] + x[ 3] * h[6]; - - return y; -} - -/** - * Pitch detection algorithm (3.3.9.5-6) - * ltpf Context of analysis - * x, n [-114..-17] Previous, [0..n-1] Current 6.4KHz samples - * tc Return the pitch-lag estimation - * return True when pitch present - * - * The `x` vector is aligned on 32 bits - */ -static bool detect_pitch( - struct lc3_ltpf_analysis *ltpf, const int16_t *x, int n, int *tc) -{ - float rm1, rm2; - float r[98]; - - const int r0 = 17, nr = 98; - int k0 = LC3_MAX( 0, ltpf->tc-4); - int nk = LC3_MIN(nr-1, ltpf->tc+4) - k0 + 1; - - correlate(x, x - r0, n, r, nr); - - int t1 = argmax_weighted(r, nr, -.5f/(nr-1), &rm1); - int t2 = k0 + argmax(r + k0, nk, &rm2); - - const int16_t *x1 = x - (r0 + t1); - const int16_t *x2 = x - (r0 + t2); - - float nc1 = rm1 <= 0 ? 0 : - rm1 / sqrtf(dot(x, x, n) * dot(x1, x1, n)); - - float nc2 = rm2 <= 0 ? 0 : - rm2 / sqrtf(dot(x, x, n) * dot(x2, x2, n)); - - int t1sel = nc2 <= 0.85f * nc1; - ltpf->tc = (t1sel ? t1 : t2); - - *tc = r0 + ltpf->tc; - return (t1sel ? nc1 : nc2) > 0.6f; -} - -/** - * Pitch-lag parameter (3.3.9.7) - * x, n [-232..-28] Previous, [0..n-1] Current 12.8KHz samples, Q14 - * tc Pitch-lag estimation - * pitch The pitch value, in fixed .4 - * return The bitstream pitch index value - * - * The `x` vector is aligned on 32 bits - */ -static int refine_pitch(const int16_t *x, int n, int tc, int *pitch) -{ - float r[17], rm; - int e, f; - - int r0 = LC3_MAX( 32, 2*tc - 4); - int nr = LC3_MIN(228, 2*tc + 4) - r0 + 1; - - correlate(x, x - (r0 - 4), n, r, nr + 8); - - e = r0 + argmax(r + 4, nr, &rm); - const float *re = r + (e - (r0 - 4)); - - float dm = interpolate_corr(re, f = 0); - for (int i = 1; i <= 3; i++) { - float d; - - if (e >= 127 && ((i & 1) | (e >= 157))) - continue; - - if ((d = interpolate_corr(re, i)) > dm) - dm = d, f = i; - - if (e > 32 && (d = interpolate_corr(re, -i)) > dm) - dm = d, f = -i; - } - - e -= (f < 0); - f += 4*(f < 0); - - *pitch = 4*e + f; - return e < 127 ? 4*e + f - 128 : - e < 157 ? 2*e + (f >> 1) + 126 : e + 283; -} - -/** - * LTPF Analysis - */ -bool lc3_ltpf_analyse( - enum lc3_dt dt, enum lc3_srate sr, struct lc3_ltpf_analysis *ltpf, - const int16_t *x, struct lc3_ltpf_data *data) -{ - /* --- Resampling to 12.8 KHz --- */ - - int z_12k8 = sizeof(ltpf->x_12k8) / sizeof(*ltpf->x_12k8); - int n_12k8 = dt == LC3_DT_7M5 ? 96 : 128; - - memmove(ltpf->x_12k8, ltpf->x_12k8 + n_12k8, - (z_12k8 - n_12k8) * sizeof(*ltpf->x_12k8)); - - int16_t *x_12k8 = ltpf->x_12k8 + (z_12k8 - n_12k8); - - resample_12k8[sr](<pf->hp50, x, x_12k8, n_12k8); - - x_12k8 -= (dt == LC3_DT_7M5 ? 44 : 24); - - /* --- Resampling to 6.4 KHz --- */ - - int z_6k4 = sizeof(ltpf->x_6k4) / sizeof(*ltpf->x_6k4); - int n_6k4 = n_12k8 >> 1; - - memmove(ltpf->x_6k4, ltpf->x_6k4 + n_6k4, - (z_6k4 - n_6k4) * sizeof(*ltpf->x_6k4)); - - int16_t *x_6k4 = ltpf->x_6k4 + (z_6k4 - n_6k4); - - resample_6k4(x_12k8, x_6k4, n_6k4); - - /* --- Pitch detection --- */ - - int tc, pitch = 0; - float nc = 0; - - bool pitch_present = detect_pitch(ltpf, x_6k4, n_6k4, &tc); - - if (pitch_present) { - int16_t u[n_12k8], v[n_12k8]; - - data->pitch_index = refine_pitch(x_12k8, n_12k8, tc, &pitch); - - interpolate(x_12k8, n_12k8, 0, u); - interpolate(x_12k8 - (pitch >> 2), n_12k8, pitch & 3, v); - - nc = dot(u, v, n_12k8) / sqrtf(dot(u, u, n_12k8) * dot(v, v, n_12k8)); - } - - /* --- Activation --- */ - - if (ltpf->active) { - int pitch_diff = - LC3_MAX(pitch, ltpf->pitch) - LC3_MIN(pitch, ltpf->pitch); - float nc_diff = nc - ltpf->nc[0]; - - data->active = pitch_present && - ((nc > 0.9f) || (nc > 0.84f && pitch_diff < 8 && nc_diff > -0.1f)); - - } else { - data->active = pitch_present && - ( (dt == LC3_DT_10M || ltpf->nc[1] > 0.94f) && - (ltpf->nc[0] > 0.94f && nc > 0.94f) ); - } - - ltpf->active = data->active; - ltpf->pitch = pitch; - ltpf->nc[1] = ltpf->nc[0]; - ltpf->nc[0] = nc; - - return pitch_present; -} - - -/* ---------------------------------------------------------------------------- - * Synthesis - * -------------------------------------------------------------------------- */ - -/** - * Synthesis filter template - * xh, nh History ring buffer of filtered samples - * lag Lag parameter in the ring buffer - * x0 w-1 previous input samples - * x, n Current samples as input, filtered as output - * c, w Coefficients `den` then `num`, and width of filter - * fade Fading mode of filter -1: Out 1: In 0: None - */ -LC3_HOT static inline void synthesize_template( - const float *xh, int nh, int lag, - const float *x0, float *x, int n, - const float *c, const int w, int fade) -{ - float g = (float)(fade <= 0); - float g_incr = (float)((fade > 0) - (fade < 0)) / n; - float u[w]; - - /* --- Load previous samples --- */ - - lag += (w >> 1); - - const float *y = x - xh < lag ? x + (nh - lag) : x - lag; - const float *y_end = xh + nh - 1; - - for (int j = 0; j < w-1; j++) { - - u[j] = 0; - - float yi = *y, xi = *(x0++); - y = y < y_end ? y + 1 : xh; - - for (int k = 0; k <= j; k++) - u[j-k] -= yi * c[k]; - - for (int k = 0; k <= j; k++) - u[j-k] += xi * c[w+k]; - } - - u[w-1] = 0; - - /* --- Process by filter length --- */ - - for (int i = 0; i < n; i += w) - for (int j = 0; j < w; j++, g += g_incr) { - - float yi = *y, xi = *x; - y = y < y_end ? y + 1 : xh; - - for (int k = 0; k < w; k++) - u[(j+(w-1)-k)%w] -= yi * c[k]; - - for (int k = 0; k < w; k++) - u[(j+(w-1)-k)%w] += xi * c[w+k]; - - *(x++) = xi - g * u[j]; - u[j] = 0; - } -} - -/** - * Synthesis filter for each samplerates (width of filter) - */ - -LC3_HOT static void synthesize_4(const float *xh, int nh, int lag, - const float *x0, float *x, int n, const float *c, int fade) -{ - synthesize_template(xh, nh, lag, x0, x, n, c, 4, fade); -} - -LC3_HOT static void synthesize_6(const float *xh, int nh, int lag, - const float *x0, float *x, int n, const float *c, int fade) -{ - synthesize_template(xh, nh, lag, x0, x, n, c, 6, fade); -} - -LC3_HOT static void synthesize_8(const float *xh, int nh, int lag, - const float *x0, float *x, int n, const float *c, int fade) -{ - synthesize_template(xh, nh, lag, x0, x, n, c, 8, fade); -} - -LC3_HOT static void synthesize_12(const float *xh, int nh, int lag, - const float *x0, float *x, int n, const float *c, int fade) -{ - synthesize_template(xh, nh, lag, x0, x, n, c, 12, fade); -} - -static void (* const synthesize[])(const float *, int, int, - const float *, float *, int, const float *, int) = -{ - [LC3_SRATE_8K ] = synthesize_4, - [LC3_SRATE_16K] = synthesize_4, - [LC3_SRATE_24K] = synthesize_6, - [LC3_SRATE_32K] = synthesize_8, - [LC3_SRATE_48K] = synthesize_12, -}; - - -/** - * LTPF Synthesis - */ -void lc3_ltpf_synthesize(enum lc3_dt dt, enum lc3_srate sr, int nbytes, - lc3_ltpf_synthesis_t *ltpf, const lc3_ltpf_data_t *data, - const float *xh, float *x) -{ - int nh = LC3_NH(dt, sr); - int dt_us = LC3_DT_US(dt); - - /* --- Filter parameters --- */ - - int p_idx = data ? data->pitch_index : 0; - int pitch = - p_idx >= 440 ? (((p_idx ) - 283) << 2) : - p_idx >= 380 ? (((p_idx >> 1) - 63) << 2) + (((p_idx & 1)) << 1) : - (((p_idx >> 2) + 32) << 2) + (((p_idx & 3)) << 0) ; - - pitch = (pitch * LC3_SRATE_KHZ(sr) * 10 + 64) / 128; - - int nbits = (nbytes*8 * 10000 + (dt_us/2)) / dt_us; - int g_idx = LC3_MAX(nbits / 80, 3 + (int)sr) - (3 + sr); - bool active = data && data->active && g_idx < 4; - - int w = LC3_MAX(4, LC3_SRATE_KHZ(sr) / 4); - float c[2*w]; - - for (int i = 0; i < w; i++) { - float g = active ? 0.4f - 0.05f * g_idx : 0; - c[ i] = g * lc3_ltpf_cden[sr][pitch & 3][(w-1)-i]; - c[w+i] = 0.85f * g * lc3_ltpf_cnum[sr][LC3_MIN(g_idx, 3)][(w-1)-i]; - } - - /* --- Transition handling --- */ - - int ns = LC3_NS(dt, sr); - int nt = ns / (3 + dt); - float x0[w]; - - if (active) - memcpy(x0, x + nt-(w-1), (w-1) * sizeof(float)); - - if (!ltpf->active && active) - synthesize[sr](xh, nh, pitch/4, ltpf->x, x, nt, c, 1); - else if (ltpf->active && !active) - synthesize[sr](xh, nh, ltpf->pitch/4, ltpf->x, x, nt, ltpf->c, -1); - else if (ltpf->active && active && ltpf->pitch == pitch) - synthesize[sr](xh, nh, pitch/4, ltpf->x, x, nt, c, 0); - else if (ltpf->active && active) { - synthesize[sr](xh, nh, ltpf->pitch/4, ltpf->x, x, nt, ltpf->c, -1); - synthesize[sr](xh, nh, pitch/4, - (x <= xh ? x + nh : x) - (w-1), x, nt, c, 1); - } - - /* --- Remainder --- */ - - memcpy(ltpf->x, x + ns - (w-1), (w-1) * sizeof(float)); - - if (active) - synthesize[sr](xh, nh, pitch/4, x0, x + nt, ns-nt, c, 0); - - /* --- Update state --- */ - - ltpf->active = active; - ltpf->pitch = pitch; - memcpy(ltpf->c, c, 2*w * sizeof(*ltpf->c)); -} - - -/* ---------------------------------------------------------------------------- - * Bitstream data - * -------------------------------------------------------------------------- */ - -/** - * LTPF disable - */ -void lc3_ltpf_disable(struct lc3_ltpf_data *data) -{ - data->active = false; -} - -/** - * Return number of bits coding the bitstream data - */ -int lc3_ltpf_get_nbits(bool pitch) -{ - return 1 + 10 * pitch; -} - -/** - * Put bitstream data - */ -void lc3_ltpf_put_data(lc3_bits_t *bits, - const struct lc3_ltpf_data *data) -{ - lc3_put_bit(bits, data->active); - lc3_put_bits(bits, data->pitch_index, 9); -} - -/** - * Get bitstream data - */ -void lc3_ltpf_get_data(lc3_bits_t *bits, struct lc3_ltpf_data *data) -{ - data->active = lc3_get_bit(bits); - data->pitch_index = lc3_get_bits(bits, 9); -} diff --git a/system/embdrv/lc3/src/ltpf.h b/system/embdrv/lc3/src/ltpf.h deleted file mode 100644 index 0d5bb3c9bb9a4623442a707fa85f8a7c14ac9787..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/ltpf.h +++ /dev/null @@ -1,111 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Long Term Postfilter - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_LTPF_H -#define __LC3_LTPF_H - -#include "common.h" -#include "bits.h" - - -/** - * LTPF data - */ - -typedef struct lc3_ltpf_data { - bool active; - int pitch_index; -} lc3_ltpf_data_t; - - -/* ---------------------------------------------------------------------------- - * Encoding - * -------------------------------------------------------------------------- */ - -/** - * LTPF analysis - * dt, sr Duration and samplerate of the frame - * ltpf Context of analysis - * allowed True when activation of LTPF is allowed - * x [-d..-1] Previous, [0..ns-1] Current samples - * data Return bitstream data - * return True when pitch present, False otherwise - * - * The `x` vector is aligned on 32 bits - * The number of previous samples `d` accessed on `x` is : - * d: { 10, 20, 30, 40, 60 } - 1 for samplerates from 8KHz to 48KHz - */ -bool lc3_ltpf_analyse(enum lc3_dt dt, enum lc3_srate sr, - lc3_ltpf_analysis_t *ltpf, const int16_t *x, lc3_ltpf_data_t *data); - -/** - * LTPF disable - * data LTPF data, disabled activation on return - */ -void lc3_ltpf_disable(lc3_ltpf_data_t *data); - -/** - * Return number of bits coding the bitstream data - * pitch True when pitch present, False otherwise - * return Bit consumption, including the pitch present flag - */ -int lc3_ltpf_get_nbits(bool pitch); - -/** - * Put bitstream data - * bits Bitstream context - * data LTPF data - */ -void lc3_ltpf_put_data(lc3_bits_t *bits, const lc3_ltpf_data_t *data); - - -/* ---------------------------------------------------------------------------- - * Decoding - * -------------------------------------------------------------------------- */ -/** - * Get bitstream data - * bits Bitstream context - * data Return bitstream data - */ -void lc3_ltpf_get_data(lc3_bits_t *bits, lc3_ltpf_data_t *data); - -/** - * LTPF synthesis - * dt, sr Duration and samplerate of the frame - * nbytes Size in bytes of the frame - * ltpf Context of synthesis - * data Bitstream data, NULL when pitch not present - * xr Base address of ring buffer of decoded samples - * x Samples to proceed in the ring buffer, filtered as output - * - * The size of the ring buffer is `nh + ns`. - * The filtering needs an history of at least 18 ms. - */ -void lc3_ltpf_synthesize(enum lc3_dt dt, enum lc3_srate sr, int nbytes, - lc3_ltpf_synthesis_t *ltpf, const lc3_ltpf_data_t *data, - const float *xr, float *x); - - -#endif /* __LC3_LTPF_H */ diff --git a/system/embdrv/lc3/src/ltpf_arm.h b/system/embdrv/lc3/src/ltpf_arm.h deleted file mode 100644 index a812b3cde1d2f2d4f07ac43b15c16c7d47f12858..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/ltpf_arm.h +++ /dev/null @@ -1,476 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -#if __ARM_FEATURE_SIMD32 - -#ifndef TEST_ARM - -#include - -static inline int16x2_t __pkhbt(int16x2_t a, int16x2_t b) -{ - int16x2_t r; - __asm("pkhbt %0, %1, %2" : "=r" (r) : "r" (a), "r" (b)); - return r; -} - -#endif /* TEST_ARM */ - - -/** - * Import - */ - -static inline int32_t filter_hp50(struct lc3_ltpf_hp50_state *, int32_t); -static inline float dot(const int16_t *, const int16_t *, int); - - -/** - * Resample from 8 / 16 / 32 KHz to 12.8 KHz Template - */ -#if !defined(resample_8k_12k8) || !defined(resample_16k_12k8) \ - || !defined(resample_32k_12k8) -static inline void arm_resample_x64k_12k8(const int p, const int16x2_t *h, - struct lc3_ltpf_hp50_state *hp50, const int16x2_t *x, int16_t *y, int n) -{ - const int w = 40 / p; - - x -= w; - - for (int i = 0; i < 5*n; i += 5) { - const int16x2_t *hn = h + (i % (2*p)) * (48 / p); - const int16x2_t *xn = x + (i / (2*p)); - - int32_t un = __smlad(*(xn++), *(hn++), 0); - - for (int k = 0; k < w; k += 5) { - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - } - - int32_t yn = filter_hp50(hp50, un); - *(y++) = (yn + (1 << 15)) >> 16; - } -} -#endif - -/** - * Resample from 24 / 48 KHz to 12.8 KHz Template - */ -#if !defined(resample_24k_12k8) || !defined(resample_48k_12k8) -static inline void arm_resample_x192k_12k8(const int p, const int16x2_t *h, - struct lc3_ltpf_hp50_state *hp50, const int16x2_t *x, int16_t *y, int n) -{ - const int w = 120 / p; - - x -= w; - - for (int i = 0; i < 15*n; i += 15) { - const int16x2_t *hn = h + (i % (2*p)) * (128 / p); - const int16x2_t *xn = x + (i / (2*p)); - - int32_t un = __smlad(*(xn++), *(hn++), 0); - - for (int k = 0; k < w; k += 15) { - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - un = __smlad(*(xn++), *(hn++), un); - } - - int32_t yn = filter_hp50(hp50, un); - *(y++) = (yn + (1 << 15)) >> 16; - } -} -#endif - -/** - * Resample from 8 Khz to 12.8 KHz - */ -#ifndef resample_8k_12k8 -#define resample_8k_12k8 arm_resample_8k_12k8 -static void arm_resample_8k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - static const int16_t alignas(int32_t) h[2*8*12] = { - 0, 214, 417, -1052, -4529, 26233, -4529, -1052, 417, 214, 0, 0, - 0, 180, 0, -1522, -2427, 24506, -5289, 0, 763, 156, -28, 0, - 0, 92, -323, -1361, 0, 19741, -3885, 1317, 861, 0, -61, 0, - 0, 0, -457, -752, 1873, 13068, 0, 2389, 598, -213, -79, 0, - 0, -61, -398, 0, 2686, 5997, 5997, 2686, 0, -398, -61, 0, - 0, -79, -213, 598, 2389, 0, 13068, 1873, -752, -457, 0, 0, - 0, -61, 0, 861, 1317, -3885, 19741, 0, -1361, -323, 92, 0, - 0, -28, 156, 763, 0, -5289, 24506, -2427, -1522, 0, 180, 0, - 0, 0, 214, 417, -1052, -4529, 26233, -4529, -1052, 417, 214, 0, - 0, 0, 180, 0, -1522, -2427, 24506, -5289, 0, 763, 156, -28, - 0, 0, 92, -323, -1361, 0, 19741, -3885, 1317, 861, 0, -61, - 0, 0, 0, -457, -752, 1873, 13068, 0, 2389, 598, -213, -79, - 0, 0, -61, -398, 0, 2686, 5997, 5997, 2686, 0, -398, -61, - 0, 0, -79, -213, 598, 2389, 0, 13068, 1873, -752, -457, 0, - 0, 0, -61, 0, 861, 1317, -3885, 19741, 0, -1361, -323, 92, - 0, 0, -28, 156, 763, 0, -5289, 24506, -2427, -1522, 0, 180, - }; - - arm_resample_x64k_12k8( - 8, (const int16x2_t *)h, hp50, (int16x2_t *)x, y, n); -} -#endif /* resample_8k_12k8 */ - -/** - * Resample from 16 Khz to 12.8 KHz - */ -#ifndef resample_16k_12k8 -#define resample_16k_12k8 arm_resample_16k_12k8 -static void arm_resample_16k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - static const int16_t alignas(int32_t) h[2*4*24] = { - - 0, -61, 214, -398, 417, 0, -1052, 2686, - -4529, 5997, 26233, 5997, -4529, 2686, -1052, 0, - 417, -398, 214, -61, 0, 0, 0, 0, - - - 0, -79, 180, -213, 0, 598, -1522, 2389, - -2427, 0, 24506, 13068, -5289, 1873, 0, -752, - 763, -457, 156, 0, -28, 0, 0, 0, - - - 0, -61, 92, 0, -323, 861, -1361, 1317, - 0, -3885, 19741, 19741, -3885, 0, 1317, -1361, - 861, -323, 0, 92, -61, 0, 0, 0, - - 0, -28, 0, 156, -457, 763, -752, 0, - 1873, -5289, 13068, 24506, 0, -2427, 2389, -1522, - 598, 0, -213, 180, -79, 0, 0, 0, - - - 0, 0, -61, 214, -398, 417, 0, -1052, - 2686, -4529, 5997, 26233, 5997, -4529, 2686, -1052, - 0, 417, -398, 214, -61, 0, 0, 0, - - - 0, 0, -79, 180, -213, 0, 598, -1522, - 2389, -2427, 0, 24506, 13068, -5289, 1873, 0, - -752, 763, -457, 156, 0, -28, 0, 0, - - - 0, 0, -61, 92, 0, -323, 861, -1361, - 1317, 0, -3885, 19741, 19741, -3885, 0, 1317, - -1361, 861, -323, 0, 92, -61, 0, 0, - - 0, 0, -28, 0, 156, -457, 763, -752, - 0, 1873, -5289, 13068, 24506, 0, -2427, 2389, - -1522, 598, 0, -213, 180, -79, 0, 0, - }; - - arm_resample_x64k_12k8( - 4, (const int16x2_t *)h, hp50, (int16x2_t *)x, y, n); -} -#endif /* resample_16k_12k8 */ - -/** - * Resample from 32 Khz to 12.8 KHz - */ -#ifndef resample_32k_12k8 -#define resample_32k_12k8 arm_resample_32k_12k8 -static void arm_resample_32k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - static const int16_t alignas(int32_t) h[2*2*48] = { - - 0, -30, -31, 46, 107, 0, -199, -162, - 209, 430, 0, -681, -526, 658, 1343, 0, - -2264, -1943, 2999, 9871, 13116, 9871, 2999, -1943, - -2264, 0, 1343, 658, -526, -681, 0, 430, - 209, -162, -199, 0, 107, 46, -31, -30, - 0, 0, 0, 0, 0, 0, 0, 0, - - 0, -14, -39, 0, 90, 78, -106, -229, - 0, 382, 299, -376, -761, 0, 1194, 937, - -1214, -2644, 0, 6534, 12253, 12253, 6534, 0, - -2644, -1214, 937, 1194, 0, -761, -376, 299, - 382, 0, -229, -106, 78, 90, 0, -39, - -14, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, -30, -31, 46, 107, 0, -199, - -162, 209, 430, 0, -681, -526, 658, 1343, - 0, -2264, -1943, 2999, 9871, 13116, 9871, 2999, - -1943, -2264, 0, 1343, 658, -526, -681, 0, - 430, 209, -162, -199, 0, 107, 46, -31, - -30, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, -14, -39, 0, 90, 78, -106, - -229, 0, 382, 299, -376, -761, 0, 1194, - 937, -1214, -2644, 0, 6534, 12253, 12253, 6534, - 0, -2644, -1214, 937, 1194, 0, -761, -376, - 299, 382, 0, -229, -106, 78, 90, 0, - -39, -14, 0, 0, 0, 0, 0, 0, - }; - - arm_resample_x64k_12k8( - 2, (const int16x2_t *)h, hp50, (int16x2_t *)x, y, n); -} -#endif /* resample_32k_12k8 */ - -/** - * Resample from 24 Khz to 12.8 KHz - */ -#ifndef resample_24k_12k8 -#define resample_24k_12k8 arm_resample_24k_12k8 -static void arm_resample_24k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - static const int16_t alignas(int32_t) h[2*8*32] = { - - 0, -50, 19, 143, -93, -290, 278, 485, - -658, -701, 1396, 901, -3019, -1042, 10276, 17488, - 10276, -1042, -3019, 901, 1396, -701, -658, 485, - 278, -290, -93, 143, 19, -50, 0, 0, - - 0, -46, 0, 141, -45, -305, 185, 543, - -501, -854, 1153, 1249, -2619, -1908, 8712, 17358, - 11772, 0, -3319, 480, 1593, -504, -796, 399, - 367, -261, -142, 138, 40, -52, -5, 0, - - 0, -41, -17, 133, 0, -304, 91, 574, - -334, -959, 878, 1516, -2143, -2590, 7118, 16971, - 13161, 1202, -3495, 0, 1731, -267, -908, 287, - 445, -215, -188, 125, 62, -52, -12, 0, - - 0, -34, -30, 120, 41, -291, 0, 577, - -164, -1015, 585, 1697, -1618, -3084, 5534, 16337, - 14406, 2544, -3526, -523, 1800, 0, -985, 152, - 509, -156, -230, 104, 83, -48, -19, 0, - - 0, -26, -41, 103, 76, -265, -83, 554, - 0, -1023, 288, 1791, -1070, -3393, 3998, 15474, - 15474, 3998, -3393, -1070, 1791, 288, -1023, 0, - 554, -83, -265, 76, 103, -41, -26, 0, - - 0, -19, -48, 83, 104, -230, -156, 509, - 152, -985, 0, 1800, -523, -3526, 2544, 14406, - 16337, 5534, -3084, -1618, 1697, 585, -1015, -164, - 577, 0, -291, 41, 120, -30, -34, 0, - - 0, -12, -52, 62, 125, -188, -215, 445, - 287, -908, -267, 1731, 0, -3495, 1202, 13161, - 16971, 7118, -2590, -2143, 1516, 878, -959, -334, - 574, 91, -304, 0, 133, -17, -41, 0, - - 0, -5, -52, 40, 138, -142, -261, 367, - 399, -796, -504, 1593, 480, -3319, 0, 11772, - 17358, 8712, -1908, -2619, 1249, 1153, -854, -501, - 543, 185, -305, -45, 141, 0, -46, 0, - - 0, 0, -50, 19, 143, -93, -290, 278, - 485, -658, -701, 1396, 901, -3019, -1042, 10276, - 17488, 10276, -1042, -3019, 901, 1396, -701, -658, - 485, 278, -290, -93, 143, 19, -50, 0, - - 0, 0, -46, 0, 141, -45, -305, 185, - 543, -501, -854, 1153, 1249, -2619, -1908, 8712, - 17358, 11772, 0, -3319, 480, 1593, -504, -796, - 399, 367, -261, -142, 138, 40, -52, -5, - - 0, 0, -41, -17, 133, 0, -304, 91, - 574, -334, -959, 878, 1516, -2143, -2590, 7118, - 16971, 13161, 1202, -3495, 0, 1731, -267, -908, - 287, 445, -215, -188, 125, 62, -52, -12, - - 0, 0, -34, -30, 120, 41, -291, 0, - 577, -164, -1015, 585, 1697, -1618, -3084, 5534, - 16337, 14406, 2544, -3526, -523, 1800, 0, -985, - 152, 509, -156, -230, 104, 83, -48, -19, - - 0, 0, -26, -41, 103, 76, -265, -83, - 554, 0, -1023, 288, 1791, -1070, -3393, 3998, - 15474, 15474, 3998, -3393, -1070, 1791, 288, -1023, - 0, 554, -83, -265, 76, 103, -41, -26, - - 0, 0, -19, -48, 83, 104, -230, -156, - 509, 152, -985, 0, 1800, -523, -3526, 2544, - 14406, 16337, 5534, -3084, -1618, 1697, 585, -1015, - -164, 577, 0, -291, 41, 120, -30, -34, - - 0, 0, -12, -52, 62, 125, -188, -215, - 445, 287, -908, -267, 1731, 0, -3495, 1202, - 13161, 16971, 7118, -2590, -2143, 1516, 878, -959, - -334, 574, 91, -304, 0, 133, -17, -41, - - 0, 0, -5, -52, 40, 138, -142, -261, - 367, 399, -796, -504, 1593, 480, -3319, 0, - 11772, 17358, 8712, -1908, -2619, 1249, 1153, -854, - -501, 543, 185, -305, -45, 141, 0, -46, - }; - - arm_resample_x192k_12k8( - 8, (const int16x2_t *)h, hp50, (int16x2_t *)x, y, n); -} -#endif /* resample_24k_12k8 */ - -/** - * Resample from 48 Khz to 12.8 KHz - */ -#ifndef resample_48k_12k8 -#define resample_48k_12k8 arm_resample_48k_12k8 -static void arm_resample_48k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - static const int16_t alignas(int32_t) h[2*4*64] = { - - 0, -13, -25, -20, 10, 51, 71, 38, - -47, -133, -145, -42, 139, 277, 242, 0, - -329, -511, -351, 144, 698, 895, 450, -535, - -1510, -1697, -521, 1999, 5138, 7737, 8744, 7737, - 5138, 1999, -521, -1697, -1510, -535, 450, 895, - 698, 144, -351, -511, -329, 0, 242, 277, - 139, -42, -145, -133, -47, 38, 71, 51, - 10, -20, -25, -13, 0, 0, 0, 0, - - 0, -9, -23, -24, 0, 41, 71, 52, - -23, -115, -152, -78, 92, 254, 272, 76, - -251, -493, -427, 0, 576, 900, 624, -262, - -1309, -1763, -954, 1272, 4356, 7203, 8679, 8169, - 5886, 2767, 0, -1542, -1660, -809, 240, 848, - 796, 292, -252, -507, -398, -82, 199, 288, - 183, 0, -130, -145, -71, 20, 69, 60, - 20, -15, -26, -17, -3, 0, 0, 0, - - 0, -6, -20, -26, -8, 31, 67, 62, - 0, -94, -152, -108, 45, 223, 287, 143, - -167, -454, -480, -134, 439, 866, 758, 0, - -1071, -1748, -1295, 601, 3559, 6580, 8485, 8485, - 6580, 3559, 601, -1295, -1748, -1071, 0, 758, - 866, 439, -134, -480, -454, -167, 143, 287, - 223, 45, -108, -152, -94, 0, 62, 67, - 31, -8, -26, -20, -6, 0, 0, 0, - - 0, -3, -17, -26, -15, 20, 60, 69, - 20, -71, -145, -130, 0, 183, 288, 199, - -82, -398, -507, -252, 292, 796, 848, 240, - -809, -1660, -1542, 0, 2767, 5886, 8169, 8679, - 7203, 4356, 1272, -954, -1763, -1309, -262, 624, - 900, 576, 0, -427, -493, -251, 76, 272, - 254, 92, -78, -152, -115, -23, 52, 71, - 41, 0, -24, -23, -9, 0, 0, 0, - - 0, 0, -13, -25, -20, 10, 51, 71, - 38, -47, -133, -145, -42, 139, 277, 242, - 0, -329, -511, -351, 144, 698, 895, 450, - -535, -1510, -1697, -521, 1999, 5138, 7737, 8744, - 7737, 5138, 1999, -521, -1697, -1510, -535, 450, - 895, 698, 144, -351, -511, -329, 0, 242, - 277, 139, -42, -145, -133, -47, 38, 71, - 51, 10, -20, -25, -13, 0, 0, 0, - - 0, 0, -9, -23, -24, 0, 41, 71, - 52, -23, -115, -152, -78, 92, 254, 272, - 76, -251, -493, -427, 0, 576, 900, 624, - -262, -1309, -1763, -954, 1272, 4356, 7203, 8679, - 8169, 5886, 2767, 0, -1542, -1660, -809, 240, - 848, 796, 292, -252, -507, -398, -82, 199, - 288, 183, 0, -130, -145, -71, 20, 69, - 60, 20, -15, -26, -17, -3, 0, 0, - - 0, 0, -6, -20, -26, -8, 31, 67, - 62, 0, -94, -152, -108, 45, 223, 287, - 143, -167, -454, -480, -134, 439, 866, 758, - 0, -1071, -1748, -1295, 601, 3559, 6580, 8485, - 8485, 6580, 3559, 601, -1295, -1748, -1071, 0, - 758, 866, 439, -134, -480, -454, -167, 143, - 287, 223, 45, -108, -152, -94, 0, 62, - 67, 31, -8, -26, -20, -6, 0, 0, - - 0, 0, -3, -17, -26, -15, 20, 60, - 69, 20, -71, -145, -130, 0, 183, 288, - 199, -82, -398, -507, -252, 292, 796, 848, - 240, -809, -1660, -1542, 0, 2767, 5886, 8169, - 8679, 7203, 4356, 1272, -954, -1763, -1309, -262, - 624, 900, 576, 0, -427, -493, -251, 76, - 272, 254, 92, -78, -152, -115, -23, 52, - 71, 41, 0, -24, -23, -9, 0, 0, - }; - - arm_resample_x192k_12k8( - 4, (const int16x2_t *)h, hp50, (int16x2_t *)x, y, n); -} -#endif /* resample_48k_12k8 */ - -/** - * Return vector of correlations - */ -#ifndef correlate -#define correlate arm_correlate -static void arm_correlate( - const int16_t *a, const int16_t *b, int n, float *y, int nc) -{ - /* --- Check alignment of `b` --- */ - - if ((uintptr_t)b & 3) - *(y++) = dot(a, b--, n), nc--; - - /* --- Processing by pair --- */ - - for ( ; nc >= 2; nc -= 2) { - const int16x2_t *an = (const int16x2_t *)(a ); - const int16x2_t *bn = (const int16x2_t *)(b--); - - int16x2_t ax, b0, b1; - int64_t v0 = 0, v1 = 0; - - b1 = (int16x2_t)*(b--) << 16; - - for (int i = 0; i < (n >> 4); i++ ) - for (int j = 0; j < 4; j++) { - - ax = *(an++), b0 = *(bn++); - v0 = __smlald (ax, b0, v0); - v1 = __smlaldx(ax, __pkhbt(b0, b1), v1); - - ax = *(an++), b1 = *(bn++); - v0 = __smlald (ax, b1, v0); - v1 = __smlaldx(ax, __pkhbt(b1, b0), v1); - } - - *(y++) = (float)((int32_t)((v0 + (1 << 5)) >> 6)); - *(y++) = (float)((int32_t)((v1 + (1 << 5)) >> 6)); - } - - /* --- Odd element count --- */ - - if (nc > 0) - *(y++) = dot(a, b, n); -} -#endif /* correlate */ - -#endif /* __ARM_FEATURE_SIMD32 */ diff --git a/system/embdrv/lc3/src/ltpf_neon.h b/system/embdrv/lc3/src/ltpf_neon.h deleted file mode 100644 index 240b8c79edd953d2b9d6003f4d69e44225a56cf0..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/ltpf_neon.h +++ /dev/null @@ -1,256 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -#if __ARM_NEON && __ARM_ARCH_ISA_A64 - -#ifndef TEST_NEON -#include -#endif /* TEST_NEON */ - - -/** - * Import - */ - -static inline int32_t filter_hp50(struct lc3_ltpf_hp50_state *, int32_t); - - -/** - * Resample from 16 Khz to 12.8 KHz - */ -#ifndef resample_16k_12k8 -#define resample_16k_12k8 neon_resample_16k_12k8 -LC3_HOT static void neon_resample_16k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - static const int16_t h[4][20] = { - - { -61, 214, -398, 417, 0, -1052, 2686, -4529, 5997, 26233, - 5997, -4529, 2686, -1052, 0, 417, -398, 214, -61, 0 }, - - { -79, 180, -213, 0, 598, -1522, 2389, -2427, 0, 24506, - 13068, -5289, 1873, 0, -752, 763, -457, 156, 0, -28 }, - - { -61, 92, 0, -323, 861, -1361, 1317, 0, -3885, 19741, - 19741, -3885, 0, 1317, -1361, 861, -323, 0, 92, -61 }, - - { -28, 0, 156, -457, 763, -752, 0, 1873, -5289, 13068, - 24506, 0, -2427, 2389, -1522, 598, 0, -213, 180, -79 }, - - }; - - x -= 20 - 1; - - for (int i = 0; i < 5*n; i += 5) { - const int16_t *hn = h[i & 3]; - const int16_t *xn = x + (i >> 2); - int32x4_t un; - - un = vmull_s16( vld1_s16(xn), vld1_s16(hn)), xn += 4, hn += 4; - un = vmlal_s16(un, vld1_s16(xn), vld1_s16(hn)), xn += 4, hn += 4; - un = vmlal_s16(un, vld1_s16(xn), vld1_s16(hn)), xn += 4, hn += 4; - un = vmlal_s16(un, vld1_s16(xn), vld1_s16(hn)), xn += 4, hn += 4; - un = vmlal_s16(un, vld1_s16(xn), vld1_s16(hn)), xn += 4, hn += 4; - - int32_t yn = filter_hp50(hp50, vaddvq_s32(un)); - *(y++) = (yn + (1 << 15)) >> 16; - } -} -#endif /* resample_16k_12k8 */ - -/** - * Resample from 32 Khz to 12.8 KHz - */ -#ifndef resample_32k_12k8 -#define resample_32k_12k8 neon_resample_32k_12k8 -LC3_HOT static void neon_resample_32k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - x -= 40 - 1; - - static const int16_t h[2][40] = { - - { -30, -31, 46, 107, 0, -199, -162, 209, 430, 0, - -681, -526, 658, 1343, 0, -2264, -1943, 2999, 9871, 13116, - 9871, 2999, -1943, -2264, 0, 1343, 658, -526, -681, 0, - 430, 209, -162, -199, 0, 107, 46, -31, -30, 0 }, - - { -14, -39, 0, 90, 78, -106, -229, 0, 382, 299, - -376, -761, 0, 1194, 937, -1214, -2644, 0, 6534, 12253, - 12253, 6534, 0, -2644, -1214, 937, 1194, 0, -761, -376, - 299, 382, 0, -229, -106, 78, 90, 0, -39, -14 }, - - }; - - for (int i = 0; i < 5*n; i += 5) { - const int16_t *hn = h[i & 1]; - const int16_t *xn = x + (i >> 1); - - int32x4_t un = vmull_s16(vld1_s16(xn), vld1_s16(hn)); - xn += 4, hn += 4; - - for (int i = 1; i < 10; i++) - un = vmlal_s16(un, vld1_s16(xn), vld1_s16(hn)), xn += 4, hn += 4; - - int32_t yn = filter_hp50(hp50, vaddvq_s32(un)); - *(y++) = (yn + (1 << 15)) >> 16; - } -} -#endif /* resample_32k_12k8 */ - -/** - * Resample from 48 Khz to 12.8 KHz - */ -#ifndef resample_48k_12k8 -#define resample_48k_12k8 neon_resample_48k_12k8 -LC3_HOT static void neon_resample_48k_12k8( - struct lc3_ltpf_hp50_state *hp50, const int16_t *x, int16_t *y, int n) -{ - static const int16_t alignas(16) h[4][64] = { - - { -13, -25, -20, 10, 51, 71, 38, -47, -133, -145, - -42, 139, 277, 242, 0, -329, -511, -351, 144, 698, - 895, 450, -535, -1510, -1697, -521, 1999, 5138, 7737, 8744, - 7737, 5138, 1999, -521, -1697, -1510, -535, 450, 895, 698, - 144, -351, -511, -329, 0, 242, 277, 139, -42, -145, - -133, -47, 38, 71, 51, 10, -20, -25, -13, 0 }, - - { -9, -23, -24, 0, 41, 71, 52, -23, -115, -152, - -78, 92, 254, 272, 76, -251, -493, -427, 0, 576, - 900, 624, -262, -1309, -1763, -954, 1272, 4356, 7203, 8679, - 8169, 5886, 2767, 0, -1542, -1660, -809, 240, 848, 796, - 292, -252, -507, -398, -82, 199, 288, 183, 0, -130, - -145, -71, 20, 69, 60, 20, -15, -26, -17, -3 }, - - { -6, -20, -26, -8, 31, 67, 62, 0, -94, -152, - -108, 45, 223, 287, 143, -167, -454, -480, -134, 439, - 866, 758, 0, -1071, -1748, -1295, 601, 3559, 6580, 8485, - 8485, 6580, 3559, 601, -1295, -1748, -1071, 0, 758, 866, - 439, -134, -480, -454, -167, 143, 287, 223, 45, -108, - -152, -94, 0, 62, 67, 31, -8, -26, -20, -6 }, - - { -3, -17, -26, -15, 20, 60, 69, 20, -71, -145, - -130, 0, 183, 288, 199, -82, -398, -507, -252, 292, - 796, 848, 240, -809, -1660, -1542, 0, 2767, 5886, 8169, - 8679, 7203, 4356, 1272, -954, -1763, -1309, -262, 624, 900, - 576, 0, -427, -493, -251, 76, 272, 254, 92, -78, - -152, -115, -23, 52, 71, 41, 0, -24, -23, -9 }, - - }; - - x -= 60 - 1; - - for (int i = 0; i < 15*n; i += 15) { - const int16_t *hn = h[i & 3]; - const int16_t *xn = x + (i >> 2); - - int32x4_t un = vmull_s16(vld1_s16(xn), vld1_s16(hn)); - xn += 4, hn += 4; - - for (int i = 1; i < 15; i++) - un = vmlal_s16(un, vld1_s16(xn), vld1_s16(hn)), xn += 4, hn += 4; - - int32_t yn = filter_hp50(hp50, vaddvq_s32(un)); - *(y++) = (yn + (1 << 15)) >> 16; - } -} -#endif /* resample_48k_12k8 */ - -/** - * Return dot product of 2 vectors - */ -#ifndef dot -#define dot neon_dot -LC3_HOT static inline float neon_dot(const int16_t *a, const int16_t *b, int n) -{ - int64x2_t v = vmovq_n_s64(0); - - for (int i = 0; i < (n >> 4); i++) { - int32x4_t u; - - u = vmull_s16( vld1_s16(a), vld1_s16(b)), a += 4, b += 4; - u = vmlal_s16(u, vld1_s16(a), vld1_s16(b)), a += 4, b += 4; - v = vpadalq_s32(v, u); - - u = vmull_s16( vld1_s16(a), vld1_s16(b)), a += 4, b += 4; - u = vmlal_s16(u, vld1_s16(a), vld1_s16(b)), a += 4, b += 4; - v = vpadalq_s32(v, u); - } - - int32_t v32 = (vaddvq_s64(v) + (1 << 5)) >> 6; - return (float)v32; -} -#endif /* dot */ - -/** - * Return vector of correlations - */ -#ifndef correlate -#define correlate neon_correlate -LC3_HOT static void neon_correlate( - const int16_t *a, const int16_t *b, int n, float *y, int nc) -{ - for ( ; nc >= 4; nc -= 4, b -= 4) { - const int16_t *an = (const int16_t *)a; - const int16_t *bn = (const int16_t *)b; - - int64x2_t v0 = vmovq_n_s64(0), v1 = v0, v2 = v0, v3 = v0; - int16x4_t ax, b0, b1; - - b0 = vld1_s16(bn-4); - - for (int i=0; i < (n >> 4); i++ ) - for (int j = 0; j < 2; j++) { - int32x4_t u0, u1, u2, u3; - - b1 = b0; - b0 = vld1_s16(bn), bn += 4; - ax = vld1_s16(an), an += 4; - - u0 = vmull_s16(ax, b0); - u1 = vmull_s16(ax, vext_s16(b1, b0, 3)); - u2 = vmull_s16(ax, vext_s16(b1, b0, 2)); - u3 = vmull_s16(ax, vext_s16(b1, b0, 1)); - - b1 = b0; - b0 = vld1_s16(bn), bn += 4; - ax = vld1_s16(an), an += 4; - - u0 = vmlal_s16(u0, ax, b0); - u1 = vmlal_s16(u1, ax, vext_s16(b1, b0, 3)); - u2 = vmlal_s16(u2, ax, vext_s16(b1, b0, 2)); - u3 = vmlal_s16(u3, ax, vext_s16(b1, b0, 1)); - - v0 = vpadalq_s32(v0, u0); - v1 = vpadalq_s32(v1, u1); - v2 = vpadalq_s32(v2, u2); - v3 = vpadalq_s32(v3, u3); - } - - *(y++) = (float)((int32_t)((vaddvq_s64(v0) + (1 << 5)) >> 6)); - *(y++) = (float)((int32_t)((vaddvq_s64(v1) + (1 << 5)) >> 6)); - *(y++) = (float)((int32_t)((vaddvq_s64(v2) + (1 << 5)) >> 6)); - *(y++) = (float)((int32_t)((vaddvq_s64(v3) + (1 << 5)) >> 6)); - } - - for ( ; nc > 0; nc--) - *(y++) = neon_dot(a, b--, n); -} -#endif /* correlate */ - -#endif /* __ARM_NEON && __ARM_ARCH_ISA_A64 */ diff --git a/system/embdrv/lc3/src/mdct.c b/system/embdrv/lc3/src/mdct.c deleted file mode 100644 index 58c7d78e52301949947888d7246ead9b8a7276cb..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/mdct.c +++ /dev/null @@ -1,451 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "tables.h" - -#include "mdct_neon.h" - - -/* ---------------------------------------------------------------------------- - * FFT processing - * -------------------------------------------------------------------------- */ - -/** - * FFT 5 Points - * x, y Input and output coefficients, of size 5xn - * n Number of interleaved transform to perform (n % 2 = 0) - */ -#ifndef fft_5 -LC3_HOT static inline void fft_5( - const struct lc3_complex *x, struct lc3_complex *y, int n) -{ - static const float cos1 = 0.3090169944; /* cos(-2Pi 1/5) */ - static const float cos2 = -0.8090169944; /* cos(-2Pi 2/5) */ - - static const float sin1 = -0.9510565163; /* sin(-2Pi 1/5) */ - static const float sin2 = -0.5877852523; /* sin(-2Pi 2/5) */ - - for (int i = 0; i < n; i++, x++, y+= 5) { - - struct lc3_complex s14 = - { x[1*n].re + x[4*n].re, x[1*n].im + x[4*n].im }; - struct lc3_complex d14 = - { x[1*n].re - x[4*n].re, x[1*n].im - x[4*n].im }; - - struct lc3_complex s23 = - { x[2*n].re + x[3*n].re, x[2*n].im + x[3*n].im }; - struct lc3_complex d23 = - { x[2*n].re - x[3*n].re, x[2*n].im - x[3*n].im }; - - y[0].re = x[0].re + s14.re + s23.re; - - y[0].im = x[0].im + s14.im + s23.im; - - y[1].re = x[0].re + s14.re * cos1 - d14.im * sin1 - + s23.re * cos2 - d23.im * sin2; - - y[1].im = x[0].im + s14.im * cos1 + d14.re * sin1 - + s23.im * cos2 + d23.re * sin2; - - y[2].re = x[0].re + s14.re * cos2 - d14.im * sin2 - + s23.re * cos1 + d23.im * sin1; - - y[2].im = x[0].im + s14.im * cos2 + d14.re * sin2 - + s23.im * cos1 - d23.re * sin1; - - y[3].re = x[0].re + s14.re * cos2 + d14.im * sin2 - + s23.re * cos1 - d23.im * sin1; - - y[3].im = x[0].im + s14.im * cos2 - d14.re * sin2 - + s23.im * cos1 + d23.re * sin1; - - y[4].re = x[0].re + s14.re * cos1 + d14.im * sin1 - + s23.re * cos2 + d23.im * sin2; - - y[4].im = x[0].im + s14.im * cos1 - d14.re * sin1 - + s23.im * cos2 - d23.re * sin2; - } -} -#endif /* fft_5 */ - -/** - * FFT Butterfly 3 Points - * x, y Input and output coefficients - * twiddles Twiddles factors, determine size of transform - * n Number of interleaved transforms - */ -#ifndef fft_bf3 -LC3_HOT static inline void fft_bf3( - const struct lc3_fft_bf3_twiddles *twiddles, - const struct lc3_complex *x, struct lc3_complex *y, int n) -{ - int n3 = twiddles->n3; - const struct lc3_complex (*w0)[2] = twiddles->t; - const struct lc3_complex (*w1)[2] = w0 + n3, (*w2)[2] = w1 + n3; - - const struct lc3_complex *x0 = x, *x1 = x0 + n*n3, *x2 = x1 + n*n3; - struct lc3_complex *y0 = y, *y1 = y0 + n3, *y2 = y1 + n3; - - for (int i = 0; i < n; i++, y0 += 3*n3, y1 += 3*n3, y2 += 3*n3) - for (int j = 0; j < n3; j++, x0++, x1++, x2++) { - - y0[j].re = x0->re + x1->re * w0[j][0].re - x1->im * w0[j][0].im - + x2->re * w0[j][1].re - x2->im * w0[j][1].im; - - y0[j].im = x0->im + x1->im * w0[j][0].re + x1->re * w0[j][0].im - + x2->im * w0[j][1].re + x2->re * w0[j][1].im; - - y1[j].re = x0->re + x1->re * w1[j][0].re - x1->im * w1[j][0].im - + x2->re * w1[j][1].re - x2->im * w1[j][1].im; - - y1[j].im = x0->im + x1->im * w1[j][0].re + x1->re * w1[j][0].im - + x2->im * w1[j][1].re + x2->re * w1[j][1].im; - - y2[j].re = x0->re + x1->re * w2[j][0].re - x1->im * w2[j][0].im - + x2->re * w2[j][1].re - x2->im * w2[j][1].im; - - y2[j].im = x0->im + x1->im * w2[j][0].re + x1->re * w2[j][0].im - + x2->im * w2[j][1].re + x2->re * w2[j][1].im; - } -} -#endif /* fft_bf3 */ - -/** - * FFT Butterfly 2 Points - * twiddles Twiddles factors, determine size of transform - * x, y Input and output coefficients - * n Number of interleaved transforms - */ -#ifndef fft_bf2 -LC3_HOT static inline void fft_bf2( - const struct lc3_fft_bf2_twiddles *twiddles, - const struct lc3_complex *x, struct lc3_complex *y, int n) -{ - int n2 = twiddles->n2; - const struct lc3_complex *w = twiddles->t; - - const struct lc3_complex *x0 = x, *x1 = x0 + n*n2; - struct lc3_complex *y0 = y, *y1 = y0 + n2; - - for (int i = 0; i < n; i++, y0 += 2*n2, y1 += 2*n2) { - - for (int j = 0; j < n2; j++, x0++, x1++) { - - y0[j].re = x0->re + x1->re * w[j].re - x1->im * w[j].im; - y0[j].im = x0->im + x1->im * w[j].re + x1->re * w[j].im; - - y1[j].re = x0->re - x1->re * w[j].re + x1->im * w[j].im; - y1[j].im = x0->im - x1->im * w[j].re - x1->re * w[j].im; - } - } -} -#endif /* fft_bf2 */ - -/** - * Perform FFT - * x, y0, y1 Input, and 2 scratch buffers of size `n` - * n Number of points 30, 40, 60, 80, 90, 120, 160, 180, 240 - * return The buffer `y0` or `y1` that hold the result - * - * Input `x` can be the same as the `y0` second scratch buffer - */ -static struct lc3_complex *fft(const struct lc3_complex *x, int n, - struct lc3_complex *y0, struct lc3_complex *y1) -{ - struct lc3_complex *y[2] = { y1, y0 }; - int i2, i3, is = 0; - - /* The number of points `n` can be decomposed as : - * - * n = 5^1 * 3^n3 * 2^n2 - * - * for n = 40, 80, 160 n3 = 0, n2 = [3..5] - * n = 30, 60, 120, 240 n3 = 1, n2 = [1..4] - * n = 90, 180 n3 = 2, n2 = [1..2] - * - * Note that the expression `n & (n-1) == 0` is equivalent - * to the check that `n` is a power of 2. */ - - fft_5(x, y[is], n /= 5); - - for (i3 = 0; n & (n-1); i3++, is ^= 1) - fft_bf3(lc3_fft_twiddles_bf3[i3], y[is], y[is ^ 1], n /= 3); - - for (i2 = 0; n > 1; i2++, is ^= 1) - fft_bf2(lc3_fft_twiddles_bf2[i2][i3], y[is], y[is ^ 1], n >>= 1); - - return y[is]; -} - - -/* ---------------------------------------------------------------------------- - * MDCT processing - * -------------------------------------------------------------------------- */ - -/** - * Windowing of samples before MDCT - * dt, sr Duration and samplerate (size of the transform) - * x, y Input current and delayed samples - * y, d Output windowed samples, and delayed ones - */ -LC3_HOT static void mdct_window(enum lc3_dt dt, enum lc3_srate sr, - const float *x, float *d, float *y) -{ - int ns = LC3_NS(dt, sr), nd = LC3_ND(dt, sr); - - const float *w0 = lc3_mdct_win[dt][sr], *w1 = w0 + ns; - const float *w2 = w1, *w3 = w2 + nd; - - const float *x0 = x + ns-nd, *x1 = x0; - float *y0 = y + ns/2, *y1 = y0; - float *d0 = d, *d1 = d + nd; - - while (x1 > x) { - *(--y0) = *d0 * *(w0++) - *(--x1) * *(--w1); - *(y1++) = (*(d0++) = *(x0++)) * *(w2++); - - *(--y0) = *d0 * *(w0++) - *(--x1) * *(--w1); - *(y1++) = (*(d0++) = *(x0++)) * *(w2++); - } - - for (x1 += ns; x0 < x1; ) { - *(--y0) = *d0 * *(w0++) - *(--d1) * *(--w1); - *(y1++) = (*(d0++) = *(x0++)) * *(w2++) + (*d1 = *(--x1)) * *(--w3); - - *(--y0) = *d0 * *(w0++) - *(--d1) * *(--w1); - *(y1++) = (*(d0++) = *(x0++)) * *(w2++) + (*d1 = *(--x1)) * *(--w3); - } -} - -/** - * Pre-rotate MDCT coefficients of N/2 points, before FFT N/4 points FFT - * def Size and twiddles factors - * x, y Input and output coefficients - * - * `x` and y` can be the same buffer - */ -LC3_HOT static void mdct_pre_fft(const struct lc3_mdct_rot_def *def, - const float *x, struct lc3_complex *y) -{ - int n4 = def->n4; - - const float *x0 = x, *x1 = x0 + 2*n4; - const struct lc3_complex *w0 = def->w, *w1 = w0 + n4; - struct lc3_complex *y0 = y, *y1 = y0 + n4; - - while (x0 < x1) { - struct lc3_complex u, uw = *(w0++); - u.re = - *(--x1) * uw.re + *x0 * uw.im; - u.im = *(x0++) * uw.re + *x1 * uw.im; - - struct lc3_complex v, vw = *(--w1); - v.re = - *(--x1) * vw.im + *x0 * vw.re; - v.im = - *(x0++) * vw.im - *x1 * vw.re; - - *(y0++) = u; - *(--y1) = v; - } -} - -/** - * Post-rotate FFT N/4 points coefficients, resulting MDCT N points - * def Size and twiddles factors - * x, y Input and output coefficients - * scale Scale on output coefficients - * - * `x` and y` can be the same buffer - */ -LC3_HOT static void mdct_post_fft(const struct lc3_mdct_rot_def *def, - const struct lc3_complex *x, float *y, float scale) -{ - int n4 = def->n4, n8 = n4 >> 1; - - const struct lc3_complex *w0 = def->w + n8, *w1 = w0 - 1; - const struct lc3_complex *x0 = x + n8, *x1 = x0 - 1; - - float *y0 = y + n4, *y1 = y0; - - for ( ; y1 > y; x0++, x1--, w0++, w1--) { - - float u0 = (x0->im * w0->im + x0->re * w0->re) * scale; - float u1 = (x1->re * w1->im - x1->im * w1->re) * scale; - - float v0 = (x0->re * w0->im - x0->im * w0->re) * scale; - float v1 = (x1->im * w1->im + x1->re * w1->re) * scale; - - *(y0++) = u0; *(y0++) = u1; - *(--y1) = v0; *(--y1) = v1; - } -} - -/** - * Pre-rotate IMDCT coefficients of N points, before FFT N/4 points FFT - * def Size and twiddles factors - * x, y Input and output coefficients - * - * `x` and `y` can be the same buffer - * The real and imaginary parts of `y` are swapped, - * to operate on FFT instead of IFFT - */ -LC3_HOT static void imdct_pre_fft(const struct lc3_mdct_rot_def *def, - const float *x, struct lc3_complex *y) -{ - int n4 = def->n4; - - const float *x0 = x, *x1 = x0 + 2*n4; - - const struct lc3_complex *w0 = def->w, *w1 = w0 + n4; - struct lc3_complex *y0 = y, *y1 = y0 + n4; - - while (x0 < x1) { - float u0 = *(x0++), u1 = *(--x1); - float v0 = *(x0++), v1 = *(--x1); - struct lc3_complex uw = *(w0++), vw = *(--w1); - - (y0 )->re = - u0 * uw.re - u1 * uw.im; - (y0++)->im = - u1 * uw.re + u0 * uw.im; - - (--y1)->re = - v1 * vw.re - v0 * vw.im; - ( y1)->im = - v0 * vw.re + v1 * vw.im; - } -} - -/** - * Post-rotate FFT N/4 points coefficients, resulting IMDCT N points - * def Size and twiddles factors - * x, y Input and output coefficients - * scale Scale on output coefficients - * - * `x` and y` can be the same buffer - * The real and imaginary parts of `x` are swapped, - * to operate on FFT instead of IFFT - */ -LC3_HOT static void imdct_post_fft(const struct lc3_mdct_rot_def *def, - const struct lc3_complex *x, float *y, float scale) -{ - int n4 = def->n4; - - const struct lc3_complex *w0 = def->w, *w1 = w0 + n4; - const struct lc3_complex *x0 = x, *x1 = x0 + n4; - - float *y0 = y, *y1 = y0 + 2*n4; - - while (x0 < x1) { - struct lc3_complex uz = *(x0++), vz = *(--x1); - struct lc3_complex uw = *(w0++), vw = *(--w1); - - *(y0++) = (uz.re * uw.im - uz.im * uw.re) * scale; - *(--y1) = (uz.re * uw.re + uz.im * uw.im) * scale; - - *(--y1) = (vz.re * vw.im - vz.im * vw.re) * scale; - *(y0++) = (vz.re * vw.re + vz.im * vw.im) * scale; - } -} - -/** - * Apply windowing of samples - * dt, sr Duration and samplerate - * x, d Middle half of IMDCT coefficients and delayed samples - * y, d Output samples and delayed ones - */ -LC3_HOT static void imdct_window(enum lc3_dt dt, enum lc3_srate sr, - const float *x, float *d, float *y) -{ - /* The full MDCT coefficients is given by symmetry : - * T[ 0 .. n/4-1] = -half[n/4-1 .. 0 ] - * T[ n/4 .. n/2-1] = half[0 .. n/4-1] - * T[ n/2 .. 3n/4-1] = half[n/4 .. n/2-1] - * T[3n/4 .. n-1] = half[n/2-1 .. n/4 ] */ - - int n4 = LC3_NS(dt, sr) >> 1, nd = LC3_ND(dt, sr); - const float *w2 = lc3_mdct_win[dt][sr], *w0 = w2 + 3*n4, *w1 = w0; - - const float *x0 = d + nd-n4, *x1 = x0; - float *y0 = y + nd-n4, *y1 = y0, *y2 = d + nd, *y3 = d; - - while (y0 > y) { - *(--y0) = *(--x0) - *(x ) * *(w1++); - *(y1++) = *(x1++) + *(x++) * *(--w0); - - *(--y0) = *(--x0) - *(x ) * *(w1++); - *(y1++) = *(x1++) + *(x++) * *(--w0); - } - - while (y1 < y + nd) { - *(y1++) = *(x1++) + *(x++) * *(--w0); - *(y1++) = *(x1++) + *(x++) * *(--w0); - } - - while (y1 < y + 2*n4) { - *(y1++) = *(x ) * *(--w0); - *(--y2) = *(x++) * *(w2++); - - *(y1++) = *(x ) * *(--w0); - *(--y2) = *(x++) * *(w2++); - } - - while (y2 > y3) { - *(y3++) = *(x ) * *(--w0); - *(--y2) = *(x++) * *(w2++); - - *(y3++) = *(x ) * *(--w0); - *(--y2) = *(x++) * *(w2++); - } -} - -/** - * Forward MDCT transformation - */ -void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr, - enum lc3_srate sr_dst, const float *x, float *d, float *y) -{ - const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr]; - int nf = LC3_NS(dt, sr_dst); - int ns = LC3_NS(dt, sr); - - struct lc3_complex buffer[ns/2]; - struct lc3_complex *z = (struct lc3_complex *)y; - union { float *f; struct lc3_complex *z; } u = { .z = buffer }; - - mdct_window(dt, sr, x, d, u.f); - - mdct_pre_fft(rot, u.f, u.z); - u.z = fft(u.z, ns/2, u.z, z); - mdct_post_fft(rot, u.z, y, sqrtf( (2.f*nf) / (ns*ns) )); -} - -/** - * Inverse MDCT transformation - */ -void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr, - enum lc3_srate sr_src, const float *x, float *d, float *y) -{ - const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr]; - int nf = LC3_NS(dt, sr_src); - int ns = LC3_NS(dt, sr); - - struct lc3_complex buffer[ns/2]; - struct lc3_complex *z = (struct lc3_complex *)y; - union { float *f; struct lc3_complex *z; } u = { .z = buffer }; - - imdct_pre_fft(rot, x, z); - z = fft(z, ns/2, z, u.z); - imdct_post_fft(rot, z, u.f, sqrtf(2.f / nf)); - - imdct_window(dt, sr, u.f, d, y); -} diff --git a/system/embdrv/lc3/src/mdct.h b/system/embdrv/lc3/src/mdct.h deleted file mode 100644 index 03ae8019d644aa776366f783bb4d22630798ce89..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/mdct.h +++ /dev/null @@ -1,57 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Compute LD-MDCT (Low Delay Modified Discret Cosinus Transform) - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_MDCT_H -#define __LC3_MDCT_H - -#include "common.h" - - -/** - * Forward MDCT transformation - * dt, sr Duration and samplerate (size of the transform) - * sr_dst Samplerate destination, scale transforam accordingly - * x, d Temporal samples and delayed buffer - * y, d Output `ns` coefficients and `nd` delayed samples - * - * `x` and `y` can be the same buffer - */ -void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr, - enum lc3_srate sr_dst, const float *x, float *d, float *y); - -/** - * Inverse MDCT transformation - * dt, sr Duration and samplerate (size of the transform) - * sr_src Samplerate source, scale transforam accordingly - * x, d Frequency coefficients and delayed buffer - * y, d Output `ns` samples and `nd` delayed ones - * - * `x` and `y` can be the same buffer - */ -void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr, - enum lc3_srate sr_src, const float *x, float *d, float *y); - - -#endif /* __LC3_MDCT_H */ diff --git a/system/embdrv/lc3/src/mdct_neon.h b/system/embdrv/lc3/src/mdct_neon.h deleted file mode 100644 index 950e750af0ec789b66973c9d7e870fe5d1ff3ed0..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/mdct_neon.h +++ /dev/null @@ -1,280 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -#if __ARM_NEON && __ARM_ARCH_ISA_A64 - -#ifndef TEST_NEON -#include -#endif /* TEST_NEON */ - - -/** - * FFT 5 Points - * The number of interleaved transform `n` assumed to be even - */ -#ifndef fft_5 -#define fft_5 neon_fft_5 -LC3_HOT static inline void neon_fft_5( - const struct lc3_complex *x, struct lc3_complex *y, int n) -{ - static const union { float f[2]; uint64_t u64; } - __cos1 = { { 0.3090169944, 0.3090169944 } }, - __cos2 = { { -0.8090169944, -0.8090169944 } }, - __sin1 = { { 0.9510565163, -0.9510565163 } }, - __sin2 = { { 0.5877852523, -0.5877852523 } }; - - float32x2_t sin1 = vcreate_f32(__sin1.u64); - float32x2_t sin2 = vcreate_f32(__sin2.u64); - float32x2_t cos1 = vcreate_f32(__cos1.u64); - float32x2_t cos2 = vcreate_f32(__cos2.u64); - - float32x4_t sin1q = vcombine_f32(sin1, sin1); - float32x4_t sin2q = vcombine_f32(sin2, sin2); - float32x4_t cos1q = vcombine_f32(cos1, cos1); - float32x4_t cos2q = vcombine_f32(cos2, cos2); - - for (int i = 0; i < n; i += 2, x += 2, y += 10) { - - float32x4_t y0, y1, y2, y3, y4; - - float32x4_t x0 = vld1q_f32( (float *)(x + 0*n) ); - float32x4_t x1 = vld1q_f32( (float *)(x + 1*n) ); - float32x4_t x2 = vld1q_f32( (float *)(x + 2*n) ); - float32x4_t x3 = vld1q_f32( (float *)(x + 3*n) ); - float32x4_t x4 = vld1q_f32( (float *)(x + 4*n) ); - - float32x4_t s14 = vaddq_f32(x1, x4); - float32x4_t s23 = vaddq_f32(x2, x3); - - float32x4_t d14 = vrev64q_f32( vsubq_f32(x1, x4) ); - float32x4_t d23 = vrev64q_f32( vsubq_f32(x2, x3) ); - - y0 = vaddq_f32( x0, vaddq_f32(s14, s23) ); - - y4 = vfmaq_f32( x0, s14, cos1q ); - y4 = vfmaq_f32( y4, s23, cos2q ); - - y1 = vfmaq_f32( y4, d14, sin1q ); - y1 = vfmaq_f32( y1, d23, sin2q ); - - y4 = vfmsq_f32( y4, d14, sin1q ); - y4 = vfmsq_f32( y4, d23, sin2q ); - - y3 = vfmaq_f32( x0, s14, cos2q ); - y3 = vfmaq_f32( y3, s23, cos1q ); - - y2 = vfmaq_f32( y3, d14, sin2q ); - y2 = vfmsq_f32( y2, d23, sin1q ); - - y3 = vfmsq_f32( y3, d14, sin2q ); - y3 = vfmaq_f32( y3, d23, sin1q ); - - vst1_f32( (float *)(y + 0), vget_low_f32(y0) ); - vst1_f32( (float *)(y + 1), vget_low_f32(y1) ); - vst1_f32( (float *)(y + 2), vget_low_f32(y2) ); - vst1_f32( (float *)(y + 3), vget_low_f32(y3) ); - vst1_f32( (float *)(y + 4), vget_low_f32(y4) ); - - vst1_f32( (float *)(y + 5), vget_high_f32(y0) ); - vst1_f32( (float *)(y + 6), vget_high_f32(y1) ); - vst1_f32( (float *)(y + 7), vget_high_f32(y2) ); - vst1_f32( (float *)(y + 8), vget_high_f32(y3) ); - vst1_f32( (float *)(y + 9), vget_high_f32(y4) ); - } -} -#endif /* fft_5 */ - -/** - * FFT Butterfly 3 Points - */ -#ifndef fft_bf3 -#define fft_bf3 neon_fft_bf3 -LC3_HOT static inline void neon_fft_bf3( - const struct lc3_fft_bf3_twiddles *twiddles, - const struct lc3_complex *x, struct lc3_complex *y, int n) -{ - int n3 = twiddles->n3; - const struct lc3_complex (*w0_ptr)[2] = twiddles->t; - const struct lc3_complex (*w1_ptr)[2] = w0_ptr + n3; - const struct lc3_complex (*w2_ptr)[2] = w1_ptr + n3; - - const struct lc3_complex *x0_ptr = x; - const struct lc3_complex *x1_ptr = x0_ptr + n*n3; - const struct lc3_complex *x2_ptr = x1_ptr + n*n3; - - struct lc3_complex *y0_ptr = y; - struct lc3_complex *y1_ptr = y0_ptr + n3; - struct lc3_complex *y2_ptr = y1_ptr + n3; - - for (int j, i = 0; i < n; i++, - y0_ptr += 3*n3, y1_ptr += 3*n3, y2_ptr += 3*n3) { - - /* --- Process by pair --- */ - - for (j = 0; j < (n3 >> 1); j++, - x0_ptr += 2, x1_ptr += 2, x2_ptr += 2) { - - float32x4_t x0 = vld1q_f32( (float *)x0_ptr ); - float32x4_t x1 = vld1q_f32( (float *)x1_ptr ); - float32x4_t x2 = vld1q_f32( (float *)x2_ptr ); - - float32x4_t x1r = vtrn1q_f32( vrev64q_f32(vnegq_f32(x1)), x1 ); - float32x4_t x2r = vtrn1q_f32( vrev64q_f32(vnegq_f32(x2)), x2 ); - - float32x4x2_t wn; - float32x4_t yn; - - wn = vld2q_f32( (float *)(w0_ptr + 2*j) ); - - yn = vfmaq_f32( x0, x1 , vtrn1q_f32(wn.val[0], wn.val[0]) ); - yn = vfmaq_f32( yn, x1r, vtrn1q_f32(wn.val[1], wn.val[1]) ); - yn = vfmaq_f32( yn, x2 , vtrn2q_f32(wn.val[0], wn.val[0]) ); - yn = vfmaq_f32( yn, x2r, vtrn2q_f32(wn.val[1], wn.val[1]) ); - vst1q_f32( (float *)(y0_ptr + 2*j), yn ); - - wn = vld2q_f32( (float *)(w1_ptr + 2*j) ); - - yn = vfmaq_f32( x0, x1 , vtrn1q_f32(wn.val[0], wn.val[0]) ); - yn = vfmaq_f32( yn, x1r, vtrn1q_f32(wn.val[1], wn.val[1]) ); - yn = vfmaq_f32( yn, x2 , vtrn2q_f32(wn.val[0], wn.val[0]) ); - yn = vfmaq_f32( yn, x2r, vtrn2q_f32(wn.val[1], wn.val[1]) ); - vst1q_f32( (float *)(y1_ptr + 2*j), yn ); - - wn = vld2q_f32( (float *)(w2_ptr + 2*j) ); - - yn = vfmaq_f32( x0, x1 , vtrn1q_f32(wn.val[0], wn.val[0]) ); - yn = vfmaq_f32( yn, x1r, vtrn1q_f32(wn.val[1], wn.val[1]) ); - yn = vfmaq_f32( yn, x2 , vtrn2q_f32(wn.val[0], wn.val[0]) ); - yn = vfmaq_f32( yn, x2r, vtrn2q_f32(wn.val[1], wn.val[1]) ); - vst1q_f32( (float *)(y2_ptr + 2*j), yn ); - - } - - /* --- Last iteration --- */ - - if (n3 & 1) { - - float32x2x2_t wn; - float32x2_t yn; - - float32x2_t x0 = vld1_f32( (float *)(x0_ptr++) ); - float32x2_t x1 = vld1_f32( (float *)(x1_ptr++) ); - float32x2_t x2 = vld1_f32( (float *)(x2_ptr++) ); - - float32x2_t x1r = vtrn1_f32( vrev64_f32(vneg_f32(x1)), x1 ); - float32x2_t x2r = vtrn1_f32( vrev64_f32(vneg_f32(x2)), x2 ); - - wn = vld2_f32( (float *)(w0_ptr + 2*j) ); - - yn = vfma_f32( x0, x1 , vtrn1_f32(wn.val[0], wn.val[0]) ); - yn = vfma_f32( yn, x1r, vtrn1_f32(wn.val[1], wn.val[1]) ); - yn = vfma_f32( yn, x2 , vtrn2_f32(wn.val[0], wn.val[0]) ); - yn = vfma_f32( yn, x2r, vtrn2_f32(wn.val[1], wn.val[1]) ); - vst1_f32( (float *)(y0_ptr + 2*j), yn ); - - wn = vld2_f32( (float *)(w1_ptr + 2*j) ); - - yn = vfma_f32( x0, x1 , vtrn1_f32(wn.val[0], wn.val[0]) ); - yn = vfma_f32( yn, x1r, vtrn1_f32(wn.val[1], wn.val[1]) ); - yn = vfma_f32( yn, x2 , vtrn2_f32(wn.val[0], wn.val[0]) ); - yn = vfma_f32( yn, x2r, vtrn2_f32(wn.val[1], wn.val[1]) ); - vst1_f32( (float *)(y1_ptr + 2*j), yn ); - - wn = vld2_f32( (float *)(w2_ptr + 2*j) ); - - yn = vfma_f32( x0, x1 , vtrn1_f32(wn.val[0], wn.val[0]) ); - yn = vfma_f32( yn, x1r, vtrn1_f32(wn.val[1], wn.val[1]) ); - yn = vfma_f32( yn, x2 , vtrn2_f32(wn.val[0], wn.val[0]) ); - yn = vfma_f32( yn, x2r, vtrn2_f32(wn.val[1], wn.val[1]) ); - vst1_f32( (float *)(y2_ptr + 2*j), yn ); - } - - } -} -#endif /* fft_bf3 */ - -/** - * FFT Butterfly 2 Points - */ -#ifndef fft_bf2 -#define fft_bf2 neon_fft_bf2 -LC3_HOT static inline void neon_fft_bf2( - const struct lc3_fft_bf2_twiddles *twiddles, - const struct lc3_complex *x, struct lc3_complex *y, int n) -{ - int n2 = twiddles->n2; - const struct lc3_complex *w_ptr = twiddles->t; - - const struct lc3_complex *x0_ptr = x; - const struct lc3_complex *x1_ptr = x0_ptr + n*n2; - - struct lc3_complex *y0_ptr = y; - struct lc3_complex *y1_ptr = y0_ptr + n2; - - for (int j, i = 0; i < n; i++, y0_ptr += 2*n2, y1_ptr += 2*n2) { - - /* --- Process by pair --- */ - - for (j = 0; j < (n2 >> 1); j++, x0_ptr += 2, x1_ptr += 2) { - - float32x4_t x0 = vld1q_f32( (float *)x0_ptr ); - float32x4_t x1 = vld1q_f32( (float *)x1_ptr ); - float32x4_t y0, y1; - - float32x4_t x1r = vtrn1q_f32( vrev64q_f32(vnegq_f32(x1)), x1 ); - - float32x4_t w = vld1q_f32( (float *)(w_ptr + 2*j) ); - float32x4_t w_re = vtrn1q_f32(w, w); - float32x4_t w_im = vtrn2q_f32(w, w); - - y0 = vfmaq_f32( x0, x1 , w_re ); - y0 = vfmaq_f32( y0, x1r, w_im ); - vst1q_f32( (float *)(y0_ptr + 2*j), y0 ); - - y1 = vfmsq_f32( x0, x1 , w_re ); - y1 = vfmsq_f32( y1, x1r, w_im ); - vst1q_f32( (float *)(y1_ptr + 2*j), y1 ); - } - - /* --- Last iteration --- */ - - if (n2 & 1) { - - float32x2_t x0 = vld1_f32( (float *)(x0_ptr++) ); - float32x2_t x1 = vld1_f32( (float *)(x1_ptr++) ); - float32x2_t y0, y1; - - float32x2_t x1r = vtrn1_f32( vrev64_f32(vneg_f32(x1)), x1 ); - - float32x2_t w = vld1_f32( (float *)(w_ptr + 2*j) ); - float32x2_t w_re = vtrn1_f32(w, w); - float32x2_t w_im = vtrn2_f32(w, w); - - y0 = vfma_f32( x0, x1 , w_re ); - y0 = vfma_f32( y0, x1r, w_im ); - vst1_f32( (float *)(y0_ptr + 2*j), y0 ); - - y1 = vfms_f32( x0, x1 , w_re ); - y1 = vfms_f32( y1, x1r, w_im ); - vst1_f32( (float *)(y1_ptr + 2*j), y1 ); - } - } -} -#endif /* fft_bf2 */ - -#endif /* __ARM_NEON && __ARM_ARCH_ISA_A64 */ diff --git a/system/embdrv/lc3/src/plc.c b/system/embdrv/lc3/src/plc.c deleted file mode 100644 index 03911b4645155edb97c8c624831dca571885cb8d..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/plc.c +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "plc.h" - - -/** - * Reset Packet Loss Concealment state - */ -void lc3_plc_reset(struct lc3_plc_state *plc) -{ - plc->seed = 24607; - lc3_plc_suspend(plc); -} - -/** - * Suspend PLC execution (Good frame received) - */ -void lc3_plc_suspend(struct lc3_plc_state *plc) -{ - plc->count = 1; - plc->alpha = 1.0f; -} - -/** - * Synthesis of a PLC frame - */ -void lc3_plc_synthesize(enum lc3_dt dt, enum lc3_srate sr, - struct lc3_plc_state *plc, const float *x, float *y) -{ - uint16_t seed = plc->seed; - float alpha = plc->alpha; - int ne = LC3_NE(dt, sr); - - alpha *= (plc->count < 4 ? 1.0f : - plc->count < 8 ? 0.9f : 0.85f); - - for (int i = 0; i < ne; i++) { - seed = (16831 + seed * 12821) & 0xffff; - y[i] = alpha * (seed & 0x8000 ? -x[i] : x[i]); - } - - plc->seed = seed; - plc->alpha = alpha; - plc->count++; -} diff --git a/system/embdrv/lc3/src/plc.h b/system/embdrv/lc3/src/plc.h deleted file mode 100644 index 6fda5b5a32c2ac645f31ea00b41fce71e4ac70a9..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/plc.h +++ /dev/null @@ -1,57 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Packet Loss Concealment - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_PLC_H -#define __LC3_PLC_H - -#include "common.h" - - -/** - * Reset PLC state - * plc PLC State to reset - */ -void lc3_plc_reset(lc3_plc_state_t *plc); - -/** - * Suspend PLC synthesis (Error-free frame decoded) - * plc PLC State - */ -void lc3_plc_suspend(lc3_plc_state_t *plc); - -/** - * Synthesis of a PLC frame - * dt, sr Duration and samplerate of the frame - * plc PLC State - * x Last good spectral coefficients - * y Return emulated ones - * - * `x` and `y` can be the same buffer - */ -void lc3_plc_synthesize(enum lc3_dt dt, enum lc3_srate sr, - lc3_plc_state_t *plc, const float *x, float *y); - - -#endif /* __LC3_PLC_H */ diff --git a/system/embdrv/lc3/src/sns.c b/system/embdrv/lc3/src/sns.c deleted file mode 100644 index 56a893ca76dc968221239281b6ab77a223f38552..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/sns.c +++ /dev/null @@ -1,880 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "sns.h" -#include "tables.h" - - -/* ---------------------------------------------------------------------------- - * DCT-16 - * -------------------------------------------------------------------------- */ - -/** - * Matrix of DCT-16 coefficients - * - * M[n][k] = 2f cos( Pi k (2n + 1) / 2N ) - * - * k = [0..N-1], n = [0..N-1], N = 16 - * f = sqrt(1/4N) for k=0, sqrt(1/2N) otherwise - */ -static const float dct16_m[16][16] = { - - { 2.50000000e-01, 3.51850934e-01, 3.46759961e-01, 3.38329500e-01, - 3.26640741e-01, 3.11806253e-01, 2.93968901e-01, 2.73300467e-01, - 2.50000000e-01, 2.24291897e-01, 1.96423740e-01, 1.66663915e-01, - 1.35299025e-01, 1.02631132e-01, 6.89748448e-02, 3.46542923e-02 }, - - { 2.50000000e-01, 3.38329500e-01, 2.93968901e-01, 2.24291897e-01, - 1.35299025e-01, 3.46542923e-02, -6.89748448e-02, -1.66663915e-01, - -2.50000000e-01, -3.11806253e-01, -3.46759961e-01, -3.51850934e-01, - -3.26640741e-01, -2.73300467e-01, -1.96423740e-01, -1.02631132e-01 }, - - { 2.50000000e-01, 3.11806253e-01, 1.96423740e-01, 3.46542923e-02, - -1.35299025e-01, -2.73300467e-01, -3.46759961e-01, -3.38329500e-01, - -2.50000000e-01, -1.02631132e-01, 6.89748448e-02, 2.24291897e-01, - 3.26640741e-01, 3.51850934e-01, 2.93968901e-01, 1.66663915e-01 }, - - { 2.50000000e-01, 2.73300467e-01, 6.89748448e-02, -1.66663915e-01, - -3.26640741e-01, -3.38329500e-01, -1.96423740e-01, 3.46542923e-02, - 2.50000000e-01, 3.51850934e-01, 2.93968901e-01, 1.02631132e-01, - -1.35299025e-01, -3.11806253e-01, -3.46759961e-01, -2.24291897e-01 }, - - { 2.50000000e-01, 2.24291897e-01, -6.89748448e-02, -3.11806253e-01, - -3.26640741e-01, -1.02631132e-01, 1.96423740e-01, 3.51850934e-01, - 2.50000000e-01, -3.46542923e-02, -2.93968901e-01, -3.38329500e-01, - -1.35299025e-01, 1.66663915e-01, 3.46759961e-01, 2.73300467e-01 }, - - { 2.50000000e-01, 1.66663915e-01, -1.96423740e-01, -3.51850934e-01, - -1.35299025e-01, 2.24291897e-01, 3.46759961e-01, 1.02631132e-01, - -2.50000000e-01, -3.38329500e-01, -6.89748448e-02, 2.73300467e-01, - 3.26640741e-01, 3.46542923e-02, -2.93968901e-01, -3.11806253e-01 }, - - { 2.50000000e-01, 1.02631132e-01, -2.93968901e-01, -2.73300467e-01, - 1.35299025e-01, 3.51850934e-01, 6.89748448e-02, -3.11806253e-01, - -2.50000000e-01, 1.66663915e-01, 3.46759961e-01, 3.46542923e-02, - -3.26640741e-01, -2.24291897e-01, 1.96423740e-01, 3.38329500e-01 }, - - { 2.50000000e-01, 3.46542923e-02, -3.46759961e-01, -1.02631132e-01, - 3.26640741e-01, 1.66663915e-01, -2.93968901e-01, -2.24291897e-01, - 2.50000000e-01, 2.73300467e-01, -1.96423740e-01, -3.11806253e-01, - 1.35299025e-01, 3.38329500e-01, -6.89748448e-02, -3.51850934e-01 }, - - { 2.50000000e-01, -3.46542923e-02, -3.46759961e-01, 1.02631132e-01, - 3.26640741e-01, -1.66663915e-01, -2.93968901e-01, 2.24291897e-01, - 2.50000000e-01, -2.73300467e-01, -1.96423740e-01, 3.11806253e-01, - 1.35299025e-01, -3.38329500e-01, -6.89748448e-02, 3.51850934e-01 }, - - { 2.50000000e-01, -1.02631132e-01, -2.93968901e-01, 2.73300467e-01, - 1.35299025e-01, -3.51850934e-01, 6.89748448e-02, 3.11806253e-01, - -2.50000000e-01, -1.66663915e-01, 3.46759961e-01, -3.46542923e-02, - -3.26640741e-01, 2.24291897e-01, 1.96423740e-01, -3.38329500e-01 }, - - { 2.50000000e-01, -1.66663915e-01, -1.96423740e-01, 3.51850934e-01, - -1.35299025e-01, -2.24291897e-01, 3.46759961e-01, -1.02631132e-01, - -2.50000000e-01, 3.38329500e-01, -6.89748448e-02, -2.73300467e-01, - 3.26640741e-01, -3.46542923e-02, -2.93968901e-01, 3.11806253e-01 }, - - { 2.50000000e-01, -2.24291897e-01, -6.89748448e-02, 3.11806253e-01, - -3.26640741e-01, 1.02631132e-01, 1.96423740e-01, -3.51850934e-01, - 2.50000000e-01, 3.46542923e-02, -2.93968901e-01, 3.38329500e-01, - -1.35299025e-01, -1.66663915e-01, 3.46759961e-01, -2.73300467e-01 }, - - { 2.50000000e-01, -2.73300467e-01, 6.89748448e-02, 1.66663915e-01, - -3.26640741e-01, 3.38329500e-01, -1.96423740e-01, -3.46542923e-02, - 2.50000000e-01, -3.51850934e-01, 2.93968901e-01, -1.02631132e-01, - -1.35299025e-01, 3.11806253e-01, -3.46759961e-01, 2.24291897e-01 }, - - { 2.50000000e-01, -3.11806253e-01, 1.96423740e-01, -3.46542923e-02, - -1.35299025e-01, 2.73300467e-01, -3.46759961e-01, 3.38329500e-01, - -2.50000000e-01, 1.02631132e-01, 6.89748448e-02, -2.24291897e-01, - 3.26640741e-01, -3.51850934e-01, 2.93968901e-01, -1.66663915e-01 }, - - { 2.50000000e-01, -3.38329500e-01, 2.93968901e-01, -2.24291897e-01, - 1.35299025e-01, -3.46542923e-02, -6.89748448e-02, 1.66663915e-01, - -2.50000000e-01, 3.11806253e-01, -3.46759961e-01, 3.51850934e-01, - -3.26640741e-01, 2.73300467e-01, -1.96423740e-01, 1.02631132e-01 }, - - { 2.50000000e-01, -3.51850934e-01, 3.46759961e-01, -3.38329500e-01, - 3.26640741e-01, -3.11806253e-01, 2.93968901e-01, -2.73300467e-01, - 2.50000000e-01, -2.24291897e-01, 1.96423740e-01, -1.66663915e-01, - 1.35299025e-01, -1.02631132e-01, 6.89748448e-02, -3.46542923e-02 }, - -}; - -/** - * Forward DCT-16 transformation - * x, y Input and output 16 values - */ -LC3_HOT static void dct16_forward(const float *x, float *y) -{ - for (int i = 0, j; i < 16; i++) - for (y[i] = 0, j = 0; j < 16; j++) - y[i] += x[j] * dct16_m[j][i]; -} - -/** - * Inverse DCT-16 transformation - * x, y Input and output 16 values - */ -LC3_HOT static void dct16_inverse(const float *x, float *y) -{ - for (int i = 0, j; i < 16; i++) - for (y[i] = 0, j = 0; j < 16; j++) - y[i] += x[j] * dct16_m[i][j]; -} - - -/* ---------------------------------------------------------------------------- - * Scale factors - * -------------------------------------------------------------------------- */ - -/** - * Scale factors - * dt, sr Duration and samplerate of the frame - * eb Energy estimation per bands - * att 1: Attack detected 0: Otherwise - * scf Output 16 scale factors - */ -LC3_HOT static void compute_scale_factors( - enum lc3_dt dt, enum lc3_srate sr, - const float *eb, bool att, float *scf) -{ - /* Pre-emphasis gain table : - * Ge[b] = 10 ^ (b * g_tilt) / 630 , b = [0..63] */ - - static const float ge_table[LC3_NUM_SRATE][LC3_NUM_BANDS] = { - - [LC3_SRATE_8K] = { /* g_tilt = 14 */ - 1.00000000e+00, 1.05250029e+00, 1.10775685e+00, 1.16591440e+00, - 1.22712524e+00, 1.29154967e+00, 1.35935639e+00, 1.43072299e+00, - 1.50583635e+00, 1.58489319e+00, 1.66810054e+00, 1.75567629e+00, - 1.84784980e+00, 1.94486244e+00, 2.04696827e+00, 2.15443469e+00, - 2.26754313e+00, 2.38658979e+00, 2.51188643e+00, 2.64376119e+00, - 2.78255940e+00, 2.92864456e+00, 3.08239924e+00, 3.24422608e+00, - 3.41454887e+00, 3.59381366e+00, 3.78248991e+00, 3.98107171e+00, - 4.19007911e+00, 4.41005945e+00, 4.64158883e+00, 4.88527357e+00, - 5.14175183e+00, 5.41169527e+00, 5.69581081e+00, 5.99484250e+00, - 6.30957344e+00, 6.64082785e+00, 6.98947321e+00, 7.35642254e+00, - 7.74263683e+00, 8.14912747e+00, 8.57695899e+00, 9.02725178e+00, - 9.50118507e+00, 1.00000000e+01, 1.05250029e+01, 1.10775685e+01, - 1.16591440e+01, 1.22712524e+01, 1.29154967e+01, 1.35935639e+01, - 1.43072299e+01, 1.50583635e+01, 1.58489319e+01, 1.66810054e+01, - 1.75567629e+01, 1.84784980e+01, 1.94486244e+01, 2.04696827e+01, - 2.15443469e+01, 2.26754313e+01, 2.38658979e+01, 2.51188643e+01 }, - - [LC3_SRATE_16K] = { /* g_tilt = 18 */ - 1.00000000e+00, 1.06800043e+00, 1.14062492e+00, 1.21818791e+00, - 1.30102522e+00, 1.38949549e+00, 1.48398179e+00, 1.58489319e+00, - 1.69266662e+00, 1.80776868e+00, 1.93069773e+00, 2.06198601e+00, - 2.20220195e+00, 2.35195264e+00, 2.51188643e+00, 2.68269580e+00, - 2.86512027e+00, 3.05994969e+00, 3.26802759e+00, 3.49025488e+00, - 3.72759372e+00, 3.98107171e+00, 4.25178630e+00, 4.54090961e+00, - 4.84969343e+00, 5.17947468e+00, 5.53168120e+00, 5.90783791e+00, - 6.30957344e+00, 6.73862717e+00, 7.19685673e+00, 7.68624610e+00, - 8.20891416e+00, 8.76712387e+00, 9.36329209e+00, 1.00000000e+01, - 1.06800043e+01, 1.14062492e+01, 1.21818791e+01, 1.30102522e+01, - 1.38949549e+01, 1.48398179e+01, 1.58489319e+01, 1.69266662e+01, - 1.80776868e+01, 1.93069773e+01, 2.06198601e+01, 2.20220195e+01, - 2.35195264e+01, 2.51188643e+01, 2.68269580e+01, 2.86512027e+01, - 3.05994969e+01, 3.26802759e+01, 3.49025488e+01, 3.72759372e+01, - 3.98107171e+01, 4.25178630e+01, 4.54090961e+01, 4.84969343e+01, - 5.17947468e+01, 5.53168120e+01, 5.90783791e+01, 6.30957344e+01 }, - - [LC3_SRATE_24K] = { /* g_tilt = 22 */ - 1.00000000e+00, 1.08372885e+00, 1.17446822e+00, 1.27280509e+00, - 1.37937560e+00, 1.49486913e+00, 1.62003281e+00, 1.75567629e+00, - 1.90267705e+00, 2.06198601e+00, 2.23463373e+00, 2.42173704e+00, - 2.62450630e+00, 2.84425319e+00, 3.08239924e+00, 3.34048498e+00, - 3.62017995e+00, 3.92329345e+00, 4.25178630e+00, 4.60778348e+00, - 4.99358789e+00, 5.41169527e+00, 5.86481029e+00, 6.35586411e+00, - 6.88803330e+00, 7.46476041e+00, 8.08977621e+00, 8.76712387e+00, - 9.50118507e+00, 1.02967084e+01, 1.11588399e+01, 1.20931568e+01, - 1.31057029e+01, 1.42030283e+01, 1.53922315e+01, 1.66810054e+01, - 1.80776868e+01, 1.95913107e+01, 2.12316686e+01, 2.30093718e+01, - 2.49359200e+01, 2.70237760e+01, 2.92864456e+01, 3.17385661e+01, - 3.43959997e+01, 3.72759372e+01, 4.03970086e+01, 4.37794036e+01, - 4.74450028e+01, 5.14175183e+01, 5.57226480e+01, 6.03882412e+01, - 6.54444792e+01, 7.09240702e+01, 7.68624610e+01, 8.32980665e+01, - 9.02725178e+01, 9.78309319e+01, 1.06022203e+02, 1.14899320e+02, - 1.24519708e+02, 1.34945600e+02, 1.46244440e+02, 1.58489319e+02 }, - - [LC3_SRATE_32K] = { /* g_tilt = 26 */ - 1.00000000e+00, 1.09968890e+00, 1.20931568e+00, 1.32987103e+00, - 1.46244440e+00, 1.60823388e+00, 1.76855694e+00, 1.94486244e+00, - 2.13874364e+00, 2.35195264e+00, 2.58641621e+00, 2.84425319e+00, - 3.12779366e+00, 3.43959997e+00, 3.78248991e+00, 4.15956216e+00, - 4.57422434e+00, 5.03022373e+00, 5.53168120e+00, 6.08312841e+00, - 6.68954879e+00, 7.35642254e+00, 8.08977621e+00, 8.89623710e+00, - 9.78309319e+00, 1.07583590e+01, 1.18308480e+01, 1.30102522e+01, - 1.43072299e+01, 1.57335019e+01, 1.73019574e+01, 1.90267705e+01, - 2.09235283e+01, 2.30093718e+01, 2.53031508e+01, 2.78255940e+01, - 3.05994969e+01, 3.36499270e+01, 3.70044512e+01, 4.06933843e+01, - 4.47500630e+01, 4.92111475e+01, 5.41169527e+01, 5.95118121e+01, - 6.54444792e+01, 7.19685673e+01, 7.91430346e+01, 8.70327166e+01, - 9.57089124e+01, 1.05250029e+02, 1.15742288e+02, 1.27280509e+02, - 1.39968963e+02, 1.53922315e+02, 1.69266662e+02, 1.86140669e+02, - 2.04696827e+02, 2.25102829e+02, 2.47543082e+02, 2.72220379e+02, - 2.99357729e+02, 3.29200372e+02, 3.62017995e+02, 3.98107171e+02 }, - - [LC3_SRATE_48K] = { /* g_tilt = 30 */ - 1.00000000e+00, 1.11588399e+00, 1.24519708e+00, 1.38949549e+00, - 1.55051578e+00, 1.73019574e+00, 1.93069773e+00, 2.15443469e+00, - 2.40409918e+00, 2.68269580e+00, 2.99357729e+00, 3.34048498e+00, - 3.72759372e+00, 4.15956216e+00, 4.64158883e+00, 5.17947468e+00, - 5.77969288e+00, 6.44946677e+00, 7.19685673e+00, 8.03085722e+00, - 8.96150502e+00, 1.00000000e+01, 1.11588399e+01, 1.24519708e+01, - 1.38949549e+01, 1.55051578e+01, 1.73019574e+01, 1.93069773e+01, - 2.15443469e+01, 2.40409918e+01, 2.68269580e+01, 2.99357729e+01, - 3.34048498e+01, 3.72759372e+01, 4.15956216e+01, 4.64158883e+01, - 5.17947468e+01, 5.77969288e+01, 6.44946677e+01, 7.19685673e+01, - 8.03085722e+01, 8.96150502e+01, 1.00000000e+02, 1.11588399e+02, - 1.24519708e+02, 1.38949549e+02, 1.55051578e+02, 1.73019574e+02, - 1.93069773e+02, 2.15443469e+02, 2.40409918e+02, 2.68269580e+02, - 2.99357729e+02, 3.34048498e+02, 3.72759372e+02, 4.15956216e+02, - 4.64158883e+02, 5.17947468e+02, 5.77969288e+02, 6.44946677e+02, - 7.19685673e+02, 8.03085722e+02, 8.96150502e+02, 1.00000000e+03 }, - }; - - float e[LC3_NUM_BANDS]; - - /* --- Copy and padding --- */ - - int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS); - int n2 = LC3_NUM_BANDS - nb; - - for (int i2 = 0; i2 < n2; i2++) - e[2*i2 + 0] = e[2*i2 + 1] = eb[i2]; - - memcpy(e + 2*n2, eb + n2, (nb - n2) * sizeof(float)); - - /* --- Smoothing, pre-emphasis and logarithm --- */ - - const float *ge = ge_table[sr]; - - float e0 = e[0], e1 = e[0], e2; - float e_sum = 0; - - for (int i = 0; i < LC3_NUM_BANDS-1; ) { - e[i] = (e0 * 0.25f + e1 * 0.5f + (e2 = e[i+1]) * 0.25f) * ge[i]; - e_sum += e[i++]; - - e[i] = (e1 * 0.25f + e2 * 0.5f + (e0 = e[i+1]) * 0.25f) * ge[i]; - e_sum += e[i++]; - - e[i] = (e2 * 0.25f + e0 * 0.5f + (e1 = e[i+1]) * 0.25f) * ge[i]; - e_sum += e[i++]; - } - - e[LC3_NUM_BANDS-1] = (e0 * 0.25f + e1 * 0.75f) * ge[LC3_NUM_BANDS-1]; - e_sum += e[LC3_NUM_BANDS-1]; - - float noise_floor = fmaxf(e_sum * (1e-4f / 64), 0x1p-32f); - - for (int i = 0; i < LC3_NUM_BANDS; i++) - e[i] = fast_log2f(fmaxf(e[i], noise_floor)) * 0.5f; - - /* --- Grouping & scaling --- */ - - float scf_sum; - - scf[0] = (e[0] + e[4]) * 1.f/12 + - (e[0] + e[3]) * 2.f/12 + - (e[1] + e[2]) * 3.f/12 ; - scf_sum = scf[0]; - - for (int i = 1; i < 15; i++) { - scf[i] = (e[4*i-1] + e[4*i+4]) * 1.f/12 + - (e[4*i ] + e[4*i+3]) * 2.f/12 + - (e[4*i+1] + e[4*i+2]) * 3.f/12 ; - scf_sum += scf[i]; - } - - scf[15] = (e[59] + e[63]) * 1.f/12 + - (e[60] + e[63]) * 2.f/12 + - (e[61] + e[62]) * 3.f/12 ; - scf_sum += scf[15]; - - for (int i = 0; i < 16; i++) - scf[i] = 0.85f * (scf[i] - scf_sum * 1.f/16); - - /* --- Attack handling --- */ - - if (!att) - return; - - float s0, s1 = scf[0], s2 = scf[1], s3 = scf[2], s4 = scf[3]; - float sn = s1 + s2; - - scf[0] = (sn += s3) * 1.f/3; - scf[1] = (sn += s4) * 1.f/4; - scf_sum = scf[0] + scf[1]; - - for (int i = 2; i < 14; i++, sn -= s0) { - s0 = s1, s1 = s2, s2 = s3, s3 = s4, s4 = scf[i+2]; - scf[i] = (sn += s4) * 1.f/5; - scf_sum += scf[i]; - } - - scf[14] = (sn ) * 1.f/4; - scf[15] = (sn -= s1) * 1.f/3; - scf_sum += scf[14] + scf[15]; - - for (int i = 0; i < 16; i++) - scf[i] = (dt == LC3_DT_7M5 ? 0.3f : 0.5f) * - (scf[i] - scf_sum * 1.f/16); -} - -/** - * Codebooks - * scf Input 16 scale factors - * lf/hfcb_idx Output the low and high frequency codebooks index - */ -LC3_HOT static void resolve_codebooks( - const float *scf, int *lfcb_idx, int *hfcb_idx) -{ - float dlfcb_max = 0, dhfcb_max = 0; - *lfcb_idx = *hfcb_idx = 0; - - for (int icb = 0; icb < 32; icb++) { - const float *lfcb = lc3_sns_lfcb[icb]; - const float *hfcb = lc3_sns_hfcb[icb]; - float dlfcb = 0, dhfcb = 0; - - for (int i = 0; i < 8; i++) { - dlfcb += (scf[ i] - lfcb[i]) * (scf[ i] - lfcb[i]); - dhfcb += (scf[8+i] - hfcb[i]) * (scf[8+i] - hfcb[i]); - } - - if (icb == 0 || dlfcb < dlfcb_max) - *lfcb_idx = icb, dlfcb_max = dlfcb; - - if (icb == 0 || dhfcb < dhfcb_max) - *hfcb_idx = icb, dhfcb_max = dhfcb; - } -} - -/** - * Unit energy normalize pulse configuration - * c Pulse configuration - * cn Normalized pulse configuration - */ -LC3_HOT static void normalize(const int *c, float *cn) -{ - int c2_sum = 0; - for (int i = 0; i < 16; i++) - c2_sum += c[i] * c[i]; - - float c_norm = 1.f / sqrtf(c2_sum); - - for (int i = 0; i < 16; i++) - cn[i] = c[i] * c_norm; -} - -/** - * Sub-procedure of `quantize()`, add unit pulse - * x, y, n Transformed residual, and vector of pulses with length - * start, end Current number of pulses, limit to reach - * corr, energy Correlation (x,y) and y energy, updated at output - */ -LC3_HOT static void add_pulse(const float *x, int *y, int n, - int start, int end, float *corr, float *energy) -{ - for (int k = start; k < end; k++) { - float best_c2 = (*corr + x[0]) * (*corr + x[0]); - float best_e = *energy + 2*y[0] + 1; - int nbest = 0; - - for (int i = 1; i < n; i++) { - float c2 = (*corr + x[i]) * (*corr + x[i]); - float e = *energy + 2*y[i] + 1; - - if (c2 * best_e > e * best_c2) - best_c2 = c2, best_e = e, nbest = i; - } - - *corr += x[nbest]; - *energy += 2*y[nbest] + 1; - y[nbest]++; - } -} - -/** - * Quantization of codebooks residual - * scf Input 16 scale factors, output quantized version - * lf/hfcb_idx Codebooks index - * c, cn Output 4 pulse configurations candidates, normalized - * shape/gain_idx Output selected shape/gain indexes - */ -LC3_HOT static void quantize(const float *scf, int lfcb_idx, int hfcb_idx, - int (*c)[16], float (*cn)[16], int *shape_idx, int *gain_idx) -{ - /* --- Residual --- */ - - const float *lfcb = lc3_sns_lfcb[lfcb_idx]; - const float *hfcb = lc3_sns_hfcb[hfcb_idx]; - float r[16], x[16]; - - for (int i = 0; i < 8; i++) { - r[ i] = scf[ i] - lfcb[i]; - r[8+i] = scf[8+i] - hfcb[i]; - } - - dct16_forward(r, x); - - /* --- Shape 3 candidate --- - * Project to or below pyramid N = 16, K = 6, - * then add unit pulses until you reach K = 6, over N = 16 */ - - float xm[16]; - float xm_sum = 0; - - for (int i = 0; i < 16; i++) { - xm[i] = fabsf(x[i]); - xm_sum += xm[i]; - } - - float proj_factor = (6 - 1) / fmaxf(xm_sum, 1e-31f); - float corr = 0, energy = 0; - int npulses = 0; - - for (int i = 0; i < 16; i++) { - c[3][i] = floorf(xm[i] * proj_factor); - npulses += c[3][i]; - corr += c[3][i] * xm[i]; - energy += c[3][i] * c[3][i]; - } - - add_pulse(xm, c[3], 16, npulses, 6, &corr, &energy); - npulses = 6; - - /* --- Shape 2 candidate --- - * Add unit pulses until you reach K = 8 on shape 3 */ - - memcpy(c[2], c[3], sizeof(c[2])); - - add_pulse(xm, c[2], 16, npulses, 8, &corr, &energy); - npulses = 8; - - /* --- Shape 1 candidate --- - * Remove any unit pulses from shape 2 that are not part of 0 to 9 - * Update energy and correlation terms accordingly - * Add unit pulses until you reach K = 10, over N = 10 */ - - memcpy(c[1], c[2], sizeof(c[1])); - - for (int i = 10; i < 16; i++) { - c[1][i] = 0; - npulses -= c[2][i]; - corr -= c[2][i] * xm[i]; - energy -= c[2][i] * c[2][i]; - } - - add_pulse(xm, c[1], 10, npulses, 10, &corr, &energy); - npulses = 10; - - /* --- Shape 0 candidate --- - * Add unit pulses until you reach K = 1, on shape 1 */ - - memcpy(c[0], c[1], sizeof(c[0])); - - add_pulse(xm + 10, c[0] + 10, 6, 0, 1, &corr, &energy); - - /* --- Add sign and unit energy normalize --- */ - - for (int j = 0; j < 16; j++) - for (int i = 0; i < 4; i++) - c[i][j] = x[j] < 0 ? -c[i][j] : c[i][j]; - - for (int i = 0; i < 4; i++) - normalize(c[i], cn[i]); - - /* --- Determe shape & gain index --- - * Search the Mean Square Error, within (shape, gain) combinations */ - - float mse_min = INFINITY; - *shape_idx = *gain_idx = 0; - - for (int ic = 0; ic < 4; ic++) { - const struct lc3_sns_vq_gains *cgains = lc3_sns_vq_gains + ic; - float cmse_min = INFINITY; - int cgain_idx = 0; - - for (int ig = 0; ig < cgains->count; ig++) { - float g = cgains->v[ig]; - - float mse = 0; - for (int i = 0; i < 16; i++) - mse += (x[i] - g * cn[ic][i]) * (x[i] - g * cn[ic][i]); - - if (mse < cmse_min) { - cgain_idx = ig, - cmse_min = mse; - } - } - - if (cmse_min < mse_min) { - *shape_idx = ic, *gain_idx = cgain_idx; - mse_min = cmse_min; - } - } -} - -/** - * Unquantization of codebooks residual - * lf/hfcb_idx Low and high frequency codebooks index - * c Table of normalized pulse configuration - * shape/gain Selected shape/gain indexes - * scf Return unquantized scale factors - */ -LC3_HOT static void unquantize(int lfcb_idx, int hfcb_idx, - const float *c, int shape, int gain, float *scf) -{ - const float *lfcb = lc3_sns_lfcb[lfcb_idx]; - const float *hfcb = lc3_sns_hfcb[hfcb_idx]; - float g = lc3_sns_vq_gains[shape].v[gain]; - - dct16_inverse(c, scf); - - for (int i = 0; i < 8; i++) - scf[i] = lfcb[i] + g * scf[i]; - - for (int i = 8; i < 16; i++) - scf[i] = hfcb[i-8] + g * scf[i]; -} - -/** - * Sub-procedure of `sns_enumerate()`, enumeration of a vector - * c, n Table of pulse configuration, and length - * idx, ls Return enumeration set - */ -static void enum_mvpq(const int *c, int n, int *idx, bool *ls) -{ - int ci, i, j; - - /* --- Scan for 1st significant coeff --- */ - - for (i = 0, c += n; (ci = *(--c)) == 0 ; i++); - - *idx = 0; - *ls = ci < 0; - - /* --- Scan remaining coefficients --- */ - - for (i++, j = LC3_ABS(ci); i < n; i++, j += LC3_ABS(ci)) { - - if ((ci = *(--c)) != 0) { - *idx = (*idx << 1) | *ls; - *ls = ci < 0; - } - - *idx += lc3_sns_mpvq_offsets[i][j]; - } -} - -/** - * Sub-procedure of `sns_deenumerate()`, deenumeration of a vector - * idx, ls Enumeration set - * npulses Number of pulses in the set - * c, n Table of pulses configuration, and length - */ -static void deenum_mvpq(int idx, bool ls, int npulses, int *c, int n) -{ - int i; - - /* --- Scan for coefficients --- */ - - for (i = n-1; i >= 0 && idx; i--) { - - int ci = 0; - - for (ci = 0; idx < lc3_sns_mpvq_offsets[i][npulses - ci]; ci++); - idx -= lc3_sns_mpvq_offsets[i][npulses - ci]; - - *(c++) = ls ? -ci : ci; - npulses -= ci; - if (ci > 0) { - ls = idx & 1; - idx >>= 1; - } - } - - /* --- Set last significant --- */ - - int ci = npulses; - - if (i-- >= 0) - *(c++) = ls ? -ci : ci; - - while (i-- >= 0) - *(c++) = 0; -} - -/** - * SNS Enumeration of PVQ configuration - * shape Selected shape index - * c Selected pulse configuration - * idx_a, ls_a Return enumeration set A - * idx_b, ls_b Return enumeration set B (shape = 0) - */ -static void enumerate(int shape, const int *c, - int *idx_a, bool *ls_a, int *idx_b, bool *ls_b) -{ - enum_mvpq(c, shape < 2 ? 10 : 16, idx_a, ls_a); - - if (shape == 0) - enum_mvpq(c + 10, 6, idx_b, ls_b); -} - -/** - * SNS Deenumeration of PVQ configuration - * shape Selected shape index - * idx_a, ls_a enumeration set A - * idx_b, ls_b enumeration set B (shape = 0) - * c Return pulse configuration - */ -static void deenumerate(int shape, - int idx_a, bool ls_a, int idx_b, bool ls_b, int *c) -{ - int npulses_a = (const int []){ 10, 10, 8, 6 }[shape]; - - deenum_mvpq(idx_a, ls_a, npulses_a, c, shape < 2 ? 10 : 16); - - if (shape == 0) - deenum_mvpq(idx_b, ls_b, 1, c + 10, 6); - else if (shape == 1) - memset(c + 10, 0, 6 * sizeof(*c)); -} - - -/* ---------------------------------------------------------------------------- - * Filtering - * -------------------------------------------------------------------------- */ - -/** - * Spectral shaping - * dt, sr Duration and samplerate of the frame - * scf_q Quantized scale factors - * inv True on inverse shaping, False otherwise - * x Spectral coefficients - * y Return shapped coefficients - * - * `x` and `y` can be the same buffer - */ -LC3_HOT static void spectral_shaping(enum lc3_dt dt, enum lc3_srate sr, - const float *scf_q, bool inv, const float *x, float *y) -{ - /* --- Interpolate scale factors --- */ - - float scf[LC3_NUM_BANDS]; - float s0, s1 = inv ? -scf_q[0] : scf_q[0]; - - scf[0] = scf[1] = s1; - for (int i = 0; i < 15; i++) { - s0 = s1, s1 = inv ? -scf_q[i+1] : scf_q[i+1]; - scf[4*i+2] = s0 + 0.125f * (s1 - s0); - scf[4*i+3] = s0 + 0.375f * (s1 - s0); - scf[4*i+4] = s0 + 0.625f * (s1 - s0); - scf[4*i+5] = s0 + 0.875f * (s1 - s0); - } - scf[62] = s1 + 0.125f * (s1 - s0); - scf[63] = s1 + 0.375f * (s1 - s0); - - int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS); - int n2 = LC3_NUM_BANDS - nb; - - for (int i2 = 0; i2 < n2; i2++) - scf[i2] = 0.5f * (scf[2*i2] + scf[2*i2+1]); - - if (n2 > 0) - memmove(scf + n2, scf + 2*n2, (nb - n2) * sizeof(float)); - - /* --- Spectral shaping --- */ - - const int *lim = lc3_band_lim[dt][sr]; - - for (int i = 0, ib = 0; ib < nb; ib++) { - float g_sns = fast_exp2f(-scf[ib]); - - for ( ; i < lim[ib+1]; i++) - y[i] = x[i] * g_sns; - } -} - - -/* ---------------------------------------------------------------------------- - * Interface - * -------------------------------------------------------------------------- */ - -/** - * SNS analysis - */ -void lc3_sns_analyze(enum lc3_dt dt, enum lc3_srate sr, - const float *eb, bool att, struct lc3_sns_data *data, - const float *x, float *y) -{ - /* Processing steps : - * - Determine 16 scale factors from bands energy estimation - * - Get codebooks indexes that match thoses scale factors - * - Quantize the residual with the selected codebook - * - The pulse configuration `c[]` is enumerated - * - Finally shape the spectrum coefficients accordingly */ - - float scf[16], cn[4][16]; - int c[4][16]; - - compute_scale_factors(dt, sr, eb, att, scf); - - resolve_codebooks(scf, &data->lfcb, &data->hfcb); - - quantize(scf, data->lfcb, data->hfcb, - c, cn, &data->shape, &data->gain); - - unquantize(data->lfcb, data->hfcb, - cn[data->shape], data->shape, data->gain, scf); - - enumerate(data->shape, c[data->shape], - &data->idx_a, &data->ls_a, &data->idx_b, &data->ls_b); - - spectral_shaping(dt, sr, scf, false, x, y); -} - -/** - * SNS synthesis - */ -void lc3_sns_synthesize(enum lc3_dt dt, enum lc3_srate sr, - const lc3_sns_data_t *data, const float *x, float *y) -{ - float scf[16], cn[16]; - int c[16]; - - deenumerate(data->shape, - data->idx_a, data->ls_a, data->idx_b, data->ls_b, c); - - normalize(c, cn); - - unquantize(data->lfcb, data->hfcb, cn, data->shape, data->gain, scf); - - spectral_shaping(dt, sr, scf, true, x, y); -} - -/** - * Return number of bits coding the bitstream data - */ -int lc3_sns_get_nbits(void) -{ - return 38; -} - -/** - * Put bitstream data - */ -void lc3_sns_put_data(lc3_bits_t *bits, const struct lc3_sns_data *data) -{ - /* --- Codebooks --- */ - - lc3_put_bits(bits, data->lfcb, 5); - lc3_put_bits(bits, data->hfcb, 5); - - /* --- Shape, gain and vectors --- * - * Write MSB bit of shape index, next LSB bits of shape and gain, - * and MVPQ vectors indexes are muxed */ - - int shape_msb = data->shape >> 1; - lc3_put_bit(bits, shape_msb); - - if (shape_msb == 0) { - const int size_a = 2390004; - int submode = data->shape & 1; - - int mux_high = submode == 0 ? - 2 * (data->idx_b + 1) + data->ls_b : data->gain & 1; - int mux_code = mux_high * size_a + data->idx_a; - - lc3_put_bits(bits, data->gain >> submode, 1); - lc3_put_bits(bits, data->ls_a, 1); - lc3_put_bits(bits, mux_code, 25); - - } else { - const int size_a = 15158272; - int submode = data->shape & 1; - - int mux_code = submode == 0 ? - data->idx_a : size_a + 2 * data->idx_a + (data->gain & 1); - - lc3_put_bits(bits, data->gain >> submode, 2); - lc3_put_bits(bits, data->ls_a, 1); - lc3_put_bits(bits, mux_code, 24); - } -} - -/** - * Get bitstream data - */ -int lc3_sns_get_data(lc3_bits_t *bits, struct lc3_sns_data *data) -{ - /* --- Codebooks --- */ - - *data = (struct lc3_sns_data){ - .lfcb = lc3_get_bits(bits, 5), - .hfcb = lc3_get_bits(bits, 5) - }; - - /* --- Shape, gain and vectors --- */ - - int shape_msb = lc3_get_bit(bits); - data->gain = lc3_get_bits(bits, 1 + shape_msb); - data->ls_a = lc3_get_bit(bits); - - int mux_code = lc3_get_bits(bits, 25 - shape_msb); - - if (shape_msb == 0) { - const int size_a = 2390004; - - if (mux_code >= size_a * 14) - return -1; - - data->idx_a = mux_code % size_a; - mux_code = mux_code / size_a; - - data->shape = (mux_code < 2); - - if (data->shape == 0) { - data->idx_b = (mux_code - 2) / 2; - data->ls_b = (mux_code - 2) % 2; - } else { - data->gain = (data->gain << 1) + (mux_code % 2); - } - - } else { - const int size_a = 15158272; - - if (mux_code >= size_a + 1549824) - return -1; - - data->shape = 2 + (mux_code >= size_a); - if (data->shape == 2) { - data->idx_a = mux_code; - } else { - mux_code -= size_a; - data->idx_a = mux_code / 2; - data->gain = (data->gain << 1) + (mux_code % 2); - } - } - - return 0; -} diff --git a/system/embdrv/lc3/src/sns.h b/system/embdrv/lc3/src/sns.h deleted file mode 100644 index 432223c4cb9ddc020145b42c9c9935ee32c281ec..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/sns.h +++ /dev/null @@ -1,103 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Spectral Noise Shaping - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_SNS_H -#define __LC3_SNS_H - -#include "common.h" -#include "bits.h" - - -/** - * Bitstream data - */ - -typedef struct lc3_sns_data { - int lfcb, hfcb; - int shape, gain; - int idx_a, idx_b; - bool ls_a, ls_b; -} lc3_sns_data_t; - - -/* ---------------------------------------------------------------------------- - * Encoding - * -------------------------------------------------------------------------- */ - -/** - * SNS analysis - * dt, sr Duration and samplerate of the frame - * eb Energy estimation per bands, and count of bands - * att 1: Attack detected 0: Otherwise - * data Return bitstream data - * x Spectral coefficients - * y Return shapped coefficients - * - * `x` and `y` can be the same buffer - */ -void lc3_sns_analyze(enum lc3_dt dt, enum lc3_srate sr, - const float *eb, bool att, lc3_sns_data_t *data, - const float *x, float *y); - -/** - * Return number of bits coding the bitstream data - * return Bit consumption - */ -int lc3_sns_get_nbits(void); - -/** - * Put bitstream data - * bits Bitstream context - * data Bitstream data - */ -void lc3_sns_put_data(lc3_bits_t *bits, const lc3_sns_data_t *data); - - -/* ---------------------------------------------------------------------------- - * Decoding - * -------------------------------------------------------------------------- */ - -/** - * Get bitstream data - * bits Bitstream context - * data Return SNS data - * return 0: Ok -1: Invalid SNS data - */ -int lc3_sns_get_data(lc3_bits_t *bits, lc3_sns_data_t *data); - -/** - * SNS synthesis - * dt, sr Duration and samplerate of the frame - * data Bitstream data - * x Spectral coefficients - * y Return shapped coefficients - * - * `x` and `y` can be the same buffer - */ -void lc3_sns_synthesize(enum lc3_dt dt, enum lc3_srate sr, - const lc3_sns_data_t *data, const float *x, float *y); - - -#endif /* __LC3_SNS_H */ diff --git a/system/embdrv/lc3/src/spec.c b/system/embdrv/lc3/src/spec.c deleted file mode 100644 index 7ecf43bde5cb87466d38c8cb8a0387211fc13689..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/spec.c +++ /dev/null @@ -1,904 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "spec.h" -#include "bits.h" -#include "tables.h" - - -/* ---------------------------------------------------------------------------- - * Global Gain / Quantization - * -------------------------------------------------------------------------- */ - -/** - * Resolve quantized gain index offset - * sr, nbytes Samplerate and size of the frame - * return Gain index offset - */ -static int resolve_gain_offset(enum lc3_srate sr, int nbytes) -{ - int g_off = (nbytes * 8) / (10 * (1 + sr)); - return 105 + 5*(1 + sr) + LC3_MIN(g_off, 115); -} - -/** - * Global Gain Estimation - * dt, sr Duration and samplerate of the frame - * x Spectral coefficients - * nbits_budget Number of bits available coding the spectrum - * nbits_off Offset on the available bits, temporarily smoothed - * g_off Gain index offset - * reset_off Return True when the nbits_off must be reset - * return The quantized gain value - */ -LC3_HOT static int estimate_gain( - enum lc3_dt dt, enum lc3_srate sr, const float *x, - int nbits_budget, float nbits_off, int g_off, bool *reset_off) -{ - int ne = LC3_NE(dt, sr) >> 2; - int e[ne]; - - /* --- Energy (dB) by 4 MDCT blocks --- */ - - float x2_max = 0; - - for (int i = 0; i < ne; i++, x += 4) { - float x0 = x[0] * x[0]; - float x1 = x[1] * x[1]; - float x2 = x[2] * x[2]; - float x3 = x[3] * x[3]; - - x2_max = fmaxf(x2_max, x0); - x2_max = fmaxf(x2_max, x1); - x2_max = fmaxf(x2_max, x2); - x2_max = fmaxf(x2_max, x3); - - e[i] = fast_db_q16(fmaxf(x0 + x1 + x2 + x3, 1e-10f)); - } - - /* --- Determine gain index --- */ - - int nbits = nbits_budget + nbits_off + 0.5f; - int g_int = 255 - g_off; - - const int k_20_28 = 20.f/28 * 0x1p16f + 0.5f; - const int k_2u7 = 2.7f * 0x1p16f + 0.5f; - const int k_1u4 = 1.4f * 0x1p16f + 0.5f; - - for (int i = 128, j, j0 = ne-1, j1 ; i > 0; i >>= 1) { - int gn = (g_int - i) * k_20_28; - int v = 0; - - for (j = j0; j >= 0 && e[j] < gn; j--); - - for (j1 = j; j >= 0; j--) { - int e_diff = e[j] - gn; - - v += e_diff < 0 ? k_2u7 : - e_diff < 43 << 16 ? e_diff + ( 7 << 16) - : 2*e_diff - (36 << 16); - } - - if (v > nbits * k_1u4) - j0 = j1; - else - g_int = g_int - i; - } - - /* --- Limit gain index --- */ - - int g_min = x2_max == 0 ? -g_off : - ceilf(28 * log10f(sqrtf(x2_max) / (32768 - 0.375f))); - - *reset_off = g_int < g_min || x2_max == 0; - if (*reset_off) - g_int = g_min; - - return g_int; -} - -/** - * Global Gain Adjustment - * sr Samplerate of the frame - * g_idx The estimated quantized gain index - * nbits Computed number of bits coding the spectrum - * nbits_budget Number of bits available for coding the spectrum - * return Gain adjust value (-1 to 2) - */ -LC3_HOT static int adjust_gain( - enum lc3_srate sr, int g_idx, int nbits, int nbits_budget) -{ - /* --- Compute delta threshold --- */ - - const int *t = (const int [LC3_NUM_SRATE][3]){ - { 80, 500, 850 }, { 230, 1025, 1700 }, { 380, 1550, 2550 }, - { 530, 2075, 3400 }, { 680, 2600, 4250 } - }[sr]; - - int delta, den = 48; - - if (nbits < t[0]) { - delta = 3*(nbits + 48); - - } else if (nbits < t[1]) { - int n0 = 3*(t[0] + 48), range = t[1] - t[0]; - delta = n0 * range + (nbits - t[0]) * (t[1] - n0); - den *= range; - - } else { - delta = LC3_MIN(nbits, t[2]); - } - - delta = (delta + den/2) / den; - - /* --- Adjust gain --- */ - - if (nbits < nbits_budget - (delta + 2)) - return -(g_idx > 0); - - if (nbits > nbits_budget) - return (g_idx < 255) + (g_idx < 254 && nbits >= nbits_budget + delta); - - return 0; -} - -/** - * Unquantize gain - * g_int Quantization gain value - * return Unquantized gain value - */ -static float unquantize_gain(int g_int) -{ - /* Unquantization gain table : - * G[i] = 10 ^ (i / 28) , i = [0..64] */ - - static const float iq_table[] = { - 1.00000000e+00, 1.08571112e+00, 1.17876863e+00, 1.27980221e+00, - 1.38949549e+00, 1.50859071e+00, 1.63789371e+00, 1.77827941e+00, - 1.93069773e+00, 2.09617999e+00, 2.27584593e+00, 2.47091123e+00, - 2.68269580e+00, 2.91263265e+00, 3.16227766e+00, 3.43332002e+00, - 3.72759372e+00, 4.04708995e+00, 4.39397056e+00, 4.77058270e+00, - 5.17947468e+00, 5.62341325e+00, 6.10540230e+00, 6.62870316e+00, - 7.19685673e+00, 7.81370738e+00, 8.48342898e+00, 9.21055318e+00, - 1.00000000e+01, 1.08571112e+01, 1.17876863e+01, 1.27980221e+01, - 1.38949549e+01, 1.50859071e+01, 1.63789371e+01, 1.77827941e+01, - 1.93069773e+01, 2.09617999e+01, 2.27584593e+01, 2.47091123e+01, - 2.68269580e+01, 2.91263265e+01, 3.16227766e+01, 3.43332002e+01, - 3.72759372e+01, 4.04708995e+01, 4.39397056e+01, 4.77058270e+01, - 5.17947468e+01, 5.62341325e+01, 6.10540230e+01, 6.62870316e+01, - 7.19685673e+01, 7.81370738e+01, 8.48342898e+01, 9.21055318e+01, - 1.00000000e+02, 1.08571112e+02, 1.17876863e+02, 1.27980221e+02, - 1.38949549e+02, 1.50859071e+02, 1.63789371e+02, 1.77827941e+02, - 1.93069773e+02 - }; - - float g = iq_table[LC3_ABS(g_int) & 0x3f]; - for(int n64 = LC3_ABS(g_int) >> 6; n64--; ) - g *= iq_table[64]; - - return g_int >= 0 ? g : 1 / g; -} - -/** - * Spectrum quantization - * dt, sr Duration and samplerate of the frame - * g_int Quantization gain value - * x Spectral coefficients, scaled as output - * xq, nq Output spectral quantized coefficients, and count - * - * The spectral coefficients `xq` are stored as : - * b0 0:positive or zero 1:negative - * b15..b1 Absolute value - */ -LC3_HOT static void quantize(enum lc3_dt dt, enum lc3_srate sr, - int g_int, float *x, uint16_t *xq, int *nq) -{ - float g_inv = 1 / unquantize_gain(g_int); - int ne = LC3_NE(dt, sr); - - *nq = ne; - - for (int i = 0; i < ne; i += 2) { - uint16_t x0, x1; - - x[i+0] *= g_inv; - x[i+1] *= g_inv; - - x0 = fminf(fabsf(x[i+0]) + 6.f/16, INT16_MAX); - x1 = fminf(fabsf(x[i+1]) + 6.f/16, INT16_MAX); - - xq[i+0] = (x0 << 1) + ((x0 > 0) & (x[i+0] < 0)); - xq[i+1] = (x1 << 1) + ((x1 > 0) & (x[i+1] < 0)); - - *nq = x0 || x1 ? ne : *nq - 2; - } -} - -/** - * Spectrum quantization inverse - * dt, sr Duration and samplerate of the frame - * g_int Quantization gain value - * x, nq Spectral quantized, and count of significants - * return Unquantized gain value - */ -LC3_HOT static float unquantize(enum lc3_dt dt, enum lc3_srate sr, - int g_int, float *x, int nq) -{ - float g = unquantize_gain(g_int); - int i, ne = LC3_NE(dt, sr); - - for (i = 0; i < nq; i++) - x[i] = x[i] * g; - - for ( ; i < ne; i++) - x[i] = 0; - - return g; -} - - -/* ---------------------------------------------------------------------------- - * Spectrum coding - * -------------------------------------------------------------------------- */ - -/** - * Resolve High-bitrate mode according size of the frame - * sr, nbytes Samplerate and size of the frame - * return True when High-Rate mode enabled - */ -static int resolve_high_rate(enum lc3_srate sr, int nbytes) -{ - return nbytes > 20 * (1 + (int)sr); -} - -/** - * Bit consumption - * dt, sr, nbytes Duration, samplerate and size of the frame - * x Spectral quantized coefficients - * n Count of significant coefficients, updated on truncation - * nbits_budget Truncate to stay in budget, when not zero - * p_lsb_mode Return True when LSB's are not AC coded, or NULL - * return The number of bits coding the spectrum - * - * The spectral coefficients `x` storage is : - * b0 0:positive or zero 1:negative - * b15..b1 Absolute value - */ -LC3_HOT static int compute_nbits( - enum lc3_dt dt, enum lc3_srate sr, int nbytes, - const uint16_t *x, int *n, int nbits_budget, bool *p_lsb_mode) -{ - int ne = LC3_NE(dt, sr); - - /* --- Mode and rate --- */ - - bool lsb_mode = nbytes >= 20 * (3 + (int)sr); - bool high_rate = resolve_high_rate(sr, nbytes); - - /* --- Loop on quantized coefficients --- */ - - int nbits = 0, nbits_lsb = 0; - uint8_t state = 0; - - int nbits_end = 0; - int n_end = 0; - - nbits_budget = nbits_budget ? nbits_budget * 2048 : INT_MAX; - - for (int i = 0, h = 0; h < 2; h++) { - const uint8_t (*lut_coeff)[4] = lc3_spectrum_lookup[high_rate][h]; - - for ( ; i < LC3_MIN(*n, (ne + 2) >> (1 - h)) - && nbits <= nbits_budget; i += 2) { - - const uint8_t *lut = lut_coeff[state]; - uint16_t a = x[i] >> 1, b = x[i+1] >> 1; - - /* --- Sign values --- */ - - int s = (a > 0) + (b > 0); - nbits += s * 2048; - - /* --- LSB values Reduce to 2*2 bits MSB values --- - * Reduce to 2x2 bits MSB values. The LSB's pair are arithmetic - * coded with an escape code followed by 1 bit for each values. - * The LSB mode does not arthmetic code the first LSB, - * add the sign of the LSB when one of pair was at value 1 */ - - int k = 0; - int m = (a | b) >> 2; - - if (m) { - - if (lsb_mode) { - nbits += lc3_spectrum_bits[lut[k++]][16] - 2*2048; - nbits_lsb += 2 + (a == 1) + (b == 1); - } - - for (m >>= lsb_mode; m; m >>= 1, k++) - nbits += lc3_spectrum_bits[lut[LC3_MIN(k, 3)]][16]; - - nbits += k * 2*2048; - a >>= k; - b >>= k; - - k = LC3_MIN(k, 3); - } - - /* --- MSB values --- */ - - nbits += lc3_spectrum_bits[lut[k]][a + 4*b]; - - /* --- Update state --- */ - - if (s && nbits <= nbits_budget) { - n_end = i + 2; - nbits_end = nbits; - } - - state = (state << 4) + (k > 1 ? 12 + k : 1 + (a + b) * (k + 1)); - } - } - - /* --- Return --- */ - - *n = n_end; - - if (p_lsb_mode) - *p_lsb_mode = lsb_mode && - nbits_end + nbits_lsb * 2048 > nbits_budget; - - if (nbits_budget >= INT_MAX) - nbits_end += nbits_lsb * 2048; - - return (nbits_end + 2047) / 2048; -} - -/** - * Put quantized spectrum - * bits Bitstream context - * dt, sr, nbytes Duration, samplerate and size of the frame - * x Spectral quantized - * nq, lsb_mode Count of significants, and LSB discard indication - * - * The spectral coefficients `x` storage is : - * b0 0:positive or zero 1:negative - * b15..b1 Absolute value - */ -LC3_HOT static void put_quantized(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, int nbytes, - const uint16_t *x, int nq, bool lsb_mode) -{ - int ne = LC3_NE(dt, sr); - bool high_rate = resolve_high_rate(sr, nbytes); - - /* --- Loop on quantized coefficients --- */ - - uint8_t state = 0; - - for (int i = 0, h = 0; h < 2; h++) { - const uint8_t (*lut_coeff)[4] = lc3_spectrum_lookup[high_rate][h]; - - for ( ; i < LC3_MIN(nq, (ne + 2) >> (1 - h)); i += 2) { - - const uint8_t *lut = lut_coeff[state]; - uint16_t a = x[i] >> 1, b = x[i+1] >> 1; - - /* --- LSB values Reduce to 2*2 bits MSB values --- - * Reduce to 2x2 bits MSB values. The LSB's pair are arithmetic - * coded with an escape code and 1 bits for each values. - * The LSB mode discard the first LSB (at this step) */ - - int m = (a | b) >> 2; - int k = 0, shr = 0; - - if (m) { - - if (lsb_mode) - lc3_put_symbol(bits, - lc3_spectrum_models + lut[k++], 16); - - for (m >>= lsb_mode; m; m >>= 1, k++) { - lc3_put_bit(bits, (a >> k) & 1); - lc3_put_bit(bits, (b >> k) & 1); - lc3_put_symbol(bits, - lc3_spectrum_models + lut[LC3_MIN(k, 3)], 16); - } - - a >>= lsb_mode; - b >>= lsb_mode; - - shr = k - lsb_mode; - k = LC3_MIN(k, 3); - } - - /* --- Sign values --- */ - - if (a) lc3_put_bit(bits, x[i+0] & 1); - if (b) lc3_put_bit(bits, x[i+1] & 1); - - /* --- MSB values --- */ - - a >>= shr; - b >>= shr; - - lc3_put_symbol(bits, lc3_spectrum_models + lut[k], a + 4*b); - - /* --- Update state --- */ - - state = (state << 4) + (k > 1 ? 12 + k : 1 + (a + b) * (k + 1)); - } - } -} - -/** - * Get quantized spectrum - * bits Bitstream context - * dt, sr, nbytes Duration, samplerate and size of the frame - * nq, lsb_mode Count of significants, and LSB discard indication - * xq Return `nq` spectral quantized coefficients - * nf_seed Return the noise factor seed associated - * return 0: Ok -1: Invalid bitstream data - */ -LC3_HOT static int get_quantized(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, int nbytes, - int nq, bool lsb_mode, float *xq, uint16_t *nf_seed) -{ - int ne = LC3_NE(dt, sr); - bool high_rate = resolve_high_rate(sr, nbytes); - - *nf_seed = 0; - - /* --- Loop on quantized coefficients --- */ - - uint8_t state = 0; - - for (int i = 0, h = 0; h < 2; h++) { - const uint8_t (*lut_coeff)[4] = lc3_spectrum_lookup[high_rate][h]; - - for ( ; i < LC3_MIN(nq, (ne + 2) >> (1 - h)); i += 2) { - - const uint8_t *lut = lut_coeff[state]; - - /* --- LSB values --- - * Until the symbol read indicates the escape value 16, - * read an LSB bit for each values. - * The LSB mode discard the first LSB (at this step) */ - - int u = 0, v = 0; - int k = 0, shl = 0; - - unsigned s = lc3_get_symbol(bits, lc3_spectrum_models + lut[k]); - - if (lsb_mode && s >= 16) { - s = lc3_get_symbol(bits, lc3_spectrum_models + lut[++k]); - shl++; - } - - for ( ; s >= 16 && shl < 14; shl++) { - u |= lc3_get_bit(bits) << shl; - v |= lc3_get_bit(bits) << shl; - - k += (k < 3); - s = lc3_get_symbol(bits, lc3_spectrum_models + lut[k]); - } - - if (s >= 16) - return -1; - - /* --- MSB & sign values --- */ - - int a = s % 4; - int b = s / 4; - - u |= a << shl; - v |= b << shl; - - xq[i ] = u && lc3_get_bit(bits) ? -u : u; - xq[i+1] = v && lc3_get_bit(bits) ? -v : v; - - *nf_seed = (*nf_seed + u * i + v * (i+1)) & 0xffff; - - /* --- Update state --- */ - - state = (state << 4) + (k > 1 ? 12 + k : 1 + (a + b) * (k + 1)); - } - } - - return 0; -} - -/** - * Put residual bits of quantization - * bits Bitstream context - * nbits Maximum number of bits to output - * x, n Spectral quantized, and count of significants - * xf Scaled spectral coefficients - * - * The spectral coefficients `x` storage is : - * b0 0:positive or zero 1:negative - * b15..b1 Absolute value - */ -LC3_HOT static void put_residual( - lc3_bits_t *bits, int nbits, const uint16_t *x, int n, const float *xf) -{ - for (int i = 0; i < n && nbits > 0; i++) { - - if (x[i] == 0) - continue; - - float xq = x[i] & 1 ? -(x[i] >> 1) : (x[i] >> 1); - - lc3_put_bit(bits, xf[i] >= xq); - nbits--; - } -} - -/** - * Get residual bits of quantization - * bits Bitstream context - * nbits Maximum number of bits to output - * x, nq Spectral quantized, and count of significants - */ -LC3_HOT static void get_residual( - lc3_bits_t *bits, int nbits, float *x, int nq) -{ - for (int i = 0; i < nq && nbits > 0; i++) { - - if (x[i] == 0) - continue; - - if (lc3_get_bit(bits) == 0) - x[i] -= x[i] < 0 ? 5.f/16 : 3.f/16; - else - x[i] += x[i] > 0 ? 5.f/16 : 3.f/16; - - nbits--; - } -} - -/** - * Put LSB values of quantized spectrum values - * bits Bitstream context - * nbits Maximum number of bits to output - * x, n Spectral quantized, and count of significants - * - * The spectral coefficients `x` storage is : - * b0 0:positive or zero 1:negative - * b15..b1 Absolute value - */ -LC3_HOT static void put_lsb( - lc3_bits_t *bits, int nbits, const uint16_t *x, int n) -{ - for (int i = 0; i < n && nbits > 0; i += 2) { - uint16_t a = x[i] >> 1, b = x[i+1] >> 1; - int a_neg = x[i] & 1, b_neg = x[i+1] & 1; - - if ((a | b) >> 2 == 0) - continue; - - if (nbits-- > 0) - lc3_put_bit(bits, a & 1); - - if (a == 1 && nbits-- > 0) - lc3_put_bit(bits, a_neg); - - if (nbits-- > 0) - lc3_put_bit(bits, b & 1); - - if (b == 1 && nbits-- > 0) - lc3_put_bit(bits, b_neg); - } -} - -/** - * Get LSB values of quantized spectrum values - * bits Bitstream context - * nbits Maximum number of bits to output - * x, nq Spectral quantized, and count of significants - * nf_seed Update the noise factor seed according - */ -LC3_HOT static void get_lsb(lc3_bits_t *bits, - int nbits, float *x, int nq, uint16_t *nf_seed) -{ - for (int i = 0; i < nq && nbits > 0; i += 2) { - - float a = fabsf(x[i]), b = fabsf(x[i+1]); - - if (fmaxf(a, b) < 4) - continue; - - if (nbits-- > 0 && lc3_get_bit(bits)) { - if (a) { - x[i] += x[i] < 0 ? -1 : 1; - *nf_seed = (*nf_seed + i) & 0xffff; - } else if (nbits-- > 0) { - x[i] = lc3_get_bit(bits) ? -1 : 1; - *nf_seed = (*nf_seed + i) & 0xffff; - } - } - - if (nbits-- > 0 && lc3_get_bit(bits)) { - if (b) { - x[i+1] += x[i+1] < 0 ? -1 : 1; - *nf_seed = (*nf_seed + i+1) & 0xffff; - } else if (nbits-- > 0) { - x[i+1] = lc3_get_bit(bits) ? -1 : 1; - *nf_seed = (*nf_seed + i+1) & 0xffff; - } - } - } -} - - -/* ---------------------------------------------------------------------------- - * Noise coding - * -------------------------------------------------------------------------- */ - -/** - * Estimate noise level - * dt, bw Duration and bandwidth of the frame - * xq, nq Quantized spectral coefficients - * x Quantization scaled spectrum coefficients - * return Noise factor (0 to 7) - * - * The spectral coefficients `x` storage is : - * b0 0:positive or zero 1:negative - * b15..b1 Absolute value - */ -LC3_HOT static int estimate_noise(enum lc3_dt dt, enum lc3_bandwidth bw, - const uint16_t *xq, int nq, const float *x) -{ - int bw_stop = (dt == LC3_DT_7M5 ? 60 : 80) * (1 + bw); - int w = 2 + dt; - - float sum = 0; - int i, n = 0, z = 0; - - for (i = 6*(3 + dt) - w; i < LC3_MIN(nq, bw_stop); i++) { - z = xq[i] ? 0 : z + 1; - if (z > 2*w) - sum += fabsf(x[i - w]), n++; - } - - for ( ; i < bw_stop + w; i++) - if (++z > 2*w) - sum += fabsf(x[i - w]), n++; - - int nf = n ? 8 - (int)((16 * sum) / n + 0.5f) : 0; - - return LC3_CLIP(nf, 0, 7); -} - -/** - * Noise filling - * dt, bw Duration and bandwidth of the frame - * nf, nf_seed The noise factor and pseudo-random seed - * g Quantization gain - * x, nq Spectral quantized, and count of significants - */ -LC3_HOT static void fill_noise(enum lc3_dt dt, enum lc3_bandwidth bw, - int nf, uint16_t nf_seed, float g, float *x, int nq) -{ - int bw_stop = (dt == LC3_DT_7M5 ? 60 : 80) * (1 + bw); - int w = 2 + dt; - - float s = g * (float)(8 - nf) / 16; - int i, z = 0; - - for (i = 6*(3 + dt) - w; i < LC3_MIN(nq, bw_stop); i++) { - z = x[i] ? 0 : z + 1; - if (z > 2*w) { - nf_seed = (13849 + nf_seed*31821) & 0xffff; - x[i - w] = nf_seed & 0x8000 ? -s : s; - } - } - - for ( ; i < bw_stop + w; i++) - if (++z > 2*w) { - nf_seed = (13849 + nf_seed*31821) & 0xffff; - x[i - w] = nf_seed & 0x8000 ? -s : s; - } -} - -/** - * Put noise factor - * bits Bitstream context - * nf Noise factor (0 to 7) - */ -static void put_noise_factor(lc3_bits_t *bits, int nf) -{ - lc3_put_bits(bits, nf, 3); -} - -/** - * Get noise factor - * bits Bitstream context - * return Noise factor (0 to 7) - */ -static int get_noise_factor(lc3_bits_t *bits) -{ - return lc3_get_bits(bits, 3); -} - - -/* ---------------------------------------------------------------------------- - * Encoding - * -------------------------------------------------------------------------- */ - -/** - * Bit consumption of the number of coded coefficients - * dt, sr Duration, samplerate of the frame - * return Bit consumpution of the number of coded coefficients - */ -static int get_nbits_nq(enum lc3_dt dt, enum lc3_srate sr) -{ - int ne = LC3_NE(dt, sr); - return 4 + (ne > 32) + (ne > 64) + (ne > 128) + (ne > 256); -} - -/** - * Bit consumption of the arithmetic coder - * dt, sr, nbytes Duration, samplerate and size of the frame - * return Bit consumption of bitstream data - */ -static int get_nbits_ac(enum lc3_dt dt, enum lc3_srate sr, int nbytes) -{ - return get_nbits_nq(dt, sr) + 3 + LC3_MIN((nbytes-1) / 160, 2); -} - -/** - * Spectrum analysis - */ -void lc3_spec_analyze(enum lc3_dt dt, enum lc3_srate sr, - int nbytes, bool pitch, const lc3_tns_data_t *tns, - struct lc3_spec_analysis *spec, float *x, - uint16_t *xq, struct lc3_spec_side *side) -{ - bool reset_off; - - /* --- Bit budget --- */ - - const int nbits_gain = 8; - const int nbits_nf = 3; - - int nbits_budget = 8*nbytes - get_nbits_ac(dt, sr, nbytes) - - lc3_bwdet_get_nbits(sr) - lc3_ltpf_get_nbits(pitch) - - lc3_sns_get_nbits() - lc3_tns_get_nbits(tns) - nbits_gain - nbits_nf; - - /* --- Global gain --- */ - - float nbits_off = spec->nbits_off + spec->nbits_spare; - nbits_off = fminf(fmaxf(nbits_off, -40), 40); - nbits_off = 0.8f * spec->nbits_off + 0.2f * nbits_off; - - int g_off = resolve_gain_offset(sr, nbytes); - - int g_int = estimate_gain(dt, sr, - x, nbits_budget, nbits_off, g_off, &reset_off); - - /* --- Quantization --- */ - - quantize(dt, sr, g_int, x, xq, &side->nq); - - int nbits = compute_nbits(dt, sr, nbytes, xq, &side->nq, 0, NULL); - - spec->nbits_off = reset_off ? 0 : nbits_off; - spec->nbits_spare = reset_off ? 0 : nbits_budget - nbits; - - /* --- Adjust gain and requantize --- */ - - int g_adj = adjust_gain(sr, g_int + g_off, nbits, nbits_budget); - - if (g_adj) - quantize(dt, sr, g_adj, x, xq, &side->nq); - - side->g_idx = g_int + g_adj + g_off; - nbits = compute_nbits(dt, sr, nbytes, - xq, &side->nq, nbits_budget, &side->lsb_mode); -} - -/** - * Put spectral quantization side data - */ -void lc3_spec_put_side(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, const struct lc3_spec_side *side) -{ - int nbits_nq = get_nbits_nq(dt, sr); - - lc3_put_bits(bits, LC3_MAX(side->nq >> 1, 1) - 1, nbits_nq); - lc3_put_bits(bits, side->lsb_mode, 1); - lc3_put_bits(bits, side->g_idx, 8); -} - -/** - * Encode spectral coefficients - */ -void lc3_spec_encode(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, enum lc3_bandwidth bw, int nbytes, - const uint16_t *xq, const lc3_spec_side_t *side, const float *x) -{ - bool lsb_mode = side->lsb_mode; - int nq = side->nq; - - put_noise_factor(bits, estimate_noise(dt, bw, xq, nq, x)); - - put_quantized(bits, dt, sr, nbytes, xq, nq, lsb_mode); - - int nbits_left = lc3_get_bits_left(bits); - - if (lsb_mode) - put_lsb(bits, nbits_left, xq, nq); - else - put_residual(bits, nbits_left, xq, nq, x); -} - - -/* ---------------------------------------------------------------------------- - * Decoding - * -------------------------------------------------------------------------- */ - -/** - * Get spectral quantization side data - */ -int lc3_spec_get_side(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, struct lc3_spec_side *side) -{ - int nbits_nq = get_nbits_nq(dt, sr); - int ne = LC3_NE(dt, sr); - - side->nq = (lc3_get_bits(bits, nbits_nq) + 1) << 1; - side->lsb_mode = lc3_get_bit(bits); - side->g_idx = lc3_get_bits(bits, 8); - - return side->nq > ne ? (side->nq = ne), -1 : 0; -} - -/** - * Decode spectral coefficients - */ -int lc3_spec_decode(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, enum lc3_bandwidth bw, - int nbytes, const lc3_spec_side_t *side, float *x) -{ - bool lsb_mode = side->lsb_mode; - int nq = side->nq; - int ret = 0; - - int nf = get_noise_factor(bits); - uint16_t nf_seed; - - if ((ret = get_quantized(bits, dt, sr, nbytes, - nq, lsb_mode, x, &nf_seed)) < 0) - return ret; - - int nbits_left = lc3_get_bits_left(bits); - - if (lsb_mode) - get_lsb(bits, nbits_left, x, nq, &nf_seed); - else - get_residual(bits, nbits_left, x, nq); - - int g_int = side->g_idx - resolve_gain_offset(sr, nbytes); - float g = unquantize(dt, sr, g_int, x, nq); - - if (nq > 2 || x[0] || x[1] || side->g_idx > 0 || nf < 7) - fill_noise(dt, bw, nf, nf_seed, g, x, nq); - - return 0; -} diff --git a/system/embdrv/lc3/src/spec.h b/system/embdrv/lc3/src/spec.h deleted file mode 100644 index 091d25f32bf6001bc1245dd6e29b06d08bb0396b..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/spec.h +++ /dev/null @@ -1,119 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Spectral coefficients encoding/decoding - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_SPEC_H -#define __LC3_SPEC_H - -#include "common.h" -#include "tables.h" -#include "bwdet.h" -#include "ltpf.h" -#include "tns.h" -#include "sns.h" - - -/** - * Spectral quantization side data - */ -typedef struct lc3_spec_side { - int g_idx, nq; - bool lsb_mode; -} lc3_spec_side_t; - - -/* ---------------------------------------------------------------------------- - * Encoding - * -------------------------------------------------------------------------- */ - -/** - * Spectrum analysis - * dt, sr, nbytes Duration, samplerate and size of the frame - * pitch, tns Pitch present indication and TNS bistream data - * spec Context of analysis - * x Spectral coefficients, scaled as output - * xq, side Return quantization data - * - * The spectral coefficients `xq` storage is : - * b0 0:positive or zero 1:negative - * b15..b1 Absolute value - */ -void lc3_spec_analyze(enum lc3_dt dt, enum lc3_srate sr, - int nbytes, bool pitch, const lc3_tns_data_t *tns, - lc3_spec_analysis_t *spec, float *x, uint16_t *xq, lc3_spec_side_t *side); - -/** - * Put spectral quantization side data - * bits Bitstream context - * dt, sr Duration and samplerate of the frame - * side Spectral quantization side data - */ -void lc3_spec_put_side(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, const lc3_spec_side_t *side); - -/** - * Encode spectral coefficients - * bits Bitstream context - * dt, sr, bw Duration, samplerate, bandwidth - * nbytes and size of the frame - * xq, side Quantization data - * x Scaled spectral coefficients - * - * The spectral coefficients `xq` storage is : - * b0 0:positive or zero 1:negative - * b15..b1 Absolute value - */ -void lc3_spec_encode(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, enum lc3_bandwidth bw, int nbytes, - const uint16_t *xq, const lc3_spec_side_t *side, const float *x); - - -/* ---------------------------------------------------------------------------- - * Decoding - * -------------------------------------------------------------------------- */ - -/** - * Get spectral quantization side data - * bits Bitstream context - * dt, sr Duration and samplerate of the frame - * side Return quantization side data - * return 0: Ok -1: Invalid bandwidth indication - */ -int lc3_spec_get_side(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_srate sr, lc3_spec_side_t *side); - -/** - * Decode spectral coefficients - * bits Bitstream context - * dt, sr, bw Duration, samplerate, bandwidth - * nbytes and size of the frame - * side Quantization side data - * x Spectral coefficients - * return 0: Ok -1: Invalid bitstream data - */ -int lc3_spec_decode(lc3_bits_t *bits, enum lc3_dt dt, enum lc3_srate sr, - enum lc3_bandwidth bw, int nbytes, const lc3_spec_side_t *side, float *x); - - -#endif /* __LC3_SPEC_H */ diff --git a/system/embdrv/lc3/src/tables.c b/system/embdrv/lc3/src/tables.c deleted file mode 100644 index aef6fc1e0467ff4b5b88ac22d253f9ffced9bfce..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/tables.c +++ /dev/null @@ -1,3457 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "tables.h" - - -/** - * Twiddles FFT 3 points - * - * T[0..N-1] = - * { cos(-2Pi * i/N) + j sin(-2Pi * i/N), - * cos(-2Pi * 2i/N) + j sin(-2Pi * 2i/N) } , N=15, 45 - */ - -static const struct lc3_fft_bf3_twiddles fft_twiddles_15 = { - .n3 = 15/3, .t = (const struct lc3_complex [][2]){ - { { 1.0000000e+0, -0.0000000e+0 }, { 1.0000000e+0, -0.0000000e+0 } }, - { { 9.1354546e-1, -4.0673664e-1 }, { 6.6913061e-1, -7.4314483e-1 } }, - { { 6.6913061e-1, -7.4314483e-1 }, { -1.0452846e-1, -9.9452190e-1 } }, - { { 3.0901699e-1, -9.5105652e-1 }, { -8.0901699e-1, -5.8778525e-1 } }, - { { -1.0452846e-1, -9.9452190e-1 }, { -9.7814760e-1, 2.0791169e-1 } }, - { { -5.0000000e-1, -8.6602540e-1 }, { -5.0000000e-1, 8.6602540e-1 } }, - { { -8.0901699e-1, -5.8778525e-1 }, { 3.0901699e-1, 9.5105652e-1 } }, - { { -9.7814760e-1, -2.0791169e-1 }, { 9.1354546e-1, 4.0673664e-1 } }, - { { -9.7814760e-1, 2.0791169e-1 }, { 9.1354546e-1, -4.0673664e-1 } }, - { { -8.0901699e-1, 5.8778525e-1 }, { 3.0901699e-1, -9.5105652e-1 } }, - { { -5.0000000e-1, 8.6602540e-1 }, { -5.0000000e-1, -8.6602540e-1 } }, - { { -1.0452846e-1, 9.9452190e-1 }, { -9.7814760e-1, -2.0791169e-1 } }, - { { 3.0901699e-1, 9.5105652e-1 }, { -8.0901699e-1, 5.8778525e-1 } }, - { { 6.6913061e-1, 7.4314483e-1 }, { -1.0452846e-1, 9.9452190e-1 } }, - { { 9.1354546e-1, 4.0673664e-1 }, { 6.6913061e-1, 7.4314483e-1 } }, - } -}; - -static const struct lc3_fft_bf3_twiddles fft_twiddles_45 = { - .n3 = 45/3, .t = (const struct lc3_complex [][2]){ - { { 1.0000000e+0, -0.0000000e+0 }, { 1.0000000e+0, -0.0000000e+0 } }, - { { 9.9026807e-1, -1.3917310e-1 }, { 9.6126170e-1, -2.7563736e-1 } }, - { { 9.6126170e-1, -2.7563736e-1 }, { 8.4804810e-1, -5.2991926e-1 } }, - { { 9.1354546e-1, -4.0673664e-1 }, { 6.6913061e-1, -7.4314483e-1 } }, - { { 8.4804810e-1, -5.2991926e-1 }, { 4.3837115e-1, -8.9879405e-1 } }, - { { 7.6604444e-1, -6.4278761e-1 }, { 1.7364818e-1, -9.8480775e-1 } }, - { { 6.6913061e-1, -7.4314483e-1 }, { -1.0452846e-1, -9.9452190e-1 } }, - { { 5.5919290e-1, -8.2903757e-1 }, { -3.7460659e-1, -9.2718385e-1 } }, - { { 4.3837115e-1, -8.9879405e-1 }, { -6.1566148e-1, -7.8801075e-1 } }, - { { 3.0901699e-1, -9.5105652e-1 }, { -8.0901699e-1, -5.8778525e-1 } }, - { { 1.7364818e-1, -9.8480775e-1 }, { -9.3969262e-1, -3.4202014e-1 } }, - { { 3.4899497e-2, -9.9939083e-1 }, { -9.9756405e-1, -6.9756474e-2 } }, - { { -1.0452846e-1, -9.9452190e-1 }, { -9.7814760e-1, 2.0791169e-1 } }, - { { -2.4192190e-1, -9.7029573e-1 }, { -8.8294759e-1, 4.6947156e-1 } }, - { { -3.7460659e-1, -9.2718385e-1 }, { -7.1933980e-1, 6.9465837e-1 } }, - { { -5.0000000e-1, -8.6602540e-1 }, { -5.0000000e-1, 8.6602540e-1 } }, - { { -6.1566148e-1, -7.8801075e-1 }, { -2.4192190e-1, 9.7029573e-1 } }, - { { -7.1933980e-1, -6.9465837e-1 }, { 3.4899497e-2, 9.9939083e-1 } }, - { { -8.0901699e-1, -5.8778525e-1 }, { 3.0901699e-1, 9.5105652e-1 } }, - { { -8.8294759e-1, -4.6947156e-1 }, { 5.5919290e-1, 8.2903757e-1 } }, - { { -9.3969262e-1, -3.4202014e-1 }, { 7.6604444e-1, 6.4278761e-1 } }, - { { -9.7814760e-1, -2.0791169e-1 }, { 9.1354546e-1, 4.0673664e-1 } }, - { { -9.9756405e-1, -6.9756474e-2 }, { 9.9026807e-1, 1.3917310e-1 } }, - { { -9.9756405e-1, 6.9756474e-2 }, { 9.9026807e-1, -1.3917310e-1 } }, - { { -9.7814760e-1, 2.0791169e-1 }, { 9.1354546e-1, -4.0673664e-1 } }, - { { -9.3969262e-1, 3.4202014e-1 }, { 7.6604444e-1, -6.4278761e-1 } }, - { { -8.8294759e-1, 4.6947156e-1 }, { 5.5919290e-1, -8.2903757e-1 } }, - { { -8.0901699e-1, 5.8778525e-1 }, { 3.0901699e-1, -9.5105652e-1 } }, - { { -7.1933980e-1, 6.9465837e-1 }, { 3.4899497e-2, -9.9939083e-1 } }, - { { -6.1566148e-1, 7.8801075e-1 }, { -2.4192190e-1, -9.7029573e-1 } }, - { { -5.0000000e-1, 8.6602540e-1 }, { -5.0000000e-1, -8.6602540e-1 } }, - { { -3.7460659e-1, 9.2718385e-1 }, { -7.1933980e-1, -6.9465837e-1 } }, - { { -2.4192190e-1, 9.7029573e-1 }, { -8.8294759e-1, -4.6947156e-1 } }, - { { -1.0452846e-1, 9.9452190e-1 }, { -9.7814760e-1, -2.0791169e-1 } }, - { { 3.4899497e-2, 9.9939083e-1 }, { -9.9756405e-1, 6.9756474e-2 } }, - { { 1.7364818e-1, 9.8480775e-1 }, { -9.3969262e-1, 3.4202014e-1 } }, - { { 3.0901699e-1, 9.5105652e-1 }, { -8.0901699e-1, 5.8778525e-1 } }, - { { 4.3837115e-1, 8.9879405e-1 }, { -6.1566148e-1, 7.8801075e-1 } }, - { { 5.5919290e-1, 8.2903757e-1 }, { -3.7460659e-1, 9.2718385e-1 } }, - { { 6.6913061e-1, 7.4314483e-1 }, { -1.0452846e-1, 9.9452190e-1 } }, - { { 7.6604444e-1, 6.4278761e-1 }, { 1.7364818e-1, 9.8480775e-1 } }, - { { 8.4804810e-1, 5.2991926e-1 }, { 4.3837115e-1, 8.9879405e-1 } }, - { { 9.1354546e-1, 4.0673664e-1 }, { 6.6913061e-1, 7.4314483e-1 } }, - { { 9.6126170e-1, 2.7563736e-1 }, { 8.4804810e-1, 5.2991926e-1 } }, - { { 9.9026807e-1, 1.3917310e-1 }, { 9.6126170e-1, 2.7563736e-1 } }, - } -}; - -const struct lc3_fft_bf3_twiddles *lc3_fft_twiddles_bf3[] = - { &fft_twiddles_15, &fft_twiddles_45 }; - - -/** - * Twiddles FFT 2 points - * - * T[0..N/2-1] = - * cos(-2Pi * i/N) + j sin(-2Pi * i/N) , N=10, 20, ... - */ - -static const struct lc3_fft_bf2_twiddles fft_twiddles_10 = { - .n2 = 10/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 8.0901699e-01, -5.8778525e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { -3.0901699e-01, -9.5105652e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_20 = { - .n2 = 20/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.5105652e-01, -3.0901699e-01 }, - { 8.0901699e-01, -5.8778525e-01 }, { 5.8778525e-01, -8.0901699e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 6.1232340e-17, -1.0000000e+00 }, - { -3.0901699e-01, -9.5105652e-01 }, { -5.8778525e-01, -8.0901699e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -9.5105652e-01, -3.0901699e-01 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_30 = { - .n2 = 30/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.7814760e-01, -2.0791169e-01 }, - { 9.1354546e-01, -4.0673664e-01 }, { 8.0901699e-01, -5.8778525e-01 }, - { 6.6913061e-01, -7.4314483e-01 }, { 5.0000000e-01, -8.6602540e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 1.0452846e-01, -9.9452190e-01 }, - { -1.0452846e-01, -9.9452190e-01 }, { -3.0901699e-01, -9.5105652e-01 }, - { -5.0000000e-01, -8.6602540e-01 }, { -6.6913061e-01, -7.4314483e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -9.1354546e-01, -4.0673664e-01 }, - { -9.7814760e-01, -2.0791169e-01 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_40 = { - .n2 = 40/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.8768834e-01, -1.5643447e-01 }, - { 9.5105652e-01, -3.0901699e-01 }, { 8.9100652e-01, -4.5399050e-01 }, - { 8.0901699e-01, -5.8778525e-01 }, { 7.0710678e-01, -7.0710678e-01 }, - { 5.8778525e-01, -8.0901699e-01 }, { 4.5399050e-01, -8.9100652e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 1.5643447e-01, -9.8768834e-01 }, - { 6.1232340e-17, -1.0000000e+00 }, { -1.5643447e-01, -9.8768834e-01 }, - { -3.0901699e-01, -9.5105652e-01 }, { -4.5399050e-01, -8.9100652e-01 }, - { -5.8778525e-01, -8.0901699e-01 }, { -7.0710678e-01, -7.0710678e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -8.9100652e-01, -4.5399050e-01 }, - { -9.5105652e-01, -3.0901699e-01 }, { -9.8768834e-01, -1.5643447e-01 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_60 = { - .n2 = 60/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.9452190e-01, -1.0452846e-01 }, - { 9.7814760e-01, -2.0791169e-01 }, { 9.5105652e-01, -3.0901699e-01 }, - { 9.1354546e-01, -4.0673664e-01 }, { 8.6602540e-01, -5.0000000e-01 }, - { 8.0901699e-01, -5.8778525e-01 }, { 7.4314483e-01, -6.6913061e-01 }, - { 6.6913061e-01, -7.4314483e-01 }, { 5.8778525e-01, -8.0901699e-01 }, - { 5.0000000e-01, -8.6602540e-01 }, { 4.0673664e-01, -9.1354546e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 2.0791169e-01, -9.7814760e-01 }, - { 1.0452846e-01, -9.9452190e-01 }, { 2.8327694e-16, -1.0000000e+00 }, - { -1.0452846e-01, -9.9452190e-01 }, { -2.0791169e-01, -9.7814760e-01 }, - { -3.0901699e-01, -9.5105652e-01 }, { -4.0673664e-01, -9.1354546e-01 }, - { -5.0000000e-01, -8.6602540e-01 }, { -5.8778525e-01, -8.0901699e-01 }, - { -6.6913061e-01, -7.4314483e-01 }, { -7.4314483e-01, -6.6913061e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -8.6602540e-01, -5.0000000e-01 }, - { -9.1354546e-01, -4.0673664e-01 }, { -9.5105652e-01, -3.0901699e-01 }, - { -9.7814760e-01, -2.0791169e-01 }, { -9.9452190e-01, -1.0452846e-01 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_80 = { - .n2 = 80/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.9691733e-01, -7.8459096e-02 }, - { 9.8768834e-01, -1.5643447e-01 }, { 9.7236992e-01, -2.3344536e-01 }, - { 9.5105652e-01, -3.0901699e-01 }, { 9.2387953e-01, -3.8268343e-01 }, - { 8.9100652e-01, -4.5399050e-01 }, { 8.5264016e-01, -5.2249856e-01 }, - { 8.0901699e-01, -5.8778525e-01 }, { 7.6040597e-01, -6.4944805e-01 }, - { 7.0710678e-01, -7.0710678e-01 }, { 6.4944805e-01, -7.6040597e-01 }, - { 5.8778525e-01, -8.0901699e-01 }, { 5.2249856e-01, -8.5264016e-01 }, - { 4.5399050e-01, -8.9100652e-01 }, { 3.8268343e-01, -9.2387953e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 2.3344536e-01, -9.7236992e-01 }, - { 1.5643447e-01, -9.8768834e-01 }, { 7.8459096e-02, -9.9691733e-01 }, - { 6.1232340e-17, -1.0000000e+00 }, { -7.8459096e-02, -9.9691733e-01 }, - { -1.5643447e-01, -9.8768834e-01 }, { -2.3344536e-01, -9.7236992e-01 }, - { -3.0901699e-01, -9.5105652e-01 }, { -3.8268343e-01, -9.2387953e-01 }, - { -4.5399050e-01, -8.9100652e-01 }, { -5.2249856e-01, -8.5264016e-01 }, - { -5.8778525e-01, -8.0901699e-01 }, { -6.4944805e-01, -7.6040597e-01 }, - { -7.0710678e-01, -7.0710678e-01 }, { -7.6040597e-01, -6.4944805e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -8.5264016e-01, -5.2249856e-01 }, - { -8.9100652e-01, -4.5399050e-01 }, { -9.2387953e-01, -3.8268343e-01 }, - { -9.5105652e-01, -3.0901699e-01 }, { -9.7236992e-01, -2.3344536e-01 }, - { -9.8768834e-01, -1.5643447e-01 }, { -9.9691733e-01, -7.8459096e-02 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_90 = { - .n2 = 90/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.9756405e-01, -6.9756474e-02 }, - { 9.9026807e-01, -1.3917310e-01 }, { 9.7814760e-01, -2.0791169e-01 }, - { 9.6126170e-01, -2.7563736e-01 }, { 9.3969262e-01, -3.4202014e-01 }, - { 9.1354546e-01, -4.0673664e-01 }, { 8.8294759e-01, -4.6947156e-01 }, - { 8.4804810e-01, -5.2991926e-01 }, { 8.0901699e-01, -5.8778525e-01 }, - { 7.6604444e-01, -6.4278761e-01 }, { 7.1933980e-01, -6.9465837e-01 }, - { 6.6913061e-01, -7.4314483e-01 }, { 6.1566148e-01, -7.8801075e-01 }, - { 5.5919290e-01, -8.2903757e-01 }, { 5.0000000e-01, -8.6602540e-01 }, - { 4.3837115e-01, -8.9879405e-01 }, { 3.7460659e-01, -9.2718385e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 2.4192190e-01, -9.7029573e-01 }, - { 1.7364818e-01, -9.8480775e-01 }, { 1.0452846e-01, -9.9452190e-01 }, - { 3.4899497e-02, -9.9939083e-01 }, { -3.4899497e-02, -9.9939083e-01 }, - { -1.0452846e-01, -9.9452190e-01 }, { -1.7364818e-01, -9.8480775e-01 }, - { -2.4192190e-01, -9.7029573e-01 }, { -3.0901699e-01, -9.5105652e-01 }, - { -3.7460659e-01, -9.2718385e-01 }, { -4.3837115e-01, -8.9879405e-01 }, - { -5.0000000e-01, -8.6602540e-01 }, { -5.5919290e-01, -8.2903757e-01 }, - { -6.1566148e-01, -7.8801075e-01 }, { -6.6913061e-01, -7.4314483e-01 }, - { -7.1933980e-01, -6.9465837e-01 }, { -7.6604444e-01, -6.4278761e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -8.4804810e-01, -5.2991926e-01 }, - { -8.8294759e-01, -4.6947156e-01 }, { -9.1354546e-01, -4.0673664e-01 }, - { -9.3969262e-01, -3.4202014e-01 }, { -9.6126170e-01, -2.7563736e-01 }, - { -9.7814760e-01, -2.0791169e-01 }, { -9.9026807e-01, -1.3917310e-01 }, - { -9.9756405e-01, -6.9756474e-02 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_120 = { - .n2 = 120/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.9862953e-01, -5.2335956e-02 }, - { 9.9452190e-01, -1.0452846e-01 }, { 9.8768834e-01, -1.5643447e-01 }, - { 9.7814760e-01, -2.0791169e-01 }, { 9.6592583e-01, -2.5881905e-01 }, - { 9.5105652e-01, -3.0901699e-01 }, { 9.3358043e-01, -3.5836795e-01 }, - { 9.1354546e-01, -4.0673664e-01 }, { 8.9100652e-01, -4.5399050e-01 }, - { 8.6602540e-01, -5.0000000e-01 }, { 8.3867057e-01, -5.4463904e-01 }, - { 8.0901699e-01, -5.8778525e-01 }, { 7.7714596e-01, -6.2932039e-01 }, - { 7.4314483e-01, -6.6913061e-01 }, { 7.0710678e-01, -7.0710678e-01 }, - { 6.6913061e-01, -7.4314483e-01 }, { 6.2932039e-01, -7.7714596e-01 }, - { 5.8778525e-01, -8.0901699e-01 }, { 5.4463904e-01, -8.3867057e-01 }, - { 5.0000000e-01, -8.6602540e-01 }, { 4.5399050e-01, -8.9100652e-01 }, - { 4.0673664e-01, -9.1354546e-01 }, { 3.5836795e-01, -9.3358043e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 2.5881905e-01, -9.6592583e-01 }, - { 2.0791169e-01, -9.7814760e-01 }, { 1.5643447e-01, -9.8768834e-01 }, - { 1.0452846e-01, -9.9452190e-01 }, { 5.2335956e-02, -9.9862953e-01 }, - { 2.8327694e-16, -1.0000000e+00 }, { -5.2335956e-02, -9.9862953e-01 }, - { -1.0452846e-01, -9.9452190e-01 }, { -1.5643447e-01, -9.8768834e-01 }, - { -2.0791169e-01, -9.7814760e-01 }, { -2.5881905e-01, -9.6592583e-01 }, - { -3.0901699e-01, -9.5105652e-01 }, { -3.5836795e-01, -9.3358043e-01 }, - { -4.0673664e-01, -9.1354546e-01 }, { -4.5399050e-01, -8.9100652e-01 }, - { -5.0000000e-01, -8.6602540e-01 }, { -5.4463904e-01, -8.3867057e-01 }, - { -5.8778525e-01, -8.0901699e-01 }, { -6.2932039e-01, -7.7714596e-01 }, - { -6.6913061e-01, -7.4314483e-01 }, { -7.0710678e-01, -7.0710678e-01 }, - { -7.4314483e-01, -6.6913061e-01 }, { -7.7714596e-01, -6.2932039e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -8.3867057e-01, -5.4463904e-01 }, - { -8.6602540e-01, -5.0000000e-01 }, { -8.9100652e-01, -4.5399050e-01 }, - { -9.1354546e-01, -4.0673664e-01 }, { -9.3358043e-01, -3.5836795e-01 }, - { -9.5105652e-01, -3.0901699e-01 }, { -9.6592583e-01, -2.5881905e-01 }, - { -9.7814760e-01, -2.0791169e-01 }, { -9.8768834e-01, -1.5643447e-01 }, - { -9.9452190e-01, -1.0452846e-01 }, { -9.9862953e-01, -5.2335956e-02 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_160 = { - .n2 = 160/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.9922904e-01, -3.9259816e-02 }, - { 9.9691733e-01, -7.8459096e-02 }, { 9.9306846e-01, -1.1753740e-01 }, - { 9.8768834e-01, -1.5643447e-01 }, { 9.8078528e-01, -1.9509032e-01 }, - { 9.7236992e-01, -2.3344536e-01 }, { 9.6245524e-01, -2.7144045e-01 }, - { 9.5105652e-01, -3.0901699e-01 }, { 9.3819134e-01, -3.4611706e-01 }, - { 9.2387953e-01, -3.8268343e-01 }, { 9.0814317e-01, -4.1865974e-01 }, - { 8.9100652e-01, -4.5399050e-01 }, { 8.7249601e-01, -4.8862124e-01 }, - { 8.5264016e-01, -5.2249856e-01 }, { 8.3146961e-01, -5.5557023e-01 }, - { 8.0901699e-01, -5.8778525e-01 }, { 7.8531693e-01, -6.1909395e-01 }, - { 7.6040597e-01, -6.4944805e-01 }, { 7.3432251e-01, -6.7880075e-01 }, - { 7.0710678e-01, -7.0710678e-01 }, { 6.7880075e-01, -7.3432251e-01 }, - { 6.4944805e-01, -7.6040597e-01 }, { 6.1909395e-01, -7.8531693e-01 }, - { 5.8778525e-01, -8.0901699e-01 }, { 5.5557023e-01, -8.3146961e-01 }, - { 5.2249856e-01, -8.5264016e-01 }, { 4.8862124e-01, -8.7249601e-01 }, - { 4.5399050e-01, -8.9100652e-01 }, { 4.1865974e-01, -9.0814317e-01 }, - { 3.8268343e-01, -9.2387953e-01 }, { 3.4611706e-01, -9.3819134e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 2.7144045e-01, -9.6245524e-01 }, - { 2.3344536e-01, -9.7236992e-01 }, { 1.9509032e-01, -9.8078528e-01 }, - { 1.5643447e-01, -9.8768834e-01 }, { 1.1753740e-01, -9.9306846e-01 }, - { 7.8459096e-02, -9.9691733e-01 }, { 3.9259816e-02, -9.9922904e-01 }, - { 6.1232340e-17, -1.0000000e+00 }, { -3.9259816e-02, -9.9922904e-01 }, - { -7.8459096e-02, -9.9691733e-01 }, { -1.1753740e-01, -9.9306846e-01 }, - { -1.5643447e-01, -9.8768834e-01 }, { -1.9509032e-01, -9.8078528e-01 }, - { -2.3344536e-01, -9.7236992e-01 }, { -2.7144045e-01, -9.6245524e-01 }, - { -3.0901699e-01, -9.5105652e-01 }, { -3.4611706e-01, -9.3819134e-01 }, - { -3.8268343e-01, -9.2387953e-01 }, { -4.1865974e-01, -9.0814317e-01 }, - { -4.5399050e-01, -8.9100652e-01 }, { -4.8862124e-01, -8.7249601e-01 }, - { -5.2249856e-01, -8.5264016e-01 }, { -5.5557023e-01, -8.3146961e-01 }, - { -5.8778525e-01, -8.0901699e-01 }, { -6.1909395e-01, -7.8531693e-01 }, - { -6.4944805e-01, -7.6040597e-01 }, { -6.7880075e-01, -7.3432251e-01 }, - { -7.0710678e-01, -7.0710678e-01 }, { -7.3432251e-01, -6.7880075e-01 }, - { -7.6040597e-01, -6.4944805e-01 }, { -7.8531693e-01, -6.1909395e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -8.3146961e-01, -5.5557023e-01 }, - { -8.5264016e-01, -5.2249856e-01 }, { -8.7249601e-01, -4.8862124e-01 }, - { -8.9100652e-01, -4.5399050e-01 }, { -9.0814317e-01, -4.1865974e-01 }, - { -9.2387953e-01, -3.8268343e-01 }, { -9.3819134e-01, -3.4611706e-01 }, - { -9.5105652e-01, -3.0901699e-01 }, { -9.6245524e-01, -2.7144045e-01 }, - { -9.7236992e-01, -2.3344536e-01 }, { -9.8078528e-01, -1.9509032e-01 }, - { -9.8768834e-01, -1.5643447e-01 }, { -9.9306846e-01, -1.1753740e-01 }, - { -9.9691733e-01, -7.8459096e-02 }, { -9.9922904e-01, -3.9259816e-02 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_180 = { - .n2 = 180/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.9939083e-01, -3.4899497e-02 }, - { 9.9756405e-01, -6.9756474e-02 }, { 9.9452190e-01, -1.0452846e-01 }, - { 9.9026807e-01, -1.3917310e-01 }, { 9.8480775e-01, -1.7364818e-01 }, - { 9.7814760e-01, -2.0791169e-01 }, { 9.7029573e-01, -2.4192190e-01 }, - { 9.6126170e-01, -2.7563736e-01 }, { 9.5105652e-01, -3.0901699e-01 }, - { 9.3969262e-01, -3.4202014e-01 }, { 9.2718385e-01, -3.7460659e-01 }, - { 9.1354546e-01, -4.0673664e-01 }, { 8.9879405e-01, -4.3837115e-01 }, - { 8.8294759e-01, -4.6947156e-01 }, { 8.6602540e-01, -5.0000000e-01 }, - { 8.4804810e-01, -5.2991926e-01 }, { 8.2903757e-01, -5.5919290e-01 }, - { 8.0901699e-01, -5.8778525e-01 }, { 7.8801075e-01, -6.1566148e-01 }, - { 7.6604444e-01, -6.4278761e-01 }, { 7.4314483e-01, -6.6913061e-01 }, - { 7.1933980e-01, -6.9465837e-01 }, { 6.9465837e-01, -7.1933980e-01 }, - { 6.6913061e-01, -7.4314483e-01 }, { 6.4278761e-01, -7.6604444e-01 }, - { 6.1566148e-01, -7.8801075e-01 }, { 5.8778525e-01, -8.0901699e-01 }, - { 5.5919290e-01, -8.2903757e-01 }, { 5.2991926e-01, -8.4804810e-01 }, - { 5.0000000e-01, -8.6602540e-01 }, { 4.6947156e-01, -8.8294759e-01 }, - { 4.3837115e-01, -8.9879405e-01 }, { 4.0673664e-01, -9.1354546e-01 }, - { 3.7460659e-01, -9.2718385e-01 }, { 3.4202014e-01, -9.3969262e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 2.7563736e-01, -9.6126170e-01 }, - { 2.4192190e-01, -9.7029573e-01 }, { 2.0791169e-01, -9.7814760e-01 }, - { 1.7364818e-01, -9.8480775e-01 }, { 1.3917310e-01, -9.9026807e-01 }, - { 1.0452846e-01, -9.9452190e-01 }, { 6.9756474e-02, -9.9756405e-01 }, - { 3.4899497e-02, -9.9939083e-01 }, { 6.1232340e-17, -1.0000000e+00 }, - { -3.4899497e-02, -9.9939083e-01 }, { -6.9756474e-02, -9.9756405e-01 }, - { -1.0452846e-01, -9.9452190e-01 }, { -1.3917310e-01, -9.9026807e-01 }, - { -1.7364818e-01, -9.8480775e-01 }, { -2.0791169e-01, -9.7814760e-01 }, - { -2.4192190e-01, -9.7029573e-01 }, { -2.7563736e-01, -9.6126170e-01 }, - { -3.0901699e-01, -9.5105652e-01 }, { -3.4202014e-01, -9.3969262e-01 }, - { -3.7460659e-01, -9.2718385e-01 }, { -4.0673664e-01, -9.1354546e-01 }, - { -4.3837115e-01, -8.9879405e-01 }, { -4.6947156e-01, -8.8294759e-01 }, - { -5.0000000e-01, -8.6602540e-01 }, { -5.2991926e-01, -8.4804810e-01 }, - { -5.5919290e-01, -8.2903757e-01 }, { -5.8778525e-01, -8.0901699e-01 }, - { -6.1566148e-01, -7.8801075e-01 }, { -6.4278761e-01, -7.6604444e-01 }, - { -6.6913061e-01, -7.4314483e-01 }, { -6.9465837e-01, -7.1933980e-01 }, - { -7.1933980e-01, -6.9465837e-01 }, { -7.4314483e-01, -6.6913061e-01 }, - { -7.6604444e-01, -6.4278761e-01 }, { -7.8801075e-01, -6.1566148e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -8.2903757e-01, -5.5919290e-01 }, - { -8.4804810e-01, -5.2991926e-01 }, { -8.6602540e-01, -5.0000000e-01 }, - { -8.8294759e-01, -4.6947156e-01 }, { -8.9879405e-01, -4.3837115e-01 }, - { -9.1354546e-01, -4.0673664e-01 }, { -9.2718385e-01, -3.7460659e-01 }, - { -9.3969262e-01, -3.4202014e-01 }, { -9.5105652e-01, -3.0901699e-01 }, - { -9.6126170e-01, -2.7563736e-01 }, { -9.7029573e-01, -2.4192190e-01 }, - { -9.7814760e-01, -2.0791169e-01 }, { -9.8480775e-01, -1.7364818e-01 }, - { -9.9026807e-01, -1.3917310e-01 }, { -9.9452190e-01, -1.0452846e-01 }, - { -9.9756405e-01, -6.9756474e-02 }, { -9.9939083e-01, -3.4899497e-02 }, - } -}; - -static const struct lc3_fft_bf2_twiddles fft_twiddles_240 = { - .n2 = 240/2, .t = (const struct lc3_complex []){ - { 1.0000000e+00, -0.0000000e+00 }, { 9.9965732e-01, -2.6176948e-02 }, - { 9.9862953e-01, -5.2335956e-02 }, { 9.9691733e-01, -7.8459096e-02 }, - { 9.9452190e-01, -1.0452846e-01 }, { 9.9144486e-01, -1.3052619e-01 }, - { 9.8768834e-01, -1.5643447e-01 }, { 9.8325491e-01, -1.8223553e-01 }, - { 9.7814760e-01, -2.0791169e-01 }, { 9.7236992e-01, -2.3344536e-01 }, - { 9.6592583e-01, -2.5881905e-01 }, { 9.5881973e-01, -2.8401534e-01 }, - { 9.5105652e-01, -3.0901699e-01 }, { 9.4264149e-01, -3.3380686e-01 }, - { 9.3358043e-01, -3.5836795e-01 }, { 9.2387953e-01, -3.8268343e-01 }, - { 9.1354546e-01, -4.0673664e-01 }, { 9.0258528e-01, -4.3051110e-01 }, - { 8.9100652e-01, -4.5399050e-01 }, { 8.7881711e-01, -4.7715876e-01 }, - { 8.6602540e-01, -5.0000000e-01 }, { 8.5264016e-01, -5.2249856e-01 }, - { 8.3867057e-01, -5.4463904e-01 }, { 8.2412619e-01, -5.6640624e-01 }, - { 8.0901699e-01, -5.8778525e-01 }, { 7.9335334e-01, -6.0876143e-01 }, - { 7.7714596e-01, -6.2932039e-01 }, { 7.6040597e-01, -6.4944805e-01 }, - { 7.4314483e-01, -6.6913061e-01 }, { 7.2537437e-01, -6.8835458e-01 }, - { 7.0710678e-01, -7.0710678e-01 }, { 6.8835458e-01, -7.2537437e-01 }, - { 6.6913061e-01, -7.4314483e-01 }, { 6.4944805e-01, -7.6040597e-01 }, - { 6.2932039e-01, -7.7714596e-01 }, { 6.0876143e-01, -7.9335334e-01 }, - { 5.8778525e-01, -8.0901699e-01 }, { 5.6640624e-01, -8.2412619e-01 }, - { 5.4463904e-01, -8.3867057e-01 }, { 5.2249856e-01, -8.5264016e-01 }, - { 5.0000000e-01, -8.6602540e-01 }, { 4.7715876e-01, -8.7881711e-01 }, - { 4.5399050e-01, -8.9100652e-01 }, { 4.3051110e-01, -9.0258528e-01 }, - { 4.0673664e-01, -9.1354546e-01 }, { 3.8268343e-01, -9.2387953e-01 }, - { 3.5836795e-01, -9.3358043e-01 }, { 3.3380686e-01, -9.4264149e-01 }, - { 3.0901699e-01, -9.5105652e-01 }, { 2.8401534e-01, -9.5881973e-01 }, - { 2.5881905e-01, -9.6592583e-01 }, { 2.3344536e-01, -9.7236992e-01 }, - { 2.0791169e-01, -9.7814760e-01 }, { 1.8223553e-01, -9.8325491e-01 }, - { 1.5643447e-01, -9.8768834e-01 }, { 1.3052619e-01, -9.9144486e-01 }, - { 1.0452846e-01, -9.9452190e-01 }, { 7.8459096e-02, -9.9691733e-01 }, - { 5.2335956e-02, -9.9862953e-01 }, { 2.6176948e-02, -9.9965732e-01 }, - { 2.8327694e-16, -1.0000000e+00 }, { -2.6176948e-02, -9.9965732e-01 }, - { -5.2335956e-02, -9.9862953e-01 }, { -7.8459096e-02, -9.9691733e-01 }, - { -1.0452846e-01, -9.9452190e-01 }, { -1.3052619e-01, -9.9144486e-01 }, - { -1.5643447e-01, -9.8768834e-01 }, { -1.8223553e-01, -9.8325491e-01 }, - { -2.0791169e-01, -9.7814760e-01 }, { -2.3344536e-01, -9.7236992e-01 }, - { -2.5881905e-01, -9.6592583e-01 }, { -2.8401534e-01, -9.5881973e-01 }, - { -3.0901699e-01, -9.5105652e-01 }, { -3.3380686e-01, -9.4264149e-01 }, - { -3.5836795e-01, -9.3358043e-01 }, { -3.8268343e-01, -9.2387953e-01 }, - { -4.0673664e-01, -9.1354546e-01 }, { -4.3051110e-01, -9.0258528e-01 }, - { -4.5399050e-01, -8.9100652e-01 }, { -4.7715876e-01, -8.7881711e-01 }, - { -5.0000000e-01, -8.6602540e-01 }, { -5.2249856e-01, -8.5264016e-01 }, - { -5.4463904e-01, -8.3867057e-01 }, { -5.6640624e-01, -8.2412619e-01 }, - { -5.8778525e-01, -8.0901699e-01 }, { -6.0876143e-01, -7.9335334e-01 }, - { -6.2932039e-01, -7.7714596e-01 }, { -6.4944805e-01, -7.6040597e-01 }, - { -6.6913061e-01, -7.4314483e-01 }, { -6.8835458e-01, -7.2537437e-01 }, - { -7.0710678e-01, -7.0710678e-01 }, { -7.2537437e-01, -6.8835458e-01 }, - { -7.4314483e-01, -6.6913061e-01 }, { -7.6040597e-01, -6.4944805e-01 }, - { -7.7714596e-01, -6.2932039e-01 }, { -7.9335334e-01, -6.0876143e-01 }, - { -8.0901699e-01, -5.8778525e-01 }, { -8.2412619e-01, -5.6640624e-01 }, - { -8.3867057e-01, -5.4463904e-01 }, { -8.5264016e-01, -5.2249856e-01 }, - { -8.6602540e-01, -5.0000000e-01 }, { -8.7881711e-01, -4.7715876e-01 }, - { -8.9100652e-01, -4.5399050e-01 }, { -9.0258528e-01, -4.3051110e-01 }, - { -9.1354546e-01, -4.0673664e-01 }, { -9.2387953e-01, -3.8268343e-01 }, - { -9.3358043e-01, -3.5836795e-01 }, { -9.4264149e-01, -3.3380686e-01 }, - { -9.5105652e-01, -3.0901699e-01 }, { -9.5881973e-01, -2.8401534e-01 }, - { -9.6592583e-01, -2.5881905e-01 }, { -9.7236992e-01, -2.3344536e-01 }, - { -9.7814760e-01, -2.0791169e-01 }, { -9.8325491e-01, -1.8223553e-01 }, - { -9.8768834e-01, -1.5643447e-01 }, { -9.9144486e-01, -1.3052619e-01 }, - { -9.9452190e-01, -1.0452846e-01 }, { -9.9691733e-01, -7.8459096e-02 }, - { -9.9862953e-01, -5.2335956e-02 }, { -9.9965732e-01, -2.6176948e-02 }, - } -}; - -const struct lc3_fft_bf2_twiddles *lc3_fft_twiddles_bf2[][3] = { - { &fft_twiddles_10 , &fft_twiddles_30 , &fft_twiddles_90 }, - { &fft_twiddles_20 , &fft_twiddles_60 , &fft_twiddles_180 }, - { &fft_twiddles_40 , &fft_twiddles_120 }, - { &fft_twiddles_80 , &fft_twiddles_240 }, - { &fft_twiddles_160 } -}; - - -/** - * MDCT Rotation twiddles - * - * 2Pi (n + 1/8) / N - * W[n] = e , n = [0..N/4-1] - */ - -static const struct lc3_mdct_rot_def mdct_rot_120 = { - .n4 = 120/4, .w = (const struct lc3_complex []){ - { 9.9997858e-01, 6.5449380e-03 }, { 9.9826561e-01, 5.8870804e-02 }, - { 9.9381646e-01, 1.1103531e-01 }, { 9.8664333e-01, 1.6289547e-01 }, - { 9.7676588e-01, 2.1430915e-01 }, { 9.6421118e-01, 2.6513543e-01 }, - { 9.4901365e-01, 3.1523498e-01 }, { 9.3121493e-01, 3.6447050e-01 }, - { 9.1086382e-01, 4.1270703e-01 }, { 8.8801610e-01, 4.5981236e-01 }, - { 8.6273439e-01, 5.0565737e-01 }, { 8.3508798e-01, 5.5011642e-01 }, - { 8.0515265e-01, 5.9306763e-01 }, { 7.7301045e-01, 6.3439328e-01 }, - { 7.3874949e-01, 6.7398011e-01 }, { 7.0246367e-01, 7.1171961e-01 }, - { 6.6425244e-01, 7.4750833e-01 }, { 6.2422054e-01, 7.8124818e-01 }, - { 5.8247770e-01, 8.1284668e-01 }, { 5.3913832e-01, 8.4221723e-01 }, - { 4.9432121e-01, 8.6927932e-01 }, { 4.4814919e-01, 8.9395878e-01 }, - { 4.0074883e-01, 9.1618796e-01 }, { 3.5225005e-01, 9.3590593e-01 }, - { 3.0278577e-01, 9.5305864e-01 }, { 2.5249158e-01, 9.6759909e-01 }, - { 2.0150532e-01, 9.7948742e-01 }, { 1.4996676e-01, 9.8869104e-01 }, - { 9.8017140e-02, 9.9518473e-01 }, { 4.5798867e-02, 9.9895068e-01 }, - } -}; - -static const struct lc3_mdct_rot_def mdct_rot_160 = { - .n4 = 160/4, .w = (const struct lc3_complex []){ - { 9.9998795e-01, 4.9087188e-03 }, { 9.9902428e-01, 4.4164277e-02 }, - { 9.9652019e-01, 8.3351737e-02 }, { 9.9247953e-01, 1.2241068e-01 }, - { 9.8690855e-01, 1.6128086e-01 }, { 9.7981582e-01, 1.9990237e-01 }, - { 9.7121229e-01, 2.3821564e-01 }, { 9.6111122e-01, 2.7616160e-01 }, - { 9.4952818e-01, 3.1368174e-01 }, { 9.3648104e-01, 3.5071820e-01 }, - { 9.2198992e-01, 3.8721389e-01 }, { 9.0607715e-01, 4.2311251e-01 }, - { 8.8876728e-01, 4.5835873e-01 }, { 8.7008699e-01, 4.9289819e-01 }, - { 8.5006509e-01, 5.2667764e-01 }, { 8.2873246e-01, 5.5964499e-01 }, - { 8.0612197e-01, 5.9174941e-01 }, { 7.8226851e-01, 6.2294139e-01 }, - { 7.5720885e-01, 6.5317284e-01 }, { 7.3098162e-01, 6.8239715e-01 }, - { 7.0362727e-01, 7.1056925e-01 }, { 6.7518798e-01, 7.3764570e-01 }, - { 6.4570760e-01, 7.6358476e-01 }, { 6.1523159e-01, 7.8834643e-01 }, - { 5.8380693e-01, 8.1189252e-01 }, { 5.5148209e-01, 8.3418673e-01 }, - { 5.1830690e-01, 8.5519469e-01 }, { 4.8433252e-01, 8.7488400e-01 }, - { 4.4961133e-01, 8.9322430e-01 }, { 4.1419687e-01, 9.1018732e-01 }, - { 3.7814376e-01, 9.2574689e-01 }, { 3.4150757e-01, 9.3987902e-01 }, - { 3.0434480e-01, 9.5256194e-01 }, { 2.6671276e-01, 9.6377607e-01 }, - { 2.2866946e-01, 9.7350412e-01 }, { 1.9027357e-01, 9.8173111e-01 }, - { 1.5158430e-01, 9.8844433e-01 }, { 1.1266129e-01, 9.9363345e-01 }, - { 7.3564564e-02, 9.9729046e-01 }, { 3.4354408e-02, 9.9940971e-01 }, - } -}; - -static const struct lc3_mdct_rot_def mdct_rot_240 = { - .n4 = 240/4, .w = (const struct lc3_complex []){ - { 9.9999465e-01, 3.2724865e-03 }, { 9.9956631e-01, 2.9448173e-02 }, - { 9.9845292e-01, 5.5603678e-02 }, { 9.9665524e-01, 8.1721074e-02 }, - { 9.9417450e-01, 1.0778246e-01 }, { 9.9101241e-01, 1.3376998e-01 }, - { 9.8717112e-01, 1.5966582e-01 }, { 9.8265328e-01, 1.8545224e-01 }, - { 9.7746197e-01, 2.1111155e-01 }, { 9.7160077e-01, 2.3662618e-01 }, - { 9.6507367e-01, 2.6197864e-01 }, { 9.5788516e-01, 2.8715155e-01 }, - { 9.5004017e-01, 3.1212766e-01 }, { 9.4154407e-01, 3.3688985e-01 }, - { 9.3240267e-01, 3.6142116e-01 }, { 9.2262226e-01, 3.8570477e-01 }, - { 9.1220953e-01, 4.0972403e-01 }, { 9.0117161e-01, 4.3346249e-01 }, - { 8.8951608e-01, 4.5690388e-01 }, { 8.7725091e-01, 4.8003212e-01 }, - { 8.6438452e-01, 5.0283138e-01 }, { 8.5092573e-01, 5.2528602e-01 }, - { 8.3688375e-01, 5.4738066e-01 }, { 8.2226822e-01, 5.6910015e-01 }, - { 8.0708914e-01, 5.9042960e-01 }, { 7.9135693e-01, 6.1135441e-01 }, - { 7.7508236e-01, 6.3186022e-01 }, { 7.5827658e-01, 6.5193299e-01 }, - { 7.4095113e-01, 6.7155895e-01 }, { 7.2311786e-01, 6.9072467e-01 }, - { 7.0478900e-01, 7.0941699e-01 }, { 6.8597711e-01, 7.2762312e-01 }, - { 6.6669509e-01, 7.4533057e-01 }, { 6.4695615e-01, 7.6252720e-01 }, - { 6.2677382e-01, 7.7920124e-01 }, { 6.0616193e-01, 7.9534126e-01 }, - { 5.8513461e-01, 8.1093618e-01 }, { 5.6370626e-01, 8.2597533e-01 }, - { 5.4189158e-01, 8.4044840e-01 }, { 5.1970551e-01, 8.5434547e-01 }, - { 4.9716327e-01, 8.6765701e-01 }, { 4.7428029e-01, 8.8037390e-01 }, - { 4.5107226e-01, 8.9248743e-01 }, { 4.2755509e-01, 9.0398929e-01 }, - { 4.0374490e-01, 9.1487161e-01 }, { 3.7965800e-01, 9.2512691e-01 }, - { 3.5531090e-01, 9.3474818e-01 }, { 3.3072029e-01, 9.4372882e-01 }, - { 3.0590302e-01, 9.5206268e-01 }, { 2.8087610e-01, 9.5974404e-01 }, - { 2.5565668e-01, 9.6676764e-01 }, { 2.3026205e-01, 9.7312866e-01 }, - { 2.0470960e-01, 9.7882275e-01 }, { 1.7901686e-01, 9.8384601e-01 }, - { 1.5320143e-01, 9.8819498e-01 }, { 1.2728100e-01, 9.9186670e-01 }, - { 1.0127334e-01, 9.9485864e-01 }, { 7.5196277e-02, 9.9716875e-01 }, - { 4.9067674e-02, 9.9879546e-01 }, { 2.2905443e-02, 9.9973764e-01 }, - } -}; - -static const struct lc3_mdct_rot_def mdct_rot_320 = { - .n4 = 320/4, .w = (const struct lc3_complex []){ - { 9.9999699e-01, 2.4543668e-03 }, { 9.9975604e-01, 2.2087527e-02 }, - { 9.9912967e-01, 4.1712172e-02 }, { 9.9811811e-01, 6.1320736e-02 }, - { 9.9672176e-01, 8.0905660e-02 }, { 9.9494116e-01, 1.0045939e-01 }, - { 9.9277699e-01, 1.1997440e-01 }, { 9.9023008e-01, 1.3944315e-01 }, - { 9.8730142e-01, 1.5885814e-01 }, { 9.8399213e-01, 1.7821189e-01 }, - { 9.8030350e-01, 1.9749694e-01 }, { 9.7623695e-01, 2.1670585e-01 }, - { 9.7179403e-01, 2.3583121e-01 }, { 9.6697647e-01, 2.5486566e-01 }, - { 9.6178612e-01, 2.7380185e-01 }, { 9.5622499e-01, 2.9263249e-01 }, - { 9.5029521e-01, 3.1135031e-01 }, { 9.4399908e-01, 3.2994809e-01 }, - { 9.3733901e-01, 3.4841868e-01 }, { 9.3031759e-01, 3.6675495e-01 }, - { 9.2293750e-01, 3.8494982e-01 }, { 9.1520161e-01, 4.0299629e-01 }, - { 9.0711289e-01, 4.2088739e-01 }, { 8.9867447e-01, 4.3861624e-01 }, - { 8.8988958e-01, 4.5617599e-01 }, { 8.8076163e-01, 4.7355988e-01 }, - { 8.7129412e-01, 4.9076120e-01 }, { 8.6149072e-01, 5.0777332e-01 }, - { 8.5135519e-01, 5.2458968e-01 }, { 8.4089145e-01, 5.4120381e-01 }, - { 8.3010353e-01, 5.5760929e-01 }, { 8.1899560e-01, 5.7379980e-01 }, - { 8.0757192e-01, 5.8976911e-01 }, { 7.9583690e-01, 6.0551104e-01 }, - { 7.8379508e-01, 6.2101954e-01 }, { 7.7145109e-01, 6.3628862e-01 }, - { 7.5880969e-01, 6.5131241e-01 }, { 7.4587576e-01, 6.6608510e-01 }, - { 7.3265427e-01, 6.8060100e-01 }, { 7.1915033e-01, 6.9485451e-01 }, - { 7.0536915e-01, 7.0884015e-01 }, { 6.9131604e-01, 7.2255252e-01 }, - { 6.7699640e-01, 7.3598632e-01 }, { 6.6241578e-01, 7.4913639e-01 }, - { 6.4757978e-01, 7.6199766e-01 }, { 6.3249412e-01, 7.7456516e-01 }, - { 6.1716463e-01, 7.8683405e-01 }, { 6.0159721e-01, 7.9879960e-01 }, - { 5.8579786e-01, 8.1045720e-01 }, { 5.6977267e-01, 8.2180235e-01 }, - { 5.5352783e-01, 8.3283068e-01 }, { 5.3706959e-01, 8.4353794e-01 }, - { 5.2040430e-01, 8.5392000e-01 }, { 5.0353838e-01, 8.6397286e-01 }, - { 4.8647834e-01, 8.7369263e-01 }, { 4.6923076e-01, 8.8307559e-01 }, - { 4.5180228e-01, 8.9211810e-01 }, { 4.3419961e-01, 9.0081668e-01 }, - { 4.1642956e-01, 9.0916798e-01 }, { 3.9849896e-01, 9.1716878e-01 }, - { 3.8041474e-01, 9.2481600e-01 }, { 3.6218386e-01, 9.3210667e-01 }, - { 3.4381335e-01, 9.3903801e-01 }, { 3.2531029e-01, 9.4560733e-01 }, - { 3.0668182e-01, 9.5181209e-01 }, { 2.8793512e-01, 9.5764992e-01 }, - { 2.6907741e-01, 9.6311855e-01 }, { 2.5011597e-01, 9.6821588e-01 }, - { 2.3105811e-01, 9.7293995e-01 }, { 2.1191117e-01, 9.7728893e-01 }, - { 1.9268253e-01, 9.8126115e-01 }, { 1.7337961e-01, 9.8485507e-01 }, - { 1.5400984e-01, 9.8806931e-01 }, { 1.3458071e-01, 9.9090264e-01 }, - { 1.1509969e-01, 9.9335395e-01 }, { 9.5574297e-02, 9.9542230e-01 }, - { 7.6012059e-02, 9.9710690e-01 }, { 5.6420516e-02, 9.9840709e-01 }, - { 3.6807223e-02, 9.9932238e-01 }, { 1.7179740e-02, 9.9985242e-01 }, - } -}; - -static const struct lc3_mdct_rot_def mdct_rot_360 = { - .n4 = 360/4, .w = (const struct lc3_complex []){ - { 9.9999762e-01, 2.1816598e-03 }, { 9.9980724e-01, 1.9633692e-02 }, - { 9.9931231e-01, 3.7079744e-02 }, { 9.9851298e-01, 5.4514502e-02 }, - { 9.9740949e-01, 7.1932653e-02 }, { 9.9600218e-01, 8.9328893e-02 }, - { 9.9429148e-01, 1.0669792e-01 }, { 9.9227791e-01, 1.2403445e-01 }, - { 9.8996208e-01, 1.4133320e-01 }, { 9.8734470e-01, 1.5858889e-01 }, - { 9.8442657e-01, 1.7579628e-01 }, { 9.8120857e-01, 1.9295012e-01 }, - { 9.7769168e-01, 2.1004518e-01 }, { 9.7387698e-01, 2.2707626e-01 }, - { 9.6976563e-01, 2.4403818e-01 }, { 9.6535887e-01, 2.6092575e-01 }, - { 9.6065806e-01, 2.7773385e-01 }, { 9.5566462e-01, 2.9445734e-01 }, - { 9.5038008e-01, 3.1109114e-01 }, { 9.4480605e-01, 3.2763018e-01 }, - { 9.3894421e-01, 3.4406942e-01 }, { 9.3279637e-01, 3.6040385e-01 }, - { 9.2636438e-01, 3.7662850e-01 }, { 9.1965022e-01, 3.9273843e-01 }, - { 9.1265592e-01, 4.0872872e-01 }, { 9.0538362e-01, 4.2459451e-01 }, - { 8.9783553e-01, 4.4033097e-01 }, { 8.9001395e-01, 4.5593329e-01 }, - { 8.8192126e-01, 4.7139674e-01 }, { 8.7355994e-01, 4.8671659e-01 }, - { 8.6493251e-01, 5.0188818e-01 }, { 8.5604162e-01, 5.1690690e-01 }, - { 8.4688997e-01, 5.3176816e-01 }, { 8.3748035e-01, 5.4646743e-01 }, - { 8.2781563e-01, 5.6100025e-01 }, { 8.1789875e-01, 5.7536218e-01 }, - { 8.0773272e-01, 5.8954885e-01 }, { 7.9732065e-01, 6.0355594e-01 }, - { 7.8666571e-01, 6.1737918e-01 }, { 7.7577115e-01, 6.3101436e-01 }, - { 7.6464028e-01, 6.4445733e-01 }, { 7.5327649e-01, 6.5770399e-01 }, - { 7.4168324e-01, 6.7075030e-01 }, { 7.2986407e-01, 6.8359230e-01 }, - { 7.1782258e-01, 6.9622607e-01 }, { 7.0556243e-01, 7.0864776e-01 }, - { 6.9308736e-01, 7.2085360e-01 }, { 6.8040117e-01, 7.3283985e-01 }, - { 6.6750772e-01, 7.4460287e-01 }, { 6.5441095e-01, 7.5613908e-01 }, - { 6.4111483e-01, 7.6744496e-01 }, { 6.2762343e-01, 7.7851708e-01 }, - { 6.1394084e-01, 7.8935204e-01 }, { 6.0007124e-01, 7.9994657e-01 }, - { 5.8601885e-01, 8.1029742e-01 }, { 5.7178796e-01, 8.2040144e-01 }, - { 5.5738289e-01, 8.3025557e-01 }, { 5.4280804e-01, 8.3985679e-01 }, - { 5.2806785e-01, 8.4920218e-01 }, { 5.1316680e-01, 8.5828890e-01 }, - { 4.9810944e-01, 8.6711417e-01 }, { 4.8290034e-01, 8.7567532e-01 }, - { 4.6754415e-01, 8.8396972e-01 }, { 4.5204555e-01, 8.9199486e-01 }, - { 4.3640924e-01, 8.9974828e-01 }, { 4.2064000e-01, 9.0722764e-01 }, - { 4.0474263e-01, 9.1443064e-01 }, { 3.8872197e-01, 9.2135511e-01 }, - { 3.7258290e-01, 9.2799891e-01 }, { 3.5633034e-01, 9.3436004e-01 }, - { 3.3996924e-01, 9.4043656e-01 }, { 3.2350458e-01, 9.4622660e-01 }, - { 3.0694138e-01, 9.5172842e-01 }, { 2.9028468e-01, 9.5694034e-01 }, - { 2.7353955e-01, 9.6186076e-01 }, { 2.5671111e-01, 9.6648818e-01 }, - { 2.3980446e-01, 9.7082121e-01 }, { 2.2282477e-01, 9.7485851e-01 }, - { 2.0577721e-01, 9.7859887e-01 }, { 1.8866696e-01, 9.8204113e-01 }, - { 1.7149925e-01, 9.8518425e-01 }, { 1.5427929e-01, 9.8802728e-01 }, - { 1.3701234e-01, 9.9056934e-01 }, { 1.1970366e-01, 9.9280967e-01 }, - { 1.0235851e-01, 9.9474757e-01 }, { 8.4982177e-02, 9.9638247e-01 }, - { 6.7579962e-02, 9.9771386e-01 }, { 5.0157162e-02, 9.9874134e-01 }, - { 3.2719083e-02, 9.9946459e-01 }, { 1.5271037e-02, 9.9988339e-01 }, - } -}; - -static const struct lc3_mdct_rot_def mdct_rot_480 = { - .n4 = 480/4, .w = (const struct lc3_complex []){ - { 9.9999866e-01, 1.6362454e-03 }, { 9.9989157e-01, 1.4725683e-02 }, - { 9.9961315e-01, 2.7812598e-02 }, { 9.9916346e-01, 4.0894747e-02 }, - { 9.9854256e-01, 5.3969889e-02 }, { 9.9775057e-01, 6.7035784e-02 }, - { 9.9678762e-01, 8.0090192e-02 }, { 9.9565388e-01, 9.3130877e-02 }, - { 9.9434953e-01, 1.0615561e-01 }, { 9.9287481e-01, 1.1916214e-01 }, - { 9.9122996e-01, 1.3214826e-01 }, { 9.8941527e-01, 1.4511174e-01 }, - { 9.8743105e-01, 1.5805036e-01 }, { 9.8527764e-01, 1.7096189e-01 }, - { 9.8295541e-01, 1.8384413e-01 }, { 9.8046475e-01, 1.9669487e-01 }, - { 9.7780610e-01, 2.0951190e-01 }, { 9.7497990e-01, 2.2229304e-01 }, - { 9.7198664e-01, 2.3503609e-01 }, { 9.6882685e-01, 2.4773886e-01 }, - { 9.6550104e-01, 2.6039919e-01 }, { 9.6200980e-01, 2.7301490e-01 }, - { 9.5835373e-01, 2.8558383e-01 }, { 9.5453345e-01, 2.9810383e-01 }, - { 9.5054962e-01, 3.1057274e-01 }, { 9.4640291e-01, 3.2298845e-01 }, - { 9.4209404e-01, 3.3534881e-01 }, { 9.3762375e-01, 3.4765171e-01 }, - { 9.3299280e-01, 3.5989504e-01 }, { 9.2820199e-01, 3.7207670e-01 }, - { 9.2325213e-01, 3.8419461e-01 }, { 9.1814408e-01, 3.9624670e-01 }, - { 9.1287871e-01, 4.0823088e-01 }, { 9.0745693e-01, 4.2014512e-01 }, - { 9.0187965e-01, 4.3198737e-01 }, { 8.9614785e-01, 4.4375560e-01 }, - { 8.9026249e-01, 4.5544780e-01 }, { 8.8422459e-01, 4.6706195e-01 }, - { 8.7803519e-01, 4.7859608e-01 }, { 8.7169533e-01, 4.9004821e-01 }, - { 8.6520612e-01, 5.0141636e-01 }, { 8.5856866e-01, 5.1269860e-01 }, - { 8.5178409e-01, 5.2389299e-01 }, { 8.4485357e-01, 5.3499762e-01 }, - { 8.3777828e-01, 5.4601058e-01 }, { 8.3055945e-01, 5.5692998e-01 }, - { 8.2319831e-01, 5.6775395e-01 }, { 8.1569611e-01, 5.7848064e-01 }, - { 8.0805415e-01, 5.8910822e-01 }, { 8.0027373e-01, 5.9963485e-01 }, - { 7.9235620e-01, 6.1005873e-01 }, { 7.8430289e-01, 6.2037809e-01 }, - { 7.7611520e-01, 6.3059115e-01 }, { 7.6779452e-01, 6.4069616e-01 }, - { 7.5934229e-01, 6.5069139e-01 }, { 7.5075995e-01, 6.6057513e-01 }, - { 7.4204897e-01, 6.7034568e-01 }, { 7.3321084e-01, 6.8000137e-01 }, - { 7.2424708e-01, 6.8954054e-01 }, { 7.1515923e-01, 6.9896157e-01 }, - { 7.0594883e-01, 7.0826283e-01 }, { 6.9661748e-01, 7.1744274e-01 }, - { 6.8716676e-01, 7.2649972e-01 }, { 6.7759830e-01, 7.3543221e-01 }, - { 6.6791374e-01, 7.4423869e-01 }, { 6.5811474e-01, 7.5291765e-01 }, - { 6.4820297e-01, 7.6146760e-01 }, { 6.3818013e-01, 7.6988708e-01 }, - { 6.2804795e-01, 7.7817464e-01 }, { 6.1780815e-01, 7.8632887e-01 }, - { 6.0746249e-01, 7.9434836e-01 }, { 5.9701275e-01, 8.0223175e-01 }, - { 5.8646072e-01, 8.0997767e-01 }, { 5.7580819e-01, 8.1758481e-01 }, - { 5.6505701e-01, 8.2505187e-01 }, { 5.5420900e-01, 8.3237755e-01 }, - { 5.4326604e-01, 8.3956061e-01 }, { 5.3222998e-01, 8.4659981e-01 }, - { 5.2110274e-01, 8.5349396e-01 }, { 5.0988620e-01, 8.6024186e-01 }, - { 4.9858230e-01, 8.6684237e-01 }, { 4.8719297e-01, 8.7329434e-01 }, - { 4.7572016e-01, 8.7959669e-01 }, { 4.6416584e-01, 8.8574831e-01 }, - { 4.5253199e-01, 8.9174817e-01 }, { 4.4082059e-01, 8.9759523e-01 }, - { 4.2903367e-01, 9.0328850e-01 }, { 4.1717323e-01, 9.0882699e-01 }, - { 4.0524131e-01, 9.1420976e-01 }, { 3.9323996e-01, 9.1943588e-01 }, - { 3.8117123e-01, 9.2450446e-01 }, { 3.6903718e-01, 9.2941463e-01 }, - { 3.5683990e-01, 9.3416555e-01 }, { 3.4458148e-01, 9.3875641e-01 }, - { 3.3226402e-01, 9.4318642e-01 }, { 3.1988962e-01, 9.4745482e-01 }, - { 3.0746042e-01, 9.5156087e-01 }, { 2.9497853e-01, 9.5550388e-01 }, - { 2.8244610e-01, 9.5928317e-01 }, { 2.6986527e-01, 9.6289809e-01 }, - { 2.5723821e-01, 9.6634802e-01 }, { 2.4456706e-01, 9.6963238e-01 }, - { 2.3185402e-01, 9.7275059e-01 }, { 2.1910124e-01, 9.7570213e-01 }, - { 2.0631092e-01, 9.7848649e-01 }, { 1.9348526e-01, 9.8110318e-01 }, - { 1.8062644e-01, 9.8355177e-01 }, { 1.6773667e-01, 9.8583184e-01 }, - { 1.5481816e-01, 9.8794298e-01 }, { 1.4187312e-01, 9.8988485e-01 }, - { 1.2890377e-01, 9.9165711e-01 }, { 1.1591234e-01, 9.9325945e-01 }, - { 1.0290104e-01, 9.9469160e-01 }, { 8.9872115e-02, 9.9595331e-01 }, - { 7.6827789e-02, 9.9704438e-01 }, { 6.3770300e-02, 9.9796460e-01 }, - { 5.0701883e-02, 9.9871383e-01 }, { 3.7624779e-02, 9.9929194e-01 }, - { 2.4541229e-02, 9.9969882e-01 }, { 1.1453473e-02, 9.9993441e-01 }, - } -}; - -static const struct lc3_mdct_rot_def mdct_rot_640 = { - .n4 = 640/4, .w = (const struct lc3_complex []){ - { 9.9999925e-01, 1.2271843e-03 }, { 9.9993901e-01, 1.1044437e-02 }, - { 9.9978239e-01, 2.0860625e-02 }, { 9.9952942e-01, 3.0674803e-02 }, - { 9.9918010e-01, 4.0486024e-02 }, { 9.9873449e-01, 5.0293344e-02 }, - { 9.9819261e-01, 6.0095815e-02 }, { 9.9755453e-01, 6.9892495e-02 }, - { 9.9682030e-01, 7.9682438e-02 }, { 9.9598999e-01, 8.9464701e-02 }, - { 9.9506369e-01, 9.9238342e-02 }, { 9.9404148e-01, 1.0900242e-01 }, - { 9.9292347e-01, 1.1875599e-01 }, { 9.9170975e-01, 1.2849811e-01 }, - { 9.9040046e-01, 1.3822785e-01 }, { 9.8899570e-01, 1.4794427e-01 }, - { 9.8749562e-01, 1.5764642e-01 }, { 9.8590037e-01, 1.6733339e-01 }, - { 9.8421009e-01, 1.7700422e-01 }, { 9.8242496e-01, 1.8665800e-01 }, - { 9.8054513e-01, 1.9629378e-01 }, { 9.7857080e-01, 2.0591064e-01 }, - { 9.7650215e-01, 2.1550766e-01 }, { 9.7433938e-01, 2.2508391e-01 }, - { 9.7208271e-01, 2.3463847e-01 }, { 9.6973234e-01, 2.4417040e-01 }, - { 9.6728851e-01, 2.5367881e-01 }, { 9.6475145e-01, 2.6316276e-01 }, - { 9.6212140e-01, 2.7262136e-01 }, { 9.5939863e-01, 2.8205367e-01 }, - { 9.5658338e-01, 2.9145880e-01 }, { 9.5367594e-01, 3.0083584e-01 }, - { 9.5067658e-01, 3.1018388e-01 }, { 9.4758559e-01, 3.1950203e-01 }, - { 9.4440327e-01, 3.2878938e-01 }, { 9.4112993e-01, 3.3804505e-01 }, - { 9.3776588e-01, 3.4726813e-01 }, { 9.3431145e-01, 3.5645774e-01 }, - { 9.3076696e-01, 3.6561300e-01 }, { 9.2713277e-01, 3.7473302e-01 }, - { 9.2340921e-01, 3.8381691e-01 }, { 9.1959666e-01, 3.9286382e-01 }, - { 9.1569547e-01, 4.0187286e-01 }, { 9.1170603e-01, 4.1084317e-01 }, - { 9.0762872e-01, 4.1977388e-01 }, { 9.0346392e-01, 4.2866413e-01 }, - { 8.9921205e-01, 4.3751307e-01 }, { 8.9487351e-01, 4.4631984e-01 }, - { 8.9044872e-01, 4.5508359e-01 }, { 8.8593811e-01, 4.6380348e-01 }, - { 8.8134211e-01, 4.7247866e-01 }, { 8.7666116e-01, 4.8110831e-01 }, - { 8.7189572e-01, 4.8969159e-01 }, { 8.6704625e-01, 4.9822767e-01 }, - { 8.6211320e-01, 5.0671573e-01 }, { 8.5709707e-01, 5.1515495e-01 }, - { 8.5199832e-01, 5.2354452e-01 }, { 8.4681746e-01, 5.3188363e-01 }, - { 8.4155498e-01, 5.4017147e-01 }, { 8.3621139e-01, 5.4840726e-01 }, - { 8.3078720e-01, 5.5659018e-01 }, { 8.2528294e-01, 5.6471946e-01 }, - { 8.1969914e-01, 5.7279431e-01 }, { 8.1403633e-01, 5.8081396e-01 }, - { 8.0829506e-01, 5.8877762e-01 }, { 8.0247589e-01, 5.9668454e-01 }, - { 7.9657938e-01, 6.0453395e-01 }, { 7.9060609e-01, 6.1232509e-01 }, - { 7.8455660e-01, 6.2005721e-01 }, { 7.7843149e-01, 6.2772957e-01 }, - { 7.7223135e-01, 6.3534143e-01 }, { 7.6595679e-01, 6.4289206e-01 }, - { 7.5960840e-01, 6.5038072e-01 }, { 7.5318680e-01, 6.5780669e-01 }, - { 7.4669260e-01, 6.6516927e-01 }, { 7.4012644e-01, 6.7246773e-01 }, - { 7.3348894e-01, 6.7970138e-01 }, { 7.2678075e-01, 6.8686952e-01 }, - { 7.2000251e-01, 6.9397146e-01 }, { 7.1315487e-01, 7.0100651e-01 }, - { 7.0623850e-01, 7.0797400e-01 }, { 6.9925406e-01, 7.1487325e-01 }, - { 6.9220222e-01, 7.2170360e-01 }, { 6.8508367e-01, 7.2846439e-01 }, - { 6.7789909e-01, 7.3515497e-01 }, { 6.7064917e-01, 7.4177469e-01 }, - { 6.6333461e-01, 7.4832292e-01 }, { 6.5595612e-01, 7.5479903e-01 }, - { 6.4851440e-01, 7.6120239e-01 }, { 6.4101018e-01, 7.6753238e-01 }, - { 6.3344418e-01, 7.7378839e-01 }, { 6.2581713e-01, 7.7996982e-01 }, - { 6.1812975e-01, 7.8607608e-01 }, { 6.1038281e-01, 7.9210658e-01 }, - { 6.0257703e-01, 7.9806073e-01 }, { 5.9471317e-01, 8.0393796e-01 }, - { 5.8679200e-01, 8.0973771e-01 }, { 5.7881426e-01, 8.1545941e-01 }, - { 5.7078075e-01, 8.2110251e-01 }, { 5.6269221e-01, 8.2666648e-01 }, - { 5.5454945e-01, 8.3215077e-01 }, { 5.4635323e-01, 8.3755486e-01 }, - { 5.3810436e-01, 8.4287822e-01 }, { 5.2980362e-01, 8.4812034e-01 }, - { 5.2145182e-01, 8.5328072e-01 }, { 5.1304977e-01, 8.5835886e-01 }, - { 5.0459826e-01, 8.6335427e-01 }, { 4.9609812e-01, 8.6826647e-01 }, - { 4.8755016e-01, 8.7309498e-01 }, { 4.7895521e-01, 8.7783934e-01 }, - { 4.7031410e-01, 8.8249909e-01 }, { 4.6162766e-01, 8.8707379e-01 }, - { 4.5289673e-01, 8.9156298e-01 }, { 4.4412214e-01, 8.9596625e-01 }, - { 4.3530476e-01, 9.0028316e-01 }, { 4.2644541e-01, 9.0451330e-01 }, - { 4.1754496e-01, 9.0865626e-01 }, { 4.0860427e-01, 9.1271165e-01 }, - { 3.9962420e-01, 9.1667906e-01 }, { 3.9060561e-01, 9.2055812e-01 }, - { 3.8154937e-01, 9.2434846e-01 }, { 3.7245636e-01, 9.2804971e-01 }, - { 3.6332745e-01, 9.3166151e-01 }, { 3.5416353e-01, 9.3518351e-01 }, - { 3.4496546e-01, 9.3861538e-01 }, { 3.3573415e-01, 9.4195678e-01 }, - { 3.2647048e-01, 9.4520740e-01 }, { 3.1717535e-01, 9.4836691e-01 }, - { 3.0784964e-01, 9.5143502e-01 }, { 2.9849426e-01, 9.5441143e-01 }, - { 2.8911012e-01, 9.5729585e-01 }, { 2.7969810e-01, 9.6008800e-01 }, - { 2.7025914e-01, 9.6278762e-01 }, { 2.6079412e-01, 9.6539444e-01 }, - { 2.5130396e-01, 9.6790822e-01 }, { 2.4178959e-01, 9.7032870e-01 }, - { 2.3225191e-01, 9.7265567e-01 }, { 2.2269185e-01, 9.7488889e-01 }, - { 2.1311032e-01, 9.7702814e-01 }, { 2.0350825e-01, 9.7907323e-01 }, - { 1.9388657e-01, 9.8102395e-01 }, { 1.8424620e-01, 9.8288012e-01 }, - { 1.7458807e-01, 9.8464156e-01 }, { 1.6491312e-01, 9.8630810e-01 }, - { 1.5522227e-01, 9.8787957e-01 }, { 1.4551646e-01, 9.8935583e-01 }, - { 1.3579663e-01, 9.9073673e-01 }, { 1.2606370e-01, 9.9202215e-01 }, - { 1.1631863e-01, 9.9321195e-01 }, { 1.0656235e-01, 9.9430602e-01 }, - { 9.6795791e-02, 9.9530426e-01 }, { 8.7019907e-02, 9.9620657e-01 }, - { 7.7235635e-02, 9.9701287e-01 }, { 6.7443920e-02, 9.9772307e-01 }, - { 5.7645703e-02, 9.9833710e-01 }, { 4.7841931e-02, 9.9885492e-01 }, - { 3.8033548e-02, 9.9927646e-01 }, { 2.8221499e-02, 9.9960169e-01 }, - { 1.8406730e-02, 9.9983058e-01 }, { 8.5901868e-03, 9.9996310e-01 }, - } -}; - -static const struct lc3_mdct_rot_def mdct_rot_720 = { - .n4 = 720/4, .w = (const struct lc3_complex []){ - { 9.9999941e-01, 1.0908306e-03 }, { 9.9995181e-01, 9.8173193e-03 }, - { 9.9982806e-01, 1.8543060e-02 }, { 9.9962818e-01, 2.7267389e-02 }, - { 9.9935216e-01, 3.5989642e-02 }, { 9.9900005e-01, 4.4709154e-02 }, - { 9.9857185e-01, 5.3425261e-02 }, { 9.9806761e-01, 6.2137299e-02 }, - { 9.9748736e-01, 7.0844606e-02 }, { 9.9683116e-01, 7.9546517e-02 }, - { 9.9609903e-01, 8.8242371e-02 }, { 9.9529105e-01, 9.6931504e-02 }, - { 9.9440728e-01, 1.0561326e-01 }, { 9.9344778e-01, 1.1428696e-01 }, - { 9.9241262e-01, 1.2295197e-01 }, { 9.9130189e-01, 1.3160761e-01 }, - { 9.9011567e-01, 1.4025323e-01 }, { 9.8885404e-01, 1.4888817e-01 }, - { 9.8751711e-01, 1.5751177e-01 }, { 9.8610498e-01, 1.6612338e-01 }, - { 9.8461775e-01, 1.7472233e-01 }, { 9.8305553e-01, 1.8330798e-01 }, - { 9.8141846e-01, 1.9187967e-01 }, { 9.7970664e-01, 2.0043675e-01 }, - { 9.7792022e-01, 2.0897856e-01 }, { 9.7605933e-01, 2.1750446e-01 }, - { 9.7412410e-01, 2.2601379e-01 }, { 9.7211469e-01, 2.3450592e-01 }, - { 9.7003125e-01, 2.4298018e-01 }, { 9.6787394e-01, 2.5143594e-01 }, - { 9.6564292e-01, 2.5987255e-01 }, { 9.6333837e-01, 2.6828937e-01 }, - { 9.6096045e-01, 2.7668577e-01 }, { 9.5850935e-01, 2.8506109e-01 }, - { 9.5598526e-01, 2.9341470e-01 }, { 9.5338836e-01, 3.0174596e-01 }, - { 9.5071887e-01, 3.1005425e-01 }, { 9.4797697e-01, 3.1833893e-01 }, - { 9.4516287e-01, 3.2659936e-01 }, { 9.4227680e-01, 3.3483492e-01 }, - { 9.3931898e-01, 3.4304499e-01 }, { 9.3628962e-01, 3.5122892e-01 }, - { 9.3318895e-01, 3.5938611e-01 }, { 9.3001722e-01, 3.6751594e-01 }, - { 9.2677467e-01, 3.7561777e-01 }, { 9.2346154e-01, 3.8369100e-01 }, - { 9.2007808e-01, 3.9173501e-01 }, { 9.1662456e-01, 3.9974919e-01 }, - { 9.1310123e-01, 4.0773292e-01 }, { 9.0950837e-01, 4.1568561e-01 }, - { 9.0584624e-01, 4.2360664e-01 }, { 9.0211513e-01, 4.3149541e-01 }, - { 8.9831532e-01, 4.3935132e-01 }, { 8.9444710e-01, 4.4717377e-01 }, - { 8.9051077e-01, 4.5496217e-01 }, { 8.8650662e-01, 4.6271592e-01 }, - { 8.8243495e-01, 4.7043443e-01 }, { 8.7829609e-01, 4.7811712e-01 }, - { 8.7409034e-01, 4.8576339e-01 }, { 8.6981803e-01, 4.9337268e-01 }, - { 8.6547947e-01, 5.0094439e-01 }, { 8.6107501e-01, 5.0847795e-01 }, - { 8.5660497e-01, 5.1597279e-01 }, { 8.5206970e-01, 5.2342834e-01 }, - { 8.4746954e-01, 5.3084403e-01 }, { 8.4280484e-01, 5.3821929e-01 }, - { 8.3807596e-01, 5.4555356e-01 }, { 8.3328326e-01, 5.5284629e-01 }, - { 8.2842709e-01, 5.6009691e-01 }, { 8.2350785e-01, 5.6730488e-01 }, - { 8.1852588e-01, 5.7446965e-01 }, { 8.1348159e-01, 5.8159067e-01 }, - { 8.0837534e-01, 5.8866740e-01 }, { 8.0320753e-01, 5.9569930e-01 }, - { 7.9797856e-01, 6.0268584e-01 }, { 7.9268881e-01, 6.0962648e-01 }, - { 7.8733870e-01, 6.1652070e-01 }, { 7.8192863e-01, 6.2336796e-01 }, - { 7.7645902e-01, 6.3016775e-01 }, { 7.7093027e-01, 6.3691955e-01 }, - { 7.6534281e-01, 6.4362285e-01 }, { 7.5969708e-01, 6.5027714e-01 }, - { 7.5399348e-01, 6.5688190e-01 }, { 7.4823247e-01, 6.6343664e-01 }, - { 7.4241448e-01, 6.6994085e-01 }, { 7.3653994e-01, 6.7639405e-01 }, - { 7.3060932e-01, 6.8279574e-01 }, { 7.2462306e-01, 6.8914543e-01 }, - { 7.1858162e-01, 6.9544264e-01 }, { 7.1248545e-01, 7.0168688e-01 }, - { 7.0633503e-01, 7.0787769e-01 }, { 7.0013081e-01, 7.1401460e-01 }, - { 6.9387328e-01, 7.2009713e-01 }, { 6.8756291e-01, 7.2612482e-01 }, - { 6.8120017e-01, 7.3209721e-01 }, { 6.7478556e-01, 7.3801385e-01 }, - { 6.6831956e-01, 7.4387429e-01 }, { 6.6180267e-01, 7.4967808e-01 }, - { 6.5523538e-01, 7.5542478e-01 }, { 6.4861819e-01, 7.6111395e-01 }, - { 6.4195160e-01, 7.6674516e-01 }, { 6.3523613e-01, 7.7231798e-01 }, - { 6.2847228e-01, 7.7783198e-01 }, { 6.2166057e-01, 7.8328675e-01 }, - { 6.1480152e-01, 7.8868187e-01 }, { 6.0789565e-01, 7.9401692e-01 }, - { 6.0094349e-01, 7.9929151e-01 }, { 5.9394556e-01, 8.0450523e-01 }, - { 5.8690240e-01, 8.0965769e-01 }, { 5.7981455e-01, 8.1474848e-01 }, - { 5.7268254e-01, 8.1977723e-01 }, { 5.6550692e-01, 8.2474355e-01 }, - { 5.5828823e-01, 8.2964706e-01 }, { 5.5102703e-01, 8.3448740e-01 }, - { 5.4372386e-01, 8.3926418e-01 }, { 5.3637929e-01, 8.4397705e-01 }, - { 5.2899387e-01, 8.4862564e-01 }, { 5.2156817e-01, 8.5320961e-01 }, - { 5.1410274e-01, 8.5772861e-01 }, { 5.0659817e-01, 8.6218229e-01 }, - { 4.9905502e-01, 8.6657030e-01 }, { 4.9147386e-01, 8.7089233e-01 }, - { 4.8385527e-01, 8.7514803e-01 }, { 4.7619984e-01, 8.7933709e-01 }, - { 4.6850814e-01, 8.8345918e-01 }, { 4.6078076e-01, 8.8751399e-01 }, - { 4.5301829e-01, 8.9150122e-01 }, { 4.4522133e-01, 8.9542056e-01 }, - { 4.3739045e-01, 8.9927170e-01 }, { 4.2952627e-01, 9.0305436e-01 }, - { 4.2162938e-01, 9.0676825e-01 }, { 4.1370038e-01, 9.1041309e-01 }, - { 4.0573988e-01, 9.1398859e-01 }, { 3.9774847e-01, 9.1749450e-01 }, - { 3.8972678e-01, 9.2093053e-01 }, { 3.8167541e-01, 9.2429643e-01 }, - { 3.7359497e-01, 9.2759194e-01 }, { 3.6548608e-01, 9.3081681e-01 }, - { 3.5734936e-01, 9.3397079e-01 }, { 3.4918542e-01, 9.3705365e-01 }, - { 3.4099489e-01, 9.4006515e-01 }, { 3.3277840e-01, 9.4300506e-01 }, - { 3.2453656e-01, 9.4587315e-01 }, { 3.1627001e-01, 9.4866922e-01 }, - { 3.0797937e-01, 9.5139304e-01 }, { 2.9966528e-01, 9.5404440e-01 }, - { 2.9132836e-01, 9.5662311e-01 }, { 2.8296927e-01, 9.5912898e-01 }, - { 2.7458862e-01, 9.6156180e-01 }, { 2.6618706e-01, 9.6392139e-01 }, - { 2.5776523e-01, 9.6620758e-01 }, { 2.4932377e-01, 9.6842019e-01 }, - { 2.4086332e-01, 9.7055904e-01 }, { 2.3238453e-01, 9.7262399e-01 }, - { 2.2388805e-01, 9.7461487e-01 }, { 2.1537451e-01, 9.7653153e-01 }, - { 2.0684457e-01, 9.7837382e-01 }, { 1.9829888e-01, 9.8014160e-01 }, - { 1.8973809e-01, 9.8183474e-01 }, { 1.8116285e-01, 9.8345311e-01 }, - { 1.7257382e-01, 9.8499659e-01 }, { 1.6397164e-01, 9.8646505e-01 }, - { 1.5535697e-01, 9.8785840e-01 }, { 1.4673047e-01, 9.8917651e-01 }, - { 1.3809280e-01, 9.9041929e-01 }, { 1.2944462e-01, 9.9158665e-01 }, - { 1.2078657e-01, 9.9267850e-01 }, { 1.1211933e-01, 9.9369475e-01 }, - { 1.0344355e-01, 9.9463533e-01 }, { 9.4759887e-02, 9.9550016e-01 }, - { 8.6069011e-02, 9.9628918e-01 }, { 7.7371581e-02, 9.9700233e-01 }, - { 6.8668259e-02, 9.9763955e-01 }, { 5.9959707e-02, 9.9820080e-01 }, - { 5.1246589e-02, 9.9868603e-01 }, { 4.2529569e-02, 9.9909521e-01 }, - { 3.3809310e-02, 9.9942830e-01 }, { 2.5086476e-02, 9.9968528e-01 }, - { 1.6361732e-02, 9.9986614e-01 }, { 7.6357413e-03, 9.9997085e-01 }, - } -}; - -static const struct lc3_mdct_rot_def mdct_rot_960 = { - .n4 = 960/4, .w = (const struct lc3_complex []){ - { 9.9999967e-01, 8.1812300e-04 }, { 9.9997289e-01, 7.3630412e-03 }, - { 9.9990328e-01, 1.3907644e-02 }, { 9.9979084e-01, 2.0451651e-02 }, - { 9.9963557e-01, 2.6994782e-02 }, { 9.9943748e-01, 3.3536757e-02 }, - { 9.9919658e-01, 4.0077295e-02 }, { 9.9891288e-01, 4.6616116e-02 }, - { 9.9858638e-01, 5.3152941e-02 }, { 9.9821711e-01, 5.9687488e-02 }, - { 9.9780508e-01, 6.6219479e-02 }, { 9.9735031e-01, 7.2748633e-02 }, - { 9.9685281e-01, 7.9274670e-02 }, { 9.9631261e-01, 8.5797312e-02 }, - { 9.9572973e-01, 9.2316279e-02 }, { 9.9510420e-01, 9.8831291e-02 }, - { 9.9443605e-01, 1.0534207e-01 }, { 9.9372529e-01, 1.1184834e-01 }, - { 9.9297196e-01, 1.1834981e-01 }, { 9.9217610e-01, 1.2484622e-01 }, - { 9.9133774e-01, 1.3133727e-01 }, { 9.9045692e-01, 1.3782270e-01 }, - { 9.8953366e-01, 1.4430223e-01 }, { 9.8856802e-01, 1.5077558e-01 }, - { 9.8756003e-01, 1.5724246e-01 }, { 9.8650973e-01, 1.6370261e-01 }, - { 9.8541718e-01, 1.7015575e-01 }, { 9.8428242e-01, 1.7660160e-01 }, - { 9.8310549e-01, 1.8303989e-01 }, { 9.8188645e-01, 1.8947033e-01 }, - { 9.8062534e-01, 1.9589266e-01 }, { 9.7932224e-01, 2.0230660e-01 }, - { 9.7797718e-01, 2.0871187e-01 }, { 9.7659022e-01, 2.1510820e-01 }, - { 9.7516144e-01, 2.2149531e-01 }, { 9.7369088e-01, 2.2787294e-01 }, - { 9.7217861e-01, 2.3424080e-01 }, { 9.7062469e-01, 2.4059864e-01 }, - { 9.6902920e-01, 2.4694616e-01 }, { 9.6739220e-01, 2.5328311e-01 }, - { 9.6571376e-01, 2.5960920e-01 }, { 9.6399395e-01, 2.6592418e-01 }, - { 9.6223284e-01, 2.7222777e-01 }, { 9.6043052e-01, 2.7851969e-01 }, - { 9.5858705e-01, 2.8479968e-01 }, { 9.5670253e-01, 2.9106748e-01 }, - { 9.5477702e-01, 2.9732280e-01 }, { 9.5281061e-01, 3.0356539e-01 }, - { 9.5080338e-01, 3.0979497e-01 }, { 9.4875543e-01, 3.1601129e-01 }, - { 9.4666684e-01, 3.2221406e-01 }, { 9.4453769e-01, 3.2840304e-01 }, - { 9.4236808e-01, 3.3457794e-01 }, { 9.4015810e-01, 3.4073852e-01 }, - { 9.3790786e-01, 3.4688450e-01 }, { 9.3561743e-01, 3.5301562e-01 }, - { 9.3328693e-01, 3.5913161e-01 }, { 9.3091644e-01, 3.6523223e-01 }, - { 9.2850608e-01, 3.7131719e-01 }, { 9.2605595e-01, 3.7738626e-01 }, - { 9.2356614e-01, 3.8343915e-01 }, { 9.2103677e-01, 3.8947562e-01 }, - { 9.1846795e-01, 3.9549541e-01 }, { 9.1585979e-01, 4.0149825e-01 }, - { 9.1321239e-01, 4.0748390e-01 }, { 9.1052587e-01, 4.1345209e-01 }, - { 9.0780035e-01, 4.1940257e-01 }, { 9.0503595e-01, 4.2533508e-01 }, - { 9.0223277e-01, 4.3124938e-01 }, { 8.9939095e-01, 4.3714520e-01 }, - { 8.9651059e-01, 4.4302229e-01 }, { 8.9359184e-01, 4.4888041e-01 }, - { 8.9063481e-01, 4.5471930e-01 }, { 8.8763962e-01, 4.6053871e-01 }, - { 8.8460641e-01, 4.6633839e-01 }, { 8.8153531e-01, 4.7211810e-01 }, - { 8.7842644e-01, 4.7787758e-01 }, { 8.7527995e-01, 4.8361659e-01 }, - { 8.7209596e-01, 4.8933489e-01 }, { 8.6887462e-01, 4.9503222e-01 }, - { 8.6561605e-01, 5.0070835e-01 }, { 8.6232041e-01, 5.0636303e-01 }, - { 8.5898782e-01, 5.1199602e-01 }, { 8.5561844e-01, 5.1760707e-01 }, - { 8.5221241e-01, 5.2319595e-01 }, { 8.4876987e-01, 5.2876243e-01 }, - { 8.4529098e-01, 5.3430625e-01 }, { 8.4177587e-01, 5.3982718e-01 }, - { 8.3822471e-01, 5.4532499e-01 }, { 8.3463763e-01, 5.5079944e-01 }, - { 8.3101481e-01, 5.5625029e-01 }, { 8.2735639e-01, 5.6167732e-01 }, - { 8.2366252e-01, 5.6708028e-01 }, { 8.1993338e-01, 5.7245896e-01 }, - { 8.1616911e-01, 5.7781311e-01 }, { 8.1236987e-01, 5.8314251e-01 }, - { 8.0853584e-01, 5.8844693e-01 }, { 8.0466718e-01, 5.9372614e-01 }, - { 8.0076404e-01, 5.9897992e-01 }, { 7.9682660e-01, 6.0420805e-01 }, - { 7.9285503e-01, 6.0941029e-01 }, { 7.8884950e-01, 6.1458642e-01 }, - { 7.8481017e-01, 6.1973623e-01 }, { 7.8073723e-01, 6.2485949e-01 }, - { 7.7663084e-01, 6.2995598e-01 }, { 7.7249118e-01, 6.3502549e-01 }, - { 7.6831844e-01, 6.4006780e-01 }, { 7.6411277e-01, 6.4508268e-01 }, - { 7.5987438e-01, 6.5006994e-01 }, { 7.5560344e-01, 6.5502934e-01 }, - { 7.5130013e-01, 6.5996069e-01 }, { 7.4696464e-01, 6.6486377e-01 }, - { 7.4259715e-01, 6.6973837e-01 }, { 7.3819784e-01, 6.7458427e-01 }, - { 7.3376692e-01, 6.7940128e-01 }, { 7.2930457e-01, 6.8418919e-01 }, - { 7.2481097e-01, 6.8894779e-01 }, { 7.2028632e-01, 6.9367688e-01 }, - { 7.1573083e-01, 6.9837625e-01 }, { 7.1114467e-01, 7.0304571e-01 }, - { 7.0652804e-01, 7.0768504e-01 }, { 7.0188116e-01, 7.1229407e-01 }, - { 6.9720420e-01, 7.1687258e-01 }, { 6.9249738e-01, 7.2142039e-01 }, - { 6.8776090e-01, 7.2593729e-01 }, { 6.8299495e-01, 7.3042309e-01 }, - { 6.7819975e-01, 7.3487761e-01 }, { 6.7337550e-01, 7.3930064e-01 }, - { 6.6852240e-01, 7.4369201e-01 }, { 6.6364066e-01, 7.4805152e-01 }, - { 6.5873050e-01, 7.5237898e-01 }, { 6.5379211e-01, 7.5667422e-01 }, - { 6.4882573e-01, 7.6093704e-01 }, { 6.4383154e-01, 7.6516727e-01 }, - { 6.3880978e-01, 7.6936471e-01 }, { 6.3376065e-01, 7.7352921e-01 }, - { 6.2868438e-01, 7.7766056e-01 }, { 6.2358117e-01, 7.8175861e-01 }, - { 6.1845126e-01, 7.8582316e-01 }, { 6.1329485e-01, 7.8985406e-01 }, - { 6.0811216e-01, 7.9385112e-01 }, { 6.0290343e-01, 7.9781417e-01 }, - { 5.9766888e-01, 8.0174305e-01 }, { 5.9240872e-01, 8.0563758e-01 }, - { 5.8712318e-01, 8.0949760e-01 }, { 5.8181249e-01, 8.1332295e-01 }, - { 5.7647688e-01, 8.1711346e-01 }, { 5.7111658e-01, 8.2086896e-01 }, - { 5.6573181e-01, 8.2458930e-01 }, { 5.6032281e-01, 8.2827432e-01 }, - { 5.5488980e-01, 8.3192386e-01 }, { 5.4943303e-01, 8.3553776e-01 }, - { 5.4395272e-01, 8.3911587e-01 }, { 5.3844911e-01, 8.4265803e-01 }, - { 5.3292243e-01, 8.4616410e-01 }, { 5.2737292e-01, 8.4963392e-01 }, - { 5.2180083e-01, 8.5306735e-01 }, { 5.1620638e-01, 8.5646423e-01 }, - { 5.1058981e-01, 8.5982442e-01 }, { 5.0495138e-01, 8.6314779e-01 }, - { 4.9929132e-01, 8.6643418e-01 }, { 4.9360987e-01, 8.6968345e-01 }, - { 4.8790727e-01, 8.7289547e-01 }, { 4.8218377e-01, 8.7607009e-01 }, - { 4.7643962e-01, 8.7920719e-01 }, { 4.7067506e-01, 8.8230663e-01 }, - { 4.6489034e-01, 8.8536827e-01 }, { 4.5908570e-01, 8.8839199e-01 }, - { 4.5326139e-01, 8.9137765e-01 }, { 4.4741768e-01, 8.9432512e-01 }, - { 4.4155479e-01, 8.9723429e-01 }, { 4.3567299e-01, 9.0010502e-01 }, - { 4.2977253e-01, 9.0293719e-01 }, { 4.2385365e-01, 9.0573069e-01 }, - { 4.1791662e-01, 9.0848539e-01 }, { 4.1196169e-01, 9.1120117e-01 }, - { 4.0598911e-01, 9.1387791e-01 }, { 3.9999914e-01, 9.1651551e-01 }, - { 3.9399204e-01, 9.1911385e-01 }, { 3.8796806e-01, 9.2167282e-01 }, - { 3.8192746e-01, 9.2419231e-01 }, { 3.7587050e-01, 9.2667220e-01 }, - { 3.6979743e-01, 9.2911240e-01 }, { 3.6370853e-01, 9.3151280e-01 }, - { 3.5760405e-01, 9.3387330e-01 }, { 3.5148424e-01, 9.3619380e-01 }, - { 3.4534939e-01, 9.3847419e-01 }, { 3.3919973e-01, 9.4071438e-01 }, - { 3.3303555e-01, 9.4291427e-01 }, { 3.2685710e-01, 9.4507377e-01 }, - { 3.2066465e-01, 9.4719279e-01 }, { 3.1445847e-01, 9.4927123e-01 }, - { 3.0823881e-01, 9.5130901e-01 }, { 3.0200595e-01, 9.5330604e-01 }, - { 2.9576015e-01, 9.5526223e-01 }, { 2.8950169e-01, 9.5717750e-01 }, - { 2.8323082e-01, 9.5905177e-01 }, { 2.7694782e-01, 9.6088496e-01 }, - { 2.7065295e-01, 9.6267699e-01 }, { 2.6434649e-01, 9.6442777e-01 }, - { 2.5802871e-01, 9.6613725e-01 }, { 2.5169988e-01, 9.6780534e-01 }, - { 2.4536026e-01, 9.6943197e-01 }, { 2.3901013e-01, 9.7101707e-01 }, - { 2.3264977e-01, 9.7256058e-01 }, { 2.2627944e-01, 9.7406243e-01 }, - { 2.1989941e-01, 9.7552255e-01 }, { 2.1350997e-01, 9.7694089e-01 }, - { 2.0711138e-01, 9.7831737e-01 }, { 2.0070391e-01, 9.7965195e-01 }, - { 1.9428785e-01, 9.8094456e-01 }, { 1.8786347e-01, 9.8219515e-01 }, - { 1.8143104e-01, 9.8340367e-01 }, { 1.7499084e-01, 9.8457006e-01 }, - { 1.6854314e-01, 9.8569428e-01 }, { 1.6208822e-01, 9.8677627e-01 }, - { 1.5562636e-01, 9.8781599e-01 }, { 1.4915783e-01, 9.8881340e-01 }, - { 1.4268292e-01, 9.8976845e-01 }, { 1.3620189e-01, 9.9068110e-01 }, - { 1.2971502e-01, 9.9155132e-01 }, { 1.2322260e-01, 9.9237906e-01 }, - { 1.1672491e-01, 9.9316428e-01 }, { 1.1022221e-01, 9.9390697e-01 }, - { 1.0371479e-01, 9.9460708e-01 }, { 9.7202924e-02, 9.9526458e-01 }, - { 9.0686897e-02, 9.9587945e-01 }, { 8.4166986e-02, 9.9645166e-01 }, - { 7.7643468e-02, 9.9698119e-01 }, { 7.1116625e-02, 9.9746801e-01 }, - { 6.4586736e-02, 9.9791210e-01 }, { 5.8054080e-02, 9.9831344e-01 }, - { 5.1518937e-02, 9.9867202e-01 }, { 4.4981587e-02, 9.9898782e-01 }, - { 3.8442310e-02, 9.9926082e-01 }, { 3.1901387e-02, 9.9949102e-01 }, - { 2.5359097e-02, 9.9967841e-01 }, { 1.8815721e-02, 9.9982297e-01 }, - { 1.2271538e-02, 9.9992470e-01 }, { 5.7268303e-03, 9.9998360e-01 }, - } -}; - -const struct lc3_mdct_rot_def * lc3_mdct_rot[LC3_NUM_DT][LC3_NUM_SRATE] = { - [LC3_DT_7M5] = { &mdct_rot_120, &mdct_rot_240, &mdct_rot_360, - &mdct_rot_480, &mdct_rot_720 }, - [LC3_DT_10M] = { &mdct_rot_160, &mdct_rot_320, &mdct_rot_480, - &mdct_rot_640, &mdct_rot_960 } -}; - - -/** - * Low delay MDCT windows (cf. 3.7.3) - */ - -static const float mdct_win_10m_80[80+50] = { - -7.07854671e-04, -2.09819773e-03, -4.52519808e-03, -8.23397633e-03, - -1.33771310e-02, -1.99972156e-02, -2.80090946e-02, -3.72150208e-02, - -4.73176826e-02, -5.79465483e-02, -6.86760675e-02, -7.90464744e-02, - -8.85970547e-02, -9.68830362e-02, -1.03496124e-01, -1.08076646e-01, - -1.10324226e-01, -1.09980985e-01, -1.06817214e-01, -1.00619042e-01, - -9.11645251e-02, -7.82061748e-02, -6.14668812e-02, -4.06336286e-02, - -1.53632952e-02, 1.47015507e-02, 4.98973651e-02, 9.05036926e-02, - 1.36691102e-01, 1.88468639e-01, 2.45645680e-01, 3.07778908e-01, - 3.74164237e-01, 4.43811480e-01, 5.15473546e-01, 5.87666172e-01, - 6.58761977e-01, 7.27057670e-01, 7.90875299e-01, 8.48664336e-01, - 8.99132024e-01, 9.41334815e-01, 9.74763483e-01, 9.99411473e-01, - 1.01576037e+00, 1.02473616e+00, 1.02763429e+00, 1.02599149e+00, - 1.02142721e+00, 1.01543986e+00, 1.00936693e+00, 1.00350816e+00, - 9.98889821e-01, 9.95313390e-01, 9.92594392e-01, 9.90577196e-01, - 9.89137162e-01, 9.88179075e-01, 9.87624927e-01, 9.87405628e-01, - 9.87452485e-01, 9.87695113e-01, 9.88064062e-01, 9.88492687e-01, - 9.88923003e-01, 9.89307497e-01, 9.89614633e-01, 9.89831927e-01, - 9.89969310e-01, 9.90060335e-01, 9.90157502e-01, 9.90325529e-01, - 9.90630379e-01, 9.91129889e-01, 9.91866549e-01, 9.92861973e-01, - 9.94115607e-01, 9.95603378e-01, 9.97279311e-01, 9.99078484e-01, - 1.00092237e+00, 1.00272811e+00, 1.00441604e+00, 1.00591922e+00, - 1.00718935e+00, 1.00820015e+00, 1.00894949e+00, 1.00945824e+00, - 1.00976898e+00, 1.00994034e+00, 1.01003945e+00, 1.01013232e+00, - 1.01027252e+00, 1.01049435e+00, 1.01080807e+00, 1.01120107e+00, - 1.01164127e+00, 1.01208013e+00, 1.01245818e+00, 1.01270696e+00, - 1.01275501e+00, 1.01253013e+00, 1.01196233e+00, 1.01098214e+00, - 1.00951244e+00, 1.00746086e+00, 1.00470868e+00, 1.00111141e+00, - 9.96504102e-01, 9.90720000e-01, 9.82376587e-01, 9.70882175e-01, - 9.54673298e-01, 9.32155386e-01, 9.01800368e-01, 8.62398408e-01, - 8.13281737e-01, 7.54455197e-01, 6.86658072e-01, 6.11348804e-01, - 5.30618165e-01, 4.47130985e-01, 3.63911468e-01, 2.84164703e-01, - 2.11020945e-01, 1.47228797e-01, 9.48266535e-02, 5.48243661e-02, - 2.70146141e-02, 9.99674359e-03, -}; - -static const float mdct_win_10m_160[160+100] = { - -4.61989875e-04, -9.74716672e-04, -1.66447310e-03, -2.59710692e-03, - -3.80628516e-03, -5.32460872e-03, -7.17588528e-03, -9.38248086e-03, - -1.19527030e-02, -1.48952816e-02, -1.82066640e-02, -2.18757093e-02, - -2.58847194e-02, -3.02086274e-02, -3.48159779e-02, -3.96706799e-02, - -4.47269805e-02, -4.99422586e-02, -5.52633479e-02, -6.06371724e-02, - -6.60096152e-02, -7.13196627e-02, -7.65117823e-02, -8.15296401e-02, - -8.63113754e-02, -9.08041129e-02, -9.49537776e-02, -9.87073651e-02, - -1.02020268e-01, -1.04843883e-01, -1.07138231e-01, -1.08869014e-01, - -1.09996966e-01, -1.10489847e-01, -1.10322584e-01, -1.09462175e-01, - -1.07883429e-01, -1.05561251e-01, -1.02465016e-01, -9.85701457e-02, - -9.38468492e-02, -8.82630999e-02, -8.17879272e-02, -7.43878560e-02, - -6.60218980e-02, -5.66565564e-02, -4.62445689e-02, -3.47458578e-02, - -2.21158161e-02, -8.31042570e-03, 6.71769764e-03, 2.30064206e-02, - 4.06010646e-02, 5.95323909e-02, 7.98335419e-02, 1.01523314e-01, - 1.24617139e-01, 1.49115252e-01, 1.75006740e-01, 2.02269985e-01, - 2.30865538e-01, 2.60736512e-01, 2.91814469e-01, 3.24009570e-01, - 3.57217518e-01, 3.91314689e-01, 4.26157164e-01, 4.61592545e-01, - 4.97447159e-01, 5.33532682e-01, 5.69654673e-01, 6.05608382e-01, - 6.41183084e-01, 6.76165350e-01, 7.10340055e-01, 7.43494372e-01, - 7.75428189e-01, 8.05943723e-01, 8.34858937e-01, 8.62010834e-01, - 8.87259971e-01, 9.10486312e-01, 9.31596250e-01, 9.50522086e-01, - 9.67236671e-01, 9.81739750e-01, 9.94055718e-01, 1.00424751e+00, - 1.01240743e+00, 1.01865099e+00, 1.02311884e+00, 1.02597245e+00, - 1.02739752e+00, 1.02758583e+00, 1.02673867e+00, 1.02506178e+00, - 1.02275651e+00, 1.02000914e+00, 1.01699650e+00, 1.01391595e+00, - 1.01104487e+00, 1.00777386e+00, 1.00484875e+00, 1.00224501e+00, - 9.99939317e-01, 9.97905542e-01, 9.96120338e-01, 9.94559753e-01, - 9.93203161e-01, 9.92029727e-01, 9.91023065e-01, 9.90166895e-01, - 9.89448837e-01, 9.88855636e-01, 9.88377852e-01, 9.88005163e-01, - 9.87729546e-01, 9.87541274e-01, 9.87432981e-01, 9.87394992e-01, - 9.87419705e-01, 9.87497321e-01, 9.87620124e-01, 9.87778192e-01, - 9.87963798e-01, 9.88167801e-01, 9.88383520e-01, 9.88602222e-01, - 9.88818277e-01, 9.89024798e-01, 9.89217866e-01, 9.89392368e-01, - 9.89546334e-01, 9.89677201e-01, 9.89785920e-01, 9.89872536e-01, - 9.89941079e-01, 9.89994556e-01, 9.90039402e-01, 9.90081472e-01, - 9.90129379e-01, 9.90190227e-01, 9.90273445e-01, 9.90386228e-01, - 9.90537983e-01, 9.90734883e-01, 9.90984259e-01, 9.91290512e-01, - 9.91658694e-01, 9.92090615e-01, 9.92588721e-01, 9.93151653e-01, - 9.93779087e-01, 9.94466818e-01, 9.95211663e-01, 9.96006862e-01, - 9.96846133e-01, 9.97720337e-01, 9.98621352e-01, 9.99538258e-01, - 1.00046196e+00, 1.00138055e+00, 1.00228487e+00, 1.00316385e+00, - 1.00400915e+00, 1.00481138e+00, 1.00556397e+00, 1.00625986e+00, - 1.00689557e+00, 1.00746662e+00, 1.00797244e+00, 1.00841147e+00, - 1.00878601e+00, 1.00909776e+00, 1.00935176e+00, 1.00955240e+00, - 1.00970709e+00, 1.00982209e+00, 1.00990696e+00, 1.00996902e+00, - 1.01001789e+00, 1.01006081e+00, 1.01010656e+00, 1.01016113e+00, - 1.01023108e+00, 1.01031948e+00, 1.01043047e+00, 1.01056410e+00, - 1.01072136e+00, 1.01089966e+00, 1.01109699e+00, 1.01130817e+00, - 1.01152919e+00, 1.01175301e+00, 1.01197388e+00, 1.01218284e+00, - 1.01237303e+00, 1.01253506e+00, 1.01266098e+00, 1.01274058e+00, - 1.01276592e+00, 1.01272696e+00, 1.01261590e+00, 1.01242289e+00, - 1.01214046e+00, 1.01175881e+00, 1.01126996e+00, 1.01066368e+00, - 1.00993075e+00, 1.00905825e+00, 1.00803431e+00, 1.00684335e+00, - 1.00547001e+00, 1.00389477e+00, 1.00209885e+00, 1.00006069e+00, - 9.97760020e-01, 9.95174643e-01, 9.92286108e-01, 9.89075787e-01, - 9.84736245e-01, 9.79861353e-01, 9.74137862e-01, 9.67333198e-01, - 9.59253976e-01, 9.49698408e-01, 9.38463416e-01, 9.25356797e-01, - 9.10198679e-01, 8.92833832e-01, 8.73143784e-01, 8.51042044e-01, - 8.26483991e-01, 7.99468149e-01, 7.70043128e-01, 7.38302860e-01, - 7.04381434e-01, 6.68461648e-01, 6.30775533e-01, 5.91579959e-01, - 5.51170316e-01, 5.09891542e-01, 4.68101711e-01, 4.26177297e-01, - 3.84517234e-01, 3.43522867e-01, 3.03600465e-01, 2.65143468e-01, - 2.28528397e-01, 1.94102191e-01, 1.62173542e-01, 1.33001524e-01, - 1.06784043e-01, 8.36505724e-02, 6.36518811e-02, 4.67653841e-02, - 3.28807275e-02, 2.18305756e-02, 1.33638143e-02, 6.75812489e-03, -}; - -static const float mdct_win_10m_240[240+150] = { - -3.61349642e-04, -7.07854671e-04, -1.07444364e-03, -1.53347854e-03, - -2.09819773e-03, -2.77842087e-03, -3.58412992e-03, -4.52519808e-03, - -5.60932724e-03, -6.84323454e-03, -8.23397633e-03, -9.78531476e-03, - -1.14988030e-02, -1.33771310e-02, -1.54218168e-02, -1.76297991e-02, - -1.99972156e-02, -2.25208056e-02, -2.51940630e-02, -2.80090946e-02, - -3.09576509e-02, -3.40299627e-02, -3.72150208e-02, -4.05005325e-02, - -4.38721922e-02, -4.73176826e-02, -5.08232534e-02, -5.43716664e-02, - -5.79465483e-02, -6.15342620e-02, -6.51170816e-02, -6.86760675e-02, - -7.21944781e-02, -7.56569598e-02, -7.90464744e-02, -8.23444256e-02, - -8.55332458e-02, -8.85970547e-02, -9.15209110e-02, -9.42884745e-02, - -9.68830362e-02, -9.92912326e-02, -1.01500847e-01, -1.03496124e-01, - -1.05263700e-01, -1.06793998e-01, -1.08076646e-01, -1.09099730e-01, - -1.09852449e-01, -1.10324226e-01, -1.10508462e-01, -1.10397741e-01, - -1.09980985e-01, -1.09249277e-01, -1.08197423e-01, -1.06817214e-01, - -1.05099580e-01, -1.03036011e-01, -1.00619042e-01, -9.78412002e-02, - -9.46930422e-02, -9.11645251e-02, -8.72464453e-02, -8.29304391e-02, - -7.82061748e-02, -7.30614243e-02, -6.74846818e-02, -6.14668812e-02, - -5.49949726e-02, -4.80544442e-02, -4.06336286e-02, -3.27204559e-02, - -2.43012258e-02, -1.53632952e-02, -5.89143427e-03, 4.12659586e-03, - 1.47015507e-02, 2.58473819e-02, 3.75765277e-02, 4.98973651e-02, - 6.28203403e-02, 7.63539773e-02, 9.05036926e-02, 1.05274712e-01, - 1.20670347e-01, 1.36691102e-01, 1.53334389e-01, 1.70595471e-01, - 1.88468639e-01, 2.06944996e-01, 2.26009300e-01, 2.45645680e-01, - 2.65834602e-01, 2.86554381e-01, 3.07778908e-01, 3.29476944e-01, - 3.51617148e-01, 3.74164237e-01, 3.97073959e-01, 4.20304305e-01, - 4.43811480e-01, 4.67544229e-01, 4.91449863e-01, 5.15473546e-01, - 5.39555764e-01, 5.63639982e-01, 5.87666172e-01, 6.11569531e-01, - 6.35289059e-01, 6.58761977e-01, 6.81923097e-01, 7.04709282e-01, - 7.27057670e-01, 7.48906896e-01, 7.70199019e-01, 7.90875299e-01, - 8.10878869e-01, 8.30157914e-01, 8.48664336e-01, 8.66354816e-01, - 8.83189685e-01, 8.99132024e-01, 9.14154056e-01, 9.28228255e-01, - 9.41334815e-01, 9.53461939e-01, 9.64604825e-01, 9.74763483e-01, - 9.83943539e-01, 9.92152910e-01, 9.99411473e-01, 1.00574608e+00, - 1.01118397e+00, 1.01576037e+00, 1.01951507e+00, 1.02249094e+00, - 1.02473616e+00, 1.02630410e+00, 1.02725098e+00, 1.02763429e+00, - 1.02751106e+00, 1.02694280e+00, 1.02599149e+00, 1.02471615e+00, - 1.02317598e+00, 1.02142721e+00, 1.01952157e+00, 1.01751012e+00, - 1.01543986e+00, 1.01346092e+00, 1.01165490e+00, 1.00936693e+00, - 1.00726318e+00, 1.00531319e+00, 1.00350816e+00, 1.00184079e+00, - 1.00030393e+00, 9.98889821e-01, 9.97591528e-01, 9.96401528e-01, - 9.95313390e-01, 9.94320108e-01, 9.93415896e-01, 9.92594392e-01, - 9.91851028e-01, 9.91179799e-01, 9.90577196e-01, 9.90038105e-01, - 9.89559439e-01, 9.89137162e-01, 9.88768437e-01, 9.88449792e-01, - 9.88179075e-01, 9.87952836e-01, 9.87769137e-01, 9.87624927e-01, - 9.87517995e-01, 9.87445813e-01, 9.87405628e-01, 9.87395112e-01, - 9.87411537e-01, 9.87452485e-01, 9.87514989e-01, 9.87596889e-01, - 9.87695113e-01, 9.87807582e-01, 9.87931200e-01, 9.88064062e-01, - 9.88203257e-01, 9.88347108e-01, 9.88492687e-01, 9.88638659e-01, - 9.88782558e-01, 9.88923003e-01, 9.89058172e-01, 9.89186767e-01, - 9.89307497e-01, 9.89419640e-01, 9.89522076e-01, 9.89614633e-01, - 9.89697035e-01, 9.89769260e-01, 9.89831927e-01, 9.89885257e-01, - 9.89930764e-01, 9.89969310e-01, 9.90002569e-01, 9.90032156e-01, - 9.90060335e-01, 9.90088981e-01, 9.90120659e-01, 9.90157502e-01, - 9.90202395e-01, 9.90257541e-01, 9.90325529e-01, 9.90408791e-01, - 9.90509649e-01, 9.90630379e-01, 9.90772711e-01, 9.90938744e-01, - 9.91129889e-01, 9.91347632e-01, 9.91592856e-01, 9.91866549e-01, - 9.92169132e-01, 9.92501085e-01, 9.92861973e-01, 9.93251918e-01, - 9.93670021e-01, 9.94115607e-01, 9.94587315e-01, 9.95083740e-01, - 9.95603378e-01, 9.96143992e-01, 9.96703453e-01, 9.97279311e-01, - 9.97869086e-01, 9.98469709e-01, 9.99078484e-01, 9.99691901e-01, - 1.00030819e+00, 1.00092237e+00, 1.00153264e+00, 1.00213546e+00, - 1.00272811e+00, 1.00330745e+00, 1.00387093e+00, 1.00441604e+00, - 1.00494055e+00, 1.00544214e+00, 1.00591922e+00, 1.00637030e+00, - 1.00679393e+00, 1.00718935e+00, 1.00755557e+00, 1.00789267e+00, - 1.00820015e+00, 1.00847842e+00, 1.00872788e+00, 1.00894949e+00, - 1.00914411e+00, 1.00931322e+00, 1.00945824e+00, 1.00958128e+00, - 1.00968409e+00, 1.00976898e+00, 1.00983831e+00, 1.00989455e+00, - 1.00994034e+00, 1.00997792e+00, 1.01001023e+00, 1.01003945e+00, - 1.01006820e+00, 1.01009839e+00, 1.01013232e+00, 1.01017166e+00, - 1.01021810e+00, 1.01027252e+00, 1.01033649e+00, 1.01041022e+00, - 1.01049435e+00, 1.01058887e+00, 1.01069350e+00, 1.01080807e+00, - 1.01093144e+00, 1.01106288e+00, 1.01120107e+00, 1.01134470e+00, - 1.01149190e+00, 1.01164127e+00, 1.01179028e+00, 1.01193757e+00, - 1.01208013e+00, 1.01221624e+00, 1.01234291e+00, 1.01245818e+00, - 1.01255888e+00, 1.01264286e+00, 1.01270696e+00, 1.01274895e+00, - 1.01276580e+00, 1.01275501e+00, 1.01271380e+00, 1.01263978e+00, - 1.01253013e+00, 1.01238231e+00, 1.01219407e+00, 1.01196233e+00, - 1.01168517e+00, 1.01135914e+00, 1.01098214e+00, 1.01055072e+00, - 1.01006213e+00, 1.00951244e+00, 1.00889869e+00, 1.00821592e+00, - 1.00746086e+00, 1.00662774e+00, 1.00571234e+00, 1.00470868e+00, - 1.00361147e+00, 1.00241429e+00, 1.00111141e+00, 9.99696165e-01, - 9.98162595e-01, 9.96504102e-01, 9.94714888e-01, 9.92789191e-01, - 9.90720000e-01, 9.88479371e-01, 9.85534766e-01, 9.82376587e-01, - 9.78974733e-01, 9.75162381e-01, 9.70882175e-01, 9.66080552e-01, - 9.60697640e-01, 9.54673298e-01, 9.47947935e-01, 9.40460905e-01, - 9.32155386e-01, 9.22977548e-01, 9.12874535e-01, 9.01800368e-01, - 8.89716328e-01, 8.76590897e-01, 8.62398408e-01, 8.47120080e-01, - 8.30747973e-01, 8.13281737e-01, 7.94729145e-01, 7.75110884e-01, - 7.54455197e-01, 7.32796355e-01, 7.10179084e-01, 6.86658072e-01, - 6.62296243e-01, 6.37168412e-01, 6.11348804e-01, 5.84920660e-01, - 5.57974743e-01, 5.30618165e-01, 5.02952396e-01, 4.75086883e-01, - 4.47130985e-01, 4.19204992e-01, 3.91425291e-01, 3.63911468e-01, - 3.36783777e-01, 3.10162784e-01, 2.84164703e-01, 2.58903371e-01, - 2.34488060e-01, 2.11020945e-01, 1.88599764e-01, 1.67310081e-01, - 1.47228797e-01, 1.28422307e-01, 1.10942255e-01, 9.48266535e-02, - 8.00991437e-02, 6.67676585e-02, 5.48243661e-02, 4.42458885e-02, - 3.49936100e-02, 2.70146141e-02, 2.02437018e-02, 1.46079676e-02, - 9.99674359e-03, 5.30523510e-03, -}; - -static const float mdct_win_10m_320[320+200] = { - -3.02115349e-04, -5.86773749e-04, -8.36650400e-04, -1.12663536e-03, - -1.47049294e-03, -1.87347339e-03, -2.33929236e-03, -2.87200807e-03, - -3.47625639e-03, -4.15596382e-03, -4.91456379e-03, -5.75517250e-03, - -6.68062338e-03, -7.69381692e-03, -8.79676075e-03, -9.99050307e-03, - -1.12757412e-02, -1.26533415e-02, -1.41243899e-02, -1.56888962e-02, - -1.73451209e-02, -1.90909737e-02, -2.09254671e-02, -2.28468479e-02, - -2.48520772e-02, -2.69374670e-02, -2.90995249e-02, -3.13350463e-02, - -3.36396073e-02, -3.60082097e-02, -3.84360174e-02, -4.09174603e-02, - -4.34465489e-02, -4.60178672e-02, -4.86259851e-02, -5.12647420e-02, - -5.39264475e-02, -5.66038431e-02, -5.92911675e-02, -6.19826820e-02, - -6.46702555e-02, -6.73454222e-02, -7.00009902e-02, -7.26305701e-02, - -7.52278496e-02, -7.77852594e-02, -8.02948025e-02, -8.27492454e-02, - -8.51412546e-02, -8.74637912e-02, -8.97106934e-02, -9.18756408e-02, - -9.39517698e-02, -9.59313774e-02, -9.78084326e-02, -9.95785130e-02, - -1.01236117e-01, -1.02774104e-01, -1.04186122e-01, -1.05468025e-01, - -1.06616088e-01, -1.07625538e-01, -1.08491230e-01, -1.09208742e-01, - -1.09773615e-01, -1.10180886e-01, -1.10427188e-01, -1.10510836e-01, - -1.10428147e-01, -1.10173922e-01, -1.09743736e-01, -1.09135313e-01, - -1.08346734e-01, -1.07373994e-01, -1.06213016e-01, -1.04860615e-01, - -1.03313240e-01, -1.01567316e-01, -9.96200551e-02, -9.74680323e-02, - -9.51072362e-02, -9.25330338e-02, -8.97412522e-02, -8.67287769e-02, - -8.34921384e-02, -8.00263990e-02, -7.63267954e-02, -7.23880616e-02, - -6.82057680e-02, -6.37761143e-02, -5.90938600e-02, -5.41531632e-02, - -4.89481272e-02, -4.34734711e-02, -3.77246130e-02, -3.16958761e-02, - -2.53817983e-02, -1.87768910e-02, -1.18746138e-02, -4.66909925e-03, - 2.84409675e-03, 1.06697612e-02, 1.88135595e-02, 2.72815601e-02, - 3.60781047e-02, 4.52070276e-02, 5.46723880e-02, 6.44786605e-02, - 7.46286220e-02, 8.51249057e-02, 9.59698399e-02, 1.07165078e-01, - 1.18711585e-01, 1.30610107e-01, 1.42859645e-01, 1.55458473e-01, - 1.68404161e-01, 1.81694789e-01, 1.95327388e-01, 2.09296321e-01, - 2.23594564e-01, 2.38216022e-01, 2.53152972e-01, 2.68396157e-01, - 2.83936139e-01, 2.99762426e-01, 3.15861908e-01, 3.32221055e-01, - 3.48826468e-01, 3.65664038e-01, 3.82715297e-01, 3.99961186e-01, - 4.17384327e-01, 4.34966962e-01, 4.52687640e-01, 4.70524201e-01, - 4.88453925e-01, 5.06454555e-01, 5.24500675e-01, 5.42567437e-01, - 5.60631204e-01, 5.78667265e-01, 5.96647704e-01, 6.14545890e-01, - 6.32336194e-01, 6.49992632e-01, 6.67487403e-01, 6.84793267e-01, - 7.01883546e-01, 7.18732254e-01, 7.35312821e-01, 7.51600199e-01, - 7.67569925e-01, 7.83197457e-01, 7.98458386e-01, 8.13329535e-01, - 8.27789227e-01, 8.41817856e-01, 8.55396130e-01, 8.68506898e-01, - 8.81133444e-01, 8.93259678e-01, 9.04874884e-01, 9.15965761e-01, - 9.26521530e-01, 9.36533999e-01, 9.45997703e-01, 9.54908841e-01, - 9.63265812e-01, 9.71068890e-01, 9.78320416e-01, 9.85022676e-01, - 9.91179208e-01, 9.96798994e-01, 1.00189402e+00, 1.00647434e+00, - 1.01055206e+00, 1.01414254e+00, 1.01726259e+00, 1.01992884e+00, - 1.02215987e+00, 1.02397632e+00, 1.02540073e+00, 1.02645534e+00, - 1.02716451e+00, 1.02755273e+00, 1.02764446e+00, 1.02746325e+00, - 1.02703590e+00, 1.02638907e+00, 1.02554820e+00, 1.02453713e+00, - 1.02338080e+00, 1.02210370e+00, 1.02072836e+00, 1.01927533e+00, - 1.01776518e+00, 1.01621736e+00, 1.01466531e+00, 1.01324907e+00, - 1.01194801e+00, 1.01018909e+00, 1.00855796e+00, 1.00701129e+00, - 1.00554876e+00, 1.00416842e+00, 1.00286727e+00, 1.00164177e+00, - 1.00048907e+00, 9.99406080e-01, 9.98389887e-01, 9.97437085e-01, - 9.96544484e-01, 9.95709855e-01, 9.94930241e-01, 9.94202405e-01, - 9.93524160e-01, 9.92893043e-01, 9.92306810e-01, 9.91763378e-01, - 9.91259764e-01, 9.90795450e-01, 9.90367789e-01, 9.89975161e-01, - 9.89616034e-01, 9.89289016e-01, 9.88992851e-01, 9.88726033e-01, - 9.88486872e-01, 9.88275104e-01, 9.88089217e-01, 9.87927711e-01, - 9.87789826e-01, 9.87674344e-01, 9.87580750e-01, 9.87507202e-01, - 9.87452945e-01, 9.87416974e-01, 9.87398469e-01, 9.87395830e-01, - 9.87408003e-01, 9.87434340e-01, 9.87473624e-01, 9.87524314e-01, - 9.87585620e-01, 9.87656379e-01, 9.87735892e-01, 9.87822558e-01, - 9.87915097e-01, 9.88013273e-01, 9.88115695e-01, 9.88221131e-01, - 9.88328903e-01, 9.88437831e-01, 9.88547679e-01, 9.88656841e-01, - 9.88764587e-01, 9.88870854e-01, 9.88974432e-01, 9.89074727e-01, - 9.89171004e-01, 9.89263102e-01, 9.89350722e-01, 9.89433065e-01, - 9.89509692e-01, 9.89581081e-01, 9.89646747e-01, 9.89706737e-01, - 9.89760693e-01, 9.89809448e-01, 9.89853013e-01, 9.89891471e-01, - 9.89925419e-01, 9.89955420e-01, 9.89982449e-01, 9.90006512e-01, - 9.90028481e-01, 9.90049748e-01, 9.90070956e-01, 9.90092836e-01, - 9.90116392e-01, 9.90142748e-01, 9.90173428e-01, 9.90208733e-01, - 9.90249864e-01, 9.90298369e-01, 9.90354850e-01, 9.90420508e-01, - 9.90495930e-01, 9.90582515e-01, 9.90681257e-01, 9.90792209e-01, - 9.90916546e-01, 9.91055074e-01, 9.91208461e-01, 9.91376861e-01, - 9.91560583e-01, 9.91760421e-01, 9.91976718e-01, 9.92209110e-01, - 9.92457914e-01, 9.92723123e-01, 9.93004954e-01, 9.93302728e-01, - 9.93616108e-01, 9.93945371e-01, 9.94289515e-01, 9.94648168e-01, - 9.95020303e-01, 9.95405817e-01, 9.95803871e-01, 9.96213027e-01, - 9.96632469e-01, 9.97061531e-01, 9.97499058e-01, 9.97943743e-01, - 9.98394057e-01, 9.98849312e-01, 9.99308343e-01, 9.99768922e-01, - 1.00023113e+00, 1.00069214e+00, 1.00115201e+00, 1.00160853e+00, - 1.00206049e+00, 1.00250721e+00, 1.00294713e+00, 1.00337891e+00, - 1.00380137e+00, 1.00421381e+00, 1.00461539e+00, 1.00500462e+00, - 1.00538063e+00, 1.00574328e+00, 1.00609151e+00, 1.00642491e+00, - 1.00674243e+00, 1.00704432e+00, 1.00733022e+00, 1.00759940e+00, - 1.00785206e+00, 1.00808818e+00, 1.00830803e+00, 1.00851125e+00, - 1.00869814e+00, 1.00886952e+00, 1.00902566e+00, 1.00916672e+00, - 1.00929336e+00, 1.00940640e+00, 1.00950702e+00, 1.00959526e+00, - 1.00967215e+00, 1.00973908e+00, 1.00979668e+00, 1.00984614e+00, - 1.00988808e+00, 1.00992409e+00, 1.00995538e+00, 1.00998227e+00, - 1.01000630e+00, 1.01002862e+00, 1.01005025e+00, 1.01007195e+00, - 1.01009437e+00, 1.01011892e+00, 1.01014650e+00, 1.01017711e+00, - 1.01021176e+00, 1.01025100e+00, 1.01029547e+00, 1.01034523e+00, - 1.01040032e+00, 1.01046156e+00, 1.01052862e+00, 1.01060152e+00, - 1.01067979e+00, 1.01076391e+00, 1.01085343e+00, 1.01094755e+00, - 1.01104595e+00, 1.01114849e+00, 1.01125440e+00, 1.01136308e+00, - 1.01147330e+00, 1.01158500e+00, 1.01169742e+00, 1.01180892e+00, - 1.01191926e+00, 1.01202724e+00, 1.01213215e+00, 1.01223273e+00, - 1.01232756e+00, 1.01241638e+00, 1.01249789e+00, 1.01257043e+00, - 1.01263330e+00, 1.01268528e+00, 1.01272556e+00, 1.01275258e+00, - 1.01276506e+00, 1.01276236e+00, 1.01274338e+00, 1.01270648e+00, - 1.01265084e+00, 1.01257543e+00, 1.01247947e+00, 1.01236111e+00, - 1.01221981e+00, 1.01205436e+00, 1.01186400e+00, 1.01164722e+00, - 1.01140252e+00, 1.01112965e+00, 1.01082695e+00, 1.01049292e+00, - 1.01012635e+00, 1.00972589e+00, 1.00929006e+00, 1.00881730e+00, - 1.00830503e+00, 1.00775283e+00, 1.00715783e+00, 1.00651805e+00, - 1.00583140e+00, 1.00509559e+00, 1.00430863e+00, 1.00346750e+00, - 1.00256950e+00, 1.00161271e+00, 1.00059427e+00, 9.99511170e-01, - 9.98360922e-01, 9.97140929e-01, 9.95848886e-01, 9.94481854e-01, - 9.93037528e-01, 9.91514656e-01, 9.89913680e-01, 9.88193062e-01, - 9.85942259e-01, 9.83566790e-01, 9.81142303e-01, 9.78521444e-01, - 9.75663604e-01, 9.72545344e-01, 9.69145663e-01, 9.65440618e-01, - 9.61404362e-01, 9.57011307e-01, 9.52236767e-01, 9.47054884e-01, - 9.41440374e-01, 9.35369161e-01, 9.28819009e-01, 9.21766289e-01, - 9.14189628e-01, 9.06069468e-01, 8.97389168e-01, 8.88133200e-01, - 8.78289389e-01, 8.67846957e-01, 8.56797064e-01, 8.45133465e-01, - 8.32854281e-01, 8.19959478e-01, 8.06451101e-01, 7.92334648e-01, - 7.77620449e-01, 7.62320618e-01, 7.46448649e-01, 7.30020573e-01, - 7.13056738e-01, 6.95580544e-01, 6.77617323e-01, 6.59195531e-01, - 6.40348643e-01, 6.21107220e-01, 6.01504928e-01, 5.81578761e-01, - 5.61367451e-01, 5.40918863e-01, 5.20273683e-01, 4.99478073e-01, - 4.78577418e-01, 4.57617260e-01, 4.36649021e-01, 4.15722146e-01, - 3.94885659e-01, 3.74190319e-01, 3.53686890e-01, 3.33426002e-01, - 3.13458647e-01, 2.93833790e-01, 2.74599264e-01, 2.55803064e-01, - 2.37490219e-01, 2.19703603e-01, 2.02485542e-01, 1.85874992e-01, - 1.69906780e-01, 1.54613227e-01, 1.40023821e-01, 1.26163740e-01, - 1.13053443e-01, 1.00708497e-01, 8.91402439e-02, 7.83561210e-02, - 6.83582123e-02, 5.91421154e-02, 5.06989301e-02, 4.30171776e-02, - 3.60802073e-02, 2.98631634e-02, 2.43372266e-02, 1.94767524e-02, - 1.52571017e-02, 1.16378749e-02, 8.43308778e-03, 4.44966900e-03, -}; - -static const float mdct_win_10m_480[480+300] = { - -2.35303215e-04, -4.61989875e-04, -6.26293154e-04, -7.92918043e-04, - -9.74716672e-04, -1.18025689e-03, -1.40920904e-03, -1.66447310e-03, - -1.94659161e-03, -2.25708173e-03, -2.59710692e-03, -2.96760762e-03, - -3.37045488e-03, -3.80628516e-03, -4.27687377e-03, -4.78246990e-03, - -5.32460872e-03, -5.90340381e-03, -6.52041973e-03, -7.17588528e-03, - -7.87142282e-03, -8.60658604e-03, -9.38248086e-03, -1.01982718e-02, - -1.10552055e-02, -1.19527030e-02, -1.28920591e-02, -1.38726348e-02, - -1.48952816e-02, -1.59585662e-02, -1.70628856e-02, -1.82066640e-02, - -1.93906598e-02, -2.06135542e-02, -2.18757093e-02, -2.31752632e-02, - -2.45122745e-02, -2.58847194e-02, -2.72926374e-02, -2.87339090e-02, - -3.02086274e-02, -3.17144037e-02, -3.32509886e-02, -3.48159779e-02, - -3.64089241e-02, -3.80274232e-02, -3.96706799e-02, -4.13357542e-02, - -4.30220337e-02, -4.47269805e-02, -4.64502229e-02, -4.81889149e-02, - -4.99422586e-02, -5.17069080e-02, -5.34816204e-02, -5.52633479e-02, - -5.70512315e-02, -5.88427175e-02, -6.06371724e-02, -6.24310403e-02, - -6.42230355e-02, -6.60096152e-02, -6.77896227e-02, -6.95599687e-02, - -7.13196627e-02, -7.30658127e-02, -7.47975891e-02, -7.65117823e-02, - -7.82071142e-02, -7.98801069e-02, -8.15296401e-02, -8.31523735e-02, - -8.47472895e-02, -8.63113754e-02, -8.78437445e-02, -8.93416436e-02, - -9.08041129e-02, -9.22279576e-02, -9.36123287e-02, -9.49537776e-02, - -9.62515531e-02, -9.75028462e-02, -9.87073651e-02, -9.98627129e-02, - -1.00968022e-01, -1.02020268e-01, -1.03018380e-01, -1.03959636e-01, - -1.04843883e-01, -1.05668684e-01, -1.06434282e-01, -1.07138231e-01, - -1.07779996e-01, -1.08357063e-01, -1.08869014e-01, -1.09313559e-01, - -1.09690356e-01, -1.09996966e-01, -1.10233226e-01, -1.10397281e-01, - -1.10489847e-01, -1.10508642e-01, -1.10453743e-01, -1.10322584e-01, - -1.10114583e-01, -1.09827693e-01, -1.09462175e-01, -1.09016396e-01, - -1.08490885e-01, -1.07883429e-01, -1.07193718e-01, -1.06419636e-01, - -1.05561251e-01, -1.04616281e-01, -1.03584904e-01, -1.02465016e-01, - -1.01256900e-01, -9.99586457e-02, -9.85701457e-02, -9.70891114e-02, - -9.55154582e-02, -9.38468492e-02, -9.20830006e-02, -9.02217102e-02, - -8.82630999e-02, -8.62049382e-02, -8.40474215e-02, -8.17879272e-02, - -7.94262503e-02, -7.69598078e-02, -7.43878560e-02, -7.17079700e-02, - -6.89199478e-02, -6.60218980e-02, -6.30134942e-02, -5.98919191e-02, - -5.66565564e-02, -5.33040616e-02, -4.98342724e-02, -4.62445689e-02, - -4.25345569e-02, -3.87019577e-02, -3.47458578e-02, -3.06634152e-02, - -2.64542508e-02, -2.21158161e-02, -1.76474054e-02, -1.30458136e-02, - -8.31042570e-03, -3.43826866e-03, 1.57031548e-03, 6.71769764e-03, - 1.20047702e-02, 1.74339832e-02, 2.30064206e-02, 2.87248142e-02, - 3.45889635e-02, 4.06010646e-02, 4.67610292e-02, 5.30713391e-02, - 5.95323909e-02, 6.61464781e-02, 7.29129318e-02, 7.98335419e-02, - 8.69080741e-02, 9.41381377e-02, 1.01523314e-01, 1.09065152e-01, - 1.16762655e-01, 1.24617139e-01, 1.32627295e-01, 1.40793819e-01, - 1.49115252e-01, 1.57592141e-01, 1.66222480e-01, 1.75006740e-01, - 1.83943194e-01, 1.93031818e-01, 2.02269985e-01, 2.11656743e-01, - 2.21188852e-01, 2.30865538e-01, 2.40683799e-01, 2.50642064e-01, - 2.60736512e-01, 2.70965907e-01, 2.81325902e-01, 2.91814469e-01, - 3.02427028e-01, 3.13160350e-01, 3.24009570e-01, 3.34971959e-01, - 3.46042294e-01, 3.57217518e-01, 3.68491565e-01, 3.79859512e-01, - 3.91314689e-01, 4.02853287e-01, 4.14468833e-01, 4.26157164e-01, - 4.37911390e-01, 4.49725632e-01, 4.61592545e-01, 4.73506703e-01, - 4.85460018e-01, 4.97447159e-01, 5.09459723e-01, 5.21490984e-01, - 5.33532682e-01, 5.45578981e-01, 5.57621716e-01, 5.69654673e-01, - 5.81668558e-01, 5.93656062e-01, 6.05608382e-01, 6.17519206e-01, - 6.29379661e-01, 6.41183084e-01, 6.52920354e-01, 6.64584079e-01, - 6.76165350e-01, 6.87657395e-01, 6.99051154e-01, 7.10340055e-01, - 7.21514933e-01, 7.32569177e-01, 7.43494372e-01, 7.54284633e-01, - 7.64931365e-01, 7.75428189e-01, 7.85767017e-01, 7.95941465e-01, - 8.05943723e-01, 8.15768707e-01, 8.25408622e-01, 8.34858937e-01, - 8.44112583e-01, 8.53165119e-01, 8.62010834e-01, 8.70645634e-01, - 8.79063156e-01, 8.87259971e-01, 8.95231329e-01, 9.02975168e-01, - 9.10486312e-01, 9.17762555e-01, 9.24799743e-01, 9.31596250e-01, - 9.38149486e-01, 9.44458839e-01, 9.50522086e-01, 9.56340292e-01, - 9.61911452e-01, 9.67236671e-01, 9.72315664e-01, 9.77150119e-01, - 9.81739750e-01, 9.86086587e-01, 9.90190638e-01, 9.94055718e-01, - 9.97684240e-01, 1.00108096e+00, 1.00424751e+00, 1.00718858e+00, - 1.00990665e+00, 1.01240743e+00, 1.01469470e+00, 1.01677466e+00, - 1.01865099e+00, 1.02033046e+00, 1.02181733e+00, 1.02311884e+00, - 1.02424026e+00, 1.02518972e+00, 1.02597245e+00, 1.02659694e+00, - 1.02706918e+00, 1.02739752e+00, 1.02758790e+00, 1.02764895e+00, - 1.02758583e+00, 1.02740852e+00, 1.02712299e+00, 1.02673867e+00, - 1.02626166e+00, 1.02570100e+00, 1.02506178e+00, 1.02435398e+00, - 1.02358239e+00, 1.02275651e+00, 1.02188060e+00, 1.02096387e+00, - 1.02000914e+00, 1.01902729e+00, 1.01801944e+00, 1.01699650e+00, - 1.01595743e+00, 1.01492344e+00, 1.01391595e+00, 1.01304757e+00, - 1.01221613e+00, 1.01104487e+00, 1.00991459e+00, 1.00882489e+00, - 1.00777386e+00, 1.00676170e+00, 1.00578665e+00, 1.00484875e+00, - 1.00394608e+00, 1.00307885e+00, 1.00224501e+00, 1.00144473e+00, - 1.00067619e+00, 9.99939317e-01, 9.99232085e-01, 9.98554813e-01, - 9.97905542e-01, 9.97284268e-01, 9.96689095e-01, 9.96120338e-01, - 9.95576126e-01, 9.95056572e-01, 9.94559753e-01, 9.94086038e-01, - 9.93633779e-01, 9.93203161e-01, 9.92792187e-01, 9.92401518e-01, - 9.92029727e-01, 9.91676778e-01, 9.91340877e-01, 9.91023065e-01, - 9.90721643e-01, 9.90436680e-01, 9.90166895e-01, 9.89913101e-01, - 9.89673564e-01, 9.89448837e-01, 9.89237484e-01, 9.89040193e-01, - 9.88855636e-01, 9.88684347e-01, 9.88524761e-01, 9.88377852e-01, - 9.88242327e-01, 9.88118564e-01, 9.88005163e-01, 9.87903202e-01, - 9.87811174e-01, 9.87729546e-01, 9.87657198e-01, 9.87594984e-01, - 9.87541274e-01, 9.87496906e-01, 9.87460625e-01, 9.87432981e-01, - 9.87412641e-01, 9.87400475e-01, 9.87394992e-01, 9.87396916e-01, - 9.87404906e-01, 9.87419705e-01, 9.87439972e-01, 9.87466328e-01, - 9.87497321e-01, 9.87533893e-01, 9.87574654e-01, 9.87620124e-01, - 9.87668980e-01, 9.87722156e-01, 9.87778192e-01, 9.87837649e-01, - 9.87899199e-01, 9.87963798e-01, 9.88030030e-01, 9.88098468e-01, - 9.88167801e-01, 9.88239030e-01, 9.88310769e-01, 9.88383520e-01, - 9.88456016e-01, 9.88529420e-01, 9.88602222e-01, 9.88674940e-01, - 9.88746626e-01, 9.88818277e-01, 9.88888248e-01, 9.88957438e-01, - 9.89024798e-01, 9.89091125e-01, 9.89155170e-01, 9.89217866e-01, - 9.89277956e-01, 9.89336519e-01, 9.89392368e-01, 9.89446283e-01, - 9.89497212e-01, 9.89546334e-01, 9.89592362e-01, 9.89636265e-01, - 9.89677201e-01, 9.89716220e-01, 9.89752029e-01, 9.89785920e-01, - 9.89817027e-01, 9.89846207e-01, 9.89872536e-01, 9.89897514e-01, - 9.89920005e-01, 9.89941079e-01, 9.89960061e-01, 9.89978226e-01, - 9.89994556e-01, 9.90010350e-01, 9.90024832e-01, 9.90039402e-01, - 9.90053211e-01, 9.90067475e-01, 9.90081472e-01, 9.90096693e-01, - 9.90112245e-01, 9.90129379e-01, 9.90147465e-01, 9.90168060e-01, - 9.90190227e-01, 9.90215190e-01, 9.90242442e-01, 9.90273445e-01, - 9.90307127e-01, 9.90344891e-01, 9.90386228e-01, 9.90432448e-01, - 9.90482565e-01, 9.90537983e-01, 9.90598060e-01, 9.90664037e-01, - 9.90734883e-01, 9.90812038e-01, 9.90894786e-01, 9.90984259e-01, - 9.91079525e-01, 9.91181924e-01, 9.91290512e-01, 9.91406471e-01, - 9.91528801e-01, 9.91658694e-01, 9.91795272e-01, 9.91939622e-01, - 9.92090615e-01, 9.92249503e-01, 9.92415240e-01, 9.92588721e-01, - 9.92768871e-01, 9.92956911e-01, 9.93151653e-01, 9.93353924e-01, - 9.93562689e-01, 9.93779087e-01, 9.94001643e-01, 9.94231202e-01, - 9.94466818e-01, 9.94709344e-01, 9.94957285e-01, 9.95211663e-01, - 9.95471264e-01, 9.95736795e-01, 9.96006862e-01, 9.96282303e-01, - 9.96561799e-01, 9.96846133e-01, 9.97133827e-01, 9.97425669e-01, - 9.97720337e-01, 9.98018509e-01, 9.98318587e-01, 9.98621352e-01, - 9.98925543e-01, 9.99231731e-01, 9.99538258e-01, 9.99846116e-01, - 1.00015391e+00, 1.00046196e+00, 1.00076886e+00, 1.00107561e+00, - 1.00138055e+00, 1.00168424e+00, 1.00198543e+00, 1.00228487e+00, - 1.00258098e+00, 1.00287441e+00, 1.00316385e+00, 1.00345006e+00, - 1.00373157e+00, 1.00400915e+00, 1.00428146e+00, 1.00454934e+00, - 1.00481138e+00, 1.00506827e+00, 1.00531880e+00, 1.00556397e+00, - 1.00580227e+00, 1.00603455e+00, 1.00625986e+00, 1.00647902e+00, - 1.00669054e+00, 1.00689557e+00, 1.00709305e+00, 1.00728380e+00, - 1.00746662e+00, 1.00764273e+00, 1.00781104e+00, 1.00797244e+00, - 1.00812588e+00, 1.00827260e+00, 1.00841147e+00, 1.00854357e+00, - 1.00866802e+00, 1.00878601e+00, 1.00889653e+00, 1.00900077e+00, - 1.00909776e+00, 1.00918888e+00, 1.00927316e+00, 1.00935176e+00, - 1.00942394e+00, 1.00949118e+00, 1.00955240e+00, 1.00960889e+00, - 1.00965997e+00, 1.00970709e+00, 1.00974924e+00, 1.00978774e+00, - 1.00982209e+00, 1.00985371e+00, 1.00988150e+00, 1.00990696e+00, - 1.00992957e+00, 1.00995057e+00, 1.00996902e+00, 1.00998650e+00, - 1.01000236e+00, 1.01001789e+00, 1.01003217e+00, 1.01004672e+00, - 1.01006081e+00, 1.01007567e+00, 1.01009045e+00, 1.01010656e+00, - 1.01012323e+00, 1.01014176e+00, 1.01016113e+00, 1.01018264e+00, - 1.01020559e+00, 1.01023108e+00, 1.01025795e+00, 1.01028773e+00, - 1.01031948e+00, 1.01035408e+00, 1.01039064e+00, 1.01043047e+00, - 1.01047227e+00, 1.01051710e+00, 1.01056410e+00, 1.01061427e+00, - 1.01066629e+00, 1.01072136e+00, 1.01077842e+00, 1.01083825e+00, - 1.01089966e+00, 1.01096373e+00, 1.01102919e+00, 1.01109699e+00, - 1.01116586e+00, 1.01123661e+00, 1.01130817e+00, 1.01138145e+00, - 1.01145479e+00, 1.01152919e+00, 1.01160368e+00, 1.01167880e+00, - 1.01175301e+00, 1.01182748e+00, 1.01190094e+00, 1.01197388e+00, - 1.01204489e+00, 1.01211499e+00, 1.01218284e+00, 1.01224902e+00, - 1.01231210e+00, 1.01237303e+00, 1.01243046e+00, 1.01248497e+00, - 1.01253506e+00, 1.01258168e+00, 1.01262347e+00, 1.01266098e+00, - 1.01269276e+00, 1.01271979e+00, 1.01274058e+00, 1.01275575e+00, - 1.01276395e+00, 1.01276592e+00, 1.01276030e+00, 1.01274782e+00, - 1.01272696e+00, 1.01269861e+00, 1.01266140e+00, 1.01261590e+00, - 1.01256083e+00, 1.01249705e+00, 1.01242289e+00, 1.01233923e+00, - 1.01224492e+00, 1.01214046e+00, 1.01202430e+00, 1.01189756e+00, - 1.01175881e+00, 1.01160845e+00, 1.01144516e+00, 1.01126996e+00, - 1.01108126e+00, 1.01087961e+00, 1.01066368e+00, 1.01043418e+00, - 1.01018968e+00, 1.00993075e+00, 1.00965566e+00, 1.00936525e+00, - 1.00905825e+00, 1.00873476e+00, 1.00839308e+00, 1.00803431e+00, - 1.00765666e+00, 1.00726014e+00, 1.00684335e+00, 1.00640701e+00, - 1.00594915e+00, 1.00547001e+00, 1.00496799e+00, 1.00444353e+00, - 1.00389477e+00, 1.00332190e+00, 1.00272313e+00, 1.00209885e+00, - 1.00144728e+00, 1.00076851e+00, 1.00006069e+00, 9.99324268e-01, - 9.98557350e-01, 9.97760020e-01, 9.96930604e-01, 9.96069427e-01, - 9.95174643e-01, 9.94246644e-01, 9.93283713e-01, 9.92286108e-01, - 9.91252309e-01, 9.90182742e-01, 9.89075787e-01, 9.87931302e-01, - 9.86355322e-01, 9.84736245e-01, 9.83175095e-01, 9.81558334e-01, - 9.79861353e-01, 9.78061749e-01, 9.76157432e-01, 9.74137862e-01, - 9.71999011e-01, 9.69732741e-01, 9.67333198e-01, 9.64791512e-01, - 9.62101150e-01, 9.59253976e-01, 9.56242718e-01, 9.53060091e-01, - 9.49698408e-01, 9.46149812e-01, 9.42407161e-01, 9.38463416e-01, - 9.34311297e-01, 9.29944987e-01, 9.25356797e-01, 9.20540463e-01, - 9.15489628e-01, 9.10198679e-01, 9.04662060e-01, 8.98875519e-01, - 8.92833832e-01, 8.86533719e-01, 8.79971272e-01, 8.73143784e-01, - 8.66047653e-01, 8.58681252e-01, 8.51042044e-01, 8.43129723e-01, - 8.34943514e-01, 8.26483991e-01, 8.17750537e-01, 8.08744982e-01, - 7.99468149e-01, 7.89923516e-01, 7.80113773e-01, 7.70043128e-01, - 7.59714574e-01, 7.49133097e-01, 7.38302860e-01, 7.27229876e-01, - 7.15920192e-01, 7.04381434e-01, 6.92619693e-01, 6.80643883e-01, - 6.68461648e-01, 6.56083014e-01, 6.43517927e-01, 6.30775533e-01, - 6.17864165e-01, 6.04795463e-01, 5.91579959e-01, 5.78228937e-01, - 5.64753589e-01, 5.51170316e-01, 5.37490509e-01, 5.23726350e-01, - 5.09891542e-01, 4.96000807e-01, 4.82066294e-01, 4.68101711e-01, - 4.54121700e-01, 4.40142182e-01, 4.26177297e-01, 4.12241789e-01, - 3.98349961e-01, 3.84517234e-01, 3.70758372e-01, 3.57088679e-01, - 3.43522867e-01, 3.30076376e-01, 3.16764033e-01, 3.03600465e-01, - 2.90599616e-01, 2.77775850e-01, 2.65143468e-01, 2.52716188e-01, - 2.40506985e-01, 2.28528397e-01, 2.16793343e-01, 2.05313990e-01, - 1.94102191e-01, 1.83168087e-01, 1.72522195e-01, 1.62173542e-01, - 1.52132068e-01, 1.42405280e-01, 1.33001524e-01, 1.23926066e-01, - 1.15185830e-01, 1.06784043e-01, 9.87263751e-02, 9.10137900e-02, - 8.36505724e-02, 7.66350831e-02, 6.99703341e-02, 6.36518811e-02, - 5.76817602e-02, 5.20524422e-02, 4.67653841e-02, 4.18095054e-02, - 3.71864025e-02, 3.28807275e-02, 2.88954850e-02, 2.52098057e-02, - 2.18305756e-02, 1.87289619e-02, 1.59212782e-02, 1.33638143e-02, - 1.10855888e-02, 8.94347419e-03, 6.75812489e-03, 3.50443813e-03, -}; - -static const float mdct_win_7m5_60[60+46] = { - 2.95060859e-03, 7.17541132e-03, 1.37695374e-02, 2.30953556e-02, - 3.54036230e-02, 5.08289304e-02, 6.94696293e-02, 9.13884278e-02, - 1.16604575e-01, 1.45073546e-01, 1.76711174e-01, 2.11342953e-01, - 2.48768614e-01, 2.88701102e-01, 3.30823871e-01, 3.74814544e-01, - 4.20308013e-01, 4.66904918e-01, 5.14185341e-01, 5.61710041e-01, - 6.09026346e-01, 6.55671016e-01, 7.01218384e-01, 7.45240679e-01, - 7.87369206e-01, 8.27223833e-01, 8.64513675e-01, 8.98977415e-01, - 9.30407518e-01, 9.58599937e-01, 9.83447719e-01, 1.00488283e+00, - 1.02285381e+00, 1.03740495e+00, 1.04859791e+00, 1.05656184e+00, - 1.06149371e+00, 1.06362578e+00, 1.06325973e+00, 1.06074505e+00, - 1.05643590e+00, 1.05069500e+00, 1.04392435e+00, 1.03647725e+00, - 1.02872867e+00, 1.02106486e+00, 1.01400658e+00, 1.00727455e+00, - 1.00172250e+00, 9.97309592e-01, 9.93985158e-01, 9.91683335e-01, - 9.90325325e-01, 9.89822613e-01, 9.90074734e-01, 9.90975314e-01, - 9.92412851e-01, 9.94273149e-01, 9.96439157e-01, 9.98791616e-01, - 1.00120985e+00, 1.00357357e+00, 1.00575984e+00, 1.00764515e+00, - 1.00910687e+00, 1.01002476e+00, 1.01028203e+00, 1.00976919e+00, - 1.00838641e+00, 1.00605124e+00, 1.00269767e+00, 9.98280464e-01, - 9.92777987e-01, 9.86186892e-01, 9.77634164e-01, 9.67447270e-01, - 9.55129725e-01, 9.40389877e-01, 9.22959280e-01, 9.02607350e-01, - 8.79202689e-01, 8.52641750e-01, 8.22881272e-01, 7.89971715e-01, - 7.54030328e-01, 7.15255742e-01, 6.73936911e-01, 6.30414716e-01, - 5.85078858e-01, 5.38398518e-01, 4.90833753e-01, 4.42885823e-01, - 3.95091024e-01, 3.48004343e-01, 3.02196710e-01, 2.58227431e-01, - 2.16641416e-01, 1.77922122e-01, 1.42480547e-01, 1.10652194e-01, - 8.26995967e-02, 5.88334516e-02, 3.92030848e-02, 2.38629107e-02, - 1.26976223e-02, 5.35665361e-03, -}; - -static const float mdct_win_7m5_120[120+92] = { - 2.20824874e-03, 3.81014420e-03, 5.91552473e-03, 8.58361457e-03, - 1.18759723e-02, 1.58335301e-02, 2.04918652e-02, 2.58883593e-02, - 3.20415894e-02, 3.89616721e-02, 4.66742169e-02, 5.51849337e-02, - 6.45038384e-02, 7.46411071e-02, 8.56000162e-02, 9.73846703e-02, - 1.09993603e-01, 1.23419277e-01, 1.37655457e-01, 1.52690437e-01, - 1.68513363e-01, 1.85093105e-01, 2.02410419e-01, 2.20450365e-01, - 2.39167941e-01, 2.58526168e-01, 2.78498539e-01, 2.99038432e-01, - 3.20104862e-01, 3.41658622e-01, 3.63660034e-01, 3.86062695e-01, - 4.08815272e-01, 4.31871046e-01, 4.55176988e-01, 4.78676593e-01, - 5.02324813e-01, 5.26060916e-01, 5.49831283e-01, 5.73576883e-01, - 5.97241338e-01, 6.20770242e-01, 6.44099662e-01, 6.67176382e-01, - 6.89958854e-01, 7.12379980e-01, 7.34396372e-01, 7.55966688e-01, - 7.77036981e-01, 7.97558114e-01, 8.17490856e-01, 8.36796950e-01, - 8.55447310e-01, 8.73400798e-01, 8.90635719e-01, 9.07128770e-01, - 9.22848784e-01, 9.37763323e-01, 9.51860206e-01, 9.65130600e-01, - 9.77556541e-01, 9.89126209e-01, 9.99846919e-01, 1.00970073e+00, - 1.01868229e+00, 1.02681455e+00, 1.03408981e+00, 1.04051196e+00, - 1.04610837e+00, 1.05088565e+00, 1.05486289e+00, 1.05807221e+00, - 1.06053414e+00, 1.06227662e+00, 1.06333815e+00, 1.06375557e+00, - 1.06356632e+00, 1.06282156e+00, 1.06155996e+00, 1.05981709e+00, - 1.05765876e+00, 1.05512006e+00, 1.05223985e+00, 1.04908779e+00, - 1.04569860e+00, 1.04210831e+00, 1.03838099e+00, 1.03455276e+00, - 1.03067200e+00, 1.02679167e+00, 1.02295558e+00, 1.01920733e+00, - 1.01587289e+00, 1.01221017e+00, 1.00884559e+00, 1.00577851e+00, - 1.00300262e+00, 1.00051460e+00, 9.98309229e-01, 9.96378601e-01, - 9.94718132e-01, 9.93316216e-01, 9.92166957e-01, 9.91258603e-01, - 9.90581104e-01, 9.90123118e-01, 9.89873712e-01, 9.89818707e-01, - 9.89946800e-01, 9.90243175e-01, 9.90695564e-01, 9.91288540e-01, - 9.92009469e-01, 9.92842693e-01, 9.93775067e-01, 9.94790398e-01, - 9.95875534e-01, 9.97014367e-01, 9.98192871e-01, 9.99394506e-01, - 1.00060586e+00, 1.00181040e+00, 1.00299457e+00, 1.00414155e+00, - 1.00523688e+00, 1.00626393e+00, 1.00720890e+00, 1.00805489e+00, - 1.00878802e+00, 1.00939182e+00, 1.00985296e+00, 1.01015529e+00, - 1.01028602e+00, 1.01022988e+00, 1.00997541e+00, 1.00950846e+00, - 1.00881848e+00, 1.00789488e+00, 1.00672876e+00, 1.00530991e+00, - 1.00363456e+00, 1.00169363e+00, 9.99485663e-01, 9.97006370e-01, - 9.94254687e-01, 9.91231967e-01, 9.87937115e-01, 9.84375125e-01, - 9.79890963e-01, 9.75269879e-01, 9.70180498e-01, 9.64580027e-01, - 9.58425534e-01, 9.51684014e-01, 9.44320232e-01, 9.36290624e-01, - 9.27580507e-01, 9.18153414e-01, 9.07976524e-01, 8.97050058e-01, - 8.85351360e-01, 8.72857927e-01, 8.59579819e-01, 8.45502615e-01, - 8.30619943e-01, 8.14946648e-01, 7.98489378e-01, 7.81262450e-01, - 7.63291769e-01, 7.44590843e-01, 7.25199287e-01, 7.05153668e-01, - 6.84490545e-01, 6.63245210e-01, 6.41477162e-01, 6.19235334e-01, - 5.96559133e-01, 5.73519989e-01, 5.50173851e-01, 5.26568538e-01, - 5.02781159e-01, 4.78860889e-01, 4.54877894e-01, 4.30898123e-01, - 4.06993964e-01, 3.83234031e-01, 3.59680098e-01, 3.36408100e-01, - 3.13496418e-01, 2.91010565e-01, 2.69019585e-01, 2.47584348e-01, - 2.26788433e-01, 2.06677771e-01, 1.87310343e-01, 1.68739644e-01, - 1.51012382e-01, 1.34171842e-01, 1.18254662e-01, 1.03290734e-01, - 8.93117360e-02, 7.63429787e-02, 6.44077291e-02, 5.35243715e-02, - 4.37084453e-02, 3.49667099e-02, 2.72984629e-02, 2.06895808e-02, - 1.51125125e-02, 1.05228754e-02, 6.85547314e-03, 4.02351119e-03, -}; - -static const float mdct_win_7m5_180[180+138] = { - 1.97084908e-03, 2.95060859e-03, 4.12447721e-03, 5.52688664e-03, - 7.17541132e-03, 9.08757730e-03, 1.12819105e-02, 1.37695374e-02, - 1.65600266e-02, 1.96650895e-02, 2.30953556e-02, 2.68612894e-02, - 3.09632560e-02, 3.54036230e-02, 4.01915610e-02, 4.53331403e-02, - 5.08289304e-02, 5.66815448e-02, 6.28935304e-02, 6.94696293e-02, - 7.64106314e-02, 8.37160016e-02, 9.13884278e-02, 9.94294008e-02, - 1.07834725e-01, 1.16604575e-01, 1.25736503e-01, 1.35226811e-01, - 1.45073546e-01, 1.55273819e-01, 1.65822194e-01, 1.76711174e-01, - 1.87928776e-01, 1.99473180e-01, 2.11342953e-01, 2.23524554e-01, - 2.36003100e-01, 2.48768614e-01, 2.61813811e-01, 2.75129161e-01, - 2.88701102e-01, 3.02514034e-01, 3.16558805e-01, 3.30823871e-01, - 3.45295567e-01, 3.59963992e-01, 3.74814544e-01, 3.89831817e-01, - 4.05001010e-01, 4.20308013e-01, 4.35739515e-01, 4.51277817e-01, - 4.66904918e-01, 4.82609041e-01, 4.98375466e-01, 5.14185341e-01, - 5.30021478e-01, 5.45869352e-01, 5.61710041e-01, 5.77528151e-01, - 5.93304696e-01, 6.09026346e-01, 6.24674189e-01, 6.40227555e-01, - 6.55671016e-01, 6.70995935e-01, 6.86184559e-01, 7.01218384e-01, - 7.16078449e-01, 7.30756084e-01, 7.45240679e-01, 7.59515122e-01, - 7.73561955e-01, 7.87369206e-01, 8.00923138e-01, 8.14211386e-01, - 8.27223833e-01, 8.39952374e-01, 8.52386102e-01, 8.64513675e-01, - 8.76324079e-01, 8.87814288e-01, 8.98977415e-01, 9.09803319e-01, - 9.20284312e-01, 9.30407518e-01, 9.40169652e-01, 9.49567795e-01, - 9.58599937e-01, 9.67260260e-01, 9.75545166e-01, 9.83447719e-01, - 9.90971957e-01, 9.98119269e-01, 1.00488283e+00, 1.01125773e+00, - 1.01724436e+00, 1.02285381e+00, 1.02808734e+00, 1.03293706e+00, - 1.03740495e+00, 1.04150164e+00, 1.04523236e+00, 1.04859791e+00, - 1.05160340e+00, 1.05425505e+00, 1.05656184e+00, 1.05853400e+00, - 1.06017414e+00, 1.06149371e+00, 1.06249943e+00, 1.06320577e+00, - 1.06362578e+00, 1.06376487e+00, 1.06363778e+00, 1.06325973e+00, - 1.06264695e+00, 1.06180496e+00, 1.06074505e+00, 1.05948492e+00, - 1.05804533e+00, 1.05643590e+00, 1.05466218e+00, 1.05274047e+00, - 1.05069500e+00, 1.04853894e+00, 1.04627898e+00, 1.04392435e+00, - 1.04149540e+00, 1.03901003e+00, 1.03647725e+00, 1.03390793e+00, - 1.03131989e+00, 1.02872867e+00, 1.02614832e+00, 1.02358988e+00, - 1.02106486e+00, 1.01856262e+00, 1.01655770e+00, 1.01400658e+00, - 1.01162953e+00, 1.00938590e+00, 1.00727455e+00, 1.00529616e+00, - 1.00344526e+00, 1.00172250e+00, 1.00012792e+00, 9.98657533e-01, - 9.97309592e-01, 9.96083571e-01, 9.94976569e-01, 9.93985158e-01, - 9.93107530e-01, 9.92341305e-01, 9.91683335e-01, 9.91130070e-01, - 9.90678325e-01, 9.90325325e-01, 9.90067562e-01, 9.89901282e-01, - 9.89822613e-01, 9.89827845e-01, 9.89913241e-01, 9.90074734e-01, - 9.90308256e-01, 9.90609852e-01, 9.90975314e-01, 9.91400330e-01, - 9.91880966e-01, 9.92412851e-01, 9.92991779e-01, 9.93613381e-01, - 9.94273149e-01, 9.94966958e-01, 9.95690370e-01, 9.96439157e-01, - 9.97208572e-01, 9.97994275e-01, 9.98791616e-01, 9.99596062e-01, - 1.00040410e+00, 1.00120985e+00, 1.00200976e+00, 1.00279924e+00, - 1.00357357e+00, 1.00432828e+00, 1.00505850e+00, 1.00575984e+00, - 1.00642767e+00, 1.00705768e+00, 1.00764515e+00, 1.00818549e+00, - 1.00867427e+00, 1.00910687e+00, 1.00947916e+00, 1.00978659e+00, - 1.01002476e+00, 1.01018954e+00, 1.01027669e+00, 1.01028203e+00, - 1.01020174e+00, 1.01003208e+00, 1.00976919e+00, 1.00940939e+00, - 1.00894931e+00, 1.00838641e+00, 1.00771780e+00, 1.00694031e+00, - 1.00605124e+00, 1.00504879e+00, 1.00393183e+00, 1.00269767e+00, - 1.00134427e+00, 9.99872092e-01, 9.98280464e-01, 9.96566569e-01, - 9.94731737e-01, 9.92777987e-01, 9.90701374e-01, 9.88504165e-01, - 9.86186892e-01, 9.83711989e-01, 9.80584643e-01, 9.77634164e-01, - 9.74455033e-01, 9.71062916e-01, 9.67447270e-01, 9.63593926e-01, - 9.59491398e-01, 9.55129725e-01, 9.50501326e-01, 9.45592810e-01, - 9.40389877e-01, 9.34886760e-01, 9.29080559e-01, 9.22959280e-01, - 9.16509579e-01, 9.09724456e-01, 9.02607350e-01, 8.95155084e-01, - 8.87356154e-01, 8.79202689e-01, 8.70699698e-01, 8.61847424e-01, - 8.52641750e-01, 8.43077833e-01, 8.33154905e-01, 8.22881272e-01, - 8.12257597e-01, 8.01285439e-01, 7.89971715e-01, 7.78318177e-01, - 7.66337710e-01, 7.54030328e-01, 7.41407991e-01, 7.28477501e-01, - 7.15255742e-01, 7.01751739e-01, 6.87975632e-01, 6.73936911e-01, - 6.59652573e-01, 6.45139489e-01, 6.30414716e-01, 6.15483622e-01, - 6.00365852e-01, 5.85078858e-01, 5.69649536e-01, 5.54084810e-01, - 5.38398518e-01, 5.22614738e-01, 5.06756805e-01, 4.90833753e-01, - 4.74866033e-01, 4.58876566e-01, 4.42885823e-01, 4.26906539e-01, - 4.10970973e-01, 3.95091024e-01, 3.79291327e-01, 3.63587417e-01, - 3.48004343e-01, 3.32563201e-01, 3.17287485e-01, 3.02196710e-01, - 2.87309403e-01, 2.72643992e-01, 2.58227431e-01, 2.44072856e-01, - 2.30208977e-01, 2.16641416e-01, 2.03398481e-01, 1.90486162e-01, - 1.77922122e-01, 1.65726674e-01, 1.53906397e-01, 1.42480547e-01, - 1.31453980e-01, 1.20841778e-01, 1.10652194e-01, 1.00891734e-01, - 9.15718851e-02, 8.26995967e-02, 7.42815529e-02, 6.63242382e-02, - 5.88334516e-02, 5.18140676e-02, 4.52698346e-02, 3.92030848e-02, - 3.36144159e-02, 2.85023308e-02, 2.38629107e-02, 1.96894227e-02, - 1.59720527e-02, 1.26976223e-02, 9.84937739e-03, 7.40724463e-03, - 5.35665361e-03, 3.83226552e-03, -}; - -static const float mdct_win_7m5_240[240+184] = { - 1.84833037e-03, 2.56481839e-03, 3.36762118e-03, 4.28736617e-03, - 5.33830143e-03, 6.52679223e-03, 7.86112587e-03, 9.34628179e-03, - 1.09916868e-02, 1.28011172e-02, 1.47805911e-02, 1.69307043e-02, - 1.92592307e-02, 2.17696937e-02, 2.44685983e-02, 2.73556543e-02, - 3.04319230e-02, 3.36980464e-02, 3.71583577e-02, 4.08148180e-02, - 4.46708068e-02, 4.87262995e-02, 5.29820633e-02, 5.74382470e-02, - 6.20968580e-02, 6.69609767e-02, 7.20298364e-02, 7.73039146e-02, - 8.27825574e-02, 8.84682102e-02, 9.43607566e-02, 1.00460272e-01, - 1.06763824e-01, 1.13273679e-01, 1.19986420e-01, 1.26903521e-01, - 1.34020853e-01, 1.41339557e-01, 1.48857211e-01, 1.56573685e-01, - 1.64484622e-01, 1.72589077e-01, 1.80879090e-01, 1.89354320e-01, - 1.98012244e-01, 2.06854141e-01, 2.15875319e-01, 2.25068672e-01, - 2.34427407e-01, 2.43948314e-01, 2.53627993e-01, 2.63464061e-01, - 2.73450494e-01, 2.83582189e-01, 2.93853469e-01, 3.04257373e-01, - 3.14790914e-01, 3.25449123e-01, 3.36227410e-01, 3.47118760e-01, - 3.58120177e-01, 3.69224663e-01, 3.80427793e-01, 3.91720023e-01, - 4.03097022e-01, 4.14551955e-01, 4.26081719e-01, 4.37676318e-01, - 4.49330196e-01, 4.61034855e-01, 4.72786043e-01, 4.84576777e-01, - 4.96401707e-01, 5.08252458e-01, 5.20122078e-01, 5.32002077e-01, - 5.43888090e-01, 5.55771601e-01, 5.67645739e-01, 5.79502786e-01, - 5.91335035e-01, 6.03138367e-01, 6.14904172e-01, 6.26623941e-01, - 6.38288834e-01, 6.49893375e-01, 6.61432360e-01, 6.72902514e-01, - 6.84293750e-01, 6.95600460e-01, 7.06811784e-01, 7.17923425e-01, - 7.28931386e-01, 7.39832773e-01, 7.50618982e-01, 7.61284053e-01, - 7.71818919e-01, 7.82220992e-01, 7.92481330e-01, 8.02599448e-01, - 8.12565230e-01, 8.22377129e-01, 8.32030518e-01, 8.41523208e-01, - 8.50848313e-01, 8.60002412e-01, 8.68979881e-01, 8.77778347e-01, - 8.86395904e-01, 8.94829421e-01, 9.03077626e-01, 9.11132652e-01, - 9.18993585e-01, 9.26652937e-01, 9.34111420e-01, 9.41364344e-01, - 9.48412967e-01, 9.55255630e-01, 9.61892013e-01, 9.68316363e-01, - 9.74530156e-01, 9.80528338e-01, 9.86313928e-01, 9.91886049e-01, - 9.97246345e-01, 1.00239190e+00, 1.00731946e+00, 1.01202707e+00, - 1.01651654e+00, 1.02079430e+00, 1.02486082e+00, 1.02871471e+00, - 1.03235170e+00, 1.03577375e+00, 1.03898432e+00, 1.04198786e+00, - 1.04478564e+00, 1.04737818e+00, 1.04976743e+00, 1.05195405e+00, - 1.05394290e+00, 1.05573463e+00, 1.05734177e+00, 1.05875726e+00, - 1.05998674e+00, 1.06103672e+00, 1.06190651e+00, 1.06260369e+00, - 1.06313289e+00, 1.06350237e+00, 1.06370981e+00, 1.06376322e+00, - 1.06366765e+00, 1.06343012e+00, 1.06305656e+00, 1.06255421e+00, - 1.06192235e+00, 1.06116702e+00, 1.06029469e+00, 1.05931469e+00, - 1.05823465e+00, 1.05705891e+00, 1.05578948e+00, 1.05442979e+00, - 1.05298793e+00, 1.05147505e+00, 1.04989930e+00, 1.04826213e+00, - 1.04656691e+00, 1.04481699e+00, 1.04302125e+00, 1.04118768e+00, - 1.03932339e+00, 1.03743168e+00, 1.03551757e+00, 1.03358511e+00, - 1.03164371e+00, 1.02969955e+00, 1.02775944e+00, 1.02582719e+00, - 1.02390791e+00, 1.02200805e+00, 1.02013910e+00, 1.01826310e+00, - 1.01687901e+00, 1.01492195e+00, 1.01309662e+00, 1.01134205e+00, - 1.00965912e+00, 1.00805036e+00, 1.00651754e+00, 1.00505799e+00, - 1.00366956e+00, 1.00235327e+00, 1.00110981e+00, 9.99937523e-01, - 9.98834524e-01, 9.97800606e-01, 9.96835756e-01, 9.95938881e-01, - 9.95108459e-01, 9.94343411e-01, 9.93642921e-01, 9.93005832e-01, - 9.92430984e-01, 9.91917493e-01, 9.91463898e-01, 9.91068214e-01, - 9.90729218e-01, 9.90446225e-01, 9.90217819e-01, 9.90041963e-01, - 9.89917085e-01, 9.89841975e-01, 9.89815048e-01, 9.89834329e-01, - 9.89898211e-01, 9.90005403e-01, 9.90154189e-01, 9.90342427e-01, - 9.90568459e-01, 9.90830953e-01, 9.91128038e-01, 9.91457566e-01, - 9.91817881e-01, 9.92207559e-01, 9.92624757e-01, 9.93067358e-01, - 9.93533398e-01, 9.94021410e-01, 9.94529685e-01, 9.95055964e-01, - 9.95598351e-01, 9.96155580e-01, 9.96725627e-01, 9.97306092e-01, - 9.97895214e-01, 9.98491441e-01, 9.99092890e-01, 9.99697063e-01, - 1.00030303e+00, 1.00090793e+00, 1.00151084e+00, 1.00210923e+00, - 1.00270118e+00, 1.00328513e+00, 1.00385926e+00, 1.00442111e+00, - 1.00496860e+00, 1.00550040e+00, 1.00601455e+00, 1.00650869e+00, - 1.00698104e+00, 1.00743004e+00, 1.00785364e+00, 1.00824962e+00, - 1.00861604e+00, 1.00895138e+00, 1.00925390e+00, 1.00952134e+00, - 1.00975175e+00, 1.00994371e+00, 1.01009550e+00, 1.01020488e+00, - 1.01027007e+00, 1.01028975e+00, 1.01026227e+00, 1.01018562e+00, - 1.01005820e+00, 1.00987882e+00, 1.00964593e+00, 1.00935753e+00, - 1.00901228e+00, 1.00860959e+00, 1.00814837e+00, 1.00762674e+00, - 1.00704343e+00, 1.00639775e+00, 1.00568877e+00, 1.00491559e+00, - 1.00407768e+00, 1.00317429e+00, 1.00220424e+00, 1.00116684e+00, - 1.00006248e+00, 9.98891422e-01, 9.97652252e-01, 9.96343856e-01, - 9.94967462e-01, 9.93524663e-01, 9.92013927e-01, 9.90433283e-01, - 9.88785147e-01, 9.87072681e-01, 9.85297443e-01, 9.83401161e-01, - 9.80949418e-01, 9.78782729e-01, 9.76468238e-01, 9.74042850e-01, - 9.71498848e-01, 9.68829968e-01, 9.66030974e-01, 9.63095104e-01, - 9.60018198e-01, 9.56795738e-01, 9.53426267e-01, 9.49903482e-01, - 9.46222115e-01, 9.42375820e-01, 9.38361702e-01, 9.34177798e-01, - 9.29823124e-01, 9.25292320e-01, 9.20580120e-01, 9.15679793e-01, - 9.10590604e-01, 9.05315030e-01, 8.99852756e-01, 8.94199497e-01, - 8.88350152e-01, 8.82301631e-01, 8.76054874e-01, 8.69612385e-01, - 8.62972799e-01, 8.56135198e-01, 8.49098179e-01, 8.41857024e-01, - 8.34414055e-01, 8.26774617e-01, 8.18939244e-01, 8.10904891e-01, - 8.02675318e-01, 7.94253751e-01, 7.85641662e-01, 7.76838609e-01, - 7.67853193e-01, 7.58685181e-01, 7.49330658e-01, 7.39809171e-01, - 7.30109944e-01, 7.20247781e-01, 7.10224161e-01, 7.00044326e-01, - 6.89711890e-01, 6.79231154e-01, 6.68608179e-01, 6.57850997e-01, - 6.46965718e-01, 6.35959617e-01, 6.24840336e-01, 6.13603503e-01, - 6.02265091e-01, 5.90829083e-01, 5.79309408e-01, 5.67711124e-01, - 5.56037416e-01, 5.44293664e-01, 5.32489768e-01, 5.20636084e-01, - 5.08743273e-01, 4.96811166e-01, 4.84849881e-01, 4.72868107e-01, - 4.60875918e-01, 4.48881081e-01, 4.36891039e-01, 4.24912022e-01, - 4.12960603e-01, 4.01035896e-01, 3.89157867e-01, 3.77322199e-01, - 3.65543767e-01, 3.53832356e-01, 3.42196115e-01, 3.30644820e-01, - 3.19187559e-01, 3.07833309e-01, 2.96588182e-01, 2.85463717e-01, - 2.74462409e-01, 2.63609584e-01, 2.52883101e-01, 2.42323489e-01, - 2.31925746e-01, 2.21690837e-01, 2.11638058e-01, 2.01766920e-01, - 1.92082236e-01, 1.82589160e-01, 1.73305997e-01, 1.64229200e-01, - 1.55362654e-01, 1.46717079e-01, 1.38299391e-01, 1.30105078e-01, - 1.22145310e-01, 1.14423458e-01, 1.06941076e-01, 9.97025893e-02, - 9.27124283e-02, 8.59737427e-02, 7.94893311e-02, 7.32616579e-02, - 6.72934102e-02, 6.15874081e-02, 5.61458003e-02, 5.09700747e-02, - 4.60617047e-02, 4.14220117e-02, 3.70514189e-02, 3.29494666e-02, - 2.91153327e-02, 2.55476401e-02, 2.22437711e-02, 1.92000659e-02, - 1.64122205e-02, 1.38747611e-02, 1.15806353e-02, 9.52213664e-03, - 7.69137380e-03, 6.07207833e-03, 4.62581217e-03, 3.60685164e-03, -}; - -static const float mdct_win_7m5_360[360+276] = { - 1.72152668e-03, 2.20824874e-03, 2.68901752e-03, 3.22613342e-03, - 3.81014420e-03, 4.45371932e-03, 5.15369240e-03, 5.91552473e-03, - 6.73869158e-03, 7.62861841e-03, 8.58361457e-03, 9.60938437e-03, - 1.07060753e-02, 1.18759723e-02, 1.31190130e-02, 1.44390108e-02, - 1.58335301e-02, 1.73063081e-02, 1.88584711e-02, 2.04918652e-02, - 2.22061476e-02, 2.40057166e-02, 2.58883593e-02, 2.78552326e-02, - 2.99059145e-02, 3.20415894e-02, 3.42610013e-02, 3.65680973e-02, - 3.89616721e-02, 4.14435824e-02, 4.40140796e-02, 4.66742169e-02, - 4.94214625e-02, 5.22588489e-02, 5.51849337e-02, 5.82005143e-02, - 6.13059845e-02, 6.45038384e-02, 6.77913923e-02, 7.11707833e-02, - 7.46411071e-02, 7.82028053e-02, 8.18549521e-02, 8.56000162e-02, - 8.94357617e-02, 9.33642589e-02, 9.73846703e-02, 1.01496718e-01, - 1.05698760e-01, 1.09993603e-01, 1.14378287e-01, 1.18853508e-01, - 1.23419277e-01, 1.28075997e-01, 1.32820581e-01, 1.37655457e-01, - 1.42578648e-01, 1.47590522e-01, 1.52690437e-01, 1.57878853e-01, - 1.63152529e-01, 1.68513363e-01, 1.73957969e-01, 1.79484737e-01, - 1.85093105e-01, 1.90784835e-01, 1.96556497e-01, 2.02410419e-01, - 2.08345433e-01, 2.14359825e-01, 2.20450365e-01, 2.26617296e-01, - 2.32856279e-01, 2.39167941e-01, 2.45550642e-01, 2.52003951e-01, - 2.58526168e-01, 2.65118408e-01, 2.71775911e-01, 2.78498539e-01, - 2.85284606e-01, 2.92132459e-01, 2.99038432e-01, 3.06004256e-01, - 3.13026529e-01, 3.20104862e-01, 3.27237324e-01, 3.34423210e-01, - 3.41658622e-01, 3.48944976e-01, 3.56279252e-01, 3.63660034e-01, - 3.71085146e-01, 3.78554327e-01, 3.86062695e-01, 3.93610554e-01, - 4.01195225e-01, 4.08815272e-01, 4.16468460e-01, 4.24155411e-01, - 4.31871046e-01, 4.39614744e-01, 4.47384019e-01, 4.55176988e-01, - 4.62990138e-01, 4.70824619e-01, 4.78676593e-01, 4.86545433e-01, - 4.94428714e-01, 5.02324813e-01, 5.10229471e-01, 5.18142927e-01, - 5.26060916e-01, 5.33982818e-01, 5.41906817e-01, 5.49831283e-01, - 5.57751234e-01, 5.65667636e-01, 5.73576883e-01, 5.81476666e-01, - 5.89364661e-01, 5.97241338e-01, 6.05102013e-01, 6.12946170e-01, - 6.20770242e-01, 6.28572094e-01, 6.36348526e-01, 6.44099662e-01, - 6.51820973e-01, 6.59513822e-01, 6.67176382e-01, 6.74806795e-01, - 6.82400711e-01, 6.89958854e-01, 6.97475722e-01, 7.04950145e-01, - 7.12379980e-01, 7.19765434e-01, 7.27103833e-01, 7.34396372e-01, - 7.41638561e-01, 7.48829639e-01, 7.55966688e-01, 7.63049259e-01, - 7.70072273e-01, 7.77036981e-01, 7.83941108e-01, 7.90781257e-01, - 7.97558114e-01, 8.04271381e-01, 8.10914901e-01, 8.17490856e-01, - 8.23997094e-01, 8.30432785e-01, 8.36796950e-01, 8.43089298e-01, - 8.49305847e-01, 8.55447310e-01, 8.61511037e-01, 8.67496281e-01, - 8.73400798e-01, 8.79227518e-01, 8.84972438e-01, 8.90635719e-01, - 8.96217173e-01, 9.01716414e-01, 9.07128770e-01, 9.12456578e-01, - 9.17697261e-01, 9.22848784e-01, 9.27909917e-01, 9.32882596e-01, - 9.37763323e-01, 9.42553356e-01, 9.47252428e-01, 9.51860206e-01, - 9.56376060e-01, 9.60800602e-01, 9.65130600e-01, 9.69366689e-01, - 9.73508812e-01, 9.77556541e-01, 9.81507226e-01, 9.85364580e-01, - 9.89126209e-01, 9.92794201e-01, 9.96367545e-01, 9.99846919e-01, - 1.00322812e+00, 1.00651341e+00, 1.00970073e+00, 1.01279029e+00, - 1.01578293e+00, 1.01868229e+00, 1.02148657e+00, 1.02419772e+00, - 1.02681455e+00, 1.02933598e+00, 1.03176043e+00, 1.03408981e+00, - 1.03632326e+00, 1.03846361e+00, 1.04051196e+00, 1.04246831e+00, - 1.04433331e+00, 1.04610837e+00, 1.04779018e+00, 1.04938334e+00, - 1.05088565e+00, 1.05229923e+00, 1.05362522e+00, 1.05486289e+00, - 1.05601521e+00, 1.05708746e+00, 1.05807221e+00, 1.05897524e+00, - 1.05979447e+00, 1.06053414e+00, 1.06119412e+00, 1.06177366e+00, - 1.06227662e+00, 1.06270324e+00, 1.06305569e+00, 1.06333815e+00, - 1.06354800e+00, 1.06368607e+00, 1.06375557e+00, 1.06375743e+00, - 1.06369358e+00, 1.06356632e+00, 1.06337707e+00, 1.06312782e+00, - 1.06282156e+00, 1.06245782e+00, 1.06203634e+00, 1.06155996e+00, - 1.06102951e+00, 1.06044797e+00, 1.05981709e+00, 1.05914163e+00, - 1.05842136e+00, 1.05765876e+00, 1.05685377e+00, 1.05600761e+00, - 1.05512006e+00, 1.05419505e+00, 1.05323346e+00, 1.05223985e+00, - 1.05121668e+00, 1.05016637e+00, 1.04908779e+00, 1.04798366e+00, - 1.04685334e+00, 1.04569860e+00, 1.04452056e+00, 1.04332348e+00, - 1.04210831e+00, 1.04087907e+00, 1.03963603e+00, 1.03838099e+00, - 1.03711403e+00, 1.03583813e+00, 1.03455276e+00, 1.03326200e+00, - 1.03196750e+00, 1.03067200e+00, 1.02937564e+00, 1.02808244e+00, - 1.02679167e+00, 1.02550635e+00, 1.02422655e+00, 1.02295558e+00, - 1.02169299e+00, 1.02044475e+00, 1.01920733e+00, 1.01799992e+00, - 1.01716022e+00, 1.01587289e+00, 1.01461783e+00, 1.01339738e+00, - 1.01221017e+00, 1.01105652e+00, 1.00993444e+00, 1.00884559e+00, - 1.00778956e+00, 1.00676790e+00, 1.00577851e+00, 1.00482173e+00, - 1.00389592e+00, 1.00300262e+00, 1.00214091e+00, 1.00131213e+00, - 1.00051460e+00, 9.99748988e-01, 9.99013486e-01, 9.98309229e-01, - 9.97634934e-01, 9.96991885e-01, 9.96378601e-01, 9.95795982e-01, - 9.95242217e-01, 9.94718132e-01, 9.94222122e-01, 9.93755313e-01, - 9.93316216e-01, 9.92905809e-01, 9.92522422e-01, 9.92166957e-01, - 9.91837704e-01, 9.91535508e-01, 9.91258603e-01, 9.91007878e-01, - 9.90781723e-01, 9.90581104e-01, 9.90404336e-01, 9.90252267e-01, - 9.90123118e-01, 9.90017726e-01, 9.89934325e-01, 9.89873712e-01, - 9.89834110e-01, 9.89816359e-01, 9.89818707e-01, 9.89841998e-01, - 9.89884438e-01, 9.89946800e-01, 9.90027287e-01, 9.90126680e-01, - 9.90243175e-01, 9.90377594e-01, 9.90528134e-01, 9.90695564e-01, - 9.90878043e-01, 9.91076302e-01, 9.91288540e-01, 9.91515602e-01, - 9.91755666e-01, 9.92009469e-01, 9.92275155e-01, 9.92553486e-01, - 9.92842693e-01, 9.93143533e-01, 9.93454080e-01, 9.93775067e-01, - 9.94104689e-01, 9.94443742e-01, 9.94790398e-01, 9.95145361e-01, - 9.95506800e-01, 9.95875534e-01, 9.96249681e-01, 9.96629919e-01, - 9.97014367e-01, 9.97403799e-01, 9.97796404e-01, 9.98192871e-01, - 9.98591286e-01, 9.98992436e-01, 9.99394506e-01, 9.99798247e-01, - 1.00020179e+00, 1.00060586e+00, 1.00100858e+00, 1.00141070e+00, - 1.00181040e+00, 1.00220846e+00, 1.00260296e+00, 1.00299457e+00, - 1.00338148e+00, 1.00376444e+00, 1.00414155e+00, 1.00451348e+00, - 1.00487832e+00, 1.00523688e+00, 1.00558730e+00, 1.00593027e+00, - 1.00626393e+00, 1.00658905e+00, 1.00690380e+00, 1.00720890e+00, - 1.00750238e+00, 1.00778498e+00, 1.00805489e+00, 1.00831287e+00, - 1.00855700e+00, 1.00878802e+00, 1.00900405e+00, 1.00920593e+00, - 1.00939182e+00, 1.00956244e+00, 1.00971590e+00, 1.00985296e+00, - 1.00997177e+00, 1.01007317e+00, 1.01015529e+00, 1.01021893e+00, - 1.01026225e+00, 1.01028602e+00, 1.01028842e+00, 1.01027030e+00, - 1.01022988e+00, 1.01016802e+00, 1.01008292e+00, 1.00997541e+00, - 1.00984369e+00, 1.00968863e+00, 1.00950846e+00, 1.00930404e+00, - 1.00907371e+00, 1.00881848e+00, 1.00853675e+00, 1.00822947e+00, - 1.00789488e+00, 1.00753391e+00, 1.00714488e+00, 1.00672876e+00, - 1.00628393e+00, 1.00581146e+00, 1.00530991e+00, 1.00478053e+00, - 1.00422177e+00, 1.00363456e+00, 1.00301719e+00, 1.00237067e+00, - 1.00169363e+00, 1.00098749e+00, 1.00025108e+00, 9.99485663e-01, - 9.98689592e-01, 9.97863666e-01, 9.97006370e-01, 9.96119199e-01, - 9.95201404e-01, 9.94254687e-01, 9.93277595e-01, 9.92270651e-01, - 9.91231967e-01, 9.90163286e-01, 9.89064394e-01, 9.87937115e-01, - 9.86779736e-01, 9.85592773e-01, 9.84375125e-01, 9.83129288e-01, - 9.81348463e-01, 9.79890963e-01, 9.78400459e-01, 9.76860435e-01, - 9.75269879e-01, 9.73627353e-01, 9.71931341e-01, 9.70180498e-01, - 9.68372652e-01, 9.66506952e-01, 9.64580027e-01, 9.62592318e-01, - 9.60540986e-01, 9.58425534e-01, 9.56244393e-01, 9.53998416e-01, - 9.51684014e-01, 9.49301185e-01, 9.46846884e-01, 9.44320232e-01, - 9.41718404e-01, 9.39042580e-01, 9.36290624e-01, 9.33464050e-01, - 9.30560854e-01, 9.27580507e-01, 9.24519592e-01, 9.21378471e-01, - 9.18153414e-01, 9.14844696e-01, 9.11451652e-01, 9.07976524e-01, - 9.04417545e-01, 9.00776308e-01, 8.97050058e-01, 8.93238398e-01, - 8.89338681e-01, 8.85351360e-01, 8.81274023e-01, 8.77109638e-01, - 8.72857927e-01, 8.68519505e-01, 8.64092796e-01, 8.59579819e-01, - 8.54976007e-01, 8.50285220e-01, 8.45502615e-01, 8.40630470e-01, - 8.35667925e-01, 8.30619943e-01, 8.25482007e-01, 8.20258909e-01, - 8.14946648e-01, 8.09546696e-01, 8.04059978e-01, 7.98489378e-01, - 7.92831417e-01, 7.87090668e-01, 7.81262450e-01, 7.75353947e-01, - 7.69363613e-01, 7.63291769e-01, 7.57139016e-01, 7.50901711e-01, - 7.44590843e-01, 7.38205136e-01, 7.31738075e-01, 7.25199287e-01, - 7.18588225e-01, 7.11905687e-01, 7.05153668e-01, 6.98332634e-01, - 6.91444101e-01, 6.84490545e-01, 6.77470119e-01, 6.70388375e-01, - 6.63245210e-01, 6.56045780e-01, 6.48788627e-01, 6.41477162e-01, - 6.34114323e-01, 6.26702000e-01, 6.19235334e-01, 6.11720596e-01, - 6.04161612e-01, 5.96559133e-01, 5.88914401e-01, 5.81234783e-01, - 5.73519989e-01, 5.65770616e-01, 5.57988067e-01, 5.50173851e-01, - 5.42330194e-01, 5.34460798e-01, 5.26568538e-01, 5.18656324e-01, - 5.10728813e-01, 5.02781159e-01, 4.94819491e-01, 4.86845139e-01, - 4.78860889e-01, 4.70869928e-01, 4.62875144e-01, 4.54877894e-01, - 4.46882512e-01, 4.38889325e-01, 4.30898123e-01, 4.22918322e-01, - 4.14950878e-01, 4.06993964e-01, 3.99052648e-01, 3.91134614e-01, - 3.83234031e-01, 3.75354653e-01, 3.67502060e-01, 3.59680098e-01, - 3.51887312e-01, 3.44130166e-01, 3.36408100e-01, 3.28728966e-01, - 3.21090505e-01, 3.13496418e-01, 3.05951565e-01, 2.98454319e-01, - 2.91010565e-01, 2.83621109e-01, 2.76285415e-01, 2.69019585e-01, - 2.61812445e-01, 2.54659232e-01, 2.47584348e-01, 2.40578694e-01, - 2.33647009e-01, 2.26788433e-01, 2.20001992e-01, 2.13301325e-01, - 2.06677771e-01, 2.00140409e-01, 1.93683630e-01, 1.87310343e-01, - 1.81027384e-01, 1.74839476e-01, 1.68739644e-01, 1.62737273e-01, - 1.56825277e-01, 1.51012382e-01, 1.45298230e-01, 1.39687469e-01, - 1.34171842e-01, 1.28762544e-01, 1.23455562e-01, 1.18254662e-01, - 1.13159677e-01, 1.08171439e-01, 1.03290734e-01, 9.85202978e-02, - 9.38600023e-02, 8.93117360e-02, 8.48752103e-02, 8.05523737e-02, - 7.63429787e-02, 7.22489246e-02, 6.82699120e-02, 6.44077291e-02, - 6.06620003e-02, 5.70343711e-02, 5.35243715e-02, 5.01334690e-02, - 4.68610790e-02, 4.37084453e-02, 4.06748365e-02, 3.77612269e-02, - 3.49667099e-02, 3.22919275e-02, 2.97357669e-02, 2.72984629e-02, - 2.49787186e-02, 2.27762542e-02, 2.06895808e-02, 1.87178169e-02, - 1.68593418e-02, 1.51125125e-02, 1.34757094e-02, 1.19462709e-02, - 1.05228754e-02, 9.20130941e-03, 7.98124316e-03, 6.85547314e-03, - 5.82657334e-03, 4.87838525e-03, 4.02351119e-03, 3.15418663e-03, -}; - -const float *lc3_mdct_win[LC3_NUM_DT][LC3_NUM_SRATE] = { - - [LC3_DT_7M5] = { - [LC3_SRATE_8K ] = mdct_win_7m5_60, - [LC3_SRATE_16K] = mdct_win_7m5_120, - [LC3_SRATE_24K] = mdct_win_7m5_180, - [LC3_SRATE_32K] = mdct_win_7m5_240, - [LC3_SRATE_48K] = mdct_win_7m5_360, - }, - - [LC3_DT_10M] = { - [LC3_SRATE_8K ] = mdct_win_10m_80, - [LC3_SRATE_16K] = mdct_win_10m_160, - [LC3_SRATE_24K] = mdct_win_10m_240, - [LC3_SRATE_32K] = mdct_win_10m_320, - [LC3_SRATE_48K] = mdct_win_10m_480, - }, -}; - - -/** - * Bands limits (cf. 3.7.1-2) - */ - -const int lc3_band_lim[LC3_NUM_DT][LC3_NUM_SRATE][LC3_NUM_BANDS+1] = { - - [LC3_DT_7M5] = { - - [LC3_SRATE_8K ] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 60, 60, 60, 60 }, - - [LC3_SRATE_16K] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 36, 38, 40, 42, 44, - 46, 48, 50, 52, 54, 56, 58, 60, 62, 65, - 68, 71, 74, 77, 80, 83, 86, 90, 94, 98, - 102, 106, 110, 115, 120 }, - - [LC3_SRATE_24K] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 29, 31, - 33, 35, 37, 39, 41, 43, 45, 47, 49, 52, - 55, 58, 61, 64, 67, 70, 74, 78, 82, 86, - 90, 95, 100, 105, 110, 115, 121, 127, 134, 141, - 148, 155, 163, 171, 180 }, - - [LC3_SRATE_32K] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 26, 28, 30, 32, 34, - 36, 38, 40, 42, 45, 48, 51, 54, 57, 60, - 63, 67, 71, 75, 79, 84, 89, 94, 99, 105, - 111, 117, 124, 131, 138, 146, 154, 163, 172, 182, - 192, 203, 215, 227, 240 }, - - [LC3_SRATE_48K] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 24, 26, 28, 30, 32, 34, 36, - 38, 40, 43, 46, 49, 52, 55, 59, 63, 67, - 71, 75, 80, 85, 90, 96, 102, 108, 115, 122, - 129, 137, 146, 155, 165, 175, 186, 197, 209, 222, - 236, 251, 266, 283, 300 }, - }, - - [LC3_DT_10M] = { - - [LC3_SRATE_8K ] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, - 71, 73, 75, 77, 80 }, - - [LC3_SRATE_16K] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, - 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, - 52, 55, 58, 61, 64, 67, 70, 73, 76, 80, - 84, 88, 92, 96, 101, 106, 111, 116, 121, 127, - 133, 139, 146, 153, 160 }, - - [LC3_SRATE_24K] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 25, 27, 29, 31, 33, 35, - 37, 39, 41, 43, 46, 49, 52, 55, 58, 61, - 64, 68, 72, 76, 80, 85, 90, 95, 100, 106, - 112, 118, 125, 132, 139, 147, 155, 164, 173, 183, - 193, 204, 215, 227, 240 }, - - [LC3_SRATE_32K] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, - 41, 44, 47, 50, 53, 56, 60, 64, 68, 72, - 76, 81, 86, 91, 97, 103, 109, 116, 123, 131, - 139, 148, 157, 166, 176, 187, 199, 211, 224, 238, - 252, 268, 284, 302, 320 }, - - [LC3_SRATE_48K] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, - 22, 24, 26, 28, 30, 32, 34, 36, 39, 42, - 45, 48, 51, 55, 59, 63, 67, 71, 76, 81, - 86, 92, 98, 105, 112, 119, 127, 135, 144, 154, - 164, 175, 186, 198, 211, 225, 240, 256, 273, 291, - 310, 330, 352, 375, 400 }, - } -}; - - -/** - * SNS Quantization (cf. 3.7.4) - */ - -const float lc3_sns_lfcb[32][8] = { - - { 2.26283366e+00, 8.13311269e-01, -5.30193495e-01, -1.35664836e+00, - -1.59952177e+00, -1.44098768e+00, -1.14381648e+00, -7.55203768e-01 }, - - { 2.94516479e+00, 2.41143318e+00, 9.60455106e-01, -4.43226488e-01, - -1.22913612e+00, -1.55590039e+00, -1.49688656e+00, -1.11689987e+00 }, - - { -2.18610707e+00, -1.97152136e+00, -1.78718620e+00, -1.91865896e+00, - -1.79399122e+00, -1.35738404e+00, -7.05444279e-01, -4.78172945e-02 }, - - { 6.93688237e-01, 9.55609857e-01, 5.75230787e-01, -1.14603419e-01, - -6.46050637e-01, -9.52351370e-01, -1.07405247e+00, -7.58087707e-01 }, - - { -1.29752132e+00, -7.40369057e-01, -3.45372484e-01, -3.13285696e-01, - -4.02977243e-01, -3.72020853e-01, -7.83414177e-02, 9.70441304e-02 }, - - { 9.14652038e-01, 1.74293043e+00, 1.90906627e+00, 1.54408484e+00, - 1.09344961e+00, 6.47479550e-01, 3.61790752e-02, -2.97092807e-01 }, - - { -2.51428813e+00, -2.89175271e+00, -2.00450667e+00, -7.50912274e-01, - 4.41202105e-01, 1.20190988e+00, 1.32742857e+00, 1.22049081e+00 }, - - { -9.22188405e-01, 6.32495141e-01, 1.08736431e+00, 6.08628625e-01, - 1.31174568e-01, -2.96149158e-01, -2.07013517e-01, 1.34924917e-01 }, - - { 7.90322288e-01, 6.28401262e-01, 3.93117924e-01, 4.80007711e-01, - 4.47815138e-01, 2.09734215e-01, 6.56691996e-03, -8.61242342e-02 }, - - { 1.44775580e+00, 2.72399952e+00, 2.31083269e+00, 9.35051270e-01, - -2.74743911e-01, -9.02077697e-01, -9.40681512e-01, -6.33697039e-01 }, - - { 7.93354526e-01, 1.43931186e-02, -5.67834845e-01, -6.54760468e-01, - -4.79458998e-01, -1.73894662e-01, 6.80162706e-02, 2.95125948e-01 }, - - { 2.72425347e+00, 2.95947572e+00, 1.84953559e+00, 5.63284922e-01, - 1.39917088e-01, 3.59641093e-01, 6.89461355e-01, 6.39790177e-01 }, - - { -5.30830198e-01, -2.12690683e-01, 5.76613628e-03, 4.24871484e-01, - 4.73128952e-01, 8.58894199e-01, 1.19111161e+00, 9.96189670e-01 }, - - { 1.68728411e+00, 2.43614509e+00, 2.33019429e+00, 1.77983778e+00, - 1.44411295e+00, 1.51995177e+00, 1.47199394e+00, 9.77682474e-01 }, - - { -2.95183273e+00, -1.59393497e+00, -1.09918773e-01, 3.88609073e-01, - 5.12932650e-01, 6.28112597e-01, 8.22621796e-01, 8.75891425e-01 }, - - { 1.01878343e-01, 5.89857324e-01, 6.19047647e-01, 1.26731314e+00, - 2.41961048e+00, 2.25174253e+00, 5.26537031e-01, -3.96591513e-01 }, - - { 2.68254575e+00, 1.32738011e+00, 1.30185274e-01, -3.38533089e-01, - -3.68219236e-01, -1.91689947e-01, -1.54782377e-01, -2.34207178e-01 }, - - { 4.82697924e+00, 3.11947804e+00, 1.39513671e+00, 2.50295316e-01, - -3.93613839e-01, -6.43458173e-01, -6.42570737e-01, -7.23193223e-01 }, - - { 8.78419936e-02, -5.69586840e-01, -1.14506016e+00, -1.66968488e+00, - -1.84534418e+00, -1.56468027e+00, -1.11746759e+00, -5.33981663e-01 }, - - { 1.39102308e+00, 1.98146479e+00, 1.11265796e+00, -2.20107509e-01, - -7.74965612e-01, -5.94063874e-01, 1.36937681e-01, 8.18242891e-01 }, - - { 3.84585894e-01, -1.60588786e-01, -5.39366810e-01, -5.29309079e-01, - 1.90433547e-01, 2.56062918e+00, 2.81896398e+00, 6.56670876e-01 }, - - { 1.93227399e+00, 3.01030180e+00, 3.06543894e+00, 2.50110161e+00, - 1.93089593e+00, 5.72153811e-01, -8.11741794e-01, -1.17641811e+00 }, - - { 1.75080463e-01, -7.50522832e-01, -1.03943893e+00, -1.13577509e+00, - -1.04197904e+00, -1.52060099e-02, 2.07048392e+00, 3.42948918e+00 }, - - { -1.18817020e+00, 3.66792874e-01, 1.30957830e+00, 1.68330687e+00, - 1.25100924e+00, 9.42375752e-01, 8.26250483e-01, 4.39952741e-01 }, - - { 2.53322203e+00, 2.11274643e+00, 1.26288412e+00, 7.61513512e-01, - 5.22117938e-01, 1.18680070e-01, -4.52346828e-01, -7.00352426e-01 }, - - { 3.99889837e+00, 4.07901751e+00, 2.82285661e+00, 1.72607213e+00, - 6.47144377e-01, -3.31148521e-01, -8.84042571e-01, -1.12697341e+00 }, - - { 5.07902593e-01, 1.58838450e+00, 1.72899024e+00, 1.00692230e+00, - 3.77121232e-01, 4.76370767e-01, 1.08754740e+00, 1.08756266e+00 }, - - { 3.16856825e+00, 3.25853458e+00, 2.42230591e+00, 1.79446078e+00, - 1.52177911e+00, 1.17196707e+00, 4.89394597e-01, -6.22795716e-02 }, - - { 1.89414767e+00, 1.25108695e+00, 5.90451211e-01, 6.08358583e-01, - 8.78171010e-01, 1.11912511e+00, 1.01857662e+00, 6.20453891e-01 }, - - { 9.48880605e-01, 2.13239439e+00, 2.72345350e+00, 2.76986077e+00, - 2.54286973e+00, 2.02046264e+00, 8.30045859e-01, -2.75569174e-02 }, - - { -1.88026757e+00, -1.26431073e+00, 3.11424977e-01, 1.83670210e+00, - 2.25634192e+00, 2.04818998e+00, 2.19526837e+00, 2.02659614e+00 }, - - { 2.46375746e-01, 9.55621773e-01, 1.52046777e+00, 1.97647400e+00, - 1.94043867e+00, 2.23375847e+00, 1.98835978e+00, 1.27232673e+00 }, - -}; - -const float lc3_sns_hfcb[32][8] = { - - { 2.32028419e-01, -1.00890271e+00, -2.14223503e+00, -2.37533814e+00, - -2.23041933e+00, -2.17595881e+00, -2.29065914e+00, -2.53286398e+00 }, - - { -1.29503937e+00, -1.79929965e+00, -1.88703148e+00, -1.80991660e+00, - -1.76340038e+00, -1.83418428e+00, -1.80480981e+00, -1.73679545e+00 }, - - { 1.39285716e-01, -2.58185126e-01, -6.50804573e-01, -1.06815732e+00, - -1.61928742e+00, -2.18762566e+00, -2.63757587e+00, -2.97897750e+00 }, - - { -3.16513102e-01, -4.77747657e-01, -5.51162076e-01, -4.84788283e-01, - -2.38388394e-01, -1.43024507e-01, 6.83186674e-02, 8.83061717e-02 }, - - { 8.79518405e-01, 2.98340096e-01, -9.15386396e-01, -2.20645975e+00, - -2.74142181e+00, -2.86139074e+00, -2.88841597e+00, -2.95182608e+00 }, - - { -2.96701922e-01, -9.75004919e-01, -1.35857500e+00, -9.83721106e-01, - -6.52956939e-01, -9.89986993e-01, -1.61467225e+00, -2.40712302e+00 }, - - { 3.40981100e-01, 2.68899789e-01, 5.63335685e-02, 4.99114047e-02, - -9.54130727e-02, -7.60166146e-01, -2.32758120e+00, -3.77155485e+00 }, - - { -1.41229759e+00, -1.48522119e+00, -1.18603580e+00, -6.25001634e-01, - 1.53902497e-01, 5.76386498e-01, 7.95092604e-01, 5.96564632e-01 }, - - { -2.28839512e-01, -3.33719070e-01, -8.09321359e-01, -1.63587877e+00, - -1.88486397e+00, -1.64496691e+00, -1.40515778e+00, -1.46666471e+00 }, - - { -1.07148629e+00, -1.41767015e+00, -1.54891762e+00, -1.45296062e+00, - -1.03182970e+00, -6.90642640e-01, -4.28843805e-01, -4.94960215e-01 }, - - { -5.90988511e-01, -7.11737759e-02, 3.45719523e-01, 3.00549461e-01, - -1.11865218e+00, -2.44089151e+00, -2.22854732e+00, -1.89509228e+00 }, - - { -8.48434099e-01, -5.83226811e-01, 9.00423688e-02, 8.45025008e-01, - 1.06572385e+00, 7.37582999e-01, 2.56590452e-01, -4.91963360e-01 }, - - { 1.14069146e+00, 9.64016892e-01, 3.81461206e-01, -4.82849341e-01, - -1.81632721e+00, -2.80279513e+00, -3.23385725e+00, -3.45908714e+00 }, - - { -3.76283238e-01, 4.25675462e-02, 5.16547697e-01, 2.51716882e-01, - -2.16179968e-01, -5.34074091e-01, -6.40786096e-01, -8.69745032e-01 }, - - { 6.65004121e-01, 1.09790765e+00, 1.38342667e+00, 1.34327359e+00, - 8.22978837e-01, 2.15876799e-01, -4.04925753e-01, -1.07025606e+00 }, - - { -8.26265954e-01, -6.71181233e-01, -2.28495593e-01, 5.18980853e-01, - 1.36721896e+00, 2.18023038e+00, 2.53596093e+00, 2.20121099e+00 }, - - { 1.41008327e+00, 7.54441908e-01, -1.30550585e+00, -1.87133711e+00, - -1.24008685e+00, -1.26712925e+00, -2.03670813e+00, -2.89685162e+00 }, - - { 3.61386818e-01, -2.19991705e-02, -5.79368834e-01, -8.79427961e-01, - -8.50685023e-01, -7.79397050e-01, -7.32182927e-01, -8.88348515e-01 }, - - { 4.37469239e-01, 3.05440420e-01, -7.38786566e-03, -4.95649855e-01, - -8.06651271e-01, -1.22431892e+00, -1.70157770e+00, -2.24491914e+00 }, - - { 6.48100319e-01, 6.82299134e-01, 2.53247464e-01, 7.35842144e-02, - 3.14216709e-01, 2.34729881e-01, 1.44600134e-01, -6.82120179e-02 }, - - { 1.11919833e+00, 1.23465533e+00, 5.89170238e-01, -1.37192460e+00, - -2.37095707e+00, -2.00779783e+00, -1.66688540e+00, -1.92631846e+00 }, - - { 1.41847497e-01, -1.10660071e-01, -2.82824593e-01, -6.59813475e-03, - 2.85929280e-01, 4.60445530e-02, -6.02596416e-01, -2.26568729e+00 }, - - { 5.04046955e-01, 8.26982163e-01, 1.11981236e+00, 1.17914044e+00, - 1.07987429e+00, 6.97536239e-01, -9.12548817e-01, -3.57684747e+00 }, - - { -5.01076050e-01, -3.25678006e-01, 2.80798195e-02, 2.62054555e-01, - 3.60590806e-01, 6.35623722e-01, 9.59012467e-01, 1.30745157e+00 }, - - { 3.74970983e+00, 1.52342612e+00, -4.57715662e-01, -7.98711008e-01, - -3.86819329e-01, -3.75901062e-01, -6.57836900e-01, -1.28163964e+00 }, - - { -1.15258991e+00, -1.10800886e+00, -5.62615117e-01, -2.20562124e-01, - -3.49842880e-01, -7.53432770e-01, -9.88596593e-01, -1.28790472e+00 }, - - { 1.02827246e+00, 1.09770519e+00, 7.68645546e-01, 2.06081978e-01, - -3.42805735e-01, -7.54939405e-01, -1.04196178e+00, -1.50335653e+00 }, - - { 1.28831972e-01, 6.89439395e-01, 1.12346905e+00, 1.30934523e+00, - 1.35511965e+00, 1.42311381e+00, 1.15706449e+00, 4.06319438e-01 }, - - { 1.34033030e+00, 1.38996825e+00, 1.04467922e+00, 6.35822746e-01, - -2.74733756e-01, -1.54923372e+00, -2.44239710e+00, -3.02457607e+00 }, - - { 2.13843105e+00, 4.24711267e+00, 2.89734110e+00, 9.32730658e-01, - -2.92822250e-01, -8.10404297e-01, -7.88868099e-01, -9.35353149e-01 }, - - { 5.64830487e-01, 1.59184978e+00, 2.39771699e+00, 3.03697344e+00, - 2.66424350e+00, 1.39304485e+00, 4.03834024e-01, -6.56270971e-01 }, - - { -4.22460548e-01, 3.26149625e-01, 1.39171313e+00, 2.23146615e+00, - 2.61179442e+00, 2.66540340e+00, 2.40103554e+00, 1.75920380e+00 }, - -}; - -const struct lc3_sns_vq_gains lc3_sns_vq_gains[4] = { - - { 2, (const float []){ - 8915.f / 4096, 12054.f / 4096 } }, - - { 4, (const float []){ - 6245.f / 4096, 15043.f / 4096, 17861.f / 4096, 21014.f / 4096 } }, - - { 4, (const float []){ - 7099.f / 4096, 9132.f / 4096, 11253.f / 4096, 14808.f / 4096 } }, - - { 8, (const float []){ - 4336.f / 4096, 5067.f / 4096, 5895.f / 4096, 8149.f / 4096, - 10235.f / 4096, 12825.f / 4096, 16868.f / 4096, 19882.f / 4096 } } -}; - -const int32_t lc3_sns_mpvq_offsets[][11] = { - { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 }, - { 0, 1, 5, 13, 25, 41, 61, 85, 113, 145, 181 }, - { 0, 1, 7, 25, 63, 129, 231, 377, 575, 833, 1159 }, - { 0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649, 5641 }, - { 0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073 , 22363 }, - { 0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081, 75517 }, - { 0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545, 224143 }, - { 0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729, 598417 }, - { 0, 1, 19, 181, 1159, 5641, 22363, 75517, 224143, 598417, 1462563 }, - { 0, 1, 21, 221, 1561, 8361, 36365, 134245, 433905, 1256465, 3317445 }, - { 0, 1, 23, 265, 2047, 11969, 56695, 227305, 795455, 2485825, 7059735 }, - { 0, 1, 25, 313, 2625, 16641, 85305, 369305,1392065, 4673345,14218905 }, - { 0, 1, 27, 365, 3303, 22569, 124515, 579125,2340495, 8405905,27298155 }, - { 0, 1, 29, 421, 4089, 29961, 177045, 880685,3800305,14546705,50250765 }, - { 0, 1, 31, 481, 4991, 39041, 246047,1303777,5984767,24331777,89129247 }, -}; - - -/** - * TNS Arithmetic Coding (cf. 3.7.5) - * The number of bits are given at 2048th of bits - */ - -const struct lc3_ac_model lc3_tns_order_models[] = { - - { { { 0, 3 }, { 3, 9 }, { 12, 23 }, { 35, 54 }, - { 89, 111 }, { 200, 190 }, { 390, 268 }, { 658, 366 }, - { 1024, 0 }, { 1024, 0 }, { 1024, 0 }, { 1024, 0 }, - { 1024, 0 }, { 1024, 0 }, { 1024, 0 }, { 1024, 0 }, - { 1024, 0 } } }, - - { { { 0, 14 }, { 14, 42 }, { 56, 100 }, { 156, 157 }, - { 313, 181 }, { 494, 178 }, { 672, 167 }, { 839, 185 }, - { 1024, 0 }, { 1024, 0 }, { 1024, 0 }, { 1024, 0 }, - { 1024, 0 }, { 1024, 0 }, { 1024, 0 }, { 1024, 0 }, - { 1024, 0 } } }, -}; - -const uint16_t lc3_tns_order_bits[][8] = { - { 17234, 13988, 11216, 8694, 6566, 4977, 3961, 3040 }, - { 12683, 9437, 6874, 5541, 5121, 5170, 5359, 5056 } -}; - -const struct lc3_ac_model lc3_tns_coeffs_models[] = { - - { { { 0, 1 }, { 1, 5 }, { 6, 15 }, { 21, 31 }, - { 52, 54 }, { 106, 86 }, { 192, 97 }, { 289, 120 }, - { 409, 159 }, { 568, 152 }, { 720, 111 }, { 831, 104 }, - { 935, 59 }, { 994, 22 }, { 1016, 6 }, { 1022, 1 }, - { 1023, 1 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, - { 4, 13 }, { 17, 43 }, { 60, 94 }, { 154, 139 }, - { 293, 173 }, { 466, 160 }, { 626, 154 }, { 780, 131 }, - { 911, 78 }, { 989, 27 }, { 1016, 6 }, { 1022, 1 }, - { 1023, 1 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, - { 4, 9 }, { 13, 43 }, { 56, 106 }, { 162, 199 }, - { 361, 217 }, { 578, 210 }, { 788, 141 }, { 929, 74 }, - { 1003, 17 }, { 1020, 1 }, { 1021, 1 }, { 1022, 1 }, - { 1023, 1 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, - { 4, 2 }, { 6, 11 }, { 17, 49 }, { 66, 204 }, - { 270, 285 }, { 555, 297 }, { 852, 120 }, { 972, 39 }, - { 1011, 9 }, { 1020, 1 }, { 1021, 1 }, { 1022, 1 }, - { 1023, 1 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, - { 4, 1 }, { 5, 7 }, { 12, 42 }, { 54, 241 }, - { 295, 341 }, { 636, 314 }, { 950, 58 }, { 1008, 9 }, - { 1017, 3 }, { 1020, 1 }, { 1021, 1 }, { 1022, 1 }, - { 1023, 1 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, - { 4, 1 }, { 5, 1 }, { 6, 13 }, { 19, 205 }, - { 224, 366 }, { 590, 377 }, { 967, 47 }, { 1014, 5 }, - { 1019, 1 }, { 1020, 1 }, { 1021, 1 }, { 1022, 1 }, - { 1023, 1 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, - { 4, 1 }, { 5, 1 }, { 6, 13 }, { 19, 281 }, - { 300, 330 }, { 630, 371 }, { 1001, 17 }, { 1018, 1 }, - { 1019, 1 }, { 1020, 1 }, { 1021, 1 }, { 1022, 1 }, - { 1023, 1 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, - { 4, 1 }, { 5, 1 }, { 6, 5 }, { 11, 297 }, - { 308, 1 }, { 309, 682 }, { 991, 26 }, { 1017, 2 }, - { 1019, 1 }, { 1020, 1 }, { 1021, 1 }, { 1022, 1 }, - { 1023, 1 } } }, - -}; - -const uint16_t lc3_tns_coeffs_bits[][17] = { - - { 20480, 15725, 12479, 10334, 8694, 7320, 6964, 6335, - 5504, 5637, 6566, 6758, 8433, 11348, 15186, 20480, 20480 }, - - { 20480, 20480, 20480, 20480, 12902, 9368, 7057, 5901, - 5254, 5485, 5598, 6076, 7608, 10742, 15186, 20480, 20480 }, - - { 20480, 20480, 20480, 20480, 13988, 9368, 6702, 4841, - 4585, 4682, 5859, 7764, 12109, 20480, 20480, 20480, 20480 }, - - { 20480, 20480, 20480, 20480, 18432, 13396, 8982, 4767, - 3779, 3658, 6335, 9656, 13988, 20480, 20480, 20480, 20480 }, - - { 20480, 20480, 20480, 20480, 20480, 14731, 9437, 4275, - 3249, 3493, 8483, 13988, 17234, 20480, 20480, 20480, 20480 }, - - { 20480, 20480, 20480, 20480, 20480, 20480, 12902, 4753, - 3040, 2953, 9105, 15725, 20480, 20480, 20480, 20480, 20480 }, - - { 20480, 20480, 20480, 20480, 20480, 20480, 12902, 3821, - 3346, 3000, 12109, 20480, 20480, 20480, 20480, 20480, 20480 }, - - { 20480, 20480, 20480, 20480, 20480, 20480, 15725, 3658, - 20480, 1201, 10854, 18432, 20480, 20480, 20480, 20480, 20480 } - -}; - - -/** - * Long Term Postfilter Synthesis (cf. 3.7.6) - * with - addition of a 0 for num coefficients - * - remove of first 0 den coefficients - */ - -const float *lc3_ltpf_cnum[LC3_NUM_SRATE][4] = { - - [LC3_SRATE_8K] = { - (const float []){ - 6.02361821e-01, 4.19760926e-01, -1.88342453e-02, 0. }, - (const float []){ - 5.99476858e-01, 4.19760926e-01, -1.59492828e-02, 0. }, - (const float []){ - 5.96776466e-01, 4.19760926e-01, -1.32488910e-02, 0. }, - (const float []){ - 5.94241012e-01, 4.19760926e-01, -1.07134366e-02, 0. }, - }, - - [LC3_SRATE_16K] = { - (const float []){ - 6.02361821e-01, 4.19760926e-01, -1.88342453e-02, 0. }, - (const float []){ - 5.99476858e-01, 4.19760926e-01, -1.59492828e-02, 0. }, - (const float []){ - 5.96776466e-01, 4.19760926e-01, -1.32488910e-02, 0. }, - (const float []){ - 5.94241012e-01, 4.19760926e-01, -1.07134366e-02, 0. }, - }, - - [LC3_SRATE_24K] = { - (const float []){ - 3.98969559e-01, 5.14250861e-01, 1.00438297e-01, -1.27889396e-02, - -1.57228008e-03, 0. }, - (const float []){ - 3.94863491e-01, 5.12381921e-01, 1.04319493e-01, -1.09199996e-02, - -1.34740833e-03, 0. }, - (const float []){ - 3.90984448e-01, 5.10605352e-01, 1.07983252e-01, -9.14343107e-03, - -1.13212462e-03, 0. }, - (const float []){ - 3.87309389e-01, 5.08912208e-01, 1.11451738e-01, -7.45028713e-03, - -9.25551405e-04, 0. }, - }, - - [LC3_SRATE_32K] = { - (const float []){ - 2.98237945e-01, 4.65280920e-01, 2.10599743e-01, 3.76678038e-02, - -1.01569616e-02, -2.53588100e-03, -3.18294617e-04, 0. }, - (const float []){ - 2.94383415e-01, 4.61929400e-01, 2.12946577e-01, 4.06617500e-02, - -8.69327230e-03, -2.17830711e-03, -2.74288806e-04, 0. }, - (const float []){ - 2.90743921e-01, 4.58746191e-01, 2.15145697e-01, 4.35010477e-02, - -7.29549535e-03, -1.83439564e-03, -2.31692019e-04, 0. }, - (const float []){ - 2.87297585e-01, 4.55714889e-01, 2.17212695e-01, 4.62008888e-02, - -5.95746380e-03, -1.50293428e-03, -1.90385191e-04, 0. }, - }, - - [LC3_SRATE_48K] = { - (const float []){ - 1.98136374e-01, 3.52449490e-01, 2.51369527e-01, 1.42414624e-01, - 5.70473102e-02, 9.29336624e-03, -7.22602537e-03, -3.17267989e-03, - -1.12183596e-03, -2.90295724e-04, -4.27081559e-05, 0. }, - (const float []){ - 1.95070943e-01, 3.48466041e-01, 2.50998846e-01, 1.44116741e-01, - 5.92894732e-02, 1.10892383e-02, -6.19290811e-03, -2.72670551e-03, - -9.66712583e-04, -2.50810092e-04, -3.69993877e-05, 0. }, - (const float []){ - 1.92181006e-01, 3.44694556e-01, 2.50622009e-01, 1.45710245e-01, - 6.14113213e-02, 1.27994140e-02, -5.20372109e-03, -2.29732451e-03, - -8.16560813e-04, -2.12385575e-04, -3.14127133e-05, 0. }, - (const float []){ - 1.89448531e-01, 3.41113925e-01, 2.50240688e-01, 1.47206563e-01, - 6.34247723e-02, 1.44320343e-02, -4.25444914e-03, -1.88308147e-03, - -6.70961906e-04, -1.74936334e-04, -2.59386474e-05, 0. }, - } -}; - -const float *lc3_ltpf_cden[LC3_NUM_SRATE][4] = { - - [LC3_SRATE_8K] = { - (const float []){ - 2.09880463e-01, 5.83527575e-01, 2.09880463e-01, 0.00000000e+00 }, - (const float []){ - 1.06999186e-01, 5.50075002e-01, 3.35690625e-01, 6.69885837e-03 }, - (const float []){ - 3.96711478e-02, 4.59220930e-01, 4.59220930e-01, 3.96711478e-02 }, - (const float []){ - 6.69885837e-03, 3.35690625e-01, 5.50075002e-01, 1.06999186e-01 }, - }, - - [LC3_SRATE_16K] = { - (const float []){ - 2.09880463e-01, 5.83527575e-01, 2.09880463e-01, 0.00000000e+00 }, - (const float []){ - 1.06999186e-01, 5.50075002e-01, 3.35690625e-01, 6.69885837e-03 }, - (const float []){ - 3.96711478e-02, 4.59220930e-01, 4.59220930e-01, 3.96711478e-02 }, - (const float []){ - 6.69885837e-03, 3.35690625e-01, 5.50075002e-01, 1.06999186e-01 }, - }, - - [LC3_SRATE_24K] = { - (const float []){ - 6.32223163e-02, 2.50730961e-01, 3.71390943e-01, 2.50730961e-01, - 6.32223163e-02, 0.00000000e+00 }, - (const float []){ - 3.45927217e-02, 1.98651560e-01, 3.62641173e-01, 2.98675055e-01, - 1.01309287e-01, 4.26354371e-03 }, - (const float []){ - 1.53574678e-02, 1.47434488e-01, 3.37425955e-01, 3.37425955e-01, - 1.47434488e-01, 1.53574678e-02 }, - (const float []){ - 4.26354371e-03, 1.01309287e-01, 2.98675055e-01, 3.62641173e-01, - 1.98651560e-01, 3.45927217e-02 }, - }, - - [LC3_SRATE_32K] = { - (const float []){ - 2.90040188e-02, 1.12985742e-01, 2.21202403e-01, 2.72390947e-01, - 2.21202403e-01, 1.12985742e-01, 2.90040188e-02, 0.00000000e+00 }, - (const float []){ - 1.70315342e-02, 8.72250379e-02, 1.96140776e-01, 2.68923798e-01, - 2.42499910e-01, 1.40577336e-01, 4.47487717e-02, 3.12703024e-03 }, - (const float []){ - 8.56367375e-03, 6.42622294e-02, 1.68767671e-01, 2.58744594e-01, - 2.58744594e-01, 1.68767671e-01, 6.42622294e-02, 8.56367375e-03 }, - (const float []){ - 3.12703024e-03, 4.47487717e-02, 1.40577336e-01, 2.42499910e-01, - 2.68923798e-01, 1.96140776e-01, 8.72250379e-02, 1.70315342e-02 }, - }, - - [LC3_SRATE_48K] = { - (const float []){ - 1.08235939e-02, 3.60896922e-02, 7.67640147e-02, 1.24153058e-01, - 1.62759644e-01, 1.77677142e-01, 1.62759644e-01, 1.24153058e-01, - 7.67640147e-02, 3.60896922e-02, 1.08235939e-02, 0.00000000e+00 }, - (const float []){ - 7.04140493e-03, 2.81970232e-02, 6.54704494e-02, 1.12464799e-01, - 1.54841896e-01, 1.76712238e-01, 1.69150721e-01, 1.35290158e-01, - 8.85142501e-02, 4.49935385e-02, 1.55761371e-02, 2.03972196e-03 }, - (const float []){ - 4.14699847e-03, 2.13575731e-02, 5.48273558e-02, 1.00497144e-01, - 1.45606034e-01, 1.73843984e-01, 1.73843984e-01, 1.45606034e-01, - 1.00497144e-01, 5.48273558e-02, 2.13575731e-02, 4.14699847e-03 }, - (const float []){ - 2.03972196e-03, 1.55761371e-02, 4.49935385e-02, 8.85142501e-02, - 1.35290158e-01, 1.69150721e-01, 1.76712238e-01, 1.54841896e-01, - 1.12464799e-01, 6.54704494e-02, 2.81970232e-02, 7.04140493e-03 }, - } -}; - - -/** - * Spectral Data Arithmetic Coding (cf. 3.7.7) - * The number of bits are given at 2048th of bits - * - * The dimensions of the lookup table are set as following : - * 1: Rate selection - * 2: Half spectrum selection (1st half / 2nd half) - * 3: State of the arithmetic coder - * 4: Number of msb bits (significant - 2), limited to 3 - * - * table[r][h][s][k] = table(normative)[s + h*256 + r*512 + k*1024] - */ - -const uint8_t lc3_spectrum_lookup[2][2][256][4] = { - - { { { 1,13, 0, 0 }, { 39,13, 0, 0 }, { 7,13, 0, 0 }, { 25,13, 0, 0 }, - { 22,13, 0, 0 }, { 22,13, 0, 0 }, { 28,13, 0, 0 }, { 22,13, 0, 0 }, - { 22,60, 0, 0 }, { 22,60, 0, 0 }, { 22,60, 0, 0 }, { 28,60, 0, 0 }, - { 28,60, 0, 0 }, { 28,60,13, 0 }, { 34,60,13, 0 }, { 31,16,13, 0 }, - { 31,16,13, 0 }, { 40, 0, 0, 0 }, { 43, 0, 0, 0 }, { 46, 0, 0, 0 }, - { 49, 0, 0, 0 }, { 52, 0, 0, 0 }, { 14, 0, 0, 0 }, { 17, 0, 0, 0 }, - { 36, 0, 0, 0 }, { 36, 0, 0, 0 }, { 36, 0, 0, 0 }, { 38, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 57, 0, 0, 0 }, { 38,13, 0, 0 }, { 22,60, 0, 0 }, - { 0, 0, 0, 0 }, { 8, 0, 0, 0 }, { 9, 0, 0, 0 }, { 11, 0, 0, 0 }, - { 47, 0, 0, 0 }, { 14, 0, 0, 0 }, { 14, 0, 0, 0 }, { 17, 0, 0, 0 }, - { 36, 0, 0, 0 }, { 36, 0, 0, 0 }, { 36, 0, 0, 0 }, { 38, 0, 0, 0 }, - { 59, 0, 0, 0 }, { 59, 0, 0, 0 }, { 38,13, 0, 0 }, { 22,60, 0, 0 }, - { 22,60, 0, 0 }, { 26, 0, 0, 0 }, { 46, 0, 0, 0 }, { 29, 0, 0, 0 }, - { 30, 0, 0, 0 }, { 32, 0, 0, 0 }, { 33, 0, 0, 0 }, { 35, 0, 0, 0 }, - { 36, 0, 0, 0 }, { 36, 0, 0, 0 }, { 36, 0, 0, 0 }, { 38, 0, 0, 0 }, - { 0,13, 0, 0 }, { 59,13, 0, 0 }, { 23,13, 0, 0 }, { 22,60, 0, 0 }, - { 46,60, 0, 0 }, { 46, 0, 0, 0 }, { 45, 0, 0, 0 }, { 47, 0, 0, 0 }, - { 48, 0, 0, 0 }, { 50, 0, 0, 0 }, { 50, 0, 0, 0 }, { 18, 0, 0, 0 }, - { 54, 0, 0, 0 }, { 54, 0, 0, 0 }, { 54, 0, 0, 0 }, { 38, 0, 0, 0 }, - { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 22,60, 0, 0 }, - { 0,60, 0, 0 }, { 62, 0, 0, 0 }, { 63, 0, 0, 0 }, { 3, 0, 0, 0 }, - { 33, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 61, 0, 0, 0 }, - { 20, 0, 0, 0 }, { 20, 0, 0, 0 }, { 20,13, 0, 0 }, { 21,13, 0, 0 }, - { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 39,13, 0, 0 }, { 28,60, 0, 0 }, - { 28,60, 0, 0 }, { 63, 0, 0, 0 }, { 63, 0, 0, 0 }, { 3, 0, 0, 0 }, - { 33, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 61, 0, 0, 0 }, - { 38, 0, 0, 0 }, { 38, 0, 0, 0 }, { 38,13, 0, 0 }, { 21,13, 0, 0 }, - { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 39,13, 0, 0 }, { 28,60, 0, 0 }, - { 28,60, 0, 0 }, { 6, 0, 0, 0 }, { 6, 0, 0, 0 }, { 6, 0, 0, 0 }, - { 2, 0, 0, 0 }, { 18, 0, 0, 0 }, { 61, 0, 0, 0 }, { 20, 0, 0, 0 }, - { 21, 0, 0, 0 }, { 21, 0, 0, 0 }, { 21,13, 0, 0 }, { 59,13, 0, 0 }, - { 39,13, 0, 0 }, { 39,13, 0, 0 }, { 7,13, 0, 0 }, { 34,60,13, 0 }, - { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,60,13, 0 }, - { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,60,13, 0 }, - { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,60,13, 0 }, - { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,60,13, 0 }, - { 34,60,13, 0 }, { 51, 0, 0, 0 }, { 51, 0, 0, 0 }, { 51, 0, 0, 0 }, - { 53, 0, 0, 0 }, { 54, 0, 0, 0 }, { 20, 0, 0, 0 }, { 38, 0, 0, 0 }, - { 38, 0, 0, 0 }, { 57, 0, 0, 0 }, { 39,13, 0, 0 }, { 39,13, 0, 0 }, - { 39,13, 0, 0 }, { 7,13, 0, 0 }, { 24,13, 0, 0 }, { 34,60,13, 0 }, - { 4,60, 0, 0 }, { 4,60, 0, 0 }, { 4,60, 0, 0 }, { 4,60, 0, 0 }, - { 4,60, 0, 0 }, { 4,60, 0, 0 }, { 4,60, 0, 0 }, { 4,60, 0, 0 }, - { 4,60, 0, 0 }, { 4,60, 0, 0 }, { 4,60, 0, 0 }, { 4,60, 0, 0 }, - { 4,60, 0, 0 }, { 4,60, 0, 0 }, { 4,60, 0, 0 }, { 4,60, 0, 0 }, - { 4,60, 0, 0 }, { 4, 0, 0, 0 }, { 4, 0, 0, 0 }, { 4, 0, 0, 0 }, - { 4, 0, 0, 0 }, { 56, 0, 0, 0 }, { 38, 0, 0, 0 }, { 57, 0, 0, 0 }, - { 57,13, 0, 0 }, { 59,13, 0, 0 }, { 7,13, 0, 0 }, { 7,13, 0, 0 }, - { 7,13, 0, 0 }, { 42,13, 0, 0 }, { 42,13, 0, 0 }, { 34,60,13, 0 }, - { 0,60,13, 0 }, { 0,60,13, 0 }, { 0,60,13, 0 }, { 0,60,13, 0 }, - { 0,60,13, 0 }, { 0,60,13, 0 }, { 0,60,13, 0 }, { 0,60,13, 0 }, - { 0,60,13, 0 }, { 0,60,13, 0 }, { 0,60,13, 0 }, { 0,60,13, 0 }, - { 0,60,13, 0 }, { 0,60,13, 0 }, { 0,60,13, 0 }, { 0,60,13, 0 }, - { 0,60,13, 0 }, { 5, 0, 0, 0 }, { 4, 0, 0, 0 }, { 4, 0, 0, 0 }, - { 5, 0, 0, 0 }, { 21, 0, 0, 0 }, { 21, 0, 0, 0 }, { 59,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 7,13, 0, 0 }, - { 25,13, 0, 0 }, { 25,13, 0, 0 }, { 25,13, 0, 0 }, { 34,60,13, 0 }, - { 4,13, 0, 0 }, { 4,13, 0, 0 }, { 4,13, 0, 0 }, { 4,13, 0, 0 }, - { 5,13, 0, 0 }, { 23,13, 0, 0 }, { 23,13, 0, 0 }, { 39,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 42,13, 0, 0 }, - { 25,13, 0, 0 }, { 25,13, 0, 0 }, { 22,13, 0, 0 }, { 31,60,13, 0 }, - { 31,60,13, 0 }, { 39,60, 0, 0 }, { 39,60, 0, 0 }, { 39,60, 0, 0 }, - { 39,60, 0, 0 }, { 7,60, 0, 0 }, { 7,60, 0, 0 }, { 42,60, 0, 0 }, - { 0,60, 0, 0 }, { 25,60, 0, 0 }, { 22,60, 0, 0 }, { 22,60, 0, 0 }, - { 22,60, 0, 0 }, { 28,60, 0, 0 }, { 34,60, 0, 0 }, { 31,16,13, 0 } }, - - { { 55, 0,13, 0 }, { 55, 0,13, 0 }, { 55, 0,13, 0 }, { 55, 0,13, 0 }, - { 55, 0,13, 0 }, { 55, 0,13, 0 }, { 55, 0,13, 0 }, { 55, 0,13, 0 }, - { 55, 0,13, 0 }, { 55, 0,13, 0 }, { 55, 0,13, 0 }, { 55, 0,13, 0 }, - { 55, 0,13, 0 }, { 55, 0,13, 0 }, { 55, 0,13, 0 }, { 55, 0,13, 0 }, - { 55, 0,13, 0 }, { 55, 0, 0, 0 }, { 40, 0, 0, 0 }, { 8, 0, 0, 0 }, - { 9, 0, 0, 0 }, { 49, 0, 0, 0 }, { 49, 0, 0, 0 }, { 52, 0, 0, 0 }, - { 17, 0, 0, 0 }, { 17, 0, 0, 0 }, { 17, 0, 0, 0 }, { 4,13, 0, 0 }, - { 0,13, 0, 0 }, { 20,13, 0, 0 }, { 17, 0, 0, 0 }, { 60,13,60,13 }, - { 40, 0, 0,13 }, { 40, 0, 0, 0 }, { 8, 0, 0, 0 }, { 43, 0, 0, 0 }, - { 27, 0, 0, 0 }, { 49, 0, 0, 0 }, { 49, 0, 0, 0 }, { 14, 0, 0, 0 }, - { 17, 0, 0, 0 }, { 17, 0, 0, 0 }, { 17, 0, 0, 0 }, { 36, 0, 0, 0 }, - { 42,13, 0, 0 }, { 42,13, 0, 0 }, { 17, 0, 0, 0 }, { 57,60,13, 0 }, - { 57, 0,13, 0 }, { 40, 0, 0, 0 }, { 8, 0, 0, 0 }, { 26, 0, 0, 0 }, - { 27, 0, 0, 0 }, { 49, 0, 0, 0 }, { 12, 0, 0, 0 }, { 14, 0, 0, 0 }, - { 17, 0, 0, 0 }, { 17, 0, 0, 0 }, { 17, 0, 0, 0 }, { 36, 0, 0, 0 }, - { 0, 0,13, 0 }, { 38, 0,13, 0 }, { 36,13, 0, 0 }, { 1,60, 0, 0 }, - { 8,60, 0, 0 }, { 8, 0, 0, 0 }, { 43, 0, 0, 0 }, { 9, 0, 0, 0 }, - { 11, 0, 0, 0 }, { 49, 0, 0, 0 }, { 12, 0, 0, 0 }, { 14, 0, 0, 0 }, - { 14, 0,13, 0 }, { 33, 0,13, 0 }, { 50, 0,13, 0 }, { 50, 0, 0, 0 }, - { 50, 0,13, 0 }, { 61, 0,13, 0 }, { 36,13, 0, 0 }, { 39,60, 0, 0 }, - { 8,60, 0, 0 }, { 8, 0, 0, 0 }, { 43, 0, 0, 0 }, { 46, 0, 0, 0 }, - { 49, 0, 0, 0 }, { 52, 0, 0, 0 }, { 30, 0, 0, 0 }, { 14, 0, 0, 0 }, - { 14, 0,13, 0 }, { 33, 0,13, 0 }, { 50, 0,13, 0 }, { 50, 0,13, 0 }, - { 50,13,13, 0 }, { 50,13, 0, 0 }, { 18,13,13, 0 }, { 25,60,13, 0 }, - { 8,60,13,13 }, { 8, 0, 0,13 }, { 43, 0, 0,13 }, { 46, 0, 0,13 }, - { 49, 0, 0,13 }, { 52, 0, 0, 0 }, { 30, 0, 0, 0 }, { 14, 0, 0, 0 }, - { 14, 0, 0, 0 }, { 18, 0,60, 0 }, { 5, 0, 0,13 }, { 5, 0, 0,13 }, - { 5, 0, 0,13 }, { 61,13, 0,13 }, { 18,13,13, 0 }, { 23,13,60, 0 }, - { 43,13, 0,13 }, { 43, 0, 0,13 }, { 43, 0, 0,13 }, { 9, 0, 0,13 }, - { 49, 0, 0,13 }, { 52, 0, 0, 0 }, { 3, 0, 0, 0 }, { 14, 0, 0, 0 }, - { 14, 0, 0, 0 }, { 50, 0, 0, 0 }, { 50,13,13, 0 }, { 50,13,13, 0 }, - { 50,13,13, 0 }, { 61, 0, 0, 0 }, { 17,13,13, 0 }, { 24,60,13, 0 }, - { 43,60,13, 0 }, { 43,60,13, 0 }, { 43,60,13, 0 }, { 43,60,13, 0 }, - { 43,60,13, 0 }, { 43,60,13, 0 }, { 43,60,13, 0 }, { 43,60,13, 0 }, - { 43,60,13, 0 }, { 43,60,13, 0 }, { 43,60,13, 0 }, { 43,60,13, 0 }, - { 43,60,13, 0 }, { 43,60,13, 0 }, { 43,60,13, 0 }, { 43,60,13, 0 }, - { 43,60,13, 0 }, { 43, 0, 0, 0 }, { 43, 0,19, 0 }, { 9, 0, 0, 0 }, - { 11, 0, 0, 0 }, { 52, 0, 0, 0 }, { 52, 0, 0, 0 }, { 14, 0, 0, 0 }, - { 14, 0, 0, 0 }, { 17, 0, 0, 0 }, { 61,13, 0, 0 }, { 61,13, 0, 0 }, - { 61,13, 0, 0 }, { 54, 0, 0, 0 }, { 17, 0,13,13 }, { 39,13,13, 0 }, - { 45,13,13, 0 }, { 45,13,13, 0 }, { 45,13,13, 0 }, { 45,13,13, 0 }, - { 45,13,13, 0 }, { 45,13,13, 0 }, { 45,13,13, 0 }, { 45,13,13, 0 }, - { 45,13,13, 0 }, { 45,13,13, 0 }, { 45,13,13, 0 }, { 45,13,13, 0 }, - { 45,13,13, 0 }, { 45,13,13, 0 }, { 45,13,13, 0 }, { 45,13,13, 0 }, - { 45,13,13, 0 }, { 45, 0,13, 0 }, { 44, 0,13, 0 }, { 27, 0, 0, 0 }, - { 29, 0, 0, 0 }, { 52, 0, 0, 0 }, { 48, 0, 0, 0 }, { 52, 0, 0, 0 }, - { 52, 0, 0, 0 }, { 17, 0, 0, 0 }, { 17, 0, 0, 0 }, { 17, 0,19, 0 }, - { 17, 0,13, 0 }, { 2, 0,13, 0 }, { 17, 0,13, 0 }, { 7,13, 0, 0 }, - { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 27, 0, 0,13 }, - { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 27, 0, 0,13 }, - { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 27, 0, 0,13 }, - { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 27, 0, 0,13 }, - { 27, 0, 0,13 }, { 27, 0, 0,13 }, { 9, 0, 0,13 }, { 27, 0, 0,13 }, - { 27, 0, 0,13 }, { 12, 0, 0,13 }, { 52, 0, 0,13 }, { 14, 0, 0,13 }, - { 14, 0, 0,13 }, { 58, 0, 0,13 }, { 41, 0, 0,13 }, { 41, 0, 0,13 }, - { 41, 0, 0,13 }, { 6, 0, 0,13 }, { 17,60, 0,13 }, { 37, 0,19,13 }, - { 9, 0, 0,13 }, { 9,16, 0,13 }, { 9, 0, 0,13 }, { 27, 0, 0,13 }, - { 11, 0, 0,13 }, { 49, 0, 0, 0 }, { 12, 0, 0, 0 }, { 52, 0, 0, 0 }, - { 14, 0, 0, 0 }, { 14, 0, 0, 0 }, { 14, 0, 0, 0 }, { 50, 0, 0, 0 }, - { 0, 0, 0,13 }, { 53, 0, 0,13 }, { 17, 0, 0,13 }, { 28, 0,13, 0 }, - { 52, 0,13, 0 }, { 52, 0,13, 0 }, { 49, 0,13, 0 }, { 52, 0, 0, 0 }, - { 12, 0, 0, 0 }, { 52, 0, 0, 0 }, { 30, 0, 0, 0 }, { 14, 0, 0, 0 }, - { 14, 0, 0, 0 }, { 17, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, - { 2, 0, 0, 0 }, { 38, 0, 0, 0 }, { 38, 0, 0, 0 }, { 34, 0, 0, 0 } } }, - - { { { 31,16,60,13 }, { 34,16,13, 0 }, { 34,16,13, 0 }, { 31,16,13, 0 }, - { 31,16,13, 0 }, { 31,16,13, 0 }, { 31,16,13, 0 }, { 19,16,60, 0 }, - { 19,16,60, 0 }, { 19,16,60, 0 }, { 19,16,60, 0 }, { 19,16,60, 0 }, - { 19,16,60, 0 }, { 19,16,60, 0 }, { 31,16,60,13 }, { 19,37,16,60 }, - { 44, 0, 0,60 }, { 44, 0, 0, 0 }, { 62, 0, 0, 0 }, { 30, 0, 0, 0 }, - { 32, 0, 0, 0 }, { 58, 0, 0, 0 }, { 35, 0, 0, 0 }, { 36, 0, 0, 0 }, - { 36, 0, 0, 0 }, { 38,13, 0, 0 }, { 0,13, 0, 0 }, { 59,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 39,13, 0, 0 }, { 34,60,13, 0 }, - { 34, 0,13, 0 }, { 45, 0, 0, 0 }, { 47, 0, 0, 0 }, { 48, 0, 0, 0 }, - { 33, 0, 0, 0 }, { 35, 0, 0, 0 }, { 35, 0, 0, 0 }, { 36, 0, 0, 0 }, - { 38,13, 0, 0 }, { 38,13, 0, 0 }, { 38,13, 0, 0 }, { 59,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 39,13, 0, 0 }, { 34,60,13, 0 }, - { 34, 0,13, 0 }, { 62, 0, 0, 0 }, { 30, 0, 0, 0 }, { 15, 0, 0, 0 }, - { 50, 0, 0, 0 }, { 53, 0, 0, 0 }, { 53, 0, 0, 0 }, { 54,13, 0, 0 }, - { 21,13, 0, 0 }, { 21,13, 0, 0 }, { 21,13, 0, 0 }, { 59,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 34,60,13, 0 }, - { 30, 0,13, 0 }, { 30, 0, 0, 0 }, { 48, 0, 0, 0 }, { 33, 0, 0, 0 }, - { 58, 0, 0, 0 }, { 18, 0, 0, 0 }, { 18, 0, 0, 0 }, { 56,13, 0, 0 }, - { 23,13, 0, 0 }, { 23,13, 0, 0 }, { 23,13, 0, 0 }, { 59,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 24,13, 0, 0 }, { 34,60,13, 0 }, - { 34, 0,13, 0 }, { 6, 0, 0, 0 }, { 6, 0, 0, 0 }, { 58, 0, 0, 0 }, - { 53, 0, 0, 0 }, { 54, 0, 0, 0 }, { 54, 0, 0, 0 }, { 21,13, 0, 0 }, - { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 39,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 42,60, 0, 0 }, { 34,16,13, 0 }, - { 6, 0,13, 0 }, { 6, 0, 0, 0 }, { 33, 0, 0, 0 }, { 58, 0, 0, 0 }, - { 53, 0, 0, 0 }, { 54, 0, 0, 0 }, { 61, 0, 0, 0 }, { 21,13, 0, 0 }, - { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 39,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 42,60, 0, 0 }, { 34,16,13, 0 }, - { 34, 0,13, 0 }, { 51, 0, 0, 0 }, { 51, 0, 0, 0 }, { 53, 0, 0, 0 }, - { 54, 0, 0, 0 }, { 56,13, 0, 0 }, { 56,13, 0, 0 }, { 57,13, 0, 0 }, - { 39,13, 0, 0 }, { 39,13, 0, 0 }, { 39,13, 0, 0 }, { 7,13, 0, 0 }, - { 42,13, 0, 0 }, { 42,13, 0, 0 }, { 25,60, 0, 0 }, { 31,16,13, 0 }, - { 31, 0,13, 0 }, { 31, 0,13, 0 }, { 31, 0,13, 0 }, { 31, 0,13, 0 }, - { 31, 0,13, 0 }, { 31, 0,13, 0 }, { 31, 0,13, 0 }, { 31, 0,13, 0 }, - { 31, 0,13, 0 }, { 31, 0,13, 0 }, { 31, 0,13, 0 }, { 31, 0,13, 0 }, - { 31, 0,13, 0 }, { 31, 0,13, 0 }, { 31, 0,13, 0 }, { 31, 0,13, 0 }, - { 31, 0,13, 0 }, { 4, 0, 0, 0 }, { 4, 0, 0, 0 }, { 4, 0, 0, 0 }, - { 5,13, 0, 0 }, { 23,13, 0, 0 }, { 23,13, 0, 0 }, { 39,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 42,13, 0, 0 }, - { 25,13, 0, 0 }, { 25,13, 0, 0 }, { 22,60, 0, 0 }, { 31,16,60, 0 }, - { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, - { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, - { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, - { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, - { 31,13, 0, 0 }, { 5,13, 0, 0 }, { 5,13, 0, 0 }, { 5,13, 0, 0 }, - { 5,13, 0, 0 }, { 57,13, 0, 0 }, { 57,13, 0, 0 }, { 39,13, 0, 0 }, - { 24,13, 0, 0 }, { 24,13, 0, 0 }, { 24,13, 0, 0 }, { 42,13, 0, 0 }, - { 22,13, 0, 0 }, { 22,60, 0, 0 }, { 28,60,13, 0 }, { 31,16,60, 0 }, - { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, - { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, - { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, - { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, { 31,13, 0, 0 }, - { 31,13, 0, 0 }, { 41,13, 0, 0 }, { 41,13, 0, 0 }, { 41,13, 0, 0 }, - { 41,13, 0, 0 }, { 39,13, 0, 0 }, { 39,13, 0, 0 }, { 7,13, 0, 0 }, - { 42,13, 0, 0 }, { 42,13, 0, 0 }, { 42,13, 0, 0 }, { 25,13, 0, 0 }, - { 28,13, 0, 0 }, { 28,60, 0, 0 }, { 28,60,13, 0 }, { 31,16,60,13 }, - { 31,13, 0, 0 }, { 41,13, 0, 0 }, { 41,13, 0, 0 }, { 41,13, 0, 0 }, - { 41,13, 0, 0 }, { 39,13, 0, 0 }, { 39,13, 0, 0 }, { 24,13, 0, 0 }, - { 25,60, 0, 0 }, { 25,60, 0, 0 }, { 25,60, 0, 0 }, { 22,60, 0, 0 }, - { 28,60, 0, 0 }, { 28,60, 0, 0 }, { 34,60,13, 0 }, { 31,16,60,13 }, - { 31,60,13,13 }, { 10,60,13, 0 }, { 10,60,13, 0 }, { 10,60,13, 0 }, - { 10,60,13, 0 }, { 10,60,13, 0 }, { 10,60,13, 0 }, { 28,60,13, 0 }, - { 34,60,13, 0 }, { 34,60,13, 0 }, { 34,16,13, 0 }, { 34,16,13, 0 }, - { 34,16,60, 0 }, { 34,16,60, 0 }, { 31,16,60, 0 }, { 19,37,16,13 } }, - - { { 8, 0,16, 0 }, { 8, 0,16, 0 }, { 8, 0,16, 0 }, { 8, 0,16, 0 }, - { 8, 0,16, 0 }, { 8, 0,16, 0 }, { 8, 0,16, 0 }, { 8, 0,16, 0 }, - { 8, 0,16, 0 }, { 8, 0,16, 0 }, { 8, 0,16, 0 }, { 8, 0,16, 0 }, - { 8, 0,16, 0 }, { 8, 0,16, 0 }, { 8, 0,16, 0 }, { 8, 0,16, 0 }, - { 8, 0,16, 0 }, { 8, 0, 0, 0 }, { 9, 0, 0, 0 }, { 11, 0, 0, 0 }, - { 47, 0, 0, 0 }, { 32, 0, 0, 0 }, { 50, 0, 0, 0 }, { 18, 0, 0, 0 }, - { 18, 0, 0, 0 }, { 20, 0, 0, 0 }, { 21, 0, 0, 0 }, { 21, 0, 0, 0 }, - { 21,13, 0, 0 }, { 39,13, 0, 0 }, { 59,13, 0, 0 }, { 34,16,60, 0 }, - { 26, 0, 0, 0 }, { 26, 0, 0, 0 }, { 27, 0, 0, 0 }, { 29, 0, 0, 0 }, - { 30, 0, 0, 0 }, { 33, 0, 0, 0 }, { 50, 0, 0, 0 }, { 18, 0, 0, 0 }, - { 18, 0, 0, 0 }, { 20, 0, 0, 0 }, { 57, 0, 0, 0 }, { 57,13, 0, 0 }, - { 57,13, 0, 0 }, { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 34,16,60, 0 }, - { 27, 0, 0, 0 }, { 27, 0, 0, 0 }, { 11, 0, 0, 0 }, { 12, 0, 0, 0 }, - { 48, 0, 0, 0 }, { 50, 0, 0, 0 }, { 58, 0, 0, 0 }, { 61, 0, 0, 0 }, - { 61, 0, 0, 0 }, { 56, 0, 0, 0 }, { 57,13, 0, 0 }, { 57,13, 0, 0 }, - { 57,13, 0, 0 }, { 59,13, 0, 0 }, { 39,13, 0, 0 }, { 34,16,60, 0 }, - { 45, 0, 0, 0 }, { 45, 0, 0, 0 }, { 12, 0, 0, 0 }, { 30, 0, 0, 0 }, - { 32, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 61, 0, 0, 0 }, - { 38, 0, 0, 0 }, { 38, 0, 0, 0 }, { 38,13, 0, 0 }, { 57,13, 0, 0 }, - { 0,13, 0, 0 }, { 59,13, 0, 0 }, { 39,13, 0, 0 }, { 34,16,60, 0 }, - { 63, 0, 0, 0 }, { 63, 0, 0, 0 }, { 3, 0, 0, 0 }, { 32, 0, 0, 0 }, - { 58, 0, 0, 0 }, { 18, 0, 0, 0 }, { 18, 0, 0, 0 }, { 20, 0, 0, 0 }, - { 21, 0, 0, 0 }, { 21, 0, 0, 0 }, { 21,13, 0, 0 }, { 59,13, 0, 0 }, - { 39,13, 0, 0 }, { 39,13, 0, 0 }, { 7,13,13, 0 }, { 31,16,60, 0 }, - { 31, 0, 0, 0 }, { 3, 0, 0, 0 }, { 3, 0, 0, 0 }, { 33, 0, 0, 0 }, - { 58, 0, 0, 0 }, { 18, 0, 0, 0 }, { 18, 0, 0, 0 }, { 20, 0, 0, 0 }, - { 21, 0, 0, 0 }, { 21, 0, 0, 0 }, { 21,13, 0, 0 }, { 59,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 7,13,13, 0 }, { 31,16,60, 0 }, - { 6, 0, 0, 0 }, { 6, 0, 0, 0 }, { 51, 0, 0, 0 }, { 51, 0, 0, 0 }, - { 53, 0, 0, 0 }, { 54, 0, 0, 0 }, { 54, 0, 0, 0 }, { 38, 0, 0, 0 }, - { 57,13, 0, 0 }, { 57,13, 0, 0 }, { 57,13, 0, 0 }, { 39,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 42,60,13, 0 }, { 31,16,60, 0 }, - { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, - { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, - { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, - { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, - { 31, 0, 0, 0 }, { 51, 0, 0, 0 }, { 53, 0, 0, 0 }, { 53, 0, 0, 0 }, - { 54, 0, 0, 0 }, { 56, 0, 0, 0 }, { 56, 0, 0, 0 }, { 57,13, 0, 0 }, - { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 59,13, 0, 0 }, { 7,13, 0, 0 }, - { 24,13, 0, 0 }, { 24,13, 0, 0 }, { 25,60,13, 0 }, { 31,16,60, 0 }, - { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, - { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, - { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, - { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, { 31, 0, 0, 0 }, - { 31, 0, 0, 0 }, { 4, 0, 0, 0 }, { 4, 0, 0, 0 }, { 4, 0, 0, 0 }, - { 54, 0, 0, 0 }, { 21,13, 0, 0 }, { 21, 0, 0, 0 }, { 57,13, 0, 0 }, - { 39,13, 0, 0 }, { 39,13, 0, 0 }, { 39,13, 0, 0 }, { 7,13, 0, 0 }, - { 42,13,13, 0 }, { 42,13,13, 0 }, { 22,60,13, 0 }, { 31,16,60, 0 }, - { 31,16, 0, 0 }, { 31,16, 0, 0 }, { 31,16, 0, 0 }, { 31,16, 0, 0 }, - { 31,16, 0, 0 }, { 31,16, 0, 0 }, { 31,16, 0, 0 }, { 31,16, 0, 0 }, - { 31,16, 0, 0 }, { 31,16, 0, 0 }, { 31,16, 0, 0 }, { 31,16, 0, 0 }, - { 31,16, 0, 0 }, { 31,16, 0, 0 }, { 31,16, 0, 0 }, { 31,16, 0, 0 }, - { 31,16, 0, 0 }, { 5, 0, 0, 0 }, { 5, 0, 0, 0 }, { 5, 0, 0, 0 }, - { 5,13, 0, 0 }, { 23,13, 0, 0 }, { 23,13, 0, 0 }, { 59,13, 0, 0 }, - { 7,13, 0, 0 }, { 7,13, 0, 0 }, { 7,13,13, 0 }, { 42,13,13, 0 }, - { 22,60,13, 0 }, { 22,60,13, 0 }, { 28,60,13, 0 }, { 31,16,60, 0 }, - { 31,13, 0, 0 }, { 4,13, 0, 0 }, { 4,13, 0, 0 }, { 4,13, 0, 0 }, - { 5,13, 0, 0 }, { 23,13, 0, 0 }, { 23,13, 0, 0 }, { 39,13,13, 0 }, - { 24,60,13, 0 }, { 24,60,13, 0 }, { 24,60,13, 0 }, { 25,60,13, 0 }, - { 28,60,13, 0 }, { 28,60,13, 0 }, { 34,16,13, 0 }, { 31,16,60, 0 }, - { 31,16,13, 0 }, { 10,16,13, 0 }, { 10,16,13, 0 }, { 10,16,13, 0 }, - { 10,16,13, 0 }, { 10,16,60, 0 }, { 10,16,60, 0 }, { 28,16,60, 0 }, - { 34,16,60, 0 }, { 34,16,60, 0 }, { 34,16,60, 0 }, { 31,16,60, 0 }, - { 31,16,60, 0 }, { 31,16,60, 0 }, { 31,16,60, 0 }, { 19,37,60, 0 } } } -}; - -const struct lc3_ac_model lc3_spectrum_models[] = { - - { { { 0, 1 }, { 1, 1 }, { 2, 175 }, { 177, 48 }, - { 225, 1 }, { 226, 1 }, { 227, 109 }, { 336, 36 }, - { 372, 171 }, { 543, 109 }, { 652, 47 }, { 699, 20 }, - { 719, 49 }, { 768, 36 }, { 804, 20 }, { 824, 10 }, - { 834, 190 } } }, - - { { { 0, 18 }, { 18, 26 }, { 44, 17 }, { 61, 10 }, - { 71, 27 }, { 98, 37 }, { 135, 24 }, { 159, 16 }, - { 175, 22 }, { 197, 32 }, { 229, 22 }, { 251, 14 }, - { 265, 17 }, { 282, 26 }, { 308, 20 }, { 328, 13 }, - { 341, 683 } } }, - - { { { 0, 71 }, { 71, 92 }, { 163, 49 }, { 212, 25 }, - { 237, 81 }, { 318, 102 }, { 420, 61 }, { 481, 33 }, - { 514, 42 }, { 556, 57 }, { 613, 39 }, { 652, 23 }, - { 675, 22 }, { 697, 30 }, { 727, 22 }, { 749, 15 }, - { 764, 260 } } }, - - { { { 0, 160 }, { 160, 130 }, { 290, 46 }, { 336, 18 }, - { 354, 121 }, { 475, 123 }, { 598, 55 }, { 653, 24 }, - { 677, 45 }, { 722, 55 }, { 777, 31 }, { 808, 15 }, - { 823, 19 }, { 842, 24 }, { 866, 15 }, { 881, 9 }, - { 890, 134 } } }, - - { { { 0, 71 }, { 71, 73 }, { 144, 33 }, { 177, 18 }, - { 195, 71 }, { 266, 76 }, { 342, 43 }, { 385, 26 }, - { 411, 34 }, { 445, 44 }, { 489, 30 }, { 519, 20 }, - { 539, 20 }, { 559, 27 }, { 586, 21 }, { 607, 15 }, - { 622, 402 } } }, - - { { { 0, 48 }, { 48, 60 }, { 108, 32 }, { 140, 19 }, - { 159, 58 }, { 217, 68 }, { 285, 42 }, { 327, 27 }, - { 354, 31 }, { 385, 42 }, { 427, 30 }, { 457, 21 }, - { 478, 19 }, { 497, 27 }, { 524, 21 }, { 545, 16 }, - { 561, 463 } } }, - - { { { 0, 138 }, { 138, 109 }, { 247, 43 }, { 290, 18 }, - { 308, 111 }, { 419, 112 }, { 531, 53 }, { 584, 25 }, - { 609, 46 }, { 655, 55 }, { 710, 32 }, { 742, 17 }, - { 759, 21 }, { 780, 27 }, { 807, 18 }, { 825, 11 }, - { 836, 188 } } }, - - { { { 0, 16 }, { 16, 24 }, { 40, 22 }, { 62, 17 }, - { 79, 24 }, { 103, 36 }, { 139, 31 }, { 170, 25 }, - { 195, 20 }, { 215, 30 }, { 245, 25 }, { 270, 20 }, - { 290, 15 }, { 305, 22 }, { 327, 19 }, { 346, 16 }, - { 362, 662 } } }, - - { { { 0, 579 }, { 579, 150 }, { 729, 12 }, { 741, 2 }, - { 743, 154 }, { 897, 73 }, { 970, 10 }, { 980, 2 }, - { 982, 14 }, { 996, 11 }, { 1007, 3 }, { 1010, 1 }, - { 1011, 3 }, { 1014, 3 }, { 1017, 1 }, { 1018, 1 }, - { 1019, 5 } } }, - - { { { 0, 398 }, { 398, 184 }, { 582, 25 }, { 607, 5 }, - { 612, 176 }, { 788, 114 }, { 902, 23 }, { 925, 6 }, - { 931, 25 }, { 956, 23 }, { 979, 8 }, { 987, 3 }, - { 990, 6 }, { 996, 6 }, { 1002, 3 }, { 1005, 2 }, - { 1007, 17 } } }, - - { { { 0, 13 }, { 13, 21 }, { 34, 18 }, { 52, 11 }, - { 63, 20 }, { 83, 29 }, { 112, 22 }, { 134, 15 }, - { 149, 14 }, { 163, 20 }, { 183, 16 }, { 199, 12 }, - { 211, 10 }, { 221, 14 }, { 235, 12 }, { 247, 10 }, - { 257, 767 } } }, - - { { { 0, 281 }, { 281, 183 }, { 464, 37 }, { 501, 9 }, - { 510, 171 }, { 681, 139 }, { 820, 37 }, { 857, 10 }, - { 867, 35 }, { 902, 36 }, { 938, 15 }, { 953, 6 }, - { 959, 9 }, { 968, 10 }, { 978, 6 }, { 984, 3 }, - { 987, 37 } } }, - - { { { 0, 198 }, { 198, 164 }, { 362, 46 }, { 408, 13 }, - { 421, 154 }, { 575, 147 }, { 722, 51 }, { 773, 16 }, - { 789, 43 }, { 832, 49 }, { 881, 24 }, { 905, 10 }, - { 915, 13 }, { 928, 16 }, { 944, 10 }, { 954, 5 }, - { 959, 65 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 93 }, { 95, 44 }, - { 139, 1 }, { 140, 1 }, { 141, 72 }, { 213, 38 }, - { 251, 86 }, { 337, 70 }, { 407, 43 }, { 450, 25 }, - { 475, 40 }, { 515, 36 }, { 551, 25 }, { 576, 16 }, - { 592, 432 } } }, - - { { { 0, 133 }, { 133, 141 }, { 274, 64 }, { 338, 28 }, - { 366, 117 }, { 483, 122 }, { 605, 59 }, { 664, 27 }, - { 691, 39 }, { 730, 48 }, { 778, 29 }, { 807, 15 }, - { 822, 15 }, { 837, 20 }, { 857, 13 }, { 870, 8 }, - { 878, 146 } } }, - - { { { 0, 128 }, { 128, 125 }, { 253, 49 }, { 302, 18 }, - { 320, 123 }, { 443, 134 }, { 577, 59 }, { 636, 23 }, - { 659, 49 }, { 708, 59 }, { 767, 32 }, { 799, 15 }, - { 814, 19 }, { 833, 24 }, { 857, 15 }, { 872, 9 }, - { 881, 143 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 23 }, { 25, 17 }, - { 42, 1 }, { 43, 1 }, { 44, 23 }, { 67, 18 }, - { 85, 20 }, { 105, 21 }, { 126, 18 }, { 144, 15 }, - { 159, 15 }, { 174, 17 }, { 191, 14 }, { 205, 12 }, - { 217, 807 } } }, - - { { { 0, 70 }, { 70, 96 }, { 166, 63 }, { 229, 38 }, - { 267, 89 }, { 356, 112 }, { 468, 65 }, { 533, 36 }, - { 569, 37 }, { 606, 47 }, { 653, 32 }, { 685, 20 }, - { 705, 17 }, { 722, 23 }, { 745, 17 }, { 762, 12 }, - { 774, 250 } } }, - - { { { 0, 55 }, { 55, 75 }, { 130, 45 }, { 175, 25 }, - { 200, 68 }, { 268, 90 }, { 358, 58 }, { 416, 33 }, - { 449, 39 }, { 488, 54 }, { 542, 39 }, { 581, 25 }, - { 606, 22 }, { 628, 31 }, { 659, 24 }, { 683, 16 }, - { 699, 325 } } }, - - { { { 0, 1 }, { 1, 2 }, { 3, 2 }, { 5, 2 }, - { 7, 2 }, { 9, 2 }, { 11, 2 }, { 13, 2 }, - { 15, 2 }, { 17, 2 }, { 19, 2 }, { 21, 2 }, - { 23, 2 }, { 25, 2 }, { 27, 2 }, { 29, 2 }, - { 31, 993 } } }, - - { { { 0, 34 }, { 34, 51 }, { 85, 38 }, { 123, 24 }, - { 147, 49 }, { 196, 69 }, { 265, 52 }, { 317, 35 }, - { 352, 34 }, { 386, 47 }, { 433, 37 }, { 470, 27 }, - { 497, 21 }, { 518, 31 }, { 549, 25 }, { 574, 19 }, - { 593, 431 } } }, - - { { { 0, 30 }, { 30, 43 }, { 73, 32 }, { 105, 22 }, - { 127, 43 }, { 170, 59 }, { 229, 45 }, { 274, 31 }, - { 305, 30 }, { 335, 42 }, { 377, 34 }, { 411, 25 }, - { 436, 19 }, { 455, 28 }, { 483, 23 }, { 506, 18 }, - { 524, 500 } } }, - - { { { 0, 9 }, { 9, 15 }, { 24, 14 }, { 38, 13 }, - { 51, 14 }, { 65, 22 }, { 87, 21 }, { 108, 18 }, - { 126, 13 }, { 139, 20 }, { 159, 18 }, { 177, 16 }, - { 193, 11 }, { 204, 17 }, { 221, 15 }, { 236, 14 }, - { 250, 774 } } }, - - { { { 0, 30 }, { 30, 44 }, { 74, 31 }, { 105, 20 }, - { 125, 41 }, { 166, 58 }, { 224, 42 }, { 266, 28 }, - { 294, 28 }, { 322, 39 }, { 361, 30 }, { 391, 22 }, - { 413, 18 }, { 431, 26 }, { 457, 21 }, { 478, 16 }, - { 494, 530 } } }, - - { { { 0, 15 }, { 15, 23 }, { 38, 20 }, { 58, 15 }, - { 73, 22 }, { 95, 33 }, { 128, 28 }, { 156, 22 }, - { 178, 18 }, { 196, 26 }, { 222, 23 }, { 245, 18 }, - { 263, 13 }, { 276, 20 }, { 296, 18 }, { 314, 15 }, - { 329, 695 } } }, - - { { { 0, 11 }, { 11, 17 }, { 28, 16 }, { 44, 13 }, - { 57, 17 }, { 74, 26 }, { 100, 23 }, { 123, 19 }, - { 142, 15 }, { 157, 22 }, { 179, 20 }, { 199, 17 }, - { 216, 12 }, { 228, 18 }, { 246, 16 }, { 262, 14 }, - { 276, 748 } } }, - - { { { 0, 448 }, { 448, 171 }, { 619, 20 }, { 639, 4 }, - { 643, 178 }, { 821, 105 }, { 926, 18 }, { 944, 4 }, - { 948, 23 }, { 971, 20 }, { 991, 7 }, { 998, 2 }, - { 1000, 5 }, { 1005, 5 }, { 1010, 2 }, { 1012, 1 }, - { 1013, 11 } } }, - - { { { 0, 332 }, { 332, 188 }, { 520, 29 }, { 549, 6 }, - { 555, 186 }, { 741, 133 }, { 874, 29 }, { 903, 7 }, - { 910, 30 }, { 940, 30 }, { 970, 11 }, { 981, 4 }, - { 985, 6 }, { 991, 7 }, { 998, 4 }, { 1002, 2 }, - { 1004, 20 } } }, - - { { { 0, 8 }, { 8, 13 }, { 21, 13 }, { 34, 11 }, - { 45, 13 }, { 58, 20 }, { 78, 18 }, { 96, 16 }, - { 112, 12 }, { 124, 17 }, { 141, 16 }, { 157, 13 }, - { 170, 10 }, { 180, 14 }, { 194, 13 }, { 207, 12 }, - { 219, 805 } } }, - - { { { 0, 239 }, { 239, 176 }, { 415, 42 }, { 457, 11 }, - { 468, 163 }, { 631, 145 }, { 776, 44 }, { 820, 13 }, - { 833, 39 }, { 872, 42 }, { 914, 19 }, { 933, 7 }, - { 940, 11 }, { 951, 13 }, { 964, 7 }, { 971, 4 }, - { 975, 49 } } }, - - { { { 0, 165 }, { 165, 145 }, { 310, 49 }, { 359, 16 }, - { 375, 138 }, { 513, 139 }, { 652, 55 }, { 707, 20 }, - { 727, 47 }, { 774, 54 }, { 828, 28 }, { 856, 12 }, - { 868, 16 }, { 884, 20 }, { 904, 12 }, { 916, 7 }, - { 923, 101 } } }, - - { { { 0, 3 }, { 3, 5 }, { 8, 5 }, { 13, 5 }, - { 18, 5 }, { 23, 7 }, { 30, 7 }, { 37, 7 }, - { 44, 4 }, { 48, 7 }, { 55, 7 }, { 62, 6 }, - { 68, 4 }, { 72, 6 }, { 78, 6 }, { 84, 6 }, - { 90, 934 } } }, - - { { { 0, 115 }, { 115, 122 }, { 237, 52 }, { 289, 22 }, - { 311, 111 }, { 422, 125 }, { 547, 61 }, { 608, 27 }, - { 635, 45 }, { 680, 57 }, { 737, 34 }, { 771, 17 }, - { 788, 19 }, { 807, 25 }, { 832, 17 }, { 849, 10 }, - { 859, 165 } } }, - - { { { 0, 107 }, { 107, 114 }, { 221, 51 }, { 272, 21 }, - { 293, 106 }, { 399, 122 }, { 521, 61 }, { 582, 28 }, - { 610, 46 }, { 656, 58 }, { 714, 35 }, { 749, 18 }, - { 767, 20 }, { 787, 26 }, { 813, 18 }, { 831, 11 }, - { 842, 182 } } }, - - { { { 0, 6 }, { 6, 10 }, { 16, 10 }, { 26, 9 }, - { 35, 10 }, { 45, 15 }, { 60, 15 }, { 75, 14 }, - { 89, 9 }, { 98, 14 }, { 112, 13 }, { 125, 12 }, - { 137, 8 }, { 145, 12 }, { 157, 11 }, { 168, 10 }, - { 178, 846 } } }, - - { { { 0, 72 }, { 72, 88 }, { 160, 50 }, { 210, 26 }, - { 236, 84 }, { 320, 102 }, { 422, 60 }, { 482, 32 }, - { 514, 41 }, { 555, 53 }, { 608, 36 }, { 644, 21 }, - { 665, 20 }, { 685, 27 }, { 712, 20 }, { 732, 13 }, - { 745, 279 } } }, - - { { { 0, 45 }, { 45, 63 }, { 108, 45 }, { 153, 30 }, - { 183, 61 }, { 244, 83 }, { 327, 58 }, { 385, 36 }, - { 421, 34 }, { 455, 47 }, { 502, 34 }, { 536, 23 }, - { 559, 19 }, { 578, 27 }, { 605, 21 }, { 626, 15 }, - { 641, 383 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 7 }, { 9, 7 }, - { 16, 1 }, { 17, 1 }, { 18, 8 }, { 26, 8 }, - { 34, 6 }, { 40, 8 }, { 48, 7 }, { 55, 7 }, - { 62, 6 }, { 68, 7 }, { 75, 7 }, { 82, 6 }, - { 88, 936 } } }, - - { { { 0, 29 }, { 29, 44 }, { 73, 35 }, { 108, 24 }, - { 132, 42 }, { 174, 62 }, { 236, 48 }, { 284, 34 }, - { 318, 30 }, { 348, 43 }, { 391, 35 }, { 426, 26 }, - { 452, 19 }, { 471, 29 }, { 500, 24 }, { 524, 19 }, - { 543, 481 } } }, - - { { { 0, 20 }, { 20, 31 }, { 51, 25 }, { 76, 17 }, - { 93, 30 }, { 123, 43 }, { 166, 34 }, { 200, 25 }, - { 225, 22 }, { 247, 32 }, { 279, 26 }, { 305, 21 }, - { 326, 16 }, { 342, 23 }, { 365, 20 }, { 385, 16 }, - { 401, 623 } } }, - - { { { 0, 742 }, { 742, 103 }, { 845, 5 }, { 850, 1 }, - { 851, 108 }, { 959, 38 }, { 997, 4 }, { 1001, 1 }, - { 1002, 7 }, { 1009, 5 }, { 1014, 2 }, { 1016, 1 }, - { 1017, 2 }, { 1019, 1 }, { 1020, 1 }, { 1021, 1 }, - { 1022, 2 } } }, - - { { { 0, 42 }, { 42, 52 }, { 94, 27 }, { 121, 16 }, - { 137, 49 }, { 186, 58 }, { 244, 36 }, { 280, 23 }, - { 303, 27 }, { 330, 36 }, { 366, 26 }, { 392, 18 }, - { 410, 17 }, { 427, 24 }, { 451, 19 }, { 470, 14 }, - { 484, 540 } } }, - - { { { 0, 13 }, { 13, 20 }, { 33, 18 }, { 51, 15 }, - { 66, 19 }, { 85, 29 }, { 114, 26 }, { 140, 21 }, - { 161, 17 }, { 178, 25 }, { 203, 22 }, { 225, 18 }, - { 243, 13 }, { 256, 19 }, { 275, 17 }, { 292, 15 }, - { 307, 717 } } }, - - { { { 0, 501 }, { 501, 169 }, { 670, 19 }, { 689, 4 }, - { 693, 155 }, { 848, 88 }, { 936, 16 }, { 952, 4 }, - { 956, 19 }, { 975, 16 }, { 991, 6 }, { 997, 2 }, - { 999, 5 }, { 1004, 4 }, { 1008, 2 }, { 1010, 1 }, - { 1011, 13 } } }, - - { { { 0, 445 }, { 445, 136 }, { 581, 22 }, { 603, 6 }, - { 609, 158 }, { 767, 98 }, { 865, 23 }, { 888, 7 }, - { 895, 31 }, { 926, 28 }, { 954, 10 }, { 964, 4 }, - { 968, 9 }, { 977, 9 }, { 986, 5 }, { 991, 2 }, - { 993, 31 } } }, - - { { { 0, 285 }, { 285, 157 }, { 442, 37 }, { 479, 10 }, - { 489, 161 }, { 650, 129 }, { 779, 39 }, { 818, 12 }, - { 830, 40 }, { 870, 42 }, { 912, 18 }, { 930, 7 }, - { 937, 12 }, { 949, 14 }, { 963, 8 }, { 971, 4 }, - { 975, 49 } } }, - - { { { 0, 349 }, { 349, 179 }, { 528, 33 }, { 561, 8 }, - { 569, 162 }, { 731, 121 }, { 852, 31 }, { 883, 9 }, - { 892, 31 }, { 923, 30 }, { 953, 12 }, { 965, 5 }, - { 970, 8 }, { 978, 9 }, { 987, 5 }, { 992, 2 }, - { 994, 30 } } }, - - { { { 0, 199 }, { 199, 156 }, { 355, 47 }, { 402, 15 }, - { 417, 146 }, { 563, 137 }, { 700, 50 }, { 750, 17 }, - { 767, 44 }, { 811, 49 }, { 860, 24 }, { 884, 10 }, - { 894, 15 }, { 909, 17 }, { 926, 10 }, { 936, 6 }, - { 942, 82 } } }, - - { { { 0, 141 }, { 141, 134 }, { 275, 50 }, { 325, 18 }, - { 343, 128 }, { 471, 135 }, { 606, 58 }, { 664, 22 }, - { 686, 48 }, { 734, 57 }, { 791, 31 }, { 822, 14 }, - { 836, 18 }, { 854, 23 }, { 877, 14 }, { 891, 8 }, - { 899, 125 } } }, - - { { { 0, 243 }, { 243, 194 }, { 437, 56 }, { 493, 17 }, - { 510, 139 }, { 649, 126 }, { 775, 45 }, { 820, 16 }, - { 836, 33 }, { 869, 36 }, { 905, 18 }, { 923, 8 }, - { 931, 10 }, { 941, 12 }, { 953, 7 }, { 960, 4 }, - { 964, 60 } } }, - - { { { 0, 91 }, { 91, 106 }, { 197, 51 }, { 248, 23 }, - { 271, 99 }, { 370, 117 }, { 487, 63 }, { 550, 30 }, - { 580, 45 }, { 625, 59 }, { 684, 37 }, { 721, 20 }, - { 741, 20 }, { 761, 27 }, { 788, 19 }, { 807, 12 }, - { 819, 205 } } }, - - { { { 0, 107 }, { 107, 94 }, { 201, 41 }, { 242, 20 }, - { 262, 92 }, { 354, 97 }, { 451, 52 }, { 503, 28 }, - { 531, 42 }, { 573, 53 }, { 626, 34 }, { 660, 20 }, - { 680, 21 }, { 701, 29 }, { 730, 21 }, { 751, 14 }, - { 765, 259 } } }, - - { { { 0, 168 }, { 168, 171 }, { 339, 68 }, { 407, 25 }, - { 432, 121 }, { 553, 123 }, { 676, 55 }, { 731, 24 }, - { 755, 34 }, { 789, 41 }, { 830, 24 }, { 854, 12 }, - { 866, 13 }, { 879, 16 }, { 895, 11 }, { 906, 6 }, - { 912, 112 } } }, - - { { { 0, 67 }, { 67, 80 }, { 147, 44 }, { 191, 23 }, - { 214, 76 }, { 290, 94 }, { 384, 57 }, { 441, 31 }, - { 472, 41 }, { 513, 54 }, { 567, 37 }, { 604, 23 }, - { 627, 21 }, { 648, 30 }, { 678, 22 }, { 700, 15 }, - { 715, 309 } } }, - - { { { 0, 46 }, { 46, 63 }, { 109, 39 }, { 148, 23 }, - { 171, 58 }, { 229, 78 }, { 307, 52 }, { 359, 32 }, - { 391, 36 }, { 427, 49 }, { 476, 37 }, { 513, 24 }, - { 537, 21 }, { 558, 30 }, { 588, 24 }, { 612, 17 }, - { 629, 395 } } }, - - { { { 0, 848 }, { 848, 70 }, { 918, 2 }, { 920, 1 }, - { 921, 75 }, { 996, 16 }, { 1012, 1 }, { 1013, 1 }, - { 1014, 2 }, { 1016, 1 }, { 1017, 1 }, { 1018, 1 }, - { 1019, 1 }, { 1020, 1 }, { 1021, 1 }, { 1022, 1 }, - { 1023, 1 } } }, - - { { { 0, 36 }, { 36, 52 }, { 88, 35 }, { 123, 22 }, - { 145, 48 }, { 193, 67 }, { 260, 48 }, { 308, 32 }, - { 340, 32 }, { 372, 45 }, { 417, 35 }, { 452, 24 }, - { 476, 20 }, { 496, 29 }, { 525, 23 }, { 548, 17 }, - { 565, 459 } } }, - - { { { 0, 24 }, { 24, 37 }, { 61, 29 }, { 90, 20 }, - { 110, 35 }, { 145, 51 }, { 196, 41 }, { 237, 29 }, - { 266, 26 }, { 292, 38 }, { 330, 31 }, { 361, 24 }, - { 385, 18 }, { 403, 27 }, { 430, 23 }, { 453, 18 }, - { 471, 553 } } }, - - { { { 0, 85 }, { 85, 97 }, { 182, 48 }, { 230, 23 }, - { 253, 91 }, { 344, 110 }, { 454, 61 }, { 515, 30 }, - { 545, 45 }, { 590, 58 }, { 648, 37 }, { 685, 21 }, - { 706, 21 }, { 727, 29 }, { 756, 20 }, { 776, 13 }, - { 789, 235 } } }, - - { { { 0, 22 }, { 22, 33 }, { 55, 27 }, { 82, 20 }, - { 102, 33 }, { 135, 48 }, { 183, 39 }, { 222, 30 }, - { 252, 26 }, { 278, 37 }, { 315, 30 }, { 345, 23 }, - { 368, 17 }, { 385, 25 }, { 410, 21 }, { 431, 17 }, - { 448, 576 } } }, - - { { { 0, 1 }, { 1, 1 }, { 2, 54 }, { 56, 33 }, - { 89, 1 }, { 90, 1 }, { 91, 49 }, { 140, 32 }, - { 172, 49 }, { 221, 47 }, { 268, 35 }, { 303, 25 }, - { 328, 30 }, { 358, 30 }, { 388, 24 }, { 412, 18 }, - { 430, 594 } } }, - - { { { 0, 45 }, { 45, 64 }, { 109, 43 }, { 152, 25 }, - { 177, 62 }, { 239, 81 }, { 320, 56 }, { 376, 35 }, - { 411, 37 }, { 448, 51 }, { 499, 38 }, { 537, 26 }, - { 563, 22 }, { 585, 31 }, { 616, 24 }, { 640, 18 }, - { 658, 366 } } }, - - { { { 0, 247 }, { 247, 148 }, { 395, 38 }, { 433, 12 }, - { 445, 154 }, { 599, 130 }, { 729, 42 }, { 771, 14 }, - { 785, 44 }, { 829, 46 }, { 875, 21 }, { 896, 9 }, - { 905, 15 }, { 920, 17 }, { 937, 9 }, { 946, 5 }, - { 951, 73 } } }, - - { { { 0, 231 }, { 231, 136 }, { 367, 41 }, { 408, 15 }, - { 423, 134 }, { 557, 119 }, { 676, 47 }, { 723, 19 }, - { 742, 44 }, { 786, 49 }, { 835, 25 }, { 860, 12 }, - { 872, 17 }, { 889, 20 }, { 909, 12 }, { 921, 7 }, - { 928, 96 } } } - -}; - -const uint16_t lc3_spectrum_bits[][17] = { - - { 20480, 20480, 5220, 9042, 20480, 20480, 6619, 9892, - 5289, 6619, 9105, 11629, 8982, 9892, 11629, 13677, 4977 }, - - { 11940, 10854, 12109, 13677, 10742, 9812, 11090, 12288, - 11348, 10240, 11348, 12683, 12109, 10854, 11629, 12902, 1197 }, - - { 7886, 7120, 8982, 10970, 7496, 6815, 8334, 10150, - 9437, 8535, 9656, 11216, 11348, 10431, 11348, 12479, 4051 }, - - { 5485, 6099, 9168, 11940, 6311, 6262, 8640, 11090, - 9233, 8640, 10334, 12479, 11781, 11090, 12479, 13988, 6009 }, - - { 7886, 7804, 10150, 11940, 7886, 7685, 9368, 10854, - 10061, 9300, 10431, 11629, 11629, 10742, 11485, 12479, 2763 }, - - { 9042, 8383, 10240, 11781, 8483, 8013, 9437, 10742, - 10334, 9437, 10431, 11485, 11781, 10742, 11485, 12288, 2346 }, - - { 5922, 6619, 9368, 11940, 6566, 6539, 8750, 10970, - 9168, 8640, 10240, 12109, 11485, 10742, 11940, 13396, 5009 }, - - { 12288, 11090, 11348, 12109, 11090, 9892, 10334, 10970, - 11629, 10431, 10970, 11629, 12479, 11348, 11781, 12288, 1289 }, - - { 1685, 5676, 13138, 18432, 5598, 7804, 13677, 18432, - 12683, 13396, 17234, 20480, 17234, 17234, 20480, 20480, 15725 }, - - { 2793, 5072, 10970, 15725, 5204, 6487, 11216, 15186, - 10970, 11216, 14336, 17234, 15186, 15186, 17234, 18432, 12109 }, - - { 12902, 11485, 11940, 13396, 11629, 10531, 11348, 12479, - 12683, 11629, 12288, 13138, 13677, 12683, 13138, 13677, 854 }, - - { 3821, 5088, 9812, 13988, 5289, 5901, 9812, 13677, - 9976, 9892, 12479, 15186, 13988, 13677, 15186, 17234, 9812 }, - - { 4856, 5412, 9168, 12902, 5598, 5736, 8863, 12288, - 9368, 8982, 11090, 13677, 12902, 12288, 13677, 15725, 8147 }, - - { 20480, 20480, 7088, 9300, 20480, 20480, 7844, 9733, - 7320, 7928, 9368, 10970, 9581, 9892, 10970, 12288, 2550 }, - - { 6031, 5859, 8192, 10635, 6410, 6286, 8433, 10742, - 9656, 9042, 10531, 12479, 12479, 11629, 12902, 14336, 5756 }, - - { 6144, 6215, 8982, 11940, 6262, 6009, 8433, 11216, - 8982, 8433, 10240, 12479, 11781, 11090, 12479, 13988, 5817 }, - - { 20480, 20480, 11216, 12109, 20480, 20480, 11216, 11940, - 11629, 11485, 11940, 12479, 12479, 12109, 12683, 13138, 704 }, - - { 7928, 6994, 8239, 9733, 7218, 6539, 8147, 9892, - 9812, 9105, 10240, 11629, 12109, 11216, 12109, 13138, 4167 }, - - { 8640, 7724, 9233, 10970, 8013, 7185, 8483, 10150, - 9656, 8694, 9656, 10970, 11348, 10334, 11090, 12288, 3391 }, - - { 20480, 18432, 18432, 18432, 18432, 18432, 18432, 18432, - 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 91 }, - - { 10061, 8863, 9733, 11090, 8982, 7970, 8806, 9976, - 10061, 9105, 9812, 10742, 11485, 10334, 10970, 11781, 2557 }, - - { 10431, 9368, 10240, 11348, 9368, 8433, 9233, 10334, - 10431, 9437, 10061, 10970, 11781, 10635, 11216, 11940, 2119 }, - - { 13988, 12479, 12683, 12902, 12683, 11348, 11485, 11940, - 12902, 11629, 11940, 12288, 13396, 12109, 12479, 12683, 828 }, - - { 10431, 9300, 10334, 11629, 9508, 8483, 9437, 10635, - 10635, 9656, 10431, 11348, 11940, 10854, 11485, 12288, 1946 }, - - { 12479, 11216, 11629, 12479, 11348, 10150, 10635, 11348, - 11940, 10854, 11216, 11940, 12902, 11629, 11940, 12479, 1146 }, - - { 13396, 12109, 12288, 12902, 12109, 10854, 11216, 11781, - 12479, 11348, 11629, 12109, 13138, 11940, 12288, 12683, 928 }, - - { 2443, 5289, 11629, 16384, 5170, 6730, 11940, 16384, - 11216, 11629, 14731, 18432, 15725, 15725, 18432, 20480, 13396 }, - - { 3328, 5009, 10531, 15186, 5040, 6031, 10531, 14731, - 10431, 10431, 13396, 16384, 15186, 14731, 16384, 18432, 11629 }, - - { 14336, 12902, 12902, 13396, 12902, 11629, 11940, 12288, - 13138, 12109, 12288, 12902, 13677, 12683, 12902, 13138, 711 }, - - { 4300, 5204, 9437, 13396, 5430, 5776, 9300, 12902, - 9656, 9437, 11781, 14731, 13396, 12902, 14731, 16384, 8982 }, - - { 5394, 5776, 8982, 12288, 5922, 5901, 8640, 11629, - 9105, 8694, 10635, 13138, 12288, 11629, 13138, 14731, 6844 }, - - { 17234, 15725, 15725, 15725, 15725, 14731, 14731, 14731, - 16384, 14731, 14731, 15186, 16384, 15186, 15186, 15186, 272 }, - - { 6461, 6286, 8806, 11348, 6566, 6215, 8334, 10742, - 9233, 8535, 10061, 12109, 11781, 10970, 12109, 13677, 5394 }, - - { 6674, 6487, 8863, 11485, 6702, 6286, 8334, 10635, - 9168, 8483, 9976, 11940, 11629, 10854, 11940, 13396, 5105 }, - - { 15186, 13677, 13677, 13988, 13677, 12479, 12479, 12683, - 13988, 12683, 12902, 13138, 14336, 13138, 13396, 13677, 565 }, - - { 7844, 7252, 8922, 10854, 7389, 6815, 8383, 10240, - 9508, 8750, 9892, 11485, 11629, 10742, 11629, 12902, 3842 }, - - { 9233, 8239, 9233, 10431, 8334, 7424, 8483, 9892, - 10061, 9105, 10061, 11216, 11781, 10742, 11485, 12479, 2906 }, - - { 20480, 20480, 14731, 14731, 20480, 20480, 14336, 14336, - 15186, 14336, 14731, 14731, 15186, 14731, 14731, 15186, 266 }, - - { 10531, 9300, 9976, 11090, 9437, 8286, 9042, 10061, - 10431, 9368, 9976, 10854, 11781, 10531, 11090, 11781, 2233 }, - - { 11629, 10334, 10970, 12109, 10431, 9368, 10061, 10970, - 11348, 10240, 10854, 11485, 12288, 11216, 11629, 12288, 1469 }, - - { 952, 6787, 15725, 20480, 6646, 9733, 16384, 20480, - 14731, 15725, 18432, 20480, 18432, 20480, 20480, 20480, 18432 }, - - { 9437, 8806, 10742, 12288, 8982, 8483, 9892, 11216, - 10742, 9892, 10854, 11940, 12109, 11090, 11781, 12683, 1891 }, - - { 12902, 11629, 11940, 12479, 11781, 10531, 10854, 11485, - 12109, 10970, 11348, 11940, 12902, 11781, 12109, 12479, 1054 }, - - { 2113, 5323, 11781, 16384, 5579, 7252, 12288, 16384, - 11781, 12288, 15186, 18432, 15725, 16384, 18432, 20480, 12902 }, - - { 2463, 5965, 11348, 15186, 5522, 6934, 11216, 14731, - 10334, 10635, 13677, 16384, 13988, 13988, 15725, 18432, 10334 }, - - { 3779, 5541, 9812, 13677, 5467, 6122, 9656, 13138, - 9581, 9437, 11940, 14731, 13138, 12683, 14336, 16384, 8982 }, - - { 3181, 5154, 10150, 14336, 5448, 6311, 10334, 13988, - 10334, 10431, 13138, 15725, 14336, 13988, 15725, 18432, 10431 }, - - { 4841, 5560, 9105, 12479, 5756, 5944, 8922, 12109, - 9300, 8982, 11090, 13677, 12479, 12109, 13677, 15186, 7460 }, - - { 5859, 6009, 8922, 11940, 6144, 5987, 8483, 11348, - 9042, 8535, 10334, 12683, 11940, 11216, 12683, 14336, 6215 }, - - { 4250, 4916, 8587, 12109, 5901, 6191, 9233, 12288, - 10150, 9892, 11940, 14336, 13677, 13138, 14731, 16384, 8383 }, - - { 7153, 6702, 8863, 11216, 6904, 6410, 8239, 10431, - 9233, 8433, 9812, 11629, 11629, 10742, 11781, 13138, 4753 }, - - { 6674, 7057, 9508, 11629, 7120, 6964, 8806, 10635, - 9437, 8750, 10061, 11629, 11485, 10531, 11485, 12683, 4062 }, - - { 5341, 5289, 8013, 10970, 6311, 6262, 8640, 11090, - 10061, 9508, 11090, 13138, 12902, 12288, 13396, 15186, 6539 }, - - { 8057, 7533, 9300, 11216, 7685, 7057, 8535, 10334, - 9508, 8694, 9812, 11216, 11485, 10431, 11348, 12479, 3541 }, - - { 9168, 8239, 9656, 11216, 8483, 7608, 8806, 10240, - 9892, 8982, 9812, 11090, 11485, 10431, 11090, 12109, 2815 }, - - { 558, 7928, 18432, 20480, 7724, 12288, 20480, 20480, - 18432, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480 }, - - { 9892, 8806, 9976, 11348, 9042, 8057, 9042, 10240, - 10240, 9233, 9976, 11090, 11629, 10531, 11216, 12109, 2371 }, - - { 11090, 9812, 10531, 11629, 9976, 8863, 9508, 10531, - 10854, 9733, 10334, 11090, 11940, 10742, 11216, 11940, 1821 }, - - { 7354, 6964, 9042, 11216, 7153, 6592, 8334, 10431, - 9233, 8483, 9812, 11485, 11485, 10531, 11629, 12902, 4349 }, - - { 11348, 10150, 10742, 11629, 10150, 9042, 9656, 10431, - 10854, 9812, 10431, 11216, 12109, 10970, 11485, 12109, 1700 }, - - { 20480, 20480, 8694, 10150, 20480, 20480, 8982, 10240, - 8982, 9105, 9976, 10970, 10431, 10431, 11090, 11940, 1610 }, - - { 9233, 8192, 9368, 10970, 8286, 7496, 8587, 9976, - 9812, 8863, 9733, 10854, 11348, 10334, 11090, 11940, 3040 }, - - { 4202, 5716, 9733, 13138, 5598, 6099, 9437, 12683, - 9300, 9168, 11485, 13988, 12479, 12109, 13988, 15725, 7804 }, - - { 4400, 5965, 9508, 12479, 6009, 6360, 9105, 11781, - 9300, 8982, 10970, 13138, 12109, 11629, 13138, 14731, 6994 } - -}; diff --git a/system/embdrv/lc3/src/tables.h b/system/embdrv/lc3/src/tables.h deleted file mode 100644 index 26bd48efd3c8f8de0579574934e9a883864120bb..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/tables.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#ifndef __LC3_TABLES_H -#define __LC3_TABLES_H - -#include "common.h" -#include "bits.h" - - -/** - * MDCT Twiddles and window coefficients - */ - -struct lc3_fft_bf3_twiddles { int n3; const struct lc3_complex (*t)[2]; }; -struct lc3_fft_bf2_twiddles { int n2; const struct lc3_complex *t; }; -struct lc3_mdct_rot_def { int n4; const struct lc3_complex *w; }; - -extern const struct lc3_fft_bf3_twiddles *lc3_fft_twiddles_bf3[]; -extern const struct lc3_fft_bf2_twiddles *lc3_fft_twiddles_bf2[][3]; -extern const struct lc3_mdct_rot_def *lc3_mdct_rot[LC3_NUM_DT][LC3_NUM_SRATE]; - -extern const float *lc3_mdct_win[LC3_NUM_DT][LC3_NUM_SRATE]; - - -/** - * Limits of bands - */ - -#define LC3_NUM_BANDS 64 - -extern const int lc3_band_lim[LC3_NUM_DT][LC3_NUM_SRATE][LC3_NUM_BANDS+1]; - - -/** - * SNS Quantization - */ - -extern const float lc3_sns_lfcb[32][8]; -extern const float lc3_sns_hfcb[32][8]; - -struct lc3_sns_vq_gains { - int count; const float *v; -}; - -extern const struct lc3_sns_vq_gains lc3_sns_vq_gains[4]; - -extern const int32_t lc3_sns_mpvq_offsets[][11]; - - -/** - * TNS Arithmetic Coding - */ - -extern const struct lc3_ac_model lc3_tns_order_models[]; -extern const uint16_t lc3_tns_order_bits[][8]; - -extern const struct lc3_ac_model lc3_tns_coeffs_models[]; -extern const uint16_t lc3_tns_coeffs_bits[][17]; - - -/** - * Long Term Postfilter - */ - -extern const float *lc3_ltpf_cnum[LC3_NUM_SRATE][4]; -extern const float *lc3_ltpf_cden[LC3_NUM_SRATE][4]; - - -/** - * Spectral Data Arithmetic Coding - */ - -extern const uint8_t lc3_spectrum_lookup[2][2][256][4]; -extern const struct lc3_ac_model lc3_spectrum_models[]; -extern const uint16_t lc3_spectrum_bits[][17]; - - -#endif /* __LC3_TABLES_H */ diff --git a/system/embdrv/lc3/src/tns.c b/system/embdrv/lc3/src/tns.c deleted file mode 100644 index 0032b4f5e5e5d34ae2d805f2c4c4be236d2ae7ea..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/tns.c +++ /dev/null @@ -1,457 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "tns.h" -#include "tables.h" - - -/* ---------------------------------------------------------------------------- - * Filter Coefficients - * -------------------------------------------------------------------------- */ - -/** - * Resolve LPC Weighting indication according bitrate - * dt, nbytes Duration and size of the frame - * return True when LPC Weighting enabled - */ -static bool resolve_lpc_weighting(enum lc3_dt dt, int nbytes) -{ - return nbytes < (dt == LC3_DT_7M5 ? 360/8 : 480/8); -} - -/** - * Return dot product of 2 vectors - * a, b, n The 2 vectors of size `n` - * return sum( a[i] * b[i] ), i = [0..n-1] - */ -LC3_HOT static inline float dot(const float *a, const float *b, int n) -{ - float v = 0; - - while (n--) - v += *(a++) * *(b++); - - return v; -} - -/** - * LPC Coefficients - * dt, bw Duration and bandwidth of the frame - * x Spectral coefficients - * gain, a Output the prediction gains and LPC coefficients - */ -LC3_HOT static void compute_lpc_coeffs( - enum lc3_dt dt, enum lc3_bandwidth bw, - const float *x, float *gain, float (*a)[9]) -{ - static const int sub_7m5_nb[] = { 9, 26, 43, 60 }; - static const int sub_7m5_wb[] = { 9, 46, 83, 120 }; - static const int sub_7m5_sswb[] = { 9, 66, 123, 180 }; - static const int sub_7m5_swb[] = { 9, 46, 82, 120, 159, 200, 240 }; - static const int sub_7m5_fb[] = { 9, 56, 103, 150, 200, 250, 300 }; - - static const int sub_10m_nb[] = { 12, 34, 57, 80 }; - static const int sub_10m_wb[] = { 12, 61, 110, 160 }; - static const int sub_10m_sswb[] = { 12, 88, 164, 240 }; - static const int sub_10m_swb[] = { 12, 61, 110, 160, 213, 266, 320 }; - static const int sub_10m_fb[] = { 12, 74, 137, 200, 266, 333, 400 }; - - /* --- Normalized autocorrelation --- */ - - static const float lag_window[] = { - 1.00000000e+00, 9.98028026e-01, 9.92135406e-01, 9.82391584e-01, - 9.68910791e-01, 9.51849807e-01, 9.31404933e-01, 9.07808230e-01, - 8.81323137e-01 - }; - - const int *sub = (const int * const [LC3_NUM_DT][LC3_NUM_SRATE]){ - { sub_7m5_nb, sub_7m5_wb, sub_7m5_sswb, sub_7m5_swb, sub_7m5_fb }, - { sub_10m_nb, sub_10m_wb, sub_10m_sswb, sub_10m_swb, sub_10m_fb }, - }[dt][bw]; - - int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB); - - const float *xs, *xe = x + *sub; - float r[2][9]; - - for (int f = 0; f < nfilters; f++) { - float c[9][3]; - - for (int s = 0; s < 3; s++) { - xs = xe, xe = x + *(++sub); - - for (int k = 0; k < 9; k++) - c[k][s] = dot(xs, xs + k, (xe - xs) - k); - } - - float e0 = c[0][0], e1 = c[0][1], e2 = c[0][2]; - - r[f][0] = 3; - for (int k = 1; k < 9; k++) - r[f][k] = e0 == 0 || e1 == 0 || e2 == 0 ? 0 : - (c[k][0]/e0 + c[k][1]/e1 + c[k][2]/e2) * lag_window[k]; - } - - /* --- Levinson-Durbin recursion --- */ - - for (int f = 0; f < nfilters; f++) { - float *a0 = a[f], a1[9]; - float err = r[f][0], rc; - - gain[f] = err; - - a0[0] = 1; - for (int k = 1; k < 9; ) { - - rc = -r[f][k]; - for (int i = 1; i < k; i++) - rc -= a0[i] * r[f][k-i]; - - rc /= err; - err *= 1 - rc * rc; - - for (int i = 1; i < k; i++) - a1[i] = a0[i] + rc * a0[k-i]; - a1[k++] = rc; - - rc = -r[f][k]; - for (int i = 1; i < k; i++) - rc -= a1[i] * r[f][k-i]; - - rc /= err; - err *= 1 - rc * rc; - - for (int i = 1; i < k; i++) - a0[i] = a1[i] + rc * a1[k-i]; - a0[k++] = rc; - } - - gain[f] /= err; - } -} - -/** - * LPC Weighting - * gain, a Prediction gain and LPC coefficients, weighted as output - */ -LC3_HOT static void lpc_weighting(float pred_gain, float *a) -{ - float gamma = 1.f - (1.f - 0.85f) * (2.f - pred_gain) / (2.f - 1.5f); - float g = 1.f; - - for (int i = 1; i < 9; i++) - a[i] *= (g *= gamma); -} - -/** - * LPC reflection - * a LPC coefficients - * rc Output refelection coefficients - */ -LC3_HOT static void lpc_reflection(const float *a, float *rc) -{ - float e, b[2][7], *b0, *b1; - - rc[7] = a[1+7]; - e = 1 - rc[7] * rc[7]; - - b1 = b[1]; - for (int i = 0; i < 7; i++) - b1[i] = (a[1+i] - rc[7] * a[7-i]) / e; - - for (int k = 6; k > 0; k--) { - b0 = b1, b1 = b[k & 1]; - - rc[k] = b0[k]; - e = 1 - rc[k] * rc[k]; - - for (int i = 0; i < k; i++) - b1[i] = (b0[i] - rc[k] * b0[k-1-i]) / e; - } - - rc[0] = b1[0]; -} - -/** - * Quantization of RC coefficients - * rc Refelection coefficients - * rc_order Return order of coefficients - * rc_i Return quantized coefficients - */ -static void quantize_rc(const float *rc, int *rc_order, int *rc_q) -{ - /* Quantization table, sin(delta * (i + 0.5)), delta = Pi / 17 */ - - static float q_thr[] = { - 9.22683595e-02, 2.73662990e-01, 4.45738356e-01, 6.02634636e-01, - 7.39008917e-01, 8.50217136e-01, 9.32472229e-01, 9.82973100e-01 - }; - - *rc_order = 8; - - for (int i = 0; i < 8; i++) { - float rc_m = fabsf(rc[i]); - - rc_q[i] = 4 * (rc_m >= q_thr[4]); - for (int j = 0; j < 4 && rc_m >= q_thr[rc_q[i]]; j++, rc_q[i]++); - - if (rc[i] < 0) - rc_q[i] = -rc_q[i]; - - *rc_order = rc_q[i] != 0 ? 8 : *rc_order - 1; - } -} - -/** - * Unquantization of RC coefficients - * rc_q Quantized coefficients - * rc_order Order of coefficients - * rc Return refelection coefficients - */ -static void unquantize_rc(const int *rc_q, int rc_order, float rc[8]) -{ - /* Quantization table, sin(delta * i), delta = Pi / 17 */ - - static float q_inv[] = { - 0.00000000e+00, 1.83749517e-01, 3.61241664e-01, 5.26432173e-01, - 6.73695641e-01, 7.98017215e-01, 8.95163302e-01, 9.61825645e-01, - 9.95734176e-01 - }; - - int i; - - for (i = 0; i < rc_order; i++) { - float rc_m = q_inv[LC3_ABS(rc_q[i])]; - rc[i] = rc_q[i] < 0 ? -rc_m : rc_m; - } -} - - -/* ---------------------------------------------------------------------------- - * Filtering - * -------------------------------------------------------------------------- */ - -/** - * Forward filtering - * dt, bw Duration and bandwidth of the frame - * rc_order, rc Order of coefficients, and coefficients - * x Spectral coefficients, filtered as output - */ -LC3_HOT static void forward_filtering( - enum lc3_dt dt, enum lc3_bandwidth bw, - const int rc_order[2], const float rc[2][8], float *x) -{ - int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB); - int nf = LC3_NE(dt, bw) >> (nfilters - 1); - int i0, ie = 3*(3 + dt); - - float s[8] = { 0 }; - - for (int f = 0; f < nfilters; f++) { - - i0 = ie; - ie = nf * (1 + f); - - if (!rc_order[f]) - continue; - - for (int i = i0; i < ie; i++) { - float xi = x[i]; - float s0, s1 = xi; - - for (int k = 0; k < rc_order[f]; k++) { - s0 = s[k]; - s[k] = s1; - - s1 = rc[f][k] * xi + s0; - xi += rc[f][k] * s0; - } - - x[i] = xi; - } - } -} - -/** - * Inverse filtering - * dt, bw Duration and bandwidth of the frame - * rc_order, rc Order of coefficients, and unquantized coefficients - * x Spectral coefficients, filtered as output - */ -LC3_HOT static void inverse_filtering( - enum lc3_dt dt, enum lc3_bandwidth bw, - const int rc_order[2], const float rc[2][8], float *x) -{ - int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB); - int nf = LC3_NE(dt, bw) >> (nfilters - 1); - int i0, ie = 3*(3 + dt); - - float s[8] = { 0 }; - - for (int f = 0; f < nfilters; f++) { - - i0 = ie; - ie = nf * (1 + f); - - if (!rc_order[f]) - continue; - - for (int i = i0; i < ie; i++) { - float xi = x[i]; - - xi -= s[7] * rc[f][7]; - for (int k = 6; k >= 0; k--) { - xi -= s[k] * rc[f][k]; - s[k+1] = s[k] + rc[f][k] * xi; - } - s[0] = xi; - x[i] = xi; - } - - for (int k = 7; k >= rc_order[f]; k--) - s[k] = 0; - } -} - - -/* ---------------------------------------------------------------------------- - * Interface - * -------------------------------------------------------------------------- */ - -/** - * TNS analysis - */ -void lc3_tns_analyze(enum lc3_dt dt, enum lc3_bandwidth bw, - bool nn_flag, int nbytes, struct lc3_tns_data *data, float *x) -{ - /* Processing steps : - * - Determine the LPC (Linear Predictive Coding) Coefficients - * - Check is the filtering is disabled - * - The coefficients are weighted on low bitrates and predicition gain - * - Convert to reflection coefficients and quantize - * - Finally filter the spectral coefficients */ - - float pred_gain[2], a[2][9]; - float rc[2][8]; - - data->nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB); - data->lpc_weighting = resolve_lpc_weighting(dt, nbytes); - - compute_lpc_coeffs(dt, bw, x, pred_gain, a); - - for (int f = 0; f < data->nfilters; f++) { - - data->rc_order[f] = 0; - if (nn_flag || pred_gain[f] <= 1.5f) - continue; - - if (data->lpc_weighting && pred_gain[f] < 2.f) - lpc_weighting(pred_gain[f], a[f]); - - lpc_reflection(a[f], rc[f]); - - quantize_rc(rc[f], &data->rc_order[f], data->rc[f]); - unquantize_rc(data->rc[f], data->rc_order[f], rc[f]); - } - - forward_filtering(dt, bw, data->rc_order, rc, x); -} - -/** - * TNS synthesis - */ -void lc3_tns_synthesize(enum lc3_dt dt, enum lc3_bandwidth bw, - const struct lc3_tns_data *data, float *x) -{ - float rc[2][8] = { }; - - for (int f = 0; f < data->nfilters; f++) - if (data->rc_order[f]) - unquantize_rc(data->rc[f], data->rc_order[f], rc[f]); - - inverse_filtering(dt, bw, data->rc_order, rc, x); -} - -/** - * Bit consumption of bitstream data - */ -int lc3_tns_get_nbits(const struct lc3_tns_data *data) -{ - int nbits = 0; - - for (int f = 0; f < data->nfilters; f++) { - - int nbits_2048 = 2048; - int rc_order = data->rc_order[f]; - - nbits_2048 += rc_order > 0 ? lc3_tns_order_bits - [data->lpc_weighting][rc_order-1] : 0; - - for (int i = 0; i < rc_order; i++) - nbits_2048 += lc3_tns_coeffs_bits[i][8 + data->rc[f][i]]; - - nbits += (nbits_2048 + (1 << 11) - 1) >> 11; - } - - return nbits; -} - -/** - * Put bitstream data - */ -void lc3_tns_put_data(lc3_bits_t *bits, const struct lc3_tns_data *data) -{ - for (int f = 0; f < data->nfilters; f++) { - int rc_order = data->rc_order[f]; - - lc3_put_bits(bits, rc_order > 0, 1); - if (rc_order <= 0) - continue; - - lc3_put_symbol(bits, - lc3_tns_order_models + data->lpc_weighting, rc_order-1); - - for (int i = 0; i < rc_order; i++) - lc3_put_symbol(bits, - lc3_tns_coeffs_models + i, 8 + data->rc[f][i]); - } -} - -/** - * Get bitstream data - */ -void lc3_tns_get_data(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_bandwidth bw, int nbytes, lc3_tns_data_t *data) -{ - data->nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB); - data->lpc_weighting = resolve_lpc_weighting(dt, nbytes); - - for (int f = 0; f < data->nfilters; f++) { - - data->rc_order[f] = lc3_get_bit(bits); - if (!data->rc_order[f]) - continue; - - data->rc_order[f] += lc3_get_symbol(bits, - lc3_tns_order_models + data->lpc_weighting); - - for (int i = 0; i < data->rc_order[f]; i++) - data->rc[f][i] = (int)lc3_get_symbol(bits, - lc3_tns_coeffs_models + i) - 8; - } -} diff --git a/system/embdrv/lc3/src/tns.h b/system/embdrv/lc3/src/tns.h deleted file mode 100644 index 534f19179da630c2830a0f702a540d8de18d1778..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/src/tns.h +++ /dev/null @@ -1,99 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -/** - * LC3 - Temporal Noise Shaping - * - * Reference : Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 - */ - -#ifndef __LC3_TNS_H -#define __LC3_TNS_H - -#include "common.h" -#include "bits.h" - - -/** - * Bitstream data - */ - -typedef struct lc3_tns_data { - int nfilters; - bool lpc_weighting; - int rc_order[2]; - int rc[2][8]; -} lc3_tns_data_t; - - -/* ---------------------------------------------------------------------------- - * Encoding - * -------------------------------------------------------------------------- */ - -/** - * TNS analysis - * dt, bw Duration and bandwidth of the frame - * nn_flag True when high energy detected near Nyquist frequency - * nbytes Size in bytes of the frame - * data Return bitstream data - * x Spectral coefficients, filtered as output - */ -void lc3_tns_analyze(enum lc3_dt dt, enum lc3_bandwidth bw, - bool nn_flag, int nbytes, lc3_tns_data_t *data, float *x); - -/** - * Return number of bits coding the data - * data Bitstream data - * return Bit consumption - */ -int lc3_tns_get_nbits(const lc3_tns_data_t *data); - -/** - * Put bitstream data - * bits Bitstream context - * data Bitstream data - */ -void lc3_tns_put_data(lc3_bits_t *bits, const lc3_tns_data_t *data); - - -/* ---------------------------------------------------------------------------- - * Decoding - * -------------------------------------------------------------------------- */ - -/** - * Get bitstream data - * bits Bitstream context - * dt, bw Duration and bandwidth of the frame - * nbytes Size in bytes of the frame - * data Bitstream data - */ -void lc3_tns_get_data(lc3_bits_t *bits, - enum lc3_dt dt, enum lc3_bandwidth bw, int nbytes, lc3_tns_data_t *data); - -/** - * TNS synthesis - * dt, bw Duration and bandwidth of the frame - * data Bitstream data - * x Spectral coefficients, filtered as output - */ -void lc3_tns_synthesize(enum lc3_dt dt, enum lc3_bandwidth bw, - const lc3_tns_data_t *data, float *x); - - -#endif /* __LC3_TNS_H */ diff --git a/system/embdrv/lc3/tables/fastmath.py b/system/embdrv/lc3/tables/fastmath.py deleted file mode 100755 index 202561ae6f5f66aa77e301d9be1af5fb0913b779..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/tables/fastmath.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np -import matplotlib.pyplot as plt - - -def fast_exp2(x, p): - - p = p.astype(np.float32) - x = x.astype(np.float32) - - y = (((((p[0]*x) + p[1])*x + p[2])*x + p[3])*x + p[4])*x + 1 - - return np.power(y.astype(np.float32), 16) - -def approx_exp2(): - - x = np.arange(-8, 8, step=1e-3) - - p = np.polyfit(x, ((2 ** (x/16)) - 1) / x, 4) - y = [ fast_exp2(x[i], p) for i in range(len(x)) ] - e = np.abs(y - 2**x) / (2 ** x) - - print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e} }}' - .format(p[0], p[1], p[2], p[3], p[4])) - print('Max relative error: ', np.max(e)) - print('Max RMS error: ', np.sqrt(np.mean(e ** 2))) - - if False: - fig, (ax1, ax2) = plt.subplots(2) - - ax1.plot(x, 2**x, label='Reference') - ax1.plot(x, y, label='Approximation') - ax1.legend() - - ax2.plot(x, e, label='Relative Error') - ax2.legend() - - plt.show() - - -def fast_log2(x, p): - - p = p.astype(np.float32) - x = x.astype(np.float32) - - (x, e) = np.frexp(x) - - y = ((((p[0]*x) + p[1])*x + p[2])*x + p[3])*x + p[4] - - return (e ) + y.astype(np.float32) - -def approx_log2(): - - x = np.logspace(-1, 0, base=2, num=100) - p = np.polyfit(x, np.log2(x), 4) - - x = np.logspace(-2, 5, num=10000) - y = [ fast_log2(x[i], p) for i in range(len(x)) ] - e = np.abs(y - np.log2(x)) - - print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e} }}' - .format(p[0], p[1], p[2], p[3], p[4])) - print('Max absolute error: ', np.max(e)) - print('Max RMS error: ', np.sqrt(np.mean(e ** 2))) - - if False: - fig, (ax1, ax2) = plt.subplots(2) - - ax1.plot(x, np.log2(x), label='Reference') - ax1.plot(x, y, label='Approximation') - ax1.legend() - - ax2.plot(x, e, label = 'Absolute error') - ax2.legend() - - plt.show() - - -def table_db_q16(): - - k = 10 * np.log10(2); - - for i in range(32): - a = k * np.log2(np.ldexp(32 + i , -5)) - (i // 16) * (k/2); - b = k * np.log2(np.ldexp(32 + i+1, -5)) - (i // 16) * (k/2); - - an = np.ldexp(a, 15) + 0.5 - bn = np.ldexp(b - a, 15) + 0.5 - print('{{ {:5d}, {:4d} }},' - .format(int(np.ldexp(a, 15) + 0.5), - int(np.ldexp(b - a, 15) + 0.5)), - end = ' ' if i % 4 < 3 else '\n') - - -if __name__ == '__main__': - - print('\n--- Approximation of 2^n ---') - approx_exp2() - - print('\n--- Approximation of log2(n) ---') - approx_log2() - - print('\n--- Table of fixed Q16 dB ---') - table_db_q16() - - print('') diff --git a/system/embdrv/lc3/tables/mktables.py b/system/embdrv/lc3/tables/mktables.py deleted file mode 100755 index 67d4312d4dac065ed5f3d5cb0d83bdb6a5ead3da..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/tables/mktables.py +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np - -LTPF_H12K8 = np.array([ - -2.04305583e-05, -4.46345894e-05, -7.16366399e-05, -1.00101113e-04, - -1.28372848e-04, -1.54543830e-04, -1.76544567e-04, -1.92256960e-04, - -1.99643819e-04, -1.96888686e-04, -1.82538332e-04, -1.55639427e-04, - -1.15860365e-04, -6.35893034e-05, 2.81006480e-19, 7.29218021e-05, - 1.52397076e-04, 2.34920777e-04, 3.16378650e-04, 3.92211738e-04, - 4.57623849e-04, 5.07824294e-04, 5.38295523e-04, 5.45072918e-04, - 5.25022155e-04, 4.76098424e-04, 3.97571380e-04, 2.90200217e-04, - 1.56344667e-04, -5.81880142e-19, -1.73252713e-04, -3.56385965e-04, - -5.41155231e-04, -7.18414023e-04, -8.78505232e-04, -1.01171451e-03, - -1.10876706e-03, -1.16134522e-03, -1.16260169e-03, -1.10764097e-03, - -9.93941563e-04, -8.21692190e-04, -5.94017766e-04, -3.17074654e-04, - 9.74695082e-19, 3.45293760e-04, 7.04480871e-04, 1.06133447e-03, - 1.39837473e-03, 1.69763080e-03, 1.94148675e-03, 2.11357591e-03, - 2.19968245e-03, 2.18860625e-03, 2.07294546e-03, 1.84975249e-03, - 1.52102188e-03, 1.09397426e-03, 5.81108062e-04, -1.42248266e-18, - -6.27153730e-04, -1.27425140e-03, -1.91223839e-03, -2.51026925e-03, - -3.03703830e-03, -3.46222687e-03, -3.75800672e-03, -3.90053247e-03, - -3.87135231e-03, -3.65866558e-03, -3.25835851e-03, -2.67475555e-03, - -1.92103305e-03, -1.01925433e-03, 1.86962369e-18, 1.09841545e-03, - 2.23113197e-03, 3.34830927e-03, 4.39702277e-03, 5.32342672e-03, - 6.07510531e-03, 6.60352025e-03, 6.86645399e-03, 6.83034270e-03, - 6.47239234e-03, 5.78237521e-03, 4.76401273e-03, 3.43586351e-03, - 1.83165284e-03, -2.25189837e-18, -1.99647619e-03, -4.08266886e-03, - -6.17308037e-03, -8.17444895e-03, -9.98882386e-03, -1.15169871e-02, - -1.26621006e-02, -1.33334458e-02, -1.34501120e-02, -1.29444881e-02, - -1.17654154e-02, -9.88086732e-03, -7.28003640e-03, -3.97473021e-03, - 2.50961778e-18, 4.58604422e-03, 9.70324900e-03, 1.52512477e-02, - 2.11120585e-02, 2.71533724e-02, 3.32324245e-02, 3.92003203e-02, - 4.49066644e-02, 5.02043309e-02, 5.49542017e-02, 5.90297032e-02, - 6.23209727e-02, 6.47385023e-02, 6.62161245e-02, 6.67132287e-02, - 6.62161245e-02, 6.47385023e-02, 6.23209727e-02, 5.90297032e-02, - 5.49542017e-02, 5.02043309e-02, 4.49066644e-02, 3.92003203e-02, - 3.32324245e-02, 2.71533724e-02, 2.11120585e-02, 1.52512477e-02, - 9.70324900e-03, 4.58604422e-03, 2.50961778e-18, -3.97473021e-03, - -7.28003640e-03, -9.88086732e-03, -1.17654154e-02, -1.29444881e-02, - -1.34501120e-02, -1.33334458e-02, -1.26621006e-02, -1.15169871e-02, - -9.98882386e-03, -8.17444895e-03, -6.17308037e-03, -4.08266886e-03, - -1.99647619e-03, -2.25189837e-18, 1.83165284e-03, 3.43586351e-03, - 4.76401273e-03, 5.78237521e-03, 6.47239234e-03, 6.83034270e-03, - 6.86645399e-03, 6.60352025e-03, 6.07510531e-03, 5.32342672e-03, - 4.39702277e-03, 3.34830927e-03, 2.23113197e-03, 1.09841545e-03, - 1.86962369e-18, -1.01925433e-03, -1.92103305e-03, -2.67475555e-03, - -3.25835851e-03, -3.65866558e-03, -3.87135231e-03, -3.90053247e-03, - -3.75800672e-03, -3.46222687e-03, -3.03703830e-03, -2.51026925e-03, - -1.91223839e-03, -1.27425140e-03, -6.27153730e-04, -1.42248266e-18, - 5.81108062e-04, 1.09397426e-03, 1.52102188e-03, 1.84975249e-03, - 2.07294546e-03, 2.18860625e-03, 2.19968245e-03, 2.11357591e-03, - 1.94148675e-03, 1.69763080e-03, 1.39837473e-03, 1.06133447e-03, - 7.04480871e-04, 3.45293760e-04, 9.74695082e-19, -3.17074654e-04, - -5.94017766e-04, -8.21692190e-04, -9.93941563e-04, -1.10764097e-03, - -1.16260169e-03, -1.16134522e-03, -1.10876706e-03, -1.01171451e-03, - -8.78505232e-04, -7.18414023e-04, -5.41155231e-04, -3.56385965e-04, - -1.73252713e-04, -5.81880142e-19, 1.56344667e-04, 2.90200217e-04, - 3.97571380e-04, 4.76098424e-04, 5.25022155e-04, 5.45072918e-04, - 5.38295523e-04, 5.07824294e-04, 4.57623849e-04, 3.92211738e-04, - 3.16378650e-04, 2.34920777e-04, 1.52397076e-04, 7.29218021e-05, - 2.81006480e-19, -6.35893034e-05, -1.15860365e-04, -1.55639427e-04, - -1.82538332e-04, -1.96888686e-04, -1.99643819e-04, -1.92256960e-04, - -1.76544567e-04, -1.54543830e-04, -1.28372848e-04, -1.00101113e-04, - -7.16366399e-05, -4.46345894e-05, -2.04305583e-05 -]) - -LTPF_HI = np.array([ - 6.69885837e-03, 3.96711478e-02, 1.06999186e-01, 2.09880463e-01, - 3.35690625e-01, 4.59220930e-01, 5.50075002e-01, 5.83527575e-01, - 5.50075002e-01, 4.59220930e-01, 3.35690625e-01, 2.09880463e-01, - 1.06999186e-01, 3.96711478e-02, 6.69885837e-03 -]) - -def print_table(t, m=4): - - for (i, v) in enumerate(t): - print('{:14.8e},'.format(v), end = '\n' if i%m == m-1 else ' ') - - if len(t) % 4: - print('') - - -def mdct_fft_twiddles(): - - for n in (10, 20, 30, 40, 60, 80, 90, 120, 160, 180, 240): - - print('\n--- fft bf2 twiddles {:3d} ---'.format(n)) - - kv = -2 * np.pi * np.arange(n // 2) / n - for (i, k) in enumerate(kv): - print('{{ {:14.7e}, {:14.7e} }},'.format(np.cos(k), np.sin(k)), - end = '\n' if i%2 == 1 else ' ') - - for n in (15, 45): - - print('\n--- fft bf3 twiddles {:3d} ---'.format(n)) - - kv = -2 * np.pi * np.arange(n) / n - for k in kv: - print(('{{ {{ {:14.7e}, {:14.7e} }},' + - ' {{ {:14.7e}, {:14.7e} }} }},').format( - np.cos(k), np.sin(k), np.cos(2*k), np.sin(2*k))) - - -def mdct_rot_twiddles(): - - for n in (120, 160, 240, 320, 360, 480, 640, 720, 960): - - print('\n--- mdct rot twiddles {:3d} ---'.format(n)) - - kv = 2 * np.pi * (np.arange(n // 4) + 1/8) / n - for (i, k) in enumerate(kv): - print('{{ {:14.7e}, {:14.7e} }},'.format(np.cos(k), np.sin(k)), - end = '\n' if i%2 == 1 else ' ') - - -def mdct_scaling(): - - print('\n--- mdct scaling ---') - ns = np.array([ [ 60, 120, 180, 240, 360], [ 80, 160, 240, 320, 480] ]) - print_table(np.sqrt(2 / ns[0])) - print_table(np.sqrt(2 / ns[1])) - - -def tns_lag_window(): - - print('\n--- tns lag window ---') - print_table(np.exp(-0.5 * (0.02 * np.pi * np.arange(9)) ** 2)) - - -def tns_quantization_table(): - - print('\n--- tns quantization table ---') - print_table(np.sin((np.arange(8) + 0.5) * (np.pi / 17))) - print_table(np.sin((np.arange(8)) * (np.pi / 17))) - - -def quant_iq_table(): - - print('\n--- quantization iq table ---') - print_table(10 ** (np.arange(65) / 28)) - - -def sns_ge_table(): - - g_tilt_table = [ 14, 18, 22, 26, 30 ] - - for (sr, g_tilt) in enumerate(g_tilt_table): - print('\n--- sns ge table, sr:{} ---'.format(sr)) - print_table(10 ** ((np.arange(64) * g_tilt) / 630)) - - -def inv_table(): - - print('\n--- inv table ---') - print_table(np.append(np.zeros(1), 1 / np.arange(1, 28))) - -def ltpf_resampler_table(): - - for sr in [ 8, 16, 32, 24, 48 ]: - - r = 192 // sr - k = 64 if r & (r-1) else 192 - - p = (192 // k) * (k // sr) - q = p * (0.5 if sr == 8 else 1) - - print('\n--- LTPF resampler {:d} KHz to 12.8 KHz ---'.format(sr)) - - h = np.rint(np.append(LTPF_H12K8, 0.) * q * 2**15).astype(int) - h = h.reshape((len(h) // p, p)).T - h = np.flip(h, axis=0) - print('... Gain:', np.max(np.sum(np.abs(h), axis=1)) / 32768.) - - for i in range(0, len(h), 192 // k): - for j in range(0, len(h[i]), 10): - print('{:5d}, {:5d}, {:5d}, {:5d}, {:5d}, ' - '{:5d}, {:5d}, {:5d}, {:5d}, {:5d},'.format( - h[i][j+0], h[i][j+1], h[i][j+2], h[i][j+3], h[i][j+4], - h[i][j+5], h[i][j+6], h[i][j+7], h[i][j+8], h[i][j+9])) - - -def ltpf_interpolate_table(): - - print('\n--- LTPF interpolation ---') - - h = np.rint(np.append(LTPF_HI, 0.) * 2**15).astype(int) - - h = h.reshape(len(h) // 4, 4).T - h = np.flip(h, axis=0) - print('... Gain:', np.max(np.sum(np.abs(h), axis=1)) / 32768.) - - for i in range(len(h)): - print('{:5d}, {:5d}, {:5d}, {:5d}'.format( - h[i][0], h[i][1], h[i][2], h[i][3])) - - -if __name__ == '__main__': - - mdct_fft_twiddles() - mdct_rot_twiddles() - mdct_scaling() - - inv_table() - sns_ge_table() - tns_lag_window() - tns_quantization_table() - quant_iq_table() - - ltpf_resampler_table() - ltpf_interpolate_table() - - print('') diff --git a/system/embdrv/lc3/test/appendix_c.py b/system/embdrv/lc3/test/appendix_c.py deleted file mode 100644 index 66b6e04bac9b4351b79e15c1f7808588c38da33f..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/appendix_c.py +++ /dev/null @@ -1,4083 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# 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. -# - -# -# Appendix C - Intermediate verification of input and output -# - -import numpy as np - - -NBYTES = (32e3 * np.array([ 7.5e-3, 10e-3 ]) / 8).astype(int) - - -### C.3.1.1 PCM Input - -X_PCM_10M = np.array([ - - [ 0, 3212, 6392, 9512, 12539, 15446, 18205, 20788, - 23170, 25328, 27244, 28898, 30272, 31357, 32137, 32609, - 32767, 32609, 32138, 31356, 30272, 28898, 27245, 25330, - 23169, 20787, 18205, 15446, 12539, 9511, 6393, 3212, - 0, -3212, -6393, -9512, -12540, -15446, -18204, -20787, - -23170, -25329, -27245, -28898, -30273, -31356, -32137, -32610, - -32766, -32609, -32137, -31356, -30272, -28898, -27244, -25329, - -23171, -20787, -18204, -15446, -12539, -9511, -6393, -3212, - -1, 3212, 6393, 9512, 12540, 15446, 18204, 20788, - 23169, 25329, 27245, 28898, 30273, 31356, 32137, 32609, - 32767, 32609, 32137, 31356, 30273, 28898, 27245, 25330, - 23170, 20787, 18204, 15446, 12540, 9512, 6393, 3212, - 0, -3212, -6393, -9512, -12539, -15447, -18204, -20787, - -23170, -25330, -27244, -28898, -30272, -31356, -32137, -32609, - -32767, -32609, -32137, -31356, -30273, -28898, -27244, -25330, - -23169, -20787, -18204, -15446, -12540, -9511, -6393, -3212, - 0, 3212, 6392, 9511, 12539, 15446, 18205, 20787, - 23169, 25329, 27245, 28898, 30273, 31356, 32137, 32609, - 32767, 32610, 32137, 31356, 30273, 28898, 27244, 25329, - 23170, 20787, 18204, 15446, 12540, 9511, 6392, 3211 ], - - [ 0, -3211, -6393, -9512, -12539, -15446, -18204, -20788, - -23170, -25329, -27245, -28898, -30273, -31356, -32137, -32609, - -32767, -32609, -32138, -31356, -30273, -28898, -27245, -25329, - -23170, -20788, -18205, -15447, -12539, -9512, -6392, -3211, - 0, 3211, 6393, 9512, 12539, 15446, 18204, 20787, - 23170, 25329, 27244, 28897, 30273, 31356, 32137, 32609, - 32767, 32609, 32137, 31356, 30273, 28897, 27244, 25330, - 23170, 20787, 18205, 15446, 12539, 9512, 6393, 3213, - 0, -3212, -6393, -9512, -12540, -15447, -18205, -20787, - -23169, -25329, -27245, -28897, -30273, -31356, -32138, -32609, - -32767, -32609, -32138, -31356, -30273, -28898, -27244, -25330, - -23170, -20787, -18205, -15446, -12540, -9513, -6392, -3212, - 0, 3212, 6393, 9512, 12540, 15446, 18204, 20788, - 23170, 25329, 27245, 28898, 30272, 31356, 32138, 32609, - 32767, 32609, 32138, 31356, 30273, 28898, 27244, 25330, - 23170, 20787, 18204, 15446, 12540, 9512, 6392, 3211, - 0, -3211, -6393, -9512, -12539, -15446, -18205, -20786, - -23170, -25329, -27245, -28898, -30272, -31356, -32137, -32609, - -32766, -32609, -32137, -31356, -30273, -28898, -27245, -25329, - -23170, -20787, -18204, -15446, -12539, -9511, -6393, -3212 ] - -]) - -X_PCM_7M5 = np.array([ - - [ 0, 3212, 6392, 9512, 12539, 15446, 18205, 20788, - 23170, 25328, 27244, 28898, 30272, 31357, 32137, 32609, - 32767, 32609, 32138, 31356, 30272, 28898, 27245, 25330, - 23169, 20787, 18205, 15446, 12539, 9511, 6393, 3212, - 0, -3212, -6393, -9512, -12540, -15446, -18204, -20787, - -23170, -25329, -27245, -28898, -30273, -31356, -32137, -32610, - -32766, -32609, -32137, -31356, -30272, -28898, -27244, -25329, - -23171, -20787, -18204, -15446, -12539, -9511, -6393, -3212, - -1, 3212, 6393, 9512, 12540, 15446, 18204, 20788, - 23169, 25329, 27245, 28898, 30273, 31356, 32137, 32609, - 32767, 32609, 32137, 31356, 30273, 28898, 27245, 25330, - 23170, 20787, 18204, 15446, 12540, 9512, 6393, 3212, - 0, -3212, -6393, -9512, -12539, -15447, -18204, -20787, - -23170, -25330, -27244, -28898, -30272, -31356, -32137, -32609, - -32767, -32609, -32137, -31356, -30273, -28898, -27244, -25330 ], - - [ -23169, -20787, -18204, -15446, -12540, -9511, -6393, -3212, - 0, 3212, 6392, 9511, 12539, 15446, 18205, 20787, - 23169, 25329, 27245, 28898, 30273, 31356, 32137, 32609, - 32767, 32610, 32137, 31356, 30273, 28898, 27244, 25329, - 23170, 20787, 18204, 15446, 12540, 9511, 6392, 3211, - 0, -3211, -6393, -9512, -12539, -15446, -18204, -20788, - -23170, -25329, -27245, -28898, -30273, -31356, -32137, -32609, - -32767, -32609, -32138, -31356, -30273, -28898, -27245, -25329, - -23170, -20788, -18205, -15447, -12539, -9512, -6392, -3211, - 0, 3211, 6393, 9512, 12539, 15446, 18204, 20787, - 23170, 25329, 27244, 28897, 30273, 31356, 32137, 32609, - 32767, 32609, 32137, 31356, 30273, 28897, 27244, 25330, - 23170, 20787, 18205, 15446, 12539, 9512, 6393, 3213, - 0, -3212, -6393, -9512, -12540, -15447, -18205, -20787, - -23169, -25329, -27245, -28897, -30273, -31356, -32138, -32609 ] - -]) - -X_PCM = [ X_PCM_7M5, X_PCM_10M ] - - -### C.3.1.2 MDCT - -X_10M = np.array([ - - [ -5.8990646e+02, 3.2262618e+04, -2.7619007e+04, 9.5178147e+04, - -1.1418053e+05, -2.2419557e+05, -2.2347007e+03, -1.9867627e+04, - -1.6067159e+04, 5.8154816e+02, -1.5722676e+04, 4.0158688e+03, - -1.0088102e+04, 1.9017417e+03, -4.1954471e+03, -9.7496049e+02, - 4.7235950e+02, -2.7499647e+03, 2.4705648e+03, -2.7529252e+03, - 2.2309610e+03, -1.4814949e+03, 8.0924574e+02, 1.0419403e+02, - -6.3151413e+02, 1.1597939e+03, -1.3202428e+03, 1.3143498e+03, - -1.1022736e+03, 7.2762067e+02, -3.2778511e+02, -1.1134462e+02, - 4.5185190e+02, -7.0065111e+02, 8.1286568e+02, -7.8143265e+02, - 6.4645208e+02, -4.1055413e+02, 1.5009894e+02, 1.1832095e+02, - -3.4137778e+02, 4.8690132e+02, -5.5346349e+02, 5.1921969e+02, - -4.1808273e+02, 2.5332159e+02, -6.4719513e+01, -1.1746306e+02, - 2.7072573e+02, -3.6623733e+02, 4.0439184e+02, -3.7097974e+02, - 2.8704947e+02, -1.6297022e+02, 2.0395888e+01, 1.1218314e+02, - -2.2577273e+02, 2.8951685e+02, -3.1083971e+02, 2.7771234e+02, - -2.0730346e+02, 1.0688285e+02, 6.1320766e+00, -1.0817459e+02, - 1.9320762e+02, -2.3845257e+02, 2.4826403e+02, -2.1609003e+02, - 1.5207388e+02, -6.9546445e+01, -2.4211219e+01, 1.0403883e+02, - -1.6888652e+02, 2.0050394e+02, -2.0326028e+02, 1.7179995e+02, - -1.1399655e+02, 4.4242025e+01, 3.4454794e+01, -1.0009362e+02, - 1.5218958e+02, -1.7342213e+02, 1.7018985e+02, -1.3794243e+02, - 8.6156013e+01, -2.4921223e+01, -4.2552602e+01, 9.5559562e+01, - -1.3740945e+02, 1.5218075e+02, -1.4462762e+02, 1.1451272e+02, - -6.4959967e+01, 1.0627359e+01, 4.7836856e+01, -9.2854453e+01, - 1.2654514e+02, -1.3593370e+02, 1.2459754e+02, -9.4075815e+01, - 4.9816314e+01, 2.1529924e-01, -5.2425581e+01, 9.0995703e+01, - -1.1737069e+02, 1.2263969e+02, -1.0917602e+02, 7.9712422e+01, - -3.5722986e+01, -9.6955535e+00, 5.6602292e+01, -8.9431609e+01, - 1.0953959e+02, -1.1249540e+02, 9.6333120e+01, -6.6446434e+01, - 2.3693799e+01, 1.7708430e+01, -5.8794346e+01, 8.8078076e+01, - -1.0478463e+02, 1.0227969e+02, -8.4957399e+01, 5.5726976e+01, - -1.4768315e+01, -2.3981122e+01, 6.1741642e+01, -8.6508895e+01, - 9.9868691e+01, -9.6459597e+01, 7.6331011e+01, -4.6588689e+01, - 6.4212746e+00, 3.0432190e+01, -6.6116496e+01, 8.6861568e+01, - -9.6320778e+01, 8.9835533e+01, -6.7287784e+01, 3.7477990e+01, - 1.3842189e+00, -3.5731585e+01, 6.8605400e+01, -8.7530923e+01, - 9.3616286e+01, -8.3728496e+01, 6.0230516e+01, -2.9414119e+01, - -7.6609110e+00, 4.2149725e+01, -7.1968501e+01, 8.7743888e+01, - -9.0802890e+01, 7.8923198e+01, -5.4973827e+01, 2.2745574e+01, - 1.5766746e+01, -4.7673661e+01, 7.5778794e+01, -8.9162686e+01 ], - - [ -6.2843560e+03, -1.4627418e+04, 4.9801516e+03, -7.0344966e+04, - 8.5564327e+04, 2.5840606e+05, -3.5208419e+04, 5.4644134e+04, - -1.1212441e+04, 1.8683629e+04, 1.8049757e+03, 7.0569176e+03, - 1.2829514e+03, 4.0930299e+03, 1.1947052e+03, 1.5425662e+03, - 6.0325642e+02, 6.4703789e+02, 1.5715070e+02, 1.0644751e+02, - -7.5883978e+00, -5.2773353e+01, -6.0996565e+01, -8.3409817e+01, - -4.3996776e+01, -3.3763658e+01, -1.2075849e+01, -2.9293481e+00, - 5.2907677e+00, 1.4501256e+01, 1.0866309e+01, 9.1905374e+00, - 3.0606323e+00, 1.6027594e+00, -1.1174900e+00, -5.4280671e+00, - -4.5919914e+00, -4.4199737e+00, -2.0085059e+00, -4.2065884e-01, - 6.3446132e-01, 2.7718649e+00, 3.5654183e+00, 2.6588468e+00, - 1.3730777e+00, 1.3705866e+00, 6.3801955e-02, -1.1191414e+00, - -2.1495458e+00, -2.1211746e+00, -1.1188698e+00, -1.3646427e+00, - -1.2245570e+00, 1.5630676e-01, 1.0243080e+00, 2.0104419e+00, - 1.8985278e+00, 1.2447591e+00, 1.7309919e+00, 9.4234385e-01, - -3.3619810e-01, -1.6030368e+00, -7.1471558e-01, -2.0710920e+00, - -2.9423847e+00, -1.7873501e+00, -8.0633559e-01, -1.6093125e-03, - 7.9415802e-01, 8.7937487e-01, 1.7154607e+00, 1.0383457e+00, - 2.3742697e+00, 9.7376296e-01, 1.5290469e+00, 1.1078186e-01, - -1.3382843e+00, -8.0183060e-01, -1.1937948e+00, -1.6144857e+00, - -2.4688787e+00, 2.7158214e-01, -2.8802354e-01, 1.5704268e-01, - -2.7983134e-01, 7.3794617e-01, 1.0364997e+00, 6.9563470e-01, - 9.9846216e-02, 7.4018952e-01, -1.6599106e-02, -6.7106650e-01, - 9.4477394e-02, -1.1325310e+00, -1.2183007e+00, -1.1326694e+00, - -7.0637699e-01, -1.1096511e+00, 1.4381563e-01, 4.6121573e-01, - 7.9281879e-01, 1.4577665e+00, 1.9515924e+00, 1.5493961e+00, - 7.6923395e-01, 1.0666962e-01, -5.8376568e-01, -1.7768814e-01, - -7.8840041e-01, -8.4273142e-01, -1.1227955e-01, 1.7007988e-01, - -1.2788265e+00, -8.2037634e-01, 2.9027089e-02, 1.1299878e+00, - 1.5466537e+00, 5.7106120e-01, 1.0054291e+00, 7.7078972e-01, - -1.2498850e-01, 1.4337381e-01, -9.1649732e-03, 1.5189923e-01, - -1.8656702e+00, -1.3065376e+00, -1.0474639e+00, -6.1982978e-01, - -4.0826276e-01, -2.5749212e-01, 7.5196564e-01, 5.9204803e-01, - 3.8971675e-01, 4.7356386e-01, 9.6497659e-01, 1.0654369e+00, - 1.0179577e-01, -8.7312829e-01, -1.0535862e+00, -5.5302243e-01, - -1.4681184e+00, -9.4220508e-01, -7.2255455e-01, -5.3132915e-01, - -1.4926868e-01, 3.6245889e-01, 1.6544183e-01, 7.2654545e-01, - -7.6464228e-02, 1.9158155e-02, 8.5964508e-01, 5.0113123e-02, - -3.5523428e-02, -1.0719814e+00, -1.0268355e+00, -3.9656991e-01, - -3.7302065e-01, -7.6860159e-01, -3.9431418e-01, -8.4906570e-02 ] - -]) - -X_7M5 = np.array([ - - [ -2.7808220e+04, 3.1171944e+04, -1.0484449e+05, -1.6109747e+05, - 7.1020534e+03, 6.1529776e+04, -4.3352596e+03, 1.6872730e+03, - 8.3021669e+03, -8.0904023e+03, 2.8986710e+03, 1.6300470e+03, - -3.9442485e+03, 3.3369609e+03, -7.5314157e+02, -1.5665608e+03, - 2.3627282e+03, -1.5968140e+03, -2.9454372e+01, 1.3170795e+03, - -1.5221502e+03, 7.5501127e+02, 3.4796318e+02, -1.0725998e+03, - 9.9368163e+02, -2.9346750e+02, -4.7457374e+02, 8.5309969e+02, - -6.3326698e+02, 2.2874568e+01, 5.0703180e+02, -6.5956792e+02, - 3.7615149e+02, 1.3645752e+02, -4.8970087e+02, 4.9257049e+02, - -1.8802536e+02, -2.2788339e+02, 4.4305145e+02, -3.4924777e+02, - 5.0697164e+01, 2.7264213e+02, -3.8309643e+02, 2.2685761e+02, - 4.8724694e+01, -2.8629820e+02, 3.1493179e+02, -1.2493286e+02, - -1.1855917e+02, 2.7825778e+02, -2.4421869e+02, 3.9752437e+01, - 1.6382158e+02, -2.5263703e+02, 1.7444462e+02, 2.6833647e+01, - -1.8770774e+02, 2.1765469e+02, -1.1027623e+02, -7.8965164e+01, - 1.9573957e+02, -1.7599945e+02, 4.9679803e+01, 1.1484006e+02, - -1.8898112e+02, 1.3092016e+02, 7.2222470e-01, -1.3789235e+02, - 1.7321190e+02, -8.5147249e+01, -4.3896934e+01, 1.4839226e+02, - -1.4915199e+02, 4.1079567e+01, 7.7806126e+01, -1.4826509e+02, - 1.1954125e+02, -9.5155767e-01, -1.0279192e+02, 1.3980505e+02, - -8.5889140e+01, -3.4465766e+01, 1.1923625e+02, -1.2267683e+02, - 5.1023135e+01, 6.4082513e+01, -1.2613323e+02, 9.9909559e+01, - -1.6509945e+01, -8.6980952e+01, 1.2384580e+02, -7.3451876e+01, - -1.5354773e+01, 1.0245575e+02, -1.1445423e+02, 4.5501562e+01, - 4.3867941e+01, -1.1121715e+02, 1.0028146e+02, -1.5168901e+01, - -6.9443433e+01, 1.1170827e+02, -7.9410276e+01, -1.4798645e+01, - 8.7563510e+01, -1.0510000e+02, 5.5384253e+01, 4.1531846e+01, - -1.0069765e+02, 9.2428209e+01, -2.7848167e+01, -6.4462037e+01, - 1.0628096e+02, -7.4978815e+01, 1.6316106e-01, 8.3599643e+01, - -1.0561445e+02, 5.2787841e+01, 2.7101412e+01, -9.7922081e+01 ], - - [ 3.8121925e+03, -2.2031854e+04, 6.2134301e+04, -2.5584480e+05, - -4.0289726e+04, -1.1591648e+04, 9.9946415e+03, -5.6931570e+03, - -1.4027155e+03, -8.4816729e+01, -1.6692931e+02, 3.7467791e+01, - 1.5876357e+02, 1.0909061e+02, -1.2446699e+01, -7.8016012e+01, - -5.9665224e+01, 1.7150538e+01, 4.1435247e+01, 1.4446691e+01, - -3.8364171e+00, -9.0141422e+00, -1.1905776e+01, -1.1758083e+01, - 2.4695821e+00, 1.6421675e+01, 1.7958775e+01, -1.0112627e+00, - -1.7276148e+01, -1.4579197e+01, -3.0796621e-01, 3.4903800e+00, - 8.9247274e+00, 1.0542251e+01, 5.1085251e+00, -6.3561781e+00, - -1.5196238e+01, -8.5814612e+00, 5.9801475e+00, 8.8788786e+00, - 6.6693886e+00, 4.0520010e+00, -2.5648927e+00, -7.3376816e+00, - -9.4020988e+00, -3.7886737e+00, 9.8324354e+00, 1.0369412e+01, - 2.7236309e+00, -1.1806094e+00, -5.4027659e+00, -7.1662503e+00, - -5.2723002e+00, 2.2261048e+00, 1.0161892e+01, 7.6651861e+00, - -2.2518007e+00, -5.1245529e+00, -5.3667831e+00, -4.6532034e+00, - -9.0748070e-01, 2.8558608e+00, 8.7396007e+00, 5.8069435e+00, - -4.9824625e+00, -6.3131200e+00, -4.2366242e+00, -1.2878986e+00, - 1.9593460e+00, 4.4854081e+00, 6.1847341e+00, 1.9350643e+00, - -6.7952522e+00, -7.6836416e+00, -1.1341833e+00, 8.9242434e-01, - 4.4208241e+00, 4.7103946e+00, 3.3250393e+00, -5.6553445e-01, - -6.6710206e+00, -5.9125999e+00, 8.2386239e-01, 4.8587135e+00, - 4.1530321e+00, 3.6100791e+00, 3.4896727e-01, -3.5268730e+00, - -6.6259985e+00, -4.6374540e+00, 4.0614812e+00, 4.8600515e+00, - 3.4816753e+00, 7.5221655e-01, -1.5176717e+00, -3.5752094e+00, - -5.3492120e+00, -1.8813288e+00, 4.5633890e+00, 5.8660550e+00, - 2.6127035e+00, -1.4095531e+00, -3.2585158e+00, -4.0492745e+00, - -3.0513819e+00, 1.0864826e+00, 6.1166169e+00, 5.3791204e+00, - -2.6627677e-01, -3.3401114e+00, -4.3742918e+00, -3.7773803e+00, - -3.2386710e-01, 2.3283535e+00, 6.5557289e+00, 4.4470718e+00, - -2.5793855e+00, -4.6626375e+00, -3.9104033e+00, -1.1065239e+00 ] - -]) - -X = [ X_7M5, X_10M ] - - -### C.3.1.3 12.8 kHz resampler - -X_TILDE_12K8D_10M = np.array([ - - [ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, -2.7136560e+00, -2.6569981e+00, -8.2098309e+00, - 2.5435023e+00, -1.2692479e+01, 3.2383771e+00, -4.3038498e+01, - 1.6475668e+02, 3.9002834e+03, 7.6897871e+03, 1.1168030e+04, - 1.4388464e+04, 1.7228860e+04, 1.9693442e+04, 2.1734211e+04, - 2.3341435e+04, 2.4458687e+04, 2.5091505e+04, 2.5237788e+04, - 2.4898746e+04, 2.4056493e+04, 2.2750447e+04, 2.1002836e+04, - 1.8837538e+04, 1.6271528e+04, 1.3371876e+04, 1.0177959e+04, - 6.7345474e+03, 3.0859120e+03, -6.8926189e+02, -4.5387403e+03, - -8.4127977e+03, -1.2248756e+04, -1.5972309e+04, -1.9535642e+04, - -2.2893718e+04, -2.5977602e+04, -2.8736936e+04, -3.1140674e+04, - -3.3157374e+04, -3.4729421e+04, -3.5844044e+04, -3.6489767e+04, - -3.6657691e+04, -3.6317413e+04, -3.5493490e+04, -3.4198956e+04, - -3.2451848e+04, -3.0250170e+04, -2.7655246e+04, -2.4700058e+04, - -2.1422013e+04, -1.7854871e+04, -1.4073383e+04, -1.0130011e+04, - -6.0696279e+03, -1.9523115e+03, 2.1432690e+03, 6.1682081e+03, - 1.0075311e+04, 1.3793150e+04, 1.7261182e+04, 2.0439154e+04, - 2.3290746e+04, 2.5752435e+04, 2.7792879e+04, 2.9395551e+04, - 3.0539419e+04, 3.1182642e+04, 3.1334658e+04, 3.1000121e+04, - 3.0185153e+04, 2.8876238e+04, 2.7121382e+04, 2.4947537e+04, - 2.2382237e+04, 1.9447889e+04, 1.6216333e+04, 1.2730773e+04, - 9.0366635e+03, 5.1844000e+03, 1.2542494e+03, -2.7040631e+03, - -6.6402694e+03, -1.0487968e+04, -1.4176374e+04, -1.7659977e+04, - -2.0896015e+04, -2.3817756e+04, -2.6379477e+04, -2.8555427e+04, - -3.0316787e+04, -3.1610147e+04, -3.2431837e+04, -3.2774372e+04, - -3.2634728e+04, -3.1986767e+04, -3.0864057e+04, -2.9283835e+04, - -2.7267471e+04, -2.4822384e+04, -2.2011114e+04, -1.8874753e+04, - -1.5449273e+04 ], - - [ -1.5449273e+04, -1.1776342e+04, -7.9350741e+03, -3.9753420e+03, - 5.6212790e+01, 4.0948091e+03, 8.0660721e+03, 1.1920829e+04, - 1.5610547e+04, 1.9067628e+04, 2.2236206e+04, 2.5079838e+04, - 2.7562773e+04, 2.9625190e+04, 3.1247708e+04, 3.2411870e+04, - 3.3105731e+04, 3.3290869e+04, 3.2986189e+04, 3.2200486e+04, - 3.0944512e+04, 2.9210715e+04, 2.7055339e+04, 2.4507368e+04, - 2.1598895e+04, 1.8359789e+04, 1.4864140e+04, 1.1157303e+04, - 7.2876208e+03, 3.3081055e+03, -7.0156289e+02, -4.6891569e+03, - -8.6058356e+03, -1.2384088e+04, -1.5958973e+04, -1.9284607e+04, - -2.2323146e+04, -2.5008095e+04, -2.7303120e+04, -2.9181339e+04, - -3.0623681e+04, -3.1579731e+04, -3.2052556e+04, -3.2039965e+04, - -3.1544863e+04, -3.0546815e+04, -2.9086911e+04, -2.7186800e+04, - -2.4871192e+04, -2.2155336e+04, -1.9106913e+04, -1.5768099e+04, - -1.2180718e+04, -8.3886907e+03, -4.4727275e+03, -4.8397983e+02, - 3.5287168e+03, 7.5007937e+03, 1.1356312e+04, 1.5052293e+04, - 1.8540697e+04, 2.1752202e+04, 2.4638955e+04, 2.7166972e+04, - 2.9306556e+04, 3.0998943e+04, 3.2231603e+04, 3.2995051e+04, - 3.3278595e+04, 3.3050597e+04, 3.2338337e+04, 3.1153755e+04, - 2.9512841e+04, 2.7417674e+04, 2.4925451e+04, 2.2071406e+04, - 1.8894430e+04, 1.5423055e+04, 1.1739349e+04, 7.8892265e+03, - 3.9209702e+03, -1.0578292e+02, -4.1130091e+03, -8.0523247e+03, - -1.1874762e+04, -1.5509335e+04, -1.8896353e+04, -2.1995901e+04, - -2.4770068e+04, -2.7154380e+04, -2.9121926e+04, -3.0652080e+04, - -3.1724909e+04, -3.2299883e+04, -3.2385523e+04, -3.1985436e+04, - -3.1105919e+04, -2.9735628e+04, -2.7920239e+04, -2.5686848e+04, - -2.3064137e+04, -2.0073280e+04, -1.6788431e+04, -1.3249779e+04, - -9.5054623e+03, -5.6021829e+03, -1.6246392e+03, 2.3816986e+03, - 6.3633660e+03, 1.0254738e+04, 1.3986117e+04, 1.7511038e+04, - 2.0787917e+04, 2.3746769e+04, 2.6347708e+04, 2.8559387e+04, - 3.0354770e+04, 3.1683451e+04, 3.2536757e+04, 3.2910967e+04, - 3.2802210e+04, 3.2182725e+04, 3.1087832e+04, 2.9535420e+04, - 2.7544339e+04, 2.5123821e+04, 2.2336463e+04, 1.9222835e+04, - 1.5819986e+04 ] - -]) - -X_TILDE_12K8D_7M5 = np.array([ - - [ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, -2.7136560e+00, -2.6569981e+00, -8.2098309e+00, - 2.5435023e+00, -1.2692479e+01, 3.2383771e+00, -4.3038498e+01, - 1.6475668e+02, 3.9002834e+03, 7.6897871e+03, 1.1168030e+04, - 1.4388464e+04, 1.7228860e+04, 1.9693442e+04, 2.1734211e+04, - 2.3341435e+04, 2.4458687e+04, 2.5091505e+04, 2.5237788e+04, - 2.4898746e+04, 2.4056493e+04, 2.2750447e+04, 2.1002836e+04, - 1.8837538e+04, 1.6271528e+04, 1.3371876e+04, 1.0177959e+04, - 6.7345474e+03, 3.0859120e+03, -6.8926189e+02, -4.5387403e+03, - -8.4127977e+03, -1.2248756e+04, -1.5972309e+04, -1.9535642e+04, - -2.2893718e+04, -2.5977602e+04, -2.8736936e+04, -3.1140674e+04, - -3.3157374e+04, -3.4729421e+04, -3.5844044e+04, -3.6489767e+04, - -3.6657691e+04, -3.6317413e+04, -3.5493490e+04, -3.4198956e+04, - -3.2451848e+04, -3.0250170e+04, -2.7655246e+04, -2.4700058e+04, - -2.1422013e+04 ], - - [ -2.1422013e+04, -1.7854871e+04, -1.4073383e+04, -1.0130011e+04, - -6.0696279e+03, -1.9523115e+03, 2.1432690e+03, 6.1682081e+03, - 1.0075311e+04, 1.3793150e+04, 1.7261182e+04, 2.0439154e+04, - 2.3290746e+04, 2.5752435e+04, 2.7792879e+04, 2.9395551e+04, - 3.0539419e+04, 3.1182642e+04, 3.1334658e+04, 3.1000121e+04, - 3.0185153e+04, 2.8876238e+04, 2.7121382e+04, 2.4947537e+04, - 2.2382237e+04, 1.9447889e+04, 1.6216333e+04, 1.2730773e+04, - 9.0366635e+03, 5.1844000e+03, 1.2542494e+03, -2.7040631e+03, - -6.6402694e+03, -1.0487968e+04, -1.4176374e+04, -1.7659977e+04, - -2.0896015e+04, -2.3817756e+04, -2.6379477e+04, -2.8555427e+04, - -3.0316787e+04, -3.1610147e+04, -3.2431837e+04, -3.2774372e+04, - -3.2634728e+04, -3.1986767e+04, -3.0864057e+04, -2.9283835e+04, - -2.7267471e+04, -2.4822384e+04, -2.2011114e+04, -1.8874753e+04, - -1.5449273e+04, -1.1776342e+04, -7.9350741e+03, -3.9753420e+03, - 5.6212790e+01, 4.0948091e+03, 8.0660721e+03, 1.1920829e+04, - 1.5610547e+04, 1.9067628e+04, 2.2236206e+04, 2.5079838e+04, - 2.7562773e+04, 2.9625190e+04, 3.1247708e+04, 3.2411870e+04, - 3.3105731e+04, 3.3290869e+04, 3.2986189e+04, 3.2200486e+04, - 3.0944512e+04, 2.9210715e+04, 2.7055339e+04, 2.4507368e+04, - 2.1598895e+04, 1.8359789e+04, 1.4864140e+04, 1.1157303e+04, - 7.2876208e+03, 3.3081055e+03, -7.0156289e+02, -4.6891569e+03, - -8.6058356e+03, -1.2384088e+04, -1.5958973e+04, -1.9284607e+04, - -2.2323146e+04, -2.5008095e+04, -2.7303120e+04, -2.9181339e+04, - -3.0623681e+04, -3.1579731e+04, -3.2052556e+04, -3.2039965e+04, - -3.1544863e+04 ] - -]) - -X_TILDE_12K8D = [ X_TILDE_12K8D_7M5, X_TILDE_12K8D_10M ] - - -### C.3.1.4 Pitch analysis - -T_CURR_10M = np.array([ 25, 26 ]) -T_CURR_7M5 = np.array([ 22, 25 ]) -T_CURR = [ T_CURR_7M5, T_CURR_10M ] - -NORMCORR_10M = np.array([ 0.677220, 0.992748 ]) -NORMCORR_7M5 = np.array([ 0.473429, 0.952099 ]) -NORMCORR = [ NORMCORR_7M5, NORMCORR_10M ] - -T1_10M = np.array([ 25, 26 ]) -T1_7M5 = np.array([ 22, 25 ]) -T1 = [ T1_7M5, T1_10M ] - -T2_10M = np.array([ 21, 26 ]) -T2_7M5 = np.array([ 21, 25 ]) -T2 = [ T2_7M5, T2_10M ] - -NORMCORR1_10M = np.array([ 0.677220, 0.992748 ]) -NORMCORR1_7M5 = np.array([ 0.473429, 0.952099 ]) -NORMCORR1 = [ NORMCORR1_7M5, NORMCORR1_10M ] - -NORMCORR2_10M = np.array([ 0.276293, 0.992748 ]) -NORMCORR2_7M5 = np.array([ 0.000000, 0.952099 ]) -NORMCORR2 = [ NORMCORR2_7M5, NORMCORR2_10M ] - - -### C.3.1.5 LTPF encoder - -PITCH_PRESENT_10M = np.array([ 1, 1 ]) -PITCH_PRESENT_7M5 = np.array([ 0, 1 ]) -PITCH_PRESENT = [ PITCH_PRESENT_7M5, PITCH_PRESENT_10M ] - -PITCH_INDEX_10M = np.array([ 76, 76 ]) -PITCH_INDEX_7M5 = np.array([ 0, 72 ]) -PITCH_INDEX = [ PITCH_INDEX_7M5, PITCH_INDEX_10M ] - -LTPF_ACTIVE_10M = np.array([ 0, 0 ]) -LTPF_ACTIVE_7M5 = np.array([ 0, 0 ]) -LTPF_ACTIVE = [ LTPF_ACTIVE_7M5, LTPF_ACTIVE_10M ] - -NC_LTPF_10M = np.array([ 0.690317, 0.998707 ]) -NC_LTPF_7M5 = np.array([ 0.000000, 0.963121 ]) -NC_LTPF = [ NC_LTPF_7M5, NC_LTPF_10M ] - - -### C.3.1.6 Per-band energy - -E_B_10M = np.array([ - - [ 3.4798963e+05, 1.0408765e+09, 7.6280953e+08, 9.0588797e+09, - 1.3037195e+10, 5.0263652e+10, 4.9938874e+06, 3.9472260e+08, - 2.5815358e+08, 3.3819826e+05, 2.4720253e+08, 1.6127203e+07, - 1.0176981e+08, 3.6166214e+06, 1.7601776e+07, 9.5054796e+05, - 2.2312350e+05, 7.5623058e+06, 6.1036902e+06, 7.5785971e+06, - 4.9771870e+06, 2.1948272e+06, 6.5487867e+05, 1.0856397e+04, - 3.9881009e+05, 1.3451218e+06, 1.7430411e+06, 1.7275154e+06, - 8.7221944e+05, 5.9920352e+04, 3.4754106e+05, 6.3569381e+05, - 2.9322749e+05, 1.8264770e+04, 1.7680584e+05, 2.8795546e+05, - 1.1948250e+05, 8.9930924e+03, 1.0371110e+05, 1.5057936e+05, - 3.6457561e+04, 4.9126130e+04, 7.2240065e+04, 7.7210962e+03, - 5.1941280e+04, 2.4886024e+04, 1.3310972e+04, 3.7010599e+04, - 6.5396090e+03, 2.5307401e+04, 4.7465699e+03, 1.9017662e+04, - 3.8107631e+03, 1.2269623e+04, 7.9690160e+03, 4.5694858e+03, - 9.2694695e+03, 4.6138651e+03, 4.2316029e+03, 5.8000267e+03, - 5.7863671e+03, 4.4037279e+03, 3.9216878e+03, 3.7117332e+03 ], - - [ 3.9493130e+07, 2.1396136e+08, 2.4801910e+07, 4.9484143e+09, - 7.3212541e+09, 6.6773691e+10, 1.2396327e+09, 2.9859813e+09, - 1.2571883e+08, 3.4907798e+08, 3.2579374e+06, 4.9800086e+07, - 1.6459643e+06, 1.6752894e+07, 1.4273206e+06, 2.3795106e+06, - 3.6391831e+05, 4.1865804e+05, 2.4696343e+04, 1.1331072e+04, - 5.7583781e+01, 2.7850268e+03, 3.7205810e+03, 6.9571975e+03, - 1.9357163e+03, 1.1399846e+03, 1.4582614e+02, 8.5810802e+00, - 1.1913932e+02, 1.0127132e+02, 5.9681539e+00, 1.5356348e+01, - 2.0311276e+01, 2.1055250e+00, 4.0428882e+00, 9.8908370e+00, - 1.8819250e+00, 6.2827408e-01, 4.5599643e+00, 1.5570596e+00, - 8.5772617e-01, 3.0652366e+00, 1.3324581e+00, 2.4566558e+00, - 4.1674750e+00, 4.6799657e-01, 3.2193746e+00, 1.0994905e+00, - 1.6164118e+00, 1.5691847e+00, 5.4527735e-01, 2.5211389e-01, - 1.0146872e+00, 5.1845169e-01, 1.7875047e+00, 3.4334672e-01, - 7.2301137e-01, 8.6777500e-01, 1.0547766e+00, 2.8083700e-01, - 6.9555959e-01, 6.1528702e-01, 1.8631657e-01, 4.6476980e-01 ] - -]) - -E_B_7M5 = np.array([ - - [ 7.7329708e+08, 9.7169006e+08, 1.0992368e+10, 2.5952396e+10, - 5.0439162e+07, 3.7859133e+09, 1.8794475e+07, 2.8468901e+06, - 6.8925976e+07, 6.5454609e+07, 8.4022938e+06, 2.6570531e+06, - 1.5557097e+07, 1.1135308e+07, 5.6722222e+05, 2.4541127e+06, - 5.5824847e+06, 2.5498151e+06, 8.6756001e+02, 1.7346984e+06, - 2.3169412e+06, 5.7004201e+05, 1.2107837e+05, 1.1504704e+06, - 9.8740319e+05, 8.6123175e+04, 2.2522023e+05, 7.2777908e+05, - 4.0102706e+05, 5.2324588e+02, 2.5708125e+05, 4.3502984e+05, - 1.4148995e+05, 1.8620654e+04, 2.4121631e+05, 4.3642188e+04, - 1.5913430e+05, 3.8451966e+04, 9.9113627e+04, 4.2170377e+04, - 5.7395127e+04, 4.5741834e+04, 3.0611513e+04, 4.5331490e+04, - 1.5575486e+04, 4.1303881e+04, 9.1981721e+03, 3.4644893e+04, - 1.7123395e+04, 1.2051636e+04, 1.3059786e+04, 1.5318037e+04, - 1.4108814e+04, 1.0037512e+04, 7.5940392e+03, 7.2531779e+03, - 8.4324439e+03, 7.8664771e+03, 7.3659535e+03, 6.8968988e+03, - 6.3095928e+03, 5.8688253e+03, 4.3696732e+03, 6.2506180e+03 ], - - [ 1.4532812e+07, 4.8540259e+08, 3.8606713e+09, 6.5456561e+10, - 1.6232620e+09, 1.3436631e+08, 9.9892859e+07, 3.2412037e+07, - 1.9676109e+06, 7.1938775e+03, 2.7865394e+04, 1.4038353e+03, - 2.5205872e+04, 1.1900762e+04, 1.5492031e+02, 6.0864981e+03, - 3.5599390e+03, 2.9414095e+02, 1.7168797e+03, 2.0870689e+02, - 1.4718096e+01, 8.1254760e+01, 1.4174751e+02, 1.3825251e+02, - 6.0988360e+00, 2.6967143e+02, 3.2251759e+02, 1.0226523e+00, - 2.9846530e+02, 2.1255299e+02, 9.4843183e-02, 1.2182752e+01, - 7.9650760e+01, 1.1113906e+02, 3.3249014e+01, 1.5228356e+02, - 5.7298325e+01, 3.0449728e+01, 3.0210123e+01, 5.1376755e+01, - 1.0210074e+02, 4.4060019e+00, 4.0272511e+01, 1.6376346e+01, - 8.1009561e+01, 1.5665824e+01, 2.5227331e+01, 4.4897310e+00, - 4.4975382e+01, 1.9821051e+01, 2.0736286e+01, 3.6319425e+01, - 7.2088263e+00, 1.1187844e+01, 2.6713368e+01, 1.7962481e+01, - 1.9492612e+01, 1.3200905e+01, 1.1809729e+01, 1.6012045e+01, - 9.3764812e+00, 1.9393796e+01, 1.6381346e+01, 1.2937103e+01 ] - -]) - -E_B = [ E_B_7M5, E_B_10M ] - - -### C.3.1.7 Bandwidth detector - -P_BW_10M = np.array([ 1, 1 ]) -P_BW_7M5 = np.array([ 1, 1 ]) -P_BW = [ P_BW_7M5, P_BW_10M ] - - -### C.3.1.8 SNS gains - -SCF_10M = np.array([ - - [ 3.5009846e+00, 4.4942639e+00, 2.3071956e+00, 1.2022551e+00, - 6.2362294e-01, 9.4722039e-03, -3.2828840e-02, -3.3840570e-01, - -7.2946152e-01, -1.0018093e+00, -1.2127892e+00, -1.4678244e+00, - -1.6640459e+00, -1.8392946e+00, -1.9307510e+00, -1.9205837e+00 ], - - [ 3.7432369e+00, 5.6927098e+00, 3.2662471e+00, 1.4474935e+00, - -4.4505556e-01, -1.2458756e+00, -1.2458756e+00, -1.2458756e+00, - -1.2458756e+00, -1.2458756e+00, -1.2458756e+00, -1.2458756e+00, - -1.2458756e+00, -1.2458756e+00, -1.2458756e+00, -1.2458756e+00 ], - - [ -1.5649514e+00, -1.1656014e+00, -1.5624815e+00, -1.1411195e+00, - -7.4976482e-01, -2.4654068e-01, 1.3534391e-01, -1.1293867e-01, - -1.6932960e-01, 5.7623565e-02, 6.7159547e-01, 9.3859612e-01, - 1.0824257e+00, 1.2057632e+00, 1.4053510e+00, 1.2160286e+00 ] - -]) - -SCF_7M5 = np.array([ - - [ 4.4048340e+00, 3.5389298e+00, 1.5267043e+00, 7.9358598e-01, - 3.0615231e-01, -3.2867352e-02, -2.7847443e-01, -4.6371063e-01, - -6.8557046e-01, -8.7944953e-01, -1.0976367e+00, -1.2286102e+00, - -1.3879732e+00, -1.5027094e+00, -1.5071962e+00, -1.5060084e+00 ], - - [ 5.4182466e+00, 4.3372862e+00, 3.1487482e-01, -7.7464674e-01, - -7.7464674e-01, -7.7464674e-01, -7.7464674e-01, -7.7464674e-01, - -7.7464674e-01, -7.7464674e-01, -7.7464674e-01, -7.7464674e-01, - -7.7464674e-01, -7.7464674e-01, -7.7464674e-01, -7.7464674e-01 ] - -]) - -SCF = [ SCF_7M5, SCF_10M ] - - -### C.3.1.9 SNS quantization: stage 2 - -T2ROT_10M = np.array([ - - [ -3.8060310e-01, 2.8077898e-01, -6.7415911e-01, -4.4050504e-01, - -5.0680535e-02, 1.2946234e+00, -3.1905543e-02, -8.3983883e-01, - -3.0573474e-02, -1.7180800e-01, -3.1795511e-01, -5.6801435e-01, - -3.4459445e-01, -5.3266246e-02, -6.2922325e-02, -2.0856957e-01 ], - - [ -6.9862836e-01, 7.4316023e-01, 1.6797292e-01, 1.7318569e+00, - 2.0540381e-01, -3.3073095e-01, -5.2816094e-01, -1.0380535e+00, - -6.4017558e-01, -3.8876809e-01, -3.3239735e-01, -4.8437565e-01, - -4.2394514e-01, -3.6228481e-01, -2.3217161e-01, -2.2684893e-01 ], - - [ -1.0349648e+00, -8.7888573e-01, 1.9107834e-01, -9.0835649e-01, - 7.6273219e-01, 5.4107875e-01, 7.5161773e-01, -7.8846551e-02, - 1.4299991e-01, -1.5545871e-01, -6.6321266e-02, -7.2264622e-02, - -1.3018946e-01, -2.4094909e-01, -1.6785267e-01, 7.1244633e-02 ] - -]) - -T2ROT_7M5 = np.array([ - - [ 5.5508969e-01, 3.8471081e-01, 4.0948426e-02, -7.5029612e-01, - -9.7881975e-01, 4.9702346e-01, -8.2168015e-02, -4.3546804e-01, - 1.8914981e-01, -1.9792621e-01, -2.4794744e-01, -2.9000112e-01, - -2.2928306e-01, -8.1890752e-02, -1.0731157e-01, -2.2349961e-01 ], - - [ -1.9137509e-01, -1.3751444e-01, 4.4707625e-01, 4.0374158e-01, - 1.6628366e+00, 3.1663673e-01, 5.0786462e-01, 5.0214496e-01, - -2.8554914e-01, -6.2625497e-01, -4.7743904e-01, -5.5803079e-01, - -4.8903072e-01, -4.6108945e-01, -2.3248007e-01, -1.2652277e-01 ], - -]) - -T2ROT = [ T2ROT_7M5, T2ROT_10M ] - -SNS_Y0_10M = np.array([ - [ -1, 1,-2,-1, 0, 3, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0 ], - [ -1, 1, 0, 3, 0, 0,-1,-2,-1,-1, 0,-1, 0, 0, 0, 0 ], - [ -2,-2, 0,-2, 2, 1, 1, 0, 0, 0, 0, 0, 0,-1, 0, 0 ] -]) - -SNS_Y1_10M = np.array([ - [ -1, 1,-2,-1, 0, 3, 0,-2, 0, 0 ], - [ -1, 1, 0, 3, 0, 0,-1,-2,-1,-1 ], - [ -2,-2, 0,-2, 2, 1, 1, 0, 0, 0 ] -]) - -SNS_Y2_10M = np.array([ - [ -1, 0,-1,-1, 0, 2, 0,-1, 0, 0, 0,-1,-1, 0, 0, 0 ], - [ -1, 1, 0, 2, 0, 0,-1,-1,-1, 0, 0,-1, 0, 0, 0, 0 ], - [ -2,-1, 0,-2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] -]) - -SNS_Y3_10M = np.array([ - [ 0, 0,-1,-1, 0, 2, 0,-1, 0, 0, 0,-1, 0, 0, 0, 0 ], - [ -1, 1, 0, 2, 0, 0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0 ], - [ -1,-1, 0,-1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] -]) - -SNS_Y0_7M5 = np.array([ - [ 1, 1, 0,-2,-3, 1, 0,-1, 0,-1, 0,-1, 0, 0, 0, 0 ], - [ 0, 0, 1, 1, 3, 1, 1, 1,-1,-1, 0,-1, 0, 0, 0, 0 ] -]) - -SNS_Y1_7M5 = np.array([ - [ 1, 1, 0,-2,-3, 1, 0,-1, 0,-1 ], - [ 0, 0, 1, 1, 3, 1, 1, 1,-1,-1 ] -]) - -SNS_Y2_7M5 = np.array([ - [ 1, 1, 0,-1,-2, 1, 0,-1, 0, 0, 0,-1, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 2, 0, 1, 1, 0,-1,-1,-1,-1, 0, 0, 0 ] -]) - -SNS_Y3_7M5 = np.array([ - [ 1, 0, 0,-1,-2, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 2, 0, 1, 1, 0,-1, 0,-1, 0, 0, 0, 0 ] -]) - -SNS_Y0 = [ SNS_Y0_7M5, SNS_Y0_10M ] -SNS_Y1 = [ SNS_Y1_7M5, SNS_Y1_10M ] -SNS_Y2 = [ SNS_Y2_7M5, SNS_Y2_10M ] -SNS_Y3 = [ SNS_Y3_7M5, SNS_Y3_10M ] - -SNS_XQ0_10M = np.array([ - - [ -2.1821789e-01, 2.1821789e-01, -4.3643578e-01, -2.1821789e-01, - -0.0000000e+00, 6.5465367e-01, -0.0000000e+00, -4.3643578e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -2.1821789e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -2.2941573e-01, 2.2941573e-01, 0.0000000e+00, 6.8824720e-01, - 0.0000000e+00, -0.0000000e+00, -2.2941573e-01, -4.5883147e-01, - -2.2941573e-01, -2.2941573e-01, -0.0000000e+00, -2.2941573e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -4.5883147e-01, -4.5883147e-01, 0.0000000e+00, -4.5883147e-01, - 4.5883147e-01, 2.2941573e-01, 2.2941573e-01, -0.0000000e+00, - 0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -2.2941573e-01, -0.0000000e+00, 0.0000000e+00 ] - -]) - -SNS_XQ1_10M = np.array([ - - [ -2.2360680e-01, 2.2360680e-01, -4.4721360e-01, -2.2360680e-01, - -0.0000000e+00, 6.7082039e-01, -0.0000000e+00, -4.4721360e-01, - -0.0000000e+00, -0.0000000e+00 ], - - [ -2.3570226e-01, 2.3570226e-01, 0.0000000e+00, 7.0710678e-01, - 0.0000000e+00, -0.0000000e+00, -2.3570226e-01, -4.7140452e-01, - -2.3570226e-01, -2.3570226e-01 ], - - [ -4.7140452e-01, -4.7140452e-01, 0.0000000e+00, -4.7140452e-01, - 4.7140452e-01, 2.3570226e-01, 2.3570226e-01, -0.0000000e+00, - 0.0000000e+00, -0.0000000e+00 ], - -]) - -SNS_XQ2_10M = np.array([ - - [ -3.1622777e-01, 0.0000000e+00, -3.1622777e-01, -3.1622777e-01, - -0.0000000e+00, 6.3245553e-01, -0.0000000e+00, -3.1622777e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -3.1622777e-01, - -3.1622777e-01, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -3.1622777e-01, 3.1622777e-01, 0.0000000e+00, 6.3245553e-01, - 0.0000000e+00, -0.0000000e+00, -3.1622777e-01, -3.1622777e-01, - -3.1622777e-01, -0.0000000e+00, -0.0000000e+00, -3.1622777e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -5.7735027e-01, -2.8867513e-01, 0.0000000e+00, -5.7735027e-01, - 2.8867513e-01, 2.8867513e-01, 2.8867513e-01, -0.0000000e+00, - 0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, 0.0000000e+00 ] - -]) - -SNS_XQ3_10M = np.array([ - - [ -0.0000000e+00, 0.0000000e+00, -3.5355339e-01, -3.5355339e-01, - -0.0000000e+00, 7.0710678e-01, -0.0000000e+00, -3.5355339e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -3.5355339e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -3.5355339e-01, 3.5355339e-01, 0.0000000e+00, 7.0710678e-01, - 0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -3.5355339e-01, - -3.5355339e-01, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -4.0824829e-01, -4.0824829e-01, 0.0000000e+00, -4.0824829e-01, - 4.0824829e-01, 4.0824829e-01, 4.0824829e-01, -0.0000000e+00, - 0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, 0.0000000e+00 ] - -]) - -SNS_XQ0_7M5 = np.array([ - - [ 2.2941573e-01, 2.2941573e-01, 0.0000000e+00, -4.5883147e-01, - -6.8824720e-01, 2.2941573e-01, -0.0000000e+00, -2.2941573e-01, - 0.0000000e+00, -2.2941573e-01, -0.0000000e+00, -2.2941573e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -0.0000000e+00, -0.0000000e+00, 2.4253563e-01, 2.4253563e-01, - 7.2760688e-01, 2.4253563e-01, 2.4253563e-01, 2.4253563e-01, - -2.4253563e-01, -2.4253563e-01, -0.0000000e+00, -2.4253563e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ] - -]) - -SNS_XQ1_7M5 = np.array([ - - [ 2.3570226e-01, 2.3570226e-01, 0.0000000e+00, -4.7140452e-01, - -7.0710678e-01, 2.3570226e-01, -0.0000000e+00, -2.3570226e-01, - 0.0000000e+00, -2.3570226e-01 ], - - [ -0.0000000e+00, -0.0000000e+00, 2.5000000e-01, 2.5000000e-01, - 7.5000000e-01, 2.5000000e-01, 2.5000000e-01, 2.5000000e-01, - -2.5000000e-01, -2.5000000e-01 ] - -]) - -SNS_XQ2_7M5 = np.array([ - - [ 3.1622777e-01, 3.1622777e-01, 0.0000000e+00, -3.1622777e-01, - -6.3245553e-01, 3.1622777e-01, -0.0000000e+00, -3.1622777e-01, - 0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -3.1622777e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -0.0000000e+00, -0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 6.3245553e-01, 0.0000000e+00, 3.1622777e-01, 3.1622777e-01, - -0.0000000e+00, -3.1622777e-01, -3.1622777e-01, -3.1622777e-01, - -3.1622777e-01, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ] - -]) - -SNS_XQ3_7M5 = np.array([ - - [ 3.5355339e-01, 0.0000000e+00, 0.0000000e+00, -3.5355339e-01, - -7.0710678e-01, 3.5355339e-01, -0.0000000e+00, -3.5355339e-01, - 0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ], - - [ -0.0000000e+00, -0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 7.0710678e-01, 0.0000000e+00, 3.5355339e-01, 3.5355339e-01, - -0.0000000e+00, -3.5355339e-01, -0.0000000e+00, -3.5355339e-01, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00 ] - -]) - -SNS_XQ0 = [ SNS_XQ0_7M5, SNS_XQ0_10M ] -SNS_XQ1 = [ SNS_XQ1_7M5, SNS_XQ1_10M ] -SNS_XQ2 = [ SNS_XQ2_7M5, SNS_XQ2_10M ] -SNS_XQ3 = [ SNS_XQ3_7M5, SNS_XQ3_10M ] - - -### C.3.1.10/12 SNS quantization gains - -IND_LF_10M = np.array([ 25, 25, 4 ]) -IND_LF_7M5 = np.array([ 17, 17 ]) -IND_LF = [ IND_LF_7M5, IND_LF_10M ] - -IND_HF_10M = np.array([ 8, 9, 27 ]) -IND_HF_7M5 = np.array([ 8, 25 ]) -IND_HF = [ IND_HF_7M5, IND_HF_10M ] - -SUBMODE_MSB_10M = np.array([ 0, 0, 1 ]) -SUBMODE_MSB_7M5 = np.array([ 0, 0 ]) -SUBMODE_MSB = [ SUBMODE_MSB_7M5, SUBMODE_MSB_10M ] - -SUBMODE_LSB_10M = np.array([ 0, 0, 1 ]) -SUBMODE_LSB_7M5 = np.array([ 1, 0 ]) -SUBMODE_LSB = [ SUBMODE_LSB_7M5, SUBMODE_LSB_10M ] - -G_IND_10M = np.array([ 0, 0, 3 ]) -G_IND_7M5 = np.array([ 0, 0 ]) -G_IND = [ G_IND_7M5, G_IND_10M ] - -LS_IND_A_10M = np.array([ 1, 1, 1 ]) -LS_IND_A_7M5 = np.array([ 0, 0 ]) -LS_IND_A = [ LS_IND_A_7M5, LS_IND_A_10M ] - -LS_IND_B_10M = np.array([ True, True, None ]) -LS_IND_B_7M5 = np.array([ None, 1 ]) -LS_IND_B = [ LS_IND_B_7M5, LS_IND_B_10M ] - -IDX_A_10M = np.array([ 865837, 1023911, 61886 ]) -IDX_A_7M5 = np.array([ 1025681, 2213651 ]) -IDX_A = [ IDX_A_7M5, IDX_A_10M ] - -IDX_B_10M = np.array([ 1, 1, None ]) -IDX_B_7M5 = np.array([ None, 1 ]) -IDX_B = [ IDX_B_7M5, IDX_B_10M ] - -SCF_Q_10M = np.array([ - - [ 3.6627046e+00, 4.1100042e+00, 2.4746060e+00, 1.1870402e+00, - 5.2877727e-01, 7.5258069e-02, 2.3608016e-01, -2.5249380e-01, - -6.8201580e-01, -1.1328318e+00, -1.0800359e+00, -1.6239492e+00, - -1.7143487e+00, -1.9073626e+00, -2.2321087e+00, -2.0267285e+00 ], - - [ 3.8168009e+00, 5.1162010e+00, 3.4807329e+00, 1.1997530e+00, - -2.2081921e-01, -1.0181629e+00, -1.0657728e+00, -1.1230690e+00, - -1.2811443e+00, -1.3048218e+00, -1.2081961e+00, -1.2804827e+00, - -8.0867787e-01, -1.0022261e+00, -1.3971454e+00, -1.1057621e+00 ], - - [ -1.3038278e+00, -1.3183731e+00, -1.4433352e+00, -1.3025832e+00, - -7.2407159e-01, -7.0739510e-02, 3.0891592e-01, 1.1110561e-01, - -2.3826205e-01, 2.2790355e-01, 7.5958402e-01, 1.0128069e+00, - 1.0886346e+00, 1.3319042e+00, 1.4367016e+00, 1.0146522e+00 ] - -]) - - -SCF_Q_7M5 = np.array([ - - [ 4.3811806e+00, 3.2082316e+00, 1.7782399e+00, 6.4980749e-01, - 2.0221356e-01, 7.0332445e-02, -2.8668104e-01, -8.5700304e-01, - -6.1964726e-01, -8.0165679e-01, -1.0516986e+00, -1.3477232e+00, - -1.4003932e+00, -1.5566567e+00, -1.6059594e+00, -1.5454836e+00 ], - - [ 5.8316083e+00, 3.9835316e+00, 8.6468396e-01, -9.5443316e-01, - -8.1173658e-01, -6.2522498e-01, -6.4450858e-01, -7.4038105e-01, - -1.0412349e+00, -6.5113903e-01, -5.8671926e-01, -9.6639127e-01, - -5.7817825e-01, -5.4629017e-01, -9.2263684e-01, -8.4544942e-01 ], - -]) - -SCF_Q = [ SCF_Q_7M5, SCF_Q_10M ] - - -### C.3.1.11 SNS interpolation - -G_SNS_10M = np.array([ - - [ 7.8961620e-02, 7.8961620e-02, 7.5959959e-02, 7.0294618e-02, - 6.5051816e-02, 6.0200039e-02, 6.6727283e-02, 8.8588922e-02, - 1.1761302e-01, 1.5614618e-01, 2.0114945e-01, 2.5143043e-01, - 3.1428006e-01, 3.9284010e-01, 4.6498069e-01, 5.2116367e-01, - 5.8413517e-01, 6.5471542e-01, 7.2092077e-01, 7.7986290e-01, - 8.4362411e-01, 9.1259840e-01, 9.3603811e-01, 9.1031240e-01, - 8.8529374e-01, 8.6096267e-01, 8.8576235e-01, 9.6402006e-01, - 1.0491919e+00, 1.1418887e+00, 1.2364330e+00, 1.3319727e+00, - 1.4348949e+00, 1.5457699e+00, 1.6682873e+00, 1.8038405e+00, - 1.9504078e+00, 2.1088841e+00, 2.1828793e+00, 2.1629996e+00, - 2.1433009e+00, 2.1237816e+00, 2.2161032e+00, 2.4351378e+00, - 2.6758212e+00, 2.9402932e+00, 3.1064119e+00, 3.1554571e+00, - 3.2052766e+00, 3.2558828e+00, 3.3368236e+00, 3.4503169e+00, - 3.5676705e+00, 3.6890154e+00, 3.8582746e+00, 4.0816214e+00, - 4.3178972e+00, 4.5678504e+00, 4.6153375e+00, 4.4539677e+00, - 4.2982400e+00, 4.1479572e+00, 4.0029288e+00, 3.8629712e+00 ], - - [ 7.0962424e-02, 7.0962424e-02, 6.3406480e-02, 5.0622552e-02, - 4.0416103e-02, 3.2267464e-02, 3.3220843e-02, 4.4105412e-02, - 5.8556233e-02, 7.7741760e-02, 1.0915042e-01, 1.6206389e-01, - 2.4062852e-01, 3.5727938e-01, 4.9237129e-01, 6.2979823e-01, - 8.0558272e-01, 1.0304308e+00, 1.2487522e+00, 1.4337794e+00, - 1.6462221e+00, 1.8901424e+00, 2.0337102e+00, 2.0505581e+00, - 2.0675455e+00, 2.0846737e+00, 2.1037086e+00, 2.1246996e+00, - 2.1459001e+00, 2.1673122e+00, 2.2081350e+00, 2.2694571e+00, - 2.3324822e+00, 2.3972575e+00, 2.4353075e+00, 2.4453201e+00, - 2.4553739e+00, 2.4654690e+00, 2.4499352e+00, 2.4092551e+00, - 2.3692505e+00, 2.3299102e+00, 2.3250020e+00, 2.3543088e+00, - 2.3839851e+00, 2.4140354e+00, 2.3319019e+00, 2.1488367e+00, - 1.9801431e+00, 1.8246926e+00, 1.7812270e+00, 1.8419813e+00, - 1.9048079e+00, 1.9697773e+00, 2.0728144e+00, 2.2196325e+00, - 2.3768496e+00, 2.5452025e+00, 2.5681376e+00, 2.4416843e+00, - 2.3214575e+00, 2.2071505e+00, 2.0984720e+00, 1.9951447e+00 ] - -]) - -G_SNS_7M5 = np.array([ - - [ 4.7988064e-02, 4.7988064e-02, 5.3121439e-02, 6.5094311e-02, - 7.9765711e-02, 9.7743851e-02, 1.2247145e-01, 1.5691066e-01, - 2.0103424e-01, 2.5756547e-01, 3.2148295e-01, 3.9091375e-01, - 4.7533955e-01, 5.7799882e-01, 6.6256861e-01, 7.1600434e-01, - 7.7374963e-01, 8.3615204e-01, 8.7920505e-01, 8.9952910e-01, - 9.2032297e-01, 9.4159751e-01, 9.8233993e-01, 1.0450324e+00, - 1.1117258e+00, 1.1826756e+00, 1.2816224e+00, 1.4147546e+00, - 1.5617162e+00, 1.7239439e+00, 1.7744028e+00, 1.7029011e+00, - 1.6342806e+00, 1.5684252e+00, 1.5609220e+00, 1.6109378e+00, - 1.6625563e+00, 1.7158288e+00, 1.7812772e+00, 1.8601545e+00, - 1.9425246e+00, 2.0285422e+00, 2.1268255e+00, 2.2387723e+00, - 2.3566116e+00, 2.4806533e+00, 2.5567427e+00, 2.5801849e+00, - 2.6038421e+00, 2.6277162e+00, 2.6757181e+00, 2.7491622e+00, - 2.8246222e+00, 2.9021534e+00, 2.9543066e+00, 2.9796549e+00, - 3.0052206e+00, 3.0310057e+00, 3.0280729e+00, 2.9965054e+00, - 2.9652670e+00, 2.9343543e+00, 2.9037639e+00, 2.8734924e+00 ], - - [ 1.7559453e-02, 1.7559453e-02, 2.0608757e-02, 2.8387910e-02, - 3.9103448e-02, 5.3863762e-02, 8.2831558e-02, 1.4220423e-01, - 2.4413451e-01, 4.1912721e-01, 6.4291757e-01, 8.8116553e-01, - 1.2077018e+00, 1.6552436e+00, 1.9140070e+00, 1.8672589e+00, - 1.8216525e+00, 1.7771601e+00, 1.7271850e+00, 1.6722548e+00, - 1.6190716e+00, 1.5675798e+00, 1.5450306e+00, 1.5502021e+00, - 1.5553909e+00, 1.5605971e+00, 1.5762459e+00, 1.6026515e+00, - 1.6294995e+00, 1.6567972e+00, 1.7147376e+00, 1.8065050e+00, - 1.9031836e+00, 2.0050361e+00, 1.9895925e+00, 1.8595441e+00, - 1.7379963e+00, 1.6243933e+00, 1.5616667e+00, 1.5443306e+00, - 1.5271869e+00, 1.5102336e+00, 1.5520535e+00, 1.6576004e+00, - 1.7703250e+00, 1.8907155e+00, 1.8893168e+00, 1.7663992e+00, - 1.6514784e+00, 1.5440344e+00, 1.4888436e+00, 1.4806393e+00, - 1.4724802e+00, 1.4643660e+00, 1.5087288e+00, 1.6104012e+00, - 1.7189253e+00, 1.8347627e+00, 1.8829418e+00, 1.8579241e+00, - 1.8332388e+00, 1.8088814e+00, 1.7848477e+00, 1.7611333e+00 ], - -]) - -G_SNS = [ G_SNS_7M5, G_SNS_10M ] - - -### C.3.1.13 Spectral shaping - -X_S_10M = np.array([ - - [ -4.6579970e+01, 2.5475086e+03, -2.0979386e+03, 6.6905115e+03, - -7.4276511e+03, -1.3496582e+04, -1.4911551e+02, -1.7600517e+03, - -1.8897070e+03, 9.0806525e+01, -3.1626076e+03, 1.0097116e+03, - -3.1704894e+03, 7.4708040e+02, -1.9508019e+03, -5.0811399e+02, - 2.7592179e+02, -1.8004443e+03, 1.7810815e+03, -2.1469042e+03, - 1.8820925e+03, -1.3520099e+03, 7.5748485e+02, 9.4849121e+01, - -5.5907550e+02, 9.9853924e+02, -1.1694214e+03, 1.2670596e+03, - -1.1564965e+03, 7.6341371e+02, -3.7429412e+02, -1.2714316e+02, - 5.5868459e+02, -8.6630814e+02, 1.0827149e+03, -1.0408470e+03, - 9.2759078e+02, -5.8910202e+02, 2.3201842e+02, 1.8289697e+02, - -5.6951623e+02, 8.1229132e+02, -9.9835988e+02, 9.3658953e+02, - -8.1543182e+02, 4.9408042e+02, -1.3648595e+02, -2.4771597e+02, - 5.9096160e+02, -7.9945187e+02, 8.7469937e+02, -8.0242901e+02, - 6.1523337e+02, -3.4929423e+02, 4.3714524e+01, 2.3825249e+02, - -4.7949197e+02, 6.1487056e+02, -6.8885288e+02, 6.1543922e+02, - -4.5940587e+02, 2.6027447e+02, 1.4932451e+01, -2.6342003e+02, - 5.1698905e+02, -6.3805644e+02, 6.6431016e+02, -6.3536804e+02, - 4.4714179e+02, -2.0448694e+02, -7.5210020e+01, 3.2318745e+02, - -5.2463109e+02, 6.3268159e+02, -6.4137909e+02, 5.4210738e+02, - -3.6539049e+02, 1.4180793e+02, 1.1043715e+02, -3.2082774e+02, - 4.9551143e+02, -5.6464214e+02, 5.5411819e+02, -4.4912438e+02, - 2.8748742e+02, -8.3157725e+01, -1.4199053e+02, 3.1886540e+02, - -4.7410616e+02, 5.2507181e+02, -4.9901112e+02, 3.9510519e+02, - -2.3175576e+02, 3.7914915e+01, 1.7066614e+02, -3.3127409e+02, - 4.6682698e+02, -5.0146152e+02, 4.5964223e+02, -3.4704713e+02, - 1.8377315e+02, 8.3068359e-01, -2.0227229e+02, 3.5108641e+02, - -4.5284836e+02, 4.7317762e+02, -4.4561519e+02, 3.2535592e+02, - -1.4580770e+02, -3.9573578e+01, 2.3102912e+02, -3.8615649e+02, - 4.7298066e+02, -4.8574358e+02, 4.1595651e+02, -2.8690887e+02, - 1.0822973e+02, 8.0889458e+01, -2.6856378e+02, 4.0232748e+02, - -4.7864051e+02, 4.7205528e+02, -3.9210707e+02, 2.5719880e+02, - -6.8160760e+01, -1.1068097e+02, 2.8495852e+02, -3.8530783e+02, - 4.4481193e+02, -4.2962793e+02, 3.3997586e+02, -2.0750452e+02, - 2.8600150e+01, 1.3080486e+02, -2.8418457e+02, 3.7335187e+02, - -4.1400983e+02, 3.8613469e+02, -2.8921905e+02, 1.5545710e+02, - 5.7416806e+00, -1.4821308e+02, 2.8457226e+02, -3.6307452e+02, - 3.8831635e+02, -3.4730222e+02, 2.4109847e+02, -1.1774263e+02, - -3.0666081e+01, 1.6872235e+02, -2.8808479e+02, 3.5123254e+02, - -3.6347751e+02, 3.0487804e+02, -2.1236231e+02, 8.7865496e+01, - 6.0906484e+01, -1.8416198e+02, 2.9273130e+02, -3.4443289e+02 ], - - [ -4.4595314e+02, -1.0379970e+03, 3.1577388e+02, -3.5610417e+03, - 3.4581766e+03, 8.3381081e+03, -1.1696533e+03, 2.4101021e+03, - -6.5655829e+02, 1.4524982e+03, 1.9701386e+02, 1.1436715e+03, - 3.0871470e+02, 1.4623552e+03, 5.8823857e+02, 9.7150548e+02, - 4.8597295e+02, 6.6672780e+02, 1.9624228e+02, 1.5262224e+02, - -1.2492188e+01, -9.9749152e+01, -1.2404934e+02, -1.7103668e+02, - -9.0965339e+01, -7.0386211e+01, -2.5404068e+01, -6.2239848e+00, - 1.1353459e+01, 3.1118246e+01, 2.3550684e+01, 1.9918764e+01, - 6.7582893e+00, 3.5391093e+00, -2.5360957e+00, -1.2318765e+01, - -1.0710738e+01, -1.0309510e+01, -4.8149059e+00, -1.0084275e+00, - 1.5451084e+00, 6.7503435e+00, 8.7185892e+00, 6.5017316e+00, - 3.3714192e+00, 3.3653026e+00, 1.5730174e-01, -2.7592084e+00, - -5.2662479e+00, -5.1967404e+00, -2.6956428e+00, -3.2877724e+00, - -2.9012824e+00, 3.7032988e-01, 2.4268422e+00, 4.6841491e+00, - 4.4233993e+00, 2.9001769e+00, 4.0245597e+00, 2.1909513e+00, - -7.8166125e-01, -3.7740437e+00, -1.6826612e+00, -4.8759902e+00, - -7.0146012e+00, -4.2610160e+00, -1.9222920e+00, -3.8849374e-03, - 1.9171256e+00, 2.1228421e+00, 4.0002861e+00, 2.4213202e+00, - 5.5365640e+00, 2.0924576e+00, 3.2856722e+00, 2.3805212e-01, - -2.6499944e+00, -1.5877393e+00, -2.3638844e+00, -3.1969127e+00, - -4.5049447e+00, 4.9555393e-01, -5.2555443e-01, 2.8655462e-01, - -4.9844313e-01, 1.3144496e+00, 1.8462413e+00, 1.2390833e+00, - 1.8391487e-01, 1.3634153e+00, -3.0575242e-02, -1.2360920e+00, - 1.7996128e-01, -2.1572539e+00, -2.3206289e+00, -2.1575175e+00, - -1.3914054e+00, -2.1857655e+00, 2.8328476e-01, 9.0849227e-01, - 1.5616765e+00, 3.0216795e+00, 4.0452889e+00, 3.2116107e+00, - 1.5944792e+00, 2.2110634e-01, -1.2957452e+00, -3.9440236e-01, - -1.7499591e+00, -1.8705540e+00, -2.4921933e-01, 4.0425431e-01, - -3.0395784e+00, -1.9499112e+00, 6.8993026e-02, 2.6858112e+00, - 3.9365468e+00, 1.4534664e+00, 2.5590207e+00, 1.9618160e+00, - -3.1812104e-01, 3.6820368e-01, -2.3536912e-02, 3.9009812e-01, - -4.7912977e+00, -3.3553682e+00, -2.6900314e+00, -1.5134286e+00, - -9.9684877e-01, -6.2871446e-01, 1.8360627e+00, 1.4455944e+00, - 9.5156525e-01, 1.0993584e+00, 2.2401521e+00, 2.4733664e+00, - 2.3631456e-01, -2.0269302e+00, -2.4458555e+00, -1.2206038e+00, - -3.2403583e+00, -2.0795885e+00, -1.5947867e+00, -1.1727234e+00, - -3.2945845e-01, 8.0000134e-01, 3.4717506e-01, 1.5246353e+00, - -1.6045804e-01, 4.0202852e-02, 1.8039411e+00, 1.0516099e-01, - -7.4544919e-02, -2.1387580e+00, -2.0486855e+00, -7.9121437e-01, - -7.4423018e-01, -1.5334714e+00, -7.8671386e-01, -1.6940090e-01 ] - -]) - -X_S_7M5 = np.array([ - - [ -1.3344626e+03, 1.4958812e+03, -5.5694903e+03, -1.0486529e+04, - 5.6650034e+02, 6.0141573e+03, -5.3094551e+02, 2.6475111e+02, - 1.6690199e+03, -2.0838083e+03, 9.3187330e+02, 6.3720777e+02, - -1.8748573e+03, 1.9287595e+03, -4.9900796e+02, -1.1216643e+03, - 1.8281601e+03, -1.3351793e+03, -2.5896432e+01, 1.1847513e+03, - -1.4008698e+03, 7.1091673e+02, 3.4181812e+02, -1.1209015e+03, - 1.1047015e+03, -3.4707684e+02, -6.0822434e+02, 1.2069267e+03, - -9.8898328e+02, 3.9434472e+01, 8.9967867e+02, -1.1231789e+03, - 6.1473708e+02, 2.1402341e+02, -7.6438486e+02, 7.6886411e+02, - -3.0289717e+02, -3.6710597e+02, 7.3659799e+02, -5.8064409e+02, - 8.6987653e+01, 4.6780721e+02, -6.8240093e+02, 4.0409628e+02, - 9.0635459e+01, -5.3255888e+02, 6.1176277e+02, -2.4268516e+02, - -2.4050228e+02, 5.6445766e+02, -5.1941054e+02, 8.4546495e+01, - 3.6675922e+02, -5.6559679e+02, 4.1109821e+02, 6.3236483e+01, - -4.6563784e+02, 5.3992584e+02, -2.8194795e+02, -2.0189361e+02, - 5.0504429e+02, -4.5411112e+02, 1.2935836e+02, 2.9902539e+02, - -4.9207698e+02, 3.4402101e+02, 1.8978015e+00, -3.6234196e+02, - 4.6346622e+02, -2.2783004e+02, -1.1745582e+02, 4.0795439e+02, - -4.1004303e+02, 1.1293439e+02, 2.1977291e+02, -4.1879288e+02, - 3.3765885e+02, -2.7615664e+00, -2.9831792e+02, 4.0573572e+02, - -2.5374285e+02, -1.0182244e+02, 3.5226045e+02, -3.6553462e+02, - 1.5203133e+02, 1.9094377e+02, -3.7905818e+02, 3.0025026e+02, - -4.9616026e+01, -2.6139695e+02, 3.7537731e+02, -2.2263305e+02, - -4.6540403e+01, 3.1054395e+02, -3.4657574e+02, 1.3778205e+02, - 1.3283532e+02, -3.3677365e+02, 3.0049394e+02, -4.5453695e+01, - -2.0808762e+02, 3.3473443e+02, -2.3547267e+02, -4.3881934e+01, - 2.5964919e+02, -3.1164958e+02, 1.6251702e+02, 1.2186915e+02, - -2.9548260e+02, 2.7121711e+02, -8.0864501e+01, -1.8718254e+02, - 3.0861481e+02, -2.1772078e+02, 4.7378118e-01, 2.4022293e+02, - -3.0348233e+02, 1.5168546e+02, 7.7875700e+01, -2.8137835e+02 ], - - [ 6.6940015e+01, -3.8686730e+02, 1.2805107e+03, -7.2628992e+03, - -1.5754672e+03, -6.2436979e+02, 8.2787173e+02, -8.0959099e+02, - -3.4245127e+02, -3.5548999e+01, -1.0732178e+02, 3.3015325e+01, - 1.9173905e+02, 1.8057154e+02, -2.3823068e+01, -1.4567609e+02, - -1.0868931e+02, 3.0479251e+01, 7.1566338e+01, 2.4158550e+01, - -6.2114342e+00, -1.4130388e+01, -1.8394789e+01, -1.8227404e+01, - 3.8411657e+00, 2.5627619e+01, 2.8307446e+01, -1.6207017e+00, - -2.8151474e+01, -2.4154773e+01, -5.2808122e-01, 6.3053889e+00, - 1.6985395e+01, 2.1137594e+01, 1.0163883e+01, -1.2646204e+01, - -2.8258074e+01, -1.5957606e+01, 1.0393474e+01, 1.5431458e+01, - 1.0833710e+01, 6.5820435e+00, -4.0055074e+00, -1.1459013e+01, - -1.4519949e+01, -5.8509646e+00, 1.5015967e+01, 1.5836030e+01, - 4.1133189e+00, -1.7829961e+00, -8.3853815e+00, -1.1122404e+01, - -8.7393669e+00, 3.6899921e+00, 1.7989851e+01, 1.3569871e+01, - -4.2575144e+00, -9.6890713e+00, -1.0139553e+01, -8.7913755e+00, - -1.6029731e+00, 5.0445901e+00, 1.4433262e+01, 9.5900419e+00, - -8.2284294e+00, -9.7476743e+00, -6.5414935e+00, -1.9885597e+00, - 2.9171599e+00, 6.6780713e+00, 9.2081019e+00, 2.8651322e+00, - -1.0061317e+01, -1.1376702e+01, -1.6700624e+00, 1.3140771e+00, - 6.5095758e+00, 6.8977417e+00, 4.8690746e+00, -8.2814942e-01, - -1.0064761e+01, -8.9205098e+00, 1.2429849e+00, 7.8244782e+00, - 6.6880480e+00, 5.8136759e+00, 5.9984867e-01, -6.0624312e+00, - -1.1389596e+01, -7.9714369e+00, 7.4518543e+00, 8.9170413e+00, - 6.3880481e+00, 1.3801389e+00, -2.8576875e+00, -6.7319113e+00, - -1.0072255e+01, -3.5424326e+00, 8.4784304e+00, 1.0898685e+01, - 4.8542048e+00, -2.6188427e+00, -5.9736376e+00, -7.4232870e+00, - -5.5939115e+00, 1.9917820e+00, 1.1064235e+01, 9.7301910e+00, - -4.8166311e-01, -6.0418655e+00, -7.8074447e+00, -6.7420485e+00, - -5.7805346e-01, 4.1557564e+00, 1.1700978e+01, 7.8318863e+00, - -4.5426418e+00, -8.2115262e+00, -6.8867416e+00, -1.9487360e+00 ] - -]) - -X_S = [ X_S_7M5, X_S_10M ] - - -### C.3.1.14 TNS coder - -X_F_10M = np.array([ - - [ -4.6579970e+01, 2.5475086e+03, -2.0979386e+03, 6.6905115e+03, - -7.4276511e+03, -1.3496582e+04, -1.4911551e+02, -1.7600517e+03, - -1.8897070e+03, 9.0806525e+01, -3.1626076e+03, 1.0097116e+03, - -3.1704894e+03, -1.4629727e+03, 1.6177531e+02, -2.8070849e+02, - 1.6836280e+02, -4.8794939e+02, 4.8735463e+01, -3.2812648e+02, - 2.0567762e+02, -2.7612607e+02, 1.7089464e+02, -1.4903447e+02, - 1.7634897e+02, -1.7636863e+02, -1.4114282e+01, 1.5326904e+02, - -2.0051680e+02, 7.5885344e+01, -1.2030117e+02, 8.6222257e+01, - 3.4247381e+01, -3.1564007e+01, 1.3038568e+02, -1.1547149e+02, - 1.5722828e+02, -1.1575179e+02, 8.3918034e+01, -4.2997589e+01, - -4.9151429e+01, 5.7178185e+01, -1.4462317e+02, 1.2240116e+02, - -1.4658879e+02, 1.0329710e+02, -4.8119513e+01, 1.5046477e+01, - 4.7974194e+01, -6.8870459e+01, 7.5850716e+01, -1.0491255e+02, - 1.0512982e+02, -9.6951573e+01, 6.8788954e+01, -3.9997908e+01, - -8.7506165e+00, 3.5520535e+01, -9.4932383e+01, 8.5065288e+01, - -6.7462450e+01, 9.2204890e+01, -2.2005176e+01, -2.2102766e+01, - 7.7845918e+01, -7.8223738e+01, 7.3211489e+01, -1.4466156e+02, - 7.8730279e+01, -2.1569349e+01, 2.0934594e+01, 1.0330210e+01, - -5.6199662e+01, 7.4347857e+01, -8.7431560e+01, 8.2441742e+01, - -7.4246878e+01, 5.8052214e+01, -1.2858317e+01, -8.5491490e+00, - 4.9073587e+01, -6.1606297e+01, 7.0756502e+01, -7.3226896e+01, - 6.7149964e+01, -4.3873945e+01, -3.2798184e-01, 1.2618393e+01, - -6.0263717e+01, 6.9581326e+01, -6.2258677e+01, 7.0807773e+01, - -5.6473108e+01, 2.9499750e+01, 6.4843952e+00, -2.1637431e+01, - 6.5900289e+01, -6.9209851e+01, 5.7574118e+01, -6.3239986e+01, - 5.0201888e+01, -2.5161732e+01, -1.8407647e+01, 3.3057952e+01, - -5.1394596e+01, 6.6274453e+01, -8.9093497e+01, 6.1636186e+01, - -1.8970991e+01, 1.8110690e+01, 1.4664315e+01, -5.7379639e+01, - 5.9659304e+01, -6.7425126e+01, 6.6740221e+01, -5.6441736e+01, - 3.3370764e+01, -8.8727172e+00, -2.8768291e+01, 4.7072609e+01, - -6.4504039e+01, 7.0679425e+01, -6.4413968e+01, 5.7895311e+01, - -2.2822099e+01, 8.2462832e+00, 2.1908355e+01, -3.0461871e+01, - 5.6741507e+01, -7.3393219e+01, 5.3252893e+01, -4.6826469e+01, - 2.0122779e+01, -5.9699302e+00, -2.3230042e+01, 3.8784526e+01, - -5.3705628e+01, 6.2675409e+01, -4.5504385e+01, 3.5709340e+01, - -1.9387569e+01, 5.2553786e+00, 3.0873151e+01, -4.6681999e+01, - 5.1345152e+01, -5.3802726e+01, 3.5105259e+01, -3.7404776e+01, - 2.0074043e+01, 1.0637688e+01, -3.4769882e+01, 4.1709646e+01, - -5.1828676e+01, 4.2299294e+01, -4.3335588e+01, 3.5793638e+01, - 1.1265725e+00, -1.0395933e+01, 3.3544261e+01, -4.9299157e+01 ], - - [ -4.4595314e+02, -1.0379970e+03, 3.1577388e+02, -3.5610417e+03, - 3.4581766e+03, 8.3381081e+03, -1.1696533e+03, 2.4101021e+03, - -6.5655829e+02, 1.4524982e+03, 1.9701386e+02, 1.1436715e+03, - 3.0871470e+02, 1.3134384e+03, -2.1221169e+02, 2.4285486e+02, - -1.3136018e+02, 2.0492262e+02, -5.7778142e+01, 2.0474887e+02, - 7.0763142e+01, 9.9953062e+01, 8.3698665e+01, 6.2817480e+01, - 7.7348745e+01, 4.8618716e+01, 1.9547983e+01, -7.2171464e+00, - -1.9159653e+01, -1.4038329e+01, -1.8628426e+01, -1.6163696e+01, - -1.4520857e+01, -4.8554891e+00, -5.7820395e-01, -3.7918076e+00, - 2.3294407e+00, 2.9495405e+00, 4.7407475e+00, 4.4409321e+00, - 1.5250457e+00, 2.7760466e+00, 1.9722269e+00, -2.1015209e+00, - -3.2710967e+00, -2.8401413e-03, -1.3044069e+00, -1.6457901e+00, - -1.6669278e+00, -2.3124530e-01, 2.3073051e+00, 8.9693576e-02, - -9.1429477e-01, 1.6390903e+00, 1.5921541e+00, 2.0781925e+00, - 5.6774613e-01, -1.4873030e+00, 9.0090862e-01, -1.7392411e-01, - -2.0619629e+00, -2.6804981e+00, 1.5808344e+00, -1.9739969e+00, - -3.2934549e+00, 8.3984861e-01, 1.6902572e+00, 1.1574818e+00, - 1.5309696e+00, -4.5293583e-01, 6.7334155e-01, -1.0828159e+00, - 2.8647595e+00, -1.0355011e+00, 1.2478700e+00, -1.0934505e+00, - -2.6607804e+00, 6.5988107e-01, 5.0203258e-01, -9.3129652e-01, - -1.6993602e+00, 3.3832184e+00, -1.1600967e-01, -2.6664726e-01, - -1.2900776e+00, 4.8121635e-01, 5.7458524e-01, -1.3748852e-02, - -1.0422755e+00, 9.6404835e-01, -6.5515813e-01, -1.2033320e+00, - 1.2628304e+00, -1.5881764e+00, -1.2024205e+00, -1.5188743e-01, - 2.1530142e-01, -1.1518121e+00, 1.5159517e+00, 7.6772612e-01, - 3.4785413e-01, 1.4223757e+00, 1.6791664e+00, 1.6342604e-03, - -9.7881678e-01, -1.0907888e+00, -1.1879306e+00, 1.1798907e+00, - -9.0898948e-02, -1.9025707e-01, 1.4674577e+00, 9.8643104e-01, - -3.5040854e+00, -8.8416089e-01, 1.4586672e+00, 2.8440488e+00, - 2.5053395e+00, -1.5126041e+00, -3.8048891e-02, 5.8273982e-02, - -1.6839084e+00, 8.3919618e-01, 8.4288521e-01, 8.2299662e-01, - -4.3286655e+00, -8.2387031e-01, 3.8407497e-01, 8.0932325e-01, - 4.2209188e-01, -1.6088979e-01, 1.1786569e+00, -1.5473109e-01, - -9.7397503e-01, -1.5447399e-01, 1.2455806e+00, 1.1521613e+00, - -1.1394046e+00, -2.4879158e+00, -1.1733733e+00, 1.0462318e+00, - -1.2964334e+00, 2.4531392e-01, 1.9106251e-01, -4.3741350e-01, - 5.7814855e-02, 7.3157372e-01, -7.7503310e-01, 5.5390581e-01, - -1.3940056e+00, -5.7191178e-01, 1.8789088e+00, -5.6670606e-01, - -4.8435902e-01, -1.8372728e+00, -9.7604008e-01, 1.0244293e+00, - 5.7039949e-01, -1.0034018e+00, -8.3178864e-02, 7.5770740e-02 ] - -]) - -X_F_7M5 = np.array([ - - [ -1.3344626e+03, 1.4958812e+03, -5.5694903e+03, -1.0486529e+04, - 5.6650034e+02, 6.0141573e+03, -5.3094551e+02, 2.6475111e+02, - 1.6690199e+03, -2.0838083e+03, -5.7181477e+02, 3.0979708e+02, - -2.1393724e+02, 1.2521746e+02, 3.2684730e+02, -1.7994574e+02, - -2.0020361e+02, 8.6111917e+00, -2.4832990e+02, 1.7213677e+02, - 1.4131656e+00, -8.5287997e+01, 1.7851510e+02, -2.3922723e+02, - 9.9313025e+01, 8.9492487e+01, -2.1678225e+02, 2.8445423e+02, - -1.0586008e+02, -1.7011189e+02, 2.0924470e+02, -4.3658588e+01, - -5.3305585e+01, 9.5065494e+01, -2.4959448e+01, -1.9882483e+01, - 6.3950343e+01, -1.8254423e+02, 1.4871147e+02, -2.9924201e+01, - -3.8358507e+01, 1.3662271e+02, -9.1506608e+01, -3.6536786e+01, - 6.1379812e+01, -1.2146687e+02, 7.5261109e+01, 6.3261448e+01, - -7.4977224e+01, 9.6981001e+01, -5.2501206e+01, -8.8542526e+01, - 8.7236325e+01, -7.1242762e+01, 3.4918529e+01, 1.0382986e+02, - -9.4414359e+01, 4.3111460e+01, -6.8550987e+00, -1.1139641e+02, - 6.8058914e+01, -6.1872729e+00, -2.3074735e+01, 1.0246797e+02, - -5.7063670e+01, -1.0528237e+01, 3.4668643e+01, -9.7928146e+01, - 5.4841513e+01, 3.8537271e+01, -4.1668071e+01, 9.3225595e+01, - -3.6482817e+01, -5.6719701e+01, 4.9322737e+01, -7.0376756e+01, - 2.4449679e+01, 7.1939467e+01, -5.4394295e+01, 5.0564463e+01, - -1.2276169e+01, -8.5637045e+01, 5.2333982e+01, -2.5308579e+01, - -5.5784300e+00, 8.7058263e+01, -5.1715921e+01, -7.2178424e-01, - 1.4946171e+01, -8.5511725e+01, 4.3784053e+01, 1.9685956e+01, - -2.5023328e+01, 8.0537198e+01, -3.0868111e+01, -3.4548956e+01, - 3.4272902e+01, -7.1390131e+01, 1.8631772e+01, 5.2295899e+01, - -3.9080597e+01, 5.2223213e+01, -9.1791474e+00, -6.4321817e+01, - 3.7530035e+01, -3.6279190e+01, 1.3252369e+00, 7.2448665e+01, - -3.9490622e+01, 1.4609831e+01, 9.3290814e+00, -7.2230799e+01, - 3.7265287e+01, 3.1414748e+00, -1.8859243e+01, 7.1138748e+01, - -3.1848909e+01, -2.1851571e+01, 2.6573367e+01, -6.9966757e+01 ], - - [ 6.6940015e+01, -3.8686730e+02, 1.2805107e+03, -7.2628992e+03, - -1.5754672e+03, -6.2436979e+02, 8.2787173e+02, -8.0959099e+02, - -3.4245127e+02, -3.5548999e+01, -7.4832843e+01, 9.1419785e+01, - 5.1342258e+01, 5.3971888e+01, -2.7664071e+01, 4.6162382e+01, - -1.0556418e+01, 6.7202580e+01, -1.7808740e+01, -6.8463927e+00, - -1.7273295e+01, 1.1657273e+00, -3.0473621e+00, 7.6704533e+00, - 3.2019440e+00, -4.9821490e+00, 9.7767521e+00, -5.6595863e+00, - -2.2488613e+00, -2.3116498e+00, 3.6060424e+00, -1.0509700e+01, - 1.0880662e+01, 1.3223251e+00, 3.8299992e+00, -3.2105583e+00, - -1.3455890e+00, -1.3800967e+00, 3.9392807e+00, -5.9971359e+00, - 3.0005141e+00, 3.1693816e+00, -2.4580934e+00, 7.4517245e-01, - -2.5522465e+00, -1.7665735e+00, 6.2439566e+00, -2.5566772e+00, - 1.0487489e+00, 4.9010207e+00, -2.4551119e+00, -2.3895763e+00, - -1.5405507e+00, 1.9495530e+00, 3.6880545e+00, 5.9918442e-01, - -2.4705668e+00, 4.8115098e+00, -4.1881444e+00, -3.6102608e+00, - -5.5087057e-01, -2.6206962e+00, 3.9639713e+00, -7.7640910e-01, - -3.9510665e+00, 4.4026144e+00, -3.2255765e+00, -1.5538782e+00, - -3.1853054e-01, 1.6928250e+00, 8.0901945e-01, 9.8517710e-01, - -3.9968911e+00, 5.2957448e-01, 7.5228614e-01, -5.5755012e+00, - 4.1839400e+00, -8.6149818e-01, 2.4716293e+00, -3.9843760e-01, - -1.6905671e+00, -8.5829267e-01, 1.9447429e+00, -3.4134235e-01, - 7.0851852e-02, 5.1275041e+00, -1.0122600e+00, 1.4475050e-01, - -3.3223224e+00, -1.0374444e+00, 3.7779787e+00, -4.5459512e+00, - 4.0726493e+00, -2.5433866e-01, 2.0525115e+00, -3.0465923e+00, - -1.7020097e+00, -1.0852672e+00, 2.3054607e+00, -5.4698297e-01, - 1.0938816e+00, 9.5295631e-01, 1.8110373e-01, -2.4274422e+00, - -9.0034207e-01, 3.4598368e-01, 3.0697391e+00, -3.3366935e-03, - -3.4637690e-02, 2.0742294e+00, -2.0643727e+00, -2.3004709e+00, - 3.4207323e-01, -1.8133178e+00, 5.0366054e+00, -8.8976033e-01, - -7.4204267e-01, 1.6508374e+00, -1.2431019e+00, -1.1825352e+00 ] - -]) - -X_F = [ X_F_7M5, X_F_10M ] - -RC_ORDER_10M = np.array([ [ 6, 0 ], [ 6, 0 ] ]) -RC_ORDER_7M5 = np.array([ [ 8, 0 ], [ 8, 0 ] ]) -RC_ORDER = [ RC_ORDER_7M5, RC_ORDER_10M ] - -RC_I_1_10M = np.array([ [ 13, 9, 4, 9, 8, 9, 8, 8 ], - [ 4, 7, 9, 9, 9, 9, 8, 8 ] ]) - -RC_I_1_7M5 = np.array([ [ 12, 13, 6, 9, 7, 9, 7, 9 ], - [ 5, 13, 8, 10, 9, 9, 7, 9 ] ]) - -RC_I_1 = [ RC_I_1_7M5, RC_I_1_10M ] - -RC_I_2_10M = np.array([ [ 8, 8, 8, 8, 8, 8, 8, 8 ], - [ 8, 8, 8, 8, 8, 8, 8, 8 ] ]) - -RC_I_2_7M5 = np.array([ [ 8, 8, 8, 8, 8, 8, 8, 8 ], - [ 8, 8, 8, 8, 8, 8, 8, 8 ] ]) - -RC_I_2 = [ RC_I_2_7M5, RC_I_2_10M ] - -RC_Q_1_10M = np.array([ - - [ 7.9801723e-01, 1.8374952e-01, -6.7369564e-01, 1.8374952e-01, - 0.0000000e+00, 1.8374952e-01, 0.0000000e+00, 0.0000000e+00 ], - - [ -6.7369564e-01, -1.8374952e-01, 1.8374952e-01, 1.8374952e-01, - 1.8374952e-01, 1.8374952e-01, 0.0000000e+00, 0.0000000e+00 ] - -]) - -RC_Q_1_7M5 = np.array([ - - [ 6.7369564e-01, 7.9801723e-01, -3.6124167e-01, 1.8374952e-01, - -1.8374952e-01, 1.8374952e-01, -1.8374952e-01, 1.8374952e-01 ], - - [ -5.2643216e-01, 7.9801723e-01, 0.0000000e+00, 3.6124167e-01, - 1.8374952e-01, 1.8374952e-01, -1.8374952e-01, 1.8374952e-01 ] - -]) - -RC_Q_1 = [ RC_Q_1_7M5, RC_Q_1_10M ] - -RC_Q_2_10M = np.array([ - - [ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00 ], - - [ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00 ] - -]) - -RC_Q_2_7M5 = np.array([ - - [ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00 ], - - [ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00 ] - -]) - -RC_Q_2 = [ RC_Q_2_7M5, RC_Q_2_10M ] - -NUM_TNS_FILTERS_10M = [ 1, 1 ] -NUM_TNS_FILTERS_7M5 = [ 1, 1 ] -NUM_TNS_FILTERS = [ NUM_TNS_FILTERS_7M5, NUM_TNS_FILTERS_10M ] - -TNS_LEV_A_10M = np.array([ - - [ 1.0000000e+00, 7.2228594e-01, -5.9139666e-01, -5.8613895e-01, - 1.1856746e-01, 2.9269254e-02, 8.0280074e-02, 3.8446982e-02, - 4.3781506e-02 ], - - [ 1.0000000e+00, -5.6089086e-01, -2.3332924e-01, 1.3258672e-01, - -7.2233128e-02, 1.1753190e-01, 1.9802609e-01, -6.1275417e-02, - 2.2455104e-02 ] - -]) - -TNS_LEV_A_7M5 = np.array([ - - [ 1.0000000e+00, 5.2890099e-01, 5.4205760e-01, -4.4859180e-01, - 3.5954391e-01, -1.9179061e-01, 1.8237136e-01, -1.1968822e-01, - 1.6649226e-01 ], - - [ 1.0000000e+00, -9.0587790e-01, 9.8849245e-01, -1.4294859e-01, - 2.5680120e-01, -5.8559598e-03, 3.0914531e-01, -2.2365546e-01, - 1.0115038e-01 ] - -]) - -TNS_LEV_A = [ TNS_LEV_A_7M5, TNS_LEV_A_10M ] - -TNS_LEV_E_10M = [ 0.412635, 1.396833 ] -TNS_LEV_E_7M5 = [ 0.397854, 0.665554 ] -TNS_LEV_E = [ TNS_LEV_E_7M5, TNS_LEV_E_10M ] - -TNS_LEV_RC_10M = np.array([ - - [ 8.3775274e-01, 1.7149527e-01, -7.0757376e-01, 1.9028627e-01, - -1.4202392e-02, 1.0144450e-01, 6.8373224e-03, 4.3781506e-02 ], - - [ -6.7692801e-01, -9.9895702e-02, 2.2652538e-01, 1.0193040e-01, - 2.0702019e-01, 1.7652182e-01, -4.8705113e-02, 2.2455104e-02 ] - -]) - -TNS_LEV_RC_7M5 = np.array([ - - [ 6.0637394e-01, 8.3208082e-01, -4.0823140e-01, 2.1979501e-01, - -1.5450397e-01, 2.2566273e-01, -2.1366897e-01, 1.6649226e-01 ], - - [ -5.4911119e-01, 7.7810682e-01, -2.2286927e-03, 3.4649135e-01, - 2.2484419e-01, 9.3957220e-02, -1.3339034e-01, 1.0115038e-01 ] - -]) - -TNS_LEV_RC = [ TNS_LEV_RC_7M5, TNS_LEV_RC_10M ] - -NBITS_TNS_10M = np.array([ 24, 18 ]) -NBITS_TNS_7M5 = np.array([ 24, 24 ]) -NBITS_TNS = [ NBITS_TNS_7M5, NBITS_TNS_10M ] - - -### C.3.1.15 Global gain estimation - -GG_OFF_10M = np.array([ -131, -131 ]) -GG_OFF_7M5 = np.array([ -127, -127 ]) -GG_OFF = [ GG_OFF_7M5, GG_OFF_10M ] - -GG_IND_10M = np.array([ 191, 166 ]) -GG_IND_7M5 = np.array([ 189, 162 ]) -GG_IND = [ GG_IND_7M5, GG_IND_10M ] - -GG_MIN_10M = np.array([ 121, 115 ]) -GG_MIN_7M5 = np.array([ 114, 109 ]) -GG_MIN = [ GG_MIN_7M5, GG_MIN_10M ] - -GG_10M = np.array([ 138.949549, 17.782794 ]) -GG_7M5 = np.array([ 163.789371, 17.782794 ]) -GG = [ GG_7M5, GG_10M ] - -NBITS_OFFSET_10M = np.array([ 0.000000, -1.200000 ]) -NBITS_OFFSET_7M5 = np.array([ 0.000000, -1.600000 ]) -NBITS_OFFSET = [ NBITS_OFFSET_7M5, NBITS_OFFSET_10M ] - - -### C.3.1.16 Quantization - -X_Q_10M = np.array([ - - [ 0, 18, -15, 48, -53, -97, -1, -13, -13, 1, - -23, 7, -23, -10, 1, -2, 1, -3, 0, -2, - 1, -2, 1, -1, 1, -1, 0, 1, -1, 0, - -1, 0, 0, 0, 1, -1, 1, -1, 0, 0, - 0, 0, -1, 1, -1, 1, 0, 0, 0, 0, - 0, -1, 1, -1, 0, 0, 0, 0, -1, 0, - 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, - 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], - - [ -25, -58, 18, -200, 194, 469, -66, 135, -37, 82, - 11, 64, 17, 74, -12, 14, -7, 11, -3, 11, - 4, 5, 5, 3, 4, 3, 1, 0, -1, -1, - -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - -]) - -X_Q_7M5 = np.array([ - - [ -8, 9, -34, -64, 3, 37, -3, 1, 10, -13, - -3, 2, -1, 1, 2, -1, -1, 0, -1, 1, - 0, 0, 1, -1, 0, 0, -1, 2, -1, -1, - 1, 0, 0, 0, 0, 0, 0, -1, 1, 0, - 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], - - [ 4, -22, 72, -408, -88, -35, 46, -45, -19, -2, - -4, 5, 3, 3, -1, 2, 0, 4, -1, 0, - -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - -]) - -X_Q = [ X_Q_7M5, X_Q_10M ] - -LASTNZ_10M = np.array([ 108, 34 ]) -LASTNZ_7M5 = np.array([ 64, 22 ]) -LASTNZ = [ LASTNZ_7M5, LASTNZ_10M ] - -NBITS_EST_10M = np.array([ 231, 250 ]) -NBITS_EST_7M5 = np.array([ 164, 140 ]) -NBITS_EST = [ NBITS_EST_7M5, NBITS_EST_10M ] - -LSB_MODE_10M = np.array([ 0, 0 ]) -LSB_MODE_7M5 = np.array([ 0, 0 ]) -LSB_MODE = [ LSB_MODE_7M5, LSB_MODE_10M ] - -NBITS_SPEC_10M = np.array([ 225, 231 ]) -NBITS_SPEC_7M5 = np.array([ 156, 146 ]) -NBITS_SPEC = [ NBITS_SPEC_7M5, NBITS_SPEC_10M ] - - -### C.3.1.17 Global Gain adjustement - -GG_IND_ADJ_10M = np.array([ 192, 168 ]) -GG_IND_ADJ_7M5 = np.array([ 190, 162 ]) -GG_IND_ADJ = [ GG_IND_ADJ_7M5, GG_IND_ADJ_10M ] - -GG_ADJ_10M = np.array([ 1.508591e+02, 2.096180e+01 ]) -GG_ADJ_7M5 = np.array([ 1.778279e+02, 1.778279e+01 ]) -GG_ADJ = [ GG_ADJ_7M5, GG_ADJ_10M ] - - -### C.3.1.18 Requantization - -X_Q_REQ_10M = np.array([ - - [ 0, 17, -14, 44, -49, -89, -1, -12, -12, 0, - -21, 7, -21, -10, 1, -2, 1, -3, 0, -2, - 1, -2, 1, -1, 1, -1, 0, 1, -1, 0, - -1, 0, 0, 0, 1, -1, 1, -1, 0, 0, - 0, 0, -1, 1, -1, 1, 0, 0, 0, 0, - 0, -1, 1, -1, 0, 0, 0, 0, -1, 0, - 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], - - [ -21, -49, 15, -170, 165, 398, -56, 115, -31, 69, - 9, 54, 15, 63, -10, 11, -6, 10, -3, 10, - 3, 5, 4, 3, 4, 2, 1, 0, -1, -1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - -]) - -X_Q_REQ_7M5 = np.array([ - - [ -7, 8, -31, -59, 3, 34, -3, 1, 9, -12, - -3, 2, -1, 1, 2, -1, -1, 0, -1, 1, - 0, 0, 1, -1, 0, 0, -1, 1, 0, -1, - 1, 0, 0, 0, 0, 0, 0, -1, 1, 0, - 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], - -]) - -X_Q_REQ = [ X_Q_REQ_7M5, X_Q_REQ_10M ] - -LASTNZ_REQ_10M = np.array([ 68, 30 ]) -LASTNZ_REQ_7M5 = np.array([ 60, None ]) -LASTNZ_REQ = [ LASTNZ_REQ_7M5, LASTNZ_REQ_10M ] - -NBITS_EST_REQ_10M = np.array([ 206, 237 ]) -NBITS_EST_REQ_7M5 = np.array([ 147, None ]) -NBITS_EST_REQ = [ NBITS_EST_REQ_7M5, NBITS_EST_REQ_10M ] - -NBITS_TRUNC_REQ_10M = np.array([ 206, 229 ]) -NBITS_TRUNC_REQ_7M5 = np.array([ 147, None ]) -NBITS_TRUNC_REQ = [ NBITS_TRUNC_REQ_7M5, NBITS_TRUNC_REQ_10M ] - -LSB_MODE_REQ_10M = np.array([ 0, 0 ]) -LSB_MODE_REQ_7M5 = np.array([ 0, None ]) -LSB_MODE_REQ = [ LSB_MODE_REQ_7M5, LSB_MODE_REQ_10M ] - - -### C.3.1.19 Residual Coding - -RES_BITS_10M = np.array([ - [ 0, 1 ,1 ,0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, - 0, 1, 1, 1, 1, 1, 0 ], - [ 0, 0, 1, 1, 0, 0 ] -], dtype=object) - -RES_BITS_7M5 = np.array([ - [ 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0 ], - [ 0, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] -], dtype=object) - -RES_BITS = [ RES_BITS_7M5, RES_BITS_10M ] - - -### C.3.1.20 Noise factor - -F_NF_10M = np.array([ 3, 7 ]) -F_NF_7M5 = np.array([ 4, 6 ]) -F_NF = [ F_NF_7M5, F_NF_10M ] - - -### C.3.1.21 Side information encoding - -BYTES_SIDE_10M = [ - - bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x19, 0x30, 0xc3, 0x8d, 0xf1, 0x88, 0xcf, 0x80, 0x43 ]), - - bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x39, 0x30, 0xc5, 0xf7, 0x6b, 0x89, 0xcf, 0x50, 0x1d ]) - -] - -BYTES_SIDE_7M5 = [ - - bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x07, 0xd3, 0x48, 0x84, 0x45, 0xbe, 0x3b ]), - - bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x90, 0x6c, 0x0f, 0x6b, 0x8c, 0xc7, 0xa2, 0x15 ]) - -] - -BYTES_SIDE = [ BYTES_SIDE_7M5, BYTES_SIDE_10M ] - - -### C.3.1.22 Arithmetic encoding - -BYTES_AC_10M = [ - - bytearray([ - 0xa7, 0x1c, 0x2a, 0x35, 0xaf, 0x69, 0x0e, 0xf9, 0xbe, 0xf1, - 0xcb, 0x2e, 0x87, 0x5f, 0x05, 0x13, 0xd7, 0x8e, 0x3c, 0xf2, - 0xcd, 0xd5, 0xad, 0x56, 0xb6, 0x5e, 0xe1, 0x8f, 0xc1, 0xbe, - 0x80, 0x99, 0x30, 0xc3, 0x8d, 0xf1, 0x88, 0xcf, 0x80, 0x43 ]), - - bytearray([ - 0x7e, 0x55, 0xff, 0x85, 0x35, 0x86, 0xf7, 0x01, 0xf8, 0x8c, - 0xaa, 0x1a, 0x1e, 0x42, 0x43, 0xd6, 0x26, 0x02, 0x37, 0x5c, - 0x78, 0xff, 0x1a, 0x55, 0xdd, 0xd2, 0x81, 0x2e, 0x68, 0xdd, - 0xc4, 0xf9, 0x30, 0xc5, 0xf7, 0x6b, 0x89, 0xcf, 0x50, 0x1d ]) - -] - -BYTES_AC_7M5 = [ - - bytearray([ - 0xfe, 0x86, 0xdb, 0xa2, 0x90, 0x78, 0x54, 0xb1, 0x5d, 0x1b, - 0x1f, 0x3b, 0x24, 0x62, 0xaf, 0xb5, 0x95, 0x9c, 0xb0, 0xa0, - 0x6f, 0xbe, 0xac, 0x07, 0xd3, 0x48, 0x84, 0x45, 0xbe, 0x3b ]), - - bytearray([ - 0xda, 0x52, 0x63, 0x57, 0xf8, 0x66, 0x37, 0xcf, 0x85, 0xe1, - 0xd4, 0x32, 0x46, 0xc2, 0x36, 0x6d, 0xed, 0xa9, 0x52, 0x58, - 0x17, 0x18, 0x90, 0x6c, 0x0f, 0x6b, 0x8c, 0xc7, 0xa2, 0x15 ]) - -] - -BYTES_AC = [ BYTES_AC_7M5, BYTES_AC_10M ] - - -### C.3.1.23 Attack detector intermediate data - -NBYTES_ATT = (88e3 * np.array([ 7.5e-3, 10e-3 ]) / 8).astype(int) - -X_PCM_ATT_10M = np.array([ - - [ 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 27852, 29491, 27852, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 ], - - [ 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 ] - -]) - -X_PCM_ATT_7M5 = np.array([ - - [ 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 27852, 29491, 27852, 0, - 0, 0, 0, 0, 0, 0, 0, 0 ], - - [ 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 ], - -]) - -X_PCM_ATT = [ X_PCM_ATT_7M5, X_PCM_ATT_10M ] - -F_ATT_7M5 = np.array([ 1, 1 ]) -F_ATT_10M = np.array([ 1, 1 ]) -F_ATT = [ F_ATT_7M5, F_ATT_10M ] - - -### C.4.1.1-4 Spectrum Decoding - -X_HAT_Q_10M = np.array([ - - [ 0.0000, 16.8125, -13.8125, 44.3125, -49.3125, -89.3125, - -0.8125, -11.8125, -12.3125, 0.0000, -20.8125, 6.8125, - -21.3125, -9.8125, 1.3125, -1.8125, 1.3125, -3.3125, - 0.0000, -2.3125, 1.3125, -1.8125, 1.3125, -0.8125, - 1.0000, -1.0000, 0.0000, 1.0000, -1.0000, 0.0000, - -1.0000, 0.0000, 0.0000, 0.0000, 1.0000, -1.0000, - 1.0000, -1.0000, 0.0000, 0.0000, 0.0000, 0.0000, - -1.0000, 1.0000, -1.0000, 1.0000, 0.0000, 0.0000, - 0.0000, 0.0000, 0.0000, -1.0000, 1.0000, -1.0000, - 0.0000, 0.0000, 0.0000, 0.0000, -1.0000, 0.0000, - 0.0000, 0.0000, -0.3125, -0.3125, 0.0000, 0.0000, - 0.0000, -1.0000, 0.0000, 0.0000, 0.0000, 0.3125, - -0.3125, -0.3125, -0.3125, -0.3125, 0.3125, -0.3125, - -0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, - -0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, - 0.3125, 0.3125, 0.3125, -0.3125, -0.3125, -0.3125, - -0.3125, -0.3125, -0.3125, -0.3125, -0.3125, -0.3125, - 0.3125, -0.3125, -0.3125, 0.3125, -0.3125, -0.3125, - -0.3125, -0.3125, -0.3125, -0.3125, 0.3125, 0.3125, - -0.3125, 0.3125, 0.3125, 0.3125, -0.3125, 0.3125, - 0.3125, -0.3125, 0.3125, -0.3125, 0.3125, 0.3125, - -0.3125, 0.3125, 0.3125, 0.3125, -0.3125, -0.3125, - 0.3125, -0.3125, 0.3125, 0.3125, -0.3125, -0.3125, - -0.3125, -0.3125, 0.3125, 0.3125, 0.3125, -0.3125, - -0.3125, 0.3125, 0.3125, 0.3125, -0.3125, -0.3125, - 0.3125, 0.3125, -0.3125, -0.3125, -0.3125, -0.3125, - -0.3125, 0.3125, -0.3125, -0.3125 ], - - [ -21.3125, -49.3125, 15.3125, -170.0000, 165.0000, 398.0000, - -56.0000, 115.0000, -31.0000, 69.0000, 9.0000, 54.0000, - 15.0000, 63.0000, -10.0000, 11.0000, -6.0000, 10.0000, - -3.0000, 10.0000, 3.0000, 5.0000, 4.0000, 3.0000, - 4.0000, 2.0000, 1.0000, 0.0000, -1.0000, -1.0000, - 0.0000, 0.0000, 0.0000, 0.0625, 0.0625, -0.0625, - -0.0625, -0.0625, 0.0625, 0.0625, -0.0625, 0.0625, - -0.0625, 0.0625, -0.0625, -0.0625, 0.0625, -0.0625, - -0.0625, -0.0625, 0.0625, 0.0625, 0.0625, -0.0625, - -0.0625, -0.0625, -0.0625, 0.0625, -0.0625, 0.0625, - -0.0625, 0.0625, 0.0625, 0.0625, 0.0625, -0.0625, - 0.0625, 0.0625, 0.0625, -0.0625, -0.0625, -0.0625, - -0.0625, 0.0625, -0.0625, 0.0625, 0.0625, -0.0625, - 0.0625, 0.0625, 0.0625, -0.0625, 0.0625, -0.0625, - -0.0625, 0.0625, -0.0625, -0.0625, -0.0625, -0.0625, - -0.0625, 0.0625, -0.0625, 0.0625, -0.0625, -0.0625, - -0.0625, -0.0625, 0.0625, 0.0625, -0.0625, 0.0625, - -0.0625, -0.0625, 0.0625, -0.0625, -0.0625, -0.0625, - 0.0625, 0.0625, -0.0625, -0.0625, 0.0625, -0.0625, - -0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, - -0.0625, -0.0625, -0.0625, 0.0625, -0.0625, 0.0625, - 0.0625, 0.0625, -0.0625, 0.0625, -0.0625, -0.0625, - -0.0625, 0.0625, -0.0625, -0.0625, -0.0625, 0.0625, - -0.0625, -0.0625, -0.0625, 0.0625, 0.0625, 0.0625, - -0.0625, -0.0625, 0.0625, -0.0625, 0.0625, 0.0625, - 0.0625, 0.0625, 0.0625, -0.0625, 0.0625, 0.0625, - 0.0625, -0.0625, 0.0625, 0.0625 ] - -]) - -X_HAT_Q_7M5 = np.array([ - - [ -7.3125, 8.3125, -31.3125, -58.8125, 3.3125, 33.8125, - -2.8125, 1.3125, 9.3125, -11.8125, -3.0000, 2.0000, - -1.0000, 1.0000, 2.0000, -1.0000, -1.0000, 0.0000, - -1.0000, 1.0000, 0.0000, 0.0000, 1.0000, -1.0000, - 0.0000, 0.0000, -1.0000, 1.0000, 0.0000, -1.0000, - 1.0000, 0.0000, 0.0000, 0.2500, -0.2500, 0.0000, - 0.0000, -1.0000, 1.0000, 0.0000, 0.0000, 1.0000, - 0.0000, 0.0000, 0.0000, -1.0000, 0.0000, 0.0000, - -0.2500, 0.2500, 0.2500, 0.2500, -0.2500, 0.2500, - 0.2500, 0.2500, -0.2500, 0.0000, 0.0000, -1.0000, - 0.0000, 0.0000, 0.2500, 0.2500, -0.2500, -0.2500, - 0.2500, 0.2500, 0.2500, -0.2500, -0.2500, 0.2500, - -0.2500, 0.2500, -0.2500, 0.2500, -0.2500, -0.2500, - -0.2500, -0.2500, -0.2500, -0.2500, 0.2500, -0.2500, - 0.2500, 0.2500, -0.2500, -0.2500, 0.2500, -0.2500, - 0.2500, 0.2500, -0.2500, -0.2500, 0.2500, -0.2500, - 0.2500, -0.2500, 0.2500, 0.2500, 0.2500, 0.2500, - 0.2500, -0.2500, -0.2500, -0.2500, 0.2500, 0.2500, - 0.2500, 0.2500, 0.2500, -0.2500, -0.2500, -0.2500, - 0.2500, 0.2500, 0.2500, -0.2500, 0.2500, 0.2500 ], - - [ 3.8125, -21.8125, 72.3125, -408.3125, -88.3125, -35.3125, - 46.3125, -45.0000, -19.0000, -2.0000, -4.0000, 5.0000, - 3.0000, 3.0000, -1.0000, 2.0000, 0.0000, 4.0000, - -1.0000, 0.0000, -1.0000, 0.0000, 0.0000, -0.1250, - -0.1250, 0.1250, -0.1250, -0.1250, 0.1250, -0.1250, - -0.1250, -0.1250, -0.1250, -0.1250, 0.1250, 0.1250, - -0.1250, -0.1250, 0.1250, -0.1250, 0.1250, -0.1250, - -0.1250, 0.1250, 0.1250, -0.1250, -0.1250, 0.1250, - -0.1250, -0.1250, -0.1250, 0.1250, -0.1250, 0.1250, - -0.1250, -0.1250, 0.1250, -0.1250, 0.1250, -0.1250, - -0.1250, 0.1250, -0.1250, -0.1250, -0.1250, -0.1250, - -0.1250, -0.1250, -0.1250, 0.1250, -0.1250, 0.1250, - 0.1250, 0.1250, -0.1250, -0.1250, -0.1250, -0.1250, - 0.1250, 0.1250, 0.1250, 0.1250, 0.1250, 0.1250, - -0.1250, -0.1250, -0.1250, 0.1250, 0.1250, -0.1250, - -0.1250, -0.1250, -0.1250, -0.1250, -0.1250, 0.1250, - 0.1250, -0.1250, 0.1250, 0.1250, 0.1250, -0.1250, - -0.1250, -0.1250, -0.1250, 0.1250, -0.1250, 0.1250, - -0.1250, -0.1250, -0.1250, -0.1250, 0.1250, 0.1250, - -0.1250, 0.1250, 0.1250, 0.1250, -0.1250, -0.1250 ] - -]) - -X_HAT_Q = [ X_HAT_Q_7M5, X_HAT_Q_10M ] - -### C.4.1.6 TNS - -X_HAT_TNS_10M = np.array([ - - [ 0.0000000e+00, 2.5363181e+03, -2.0837409e+03, 6.6849426e+03, - -7.4392379e+03, -1.3473601e+04, -1.2257300e+02, -1.7820228e+03, - -1.8574523e+03, 0.0000000e+00, -3.1397544e+03, 1.0277274e+03, - -3.2151839e+03, 7.6090367e+02, -1.9466503e+03, -5.2445445e+02, - 3.3140414e+02, -1.8519794e+03, 1.7920998e+03, -2.1685321e+03, - 1.8597265e+03, -1.3374728e+03, 7.4531009e+02, 1.3315563e+02, - -6.0572955e+02, 1.0738661e+03, -1.2042433e+03, 1.2934874e+03, - -1.0948115e+03, 6.2875792e+02, -2.6176578e+02, -3.3286816e+02, - 6.3874781e+02, -9.2546646e+02, 1.0536075e+03, -1.0082162e+03, - 8.4609116e+02, -5.3643862e+02, 8.6016577e+01, 3.1548104e+02, - -6.4537299e+02, 7.8414243e+02, -9.2031551e+02, 8.4727748e+02, - -7.1936859e+02, 4.6589807e+02, -6.4881797e+01, -2.6457448e+02, - 5.6215195e+02, -6.6813432e+02, 6.6226333e+02, -6.5474860e+02, - 5.2409793e+02, -4.0142502e+02, 6.3505532e+01, 1.7235901e+02, - -4.1924611e+02, 5.0550392e+02, -6.5734435e+02, 5.0345309e+02, - -3.6608788e+02, 8.0016434e+01, 9.3237184e+01, -3.5017721e+02, - 4.2795992e+02, -4.6886670e+02, 3.7402812e+02, -3.7888490e+02, - 1.5291801e+02, -1.5802320e+01, -1.9719846e+02, 3.4187888e+02, - -4.2748515e+02, 3.5181826e+02, -3.0466662e+02, 7.6284275e+01, - 8.7663093e+01, -2.9659233e+02, 3.1030268e+02, -2.9594060e+02, - 2.6439080e+02, -9.3629481e+01, 5.7399177e+01, 1.6375927e+02, - -2.3208956e+02, 3.5517121e+02, -2.5708880e+02, 2.5690950e+02, - -5.2915469e+01, 2.3237996e+01, 1.8246977e+02, -1.5537990e+02, - 2.8029628e+02, -2.5001493e+02, 1.6287623e+02, -1.2710806e+02, - -6.9041960e+01, 5.1949460e+01, -2.3006446e+02, 1.3249613e+02, - -2.3061667e+02, 6.5507752e+01, -6.6442896e+00, -1.4373816e+02, - 1.3523410e+02, -1.2379774e+02, 5.2635973e+01, -6.1214557e+01, - -4.6571211e+01, 6.8132465e+00, -1.2664460e+02, 3.6959535e+01, - -3.5846511e+01, 2.8934234e+01, -4.3948154e+01, 8.1935863e+01, - 7.4660900e+00, 5.1207805e+01, -2.1748068e+01, 8.5958555e+01, - 4.9435547e+00, -4.1272410e+01, 1.2552229e+02, -1.6625839e+02, - 1.9307762e+02, -1.0613596e+02, 1.4547859e+01, 1.0890433e+02, - -1.0539493e+02, 1.9916467e+02, -1.9460994e+02, 1.3162563e+02, - -2.6679242e+01, -1.0641065e+02, 1.9984677e+02, -1.8499813e+02, - 1.3746427e+02, -1.2384807e+02, -4.8113073e+00, -1.1154394e+01, - -4.8901484e+01, 9.9602073e+01, -6.2727442e+01, 4.0646873e+01, - -3.8839607e+01, 5.5618701e+01, 1.5609019e+01, 2.6413984e+01, - -1.3661998e+01, -2.1935131e+01, 7.0604596e+01, -3.6013874e+01, - -5.2534512e+00, -1.9095831e+01, -5.9462211e+01, -2.0474437e+01, - -8.2457334e+01, 6.6458037e+01, -1.3905842e+02, 4.4992015e+01 ], - - [ -4.4674836e+02, -1.0336788e+03, 3.2097756e+02, -3.5635060e+03, - 3.4586970e+03, 8.3427964e+03, -1.1738608e+03, 2.4106070e+03, - -6.4981580e+02, 1.4463642e+03, 1.8865620e+02, 1.1319372e+03, - 3.1442700e+02, 1.4722656e+03, 5.9737149e+02, 9.6658866e+02, - 4.9169825e+02, 6.7177464e+02, 1.9327293e+02, 1.5499589e+02, - -2.1600722e+01, -9.8228391e+01, -1.2744379e+02, -1.7269979e+02, - -8.5793205e+01, -7.4701778e+01, -2.2833266e+01, 8.7668786e-01, - 1.4493209e+01, 2.7797597e+01, 4.0794920e+01, 4.3722928e+01, - 3.6950947e+01, 2.9794074e+01, 2.0218141e+01, 7.2233914e+00, - -4.3603335e+00, -1.3552659e+01, -1.6604838e+01, -1.8237845e+01, - -1.9241801e+01, -1.3923796e+01, -1.1242668e+01, -3.6760056e+00, - -1.1829705e+00, 2.5681718e+00, 7.2841081e+00, 6.6584846e+00, - 6.5203815e+00, 4.4803237e+00, 5.1830531e+00, 3.8023813e+00, - 2.5801707e+00, -8.9194181e-01, -2.7289508e+00, -4.3183797e+00, - -5.5686696e+00, -3.5658387e+00, -5.0013288e+00, -1.5969716e+00, - -2.5434186e+00, 1.0495670e+00, 2.5178803e+00, 4.0287891e+00, - 5.1309495e+00, 2.8569829e+00, 4.5137803e+00, 3.7678816e+00, - 3.5274736e+00, 2.1055313e-01, -1.4896329e+00, -3.0388583e+00, - -4.4849681e+00, -2.7741285e+00, -4.6088456e+00, -1.5252078e+00, - -1.4816216e-01, -7.4985193e-01, 2.1073955e+00, 3.0534784e+00, - 4.4307001e+00, 2.0418555e+00, 3.6512371e+00, 8.8259920e-01, - -5.5756792e-01, 2.4731249e-01, -2.4585823e+00, -3.1307473e+00, - -4.3178686e+00, -4.4328370e+00, -4.5859669e+00, -1.9461803e+00, - -2.7535202e+00, 5.2435412e-01, -5.7680820e-01, -1.1178729e-01, - -4.7067976e-01, -9.7145273e-01, 1.1713253e+00, 1.5417023e+00, - -6.2164141e-02, 1.8196547e+00, -3.3253562e-01, -8.7085257e-01, - 4.0545492e-01, -1.6971448e+00, -2.1315433e+00, -3.1522747e+00, - -7.0840626e-01, 1.9820684e-01, -1.2521487e+00, -1.2659519e+00, - 9.9900232e-01, -5.5880815e-01, -1.1085204e+00, 6.9059170e-01, - 1.6309021e+00, 2.4853740e+00, 2.8911996e+00, 3.6269550e+00, - 1.3909661e+00, 9.7770819e-02, -1.4853328e+00, -1.9863830e-01, - -2.7510985e+00, -8.4492066e-01, -1.7063127e-01, 1.1338053e+00, - -4.4636302e-01, 1.7476214e+00, -3.9440033e-02, -6.3944530e-01, - -1.7198507e+00, 7.4867347e-02, -1.8649133e+00, -2.4597157e+00, - -2.9678215e+00, -5.7798031e-01, -2.1073509e+00, -2.2439980e+00, - -2.4007588e+00, 2.2681540e-01, 1.3649713e+00, 2.4256778e+00, - 9.1907814e-01, 4.7699713e-01, 2.1704836e+00, -3.5175645e-01, - 1.3125148e+00, 1.2589840e+00, 2.0656111e+00, 2.3990940e+00, - 2.6834440e+00, 6.0589675e-01, 1.9858819e+00, 1.9373749e+00, - 2.1901227e+00, -3.8495770e-01, 1.1720109e+00, 1.3860966e+00 ] - -]) - -X_HAT_TNS_7M5 = np.array([ - - [ -1.3003668e+03, 1.4781948e+03, -5.5682374e+03, -1.0458506e+04, - 5.8905505e+02, 6.0128073e+03, -5.0014108e+02, 2.3339917e+02, - 1.6560227e+03, -2.1005926e+03, 9.8231590e+02, 6.5472037e+02, - -1.8816616e+03, 1.9995050e+03, -5.2483056e+02, -1.1296152e+03, - 1.8917056e+03, -1.4074840e+03, 7.3771850e+01, 1.1607281e+03, - -1.4654795e+03, 9.0328961e+02, 1.8790564e+02, -1.0278688e+03, - 1.0629204e+03, -5.3634594e+02, -3.2451913e+02, 9.0207993e+02, - -8.0267777e+02, 1.2277267e+02, 5.5484886e+02, -6.8584739e+02, - 4.1901310e+02, 7.2779950e+01, -4.3460765e+02, 4.5133152e+02, - -2.1578787e+02, -2.4628376e+02, 5.3756691e+02, -3.8146878e+02, - 3.4097661e+01, 4.5169871e+02, -5.0575362e+02, 2.7278971e+02, - 9.4493294e+01, -5.2727129e+02, 4.9704432e+02, -2.0290693e+02, - -2.1943755e+02, 4.6316564e+02, -3.5988557e+02, 1.5354987e+02, - 8.8971222e+01, -2.1177185e+02, 2.9338708e+02, -1.6015893e+02, - -3.0076244e+01, 1.4282354e+02, -1.8203323e+02, -3.8237583e+01, - 8.0989223e+01, -6.7911301e+01, 4.5876843e+01, 5.8160967e+01, - -1.2140603e+02, 3.0523591e+01, 1.0177828e+02, -7.1769925e+01, - 6.9697281e+01, -4.4342614e+01, -7.7392269e+01, 1.5965917e+02, - -1.5467801e+02, 8.0965471e+01, 5.9745822e+00, -7.8890418e+01, - 9.3802490e+01, -1.3176806e+02, 3.1336676e+01, 5.8640239e-01, - -1.0941547e+02, 8.4322101e+01, -1.0231229e+01, -7.6312076e+01, - 1.2996536e+02, -2.7610121e+01, -8.9190623e+01, 7.8060953e+01, - 6.1715955e+00, -9.5954760e+01, 1.3405798e+02, -1.2502304e+01, - -1.3552601e+02, 1.1952233e+02, -6.4806966e+00, -1.2142849e+02, - 1.8115437e+02, -1.4257871e+02, 3.1225251e+01, 1.6033227e+02, - -1.6511810e+02, 1.5240738e+02, 1.2638046e+01, -1.6469393e+02, - 1.4205406e+02, -1.1641621e+02, 4.7933541e+01, 9.6516025e+01, - -1.1306054e+02, 1.3942714e+02, -2.5241905e+01, -9.3530513e+01, - 8.8433097e+01, -1.0959238e+02, 8.7282861e+01, 3.9977748e+01, - -7.0411977e+01, 4.1780370e+01, 1.4511943e+01, 3.1125577e+01 ], - - [ 6.7796903e+01, -3.8788720e+02, 1.2859183e+03, -7.2609371e+03, - -1.5704430e+03, -6.2795492e+02, 8.2356565e+02, -8.0022573e+02, - -3.3787309e+02, -3.5565588e+01, -1.0363528e+02, 3.3897199e+01, - 1.9043187e+02, 1.7876914e+02, -1.5669449e+01, -1.4678018e+02, - -1.0987901e+02, 3.8138527e+01, 7.5635735e+01, 2.8493842e+01, - -9.6336587e+00, -2.2372156e+01, -1.9441869e+01, -2.6295536e+01, - -6.7279947e+00, 3.2810187e+01, 3.3795132e+01, 2.0377831e+00, - -2.2847912e+01, -2.2110999e+01, -7.4749335e+00, 8.1844245e-01, - 6.9094406e+00, 1.1427591e+01, 1.0664575e+01, 2.5808397e+00, - -1.1296056e+01, -1.5517110e+01, -3.3427801e+00, 6.2108447e+00, - 1.0440121e+01, 4.7195530e+00, -4.6830353e+00, -4.3321706e+00, - -4.2308894e-01, -6.6286888e-01, -3.0541198e+00, 1.0803641e+00, - 3.4706447e+00, -1.0277278e+00, -5.8300676e+00, -1.2004259e+00, - 2.9511818e+00, 4.4258015e+00, -1.2798751e-01, -5.6192448e+00, - -1.1434112e+00, 2.9285732e-01, 2.3558315e+00, 8.5236355e-01, - -3.6033829e+00, 3.6155080e-01, -1.9369648e-02, -3.0335453e+00, - -3.9032015e+00, -3.0556779e+00, 3.9409059e-01, 3.5833234e-01, - -1.1380321e+00, 3.0590734e+00, 2.1256269e+00, 1.1948865e+00, - 1.8418728e+00, 1.9339640e+00, -1.8934727e+00, -7.8211470e+00, - -7.2315006e+00, -1.6085474e+00, 7.0887341e+00, 1.1289772e+01, - 7.3233713e+00, 5.9236776e-01, -4.6290981e+00, -4.8012930e+00, - -5.3731448e+00, -4.9951949e+00, -1.0331793e+00, 6.8575568e+00, - 1.1172332e+01, 2.1481470e+00, -9.4111289e+00, -1.2048567e+01, - -6.2321457e+00, 1.2834480e+00, 4.2595916e+00, 8.2235361e+00, - 9.4292179e+00, -8.2653408e-01, -7.7277654e+00, -5.0381286e+00, - 2.5809009e+00, 2.9671834e+00, -3.1758077e+00, -4.8014638e+00, - -2.4972384e+00, 3.7424503e+00, 3.1651108e+00, 2.1258770e+00, - -3.9826224e-01, -5.5310115e+00, -6.7195904e+00, -4.6113744e+00, - 4.7359889e+00, 1.1737180e+01, 4.3792994e+00, -2.4150647e+00, - -3.2444202e+00, -3.3837188e-01, -2.0142283e+00, -6.2230109e+00 ] - -]) - -X_HAT_TNS = [ X_HAT_TNS_7M5, X_HAT_TNS_10M ] - -X_HAT_F_48K_10M = np.array([ - - 9.4517170e+02, 6.1123091e+02, 2.6864344e+03, -9.2131878e+02, - 3.9506388e+03, -1.6369062e+03, 2.4082498e+04, -3.0114303e+02, - -7.0038117e+03, -5.0717257e+03, -4.3561383e+03, -4.8809024e+03, - -2.4479052e+03, -6.2613898e+01, 2.0513506e+03, -1.4311748e+02, - 1.4311748e+02, -9.0641071e+02, 9.5411654e+01, -1.2880573e+03, - 5.2476410e+02, -1.1926457e+03, 4.7705827e+01, -9.5411654e+01, - 3.8164662e+02, 9.5411654e+01, 2.3852913e+02, 9.5411654e+01, - 9.5411654e+01, -9.5411654e+01, -1.9082331e+02, -1.9082331e+02, - 0.0000000e+00, 0.0000000e+00, -4.7705827e+02, 5.7246992e+02, - 2.8623496e+02, 3.3394079e+02, -4.7705827e+01, -9.5411654e+01, - -9.5411654e+01, -9.5411654e+01, -9.5411654e+01, 0.0000000e+00, - 0.0000000e+00, 2.3852913e+02, 4.7705827e+01, 8.1099906e+02, - -5.2476410e+02, 0.0000000e+00, -9.5411654e+01, 9.5411654e+01, - -1.9082331e+02, -4.7705827e+01, -9.5411654e+01, 1.4311748e+02, - 4.7705827e+01, 9.5411654e+01, 0.0000000e+00, 0.0000000e+00, - -2.3852913e+02, -9.5411654e+01, -2.8623496e+02, -3.3394079e+02, - -1.4311748e+02, -4.7705827e+01, 4.7705827e+01, 4.7705827e+01, - 1.9082331e+02, 2.3852913e+02, 9.5411654e+01, 0.0000000e+00, - -9.5411654e+01, -1.9082331e+02, -1.9082331e+02, -9.5411654e+01, - -1.4311748e+02, 4.7705827e+01, 4.7705827e+01, 2.8623496e+02, - 1.4311748e+02, 2.3852913e+02, 1.9082331e+02, 1.4311748e+02, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, -4.7705827e+01, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, -4.7705827e+01, - 4.7705827e+01, -2.3852913e+02, 0.0000000e+00, -9.5411654e+01, - -2.8623496e+02, -2.3852913e+02, -4.7705827e+01, -4.7705827e+01, - 0.0000000e+00, 0.0000000e+00, -4.7705827e+01, 4.7705827e+01, - -4.7705827e+01, -9.5411654e+01, -4.7705827e+01, -4.7705827e+01, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 4.7705827e+01, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, -4.7705827e+01, -4.7705827e+01, 0.0000000e+00, - 0.0000000e+00, 4.7705827e+01, 0.0000000e+00, -4.7705827e+01, - 0.0000000e+00, -4.7705827e+01, 1.4311748e+02, -9.5411654e+01, - -4.7705827e+01, 4.7705827e+01, -4.7705827e+01, -4.7705827e+01, - 4.7705827e+01, 4.7705827e+01, 0.0000000e+00, 9.5411654e+01, - -1.9082331e+02, 9.5411654e+01, 1.9082331e+02, -9.5411654e+01, - -9.5411654e+01, 1.9082331e+02, -1.9082331e+02, 9.5411654e+01, - 4.7705827e+01, 0.0000000e+00, -4.7705827e+01, 0.0000000e+00, - 0.0000000e+00, 4.7705827e+01, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 5.9632284e+00, 5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, -5.9632284e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 4.7705827e+01, - -4.7705827e+01, -4.7705827e+01, 0.0000000e+00, 0.0000000e+00, - -4.7705827e+01, 0.0000000e+00, 4.7705827e+01, 0.0000000e+00, - 0.0000000e+00, -4.7705827e+01, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 4.7705827e+01, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 4.7705827e+01, 0.0000000e+00, -4.7705827e+01, - -4.7705827e+01, -4.7705827e+01, -4.7705827e+01, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 4.7705827e+01, 4.7705827e+01, - 4.7705827e+01, 0.0000000e+00, 0.0000000e+00, -4.7705827e+01, - -9.5411654e+01, -9.5411654e+01, -9.5411654e+01, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 9.5411654e+01, - 4.7705827e+01, 4.7705827e+01, 4.7705827e+01, 4.7705827e+01, - 0.0000000e+00, 0.0000000e+00, -4.7705827e+01, -4.7705827e+01, - -4.7705827e+01, 0.0000000e+00, -4.7705827e+01, -4.7705827e+01, - -4.7705827e+01, 0.0000000e+00, -4.7705827e+01, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 4.7705827e+01, 4.7705827e+01, 0.0000000e+00, - 0.0000000e+00, 4.7705827e+01, -4.7705827e+01, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, -4.7705827e+01, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, -5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 4.7705827e+01, 0.0000000e+00, - 4.7705827e+01, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - -5.9632284e+00, 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 4.7705827e+01, -4.7705827e+01, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, -5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, 5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, -5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, - -5.9632284e+00, -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, -5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, -5.9632284e+00, 5.9632284e+00, - 5.9632284e+00, 5.9632284e+00, 5.9632284e+00, -5.9632284e+00 - -]) - -RC_ORDER_48K_10M = np.array([ 4, 5 ]) - -RC_I_1_48K_10M = np.array([ 3, 10, 10, 9, 8, 8, 8, 8 ]) -RC_I_2_48K_10M = np.array([ 4, 9, 11, 9, 9, 8, 8, 8 ]) - -X_HAT_TNS_48K_10M = np.array([ - - 9.4517170e+02, 6.1123091e+02, 2.6864344e+03, -9.2131878e+02, - 3.9506388e+03, -1.6369062e+03, 2.4082498e+04, -3.0114303e+02, - -7.0038117e+03, -5.0717257e+03, -4.3561383e+03, -4.8809024e+03, - -2.4479052e+03, -2.2398317e+03, -3.1132766e+01, 2.0090579e+02, - 1.1862042e+03, 5.7338427e+02, 6.1759350e+02, -9.7469088e+02, - -6.4374897e+02, -2.0211697e+03, -1.7062857e+03, -1.3890132e+03, - -4.2328832e+02, 3.5577372e+02, 1.1106915e+03, 1.4302110e+03, - 1.4201992e+03, 9.4898618e+02, 2.3607533e+02, -4.7224392e+02, - -8.4841824e+02, -9.9022181e+02, -1.3448133e+03, -4.1592231e+02, - 2.0637545e+02, 9.3371650e+02, 1.1146864e+03, 9.6858809e+02, - 5.9597157e+02, 9.1928376e+01, -3.7626331e+02, -6.1986247e+02, - -6.9177579e+02, -3.4667628e+02, -1.0196915e+02, 9.4981560e+02, - 5.0772033e+02, 5.6925480e+02, 2.7206846e+02, 8.9632931e+01, - -3.0001737e+02, -4.6633999e+02, -5.8788470e+02, -3.5775041e+02, - -1.5049111e+02, 1.4316978e+02, 2.9621193e+02, 3.6240991e+02, - 9.5814668e+01, -7.8107250e+01, -4.7386669e+02, -8.4266712e+02, - -9.1319744e+02, -7.8870946e+02, -4.4400310e+02, -5.1962032e+01, - 4.4241817e+02, 8.5744581e+02, 9.6559775e+02, 8.1789237e+02, - 4.2722231e+02, -1.1744557e+02, -6.0875733e+02, -8.7077276e+02, - -9.9676704e+02, -7.3639748e+02, -3.7055666e+02, 2.7449836e+02, - 6.9342929e+02, 1.0695021e+03, 1.1847878e+03, 1.0572091e+03, - 6.5809175e+02, 2.0789887e+02, -2.0474320e+02, -5.3854975e+02, - -6.4606559e+02, -5.9469535e+02, -4.1519106e+02, -2.2005318e+02, - 6.5763023e+01, -1.8180468e+00, 1.1794585e+02, 3.7652871e+01, - -2.6013985e+02, -4.9007184e+02, -5.2184675e+02, -4.8856445e+02, - -3.1503130e+02, -1.1131138e+02, 2.8240046e+01, 2.1696333e+02, - 2.2485577e+02, 1.2779759e+02, 2.8796892e+01, -9.8980705e+01, - -1.5201103e+02, -1.6768213e+02, -1.4166855e+02, -3.8081735e+01, - 1.9957705e+01, 7.3452728e+01, 9.9166879e+01, 9.4204641e+01, - 7.0145854e+01, -1.3744063e+01, -9.3049197e+01, -1.1359718e+02, - -1.1480749e+02, -3.8801493e+01, -5.6439787e-01, -7.4563180e+00, - 2.1645294e+01, -2.1494684e+01, 1.2628610e+02, 1.3469076e+01, - -3.1053646e+01, 1.0922488e+00, -7.3585334e+01, -1.0982479e+02, - -4.7186648e+01, 1.5142158e+01, 4.5632808e+01, 1.6549594e+02, - -3.6083949e+01, 5.8172372e+01, 2.0212810e+02, 6.2799792e+01, - -3.6264662e+01, 1.1267918e+02, -1.4073978e+02, -3.0415441e+01, - 1.2090131e+00, 5.3715012e+00, -1.1377286e+01, -4.5565675e+00, - -5.6917226e+00, 4.3600122e+01, 4.1505158e+01, 4.0418175e+01, - 3.0433405e+01, 1.8807364e+01, 8.6851800e+00, 1.3063317e+00, - -1.6374357e+00, -5.1287186e-01, -8.3181817e+00, -1.3316624e+01, - -1.1754958e+01, -9.3082910e+00, -4.7125436e+00, 4.7799716e+01, - -1.4779469e+00, -4.4671371e+01, -4.7792557e+01, -5.2664965e+01, - -8.7747532e+01, -6.2908560e+01, 7.0728829e+00, 2.9933713e+01, - 5.4684947e+01, 1.2283279e+01, 6.0871825e+00, -9.7832692e+00, - -2.0805101e+01, 2.5453410e+01, 2.2568456e+01, 2.6671505e+01, - 2.3653407e+01, 6.0861792e+01, 4.5907030e+01, -1.3920574e+01, - -7.4036162e+01, -1.3377313e+02, -1.7526999e+02, -1.4452509e+02, - -9.6576994e+01, -3.4117396e+01, 7.2828977e+01, 1.5570493e+02, - 2.1295914e+02, 1.8790695e+02, 1.3270346e+02, 9.1184381e+00, - -1.5641394e+02, -2.9335242e+02, -3.8817395e+02, -3.2871789e+02, - -2.0655338e+02, -4.3550786e+01, 1.0968391e+02, 3.0824064e+02, - 3.3663279e+02, 3.0642586e+02, 1.8519446e+02, 5.7390329e+01, - -1.1630607e+02, -2.0276872e+02, -2.7699576e+02, -2.4543885e+02, - -1.7669630e+02, -1.9362678e+01, 4.7199101e+01, 1.0516333e+02, - 8.6666990e+01, 8.8657037e+01, -1.5558419e+01, -3.6914314e+01, - -8.0595009e+01, -7.0566026e+01, -5.9248668e+01, -1.4894165e+01, - 1.6364229e+01, 9.4426516e+01, 1.2736629e+02, 9.8422987e+01, - 5.1256905e+01, 4.3261239e+01, -7.3161150e+01, -8.1108665e+01, - -9.8148881e+01, -5.9938566e+01, -2.8972996e+01, -2.3262373e+01, - 2.3557895e+01, 4.1063112e+01, 4.9456507e+01, 2.9572229e+01, - 2.1373324e+01, -1.2116045e+01, -1.7920284e+01, -2.5397799e+01, - -1.5011495e+01, -1.6604903e+01, 5.7220095e+00, 4.2124559e+00, - 9.1295553e+00, 2.0972476e+00, 1.0219314e+01, 1.7408319e+00, - 9.3716408e-01, -4.4755970e+00, 4.3615172e+01, 2.1619284e+01, - 7.0197660e+01, 2.9541340e+01, 2.1495384e+01, -1.5543427e+01, - -2.9701692e+01, -4.8601263e+01, -4.1417636e+01, -2.0218456e+01, - -4.1919983e+00, 1.0811220e+01, 1.8282903e+01, 2.9153799e+01, - 2.6637698e+01, 2.0822319e+01, -2.0049692e+00, -1.7515145e+01, - -1.8945085e+01, -2.6096971e+01, -1.0443081e+01, 2.8259408e+00, - 1.9054250e+01, 2.6408940e+01, 2.9532072e+01, 1.1442436e+01, - 7.5316255e+00, -3.0305702e+00, -5.1747435e+00, -1.8407036e+01, - -7.2025275e+00, -1.3142410e+00, -8.9104503e-01, -1.9580507e+00, - 9.0242278e+00, 5.0649445e-01, 9.0989185e+00, 8.4374358e+00, - 1.2180369e+01, 9.8043365e+00, 1.0390873e+01, -4.5184465e+00, - -3.0104815e-01, -1.3617490e+01, -2.8571680e+00, 4.7226441e-02, - 1.0968668e+01, 1.4263590e+01, 1.9054635e+01, 4.5694855e+00, - -5.1714614e+00, -5.6951038e+00, -1.5868058e+01, -6.3038212e+00, - 6.0252467e-01, 5.9026641e+00, 7.8745777e+00, 8.8744978e+00, - 5.3462027e+01, -1.8654382e+01, -4.3353244e+00, -2.6929767e+01, - -1.5311914e+01, -2.7217677e+01, 3.5149041e-01, -3.3211226e+00, - 7.7038597e+00, 2.4167585e+00, 3.1307056e+00, -6.1700798e+00, - -9.6229135e+00, -1.5399820e+01, -1.5266153e+01, -2.7143843e+00, - 8.4318705e+00, 1.8387062e+01, 1.1142869e+01, 1.6194808e+01, - -9.1085598e-01, -9.8865640e+00, -9.6606173e+00, -4.4966142e+00, - -1.0006828e+01, -8.3653492e+00, 3.2044245e+00, -2.9444546e-01, - 1.0908085e+01, 1.3460563e+01, 1.7296403e+01, 2.3331346e+00, - -6.4643323e+00, -1.8141900e+01, -2.2182809e+01, -1.1540102e+01, - 1.1288138e+00, 2.4890144e+00, 1.6559739e+01, 8.5186198e+00, - 1.5415016e+01, -1.5380758e+00, -8.2713929e+00, -8.0722274e+00, - -2.5013191e+00, -8.9116220e+00, -7.8813678e+00, -9.3233771e+00, - 3.7714591e+00, -1.8991746e+00, -8.2806999e-01, 5.9195021e+00, - 1.1264459e+01, 1.3340521e+01, 1.4254734e+01, 7.3923870e-01, - 2.7992830e+00, -1.2191542e+01, -4.1559084e+00, -1.4491802e+01, - -1.1202358e+01, -1.3530333e+01, -8.4296049e+00, -7.8650114e+00, - -4.0242598e+00, -3.9190447e+00, -3.2052868e+00, 6.8414475e+00, - 1.2298364e+01, 4.5966329e+00, -2.2198027e+00, 1.4780361e+00, - 2.6041179e+00, -5.9986780e+00, 1.8848742e+00, 5.1985761e+00, - 1.0933162e+01, 1.2576045e+01, 2.6295117e+00, -6.3792422e+00, - -3.2379866e+00, -1.0344676e+00, -7.5143096e+00, 2.5669904e+00, - 7.6423118e+00, 1.4123706e+01, 1.5442459e+01, 4.3051286e+00 - -]) - -### C.4.1.7 Spectral shaping - -X_HAT_SNS_10M = np.array([ - - [ 0.0000000e+00, 3.2120898e+04, -2.7432096e+04, 9.5098925e+04, - -1.1435865e+05, -2.2381382e+05, -1.8369247e+03, -2.0115639e+04, - -1.5792914e+04, 0.0000000e+00, -1.5609063e+04, 4.0875220e+03, - -1.0230315e+04, 1.9369297e+03, -4.1865185e+03, -1.0063143e+03, - 5.6734153e+02, -2.8286784e+03, 2.4858485e+03, -2.7806581e+03, - 2.2044492e+03, -1.4655656e+03, 7.9623905e+02, 1.4627465e+02, - -6.8421307e+02, 1.2472853e+03, -1.3595558e+03, 1.3417640e+03, - -1.0434807e+03, 5.9927829e+02, -2.2923931e+02, -2.9150665e+02, - 5.1660528e+02, -7.4849706e+02, 7.9101280e+02, -7.5693454e+02, - 5.8965376e+02, -3.7385221e+02, 5.5646432e+01, 2.0409315e+02, - -3.8684762e+02, 4.7002840e+02, -5.1019782e+02, 4.6970753e+02, - -3.6882983e+02, 2.3887213e+02, -3.0765937e+01, -1.2545710e+02, - 2.5752773e+02, -3.0607937e+02, 3.0617821e+02, -3.0270399e+02, - 2.4452840e+02, -1.8729289e+02, 2.9629779e+01, 8.1156654e+01, - -1.9740547e+02, 2.3802067e+02, -2.9662172e+02, 2.2717944e+02, - -1.6519442e+02, 3.2859099e+01, 3.8288258e+01, -1.4380181e+02, - 1.5993592e+02, -1.7522348e+02, 1.3978068e+02, -1.2885956e+02, - 5.2007743e+01, -5.3744028e+00, -6.3481105e+01, 1.1005588e+02, - -1.3761380e+02, 1.1149518e+02, -9.6552293e+01, 2.4175349e+01, - 2.7349618e+01, -9.2532521e+01, 9.6809951e+01, -9.2329191e+01, - 8.1204030e+01, -2.8757018e+01, 1.7629374e+01, 5.0296426e+01, - -6.9554039e+01, 1.0643991e+02, -7.7045965e+01, 7.6992232e+01, - -1.5336408e+01, 6.7350324e+00, 5.2884931e+01, -4.5033515e+01, - 7.8565630e+01, -7.0077921e+01, 4.5653385e+01, -3.5627746e+01, - -1.8715552e+01, 1.4082202e+01, -6.2364732e+01, 3.5916392e+01, - -6.2514422e+01, 1.6978510e+01, -1.7220883e+00, -3.7254517e+01, - 3.5050409e+01, -3.2086295e+01, 1.2895849e+01, -1.4997608e+01, - -1.1409978e+01, 1.6692500e+00, -3.1028013e+01, 8.5596145e+00, - -8.3018444e+00, 6.7010013e+00, -1.0178138e+01, 1.8975872e+01, - 1.6344865e+00, 1.1210482e+01, -4.7611165e+00, 1.8818163e+01, - 1.0822497e+00, -8.9424468e+00, 2.7196773e+01, -3.6023020e+01, - 4.1833912e+01, -2.2996359e+01, 3.1520683e+00, 2.4451081e+01, - -2.3663155e+01, 4.4716235e+01, -4.3693613e+01, 2.9552445e+01, - -5.9899945e+00, -2.4756795e+01, 4.6495022e+01, -4.3040437e+01, - 3.1981524e+01, -2.8813669e+01, -1.1193668e+00, -2.6891294e+00, - -1.1789293e+01, 2.4012319e+01, -1.5122490e+01, 9.7992507e+00, - -9.3635505e+00, 1.3408697e+01, 3.8993996e+00, 6.5986643e+00, - -3.4130004e+00, -5.4797703e+00, 1.7638234e+01, -8.9968811e+00, - -1.3124018e+00, -4.9433015e+00, -1.5392870e+01, -5.3001786e+00, - -2.1345573e+01, 1.7203866e+01, -3.5997789e+01, 1.1646997e+01 ], - - [ -6.2955623e+03, -1.4566565e+04, 5.0622202e+03, -7.0393645e+04, - 8.5577202e+04, 2.5855135e+05, -3.5335070e+04, 5.4655582e+04, - -1.1097295e+04, 1.8604727e+04, 1.7284056e+03, 6.9845121e+03, - 1.3066905e+03, 4.1207686e+03, 1.2132541e+03, 1.5347593e+03, - 6.1036346e+02, 6.5193569e+02, 1.5477285e+02, 1.0810302e+02, - -1.3121390e+01, -5.1968778e+01, -6.2665661e+01, -8.4220873e+01, - -4.1495195e+01, -3.5833798e+01, -1.0853816e+01, 4.1261732e-01, - 6.7539065e+00, 1.2953817e+01, 1.8822817e+01, 2.0173803e+01, - 1.6734007e+01, 1.3492868e+01, 8.9088009e+00, 3.1828720e+00, - -1.8693963e+00, -5.8104021e+00, -6.9265975e+00, -7.6077959e+00, - -7.9011791e+00, -5.7174692e+00, -4.5976263e+00, -1.5032819e+00, - -4.8178832e-01, 1.0459392e+00, 2.9544513e+00, 2.7006970e+00, - 2.6614506e+00, 1.8287519e+00, 2.1513094e+00, 1.5782394e+00, - 1.0890240e+00, -3.7646581e-01, -1.1518203e+00, -1.8534533e+00, - -2.3900791e+00, -1.5304619e+00, -2.1511073e+00, -6.8686891e-01, - -1.0939425e+00, 4.4580685e-01, 1.0694775e+00, 1.7112407e+00, - 2.1522574e+00, 1.1984063e+00, 1.8933761e+00, 1.5608228e+00, - 1.4612352e+00, 8.7220397e-02, -6.3880600e-01, -1.3031673e+00, - -1.9233091e+00, -1.2909908e+00, -2.1448096e+00, -7.0978302e-01, - -7.4823965e-02, -3.7868573e-01, 1.0642643e+00, 1.5420494e+00, - 2.4281898e+00, 1.1190134e+00, 2.0010149e+00, 4.8369747e-01, - -3.1302463e-01, 1.3884389e-01, -1.3802746e+00, -1.7576352e+00, - -2.3441435e+00, -2.4065591e+00, -2.4896924e+00, -1.0565690e+00, - -1.4455632e+00, 2.7527927e-01, -3.0281700e-01, -5.8686912e-02, - -2.3895075e-01, -4.9317896e-01, 5.9464861e-01, 7.8267846e-01, - -3.1558969e-02, 8.7786664e-01, -1.6042710e-01, -4.2013050e-01, - 1.9560599e-01, -8.1876351e-01, -9.6031363e-01, -1.4201787e+00, - -3.1915476e-01, 8.9297143e-02, -5.6412436e-01, -5.3261760e-01, - 4.2030523e-01, -2.3510454e-01, -4.6638224e-01, 2.9054917e-01, - 6.4077498e-01, 9.7649360e-01, 1.1359409e+00, 1.4250163e+00, - 5.4650505e-01, 3.8070710e-02, -5.7836964e-01, -7.7347222e-02, - -1.0712427e+00, -3.2900133e-01, -6.6441638e-02, 4.6435375e-01, - -1.8280947e-01, 7.1574422e-01, -1.6152798e-02, -2.6188697e-01, - -7.0437063e-01, 3.2250148e-02, -8.0333729e-01, -1.0595566e+00, - -1.2784303e+00, -2.4897303e-01, -9.0777061e-01, -1.0166946e+00, - -1.0877187e+00, 1.0276390e-01, 6.1843142e-01, 1.0990088e+00, - 4.1640936e-01, 2.1611445e-01, 1.0343162e+00, -1.6762504e-01, - 6.2546212e-01, 5.9995270e-01, 9.8434057e-01, 1.1432576e+00, - 1.2787609e+00, 3.0368561e-01, 9.9535729e-01, 9.7104477e-01, - 1.0977262e+00, -1.9294725e-01, 5.8743153e-01, 6.9473485e-01 ] -]) - -X_HAT_SNS_7M5 = np.array([ - - [ -2.7097714e+04, 3.0803384e+04, -1.0482091e+05, -1.6066697e+05, - 7.3848155e+03, 6.1515964e+04, -4.0837362e+03, 1.4874654e+03, - 8.2375155e+03, -8.1555674e+03, 3.0555770e+03, 1.6748461e+03, - -3.9585632e+03, 3.4593583e+03, -7.9211504e+02, -1.5776652e+03, - 2.4448549e+03, -1.6832871e+03, 8.3907446e+01, 1.2903730e+03, - -1.5923535e+03, 9.5931605e+02, 1.9128372e+02, -9.8357603e+02, - 9.5609940e+02, -4.5350218e+02, -2.5320962e+02, 6.3762292e+02, - -5.1397160e+02, 7.1216163e+01, 3.1269611e+02, -4.0275234e+02, - 2.5638994e+02, 4.6403201e+01, -2.7843009e+02, 2.8914418e+02, - -1.3395170e+02, -1.5288222e+02, 3.2333756e+02, -2.2944713e+02, - 1.9872415e+01, 2.6325395e+02, -2.8392752e+02, 1.5314277e+02, - 5.0798626e+01, -2.8345564e+02, 2.5587542e+02, -1.0445526e+02, - -1.0817500e+02, 2.2832437e+02, -1.6921255e+02, 7.2196740e+01, - 3.9741076e+01, -9.4592848e+01, 1.2449531e+02, -6.7961530e+01, - -1.2124324e+01, 5.7574971e+01, -7.1197322e+01, -1.4955585e+01, - 3.1388922e+01, -2.6320323e+01, 1.7618904e+01, 2.2336595e+01, - -4.6625728e+01, 1.1616015e+01, 3.8732599e+01, -2.7312663e+01, - 2.6048066e+01, -1.6572229e+01, -2.8923924e+01, 5.8075573e+01, - -5.6263689e+01, 2.9450962e+01, 2.1151792e+00, -2.7929547e+01, - 3.3208863e+01, -4.5403546e+01, 1.0797732e+01, 2.0205768e-01, - -3.7035922e+01, 2.8542095e+01, -3.4631575e+00, -2.5611045e+01, - 4.3617589e+01, -9.2662146e+00, -2.9678561e+01, 2.5975116e+01, - 2.0536248e+00, -3.1929357e+01, 4.4228879e+01, -4.1248038e+00, - -4.4713214e+01, 3.9433226e+01, -2.1402050e+00, -4.0100915e+01, - 5.9824970e+01, -4.7085628e+01, 1.0420556e+01, 5.3506419e+01, - -5.5103555e+01, 5.0861706e+01, 4.2620261e+00, -5.5541010e+01, - 4.7905991e+01, -3.9259942e+01, 1.6335294e+01, 3.2891742e+01, - -3.8529956e+01, 4.7515440e+01, -8.6928230e+00, -3.2210096e+01, - 3.0454645e+01, -3.7741492e+01, 3.0058525e+01, 1.3912599e+01, - -2.4503972e+01, 1.4539927e+01, 5.0502807e+00, 1.0831968e+01 ], - - [ 3.8609917e+03, -2.2089936e+04, 6.2396694e+04, -2.5577568e+05, - -4.0161241e+04, -1.1658208e+04, 9.9426556e+03, -5.6272992e+03, - -1.3839628e+03, -8.4856310e+01, -1.6119528e+02, 3.8468595e+01, - 1.5768120e+02, 1.0800171e+02, -8.1867250e+00, -7.8607304e+01, - -6.0318312e+01, 2.1460378e+01, 4.3791334e+01, 1.7039175e+01, - -5.9501127e+00, -1.4271781e+01, -1.2583485e+01, -1.6962650e+01, - -4.3255972e+00, 2.1024124e+01, 2.1440266e+01, 1.2715073e+00, - -1.4021429e+01, -1.3345628e+01, -4.3592289e+00, 4.5305297e-01, - 3.6304646e+00, 5.6994442e+00, 5.3601809e+00, 1.2971700e+00, - -6.0746373e+00, -8.3445774e+00, -1.9233529e+00, 3.5735662e+00, - 6.4270894e+00, 2.9054250e+00, -2.9987419e+00, -2.7740687e+00, - -2.7396267e-01, -4.2922732e-01, -1.9998336e+00, 7.0742100e-01, - 2.2980847e+00, -6.8050918e-01, -3.7563574e+00, -7.7344365e-01, - 1.7803940e+00, 2.6700051e+00, -7.2296053e-02, -3.1741317e+00, - -6.0475055e-01, 1.5489233e-01, 1.2469224e+00, 4.5114909e-01, - -2.0399596e+00, 2.0468239e-01, -1.1728671e-02, -1.8368664e+00, - -2.3634589e+00, -1.9790219e+00, 2.5523434e-01, 2.3207537e-01, - -7.6437315e-01, 2.0546640e+00, 1.4277033e+00, 8.0700716e-01, - 1.2439713e+00, 1.3061682e+00, -1.2859071e+00, -5.3115466e+00, - -4.9111022e+00, -1.0984600e+00, 4.8408213e+00, 7.7096653e+00, - 4.8540011e+00, 3.9262706e-01, -3.0682108e+00, -2.9814266e+00, - -3.3365255e+00, -3.1018325e+00, -6.0106119e-01, 3.9894443e+00, - 6.4996032e+00, 1.2497035e+00, -5.1293438e+00, -6.5668257e+00, - -3.3967039e+00, 6.9951716e-01, 2.2622003e+00, 4.3673873e+00, - 5.0077054e+00, -4.3895891e-01, -4.1593548e+00, -2.7116978e+00, - 1.3891315e+00, 1.5970423e+00, -1.7323481e+00, -2.6191154e+00, - -1.3622003e+00, 2.0414418e+00, 1.7497613e+00, 1.1752440e+00, - -2.2017045e-01, -3.0576971e+00, -3.7647976e+00, -2.5836234e+00, - 2.6534415e+00, 6.5760121e+00, 2.4535983e+00, -1.3713128e+00, - -1.8422343e+00, -1.9213303e-01, -1.1437114e+00, -3.5335263e+00 ], -]) - -X_HAT_SNS = [ X_HAT_SNS_7M5, X_HAT_SNS_10M ] - -### C.4.1.8 MDCT - -T_HAT_MDCT_10M = np.array([ - - [ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - 6.1525095e-01, 1.7117620e+00, -1.6200436e-01, -2.1107548e+00, - 9.1636911e-01, 8.7583398e+00, 1.4291828e+01, 1.4615904e+01, - 1.9312730e+01, 2.2178311e+01, 2.1178760e+01, 1.9939021e+01, - 3.2745193e+01, 3.1385007e+01, 4.5642888e+01, 3.8185668e+01, - 4.3452271e+01, 3.0174130e+01, 2.7510416e+01, 3.9048290e+00, - -4.1911157e+00, -3.4032526e+01, -4.3089457e+01, -7.1817465e+01, - -7.3319439e+01, -1.0231340e+02, -8.2645833e+01, -1.0207070e+02, - -7.4253115e+01, -9.5269932e+01, -1.2210097e+02, -1.3216707e+02, - -1.2665681e+02, -1.6033791e+02, -1.3067613e+02, -1.8796611e+01, - 6.2097263e+01, 7.2290617e+00, -1.2550979e+02, -8.9649115e+01, - 7.6135408e+02, 2.7072170e+03, 6.1558256e+03, 9.6522574e+03, - 1.2566221e+04, 1.5421574e+04, 1.8329565e+04, 2.1102710e+04, - 2.3323039e+04, 2.5451924e+04, 2.7365468e+04, 2.8891223e+04, - 3.0341813e+04, 3.1380038e+04, 3.2134454e+04, 3.2606958e+04, - 3.2683895e+04, 3.2518324e+04, 3.2036626e+04, 3.1278795e+04, - 3.0136453e+04, 2.8694957e+04, 2.7009676e+04, 2.5075921e+04, - 2.2940269e+04, 2.0564299e+04, 1.7956441e+04, 1.5202722e+04, - 1.2352834e+04, 9.3639445e+03, 6.2714619e+03, 3.1112267e+03, - -1.0075267e+02, -3.3115389e+03, -6.4954073e+03, -9.6110111e+03, - -1.2594144e+04, -1.5477538e+04, -1.8214406e+04, -2.0797170e+04, - -2.3195615e+04, -2.5355124e+04, -2.7302557e+04, -2.8919494e+04, - -3.0273227e+04, -3.1357707e+04, -3.2152224e+04, -3.2625545e+04, - -3.2802109e+04, -3.2640407e+04, -3.2172861e+04, -3.1393517e+04, - -3.0316009e+04, -2.8922986e+04, -2.7290775e+04, -2.5351571e+04, - -2.3183937e+04, -2.0795771e+04, -1.8212609e+04, -1.5453610e+04, - -1.2543978e+04, -9.4923186e+03, -6.3663932e+03, -3.1740539e+03, - 4.2407582e+01, 3.2479359e+03, 6.4369448e+03, 9.5564107e+03, - 1.2589389e+04, 1.5494437e+04, 1.8238168e+04, 2.0814647e+04, - 2.3183440e+04, 2.5340307e+04, 2.7236643e+04, 2.8879098e+04, - 3.0219987e+04, 3.1304367e+04, 3.2073455e+04, 3.2541098e+04, - 3.2660415e+04, 3.2490788e+04, 3.2004309e+04, 3.1215306e+04, - 3.0131477e+04, 2.8751611e+04, 2.7114762e+04, 2.5198099e+04, - 2.3044166e+04, 2.0655799e+04, 1.8068458e+04, 1.5312555e+04, - 1.2400688e+04, 9.3834439e+03, 6.2670869e+03, 3.1043555e+03, - -9.0364008e+01, -3.2949280e+03, -6.4558716e+03, -9.5736656e+03, - -1.2593429e+04, -1.5487321e+04, -1.8231003e+04, -2.0808229e+04, - -2.3191386e+04, -2.5327915e+04, -2.7226934e+04, -2.8860268e+04, - -3.0235350e+04, -3.1313467e+04, -3.2092397e+04, -3.2585580e+04, - -3.2777259e+04, -3.2606534e+04, -3.2146234e+04, -3.1383325e+04, - -3.0295384e+04, -2.8926934e+04, -2.7297985e+04, -2.5343669e+04, - -2.3152305e+04, -2.0670493e+04, -1.7934304e+04, -1.4904360e+04, - -1.1690361e+04, -8.2034060e+03, -4.4966301e+03, -5.9716414e+02, - 3.3525737e+03, 7.3668269e+03, 1.1354417e+04, 1.5112467e+04, - 1.8623854e+04, 2.1896001e+04, 2.4687380e+04, 2.6938007e+04, - 2.8626837e+04, 2.9696113e+04, 3.0136274e+04, 2.9938040e+04, - 2.9086081e+04, 2.7633076e+04, 2.5690739e+04, 2.3353541e+04, - 2.0706676e+04, 1.7862611e+04, 1.4893850e+04, 1.1890794e+04, - 9.0400724e+03, 6.3496693e+03, 3.8416289e+03, 1.6255098e+03, - -2.6829587e+02, -1.8648283e+03, -3.1265144e+03, -4.0739027e+03, - -4.7217057e+03, -5.1308259e+03, -5.2994797e+03, -5.2717085e+03, - -5.0702632e+03, -4.7404796e+03, -4.2926332e+03, -3.7668674e+03, - -3.1863326e+03, -2.5717341e+03, -1.9487052e+03, -1.3380710e+03, - -7.5480786e+02, -2.1731911e+02, 2.6258546e+02, 6.7531993e+02, - 1.0134680e+03, 1.2732878e+03, 1.4518662e+03, 1.5497281e+03, - 1.5671087e+03, 1.5098872e+03, 1.3843562e+03, 1.1969411e+03, - 9.5570061e+02, 6.6987624e+02, 3.5217663e+02, 9.8694010e+00, - -3.4394935e+02, -6.9967997e+02, -1.0489605e+03, -1.3797643e+03, - -1.6859141e+03, -1.9573045e+03, -2.1892388e+03, -2.3761776e+03, - -2.5135134e+03, -2.6015039e+03, -2.6377063e+03, -2.6272971e+03, - -2.5708325e+03, -2.4734547e+03, -2.3405452e+03, -2.1774990e+03, - -1.9928710e+03, -1.7900465e+03, -1.5787667e+03, -1.3647693e+03, - -1.1565972e+03, -9.5713834e+02, -7.7246019e+02, -6.0536929e+02, - -4.5916520e+02, -3.3470350e+02, -2.3251725e+02, -1.5151486e+02, - -9.0224117e+01, -4.6447782e+01, -1.7377196e+01, -1.6206249e-01, - 8.2694380e+00, 1.0620902e+01, 9.2650945e+00, 5.7978679e+00 ], - - [ -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -5.8307275e+01, -1.5961611e+02, -3.2822433e+02, -5.8684193e+02, - -9.5063064e+02, -1.4274461e+03, -2.0154696e+03, -2.7009630e+03, - -3.4569464e+03, -4.2430564e+03, -5.0068652e+03, -5.6873576e+03, - -6.2169269e+03, -6.5268185e+03, -6.5539697e+03, -6.2419962e+03, - -5.5512117e+03, -4.4569448e+03, -2.9581517e+03, -1.0742654e+03, - 1.1530263e+03, 3.6594640e+03, 6.3646353e+03, 9.1749853e+03, - 1.1985116e+04, 1.4691422e+04, 1.7187008e+04, 1.9378907e+04, - 2.1179777e+04, 2.2522740e+04, 2.3359818e+04, 2.3657684e+04, - 2.3405693e+04, 2.2611255e+04, 2.1297773e+04, 1.9499385e+04, - 1.7264572e+04, 1.4646235e+04, 1.1703370e+04, 8.4960382e+03, - 5.0883571e+03, 1.5400010e+03, -2.0852434e+03, -5.7317898e+03, - -9.3443119e+03, -1.2867162e+04, -1.6250847e+04, -1.9448892e+04, - -2.2417993e+04, -2.5119550e+04, -2.7519523e+04, -2.9589531e+04, - -3.1306279e+04, -3.2653256e+04, -3.3615026e+04, -3.4186391e+04, - -3.4364519e+04, -3.4152077e+04, -3.3554064e+04, -3.2586709e+04, - -3.1263292e+04, -2.9603089e+04, -2.7630063e+04, -2.5371579e+04, - -2.2853607e+04, -2.0109903e+04, -1.7174483e+04, -1.4079475e+04, - -1.0861936e+04, -7.5574424e+03, -4.2020683e+03, -8.2997756e+02, - 2.5249878e+03, 5.8295399e+03, 9.0523976e+03, 1.2164914e+04, - 1.5141205e+04, 1.7954597e+04, 2.0583186e+04, 2.3005366e+04, - 2.5205897e+04, 2.7165327e+04, 2.8871803e+04, 3.0312108e+04, - 3.1479927e+04, 3.2363955e+04, 3.2960351e+04, 3.3265900e+04, - 3.3277052e+04, 3.2993786e+04, 3.2419707e+04, 3.1554084e+04, - 3.0408074e+04, 2.8986068e+04, 2.7298583e+04, 2.5360460e+04, - 2.3186540e+04, 2.0794689e+04, 1.8206602e+04, 1.5444741e+04, - 1.2535402e+04, 9.5045150e+03, 6.3825434e+03, 3.1961404e+03, - -1.9030604e+01, -3.2350097e+03, -6.4178539e+03, -9.5376996e+03, - -1.2564818e+04, -1.5468879e+04, -1.8222757e+04, -2.0799617e+04, - -2.3177492e+04, -2.5329860e+04, -2.7239548e+04, -2.8887388e+04, - -3.0257022e+04, -3.1336972e+04, -3.2115659e+04, -3.2585521e+04, - -3.2741691e+04, -3.2583544e+04, -3.2112334e+04, -3.1332786e+04, - -3.0253039e+04, -2.8881031e+04, -2.7231757e+04, -2.5321143e+04, - -2.3168095e+04, -2.0790131e+04, -1.8212051e+04, -1.5458479e+04, - -1.2554090e+04, -9.5278709e+03, -6.4088050e+03, -3.2282766e+03, - -1.5127187e+01, 3.1974595e+03, 6.3806758e+03, 9.5013370e+03, - 1.2533377e+04, 1.5443257e+04, 1.8203988e+04, 2.0793445e+04, - 2.3180292e+04, 2.5344634e+04, 2.7265053e+04, 2.8919963e+04, - 3.0294320e+04, 3.1376795e+04, 3.2154178e+04, 3.2622959e+04, - 3.2776568e+04, 3.2617286e+04, 3.2145842e+04, 3.1360660e+04, - 3.0278348e+04, 2.8901877e+04, 2.7241369e+04, 2.5301056e+04, - 2.3077170e+04, 2.0602593e+04, 1.7860920e+04, 1.4845935e+04, - 1.1575770e+04, 8.0714330e+03, 4.3590833e+03, 4.8619425e+02, - -3.4812252e+03, -7.4811451e+03, -1.1420224e+04, -1.5218969e+04, - -1.8767216e+04, -2.1982348e+04, -2.4766842e+04, -2.7038512e+04, - -2.8729372e+04, -2.9797530e+04, -3.0215913e+04, -2.9983529e+04, - -2.9130275e+04, -2.7706100e+04, -2.5778477e+04, -2.3437188e+04, - -2.0783932e+04, -1.7920105e+04, -1.4952584e+04, -1.1982327e+04, - -9.1037807e+03, -6.3864700e+03, -3.9012432e+03, -1.6878870e+03, - 2.1843895e+02, 1.8077853e+03, 3.0762163e+03, 4.0339692e+03, - 4.7031968e+03, 5.1098317e+03, 5.2820716e+03, 5.2546005e+03, - 5.0617380e+03, 4.7306477e+03, 4.2889148e+03, 3.7647491e+03, - 3.1840313e+03, 2.5717028e+03, 1.9493478e+03, 1.3380429e+03, - 7.5567371e+02, 2.1773747e+02, -2.6311651e+02, -6.7663706e+02, - -1.0155643e+03, -1.2750705e+03, -1.4528246e+03, -1.5489867e+03, - -1.5659952e+03, -1.5076498e+03, -1.3804175e+03, -1.1912334e+03, - -9.4848033e+02, -6.6207374e+02, -3.4175876e+02, 1.6521653e+00, - 3.5767927e+02, 7.1550189e+02, 1.0651058e+03, 1.3968326e+03, - 1.7019804e+03, 1.9728594e+03, 2.2034762e+03, 2.3889564e+03, - 2.5257870e+03, 2.6127289e+03, 2.6495795e+03, 2.6378966e+03, - 2.5805079e+03, 2.4818035e+03, 2.3472272e+03, 2.1829178e+03, - 1.9955916e+03, 1.7924019e+03, 1.5804111e+03, 1.3664419e+03, - 1.1569292e+03, 9.5724044e+02, 7.7214172e+02, 6.0521399e+02, - 4.5883364e+02, 3.3442067e+02, 2.3213371e+02, 1.5121914e+02, - 9.0047461e+01, 4.6310025e+01, 1.7308037e+01, 7.2726310e-02, - -8.3269806e+00, -1.0647845e+01, -9.2769990e+00, -5.7939041e+00 ], - -]) - -T_HAT_MDCT_7M5 = np.array([ - - [ -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - 9.0382948e-01, 2.8563300e+00, 2.0863167e+00, 3.2605273e+00, - 1.8231017e+00, -2.6473031e+00, -7.7420704e+00, -1.6971743e+01, - -4.4169569e+00, 4.7473387e+00, 7.9882732e+00, 2.1090757e+00, - 6.9477046e+00, 7.6294361e+00, 4.5069158e+00, 1.1288109e+00, - 5.5301798e-01, -1.2320805e+00, 1.2696965e+01, 1.7998129e+01, - 1.9997378e+01, 2.3310802e+01, 3.4116671e+01, 3.1619222e+01, - 2.3643252e+01, 2.2595989e+01, 2.4150879e+01, 1.7561939e+01, - 2.4167995e+01, 2.1868269e+01, 1.2021561e+01, 1.0810360e+01, - -1.1321816e+01, -1.3811836e+01, -2.7571991e+01, -3.3459505e+01, - -2.6720233e+01, -4.0425004e+01, -4.1666697e+01, -4.8106995e+01, - -7.1121739e+01, -8.5018856e+01, -6.4519501e+01, -6.1651047e+01, - -6.2001672e+01, -4.9054098e+01, 5.3605147e+00, -2.7222279e+00, - -6.3200946e+00, -2.8873822e+01, -5.6314175e+01, -5.9551902e+01, - -2.1183627e+01, -9.5007617e+01, -6.7674879e+01, 7.6546124e+01, - 3.6355638e+02, 2.0908440e+02, 9.2290767e+01, -8.4453487e+01, - -2.0810832e+02, -1.9235273e+02, -4.0634578e+02, -2.2011977e+02, - 6.2920459e+02, 3.1481663e+03, 6.2343351e+03, 9.4022080e+03, - 1.2520451e+04, 1.5313131e+04, 1.8128985e+04, 2.0762454e+04, - 2.3084787e+04, 2.5275848e+04, 2.7095495e+04, 2.8665301e+04, - 3.0094623e+04, 3.1202047e+04, 3.2006678e+04, 3.2461623e+04, - 3.2568832e+04, 3.2408327e+04, 3.1961953e+04, 3.1146555e+04, - 3.0073949e+04, 2.8725124e+04, 2.7099832e+04, 2.5196695e+04, - 2.3022972e+04, 2.0643354e+04, 1.8079103e+04, 1.5352852e+04, - 1.2476728e+04, 9.4135962e+03, 6.2948219e+03, 3.1010477e+03, - -9.0897787e+01, -3.3383673e+03, -6.5093586e+03, -9.6214110e+03, - -1.2638625e+04, -1.5564780e+04, -1.8289238e+04, -2.0877731e+04, - -2.3274493e+04, -2.5456613e+04, -2.7372293e+04, -2.9018289e+04, - -3.0399516e+04, -3.1474248e+04, -3.2213279e+04, -3.2686770e+04, - -3.2836146e+04, -3.2655386e+04, -3.2161995e+04, -3.1363572e+04, - -3.0296725e+04, -2.8893704e+04, -2.7226660e+04, -2.5303018e+04, - -2.3185989e+04, -2.0860640e+04, -1.8388180e+04, -1.5768019e+04, - -1.3017648e+04, -1.0256225e+04, -7.4288937e+03, -4.6404303e+03, - -1.8479563e+03, 8.9695589e+02, 3.6050165e+03, 6.1774761e+03, - 8.5802409e+03, 1.0843314e+04, 1.2957357e+04, 1.4915752e+04, - 1.6688121e+04, 1.8234848e+04, 1.9622853e+04, 2.0843143e+04, - 2.1874370e+04, 2.2730604e+04, 2.3433492e+04, 2.3972978e+04, - 2.4361621e+04, 2.4632443e+04, 2.4789213e+04, 2.4834368e+04, - 2.4817473e+04, 2.4691904e+04, 2.4506825e+04, 2.4260930e+04, - 2.3952544e+04, 2.3583514e+04, 2.3158707e+04, 2.2682736e+04, - 2.2114814e+04, 2.1501602e+04, 2.0804765e+04, 2.0028682e+04, - 1.9176325e+04, 1.8229068e+04, 1.7186098e+04, 1.6064305e+04, - 1.4857345e+04, 1.3566101e+04, 1.2216378e+04, 1.0824025e+04, - 9.3566686e+03, 7.8525218e+03, 6.3408636e+03, 4.8352443e+03, - 3.3500951e+03, 1.8786022e+03, 4.4842764e+02, -8.8483949e+02, - -2.1241927e+03, -3.2448273e+03, -4.2656467e+03, -5.1440714e+03, - -5.9062863e+03, -6.5125637e+03, -6.9672797e+03, -7.2820785e+03, - -7.4483481e+03, -7.4911171e+03, -7.4042834e+03, -7.2043747e+03, - -6.8934126e+03, -6.5065747e+03, -6.0545237e+03, -5.5534407e+03, - -5.0174587e+03, -4.4641711e+03, -3.9151968e+03, -3.3732391e+03, - -2.8528068e+03, -2.3664418e+03, -1.9195477e+03, -1.5167365e+03, - -1.1638365e+03, -8.6204669e+02, -6.1212532e+02, -4.0852043e+02, - -2.5108888e+02, -1.3435049e+02, -5.3189240e+01, -1.0851528e+00, - 2.6728439e+01, 3.7348684e+01, 3.5932093e+01, 2.7568411e+01 ], - - [ -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, - -0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, - 7.4140637e+01, 1.4259396e+02, 2.4292388e+02, 3.8197729e+02, - 5.6596483e+02, 8.0010169e+02, 1.0881546e+03, 1.4325879e+03, - 1.8337245e+03, 2.2902305e+03, 2.7978462e+03, 3.3513844e+03, - 3.9420820e+03, 4.5597592e+03, 5.1914056e+03, 5.8224872e+03, - 6.4359174e+03, 7.0133507e+03, 7.5344894e+03, 7.9783768e+03, - 8.3235628e+03, 8.5499202e+03, 8.6355016e+03, 8.5623082e+03, - 8.3125769e+03, 7.8732452e+03, 7.2322659e+03, 6.3830254e+03, - 5.3220070e+03, 4.0508083e+03, 2.5743934e+03, 9.0382380e+02, - -9.4658515e+02, -2.9577774e+03, -5.1073476e+03, -7.3680800e+03, - -9.7116793e+03, -1.2105745e+04, -1.4518157e+04, -1.6913624e+04, - -1.9259368e+04, -2.1519698e+04, -2.3664419e+04, -2.5661182e+04, - -2.7484674e+04, -2.9109128e+04, -3.0513566e+04, -3.1680767e+04, - -3.2599500e+04, -3.3259046e+04, -3.3656364e+04, -3.3789359e+04, - -3.3661417e+04, -3.3275865e+04, -3.2647991e+04, -3.1778553e+04, - -3.0687860e+04, -2.9386993e+04, -2.7893292e+04, -2.6217793e+04, - -2.4380305e+04, -2.2396921e+04, -2.0285631e+04, -1.8056304e+04, - -1.5731396e+04, -1.3310749e+04, -1.0817930e+04, -8.2632546e+03, - -5.6584950e+03, -3.0169039e+03, -3.5049466e+02, 2.3300294e+03, - 5.0072558e+03, 7.6692538e+03, 1.0296341e+04, 1.2873294e+04, - 1.5379430e+04, 1.7799709e+04, 2.0110518e+04, 2.2292425e+04, - 2.4321243e+04, 2.6179470e+04, 2.7838772e+04, 2.9288536e+04, - 3.0502052e+04, 3.1467674e+04, 3.2161346e+04, 3.2580900e+04, - 3.2712443e+04, 3.2548152e+04, 3.2079638e+04, 3.1315042e+04, - 3.0239307e+04, 2.8881574e+04, 2.7232557e+04, 2.5325302e+04, - 2.3165560e+04, 2.0776212e+04, 1.8202819e+04, 1.5452512e+04, - 1.2552870e+04, 9.5323059e+03, 6.4141989e+03, 3.2353808e+03, - 3.2008805e+01, -3.1778835e+03, -6.3568255e+03, -9.4682388e+03, - -1.2490842e+04, -1.5403926e+04, -1.8154186e+04, -2.0745346e+04, - -2.3121161e+04, -2.5285375e+04, -2.7200767e+04, -2.8855100e+04, - -3.0236188e+04, -3.1303814e+04, -3.2106304e+04, -3.2610143e+04, - -3.2801911e+04, -3.2722047e+04, -3.2333816e+04, -3.1622380e+04, - -3.0637858e+04, -2.9319050e+04, -2.7722782e+04, -2.5854268e+04, - -2.3707550e+04, -2.1309710e+04, -1.8683478e+04, -1.5843106e+04, - -1.2810610e+04, -9.6245078e+03, -6.3128385e+03, -2.9018457e+03, - 5.6021860e+02, 4.0355321e+03, 7.4888401e+03, 1.0869459e+04, - 1.4146120e+04, 1.7266962e+04, 2.0195488e+04, 2.2894666e+04, - 2.5327458e+04, 2.7459548e+04, 2.9268259e+04, 3.0729712e+04, - 3.1824168e+04, 3.2542974e+04, 3.2879994e+04, 3.2838377e+04, - 3.2420961e+04, 3.1641217e+04, 3.0522280e+04, 2.9086732e+04, - 2.7364573e+04, 2.5386626e+04, 2.3192561e+04, 2.0822736e+04, - 1.8313768e+04, 1.5710203e+04, 1.3055162e+04, 1.0388760e+04, - 7.7479346e+03, 5.1773492e+03, 2.7035918e+03, 3.6336147e+02, - -1.8203312e+03, -3.8257571e+03, -5.6281400e+03, -7.2191945e+03, - -8.5918440e+03, -9.7361057e+03, -1.0653660e+04, -1.1351662e+04, - -1.1834991e+04, -1.2108888e+04, -1.2194030e+04, -1.2106898e+04, - -1.1844914e+04, -1.1451706e+04, -1.0928890e+04, -1.0302174e+04, - -9.5993172e+03, -8.8336978e+03, -8.0218966e+03, -7.1899794e+03, - -6.3420744e+03, -5.5028868e+03, -4.6880751e+03, -3.9103856e+03, - -3.1844358e+03, -2.5158381e+03, -1.9161507e+03, -1.3860285e+03, - -9.3082869e+02, -5.4957243e+02, -2.3962727e+02, 2.0859282e+00, - 1.8035744e+02, 3.0232747e+02, 3.7488265e+02, 4.0574857e+02, - 4.0326247e+02, 3.7569870e+02, 3.3102137e+02, 2.7655429e+02, - 2.1828293e+02, 1.6157727e+02, 1.1024218e+02, 6.6816369e+01 ] - -]) - -T_HAT_MDCT = [ T_HAT_MDCT_7M5, T_HAT_MDCT_10M ] - -### C.4.1.9 LTPF - -X_HAT_LTPF_10M = np.array([ - - [ 6.1525095e-01, 1.7117620e+00, -1.6200436e-01, -2.1107548e+00, - 9.1636911e-01, 8.7583398e+00, 1.4291828e+01, 1.4615904e+01, - 1.9312730e+01, 2.2178311e+01, 2.1178760e+01, 1.9939021e+01, - 3.2745193e+01, 3.1385007e+01, 4.5642888e+01, 3.8185668e+01, - 4.3452271e+01, 3.0174130e+01, 2.7510416e+01, 3.9048290e+00, - -4.1911157e+00, -3.4032526e+01, -4.3089457e+01, -7.1817465e+01, - -7.3319439e+01, -1.0231340e+02, -8.2645833e+01, -1.0207070e+02, - -7.4253115e+01, -9.5269932e+01, -1.2210097e+02, -1.3216707e+02, - -1.2665681e+02, -1.6033791e+02, -1.3067613e+02, -1.8796611e+01, - 6.2097263e+01, 7.2290617e+00, -1.2550979e+02, -8.9649115e+01, - 7.6135408e+02, 2.7072170e+03, 6.1558256e+03, 9.6522574e+03, - 1.2566221e+04, 1.5421574e+04, 1.8329565e+04, 2.1102710e+04, - 2.3323039e+04, 2.5451924e+04, 2.7365468e+04, 2.8891223e+04, - 3.0341813e+04, 3.1380038e+04, 3.2134454e+04, 3.2606958e+04, - 3.2683895e+04, 3.2518324e+04, 3.2036626e+04, 3.1278795e+04, - 3.0136453e+04, 2.8694957e+04, 2.7009676e+04, 2.5075921e+04, - 2.2940269e+04, 2.0564299e+04, 1.7956441e+04, 1.5202722e+04, - 1.2352834e+04, 9.3639445e+03, 6.2714619e+03, 3.1112267e+03, - -1.0075267e+02, -3.3115389e+03, -6.4954073e+03, -9.6110111e+03, - -1.2594144e+04, -1.5477538e+04, -1.8214406e+04, -2.0797170e+04, - -2.3195615e+04, -2.5355124e+04, -2.7302557e+04, -2.8919494e+04, - -3.0273227e+04, -3.1357707e+04, -3.2152224e+04, -3.2625545e+04, - -3.2802109e+04, -3.2640407e+04, -3.2172861e+04, -3.1393517e+04, - -3.0316009e+04, -2.8922986e+04, -2.7290775e+04, -2.5351571e+04, - -2.3183937e+04, -2.0795771e+04, -1.8212609e+04, -1.5453610e+04, - -1.2543978e+04, -9.4923186e+03, -6.3663932e+03, -3.1740539e+03, - 4.2407582e+01, 3.2479359e+03, 6.4369448e+03, 9.5564107e+03, - 1.2589389e+04, 1.5494437e+04, 1.8238168e+04, 2.0814647e+04, - 2.3183440e+04, 2.5340307e+04, 2.7236643e+04, 2.8879098e+04, - 3.0219987e+04, 3.1304367e+04, 3.2073455e+04, 3.2541098e+04, - 3.2660415e+04, 3.2490788e+04, 3.2004309e+04, 3.1215306e+04, - 3.0131477e+04, 2.8751611e+04, 2.7114762e+04, 2.5198099e+04, - 2.3044166e+04, 2.0655799e+04, 1.8068458e+04, 1.5312555e+04, - 1.2400688e+04, 9.3834439e+03, 6.2670869e+03, 3.1043555e+03, - -9.0364008e+01, -3.2949280e+03, -6.4558716e+03, -9.5736656e+03, - -1.2593429e+04, -1.5487321e+04, -1.8231003e+04, -2.0808229e+04, - -2.3191386e+04, -2.5327915e+04, -2.7226934e+04, -2.8860268e+04, - -3.0235350e+04, -3.1313467e+04, -3.2092397e+04, -3.2585580e+04, - -3.2777259e+04, -3.2606534e+04, -3.2146234e+04, -3.1383325e+04, - -3.0295384e+04, -2.8926934e+04, -2.7297985e+04, -2.5343669e+04 ], - - [ -2.3210612e+04, -2.0830109e+04, -1.8262528e+04, -1.5491202e+04, - -1.2640992e+04, -9.6308521e+03, -6.5120997e+03, -3.2981272e+03, - -1.0437273e+02, 3.1237705e+03, 6.3475523e+03, 9.4251090e+03, - 1.2406927e+04, 1.5369182e+04, 1.8133410e+04, 2.0696011e+04, - 2.3075625e+04, 2.5239168e+04, 2.7178122e+04, 2.8863775e+04, - 3.0239107e+04, 3.1292540e+04, 3.2055374e+04, 3.2528526e+04, - 3.2691792e+04, 3.2554032e+04, 3.2080858e+04, 3.1269701e+04, - 3.0219849e+04, 2.8872409e+04, 2.7201446e+04, 2.5283194e+04, - 2.3137397e+04, 2.0746427e+04, 1.8171258e+04, 1.5425482e+04, - 1.2542866e+04, 9.5154094e+03, 6.4038902e+03, 3.2243297e+03, - 1.8093877e+01, -3.2004786e+03, -6.3778766e+03, -9.4986572e+03, - -1.2530644e+04, -1.5438896e+04, -1.8199553e+04, -2.0786963e+04, - -2.3172801e+04, -2.5336869e+04, -2.7256938e+04, -2.8914212e+04, - -3.0292811e+04, -3.1379968e+04, -3.2163160e+04, -3.2636663e+04, - -3.2797410e+04, -3.2642190e+04, -3.2169708e+04, -3.1389768e+04, - -3.0307591e+04, -2.8933213e+04, -2.7277887e+04, -2.5361709e+04, - -2.3197556e+04, -2.0809583e+04, -1.8223444e+04, -1.5459240e+04, - -1.2547850e+04, -9.5147469e+03, -6.3913071e+03, -3.2061552e+03, - 1.1474435e+01, 3.2280361e+03, 6.4146913e+03, 9.5376172e+03, - 1.2570372e+04, 1.5481142e+04, 1.8242641e+04, 2.0827867e+04, - 2.3213026e+04, 2.5375280e+04, 2.7293037e+04, 2.8947339e+04, - 3.0323330e+04, 3.1406817e+04, 3.2187891e+04, 3.2660531e+04, - 3.2817886e+04, 3.2659083e+04, 3.2187190e+04, 3.1402569e+04, - 3.0317849e+04, 2.8939620e+04, 2.7281206e+04, 2.5360297e+04, - 2.3194809e+04, 2.0805310e+04, 1.8215867e+04, 1.5450539e+04, - 1.2535402e+04, 9.5045150e+03, 6.3825434e+03, 3.1961404e+03, - -1.9030604e+01, -3.2350097e+03, -6.4178539e+03, -9.5376996e+03, - -1.2564818e+04, -1.5468879e+04, -1.8222757e+04, -2.0799617e+04, - -2.3177492e+04, -2.5329860e+04, -2.7239548e+04, -2.8887388e+04, - -3.0257022e+04, -3.1336972e+04, -3.2115659e+04, -3.2585521e+04, - -3.2741691e+04, -3.2583544e+04, -3.2112334e+04, -3.1332786e+04, - -3.0253039e+04, -2.8881031e+04, -2.7231757e+04, -2.5321143e+04, - -2.3168095e+04, -2.0790131e+04, -1.8212051e+04, -1.5458479e+04, - -1.2554090e+04, -9.5278709e+03, -6.4088050e+03, -3.2282766e+03, - -1.5127187e+01, 3.1974595e+03, 6.3806758e+03, 9.5013370e+03, - 1.2533377e+04, 1.5443257e+04, 1.8203988e+04, 2.0793445e+04, - 2.3180292e+04, 2.5344634e+04, 2.7265053e+04, 2.8919963e+04, - 3.0294320e+04, 3.1376795e+04, 3.2154178e+04, 3.2622959e+04, - 3.2776568e+04, 3.2617286e+04, 3.2145842e+04, 3.1360660e+04, - 3.0278348e+04, 2.8901877e+04, 2.7241369e+04, 2.5301056e+04 ], - -]) - -X_HAT_LTPF_7M5 = np.array([ - - [ 9.0382948e-01, 2.8563300e+00, 2.0863167e+00, 3.2605273e+00, - 1.8231017e+00, -2.6473031e+00, -7.7420704e+00, -1.6971743e+01, - -4.4169569e+00, 4.7473387e+00, 7.9882732e+00, 2.1090757e+00, - 6.9477046e+00, 7.6294361e+00, 4.5069158e+00, 1.1288109e+00, - 5.5301798e-01, -1.2320805e+00, 1.2696965e+01, 1.7998129e+01, - 1.9997378e+01, 2.3310802e+01, 3.4116671e+01, 3.1619222e+01, - 2.3643252e+01, 2.2595989e+01, 2.4150879e+01, 1.7561939e+01, - 2.4167995e+01, 2.1868269e+01, 1.2021561e+01, 1.0810360e+01, - -1.1321816e+01, -1.3811836e+01, -2.7571991e+01, -3.3459505e+01, - -2.6720233e+01, -4.0425004e+01, -4.1666697e+01, -4.8106995e+01, - -7.1121739e+01, -8.5018856e+01, -6.4519501e+01, -6.1651047e+01, - -6.2001672e+01, -4.9054098e+01, 5.3605147e+00, -2.7222279e+00, - -6.3200946e+00, -2.8873822e+01, -5.6314175e+01, -5.9551902e+01, - -2.1183627e+01, -9.5007617e+01, -6.7674879e+01, 7.6546124e+01, - 3.6355638e+02, 2.0908440e+02, 9.2290767e+01, -8.4453487e+01, - -2.0810832e+02, -1.9235273e+02, -4.0634578e+02, -2.2011977e+02, - 6.2920459e+02, 3.1481663e+03, 6.2343351e+03, 9.4022080e+03, - 1.2520451e+04, 1.5313131e+04, 1.8128985e+04, 2.0762454e+04, - 2.3084787e+04, 2.5275848e+04, 2.7095495e+04, 2.8665301e+04, - 3.0094623e+04, 3.1202047e+04, 3.2006678e+04, 3.2461623e+04, - 3.2568832e+04, 3.2408327e+04, 3.1961953e+04, 3.1146555e+04, - 3.0073949e+04, 2.8725124e+04, 2.7099832e+04, 2.5196695e+04, - 2.3022972e+04, 2.0643354e+04, 1.8079103e+04, 1.5352852e+04, - 1.2476728e+04, 9.4135962e+03, 6.2948219e+03, 3.1010477e+03, - -9.0897787e+01, -3.3383673e+03, -6.5093586e+03, -9.6214110e+03, - -1.2638625e+04, -1.5564780e+04, -1.8289238e+04, -2.0877731e+04, - -2.3274493e+04, -2.5456613e+04, -2.7372293e+04, -2.9018289e+04, - -3.0399516e+04, -3.1474248e+04, -3.2213279e+04, -3.2686770e+04, - -3.2836146e+04, -3.2655386e+04, -3.2161995e+04, -3.1363572e+04, - -3.0296725e+04, -2.8893704e+04, -2.7226660e+04, -2.5303018e+04 ], - - [ -2.3111848e+04, -2.0718046e+04, -1.8145256e+04, -1.5386042e+04, - -1.2451683e+04, -9.4561229e+03, -6.3407390e+03, -3.2078423e+03, - -1.4231827e+01, 3.1871864e+03, 6.4028626e+03, 9.5288605e+03, - 1.2522323e+04, 1.5403074e+04, 1.8148763e+04, 2.0738239e+04, - 2.3124038e+04, 2.5248199e+04, 2.7157343e+04, 2.8821520e+04, - 3.0197933e+04, 3.1280524e+04, 3.2068994e+04, 3.2535286e+04, - 3.2674198e+04, 3.2505688e+04, 3.2021479e+04, 3.1217393e+04, - 3.0139480e+04, 2.8742712e+04, 2.7081219e+04, 2.5164753e+04, - 2.3005958e+04, 2.0625737e+04, 1.8051360e+04, 1.5314656e+04, - 1.2403135e+04, 9.3958576e+03, 6.2866076e+03, 3.1150574e+03, - -8.3043055e+01, -3.2906309e+03, -6.4783209e+03, -9.5968770e+03, - -1.2627329e+04, -1.5543027e+04, -1.8297188e+04, -2.0856742e+04, - -2.3242831e+04, -2.5406524e+04, -2.7315500e+04, -2.8954115e+04, - -3.0311322e+04, -3.1397263e+04, -3.2199564e+04, -3.2663393e+04, - -3.2812053e+04, -3.2631820e+04, -3.2158938e+04, -3.1361864e+04, - -3.0286591e+04, -2.8909485e+04, -2.7252911e+04, -2.5338382e+04, - -2.3179744e+04, -2.0801866e+04, -1.8222214e+04, -1.5467629e+04, - -1.2551908e+04, -9.5234786e+03, -6.4050183e+03, -3.2234113e+03, - -1.0202956e+01, 3.2050827e+03, 6.3811438e+03, 9.5000550e+03, - 1.2526624e+04, 1.5433267e+04, 1.8190970e+04, 2.0775689e+04, - 2.3157406e+04, 2.5317424e+04, 2.7226647e+04, 2.8880016e+04, - 3.0250964e+04, 3.1333324e+04, 3.2108157e+04, 3.2579815e+04, - 3.2739171e+04, 3.2585501e+04, 3.2115570e+04, 3.1342610e+04, - 3.0239307e+04, 2.8881574e+04, 2.7232557e+04, 2.5325302e+04, - 2.3165560e+04, 2.0776212e+04, 1.8202819e+04, 1.5452512e+04, - 1.2552870e+04, 9.5323059e+03, 6.4141989e+03, 3.2353808e+03, - 3.2008805e+01, -3.1778835e+03, -6.3568255e+03, -9.4682388e+03, - -1.2490842e+04, -1.5403926e+04, -1.8154186e+04, -2.0745346e+04, - -2.3121161e+04, -2.5285375e+04, -2.7200767e+04, -2.8855100e+04, - -3.0236188e+04, -3.1303814e+04, -3.2106304e+04, -3.2610143e+04 ] - -]) - -X_HAT_LTPF = [ X_HAT_LTPF_7M5, X_HAT_LTPF_10M ] - -LTPF_C2_NBITS = 320 - -LTPF_C2_ACTIVE = np.array([ False, True ]) -LTPF_C2_PITCH_INDEX = np.array([ 60, 56 ]) - -LTPF_C2_C_N = np.array([ - [ 0. , 0. , 0. ], - [ 2.0480302e-01, 1.4271871e-01, -6.4036434e-03 ], -]) - -LTPF_C2_C_D = np.array([ - [ 0. , 0. , 0. , 0. ], - [ 1.5868459e-02, 1.8368837e-01, 1.8368837e-01, 1.5868459e-02 ], -]) - -LTPF_C2_X = np.array([ - - [ 2.1004800e+03, 2.0660438e+03, 2.0070810e+03, 1.9335150e+03, - 1.8437505e+03, 1.7474564e+03, 1.6433626e+03, 1.5341100e+03, - 1.4257583e+03, 1.3211557e+03, 1.2062000e+03, 1.0819606e+03, - 9.5194047e+02, 8.1893657e+02, 6.7789896e+02, 5.3732954e+02, - 4.0506079e+02, 2.7179124e+02, 1.3998655e+02, 1.9709326e+00, - -1.3683087e+02, -2.7783589e+02, -4.1717230e+02, -5.5239764e+02, - -6.7544678e+02, -7.8374115e+02, -8.8533384e+02, -9.8169275e+02, - -1.0740844e+03, -1.1619601e+03, -1.2468187e+03, -1.3276334e+03, - -1.3976625e+03, -1.4581676e+03, -1.5080701e+03, -1.5565703e+03, - -1.6009886e+03, -1.6442955e+03, -1.6843665e+03, -1.7151734e+03, - -1.7459758e+03, -1.7579559e+03, -1.7383847e+03, -1.6558090e+03, - -1.4937678e+03, -1.2402230e+03, -9.0680789e+02, -5.2126546e+02, - -1.0907639e+02, 2.9396419e+02, 6.6844988e+02, 9.9743497e+02, - 1.2728461e+03, 1.5005211e+03, 1.6749621e+03, 1.8070876e+03, - 1.9030819e+03, 1.9644916e+03, 1.9851832e+03, 1.9771133e+03, - 1.9382403e+03, 1.8819654e+03, 1.8027215e+03, 1.7116504e+03, - 1.6036716e+03, 1.4931560e+03, 1.3786289e+03, 1.2583587e+03, - 1.1369652e+03, 1.0121811e+03, 8.8292297e+02, 7.5232872e+02, - 6.2279997e+02, 4.8668604e+02, 3.4937590e+02, 2.1277380e+02, - 7.7335654e+01, -5.2960798e+01, -1.8097039e+02, -3.0070120e+02, - -4.1472118e+02, -5.2643886e+02, -6.3396297e+02, -7.3691168e+02, - -8.3480847e+02, -9.2600159e+02, -1.0147685e+03, -1.0954793e+03, - -1.1736112e+03, -1.2509220e+03, -1.3222525e+03, -1.3883874e+03, - -1.4496560e+03, -1.5064726e+03, -1.5576614e+03, -1.6028926e+03, - -1.6434987e+03, -1.6803495e+03, -1.7069786e+03, -1.7018749e+03, - -1.6517403e+03, -1.5416168e+03, -1.3607723e+03, -1.1195564e+03, - -8.2569063e+02, -4.9652560e+02, -1.5319529e+02, 1.8519693e+02, - 5.0070752e+02, 7.8614834e+02, 1.0314193e+03, 1.2402508e+03, - 1.4166554e+03, 1.5555207e+03, 1.6600606e+03, 1.7324994e+03, - 1.7753655e+03, 1.7931195e+03, 1.7839794e+03, 1.7543157e+03, - 1.7049335e+03, 1.6342871e+03, 1.5549646e+03, 1.4629383e+03, - 1.3581758e+03, 1.2457595e+03, 1.1299878e+03, 1.0119864e+03, - 8.9090477e+02, 7.6719677e+02, 6.4285660e+02, 5.1408928e+02, - 3.8508372e+02, 2.5534679e+02, 1.2497756e+02, -3.9966107e+00, - -1.2599628e+02, -2.4595825e+02, -3.6034285e+02, -4.7095724e+02, - -5.7730810e+02, -6.8592514e+02, -7.8960041e+02, -8.9182726e+02, - -9.8741569e+02, -1.0733871e+03, -1.1555560e+03, -1.2285264e+03, - -1.2950383e+03, -1.3587508e+03, -1.4190449e+03, -1.4731166e+03, - -1.5244161e+03, -1.5700435e+03, -1.6143711e+03, -1.6442522e+03, - -1.6504480e+03, -1.6200592e+03, -1.5385467e+03, -1.4018632e+03 ], - - [ -1.2097642e+03, -9.7471997e+02, -7.0651192e+02, -4.1925510e+02, - -1.2278127e+02, 1.6308666e+02, 4.3389868e+02, 6.8416589e+02, - 9.0871878e+02, 1.1028177e+03, 1.2670447e+03, 1.4015901e+03, - 1.5108776e+03, 1.5894427e+03, 1.6428125e+03, 1.6684610e+03, - 1.6687068e+03, 1.6467684e+03, 1.6069401e+03, 1.5504379e+03, - 1.4802355e+03, 1.3985477e+03, 1.3037872e+03, 1.1957600e+03, - 1.0853732e+03, 9.7233331e+02, 8.4944729e+02, 7.2549848e+02, - 5.9937450e+02, 4.8205790e+02, 3.5945231e+02, 2.3181221e+02, - 1.0289577e+02, -2.2787734e+01, -1.4227469e+02, -2.5954609e+02, - -3.7614640e+02, -4.8391910e+02, -5.8341913e+02, -6.8123214e+02, - -7.7747871e+02, -8.6932601e+02, -9.5415487e+02, -1.0385138e+03, - -1.1184902e+03, -1.1867290e+03, -1.2499404e+03, -1.3128700e+03, - -1.3730047e+03, -1.4324194e+03, -1.4841659e+03, -1.5297608e+03, - -1.5601321e+03, -1.5603639e+03, -1.5252096e+03, -1.4567924e+03, - -1.3535284e+03, -1.2050129e+03, -1.0232675e+03, -8.1556031e+02, - -5.8338838e+02, -3.4263538e+02, -9.1284066e+01, 1.4792883e+02, - 3.7724977e+02, 5.9063752e+02, 7.8210956e+02, 9.5337152e+02, - 1.1069618e+03, 1.2346417e+03, 1.3304957e+03, 1.4081378e+03, - 1.4660754e+03, 1.5064930e+03, 1.5231194e+03, 1.5173564e+03, - 1.4891356e+03, 1.4460229e+03, 1.3890302e+03, 1.3171848e+03, - 1.2329448e+03, 1.1400293e+03, 1.0376506e+03, 9.3324803e+02, - 8.2426407e+02, 7.1443513e+02, 6.0252527e+02, 4.9088960e+02, - 3.7646014e+02, 2.6184052e+02, 1.4340035e+02, 3.0422051e+01, - -8.5724331e+01, -1.9809318e+02, -3.0918985e+02, -4.1384220e+02, - -5.0992503e+02, -6.0275760e+02, -6.9829113e+02, -7.9525188e+02, - -8.9453019e+02, -9.7802721e+02, -1.0526954e+03, -1.1251736e+03, - -1.1955435e+03, -1.2637584e+03, -1.3263901e+03, -1.3794649e+03, - -1.4229086e+03, -1.4542303e+03, -1.4659972e+03, -1.4469638e+03, - -1.3956114e+03, -1.3075606e+03, -1.1938217e+03, -1.0487411e+03, - -8.7590742e+02, -6.8650630e+02, -4.8348960e+02, -2.7915529e+02, - -7.3951415e+01, 1.2639053e+02, 3.2037647e+02, 5.0816397e+02, - 6.7805869e+02, 8.2207151e+02, 9.5456310e+02, 1.0705573e+03, - 1.1629335e+03, 1.2429314e+03, 1.3063791e+03, 1.3382875e+03, - 1.3364949e+03, 1.3197603e+03, 1.3011283e+03, 1.2904738e+03, - 1.2841453e+03, 1.2735627e+03, 1.2483109e+03, 1.1982190e+03, - 1.1236072e+03, 1.0353182e+03, 9.4811986e+02, 8.4791470e+02, - 7.4977805e+02, 6.0946439e+02, 4.1686370e+02, 1.5206161e+02, - -7.9210822e+01, -2.2784261e+02, -3.2684361e+02, -3.9056312e+02, - -4.6716161e+02, -5.4206330e+02, -6.2230545e+02, -7.0009951e+02, - -7.7171489e+02, -8.3103588e+02, -8.8858361e+02, -9.5353054e+02 ] - -]) - -LTPF_C2_PREV = np.array([ - - [ 3.6075890e+02, 2.5558573e+02, 1.5676072e+02, 6.2869832e+01, - -2.7464215e+01, -1.0807999e+02, -1.8538536e+02, -2.5213341e+02, - -3.1737297e+02, -3.7675903e+02, -4.3291912e+02, -4.8396843e+02, - -5.3257774e+02, -5.7812590e+02, -6.2166743e+02, -6.6533460e+02, - -7.0685062e+02, -7.4579194e+02, -7.7729679e+02, -8.0489134e+02, - -8.3252315e+02, -8.5569655e+02, -8.7998412e+02, -9.0742496e+02, - -9.3370927e+02, -9.5471476e+02, -9.7276449e+02, -9.9514771e+02, - -1.0136386e+03, -1.0163600e+03, -9.9100449e+02, -9.3570452e+02, - -8.4068970e+02, -7.0878785e+02, -5.4236585e+02, -3.4883259e+02, - -1.3544369e+02, 7.6143761e+01, 2.8313432e+02, 4.7371481e+02, - 6.3854542e+02, 7.8591376e+02, 9.1647781e+02, 1.0326049e+03, - 1.1226394e+03, 1.1855486e+03, 1.2110267e+03, 1.2072759e+03, - 1.1810221e+03, 1.1433488e+03, 1.0943565e+03, 1.0414966e+03, - 9.8463390e+02, 9.1048007e+02, 8.1752062e+02, 7.2333732e+02, - 6.4850080e+02, 5.9874218e+02, 5.6539980e+02, 5.5634736e+02, - 5.3800637e+02, 4.9467989e+02, 4.1631880e+02, 2.8517505e+02, - 1.1305724e+02, -8.8498535e+01, -2.9818901e+02, -4.9635689e+02, - -6.7273562e+02, -8.1632731e+02, -9.2538304e+02, -1.0146932e+03, - -1.0962177e+03, -1.1660919e+03, -1.2306080e+03, -1.2853503e+03, - -1.3346346e+03, -1.3883886e+03, -1.4496624e+03, -1.5155564e+03, - -1.5793268e+03, -1.6396210e+03, -1.6937295e+03, -1.7314870e+03, - -1.7610564e+03, -1.7775059e+03, -1.7806815e+03, -1.7684558e+03, - -1.6949960e+03, -1.4776266e+03, -1.0700242e+03, -5.1121101e+02, - 1.0329967e+02, 6.7165782e+02, 1.1381176e+03, 1.4974226e+03, - 1.7689436e+03, 1.9620604e+03, 2.0875907e+03, 2.1420343e+03, - 2.1555856e+03, 2.1497779e+03, 2.1345923e+03, 2.1141460e+03, - 2.0831857e+03, 2.0328927e+03, 1.9628672e+03, 1.8762276e+03, - 1.7788061e+03, 1.6631901e+03, 1.5303905e+03, 1.3855681e+03, - 1.2298992e+03, 1.0770934e+03, 9.1998634e+02, 7.6869655e+02, - 6.1555385e+02, 4.7278828e+02, 3.3511742e+02, 2.0334643e+02, - 8.1069660e+01, -4.1916116e+01, -1.7411361e+02, -3.0622256e+02, - -4.3179154e+02, -5.5570746e+02, -6.8069811e+02, -7.9809071e+02, - -9.0053455e+02, -9.9388321e+02, -1.0834733e+03, -1.1654917e+03, - -1.2466250e+03, -1.3184789e+03, -1.3814537e+03, -1.4386054e+03, - -1.5024822e+03, -1.5617271e+03, -1.6148868e+03, -1.6639722e+03, - -1.7108728e+03, -1.7519590e+03, -1.7805217e+03, -1.8036393e+03, - -1.8080682e+03, -1.7690236e+03, -1.6458189e+03, -1.4003994e+03, - -1.0280788e+03, -5.6864419e+02, -7.5505097e+01, 3.9987715e+02, - 8.1589313e+02, 1.1654034e+03, 1.4482132e+03, 1.6762780e+03, - 1.8458377e+03, 1.9698779e+03, 2.0528472e+03, 2.0941040e+03 ], - - [ 2.1004800e+03, 2.0660438e+03, 2.0070810e+03, 1.9335150e+03, - 1.8437505e+03, 1.7474564e+03, 1.6433626e+03, 1.5341100e+03, - 1.4257583e+03, 1.3211557e+03, 1.2062000e+03, 1.0819606e+03, - 9.5194047e+02, 8.1893657e+02, 6.7789896e+02, 5.3732954e+02, - 4.0506079e+02, 2.7179124e+02, 1.3998655e+02, 1.9709326e+00, - -1.3683087e+02, -2.7783589e+02, -4.1717230e+02, -5.5239764e+02, - -6.7544678e+02, -7.8374115e+02, -8.8533384e+02, -9.8169275e+02, - -1.0740844e+03, -1.1619601e+03, -1.2468187e+03, -1.3276334e+03, - -1.3976625e+03, -1.4581676e+03, -1.5080701e+03, -1.5565703e+03, - -1.6009886e+03, -1.6442955e+03, -1.6843665e+03, -1.7151734e+03, - -1.7459758e+03, -1.7579559e+03, -1.7383847e+03, -1.6558090e+03, - -1.4937678e+03, -1.2402230e+03, -9.0680789e+02, -5.2126546e+02, - -1.0907639e+02, 2.9396419e+02, 6.6844988e+02, 9.9743497e+02, - 1.2728461e+03, 1.5005211e+03, 1.6749621e+03, 1.8070876e+03, - 1.9030819e+03, 1.9644916e+03, 1.9851832e+03, 1.9771133e+03, - 1.9382403e+03, 1.8819654e+03, 1.8027215e+03, 1.7116504e+03, - 1.6036716e+03, 1.4931560e+03, 1.3786289e+03, 1.2583587e+03, - 1.1369652e+03, 1.0121811e+03, 8.8292297e+02, 7.5232872e+02, - 6.2279997e+02, 4.8668604e+02, 3.4937590e+02, 2.1277380e+02, - 7.7335654e+01, -5.2960798e+01, -1.8097039e+02, -3.0070120e+02, - -4.1472118e+02, -5.2643886e+02, -6.3396297e+02, -7.3691168e+02, - -8.3480847e+02, -9.2600159e+02, -1.0147685e+03, -1.0954793e+03, - -1.1736112e+03, -1.2509220e+03, -1.3222525e+03, -1.3883874e+03, - -1.4496560e+03, -1.5064726e+03, -1.5576614e+03, -1.6028926e+03, - -1.6434987e+03, -1.6803495e+03, -1.7069786e+03, -1.7018749e+03, - -1.6517403e+03, -1.5416168e+03, -1.3607723e+03, -1.1195564e+03, - -8.2569063e+02, -4.9652560e+02, -1.5319529e+02, 1.8519693e+02, - 5.0070752e+02, 7.8614834e+02, 1.0314193e+03, 1.2402508e+03, - 1.4166554e+03, 1.5555207e+03, 1.6600606e+03, 1.7324994e+03, - 1.7753655e+03, 1.7931195e+03, 1.7839794e+03, 1.7543157e+03, - 1.7049335e+03, 1.6342871e+03, 1.5549646e+03, 1.4629383e+03, - 1.3581758e+03, 1.2457595e+03, 1.1299878e+03, 1.0119864e+03, - 8.9090477e+02, 7.6719677e+02, 6.4285660e+02, 5.1408928e+02, - 3.8508372e+02, 2.5534679e+02, 1.2497756e+02, -3.9966107e+00, - -1.2599628e+02, -2.4595825e+02, -3.6034285e+02, -4.7095724e+02, - -5.7730810e+02, -6.8592514e+02, -7.8960041e+02, -8.9182726e+02, - -9.8741569e+02, -1.0733871e+03, -1.1555560e+03, -1.2285264e+03, - -1.2950383e+03, -1.3587508e+03, -1.4190449e+03, -1.4731166e+03, - -1.5244161e+03, -1.5700435e+03, -1.6143711e+03, -1.6442522e+03, - -1.6504480e+03, -1.6200592e+03, -1.5385467e+03, -1.4018632e+03 ], - -]) - -LTPF_C2_TRANS = np.array([ - - -1.2097642e+03, -9.7530715e+02, -7.0586256e+02, -4.1543418e+02, - -1.1414107e+02, 1.7777097e+02, 4.5531279e+02, 7.1225199e+02, - 9.4297106e+02, 1.1428504e+03, 1.3122721e+03, 1.4510401e+03, - 1.5632810e+03, 1.6437088e+03, 1.6979967e+03, 1.7236213e+03, - 1.7231450e+03, 1.6998644e+03, 1.6575399e+03, 1.5978279e+03, - 1.5240838e+03, 1.4378667e+03, 1.3380626e+03, 1.2256564e+03, - 1.1110323e+03, 9.9312189e+02, 8.6572627e+02, 7.3745656e+02, - 6.0633674e+02, 4.8191123e+02, 3.5135472e+02, 2.1648189e+02, - 8.0831679e+01, -5.1111363e+01, -1.7717212e+02, -3.0113312e+02, - -4.2348388e+02, -5.3759466e+02, -6.4602675e+02, -7.5403092e+02, - -8.6017221e+02, -9.5944484e+02, -1.0506850e+03, -1.1398086e+03, - -1.2228263e+03, -1.2941518e+03, -1.3612258e+03, -1.4273749e+03, - -1.4894501e+03, -1.5495534e+03, -1.6019734e+03, -1.6490374e+03, - -1.6814663e+03, -1.6844562e+03, -1.6513997e+03, -1.5793876e+03, - -1.4632011e+03, -1.2939942e+03, -1.0852074e+03, -8.4480887e+02, - -5.7732264e+02, -3.0008156e+02, -1.5103259e+01, 2.5424761e+02, - 5.1054364e+02, 7.4618547e+02, 9.5531914e+02, 1.1392454e+03, - 1.2997276e+03, 1.4305069e+03, 1.5279454e+03, 1.6037570e+03, - 1.6553093e+03, 1.6847892e+03, 1.6879843e+03, 1.6682815e+03, - 1.6264868e+03, 1.5696403e+03, 1.4983779e+03, 1.4119806e+03, - 1.3127144e+03, 1.2052332e+03, 1.0900241e+03, 9.7210566e+02, - 8.4877207e+02, 7.2467907e+02, 5.9961756e+02, 4.7505541e+02, - 3.4639404e+02, 2.1700781e+02, 8.5155762e+01, -4.0026523e+01, - -1.6698145e+02, -2.8953979e+02, -4.0971310e+02, -5.2233024e+02, - -6.2776248e+02, -7.3117198e+02, -8.3540014e+02, -9.3755661e+02, - -1.0392995e+03, -1.1263481e+03, -1.2052728e+03, -1.2805748e+03, - -1.3532553e+03, -1.4234920e+03, -1.4883360e+03, -1.5444401e+03, - -1.5915550e+03, -1.6260829e+03, -1.6379761e+03, -1.6152110e+03, - -1.5560714e+03, -1.4554812e+03, -1.3203947e+03, -1.1456045e+03, - -9.3870522e+02, -7.1082654e+02, -4.6691560e+02, -2.2039906e+02, - 2.5206392e+01, 2.6135641e+02, 4.8629103e+02, 6.9790232e+02, - 8.8592993e+02, 1.0460616e+03, 1.1899193e+03, 1.3098413e+03, - 1.4023098e+03, 1.4788921e+03, 1.5346583e+03, 1.5579963e+03, - 1.5491955e+03, 1.5242006e+03, 1.4921986e+03, 1.4607118e+03, - 1.4256432e+03, 1.3811223e+03, 1.3213357e+03, 1.2406869e+03, - 1.1418577e+03, 1.0338657e+03, 9.2734345e+02, 8.0983956e+02, - 6.9568058e+02, 5.4691592e+02, 3.6168815e+02, 1.2569299e+02, - -7.2937241e+01, -2.1016935e+02, -3.1888920e+02, -4.0476988e+02, - -5.0359952e+02, -5.9623817e+02, -6.9164993e+02, -7.8397385e+02, - -8.7149927e+02, -9.4943765e+02, -1.0247441e+03, -1.1018532e+03, - -]) - -LTPF_C3_NBITS = 320 - -LTPF_C3_ACTIVE = np.array([ True, False ]) -LTPF_C3_PITCH_INDEX = np.array([ 56, 0 ]) - -LTPF_C3_C_N = np.array([ - [ 2.0480302e-01, 1.4271871e-01, -6.4036434e-03 ], - [ 0. , 0. , 0. ], -]) - -LTPF_C3_C_D = np.array([ - [ 1.5868459e-02, 1.8368837e-01, 1.8368837e-01, 1.5868459e-02 ], - [ 0. , 0. , 0. , 0. ], -]) - -LTPF_C3_X = np.array([ - - [ -3.4872147e+02, -3.2869651e+02, -3.0368708e+02, -2.7206929e+02, - -2.3135299e+02, -1.8746149e+02, -1.4271272e+02, -9.8455678e+01, - -4.8137684e+01, 2.0589588e-01, 4.5670854e+01, 8.5887062e+01, - 1.2485726e+02, 1.6126194e+02, 1.9191268e+02, 2.2387152e+02, - 2.4650629e+02, 2.6665533e+02, 2.8210563e+02, 2.9385531e+02, - 3.0042345e+02, 2.9898320e+02, 2.9792092e+02, 2.9201085e+02, - 2.8341711e+02, 2.7006923e+02, 2.5925000e+02, 2.4396424e+02, - 2.2871379e+02, 2.1604489e+02, 2.0086440e+02, 1.8158468e+02, - 1.6604772e+02, 1.4881816e+02, 1.3450578e+02, 1.1691585e+02, - 1.0011405e+02, 8.1066153e+01, 5.7608036e+01, 3.3232973e+01, - 8.7252186e+00, -1.9268859e+01, -5.0019465e+01, -7.8718920e+01, - -1.1264618e+02, -1.4558774e+02, -1.7907091e+02, -2.1353821e+02, - -2.4860083e+02, -2.7968268e+02, -3.0845126e+02, -3.3166214e+02, - -3.4854139e+02, -3.6210272e+02, -3.6311551e+02, -3.6538831e+02, - -3.5698782e+02, -3.4320560e+02, -3.2228293e+02, -2.9431070e+02, - -2.6126653e+02, -2.2161989e+02, -1.7770590e+02, -1.3258934e+02, - -8.8768668e+01, -4.1250510e+01, 4.8812815e+00, 4.8960277e+01, - 9.1265856e+01, 1.2722198e+02, 1.5854814e+02, 1.8841450e+02, - 2.1263776e+02, 2.3530944e+02, 2.5135346e+02, 2.6817644e+02, - 2.7730158e+02, 2.7972049e+02, 2.7893036e+02, 2.7638406e+02, - 2.6804826e+02, 2.6051672e+02, 2.4861891e+02, 2.3713159e+02, - 2.2260424e+02, 2.0911457e+02, 1.9338336e+02, 1.8071811e+02, - 1.6387353e+02, 1.5139501e+02, 1.3594276e+02, 1.2442513e+02, - 1.1022492e+02, 9.7036956e+01, 7.4818560e+01, 5.7999575e+01, - 3.1360863e+01, 8.7303630e+00, -1.6051537e+01, -4.5294499e+01, - -7.3824309e+01, -1.0455773e+02, -1.3439723e+02, -1.6704153e+02, - -1.9839956e+02, -2.3387826e+02, -2.6412575e+02, -2.9170423e+02, - -3.1531207e+02, -3.3274995e+02, -3.4693113e+02, -3.5369132e+02, - -3.5301724e+02, -3.4943527e+02, -3.3608402e+02, -3.1755446e+02, - -2.9205556e+02, -2.6071672e+02, -2.2432542e+02, -1.8738248e+02, - -1.4392604e+02, -1.0106545e+02, -5.5577429e+01, -9.8667562e+00, - 3.7353443e+01, 7.5303068e+01, 1.1105079e+02, 1.4264083e+02, - 1.7184174e+02, 1.9822361e+02, 2.2081903e+02, 2.4084291e+02, - 2.5643437e+02, 2.6758684e+02, 2.7445589e+02, 2.7569331e+02, - 2.7159104e+02, 2.6648908e+02, 2.5914969e+02, 2.4863883e+02, - 2.3470167e+02, 2.2613959e+02, 2.1126267e+02, 2.0090440e+02, - 1.8404815e+02, 1.6736836e+02, 1.5327263e+02, 1.3857671e+02, - 1.2564592e+02, 1.1183479e+02, 9.8674586e+01, 7.9462699e+01, - 6.1566145e+01, 3.4757509e+01, 9.1597341e+00, -1.6506764e+01, - -4.4310986e+01, -7.7716465e+01, -1.1113407e+02, -1.4150980e+02 ], - - [ -1.6775203e+02, -2.0410277e+02, -2.4176001e+02, -2.7386652e+02, - -2.9629852e+02, -3.0908748e+02, -3.0195831e+02, -2.8578850e+02, - -2.6686979e+02, -2.6140403e+02, -2.6601879e+02, -2.7595293e+02, - -2.8053255e+02, -2.9088609e+02, -2.8340082e+02, -2.8587804e+02, - -2.5164112e+02, -2.1308294e+02, -1.5229837e+02, -8.7968057e+01, - -3.9965246e+01, 1.9682469e+01, 8.3439201e+01, 1.3071313e+02, - 2.0278676e+02, 2.2530998e+02, 2.4917273e+02, 2.2837462e+02, - 2.0851337e+02, 1.8379204e+02, 1.0597931e+02, 5.0251896e+01, - 5.3816342e+01, 1.9418724e+02, 3.6073746e+02, 4.9001894e+02, - 5.6206313e+02, 5.4551465e+02, 5.0418915e+02, 3.9875911e+02, - 2.9036149e+02, 2.1569487e+02, 1.2216776e+02, 5.6342202e+01, - 1.9881173e+01, -1.0527142e+01, -2.8641229e+01, -6.5396380e+01, - -2.2087227e+01, -1.9320385e+00, 9.9837180e+00, -1.2901176e+01, - -4.8912099e+01, -1.0229260e+02, -1.3236180e+02, -1.1357973e+02, - -1.6394336e+02, -2.0430337e+02, -2.3625105e+02, -2.7025726e+02, - -2.1302135e+02, -2.2632729e+02, -2.0952571e+02, -2.1427507e+02, - -2.5180218e+02, -2.9681097e+02, -3.2929367e+02, -3.2993365e+02, - -3.3630273e+02, -3.0716107e+02, -2.2776881e+02, -2.2007043e+02, - -1.7036950e+02, -1.6356561e+02, -1.0711820e+02, 3.8723772e+01, - 9.2665406e+01, 1.2719129e+02, 2.3419328e+02, 2.4827798e+02, - 2.2061102e+02, 1.4474493e+02, 1.0064081e+02, 9.5343023e+01, - 5.5501524e+01, 3.6218435e+00, -6.9277352e+01, -1.2309115e+01, - -2.9683737e+01, -1.1059060e+01, 1.2650129e+02, 2.8907139e+02, - 5.9646998e+02, 7.2219690e+02, 6.4274592e+02, 2.5572095e+02, - 8.9009716e+00, -1.6887796e+02, -5.4165018e+02, -8.8289542e+02, - -9.0816906e+02, 2.8400805e+02, 1.3941683e+03, 1.4288425e+03, - 1.0428507e+03, 6.0910516e+02, 4.9505488e+02, 5.1165385e+02, - -4.9324168e+01, -5.0538446e+02, -6.1278936e+02, -6.0237215e+02, - -1.0190721e+03, -1.3790932e+03, -1.3541381e+03, 7.7933615e+01, - 1.3253623e+03, 1.3970218e+03, 1.1115023e+03, 7.7044387e+02, - 5.1675398e+02, 2.7357534e+02, -1.1882263e+02, -3.6893899e+02, - -5.9907798e+02, -6.8538645e+02, -1.0290340e+03, -1.2093927e+03, - -1.3183905e+03, -6.4097534e+02, 7.8577340e+02, 1.3858651e+03, - 1.2575136e+03, 1.0978140e+03, 7.7239776e+02, 3.5047643e+02, - 1.3677282e+02, -2.9932975e+01, -3.3626785e+02, -6.8938845e+02, - -8.0039496e+02, -8.8267000e+02, -8.9787173e+02, -8.6951038e+02, - 4.6805939e+02, 1.7552178e+03, 1.5546574e+03, 1.1148179e+03, - 7.4606055e+02, 5.7001670e+02, 3.6944970e+02, 9.7838518e+01, - -1.1941272e+02, -4.1377871e+02, -7.6382784e+02, -8.4434380e+02, - -7.9151095e+02, -8.6493987e+02, -2.8343467e+02, 1.2284377e+03 ], - -]) - -LTPF_C3_PREV = np.array([ - - [ 6.4066155e+01, 9.8702625e+01, 1.3788395e+02, 1.7357908e+02, - 2.0965843e+02, 2.3764314e+02, 2.6644923e+02, 2.9043075e+02, - 3.1194822e+02, 3.2482869e+02, 3.3339160e+02, 3.4071606e+02, - 3.4077768e+02, 3.3516446e+02, 3.2705459e+02, 3.1766371e+02, - 3.0450863e+02, 2.8884502e+02, 2.7626398e+02, 2.5687540e+02, - 2.3783751e+02, 2.1914457e+02, 1.9792827e+02, 1.7491941e+02, - 1.5135385e+02, 1.2210867e+02, 9.3873907e+01, 6.1133113e+01, - 2.5655472e+01, -9.0068272e+00, -4.6864087e+01, -8.5961652e+01, - -1.2549724e+02, -1.6396142e+02, -2.0212479e+02, -2.3817055e+02, - -2.7665292e+02, -3.0851152e+02, -3.4115267e+02, -3.6978674e+02, - -3.9095963e+02, -4.0758998e+02, -4.1787548e+02, -4.2041787e+02, - -4.1483578e+02, -4.0572811e+02, -3.8202738e+02, -3.5555284e+02, - -3.2171184e+02, -2.8408934e+02, -2.3936543e+02, -1.8996836e+02, - -1.4140617e+02, -9.0899975e+01, -4.2131433e+01, 5.1447212e+00, - 5.1259588e+01, 9.2032590e+01, 1.3108193e+02, 1.6957969e+02, - 2.0599062e+02, 2.3735997e+02, 2.6672423e+02, 2.9065678e+02, - 3.1149055e+02, 3.2543573e+02, 3.3604446e+02, 3.4053351e+02, - 3.4068048e+02, 3.3756977e+02, 3.3026320e+02, 3.2068706e+02, - 3.0912932e+02, 2.9328335e+02, 2.7625928e+02, 2.6245063e+02, - 2.4670232e+02, 2.2666582e+02, 2.0533576e+02, 1.8873190e+02, - 1.6715637e+02, 1.4420637e+02, 1.1629663e+02, 8.8561616e+01, - 5.8962789e+01, 2.5166894e+01, -1.1130553e+01, -4.5737395e+01, - -8.2162714e+01, -1.2346999e+02, -1.6150200e+02, -2.0028107e+02, - -2.3669696e+02, -2.7393564e+02, -3.0977094e+02, -3.4398480e+02, - -3.6896668e+02, -3.9241987e+02, -4.0955117e+02, -4.2052014e+02, - -4.2287410e+02, -4.1573504e+02, -4.0403021e+02, -3.8178373e+02, - -3.5516185e+02, -3.2075205e+02, -2.8058887e+02, -2.3403076e+02, - -1.8587624e+02, -1.3565255e+02, -8.4981034e+01, -3.4327765e+01, - 1.6122604e+01, 6.2803153e+01, 1.0703665e+02, 1.4333420e+02, - 1.8149169e+02, 2.1834576e+02, 2.4733100e+02, 2.7545243e+02, - 2.9756989e+02, 3.1498586e+02, 3.2836159e+02, 3.3505102e+02, - 3.3656005e+02, 3.3923920e+02, 3.3129967e+02, 3.2145289e+02, - 3.1074707e+02, 2.9901767e+02, 2.8311559e+02, 2.6682498e+02, - 2.4940742e+02, 2.3261497e+02, 2.1196627e+02, 1.9333406e+02, - 1.7509963e+02, 1.5279050e+02, 1.3109055e+02, 1.0449469e+02, - 7.8409595e+01, 4.9363873e+01, 1.7554459e+01, -1.5539732e+01, - -4.8805768e+01, -8.5198692e+01, -1.2189071e+02, -1.5886754e+02, - -1.9634205e+02, -2.3335312e+02, -2.7073502e+02, -3.0557489e+02, - -3.3663951e+02, -3.6449227e+02, -3.8546603e+02, -4.0164063e+02, - -4.1170176e+02, -4.1157567e+02, -4.0619410e+02, -3.9613725e+02 ], - - [ -3.7147766e+02, -3.4548841e+02, -3.1333857e+02, -2.7463625e+02, - -2.2842732e+02, -1.8027124e+02, -1.3148070e+02, -8.3137241e+01, - -3.0054878e+01, 1.9883532e+01, 6.6714609e+01, 1.0807815e+02, - 1.4822202e+02, 1.8586131e+02, 2.1800420e+02, 2.5060047e+02, - 2.7401990e+02, 2.9513896e+02, 3.1106912e+02, 3.2286594e+02, - 3.2918272e+02, 3.2833211e+02, 3.2739842e+02, 3.2088124e+02, - 3.1147526e+02, 2.9799117e+02, 2.8657122e+02, 2.7043218e+02, - 2.5431668e+02, 2.3996550e+02, 2.2300791e+02, 2.0270053e+02, - 1.8568534e+02, 1.6689279e+02, 1.5012389e+02, 1.2962033e+02, - 1.0942755e+02, 8.6477433e+01, 5.9720239e+01, 3.1778371e+01, - 2.9431398e+00, -2.9247908e+01, -6.3765298e+01, -9.6917096e+01, - -1.3470119e+02, -1.7108334e+02, -2.0808704e+02, -2.4574024e+02, - -2.8326377e+02, -3.1633765e+02, -3.4671102e+02, -3.7097994e+02, - -3.8869922e+02, -4.0237282e+02, -4.0334704e+02, -4.0408504e+02, - -3.9385794e+02, -3.7723701e+02, -3.5253919e+02, -3.2150862e+02, - -2.8492979e+02, -2.4106826e+02, -1.9287257e+02, -1.4370111e+02, - -9.5563935e+01, -4.3545337e+01, 7.0713976e+00, 5.5117442e+01, - 1.0039302e+02, 1.3954207e+02, 1.7504613e+02, 2.0852764e+02, - 2.3658875e+02, 2.6248596e+02, 2.8111481e+02, 2.9971212e+02, - 3.1019868e+02, 3.1449414e+02, 3.1475549e+02, 3.1252800e+02, - 3.0472635e+02, 2.9675698e+02, 2.8382811e+02, 2.7136329e+02, - 2.5584249e+02, 2.4078158e+02, 2.2398280e+02, 2.0974116e+02, - 1.9071035e+02, 1.7568738e+02, 1.5790704e+02, 1.4374608e+02, - 1.2653380e+02, 1.0989392e+02, 8.5342354e+01, 6.5160001e+01, - 3.5365747e+01, 9.6994716e+00, -1.9148759e+01, -5.2247954e+01, - -8.4460390e+01, -1.1917021e+02, -1.5343168e+02, -1.9000568e+02, - -2.2535999e+02, -2.6422733e+02, -2.9746477e+02, -3.2794048e+02, - -3.5381425e+02, -3.7289983e+02, -3.8800620e+02, -3.9445315e+02, - -3.9341234e+02, -3.8871213e+02, -3.7329028e+02, -3.5219370e+02, - -3.2339521e+02, -2.8848818e+02, -2.4782613e+02, -2.0517168e+02, - -1.5630958e+02, -1.0872773e+02, -5.8413582e+01, -7.9029246e+00, - 4.3081069e+01, 8.5378547e+01, 1.2552492e+02, 1.6074903e+02, - 1.9342830e+02, 2.2272087e+02, 2.4784891e+02, 2.6963531e+02, - 2.8673587e+02, 2.9921346e+02, 3.0619842e+02, 3.0724158e+02, - 3.0343005e+02, 2.9800183e+02, 2.8972999e+02, 2.7822622e+02, - 2.6355926e+02, 2.5308771e+02, 2.3630848e+02, 2.2381546e+02, - 2.0555172e+02, 1.8801065e+02, 1.7231093e+02, 1.5597740e+02, - 1.4132322e+02, 1.2578292e+02, 1.1037371e+02, 8.8726457e+01, - 6.8198855e+01, 3.9334854e+01, 1.1725578e+01, -1.6214439e+01, - -4.7122569e+01, -8.2888237e+01, -1.1823402e+02, -1.5159407e+02 ], - -]) - -LTPF_C3_TRANS = np.array([ - - -1.8246409e+02, -2.2173994e+02, -2.6085374e+02, -2.9483717e+02, - -3.2011835e+02, -3.3711584e+02, -3.3663215e+02, -3.2868626e+02, - -3.1677331e+02, -3.1352548e+02, -3.1534653e+02, -3.1872408e+02, - -3.1513281e+02, -3.1569554e+02, -2.9910316e+02, -2.9198409e+02, - -2.5148901e+02, -2.0982533e+02, -1.4838034e+02, -8.5301198e+01, - -3.6694674e+01, 2.3482066e+01, 8.5828448e+01, 1.3216759e+02, - 2.0172964e+02, 2.2393590e+02, 2.4953564e+02, 2.3256572e+02, - 2.1734484e+02, 1.9615122e+02, 1.2352168e+02, 7.1940230e+01, - 7.4762310e+01, 2.0724785e+02, 3.6354237e+02, 4.8584290e+02, - 5.5511323e+02, 5.3946449e+02, 5.0046673e+02, 3.9744659e+02, - 2.9036149e+02, 2.1569487e+02, 1.2216776e+02, 5.6342202e+01, - 1.9881173e+01, -1.0527142e+01, -2.8641229e+01, -6.5396380e+01, - -2.2087227e+01, -1.9320385e+00, 9.9837180e+00, -1.2901176e+01, - -4.8912099e+01, -1.0229260e+02, -1.3236180e+02, -1.1357973e+02, - -1.6394336e+02, -2.0430337e+02, -2.3625105e+02, -2.7025726e+02, - -2.1302135e+02, -2.2632729e+02, -2.0952571e+02, -2.1427507e+02, - -2.5180218e+02, -2.9681097e+02, -3.2929367e+02, -3.2993365e+02, - -3.3630273e+02, -3.0716107e+02, -2.2776881e+02, -2.2007043e+02, - -1.7036950e+02, -1.6356561e+02, -1.0711820e+02, 3.8723772e+01, - 9.2665406e+01, 1.2719129e+02, 2.3419328e+02, 2.4827798e+02, - 2.2061102e+02, 1.4474493e+02, 1.0064081e+02, 9.5343023e+01, - 5.5501524e+01, 3.6218435e+00, -6.9277352e+01, -1.2309115e+01, - -2.9683737e+01, -1.1059060e+01, 1.2650129e+02, 2.8907139e+02, - 5.9646998e+02, 7.2219690e+02, 6.4274592e+02, 2.5572095e+02, - 8.9009716e+00, -1.6887796e+02, -5.4165018e+02, -8.8289542e+02, - -9.0816906e+02, 2.8400805e+02, 1.3941683e+03, 1.4288425e+03, - 1.0428507e+03, 6.0910516e+02, 4.9505488e+02, 5.1165385e+02, - -4.9324168e+01, -5.0538446e+02, -6.1278936e+02, -6.0237215e+02, - -1.0190721e+03, -1.3790932e+03, -1.3541381e+03, 7.7933615e+01, - 1.3253623e+03, 1.3970218e+03, 1.1115023e+03, 7.7044387e+02, - 5.1675398e+02, 2.7357534e+02, -1.1882263e+02, -3.6893899e+02, - -5.9907798e+02, -6.8538645e+02, -1.0290340e+03, -1.2093927e+03, - -1.3183905e+03, -6.4097534e+02, 7.8577340e+02, 1.3858651e+03, - 1.2575136e+03, 1.0978140e+03, 7.7239776e+02, 3.5047643e+02, - 1.3677282e+02, -2.9932975e+01, -3.3626785e+02, -6.8938845e+02, - -8.0039496e+02, -8.8267000e+02, -8.9787173e+02, -8.6951038e+02, - 4.6805939e+02, 1.7552178e+03, 1.5546574e+03, 1.1148179e+03, - 7.4606055e+02, 5.7001670e+02, 3.6944970e+02, 9.7838518e+01, - -1.1941272e+02, -4.1377871e+02, -7.6382784e+02, -8.4434380e+02, - -7.9151095e+02, -8.6493987e+02, -2.8343467e+02, 1.2284377e+03, - -]) - -LTPF_C4_NBITS = 320 - -LTPF_C4_ACTIVE = np.array([ True, True ]) -LTPF_C4_PITCH_INDEX = np.array([ 56, 56 ]) - -LTPF_C4_C_N = np.array([ - [ 2.0480302e-01, 1.4271871e-01, -6.4036434e-03 ], - [ 2.0480302e-01, 1.4271871e-01, -6.4036434e-03 ], -]) - -LTPF_C4_C_D = np.array([ - [ 1.5868459e-02, 1.8368837e-01, 1.8368837e-01, 1.5868459e-02 ], - [ 1.5868459e-02, 1.8368837e-01, 1.8368837e-01, 1.5868459e-02 ], -]) - -LTPF_C4_X = np.array([ - - [ -1.3212378e+02, 4.5530263e+00, 1.4615982e+02, 2.9071151e+02, - 4.2471908e+02, 5.4825306e+02, 6.6032559e+02, 7.5740827e+02, - 8.3891172e+02, 9.0995714e+02, 9.6747077e+02, 1.0121710e+03, - 1.0274871e+03, 1.0037721e+03, 9.3793010e+02, 8.2480912e+02, - 6.6687812e+02, 5.0610704e+02, 3.7535508e+02, 2.8417912e+02, - 2.3507950e+02, 2.2431573e+02, 2.3503665e+02, 2.5100781e+02, - 2.5591188e+02, 2.4573096e+02, 2.3732458e+02, 2.2379033e+02, - 2.0393082e+02, 1.7940329e+02, 1.5349002e+02, 1.2421970e+02, - 8.2607174e+01, 3.3890085e+01, -1.4919514e+01, -6.7050562e+01, - -1.2022717e+02, -1.7802094e+02, -2.3045847e+02, -2.7788664e+02, - -3.3683640e+02, -4.1806874e+02, -5.2071432e+02, -6.3745995e+02, - -7.6831195e+02, -8.9933303e+02, -1.0058396e+03, -1.0704297e+03, - -1.0883680e+03, -1.0715794e+03, -1.0235340e+03, -9.4781945e+02, - -8.5584778e+02, -7.4716794e+02, -6.2920874e+02, -5.0223965e+02, - -3.6316475e+02, -2.2074077e+02, -7.5442666e+01, 6.7658245e+01, - 2.0420074e+02, 3.3396592e+02, 4.4656898e+02, 5.4596637e+02, - 6.3808859e+02, 7.2787698e+02, 8.1472882e+02, 8.9279612e+02, - 9.5178350e+02, 9.7288475e+02, 9.4735790e+02, 8.8244167e+02, - 7.9508887e+02, 7.0282080e+02, 6.0598321e+02, 5.1640859e+02, - 4.3937674e+02, 3.7245496e+02, 3.2160255e+02, 2.8003421e+02, - 2.5119199e+02, 2.3495839e+02, 2.2200688e+02, 2.0973737e+02, - 1.9073208e+02, 1.6793312e+02, 1.4320783e+02, 1.1276855e+02, - 8.0839691e+01, 4.8429863e+01, 1.1662609e+01, -3.3424450e+01, - -7.9726479e+01, -1.2393767e+02, -1.7110449e+02, -2.1662821e+02, - -2.6310613e+02, -3.1774127e+02, -3.9885548e+02, -5.1583270e+02, - -6.4243905e+02, -7.6184139e+02, -8.6566023e+02, -9.4822201e+02, - -1.0112142e+03, -1.0437627e+03, -1.0457937e+03, -1.0207768e+03, - -9.6819885e+02, -8.9378058e+02, -7.9861844e+02, -6.8734848e+02, - -5.6329990e+02, -4.2840844e+02, -2.8589443e+02, -1.4101586e+02, - -5.6273423e-01, 1.3949815e+02, 2.7417238e+02, 4.0010557e+02, - 5.2193759e+02, 6.3439172e+02, 7.3810702e+02, 8.2658657e+02, - 8.9885978e+02, 9.5846967e+02, 9.8349123e+02, 9.6474177e+02, - 9.0987618e+02, 8.3178192e+02, 7.4721512e+02, 6.6076640e+02, - 5.7958128e+02, 5.0626404e+02, 4.3829495e+02, 3.7955641e+02, - 3.3400402e+02, 3.0012060e+02, 2.6635949e+02, 2.3180026e+02, - 1.9980913e+02, 1.7106449e+02, 1.4708346e+02, 1.1651799e+02, - 8.3457665e+01, 5.6291779e+01, 3.0698836e+01, 5.4712667e+00, - -2.9709210e+01, -7.0496428e+01, -1.0899206e+02, -1.5337912e+02, - -1.9940203e+02, -2.4464990e+02, -2.9496636e+02, -3.6218204e+02, - -4.5477003e+02, -5.6091604e+02, -6.6582484e+02, -7.5807547e+02 ], - - [ -8.3474175e+02, -8.9039341e+02, -9.2355843e+02, -9.3729800e+02, - -9.2464041e+02, -8.9038579e+02, -8.3678014e+02, -7.6008712e+02, - -6.6935538e+02, -5.6422713e+02, -4.4941540e+02, -3.2822721e+02, - -1.9802065e+02, -6.6766936e+01, 6.3833225e+01, 1.9485046e+02, - 3.2069998e+02, 4.3761734e+02, 5.4460736e+02, 6.4521909e+02, - 7.4169295e+02, 8.2759672e+02, 8.9638366e+02, 9.3673025e+02, - 9.4669839e+02, 9.2302657e+02, 8.8064813e+02, 8.2833056e+02, - 7.6070809e+02, 6.9391450e+02, 6.2171679e+02, 5.4789771e+02, - 4.8160318e+02, 4.2010754e+02, 3.6391872e+02, 3.1081191e+02, - 2.6834464e+02, 2.2822565e+02, 1.8578653e+02, 1.5071546e+02, - 1.1735576e+02, 8.3222831e+01, 4.9624826e+01, 1.0744867e+01, - -2.5764012e+01, -6.4812135e+01, -1.0358083e+02, -1.4353059e+02, - -1.8297458e+02, -2.2359073e+02, -2.6775258e+02, -3.1656152e+02, - -3.7871430e+02, -4.4751491e+02, -5.2485941e+02, -6.0299909e+02, - -6.8515536e+02, -7.6401821e+02, -8.2770748e+02, -8.7387481e+02, - -8.9915932e+02, -9.0643654e+02, -8.8914063e+02, -8.5144521e+02, - -7.9103639e+02, -7.1441804e+02, -6.2692990e+02, -5.2729939e+02, - -4.2275301e+02, -3.0657474e+02, -1.8688744e+02, -6.1633756e+01, - 5.8686296e+01, 1.8250335e+02, 3.0377201e+02, 4.1978552e+02, - 5.3054960e+02, 6.2835118e+02, 7.2035468e+02, 7.9934358e+02, - 8.5642737e+02, 8.9765907e+02, 9.2069014e+02, 9.1957966e+02, - 8.9145864e+02, 8.3848660e+02, 7.7429387e+02, 7.0401776e+02, - 6.3210907e+02, 5.6076246e+02, 4.9172735e+02, 4.2473574e+02, - 3.6317680e+02, 3.0715534e+02, 2.5275264e+02, 2.0664538e+02, - 1.6042746e+02, 1.1820978e+02, 7.3335304e+01, 3.4381568e+01, - -5.8542117e+00, -4.4553111e+01, -8.3479478e+01, -1.2048090e+02, - -1.6116063e+02, -2.0192831e+02, -2.4373220e+02, -2.8256043e+02, - -3.2919802e+02, -3.7322793e+02, -4.2010268e+02, -4.7218497e+02, - -5.3461522e+02, -6.1386549e+02, -6.9152470e+02, -7.6738453e+02, - -8.2527123e+02, -8.6158674e+02, -8.7895938e+02, -8.7597504e+02, - -8.5108741e+02, -8.0480220e+02, -7.4250154e+02, -6.5876002e+02, - -5.6356029e+02, -4.5524527e+02, -3.4038894e+02, -2.2360514e+02, - -1.0268552e+02, 2.5676655e+01, 1.5166378e+02, 2.7540954e+02, - 3.9465179e+02, 5.0881759e+02, 6.1514014e+02, 7.1241132e+02, - 7.9504576e+02, 8.7166197e+02, 9.3226594e+02, 9.7438372e+02, - 9.8472937e+02, 9.6485548e+02, 9.1860685e+02, 8.5256605e+02, - 7.8008367e+02, 7.0149395e+02, 6.2054247e+02, 5.4108956e+02, - 4.6123090e+02, 3.8599064e+02, 3.1521582e+02, 2.4589274e+02, - 1.8211975e+02, 1.3163470e+02, 8.4985461e+01, 3.6873046e+01, - -6.0437124e+00, -4.8770494e+01, -8.4128492e+01, -1.2196451e+02 ], - -]) - -LTPF_C4_PREV = np.array([ - - [ 8.5827694e+02, 8.3064489e+02, 8.0499625e+02, 7.8056066e+02, - 7.6744901e+02, 7.5611316e+02, 7.1123694e+02, 6.4234457e+02, - 5.7975881e+02, 5.3276775e+02, 5.0354201e+02, 4.6493297e+02, - 4.2651511e+02, 3.8147439e+02, 3.2876260e+02, 2.7004720e+02, - 2.0149312e+02, 1.2434150e+02, 4.6683685e+01, -2.4488830e+01, - -9.4758661e+01, -1.6910076e+02, -2.4454068e+02, -3.2272819e+02, - -4.1153117e+02, -5.2406430e+02, -6.6312995e+02, -7.9501146e+02, - -9.1517707e+02, -1.0195879e+03, -1.1003671e+03, -1.1506760e+03, - -1.1718109e+03, -1.1569278e+03, -1.1251298e+03, -1.0925962e+03, - -1.0572755e+03, -1.0074938e+03, -9.3394117e+02, -8.3773785e+02, - -7.2203590e+02, -5.9088086e+02, -4.5612949e+02, -3.2040519e+02, - -1.7104088e+02, -2.9232508e+01, 1.0254422e+02, 2.3645451e+02, - 3.6931210e+02, 4.8954097e+02, 5.9869449e+02, 7.0325516e+02, - 7.9700038e+02, 8.6886012e+02, 9.1083211e+02, 9.2243956e+02, - 9.0940850e+02, 8.7320143e+02, 8.2061884e+02, 7.7544913e+02, - 7.3767280e+02, 7.0507470e+02, 6.8093384e+02, 6.6014067e+02, - 6.3137283e+02, 6.0264808e+02, 5.6924398e+02, 5.4487108e+02, - 5.1295321e+02, 4.8260718e+02, 4.4645113e+02, 4.0584256e+02, - 3.5619699e+02, 2.8935939e+02, 2.1760106e+02, 1.4449684e+02, - 7.4653166e+01, -1.4735621e+00, -8.3781827e+01, -1.5582846e+02, - -2.3783590e+02, -3.2355910e+02, -4.0747488e+02, -5.0371066e+02, - -6.0048961e+02, -7.0726549e+02, -8.2713764e+02, -9.4294256e+02, - -1.0401191e+03, -1.1242695e+03, -1.1843296e+03, -1.1977911e+03, - -1.1759957e+03, -1.1382443e+03, -1.0869538e+03, -1.0150254e+03, - -9.2445459e+02, -8.2418678e+02, -7.1231843e+02, -5.8566805e+02, - -4.4749524e+02, -3.2163393e+02, -1.9483077e+02, -6.6146712e+01, - 7.2606186e+01, 2.1709089e+02, 3.6141116e+02, 4.9774327e+02, - 6.2102585e+02, 7.3301494e+02, 8.2884523e+02, 9.1772806e+02, - 9.8287592e+02, 1.0258870e+03, 1.0350466e+03, 1.0124387e+03, - 9.5526828e+02, 8.4870459e+02, 6.9698370e+02, 5.5384197e+02, - 4.7329566e+02, 4.4187783e+02, 4.2164793e+02, 4.0723567e+02, - 4.0287348e+02, 3.9294225e+02, 3.8536364e+02, 3.6737694e+02, - 3.4038387e+02, 3.2024898e+02, 2.9202545e+02, 2.5623304e+02, - 2.0059931e+02, 1.4494932e+02, 8.7316562e+01, 2.0208470e+01, - -5.1106062e+01, -1.0972390e+02, -1.7160643e+02, -2.3635682e+02, - -3.0057986e+02, -3.6841959e+02, -4.5812030e+02, -5.5409463e+02, - -6.5667832e+02, -7.6531178e+02, -9.0843842e+02, -1.0761546e+03, - -1.2069858e+03, -1.2737779e+03, -1.2929641e+03, -1.2624172e+03, - -1.2008239e+03, -1.1122508e+03, -9.9807662e+02, -8.7056340e+02, - -7.3753241e+02, -6.0499387e+02, -4.6029956e+02, -3.2128673e+02 ], - - [ -1.8675929e+02, -4.2406693e+01, 1.0644289e+02, 2.5996083e+02, - 4.0591306e+02, 5.4343259e+02, 6.6906247e+02, 7.7899810e+02, - 8.7298704e+02, 9.5506440e+02, 1.0209952e+03, 1.0688758e+03, - 1.0833988e+03, 1.0572928e+03, 9.8779757e+02, 8.6895392e+02, - 7.0635769e+02, 5.4680902e+02, 4.2601966e+02, 3.4987333e+02, - 3.1179292e+02, 3.0331866e+02, 3.0951274e+02, 3.1789860e+02, - 3.1563910e+02, 3.0013119e+02, 2.8624618e+02, 2.6714149e+02, - 2.4150830e+02, 2.0837106e+02, 1.7059521e+02, 1.2855863e+02, - 7.5094806e+01, 1.5176971e+01, -4.3358321e+01, -1.0315083e+02, - -1.6398964e+02, -2.2910287e+02, -2.9037721e+02, -3.5326931e+02, - -4.3186627e+02, -5.2797253e+02, -6.4097239e+02, -7.7021355e+02, - -9.1916034e+02, -1.0635912e+03, -1.1696907e+03, -1.2240756e+03, - -1.2277996e+03, -1.1942767e+03, -1.1287017e+03, -1.0350001e+03, - -9.2445100e+02, -7.9889645e+02, -6.6691580e+02, -5.2684803e+02, - -3.7726996e+02, -2.2821747e+02, -7.6317887e+01, 7.6079467e+01, - 2.2531300e+02, 3.6948450e+02, 4.9788068e+02, 6.1407961e+02, - 7.2081446e+02, 8.2045742e+02, 9.1242924e+02, 9.9212633e+02, - 1.0508862e+03, 1.0718419e+03, 1.0464386e+03, 9.7937941e+02, - 8.8142794e+02, 7.6477603e+02, 6.3740319e+02, 5.2412010e+02, - 4.3571759e+02, 3.6988854e+02, 3.2884698e+02, 3.0173096e+02, - 2.8691049e+02, 2.7882926e+02, 2.6731147e+02, 2.5356111e+02, - 2.3340364e+02, 2.0894382e+02, 1.8071643e+02, 1.4579425e+02, - 1.0855560e+02, 6.8052759e+01, 2.0813765e+01, -3.3555159e+01, - -8.7826734e+01, -1.4078458e+02, -1.9733530e+02, -2.5226649e+02, - -3.0811893e+02, -3.7371017e+02, -4.6559419e+02, -5.8909591e+02, - -7.2198295e+02, -8.5479624e+02, -9.7874703e+02, -1.0795937e+03, - -1.1503967e+03, -1.1796433e+03, -1.1713652e+03, -1.1317595e+03, - -1.0619895e+03, -9.6960460e+02, -8.5726543e+02, -7.3060563e+02, - -5.9289544e+02, -4.4495754e+02, -2.9059997e+02, -1.3479531e+02, - 1.7757467e+01, 1.7012020e+02, 3.1647370e+02, 4.5257127e+02, - 5.8125188e+02, 6.9866277e+02, 8.0708027e+02, 9.0151273e+02, - 9.8106784e+02, 1.0459462e+03, 1.0733030e+03, 1.0542555e+03, - 9.9525660e+02, 9.0830183e+02, 8.0934326e+02, 7.0399220e+02, - 6.0377076e+02, 5.1638905e+02, 4.4150465e+02, 3.8256291e+02, - 3.4048809e+02, 3.1118639e+02, 2.8406392e+02, 2.5713040e+02, - 2.3131764e+02, 2.0600503e+02, 1.8197113e+02, 1.5035197e+02, - 1.1569230e+02, 8.4266914e+01, 5.1996878e+01, 1.7843797e+01, - -2.6863170e+01, -7.5983644e+01, -1.2245636e+02, -1.7436828e+02, - -2.2708180e+02, -2.7906654e+02, -3.3755256e+02, -4.1588336e+02, - -5.2295173e+02, -6.4523634e+02, -7.6683613e+02, -8.7677439e+02 ], - -]) - -LTPF_C4_TRANS = np.array([ - - -9.6976885e+02, -1.0376330e+03, -1.0764010e+03, -1.0872965e+03, - -1.0660439e+03, -1.0190108e+03, -9.4899438e+02, -8.5471701e+02, - -7.4561708e+02, -6.2178553e+02, -4.8798080e+02, -3.4713910e+02, - -1.9841833e+02, -5.0343781e+01, 9.6414723e+01, 2.4225179e+02, - 3.8080735e+02, 5.0947979e+02, 6.2776176e+02, 7.3826963e+02, - 8.4169803e+02, 9.3159353e+02, 1.0031138e+03, 1.0438329e+03, - 1.0480614e+03, 1.0127914e+03, 9.5385188e+02, 8.8138762e+02, - 7.9431025e+02, 7.0979394e+02, 6.2416163e+02, 5.4300509e+02, - 4.7372434e+02, 4.1360311e+02, 3.6279724e+02, 3.1673275e+02, - 2.7937838e+02, 2.4267574e+02, 2.0418215e+02, 1.7211796e+02, - 1.3914947e+02, 1.0348883e+02, 6.8276707e+01, 2.9143910e+01, - -7.9633499e+00, -4.9829988e+01, -9.3834050e+01, -1.3941156e+02, - -1.8501204e+02, -2.3271716e+02, -2.8327412e+02, -3.3841588e+02, - -4.0881202e+02, -4.9188847e+02, -5.8927352e+02, -6.8905431e+02, - -7.8967502e+02, -8.8144454e+02, -9.5326854e+02, -1.0026317e+03, - -1.0264190e+03, -1.0268593e+03, -9.9874748e+02, -9.4795333e+02, - -8.7252905e+02, -7.7954835e+02, -6.7411996e+02, -5.5559866e+02, - -4.3134824e+02, -2.9558412e+02, -1.5723885e+02, -1.5143571e+01, - 1.2171974e+02, 2.6041913e+02, 3.9322892e+02, 5.1828299e+02, - 6.3629063e+02, 7.4159801e+02, 8.3990996e+02, 9.2215495e+02, - 9.7897443e+02, 1.0129522e+03, 1.0197564e+03, 9.9746243e+02, - 9.4932784e+02, 8.7962855e+02, 8.0193420e+02, 7.2094920e+02, - 6.4030858e+02, 5.6344020e+02, 4.9240203e+02, 4.2631986e+02, - 3.6714651e+02, 3.1424334e+02, 2.6363836e+02, 2.1946532e+02, - 1.7487874e+02, 1.3448581e+02, 9.0857113e+01, 5.1852661e+01, - 1.0318345e+01, -3.0189483e+01, -7.1704052e+01, -1.1290529e+02, - -1.5806523e+02, -2.0311837e+02, -2.4946754e+02, -2.9428673e+02, - -3.4738868e+02, -4.0117413e+02, -4.6307505e+02, -5.3393190e+02, - -6.1557536e+02, -7.0983150e+02, -7.9873811e+02, -8.8091592e+02, - -9.4071232e+02, -9.7639817e+02, -9.9018818e+02, -9.8005670e+02, - -9.4511932e+02, -8.8673987e+02, -8.1023192e+02, -7.1271293e+02, - -6.0397885e+02, -4.8247591e+02, -3.5415373e+02, -2.2240894e+02, - -8.6345911e+01, 5.4855371e+01, 1.9247458e+02, 3.2774740e+02, - 4.5715456e+02, 5.8013934e+02, 6.9372155e+02, 7.9720836e+02, - 8.8545637e+02, 9.6285451e+02, 1.0187327e+03, 1.0521050e+03, - 1.0516389e+03, 1.0206935e+03, 9.6358799e+02, 8.8842240e+02, - 8.0838051e+02, 7.2366647e+02, 6.3870123e+02, 5.5707357e+02, - 4.7704505e+02, 4.0312802e+02, 3.3463611e+02, 2.6847649e+02, - 2.0824825e+02, 1.5901226e+02, 1.1171069e+02, 6.3026014e+01, - 1.8987746e+01, -2.5300684e+01, -6.3942070e+01, -1.0563596e+02, - -]) - -LTPF_C5_NBITS = 320 - -LTPF_C5_ACTIVE = np.array([ True, True ]) -LTPF_C5_PITCH_INDEX = np.array([ 56, 52 ]) - -LTPF_C5_C_N = np.array([ - [ 2.0480302e-01, 1.4271871e-01, -6.4036434e-03 ], - [ 2.0480302e-01, 1.4271871e-01, -6.4036434e-03 ], -]) - -LTPF_C5_C_D = np.array([ - [ 1.5868459e-02, 1.8368837e-01, 1.8368837e-01, 1.5868459e-02 ], - [ 4.2799674e-02, 2.2003000e-01, 1.3427625e-01, 2.6795433e-03 ], -]) - -LTPF_C5_X = np.array([ - - [ -1.6060766e+02, -1.9568387e+02, -2.3100280e+02, -2.6630342e+02, - -3.0336764e+02, -3.3854889e+02, -3.7043669e+02, -4.1163573e+02, - -4.5567039e+02, -5.1558927e+02, -5.7814485e+02, -6.4080974e+02, - -6.9798700e+02, -7.4456362e+02, -7.7654511e+02, -7.9319453e+02, - -7.9402247e+02, -7.7652860e+02, -7.4572416e+02, -6.9989705e+02, - -6.3841065e+02, -5.6041492e+02, -4.6954673e+02, -3.7010557e+02, - -2.6541886e+02, -1.5525665e+02, -4.1036675e+01, 7.7898304e+01, - 1.9450287e+02, 3.0691788e+02, 4.1560715e+02, 5.1731671e+02, - 6.1122047e+02, 6.9593032e+02, 7.7071271e+02, 8.3246711e+02, - 8.7294256e+02, 8.9535004e+02, 8.9058119e+02, 8.6785095e+02, - 8.2896133e+02, 7.8301121e+02, 7.2447207e+02, 6.6383224e+02, - 5.9764845e+02, 5.3040514e+02, 4.6518541e+02, 3.9659186e+02, - 3.2746766e+02, 2.6753027e+02, 2.0739840e+02, 1.4677357e+02, - 9.5287069e+01, 4.7197825e+01, -1.1700140e+00, -4.9161682e+01, - -9.6726950e+01, -1.4038011e+02, -1.8662421e+02, -2.2897297e+02, - -2.6864070e+02, -3.1060300e+02, -3.4908047e+02, -3.8903634e+02, - -4.3354889e+02, -4.7982553e+02, -5.3003184e+02, -5.8409985e+02, - -6.3676286e+02, -6.8405252e+02, -7.2580553e+02, -7.5743871e+02, - -7.7706979e+02, -7.8082023e+02, -7.7270174e+02, -7.4653280e+02, - -7.1067906e+02, -6.5596456e+02, -5.8829707e+02, -5.0656026e+02, - -4.1202861e+02, -3.1175500e+02, -2.0302114e+02, -9.4710595e+01, - 2.0375247e+01, 1.3270062e+02, 2.4243959e+02, 3.5297406e+02, - 4.5553582e+02, 5.5590475e+02, 6.4792544e+02, 7.2690018e+02, - 7.9536436e+02, 8.5008231e+02, 8.8455109e+02, 9.0442411e+02, - 8.9923508e+02, 8.7803657e+02, 8.3884819e+02, 7.8786430e+02, - 7.2427475e+02, 6.5372622e+02, 5.8223046e+02, 5.0499317e+02, - 4.2757252e+02, 3.4979799e+02, 2.7384122e+02, 2.0202195e+02, - 1.3245127e+02, 6.9157310e+01, 1.0836031e+01, -5.0190037e+01, - -1.0459364e+02, -1.5805356e+02, -2.0733214e+02, -2.4766726e+02, - -2.9312137e+02, -3.3816241e+02, -3.7627128e+02, -4.1399424e+02, - -4.4836893e+02, -4.8327539e+02, -5.1189667e+02, -5.4560547e+02, - -5.8121896e+02, -6.1491595e+02, -6.4841741e+02, -6.7347617e+02, - -6.9479054e+02, -7.0418229e+02, -7.0192552e+02, -6.8320863e+02, - -6.5899253e+02, -6.2202504e+02, -5.7186005e+02, -5.1046639e+02, - -4.4158751e+02, -3.6145704e+02, -2.7098565e+02, -1.7538139e+02, - -7.6006538e+01, 2.3722024e+01, 1.2888233e+02, 2.3123425e+02, - 3.3082160e+02, 4.2819177e+02, 5.1739280e+02, 6.0102219e+02, - 6.7529473e+02, 7.3951297e+02, 8.0008252e+02, 8.4203459e+02, - 8.6655983e+02, 8.6963556e+02, 8.5619100e+02, 8.2481263e+02, - 7.8075652e+02, 7.2216895e+02, 6.6035959e+02, 5.8959592e+02 ], - - [ 5.1338681e+02, 4.3458985e+02, 3.6021867e+02, 2.8040781e+02, - 2.0424899e+02, 1.3450352e+02, 6.6513343e+01, 5.6705127e+00, - -5.2746410e+01, -1.1038385e+02, -1.6030998e+02, -2.0583244e+02, - -2.4887172e+02, -2.9195508e+02, -3.2720109e+02, -3.6021736e+02, - -3.9187844e+02, -4.2450350e+02, -4.5121148e+02, -4.8051913e+02, - -5.0679429e+02, -5.3473222e+02, -5.6274008e+02, -5.8904566e+02, - -6.1354818e+02, -6.2864496e+02, -6.3771702e+02, -6.3780508e+02, - -6.2690341e+02, -6.0523722e+02, -5.7468865e+02, -5.3607922e+02, - -4.8568411e+02, -4.2700735e+02, -3.5998795e+02, -2.8215398e+02, - -2.0120100e+02, -1.1187382e+02, -2.5873841e+01, 6.7900858e+01, - 1.6266005e+02, 2.5147024e+02, 3.4066102e+02, 4.2711439e+02, - 5.0521368e+02, 5.8027967e+02, 6.4926123e+02, 7.0606425e+02, - 7.5197499e+02, 7.7936955e+02, 7.9241574e+02, 7.9273830e+02, - 7.7226162e+02, 7.4318941e+02, 6.9912979e+02, 6.4987144e+02, - 5.8935287e+02, 5.2867427e+02, 4.5818050e+02, 3.9091836e+02, - 3.1175882e+02, 2.4316163e+02, 1.6901936e+02, 1.0131712e+02, - 4.0884705e+01, -1.8284360e+01, -7.2463773e+01, -1.2615956e+02, - -1.7449474e+02, -2.1740936e+02, -2.5946712e+02, -2.9956841e+02, - -3.3765147e+02, -3.6878225e+02, -4.0090001e+02, -4.3495156e+02, - -4.6061972e+02, -4.8952939e+02, -5.1712969e+02, -5.4061916e+02, - -5.6432757e+02, -5.8583512e+02, -5.9997738e+02, -6.0321240e+02, - -6.0215834e+02, -5.9411694e+02, -5.7827835e+02, -5.5352370e+02, - -5.2218352e+02, -4.8118496e+02, -4.3153207e+02, -3.7290541e+02, - -3.0763879e+02, -2.3045577e+02, -1.5030005e+02, -6.8343251e+01, - 1.9827505e+01, 1.0879534e+02, 2.0178224e+02, 2.8957061e+02, - 3.7779733e+02, 4.6428381e+02, 5.4088918e+02, 6.1377535e+02, - 6.8124334e+02, 7.3734864e+02, 7.7681316e+02, 8.0293170e+02, - 8.0890279e+02, 8.0620381e+02, 7.8580399e+02, 7.5204050e+02, - 7.1105755e+02, 6.5621411e+02, 5.9523050e+02, 5.2862471e+02, - 4.5293754e+02, 3.7743682e+02, 3.0188947e+02, 2.2243974e+02, - 1.4611001e+02, 6.9741588e+01, 3.0745399e+00, -6.6469812e+01, - -1.2845539e+02, -1.8845561e+02, -2.4293629e+02, -2.9314084e+02, - -3.3894702e+02, -3.8275365e+02, -4.2041853e+02, -4.5718992e+02, - -4.8545538e+02, -5.1088490e+02, -5.3523663e+02, -5.5122371e+02, - -5.7210009e+02, -5.8455365e+02, -5.9877467e+02, -6.0919241e+02, - -6.1143839e+02, -6.0342076e+02, -5.8730343e+02, -5.6903506e+02, - -5.3921882e+02, -5.0539402e+02, -4.6156875e+02, -4.1089541e+02, - -3.4967700e+02, -2.8252157e+02, -2.1092501e+02, -1.3135475e+02, - -4.8131277e+01, 3.4353741e+01, 1.2201908e+02, 2.0824054e+02, - 2.9606295e+02, 3.8043837e+02, 4.5867136e+02, 5.3182302e+02 ], - -]) - -LTPF_C5_PREV = np.array([ - - [ -9.6976885e+02, -1.0376330e+03, -1.0764010e+03, -1.0872965e+03, - -1.0660439e+03, -1.0190108e+03, -9.4899438e+02, -8.5471701e+02, - -7.4561708e+02, -6.2178553e+02, -4.8798080e+02, -3.4713910e+02, - -1.9841833e+02, -5.0343781e+01, 9.6414723e+01, 2.4225179e+02, - 3.8080735e+02, 5.0947979e+02, 6.2776176e+02, 7.3826963e+02, - 8.4169803e+02, 9.3159353e+02, 1.0031138e+03, 1.0438329e+03, - 1.0480614e+03, 1.0127914e+03, 9.5385188e+02, 8.8138762e+02, - 7.9431025e+02, 7.0979394e+02, 6.2416163e+02, 5.4300509e+02, - 4.7372434e+02, 4.1360311e+02, 3.6279724e+02, 3.1673275e+02, - 2.7937838e+02, 2.4267574e+02, 2.0418215e+02, 1.7211796e+02, - 1.3914947e+02, 1.0348883e+02, 6.8276707e+01, 2.9143910e+01, - -7.9633499e+00, -4.9829988e+01, -9.3834050e+01, -1.3941156e+02, - -1.8501204e+02, -2.3271716e+02, -2.8327412e+02, -3.3841588e+02, - -4.0881202e+02, -4.9188847e+02, -5.8927352e+02, -6.8905431e+02, - -7.8967502e+02, -8.8144454e+02, -9.5326854e+02, -1.0026317e+03, - -1.0264190e+03, -1.0268593e+03, -9.9874748e+02, -9.4795333e+02, - -8.7252905e+02, -7.7954835e+02, -6.7411996e+02, -5.5559866e+02, - -4.3134824e+02, -2.9558412e+02, -1.5723885e+02, -1.5143571e+01, - 1.2171974e+02, 2.6041913e+02, 3.9322892e+02, 5.1828299e+02, - 6.3629063e+02, 7.4159801e+02, 8.3990996e+02, 9.2215495e+02, - 9.7897443e+02, 1.0129522e+03, 1.0197564e+03, 9.9746243e+02, - 9.4932784e+02, 8.7962855e+02, 8.0193420e+02, 7.2094920e+02, - 6.4030858e+02, 5.6344020e+02, 4.9240203e+02, 4.2631986e+02, - 3.6714651e+02, 3.1424334e+02, 2.6363836e+02, 2.1946532e+02, - 1.7487874e+02, 1.3448581e+02, 9.0857113e+01, 5.1852661e+01, - 1.0318345e+01, -3.0189483e+01, -7.1704052e+01, -1.1290529e+02, - -1.5806523e+02, -2.0311837e+02, -2.4946754e+02, -2.9428673e+02, - -3.4738868e+02, -4.0117413e+02, -4.6307505e+02, -5.3393190e+02, - -6.1557536e+02, -7.0983150e+02, -7.9873811e+02, -8.8091592e+02, - -9.4071232e+02, -9.7639817e+02, -9.9018818e+02, -9.8005670e+02, - -9.4511932e+02, -8.8673987e+02, -8.1023192e+02, -7.1271293e+02, - -6.0397885e+02, -4.8247591e+02, -3.5415373e+02, -2.2240894e+02, - -8.6345911e+01, 5.4855371e+01, 1.9247458e+02, 3.2774740e+02, - 4.5715456e+02, 5.8013934e+02, 6.9372155e+02, 7.9720836e+02, - 8.8545637e+02, 9.6285451e+02, 1.0187327e+03, 1.0521050e+03, - 1.0516389e+03, 1.0206935e+03, 9.6358799e+02, 8.8842240e+02, - 8.0838051e+02, 7.2366647e+02, 6.3870123e+02, 5.5707357e+02, - 4.7704505e+02, 4.0312802e+02, 3.3463611e+02, 2.6847649e+02, - 2.0824825e+02, 1.5901226e+02, 1.1171069e+02, 6.3026014e+01, - 1.8987746e+01, -2.5300684e+01, -6.3942070e+01, -1.0563596e+02 ], - - [ -1.4774474e+02, -1.8760166e+02, -2.2888898e+02, -2.7036124e+02, - -3.1332685e+02, -3.5581512e+02, -3.9771599e+02, -4.4936892e+02, - -5.0524457e+02, -5.7736164e+02, -6.5368200e+02, -7.3121324e+02, - -8.0200835e+02, -8.5934306e+02, -8.9755526e+02, -9.1640499e+02, - -9.1557588e+02, -8.9266707e+02, -8.5215743e+02, -7.9312106e+02, - -7.1595184e+02, -6.2138325e+02, -5.1398723e+02, -3.9767506e+02, - -2.7618028e+02, -1.4941349e+02, -1.8433316e+01, 1.1606930e+02, - 2.4697130e+02, 3.7323736e+02, 4.9468012e+02, 6.0791740e+02, - 7.1199453e+02, 8.0485505e+02, 8.8578958e+02, 9.5117733e+02, - 9.9264372e+02, 1.0115211e+03, 9.9864359e+02, 9.6401858e+02, - 9.1024930e+02, 8.4835436e+02, 7.7530833e+02, 7.0141455e+02, - 6.2384959e+02, 5.4721968e+02, 4.7387003e+02, 3.9972348e+02, - 3.2726546e+02, 2.6394537e+02, 2.0233246e+02, 1.4286080e+02, - 9.1074446e+01, 4.1308373e+01, -8.2303699e+00, -5.6391830e+01, - -1.0380366e+02, -1.4867461e+02, -1.9589518e+02, -2.3948198e+02, - -2.8179404e+02, -3.2661184e+02, -3.6849411e+02, -4.1204691e+02, - -4.6073272e+02, -5.1299590e+02, -5.7214182e+02, -6.3765069e+02, - -7.0266168e+02, -7.6246325e+02, -8.1462585e+02, -8.5309773e+02, - -8.7583931e+02, -8.7977551e+02, -8.6820607e+02, -8.3598008e+02, - -7.9127858e+02, -7.2555633e+02, -6.4513927e+02, -5.4928065e+02, - -4.4082024e+02, -3.2665281e+02, -2.0436663e+02, -8.1707251e+01, - 4.7901921e+01, 1.7432524e+02, 2.9759562e+02, 4.1992512e+02, - 5.3317251e+02, 6.4237470e+02, 7.4113789e+02, 8.2606130e+02, - 8.9883116e+02, 9.5428904e+02, 9.8624536e+02, 9.9869004e+02, - 9.8266888e+02, 9.4925619e+02, 8.9813116e+02, 8.3623319e+02, - 7.6348823e+02, 6.8594085e+02, 6.0808870e+02, 5.2646492e+02, - 4.4600650e+02, 3.6561691e+02, 2.8872526e+02, 2.1691496e+02, - 1.4728773e+02, 8.4221474e+01, 2.6048470e+01, -3.4388207e+01, - -8.8802146e+01, -1.4299353e+02, -1.9336320e+02, -2.3710707e+02, - -2.8587475e+02, -3.3270152e+02, -3.7422945e+02, -4.1636455e+02, - -4.5573665e+02, -4.9726692e+02, -5.3543762e+02, -5.8065815e+02, - -6.2910888e+02, -6.7690028e+02, -7.2375327e+02, -7.6132305e+02, - -7.9286869e+02, -8.0958989e+02, -8.1191872e+02, -7.9586469e+02, - -7.7057333e+02, -7.2915594e+02, -6.7231474e+02, -6.0134288e+02, - -5.1986758e+02, -4.2496645e+02, -3.1966315e+02, -2.0893647e+02, - -9.4117050e+01, 2.1901801e+01, 1.4286090e+02, 2.5974483e+02, - 3.7391931e+02, 4.8475194e+02, 5.8679531e+02, 6.8253551e+02, - 7.6686124e+02, 8.3927651e+02, 9.0416036e+02, 9.4669654e+02, - 9.6938119e+02, 9.6791538e+02, 9.4724817e+02, 9.0746962e+02, - 8.5438295e+02, 7.8710681e+02, 7.1621104e+02, 6.3739148e+02 ], - -]) - -LTPF_C5_TRANS = np.array([ - - 5.5469254e+02, 4.6885623e+02, 3.8726237e+02, 3.0166318e+02, - 2.2151059e+02, 1.4759060e+02, 7.6115964e+01, 1.2068315e+01, - -5.0213437e+01, -1.1124791e+02, -1.6496412e+02, -2.1495097e+02, - -2.6214927e+02, -3.0944212e+02, -3.5014054e+02, -3.8896389e+02, - -4.2617800e+02, -4.6406673e+02, -4.9691186e+02, -5.3314161e+02, - -5.6776429e+02, -6.0515795e+02, -6.4220526e+02, -6.7634237e+02, - -7.0656015e+02, -7.2541177e+02, -7.3535446e+02, -7.3265481e+02, - -7.1676788e+02, -6.8818630e+02, -6.4788454e+02, -5.9638237e+02, - -5.3135114e+02, -4.5622803e+02, -3.7085252e+02, -2.7464233e+02, - -1.7527279e+02, -6.8212512e+01, 3.6401489e+01, 1.4772605e+02, - 2.5777143e+02, 3.5986766e+02, 4.6046220e+02, 5.5572298e+02, - 6.4084254e+02, 7.2023220e+02, 7.9091946e+02, 8.4596132e+02, - 8.8561830e+02, 9.0316671e+02, 9.0353933e+02, 8.8830570e+02, - 8.5210347e+02, 8.0683786e+02, 7.4767132e+02, 6.8402115e+02, - 6.1000133e+02, 5.3637714e+02, 4.5522905e+02, 3.7796360e+02, - 2.9165202e+02, 2.1765490e+02, 1.3937214e+02, 6.9124279e+01, - 5.1484918e+00, -5.7974304e+01, -1.1532103e+02, -1.7106128e+02, - -2.2144596e+02, -2.6763632e+02, -3.1235860e+02, -3.5424602e+02, - -3.9420762e+02, -4.2862777e+02, -4.6393345e+02, -5.0059201e+02, - -5.3052040e+02, -5.6462343e+02, -5.9733595e+02, -6.2614003e+02, - -6.5395598e+02, -6.7654796e+02, -6.8956058e+02, -6.9036404e+02, - -6.8409998e+02, -6.6772245e+02, -6.4131629e+02, -6.0423695e+02, - -5.5819928e+02, -5.0085813e+02, -4.3386043e+02, -3.5697723e+02, - -2.7353263e+02, -1.7946159e+02, -8.3894727e+01, 1.3870299e+01, - 1.1661147e+02, 2.1714406e+02, 3.1916911e+02, 4.1466126e+02, - 5.0807281e+02, 5.9699545e+02, 6.7493085e+02, 7.4602304e+02, - 8.0681874e+02, 8.5162090e+02, 8.7732032e+02, 8.8801241e+02, - 8.7733827e+02, 8.5711309e+02, 8.1939693e+02, 7.7020353e+02, - 7.1415915e+02, 6.4639833e+02, 5.7422282e+02, 4.9782204e+02, - 4.1400066e+02, 3.3290948e+02, 2.5272667e+02, 1.7094246e+02, - 9.4679864e+01, 1.9214845e+01, -4.7039158e+01, -1.1560544e+02, - -1.7609914e+02, -2.3440216e+02, -2.8752910e+02, -3.3711616e+02, - -3.8273508e+02, -4.2591674e+02, -4.6397521e+02, -5.0230060e+02, - -5.3283216e+02, -5.6227577e+02, -5.9128189e+02, -6.1269433e+02, - -6.3821208e+02, -6.5457809e+02, -6.7024858e+02, -6.7829939e+02, - -6.7675317e+02, -6.6455106e+02, -6.4328023e+02, -6.1728360e+02, - -5.7844437e+02, -5.3391997e+02, -4.7785175e+02, -4.1395668e+02, - -3.3933775e+02, -2.5814915e+02, -1.7234111e+02, -7.9862248e+01, - 1.5711615e+01, 1.1047993e+02, 2.0926197e+02, 3.0481978e+02, - 4.0036676e+02, 4.9118016e+02, 5.7429258e+02, 6.5078515e+02, - -]) - -### C.4.1.10 Output signal clipping - -X_HAT_CLIP_10M = np.array([ - - [ 6.1525095e-01, 1.7117620e+00, -1.6200436e-01, -2.1107548e+00, - 9.1636911e-01, 8.7583398e+00, 1.4291828e+01, 1.4615904e+01, - 1.9312730e+01, 2.2178311e+01, 2.1178760e+01, 1.9939021e+01, - 3.2745193e+01, 3.1385007e+01, 4.5642888e+01, 3.8185668e+01, - 4.3452271e+01, 3.0174130e+01, 2.7510416e+01, 3.9048290e+00, - -4.1911157e+00, -3.4032526e+01, -4.3089457e+01, -7.1817465e+01, - -7.3319439e+01, -1.0231340e+02, -8.2645833e+01, -1.0207070e+02, - -7.4253115e+01, -9.5269932e+01, -1.2210097e+02, -1.3216707e+02, - -1.2665681e+02, -1.6033791e+02, -1.3067613e+02, -1.8796611e+01, - 6.2097263e+01, 7.2290617e+00, -1.2550979e+02, -8.9649115e+01, - 7.6135408e+02, 2.7072170e+03, 6.1558256e+03, 9.6522574e+03, - 1.2566221e+04, 1.5421574e+04, 1.8329565e+04, 2.1102710e+04, - 2.3323039e+04, 2.5451924e+04, 2.7365468e+04, 2.8891223e+04, - 3.0341813e+04, 3.1380038e+04, 3.2134454e+04, 3.2606958e+04, - 3.2683895e+04, 3.2518324e+04, 3.2036626e+04, 3.1278795e+04, - 3.0136453e+04, 2.8694957e+04, 2.7009676e+04, 2.5075921e+04, - 2.2940269e+04, 2.0564299e+04, 1.7956441e+04, 1.5202722e+04, - 1.2352834e+04, 9.3639445e+03, 6.2714619e+03, 3.1112267e+03, - -1.0075267e+02, -3.3115389e+03, -6.4954073e+03, -9.6110111e+03, - -1.2594144e+04, -1.5477538e+04, -1.8214406e+04, -2.0797170e+04, - -2.3195615e+04, -2.5355124e+04, -2.7302557e+04, -2.8919494e+04, - -3.0273227e+04, -3.1357707e+04, -3.2152224e+04, -3.2625545e+04, - -3.2768000e+04, -3.2640407e+04, -3.2172861e+04, -3.1393517e+04, - -3.0316009e+04, -2.8922986e+04, -2.7290775e+04, -2.5351571e+04, - -2.3183937e+04, -2.0795771e+04, -1.8212609e+04, -1.5453610e+04, - -1.2543978e+04, -9.4923186e+03, -6.3663932e+03, -3.1740539e+03, - 4.2407582e+01, 3.2479359e+03, 6.4369448e+03, 9.5564107e+03, - 1.2589389e+04, 1.5494437e+04, 1.8238168e+04, 2.0814647e+04, - 2.3183440e+04, 2.5340307e+04, 2.7236643e+04, 2.8879098e+04, - 3.0219987e+04, 3.1304367e+04, 3.2073455e+04, 3.2541098e+04, - 3.2660415e+04, 3.2490788e+04, 3.2004309e+04, 3.1215306e+04, - 3.0131477e+04, 2.8751611e+04, 2.7114762e+04, 2.5198099e+04, - 2.3044166e+04, 2.0655799e+04, 1.8068458e+04, 1.5312555e+04, - 1.2400688e+04, 9.3834439e+03, 6.2670869e+03, 3.1043555e+03, - -9.0364008e+01, -3.2949280e+03, -6.4558716e+03, -9.5736656e+03, - -1.2593429e+04, -1.5487321e+04, -1.8231003e+04, -2.0808229e+04, - -2.3191386e+04, -2.5327915e+04, -2.7226934e+04, -2.8860268e+04, - -3.0235350e+04, -3.1313467e+04, -3.2092397e+04, -3.2585580e+04, - -3.2768000e+04, -3.2606534e+04, -3.2146234e+04, -3.1383325e+04, - -3.0295384e+04, -2.8926934e+04, -2.7297985e+04, -2.5343669e+04 ], - - [ -2.3210612e+04, -2.0830109e+04, -1.8262528e+04, -1.5491202e+04, - -1.2640992e+04, -9.6308521e+03, -6.5120997e+03, -3.2981272e+03, - -1.0437273e+02, 3.1237705e+03, 6.3475523e+03, 9.4251090e+03, - 1.2406927e+04, 1.5369182e+04, 1.8133410e+04, 2.0696011e+04, - 2.3075625e+04, 2.5239168e+04, 2.7178122e+04, 2.8863775e+04, - 3.0239107e+04, 3.1292540e+04, 3.2055374e+04, 3.2528526e+04, - 3.2691792e+04, 3.2554032e+04, 3.2080858e+04, 3.1269701e+04, - 3.0219849e+04, 2.8872409e+04, 2.7201446e+04, 2.5283194e+04, - 2.3137397e+04, 2.0746427e+04, 1.8171258e+04, 1.5425482e+04, - 1.2542866e+04, 9.5154094e+03, 6.4038902e+03, 3.2243297e+03, - 1.8093877e+01, -3.2004786e+03, -6.3778766e+03, -9.4986572e+03, - -1.2530644e+04, -1.5438896e+04, -1.8199553e+04, -2.0786963e+04, - -2.3172801e+04, -2.5336869e+04, -2.7256938e+04, -2.8914212e+04, - -3.0292811e+04, -3.1379968e+04, -3.2163160e+04, -3.2636663e+04, - -3.2768000e+04, -3.2642190e+04, -3.2169708e+04, -3.1389768e+04, - -3.0307591e+04, -2.8933213e+04, -2.7277887e+04, -2.5361709e+04, - -2.3197556e+04, -2.0809583e+04, -1.8223444e+04, -1.5459240e+04, - -1.2547850e+04, -9.5147469e+03, -6.3913071e+03, -3.2061552e+03, - 1.1474435e+01, 3.2280361e+03, 6.4146913e+03, 9.5376172e+03, - 1.2570372e+04, 1.5481142e+04, 1.8242641e+04, 2.0827867e+04, - 2.3213026e+04, 2.5375280e+04, 2.7293037e+04, 2.8947339e+04, - 3.0323330e+04, 3.1406817e+04, 3.2187891e+04, 3.2660531e+04, - 3.2767000e+04, 3.2659083e+04, 3.2187190e+04, 3.1402569e+04, - 3.0317849e+04, 2.8939620e+04, 2.7281206e+04, 2.5360297e+04, - 2.3194809e+04, 2.0805310e+04, 1.8215867e+04, 1.5450539e+04, - 1.2535402e+04, 9.5045150e+03, 6.3825434e+03, 3.1961404e+03, - -1.9030604e+01, -3.2350097e+03, -6.4178539e+03, -9.5376996e+03, - -1.2564818e+04, -1.5468879e+04, -1.8222757e+04, -2.0799617e+04, - -2.3177492e+04, -2.5329860e+04, -2.7239548e+04, -2.8887388e+04, - -3.0257022e+04, -3.1336972e+04, -3.2115659e+04, -3.2585521e+04, - -3.2741691e+04, -3.2583544e+04, -3.2112334e+04, -3.1332786e+04, - -3.0253039e+04, -2.8881031e+04, -2.7231757e+04, -2.5321143e+04, - -2.3168095e+04, -2.0790131e+04, -1.8212051e+04, -1.5458479e+04, - -1.2554090e+04, -9.5278709e+03, -6.4088050e+03, -3.2282766e+03, - -1.5127187e+01, 3.1974595e+03, 6.3806758e+03, 9.5013370e+03, - 1.2533377e+04, 1.5443257e+04, 1.8203988e+04, 2.0793445e+04, - 2.3180292e+04, 2.5344634e+04, 2.7265053e+04, 2.8919963e+04, - 3.0294320e+04, 3.1376795e+04, 3.2154178e+04, 3.2622959e+04, - 3.2767000e+04, 3.2617286e+04, 3.2145842e+04, 3.1360660e+04, - 3.0278348e+04, 2.8901877e+04, 2.7241369e+04, 2.5301056e+04 ], - -]) - -X_HAT_CLIP_7M5 = np.array([ - - [ 9.0382948e-01, 2.8563300e+00, 2.0863167e+00, 3.2605273e+00, - 1.8231017e+00, -2.6473031e+00, -7.7420704e+00, -1.6971743e+01, - -4.4169569e+00, 4.7473387e+00, 7.9882732e+00, 2.1090757e+00, - 6.9477046e+00, 7.6294361e+00, 4.5069158e+00, 1.1288109e+00, - 5.5301798e-01, -1.2320805e+00, 1.2696965e+01, 1.7998129e+01, - 1.9997378e+01, 2.3310802e+01, 3.4116671e+01, 3.1619222e+01, - 2.3643252e+01, 2.2595989e+01, 2.4150879e+01, 1.7561939e+01, - 2.4167995e+01, 2.1868269e+01, 1.2021561e+01, 1.0810360e+01, - -1.1321816e+01, -1.3811836e+01, -2.7571991e+01, -3.3459505e+01, - -2.6720233e+01, -4.0425004e+01, -4.1666697e+01, -4.8106995e+01, - -7.1121739e+01, -8.5018856e+01, -6.4519501e+01, -6.1651047e+01, - -6.2001672e+01, -4.9054098e+01, 5.3605147e+00, -2.7222279e+00, - -6.3200946e+00, -2.8873822e+01, -5.6314175e+01, -5.9551902e+01, - -2.1183627e+01, -9.5007617e+01, -6.7674879e+01, 7.6546124e+01, - 3.6355638e+02, 2.0908440e+02, 9.2290767e+01, -8.4453487e+01, - -2.0810832e+02, -1.9235273e+02, -4.0634578e+02, -2.2011977e+02, - 6.2920459e+02, 3.1481663e+03, 6.2343351e+03, 9.4022080e+03, - 1.2520451e+04, 1.5313131e+04, 1.8128985e+04, 2.0762454e+04, - 2.3084787e+04, 2.5275848e+04, 2.7095495e+04, 2.8665301e+04, - 3.0094623e+04, 3.1202047e+04, 3.2006678e+04, 3.2461623e+04, - 3.2568832e+04, 3.2408327e+04, 3.1961953e+04, 3.1146555e+04, - 3.0073949e+04, 2.8725124e+04, 2.7099832e+04, 2.5196695e+04, - 2.3022972e+04, 2.0643354e+04, 1.8079103e+04, 1.5352852e+04, - 1.2476728e+04, 9.4135962e+03, 6.2948219e+03, 3.1010477e+03, - -9.0897787e+01, -3.3383673e+03, -6.5093586e+03, -9.6214110e+03, - -1.2638625e+04, -1.5564780e+04, -1.8289238e+04, -2.0877731e+04, - -2.3274493e+04, -2.5456613e+04, -2.7372293e+04, -2.9018289e+04, - -3.0399516e+04, -3.1474248e+04, -3.2213279e+04, -3.2686770e+04, - -3.2768000e+04, -3.2655386e+04, -3.2161995e+04, -3.1363572e+04, - -3.0296725e+04, -2.8893704e+04, -2.7226660e+04, -2.5303018e+04 ], - - [ -2.3111848e+04, -2.0718046e+04, -1.8145256e+04, -1.5386042e+04, - -1.2451683e+04, -9.4561229e+03, -6.3407390e+03, -3.2078423e+03, - -1.4231827e+01, 3.1871864e+03, 6.4028626e+03, 9.5288605e+03, - 1.2522323e+04, 1.5403074e+04, 1.8148763e+04, 2.0738239e+04, - 2.3124038e+04, 2.5248199e+04, 2.7157343e+04, 2.8821520e+04, - 3.0197933e+04, 3.1280524e+04, 3.2068994e+04, 3.2535286e+04, - 3.2674198e+04, 3.2505688e+04, 3.2021479e+04, 3.1217393e+04, - 3.0139480e+04, 2.8742712e+04, 2.7081219e+04, 2.5164753e+04, - 2.3005958e+04, 2.0625737e+04, 1.8051360e+04, 1.5314656e+04, - 1.2403135e+04, 9.3958576e+03, 6.2866076e+03, 3.1150574e+03, - -8.3043055e+01, -3.2906309e+03, -6.4783209e+03, -9.5968770e+03, - -1.2627329e+04, -1.5543027e+04, -1.8297188e+04, -2.0856742e+04, - -2.3242831e+04, -2.5406524e+04, -2.7315500e+04, -2.8954115e+04, - -3.0311322e+04, -3.1397263e+04, -3.2199564e+04, -3.2663393e+04, - -3.2768000e+04, -3.2631820e+04, -3.2158938e+04, -3.1361864e+04, - -3.0286591e+04, -2.8909485e+04, -2.7252911e+04, -2.5338382e+04, - -2.3179744e+04, -2.0801866e+04, -1.8222214e+04, -1.5467629e+04, - -1.2551908e+04, -9.5234786e+03, -6.4050183e+03, -3.2234113e+03, - -1.0202956e+01, 3.2050827e+03, 6.3811438e+03, 9.5000550e+03, - 1.2526624e+04, 1.5433267e+04, 1.8190970e+04, 2.0775689e+04, - 2.3157406e+04, 2.5317424e+04, 2.7226647e+04, 2.8880016e+04, - 3.0250964e+04, 3.1333324e+04, 3.2108157e+04, 3.2579815e+04, - 3.2739171e+04, 3.2585501e+04, 3.2115570e+04, 3.1342610e+04, - 3.0239307e+04, 2.8881574e+04, 2.7232557e+04, 2.5325302e+04, - 2.3165560e+04, 2.0776212e+04, 1.8202819e+04, 1.5452512e+04, - 1.2552870e+04, 9.5323059e+03, 6.4141989e+03, 3.2353808e+03, - 3.2008805e+01, -3.1778835e+03, -6.3568255e+03, -9.4682388e+03, - -1.2490842e+04, -1.5403926e+04, -1.8154186e+04, -2.0745346e+04, - -2.3121161e+04, -2.5285375e+04, -2.7200767e+04, -2.8855100e+04, - -3.0236188e+04, -3.1303814e+04, -3.2106304e+04, -3.2610143e+04 ], - -]) - -X_HAT_CLIP = [ X_HAT_CLIP_7M5, X_HAT_CLIP_10M ] diff --git a/system/embdrv/lc3/test/arm/ltpf_arm.c b/system/embdrv/lc3/test/arm/ltpf_arm.c deleted file mode 100644 index e7b8bfc8f7e554b570e29c1c70a9be73974c50e2..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/arm/ltpf_arm.c +++ /dev/null @@ -1,114 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 -#include -#include - -#include "simd32.h" - -/* -------------------------------------------------------------------------- */ - -#define TEST_ARM -#include - -void lc3_put_bits_generic(lc3_bits_t *a, unsigned b, int c) -{ (void)a, (void)b, (void)c; } - -unsigned lc3_get_bits_generic(struct lc3_bits *a, int b) -{ return (void)a, (void)b, 0; } - -/* -------------------------------------------------------------------------- */ - -static int check_resampler() -{ - int16_t __x[60+480], *x = __x + 60; - for (int i = -60; i < 480; i++) - x[i] = rand() & 0xffff; - - struct lc3_ltpf_hp50_state hp50 = { 0 }, hp50_arm = { 0 }; - int16_t y[128], y_arm[128]; - - resample_8k_12k8(&hp50, x, y, 128); - arm_resample_8k_12k8(&hp50_arm, x, y_arm, 128); - if (memcmp(y, y_arm, 128 * sizeof(*y)) != 0) - return -1; - - resample_16k_12k8(&hp50, x, y, 128); - arm_resample_16k_12k8(&hp50_arm, x, y_arm, 128); - if (memcmp(y, y_arm, 128 * sizeof(*y)) != 0) - return -1; - - resample_24k_12k8(&hp50, x, y, 128); - arm_resample_24k_12k8(&hp50_arm, x, y_arm, 128); - if (memcmp(y, y_arm, 128 * sizeof(*y)) != 0) - return -1; - - resample_32k_12k8(&hp50, x, y, 128); - arm_resample_32k_12k8(&hp50_arm, x, y_arm, 128); - if (memcmp(y, y_arm, 128 * sizeof(*y)) != 0) - return -1; - - resample_48k_12k8(&hp50, x, y, 128); - arm_resample_48k_12k8(&hp50_arm, x, y_arm, 128); - if (memcmp(y, y_arm, 128 * sizeof(*y)) != 0) - return -1; - - return 0; -} - -static int check_correlate() -{ - int16_t alignas(4) a[500], b[500]; - float y[100], y_arm[100]; - - for (int i = 0; i < 500; i++) { - a[i] = rand() & 0xffff; - b[i] = rand() & 0xffff; - } - - correlate(a, b+200, 128, y, 100); - arm_correlate(a, b+200, 128, y_arm, 100); - if (memcmp(y, y_arm, 100 * sizeof(*y)) != 0) - return -1; - - correlate(a, b+199, 128, y, 99); - arm_correlate(a, b+199, 128, y_arm, 99); - if (memcmp(y, y_arm, 99 * sizeof(*y)) != 0) - return -1; - - correlate(a, b+199, 128, y, 100); - arm_correlate(a, b+199, 128, y_arm, 100); - if (memcmp(y, y_arm, 100 * sizeof(*y)) != 0) - return -1; - - return 0; -} - -int check_ltpf(void) -{ - int ret; - - if ((ret = check_resampler()) < 0) - return ret; - - if ((ret = check_correlate()) < 0) - return ret; - - return 0; -} diff --git a/system/embdrv/lc3/test/arm/simd32.h b/system/embdrv/lc3/test/arm/simd32.h deleted file mode 100644 index fd17f71e443632d42ed38dca14c27d89ce432d2f..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/arm/simd32.h +++ /dev/null @@ -1,64 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -#if __ARM_FEATURE_SIMD32 - -#include - -#else -#define __ARM_FEATURE_SIMD32 1 - -#include - -typedef int32_t int16x2_t; - -__attribute__((unused)) -static int16x2_t __pkhbt(int16x2_t a, int16x2_t b) -{ - uint32_t a_bot = (uint32_t)a & 0x0000ffffu; - uint32_t b_top = (uint32_t)b & 0xffff0000u; - - return (int16x2_t)(a_bot | b_top); -} - -__attribute__((unused)) -static int32_t __smlad(int16x2_t a, int16x2_t b, int32_t u) -{ - int16_t a_hi = a >> 16, a_lo = a & 0xffff; - int16_t b_hi = b >> 16, b_lo = b & 0xffff; - - return u + (a_hi * b_hi) + (a_lo * b_lo); -} - -__attribute__((unused)) -static int64_t __smlald(int16x2_t a, int16x2_t b, int64_t u) -{ - int16_t a_hi = a >> 16, a_lo = a & 0xffff; - int16_t b_hi = b >> 16, b_lo = b & 0xffff; - return u + (a_hi * b_hi) + (a_lo * b_lo); -} - -__attribute__((unused)) -static int64_t __smlaldx(int16x2_t a, int16x2_t b, int64_t u) -{ - int16_t a_hi = a >> 16, a_lo = a & 0xffff; - int16_t b_hi = b >> 16, b_lo = b & 0xffff; - return u + (a_hi * b_lo) + (a_lo * b_hi); -} - -#endif /* __ARM_FEATURE_SIMD32 */ diff --git a/system/embdrv/lc3/test/arm/test_arm.c b/system/embdrv/lc3/test/arm/test_arm.c deleted file mode 100644 index 1e5c15bea4483c71fa04ef0af0dab19836fc6f6e..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/arm/test_arm.c +++ /dev/null @@ -1,32 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 - -int check_ltpf(void); - -int main() -{ - int r, ret = 0; - - printf("Checking LTPF ARM... "); fflush(stdout); - printf("%s\n", (r = check_ltpf()) == 0 ? "OK" : "Failed"); - ret = ret || r; - - return ret; -} diff --git a/system/embdrv/lc3/test/attdet.py b/system/embdrv/lc3/test/attdet.py deleted file mode 100644 index c318e329f308eaf03f34d8db52f25c74b786995d..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/attdet.py +++ /dev/null @@ -1,185 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np - -import build.lc3 as lc3 -import tables as T, appendix_c as C - - -### ------------------------------------------------------------------------ ### - -class AttackDetector: - - def __init__(self, dt, sr): - - self.dt = dt - self.sr = sr - self.ms = T.DT_MS[dt] - - self.xn1 = 0 - self.xn2 = 0 - self.en1 = 0 - self.an1 = 0 - self.p_att = 0 - - def is_enabled(self, nbytes): - - c1 = self.dt == T.DT_10M and \ - self.sr == T.SRATE_32K and nbytes > 80 - - c2 = self.dt == T.DT_10M and \ - self.sr >= T.SRATE_48K and nbytes >= 100 - - c3 = self.dt == T.DT_7M5 and \ - self.sr == T.SRATE_32K and nbytes >= 61 and nbytes < 150 - - c4 = self.dt == T.DT_7M5 and \ - self.sr >= T.SRATE_48K and nbytes >= 75 and nbytes < 150 - - return c1 or c2 or c3 or c4 - - def run(self, nbytes, x): - - ### 3.3.6.2 Downsampling and filtering input - - mf = int(16 * self.ms) - - r = len(x) // mf - x_att = np.array([ np.sum(x[i*r:(i+1)*r]) for i in range(mf) ]) - - x_hp = np.empty(mf) - x_hp[0 ] = 0.375 * x_att[0 ] - 0.5 * self.xn1 + 0.125 * self.xn2 - x_hp[1 ] = 0.375 * x_att[1 ] - 0.5 * x_att[0 ] + 0.125 * self.xn1 - x_hp[2:] = 0.375 * x_att[2:] - 0.5 * x_att[1:-1] + 0.125 * x_att[0:-2] - self.xn2 = x_att[-2] - self.xn1 = x_att[-1] - - ### 3.3.6.3 Energy calculation - - nb = int(self.ms / 2.5) - - e_att = np.array([ np.sum(np.square(x_hp[40*i:40*(i+1)])) - for i in range(nb) ]) - - a_att = np.empty(nb) - a_att[0] = np.maximum(0.25 * self.an1, self.en1) - for i in range(1,nb): - a_att[i] = np.maximum(0.25 * a_att[i-1], e_att[i-1]) - self.en1 = e_att[-1] - self.an1 = a_att[-1] - - ### 3.3.6.4 Attack Detection - - p_att = -1 - flags = [ (e_att[i] > 8.5 * a_att[i]) for i in range(nb) ] - - for (i, f) in enumerate(flags): - if f: p_att = i - - f_att = p_att >= 0 or self.p_att - 1 >= nb // 2 - self.p_att = 1 + p_att - - return self.is_enabled(nbytes) and f_att - - -def initial_state(): - return { 'en1': 0.0, 'an1': 0.0, 'p_att': 0 } - -### ------------------------------------------------------------------------ ### - -def check_enabling(rng, dt): - - ok = True - - for sr in range(T.SRATE_16K, T.NUM_SRATE): - - attdet = AttackDetector(dt, sr) - - for nbytes in [ 61, 61-1, 75-1, 75, 80, 80+1, 100-1, 100, 150-1, 150 ]: - - f_att = lc3.attdet_run(dt, sr, nbytes, - initial_state(), 2 * rng.random(T.NS[dt][sr]+6) - 1) - - ok = ok and f_att == attdet.is_enabled(nbytes) - - return ok - -def check_unit(rng, dt, sr): - - ns = T.NS[dt][sr] - ok = True - - attdet = AttackDetector(dt, sr) - - state_c = initial_state() - x_c = np.zeros(ns+6) - - for run in range(100): - - ### Generate noise, and an attack at random point - - x = ((2 * rng.random(ns)) - 1) * (2 ** 8 - 1) - x[(ns * rng.random()).astype(int)] *= 2 ** 7 - - ### Check Implementation - - f_att = attdet.run(100, x) - - x_c = np.append(x_c[-6:], x) - f_att_c = lc3.attdet_run(dt, sr, 100, state_c, x_c) - - ok = ok and f_att_c == f_att - ok = ok and np.amax(np.abs(1 - state_c['en1']/attdet.en1)) < 2 - ok = ok and np.amax(np.abs(1 - state_c['an1']/attdet.an1)) < 2 - ok = ok and state_c['p_att'] == attdet.p_att - - return ok - -def check_appendix_c(dt): - - sr = T.SRATE_48K - - state = initial_state() - - x = np.append(np.zeros(6), C.X_PCM_ATT[dt][0]) - f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[dt], state, x) - ok = f_att == C.F_ATT[dt][0] - - x = np.append(x[-6:], C.X_PCM_ATT[dt][1]) - f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[dt], state, x) - ok = f_att == C.F_ATT[dt][1] - - return ok - -def check(): - - rng = np.random.default_rng(1234) - ok = True - - for dt in range(T.NUM_DT): - ok and check_enabling(rng, dt) - - for dt in range(T.NUM_DT): - for sr in range(T.SRATE_32K, T.NUM_SRATE): - ok = ok and check_unit(rng, dt, sr) - - for dt in range(T.NUM_DT): - ok = ok and check_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/attdet_py.c b/system/embdrv/lc3/test/attdet_py.c deleted file mode 100644 index d85a8a5ab54ff7308a8c94a2689c15820fc066f9..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/attdet_py.c +++ /dev/null @@ -1,62 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 -#include - -#include -#include "ctypes.h" - -static PyObject *attdet_run_py(PyObject *m, PyObject *args) -{ - unsigned dt, sr, nbytes; - PyObject *attdet_obj, *x_obj; - struct lc3_attdet_analysis attdet = { 0 }; - int16_t *x; - - if (!PyArg_ParseTuple(args, "IIIOO", - &dt, &sr, &nbytes, &attdet_obj, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - CTYPES_CHECK(NULL, attdet_obj = to_attdet_analysis(attdet_obj, &attdet)); - - int ns = LC3_NS(dt, sr); - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_INT16, ns+6, &x)); - - int att = lc3_attdet_run(dt, sr, nbytes, &attdet, x+6); - - from_attdet_analysis(attdet_obj, &attdet); - return Py_BuildValue("i", att); -} - -static PyMethodDef methods[] = { - { "attdet_run", attdet_run_py, METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_attdet_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/test/bitstream.py b/system/embdrv/lc3/test/bitstream.py deleted file mode 100644 index 11edbd56f617e24be86d36443c7023101e9dbe18..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/bitstream.py +++ /dev/null @@ -1,240 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import math - -class Bitstream: - - def __init__(self, data): - - self.bytes = data - - self.bp_bw = len(data) - 1 - self.mask_bw = 1 - - self.bp = 0 - self.low = 0 - self.range = 0xffffff - - def dump(self): - - b = self.bytes - - for i in range(0, len(b), 20): - print(''.join('{:02x} '.format(x) - for x in b[i:min(i+20, len(b))] )) - -class BitstreamReader(Bitstream): - - def __init__(self, data): - - super().__init__(data) - - self.low = ( (self.bytes[0] << 16) | - (self.bytes[1] << 8) | - (self.bytes[2] ) ) - self.bp = 3 - - def read_bit(self): - - bit = bool(self.bytes[self.bp_bw] & self.mask_bw) - - self.mask_bw <<= 1 - if self.mask_bw == 0x100: - self.mask_bw = 1 - self.bp_bw -= 1 - - return bit - - def read_uint(self, nbits): - - val = 0 - for k in range(nbits): - val |= self.read_bit() << k - - return val - - def ac_decode(self, cum_freqs, sym_freqs): - - r = self.range >> 10 - if self.low >= r << 10: - raise ValueError('Invalid ac bitstream') - - val = len(cum_freqs) - 1 - while self.low < r * cum_freqs[val]: - val -= 1 - - self.low -= r * cum_freqs[val] - self.range = r * sym_freqs[val] - while self.range < 0x10000: - self.range <<= 8 - - self.low <<= 8 - self.low &= 0xffffff - self.low += self.bytes[self.bp] - self.bp += 1 - - return val - - def get_bits_left(self): - - nbits = 8 * len(self.bytes) - - nbits_bw = nbits - \ - (8*self.bp_bw + 8 - int(math.log2(self.mask_bw))) - - nbits_ac = 8 * (self.bp - 3) + \ - (25 - int(math.floor(math.log2(self.range)))) - - return nbits - (nbits_bw + nbits_ac) - -class BitstreamWriter(Bitstream): - - def __init__(self, nbytes): - - super().__init__(bytearray(nbytes)) - - self.cache = -1 - self.carry = 0 - self.carry_count = 0 - - def write_bit(self, bit): - - mask = self.mask_bw - bp = self.bp_bw - - if bit == 0: - self.bytes[bp] &= ~mask - else: - self.bytes[bp] |= mask - - self.mask_bw <<= 1 - if self.mask_bw == 0x100: - self.mask_bw = 1 - self.bp_bw -= 1 - - def write_uint(self, val, nbits): - - for k in range(nbits): - self.write_bit(val & 1) - val >>= 1 - - def ac_shift(self): - - if self.low < 0xff0000 or self.carry == 1: - - if self.cache >= 0: - self.bytes[self.bp] = self.cache + self.carry - self.bp += 1 - - while self.carry_count > 0: - self.bytes[self.bp] = (self.carry + 0xff) & 0xff - self.bp += 1 - self.carry_count -= 1 - - self.cache = self.low >> 16 - self.carry = 0 - - else: - self.carry_count += 1 - - self.low <<= 8 - self.low &= 0xffffff - - def ac_encode(self, cum_freq, sym_freq): - - r = self.range >> 10 - self.low += r * cum_freq - if (self.low >> 24) != 0: - self.carry = 1 - - self.low &= 0xffffff - self.range = r * sym_freq - while self.range < 0x10000: - self.range <<= 8; - self.ac_shift() - - def get_bits_left(self): - - nbits = 8 * len(self.bytes) - - nbits_bw = nbits - \ - (8*self.bp_bw + 8 - int(math.log2(self.mask_bw))) - - nbits_ac = 8 * self.bp + (25 - int(math.floor(math.log2(self.range)))) - if self.cache >= 0: - nbits_ac += 8 - if self.carry_count > 0: - nbits_ac += 8 * self.carry_count - - return nbits - (nbits_bw + nbits_ac) - - def terminate(self): - - bits = 1 - while self.range >> (24 - bits) == 0: - bits += 1 - - mask = 0xffffff >> bits; - val = self.low + mask; - - over1 = val >> 24 - val &= 0x00ffffff - high = self.low + self.range - over2 = high >> 24 - high &= 0x00ffffff - val = val & ~mask - - if over1 == over2: - - if val + mask >= high: - bits += 1 - mask >>= 1 - val = ((self.low + mask) & 0x00ffffff) & ~mask - - if val < self.low: - self.carry = 1 - - self.low = val - while bits > 0: - self.ac_shift() - bits -= 8 - bits += 8; - - val = self.cache - - if self.carry_count > 0: - self.bytes[self.bp] = self.cache - self.bp += 1 - - while self.carry_count > 1: - self.bytes[self.bp] = 0xff - self.bp += 1 - self.carry_count -= 1 - - val = 0xff >> (8 - bits) - - mask = 0x80; - for k in range(bits): - - if val & mask == 0: - self.bytes[self.bp] &= ~mask - else: - self.bytes[self.bp] |= mask - - mask >>= 1 - - return self.bytes diff --git a/system/embdrv/lc3/test/bwdet.py b/system/embdrv/lc3/test/bwdet.py deleted file mode 100644 index 2f55c87189d35fa2c36380e420139ef03b0d733e..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/bwdet.py +++ /dev/null @@ -1,162 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np - -import build.lc3 as lc3 -import tables as T, appendix_c as C - - -BW_START = [ - [ [], [ 51 ], [ 45, 58 ], [ 42, 53, 60 ], [ 40, 51, 57, 61 ] ], - [ [], [ 53 ], [ 47, 59 ], [ 44, 54, 60 ], [ 41, 51, 57, 61 ] ] -] - -BW_STOP = [ - [ [], [ 63 ], [ 55, 63 ], [ 51, 58, 63 ], [ 48, 55, 60, 63 ] ], - [ [], [ 63 ], [ 56, 63 ], [ 52, 59, 63 ], [ 49, 55, 60, 63 ] ] -] - -TQ = [ 20, 10, 10, 10 ] - -TC = [ 15, 23, 20, 20 ] -L = [ [ 4, 4, 3, 2 ], [ 4, 4, 3, 1 ] ] - - -### ------------------------------------------------------------------------ ### - -class BandwidthDetector: - - def __init__(self, dt, sr): - - self.dt = dt - self.sr = sr - - def run(self, e): - - dt = self.dt - sr = self.sr - - ### Stage 1, determine bw0 candidate - - bw0 = 0 - - for bw in range(sr): - i0 = BW_START[dt][sr][bw] - i1 = BW_STOP[dt][sr][bw] - if np.mean(e[i0:i1+1]) >= TQ[bw]: - bw0 = bw + 1 - - ### Stage 2, Cut-off random coefficients at each steps - - bw = bw0 - - if bw0 < sr: - l = L[dt][bw0] - i0 = BW_START[dt][sr][bw0] - l - i1 = BW_START[dt][sr][bw0] - - c = 10 * np.log10(1e-31 + e[i0-l+1:i1-l+2] / e[i0+1:i1+2]) - if np.amax(c) <= TC[bw0]: - bw = sr - - self.bw = bw - return self.bw - - def get_nbits(self): - - return 0 if self.sr == 0 else \ - 1 + np.log2(self.sr).astype(int) - - def store_bw(self, b): - - b.write_uint(self.bw, self.get_nbits()) - - def get_bw(self, b): - - return b.read_uint(self.get_nbits()) - -### ------------------------------------------------------------------------ ### - -def check_unit(rng, dt, sr): - - ok = True - - bwdet = BandwidthDetector(dt, sr) - - for bw0 in range(sr+1): - for drop in range(10): - - ### Generate random 'high' energy and - ### scale relevant bands to select 'bw0' - - e = 20 + 100 * rng.random(64) - - for i in range(sr): - if i+1 != bw0: - i0 = BW_START[dt][sr][i] - i1 = BW_STOP[dt][sr][i] - e[i0:i1+1] /= (np.mean(e[i0:i1+1]) / TQ[i] + 1e-3) - - ### Stage 2 Condition, - ### cut-off random coefficients at each steps - - if bw0 < sr: - l = L[dt][bw0] - i0 = BW_START[dt][sr][bw0] - l - i1 = BW_START[dt][sr][bw0] - - e[i0-l+1:i1+2] /= np.power(10, np.arange(2*l+1) / (1 + drop)) - - ### Check with implementation - - bw_c = lc3.bwdet_run(dt, sr, e) - - ok = ok and bw_c == bwdet.run(e) - - return ok - -def check_appendix_c(dt): - - sr = T.SRATE_16K - ok = True - - E_B = C.E_B[dt] - P_BW = C.P_BW[dt] - - bw = lc3.bwdet_run(dt, sr, E_B[0]) - ok = ok and bw == P_BW[0] - - bw = lc3.bwdet_run(dt, sr, E_B[1]) - ok = ok and bw == P_BW[1] - - return ok - -def check(): - - rng = np.random.default_rng(1234) - - ok = True - for dt in range(T.NUM_DT): - for sr in range(T.NUM_SRATE): - ok = ok and check_unit(rng, dt, sr) - - for dt in range(T.NUM_DT): - ok = ok and check_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/bwdet_py.c b/system/embdrv/lc3/test/bwdet_py.c deleted file mode 100644 index c2decb304811e420501e22c3c31ab22795b111c0..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/bwdet_py.c +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 -#include - -#include -#include "ctypes.h" - -static PyObject *bwdet_run_py(PyObject *m, PyObject *args) -{ - unsigned dt, sr; - PyObject *e_obj; - float *e; - - if (!PyArg_ParseTuple(args, "IIO", &dt, &sr, &e_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - CTYPES_CHECK("e", to_1d_ptr(e_obj, NPY_FLOAT, LC3_NUM_BANDS, &e)); - - int bw = lc3_bwdet_run(dt, sr, e); - - return Py_BuildValue("i", bw); -} - -static PyMethodDef methods[] = { - { "bwdet_run", bwdet_run_py, METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_bwdet_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/test/ctypes.h b/system/embdrv/lc3/test/ctypes.h deleted file mode 100644 index 97a3add9bc0982c8d1d03880de2a691d9191da27..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/ctypes.h +++ /dev/null @@ -1,886 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#ifndef __CTYPES_H -#define __CTYPES_H - -#include -#include - -#include - - -#define CTYPES_CHECK(exc, t) \ - do { \ - if (!(t)) return (exc) ? PyErr_Format(PyExc_TypeError, exc) : NULL; \ - } while(0) - - -/** - * From C types to Numpy Array types - */ - -#define to_scalar(obj, t, ptr) \ - __to_scalar(obj, t, (void *)(ptr)) - -#define to_1d_ptr(obj, t, n, ptr) \ - __to_1d_ptr(obj, t, n, (void **)(ptr)) - -#define to_2d_ptr(obj, t, n1, n2, ptr) \ - __to_2d_ptr(obj, t, n1, n2, (void **)(ptr)) - -#define to_1d_copy(obj, t, ptr, n) \ - __to_1d_copy(obj, t, ptr, n) - -#define to_2d_copy(obj, t, ptr, n1, n2) \ - __to_2d_copy(obj, t, ptr, n1, n2) - - -/** - * From Numpy Array types to C types - */ - -#define new_scalar(obj, ptr) \ - __new_scalar(obj, ptr) - -#define new_1d_ptr(t, n, ptr) \ - __new_1d_ptr(t, n, (void **)(ptr)) - -#define new_2d_ptr(t, n1, n2, ptr) \ - __new_2d_ptr(t, n1, n2, (void **)(ptr)) - -#define new_1d_copy(t, n, src) \ - __new_1d_copy(t, n, src) - -#define new_2d_copy(t, n1, n2, src) \ - __new_2d_copy(t, n1, n2, src) - - -/* -------------------------------------------------------------------------- */ - -__attribute__((unused)) -static PyObject *__to_scalar(PyObject *obj, int t, void *ptr) -{ - obj = obj ? PyArray_FROMANY(obj, t, 0, 0, NPY_ARRAY_FORCECAST) : obj; - if (!obj) - return NULL; - - memcpy(ptr, PyArray_DATA((PyArrayObject *)obj), - PyArray_NBYTES((PyArrayObject *)obj)); - - return obj; -} - -__attribute__((unused)) -static PyObject *__to_1d_ptr(PyObject *obj, int t, int n, void **ptr) -{ - obj = obj ? PyArray_FROMANY(obj, - t, 1, 1, NPY_ARRAY_FORCECAST|NPY_ARRAY_CARRAY) : obj; - if (!obj || (n && PyArray_SIZE((PyArrayObject *)obj) != n)) - return NULL; - - *ptr = PyArray_DATA((PyArrayObject *)obj); - return obj; -} - -__attribute__((unused)) -static PyObject *__to_2d_ptr(PyObject *obj, int t, int n1, int n2, void **ptr) -{ - obj = obj ? PyArray_FROMANY(obj, - t, 2, 2, NPY_ARRAY_FORCECAST|NPY_ARRAY_CARRAY) : obj; - if (!obj || (n1 && PyArray_DIMS((PyArrayObject *)obj)[0] != n1) - || (n2 && PyArray_DIMS((PyArrayObject *)obj)[1] != n2)) - return NULL; - - *ptr = PyArray_DATA((PyArrayObject *)obj); - return obj; -} - -__attribute__((unused)) -static PyObject *__to_1d_copy(PyObject *obj, int t, void *v, int n) -{ - void *src; - - if ((obj = to_1d_ptr(obj, t, n, &src))) - memcpy(v, src, PyArray_NBYTES((PyArrayObject *)obj)); - - return obj; -} - -__attribute__((unused)) -static PyObject *__to_2d_copy(PyObject *obj, int t, void *v, int n1, int n2) -{ - void *src; - - if ((obj = to_2d_ptr(obj, t, n1, n2, &src))) - memcpy(v, src, PyArray_NBYTES((PyArrayObject *)obj)); - - return obj; -} - -/* -------------------------------------------------------------------------- */ - -__attribute__((unused)) -static PyObject *__new_scalar(int t, const void *ptr) -{ - PyObject *obj = PyArray_SimpleNew(0, NULL, t); - - memcpy(PyArray_DATA((PyArrayObject *)obj), ptr, - PyArray_NBYTES((PyArrayObject *)obj)); - - return obj; -} - -__attribute__((unused)) -static PyObject *__new_1d_ptr(int t, int n, void **ptr) -{ - PyObject *obj = PyArray_SimpleNew(1, (const npy_intp []){ n }, t); - - *ptr = PyArray_DATA((PyArrayObject *)obj); - return obj; -} - -__attribute__((unused)) -static PyObject *__new_2d_ptr(int t, int n1, int n2, void **ptr) -{ - PyObject *obj; - - obj = PyArray_SimpleNew(2, ((const npy_intp []){ n1, n2 }), t); - - *ptr = PyArray_DATA((PyArrayObject *)obj); - return obj; -} - -__attribute__((unused)) -static PyObject *__new_1d_copy(int t, int n, const void *src) -{ - PyObject *obj; - void *dst; - - if ((obj = new_1d_ptr(t, n, &dst))) - memcpy(dst, src, PyArray_NBYTES((PyArrayObject *)obj)); - - return obj; -} - -__attribute__((unused)) -static PyObject *__new_2d_copy(int t, int n1, int n2, const void *src) -{ - PyObject *obj; - void *dst; - - if ((obj = new_2d_ptr(t, n1, n2, &dst))) - memcpy(dst, src, PyArray_NBYTES((PyArrayObject *)obj)); - - return obj; -} - -/* -------------------------------------------------------------------------- */ - -#include - -__attribute__((unused)) -static PyObject *to_attdet_analysis( - PyObject *obj, struct lc3_attdet_analysis *attdet) -{ - CTYPES_CHECK("attdet", obj && PyDict_Check(obj)); - - CTYPES_CHECK("attdet.en1", to_scalar( - PyDict_GetItemString(obj, "en1"), NPY_INT32, &attdet->en1)); - - CTYPES_CHECK("attdet.an1", to_scalar( - PyDict_GetItemString(obj, "an1"), NPY_INT32, &attdet->an1)); - - CTYPES_CHECK("attdet.p_att", to_scalar( - PyDict_GetItemString(obj, "p_att"), NPY_INT, &attdet->p_att)); - - return obj; -} - -__attribute__((unused)) -static PyObject *from_attdet_analysis( - PyObject *obj, const struct lc3_attdet_analysis *attdet) -{ - if (!obj) obj = PyDict_New(); - - PyDict_SetItemString(obj, "en1", - new_scalar(NPY_INT32, &attdet->en1)); - - PyDict_SetItemString(obj, "an1", - new_scalar(NPY_INT32, &attdet->an1)); - - PyDict_SetItemString(obj, "p_att", - new_scalar(NPY_INT, &attdet->p_att)); - - return obj; -} - -/* -------------------------------------------------------------------------- */ - -#include - -__attribute__((unused)) -static PyObject *to_ltpf_hp50_state( - PyObject *obj, struct lc3_ltpf_hp50_state *hp50) -{ - CTYPES_CHECK("hp50", obj && PyDict_Check(obj)); - - CTYPES_CHECK("hp50.s1", to_scalar( - PyDict_GetItemString(obj, "s1"), NPY_INT64, &hp50->s1)); - - CTYPES_CHECK("hp50.s2", to_scalar( - PyDict_GetItemString(obj, "s2"), NPY_INT64, &hp50->s2)); - - return obj; -} - -__attribute__((unused)) -static PyObject *from_ltpf_hp50_state( - PyObject *obj, const struct lc3_ltpf_hp50_state *hp50) -{ - PyDict_SetItemString(obj, "s1", - new_scalar(NPY_INT64, &hp50->s1)); - - PyDict_SetItemString(obj, "s2", - new_scalar(NPY_INT64, &hp50->s2)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_ltpf_analysis( - PyObject *obj, struct lc3_ltpf_analysis *ltpf) -{ - PyObject *nc_obj, *x_12k8_obj, *x_6k4_obj; - const int n_12k8 = sizeof(ltpf->x_12k8) / sizeof(*ltpf->x_12k8); - const int n_6k4 = sizeof(ltpf->x_6k4) / sizeof(*ltpf->x_6k4); - - CTYPES_CHECK("ltpf", obj && PyDict_Check(obj)); - - CTYPES_CHECK("ltpf.active", to_scalar( - PyDict_GetItemString(obj, "active"), NPY_BOOL, <pf->active)); - - CTYPES_CHECK("ltpf.pitch", to_scalar( - PyDict_GetItemString(obj, "pitch"), NPY_INT, <pf->pitch)); - - CTYPES_CHECK("ltpf.nc", nc_obj = to_1d_copy( - PyDict_GetItemString(obj, "nc"), NPY_FLOAT, ltpf->nc, 2)); - PyDict_SetItemString(obj, "nc", nc_obj); - - CTYPES_CHECK(NULL, to_ltpf_hp50_state( - PyDict_GetItemString(obj, "hp50"), <pf->hp50)); - - CTYPES_CHECK("ltpf.x_12k8", x_12k8_obj = to_1d_copy( - PyDict_GetItemString(obj, "x_12k8"), NPY_INT16, ltpf->x_12k8, n_12k8)); - PyDict_SetItemString(obj, "x_12k8", x_12k8_obj); - - CTYPES_CHECK("ltpf.x_6k4", x_6k4_obj = to_1d_copy( - PyDict_GetItemString(obj, "x_6k4"), NPY_INT16, ltpf->x_6k4, n_6k4)); - PyDict_SetItemString(obj, "x_6k4", x_6k4_obj); - - CTYPES_CHECK("ltpf.tc", to_scalar( - PyDict_GetItemString(obj, "tc"), NPY_INT, <pf->tc)); - - return obj; -} - -__attribute__((unused)) -static PyObject *from_ltpf_analysis( - PyObject *obj, const struct lc3_ltpf_analysis *ltpf) -{ - const int n_12k8 = sizeof(ltpf->x_12k8) / sizeof(*ltpf->x_12k8); - const int n_6k4 = sizeof(ltpf->x_6k4) / sizeof(*ltpf->x_6k4); - - if (!obj) obj = PyDict_New(); - - PyDict_SetItemString(obj, "active", - new_scalar(NPY_BOOL, <pf->active)); - - PyDict_SetItemString(obj, "pitch", - new_scalar(NPY_INT, <pf->pitch)); - - PyDict_SetItemString(obj, "nc", - new_1d_copy(NPY_FLOAT, 2, <pf->nc)); - - PyDict_SetItemString(obj, "hp50", - from_ltpf_hp50_state(PyDict_New(), <pf->hp50)); - - PyDict_SetItemString(obj, "x_12k8", - new_1d_copy(NPY_INT16, n_12k8, <pf->x_12k8)); - - PyDict_SetItemString(obj, "x_6k4", - new_1d_copy(NPY_INT16, n_6k4, <pf->x_6k4)); - - PyDict_SetItemString(obj, "tc", - new_scalar(NPY_INT, <pf->tc)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_ltpf_synthesis( - PyObject *obj, struct lc3_ltpf_synthesis *ltpf) -{ - PyObject *c_obj, *x_obj; - - CTYPES_CHECK("ltpf", obj && PyDict_Check(obj)); - - CTYPES_CHECK("ltpf.active", to_scalar( - PyDict_GetItemString(obj, "active"), NPY_BOOL, <pf->active)); - - CTYPES_CHECK("ltpf.pitch", to_scalar( - PyDict_GetItemString(obj, "pitch"), NPY_INT, <pf->pitch)); - - CTYPES_CHECK("ltpf.c", c_obj = to_1d_copy( - PyDict_GetItemString(obj, "c"), NPY_FLOAT, ltpf->c, 2*12)); - PyDict_SetItemString(obj, "c", c_obj); - - CTYPES_CHECK("ltpf.x", x_obj = to_1d_copy( - PyDict_GetItemString(obj, "x"), NPY_FLOAT, ltpf->x, 12)); - PyDict_SetItemString(obj, "x", x_obj); - - return obj; -} - -__attribute__((unused)) -static PyObject *from_ltpf_synthesis( - PyObject *obj, const struct lc3_ltpf_synthesis *ltpf) -{ - if (!obj) obj = PyDict_New(); - - PyDict_SetItemString(obj, "active", - new_scalar(NPY_BOOL, <pf->active)); - - PyDict_SetItemString(obj, "pitch", - new_scalar(NPY_INT, <pf->pitch)); - - PyDict_SetItemString(obj, "c", - new_1d_copy(NPY_FLOAT, 2*12, <pf->c)); - - PyDict_SetItemString(obj, "x", - new_1d_copy(NPY_FLOAT, 12, <pf->x)); - - return obj; -} - -__attribute__((unused)) -static PyObject *new_ltpf_data(const struct lc3_ltpf_data *data) -{ - PyObject *obj = PyDict_New(); - - PyDict_SetItemString(obj, "active", - new_scalar(NPY_BOOL, &data->active)); - - PyDict_SetItemString(obj, "pitch_index", - new_scalar(NPY_INT, &data->pitch_index)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_ltpf_data( - PyObject *obj, const struct lc3_ltpf_data *data) -{ - PyObject *item; - - CTYPES_CHECK("ltpf", obj && PyDict_Check(obj)); - - if ((item = PyDict_GetItemString(obj, "active"))) - CTYPES_CHECK("ltpf.active", - to_scalar(item, NPY_BOOL, &data->active)); - - if ((item = PyDict_GetItemString(obj, "pitch_index"))) - CTYPES_CHECK("ltpf.pitch_index", - to_scalar(item, NPY_INT, &data->pitch_index)); - - return obj; -} - -/* -------------------------------------------------------------------------- */ - -#include - -__attribute__((unused)) -static PyObject *new_sns_data(const struct lc3_sns_data *data) -{ - PyObject *obj = PyDict_New(); - - PyDict_SetItemString(obj, "lfcb", - new_scalar(NPY_INT, &data->lfcb)); - - PyDict_SetItemString(obj, "hfcb", - new_scalar(NPY_INT, &data->hfcb)); - - PyDict_SetItemString(obj, "shape", - new_scalar(NPY_INT, &data->shape)); - - PyDict_SetItemString(obj, "gain", - new_scalar(NPY_INT, &data->gain)); - - PyDict_SetItemString(obj, "idx_a", - new_scalar(NPY_INT, &data->idx_a)); - - PyDict_SetItemString(obj, "ls_a", - new_scalar(NPY_BOOL, &data->ls_a)); - - PyDict_SetItemString(obj, "idx_b", - new_scalar(NPY_INT, &data->idx_b)); - - PyDict_SetItemString(obj, "ls_b", - new_scalar(NPY_BOOL, &data->ls_b)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_sns_data(PyObject *obj, struct lc3_sns_data *data) -{ - PyObject *item; - - CTYPES_CHECK("sns", obj && PyDict_Check(obj)); - - if ((item = PyDict_GetItemString(obj, "lfcb"))) - CTYPES_CHECK("sns.lfcb", to_scalar(item, NPY_INT, &data->lfcb)); - - if ((item = PyDict_GetItemString(obj, "hfcb"))) - CTYPES_CHECK("sns.hfcb", to_scalar(item, NPY_INT, &data->hfcb)); - - if ((item = PyDict_GetItemString(obj, "shape"))) - CTYPES_CHECK("sns.shape", to_scalar(item, NPY_INT, &data->shape)); - - if ((item = PyDict_GetItemString(obj, "gain"))) - CTYPES_CHECK("sns.gain", to_scalar(item, NPY_INT, &data->gain)); - - if ((item = PyDict_GetItemString(obj, "idx_a"))) - CTYPES_CHECK("sns.idx_a", to_scalar(item, NPY_INT, &data->idx_a)); - - if ((item = PyDict_GetItemString(obj, "ls_a"))) - CTYPES_CHECK("sns.ls_a", to_scalar(item, NPY_INT, &data->ls_a)); - - if ((item = PyDict_GetItemString(obj, "idx_b"))) - CTYPES_CHECK("sns.idx_b", to_scalar(item, NPY_INT, &data->idx_b)); - - if ((item = PyDict_GetItemString(obj, "ls_b"))) - CTYPES_CHECK("sns.ls_b", to_scalar(item, NPY_INT, &data->ls_b)); - - return obj; -} - -/* -------------------------------------------------------------------------- */ - -#include - -__attribute__((unused)) -static PyObject *new_tns_data(const struct lc3_tns_data *side) -{ - PyObject *obj = PyDict_New(); - - PyDict_SetItemString(obj, "nfilters", - new_scalar(NPY_INT, &side->nfilters)); - - PyDict_SetItemString(obj, "lpc_weighting", - new_scalar(NPY_BOOL, &side->lpc_weighting)); - - PyDict_SetItemString(obj, "rc_order", - new_1d_copy(NPY_INT, 2, side->rc_order)); - - PyDict_SetItemString(obj, "rc", - new_2d_copy(NPY_INT, 2, 8, side->rc)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_tns_data(PyObject *obj, struct lc3_tns_data *side) -{ - PyObject *item; - - CTYPES_CHECK("tns", obj && PyDict_Check(obj)); - - if ((item = PyDict_GetItemString(obj, "nfilters"))) - CTYPES_CHECK("tns.nfilters", - to_scalar(item, NPY_INT, &side->nfilters)); - - if ((item = PyDict_GetItemString(obj, "lpc_weighting"))) { - CTYPES_CHECK("tns.lpc_weighting", - to_scalar(item, NPY_BOOL, &side->lpc_weighting)); - } - - if ((item = PyDict_GetItemString(obj, "rc_order"))) { - CTYPES_CHECK("tns.rc_order", - item = to_1d_copy(item, NPY_INT, side->rc_order, 2)); - PyDict_SetItemString(obj, "rc_order", item); - } - - if ((item = PyDict_GetItemString(obj, "rc"))) { - CTYPES_CHECK("tns.rc", - item = to_2d_copy(item, NPY_INT, side->rc, 2, 8)); - PyDict_SetItemString(obj, "rc", item); - } - - return obj; -} - -/* -------------------------------------------------------------------------- */ - -#include - -__attribute__((unused)) -static PyObject *from_spec_analysis( - PyObject *obj, const struct lc3_spec_analysis *spec) -{ - if (!obj) obj = PyDict_New(); - - PyDict_SetItemString(obj, "nbits_off", - new_scalar(NPY_FLOAT, &spec->nbits_off)); - - PyDict_SetItemString(obj, "nbits_spare", - new_scalar(NPY_INT, &spec->nbits_spare)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_spec_analysis( - PyObject *obj, struct lc3_spec_analysis *spec) -{ - CTYPES_CHECK("spec", obj && PyDict_Check(obj)); - - CTYPES_CHECK("spec.nbits_off", - to_scalar(PyDict_GetItemString(obj, "nbits_off"), - NPY_FLOAT, &spec->nbits_off)); - - CTYPES_CHECK("spec.nbits_spare", - to_scalar(PyDict_GetItemString(obj, "nbits_spare"), - NPY_INT, &spec->nbits_spare)); - - return obj; -} - -__attribute__((unused)) -static PyObject *new_spec_side(const struct lc3_spec_side *side) -{ - PyObject *obj = PyDict_New(); - - PyDict_SetItemString(obj, "g_idx", - new_scalar(NPY_INT, &side->g_idx)); - - PyDict_SetItemString(obj, "nq", - new_scalar(NPY_INT, &side->nq)); - - PyDict_SetItemString(obj, "lsb_mode", - new_scalar(NPY_BOOL, &side->lsb_mode)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_spec_data( - PyObject *obj, struct lc3_spec_side *side) -{ - PyObject *item; - - CTYPES_CHECK("side", obj && PyDict_Check(obj)); - - if ((item = PyDict_GetItemString(obj, "g_idx"))) - CTYPES_CHECK("side.g_idx", - to_scalar(item, NPY_INT, &side->g_idx)); - - if ((item = PyDict_GetItemString(obj, "nq"))) - CTYPES_CHECK("side.nq", - to_scalar(item, NPY_INT, &side->nq)); - - if ((item = PyDict_GetItemString(obj, "lsb_mode"))) - CTYPES_CHECK("side.lsb_mode", - to_scalar(item, NPY_BOOL, &side->lsb_mode)); - - return obj; -} - -/* -------------------------------------------------------------------------- */ - -#ifdef __CTYPES_LC3_C - -__attribute__((unused)) -static PyObject *new_side_data(const struct side_data *side) -{ - PyObject *obj = PyDict_New(); - - PyDict_SetItemString(obj, "bw", - new_scalar(NPY_INT, &(int){ side->bw })); - - PyDict_SetItemString(obj, "ltpf", - new_ltpf_data(&side->ltpf)); - - PyDict_SetItemString(obj, "sns", - new_sns_data(&side->sns)); - - PyDict_SetItemString(obj, "tns", - new_tns_data(&side->tns)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_side_data(PyObject *obj, struct side_data *side) -{ - PyObject *item; - - CTYPES_CHECK("frame", obj && PyDict_Check(obj)); - - if ((item = PyDict_GetItemString(obj, "bw"))) { - int bw; - CTYPES_CHECK("frame.bw", to_scalar(item, NPY_INT, &bw)); - side->bw = bw; - } - - if ((item = PyDict_GetItemString(obj, "ltpf"))) - to_ltpf_data(item, &side->ltpf); - - if ((item = PyDict_GetItemString(obj, "sns"))) - to_sns_data(item, &side->sns); - - if ((item = PyDict_GetItemString(obj, "tns"))) - to_tns_data(item, &side->tns); - - return obj; -} - -__attribute__((unused)) -static PyObject *new_plc_state(const struct lc3_plc_state *plc) -{ - PyObject *obj = PyDict_New(); - - PyDict_SetItemString(obj, "seed", - new_scalar(NPY_UINT16, &plc->seed)); - - PyDict_SetItemString(obj, "count", - new_scalar(NPY_INT, &plc->count)); - - PyDict_SetItemString(obj, "alpha", - new_scalar(NPY_FLOAT, &plc->alpha)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_plc_state( - PyObject *obj, struct lc3_plc_state *plc) -{ - CTYPES_CHECK("plc", obj && PyDict_Check(obj)); - - CTYPES_CHECK("plc.seed", to_scalar( - PyDict_GetItemString(obj, "seed"), NPY_UINT16, &plc->seed)); - - CTYPES_CHECK("plc.count", to_scalar( - PyDict_GetItemString(obj, "count"), NPY_INT, &plc->count)); - - CTYPES_CHECK("plc.alpha", to_scalar( - PyDict_GetItemString(obj, "alpha"), NPY_FLOAT, &plc->alpha)); - - return obj; -} - -__attribute__((unused)) -static PyObject *from_encoder(PyObject *obj, const struct lc3_encoder *enc) -{ - unsigned dt = enc->dt, sr = enc->sr; - unsigned sr_pcm = enc->sr_pcm; - int ns = LC3_NS(dt, sr); - int nd = LC3_ND(dt, sr); - int nt = LC3_NT(sr); - - if (!obj) obj = PyDict_New(); - - PyDict_SetItemString(obj, "dt", - new_scalar(NPY_INT, &dt)); - - PyDict_SetItemString(obj, "sr", - new_scalar(NPY_INT, &sr)); - - PyDict_SetItemString(obj, "sr_pcm", - new_scalar(NPY_INT, &sr_pcm)); - - PyDict_SetItemString(obj, "attdet", - from_attdet_analysis(NULL, &enc->attdet)); - - PyDict_SetItemString(obj, "ltpf", - from_ltpf_analysis(NULL, &enc->ltpf)); - - PyDict_SetItemString(obj, "quant", - from_spec_analysis(NULL, &enc->spec)); - - PyDict_SetItemString(obj, "xt", - new_1d_copy(NPY_INT16, nt+ns, enc->xt-nt)); - - PyDict_SetItemString(obj, "xs", - new_1d_copy(NPY_FLOAT, ns, enc->xs)); - - PyDict_SetItemString(obj, "xd", - new_1d_copy(NPY_FLOAT, nd, enc->xd)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_encoder(PyObject *obj, struct lc3_encoder *enc) -{ - unsigned dt, sr, sr_pcm; - PyObject *xt_obj, *xs_obj, *xd_obj; - - CTYPES_CHECK("encoder", obj && PyDict_Check(obj)); - - CTYPES_CHECK("encoder.dt", to_scalar( - PyDict_GetItemString(obj, "dt"), NPY_INT, &dt)); - CTYPES_CHECK("encoder.dt", (unsigned)(enc->dt = dt) < LC3_NUM_DT); - - CTYPES_CHECK("encoder.sr", to_scalar( - PyDict_GetItemString(obj, "sr"), NPY_INT, &sr)); - CTYPES_CHECK("encoder.sr", (unsigned)(enc->sr = sr) < LC3_NUM_SRATE); - - CTYPES_CHECK("encoder.sr_pcm", to_scalar( - PyDict_GetItemString(obj, "sr_pcm"), NPY_INT, &sr_pcm)); - CTYPES_CHECK("encoder.s_pcmr", - (unsigned)(enc->sr_pcm = sr_pcm) < LC3_NUM_SRATE); - - int ns = LC3_NS(dt, sr); - int nd = LC3_ND(dt, sr); - int nt = LC3_NT(sr); - - CTYPES_CHECK(NULL, to_attdet_analysis( - PyDict_GetItemString(obj, "attdet"), &enc->attdet)); - - CTYPES_CHECK(NULL, to_ltpf_analysis( - PyDict_GetItemString(obj, "ltpf"), &enc->ltpf)); - - CTYPES_CHECK(NULL, to_spec_analysis( - PyDict_GetItemString(obj, "quant"), &enc->spec)); - - CTYPES_CHECK("encoder.xt", xt_obj = to_1d_copy( - PyDict_GetItemString(obj, "xt"), NPY_INT16, enc->xt-nt, ns+nt)); - PyDict_SetItemString(obj, "xt", xt_obj); - - CTYPES_CHECK("encoder.xs", xs_obj = to_1d_copy( - PyDict_GetItemString(obj, "xs"), NPY_FLOAT, enc->xs, ns)); - PyDict_SetItemString(obj, "xs", xs_obj); - - CTYPES_CHECK("encoder.xd", xd_obj = to_1d_copy( - PyDict_GetItemString(obj, "xd"), NPY_FLOAT, enc->xd, nd)); - PyDict_SetItemString(obj, "xd", xd_obj); - - return obj; -} - -__attribute__((unused)) -static PyObject *from_decoder(PyObject *obj, const struct lc3_decoder *dec) -{ - unsigned dt = dec->dt, sr = dec->sr; - unsigned sr_pcm = dec->sr_pcm; - unsigned xs_pos = dec->xs - dec->xh; - int nh = LC3_NH(dt, sr); - int ns = LC3_NS(dt, sr); - int nd = LC3_ND(dt, sr); - - if (!obj) obj = PyDict_New(); - - PyDict_SetItemString(obj, "dt", - new_scalar(NPY_INT, &dt)); - - PyDict_SetItemString(obj, "sr", - new_scalar(NPY_INT, &sr)); - - PyDict_SetItemString(obj, "sr_pcm", - new_scalar(NPY_INT, &sr_pcm)); - - PyDict_SetItemString(obj, "ltpf", - from_ltpf_synthesis(NULL, &dec->ltpf)); - - PyDict_SetItemString(obj, "plc", - new_plc_state(&dec->plc)); - - PyDict_SetItemString(obj, "xh", - new_1d_copy(NPY_FLOAT, nh, dec->xh)); - - PyDict_SetItemString(obj, "xs_pos", - new_scalar(NPY_INT, &xs_pos)); - - PyDict_SetItemString(obj, "xd", - new_1d_copy(NPY_FLOAT, nd, dec->xd)); - - PyDict_SetItemString(obj, "xg", - new_1d_copy(NPY_FLOAT, ns, dec->xg)); - - return obj; -} - -__attribute__((unused)) -static PyObject *to_decoder(PyObject *obj, struct lc3_decoder *dec) -{ - unsigned dt, sr, sr_pcm, xs_pos; - PyObject *xh_obj, *xd_obj, *xg_obj; - - CTYPES_CHECK("decoder", obj && PyDict_Check(obj)); - - CTYPES_CHECK("decoder.dt", to_scalar( - PyDict_GetItemString(obj, "dt"), NPY_INT, &dt)); - CTYPES_CHECK("decoder.dt", (unsigned)(dec->dt = dt) < LC3_NUM_DT); - - CTYPES_CHECK("decoder.sr", to_scalar( - PyDict_GetItemString(obj, "sr"), NPY_INT, &sr)); - CTYPES_CHECK("decoder.sr", (unsigned)(dec->sr = sr) < LC3_NUM_SRATE); - - CTYPES_CHECK("decoder.sr_pcm", to_scalar( - PyDict_GetItemString(obj, "sr_pcm"), NPY_INT, &sr_pcm)); - CTYPES_CHECK("decoder.sr_pcm", - (unsigned)(dec->sr_pcm = sr_pcm) < LC3_NUM_SRATE); - - int nh = LC3_NH(dt, sr); - int ns = LC3_NS(dt, sr); - int nd = LC3_ND(dt, sr); - - CTYPES_CHECK(NULL, to_ltpf_synthesis( - PyDict_GetItemString(obj, "ltpf"), &dec->ltpf)); - - CTYPES_CHECK(NULL, to_plc_state( - PyDict_GetItemString(obj, "plc"), &dec->plc)); - - CTYPES_CHECK("decoder.xh", xh_obj = to_1d_copy( - PyDict_GetItemString(obj, "xh"), NPY_FLOAT, dec->xh, nh)); - PyDict_SetItemString(obj, "xh", xh_obj); - - CTYPES_CHECK("decoder.xs", to_scalar( - PyDict_GetItemString(obj, "xs_pos"), NPY_INT, &xs_pos)); - dec->xs = dec->xh + xs_pos; - - CTYPES_CHECK("decoder.xd", xd_obj = to_1d_copy( - PyDict_GetItemString(obj, "xd"), NPY_FLOAT, dec->xd, nd)); - PyDict_SetItemString(obj, "xd", xd_obj); - - CTYPES_CHECK("decoder.xg", xg_obj = to_1d_copy( - PyDict_GetItemString(obj, "xg"), NPY_FLOAT, dec->xg, ns)); - PyDict_SetItemString(obj, "xg", xg_obj); - - return obj; -} - - -/* -------------------------------------------------------------------------- */ - -#endif /* __CTYPES_LC3_C */ - -#endif /* __CTYPES */ diff --git a/system/embdrv/lc3/test/decoder.py b/system/embdrv/lc3/test/decoder.py deleted file mode 100755 index 93ed9189ed50919e8f784f0574507be4829117d2..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/decoder.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np -import scipy.signal as signal -import scipy.io.wavfile as wavfile -import struct -import argparse - -import build.lc3 as lc3 -import tables as T, appendix_c as C - -import mdct, energy, bwdet, sns, tns, spec, ltpf -import bitstream - -### ------------------------------------------------------------------------ ### - -class Decoder: - - def __init__(self, dt_ms, sr_hz): - - dt = { 7.5: T.DT_7M5, 10: T.DT_10M }[dt_ms] - - sr = { 8000: T.SRATE_8K , 16000: T.SRATE_16K, 24000: T.SRATE_24K, - 32000: T.SRATE_32K, 48000: T.SRATE_48K }[sr_hz] - - self.sr = sr - self.ne = T.NE[dt][sr] - self.ns = T.NS[dt][sr] - - self.mdct = mdct.MdctInverse(dt, sr) - - self.bwdet = bwdet.BandwidthDetector(dt, sr) - self.spec = spec.SpectrumSynthesis(dt, sr) - self.tns = tns.TnsSynthesis(dt) - self.sns = sns.SnsSynthesis(dt, sr) - self.ltpf = ltpf.LtpfSynthesis(dt, sr) - - def decode(self, data): - - b = bitstream.BitstreamReader(data) - - bw = self.bwdet.get_bw(b) - if bw > self.sr: - raise ValueError('Invalid bandwidth indication') - - self.spec.load(b) - - self.tns.load(b, bw, len(data)) - - pitch = b.read_bit() - - self.sns.load(b) - - if pitch: - self.ltpf.load(b) - else: - self.ltpf.disable() - - x = self.spec.decode(b, bw, len(data)) - - return (x, bw, pitch) - - def synthesize(self, x, bw, pitch, nbytes): - - x = self.tns.run(x, bw) - - x = self.sns.run(x) - - x = np.append(x, np.zeros(self.ns - self.ne)) - x = self.mdct.run(x) - - x = self.ltpf.run(x, len(data)) - - return x - - def run(self, data): - - (x, bw, pitch) = self.decode(data) - - x = self.synthesize(x, bw, pitch, len(data)) - - return x - -### ------------------------------------------------------------------------ ### - -def check_appendix_c(dt): - - ok = True - - dec_c = lc3.setup_decoder(int(T.DT_MS[dt] * 1000), 16000) - - for i in range(len(C.BYTES_AC[dt])): - - pcm = lc3.decode(dec_c, bytes(C.BYTES_AC[dt][i])) - ok = ok and np.max(np.abs(pcm - C.X_HAT_CLIP[dt][i])) < 1 - - return ok - -def check(): - - ok = True - - for dt in range(T.NUM_DT): - ok = ok and check_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### - -if __name__ == "__main__": - - parser = argparse.ArgumentParser(description='LC3 Decoder Test Framework') - parser.add_argument('lc3_file', - help='Input bitstream file', type=argparse.FileType('r')) - parser.add_argument('--pyout', - help='Python output file', type=argparse.FileType('w')) - parser.add_argument('--cout', - help='C output file', type=argparse.FileType('w')) - args = parser.parse_args() - - ### File Header ### - - f_lc3 = open(args.lc3_file.name, 'rb') - - header = struct.unpack('=HHHHHHHI', f_lc3.read(18)) - - if header[0] != 0xcc1c: - raise ValueError('Invalid bitstream file') - - if header[4] != 1: - raise ValueError('Unsupported number of channels') - - sr_hz = header[2] * 100 - bitrate = header[3] * 100 - nchannels = header[4] - dt_ms = header[5] / 100 - - f_lc3.seek(header[1]) - - ### Setup ### - - dec = Decoder(dt_ms, sr_hz) - dec_c = lc3.setup_decoder(int(dt_ms * 1000), sr_hz) - - pcm_c = np.empty(0).astype(np.int16) - pcm_py = np.empty(0).astype(np.int16) - - ### Decoding loop ### - - nframes = 0 - - while True: - - data = f_lc3.read(2) - if len(data) != 2: - break - - if nframes >= 1000: - break - - (frame_nbytes,) = struct.unpack('=H', data) - - print('Decoding frame %d' % nframes, end='\r') - - data = f_lc3.read(frame_nbytes) - - x = dec.run(data) - pcm_py = np.append(pcm_py, - np.clip(np.round(x), -32768, 32767).astype(np.int16)) - - x_c = lc3.decode(dec_c, data) - pcm_c = np.append(pcm_c, x_c) - - nframes += 1 - - print('done ! %16s' % '') - - ### Terminate ### - - if args.pyout: - wavfile.write(args.pyout.name, sr_hz, pcm_py) - if args.cout: - wavfile.write(args.cout.name, sr_hz, pcm_c) - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/encoder.py b/system/embdrv/lc3/test/encoder.py deleted file mode 100755 index 0382b96e799b5dda012acf3cf82b1d156d12bcc1..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/encoder.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np -import scipy.signal as signal -import scipy.io.wavfile as wavfile -import struct -import argparse - -import build.lc3 as lc3 -import tables as T, appendix_c as C - -import attdet, ltpf -import mdct, energy, bwdet, sns, tns, spec -import bitstream - -### ------------------------------------------------------------------------ ### - -class Encoder: - - def __init__(self, dt_ms, sr_hz): - - dt = { 7.5: T.DT_7M5, 10: T.DT_10M }[dt_ms] - - sr = { 8000: T.SRATE_8K , 16000: T.SRATE_16K, 24000: T.SRATE_24K, - 32000: T.SRATE_32K, 48000: T.SRATE_48K }[sr_hz] - - self.ne = T.NE[dt][sr] - - self.attdet = attdet.AttackDetector(dt, sr) - self.ltpf = ltpf.Ltpf(dt, sr) - - self.mdct = mdct.Mdct(dt, sr) - self.energy = e_energy.EnergyBand(dt, sr) - self.bwdet = bwdet.BandwidthDetector(dt, sr) - self.sns = sns.SnsAnalysis(dt, sr) - self.tns = tns.TnsAnalysis(dt) - self.spec = spec.SpectrumEncoder(dt, sr) - - def analyse(self, x, nbytes): - - att = self.attdet.run(nbytes, x) - - pitch_present = self.ltpf.run(x) - - x = self.mdct.forward(x)[:self.ne] - - (e, nn_flag) = self.energy.compute(x) - if nn_flag: - self.ltpf.disable() - - bw = self.bwdet.run(e) - - x = self.sns.run(e, att, x) - - x = self.tns.run(x, bw, nn_flag, nbytes) - - (xq, lastnz, x) = self.spec.quantize(bw, nbytes, - self.bwdet.get_nbits(), self.ltpf.get_nbits(), - self.sns.get_nbits(), self.tns.get_nbits(), x) - - return pitch_present - - def encode(self, pitch_present, nbytes): - - b = bitstream.BitstreamWriter(nbytes) - - self.bwdet.store(b) - - self.spec.store(b) - - self.tns.store(b) - - b.write_bit(pitch_present) - - self.sns.store(b) - - if pitch_present: - self.ltpf.store_data(b) - - self.spec.encode(b) - - return b.terminate() - - def run(self, x, nbytes): - - pitch_present = self.analyse(x, nbytes) - - data = self.encode(pitch_present, nbytes) - - return data - -### ------------------------------------------------------------------------ ### - -def check_appendix_c(dt): - - ok = True - - enc_c = lc3.setup_encoder(int(T.DT_MS[dt] * 1000), 16000) - - for i in range(len(C.X_PCM[dt])): - - data = lc3.encode(enc_c, C.X_PCM[dt][i], C.NBYTES[dt]) - ok = ok and data == C.BYTES_AC[dt][i] - if not ok: - dump(data) - dump(C.BYTES_AC[dt][i]) - - return ok - -def check(): - - ok = True - - for dt in range(T.NUM_DT): - ok = ok and check_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### - -def dump(data): - for i in range(0, len(data), 20): - print(''.join('{:02x} '.format(x) - for x in data[i:min(i+20, len(data))] )) - -if __name__ == "__main__": - - parser = argparse.ArgumentParser(description='LC3 Encoder Test Framework') - parser.add_argument('wav_file', - help='Input wave file', type=argparse.FileType('r')) - parser.add_argument('--bitrate', - help='Bitrate in bps', type=int, required=True) - parser.add_argument('--dt', - help='Frame duration in ms', type=float, default=10) - parser.add_argument('--pyout', - help='Python output file', type=argparse.FileType('w')) - parser.add_argument('--cout', - help='C output file', type=argparse.FileType('w')) - args = parser.parse_args() - - if args.bitrate < 16000 or args.bitrate > 320000: - raise ValueError('Invalid bitate %d bps' % args.bitrate) - - if args.dt not in (7.5, 10): - raise ValueError('Invalid frame duration %.1f ms' % args.dt) - - (sr_hz, pcm) = wavfile.read(args.wav_file.name) - if sr_hz not in (8000, 16000, 24000, 320000, 48000): - raise ValueError('Unsupported input samplerate: %d' % sr_hz) - - ### Setup ### - - enc = Encoder(args.dt, sr_hz) - enc_c = lc3.setup_encoder(int(args.dt * 1000), sr_hz) - - frame_samples = int((args.dt * sr_hz) / 1000) - frame_nbytes = int((args.bitrate * args.dt) / (1000 * 8)) - - ### File Header ### - - f_py = open(args.pyout.name, 'wb') if args.pyout else None - f_c = open(args.cout.name , 'wb') if args.cout else None - - header = struct.pack('=HHHHHHHI', 0xcc1c, 18, - sr_hz // 100, args.bitrate // 100, 1, int(args.dt * 100), 0, len(pcm)) - - for f in (f_py, f_c): - if f: f.write(header) - - ### Encoding loop ### - - if len(pcm) % frame_samples > 0: - pcm = np.append(pcm, np.zeros(frame_samples - (len(pcm) % frame_samples))) - - for i in range(0, len(pcm), frame_samples): - - print('Encoding frame %d' % (i // frame_samples), end='\r') - - frame_pcm = pcm[i:i+frame_samples] - - data = enc.run(frame_pcm, frame_nbytes) - data_c = lc3.encode(enc_c, frame_pcm, frame_nbytes) - - for f in (f_py, f_c): - if f: f.write(struct.pack('=H', frame_nbytes)) - - if f_py: f_py.write(data) - if f_c: f_c.write(data_c) - - print('done ! %16s' % '') - - ### Terminate ### - - for f in (f_py, f_c): - if f: f.close() - - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/energy.py b/system/embdrv/lc3/test/energy.py deleted file mode 100644 index 13c6828fb53ef9b719da91368661401ba3dced2c..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/energy.py +++ /dev/null @@ -1,92 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np - -import build.lc3 as lc3 -import tables as T, appendix_c as C - -### ------------------------------------------------------------------------ ### - -class EnergyBand: - - def __init__(self, dt, sr): - - self.dt = dt - self.I = T.I[dt][sr] - - def compute(self, x): - - e = [ np.mean(np.square(x[self.I[i]:self.I[i+1]])) - for i in range(len(self.I)-1) ] - - e_lo = np.sum(e[:len(e) - [4, 2][self.dt]]) - e_hi = np.sum(e[len(e) - [4, 2][self.dt]:]) - - return np.append(e, np.zeros(64-len(e))), (e_hi > 30*e_lo) - -### ------------------------------------------------------------------------ ### - -def check_unit(rng, dt, sr): - - ns = T.NS[dt][sr] - ok = True - - nrg = EnergyBand(dt, sr) - - x = (2 * rng.random(T.NS[dt][sr])) - 1 - - (e , nn ) = nrg.compute(x) - (e_c, nn_c) = lc3.energy_compute(dt, sr, x) - ok = ok and np.amax(np.abs(e_c - e)) < 1e-5 and nn_c == nn - - x[15*ns//16:] *= 1e2; - - (e , nn ) = nrg.compute(x) - (e_c, nn_c) = lc3.energy_compute(dt, sr, x) - ok = ok and np.amax(np.abs(e_c - e)) < 1e-3 and nn_c == nn - - return ok - -def check_appendix_c(dt): - - sr = T.SRATE_16K - ok = True - - e = lc3.energy_compute(dt, sr, C.X[dt][0])[0] - ok = ok and np.amax(np.abs(1 - e/C.E_B[dt][0])) < 1e-6 - - e = lc3.energy_compute(dt, sr, C.X[dt][1])[0] - ok = ok and np.amax(np.abs(1 - e/C.E_B[dt][1])) < 1e-6 - - return ok - -def check(): - - rng = np.random.default_rng(1234) - - ok = True - - for dt in range(T.NUM_DT): - for sr in range(T.NUM_SRATE): - ok = ok and check_unit(rng, dt, sr) - - for dt in range(T.NUM_DT): - ok = ok and check_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/energy_py.c b/system/embdrv/lc3/test/energy_py.c deleted file mode 100644 index 3b65ba5663be4b7741f21041749211ad395b1018..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/energy_py.c +++ /dev/null @@ -1,62 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "lc3.h" - -#define PY_SSIZE_T_CLEAN -#include -#include - -#include -#include "ctypes.h" - -static PyObject *energy_compute_py(PyObject *m, PyObject *args) -{ - unsigned dt, sr; - PyObject *x_obj, *e_obj; - float *x, *e; - - if (!PyArg_ParseTuple(args, "IIO", &dt, &sr, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int ns = LC3_NS(dt, sr); - - CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, ns, &x)); - e_obj = new_1d_ptr(NPY_FLOAT, LC3_NUM_BANDS, &e); - - int nn_flag = lc3_energy_compute(dt, sr, x, e); - - return Py_BuildValue("Ni", e_obj, nn_flag); -} - -static PyMethodDef methods[] = { - { "energy_compute", energy_compute_py, METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_energy_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/test/lc3_py.c b/system/embdrv/lc3/test/lc3_py.c deleted file mode 100644 index 2984beb28d4943e33e3f5f3eec80f462c926724d..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/lc3_py.c +++ /dev/null @@ -1,142 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "lc3.h" - -#define PY_SSIZE_T_CLEAN -#include -#include - -#include - -#define __CTYPES_LC3_C -#include "ctypes.h" - -static PyObject *setup_encoder_py(PyObject *m, PyObject *args) -{ - int dt_us, sr_hz; - - if (!PyArg_ParseTuple(args, "ii", &dt_us, &sr_hz)) - return NULL; - - CTYPES_CHECK("dt_us", LC3_CHECK_DT_US(dt_us)); - CTYPES_CHECK("sr_hz", LC3_CHECK_SR_HZ(sr_hz)); - - lc3_encoder_t encoder = lc3_setup_encoder(dt_us, sr_hz, 0, - malloc(lc3_encoder_size(dt_us, sr_hz))); - - PyObject *encoder_obj = from_encoder(NULL, encoder); - - free(encoder); - - return Py_BuildValue("N", encoder_obj); -} - -static PyObject *encode_py(PyObject *m, PyObject *args) -{ - PyObject *encoder_obj, *pcm_obj; - int nbytes; - int16_t *pcm; - - if (!PyArg_ParseTuple(args, "OOi", &encoder_obj, &pcm_obj, &nbytes)) - return NULL; - - lc3_encoder_t encoder = - lc3_setup_encoder(10000, 48000, 0, &(lc3_encoder_mem_48k_t){ }); - - CTYPES_CHECK(NULL, encoder_obj = to_encoder(encoder_obj, encoder)); - - int ns = LC3_NS(encoder->dt, encoder->sr); - - CTYPES_CHECK("x", pcm_obj = to_1d_ptr(pcm_obj, NPY_INT16, ns, &pcm)); - CTYPES_CHECK("nbytes", nbytes >= 20 && nbytes <= 400); - - uint8_t out[nbytes]; - - lc3_encode(encoder, LC3_PCM_FORMAT_S16, pcm, 1, nbytes, out); - - from_encoder(encoder_obj, encoder); - - return Py_BuildValue("N", - PyBytes_FromStringAndSize((const char *)out, nbytes)); -} - -static PyObject *setup_decoder_py(PyObject *m, PyObject *args) -{ - int dt_us, sr_hz; - - if (!PyArg_ParseTuple(args, "ii", &dt_us, &sr_hz)) - return NULL; - - CTYPES_CHECK("dt_us", LC3_CHECK_DT_US(dt_us)); - CTYPES_CHECK("sr_hz", LC3_CHECK_SR_HZ(sr_hz)); - - lc3_decoder_t decoder = lc3_setup_decoder(dt_us, sr_hz, 0, - malloc(lc3_decoder_size(dt_us, sr_hz))); - - PyObject *decoder_obj = from_decoder(NULL, decoder); - - free(decoder); - - return Py_BuildValue("N", decoder_obj); -} - -static PyObject *decode_py(PyObject *m, PyObject *args) -{ - PyObject *decoder_obj, *pcm_obj, *in_obj; - int16_t *pcm; - - if (!PyArg_ParseTuple(args, "OO", &decoder_obj, &in_obj)) - return NULL; - - CTYPES_CHECK("in", in_obj == Py_None || PyBytes_Check(in_obj)); - - char *in = in_obj == Py_None ? NULL : PyBytes_AsString(in_obj); - int nbytes = in_obj == Py_None ? 0 : PyBytes_Size(in_obj); - - lc3_decoder_t decoder = - lc3_setup_decoder(10000, 48000, 0, &(lc3_decoder_mem_48k_t){ }); - - CTYPES_CHECK(NULL, decoder_obj = to_decoder(decoder_obj, decoder)); - - int ns = LC3_NS(decoder->dt, decoder->sr); - pcm_obj = new_1d_ptr(NPY_INT16, ns, &pcm); - - lc3_decode(decoder, in, nbytes, LC3_PCM_FORMAT_S16, pcm, 1); - - from_decoder(decoder_obj, decoder); - - return Py_BuildValue("N", pcm_obj); -} - -static PyMethodDef methods[] = { - { "setup_encoder" , setup_encoder_py , METH_VARARGS }, - { "encode" , encode_py , METH_VARARGS }, - { "setup_decoder" , setup_decoder_py , METH_VARARGS }, - { "decode" , decode_py , METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_interface_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/test/ltpf.py b/system/embdrv/lc3/test/ltpf.py deleted file mode 100644 index 1a852c83c11c81b7148329d6d155628262550f37..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/ltpf.py +++ /dev/null @@ -1,660 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np -import scipy.signal as signal - -import build.lc3 as lc3 -import tables as T, appendix_c as C - -### ------------------------------------------------------------------------ ### - -class Resampler_12k8: - - def __init__(self, dt, sr, history = 0): - - self.sr = sr - self.p = 192 // T.SRATE_KHZ[sr] - self.w = 240 // self.p - - self.n = ((T.DT_MS[dt] * 128) / 10).astype(int) - self.d = [ 44, 24 ][dt] - - self.x = np.zeros(self.w + T.NS[dt][sr]) - self.u = np.zeros(self.n + 2) - self.y = np.zeros(self.n + self.d + history) - - def resample(self, x): - - p = self.p - w = self.w - d = self.d - n = self.n - - ### Sliding window - - self.x[:w] = self.x[-w:] - self.x[w:] = x - self.u[:2] = self.u[-2:] - - if len(self.y) > 2*n + d: - self.y[n+d:-n] = self.y[d+2*n:] - if len(self.y) > n + d: - self.y[-n:] = self.y[:n] - self.y[:d] = self.y[n:d+n] - - x = self.x - u = self.u - - ### 3.3.9.3 Resampling - - h = np.zeros(240 + p) - h[-119:] = T.LTPF_H12K8[:119] - h[ :120] = T.LTPF_H12K8[119:] - - for i in range(n): - e = (15 * i) // p - f = (15 * i) % p - k = np.arange(-120, 120 + p, p) - f - u[2+i] = p * np.dot( x[e:e+w+1], np.take(h, k) ) - - if self.sr == T.SRATE_8K: - u = 0.5 * u - - ### 3.3.9.4 High-pass filtering - - b = [ 0.9827947082978771, -1.9655894165957540, 0.9827947082978771 ] - a = [ 1 , -1.9652933726226904, 0.9658854605688177 ] - - self.y[d:d+n] = b[0] * u[2:] + b[1] * u[1:-1] + b[2] * u[:-2] - for i in range(n): - self.y[d+i] -= a[1] * self.y[d+i-1] + a[2] * self.y[d+i-2] - - return self.y - - -class Resampler_6k4: - - def __init__(self, n, history = 0): - - self.x = np.zeros(n + 5) - self.n = n // 2 - - self.y = np.zeros(self.n + history) - - def resample(self, x): - - n = self.n - - ### Sliding window - - self.x[:3] = self.x[-5:-2] - self.x[3:] = x[:2*n+2] - x = self.x - - if len(self.y) > 2*n: - self.y[n:-n] = self.y[2*n:] - if len(self.y) > n: - self.y[-n:] = self.y[:n] - - ### 3.3.9.5 Downsampling to 6.4 KHz - - h = [ 0.1236796411180537, 0.2353512128364889, 0.2819382920909148, - 0.2353512128364889, 0.1236796411180537 ] - - self.y[:n] = [ np.dot(x[2*i:2*i+5], h) for i in range(self.n) ] - return self.y - - -def initial_hp50_state(): - return { 's1': 0, 's2': 0 } - -### ------------------------------------------------------------------------ ### - -class Ltpf: - - def __init__(self, dt, sr): - - self.dt = dt - self.sr = sr - - (self.pitch_present, self.pitch_index) = (None, None) - - def get_data(self): - - return { 'active' : self.active, - 'pitch_index' : self.pitch_index } - - def get_nbits(self): - - return 1 + 10 * int(self.pitch_present) - - -class LtpfAnalysis(Ltpf): - - def __init__(self, dt, sr): - - super().__init__(dt, sr) - - self.resampler_12k8 = Resampler_12k8( - dt, sr, history = 232) - - self.resampler_6k4 = Resampler_6k4( - self.resampler_12k8.n, history = 114) - - self.active = False - self.tc = 0 - self.pitch = 0 - self.nc = np.zeros(2) - - def correlate(self, x, n, k0, k1): - - return [ np.dot(x[:n], np.take(x, np.arange(n) - k)) \ - for k in range(k0, 1+k1) ] - - def norm_corr(self, x, n, k): - - u = x[:n] - v = np.take(x, np.arange(n) - k) - uv = np.dot(u, v) - return uv / np.sqrt(np.dot(u, u) * np.dot(v, v)) if uv > 0 else 0 - - def run(self, x): - - ### 3.3.9.3-4 Resampling - - x_12k8 = self.resampler_12k8.resample(x) - - ### 3.3.9.5-6 Pitch detection algorithm - - x = self.resampler_6k4.resample(x_12k8) - n = self.resampler_6k4.n - - r = self.correlate(x, n, 17, 114) - rw = r * (1 - 0.5 * np.arange(len(r)) / (len(r) - 1)) - - tc = self.tc - k0 = max(0, tc-4) - k1 = min(len(r)-1, tc+4) - t = [ 17 + np.argmax(rw), 17 + k0 + np.argmax(r[k0:1+k1]) ] - - nc = [ self.norm_corr(x, n, t[i]) for i in range(2) ] - ti = int(nc[1] > 0.85 * nc[0]) - self.tc = t[ti] - 17 - - self.pitch_present = bool(nc[ti] > 0.6) - - ### 3.3.9.7 Pitch-lag parameter - - if self.pitch_present: - tc = self.tc + 17 - - x = x_12k8 - n = self.resampler_12k8.n - - k0 = max( 32, 2*tc-4) - k1 = min(228, 2*tc+4) - r = self.correlate(x, n, k0-4, k1+4) - e = k0 + np.argmax(r[4:-4]) - - h = np.zeros(42) - h[-15:] = T.LTPF_H4[:15] - h[ :16] = T.LTPF_H4[15:] - - m = np.arange(-4, 5) - s = [ np.dot( np.take(r, e-k0+4 + m), np.take(h, 4*m-d) ) \ - for d in range(-3, 4) ] - - f = np.argmax(s[3:]) if e <= 32 else \ - -3 + np.argmax(s) if e < 127 else \ - -2 + 2*np.argmax(s[1:-1:2]) if e < 157 else 0 - - e -= (f < 0) - f += 4*(f < 0) - - self.pitch_index = 4*e + f - 128 if e < 127 else \ - 2*e + f//2 + 126 if e < 157 else e + 283 - - else: - e = f = 0 - self.pitch_index = 0 - - ### 3.3.9.8 Activation bit - - h = np.zeros(24) - h[-7:] = T.LTPF_HI[:7] - h[ :8] = T.LTPF_HI[7:] - - k = np.arange(-2, 3) - u = [ np.dot( np.take(x, i-k), np.take(h, 4*k) ) \ - for i in range(n) ] - v = [ np.dot( np.take(x, i-k), np.take(h, 4*k-f) ) \ - for i in range(-e, n-e) ] - - nc = max(0, np.dot(u, v)) / np.sqrt(np.dot(u, u) * np.dot(v, v)) \ - if self.pitch_present else 0 - - pitch = e + f/4 - - if not self.active: - active = (self.dt == T.DT_10M or self.nc[1] > 0.94) \ - and self.nc[0] > 0.94 and nc > 0.94 - - else: - dp = abs(pitch - self.pitch) - dc = nc - self.nc[0] - active = nc > 0.9 or (dp < 2 and dc > -0.1 and nc > 0.84) - - if not self.pitch_present: - active = False - pitch = 0 - nc = 0 - - self.active = active - self.pitch = pitch - self.nc[1] = self.nc[0] - self.nc[0] = nc - - return self.pitch_present - - def disable(self): - - self.active = False - - def store(self, b): - - b.write_uint(self.active, 1) - b.write_uint(self.pitch_index, 9) - - -class LtpfSynthesis(Ltpf): - - C_N = [ T.LTPF_N_8K , T.LTPF_N_16K, - T.LTPF_N_24K, T.LTPF_N_32K, T.LTPF_N_48K ] - - C_D = [ T.LTPF_D_8K , T.LTPF_D_16K, - T.LTPF_D_24K, T.LTPF_D_32K, T.LTPF_D_48K ] - - def __init__(self, dt, sr): - - super().__init__(dt, sr) - - self.C_N = LtpfSynthesis.C_N[sr] - self.C_D = LtpfSynthesis.C_D[sr] - - ns = T.NS[dt][sr] - - self.active = [ False, False ] - self.pitch_index = 0 - - max_pitch_12k8 = 228 - max_pitch = max_pitch_12k8 * T.SRATE_KHZ[self.sr] / 12.8 - max_pitch = np.ceil(max_pitch).astype(int) - - self.x = np.zeros(ns) - self.y = np.zeros(max_pitch + len(self.C_D[0])) - - self.p_e = [ 0, 0 ] - self.p_f = [ 0, 0 ] - self.c_n = [ None, None ] - self.c_d = [ None, None ] - - def load(self, b): - - self.active[0] = bool(b.read_uint(1)) - self.pitch_index = b.read_uint(9) - - def disable(self): - - self.active[0] = False - self.pitch_index = 0 - - def run(self, x, nbytes): - - sr = self.sr - dt = self.dt - - ### 3.4.9.4 Filter parameters - - pitch_index = self.pitch_index - - if pitch_index >= 440: - p_e = pitch_index - 283 - p_f = 0 - elif pitch_index >= 380: - p_e = pitch_index // 2 - 63 - p_f = 2*(pitch_index - 2*(p_e + 63)) - else: - p_e = pitch_index // 4 + 32 - p_f = pitch_index - 4*(p_e - 32) - - p = (p_e + p_f / 4) * T.SRATE_KHZ[self.sr] / 12.8 - - self.p_e[0] = int(p * 4 + 0.5) // 4 - self.p_f[0] = int(p * 4 + 0.5) - 4*self.p_e[0] - - nbits = round(nbytes*80 / T.DT_MS[dt]) - g_idx = max(nbits // 80, 3+sr) - (3+sr) - - g = [ 0.4, 0.35, 0.3, 0.25 ][g_idx] if g_idx < 4 else 0 - g_idx = min(g_idx, 3) - - self.c_n[0] = 0.85 * g * LtpfSynthesis.C_N[sr][g_idx] - self.c_d[0] = g * LtpfSynthesis.C_D[sr][self.p_f[0]] - - ### 3.4.9.2 Transition handling - - n0 = (T.SRATE_KHZ[sr] * 1000) // 400 - ns = T.NS[dt][sr] - - x = np.append(x, self.x) - y = np.append(np.zeros(ns), self.y) - yc = y.copy() - - c_n = self.c_n - c_d = self.c_d - - l_n = len(c_n[0]) - l_d = len(c_d[0]) - - d = [ self.p_e[0] - (l_d - 1) // 2, - self.p_e[1] - (l_d - 1) // 2 ] - - for k in range(n0): - - if not self.active[0] and not self.active[1]: - y[k] = x[k] - - elif self.active[0] and not self.active[1]: - u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \ - np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d))) - y[k] = x[k] - (k/n0) * u - - elif not self.active[0] and self.active[1]: - u = np.dot(c_n[1], np.take(x, k - np.arange(l_n))) - \ - np.dot(c_d[1], np.take(y, k - d[1] - np.arange(l_d))) - y[k] = x[k] - (1 - k/n0) * u - - elif self.p_e[0] == self.p_e[1] and self.p_f[0] == self.p_f[1]: - u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \ - np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d))) - y[k] = x[k] - u - - else: - u = np.dot(c_n[1], np.take(x, k - np.arange(l_n))) - \ - np.dot(c_d[1], np.take(y, k - d[1] - np.arange(l_d))) - yc[k] = x[k] - (1 - k/n0) * u - - u = np.dot(c_n[0], np.take(yc, k - np.arange(l_n))) - \ - np.dot(c_d[0], np.take(y , k - d[0] - np.arange(l_d))) - y[k] = yc[k] - (k/n0) * u - - - ### 3.4.9.3 Remainder of the frame - - for k in range(n0, ns): - - if not self.active[0]: - y[k] = x[k] - - else: - u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \ - np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d))) - y[k] = x[k] - u - - ### Sliding window - - self.active[1] = self.active[0] - self.p_e[1] = self.p_e[0] - self.p_f[1] = self.p_f[0] - self.c_n[1] = self.c_n[0] - self.c_d[1] = self.c_d[0] - - self.x = x[:ns] - self.y = np.append(self.y[ns:], y[:ns]) - - return y[:ns] - -def initial_state(): - return { 'active' : False, 'pitch': 0, 'nc': np.zeros(2), - 'hp50' : initial_hp50_state(), - 'x_12k8' : np.zeros(384), 'x_6k4' : np.zeros(178), 'tc' : 0 } - -def initial_sstate(): - return { 'active': False, 'pitch': 0, - 'c': np.zeros(2*12), 'x': np.zeros(12) } - -### ------------------------------------------------------------------------ ### - -def check_resampler(rng, dt, sr): - - ns = T.NS[dt][sr] - nt = (5 * T.SRATE_KHZ[sr]) // 4 - ok = True - - r = Resampler_12k8(dt, sr) - - hp50_c = initial_hp50_state() - x_c = np.zeros(nt) - y_c = np.zeros(384) - - for run in range(10): - - x = ((2 * rng.random(ns)) - 1) * (2 ** 15 - 1) - y = r.resample(x) - - x_c = np.append(x_c[-nt:], x.astype(np.int16)) - y_c[:-r.n] = y_c[r.n:] - y_c = lc3.ltpf_resample(dt, sr, hp50_c, x_c, y_c) - - ok = ok and np.amax(np.abs(y_c[-r.d-r.n:] - y[:r.d+r.n]/2)) < 4 - - return ok - -def check_resampler_appendix_c(dt): - - sr = T.SRATE_16K - ok = True - - nt = (5 * T.SRATE_KHZ[sr]) // 4 - n = [ 96, 128 ][dt] - k = [ 44, 24 ][dt] + n - - state = initial_hp50_state() - - x = np.append(np.zeros(nt), C.X_PCM[dt][0]) - y = np.zeros(384) - y = lc3.ltpf_resample(dt, sr, state, x, y) - u = y[-k:len(C.X_TILDE_12K8D[dt][0])-k] - - ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[dt][0]/2)) < 2 - - x = np.append(x[-nt:], C.X_PCM[dt][1]) - y[:-n] = y[n:] - y = lc3.ltpf_resample(dt, sr, state, x, y) - u = y[-k:len(C.X_TILDE_12K8D[dt][1])-k] - - ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[dt][1]/2)) < 2 - - return ok - -def check_analysis(rng, dt, sr): - - ns = T.NS[dt][sr] - nt = (5 * T.SRATE_KHZ[sr]) // 4 - ok = True - - state_c = initial_state() - x_c = np.zeros(ns+nt) - - ltpf = LtpfAnalysis(dt, sr) - - t = np.arange(100 * ns) / (T.SRATE_KHZ[sr] * 1000) - s = signal.chirp(t, f0=10, f1=3e3, t1=t[-1], method='logarithmic') - - for i in range(20): - - x = s[i*ns:(i+1)*ns] * (2 ** 15 - 1) - - pitch_present = ltpf.run(x) - data = ltpf.get_data() - - x_c = np.append(x_c[-nt:], x.astype(np.int16)) - (pitch_present_c, data_c) = lc3.ltpf_analyse(dt, sr, state_c, x_c) - - ok = ok and (not pitch_present or state_c['tc'] == ltpf.tc) - ok = ok and np.amax(np.abs(state_c['nc'][0] - ltpf.nc[0])) < 1e-2 - ok = ok and pitch_present_c == pitch_present - ok = ok and data_c['active'] == data['active'] - ok = ok and data_c['pitch_index'] == data['pitch_index'] - ok = ok and lc3.ltpf_get_nbits(pitch_present) == ltpf.get_nbits() - - return ok - -def check_synthesis(rng, dt, sr): - - ok = True - - ns = T.NS[dt][sr] - nd = 18 * T.SRATE_KHZ[sr] - - synthesis = LtpfSynthesis(dt, sr) - - state_c = initial_sstate() - x_c = np.zeros(nd+ns) - - for i in range(50): - pitch_present = bool(rng.integers(0, 10) >= 1) - if not pitch_present: - synthesis.disable() - else: - synthesis.active[0] = bool(rng.integers(0, 5) >= 1) - synthesis.pitch_index = rng.integers(0, 512) - - data_c = None if not pitch_present else \ - { 'active' : synthesis.active[0], - 'pitch_index' : synthesis.pitch_index } - - x = rng.random(ns) * 1e4 - nbytes = rng.integers(10*(2+sr), 10*(6+sr)) - - x_c[:nd] = x_c[ns:] - x_c[nd:] = x - - y = synthesis.run(x, nbytes) - x_c = lc3.ltpf_synthesize(dt, sr, nbytes, state_c, data_c, x_c) - - ok = ok and np.amax(np.abs(x_c[nd:] - y)) < 1e-2 - - return ok - -def check_analysis_appendix_c(dt): - - sr = T.SRATE_16K - nt = (5 * T.SRATE_KHZ[sr]) // 4 - ok = True - - state = initial_state() - - x = np.append(np.zeros(nt), C.X_PCM[dt][0]) - (pitch_present, data) = lc3.ltpf_analyse(dt, sr, state, x) - - ok = ok and C.T_CURR[dt][0] - state['tc'] == 17 - ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[dt][0])) < 1e-5 - ok = ok and pitch_present == C.PITCH_PRESENT[dt][0] - ok = ok and data['pitch_index'] == C.PITCH_INDEX[dt][0] - ok = ok and data['active'] == C.LTPF_ACTIVE[dt][0] - - x = np.append(x[-nt:], C.X_PCM[dt][1]) - (pitch_present, data) = lc3.ltpf_analyse(dt, sr, state, x) - - ok = ok and C.T_CURR[dt][1] - state['tc'] == 17 - ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[dt][1])) < 1e-5 - ok = ok and pitch_present == C.PITCH_PRESENT[dt][1] - ok = ok and data['pitch_index'] == C.PITCH_INDEX[dt][1] - ok = ok and data['active'] == C.LTPF_ACTIVE[dt][1] - - return ok - -def check_synthesis_appendix_c(dt): - - sr = T.SRATE_16K - ok = True - - if dt != T.DT_10M: - return ok - - ns = T.NS[dt][sr] - nd = 18 * T.SRATE_KHZ[sr] - - NBYTES = [ C.LTPF_C2_NBITS // 8, C.LTPF_C3_NBITS // 8, - C.LTPF_C4_NBITS // 8, C.LTPF_C5_NBITS // 8 ] - - ACTIVE = [ C.LTPF_C2_ACTIVE, C.LTPF_C3_ACTIVE, - C.LTPF_C4_ACTIVE, C.LTPF_C5_ACTIVE ] - - PITCH_INDEX = [ C.LTPF_C2_PITCH_INDEX, C.LTPF_C3_PITCH_INDEX, - C.LTPF_C4_PITCH_INDEX, C.LTPF_C5_PITCH_INDEX ] - - X = [ C.LTPF_C2_X, C.LTPF_C3_X, - C.LTPF_C4_X, C.LTPF_C5_X ] - - PREV = [ C.LTPF_C2_PREV, C.LTPF_C3_PREV, - C.LTPF_C4_PREV, C.LTPF_C5_PREV ] - - TRANS = [ C.LTPF_C2_TRANS, C.LTPF_C3_TRANS, - C.LTPF_C4_TRANS, C.LTPF_C5_TRANS ] - - for i in range(4): - - state = initial_sstate() - nbytes = NBYTES[i] - - data = { 'active' : ACTIVE[i][0], 'pitch_index' : PITCH_INDEX[i][0] } - x = np.append(np.zeros(nd), X[i][0]) - - lc3.ltpf_synthesize(dt, sr, nbytes, state, data, x) - - data = { 'active' : ACTIVE[i][1], 'pitch_index' : PITCH_INDEX[i][1] } - x[ :nd-ns] = PREV[i][0][-nd+ns:] - x[nd-ns:nd] = PREV[i][1] - x[nd:nd+ns] = X[i][1] - - y = lc3.ltpf_synthesize(dt, sr, nbytes, state, data, x)[nd:] - - ok = ok and np.amax(np.abs(y - TRANS[i])) < 1e-3 - - return ok - -def check(): - - rng = np.random.default_rng(1234) - ok = True - - for dt in range(T.NUM_DT): - for sr in range(T.NUM_SRATE): - ok = ok and check_resampler(rng, dt, sr) - ok = ok and check_analysis(rng, dt, sr) - ok = ok and check_synthesis(rng, dt, sr) - - for dt in range(T.NUM_DT): - ok = ok and check_resampler_appendix_c(dt) - ok = ok and check_analysis_appendix_c(dt) - ok = ok and check_synthesis_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/ltpf_py.c b/system/embdrv/lc3/test/ltpf_py.c deleted file mode 100644 index c51eadd6955d878269200f8af0217b3e8496eb34..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/ltpf_py.c +++ /dev/null @@ -1,138 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 -#include - -#include -#include "ctypes.h" - -static PyObject *resample_py(PyObject *m, PyObject *args) -{ - unsigned dt, sr; - PyObject *hp50_obj, *x_obj, *y_obj; - struct lc3_ltpf_hp50_state hp50; - int16_t *x, *y; - - if (!PyArg_ParseTuple(args, "IIOOO", &dt, &sr, &hp50_obj, &x_obj, &y_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - CTYPES_CHECK(NULL, hp50_obj = to_ltpf_hp50_state(hp50_obj, &hp50)); - - int ns = LC3_NS(dt, sr), nt = LC3_NT(dt); - int ny = sizeof((struct lc3_ltpf_analysis){ }.x_12k8) / sizeof(int16_t); - int n = dt == LC3_DT_7M5 ? 96 : 128; - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_INT16, ns+nt, &x)); - CTYPES_CHECK("y", y_obj = to_1d_ptr(y_obj, NPY_INT16, ny, &y)); - - resample_12k8[sr](&hp50, x + nt, y + (ny - n), n); - - from_ltpf_hp50_state(hp50_obj, &hp50); - return Py_BuildValue("O", y_obj); -} - -static PyObject *analyse_py(PyObject *m, PyObject *args) -{ - PyObject *ltpf_obj, *x_obj; - unsigned dt, sr; - struct lc3_ltpf_analysis ltpf; - struct lc3_ltpf_data data = { 0 }; - int16_t *x; - - if (!PyArg_ParseTuple(args, "IIOO", &dt, &sr, <pf_obj, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", dt < LC3_NUM_DT); - CTYPES_CHECK("sr", sr < LC3_NUM_SRATE); - CTYPES_CHECK(NULL, ltpf_obj = to_ltpf_analysis(ltpf_obj, <pf)); - - int ns = LC3_NS(dt, sr), nt = LC3_NT(sr); - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_INT16, ns+nt, &x)); - - int pitch_present = - lc3_ltpf_analyse(dt, sr, <pf, x + nt, &data); - - from_ltpf_analysis(ltpf_obj, <pf); - return Py_BuildValue("iN", pitch_present, new_ltpf_data(&data)); -} - -static PyObject *synthesize_py(PyObject *m, PyObject *args) -{ - PyObject *ltpf_obj, *data_obj, *x_obj; - struct lc3_ltpf_synthesis ltpf; - struct lc3_ltpf_data data; - bool pitch_present; - unsigned dt, sr; - int nbytes; - float *x; - - if (!PyArg_ParseTuple(args, "IIiOOO", - &dt, &sr, &nbytes, <pf_obj, &data_obj, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", dt < LC3_NUM_DT); - CTYPES_CHECK("sr", sr < LC3_NUM_SRATE); - CTYPES_CHECK("nbytes", nbytes >= 20 && nbytes <= 400); - CTYPES_CHECK(NULL, ltpf_obj = to_ltpf_synthesis(ltpf_obj, <pf)); - - if ((pitch_present = (data_obj != Py_None))) - CTYPES_CHECK(NULL, data_obj = to_ltpf_data(data_obj, &data)); - - int ns = LC3_NS(dt,sr), nd = 18 * LC3_SRATE_KHZ(sr); - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, nd+ns, &x)); - - lc3_ltpf_synthesize(dt, sr, nbytes, - <pf, pitch_present ? &data : NULL, x, x + nd); - - from_ltpf_synthesis(ltpf_obj, <pf); - return Py_BuildValue("O", x_obj); -} - -static PyObject *get_nbits_py(PyObject *m, PyObject *args) -{ - int pitch_present; - - if (!PyArg_ParseTuple(args, "i", &pitch_present)) - return NULL; - - int nbits = lc3_ltpf_get_nbits(pitch_present); - - return Py_BuildValue("i", nbits); -} - -static PyMethodDef methods[] = { - { "ltpf_resample" , resample_py , METH_VARARGS }, - { "ltpf_analyse" , analyse_py , METH_VARARGS }, - { "ltpf_synthesize", synthesize_py, METH_VARARGS }, - { "ltpf_get_nbits" , get_nbits_py , METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_ltpf_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/test/mdct.py b/system/embdrv/lc3/test/mdct.py deleted file mode 100644 index aafba3fa307b23ca1329bb56b5369bf6853e6227..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/mdct.py +++ /dev/null @@ -1,198 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np -import scipy.fft - -import build.lc3 as lc3 -import tables as T, appendix_c as C - -### ------------------------------------------------------------------------ ### - -class Mdct: - - W = [ [ T.W_7M5_60, T.W_7M5_120, T.W_7M5_180, T.W_7M5_240, T.W_7M5_360 ], - [ T.W_10M_80, T.W_10M_160, T.W_10M_240, T.W_10M_320, T.W_10M_480 ] ] - - def __init__(self, dt, sr): - - self.ns = T.NS[dt][sr] - self.nd = T.ND[dt][sr] - - self.t = np.zeros(2*self.ns) - self.w = Mdct.W[dt][sr] - - -class MdctForward(Mdct): - - def __init__(self, dt, sr): - - super().__init__(dt, sr) - - def run(self, x): - - ns = self.ns - nd = self.nd - - self.t[nd:nd+ns] = x - t = self.t * self.w - self.t[0:nd] = x[ns-nd:] - - n = len(t) - n2 = n // 2 - - z = t * np.exp(-2j * np.pi * np.arange(n) / (2*n)) - z = scipy.fft.fft(z)[:n2] - z = z * np.exp(-2j * np.pi * - (n2/2 + 0.5) * (np.arange(n2) + 0.5) / (2 * n2)) - return np.real(z) * np.sqrt(2/n2) - - -class MdctInverse(Mdct): - - def __init__(self, dt, sr): - - super().__init__(dt, sr) - - def run(self, x): - - ns = self.ns - nd = self.nd - - n = len(x) - - x = np.append(x, -x[::-1]) - z = x * np.exp(2j * np.pi * (n/2 + 0.5) * np.arange(2*n) / (2*n)) - z = scipy.fft.ifft(z) * n - z = z * np.exp(2j * np.pi * (np.arange(2*n) + (n/2 + 0.5)) / (4*n)) - t = np.real(z) * np.sqrt(2/n) - - t = t * self.w[::-1] - - y = np.empty(ns) - y[:nd] = t[ns-nd:ns] + self.t[2*ns-nd:] - y[nd:] = t[ns:2*ns-nd] - self.t = t - - return y - -### ------------------------------------------------------------------------ ### - -def check_forward_unit(rng, dt, sr): - - ns = T.NS[dt][sr] - nd = T.ND[dt][sr] - ok = True - - x = (2 * rng.random(ns)) - 1 - - y = [ None ] * 2 - y_c = [ None ] * 2 - - mdct = MdctForward(dt, sr) - y[0] = mdct.run(x) - y[1] = mdct.run(x) - - (y_c[0], d_c) = lc3.mdct_forward(dt, sr, x, np.zeros(nd)) - y_c[1] = lc3.mdct_forward(dt, sr, x, d_c)[0] - - ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5 - ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5 - - return ok - - -def check_forward_appendix_c(dt): - - sr = T.SRATE_16K - ns = T.NS[dt][sr] - nd = T.ND[dt][sr] - ok = True - - (y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[dt][0], np.zeros(nd)) - ok = ok and np.amax(np.abs(y - C.X[dt][0])) < 1e-1 - - (y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[dt][1], d) - ok = ok and np.amax(np.abs(y - C.X[dt][1])) < 1e-1 - - return ok - - -def check_inverse_unit(rng, dt, sr): - - ns = T.NS[dt][sr] - nd = [ (23 * ns) // 30, (5 * ns) // 8 ][dt] - ok = True - - x = (2 * rng.random(ns)) - 1 - - y = [ None ] * 2 - y_c = [ None ] * 2 - - mdct = MdctInverse(dt, sr) - y[0] = mdct.run(x) - y[1] = mdct.run(x) - - (y_c[0], d_c) = lc3.mdct_inverse(dt, sr, x, np.zeros(nd)) - y_c[1] = lc3.mdct_inverse(dt, sr, x, d_c)[0] - - ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5 - ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5 - - return ok - - -def check_inverse_appendix_c(dt): - - sr = T.SRATE_16K - ns = T.NS[dt][sr] - nd = [ (23 * ns) // 30, (5 * ns) // 8 ][dt] - ok = True - - (y, d0) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[dt][0], np.zeros(nd)) - yr = C.T_HAT_MDCT[dt][0][ns-nd:2*ns-nd] - dr = C.T_HAT_MDCT[dt][0][2*ns-nd:] - - ok = ok and np.amax(np.abs(yr - y )) < 1e-1 - ok = ok and np.amax(np.abs(dr - d0)) < 1e-1 - - (y, d1) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[dt][1], d0) - yr[ :nd] = C.T_HAT_MDCT[dt][1][ns-nd:ns] + d0 - yr[nd:ns] = C.T_HAT_MDCT[dt][1][ns:2*ns-nd] - dr = C.T_HAT_MDCT[dt][1][2*ns-nd:] - - ok = ok and np.amax(np.abs(yr - y )) < 1e-1 - ok = ok and np.amax(np.abs(dr - d1)) < 1e-1 - - return ok - - -def check(): - - rng = np.random.default_rng(1234) - - ok = True - - for dt in range(T.NUM_DT): - for sr in range(T.NUM_SRATE): - ok = ok and check_forward_unit(rng, dt, sr) - ok = ok and check_inverse_unit(rng, dt, sr) - - for dt in range(T.NUM_DT): - ok = ok and check_forward_appendix_c(dt) - ok = ok and check_inverse_appendix_c(dt) - - return ok diff --git a/system/embdrv/lc3/test/mdct_py.c b/system/embdrv/lc3/test/mdct_py.c deleted file mode 100644 index 3479503005645d908fb80d7062a55c44b735103b..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/mdct_py.c +++ /dev/null @@ -1,93 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 -#include - -#include -#include "ctypes.h" - - -static PyObject *mdct_forward_py(PyObject *m, PyObject *args) -{ - PyObject *x_obj, *xd_obj, *y_obj, *d_obj; - enum lc3_dt dt; - enum lc3_srate sr; - float *x, *xd, *y, *d; - - if (!PyArg_ParseTuple(args, "iiOO", &dt, &sr, &x_obj, &xd_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int ns = LC3_NS(dt, sr), nd = LC3_ND(dt, sr); - - CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, ns, &x)); - CTYPES_CHECK("xd", to_1d_ptr(xd_obj, NPY_FLOAT, nd, &xd)); - d_obj = new_1d_ptr(NPY_FLOAT, nd, &d); - y_obj = new_1d_ptr(NPY_FLOAT, ns, &y); - - memcpy(d, xd, nd * sizeof(float)); - - lc3_mdct_forward(dt, sr, sr, x, d, y); - - return Py_BuildValue("NN", y_obj, d_obj); -} - -static PyObject *mdct_inverse_py(PyObject *m, PyObject *args) -{ - PyObject *x_obj, *xd_obj, *d_obj, *y_obj; - enum lc3_dt dt; - enum lc3_srate sr; - float *x, *xd, *d, *y; - - if (!PyArg_ParseTuple(args, "iiOO", &dt, &sr, &x_obj, &xd_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int ns = LC3_NS(dt, sr), nd = LC3_ND(dt, sr); - - CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, ns, &x)); - CTYPES_CHECK("xd", to_1d_ptr(xd_obj, NPY_FLOAT, nd, &xd)); - d_obj = new_1d_ptr(NPY_FLOAT, nd, &d); - y_obj = new_1d_ptr(NPY_FLOAT, ns, &y); - - memcpy(d, xd, nd * sizeof(float)); - - lc3_mdct_inverse(dt, sr, sr, x, d, y); - - return Py_BuildValue("NN", y_obj, d_obj); -} - -static PyMethodDef methods[] = { - { "mdct_forward", mdct_forward_py, METH_VARARGS }, - { "mdct_inverse", mdct_inverse_py, METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_mdct_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/test/module_py.c b/system/embdrv/lc3/test/module_py.c deleted file mode 100644 index 6163a9c72b04c7d6c4097bec6d18fa0ef58543ed..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/module_py.c +++ /dev/null @@ -1,53 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 - -static struct PyModuleDef module_def = { - PyModuleDef_HEAD_INIT, - .m_name = "LC3", - .m_doc = "LC3 Test Python Module", - .m_size = -1, -}; - -PyMODINIT_FUNC lc3_mdct_py_init(PyObject *); -PyMODINIT_FUNC lc3_energy_py_init(PyObject *); -PyMODINIT_FUNC lc3_attdet_py_init(PyObject *); -PyMODINIT_FUNC lc3_bwdet_py_init(PyObject *); -PyMODINIT_FUNC lc3_ltpf_py_init(PyObject *); -PyMODINIT_FUNC lc3_sns_py_init(PyObject *); -PyMODINIT_FUNC lc3_tns_py_init(PyObject *); -PyMODINIT_FUNC lc3_spec_py_init(PyObject *); -PyMODINIT_FUNC lc3_interface_py_init(PyObject *); - -PyMODINIT_FUNC PyInit_lc3(void) -{ - PyObject *m = PyModule_Create(&module_def); - - if (m) m = lc3_mdct_py_init(m); - if (m) m = lc3_energy_py_init(m); - if (m) m = lc3_attdet_py_init(m); - if (m) m = lc3_bwdet_py_init(m); - if (m) m = lc3_ltpf_py_init(m); - if (m) m = lc3_sns_py_init(m); - if (m) m = lc3_tns_py_init(m); - if (m) m = lc3_spec_py_init(m); - if (m) m = lc3_interface_py_init(m); - - return m; -} diff --git a/system/embdrv/lc3/test/neon/ltpf_neon.c b/system/embdrv/lc3/test/neon/ltpf_neon.c deleted file mode 100644 index 0577bd135bf0f429fa5ab708181403003d43db8a..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/neon/ltpf_neon.c +++ /dev/null @@ -1,116 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "neon.h" - -#include -#include -#include - -/* -------------------------------------------------------------------------- */ - -#define TEST_NEON -#include - -void lc3_put_bits_generic(lc3_bits_t *a, unsigned b, int c) -{ (void)a, (void)b, (void)c; } - -unsigned lc3_get_bits_generic(struct lc3_bits *a, int b) -{ return (void)a, (void)b, 0; } - -/* -------------------------------------------------------------------------- */ - -static int check_resampler() -{ - int16_t __x[60+480], *x = __x + 60; - for (int i = -60; i < 480; i++) - x[i] = rand() & 0xffff; - - struct lc3_ltpf_hp50_state hp50 = { 0 }, hp50_neon = { 0 }; - int16_t y[128], y_neon[128]; - - resample_16k_12k8(&hp50, x, y, 128); - neon_resample_16k_12k8(&hp50_neon, x, y_neon, 128); - if (memcmp(y, y_neon, 128 * sizeof(*y)) != 0) - return printf("Error\n"), -1; - - resample_32k_12k8(&hp50, x, y, 128); - neon_resample_32k_12k8(&hp50_neon, x, y_neon, 128); - if (memcmp(y, y_neon, 128 * sizeof(*y)) != 0) - return printf("Error\n"), -1; - - resample_48k_12k8(&hp50, x, y, 128); - neon_resample_48k_12k8(&hp50_neon, x, y_neon, 128); - if (memcmp(y, y_neon, 128 * sizeof(*y)) != 0) - return -1; - - return 0; -} - -static int check_dot() -{ - int16_t x[200]; - for (int i = 0; i < 200; i++) - x[i] = rand() & 0xffff; - - float y = dot(x, x+3, 128); - float y_neon = neon_dot(x, x+3, 128); - if (y != y_neon) - return -1; - - return 0; -} - -static int check_correlate() -{ - int16_t alignas(4) a[500], b[500]; - float y[100], y_neon[100]; - - for (int i = 0; i < 500; i++) { - a[i] = rand() & 0xffff; - b[i] = rand() & 0xffff; - } - - correlate(a, b+200, 128, y, 100); - neon_correlate(a, b+200, 128, y_neon, 100); - if (memcmp(y, y_neon, 100 * sizeof(*y)) != 0) - return -1; - - correlate(a, b+199, 128, y, 99); - neon_correlate(a, b+199, 128, y_neon, 99); - if (memcmp(y, y_neon, 99 * sizeof(*y)) != 0) - return -1; - - return 0; -} - -int check_ltpf(void) -{ - int ret; - - if ((ret = check_resampler()) < 0) - return ret; - - if ((ret = check_dot()) < 0) - return ret; - - if ((ret = check_correlate()) < 0) - return ret; - - return 0; -} diff --git a/system/embdrv/lc3/test/neon/mdct_neon.c b/system/embdrv/lc3/test/neon/mdct_neon.c deleted file mode 100644 index d5f3888755bc2e16a2da27fea526c09d436b8733..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/neon/mdct_neon.c +++ /dev/null @@ -1,74 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "neon.h" - -#include -#include -#include - -/* -------------------------------------------------------------------------- */ - -#define TEST_NEON -#include - -/* -------------------------------------------------------------------------- */ - -static int check_fft(void) -{ - struct lc3_complex x[240]; - struct lc3_complex y[240], y_neon[240]; - - for (int i = 0; i < 240; i++) { - x[i].re = (double)rand() / RAND_MAX; - x[i].im = (double)rand() / RAND_MAX; - } - - fft_5(x, y, 240/5); - neon_fft_5(x, y_neon, 240/5); - for (int i = 0; i < 240; i++) - if (fabsf(y[i].re - y_neon[i].re) > 1e-6f || - fabsf(y[i].im - y_neon[i].im) > 1e-6f ) - return -1; - - fft_bf3(lc3_fft_twiddles_bf3[0], x, y, 240/15); - neon_fft_bf3(lc3_fft_twiddles_bf3[0], x, y_neon, 240/15); - for (int i = 0; i < 240; i++) - if (fabsf(y[i].re - y_neon[i].re) > 1e-6f || - fabsf(y[i].im - y_neon[i].im) > 1e-6f ) - return -1; - - fft_bf2(lc3_fft_twiddles_bf2[0][1], x, y, 240/30); - neon_fft_bf2(lc3_fft_twiddles_bf2[0][1], x, y_neon, 240/30); - for (int i = 0; i < 240; i++) - if (fabsf(y[i].re - y_neon[i].re) > 1e-6f || - fabsf(y[i].im - y_neon[i].im) > 1e-6f ) - return -1; - - return 0; -} - -int check_mdct(void) -{ - int ret; - - if ((ret = check_fft()) < 0) - return ret; - - return 0; -} diff --git a/system/embdrv/lc3/test/neon/neon.h b/system/embdrv/lc3/test/neon/neon.h deleted file mode 100644 index acd2392893d10ebbbfd642c3296fb247350015d8..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/neon/neon.h +++ /dev/null @@ -1,330 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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. - * - ******************************************************************************/ - -#if __ARM_NEON - -#include - -#else -#define __ARM_NEON 1 - -#include - - -/* ---------------------------------------------------------------------------- - * Integer - * -------------------------------------------------------------------------- */ - -typedef struct { int16_t e[4]; } int16x4_t; - -typedef struct { int16_t e[8]; } int16x8_t; -typedef struct { int32_t e[4]; } int32x4_t; -typedef struct { int64_t e[2]; } int64x2_t; - - -/** - * Load / Store - */ - -__attribute__((unused)) -static int16x4_t vld1_s16(const int16_t *p) -{ - return (int16x4_t){ { p[0], p[1], p[2], p[3] } }; -} - - -/** - * Arithmetic - */ - -__attribute__((unused)) -static int32x4_t vmull_s16(int16x4_t a, int16x4_t b) -{ - return (int32x4_t){ { a.e[0] * b.e[0], a.e[1] * b.e[1], - a.e[2] * b.e[2], a.e[3] * b.e[3] } }; -} - -__attribute__((unused)) -static int32x4_t vmlal_s16(int32x4_t r, int16x4_t a, int16x4_t b) -{ - return (int32x4_t){ { - r.e[0] + a.e[0] * b.e[0], r.e[1] + a.e[1] * b.e[1], - r.e[2] + a.e[2] * b.e[2], r.e[3] + a.e[3] * b.e[3] } }; -} - -__attribute__((unused)) -static int64x2_t vpadalq_s32(int64x2_t a, int32x4_t b) -{ - int64x2_t r; - - r.e[0] = a.e[0] + ((int64_t)b.e[0] + b.e[1]); - r.e[1] = a.e[1] + ((int64_t)b.e[2] + b.e[3]); - - return r; -} - - -/** - * Reduce - */ - -__attribute__((unused)) -static int32_t vaddvq_s32(int32x4_t v) -{ - return v.e[0] + v.e[1] + v.e[2] + v.e[3]; -} - -__attribute__((unused)) -static int64_t vaddvq_s64(int64x2_t v) -{ - return v.e[0] + v.e[1]; -} - - -/** - * Manipulation - */ - -__attribute__((unused)) -static int16x4_t vext_s16(int16x4_t a, int16x4_t b, const int n) -{ - int16_t x[] = { a.e[0], a.e[1], a.e[2], a.e[3], - b.e[0], b.e[1], b.e[2], b.e[3] }; - - return (int16x4_t){ { x[n], x[n+1], x[n+2], x[n+3] } }; -} - -__attribute__((unused)) -static int32x4_t vmovq_n_s32(uint32_t v) -{ - return (int32x4_t){ { v, v, v, v } }; -} - -__attribute__((unused)) -static int64x2_t vmovq_n_s64(int64_t v) -{ - return (int64x2_t){ { v, v, } }; -} - - - -/* ---------------------------------------------------------------------------- - * Floating Point - * -------------------------------------------------------------------------- */ - -typedef struct { float e[2]; } float32x2_t; -typedef struct { float e[4]; } float32x4_t; - -typedef struct { float32x2_t val[2]; } float32x2x2_t; -typedef struct { float32x4_t val[2]; } float32x4x2_t; - - -/** - * Load / Store - */ - -__attribute__((unused)) -static float32x2_t vld1_f32(const float *p) -{ - return (float32x2_t){ { p[0], p[1] } }; -} - -__attribute__((unused)) -static float32x4_t vld1q_f32(const float *p) -{ - return (float32x4_t){ { p[0], p[1], p[2], p[3] } }; -} - -__attribute__((unused)) -static float32x4_t vld1q_dup_f32(const float *p) -{ - return (float32x4_t){ { p[0], p[0], p[0], p[0] } }; -} - -__attribute__((unused)) -static float32x2x2_t vld2_f32(const float *p) -{ - return (float32x2x2_t){ .val[0] = { { p[0], p[2] } }, - .val[1] = { { p[1], p[3] } } }; -} - -__attribute__((unused)) -static float32x4x2_t vld2q_f32(const float *p) -{ - return (float32x4x2_t){ .val[0] = { { p[0], p[2], p[4], p[6] } }, - .val[1] = { { p[1], p[3], p[5], p[7] } } }; -} - -__attribute__((unused)) -static void vst1_f32(float *p, float32x2_t v) -{ - p[0] = v.e[0], p[1] = v.e[1]; -} - -__attribute__((unused)) -static void vst1q_f32(float *p, float32x4_t v) -{ - p[0] = v.e[0], p[1] = v.e[1], p[2] = v.e[2], p[3] = v.e[3]; -} - -/** - * Arithmetic - */ - -__attribute__((unused)) -static float32x2_t vneg_f32(float32x2_t a) -{ - return (float32x2_t){ { -a.e[0], -a.e[1] } }; -} - -__attribute__((unused)) -static float32x4_t vnegq_f32(float32x4_t a) -{ - return (float32x4_t){ { -a.e[0], -a.e[1], -a.e[2], -a.e[3] } }; -} - -__attribute__((unused)) -static float32x4_t vaddq_f32(float32x4_t a, float32x4_t b) -{ - return (float32x4_t){ { a.e[0] + b.e[0], a.e[1] + b.e[1], - a.e[2] + b.e[2], a.e[3] + b.e[3] } }; -} - -__attribute__((unused)) -static float32x4_t vsubq_f32(float32x4_t a, float32x4_t b) -{ - return (float32x4_t){ { a.e[0] - b.e[0], a.e[1] - b.e[1], - a.e[2] - b.e[2], a.e[3] - b.e[3] } }; -} - -__attribute__((unused)) -static float32x2_t vfma_f32(float32x2_t a, float32x2_t b, float32x2_t c) -{ - return (float32x2_t){ { - a.e[0] + b.e[0] * c.e[0], a.e[1] + b.e[1] * c.e[1] } }; -} - -__attribute__((unused)) -static float32x4_t vfmaq_f32(float32x4_t a, float32x4_t b, float32x4_t c) -{ - return (float32x4_t){ { - a.e[0] + b.e[0] * c.e[0], a.e[1] + b.e[1] * c.e[1], - a.e[2] + b.e[2] * c.e[2], a.e[3] + b.e[3] * c.e[3] } }; -} - -__attribute__((unused)) -static float32x2_t vfms_f32(float32x2_t a, float32x2_t b, float32x2_t c) -{ - return (float32x2_t){ { - a.e[0] - b.e[0] * c.e[0], a.e[1] - b.e[1] * c.e[1] } }; -} - -__attribute__((unused)) -static float32x4_t vfmsq_f32(float32x4_t a, float32x4_t b, float32x4_t c) -{ - return (float32x4_t){ { - a.e[0] - b.e[0] * c.e[0], a.e[1] - b.e[1] * c.e[1], - a.e[2] - b.e[2] * c.e[2], a.e[3] - b.e[3] * c.e[3] } }; -} - - -/** - * Manipulation - */ - -__attribute__((unused)) -static float32x2_t vcreate_f32(uint64_t u) -{ - float *f = (float *)&u; - return (float32x2_t){ { f[0] , f[1] } }; -} - -__attribute__((unused)) -static float32x4_t vcombine_f32(float32x2_t a, float32x2_t b) -{ - return (float32x4_t){ { a.e[0], a.e[1], b.e[0], b.e[1] } }; -} - -__attribute__((unused)) -static float32x2_t vget_low_f32(float32x4_t a) -{ - return (float32x2_t){ { a.e[0], a.e[1] } }; -} - -__attribute__((unused)) -static float32x2_t vget_high_f32(float32x4_t a) -{ - return (float32x2_t){ { a.e[2], a.e[3] } }; -} - -__attribute__((unused)) -static float32x4_t vmovq_n_f32(float v) -{ - return (float32x4_t){ { v, v, v, v } }; -} - -__attribute__((unused)) -static float32x2_t vrev64_f32(float32x2_t v) -{ - return (float32x2_t){ { v.e[1], v.e[0] } }; -} - -__attribute__((unused)) -static float32x4_t vrev64q_f32(float32x4_t v) -{ - return (float32x4_t){ { v.e[1], v.e[0], v.e[3], v.e[2] } }; -} - -__attribute__((unused)) -static float32x2_t vtrn1_f32(float32x2_t a, float32x2_t b) -{ - return (float32x2_t){ { a.e[0], b.e[0] } }; -} - -__attribute__((unused)) -static float32x2_t vtrn2_f32(float32x2_t a, float32x2_t b) -{ - return (float32x2_t){ { a.e[1], b.e[1] } }; -} - -__attribute__((unused)) -static float32x4_t vtrn1q_f32(float32x4_t a, float32x4_t b) -{ - return (float32x4_t){ { a.e[0], b.e[0], a.e[2], b.e[2] } }; -} - -__attribute__((unused)) -static float32x4_t vtrn2q_f32(float32x4_t a, float32x4_t b) -{ - return (float32x4_t){ { a.e[1], b.e[1], a.e[3], b.e[3] } }; -} - -__attribute__((unused)) -static float32x4_t vzip1q_f32(float32x4_t a, float32x4_t b) -{ - return (float32x4_t){ { a.e[0], b.e[0], a.e[1], b.e[1] } }; -} - -__attribute__((unused)) -static float32x4_t vzip2q_f32(float32x4_t a, float32x4_t b) -{ - return (float32x4_t){ { a.e[2], b.e[2], a.e[3], b.e[3] } }; -} - - -#endif /* __ARM_NEON */ diff --git a/system/embdrv/lc3/test/neon/test_neon.c b/system/embdrv/lc3/test/neon/test_neon.c deleted file mode 100644 index 50622c71a6168f15e32137a1a8f7715d91dc2f2a..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/neon/test_neon.c +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 - -int check_ltpf(void); -int check_mdct(void); - -int main() -{ - int r, ret = 0; - - printf("Checking LTPF Neon... "); fflush(stdout); - printf("%s\n", (r = check_ltpf()) == 0 ? "OK" : "Failed"); - ret = ret || r; - - printf("Checking MDCT Neon... "); fflush(stdout); - printf("%s\n", (r = check_mdct()) == 0 ? "OK" : "Failed"); - ret = ret || r; - - return ret; -} diff --git a/system/embdrv/lc3/test/run.py b/system/embdrv/lc3/test/run.py deleted file mode 100755 index 4b61f7a8f5bf906668a92b264267a4254d74b6b0..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/run.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import mdct, energy, bwdet, attdet -import ltpf, sns, tns, spec, encoder, decoder - -ok = True - -for m in [ ( mdct , "MDCT" ), - ( energy , "Energy Band" ), - ( bwdet , "Bandwidth Detector" ), - ( attdet , "Attack Detector" ), - ( ltpf , "Long Term Postfilter" ), - ( sns , "Spectral Noise Shaping" ), - ( tns , "Temporal Noise Shaping" ), - ( spec , "Spectral Quantization" ), - ( encoder , "Encoder" ), - ( decoder , "Decoder" ) ]: - - print('[{:^6}] {:}'.format('...', m[1]), end='\r', flush=True) - ret = m[0].check() - print('[{:^6}] {:}'.format('OK' if ret else 'FAILED', m[1])) - - ok = ok and ret - -exit(0 if ok else 1); diff --git a/system/embdrv/lc3/test/setup.py b/system/embdrv/lc3/test/setup.py deleted file mode 100755 index 8e1289151367d3018eb7a884f5dc34e61af1aaa2..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/setup.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from distutils.core import setup, Extension -import os, sys, glob - -if len(sys.argv) <= 1: - sys.argv = sys.argv + [ - 'build', '--build-base', os.getcwd() + os.sep + 'build', - 'install', '--install-lib', os.getcwd() + os.sep + 'build' ] - -INC_DIR = '..' + os.sep + 'include' -SRC_DIR = '..' + os.sep + 'src' - -sources = glob.glob('*_py.c') + \ - [ SRC_DIR + os.sep + 'tables.c', - SRC_DIR + os.sep + 'bits.c', - SRC_DIR + os.sep + 'plc.c' ] - -depends = [ 'ctypes.h' ] + \ - glob.glob(INC_DIR + os.sep + '*.h') + \ - glob.glob(SRC_DIR + os.sep + '*.[c,h]') - -includes = [ SRC_DIR, INC_DIR ] - -ctiming = Extension('lc3', - extra_compile_args = ['-std=c11'], - define_macros = [ ('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION') ], - sources = sources, - depends = depends, - include_dirs = includes) - -setup(name = 'LC3', - version = '1.0', - description = 'LC3 Test Python Module', - ext_modules = [ctiming]) diff --git a/system/embdrv/lc3/test/sns.py b/system/embdrv/lc3/test/sns.py deleted file mode 100644 index 897ed793ee1aa669a0f79976c5e2c0462a3c423e..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/sns.py +++ /dev/null @@ -1,594 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np -import scipy.fftpack as fftpack - -import build.lc3 as lc3 -import tables as T, appendix_c as C - -### ------------------------------------------------------------------------ ### - -class Sns: - - def __init__(self, dt, sr): - - self.dt = dt - self.sr = sr - - (self.ind_lf, self.ind_hf, self.shape, self.gain) = \ - (None, None, None, None) - - (self.idx_a, self.ls_a, self.idx_b, self.ls_b) = \ - (None, None, None, None) - - def get_data(self): - - data = { 'lfcb' : self.ind_lf, 'hfcb' : self.ind_hf, - 'shape' : self.shape, 'gain' : self.gain, - 'idx_a' : self.idx_a, 'ls_a' : self.ls_a } - - if self.idx_b is not None: - data.update({ 'idx_b' : self.idx_b, 'ls_b' : self.ls_b }) - - return data - - def get_nbits(self): - - return 38 - - def spectral_shaping(self, scf, inv, x): - - ## 3.3.7.4 Scale factors interpolation - - scf_i = np.empty(4*len(scf)) - scf_i[0 ] = scf[0] - scf_i[1 ] = scf[0] - scf_i[2:62:4] = scf[:15] + 1/8 * (scf[1:] - scf[:15]) - scf_i[3:63:4] = scf[:15] + 3/8 * (scf[1:] - scf[:15]) - scf_i[4:64:4] = scf[:15] + 5/8 * (scf[1:] - scf[:15]) - scf_i[5:64:4] = scf[:15] + 7/8 * (scf[1:] - scf[:15]) - scf_i[62 ] = scf[15 ] + 1/8 * (scf[15] - scf[14 ]) - scf_i[63 ] = scf[15 ] + 3/8 * (scf[15] - scf[14 ]) - - n2 = 64 - min(len(x), 64) - - for i in range(n2): - scf_i[i] = 0.5 * (scf_i[2*i] + scf_i[2*i+1]) - scf_i = np.append(scf_i[:n2], scf_i[2*n2:]) - - g_sns = np.power(2, [ -scf_i, scf_i ][inv]) - - ## 3.3.7.4 Spectral shaping - - y = np.empty(len(x)) - I = T.I[self.dt][self.sr] - - for b in range(len(g_sns)): - y[I[b]:I[b+1]] = x[I[b]:I[b+1]] * g_sns[b] - - return y - - -class SnsAnalysis(Sns): - - def __init__(self, dt, sr): - - super().__init__(dt, sr) - - def compute_scale_factors(self, e, att): - - dt = self.dt - - ## 3.3.7.2.1 Padding - - n2 = 64 - len(e) - - e = np.append(np.empty(n2), e) - for i in range(n2): - e[2*i+0] = e[2*i+1] = e[n2+i] - - ## 3.3.7.2.2 Smoothing - - e_s = np.zeros(len(e)) - e_s[0 ] = 0.75 * e[0 ] + 0.25 * e[1 ] - e_s[1:63] = 0.25 * e[0:62] + 0.5 * e[1:63] + 0.25 * e[2:64] - e_s[ 63] = 0.25 * e[ 62] + 0.75 * e[ 63] - - ## 3.3.7.2.3 Pre-emphasis - - g_tilt = [ 14, 18, 22, 26, 30 ][self.sr] - e_p = e_s * (10 ** ((np.arange(64) * g_tilt) / 630)) - - ## 3.3.7.2.4 Noise floor - - noise_floor = max(np.average(e_p) * (10 ** (-40/10)), 2 ** -32) - e_p = np.fmax(e_p, noise_floor * np.ones(len(e))) - - ## 3.3.7.2.5 Logarithm - - e_l = np.log2(10 ** -31 + e_p) / 2 - - ## 3.3.7.2.6 Band energy grouping - - w = [ 1/12, 2/12, 3/12, 3/12, 2/12, 1/12 ] - - e_4 = np.zeros(len(e_l) // 4) - e_4[0 ] = w[0] * e_l[0] + np.sum(w[1:] * e_l[:5]) - e_4[1:15] = [ np.sum(w * e_l[4*i-1:4*i+5]) for i in range(1, 15) ] - e_4[ 15] = np.sum(w[:5] * e_l[59:64]) + w[5] * e_l[63] - - ## 3.3.7.2.7 Mean removal and scaling, attack handling - - scf = 0.85 * (e_4 - np.average(e_4)) - - scf_a = np.zeros(len(scf)) - scf_a[0 ] = np.average(scf[:3]) - scf_a[1 ] = np.average(scf[:4]) - scf_a[2:14] = [ np.average(scf[i:i+5]) for i in range(12) ] - scf_a[ 14] = np.average(scf[12:]) - scf_a[ 15] = np.average(scf[13:]) - - scf_a = (0.5 if self.dt == T.DT_10M else 0.3) * \ - (scf_a - np.average(scf_a)) - - return scf_a if att else scf - - def enum_mpvq(self, v): - - sign = None - index = 0 - x = 0 - - for (n, vn) in enumerate(v[::-1]): - - if sign is not None and vn != 0: - index = 2*index + sign - if vn != 0: - sign = 1 if vn < 0 else 0 - - index += T.SNS_MPVQ_OFFSETS[n][x] - x += abs(vn) - - return (index, bool(sign)) - - def quantize(self, scf): - - ## 3.3.7.3.2 Stage 1 - - dmse_lf = [ np.sum((scf[:8] - T.SNS_LFCB[i]) ** 2) for i in range(32) ] - dmse_hf = [ np.sum((scf[8:] - T.SNS_HFCB[i]) ** 2) for i in range(32) ] - - self.ind_lf = np.argmin(dmse_lf) - self.ind_hf = np.argmin(dmse_hf) - - st1 = np.append(T.SNS_LFCB[self.ind_lf], T.SNS_HFCB[self.ind_hf]) - r1 = scf - st1 - - ## 3.3.7.3.3 Stage 2 - - t2_rot = fftpack.dct(r1, norm = 'ortho') - x = np.abs(t2_rot) - - ## 3.3.7.3.3 Stage 2 Shape search, step 1 - - K = 6 - - proj_fac = (K - 1) / sum(np.abs(t2_rot)) - y3 = np.floor(x * proj_fac).astype(int) - - ## 3.3.7.3.3 Stage 2 Shape search, step 2 - - corr_xy = np.sum(y3 * x) - energy_y = np.sum(y3 * y3) - - k0 = sum(y3) - for k in range(k0, K): - q_pvq = ((corr_xy + x) ** 2) / (energy_y + 2*y3 + 1) - n_best = np.argmax(q_pvq) - - corr_xy += x[n_best] - energy_y += 2*y3[n_best] + 1 - y3[n_best] += 1 - - ## 3.3.7.3.3 Stage 2 Shape search, step 3 - - K = 8 - - y2 = y3.copy() - - for k in range(sum(y2), K): - q_pvq = ((corr_xy + x) ** 2) / (energy_y + 2*y2 + 1) - n_best = np.argmax(q_pvq) - - corr_xy += x[n_best] - energy_y += 2*y2[n_best] + 1 - y2[n_best] += 1 - - - ## 3.3.7.3.3 Stage 2 Shape search, step 4 - - y1 = np.append(y2[:10], [0] * 6) - - ## 3.3.7.3.3 Stage 2 Shape search, step 5 - - corr_xy -= sum(y2[10:] * x[10:]) - energy_y -= sum(y2[10:] * y2[10:]) - - ## 3.3.7.3.3 Stage 2 Shape search, step 6 - - K = 10 - - for k in range(sum(y1), K): - q_pvq = ((corr_xy + x[:10]) ** 2) / (energy_y + 2*y1[:10] + 1) - n_best = np.argmax(q_pvq) - - corr_xy += x[n_best] - energy_y += 2*y1[n_best] + 1 - y1[n_best] += 1 - - ## 3.3.7.3.3 Stage 2 Shape search, step 7 - - y0 = np.append(y1[:10], [ 0 ] * 6) - - q_pvq = ((corr_xy + x[10:]) ** 2) / (energy_y + 2*y0[10:] + 1) - n_best = 10 + np.argmax(q_pvq) - - y0[n_best] += 1 - - ## 3.3.7.3.3 Stage 2 Shape search, step 8 - - y0 *= np.sign(t2_rot).astype(int) - y1 *= np.sign(t2_rot).astype(int) - y2 *= np.sign(t2_rot).astype(int) - y3 *= np.sign(t2_rot).astype(int) - - ## 3.3.7.3.3 Stage 2 Shape search, step 9 - - xq = [ y / np.sqrt(sum(y ** 2)) for y in (y0, y1, y2, y3) ] - - ## 3.3.7.3.3 Shape and gain combination determination - - G = [ T.SNS_VQ_REG_ADJ_GAINS, T.SNS_VQ_REG_LF_ADJ_GAINS, - T.SNS_VQ_NEAR_ADJ_GAINS, T.SNS_VQ_FAR_ADJ_GAINS ] - - dMSE = [ [ sum((t2_rot - G[j][i] * xq[j]) ** 2) - for i in range(len(G[j])) ] for j in range(4) ] - - self.shape = np.argmin([ np.min(dMSE[j]) for j in range(4) ]) - self.gain = np.argmin(dMSE[self.shape]) - - gain = G[self.shape][self.gain] - - ## 3.3.7.3.3 Enumeration of the selected PVQ pulse configurations - - if self.shape == 0: - (self.idx_a, self.ls_a) = self.enum_mpvq(y0[:10]) - (self.idx_b, self.ls_b) = self.enum_mpvq(y0[10:]) - elif self.shape == 1: - (self.idx_a, self.ls_a) = self.enum_mpvq(y1[:10]) - (self.idx_b, self.ls_b) = (None, None) - elif self.shape == 2: - (self.idx_a, self.ls_a) = self.enum_mpvq(y2) - (self.idx_b, self.ls_b) = (None, None) - elif self.shape == 3: - (self.idx_a, self.ls_a) = self.enum_mpvq(y3) - (self.idx_b, self.ls_b) = (None, None) - - ## 3.3.7.3.4 Synthesis of the Quantized scale factor - - scf_q = st1 + gain * fftpack.idct(xq[self.shape], norm = 'ortho') - - return scf_q - - def run(self, eb, att, x): - - scf = self.compute_scale_factors(eb, att) - scf_q = self.quantize(scf) - y = self.spectral_shaping(scf_q, False, x) - - return y - - def store(self, b): - - shape = self.shape - gain_msb_bits = np.array([ 1, 1, 2, 2 ])[shape] - gain_lsb_bits = np.array([ 0, 1, 0, 1 ])[shape] - - b.write_uint(self.ind_lf, 5) - b.write_uint(self.ind_hf, 5) - - b.write_bit(shape >> 1) - - b.write_uint(self.gain >> gain_lsb_bits, gain_msb_bits) - - b.write_bit(self.ls_a) - - if self.shape == 0: - sz_shape_a = 2390004 - index_joint = self.idx_a + \ - (2 * self.idx_b + self.ls_b + 2) * sz_shape_a - - elif self.shape == 1: - sz_shape_a = 2390004 - index_joint = self.idx_a + (self.gain & 1) * sz_shape_a - - elif self.shape == 2: - index_joint = self.idx_a - - elif self.shape == 3: - sz_shape_a = 15158272 - index_joint = sz_shape_a + (self.gain & 1) + 2 * self.idx_a - - b.write_uint(index_joint, 14 - gain_msb_bits) - b.write_uint(index_joint >> (14 - gain_msb_bits), 12) - - -class SnsSynthesis(Sns): - - def __init__(self, dt, sr): - - super().__init__(dt, sr) - - def deenum_mpvq(self, index, ls, npulses, n): - - y = np.zeros(n, dtype=np.int) - pos = 0 - - for i in range(len(y)-1, -1, -1): - - if index > 0: - yi = 0 - while index < T.SNS_MPVQ_OFFSETS[i][npulses - yi]: yi += 1 - index -= T.SNS_MPVQ_OFFSETS[i][npulses - yi] - else: - yi = npulses - - y[pos] = [ yi, -yi ][int(ls)] - pos += 1 - - npulses -= yi - if npulses <= 0: - break - - if yi > 0: - ls = index & 1 - index >>= 1 - - return y - - def unquantize(self): - - ## 3.7.4.2.1-2 SNS VQ Decoding - - y = np.empty(16, dtype=np.int) - - if self.shape == 0: - y[:10] = self.deenum_mpvq(self.idx_a, self.ls_a, 10, 10) - y[10:] = self.deenum_mpvq(self.idx_b, self.ls_b, 1, 6) - elif self.shape == 1: - y[:10] = self.deenum_mpvq(self.idx_a, self.ls_a, 10, 10) - y[10:] = np.zeros(6, dtype=np.int) - elif self.shape == 2: - y = self.deenum_mpvq(self.idx_a, self.ls_a, 8, 16) - elif self.shape == 3: - y = self.deenum_mpvq(self.idx_a, self.ls_a, 6, 16) - - ## 3.7.4.2.3 Unit energy normalization - - y = y / np.sqrt(sum(y ** 2)) - - ## 3.7.4.2.4 Reconstruction of the quantized scale factors - - G = [ T.SNS_VQ_REG_ADJ_GAINS, T.SNS_VQ_REG_LF_ADJ_GAINS, - T.SNS_VQ_NEAR_ADJ_GAINS, T.SNS_VQ_FAR_ADJ_GAINS ] - - gain = G[self.shape][self.gain] - - scf = np.append(T.SNS_LFCB[self.ind_lf], T.SNS_HFCB[self.ind_hf]) \ - + gain * fftpack.idct(y, norm = 'ortho') - - return scf - - def load(self, b): - - self.ind_lf = b.read_uint(5) - self.ind_hf = b.read_uint(5) - - shape_msb = b.read_bit() - - gain_msb_bits = 1 + shape_msb - self.gain = b.read_uint(gain_msb_bits) - - self.ls_a = b.read_bit() - - index_joint = b.read_uint(14 - gain_msb_bits) - index_joint |= b.read_uint(12) << (14 - gain_msb_bits) - - if shape_msb == 0: - sz_shape_a = 2390004 - - if index_joint >= sz_shape_a * 14: - raise ValueError('Invalide SNS joint index') - - self.idx_a = index_joint % sz_shape_a - index_joint = index_joint // sz_shape_a - if index_joint >= 2: - self.shape = 0 - self.idx_b = (index_joint - 2) // 2 - self.ls_b = (index_joint - 2) % 2 - else: - self.shape = 1 - self.gain = (self.gain << 1) + (index_joint & 1) - - else: - sz_shape_a = 15158272 - if index_joint >= sz_shape_a + 1549824: - raise ValueError('Invalide SNS joint index') - - if index_joint < sz_shape_a: - self.shape = 2 - self.idx_a = index_joint - else: - self.shape = 3 - index_joint -= sz_shape_a - self.gain = (self.gain << 1) + (index_joint % 2) - self.idx_a = index_joint // 2 - - def run(self, x): - - scf = self.unquantize() - y = self.spectral_shaping(scf, True, x) - - return y - -### ------------------------------------------------------------------------ ### - -def check_analysis(rng, dt, sr): - - ok = True - - analysis = SnsAnalysis(dt, sr) - - for i in range(10): - x = rng.random(T.NE[dt][sr]) * 1e4 - e = rng.random(min(len(x), 64)) * 1e10 - - for att in (0, 1): - y = analysis.run(e, att, x) - data = analysis.get_data() - - (y_c, data_c) = lc3.sns_analyze(dt, sr, e, att, x) - - for k in data.keys(): - ok = ok and data_c[k] == data[k] - - ok = ok and lc3.sns_get_nbits() == analysis.get_nbits() - ok = ok and np.amax(np.abs(y - y_c)) < 1e-1 - - return ok - -def check_synthesis(rng, dt, sr): - - ok = True - - synthesis = SnsSynthesis(dt, sr) - - for i in range(100): - - synthesis.ind_lf = rng.integers(0, 32) - synthesis.ind_hf = rng.integers(0, 32) - - shape = rng.integers(0, 4) - sz_shape_a = [ 2390004, 2390004, 15158272, 774912 ][shape] - sz_shape_b = [ 6, 1, 0, 0 ][shape] - synthesis.shape = shape - synthesis.gain = rng.integers(0, [ 2, 4, 4, 8 ][shape]) - synthesis.idx_a = rng.integers(0, sz_shape_a, endpoint=True) - synthesis.ls_a = bool(rng.integers(0, 1, endpoint=True)) - synthesis.idx_b = rng.integers(0, sz_shape_b, endpoint=True) - synthesis.ls_b = bool(rng.integers(0, 1, endpoint=True)) - - x = rng.random(T.NE[dt][sr]) * 1e4 - - y = synthesis.run(x) - y_c = lc3.sns_synthesize(dt, sr, synthesis.get_data(), x) - ok = ok and np.amax(np.abs(y - y_c)) < 1e0 - - return ok - -def check_analysis_appendix_c(dt): - - sr = T.SRATE_16K - ok = True - - for i in range(len(C.E_B[dt])): - - scf = lc3.sns_compute_scale_factors(dt, sr, C.E_B[dt][i], False) - ok = ok and np.amax(np.abs(scf - C.SCF[dt][i])) < 1e-4 - - (lf, hf) = lc3.sns_resolve_codebooks(scf) - ok = ok and lf == C.IND_LF[dt][i] and hf == C.IND_HF[dt][i] - - (y, yn, shape, gain) = lc3.sns_quantize(scf, lf, hf) - ok = ok and np.any(y[0][:16] - C.SNS_Y0[dt][i] == 0) - ok = ok and np.any(y[1][:10] - C.SNS_Y1[dt][i] == 0) - ok = ok and np.any(y[2][:16] - C.SNS_Y2[dt][i] == 0) - ok = ok and np.any(y[3][:16] - C.SNS_Y3[dt][i] == 0) - ok = ok and shape == 2*C.SUBMODE_MSB[dt][i] + C.SUBMODE_LSB[dt][i] - ok = ok and gain == C.G_IND[dt][i] - - scf_q = lc3.sns_unquantize(lf, hf, yn[shape], shape, gain) - ok = ok and np.amax(np.abs(scf_q - C.SCF_Q[dt][i])) < 1e-5 - - x = lc3.sns_spectral_shaping(dt, sr, C.SCF_Q[dt][i], False, C.X[dt][i]) - ok = ok and np.amax(np.abs(1 - x/C.X_S[dt][i])) < 1e-5 - - (x, data) = lc3.sns_analyze(dt, sr, C.E_B[dt][i], False, C.X[dt][i]) - ok = ok and data['lfcb'] == C.IND_LF[dt][i] - ok = ok and data['hfcb'] == C.IND_HF[dt][i] - ok = ok and data['shape'] == \ - 2*C.SUBMODE_MSB[dt][i] + C.SUBMODE_LSB[dt][i] - ok = ok and data['gain'] == C.G_IND[dt][i] - ok = ok and data['idx_a'] == C.IDX_A[dt][i] - ok = ok and data['ls_a'] == C.LS_IND_A[dt][i] - ok = ok and (C.IDX_B[dt][i] is None or - data['idx_b'] == C.IDX_B[dt][i]) - ok = ok and (C.LS_IND_B[dt][i] is None or - data['ls_b'] == C.LS_IND_B[dt][i]) - ok = ok and np.amax(np.abs(1 - x/C.X_S[dt][i])) < 1e-5 - - return ok - -def check_synthesis_appendix_c(dt): - - sr = T.SRATE_16K - ok = True - - for i in range(len(C.X_HAT_TNS[dt])): - - data = { - 'lfcb' : C.IND_LF[dt][i], 'hfcb' : C.IND_HF[dt][i], - 'shape' : 2*C.SUBMODE_MSB[dt][i] + C.SUBMODE_LSB[dt][i], - 'gain' : C.G_IND[dt][i], - 'idx_a' : C.IDX_A[dt][i], - 'ls_a' : C.LS_IND_A[dt][i], - 'idx_b' : C.IDX_B[dt][i] if C.IDX_B[dt][i] is not None else 0, - 'ls_b' : C.LS_IND_B[dt][i] if C.LS_IND_B[dt][i] is not None else 0, - } - - x = lc3.sns_synthesize(dt, sr, data, C.X_HAT_TNS[dt][i]) - ok = ok and np.amax(np.abs(x - C.X_HAT_SNS[dt][i])) < 1e0 - - return ok - -def check(): - - rng = np.random.default_rng(1234) - ok = True - - for dt in range(T.NUM_DT): - for sr in range(T.NUM_SRATE): - ok = ok and check_analysis(rng, dt, sr) - ok = ok and check_synthesis(rng, dt, sr) - - for dt in range(T.NUM_DT): - ok = ok and check_analysis_appendix_c(dt) - ok = ok and check_synthesis_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/sns_py.c b/system/embdrv/lc3/test/sns_py.c deleted file mode 100644 index 2ef3e833c9deb8ef136e48488a36895a981dda02..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/sns_py.c +++ /dev/null @@ -1,215 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "lc3.h" -#include -#include - -#include -#include "ctypes.h" - -static PyObject *compute_scale_factors_py(PyObject *m, PyObject *args) -{ - unsigned dt, sr; - PyObject *eb_obj, *scf_obj; - float *eb, *scf; - int att; - - if (!PyArg_ParseTuple(args, "IIOp", &dt, &sr, &eb_obj, &att)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS); - - CTYPES_CHECK("eb", to_1d_ptr(eb_obj, NPY_FLOAT, nb, &eb)); - scf_obj = new_1d_ptr(NPY_FLOAT, 16, &scf); - - compute_scale_factors(dt, sr, eb, att, scf); - - return Py_BuildValue("N", scf_obj); -} - -static PyObject *resolve_codebooks_py(PyObject *m, PyObject *args) -{ - PyObject *scf_obj; - float *scf; - int lfcb_idx, hfcb_idx; - - if (!PyArg_ParseTuple(args, "O", &scf_obj)) - return NULL; - - CTYPES_CHECK("eb", to_1d_ptr(scf_obj, NPY_FLOAT, 16, &scf)); - - resolve_codebooks(scf, &lfcb_idx, &hfcb_idx); - - return Py_BuildValue("ii", lfcb_idx, hfcb_idx); -} - -static PyObject *quantize_py(PyObject *m, PyObject *args) -{ - PyObject *scf_obj, *y_obj, *yn_obj; - float *scf; - int lfcb_idx, hfcb_idx; - int shape_idx, gain_idx; - float (*yn)[16]; - int (*y)[16]; - - if (!PyArg_ParseTuple(args, "Oii", &scf_obj, &lfcb_idx, &hfcb_idx)) - return NULL; - - CTYPES_CHECK("scf", to_1d_ptr(scf_obj, NPY_FLOAT, 16, &scf)); - CTYPES_CHECK("lfcb_idx", (unsigned)lfcb_idx < 32); - CTYPES_CHECK("hfcb_idx", (unsigned)hfcb_idx < 32); - - y_obj = new_2d_ptr(NPY_INT, 4, 16, &y); - yn_obj = new_2d_ptr(NPY_FLOAT, 4, 16, &yn); - - quantize(scf, lfcb_idx, hfcb_idx, - y, yn, &shape_idx, &gain_idx); - - return Py_BuildValue("NNii", y_obj, yn_obj, shape_idx, gain_idx); -} - -static PyObject *unquantize_py(PyObject *m, PyObject *args) -{ - PyObject *y_obj, *scf_obj; - int lfcb_idx, hfcb_idx; - int shape, gain; - float *y, *scf; - - if (!PyArg_ParseTuple(args, "iiOii", - &lfcb_idx, &hfcb_idx, &y_obj, &shape, &gain)) - return NULL; - - CTYPES_CHECK("lfcb_idx", (unsigned)lfcb_idx < 32); - CTYPES_CHECK("hfcb_idx", (unsigned)hfcb_idx < 32); - CTYPES_CHECK("y", to_1d_ptr(y_obj, NPY_FLOAT, 16, &y)); - CTYPES_CHECK("shape", (unsigned)shape < 4); - CTYPES_CHECK("gain", - (unsigned)gain < (unsigned)lc3_sns_vq_gains[shape].count); - - scf_obj = new_1d_ptr(NPY_FLOAT, 16, &scf); - - unquantize(lfcb_idx, hfcb_idx, y, shape, gain, scf); - - return Py_BuildValue("N", scf_obj); -} - -static PyObject *spectral_shaping_py(PyObject *m, PyObject *args) -{ - PyObject *scf_q_obj, *x_obj; - unsigned dt, sr; - float *scf_q, *x; - int inv; - - if (!PyArg_ParseTuple(args, "IIOpO", &dt, &sr, &scf_q_obj, &inv, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int ne = LC3_NE(dt, sr); - - CTYPES_CHECK("scf_q", to_1d_ptr(scf_q_obj, NPY_FLOAT, 16, &scf_q)); - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - spectral_shaping(dt, sr, scf_q, inv, x, x); - - return Py_BuildValue("O", x_obj); -} - -static PyObject *analyze_py(PyObject *m, PyObject *args) -{ - PyObject *eb_obj, *x_obj; - struct lc3_sns_data data = { 0 }; - unsigned dt, sr; - float *eb, *x; - int att; - - if (!PyArg_ParseTuple(args, "IIOpO", &dt, &sr, &eb_obj, &att, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int ne = LC3_NE(dt, sr); - int nb = LC3_MIN(ne, LC3_NUM_BANDS); - - CTYPES_CHECK("eb", to_1d_ptr(eb_obj, NPY_FLOAT, nb, &eb)); - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - lc3_sns_analyze(dt, sr, eb, att, &data, x, x); - - return Py_BuildValue("ON", x_obj, new_sns_data(&data)); -} - -static PyObject *synthesize_py(PyObject *m, PyObject *args) -{ - PyObject *data_obj, *x_obj; - struct lc3_sns_data data; - unsigned dt, sr; - float *x; - - if (!PyArg_ParseTuple(args, "IIOO", &dt, &sr, &data_obj, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - CTYPES_CHECK(NULL, data_obj = to_sns_data(data_obj, &data)); - - int ne = LC3_NE(dt, sr); - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - lc3_sns_synthesize(dt, sr, &data, x, x); - - return Py_BuildValue("O", x_obj); -} - -static PyObject *get_nbits_py(PyObject *m, PyObject *args) -{ - if (!PyArg_ParseTuple(args, "")) - return NULL; - - int nbits = lc3_sns_get_nbits(); - - return Py_BuildValue("i", nbits); -} - -static PyMethodDef methods[] = { - { "sns_compute_scale_factors", compute_scale_factors_py, METH_VARARGS }, - { "sns_resolve_codebooks" , resolve_codebooks_py , METH_VARARGS }, - { "sns_quantize" , quantize_py , METH_VARARGS }, - { "sns_unquantize" , unquantize_py , METH_VARARGS }, - { "sns_spectral_shaping" , spectral_shaping_py , METH_VARARGS }, - { "sns_analyze" , analyze_py , METH_VARARGS }, - { "sns_synthesize" , synthesize_py , METH_VARARGS }, - { "sns_get_nbits" , get_nbits_py , METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_sns_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/test/spec.py b/system/embdrv/lc3/test/spec.py deleted file mode 100644 index 0117d57d7000b6b4176f2472e496428208d15664..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/spec.py +++ /dev/null @@ -1,812 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np - -import build.lc3 as lc3 -import tables as T, appendix_c as C - -import bwdet as m_bwdet -import ltpf as m_ltpf -import sns as m_sns -import tns as m_tns - -### ------------------------------------------------------------------------ ### - -class SpectrumQuantization: - - def __init__(self, dt, sr): - - self.dt = dt - self.sr = sr - - def get_gain_offset(self, nbytes): - - g_off = (nbytes * 8) // (10 * (1 + self.sr)) - g_off = -min(115, g_off) - (105 + 5*(1 + self.sr)) - - return g_off - - def get_noise_indices(self, bw, xq, lastnz): - - nf_start = [ 18, 24 ][self.dt] - nf_width = [ 2, 3 ][self.dt] - - bw_stop = int([ 80, 160, 240, 320, 400 ][bw] * (T.DT_MS[self.dt] / 10)) - - xq = np.append(xq[:lastnz], np.zeros(len(xq) - lastnz)) - - i_nf = [ np.all(xq[k-nf_width:min(bw_stop, k+nf_width+1)] == 0) - for k in range(nf_start, bw_stop) ] - - return (i_nf, nf_start, bw_stop) - - -class SpectrumAnalysis(SpectrumQuantization): - - def __init__(self, dt, sr): - - super().__init__(dt, sr) - - self.reset_off = 0 - self.nbits_off = 0 - self.nbits_spec = 0 - self.nbits_est = 0 - - self.g_idx = None - - def estimate_gain(self, x, nbits_spec, nbits_off, g_off): - - nbits = int(nbits_spec + nbits_off + 0.5) - - ### Energy (dB) by 4 MDCT coefficients - - e = [ np.sum(x[4*k:4*(k+1)] ** 2) for k in range(len(x) // 4) ] - e = 10 * np.log10(2**-31 + np.array(e)) - - ### Compute gain index - - g_idx = 255 - - for i in range(8): - factor = 1 << (7 - i) - g_idx -= factor - tmp = 0 - iszero = 1 - - for ei in e[-1::-1]: - - if ei * 28/20 < g_idx + g_off: - if iszero == 0: - tmp += 2.7*28/20 - else: - if g_idx + g_off < (ei - 43) * 28/20: - tmp += 2*ei*28/20 - 2*(g_idx + g_off) - 36*28/20 - else: - tmp += ei*28/20 - (g_idx + g_off) + 7*28/20 - iszero = 0 - - if tmp > nbits * 1.4 * 28/20 and iszero == 0: - g_idx += factor - - ### Limit gain index - - x_max = np.amax(np.abs(x)) - if x_max > 0: - g_min = 28 * np.log10(x_max / (32768 - 0.375)) - g_min = np.ceil(g_min).astype(int) - g_off - reset_off = g_idx < g_min - else: - g_min = 0 - reset_off = True - - if reset_off: - g_idx = g_min - - return (g_idx + g_off, reset_off) - - def quantize(self, g_int, x): - - xg = x / 10 ** (g_int / 28) - - xq = np.where(xg < 0, np.ceil(xg - 0.375), np.floor(xg + 0.375)) - xq = xq.astype(int) - xq = np.fmin(np.fmax(xq, -32768), 32767) - - nz_pairs = np.any([ xq[::2] != 0, xq[1::2] != 0 ], axis=0) - lastnz = len(xq) - 2 * np.argmax(nz_pairs[-1::-1]) - if not np.any(nz_pairs): - lastnz = 0 - - return (xg, xq, lastnz) - - def compute_nbits(self, nbytes, x, lastnz, nbits_spec): - - mode = 1 if nbytes >= 20 * (3 + self.sr) else 0 - rate = 512 if nbytes > 20 * (1 + self.sr) else 0 - - nbits_est = 0 - nbits_trunc = 0 - nbits_lsb = 0 - lastnz_trunc = 2 - c = 0 - - for n in range(0, lastnz, 2): - t = c + rate - if n > len(x) // 2: - t += 256 - - a = abs(x[n ]) - b = abs(x[n+1]) - lev = 0 - while max(a, b) >= 4: - nbits_est += \ - T.AC_SPEC_BITS[T.AC_SPEC_LOOKUP[t + lev*1024]][16]; - if lev == 0 and mode == 1: - nbits_lsb += 2 - else: - nbits_est += 2 * 2048 - - a >>= 1 - b >>= 1 - lev = min(lev + 1, 3) - - nbits_est += \ - T.AC_SPEC_BITS[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b] - - a_lsb = abs(x[n ]) - b_lsb = abs(x[n+1]) - nbits_est += (min(a_lsb, 1) + min(b_lsb, 1)) * 2048 - if lev > 0 and mode == 1: - a_lsb >>= 1; - b_lsb >>= 1; - nbits_lsb += int(a_lsb == 0 and x[n ] != 0) - nbits_lsb += int(b_lsb == 0 and x[n+1] != 0) - - if (x[n] != 0 or x[n+1] != 0) and \ - (nbits_est <= nbits_spec * 2048): - lastnz_trunc = n + 2; - nbits_trunc = nbits_est - - t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev; - c = (c & 15) * 16 + t; - - nbits_est = (nbits_est + 2047) // 2048 + nbits_lsb; - nbits_trunc = (nbits_trunc + 2047) // 2048 - - self.rate = rate - self.lsb_mode = mode == 1 and nbits_est > nbits_spec - - return (nbits_est, nbits_trunc, lastnz_trunc, self.lsb_mode) - - def adjust_gain(self, g_idx, nbits, nbits_spec): - - T1 = [ 80, 230, 380, 530, 680 ] - T2 = [ 500, 1025, 1550, 2075, 2600 ] - T3 = [ 850, 1700, 2550, 3400, 4250 ] - - sr = self.sr - - if nbits < T1[sr]: - delta = (nbits + 48) / 16 - - elif nbits < T2[sr]: - a = T1[sr] / 16 + 3 - b = T2[sr] / 48 - delta = a + (nbits - T1[sr]) * (b - a) / (T2[sr] - T1[sr]) - - elif nbits < T3[sr]: - delta = nbits / 48 - - else: - delta = T3[sr] / 48; - - delta = np.fix(delta + 0.5).astype(int) - - if (g_idx < 255 and nbits > nbits_spec) or \ - (g_idx > 0 and nbits < nbits_spec - (delta + 2)): - - if nbits < nbits_spec - (delta + 2): - return - 1 - - if g_idx == 254 or nbits < nbits_spec + delta: - return 1 - - else: - return 2 - - return 0 - - def estimate_noise(self, bw, xq, lastnz, x): - - (i_nf, nf_start, nf_stop) = self.get_noise_indices(bw, xq, lastnz) - - nf = 8 - 16 * sum(abs(x[nf_start:nf_stop] * i_nf)) / sum(i_nf) \ - if sum(i_nf) > 0 else 0 - - return min(max(np.rint(nf).astype(int), 0), 7) - - def run(self, - bw, nbytes, nbits_bw, nbits_ltpf, nbits_sns, nbits_tns, x): - - sr = self.sr - - ### Bit budget - - nbits_gain = 8 - nbits_nf = 3 - - nbits_ari = np.ceil(np.log2(len(x) / 2)).astype(int) - nbits_ari += 3 + min((8*nbytes - 1) // 1280, 2) - - nbits_spec = 8*nbytes - \ - nbits_bw - nbits_ltpf - nbits_sns - nbits_tns - \ - nbits_gain - nbits_nf - nbits_ari - - ### Global gain estimation - - nbits_off = self.nbits_off + self.nbits_spec - self.nbits_est - nbits_off = min(40, max(-40, nbits_off)) - - nbits_off = 0 if self.reset_off else \ - 0.8 * self.nbits_off + 0.2 * nbits_off - - g_off = self.get_gain_offset(nbytes) - - (g_int, self.reset_off) = \ - self.estimate_gain(x, nbits_spec, nbits_off, g_off) - self.nbits_off = nbits_off - self.nbits_spec = nbits_spec - - ### Quantization - - (xg, xq, lastnz) = self.quantize(g_int, x) - - (nbits_est, nbits_trunc, lastnz_trunc, _) = \ - self.compute_nbits(nbytes, xq, lastnz, nbits_spec) - - self.nbits_est = nbits_est - - ### Adjust gain and requantize - - g_adj = self.adjust_gain(g_int - g_off, nbits_est, nbits_spec) - - (xg, xq, lastnz) = self.quantize(g_adj, xg) - - (nbits_est, nbits_trunc, lastnz_trunc, lsb_mode) = \ - self.compute_nbits(nbytes, xq, lastnz, nbits_spec) - - self.g_idx = g_int + g_adj - g_off - self.xq = xq - self.lastnz = lastnz_trunc - - self.nbits_residual_max = nbits_spec - nbits_trunc + 4 - self.xg = xg - - ### Noise factor - - self.noise_factor = self.estimate_noise(bw, xq, lastnz, x) - - return (self.xq, self.lastnz, self.xg) - - def store(self, b): - - ne = T.NE[self.dt][self.sr] - nbits_lastnz = np.ceil(np.log2(ne/2)).astype(int) - - b.write_uint((self.lastnz >> 1) - 1, nbits_lastnz) - b.write_uint(self.lsb_mode, 1) - - def encode(self, bits): - - ### Noise factor - - bits.write_uint(self.noise_factor, 3) - - ### Quantized data - - lsbs = [] - - x = self.xq - c = 0 - - for n in range(0, self.lastnz, 2): - t = c + self.rate - if n > len(x) // 2: - t += 256 - - a = abs(x[n ]) - b = abs(x[n+1]) - lev = 0 - while max(a, b) >= 4: - - bits.ac_encode( - T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][16], - T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][16]) - - if lev == 0 and self.lsb_mode: - lsb_0 = a & 1 - lsb_1 = b & 1 - else: - bits.write_bit(a & 1) - bits.write_bit(b & 1) - - a >>= 1 - b >>= 1 - lev = min(lev + 1, 3) - - bits.ac_encode( - T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b], - T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b]) - - a_lsb = abs(x[n ]) - b_lsb = abs(x[n+1]) - if lev > 0 and self.lsb_mode: - a_lsb >>= 1 - b_lsb >>= 1 - - lsbs.append(lsb_0) - if a_lsb == 0 and x[n+0] != 0: - lsbs.append(int(x[n+0] < 0)) - - lsbs.append(lsb_1) - if b_lsb == 0 and x[n+1] != 0: - lsbs.append(int(x[n+1] < 0)) - - if a_lsb > 0: - bits.write_bit(int(x[n+0] < 0)) - - if b_lsb > 0: - bits.write_bit(int(x[n+1] < 0)) - - t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev; - c = (c & 15) * 16 + t; - - ### Residual data - - if self.lsb_mode == 0: - nbits_residual = min(bits.get_bits_left(), self.nbits_residual_max) - - for i in range(len(self.xg)): - - if self.xq[i] == 0: - continue - - bits.write_bit(self.xg[i] >= self.xq[i]) - nbits_residual -= 1 - if nbits_residual <= 0: - break - - else: - nbits_residual = min(bits.get_bits_left(), len(lsbs)) - for lsb in lsbs[:nbits_residual]: - bits.write_bit(lsb) - - -class SpectrumSynthesis(SpectrumQuantization): - - def __init__(self, dt, sr): - - super().__init__(dt, sr) - - def fill_noise(self, bw, x, lastnz, f_nf, nf_seed): - - (i_nf, nf_start, nf_stop) = self.get_noise_indices(bw, x, lastnz) - - k_nf = nf_start + np.argwhere(i_nf) - l_nf = (8 - f_nf)/16 - - for k in k_nf: - nf_seed = (13849 + nf_seed * 31821) & 0xffff - x[k] = [ -l_nf, l_nf ][nf_seed < 0x8000] - - return x - - def load(self, b): - - ne = T.NE[self.dt][self.sr] - nbits_lastnz = np.ceil(np.log2(ne/2)).astype(int) - - self.lastnz = (b.read_uint(nbits_lastnz) + 1) << 1 - self.lsb_mode = b.read_uint(1) - self.g_idx = b.read_uint(8) - - if self.lastnz > ne: - raise ValueError('Invalid count of coded samples') - - def decode(self, bits, bw, nbytes): - - ### Noise factor - - f_nf = bits.read_uint(3) - - ### Quantized data - - x = np.zeros(T.NE[self.dt][self.sr]) - rate = 512 if nbytes > 20 * (1 + self.sr) else 0 - - levs = np.zeros(len(x), dtype=np.int) - c = 0 - - for n in range(0, self.lastnz, 2): - t = c + rate - if n > len(x) // 2: - t += 256 - - for lev in range(14): - - s = t + min(lev, 3) * 1024 - - sym = bits.ac_decode( - T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[s]], - T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[s]]) - - if sym < 16: - break - - if self.lsb_mode == 0 or lev > 0: - x[n ] += bits.read_bit() << lev - x[n+1] += bits.read_bit() << lev - - if lev >= 14: - raise ValueError('Out of range value') - - a = sym % 4 - b = sym // 4 - - levs[n ] = lev - levs[n+1] = lev - - x[n ] += a << lev - x[n+1] += b << lev - - if x[n] and bits.read_bit(): - x[n] = -x[n] - - if x[n+1] and bits.read_bit(): - x[n+1] = -x[n+1] - - lev = min(lev, 3) - t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev; - c = (c & 15) * 16 + t; - - ### Residual data - - nbits_residual = bits.get_bits_left() - if nbits_residual < 0: - raise ValueError('Out of bitstream') - - if self.lsb_mode == 0: - - xr = np.zeros(len(x), dtype=np.bool) - - for i in range(len(x)): - - if nbits_residual <= 0: - xr.resize(i) - break - - if x[i] == 0: - continue - - xr[i] = bits.read_bit() - nbits_residual -= 1 - - else: - - for i in range(len(levs)): - - if nbits_residual <= 0: - break - - if levs[i] <= 0: - continue - - lsb = bits.read_bit() - nbits_residual -= 1 - if not lsb: - continue - - sign = int(x[i] < 0) - - if x[i] == 0: - - if nbits_residual <= 0: - break - - sign = bits.read_bit() - nbits_residual -= 1 - - x[i] += [ 1, -1 ][sign] - - ### Set residual and noise - - nf_seed = sum(abs(x.astype(np.int)) * range(len(x))) - - zero_frame = (self.lastnz <= 2 and x[0] == 0 and x[1] == 0 - and self.g_idx <= 0 and nf >= 7) - - if self.lsb_mode == 0: - - for i in range(len(xr)): - - if x[i] and xr[i] == 0: - x[i] += [ -0.1875, -0.3125 ][x[i] < 0] - elif x[i]: - x[i] += [ 0.1875, 0.3125 ][x[i] > 0] - - if not zero_frame: - x = self.fill_noise(bw, x, self.lastnz, f_nf, nf_seed) - - ### Rescale coefficients - - g_int = self.get_gain_offset(nbytes) + self.g_idx - x *= 10 ** (g_int / 28) - - return x - - -def initial_state(): - return { 'nbits_off' : 0.0, 'nbits_spare' : 0 } - - -### ------------------------------------------------------------------------ ### - -def check_estimate_gain(rng, dt, sr): - - ne = T.I[dt][sr][-1] - ok = True - - analysis = SpectrumAnalysis(dt, sr) - - for i in range(10): - x = rng.random(ne) * i * 1e2 - - nbytes = 20 + int(rng.random() * 100) - nbits_budget = 8 * nbytes - int(rng.random() * 100) - nbits_off = rng.random() * 10 - g_off = 10 - int(rng.random() * 20) - - (g_int, reset_off) = \ - analysis.estimate_gain(x, nbits_budget, nbits_off, g_off) - - (g_int_c, reset_off_c) = lc3.spec_estimate_gain( - dt, sr, x, nbits_budget, nbits_off, -g_off) - - ok = ok and g_int_c == g_int - ok = ok and reset_off_c == reset_off - - return ok - -def check_quantization(rng, dt, sr): - - ne = T.I[dt][sr][-1] - ok = True - - analysis = SpectrumAnalysis(dt, sr) - - for g_int in range(-128, 128): - - x = rng.random(ne) * 1e2 - nbytes = 20 + int(rng.random() * 30) - - (xg, xq, nq) = analysis.quantize(g_int, x) - (xg_c, xq_c, nq_c) = lc3.spec_quantize(dt, sr, g_int, x) - - ok = ok and np.amax(np.abs(1 - xg_c/xg)) < 1e-6 - ok = ok and np.any(abs(xq_c - xq) < 1) - ok = ok and nq_c == nq - - return ok - -def check_compute_nbits(rng, dt, sr): - - ne = T.I[dt][sr][-1] - ok = True - - analysis = SpectrumAnalysis(dt, sr) - - for nbytes in range(20, 150): - - nbits_budget = nbytes * 8 - int(rng.random() * 100) - xq = (rng.random(ne) * 8).astype(int) - nq = ne // 2 + int(rng.random() * ne // 2) - - nq = nq - nq % 2 - if xq[nq-2] == 0 and xq[nq-1] == 0: - xq[nq-2] = 1 - - (nbits, nbits_trunc, nq_trunc, lsb_mode) = \ - analysis.compute_nbits(nbytes, xq, nq, nbits_budget) - - (nbits_c, nq_c, _) = \ - lc3.spec_compute_nbits(dt, sr, nbytes, xq, nq, 0) - - (nbits_trunc_c, nq_trunc_c, lsb_mode_c) = \ - lc3.spec_compute_nbits(dt, sr, nbytes, xq, nq, nbits_budget) - - ok = ok and nbits_c == nbits - ok = ok and nbits_trunc_c == nbits_trunc - ok = ok and nq_trunc_c == nq_trunc - ok = ok and lsb_mode_c == lsb_mode - - return ok - -def check_adjust_gain(rng, dt, sr): - - ne = T.I[dt][sr][-1] - ok = True - - analysis = SpectrumAnalysis(dt, sr) - - for g_idx in (0, 128, 254, 255): - for nbits in range(50, 5000, 5): - nbits_budget = int(nbits * (0.95 + (rng.random() * 0.1))) - - g_adj = analysis.adjust_gain(g_idx, nbits, nbits_budget) - - g_adj_c = lc3.spec_adjust_gain(sr, g_idx, nbits, nbits_budget) - - ok = ok and g_adj_c == g_adj - - return ok - -def check_unit(rng, dt, sr): - - ns = T.NS[dt][sr] - ne = T.I[dt][sr][-1] - ok = True - - state_c = initial_state() - - bwdet = m_bwdet.BandwidthDetector(dt, sr) - ltpf = m_ltpf.LtpfAnalysis(dt, sr) - tns = m_tns.TnsAnalysis(dt) - sns = m_sns.SnsAnalysis(dt, sr) - analysis = SpectrumAnalysis(dt, sr) - - nbytes = 100 - - for i in range(10): - - x = rng.random(ns) * 1e4 - e = rng.random(min(len(x), 64)) * 1e10 - - bwdet.run(e) - pitch_present = ltpf.run(x) - tns.run(x[:ne], sr, False, nbytes) - sns.run(e, False, x) - - (xq, nq, _) = analysis.run(sr, nbytes, bwdet.get_nbits(), - ltpf.get_nbits(), sns.get_nbits(), tns.get_nbits(), x[:ne]) - - (_, xq_c, side_c) = lc3.spec_analyze( - dt, sr, nbytes, pitch_present, tns.get_data(), state_c, x[:ne]) - - ok = ok and side_c['g_idx'] == analysis.g_idx - ok = ok and side_c['nq'] == nq - ok = ok and np.any(abs(xq_c - xq) < 1) - - return ok - -def check_noise(rng, dt, bw): - - ne = T.NE[dt][bw] - ok = True - - analysis = SpectrumAnalysis(dt, bw) - - for i in range(10): - - xq = ((rng.random(ne) - 0.5) * 10 ** (0.5)).astype(int) - nq = ne - int(rng.random() * 5) - x = rng.random(ne) * i * 1e-1 - - nf = analysis.estimate_noise(bw, xq, nq, x) - nf_c = lc3.spec_estimate_noise(dt, bw, xq, nq, x) - - ok = ok and nf_c == nf - - return ok - -def check_appendix_c(dt): - - sr = T.SRATE_16K - ne = T.NE[dt][sr] - ok = True - - state_c = initial_state() - - for i in range(len(C.X_F[dt])): - - g_int = lc3.spec_estimate_gain(dt, sr, C.X_F[dt][i], - C.NBITS_SPEC[dt][i], C.NBITS_OFFSET[dt][i], -C.GG_OFF[dt][i])[0] - ok = ok and g_int == C.GG_IND[dt][i] + C.GG_OFF[dt][i] - - (_, xq, nq) = lc3.spec_quantize(dt, sr, - C.GG_IND[dt][i] + C.GG_OFF[dt][i], C.X_F[dt][i]) - ok = ok and np.any((xq - C.X_Q[dt][i]) == 0) - ok = ok and nq == C.LASTNZ[dt][i] - - nbits = lc3.spec_compute_nbits(dt, sr, - C.NBYTES[dt], C.X_Q[dt][i], C.LASTNZ[dt][i], 0)[0] - ok = ok and nbits == C.NBITS_EST[dt][i] - - g_adj = lc3.spec_adjust_gain(sr, - C.GG_IND[dt][i], C.NBITS_EST[dt][i], C.NBITS_SPEC[dt][i]) - ok = ok and g_adj == C.GG_IND_ADJ[dt][i] - C.GG_IND[dt][i] - - if C.GG_IND_ADJ[dt][i] != C.GG_IND[dt][i]: - - (_, xq, nq) = lc3.spec_quantize(dt, sr, - C.GG_IND_ADJ[dt][i] + C.GG_OFF[dt][i], C.X_F[dt][i]) - lastnz = C.LASTNZ_REQ[dt][i] - ok = ok and np.any(((xq - C.X_Q_REQ[dt][i])[:lastnz]) == 0) - - tns_data = { - 'nfilters' : C.NUM_TNS_FILTERS[dt][i], - 'lpc_weighting' : [ True, True ], - 'rc_order' : [ C.RC_ORDER[dt][i][0], 0 ], - 'rc' : [ C.RC_I_1[dt][i] - 8, np.zeros(8, dtype = np.int) ] - } - - (x, xq, side) = lc3.spec_analyze(dt, sr, C.NBYTES[dt], - C.PITCH_PRESENT[dt][i], tns_data, state_c, C.X_F[dt][i]) - - ok = ok and np.abs(state_c['nbits_off'] - C.NBITS_OFFSET[dt][i]) < 1e-5 - if C.GG_IND_ADJ[dt][i] != C.GG_IND[dt][i]: - xq = C.X_Q_REQ[dt][i] - nq = C.LASTNZ_REQ[dt][i] - ok = ok and side['g_idx'] == C.GG_IND_ADJ[dt][i] - ok = ok and side['nq'] == nq - ok = ok and np.any(((xq[:nq] - xq[:nq])) == 0) - else: - xq = C.X_Q[dt][i] - nq = C.LASTNZ[dt][i] - ok = ok and side['g_idx'] == C.GG_IND[dt][i] - ok = ok and side['nq'] == nq - ok = ok and np.any((xq[:nq] - C.X_Q[dt][i][:nq]) == 0) - ok = ok and side['lsb_mode'] == C.LSB_MODE[dt][i] - - gg = C.GG[dt][i] if C.GG_IND_ADJ[dt][i] == C.GG_IND[dt][i] \ - else C.GG_ADJ[dt][i] - - nf = lc3.spec_estimate_noise(dt, C.P_BW[dt][i], - xq, nq, C.X_F[dt][i] / gg) - ok = ok and nf == C.F_NF[dt][i] - - return ok - -def check(): - - rng = np.random.default_rng(1234) - ok = True - - for dt in range(T.NUM_DT): - for sr in range(T.NUM_SRATE): - ok = ok and check_estimate_gain(rng, dt, sr) - ok = ok and check_quantization(rng, dt, sr) - ok = ok and check_compute_nbits(rng, dt, sr) - ok = ok and check_adjust_gain(rng, dt, sr) - ok = ok and check_unit(rng, dt, sr) - ok = ok and check_noise(rng, dt, sr) - - for dt in range(T.NUM_DT): - ok = ok and check_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/spec_py.c b/system/embdrv/lc3/test/spec_py.c deleted file mode 100644 index 814f2536c96b21271ab9bdaafe9a93e10c181bb2..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/spec_py.c +++ /dev/null @@ -1,209 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "lc3.h" -#include -#include - -#include -#include "ctypes.h" - -static PyObject *estimate_gain_py(PyObject *m, PyObject *args) -{ - PyObject *x_obj; - unsigned dt, sr; - float *x; - int nbits_budget; - float nbits_off; - int g_off; - bool reset_off; - - if (!PyArg_ParseTuple(args, "IIOifi", &dt, &sr, - &x_obj, &nbits_budget, &nbits_off, &g_off)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int ne = LC3_NE(dt, sr); - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - int g_int = estimate_gain(dt, sr, - x, nbits_budget, nbits_off, g_off, &reset_off); - - return Py_BuildValue("ii", g_int, reset_off); -} - -static PyObject *adjust_gain_py(PyObject *m, PyObject *args) -{ - unsigned sr; - int g_idx, nbits, nbits_budget; - - if (!PyArg_ParseTuple(args, "Iiii", &sr, &g_idx, &nbits, &nbits_budget)) - return NULL; - - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - CTYPES_CHECK("g_idx", g_idx >= 0 && g_idx <= 255); - - g_idx = adjust_gain(sr, g_idx, nbits, nbits_budget); - - return Py_BuildValue("i", g_idx); -} - -static PyObject *quantize_py(PyObject *m, PyObject *args) -{ - PyObject *x_obj, *xq_obj; - unsigned dt, sr; - float *x; - int16_t *xq; - int g_int, nq; - - if (!PyArg_ParseTuple(args, "IIiO", &dt, &sr, &g_int, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - CTYPES_CHECK("g_int", g_int >= -255 && g_int <= 255); - - int ne = LC3_NE(dt, sr); - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - xq_obj = new_1d_ptr(NPY_INT16, ne, &xq); - uint16_t __xq[ne]; - - quantize(dt, sr, g_int, x, __xq, &nq); - - for (int i = 0; i < nq; i++) - xq[i] = __xq[i] & 1 ? -(__xq[i] >> 1) : (__xq[i] >> 1); - - return Py_BuildValue("ONi", x_obj, xq_obj, nq); -} - -static PyObject *compute_nbits_py(PyObject *m, PyObject *args) -{ - PyObject *xq_obj; - unsigned dt, sr, nbytes; - int16_t *xq; - int nq, nbits_budget; - bool lsb_mode; - - if (!PyArg_ParseTuple(args, "IIIOii", &dt, &sr, - &nbytes, &xq_obj, &nq, &nbits_budget)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int ne = LC3_NE(dt, sr); - - CTYPES_CHECK("xq", xq_obj = to_1d_ptr(xq_obj, NPY_INT16, ne, &xq)); - - uint16_t __xq[ne]; - for (int i = 0; i < ne; i++) - __xq[i] = xq[i] < 0 ? (-xq[i] << 1) + 1 : (xq[i] << 1); - - int nbits = compute_nbits( - dt, sr, nbytes, __xq, &nq, nbits_budget, &lsb_mode); - - return Py_BuildValue("iii", nbits, nq, lsb_mode); -} - -static PyObject *analyze_py(PyObject *m, PyObject *args) -{ - PyObject *tns_obj, *spec_obj, *x_obj, *xq_obj; - struct lc3_tns_data tns = { 0 }; - struct lc3_spec_analysis spec = { 0 }; - struct lc3_spec_side side = { 0 }; - unsigned dt, sr, nbytes; - int pitch; - float *x; - int16_t *xq; - - if (!PyArg_ParseTuple(args, "IIIpOOO", &dt, &sr, &nbytes, - &pitch, &tns_obj, &spec_obj, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE); - - int ne = LC3_NE(dt, sr); - - CTYPES_CHECK(NULL, tns_obj = to_tns_data(tns_obj, &tns)); - CTYPES_CHECK(NULL, spec_obj = to_spec_analysis(spec_obj, &spec)); - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - xq_obj = new_1d_ptr(NPY_INT16, ne, &xq); - uint16_t __xq[ne]; - - lc3_spec_analyze(dt, sr, nbytes, pitch, &tns, &spec, x, __xq, &side); - - for (int i = 0; i < ne; i++) - xq[i] = __xq[i] & 1 ? -(__xq[i] >> 1) : (__xq[i] >> 1); - - from_spec_analysis(spec_obj, &spec); - return Py_BuildValue("ONN", x_obj, xq_obj, new_spec_side(&side)); -} - -static PyObject *estimate_noise_py(PyObject *m, PyObject *args) -{ - PyObject *x_obj, *xq_obj; - unsigned dt, bw; - int16_t *xq; - float *x; - int nq; - - if (!PyArg_ParseTuple(args, "IIOIO", &dt, &bw, &xq_obj, &nq, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("bw", (unsigned)bw < LC3_NUM_BANDWIDTH); - - int ne = LC3_NE(dt, bw); - - CTYPES_CHECK("xq", xq_obj = to_1d_ptr(xq_obj, NPY_INT16, ne, &xq)); - CTYPES_CHECK("x" , x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x )); - - uint16_t __xq[nq]; - for (int i = 0; i < nq; i++) - __xq[i] = xq[i] < 0 ? (-xq[i] << 1) + 1 : (xq[i] << 1); - - int noise_factor = estimate_noise(dt, bw, __xq, nq, x); - - return Py_BuildValue("i", noise_factor); -} - -static PyMethodDef methods[] = { - { "spec_estimate_gain" , estimate_gain_py , METH_VARARGS }, - { "spec_adjust_gain" , adjust_gain_py , METH_VARARGS }, - { "spec_quantize" , quantize_py , METH_VARARGS }, - { "spec_compute_nbits" , compute_nbits_py , METH_VARARGS }, - { "spec_analyze" , analyze_py , METH_VARARGS }, - { "spec_estimate_noise", estimate_noise_py, METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_spec_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/test/tables.py b/system/embdrv/lc3/test/tables.py deleted file mode 100644 index 488658690c1305cbd3bab1d921a69bf8ae89ef83..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/tables.py +++ /dev/null @@ -1,2709 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np - - -### Generic ### - -DT_7M5 = 0 -DT_10M = 1 -NUM_DT = 2 - -DT_MS = np.array([ 7.5, 10 ]) - - -SRATE_8K = 0 -SRATE_16K = 1 -SRATE_24K = 2 -SRATE_32K = 3 -SRATE_48K = 4 -NUM_SRATE = 5 - -SRATE_KHZ = np.array([ 8, 16, 24, 32, 48 ]) - - -NS = [ (SRATE_KHZ * DT_MS[dt]).astype(int) for dt in range(NUM_DT) ] -NE = [ np.append(NS[dt][:-1], (NS[dt][-1] * 5) // 6) for dt in range(NUM_DT) ] - -ND = [ (23 * NS[0]) // 30, (5 * NS[1]) // 8 ] - - -### 3.7.1/2 ### - -I_10M_8K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, - 71, 73, 75, 77, 80 -]) - -I_10M_16K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, - 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, - 52, 55, 58, 61, 64, 67, 70, 73, 76, 80, - 84, 88, 92, 96, 101, 106, 111, 116, 121, 127, - 133, 139, 146, 153, 160 -]) - -I_10M_24K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 25, 27, 29, 31, 33, 35, - 37, 39, 41, 43, 46, 49, 52, 55, 58, 61, - 64, 68, 72, 76, 80, 85, 90, 95, 100, 106, - 112, 118, 125, 132, 139, 147, 155, 164, 173, 183, - 193, 204, 215, 227, 240 -]) - -I_10M_32K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, - 41, 44, 47, 50, 53, 56, 60, 64, 68, 72, - 76, 81, 86, 91, 97, 103, 109, 116, 123, 131, - 139, 148, 157, 166, 176, 187, 199, 211, 224, 238, - 252, 268, 284, 302, 320 -]) - -I_10M_48K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, - 22, 24, 26, 28, 30, 32, 34, 36, 39, 42, - 45, 48, 51, 55, 59, 63, 67, 71, 76, 81, - 86, 92, 98, 105, 112, 119, 127, 135, 144, 154, - 164, 175, 186, 198, 211, 225, 240, 256, 273, 291, - 310, 330, 352, 375, 400 -]) - -I_7M5_8K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60 -]) - -I_7M5_16K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 36, 38, 40, 42, 44, - 46, 48, 50, 52, 54, 56, 58, 60, 62, 65, - 68, 71, 74, 77, 80, 83, 86, 90, 94, 98, - 102, 106, 110, 115, 120 -]) - -I_7M5_24K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 29, 31, - 33, 35, 37, 39, 41, 43, 45, 47, 49, 52, - 55, 58, 61, 64, 67, 70, 74, 78, 82, 86, - 90, 95, 100, 105, 110, 115, 121, 127, 134, 141, - 148, 155, 163, 171, 180 -]) - -I_7M5_32K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 26, 28, 30, 32, 34, - 36, 38, 40, 42, 45, 48, 51, 54, 57, 60, - 63, 67, 71, 75, 79, 84, 89, 94, 99, 105, - 111, 117, 124, 131, 138, 146, 154, 163, 172, 182, - 192, 203, 215, 227, 240 -]) - -I_7M5_48K = np.array([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 24, 26, 28, 30, 32, 34, 36, - 38, 40, 43, 46, 49, 52, 55, 59, 63, 67, - 71, 75, 80, 85, 90, 96, 102, 108, 115, 122, - 129, 137, 146, 155, 165, 175, 186, 197, 209, 222, - 236, 251, 266, 283, 300 -]) - -I = [ [ I_7M5_8K, I_7M5_16K, I_7M5_24K, I_7M5_32K, I_7M5_48K ], - [ I_10M_8K, I_10M_16K, I_10M_24K, I_10M_32K, I_10M_48K ] ] - - -### 3.7.3 ### - -W_10M_80 = np.array([ - -7.07854671e-04, -2.09819773e-03, -4.52519808e-03, -8.23397633e-03, - -1.33771310e-02, -1.99972156e-02, -2.80090946e-02, -3.72150208e-02, - -4.73176826e-02, -5.79465483e-02, -6.86760675e-02, -7.90464744e-02, - -8.85970547e-02, -9.68830362e-02, -1.03496124e-01, -1.08076646e-01, - -1.10324226e-01, -1.09980985e-01, -1.06817214e-01, -1.00619042e-01, - -9.11645251e-02, -7.82061748e-02, -6.14668812e-02, -4.06336286e-02, - -1.53632952e-02, 1.47015507e-02, 4.98973651e-02, 9.05036926e-02, - 1.36691102e-01, 1.88468639e-01, 2.45645680e-01, 3.07778908e-01, - 3.74164237e-01, 4.43811480e-01, 5.15473546e-01, 5.87666172e-01, - 6.58761977e-01, 7.27057670e-01, 7.90875299e-01, 8.48664336e-01, - 8.99132024e-01, 9.41334815e-01, 9.74763483e-01, 9.99411473e-01, - 1.01576037e+00, 1.02473616e+00, 1.02763429e+00, 1.02599149e+00, - 1.02142721e+00, 1.01543986e+00, 1.00936693e+00, 1.00350816e+00, - 9.98889821e-01, 9.95313390e-01, 9.92594392e-01, 9.90577196e-01, - 9.89137162e-01, 9.88179075e-01, 9.87624927e-01, 9.87405628e-01, - 9.87452485e-01, 9.87695113e-01, 9.88064062e-01, 9.88492687e-01, - 9.88923003e-01, 9.89307497e-01, 9.89614633e-01, 9.89831927e-01, - 9.89969310e-01, 9.90060335e-01, 9.90157502e-01, 9.90325529e-01, - 9.90630379e-01, 9.91129889e-01, 9.91866549e-01, 9.92861973e-01, - 9.94115607e-01, 9.95603378e-01, 9.97279311e-01, 9.99078484e-01, - 1.00092237e+00, 1.00272811e+00, 1.00441604e+00, 1.00591922e+00, - 1.00718935e+00, 1.00820015e+00, 1.00894949e+00, 1.00945824e+00, - 1.00976898e+00, 1.00994034e+00, 1.01003945e+00, 1.01013232e+00, - 1.01027252e+00, 1.01049435e+00, 1.01080807e+00, 1.01120107e+00, - 1.01164127e+00, 1.01208013e+00, 1.01245818e+00, 1.01270696e+00, - 1.01275501e+00, 1.01253013e+00, 1.01196233e+00, 1.01098214e+00, - 1.00951244e+00, 1.00746086e+00, 1.00470868e+00, 1.00111141e+00, - 9.96504102e-01, 9.90720000e-01, 9.82376587e-01, 9.70882175e-01, - 9.54673298e-01, 9.32155386e-01, 9.01800368e-01, 8.62398408e-01, - 8.13281737e-01, 7.54455197e-01, 6.86658072e-01, 6.11348804e-01, - 5.30618165e-01, 4.47130985e-01, 3.63911468e-01, 2.84164703e-01, - 2.11020945e-01, 1.47228797e-01, 9.48266535e-02, 5.48243661e-02, - 2.70146141e-02, 9.99674359e-03, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_10M_160 = np.array([ - -4.61989875e-04, -9.74716672e-04, -1.66447310e-03, -2.59710692e-03, - -3.80628516e-03, -5.32460872e-03, -7.17588528e-03, -9.38248086e-03, - -1.19527030e-02, -1.48952816e-02, -1.82066640e-02, -2.18757093e-02, - -2.58847194e-02, -3.02086274e-02, -3.48159779e-02, -3.96706799e-02, - -4.47269805e-02, -4.99422586e-02, -5.52633479e-02, -6.06371724e-02, - -6.60096152e-02, -7.13196627e-02, -7.65117823e-02, -8.15296401e-02, - -8.63113754e-02, -9.08041129e-02, -9.49537776e-02, -9.87073651e-02, - -1.02020268e-01, -1.04843883e-01, -1.07138231e-01, -1.08869014e-01, - -1.09996966e-01, -1.10489847e-01, -1.10322584e-01, -1.09462175e-01, - -1.07883429e-01, -1.05561251e-01, -1.02465016e-01, -9.85701457e-02, - -9.38468492e-02, -8.82630999e-02, -8.17879272e-02, -7.43878560e-02, - -6.60218980e-02, -5.66565564e-02, -4.62445689e-02, -3.47458578e-02, - -2.21158161e-02, -8.31042570e-03, 6.71769764e-03, 2.30064206e-02, - 4.06010646e-02, 5.95323909e-02, 7.98335419e-02, 1.01523314e-01, - 1.24617139e-01, 1.49115252e-01, 1.75006740e-01, 2.02269985e-01, - 2.30865538e-01, 2.60736512e-01, 2.91814469e-01, 3.24009570e-01, - 3.57217518e-01, 3.91314689e-01, 4.26157164e-01, 4.61592545e-01, - 4.97447159e-01, 5.33532682e-01, 5.69654673e-01, 6.05608382e-01, - 6.41183084e-01, 6.76165350e-01, 7.10340055e-01, 7.43494372e-01, - 7.75428189e-01, 8.05943723e-01, 8.34858937e-01, 8.62010834e-01, - 8.87259971e-01, 9.10486312e-01, 9.31596250e-01, 9.50522086e-01, - 9.67236671e-01, 9.81739750e-01, 9.94055718e-01, 1.00424751e+00, - 1.01240743e+00, 1.01865099e+00, 1.02311884e+00, 1.02597245e+00, - 1.02739752e+00, 1.02758583e+00, 1.02673867e+00, 1.02506178e+00, - 1.02275651e+00, 1.02000914e+00, 1.01699650e+00, 1.01391595e+00, - 1.01104487e+00, 1.00777386e+00, 1.00484875e+00, 1.00224501e+00, - 9.99939317e-01, 9.97905542e-01, 9.96120338e-01, 9.94559753e-01, - 9.93203161e-01, 9.92029727e-01, 9.91023065e-01, 9.90166895e-01, - 9.89448837e-01, 9.88855636e-01, 9.88377852e-01, 9.88005163e-01, - 9.87729546e-01, 9.87541274e-01, 9.87432981e-01, 9.87394992e-01, - 9.87419705e-01, 9.87497321e-01, 9.87620124e-01, 9.87778192e-01, - 9.87963798e-01, 9.88167801e-01, 9.88383520e-01, 9.88602222e-01, - 9.88818277e-01, 9.89024798e-01, 9.89217866e-01, 9.89392368e-01, - 9.89546334e-01, 9.89677201e-01, 9.89785920e-01, 9.89872536e-01, - 9.89941079e-01, 9.89994556e-01, 9.90039402e-01, 9.90081472e-01, - 9.90129379e-01, 9.90190227e-01, 9.90273445e-01, 9.90386228e-01, - 9.90537983e-01, 9.90734883e-01, 9.90984259e-01, 9.91290512e-01, - 9.91658694e-01, 9.92090615e-01, 9.92588721e-01, 9.93151653e-01, - 9.93779087e-01, 9.94466818e-01, 9.95211663e-01, 9.96006862e-01, - 9.96846133e-01, 9.97720337e-01, 9.98621352e-01, 9.99538258e-01, - 1.00046196e+00, 1.00138055e+00, 1.00228487e+00, 1.00316385e+00, - 1.00400915e+00, 1.00481138e+00, 1.00556397e+00, 1.00625986e+00, - 1.00689557e+00, 1.00746662e+00, 1.00797244e+00, 1.00841147e+00, - 1.00878601e+00, 1.00909776e+00, 1.00935176e+00, 1.00955240e+00, - 1.00970709e+00, 1.00982209e+00, 1.00990696e+00, 1.00996902e+00, - 1.01001789e+00, 1.01006081e+00, 1.01010656e+00, 1.01016113e+00, - 1.01023108e+00, 1.01031948e+00, 1.01043047e+00, 1.01056410e+00, - 1.01072136e+00, 1.01089966e+00, 1.01109699e+00, 1.01130817e+00, - 1.01152919e+00, 1.01175301e+00, 1.01197388e+00, 1.01218284e+00, - 1.01237303e+00, 1.01253506e+00, 1.01266098e+00, 1.01274058e+00, - 1.01276592e+00, 1.01272696e+00, 1.01261590e+00, 1.01242289e+00, - 1.01214046e+00, 1.01175881e+00, 1.01126996e+00, 1.01066368e+00, - 1.00993075e+00, 1.00905825e+00, 1.00803431e+00, 1.00684335e+00, - 1.00547001e+00, 1.00389477e+00, 1.00209885e+00, 1.00006069e+00, - 9.97760020e-01, 9.95174643e-01, 9.92286108e-01, 9.89075787e-01, - 9.84736245e-01, 9.79861353e-01, 9.74137862e-01, 9.67333198e-01, - 9.59253976e-01, 9.49698408e-01, 9.38463416e-01, 9.25356797e-01, - 9.10198679e-01, 8.92833832e-01, 8.73143784e-01, 8.51042044e-01, - 8.26483991e-01, 7.99468149e-01, 7.70043128e-01, 7.38302860e-01, - 7.04381434e-01, 6.68461648e-01, 6.30775533e-01, 5.91579959e-01, - 5.51170316e-01, 5.09891542e-01, 4.68101711e-01, 4.26177297e-01, - 3.84517234e-01, 3.43522867e-01, 3.03600465e-01, 2.65143468e-01, - 2.28528397e-01, 1.94102191e-01, 1.62173542e-01, 1.33001524e-01, - 1.06784043e-01, 8.36505724e-02, 6.36518811e-02, 4.67653841e-02, - 3.28807275e-02, 2.18305756e-02, 1.33638143e-02, 6.75812489e-03, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_10M_240 = np.array([ - -3.61349642e-04, -7.07854671e-04, -1.07444364e-03, -1.53347854e-03, - -2.09819773e-03, -2.77842087e-03, -3.58412992e-03, -4.52519808e-03, - -5.60932724e-03, -6.84323454e-03, -8.23397633e-03, -9.78531476e-03, - -1.14988030e-02, -1.33771310e-02, -1.54218168e-02, -1.76297991e-02, - -1.99972156e-02, -2.25208056e-02, -2.51940630e-02, -2.80090946e-02, - -3.09576509e-02, -3.40299627e-02, -3.72150208e-02, -4.05005325e-02, - -4.38721922e-02, -4.73176826e-02, -5.08232534e-02, -5.43716664e-02, - -5.79465483e-02, -6.15342620e-02, -6.51170816e-02, -6.86760675e-02, - -7.21944781e-02, -7.56569598e-02, -7.90464744e-02, -8.23444256e-02, - -8.55332458e-02, -8.85970547e-02, -9.15209110e-02, -9.42884745e-02, - -9.68830362e-02, -9.92912326e-02, -1.01500847e-01, -1.03496124e-01, - -1.05263700e-01, -1.06793998e-01, -1.08076646e-01, -1.09099730e-01, - -1.09852449e-01, -1.10324226e-01, -1.10508462e-01, -1.10397741e-01, - -1.09980985e-01, -1.09249277e-01, -1.08197423e-01, -1.06817214e-01, - -1.05099580e-01, -1.03036011e-01, -1.00619042e-01, -9.78412002e-02, - -9.46930422e-02, -9.11645251e-02, -8.72464453e-02, -8.29304391e-02, - -7.82061748e-02, -7.30614243e-02, -6.74846818e-02, -6.14668812e-02, - -5.49949726e-02, -4.80544442e-02, -4.06336286e-02, -3.27204559e-02, - -2.43012258e-02, -1.53632952e-02, -5.89143427e-03, 4.12659586e-03, - 1.47015507e-02, 2.58473819e-02, 3.75765277e-02, 4.98973651e-02, - 6.28203403e-02, 7.63539773e-02, 9.05036926e-02, 1.05274712e-01, - 1.20670347e-01, 1.36691102e-01, 1.53334389e-01, 1.70595471e-01, - 1.88468639e-01, 2.06944996e-01, 2.26009300e-01, 2.45645680e-01, - 2.65834602e-01, 2.86554381e-01, 3.07778908e-01, 3.29476944e-01, - 3.51617148e-01, 3.74164237e-01, 3.97073959e-01, 4.20304305e-01, - 4.43811480e-01, 4.67544229e-01, 4.91449863e-01, 5.15473546e-01, - 5.39555764e-01, 5.63639982e-01, 5.87666172e-01, 6.11569531e-01, - 6.35289059e-01, 6.58761977e-01, 6.81923097e-01, 7.04709282e-01, - 7.27057670e-01, 7.48906896e-01, 7.70199019e-01, 7.90875299e-01, - 8.10878869e-01, 8.30157914e-01, 8.48664336e-01, 8.66354816e-01, - 8.83189685e-01, 8.99132024e-01, 9.14154056e-01, 9.28228255e-01, - 9.41334815e-01, 9.53461939e-01, 9.64604825e-01, 9.74763483e-01, - 9.83943539e-01, 9.92152910e-01, 9.99411473e-01, 1.00574608e+00, - 1.01118397e+00, 1.01576037e+00, 1.01951507e+00, 1.02249094e+00, - 1.02473616e+00, 1.02630410e+00, 1.02725098e+00, 1.02763429e+00, - 1.02751106e+00, 1.02694280e+00, 1.02599149e+00, 1.02471615e+00, - 1.02317598e+00, 1.02142721e+00, 1.01952157e+00, 1.01751012e+00, - 1.01543986e+00, 1.01346092e+00, 1.01165490e+00, 1.00936693e+00, - 1.00726318e+00, 1.00531319e+00, 1.00350816e+00, 1.00184079e+00, - 1.00030393e+00, 9.98889821e-01, 9.97591528e-01, 9.96401528e-01, - 9.95313390e-01, 9.94320108e-01, 9.93415896e-01, 9.92594392e-01, - 9.91851028e-01, 9.91179799e-01, 9.90577196e-01, 9.90038105e-01, - 9.89559439e-01, 9.89137162e-01, 9.88768437e-01, 9.88449792e-01, - 9.88179075e-01, 9.87952836e-01, 9.87769137e-01, 9.87624927e-01, - 9.87517995e-01, 9.87445813e-01, 9.87405628e-01, 9.87395112e-01, - 9.87411537e-01, 9.87452485e-01, 9.87514989e-01, 9.87596889e-01, - 9.87695113e-01, 9.87807582e-01, 9.87931200e-01, 9.88064062e-01, - 9.88203257e-01, 9.88347108e-01, 9.88492687e-01, 9.88638659e-01, - 9.88782558e-01, 9.88923003e-01, 9.89058172e-01, 9.89186767e-01, - 9.89307497e-01, 9.89419640e-01, 9.89522076e-01, 9.89614633e-01, - 9.89697035e-01, 9.89769260e-01, 9.89831927e-01, 9.89885257e-01, - 9.89930764e-01, 9.89969310e-01, 9.90002569e-01, 9.90032156e-01, - 9.90060335e-01, 9.90088981e-01, 9.90120659e-01, 9.90157502e-01, - 9.90202395e-01, 9.90257541e-01, 9.90325529e-01, 9.90408791e-01, - 9.90509649e-01, 9.90630379e-01, 9.90772711e-01, 9.90938744e-01, - 9.91129889e-01, 9.91347632e-01, 9.91592856e-01, 9.91866549e-01, - 9.92169132e-01, 9.92501085e-01, 9.92861973e-01, 9.93251918e-01, - 9.93670021e-01, 9.94115607e-01, 9.94587315e-01, 9.95083740e-01, - 9.95603378e-01, 9.96143992e-01, 9.96703453e-01, 9.97279311e-01, - 9.97869086e-01, 9.98469709e-01, 9.99078484e-01, 9.99691901e-01, - 1.00030819e+00, 1.00092237e+00, 1.00153264e+00, 1.00213546e+00, - 1.00272811e+00, 1.00330745e+00, 1.00387093e+00, 1.00441604e+00, - 1.00494055e+00, 1.00544214e+00, 1.00591922e+00, 1.00637030e+00, - 1.00679393e+00, 1.00718935e+00, 1.00755557e+00, 1.00789267e+00, - 1.00820015e+00, 1.00847842e+00, 1.00872788e+00, 1.00894949e+00, - 1.00914411e+00, 1.00931322e+00, 1.00945824e+00, 1.00958128e+00, - 1.00968409e+00, 1.00976898e+00, 1.00983831e+00, 1.00989455e+00, - 1.00994034e+00, 1.00997792e+00, 1.01001023e+00, 1.01003945e+00, - 1.01006820e+00, 1.01009839e+00, 1.01013232e+00, 1.01017166e+00, - 1.01021810e+00, 1.01027252e+00, 1.01033649e+00, 1.01041022e+00, - 1.01049435e+00, 1.01058887e+00, 1.01069350e+00, 1.01080807e+00, - 1.01093144e+00, 1.01106288e+00, 1.01120107e+00, 1.01134470e+00, - 1.01149190e+00, 1.01164127e+00, 1.01179028e+00, 1.01193757e+00, - 1.01208013e+00, 1.01221624e+00, 1.01234291e+00, 1.01245818e+00, - 1.01255888e+00, 1.01264286e+00, 1.01270696e+00, 1.01274895e+00, - 1.01276580e+00, 1.01275501e+00, 1.01271380e+00, 1.01263978e+00, - 1.01253013e+00, 1.01238231e+00, 1.01219407e+00, 1.01196233e+00, - 1.01168517e+00, 1.01135914e+00, 1.01098214e+00, 1.01055072e+00, - 1.01006213e+00, 1.00951244e+00, 1.00889869e+00, 1.00821592e+00, - 1.00746086e+00, 1.00662774e+00, 1.00571234e+00, 1.00470868e+00, - 1.00361147e+00, 1.00241429e+00, 1.00111141e+00, 9.99696165e-01, - 9.98162595e-01, 9.96504102e-01, 9.94714888e-01, 9.92789191e-01, - 9.90720000e-01, 9.88479371e-01, 9.85534766e-01, 9.82376587e-01, - 9.78974733e-01, 9.75162381e-01, 9.70882175e-01, 9.66080552e-01, - 9.60697640e-01, 9.54673298e-01, 9.47947935e-01, 9.40460905e-01, - 9.32155386e-01, 9.22977548e-01, 9.12874535e-01, 9.01800368e-01, - 8.89716328e-01, 8.76590897e-01, 8.62398408e-01, 8.47120080e-01, - 8.30747973e-01, 8.13281737e-01, 7.94729145e-01, 7.75110884e-01, - 7.54455197e-01, 7.32796355e-01, 7.10179084e-01, 6.86658072e-01, - 6.62296243e-01, 6.37168412e-01, 6.11348804e-01, 5.84920660e-01, - 5.57974743e-01, 5.30618165e-01, 5.02952396e-01, 4.75086883e-01, - 4.47130985e-01, 4.19204992e-01, 3.91425291e-01, 3.63911468e-01, - 3.36783777e-01, 3.10162784e-01, 2.84164703e-01, 2.58903371e-01, - 2.34488060e-01, 2.11020945e-01, 1.88599764e-01, 1.67310081e-01, - 1.47228797e-01, 1.28422307e-01, 1.10942255e-01, 9.48266535e-02, - 8.00991437e-02, 6.67676585e-02, 5.48243661e-02, 4.42458885e-02, - 3.49936100e-02, 2.70146141e-02, 2.02437018e-02, 1.46079676e-02, - 9.99674359e-03, 5.30523510e-03, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_10M_320 = np.array([ - -3.02115349e-04, -5.86773749e-04, -8.36650400e-04, -1.12663536e-03, - -1.47049294e-03, -1.87347339e-03, -2.33929236e-03, -2.87200807e-03, - -3.47625639e-03, -4.15596382e-03, -4.91456379e-03, -5.75517250e-03, - -6.68062338e-03, -7.69381692e-03, -8.79676075e-03, -9.99050307e-03, - -1.12757412e-02, -1.26533415e-02, -1.41243899e-02, -1.56888962e-02, - -1.73451209e-02, -1.90909737e-02, -2.09254671e-02, -2.28468479e-02, - -2.48520772e-02, -2.69374670e-02, -2.90995249e-02, -3.13350463e-02, - -3.36396073e-02, -3.60082097e-02, -3.84360174e-02, -4.09174603e-02, - -4.34465489e-02, -4.60178672e-02, -4.86259851e-02, -5.12647420e-02, - -5.39264475e-02, -5.66038431e-02, -5.92911675e-02, -6.19826820e-02, - -6.46702555e-02, -6.73454222e-02, -7.00009902e-02, -7.26305701e-02, - -7.52278496e-02, -7.77852594e-02, -8.02948025e-02, -8.27492454e-02, - -8.51412546e-02, -8.74637912e-02, -8.97106934e-02, -9.18756408e-02, - -9.39517698e-02, -9.59313774e-02, -9.78084326e-02, -9.95785130e-02, - -1.01236117e-01, -1.02774104e-01, -1.04186122e-01, -1.05468025e-01, - -1.06616088e-01, -1.07625538e-01, -1.08491230e-01, -1.09208742e-01, - -1.09773615e-01, -1.10180886e-01, -1.10427188e-01, -1.10510836e-01, - -1.10428147e-01, -1.10173922e-01, -1.09743736e-01, -1.09135313e-01, - -1.08346734e-01, -1.07373994e-01, -1.06213016e-01, -1.04860615e-01, - -1.03313240e-01, -1.01567316e-01, -9.96200551e-02, -9.74680323e-02, - -9.51072362e-02, -9.25330338e-02, -8.97412522e-02, -8.67287769e-02, - -8.34921384e-02, -8.00263990e-02, -7.63267954e-02, -7.23880616e-02, - -6.82057680e-02, -6.37761143e-02, -5.90938600e-02, -5.41531632e-02, - -4.89481272e-02, -4.34734711e-02, -3.77246130e-02, -3.16958761e-02, - -2.53817983e-02, -1.87768910e-02, -1.18746138e-02, -4.66909925e-03, - 2.84409675e-03, 1.06697612e-02, 1.88135595e-02, 2.72815601e-02, - 3.60781047e-02, 4.52070276e-02, 5.46723880e-02, 6.44786605e-02, - 7.46286220e-02, 8.51249057e-02, 9.59698399e-02, 1.07165078e-01, - 1.18711585e-01, 1.30610107e-01, 1.42859645e-01, 1.55458473e-01, - 1.68404161e-01, 1.81694789e-01, 1.95327388e-01, 2.09296321e-01, - 2.23594564e-01, 2.38216022e-01, 2.53152972e-01, 2.68396157e-01, - 2.83936139e-01, 2.99762426e-01, 3.15861908e-01, 3.32221055e-01, - 3.48826468e-01, 3.65664038e-01, 3.82715297e-01, 3.99961186e-01, - 4.17384327e-01, 4.34966962e-01, 4.52687640e-01, 4.70524201e-01, - 4.88453925e-01, 5.06454555e-01, 5.24500675e-01, 5.42567437e-01, - 5.60631204e-01, 5.78667265e-01, 5.96647704e-01, 6.14545890e-01, - 6.32336194e-01, 6.49992632e-01, 6.67487403e-01, 6.84793267e-01, - 7.01883546e-01, 7.18732254e-01, 7.35312821e-01, 7.51600199e-01, - 7.67569925e-01, 7.83197457e-01, 7.98458386e-01, 8.13329535e-01, - 8.27789227e-01, 8.41817856e-01, 8.55396130e-01, 8.68506898e-01, - 8.81133444e-01, 8.93259678e-01, 9.04874884e-01, 9.15965761e-01, - 9.26521530e-01, 9.36533999e-01, 9.45997703e-01, 9.54908841e-01, - 9.63265812e-01, 9.71068890e-01, 9.78320416e-01, 9.85022676e-01, - 9.91179208e-01, 9.96798994e-01, 1.00189402e+00, 1.00647434e+00, - 1.01055206e+00, 1.01414254e+00, 1.01726259e+00, 1.01992884e+00, - 1.02215987e+00, 1.02397632e+00, 1.02540073e+00, 1.02645534e+00, - 1.02716451e+00, 1.02755273e+00, 1.02764446e+00, 1.02746325e+00, - 1.02703590e+00, 1.02638907e+00, 1.02554820e+00, 1.02453713e+00, - 1.02338080e+00, 1.02210370e+00, 1.02072836e+00, 1.01927533e+00, - 1.01776518e+00, 1.01621736e+00, 1.01466531e+00, 1.01324907e+00, - 1.01194801e+00, 1.01018909e+00, 1.00855796e+00, 1.00701129e+00, - 1.00554876e+00, 1.00416842e+00, 1.00286727e+00, 1.00164177e+00, - 1.00048907e+00, 9.99406080e-01, 9.98389887e-01, 9.97437085e-01, - 9.96544484e-01, 9.95709855e-01, 9.94930241e-01, 9.94202405e-01, - 9.93524160e-01, 9.92893043e-01, 9.92306810e-01, 9.91763378e-01, - 9.91259764e-01, 9.90795450e-01, 9.90367789e-01, 9.89975161e-01, - 9.89616034e-01, 9.89289016e-01, 9.88992851e-01, 9.88726033e-01, - 9.88486872e-01, 9.88275104e-01, 9.88089217e-01, 9.87927711e-01, - 9.87789826e-01, 9.87674344e-01, 9.87580750e-01, 9.87507202e-01, - 9.87452945e-01, 9.87416974e-01, 9.87398469e-01, 9.87395830e-01, - 9.87408003e-01, 9.87434340e-01, 9.87473624e-01, 9.87524314e-01, - 9.87585620e-01, 9.87656379e-01, 9.87735892e-01, 9.87822558e-01, - 9.87915097e-01, 9.88013273e-01, 9.88115695e-01, 9.88221131e-01, - 9.88328903e-01, 9.88437831e-01, 9.88547679e-01, 9.88656841e-01, - 9.88764587e-01, 9.88870854e-01, 9.88974432e-01, 9.89074727e-01, - 9.89171004e-01, 9.89263102e-01, 9.89350722e-01, 9.89433065e-01, - 9.89509692e-01, 9.89581081e-01, 9.89646747e-01, 9.89706737e-01, - 9.89760693e-01, 9.89809448e-01, 9.89853013e-01, 9.89891471e-01, - 9.89925419e-01, 9.89955420e-01, 9.89982449e-01, 9.90006512e-01, - 9.90028481e-01, 9.90049748e-01, 9.90070956e-01, 9.90092836e-01, - 9.90116392e-01, 9.90142748e-01, 9.90173428e-01, 9.90208733e-01, - 9.90249864e-01, 9.90298369e-01, 9.90354850e-01, 9.90420508e-01, - 9.90495930e-01, 9.90582515e-01, 9.90681257e-01, 9.90792209e-01, - 9.90916546e-01, 9.91055074e-01, 9.91208461e-01, 9.91376861e-01, - 9.91560583e-01, 9.91760421e-01, 9.91976718e-01, 9.92209110e-01, - 9.92457914e-01, 9.92723123e-01, 9.93004954e-01, 9.93302728e-01, - 9.93616108e-01, 9.93945371e-01, 9.94289515e-01, 9.94648168e-01, - 9.95020303e-01, 9.95405817e-01, 9.95803871e-01, 9.96213027e-01, - 9.96632469e-01, 9.97061531e-01, 9.97499058e-01, 9.97943743e-01, - 9.98394057e-01, 9.98849312e-01, 9.99308343e-01, 9.99768922e-01, - 1.00023113e+00, 1.00069214e+00, 1.00115201e+00, 1.00160853e+00, - 1.00206049e+00, 1.00250721e+00, 1.00294713e+00, 1.00337891e+00, - 1.00380137e+00, 1.00421381e+00, 1.00461539e+00, 1.00500462e+00, - 1.00538063e+00, 1.00574328e+00, 1.00609151e+00, 1.00642491e+00, - 1.00674243e+00, 1.00704432e+00, 1.00733022e+00, 1.00759940e+00, - 1.00785206e+00, 1.00808818e+00, 1.00830803e+00, 1.00851125e+00, - 1.00869814e+00, 1.00886952e+00, 1.00902566e+00, 1.00916672e+00, - 1.00929336e+00, 1.00940640e+00, 1.00950702e+00, 1.00959526e+00, - 1.00967215e+00, 1.00973908e+00, 1.00979668e+00, 1.00984614e+00, - 1.00988808e+00, 1.00992409e+00, 1.00995538e+00, 1.00998227e+00, - 1.01000630e+00, 1.01002862e+00, 1.01005025e+00, 1.01007195e+00, - 1.01009437e+00, 1.01011892e+00, 1.01014650e+00, 1.01017711e+00, - 1.01021176e+00, 1.01025100e+00, 1.01029547e+00, 1.01034523e+00, - 1.01040032e+00, 1.01046156e+00, 1.01052862e+00, 1.01060152e+00, - 1.01067979e+00, 1.01076391e+00, 1.01085343e+00, 1.01094755e+00, - 1.01104595e+00, 1.01114849e+00, 1.01125440e+00, 1.01136308e+00, - 1.01147330e+00, 1.01158500e+00, 1.01169742e+00, 1.01180892e+00, - 1.01191926e+00, 1.01202724e+00, 1.01213215e+00, 1.01223273e+00, - 1.01232756e+00, 1.01241638e+00, 1.01249789e+00, 1.01257043e+00, - 1.01263330e+00, 1.01268528e+00, 1.01272556e+00, 1.01275258e+00, - 1.01276506e+00, 1.01276236e+00, 1.01274338e+00, 1.01270648e+00, - 1.01265084e+00, 1.01257543e+00, 1.01247947e+00, 1.01236111e+00, - 1.01221981e+00, 1.01205436e+00, 1.01186400e+00, 1.01164722e+00, - 1.01140252e+00, 1.01112965e+00, 1.01082695e+00, 1.01049292e+00, - 1.01012635e+00, 1.00972589e+00, 1.00929006e+00, 1.00881730e+00, - 1.00830503e+00, 1.00775283e+00, 1.00715783e+00, 1.00651805e+00, - 1.00583140e+00, 1.00509559e+00, 1.00430863e+00, 1.00346750e+00, - 1.00256950e+00, 1.00161271e+00, 1.00059427e+00, 9.99511170e-01, - 9.98360922e-01, 9.97140929e-01, 9.95848886e-01, 9.94481854e-01, - 9.93037528e-01, 9.91514656e-01, 9.89913680e-01, 9.88193062e-01, - 9.85942259e-01, 9.83566790e-01, 9.81142303e-01, 9.78521444e-01, - 9.75663604e-01, 9.72545344e-01, 9.69145663e-01, 9.65440618e-01, - 9.61404362e-01, 9.57011307e-01, 9.52236767e-01, 9.47054884e-01, - 9.41440374e-01, 9.35369161e-01, 9.28819009e-01, 9.21766289e-01, - 9.14189628e-01, 9.06069468e-01, 8.97389168e-01, 8.88133200e-01, - 8.78289389e-01, 8.67846957e-01, 8.56797064e-01, 8.45133465e-01, - 8.32854281e-01, 8.19959478e-01, 8.06451101e-01, 7.92334648e-01, - 7.77620449e-01, 7.62320618e-01, 7.46448649e-01, 7.30020573e-01, - 7.13056738e-01, 6.95580544e-01, 6.77617323e-01, 6.59195531e-01, - 6.40348643e-01, 6.21107220e-01, 6.01504928e-01, 5.81578761e-01, - 5.61367451e-01, 5.40918863e-01, 5.20273683e-01, 4.99478073e-01, - 4.78577418e-01, 4.57617260e-01, 4.36649021e-01, 4.15722146e-01, - 3.94885659e-01, 3.74190319e-01, 3.53686890e-01, 3.33426002e-01, - 3.13458647e-01, 2.93833790e-01, 2.74599264e-01, 2.55803064e-01, - 2.37490219e-01, 2.19703603e-01, 2.02485542e-01, 1.85874992e-01, - 1.69906780e-01, 1.54613227e-01, 1.40023821e-01, 1.26163740e-01, - 1.13053443e-01, 1.00708497e-01, 8.91402439e-02, 7.83561210e-02, - 6.83582123e-02, 5.91421154e-02, 5.06989301e-02, 4.30171776e-02, - 3.60802073e-02, 2.98631634e-02, 2.43372266e-02, 1.94767524e-02, - 1.52571017e-02, 1.16378749e-02, 8.43308778e-03, 4.44966900e-03, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_10M_480 = np.array([ - -2.35303215e-04, -4.61989875e-04, -6.26293154e-04, -7.92918043e-04, - -9.74716672e-04, -1.18025689e-03, -1.40920904e-03, -1.66447310e-03, - -1.94659161e-03, -2.25708173e-03, -2.59710692e-03, -2.96760762e-03, - -3.37045488e-03, -3.80628516e-03, -4.27687377e-03, -4.78246990e-03, - -5.32460872e-03, -5.90340381e-03, -6.52041973e-03, -7.17588528e-03, - -7.87142282e-03, -8.60658604e-03, -9.38248086e-03, -1.01982718e-02, - -1.10552055e-02, -1.19527030e-02, -1.28920591e-02, -1.38726348e-02, - -1.48952816e-02, -1.59585662e-02, -1.70628856e-02, -1.82066640e-02, - -1.93906598e-02, -2.06135542e-02, -2.18757093e-02, -2.31752632e-02, - -2.45122745e-02, -2.58847194e-02, -2.72926374e-02, -2.87339090e-02, - -3.02086274e-02, -3.17144037e-02, -3.32509886e-02, -3.48159779e-02, - -3.64089241e-02, -3.80274232e-02, -3.96706799e-02, -4.13357542e-02, - -4.30220337e-02, -4.47269805e-02, -4.64502229e-02, -4.81889149e-02, - -4.99422586e-02, -5.17069080e-02, -5.34816204e-02, -5.52633479e-02, - -5.70512315e-02, -5.88427175e-02, -6.06371724e-02, -6.24310403e-02, - -6.42230355e-02, -6.60096152e-02, -6.77896227e-02, -6.95599687e-02, - -7.13196627e-02, -7.30658127e-02, -7.47975891e-02, -7.65117823e-02, - -7.82071142e-02, -7.98801069e-02, -8.15296401e-02, -8.31523735e-02, - -8.47472895e-02, -8.63113754e-02, -8.78437445e-02, -8.93416436e-02, - -9.08041129e-02, -9.22279576e-02, -9.36123287e-02, -9.49537776e-02, - -9.62515531e-02, -9.75028462e-02, -9.87073651e-02, -9.98627129e-02, - -1.00968022e-01, -1.02020268e-01, -1.03018380e-01, -1.03959636e-01, - -1.04843883e-01, -1.05668684e-01, -1.06434282e-01, -1.07138231e-01, - -1.07779996e-01, -1.08357063e-01, -1.08869014e-01, -1.09313559e-01, - -1.09690356e-01, -1.09996966e-01, -1.10233226e-01, -1.10397281e-01, - -1.10489847e-01, -1.10508642e-01, -1.10453743e-01, -1.10322584e-01, - -1.10114583e-01, -1.09827693e-01, -1.09462175e-01, -1.09016396e-01, - -1.08490885e-01, -1.07883429e-01, -1.07193718e-01, -1.06419636e-01, - -1.05561251e-01, -1.04616281e-01, -1.03584904e-01, -1.02465016e-01, - -1.01256900e-01, -9.99586457e-02, -9.85701457e-02, -9.70891114e-02, - -9.55154582e-02, -9.38468492e-02, -9.20830006e-02, -9.02217102e-02, - -8.82630999e-02, -8.62049382e-02, -8.40474215e-02, -8.17879272e-02, - -7.94262503e-02, -7.69598078e-02, -7.43878560e-02, -7.17079700e-02, - -6.89199478e-02, -6.60218980e-02, -6.30134942e-02, -5.98919191e-02, - -5.66565564e-02, -5.33040616e-02, -4.98342724e-02, -4.62445689e-02, - -4.25345569e-02, -3.87019577e-02, -3.47458578e-02, -3.06634152e-02, - -2.64542508e-02, -2.21158161e-02, -1.76474054e-02, -1.30458136e-02, - -8.31042570e-03, -3.43826866e-03, 1.57031548e-03, 6.71769764e-03, - 1.20047702e-02, 1.74339832e-02, 2.30064206e-02, 2.87248142e-02, - 3.45889635e-02, 4.06010646e-02, 4.67610292e-02, 5.30713391e-02, - 5.95323909e-02, 6.61464781e-02, 7.29129318e-02, 7.98335419e-02, - 8.69080741e-02, 9.41381377e-02, 1.01523314e-01, 1.09065152e-01, - 1.16762655e-01, 1.24617139e-01, 1.32627295e-01, 1.40793819e-01, - 1.49115252e-01, 1.57592141e-01, 1.66222480e-01, 1.75006740e-01, - 1.83943194e-01, 1.93031818e-01, 2.02269985e-01, 2.11656743e-01, - 2.21188852e-01, 2.30865538e-01, 2.40683799e-01, 2.50642064e-01, - 2.60736512e-01, 2.70965907e-01, 2.81325902e-01, 2.91814469e-01, - 3.02427028e-01, 3.13160350e-01, 3.24009570e-01, 3.34971959e-01, - 3.46042294e-01, 3.57217518e-01, 3.68491565e-01, 3.79859512e-01, - 3.91314689e-01, 4.02853287e-01, 4.14468833e-01, 4.26157164e-01, - 4.37911390e-01, 4.49725632e-01, 4.61592545e-01, 4.73506703e-01, - 4.85460018e-01, 4.97447159e-01, 5.09459723e-01, 5.21490984e-01, - 5.33532682e-01, 5.45578981e-01, 5.57621716e-01, 5.69654673e-01, - 5.81668558e-01, 5.93656062e-01, 6.05608382e-01, 6.17519206e-01, - 6.29379661e-01, 6.41183084e-01, 6.52920354e-01, 6.64584079e-01, - 6.76165350e-01, 6.87657395e-01, 6.99051154e-01, 7.10340055e-01, - 7.21514933e-01, 7.32569177e-01, 7.43494372e-01, 7.54284633e-01, - 7.64931365e-01, 7.75428189e-01, 7.85767017e-01, 7.95941465e-01, - 8.05943723e-01, 8.15768707e-01, 8.25408622e-01, 8.34858937e-01, - 8.44112583e-01, 8.53165119e-01, 8.62010834e-01, 8.70645634e-01, - 8.79063156e-01, 8.87259971e-01, 8.95231329e-01, 9.02975168e-01, - 9.10486312e-01, 9.17762555e-01, 9.24799743e-01, 9.31596250e-01, - 9.38149486e-01, 9.44458839e-01, 9.50522086e-01, 9.56340292e-01, - 9.61911452e-01, 9.67236671e-01, 9.72315664e-01, 9.77150119e-01, - 9.81739750e-01, 9.86086587e-01, 9.90190638e-01, 9.94055718e-01, - 9.97684240e-01, 1.00108096e+00, 1.00424751e+00, 1.00718858e+00, - 1.00990665e+00, 1.01240743e+00, 1.01469470e+00, 1.01677466e+00, - 1.01865099e+00, 1.02033046e+00, 1.02181733e+00, 1.02311884e+00, - 1.02424026e+00, 1.02518972e+00, 1.02597245e+00, 1.02659694e+00, - 1.02706918e+00, 1.02739752e+00, 1.02758790e+00, 1.02764895e+00, - 1.02758583e+00, 1.02740852e+00, 1.02712299e+00, 1.02673867e+00, - 1.02626166e+00, 1.02570100e+00, 1.02506178e+00, 1.02435398e+00, - 1.02358239e+00, 1.02275651e+00, 1.02188060e+00, 1.02096387e+00, - 1.02000914e+00, 1.01902729e+00, 1.01801944e+00, 1.01699650e+00, - 1.01595743e+00, 1.01492344e+00, 1.01391595e+00, 1.01304757e+00, - 1.01221613e+00, 1.01104487e+00, 1.00991459e+00, 1.00882489e+00, - 1.00777386e+00, 1.00676170e+00, 1.00578665e+00, 1.00484875e+00, - 1.00394608e+00, 1.00307885e+00, 1.00224501e+00, 1.00144473e+00, - 1.00067619e+00, 9.99939317e-01, 9.99232085e-01, 9.98554813e-01, - 9.97905542e-01, 9.97284268e-01, 9.96689095e-01, 9.96120338e-01, - 9.95576126e-01, 9.95056572e-01, 9.94559753e-01, 9.94086038e-01, - 9.93633779e-01, 9.93203161e-01, 9.92792187e-01, 9.92401518e-01, - 9.92029727e-01, 9.91676778e-01, 9.91340877e-01, 9.91023065e-01, - 9.90721643e-01, 9.90436680e-01, 9.90166895e-01, 9.89913101e-01, - 9.89673564e-01, 9.89448837e-01, 9.89237484e-01, 9.89040193e-01, - 9.88855636e-01, 9.88684347e-01, 9.88524761e-01, 9.88377852e-01, - 9.88242327e-01, 9.88118564e-01, 9.88005163e-01, 9.87903202e-01, - 9.87811174e-01, 9.87729546e-01, 9.87657198e-01, 9.87594984e-01, - 9.87541274e-01, 9.87496906e-01, 9.87460625e-01, 9.87432981e-01, - 9.87412641e-01, 9.87400475e-01, 9.87394992e-01, 9.87396916e-01, - 9.87404906e-01, 9.87419705e-01, 9.87439972e-01, 9.87466328e-01, - 9.87497321e-01, 9.87533893e-01, 9.87574654e-01, 9.87620124e-01, - 9.87668980e-01, 9.87722156e-01, 9.87778192e-01, 9.87837649e-01, - 9.87899199e-01, 9.87963798e-01, 9.88030030e-01, 9.88098468e-01, - 9.88167801e-01, 9.88239030e-01, 9.88310769e-01, 9.88383520e-01, - 9.88456016e-01, 9.88529420e-01, 9.88602222e-01, 9.88674940e-01, - 9.88746626e-01, 9.88818277e-01, 9.88888248e-01, 9.88957438e-01, - 9.89024798e-01, 9.89091125e-01, 9.89155170e-01, 9.89217866e-01, - 9.89277956e-01, 9.89336519e-01, 9.89392368e-01, 9.89446283e-01, - 9.89497212e-01, 9.89546334e-01, 9.89592362e-01, 9.89636265e-01, - 9.89677201e-01, 9.89716220e-01, 9.89752029e-01, 9.89785920e-01, - 9.89817027e-01, 9.89846207e-01, 9.89872536e-01, 9.89897514e-01, - 9.89920005e-01, 9.89941079e-01, 9.89960061e-01, 9.89978226e-01, - 9.89994556e-01, 9.90010350e-01, 9.90024832e-01, 9.90039402e-01, - 9.90053211e-01, 9.90067475e-01, 9.90081472e-01, 9.90096693e-01, - 9.90112245e-01, 9.90129379e-01, 9.90147465e-01, 9.90168060e-01, - 9.90190227e-01, 9.90215190e-01, 9.90242442e-01, 9.90273445e-01, - 9.90307127e-01, 9.90344891e-01, 9.90386228e-01, 9.90432448e-01, - 9.90482565e-01, 9.90537983e-01, 9.90598060e-01, 9.90664037e-01, - 9.90734883e-01, 9.90812038e-01, 9.90894786e-01, 9.90984259e-01, - 9.91079525e-01, 9.91181924e-01, 9.91290512e-01, 9.91406471e-01, - 9.91528801e-01, 9.91658694e-01, 9.91795272e-01, 9.91939622e-01, - 9.92090615e-01, 9.92249503e-01, 9.92415240e-01, 9.92588721e-01, - 9.92768871e-01, 9.92956911e-01, 9.93151653e-01, 9.93353924e-01, - 9.93562689e-01, 9.93779087e-01, 9.94001643e-01, 9.94231202e-01, - 9.94466818e-01, 9.94709344e-01, 9.94957285e-01, 9.95211663e-01, - 9.95471264e-01, 9.95736795e-01, 9.96006862e-01, 9.96282303e-01, - 9.96561799e-01, 9.96846133e-01, 9.97133827e-01, 9.97425669e-01, - 9.97720337e-01, 9.98018509e-01, 9.98318587e-01, 9.98621352e-01, - 9.98925543e-01, 9.99231731e-01, 9.99538258e-01, 9.99846116e-01, - 1.00015391e+00, 1.00046196e+00, 1.00076886e+00, 1.00107561e+00, - 1.00138055e+00, 1.00168424e+00, 1.00198543e+00, 1.00228487e+00, - 1.00258098e+00, 1.00287441e+00, 1.00316385e+00, 1.00345006e+00, - 1.00373157e+00, 1.00400915e+00, 1.00428146e+00, 1.00454934e+00, - 1.00481138e+00, 1.00506827e+00, 1.00531880e+00, 1.00556397e+00, - 1.00580227e+00, 1.00603455e+00, 1.00625986e+00, 1.00647902e+00, - 1.00669054e+00, 1.00689557e+00, 1.00709305e+00, 1.00728380e+00, - 1.00746662e+00, 1.00764273e+00, 1.00781104e+00, 1.00797244e+00, - 1.00812588e+00, 1.00827260e+00, 1.00841147e+00, 1.00854357e+00, - 1.00866802e+00, 1.00878601e+00, 1.00889653e+00, 1.00900077e+00, - 1.00909776e+00, 1.00918888e+00, 1.00927316e+00, 1.00935176e+00, - 1.00942394e+00, 1.00949118e+00, 1.00955240e+00, 1.00960889e+00, - 1.00965997e+00, 1.00970709e+00, 1.00974924e+00, 1.00978774e+00, - 1.00982209e+00, 1.00985371e+00, 1.00988150e+00, 1.00990696e+00, - 1.00992957e+00, 1.00995057e+00, 1.00996902e+00, 1.00998650e+00, - 1.01000236e+00, 1.01001789e+00, 1.01003217e+00, 1.01004672e+00, - 1.01006081e+00, 1.01007567e+00, 1.01009045e+00, 1.01010656e+00, - 1.01012323e+00, 1.01014176e+00, 1.01016113e+00, 1.01018264e+00, - 1.01020559e+00, 1.01023108e+00, 1.01025795e+00, 1.01028773e+00, - 1.01031948e+00, 1.01035408e+00, 1.01039064e+00, 1.01043047e+00, - 1.01047227e+00, 1.01051710e+00, 1.01056410e+00, 1.01061427e+00, - 1.01066629e+00, 1.01072136e+00, 1.01077842e+00, 1.01083825e+00, - 1.01089966e+00, 1.01096373e+00, 1.01102919e+00, 1.01109699e+00, - 1.01116586e+00, 1.01123661e+00, 1.01130817e+00, 1.01138145e+00, - 1.01145479e+00, 1.01152919e+00, 1.01160368e+00, 1.01167880e+00, - 1.01175301e+00, 1.01182748e+00, 1.01190094e+00, 1.01197388e+00, - 1.01204489e+00, 1.01211499e+00, 1.01218284e+00, 1.01224902e+00, - 1.01231210e+00, 1.01237303e+00, 1.01243046e+00, 1.01248497e+00, - 1.01253506e+00, 1.01258168e+00, 1.01262347e+00, 1.01266098e+00, - 1.01269276e+00, 1.01271979e+00, 1.01274058e+00, 1.01275575e+00, - 1.01276395e+00, 1.01276592e+00, 1.01276030e+00, 1.01274782e+00, - 1.01272696e+00, 1.01269861e+00, 1.01266140e+00, 1.01261590e+00, - 1.01256083e+00, 1.01249705e+00, 1.01242289e+00, 1.01233923e+00, - 1.01224492e+00, 1.01214046e+00, 1.01202430e+00, 1.01189756e+00, - 1.01175881e+00, 1.01160845e+00, 1.01144516e+00, 1.01126996e+00, - 1.01108126e+00, 1.01087961e+00, 1.01066368e+00, 1.01043418e+00, - 1.01018968e+00, 1.00993075e+00, 1.00965566e+00, 1.00936525e+00, - 1.00905825e+00, 1.00873476e+00, 1.00839308e+00, 1.00803431e+00, - 1.00765666e+00, 1.00726014e+00, 1.00684335e+00, 1.00640701e+00, - 1.00594915e+00, 1.00547001e+00, 1.00496799e+00, 1.00444353e+00, - 1.00389477e+00, 1.00332190e+00, 1.00272313e+00, 1.00209885e+00, - 1.00144728e+00, 1.00076851e+00, 1.00006069e+00, 9.99324268e-01, - 9.98557350e-01, 9.97760020e-01, 9.96930604e-01, 9.96069427e-01, - 9.95174643e-01, 9.94246644e-01, 9.93283713e-01, 9.92286108e-01, - 9.91252309e-01, 9.90182742e-01, 9.89075787e-01, 9.87931302e-01, - 9.86355322e-01, 9.84736245e-01, 9.83175095e-01, 9.81558334e-01, - 9.79861353e-01, 9.78061749e-01, 9.76157432e-01, 9.74137862e-01, - 9.71999011e-01, 9.69732741e-01, 9.67333198e-01, 9.64791512e-01, - 9.62101150e-01, 9.59253976e-01, 9.56242718e-01, 9.53060091e-01, - 9.49698408e-01, 9.46149812e-01, 9.42407161e-01, 9.38463416e-01, - 9.34311297e-01, 9.29944987e-01, 9.25356797e-01, 9.20540463e-01, - 9.15489628e-01, 9.10198679e-01, 9.04662060e-01, 8.98875519e-01, - 8.92833832e-01, 8.86533719e-01, 8.79971272e-01, 8.73143784e-01, - 8.66047653e-01, 8.58681252e-01, 8.51042044e-01, 8.43129723e-01, - 8.34943514e-01, 8.26483991e-01, 8.17750537e-01, 8.08744982e-01, - 7.99468149e-01, 7.89923516e-01, 7.80113773e-01, 7.70043128e-01, - 7.59714574e-01, 7.49133097e-01, 7.38302860e-01, 7.27229876e-01, - 7.15920192e-01, 7.04381434e-01, 6.92619693e-01, 6.80643883e-01, - 6.68461648e-01, 6.56083014e-01, 6.43517927e-01, 6.30775533e-01, - 6.17864165e-01, 6.04795463e-01, 5.91579959e-01, 5.78228937e-01, - 5.64753589e-01, 5.51170316e-01, 5.37490509e-01, 5.23726350e-01, - 5.09891542e-01, 4.96000807e-01, 4.82066294e-01, 4.68101711e-01, - 4.54121700e-01, 4.40142182e-01, 4.26177297e-01, 4.12241789e-01, - 3.98349961e-01, 3.84517234e-01, 3.70758372e-01, 3.57088679e-01, - 3.43522867e-01, 3.30076376e-01, 3.16764033e-01, 3.03600465e-01, - 2.90599616e-01, 2.77775850e-01, 2.65143468e-01, 2.52716188e-01, - 2.40506985e-01, 2.28528397e-01, 2.16793343e-01, 2.05313990e-01, - 1.94102191e-01, 1.83168087e-01, 1.72522195e-01, 1.62173542e-01, - 1.52132068e-01, 1.42405280e-01, 1.33001524e-01, 1.23926066e-01, - 1.15185830e-01, 1.06784043e-01, 9.87263751e-02, 9.10137900e-02, - 8.36505724e-02, 7.66350831e-02, 6.99703341e-02, 6.36518811e-02, - 5.76817602e-02, 5.20524422e-02, 4.67653841e-02, 4.18095054e-02, - 3.71864025e-02, 3.28807275e-02, 2.88954850e-02, 2.52098057e-02, - 2.18305756e-02, 1.87289619e-02, 1.59212782e-02, 1.33638143e-02, - 1.10855888e-02, 8.94347419e-03, 6.75812489e-03, 3.50443813e-03, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_7M5_60 = np.array([ - 2.95060859e-03, 7.17541132e-03, 1.37695374e-02, 2.30953556e-02, - 3.54036230e-02, 5.08289304e-02, 6.94696293e-02, 9.13884278e-02, - 1.16604575e-01, 1.45073546e-01, 1.76711174e-01, 2.11342953e-01, - 2.48768614e-01, 2.88701102e-01, 3.30823871e-01, 3.74814544e-01, - 4.20308013e-01, 4.66904918e-01, 5.14185341e-01, 5.61710041e-01, - 6.09026346e-01, 6.55671016e-01, 7.01218384e-01, 7.45240679e-01, - 7.87369206e-01, 8.27223833e-01, 8.64513675e-01, 8.98977415e-01, - 9.30407518e-01, 9.58599937e-01, 9.83447719e-01, 1.00488283e+00, - 1.02285381e+00, 1.03740495e+00, 1.04859791e+00, 1.05656184e+00, - 1.06149371e+00, 1.06362578e+00, 1.06325973e+00, 1.06074505e+00, - 1.05643590e+00, 1.05069500e+00, 1.04392435e+00, 1.03647725e+00, - 1.02872867e+00, 1.02106486e+00, 1.01400658e+00, 1.00727455e+00, - 1.00172250e+00, 9.97309592e-01, 9.93985158e-01, 9.91683335e-01, - 9.90325325e-01, 9.89822613e-01, 9.90074734e-01, 9.90975314e-01, - 9.92412851e-01, 9.94273149e-01, 9.96439157e-01, 9.98791616e-01, - 1.00120985e+00, 1.00357357e+00, 1.00575984e+00, 1.00764515e+00, - 1.00910687e+00, 1.01002476e+00, 1.01028203e+00, 1.00976919e+00, - 1.00838641e+00, 1.00605124e+00, 1.00269767e+00, 9.98280464e-01, - 9.92777987e-01, 9.86186892e-01, 9.77634164e-01, 9.67447270e-01, - 9.55129725e-01, 9.40389877e-01, 9.22959280e-01, 9.02607350e-01, - 8.79202689e-01, 8.52641750e-01, 8.22881272e-01, 7.89971715e-01, - 7.54030328e-01, 7.15255742e-01, 6.73936911e-01, 6.30414716e-01, - 5.85078858e-01, 5.38398518e-01, 4.90833753e-01, 4.42885823e-01, - 3.95091024e-01, 3.48004343e-01, 3.02196710e-01, 2.58227431e-01, - 2.16641416e-01, 1.77922122e-01, 1.42480547e-01, 1.10652194e-01, - 8.26995967e-02, 5.88334516e-02, 3.92030848e-02, 2.38629107e-02, - 1.26976223e-02, 5.35665361e-03, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_7M5_120 = np.array([ - 2.20824874e-03, 3.81014420e-03, 5.91552473e-03, 8.58361457e-03, - 1.18759723e-02, 1.58335301e-02, 2.04918652e-02, 2.58883593e-02, - 3.20415894e-02, 3.89616721e-02, 4.66742169e-02, 5.51849337e-02, - 6.45038384e-02, 7.46411071e-02, 8.56000162e-02, 9.73846703e-02, - 1.09993603e-01, 1.23419277e-01, 1.37655457e-01, 1.52690437e-01, - 1.68513363e-01, 1.85093105e-01, 2.02410419e-01, 2.20450365e-01, - 2.39167941e-01, 2.58526168e-01, 2.78498539e-01, 2.99038432e-01, - 3.20104862e-01, 3.41658622e-01, 3.63660034e-01, 3.86062695e-01, - 4.08815272e-01, 4.31871046e-01, 4.55176988e-01, 4.78676593e-01, - 5.02324813e-01, 5.26060916e-01, 5.49831283e-01, 5.73576883e-01, - 5.97241338e-01, 6.20770242e-01, 6.44099662e-01, 6.67176382e-01, - 6.89958854e-01, 7.12379980e-01, 7.34396372e-01, 7.55966688e-01, - 7.77036981e-01, 7.97558114e-01, 8.17490856e-01, 8.36796950e-01, - 8.55447310e-01, 8.73400798e-01, 8.90635719e-01, 9.07128770e-01, - 9.22848784e-01, 9.37763323e-01, 9.51860206e-01, 9.65130600e-01, - 9.77556541e-01, 9.89126209e-01, 9.99846919e-01, 1.00970073e+00, - 1.01868229e+00, 1.02681455e+00, 1.03408981e+00, 1.04051196e+00, - 1.04610837e+00, 1.05088565e+00, 1.05486289e+00, 1.05807221e+00, - 1.06053414e+00, 1.06227662e+00, 1.06333815e+00, 1.06375557e+00, - 1.06356632e+00, 1.06282156e+00, 1.06155996e+00, 1.05981709e+00, - 1.05765876e+00, 1.05512006e+00, 1.05223985e+00, 1.04908779e+00, - 1.04569860e+00, 1.04210831e+00, 1.03838099e+00, 1.03455276e+00, - 1.03067200e+00, 1.02679167e+00, 1.02295558e+00, 1.01920733e+00, - 1.01587289e+00, 1.01221017e+00, 1.00884559e+00, 1.00577851e+00, - 1.00300262e+00, 1.00051460e+00, 9.98309229e-01, 9.96378601e-01, - 9.94718132e-01, 9.93316216e-01, 9.92166957e-01, 9.91258603e-01, - 9.90581104e-01, 9.90123118e-01, 9.89873712e-01, 9.89818707e-01, - 9.89946800e-01, 9.90243175e-01, 9.90695564e-01, 9.91288540e-01, - 9.92009469e-01, 9.92842693e-01, 9.93775067e-01, 9.94790398e-01, - 9.95875534e-01, 9.97014367e-01, 9.98192871e-01, 9.99394506e-01, - 1.00060586e+00, 1.00181040e+00, 1.00299457e+00, 1.00414155e+00, - 1.00523688e+00, 1.00626393e+00, 1.00720890e+00, 1.00805489e+00, - 1.00878802e+00, 1.00939182e+00, 1.00985296e+00, 1.01015529e+00, - 1.01028602e+00, 1.01022988e+00, 1.00997541e+00, 1.00950846e+00, - 1.00881848e+00, 1.00789488e+00, 1.00672876e+00, 1.00530991e+00, - 1.00363456e+00, 1.00169363e+00, 9.99485663e-01, 9.97006370e-01, - 9.94254687e-01, 9.91231967e-01, 9.87937115e-01, 9.84375125e-01, - 9.79890963e-01, 9.75269879e-01, 9.70180498e-01, 9.64580027e-01, - 9.58425534e-01, 9.51684014e-01, 9.44320232e-01, 9.36290624e-01, - 9.27580507e-01, 9.18153414e-01, 9.07976524e-01, 8.97050058e-01, - 8.85351360e-01, 8.72857927e-01, 8.59579819e-01, 8.45502615e-01, - 8.30619943e-01, 8.14946648e-01, 7.98489378e-01, 7.81262450e-01, - 7.63291769e-01, 7.44590843e-01, 7.25199287e-01, 7.05153668e-01, - 6.84490545e-01, 6.63245210e-01, 6.41477162e-01, 6.19235334e-01, - 5.96559133e-01, 5.73519989e-01, 5.50173851e-01, 5.26568538e-01, - 5.02781159e-01, 4.78860889e-01, 4.54877894e-01, 4.30898123e-01, - 4.06993964e-01, 3.83234031e-01, 3.59680098e-01, 3.36408100e-01, - 3.13496418e-01, 2.91010565e-01, 2.69019585e-01, 2.47584348e-01, - 2.26788433e-01, 2.06677771e-01, 1.87310343e-01, 1.68739644e-01, - 1.51012382e-01, 1.34171842e-01, 1.18254662e-01, 1.03290734e-01, - 8.93117360e-02, 7.63429787e-02, 6.44077291e-02, 5.35243715e-02, - 4.37084453e-02, 3.49667099e-02, 2.72984629e-02, 2.06895808e-02, - 1.51125125e-02, 1.05228754e-02, 6.85547314e-03, 4.02351119e-03, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_7M5_180 = np.array([ - 1.97084908e-03, 2.95060859e-03, 4.12447721e-03, 5.52688664e-03, - 7.17541132e-03, 9.08757730e-03, 1.12819105e-02, 1.37695374e-02, - 1.65600266e-02, 1.96650895e-02, 2.30953556e-02, 2.68612894e-02, - 3.09632560e-02, 3.54036230e-02, 4.01915610e-02, 4.53331403e-02, - 5.08289304e-02, 5.66815448e-02, 6.28935304e-02, 6.94696293e-02, - 7.64106314e-02, 8.37160016e-02, 9.13884278e-02, 9.94294008e-02, - 1.07834725e-01, 1.16604575e-01, 1.25736503e-01, 1.35226811e-01, - 1.45073546e-01, 1.55273819e-01, 1.65822194e-01, 1.76711174e-01, - 1.87928776e-01, 1.99473180e-01, 2.11342953e-01, 2.23524554e-01, - 2.36003100e-01, 2.48768614e-01, 2.61813811e-01, 2.75129161e-01, - 2.88701102e-01, 3.02514034e-01, 3.16558805e-01, 3.30823871e-01, - 3.45295567e-01, 3.59963992e-01, 3.74814544e-01, 3.89831817e-01, - 4.05001010e-01, 4.20308013e-01, 4.35739515e-01, 4.51277817e-01, - 4.66904918e-01, 4.82609041e-01, 4.98375466e-01, 5.14185341e-01, - 5.30021478e-01, 5.45869352e-01, 5.61710041e-01, 5.77528151e-01, - 5.93304696e-01, 6.09026346e-01, 6.24674189e-01, 6.40227555e-01, - 6.55671016e-01, 6.70995935e-01, 6.86184559e-01, 7.01218384e-01, - 7.16078449e-01, 7.30756084e-01, 7.45240679e-01, 7.59515122e-01, - 7.73561955e-01, 7.87369206e-01, 8.00923138e-01, 8.14211386e-01, - 8.27223833e-01, 8.39952374e-01, 8.52386102e-01, 8.64513675e-01, - 8.76324079e-01, 8.87814288e-01, 8.98977415e-01, 9.09803319e-01, - 9.20284312e-01, 9.30407518e-01, 9.40169652e-01, 9.49567795e-01, - 9.58599937e-01, 9.67260260e-01, 9.75545166e-01, 9.83447719e-01, - 9.90971957e-01, 9.98119269e-01, 1.00488283e+00, 1.01125773e+00, - 1.01724436e+00, 1.02285381e+00, 1.02808734e+00, 1.03293706e+00, - 1.03740495e+00, 1.04150164e+00, 1.04523236e+00, 1.04859791e+00, - 1.05160340e+00, 1.05425505e+00, 1.05656184e+00, 1.05853400e+00, - 1.06017414e+00, 1.06149371e+00, 1.06249943e+00, 1.06320577e+00, - 1.06362578e+00, 1.06376487e+00, 1.06363778e+00, 1.06325973e+00, - 1.06264695e+00, 1.06180496e+00, 1.06074505e+00, 1.05948492e+00, - 1.05804533e+00, 1.05643590e+00, 1.05466218e+00, 1.05274047e+00, - 1.05069500e+00, 1.04853894e+00, 1.04627898e+00, 1.04392435e+00, - 1.04149540e+00, 1.03901003e+00, 1.03647725e+00, 1.03390793e+00, - 1.03131989e+00, 1.02872867e+00, 1.02614832e+00, 1.02358988e+00, - 1.02106486e+00, 1.01856262e+00, 1.01655770e+00, 1.01400658e+00, - 1.01162953e+00, 1.00938590e+00, 1.00727455e+00, 1.00529616e+00, - 1.00344526e+00, 1.00172250e+00, 1.00012792e+00, 9.98657533e-01, - 9.97309592e-01, 9.96083571e-01, 9.94976569e-01, 9.93985158e-01, - 9.93107530e-01, 9.92341305e-01, 9.91683335e-01, 9.91130070e-01, - 9.90678325e-01, 9.90325325e-01, 9.90067562e-01, 9.89901282e-01, - 9.89822613e-01, 9.89827845e-01, 9.89913241e-01, 9.90074734e-01, - 9.90308256e-01, 9.90609852e-01, 9.90975314e-01, 9.91400330e-01, - 9.91880966e-01, 9.92412851e-01, 9.92991779e-01, 9.93613381e-01, - 9.94273149e-01, 9.94966958e-01, 9.95690370e-01, 9.96439157e-01, - 9.97208572e-01, 9.97994275e-01, 9.98791616e-01, 9.99596062e-01, - 1.00040410e+00, 1.00120985e+00, 1.00200976e+00, 1.00279924e+00, - 1.00357357e+00, 1.00432828e+00, 1.00505850e+00, 1.00575984e+00, - 1.00642767e+00, 1.00705768e+00, 1.00764515e+00, 1.00818549e+00, - 1.00867427e+00, 1.00910687e+00, 1.00947916e+00, 1.00978659e+00, - 1.01002476e+00, 1.01018954e+00, 1.01027669e+00, 1.01028203e+00, - 1.01020174e+00, 1.01003208e+00, 1.00976919e+00, 1.00940939e+00, - 1.00894931e+00, 1.00838641e+00, 1.00771780e+00, 1.00694031e+00, - 1.00605124e+00, 1.00504879e+00, 1.00393183e+00, 1.00269767e+00, - 1.00134427e+00, 9.99872092e-01, 9.98280464e-01, 9.96566569e-01, - 9.94731737e-01, 9.92777987e-01, 9.90701374e-01, 9.88504165e-01, - 9.86186892e-01, 9.83711989e-01, 9.80584643e-01, 9.77634164e-01, - 9.74455033e-01, 9.71062916e-01, 9.67447270e-01, 9.63593926e-01, - 9.59491398e-01, 9.55129725e-01, 9.50501326e-01, 9.45592810e-01, - 9.40389877e-01, 9.34886760e-01, 9.29080559e-01, 9.22959280e-01, - 9.16509579e-01, 9.09724456e-01, 9.02607350e-01, 8.95155084e-01, - 8.87356154e-01, 8.79202689e-01, 8.70699698e-01, 8.61847424e-01, - 8.52641750e-01, 8.43077833e-01, 8.33154905e-01, 8.22881272e-01, - 8.12257597e-01, 8.01285439e-01, 7.89971715e-01, 7.78318177e-01, - 7.66337710e-01, 7.54030328e-01, 7.41407991e-01, 7.28477501e-01, - 7.15255742e-01, 7.01751739e-01, 6.87975632e-01, 6.73936911e-01, - 6.59652573e-01, 6.45139489e-01, 6.30414716e-01, 6.15483622e-01, - 6.00365852e-01, 5.85078858e-01, 5.69649536e-01, 5.54084810e-01, - 5.38398518e-01, 5.22614738e-01, 5.06756805e-01, 4.90833753e-01, - 4.74866033e-01, 4.58876566e-01, 4.42885823e-01, 4.26906539e-01, - 4.10970973e-01, 3.95091024e-01, 3.79291327e-01, 3.63587417e-01, - 3.48004343e-01, 3.32563201e-01, 3.17287485e-01, 3.02196710e-01, - 2.87309403e-01, 2.72643992e-01, 2.58227431e-01, 2.44072856e-01, - 2.30208977e-01, 2.16641416e-01, 2.03398481e-01, 1.90486162e-01, - 1.77922122e-01, 1.65726674e-01, 1.53906397e-01, 1.42480547e-01, - 1.31453980e-01, 1.20841778e-01, 1.10652194e-01, 1.00891734e-01, - 9.15718851e-02, 8.26995967e-02, 7.42815529e-02, 6.63242382e-02, - 5.88334516e-02, 5.18140676e-02, 4.52698346e-02, 3.92030848e-02, - 3.36144159e-02, 2.85023308e-02, 2.38629107e-02, 1.96894227e-02, - 1.59720527e-02, 1.26976223e-02, 9.84937739e-03, 7.40724463e-03, - 5.35665361e-03, 3.83226552e-03, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_7M5_240 = np.array([ - 1.84833037e-03, 2.56481839e-03, 3.36762118e-03, 4.28736617e-03, - 5.33830143e-03, 6.52679223e-03, 7.86112587e-03, 9.34628179e-03, - 1.09916868e-02, 1.28011172e-02, 1.47805911e-02, 1.69307043e-02, - 1.92592307e-02, 2.17696937e-02, 2.44685983e-02, 2.73556543e-02, - 3.04319230e-02, 3.36980464e-02, 3.71583577e-02, 4.08148180e-02, - 4.46708068e-02, 4.87262995e-02, 5.29820633e-02, 5.74382470e-02, - 6.20968580e-02, 6.69609767e-02, 7.20298364e-02, 7.73039146e-02, - 8.27825574e-02, 8.84682102e-02, 9.43607566e-02, 1.00460272e-01, - 1.06763824e-01, 1.13273679e-01, 1.19986420e-01, 1.26903521e-01, - 1.34020853e-01, 1.41339557e-01, 1.48857211e-01, 1.56573685e-01, - 1.64484622e-01, 1.72589077e-01, 1.80879090e-01, 1.89354320e-01, - 1.98012244e-01, 2.06854141e-01, 2.15875319e-01, 2.25068672e-01, - 2.34427407e-01, 2.43948314e-01, 2.53627993e-01, 2.63464061e-01, - 2.73450494e-01, 2.83582189e-01, 2.93853469e-01, 3.04257373e-01, - 3.14790914e-01, 3.25449123e-01, 3.36227410e-01, 3.47118760e-01, - 3.58120177e-01, 3.69224663e-01, 3.80427793e-01, 3.91720023e-01, - 4.03097022e-01, 4.14551955e-01, 4.26081719e-01, 4.37676318e-01, - 4.49330196e-01, 4.61034855e-01, 4.72786043e-01, 4.84576777e-01, - 4.96401707e-01, 5.08252458e-01, 5.20122078e-01, 5.32002077e-01, - 5.43888090e-01, 5.55771601e-01, 5.67645739e-01, 5.79502786e-01, - 5.91335035e-01, 6.03138367e-01, 6.14904172e-01, 6.26623941e-01, - 6.38288834e-01, 6.49893375e-01, 6.61432360e-01, 6.72902514e-01, - 6.84293750e-01, 6.95600460e-01, 7.06811784e-01, 7.17923425e-01, - 7.28931386e-01, 7.39832773e-01, 7.50618982e-01, 7.61284053e-01, - 7.71818919e-01, 7.82220992e-01, 7.92481330e-01, 8.02599448e-01, - 8.12565230e-01, 8.22377129e-01, 8.32030518e-01, 8.41523208e-01, - 8.50848313e-01, 8.60002412e-01, 8.68979881e-01, 8.77778347e-01, - 8.86395904e-01, 8.94829421e-01, 9.03077626e-01, 9.11132652e-01, - 9.18993585e-01, 9.26652937e-01, 9.34111420e-01, 9.41364344e-01, - 9.48412967e-01, 9.55255630e-01, 9.61892013e-01, 9.68316363e-01, - 9.74530156e-01, 9.80528338e-01, 9.86313928e-01, 9.91886049e-01, - 9.97246345e-01, 1.00239190e+00, 1.00731946e+00, 1.01202707e+00, - 1.01651654e+00, 1.02079430e+00, 1.02486082e+00, 1.02871471e+00, - 1.03235170e+00, 1.03577375e+00, 1.03898432e+00, 1.04198786e+00, - 1.04478564e+00, 1.04737818e+00, 1.04976743e+00, 1.05195405e+00, - 1.05394290e+00, 1.05573463e+00, 1.05734177e+00, 1.05875726e+00, - 1.05998674e+00, 1.06103672e+00, 1.06190651e+00, 1.06260369e+00, - 1.06313289e+00, 1.06350237e+00, 1.06370981e+00, 1.06376322e+00, - 1.06366765e+00, 1.06343012e+00, 1.06305656e+00, 1.06255421e+00, - 1.06192235e+00, 1.06116702e+00, 1.06029469e+00, 1.05931469e+00, - 1.05823465e+00, 1.05705891e+00, 1.05578948e+00, 1.05442979e+00, - 1.05298793e+00, 1.05147505e+00, 1.04989930e+00, 1.04826213e+00, - 1.04656691e+00, 1.04481699e+00, 1.04302125e+00, 1.04118768e+00, - 1.03932339e+00, 1.03743168e+00, 1.03551757e+00, 1.03358511e+00, - 1.03164371e+00, 1.02969955e+00, 1.02775944e+00, 1.02582719e+00, - 1.02390791e+00, 1.02200805e+00, 1.02013910e+00, 1.01826310e+00, - 1.01687901e+00, 1.01492195e+00, 1.01309662e+00, 1.01134205e+00, - 1.00965912e+00, 1.00805036e+00, 1.00651754e+00, 1.00505799e+00, - 1.00366956e+00, 1.00235327e+00, 1.00110981e+00, 9.99937523e-01, - 9.98834524e-01, 9.97800606e-01, 9.96835756e-01, 9.95938881e-01, - 9.95108459e-01, 9.94343411e-01, 9.93642921e-01, 9.93005832e-01, - 9.92430984e-01, 9.91917493e-01, 9.91463898e-01, 9.91068214e-01, - 9.90729218e-01, 9.90446225e-01, 9.90217819e-01, 9.90041963e-01, - 9.89917085e-01, 9.89841975e-01, 9.89815048e-01, 9.89834329e-01, - 9.89898211e-01, 9.90005403e-01, 9.90154189e-01, 9.90342427e-01, - 9.90568459e-01, 9.90830953e-01, 9.91128038e-01, 9.91457566e-01, - 9.91817881e-01, 9.92207559e-01, 9.92624757e-01, 9.93067358e-01, - 9.93533398e-01, 9.94021410e-01, 9.94529685e-01, 9.95055964e-01, - 9.95598351e-01, 9.96155580e-01, 9.96725627e-01, 9.97306092e-01, - 9.97895214e-01, 9.98491441e-01, 9.99092890e-01, 9.99697063e-01, - 1.00030303e+00, 1.00090793e+00, 1.00151084e+00, 1.00210923e+00, - 1.00270118e+00, 1.00328513e+00, 1.00385926e+00, 1.00442111e+00, - 1.00496860e+00, 1.00550040e+00, 1.00601455e+00, 1.00650869e+00, - 1.00698104e+00, 1.00743004e+00, 1.00785364e+00, 1.00824962e+00, - 1.00861604e+00, 1.00895138e+00, 1.00925390e+00, 1.00952134e+00, - 1.00975175e+00, 1.00994371e+00, 1.01009550e+00, 1.01020488e+00, - 1.01027007e+00, 1.01028975e+00, 1.01026227e+00, 1.01018562e+00, - 1.01005820e+00, 1.00987882e+00, 1.00964593e+00, 1.00935753e+00, - 1.00901228e+00, 1.00860959e+00, 1.00814837e+00, 1.00762674e+00, - 1.00704343e+00, 1.00639775e+00, 1.00568877e+00, 1.00491559e+00, - 1.00407768e+00, 1.00317429e+00, 1.00220424e+00, 1.00116684e+00, - 1.00006248e+00, 9.98891422e-01, 9.97652252e-01, 9.96343856e-01, - 9.94967462e-01, 9.93524663e-01, 9.92013927e-01, 9.90433283e-01, - 9.88785147e-01, 9.87072681e-01, 9.85297443e-01, 9.83401161e-01, - 9.80949418e-01, 9.78782729e-01, 9.76468238e-01, 9.74042850e-01, - 9.71498848e-01, 9.68829968e-01, 9.66030974e-01, 9.63095104e-01, - 9.60018198e-01, 9.56795738e-01, 9.53426267e-01, 9.49903482e-01, - 9.46222115e-01, 9.42375820e-01, 9.38361702e-01, 9.34177798e-01, - 9.29823124e-01, 9.25292320e-01, 9.20580120e-01, 9.15679793e-01, - 9.10590604e-01, 9.05315030e-01, 8.99852756e-01, 8.94199497e-01, - 8.88350152e-01, 8.82301631e-01, 8.76054874e-01, 8.69612385e-01, - 8.62972799e-01, 8.56135198e-01, 8.49098179e-01, 8.41857024e-01, - 8.34414055e-01, 8.26774617e-01, 8.18939244e-01, 8.10904891e-01, - 8.02675318e-01, 7.94253751e-01, 7.85641662e-01, 7.76838609e-01, - 7.67853193e-01, 7.58685181e-01, 7.49330658e-01, 7.39809171e-01, - 7.30109944e-01, 7.20247781e-01, 7.10224161e-01, 7.00044326e-01, - 6.89711890e-01, 6.79231154e-01, 6.68608179e-01, 6.57850997e-01, - 6.46965718e-01, 6.35959617e-01, 6.24840336e-01, 6.13603503e-01, - 6.02265091e-01, 5.90829083e-01, 5.79309408e-01, 5.67711124e-01, - 5.56037416e-01, 5.44293664e-01, 5.32489768e-01, 5.20636084e-01, - 5.08743273e-01, 4.96811166e-01, 4.84849881e-01, 4.72868107e-01, - 4.60875918e-01, 4.48881081e-01, 4.36891039e-01, 4.24912022e-01, - 4.12960603e-01, 4.01035896e-01, 3.89157867e-01, 3.77322199e-01, - 3.65543767e-01, 3.53832356e-01, 3.42196115e-01, 3.30644820e-01, - 3.19187559e-01, 3.07833309e-01, 2.96588182e-01, 2.85463717e-01, - 2.74462409e-01, 2.63609584e-01, 2.52883101e-01, 2.42323489e-01, - 2.31925746e-01, 2.21690837e-01, 2.11638058e-01, 2.01766920e-01, - 1.92082236e-01, 1.82589160e-01, 1.73305997e-01, 1.64229200e-01, - 1.55362654e-01, 1.46717079e-01, 1.38299391e-01, 1.30105078e-01, - 1.22145310e-01, 1.14423458e-01, 1.06941076e-01, 9.97025893e-02, - 9.27124283e-02, 8.59737427e-02, 7.94893311e-02, 7.32616579e-02, - 6.72934102e-02, 6.15874081e-02, 5.61458003e-02, 5.09700747e-02, - 4.60617047e-02, 4.14220117e-02, 3.70514189e-02, 3.29494666e-02, - 2.91153327e-02, 2.55476401e-02, 2.22437711e-02, 1.92000659e-02, - 1.64122205e-02, 1.38747611e-02, 1.15806353e-02, 9.52213664e-03, - 7.69137380e-03, 6.07207833e-03, 4.62581217e-03, 3.60685164e-03, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - -W_7M5_360 = np.array([ - 1.72152668e-03, 2.20824874e-03, 2.68901752e-03, 3.22613342e-03, - 3.81014420e-03, 4.45371932e-03, 5.15369240e-03, 5.91552473e-03, - 6.73869158e-03, 7.62861841e-03, 8.58361457e-03, 9.60938437e-03, - 1.07060753e-02, 1.18759723e-02, 1.31190130e-02, 1.44390108e-02, - 1.58335301e-02, 1.73063081e-02, 1.88584711e-02, 2.04918652e-02, - 2.22061476e-02, 2.40057166e-02, 2.58883593e-02, 2.78552326e-02, - 2.99059145e-02, 3.20415894e-02, 3.42610013e-02, 3.65680973e-02, - 3.89616721e-02, 4.14435824e-02, 4.40140796e-02, 4.66742169e-02, - 4.94214625e-02, 5.22588489e-02, 5.51849337e-02, 5.82005143e-02, - 6.13059845e-02, 6.45038384e-02, 6.77913923e-02, 7.11707833e-02, - 7.46411071e-02, 7.82028053e-02, 8.18549521e-02, 8.56000162e-02, - 8.94357617e-02, 9.33642589e-02, 9.73846703e-02, 1.01496718e-01, - 1.05698760e-01, 1.09993603e-01, 1.14378287e-01, 1.18853508e-01, - 1.23419277e-01, 1.28075997e-01, 1.32820581e-01, 1.37655457e-01, - 1.42578648e-01, 1.47590522e-01, 1.52690437e-01, 1.57878853e-01, - 1.63152529e-01, 1.68513363e-01, 1.73957969e-01, 1.79484737e-01, - 1.85093105e-01, 1.90784835e-01, 1.96556497e-01, 2.02410419e-01, - 2.08345433e-01, 2.14359825e-01, 2.20450365e-01, 2.26617296e-01, - 2.32856279e-01, 2.39167941e-01, 2.45550642e-01, 2.52003951e-01, - 2.58526168e-01, 2.65118408e-01, 2.71775911e-01, 2.78498539e-01, - 2.85284606e-01, 2.92132459e-01, 2.99038432e-01, 3.06004256e-01, - 3.13026529e-01, 3.20104862e-01, 3.27237324e-01, 3.34423210e-01, - 3.41658622e-01, 3.48944976e-01, 3.56279252e-01, 3.63660034e-01, - 3.71085146e-01, 3.78554327e-01, 3.86062695e-01, 3.93610554e-01, - 4.01195225e-01, 4.08815272e-01, 4.16468460e-01, 4.24155411e-01, - 4.31871046e-01, 4.39614744e-01, 4.47384019e-01, 4.55176988e-01, - 4.62990138e-01, 4.70824619e-01, 4.78676593e-01, 4.86545433e-01, - 4.94428714e-01, 5.02324813e-01, 5.10229471e-01, 5.18142927e-01, - 5.26060916e-01, 5.33982818e-01, 5.41906817e-01, 5.49831283e-01, - 5.57751234e-01, 5.65667636e-01, 5.73576883e-01, 5.81476666e-01, - 5.89364661e-01, 5.97241338e-01, 6.05102013e-01, 6.12946170e-01, - 6.20770242e-01, 6.28572094e-01, 6.36348526e-01, 6.44099662e-01, - 6.51820973e-01, 6.59513822e-01, 6.67176382e-01, 6.74806795e-01, - 6.82400711e-01, 6.89958854e-01, 6.97475722e-01, 7.04950145e-01, - 7.12379980e-01, 7.19765434e-01, 7.27103833e-01, 7.34396372e-01, - 7.41638561e-01, 7.48829639e-01, 7.55966688e-01, 7.63049259e-01, - 7.70072273e-01, 7.77036981e-01, 7.83941108e-01, 7.90781257e-01, - 7.97558114e-01, 8.04271381e-01, 8.10914901e-01, 8.17490856e-01, - 8.23997094e-01, 8.30432785e-01, 8.36796950e-01, 8.43089298e-01, - 8.49305847e-01, 8.55447310e-01, 8.61511037e-01, 8.67496281e-01, - 8.73400798e-01, 8.79227518e-01, 8.84972438e-01, 8.90635719e-01, - 8.96217173e-01, 9.01716414e-01, 9.07128770e-01, 9.12456578e-01, - 9.17697261e-01, 9.22848784e-01, 9.27909917e-01, 9.32882596e-01, - 9.37763323e-01, 9.42553356e-01, 9.47252428e-01, 9.51860206e-01, - 9.56376060e-01, 9.60800602e-01, 9.65130600e-01, 9.69366689e-01, - 9.73508812e-01, 9.77556541e-01, 9.81507226e-01, 9.85364580e-01, - 9.89126209e-01, 9.92794201e-01, 9.96367545e-01, 9.99846919e-01, - 1.00322812e+00, 1.00651341e+00, 1.00970073e+00, 1.01279029e+00, - 1.01578293e+00, 1.01868229e+00, 1.02148657e+00, 1.02419772e+00, - 1.02681455e+00, 1.02933598e+00, 1.03176043e+00, 1.03408981e+00, - 1.03632326e+00, 1.03846361e+00, 1.04051196e+00, 1.04246831e+00, - 1.04433331e+00, 1.04610837e+00, 1.04779018e+00, 1.04938334e+00, - 1.05088565e+00, 1.05229923e+00, 1.05362522e+00, 1.05486289e+00, - 1.05601521e+00, 1.05708746e+00, 1.05807221e+00, 1.05897524e+00, - 1.05979447e+00, 1.06053414e+00, 1.06119412e+00, 1.06177366e+00, - 1.06227662e+00, 1.06270324e+00, 1.06305569e+00, 1.06333815e+00, - 1.06354800e+00, 1.06368607e+00, 1.06375557e+00, 1.06375743e+00, - 1.06369358e+00, 1.06356632e+00, 1.06337707e+00, 1.06312782e+00, - 1.06282156e+00, 1.06245782e+00, 1.06203634e+00, 1.06155996e+00, - 1.06102951e+00, 1.06044797e+00, 1.05981709e+00, 1.05914163e+00, - 1.05842136e+00, 1.05765876e+00, 1.05685377e+00, 1.05600761e+00, - 1.05512006e+00, 1.05419505e+00, 1.05323346e+00, 1.05223985e+00, - 1.05121668e+00, 1.05016637e+00, 1.04908779e+00, 1.04798366e+00, - 1.04685334e+00, 1.04569860e+00, 1.04452056e+00, 1.04332348e+00, - 1.04210831e+00, 1.04087907e+00, 1.03963603e+00, 1.03838099e+00, - 1.03711403e+00, 1.03583813e+00, 1.03455276e+00, 1.03326200e+00, - 1.03196750e+00, 1.03067200e+00, 1.02937564e+00, 1.02808244e+00, - 1.02679167e+00, 1.02550635e+00, 1.02422655e+00, 1.02295558e+00, - 1.02169299e+00, 1.02044475e+00, 1.01920733e+00, 1.01799992e+00, - 1.01716022e+00, 1.01587289e+00, 1.01461783e+00, 1.01339738e+00, - 1.01221017e+00, 1.01105652e+00, 1.00993444e+00, 1.00884559e+00, - 1.00778956e+00, 1.00676790e+00, 1.00577851e+00, 1.00482173e+00, - 1.00389592e+00, 1.00300262e+00, 1.00214091e+00, 1.00131213e+00, - 1.00051460e+00, 9.99748988e-01, 9.99013486e-01, 9.98309229e-01, - 9.97634934e-01, 9.96991885e-01, 9.96378601e-01, 9.95795982e-01, - 9.95242217e-01, 9.94718132e-01, 9.94222122e-01, 9.93755313e-01, - 9.93316216e-01, 9.92905809e-01, 9.92522422e-01, 9.92166957e-01, - 9.91837704e-01, 9.91535508e-01, 9.91258603e-01, 9.91007878e-01, - 9.90781723e-01, 9.90581104e-01, 9.90404336e-01, 9.90252267e-01, - 9.90123118e-01, 9.90017726e-01, 9.89934325e-01, 9.89873712e-01, - 9.89834110e-01, 9.89816359e-01, 9.89818707e-01, 9.89841998e-01, - 9.89884438e-01, 9.89946800e-01, 9.90027287e-01, 9.90126680e-01, - 9.90243175e-01, 9.90377594e-01, 9.90528134e-01, 9.90695564e-01, - 9.90878043e-01, 9.91076302e-01, 9.91288540e-01, 9.91515602e-01, - 9.91755666e-01, 9.92009469e-01, 9.92275155e-01, 9.92553486e-01, - 9.92842693e-01, 9.93143533e-01, 9.93454080e-01, 9.93775067e-01, - 9.94104689e-01, 9.94443742e-01, 9.94790398e-01, 9.95145361e-01, - 9.95506800e-01, 9.95875534e-01, 9.96249681e-01, 9.96629919e-01, - 9.97014367e-01, 9.97403799e-01, 9.97796404e-01, 9.98192871e-01, - 9.98591286e-01, 9.98992436e-01, 9.99394506e-01, 9.99798247e-01, - 1.00020179e+00, 1.00060586e+00, 1.00100858e+00, 1.00141070e+00, - 1.00181040e+00, 1.00220846e+00, 1.00260296e+00, 1.00299457e+00, - 1.00338148e+00, 1.00376444e+00, 1.00414155e+00, 1.00451348e+00, - 1.00487832e+00, 1.00523688e+00, 1.00558730e+00, 1.00593027e+00, - 1.00626393e+00, 1.00658905e+00, 1.00690380e+00, 1.00720890e+00, - 1.00750238e+00, 1.00778498e+00, 1.00805489e+00, 1.00831287e+00, - 1.00855700e+00, 1.00878802e+00, 1.00900405e+00, 1.00920593e+00, - 1.00939182e+00, 1.00956244e+00, 1.00971590e+00, 1.00985296e+00, - 1.00997177e+00, 1.01007317e+00, 1.01015529e+00, 1.01021893e+00, - 1.01026225e+00, 1.01028602e+00, 1.01028842e+00, 1.01027030e+00, - 1.01022988e+00, 1.01016802e+00, 1.01008292e+00, 1.00997541e+00, - 1.00984369e+00, 1.00968863e+00, 1.00950846e+00, 1.00930404e+00, - 1.00907371e+00, 1.00881848e+00, 1.00853675e+00, 1.00822947e+00, - 1.00789488e+00, 1.00753391e+00, 1.00714488e+00, 1.00672876e+00, - 1.00628393e+00, 1.00581146e+00, 1.00530991e+00, 1.00478053e+00, - 1.00422177e+00, 1.00363456e+00, 1.00301719e+00, 1.00237067e+00, - 1.00169363e+00, 1.00098749e+00, 1.00025108e+00, 9.99485663e-01, - 9.98689592e-01, 9.97863666e-01, 9.97006370e-01, 9.96119199e-01, - 9.95201404e-01, 9.94254687e-01, 9.93277595e-01, 9.92270651e-01, - 9.91231967e-01, 9.90163286e-01, 9.89064394e-01, 9.87937115e-01, - 9.86779736e-01, 9.85592773e-01, 9.84375125e-01, 9.83129288e-01, - 9.81348463e-01, 9.79890963e-01, 9.78400459e-01, 9.76860435e-01, - 9.75269879e-01, 9.73627353e-01, 9.71931341e-01, 9.70180498e-01, - 9.68372652e-01, 9.66506952e-01, 9.64580027e-01, 9.62592318e-01, - 9.60540986e-01, 9.58425534e-01, 9.56244393e-01, 9.53998416e-01, - 9.51684014e-01, 9.49301185e-01, 9.46846884e-01, 9.44320232e-01, - 9.41718404e-01, 9.39042580e-01, 9.36290624e-01, 9.33464050e-01, - 9.30560854e-01, 9.27580507e-01, 9.24519592e-01, 9.21378471e-01, - 9.18153414e-01, 9.14844696e-01, 9.11451652e-01, 9.07976524e-01, - 9.04417545e-01, 9.00776308e-01, 8.97050058e-01, 8.93238398e-01, - 8.89338681e-01, 8.85351360e-01, 8.81274023e-01, 8.77109638e-01, - 8.72857927e-01, 8.68519505e-01, 8.64092796e-01, 8.59579819e-01, - 8.54976007e-01, 8.50285220e-01, 8.45502615e-01, 8.40630470e-01, - 8.35667925e-01, 8.30619943e-01, 8.25482007e-01, 8.20258909e-01, - 8.14946648e-01, 8.09546696e-01, 8.04059978e-01, 7.98489378e-01, - 7.92831417e-01, 7.87090668e-01, 7.81262450e-01, 7.75353947e-01, - 7.69363613e-01, 7.63291769e-01, 7.57139016e-01, 7.50901711e-01, - 7.44590843e-01, 7.38205136e-01, 7.31738075e-01, 7.25199287e-01, - 7.18588225e-01, 7.11905687e-01, 7.05153668e-01, 6.98332634e-01, - 6.91444101e-01, 6.84490545e-01, 6.77470119e-01, 6.70388375e-01, - 6.63245210e-01, 6.56045780e-01, 6.48788627e-01, 6.41477162e-01, - 6.34114323e-01, 6.26702000e-01, 6.19235334e-01, 6.11720596e-01, - 6.04161612e-01, 5.96559133e-01, 5.88914401e-01, 5.81234783e-01, - 5.73519989e-01, 5.65770616e-01, 5.57988067e-01, 5.50173851e-01, - 5.42330194e-01, 5.34460798e-01, 5.26568538e-01, 5.18656324e-01, - 5.10728813e-01, 5.02781159e-01, 4.94819491e-01, 4.86845139e-01, - 4.78860889e-01, 4.70869928e-01, 4.62875144e-01, 4.54877894e-01, - 4.46882512e-01, 4.38889325e-01, 4.30898123e-01, 4.22918322e-01, - 4.14950878e-01, 4.06993964e-01, 3.99052648e-01, 3.91134614e-01, - 3.83234031e-01, 3.75354653e-01, 3.67502060e-01, 3.59680098e-01, - 3.51887312e-01, 3.44130166e-01, 3.36408100e-01, 3.28728966e-01, - 3.21090505e-01, 3.13496418e-01, 3.05951565e-01, 2.98454319e-01, - 2.91010565e-01, 2.83621109e-01, 2.76285415e-01, 2.69019585e-01, - 2.61812445e-01, 2.54659232e-01, 2.47584348e-01, 2.40578694e-01, - 2.33647009e-01, 2.26788433e-01, 2.20001992e-01, 2.13301325e-01, - 2.06677771e-01, 2.00140409e-01, 1.93683630e-01, 1.87310343e-01, - 1.81027384e-01, 1.74839476e-01, 1.68739644e-01, 1.62737273e-01, - 1.56825277e-01, 1.51012382e-01, 1.45298230e-01, 1.39687469e-01, - 1.34171842e-01, 1.28762544e-01, 1.23455562e-01, 1.18254662e-01, - 1.13159677e-01, 1.08171439e-01, 1.03290734e-01, 9.85202978e-02, - 9.38600023e-02, 8.93117360e-02, 8.48752103e-02, 8.05523737e-02, - 7.63429787e-02, 7.22489246e-02, 6.82699120e-02, 6.44077291e-02, - 6.06620003e-02, 5.70343711e-02, 5.35243715e-02, 5.01334690e-02, - 4.68610790e-02, 4.37084453e-02, 4.06748365e-02, 3.77612269e-02, - 3.49667099e-02, 3.22919275e-02, 2.97357669e-02, 2.72984629e-02, - 2.49787186e-02, 2.27762542e-02, 2.06895808e-02, 1.87178169e-02, - 1.68593418e-02, 1.51125125e-02, 1.34757094e-02, 1.19462709e-02, - 1.05228754e-02, 9.20130941e-03, 7.98124316e-03, 6.85547314e-03, - 5.82657334e-03, 4.87838525e-03, 4.02351119e-03, 3.15418663e-03, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -]) - - -### 3.7.4 ### - -SNS_LFCB = np.array([ - - [ 2.26283366e+00, 8.13311269e-01, -5.30193495e-01, -1.35664836e+00, - -1.59952177e+00, -1.44098768e+00, -1.14381648e+00, -7.55203768e-01 ], - - [ 2.94516479e+00, 2.41143318e+00, 9.60455106e-01, -4.43226488e-01, - -1.22913612e+00, -1.55590039e+00, -1.49688656e+00, -1.11689987e+00 ], - - [ -2.18610707e+00, -1.97152136e+00, -1.78718620e+00, -1.91865896e+00, - -1.79399122e+00, -1.35738404e+00, -7.05444279e-01, -4.78172945e-02 ], - - [ 6.93688237e-01, 9.55609857e-01, 5.75230787e-01, -1.14603419e-01, - -6.46050637e-01, -9.52351370e-01, -1.07405247e+00, -7.58087707e-01 ], - - [ -1.29752132e+00, -7.40369057e-01, -3.45372484e-01, -3.13285696e-01, - -4.02977243e-01, -3.72020853e-01, -7.83414177e-02, 9.70441304e-02 ], - - [ 9.14652038e-01, 1.74293043e+00, 1.90906627e+00, 1.54408484e+00, - 1.09344961e+00, 6.47479550e-01, 3.61790752e-02, -2.97092807e-01 ], - - [ -2.51428813e+00, -2.89175271e+00, -2.00450667e+00, -7.50912274e-01, - 4.41202105e-01, 1.20190988e+00, 1.32742857e+00, 1.22049081e+00 ], - - [ -9.22188405e-01, 6.32495141e-01, 1.08736431e+00, 6.08628625e-01, - 1.31174568e-01, -2.96149158e-01, -2.07013517e-01, 1.34924917e-01 ], - - [ 7.90322288e-01, 6.28401262e-01, 3.93117924e-01, 4.80007711e-01, - 4.47815138e-01, 2.09734215e-01, 6.56691996e-03, -8.61242342e-02 ], - - [ 1.44775580e+00, 2.72399952e+00, 2.31083269e+00, 9.35051270e-01, - -2.74743911e-01, -9.02077697e-01, -9.40681512e-01, -6.33697039e-01 ], - - [ 7.93354526e-01, 1.43931186e-02, -5.67834845e-01, -6.54760468e-01, - -4.79458998e-01, -1.73894662e-01, 6.80162706e-02, 2.95125948e-01 ], - - [ 2.72425347e+00, 2.95947572e+00, 1.84953559e+00, 5.63284922e-01, - 1.39917088e-01, 3.59641093e-01, 6.89461355e-01, 6.39790177e-01 ], - - [ -5.30830198e-01, -2.12690683e-01, 5.76613628e-03, 4.24871484e-01, - 4.73128952e-01, 8.58894199e-01, 1.19111161e+00, 9.96189670e-01 ], - - [ 1.68728411e+00, 2.43614509e+00, 2.33019429e+00, 1.77983778e+00, - 1.44411295e+00, 1.51995177e+00, 1.47199394e+00, 9.77682474e-01 ], - - [ -2.95183273e+00, -1.59393497e+00, -1.09918773e-01, 3.88609073e-01, - 5.12932650e-01, 6.28112597e-01, 8.22621796e-01, 8.75891425e-01 ], - - [ 1.01878343e-01, 5.89857324e-01, 6.19047647e-01, 1.26731314e+00, - 2.41961048e+00, 2.25174253e+00, 5.26537031e-01, -3.96591513e-01 ], - - [ 2.68254575e+00, 1.32738011e+00, 1.30185274e-01, -3.38533089e-01, - -3.68219236e-01, -1.91689947e-01, -1.54782377e-01, -2.34207178e-01 ], - - [ 4.82697924e+00, 3.11947804e+00, 1.39513671e+00, 2.50295316e-01, - -3.93613839e-01, -6.43458173e-01, -6.42570737e-01, -7.23193223e-01 ], - - [ 8.78419936e-02, -5.69586840e-01, -1.14506016e+00, -1.66968488e+00, - -1.84534418e+00, -1.56468027e+00, -1.11746759e+00, -5.33981663e-01 ], - - [ 1.39102308e+00, 1.98146479e+00, 1.11265796e+00, -2.20107509e-01, - -7.74965612e-01, -5.94063874e-01, 1.36937681e-01, 8.18242891e-01 ], - - [ 3.84585894e-01, -1.60588786e-01, -5.39366810e-01, -5.29309079e-01, - 1.90433547e-01, 2.56062918e+00, 2.81896398e+00, 6.56670876e-01 ], - - [ 1.93227399e+00, 3.01030180e+00, 3.06543894e+00, 2.50110161e+00, - 1.93089593e+00, 5.72153811e-01, -8.11741794e-01, -1.17641811e+00 ], - - [ 1.75080463e-01, -7.50522832e-01, -1.03943893e+00, -1.13577509e+00, - -1.04197904e+00, -1.52060099e-02, 2.07048392e+00, 3.42948918e+00 ], - - [ -1.18817020e+00, 3.66792874e-01, 1.30957830e+00, 1.68330687e+00, - 1.25100924e+00, 9.42375752e-01, 8.26250483e-01, 4.39952741e-01 ], - - [ 2.53322203e+00, 2.11274643e+00, 1.26288412e+00, 7.61513512e-01, - 5.22117938e-01, 1.18680070e-01, -4.52346828e-01, -7.00352426e-01 ], - - [ 3.99889837e+00, 4.07901751e+00, 2.82285661e+00, 1.72607213e+00, - 6.47144377e-01, -3.31148521e-01, -8.84042571e-01, -1.12697341e+00 ], - - [ 5.07902593e-01, 1.58838450e+00, 1.72899024e+00, 1.00692230e+00, - 3.77121232e-01, 4.76370767e-01, 1.08754740e+00, 1.08756266e+00 ], - - [ 3.16856825e+00, 3.25853458e+00, 2.42230591e+00, 1.79446078e+00, - 1.52177911e+00, 1.17196707e+00, 4.89394597e-01, -6.22795716e-02 ], - - [ 1.89414767e+00, 1.25108695e+00, 5.90451211e-01, 6.08358583e-01, - 8.78171010e-01, 1.11912511e+00, 1.01857662e+00, 6.20453891e-01 ], - - [ 9.48880605e-01, 2.13239439e+00, 2.72345350e+00, 2.76986077e+00, - 2.54286973e+00, 2.02046264e+00, 8.30045859e-01, -2.75569174e-02 ], - - [ -1.88026757e+00, -1.26431073e+00, 3.11424977e-01, 1.83670210e+00, - 2.25634192e+00, 2.04818998e+00, 2.19526837e+00, 2.02659614e+00 ], - - [ 2.46375746e-01, 9.55621773e-01, 1.52046777e+00, 1.97647400e+00, - 1.94043867e+00, 2.23375847e+00, 1.98835978e+00, 1.27232673e+00 ], - -]) - -SNS_HFCB = np.array([ - - [ 2.32028419e-01, -1.00890271e+00, -2.14223503e+00, -2.37533814e+00, - -2.23041933e+00, -2.17595881e+00, -2.29065914e+00, -2.53286398e+00 ], - - [ -1.29503937e+00, -1.79929965e+00, -1.88703148e+00, -1.80991660e+00, - -1.76340038e+00, -1.83418428e+00, -1.80480981e+00, -1.73679545e+00 ], - - [ 1.39285716e-01, -2.58185126e-01, -6.50804573e-01, -1.06815732e+00, - -1.61928742e+00, -2.18762566e+00, -2.63757587e+00, -2.97897750e+00 ], - - [ -3.16513102e-01, -4.77747657e-01, -5.51162076e-01, -4.84788283e-01, - -2.38388394e-01, -1.43024507e-01, 6.83186674e-02, 8.83061717e-02 ], - - [ 8.79518405e-01, 2.98340096e-01, -9.15386396e-01, -2.20645975e+00, - -2.74142181e+00, -2.86139074e+00, -2.88841597e+00, -2.95182608e+00 ], - - [ -2.96701922e-01, -9.75004919e-01, -1.35857500e+00, -9.83721106e-01, - -6.52956939e-01, -9.89986993e-01, -1.61467225e+00, -2.40712302e+00 ], - - [ 3.40981100e-01, 2.68899789e-01, 5.63335685e-02, 4.99114047e-02, - -9.54130727e-02, -7.60166146e-01, -2.32758120e+00, -3.77155485e+00 ], - - [ -1.41229759e+00, -1.48522119e+00, -1.18603580e+00, -6.25001634e-01, - 1.53902497e-01, 5.76386498e-01, 7.95092604e-01, 5.96564632e-01 ], - - [ -2.28839512e-01, -3.33719070e-01, -8.09321359e-01, -1.63587877e+00, - -1.88486397e+00, -1.64496691e+00, -1.40515778e+00, -1.46666471e+00 ], - - [ -1.07148629e+00, -1.41767015e+00, -1.54891762e+00, -1.45296062e+00, - -1.03182970e+00, -6.90642640e-01, -4.28843805e-01, -4.94960215e-01 ], - - [ -5.90988511e-01, -7.11737759e-02, 3.45719523e-01, 3.00549461e-01, - -1.11865218e+00, -2.44089151e+00, -2.22854732e+00, -1.89509228e+00 ], - - [ -8.48434099e-01, -5.83226811e-01, 9.00423688e-02, 8.45025008e-01, - 1.06572385e+00, 7.37582999e-01, 2.56590452e-01, -4.91963360e-01 ], - - [ 1.14069146e+00, 9.64016892e-01, 3.81461206e-01, -4.82849341e-01, - -1.81632721e+00, -2.80279513e+00, -3.23385725e+00, -3.45908714e+00 ], - - [ -3.76283238e-01, 4.25675462e-02, 5.16547697e-01, 2.51716882e-01, - -2.16179968e-01, -5.34074091e-01, -6.40786096e-01, -8.69745032e-01 ], - - [ 6.65004121e-01, 1.09790765e+00, 1.38342667e+00, 1.34327359e+00, - 8.22978837e-01, 2.15876799e-01, -4.04925753e-01, -1.07025606e+00 ], - - [ -8.26265954e-01, -6.71181233e-01, -2.28495593e-01, 5.18980853e-01, - 1.36721896e+00, 2.18023038e+00, 2.53596093e+00, 2.20121099e+00 ], - - [ 1.41008327e+00, 7.54441908e-01, -1.30550585e+00, -1.87133711e+00, - -1.24008685e+00, -1.26712925e+00, -2.03670813e+00, -2.89685162e+00 ], - - [ 3.61386818e-01, -2.19991705e-02, -5.79368834e-01, -8.79427961e-01, - -8.50685023e-01, -7.79397050e-01, -7.32182927e-01, -8.88348515e-01 ], - - [ 4.37469239e-01, 3.05440420e-01, -7.38786566e-03, -4.95649855e-01, - -8.06651271e-01, -1.22431892e+00, -1.70157770e+00, -2.24491914e+00 ], - - [ 6.48100319e-01, 6.82299134e-01, 2.53247464e-01, 7.35842144e-02, - 3.14216709e-01, 2.34729881e-01, 1.44600134e-01, -6.82120179e-02 ], - - [ 1.11919833e+00, 1.23465533e+00, 5.89170238e-01, -1.37192460e+00, - -2.37095707e+00, -2.00779783e+00, -1.66688540e+00, -1.92631846e+00 ], - - [ 1.41847497e-01, -1.10660071e-01, -2.82824593e-01, -6.59813475e-03, - 2.85929280e-01, 4.60445530e-02, -6.02596416e-01, -2.26568729e+00 ], - - [ 5.04046955e-01, 8.26982163e-01, 1.11981236e+00, 1.17914044e+00, - 1.07987429e+00, 6.97536239e-01, -9.12548817e-01, -3.57684747e+00 ], - - [ -5.01076050e-01, -3.25678006e-01, 2.80798195e-02, 2.62054555e-01, - 3.60590806e-01, 6.35623722e-01, 9.59012467e-01, 1.30745157e+00 ], - - [ 3.74970983e+00, 1.52342612e+00, -4.57715662e-01, -7.98711008e-01, - -3.86819329e-01, -3.75901062e-01, -6.57836900e-01, -1.28163964e+00 ], - - [ -1.15258991e+00, -1.10800886e+00, -5.62615117e-01, -2.20562124e-01, - -3.49842880e-01, -7.53432770e-01, -9.88596593e-01, -1.28790472e+00 ], - - [ 1.02827246e+00, 1.09770519e+00, 7.68645546e-01, 2.06081978e-01, - -3.42805735e-01, -7.54939405e-01, -1.04196178e+00, -1.50335653e+00 ], - - [ 1.28831972e-01, 6.89439395e-01, 1.12346905e+00, 1.30934523e+00, - 1.35511965e+00, 1.42311381e+00, 1.15706449e+00, 4.06319438e-01 ], - - [ 1.34033030e+00, 1.38996825e+00, 1.04467922e+00, 6.35822746e-01, - -2.74733756e-01, -1.54923372e+00, -2.44239710e+00, -3.02457607e+00 ], - - [ 2.13843105e+00, 4.24711267e+00, 2.89734110e+00, 9.32730658e-01, - -2.92822250e-01, -8.10404297e-01, -7.88868099e-01, -9.35353149e-01 ], - - [ 5.64830487e-01, 1.59184978e+00, 2.39771699e+00, 3.03697344e+00, - 2.66424350e+00, 1.39304485e+00, 4.03834024e-01, -6.56270971e-01 ], - - [ -4.22460548e-01, 3.26149625e-01, 1.39171313e+00, 2.23146615e+00, - 2.61179442e+00, 2.66540340e+00, 2.40103554e+00, 1.75920380e+00 ], - -]) - -SNS_VQ_REG_ADJ_GAINS = \ - np.array([ 8915, 12054 ]) / 4096 - -SNS_VQ_REG_LF_ADJ_GAINS = \ - np.array([ 6245, 15043, 17861, 21014 ]) / 4096 - -SNS_VQ_NEAR_ADJ_GAINS = \ - np.array([ 7099, 9132, 11253, 14808 ]) / 4096 - -SNS_VQ_FAR_ADJ_GAINS = \ - np.array([ 4336, 5067, 5895, 8149, 10235, 12825, 16868, 19882 ]) / 4096 - -SNS_MPVQ_OFFSETS = np.array([ - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], - [ 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 ], - [ 0, 1, 5, 13, 25, 41, 61, 85, 113, 145, 181 ], - [ 0, 1, 7, 25, 63, 129, 231, 377, 575, 833, 1159 ], - [ 0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649, 5641 ], - [ 0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073 , 22363 ], - [ 0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081, 75517 ], - [ 0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545, 224143 ], - [ 0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729, 598417 ], - [ 0, 1, 19, 181, 1159, 5641, 22363, 75517, 224143, 598417, 1462563 ], - [ 0, 1, 21, 221, 1561, 8361, 36365, 134245, 433905, 1256465, 3317445 ], - [ 0, 1, 23, 265, 2047, 11969, 56695, 227305, 795455, 2485825, 7059735 ], - [ 0, 1, 25, 313, 2625, 16641, 85305, 369305,1392065, 4673345,14218905 ], - [ 0, 1, 27, 365, 3303, 22569, 124515, 579125,2340495, 8405905,27298155 ], - [ 0, 1, 29, 421, 4089, 29961, 177045, 880685,3800305,14546705,50250765 ], - [ 0, 1, 31, 481, 4991, 39041, 246047,1303777,5984767,24331777,89129247 ], -]) - -### 3.7.5 ### - -TNS_ORDER_BITS = np.array([ - [ 0, 17234, 13988, 11216, 8694, 6566, 4977, 3961, 3040 ], - [ 0, 12683, 9437, 6874, 5541, 5121, 5170, 5359, 5056 ] -]) - -TNS_ORDER_FREQ = np.array([ - [ 3, 9, 23, 54, 111, 190, 268, 366 ], - [ 14, 42, 100, 157, 181, 178, 167, 185 ] -]) - -TNS_ORDER_CUMFREQ = np.array([ - [ 0, 3, 12, 35, 89, 200, 390, 658 ], - [ 0, 14, 56, 156, 313, 494, 672, 839 ] -]) - -TNS_COEF_BITS = np.array([ - - [ 20480, 15725, 12479, 10334, 8694, 7320, 6964, 6335, - 5504, 5637, 6566, 6758, 8433, 11348, 15186, 20480, 20480 ], - - [ 20480, 20480, 20480, 20480, 12902, 9368, 7057, 5901, - 5254, 5485, 5598, 6076, 7608, 10742, 15186, 20480, 20480 ], - - [ 20480, 20480, 20480, 20480, 13988, 9368, 6702, 4841, - 4585, 4682, 5859, 7764, 12109, 20480, 20480, 20480, 20480 ], - - [ 20480, 20480, 20480, 20480, 18432, 13396, 8982, 4767, - 3779, 3658, 6335, 9656, 13988, 20480, 20480, 20480, 20480 ], - - [ 20480, 20480, 20480, 20480, 20480, 14731, 9437, 4275, - 3249, 3493, 8483, 13988, 17234, 20480, 20480, 20480, 20480 ], - - [ 20480, 20480, 20480, 20480, 20480, 20480, 12902, 4753, - 3040, 2953, 9105, 15725, 20480, 20480, 20480, 20480, 20480 ], - - [ 20480, 20480, 20480, 20480, 20480, 20480, 12902, 3821, - 3346, 3000, 12109, 20480, 20480, 20480, 20480, 20480, 20480 ], - - [ 20480, 20480, 20480, 20480, 20480, 20480, 15725, 3658, - 20480, 1201, 10854, 18432, 20480, 20480, 20480, 20480, 20480 ] - -]) - -TNS_COEF_FREQ = np.array([ - [ 1, 5, 15, 31, 54, 86, 97, 120, 159, 152, 111, 104, 59, 22, 6, 1, 1 ], - [ 1, 1, 1, 1, 13, 43, 94, 139, 173, 160, 154, 131, 78, 27, 6, 1, 1 ], - [ 1, 1, 1, 1, 9, 43, 106, 199, 217, 210, 141, 74, 17, 1, 1, 1, 1 ], - [ 1, 1, 1, 1, 2, 11, 49, 204, 285, 297, 120, 39, 9, 1, 1, 1, 1 ], - [ 1, 1, 1, 1, 1, 7, 42, 241, 341, 314, 58, 9, 3, 1, 1, 1, 1 ], - [ 1, 1, 1, 1, 1, 1, 13, 205, 366, 377, 47, 5, 1, 1, 1, 1, 1 ], - [ 1, 1, 1, 1, 1, 1, 13, 281, 330, 371, 17, 1, 1, 1, 1, 1, 1 ], - [ 1, 1, 1, 1, 1, 1, 5, 297, 1, 682, 26, 2, 1, 1, 1, 1, 1 ] -]) - -TNS_COEF_CUMFREQ = np.array([ - - [ 0, 1, 6, 21, 52, 106, 192, 289, - 409, 568, 720, 831, 935, 994, 1016, 1022, 1023 ], - - [ 0, 1, 2, 3, 4, 17, 60, 154, - 293, 466, 626, 780, 911, 989, 1016, 1022, 1023 ], - - [ 0, 1, 2, 3, 4, 13, 56, 162, - 361, 578, 788, 929, 1003, 1020, 1021, 1022, 1023 ], - - [ 0, 1, 2, 3, 4, 6, 17, 66, - 270, 555, 852, 972, 1011, 1020, 1021, 1022, 1023 ], - - [ 0, 1, 2, 3, 4, 5, 12, 54, - 295, 636, 950, 1008, 1017, 1020, 1021, 1022, 1023 ], - - [ 0, 1, 2, 3, 4, 5, 6, 19, - 224, 590, 967, 1014, 1019, 1020, 1021, 1022, 1023 ], - - [ 0, 1, 2, 3, 4, 5, 6, 19, - 300, 630, 1001, 1018, 1019, 1020, 1021, 1022, 1023 ], - - [ 0, 1, 2, 3, 4, 5, 6, 11, - 308, 309, 991, 1017, 1019, 1020, 1021, 1022, 1023 ], - -]) - - -### 3.7.6 ### - -LTPF_H12K8 = np.array([ - -2.04305583e-05, -4.46345894e-05, -7.16366399e-05, -1.00101113e-04, - -1.28372848e-04, -1.54543830e-04, -1.76544567e-04, -1.92256960e-04, - -1.99643819e-04, -1.96888686e-04, -1.82538332e-04, -1.55639427e-04, - -1.15860365e-04, -6.35893034e-05, 2.81006480e-19, 7.29218021e-05, - 1.52397076e-04, 2.34920777e-04, 3.16378650e-04, 3.92211738e-04, - 4.57623849e-04, 5.07824294e-04, 5.38295523e-04, 5.45072918e-04, - 5.25022155e-04, 4.76098424e-04, 3.97571380e-04, 2.90200217e-04, - 1.56344667e-04, -5.81880142e-19, -1.73252713e-04, -3.56385965e-04, - -5.41155231e-04, -7.18414023e-04, -8.78505232e-04, -1.01171451e-03, - -1.10876706e-03, -1.16134522e-03, -1.16260169e-03, -1.10764097e-03, - -9.93941563e-04, -8.21692190e-04, -5.94017766e-04, -3.17074654e-04, - 9.74695082e-19, 3.45293760e-04, 7.04480871e-04, 1.06133447e-03, - 1.39837473e-03, 1.69763080e-03, 1.94148675e-03, 2.11357591e-03, - 2.19968245e-03, 2.18860625e-03, 2.07294546e-03, 1.84975249e-03, - 1.52102188e-03, 1.09397426e-03, 5.81108062e-04, -1.42248266e-18, - -6.27153730e-04, -1.27425140e-03, -1.91223839e-03, -2.51026925e-03, - -3.03703830e-03, -3.46222687e-03, -3.75800672e-03, -3.90053247e-03, - -3.87135231e-03, -3.65866558e-03, -3.25835851e-03, -2.67475555e-03, - -1.92103305e-03, -1.01925433e-03, 1.86962369e-18, 1.09841545e-03, - 2.23113197e-03, 3.34830927e-03, 4.39702277e-03, 5.32342672e-03, - 6.07510531e-03, 6.60352025e-03, 6.86645399e-03, 6.83034270e-03, - 6.47239234e-03, 5.78237521e-03, 4.76401273e-03, 3.43586351e-03, - 1.83165284e-03, -2.25189837e-18, -1.99647619e-03, -4.08266886e-03, - -6.17308037e-03, -8.17444895e-03, -9.98882386e-03, -1.15169871e-02, - -1.26621006e-02, -1.33334458e-02, -1.34501120e-02, -1.29444881e-02, - -1.17654154e-02, -9.88086732e-03, -7.28003640e-03, -3.97473021e-03, - 2.50961778e-18, 4.58604422e-03, 9.70324900e-03, 1.52512477e-02, - 2.11120585e-02, 2.71533724e-02, 3.32324245e-02, 3.92003203e-02, - 4.49066644e-02, 5.02043309e-02, 5.49542017e-02, 5.90297032e-02, - 6.23209727e-02, 6.47385023e-02, 6.62161245e-02, 6.67132287e-02, - 6.62161245e-02, 6.47385023e-02, 6.23209727e-02, 5.90297032e-02, - 5.49542017e-02, 5.02043309e-02, 4.49066644e-02, 3.92003203e-02, - 3.32324245e-02, 2.71533724e-02, 2.11120585e-02, 1.52512477e-02, - 9.70324900e-03, 4.58604422e-03, 2.50961778e-18, -3.97473021e-03, - -7.28003640e-03, -9.88086732e-03, -1.17654154e-02, -1.29444881e-02, - -1.34501120e-02, -1.33334458e-02, -1.26621006e-02, -1.15169871e-02, - -9.98882386e-03, -8.17444895e-03, -6.17308037e-03, -4.08266886e-03, - -1.99647619e-03, -2.25189837e-18, 1.83165284e-03, 3.43586351e-03, - 4.76401273e-03, 5.78237521e-03, 6.47239234e-03, 6.83034270e-03, - 6.86645399e-03, 6.60352025e-03, 6.07510531e-03, 5.32342672e-03, - 4.39702277e-03, 3.34830927e-03, 2.23113197e-03, 1.09841545e-03, - 1.86962369e-18, -1.01925433e-03, -1.92103305e-03, -2.67475555e-03, - -3.25835851e-03, -3.65866558e-03, -3.87135231e-03, -3.90053247e-03, - -3.75800672e-03, -3.46222687e-03, -3.03703830e-03, -2.51026925e-03, - -1.91223839e-03, -1.27425140e-03, -6.27153730e-04, -1.42248266e-18, - 5.81108062e-04, 1.09397426e-03, 1.52102188e-03, 1.84975249e-03, - 2.07294546e-03, 2.18860625e-03, 2.19968245e-03, 2.11357591e-03, - 1.94148675e-03, 1.69763080e-03, 1.39837473e-03, 1.06133447e-03, - 7.04480871e-04, 3.45293760e-04, 9.74695082e-19, -3.17074654e-04, - -5.94017766e-04, -8.21692190e-04, -9.93941563e-04, -1.10764097e-03, - -1.16260169e-03, -1.16134522e-03, -1.10876706e-03, -1.01171451e-03, - -8.78505232e-04, -7.18414023e-04, -5.41155231e-04, -3.56385965e-04, - -1.73252713e-04, -5.81880142e-19, 1.56344667e-04, 2.90200217e-04, - 3.97571380e-04, 4.76098424e-04, 5.25022155e-04, 5.45072918e-04, - 5.38295523e-04, 5.07824294e-04, 4.57623849e-04, 3.92211738e-04, - 3.16378650e-04, 2.34920777e-04, 1.52397076e-04, 7.29218021e-05, - 2.81006480e-19, -6.35893034e-05, -1.15860365e-04, -1.55639427e-04, - -1.82538332e-04, -1.96888686e-04, -1.99643819e-04, -1.92256960e-04, - -1.76544567e-04, -1.54543830e-04, -1.28372848e-04, -1.00101113e-04, - -7.16366399e-05, -4.46345894e-05, -2.04305583e-05 -]) - -LTPF_H4 = np.array([ - -2.87456116e-03, -3.00125103e-03, 2.74547165e-03, 1.53572770e-02, - 2.86823405e-02, 2.95038503e-02, 4.59833449e-03, -4.72963246e-02, - -1.05835916e-01, -1.30305021e-01, -7.54404636e-02, 8.35788573e-02, - 3.30182571e-01, 6.03297008e-01, 8.17488686e-01, 8.98638285e-01, - 8.17488686e-01, 6.03297008e-01, 3.30182571e-01, 8.35788573e-02, - -7.54404636e-02, -1.30305021e-01, -1.05835916e-01, -4.72963246e-02, - 4.59833449e-03, 2.95038503e-02, 2.86823405e-02, 1.53572770e-02, - 2.74547165e-03, -3.00125103e-03, -2.87456116e-03 -]) - -LTPF_HI = np.array([ - 6.69885837e-03, 3.96711478e-02, 1.06999186e-01, 2.09880463e-01, - 3.35690625e-01, 4.59220930e-01, 5.50075002e-01, 5.83527575e-01, - 5.50075002e-01, 4.59220930e-01, 3.35690625e-01, 2.09880463e-01, - 1.06999186e-01, 3.96711478e-02, 6.69885837e-03 -]) - -LTPF_N_8K = np.array([ - [ 6.02361821e-01, 4.19760926e-01, -1.88342453e-02 ], - [ 5.99476858e-01, 4.19760926e-01, -1.59492828e-02 ], - [ 5.96776466e-01, 4.19760926e-01, -1.32488910e-02 ], - [ 5.94241012e-01, 4.19760926e-01, -1.07134366e-02 ], -]) - -LTPF_N_16K = np.array([ - [ 6.02361821e-01, 4.19760926e-01, -1.88342453e-02 ], - [ 5.99476858e-01, 4.19760926e-01, -1.59492828e-02 ], - [ 5.96776466e-01, 4.19760926e-01, -1.32488910e-02 ], - [ 5.94241012e-01, 4.19760926e-01, -1.07134366e-02 ], -]) - -LTPF_N_24K = np.array([ - - [ 3.98969559e-01, 5.14250861e-01, 1.00438297e-01, -1.27889396e-02, - -1.57228008e-03 ], - - [ 3.94863491e-01, 5.12381921e-01, 1.04319493e-01, -1.09199996e-02, - -1.34740833e-03 ], - - [ 3.90984448e-01, 5.10605352e-01, 1.07983252e-01, -9.14343107e-03, - -1.13212462e-03 ], - - [ 3.87309389e-01, 5.08912208e-01, 1.11451738e-01, -7.45028713e-03, - -9.25551405e-04 ], - -]) - -LTPF_N_32K = np.array([ - - [ 2.98237945e-01, 4.65280920e-01, 2.10599743e-01, 3.76678038e-02, - -1.01569616e-02, -2.53588100e-03, -3.18294617e-04 ], - - [ 2.94383415e-01, 4.61929400e-01, 2.12946577e-01, 4.06617500e-02, - -8.69327230e-03, -2.17830711e-03, -2.74288806e-04 ], - - [ 2.90743921e-01, 4.58746191e-01, 2.15145697e-01, 4.35010477e-02, - -7.29549535e-03, -1.83439564e-03, -2.31692019e-04 ], - - [ 2.87297585e-01, 4.55714889e-01, 2.17212695e-01, 4.62008888e-02, - -5.95746380e-03, -1.50293428e-03, -1.90385191e-04 ], - -]) - -LTPF_N_48K = np.array([ - - [ 1.98136374e-01, 3.52449490e-01, 2.51369527e-01, 1.42414624e-01, - 5.70473102e-02, 9.29336624e-03, -7.22602537e-03, -3.17267989e-03, - -1.12183596e-03, -2.90295724e-04, -4.27081559e-05 ], - - [ 1.95070943e-01, 3.48466041e-01, 2.50998846e-01, 1.44116741e-01, - 5.92894732e-02, 1.10892383e-02, -6.19290811e-03, -2.72670551e-03, - -9.66712583e-04, -2.50810092e-04, -3.69993877e-05 ], - - [ 1.92181006e-01, 3.44694556e-01, 2.50622009e-01, 1.45710245e-01, - 6.14113213e-02, 1.27994140e-02, -5.20372109e-03, -2.29732451e-03, - -8.16560813e-04, -2.12385575e-04, -3.14127133e-05 ], - - [ 1.89448531e-01, 3.41113925e-01, 2.50240688e-01, 1.47206563e-01, - 6.34247723e-02, 1.44320343e-02, -4.25444914e-03, -1.88308147e-03, - -6.70961906e-04, -1.74936334e-04, -2.59386474e-05 ], - -]) - -LTPF_D_8K = np.array([ - - [ 0.00000000e+00, 2.09880463e-01, 5.83527575e-01, 2.09880463e-01, - 0.00000000e+00 ], - - [ 0.00000000e+00, 1.06999186e-01, 5.50075002e-01, 3.35690625e-01, - 6.69885837e-03 ], - - [ 0.00000000e+00, 3.96711478e-02, 4.59220930e-01, 4.59220930e-01, - 3.96711478e-02 ], - - [ 0.00000000e+00, 6.69885837e-03, 3.35690625e-01, 5.50075002e-01, - 1.06999186e-01 ], - -]) - -LTPF_D_16K = np.array([ - - [ 0.00000000e+00, 2.09880463e-01, 5.83527575e-01, 2.09880463e-01, - 0.00000000e+00 ], - - [ 0.00000000e+00, 1.06999186e-01, 5.50075002e-01, 3.35690625e-01, - 6.69885837e-03 ], - - [ 0.00000000e+00, 3.96711478e-02, 4.59220930e-01, 4.59220930e-01, - 3.96711478e-02 ], - - [ 0.00000000e+00, 6.69885837e-03, 3.35690625e-01, 5.50075002e-01, - 1.06999186e-01 ], - -]) - -LTPF_D_24K = np.array([ - - [ 0.00000000e+00, 6.32223163e-02, 2.50730961e-01, 3.71390943e-01, - 2.50730961e-01, 6.32223163e-02, 0.00000000e+00 ], - - [ 0.00000000e+00, 3.45927217e-02, 1.98651560e-01, 3.62641173e-01, - 2.98675055e-01, 1.01309287e-01, 4.26354371e-03 ], - - [ 0.00000000e+00, 1.53574678e-02, 1.47434488e-01, 3.37425955e-01, - 3.37425955e-01, 1.47434488e-01, 1.53574678e-02 ], - - [ 0.00000000e+00, 4.26354371e-03, 1.01309287e-01, 2.98675055e-01, - 3.62641173e-01, 1.98651560e-01, 3.45927217e-02 ], - -]) - -LTPF_D_32K = np.array([ - - [ 0.00000000e+00, 2.90040188e-02, 1.12985742e-01, 2.21202403e-01, - 2.72390947e-01, 2.21202403e-01, 1.12985742e-01, 2.90040188e-02, - 0.00000000e+00 ], - - [ 0.00000000e+00, 1.70315342e-02, 8.72250379e-02, 1.96140776e-01, - 2.68923798e-01, 2.42499910e-01, 1.40577336e-01, 4.47487717e-02, - 3.12703024e-03 ], - - [ 0.00000000e+00, 8.56367375e-03, 6.42622294e-02, 1.68767671e-01, - 2.58744594e-01, 2.58744594e-01, 1.68767671e-01, 6.42622294e-02, - 8.56367375e-03 ], - - [ 0.00000000e+00, 3.12703024e-03, 4.47487717e-02, 1.40577336e-01, - 2.42499910e-01, 2.68923798e-01, 1.96140776e-01, 8.72250379e-02, - 1.70315342e-02 ], - -]) - -LTPF_D_48K = np.array([ - - [ 0.00000000e+00, 1.08235939e-02, 3.60896922e-02, 7.67640147e-02, - 1.24153058e-01, 1.62759644e-01, 1.77677142e-01, 1.62759644e-01, - 1.24153058e-01, 7.67640147e-02, 3.60896922e-02, 1.08235939e-02, - 0.00000000e+00 ], - - [ 0.00000000e+00, 7.04140493e-03, 2.81970232e-02, 6.54704494e-02, - 1.12464799e-01, 1.54841896e-01, 1.76712238e-01, 1.69150721e-01, - 1.35290158e-01, 8.85142501e-02, 4.49935385e-02, 1.55761371e-02, - 2.03972196e-03 ], - - [ 0.00000000e+00, 4.14699847e-03, 2.13575731e-02, 5.48273558e-02, - 1.00497144e-01, 1.45606034e-01, 1.73843984e-01, 1.73843984e-01, - 1.45606034e-01, 1.00497144e-01, 5.48273558e-02, 2.13575731e-02, - 4.14699847e-03 ], - - [ 0.00000000e+00, 2.03972196e-03, 1.55761371e-02, 4.49935385e-02, - 8.85142501e-02, 1.35290158e-01, 1.69150721e-01, 1.76712238e-01, - 1.54841896e-01, 1.12464799e-01, 6.54704494e-02, 2.81970232e-02, - 7.04140493e-03 ], - -]) - -### 3.7.7 ### - -AC_SPEC_LOOKUP = np.array([ - 1, 39, 7, 25, 22, 22, 28, 22, 22, 22, 22, 28, 28, 28, 34, 31, - 31, 40, 43, 46, 49, 52, 14, 17, 36, 36, 36, 38, 0, 57, 38, 22, - 0, 8, 9, 11, 47, 14, 14, 17, 36, 36, 36, 38, 59, 59, 38, 22, - 22, 26, 46, 29, 30, 32, 33, 35, 36, 36, 36, 38, 0, 59, 23, 22, - 46, 46, 45, 47, 48, 50, 50, 18, 54, 54, 54, 38, 59, 59, 59, 22, - 0, 62, 63, 3, 33, 2, 2, 61, 20, 20, 20, 21, 59, 59, 39, 28, - 28, 63, 63, 3, 33, 2, 2, 61, 38, 38, 38, 21, 59, 59, 39, 28, - 28, 6, 6, 6, 2, 18, 61, 20, 21, 21, 21, 59, 39, 39, 7, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 51, 51, 51, 53, 54, 20, 38, 38, 57, 39, 39, 39, 7, 24, 34, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 56, 38, 57, 57, 59, 7, 7, 7, 42, 42, 34, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 5, 4, 4, 5, 21, 21, 59, 7, 7, 7, 7, 25, 25, 25, 34, - 4, 4, 4, 4, 5, 23, 23, 39, 7, 7, 7, 42, 25, 25, 22, 31, - 31, 39, 39, 39, 39, 7, 7, 42, 0, 25, 22, 22, 22, 28, 34, 31, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 40, 8, 9, 49, 49, 52, 17, 17, 17, 4, 0, 20, 17, 60, - 40, 40, 8, 43, 27, 49, 49, 14, 17, 17, 17, 36, 42, 42, 17, 57, - 57, 40, 8, 26, 27, 49, 12, 14, 17, 17, 17, 36, 0, 38, 36, 1, - 8, 8, 43, 9, 11, 49, 12, 14, 14, 33, 50, 50, 50, 61, 36, 39, - 8, 8, 43, 46, 49, 52, 30, 14, 14, 33, 50, 50, 50, 50, 18, 25, - 8, 8, 43, 46, 49, 52, 30, 14, 14, 18, 5, 5, 5, 61, 18, 23, - 43, 43, 43, 9, 49, 52, 3, 14, 14, 50, 50, 50, 50, 61, 17, 24, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 9, 11, 52, 52, 14, 14, 17, 61, 61, 61, 54, 17, 39, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 44, 27, 29, 52, 48, 52, 52, 17, 17, 17, 17, 2, 17, 7, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 9, 27, 27, 12, 52, 14, 14, 58, 41, 41, 41, 6, 17, 37, - 9, 9, 9, 27, 11, 49, 12, 52, 14, 14, 14, 50, 0, 53, 17, 28, - 52, 52, 49, 52, 12, 52, 30, 14, 14, 17, 2, 2, 2, 38, 38, 34, - 31, 34, 34, 31, 31, 31, 31, 19, 19, 19, 19, 19, 19, 19, 31, 19, - 44, 44, 62, 30, 32, 58, 35, 36, 36, 38, 0, 59, 7, 7, 39, 34, - 34, 45, 47, 48, 33, 35, 35, 36, 38, 38, 38, 59, 7, 7, 39, 34, - 34, 62, 30, 15, 50, 53, 53, 54, 21, 21, 21, 59, 7, 7, 7, 34, - 30, 30, 48, 33, 58, 18, 18, 56, 23, 23, 23, 59, 7, 7, 24, 34, - 34, 6, 6, 58, 53, 54, 54, 21, 59, 59, 59, 39, 7, 7, 42, 34, - 6, 6, 33, 58, 53, 54, 61, 21, 59, 59, 59, 39, 7, 7, 42, 34, - 34, 51, 51, 53, 54, 56, 56, 57, 39, 39, 39, 7, 42, 42, 25, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 4, 4, 4, 5, 23, 23, 39, 7, 7, 7, 42, 25, 25, 22, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 5, 5, 5, 5, 57, 57, 39, 24, 24, 24, 42, 22, 22, 28, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 41, 41, 41, 41, 39, 39, 7, 42, 42, 42, 25, 28, 28, 28, 31, - 31, 41, 41, 41, 41, 39, 39, 24, 25, 25, 25, 22, 28, 28, 34, 31, - 31, 10, 10, 10, 10, 10, 10, 28, 34, 34, 34, 34, 34, 34, 31, 19, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 9, 11, 47, 32, 50, 18, 18, 20, 21, 21, 21, 39, 59, 34, - 26, 26, 27, 29, 30, 33, 50, 18, 18, 20, 57, 57, 57, 59, 59, 34, - 27, 27, 11, 12, 48, 50, 58, 61, 61, 56, 57, 57, 57, 59, 39, 34, - 45, 45, 12, 30, 32, 2, 2, 61, 38, 38, 38, 57, 0, 59, 39, 34, - 63, 63, 3, 32, 58, 18, 18, 20, 21, 21, 21, 59, 39, 39, 7, 31, - 31, 3, 3, 33, 58, 18, 18, 20, 21, 21, 21, 59, 7, 7, 7, 31, - 6, 6, 51, 51, 53, 54, 54, 38, 57, 57, 57, 39, 7, 7, 42, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 51, 53, 53, 54, 56, 56, 57, 59, 59, 59, 7, 24, 24, 25, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 4, 4, 4, 54, 21, 21, 57, 39, 39, 39, 7, 42, 42, 22, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 5, 5, 5, 5, 23, 23, 59, 7, 7, 7, 42, 22, 22, 28, 31, - 31, 4, 4, 4, 5, 23, 23, 39, 24, 24, 24, 25, 28, 28, 34, 31, - 31, 10, 10, 10, 10, 10, 10, 28, 34, 34, 34, 31, 31, 31, 31, 19, - 13, 13, 13, 13, 13, 13, 13, 13, 60, 60, 60, 60, 60, 60, 60, 16, - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 60, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 13, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 0, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 13, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, - 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 37, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 60, 16, - 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 60, 16, - 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 60, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 60, 16, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 60, 60, 16, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 60, 60, 16, - 13, 13, 13, 13, 13, 13, 13, 13, 60, 60, 60, 60, 60, 60, 60, 16, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 16, 16, 16, 16, 16, 37, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 60, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 60, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 60, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 60, 60, 60, 16, - 13, 13, 13, 13, 13, 13, 13, 13, 60, 60, 60, 60, 60, 60, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 37, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 13, 13, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 0, 13, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 19, 13, 13, 13, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 60, 13, 13, 13, 13, 13, 13, 60, 60, 60, 60, 60, 60, 60, 60, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 60, 60, 60, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 60, - 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 60, - 13, 13, 13, 13, 13, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 13, 13, 13, 13, 0, 0, - 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 60, - 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]) - -AC_SPEC_BITS = np.array([ - - [ 20480, 20480, 5220, 9042, 20480, 20480, 6619, 9892, - 5289, 6619, 9105, 11629, 8982, 9892, 11629, 13677, 4977 ], - - [ 11940, 10854, 12109, 13677, 10742, 9812, 11090, 12288, - 11348, 10240, 11348, 12683, 12109, 10854, 11629, 12902, 1197 ], - - [ 7886, 7120, 8982, 10970, 7496, 6815, 8334, 10150, - 9437, 8535, 9656, 11216, 11348, 10431, 11348, 12479, 4051 ], - - [ 5485, 6099, 9168, 11940, 6311, 6262, 8640, 11090, - 9233, 8640, 10334, 12479, 11781, 11090, 12479, 13988, 6009 ], - - [ 7886, 7804, 10150, 11940, 7886, 7685, 9368, 10854, - 10061, 9300, 10431, 11629, 11629, 10742, 11485, 12479, 2763 ], - - [ 9042, 8383, 10240, 11781, 8483, 8013, 9437, 10742, - 10334, 9437, 10431, 11485, 11781, 10742, 11485, 12288, 2346 ], - - [ 5922, 6619, 9368, 11940, 6566, 6539, 8750, 10970, - 9168, 8640, 10240, 12109, 11485, 10742, 11940, 13396, 5009 ], - - [ 12288, 11090, 11348, 12109, 11090, 9892, 10334, 10970, - 11629, 10431, 10970, 11629, 12479, 11348, 11781, 12288, 1289 ], - - [ 1685, 5676, 13138, 18432, 5598, 7804, 13677, 18432, - 12683, 13396, 17234, 20480, 17234, 17234, 20480, 20480, 15725 ], - - [ 2793, 5072, 10970, 15725, 5204, 6487, 11216, 15186, - 10970, 11216, 14336, 17234, 15186, 15186, 17234, 18432, 12109 ], - - [ 12902, 11485, 11940, 13396, 11629, 10531, 11348, 12479, - 12683, 11629, 12288, 13138, 13677, 12683, 13138, 13677, 854 ], - - [ 3821, 5088, 9812, 13988, 5289, 5901, 9812, 13677, - 9976, 9892, 12479, 15186, 13988, 13677, 15186, 17234, 9812 ], - - [ 4856, 5412, 9168, 12902, 5598, 5736, 8863, 12288, - 9368, 8982, 11090, 13677, 12902, 12288, 13677, 15725, 8147 ], - - [ 20480, 20480, 7088, 9300, 20480, 20480, 7844, 9733, - 7320, 7928, 9368, 10970, 9581, 9892, 10970, 12288, 2550 ], - - [ 6031, 5859, 8192, 10635, 6410, 6286, 8433, 10742, - 9656, 9042, 10531, 12479, 12479, 11629, 12902, 14336, 5756 ], - - [ 6144, 6215, 8982, 11940, 6262, 6009, 8433, 11216, - 8982, 8433, 10240, 12479, 11781, 11090, 12479, 13988, 5817 ], - - [ 20480, 20480, 11216, 12109, 20480, 20480, 11216, 11940, - 11629, 11485, 11940, 12479, 12479, 12109, 12683, 13138, 704 ], - - [ 7928, 6994, 8239, 9733, 7218, 6539, 8147, 9892, - 9812, 9105, 10240, 11629, 12109, 11216, 12109, 13138, 4167 ], - - [ 8640, 7724, 9233, 10970, 8013, 7185, 8483, 10150, - 9656, 8694, 9656, 10970, 11348, 10334, 11090, 12288, 3391 ], - - [ 20480, 18432, 18432, 18432, 18432, 18432, 18432, 18432, - 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 91 ], - - [ 10061, 8863, 9733, 11090, 8982, 7970, 8806, 9976, - 10061, 9105, 9812, 10742, 11485, 10334, 10970, 11781, 2557 ], - - [ 10431, 9368, 10240, 11348, 9368, 8433, 9233, 10334, - 10431, 9437, 10061, 10970, 11781, 10635, 11216, 11940, 2119 ], - - [ 13988, 12479, 12683, 12902, 12683, 11348, 11485, 11940, - 12902, 11629, 11940, 12288, 13396, 12109, 12479, 12683, 828 ], - - [ 10431, 9300, 10334, 11629, 9508, 8483, 9437, 10635, - 10635, 9656, 10431, 11348, 11940, 10854, 11485, 12288, 1946 ], - - [ 12479, 11216, 11629, 12479, 11348, 10150, 10635, 11348, - 11940, 10854, 11216, 11940, 12902, 11629, 11940, 12479, 1146 ], - - [ 13396, 12109, 12288, 12902, 12109, 10854, 11216, 11781, - 12479, 11348, 11629, 12109, 13138, 11940, 12288, 12683, 928 ], - - [ 2443, 5289, 11629, 16384, 5170, 6730, 11940, 16384, - 11216, 11629, 14731, 18432, 15725, 15725, 18432, 20480, 13396 ], - - [ 3328, 5009, 10531, 15186, 5040, 6031, 10531, 14731, - 10431, 10431, 13396, 16384, 15186, 14731, 16384, 18432, 11629 ], - - [ 14336, 12902, 12902, 13396, 12902, 11629, 11940, 12288, - 13138, 12109, 12288, 12902, 13677, 12683, 12902, 13138, 711 ], - - [ 4300, 5204, 9437, 13396, 5430, 5776, 9300, 12902, - 9656, 9437, 11781, 14731, 13396, 12902, 14731, 16384, 8982 ], - - [ 5394, 5776, 8982, 12288, 5922, 5901, 8640, 11629, - 9105, 8694, 10635, 13138, 12288, 11629, 13138, 14731, 6844 ], - - [ 17234, 15725, 15725, 15725, 15725, 14731, 14731, 14731, - 16384, 14731, 14731, 15186, 16384, 15186, 15186, 15186, 272 ], - - [ 6461, 6286, 8806, 11348, 6566, 6215, 8334, 10742, - 9233, 8535, 10061, 12109, 11781, 10970, 12109, 13677, 5394 ], - - [ 6674, 6487, 8863, 11485, 6702, 6286, 8334, 10635, - 9168, 8483, 9976, 11940, 11629, 10854, 11940, 13396, 5105 ], - - [ 15186, 13677, 13677, 13988, 13677, 12479, 12479, 12683, - 13988, 12683, 12902, 13138, 14336, 13138, 13396, 13677, 565 ], - - [ 7844, 7252, 8922, 10854, 7389, 6815, 8383, 10240, - 9508, 8750, 9892, 11485, 11629, 10742, 11629, 12902, 3842 ], - - [ 9233, 8239, 9233, 10431, 8334, 7424, 8483, 9892, - 10061, 9105, 10061, 11216, 11781, 10742, 11485, 12479, 2906 ], - - [ 20480, 20480, 14731, 14731, 20480, 20480, 14336, 14336, - 15186, 14336, 14731, 14731, 15186, 14731, 14731, 15186, 266 ], - - [ 10531, 9300, 9976, 11090, 9437, 8286, 9042, 10061, - 10431, 9368, 9976, 10854, 11781, 10531, 11090, 11781, 2233 ], - - [ 11629, 10334, 10970, 12109, 10431, 9368, 10061, 10970, - 11348, 10240, 10854, 11485, 12288, 11216, 11629, 12288, 1469 ], - - [ 952, 6787, 15725, 20480, 6646, 9733, 16384, 20480, - 14731, 15725, 18432, 20480, 18432, 20480, 20480, 20480, 18432 ], - - [ 9437, 8806, 10742, 12288, 8982, 8483, 9892, 11216, - 10742, 9892, 10854, 11940, 12109, 11090, 11781, 12683, 1891 ], - - [ 12902, 11629, 11940, 12479, 11781, 10531, 10854, 11485, - 12109, 10970, 11348, 11940, 12902, 11781, 12109, 12479, 1054 ], - - [ 2113, 5323, 11781, 16384, 5579, 7252, 12288, 16384, - 11781, 12288, 15186, 18432, 15725, 16384, 18432, 20480, 12902 ], - - [ 2463, 5965, 11348, 15186, 5522, 6934, 11216, 14731, - 10334, 10635, 13677, 16384, 13988, 13988, 15725, 18432, 10334 ], - - [ 3779, 5541, 9812, 13677, 5467, 6122, 9656, 13138, - 9581, 9437, 11940, 14731, 13138, 12683, 14336, 16384, 8982 ], - - [ 3181, 5154, 10150, 14336, 5448, 6311, 10334, 13988, - 10334, 10431, 13138, 15725, 14336, 13988, 15725, 18432, 10431 ], - - [ 4841, 5560, 9105, 12479, 5756, 5944, 8922, 12109, - 9300, 8982, 11090, 13677, 12479, 12109, 13677, 15186, 7460 ], - - [ 5859, 6009, 8922, 11940, 6144, 5987, 8483, 11348, - 9042, 8535, 10334, 12683, 11940, 11216, 12683, 14336, 6215 ], - - [ 4250, 4916, 8587, 12109, 5901, 6191, 9233, 12288, - 10150, 9892, 11940, 14336, 13677, 13138, 14731, 16384, 8383 ], - - [ 7153, 6702, 8863, 11216, 6904, 6410, 8239, 10431, - 9233, 8433, 9812, 11629, 11629, 10742, 11781, 13138, 4753 ], - - [ 6674, 7057, 9508, 11629, 7120, 6964, 8806, 10635, - 9437, 8750, 10061, 11629, 11485, 10531, 11485, 12683, 4062 ], - - [ 5341, 5289, 8013, 10970, 6311, 6262, 8640, 11090, - 10061, 9508, 11090, 13138, 12902, 12288, 13396, 15186, 6539 ], - - [ 8057, 7533, 9300, 11216, 7685, 7057, 8535, 10334, - 9508, 8694, 9812, 11216, 11485, 10431, 11348, 12479, 3541 ], - - [ 9168, 8239, 9656, 11216, 8483, 7608, 8806, 10240, - 9892, 8982, 9812, 11090, 11485, 10431, 11090, 12109, 2815 ], - - [ 558, 7928, 18432, 20480, 7724, 12288, 20480, 20480, - 18432, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480 ], - - [ 9892, 8806, 9976, 11348, 9042, 8057, 9042, 10240, - 10240, 9233, 9976, 11090, 11629, 10531, 11216, 12109, 2371 ], - - [ 11090, 9812, 10531, 11629, 9976, 8863, 9508, 10531, - 10854, 9733, 10334, 11090, 11940, 10742, 11216, 11940, 1821 ], - - [ 7354, 6964, 9042, 11216, 7153, 6592, 8334, 10431, - 9233, 8483, 9812, 11485, 11485, 10531, 11629, 12902, 4349 ], - - [ 11348, 10150, 10742, 11629, 10150, 9042, 9656, 10431, - 10854, 9812, 10431, 11216, 12109, 10970, 11485, 12109, 1700 ], - - [ 20480, 20480, 8694, 10150, 20480, 20480, 8982, 10240, - 8982, 9105, 9976, 10970, 10431, 10431, 11090, 11940, 1610 ], - - [ 9233, 8192, 9368, 10970, 8286, 7496, 8587, 9976, - 9812, 8863, 9733, 10854, 11348, 10334, 11090, 11940, 3040 ], - - [ 4202, 5716, 9733, 13138, 5598, 6099, 9437, 12683, - 9300, 9168, 11485, 13988, 12479, 12109, 13988, 15725, 7804 ], - - [ 4400, 5965, 9508, 12479, 6009, 6360, 9105, 11781, - 9300, 8982, 10970, 13138, 12109, 11629, 13138, 14731, 6994 ] -]) - -AC_SPEC_CUMFREQ = np.array([ - - [ 0, 1, 2, 177, 225, 226, 227, 336, - 372, 543, 652, 699, 719, 768, 804, 824, 834 ], - - [ 0, 18, 44, 61, 71, 98, 135, 159, - 175, 197, 229, 251, 265, 282, 308, 328, 341 ], - - [ 0, 71, 163, 212, 237, 318, 420, 481, - 514, 556, 613, 652, 675, 697, 727, 749, 764 ], - - [ 0, 160, 290, 336, 354, 475, 598, 653, - 677, 722, 777, 808, 823, 842, 866, 881, 890 ], - - [ 0, 71, 144, 177, 195, 266, 342, 385, - 411, 445, 489, 519, 539, 559, 586, 607, 622 ], - - [ 0, 48, 108, 140, 159, 217, 285, 327, - 354, 385, 427, 457, 478, 497, 524, 545, 561 ], - - [ 0, 138, 247, 290, 308, 419, 531, 584, - 609, 655, 710, 742, 759, 780, 807, 825, 836 ], - - [ 0, 16, 40, 62, 79, 103, 139, 170, - 195, 215, 245, 270, 290, 305, 327, 346, 362 ], - - [ 0, 579, 729, 741, 743, 897, 970, 980, - 982, 996, 1007, 1010, 1011, 1014, 1017, 1018, 1019 ], - - [ 0, 398, 582, 607, 612, 788, 902, 925, - 931, 956, 979, 987, 990, 996, 1002, 1005, 1007 ], - - [ 0, 13, 34, 52, 63, 83, 112, 134, - 149, 163, 183, 199, 211, 221, 235, 247, 257 ], - - [ 0, 281, 464, 501, 510, 681, 820, 857, - 867, 902, 938, 953, 959, 968, 978, 984, 987 ], - - [ 0, 198, 362, 408, 421, 575, 722, 773, - 789, 832, 881, 905, 915, 928, 944, 954, 959 ], - - [ 0, 1, 2, 95, 139, 140, 141, 213, - 251, 337, 407, 450, 475, 515, 551, 576, 592 ], - - [ 0, 133, 274, 338, 366, 483, 605, 664, - 691, 730, 778, 807, 822, 837, 857, 870, 878 ], - - [ 0, 128, 253, 302, 320, 443, 577, 636, - 659, 708, 767, 799, 814, 833, 857, 872, 881 ], - - [ 0, 1, 2, 25, 42, 43, 44, 67, - 85, 105, 126, 144, 159, 174, 191, 205, 217 ], - - [ 0, 70, 166, 229, 267, 356, 468, 533, - 569, 606, 653, 685, 705, 722, 745, 762, 774 ], - - [ 0, 55, 130, 175, 200, 268, 358, 416, - 449, 488, 542, 581, 606, 628, 659, 683, 699 ], - - [ 0, 1, 3, 5, 7, 9, 11, 13, - 15, 17, 19, 21, 23, 25, 27, 29, 31 ], - - [ 0, 34, 85, 123, 147, 196, 265, 317, - 352, 386, 433, 470, 497, 518, 549, 574, 593 ], - - [ 0, 30, 73, 105, 127, 170, 229, 274, - 305, 335, 377, 411, 436, 455, 483, 506, 524 ], - - [ 0, 9, 24, 38, 51, 65, 87, 108, - 126, 139, 159, 177, 193, 204, 221, 236, 250 ], - - [ 0, 30, 74, 105, 125, 166, 224, 266, - 294, 322, 361, 391, 413, 431, 457, 478, 494 ], - - [ 0, 15, 38, 58, 73, 95, 128, 156, - 178, 196, 222, 245, 263, 276, 296, 314, 329 ], - - [ 0, 11, 28, 44, 57, 74, 100, 123, - 142, 157, 179, 199, 216, 228, 246, 262, 276 ], - - [ 0, 448, 619, 639, 643, 821, 926, 944, - 948, 971, 991, 998, 1000, 1005, 1010, 1012, 1013 ], - - [ 0, 332, 520, 549, 555, 741, 874, 903, - 910, 940, 970, 981, 985, 991, 998, 1002, 1004 ], - - [ 0, 8, 21, 34, 45, 58, 78, 96, - 112, 124, 141, 157, 170, 180, 194, 207, 219 ], - - [ 0, 239, 415, 457, 468, 631, 776, 820, - 833, 872, 914, 933, 940, 951, 964, 971, 975 ], - - [ 0, 165, 310, 359, 375, 513, 652, 707, - 727, 774, 828, 856, 868, 884, 904, 916, 923 ], - - [ 0, 3, 8, 13, 18, 23, 30, 37, - 44, 48, 55, 62, 68, 72, 78, 84, 90 ], - - [ 0, 115, 237, 289, 311, 422, 547, 608, - 635, 680, 737, 771, 788, 807, 832, 849, 859 ], - - [ 0, 107, 221, 272, 293, 399, 521, 582, - 610, 656, 714, 749, 767, 787, 813, 831, 842 ], - - [ 0, 6, 16, 26, 35, 45, 60, 75, - 89, 98, 112, 125, 137, 145, 157, 168, 178 ], - - [ 0, 72, 160, 210, 236, 320, 422, 482, - 514, 555, 608, 644, 665, 685, 712, 732, 745 ], - - [ 0, 45, 108, 153, 183, 244, 327, 385, - 421, 455, 502, 536, 559, 578, 605, 626, 641 ], - - [ 0, 1, 2, 9, 16, 17, 18, 26, - 34, 40, 48, 55, 62, 68, 75, 82, 88 ], - - [ 0, 29, 73, 108, 132, 174, 236, 284, - 318, 348, 391, 426, 452, 471, 500, 524, 543 ], - - [ 0, 20, 51, 76, 93, 123, 166, 200, - 225, 247, 279, 305, 326, 342, 365, 385, 401 ], - - [ 0, 742, 845, 850, 851, 959, 997, 1001, - 1002, 1009, 1014, 1016, 1017, 1019, 1020, 1021, 1022 ], - - [ 0, 42, 94, 121, 137, 186, 244, 280, - 303, 330, 366, 392, 410, 427, 451, 470, 484 ], - - [ 0, 13, 33, 51, 66, 85, 114, 140, - 161, 178, 203, 225, 243, 256, 275, 292, 307 ], - - [ 0, 501, 670, 689, 693, 848, 936, 952, - 956, 975, 991, 997, 999, 1004, 1008, 1010, 1011 ], - - [ 0, 445, 581, 603, 609, 767, 865, 888, - 895, 926, 954, 964, 968, 977, 986, 991, 993 ], - - [ 0, 285, 442, 479, 489, 650, 779, 818, - 830, 870, 912, 930, 937, 949, 963, 971, 975 ], - - [ 0, 349, 528, 561, 569, 731, 852, 883, - 892, 923, 953, 965, 970, 978, 987, 992, 994 ], - - [ 0, 199, 355, 402, 417, 563, 700, 750, - 767, 811, 860, 884, 894, 909, 926, 936, 942 ], - - [ 0, 141, 275, 325, 343, 471, 606, 664, - 686, 734, 791, 822, 836, 854, 877, 891, 899 ], - - [ 0, 243, 437, 493, 510, 649, 775, 820, - 836, 869, 905, 923, 931, 941, 953, 960, 964 ], - - [ 0, 91, 197, 248, 271, 370, 487, 550, - 580, 625, 684, 721, 741, 761, 788, 807, 819 ], - - [ 0, 107, 201, 242, 262, 354, 451, 503, - 531, 573, 626, 660, 680, 701, 730, 751, 765 ], - - [ 0, 168, 339, 407, 432, 553, 676, 731, - 755, 789, 830, 854, 866, 879, 895, 906, 912 ], - - [ 0, 67, 147, 191, 214, 290, 384, 441, - 472, 513, 567, 604, 627, 648, 678, 700, 715 ], - - [ 0, 46, 109, 148, 171, 229, 307, 359, - 391, 427, 476, 513, 537, 558, 588, 612, 629 ], - - [ 0, 848, 918, 920, 921, 996, 1012, 1013, - 1014, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023 ], - - [ 0, 36, 88, 123, 145, 193, 260, 308, - 340, 372, 417, 452, 476, 496, 525, 548, 565 ], - - [ 0, 24, 61, 90, 110, 145, 196, 237, - 266, 292, 330, 361, 385, 403, 430, 453, 471 ], - - [ 0, 85, 182, 230, 253, 344, 454, 515, - 545, 590, 648, 685, 706, 727, 756, 776, 789 ], - - [ 0, 22, 55, 82, 102, 135, 183, 222, - 252, 278, 315, 345, 368, 385, 410, 431, 448 ], - - [ 0, 1, 2, 56, 89, 90, 91, 140, - 172, 221, 268, 303, 328, 358, 388, 412, 430 ], - - [ 0, 45, 109, 152, 177, 239, 320, 376, - 411, 448, 499, 537, 563, 585, 616, 640, 658 ], - - [ 0, 247, 395, 433, 445, 599, 729, 771, - 785, 829, 875, 896, 905, 920, 937, 946, 951 ], - - [ 0, 231, 367, 408, 423, 557, 676, 723, - 742, 786, 835, 860, 872, 889, 909, 921, 928 ] - -]) - -AC_SPEC_FREQ = np.array([ - - [ 1, 1, 175, 48, 1, 1, 109, 36, - 171, 109, 47, 20, 49, 36, 20, 10, 190 ], - - [ 18, 26, 17, 10, 27, 37, 24, 16, - 22, 32, 22, 14, 17, 26, 20, 13, 683 ], - - [ 71, 92, 49, 25, 81, 102, 61, 33, - 42, 57, 39, 23, 22, 30, 22, 15, 260 ], - - [ 160, 130, 46, 18, 121, 123, 55, 24, - 45, 55, 31, 15, 19, 24, 15, 9, 134 ], - - [ 71, 73, 33, 18, 71, 76, 43, 26, - 34, 44, 30, 20, 20, 27, 21, 15, 402 ], - - [ 48, 60, 32, 19, 58, 68, 42, 27, - 31, 42, 30, 21, 19, 27, 21, 16, 463 ], - - [ 138, 109, 43, 18, 111, 112, 53, 25, - 46, 55, 32, 17, 21, 27, 18, 11, 188 ], - - [ 16, 24, 22, 17, 24, 36, 31, 25, - 20, 30, 25, 20, 15, 22, 19, 16, 662 ], - - [ 579, 150, 12, 2, 154, 73, 10, 2, - 14, 11, 3, 1, 3, 3, 1, 1, 5 ], - - [ 398, 184, 25, 5, 176, 114, 23, 6, - 25, 23, 8, 3, 6, 6, 3, 2, 17 ], - - [ 13, 21, 18, 11, 20, 29, 22, 15, - 14, 20, 16, 12, 10, 14, 12, 10, 767 ], - - [ 281, 183, 37, 9, 171, 139, 37, 10, - 35, 36, 15, 6, 9, 10, 6, 3, 37 ], - - [ 198, 164, 46, 13, 154, 147, 51, 16, - 43, 49, 24, 10, 13, 16, 10, 5, 65 ], - - [ 1, 1, 93, 44, 1, 1, 72, 38, - 86, 70, 43, 25, 40, 36, 25, 16, 432 ], - - [ 133, 141, 64, 28, 117, 122, 59, 27, - 39, 48, 29, 15, 15, 20, 13, 8, 146 ], - - [ 128, 125, 49, 18, 123, 134, 59, 23, - 49, 59, 32, 15, 19, 24, 15, 9, 143 ], - - [ 1, 1, 23, 17, 1, 1, 23, 18, - 20, 21, 18, 15, 15, 17, 14, 12, 807 ], - - [ 70, 96, 63, 38, 89, 112, 65, 36, - 37, 47, 32, 20, 17, 23, 17, 12, 250 ], - - [ 55, 75, 45, 25, 68, 90, 58, 33, - 39, 54, 39, 25, 22, 31, 24, 16, 325 ], - - [ 1, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 993 ], - - [ 34, 51, 38, 24, 49, 69, 52, 35, - 34, 47, 37, 27, 21, 31, 25, 19, 431 ], - - [ 30, 43, 32, 22, 43, 59, 45, 31, - 30, 42, 34, 25, 19, 28, 23, 18, 500 ], - - [ 9, 15, 14, 13, 14, 22, 21, 18, - 13, 20, 18, 16, 11, 17, 15, 14, 774 ], - - [ 30, 44, 31, 20, 41, 58, 42, 28, - 28, 39, 30, 22, 18, 26, 21, 16, 530 ], - - [ 15, 23, 20, 15, 22, 33, 28, 22, - 18, 26, 23, 18, 13, 20, 18, 15, 695 ], - - [ 11, 17, 16, 13, 17, 26, 23, 19, - 15, 22, 20, 17, 12, 18, 16, 14, 748 ], - - [ 448, 171, 20, 4, 178, 105, 18, 4, - 23, 20, 7, 2, 5, 5, 2, 1, 11 ], - - [ 332, 188, 29, 6, 186, 133, 29, 7, - 30, 30, 11, 4, 6, 7, 4, 2, 20 ], - - [ 8, 13, 13, 11, 13, 20, 18, 16, - 12, 17, 16, 13, 10, 14, 13, 12, 805 ], - - [ 239, 176, 42, 11, 163, 145, 44, 13, - 39, 42, 19, 7, 11, 13, 7, 4, 49 ], - - [ 165, 145, 49, 16, 138, 139, 55, 20, - 47, 54, 28, 12, 16, 20, 12, 7, 101 ], - - [ 3, 5, 5, 5, 5, 7, 7, 7, - 4, 7, 7, 6, 4, 6, 6, 6, 934 ], - - [ 115, 122, 52, 22, 111, 125, 61, 27, - 45, 57, 34, 17, 19, 25, 17, 10, 165 ], - - [ 107, 114, 51, 21, 106, 122, 61, 28, - 46, 58, 35, 18, 20, 26, 18, 11, 182 ], - - [ 6, 10, 10, 9, 10, 15, 15, 14, - 9, 14, 13, 12, 8, 12, 11, 10, 846 ], - - [ 72, 88, 50, 26, 84, 102, 60, 32, - 41, 53, 36, 21, 20, 27, 20, 13, 279 ], - - [ 45, 63, 45, 30, 61, 83, 58, 36, - 34, 47, 34, 23, 19, 27, 21, 15, 383 ], - - [ 1, 1, 7, 7, 1, 1, 8, 8, - 6, 8, 7, 7, 6, 7, 7, 6, 936 ], - - [ 29, 44, 35, 24, 42, 62, 48, 34, - 30, 43, 35, 26, 19, 29, 24, 19, 481 ], - - [ 20, 31, 25, 17, 30, 43, 34, 25, - 22, 32, 26, 21, 16, 23, 20, 16, 623 ], - - [ 742, 103, 5, 1, 108, 38, 4, 1, - 7, 5, 2, 1, 2, 1, 1, 1, 2 ], - - [ 42, 52, 27, 16, 49, 58, 36, 23, - 27, 36, 26, 18, 17, 24, 19, 14, 540 ], - - [ 13, 20, 18, 15, 19, 29, 26, 21, - 17, 25, 22, 18, 13, 19, 17, 15, 717 ], - - [ 501, 169, 19, 4, 155, 88, 16, 4, - 19, 16, 6, 2, 5, 4, 2, 1, 13 ], - - [ 445, 136, 22, 6, 158, 98, 23, 7, - 31, 28, 10, 4, 9, 9, 5, 2, 31 ], - - [ 285, 157, 37, 10, 161, 129, 39, 12, - 40, 42, 18, 7, 12, 14, 8, 4, 49 ], - - [ 349, 179, 33, 8, 162, 121, 31, 9, - 31, 30, 12, 5, 8, 9, 5, 2, 30 ], - - [ 199, 156, 47, 15, 146, 137, 50, 17, - 44, 49, 24, 10, 15, 17, 10, 6, 82 ], - - [ 141, 134, 50, 18, 128, 135, 58, 22, - 48, 57, 31, 14, 18, 23, 14, 8, 125 ], - - [ 243, 194, 56, 17, 139, 126, 45, 16, - 33, 36, 18, 8, 10, 12, 7, 4, 60 ], - - [ 91, 106, 51, 23, 99, 117, 63, 30, - 45, 59, 37, 20, 20, 27, 19, 12, 205 ], - - [ 107, 94, 41, 20, 92, 97, 52, 28, - 42, 53, 34, 20, 21, 29, 21, 14, 259 ], - - [ 168, 171, 68, 25, 121, 123, 55, 24, - 34, 41, 24, 12, 13, 16, 11, 6, 112 ], - - [ 67, 80, 44, 23, 76, 94, 57, 31, - 41, 54, 37, 23, 21, 30, 22, 15, 309 ], - - [ 46, 63, 39, 23, 58, 78, 52, 32, - 36, 49, 37, 24, 21, 30, 24, 17, 395 ], - - [ 848, 70, 2, 1, 75, 16, 1, 1, - 2, 1, 1, 1, 1, 1, 1, 1, 1 ], - - [ 36, 52, 35, 22, 48, 67, 48, 32, - 32, 45, 35, 24, 20, 29, 23, 17, 459 ], - - [ 24, 37, 29, 20, 35, 51, 41, 29, - 26, 38, 31, 24, 18, 27, 23, 18, 553 ], - - [ 85, 97, 48, 23, 91, 110, 61, 30, - 45, 58, 37, 21, 21, 29, 20, 13, 235 ], - - [ 22, 33, 27, 20, 33, 48, 39, 30, - 26, 37, 30, 23, 17, 25, 21, 17, 576 ], - - [ 1, 1, 54, 33, 1, 1, 49, 32, - 49, 47, 35, 25, 30, 30, 24, 18, 594 ], - - [ 45, 64, 43, 25, 62, 81, 56, 35, - 37, 51, 38, 26, 22, 31, 24, 18, 366 ], - - [ 247, 148, 38, 12, 154, 130, 42, 14, - 44, 46, 21, 9, 15, 17, 9, 5, 73 ], - - [ 231, 136, 41, 15, 134, 119, 47, 19, - 44, 49, 25, 12, 17, 20, 12, 7, 96 ] - -]) diff --git a/system/embdrv/lc3/test/tns.py b/system/embdrv/lc3/test/tns.py deleted file mode 100644 index 188093fa86298bf8074f20ef9fe3e168c98feb54..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/tns.py +++ /dev/null @@ -1,440 +0,0 @@ -# -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import numpy as np - -import build.lc3 as lc3 -import tables as T, appendix_c as C - -### ------------------------------------------------------------------------ ### - -class Tns: - - SUB_LIM_10M_NB = [ [ 12, 34, 57, 80 ] ] - SUB_LIM_10M_WB = [ [ 12, 61, 110, 160 ] ] - SUB_LIM_10M_SSWB = [ [ 12, 88, 164, 240 ] ] - SUB_LIM_10M_SWB = [ [ 12, 61, 110, 160 ], [ 160, 213, 266, 320 ] ] - SUB_LIM_10M_FB = [ [ 12, 74, 137, 200 ], [ 200, 266, 333, 400 ] ] - - SUB_LIM_10M = [ SUB_LIM_10M_NB, SUB_LIM_10M_WB, - SUB_LIM_10M_SSWB, SUB_LIM_10M_SWB, SUB_LIM_10M_FB ] - - SUB_LIM_7M5_NB = [ [ 9, 26, 43, 60 ] ] - SUB_LIM_7M5_WB = [ [ 9, 46, 83, 120 ] ] - SUB_LIM_7M5_SSWB = [ [ 9, 66, 123, 180 ] ] - SUB_LIM_7M5_SWB = [ [ 9, 46, 82, 120 ], [ 120, 159, 200, 240 ] ] - SUB_LIM_7M5_FB = [ [ 9, 56, 103, 150 ], [ 150, 200, 250, 300 ] ] - - SUB_LIM_7M5 = [ SUB_LIM_7M5_NB, SUB_LIM_7M5_WB, - SUB_LIM_7M5_SSWB, SUB_LIM_7M5_SWB, SUB_LIM_7M5_FB ] - - SUB_LIM = [ SUB_LIM_7M5, SUB_LIM_10M ] - - FREQ_LIM_10M_NB = [ 12, 80 ] - FREQ_LIM_10M_WB = [ 12, 160 ] - FREQ_LIM_10M_SSWB = [ 12, 240 ] - FREQ_LIM_10M_SWB = [ 12, 160, 320 ] - FREQ_LIM_10M_FB = [ 12, 200, 400 ] - - FREQ_LIM_10M = [ FREQ_LIM_10M_NB, FREQ_LIM_10M_WB, - FREQ_LIM_10M_SSWB, FREQ_LIM_10M_SWB, FREQ_LIM_10M_FB ] - - FREQ_LIM_7M5_NB = [ 9, 60 ] - FREQ_LIM_7M5_WB = [ 9, 120 ] - FREQ_LIM_7M5_SSWB = [ 9, 180 ] - FREQ_LIM_7M5_SWB = [ 9, 120, 240 ] - FREQ_LIM_7M5_FB = [ 9, 150, 300 ] - - FREQ_LIM_7M5 = [ FREQ_LIM_7M5_NB, FREQ_LIM_7M5_WB, - FREQ_LIM_7M5_SSWB, FREQ_LIM_7M5_SWB, FREQ_LIM_7M5_FB ] - - FREQ_LIM = [ FREQ_LIM_7M5, FREQ_LIM_10M ] - - def __init__(self, dt): - - self.dt = dt - - (self.nfilters, self.lpc_weighting, self.rc_order, self.rc) = \ - (None, None, None, None) - - def get_data(self): - - return { 'nfilters' : self.nfilters, - 'lpc_weighting' : self.lpc_weighting, - 'rc_order' : self.rc_order, 'rc' : self.rc - 8 } - - def get_nbits(self): - - lpc_weighting = self.lpc_weighting - nbits = 0 - - for f in range(self.nfilters): - rc_order = self.rc_order[f] - rc = self.rc[f] - - nbits_order = T.TNS_ORDER_BITS[int(lpc_weighting)][rc_order] - nbits_coef = sum([ T.TNS_COEF_BITS[k][rc[k]] - for k in range(rc_order) ]) - - nbits += ((2048 + nbits_order + nbits_coef) + 2047) >> 11 - - return nbits - - -class TnsAnalysis(Tns): - - def __init__(self, dt): - - super().__init__(dt) - - def compute_lpc_coeffs(self, bw, f, x): - - ### Normalized autocorrelation function - - S = Tns.SUB_LIM[self.dt][bw][f] - - r = np.append([ 3 ], np.zeros(8)) - e = [ sum(x[S[s]:S[s+1]] ** 2) for s in range(3) ] - - for k in range(len(r) if sum(e) > 0 else 0): - c = [ np.dot(x[S[s]:S[s+1]-k], x[S[s]+k:S[s+1]]) - for s in range(3) ] - - r[k] = np.sum( np.array(c) / np.array(e) ) - - r *= np.exp(-0.5 * (0.02 * np.pi * np.arange(9)) ** 2) - - ### Levinson-Durbin recursion - - err = r[0] - a = np.ones(len(r)) - - for k in range(1, len(a)): - - rc = -sum(a[:k] * r[k:0:-1]) / err - - a[1:k] += rc * a[k-1:0:-1] - a[k] = rc - - err *= 1 - rc ** 2 - - return (r[0] / err, a) - - def lpc_weighting(self, pred_gain, a): - - gamma = 1 - (1 - 0.85) * (2 - pred_gain) / (2 - 1.5) - return a * np.power(gamma, np.arange(len(a))) - - def coeffs_reflexion(self, a): - - rc = np.zeros(8) - b = a.copy() - - for k in range(8, 0, -1): - rc[k-1] = b[k] - e = 1 - rc[k-1] ** 2 - b[1:k] = (b[1:k] - rc[k-1] * b[k-1:0:-1]) / e - - return rc - - def quantization(self, rc, lpc_weighting): - - delta = np.pi / 17 - rc_i = np.rint(np.arcsin(rc) / delta).astype(int) + 8 - rc_q = np.sin(delta * (rc_i - 8)) - - rc_order = len(rc_i) - np.argmin(rc_i[::-1] == 8) - - return (rc_order, rc_q, rc_i) - - def filtering(self, st, x, rc_order, rc): - - y = np.empty(len(x)) - - for i in range(len(x)): - - xi = x[i] - s1 = xi - - for k in range(rc_order): - s0 = st[k] - st[k] = s1 - - s1 = rc[k] * xi + s0 - xi += rc[k] * s0 - - y[i] = xi - - return y - - def run(self, x, bw, nn_flag, nbytes): - - fstate = np.zeros(8) - y = x.copy() - - self.nfilters = len(Tns.SUB_LIM[self.dt][bw]) - self.lpc_weighting = nbytes * 8 < 48 * T.DT_MS[self.dt] - self.rc_order = np.zeros(2, dtype=np.int) - self.rc = np.zeros((2, 8), dtype=np.int) - - for f in range(self.nfilters): - - (pred_gain, a) = self.compute_lpc_coeffs(bw, f, x) - - tns_off = pred_gain <= 1.5 or nn_flag - if tns_off: - continue - - if self.lpc_weighting and pred_gain < 2: - a = self.lpc_weighting(pred_gain, a) - - rc = self.coeffs_reflexion(a) - - (rc_order, rc_q, rc_i) = \ - self.quantization(rc, self.lpc_weighting) - - self.rc_order[f] = rc_order - self.rc[f] = rc_i - - if rc_order > 0: - i0 = Tns.FREQ_LIM[self.dt][bw][f] - i1 = Tns.FREQ_LIM[self.dt][bw][f+1] - - y[i0:i1] = self.filtering( - fstate, x[i0:i1], rc_order, rc_q) - - return y - - def store(self, b): - - for f in range(self.nfilters): - lpc_weighting = self.lpc_weighting[f] - rc_order = self.rc_order[f] - rc = self.rc[f] - - b.write_bit(min(rc_order, 1)) - - if rc_order > 0: - b.ac_encode( - T.TNS_ORDER_CUMFREQ[int(lpc_weighting)][rc_order-1], - T.TNS_ORDER_FREQ[int(lpc_weighting)][rc_order-1] ) - - for k in range(rc_order): - b.ac_encode(T.TNS_COEF_CUMFREQ[k][rc[k]], - T.TNS_COEF_FREQ[k][rc[k]] ) - - -class TnsSynthesis(Tns): - - def filtering(self, st, x, rc_order, rc): - - y = x.copy() - - for i in range(len(x)): - - xi = x[i] - rc[rc_order-1] * st[rc_order-1] - for k in range(rc_order-2, -1, -1): - xi -= rc[k] * st[k] - st[k+1] = xi * rc[k] + st[k]; - st[0] = xi; - - y[i] = xi - - return y - - def load(self, b, bw, nbytes): - - self.nfilters = len(Tns.SUB_LIM[self.dt][bw]) - self.lpc_weighting = nbytes * 8 < 48 * T.DT_MS[self.dt] - self.rc_order = np.zeros(2, dtype=np.int) - self.rc = 8 * np.ones((2, 8), dtype=np.int) - - for f in range(self.nfilters): - - if not b.read_bit(): - continue - - rc_order = 1 + b.ac_decode( - T.TNS_ORDER_CUMFREQ[int(self.lpc_weighting)], - T.TNS_ORDER_FREQ[int(self.lpc_weighting)]) - - self.rc_order[f] = rc_order - - for k in range(rc_order): - rc = b.ac_decode(T.TNS_COEF_CUMFREQ[k], T.TNS_COEF_FREQ[k]) - self.rc[f][k] = rc - - def run(self, x, bw): - - fstate = np.zeros(8) - y = x.copy() - - for f in range(self.nfilters): - - rc_order = self.rc_order[f] - rc = np.sin((np.pi / 17) * (self.rc[f] - 8)) - - if rc_order > 0: - i0 = Tns.FREQ_LIM[self.dt][bw][f] - i1 = Tns.FREQ_LIM[self.dt][bw][f+1] - - y[i0:i1] = self.filtering( - fstate, x[i0:i1], rc_order, rc) - - return y - - -### ------------------------------------------------------------------------ ### - -def check_analysis(rng, dt, bw): - - ok = True - - analysis = TnsAnalysis(dt) - nbytes_lim = int((48 * T.DT_MS[dt]) // 8) - - for i in range(10): - x = rng.random(T.NE[dt][bw]) * 1e2 - x = pow(x, .5 + i/5) - - for nn_flag in (True, False): - for nbytes in (nbytes_lim, nbytes_lim + 1): - - y = analysis.run(x, bw, nn_flag, nbytes) - (y_c, data_c) = lc3.tns_analyze(dt, bw, nn_flag, nbytes, x) - - ok = ok and data_c['nfilters'] == analysis.nfilters - ok = ok and data_c['lpc_weighting'] == analysis.lpc_weighting - for f in range(analysis.nfilters): - rc_order = analysis.rc_order[f] - rc_order_c = data_c['rc_order'][f] - rc_c = 8 + data_c['rc'][f] - ok = ok and rc_order_c == rc_order - ok = ok and not np.any((rc_c - analysis.rc[f])[:rc_order]) - - ok = ok and lc3.tns_get_nbits(data_c) == analysis.get_nbits() - ok = ok and np.amax(np.abs(y_c - y)) < 1e-2 - - return ok - -def check_synthesis(rng, dt, bw): - - ok = True - synthesis = TnsSynthesis(dt) - - for i in range(100): - - x = rng.random(T.NE[dt][bw]) * 1e2 - - synthesis.nfilters = 1 + int(bw >= T.SRATE_32K) - synthesis.rc_order = rng.integers(0, 9, 2) - synthesis.rc = rng.integers(0, 17, 16).reshape(2, 8) - - y = synthesis.run(x, bw) - y_c = lc3.tns_synthesize(dt, bw, synthesis.get_data(), x) - - ok = ok and np.amax(np.abs(y_c - y) < 1e-6) - - return ok - -def check_analysis_appendix_c(dt): - - sr = T.SRATE_16K - ok = True - - fs = Tns.FREQ_LIM[dt][sr][0] - fe = Tns.FREQ_LIM[dt][sr][1] - st = np.zeros(8) - - for i in range(len(C.X_S[dt])): - - (_, a) = lc3.tns_compute_lpc_coeffs(dt, sr, C.X_S[dt][i]) - ok = ok and np.amax(np.abs(a[0] - C.TNS_LEV_A[dt][i])) < 1e-5 - - rc = lc3.tns_lpc_reflection(a[0]) - ok = ok and np.amax(np.abs(rc - C.TNS_LEV_RC[dt][i])) < 1e-5 - - (rc_order, rc_i) = lc3.tns_quantize_rc(C.TNS_LEV_RC[dt][i]) - ok = ok and rc_order == C.RC_ORDER[dt][i][0] - ok = ok and np.any((rc_i + 8) - C.RC_I_1[dt][i] == 0) - - rc_q = lc3.tns_unquantize_rc(rc_i, rc_order) - ok = ok and np.amax(np.abs(rc_q - C.RC_Q_1[dt][i])) < 1e-6 - - (x, side) = lc3.tns_analyze(dt, sr, False, C.NBYTES[dt], C.X_S[dt][i]) - ok = ok and side['nfilters'] == 1 - ok = ok and side['rc_order'][0] == C.RC_ORDER[dt][i][0] - ok = ok and not np.any((side['rc'][0] + 8) - C.RC_I_1[dt][i]) - ok = ok and lc3.tns_get_nbits(side) == C.NBITS_TNS[dt][i] - ok = ok and np.amax(np.abs(x - C.X_F[dt][i])) < 1e-3 - - return ok - -def check_synthesis_appendix_c(dt): - - sr = T.SRATE_16K - ok = True - - for i in range(len(C.X_HAT_Q[dt])): - - side = { - 'nfilters' : 1, - 'lpc_weighting' : C.NBYTES[dt] * 8 < 48 * T.DT_MS[dt], - 'rc_order': C.RC_ORDER[dt][i], - 'rc': [ C.RC_I_1[dt][i] - 8, C.RC_I_2[dt][i] - 8 ] - } - - g_int = C.GG_IND_ADJ[dt][i] + C.GG_OFF[dt][i] - x = C.X_HAT_Q[dt][i] * (10 ** (g_int / 28)) - - x = lc3.tns_synthesize(dt, sr, side, x) - ok = ok and np.amax(np.abs(x - C.X_HAT_TNS[dt][i])) < 1e-3 - - if dt != T.DT_10M: - return ok - - sr = T.SRATE_48K - - side = { - 'nfilters' : 2, - 'lpc_weighting' : False, - 'rc_order': C.RC_ORDER_48K_10M, - 'rc': [ C.RC_I_1_48K_10M - 8, C.RC_I_2_48K_10M - 8 ] - } - - x = C.X_HAT_F_48K_10M - x = lc3.tns_synthesize(dt, sr, side, x) - ok = ok and np.amax(np.abs(x - C.X_HAT_TNS_48K_10M)) < 1e-3 - - return ok - -def check(): - - rng = np.random.default_rng(1234) - ok = True - - for dt in range(T.NUM_DT): - for sr in range(T.NUM_SRATE): - ok = ok and check_analysis(rng, dt, sr) - ok = ok and check_synthesis(rng, dt, sr) - - for dt in range(T.NUM_DT): - ok = ok and check_analysis_appendix_c(dt) - ok = ok and check_synthesis_appendix_c(dt) - - return ok - -### ------------------------------------------------------------------------ ### diff --git a/system/embdrv/lc3/test/tns_py.c b/system/embdrv/lc3/test/tns_py.c deleted file mode 100644 index cb96d02e3ea86640410b7db15698c591b6f247c4..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/test/tns_py.c +++ /dev/null @@ -1,183 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 "lc3.h" -#include -#include - -#include -#include "ctypes.h" - -static PyObject *compute_lpc_coeffs_py(PyObject *m, PyObject *args) -{ - PyObject *x_obj, *a_obj, *g_obj; - unsigned dt, bw; - float *x, *g, (*a)[9]; - - if (!PyArg_ParseTuple(args, "IIO", &dt, &bw, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("sr", (unsigned)bw < LC3_NUM_BANDWIDTH); - - int ne = LC3_NE(dt, bw); - - CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - g_obj = new_1d_ptr(NPY_FLOAT, 2, &g); - a_obj = new_2d_ptr(NPY_FLOAT, 2, 9, &a); - - compute_lpc_coeffs(dt, bw, x, g, a); - - return Py_BuildValue("NN", g_obj, a_obj); -} - -static PyObject *lpc_reflection_py(PyObject *m, PyObject *args) -{ - PyObject *a_obj, *rc_obj; - float *a, *rc; - - if (!PyArg_ParseTuple(args, "O", &a_obj)) - return NULL; - - CTYPES_CHECK("a", to_1d_ptr(a_obj, NPY_FLOAT, 9, &a)); - rc_obj = new_1d_ptr(NPY_FLOAT, 8, &rc); - - lpc_reflection(a, rc); - - return Py_BuildValue("N", rc_obj); -} - -static PyObject *quantize_rc_py(PyObject *m, PyObject *args) -{ - PyObject *rc_obj, *rc_q_obj; - float *rc; - int rc_order, *rc_q; - - if (!PyArg_ParseTuple(args, "O", &rc_obj)) - return NULL; - - CTYPES_CHECK("rc", to_1d_ptr(rc_obj, NPY_FLOAT, 8, &rc)); - - rc_q_obj = new_1d_ptr(NPY_INT, 8, &rc_q); - - quantize_rc(rc, &rc_order, rc_q); - - return Py_BuildValue("iN", rc_order, rc_q_obj); -} - -static PyObject *unquantize_rc_py(PyObject *m, PyObject *args) -{ - PyObject *rc_q_obj, *rc_obj; - int rc_order, *rc_q; - float *rc; - - if (!PyArg_ParseTuple(args, "OI", &rc_q_obj, &rc_order)) - return NULL; - - CTYPES_CHECK("rc_q", to_1d_ptr(rc_q_obj, NPY_INT, 8, &rc_q)); - CTYPES_CHECK("rc_order", (unsigned)rc_order <= 8); - - rc_obj = new_1d_ptr(NPY_FLOAT, 8, &rc); - - unquantize_rc(rc_q, rc_order, rc); - - return Py_BuildValue("N", rc_obj); -} - -static PyObject *analyze_py(PyObject *m, PyObject *args) -{ - PyObject *x_obj; - struct lc3_tns_data data = { 0 }; - unsigned dt, bw; - int nn_flag; - unsigned nbytes; - float *x; - - if (!PyArg_ParseTuple(args, "IIpIO", &dt, &bw, &nn_flag, &nbytes, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("bw", (unsigned)bw < LC3_NUM_BANDWIDTH); - - int ne = LC3_NE(dt, bw); - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - lc3_tns_analyze(dt, bw, nn_flag, nbytes, &data, x); - - return Py_BuildValue("ON", x_obj, new_tns_data(&data)); -} - -static PyObject *synthesize_py(PyObject *m, PyObject *args) -{ - PyObject *data_obj, *x_obj; - unsigned dt, bw; - struct lc3_tns_data data; - float *x; - - if (!PyArg_ParseTuple(args, "IIOO", &dt, &bw, &data_obj, &x_obj)) - return NULL; - - CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT); - CTYPES_CHECK("bw", (unsigned)bw < LC3_NUM_BANDWIDTH); - CTYPES_CHECK(NULL, data_obj = to_tns_data(data_obj, &data)); - - int ne = LC3_NE(dt, bw); - - CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x)); - - lc3_tns_synthesize(dt, bw, &data, x); - - return Py_BuildValue("O", x_obj); -} - -static PyObject *get_nbits_py(PyObject *m, PyObject *args) -{ - PyObject *data_obj; - struct lc3_tns_data data = { 0 }; - - if (!PyArg_ParseTuple(args, "O", &data_obj)) - return NULL; - - CTYPES_CHECK("data", to_tns_data(data_obj, &data)); - - int nbits = lc3_tns_get_nbits(&data); - - return Py_BuildValue("i", nbits); -} - -static PyMethodDef methods[] = { - { "tns_compute_lpc_coeffs", compute_lpc_coeffs_py, METH_VARARGS }, - { "tns_lpc_reflection" , lpc_reflection_py , METH_VARARGS }, - { "tns_quantize_rc" , quantize_rc_py , METH_VARARGS }, - { "tns_unquantize_rc" , unquantize_rc_py , METH_VARARGS }, - { "tns_analyze" , analyze_py , METH_VARARGS }, - { "tns_synthesize" , synthesize_py , METH_VARARGS }, - { "tns_get_nbits" , get_nbits_py , METH_VARARGS }, - { NULL }, -}; - -PyMODINIT_FUNC lc3_tns_py_init(PyObject *m) -{ - import_array(); - - PyModule_AddFunctions(m, methods); - - return m; -} diff --git a/system/embdrv/lc3/tools/dlc3.c b/system/embdrv/lc3/tools/dlc3.c deleted file mode 100644 index b334898e69b30561ce5a8e7b23b4b6483bc50ffa..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/tools/dlc3.c +++ /dev/null @@ -1,257 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#define _POSIX_C_SOURCE 199309L - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "lc3bin.h" -#include "wave.h" - -#ifndef MIN -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) -#endif - -#ifndef MAX -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#endif - - -/** - * Error handling - */ - -static void error(int status, const char *format, ...) -{ - va_list args; - - fflush(stdout); - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - - fprintf(stderr, status ? ": %s\n" : "\n", strerror(status)); - exit(status); -} - - -/** - * Parameters - */ - -struct parameters { - const char *fname_in; - const char *fname_out; - int bitdepth; - int srate_hz; -}; - -static struct parameters parse_args(int argc, char *argv[]) -{ - static const char *usage = - "Usage: %s [in_file] [wav_file]\n" - "\n" - "wav_file\t" "Input wave file, stdin if omitted\n" - "out_file\t" "Output bitstream file, stdout if omitted\n" - "\n" - "Options:\n" - "\t-h\t" "Display help\n" - "\t-b\t" "Output bitdepth, 16 bits (default) or 24 bits\n" - "\t-r\t" "Output samplerate, default is LC3 stream samplerate\n" - "\n"; - - struct parameters p = { .bitdepth = 16 }; - - for (int iarg = 1; iarg < argc; ) { - const char *arg = argv[iarg++]; - - if (arg[0] == '-') { - if (arg[2] != '\0') - error(EINVAL, "Option %s", arg); - - char opt = arg[1]; - const char *optarg; - - switch (opt) { - case 'b': case 'r': - if (iarg >= argc) - error(EINVAL, "Argument %s", arg); - optarg = argv[iarg++]; - } - - switch (opt) { - case 'h': fprintf(stderr, usage, argv[0]); exit(0); - case 'b': p.bitdepth = atoi(optarg); break; - case 'r': p.srate_hz = atoi(optarg); break; - default: - error(EINVAL, "Option %s", arg); - } - - } else { - - if (!p.fname_in) - p.fname_in = arg; - else if (!p.fname_out) - p.fname_out = arg; - else - error(EINVAL, "Argument %s", arg); - } - } - - return p; -} - -/** - * Return time in (us) from unspecified point in the past - */ -static unsigned clock_us(void) -{ - struct timespec ts; - - clock_gettime(CLOCK_REALTIME, &ts); - - return (unsigned)(ts.tv_sec * 1000*1000) + (unsigned)(ts.tv_nsec / 1000); -} - -/** - * Entry point - */ -int main(int argc, char *argv[]) -{ - /* --- Read parameters --- */ - - struct parameters p = parse_args(argc, argv); - FILE *fp_in = stdin, *fp_out = stdout; - - if (p.fname_in && (fp_in = fopen(p.fname_in, "rb")) == NULL) - error(errno, "%s", p.fname_in); - - if (p.fname_out && (fp_out = fopen(p.fname_out, "wb")) == NULL) - error(errno, "%s", p.fname_out); - - if (p.srate_hz && !LC3_CHECK_SR_HZ(p.srate_hz)) - error(EINVAL, "Samplerate %d Hz", p.srate_hz); - - if (p.bitdepth && p.bitdepth != 16 && p.bitdepth != 24) - error(EINVAL, "Bitdepth %d", p.bitdepth); - - /* --- Check parameters --- */ - - int frame_us, srate_hz, nch, nsamples; - - if (lc3bin_read_header(fp_in, &frame_us, &srate_hz, &nch, &nsamples) < 0) - error(EINVAL, "LC3 binary input file"); - - if (nch < 1 || nch > 2) - error(EINVAL, "Number of channels %d", nch); - - if (!LC3_CHECK_DT_US(frame_us)) - error(EINVAL, "Frame duration"); - - if (!LC3_CHECK_SR_HZ(srate_hz) || (p.srate_hz && p.srate_hz < srate_hz)) - error(EINVAL, "Samplerate %d Hz", srate_hz); - - int pcm_sbits = p.bitdepth; - int pcm_sbytes = 2 + 2*(pcm_sbits > 16); - - int pcm_srate_hz = !p.srate_hz ? srate_hz : p.srate_hz; - int pcm_samples = !p.srate_hz ? nsamples : - ((int64_t)nsamples * pcm_srate_hz) / srate_hz; - - wave_write_header(fp_out, - pcm_sbits, pcm_sbytes, pcm_srate_hz, nch, pcm_samples); - - /* --- Setup decoding --- */ - - int frame_samples = lc3_frame_samples(frame_us, pcm_srate_hz); - int encode_samples = pcm_samples + - lc3_delay_samples(frame_us, pcm_srate_hz); - - lc3_decoder_t dec[nch]; - uint8_t in[nch * LC3_MAX_FRAME_BYTES]; - int8_t alignas(int32_t) pcm[nch * frame_samples * pcm_sbytes]; - enum lc3_pcm_format pcm_fmt = - pcm_sbits == 24 ? LC3_PCM_FORMAT_S24 : LC3_PCM_FORMAT_S16; - - for (int ich = 0; ich < nch; ich++) - dec[ich] = lc3_setup_decoder(frame_us, srate_hz, p.srate_hz, - malloc(lc3_decoder_size(frame_us, pcm_srate_hz))); - - /* --- Decoding loop --- */ - - static const char *dash_line = "========================================"; - - int nsec = 0; - unsigned t0 = clock_us(); - - for (int i = 0; i * frame_samples < encode_samples; i++) { - - int frame_bytes = lc3bin_read_data(fp_in, nch, in); - - if (floorf(i * frame_us * 1e-6) > nsec) { - - float progress = fminf((float)i * frame_samples / pcm_samples, 1); - - fprintf(stderr, "%02d:%02d [%-40s]\r", - nsec / 60, nsec % 60, - dash_line + (int)floorf((1 - progress) * 40)); - - nsec = rint(i * frame_us * 1e-6); - } - - if (frame_bytes <= 0) - memset(pcm, 0, nch * frame_samples * pcm_sbytes); - else - for (int ich = 0; ich < nch; ich++) - lc3_decode(dec[ich], - in + ich * frame_bytes, frame_bytes, - pcm_fmt, pcm + ich * pcm_sbytes, nch); - - int pcm_offset = i > 0 ? 0 : encode_samples - pcm_samples; - int pcm_nwrite = MIN(frame_samples - pcm_offset, - encode_samples - i*frame_samples); - - wave_write_pcm(fp_out, pcm_sbytes, pcm, nch, pcm_offset, pcm_nwrite); - } - - unsigned t = (clock_us() - t0) / 1000; - nsec = nsamples / srate_hz; - - fprintf(stderr, "%02d:%02d Decoded in %d.%03d seconds %20s\n", - nsec / 60, nsec % 60, t / 1000, t % 1000, ""); - - /* --- Cleanup --- */ - - for (int ich = 0; ich < nch; ich++) - free(dec[ich]); - - if (fp_in != stdin) - fclose(fp_in); - - if (fp_out != stdout) - fclose(fp_out); -} diff --git a/system/embdrv/lc3/tools/elc3.c b/system/embdrv/lc3/tools/elc3.c deleted file mode 100644 index b81c6566477df179c9851f5900cd2a01aceeacfd..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/tools/elc3.c +++ /dev/null @@ -1,258 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#define _POSIX_C_SOURCE 199309L - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "lc3bin.h" -#include "wave.h" - - -/** - * Error handling - */ - -static void error(int status, const char *format, ...) -{ - va_list args; - - fflush(stdout); - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - - fprintf(stderr, status ? ": %s\n" : "\n", strerror(status)); - exit(status); -} - - -/** - * Parameters - */ - -struct parameters { - const char *fname_in; - const char *fname_out; - float frame_ms; - int srate_hz; - int bitrate; -}; - -static struct parameters parse_args(int argc, char *argv[]) -{ - static const char *usage = - "Usage: %s [options] [wav_file] [out_file]\n" - "\n" - "wav_file\t" "Input wave file, stdin if omitted\n" - "out_file\t" "Output bitstream file, stdout if omitted\n" - "\n" - "Options:\n" - "\t-h\t" "Display help\n" - "\t-b\t" "Bitrate in bps (mandatory)\n" - "\t-m\t" "Frame duration in ms (default 10)\n" - "\t-r\t" "Encoder samplerate (default is input samplerate)\n" - "\n"; - - struct parameters p = { .frame_ms = 10 }; - - for (int iarg = 1; iarg < argc; ) { - const char *arg = argv[iarg++]; - - if (arg[0] == '-') { - if (arg[2] != '\0') - error(EINVAL, "Option %s", arg); - - char opt = arg[1]; - const char *optarg; - - switch (opt) { - case 'b': case 'm': case 'r': - if (iarg >= argc) - error(EINVAL, "Argument %s", arg); - optarg = argv[iarg++]; - } - - switch (opt) { - case 'h': fprintf(stderr, usage, argv[0]); exit(0); - case 'b': p.bitrate = atoi(optarg); break; - case 'm': p.frame_ms = atof(optarg); break; - case 'r': p.srate_hz = atoi(optarg); break; - default: - error(EINVAL, "Option %s", arg); - } - - } else { - - if (!p.fname_in) - p.fname_in = arg; - else if (!p.fname_out) - p.fname_out = arg; - else - error(EINVAL, "Argument %s", arg); - } - } - - return p; -} - - -/** - * Return time in (us) from unspecified point in the past - */ - -static unsigned clock_us(void) -{ - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - - return (unsigned)(ts.tv_sec * 1000*1000) + (unsigned)(ts.tv_nsec / 1000); -} - - -/** - * Entry point - */ - -int main(int argc, char *argv[]) -{ - /* --- Read parameters --- */ - - struct parameters p = parse_args(argc, argv); - FILE *fp_in = stdin, *fp_out = stdout; - - if (p.fname_in && (fp_in = fopen(p.fname_in, "rb")) == NULL) - error(errno, "%s", p.fname_in); - - if (p.fname_out && (fp_out = fopen(p.fname_out, "wb")) == NULL) - error(errno, "%s", p.fname_out); - - if (p.srate_hz && !LC3_CHECK_SR_HZ(p.srate_hz)) - error(EINVAL, "Samplerate %d Hz", p.srate_hz); - - /* --- Check parameters --- */ - - int frame_us = p.frame_ms * 1000; - int srate_hz, nch, nsamples; - int pcm_sbits, pcm_sbytes; - - if (wave_read_header(fp_in, - &pcm_sbits, &pcm_sbytes, &srate_hz, &nch, &nsamples) < 0) - error(EINVAL, "Bad or unsupported WAVE input file"); - - if (p.bitrate <= 0) - error(EINVAL, "Bitrate"); - - if (!LC3_CHECK_DT_US(frame_us)) - error(EINVAL, "Frame duration"); - - if (!LC3_CHECK_SR_HZ(srate_hz) || (p.srate_hz && p.srate_hz > srate_hz)) - error(EINVAL, "Samplerate %d Hz", srate_hz); - - if (pcm_sbits != 16 && pcm_sbits != 24) - error(EINVAL, "Bitdepth %d", pcm_sbits); - - if (pcm_sbytes != (pcm_sbits == 16 ? 2 : 4)) - error(EINVAL, "Sample storage on %d bytes", pcm_sbytes); - - if (nch < 1 || nch > 2) - error(EINVAL, "Number of channels %d", nch); - - int enc_srate_hz = !p.srate_hz ? srate_hz : p.srate_hz; - int enc_samples = !p.srate_hz ? nsamples : - ((int64_t)nsamples * enc_srate_hz) / srate_hz; - - lc3bin_write_header(fp_out, - frame_us, enc_srate_hz, p.bitrate, nch, enc_samples); - - /* --- Setup encoding --- */ - - int frame_bytes = lc3_frame_bytes(frame_us, p.bitrate / nch); - int frame_samples = lc3_frame_samples(frame_us, srate_hz); - int encode_samples = nsamples + lc3_delay_samples(frame_us, srate_hz); - - lc3_encoder_t enc[nch]; - int8_t alignas(int32_t) pcm[nch * frame_samples * pcm_sbytes]; - enum lc3_pcm_format pcm_fmt = - pcm_sbits == 24 ? LC3_PCM_FORMAT_S24 : LC3_PCM_FORMAT_S16; - uint8_t out[nch][frame_bytes]; - - for (int ich = 0; ich < nch; ich++) - enc[ich] = lc3_setup_encoder(frame_us, enc_srate_hz, srate_hz, - malloc(lc3_encoder_size(frame_us, srate_hz))); - - /* --- Encoding loop --- */ - - static const char *dash_line = "========================================"; - - int nsec = 0; - unsigned t0 = clock_us(); - - for (int i = 0; i * frame_samples < encode_samples; i++) { - - int nread = wave_read_pcm(fp_in, pcm_sbytes, nch, frame_samples, pcm); - - memset(pcm + nread * nch, 0, - nch * (frame_samples - nread) * pcm_sbytes); - - if (floorf(i * frame_us * 1e-6) > nsec) { - float progress = fminf( - (float)i * frame_samples / encode_samples, 1); - - fprintf(stderr, "%02d:%02d [%-40s]\r", - nsec / 60, nsec % 60, - dash_line + (int)floorf((1 - progress) * 40)); - - nsec = (int)(i * frame_us * 1e-6); - } - - for (int ich = 0; ich < nch; ich++) - lc3_encode(enc[ich], - pcm_fmt, pcm + ich * pcm_sbytes, nch, - frame_bytes, out[ich]); - - lc3bin_write_data(fp_out, out, nch, frame_bytes); - } - - unsigned t = (clock_us() - t0) / 1000; - nsec = encode_samples / srate_hz; - - fprintf(stderr, "%02d:%02d Encoded in %d.%d seconds %20s\n", - nsec / 60, nsec % 60, t / 1000, t % 1000, ""); - - /* --- Cleanup --- */ - - for (int ich = 0; ich < nch; ich++) - free(enc[ich]); - - if (fp_in != stdin) - fclose(fp_in); - - if (fp_out != stdout) - fclose(fp_out); -} diff --git a/system/embdrv/lc3/tools/lc3bin.c b/system/embdrv/lc3/tools/lc3bin.c deleted file mode 100644 index 4187808366571f5e04b1e58a1861c5d201d22a7e..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/tools/lc3bin.c +++ /dev/null @@ -1,110 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 -#include "lc3bin.h" - - -/** - * LC3 binary header - */ - -#define LC3_FILE_ID (0x1C | (0xCC << 8)) - -struct lc3bin_header { - uint16_t file_id; - uint16_t header_size; - uint16_t srate_100hz; - uint16_t bitrate_100bps; - uint16_t channels; - uint16_t frame_10us; - uint16_t rfu; - uint16_t nsamples_low; - uint16_t nsamples_high; -}; - - -/** - * Read LC3 binary header - */ -int lc3bin_read_header(FILE *fp, - int *frame_us, int *srate_hz, int *nchannels, int *nsamples) -{ - struct lc3bin_header hdr; - - if (fread(&hdr, sizeof(hdr), 1, fp) != 1 - || hdr.file_id != LC3_FILE_ID) - return -1; - - *nchannels = hdr.channels; - *frame_us = hdr.frame_10us * 10; - *srate_hz = hdr.srate_100hz * 100; - *nsamples = hdr.nsamples_low | (hdr.nsamples_high << 16); - - fseek(fp, SEEK_SET, hdr.header_size); - - return 0; -} - -/** - * Read LC3 block of data - */ -int lc3bin_read_data(FILE *fp, int nchannels, void *buffer) -{ - uint16_t nbytes; - - if (fread(&nbytes, sizeof(nbytes), 1, fp) < 1 - || nbytes > nchannels * LC3_MAX_FRAME_BYTES - || nbytes % nchannels - || fread(buffer, nbytes, 1, fp) < 1) - return -1; - - return nbytes / nchannels; -} - -/** - * Write LC3 binary header - */ -void lc3bin_write_header(FILE *fp, - int frame_us, int srate_hz, int bitrate, int nchannels, int nsamples) -{ - struct lc3bin_header hdr = { - .file_id = LC3_FILE_ID, - .header_size = sizeof(struct lc3bin_header), - .srate_100hz = srate_hz / 100, - .bitrate_100bps = bitrate / 100, - .channels = nchannels, - .frame_10us = frame_us / 10, - .nsamples_low = nsamples & 0xffff, - .nsamples_high = nsamples >> 16, - }; - - fwrite(&hdr, sizeof(hdr), 1, fp); -} - -/** - * Write LC3 block of data - */ -void lc3bin_write_data(FILE *fp, - const void *data, int nchannels, int frame_bytes) -{ - uint16_t nbytes = nchannels * frame_bytes; - fwrite(&nbytes, sizeof(nbytes), 1, fp); - - fwrite(data, 1, nbytes, fp); -} diff --git a/system/embdrv/lc3/tools/lc3bin.h b/system/embdrv/lc3/tools/lc3bin.h deleted file mode 100644 index b2d70e6625703acf22ed18c43ff5b258b91141fc..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/tools/lc3bin.h +++ /dev/null @@ -1,71 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#ifndef __LC3BIN_H -#define __LC3BIN_H - -#include -#include -#include - - -/** - * Read LC3 binary header - * fp Opened file, moved after header on return - * frame_us Return frame duration, in us - * srate_hz Return samplerate, in Hz - * nchannels Return number of channels - * nsamples Return count of source samples by channels - * return 0: Ok -1: Bad LC3 File - */ -int lc3bin_read_header(FILE *fp, - int *frame_us, int *srate_hz, int *nchannels, int *nsamples); - -/** - * Read LC3 block of data - * fp Opened file - * nchannels Number of channels - * buffer Output buffer of `nchannels * LC3_MAX_FRAME_BYTES` - * return Size of each 'nchannels` frames, -1 on error - */ -int lc3bin_read_data(FILE *fp, int nchannels, void *buffer); - -/** - * Write LC3 binary header - * fp Opened file, moved after header on return - * frame_us Frame duration, in us - * srate_hz Samplerate, in Hz - * bitrate Bitrate indication of the stream, in bps - * nchannels Number of channels - * nsamples Count of source samples by channels - */ -void lc3bin_write_header(FILE *fp, - int frame_us, int srate_hz, int bitrate, int nchannels, int nsamples); - -/** - * Write LC3 block of data - * fp Opened file - * data The frames data - * nchannels Number of channels - * frame_bytes Size of each `nchannels` frames - */ -void lc3bin_write_data(FILE *fp, - const void *data, int nchannels, int frame_bytes); - - -#endif /* __LC3BIN_H */ diff --git a/system/embdrv/lc3/tools/wave.c b/system/embdrv/lc3/tools/wave.c deleted file mode 100644 index ca68e253870d3cb732a5941eef8d6c31495d0d12..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/tools/wave.c +++ /dev/null @@ -1,179 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * 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 -#include "wave.h" - - -/** - * Id formatting - */ - -#define __WAVE_ID(s) \ - (uint32_t)( s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24) ) - - -/** - * File format statement - * | type_id WAVE_FILE_TYPE_ID - * | size File size - 8 bytes - * | type_id WAVE_FILE_FMT_ID - */ - -#define WAVE_FILE_TYPE_ID __WAVE_ID("RIFF") -#define WAVE_FILE_FMT_ID __WAVE_ID("WAVE") - -struct wave_file { - uint32_t type_id; - uint32_t size; - uint32_t fmt_id; -}; - - -/** - * Audio format statement - * | id WAVE_FORMAT_ID - * | size Size of the block - 8 bytes (= 16 bytes) - * | format WAVE_FORMAT_PCM - * | channels Number of channels - * | samplerate Sampling rate - * | byterate Bytes per secondes = `samplerate * framesize` - * | framesize Bytes per sampling time = `channels * bitdepth / 8` - * | bitdepth Number of bits per sample - */ - -#define WAVE_FORMAT_ID __WAVE_ID("fmt ") -#define WAVE_FORMAT_PCM 1 - -struct wave_format { - uint32_t id; - uint32_t size; - uint16_t fmt; - uint16_t channels; - uint32_t samplerate; - uint32_t byterate; - uint16_t framesize; - uint16_t bitdepth; -}; - - -/** - * Audio data statement - * | id WAV_DATA_ID - * | size Size of the data following - */ - -#define WAVE_DATA_ID __WAVE_ID("data") - -struct wave_data { - uint32_t id; - uint32_t size; -}; - - -/** - * Read WAVE file header - */ -int wave_read_header(FILE *fp, int *bitdepth, int *samplesize, - int *samplerate, int *nchannels, int *nframes) -{ - struct wave_file file; - struct wave_format format; - struct wave_data data; - - if (fread(&file, sizeof(file), 1, fp) != 1 - || file.type_id != WAVE_FILE_TYPE_ID - || file.fmt_id != WAVE_FILE_FMT_ID) - return -1; - - if (fread(&format, sizeof(format), 1, fp) != 1 - || format.id != WAVE_FORMAT_ID - || format.fmt != WAVE_FORMAT_PCM - || format.byterate != format.samplerate * format.framesize) - return -1; - - fseek(fp, sizeof(format) - (8 + format.size), SEEK_CUR); - - if (fread(&data, sizeof(data), 1, fp) != 1 - || data.id != WAVE_DATA_ID) - return -1; - - *bitdepth = format.bitdepth; - *samplesize = format.framesize / format.channels; - *samplerate = format.samplerate; - *nchannels = format.channels; - *nframes = data.size / format.framesize; - - return 0; -} - -/** - * Read PCM samples from wave file - */ -int wave_read_pcm(FILE *fp, int samplesize, - int nch, int count, void *buffer) -{ - return fread(buffer, nch * samplesize, count, fp); -} - -/** - * Write WAVE file header - */ -void wave_write_header(FILE *fp, int bitdepth, int samplesize, - int samplerate, int nchannels, int nframes) -{ - struct { - struct wave_file file; - struct wave_format format; - struct wave_data data; - } header; - - long data_size = nchannels * nframes * samplesize; - long file_size = sizeof(header) + data_size; - - header.file = (struct wave_file){ - WAVE_FILE_TYPE_ID, file_size - 8, - .fmt_id = WAVE_FILE_FMT_ID - }; - - header.format = (struct wave_format){ - WAVE_FORMAT_ID, sizeof(header.format) - 8, - .fmt = WAVE_FORMAT_PCM, - .channels = nchannels, - .samplerate = samplerate, - .byterate = samplerate * nchannels * samplesize, - .framesize = nchannels * samplesize, - .bitdepth = bitdepth, - }; - - header.data = (struct wave_data){ - WAVE_DATA_ID, data_size - }; - - fwrite(&header, sizeof(header), 1, fp); -} - -/** - * Write PCM samples to wave file - */ -void wave_write_pcm(FILE *fp, int samplesize, - const void *_pcm, int nch, int off, int count) -{ - const int8_t *pcm = _pcm; - fwrite(pcm + nch * off * samplesize, nch * samplesize, count, fp); -} diff --git a/system/embdrv/lc3/tools/wave.h b/system/embdrv/lc3/tools/wave.h deleted file mode 100644 index 87e8186e4a5ef820346e4db4b40704a4bfd92749..0000000000000000000000000000000000000000 --- a/system/embdrv/lc3/tools/wave.h +++ /dev/null @@ -1,73 +0,0 @@ -/****************************************************************************** - * - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#ifndef __WAVE_H -#define __WAVE_H - -#include -#include - - -/** - * Read WAVE file header - * fp Opened file, moved after header on return - * bitdepth Return bitdepth - * samplesize Return size of samples, in bytes - * samplerate Return samplerate, in Hz - * nchannels Return number of channels - * nframes Return count of frames - * return 0: Ok -1: Bad or unsupported WAVE File - */ -int wave_read_header(FILE *fp, int *bitdepth, int *samplesize, - int *samplerate, int *nchannels, int *nframes); - -/** - * Read PCM samples from wave file - * fp Opened file - * samplesize Size of samples, in bytes - * nch, count Number of channels and count of frames to read - * buffer Output buffer of `nchannels * count` interleaved samples - * return Number of frames read - */ -int wave_read_pcm(FILE *fp, int samplesize, - int nch, int count, void *_buffer); - -/** - * Write WAVE file header - * fp Opened file, moved after header on return - * bitdepth Bitdepth - * samplesize Size of samples - * samplerate Samplerate, in Hz - * nchannels Number of channels - * nframes Count of frames - */ -void wave_write_header(FILE *fp, int bitdepth, int samplesize, - int samplerate, int nchannels, int nframes); - -/** - * Write PCM samples to wave file - * fp Opened file - * samplesize Size of samples, in bytes - * pcm, nch PCM frames, as 'nch' interleaved samples - * off, count Offset and count of frames - */ -void wave_write_pcm(FILE *fp, int samplesize, - const void *pcm, int nch, int off, int count); - - -#endif /* __WAVE_H */ diff --git a/system/embdrv/sbc/decoder/srce/dequant.c b/system/embdrv/sbc/decoder/srce/dequant.c index e2bce9e950ffd6195b603c5ca22ea31d61e1f468..2dccd73fe68103a4a0d346ab2a76aa555a0c1754 100644 --- a/system/embdrv/sbc/decoder/srce/dequant.c +++ b/system/embdrv/sbc/decoder/srce/dequant.c @@ -117,8 +117,57 @@ #define SBC_DEQUANT_SCALING_FACTOR 1.38019122262781f #endif -const uint32_t dequant_long_scaled[17]; -const uint32_t dequant_long_unscaled[17]; +const uint32_t dequant_long_scaled[17] = { + 0, 0, + 0x1ee9e116, /* bits=2 0.24151243 1/3 * (1/1.38019122262781) + (0x00000008)*/ + 0x0d3fa99c, /* bits=3 0.10350533 1/7 * (1/1.38019122262781) + (0x00000013)*/ + 0x062ec69e, /* bits=4 0.04830249 1/15 * (1/1.38019122262781) + (0x00000029)*/ + 0x02fddbfa, /* bits=5 0.02337217 1/31 * (1/1.38019122262781) + (0x00000055)*/ + 0x0178d9f5, /* bits=6 0.01150059 1/63 * (1/1.38019122262781) + (0x000000ad)*/ + 0x00baf129, /* bits=7 0.00570502 1/127 * (1/1.38019122262781) + (0x0000015e)*/ + 0x005d1abe, /* bits=8 0.00284132 1/255 * (1/1.38019122262781) + (0x000002bf)*/ + 0x002e760d, /* bits=9 0.00141788 1/511 * (1/1.38019122262781) + (0x00000582)*/ + 0x00173536, /* bits=10 0.00070825 1/1023 * (1/1.38019122262781) + (0x00000b07)*/ + 0x000b9928, /* bits=11 0.00035395 1/2047 * (1/1.38019122262781) + (0x00001612)*/ + 0x0005cc37, /* bits=12 0.00017693 1/4095 * (1/1.38019122262781) + (0x00002c27)*/ + 0x0002e604, /* bits=13 0.00008846 1/8191 * (1/1.38019122262781) + (0x00005852)*/ + 0x000172fc, /* bits=14 0.00004422 1/16383 * (1/1.38019122262781) + (0x0000b0a7)*/ + 0x0000b97d, /* bits=15 0.00002211 1/32767 * (1/1.38019122262781) + (0x00016150)*/ + 0x00005cbe, /* bits=16 0.00001106 1/65535 * (1/1.38019122262781) + (0x0002c2a5)*/ +}; + +const uint32_t dequant_long_unscaled[17] = { + 0, 0, 0x2aaaaaab, /* bits=2 0.33333333 1/3 (0x00000005)*/ + 0x12492492, /* bits=3 0.14285714 1/7 (0x0000000e)*/ + 0x08888889, /* bits=4 0.06666667 1/15 (0x0000001d)*/ + 0x04210842, /* bits=5 0.03225806 1/31 (0x0000003e)*/ + 0x02082082, /* bits=6 0.01587302 1/63 (0x0000007e)*/ + 0x01020408, /* bits=7 0.00787402 1/127 (0x000000fe)*/ + 0x00808081, /* bits=8 0.00392157 1/255 (0x000001fd)*/ + 0x00402010, /* bits=9 0.00195695 1/511 (0x000003fe)*/ + 0x00200802, /* bits=10 0.00097752 1/1023 (0x000007fe)*/ + 0x00100200, /* bits=11 0.00048852 1/2047 (0x00000ffe)*/ + 0x00080080, /* bits=12 0.00024420 1/4095 (0x00001ffe)*/ + 0x00040020, /* bits=13 0.00012209 1/8191 (0x00003ffe)*/ + 0x00020008, /* bits=14 0.00006104 1/16383 (0x00007ffe)*/ + 0x00010002, /* bits=15 0.00003052 1/32767 (0x0000fffe)*/ + 0x00008001, /* bits=16 0.00001526 1/65535 (0x0001fffc)*/ +}; /** Scales x by y bits to the right, adding a rounding factor. */ diff --git a/system/embdrv/sbc/decoder/srce/framing.c b/system/embdrv/sbc/decoder/srce/framing.c index f835b52ff1cc5846748c0ada1fccb86148dd3539..7c1c08775ed644cb78577f760e4d25c3bb3a8f49 100644 --- a/system/embdrv/sbc/decoder/srce/framing.c +++ b/system/embdrv/sbc/decoder/srce/framing.c @@ -96,57 +96,6 @@ const OI_BYTE crc8_narrow[256] = { 0x7f, 0x62, 0x45, 0x58, 0x0b, 0x16, 0x31, 0x2c, 0x97, 0x8a, 0xad, 0xb0, 0xe3, 0xfe, 0xd9, 0xc4}; #endif -const uint32_t dequant_long_scaled[17] = { - 0, 0, - 0x1ee9e116, /* bits=2 0.24151243 1/3 * (1/1.38019122262781) - (0x00000008)*/ - 0x0d3fa99c, /* bits=3 0.10350533 1/7 * (1/1.38019122262781) - (0x00000013)*/ - 0x062ec69e, /* bits=4 0.04830249 1/15 * (1/1.38019122262781) - (0x00000029)*/ - 0x02fddbfa, /* bits=5 0.02337217 1/31 * (1/1.38019122262781) - (0x00000055)*/ - 0x0178d9f5, /* bits=6 0.01150059 1/63 * (1/1.38019122262781) - (0x000000ad)*/ - 0x00baf129, /* bits=7 0.00570502 1/127 * (1/1.38019122262781) - (0x0000015e)*/ - 0x005d1abe, /* bits=8 0.00284132 1/255 * (1/1.38019122262781) - (0x000002bf)*/ - 0x002e760d, /* bits=9 0.00141788 1/511 * (1/1.38019122262781) - (0x00000582)*/ - 0x00173536, /* bits=10 0.00070825 1/1023 * (1/1.38019122262781) - (0x00000b07)*/ - 0x000b9928, /* bits=11 0.00035395 1/2047 * (1/1.38019122262781) - (0x00001612)*/ - 0x0005cc37, /* bits=12 0.00017693 1/4095 * (1/1.38019122262781) - (0x00002c27)*/ - 0x0002e604, /* bits=13 0.00008846 1/8191 * (1/1.38019122262781) - (0x00005852)*/ - 0x000172fc, /* bits=14 0.00004422 1/16383 * (1/1.38019122262781) - (0x0000b0a7)*/ - 0x0000b97d, /* bits=15 0.00002211 1/32767 * (1/1.38019122262781) - (0x00016150)*/ - 0x00005cbe, /* bits=16 0.00001106 1/65535 * (1/1.38019122262781) - (0x0002c2a5)*/ -}; - -const uint32_t dequant_long_unscaled[17] = { - 0, 0, 0x2aaaaaab, /* bits=2 0.33333333 1/3 (0x00000005)*/ - 0x12492492, /* bits=3 0.14285714 1/7 (0x0000000e)*/ - 0x08888889, /* bits=4 0.06666667 1/15 (0x0000001d)*/ - 0x04210842, /* bits=5 0.03225806 1/31 (0x0000003e)*/ - 0x02082082, /* bits=6 0.01587302 1/63 (0x0000007e)*/ - 0x01020408, /* bits=7 0.00787402 1/127 (0x000000fe)*/ - 0x00808081, /* bits=8 0.00392157 1/255 (0x000001fd)*/ - 0x00402010, /* bits=9 0.00195695 1/511 (0x000003fe)*/ - 0x00200802, /* bits=10 0.00097752 1/1023 (0x000007fe)*/ - 0x00100200, /* bits=11 0.00048852 1/2047 (0x00000ffe)*/ - 0x00080080, /* bits=12 0.00024420 1/4095 (0x00001ffe)*/ - 0x00040020, /* bits=13 0.00012209 1/8191 (0x00003ffe)*/ - 0x00020008, /* bits=14 0.00006104 1/16383 (0x00007ffe)*/ - 0x00010002, /* bits=15 0.00003052 1/32767 (0x0000fffe)*/ - 0x00008001, /* bits=16 0.00001526 1/65535 (0x0001fffc)*/ -}; #if defined(OI_DEBUG) || defined(PRINT_SAMPLES) || defined(PRINT_SCALEFACTORS) #include diff --git a/system/embdrv/sbc/encoder/include/sbc_encoder.h b/system/embdrv/sbc/encoder/include/sbc_encoder.h index fa54da25b0de51a3fff5cb0c7277573ae1eaa968..811fecf7384e6e3b186d985976d61c9921a3c637 100644 --- a/system/embdrv/sbc/encoder/include/sbc_encoder.h +++ b/system/embdrv/sbc/encoder/include/sbc_encoder.h @@ -28,9 +28,7 @@ #define ENCODER_VERSION "0025" #include -#include - -#include "bt_target.h" +#include /*DEFINES*/ #ifndef FALSE @@ -163,8 +161,6 @@ (SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS * SBC_MAX_NUM_OF_CHANNELS * \ SBC_MAX_NUM_OF_SUBBANDS) -#include "sbc_types.h" - typedef struct SBC_ENC_PARAMS_TAG { int16_t s16SamplingFreq; /* 16k, 32k, 44.1k or 48k*/ int16_t s16ChannelMode; /* mono, dual, streo or joint streo*/ diff --git a/system/embdrv/sbc/encoder/srce/sbc_encoder.c b/system/embdrv/sbc/encoder/srce/sbc_encoder.c index 54212ad6f6fda682ca065148f46e390d3296c75c..e69b1b6153d14ab5a91141192aa6d286e1c40bd3 100644 --- a/system/embdrv/sbc/encoder/srce/sbc_encoder.c +++ b/system/embdrv/sbc/encoder/srce/sbc_encoder.c @@ -23,10 +23,11 @@ ******************************************************************************/ #include "sbc_encoder.h" -#include -#include "bt_target.h" + #include "sbc_enc_func_declare.h" +#define abs32(x) (((x) >= 0) ? (x) : (-(x))) + int16_t EncMaxShiftCounter; #if (SBC_JOINT_STE_INCLUDED == TRUE) diff --git a/system/embdrv/tests/Android.bp b/system/embdrv/tests/Android.bp index 7941fa92d95380231853e4d954ff5fcbbe9fe904..6b06547e9d7f1f2d1d48291a0497a7dd604094ee 100644 --- a/system/embdrv/tests/Android.bp +++ b/system/embdrv/tests/Android.bp @@ -10,10 +10,9 @@ package { cc_test { name: "libaptx_enc_tests", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, @@ -30,10 +29,9 @@ cc_test { cc_test { name: "libaptxhd_enc_tests", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, diff --git a/system/gd/Android.bp b/system/gd/Android.bp index 656afad7d54e8ac241651652718630df707ce29a..07a5dcafbd26c5fc5c94b21d89de948c8c137c77 100644 --- a/system/gd/Android.bp +++ b/system/gd/Android.bp @@ -11,7 +11,7 @@ package { cc_defaults { name: "gd_defaults", defaults: [ - "fluoride_common_options", + "bluetooth_cflags", ], tidy_checks: [ "-performance-unnecessary-value-param", @@ -30,17 +30,13 @@ cc_defaults { enabled: false, }, }, - cpp_std: "c++17", cflags: [ "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))", "-DGOOGLE_PROTOBUF_NO_RTTI", - "-DLOG_NDEBUG=1", + "-DLOG_NDEBUG=0", "-Wno-unused-result", "-fvisibility=hidden", ], - conlyflags: [ - "-std=c99", - ], header_libs: ["jni_headers"], } @@ -98,26 +94,22 @@ cc_defaults { name: "libbluetooth_gd_defaults", defaults: [ "gd_defaults", - "libchrome_support_defaults", ], host_supported: true, target: { linux: { srcs: [ - ":BluetoothBtaaSources_linux_generic", ":BluetoothOsSources_linux_generic", ], }, host: { srcs: [ - ":BluetoothBtaaSources_host", ":BluetoothHalSources_hci_host", ":BluetoothOsSources_host", ], }, android: { srcs: [ - ":BluetoothBtaaSources_android", ":BluetoothHalSources_hci_android_hidl", ":BluetoothOsSources_android", ], @@ -140,7 +132,6 @@ cc_defaults { srcs: [ ":BluetoothAttSources", ":BluetoothCommonSources", - ":BluetoothCryptoToolboxSources", ":BluetoothDumpsysSources", ":BluetoothHalSources", ":BluetoothHciSources", @@ -156,27 +147,41 @@ cc_defaults { ":BluetoothStorageSources", ":BluetoothSyspropsSources", "module.cc", + "module_dumper.cc", + "module_dumper_flatbuffer.cc", "stack_manager.cc", ], generated_headers: [ "BluetoothGeneratedBundlerSchema_h_bfbs", "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], shared_libs: [ "libcrypto", "libflatbuffers-cpp", + "liblog", + ], + export_shared_lib_headers: [ + "libflatbuffers-cpp", ], whole_static_libs: [ + "bluetooth_flags_c_lib", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", + "libbluetooth_smp_pdl", "libc++fs", ], static_libs: [ + "libbase", "libbluetooth-dumpsys", "libbluetooth-protos", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", "libbluetooth_rust_interop", "libbt-platform-protos-lite", "libbt_shim_bridge", "libbt_shim_ffi", + "libosi", + "server_configurable_flags", ], include_dirs: [ "packages/modules/Bluetooth/system/include", @@ -190,10 +195,14 @@ cc_library { defaults: [ "libbluetooth_gd_defaults", ], + include_dirs: [ + "packages/modules/Bluetooth/system", + ], apex_available: [ "com.android.btservices", ], min_sdk_version: "31", + static_libs: ["libchrome"], } cc_library { @@ -201,12 +210,21 @@ cc_library { defaults: [ "libbluetooth_gd_defaults", ], + include_dirs: [ + "packages/modules/Bluetooth/system", + ], srcs: [ ":BluetoothOsSources_fake_timer", ], cflags: [ "-DFUZZ_TARGET", "-DUSE_FAKE_TIMERS", + "-Wno-unused-parameter", + ], + static_libs: [ + "libbluetooth-types", + "libchrome", + "libosi", ], } @@ -215,19 +233,31 @@ cc_library { defaults: [ "libbluetooth_gd_defaults", ], + include_dirs: [ + "packages/modules/Bluetooth/system", + ], srcs: [ ":BluetoothOsSources_fake_timer", ], cflags: [ "-DUSE_FAKE_TIMERS", ], + static_libs: [ + "libbluetooth-types", + "libchrome", + "libosi", + ], } cc_binary { name: "bluetooth_stack_with_facade", defaults: [ "gd_defaults", - "libchrome_support_defaults", + ], + include_dirs: [ + "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/include", + "packages/modules/Bluetooth/system/types", ], host_supported: true, srcs: [ @@ -247,7 +277,6 @@ cc_binary { "BlueberryFacadeGeneratedStub_h", "BluetoothGeneratedBundlerSchema_h_bfbs", "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", // Needed here to guarantee that generated zip file is created before // bluetooth_cert_tests.zip is packaged "BlueberryFacadeAndCertGeneratedStub_py", @@ -259,19 +288,26 @@ cc_binary { "breakpad_client", "libbluetooth-dumpsys", "libbluetooth-protos", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", "libbluetooth_gd", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", "libbluetooth_rust_interop", + "libbluetooth_smp_pdl", "libbt_shim_bridge", "libbt_shim_ffi", + "libchrome", "libflatbuffers-cpp", + "libosi", ], shared_libs: [ "libcrypto", "libgrpc++", - "libgrpc++_unsecure", "libgrpc_wrap", "libprotobuf-cpp-full", "libunwindstack", + "server_configurable_flags", ], target: { android: { @@ -303,13 +339,15 @@ cc_binary { cc_test { name: "bluetooth_test_gd_unit", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "gd_defaults", - "libchrome_support_defaults", "mts_defaults", ], + include_dirs: [ + "packages/modules/Bluetooth/system/include", + "packages/modules/Bluetooth/system/types", + ], host_supported: true, // TODO(b/231993739): Reenable isolated:true by deleting the explicit disable below isolated: false, @@ -351,7 +389,6 @@ cc_test { }, }, srcs: [ - ":BluetoothBtaaSources_linux_generic_tests", ":BluetoothCommonTestSources", ":BluetoothCryptoToolboxTestSources", ":BluetoothDumpsysTestSources", @@ -370,26 +407,36 @@ cc_test { generated_headers: [ "BluetoothGeneratedBundlerSchema_h_bfbs", "BluetoothGeneratedDumpsysDataSchema_h", + "BluetoothGeneratedDumpsysInternalTestData_h", "BluetoothGeneratedDumpsysTestData_h", - "BluetoothGeneratedPackets_h", ], static_libs: [ "libbluetooth-dumpsys", "libbluetooth-dumpsys-test", "libbluetooth-dumpsys-unittest", "libbluetooth-protos", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", "libbluetooth_gd_unit_tests", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", "libbluetooth_rust_interop", + "libbluetooth_smp_pdl", "libbt-platform-protos-lite", "libbt-platform-protos-lite", "libbt_shim_bridge", "libbt_shim_ffi", "libc++fs", + "libchrome", + "libflagtest", "libflatbuffers-cpp", "libgmock", + "libosi", ], shared_libs: [ + "libbase", "libcrypto", + "server_configurable_flags", ], sanitize: { address: true, @@ -398,12 +445,50 @@ cc_test { } cc_test { - name: "bluetooth_packet_parser_test", + name: "bluetooth_test_gdx_unit", test_suites: ["device-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "gd_defaults", - "libchrome_support_defaults", + "mts_defaults", + ], + include_dirs: [ + "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/include", + "packages/modules/Bluetooth/system/stack/include", + "packages/modules/Bluetooth/system/types", + ], + host_supported: true, + srcs: [ + ":TestCommonMockFunctions", + "module_mainloop_unittest.cc", + ], + generated_headers: [ + "BluetoothGeneratedBundlerSchema_h_bfbs", + "BluetoothGeneratedDumpsysDataSchema_h", + "BluetoothGeneratedDumpsysInternalTestData_h", + "BluetoothGeneratedDumpsysTestData_h", + ], + static_libs: [ + "libbluetooth_gd", + "libbt-btu-main-thread", + "libbt-common", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libchrome", + "libevent", + "libflatbuffers-cpp", + ], + sanitize: { + address: true, + }, + min_sdk_version: "Tiramisu", +} + +cc_test { + name: "bluetooth_packet_parser_test", + test_suites: ["general-tests"], + defaults: [ + "gd_defaults", "mts_defaults", ], include_dirs: ["packages/modules/Bluetooth/system/gd"], @@ -414,7 +499,6 @@ cc_test { srcs: [ ":BluetoothPacketParserTestPacketTestSources", ":BluetoothPacketSources", - "hci/address.cc", ], generated_headers: [ "BluetoothPacketParserTestPacketPdlGen_h", @@ -456,6 +540,8 @@ cc_defaults { ], static_libs: [ "libbluetooth-protos", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", "libbluetooth_gd_fuzzing", "libbluetooth_rust_interop", "libbt_shim_bridge", @@ -463,17 +549,18 @@ cc_defaults { "libchrome", "libgmock", "libgtest", + "libosi", ], host_supported: true, generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], shared_libs: [ + "libbase", "libcrypto", - "libflatbuffers-cpp", "libgrpc++", "libgrpc_wrap", + "server_configurable_flags", ], cflags: [ "-DFUZZ_TARGET", @@ -507,6 +594,7 @@ cc_fuzz { cc: ["android-bluetooth-security@google.com"], componentid: 27441, }, + cflags: ["-Wno-unused-parameter"], } cc_fuzz { @@ -516,6 +604,7 @@ cc_fuzz { ":BluetoothHalFuzzSources", "hci/fuzz/hci_layer_fuzz_test.cc", ], + cflags: ["-Wno-unused-parameter"], } cc_fuzz { @@ -528,13 +617,13 @@ cc_fuzz { cc: ["android-bluetooth-security@google.com"], componentid: 27441, }, + cflags: ["-Wno-unused-parameter"], } cc_benchmark { name: "bluetooth_benchmark_gd", defaults: [ "gd_defaults", - "libchrome_support_defaults", ], host_supported: true, srcs: [ @@ -544,47 +633,7 @@ cc_benchmark { static_libs: [ "libbluetooth_gd", "libbt_shim_bridge", - ], -} - -filegroup { - name: "BluetoothHciClassSources", - srcs: [ - "hci/address.cc", - "hci/class_of_device.cc", - ], -} - -genrule { - name: "BluetoothGeneratedPackets_h", - tools: [ - "bluetooth_packetgen", - ], - cmd: "$(location bluetooth_packetgen) --fuzzing --testing --include=packages/modules/Bluetooth/system/gd --out=$(genDir) $(in)", - srcs: [ - "hci/hci_packets.pdl", - "l2cap/l2cap_packets.pdl", - "security/smp_packets.pdl", - ], - out: [ - "hci/hci_packets.h", - "l2cap/l2cap_packets.h", - "security/smp_packets.h", - ], - visibility: ["//visibility:public"], -} - -genrule { - name: "BluetoothGeneratedPackets_rust", - tools: [ - "bluetooth_packetgen", - ], - cmd: "$(location bluetooth_packetgen) --include=packages/modules/Bluetooth/system/gd --out=$(genDir) $(in) --rust", - srcs: [ - "hci/hci_packets.pdl", - ], - out: [ - "hci/hci_packets.rs", + "libchrome", ], } @@ -604,7 +653,7 @@ rust_library { rustlibs: [ "libbytes", "liblog_rust", - "libnum_traits", + "libpdl_runtime", "libthiserror", ], apex_available: [ @@ -630,44 +679,7 @@ rust_test_host { rustlibs: [ "libbytes", "liblog_rust", - "libnum_traits", - "libthiserror", - ], -} - -// Generate and run tests of rust pdl parser for tests packets -genrule { - name: "TestGeneratedPackets_rust", - tools: [ - "bluetooth_packetgen", - ], - cmd: "$(location bluetooth_packetgen) --include=packages/modules/Bluetooth/system/gd --out=$(genDir) $(in) --rust", - srcs: [ - "packet/parser/test/rust_test_packets.pdl", - ], - out: [ - "packet/parser/test/rust_test_packets.rs", - ], -} - -rust_test_host { - name: "packets_test_rust", - defaults: [ - "gd_rust_defaults", - "mts_defaults", - ], - srcs: [ - "rust/packets/test_lib.rs", - - ":TestGeneratedPackets_rust", - ], - test_suites: ["general-tests"], - edition: "2018", - proc_macros: ["libnum_derive"], - rustlibs: [ - "libbytes", - "liblog_rust", - "libnum_traits", + "libpdl_runtime", "libthiserror", ], } @@ -680,17 +692,16 @@ genrule { ], cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -b --schema -o $(genDir) $(in) ", srcs: [ - "btaa/activity_attribution.fbs", "common/init_flags.fbs", "dumpsys_data.fbs", "hci/hci_acl_manager.fbs", "hci/hci_controller.fbs", "l2cap/classic/l2cap_classic_module.fbs", + "module_unittest.fbs", "os/wakelock_manager.fbs", "shim/dumpsys.fbs", ], out: [ - "activity_attribution.bfbs", "dumpsys.bfbs", "dumpsys_data.bfbs", "hci_acl_manager.bfbs", @@ -708,17 +719,16 @@ genrule { ], cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -o $(genDir) --cpp $(in) ", srcs: [ - "btaa/activity_attribution.fbs", "common/init_flags.fbs", "dumpsys_data.fbs", "hci/hci_acl_manager.fbs", "hci/hci_controller.fbs", "l2cap/classic/l2cap_classic_module.fbs", + "module_unittest.fbs", "os/wakelock_manager.fbs", "shim/dumpsys.fbs", ], out: [ - "activity_attribution_generated.h", "dumpsys_data_generated.h", "dumpsys_generated.h", "hci_acl_manager_generated.h", @@ -729,42 +739,6 @@ genrule { ], } -genrule { - name: "BluetoothGeneratedPackets_python3_cc", - tools: [ - "bluetooth_packetgen", - ], - cmd: "$(location bluetooth_packetgen) --include=packages/modules/Bluetooth/system/gd --out=$(genDir) --num_shards=10 $(in)", - srcs: [ - "l2cap/l2cap_packets.pdl", - "security/smp_packets.pdl", - ], - out: [ - "l2cap/l2cap_packets_python3.cc", - "l2cap/l2cap_packets_python3_shard_0.cc", - "l2cap/l2cap_packets_python3_shard_1.cc", - "l2cap/l2cap_packets_python3_shard_2.cc", - "l2cap/l2cap_packets_python3_shard_3.cc", - "l2cap/l2cap_packets_python3_shard_4.cc", - "l2cap/l2cap_packets_python3_shard_5.cc", - "l2cap/l2cap_packets_python3_shard_6.cc", - "l2cap/l2cap_packets_python3_shard_7.cc", - "l2cap/l2cap_packets_python3_shard_8.cc", - "l2cap/l2cap_packets_python3_shard_9.cc", - "security/smp_packets_python3.cc", - "security/smp_packets_python3_shard_0.cc", - "security/smp_packets_python3_shard_1.cc", - "security/smp_packets_python3_shard_2.cc", - "security/smp_packets_python3_shard_3.cc", - "security/smp_packets_python3_shard_4.cc", - "security/smp_packets_python3_shard_5.cc", - "security/smp_packets_python3_shard_6.cc", - "security/smp_packets_python3_shard_7.cc", - "security/smp_packets_python3_shard_8.cc", - "security/smp_packets_python3_shard_9.cc", - ], -} - cc_defaults { name: "bluetooth_py3_native_extension_defaults", include_dirs: [ @@ -847,39 +821,21 @@ cc_library_host_shared { srcs: [ ":BluetoothPacketSources", "common/strings.cc", - "hci/address.cc", - "hci/class_of_device.cc", "l2cap/fcs.cc", "packet/python3_module.cc", ], - generated_headers: [ - "BluetoothGeneratedPackets_h", - ], generated_sources: [ "BluetoothGeneratedPackets_python3_cc", ], header_libs: [ "pybind11_headers", ], + static_libs: [ + "libbluetooth_l2cap_pdl", + ], cflags: [ "-fexceptions", ], rtti: true, } - -// Generate the python parser+serializer backend for -// hci_packets.pdl. -genrule { - name: "gd_hci_packets_python3_gen", - defaults: ["pdl_python_generator_defaults"], - cmd: "$(location :pdl) $(in) |" + - " $(location :pdl_python_generator)" + - " --output $(out) --custom-type-location blueberry.utils.bluetooth", - srcs: [ - ":BluetoothHciPackets", - ], - out: [ - "hci_packets.py", - ], -} diff --git a/system/gd/BUILD.gn b/system/gd/BUILD.gn index 7acf5217bcf16d70c2fa5c3e29867eaf5062b838..ce72aae9292247402fa349b3d3740faba425fc77 100644 --- a/system/gd/BUILD.gn +++ b/system/gd/BUILD.gn @@ -46,15 +46,17 @@ group("gd_default_deps") { deps = [ "//bt/system:libbt-platform-protos-lite", "//bt/system/gd:BluetoothGeneratedDumpsysDataSchema_h", - "//bt/system/gd:BluetoothGeneratedPackets_h", "//bt/system/gd/dumpsys:libbluetooth-dumpsys", "//bt/system/gd/rust/shim:init_flags_bridge_header", + "//bt/system/pdl:BluetoothGeneratedPackets_h", ] } static_library("libbluetooth_gd") { sources = [ "module.cc", + "module_dumper.cc", + "module_dumper_flatbuffer.cc", "stack_manager.cc", ] @@ -64,12 +66,9 @@ static_library("libbluetooth_gd") { "//bt/system/gd/rust/common:libbt_keystore_cc", "//bt/system/gd/rust/topshim:libbluetooth_topshim", "//bt/system/gd/rust/shim:libbluetooth_rust_interop", - "//bt/system/gd:BluetoothGeneratedPackets_h", "//bt/system/gd/att:BluetoothAttSources", "//bt/system/gd/common:BluetoothCommonSources", - "//bt/system/gd/crypto_toolbox:BluetoothCryptoToolboxSources", "//bt/system/gd/dumpsys:BluetoothDumpsysSources", - "//bt/system/gd/btaa:BluetoothBtaaSources_linux", "//bt/system/gd/hal:BluetoothHalSources", "//bt/system/gd/hal:BluetoothHalSources_hci_host", "//bt/system/gd/l2cap:BluetoothL2capSources", @@ -79,12 +78,12 @@ static_library("libbluetooth_gd") { "//bt/system/gd/shim:BluetoothShimSources", "//bt/system/gd/storage:BluetoothStorageSources", "//bt/system/gd/sysprops:BluetoothSyspropsSources", + "//bt/system/pdl:BluetoothGeneratedPackets_h", ] } flatbuffer("BluetoothGeneratedDumpsysDataSchema_h") { sources = [ - "btaa/activity_attribution.fbs", "common/init_flags.fbs", "dumpsys_data.fbs", "hci/hci_acl_manager.fbs", @@ -97,7 +96,6 @@ flatbuffer("BluetoothGeneratedDumpsysDataSchema_h") { bt_flatc_binary_schema("BluetoothGeneratedDumpsysBinarySchema_bfbs") { sources = [ - "btaa/activity_attribution.fbs", "common/init_flags.fbs", "dumpsys_data.fbs", "hci/hci_acl_manager.fbs", @@ -109,33 +107,3 @@ bt_flatc_binary_schema("BluetoothGeneratedDumpsysBinarySchema_bfbs") { include_dir = "system/gd" } - -packetgen_py("BluetoothGeneratedPackets_python3_cc") { - sources = [ - "hci/hci_packets.pdl", - "l2cap/l2cap_packets.pdl", - "security/smp_packets.pdl", - ] - - include = "system/gd" - source_root = "../.." - shards = 10 -} - -packetgen_headers("BluetoothGeneratedPackets_h") { - sources = [ - "hci/hci_packets.pdl", - "l2cap/l2cap_packets.pdl", - "security/smp_packets.pdl", - ] - - include = "system/gd" - source_root = "../.." -} - -packetgen_rust("BluetoothGeneratedPackets_rust") { - sources = [ "hci/hci_packets.pdl" ] - - include = "system/gd" - source_root = "../.." -} diff --git a/system/gd/att/att_module.cc b/system/gd/att/att_module.cc index 99846fb8fedd02c58b777f5d47694bb523fd898d..e552a2163aa0b78f23335cd0986d13aa31e88d9f 100644 --- a/system/gd/att/att_module.cc +++ b/system/gd/att/att_module.cc @@ -33,12 +33,12 @@ const ModuleFactory AttModule::Factory = ModuleFactory([]() { return new AttModu namespace { void OnAttRegistrationCompleteLe( - l2cap::le::FixedChannelManager::RegistrationResult result, - std::unique_ptr le_smp_service) { + l2cap::le::FixedChannelManager::RegistrationResult /* result */, + std::unique_ptr /* le_smp_service */) { LOG_INFO("ATT channel registration complete"); } -void OnAttConnectionOpenLe(std::unique_ptr channel) { +void OnAttConnectionOpenLe(std::unique_ptr /* channel */) { LOG_INFO("ATT conneciton opened"); } } // namespace diff --git a/system/gd/btaa/Android.bp b/system/gd/btaa/Android.bp deleted file mode 100644 index 6b4c269ba40b392e88fb988c076605959cb16b86..0000000000000000000000000000000000000000 --- a/system/gd/btaa/Android.bp +++ /dev/null @@ -1,39 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "system_bt_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["system_bt_license"], -} - -filegroup { - name: "BluetoothBtaaSources_android", - srcs: [ - "android/activity_attribution.cc", - ], -} - -filegroup { - name: "BluetoothBtaaSources_host", - srcs: [ - "host/activity_attribution.cc", - ], -} - -filegroup { - name: "BluetoothBtaaSources_linux_generic", - srcs: [ - "linux_generic/attribution_processor.cc", - "linux_generic/cmd_evt_classification.cc", - "linux_generic/hci_processor.cc", - "linux_generic/wakelock_processor.cc", - ], -} - -filegroup { - name: "BluetoothBtaaSources_linux_generic_tests", - srcs: [ - "linux_generic/attribution_processor_tests.cc", - ], -} diff --git a/system/gd/btaa/activity_attribution.fbs b/system/gd/btaa/activity_attribution.fbs deleted file mode 100644 index b3ba8517763d552e2a604bec6bbd0e815a69fdbd..0000000000000000000000000000000000000000 --- a/system/gd/btaa/activity_attribution.fbs +++ /dev/null @@ -1,37 +0,0 @@ -namespace bluetooth.activity_attribution; - -attribute "privacy"; - -table WakeupEntry { - wakeup_time:string; - activity:string; - address:string; - package_info:string; -} - -table ActivityAggregationEntry { - package_info:string; - address:string; - activity:string; - wakeup_count:int; - byte_count:int; - wakelock_duration_ms:int; - creation_time:string; -} - -table ActivityAttributionData { - title_device_wakeup:string; - num_device_wakeup:int; - device_wakeup_attribution:[WakeupEntry]; - title_device_activity:string; - num_device_activity:int; - device_activity_aggregation:[ActivityAggregationEntry]; - title_app_wakeup:string; - num_app_wakeup:int; - app_wakeup_attribution:[WakeupEntry]; - title_app_activity:string; - num_app_activity:int; - app_activity_aggregation:[ActivityAggregationEntry]; -} - -root_type ActivityAttributionData; \ No newline at end of file diff --git a/system/gd/btaa/activity_attribution.h b/system/gd/btaa/activity_attribution.h deleted file mode 100644 index 93f5549dd3b979097b5f0a311a933e901ed210d8..0000000000000000000000000000000000000000 --- a/system/gd/btaa/activity_attribution.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "hal/snoop_logger.h" -#include "hci/address.h" -#include "module.h" - -namespace bluetooth { -namespace activity_attribution { - -enum class Activity : uint8_t { UNKNOWN = 0, ACL, ADVERTISE, CONNECT, CONTROL, HFP, ISO, SCAN, VENDOR }; - -using CreationTime = std::chrono::time_point; - -struct BtaaAggregationEntry { - hci::Address address; - Activity activity; - uint16_t wakeup_count; - uint32_t byte_count; - uint32_t wakelock_duration_ms; - CreationTime creation_time; -}; - -class ActivityAttributionCallback { - public: - virtual ~ActivityAttributionCallback() = default; - - // Callback when Bluetooth woke up the system - virtual void OnWakeup(const Activity activity, const hci::Address& address) = 0; - - // Callback when Bluetooth activity logs are ready to be moved - virtual void OnActivityLogsReady(const std::vector logs) = 0; -}; - -class ActivityAttribution : public bluetooth::Module { - public: - ActivityAttribution() = default; - ActivityAttribution(const ActivityAttribution&) = delete; - ActivityAttribution& operator=(const ActivityAttribution&) = delete; - - ~ActivityAttribution() = default; - - void Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type); - void OnWakelockAcquired(); - void OnWakelockReleased(); - void OnWakeup(); - void RegisterActivityAttributionCallback(ActivityAttributionCallback* callback); - void NotifyActivityAttributionInfo(int uid, const std::string& package_name, const std::string& device_address); - - static const ModuleFactory Factory; - - protected: - std::string ToString() const override; - void ListDependencies(ModuleList* list) const override; - void Start() override; - void Stop() override; - DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const override; // Module - - private: - struct impl; - std::unique_ptr pimpl_; -}; - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/android/activity_attribution.cc b/system/gd/btaa/android/activity_attribution.cc deleted file mode 100644 index 79e0cea62d09cf06e27ac4316f630ac233e9cebb..0000000000000000000000000000000000000000 --- a/system/gd/btaa/android/activity_attribution.cc +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "btaa" - -#include "btaa/activity_attribution.h" -#include "activity_attribution_generated.h" - -#include -#include -#include -#include - -#include "btaa/attribution_processor.h" -#include "btaa/hci_processor.h" -#include "btaa/wakelock_processor.h" -#include "module.h" -#include "os/log.h" - -using aidl::android::system::suspend::BnSuspendCallback; -using aidl::android::system::suspend::BnWakelockCallback; -using aidl::android::system::suspend::ISuspendCallback; -using aidl::android::system::suspend::ISuspendControlService; -using Status = ::ndk::ScopedAStatus; -using namespace ndk; - -namespace bluetooth { -namespace activity_attribution { - -const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return new ActivityAttribution(); }); - -static const std::string kBtWakelockName("hal_bluetooth_lock"); -static const std::string kBtWakeupReason("hs_uart_wakeup"); -static const std::string kSuspendService("suspend_control"); -static const size_t kHciAclHeaderSize = 4; - -static std::mutex g_module_mutex; -static ActivityAttribution* g_module = nullptr; -static bool is_wakeup_callback_registered = false; -static bool is_wakelock_callback_registered = false; - -struct wakelock_callback : public BnWakelockCallback { - wakelock_callback() {} - - Status notifyAcquired() override { - std::lock_guard guard(g_module_mutex); - if (g_module != nullptr) { - g_module->OnWakelockAcquired(); - } - return Status::ok(); - } - Status notifyReleased() override { - std::lock_guard guard(g_module_mutex); - if (g_module != nullptr) { - g_module->OnWakelockReleased(); - } - return Status::ok(); - } -}; - -static std::shared_ptr g_wakelock_callback = nullptr; - -struct wakeup_callback : public BnSuspendCallback { - wakeup_callback() {} - - Status notifyWakeup(bool success, const std::vector& wakeup_reasons) override { - for (auto& wakeup_reason : wakeup_reasons) { - if (wakeup_reason.find(kBtWakeupReason) != std::string::npos) { - std::lock_guard guard(g_module_mutex); - if (g_module != nullptr) { - g_module->OnWakeup(); - } - break; - } - } - return Status::ok(); - } -}; - -static std::shared_ptr g_wakeup_callback = nullptr; - -struct ActivityAttribution::impl { - impl(ActivityAttribution* module) { - std::lock_guard guard(g_module_mutex); - g_module = module; - if (is_wakeup_callback_registered && is_wakelock_callback_registered) { - LOG_ERROR("Wakeup and wakelock callbacks are already registered"); - return; - } - - Status register_callback_status; - bool is_register_successful = false; - if (!AServiceManager_isDeclared(kSuspendService.c_str())) { - LOG_ERROR("No suspend control service available."); - return; - } - auto control_service = ISuspendControlService::fromBinder( - SpAIBinder(AServiceManager_waitForService(kSuspendService.c_str()))); - - if (!is_wakeup_callback_registered) { - g_wakeup_callback = SharedRefBase::make(); - register_callback_status = control_service->registerCallback(g_wakeup_callback, &is_register_successful); - if (!is_register_successful || !register_callback_status.isOk()) { - LOG_ERROR("Fail to register wakeup callback"); - return; - } - is_wakeup_callback_registered = true; - } - - if (!is_wakelock_callback_registered) { - g_wakelock_callback = SharedRefBase::make(); - register_callback_status = - control_service->registerWakelockCallback(g_wakelock_callback, kBtWakelockName, &is_register_successful); - if (!is_register_successful || !register_callback_status.isOk()) { - LOG_ERROR("Fail to register wakelock callback"); - return; - } - is_wakelock_callback_registered = true; - } - } - - ~impl() { - std::lock_guard guard(g_module_mutex); - g_module = nullptr; - } - - void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) { - attribution_processor_.OnBtaaPackets(std::move(hci_processor_.OnHciPacket(std::move(packet), type, length))); - } - - void on_wakelock_acquired() { - wakelock_processor_.OnWakelockAcquired(); - } - - void on_wakelock_released() { - uint32_t wakelock_duration_ms = 0; - - wakelock_duration_ms = wakelock_processor_.OnWakelockReleased(); - if (wakelock_duration_ms != 0) { - attribution_processor_.OnWakelockReleased(wakelock_duration_ms); - } - } - - void on_wakeup() { - attribution_processor_.OnWakeup(); - } - - void register_callback(ActivityAttributionCallback* callback) { - callback_ = callback; - } - - void notify_activity_attribution_info(int uid, const std::string& package_name, const std::string& device_address) { - attribution_processor_.NotifyActivityAttributionInfo(uid, package_name, device_address); - } - - void Dump( - std::promise> promise, flatbuffers::FlatBufferBuilder* fb_builder) { - attribution_processor_.Dump(std::move(promise), fb_builder); - } - - ActivityAttributionCallback* callback_; - AttributionProcessor attribution_processor_; - HciProcessor hci_processor_; - WakelockProcessor wakelock_processor_; -}; - -void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type) { - uint16_t original_length = packet.size(); - uint16_t truncate_length; - - switch (type) { - case hal::SnoopLogger::PacketType::CMD: - case hal::SnoopLogger::PacketType::EVT: - truncate_length = packet.size(); - break; - case hal::SnoopLogger::PacketType::ACL: - case hal::SnoopLogger::PacketType::SCO: - case hal::SnoopLogger::PacketType::ISO: - truncate_length = kHciAclHeaderSize; - break; - } - - if (!truncate_length) { - return; - } - - hal::HciPacket truncate_packet(packet.begin(), packet.begin() + truncate_length); - CallOn(pimpl_.get(), &impl::on_hci_packet, truncate_packet, type, original_length); -} - -void ActivityAttribution::OnWakelockAcquired() { - CallOn(pimpl_.get(), &impl::on_wakelock_acquired); -} - -void ActivityAttribution::OnWakelockReleased() { - CallOn(pimpl_.get(), &impl::on_wakelock_released); -} - -void ActivityAttribution::OnWakeup() { - CallOn(pimpl_.get(), &impl::on_wakeup); -} - -void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) { - CallOn(pimpl_.get(), &impl::register_callback, callback); -} - -void ActivityAttribution::NotifyActivityAttributionInfo( - int uid, const std::string& package_name, const std::string& device_address) { - CallOn(pimpl_.get(), &impl::notify_activity_attribution_info, uid, package_name, device_address); -} - -std::string ActivityAttribution::ToString() const { - return "Btaa Module"; -} - -void ActivityAttribution::ListDependencies(ModuleList* list) const {} - -void ActivityAttribution::Start() { - pimpl_ = std::make_unique(this); -} - -void ActivityAttribution::Stop() { - pimpl_.reset(); -} - -DumpsysDataFinisher ActivityAttribution::GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const { - ASSERT(fb_builder != nullptr); - - std::promise> promise; - auto future = promise.get_future(); - pimpl_->Dump(std::move(promise), fb_builder); - - auto dumpsys_data = future.get(); - - return [dumpsys_data](DumpsysDataBuilder* dumpsys_builder) { - dumpsys_builder->add_activity_attribution_dumpsys_data(dumpsys_data); - }; -} - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/attribution_processor.h b/system/gd/btaa/attribution_processor.h deleted file mode 100644 index e28e6cb2168cd63188ca0579db2880fcde970e82..0000000000000000000000000000000000000000 --- a/system/gd/btaa/attribution_processor.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "hci_processor.h" - -namespace bluetooth { -namespace activity_attribution { - -static constexpr size_t kWakeupAggregatorSize = 200; - -struct AddressActivityKey { - hci::Address address; - Activity activity; - - bool operator==(const AddressActivityKey& other) const { - return (address == other.address && activity == other.activity); - } -}; - -struct AddressActivityKeyHasher { - std::size_t operator()(const AddressActivityKey& key) const { - return ( - (std::hash()(key.address.ToString()) ^ - (std::hash()(static_cast(key.activity))))); - } -}; - -struct AppActivityKey { - std::string app; - Activity activity; - - bool operator==(const AppActivityKey& other) const { - return (app == other.app && activity == other.activity); - } -}; - -struct AppActivityKeyHasher { - std::size_t operator()(const AppActivityKey& key) const { - return ( - (std::hash()(key.app) ^ (std::hash()(static_cast(key.activity))))); - } -}; - -struct DeviceWakeupDescriptor { - Activity activity_; - const hci::Address address_; - DeviceWakeupDescriptor(Activity activity, const hci::Address address) : activity_(activity), address_(address) {} - virtual ~DeviceWakeupDescriptor() {} -}; - -struct AppWakeupDescriptor { - Activity activity_; - std::string package_info_; - AppWakeupDescriptor(Activity activity, std::string package_info) : activity_(activity), package_info_(package_info) {} - virtual ~AppWakeupDescriptor() {} -}; - -class AttributionProcessor { - public: - void OnBtaaPackets(std::vector btaa_packets); - void OnWakelockReleased(uint32_t duration_ms); - void OnWakeup(); - void NotifyActivityAttributionInfo(int uid, const std::string& package_name, const std::string& device_address); - void Dump( - std::promise> promise, flatbuffers::FlatBufferBuilder* fb_builder); - - using ClockType = std::chrono::time_point; - using NowFunc = ClockType (*)(); - - // by default, we use the std::chrono::system_clock::now implementation to - // get the current timestamp - AttributionProcessor() : now_func_(std::chrono::system_clock::now) {} - // in other cases, we may need to use different implementation - // e.g., for testing purposes - AttributionProcessor(NowFunc func) : now_func_(func) {} - - private: - // this function is added for testing support in - // OnWakelockReleased - NowFunc now_func_ = std::chrono::system_clock::now; - bool wakeup_ = false; - std::unordered_map btaa_aggregator_; - std::unordered_map wakelock_duration_aggregator_; - std::unordered_map address_app_map_; - std::unordered_map app_activity_aggregator_; - common::TimestampedCircularBuffer device_wakeup_aggregator_ = - common::TimestampedCircularBuffer(kWakeupAggregatorSize); - common::TimestampedCircularBuffer app_wakeup_aggregator_ = - common::TimestampedCircularBuffer(kWakeupAggregatorSize); - const char* ActivityToString(Activity activity); -}; - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/cmd_evt_classification.h b/system/gd/btaa/cmd_evt_classification.h deleted file mode 100644 index 1aae6c2244bfec0f287f0b31b00e2c32d1fbacf1..0000000000000000000000000000000000000000 --- a/system/gd/btaa/cmd_evt_classification.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "btaa/activity_attribution.h" -#include "hci/hci_packets.h" - -namespace bluetooth { -namespace activity_attribution { - -struct CmdEvtActivityClassification { - Activity activity; - uint16_t connection_handle_pos; - uint16_t address_pos; -}; - -CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode); -CmdEvtActivityClassification lookup_event(hci::EventCode event_code); -CmdEvtActivityClassification lookup_le_event(hci::SubeventCode subevent_code); - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/hci_processor.h b/system/gd/btaa/hci_processor.h deleted file mode 100644 index 47fbc68c3e870d0b42170691895a1dc68014c0a6..0000000000000000000000000000000000000000 --- a/system/gd/btaa/hci_processor.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "btaa/activity_attribution.h" -#include "btaa/cmd_evt_classification.h" -#include "hal/snoop_logger.h" -#include "hci/address.h" - -namespace bluetooth { -namespace activity_attribution { - -struct BtaaHciPacket { - Activity activity; - hci::Address address; - uint16_t byte_count; - - BtaaHciPacket() {} - BtaaHciPacket(Activity activity, hci::Address address, uint16_t byte_count) - : activity(activity), address(address), byte_count(byte_count) {} -}; - -class DeviceParser { - public: - void match_handle_with_address(uint16_t connection_handle, hci::Address& address); - - private: - std::map connection_lookup_table_; -}; - -struct PendingCommand { - hci::OpCode opcode; - BtaaHciPacket btaa_hci_packet; -}; - -class HciProcessor { - public: - std::vector OnHciPacket(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length); - - private: - void process_le_event(std::vector& btaa_hci_packets, int16_t byte_count, hci::EventView& event); - void process_special_event( - std::vector& btaa_hci_packets, - hci::EventCode event_code, - uint16_t byte_count, - hci::EventView& event); - void process_command( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count); - void process_event( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count); - void process_acl( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count); - void process_sco( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count); - void process_iso( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count); - - DeviceParser device_parser_; - PendingCommand pending_command_; -}; - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/host/activity_attribution.cc b/system/gd/btaa/host/activity_attribution.cc deleted file mode 100644 index ec02daf10884d7856c4cd5e3449cc4fd9e7e34cf..0000000000000000000000000000000000000000 --- a/system/gd/btaa/host/activity_attribution.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "btaa/activity_attribution.h" - -#include "module.h" - -namespace bluetooth { -namespace activity_attribution { - -struct ActivityAttribution::impl {}; - -void ActivityAttribution::OnWakelockAcquired() {} - -void ActivityAttribution::OnWakelockReleased() {} - -void ActivityAttribution::OnWakeup() {} - -void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {} - -void ActivityAttribution::NotifyActivityAttributionInfo( - int uid, const std::string& package_name, const std::string& device_address) {} - -std::string ActivityAttribution::ToString() const { - return "Btaa Module"; -} - -void ActivityAttribution::ListDependencies(ModuleList* list) const {} - -void ActivityAttribution::Start() {} - -void ActivityAttribution::Stop() {} - -const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return new ActivityAttribution(); }); - -DumpsysDataFinisher EmptyDumpsysDataFinisher = [](DumpsysDataBuilder* dumpsys_data_builder) {}; -DumpsysDataFinisher ActivityAttribution::GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const { - return EmptyDumpsysDataFinisher; -} -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/linux/activity_attribution.cc b/system/gd/btaa/linux/activity_attribution.cc deleted file mode 100644 index c4a4eb0aab50a2712ca6a6e9ed3fe9ef76fc20b3..0000000000000000000000000000000000000000 --- a/system/gd/btaa/linux/activity_attribution.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "btaa/activity_attribution.h" - -// TODO: Implement for Linux. -namespace bluetooth { -namespace activity_attribution { - -const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return new ActivityAttribution(); }); - -struct ActivityAttribution::impl { - impl(ActivityAttribution* module) {} - - void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {} - - void register_callback(ActivityAttributionCallback* callback) {} -}; - -void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type) {} - -void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {} - -void ActivityAttribution::NotifyActivityAttributionInfo( - int uid, const std::string& package_name, const std::string& device_address) {} - -std::string ActivityAttribution::ToString() const { - return "Btaa Module"; -} - -void ActivityAttribution::ListDependencies(ModuleList* list) const {} - -void ActivityAttribution::Start() {} - -void ActivityAttribution::Stop() {} - -DumpsysDataFinisher EmptyDumpsysDataFinisher = [](DumpsysDataBuilder* dumpsys_data_builder) {}; -DumpsysDataFinisher ActivityAttribution::GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const { - return EmptyDumpsysDataFinisher; -} - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/linux_generic/attribution_processor.cc b/system/gd/btaa/linux_generic/attribution_processor.cc deleted file mode 100644 index eadad9d30e0fe5fa093ac0c6c7017f464e2abfed..0000000000000000000000000000000000000000 --- a/system/gd/btaa/linux_generic/attribution_processor.cc +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "btaa/attribution_processor.h" -#include "common/strings.h" - -#include "os/log.h" - -namespace bluetooth { -namespace activity_attribution { - -constexpr char kActivityAttributionTimeFormat[] = "%Y-%m-%d %H:%M:%S"; -static const std::string kUnknownPackageInfo = "UNKNOWN"; -// A device-activity aggregation entry expires after two days (172800 seconds) -static const int kDurationToKeepDeviceActivityEntrySecs = 172800; -// A transient device-activity aggregation entry is defined as an entry with very few Byte count -// (200 Bytes, this is about the size of 5 advertising packets) over a period of time (15 minutes) -static const int kByteCountTransientDeviceActivityEntry = 200; -static const int kDurationTransientDeviceActivityEntrySecs = 900; -static const int kMapSizeTrimDownAggregationEntry = 200; - -void AttributionProcessor::OnBtaaPackets(std::vector btaa_packets) { - AddressActivityKey key; - - for (auto& btaa_packet : btaa_packets) { - key.address = btaa_packet.address; - key.activity = btaa_packet.activity; - - if (wakelock_duration_aggregator_.find(key) == wakelock_duration_aggregator_.end()) { - wakelock_duration_aggregator_[key] = {}; - } - wakelock_duration_aggregator_[key].byte_count += btaa_packet.byte_count; - - if (wakeup_) { - wakelock_duration_aggregator_[key].wakeup_count += 1; - device_wakeup_aggregator_.Push(std::move(DeviceWakeupDescriptor(btaa_packet.activity, btaa_packet.address))); - std::string package_info = kUnknownPackageInfo; - std::string address = btaa_packet.address.ToString(); - if (address_app_map_.find(address) != address_app_map_.end()) { - package_info = address_app_map_[address]; - } - app_wakeup_aggregator_.Push(std::move(AppWakeupDescriptor(btaa_packet.activity, package_info))); - } - } - wakeup_ = false; -} - -void AttributionProcessor::OnWakelockReleased(uint32_t duration_ms) { - uint32_t total_byte_count = 0; - - for (auto& it : wakelock_duration_aggregator_) { - total_byte_count += it.second.byte_count; - } - - if (total_byte_count == 0) { - return; - } - - auto cur_time = now_func_(); - for (auto& it : wakelock_duration_aggregator_) { - it.second.wakelock_duration_ms = (uint64_t)duration_ms * it.second.byte_count / total_byte_count; - if (btaa_aggregator_.find(it.first) == btaa_aggregator_.end()) { - btaa_aggregator_[it.first] = {}; - btaa_aggregator_[it.first].creation_time = cur_time; - } - - auto elapsed_time_sec = - std::chrono::duration_cast(cur_time - btaa_aggregator_[it.first].creation_time).count(); - if (elapsed_time_sec > kDurationToKeepDeviceActivityEntrySecs) { - btaa_aggregator_[it.first].wakeup_count = 0; - btaa_aggregator_[it.first].byte_count = 0; - btaa_aggregator_[it.first].wakelock_duration_ms = 0; - btaa_aggregator_[it.first].creation_time = cur_time; - } - - btaa_aggregator_[it.first].wakeup_count += it.second.wakeup_count; - btaa_aggregator_[it.first].byte_count += it.second.byte_count; - btaa_aggregator_[it.first].wakelock_duration_ms += it.second.wakelock_duration_ms; - - std::string address = it.first.address.ToString(); - std::string package_info = kUnknownPackageInfo; - if (address_app_map_.find(address) != address_app_map_.end()) { - package_info = address_app_map_[address]; - } - AppActivityKey key; - key.app = package_info; - key.activity = it.first.activity; - - if (app_activity_aggregator_.find(key) == app_activity_aggregator_.end()) { - app_activity_aggregator_[key] = {}; - app_activity_aggregator_[key].creation_time = cur_time; - } - - elapsed_time_sec = - std::chrono::duration_cast(cur_time - app_activity_aggregator_[key].creation_time) - .count(); - if (elapsed_time_sec > kDurationToKeepDeviceActivityEntrySecs) { - app_activity_aggregator_[key].wakeup_count = 0; - app_activity_aggregator_[key].byte_count = 0; - app_activity_aggregator_[key].wakelock_duration_ms = 0; - app_activity_aggregator_[key].creation_time = cur_time; - } - - app_activity_aggregator_[key].wakeup_count += it.second.wakeup_count; - app_activity_aggregator_[key].byte_count += it.second.byte_count; - app_activity_aggregator_[key].wakelock_duration_ms += it.second.wakelock_duration_ms; - } - wakelock_duration_aggregator_.clear(); - - if (btaa_aggregator_.size() <= kMapSizeTrimDownAggregationEntry && - app_activity_aggregator_.size() <= kMapSizeTrimDownAggregationEntry) { - return; - } - // Trim down the transient entries in the aggregator to avoid that it overgrows - if (btaa_aggregator_.size() > kMapSizeTrimDownAggregationEntry) { - auto it = btaa_aggregator_.begin(); - while (it != btaa_aggregator_.end()) { - auto elapsed_time_sec = - std::chrono::duration_cast(cur_time - it->second.creation_time).count(); - if (elapsed_time_sec > kDurationTransientDeviceActivityEntrySecs && - it->second.byte_count < kByteCountTransientDeviceActivityEntry) { - it = btaa_aggregator_.erase(it); - } else { - it++; - } - } - } - - if (app_activity_aggregator_.size() > kMapSizeTrimDownAggregationEntry) { - auto it = app_activity_aggregator_.begin(); - while (it != app_activity_aggregator_.end()) { - auto elapsed_time_sec = - std::chrono::duration_cast(cur_time - it->second.creation_time).count(); - if (elapsed_time_sec > kDurationTransientDeviceActivityEntrySecs && - it->second.byte_count < kByteCountTransientDeviceActivityEntry) { - it = app_activity_aggregator_.erase(it); - } else { - it++; - } - } - } -} - -void AttributionProcessor::OnWakeup() { - if (wakeup_) { - LOG_INFO("Previous wakeup notification is not consumed."); - } - wakeup_ = true; -} - -void AttributionProcessor::NotifyActivityAttributionInfo( - int uid, const std::string& package_name, const std::string& device_address) { - if (address_app_map_.size() > kMapSizeTrimDownAggregationEntry) { - LOG_INFO("The map from device address and app info overflows."); - return; - } - address_app_map_[device_address] = package_name + "/" + std::to_string(uid); -} - -void AttributionProcessor::Dump( - std::promise> promise, flatbuffers::FlatBufferBuilder* fb_builder) { - // Dump device-based wakeup attribution data - auto title_device_wakeup = fb_builder->CreateString("----- Device-based Wakeup Attribution Dumpsys -----"); - std::vector> device_wakeup_aggregator = - device_wakeup_aggregator_.Pull(); - std::vector> device_wakeup_entry_offsets; - for (auto& it : device_wakeup_aggregator) { - WakeupEntryBuilder wakeup_entry_builder(*fb_builder); - std::chrono::milliseconds duration(it.timestamp); - std::chrono::time_point wakeup_time(duration); - wakeup_entry_builder.add_wakeup_time(fb_builder->CreateString( - bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, wakeup_time).c_str())); - wakeup_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.entry.activity_)))); - wakeup_entry_builder.add_address(fb_builder->CreateString(it.entry.address_.ToString())); - device_wakeup_entry_offsets.push_back(wakeup_entry_builder.Finish()); - } - auto device_wakeup_entries = fb_builder->CreateVector(device_wakeup_entry_offsets); - - // Dump device-based activity aggregation data - auto title_device_activity = fb_builder->CreateString("----- Device-based Activity Attribution Dumpsys -----"); - std::vector> device_aggregation_entry_offsets; - for (auto& it : btaa_aggregator_) { - ActivityAggregationEntryBuilder device_entry_builder(*fb_builder); - device_entry_builder.add_address(fb_builder->CreateString(it.first.address.ToString())); - device_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.first.activity)))); - device_entry_builder.add_wakeup_count(it.second.wakeup_count); - device_entry_builder.add_byte_count(it.second.byte_count); - device_entry_builder.add_wakelock_duration_ms(it.second.wakelock_duration_ms); - device_entry_builder.add_creation_time(fb_builder->CreateString( - bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, it.second.creation_time) - .c_str())); - device_aggregation_entry_offsets.push_back(device_entry_builder.Finish()); - } - auto device_aggregation_entries = fb_builder->CreateVector(device_aggregation_entry_offsets); - - // Dump App-based wakeup attribution data - auto title_app_wakeup = fb_builder->CreateString("----- App-based Wakeup Attribution Dumpsys -----"); - std::vector> app_wakeup_aggregator = app_wakeup_aggregator_.Pull(); - std::vector> app_wakeup_entry_offsets; - for (auto& it : app_wakeup_aggregator) { - WakeupEntryBuilder wakeup_entry_builder(*fb_builder); - std::chrono::milliseconds duration(it.timestamp); - std::chrono::time_point wakeup_time(duration); - wakeup_entry_builder.add_wakeup_time(fb_builder->CreateString( - bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, wakeup_time).c_str())); - wakeup_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.entry.activity_)))); - wakeup_entry_builder.add_package_info(fb_builder->CreateString(it.entry.package_info_)); - app_wakeup_entry_offsets.push_back(wakeup_entry_builder.Finish()); - } - auto app_wakeup_entries = fb_builder->CreateVector(app_wakeup_entry_offsets); - - // Dump app-based activity aggregation data - auto title_app_activity = fb_builder->CreateString("----- App-based Activity Attribution Dumpsys -----"); - std::vector> app_aggregation_entry_offsets; - for (auto& it : app_activity_aggregator_) { - ActivityAggregationEntryBuilder app_entry_builder(*fb_builder); - app_entry_builder.add_package_info(fb_builder->CreateString(it.first.app)); - app_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.first.activity)))); - app_entry_builder.add_wakeup_count(it.second.wakeup_count); - app_entry_builder.add_byte_count(it.second.byte_count); - app_entry_builder.add_wakelock_duration_ms(it.second.wakelock_duration_ms); - app_entry_builder.add_creation_time(fb_builder->CreateString( - bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, it.second.creation_time) - .c_str())); - app_aggregation_entry_offsets.push_back(app_entry_builder.Finish()); - } - auto app_aggregation_entries = fb_builder->CreateVector(app_aggregation_entry_offsets); - - ActivityAttributionDataBuilder builder(*fb_builder); - builder.add_title_device_wakeup(title_device_wakeup); - builder.add_num_device_wakeup(device_wakeup_aggregator.size()); - builder.add_device_wakeup_attribution(device_wakeup_entries); - builder.add_title_device_activity(title_device_activity); - builder.add_num_device_activity(btaa_aggregator_.size()); - builder.add_device_activity_aggregation(device_aggregation_entries); - btaa_aggregator_.clear(); - - builder.add_title_app_wakeup(title_app_wakeup); - builder.add_num_app_wakeup(app_wakeup_aggregator.size()); - builder.add_app_wakeup_attribution(app_wakeup_entries); - builder.add_title_app_activity(title_app_activity); - builder.add_num_app_activity(app_activity_aggregator_.size()); - builder.add_app_activity_aggregation(app_aggregation_entries); - app_activity_aggregator_.clear(); - - flatbuffers::Offset dumpsys_data = builder.Finish(); - promise.set_value(dumpsys_data); -} - -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - -const char* AttributionProcessor::ActivityToString(Activity activity) { - switch (activity) { - CASE_RETURN_TEXT(Activity::ACL); - CASE_RETURN_TEXT(Activity::ADVERTISE); - CASE_RETURN_TEXT(Activity::CONNECT); - CASE_RETURN_TEXT(Activity::CONTROL); - CASE_RETURN_TEXT(Activity::HFP); - CASE_RETURN_TEXT(Activity::ISO); - CASE_RETURN_TEXT(Activity::SCAN); - CASE_RETURN_TEXT(Activity::VENDOR); - default: - return "UNKNOWN"; - } -} - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/linux_generic/attribution_processor_tests.cc b/system/gd/btaa/linux_generic/attribution_processor_tests.cc deleted file mode 100644 index 1a27206190f31977547de3f3a5a70ce36f516223..0000000000000000000000000000000000000000 --- a/system/gd/btaa/linux_generic/attribution_processor_tests.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include "btaa/activity_attribution.h" -#include "btaa/attribution_processor.h" - -using bluetooth::hci::Address; -using namespace bluetooth::activity_attribution; -using namespace std::chrono; - -// mock for std::chrono::system_clock::now -static AttributionProcessor::ClockType now_ret_val; -static AttributionProcessor::ClockType fake_now() { - return now_ret_val; -} - -class AttributionProcessorTest : public ::testing::Test { - protected: - void SetUp() override { - pAttProc = std::make_unique(fake_now); - } - void TearDown() override { - pAttProc.reset(); - } - - std::unique_ptr pAttProc; -}; - -static void fake_now_set_current() { - now_ret_val = system_clock::now(); -} - -static void fake_now_advance_1000sec() { - now_ret_val += seconds(1000s); -} - -TEST_F(AttributionProcessorTest, UAFInOnWakelockReleasedRegressionTest) { - std::vector btaaPackets; - Address addr; - - fake_now_set_current(); - - // setup the condition 1 for triggering erase operation - // add 220 entries in app_activity_aggregator_ - // and btaa_aggregator_ - for (int i = 0; i < 220; i++) { - std::string addrStr = base::StringPrintf("21:43:65:87:a9:%02x", i + 10); - ASSERT_TRUE(Address::FromString(addrStr, addr)); - BtaaHciPacket packet(Activity::ACL, addr, 30 * i); - btaaPackets.push_back(packet); - pAttProc->NotifyActivityAttributionInfo(i + 1000, "com.test.app" + std::to_string(i), addrStr); - } - - pAttProc->OnBtaaPackets(btaaPackets); - pAttProc->OnWakelockReleased(100); - - // setup the condition 2 for triggering erase operation - // make elapsed_time_sec > 900s - fake_now_advance_1000sec(); - - pAttProc->OnBtaaPackets(btaaPackets); - pAttProc->OnWakelockReleased(100); -} diff --git a/system/gd/btaa/linux_generic/cmd_evt_classification.cc b/system/gd/btaa/linux_generic/cmd_evt_classification.cc deleted file mode 100644 index 60fc5660daa6607c00cc31de06e5ec6dd443f449..0000000000000000000000000000000000000000 --- a/system/gd/btaa/linux_generic/cmd_evt_classification.cc +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "btaa/cmd_evt_classification.h" - -namespace bluetooth { -namespace activity_attribution { - -CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode) { - CmdEvtActivityClassification classification = {}; - switch (opcode) { - case hci::OpCode::INQUIRY: - case hci::OpCode::INQUIRY_CANCEL: - case hci::OpCode::PERIODIC_INQUIRY_MODE: - case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0}; - break; - - case hci::OpCode::CREATE_CONNECTION: - case hci::OpCode::CREATE_CONNECTION_CANCEL: - case hci::OpCode::ACCEPT_CONNECTION_REQUEST: - case hci::OpCode::LINK_KEY_REQUEST_REPLY: - case hci::OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY: - case hci::OpCode::PIN_CODE_REQUEST_REPLY: - case hci::OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY: - case hci::OpCode::REJECT_CONNECTION_REQUEST: - case hci::OpCode::REMOTE_NAME_REQUEST: - case hci::OpCode::REMOTE_NAME_REQUEST_CANCEL: - case hci::OpCode::ACCEPT_SYNCHRONOUS_CONNECTION: - case hci::OpCode::REJECT_SYNCHRONOUS_CONNECTION: - case hci::OpCode::IO_CAPABILITY_REQUEST_REPLY: - case hci::OpCode::USER_CONFIRMATION_REQUEST_REPLY: - case hci::OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY: - case hci::OpCode::USER_PASSKEY_REQUEST_REPLY: - case hci::OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY: - case hci::OpCode::REMOTE_OOB_DATA_REQUEST_REPLY: - case hci::OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY: - case hci::OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY: - case hci::OpCode::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION: - case hci::OpCode::REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY: - case hci::OpCode::SWITCH_ROLE: - case hci::OpCode::READ_STORED_LINK_KEY: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 3}; - break; - - case hci::OpCode::CENTRAL_LINK_KEY: - case hci::OpCode::READ_DEFAULT_LINK_POLICY_SETTINGS: - case hci::OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS: - case hci::OpCode::WRITE_SCAN_ENABLE: - case hci::OpCode::READ_PAGE_SCAN_ACTIVITY: - case hci::OpCode::WRITE_PAGE_SCAN_ACTIVITY: - case hci::OpCode::READ_PAGE_SCAN_TYPE: - case hci::OpCode::WRITE_PAGE_SCAN_TYPE: - case hci::OpCode::READ_SIMPLE_PAIRING_MODE: - case hci::OpCode::WRITE_SIMPLE_PAIRING_MODE: - case hci::OpCode::READ_SCAN_ENABLE: - case hci::OpCode::LE_CREATE_CONNECTION_CANCEL: - case hci::OpCode::LE_READ_FILTER_ACCEPT_LIST_SIZE: - case hci::OpCode::LE_CLEAR_FILTER_ACCEPT_LIST: - case hci::OpCode::SEND_KEYPRESS_NOTIFICATION: - case hci::OpCode::LE_CLEAR_RESOLVING_LIST: - case hci::OpCode::LE_READ_RESOLVING_LIST_SIZE: - case hci::OpCode::LE_SET_HOST_CHANNEL_CLASSIFICATION: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 0}; - break; - - case hci::OpCode::DISCONNECT: - case hci::OpCode::CHANGE_CONNECTION_PACKET_TYPE: - case hci::OpCode::AUTHENTICATION_REQUESTED: - case hci::OpCode::SET_CONNECTION_ENCRYPTION: - case hci::OpCode::CHANGE_CONNECTION_LINK_KEY: - case hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES: - case hci::OpCode::READ_REMOTE_EXTENDED_FEATURES: - case hci::OpCode::READ_REMOTE_VERSION_INFORMATION: - case hci::OpCode::READ_CLOCK_OFFSET: - case hci::OpCode::READ_LMP_HANDLE: - case hci::OpCode::SETUP_SYNCHRONOUS_CONNECTION: - case hci::OpCode::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION: - case hci::OpCode::HOLD_MODE: - case hci::OpCode::SNIFF_MODE: - case hci::OpCode::EXIT_SNIFF_MODE: - case hci::OpCode::QOS_SETUP: - case hci::OpCode::ROLE_DISCOVERY: - case hci::OpCode::READ_LINK_POLICY_SETTINGS: - case hci::OpCode::WRITE_LINK_POLICY_SETTINGS: - case hci::OpCode::FLOW_SPECIFICATION: - case hci::OpCode::SNIFF_SUBRATING: - case hci::OpCode::FLUSH: - case hci::OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT: - case hci::OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT: - case hci::OpCode::READ_LINK_SUPERVISION_TIMEOUT: - case hci::OpCode::WRITE_LINK_SUPERVISION_TIMEOUT: - case hci::OpCode::REFRESH_ENCRYPTION_KEY: - case hci::OpCode::READ_FAILED_CONTACT_COUNTER: - case hci::OpCode::RESET_FAILED_CONTACT_COUNTER: - case hci::OpCode::READ_LINK_QUALITY: - case hci::OpCode::READ_RSSI: - case hci::OpCode::READ_AFH_CHANNEL_MAP: - case hci::OpCode::READ_CLOCK: - case hci::OpCode::READ_ENCRYPTION_KEY_SIZE: - // READ_LOOPBACK_MODE = 0x1801, - // WRITE_LOOPBACK_MODE = 0x1802, - // ENABLE_DEVICE_UNDER_TEST_MODE = 0x1803, - // WRITE_SIMPLE_PAIRING_DEBUG_MODE = 0x1804, - // WRITE_SECURE_CONNECTIONS_TEST_MODE = 0x180a, - case hci::OpCode::ENHANCED_FLUSH: - case hci::OpCode::LE_CONNECTION_UPDATE: - case hci::OpCode::LE_START_ENCRYPTION: - case hci::OpCode::LE_LONG_TERM_KEY_REQUEST_REPLY: - case hci::OpCode::LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY: - case hci::OpCode::LE_READ_PHY: - case hci::OpCode::LE_SET_PHY: - case hci::OpCode::LE_READ_REMOTE_FEATURES: - case hci::OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY: - case hci::OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY: - case hci::OpCode::LE_SET_DATA_LENGTH: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0}; - break; - - case hci::OpCode::SET_EVENT_MASK: - case hci::OpCode::RESET: - case hci::OpCode::SET_EVENT_FILTER: - case hci::OpCode::READ_PIN_TYPE: - case hci::OpCode::WRITE_PIN_TYPE: - case hci::OpCode::WRITE_LOCAL_NAME: - case hci::OpCode::READ_LOCAL_NAME: - case hci::OpCode::READ_CONNECTION_ACCEPT_TIMEOUT: - case hci::OpCode::WRITE_CONNECTION_ACCEPT_TIMEOUT: - case hci::OpCode::READ_PAGE_TIMEOUT: - case hci::OpCode::WRITE_PAGE_TIMEOUT: - case hci::OpCode::READ_AUTHENTICATION_ENABLE: - case hci::OpCode::WRITE_AUTHENTICATION_ENABLE: - case hci::OpCode::READ_CLASS_OF_DEVICE: - case hci::OpCode::WRITE_CLASS_OF_DEVICE: - case hci::OpCode::READ_VOICE_SETTING: - case hci::OpCode::WRITE_VOICE_SETTING: - case hci::OpCode::READ_NUM_BROADCAST_RETRANSMITS: - case hci::OpCode::WRITE_NUM_BROADCAST_RETRANSMITS: - case hci::OpCode::READ_HOLD_MODE_ACTIVITY: - case hci::OpCode::WRITE_HOLD_MODE_ACTIVITY: - case hci::OpCode::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE: - case hci::OpCode::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE: - case hci::OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL: - case hci::OpCode::HOST_BUFFER_SIZE: - case hci::OpCode::HOST_NUMBER_OF_COMPLETED_PACKETS: - case hci::OpCode::READ_NUMBER_OF_SUPPORTED_IAC: - case hci::OpCode::READ_CURRENT_IAC_LAP: - case hci::OpCode::WRITE_CURRENT_IAC_LAP: - case hci::OpCode::SET_AFH_HOST_CHANNEL_CLASSIFICATION: - case hci::OpCode::READ_AFH_CHANNEL_ASSESSMENT_MODE: - case hci::OpCode::WRITE_AFH_CHANNEL_ASSESSMENT_MODE: - case hci::OpCode::READ_LE_HOST_SUPPORT: - case hci::OpCode::WRITE_LE_HOST_SUPPORT: - case hci::OpCode::READ_SECURE_CONNECTIONS_HOST_SUPPORT: - case hci::OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT: - case hci::OpCode::READ_LOCAL_OOB_EXTENDED_DATA: - case hci::OpCode::SET_ECOSYSTEM_BASE_INTERVAL: - case hci::OpCode::CONFIGURE_DATA_PATH: - case hci::OpCode::READ_LOCAL_VERSION_INFORMATION: - case hci::OpCode::READ_LOCAL_SUPPORTED_COMMANDS: - case hci::OpCode::READ_LOCAL_SUPPORTED_FEATURES: - case hci::OpCode::READ_LOCAL_EXTENDED_FEATURES: - case hci::OpCode::READ_BUFFER_SIZE: - case hci::OpCode::READ_BD_ADDR: - case hci::OpCode::READ_DATA_BLOCK_SIZE: - case hci::OpCode::READ_LOCAL_SUPPORTED_CODECS_V1: - case hci::OpCode::READ_LOCAL_SUPPORTED_CODECS_V2: - case hci::OpCode::READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES: - case hci::OpCode::READ_LOCAL_SUPPORTED_CONTROLLER_DELAY: - case hci::OpCode::READ_LOCAL_OOB_DATA: - case hci::OpCode::LE_GENERATE_DHKEY_V2: - case hci::OpCode::LE_MODIFY_SLEEP_CLOCK_ACCURACY: - case hci::OpCode::LE_READ_BUFFER_SIZE_V2: - case hci::OpCode::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH: - case hci::OpCode::LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH: - case hci::OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY: - case hci::OpCode::LE_GENERATE_DHKEY_V1: - case hci::OpCode::LE_SET_EVENT_MASK: - case hci::OpCode::LE_READ_BUFFER_SIZE_V1: - case hci::OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES: - case hci::OpCode::LE_SET_RANDOM_ADDRESS: - case hci::OpCode::LE_READ_TRANSMIT_POWER: - case hci::OpCode::LE_READ_RF_PATH_COMPENSATION_POWER: - case hci::OpCode::LE_WRITE_RF_PATH_COMPENSATION_POWER: - case hci::OpCode::LE_SET_DEFAULT_PHY: - case hci::OpCode::LE_ENCRYPT: - case hci::OpCode::LE_RAND: - case hci::OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE: - case hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT: - case hci::OpCode::LE_READ_MAXIMUM_DATA_LENGTH: - case hci::OpCode::LE_READ_SUPPORTED_STATES: - classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 0}; - break; - - case hci::OpCode::DELETE_STORED_LINK_KEY: - classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 3}; - break; - case hci::OpCode::READ_TRANSMIT_POWER_LEVEL: - classification = {.activity = Activity::CONTROL, .connection_handle_pos = 3, .address_pos = 0}; - break; - - case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY: - case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY: - case hci::OpCode::READ_INQUIRY_SCAN_TYPE: - case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE: - case hci::OpCode::READ_INQUIRY_MODE: - case hci::OpCode::WRITE_INQUIRY_MODE: - case hci::OpCode::READ_EXTENDED_INQUIRY_RESPONSE: - case hci::OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE: - case hci::OpCode::LE_SET_CIG_PARAMETERS: - case hci::OpCode::LE_CREATE_CIS: - case hci::OpCode::LE_REMOVE_CIG: - case hci::OpCode::LE_ACCEPT_CIS_REQUEST: - case hci::OpCode::LE_REJECT_CIS_REQUEST: - case hci::OpCode::LE_CREATE_BIG: - case hci::OpCode::LE_TERMINATE_BIG: - case hci::OpCode::LE_BIG_CREATE_SYNC: - case hci::OpCode::LE_BIG_TERMINATE_SYNC: - case hci::OpCode::LE_REQUEST_PEER_SCA: - case hci::OpCode::LE_SETUP_ISO_DATA_PATH: - case hci::OpCode::LE_REMOVE_ISO_DATA_PATH: - case hci::OpCode::LE_SET_HOST_FEATURE: - case hci::OpCode::LE_READ_ISO_LINK_QUALITY: - case hci::OpCode::LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL: - case hci::OpCode::LE_READ_REMOTE_TRANSMIT_POWER_LEVEL: - case hci::OpCode::LE_SET_PATH_LOSS_REPORTING_PARAMETERS: - case hci::OpCode::LE_SET_PATH_LOSS_REPORTING_ENABLE: - case hci::OpCode::LE_SET_TRANSMIT_POWER_REPORTING_ENABLE: - case hci::OpCode::LE_GET_VENDOR_CAPABILITIES: - case hci::OpCode::LE_MULTI_ADVT: - case hci::OpCode::LE_BATCH_SCAN: - case hci::OpCode::LE_ADV_FILTER: - case hci::OpCode::LE_ENERGY_INFO: - case hci::OpCode::LE_EXTENDED_SCAN_PARAMS: - case hci::OpCode::CONTROLLER_DEBUG_INFO: - case hci::OpCode::CONTROLLER_A2DP_OPCODE: - case hci::OpCode::CONTROLLER_BQR: - case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL: - case hci::OpCode::WRITE_INQUIRY_TRANSMIT_POWER_LEVEL: - case hci::OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS: - case hci::OpCode::LE_SET_EXTENDED_SCAN_ENABLE: - case hci::OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL: - case hci::OpCode::LE_SET_SCAN_PARAMETERS: - case hci::OpCode::LE_SET_SCAN_ENABLE: - case hci::OpCode::LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS: - case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE: - case hci::OpCode::LE_CLEAR_PERIODIC_ADVERTISER_LIST: - case hci::OpCode::LE_READ_PERIODIC_ADVERTISER_LIST_SIZE: - case hci::OpCode::LE_PERIODIC_ADVERTISING_TERMINATE_SYNC: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0}; - break; - - case hci::OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER: - case hci::OpCode::LE_SET_ADVERTISING_DATA: - case hci::OpCode::LE_SET_SCAN_RESPONSE_DATA: - case hci::OpCode::LE_SET_ADVERTISING_ENABLE: - case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_DATA: - case hci::OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA: - case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE: - case hci::OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH: - case hci::OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS: - case hci::OpCode::LE_REMOVE_ADVERTISING_SET: - case hci::OpCode::LE_CLEAR_ADVERTISING_SETS: - case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_PARAMETERS: - case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_DATA: - case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE: - case hci::OpCode::LE_SET_ADVERTISING_SET_RANDOM_ADDRESS: - classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 0}; - break; - - case hci::OpCode::LE_SET_ADVERTISING_PARAMETERS: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 10}; - break; - case hci::OpCode::LE_CREATE_CONNECTION: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 9}; - break; - case hci::OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST: - case hci::OpCode::LE_READ_CHANNEL_MAP: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 0}; - break; - - case hci::OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST: - case hci::OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST: - case hci::OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST: - case hci::OpCode::LE_READ_PEER_RESOLVABLE_ADDRESS: - case hci::OpCode::LE_READ_LOCAL_RESOLVABLE_ADDRESS: - case hci::OpCode::LE_SET_PRIVACY_MODE: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 4}; - break; - - case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS: - classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 15}; - break; - case hci::OpCode::LE_EXTENDED_CREATE_CONNECTION: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 6}; - break; - case hci::OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 6}; - break; - case hci::OpCode::LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST: - case hci::OpCode::LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 4}; - break; - case hci::OpCode::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER: - case hci::OpCode::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER: - case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 3, .address_pos = 0}; - break; - - default: - classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0}; - break; - } - return classification; -} - -CmdEvtActivityClassification lookup_event(hci::EventCode event_code) { - CmdEvtActivityClassification classification = {}; - switch (event_code) { - case hci::EventCode::INQUIRY_COMPLETE: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0}; - break; - case hci::EventCode::CONNECTION_COMPLETE: - case hci::EventCode::SYNCHRONOUS_CONNECTION_COMPLETE: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 5}; - break; - - case hci::EventCode::CONNECTION_REQUEST: - case hci::EventCode::PIN_CODE_REQUEST: - case hci::EventCode::LINK_KEY_REQUEST: - case hci::EventCode::LINK_KEY_NOTIFICATION: - case hci::EventCode::USER_PASSKEY_NOTIFICATION: - case hci::EventCode::KEYPRESS_NOTIFICATION: - case hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION: - case hci::EventCode::IO_CAPABILITY_REQUEST: - case hci::EventCode::IO_CAPABILITY_RESPONSE: - case hci::EventCode::USER_CONFIRMATION_REQUEST: - case hci::EventCode::USER_PASSKEY_REQUEST: - case hci::EventCode::REMOTE_OOB_DATA_REQUEST: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 2}; - break; - - case hci::EventCode::DISCONNECTION_COMPLETE: - case hci::EventCode::AUTHENTICATION_COMPLETE: - case hci::EventCode::ENCRYPTION_CHANGE: - case hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE: - case hci::EventCode::LINK_SUPERVISION_TIMEOUT_CHANGED: - case hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE: - case hci::EventCode::CENTRAL_LINK_KEY_COMPLETE: - case hci::EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE: - case hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE: - case hci::EventCode::QOS_SETUP_COMPLETE: - case hci::EventCode::MODE_CHANGE: - case hci::EventCode::READ_CLOCK_OFFSET_COMPLETE: - case hci::EventCode::CONNECTION_PACKET_TYPE_CHANGED: - case hci::EventCode::FLOW_SPECIFICATION_COMPLETE: - case hci::EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE: - case hci::EventCode::SYNCHRONOUS_CONNECTION_CHANGED: - case hci::EventCode::SNIFF_SUBRATING: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0}; - break; - - case hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE: - case hci::EventCode::EXTENDED_INQUIRY_RESULT: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 3}; - break; - case hci::EventCode::FLUSH_OCCURRED: - case hci::EventCode::MAX_SLOTS_CHANGE: - case hci::EventCode::QOS_VIOLATION: - case hci::EventCode::ENHANCED_FLUSH_COMPLETE: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 2, .address_pos = 0}; - break; - case hci::EventCode::ROLE_CHANGE: - case hci::EventCode::SIMPLE_PAIRING_COMPLETE: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 3}; - break; - case hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 2}; - break; - - default: - classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0}; - } - return classification; -} - -CmdEvtActivityClassification lookup_le_event(hci::SubeventCode subevent_code) { - CmdEvtActivityClassification classification = {}; - switch (subevent_code) { - case hci::SubeventCode::CONNECTION_COMPLETE: - case hci::SubeventCode::ENHANCED_CONNECTION_COMPLETE: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 7}; - break; - - case hci::SubeventCode::CONNECTION_UPDATE_COMPLETE: - case hci::SubeventCode::READ_REMOTE_FEATURES_COMPLETE: - case hci::SubeventCode::PHY_UPDATE_COMPLETE: - case hci::SubeventCode::CTE_REQUEST_FAILED: - case hci::SubeventCode::TRANSMIT_POWER_REPORTING: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 0}; - break; - - case hci::SubeventCode::LONG_TERM_KEY_REQUEST: - case hci::SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST: - case hci::SubeventCode::DATA_LENGTH_CHANGE: - case hci::SubeventCode::CHANNEL_SELECTION_ALGORITHM: - case hci::SubeventCode::CONNECTION_IQ_REPORT: - case hci::SubeventCode::PATH_LOSS_THRESHOLD: - classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0}; - break; - - case hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE: - case hci::SubeventCode::GENERATE_DHKEY_COMPLETE: - classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 0}; - break; - - case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED: - case hci::SubeventCode::PERIODIC_ADVERTISING_REPORT: - case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST: - case hci::SubeventCode::ADVERTISING_SET_TERMINATED: - classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 0}; - break; - - case hci::SubeventCode::SCAN_TIMEOUT: - case hci::SubeventCode::BIG_INFO_ADVERTISING_REPORT: - case hci::SubeventCode::CONNECTIONLESS_IQ_REPORT: - case hci::SubeventCode::CREATE_BIG_COMPLETE: - case hci::SubeventCode::TERMINATE_BIG_COMPLETE: - case hci::SubeventCode::BIG_SYNC_ESTABLISHED: - case hci::SubeventCode::BIG_SYNC_LOST: - case hci::SubeventCode::REQUEST_PEER_SCA_COMPLETE: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0}; - break; - - case hci::SubeventCode::SCAN_REQUEST_RECEIVED: - classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 5}; - break; - - case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED: - case hci::SubeventCode::CIS_ESTABLISHED: - case hci::SubeventCode::CIS_REQUEST: - classification = {.activity = Activity::SCAN, .connection_handle_pos = 4, .address_pos = 0}; - break; - - default: - classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0}; - } - return classification; -} - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/linux_generic/hci_processor.cc b/system/gd/btaa/linux_generic/hci_processor.cc deleted file mode 100644 index 28c1e70b19ae01ce5e70f830bcaa21631c3f8e18..0000000000000000000000000000000000000000 --- a/system/gd/btaa/linux_generic/hci_processor.cc +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "btaa/hci_processor.h" - -#include "os/log.h" - -namespace bluetooth { -namespace activity_attribution { - -void DeviceParser::match_handle_with_address(uint16_t connection_handle, hci::Address& address) { - if (connection_handle && !address.IsEmpty()) { - connection_lookup_table_[connection_handle] = address; - } else if (connection_handle) { - if (connection_lookup_table_.find(connection_handle) != connection_lookup_table_.end()) { - address = connection_lookup_table_[connection_handle]; - } - } -} - -void HciProcessor::process_le_event( - std::vector& btaa_hci_packets, int16_t byte_count, hci::EventView& event) { - uint16_t connection_handle_value = 0; - hci::Address address_value; - - auto le_packet_view = hci::LeMetaEventView::Create(event); - if (!le_packet_view.IsValid()) { - return; - } - - auto subevent_code = le_packet_view.GetSubeventCode(); - auto le_event_info = lookup_le_event(subevent_code); - - if (le_event_info.activity != Activity::UNKNOWN) { - // lookup_le_event returns all simple classic event which does not require additional processing. - if (le_event_info.connection_handle_pos) { - auto connection_handle_it = event.begin() + le_event_info.connection_handle_pos; - connection_handle_value = connection_handle_it.extract(); - } - if (le_event_info.address_pos) { - auto address_value_it = event.begin() + le_event_info.address_pos; - address_value = address_value_it.extract(); - } - device_parser_.match_handle_with_address(connection_handle_value, address_value); - btaa_hci_packets.push_back(BtaaHciPacket(le_event_info.activity, address_value, byte_count)); - } -} - -void HciProcessor::process_special_event( - std::vector& btaa_hci_packets, - hci::EventCode event_code, - uint16_t byte_count, - hci::EventView& event) { - uint16_t avg_byte_count; - hci::Address address_value; - - switch (event_code) { - case hci::EventCode::INQUIRY_RESULT: - case hci::EventCode::INQUIRY_RESULT_WITH_RSSI: { - auto packet_view = hci::InquiryResultView::Create(event); - if (!packet_view.IsValid()) { - return; - } - auto inquiry_results = packet_view.GetResponses(); - avg_byte_count = byte_count / inquiry_results.size(); - for (auto& inquiry_result : inquiry_results) { - btaa_hci_packets.push_back(BtaaHciPacket(Activity::SCAN, inquiry_result.bd_addr_, avg_byte_count)); - } - } break; - - case hci::EventCode::NUMBER_OF_COMPLETED_PACKETS: { - auto packet_view = hci::NumberOfCompletedPacketsView::Create(event); - if (!packet_view.IsValid()) { - return; - } - auto completed_packets = packet_view.GetCompletedPackets(); - avg_byte_count = byte_count / completed_packets.size(); - for (auto& completed_packet : completed_packets) { - device_parser_.match_handle_with_address(completed_packet.connection_handle_, address_value); - btaa_hci_packets.push_back(BtaaHciPacket(Activity::CONNECT, address_value, avg_byte_count)); - } - } break; - - case hci::EventCode::RETURN_LINK_KEYS: { - auto packet_view = hci::ReturnLinkKeysView::Create(event); - if (!packet_view.IsValid()) { - return; - } - auto keys_and_addresses = packet_view.GetKeys(); - avg_byte_count = byte_count / keys_and_addresses.size(); - for (auto& key_and_address : keys_and_addresses) { - btaa_hci_packets.push_back(BtaaHciPacket(Activity::CONNECT, key_and_address.address_, avg_byte_count)); - } - } break; - - default: { - btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count)); - } break; - } -} - -void HciProcessor::process_command( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count) { - hci::CommandView command = hci::CommandView::Create(packet_view); - if (!command.IsValid()) { - return; - } - - uint16_t connection_handle_value = 0; - hci::Address address_value; - auto opcode = command.GetOpCode(); - auto cmd_info = lookup_cmd(opcode); - - if (cmd_info.connection_handle_pos) { - auto connection_handle_it = command.begin() + cmd_info.connection_handle_pos; - connection_handle_value = connection_handle_it.extract(); - } - if (cmd_info.address_pos) { - auto address_value_it = command.begin() + cmd_info.address_pos; - address_value = address_value_it.extract(); - } - device_parser_.match_handle_with_address(connection_handle_value, address_value); - pending_command_.btaa_hci_packet = BtaaHciPacket(cmd_info.activity, address_value, byte_count); - - pending_command_.opcode = opcode; -} - -void HciProcessor::process_event( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count) { - hci::EventView event = hci::EventView::Create(packet_view); - if (!event.IsValid()) { - return; - } - - uint16_t connection_handle_value = 0; - hci::Address address_value; - auto event_code = event.GetEventCode(); - auto event_info = lookup_event(event_code); - - if (event_info.activity != Activity::UNKNOWN) { - // lookup_event returns all simple classic event which does not require additional processing. - if (event_info.connection_handle_pos) { - auto connection_handle_it = event.begin() + event_info.connection_handle_pos; - connection_handle_value = connection_handle_it.extract(); - } - if (event_info.address_pos) { - auto address_value_it = event.begin() + event_info.address_pos; - address_value = address_value_it.extract(); - } - device_parser_.match_handle_with_address(connection_handle_value, address_value); - btaa_hci_packets.push_back(BtaaHciPacket(event_info.activity, address_value, byte_count)); - } else { - // The event requires additional processing. - switch (event_code) { - case hci::EventCode::COMMAND_COMPLETE: { - auto packet_view = hci::CommandCompleteView::Create(event); - if (packet_view.IsValid() && packet_view.GetCommandOpCode() == pending_command_.opcode) { - pending_command_.btaa_hci_packet.byte_count += byte_count; - btaa_hci_packets.push_back(std::move(pending_command_.btaa_hci_packet)); - } else { - btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count)); - } - } break; - case hci::EventCode::COMMAND_STATUS: { - auto packet_view = hci::CommandStatusView::Create(event); - if (packet_view.IsValid() && packet_view.GetCommandOpCode() == pending_command_.opcode) { - pending_command_.btaa_hci_packet.byte_count += byte_count; - btaa_hci_packets.push_back(std::move(pending_command_.btaa_hci_packet)); - } else { - btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count)); - } - break; - } - case hci::EventCode::LE_META_EVENT: - process_le_event(btaa_hci_packets, byte_count, event); - break; - case hci::EventCode::VENDOR_SPECIFIC: - btaa_hci_packets.push_back(BtaaHciPacket(Activity::VENDOR, address_value, byte_count)); - break; - default: - process_special_event(btaa_hci_packets, event_code, byte_count, event); - break; - } - } -} - -void HciProcessor::process_acl( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count) { - hci::AclView acl = hci::AclView::Create(packet_view); - auto connection_handle = acl.begin(); - // Connection handle is extracted from the 12 least significant bit. - uint16_t connection_handle_value = connection_handle.extract() & 0xfff; - hci::Address address_value; - device_parser_.match_handle_with_address(connection_handle_value, address_value); - btaa_hci_packets.push_back(BtaaHciPacket(Activity::ACL, address_value, byte_count)); -} - -void HciProcessor::process_sco( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count) { - hci::ScoView sco = hci::ScoView::Create(packet_view); - auto connection_handle = sco.begin(); - // Connection handle is extracted from the 12 least significant bit. - uint16_t connection_handle_value = connection_handle.extract() & 0xfff; - hci::Address address_value; - device_parser_.match_handle_with_address(connection_handle_value, address_value); - btaa_hci_packets.push_back(BtaaHciPacket(Activity::HFP, address_value, byte_count)); -} - -void HciProcessor::process_iso( - std::vector& btaa_hci_packets, - packet::PacketView& packet_view, - uint16_t byte_count) { - hci::IsoView iso = hci::IsoView::Create(packet_view); - auto connection_handle = iso.begin(); - // Connection handle is extracted from the 12 least significant bit. - uint16_t connection_handle_value = connection_handle.extract() & 0xfff; - hci::Address address_value; - device_parser_.match_handle_with_address(connection_handle_value, address_value); - btaa_hci_packets.push_back(BtaaHciPacket(Activity::ISO, address_value, byte_count)); -} - -std::vector HciProcessor::OnHciPacket( - hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) { - std::vector btaa_hci_packets; - auto packet_view = packet::PacketView(std::make_shared>(packet)); - switch (type) { - case hal::SnoopLogger::PacketType::CMD: - process_command(btaa_hci_packets, packet_view, length); - break; - case hal::SnoopLogger::PacketType::EVT: - process_event(btaa_hci_packets, packet_view, length); - break; - case hal::SnoopLogger::PacketType::ACL: - process_acl(btaa_hci_packets, packet_view, length); - break; - case hal::SnoopLogger::PacketType::SCO: - process_sco(btaa_hci_packets, packet_view, length); - break; - case hal::SnoopLogger::PacketType::ISO: - process_iso(btaa_hci_packets, packet_view, length); - break; - } - return btaa_hci_packets; -} - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/btaa/linux_generic/wakelock_processor.cc b/system/gd/btaa/linux_generic/wakelock_processor.cc deleted file mode 100644 index bd3b3edc89c80ded62482fb5ef6e4c0612f7b30b..0000000000000000000000000000000000000000 --- a/system/gd/btaa/linux_generic/wakelock_processor.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "btaa/wakelock_processor.h" - -#include "os/log.h" - -namespace bluetooth { -namespace activity_attribution { - -static const int kWakelockMaxDurationMs(10000); - -WakelockProcessor::WakelockProcessor() { - wakelock_net_count_ = 0; - wakelock_acquired_time_ = {}; -} - -uint32_t WakelockProcessor::OnWakelockReleased() { - auto cur_time = std::chrono::system_clock::now(); - uint32_t wakelock_duration_ms = 0; - - if (wakelock_net_count_ == 0) { - LOG_INFO("Release a never acquired wakelock, ignored."); - } else { - wakelock_net_count_--; - if (wakelock_net_count_ == 0) { - wakelock_duration_ms = static_cast( - std::chrono::duration_cast(cur_time - wakelock_acquired_time_).count()); - wakelock_acquired_time_ = {}; - } - } - - return wakelock_duration_ms; -} - -void WakelockProcessor::OnWakelockAcquired() { - auto cur_time = std::chrono::system_clock::now(); - - if (wakelock_net_count_ == 0) { - if (wakelock_acquired_time_.time_since_epoch().count()) { - LOG_INFO("Previous wakelock acquired time is not consumed, dropped."); - } - wakelock_acquired_time_ = cur_time; - } else if (cur_time - wakelock_acquired_time_ > std::chrono::milliseconds(kWakelockMaxDurationMs)) { - LOG_INFO("Wakelock held for too long, likely we missed a release notification. Resetting wakelock stats."); - wakelock_net_count_ = 0; - wakelock_acquired_time_ = cur_time; - } - - wakelock_net_count_++; -} - -} // namespace activity_attribution -} // namespace bluetooth diff --git a/system/gd/cert/bluetooth_packets_python3_setup.py b/system/gd/cert/bluetooth_packets_python3_setup.py index 6e3657b07090a237225aff69ae65a70fbf1a53f3..26257c6dad0b0fbb901d8548d4124231f51d4249 100644 --- a/system/gd/cert/bluetooth_packets_python3_setup.py +++ b/system/gd/cert/bluetooth_packets_python3_setup.py @@ -32,7 +32,8 @@ ANDROID_BUILD_TOP = os.getenv("ANDROID_BUILD_TOP") PYBIND11_INCLUDE_DIR = os.path.join(ANDROID_BUILD_TOP, "external/python/pybind11/include") GD_DIR = os.path.join(ANDROID_BUILD_TOP, "packages/modules/Bluetooth/system/gd") BT_PACKETS_GEN_DIR = os.path.join( - ANDROID_BUILD_TOP, "out/soong/.intermediates/packages/modules/Bluetooth/system/gd/BluetoothGeneratedPackets_h/gen") + ANDROID_BUILD_TOP, + "out/soong/.intermediates/packages/modules/Bluetooth/system/pdl/l2cap/BluetoothGeneratedPacketsL2cap_h/gen") BT_PACKETS_PY3_GEN_DIR = os.path.join( ANDROID_BUILD_TOP, "out/soong/.intermediates/packages/modules/Bluetooth/system/gd/BluetoothGeneratedPackets_python3_cc/gen") @@ -52,7 +53,6 @@ BT_PACKETS_BASE_SRCS = [ BT_PACKETS_PY3_SRCs = \ [os.path.join(GD_DIR, "packet/python3_module.cc")] \ + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "l2cap", "*.cc")) \ - + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "security", "*.cc")) bluetooth_packets_python3_module = Extension( 'bluetooth_packets_python3', diff --git a/system/gd/cert/run b/system/gd/cert/run index 8fcf22b5161cb7356487b9d255d389d3dfa12c07..7e3db405c9966edd06229bc7fe1d099f5d4c7f7b 100755 --- a/system/gd/cert/run +++ b/system/gd/cert/run @@ -43,7 +43,7 @@ function sad_hedgehog { echo -e "{$NOCOLOR}" } -PYTHON_BIN="python3.10" +PYTHON_BIN="python3.11" function check_environment { if [[ -z "${ANDROID_BUILD_TOP}" ]] || [[ -z "${ANDROID_HOST_OUT}" ]] ; then @@ -60,10 +60,9 @@ function check_environment { echo -e "${RED}You must have ${PYTHON_BIN} installed${NOCOLOR}" exit 1 fi - ${PYTHON_BIN} -m virtualenv --version + ${PYTHON_BIN} -m venv -h > /dev/null if [[ $? -ne 0 ]] ; then - echo -e "${RED}virtualenv not installed for ${PYTHON_BIN}${NOCOLOR}" - echo -e "${RED}Please run '${PYTHON_BIN} -m pip install virtualenv' to install it${NOCOLOR}" + echo -e "${RED}venv not available for ${PYTHON_BIN}${NOCOLOR}" exit 1 fi } @@ -82,8 +81,8 @@ OUT_TARGET="${ANDROID_BUILD_TOP}/out/target" TEST_CONFIG="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/blueberry/tests/gd/host_config.yaml" TEST_FILTER="--presubmit" TEST_RUNNER="blueberry/tests/gd/gd_test_runner.py" -CPP_BUILD_TARGET="bluetooth_stack_with_facade root-canal bluetooth_packets_python3 gd_hci_packets_python3_gen" -RUST_BUILD_TARGET="bluetooth_with_facades root-canal bluetooth_packets_python3 bt_topshim_facade gd_hci_packets_python3_gen" +CPP_BUILD_TARGET="bluetooth_stack_with_facade root-canal bluetooth_packets_python3 gd_hci_packets_python3_gen gd_smp_packets_python3_gen" +RUST_BUILD_TARGET="bluetooth_with_facades root-canal bluetooth_packets_python3 bt_topshim_facade gd_hci_packets_python3_gen gd_smp_packets_python3_gen" BUILD_TARGET=$CPP_BUILD_TARGET CLEAN_VENV=false @@ -319,7 +318,7 @@ function setup_venv { echo -e "${NOCOLOR}" fi fi - ${PYTHON_BIN} -m virtualenv --python `which "${PYTHON_BIN}"` "${CERT_TEST_VENV}" + ${PYTHON_BIN} -m venv --clear "${CERT_TEST_VENV}" if [[ $? -ne 0 ]] ; then echo -e "${RED}Error setting up virtualenv${NOCOLOR}" exit 1 @@ -353,7 +352,6 @@ function incremental_venv { cp {$HOST_LIB,$DEST_LIB_DIR}/libchrome.so cp {$HOST_LIB,$DEST_LIB_DIR}/libcrypto-host.so cp {$HOST_LIB,$DEST_LIB_DIR}/libevent-host.so - cp {$HOST_LIB,$DEST_LIB_DIR}/libgrpc++_unsecure.so cp {$HOST_LIB,$DEST_LIB_DIR}/libgrpc++.so cp {$HOST_LIB,$DEST_LIB_DIR}/libgrpc_wrap.so cp {$HOST_LIB,$DEST_LIB_DIR}/liblog.so diff --git a/system/gd/common/Android.bp b/system/gd/common/Android.bp index ad6d0365b5f985e757938f7b5c9aaf9689f442a4..36da276e450baabec33127d26985911b2955a835 100644 --- a/system/gd/common/Android.bp +++ b/system/gd/common/Android.bp @@ -30,7 +30,6 @@ filegroup { "metric_id_manager_unittest.cc", "multi_priority_queue_test.cc", "numbers_test.cc", - "observer_registry_test.cc", "strings_test.cc", "sync_map_count_test.cc", ], diff --git a/system/gd/common/audit_log.cc b/system/gd/common/audit_log.cc index 07d1b832c4a6868b5ed8bdd23ccc0d7ff6fcb456..686e1120fd71a70fcbcac3476c20a3ac2861127b 100644 --- a/system/gd/common/audit_log.cc +++ b/system/gd/common/audit_log.cc @@ -21,26 +21,29 @@ #include "os/log.h" namespace { -#if defined(__ANDROID__) +#if defined(__ANDROID__) && !defined (FUZZ_TARGET) // Tags for security logging, should be in sync with // frameworks/base/core/java/android/app/admin/SecurityLogTags.logtags constexpr int SEC_TAG_BLUETOOTH_CONNECTION = 210039; -#endif /* defined(__ANDROID__) */ +#endif /* defined(__ANDROID__) && !defined (FUZZ_TARGET) */ } // namespace namespace bluetooth { namespace common { -void LogConnectionAdminAuditEvent(const char* action, const hci::Address& address, hci::ErrorCode status) { -#if defined(__ANDROID__) +void LogConnectionAdminAuditEvent( + [[maybe_unused]] const char* action, + [[maybe_unused]] const hci::Address& address, + [[maybe_unused]] hci::ErrorCode status) { +#if defined(__ANDROID__) && !defined (FUZZ_TARGET) android_log_event_list(SEC_TAG_BLUETOOTH_CONNECTION) << ADDRESS_TO_LOGGABLE_CSTR(address) << /* success */ int32_t(status == hci::ErrorCode::SUCCESS) << common::StringFormat("%s: %s", action, ErrorCodeText(status).c_str()).c_str() << LOG_ID_SECURITY; -#endif /* defined(__ANDROID__) */ +#endif /* defined(__ANDROID__) && !defined (FUZZ_TARGET) */ } } // namespace common diff --git a/system/gd/common/callback_list.h b/system/gd/common/callback_list.h deleted file mode 100644 index 441a5fa3ef3ac2309a2866522daf1a007169ab30..0000000000000000000000000000000000000000 --- a/system/gd/common/callback_list.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include "base/callback_list.h" -#include "os/handler.h" - -/* This file contains CallbackList implementation that will execute callback on provided Handler thread - -Example usage inside your class: - -private: - common::CallbackList callbacks_list_; -public: - std::unique_ptr::Subscription> RegisterCallback( - const base::RepeatingCallback& cb, os::Handler* handler) { - return callbacks_list_.Add({cb, handler}); - } - - void NotifyAllCallbacks(int value) { - callbacks_list_.Notify(value); - } -*/ - -namespace bluetooth { -namespace common { - -namespace { -template -struct CallbackWithHandler { - CallbackWithHandler(base::RepeatingCallback callback, os::Handler* handler) - : callback(callback), handler(handler) {} - - bool is_null() const { - return callback.is_null(); - } - - void Reset() { - callback.Reset(); - } - - base::RepeatingCallback callback; - os::Handler* handler; -}; - -} // namespace - -template -class CallbackList; -template -class CallbackList : public base::internal::CallbackListBase> { - public: - using CallbackType = CallbackWithHandler; - CallbackList() = default; - CallbackList(const CallbackList&) = delete; - CallbackList& operator=(const CallbackList&) = delete; - - template - void Notify(RunArgs&&... args) { - auto it = this->GetIterator(); - CallbackType* cb; - while ((cb = it.GetNext()) != nullptr) { - cb->handler->Post(base::Bind(cb->callback, args...)); - } - } -}; - -} // namespace common -} // namespace bluetooth diff --git a/system/gd/common/contextual_callback.h b/system/gd/common/contextual_callback.h index ba78ed6ba13f04b21341adfe75c40c1f289a5916..af4929663a47bdf7098e5810959d2d202eb2be4c 100644 --- a/system/gd/common/contextual_callback.h +++ b/system/gd/common/contextual_callback.h @@ -16,18 +16,13 @@ #pragma once -#include "common/bind.h" -#include "common/callback.h" +#include "bind.h" +#include "callback.h" +#include "i_postable_context.h" namespace bluetooth { namespace common { -class IPostableContext { - public: - virtual ~IPostableContext(){}; - virtual void Post(OnceClosure closure) = 0; -}; - template class ContextualOnceCallback; diff --git a/system/btif/src/profile_log_levels.h b/system/gd/common/i_postable_context.h similarity index 65% rename from system/btif/src/profile_log_levels.h rename to system/gd/common/i_postable_context.h index 6084be41b3eb668a1084bef965f026fb0721fe99..c17297069c8f1db21c2b068eb8a72aee52e55eaf 100644 --- a/system/btif/src/profile_log_levels.h +++ b/system/gd/common/i_postable_context.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Android Open Source Project + * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,16 @@ #pragma once -#include "osi/include/config.h" +#include -/* - Sets log levels for each profile based on bt_stack.conf, and the - INIT_logging_debug_enabled_for_all flag. Only the latter can be (easily) - changed at runtime. -*/ -void load_levels_from_config(const config_t* config); +namespace bluetooth { +namespace common { + +class IPostableContext { + public: + virtual ~IPostableContext(){}; + virtual void Post(base::OnceClosure closure) = 0; +}; + +} // namespace common +} // namespace bluetooth diff --git a/system/gd/common/init_flags.h b/system/gd/common/init_flags.h index 58cb92dd96fa765563cb313d918a705e8dc31c2b..9f0f12a1238c96c079fb29dd22cecb48787cdb3d 100644 --- a/system/gd/common/init_flags.h +++ b/system/gd/common/init_flags.h @@ -16,9 +16,7 @@ #pragma once -#include #include -#include #include "src/init_flags.rs.h" @@ -52,14 +50,6 @@ class InitFlags final { return init_flags::btm_dm_flush_discovery_queue_on_search_cancel_is_enabled(); } - inline static bool IsSnoopLoggerSocketEnabled() { - return init_flags::gd_hal_snoop_logger_socket_is_enabled(); - } - - inline static bool IsSnoopLoggerFilteringEnabled() { - return init_flags::gd_hal_snoop_logger_filtering_is_enabled(); - } - inline static bool IsBluetoothQualityReportCallbackEnabled() { return init_flags::bluetooth_quality_report_callback_is_enabled(); } @@ -68,6 +58,10 @@ class InitFlags final { return init_flags::leaudio_targeted_announcement_reconnection_mode_is_enabled(); } + inline static bool UseRsiFromCachedInquiryResults() { + return init_flags::use_rsi_from_cached_inqiry_results_is_enabled(); + } + inline static int GetAdapterIndex() { return init_flags::get_hci_adapter(); } diff --git a/system/gd/common/init_flags_test.cc b/system/gd/common/init_flags_test.cc index c194f39447196e03aaa94e7205a9d3bfd7b3d5b4..8c4e357fcd310264ceed8e68248e6cbdd94cdd05 100644 --- a/system/gd/common/init_flags_test.cc +++ b/system/gd/common/init_flags_test.cc @@ -81,26 +81,20 @@ TEST(InitFlagsTest, test_debug_logging_multiple_flags) { ASSERT_EQ(InitFlags::GetDefaultLogLevel(), LOG_TAG_WARN); } -TEST(InitFlagsTest, test_enable_snoop_logger_socket) { - const char* input[] = {"INIT_gd_hal_snoop_logger_socket=true", nullptr}; - InitFlags::Load(input); - ASSERT_TRUE(InitFlags::IsSnoopLoggerSocketEnabled()); -} - TEST(InitFlagsTest, test_device_iot_config_logging_is_enabled) { const char* input[] = {"INIT_device_iot_config_logging=true", nullptr}; InitFlags::Load(input); ASSERT_TRUE(InitFlags::IsDeviceIotConfigLoggingEnabled()); } -TEST(InitFlagsTest, test_enable_snoop_logger_filtering) { - const char* input[] = {"INIT_gd_hal_snoop_logger_filtering=true", nullptr}; - InitFlags::Load(input); - ASSERT_TRUE(InitFlags::IsSnoopLoggerFilteringEnabled()); -} - TEST(InitFlagsTest, test_enable_bluetooth_quality_report_callback) { const char* input[] = {"INIT_bluetooth_quality_report_callback=true", nullptr}; InitFlags::Load(input); ASSERT_TRUE(InitFlags::IsBluetoothQualityReportCallbackEnabled()); } + +TEST(InitFlagsTest, test_enable_use_rsi_from_cached_inqiry_results) { + const char* input[] = {"INIT_use_rsi_from_cached_inqiry_results=true", nullptr}; + InitFlags::Load(input); + ASSERT_TRUE(InitFlags::UseRsiFromCachedInquiryResults()); +} diff --git a/system/gd/common/observer_registry.h b/system/gd/common/observer_registry.h deleted file mode 100644 index 99de57f98c3ff716d32f8416cc4d0d34ba722acd..0000000000000000000000000000000000000000 --- a/system/gd/common/observer_registry.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include "common/bind.h" -#include "common/callback.h" -#include "os/log.h" - -namespace bluetooth { -namespace common { - -// Tracks an observer registration on client (observer) code. Register() returns a wrapped callback object which can -// be passed to server's register API. Unregister() invalidates the wrapped callback so all callbacks that are posted -// to the client handler after the client called Unregister() call and before the server processed the Unregister() -// call on its handler, are dropped. -// Note: Register() invalidates the previous registration. -class SingleObserverRegistry { - public: - template - decltype(auto) Register(Callback callback) { - session_++; - return Bind(&SingleObserverRegistry::callback_wrapper, Unretained(this), session_, callback); - } - - void Unregister() { - session_++; - } - - private: - template - void callback_wrapper(int session, Callback callback, T... t) { - if (session == session_) { - callback.Run(std::forward(t)...); - } - } - - uint8_t session_ = 0; -}; - -// Tracks observer registration for multiple event type. Each event type is represented as an integer in [0, Capacity). -template -class MultipleObserverRegistry { - public: - template - decltype(auto) Register(int event_type, Callback callback) { - ASSERT(event_type < Capacity); - return registry_[event_type].Register(callback); - } - - void Unregister(int event_type) { - ASSERT(event_type < Capacity); - registry_[event_type].Unregister(); - } - - std::array registry_; -}; - -} // namespace common -} // namespace bluetooth diff --git a/system/gd/common/observer_registry_test.cc b/system/gd/common/observer_registry_test.cc deleted file mode 100644 index f1233a89d18469b17862d979f7132d0d2e12ab0d..0000000000000000000000000000000000000000 --- a/system/gd/common/observer_registry_test.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "common/observer_registry.h" - -#include "common/bind.h" -#include "gtest/gtest.h" - -namespace bluetooth { -namespace common { - -class SingleObserverRegistryTest : public ::testing::Test { - protected: - void SetUp() override { - registry_ = new SingleObserverRegistry; - } - - void TearDown() override { - delete registry_; - } - - SingleObserverRegistry* registry_; -}; - -void Increment(int* count) { - (*count)++; -} - -void IncrementBy(int* count, int n) { - (*count) += n; -} - -TEST_F(SingleObserverRegistryTest, wrapped_callback) { - int count = 0; - auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); - wrapped_callback.Run(); - EXPECT_EQ(count, 1); - wrapped_callback.Run(); - EXPECT_EQ(count, 2); - wrapped_callback.Run(); - EXPECT_EQ(count, 3); - registry_->Unregister(); -} - -TEST_F(SingleObserverRegistryTest, unregister) { - int count = 0; - auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); - registry_->Unregister(); - wrapped_callback.Run(); - EXPECT_EQ(count, 0); -} - -TEST_F(SingleObserverRegistryTest, second_register) { - int count = 0; - auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); - registry_->Unregister(); - auto wrapped_callback2 = registry_->Register(Bind(&Increment, Unretained(&count))); - wrapped_callback.Run(); - EXPECT_EQ(count, 0); - wrapped_callback2.Run(); - EXPECT_EQ(count, 1); -} - -class MultipleObserverRegistryTest : public ::testing::Test { - protected: - void SetUp() override { - registry_ = new MultipleObserverRegistry<2>; - } - - void TearDown() override { - delete registry_; - } - - MultipleObserverRegistry<2>* registry_; -}; - -TEST_F(MultipleObserverRegistryTest, single_wrapped_callback) { - int count = 0; - auto wrapped_callback = registry_->Register(0, Bind(&Increment, Unretained(&count))); - wrapped_callback.Run(); - EXPECT_EQ(count, 1); - wrapped_callback.Run(); - EXPECT_EQ(count, 2); - wrapped_callback.Run(); - EXPECT_EQ(count, 3); - registry_->Unregister(0); -} - -TEST_F(MultipleObserverRegistryTest, multiple_wrapped_callback) { - int count = 0; - auto wrapped_callback0 = registry_->Register(0, Bind(&Increment, Unretained(&count))); - auto wrapped_callback1 = registry_->Register(1, Bind(&IncrementBy, Unretained(&count), 10)); - wrapped_callback0.Run(); - EXPECT_EQ(count, 1); - wrapped_callback1.Run(); - EXPECT_EQ(count, 11); - registry_->Unregister(0); - wrapped_callback0.Run(); - EXPECT_EQ(count, 11); - wrapped_callback1.Run(); - EXPECT_EQ(count, 21); - registry_->Unregister(1); - EXPECT_EQ(count, 21); -} - -} // namespace common -} // namespace bluetooth diff --git a/system/gd/common/strings_test.cc b/system/gd/common/strings_test.cc index 64f214297309820b14867dda9c8aed45edb6a310..ddc03c3acd7f032ad30584e7a8ce028501b623e1 100644 --- a/system/gd/common/strings_test.cc +++ b/system/gd/common/strings_test.cc @@ -44,6 +44,8 @@ static inline bool is_arch64() { return sizeof(long) == 8; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winteger-overflow" TEST(StringsTest, to_hex_string_from_number) { ASSERT_EQ(ToHexString(0), "0x00000000"); ASSERT_EQ(ToHexString(3), "0x00000003"); @@ -87,6 +89,7 @@ TEST(StringsTest, to_hex_string_from_number_unsigned_int) { ASSERT_EQ(ToHexString(1U + UINT_MAX), "0x00000000"); // Rolled over ASSERT_EQ(ToHexString(2U + UINT_MAX), "0x00000001"); // Rolled over } +#pragma clang diagnostic pop TEST(StringsTest, trim_string_test) { ASSERT_EQ(StringTrim(" aa bb"), "aa bb"); @@ -257,7 +260,7 @@ TEST(StringsTest, string_format_time_with_ms_test) { } class ExampleClass {}; -std::ostream& operator<<(std::ostream& os, const ExampleClass& obj) { +std::ostream& operator<<(std::ostream& os, const ExampleClass& /* obj */) { os << "ExampleClass"; return os; } diff --git a/system/gd/common/testing/android/log_capture.cc b/system/gd/common/testing/android/log_capture.cc index 174bc3dd32a8e33fd84c6429dcd8916d784c4364..3b09dc3c6870cef84db295808edcd41aae6ca1fc 100644 --- a/system/gd/common/testing/android/log_capture.cc +++ b/system/gd/common/testing/android/log_capture.cc @@ -16,12 +16,10 @@ #include "common/testing/log_capture.h" -#include #include #include #include -#include #include #include "os/log.h" @@ -43,7 +41,7 @@ LogCapture* LogCapture::Rewind() { return this; } -bool LogCapture::Find(std::string to_find) { +bool LogCapture::Find(const std::string& /* to_find */) { // For |atest| assume all log captures succeed return true; } @@ -63,10 +61,7 @@ size_t LogCapture::Size() const { return size; } -void LogCapture::WaitUntilLogContains(std::promise* promise, std::string text) { - std::async([promise, text]() { promise->set_value(); }); - promise->get_future().wait(); -} +void LogCapture::WaitUntilLogContains(const std::string& /* text */) {} std::pair LogCapture::create_backing_store() const { int dup_fd = -1; @@ -74,7 +69,7 @@ std::pair LogCapture::create_backing_store() const { return std::make_pair(dup_fd, fd); } -bool LogCapture::set_non_blocking(int fd) const { +bool LogCapture::set_non_blocking(int /* fd */) const { return true; } diff --git a/system/gd/common/testing/host/log_capture.cc b/system/gd/common/testing/host/log_capture.cc index 4d034b43cbdb65668c684267f116b3840cc8e1ce..7749b8e2fe9d13aeac743eb20ab6616b42f8fc1e 100644 --- a/system/gd/common/testing/host/log_capture.cc +++ b/system/gd/common/testing/host/log_capture.cc @@ -16,7 +16,6 @@ #include "common/testing/log_capture.h" -#include #include #include @@ -71,7 +70,7 @@ LogCapture* LogCapture::Rewind() { return this; } -bool LogCapture::Find(std::string to_find) { +bool LogCapture::Find(const std::string& to_find) { std::string str = this->Read(); return str.find(to_find) != std::string::npos; } @@ -135,15 +134,11 @@ size_t LogCapture::Size() const { return size; } -void LogCapture::WaitUntilLogContains(std::promise* promise, std::string text) { - std::async([this, promise, text]() { - bool found = false; - do { - found = this->Rewind()->Find(text); - } while (!found); - promise->set_value(); - }); - promise->get_future().wait(); +void LogCapture::WaitUntilLogContains(const std::string& text) { + bool found = false; + do { + found = this->Rewind()->Find(text); + } while (!found); } std::pair LogCapture::create_backing_store() const { diff --git a/system/gd/common/testing/host/log_capture_test.cc b/system/gd/common/testing/host/log_capture_test.cc index 320b4fe358168c53bbbf31f105ffcf84f23b3ba7..e10c83d2f6488287435553a63533bd820a98b0bb 100644 --- a/system/gd/common/testing/host/log_capture_test.cc +++ b/system/gd/common/testing/host/log_capture_test.cc @@ -146,8 +146,7 @@ TEST_F(LogCaptureTest, DISABLED_wait_until_log_contains) { std::unique_ptr log_capture = std::make_unique(); LOG_DEBUG("%s", kLogDebug); - std::promise promise; - log_capture->WaitUntilLogContains(&promise, kLogDebug); + log_capture->WaitUntilLogContains(kLogDebug); bluetooth::common::InitFlags::Load(nullptr); } diff --git a/system/gd/common/testing/log_capture.h b/system/gd/common/testing/log_capture.h index e08c0fa9e107bac46c02ce0228109f6a193756a8..ac34febd6f560bd865628249aee5fcd6c0f3720f 100644 --- a/system/gd/common/testing/log_capture.h +++ b/system/gd/common/testing/log_capture.h @@ -31,7 +31,7 @@ class LogCapture { LogCapture* Rewind(); // Searches from filepointer to end of file for |to_find| string // Returns true if found, false otherwise - bool Find(std::string to_find); + bool Find(const std::string& to_find); // Reads and returns the entirety of the backing store into a string std::string Read(); // Flushes contents of log capture back to |stderr| @@ -43,7 +43,7 @@ class LogCapture { // Truncates and resets the file pointer discarding all logs up to this point void Reset(); // Wait until the provided string shows up in the logs - void WaitUntilLogContains(std::promise* promise, std::string text); + void WaitUntilLogContains(const std::string& text); private: std::pair create_backing_store() const; diff --git a/system/gd/crypto_toolbox/Android.bp b/system/gd/crypto_toolbox/Android.bp index 671508d37b0ef6423ab8c6a21feb66a2b1a1d2a5..3b5eb6dd785ed5b894f5a08cedf876d211c159be 100644 --- a/system/gd/crypto_toolbox/Android.bp +++ b/system/gd/crypto_toolbox/Android.bp @@ -9,17 +9,28 @@ package { } filegroup { - name: "BluetoothCryptoToolboxSources", + name: "BluetoothCryptoToolboxTestSources", srcs: [ - "aes.cc", - "aes_cmac.cc", - "crypto_toolbox.cc", + "crypto_toolbox_test.cc", ], } -filegroup { - name: "BluetoothCryptoToolboxTestSources", +cc_library { + name: "libbluetooth_crypto_toolbox", + defaults: ["fluoride_defaults"], + host_supported: true, + apex_available: ["com.android.btservices"], + min_sdk_version: "29", + include_dirs: [ + "packages/modules/Bluetooth/system/gd", + ], + shared_libs: [ + "libcutils", + "liblog", + ], srcs: [ - "crypto_toolbox_test.cc", + "aes.cc", + "aes_cmac.cc", + "crypto_toolbox.cc", ], } diff --git a/system/gd/crypto_toolbox/BUILD.gn b/system/gd/crypto_toolbox/BUILD.gn index 7dd35a8f11d49efccde3c1e8c85ba8ff463de877..1983ff921f58c549e34d6f5d1ec078551d242977 100644 --- a/system/gd/crypto_toolbox/BUILD.gn +++ b/system/gd/crypto_toolbox/BUILD.gn @@ -13,12 +13,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -source_set("BluetoothCryptoToolboxSources") { +static_library("crypto_toolbox") { sources = [ "aes.cc", "aes_cmac.cc", "crypto_toolbox.cc", ] + include_dirs = [ "//bt/system/gd" ] + configs += [ "//bt/system/gd:gd_defaults" ] } diff --git a/system/gd/crypto_toolbox/aes_cmac.cc b/system/gd/crypto_toolbox/aes_cmac.cc index 7dda9d930f4f7f4aa28f44033bd77e87483fff00..4ec4266d1ba7be59ddb566a4837b2aa6447a6b74 100644 --- a/system/gd/crypto_toolbox/aes_cmac.cc +++ b/system/gd/crypto_toolbox/aes_cmac.cc @@ -23,11 +23,15 @@ ******************************************************************************/ #include +#include -#include "crypto_toolbox/aes.h" -#include "crypto_toolbox/crypto_toolbox.h" +#include "aes.h" +#include "crypto_toolbox.h" +#include "hci/octets.h" + +using bluetooth::hci::kOctet16Length; +using bluetooth::hci::Octet16; -namespace bluetooth { namespace crypto_toolbox { namespace { @@ -44,14 +48,13 @@ thread_local tCMAC_CB cmac_cb; Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /** utility function to do an biteise exclusive-OR of two bit strings of the - * length of OCTET16_LEN. Result is stored in first argument. + * length of kOctet16Length. Result is stored in first argument. */ static void xor_128(Octet16* a, const Octet16& b) { - // CHECK(a); uint8_t i, *aa = a->data(); const uint8_t* bb = b.data(); - for (i = 0; i < OCTET16_LEN; i++) { + for (i = 0; i < kOctet16Length; i++) { aa[i] = aa[i] ^ bb[i]; } } @@ -76,18 +79,18 @@ Octet16 aes_128(const Octet16& key, const Octet16& message) { /** utility function to padding the given text to be a 128 bits data. The * parameter dest is input and output parameter, it must point to a - * OCTET16_LEN memory space; where include length bytes valid data. */ + * kOctet16Length memory space; where include length bytes valid data. */ static void padding(Octet16* dest, uint8_t length) { uint8_t i, *p = dest->data(); /* original last block */ - for (i = length; i < OCTET16_LEN; i++) p[OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0; + for (i = length; i < kOctet16Length; i++) p[kOctet16Length - i - 1] = (i == length) ? 0x80 : 0; } /** utility function to left shift one bit for a 128 bits value. */ static void leftshift_onebit(uint8_t* input, uint8_t* output) { uint8_t i, overflow = 0, next_overflow = 0; /* input[0] is LSB */ - for (i = 0; i < OCTET16_LEN; i++) { + for (i = 0; i < kOctet16Length; i++) { next_overflow = (input[i] & 0x80) ? 1 : 0; output[i] = (input[i] << 1) | overflow; overflow = next_overflow; @@ -103,9 +106,9 @@ static Octet16 cmac_aes_k_calculate(const Octet16& key) { uint16_t i = 1; while (i <= cmac_cb.round) { /* Mi' := Mi (+) X */ - xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], x); + xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * kOctet16Length], x); - output = aes_128(key, &cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], OCTET16_LEN); + output = aes_128(key, *(Octet16*)&cmac_cb.text[(cmac_cb.round - i) * kOctet16Length]); x = output; i++; } @@ -121,7 +124,7 @@ static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) { bool flag; /* last block is a complete block set flag to 1 */ - flag = ((cmac_cb.len % OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false; + flag = ((cmac_cb.len % kOctet16Length) == 0 && cmac_cb.len != 0) ? true : false; if (flag) { /* last block is complete block */ xor_128((Octet16*)&cmac_cb.text[0], k1); @@ -138,13 +141,13 @@ static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) { */ static void cmac_generate_subkey(const Octet16& key) { Octet16 zero{}; - Octet16 p = aes_128(key, zero.data(), OCTET16_LEN); + Octet16 p = aes_128(key, zero); Octet16 k1, k2; uint8_t* pp = p.data(); /* If MSB(L) = 0, then K1 = L << 1 */ - if ((pp[OCTET16_LEN - 1] & 0x80) != 0) { + if ((pp[kOctet16Length - 1] & 0x80) != 0) { /* Else K1 = ( L << 1 ) (+) Rb */ leftshift_onebit(pp, k1.data()); xor_128(&k1, const_Rb); @@ -152,7 +155,7 @@ static void cmac_generate_subkey(const Octet16& key) { leftshift_onebit(pp, k1.data()); } - if ((k1[OCTET16_LEN - 1] & 0x80) != 0) { + if ((k1[kOctet16Length - 1] & 0x80) != 0) { /* K2 = (K1 << 1) (+) Rb */ leftshift_onebit(k1.data(), k2.data()); xor_128(&k2, const_Rb); @@ -172,10 +175,12 @@ Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) { uint32_t len; uint16_t diff; /* n is number of rounds */ - uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN; + uint16_t n = (length + kOctet16Length - 1) / kOctet16Length; if (n == 0) n = 1; - len = n * OCTET16_LEN; + len = n * kOctet16Length; + + // VLOG(1) << "AES128_CMAC started, allocate buffer size=" << len; /* allocate a memory space of multiple of 16 bytes to hold text */ cmac_cb.text = (uint8_t*)alloca(len); @@ -202,4 +207,3 @@ Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) { } } // namespace crypto_toolbox -} // namespace bluetooth diff --git a/system/gd/crypto_toolbox/crypto_toolbox.cc b/system/gd/crypto_toolbox/crypto_toolbox.cc index 67f1a70798346cd19faca798e34648e36f13df8a..81620b920822d222cd03f00c52f86c151e0a4331 100644 --- a/system/gd/crypto_toolbox/crypto_toolbox.cc +++ b/system/gd/crypto_toolbox/crypto_toolbox.cc @@ -14,18 +14,19 @@ * limitations under the License. */ -#include "crypto_toolbox/crypto_toolbox.h" +#include "crypto_toolbox.h" #include #include -#include "crypto_toolbox/aes.h" +#include "hci/octets.h" -namespace bluetooth { -namespace crypto_toolbox { +using bluetooth::hci::kOctet16Length; +using bluetooth::hci::kOctet32Length; +using bluetooth::hci::Octet16; -constexpr int OCTET32_LEN = 32; +namespace crypto_toolbox { Octet16 h6(const Octet16& w, std::array keyid) { return aes_cmac(w, keyid.data(), keyid.size()); @@ -35,17 +36,20 @@ Octet16 h7(const Octet16& salt, const Octet16& w) { return aes_cmac(salt, w.data(), w.size()); } -Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z) { - constexpr size_t msg_len = OCTET32_LEN /* U size */ + OCTET32_LEN /* V size */ + 1 /* Z size */; +Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z) { + constexpr size_t msg_len = + kOctet32Length /* U size */ + kOctet32Length /* V size */ + 1 /* Z size */; - // DVLOG(2) << "U=" << HexEncode(u, OCTET32_LEN) << ", V=" << HexEncode(v, OCTET32_LEN) - // << ", X=" << HexEncode(x.data(), x.size()) << ", Z=" << std::hex << +z; + // VLOG(1) << "U=" << HexEncode(u, kOctet32Length) + // << ", V=" << HexEncode(v, kOctet32Length) + // << ", X=" << HexEncode(x.data(), x.size()) << ", Z=" << std::hex + // << +z; std::array msg; auto it = msg.begin(); it = std::copy(&z, &z + 1, it); - it = std::copy(v, v + OCTET32_LEN, it); - it = std::copy(u, u + OCTET32_LEN, it); + it = std::copy(v, v + kOctet32Length, it); + it = std::copy(u, u + kOctet32Length, it); return aes_cmac(x, msg.data(), msg.size()); } @@ -59,8 +63,9 @@ static Octet16 calculate_mac_key_or_ltk( uint8_t* a1, uint8_t* a2, uint8_t* length) { - constexpr size_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ + OCTET16_LEN /* N1 size */ + - OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ + 7 /* A2 size*/ + 2 /* Length size */; + constexpr size_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ + + kOctet16Length /* N1 size */ + kOctet16Length /* N2 size */ + + 7 /* A1 size*/ + 7 /* A2 size*/ + 2 /* Length size */; std::array msg; auto it = msg.begin(); @@ -75,15 +80,23 @@ static Octet16 calculate_mac_key_or_ltk( return aes_cmac(t, msg.data(), msg.size()); } -void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk) { - // DVLOG(2) << __func__ << "W=" << HexEncode(w, OCTET32_LEN) << ", N1=" << HexEncode(n1.data(), n1.size()) - // << ", N2=" << HexEncode(n2.data(), n2.size()) << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2, - // 7); +void f5( + const uint8_t* w, + const Octet16& n1, + const Octet16& n2, + uint8_t* a1, + uint8_t* a2, + Octet16* mac_key, + Octet16* ltk) { + // VLOG(1) << __func__ << "W=" << HexEncode(w, kOctet32Length) << ", N1=" << + // HexEncode(n1.data(), n1.size()) + // << ", N2=" << HexEncode(n2.data(), n2.size()) << ", A1=" << HexEncode(a1, 7) << ", + // A2=" << HexEncode(a2, 7); const Octet16 salt{0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60, 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C}; - Octet16 t = aes_cmac(salt, w, OCTET32_LEN); + Octet16 t = aes_cmac(salt, w, kOctet32Length); - // DVLOG(2) << "T=" << HexEncode(t.data(), t.size()); + // VLOG(1) << "T=" << HexEncode(t.data(), t.size()); uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62}; /* 0x62746c65 */ uint8_t length[2] = {0x00, 0x01}; /* 0x0100 */ @@ -92,18 +105,22 @@ void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, uint8_t* *ltk = calculate_mac_key_or_ltk(t, 1, key_id, n1, n2, a1, a2, length); - // DVLOG(2) << "mac_key=" << HexEncode(mac_key->data(), mac_key->size()); - // DVLOG(2) << "ltk=" << HexEncode(ltk->data(), ltk->size()); + // VLOG(1) << "mac_key=" << HexEncode(mac_key->data(), mac_key->size()); + // VLOG(1) << "ltk=" << HexEncode(ltk->data(), ltk->size()); } Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2, const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2) { - const uint8_t msg_len = OCTET16_LEN /* N1 size */ + OCTET16_LEN /* N2 size */ + OCTET16_LEN /* R size */ + - 3 /* IOcap size */ + 7 /* A1 size*/ + 7 /* A2 size*/; + const uint8_t msg_len = kOctet16Length /* N1 size */ + kOctet16Length /* N2 size */ + + kOctet16Length /* R size */ + 3 /* IOcap size */ + 7 /* A1 size*/ + + 7 /* A2 size*/; - // DVLOG(2) << __func__ << "W=" << HexEncode(w.data(), w.size()) << ", N1=" << HexEncode(n1.data(), n1.size()) - // << ", N2=" << HexEncode(n2.data(), n2.size()) << ", R=" << HexEncode(r.data(), r.size()) - // << ", IOcap=" << HexEncode(iocap, 3) << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2, 7); + // VLOG(1) << __func__ << "W=" << HexEncode(w.data(), w.size()) << ", N1=" << + // HexEncode(n1.data(), n1.size()) + // << ", N2=" << HexEncode(n2.data(), n2.size()) << ", R=" << HexEncode(r.data(), + // r.size()) + // << ", IOcap=" << HexEncode(iocap, 3) << ", A1=" << HexEncode(a1, 7) << ", A2=" << + // HexEncode(a2, 7); std::array msg; auto it = msg.begin(); @@ -117,18 +134,19 @@ f6(const Octet16& w, const Octet16& n1, const Octet16& n2, const Octet16& r, uin return aes_cmac(w, msg.data(), msg.size()); } -uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y) { - constexpr size_t msg_len = OCTET32_LEN /* U size */ + OCTET32_LEN /* V size */ - + OCTET16_LEN /* Y size */; +uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x, const Octet16& y) { + constexpr size_t msg_len = kOctet32Length /* U size */ + kOctet32Length /* V size */ + + kOctet16Length /* Y size */; - // DVLOG(2) << __func__ << "U=" << HexEncode(u, OCTET32_LEN) << ", V=" << HexEncode(v, OCTET32_LEN) + // VLOG(1) << __func__ << "U=" << HexEncode(u, kOctet32Length) << ", V=" << HexEncode(v, + // kOctet32Length) // << ", X=" << HexEncode(x.data(), x.size()) << ", Y=" << HexEncode(y.data(), y.size()); std::array msg; auto it = msg.begin(); it = std::copy(y.begin(), y.end(), it); - it = std::copy(v, v + OCTET32_LEN, it); - it = std::copy(u, u + OCTET32_LEN, it); + it = std::copy(v, v + kOctet32Length, it); + it = std::copy(u, u + kOctet32Length, it); Octet16 cmac = aes_cmac(x, msg.data(), msg.size()); @@ -186,7 +204,7 @@ Octet16 c1( it = std::copy(preq, preq + 7, it); it = std::copy(pres, pres + 7, it); - for (uint8_t i = 0; i < OCTET16_LEN; i++) { + for (uint8_t i = 0; i < kOctet16Length; i++) { p1[i] = r[i] ^ p1[i]; } @@ -199,7 +217,7 @@ Octet16 c1( it = std::copy(ia, ia + 6, it); it = std::copy(padding.begin(), padding.end(), it); - for (uint8_t i = 0; i < OCTET16_LEN; i++) { + for (uint8_t i = 0; i < kOctet16Length; i++) { p2[i] = p1bis[i] ^ p2[i]; } @@ -208,12 +226,10 @@ Octet16 c1( Octet16 s1(const Octet16& k, const Octet16& r1, const Octet16& r2) { Octet16 text{0}; - constexpr uint8_t BT_OCTET8_LEN = 8; - memcpy(text.data(), r1.data(), BT_OCTET8_LEN); - memcpy(text.data() + BT_OCTET8_LEN, r2.data(), BT_OCTET8_LEN); + memcpy(text.data(), r1.data(), kOctet16Length / 2); + memcpy(text.data() + kOctet16Length / 2, r2.data(), kOctet16Length / 2); return aes_128(k, text); } } // namespace crypto_toolbox -} // namespace bluetooth \ No newline at end of file diff --git a/system/gd/crypto_toolbox/crypto_toolbox.h b/system/gd/crypto_toolbox/crypto_toolbox.h index aa15d6ead84ed6d950fe50e2dfe63aad5368904a..eff79f0b324ca8e6c1fd4df49f6b8775e32c1b11 100644 --- a/system/gd/crypto_toolbox/crypto_toolbox.h +++ b/system/gd/crypto_toolbox/crypto_toolbox.h @@ -16,75 +16,77 @@ #pragma once -#include #include #include #include -namespace bluetooth { -namespace crypto_toolbox { +#include "hci/octets.h" -constexpr int OCTET16_LEN = 16; -using Octet16 = std::array; +namespace crypto_toolbox { -Octet16 c1( - const Octet16& k, - const Octet16& r, +bluetooth::hci::Octet16 c1( + const bluetooth::hci::Octet16& k, + const bluetooth::hci::Octet16& r, const uint8_t* pres, const uint8_t* preq, const uint8_t iat, const uint8_t* ia, const uint8_t rat, const uint8_t* ra); -Octet16 s1(const Octet16& k, const Octet16& r1, const Octet16& r2); +bluetooth::hci::Octet16 s1( + const bluetooth::hci::Octet16& k, + const bluetooth::hci::Octet16& r1, + const bluetooth::hci::Octet16& r2); -Octet16 aes_128(const Octet16& key, const Octet16& message); -Octet16 aes_cmac(const Octet16& key, const uint8_t* message, uint16_t length); -Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z); +bluetooth::hci::Octet16 aes_128( + const bluetooth::hci::Octet16& key, const bluetooth::hci::Octet16& message); +bluetooth::hci::Octet16 aes_cmac( + const bluetooth::hci::Octet16& key, const uint8_t* message, uint16_t length); +bluetooth::hci::Octet16 f4( + const uint8_t* u, const uint8_t* v, const bluetooth::hci::Octet16& x, uint8_t z); void f5( - uint8_t* w, - const Octet16& n1, - const Octet16& n2, + const uint8_t* w, + const bluetooth::hci::Octet16& n1, + const bluetooth::hci::Octet16& n2, uint8_t* a1, uint8_t* a2, - Octet16* mac_key, - Octet16* ltk); -Octet16 f6( - const Octet16& w, - const Octet16& n1, - const Octet16& n2, - const Octet16& r, + bluetooth::hci::Octet16* mac_key, + bluetooth::hci::Octet16* ltk); +bluetooth::hci::Octet16 f6( + const bluetooth::hci::Octet16& w, + const bluetooth::hci::Octet16& n1, + const bluetooth::hci::Octet16& n2, + const bluetooth::hci::Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2); -Octet16 h6(const Octet16& w, std::array keyid); -Octet16 h7(const Octet16& salt, const Octet16& w); -uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y); -Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7); -Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7); - -/* This function computes AES_128(key, message). |key| must be 128bit. - * |message| can be at most 16 bytes long, it's length in bytes is given in - * |length| */ -inline Octet16 aes_128(const Octet16& key, const uint8_t* message, const uint8_t length) { - // CHECK(length <= OCTET16_LEN) << "you tried aes_128 more than 16 bytes!"; - Octet16 msg{0}; - std::copy(message, message + length, msg.begin()); - return aes_128(key, msg); -} +bluetooth::hci::Octet16 h6(const bluetooth::hci::Octet16& w, std::array keyid); +bluetooth::hci::Octet16 h7(const bluetooth::hci::Octet16& salt, const bluetooth::hci::Octet16& w); +uint32_t g2( + const uint8_t* u, + const uint8_t* v, + const bluetooth::hci::Octet16& x, + const bluetooth::hci::Octet16& y); +bluetooth::hci::Octet16 ltk_to_link_key(const bluetooth::hci::Octet16& ltk, bool use_h7); +bluetooth::hci::Octet16 link_key_to_ltk(const bluetooth::hci::Octet16& link_key, bool use_h7); // |tlen| - lenth of mac desired // |p_signature| - data pointer to where signed data to be stored, tlen long. -inline void aes_cmac(const Octet16& key, const uint8_t* message, uint16_t length, uint16_t tlen, uint8_t* p_signature) { - Octet16 signature = aes_cmac(key, message, length); +inline void aes_cmac( + const bluetooth::hci::Octet16& key, + const uint8_t* message, + uint16_t length, + uint16_t tlen, + uint8_t* p_signature) { + bluetooth::hci::Octet16 signature = aes_cmac(key, message, length); - uint8_t* p_mac = signature.data() + (OCTET16_LEN - tlen); + uint8_t* p_mac = signature.data() + (bluetooth::hci::kOctet16Length - tlen); memcpy(p_signature, p_mac, tlen); } -inline Octet16 aes_cmac(const Octet16& key, const Octet16& message) { +inline bluetooth::hci::Octet16 aes_cmac( + const bluetooth::hci::Octet16& key, const bluetooth::hci::Octet16& message) { return aes_cmac(key, message.data(), message.size()); } } // namespace crypto_toolbox -} // namespace bluetooth diff --git a/system/gd/crypto_toolbox/crypto_toolbox_test.cc b/system/gd/crypto_toolbox/crypto_toolbox_test.cc index f28c34efe1f3dc494dcaf4c1bd7472d267ab8ae3..757bae00e4243fe5f4395a6ecaf08662b8b8b19e 100644 --- a/system/gd/crypto_toolbox/crypto_toolbox_test.cc +++ b/system/gd/crypto_toolbox/crypto_toolbox_test.cc @@ -23,9 +23,11 @@ #include #include "crypto_toolbox/aes.h" +#include "hci/octets.h" -namespace bluetooth { namespace crypto_toolbox { +using bluetooth::hci::kOctet16Length; +using bluetooth::hci::Octet16; // BT Spec 5.0 | Vol 3, Part H D.1 TEST(CryptoToolboxTest, bt_spec_test_d_1_test) { @@ -41,7 +43,7 @@ TEST(CryptoToolboxTest, bt_spec_test_d_1_test) { aes_set_key(k, sizeof(k), &ctx); aes_encrypt(m, output, &ctx); /* outputs in byte 48 to byte 63 */ - EXPECT_TRUE(memcmp(output, aes_cmac_k_m, OCTET16_LEN) == 0); + EXPECT_TRUE(memcmp(output, aes_cmac_k_m, kOctet16Length) == 0); // useful for debugging // LOG(INFO) << "k " << base::HexEncode(k, OCTET16_LEN); @@ -271,7 +273,7 @@ TEST(CryptoToolboxTest, bt_spec_example_d_7_test) { std::reverse(std::begin(expected_aes_128), std::end(expected_aes_128)); std::reverse(std::begin(expected_ah), std::end(expected_ah)); - Octet16 result = aes_128(IRK, prand.data(), 3); + Octet16 result = aes_128(IRK, prand); EXPECT_EQ(expected_aes_128, result); // little/big endian 24 bits @@ -353,4 +355,3 @@ TEST(CryptoToolboxTest, bt_spec_example_d_12_test) { } } // namespace crypto_toolbox -} // namespace bluetooth diff --git a/system/gd/dumpsys/Android.bp b/system/gd/dumpsys/Android.bp index 56314bc82548b4b67ace853ab8c2f1bf299e2b3e..085c44b7f95ba031b0f8f4f5cb766bf6dfeafcee 100644 --- a/system/gd/dumpsys/Android.bp +++ b/system/gd/dumpsys/Android.bp @@ -131,6 +131,26 @@ genrule { ], } +genrule { + name: "BluetoothGeneratedDumpsysInternalTestData_h", + tools: [ + "flatc", + ], + cmd: "$(location flatc) --cpp -o $(genDir)/dumpsys/internal/test_data $(in)", + srcs: [ + "internal/test_data/float.fbs", + "internal/test_data/integer.fbs", + "internal/test_data/string.fbs", + "internal/test_data/struct.fbs", + ], + out: [ + "dumpsys/internal/test_data/float_generated.h", + "dumpsys/internal/test_data/integer_generated.h", + "dumpsys/internal/test_data/string_generated.h", + "dumpsys/internal/test_data/struct_generated.h", + ], +} + cc_library { name: "libbluetooth-dumpsys", host_supported: true, @@ -173,10 +193,9 @@ cc_library { cc_test { name: "bluetooth_flatbuffer_tests", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", - "fluoride_common_options", + "bluetooth_cflags", "mts_defaults", ], host_supported: true, diff --git a/system/gd/dumpsys/bundler/Android.bp b/system/gd/dumpsys/bundler/Android.bp index 0dcaa0037fa52683e5c062296c1b4997aa017e51..0a5f57d3687de6f0878aa31c247c2d58f1ad582d 100644 --- a/system/gd/dumpsys/bundler/Android.bp +++ b/system/gd/dumpsys/bundler/Android.bp @@ -48,8 +48,7 @@ genrule { cc_defaults { name: "bluetooth_flatbuffer_bundler_defaults", - defaults: ["fluoride_common_options"], - cpp_std: "c++17", + defaults: ["bluetooth_cflags"], generated_headers: [ "BluetoothGeneratedBundlerSchema_h_bfbs", ], @@ -69,6 +68,7 @@ cc_binary_host { defaults: [ "bluetooth_flatbuffer_bundler_defaults", ], + cflags: ["-Wno-unused-parameter"], } cc_test_host { @@ -85,4 +85,5 @@ cc_test_host { test_options: { unit_test: true, }, + cflags: ["-Wno-unused-parameter"], } diff --git a/system/gd/dumpsys/filter.cc b/system/gd/dumpsys/filter.cc index 4d99fb3aeeb8ca2679fc9b7109f5345a2654d1f0..982bec6722edb98b4c7756579a5cfe806c4853b9 100644 --- a/system/gd/dumpsys/filter.cc +++ b/system/gd/dumpsys/filter.cc @@ -50,7 +50,7 @@ class Filter { * * @return true if field was filtered successfully, false otherwise. */ - virtual bool FilterField(const reflection::Field* field, flatbuffers::Table* table) { + virtual bool FilterField(const reflection::Field* /* field */, flatbuffers::Table* /* table */) { return false; } @@ -62,7 +62,8 @@ class Filter { * @param table The populated field data, if any * */ - virtual void FilterObject(const reflection::Object* object, flatbuffers::Table* table){}; + virtual void FilterObject( + const reflection::Object* /* object */, flatbuffers::Table* /* table */){}; /** * Given both reflection field data and the populated table data, if any, @@ -72,7 +73,8 @@ class Filter { * @param table The populated field data, if any * */ - virtual void FilterTable(const reflection::Schema* schema, flatbuffers::Table* table){}; + virtual void FilterTable( + const reflection::Schema* /* schema */, flatbuffers::Table* /* table */){}; const dumpsys::ReflectionSchema& reflection_schema_; }; @@ -80,7 +82,7 @@ class Filter { class DeveloperPrivacyFilter : public Filter { public: DeveloperPrivacyFilter(const dumpsys::ReflectionSchema& reflection_schema) : Filter(reflection_schema) {} - void FilterInPlace(char* dumpsys_data) override { /* Nothing to do in this mode */ + void FilterInPlace(char* /* dumpsys_data */) override { /* Nothing to do in this mode */ } }; diff --git a/system/gd/dumpsys/internal/filter_internal.h b/system/gd/dumpsys/internal/filter_internal.h index 745f1d2f9ef03d40aa6ca4d7a68dd4acfea0a93b..ea23b005801fab9838cc0b0e4346be16f8df5a5f 100644 --- a/system/gd/dumpsys/internal/filter_internal.h +++ b/system/gd/dumpsys/internal/filter_internal.h @@ -21,6 +21,7 @@ #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" +#include "macros.h" namespace bluetooth { namespace dumpsys { @@ -121,10 +122,6 @@ bool FilterTypeLong(const reflection::Field& field, flatbuffers::Table* table, P bool FilterTypeString(const reflection::Field& field, flatbuffers::Table* table, PrivacyLevel privacy_level); bool FilterTypeStruct(const reflection::Field& field, flatbuffers::Table* table, PrivacyLevel privacy_level); -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string FlatbufferTypeText(const flatbuffers::BaseType& type) { switch (type) { CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_NONE); @@ -147,7 +144,6 @@ inline std::string FlatbufferTypeText(const flatbuffers::BaseType& type) { return base::StringPrintf("UNKNOWN[%d]", (int)type); } } -#undef CASE_RETURN_TEXT } // namespace internal } // namespace dumpsys diff --git a/system/gd/dumpsys/internal/test_data/float_generated.h b/system/gd/dumpsys/internal/test_data/float_generated.h deleted file mode 100644 index 8f2e6f31fe6ee3935eb2efda36cce57ac5f9765d..0000000000000000000000000000000000000000 --- a/system/gd/dumpsys/internal/test_data/float_generated.h +++ /dev/null @@ -1,86 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - -#ifndef FLATBUFFERS_GENERATED_FLOAT_TESTING_H_ -#define FLATBUFFERS_GENERATED_FLOAT_TESTING_H_ - -#include "flatbuffers/flatbuffers.h" - -// Ensure the included flatbuffers.h is the same version as when this file was -// generated, otherwise it may not be compatible. -static_assert( - FLATBUFFERS_VERSION_MAJOR == 2 && FLATBUFFERS_VERSION_MINOR == 0 && FLATBUFFERS_VERSION_REVISION == 7, - "Non-compatible flatbuffers version included"); - -namespace testing { - -struct TestTableFloat; -struct TestTableFloatBuilder; - -struct TestTableFloat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TestTableFloatBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_TEST_FLOAT = 4 }; - float test_float() const { - return GetField(VT_TEST_FLOAT, 0.0f); - } - bool Verify(flatbuffers::Verifier& verifier) const { - return VerifyTableStart(verifier) && VerifyField(verifier, VT_TEST_FLOAT, 4) && verifier.EndTable(); - } -}; - -struct TestTableFloatBuilder { - typedef TestTableFloat Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_test_float(float test_float) { - fbb_.AddElement(TestTableFloat::VT_TEST_FLOAT, test_float, 0.0f); - } - explicit TestTableFloatBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateTestTableFloat( - flatbuffers::FlatBufferBuilder& _fbb, float test_float = 0.0f) { - TestTableFloatBuilder builder_(_fbb); - builder_.add_test_float(test_float); - return builder_.Finish(); -} - -inline const testing::TestTableFloat* GetTestTableFloat(const void* buf) { - return flatbuffers::GetRoot(buf); -} - -inline const testing::TestTableFloat* GetSizePrefixedTestTableFloat(const void* buf) { - return flatbuffers::GetSizePrefixedRoot(buf); -} - -inline bool VerifyTestTableFloatBuffer(flatbuffers::Verifier& verifier) { - return verifier.VerifyBuffer(nullptr); -} - -inline bool VerifySizePrefixedTestTableFloatBuffer(flatbuffers::Verifier& verifier) { - return verifier.VerifySizePrefixedBuffer(nullptr); -} - -inline const char* TestTableFloatExtension() { - return "bfbs"; -} - -inline void FinishTestTableFloatBuffer( - flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedTestTableFloatBuffer( - flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace testing - -#endif // FLATBUFFERS_GENERATED_FLOAT_TESTING_H_ diff --git a/system/gd/dumpsys/internal/test_data/integer_generated.h b/system/gd/dumpsys/internal/test_data/integer_generated.h deleted file mode 100644 index ffe69de0406eea28ed3ab9b17457ea6c63bd744c..0000000000000000000000000000000000000000 --- a/system/gd/dumpsys/internal/test_data/integer_generated.h +++ /dev/null @@ -1,86 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - -#ifndef FLATBUFFERS_GENERATED_INTEGER_TESTING_H_ -#define FLATBUFFERS_GENERATED_INTEGER_TESTING_H_ - -#include "flatbuffers/flatbuffers.h" - -// Ensure the included flatbuffers.h is the same version as when this file was -// generated, otherwise it may not be compatible. -static_assert( - FLATBUFFERS_VERSION_MAJOR == 2 && FLATBUFFERS_VERSION_MINOR == 0 && FLATBUFFERS_VERSION_REVISION == 7, - "Non-compatible flatbuffers version included"); - -namespace testing { - -struct TestTableInteger; -struct TestTableIntegerBuilder; - -struct TestTableInteger FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TestTableIntegerBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_TEST_INT = 4 }; - int32_t test_int() const { - return GetField(VT_TEST_INT, 0); - } - bool Verify(flatbuffers::Verifier& verifier) const { - return VerifyTableStart(verifier) && VerifyField(verifier, VT_TEST_INT, 4) && verifier.EndTable(); - } -}; - -struct TestTableIntegerBuilder { - typedef TestTableInteger Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_test_int(int32_t test_int) { - fbb_.AddElement(TestTableInteger::VT_TEST_INT, test_int, 0); - } - explicit TestTableIntegerBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateTestTableInteger( - flatbuffers::FlatBufferBuilder& _fbb, int32_t test_int = 0) { - TestTableIntegerBuilder builder_(_fbb); - builder_.add_test_int(test_int); - return builder_.Finish(); -} - -inline const testing::TestTableInteger* GetTestTableInteger(const void* buf) { - return flatbuffers::GetRoot(buf); -} - -inline const testing::TestTableInteger* GetSizePrefixedTestTableInteger(const void* buf) { - return flatbuffers::GetSizePrefixedRoot(buf); -} - -inline bool VerifyTestTableIntegerBuffer(flatbuffers::Verifier& verifier) { - return verifier.VerifyBuffer(nullptr); -} - -inline bool VerifySizePrefixedTestTableIntegerBuffer(flatbuffers::Verifier& verifier) { - return verifier.VerifySizePrefixedBuffer(nullptr); -} - -inline const char* TestTableIntegerExtension() { - return "bfbs"; -} - -inline void FinishTestTableIntegerBuffer( - flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedTestTableIntegerBuffer( - flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace testing - -#endif // FLATBUFFERS_GENERATED_INTEGER_TESTING_H_ diff --git a/system/gd/dumpsys/internal/test_data/string_generated.h b/system/gd/dumpsys/internal/test_data/string_generated.h deleted file mode 100644 index 83ea7fe1063adc2ab79f54dc6c700bfc3bd1bf00..0000000000000000000000000000000000000000 --- a/system/gd/dumpsys/internal/test_data/string_generated.h +++ /dev/null @@ -1,88 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - -#ifndef FLATBUFFERS_GENERATED_STRING_TESTING_H_ -#define FLATBUFFERS_GENERATED_STRING_TESTING_H_ - -#include "flatbuffers/flatbuffers.h" - -namespace testing { - -struct TestTableString; -struct TestTableStringBuilder; - -struct TestTableString FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TestTableStringBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_TEST_STRING = 4 }; - const flatbuffers::String* test_string() const { - return GetPointer(VT_TEST_STRING); - } - bool Verify(flatbuffers::Verifier& verifier) const { - return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TEST_STRING) && - verifier.VerifyString(test_string()) && verifier.EndTable(); - } -}; - -struct TestTableStringBuilder { - typedef TestTableString Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_test_string(flatbuffers::Offset test_string) { - fbb_.AddOffset(TestTableString::VT_TEST_STRING, test_string); - } - explicit TestTableStringBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - TestTableStringBuilder& operator=(const TestTableStringBuilder&); - flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateTestTableString( - flatbuffers::FlatBufferBuilder& _fbb, flatbuffers::Offset test_string = 0) { - TestTableStringBuilder builder_(_fbb); - builder_.add_test_string(test_string); - return builder_.Finish(); -} - -inline flatbuffers::Offset CreateTestTableStringDirect( - flatbuffers::FlatBufferBuilder& _fbb, const char* test_string = nullptr) { - auto test_string__ = test_string ? _fbb.CreateString(test_string) : 0; - return testing::CreateTestTableString(_fbb, test_string__); -} - -inline const testing::TestTableString* GetTestTableString(const void* buf) { - return flatbuffers::GetRoot(buf); -} - -inline const testing::TestTableString* GetSizePrefixedTestTableString(const void* buf) { - return flatbuffers::GetSizePrefixedRoot(buf); -} - -inline bool VerifyTestTableStringBuffer(flatbuffers::Verifier& verifier) { - return verifier.VerifyBuffer(nullptr); -} - -inline bool VerifySizePrefixedTestTableStringBuffer(flatbuffers::Verifier& verifier) { - return verifier.VerifySizePrefixedBuffer(nullptr); -} - -inline const char* TestTableStringExtension() { - return "bfbs"; -} - -inline void FinishTestTableStringBuffer( - flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedTestTableStringBuffer( - flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace testing - -#endif // FLATBUFFERS_GENERATED_STRING_TESTING_H_ diff --git a/system/gd/dumpsys/internal/test_data/struct_generated.h b/system/gd/dumpsys/internal/test_data/struct_generated.h deleted file mode 100644 index 44d08d719b3000439233d615fa1f822fce9dde7a..0000000000000000000000000000000000000000 --- a/system/gd/dumpsys/internal/test_data/struct_generated.h +++ /dev/null @@ -1,125 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - -#ifndef FLATBUFFERS_GENERATED_STRUCT_TESTING_H_ -#define FLATBUFFERS_GENERATED_STRUCT_TESTING_H_ - -#include "flatbuffers/flatbuffers.h" - -// Ensure the included flatbuffers.h is the same version as when this file was -// generated, otherwise it may not be compatible. -static_assert( - FLATBUFFERS_VERSION_MAJOR == 2 && FLATBUFFERS_VERSION_MINOR == 0 && FLATBUFFERS_VERSION_REVISION == 7, - "Non-compatible flatbuffers version included"); - -namespace testing { - -struct TestSubTable; -struct TestSubTableBuilder; - -struct TestTableStruct; -struct TestTableStructBuilder; - -struct TestSubTable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TestSubTableBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_PLACEHOLDER = 4 }; - int32_t placeholder() const { - return GetField(VT_PLACEHOLDER, 0); - } - bool Verify(flatbuffers::Verifier& verifier) const { - return VerifyTableStart(verifier) && VerifyField(verifier, VT_PLACEHOLDER, 4) && verifier.EndTable(); - } -}; - -struct TestSubTableBuilder { - typedef TestSubTable Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_placeholder(int32_t placeholder) { - fbb_.AddElement(TestSubTable::VT_PLACEHOLDER, placeholder, 0); - } - explicit TestSubTableBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateTestSubTable( - flatbuffers::FlatBufferBuilder& _fbb, int32_t placeholder = 0) { - TestSubTableBuilder builder_(_fbb); - builder_.add_placeholder(placeholder); - return builder_.Finish(); -} - -struct TestTableStruct FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TestTableStructBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_SUB_TABLE = 4 }; - const testing::TestSubTable* sub_table() const { - return GetPointer(VT_SUB_TABLE); - } - bool Verify(flatbuffers::Verifier& verifier) const { - return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SUB_TABLE) && verifier.VerifyTable(sub_table()) && - verifier.EndTable(); - } -}; - -struct TestTableStructBuilder { - typedef TestTableStruct Table; - flatbuffers::FlatBufferBuilder& fbb_; - flatbuffers::uoffset_t start_; - void add_sub_table(flatbuffers::Offset sub_table) { - fbb_.AddOffset(TestTableStruct::VT_SUB_TABLE, sub_table); - } - explicit TestTableStructBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset(end); - return o; - } -}; - -inline flatbuffers::Offset CreateTestTableStruct( - flatbuffers::FlatBufferBuilder& _fbb, flatbuffers::Offset sub_table = 0) { - TestTableStructBuilder builder_(_fbb); - builder_.add_sub_table(sub_table); - return builder_.Finish(); -} - -inline const testing::TestTableStruct* GetTestTableStruct(const void* buf) { - return flatbuffers::GetRoot(buf); -} - -inline const testing::TestTableStruct* GetSizePrefixedTestTableStruct(const void* buf) { - return flatbuffers::GetSizePrefixedRoot(buf); -} - -inline bool VerifyTestTableStructBuffer(flatbuffers::Verifier& verifier) { - return verifier.VerifyBuffer(nullptr); -} - -inline bool VerifySizePrefixedTestTableStructBuffer(flatbuffers::Verifier& verifier) { - return verifier.VerifySizePrefixedBuffer(nullptr); -} - -inline const char* TestTableStructExtension() { - return "bfbs"; -} - -inline void FinishTestTableStructBuffer( - flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedTestTableStructBuffer( - flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace testing - -#endif // FLATBUFFERS_GENERATED_STRUCT_TESTING_H_ diff --git a/system/gd/dumpsys/test_data/bar.h b/system/gd/dumpsys/test_data/bar.h index 5d6d0eead1b7b7d9ce632790704de8c5205e159f..0fa531b36ac5656737553b4f34dc75ad5911d474 100644 --- a/system/gd/dumpsys/test_data/bar.h +++ b/system/gd/dumpsys/test_data/bar.h @@ -9,8 +9,8 @@ namespace testing { class BarTestDataClass : public DumpsysTestDataClass { public: - TableAddFunction GetTable(flatbuffers::FlatBufferBuilder& fb_builder) override { - return [](DumpsysTestDataRootBuilder* builder) {}; + TableAddFunction GetTable(flatbuffers::FlatBufferBuilder& /* fb_builder */) override { + return [](DumpsysTestDataRootBuilder* /* builder */) {}; } }; diff --git a/system/gd/dumpsys_data.fbs b/system/gd/dumpsys_data.fbs index 326d211357f895989cc121ded0fda87168292c0b..e2e4454f3e788936877c3d060c09b3671d37c9b2 100644 --- a/system/gd/dumpsys_data.fbs +++ b/system/gd/dumpsys_data.fbs @@ -9,7 +9,6 @@ // privacy:"Any" -include "btaa/activity_attribution.fbs"; include "common/init_flags.fbs"; include "hci/hci_acl_manager.fbs"; include "hci/hci_controller.fbs"; @@ -31,7 +30,6 @@ table DumpsysData { hci_acl_manager_dumpsys_data:bluetooth.hci.AclManagerData (privacy:"Any"); hci_controller_dumpsys_data:bluetooth.hci.ControllerData (privacy:"Any"); module_unittest_data:bluetooth.ModuleUnitTestData; // private - activity_attribution_dumpsys_data:bluetooth.activity_attribution.ActivityAttributionData (privacy:"Any"); } root_type DumpsysData; diff --git a/system/gd/facade/facade_main.cc b/system/gd/facade/facade_main.cc index bda4e00b9dcfa4bd9fcce95ff7bdad9584776365..b16cde018bae2dc1094cd8abcd3861297e33b677 100644 --- a/system/gd/facade/facade_main.cc +++ b/system/gd/facade/facade_main.cc @@ -70,7 +70,7 @@ void interrupt_handler(int signal_number) { } struct sigaction new_act = {.sa_handler = interrupt_handler}; -bool crash_callback(const void* crash_context, size_t crash_context_size, void* context) { +bool crash_callback(const void* crash_context, size_t crash_context_size, void* /* context */) { std::optional tid; if (crash_context_size >= sizeof(google_breakpad::ExceptionHandler::CrashContext)) { auto* ctx = static_cast(crash_context); diff --git a/system/gd/facade/grpc_root_server.cc b/system/gd/facade/grpc_root_server.cc index 162405cf1d87072ffbceb70ccc5b79138db26da4..b53522d6bc182b99899a6ae341d554cd960dbe87 100644 --- a/system/gd/facade/grpc_root_server.cc +++ b/system/gd/facade/grpc_root_server.cc @@ -51,9 +51,9 @@ class RootFacadeService : public ::blueberry::facade::RootFacade::Service { explicit RootFacadeService(int grpc_port) : grpc_port_(grpc_port) {} ::grpc::Status StartStack( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::StartStackRequest* request, - ::blueberry::facade::StartStackResponse* response) override { + ::blueberry::facade::StartStackResponse* /* response */) override { if (is_running_) { return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is running"); } @@ -124,9 +124,9 @@ class RootFacadeService : public ::blueberry::facade::RootFacade::Service { } ::grpc::Status StopStack( - ::grpc::ServerContext* context, - const ::blueberry::facade::StopStackRequest* request, - ::blueberry::facade::StopStackResponse* response) override { + ::grpc::ServerContext* /* context */, + const ::blueberry::facade::StopStackRequest* /* request */, + ::blueberry::facade::StopStackResponse* /* response */) override { if (!is_running_) { return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is not running"); } diff --git a/system/gd/facade/read_only_property_server.cc b/system/gd/facade/read_only_property_server.cc index 6c3e262ff3c536c3e0353c9844b84e0a699d2011..36ddd3903fe9c84927631c9ece9a83a78712d281 100644 --- a/system/gd/facade/read_only_property_server.cc +++ b/system/gd/facade/read_only_property_server.cc @@ -25,8 +25,8 @@ class ReadOnlyPropertyService : public blueberry::facade::ReadOnlyProperty::Serv public: ReadOnlyPropertyService(hci::Controller* controller) : controller_(controller) {} ::grpc::Status ReadLocalAddress( - ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, ::blueberry::facade::BluetoothAddress* response) override { auto address = controller_->GetMacAddress().ToString(); response->set_address(address); diff --git a/system/gd/grpc/grpc_module.cc b/system/gd/grpc/grpc_module.cc index 3dd40ab811273830fa3dc469ce453e6e3d8b6a75..96200c07e8129e45606177012711b7b692415fd4 100644 --- a/system/gd/grpc/grpc_module.cc +++ b/system/gd/grpc/grpc_module.cc @@ -24,7 +24,7 @@ using ::grpc::ServerBuilder; namespace bluetooth { namespace grpc { -void GrpcModule::ListDependencies(ModuleList* list) const {} +void GrpcModule::ListDependencies(ModuleList* /* list */) const {} void GrpcModule::Start() { ASSERT(!started_); diff --git a/system/gd/hal/Android.bp b/system/gd/hal/Android.bp index 077152423d85a7cdce363d8a20f8c1997fead4c2..27e6b6f204821a7d4c23f54112cc063cdb7f3e4a 100644 --- a/system/gd/hal/Android.bp +++ b/system/gd/hal/Android.bp @@ -10,6 +10,7 @@ package { filegroup { name: "BluetoothHalSources", srcs: [ + "nocp_iso_clocker.cc", "snoop_logger.cc", "snoop_logger_socket.cc", "snoop_logger_socket_thread.cc", diff --git a/system/gd/hal/BUILD.gn b/system/gd/hal/BUILD.gn index fa9f3a64f62b7c247cc597670336282f51016d8f..67034e1cc069544a3cb30d2942ea3b1dfb051149 100644 --- a/system/gd/hal/BUILD.gn +++ b/system/gd/hal/BUILD.gn @@ -16,6 +16,7 @@ source_set("BluetoothHalSources") { sources = [ + "nocp_iso_clocker.cc", "snoop_logger.cc", "snoop_logger_socket.cc", "snoop_logger_socket_thread.cc", @@ -27,10 +28,17 @@ source_set("BluetoothHalSources") { } source_set("BluetoothHalSources_hci_host") { - sources = [ - "hci_hal_host.cc", - "mgmt.cc", - ] + if (use.floss_rootcanal) { + sources = [ + "hci_hal_host_rootcanal.cc", + "mgmt.cc", + ] + } else { + sources = [ + "hci_hal_host.cc", + "mgmt.cc", + ] + } configs += [ "//bt/system/gd:gd_defaults" ] deps = [ "//bt/system/gd:gd_default_deps" ] diff --git a/system/gd/hal/facade.cc b/system/gd/hal/facade.cc index 1e967ce734cc0367eeb32ed22d2ff6eb4fb73fa8..1182e4946478bb2047ccf9bcf1389bb621ac75e6 100644 --- a/system/gd/hal/facade.cc +++ b/system/gd/hal/facade.cc @@ -42,9 +42,9 @@ class HciHalFacadeService : public blueberry::facade::hal::HciHalFacade::Service } ::grpc::Status SendCommand( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::Data* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { std::unique_lock lock(mutex_); can_send_hci_command_ = false; std::string req_string = request->payload(); @@ -56,18 +56,18 @@ class HciHalFacadeService : public blueberry::facade::hal::HciHalFacade::Service } ::grpc::Status SendAcl( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::Data* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { std::string req_string = request->payload(); hal_->sendAclData(std::vector(req_string.begin(), req_string.end())); return ::grpc::Status::OK; } ::grpc::Status SendSco( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::Data* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { std::string req_string = request->payload(); hal_->sendScoData(std::vector(req_string.begin(), req_string.end())); return ::grpc::Status::OK; @@ -75,28 +75,28 @@ class HciHalFacadeService : public blueberry::facade::hal::HciHalFacade::Service ::grpc::Status StreamEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override { return pending_hci_events_.RunLoop(context, writer); }; ::grpc::Status StreamAcl( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override { return pending_acl_events_.RunLoop(context, writer); }; ::grpc::Status StreamSco( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override { return pending_sco_events_.RunLoop(context, writer); }; ::grpc::Status StreamIso( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override { return pending_iso_events_.RunLoop(context, writer); }; diff --git a/system/gd/hal/fuzz/fuzz_hci_hal.h b/system/gd/hal/fuzz/fuzz_hci_hal.h index 5a737844048c7114526ef61d413822c8e432dde4..b2c48a6c62d9a9310f41f7b053dca723619648a2 100644 --- a/system/gd/hal/fuzz/fuzz_hci_hal.h +++ b/system/gd/hal/fuzz/fuzz_hci_hal.h @@ -30,9 +30,9 @@ class FuzzHciHal : public HciHal { void unregisterIncomingPacketCallback() override; void sendHciCommand(HciPacket command) override; - void sendAclData(HciPacket packet) override {} - void sendScoData(HciPacket packet) override {} - void sendIsoData(HciPacket packet) override {} + void sendAclData(HciPacket /* packet */) override {} + void sendScoData(HciPacket /* packet */) override {} + void sendIsoData(HciPacket /* packet */) override {} void injectArbitrary(FuzzedDataProvider& fdp); @@ -43,7 +43,7 @@ class FuzzHciHal : public HciHal { static const ModuleFactory Factory; protected: - void ListDependencies(ModuleList* list) const override {} + void ListDependencies(ModuleList* /* list */) const override {} void Start() override {} void Stop() override {} diff --git a/system/gd/hal/hci_hal_android_hidl.cc b/system/gd/hal/hci_hal_android_hidl.cc index 4849894f2b7646da42e19d519b46026d2400531f..686b9510cf6d14fb1f47caf9bdf8770e608ab417 100644 --- a/system/gd/hal/hci_hal_android_hidl.cc +++ b/system/gd/hal/hci_hal_android_hidl.cc @@ -34,11 +34,11 @@ #include #include -#include "btaa/activity_attribution.h" #include "common/init_flags.h" #include "common/stop_watch.h" #include "common/strings.h" #include "hal/hci_hal.h" +#include "hal/nocp_iso_clocker.h" #include "hal/snoop_logger.h" #include "os/alarm.h" #include "os/log.h" @@ -62,9 +62,11 @@ namespace { class HciDeathRecipient : public ::android::hardware::hidl_death_recipient { public: virtual void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) { - LOG_ERROR("Bluetooth HAL service died. Calling exit(0);"); + LOG_ERROR("The Bluetooth HAL service died. Dumping logs and crashing in 1 second."); common::StopWatch::DumpStopWatchLog(); - exit(0); + // At shutdown, sometimes the HAL service gets killed before Bluetooth. + std::this_thread::sleep_for(std::chrono::seconds(1)); + LOG_ALWAYS_FATAL("The Bluetooth HAL died."); } }; @@ -81,8 +83,8 @@ std::string GetTimerText(const char* func_name, VecType vec) { class InternalHciCallbacks : public IBluetoothHciCallbacks_1_1 { public: - InternalHciCallbacks(activity_attribution::ActivityAttribution* btaa_logger_, SnoopLogger* btsnoop_logger) - : btaa_logger_(btaa_logger_), btsnoop_logger_(btsnoop_logger) { + InternalHciCallbacks(SnoopLogger* btsnoop_logger, NocpIsoClocker* nocp_iso_clocker) + : btsnoop_logger_(btsnoop_logger), nocp_iso_clocker_(nocp_iso_clocker) { init_promise_ = new std::promise(); } @@ -113,10 +115,9 @@ class InternalHciCallbacks : public IBluetoothHciCallbacks_1_1 { Return hciEventReceived(const hidl_vec& event) override { common::StopWatch stop_watch(GetTimerText(__func__, event)); std::vector received_hci_packet(event.begin(), event.end()); - btsnoop_logger_->Capture(received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::EVT); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(received_hci_packet, SnoopLogger::PacketType::EVT); - } + nocp_iso_clocker_->OnHciEvent(received_hci_packet); + btsnoop_logger_->Capture( + received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::EVT); { std::lock_guard incoming_packet_callback_lock(incoming_packet_callback_mutex_); if (callback_ != nullptr) { @@ -129,10 +130,8 @@ class InternalHciCallbacks : public IBluetoothHciCallbacks_1_1 { Return aclDataReceived(const hidl_vec& data) override { common::StopWatch stop_watch(GetTimerText(__func__, data)); std::vector received_hci_packet(data.begin(), data.end()); - btsnoop_logger_->Capture(received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::ACL); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(received_hci_packet, SnoopLogger::PacketType::ACL); - } + btsnoop_logger_->Capture( + received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::ACL); { std::lock_guard incoming_packet_callback_lock(incoming_packet_callback_mutex_); if (callback_ != nullptr) { @@ -145,11 +144,8 @@ class InternalHciCallbacks : public IBluetoothHciCallbacks_1_1 { Return scoDataReceived(const hidl_vec& data) override { common::StopWatch stop_watch(GetTimerText(__func__, data)); std::vector received_hci_packet(data.begin(), data.end()); - btsnoop_logger_->Capture(received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::SCO); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(received_hci_packet, SnoopLogger::PacketType::SCO); - } - + btsnoop_logger_->Capture( + received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::SCO); { std::lock_guard incoming_packet_callback_lock(incoming_packet_callback_mutex_); if (callback_ != nullptr) { @@ -177,8 +173,8 @@ class InternalHciCallbacks : public IBluetoothHciCallbacks_1_1 { std::mutex incoming_packet_callback_mutex_; std::promise* init_promise_ = nullptr; HciHalCallbacks* callback_ = nullptr; - activity_attribution::ActivityAttribution* btaa_logger_ = nullptr; SnoopLogger* btsnoop_logger_ = nullptr; + NocpIsoClocker* nocp_iso_clocker_ = nullptr; }; static constexpr char kBluetoothAidlHalServiceName[] = @@ -186,9 +182,8 @@ static constexpr char kBluetoothAidlHalServiceName[] = class AidlHciCallbacks : public ::aidl::android::hardware::bluetooth::BnBluetoothHciCallbacks { public: - AidlHciCallbacks( - activity_attribution::ActivityAttribution* btaa_logger_, SnoopLogger* btsnoop_logger) - : btaa_logger_(btaa_logger_), btsnoop_logger_(btsnoop_logger) { + AidlHciCallbacks(SnoopLogger* btsnoop_logger, NocpIsoClocker* nocp_iso_clocker) + : btsnoop_logger_(btsnoop_logger), nocp_iso_clocker_(nocp_iso_clocker) { init_promise_ = new std::promise(); } @@ -217,11 +212,9 @@ class AidlHciCallbacks : public ::aidl::android::hardware::bluetooth::BnBluetoot ::ndk::ScopedAStatus hciEventReceived(const std::vector& event) override { common::StopWatch stop_watch(GetTimerText(__func__, event)); std::vector received_hci_packet(event.begin(), event.end()); + nocp_iso_clocker_->OnHciEvent(received_hci_packet); btsnoop_logger_->Capture( received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::EVT); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(received_hci_packet, SnoopLogger::PacketType::EVT); - } bool sent = false; { std::lock_guard incoming_packet_callback_lock(incoming_packet_callback_mutex_); @@ -241,9 +234,6 @@ class AidlHciCallbacks : public ::aidl::android::hardware::bluetooth::BnBluetoot std::vector received_hci_packet(data.begin(), data.end()); btsnoop_logger_->Capture( received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::ACL); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(received_hci_packet, SnoopLogger::PacketType::ACL); - } bool sent = false; { std::lock_guard incoming_packet_callback_lock(incoming_packet_callback_mutex_); @@ -263,9 +253,6 @@ class AidlHciCallbacks : public ::aidl::android::hardware::bluetooth::BnBluetoot std::vector received_hci_packet(data.begin(), data.end()); btsnoop_logger_->Capture( received_hci_packet, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::SCO); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(received_hci_packet, SnoopLogger::PacketType::SCO); - } bool sent = false; { std::lock_guard incoming_packet_callback_lock(incoming_packet_callback_mutex_); @@ -303,8 +290,8 @@ class AidlHciCallbacks : public ::aidl::android::hardware::bluetooth::BnBluetoot std::mutex incoming_packet_callback_mutex_; std::promise* init_promise_ = nullptr; HciHalCallbacks* callback_ = nullptr; - activity_attribution::ActivityAttribution* btaa_logger_ = nullptr; SnoopLogger* btsnoop_logger_ = nullptr; + NocpIsoClocker* nocp_iso_clocker_ = nullptr; }; } // namespace @@ -330,10 +317,8 @@ class HciHalHidl : public HciHal { } void sendHciCommand(HciPacket command) override { - btsnoop_logger_->Capture(command, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(command, SnoopLogger::PacketType::CMD); - } + btsnoop_logger_->Capture( + command, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD); if (aidl_hci_) { aidl_hci_->sendHciCommand(command); } else { @@ -342,10 +327,8 @@ class HciHalHidl : public HciHal { } void sendAclData(HciPacket packet) override { - btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(packet, SnoopLogger::PacketType::ACL); - } + btsnoop_logger_->Capture( + packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL); if (aidl_hci_) { aidl_hci_->sendAclData(packet); } else { @@ -354,10 +337,8 @@ class HciHalHidl : public HciHal { } void sendScoData(HciPacket packet) override { - btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_->Capture(packet, SnoopLogger::PacketType::SCO); - } + btsnoop_logger_->Capture( + packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO); if (aidl_hci_) { aidl_hci_->sendScoData(packet); } else { @@ -381,10 +362,8 @@ class HciHalHidl : public HciHal { protected: void ListDependencies(ModuleList* list) const { + list->add(); list->add(); - if (common::init_flags::btaa_hci_is_enabled()) { - list->add(); - } } void Start() override { @@ -395,9 +374,7 @@ class HciHalHidl : public HciHal { ASSERT(bt_hci_1_1_ == nullptr); ASSERT(aidl_hci_ == nullptr); - if (common::init_flags::btaa_hci_is_enabled()) { - btaa_logger_ = GetDependency(); - } + nocp_iso_clocker_ = GetDependency(); btsnoop_logger_ = GetDependency(); if (AServiceManager_isDeclared(kBluetoothAidlHalServiceName)) { @@ -416,10 +393,12 @@ class HciHalHidl : public HciHal { if (aidl_hci_ != nullptr) { LOG_INFO("Using the AIDL interface"); aidl_death_recipient_ = - ::ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new([](void* cookie) { - LOG_ERROR("Bluetooth HAL service died. Calling exit(0);"); + ::ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new([](void* /* cookie*/) { + LOG_ERROR("The Bluetooth HAL service died. Dumping logs and crashing in 1 second."); common::StopWatch::DumpStopWatchLog(); - exit(0); + // At shutdown, sometimes the HAL service gets killed before Bluetooth. + std::this_thread::sleep_for(std::chrono::seconds(1)); + LOG_ALWAYS_FATAL("The Bluetooth HAL died."); })); auto death_link = @@ -428,7 +407,8 @@ class HciHalHidl : public HciHal { ASSERT_LOG( death_link == STATUS_OK, "Unable to set the death recipient for the Bluetooth HAL"); - aidl_callbacks_ = ::ndk::SharedRefBase::make(btaa_logger_, btsnoop_logger_); + aidl_callbacks_ = + ::ndk::SharedRefBase::make(btsnoop_logger_, nocp_iso_clocker_); aidl_hci_->initialize(aidl_callbacks_); } } @@ -468,7 +448,7 @@ class HciHalHidl : public HciHal { ASSERT(bt_hci_ != nullptr); auto death_link = bt_hci_->linkToDeath(hci_death_recipient_, 0); ASSERT_LOG(death_link.isOk(), "Unable to set the death recipient for the Bluetooth HAL"); - hidl_callbacks_ = new InternalHciCallbacks(btaa_logger_, btsnoop_logger_); + hidl_callbacks_ = new InternalHciCallbacks(btsnoop_logger_, nocp_iso_clocker_); if (bt_hci_1_1_ != nullptr) { bt_hci_1_1_->initialize_1_1(hidl_callbacks_); @@ -526,8 +506,8 @@ class HciHalHidl : public HciHal { std::shared_ptr aidl_hci_; std::shared_ptr aidl_callbacks_; ::ndk::ScopedAIBinder_DeathRecipient aidl_death_recipient_; - activity_attribution::ActivityAttribution* btaa_logger_; SnoopLogger* btsnoop_logger_; + NocpIsoClocker* nocp_iso_clocker_; }; const ModuleFactory HciHal::Factory = ModuleFactory([]() { return new HciHalHidl(); }); diff --git a/system/gd/hal/hci_hal_fake.h b/system/gd/hal/hci_hal_fake.h index d9ebb0564c60f52ce5ba64de4bdf191bf8ecb91d..dbccb97a0d23f022c01f20937b49ad551644c2e9 100644 --- a/system/gd/hal/hci_hal_fake.h +++ b/system/gd/hal/hci_hal_fake.h @@ -76,7 +76,7 @@ class TestHciHal : public hal::HciHal { void Stop() {} - void ListDependencies(ModuleList*) const {} + void ListDependencies(ModuleList* /* list */) const {} std::string ToString() const override { return std::string("TestHciHal"); diff --git a/system/gd/hal/hci_hal_host.cc b/system/gd/hal/hci_hal_host.cc index 685590e623c2fbf9db5fda4ebf0ceef98ffa8c36..b3d9c0840c55d48992c41071c38f5d9fbeb5b471 100644 --- a/system/gd/hal/hci_hal_host.cc +++ b/system/gd/hal/hci_hal_host.cc @@ -31,6 +31,7 @@ #include "gd/common/init_flags.h" #include "hal/hci_hal.h" #include "hal/mgmt.h" +#include "hal/nocp_iso_clocker.h" #include "hal/snoop_logger.h" #include "metrics/counter_metrics.h" #include "os/log.h" @@ -60,7 +61,6 @@ constexpr uint16_t HCI_DEV_NONE = 0xffff; /* reference from /include/net/bluetooth/mgmt.h */ #define MGMT_OP_INDEX_LIST 0x0003 -#define MGMT_EV_INDEX_ADDED 0x0004 #define MGMT_EV_COMMAND_COMP 0x0001 #define MGMT_EV_SIZE_MAX 1024 #define REPEAT_ON_INTR(fn) \ @@ -145,23 +145,35 @@ int waitHciDev(int hci_interface) { break; } - if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) { - close(fd); - return -1; - } else if (ev.opcode == MGMT_EV_COMMAND_COMP) { + if (ev.opcode == MGMT_EV_COMMAND_COMP) { struct mgmt_event_read_index* cc; int i; cc = (struct mgmt_event_read_index*)ev.data; - if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue; - - for (i = 0; i < cc->num_intf; i++) { - if (cc->index[i] == hci_interface) { - close(fd); - return 0; + if (cc->cc_opcode != MGMT_OP_INDEX_LIST) continue; + + // Find the interface in the list of available indices. If unavailable, + // the result is -1. + ret = -1; + if (cc->status == 0) { + for (i = 0; i < cc->num_intf; i++) { + if (cc->index[i] == hci_interface) { + ret = 0; + break; + } } + + // Chipset might be lost. Wait for index added event. + LOG_ERROR("HCI interface(%d) not found in the MGMT lndex list", hci_interface); + } else { + // Unlikely event (probably developer error or driver shut down). + LOG_ERROR("Failed to read index list: status(%d)", cc->status); } + + // Close and return result of Index List. + close(fd); + return ret; } } } @@ -273,6 +285,7 @@ class HciHalHost : public HciHal { protected: void ListDependencies(ModuleList* list) const { + list->add(); list->add(); list->add(); } @@ -281,12 +294,20 @@ class HciHalHost : public HciHal { std::lock_guard lock(api_mutex_); ASSERT(sock_fd_ == INVALID_FD); sock_fd_ = ConnectToSocket(); - ASSERT(sock_fd_ != INVALID_FD); + + // We don't want to crash when the chipset is broken. + if (sock_fd_ == INVALID_FD) { + LOG_ERROR("Failed to connect to HCI socket. Aborting HAL initialization process."); + raise(SIGINT); + return; + } + reactable_ = hci_incoming_thread_.GetReactor()->Register( sock_fd_, common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)), common::Bind(&HciHalHost::send_packet_ready, common::Unretained(this))); hci_incoming_thread_.GetReactor()->ModifyRegistration(reactable_, os::Reactor::REACT_ON_READ_ONLY); + nocp_iso_clocker_ = GetDependency(); btsnoop_logger_ = GetDependency(); LOG_INFO("HAL opened successfully"); } @@ -327,6 +348,7 @@ class HciHalHost : public HciHal { bluetooth::os::Reactor::Reactable* reactable_ = nullptr; std::queue> hci_outgoing_queue_; SnoopLogger* btsnoop_logger_ = nullptr; + NocpIsoClocker* nocp_iso_clocker_ = nullptr; void write_to_fd(HciPacket packet) { // TODO: replace this with new queue when it's ready @@ -362,7 +384,15 @@ class HciHalHost : public HciHal { ssize_t received_size; RUN_NO_INTR(received_size = read(sock_fd_, buf, kBufSize)); - ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno)); + + // we don't want crash when the chipset is broken. + if (received_size == -1) { + LOG_ERROR("Can't receive from socket: %s", strerror(errno)); + close(sock_fd_); + raise(SIGINT); + return; + } + if (received_size == 0) { LOG_WARN("Can't read H4 header. EOF received"); // First close sock fd before raising sigint @@ -384,6 +414,7 @@ class HciHalHost : public HciHal { HciPacket receivedHciPacket; receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciEvtHeaderSize + payload_size); + nocp_iso_clocker_->OnHciEvent(receivedHciPacket); btsnoop_logger_->Capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::EVT); { std::lock_guard incoming_packet_callback_lock(incoming_packet_callback_mutex_); diff --git a/system/gd/hal/mgmt.cc b/system/gd/hal/mgmt.cc index f07b0d10434de353975b9e973e583ef1e5665839..5e406448865fefe6567b2f0634f0ae4ac1aa2ce6 100644 --- a/system/gd/hal/mgmt.cc +++ b/system/gd/hal/mgmt.cc @@ -23,11 +23,12 @@ #include "hal/mgmt.h" -#include #include #include #include +#include + #include "common/init_flags.h" #include "os/log.h" diff --git a/system/gd/hal/nocp_iso_clocker.cc b/system/gd/hal/nocp_iso_clocker.cc new file mode 100644 index 0000000000000000000000000000000000000000..1fb1c500eb2a6dd5536af282a6ab0eee9cf04d76 --- /dev/null +++ b/system/gd/hal/nocp_iso_clocker.cc @@ -0,0 +1,127 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hal/nocp_iso_clocker.h" + +namespace bluetooth::hal { + +static class : public NocpIsoHandler { + void OnEvent(uint32_t, int) override {} +} g_empty_handler; + +static std::atomic g_handler = &g_empty_handler; + +NocpIsoClocker::NocpIsoClocker() : cig_id_(-1), cis_handle_(-1) {} + +void NocpIsoClocker::OnHciEvent(const HciPacket& packet) { + const int HCI_CMD_SET_CIG_PARAMETERS = 0x2062; + const int HCI_EVT_COMMAND_COMPLETE = 0x0e; + const int HCI_EVT_NUMBER_OF_COMPLETED_PACKETS = 0x13; + + // HCI Event [Core 4.E.5.4.4] + // | [0] Event Code + // | [1] Parameter Total Length + // | [2+] Parameters + + if (packet.size() < 2) return; + + const uint8_t* payload = packet.data() + 2; + size_t payload_length = std::min(size_t(packet[1]), packet.size() - 2); + + switch (packet[0]) { + // HCI Command Complete Event [Core 4.E.7.7.14] + // | [0] Num_HCI_Command_Packets, Ignored + // | [1..2] Command_Opcode, catch `HCI_LE_Set_CIG_Parameters` + // | [3+] Return Parameters + + case HCI_EVT_COMMAND_COMPLETE: { + if (payload_length < 3) return; + + int cmd_opcode = payload[1] | (payload[2] << 8); + if (cmd_opcode != HCI_CMD_SET_CIG_PARAMETERS) return; + + const uint8_t* parameters = payload + 3; + size_t parameters_length = payload_length - 3; + + // HCI LE Set CIG Parameters return parameters [4.E.7.8.97] + // | [0] Status, 0 when OK + // | [1] CIG_ID + // | [2] CIS_Count + // | [3..4] Connection_Handle[0] + + if (parameters_length < 3) return; + + int status = parameters[0]; + int cig_id = parameters[1]; + int cis_count = parameters[2]; + + if (status != 0) return; + + if (cig_id_ >= 0 && cis_handle_ >= 0 && cig_id_ != cig_id) { + LOG_WARN("Multiple groups not supported"); + return; + } + + cig_id_ = -1; + cis_handle_ = -1; + + if (cis_count > 0 && parameters_length >= 5) { + cig_id_ = cig_id; + cis_handle_ = (parameters[3] | (parameters[4] << 8)) & 0xfff; + } + + break; + } + + // HCI Number Of Completed Packets event [Core 4.E.7.7.19] + // | [0] Num_Handles + // | FOR each `Num_Handles` connection handles + // | | [0..1] Connection_Handle, catch the CIS Handle + // | | [2..3] Num_Completed_Packets + + case HCI_EVT_NUMBER_OF_COMPLETED_PACKETS: { + if (payload_length < 1) return; + + int i, num_handles = payload[0]; + const uint8_t* item = payload + 1; + if (payload_length < size_t(1 + 4 * num_handles)) return; + + for (i = 0; i < num_handles && ((item[0] | (item[1] << 8)) & 0xfff) != cis_handle_; + i++, item += 4) + ; + if (i >= num_handles) return; + + auto timestamp = std::chrono::system_clock::now().time_since_epoch(); + unsigned timestamp_us = + std::chrono::duration_cast(timestamp).count(); + int num_of_completed_packets = item[2] | (item[3] << 8); + (*g_handler).OnEvent(timestamp_us, num_of_completed_packets); + + break; + } + } +} + +void NocpIsoClocker::Register(NocpIsoHandler* handler) { + g_handler = handler; +} +void NocpIsoClocker::Unregister() { + g_handler = &g_empty_handler; +} + +const ModuleFactory NocpIsoClocker::Factory = ModuleFactory([]() { return new NocpIsoClocker(); }); + +} // namespace bluetooth::hal diff --git a/system/gd/hal/nocp_iso_clocker.h b/system/gd/hal/nocp_iso_clocker.h new file mode 100644 index 0000000000000000000000000000000000000000..e8d860403a372d55281a06f069ce3376cd45a99e --- /dev/null +++ b/system/gd/hal/nocp_iso_clocker.h @@ -0,0 +1,55 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hci_hal.h" +#include "module.h" + +namespace bluetooth::hal { + +class NocpIsoHandler { + public: + virtual ~NocpIsoHandler() = default; + virtual void OnEvent(uint32_t timestamp_us, int num_of_completed_packets) = 0; +}; + +class NocpIsoClocker : public ::bluetooth::Module { + public: + static const ModuleFactory Factory; + + void OnHciEvent(const HciPacket& packet); + + static void Register(NocpIsoHandler* handler); + static void Unregister(); + + protected: + void ListDependencies(ModuleList*) const override{}; + void Start() override{}; + void Stop() override{}; + + std::string ToString() const override { + return std::string("NocpIsoClocker"); + } + + NocpIsoClocker(); + + private: + int cig_id_; + int cis_handle_; +}; + +} // namespace bluetooth::hal diff --git a/system/gd/hal/snoop_logger.cc b/system/gd/hal/snoop_logger.cc index 6e97abd7254d7050b84662d5f0dbfcf50a09786d..6efb3c807d3cf3f360863d3012170df279e4dcfa 100644 --- a/system/gd/hal/snoop_logger.cc +++ b/system/gd/hal/snoop_logger.cc @@ -28,17 +28,18 @@ #include "common/init_flags.h" #include "common/strings.h" #include "hal/snoop_logger_common.h" -#include "hal/syscall_wrapper_impl.h" -#include "os/fake_timer/fake_timerfd.h" +#include "module_dumper_flatbuffer.h" #include "os/files.h" #include "os/log.h" #include "os/parameter_provider.h" #include "os/system_properties.h" -namespace bluetooth { #ifdef USE_FAKE_TIMERS -using os::fake_timer::fake_timerfd_get_clock; +#include "os/fake_timer/fake_timerfd.h" +using bluetooth::os::fake_timer::fake_timerfd_get_clock; #endif + +namespace bluetooth { namespace hal { // Adds L2CAP channel to acceptlist. @@ -214,11 +215,11 @@ void ProfilesFilter::PrintProfilesConfig() { for (int i = 0; i < FILTER_PROFILE_MAX; i++) { if (profiles[i].enabled) { LOG_DEBUG( - "\ntype: %s \ - \nenabled: %d, l2cap_opened: %d, rfcomm_opened: %d\ - \nflow_ext_l2cap: %d, flow_ext_rfcomm: %d\ - \nlcid: %d, rcid: %d, rfcomm_uuid: %d, psm: %d\ - \nscn: %d \n", + "\ntype: %s" + "\nenabled: %d, l2cap_opened: %d, rfcomm_opened: %d" + "\nflow_ext_l2cap: %d, flow_ext_rfcomm: %d" + "\nlcid: %d, rcid: %d, rfcomm_uuid: %d, psm: %d" + "\nscn: %d\n", ProfilesFilter::ProfileToString(profiles[i].type).c_str(), profiles[i].enabled, profiles[i].l2cap_opened, @@ -496,11 +497,6 @@ SnoopLogger::SnoopLogger( snoop_log_persists(snoop_log_persists) { btsnoop_mode_ = btsnoop_mode; - if (btsnoop_mode_ == kBtSnoopLogModeFiltered && - !bluetooth::common::InitFlags::IsSnoopLoggerFilteringEnabled()) { - btsnoop_mode_ = kBtSnoopLogModeDisabled; - } - if (btsnoop_mode_ == kBtSnoopLogModeFiltered) { LOG_INFO("Snoop Logs filtered mode enabled"); EnableFilters(); @@ -648,7 +644,8 @@ bool SnoopLogger::ShouldFilterLog(bool is_received, uint8_t* packet) { return false; } -void SnoopLogger::CalculateAclPacketLength(uint32_t& length, uint8_t* packet, bool is_received) { +void SnoopLogger::CalculateAclPacketLength( + uint32_t& length, uint8_t* packet, bool /* is_received */) { uint32_t def_len = ((((uint16_t)packet[ACL_LENGTH_OFFSET + 1]) << 8) + packet[ACL_LENGTH_OFFSET]) + ACL_HEADER_LENGTH + PACKET_TYPE_LENGTH; @@ -1259,7 +1256,7 @@ void SnoopLogger::Capture(HciPacket& packet, Direction direction, PacketType typ if (socket_ != nullptr) { socket_->Write(&header, sizeof(PacketHeaderType)); - socket_->Write(packet.data(), packet.size()); + socket_->Write(packet.data(), (size_t)(length - 1)); } // std::ofstream::flush() pushes user data into kernel memory. The data will be written even if this process @@ -1314,7 +1311,7 @@ void SnoopLogger::DumpSnoozLogToFile(const std::vector& data) const } } -void SnoopLogger::ListDependencies(ModuleList* list) const { +void SnoopLogger::ListDependencies(ModuleList* /* list */) const { // We have no dependencies } @@ -1327,18 +1324,17 @@ void SnoopLogger::Start() { EnableFilters(); } - if (bluetooth::common::InitFlags::IsSnoopLoggerSocketEnabled()) { - auto snoop_logger_socket = std::make_unique(&syscall_if); - snoop_logger_socket_thread_ = std::make_unique(std::move(snoop_logger_socket)); - auto thread_started_future = snoop_logger_socket_thread_->Start(); - thread_started_future.wait(); - if (thread_started_future.get()) { - RegisterSocket(snoop_logger_socket_thread_.get()); - } else { - snoop_logger_socket_thread_->Stop(); - snoop_logger_socket_thread_.reset(); - snoop_logger_socket_thread_ = nullptr; - } + auto snoop_logger_socket = std::make_unique(&syscall_if); + snoop_logger_socket_thread_ = + std::make_unique(std::move(snoop_logger_socket)); + auto thread_started_future = snoop_logger_socket_thread_->Start(); + thread_started_future.wait(); + if (thread_started_future.get()) { + RegisterSocket(snoop_logger_socket_thread_.get()); + } else { + snoop_logger_socket_thread_->Stop(); + snoop_logger_socket_thread_.reset(); + snoop_logger_socket_thread_ = nullptr; } } alarm_ = std::make_unique(GetHandler()); @@ -1371,10 +1367,11 @@ void SnoopLogger::Stop() { } } -DumpsysDataFinisher SnoopLogger::GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const { +DumpsysDataFinisher SnoopLogger::GetDumpsysData( + flatbuffers::FlatBufferBuilder* /* builder */) const { LOG_DEBUG("Dumping btsnooz log data to %s", snooz_log_path_.c_str()); DumpSnoozLogToFile(btsnooz_buffer_.Pull()); - return Module::GetDumpsysData(builder); + return EmptyDumpsysDataFinisher; } size_t SnoopLogger::GetMaxPacketsPerFile() { diff --git a/system/gd/hal/snoop_logger.h b/system/gd/hal/snoop_logger.h index 369de043b4117d7a28bc360f900df4e471132962..7eb1d1f7220d2b22b521e6e78ab93fbe01af6e98 100644 --- a/system/gd/hal/snoop_logger.h +++ b/system/gd/hal/snoop_logger.h @@ -17,14 +17,13 @@ #pragma once #include -#include -#include #include #include #include #include "common/circular_buffer.h" #include "hal/hci_hal.h" +#include "hal/snoop_logger_socket_interface.h" #include "hal/snoop_logger_socket_thread.h" #include "hal/syscall_wrapper_impl.h" #include "module.h" diff --git a/system/gd/hal/snoop_logger_socket.cc b/system/gd/hal/snoop_logger_socket.cc index fc46d4495e5245a123566c0c3c7038cd171ab928..74bbb258dc07c760b706bba2f177c6ad67a1be1d 100644 --- a/system/gd/hal/snoop_logger_socket.cc +++ b/system/gd/hal/snoop_logger_socket.cc @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -33,13 +32,12 @@ #include #include +#include #include #include "common/init_flags.h" #include "hal/snoop_logger_common.h" -#include "os/handler.h" #include "os/log.h" -#include "os/thread.h" #include "os/utils.h" namespace bluetooth { diff --git a/system/gd/hal/snoop_logger_socket_test.cc b/system/gd/hal/snoop_logger_socket_test.cc index 1fbba4c173e717e1fabb32ac214f158e391874e5..da379abc59f1484bdb8dff4f03cc983ed69f3627 100644 --- a/system/gd/hal/snoop_logger_socket_test.cc +++ b/system/gd/hal/snoop_logger_socket_test.cc @@ -14,21 +14,19 @@ * limitations under the License. */ -#include +#include "hal/snoop_logger_socket.h" + #include #include #include #include -#include +#include #include "common/init_flags.h" #include "hal/snoop_logger_common.h" -#include "hal/snoop_logger_socket_thread.h" #include "hal/syscall_wrapper_impl.h" #include "hal/syscall_wrapper_mock.h" -#include "os/log.h" -#include "os/utils.h" static const char* test_flags[] = { "INIT_logging_debug_enabled_for_all=true", @@ -233,15 +231,17 @@ TEST_F(SnoopLoggerSocketModuleTest, test_Write_fd_fail_on_Send_EINTR) { char data[10]; int intr_count = 5; - ON_CALL(mock, Send).WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags) { - if (intr_count > 0) { - intr_count--; - errno = EINTR; - return -1; - } - errno = 0; - return 0; - })); + ON_CALL(mock, Send) + .WillByDefault( + Invoke([&](int /* fd */, const void* /* buf */, size_t /* n */, int /* flags */) { + if (intr_count > 0) { + intr_count--; + errno = EINTR; + return -1; + } + errno = 0; + return 0; + })); EXPECT_CALL(mock, Send(Eq(fd), Eq(data), Eq(sizeof(data)), _)).Times(intr_count + 1); @@ -313,7 +313,10 @@ TEST_F(SnoopLoggerSocketModuleTest, test_AcceptIncomingConnection_fail_on_accept int intr_count = 5; ON_CALL(mock, Accept(Eq(fd), _, _, _)) - .WillByDefault(Invoke([&](int fd, struct sockaddr* addr, socklen_t* addr_len, int flags) { + .WillByDefault(Invoke([&](int /* fd */, + struct sockaddr* /* addr */, + socklen_t* /* addr_len */, + int /* flags */) { if (intr_count > 0) { intr_count--; errno = EINTR; @@ -356,7 +359,7 @@ TEST_F(SnoopLoggerSocketModuleTest, test_AcceptIncomingConnection_success) { TEST_F(SnoopLoggerSocketModuleTest, test_InitializeCommunications_fail_on_Pipe2) { int ret = -9; - ON_CALL(mock, Pipe2(_, _)).WillByDefault(Invoke([ret](int* fds, int) { return ret; })); + ON_CALL(mock, Pipe2(_, _)).WillByDefault(Invoke([ret](int* /* fds */, int) { return ret; })); EXPECT_CALL(mock, FDZero); EXPECT_CALL(mock, Pipe2(_, _)); diff --git a/system/gd/hal/snoop_logger_socket_thread.cc b/system/gd/hal/snoop_logger_socket_thread.cc index fa6160ec14ef6678d36442d9dfc4d4eed474ada2..9ce6e6ee199ef4951546b7ecd61ded44bb367b78 100644 --- a/system/gd/hal/snoop_logger_socket_thread.cc +++ b/system/gd/hal/snoop_logger_socket_thread.cc @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -33,14 +32,9 @@ #include #include -#include - #include "common/init_flags.h" #include "hal/snoop_logger_common.h" -#include "os/handler.h" #include "os/log.h" -#include "os/thread.h" -#include "os/utils.h" namespace bluetooth { namespace hal { diff --git a/system/gd/hal/snoop_logger_test.cc b/system/gd/hal/snoop_logger_test.cc index c53bf30b1c75f82fec4e58a4aeaa641f38169ba1..1536958c94164024cd61639763695ef4e27e2a3a 100644 --- a/system/gd/hal/snoop_logger_test.cc +++ b/system/gd/hal/snoop_logger_test.cc @@ -115,8 +115,6 @@ using namespace std::chrono_literals; const char* test_flags[] = { "INIT_logging_debug_enabled_for_all=true", - "INIT_gd_hal_snoop_logger_socket=true", - "INIT_gd_hal_snoop_logger_filtering=true", nullptr, }; @@ -1544,7 +1542,7 @@ TEST_F(SnoopLoggerModuleTest, custom_socket_interface_register_logging_disabled_ SnoopLoggerSocketMock() { write_called = false; } - virtual void Write(const void* data, size_t length) { + virtual void Write(const void* /* data */, size_t /* length */) { write_called = true; } }; @@ -1575,7 +1573,7 @@ TEST_F(SnoopLoggerModuleTest, custom_socket_interface_register_logging_enabled_t SnoopLoggerSocketMock() { write_called = false; } - virtual void Write(const void* data, size_t length) { + virtual void Write(const void* /* data */, size_t /* length */) { write_called = true; } }; @@ -1589,4 +1587,117 @@ TEST_F(SnoopLoggerModuleTest, custom_socket_interface_register_logging_enabled_t test_registry->StopAll(); } + +TEST_F(SnoopLoggerModuleTest, custom_socket_profiles_filtered_hfp_hf_test) { + uint16_t conn_handle = 0x000b; + uint16_t local_cid = 0x0043; + uint16_t remote_cid = 0x3040; + uint8_t dlci = 0x06; + uint16_t psm = 0x0003; + uint16_t profile_uuid_hfp_hf = 0x111f; + bool flow = true; + const std::string clcc_pattern = "\x0d\x0a+CLCC:"; + const uint16_t HEADER_SIZE = 12; + size_t expected_data_size = HEADER_SIZE + strlen(clcc_pattern.c_str()); + std::vector kPhoneNumber = { + 0x0b, 0x00, 0x30, 0x00, 0x2c, 0x00, 0x40, 0x30, 0x19, 0xff, 0x4f, 0x01, 0x0d, + 0x0a, 0x2b, 0x43, 0x4c, 0x43, 0x43, 0x3a, 0x20, 0x31, 0x2c, 0x31, 0x2c, 0x34, + 0x2c, 0x30, 0x2c, 0x30, 0x2c, 0x22, 0x2b, 0x39, 0x39, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x22, 0x2c, 0x31, 0x34, 0x35, 0x0d, 0x0a, 0x49, + }; + + // Set pbap and map filtering modes + ASSERT_TRUE(bluetooth::os::SetSystemProperty( + SnoopLogger::kBtSnoopLogFilterProfilePbapModeProperty, + SnoopLogger::kBtSnoopLogFilterProfileModeMagic)); + auto filterPbapModeProperty = + bluetooth::os::GetSystemProperty(SnoopLogger::kBtSnoopLogFilterProfilePbapModeProperty); + ASSERT_TRUE( + filterPbapModeProperty && + (filterPbapModeProperty->find(SnoopLogger::kBtSnoopLogFilterProfileModeMagic) != + std::string::npos)); + ASSERT_TRUE(bluetooth::os::SetSystemProperty( + SnoopLogger::kBtSnoopLogFilterProfileMapModeProperty, + SnoopLogger::kBtSnoopLogFilterProfileModeMagic)); + auto filterMapModeProperty = + bluetooth::os::GetSystemProperty(SnoopLogger::kBtSnoopLogFilterProfileMapModeProperty); + ASSERT_TRUE( + filterMapModeProperty && + (filterMapModeProperty->find(SnoopLogger::kBtSnoopLogFilterProfileModeMagic) != + std::string::npos)); + + auto* snoop_logger = new TestSnoopLoggerModule( + temp_snoop_log_.string(), + temp_snooz_log_.string(), + 10, + SnoopLogger::kBtSnoopLogModeFiltered, + false, + false); + + test_registry->InjectTestModule(&SnoopLogger::Factory, snoop_logger); + + int new_port = 8873; + SyscallWrapperImpl syscall_if; + auto sls = std::make_unique( + &syscall_if, SnoopLoggerSocket::DEFAULT_LOCALHOST_, new_port); + SnoopLoggerSocketThread slsThread(std::move(sls)); + auto thread_start_future = slsThread.Start(); + thread_start_future.wait(); + ASSERT_TRUE(thread_start_future.get()); + + snoop_logger->RegisterSocket(&slsThread); + + snoop_logger->SetL2capChannelOpen(conn_handle, local_cid, remote_cid, psm, false); + snoop_logger->SetRfcommPortOpen(conn_handle, local_cid, dlci, profile_uuid_hfp_hf, flow); + + // // Create a TCP socket file descriptor + int socket_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP); + ASSERT_TRUE(socket_fd != INVALID_FD); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(SnoopLoggerSocket::DEFAULT_LOCALHOST_); + addr.sin_port = htons(new_port); + + int ret = 0; + // Connect to snoop logger socket + RUN_NO_INTR(ret = connect(socket_fd, (struct sockaddr*)&addr, sizeof(addr))); + ASSERT_TRUE(ret == 0); + + char recv_buf1[sizeof(SnoopLoggerCommon::FileHeaderType)]; + char recv_buf2[sizeof(SnoopLogger::PacketHeaderType)]; + char recv_buf3[kPhoneNumber.size()]; + int bytes_read = -1; + + auto a = std::async(std::launch::async, [socket_fd, &recv_buf1, &recv_buf2, &recv_buf3] { + recv(socket_fd, recv_buf1, sizeof(recv_buf1), 0); + recv(socket_fd, recv_buf2, sizeof(recv_buf2), 0); + return recv(socket_fd, recv_buf3, sizeof(recv_buf3), 0); + }); + + slsThread.GetSocket()->WaitForClientSocketConnected(); + + snoop_logger->Capture( + kPhoneNumber, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL); + snoop_logger->SetL2capChannelClose(conn_handle, local_cid, remote_cid); + snoop_logger->SetRfcommPortClose(conn_handle, local_cid, dlci, profile_uuid_hfp_hf); + + a.wait(); + bytes_read = a.get(); + + ASSERT_TRUE( + std::memcmp(recv_buf1, &SnoopLoggerCommon::kBtSnoopFileHeader, sizeof(recv_buf1)) == 0); + ASSERT_EQ(bytes_read, static_cast(expected_data_size)); + ASSERT_TRUE(std::memcmp(recv_buf3, kPhoneNumber.data(), expected_data_size) == 0); + + ASSERT_TRUE(bluetooth::os::SetSystemProperty( + SnoopLogger::kBtSnoopLogFilterProfileMapModeProperty, + SnoopLogger::kBtSnoopLogFilterProfileModeDisabled)); + ASSERT_TRUE(bluetooth::os::SetSystemProperty( + SnoopLogger::kBtSnoopLogFilterProfilePbapModeProperty, + SnoopLogger::kBtSnoopLogFilterProfileModeDisabled)); + + test_registry->StopAll(); + close(socket_fd); +} } // namespace testing diff --git a/system/gd/hal/syscall_wrapper_impl.cc b/system/gd/hal/syscall_wrapper_impl.cc index d9d322d54f0cbb988f868ad29e66d7e765cc2d45..4fda7909cd298f02eb214c554cbcc0e7a49eb910 100644 --- a/system/gd/hal/syscall_wrapper_impl.cc +++ b/system/gd/hal/syscall_wrapper_impl.cc @@ -18,9 +18,10 @@ #include "hal/syscall_wrapper_impl.h" -#include #include +#include + namespace bluetooth { namespace hal { diff --git a/system/gd/hci/Android.bp b/system/gd/hci/Android.bp index ce384a2bf41b76ad1fb7e6e32f4111c31155afcc..530cb7b823463e340bbd95b786d9b581301d5f54 100644 --- a/system/gd/hci/Android.bp +++ b/system/gd/hci/Android.bp @@ -7,19 +7,9 @@ package { default_applicable_licenses: ["system_bt_license"], } -filegroup { - name: "BluetoothHciPacketSources", - srcs: [ - "address.cc", - "class_of_device.cc", - ], - visibility: ["//visibility:public"], -} - filegroup { name: "BluetoothHciSources", srcs: [ - ":BluetoothHciPacketSources", "acl_manager.cc", "acl_manager/acl_connection.cc", "acl_manager/acl_fragmenter.cc", @@ -50,6 +40,7 @@ filegroup { "acl_builder_test.cc", "acl_manager/acl_scheduler_test.cc", "acl_manager/classic_acl_connection_test.cc", + "acl_manager/classic_impl_test.cc", "acl_manager/le_acl_connection_test.cc", "acl_manager/le_impl_test.cc", "acl_manager/round_robin_scheduler_test.cc", @@ -102,10 +93,3 @@ filegroup { "fuzz/status_vs_complete_commands.cc", ], } - -filegroup { - name: "BluetoothHciPackets", - srcs: [ - "hci_packets.pdl", - ], -} diff --git a/system/gd/hci/acl_manager.cc b/system/gd/hci/acl_manager.cc index cb5ca5172dc65450115708f9dafd770f2b93da71..6f58a4ac8bff36c3982614fb16b508d44e01e331 100644 --- a/system/gd/hci/acl_manager.cc +++ b/system/gd/hci/acl_manager.cc @@ -19,12 +19,11 @@ #include #include #include -#include #include "common/bidi_queue.h" +#include "dumpsys_data_generated.h" #include "hci/acl_manager/acl_scheduler.h" #include "hci/acl_manager/classic_impl.h" -#include "hci/acl_manager/connection_management_callbacks.h" #include "hci/acl_manager/le_acceptlist_callbacks.h" #include "hci/acl_manager/le_acl_connection.h" #include "hci/acl_manager/le_impl.h" @@ -68,9 +67,7 @@ struct AclManager::impl { round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_layer_->GetAclQueueEnd()); acl_scheduler_ = acl_manager_.GetDependency(); - if (bluetooth::common::init_flags::gd_remote_name_request_is_enabled()) { - remote_name_request_module_ = acl_manager_.GetDependency(); - } + remote_name_request_module_ = acl_manager_.GetDependency(); bool crash_on_unknown_handle = false; { @@ -282,7 +279,7 @@ void AclManager::SetPrivacyPolicyForInitiatorAddress( AddressWithType fixed_address, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { - crypto_toolbox::Octet16 rotation_irk{}; + Octet16 rotation_irk{}; auto irk_prop = GetDependency()->GetProperty("Adapter", "LE_LOCAL_KEY_IRK"); if (irk_prop.has_value()) { @@ -305,7 +302,7 @@ void AclManager::SetPrivacyPolicyForInitiatorAddress( void AclManager::SetPrivacyPolicyForInitiatorAddressForTest( LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { CallOn( @@ -426,9 +423,7 @@ void AclManager::ListDependencies(ModuleList* list) const { list->add(); list->add(); list->add(); - if (bluetooth::common::init_flags::gd_remote_name_request_is_enabled()) { - list->add(); - } + list->add(); } void AclManager::Start() { diff --git a/system/gd/hci/acl_manager.h b/system/gd/hci/acl_manager.h index ff8f299794a1204e0511431ce57f1e8949bc6182..f7fa63fd2e2035d706b7daa21fd2bdba4a22d0e7 100644 --- a/system/gd/hci/acl_manager.h +++ b/system/gd/hci/acl_manager.h @@ -20,15 +20,12 @@ #include #include -#include "common/bidi_queue.h" -#include "common/callback.h" #include "hci/acl_manager/connection_callbacks.h" #include "hci/acl_manager/le_acceptlist_callbacks.h" #include "hci/acl_manager/le_connection_callbacks.h" #include "hci/address.h" #include "hci/address_with_type.h" #include "hci/distance_measurement_manager.h" -#include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "hci/le_address_manager.h" #include "hci/le_scanning_manager.h" @@ -36,143 +33,154 @@ #include "os/handler.h" namespace bluetooth { - namespace security { class SecurityModule; -} +} // namespace security namespace shim { namespace legacy { class Acl; -} +} // namespace legacy class Btm; -void L2CA_UseLegacySecurityModule(); bool L2CA_SetAclPriority(uint16_t, bool); -} +} // namespace shim namespace hci { class AclManager : public Module { - friend class bluetooth::shim::Btm; - friend class bluetooth::shim::legacy::Acl; - friend void bluetooth::shim::L2CA_UseLegacySecurityModule(); - friend bool bluetooth::shim::L2CA_SetAclPriority(uint16_t, bool); - friend class bluetooth::hci::LeScanningManager; - friend class bluetooth::hci::DistanceMeasurementManager; - -public: - AclManager(); - AclManager(const AclManager&) = delete; - AclManager& operator=(const AclManager&) = delete; - - // NOTE: It is necessary to forward declare a default destructor that overrides the base class one, because - // "struct impl" is forwarded declared in .cc and compiler needs a concrete definition of "struct impl" when - // compiling AclManager's destructor. Hence we need to forward declare the destructor for AclManager to delay - // compiling AclManager's destructor until it starts linking the .cc file. - ~AclManager(); - - // Should register only once when user module starts. - // Generates OnConnectSuccess when an incoming connection is established. - virtual void RegisterCallbacks(acl_manager::ConnectionCallbacks* callbacks, os::Handler* handler); - virtual void UnregisterCallbacks(acl_manager::ConnectionCallbacks* callbacks, std::promise promise); - - // Should register only once when user module starts. - virtual void RegisterLeCallbacks(acl_manager::LeConnectionCallbacks* callbacks, os::Handler* handler); - virtual void UnregisterLeCallbacks(acl_manager::LeConnectionCallbacks* callbacks, std::promise promise); - void RegisterLeAcceptlistCallbacks(acl_manager::LeAcceptlistCallbacks* callbacks); - void UnregisterLeAcceptlistCallbacks( - acl_manager::LeAcceptlistCallbacks* callbacks, std::promise promise); - - // Generates OnConnectSuccess if connected, or OnConnectFail otherwise - virtual void CreateConnection(Address address); - - // Generates OnLeConnectSuccess if connected, or OnLeConnectFail otherwise - virtual void CreateLeConnection(AddressWithType address_with_type, bool is_direct); - - // Ask the controller for specific data parameters - virtual void SetLeSuggestedDefaultDataParameters(uint16_t octets, uint16_t time); - - virtual void LeSetDefaultSubrate( - uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t sup_tout); - - virtual void SetPrivacyPolicyForInitiatorAddress( - LeAddressManager::AddressPolicy address_policy, - AddressWithType fixed_address, - std::chrono::milliseconds minimum_rotation_time, - std::chrono::milliseconds maximum_rotation_time); - - // TODO(jpawlowski): remove once we have config file abstraction in cert tests - virtual void SetPrivacyPolicyForInitiatorAddressForTest( - LeAddressManager::AddressPolicy address_policy, - AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, - std::chrono::milliseconds minimum_rotation_time, - std::chrono::milliseconds maximum_rotation_time); - - // Generates OnConnectFail with error code "terminated by local host 0x16" if cancelled, or OnConnectSuccess if not - // successfully cancelled and already connected - virtual void CancelConnect(Address address); - virtual void RemoveFromBackgroundList(AddressWithType address_with_type); - virtual void IsOnBackgroundList(AddressWithType address_with_type, std::promise promise); - - virtual void CancelLeConnect(AddressWithType address_with_type); - - virtual void ClearFilterAcceptList(); - - virtual void AddDeviceToResolvingList( - AddressWithType address_with_type, - const std::array& peer_irk, - const std::array& local_irk); - virtual void RemoveDeviceFromResolvingList(AddressWithType address_with_type); - virtual void ClearResolvingList(); - - virtual void CentralLinkKey(KeyFlag key_flag); - virtual void SwitchRole(Address address, Role role); - virtual uint16_t ReadDefaultLinkPolicySettings(); - virtual void WriteDefaultLinkPolicySettings(uint16_t default_link_policy_settings); - - // Callback from Advertising Manager to notify the advitiser (local) address - virtual void OnAdvertisingSetTerminated( - ErrorCode status, - uint16_t conn_handle, - uint8_t adv_set_id, - hci::AddressWithType adv_address, - bool is_discoverable); - - // In order to avoid circular dependency use setter rather than module dependency. - virtual void SetSecurityModule(security::SecurityModule* security_module); - - virtual LeAddressManager* GetLeAddressManager(); - - // Virtual ACL disconnect emitted during suspend. - virtual void OnClassicSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reason); - virtual void OnLeSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reason); - virtual void SetSystemSuspendState(bool suspended); - - static const ModuleFactory Factory; - -protected: - void ListDependencies(ModuleList* list) const override; - - void Start() override; - - void Stop() override; - - std::string ToString() const override; - - DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const override; // Module - -private: - virtual uint16_t HACK_GetHandle(const Address address); - virtual uint16_t HACK_GetLeHandle(const Address address); - - // Hack for the shim to get non-acl disconnect callback. Shim needs to post to their handler! - virtual void HACK_SetNonAclDisconnectCallback(std::function); - - virtual void HACK_SetAclTxPriority(uint8_t handle, bool high_priority); + friend class bluetooth::shim::Btm; + friend class bluetooth::shim::legacy::Acl; + friend bool bluetooth::shim::L2CA_SetAclPriority(uint16_t, bool); + friend class bluetooth::hci::LeScanningManager; + friend class bluetooth::hci::DistanceMeasurementManager; + + public: + AclManager(); + AclManager(const AclManager&) = delete; + AclManager& operator=(const AclManager&) = delete; + + // NOTE: It is necessary to forward declare a default destructor that + // overrides the base class one, because "struct impl" is forwarded declared + // in .cc and compiler needs a concrete definition of "struct impl" when + // compiling AclManager's destructor. Hence we need to forward declare the + // destructor for AclManager to delay compiling AclManager's destructor until + // it starts linking the .cc file. + ~AclManager(); + + // Should register only once when user module starts. + // Generates OnConnectSuccess when an incoming connection is established. + virtual void RegisterCallbacks(acl_manager::ConnectionCallbacks* callbacks, os::Handler* handler); + virtual void UnregisterCallbacks( + acl_manager::ConnectionCallbacks* callbacks, std::promise promise); + + // Should register only once when user module starts. + virtual void RegisterLeCallbacks( + acl_manager::LeConnectionCallbacks* callbacks, os::Handler* handler); + virtual void UnregisterLeCallbacks( + acl_manager::LeConnectionCallbacks* callbacks, std::promise promise); + void RegisterLeAcceptlistCallbacks(acl_manager::LeAcceptlistCallbacks* callbacks); + void UnregisterLeAcceptlistCallbacks( + acl_manager::LeAcceptlistCallbacks* callbacks, std::promise promise); + + // Generates OnConnectSuccess if connected, or OnConnectFail otherwise + virtual void CreateConnection(Address address); + + // Generates OnLeConnectSuccess if connected, or OnLeConnectFail otherwise + virtual void CreateLeConnection(AddressWithType address_with_type, bool is_direct); + + // Ask the controller for specific data parameters + virtual void SetLeSuggestedDefaultDataParameters(uint16_t octets, uint16_t time); + + virtual void LeSetDefaultSubrate( + uint16_t subrate_min, + uint16_t subrate_max, + uint16_t max_latency, + uint16_t cont_num, + uint16_t sup_tout); + + virtual void SetPrivacyPolicyForInitiatorAddress( + LeAddressManager::AddressPolicy address_policy, + AddressWithType fixed_address, + std::chrono::milliseconds minimum_rotation_time, + std::chrono::milliseconds maximum_rotation_time); + + // TODO(jpawlowski): remove once we have config file abstraction in cert tests + virtual void SetPrivacyPolicyForInitiatorAddressForTest( + LeAddressManager::AddressPolicy address_policy, + AddressWithType fixed_address, + Octet16 rotation_irk, + std::chrono::milliseconds minimum_rotation_time, + std::chrono::milliseconds maximum_rotation_time); + + // Generates OnConnectFail with error code "terminated by local host 0x16" if + // cancelled, or OnConnectSuccess if not successfully cancelled and already + // connected + virtual void CancelConnect(Address address); + virtual void RemoveFromBackgroundList(AddressWithType address_with_type); + virtual void IsOnBackgroundList(AddressWithType address_with_type, std::promise promise); + + virtual void CancelLeConnect(AddressWithType address_with_type); + + virtual void ClearFilterAcceptList(); + + virtual void AddDeviceToResolvingList( + AddressWithType address_with_type, + const std::array& peer_irk, + const std::array& local_irk); + virtual void RemoveDeviceFromResolvingList(AddressWithType address_with_type); + virtual void ClearResolvingList(); + + virtual void CentralLinkKey(KeyFlag key_flag); + virtual void SwitchRole(Address address, Role role); + virtual uint16_t ReadDefaultLinkPolicySettings(); + virtual void WriteDefaultLinkPolicySettings(uint16_t default_link_policy_settings); + + // Callback from Advertising Manager to notify the advitiser (local) address + virtual void OnAdvertisingSetTerminated( + ErrorCode status, + uint16_t conn_handle, + uint8_t adv_set_id, + hci::AddressWithType adv_address, + bool is_discoverable); + + // In order to avoid circular dependency use setter rather than module + // dependency. + virtual void SetSecurityModule(security::SecurityModule* security_module); + + virtual LeAddressManager* GetLeAddressManager(); + + // Virtual ACL disconnect emitted during suspend. + virtual void OnClassicSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reason); + virtual void OnLeSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reason); + virtual void SetSystemSuspendState(bool suspended); + + static const ModuleFactory Factory; + + protected: + void ListDependencies(ModuleList* list) const override; + + void Start() override; + + void Stop() override; + + std::string ToString() const override; + + DumpsysDataFinisher GetDumpsysData( + flatbuffers::FlatBufferBuilder* builder) const override; // Module + + private: + virtual uint16_t HACK_GetHandle(const Address address); + virtual uint16_t HACK_GetLeHandle(const Address address); + + // Hack for the shim to get non-acl disconnect callback. Shim needs to post to + // their handler! + virtual void HACK_SetNonAclDisconnectCallback( + std::function); + + virtual void HACK_SetAclTxPriority(uint8_t handle, bool high_priority); - struct impl; - std::unique_ptr pimpl_; + struct impl; + std::unique_ptr pimpl_; }; } // namespace hci diff --git a/system/gd/hci/acl_manager/acl_scheduler.cc b/system/gd/hci/acl_manager/acl_scheduler.cc index a5f22f2bd23535105fdd44cc612ede5fcf59cf3e..d6be6b2b88a0f770315e74976957830adc4dff92 100644 --- a/system/gd/hci/acl_manager/acl_scheduler.cc +++ b/system/gd/hci/acl_manager/acl_scheduler.cc @@ -100,7 +100,7 @@ struct AclScheduler::impl { return entry_ptr != nullptr && entry_ptr->address == address; }, [&]() { cancel_connection.Invoke(); }, - [&](auto entry) { cancel_connection_completed.Invoke(); }); + [&](auto /* entry */) { cancel_connection_completed.Invoke(); }); if (!ok) { LOG_ERROR("Attempted to cancel connection to %s that does not exist", ADDRESS_TO_LOGGABLE_CSTR(address)); @@ -116,7 +116,7 @@ struct AclScheduler::impl { try_dequeue_next_operation(); } - void ReportRemoteNameRequestCompletion(Address address) { + void ReportRemoteNameRequestCompletion(Address /* address */) { if (!outgoing_entry_.has_value()) { LOG_ERROR("Remote name request completion reported, but none taking place!"); return; @@ -271,7 +271,7 @@ void AclScheduler::CancelRemoteNameRequest(Address address, common::ContextualOn &impl::CancelRemoteNameRequest, common::Unretained(pimpl_.get()), address, std::move(cancel_request)); } -void AclScheduler::ListDependencies(ModuleList* list) const {} +void AclScheduler::ListDependencies(ModuleList* /* list */) const {} void AclScheduler::Start() {} diff --git a/system/gd/hci/acl_manager/acl_scheduler.h b/system/gd/hci/acl_manager/acl_scheduler.h index bdf09928196896a4e05edb179d596ee1f2b13838..995b80ae926f846df8d05b867d65b1aff27f377e 100644 --- a/system/gd/hci/acl_manager/acl_scheduler.h +++ b/system/gd/hci/acl_manager/acl_scheduler.h @@ -46,7 +46,7 @@ class AclScheduler : public bluetooth::Module { // Report that an ACL connection has completed, and dispatch to the appropriate callback based on the internal // state. Then, start the next operation. - void ReportAclConnectionCompletion( + virtual void ReportAclConnectionCompletion( Address address, common::ContextualOnceCallback handle_outgoing_connection, common::ContextualOnceCallback handle_incoming_connection, @@ -93,9 +93,9 @@ class AclScheduler : public bluetooth::Module { public: static const ModuleFactory Factory; AclScheduler(); - ~AclScheduler(); + virtual ~AclScheduler(); }; } // namespace acl_manager } // namespace hci -} // namespace bluetooth \ No newline at end of file +} // namespace bluetooth diff --git a/system/gd/hci/acl_manager/acl_scheduler_test.cc b/system/gd/hci/acl_manager/acl_scheduler_test.cc index 16bb81b81e6fa36c63a0978c097043c0db066d46..16fd704c43bd5f5a2df45684cfc89589b3b3e670 100644 --- a/system/gd/hci/acl_manager/acl_scheduler_test.cc +++ b/system/gd/hci/acl_manager/acl_scheduler_test.cc @@ -68,16 +68,17 @@ class AclSchedulerTest : public ::testing::Test { } common::ContextualOnceCallback impossibleCallbackTakingString() { - return client_handler_->BindOnce([](std::string _) { ADD_FAILURE(); }); + return client_handler_->BindOnce([](std::string /* _ */) { ADD_FAILURE(); }); } common::ContextualOnceCallback emptyCallbackTakingString() { - return client_handler_->BindOnce([](std::string _) {}); + return client_handler_->BindOnce([](std::string /* _ */) {}); } common::ContextualOnceCallback promiseCallbackTakingString(std::promise promise) { return client_handler_->BindOnce( - [](std::promise promise, std::string _) { promise.set_value(); }, std::move(promise)); + [](std::promise promise, std::string /* _ */) { promise.set_value(); }, + std::move(promise)); } common::ContextualOnceCallback impossibleCallback() { diff --git a/system/gd/hci/acl_manager/assembler.h b/system/gd/hci/acl_manager/assembler.h index 9ef1293201b6d8327ddd64b8ace623d5c6ed39a9..2bc0a2cdc4760156483a6145269b2fa098e557ba 100644 --- a/system/gd/hci/acl_manager/assembler.h +++ b/system/gd/hci/acl_manager/assembler.h @@ -34,23 +34,35 @@ constexpr size_t kMaxQueuedPacketsPerConnection = 10; constexpr size_t kL2capBasicFrameHeaderSize = 4; namespace { +// This is a helper class to keep the state of the assembler and expose PacketView<>::Append. class PacketViewForRecombination : public packet::PacketView { public: - PacketViewForRecombination(const PacketView& packetView) : PacketView(packetView) {} + PacketViewForRecombination(const PacketView& packetView) + : PacketView(packetView), received_first_(true) {} + + PacketViewForRecombination() + : PacketView(PacketView(std::make_shared>())) {} + void AppendPacketView(packet::PacketView to_append) { Append(to_append); } + + bool ReceivedFirstPacket() { + return received_first_; + } + + private: + bool received_first_{}; }; -// Per spec 5.1 Vol 2 Part B 5.3, ACL link shall carry L2CAP data. Therefore, an ACL packet shall contain L2CAP PDU. -// This function returns the PDU size of the L2CAP data if it's a starting packet. Returns 0 if it's invalid. -uint16_t GetL2capPduSize(AclView packet) { - auto l2cap_payload = packet.GetPayload(); - if (l2cap_payload.size() < kL2capBasicFrameHeaderSize) { - LOG_ERROR("Controller sent an invalid L2CAP starting packet!"); - return 0; +// Per spec 5.1 Vol 2 Part B 5.3, ACL link shall carry L2CAP data. Therefore, an ACL packet shall +// contain L2CAP PDU. This function returns the PDU size of the L2CAP starting packet, or +// kL2capBasicFrameHeaderSize if it's invalid. +size_t GetL2capPduSize(packet::PacketView pdu) { + if (pdu.size() < 2) { + return kL2capBasicFrameHeaderSize; // We need at least 4 bytes to send it to L2CAP } - return (l2cap_payload.at(1) << 8u) + l2cap_payload.at(0); + return (static_cast(pdu[1]) << 8u) + pdu[0]; } } // namespace @@ -61,9 +73,7 @@ struct assembler { AddressWithType address_with_type_; AclConnection::QueueDownEnd* down_end_; os::Handler* handler_; - PacketViewForRecombination recombination_stage_{ - PacketView(std::make_shared>())}; - size_t remaining_sdu_continuation_packet_size_ = 0; + PacketViewForRecombination recombination_stage_{}; std::shared_ptr enqueue_registered_ = std::make_shared(false); std::queue> incoming_queue_; @@ -74,7 +84,7 @@ struct assembler { } // Invoked from some external Queue Reactable context - std::unique_ptr> on_le_incoming_data_ready() { + std::unique_ptr> on_data_ready() { auto packet = incoming_queue_.front(); incoming_queue_.pop(); if (incoming_queue_.empty() && enqueue_registered_->exchange(false)) { @@ -85,7 +95,6 @@ struct assembler { void on_incoming_packet(AclView packet) { PacketView payload = packet.GetPayload(); - size_t payload_size = payload.size(); auto broadcast_flag = packet.GetBroadcastFlag(); if (broadcast_flag == BroadcastFlag::ACTIVE_PERIPHERAL_BROADCAST) { LOG_WARN("Dropping broadcast from remote"); @@ -97,58 +106,39 @@ struct assembler { return; } if (packet_boundary_flag == PacketBoundaryFlag::CONTINUING_FRAGMENT) { - if (remaining_sdu_continuation_packet_size_ < payload_size) { - LOG_WARN("Remote sent unexpected L2CAP PDU. Drop the entire L2CAP PDU"); - recombination_stage_ = - PacketViewForRecombination(PacketView(std::make_shared>())); - remaining_sdu_continuation_packet_size_ = 0; + if (!recombination_stage_.ReceivedFirstPacket()) { + LOG_ERROR("Continuing fragment received without previous first, dropping it."); return; } - remaining_sdu_continuation_packet_size_ -= payload_size; recombination_stage_.AppendPacketView(payload); - if (remaining_sdu_continuation_packet_size_ != 0) { - return; - } else { - payload = recombination_stage_; - recombination_stage_ = - PacketViewForRecombination(PacketView(std::make_shared>())); - } } else if (packet_boundary_flag == PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE) { - if (recombination_stage_.size() > 0) { + if (recombination_stage_.ReceivedFirstPacket()) { LOG_ERROR("Controller sent a starting packet without finishing previous packet. Drop previous one."); } - size_t l2cap_pdu_size = GetL2capPduSize(packet); - if (l2cap_pdu_size == 0) { - LOG_WARN("dropping an invalid L2CAP packet"); - return; - } - - remaining_sdu_continuation_packet_size_ = l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize); - if ((payload_size - kL2capBasicFrameHeaderSize) > l2cap_pdu_size) { - LOG_WARN( - "Remote presented mismatched packet sizes payload_size:%zu l2cap_pdu_size:%zu", - payload_size - kL2capBasicFrameHeaderSize, - l2cap_pdu_size); - remaining_sdu_continuation_packet_size_ = 0; - } else { - remaining_sdu_continuation_packet_size_ = - l2cap_pdu_size - (payload_size - kL2capBasicFrameHeaderSize); - } - if (remaining_sdu_continuation_packet_size_ > 0) { - recombination_stage_ = payload; - return; - } + recombination_stage_ = payload; + } + // Check the size of the packet + size_t expected_size = GetL2capPduSize(recombination_stage_) + kL2capBasicFrameHeaderSize; + if (expected_size < recombination_stage_.size()) { + LOG_INFO("Packet size doesn't match L2CAP header, dropping it."); + recombination_stage_ = PacketViewForRecombination(); + return; + } else if (expected_size > recombination_stage_.size()) { + // Wait for the next fragment before sending + return; } if (incoming_queue_.size() > kMaxQueuedPacketsPerConnection) { LOG_ERROR("Dropping packet from %s due to congestion", ADDRESS_TO_LOGGABLE_CSTR(address_with_type_)); + recombination_stage_ = PacketViewForRecombination(); return; } - incoming_queue_.push(payload); + incoming_queue_.push(recombination_stage_); + recombination_stage_ = PacketViewForRecombination(); if (!enqueue_registered_->exchange(true)) { - down_end_->RegisterEnqueue(handler_, - common::Bind(&assembler::on_le_incoming_data_ready, common::Unretained(this))); + down_end_->RegisterEnqueue( + handler_, common::Bind(&assembler::on_data_ready, common::Unretained(this))); } } }; diff --git a/system/gd/hci/acl_manager/classic_acl_connection.cc b/system/gd/hci/acl_manager/classic_acl_connection.cc index f80dbffda8f5cf39a8a96a3f02613315a7865fcb..3373aad683cd34cd4880ab9c4a7471d9e861369a 100644 --- a/system/gd/hci/acl_manager/classic_acl_connection.cc +++ b/system/gd/hci/acl_manager/classic_acl_connection.cc @@ -15,8 +15,9 @@ */ #include "hci/acl_manager/classic_acl_connection.h" -#include "hci/acl_manager/event_checkers.h" + #include "hci/address.h" +#include "hci/event_checkers.h" #include "os/metrics.h" using bluetooth::hci::Address; @@ -369,71 +370,73 @@ void ClassicAclConnection::RegisterCallbacks(ConnectionManagementCallbacks* call bool ClassicAclConnection::Disconnect(DisconnectReason reason) { acl_connection_interface_->EnqueueCommand( DisconnectBuilder::Create(handle_, reason), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::ChangeConnectionPacketType(uint16_t packet_type) { acl_connection_interface_->EnqueueCommand( ChangeConnectionPacketTypeBuilder::Create(handle_, packet_type), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce( + check_status)); return true; } bool ClassicAclConnection::AuthenticationRequested() { acl_connection_interface_->EnqueueCommand( AuthenticationRequestedBuilder::Create(handle_), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::SetConnectionEncryption(Enable enable) { acl_connection_interface_->EnqueueCommand( SetConnectionEncryptionBuilder::Create(handle_, enable), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::ChangeConnectionLinkKey() { acl_connection_interface_->EnqueueCommand( ChangeConnectionLinkKeyBuilder::Create(handle_), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::ReadClockOffset() { acl_connection_interface_->EnqueueCommand( ReadClockOffsetBuilder::Create(handle_), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::HoldMode(uint16_t max_interval, uint16_t min_interval) { acl_connection_interface_->EnqueueCommand( HoldModeBuilder::Create(handle_, max_interval, min_interval), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::SniffMode(uint16_t max_interval, uint16_t min_interval, uint16_t attempt, uint16_t timeout) { acl_connection_interface_->EnqueueCommand( SniffModeBuilder::Create(handle_, max_interval, min_interval, attempt, timeout), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::ExitSniffMode() { acl_connection_interface_->EnqueueCommand( ExitSniffModeBuilder::Create(handle_), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::QosSetup(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation) { acl_connection_interface_->EnqueueCommand( - QosSetupBuilder::Create(handle_, service_type, token_rate, peak_bandwidth, latency, delay_variation), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + QosSetupBuilder::Create( + handle_, service_type, token_rate, peak_bandwidth, latency, delay_variation), + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } @@ -455,7 +458,8 @@ bool ClassicAclConnection::ReadLinkPolicySettings() { bool ClassicAclConnection::WriteLinkPolicySettings(uint16_t link_policy_settings) { acl_connection_interface_->EnqueueCommand( WriteLinkPolicySettingsBuilder::Create(handle_, link_policy_settings), - pimpl_->tracker.client_handler_->BindOnce(&check_command_complete)); + pimpl_->tracker.client_handler_->BindOnce( + check_complete)); return true; } @@ -463,24 +467,31 @@ bool ClassicAclConnection::FlowSpecification(FlowDirection flow_direction, Servi uint32_t token_rate, uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency) { acl_connection_interface_->EnqueueCommand( - FlowSpecificationBuilder::Create(handle_, flow_direction, service_type, token_rate, token_bucket_size, - peak_bandwidth, access_latency), - pimpl_->tracker.client_handler_->BindOnce(&check_command_status)); + FlowSpecificationBuilder::Create( + handle_, + flow_direction, + service_type, + token_rate, + token_bucket_size, + peak_bandwidth, + access_latency), + pimpl_->tracker.client_handler_->BindOnce(check_status)); return true; } bool ClassicAclConnection::SniffSubrating(uint16_t maximum_latency, uint16_t minimum_remote_timeout, uint16_t minimum_local_timeout) { acl_connection_interface_->EnqueueCommand( - SniffSubratingBuilder::Create(handle_, maximum_latency, minimum_remote_timeout, minimum_local_timeout), - pimpl_->tracker.client_handler_->BindOnce(&check_command_complete)); + SniffSubratingBuilder::Create( + handle_, maximum_latency, minimum_remote_timeout, minimum_local_timeout), + pimpl_->tracker.client_handler_->BindOnce(check_complete)); return true; } bool ClassicAclConnection::Flush() { acl_connection_interface_->EnqueueCommand( FlushBuilder::Create(handle_), - pimpl_->tracker.client_handler_->BindOnce(&check_command_complete)); + pimpl_->tracker.client_handler_->BindOnce(check_complete)); return true; } @@ -495,7 +506,8 @@ bool ClassicAclConnection::ReadAutomaticFlushTimeout() { bool ClassicAclConnection::WriteAutomaticFlushTimeout(uint16_t flush_timeout) { acl_connection_interface_->EnqueueCommand( WriteAutomaticFlushTimeoutBuilder::Create(handle_, flush_timeout), - pimpl_->tracker.client_handler_->BindOnce(&check_command_complete)); + pimpl_->tracker.client_handler_->BindOnce( + check_complete)); return true; } @@ -518,7 +530,8 @@ bool ClassicAclConnection::ReadLinkSupervisionTimeout() { bool ClassicAclConnection::WriteLinkSupervisionTimeout(uint16_t link_supervision_timeout) { acl_connection_interface_->EnqueueCommand( WriteLinkSupervisionTimeoutBuilder::Create(handle_, link_supervision_timeout), - pimpl_->tracker.client_handler_->BindOnce(&check_command_complete)); + pimpl_->tracker.client_handler_->BindOnce( + check_complete)); return true; } @@ -533,7 +546,8 @@ bool ClassicAclConnection::ReadFailedContactCounter() { bool ClassicAclConnection::ResetFailedContactCounter() { acl_connection_interface_->EnqueueCommand( ResetFailedContactCounterBuilder::Create(handle_), - pimpl_->tracker.client_handler_->BindOnce(&check_command_complete)); + pimpl_->tracker.client_handler_->BindOnce( + check_complete)); return true; } 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 af062020a1ba24ee50a2c5b51cef52e4ed41cf13..ff7800916df1c09bbacd377e82950a851373c9a7 100644 --- a/system/gd/hci/acl_manager/classic_acl_connection_test.cc +++ b/system/gd/hci/acl_manager/classic_acl_connection_test.cc @@ -102,7 +102,7 @@ std::vector error_code_vector = { // Generic template for all commands template -T CreateCommand(U u) { +T CreateCommand(U /* u */) { T command; return command; } @@ -183,51 +183,58 @@ class TestAclConnectionInterface : public hci::AclConnectionInterface { class TestConnectionManagementCallbacks : public hci::acl_manager::ConnectionManagementCallbacks { public: ~TestConnectionManagementCallbacks() = default; - void OnConnectionPacketTypeChanged(uint16_t packet_type) override {} - void OnAuthenticationComplete(hci::ErrorCode hci_status) override {} - void OnEncryptionChange(hci::EncryptionEnabled enabled) override {} + void OnConnectionPacketTypeChanged(uint16_t /* packet_type */) override {} + void OnAuthenticationComplete(hci::ErrorCode /* hci_status */) override {} + void OnEncryptionChange(hci::EncryptionEnabled /* enabled */) override {} void OnChangeConnectionLinkKeyComplete() override {} - void OnReadClockOffsetComplete(uint16_t clock_offset) override {} - void OnModeChange(hci::ErrorCode status, hci::Mode current_mode, uint16_t interval) override {} + void OnReadClockOffsetComplete(uint16_t /* clock_offset */) override {} + void OnModeChange( + hci::ErrorCode /* status */, hci::Mode /* current_mode */, uint16_t /* interval */) override { + } void OnSniffSubrating( - hci::ErrorCode hci_status, - uint16_t maximum_transmit_latency, - uint16_t maximum_receive_latency, - uint16_t minimum_remote_timeout, - uint16_t minimum_local_timeout) override {} + hci::ErrorCode /* hci_status */, + uint16_t /* maximum_transmit_latency */, + uint16_t /* maximum_receive_latency */, + uint16_t /* minimum_remote_timeout */, + uint16_t /* minimum_local_timeout */) override {} void OnQosSetupComplete( - hci::ServiceType service_type, - uint32_t token_rate, - uint32_t peak_bandwidth, - uint32_t latency, - uint32_t delay_variation) override {} + hci::ServiceType /* service_type */, + uint32_t /* token_rate */, + uint32_t /* peak_bandwidth */, + uint32_t /* latency */, + uint32_t /* delay_variation */) override {} void OnFlowSpecificationComplete( - hci::FlowDirection flow_direction, - hci::ServiceType service_type, - uint32_t token_rate, - uint32_t token_bucket_size, - uint32_t peak_bandwidth, - uint32_t access_latency) override {} + hci::FlowDirection /* flow_direction */, + hci::ServiceType /* service_type */, + uint32_t /* token_rate */, + uint32_t /* token_bucket_size */, + uint32_t /* peak_bandwidth */, + uint32_t /* access_latency */) override {} void OnFlushOccurred() override {} - void OnRoleDiscoveryComplete(hci::Role current_role) override {} - void OnReadLinkPolicySettingsComplete(uint16_t link_policy_settings) override {} - void OnReadAutomaticFlushTimeoutComplete(uint16_t flush_timeout) override {} - void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) override {} - void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) override {} - void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) override {} - void OnReadLinkQualityComplete(uint8_t link_quality) override {} - void OnReadAfhChannelMapComplete(hci::AfhMode afh_mode, std::array afh_channel_map) override {} - void OnReadRssiComplete(uint8_t rssi) override {} - void OnReadClockComplete(uint32_t clock, uint16_t accuracy) override {} - void OnCentralLinkKeyComplete(hci::KeyFlag key_flag) override {} - void OnRoleChange(hci::ErrorCode hci_status, hci::Role new_role) override {} + void OnRoleDiscoveryComplete(hci::Role /* current_role */) override {} + void OnReadLinkPolicySettingsComplete(uint16_t /* link_policy_settings */) override {} + void OnReadAutomaticFlushTimeoutComplete(uint16_t /* flush_timeout */) override {} + void OnReadTransmitPowerLevelComplete(uint8_t /* transmit_power_level */) override {} + void OnReadLinkSupervisionTimeoutComplete(uint16_t /* link_supervision_timeout */) override {} + void OnReadFailedContactCounterComplete(uint16_t /* failed_contact_counter */) override {} + void OnReadLinkQualityComplete(uint8_t /* link_quality */) override {} + void OnReadAfhChannelMapComplete( + hci::AfhMode /* afh_mode */, std::array /* afh_channel_map */) override {} + void OnReadRssiComplete(uint8_t /* rssi */) override {} + void OnReadClockComplete(uint32_t /* clock */, uint16_t /* accuracy */) override {} + void OnCentralLinkKeyComplete(hci::KeyFlag /* key_flag */) override {} + void OnRoleChange(hci::ErrorCode /* hci_status */, hci::Role /* new_role */) override {} void OnDisconnection(hci::ErrorCode reason) override { on_disconnection_error_code_queue_.push(reason); } void OnReadRemoteVersionInformationComplete( - hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override {} - void OnReadRemoteSupportedFeaturesComplete(uint64_t features) override {} - void OnReadRemoteExtendedFeaturesComplete(uint8_t page_number, uint8_t max_page_number, uint64_t features) override {} + hci::ErrorCode /* hci_status */, + uint8_t /* lmp_version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) override {} + void OnReadRemoteSupportedFeaturesComplete(uint64_t /* features */) override {} + void OnReadRemoteExtendedFeaturesComplete( + uint8_t /* page_number */, uint8_t /* max_page_number */, uint64_t /* features */) override {} std::queue on_disconnection_error_code_queue_; }; @@ -283,8 +290,8 @@ class ClassicAclConnectionWithCallbacksTest : public ClassicAclConnectionTest { std::make_unique(queue_, &acl_connection_interface_, kConnectionHandle, address_); connection_->RegisterCallbacks(&callbacks_, handler_); is_callbacks_registered_ = true; - connection_management_callbacks_ = - connection_->GetEventCallbacks([this](uint16_t hci_handle) { is_callbacks_invalidated_ = true; }); + connection_management_callbacks_ = connection_->GetEventCallbacks( + [this](uint16_t /* hci_handle */) { is_callbacks_invalidated_ = true; }); is_callbacks_invalidated_ = false; } diff --git a/system/gd/hci/acl_manager/classic_impl.h b/system/gd/hci/acl_manager/classic_impl.h index 4df6ca440d473904f32d2ecc307c1e6e0a4d4c83..85d9dfce0b172bf7be21963d4f4fe9bd891b5d8f 100644 --- a/system/gd/hci/acl_manager/classic_impl.h +++ b/system/gd/hci/acl_manager/classic_impl.h @@ -24,9 +24,9 @@ #include "common/init_flags.h" #include "hci/acl_manager/acl_scheduler.h" #include "hci/acl_manager/assembler.h" -#include "hci/acl_manager/event_checkers.h" #include "hci/acl_manager/round_robin_scheduler.h" #include "hci/controller.h" +#include "hci/event_checkers.h" #include "hci/remote_name_request.h" #include "os/metrics.h" #include "security/security_manager_listener.h" @@ -274,8 +274,10 @@ struct classic_impl : public security::ISecurityManagerListener { client_callbacks_, &ConnectionCallbacks::HACK_OnEscoConnectRequest, address, request.GetClassOfDevice()); return; - case ConnectionRequestLinkType::UNKNOWN: - LOG_ERROR("Request has unknown ConnectionRequestLinkType."); + default: + LOG_ERROR( + "Request has unknown ConnectionRequestLinkType %s", + ConnectionRequestLinkTypeText(request.GetLinkType()).c_str()); return; } @@ -406,8 +408,10 @@ struct classic_impl : public security::ISecurityManagerListener { // HACK: Some failed SCO connections are reporting failures via // ConnectComplete instead of ScoConnectionComplete. - // Drop such packets. - if (handle == 0xffff && link_type == LinkType::SCO) { + // The pattern of it is that the handle is always 0xffff. + // We check it with 0x0fff since PDL only extracts 12 bits for handle. + // Drop such packets when the pattern is matched. + if (handle == 0x0fff && link_type == LinkType::SCO) { LOG_ERROR( "ConnectionComplete with invalid handle(%u), link type(%u) and status(%d). Dropping packet.", handle, @@ -446,12 +450,7 @@ struct classic_impl : public security::ISecurityManagerListener { ADDRESS_TO_LOGGABLE_CSTR(address), ErrorCodeText(status).c_str()); LOG_WARN("Firmware error after RemoteNameRequestCancel?"); // see b/184239841 - if (bluetooth::common::init_flags::gd_remote_name_request_is_enabled()) { - ASSERT_LOG( - remote_name_request_module != nullptr, - "RNR module enabled but module not provided"); - remote_name_request_module->ReportRemoteNameRequestCancellation(address); - } + remote_name_request_module->ReportRemoteNameRequestCancellation(address); }, common::Unretained(remote_name_request_module_), address, @@ -473,7 +472,7 @@ struct classic_impl : public security::ISecurityManagerListener { void actually_cancel_connect(Address address) { std::unique_ptr packet = CreateConnectionCancelBuilder::Create(address); acl_connection_interface_->EnqueueCommand( - std::move(packet), handler_->BindOnce(&check_command_complete)); + std::move(packet), handler_->BindOnce(check_complete)); } static constexpr bool kRemoveConnectionAfterwards = true; @@ -508,7 +507,7 @@ struct classic_impl : public security::ISecurityManagerListener { return; } uint16_t handle = packet_type_changed.GetConnectionHandle(); - connections.execute(handle, [=](ConnectionManagementCallbacks* callbacks) { + connections.execute(handle, [=](ConnectionManagementCallbacks* /* callbacks */) { // We don't handle this event; we didn't do this in legacy stack either. }); } @@ -757,20 +756,21 @@ struct classic_impl : public security::ISecurityManagerListener { void central_link_key(KeyFlag key_flag) { std::unique_ptr packet = CentralLinkKeyBuilder::Create(key_flag); acl_connection_interface_->EnqueueCommand( - std::move(packet), handler_->BindOnce(&check_command_status)); + std::move(packet), handler_->BindOnce(check_status)); } void switch_role(Address address, Role role) { std::unique_ptr packet = SwitchRoleBuilder::Create(address, role); acl_connection_interface_->EnqueueCommand( - std::move(packet), handler_->BindOnce(&check_command_status)); + std::move(packet), handler_->BindOnce(check_status)); } void write_default_link_policy_settings(uint16_t default_link_policy_settings) { std::unique_ptr packet = WriteDefaultLinkPolicySettingsBuilder::Create(default_link_policy_settings); acl_connection_interface_->EnqueueCommand( - std::move(packet), handler_->BindOnce(&check_command_complete)); + std::move(packet), + handler_->BindOnce(check_complete)); } void accept_connection(Address address) { @@ -782,12 +782,14 @@ struct classic_impl : public security::ISecurityManagerListener { void reject_connection(std::unique_ptr builder) { acl_connection_interface_->EnqueueCommand( - std::move(builder), handler_->BindOnce(&check_command_status)); + std::move(builder), handler_->BindOnce(check_status)); } - void OnDeviceBonded(bluetooth::hci::AddressWithType device) override {} - void OnDeviceUnbonded(bluetooth::hci::AddressWithType device) override {} - void OnDeviceBondFailed(bluetooth::hci::AddressWithType device, security::PairingFailure status) override {} + void OnDeviceBonded(bluetooth::hci::AddressWithType /* device */) override {} + void OnDeviceUnbonded(bluetooth::hci::AddressWithType /* device */) override {} + void OnDeviceBondFailed( + bluetooth::hci::AddressWithType /* device */, + security::PairingFailure /* status */) override {} void set_security_module(security::SecurityModule* security_module) { security_manager_ = security_module->GetSecurityManager(); diff --git a/system/gd/hci/acl_manager/classic_impl_test.cc b/system/gd/hci/acl_manager/classic_impl_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..c8caf1fc4185df3b0efb702826721000dba2ec94 --- /dev/null +++ b/system/gd/hci/acl_manager/classic_impl_test.cc @@ -0,0 +1,281 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hci/acl_manager/classic_impl.h" + +#include +#include + +#include +#include + +#include "common/bidi_queue.h" +#include "common/callback.h" +#include "common/testing/log_capture.h" +#include "hci/acl_manager.h" +#include "hci/acl_manager/acl_scheduler.h" +#include "hci/acl_manager/connection_callbacks_mock.h" +#include "hci/acl_manager/connection_management_callbacks_mock.h" +#include "hci/address.h" +#include "hci/controller_mock.h" +#include "hci/hci_layer_fake.h" +#include "hci/hci_packets.h" +#include "os/handler.h" +#include "os/log.h" +#include "packet/bit_inserter.h" +#include "packet/raw_builder.h" + +using namespace bluetooth; +using namespace std::chrono_literals; + +using ::bluetooth::common::BidiQueue; +using ::bluetooth::common::Callback; +using ::bluetooth::os::Handler; +using ::bluetooth::os::Thread; +using ::bluetooth::packet::BitInserter; +using ::bluetooth::packet::RawBuilder; +using ::bluetooth::testing::LogCapture; + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Eq; +using ::testing::Field; +using ::testing::Mock; +using ::testing::MockFunction; +using ::testing::SaveArg; +using ::testing::VariantWith; +using ::testing::WithArg; + +namespace { +constexpr bool kCrashOnUnknownHandle = true; +constexpr char kFixedAddress[] = "c0:aa:bb:cc:dd:ee"; +const bluetooth::hci::Address kRemoteAddress = + bluetooth::hci::Address({0x00, 0x11, 0x22, 0x33, 0x44, 0x55}); +[[maybe_unused]] constexpr uint16_t kHciHandle = 123; +template +std::shared_ptr> Serialize(std::unique_ptr build) { + auto bytes = std::make_shared>(); + BitInserter bi(*bytes); + build->Serialize(bi); + return bytes; +} + +template +T CreateCommandView(std::shared_ptr> bytes) { + return T::Create(hci::CommandView::Create(hci::PacketView(bytes))); +} + +template +T CreateAclCommandView(std::shared_ptr> bytes) { + return T::Create(CreateCommandView(bytes)); +} + +template +T CreateConnectionManagementCommandView(std::shared_ptr> bytes) { + return T::Create(CreateAclCommandView(bytes)); +} + +template +T CreateSecurityCommandView(std::shared_ptr> bytes) { + return T::Create(CreateCommandView(bytes)); +} + +template +T CreateEventView(std::shared_ptr> bytes) { + return T::Create(hci::EventView::Create(hci::PacketView(bytes))); +} + +[[maybe_unused]] hci::CommandCompleteView ReturnCommandComplete( + hci::OpCode op_code, hci::ErrorCode error_code) { + std::vector success_vector{static_cast(error_code)}; + auto builder = hci::CommandCompleteBuilder::Create( + uint8_t{1}, op_code, std::make_unique(success_vector)); + auto bytes = Serialize(std::move(builder)); + return hci::CommandCompleteView::Create( + hci::EventView::Create(hci::PacketView(bytes))); +} + +[[maybe_unused]] hci::CommandStatusView ReturnCommandStatus( + hci::OpCode op_code, hci::ErrorCode error_code) { + std::vector success_vector{static_cast(error_code)}; + auto builder = hci::CommandStatusBuilder::Create( + hci::ErrorCode::SUCCESS, uint8_t{1}, op_code, std::make_unique(success_vector)); + auto bytes = Serialize(std::move(builder)); + return hci::CommandStatusView::Create( + hci::EventView::Create(hci::PacketView(bytes))); +} + +bool handle_outgoing_connection_ = false; +bool handle_incoming_connection_ = false; + +} // namespace + +namespace bluetooth { +namespace hci { +namespace acl_manager { + +class MockAclScheduler : public AclScheduler { + public: + virtual void ReportAclConnectionCompletion( + Address /* address */, + common::ContextualOnceCallback handle_outgoing_connection, + common::ContextualOnceCallback handle_incoming_connection, + common::ContextualOnceCallback handle_unknown_connection) override { + if (handle_outgoing_connection_) { + handle_outgoing_connection.InvokeIfNotEmpty(); + return; + } + + if (handle_incoming_connection_) { + handle_incoming_connection.InvokeIfNotEmpty(); + } else { + handle_unknown_connection.InvokeIfNotEmpty("set_of_incoming_connecting_addresses()"); + } + } +}; + +PacketView GetPacketView(std::unique_ptr packet) { + auto bytes = std::make_shared>(); + BitInserter i(*bytes); + bytes->reserve(packet->size()); + packet->Serialize(i); + return packet::PacketView(bytes); +} + +class ClassicImplTest : public ::testing::Test { + protected: + void SetUp() override { + bluetooth::common::InitFlags::SetAllForTesting(); + thread_ = new Thread("thread", Thread::Priority::NORMAL); + handler_ = new Handler(thread_); + hci_layer_ = new TestHciLayer(); + controller_ = new testing::MockController(); + + EXPECT_CALL(*controller_, GetNumAclPacketBuffers); + EXPECT_CALL(*controller_, GetAclPacketLength); + EXPECT_CALL(*controller_, GetLeBufferSize); + EXPECT_CALL(*controller_, RegisterCompletedAclPacketsCallback); + EXPECT_CALL(*controller_, UnregisterCompletedAclPacketsCallback); + + round_robin_scheduler_ = + new acl_manager::RoundRobinScheduler(handler_, controller_, hci_queue_.GetUpEnd()); + hci_queue_.GetDownEnd()->RegisterDequeue( + handler_, common::Bind(&ClassicImplTest::HciDownEndDequeue, common::Unretained(this))); + acl_scheduler_ = new MockAclScheduler(); + rnr_ = new RemoteNameRequestModule(); + classic_impl_ = new acl_manager::classic_impl( + hci_layer_, + controller_, + handler_, + round_robin_scheduler_, + kCrashOnUnknownHandle, + acl_scheduler_, + rnr_); + classic_impl_->handle_register_callbacks(&mock_connection_callback_, handler_); + + Address address; + Address::FromString(kFixedAddress, address); + } + + void TearDown() override { + sync_handler(); + delete classic_impl_; + + hci_queue_.GetDownEnd()->UnregisterDequeue(); + + delete rnr_; + delete acl_scheduler_; + delete round_robin_scheduler_; + delete controller_; + delete hci_layer_; + + handler_->Clear(); + delete handler_; + delete thread_; + } + + MockAclScheduler* acl_scheduler_; + RemoteNameRequestModule* rnr_; + + void sync_handler() { + thread_->GetReactor()->WaitForIdle(2s); + } + + void HciDownEndDequeue() { + auto packet = hci_queue_.GetDownEnd()->TryDequeue(); + // Convert from a Builder to a View + auto bytes = std::make_shared>(); + bluetooth::packet::BitInserter i(*bytes); + bytes->reserve(packet->size()); + packet->Serialize(i); + auto packet_view = bluetooth::packet::PacketView(bytes); + AclView acl_packet_view = AclView::Create(packet_view); + ASSERT_TRUE(acl_packet_view.IsValid()); + PacketView count_view = acl_packet_view.GetPayload(); + sent_acl_packets_.push(acl_packet_view); + + packet_count_--; + if (packet_count_ == 0) { + packet_promise_->set_value(); + packet_promise_ = nullptr; + } + } + + protected: + Address remote_address_; + + uint16_t packet_count_; + std::unique_ptr> packet_promise_; + std::unique_ptr> packet_future_; + std::queue sent_acl_packets_; + + BidiQueue hci_queue_{3}; + + Thread* thread_; + Handler* handler_; + TestHciLayer* hci_layer_{nullptr}; + testing::MockController* controller_; + acl_manager::RoundRobinScheduler* round_robin_scheduler_{nullptr}; + + acl_manager::MockConnectionCallback mock_connection_callback_; + acl_manager::MockConnectionManagementCallbacks connection_management_callbacks_; + + struct acl_manager::classic_impl* classic_impl_; +}; + +TEST_F(ClassicImplTest, nop) {} + +TEST_F(ClassicImplTest, on_classic_event_CONNECTION_COMPLETE__SUCCESS) { + // Expecting valid response + EXPECT_CALL(mock_connection_callback_, OnConnectSuccess); + handle_outgoing_connection_ = true; + + auto command = ConnectionCompleteBuilder::Create( + ErrorCode::SUCCESS, + kHciHandle, + kRemoteAddress, + LinkType::ACL, + bluetooth::hci::Enable::ENABLED); + + auto bytes = Serialize(std::move(command)); + auto view = CreateEventView(bytes); + ASSERT_TRUE(view.IsValid()); + classic_impl_->on_classic_event(view); +} + +} // namespace acl_manager +} // namespace hci +} // namespace bluetooth diff --git a/system/gd/hci/acl_manager/connection_callbacks_mock.h b/system/gd/hci/acl_manager/connection_callbacks_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..4f50b8a72bc93d077d947b53cb67c23acb26412b --- /dev/null +++ b/system/gd/hci/acl_manager/connection_callbacks_mock.h @@ -0,0 +1,42 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "hci/acl_manager/connection_callbacks.h" +#include "hci/hci_packets.h" + +namespace bluetooth { +namespace hci { +namespace acl_manager { + +class MockConnectionCallback : public ConnectionCallbacks { + public: + MOCK_METHOD( + void, OnConnectSuccess, (std::unique_ptr connection), (override)); + MOCK_METHOD(void, OnConnectRequest, (Address, ClassOfDevice), (override)); + MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason, bool locally_initiated), (override)); + + MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override)); + MOCK_METHOD(void, HACK_OnScoConnectRequest, (Address, ClassOfDevice), (override)); +}; + +} // namespace acl_manager +} // namespace hci +} // namespace bluetooth diff --git a/system/gd/hci/acl_manager/connection_management_callbacks_mock.h b/system/gd/hci/acl_manager/connection_management_callbacks_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..88ab212f26e73e006c625d2a28e1be85db8ea916 --- /dev/null +++ b/system/gd/hci/acl_manager/connection_management_callbacks_mock.h @@ -0,0 +1,101 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "hci/acl_manager/connection_management_callbacks.h" +#include "hci/hci_packets.h" + +namespace bluetooth { +namespace hci { +namespace acl_manager { + +class MockConnectionManagementCallbacks : public ConnectionManagementCallbacks { + public: + MOCK_METHOD(void, OnConnectionPacketTypeChanged, (uint16_t packet_type), (override)); + MOCK_METHOD(void, OnAuthenticationComplete, (ErrorCode hci_status), (override)); + MOCK_METHOD(void, OnEncryptionChange, (EncryptionEnabled enabled)), (override); + MOCK_METHOD(void, OnChangeConnectionLinkKeyComplete, (), (override)); + MOCK_METHOD(void, OnReadClockOffsetComplete, (uint16_t clock_offse), (override)); + MOCK_METHOD( + void, OnModeChange, (ErrorCode status, Mode current_mode, uint16_t interval), (override)); + MOCK_METHOD( + void, + OnSniffSubrating, + (ErrorCode status, + uint16_t maximum_transmit_latency, + uint16_t maximum_receive_latency, + uint16_t minimum_remote_timeout, + uint16_t minimum_local_timeout), + (override)); + MOCK_METHOD( + void, + OnQosSetupComplete, + (ServiceType service_type, + uint32_t token_rate, + uint32_t peak_bandwidth, + uint32_t latency, + uint32_t delay_variation), + (override)); + MOCK_METHOD( + void, + OnFlowSpecificationComplete, + (FlowDirection flow_direction, + ServiceType service_type, + uint32_t token_rate, + uint32_t token_bucket_size, + uint32_t peak_bandwidth, + uint32_t access_latency), + (override)); + MOCK_METHOD(void, OnFlushOccurred, (), (override)); + MOCK_METHOD(void, OnRoleDiscoveryComplete, (Role current_role), (override)); + MOCK_METHOD(void, OnReadLinkPolicySettingsComplete, (uint16_t link_policy_settings), (override)); + MOCK_METHOD(void, OnReadAutomaticFlushTimeoutComplete, (uint16_t flush_timeout), (override)); + MOCK_METHOD(void, OnReadTransmitPowerLevelComplete, (uint8_t transmit_power_level), (override)); + MOCK_METHOD( + void, OnReadLinkSupervisionTimeoutComplete, (uint16_t link_supervision_timeout), (override)); + MOCK_METHOD( + void, OnReadFailedContactCounterComplete, (uint16_t failed_contact_counter), (override)); + MOCK_METHOD(void, OnReadLinkQualityComplete, (uint8_t link_quality), (override)); + MOCK_METHOD( + void, + OnReadAfhChannelMapComplete, + (AfhMode afh_mode, (std::array)afh_channel_map), + (override)); + MOCK_METHOD(void, OnReadRssiComplete, (uint8_t rssi), (override)); + MOCK_METHOD(void, OnReadClockComplete, (uint32_t clock, uint16_t accuracy), (override)); + MOCK_METHOD(void, OnCentralLinkKeyComplete, (KeyFlag flag), (override)); + MOCK_METHOD(void, OnRoleChange, (ErrorCode hci_status, Role new_role), (override)); + MOCK_METHOD(void, OnDisconnection, (ErrorCode reason), (override)); + MOCK_METHOD( + void, + OnReadRemoteVersionInformationComplete, + (ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version), + (override)); + MOCK_METHOD(void, OnReadRemoteSupportedFeaturesComplete, (uint64_t features), (override)); + MOCK_METHOD( + void, + OnReadRemoteExtendedFeaturesComplete, + (uint8_t page_number, uint8_t max_page_number, uint64_t features), + (override)); +}; + +} // namespace acl_manager +} // namespace hci +} // namespace bluetooth diff --git a/system/gd/hci/acl_manager/le_acl_connection.h b/system/gd/hci/acl_manager/le_acl_connection.h index 58a8b77a48f9781f44e3d6122384328dcb160414..b42da543466f431ea0b31ff9d8142ca88387ae90 100644 --- a/system/gd/hci/acl_manager/le_acl_connection.h +++ b/system/gd/hci/acl_manager/le_acl_connection.h @@ -83,8 +83,7 @@ class LeAclConnection : public AclConnection { // The peer address and type returned from the Connection Complete Event AddressWithType peer_address_with_type_; - Address remote_initiator_address_; - Address local_initiator_address_; + // 5.2::7.7.65.10 Connection interval used on this connection. // Range: 0x0006 to 0x0C80 // Time = N * 1.25 ms @@ -108,6 +107,27 @@ class LeAclConnection : public AclConnection { Address local_resolvable_private_address_ = Address::kEmpty; Address peer_resolvable_private_address_ = Address::kEmpty; + virtual AddressWithType GetPeerAddress() const { + return peer_address_with_type_; + } + + // This function return actual peer address which was used for the connection over the air. + virtual AddressWithType GetPeerOtaAddress() const { + if (peer_resolvable_private_address_ == Address::kEmpty) { + return GetPeerAddress(); + } + return AddressWithType(peer_resolvable_private_address_, AddressType::RANDOM_DEVICE_ADDRESS); + } + + // This function return actual local address which was used for the connection over the air. + virtual AddressWithType GetLocalOtaAddress() const { + if (local_resolvable_private_address_ == Address::kEmpty) { + return GetLocalAddress(); + } + + return AddressWithType(local_resolvable_private_address_, AddressType::RANDOM_DEVICE_ADDRESS); + } + virtual void RegisterCallbacks(LeConnectionManagementCallbacks* callbacks, os::Handler* handler); virtual void Disconnect(DisconnectReason reason); diff --git a/system/gd/hci/acl_manager/le_acl_connection_test.cc b/system/gd/hci/acl_manager/le_acl_connection_test.cc index d562c29ffdfb0b628bc1cd862f092f0bc0bfb04a..02281a6acc2b7a31cc1942cd60f931205ae30b8e 100644 --- a/system/gd/hci/acl_manager/le_acl_connection_test.cc +++ b/system/gd/hci/acl_manager/le_acl_connection_test.cc @@ -65,17 +65,25 @@ namespace { class TestLeConnectionManagementCallbacks : public hci::acl_manager::LeConnectionManagementCallbacks { void OnConnectionUpdate( - hci::ErrorCode hci_status, - uint16_t connection_interval, - uint16_t connection_latency, - uint16_t supervision_timeout) override {} - virtual void OnDataLengthChange(uint16_t tx_octets, uint16_t tx_time, uint16_t rx_octets, uint16_t rx_time) override { - } - virtual void OnDisconnection(hci::ErrorCode reason) override {} + hci::ErrorCode /* hci_status */, + uint16_t /* connection_interval */, + uint16_t /* connection_latency */, + uint16_t /* supervision_timeout */) override {} + virtual void OnDataLengthChange( + uint16_t /* tx_octets */, + uint16_t /* tx_time */, + uint16_t /* rx_octets */, + uint16_t /* rx_time */) override {} + virtual void OnDisconnection(hci::ErrorCode /* reason */) override {} virtual void OnReadRemoteVersionInformationComplete( - hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override {} - virtual void OnLeReadRemoteFeaturesComplete(hci::ErrorCode hci_status, uint64_t features) override {} - virtual void OnPhyUpdate(hci::ErrorCode hci_status, uint8_t tx_phy, uint8_t rx_phy) override {} + hci::ErrorCode /* hci_status */, + uint8_t /* lmp_version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) override {} + virtual void OnLeReadRemoteFeaturesComplete( + hci::ErrorCode /* hci_status */, uint64_t /* features */) override {} + virtual void OnPhyUpdate( + hci::ErrorCode /* hci_status */, uint8_t /* tx_phy */, uint8_t /* rx_phy */) override {} MOCK_METHOD( void, OnLeSubrateChange, @@ -251,4 +259,4 @@ TEST_F(LeAclConnectionTest, LeSubrateRequest_error) { } } // namespace -} // namespace bluetooth::hci::acl_manager \ No newline at end of file +} // namespace bluetooth::hci::acl_manager diff --git a/system/gd/hci/acl_manager/le_impl.h b/system/gd/hci/acl_manager/le_impl.h index 8ab75821201cbcd95ad5dd3b67ec69525a726f0b..602423e2d9ed6fdc084e36ea6ec221488416dbd1 100644 --- a/system/gd/hci/acl_manager/le_impl.h +++ b/system/gd/hci/acl_manager/le_impl.h @@ -18,17 +18,13 @@ #include -#include -#include #include #include -#include #include #include #include "common/bind.h" #include "common/init_flags.h" -#include "crypto_toolbox/crypto_toolbox.h" #include "hci/acl_manager/assembler.h" #include "hci/acl_manager/le_acceptlist_callbacks.h" #include "hci/acl_manager/le_connection_management_callbacks.h" @@ -37,13 +33,10 @@ #include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "hci/le_address_manager.h" +#include "macros.h" #include "os/alarm.h" #include "os/handler.h" -#include "os/metrics.h" #include "os/system_properties.h" -#include "packet/packet_view.h" - -using bluetooth::crypto_toolbox::Octet16; namespace bluetooth { namespace hci { @@ -92,10 +85,6 @@ enum class ConnectabilityState { DISARMING = 3, }; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string connectability_state_machine_text(const ConnectabilityState& state) { switch (state) { CASE_RETURN_TEXT(ConnectabilityState::DISARMED); @@ -106,7 +95,6 @@ inline std::string connectability_state_machine_text(const ConnectabilityState& return base::StringPrintf("UNKNOWN[%d]", state); } } -#undef CASE_RETURN_TEXT struct le_acl_connection { le_acl_connection( @@ -355,16 +343,6 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { AddressWithType remote_address(address, peer_address_type); AddressWithType local_address = le_address_manager_->GetInitiatorAddress(); const bool in_filter_accept_list = is_device_in_connect_list(remote_address); - auto argument_list = std::vector>(); - argument_list.push_back( - std::make_pair(os::ArgumentType::ACL_STATUS_CODE, static_cast(status))); - - bluetooth::os::LogMetricBluetoothLEConnectionMetricEvent( - address, - android::bluetooth::le::LeConnectionOriginType::ORIGIN_NATIVE, - android::bluetooth::le::LeConnectionType::CONNECTION_TYPE_LE_ACL, - android::bluetooth::le::LeConnectionState::STATE_LE_ACL_END, - argument_list); if (role == hci::Role::CENTRAL) { connectability_state_ = ConnectabilityState::DISARMED; @@ -372,6 +350,11 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { on_le_connection_canceled_on_pause(); return; } + if (status == ErrorCode::UNKNOWN_CONNECTION && arm_on_disarm_) { + arm_on_disarm_ = false; + arm_connectability(); + return; + } on_common_le_connection_complete(remote_address); if (status == ErrorCode::UNKNOWN_CONNECTION) { if (remote_address.GetAddress() != Address::kEmpty) { @@ -501,16 +484,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { } AddressWithType remote_address(address, remote_address_type); const bool in_filter_accept_list = is_device_in_connect_list(remote_address); - auto argument_list = std::vector>(); - argument_list.push_back( - std::make_pair(os::ArgumentType::ACL_STATUS_CODE, static_cast(status))); - bluetooth::os::LogMetricBluetoothLEConnectionMetricEvent( - address, - android::bluetooth::le::LeConnectionOriginType::ORIGIN_NATIVE, - android::bluetooth::le::LeConnectionType::CONNECTION_TYPE_LE_ACL, - android::bluetooth::le::LeConnectionState::STATE_LE_ACL_END, - argument_list); if (role == hci::Role::CENTRAL) { connectability_state_ = ConnectabilityState::DISARMED; @@ -734,7 +708,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { } auto handle = request_view.GetConnectionHandle(); - connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { + connections.execute(handle, [=](LeConnectionManagementCallbacks* /* callbacks */) { // TODO: this is blindly accepting any parameters, just so we don't hang connection // have proper parameter negotiation le_acl_connection_interface_->EnqueueCommand( @@ -746,7 +720,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { request_view.GetTimeout(), 0, 0), - handler_->BindOnce([](CommandCompleteView status) {})); + handler_->BindOnce([](CommandCompleteView /* status */) {})); }); } @@ -799,7 +773,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { if (connect_list.find(address_with_type) != connect_list.end()) { LOG_WARN( - "Device already exists in acceptlist and cannot be added:%s", + "Device already exists in acceptlist and cannot be added: %s", ADDRESS_TO_LOGGABLE_CSTR(address_with_type)); return; } @@ -816,7 +790,8 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { void remove_device_from_connect_list(AddressWithType address_with_type) { if (connect_list.find(address_with_type) == connect_list.end()) { - LOG_WARN("Device not in acceptlist and cannot be removed:%s", + LOG_WARN( + "Device not in acceptlist and cannot be removed: %s", ADDRESS_TO_LOGGABLE_CSTR(address_with_type)); return; } @@ -1014,14 +989,6 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { void disarm_connectability() { - auto argument_list = std::vector>(); - bluetooth::os::LogMetricBluetoothLEConnectionMetricEvent( - Address::kEmpty, - os::LeConnectionOriginType::ORIGIN_UNSPECIFIED, - os::LeConnectionType::CONNECTION_TYPE_LE_ACL, - os::LeConnectionState::STATE_LE_ACL_CANCEL, - argument_list); - switch (connectability_state_) { case ConnectabilityState::ARMED: LOG_INFO("Disarming LE connection state machine with create connection cancel"); @@ -1055,9 +1022,13 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { return; } + bool already_in_connect_list = connect_list.find(address_with_type) != connect_list.end(); // TODO: Configure default LE connection parameters? if (add_to_connect_list) { - add_device_to_connect_list(address_with_type); + if (!already_in_connect_list) { + add_device_to_connect_list(address_with_type); + } + if (is_direct) { direct_connections_.insert(address_with_type); if (create_connection_timeout_alarms_.find(address_with_type) == create_connection_timeout_alarms_.end()) { @@ -1094,10 +1065,16 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { switch (connectability_state_) { case ConnectabilityState::ARMED: case ConnectabilityState::ARMING: - // Ignored, if we add new device to the filter accept list, create connection command will be sent by OnResume. - LOG_DEBUG( - "Deferred until filter accept list updated create connection state %s", - connectability_state_machine_text(connectability_state_).c_str()); + if (already_in_connect_list) { + arm_on_disarm_ = true; + disarm_connectability(); + } else { + // Ignored, if we add new device to the filter accept list, create connection command will + // be sent by OnResume. + LOG_DEBUG( + "Deferred until filter accept list updated create connection state %s", + connectability_state_machine_text(connectability_state_).c_str()); + } break; default: // If we added to filter accept list then the arming of the le state machine @@ -1118,16 +1095,6 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { if (create_connection_timeout_alarms_.find(address_with_type) != create_connection_timeout_alarms_.end()) { create_connection_timeout_alarms_.at(address_with_type).Cancel(); create_connection_timeout_alarms_.erase(address_with_type); - auto argument_list = std::vector>(); - argument_list.push_back(std::make_pair( - os::ArgumentType::ACL_STATUS_CODE, - static_cast(android::bluetooth::hci::StatusEnum::STATUS_CONNECTION_TOUT))); - bluetooth::os::LogMetricBluetoothLEConnectionMetricEvent( - address_with_type.GetAddress(), - android::bluetooth::le::LeConnectionOriginType::ORIGIN_NATIVE, - android::bluetooth::le::LeConnectionType::CONNECTION_TYPE_LE_ACL, - android::bluetooth::le::LeConnectionState::STATE_LE_ACL_TIMEOUT, - argument_list); if (background_connections_.find(address_with_type) != background_connections_.end()) { direct_connections_.erase(address_with_type); @@ -1156,7 +1123,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { void set_le_suggested_default_data_parameters(uint16_t length, uint16_t time) { auto packet = LeWriteSuggestedDefaultDataLengthBuilder::Create(length, time); le_acl_connection_interface_->EnqueueCommand( - std::move(packet), handler_->BindOnce([](CommandCompleteView complete) {})); + std::move(packet), handler_->BindOnce([](CommandCompleteView /* complete */) {})); } void LeSetDefaultSubrate( @@ -1178,7 +1145,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { void set_privacy_policy_for_initiator_address( LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { le_address_manager_->SetPrivacyPolicyForInitiatorAddress( @@ -1194,7 +1161,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { void set_privacy_policy_for_initiator_address_for_test( LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { le_address_manager_->SetPrivacyPolicyForInitiatorAddressForTest( @@ -1343,6 +1310,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback { LeAcceptlistCallbacks* le_acceptlist_callbacks_ = nullptr; std::unordered_set connecting_le_{}; bool arm_on_resume_{}; + bool arm_on_disarm_{}; std::unordered_set direct_connections_{}; // Set of devices that will not be removed from connect list after direct connect timeout std::unordered_set background_connections_; diff --git a/system/gd/hci/acl_manager/le_impl_test.cc b/system/gd/hci/acl_manager/le_impl_test.cc index 2e9c4b47099e33c034b01f62f766b0618a3881fe..2332fcd930d607cdbfc28eed1478bdc70fdab0a8 100644 --- a/system/gd/hci/acl_manager/le_impl_test.cc +++ b/system/gd/hci/acl_manager/le_impl_test.cc @@ -23,14 +23,13 @@ #include #include "common/bidi_queue.h" -#include "common/callback.h" #include "common/testing/log_capture.h" -#include "hci/acl_manager.h" #include "hci/acl_manager/le_connection_callbacks.h" #include "hci/acl_manager/le_connection_management_callbacks.h" #include "hci/address_with_type.h" #include "hci/controller.h" #include "hci/hci_packets.h" +#include "hci/octets.h" #include "os/handler.h" #include "os/log.h" #include "packet/bit_inserter.h" @@ -68,7 +67,7 @@ constexpr uint16_t kHciHandle = 123; [[maybe_unused]] constexpr bool kSkipFilterAcceptList = !kAddToFilterAcceptList; [[maybe_unused]] constexpr bool kIsDirectConnection = true; [[maybe_unused]] constexpr bool kIsBackgroundConnection = !kIsDirectConnection; -constexpr crypto_toolbox::Octet16 kRotationIrk = {}; +constexpr hci::Octet16 kRotationIrk = {}; constexpr std::chrono::milliseconds kMinimumRotationTime(14 * 1000); constexpr std::chrono::milliseconds kMaximumRotationTime(16 * 1000); constexpr uint16_t kIntervalMax = 0x40; @@ -322,7 +321,7 @@ class TestHciLayer : public HciLayer { return CommandView::Create(GetPacketView(std::move(last))); } - CommandView GetCommand(OpCode op_code) { + std::optional GetCommandOptional(OpCode op_code) { if (!command_queue_.empty()) { std::lock_guard lock(command_queue_mutex_); if (command_future_ != nullptr) { @@ -330,16 +329,26 @@ class TestHciLayer : public HciLayer { command_promise_.reset(); } } else if (command_future_ != nullptr) { - auto result = command_future_->wait_for(std::chrono::milliseconds(1000)); - EXPECT_NE(std::future_status::timeout, result); + command_future_->wait_for(std::chrono::milliseconds(1000)); } std::lock_guard lock(command_queue_mutex_); + if (command_queue_.empty()) { + return std::nullopt; + } else { + CommandView command_packet_view = GetLastCommand(); + EXPECT_TRUE(command_packet_view.IsValid()); + EXPECT_EQ(command_packet_view.GetOpCode(), op_code); + return command_packet_view; + } + } + + CommandView GetCommand(OpCode op_code) { + std::optional command = GetCommandOptional(op_code); ASSERT_LOG( - !command_queue_.empty(), "Expecting command %s but command queue was empty", OpCodeText(op_code).c_str()); - CommandView command_packet_view = GetLastCommand(); - EXPECT_TRUE(command_packet_view.IsValid()); - EXPECT_EQ(command_packet_view.GetOpCode(), op_code); - return command_packet_view; + command.has_value(), + "Expecting command %s but command queue was empty", + OpCodeText(op_code).c_str()); + return command.value(); } void CommandCompleteCallback(std::unique_ptr event_builder) { @@ -480,7 +489,7 @@ class LeImplTest : public ::testing::Test { hci::Address address; Address::FromString("D0:05:04:03:02:01", address); hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS); - crypto_toolbox::Octet16 rotation_irk{}; + Octet16 rotation_irk{}; auto minimum_rotation_time = std::chrono::milliseconds(7 * 60 * 1000); auto maximum_rotation_time = std::chrono::milliseconds(15 * 60 * 1000); le_impl_->set_privacy_policy_for_initiator_address( @@ -1812,6 +1821,58 @@ TEST_F(LeImplTest, DisconnectionAcceptlistCallback) { Mock::VerifyAndClearExpectations(&callbacks); } +TEST_F(LeImplTest, direct_connection_after_background_connection) { + set_random_device_address_policy(); + + hci::AddressWithType address( + {0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, AddressType::PUBLIC_DEVICE_ADDRESS); + + // arrange: Create background connection + ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture()); + le_impl_->create_le_connection(address, true, /* is_direct */ false); + hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); + ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture()); + hci_layer_->CommandCompleteCallback( + LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + auto raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); + hci_layer_->CommandStatusCallback( + LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // act: Create direct connection + ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture()); + le_impl_->create_le_connection(address, true, /* is_direct */ true); + auto cancel_connection = hci_layer_->GetCommandOptional(OpCode::LE_CREATE_CONNECTION_CANCEL); + if (cancel_connection) { + ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture()); + hci_layer_->CommandCompleteCallback( + LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, + kHciHandle, + Role::CENTRAL, + AddressType::PUBLIC_DEVICE_ADDRESS, + Address::kEmpty, + 0x0000, + 0x0000, + 0x0000, + ClockAccuracy::PPM_30)); + } + auto raw_direct_create_connection = hci_layer_->GetCommandOptional(OpCode::LE_CREATE_CONNECTION); + + // assert + ASSERT_TRUE(raw_direct_create_connection.has_value()); + auto bg_create_connection = LeCreateConnectionView::Create( + LeConnectionManagementCommandView::Create(AclCommandView::Create(raw_bg_create_connection))); + EXPECT_TRUE(bg_create_connection.IsValid()); + auto direct_create_connection = + LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( + AclCommandView::Create(*raw_direct_create_connection))); + EXPECT_TRUE(direct_create_connection.IsValid()); + LOG_INFO("Scan Interval %u", direct_create_connection.GetLeScanInterval()); + ASSERT_NE(direct_create_connection.GetLeScanInterval(), bg_create_connection.GetLeScanInterval()); +} + } // namespace acl_manager } // namespace hci } // namespace bluetooth diff --git a/system/gd/hci/acl_manager_test.cc b/system/gd/hci/acl_manager_test.cc index 2e1f82f9c729154bd53808f4dd252fe21f6445c4..9cb0643834f935a88374976ed3f0482d038ee9a0 100644 --- a/system/gd/hci/acl_manager_test.cc +++ b/system/gd/hci/acl_manager_test.cc @@ -25,40 +25,47 @@ #include #include "common/bind.h" +#include "hci/acl_manager/connection_callbacks_mock.h" +#include "hci/acl_manager/connection_management_callbacks_mock.h" #include "hci/acl_manager/le_connection_callbacks_mock.h" #include "hci/acl_manager/le_connection_management_callbacks_mock.h" #include "hci/address.h" #include "hci/class_of_device.h" #include "hci/controller.h" +#include "hci/controller_mock.h" #include "hci/hci_layer.h" #include "hci/hci_layer_fake.h" #include "os/fake_timer/fake_timerfd.h" #include "os/thread.h" #include "packet/raw_builder.h" +using bluetooth::common::BidiQueue; +using bluetooth::common::BidiQueueEnd; +using bluetooth::os::fake_timer::fake_timerfd_advance; +using bluetooth::packet::kLittleEndian; +using bluetooth::packet::PacketView; +using bluetooth::packet::RawBuilder; using testing::_; +using testing::ElementsAreArray; -namespace bluetooth { -namespace hci { -namespace acl_manager { namespace { -using common::BidiQueue; -using common::BidiQueueEnd; -using os::fake_timer::fake_timerfd_advance; -using packet::kLittleEndian; -using packet::PacketView; -using packet::RawBuilder; - constexpr auto kTimeout = std::chrono::seconds(2); constexpr auto kShortTimeout = std::chrono::milliseconds(100); +constexpr uint16_t kHciHandle = 123; constexpr uint16_t kScanIntervalFast = 0x0060; constexpr uint16_t kScanWindowFast = 0x0030; constexpr uint16_t kScanIntervalSlow = 0x0800; constexpr uint16_t kScanWindowSlow = 0x0030; -const AddressWithType empty_address_with_type = hci::AddressWithType(); +const bluetooth::hci::AddressWithType empty_address_with_type = bluetooth::hci::AddressWithType(); + +} // namespace -class TestController : public Controller { +namespace bluetooth { +namespace hci { +namespace acl_manager { + +class TestController : public testing::MockController { public: void RegisterCompletedAclPacketsCallback( common::ContextualCallback cb) override { @@ -77,7 +84,7 @@ class TestController : public Controller { return total_acl_buffers_; } - bool IsSupported(bluetooth::hci::OpCode op_code) const override { + bool IsSupported(bluetooth::hci::OpCode /* op_code */) const override { return false; } @@ -99,14 +106,20 @@ class TestController : public Controller { protected: void Start() override {} void Stop() override {} - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} }; class AclManagerNoCallbacksTest : public ::testing::Test { protected: void SetUp() override { test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry - test_controller_ = new TestController; + test_controller_ = new TestController; // Ownership is transferred to registry + + EXPECT_CALL(*test_controller_, GetMacAddress()); + EXPECT_CALL(*test_controller_, GetLeFilterAcceptListSize()); + EXPECT_CALL(*test_controller_, GetLeResolvingListSize()); + EXPECT_CALL(*test_controller_, SupportsBlePrivacy()); + fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); fake_registry_.InjectTestModule(&Controller::Factory, test_controller_); client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory); @@ -133,13 +146,22 @@ class AclManagerNoCallbacksTest : public ::testing::Test { my_initiating_address = AddressWithType( set_random_address_packet.GetRandomAddress(), AddressType::RANDOM_DEVICE_ADDRESS); test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + + ON_CALL(mock_connection_callback_, OnConnectSuccess) + .WillByDefault([this](std::unique_ptr connection) { + connections_.push_back(std::move(connection)); + if (connection_promise_ != nullptr) { + connection_promise_->set_value(); + connection_promise_.reset(); + } + }); } void TearDown() override { // Invalid mutex exception is raised if the connections // are cleared after the AclConnectionInterface is deleted // through fake_registry_. - mock_connection_callback_.Clear(); + connections_.clear(); le_connections_.clear(); fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20)); fake_registry_.StopAll(); @@ -160,9 +182,9 @@ class AclManagerNoCallbacksTest : public ::testing::Test { const bool use_connect_list_ = true; // gd currently only supports connect list std::future GetConnectionFuture() { - ASSERT_LOG(mock_connection_callback_.connection_promise_ == nullptr, "Promises promises ... Only one at a time"); - mock_connection_callback_.connection_promise_ = std::make_unique>(); - return mock_connection_callback_.connection_promise_->get_future(); + ASSERT_LOG(connection_promise_ == nullptr, "Promises promises ... Only one at a time"); + connection_promise_ = std::make_unique>(); + return connection_promise_->get_future(); } std::future GetLeConnectionFuture() { @@ -172,7 +194,7 @@ class AclManagerNoCallbacksTest : public ::testing::Test { } std::shared_ptr GetLastConnection() { - return mock_connection_callback_.connections_.back(); + return connections_.back(); } std::shared_ptr GetLastLeConnection() { @@ -203,29 +225,9 @@ class AclManagerNoCallbacksTest : public ::testing::Test { return command; } - class MockConnectionCallback : public ConnectionCallbacks { - public: - void OnConnectSuccess(std::unique_ptr connection) override { - // Convert to std::shared_ptr during push_back() - connections_.push_back(std::move(connection)); - if (connection_promise_ != nullptr) { - connection_promise_->set_value(); - connection_promise_.reset(); - } - } - - void Clear() { - connections_.clear(); - } - MOCK_METHOD(void, OnConnectRequest, (Address, ClassOfDevice), (override)); - MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason, bool locally_initiated), (override)); - - MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override)); - MOCK_METHOD(void, HACK_OnScoConnectRequest, (Address, ClassOfDevice), (override)); - - std::list> connections_; - std::unique_ptr> connection_promise_; - } mock_connection_callback_; + std::list> connections_; + std::unique_ptr> connection_promise_; + MockConnectionCallback mock_connection_callback_; std::list> le_connections_; std::unique_ptr> le_connection_promise_; @@ -272,7 +274,7 @@ class AclManagerWithConnectionTest : public AclManagerTest { // Invalid mutex exception is raised if the connection // is cleared after the AclConnectionInterface is deleted // through fake_registry_. - mock_connection_callback_.Clear(); + connections_.clear(); le_connections_.clear(); connection_.reset(); fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20)); @@ -283,55 +285,12 @@ class AclManagerWithConnectionTest : public AclManagerTest { uint16_t handle_; std::shared_ptr connection_; - class MockConnectionManagementCallbacks : public ConnectionManagementCallbacks { - public: - MOCK_METHOD1(OnConnectionPacketTypeChanged, void(uint16_t packet_type)); - MOCK_METHOD1(OnAuthenticationComplete, void(hci::ErrorCode hci_status)); - MOCK_METHOD1(OnEncryptionChange, void(EncryptionEnabled enabled)); - MOCK_METHOD0(OnChangeConnectionLinkKeyComplete, void()); - MOCK_METHOD1(OnReadClockOffsetComplete, void(uint16_t clock_offse)); - MOCK_METHOD3(OnModeChange, void(ErrorCode status, Mode current_mode, uint16_t interval)); - MOCK_METHOD5( - OnSniffSubrating, - void( - ErrorCode status, - uint16_t maximum_transmit_latency, - uint16_t maximum_receive_latency, - uint16_t minimum_remote_timeout, - uint16_t minimum_local_timeout)); - MOCK_METHOD5(OnQosSetupComplete, void(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth, - uint32_t latency, uint32_t delay_variation)); - MOCK_METHOD6(OnFlowSpecificationComplete, - void(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate, - uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency)); - MOCK_METHOD0(OnFlushOccurred, void()); - MOCK_METHOD1(OnRoleDiscoveryComplete, void(Role current_role)); - MOCK_METHOD1(OnReadLinkPolicySettingsComplete, void(uint16_t link_policy_settings)); - MOCK_METHOD1(OnReadAutomaticFlushTimeoutComplete, void(uint16_t flush_timeout)); - MOCK_METHOD1(OnReadTransmitPowerLevelComplete, void(uint8_t transmit_power_level)); - MOCK_METHOD1(OnReadLinkSupervisionTimeoutComplete, void(uint16_t link_supervision_timeout)); - MOCK_METHOD1(OnReadFailedContactCounterComplete, void(uint16_t failed_contact_counter)); - MOCK_METHOD1(OnReadLinkQualityComplete, void(uint8_t link_quality)); - MOCK_METHOD2(OnReadAfhChannelMapComplete, void(AfhMode afh_mode, std::array afh_channel_map)); - MOCK_METHOD1(OnReadRssiComplete, void(uint8_t rssi)); - MOCK_METHOD2(OnReadClockComplete, void(uint32_t clock, uint16_t accuracy)); - MOCK_METHOD1(OnCentralLinkKeyComplete, void(KeyFlag flag)); - MOCK_METHOD2(OnRoleChange, void(ErrorCode hci_status, Role new_role)); - MOCK_METHOD1(OnDisconnection, void(ErrorCode reason)); - MOCK_METHOD4( - OnReadRemoteVersionInformationComplete, - void(hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version)); - MOCK_METHOD1(OnReadRemoteSupportedFeaturesComplete, void(uint64_t features)); - MOCK_METHOD3( - OnReadRemoteExtendedFeaturesComplete, void(uint8_t page_number, uint8_t max_page_number, uint64_t features)); - } mock_connection_management_callbacks_; + MockConnectionManagementCallbacks mock_connection_management_callbacks_; }; TEST_F(AclManagerTest, startup_teardown) {} TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_success) { - uint16_t handle = 1; - acl_manager_->CreateConnection(remote); // Wait for the connection request @@ -342,8 +301,8 @@ TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_success) { auto first_connection = GetConnectionFuture(); - test_hci_layer_->IncomingEvent( - ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, remote, LinkType::ACL, Enable::DISABLED)); + test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create( + ErrorCode::SUCCESS, kHciHandle, remote, LinkType::ACL, Enable::DISABLED)); auto first_connection_status = first_connection.wait_for(kTimeout); ASSERT_EQ(first_connection_status, std::future_status::ready); @@ -353,8 +312,6 @@ TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_success) { } TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_fail) { - uint16_t handle = 0x123; - acl_manager_->CreateConnection(remote); // Wait for the connection request @@ -363,12 +320,36 @@ TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_fail) { last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION); } + struct callback_t { + hci::Address bd_addr; + hci::ErrorCode reason; + bool is_locally_initiated; + }; + + auto promise = std::promise(); + auto future = promise.get_future(); + ON_CALL(mock_connection_callback_, OnConnectFail) + .WillByDefault( + [&promise](hci::Address bd_addr, hci::ErrorCode reason, bool is_locally_initiated) { + promise.set_value({ + .bd_addr = bd_addr, + .reason = reason, + .is_locally_initiated = is_locally_initiated, + }); + }); + EXPECT_CALL(mock_connection_callback_, OnConnectFail(remote, ErrorCode::PAGE_TIMEOUT, true)); - test_hci_layer_->IncomingEvent( - ConnectionCompleteBuilder::Create(ErrorCode::PAGE_TIMEOUT, handle, remote, LinkType::ACL, Enable::DISABLED)); - fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20)); - fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20)); - fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20)); + + // Remote response event to the connection request + test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create( + ErrorCode::PAGE_TIMEOUT, kHciHandle, remote, LinkType::ACL, Enable::DISABLED)); + + ASSERT_EQ(std::future_status::ready, future.wait_for(kTimeout)); + auto callback = future.get(); + + ASSERT_EQ(remote, callback.bd_addr); + ASSERT_EQ(ErrorCode::PAGE_TIMEOUT, callback.reason); + ASSERT_EQ(true, callback.is_locally_initiated); } class AclManagerWithLeConnectionTest : public AclManagerTest { @@ -398,7 +379,7 @@ class AclManagerWithLeConnectionTest : public AclManagerTest { auto first_connection = GetLeConnectionFuture(); EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(remote_with_type_, _)) .WillRepeatedly([this]( - hci::AddressWithType address_with_type, + hci::AddressWithType /* address_with_type */, std::unique_ptr connection) { le_connections_.push_back(std::move(connection)); if (le_connection_promise_ != nullptr) { @@ -436,7 +417,7 @@ class AclManagerWithLeConnectionTest : public AclManagerTest { // Invalid mutex exception is raised if the connection // is cleared after the AclConnectionInterface is deleted // through fake_registry_. - mock_connection_callback_.Clear(); + connections_.clear(); le_connections_.clear(); connection_.reset(); fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20)); @@ -559,15 +540,15 @@ TEST_F(AclManagerTest, create_connection_with_fast_mode) { auto first_connection = GetLeConnectionFuture(); EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(remote_with_type, _)) - .WillRepeatedly( - [this]( - hci::AddressWithType address_with_type, std::unique_ptr connection) { - le_connections_.push_back(std::move(connection)); - if (le_connection_promise_ != nullptr) { - le_connection_promise_->set_value(); - le_connection_promise_.reset(); - } - }); + .WillRepeatedly([this]( + hci::AddressWithType /* address_with_type */, + std::unique_ptr connection) { + le_connections_.push_back(std::move(connection)); + if (le_connection_promise_ != nullptr) { + le_connection_promise_->set_value(); + le_connection_promise_.reset(); + } + }); test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( ErrorCode::SUCCESS, @@ -600,15 +581,15 @@ TEST_F(AclManagerTest, create_connection_with_slow_mode) { test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); auto first_connection = GetLeConnectionFuture(); EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(remote_with_type, _)) - .WillRepeatedly( - [this]( - hci::AddressWithType address_with_type, std::unique_ptr connection) { - le_connections_.push_back(std::move(connection)); - if (le_connection_promise_ != nullptr) { - le_connection_promise_->set_value(); - le_connection_promise_.reset(); - } - }); + .WillRepeatedly([this]( + hci::AddressWithType /* address_with_type */, + std::unique_ptr connection) { + le_connections_.push_back(std::move(connection)); + if (le_connection_promise_ != nullptr) { + le_connection_promise_->set_value(); + le_connection_promise_.reset(); + } + }); test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( ErrorCode::SUCCESS, @@ -1407,7 +1388,179 @@ TEST_F(AclManagerWithConnectionTest, remote_esco_connect_request) { fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20)); } -} // namespace +class AclManagerWithConnectionAssemblerTest : public AclManagerWithConnectionTest { + protected: + void SetUp() override { + AclManagerWithConnectionTest::SetUp(); + connection_queue_end_ = connection_->GetAclQueueEnd(); + } + + std::vector MakeAclPayload(size_t length, uint16_t cid, uint8_t offset) { + std::vector acl_payload; + acl_payload.push_back(length & 0xff); + acl_payload.push_back((length >> 8u) & 0xff); + acl_payload.push_back(cid & 0xff); + acl_payload.push_back((cid >> 8u) & 0xff); + for (uint8_t i = 0; i < length; i++) { + acl_payload.push_back(i + offset); + } + return acl_payload; + } + + void SendSinglePacket(const std::vector& acl_payload) { + auto payload_builder = std::make_unique(acl_payload); + + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, + BroadcastFlag::POINT_TO_POINT, + std::move(payload_builder))); + } + + void ReceiveAndCheckSinglePacket(const std::vector& acl_payload) { + std::unique_ptr> received; + do { + received = connection_queue_end_->TryDequeue(); + } while (received == nullptr); + + std::vector received_vector; + for (uint8_t byte : *received) { + received_vector.push_back(byte); + } + + EXPECT_THAT(received_vector, ElementsAreArray(acl_payload)); + } + + void SendAndReceiveSinglePacket(const std::vector& acl_payload) { + SendSinglePacket(acl_payload); + ReceiveAndCheckSinglePacket(acl_payload); + } + + void TearDown() override { + // Make sure that all previous packets were received and the assembler is in a good state. + SendAndReceiveSinglePacket(MakeAclPayload(0x60, 0xACC, 3)); + AclManagerWithConnectionTest::TearDown(); + } + AclConnection::QueueUpEnd* connection_queue_end_{}; +}; + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_single_packet) {} + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_short_packet_discarded) { + std::vector invalid_payload{1, 2}; + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, + BroadcastFlag::POINT_TO_POINT, + std::make_unique(invalid_payload))); +} + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_two_short_packets_discarded) { + std::vector invalid_payload{1, 2}; + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, + BroadcastFlag::POINT_TO_POINT, + std::make_unique(invalid_payload))); + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, + BroadcastFlag::POINT_TO_POINT, + std::make_unique(invalid_payload))); +} + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_single_valid_packet) { + SendAndReceiveSinglePacket(MakeAclPayload(20, 0x41, 2)); +} + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_one_byte_packets) { + size_t payload_size = 0x30; + std::vector payload = MakeAclPayload(payload_size, 0xABB /* cid */, 4 /* offset */); + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, + BroadcastFlag::POINT_TO_POINT, + std::make_unique( + std::vector{payload.cbegin(), payload.cbegin() + 1}))); + for (size_t i = 1; i < payload.size(); i++) { + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::CONTINUING_FRAGMENT, + BroadcastFlag::POINT_TO_POINT, + std::make_unique( + std::vector{payload.cbegin() + i, payload.cbegin() + i + 1}))); + } + ReceiveAndCheckSinglePacket(payload); +} + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_two_byte_packets) { + size_t payload_size = 0x30; // must be even + std::vector payload = MakeAclPayload(payload_size, 0xABB /* cid */, 4 /* offset */); + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, + BroadcastFlag::POINT_TO_POINT, + std::make_unique( + std::vector{payload.cbegin(), payload.cbegin() + 2}))); + for (size_t i = 1; i < payload.size() / 2; i++) { + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::CONTINUING_FRAGMENT, + BroadcastFlag::POINT_TO_POINT, + std::make_unique( + std::vector{payload.cbegin() + 2 * i, payload.cbegin() + 2 * (i + 1)}))); + } + ReceiveAndCheckSinglePacket(payload); +} + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_continuation_without_begin) { + size_t payload_size = 0x30; + std::vector payload = MakeAclPayload(payload_size, 0xABB /* cid */, 4 /* offset */); + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::CONTINUING_FRAGMENT, + BroadcastFlag::POINT_TO_POINT, + std::make_unique(std::vector{payload.cbegin(), payload.cend()}))); +} + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_drop_broadcasts) { + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE, + BroadcastFlag::ACTIVE_PERIPHERAL_BROADCAST, + std::make_unique(MakeAclPayload(20, 0xBBB /* cid */, 5 /* offset */)))); +} + +TEST_F(AclManagerWithConnectionAssemblerTest, assembler_test_drop_non_flushable) { + test_hci_layer_->IncomingAclData( + handle_, + AclBuilder::Create( + handle_, + PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE, + BroadcastFlag::POINT_TO_POINT, + std::make_unique(MakeAclPayload(20, 0xAAA /* cid */, 6 /* offset */)))); +} + } // namespace acl_manager } // namespace hci } // namespace bluetooth diff --git a/system/gd/hci/acl_manager_unittest.cc b/system/gd/hci/acl_manager_unittest.cc index c780e6371f4de9b6dd36fe178638bd59c9c47a7d..f1273631b7644a3452bd3a932106b7f032c43eda 100644 --- a/system/gd/hci/acl_manager_unittest.cc +++ b/system/gd/hci/acl_manager_unittest.cc @@ -105,7 +105,7 @@ class TestController : public Controller { return total_acl_buffers_; } - bool IsSupported(bluetooth::hci::OpCode op_code) const override { + bool IsSupported(bluetooth::hci::OpCode /* op_code */) const override { return false; } @@ -119,7 +119,7 @@ class TestController : public Controller { protected: void Start() override {} void Stop() override {} - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} private: uint16_t acl_buffer_length_ = 1024; @@ -165,7 +165,7 @@ class TestHciLayer : public HciLayer { return CommandView::Create(GetPacketView(std::move(last))); } - ConnectionManagementCommandView GetCommand(OpCode op_code) { + ConnectionManagementCommandView GetCommand(OpCode /* op_code */) { if (command_future_ != nullptr) { command_future_->wait_for(std::chrono::milliseconds(1000)); } @@ -180,7 +180,7 @@ class TestHciLayer : public HciLayer { return command; } - ConnectionManagementCommandView GetLastCommand(OpCode op_code) { + ConnectionManagementCommandView GetLastCommand(OpCode /* op_code */) { if (!command_queue_.empty() && command_future_ != nullptr) { command_future_.reset(); hci_command_promise_.reset(); @@ -303,7 +303,7 @@ class TestHciLayer : public HciLayer { return acl_queue_.GetUpEnd(); } - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} void Start() override { RegisterEventHandler( EventCode::COMMAND_COMPLETE, GetHandler()->BindOn(this, &TestHciLayer::CommandCompleteCallback)); @@ -371,7 +371,9 @@ class MockConnectionCallback : public ConnectionCallbacks { class MockLeConnectionCallbacks : public LeConnectionCallbacks { public: - void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr connection) override { + void OnLeConnectSuccess( + AddressWithType /* address_with_type */, + std::unique_ptr connection) override { le_connections_.push_back(std::move(connection)); if (le_connection_promise_ != nullptr) { std::promise* prom = le_connection_promise_.release(); diff --git a/system/gd/hci/address_with_type.h b/system/gd/hci/address_with_type.h index 874c7d7e8f645c51eed337918dd1417ff12389a9..c07ceb0ce6c547444bf6d59ca02f68a9fd9a27d5 100644 --- a/system/gd/hci/address_with_type.h +++ b/system/gd/hci/address_with_type.h @@ -26,6 +26,7 @@ #include "crypto_toolbox/crypto_toolbox.h" #include "hci/address.h" #include "hci/hci_packets.h" +#include "hci/octets.h" namespace bluetooth { namespace hci { @@ -51,16 +52,16 @@ class AddressWithType final : public bluetooth::common::IRedactableLoggable { } /* Is this an Resolvable Private Address, that was generated from given irk ? */ - bool IsRpaThatMatchesIrk(const crypto_toolbox::Octet16& irk) const { + bool IsRpaThatMatchesIrk(const hci::Octet16& irk) const { if (!IsRpa()) return false; /* use the 3 MSB of bd address as prand */ - uint8_t prand[3]; + Octet16 prand{}; prand[0] = address_.address[3]; prand[1] = address_.address[4]; prand[2] = address_.address[5]; /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */ - crypto_toolbox::Octet16 computed_hash = crypto_toolbox::aes_128(irk, &prand[0], 3); + hci::Octet16 computed_hash = crypto_toolbox::aes_128(irk, prand); uint8_t hash[3]; hash[0] = address_.address[0]; hash[1] = address_.address[1]; diff --git a/system/gd/hci/address_with_type_test.cc b/system/gd/hci/address_with_type_test.cc index 001f4542cbe9c033207357c11cb2e1ca35570fa2..98a81deacd77c7d68949ae29e71b33c438c902de 100644 --- a/system/gd/hci/address_with_type_test.cc +++ b/system/gd/hci/address_with_type_test.cc @@ -25,6 +25,7 @@ #include "hci/address.h" #include "hci/hci_packets.h" +#include "hci/octets.h" namespace bluetooth { namespace hci { @@ -91,8 +92,23 @@ TEST(AddressWithTypeTest, IsRpaThatMatchesIrk) { AddressWithType(Address{{0xDE, 0x12, 0xC9, 0x03, 0x02, 0x50}}, AddressType::RANDOM_DEVICE_ADDRESS); AddressWithType address_2 = AddressWithType(Address{{0xDD, 0x12, 0xC9, 0x03, 0x02, 0x50}}, AddressType::RANDOM_DEVICE_ADDRESS); - crypto_toolbox::Octet16 irk_1{0x90, 0x5e, 0x60, 0x59, 0xc9, 0x11, 0x43, 0x7b, - 0x04, 0x09, 0x6a, 0x53, 0x28, 0xe6, 0x59, 0x6d}; + Octet16 irk_1{ + 0x90, + 0x5e, + 0x60, + 0x59, + 0xc9, + 0x11, + 0x43, + 0x7b, + 0x04, + 0x09, + 0x6a, + 0x53, + 0x28, + 0xe6, + 0x59, + 0x6d}; EXPECT_TRUE(address_1.IsRpaThatMatchesIrk(irk_1)); EXPECT_FALSE(address_2.IsRpaThatMatchesIrk(irk_1)); diff --git a/system/gd/hci/controller.cc b/system/gd/hci/controller.cc index 5576293017cb29f90efb67f27e544a2d54447bf2..7b78be8aa419b2de2a5133000d994f6722ee6137 100644 --- a/system/gd/hci/controller.cc +++ b/system/gd/hci/controller.cc @@ -23,6 +23,8 @@ #include #include "common/init_flags.h" +#include "dumpsys_data_generated.h" +#include "hci/event_checkers.h" #include "hci/hci_layer.h" #include "hci_controller_generated.h" #include "os/metrics.h" @@ -98,6 +100,12 @@ struct Controller::impl { handler->BindOnceOn(this, &Controller::impl::le_read_buffer_size_handler)); } + if (is_supported(OpCode::READ_LOCAL_SUPPORTED_CODECS_V1)) { + hci_->EnqueueCommand( + ReadLocalSupportedCodecsV1Builder::Create(), + handler->BindOnceOn(this, &Controller::impl::read_local_supported_codecs_v1_handler)); + } + hci_->EnqueueCommand( LeReadFilterAcceptListSizeBuilder::Create(), handler->BindOnceOn(this, &Controller::impl::le_read_connect_list_size_handler)); @@ -208,9 +216,6 @@ struct Controller::impl { } void Stop() { - if (bluetooth::common::init_flags::gd_core_is_enabled()) { - hci_->UnregisterEventHandler(EventCode::NUMBER_OF_COMPLETED_PACKETS); - } hci_ = nullptr; } @@ -369,6 +374,16 @@ struct Controller::impl { } } + void read_local_supported_codecs_v1_handler(CommandCompleteView view) { + auto complete_view = ReadLocalSupportedCodecsV1CompleteView::Create(view); + ASSERT(complete_view.IsValid()); + ErrorCode status = complete_view.GetStatus(); + ASSERT_LOG( + status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str()); + local_supported_codec_ids_ = complete_view.GetSupportedCodecs(); + local_supported_vendor_codec_ids_ = complete_view.GetVendorSpecificCodecs(); + } + void set_min_encryption_key_size_handler(CommandCompleteView view) { auto complete_view = SetMinEncryptionKeySizeCompleteView::Create(view); ASSERT(complete_view.IsValid()); @@ -604,8 +619,9 @@ struct Controller::impl { void set_event_mask(uint64_t event_mask) { std::unique_ptr packet = SetEventMaskBuilder::Create(event_mask); - hci_->EnqueueCommand(std::move(packet), module_.GetHandler()->BindOnceOn( - this, &Controller::impl::check_status)); + hci_->EnqueueCommand( + std::move(packet), + module_.GetHandler()->BindOnce(check_complete)); } void write_le_host_support(Enable enable, Enable deprecated_host_bit) { @@ -616,27 +632,28 @@ struct Controller::impl { std::unique_ptr packet = WriteLeHostSupportBuilder::Create(enable, deprecated_host_bit); hci_->EnqueueCommand( std::move(packet), - module_.GetHandler()->BindOnceOn(this, &Controller::impl::check_status)); + module_.GetHandler()->BindOnce(check_complete)); } void write_simple_pairing_mode(Enable enable) { std::unique_ptr packet = WriteSimplePairingModeBuilder::Create(enable); hci_->EnqueueCommand( std::move(packet), - module_.GetHandler()->BindOnceOn(this, &Controller::impl::check_status)); + module_.GetHandler()->BindOnce(check_complete)); } void reset() { std::unique_ptr packet = ResetBuilder::Create(); - hci_->EnqueueCommand(std::move(packet), - module_.GetHandler()->BindOnceOn(this, &Controller::impl::check_status)); + hci_->EnqueueCommand( + std::move(packet), module_.GetHandler()->BindOnce(check_complete)); } void le_rand(LeRandCallback cb) { std::unique_ptr packet = LeRandBuilder::Create(); hci_->EnqueueCommand( std::move(packet), - module_.GetHandler()->BindOnceOn(this, &Controller::impl::le_rand_cb, cb)); + module_.GetHandler()->BindOnceOn( + this, &Controller::impl::le_rand_cb, std::move(cb))); } template @@ -645,12 +662,13 @@ struct Controller::impl { auto status_view = T::Create(view); ASSERT(status_view.IsValid()); ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); - cb.Run(status_view.GetRandomNumber()); + std::move(cb).Run(status_view.GetRandomNumber()); } void set_event_filter(std::unique_ptr packet) { - hci_->EnqueueCommand(std::move(packet), module_.GetHandler()->BindOnceOn( - this, &Controller::impl::check_status)); + hci_->EnqueueCommand( + std::move(packet), + module_.GetHandler()->BindOnce(check_complete)); } void write_local_name(std::string local_name) { @@ -661,8 +679,9 @@ struct Controller::impl { std::copy(std::begin(local_name), std::end(local_name), std::begin(local_name_array)); std::unique_ptr packet = WriteLocalNameBuilder::Create(local_name_array); - hci_->EnqueueCommand(std::move(packet), module_.GetHandler()->BindOnceOn( - this, &Controller::impl::check_status)); + hci_->EnqueueCommand( + std::move(packet), + module_.GetHandler()->BindOnce(check_complete)); } void host_buffer_size(uint16_t host_acl_data_packet_length, uint8_t host_synchronous_data_packet_length, @@ -670,32 +689,16 @@ struct Controller::impl { std::unique_ptr packet = HostBufferSizeBuilder::Create(host_acl_data_packet_length, host_synchronous_data_packet_length, host_total_num_acl_data_packets, host_total_num_synchronous_data_packets); - hci_->EnqueueCommand(std::move(packet), module_.GetHandler()->BindOnceOn( - this, &Controller::impl::check_status)); + hci_->EnqueueCommand( + std::move(packet), + module_.GetHandler()->BindOnce(check_complete)); } void le_set_event_mask(uint64_t le_event_mask) { std::unique_ptr packet = LeSetEventMaskBuilder::Create(le_event_mask); hci_->EnqueueCommand( - std::move(packet), module_.GetHandler()->BindOnceOn(this, &Controller::impl::check_le_set_event_mask_status)); - } - - void check_le_set_event_mask_status(CommandCompleteView view) { - ASSERT(view.IsValid()); - auto status_view = LeSetEventMaskCompleteView::Create(view); - ASSERT(status_view.IsValid()); - auto status = status_view.GetStatus(); - if (status != ErrorCode::SUCCESS) { - LOG_WARN("Unexpected return status %s", ErrorCodeText(status).c_str()); - } - } - - template - void check_status(CommandCompleteView view) { - ASSERT(view.IsValid()); - auto status_view = T::Create(view); - ASSERT(status_view.IsValid()); - ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); + std::move(packet), + module_.GetHandler()->BindOnce(check_complete)); } #define OP_CODE_MAPPING(name) \ @@ -763,6 +766,8 @@ struct Controller::impl { OP_CODE_MAPPING(HOLD_MODE) OP_CODE_MAPPING(SNIFF_MODE) OP_CODE_MAPPING(EXIT_SNIFF_MODE) + OP_CODE_MAPPING(PARK_STATE) + OP_CODE_MAPPING(EXIT_PARK_STATE) OP_CODE_MAPPING(QOS_SETUP) OP_CODE_MAPPING(ROLE_DISCOVERY) OP_CODE_MAPPING(SWITCH_ROLE) @@ -1052,6 +1057,22 @@ struct Controller::impl { return true; case OpCode::NONE: return false; + case OpCode::LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES: + case OpCode::LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES: + case OpCode::LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES: + case OpCode::LE_CS_SECURITY_ENABLE: + case OpCode::LE_CS_SET_DEFAULT_SETTINGS: + case OpCode::LE_CS_READ_REMOTE_FAE_TABLE: + case OpCode::LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE: + case OpCode::LE_CS_CREATE_CONFIG: + case OpCode::LE_CS_REMOVE_CONFIG: + case OpCode::LE_CS_SET_CHANNEL_CLASSIFICATION: + case OpCode::LE_CS_PROCEDURE_ENABLE: + case OpCode::LE_CS_TEST: + case OpCode::LE_CS_TEST_END: + case OpCode::LE_CS_SET_PROCEDURE_PARAMETERS: + // TODO add to OP_CODE_MAPPING list + return false; } return false; } @@ -1073,6 +1094,8 @@ struct Controller::impl { Address mac_address_{}; std::string local_name_{}; LeBufferSize le_buffer_size_{}; + std::vector local_supported_codec_ids_{}; + std::vector local_supported_vendor_codec_ids_{}; LeBufferSize iso_buffer_size_{}; uint64_t le_local_supported_features_{}; uint64_t le_supported_states_{}; @@ -1114,6 +1137,10 @@ LocalVersionInformation Controller::GetLocalVersionInformation() const { return impl_->local_version_information_; } +std::vector Controller::GetLocalSupportedBrEdrCodecIds() const { + return impl_->local_supported_codec_ids_; +} + #define BIT(x) (0x1ULL << (x)) #define LOCAL_FEATURE_ACCESSOR(name, page, bit) \ @@ -1233,7 +1260,7 @@ void Controller::Reset() { } void Controller::LeRand(LeRandCallback cb) { - CallOn(impl_.get(), &impl::le_rand, cb); + CallOn(impl_.get(), &impl::le_rand, std::move(cb)); } void Controller::SetEventFilterClearAll() { @@ -1358,6 +1385,25 @@ bool Controller::IsSupported(bluetooth::hci::OpCode op_code) const { return impl_->is_supported(op_code); } +uint64_t Controller::MaskLeEventMask(HciVersion version, uint64_t mask) { + if (!common::init_flags::subrating_is_enabled()) { + mask = mask & ~(static_cast(LLFeaturesBits::CONNECTION_SUBRATING_HOST_SUPPORT)); + } + if (version >= HciVersion::V_5_3) { + return mask; + } else if (version >= HciVersion::V_5_2) { + return mask & kLeEventMask52; + } else if (version >= HciVersion::V_5_1) { + return mask & kLeEventMask51; + } else if (version >= HciVersion::V_5_0) { + return mask & kLeEventMask50; + } else if (version >= HciVersion::V_4_2) { + return mask & kLeEventMask42; + } else { + return mask & kLeEventMask41; + } +} + const ModuleFactory Controller::Factory = ModuleFactory([]() { return new Controller(); }); void Controller::ListDependencies(ModuleList* list) const { diff --git a/system/gd/hci/controller.h b/system/gd/hci/controller.h index 4dc94752253b68d22c0b86eb1da1bb6945732550..b83b215e099481189f72c51b8d3ccdaef62e3392 100644 --- a/system/gd/hci/controller.h +++ b/system/gd/hci/controller.h @@ -16,13 +16,10 @@ #pragma once -#include "common/init_flags.h" #include "hci/address.h" #include "hci/hci_packets.h" #include "hci/le_rand_callback.h" -#include "hci_controller_generated.h" #include "module.h" -#include "os/handler.h" // TODO Remove this once all QTI specific hacks are removed. #define LMP_COMPID_QTI 0x001D @@ -185,6 +182,9 @@ class Controller : public Module { virtual uint8_t GetLePeriodicAdvertiserListSize() const; + // 7.4.8 Read Local Supported Codecs command v1 only returns codecs on the BR/EDR transport + virtual std::vector GetLocalSupportedBrEdrCodecIds() const; + struct VendorCapabilities { uint8_t is_supported_; uint8_t max_advt_instances_; @@ -215,25 +215,11 @@ class Controller : public Module { static constexpr uint64_t kLeEventMask53 = 0x00000007ffffffff; static constexpr uint64_t kLeEventMask52 = 0x00000003ffffffff; static constexpr uint64_t kLeEventMask51 = 0x0000000000ffffff; + static constexpr uint64_t kLeEventMask50 = 0x0000000000ffffff; static constexpr uint64_t kLeEventMask42 = 0x00000000000003ff; static constexpr uint64_t kLeEventMask41 = 0x000000000000003f; - static uint64_t MaskLeEventMask(HciVersion version, uint64_t mask) { - if (!common::init_flags::subrating_is_enabled()) { - mask = mask & ~(static_cast(LLFeaturesBits::CONNECTION_SUBRATING_HOST_SUPPORT)); - } - if (version >= HciVersion::V_5_3) { - return mask; - } else if (version >= HciVersion::V_5_2) { - return mask & kLeEventMask52; - } else if (version >= HciVersion::V_5_1) { - return mask & kLeEventMask51; - } else if (version >= HciVersion::V_4_2) { - return mask & kLeEventMask42; - } else { - return mask & kLeEventMask41; - } - } + static uint64_t MaskLeEventMask(HciVersion version, uint64_t mask); protected: void ListDependencies(ModuleList* list) const override; diff --git a/system/gd/hci/controller_test.cc b/system/gd/hci/controller_test.cc index a17171a2c40b26ec63b18d7e799754235f6d9b78..7a16b203ff2cab0f9c92f422f5e7807cccfeb401 100644 --- a/system/gd/hci/controller_test.cc +++ b/system/gd/hci/controller_test.cc @@ -18,25 +18,21 @@ #include -#include #include #include -#include #include #include "common/bind.h" -#include "common/callback.h" #include "common/init_flags.h" #include "hci/address.h" #include "hci/hci_layer.h" +#include "module_dumper.h" #include "os/thread.h" #include "packet/raw_builder.h" using namespace bluetooth; using namespace std::chrono_literals; -using common::BidiQueue; -using common::BidiQueueEnd; using packet::kLittleEndian; using packet::PacketView; using packet::RawBuilder; @@ -76,8 +72,8 @@ class TestHciLayer : public HciLayer { } void EnqueueCommand( - std::unique_ptr command, - common::ContextualOnceCallback on_status) override { + std::unique_ptr /* command */, + common::ContextualOnceCallback /* on_status */) override { FAIL() << "Controller properties should not generate Command Status"; } @@ -116,6 +112,12 @@ class TestHciLayer : public HciLayer { event_builder = ReadLocalSupportedCommandsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, supported_commands); } break; + case (OpCode::READ_LOCAL_SUPPORTED_CODECS_V1): { + std::vector supported_codecs{0, 1, 2, 3, 4, 5, 6}; + std::vector supported_vendor_codecs; + event_builder = ReadLocalSupportedCodecsV1CompleteBuilder::Create( + num_packets, ErrorCode::SUCCESS, supported_codecs, supported_vendor_codecs); + } break; case (OpCode::READ_LOCAL_EXTENDED_FEATURES): { ReadLocalExtendedFeaturesView read_command = ReadLocalExtendedFeaturesView::Create(command); ASSERT_TRUE(read_command.IsValid()); @@ -250,7 +252,7 @@ class TestHciLayer : public HciLayer { number_of_completed_packets_callback_.Invoke(event); } - CommandView GetCommand(OpCode op_code) { + CommandView GetCommand(OpCode /* op_code */) { std::unique_lock lock(mutex_); std::chrono::milliseconds time = std::chrono::milliseconds(3000); @@ -268,7 +270,7 @@ class TestHciLayer : public HciLayer { return command; } - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} void Start() override {} void Stop() override {} @@ -358,6 +360,7 @@ TEST_F(ControllerTest, read_controller_info) { ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_rx_time_, 0x78); ASSERT_EQ(controller_->GetLeMaximumAdvertisingDataLength(), 0x0672); ASSERT_EQ(controller_->GetLeNumberOfSupportedAdverisingSets(), 0xF0); + ASSERT_TRUE(controller_->GetLocalSupportedBrEdrCodecIds().size() > 0); } TEST_F(ControllerTest, read_write_local_name) { diff --git a/system/gd/hci/distance_measurement_interface.h b/system/gd/hci/distance_measurement_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..91d6ef7bbf0b7c40e43c7d2c66004fde14d4755c --- /dev/null +++ b/system/gd/hci/distance_measurement_interface.h @@ -0,0 +1,39 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hci/command_interface.h" +#include "hci/hci_packets.h" + +namespace bluetooth { +namespace hci { + +constexpr hci::SubeventCode DistanceMeasurementEvents[] = { + hci::SubeventCode::LE_CS_TEST_END_COMPLETE, + hci::SubeventCode::LE_CS_SUBEVENT_RESULT_CONTINUE, + hci::SubeventCode::LE_CS_SUBEVENT_RESULT, + hci::SubeventCode::LE_CS_PROCEDURE_ENABLE_COMPLETE, + hci::SubeventCode::LE_CS_CONFIG_COMPLETE, + hci::SubeventCode::LE_CS_SECURITY_ENABLE_COMPLETE, + hci::SubeventCode::LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE, + hci::SubeventCode::LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE, +}; + +typedef CommandInterface DistanceMeasurementInterface; + +} // namespace hci +} // namespace bluetooth diff --git a/system/gd/hci/distance_measurement_manager.cc b/system/gd/hci/distance_measurement_manager.cc index 488b78e456b177acfd1877bd3c46dbb3819aad87..b7379ca287adfe0bd8cb29e3f77d76cfe104c60e 100644 --- a/system/gd/hci/distance_measurement_manager.cc +++ b/system/gd/hci/distance_measurement_manager.cc @@ -19,7 +19,10 @@ #include +#include "common/strings.h" #include "hci/acl_manager.h" +#include "hci/distance_measurement_interface.h" +#include "hci/event_checkers.h" #include "hci/hci_layer.h" #include "module.h" #include "os/handler.h" @@ -33,6 +36,24 @@ const ModuleFactory DistanceMeasurementManager::Factory = static constexpr uint16_t kIllegalConnectionHandle = 0xffff; static constexpr uint8_t kTxPowerNotAvailable = 0xfe; static constexpr int8_t kRSSIDropOffAt1M = 41; +static constexpr uint8_t kCsMaxTxPower = 12; // 12 dBm +static constexpr CsSyncAntennaSelection kCsSyncAntennaSelection = CsSyncAntennaSelection::ANTENNA_2; +static constexpr uint8_t kConfigId = 0x01; // Use 0x01 to create config and enable procedure +static constexpr uint8_t kMinMainModeSteps = 0x02; +static constexpr uint8_t kMaxMainModeSteps = 0x05; +static constexpr uint8_t kMainModeRepetition = 0x00; // No repetition +static constexpr uint8_t kMode0Steps = + 0x03; // Maximum number of mode-0 steps to increase success subevent rate +static constexpr uint8_t kChannelMapRepetition = 0x01; // No repetition +static constexpr uint8_t kCh3cJump = 0x03; // Skip 3 Channels +static constexpr uint16_t kMaxProcedureLen = 0xFFFF; // 40.959375s +static constexpr uint16_t kMinProcedureInterval = 0x01; +static constexpr uint16_t kMaxProcedureInterval = 0xFF; +static constexpr uint16_t kMaxProcedureCount = 0x01; +static constexpr uint32_t kMinSubeventLen = 0x0004E2; // 1250us +static constexpr uint32_t kMaxSubeventLen = 0x3d0900; // 4s +static constexpr uint8_t kToneAntennaConfigSelection = 0x07; // 2x2 +static constexpr uint8_t kTxPwrDelta = 0x00; struct DistanceMeasurementManager::impl { ~impl() {} @@ -43,6 +64,11 @@ struct DistanceMeasurementManager::impl { hci_layer_->RegisterLeEventHandler( hci::SubeventCode::TRANSMIT_POWER_REPORTING, handler_->BindOn(this, &impl::on_transmit_power_reporting)); + distance_measurement_interface_ = hci_layer_->GetDistanceMeasurementInterface( + handler_->BindOn(this, &DistanceMeasurementManager::impl::handle_event)); + distance_measurement_interface_->EnqueueCommand( + LeCsReadLocalSupportedCapabilitiesBuilder::Create(), + handler_->BindOnceOn(this, &impl::on_cs_read_local_supported_capabilities)); } void stop() { @@ -60,7 +86,7 @@ struct DistanceMeasurementManager::impl { // Remove this check if we support any connection less method if (connection_handle == kIllegalConnectionHandle) { - LOG_WARN("Can not find any LE connection"); + LOG_WARN("Can't find any LE connection for %s", ADDRESS_TO_LOGGABLE_CSTR(address)); distance_measurement_callbacks_->OnDistanceMeasurementStartFail( address, REASON_NO_LE_CONNECTION, method); return; @@ -84,6 +110,35 @@ struct DistanceMeasurementManager::impl { rssi_trackers[address].frequency = frequency; } } break; + case METHOD_CS: { + start_distance_measurement_with_cs(address, connection_handle); + } break; + } + } + + void start_distance_measurement_with_cs( + const Address& cs_remote_address, uint16_t connection_handle) { + LOG_INFO( + "connection_handle: %d, address: %s", + connection_handle, + ADDRESS_TO_LOGGABLE_CSTR(cs_remote_address)); + if (cs_trackers_.find(connection_handle) != cs_trackers_.end() && + cs_trackers_[connection_handle].address != cs_remote_address) { + LOG_WARN("Remove old tracker for %s ", ADDRESS_TO_LOGGABLE_CSTR(cs_remote_address)); + cs_trackers_.erase(connection_handle); + } + + if (cs_trackers_.find(connection_handle) == cs_trackers_.end()) { + // Create a cs tracker with role initiator + cs_trackers_[connection_handle].address = cs_remote_address; + // TODO: Check ROLE via CS config. (b/304295768) + cs_trackers_[connection_handle].role = CsRole::INITIATOR; + } + + if (!cs_trackers_[connection_handle].setup_complete) { + send_le_cs_read_remote_supported_capabilities(connection_handle); + send_le_cs_set_default_settings(connection_handle); + send_le_cs_security_enable(connection_handle); } } @@ -98,13 +153,20 @@ struct DistanceMeasurementManager::impl { hci_layer_->EnqueueCommand( LeSetTransmitPowerReportingEnableBuilder::Create( rssi_trackers[address].handle, 0x00, 0x00), - handler_->BindOnceOn( - this, &impl::check_status)); + handler_->BindOnce(check_complete)); rssi_trackers[address].alarm->Cancel(); rssi_trackers[address].alarm.reset(); rssi_trackers.erase(address); } } break; + case METHOD_CS: { + uint16_t connection_handle = acl_manager_->HACK_GetLeHandle(address); + if (cs_trackers_.find(connection_handle) == cs_trackers_.end()) { + LOG_WARN("Can't find CS tracker for %s ", ADDRESS_TO_LOGGABLE_CSTR(address)); + } else { + cs_trackers_.erase(connection_handle); + } + } break; } } @@ -135,6 +197,272 @@ struct DistanceMeasurementManager::impl { std::chrono::milliseconds(rssi_trackers[address].frequency)); } + void handle_event(LeMetaEventView event) { + if (!event.IsValid()) { + LOG_ERROR("Received invalid LeMetaEventView"); + return; + } + switch (event.GetSubeventCode()) { + case hci::SubeventCode::LE_CS_TEST_END_COMPLETE: + case hci::SubeventCode::LE_CS_SUBEVENT_RESULT_CONTINUE: + case hci::SubeventCode::LE_CS_SUBEVENT_RESULT: + case hci::SubeventCode::LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE: { + LOG_WARN("Unhandled subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str()); + } break; + case hci::SubeventCode::LE_CS_PROCEDURE_ENABLE_COMPLETE: { + on_cs_procedure_enable_complete(LeCsProcedureEnableCompleteView::Create(event)); + } break; + case hci::SubeventCode::LE_CS_CONFIG_COMPLETE: { + on_cs_config_complete(LeCsConfigCompleteView::Create(event)); + } break; + case hci::SubeventCode::LE_CS_SECURITY_ENABLE_COMPLETE: { + on_cs_security_enable_complete(LeCsSecurityEnableCompleteView::Create(event)); + } break; + case hci::SubeventCode::LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE: { + on_cs_read_remote_supported_capabilities_complete( + LeCsReadRemoteSupportedCapabilitiesCompleteView::Create(event)); + } break; + default: + LOG_INFO("Unknown subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str()); + } + } + + void send_le_cs_read_local_supported_capabilities() { + hci_layer_->EnqueueCommand( + LeCsReadLocalSupportedCapabilitiesBuilder::Create(), + handler_->BindOnceOn(this, &impl::on_cs_read_local_supported_capabilities)); + } + + void send_le_cs_read_remote_supported_capabilities(uint16_t connection_handle) { + hci_layer_->EnqueueCommand( + LeCsReadRemoteSupportedCapabilitiesBuilder::Create(connection_handle), + handler_->BindOnce(check_status)); + } + + void send_le_cs_security_enable(uint16_t connection_handle) { + hci_layer_->EnqueueCommand( + LeCsSecurityEnableBuilder::Create(connection_handle), + handler_->BindOnce(check_status)); + } + + void send_le_cs_set_default_settings(uint16_t connection_handle) { + uint8_t role_enable = (1 << (uint8_t)CsRole::INITIATOR) | 1 << ((uint8_t)CsRole::REFLECTOR); + hci_layer_->EnqueueCommand( + LeCsSetDefaultSettingsBuilder::Create( + connection_handle, + role_enable, + kCsSyncAntennaSelection, + kCsMaxTxPower // max_tx_power + ), + handler_->BindOnceOn(this, &impl::on_cs_set_default_settings_complete)); + } + + void send_le_cs_create_config(uint16_t connection_handle) { + auto channel_vector = common::FromHexString("1FFFFFFFFFFFFC7FFFFC"); // use all 72 Channel + std::array channel_map; + std::copy(channel_vector->begin(), channel_vector->end(), channel_map.begin()); + std::reverse(channel_map.begin(), channel_map.end()); + hci_layer_->EnqueueCommand( + LeCsCreateConfigBuilder::Create( + connection_handle, + kConfigId, + CsCreateContext::BOTH_LOCAL_AND_REMOTE_CONTROLLER, + CsMainModeType::MODE_2, + CsSubModeType::UNUSED, + kMinMainModeSteps, + kMaxMainModeSteps, + kMainModeRepetition, + kMode0Steps, + CsRole::INITIATOR, + CsConfigRttType::RTT_WITH_128_BIT_RANDOM_SEQUENCE, + CsSyncPhy::LE_1M_PHY, + channel_map, + kChannelMapRepetition, + CsChannelSelectionType::TYPE_3B, + CsCh3cShape::HAT_SHAPE, + kCh3cJump, + Enable::DISABLED), + handler_->BindOnce(check_status)); + } + + void send_le_cs_set_procedure_parameters(uint16_t connection_handle) { + CsPreferredPeerAntenna preferred_peer_antenna; + hci_layer_->EnqueueCommand( + LeCsSetProcedureParametersBuilder::Create( + connection_handle, + kConfigId, + kMaxProcedureLen, + kMinProcedureInterval, + kMaxProcedureInterval, + kMaxProcedureCount, + kMinSubeventLen, + kMaxSubeventLen, + kToneAntennaConfigSelection, + CsPhy::LE_1M_PHY, + kTxPwrDelta, + preferred_peer_antenna), + handler_->BindOnceOn(this, &impl::on_cs_set_procedure_parameters)); + } + + void send_le_cs_procedure_enable(uint16_t connection_handle, Enable enable) { + hci_layer_->EnqueueCommand( + LeCsProcedureEnableBuilder::Create(connection_handle, kConfigId, enable), + handler_->BindOnce(check_status)); + } + + void on_cs_read_local_supported_capabilities(CommandCompleteView view) { + auto complete_view = LeCsReadLocalSupportedCapabilitiesCompleteView::Create(view); + if (!complete_view.IsValid()) { + LOG_WARN("Get invalid LeCsReadLocalSupportedCapabilitiesComplete"); + is_channel_sounding_supported_ = false; + return; + } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) { + std::string error_code = ErrorCodeText(complete_view.GetStatus()); + LOG_WARN( + "Received LeCsReadLocalSupportedCapabilitiesComplete with error code %s", + error_code.c_str()); + is_channel_sounding_supported_ = false; + return; + } + is_channel_sounding_supported_ = true; + cs_subfeature_supported_ = complete_view.GetOptionalSubfeaturesSupported(); + } + + void on_cs_read_remote_supported_capabilities_complete( + LeCsReadRemoteSupportedCapabilitiesCompleteView event_view) { + if (!event_view.IsValid()) { + LOG_WARN("Get invalid LeCsReadRemoteSupportedCapabilitiesCompleteView"); + return; + } else if (event_view.GetStatus() != ErrorCode::SUCCESS) { + std::string error_code = ErrorCodeText(event_view.GetStatus()); + LOG_WARN( + "Received LeCsReadRemoteSupportedCapabilitiesCompleteView with error code %s", + error_code.c_str()); + return; + } + uint16_t connection_handle = event_view.GetConnectionHandle(); + if (cs_trackers_.find(connection_handle) == cs_trackers_.end()) { + // Create a cs tracker with role reflector + // TODO: Check ROLE via CS config. (b/304295768) + cs_trackers_[connection_handle].role = CsRole::REFLECTOR; + send_le_cs_set_default_settings(event_view.GetConnectionHandle()); + } + + if (event_view.GetOptionalSubfeaturesSupported().phase_based_ranging_ == 0x01) { + cs_trackers_[connection_handle].remote_support_phase_based_ranging = true; + } + LOG_INFO( + "connection_handle:%d, num_antennas_supported:%d, max_antenna_paths_supported:%d, " + "roles_supported:%s, phase_based_ranging_supported: %d ", + event_view.GetConnectionHandle(), + event_view.GetNumAntennasSupported(), + event_view.GetMaxAntennaPathsSupported(), + event_view.GetRolesSupported().ToString().c_str(), + event_view.GetOptionalSubfeaturesSupported().phase_based_ranging_); + } + + void on_cs_set_default_settings_complete(CommandCompleteView view) { + auto complete_view = LeCsSetDefaultSettingsCompleteView::Create(view); + if (!complete_view.IsValid()) { + LOG_WARN("Get invalid LeCsSetDefaultSettingsComplete"); + return; + } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) { + std::string error_code = ErrorCodeText(complete_view.GetStatus()); + LOG_WARN("Received LeCsSetDefaultSettingsComplete with error code %s", error_code.c_str()); + return; + } + } + + void on_cs_security_enable_complete(LeCsSecurityEnableCompleteView event_view) { + if (!event_view.IsValid()) { + LOG_WARN("Get invalid LeCsSecurityEnableCompleteView"); + return; + } else if (event_view.GetStatus() != ErrorCode::SUCCESS) { + std::string error_code = ErrorCodeText(event_view.GetStatus()); + LOG_WARN("Received LeCsSecurityEnableCompleteView with error code %s", error_code.c_str()); + return; + } + uint16_t connection_handle = event_view.GetConnectionHandle(); + if (cs_trackers_.find(connection_handle) == cs_trackers_.end()) { + LOG_WARN("Can't find cs tracker for connection_handle %d", connection_handle); + return; + } + cs_trackers_[connection_handle].setup_complete = true; + LOG_INFO( + "Setup phase complete, connection_handle: %d, address: %s", + connection_handle, + ADDRESS_TO_LOGGABLE_CSTR(cs_trackers_[connection_handle].address)); + if (cs_trackers_[connection_handle].role == CsRole::INITIATOR) { + send_le_cs_create_config(connection_handle); + } + } + + void on_cs_config_complete(LeCsConfigCompleteView event_view) { + if (!event_view.IsValid()) { + LOG_WARN("Get invalid LeCsConfigCompleteView"); + return; + } else if (event_view.GetStatus() != ErrorCode::SUCCESS) { + std::string error_code = ErrorCodeText(event_view.GetStatus()); + LOG_WARN("Received LeCsConfigCompleteView with error code %s", error_code.c_str()); + return; + } + uint16_t connection_handle = event_view.GetConnectionHandle(); + if (cs_trackers_.find(connection_handle) == cs_trackers_.end()) { + LOG_WARN("Can't find cs tracker for connection_handle %d", connection_handle); + return; + } + if (event_view.GetAction() == CsAction::CONFIG_REMOVED) { + return; + } + LOG_INFO("Get %s", event_view.ToString().c_str()); + cs_trackers_[connection_handle].role = event_view.GetRole(); + cs_trackers_[connection_handle].config_set = true; + cs_trackers_[connection_handle].main_mode_type = event_view.GetMainModeType(); + cs_trackers_[connection_handle].sub_mode_type = event_view.GetSubModeType(); + cs_trackers_[connection_handle].rtt_type = event_view.GetRttType(); + + if (cs_trackers_[connection_handle].role == CsRole::INITIATOR) { + send_le_cs_set_procedure_parameters(event_view.GetConnectionHandle()); + } + } + + void on_cs_set_procedure_parameters(CommandCompleteView view) { + auto complete_view = LeCsSetProcedureParametersCompleteView::Create(view); + if (!complete_view.IsValid()) { + LOG_WARN("Get Invalid LeCsSetProcedureParametersCompleteView"); + return; + } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) { + std::string error_code = ErrorCodeText(complete_view.GetStatus()); + LOG_WARN( + "Received LeCsSetProcedureParametersCompleteView with error code %s", error_code.c_str()); + return; + } + uint16_t connection_handle = complete_view.GetConnectionHandle(); + if (cs_trackers_.find(connection_handle) == cs_trackers_.end()) { + LOG_WARN("Can't find cs tracker for connection_handle %d", connection_handle); + return; + } + + if (cs_trackers_[connection_handle].role == CsRole::INITIATOR) { + send_le_cs_procedure_enable(complete_view.GetConnectionHandle(), Enable::ENABLED); + } + } + + void on_cs_procedure_enable_complete(LeCsProcedureEnableCompleteView event_view) { + if (!event_view.IsValid()) { + LOG_WARN("Get invalid LeCsProcedureEnableCompleteView"); + return; + } else if (event_view.GetStatus() != ErrorCode::SUCCESS) { + std::string error_code = ErrorCodeText(event_view.GetStatus()); + LOG_WARN("Received LeCsProcedureEnableCompleteView with error code %s", error_code.c_str()); + return; + } + + if (event_view.GetState() == Enable::ENABLED) { + LOG_INFO("Procedure enabled, %s", event_view.ToString().c_str()); + } + } + void on_read_remote_transmit_power_level_status(Address address, CommandStatusView view) { auto status_view = LeReadRemoteTransmitPowerLevelStatusView::Create(view); if (!status_view.IsValid()) { @@ -258,19 +586,6 @@ struct DistanceMeasurementManager::impl { DistanceMeasurementMethod::METHOD_RSSI); } - template - void check_status(CommandCompleteView view) { - auto status_view = View::Create(view); - if (!status_view.IsValid()) { - LOG_WARN("Get invalid command complete event"); - } else if (status_view.GetStatus() != ErrorCode::SUCCESS) { - LOG_INFO( - "Got a Command complete %s, status %s", - OpCodeText(view.GetCommandOpCode()).c_str(), - ErrorCodeText(status_view.GetStatus()).c_str()); - } - } - struct RSSITracker { uint16_t handle; uint16_t frequency; @@ -279,11 +594,28 @@ struct DistanceMeasurementManager::impl { std::unique_ptr alarm; }; + struct CsTracker { + Address address; + uint16_t local_counter; + uint16_t remote_counter; + CsRole role; + bool setup_complete = false; + bool config_set = false; + CsMainModeType main_mode_type; + CsSubModeType sub_mode_type; + CsRttType rtt_type; + bool remote_support_phase_based_ranging = false; + }; + os::Handler* handler_; hci::HciLayer* hci_layer_; hci::AclManager* acl_manager_; + bool is_channel_sounding_supported_ = false; + hci::DistanceMeasurementInterface* distance_measurement_interface_; std::unordered_map rssi_trackers; + std::unordered_map cs_trackers_; DistanceMeasurementCallbacks* distance_measurement_callbacks_; + CsOptionalSubfeaturesSupported cs_subfeature_supported_; }; DistanceMeasurementManager::DistanceMeasurementManager() { diff --git a/system/gd/hci/distance_measurement_manager.h b/system/gd/hci/distance_measurement_manager.h index a009bf3198381bb3efe8ae0d36fa1924324615e3..2dd2a1b4cb9e331f7428978b23cbaec3a4c41690 100644 --- a/system/gd/hci/distance_measurement_manager.h +++ b/system/gd/hci/distance_measurement_manager.h @@ -24,6 +24,7 @@ namespace hci { enum DistanceMeasurementMethod { METHOD_AUTO, METHOD_RSSI, + METHOD_CS, }; enum DistanceMeasurementErrorCode { diff --git a/system/gd/hci/acl_manager/event_checkers.h b/system/gd/hci/event_checkers.h similarity index 70% rename from system/gd/hci/acl_manager/event_checkers.h rename to system/gd/hci/event_checkers.h index 1765661e2ce9ee5cc370a6e7a82085d6fead51f6..cda96903e9413c7b564f99cec85c5fc08ff3916c 100644 --- a/system/gd/hci/acl_manager/event_checkers.h +++ b/system/gd/hci/event_checkers.h @@ -16,44 +16,45 @@ #pragma once +#include "hci/hci_packets.h" +#include "os/log.h" + namespace bluetooth { namespace hci { -namespace acl_manager { template -void check_command_complete(CommandCompleteView view) { +void check_complete(CommandCompleteView view) { ASSERT(view.IsValid()); auto status_view = T::Create(view); if (!status_view.IsValid()) { - LOG_ERROR("Received command complete with invalid packet, opcode 0x%02hx", view.GetCommandOpCode()); + LOG_ERROR("Invalid packet, opcode 0x%02hx", view.GetCommandOpCode()); return; } ErrorCode status = status_view.GetStatus(); OpCode op_code = status_view.GetCommandOpCode(); if (status != ErrorCode::SUCCESS) { std::string error_code = ErrorCodeText(status); - LOG_ERROR("Received command complete with error code %s, opcode 0x%02hx", error_code.c_str(), op_code); + LOG_ERROR("Error code %s, opcode 0x%02hx", error_code.c_str(), op_code); return; } } template -void check_command_status(CommandStatusView view) { +void check_status(CommandStatusView view) { ASSERT(view.IsValid()); auto status_view = T::Create(view); if (!status_view.IsValid()) { - LOG_ERROR("Received command status with invalid packet, opcode 0x%02hx", view.GetCommandOpCode()); + LOG_ERROR("Invalid packet, opcode 0x%02hx", view.GetCommandOpCode()); return; } ErrorCode status = status_view.GetStatus(); OpCode op_code = status_view.GetCommandOpCode(); if (status != ErrorCode::SUCCESS) { std::string error_code = ErrorCodeText(status); - LOG_ERROR("Received command status with error code %s, opcode 0x%02hx", error_code.c_str(), op_code); + LOG_ERROR("Error code %s, opcode 0x%02hx", error_code.c_str(), op_code); return; } } -} // namespace acl_manager } // namespace hci } // namespace bluetooth diff --git a/system/gd/hci/facade/acl_manager_facade.cc b/system/gd/hci/facade/acl_manager_facade.cc index fba88c3d7c64730ca32b604c4c3cc22c8cc9e77f..94269fe4e2fc45ac16cd82c0c09dfd4086d3f77e 100644 --- a/system/gd/hci/facade/acl_manager_facade.cc +++ b/system/gd/hci/facade/acl_manager_facade.cc @@ -77,7 +77,9 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect } ::grpc::Status Disconnect( - ::grpc::ServerContext* context, const HandleMsg* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const HandleMsg* request, + ::google::protobuf::Empty* /* response */) override { LOG_INFO("handle=%d", request->handle()); std::unique_lock lock(acl_connections_mutex_); auto connection = acl_connections_.find(request->handle()); @@ -91,7 +93,9 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect } ::grpc::Status AuthenticationRequested( - ::grpc::ServerContext* context, const HandleMsg* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const HandleMsg* request, + ::google::protobuf::Empty* /* response */) override { LOG_INFO("handle=%d", request->handle()); std::unique_lock lock(acl_connections_mutex_); auto connection = acl_connections_.find(request->handle()); @@ -118,9 +122,9 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect } while (0) ::grpc::Status ConnectionCommand( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ConnectionCommandMsg* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { LOG_INFO("size=%zu", request->packet().size()); auto command_view = ConnectionManagementCommandView::Create(AclCommandView::Create(CommandView::Create(PacketView( @@ -269,7 +273,7 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect ::grpc::Status FetchIncomingConnection( ::grpc::ServerContext* context, - const google::protobuf::Empty* request, + const google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { LOG_INFO("wait for one incoming connection"); if (per_connection_events_.size() > current_connection_request_) { @@ -281,7 +285,9 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect } ::grpc::Status SendAclData( - ::grpc::ServerContext* context, const AclData* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const AclData* request, + ::google::protobuf::Empty* /* response */) override { LOG_INFO("handle=%d, size=%zu", request->handle(), request->payload().size()); std::promise promise; auto future = promise.get_future(); @@ -376,11 +382,11 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect current_connection_request_++; } - void OnConnectRequest(Address address, ClassOfDevice cod) override { + void OnConnectRequest(Address /* address */, ClassOfDevice /* cod */) override { LOG_ERROR("Remote connect request unimplemented"); } - void OnConnectFail(Address address, ErrorCode reason, bool locally_initiated) override { + void OnConnectFail(Address address, ErrorCode reason, bool /* locally_initiated */) override { LOG_INFO("addr=%s, reason=%s", ADDRESS_TO_LOGGABLE_CSTR(address), ErrorCodeText(reason).c_str()); std::unique_ptr builder = @@ -391,11 +397,11 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect current_connection_request_++; } - void HACK_OnEscoConnectRequest(Address address, ClassOfDevice cod) override { + void HACK_OnEscoConnectRequest(Address /* address */, ClassOfDevice /* cod */) override { LOG_ERROR("Remote ESCO connect request unimplemented"); } - void HACK_OnScoConnectRequest(Address address, ClassOfDevice cod) override { + void HACK_OnScoConnectRequest(Address /* address */, ClassOfDevice /* cod */) override { LOG_ERROR("Remote SCO connect request unimplemented"); } @@ -415,7 +421,7 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect LOG_INFO("key_flag:%s", KeyFlagText(key_flag).c_str()); } - void OnRoleChange(hci::ErrorCode hci_status, Role new_role) override { + void OnRoleChange(hci::ErrorCode /* hci_status */, Role new_role) override { LOG_INFO("new_role:%d", (uint8_t)new_role); } @@ -427,7 +433,7 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect LOG_INFO("OnConnectionPacketTypeChanged packet_type:%d", packet_type); } - void OnAuthenticationComplete(hci::ErrorCode hci_status) override { + void OnAuthenticationComplete(hci::ErrorCode /* hci_status */) override { LOG_INFO("OnAuthenticationComplete"); } @@ -443,12 +449,12 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect LOG_INFO("OnReadClockOffsetComplete clock_offset:%d", clock_offset); }; - void OnModeChange(ErrorCode status, Mode current_mode, uint16_t interval) override { + void OnModeChange(ErrorCode /* status */, Mode current_mode, uint16_t interval) override { LOG_INFO("OnModeChange Mode:%d, interval:%d", (uint8_t)current_mode, interval); }; void OnSniffSubrating( - hci::ErrorCode hci_status, + hci::ErrorCode /* hci_status */, uint16_t maximum_transmit_latency, uint16_t maximum_receive_latency, uint16_t minimum_remote_timeout, @@ -523,7 +529,8 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect LOG_INFO("OnReadLinkQualityComplete link_quality:%d", link_quality); } - void OnReadAfhChannelMapComplete(AfhMode afh_mode, std::array afh_channel_map) override { + void OnReadAfhChannelMapComplete( + AfhMode afh_mode, std::array /* afh_channel_map */) override { LOG_INFO("OnReadAfhChannelMapComplete afh_mode:%d", (uint8_t)afh_mode); } @@ -544,7 +551,10 @@ class AclManagerFacadeService : public AclManagerFacade::Service, public Connect event_stream_->OnIncomingEvent(disconnection); } void OnReadRemoteVersionInformationComplete( - hci::ErrorCode error_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override { + hci::ErrorCode /* error_status */, + uint8_t lmp_version, + uint16_t manufacturer_name, + uint16_t sub_version) override { LOG_INFO( "OnReadRemoteVersionInformationComplete lmp_version:%hhu manufacturer_name:%hu sub_version:%hu", lmp_version, diff --git a/system/gd/hci/facade/controller_facade.cc b/system/gd/hci/facade/controller_facade.cc index ee59060179fd2ff82734208321a4f300bc0c32a2..ee075e6aaf85f4944c03d4dcdf52b6d75b197ec8 100644 --- a/system/gd/hci/facade/controller_facade.cc +++ b/system/gd/hci/facade/controller_facade.cc @@ -44,37 +44,47 @@ class ControllerFacadeService : public ControllerFacade::Service { ControllerFacadeService(Controller* controller, ::bluetooth::os::Handler*) : controller_(controller) {} ::grpc::Status GetMacAddress( - ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, BluetoothAddress* response) override { + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, + BluetoothAddress* response) override { Address local_address = controller_->GetMacAddress(); response->set_address(local_address.ToString()); return ::grpc::Status::OK; } - ::grpc::Status GetLocalName(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - NameMsg* response) override { + ::grpc::Status GetLocalName( + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, + NameMsg* response) override { std::string local_name = controller_->GetLocalName(); response->set_name(local_name); return ::grpc::Status::OK; } - ::grpc::Status WriteLocalName(::grpc::ServerContext* context, const NameMsg* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status WriteLocalName( + ::grpc::ServerContext* /* context */, + const NameMsg* request, + ::google::protobuf::Empty* /* response */) override { controller_->WriteLocalName(request->name()); return ::grpc::Status::OK; } ::grpc::Status IsSupportedCommand( - ::grpc::ServerContext* context, const OpCodeMsg* request, SupportedMsg* response) override { + ::grpc::ServerContext* /* context */, + const OpCodeMsg* request, + SupportedMsg* response) override { bool ret = controller_->IsSupported(static_cast(request->op_code())); response->set_supported(ret); return ::grpc::Status::OK; } -#define SUPPORTED_API(name) \ - ::grpc::Status name( \ - ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, SupportedMsg* response) override { \ - response->set_supported(controller_->name()); \ - return ::grpc::Status::OK; \ +#define SUPPORTED_API(name) \ + ::grpc::Status name( \ + ::grpc::ServerContext* /* context */, \ + const ::google::protobuf::Empty* /* request */, \ + SupportedMsg* response) override { \ + response->set_supported(controller_->name()); \ + return ::grpc::Status::OK; \ } SUPPORTED_API(SupportsSimplePairing) @@ -145,7 +155,9 @@ class ControllerFacadeService : public ControllerFacade::Service { SUPPORTED_API(SupportsBlePeriodicAdvertisingAdi) ::grpc::Status GetLeNumberOfSupportedAdvertisingSets( - ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, SingleValueMsg* response) override { + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, + SingleValueMsg* response) override { uint8_t ret = controller_->GetLeNumberOfSupportedAdverisingSets(); response->set_value(ret); return ::grpc::Status::OK; diff --git a/system/gd/hci/facade/facade.cc b/system/gd/hci/facade/facade.cc index 75ade3dcde3f8750b9fa7576ccb93df801ef1bff..5da9a71e31c7374895645d6de840611a9be65531 100644 --- a/system/gd/hci/facade/facade.cc +++ b/system/gd/hci/facade/facade.cc @@ -69,9 +69,9 @@ class HciFacadeService : public HciFacade::Service { }; ::grpc::Status SendCommand( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::Data* command, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { auto payload = std::vector(command->payload().begin(), command->payload().end()); auto packet = std::make_unique(payload); auto opcode = static_cast(payload.at(1) << 8 | payload.at(0)); @@ -84,18 +84,18 @@ class HciFacadeService : public HciFacade::Service { } ::grpc::Status RequestEvent( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::hci::EventRequest* event, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci_layer_->RegisterEventHandler( static_cast(event->code()), facade_handler_->BindOn(this, &HciFacadeService::on_event)); return ::grpc::Status::OK; } ::grpc::Status RequestLeSubevent( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::hci::EventRequest* event, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci_layer_->RegisterLeEventHandler( static_cast(event->code()), facade_handler_->BindOn(this, &HciFacadeService::on_le_subevent)); return ::grpc::Status::OK; @@ -103,14 +103,14 @@ class HciFacadeService : public HciFacade::Service { ::grpc::Status StreamEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override { return pending_events_.RunLoop(context, writer); }; ::grpc::Status StreamLeSubevents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override { return pending_le_events_.RunLoop(context, writer); }; @@ -135,9 +135,9 @@ class HciFacadeService : public HciFacade::Service { }; ::grpc::Status SendAcl( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::Data* acl, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { waiting_acl_packet_ = std::make_unique(std::vector(acl->payload().begin(), acl->payload().end())); std::promise enqueued; @@ -157,7 +157,7 @@ class HciFacadeService : public HciFacade::Service { ::grpc::Status StreamAcl( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override { hci_layer_->GetAclQueueEnd()->RegisterDequeue( facade_handler_, common::Bind(&HciFacadeService::on_acl_ready, common::Unretained(this))); diff --git a/system/gd/hci/facade/le_acl_manager_facade.cc b/system/gd/hci/facade/le_acl_manager_facade.cc index 6bcd0f9b605abb55546f1842e6859359848b74a2..a87768498f023fb2bc4710ed268bf1e25287e0b0 100644 --- a/system/gd/hci/facade/le_acl_manager_facade.cc +++ b/system/gd/hci/facade/le_acl_manager_facade.cc @@ -16,7 +16,6 @@ #include "hci/facade/le_acl_manager_facade.h" -#include #include #include @@ -26,6 +25,7 @@ #include "grpc/grpc_event_queue.h" #include "hci/acl_manager.h" #include "hci/hci_packets.h" +#include "hci/octets.h" #include "packet/raw_builder.h" using ::grpc::ServerAsyncResponseWriter; @@ -94,9 +94,9 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC } ::grpc::Status CancelConnection( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::BluetoothAddressWithType* request, - google::protobuf::Empty* response) override { + google::protobuf::Empty* /* response */) override { LOG_INFO("peer=%s, type=%d", request->address().address().c_str(), request->type()); Address peer_address; ASSERT(Address::FromString(request->address().address(), peer_address)); @@ -113,8 +113,10 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC return ::grpc::Status::OK; } - ::grpc::Status Disconnect(::grpc::ServerContext* context, const LeHandleMsg* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status Disconnect( + ::grpc::ServerContext* /* context */, + const LeHandleMsg* request, + ::google::protobuf::Empty* /* response */) override { LOG_INFO("handle=%d", request->handle()); std::unique_lock lock(acl_connections_mutex_); auto connection = acl_connections_.find(request->handle()); @@ -141,9 +143,9 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC } while (0) ::grpc::Status ConnectionCommand( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const LeConnectionCommandMsg* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { LOG_INFO("size=%zu", request->packet().size()); auto command_view = ConnectionManagementCommandView::Create(AclCommandView::Create(CommandView::Create(PacketView( @@ -167,7 +169,7 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC ::grpc::Status FetchIncomingConnection( ::grpc::ServerContext* context, - const google::protobuf::Empty* request, + const google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { LOG_INFO("wait for one incoming connection"); if (incoming_connection_events_ != nullptr) { @@ -180,7 +182,9 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC } ::grpc::Status AddDeviceToResolvingList( - ::grpc::ServerContext* context, const IrkMsg* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const IrkMsg* request, + ::google::protobuf::Empty* /* response */) override { LOG_INFO("peer=%s, type=%d", request->peer().address().address().c_str(), request->peer().type()); Address peer_address; ASSERT(Address::FromString(request->peer().address().address(), peer_address)); @@ -188,30 +192,32 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC auto request_peer_irk_length = request->peer_irk().end() - request->peer_irk().begin(); - if (request_peer_irk_length != crypto_toolbox::OCTET16_LEN) { + if (request_peer_irk_length != kOctet16Length) { return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid Peer IRK"); } auto request_local_irk_length = request->local_irk().end() - request->local_irk().begin(); - if (request_local_irk_length != crypto_toolbox::OCTET16_LEN) { + if (request_local_irk_length != kOctet16Length) { return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid Local IRK"); } - crypto_toolbox::Octet16 peer_irk = {}; - crypto_toolbox::Octet16 local_irk = {}; + Octet16 peer_irk = {}; + Octet16 local_irk = {}; std::vector peer_irk_data(request->peer_irk().begin(), request->peer_irk().end()); - std::copy_n(peer_irk_data.begin(), crypto_toolbox::OCTET16_LEN, peer_irk.begin()); + std::copy_n(peer_irk_data.begin(), kOctet16Length, peer_irk.begin()); std::vector local_irk_data(request->local_irk().begin(), request->local_irk().end()); - std::copy_n(local_irk_data.begin(), crypto_toolbox::OCTET16_LEN, local_irk.begin()); + std::copy_n(local_irk_data.begin(), kOctet16Length, local_irk.begin()); acl_manager_->AddDeviceToResolvingList(peer, peer_irk, local_irk); return ::grpc::Status::OK; } ::grpc::Status SendAclData( - ::grpc::ServerContext* context, const LeAclData* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const LeAclData* request, + ::google::protobuf::Empty* /* response */) override { LOG_INFO("handle=%d, size=%zu", request->handle(), request->payload().size()); std::promise promise; auto future = promise.get_future(); @@ -341,7 +347,7 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC std::shared_ptr<::bluetooth::grpc::GrpcEventQueue> event_stream) : handle_(handle), connection_(std::move(connection)), event_stream_(std::move(event_stream)) {} void OnConnectionUpdate( - hci::ErrorCode hci_status, + hci::ErrorCode /* hci_status */, uint16_t connection_interval, uint16_t connection_latency, uint16_t supervision_timeout) override { @@ -357,7 +363,8 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC "tx_octets: 0x%hx, tx_time: 0x%hx, rx_octets 0x%hx, rx_time 0x%hx", tx_octets, tx_time, rx_octets, rx_time); } - void OnPhyUpdate(hci::ErrorCode hci_status, uint8_t tx_phy, uint8_t rx_phy) override {} + void OnPhyUpdate( + hci::ErrorCode /* hci_status */, uint8_t /* tx_phy */, uint8_t /* rx_phy */) override {} void OnDisconnection(ErrorCode reason) override { LOG_INFO("reason: %s", ErrorCodeText(reason).c_str()); std::unique_ptr builder = @@ -368,8 +375,12 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC } void OnReadRemoteVersionInformationComplete( - hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override {} - void OnLeReadRemoteFeaturesComplete(hci::ErrorCode hci_status, uint64_t features) override {} + hci::ErrorCode /* hci_status */, + uint8_t /* lmp_version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) override {} + void OnLeReadRemoteFeaturesComplete( + hci::ErrorCode /* hci_status */, uint64_t /* features */) override {} LeConnectionManagementCallbacks* GetCallbacks() { return this; @@ -398,7 +409,7 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC }; ::grpc::Status IsOnBackgroundList( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::hci::BackgroundRequestMsg* request, ::blueberry::facade::hci::BackgroundResultMsg* msg) { Address peer_address; @@ -412,9 +423,9 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC } ::grpc::Status RemoveFromBackgroundList( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::blueberry::facade::hci::BackgroundRequestMsg* request, - ::google::protobuf::Empty* response) { + ::google::protobuf::Empty* /* response */) { Address peer_address; ASSERT(Address::FromString(request->peer_address().address().address(), peer_address)); AddressWithType peer(peer_address, static_cast(request->peer_address().type())); diff --git a/system/gd/hci/facade/le_advertising_manager_facade.cc b/system/gd/hci/facade/le_advertising_manager_facade.cc index 93e40ae6c8a621a8fea2245b735772d658d9fb4f..db2dfda467addf5fe0c3b612b8482740a203f796 100644 --- a/system/gd/hci/facade/le_advertising_manager_facade.cc +++ b/system/gd/hci/facade/le_advertising_manager_facade.cc @@ -25,6 +25,7 @@ #include "common/bidi_queue.h" #include "common/bind.h" #include "grpc/grpc_event_queue.h" +#include "hardware/ble_advertiser.h" #include "hci/address.h" #include "hci/address_with_type.h" #include "hci/le_advertising_manager.h" @@ -176,9 +177,9 @@ class LeAdvertiser { public: LeAdvertiser(hci::AdvertisingConfig config) : config_(std::move(config)) {} - void ScanCallback(Address address, AddressType address_type) {} + void ScanCallback(Address /* address */, AddressType /* address_type */) {} - void TerminatedCallback(ErrorCode error_code, uint8_t, uint8_t) {} + void TerminatedCallback(ErrorCode /* error_code */, uint8_t, uint8_t) {} hci::AdvertiserId GetAdvertiserId() { return id_; @@ -221,8 +222,10 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser le_advertising_manager_->RegisterAdvertisingCallback(this); } - ::grpc::Status CreateAdvertiser(::grpc::ServerContext* context, const CreateAdvertiserRequest* request, - CreateAdvertiserResponse* response) override { + ::grpc::Status CreateAdvertiser( + ::grpc::ServerContext* /* context */, + const CreateAdvertiserRequest* request, + CreateAdvertiserResponse* response) override { hci::AdvertisingConfig config = {}; if (!AdvertisingConfigFromProto(request->config(), &config)) { LOG_WARN("Error parsing advertising config %s", request->SerializeAsString().c_str()); @@ -234,6 +237,7 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser pending_advertiser_id_ = std::promise(); auto future = pending_advertiser_id_->get_future(); le_advertising_manager_->ExtendedCreateAdvertiser( + kAdvertiserClientIdJni, 0, config, common::Bind(&LeAdvertiser::ScanCallback, common::Unretained(&le_advertiser)), @@ -253,9 +257,10 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser return ::grpc::Status::OK; } - ::grpc::Status ExtendedCreateAdvertiser(::grpc::ServerContext* context, - const ExtendedCreateAdvertiserRequest* request, - ExtendedCreateAdvertiserResponse* response) override { + ::grpc::Status ExtendedCreateAdvertiser( + ::grpc::ServerContext* /* context */, + const ExtendedCreateAdvertiserRequest* request, + ExtendedCreateAdvertiserResponse* response) override { hci::AdvertisingConfig config = {}; if (!ExtendedAdvertisingConfigFromProto(request->config(), &config)) { LOG_WARN("Error parsing advertising config %s", request->SerializeAsString().c_str()); @@ -266,6 +271,7 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser pending_advertiser_id_ = std::promise(); auto future = pending_advertiser_id_->get_future(); le_advertising_manager_->ExtendedCreateAdvertiser( + kAdvertiserClientIdJni, 0, config, common::Bind(&LeAdvertiser::ScanCallback, common::Unretained(&le_advertiser)), @@ -286,15 +292,17 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser } ::grpc::Status EnableAdvertiser( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const EnableAdvertiserRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { le_advertising_manager_->EnableAdvertiser(request->advertiser_id(), request->enable(), 0, 0); return ::grpc::Status::OK; } ::grpc::Status SetData( - ::grpc::ServerContext* context, const SetDataRequest* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const SetDataRequest* request, + ::google::protobuf::Empty* /* response */) override { std::vector advertising_data = {}; for (const auto& elem : request->data()) { advertising_data.push_back(GapDataFromProto(elem)); @@ -304,9 +312,9 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser } ::grpc::Status SetParameters( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const SetParametersRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::AdvertisingConfig config = {}; if (!AdvertisingConfigFromProto(request->config(), &config)) { LOG_WARN("Error parsing advertising config %s", request->SerializeAsString().c_str()); @@ -317,9 +325,9 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser } ::grpc::Status SetPeriodicParameters( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const SetPeriodicParametersRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::PeriodicAdvertisingParameters config = {}; if (!PeriodicAdvertisingParametersFromProto(request->config(), &config)) { LOG_WARN("Error parsing periodic advertising parameters %s", request->SerializeAsString().c_str()); @@ -331,9 +339,9 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser } ::grpc::Status SetPeriodicData( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const SetPeriodicDataRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { std::vector advertising_data = {}; for (const auto& elem : request->data()) { advertising_data.push_back(GapDataFromProto(elem)); @@ -343,31 +351,34 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser } ::grpc::Status EnablePeriodicAdvertising( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const EnablePeriodicAdvertisingRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { le_advertising_manager_->EnablePeriodicAdvertising( request->advertiser_id(), request->enable(), request->include_adi()); return ::grpc::Status::OK; } ::grpc::Status GetOwnAddress( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const GetOwnAddressRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { le_advertising_manager_->GetOwnAddress(request->advertiser_id()); return ::grpc::Status::OK; } - ::grpc::Status GetNumberOfAdvertisingInstances(::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, - GetNumberOfAdvertisingInstancesResponse* response) override { + ::grpc::Status GetNumberOfAdvertisingInstances( + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, + GetNumberOfAdvertisingInstancesResponse* response) override { response->set_num_advertising_instances(le_advertising_manager_->GetNumberOfAdvertisingInstances()); return ::grpc::Status::OK; } - ::grpc::Status RemoveAdvertiser(::grpc::ServerContext* context, const RemoveAdvertiserRequest* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status RemoveAdvertiser( + ::grpc::ServerContext* /* context */, + const RemoveAdvertiserRequest* request, + ::google::protobuf::Empty* /* response */) override { if (request->advertiser_id() == LeAdvertisingManager::kInvalidId) { LOG_WARN("Invalid advertiser ID %d", request->advertiser_id()); return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invlid advertiser ID received"); @@ -385,19 +396,20 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser ::grpc::Status FetchCallbackEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return callback_events_.RunLoop(context, writer); } ::grpc::Status FetchAddressEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return address_events_.RunLoop(context, writer); } - void OnAdvertisingSetStarted(int reg_id, uint8_t advertiser_id, int8_t tx_power, AdvertisingStatus status) { + void OnAdvertisingSetStarted( + int reg_id, uint8_t advertiser_id, int8_t /* tx_power */, AdvertisingStatus status) { if (pending_advertiser_id_.has_value()) { pending_advertiser_id_->set_value(advertiser_id); pending_advertiser_id_.reset(); @@ -435,7 +447,8 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser callback_events_.OnIncomingEvent(msg); }; - void OnAdvertisingParametersUpdated(uint8_t advertiser_id, int8_t tx_power, uint8_t status) { + void OnAdvertisingParametersUpdated( + uint8_t advertiser_id, int8_t /* tx_power */, uint8_t status) { AdvertisingCallbackMsg msg; msg.set_message_type(AdvertisingCallbackMsgType::ADVERTISING_PARAMETERS_UPDATED); msg.set_advertiser_id(advertiser_id); @@ -459,7 +472,7 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser callback_events_.OnIncomingEvent(msg); }; - void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool enable, uint8_t status) { + void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool /* enable */, uint8_t status) { AdvertisingCallbackMsg msg; msg.set_message_type(AdvertisingCallbackMsgType::PERIODIC_ADVERTISING_ENABLED); msg.set_advertiser_id(advertiser_id); diff --git a/system/gd/hci/facade/le_initiator_address_facade.cc b/system/gd/hci/facade/le_initiator_address_facade.cc index 725ee6290e377ac8f51477ccd3ff9fc42d51a8e3..32bc607f1dbf72436be9fb9b6d7a709b16eda570 100644 --- a/system/gd/hci/facade/le_initiator_address_facade.cc +++ b/system/gd/hci/facade/le_initiator_address_facade.cc @@ -16,16 +16,11 @@ #include "hci/facade/le_initiator_address_facade.h" -#include -#include -#include - #include "blueberry/facade/hci/le_initiator_address_facade.grpc.pb.h" #include "blueberry/facade/hci/le_initiator_address_facade.pb.h" -#include "common/bind.h" -#include "grpc/grpc_event_queue.h" #include "hci/acl_manager.h" #include "hci/hci_packets.h" +#include "hci/octets.h" #include "packet/raw_builder.h" using ::grpc::ServerAsyncResponseWriter; @@ -50,7 +45,9 @@ class LeInitiatorAddressFacadeService : public LeInitiatorAddressFacade::Service } ::grpc::Status SetPrivacyPolicyForInitiatorAddress( - ::grpc::ServerContext* context, const PrivacyPolicy* request, ::google::protobuf::Empty* writer) override { + ::grpc::ServerContext* /* context */, + const PrivacyPolicy* request, + ::google::protobuf::Empty* /* writer */) override { Address address = Address::kEmpty; LeAddressManager::AddressPolicy address_policy = static_cast(request->address_policy()); @@ -60,11 +57,11 @@ class LeInitiatorAddressFacadeService : public LeInitiatorAddressFacade::Service AddressWithType address_with_type(address, static_cast(request->address_with_type().type())); auto minimum_rotation_time = std::chrono::milliseconds(request->minimum_rotation_time()); auto maximum_rotation_time = std::chrono::milliseconds(request->maximum_rotation_time()); - crypto_toolbox::Octet16 irk = {}; + Octet16 irk = {}; auto request_irk_length = request->rotation_irk().end() - request->rotation_irk().begin(); - if (request_irk_length == crypto_toolbox::OCTET16_LEN) { + if (request_irk_length == kOctet16Length) { std::vector irk_data(request->rotation_irk().begin(), request->rotation_irk().end()); - std::copy_n(irk_data.begin(), crypto_toolbox::OCTET16_LEN, irk.begin()); + std::copy_n(irk_data.begin(), kOctet16Length, irk.begin()); acl_manager_->SetPrivacyPolicyForInitiatorAddressForTest( address_policy, address_with_type, irk, minimum_rotation_time, maximum_rotation_time); } else { @@ -76,8 +73,8 @@ class LeInitiatorAddressFacadeService : public LeInitiatorAddressFacade::Service } ::grpc::Status GetCurrentInitiatorAddress( - ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, ::blueberry::facade::BluetoothAddressWithType* response) override { AddressWithType current = address_manager_->GetInitiatorAddress(); auto bluetooth_address = new ::blueberry::facade::BluetoothAddress(); @@ -88,8 +85,8 @@ class LeInitiatorAddressFacadeService : public LeInitiatorAddressFacade::Service } ::grpc::Status NewResolvableAddress( - ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, ::blueberry::facade::BluetoothAddressWithType* response) override { AddressWithType another = address_manager_->NewResolvableAddress(); auto bluetooth_address = new ::blueberry::facade::BluetoothAddress(); diff --git a/system/gd/hci/facade/le_scanning_manager_facade.cc b/system/gd/hci/facade/le_scanning_manager_facade.cc index 60c0b315cce665184d4e817f26112309a50fcf0a..5109628b9906892e7825f3fa6207553e973c25d9 100644 --- a/system/gd/hci/facade/le_scanning_manager_facade.cc +++ b/system/gd/hci/facade/le_scanning_manager_facade.cc @@ -51,9 +51,9 @@ class LeScanningManagerFacadeService : public LeScanningManagerFacade::Service, } ::grpc::Status RegisterScanner( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const RegisterScannerRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { uint32_t uuid_raw = request->uuid(); bluetooth::hci::Uuid uuid = bluetooth::hci::Uuid::From32Bit(uuid_raw); le_scanning_manager_->RegisterScanner(uuid); @@ -61,21 +61,25 @@ class LeScanningManagerFacadeService : public LeScanningManagerFacade::Service, } ::grpc::Status Unregister( - ::grpc::ServerContext* context, const UnregisterRequest* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const UnregisterRequest* request, + ::google::protobuf::Empty* /* response */) override { le_scanning_manager_->Unregister(request->scanner_id()); return ::grpc::Status::OK; } ::grpc::Status Scan( - ::grpc::ServerContext* context, const ScanRequest* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const ScanRequest* request, + ::google::protobuf::Empty* /* response */) override { le_scanning_manager_->Scan(request->start()); return ::grpc::Status::OK; } ::grpc::Status SetScanParameters( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const SetScanParametersRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { auto scan_type = static_cast(request->scan_type()); le_scanning_manager_->SetScanParameters( request->scanner_id(), scan_type, request->scan_interval(), request->scan_window()); @@ -84,19 +88,20 @@ class LeScanningManagerFacadeService : public LeScanningManagerFacade::Service, ::grpc::Status FetchCallbackEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return callback_events_.RunLoop(context, writer); } ::grpc::Status FetchAdvertisingReports( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return advertising_reports_.RunLoop(context, writer); } - void OnScannerRegistered(const bluetooth::hci::Uuid app_uuid, ScannerId scanner_id, ScanningStatus status) { + void OnScannerRegistered( + const bluetooth::hci::Uuid app_uuid, ScannerId /* scanner_id */, ScanningStatus status) { ScanningCallbackMsg msg; msg.set_message_type(ScanningCallbackMsgType::SCANNER_REGISTERED); msg.set_status(static_cast(status)); @@ -113,15 +118,15 @@ class LeScanningManagerFacadeService : public LeScanningManagerFacade::Service, }; void OnScanResult( - uint16_t event_type, + uint16_t /* event_type */, uint8_t address_type, Address address, - uint8_t primary_phy, - uint8_t secondary_phy, - uint8_t advertising_sid, - int8_t tx_power, + uint8_t /* primary_phy */, + uint8_t /* secondary_phy */, + uint8_t /* advertising_sid */, + int8_t /* tx_power */, int8_t rssi, - uint16_t periodic_advertising_interval, + uint16_t /* periodic_advertising_interval */, std::vector advertising_data) { AdvertisingReportMsg advertising_report_msg; std::vector advertisements; @@ -139,40 +144,54 @@ class LeScanningManagerFacadeService : public LeScanningManagerFacade::Service, advertising_report_msg.set_event(std::string(bytes.begin(), bytes.end())); advertising_reports_.OnIncomingEvent(std::move(advertising_report_msg)); }; - void OnTrackAdvFoundLost(AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info){}; - void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector data){}; - void OnBatchScanThresholdCrossed(int client_if){}; + void OnTrackAdvFoundLost(AdvertisingFilterOnFoundOnLostInfo /* on_found_on_lost_info */){}; + void OnBatchScanReports( + int /* client_if */, + int /* status */, + int /* report_format */, + int /* num_records */, + std::vector /* data */){}; + void OnBatchScanThresholdCrossed(int /* client_if */){}; void OnTimeout(){}; - void OnFilterEnable(Enable enable, uint8_t status){}; - void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status){}; + void OnFilterEnable(Enable /* enable */, uint8_t /* status */){}; + void OnFilterParamSetup( + uint8_t /* available_spaces */, ApcfAction /* action */, uint8_t /* status */){}; void OnFilterConfigCallback( - ApcfFilterType filter_type, uint8_t available_spaces, ApcfAction action, uint8_t status){}; + ApcfFilterType /* filter_type */, + uint8_t /* available_spaces */, + ApcfAction /* action */, + uint8_t /* status */){}; void OnPeriodicSyncStarted( - int reg_id, - uint8_t status, - uint16_t sync_handle, - uint8_t advertising_sid, - AddressWithType address_with_type, - uint8_t phy, - uint16_t interval) override { + int /* reg_id */, + uint8_t /* status */, + uint16_t /* sync_handle */, + uint8_t /* advertising_sid */, + AddressWithType /* address_with_type */, + uint8_t /* phy */, + uint16_t /* interval */) override { LOG_INFO("OnPeriodicSyncStarted in LeScanningManagerFacadeService"); }; void OnPeriodicSyncReport( - uint16_t sync_handle, int8_t tx_power, int8_t rssi, uint8_t status, std::vector data) override { + uint16_t /* sync_handle */, + int8_t /* tx_power */, + int8_t /* rssi */, + uint8_t /* status */, + std::vector /* data */) override { LOG_INFO("OnPeriodicSyncReport in LeScanningManagerFacadeService"); }; - void OnPeriodicSyncLost(uint16_t sync_handle) override { + void OnPeriodicSyncLost(uint16_t /* sync_handle */) override { LOG_INFO("OnPeriodicSyncLost in LeScanningManagerFacadeService"); }; - void OnPeriodicSyncTransferred(int pa_source, uint8_t status, Address address) override { + void OnPeriodicSyncTransferred( + int /* pa_source */, uint8_t /* status */, Address /* address */) override { LOG_INFO("OnPeriodicSyncTransferred in LeScanningManagerFacadeService"); }; - void OnBigInfoReport(uint16_t sync_handle, bool encrypted) override { + void OnBigInfoReport(uint16_t /* sync_handle */, bool /* encrypted */) override { LOG_INFO("OnBigInfoReport in LeScanningManagerFacadeService"); }; diff --git a/system/gd/hci/fuzz/fuzz_hci_layer.cc b/system/gd/hci/fuzz/fuzz_hci_layer.cc index c54960d56a6e0a565b5194df26d44e0cf5df4440..902ba547bf8f1092910b0591ba9a12e81e5468f2 100644 --- a/system/gd/hci/fuzz/fuzz_hci_layer.cc +++ b/system/gd/hci/fuzz/fuzz_hci_layer.cc @@ -25,47 +25,62 @@ using bluetooth::common::ContextualCallback; using bluetooth::fuzz::GetArbitraryBytes; using bluetooth::fuzz::InvokeIfValid; -hci::SecurityInterface* FuzzHciLayer::GetSecurityInterface(ContextualCallback event_handler) { +hci::SecurityInterface* FuzzHciLayer::GetSecurityInterface( + ContextualCallback /* event_handler */) { return &security_interface_; } hci::LeSecurityInterface* FuzzHciLayer::GetLeSecurityInterface( - ContextualCallback event_handler) { + ContextualCallback /* event_handler */) { return &le_security_interface_; } hci::AclConnectionInterface* FuzzHciLayer::GetAclConnectionInterface( - ContextualCallback event_handler, - ContextualCallback on_disconnect, - ContextualCallback< - void(hci::ErrorCode, uint16_t, uint8_t version, uint16_t manufacturer_name, uint16_t sub_version)> - on_read_remote_version) { + ContextualCallback /* event_handler */, + ContextualCallback /* on_disconnect */, + ContextualCallback + /* on_read_remote_version */) { return &acl_connection_interface_; } hci::LeAclConnectionInterface* FuzzHciLayer::GetLeAclConnectionInterface( - ContextualCallback event_handler, - ContextualCallback on_disconnect, - ContextualCallback< - void(hci::ErrorCode, uint16_t, uint8_t version, uint16_t manufacturer_name, uint16_t sub_version)> - on_read_remote_version) { + ContextualCallback /* event_handler */, + ContextualCallback /* on_disconnect */, + ContextualCallback + /* on_read_remote_version */) { return &le_acl_connection_interface_; } hci::LeAdvertisingInterface* FuzzHciLayer::GetLeAdvertisingInterface( - ContextualCallback event_handler) { + ContextualCallback /* event_handler */) { return &le_advertising_interface_; } hci::LeScanningInterface* FuzzHciLayer::GetLeScanningInterface( - ContextualCallback event_handler) { + ContextualCallback /* event_handler */) { return &le_scanning_interface_; } -hci::LeIsoInterface* FuzzHciLayer::GetLeIsoInterface(ContextualCallback event_handler) { +hci::LeIsoInterface* FuzzHciLayer::GetLeIsoInterface( + ContextualCallback /* event_handler */) { return &le_iso_interface_; } +hci::DistanceMeasurementInterface* FuzzHciLayer::GetDistanceMeasurementInterface( + ContextualCallback /* event_handler */) { + return &distance_measurement_interface_; +} + void FuzzHciLayer::Start() { acl_dev_null_ = new os::fuzz::DevNullQueue(acl_queue_.GetDownEnd(), GetHandler()); acl_dev_null_->Start(); diff --git a/system/gd/hci/fuzz/fuzz_hci_layer.h b/system/gd/hci/fuzz/fuzz_hci_layer.h index e7de180d960ddcb8c0632734ef1c711b15d83500..c818f25a1ffb4283a7de4e0bd98b645884415ed8 100644 --- a/system/gd/hci/fuzz/fuzz_hci_layer.h +++ b/system/gd/hci/fuzz/fuzz_hci_layer.h @@ -32,11 +32,13 @@ namespace fuzz { template class FuzzCommandInterface : public CommandInterface { public: - void EnqueueCommand(std::unique_ptr command, - common::ContextualOnceCallback on_complete) override {} + void EnqueueCommand( + std::unique_ptr /* command */, + common::ContextualOnceCallback /* on_complete */) override {} - void EnqueueCommand(std::unique_ptr command, - common::ContextualOnceCallback on_status) override {} + void EnqueueCommand( + std::unique_ptr /* command */, + common::ContextualOnceCallback /* on_status */) override {} }; class FuzzHciLayer : public HciLayer { @@ -50,7 +52,7 @@ class FuzzHciLayer : public HciLayer { } void EnqueueCommand( - std::unique_ptr command, + std::unique_ptr /* command */, common::ContextualOnceCallback on_complete) override { on_command_complete_ = std::move(on_complete); if (auto_reply_fdp != nullptr) { @@ -59,7 +61,7 @@ class FuzzHciLayer : public HciLayer { } void EnqueueCommand( - std::unique_ptr command, + std::unique_ptr /* command */, common::ContextualOnceCallback on_status) override { on_command_status_ = std::move(on_status); if (auto_reply_fdp != nullptr) { @@ -129,6 +131,9 @@ class FuzzHciLayer : public HciLayer { hci::LeIsoInterface* GetLeIsoInterface(common::ContextualCallback event_handler) override; + hci::DistanceMeasurementInterface* GetDistanceMeasurementInterface( + common::ContextualCallback event_handler) override; + void injectArbitrary(FuzzedDataProvider& fdp); std::string ToString() const override { @@ -138,7 +143,7 @@ class FuzzHciLayer : public HciLayer { static const ModuleFactory Factory; protected: - void ListDependencies(ModuleList* list) const override {} + void ListDependencies(ModuleList* /* list */) const override {} void Start() override; void Stop() override; @@ -179,6 +184,7 @@ class FuzzHciLayer : public HciLayer { FuzzCommandInterface le_advertising_interface_{}; FuzzCommandInterface le_scanning_interface_{}; FuzzCommandInterface le_iso_interface_{}; + FuzzCommandInterface distance_measurement_interface_{}; common::ContextualOnceCallback on_command_complete_; common::ContextualOnceCallback on_command_status_; diff --git a/system/gd/hci/fuzz/hci_layer_fuzz_client.cc b/system/gd/hci/fuzz/hci_layer_fuzz_client.cc index 3a19df4d1153f03c8ed9a87a3ae1732564deae1f..fa51a2cdf25ec9b7fa5a3afd431712b5d64495c2 100644 --- a/system/gd/hci/fuzz/hci_layer_fuzz_client.cc +++ b/system/gd/hci/fuzz/hci_layer_fuzz_client.cc @@ -44,6 +44,8 @@ void HciLayerFuzzClient::Start() { GetHandler()->Bind([](hci::ErrorCode, uint16_t, uint8_t, uint16_t, uint16_t) {})); le_advertising_interface_ = hci_->GetLeAdvertisingInterface(GetHandler()->Bind([](LeMetaEventView) {})); le_scanning_interface_ = hci_->GetLeScanningInterface(GetHandler()->Bind([](LeMetaEventView) {})); + distance_measurement_interface_ = + hci_->GetDistanceMeasurementInterface(GetHandler()->Bind([](LeMetaEventView) {})); } void HciLayerFuzzClient::Stop() { diff --git a/system/gd/hci/fuzz/hci_layer_fuzz_client.h b/system/gd/hci/fuzz/hci_layer_fuzz_client.h index 16763ce56282e198fe8b8a83552119af0d5e1ba9..c2151bf652c452296c9adf7c419f6a061fdea14d 100644 --- a/system/gd/hci/fuzz/hci_layer_fuzz_client.h +++ b/system/gd/hci/fuzz/hci_layer_fuzz_client.h @@ -68,11 +68,13 @@ class HciLayerFuzzClient : public Module { } if (uses_command_status(commandPacket.GetOpCode())) { - interface->EnqueueCommand(TBUILDER::FromView(commandPacket), - GetHandler()->BindOnce([](CommandStatusView status) {})); + interface->EnqueueCommand( + TBUILDER::FromView(commandPacket), + GetHandler()->BindOnce([](CommandStatusView /* status */) {})); } else { - interface->EnqueueCommand(TBUILDER::FromView(commandPacket), - GetHandler()->BindOnce([](CommandCompleteView status) {})); + interface->EnqueueCommand( + TBUILDER::FromView(commandPacket), + GetHandler()->BindOnce([](CommandCompleteView /* status */) {})); } } @@ -86,6 +88,7 @@ class HciLayerFuzzClient : public Module { LeAclConnectionInterface* le_acl_connection_interface_; LeAdvertisingInterface* le_advertising_interface_; LeScanningInterface* le_scanning_interface_; + DistanceMeasurementInterface* distance_measurement_interface_; }; } // namespace fuzz diff --git a/system/gd/hci/hci_layer.cc b/system/gd/hci/hci_layer.cc index 3e8ab7837149b7c0876283fa04836a8403ad7c52..0b61fd4a4a19f6b9703b4d1c3b85232dd62ef8f1 100644 --- a/system/gd/hci/hci_layer.cc +++ b/system/gd/hci/hci_layer.cc @@ -23,6 +23,7 @@ #include "os/alarm.h" #include "os/metrics.h" #include "os/queue.h" +#include "osi/include/stack_power_telemetry.h" #include "packet/packet_builder.h" #include "storage/storage_module.h" @@ -188,6 +189,7 @@ struct HciLayer::impl { OpCodeText(op_code).c_str()); if (waiting_command_ == OpCode::CONTROLLER_DEBUG_INFO && op_code != OpCode::CONTROLLER_DEBUG_INFO) { LOG_ERROR("Discarding event that came after timeout 0x%02hx (%s)", op_code, OpCodeText(op_code).c_str()); + common::StopWatch::DumpStopWatchLog(); return; } ASSERT_LOG( @@ -272,6 +274,7 @@ struct HciLayer::impl { auto cmd_view = CommandView::Create(PacketView(bytes)); ASSERT(cmd_view.IsValid()); OpCode op_code = cmd_view.GetOpCode(); + power_telemetry::GetInstance().LogHciCmdDetail(); command_queue_.front().command_view = std::make_unique(std::move(cmd_view)); log_link_layer_connection_command(command_queue_.front().command_view); log_classic_pairing_command_status(command_queue_.front().command_view, ErrorCode::STATUS_UNKNOWN); @@ -372,6 +375,7 @@ struct HciLayer::impl { } else { log_hci_event(command_queue_.front().command_view, event, module_.GetDependency()); } + power_telemetry::GetInstance().LogHciEvtDetail(); EventCode event_code = event.GetEventCode(); // Root Inflamation is a special case, since it aborts here if (event_code == EventCode::VENDOR_SPECIFIC) { @@ -655,6 +659,14 @@ LeIsoInterface* HciLayer::GetLeIsoInterface(ContextualCallback event_handler) { + for (const auto subevent : DistanceMeasurementEvents) { + RegisterLeEventHandler(subevent, event_handler); + } + return &distance_measurement_interface; +} + const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); }); void HciLayer::ListDependencies(ModuleList* list) const { diff --git a/system/gd/hci/hci_layer.h b/system/gd/hci/hci_layer.h index 6a93309b3e5a41f2d63e6b84a475c5b1610e97ac..0acc3dd9e8a95e93b8a22349362ed89dc66f4d06 100644 --- a/system/gd/hci/hci_layer.h +++ b/system/gd/hci/hci_layer.h @@ -30,6 +30,7 @@ #include "common/contextual_callback.h" #include "hal/hci_hal.h" #include "hci/acl_connection_interface.h" +#include "hci/distance_measurement_interface.h" #include "hci/hci_packets.h" #include "hci/le_acl_connection_interface.h" #include "hci/le_advertising_interface.h" @@ -100,6 +101,9 @@ class HciLayer : public Module, public CommandInterface { virtual LeIsoInterface* GetLeIsoInterface(common::ContextualCallback event_handler); + virtual DistanceMeasurementInterface* GetDistanceMeasurementInterface( + common::ContextualCallback event_handler); + std::string ToString() const override { return "Hci Layer"; } @@ -165,6 +169,7 @@ class HciLayer : public Module, public CommandInterface { CommandInterfaceImpl le_advertising_interface{*this}; CommandInterfaceImpl le_scanning_interface{*this}; CommandInterfaceImpl le_iso_interface{*this}; + CommandInterfaceImpl distance_measurement_interface{*this}; }; } // namespace hci } // namespace bluetooth diff --git a/system/gd/hci/hci_layer_fake.cc b/system/gd/hci/hci_layer_fake.cc index 3000c567ea9948bc898a48c247b5eedc3d29b71b..f0b10af740890457aae505ef40b6438fe19494fe 100644 --- a/system/gd/hci/hci_layer_fake.cc +++ b/system/gd/hci/hci_layer_fake.cc @@ -104,6 +104,10 @@ CommandView TestHciLayer::GetCommand() { return command_packet_view; } +void TestHciLayer::AssertNoQueuedCommand() { + EXPECT_TRUE(command_queue_.empty()); +} + void TestHciLayer::RegisterEventHandler( EventCode event_code, common::ContextualCallback event_handler) { registered_events_[event_code] = event_handler; @@ -168,28 +172,36 @@ void TestHciLayer::InitEmptyCommand() { ASSERT_TRUE(empty_command_view_.IsValid()); } -void TestHciLayer::IncomingAclData(uint16_t handle) { +void TestHciLayer::IncomingAclData(uint16_t handle, std::unique_ptr acl_builder) { os::Handler* hci_handler = GetHandler(); auto* queue_end = acl_queue_.GetDownEnd(); std::promise promise; auto future = promise.get_future(); + auto packet = GetPacketView(std::move(acl_builder)); + auto acl_view = AclView::Create(packet); queue_end->RegisterEnqueue( hci_handler, common::Bind( - [](decltype(queue_end) queue_end, uint16_t handle, std::promise promise) { - auto packet = GetPacketView(NextAclPacket(handle)); - AclView acl2 = AclView::Create(packet); + [](decltype(queue_end) queue_end, + uint16_t /* handle */, + AclView acl2, + std::promise promise) { queue_end->UnregisterEnqueue(); promise.set_value(); return std::make_unique(acl2); }, queue_end, handle, + acl_view, common::Passed(std::move(promise)))); auto status = future.wait_for(std::chrono::milliseconds(1000)); ASSERT_EQ(status, std::future_status::ready); } +void TestHciLayer::IncomingAclData(uint16_t handle) { + IncomingAclData(handle, NextAclPacket(handle)); +} + void TestHciLayer::AssertNoOutgoingAclData() { auto queue_end = acl_queue_.GetDownEnd(); EXPECT_EQ(queue_end->TryDequeue(), nullptr); @@ -218,7 +230,7 @@ void TestHciLayer::do_disconnect(uint16_t handle, ErrorCode reason) { HciLayer::Disconnect(handle, reason); } -void TestHciLayer::ListDependencies(ModuleList* list) const {} +void TestHciLayer::ListDependencies(ModuleList* /* list */) const {} void TestHciLayer::Start() { std::lock_guard lock(mutex_); InitEmptyCommand(); @@ -226,4 +238,4 @@ void TestHciLayer::Start() { void TestHciLayer::Stop() {} } // namespace hci -} // namespace bluetooth \ No newline at end of file +} // namespace bluetooth diff --git a/system/gd/hci/hci_layer_fake.h b/system/gd/hci/hci_layer_fake.h index a2c3ea1018e7498366916372bc73787194cab2a8..939ae4eb335991b8510918adf5ec1a6299442ec1 100644 --- a/system/gd/hci/hci_layer_fake.h +++ b/system/gd/hci/hci_layer_fake.h @@ -42,6 +42,8 @@ class TestHciLayer : public HciLayer { CommandView GetCommand(); + void AssertNoQueuedCommand(); + void RegisterEventHandler(EventCode event_code, common::ContextualCallback event_handler) override; void UnregisterEventHandler(EventCode event_code) override; @@ -61,6 +63,8 @@ class TestHciLayer : public HciLayer { void IncomingAclData(uint16_t handle); + void IncomingAclData(uint16_t handle, std::unique_ptr acl_builder); + void AssertNoOutgoingAclData(); packet::PacketView OutgoingAclData(); diff --git a/system/gd/hci/hci_layer_mock.h b/system/gd/hci/hci_layer_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..38e37deddc7d75ba5f984a3d002820671b999e9c --- /dev/null +++ b/system/gd/hci/hci_layer_mock.h @@ -0,0 +1,120 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +#include + +#include "common/contextual_callback.h" +#include "hci/address.h" +#include "hci/hci_layer.h" +#include "hci/hci_packets.h" +#include "module.h" +#include "os/handler.h" + +// Unit test interfaces +namespace bluetooth { +namespace hci { +namespace testing { + +class MockHciLayer : public HciLayer { + public: + MOCK_METHOD( + void, + EnqueueCommand, + (std::unique_ptr, common::ContextualOnceCallback), + (override)); + MOCK_METHOD( + void, + EnqueueCommand, + (std::unique_ptr, common::ContextualOnceCallback), + (override)); + MOCK_METHOD((common::BidiQueueEnd*), GetAclQueueEnd, (), (override)); + MOCK_METHOD((common::BidiQueueEnd*), GetScoQueueEnd, (), (override)); + MOCK_METHOD((common::BidiQueueEnd*), GetIsoQueueEnd, (), (override)); + MOCK_METHOD( + (void), + RegisterEventHandler, + (EventCode, common::ContextualCallback), + (override)); + MOCK_METHOD((void), UnregisterEventHandler, (EventCode), (override)); + MOCK_METHOD( + (void), + RegisterLeEventHandler, + (SubeventCode, common::ContextualCallback), + (override)); + MOCK_METHOD((void), UnregisterLeEventHandler, (SubeventCode), (override)); + MOCK_METHOD( + (SecurityInterface*), + GetSecurityInterface, + (common::ContextualCallback event_handler), + (override)); + + MOCK_METHOD( + (LeSecurityInterface*), + GetLeSecurityInterface, + (common::ContextualCallback event_handler), + (override)); + + MOCK_METHOD( + (AclConnectionInterface*), + GetAclConnectionInterface, + (common::ContextualCallback event_handler, + common::ContextualCallback on_disconnect, + common::ContextualCallback + on_read_remote_version_complete), + (override)); + MOCK_METHOD((void), PutAclConnectionInterface, (), (override)); + + MOCK_METHOD( + (LeAclConnectionInterface*), + GetLeAclConnectionInterface, + (common::ContextualCallback event_handler, + common::ContextualCallback on_disconnect, + common::ContextualCallback + on_read_remote_version_complete), + (override)); + MOCK_METHOD((void), PutLeAclConnectionInterface, (), (override)); + + MOCK_METHOD( + (LeAdvertisingInterface*), + GetLeAdvertisingInterface, + (common::ContextualCallback event_handler), + (override)); + + MOCK_METHOD( + (LeScanningInterface*), + GetLeScanningInterface, + (common::ContextualCallback event_handler), + (override)); + + MOCK_METHOD( + (LeIsoInterface*), + GetLeIsoInterface, + (common::ContextualCallback event_handler), + (override)); + + MOCK_METHOD( + (DistanceMeasurementInterface*), + GetDistanceMeasurementInterface, + (common::ContextualCallback event_handler), + (override)); +}; + +} // namespace testing +} // namespace hci +} // namespace bluetooth diff --git a/system/gd/hci/hci_layer_unittest.cc b/system/gd/hci/hci_layer_unittest.cc index ef1d25ea990188cff621e061bacffd94e62a1e54..52cbb0bf96031cdb85f0e4660d0c7bfd4bb56cd5 100644 --- a/system/gd/hci/hci_layer_unittest.cc +++ b/system/gd/hci/hci_layer_unittest.cc @@ -118,6 +118,8 @@ class HciLayerTest : public ::testing::Test { TestModuleRegistry fake_registry_; }; +class HciLayerDeathTest : public HciLayerTest {}; + TEST_F(HciLayerTest, setup_teardown) {} TEST_F(HciLayerTest, reset_command_sent_on_start) { @@ -136,7 +138,7 @@ TEST_F(HciLayerTest, controller_debug_info_requested_on_hci_timeout) { ASSERT_TRUE(debug_info_view.IsValid()); } -TEST_F(HciLayerTest, abort_after_hci_restart_timeout) { +TEST_F(HciLayerDeathTest, abort_after_hci_restart_timeout) { FailIfResetNotSent(); FakeTimerAdvance(HciLayer::kHciTimeoutMs.count()); @@ -154,7 +156,28 @@ TEST_F(HciLayerTest, abort_after_hci_restart_timeout) { ""); } -TEST_F(HciLayerTest, abort_on_root_inflammation_event) { +TEST_F(HciLayerDeathTest, discard_event_after_hci_timeout) { + FailIfResetNotSent(); + FakeTimerAdvance(HciLayer::kHciTimeoutMs.count()); + + auto sent_command = hal_->GetSentCommand(); + ASSERT_TRUE(sent_command.has_value()); + auto debug_info_view = ControllerDebugInfoView::Create(VendorCommandView::Create(*sent_command)); + ASSERT_TRUE(debug_info_view.IsValid()); + + // This event should be discarded, not cause an abort. + hal_->InjectEvent(ResetCompleteBuilder::Create(1, ErrorCode::SUCCESS)); + sync_handler(); + + ASSERT_DEATH( + { + FakeTimerAdvance(HciLayer::kHciTimeoutRestartMs.count()); + sync_handler(); + }, + ""); +} + +TEST_F(HciLayerDeathTest, abort_on_root_inflammation_event) { FailIfResetNotSent(); ASSERT_DEATH( @@ -174,7 +197,7 @@ TEST_F(HciLayerTest, successful_reset) { sync_handler(); } -TEST_F(HciLayerTest, abort_if_reset_complete_returns_error) { +TEST_F(HciLayerDeathTest, abort_if_reset_complete_returns_error) { FailIfResetNotSent(); ASSERT_DEATH( { @@ -186,17 +209,19 @@ TEST_F(HciLayerTest, abort_if_reset_complete_returns_error) { TEST_F(HciLayerTest, event_handler_is_invoked) { FailIfResetNotSent(); - hci_->RegisterEventHandler(EventCode::COMMAND_COMPLETE, hci_handler_->Bind([](EventView view) { - LOG_DEBUG("%s", kOurEventHandlerWasInvoked); - })); + hci_->RegisterEventHandler( + EventCode::COMMAND_COMPLETE, hci_handler_->Bind([](EventView /* view */) { + LOG_DEBUG("%s", kOurEventHandlerWasInvoked); + })); hal_->InjectEvent(ResetCompleteBuilder::Create(1, ErrorCode::SUCCESS)); } TEST_F(HciLayerTest, le_event_handler_is_invoked) { FailIfResetNotSent(); - hci_->RegisterLeEventHandler(SubeventCode::ENHANCED_CONNECTION_COMPLETE, hci_handler_->Bind([](LeMetaEventView view) { - LOG_DEBUG("%s", kOurLeEventHandlerWasInvoked); - })); + hci_->RegisterLeEventHandler( + SubeventCode::ENHANCED_CONNECTION_COMPLETE, + hci_handler_->Bind( + [](LeMetaEventView /* view */) { LOG_DEBUG("%s", kOurLeEventHandlerWasInvoked); })); hci::Address remote_address; Address::FromString("D0:05:04:03:02:01", remote_address); hal_->InjectEvent(LeEnhancedConnectionCompleteBuilder::Create( @@ -213,28 +238,29 @@ TEST_F(HciLayerTest, le_event_handler_is_invoked) { ClockAccuracy::PPM_30)); } -TEST_F(HciLayerTest, abort_on_second_register_event_handler) { +TEST_F(HciLayerDeathTest, abort_on_second_register_event_handler) { FailIfResetNotSent(); ASSERT_DEATH( { hci_->RegisterEventHandler( - EventCode::SIMPLE_PAIRING_COMPLETE, hci_handler_->Bind([](EventView view) {})); + EventCode::SIMPLE_PAIRING_COMPLETE, hci_handler_->Bind([](EventView /* view */) {})); hci_->RegisterEventHandler( - EventCode::SIMPLE_PAIRING_COMPLETE, hci_handler_->Bind([](EventView view) {})); + EventCode::SIMPLE_PAIRING_COMPLETE, hci_handler_->Bind([](EventView /* view */) {})); sync_handler(); }, ""); } -TEST_F(HciLayerTest, abort_on_second_register_le_event_handler) { +TEST_F(HciLayerDeathTest, abort_on_second_register_le_event_handler) { ASSERT_DEATH( { FailIfResetNotSent(); hci_->RegisterLeEventHandler( - SubeventCode::ENHANCED_CONNECTION_COMPLETE, hci_handler_->Bind([](LeMetaEventView view) {})); + SubeventCode::ENHANCED_CONNECTION_COMPLETE, + hci_handler_->Bind([](LeMetaEventView /* view */) {})); hci_->RegisterLeEventHandler( SubeventCode::ENHANCED_CONNECTION_COMPLETE, - hci_handler_->Bind([](LeMetaEventView view) {})); + hci_handler_->Bind([](LeMetaEventView /* view */) {})); sync_handler(); }, ""); @@ -243,26 +269,29 @@ TEST_F(HciLayerTest, abort_on_second_register_le_event_handler) { TEST_F(HciLayerTest, our_acl_event_callback_is_invoked) { FailIfResetNotSent(); hci_->GetAclConnectionInterface( - hci_handler_->Bind([](EventView view) { LOG_DEBUG("%s", kOurAclEventHandlerWasInvoked); }), - hci_handler_->Bind([](uint16_t handle, ErrorCode reason) {}), - hci_handler_->Bind([](hci::ErrorCode hci_status, - uint16_t handle, - uint8_t version, - uint16_t manufacturer_name, - uint16_t sub_version) {})); + hci_handler_->Bind( + [](EventView /* view */) { LOG_DEBUG("%s", kOurAclEventHandlerWasInvoked); }), + hci_handler_->Bind([](uint16_t /* handle */, ErrorCode /* reason */) {}), + hci_handler_->Bind([](hci::ErrorCode /* hci_status */, + uint16_t /* handle */, + uint8_t /* version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) {})); hal_->InjectEvent(ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, 0x0001, 0x0123)); } TEST_F(HciLayerTest, our_disconnect_callback_is_invoked) { FailIfResetNotSent(); hci_->GetAclConnectionInterface( - hci_handler_->Bind([](EventView view) {}), - hci_handler_->Bind([](uint16_t handle, ErrorCode reason) { LOG_DEBUG("%s", kOurDisconnectHandlerWasInvoked); }), - hci_handler_->Bind([](hci::ErrorCode hci_status, - uint16_t handle, - uint8_t version, - uint16_t manufacturer_name, - uint16_t sub_version) {})); + hci_handler_->Bind([](EventView /* view */) {}), + hci_handler_->Bind([](uint16_t /* handle */, ErrorCode /* reason */) { + LOG_DEBUG("%s", kOurDisconnectHandlerWasInvoked); + }), + hci_handler_->Bind([](hci::ErrorCode /* hci_status */, + uint16_t /* handle */, + uint8_t /* version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) {})); hal_->InjectEvent(DisconnectionCompleteBuilder::Create( ErrorCode::SUCCESS, 0x0001, ErrorCode::REMOTE_USER_TERMINATED_CONNECTION)); } @@ -270,13 +299,15 @@ TEST_F(HciLayerTest, our_disconnect_callback_is_invoked) { TEST_F(HciLayerTest, our_read_remote_version_callback_is_invoked) { FailIfResetNotSent(); hci_->GetAclConnectionInterface( - hci_handler_->Bind([](EventView view) {}), - hci_handler_->Bind([](uint16_t handle, ErrorCode reason) {}), - hci_handler_->Bind([](hci::ErrorCode hci_status, - uint16_t handle, - uint8_t version, - uint16_t manufacturer_name, - uint16_t sub_version) { LOG_DEBUG("%s", kOurReadRemoteVersionHandlerWasInvoked); })); + hci_handler_->Bind([](EventView /* view */) {}), + hci_handler_->Bind([](uint16_t /* handle */, ErrorCode /* reason */) {}), + hci_handler_->Bind([](hci::ErrorCode /* hci_status */, + uint16_t /* handle */, + uint8_t /* version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) { + LOG_DEBUG("%s", kOurReadRemoteVersionHandlerWasInvoked); + })); hal_->InjectEvent(ReadRemoteVersionInformationCompleteBuilder::Create( ErrorCode::SUCCESS, 0x0001, 0x0b, 0x000f, 0x0000)); } @@ -284,26 +315,29 @@ TEST_F(HciLayerTest, our_read_remote_version_callback_is_invoked) { TEST_F(HciLayerTest, our_le_acl_event_callback_is_invoked) { FailIfResetNotSent(); hci_->GetLeAclConnectionInterface( - hci_handler_->Bind([](LeMetaEventView view) { LOG_DEBUG("%s", kOurLeAclEventHandlerWasInvoked); }), - hci_handler_->Bind([](uint16_t handle, ErrorCode reason) {}), - hci_handler_->Bind([](hci::ErrorCode hci_status, - uint16_t handle, - uint8_t version, - uint16_t manufacturer_name, - uint16_t sub_version) {})); + hci_handler_->Bind( + [](LeMetaEventView /* view */) { LOG_DEBUG("%s", kOurLeAclEventHandlerWasInvoked); }), + hci_handler_->Bind([](uint16_t /* handle */, ErrorCode /* reason */) {}), + hci_handler_->Bind([](hci::ErrorCode /* hci_status */, + uint16_t /* handle */, + uint8_t /* version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) {})); hal_->InjectEvent(LeDataLengthChangeBuilder::Create(0x0001, 0x001B, 0x0148, 0x001B, 0x0148)); } TEST_F(HciLayerTest, our_le_disconnect_callback_is_invoked) { FailIfResetNotSent(); hci_->GetLeAclConnectionInterface( - hci_handler_->Bind([](LeMetaEventView view) {}), - hci_handler_->Bind([](uint16_t handle, ErrorCode reason) { LOG_DEBUG("%s", kOurLeDisconnectHandlerWasInvoked); }), - hci_handler_->Bind([](hci::ErrorCode hci_status, - uint16_t handle, - uint8_t version, - uint16_t manufacturer_name, - uint16_t sub_version) {})); + hci_handler_->Bind([](LeMetaEventView /* view */) {}), + hci_handler_->Bind([](uint16_t /* handle */, ErrorCode /* reason */) { + LOG_DEBUG("%s", kOurLeDisconnectHandlerWasInvoked); + }), + hci_handler_->Bind([](hci::ErrorCode /* hci_status */, + uint16_t /* handle */, + uint8_t /* version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) {})); hal_->InjectEvent(DisconnectionCompleteBuilder::Create( ErrorCode::SUCCESS, 0x0001, ErrorCode::REMOTE_USER_TERMINATED_CONNECTION)); } @@ -311,80 +345,87 @@ TEST_F(HciLayerTest, our_le_disconnect_callback_is_invoked) { TEST_F(HciLayerTest, our_le_read_remote_version_callback_is_invoked) { FailIfResetNotSent(); hci_->GetLeAclConnectionInterface( - hci_handler_->Bind([](LeMetaEventView view) {}), - hci_handler_->Bind([](uint16_t handle, ErrorCode reason) {}), - hci_handler_->Bind([](hci::ErrorCode hci_status, - uint16_t handle, - uint8_t version, - uint16_t manufacturer_name, - uint16_t sub_version) { LOG_DEBUG("%s", kOurLeReadRemoteVersionHandlerWasInvoked); })); + hci_handler_->Bind([](LeMetaEventView /* view */) {}), + hci_handler_->Bind([](uint16_t /* handle */, ErrorCode /* reason */) {}), + hci_handler_->Bind([](hci::ErrorCode /* hci_status */, + uint16_t /* handle */, + uint8_t /* version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) { + LOG_DEBUG("%s", kOurLeReadRemoteVersionHandlerWasInvoked); + })); hal_->InjectEvent(ReadRemoteVersionInformationCompleteBuilder::Create( ErrorCode::SUCCESS, 0x0001, 0x0b, 0x000f, 0x0000)); } TEST_F(HciLayerTest, our_security_callback_is_invoked) { FailIfResetNotSent(); - hci_->GetSecurityInterface( - hci_handler_->Bind([](EventView view) { LOG_DEBUG("%s", kOurSecurityEventHandlerWasInvoked); })); + hci_->GetSecurityInterface(hci_handler_->Bind( + [](EventView /* view */) { LOG_DEBUG("%s", kOurSecurityEventHandlerWasInvoked); })); hal_->InjectEvent(EncryptionChangeBuilder::Create( ErrorCode::SUCCESS, 0x0001, bluetooth::hci::EncryptionEnabled::ON)); } TEST_F(HciLayerTest, our_le_security_callback_is_invoked) { FailIfResetNotSent(); - hci_->GetLeSecurityInterface( - hci_handler_->Bind([](LeMetaEventView view) { LOG_DEBUG("%s", kOurLeSecurityEventHandlerWasInvoked); })); + hci_->GetLeSecurityInterface(hci_handler_->Bind( + [](LeMetaEventView /* view */) { LOG_DEBUG("%s", kOurLeSecurityEventHandlerWasInvoked); })); hal_->InjectEvent(LeLongTermKeyRequestBuilder::Create(0x0001, {0, 0, 0, 0, 0, 0, 0, 0}, 0)); } TEST_F(HciLayerTest, our_le_advertising_callback_is_invoked) { FailIfResetNotSent(); - hci_->GetLeAdvertisingInterface( - hci_handler_->Bind([](LeMetaEventView view) { LOG_DEBUG("%s", kOurLeAdvertisementEventHandlerWasInvoked); })); + hci_->GetLeAdvertisingInterface(hci_handler_->Bind([](LeMetaEventView /* view */) { + LOG_DEBUG("%s", kOurLeAdvertisementEventHandlerWasInvoked); + })); hal_->InjectEvent( LeAdvertisingSetTerminatedBuilder::Create(ErrorCode::SUCCESS, 0x01, 0x001, 0x01)); } TEST_F(HciLayerTest, our_le_scanning_callback_is_invoked) { FailIfResetNotSent(); - hci_->GetLeScanningInterface( - hci_handler_->Bind([](LeMetaEventView view) { LOG_DEBUG("%s", kOurLeScanningEventHandlerWasInvoked); })); + hci_->GetLeScanningInterface(hci_handler_->Bind( + [](LeMetaEventView /* view */) { LOG_DEBUG("%s", kOurLeScanningEventHandlerWasInvoked); })); hal_->InjectEvent(LeScanTimeoutBuilder::Create()); } TEST_F(HciLayerTest, our_le_iso_callback_is_invoked) { FailIfResetNotSent(); - hci_->GetLeIsoInterface( - hci_handler_->Bind([](LeMetaEventView view) { LOG_DEBUG("%s", kOurLeIsoEventHandlerWasInvoked); })); + hci_->GetLeIsoInterface(hci_handler_->Bind( + [](LeMetaEventView /* view */) { LOG_DEBUG("%s", kOurLeIsoEventHandlerWasInvoked); })); hal_->InjectEvent(LeCisRequestBuilder::Create(0x0001, 0x0001, 0x01, 0x01)); } TEST_F(HciLayerTest, our_command_complete_callback_is_invoked) { FailIfResetNotSent(); hal_->InjectEvent(ResetCompleteBuilder::Create(1, ErrorCode::SUCCESS)); - hci_->EnqueueCommand(ResetBuilder::Create(), hci_handler_->BindOnce([](CommandCompleteView view) { - LOG_DEBUG("%s", kOurCommandCompleteHandlerWasInvoked); - })); + hci_->EnqueueCommand( + ResetBuilder::Create(), hci_handler_->BindOnce([](CommandCompleteView /* view */) { + LOG_DEBUG("%s", kOurCommandCompleteHandlerWasInvoked); + })); hal_->InjectEvent(ResetCompleteBuilder::Create(1, ErrorCode::SUCCESS)); } TEST_F(HciLayerTest, our_command_status_callback_is_invoked) { FailIfResetNotSent(); hal_->InjectEvent(ResetCompleteBuilder::Create(1, ErrorCode::SUCCESS)); - hci_->EnqueueCommand(ReadClockOffsetBuilder::Create(0x001), hci_handler_->BindOnce([](CommandStatusView view) { - LOG_DEBUG("%s", kOurCommandStatusHandlerWasInvoked); - })); + hci_->EnqueueCommand( + ReadClockOffsetBuilder::Create(0x001), + hci_handler_->BindOnce([](CommandStatusView /* view */) { + LOG_DEBUG("%s", kOurCommandStatusHandlerWasInvoked); + })); hal_->InjectEvent(ReadClockOffsetStatusBuilder::Create(ErrorCode::SUCCESS, 1)); } TEST_F( - HciLayerTest, + HciLayerDeathTest, command_complete_callback_is_invoked_with_an_opcode_that_does_not_match_command_queue) { ASSERT_DEATH( { FailIfResetNotSent(); hci_->EnqueueCommand( - ReadClockOffsetBuilder::Create(0x001), hci_handler_->BindOnce([](CommandCompleteView view) {})); + ReadClockOffsetBuilder::Create(0x001), + hci_handler_->BindOnce([](CommandCompleteView /* view */) {})); hal_->InjectEvent(ReadClockOffsetStatusBuilder::Create(ErrorCode::SUCCESS, 1)); sync_handler(); }, @@ -392,20 +433,21 @@ TEST_F( } TEST_F( - HciLayerTest, + HciLayerDeathTest, command_status_callback_is_invoked_with_an_opcode_that_does_not_match_command_queue) { ASSERT_DEATH( { FailIfResetNotSent(); hci_->EnqueueCommand( - ReadClockOffsetBuilder::Create(0x001), hci_handler_->BindOnce([](CommandStatusView view) {})); + ReadClockOffsetBuilder::Create(0x001), + hci_handler_->BindOnce([](CommandStatusView /* view */) {})); hal_->InjectEvent(ReadClockOffsetStatusBuilder::Create(ErrorCode::SUCCESS, 1)); sync_handler(); }, ""); } -TEST_F(HciLayerTest, command_complete_callback_is_invoked_but_command_queue_empty) { +TEST_F(HciLayerDeathTest, command_complete_callback_is_invoked_but_command_queue_empty) { ASSERT_DEATH( { FailIfResetNotSent(); @@ -416,7 +458,7 @@ TEST_F(HciLayerTest, command_complete_callback_is_invoked_but_command_queue_empt ""); } -TEST_F(HciLayerTest, command_status_callback_is_invoked_but_command_queue_empty) { +TEST_F(HciLayerDeathTest, command_status_callback_is_invoked_but_command_queue_empty) { ASSERT_DEATH( { FailIfResetNotSent(); @@ -430,7 +472,9 @@ TEST_F(HciLayerTest, command_status_callback_is_invoked_but_command_queue_empty) TEST_F(HciLayerTest, command_status_callback_is_invoked_with_failure_status) { FailIfResetNotSent(); hal_->InjectEvent(ResetCompleteBuilder::Create(1, ErrorCode::SUCCESS)); - hci_->EnqueueCommand(ReadClockOffsetBuilder::Create(0x001), hci_handler_->BindOnce([](CommandStatusView view) {})); + hci_->EnqueueCommand( + ReadClockOffsetBuilder::Create(0x001), + hci_handler_->BindOnce([](CommandStatusView /* view */) {})); hal_->InjectEvent(ReadClockOffsetStatusBuilder::Create(ErrorCode::HARDWARE_FAILURE, 1)); sync_handler(); } diff --git a/system/gd/hci/hci_packets_test.cc b/system/gd/hci/hci_packets_test.cc index 6e6a370e0b3327dc7ced4410c1697ec1d38ecf7a..a7ccb1ff5596e7baf0aa5f385db0111551ced037 100644 --- a/system/gd/hci/hci_packets_test.cc +++ b/system/gd/hci/hci_packets_test.cc @@ -275,7 +275,9 @@ TEST(HciPacketsTest, testLeSetExtendedAdvertisingData) { std::vector advertising_data{ 0x02, 0x01, 0x02, 0x0a, 0x09, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x33, 0x20, 0x58, }; - ASSERT_EQ(advertising_data, view.GetAdvertisingData()); + auto payload = view.GetPayload(); + std::vector payload_data(payload.begin(), payload.end()); + ASSERT_EQ(advertising_data, payload_data); } std::vector le_set_extended_advertising_parameters_set_0{ diff --git a/system/gd/hci/le_address_manager.cc b/system/gd/hci/le_address_manager.cc index 97b7e85de32b3bf01a33038148e738526690cedd..1c954a36c3e06fc0409e4e4a5a0502e7002744e7 100644 --- a/system/gd/hci/le_address_manager.cc +++ b/system/gd/hci/le_address_manager.cc @@ -17,6 +17,7 @@ #include "hci/le_address_manager.h" #include "common/init_flags.h" +#include "hci/octets.h" #include "os/log.h" #include "os/rand.h" @@ -48,7 +49,7 @@ LeAddressManager::~LeAddressManager() { void LeAddressManager::SetPrivacyPolicyForInitiatorAddress( AddressPolicy address_policy, AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + Octet16 rotation_irk, bool supports_ble_privacy, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { @@ -110,7 +111,7 @@ void LeAddressManager::SetPrivacyPolicyForInitiatorAddress( void LeAddressManager::SetPrivacyPolicyForInitiatorAddressForTest( AddressPolicy address_policy, AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { ASSERT(address_policy != AddressPolicy::POLICY_NOT_SET); @@ -384,8 +385,13 @@ hci::Address LeAddressManager::generate_rpa() { address.address[4] = prand[1]; address.address[5] = prand[2]; + Octet16 rand{}; + rand[0] = prand[0]; + rand[1] = prand[1]; + rand[2] = prand[2]; + /* encrypt with IRK */ - crypto_toolbox::Octet16 p = crypto_toolbox::aes_128(rotation_irk_, prand.data(), 3); + Octet16 p = crypto_toolbox::aes_128(rotation_irk_, rand); /* set hash to be LSB of rpAddress */ address.address[0] = p[0]; diff --git a/system/gd/hci/le_address_manager.h b/system/gd/hci/le_address_manager.h index 776fe99570f347613fc4759f4b43a3b37102aed5..6f882a64936a58d62693b5d257b4749e41b35640 100644 --- a/system/gd/hci/le_address_manager.h +++ b/system/gd/hci/le_address_manager.h @@ -16,13 +16,11 @@ #pragma once #include -#include -#include #include #include "common/callback.h" #include "hci/address_with_type.h" -#include "hci/hci_layer.h" +#include "hci/octets.h" #include "os/alarm.h" namespace bluetooth { @@ -60,7 +58,7 @@ class LeAddressManager { void SetPrivacyPolicyForInitiatorAddress( AddressPolicy address_policy, AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + Octet16 rotation_irk, bool supports_ble_privacy, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time); @@ -68,7 +66,7 @@ class LeAddressManager { void SetPrivacyPolicyForInitiatorAddressForTest( AddressPolicy address_policy, AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time); AddressPolicy GetAddressPolicy(); @@ -133,7 +131,7 @@ class LeAddressManager { struct RotateRandomAddressCommand {}; struct UpdateIRKCommand { - crypto_toolbox::Octet16 rotation_irk; + Octet16 rotation_irk; std::chrono::milliseconds minimum_rotation_time; std::chrono::milliseconds maximum_rotation_time; }; @@ -175,7 +173,7 @@ class LeAddressManager { AddressWithType cached_address_; Address public_address_; std::unique_ptr address_rotation_alarm_; - crypto_toolbox::Octet16 rotation_irk_; + Octet16 rotation_irk_; uint8_t connect_list_size_; uint8_t resolving_list_size_; std::queue cached_commands_; diff --git a/system/gd/hci/le_address_manager_test.cc b/system/gd/hci/le_address_manager_test.cc index b1ede37b37dc6bc105d267d2651f2c8c9cbb0ec5..aee27db67c5df0952a3395d7c9ffb39f4ae70c1e 100644 --- a/system/gd/hci/le_address_manager_test.cc +++ b/system/gd/hci/le_address_manager_test.cc @@ -19,10 +19,12 @@ #include #include "common/init_flags.h" +#include "hci/hci_layer.h" +#include "hci/octets.h" #include "os/log.h" #include "packet/raw_builder.h" -using ::bluetooth::crypto_toolbox::Octet16; +using ::bluetooth::hci::Octet16; using ::bluetooth::os::Handler; using ::bluetooth::os::Thread; @@ -112,7 +114,7 @@ class TestHciLayer : public HciLayer { command_complete_callbacks.pop_front(); } - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} void Start() override {} void Stop() override {} @@ -170,7 +172,7 @@ class LeAddressManagerTest : public ::testing::Test { AllocateClients(1); } - void sync_handler(os::Handler* handler) { + void sync_handler(os::Handler* /* handler */) { std::promise promise; auto future = promise.get_future(); handler_->Post(common::BindOnce(&std::promise::set_value, common::Unretained(&promise))); diff --git a/system/gd/hci/le_advertising_manager.cc b/system/gd/hci/le_advertising_manager.cc index f50b091cf169ad6303ce4e889c68eacbdc746fd5..5d4be6313a9715b237a58113138ca9d0a54a2506 100644 --- a/system/gd/hci/le_advertising_manager.cc +++ b/system/gd/hci/le_advertising_manager.cc @@ -15,13 +15,18 @@ */ #include "hci/le_advertising_manager.h" +#include + +#include #include #include #include "common/init_flags.h" #include "common/strings.h" +#include "hardware/ble_advertiser.h" #include "hci/acl_manager.h" #include "hci/controller.h" +#include "hci/event_checkers.h" #include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "hci/le_advertising_interface.h" @@ -30,6 +35,7 @@ #include "os/handler.h" #include "os/log.h" #include "os/system_properties.h" +#include "packet/fragmenting_inserter.h" namespace bluetooth { namespace hci { @@ -197,6 +203,10 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb return num_instances_; } + int get_advertiser_reg_id(AdvertiserId advertiser_id) { + return id_map_[advertiser_id]; + } + AdvertisingApiType get_advertising_api_type() const { return advertising_api_type_; } @@ -350,7 +360,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb if (advertising_api_type_ == AdvertisingApiType::EXTENDED) { le_advertising_interface_->EnqueueCommand( hci::LeRemoveAdvertisingSetBuilder::Create(advertiser_id), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); if (advertising_sets_[advertiser_id].address_rotation_alarm != nullptr) { advertising_sets_[advertiser_id].address_rotation_alarm->Cancel(); @@ -457,8 +467,9 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb set_data(id, false, config.advertisement); if (advertising_sets_[id].address_type != AdvertiserAddressType::PUBLIC) { le_advertising_interface_->EnqueueCommand( - hci::LeMultiAdvtSetRandomAddrBuilder::Create(advertising_sets_[id].current_address.GetAddress(), id), - module_handler_->BindOnce(impl::check_status)); + hci::LeMultiAdvtSetRandomAddrBuilder::Create( + advertising_sets_[id].current_address.GetAddress(), id), + module_handler_->BindOnce(check_complete)); } if (!paused) { enable_advertiser(id, true, 0, 0); @@ -484,11 +495,21 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb advertising_sets_[id].status_callback = std::move(status_callback); advertising_sets_[id].timeout_callback = std::move(timeout_callback); + // legacy start_advertising use default jni client id create_extended_advertiser_with_id( - kIdLocal, id, config, scan_callback, set_terminated_callback, duration, 0, handler); + kAdvertiserClientIdJni, + kIdLocal, + id, + config, + scan_callback, + set_terminated_callback, + duration, + 0, + handler); } void create_extended_advertiser( + uint8_t client_id, int reg_id, const AdvertisingConfig config, common::Callback scan_callback, @@ -503,6 +524,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb return; } create_extended_advertiser_with_id( + client_id, reg_id, id, config, @@ -514,6 +536,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb } void create_extended_advertiser_with_id( + uint8_t client_id, int reg_id, AdvertiserId id, const AdvertisingConfig config, @@ -569,9 +592,19 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb id, advertising_sets_[id].current_address)); - // but we only rotate if the AdvertiserAddressType is non-public (since static random - // addresses don't rotate) - if (advertising_sets_[id].address_type != AdvertiserAddressType::PUBLIC) { + bool leaudio_requested_nrpa = false; + if (client_id == kAdvertiserClientIdLeAudio && + advertising_sets_[id].address_type == AdvertiserAddressType::NONRESOLVABLE_RANDOM) { + LOG_INFO( + "Advertiser started by le audio client with address type: %d", + advertising_sets_[id].address_type); + leaudio_requested_nrpa = true; + } + + // but we only rotate if the AdvertiserAddressType is non-public + // or non-rpa requested by leaudio(since static random addresses don't rotate) + if (advertising_sets_[id].address_type != AdvertiserAddressType::PUBLIC && + !leaudio_requested_nrpa) { // start timer for random address advertising_sets_[id].address_rotation_alarm = std::make_unique(module_handler_); advertising_sets_[id].address_rotation_alarm->Schedule( @@ -621,24 +654,24 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb case (AdvertisingApiType::LEGACY): le_advertising_interface_->EnqueueCommand( hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); break; case (AdvertisingApiType::ANDROID_HCI): le_advertising_interface_->EnqueueCommand( hci::LeMultiAdvtSetEnableBuilder::Create(Enable::DISABLED, advertiser_id), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); break; case (AdvertisingApiType::EXTENDED): { le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::DISABLED, enabled_vector), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); // Only set periodic advertising if supported. if (controller_->SupportsBlePeriodicAdvertising()) { le_advertising_interface_->EnqueueCommand( hci::LeSetPeriodicAdvertisingEnableBuilder::Create(false, false, advertiser_id), module_handler_->BindOnce( - impl::check_status)); + check_complete)); } } break; } @@ -681,7 +714,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb if (advertising_sets_[advertiser_id].connectable) { le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::DISABLED, enabled_sets), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); } rotate_advertiser_address(advertiser_id); @@ -693,7 +726,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb if (advertising_sets_[advertiser_id].connectable && !paused) { le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::ENABLED, enabled_sets), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); } advertising_sets_[advertiser_id].address_rotation_alarm->Schedule( @@ -747,6 +780,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb module_handler_->BindOnceOn( this, &impl::check_status_with_id, + true, advertiser_id)); } break; case (AdvertisingApiType::ANDROID_HCI): { @@ -763,7 +797,8 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb config.filter_policy, advertiser_id, config.tx_power), - module_handler_->BindOnceOn(this, &impl::check_status_with_id, advertiser_id)); + module_handler_->BindOnceOn( + this, &impl::check_status_with_id, true, advertiser_id)); } break; case (AdvertisingApiType::EXTENDED): { // sid must be in range 0x00 to 0x0F. Since no controller supports more than @@ -877,10 +912,12 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb bool check_extended_advertising_data(std::vector data, bool include_flag) { uint16_t data_len = 0; + uint16_t data_limit = IS_FLAG_ENABLED(divide_long_single_gap_data) ? kLeMaximumGapDataLength + : kLeMaximumFragmentLength; // check data size for (size_t i = 0; i < data.size(); i++) { - if (data[i].size() > kLeMaximumFragmentLength) { - LOG_WARN("AD data len shall not greater than %d", kLeMaximumFragmentLength); + if (data[i].size() > data_limit) { + LOG_WARN("AD data len shall not greater than %d", data_limit); return false; } data_len += data[i].size(); @@ -943,31 +980,42 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb le_advertising_interface_->EnqueueCommand( hci::LeSetScanResponseDataBuilder::Create(data), module_handler_->BindOnceOn( - this, &impl::check_status_with_id, advertiser_id)); + this, + &impl::check_status_with_id, + true, + advertiser_id)); } else { le_advertising_interface_->EnqueueCommand( hci::LeSetAdvertisingDataBuilder::Create(data), module_handler_->BindOnceOn( - this, &impl::check_status_with_id, advertiser_id)); + this, + &impl::check_status_with_id, + true, + advertiser_id)); } } break; case (AdvertisingApiType::ANDROID_HCI): { if (set_scan_rsp) { le_advertising_interface_->EnqueueCommand( hci::LeMultiAdvtSetScanRespBuilder::Create(data, advertiser_id), - module_handler_->BindOnceOn(this, &impl::check_status_with_id, advertiser_id)); + module_handler_->BindOnceOn( + this, &impl::check_status_with_id, true, advertiser_id)); } else { le_advertising_interface_->EnqueueCommand( hci::LeMultiAdvtSetDataBuilder::Create(data, advertiser_id), - module_handler_->BindOnceOn(this, &impl::check_status_with_id, advertiser_id)); + module_handler_->BindOnceOn( + this, &impl::check_status_with_id, true, advertiser_id)); } } break; case (AdvertisingApiType::EXTENDED): { uint16_t data_len = 0; + bool divide_gap_flag = IS_FLAG_ENABLED(divide_long_single_gap_data); // check data size for (size_t i = 0; i < data.size(); i++) { - if (data[i].size() > kLeMaximumFragmentLength) { - LOG_WARN("AD data len shall not greater than %d", kLeMaximumFragmentLength); + uint16_t data_limit = + divide_gap_flag ? kLeMaximumGapDataLength : kLeMaximumFragmentLength; + if (data[i].size() > data_limit) { + LOG_WARN("AD data len shall not greater than %d", data_limit); if (advertising_callbacks_ != nullptr) { if (set_scan_rsp) { advertising_callbacks_->OnScanResponseDataSet( @@ -1005,17 +1053,36 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb uint16_t sub_data_len = 0; Operation operation = Operation::FIRST_FRAGMENT; - for (size_t i = 0; i < data.size(); i++) { - if (sub_data_len + data[i].size() > kLeMaximumFragmentLength) { - send_data_fragment(advertiser_id, set_scan_rsp, sub_data, operation); + if (divide_gap_flag) { + std::vector> fragments; + packet::FragmentingInserter it( + kLeMaximumFragmentLength, std::back_insert_iterator(fragments)); + for (auto gap_data : data) { + gap_data.Serialize(it); + } + it.finalize(); + + for (size_t i = 0; i < fragments.size(); i++) { + send_data_fragment_with_raw_builder( + advertiser_id, + set_scan_rsp, + std::move(fragments[i]), + (i == fragments.size() - 1) ? Operation::LAST_FRAGMENT : operation); operation = Operation::INTERMEDIATE_FRAGMENT; - sub_data_len = 0; - sub_data.clear(); } - sub_data.push_back(data[i]); - sub_data_len += data[i].size(); + } else { + for (size_t i = 0; i < data.size(); i++) { + if (sub_data_len + data[i].size() > kLeMaximumFragmentLength) { + send_data_fragment(advertiser_id, set_scan_rsp, sub_data, operation); + operation = Operation::INTERMEDIATE_FRAGMENT; + sub_data_len = 0; + sub_data.clear(); + } + sub_data.push_back(data[i]); + sub_data_len += data[i].size(); + } + send_data_fragment(advertiser_id, set_scan_rsp, sub_data, Operation::LAST_FRAGMENT); } - send_data_fragment(advertiser_id, set_scan_rsp, sub_data, Operation::LAST_FRAGMENT); } } break; } @@ -1023,32 +1090,96 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb void send_data_fragment( AdvertiserId advertiser_id, bool set_scan_rsp, std::vector data, Operation operation) { - if (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT) { + if (IS_FLAG_ENABLED(divide_long_single_gap_data)) { + // For first and intermediate fragment, do not trigger advertising_callbacks_. + bool send_callback = + (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT); if (set_scan_rsp) { le_advertising_interface_->EnqueueCommand( - hci::LeSetExtendedScanResponseDataBuilder::Create(advertiser_id, operation, kFragment_preference, data), + hci::LeSetExtendedScanResponseDataBuilder::Create( + advertiser_id, operation, kFragment_preference, data), module_handler_->BindOnceOn( - this, &impl::check_status_with_id, advertiser_id)); + this, + &impl::check_status_with_id, + send_callback, + advertiser_id)); } else { le_advertising_interface_->EnqueueCommand( - hci::LeSetExtendedAdvertisingDataBuilder::Create(advertiser_id, operation, kFragment_preference, data), + hci::LeSetExtendedAdvertisingDataBuilder::Create( + advertiser_id, operation, kFragment_preference, data), module_handler_->BindOnceOn( - this, &impl::check_status_with_id, advertiser_id)); + this, + &impl::check_status_with_id, + send_callback, + advertiser_id)); } } else { - // For first and intermediate fragment, do not trigger advertising_callbacks_. - if (set_scan_rsp) { - le_advertising_interface_->EnqueueCommand( - hci::LeSetExtendedScanResponseDataBuilder::Create(advertiser_id, operation, kFragment_preference, data), - module_handler_->BindOnce(impl::check_status)); + if (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT) { + if (set_scan_rsp) { + le_advertising_interface_->EnqueueCommand( + hci::LeSetExtendedScanResponseDataBuilder::Create( + advertiser_id, operation, kFragment_preference, data), + module_handler_->BindOnceOn( + this, + &impl::check_status_with_id, + true, + advertiser_id)); + } else { + le_advertising_interface_->EnqueueCommand( + hci::LeSetExtendedAdvertisingDataBuilder::Create( + advertiser_id, operation, kFragment_preference, data), + module_handler_->BindOnceOn( + this, + &impl::check_status_with_id, + true, + advertiser_id)); + } } else { - le_advertising_interface_->EnqueueCommand( - hci::LeSetExtendedAdvertisingDataBuilder::Create(advertiser_id, operation, kFragment_preference, data), - module_handler_->BindOnce(impl::check_status)); + // For first and intermediate fragment, do not trigger advertising_callbacks_. + if (set_scan_rsp) { + le_advertising_interface_->EnqueueCommand( + hci::LeSetExtendedScanResponseDataBuilder::Create( + advertiser_id, operation, kFragment_preference, data), + module_handler_->BindOnce(check_complete)); + } else { + le_advertising_interface_->EnqueueCommand( + hci::LeSetExtendedAdvertisingDataBuilder::Create( + advertiser_id, operation, kFragment_preference, data), + module_handler_->BindOnce(check_complete)); + } } } } + void send_data_fragment_with_raw_builder( + AdvertiserId advertiser_id, + bool set_scan_rsp, + std::unique_ptr data, + Operation operation) { + // For first and intermediate fragment, do not trigger advertising_callbacks_. + bool send_callback = + (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT); + if (set_scan_rsp) { + le_advertising_interface_->EnqueueCommand( + hci::LeSetExtendedScanResponseDataRawBuilder::Create( + advertiser_id, operation, kFragment_preference, std::move(data)), + module_handler_->BindOnceOn( + this, + &impl::check_status_with_id, + send_callback, + advertiser_id)); + } else { + le_advertising_interface_->EnqueueCommand( + hci::LeSetExtendedAdvertisingDataRawBuilder::Create( + advertiser_id, operation, kFragment_preference, std::move(data)), + module_handler_->BindOnceOn( + this, + &impl::check_status_with_id, + send_callback, + advertiser_id)); + } + } + void enable_advertiser( AdvertiserId advertiser_id, bool enable, uint16_t duration, uint8_t max_extended_advertising_events) { EnabledSet curr_set; @@ -1099,6 +1230,12 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb if (enable) { enabled_sets_[advertiser_id].advertising_handle_ = advertiser_id; + if (advertising_api_type_ == AdvertisingApiType::EXTENDED) { + enabled_sets_[advertiser_id].duration_ = duration; + enabled_sets_[advertiser_id].max_extended_advertising_events_ = + max_extended_advertising_events; + } + advertising_sets_[advertiser_id].duration = duration; advertising_sets_[advertiser_id].max_extended_advertising_events = max_extended_advertising_events; } else { @@ -1124,15 +1261,18 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb module_handler_->BindOnceOn( this, &impl::check_status_with_id, + true, advertiser_id)); } void set_periodic_data(AdvertiserId advertiser_id, std::vector data) { uint16_t data_len = 0; + bool divide_gap_flag = IS_FLAG_ENABLED(divide_long_single_gap_data); // check data size for (size_t i = 0; i < data.size(); i++) { - if (data[i].size() > kLeMaximumFragmentLength) { - LOG_WARN("AD data len shall not greater than %d", kLeMaximumFragmentLength); + uint16_t data_limit = divide_gap_flag ? kLeMaximumGapDataLength : kLeMaximumFragmentLength; + if (data[i].size() > data_limit) { + LOG_WARN("AD data len shall not greater than %d", data_limit); if (advertising_callbacks_ != nullptr) { advertising_callbacks_->OnPeriodicAdvertisingDataSet( advertiser_id, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR); @@ -1152,41 +1292,92 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb return; } - if (data_len <= kLeMaximumFragmentLength) { + uint16_t data_fragment_limit = + divide_gap_flag ? kLeMaximumPeriodicDataFragmentLength : kLeMaximumFragmentLength; + if (data_len <= data_fragment_limit) { send_periodic_data_fragment(advertiser_id, data, Operation::COMPLETE_ADVERTISEMENT); } else { std::vector sub_data; uint16_t sub_data_len = 0; Operation operation = Operation::FIRST_FRAGMENT; - for (size_t i = 0; i < data.size(); i++) { - if (sub_data_len + data[i].size() > kLeMaximumFragmentLength) { - send_periodic_data_fragment(advertiser_id, sub_data, operation); + if (divide_gap_flag) { + std::vector> fragments; + packet::FragmentingInserter it( + kLeMaximumPeriodicDataFragmentLength, std::back_insert_iterator(fragments)); + for (auto gap_data : data) { + gap_data.Serialize(it); + } + it.finalize(); + + for (size_t i = 0; i < fragments.size(); i++) { + send_periodic_data_fragment_with_raw_builder( + advertiser_id, + std::move(fragments[i]), + (i == fragments.size() - 1) ? Operation::LAST_FRAGMENT : operation); operation = Operation::INTERMEDIATE_FRAGMENT; - sub_data_len = 0; - sub_data.clear(); } - sub_data.push_back(data[i]); - sub_data_len += data[i].size(); + } else { + for (size_t i = 0; i < data.size(); i++) { + if (sub_data_len + data[i].size() > kLeMaximumFragmentLength) { + send_periodic_data_fragment(advertiser_id, sub_data, operation); + operation = Operation::INTERMEDIATE_FRAGMENT; + sub_data_len = 0; + sub_data.clear(); + } + sub_data.push_back(data[i]); + sub_data_len += data[i].size(); + } + send_periodic_data_fragment(advertiser_id, sub_data, Operation::LAST_FRAGMENT); } - send_periodic_data_fragment(advertiser_id, sub_data, Operation::LAST_FRAGMENT); } } void send_periodic_data_fragment(AdvertiserId advertiser_id, std::vector data, Operation operation) { - if (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT) { + if (IS_FLAG_ENABLED(divide_long_single_gap_data)) { + // For first and intermediate fragment, do not trigger advertising_callbacks_. + bool send_callback = + (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT); le_advertising_interface_->EnqueueCommand( hci::LeSetPeriodicAdvertisingDataBuilder::Create(advertiser_id, operation, data), module_handler_->BindOnceOn( - this, &impl::check_status_with_id, advertiser_id)); + this, + &impl::check_status_with_id, + send_callback, + advertiser_id)); } else { - // For first and intermediate fragment, do not trigger advertising_callbacks_. - le_advertising_interface_->EnqueueCommand( - hci::LeSetPeriodicAdvertisingDataBuilder::Create(advertiser_id, operation, data), - module_handler_->BindOnce(impl::check_status)); + if (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT) { + le_advertising_interface_->EnqueueCommand( + hci::LeSetPeriodicAdvertisingDataBuilder::Create(advertiser_id, operation, data), + module_handler_->BindOnceOn( + this, + &impl::check_status_with_id, + true, + advertiser_id)); + } else { + // For first and intermediate fragment, do not trigger advertising_callbacks_. + le_advertising_interface_->EnqueueCommand( + hci::LeSetPeriodicAdvertisingDataBuilder::Create(advertiser_id, operation, data), + module_handler_->BindOnce(check_complete)); + } } } + void send_periodic_data_fragment_with_raw_builder( + AdvertiserId advertiser_id, std::unique_ptr data, Operation operation) { + // For first and intermediate fragment, do not trigger advertising_callbacks_. + bool send_callback = + (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT); + le_advertising_interface_->EnqueueCommand( + hci::LeSetPeriodicAdvertisingDataRawBuilder::Create( + advertiser_id, operation, std::move(data)), + module_handler_->BindOnceOn( + this, + &impl::check_status_with_id, + send_callback, + advertiser_id)); + } + void enable_periodic_advertising(AdvertiserId advertiser_id, bool enable, bool include_adi) { if (!controller_->SupportsBlePeriodicAdvertising()) { return; @@ -1223,7 +1414,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb case (AdvertisingApiType::LEGACY): { le_advertising_interface_->EnqueueCommand( hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); } break; case (AdvertisingApiType::ANDROID_HCI): { for (size_t i = 0; i < enabled_sets_.size(); i++) { @@ -1231,7 +1422,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb if (id != kInvalidHandle) { le_advertising_interface_->EnqueueCommand( hci::LeMultiAdvtSetEnableBuilder::Create(Enable::DISABLED, id), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); } } } break; @@ -1239,7 +1430,8 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb if (enabled_sets.size() != 0) { le_advertising_interface_->EnqueueCommand( hci::LeSetExtendedAdvertisingEnableBuilder::Create(Enable::DISABLED, enabled_sets), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce( + check_complete)); } } break; } @@ -1275,8 +1467,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb true, enabled_sets, false /* trigger_callbacks */) - : module_handler_->BindOnce( - impl::check_status)); + : module_handler_->BindOnce(check_complete)); } break; case (AdvertisingApiType::ANDROID_HCI): { for (size_t i = 0; i < enabled_sets_.size(); i++) { @@ -1292,7 +1483,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb true, enabled_sets, false /* trigger_callbacks */) - : module_handler_->BindOnce(impl::check_status)); + : module_handler_->BindOnce(check_complete)); } } } break; @@ -1310,7 +1501,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb enabled_sets, false /* trigger_callbacks */) : module_handler_->BindOnce( - impl::check_status)); + check_complete)); } } break; } @@ -1521,7 +1712,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb } template - void check_status_with_id(AdvertiserId id, CommandCompleteView view) { + void check_status_with_id(bool send_callback, AdvertiserId id, CommandCompleteView view) { ASSERT(view.IsValid()); auto status_view = View::Create(view); ASSERT(status_view.IsValid()); @@ -1543,6 +1734,13 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb return; } + if (IS_FLAG_ENABLED(divide_long_single_gap_data)) { + // Do not trigger callback if send_callback is false + if (!send_callback) { + return; + } + } + OpCode opcode = view.GetCommandOpCode(); switch (opcode) { @@ -1587,19 +1785,6 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb } } - template - static void check_status(CommandCompleteView view) { - ASSERT(view.IsValid()); - auto status_view = View::Create(view); - ASSERT(status_view.IsValid()); - if (status_view.GetStatus() != ErrorCode::SUCCESS) { - LOG_INFO( - "Got a Command complete %s, status %s", - OpCodeText(view.GetCommandOpCode()).c_str(), - ErrorCodeText(status_view.GetStatus()).c_str()); - } - } - void start_advertising_fail(int reg_id, AdvertisingCallback::AdvertisingStatus status) { ASSERT(status != AdvertisingCallback::AdvertisingStatus::SUCCESS); advertising_callbacks_->OnAdvertisingSetStarted(reg_id, kInvalidId, 0, status); @@ -1638,7 +1823,12 @@ size_t LeAdvertisingManager::GetNumberOfAdvertisingInstances() const { return pimpl_->GetNumberOfAdvertisingInstances(); } +int LeAdvertisingManager::GetAdvertiserRegId(AdvertiserId advertiser_id) { + return pimpl_->get_advertiser_reg_id(advertiser_id); +} + void LeAdvertisingManager::ExtendedCreateAdvertiser( + uint8_t client_id, int reg_id, const AdvertisingConfig config, common::Callback scan_callback, @@ -1707,6 +1897,7 @@ void LeAdvertisingManager::ExtendedCreateAdvertiser( CallOn( pimpl_.get(), &impl::create_extended_advertiser, + client_id, reg_id, config, scan_callback, diff --git a/system/gd/hci/le_advertising_manager.h b/system/gd/hci/le_advertising_manager.h index 4b1274b178a0f1cbeed0d8674eee832cb0ebc18c..448bde83f7b629ee942f14c7e2a3ea99e2876802 100644 --- a/system/gd/hci/le_advertising_manager.h +++ b/system/gd/hci/le_advertising_manager.h @@ -104,6 +104,8 @@ class LeAdvertisingManager : public bluetooth::Module { static constexpr uint8_t kInvalidHandle = 0xFF; static constexpr uint8_t kAdvertisingSetIdMask = 0x0F; static constexpr uint16_t kLeMaximumFragmentLength = 251; + static constexpr uint16_t kLeMaximumPeriodicDataFragmentLength = 252; + static constexpr uint16_t kLeMaximumGapDataLength = 255; static constexpr FragmentPreference kFragment_preference = FragmentPreference::CONTROLLER_SHOULD_NOT; LeAdvertisingManager(); LeAdvertisingManager(const LeAdvertisingManager&) = delete; @@ -111,7 +113,10 @@ class LeAdvertisingManager : public bluetooth::Module { size_t GetNumberOfAdvertisingInstances() const; + int GetAdvertiserRegId(AdvertiserId advertiser_id); + void ExtendedCreateAdvertiser( + uint8_t client_id, int reg_id, const AdvertisingConfig config, common::Callback scan_callback, diff --git a/system/gd/hci/le_advertising_manager_mock.h b/system/gd/hci/le_advertising_manager_mock.h index a6198caeb20faa3091ea7dd7d300e22dad62e400..d56e91de3a296b060df046e4d783ba36c676c0be 100644 --- a/system/gd/hci/le_advertising_manager_mock.h +++ b/system/gd/hci/le_advertising_manager_mock.h @@ -36,7 +36,8 @@ class MockLeAdvertisingManager : public LeAdvertisingManager { MOCK_METHOD( AdvertiserId, ExtendedCreateAdvertiser, - (int regId, + (uint8_t client_id, + int regId, const AdvertisingConfig, const common::Callback&, const common::Callback&, diff --git a/system/gd/hci/le_advertising_manager_test.cc b/system/gd/hci/le_advertising_manager_test.cc index 4a7c420aefc663171370558812167e1a543e713a..a048b0e99c988c081484a045b123bcc5dcb20445 100644 --- a/system/gd/hci/le_advertising_manager_test.cc +++ b/system/gd/hci/le_advertising_manager_test.cc @@ -16,6 +16,8 @@ #include "hci/le_advertising_manager.h" +#include +#include #include #include @@ -25,6 +27,7 @@ #include #include "common/bind.h" +#include "hardware/ble_advertiser.h" #include "hci/acl_manager.h" #include "hci/address.h" #include "hci/controller.h" @@ -32,6 +35,8 @@ #include "os/thread.h" #include "packet/raw_builder.h" +#define TEST_BT com::android::bluetooth::flags + namespace bluetooth { namespace hci { namespace { @@ -85,7 +90,7 @@ class TestController : public Controller { protected: void Start() override {} void Stop() override {} - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} private: std::set supported_opcodes_{}; @@ -113,18 +118,18 @@ class TestLeAddressManager : public LeAddressManager { return AddressPolicy::USE_STATIC_ADDRESS; } - void Unregister(LeAddressManagerCallback* callback) override { + void Unregister(LeAddressManagerCallback* /* callback */) override { if (!ignore_unregister_for_testing) { client_ = nullptr; } test_client_state_ = UNREGISTERED; } - void AckPause(LeAddressManagerCallback* callback) override { + void AckPause(LeAddressManagerCallback* /* callback */) override { test_client_state_ = PAUSED; } - void AckResume(LeAddressManagerCallback* callback) override { + void AckResume(LeAddressManagerCallback* /* callback */) override { test_client_state_ = RESUMED; } @@ -168,11 +173,11 @@ class TestAclManager : public AclManager { delete thread_; } - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} - void SetRandomAddress(Address address) {} + void SetRandomAddress(Address /* address */) {} - void enqueue_command(std::unique_ptr command_packet){}; + void enqueue_command(std::unique_ptr /* command_packet */){}; os::Thread* thread_; os::Handler* handler_; @@ -220,9 +225,9 @@ class LeAdvertisingManagerTest : public ::testing::Test { const common::Callback set_terminated_callback = common::Bind(&LeAdvertisingManagerTest::on_set_terminated, common::Unretained(this)); - void on_scan(Address address, AddressType address_type) {} + void on_scan(Address /* address */, AddressType /* address_type */) {} - void on_set_terminated(ErrorCode error_code, uint8_t, uint8_t) {} + void on_set_terminated(ErrorCode /* error_code */, uint8_t, uint8_t) {} void sync_client_handler() { ASSERT(thread_.GetReactor()->WaitForIdle(2s)); @@ -270,7 +275,14 @@ class LeAdvertisingAPITest : public LeAdvertisingManagerTest { .WillOnce(SaveArg<1>(&advertiser_id_)); le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector adv_opcodes = { OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER, @@ -334,7 +346,14 @@ class LeAndroidHciAdvertisingAPITest : public LeAndroidHciAdvertisingManagerTest .WillOnce(SaveArg<1>(&advertiser_id_)); le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector sub_ocf = { SubOcf::SET_PARAM, @@ -385,7 +404,14 @@ class LeAndroidHciAdvertisingAPIPublicAddressTest : public LeAndroidHciAdvertisi .WillOnce(SaveArg<1>(&advertiser_id_)); le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector sub_ocf = { SubOcf::SET_PARAM, @@ -445,7 +471,14 @@ class LeExtendedAdvertisingAPITest : public LeExtendedAdvertisingManagerTest { .WillOnce(SaveArg<1>(&advertiser_id_)); le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector adv_opcodes = { OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, @@ -495,7 +528,14 @@ TEST_F(LeAdvertisingManagerTest, create_advertiser_test) { advertising_config.channel_map = 1; le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector adv_opcodes = { OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER, OpCode::LE_SET_ADVERTISING_PARAMETERS, @@ -552,7 +592,14 @@ TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { .WillOnce(SaveArg<1>(&id)); le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector sub_ocf = { SubOcf::SET_PARAM, @@ -589,7 +636,14 @@ TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_with_rpa_test) { .WillOnce(SaveArg<1>(&id)); le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector sub_ocf = { SubOcf::SET_PARAM, SubOcf::SET_SCAN_RESP, @@ -635,7 +689,14 @@ TEST_F(LeExtendedAdvertisingManagerTest, create_advertiser_test) { .WillOnce(SaveArg<1>(&id)); le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector adv_opcodes = { OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, @@ -664,6 +725,178 @@ TEST_F(LeExtendedAdvertisingManagerTest, create_advertiser_test) { ASSERT_EQ(OpCode::LE_REMOVE_ADVERTISING_SET, test_hci_layer_->GetCommand().GetOpCode()); } +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingManagerTest, + create_advertiser_valid_max_251_ad_data_length_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { + AdvertisingConfig advertising_config{}; + advertising_config.advertising_type = AdvertisingType::ADV_IND; + advertising_config.requested_advertiser_address_type = AdvertiserAddressType::PUBLIC; + std::vector gap_data{}; + // data length 251 + GapData data_item{}; + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[249]; + std::copy_n(service_data, 249, std::back_inserter(data_item.data_)); + gap_data.push_back(data_item); + advertising_config.advertisement = gap_data; + advertising_config.scan_response = gap_data; + advertising_config.channel_map = 1; + advertising_config.sid = 0x01; + + AdvertiserId id; + EXPECT_CALL( + mock_advertising_callback_, + OnAdvertisingSetStarted(0, _, -23, AdvertisingCallback::AdvertisingStatus::SUCCESS)) + .WillOnce(SaveArg<1>(&id)); + + le_advertising_manager_->ExtendedCreateAdvertiser( + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); + + std::vector adv_opcodes = { + OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, + OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA, + OpCode::LE_SET_EXTENDED_ADVERTISING_DATA, + OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, + }; + std::vector success_vector{static_cast(ErrorCode::SUCCESS)}; + for (size_t i = 0; i < adv_opcodes.size(); i++) { + ASSERT_EQ(adv_opcodes[i], test_hci_layer_->GetCommand().GetOpCode()); + if (adv_opcodes[i] == OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS) { + test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingParametersCompleteBuilder::Create( + uint8_t{1}, ErrorCode::SUCCESS, static_cast(-23))); + } else { + test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create( + uint8_t{1}, adv_opcodes[i], std::make_unique(success_vector))); + } + } + sync_client_handler(); + + // Remove the advertiser + ASSERT_NE(LeAdvertisingManager::kInvalidId, id); + le_advertising_manager_->RemoveAdvertiser(id); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + ASSERT_EQ(OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + ASSERT_EQ(OpCode::LE_REMOVE_ADVERTISING_SET, test_hci_layer_->GetCommand().GetOpCode()); +} + +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingManagerTest, + create_advertiser_valid_max_252_ad_data_length_fragments_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { + AdvertisingConfig advertising_config{}; + advertising_config.advertising_type = AdvertisingType::ADV_IND; + advertising_config.requested_advertiser_address_type = AdvertiserAddressType::PUBLIC; + std::vector gap_data{}; + // set data 252 bytes, this should pass and be fragmented into 2 packets + GapData data_item{}; + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[250]; + std::copy_n(service_data, 250, std::back_inserter(data_item.data_)); + gap_data.push_back(data_item); + advertising_config.advertisement = gap_data; + advertising_config.scan_response = gap_data; + advertising_config.channel_map = 1; + advertising_config.sid = 0x01; + + AdvertiserId id; + EXPECT_CALL( + mock_advertising_callback_, + OnAdvertisingSetStarted(0, _, -23, AdvertisingCallback::AdvertisingStatus::SUCCESS)) + .WillOnce(SaveArg<1>(&id)); + + le_advertising_manager_->ExtendedCreateAdvertiser( + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); + + std::vector adv_opcodes = { + OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, + OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA, // 1st fragment + OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA, // 2nd fragment + OpCode::LE_SET_EXTENDED_ADVERTISING_DATA, // 1st fragment + OpCode::LE_SET_EXTENDED_ADVERTISING_DATA, // 2nd fragment + OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, + }; + std::vector success_vector{static_cast(ErrorCode::SUCCESS)}; + for (size_t i = 0; i < adv_opcodes.size(); i++) { + ASSERT_EQ(adv_opcodes[i], test_hci_layer_->GetCommand().GetOpCode()); + if (adv_opcodes[i] == OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS) { + test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingParametersCompleteBuilder::Create( + uint8_t{1}, ErrorCode::SUCCESS, static_cast(-23))); + } else if (adv_opcodes[i] == OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA) { + test_hci_layer_->IncomingEvent( + LeSetExtendedScanResponseDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + } else if (adv_opcodes[i] == OpCode::LE_SET_EXTENDED_ADVERTISING_DATA) { + test_hci_layer_->IncomingEvent( + LeSetExtendedAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + } else { + test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create( + uint8_t{1}, adv_opcodes[i], std::make_unique(success_vector))); + } + } + sync_client_handler(); + + // Remove the advertiser + ASSERT_NE(LeAdvertisingManager::kInvalidId, id); + le_advertising_manager_->RemoveAdvertiser(id); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + ASSERT_EQ(OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + ASSERT_EQ(OpCode::LE_REMOVE_ADVERTISING_SET, test_hci_layer_->GetCommand().GetOpCode()); +} + +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingManagerTest, + create_advertiser_test_invalid_256_ad_data_length_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { + AdvertisingConfig advertising_config{}; + advertising_config.advertising_type = AdvertisingType::ADV_IND; + advertising_config.requested_advertiser_address_type = AdvertiserAddressType::PUBLIC; + std::vector gap_data{}; + + // set data 256 bytes, this should fail with error + GapData data_item{}; + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[254]; + std::copy_n(service_data, 254, std::back_inserter(data_item.data_)); + gap_data.push_back(data_item); + + advertising_config.advertisement = gap_data; + advertising_config.scan_response = gap_data; + advertising_config.channel_map = 1; + advertising_config.sid = 0x01; + + AdvertiserId id; + EXPECT_CALL( + mock_advertising_callback_, + OnAdvertisingSetStarted(0, _, _, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE)) + .WillOnce(SaveArg<1>(&id)); + + le_advertising_manager_->ExtendedCreateAdvertiser( + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); + + sync_client_handler(); +} + TEST_F(LeExtendedAdvertisingManagerTest, ignore_on_pause_on_resume_after_unregistered) { TestLeAddressManager* test_le_address_manager = (TestLeAddressManager*)test_acl_manager_->GetLeAddressManager(); test_le_address_manager->ignore_unregister_for_testing = true; @@ -692,7 +925,14 @@ TEST_F(LeExtendedAdvertisingManagerTest, ignore_on_pause_on_resume_after_unregis .WillOnce(SaveArg<1>(&id)); le_advertising_manager_->ExtendedCreateAdvertiser( - 0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_); + kAdvertiserClientIdJni, + 0x00, + advertising_config, + scan_callback, + set_terminated_callback, + 0, + 0, + client_handler_); std::vector adv_opcodes = { OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, @@ -952,54 +1192,168 @@ TEST_F(LeExtendedAdvertisingAPITest, set_scan_response_fragments_test) { test_hci_layer_->IncomingEvent(LeSetExtendedScanResponseDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } -TEST_F(LeExtendedAdvertisingAPITest, set_data_with_invalid_ad_structure) { - // Set advertising data with AD structure that length greater than 251 +TEST_F(LeExtendedAdvertisingAPITest, set_data_with_invalid_length) { + // Set advertising data with data that greater than le_maximum_advertising_data_length_ + std::vector advertising_data{}; + for (uint8_t i = 0; i < 10; i++) { + GapData data_item{}; + data_item.data_.push_back(0xfb); + data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS; + uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i}; + std::copy_n(uuid, 16, std::back_inserter(data_item.data_)); + uint8_t service_data[200]; + std::copy_n(service_data, 200, std::back_inserter(data_item.data_)); + advertising_data.push_back(data_item); + } + + EXPECT_CALL( + mock_advertising_callback_, + OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE)); + le_advertising_manager_->SetData(advertiser_id_, false, advertising_data); + + EXPECT_CALL( + mock_advertising_callback_, + OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE)); + le_advertising_manager_->SetData(advertiser_id_, true, advertising_data); + + sync_client_handler(); +} + +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingAPITest, + set_data_valid_max_251_ad_data_length_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { + // Set advertising data std::vector advertising_data{}; + // set data 251 bytes GapData data_item{}; - data_item.data_.push_back(0xfb); - data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS; - uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00}; - std::copy_n(uuid, 16, std::back_inserter(data_item.data_)); - uint8_t service_data[233]; - std::copy_n(service_data, 233, std::back_inserter(data_item.data_)); + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[249]; + std::copy_n(service_data, 249, std::back_inserter(data_item.data_)); advertising_data.push_back(data_item); + le_advertising_manager_->SetData(advertiser_id_, false, advertising_data); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_ADVERTISING_DATA, test_hci_layer_->GetCommand().GetOpCode()); EXPECT_CALL( mock_advertising_callback_, - OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR)); + OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetExtendedAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + // Set scan response data + std::vector response_data{}; + // set data 251 bytes + GapData data_item2{}; + data_item2.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + std::copy_n(service_data, 249, std::back_inserter(data_item2.data_)); + response_data.push_back(data_item2); + + le_advertising_manager_->SetData(advertiser_id_, true, response_data); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA, test_hci_layer_->GetCommand().GetOpCode()); + EXPECT_CALL( + mock_advertising_callback_, + OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanResponseDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); +} + +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingAPITest, + set_data_valid_252_ad_data_length_fragments_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { + // Set advertising data + std::vector advertising_data{}; + // set data 252 bytes + GapData data_item{}; + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[250]; + std::copy_n(service_data, 250, std::back_inserter(data_item.data_)); + advertising_data.push_back(data_item); le_advertising_manager_->SetData(advertiser_id_, false, advertising_data); + // First fragment + auto command = test_hci_layer_->GetCommand(); + ASSERT_EQ(command.GetOpCode(), OpCode::LE_SET_EXTENDED_ADVERTISING_DATA); + ASSERT_EQ( + 1ul /* Advertising_Handle */ + 1ul /* Operation */ + 1ul /* Fragment_Preference */ + + 1ul /*Advertising_Data_Length*/ + + 251ul /* Max data length 251 includes AD length and type */, + command.GetPayload().size()); + // Second fragment + auto command2 = test_hci_layer_->GetCommand(); + ASSERT_EQ(command2.GetOpCode(), OpCode::LE_SET_EXTENDED_ADVERTISING_DATA); + ASSERT_EQ( + 1ul /* Advertising_Handle */ + 1ul /* Operation */ + 1ul /* Fragment_Preference */ + + 1ul /*Advertising_Data_Length*/ + 1ul /* Remaining 1 byte data */, + command2.GetPayload().size()); + EXPECT_CALL( mock_advertising_callback_, - OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR)); - le_advertising_manager_->SetData(advertiser_id_, true, advertising_data); + OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetExtendedAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetExtendedAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); - sync_client_handler(); + // Set scan response data + std::vector response_data{}; + // set data 252 bytes, this should pass and be fragmented into 2 packets + GapData data_item2{}; + data_item2.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + std::copy_n(service_data, 250, std::back_inserter(data_item2.data_)); + response_data.push_back(data_item2); + + le_advertising_manager_->SetData(advertiser_id_, true, response_data); + + // First fragment + command = test_hci_layer_->GetCommand(); + ASSERT_EQ(command.GetOpCode(), OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA); + ASSERT_EQ( + 1ul /* Advertising_Handle */ + 1ul /* Operation */ + 1ul /* Fragment_Preference */ + + 1ul /*Advertising_Data_Length*/ + + 251ul /* Max data length 251 includes AD length and type */, + command.GetPayload().size()); + // Second fragment + command2 = test_hci_layer_->GetCommand(); + ASSERT_EQ(command2.GetOpCode(), OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA); + ASSERT_EQ( + 1ul /* Advertising_Handle */ + 1ul /* Operation */ + 1ul /* Fragment_Preference */ + + 1ul /*Advertising_Data_Length*/ + 1ul /* Remaining 1 byte data */, + command2.GetPayload().size()); + + EXPECT_CALL( + mock_advertising_callback_, + OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanResponseDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanResponseDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } -TEST_F(LeExtendedAdvertisingAPITest, set_data_with_invalid_length) { +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingAPITest, + set_data_with_invalid_256_ad_data_length_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { // Set advertising data with data that greater than le_maximum_advertising_data_length_ std::vector advertising_data{}; - for (uint8_t i = 0; i < 10; i++) { - GapData data_item{}; - data_item.data_.push_back(0xfb); - data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS; - uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i}; - std::copy_n(uuid, 16, std::back_inserter(data_item.data_)); - uint8_t service_data[200]; - std::copy_n(service_data, 200, std::back_inserter(data_item.data_)); - advertising_data.push_back(data_item); - } + + // set data 256 bytes, this should fail with error + GapData data_item{}; + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[254]; + std::copy_n(service_data, 254, std::back_inserter(data_item.data_)); + advertising_data.push_back(data_item); EXPECT_CALL( mock_advertising_callback_, - OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE)); + OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR)); le_advertising_manager_->SetData(advertiser_id_, false, advertising_data); EXPECT_CALL( mock_advertising_callback_, - OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE)); + OnScanResponseDataSet( + advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR)); le_advertising_manager_->SetData(advertiser_id_, true, advertising_data); sync_client_handler(); @@ -1172,23 +1526,94 @@ TEST_F(LeExtendedAdvertisingAPITest, set_periodic_data_fragments_test) { test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); } -TEST_F(LeExtendedAdvertisingAPITest, set_perodic_data_with_invalid_ad_structure) { - // Set advertising data with AD structure that length greater than 251 +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingAPITest, + set_periodic_data_valid_max_252_ad_data_length_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { + // Set advertising data std::vector advertising_data{}; + + // set data 252 bytes, this should pass and be sent in 1 packet GapData data_item{}; - data_item.data_.push_back(0xfb); - data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS; - uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00}; - std::copy_n(uuid, 16, std::back_inserter(data_item.data_)); - uint8_t service_data[233]; - std::copy_n(service_data, 233, std::back_inserter(data_item.data_)); + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[250]; + std::copy_n(service_data, 250, std::back_inserter(data_item.data_)); advertising_data.push_back(data_item); + le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data); + + ASSERT_EQ(OpCode::LE_SET_PERIODIC_ADVERTISING_DATA, test_hci_layer_->GetCommand().GetOpCode()); + EXPECT_CALL( + mock_advertising_callback_, + OnPeriodicAdvertisingDataSet( + advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + sync_client_handler(); +} + +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingAPITest, + set_periodic_data_valid_253_ad_data_length_fragments_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { + // Set advertising data + std::vector advertising_data{}; + + // set data 253 bytes, this should pass and be fragmented into 2 packets + GapData data_item{}; + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[251]; + std::copy_n(service_data, 251, std::back_inserter(data_item.data_)); + advertising_data.push_back(data_item); + + le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data); + + // First fragment + auto command = test_hci_layer_->GetCommand(); + ASSERT_EQ(command.GetOpCode(), OpCode::LE_SET_PERIODIC_ADVERTISING_DATA); + ASSERT_EQ( + 1ul /* Advertising_Handle */ + 1ul /* Operation */ + 1ul /*Advertising_Data_Length*/ + + 252ul /* Max data length 252 includes AD length and type */, + command.GetPayload().size()); + // Second fragment + auto command2 = test_hci_layer_->GetCommand(); + ASSERT_EQ(command2.GetOpCode(), OpCode::LE_SET_PERIODIC_ADVERTISING_DATA); + ASSERT_EQ( + 1ul /* Advertising_Handle */ + 1ul /* Operation */ + 1ul /*Advertising_Data_Length*/ + + 1ul /* Remaining 1 byte data */, + command2.GetPayload().size()); + EXPECT_CALL( mock_advertising_callback_, - OnPeriodicAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR)); + OnPeriodicAdvertisingDataSet( + advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); +} + +TEST_F_WITH_FLAGS( + LeExtendedAdvertisingAPITest, + set_periodic_data_invalid_256_ad_data_length_test, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, divide_long_single_gap_data))) { + // Set advertising data + std::vector advertising_data{}; + + // set data 256 bytes, this should fail with error + GapData data_item{}; + data_item.data_type_ = GapDataType::MANUFACTURER_SPECIFIC_DATA; + uint8_t service_data[254]; + std::copy_n(service_data, 254, std::back_inserter(data_item.data_)); + advertising_data.push_back(data_item); + EXPECT_CALL( + mock_advertising_callback_, + OnPeriodicAdvertisingDataSet( + advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR)); le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data); + + sync_client_handler(); } TEST_F(LeExtendedAdvertisingAPITest, set_perodic_data_with_invalid_length) { @@ -1239,7 +1664,9 @@ TEST_F(LeExtendedAdvertisingAPITest, trigger_advertiser_callbacks_if_started_whi auto id_promise = std::promise{}; auto id_future = id_promise.get_future(); le_advertising_manager_->RegisterAdvertiser(client_handler_->BindOnce( - [](std::promise promise, uint8_t id, uint8_t _status) { promise.set_value(id); }, + [](std::promise promise, uint8_t id, uint8_t /* _status */) { + promise.set_value(id); + }, std::move(id_promise))); sync_client_handler(); auto set_id = id_future.get(); @@ -1259,11 +1686,13 @@ TEST_F(LeExtendedAdvertisingAPITest, trigger_advertiser_callbacks_if_started_whi {}, 0, base::BindOnce( - [](std::promise promise, uint8_t status) { promise.set_value((ErrorCode)status); }, + [](std::promise promise, uint8_t status) { + promise.set_value((ErrorCode)status); + }, std::move(status_promise)), - base::Bind([](uint8_t _status) {}), - base::Bind([](Address _address, AddressType _address_type) {}), - base::Bind([](ErrorCode _status, uint8_t _unused_1, uint8_t _unused_2) {}), + base::Bind([](uint8_t /* _status */) {}), + base::Bind([](Address /* _address */, AddressType /* _address_type */) {}), + base::Bind([](ErrorCode /* _status */, uint8_t /* _unused_1 */, uint8_t /* _unused_2 */) {}), client_handler_); test_hci_layer_->GetCommand(); @@ -1288,6 +1717,47 @@ TEST_F(LeExtendedAdvertisingAPITest, trigger_advertiser_callbacks_if_started_whi sync_client_handler(); } +TEST_F(LeExtendedAdvertisingAPITest, duration_maxevents_restored_on_resume) { + // arrange + auto test_le_address_manager = (TestLeAddressManager*)test_acl_manager_->GetLeAddressManager(); + uint16_t duration = 1000; + uint8_t max_extended_advertising_events = 100; + + // enable advertiser + le_advertising_manager_->EnableAdvertiser( + advertiser_id_, true, duration, max_extended_advertising_events); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + EXPECT_CALL( + mock_advertising_callback_, + OnAdvertisingEnabled(advertiser_id_, true, AdvertisingCallback::AdvertisingStatus::SUCCESS)); + test_hci_layer_->IncomingEvent( + LeSetExtendedAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + test_le_address_manager->client_->OnPause(); + // verify advertising is disabled onPause + ASSERT_EQ(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedAdvertisingEnableCompleteBuilder::Create(1, ErrorCode::SUCCESS)); + sync_client_handler(); + + test_le_address_manager->client_->OnResume(); + // verify advertising is reenabled onResume with correct parameters + auto command = test_hci_layer_->GetCommand(); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, command.GetOpCode()); + auto enable_command_view = + LeSetExtendedAdvertisingEnableView::Create(LeAdvertisingCommandView::Create(command)); + ASSERT_TRUE(enable_command_view.IsValid()); + ASSERT_EQ(bluetooth::hci::Enable::ENABLED, enable_command_view.GetEnable()); + auto enabled_sets = enable_command_view.GetEnabledSets(); + ASSERT_EQ(static_cast(1), enabled_sets.size()); + ASSERT_EQ(duration, enabled_sets[0].duration_); + ASSERT_EQ(max_extended_advertising_events, enabled_sets[0].max_extended_advertising_events_); + test_hci_layer_->IncomingEvent( + LeSetExtendedAdvertisingEnableCompleteBuilder::Create(1, ErrorCode::SUCCESS)); + + sync_client_handler(); +} + TEST_F(LeExtendedAdvertisingAPITest, no_callbacks_on_pause) { // arrange auto test_le_address_manager = (TestLeAddressManager*)test_acl_manager_->GetLeAddressManager(); @@ -1332,6 +1802,7 @@ TEST_F(LeExtendedAdvertisingManagerTest, use_rpa) { // act: start advertising set with RPA le_advertising_manager_->ExtendedCreateAdvertiser( + kAdvertiserClientIdJni, 0x00, AdvertisingConfig{ .requested_advertiser_address_type = AdvertiserAddressType::RESOLVABLE_RANDOM, @@ -1359,6 +1830,7 @@ TEST_F(LeExtendedAdvertisingManagerTest, use_non_resolvable_address) { // start advertising set with NRPA le_advertising_manager_->ExtendedCreateAdvertiser( + kAdvertiserClientIdJni, 0x00, AdvertisingConfig{ .requested_advertiser_address_type = AdvertiserAddressType::NONRESOLVABLE_RANDOM, @@ -1395,6 +1867,7 @@ TEST_F(LeExtendedAdvertisingManagerTest, use_public_address_type_if_public_addre // act: start advertising set with RPA le_advertising_manager_->ExtendedCreateAdvertiser( + kAdvertiserClientIdJni, 0x00, AdvertisingConfig{ .requested_advertiser_address_type = AdvertiserAddressType::RESOLVABLE_RANDOM, diff --git a/system/gd/hci/le_periodic_sync_manager.h b/system/gd/hci/le_periodic_sync_manager.h index 9cd92cda7ee4602112c45106a94312ee0255c940..9036597ac5fc861815da0ccecfab82fb3fc8e2d7 100644 --- a/system/gd/hci/le_periodic_sync_manager.h +++ b/system/gd/hci/le_periodic_sync_manager.h @@ -22,6 +22,7 @@ #include "common/callback.h" #include "common/init_flags.h" #include "hci/address_with_type.h" +#include "hci/event_checkers.h" #include "hci/hci_packets.h" #include "hci/le_scanning_callback.h" #include "hci/le_scanning_interface.h" @@ -118,14 +119,13 @@ class PeriodicSyncManager { LOG_ERROR("[PSync]: invalid index for handle %u", handle); le_scanning_interface_->EnqueueCommand( hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(handle), - handler_->BindOnceOn( - this, &PeriodicSyncManager::check_status)); + handler_->BindOnce(check_complete)); return; }; periodic_syncs_.erase(periodic_sync); le_scanning_interface_->EnqueueCommand( hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(handle), - handler_->BindOnceOn(this, &PeriodicSyncManager::check_status)); + handler_->BindOnce(check_complete)); } void CancelCreateSync(uint8_t adv_sid, Address address) { @@ -185,7 +185,8 @@ class PeriodicSyncManager { connection_handle)); } - void SyncTxParameters(const Address& address, uint8_t mode, uint16_t skip, uint16_t timeout, int reg_id) { + void SyncTxParameters( + const Address& /* address */, uint8_t mode, uint16_t skip, uint16_t timeout, int reg_id) { LOG_DEBUG("[PAST]: mode=%u, skip=%u, timeout=%u", mode, skip, timeout); auto sync_cte_type = static_cast( static_cast(PeriodicSyncCteType::AVOID_AOA_CONSTANT_TONE_EXTENSION) | @@ -197,9 +198,8 @@ class PeriodicSyncManager { le_scanning_interface_->EnqueueCommand( hci::LeSetDefaultPeriodicAdvertisingSyncTransferParametersBuilder::Create( static_cast(mode), skip, timeout, sync_cte_type), - handler_->BindOnceOn( - this, - &PeriodicSyncManager::check_status)); + handler_->BindOnce( + check_complete)); } void HandlePeriodicAdvertisingCreateSyncStatus(CommandStatusView) {} @@ -236,24 +236,6 @@ class PeriodicSyncManager { periodic_sync_transfers_.erase(periodic_sync_transfer); } - template - void check_status(CommandCompleteView view) { - ASSERT(view.IsValid()); - auto status_view = View::Create(view); - ASSERT(status_view.IsValid()); - if (status_view.GetStatus() != ErrorCode::SUCCESS) { - LOG_WARN( - "Got a Command complete %s, status %s", - OpCodeText(view.GetCommandOpCode()).c_str(), - ErrorCodeText(status_view.GetStatus()).c_str()); - } else { - LOG_DEBUG( - "Got a Command complete %s, status %s", - OpCodeText(view.GetCommandOpCode()).c_str(), - ErrorCodeText(status_view.GetStatus()).c_str()); - } - } - void HandleLePeriodicAdvertisingSyncEstablished(LePeriodicAdvertisingSyncEstablishedView event_view) { ASSERT(event_view.IsValid()); LOG_DEBUG( @@ -295,8 +277,7 @@ class PeriodicSyncManager { LOG_WARN("Terminate sync"); le_scanning_interface_->EnqueueCommand( hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(event_view.GetSyncHandle()), - handler_->BindOnceOn( - this, &PeriodicSyncManager::check_status)); + handler_->BindOnce(check_complete)); } AdvanceRequest(); return; @@ -347,6 +328,10 @@ class PeriodicSyncManager { LOG_DEBUG("[PSync]: sync_handle = %d", sync_handle); callbacks_->OnPeriodicSyncLost(sync_handle); auto periodic_sync = GetEstablishedSyncFromHandle(sync_handle); + if (periodic_sync == periodic_syncs_.end()) { + LOG_ERROR("[PSync]: index not found for handle %u", sync_handle); + return; + } periodic_syncs_.erase(periodic_sync); } diff --git a/system/gd/hci/le_rand_callback.h b/system/gd/hci/le_rand_callback.h index 60222e9fe3aacc465a596179cc186f7b60b0fd1c..da55c948a3ee991464df07276cd853a79ea9913c 100644 --- a/system/gd/hci/le_rand_callback.h +++ b/system/gd/hci/le_rand_callback.h @@ -21,7 +21,7 @@ namespace bluetooth { namespace hci { -using LeRandCallback = common::Callback; +using LeRandCallback = common::OnceCallback; } // namespace hci } // namespace bluetooth diff --git a/system/gd/hci/le_scanning_manager.cc b/system/gd/hci/le_scanning_manager.cc index 128a9e55cd8bba391c778afb72bb20d5dc8c5c96..a075c38b797167b1fd991197d2464851454552b3 100644 --- a/system/gd/hci/le_scanning_manager.cc +++ b/system/gd/hci/le_scanning_manager.cc @@ -20,6 +20,7 @@ #include "hci/acl_manager.h" #include "hci/controller.h" +#include "hci/event_checkers.h" #include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "hci/le_periodic_sync_manager.h" @@ -74,69 +75,85 @@ struct Scanner { }; class NullScanningCallback : public ScanningCallback { - void OnScannerRegistered(const Uuid app_uuid, ScannerId scanner_id, ScanningStatus status) override { + void OnScannerRegistered( + const Uuid /* app_uuid */, ScannerId /* scanner_id */, ScanningStatus /* status */) override { LOG_INFO("OnScannerRegistered in NullScanningCallback"); } - void OnSetScannerParameterComplete(ScannerId scanner_id, ScanningStatus status) override { + void OnSetScannerParameterComplete( + ScannerId /* scanner_id */, ScanningStatus /* status */) override { LOG_INFO("OnSetScannerParameterComplete in NullScanningCallback"); } void OnScanResult( - uint16_t event_type, - uint8_t address_type, - Address address, - uint8_t primary_phy, - uint8_t secondary_phy, - uint8_t advertising_sid, - int8_t tx_power, - int8_t rssi, - uint16_t periodic_advertising_interval, - std::vector advertising_data) override { + uint16_t /* event_type */, + uint8_t /* address_type */, + Address /* address */, + uint8_t /* primary_phy */, + uint8_t /* secondary_phy */, + uint8_t /* advertising_sid */, + int8_t /* tx_power */, + int8_t /* rssi */, + uint16_t /* periodic_advertising_interval */, + std::vector /* advertising_data */) override { LOG_INFO("OnScanResult in NullScanningCallback"); } - void OnTrackAdvFoundLost(AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info) override { + void OnTrackAdvFoundLost( + AdvertisingFilterOnFoundOnLostInfo /* on_found_on_lost_info */) override { LOG_INFO("OnTrackAdvFoundLost in NullScanningCallback"); } void OnBatchScanReports( - int client_if, int status, int report_format, int num_records, std::vector data) override { + int /* client_if */, + int /* status */, + int /* report_format */, + int /* num_records */, + std::vector /* data */) override { LOG_INFO("OnBatchScanReports in NullScanningCallback"); } - void OnBatchScanThresholdCrossed(int client_if) override { + void OnBatchScanThresholdCrossed(int /* client_if */) override { LOG_INFO("OnBatchScanThresholdCrossed in NullScanningCallback"); } void OnTimeout() override { LOG_INFO("OnTimeout in NullScanningCallback"); } - void OnFilterEnable(Enable enable, uint8_t status) override { + void OnFilterEnable(Enable /* enable */, uint8_t /* status */) override { LOG_INFO("OnFilterEnable in NullScanningCallback"); } - void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status) override { + void OnFilterParamSetup( + uint8_t /* available_spaces */, ApcfAction /* action */, uint8_t /* status */) override { LOG_INFO("OnFilterParamSetup in NullScanningCallback"); } void OnFilterConfigCallback( - ApcfFilterType filter_type, uint8_t available_spaces, ApcfAction action, uint8_t status) override { + ApcfFilterType /* filter_type */, + uint8_t /* available_spaces */, + ApcfAction /* action */, + uint8_t /* status */) override { LOG_INFO("OnFilterConfigCallback in NullScanningCallback"); } void OnPeriodicSyncStarted( - int reg_id, - uint8_t status, - uint16_t sync_handle, - uint8_t advertising_sid, - AddressWithType address_with_type, - uint8_t phy, - uint16_t interval) override { + int /* reg_id */, + uint8_t /* status */, + uint16_t /* sync_handle */, + uint8_t /* advertising_sid */, + AddressWithType /* address_with_type */, + uint8_t /* phy */, + uint16_t /* interval */) override { LOG_INFO("OnPeriodicSyncStarted in NullScanningCallback"); }; void OnPeriodicSyncReport( - uint16_t sync_handle, int8_t tx_power, int8_t rssi, uint8_t status, std::vector data) override { + uint16_t /* sync_handle */, + int8_t /* tx_power */, + int8_t /* rssi */, + uint8_t /* status */, + std::vector /* data */) override { LOG_INFO("OnPeriodicSyncReport in NullScanningCallback"); }; - void OnPeriodicSyncLost(uint16_t sync_handle) override { + void OnPeriodicSyncLost(uint16_t /* sync_handle */) override { LOG_INFO("OnPeriodicSyncLost in NullScanningCallback"); }; - void OnPeriodicSyncTransferred(int pa_source, uint8_t status, Address address) override { + void OnPeriodicSyncTransferred( + int /* pa_source */, uint8_t /* status */, Address /* address */) override { LOG_INFO("OnPeriodicSyncTransferred in NullScanningCallback"); }; - void OnBigInfoReport(uint16_t sync_handle, bool encrypted) { + void OnBigInfoReport(uint16_t /* sync_handle */, bool /* encrypted */) { LOG_INFO("OnBigInfoReport in NullScanningCallback"); }; }; @@ -546,6 +563,8 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { } void scan(bool start) { + // On-resume flag should always be reset if there is an explicit start/stop call. + scan_on_resume_ = false; if (start) { configure_scan(); start_scan(); @@ -576,13 +595,14 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { le_scanning_interface_->EnqueueCommand( LeSetExtendedScanEnableBuilder::Create( Enable::ENABLED, FilterDuplicates::DISABLED /* filter duplicates */, 0, 0), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); break; case ScanApiType::ANDROID_HCI: case ScanApiType::LEGACY: le_scanning_interface_->EnqueueCommand( - LeSetScanEnableBuilder::Create(Enable::ENABLED, Enable::DISABLED /* filter duplicates */), - module_handler_->BindOnce(impl::check_status)); + LeSetScanEnableBuilder::Create( + Enable::ENABLED, Enable::DISABLED /* filter duplicates */), + module_handler_->BindOnce(check_complete)); break; } } @@ -599,13 +619,14 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { le_scanning_interface_->EnqueueCommand( LeSetExtendedScanEnableBuilder::Create( Enable::DISABLED, FilterDuplicates::DISABLED /* filter duplicates */, 0, 0), - module_handler_->BindOnce(impl::check_status)); + module_handler_->BindOnce(check_complete)); break; case ScanApiType::ANDROID_HCI: case ScanApiType::LEGACY: le_scanning_interface_->EnqueueCommand( - LeSetScanEnableBuilder::Create(Enable::DISABLED, Enable::DISABLED /* filter duplicates */), - module_handler_->BindOnce(impl::check_status)); + LeSetScanEnableBuilder::Create( + Enable::DISABLED, Enable::DISABLED /* filter duplicates */), + module_handler_->BindOnce(check_complete)); break; } } @@ -874,7 +895,7 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { combined_data.push_back((uint8_t)data); combined_data.push_back((uint8_t)(data >> 8)); } else if (uuid_len == Uuid::kNumBytes32) { - uint16_t data = uuid.As32Bit(); + uint32_t data = uuid.As32Bit(); combined_data.push_back((uint8_t)data); combined_data.push_back((uint8_t)(data >> 8)); combined_data.push_back((uint8_t)(data >> 16)); @@ -893,7 +914,7 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { combined_data.push_back((uint8_t)data); combined_data.push_back((uint8_t)(data >> 8)); } else if (uuid_len == Uuid::kNumBytes32) { - uint16_t data = uuid_mask.As32Bit(); + uint32_t data = uuid_mask.As32Bit(); combined_data.push_back((uint8_t)data); combined_data.push_back((uint8_t)(data >> 8)); combined_data.push_back((uint8_t)(data >> 16)); @@ -1256,14 +1277,18 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { periodic_sync_manager_.CancelCreateSync(sid, address); } - void transfer_sync(const Address& address, uint16_t service_data, uint16_t sync_handle, int pa_source) { + void transfer_sync( + const Address& address, + uint16_t connection_handle, + uint16_t service_data, + uint16_t sync_handle, + int pa_source) { if (!is_periodic_advertising_sync_transfer_sender_supported_) { LOG_WARN("PAST sender not supported on this device"); int status = static_cast(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); return; } - uint16_t connection_handle = acl_manager_->HACK_GetLeHandle(address); if (connection_handle == 0xFFFF) { LOG_ERROR("[PAST]: Invalid connection handle or no LE ACL link"); int status = static_cast(ErrorCode::UNKNOWN_CONNECTION); @@ -1273,14 +1298,18 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { periodic_sync_manager_.TransferSync(address, service_data, sync_handle, pa_source, connection_handle); } - void transfer_set_info(const Address& address, uint16_t service_data, uint8_t adv_handle, int pa_source) { + void transfer_set_info( + const Address& address, + uint16_t connection_handle, + uint16_t service_data, + uint8_t adv_handle, + int pa_source) { if (!is_periodic_advertising_sync_transfer_sender_supported_) { LOG_WARN("PAST sender not supported on this device"); int status = static_cast(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); return; } - uint16_t connection_handle = acl_manager_->HACK_GetLeHandle(address); if (connection_handle == 0xFFFF) { LOG_ERROR("[PAST]:Invalid connection handle or no LE ACL link"); int status = static_cast(ErrorCode::UNKNOWN_CONNECTION); @@ -1551,7 +1580,7 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { } } - void on_storage_threshold_breach(VendorSpecificEventView event) { + void on_storage_threshold_breach(VendorSpecificEventView /* event */) { if (batch_scan_config_.ref_value == kInvalidScannerId) { LOG_WARN("storage threshold was not set !!"); return; @@ -1614,6 +1643,7 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { } paused_ = false; if (scan_on_resume_ == true) { + scan_on_resume_ = false; start_scan(); } le_address_manager_->AckResume(this); @@ -1655,29 +1685,6 @@ struct LeScanningManager::impl : public LeAddressManagerCallback { std::unordered_map tracker_id_map_; uint16_t total_num_of_advt_tracked_ = 0x00; int8_t le_rx_path_loss_comp_ = 0; - - static void check_status(CommandCompleteView view) { - switch (view.GetCommandOpCode()) { - case (OpCode::LE_SET_SCAN_ENABLE): { - auto status_view = LeSetScanEnableCompleteView::Create(view); - ASSERT(status_view.IsValid()); - ASSERT_LOG( - status_view.GetStatus() == ErrorCode::SUCCESS, - "Receive set scan enable with error code %s", - ErrorCodeText(status_view.GetStatus()).c_str()); - } break; - case (OpCode::LE_SET_EXTENDED_SCAN_ENABLE): { - auto status_view = LeSetExtendedScanEnableCompleteView::Create(view); - ASSERT(status_view.IsValid()); - ASSERT_LOG( - status_view.GetStatus() == ErrorCode::SUCCESS, - "Receive set extended scan enable with error code %s", - ErrorCodeText(status_view.GetStatus()).c_str()); - } break; - default: - LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str()); - } - } }; LeScanningManager::LeScanningManager() { @@ -1796,13 +1803,22 @@ void LeScanningManager::CancelCreateSync(uint8_t sid, const Address& address) { } void LeScanningManager::TransferSync( - const Address& address, uint16_t service_data, uint16_t sync_handle, int pa_source) { - CallOn(pimpl_.get(), &impl::transfer_sync, address, service_data, sync_handle, pa_source); + const Address& address, + uint16_t handle, + uint16_t service_data, + uint16_t sync_handle, + int pa_source) { + CallOn(pimpl_.get(), &impl::transfer_sync, address, handle, service_data, sync_handle, pa_source); } void LeScanningManager::TransferSetInfo( - const Address& address, uint16_t service_data, uint8_t adv_handle, int pa_source) { - CallOn(pimpl_.get(), &impl::transfer_set_info, address, service_data, adv_handle, pa_source); + const Address& address, + uint16_t handle, + uint16_t service_data, + uint8_t adv_handle, + int pa_source) { + CallOn( + pimpl_.get(), &impl::transfer_set_info, address, handle, service_data, adv_handle, pa_source); } void LeScanningManager::SyncTxParameters( diff --git a/system/gd/hci/le_scanning_manager.h b/system/gd/hci/le_scanning_manager.h index c9691896de171e5fafe92187f44883ca2fd2341a..526728fc0e2a0fba9c8424b884d8b6e490191db4 100644 --- a/system/gd/hci/le_scanning_manager.h +++ b/system/gd/hci/le_scanning_manager.h @@ -84,9 +84,19 @@ class LeScanningManager : public bluetooth::Module { virtual void CancelCreateSync(uint8_t sid, const Address& address); - virtual void TransferSync(const Address& address, uint16_t service_data, uint16_t sync_handle, int pa_source); - - virtual void TransferSetInfo(const Address& address, uint16_t service_data, uint8_t adv_handle, int pa_source); + virtual void TransferSync( + const Address& address, + uint16_t handle, + uint16_t service_data, + uint16_t sync_handle, + int pa_source); + + virtual void TransferSetInfo( + const Address& address, + uint16_t handle, + uint16_t service_data, + uint8_t adv_handle, + int pa_source); virtual void SyncTxParameters(const Address& addr, uint8_t mode, uint16_t skip, uint16_t timeout, int reg_id); diff --git a/system/gd/hci/le_scanning_manager_mock.h b/system/gd/hci/le_scanning_manager_mock.h index a8890764ca57c41d9841fdd9b2489aae781a7cb7..7dce736f1dc805645a372f08d5bfbe27f87a4ce6 100644 --- a/system/gd/hci/le_scanning_manager_mock.h +++ b/system/gd/hci/le_scanning_manager_mock.h @@ -65,8 +65,18 @@ class MockLeScanningManager : public LeScanningManager { MOCK_METHOD(void, StartSync, (uint8_t, const AddressWithType&, uint16_t, uint16_t, int)); MOCK_METHOD(void, StopSync, (uint16_t)); MOCK_METHOD(void, CancelCreateSync, (uint8_t, const Address&)); - MOCK_METHOD(void, TransferSync, (const Address&, uint16_t, uint16_t sync_handle, int pa_source)); - MOCK_METHOD(void, TransferSetInfo, (const Address&, uint16_t, uint8_t, int)); + MOCK_METHOD( + void, + TransferSync, + (const Address&, + uint16_t connection_handle, + uint16_t service_data, + uint16_t sync_handle, + int pa_source)); + MOCK_METHOD( + void, + TransferSetInfo, + (const Address&, uint16_t connection_handle, uint16_t service_data, uint8_t, int)); MOCK_METHOD(void, SyncTxParameters, (const Address&, uint8_t, uint16_t, uint16_t, int)); }; diff --git a/system/gd/hci/le_scanning_manager_test.cc b/system/gd/hci/le_scanning_manager_test.cc index cab04ac15a00f45ad3b7ffc5fffaa45d182e1432..41539ee8c080591328de49b1c221c79873d4a1ab 100644 --- a/system/gd/hci/le_scanning_manager_test.cc +++ b/system/gd/hci/le_scanning_manager_test.cc @@ -135,14 +135,23 @@ class TestController : public Controller { support_ble_extended_advertising_ = support; } + bool SupportsBlePeriodicAdvertisingSyncTransferSender() const override { + return support_ble_periodic_advertising_sync_transfer_; + } + + void SetBlePeriodicAdvertisingSyncTransferSenderSupport(bool support) { + support_ble_periodic_advertising_sync_transfer_ = support; + } + protected: void Start() override {} void Stop() override {} - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} private: std::set supported_opcodes_{}; bool support_ble_extended_advertising_ = false; + bool support_ble_periodic_advertising_sync_transfer_ = false; }; class TestLeAddressManager : public LeAddressManager { @@ -161,18 +170,18 @@ class TestLeAddressManager : public LeAddressManager { return AddressPolicy::USE_STATIC_ADDRESS; } - void Unregister(LeAddressManagerCallback* callback) override { + void Unregister(LeAddressManagerCallback* /* callback */) override { if (!ignore_unregister_for_testing) { client_ = nullptr; } test_client_state_ = UNREGISTERED; } - void AckPause(LeAddressManagerCallback* callback) override { + void AckPause(LeAddressManagerCallback* /* callback */) override { test_client_state_ = PAUSED; } - void AckResume(LeAddressManagerCallback* callback) override { + void AckResume(LeAddressManagerCallback* /* callback */) override { test_client_state_ = RESUMED; } @@ -208,11 +217,11 @@ class TestAclManager : public AclManager { delete thread_; } - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} - void SetRandomAddress(Address address) {} + void SetRandomAddress(Address /* address */) {} - void enqueue_command(std::unique_ptr command_packet){}; + void enqueue_command(std::unique_ptr /* command_packet */){}; private: os::Thread* thread_; @@ -319,6 +328,7 @@ class LeScanningManagerAndroidHciTest : public LeScanningManagerTest { test_controller_->AddSupported(OpCode::LE_EXTENDED_SCAN_PARAMS); test_controller_->AddSupported(OpCode::LE_ADV_FILTER); test_controller_->AddSupported(OpCode::LE_BATCH_SCAN); + test_controller_->SetBlePeriodicAdvertisingSyncTransferSenderSupport(true); start_le_scanning_manager(); ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory)); @@ -579,6 +589,72 @@ TEST_F(LeScanningManagerAndroidHciTest, read_batch_scan_result) { uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 0, {})); } +TEST_F(LeScanningManagerAndroidHciTest, start_sync_test) { + Address address; + const uint16_t handle = 0x0001; + const uint16_t service_data = 0x0000; + const uint16_t sync_handle = 0x0002; + const int pa_source = 3; + + Address::FromString("12:34:56:78:9a:bc", address); + + le_scanning_manager->TransferSync(address, handle, service_data, sync_handle, pa_source); + sync_client_handler(); + + ASSERT_EQ( + OpCode::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER, test_hci_layer_->GetCommand().GetOpCode()); +} + +TEST_F(LeScanningManagerAndroidHciTest, start_sync_invalid_handle_test) { + Address address; + const uint16_t handle = 0xFFFF; + const uint16_t service_data = 0x0000; + const uint16_t sync_handle = 0x0002; + const int pa_source = 3; + + Address::FromString("12:34:56:78:9a:bc", address); + + EXPECT_CALL( + mock_callbacks_, + OnPeriodicSyncTransferred( + pa_source, static_cast(ErrorCode::UNKNOWN_CONNECTION), address)); + le_scanning_manager->TransferSync(address, handle, service_data, sync_handle, pa_source); + sync_client_handler(); +} + +TEST_F(LeScanningManagerAndroidHciTest, set_info_test) { + Address address; + const uint16_t handle = 0x0001; + const uint16_t service_data = 0x0000; + const uint16_t sync_handle = 0x0002; + const int pa_source = 3; + + Address::FromString("12:34:56:78:9a:bc", address); + + le_scanning_manager->TransferSetInfo(address, handle, service_data, sync_handle, pa_source); + sync_client_handler(); + + ASSERT_EQ( + OpCode::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER, test_hci_layer_->GetCommand().GetOpCode()); +} + +TEST_F(LeScanningManagerAndroidHciTest, set_info_invalid_handle_test) { + Address address; + const uint16_t handle = 0xFFFF; + const uint16_t service_data = 0x0000; + const uint16_t sync_handle = 0x0002; + const int pa_source = 3; + + Address::FromString("12:34:56:78:9a:bc", address); + + EXPECT_CALL( + mock_callbacks_, + OnPeriodicSyncTransferred( + pa_source, static_cast(ErrorCode::UNKNOWN_CONNECTION), address)); + le_scanning_manager->TransferSetInfo(address, handle, service_data, sync_handle, pa_source); + sync_client_handler(); +} + TEST_F(LeScanningManagerExtendedTest, startup_teardown) {} TEST_F(LeScanningManagerExtendedTest, start_scan_test) { @@ -611,6 +687,72 @@ TEST_F(LeScanningManagerExtendedTest, start_scan_test) { test_hci_layer_->IncomingLeMetaEvent(LeExtendedAdvertisingReportBuilder::Create({report})); } +TEST_F(LeScanningManagerExtendedTest, start_scan_on_resume_conflict_test) { + TestLeAddressManager* test_le_address_manager = + (TestLeAddressManager*)test_acl_manager_->GetLeAddressManager(); + + // Enable scan + le_scanning_manager->Scan(true); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + sync_client_handler(); + + // Pause scan + test_le_address_manager->client_->OnPause(); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + // Disable scan + le_scanning_manager->Scan(false); + test_hci_layer_->AssertNoQueuedCommand(); + + // Enable Scan + le_scanning_manager->Scan(true); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + // Ensure there is no double enable commands on resume + test_le_address_manager->client_->OnResume(); + sync_client_handler(); + test_hci_layer_->AssertNoQueuedCommand(); +} + +TEST_F(LeScanningManagerExtendedTest, on_pause_on_resume_test) { + TestLeAddressManager* test_le_address_manager = + (TestLeAddressManager*)test_acl_manager_->GetLeAddressManager(); + + // Enable scan + le_scanning_manager->Scan(true); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + sync_client_handler(); + + // Pause scan + test_le_address_manager->client_->OnPause(); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + // Ensure scan is resumed (enabled) + test_le_address_manager->client_->OnResume(); + ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode()); + test_hci_layer_->IncomingEvent( + LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); +} + TEST_F(LeScanningManagerExtendedTest, ignore_on_pause_on_resume_after_unregistered) { TestLeAddressManager* test_le_address_manager = (TestLeAddressManager*)test_acl_manager_->GetLeAddressManager(); test_le_address_manager->ignore_unregister_for_testing = true; diff --git a/system/gd/hci/msft.cc b/system/gd/hci/msft.cc index e51c7acaef7b4b598b5bee13fdf883fbc8e6caa4..8b27167e15d59643609f94a635c3c6908be578e9 100644 --- a/system/gd/hci/msft.cc +++ b/system/gd/hci/msft.cc @@ -78,7 +78,7 @@ struct MsftExtensionManager::impl { LOG_INFO("MsftExtensionManager stop()"); } - void handle_rssi_event(MsftRssiEventPayloadView view) { + void handle_rssi_event(MsftRssiEventPayloadView /* view */) { LOG_WARN("The Microsoft MSFT_RSSI_EVENT is not supported yet."); } diff --git a/system/gd/hci/octets.h b/system/gd/hci/octets.h new file mode 100644 index 0000000000000000000000000000000000000000..0eba1561c0d1c555147b0c61c077e529e77453b5 --- /dev/null +++ b/system/gd/hci/octets.h @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace bluetooth::hci { + +constexpr int kOctet16Length = 16; +using Octet16 = std::array; + +constexpr int kOctet32Length = 32; +using Octet32 = std::array; +} // namespace bluetooth::hci diff --git a/system/gd/hci/remote_name_request.cc b/system/gd/hci/remote_name_request.cc index bc2fc452c6028a8eee6b8597305795f5da1ac48c..5c5c5c8cc182f1d21403b053c081d1c488d98f06 100644 --- a/system/gd/hci/remote_name_request.cc +++ b/system/gd/hci/remote_name_request.cc @@ -22,7 +22,7 @@ #include #include "hci/acl_manager/acl_scheduler.h" -#include "hci/acl_manager/event_checkers.h" +#include "hci/event_checkers.h" #include "hci/hci_layer.h" namespace bluetooth { @@ -132,7 +132,16 @@ struct RemoteNameRequestModule::impl { void on_start_remote_name_request_status( Address address, CompletionCallback on_completion, CommandStatusView status) { + // TODO(b/294961421): Remove the ifdef when firmware fix in place. Realtek controllers + // unexpectedly sent a Remote Name Req Complete HCI event without the corresponding HCI command. +#ifndef TARGET_FLOSS ASSERT(pending_ == true); +#else + if (pending_ != true) { + LOG_WARN("Unexpected remote name response with no request pending"); + return; + } +#endif ASSERT(status.GetCommandOpCode() == OpCode::REMOTE_NAME_REQUEST); LOG_INFO( "Got status %hhu when starting remote name request to to %s", @@ -150,22 +159,27 @@ struct RemoteNameRequestModule::impl { LOG_INFO("Cancelling remote name request to %s", address.ToRedactedStringForLogging().c_str()); hci_layer_->EnqueueCommand( RemoteNameRequestCancelBuilder::Create(address), - handler_->BindOnce( - &acl_manager::check_command_complete)); + handler_->BindOnce(check_complete)); } void on_remote_host_supported_features_notification(EventView view) { auto packet = RemoteHostSupportedFeaturesNotificationView::Create(view); ASSERT(packet.IsValid()); - if (pending_) { + if (pending_ && !on_remote_host_supported_features_notification_.IsEmpty()) { LOG_INFO( "Received REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION from %s", packet.GetBdAddr().ToRedactedStringForLogging().c_str()); on_remote_host_supported_features_notification_.Invoke(packet.GetHostSupportedFeatures()); - } else { + // Remove the callback so that we won't call it again. + on_remote_host_supported_features_notification_ = RemoteHostSupportedFeaturesCallback(); + } else if (!pending_) { LOG_ERROR( "Received unexpected REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION when no Remote Name " "Request is outstanding"); + } else { // callback is not set, which indicates we have processed the feature notification. + LOG_ERROR( + "Received more than one REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION during Remote Name " + "Request"); } } diff --git a/system/gd/hci/remote_name_request_test.cc b/system/gd/hci/remote_name_request_test.cc index 9bfdf00880513c9eb49e4af9a30546f6121a97c6..ebddd0112313e10255d80beeb4e88458fcc9270f 100644 --- a/system/gd/hci/remote_name_request_test.cc +++ b/system/gd/hci/remote_name_request_test.cc @@ -87,18 +87,19 @@ class RemoteNameRequestModuleTest : public ::testing::Test { template common::ContextualOnceCallback impossibleCallback() { - return client_handler_->BindOnce([](T... args) { ADD_FAILURE(); }); + return client_handler_->BindOnce([](T... /* args */) { ADD_FAILURE(); }); } template common::ContextualOnceCallback emptyCallback() { - return client_handler_->BindOnce([](T... args) {}); + return client_handler_->BindOnce([](T... /* args */) {}); } template common::ContextualOnceCallback promiseCallback(std::promise promise) { return client_handler_->BindOnce( - [](std::promise promise, T... args) { promise.set_value(); }, std::move(promise)); + [](std::promise promise, T... /* args */) { promise.set_value(); }, + std::move(promise)); } template diff --git a/system/gd/iso/facade.cc b/system/gd/iso/facade.cc index 42779f0e63723f0545a5cb82a873ebe2258e12a2..f405b9656d469328f5a42e482d354ada264a8e14 100644 --- a/system/gd/iso/facade.cc +++ b/system/gd/iso/facade.cc @@ -52,9 +52,9 @@ class IsoModuleFacadeService : public IsoModuleFacade::Service { } ::grpc::Status LeSetCigParameters( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::bluetooth::iso::LeSetCigParametersRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { std::vector cis_config; hci::CisParametersConfig cfg; @@ -93,9 +93,9 @@ class IsoModuleFacadeService : public IsoModuleFacade::Service { } ::grpc::Status LeSetCigParametersTest( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::bluetooth::iso::LeSetCigParametersTestRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { std::vector cis_config; for (const auto& cc : request->cis_configs()) { @@ -140,9 +140,9 @@ class IsoModuleFacadeService : public IsoModuleFacade::Service { } ::grpc::Status LeCreateCis( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::bluetooth::iso::LeCreateCisRequest* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { std::vector> create_cis_params; for (const auto& handle_pair : request->handle_pair()) { create_cis_params.push_back( @@ -154,21 +154,23 @@ class IsoModuleFacadeService : public IsoModuleFacade::Service { } ::grpc::Status FetchIsoData( - ::grpc::ServerContext* context, const LeCisHandleMsg* request, ::grpc::ServerWriter* writer) override { + ::grpc::ServerContext* context, + const LeCisHandleMsg* /* request */, + ::grpc::ServerWriter* writer) override { return le_iso_data_.RunLoop(context, writer); } ::grpc::Status FetchIsoEvents( ::grpc::ServerContext* context, - const google::protobuf::Empty* request, + const google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return le_iso_events_.RunLoop(context, writer); } ::grpc::Status SendIsoPacket( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const ::bluetooth::iso::IsoPacket* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { std::vector packet(request->payload().begin(), request->payload().end()); iso_module_->GetIsoManager()->SendIsoPacket(request->handle(), packet); return ::grpc::Status::OK; diff --git a/system/gd/iso/internal/iso_manager_impl.cc b/system/gd/iso/internal/iso_manager_impl.cc index 1ea385894943e2b0ff4c73320563bf0346b86546..4f3b1f99993fc20366183b7adc2957d8071d27a6 100644 --- a/system/gd/iso/internal/iso_manager_impl.cc +++ b/system/gd/iso/internal/iso_manager_impl.cc @@ -131,9 +131,9 @@ void IsoManagerImpl::SetCigParametersComplete( std::vector handles; while (cis_it != cis_configs.end()) { iso_connections_.push_back({ + .connection_handle = *handle_it, .cig_id = cig_id, .cis_id = cis_it->cis_id_, - .connection_handle = *handle_it, }); handles.push_back(*handle_it); @@ -156,8 +156,8 @@ void IsoManagerImpl::SetCigParametersTest( hci::ClockAccuracy peripherals_clock_accuracy, hci::Packing packing, hci::Enable framing, - uint16_t max_transport_latency_m_to_s, - uint16_t max_transport_latency_s_to_m, + uint16_t /* max_transport_latency_m_to_s */, + uint16_t /* max_transport_latency_s_to_m */, const std::vector& cis_test_configs, SetCigParametersCallback command_complete_callback) { hci_le_iso_interface_->EnqueueCommand( @@ -204,9 +204,9 @@ void IsoManagerImpl::SetCigParametersTestComplete( std::vector handles; while (cis_it != cis_configs.end()) { iso_connections_.push_back({ + .connection_handle = *handle_it, .cig_id = cig_id, .cis_id = cis_it->cis_id_, - .connection_handle = *handle_it, }); handles.push_back(*handle_it); @@ -254,7 +254,8 @@ void IsoManagerImpl::SendIsoPacket(uint16_t cis_handle, std::vector pac auto builder = hci::IsoWithoutTimestampBuilder::Create( cis_handle, hci::IsoPacketBoundaryFlag::COMPLETE_SDU, - 0 /* sequence_number*/, + 0 /* sequence_number */, + packet.size() /* iso_sdu_length */, hci::IsoPacketStatusFlag::VALID, std::make_unique(packet)); LOG_INFO("%c%c", packet[0], packet[1]); diff --git a/system/gd/l2cap/classic/facade.cc b/system/gd/l2cap/classic/facade.cc index 7fe4ae22f131bc8f251f767b2cb70dd0dcb81c6b..aabbefac7fd731c1221bb29957f9d784c7324525 100644 --- a/system/gd/l2cap/classic/facade.cc +++ b/system/gd/l2cap/classic/facade.cc @@ -50,18 +50,24 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service ASSERT(facade_handler_ != nullptr); } - ::grpc::Status FetchConnectionComplete(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* writer) override { + ::grpc::Status FetchConnectionComplete( + ::grpc::ServerContext* context, + const ::google::protobuf::Empty* /* request */, + ::grpc::ServerWriter* writer) override { return pending_connection_complete_.RunLoop(context, writer); } - ::grpc::Status FetchConnectionClose(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* writer) override { + ::grpc::Status FetchConnectionClose( + ::grpc::ServerContext* context, + const ::google::protobuf::Empty* /* request */, + ::grpc::ServerWriter* writer) override { return pending_connection_close_.RunLoop(context, writer); } - ::grpc::Status SendDynamicChannelPacket(::grpc::ServerContext* context, const DynamicChannelPacket* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SendDynamicChannelPacket( + ::grpc::ServerContext* /* context */, + const DynamicChannelPacket* request, + ::google::protobuf::Empty* /* response */) override { std::unique_lock lock(channel_map_mutex_); if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered"); @@ -73,9 +79,10 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service return ::grpc::Status::OK; } - ::grpc::Status OpenChannel(::grpc::ServerContext* context, - const ::bluetooth::l2cap::classic::OpenChannelRequest* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status OpenChannel( + ::grpc::ServerContext* /* context */, + const ::bluetooth::l2cap::classic::OpenChannelRequest* request, + ::google::protobuf::Empty* /* response */) override { auto service_helper = dynamic_channel_helper_map_.find(request->psm()); if (service_helper == dynamic_channel_helper_map_.end()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered"); @@ -86,9 +93,10 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service return ::grpc::Status::OK; } - ::grpc::Status CloseChannel(::grpc::ServerContext* context, - const ::bluetooth::l2cap::classic::CloseChannelRequest* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status CloseChannel( + ::grpc::ServerContext* /* context */, + const ::bluetooth::l2cap::classic::CloseChannelRequest* request, + ::google::protobuf::Empty* /* response */) override { auto psm = request->psm(); if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered"); @@ -97,23 +105,29 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service return ::grpc::Status::OK; } - ::grpc::Status FetchL2capData(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* writer) override { + ::grpc::Status FetchL2capData( + ::grpc::ServerContext* context, + const ::google::protobuf::Empty* /* request */, + ::grpc::ServerWriter* writer) override { auto status = pending_l2cap_data_.RunLoop(context, writer); return status; } - ::grpc::Status SetDynamicChannel(::grpc::ServerContext* context, const SetEnableDynamicChannelRequest* request, - google::protobuf::Empty* response) override { + ::grpc::Status SetDynamicChannel( + ::grpc::ServerContext* /* context */, + const SetEnableDynamicChannelRequest* request, + google::protobuf::Empty* /* response */) override { dynamic_channel_helper_map_.emplace( request->psm(), std::make_unique(this, l2cap_layer_, facade_handler_, request->psm(), request->retransmission_mode())); return ::grpc::Status::OK; } - ::grpc::Status SetTrafficPaused(::grpc::ServerContext* context, const SetTrafficPausedRequest* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SetTrafficPaused( + ::grpc::ServerContext* /* context */, + const SetTrafficPausedRequest* request, + ::google::protobuf::Empty* /* response */) override { auto psm = request->psm(); if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered"); @@ -126,17 +140,19 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service return ::grpc::Status::OK; } - ::grpc::Status GetChannelQueueDepth(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - GetChannelQueueDepthResponse* response) override { + ::grpc::Status GetChannelQueueDepth( + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, + GetChannelQueueDepthResponse* response) override { // Use the value kChannelQueueSize (5) in internal/dynamic_channel_impl.h response->set_size(5); return ::grpc::Status::OK; } ::grpc::Status InitiateConnectionForSecurity( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddress* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address(), peer)); outgoing_pairing_remote_devices_.insert(peer); @@ -145,7 +161,9 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service } void SecurityConnectionEventOccurred( - hci::ErrorCode hci_status, hci::Address remote, LinkSecurityInterfaceCallbackEventType event_type) { + hci::ErrorCode /* hci_status */, + hci::Address remote, + LinkSecurityInterfaceCallbackEventType event_type) { LinkSecurityInterfaceCallbackEvent msg; msg.mutable_address()->set_address(remote.ToString()); msg.set_event_type(event_type); @@ -154,16 +172,16 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service ::grpc::Status FetchSecurityConnectionEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { security_interface_ = l2cap_layer_->GetSecurityInterface(facade_handler_, this); return security_connection_events_.RunLoop(context, writer); } ::grpc::Status SecurityLinkHold( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddress* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address(), peer)); auto entry = security_link_map_.find(peer); @@ -176,9 +194,9 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service } ::grpc::Status SecurityLinkEnsureAuthenticated( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddress* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address(), peer)); auto entry = security_link_map_.find(peer); @@ -191,9 +209,9 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service } ::grpc::Status SecurityLinkRelease( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddress* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address(), peer)); outgoing_pairing_remote_devices_.erase(peer); @@ -207,9 +225,9 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service } ::grpc::Status SecurityLinkDisconnect( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddress* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address(), peer)); outgoing_pairing_remote_devices_.erase(peer); @@ -256,7 +274,7 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service hci_status, remote, LinkSecurityInterfaceCallbackEventType::ON_AUTHENTICATION_COMPLETE); } - void OnEncryptionChange(hci::Address remote, bool encrypted) override { + void OnEncryptionChange(hci::Address remote, bool /* encrypted */) override { SecurityConnectionEventOccurred( hci::ErrorCode::SUCCESS, remote, LinkSecurityInterfaceCallbackEventType::ON_ENCRYPTION_CHANGE); } @@ -312,8 +330,9 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service channel_->Close(); } - void on_l2cap_service_registration_complete(DynamicChannelManager::RegistrationResult registration_result, - std::unique_ptr service) {} + void on_l2cap_service_registration_complete( + DynamicChannelManager::RegistrationResult /* registration_result */, + std::unique_ptr /* service */) {} // invoked from Facade Handler void on_connection_open(std::unique_ptr channel) { @@ -363,7 +382,7 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service } } - void on_connect_fail(DynamicChannelManager::ConnectionResult result) {} + void on_connect_fail(DynamicChannelManager::ConnectionResult /* result */) {} void on_incoming_packet() { auto packet = channel_->GetQueueUpEnd()->TryDequeue(); diff --git a/system/gd/l2cap/classic/internal/link.cc b/system/gd/l2cap/classic/internal/link.cc index e6d4f0d0ab555ce97cefdd58166b28187a644160..a851c37485478f06fde0fabf89ef583fc29e0e87 100644 --- a/system/gd/l2cap/classic/internal/link.cc +++ b/system/gd/l2cap/classic/internal/link.cc @@ -408,7 +408,8 @@ void Link::OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) { void Link::OnReadLinkQualityComplete(uint8_t link_quality) { LOG_INFO("UNIMPLEMENTED %s link_quality:%hhu", __func__, link_quality); } -void Link::OnReadAfhChannelMapComplete(hci::AfhMode afh_mode, std::array afh_channel_map) { +void Link::OnReadAfhChannelMapComplete( + hci::AfhMode afh_mode, std::array /* afh_channel_map */) { LOG_INFO("UNIMPLEMENTED %s afh_mode:%s", __func__, hci::AfhModeText(afh_mode).c_str()); } void Link::OnReadRssiComplete(uint8_t rssi) { @@ -457,7 +458,7 @@ void Link::AddEncryptionChangeListener(EncryptionChangeListener listener) { encryption_change_listener_.push_back(listener); } -void Link::OnPendingPacketChange(Cid local_cid, bool has_packet) { +void Link::OnPendingPacketChange(Cid /* local_cid */, bool has_packet) { if (has_packet) { remaining_packets_to_be_sent_++; } else { diff --git a/system/gd/l2cap/classic/internal/link.h b/system/gd/l2cap/classic/internal/link.h index d30056c6a1421f8a346ac38f09bdce18104104d1..37e100763ab07460ff047e3c2f0c80f132a4a1dc 100644 --- a/system/gd/l2cap/classic/internal/link.h +++ b/system/gd/l2cap/classic/internal/link.h @@ -162,7 +162,7 @@ class Link : public l2cap::internal::ILink, return GetDevice().ToRedactedStringForLogging(); } - void SendLeCredit(Cid local_cid, uint16_t credit) override {} + void SendLeCredit(Cid /* local_cid */, uint16_t /* credit */) override {} // ConnectionManagementCallbacks void OnConnectionPacketTypeChanged(uint16_t packet_type) override; diff --git a/system/gd/l2cap/classic/internal/link_manager.cc b/system/gd/l2cap/classic/internal/link_manager.cc index fa53f2c2c0a4a287058b529630514bd36ac6fa06..87f36b6e91c29dad89950b4128eedf7a7c37f517 100644 --- a/system/gd/l2cap/classic/internal/link_manager.cc +++ b/system/gd/l2cap/classic/internal/link_manager.cc @@ -286,11 +286,11 @@ void LinkManager::OnConnectSuccess(std::unique_ptr(), parameter_provider, nullptr, nullptr, nullptr){}; - explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider, - std::unique_ptr acl_connection, LinkManager* link_manager) + explicit MockLink( + os::Handler* handler, + l2cap::internal::ParameterProvider* parameter_provider, + std::unique_ptr acl_connection, + LinkManager* /* link_manager */) : Link(handler, std::move(acl_connection), parameter_provider, nullptr, nullptr, nullptr){}; MOCK_METHOD(hci::AddressWithType, GetDevice, (), (const, override)); MOCK_METHOD(void, OnAclDisconnected, (hci::ErrorCode status), (override)); diff --git a/system/gd/l2cap/classic/internal/signalling_manager.cc b/system/gd/l2cap/classic/internal/signalling_manager.cc index 3187975a8c5aee3e255525ba7f1cc656a0f366a2..b5cef616fb87cacc074c926d4d729003276ba6f0 100644 --- a/system/gd/l2cap/classic/internal/signalling_manager.cc +++ b/system/gd/l2cap/classic/internal/signalling_manager.cc @@ -161,7 +161,7 @@ void ClassicSignallingManager::SendInformationRequest(InformationRequestInfoType } } -void ClassicSignallingManager::SendEchoRequest(std::unique_ptr payload) { +void ClassicSignallingManager::SendEchoRequest(std::unique_ptr /* payload */) { LOG_WARN("Not supported"); } @@ -242,8 +242,12 @@ void ClassicSignallingManager::on_security_result_for_incoming( link_->SendInitialConfigRequestOrQueue(new_channel->GetCid()); } -void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid, - ConnectionResponseResult result, ConnectionResponseStatus status) { +void ClassicSignallingManager::OnConnectionResponse( + SignalId signal_id, + Cid remote_cid, + Cid cid, + ConnectionResponseResult result, + ConnectionResponseStatus /* status */) { if (command_just_sent_.signal_id_ != signal_id || command_just_sent_.command_code_ != CommandCode::CONNECTION_REQUEST) { LOG_WARN("Unexpected response: no pending request. Expected signal id %d type %s, got %d", @@ -432,8 +436,8 @@ void ClassicSignallingManager::SendInitialConfigRequest(Cid local_cid) { send_configuration_request(channel->GetRemoteCid(), std::move(config)); } -void ClassicSignallingManager::negotiate_configuration(Cid cid, Continuation is_continuation, - std::vector> options) { +void ClassicSignallingManager::negotiate_configuration( + Cid cid, Continuation, std::vector> options) { auto channel = channel_allocator_->FindChannelByCid(cid); auto& configuration_state = channel_configuration_[channel->GetCid()]; std::vector> negotiation_config; @@ -605,7 +609,8 @@ void ClassicSignallingManager::OnDisconnectionRequest(SignalId signal_id, Cid ci channel_configuration_.erase(cid); } -void ClassicSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid) { +void ClassicSignallingManager::OnDisconnectionResponse( + SignalId signal_id, Cid /* remote_cid */, Cid cid) { if (command_just_sent_.signal_id_ != signal_id || command_just_sent_.command_code_ != CommandCode::DISCONNECTION_REQUEST) { LOG_WARN("Unexpected response: no pending request. Expected signal id %d type %s, got %d", @@ -641,7 +646,8 @@ void ClassicSignallingManager::OnEchoRequest(SignalId signal_id, const PacketVie enqueue_buffer_->Enqueue(std::move(builder), handler_); } -void ClassicSignallingManager::OnEchoResponse(SignalId signal_id, const PacketView& packet) { +void ClassicSignallingManager::OnEchoResponse( + SignalId signal_id, const PacketView& /* packet */) { if (command_just_sent_.signal_id_ != signal_id || command_just_sent_.command_code_ != CommandCode::ECHO_REQUEST) { LOG_WARN("Unexpected response: no pending request. Expected signal id %d type %s, got %d", command_just_sent_.signal_id_.Value(), CommandCodeText(command_just_sent_.command_code_).data(), diff --git a/system/gd/l2cap/classic/l2cap_classic_module.cc b/system/gd/l2cap/classic/l2cap_classic_module.cc index 5c43373ccf07a5cdd6087ef8408fea0dd89f3d7b..ddcb86c24a527806d29c9a9eb04fbf5e0b78ab81 100644 --- a/system/gd/l2cap/classic/l2cap_classic_module.cc +++ b/system/gd/l2cap/classic/l2cap_classic_module.cc @@ -15,19 +15,18 @@ */ #define LOG_TAG "l2cap2" +#include "l2cap/classic/l2cap_classic_module.h" + #include #include -#include "common/bidi_queue.h" +#include "dumpsys_data_generated.h" #include "hci/acl_manager.h" #include "hci/address.h" -#include "hci/hci_layer.h" -#include "hci/hci_packets.h" #include "l2cap/classic/internal/dumpsys_helper.h" #include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h" #include "l2cap/classic/internal/fixed_channel_service_manager_impl.h" #include "l2cap/classic/internal/link_manager.h" -#include "l2cap/classic/l2cap_classic_module.h" #include "l2cap/internal/parameter_provider.h" #include "l2cap_classic_module_generated.h" #include "module.h" diff --git a/system/gd/l2cap/classic/link_property_listener.h b/system/gd/l2cap/classic/link_property_listener.h index 28850745910d9c964e43fe75166654975ffde29a..052530f333aa4fb95db9dfb1e110dd4d37ee41bc 100644 --- a/system/gd/l2cap/classic/link_property_listener.h +++ b/system/gd/l2cap/classic/link_property_listener.h @@ -35,59 +35,69 @@ class LinkPropertyListener { /** * Invoked when an ACL link is connected. */ - virtual void OnLinkConnected(hci::Address remote, uint16_t handle) {} + virtual void OnLinkConnected(hci::Address /* remote */, uint16_t /* handle */) {} /** * Invoked when an ACL link is disconnected. */ - virtual void OnLinkDisconnected(hci::Address remote) {} + virtual void OnLinkDisconnected(hci::Address /* remote */) {} /** * Invoked when received remote version information for a given link */ virtual void OnReadRemoteVersionInformation( - hci::ErrorCode hci_status, - hci::Address remote, - uint8_t lmp_version, - uint16_t manufacturer_name, - uint16_t sub_version) {} + hci::ErrorCode /* hci_status */, + hci::Address /* remote */, + uint8_t /* lmp_version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) {} /** - * Invoked when received remote features and remote supported features for a given link + * Invoked when received remote features and remote supported features for a + * given link */ - virtual void OnReadRemoteSupportedFeatures(hci::Address remote, uint64_t features) {} + virtual void OnReadRemoteSupportedFeatures(hci::Address /* remote */, uint64_t /* features */) {} /** - * Invoked when received remote features and remote extended features for a given link + * Invoked when received remote features and remote extended features for a + * given link */ virtual void OnReadRemoteExtendedFeatures( - hci::Address remote, uint8_t page_number, uint8_t max_page_number, uint64_t features) {} + hci::Address /* remote */, + uint8_t /* page_number */, + uint8_t /* max_page_number */, + uint64_t /* features */) {} /** * Invoked when received role change */ - virtual void OnRoleChange(hci::ErrorCode hci_status, hci::Address remote, hci::Role role) {} + virtual void OnRoleChange( + hci::ErrorCode /* status */, hci::Address /* remote */, hci::Role /* role */) {} /** * Invoked when received clock offset */ - virtual void OnReadClockOffset(hci::Address remote, uint16_t clock_offset) {} + virtual void OnReadClockOffset(hci::Address /* remote */, uint16_t /* clock_offset */) {} /** * Invoked when received mode change */ - virtual void OnModeChange(hci::ErrorCode hci_status, hci::Address remote, hci::Mode mode, uint16_t interval) {} + virtual void OnModeChange( + hci::ErrorCode /* hci_status */, + hci::Address /* remote */, + hci::Mode /* mode */, + uint16_t /* interval */) {} /** * Invoked when received sniff subrating */ virtual void OnSniffSubrating( - hci::ErrorCode hci_status, - hci::Address remote, - uint16_t max_tx_lat, - uint16_t max_rx_lat, - uint16_t min_remote_timeout, - uint16_t min_local_timeout) {} + hci::ErrorCode /* hci_status */, + hci::Address /* remote */, + uint16_t /* max_tx_lat */, + uint16_t /* max_rx_lat */, + uint16_t /* min_remote_timeout */, + uint16_t /* min_local_timeout */) {} }; } // namespace classic diff --git a/system/gd/l2cap/classic/link_security_interface.h b/system/gd/l2cap/classic/link_security_interface.h index 90fac62e6fa41eac065b8c8fe15babd9f4864138..38b3be0ef1a70c62b6e5bd8cd901d2230d8a66a0 100644 --- a/system/gd/l2cap/classic/link_security_interface.h +++ b/system/gd/l2cap/classic/link_security_interface.h @@ -102,18 +102,19 @@ class LinkSecurityInterfaceListener { * is invalidated then. * @param remote */ - virtual void OnLinkDisconnected(hci::Address remote) {} + virtual void OnLinkDisconnected(hci::Address /* remote */) {} /** * Invoked when AuthenticationComplete event is received for a given link */ - virtual void OnAuthenticationComplete(hci::ErrorCode hci_status, hci::Address remote) {} + virtual void OnAuthenticationComplete( + hci::ErrorCode /* hci_status */, hci::Address /* remote */) {} /** * Invoked when EncryptionChange event is received for a given link * @param encrypted */ - virtual void OnEncryptionChange(hci::Address remote, bool encrypted) {} + virtual void OnEncryptionChange(hci::Address /* remote */, bool /* encrypted */) {} }; } // namespace classic diff --git a/system/gd/l2cap/classic/security_enforcement_interface.h b/system/gd/l2cap/classic/security_enforcement_interface.h index 01a5c7aad9374b95418677ff824128cbb534b267..5f429c6979e7fda9bdeb0036792680ebdf1b67c2 100644 --- a/system/gd/l2cap/classic/security_enforcement_interface.h +++ b/system/gd/l2cap/classic/security_enforcement_interface.h @@ -46,7 +46,10 @@ class SecurityEnforcementInterface { */ class SecurityEnforcementRejectAllImpl : public SecurityEnforcementInterface { public: - void Enforce(hci::AddressWithType remote, SecurityPolicy policy, ResultCallback result_callback) override { + void Enforce( + hci::AddressWithType /* remote */, + SecurityPolicy policy, + ResultCallback result_callback) override { if (policy == SecurityPolicy::_SDP_ONLY_NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK) { result_callback.InvokeIfNotEmpty(true); } else { diff --git a/system/gd/l2cap/fuzz/Android.bp b/system/gd/l2cap/fuzz/Android.bp index 6127a9867901b8707876084ef50c077916eae536..7cd46ce4fcbfc5977a1be3b4ff9f4592caaa29b8 100644 --- a/system/gd/l2cap/fuzz/Android.bp +++ b/system/gd/l2cap/fuzz/Android.bp @@ -28,7 +28,6 @@ cc_fuzz { "packages/modules/Bluetooth/system/stack/include", "packages/modules/Bluetooth/system/stack/l2cap", "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/include", "system/security/keystore/include", ], srcs: [ @@ -42,4 +41,5 @@ cc_fuzz { cc: ["android-bluetooth-security@google.com"], componentid: 27441, }, + cflags: ["-Wno-unused-parameter"], } diff --git a/system/gd/l2cap/internal/basic_mode_channel_data_controller.h b/system/gd/l2cap/internal/basic_mode_channel_data_controller.h index ae4e508b9c75893772117c53624497058d8eb450..66c171c0d1c41f2a0f6d961db8c890caa261001b 100644 --- a/system/gd/l2cap/internal/basic_mode_channel_data_controller.h +++ b/system/gd/l2cap/internal/basic_mode_channel_data_controller.h @@ -52,8 +52,9 @@ class BasicModeDataController : public DataController { std::unique_ptr GetNextPacket() override; - void EnableFcs(bool enabled) override {} - void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override {} + void EnableFcs(bool /* enabled */) override {} + void SetRetransmissionAndFlowControlOptions( + const RetransmissionAndFlowControlConfigurationOption& /* option */) override {} private: Cid cid_; diff --git a/system/gd/l2cap/internal/ilink.h b/system/gd/l2cap/internal/ilink.h index dfac779512476ecfbeaee9b3ed386e0b82e33a72..bc978c86d57c1fb32f6ec1b410ad64cba9148b21 100644 --- a/system/gd/l2cap/internal/ilink.h +++ b/system/gd/l2cap/internal/ilink.h @@ -34,13 +34,13 @@ class ILink { // Used by sender to indicate whether there is any pending packet to be sent. // If there is pending packet, don't delete the link. - virtual void OnPendingPacketChange(Cid local_cid, bool has_packet) {} + virtual void OnPendingPacketChange(Cid /* local_cid */, bool /* has_packet */) {} // To be used by LE credit based channel data controller over LE link - virtual void SendLeCredit(Cid local_cid, uint16_t credit) {} + virtual void SendLeCredit(Cid /* local_cid */, uint16_t /* credit */) {} // Used by A2dp software encoding - virtual void SetChannelTxPriority(Cid local_cid, bool high_priority) {} + virtual void SetChannelTxPriority(Cid /* local_cid */, bool /* high_priority */) {} }; } // namespace internal } // namespace l2cap diff --git a/system/gd/l2cap/internal/le_credit_based_channel_data_controller.h b/system/gd/l2cap/internal/le_credit_based_channel_data_controller.h index 75998c5b77fd2ef6f2003d725942f6e145b4601a..b9e510f14317de2b4b8cb0d3ff8bfba3b85326e1 100644 --- a/system/gd/l2cap/internal/le_credit_based_channel_data_controller.h +++ b/system/gd/l2cap/internal/le_credit_based_channel_data_controller.h @@ -49,8 +49,9 @@ class LeCreditBasedDataController : public DataController { void OnPdu(packet::PacketView pdu) override; std::unique_ptr GetNextPacket() override; - void EnableFcs(bool enabled) override {} - void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override {} + void EnableFcs(bool /* enabled */) override {} + void SetRetransmissionAndFlowControlOptions( + const RetransmissionAndFlowControlConfigurationOption& /* option */) override {} // TODO: Set MTU and MPS from signalling channel void SetMtu(Mtu mtu); diff --git a/system/gd/l2cap/internal/scheduler.h b/system/gd/l2cap/internal/scheduler.h index 281bf8ef960e1f05bd8667a83bb44ca98019d56d..a0a242dc939036d6362405918ff3739baeb1152c 100644 --- a/system/gd/l2cap/internal/scheduler.h +++ b/system/gd/l2cap/internal/scheduler.h @@ -34,11 +34,11 @@ namespace internal { /** * Handle the scheduling of packets through the l2cap stack. - * For each attached channel, dequeue its outgoing packets and enqueue it to the given LinkQueueUpEnd, according to some - * policy (cid). + * For each attached channel, dequeue its outgoing packets and enqueue it to the + * given LinkQueueUpEnd, according to some policy (cid). * - * Note: If a channel cannot dequeue from ChannelQueueDownEnd so that the buffer for incoming packet is full, further - * incoming packets will be dropped. + * Note: If a channel cannot dequeue from ChannelQueueDownEnd so that the buffer + * for incoming packet is full, further incoming packets will be dropped. */ class Scheduler { public: @@ -50,20 +50,22 @@ class Scheduler { using LowerQueueUpEnd = common::BidiQueueEnd; /** - * Callback from the sender to indicate that the scheduler could dequeue number_packets from it + * Callback from the sender to indicate that the scheduler could dequeue + * number_packets from it */ - virtual void OnPacketsReady(Cid cid, int number_packets) {} + virtual void OnPacketsReady(Cid /* cid */, int /* number_packets */) {} /** * Let the scheduler send the specified cid first. * Used by A2dp software encoding. */ - virtual void SetChannelTxPriority(Cid cid, bool high_priority) {} + virtual void SetChannelTxPriority(Cid /* cid */, bool /* high_priority */) {} /** - * Called by data controller to indicate that a channel is closed and packets should be dropped + * Called by data controller to indicate that a channel is closed and packets + * should be dropped */ - virtual void RemoveChannel(Cid cid) {} + virtual void RemoveChannel(Cid /* cid */) {} virtual ~Scheduler() = default; }; diff --git a/system/gd/l2cap/le/facade.cc b/system/gd/l2cap/le/facade.cc index b0e795594c0b64954f2175876be72f4d5cac4905..3a7aa3aae5860d282c94b34bd0c6b747d8f7f062 100644 --- a/system/gd/l2cap/le/facade.cc +++ b/system/gd/l2cap/le/facade.cc @@ -59,13 +59,17 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { ASSERT(facade_handler_ != nullptr); } - ::grpc::Status FetchL2capData(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter<::bluetooth::l2cap::le::L2capPacket>* writer) override { + ::grpc::Status FetchL2capData( + ::grpc::ServerContext* context, + const ::google::protobuf::Empty* /* request */, + ::grpc::ServerWriter<::bluetooth::l2cap::le::L2capPacket>* writer) override { return pending_l2cap_data_.RunLoop(context, writer); } - ::grpc::Status OpenDynamicChannel(::grpc::ServerContext* context, const OpenDynamicChannelRequest* request, - OpenDynamicChannelResponse* response) override { + ::grpc::Status OpenDynamicChannel( + ::grpc::ServerContext* /* context */, + const OpenDynamicChannelRequest* request, + OpenDynamicChannelResponse* response) override { auto service_helper = dynamic_channel_helper_map_.find(request->psm()); if (service_helper == dynamic_channel_helper_map_.end()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered"); @@ -80,8 +84,10 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { return ::grpc::Status::OK; } - ::grpc::Status CloseDynamicChannel(::grpc::ServerContext* context, const CloseDynamicChannelRequest* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status CloseDynamicChannel( + ::grpc::ServerContext* /* context */, + const CloseDynamicChannelRequest* request, + ::google::protobuf::Empty* /* response */) override { auto service_helper = dynamic_channel_helper_map_.find(request->psm()); if (service_helper == dynamic_channel_helper_map_.end()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered"); @@ -99,9 +105,10 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { return ::grpc::Status::OK; } - ::grpc::Status SetDynamicChannel(::grpc::ServerContext* context, - const ::bluetooth::l2cap::le::SetEnableDynamicChannelRequest* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SetDynamicChannel( + ::grpc::ServerContext* /* context */, + const ::bluetooth::l2cap::le::SetEnableDynamicChannelRequest* request, + ::google::protobuf::Empty* /* response */) override { if (request->enable()) { dynamic_channel_helper_map_.emplace(request->psm(), std::make_unique( this, l2cap_layer_, facade_handler_, request->psm(), @@ -117,9 +124,10 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { } } - ::grpc::Status SendDynamicChannelPacket(::grpc::ServerContext* context, - const ::bluetooth::l2cap::le::DynamicChannelPacket* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SendDynamicChannelPacket( + ::grpc::ServerContext* /* context */, + const ::bluetooth::l2cap::le::DynamicChannelPacket* request, + ::google::protobuf::Empty* /* response */) override { std::unique_lock lock(channel_map_mutex_); if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered"); @@ -184,7 +192,7 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { common::Bind(&L2capDynamicChannelHelper::on_incoming_packet, common::Unretained(this))); } - void on_close_callback(hci::ErrorCode error_code) { + void on_close_callback(hci::ErrorCode /* error_code */) { { std::unique_lock lock(channel_open_cv_mutex_); channel_->GetQueueUpEnd()->UnregisterDequeue(); @@ -252,8 +260,10 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { std::mutex channel_open_cv_mutex_; }; - ::grpc::Status SetFixedChannel(::grpc::ServerContext* context, const SetEnableFixedChannelRequest* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SetFixedChannel( + ::grpc::ServerContext* /* context */, + const SetEnableFixedChannelRequest* request, + ::google::protobuf::Empty* /* response */) override { if (request->enable()) { fixed_channel_helper_map_.emplace(request->cid(), std::make_unique( this, l2cap_layer_, facade_handler_, request->cid())); @@ -269,8 +279,10 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { } } - ::grpc::Status SendFixedChannelPacket(::grpc::ServerContext* context, const FixedChannelPacket* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SendFixedChannelPacket( + ::grpc::ServerContext* /* context */, + const FixedChannelPacket* request, + ::google::protobuf::Empty* /* response */) override { std::unique_lock lock(channel_map_mutex_); if (fixed_channel_helper_map_.find(request->cid()) == fixed_channel_helper_map_.end()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Cid not registered"); @@ -335,7 +347,7 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { common::Bind(&L2capFixedChannelHelper::on_incoming_packet, common::Unretained(this))); } - void on_close_callback(hci::ErrorCode error_code) { + void on_close_callback(hci::ErrorCode /* error_code */) { { std::unique_lock lock(channel_open_cv_mutex_); channel_->GetQueueUpEnd()->UnregisterDequeue(); @@ -343,7 +355,7 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { channel_ = nullptr; } - void on_connect_fail(FixedChannelManager::ConnectionResult result) { + void on_connect_fail(FixedChannelManager::ConnectionResult /* result */) { { std::unique_lock lock(channel_open_cv_mutex_); channel_ = nullptr; @@ -401,8 +413,10 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { std::mutex channel_open_cv_mutex_; }; - ::grpc::Status SendConnectionParameterUpdate(::grpc::ServerContext* context, const ConnectionParameter* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SendConnectionParameterUpdate( + ::grpc::ServerContext* /* context */, + const ConnectionParameter* request, + ::google::protobuf::Empty* /* response */) override { if (dynamic_channel_helper_map_.empty()) { return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Need to open at least one dynamic channel first"); } diff --git a/system/gd/l2cap/le/internal/link.cc b/system/gd/l2cap/le/internal/link.cc index e97def9185a7b49d278ac85091e3cce2fe9635bc..f1a0fe385545c169b770ee2b17b997d644128c19 100644 --- a/system/gd/l2cap/le/internal/link.cc +++ b/system/gd/l2cap/le/internal/link.cc @@ -35,15 +35,24 @@ namespace internal { static constexpr uint16_t kDefaultMinimumCeLength = 0x0002; static constexpr uint16_t kDefaultMaximumCeLength = 0x0C00; -Link::Link(os::Handler* l2cap_handler, std::unique_ptr acl_connection, - l2cap::internal::ParameterProvider* parameter_provider, - DynamicChannelServiceManagerImpl* dynamic_service_manager, - FixedChannelServiceManagerImpl* fixed_service_manager, LinkManager* link_manager) - : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)), +Link::Link( + os::Handler* l2cap_handler, + std::unique_ptr acl_connection, + l2cap::internal::ParameterProvider* parameter_provider, + DynamicChannelServiceManagerImpl* dynamic_service_manager, + FixedChannelServiceManagerImpl* /* fixed_service_manager */, + LinkManager* link_manager) + : l2cap_handler_(l2cap_handler), + acl_connection_(std::move(acl_connection)), data_pipeline_manager_(l2cap_handler, this, acl_connection_->GetAclQueueEnd()), - parameter_provider_(parameter_provider), dynamic_service_manager_(dynamic_service_manager), - signalling_manager_(l2cap_handler_, this, &data_pipeline_manager_, dynamic_service_manager_, - &dynamic_channel_allocator_), + parameter_provider_(parameter_provider), + dynamic_service_manager_(dynamic_service_manager), + signalling_manager_( + l2cap_handler_, + this, + &data_pipeline_manager_, + dynamic_service_manager_, + &dynamic_channel_allocator_), link_manager_(link_manager) { ASSERT(l2cap_handler_ != nullptr); ASSERT(acl_connection_ != nullptr); @@ -65,7 +74,7 @@ void Link::OnDisconnection(hci::ErrorCode status) { } void Link::OnConnectionUpdate( - hci::ErrorCode hci_status, + hci::ErrorCode /* hci_status */, uint16_t connection_interval, uint16_t connection_latency, uint16_t supervision_timeout) { @@ -98,9 +107,11 @@ void Link::OnReadRemoteVersionInformationComplete( hci_status, GetDevice(), lmp_version, manufacturer_name, sub_version); } -void Link::OnLeReadRemoteFeaturesComplete(hci::ErrorCode hci_status, uint64_t features) {} +void Link::OnLeReadRemoteFeaturesComplete(hci::ErrorCode /* hci_status*/, uint64_t /* features */) { +} -void Link::OnPhyUpdate(hci::ErrorCode hci_status, uint8_t tx_phy, uint8_t rx_phy) {} +void Link::OnPhyUpdate( + hci::ErrorCode /* hci_status */, uint8_t /* tx_phy */, uint8_t /* rx_phy */) {} void Link::OnLeSubrateChange( hci::ErrorCode hci_status, @@ -169,7 +180,8 @@ void Link::SendConnectionParameterUpdate(uint16_t conn_interval_min, uint16_t co update_request_signal_id_ = kInvalidSignalId; } -std::shared_ptr Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) { +std::shared_ptr Link::AllocateFixedChannel( + Cid cid, SecurityPolicy /* security_policy */) { auto channel = fixed_channel_allocator_.AllocateChannel(cid); data_pipeline_manager_.AttachChannel(cid, channel, l2cap::internal::DataPipelineManager::ChannelMode::BASIC); return channel; @@ -308,7 +320,7 @@ void Link::on_connection_update_complete(SignalId signal_id, hci::ErrorCode erro signalling_manager_.SendConnectionParameterUpdateResponse(SignalId(), result); } -void Link::OnPendingPacketChange(Cid local_cid, bool has_packet) { +void Link::OnPendingPacketChange(Cid /* local_cid */, bool has_packet) { if (has_packet) { remaining_packets_to_be_sent_++; } else { diff --git a/system/gd/l2cap/le/internal/signalling_manager.cc b/system/gd/l2cap/le/internal/signalling_manager.cc index 084f900c6a446b500143eace8ca6eab4ce9d8643..8623ea1949d7de88e370a79d330e8f3e17786f5a 100644 --- a/system/gd/l2cap/le/internal/signalling_manager.cc +++ b/system/gd/l2cap/le/internal/signalling_manager.cc @@ -110,9 +110,11 @@ void LeSignallingManager::SendCredit(Cid local_cid, uint16_t credits) { enqueue_buffer_->Enqueue(std::move(builder), handler_); } -void LeSignallingManager::SendEnhancedConnectionRequest(Psm psm, std::vector local_cid, Mtu mtu) {} +void LeSignallingManager::SendEnhancedConnectionRequest( + Psm /* psm */, std::vector /* local_cid */, Mtu /* mtu */) {} -void LeSignallingManager::SendEnhancedReconfigureRequest(std::vector local_cid, Mtu mtu) {} +void LeSignallingManager::SendEnhancedReconfigureRequest( + std::vector /* local_cid */, Mtu /* mtu */) {} void LeSignallingManager::CancelAlarm() { alarm_.Cancel(); @@ -200,10 +202,10 @@ void LeSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid r PendingConnection pending{ .remote_cid = remote_cid, - .incoming_signal_id = signal_id, - .initial_credits = initial_credits, - .max_pdu_size = mps, .mtu = mtu, + .max_pdu_size = mps, + .initial_credits = initial_credits, + .incoming_signal_id = signal_id, }; dynamic_service_manager_->GetSecurityEnforcementInterface()->Enforce( link_->GetDevice(), diff --git a/system/gd/l2cap/le/l2cap_le_module.cc b/system/gd/l2cap/le/l2cap_le_module.cc index 50db2f89bc8ab699ad50ee24d21ed6643edae377..fff5fa4ff55d2be2db19e117e7946af6817a05c7 100644 --- a/system/gd/l2cap/le/l2cap_le_module.cc +++ b/system/gd/l2cap/le/l2cap_le_module.cc @@ -39,7 +39,10 @@ const ModuleFactory L2capLeModule::Factory = ModuleFactory([]() { return new L2c */ class SecurityEnforcementRejectAllImpl : public SecurityEnforcementInterface { public: - void Enforce(hci::AddressWithType remote, SecurityPolicy policy, ResultCallback result_callback) override { + void Enforce( + hci::AddressWithType /* remote */, + SecurityPolicy policy, + ResultCallback result_callback) override { if (policy == SecurityPolicy::NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK) { result_callback.InvokeIfNotEmpty(true); } else { diff --git a/system/gd/l2cap/le/l2cap_le_module.h b/system/gd/l2cap/le/l2cap_le_module.h index 28352c0c68b75b367d49eaede83f5a82056278ea..999f1dfad1560224bd8d7a00c3c947de2fa6da7f 100644 --- a/system/gd/l2cap/le/l2cap_le_module.h +++ b/system/gd/l2cap/le/l2cap_le_module.h @@ -25,10 +25,6 @@ namespace bluetooth { -namespace shim { -void L2CA_UseLegacySecurityModule(); -} - namespace security { class SecurityModule; } @@ -70,7 +66,6 @@ class L2capLeModule : public bluetooth::Module { std::unique_ptr pimpl_; friend security::SecurityModule; - friend void bluetooth::shim::L2CA_UseLegacySecurityModule(); /** * Only for the LE security module to inject functionality to enforce security level for a connection. When LE diff --git a/system/gd/l2cap/le/link_options.cc b/system/gd/l2cap/le/link_options.cc index adf74eec9a659afdd664c89c7ffb1c5298a5087a..9db2e3816861172e1a41669195b678d131b1a1c4 100644 --- a/system/gd/l2cap/le/link_options.cc +++ b/system/gd/l2cap/le/link_options.cc @@ -58,7 +58,11 @@ bool LinkOptions::UpdateConnectionParameter(uint16_t conn_interval_min, uint16_t return true; } -bool LinkOptions::SetPhy(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys, uint16_t phy_options) { +bool LinkOptions::SetPhy( + uint8_t /* all_phys */, + uint8_t /* tx_phys */, + uint8_t /* rx_phys */, + uint16_t /* phy_options */) { LOG_ERROR("Not implemented"); return false; } diff --git a/system/gd/l2cap/le/link_property_listener.h b/system/gd/l2cap/le/link_property_listener.h index 9af175b23a29177f84e1ec40e989b161014ef320..9960dab952f0b06f1c228b00c0862b71ff156aac 100644 --- a/system/gd/l2cap/le/link_property_listener.h +++ b/system/gd/l2cap/le/link_property_listener.h @@ -35,42 +35,48 @@ class LinkPropertyListener { /** * Invoked when an ACL link is connected. */ - virtual void OnLinkConnected(hci::AddressWithType remote, uint16_t handle, hci::Role my_role) {} + virtual void OnLinkConnected( + hci::AddressWithType /* remote */, uint16_t /* handle */, hci::Role /* my_role */) {} /** * Invoked when an ACL link is disconnected. */ - virtual void OnLinkDisconnected(hci::AddressWithType remote) {} + virtual void OnLinkDisconnected(hci::AddressWithType /* remote */) {} /** * Invoked when received remote version information for a given link */ virtual void OnReadRemoteVersionInformation( - hci::ErrorCode hci_status, - hci::AddressWithType remote, - uint8_t lmp_version, - uint16_t manufacturer_name, - uint16_t sub_version) {} + hci::ErrorCode /* hci_status */, + hci::AddressWithType /* remote */, + uint8_t /* lmp_version */, + uint16_t /* manufacturer_name */, + uint16_t /* sub_version */) {} /** * Invoked when received connection update for a given link */ virtual void OnConnectionUpdate( - hci::AddressWithType remote, - uint16_t connection_interval, - uint16_t connection_latency, - uint16_t supervision_timeout) {} + hci::AddressWithType /* remote */, + uint16_t /* connection_interval */, + uint16_t /* connection_latency */, + uint16_t /* supervision_timeout */) {} /** * Invoked when received PHY update for a given link */ - virtual void OnPhyUpdate(hci::AddressWithType remote, uint8_t tx_phy, uint8_t rx_phy) {} + virtual void OnPhyUpdate( + hci::AddressWithType /* remote */, uint8_t /* tx_phy */, uint8_t /* rx_phy */) {} /** * Invoked when received data length exchange for a given link */ virtual void OnDataLengthChange( - hci::AddressWithType remote, uint16_t tx_octets, uint16_t tx_time, uint16_t rx_octets, uint16_t rx_time) {} + hci::AddressWithType /* remote */, + uint16_t /* tx_octets */, + uint16_t /* tx_time */, + uint16_t /* rx_octets */, + uint16_t /* rx_time */) {} }; } // namespace le diff --git a/system/gd/metrics/BUILD.gn b/system/gd/metrics/BUILD.gn index d4a952258a72ee065973d76cb0b4341326ec5483..3f248bab2f5a3845bf420c8ff73afc3565ea9e39 100644 --- a/system/gd/metrics/BUILD.gn +++ b/system/gd/metrics/BUILD.gn @@ -34,6 +34,7 @@ source_set("BluetoothMetricsSources") { sources = [ "counter_metrics.cc", "utils.cc", + "metrics_state.cc" ] configs += [ "//bt/system/gd:gd_defaults"] diff --git a/system/gd/metrics/chromeos/OWNERS b/system/gd/metrics/chromeos/OWNERS index 45bfdd2be4f3b49a5c0053e783ad429ded0c1be1..a823e6e1ddc6d3d153fe4acbd207c3b06ae03b10 100644 --- a/system/gd/metrics/chromeos/OWNERS +++ b/system/gd/metrics/chromeos/OWNERS @@ -1 +1 @@ -include platform/packages/modules/Bluetooth:/OWNERS_chromeos +include /OWNERS_chromeos diff --git a/system/gd/metrics/chromeos/metrics.cc b/system/gd/metrics/chromeos/metrics.cc index 324c1eedba6701483bbd2f1d77e26dffb4aa9959..9ee8f05b2ccb8da10692d656d57b2bedccd8c437 100644 --- a/system/gd/metrics/chromeos/metrics.cc +++ b/system/gd/metrics/chromeos/metrics.cc @@ -70,10 +70,10 @@ void LogMetricsBondCreateAttempt(RawAddress* addr, uint32_t device_type) { LOG_DEBUG( "PairingStateChanged: %s, %d, %s, %d, %d", boot_id.c_str(), - boot_time, + (int)boot_time, addr_string.c_str(), - connection_type, - PairingState::PAIR_STARTING); + (int)connection_type, + (int)PairingState::PAIR_STARTING); ::metrics::structured::events::bluetooth::BluetoothPairingStateChanged() .SetBootId(boot_id) @@ -102,13 +102,16 @@ void LogMetricsBondStateChanged( // Ignore the start of pairing event as its logged separated above. if (pairing_state == PairingState::PAIR_STARTING) return; + // Ignore absurd state. + if (pairing_state == PairingState::PAIR_FAIL_END) return; + LOG_DEBUG( "PairingStateChanged: %s, %d, %s, %d, %d", boot_id.c_str(), - boot_time, + (int)boot_time, addr_string.c_str(), - connection_type, - pairing_state); + (int)connection_type, + (int)pairing_state); ::metrics::structured::events::bluetooth::BluetoothPairingStateChanged() .SetBootId(boot_id) @@ -145,15 +148,15 @@ void LogMetricsDeviceInfoReport( LOG_DEBUG( "DeviceInfoReport %s %d %s %d %d %d %d %d %d %d", boot_id.c_str(), - boot_time, + (int)boot_time, addr_string.c_str(), - device_type, - major_class, - category, - vendor_id, - vendor_id_src, - product_id, - version); + (int)device_type, + (int)major_class, + (int)category, + (int)vendor_id, + (int)vendor_id_src, + (int)product_id, + (int)version); if (!IsDeviceInfoInAllowlist(vendor_id_src, vendor_id, product_id)) { vendor_id_src = 0; @@ -193,11 +196,11 @@ void LogMetricsProfileConnectionStateChanged(RawAddress* addr, uint32_t profile, LOG_DEBUG( "ProfileConnectionStateChanged: %s, %d, %s, %d, %d, %d", boot_id.c_str(), - boot_time, + (int)boot_time, addr_string.c_str(), - event.type, - event.profile, - event.state); + (int)event.type, + (int)event.profile, + (int)event.state); ::metrics::structured::events::bluetooth::BluetoothProfileConnectionStateChanged() .SetBootId(boot_id) @@ -242,13 +245,13 @@ void LogMetricsAclConnectionStateChanged( LOG_DEBUG( "AclConnectionStateChanged: %s, %d, %s, %d, %d, %d, %d, %d", boot_id.c_str(), - event.start_time, + (int)event.start_time, addr_string.c_str(), - transport, - event.direction, - event.initiator, - event.state, - event.start_status); + (int)transport, + (int)event.direction, + (int)event.initiator, + (int)event.state, + (int)event.start_status); ::metrics::structured::events::bluetooth::BluetoothAclConnectionStateChanged() .SetBootId(boot_id) @@ -265,13 +268,13 @@ void LogMetricsAclConnectionStateChanged( LOG_DEBUG( "AclConnectionStateChanged: %s, %d, %s, %d, %d, %d, %d, %d", boot_id.c_str(), - boot_time, + (int)boot_time, addr_string.c_str(), - transport, - event.direction, - event.initiator, - event.state, - event.status); + (int)transport, + (int)event.direction, + (int)event.initiator, + (int)event.state, + (int)event.status); ::metrics::structured::events::bluetooth::BluetoothAclConnectionStateChanged() .SetBootId(boot_id) diff --git a/system/gd/metrics/chromeos/metrics_event.cc b/system/gd/metrics/chromeos/metrics_event.cc index 474999be5f79e8d84ed2705dbd44012c33b757ef..a1efc368fff58868508d5ab30b32d44d266e379b 100644 --- a/system/gd/metrics/chromeos/metrics_event.cc +++ b/system/gd/metrics/chromeos/metrics_event.cc @@ -208,7 +208,7 @@ static PairingState FailReasonToPairingState(int32_t fail_reason) { return PairingState::PAIR_FAIL_AUTH_FAILED; case hci::ErrorCode::ROLE_SWITCH_FAILED: return PairingState::PAIR_FAIL_FAILED; - case hci::ErrorCode::HOST_BUSY: + case hci::ErrorCode::HOST_BUSY_PAIRING: return PairingState::PAIR_FAIL_BUSY; case hci::ErrorCode::CONTROLLER_BUSY: return PairingState::PAIR_FAIL_BUSY; @@ -265,11 +265,16 @@ PairingState ToPairingState(uint32_t status, uint32_t bond_state, int32_t fail_r if ((BtStatus)status == BtStatus::BT_STATUS_SUCCESS && (hci::ErrorCode)fail_reason == hci::ErrorCode::SUCCESS) { if ((BtBondState)bond_state == BtBondState::BT_BOND_STATE_BONDED) { return PairingState::PAIR_SUCCEED; - } else { - return PairingState::PAIR_FAIL_CANCELLED; + } else { // must be BtBondState::BT_BOND_STATE_NONE as BT_BOND_STATE_BONDING case has been + // checked early + // This implies the event is from forgetting a device. Return an absurd value to let caller + // know. + return PairingState::PAIR_FAIL_END; } } + // TODO(b/287392029): Translate cases of bond cancelled into PairingState:PAIR_FAIL_CANCELLED + // When both status and fail reason are provided and disagree with each other, overwrite status with the fail reason // as fail reason is generated closer to the HCI and provides a more accurate description. if (status) pairing_state = StatusToPairingState(status); @@ -695,4 +700,4 @@ MetricsChipsetInfo GetMetricsChipsetInfo() { } } // namespace metrics -} // namespace bluetooth \ No newline at end of file +} // namespace bluetooth diff --git a/system/gd/metrics/counter_metrics.cc b/system/gd/metrics/counter_metrics.cc index 820990eb361c62b587b29907565b058479d57fd9..8cd69ed5158ac25000401845cf66d2f81edd428a 100644 --- a/system/gd/metrics/counter_metrics.cc +++ b/system/gd/metrics/counter_metrics.cc @@ -28,8 +28,7 @@ const int COUNTER_METRICS_PERDIOD_MINUTES = 360; // Drain counters every 6 hours const ModuleFactory CounterMetrics::Factory = ModuleFactory([]() { return new CounterMetrics(); }); -void CounterMetrics::ListDependencies(ModuleList* list) const { -} +void CounterMetrics::ListDependencies(ModuleList* /* list */) const {} void CounterMetrics::Start() { alarm_ = std::make_unique(GetHandler()); @@ -100,4 +99,4 @@ void CounterMetrics::DrainBufferedCounters() { } } // namespace metrics -} // namespace bluetooth \ No newline at end of file +} // namespace bluetooth diff --git a/system/gd/metrics/linux/OWNERS b/system/gd/metrics/linux/OWNERS index 45bfdd2be4f3b49a5c0053e783ad429ded0c1be1..a823e6e1ddc6d3d153fe4acbd207c3b06ae03b10 100644 --- a/system/gd/metrics/linux/OWNERS +++ b/system/gd/metrics/linux/OWNERS @@ -1 +1 @@ -include platform/packages/modules/Bluetooth:/OWNERS_chromeos +include /OWNERS_chromeos diff --git a/system/gd/metrics/metrics_state.cc b/system/gd/metrics/metrics_state.cc index 30c30f61a72054baeaf7cb5ff2eff562feb7f9b6..7265fb9492e1e1eb36f855174518f09675aa3603 100644 --- a/system/gd/metrics/metrics_state.cc +++ b/system/gd/metrics/metrics_state.cc @@ -50,12 +50,6 @@ void LEConnectionMetricState::AddStateChangedEvent( LeConnectionType connection_type, LeConnectionState transaction_state, std::vector> argument_list) { - LOG_INFO( - "LEConnectionMetricState: Origin Type: %s, Connection Type: %s, Transaction State: " - "%s", - common::ToHexString(origin_type).c_str(), - common::ToHexString(connection_type).c_str(), - common::ToHexString(transaction_state).c_str()); ClockTimePoint current_timestamp = std::chrono::high_resolution_clock::now(); state = transaction_state; @@ -175,6 +169,8 @@ void LEConnectionMetricsRemoteDevice::AddStateChangedEvent( common::ToHexString(transaction_state).c_str(), common::ToHexString(connection_type).c_str(), common::ToHexString(origin_type).c_str()); + + std::unique_lock lock(le_connection_metrics_remote_device_guard); if (address.IsEmpty()) { LOG_INFO( "LEConnectionMetricsRemoteDevice: Empty Address Cancellation %s, %s, %s\n", @@ -193,7 +189,6 @@ void LEConnectionMetricsRemoteDevice::AddStateChangedEvent( if (device_metric->IsCancelled() && transaction_state == LeConnectionState::STATE_LE_ACL_END) { - LOG_INFO("LEConnectionMetricsRemoteDevice: Session is now complete after cancellation"); // complete the connection device_metric->AddStateChangedEvent( origin_type, connection_type, transaction_state, argument_list); @@ -204,7 +199,6 @@ void LEConnectionMetricsRemoteDevice::AddStateChangedEvent( return; } - std::unique_lock lock(le_connection_metrics_remote_device_guard); auto it = opened_devices.find(address); if (it == opened_devices.end()) { device_metrics.push_back(std::make_unique(address)); diff --git a/system/gd/module.cc b/system/gd/module.cc index 7630e694d329f1195c39fdaab9eb659034a8330d..ee3c62f02191115b4a0df9b58c4f97475f3c5dc1 100644 --- a/system/gd/module.cc +++ b/system/gd/module.cc @@ -18,11 +18,10 @@ #include "module.h" #include "common/init_flags.h" -#include "os/wakelock_manager.h" +#include "module_dumper_flatbuffer.h" using ::bluetooth::os::Handler; using ::bluetooth::os::Thread; -using ::bluetooth::os::WakelockManager; namespace bluetooth { @@ -36,8 +35,7 @@ Handler* Module::GetHandler() const { return handler_; } -DumpsysDataFinisher EmptyDumpsysDataFinisher = [](DumpsysDataBuilder* dumpsys_data_builder) {}; -DumpsysDataFinisher Module::GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const { +DumpsysDataFinisher Module::GetDumpsysData(flatbuffers::FlatBufferBuilder* /* builder */) const { return EmptyDumpsysDataFinisher; } @@ -134,45 +132,4 @@ os::Handler* ModuleRegistry::GetModuleHandler(const ModuleFactory* module) const return nullptr; } -void ModuleDumper::DumpState(std::string* output) const { - ASSERT(output != nullptr); - - flatbuffers::FlatBufferBuilder builder(1024); - auto title = builder.CreateString(title_); - - common::InitFlagsDataBuilder init_flags_builder(builder); - init_flags_builder.add_title(builder.CreateString("----- Init Flags -----")); - std::vector> flags; - for (const auto& flag : common::init_flags::dump()) { - flags.push_back(common::CreateInitFlagValue( - builder, - builder.CreateString(std::string(flag.flag)), - builder.CreateString(std::string(flag.value)))); - } - init_flags_builder.add_values(builder.CreateVector(flags)); - auto init_flags_offset = init_flags_builder.Finish(); - - auto wakelock_offset = WakelockManager::Get().GetDumpsysData(&builder); - - std::queue queue; - for (auto it = module_registry_.start_order_.rbegin(); it != module_registry_.start_order_.rend(); it++) { - auto instance = module_registry_.started_modules_.find(*it); - ASSERT(instance != module_registry_.started_modules_.end()); - queue.push(instance->second->GetDumpsysData(&builder)); - } - - DumpsysDataBuilder data_builder(builder); - data_builder.add_title(title); - data_builder.add_init_flags(init_flags_offset); - data_builder.add_wakelock_manager_data(wakelock_offset); - - while (!queue.empty()) { - queue.front()(&data_builder); - queue.pop(); - } - - builder.Finish(data_builder.Finish()); - *output = std::string(builder.GetBufferPointer(), builder.GetBufferPointer() + builder.GetSize()); -} - } // namespace bluetooth diff --git a/system/gd/module.h b/system/gd/module.h index 7695f1ad3705e6797b1bec8e61d95c70297abb83..7083fa0725fe2f6cba836a3f991f0a2dd64d453e 100644 --- a/system/gd/module.h +++ b/system/gd/module.h @@ -161,17 +161,6 @@ class ModuleRegistry { std::string last_instance_; }; -class ModuleDumper { - public: - ModuleDumper(const ModuleRegistry& module_registry, const char* title) - : module_registry_(module_registry), title_(title) {} - void DumpState(std::string* output) const; - - private: - const ModuleRegistry& module_registry_; - const std::string title_; -}; - class TestModuleRegistry : public ModuleRegistry { public: void InjectTestModule(const ModuleFactory* module, Module* instance) { diff --git a/system/gd/module_dumper.cc b/system/gd/module_dumper.cc new file mode 100644 index 0000000000000000000000000000000000000000..8a14864e162af7ea56fa61d3070008b1bf005eea --- /dev/null +++ b/system/gd/module_dumper.cc @@ -0,0 +1,71 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "BtGdModule" + +#include "module_dumper.h" + +#include "common/init_flags.h" +#include "dumpsys_data_generated.h" +#include "module.h" +#include "os/wakelock_manager.h" + +using ::bluetooth::os::WakelockManager; + +namespace bluetooth { + +void ModuleDumper::DumpState(std::string* output) const { + ASSERT(output != nullptr); + + flatbuffers::FlatBufferBuilder builder(1024); + auto title = builder.CreateString(title_); + + common::InitFlagsDataBuilder init_flags_builder(builder); + init_flags_builder.add_title(builder.CreateString("----- Init Flags -----")); + std::vector> flags; + for (const auto& flag : common::init_flags::dump()) { + flags.push_back(common::CreateInitFlagValue( + builder, + builder.CreateString(std::string(flag.flag)), + builder.CreateString(std::string(flag.value)))); + } + init_flags_builder.add_values(builder.CreateVector(flags)); + auto init_flags_offset = init_flags_builder.Finish(); + + auto wakelock_offset = WakelockManager::Get().GetDumpsysData(&builder); + + std::queue queue; + for (auto it = module_registry_.start_order_.rbegin(); it != module_registry_.start_order_.rend(); + it++) { + auto instance = module_registry_.started_modules_.find(*it); + ASSERT(instance != module_registry_.started_modules_.end()); + queue.push(instance->second->GetDumpsysData(&builder)); + } + + DumpsysDataBuilder data_builder(builder); + data_builder.add_title(title); + data_builder.add_init_flags(init_flags_offset); + data_builder.add_wakelock_manager_data(wakelock_offset); + + while (!queue.empty()) { + queue.front()(&data_builder); + queue.pop(); + } + + builder.Finish(data_builder.Finish()); + *output = std::string(builder.GetBufferPointer(), builder.GetBufferPointer() + builder.GetSize()); +} + +} // namespace bluetooth diff --git a/system/gd/btaa/wakelock_processor.h b/system/gd/module_dumper.h similarity index 63% rename from system/gd/btaa/wakelock_processor.h rename to system/gd/module_dumper.h index 8b700d2d84ba6ec3955aaefd8ca54e6bfd9eb6e6..95863c916ff58f01ef3f5dfa3c8f7ea22f195aa9 100644 --- a/system/gd/btaa/wakelock_processor.h +++ b/system/gd/module_dumper.h @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Android Open Source Project + * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +16,21 @@ #pragma once -#include -#include +#include namespace bluetooth { -namespace activity_attribution { -class WakelockProcessor { - public: - WakelockProcessor(); +class ModuleRegistry; - uint32_t OnWakelockReleased(); - void OnWakelockAcquired(); +class ModuleDumper { + public: + ModuleDumper(const ModuleRegistry& module_registry, const char* title) + : module_registry_(module_registry), title_(title) {} + void DumpState(std::string* output) const; private: - std::chrono::time_point wakelock_acquired_time_; - uint8_t wakelock_net_count_; + const ModuleRegistry& module_registry_; + const std::string title_; }; -} // namespace activity_attribution } // namespace bluetooth diff --git a/system/gd/module_dumper_flatbuffer.cc b/system/gd/module_dumper_flatbuffer.cc new file mode 100644 index 0000000000000000000000000000000000000000..aa232d27cd67f98197c6b59e36d65877e1c93802 --- /dev/null +++ b/system/gd/module_dumper_flatbuffer.cc @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module_dumper_flatbuffer.h" + +#include "dumpsys_data_generated.h" + +namespace bluetooth { +DumpsysDataFinisher EmptyDumpsysDataFinisher = [](DumpsysDataBuilder* /* dumpsys_data_builder */) { +}; +} // namespace bluetooth diff --git a/system/test/common/log_msg.h b/system/gd/module_dumper_flatbuffer.h similarity index 76% rename from system/test/common/log_msg.h rename to system/gd/module_dumper_flatbuffer.h index bb5e7c9054a661797bae32480ba3ffe73367ac1b..21b19a729134ebdf959774c3ee48a97b42dd37cd 100644 --- a/system/test/common/log_msg.h +++ b/system/gd/module_dumper_flatbuffer.h @@ -16,17 +16,13 @@ #pragma once -#include #include -#include namespace bluetooth { -namespace testing { -namespace common { -size_t get_common_log_msg_size(); -extern std::function log_msg; +struct DumpsysDataBuilder; +using DumpsysDataFinisher = std::function; + +extern DumpsysDataFinisher EmptyDumpsysDataFinisher; -} // namespace common -} // namespace testing } // namespace bluetooth diff --git a/system/gd/module_mainloop.h b/system/gd/module_mainloop.h new file mode 100644 index 0000000000000000000000000000000000000000..0f1b46085db3d351206caef6df1fd35c04809806 --- /dev/null +++ b/system/gd/module_mainloop.h @@ -0,0 +1,59 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "stack/include/main_thread.h" + +namespace bluetooth { + +class ModuleMainloop { + public: + ModuleMainloop() noexcept = default; + virtual ~ModuleMainloop() = default; + ModuleMainloop(const ModuleMainloop& mod) = delete; + + protected: + // Threadsafe post onto mainloop a function with copyable arguments + template + void PostFunctionOnMain(Functor&& functor, Args&&... args) const { + do_in_main_thread( + FROM_HERE, base::BindOnce(std::forward(functor), std::forward(args)...)); + } + + // Threadsafe post onto mainloop a method and contex with copyable arguments + template + void PostMethodOnMain(std::shared_ptr ref, Functor&& functor, Args... args) const { + do_in_main_thread( + FROM_HERE, + base::BindOnce( + [](std::weak_ptr ref, Functor&& functor, Args&&... args) { + if (std::shared_ptr spt = ref.lock()) { + base::BindOnce(std::forward(functor), spt, std::forward(args)...) + .Run(); + } + }, + std::weak_ptr(ref), + std::forward(functor), + std::forward(args)...)); + } +}; + +} // namespace bluetooth diff --git a/system/gd/module_mainloop_unittest.cc b/system/gd/module_mainloop_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..b01a50e0c1d0405c2d706df482e79d73b7df554a --- /dev/null +++ b/system/gd/module_mainloop_unittest.cc @@ -0,0 +1,247 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module_mainloop_unittest.h" + +#include +#include +#include +#include +#include + +#include + +#include "gtest/gtest.h" +#include "module.h" +#include "os/handler.h" +#include "os/log.h" +#include "os/thread.h" +#include "stack/include/main_thread.h" + +using namespace bluetooth; + +namespace { +constexpr int sync_timeout_in_ms = 3000; + +std::promise external_function_promise; +std::promise private_impl_promise; +std::promise protected_method_promise; + +} // namespace + +// Global function with C linkage +void external_function(int /* a */, double /* b */, char /* c */) { + external_function_promise.set_value(base::PlatformThread::CurrentId()); +} + +// Module private implementation that is inaccessible externally +struct TestModule::PrivateImpl : public ModuleMainloop { + const int kMaxTestModuleRecurseDepth = 10; + + void privateCallableMethod(int /* a */, double /* b */, char /* c */) { + private_impl_promise.set_value(base::PlatformThread::CurrentId()); + } + + void repostMethodTest(int /* a */, double /* b */, char /* c */) { + private_impl_promise.set_value(base::PlatformThread::CurrentId()); + } + + void privateCallableRepostMethod( + std::shared_ptr ptr, int a, double b, char c) { + PostMethodOnMain(ptr, &PrivateImpl::repostMethodTest, a, b, c); + } + + void privateCallableRecursiveMethod( + std::shared_ptr ptr, int depth, double b, char c) { + if (depth > kMaxTestModuleRecurseDepth) { + private_impl_promise.set_value(base::PlatformThread::CurrentId()); + return; + } + PostMethodOnMain(ptr, &PrivateImpl::privateCallableRecursiveMethod, ptr, depth + 1, b, c); + } +}; + +// Protected module method executed on handler +void TestModule::call_on_handler_protected_method(int handler_tid, int a, int b, int c) { + protected_method_promise = std::promise(); + auto future = protected_method_promise.get_future(); + CallOn(this, &TestModule::protected_method, a, b, c); + ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready); + ASSERT_EQ(future.get(), handler_tid); +} + +// Global external function executed on main loop +void TestModule::call_on_main_external_function(int mainloop_tid, int a, double b, char c) { + external_function_promise = std::promise(); + auto future = external_function_promise.get_future(); + PostFunctionOnMain(&external_function, a, b, c); + ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready); + ASSERT_EQ(future.get(), mainloop_tid); +} + +// Private implementation method executed on main loop +void TestModule::call_on_main(int mainloop_tid, int a, int b, int c) { + private_impl_promise = std::promise(); + auto future = private_impl_promise.get_future(); + PostMethodOnMain(pimpl_, &TestModule::PrivateImpl::privateCallableMethod, a, b, c); + ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready); + ASSERT_EQ(future.get(), mainloop_tid); +} + +// Private implementation method executed on main loop and reposted +void TestModule::call_on_main_repost(int mainloop_tid, int a, int b, int c) { + private_impl_promise = std::promise(); + auto future = private_impl_promise.get_future(); + PostMethodOnMain(pimpl_, &TestModule::PrivateImpl::privateCallableRepostMethod, pimpl_, a, b, c); + ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready); + ASSERT_EQ(future.get(), mainloop_tid); +} + +// Private implementation method executed on main loop recursively +void TestModule::call_on_main_recurse(int mainloop_tid, int depth, int b, int c) { + private_impl_promise = std::promise(); + auto future = private_impl_promise.get_future(); + PostMethodOnMain( + pimpl_, &TestModule::PrivateImpl::privateCallableRecursiveMethod, pimpl_, depth, b, c); + ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready); + ASSERT_EQ(future.get(), mainloop_tid); +} + +void TestModule::protected_method(int /* a */, int /* b */, int /* c */) { + protected_method_promise.set_value(base::PlatformThread::CurrentId()); +} + +bool TestModule::IsStarted() const { + return pimpl_ != nullptr; +} + +void TestModule::Start() { + ASSERT_FALSE(IsStarted()); + pimpl_ = std::make_shared(); +} + +void TestModule::Stop() { + ASSERT_TRUE(IsStarted()); + pimpl_.reset(); +} + +std::string TestModule::ToString() const { + return std::string(__func__); +} + +const bluetooth::ModuleFactory TestModule::Factory = + bluetooth::ModuleFactory([]() { return new TestModule(); }); + +// +// Module GDx Testing Below +// +class ModuleGdxTest : public ::testing::Test { + protected: + void SetUp() override { + test_framework_tid_ = base::PlatformThread::CurrentId(); + module_ = new TestModule(); + main_thread_start_up(); + mainloop_tid_ = get_mainloop_tid(); + } + + void TearDown() override { + sync_main_handler(); + main_thread_shut_down(); + delete module_; + } + + void sync_main_handler() { + std::promise promise = std::promise(); + std::future future = promise.get_future(); + post_on_bt_main([&promise]() { promise.set_value(); }); + future.wait_for(std::chrono::milliseconds(sync_timeout_in_ms)); + }; + + static pid_t get_mainloop_tid() { + std::promise pid_promise = std::promise(); + auto future = pid_promise.get_future(); + post_on_bt_main([&pid_promise]() { pid_promise.set_value(base::PlatformThread::CurrentId()); }); + return future.get(); + } + + pid_t test_framework_tid_{-1}; + pid_t mainloop_tid_{-1}; + TestModuleRegistry module_registry_; + TestModule* module_; +}; + +class ModuleGdxWithStackTest : public ModuleGdxTest { + protected: + void SetUp() override { + ModuleGdxTest::SetUp(); + module_registry_.InjectTestModule(&TestModule::Factory, module_ /* pass ownership */); + module_ = nullptr; // ownership is passed + handler_tid_ = get_handler_tid(module_registry_.GetTestModuleHandler(&TestModule::Factory)); + } + + static pid_t get_handler_tid(os::Handler* handler) { + std::promise handler_tid_promise = std::promise(); + std::future future = handler_tid_promise.get_future(); + handler->Post(common::BindOnce( + [](std::promise promise) { promise.set_value(base::PlatformThread::CurrentId()); }, + std::move(handler_tid_promise))); + return future.get(); + } + + void TearDown() override { + module_registry_.StopAll(); + ModuleGdxTest::TearDown(); + } + + TestModule* Mod() { + return module_registry_.GetModuleUnderTest(); + } + + pid_t handler_tid_{-1}; +}; + +TEST_F(ModuleGdxTest, nop) {} + +TEST_F(ModuleGdxTest, lifecycle) { + ::bluetooth::os::Thread* thread = + new bluetooth::os::Thread("Name", bluetooth::os::Thread::Priority::REAL_TIME); + ASSERT_FALSE(module_registry_.IsStarted()); + module_registry_.Start(thread); + ASSERT_TRUE(module_registry_.IsStarted()); + module_registry_.StopAll(); + ASSERT_FALSE(module_registry_.IsStarted()); + delete thread; +} + +TEST_F(ModuleGdxWithStackTest, call_on_handler_protected_method) { + Mod()->call_on_handler_protected_method(handler_tid_, 1, 2, 3); +} + +TEST_F(ModuleGdxWithStackTest, test_call_on_main) { + Mod()->call_on_main(mainloop_tid_, 1, 2, 3); +} + +TEST_F(ModuleGdxWithStackTest, test_call_external_function) { + Mod()->call_on_main_external_function(mainloop_tid_, 1, 2.3, 'c'); +} + +TEST_F(ModuleGdxWithStackTest, test_call_on_main_repost) { + Mod()->call_on_main_repost(mainloop_tid_, 1, 2, 3); +} + +TEST_F(ModuleGdxWithStackTest, test_call_on_main_recurse) { + Mod()->call_on_main_recurse(mainloop_tid_, 1, 2, 3); +} diff --git a/system/gd/module_mainloop_unittest.h b/system/gd/module_mainloop_unittest.h new file mode 100644 index 0000000000000000000000000000000000000000..bafc44e60602dbae182e39bfe7b568131a0f7f14 --- /dev/null +++ b/system/gd/module_mainloop_unittest.h @@ -0,0 +1,57 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "module.h" +#include "module_mainloop.h" + +using namespace bluetooth; + +void external_function(int /* a */, double /* b */, char /* c */); + +class TestModule : public Module, public ModuleMainloop { + public: + void call_on_handler_protected_method(pid_t tid, int a, int b, int c); + void call_on_main_external_function(pid_t tid, int a, double b, char c); + void call_on_main(pid_t tid, int a, int b, int c); + void call_on_main_repost(pid_t tid, int a, int b, int c); + void call_on_main_recurse(pid_t tid, int a, int b, int c); + + static const bluetooth::ModuleFactory Factory; + + protected: + void protected_method(int a, int b, int c); + void call_on_main_internal(int a, int b, int c); + bool IsStarted() const; + + void ListDependencies(bluetooth::ModuleList* /* list */) const override {} + void Start() override; + void Stop() override; + std::string ToString() const override; + + private: + struct PrivateImpl; + std::shared_ptr pimpl_; + + bool started_ = false; + + friend bluetooth::ModuleRegistry; +}; diff --git a/system/gd/module_unittest.cc b/system/gd/module_unittest.cc index 975c04acfbf2b8244b067f1b131f1d806748379e..ab5d52d0f7a563398679dd12f95e30aa04daa90c 100644 --- a/system/gd/module_unittest.cc +++ b/system/gd/module_unittest.cc @@ -15,16 +15,17 @@ */ #include "module.h" -#include "module_unittest_generated.h" -#include "os/handler.h" -#include "os/thread.h" - -#include "gtest/gtest.h" #include -#include #include +#include "dumpsys_data_generated.h" +#include "gtest/gtest.h" +#include "module_dumper.h" +#include "module_unittest_generated.h" +#include "os/handler.h" +#include "os/thread.h" + using ::bluetooth::os::Thread; namespace bluetooth { @@ -53,7 +54,7 @@ class TestModuleNoDependency : public Module { static const ModuleFactory Factory; protected: - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} void Start() override { // A module is not considered started until Start() finishes @@ -116,7 +117,7 @@ class TestModuleNoDependencyTwo : public Module { static const ModuleFactory Factory; protected: - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} void Start() override { // A module is not considered started until Start() finishes diff --git a/system/gd/neighbor/facade/facade.cc b/system/gd/neighbor/facade/facade.cc index 8056cf778e4800038db76095221ae975a36deb6d..58d106bc7e7ce75883d3341705b99fc8a37ff480 100644 --- a/system/gd/neighbor/facade/facade.cc +++ b/system/gd/neighbor/facade/facade.cc @@ -52,7 +52,9 @@ class NeighborFacadeService : public NeighborFacade::Service { facade_handler_(facade_handler) {} ::grpc::Status SetConnectability( - ::grpc::ServerContext* context, const EnableMsg* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const EnableMsg* request, + ::google::protobuf::Empty* /* response */) override { if (request->enabled()) { connectability_module_->StartConnectability(); } else { @@ -62,9 +64,9 @@ class NeighborFacadeService : public NeighborFacade::Service { } ::grpc::Status SetDiscoverability( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const DiscoverabilitiyMsg* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { switch (request->mode()) { case DiscoverabilityMode::OFF: discoverability_module_->StopDiscoverability(); @@ -116,9 +118,9 @@ class NeighborFacadeService : public NeighborFacade::Service { } ::grpc::Status ReadRemoteName( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const RemoteNameRequestMsg* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address remote; ASSERT(hci::Address::FromString(request->address(), remote)); hci::PageScanRepetitionMode mode; @@ -143,21 +145,23 @@ class NeighborFacadeService : public NeighborFacade::Service { request->clock_offset(), request->clock_offset() != 0 ? hci::ClockOffsetValid::VALID : hci::ClockOffsetValid::INVALID), - facade_handler_->BindOnce([](hci::ErrorCode status) { /* ignore */ }), - facade_handler_->BindOnce([](uint64_t features) { /* ignore */ }), + facade_handler_->BindOnce([](hci::ErrorCode /* status */) { /* ignore */ }), + facade_handler_->BindOnce([](uint64_t /* features */) { /* ignore */ }), facade_handler_->BindOnceOn(this, &NeighborFacadeService::on_remote_name, remote)); return ::grpc::Status::OK; } ::grpc::Status GetRemoteNameEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return pending_remote_names_.RunLoop(context, writer); } ::grpc::Status EnableInquiryScan( - ::grpc::ServerContext* context, const EnableMsg* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const EnableMsg* request, + ::google::protobuf::Empty* /* response */) override { if (request->enabled()) { scan_module_->SetInquiryScan(); } else { @@ -167,7 +171,9 @@ class NeighborFacadeService : public NeighborFacade::Service { } ::grpc::Status EnablePageScan( - ::grpc::ServerContext* context, const EnableMsg* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const EnableMsg* request, + ::google::protobuf::Empty* /* response */) override { if (request->enabled()) { scan_module_->SetPageScan(); } else { diff --git a/system/gd/neighbor/inquiry_test.cc b/system/gd/neighbor/inquiry_test.cc index 3833e21c380c18575f0d02f54ca566b9b64b6260..b072c66ef488e51a570a66e888504e57a8111bf1 100644 --- a/system/gd/neighbor/inquiry_test.cc +++ b/system/gd/neighbor/inquiry_test.cc @@ -294,7 +294,7 @@ class TestHciLayer : public hci::HciLayer { inquiry_result_callback_.Invoke(std::move(view)); } - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} void Start() override {} void Stop() override {} diff --git a/system/gd/neighbor/name_db.cc b/system/gd/neighbor/name_db.cc index dc20ece0078ef0a438e206ad0fdc2a16f1407b88..e7f9d56ee28f9236c0c477f9781520d1629e6246 100644 --- a/system/gd/neighbor/name_db.cc +++ b/system/gd/neighbor/name_db.cc @@ -87,14 +87,10 @@ void neighbor::NameDbModule::impl::ReadRemoteNameRequest( address, hci::RemoteNameRequestBuilder::Create( address, page_scan_repetition_mode, clock_offset, clock_offset_valid), - handler_->BindOnce( - [](neighbor::NameDbModule::impl* self, hci::Address address, hci::ErrorCode status) { - self->OnRemoteNameResponse(address, status, {}); - }, - common::Unretained(this), - address), - handler_->BindOnce( - [&](uint64_t features) { LOG_WARN("UNIMPLEMENTED: ignoring host supported features"); }), + handler_->BindOnce([](hci::ErrorCode /* status */) {}), + handler_->BindOnce([&](uint64_t /* features */) { + LOG_WARN("UNIMPLEMENTED: ignoring host supported features"); + }), handler_->BindOnceOn(this, &NameDbModule::impl::OnRemoteNameResponse, address)); } diff --git a/system/gd/os/android/metrics.cc b/system/gd/os/android/metrics.cc index f45d282817230c6de4cee1797af87502698cf3a6..a64f3319350b1254660b026e5548f3df565794c6 100644 --- a/system/gd/os/android/metrics.cc +++ b/system/gd/os/android/metrics.cc @@ -177,7 +177,10 @@ void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int } void LogMetricHfpPacketLossStats( - const Address& address, int num_decoded_frames, double packet_loss_ratio) {} + const Address& /* address */, + int /* num_decoded_frames */, + double /* packet_loss_ratio */, + uint16_t /* codec_type */) {} void LogMetricReadRssiResult(const Address& address, uint16_t handle, uint32_t cmd_status, int8_t rssi) { int metric_id = 0; @@ -429,7 +432,8 @@ void LogMetricBluetoothHalCrashReason( } void LogMetricBluetoothLocalSupportedFeatures(uint32_t page_num, uint64_t features) { - int ret = stats_write(BLUETOOTH_LOCAL_SUPPORTED_FEATURES_REPORTED, page_num, features); + int ret = stats_write( + BLUETOOTH_LOCAL_SUPPORTED_FEATURES_REPORTED, page_num, static_cast(features)); if (ret < 0) { LOG_WARN( "Failed for LogMetricBluetoothLocalSupportedFeatures, " @@ -490,7 +494,12 @@ void LogMetricBluetoothRemoteSupportedFeatures( if (!address.IsEmpty()) { metric_id = MetricIdManager::GetInstance().AllocateId(address); } - int ret = stats_write(BLUETOOTH_REMOTE_SUPPORTED_FEATURES_REPORTED, metric_id, page, features, connection_handle); + int ret = stats_write( + BLUETOOTH_REMOTE_SUPPORTED_FEATURES_REPORTED, + metric_id, + page, + static_cast(features), + connection_handle); if (ret < 0) { LOG_WARN( "Failed for LogMetricBluetoothRemoteSupportedFeatures, " diff --git a/system/gd/os/android/wakelock_native.cc b/system/gd/os/android/wakelock_native.cc index 20dbdeb8aa135ec2a3eb6fdbe89c31efc4da09c4..f3425fabe6930c5e57809c580dbf473d61f2ede9 100644 --- a/system/gd/os/android/wakelock_native.cc +++ b/system/gd/os/android/wakelock_native.cc @@ -24,11 +24,11 @@ #include #include #include - #include #include #include +#include #include // We want the os/log.h definitions @@ -108,7 +108,7 @@ WakelockNative::StatusCode WakelockNative::Acquire(const std::string& lock_name) return StatusCode::SUCCESS; } -WakelockNative::StatusCode WakelockNative::Release(const std::string& lock_name) { +WakelockNative::StatusCode WakelockNative::Release(const std::string& /* lock_name */) { if (!pimpl_->current_wakelock) { LOG_WARN("no lock is currently acquired"); return StatusCode::SUCCESS; diff --git a/system/gd/os/android/wakelock_native_test.cc b/system/gd/os/android/wakelock_native_test.cc index 7bc7841a924639b678866b549dbc3c9c5306e7ed..66c2204e3062b8d011704ec76a7d52c96f6f033e 100644 --- a/system/gd/os/android/wakelock_native_test.cc +++ b/system/gd/os/android/wakelock_native_test.cc @@ -106,7 +106,8 @@ class WakelockCallback : public BnWakelockCallback { class SuspendCallback : public BnSuspendCallback { public: - ScopedAStatus notifyWakeup(bool success, const std::vector& wakeup_reasons) override { + ScopedAStatus notifyWakeup( + bool /* success */, const std::vector& /* wakeup_reasons */) override { std::lock_guard lock_guard(mutex); fprintf(stderr, "notifyWakeup\n"); return ScopedAStatus::ok(); @@ -271,4 +272,4 @@ TEST_F(WakelockNativeTest, test_clean_up) { ASSERT_EQ(control_callback->net_acquired_count, 0); } -} // namespace testing \ No newline at end of file +} // namespace testing diff --git a/system/gd/os/chromeos/metrics.cc b/system/gd/os/chromeos/metrics.cc index cfef9173db52836c042cd853fd4e6932347ac9a2..76023230ead7117e564f2a8a8b4d58ef12ffd7f6 100644 --- a/system/gd/os/chromeos/metrics.cc +++ b/system/gd/os/chromeos/metrics.cc @@ -86,7 +86,7 @@ void LogMetricA2dpAudioOverrunEvent( } void LogMetricHfpPacketLossStats( - const Address& address, int num_decoded_frames, double packet_loss_ratio) { + const Address& address, int num_decoded_frames, double packet_loss_ratio, uint16_t codec_type) { std::string boot_id; std::string addr_string; @@ -95,17 +95,42 @@ void LogMetricHfpPacketLossStats( addr_string = address.ToString(); LOG_DEBUG( - "HfpPacketLoss: %s, %s, %d, %f", + "HfpPacketLoss: %s, %s, %d, %f, %u", boot_id.c_str(), addr_string.c_str(), num_decoded_frames, - packet_loss_ratio); + packet_loss_ratio, + codec_type); ::metrics::structured::events::bluetooth::BluetoothHfpPacketLoss() .SetBootId(boot_id) .SetDeviceId(addr_string) .SetDecodedFrames(num_decoded_frames) .SetPacketLossRatio(packet_loss_ratio) + .SetCodecType(codec_type) + .Record(); +} + +void LogMetricMmcTranscodeRttStats( + int maximum_rtt, double mean_rtt, int num_requests, int codec_type) { + std::string boot_id; + + if (!metrics::GetBootId(&boot_id)) return; + + LOG_DEBUG( + "MmcTranscodeRttStats: %s, %d, %f, %d, %d", + boot_id.c_str(), + maximum_rtt, + mean_rtt, + num_requests, + codec_type); + + ::metrics::structured::events::bluetooth::BluetoothMmcTranscodeRtt() + .SetBootId(boot_id) + .SetMaximumRtt(maximum_rtt) + .SetMeanRtt(mean_rtt) + .SetNumRequests(num_requests) + .SetCodecType(codec_type) .Record(); } diff --git a/system/gd/os/fake_timer/fake_timerfd.cc b/system/gd/os/fake_timer/fake_timerfd.cc index f4b240eb8cacd28e3cffea03e088418b7a711284..54785b3d940db4ac646fa83e86b96fd233fb0da2 100644 --- a/system/gd/os/fake_timer/fake_timerfd.cc +++ b/system/gd/os/fake_timer/fake_timerfd.cc @@ -41,7 +41,7 @@ static uint64_t timespec_to_ms(const timespec* t) { return t->tv_sec * 1000 + t->tv_nsec / 1000000; } -int fake_timerfd_create(int clockid, int flags) { +int fake_timerfd_create(int /* clockid */, int /* flags */) { int fd = eventfd(0, EFD_SEMAPHORE); if (fd == -1) { return fd; @@ -53,7 +53,11 @@ int fake_timerfd_create(int clockid, int flags) { return fd; } -int fake_timerfd_settime(int fd, int flags, const struct itimerspec* new_value, struct itimerspec* old_value) { +int fake_timerfd_settime( + int fd, + int /* flags */, + const struct itimerspec* new_value, + struct itimerspec* /* old_value */) { if (fake_timers.find(fd) == fake_timers.end()) { return -1; } diff --git a/system/gd/os/host/metrics.cc b/system/gd/os/host/metrics.cc index 3de27662e8a8fb3e52339f727edaefcbadba9c05..d2c3b900d39bf2f551abfbf87a2930a3a5f04760 100644 --- a/system/gd/os/host/metrics.cc +++ b/system/gd/os/host/metrics.cc @@ -25,112 +25,141 @@ namespace os { using bluetooth::hci::Address; void LogMetricClassicPairingEvent( - const Address& address, - uint16_t handle, - uint32_t hci_cmd, - uint16_t hci_event, - uint16_t cmd_status, - uint16_t reason_code, - int64_t event_value) {} + const Address& /* address */, + uint16_t /* handle */, + uint32_t /* hci_cmd */, + uint16_t /* hci_event */, + uint16_t /* cmd_status */, + uint16_t /* reason_code */, + int64_t /* event_value */) {} void LogMetricSocketConnectionState( - const Address& address, - int port, - int type, - android::bluetooth::SocketConnectionstateEnum connection_state, - int64_t tx_bytes, - int64_t rx_bytes, - int uid, - int server_port, - android::bluetooth::SocketRoleEnum socket_role) {} - -void LogMetricHciTimeoutEvent(uint32_t hci_cmd) {} + const Address& /* address */, + int /* port */, + int /* type */, + android::bluetooth::SocketConnectionstateEnum /* connection_state */, + int64_t /* tx_bytes */, + int64_t /* rx_bytes */, + int /* uid */, + int /* server_port */, + android::bluetooth::SocketRoleEnum /* socket_role */) {} + +void LogMetricHciTimeoutEvent(uint32_t /* hci_cmd */) {} void LogMetricA2dpAudioUnderrunEvent( - const Address& address, uint64_t encoding_interval_millis, int num_missing_pcm_bytes) {} + const Address& /* address */, + uint64_t /* encoding_interval_millis */, + int /* num_missing_pcm_bytes */) {} void LogMetricA2dpAudioOverrunEvent( - const Address& address, - uint64_t encoding_interval_millis, - int num_dropped_buffers, - int num_dropped_encoded_frames, - int num_dropped_encoded_bytes) {} + const Address& /* address */, + uint64_t /* encoding_interval_millis */, + int /* num_dropped_buffers */, + int /* num_dropped_encoded_frames */, + int /* num_dropped_encoded_bytes */) {} void LogMetricHfpPacketLossStats( - const Address& address, int num_decoded_frames, double packet_loss_ratio) {} + const Address& /* address */, + int /* num_decoded_frames */, + double /* packet_loss_ratio */, + uint16_t /* codec_type */) {} -void LogMetricReadRssiResult(const Address& address, uint16_t handle, uint32_t cmd_status, int8_t rssi) {} +void LogMetricMmcTranscodeRttStats( + int /* maximum_rtt */, double /* mean_rtt */, int /* num_requests */, int /* codec_type */) {} + +void LogMetricReadRssiResult( + const Address& /* address */, + uint16_t /* handle */, + uint32_t /* cmd_status */, + int8_t /* rssi */) {} void LogMetricReadFailedContactCounterResult( - const Address& address, uint16_t handle, uint32_t cmd_status, int32_t failed_contact_counter) {} + const Address& /* address */, + uint16_t /* handle */, + uint32_t /* cmd_status */, + int32_t /* failed_contact_counter */) {} void LogMetricReadTxPowerLevelResult( - const Address& address, uint16_t handle, uint32_t cmd_status, int32_t transmit_power_level) {} + const Address& /* address */, + uint16_t /* handle */, + uint32_t /* cmd_status */, + int32_t /* transmit_power_level */) {} void LogMetricRemoteVersionInfo( - uint16_t handle, uint8_t status, uint8_t version, uint16_t manufacturer_name, uint16_t subversion) {} + uint16_t /* handle */, + uint8_t /* status */, + uint8_t /* version */, + uint16_t /* manufacturer_name */, + uint16_t /* subversion */) {} void LogMetricLinkLayerConnectionEvent( - const Address* address, - uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, - uint16_t link_type, - uint32_t hci_cmd, - uint16_t hci_event, - uint16_t hci_ble_event, - uint16_t cmd_status, - uint16_t reason_code) {} + const Address* /* address */, + uint32_t /* connection_handle */, + android::bluetooth::DirectionEnum /* direction */, + uint16_t /* link_type */, + uint32_t /* hci_cmd */, + uint16_t /* hci_event */, + uint16_t /* hci_ble_event */, + uint16_t /* cmd_status */, + uint16_t /* reason_code */) {} void LogMetricManufacturerInfo( - const Address& address, - android::bluetooth::AddressTypeEnum address_type, - android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, - const std::string& manufacturer, - const std::string& model, - const std::string& hardware_version, - const std::string& software_version) {} + const Address& /* address */, + android::bluetooth::AddressTypeEnum /* address_type */, + android::bluetooth::DeviceInfoSrcEnum /* source_type */, + const std::string& /* source_name */, + const std::string& /* manufacturer */, + const std::string& /* model */, + const std::string& /* hardware_version */, + const std::string& /* software_version */) {} void LogMetricSdpAttribute( - const Address& address, - uint16_t protocol_uuid, - uint16_t attribute_id, - size_t attribute_size, - const char* attribute_value) {} + const Address& /* address */, + uint16_t /* protocol_uuid */, + uint16_t /* attribute_id */, + size_t /* attribute_size */, + const char* /* attribute_value */) {} void LogMetricSmpPairingEvent( - const Address& address, uint16_t smp_cmd, android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {} + const Address& /* address */, + uint16_t /* smp_cmd */, + android::bluetooth::DirectionEnum /* direction */, + uint16_t /* smp_fail_reason */) {} -void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int audio_coding_mode) {} +void LogMetricA2dpPlaybackEvent( + const Address& /* address */, int /* playback_state */, int /* audio_coding_mode */) {} void LogMetricBluetoothHalCrashReason( - const Address& address, uint32_t error_code, uint32_t vendor_error_code) {} + const Address& /* address */, uint32_t /* error_code */, uint32_t /* vendor_error_code */) {} -void LogMetricBluetoothLocalSupportedFeatures(uint32_t page_num, uint64_t features) {} +void LogMetricBluetoothLocalSupportedFeatures(uint32_t /* page_num */, uint64_t /* features */) {} void LogMetricBluetoothLocalVersions( - uint32_t lmp_manufacturer_name, - uint8_t lmp_version, - uint32_t lmp_subversion, - uint8_t hci_version, - uint32_t hci_reversion) {} + uint32_t /* lmp_manufacturer_name */, + uint8_t /* lmp_version */, + uint32_t /* lmp_subversion */, + uint8_t /* hci_version */, + uint32_t /* hci_reversion */) {} void LogMetricBluetoothDisconnectionReasonReported( - uint32_t reason, const Address& address, uint32_t connection_handle) {} + uint32_t /* reason */, const Address& /* address */, uint32_t /* connection_handle */) {} void LogMetricBluetoothRemoteSupportedFeatures( - const Address& address, uint32_t page, uint64_t features, uint32_t connection_handle) {} + const Address& /* address */, + uint32_t /* page */, + uint64_t /* features */, + uint32_t /* connection_handle */) {} -void LogMetricBluetoothCodePathCounterMetrics(int32_t key, int64_t count) {} +void LogMetricBluetoothCodePathCounterMetrics(int32_t /* key */, int64_t /* count */) {} void LogMetricBluetoothLEConnectionMetricEvent( - const Address& address, - android::bluetooth::le::LeConnectionOriginType origin_type, - android::bluetooth::le::LeConnectionType connection_type, - android::bluetooth::le::LeConnectionState transaction_state, - std::vector>& argument_list) {} + const Address& /* address */, + android::bluetooth::le::LeConnectionOriginType /* origin_type */, + android::bluetooth::le::LeConnectionType /* connection_type */, + android::bluetooth::le::LeConnectionState /* transaction_state */, + std::vector>& /* argument_list */) {} -void LogMetricBluetoothLEConnection(os::LEConnectionSessionOptions session_options) {} +void LogMetricBluetoothLEConnection(os::LEConnectionSessionOptions /* session_options */) {} } // namespace os } // namespace bluetooth diff --git a/system/gd/os/host/parameter_provider.cc b/system/gd/os/host/parameter_provider.cc index aee9b1659cf27d3d281dd9102729023fa6607663..4653790ff5f22465717a28c41aa91d2ac804d787 100644 --- a/system/gd/os/host/parameter_provider.cc +++ b/system/gd/os/host/parameter_provider.cc @@ -104,19 +104,20 @@ bluetooth_keystore::BluetoothKeystoreInterface* ParameterProvider::GetBtKeystore return nullptr; } -void ParameterProvider::SetBtKeystoreInterface(bluetooth_keystore::BluetoothKeystoreInterface* bt_keystore) {} +void ParameterProvider::SetBtKeystoreInterface( + bluetooth_keystore::BluetoothKeystoreInterface* /* bt_keystore */) {} bool ParameterProvider::IsCommonCriteriaMode() { return false; } -void ParameterProvider::SetCommonCriteriaMode(bool enable) {} +void ParameterProvider::SetCommonCriteriaMode(bool /* enable */) {} int ParameterProvider::GetCommonCriteriaConfigCompareResult() { return 0b11; } -void ParameterProvider::SetCommonCriteriaConfigCompareResult(int result) {} +void ParameterProvider::SetCommonCriteriaConfigCompareResult(int /* result */) {} } // namespace os -} // namespace bluetooth \ No newline at end of file +} // namespace bluetooth diff --git a/system/gd/os/host/wakelock_native.cc b/system/gd/os/host/wakelock_native.cc index f173cf4fca8c45b6e5af055eb2a15b9563da6255..8817ec0a6ad61025d2b926209f889b259bc882c3 100644 --- a/system/gd/os/host/wakelock_native.cc +++ b/system/gd/os/host/wakelock_native.cc @@ -31,12 +31,12 @@ void WakelockNative::Initialize() { LOG_INFO("Host native wakelock is not implemented"); } -WakelockNative::StatusCode WakelockNative::Acquire(const std::string& lock_name) { +WakelockNative::StatusCode WakelockNative::Acquire(const std::string& /* lock_name */) { LOG_INFO("Host native wakelock is not implemented"); return StatusCode::SUCCESS; } -WakelockNative::StatusCode WakelockNative::Release(const std::string& lock_name) { +WakelockNative::StatusCode WakelockNative::Release(const std::string& /* lock_name */) { LOG_INFO("Host native wakelock is not implemented"); return StatusCode::SUCCESS; } @@ -50,4 +50,4 @@ WakelockNative::~WakelockNative() = default; } // namespace internal } // namespace os -} // namespace bluetooth \ No newline at end of file +} // namespace bluetooth diff --git a/system/gd/os/linux/metrics.cc b/system/gd/os/linux/metrics.cc index fb0a26b42e7e7edb2fb54620476bd04a436f51e3..ed653d9812a0f8165fb52a319ea1761395f2ab09 100644 --- a/system/gd/os/linux/metrics.cc +++ b/system/gd/os/linux/metrics.cc @@ -101,7 +101,11 @@ void LogMetricSmpPairingEvent( void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int audio_coding_mode) {} void LogMetricHfpPacketLossStats( - const Address& address, int num_decoded_frames, double packet_loss_ratio) {} + const Address& address, int num_decoded_frames, double packet_loss_ratio, uint16_t codec_type) { +} + +void LogMetricMmcTranscodeRttStats( + int maximum_rtt, double mean_rtt, int num_requests, int codec_type) {} void LogMetricBluetoothHalCrashReason( const Address& address, uint32_t error_code, uint32_t vendor_error_code) {} diff --git a/system/gd/os/linux_generic/alarm.cc b/system/gd/os/linux_generic/alarm.cc index f172d445b5e7b07af90b931a1298c1864629b1e3..4820018eb1a5b591ff340a9b73f3a294bfd21413 100644 --- a/system/gd/os/linux_generic/alarm.cc +++ b/system/gd/os/linux_generic/alarm.cc @@ -75,13 +75,13 @@ void Alarm::on_fire() { uint64_t times_invoked; auto bytes_read = read(fd_, ×_invoked, sizeof(uint64_t)); lock.unlock(); - std::move(task).Run(); ASSERT(bytes_read == static_cast(sizeof(uint64_t))); ASSERT_LOG( times_invoked == static_cast(1), "Invoked number of times:%lu fd:%d", (unsigned long)times_invoked, fd_); + std::move(task).Run(); } } // namespace os diff --git a/system/gd/os/linux_generic/repeating_alarm_unittest.cc b/system/gd/os/linux_generic/repeating_alarm_unittest.cc index f8aa958756e5e217ce61860775de310383d98ab3..2e2bcdf4ed478d05ddcf3c5f4952f933c93c3f04 100644 --- a/system/gd/os/linux_generic/repeating_alarm_unittest.cc +++ b/system/gd/os/linux_generic/repeating_alarm_unittest.cc @@ -68,11 +68,11 @@ class RepeatingAlarmTest : public ::testing::Test { void verify_delayed_tasks( int* counter, - std::chrono::steady_clock::time_point start_time, + std::chrono::steady_clock::time_point /* start_time */, int scheduled_tasks, std::promise* promise, - int task_length_ms, - int interval_between_tasks_ms) { + int /* task_length_ms */, + int /* interval_between_tasks_ms */) { *counter = *counter + 1; if (*counter == scheduled_tasks) { promise->set_value(); diff --git a/system/gd/os/log.h b/system/gd/os/log.h index d0a385ac7026fab51459230fad1c233ebaac4ffa..468261e86f927f1dd916e1aa1d8f2dd10b6d534b 100644 --- a/system/gd/os/log.h +++ b/system/gd/os/log.h @@ -31,99 +31,108 @@ static_assert(LOG_TAG != nullptr, "LOG_TAG should never be NULL"); #include "os/log_tags.h" #include "os/logging/log_adapter.h" +#if defined(FUZZ_TARGET) + +#define LOG_VERBOSE_INT(...) +#define LOG_DEBUG_INT(...) +#define LOG_INFO_INT(...) +#define LOG_WARN_INT(...) + +#define LOG_ERROR_INT(...) do { \ + fprintf(stderr, __VA_ARGS__); \ +} while (false) + +// for fuzz targets, we just +// need to abort in this statement +// to catch the bug +#define LOG_ALWAYS_FATAL_INT(...) do { \ + fprintf(stderr, __VA_ARGS__); \ + abort(); \ + } while (false) + +#else /* end of defined(FUZZ_TARGET) */ + #if defined(__ANDROID__) #include #include -#ifdef FUZZ_TARGET -#define LOG_VERBOSE(...) -#define LOG_DEBUG(...) -#define LOG_INFO(...) -#define LOG_WARN(...) -#else - -static_assert(LOG_TAG != nullptr, "LOG_TAG is null after header inclusion"); - #if __has_include("src/init_flags.rs.h") #include "common/init_flags.h" -#define LOG_VERBOSE(fmt, args...) \ +#define LOG_VERBOSE_INT(fmt, args...) \ do { \ if (bluetooth::common::InitFlags::GetLogLevelForTag(LOG_TAG) >= LOG_TAG_VERBOSE) { \ - ALOGV("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args); \ + ALOGV(fmt, ##args); \ } \ } while (false) -#define LOG_DEBUG(fmt, args...) \ +#define LOG_DEBUG_INT(fmt, args...) \ do { \ if (bluetooth::common::InitFlags::GetLogLevelForTag(LOG_TAG) >= LOG_TAG_DEBUG) { \ - ALOGD("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args); \ + ALOGD(fmt, ##args); \ } \ } while (false) #endif /* __has_include("src/init_flags.rs.h") */ -#define LOG_INFO(fmt, args...) ALOGI("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args) -#define LOG_WARN(fmt, args...) ALOGW("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args) -#endif /* FUZZ_TARGET */ -#define LOG_ERROR(fmt, args...) ALOGE("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args) +#define LOG_INFO_INT(fmt, args...) ALOGI(fmt, ##args) +#define LOG_WARN_INT(fmt, args...) ALOGW(fmt, ##args) +#define LOG_ERROR_INT(fmt, args...) ALOGE(fmt, ##args) +#define LOG_ALWAYS_FATAL_INT(fmt, args...) do { \ + ALOGE(fmt, ##args); \ + abort(); \ +} while (false) -#elif defined (ANDROID_EMULATOR) +#elif defined (ANDROID_EMULATOR) /* end of defined(__ANDROID__) */ // Log using android emulator logging mechanism #include "android/utils/debug.h" -#define LOGWRAPPER(fmt, args...) VERBOSE_INFO(bluetooth, "bluetooth: %s:%d - %s: " fmt, \ - __FILE__, __LINE__, __func__, ##args) +#define LOGWRAPPER(fmt, args...) VERBOSE_INFO(bluetooth, "bluetooth: " fmt, \ + ##args) -#define LOG_VEBOSE(...) LOGWRAPPER(__VA_ARGS__) -#define LOG_DEBUG(...) LOGWRAPPER(__VA_ARGS__) -#define LOG_INFO(...) LOGWRAPPER(__VA_ARGS__) -#define LOG_WARN(...) LOGWRAPPER(__VA_ARGS__) -#define LOG_ERROR(...) LOGWRAPPER(__VA_ARGS__) -#define LOG_ALWAYS_FATAL(fmt, args...) \ +#define LOG_VEBOSE_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_DEBUG_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_INFO_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_WARN_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_ERROR_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_ALWAYS_FATAL_INT(fmt, args...) \ do { \ - fprintf(stderr, "%s:%d - %s: " fmt "\n", __FILE__, __LINE__, __func__, ##args); \ + fprintf(stderr, fmt "\n", ##args); \ abort(); \ } while (false) -#elif defined(TARGET_FLOSS) +#elif defined(TARGET_FLOSS) /* end of defined (ANDROID_EMULATOR) */ #include "gd/common/init_flags.h" #include "gd/os/syslog.h" // Prefix the log with tag, file, line and function #define LOGWRAPPER(tag, fmt, args...) \ - write_syslog(tag, "%s:%s:%d - %s: " fmt, LOG_TAG, __FILE__, __LINE__, __func__, ##args) - -#ifdef FUZZ_TARGET -#define LOG_VERBOSE(...) -#define LOG_DEBUG(...) -#define LOG_INFO(...) -#define LOG_WARN(...) -#else -#define LOG_VERBOSE(...) \ + write_syslog(tag, "%s: " fmt, LOG_TAG, ##args) + +#define LOG_VERBOSE_INT(...) \ do { \ if (bluetooth::common::InitFlags::GetLogLevelForTag(LOG_TAG) >= LOG_TAG_VERBOSE) { \ LOGWRAPPER(LOG_TAG_VERBOSE, __VA_ARGS__); \ } \ } while (false) -#define LOG_DEBUG(...) \ +#define LOG_DEBUG_INT(...) \ do { \ if (bluetooth::common::InitFlags::GetLogLevelForTag(LOG_TAG) >= LOG_TAG_DEBUG) { \ LOGWRAPPER(LOG_TAG_DEBUG, __VA_ARGS__); \ } \ } while (false) -#define LOG_INFO(...) LOGWRAPPER(LOG_TAG_INFO, __VA_ARGS__) -#define LOG_WARN(...) LOGWRAPPER(LOG_TAG_WARN, __VA_ARGS__) -#endif /*FUZZ_TARGET*/ -#define LOG_ERROR(...) LOGWRAPPER(LOG_TAG_ERROR, __VA_ARGS__) +#define LOG_INFO_INT(...) LOGWRAPPER(LOG_TAG_INFO, __VA_ARGS__) +#define LOG_WARN_INT(...) LOGWRAPPER(LOG_TAG_WARN, __VA_ARGS__) +#define LOG_ERROR_INT(...) LOGWRAPPER(LOG_TAG_ERROR, __VA_ARGS__) -#define LOG_ALWAYS_FATAL(...) \ +#define LOG_ALWAYS_FATAL_INT(...) \ do { \ LOGWRAPPER(LOG_TAG_FATAL, __VA_ARGS__); \ abort(); \ } while (false) -#else +#else /* end of defined (TARGET_FLOSS) */ + /* syslog didn't work well here since we would be redefining LOG_DEBUG. */ #include #include @@ -146,50 +155,62 @@ static_assert(LOG_TAG != nullptr, "LOG_TAG is null after header inclusion"); /* pid max is 2^22 = 4194304 in 64-bit system, and 32768 by default, hence 7 digits are needed most */ \ fprintf( \ stderr, \ - "%s %7d %7ld %s - %s:%d - %s: " fmt "\n", \ + "%s %7d %7ld %s:" fmt "\n", \ _buf, \ static_cast(getpid()), \ syscall(SYS_gettid), \ LOG_TAG, \ - __FILE__, \ - __LINE__, \ - __func__, \ ##args); \ } while (false) -#ifdef FUZZ_TARGET -#define LOG_VERBOSE(...) -#define LOG_DEBUG(...) -#define LOG_INFO(...) -#define LOG_WARN(...) -#else -#define LOG_VERBOSE(fmt, args...) \ - do { \ - if (bluetooth::common::InitFlags::GetLogLevelForTag(LOG_TAG) >= LOG_TAG_VERBOSE) { \ - LOGWRAPPER(fmt, ##args); \ - } \ - } while (false) -#define LOG_DEBUG(fmt, args...) \ - do { \ - if (bluetooth::common::InitFlags::GetLogLevelForTag(LOG_TAG) >= LOG_TAG_DEBUG) { \ - LOGWRAPPER(fmt, ##args); \ - } \ - } while (false) -#define LOG_INFO(...) LOGWRAPPER(__VA_ARGS__) -#define LOG_WARN(...) LOGWRAPPER(__VA_ARGS__) -#endif /* FUZZ_TARGET */ -#define LOG_ERROR(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_VERBOSE_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_DEBUG_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_INFO_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_WARN_INT(...) LOGWRAPPER(__VA_ARGS__) +#define LOG_ERROR_INT(...) LOGWRAPPER(__VA_ARGS__) #ifndef LOG_ALWAYS_FATAL -#define LOG_ALWAYS_FATAL(...) \ - do { \ - LOGWRAPPER(__VA_ARGS__); \ - abort(); \ +#define LOG_ALWAYS_FATAL_INT(...) \ + do { \ + LOGWRAPPER(__VA_ARGS__); \ + abort(); \ } while (false) #endif #endif /* defined(__ANDROID__) */ +#endif /* defined(FUZZ_TARGET) */ + +#define _LOG_SRC_FMT_STR "%s:%d - %s: " +#define _PREPEND_SRC_LOC_IN_LOG(fmt, args...) \ + _LOG_SRC_FMT_STR fmt, __FILE__, __LINE__, __func__, ##args +// --------------------------------------------------------- +// All MACROs defined above are internal and should *not* be +// used directly (use LOG_XXX defined below instead). +// the output of LOG_XXX_INT does not contain the source +// location of the log emitting statement, so far they are only used by +// LogMsg, where the source locations is passed in. + +#define LOG_VERBOSE(fmt, args...) \ + LOG_VERBOSE_INT(_PREPEND_SRC_LOC_IN_LOG(fmt, ##args)) + +#define LOG_DEBUG(fmt, args...) \ + LOG_DEBUG_INT(_PREPEND_SRC_LOC_IN_LOG(fmt, ##args)) + +#define LOG_INFO(fmt, args...) \ + LOG_INFO_INT(_PREPEND_SRC_LOC_IN_LOG(fmt, ##args)) + +#define LOG_WARN(fmt, args...) \ + LOG_WARN_INT(_PREPEND_SRC_LOC_IN_LOG(fmt, ##args)) + +#define LOG_ERROR(fmt, args...) \ + LOG_ERROR_INT(_PREPEND_SRC_LOC_IN_LOG(fmt, ##args)) + +#ifndef LOG_ALWAYS_FATAL +#define LOG_ALWAYS_FATAL(fmt, args...) \ + LOG_ALWAYS_FATAL_INT(_PREPEND_SRC_LOC_IN_LOG(fmt, ##args)) +#endif + #define ASSERT(condition) \ do { \ if (!(condition)) { \ @@ -203,9 +224,3 @@ static_assert(LOG_TAG != nullptr, "LOG_TAG is null after header inclusion"); LOG_ALWAYS_FATAL("assertion '" #condition "' failed - " fmt, ##args); \ } \ } while (false) - -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif diff --git a/system/gd/os/logging/log_adapter.h b/system/gd/os/logging/log_adapter.h index 47e976c7d0118813daf1d9c586055b58d86b3765..4a33a0b0ac3105170b681d74d1500e6d907939bc 100644 --- a/system/gd/os/logging/log_adapter.h +++ b/system/gd/os/logging/log_adapter.h @@ -37,3 +37,14 @@ std::string ToLoggableStr(const Loggable& loggable) { #define ADDRESS_TO_LOGGABLE_STR(addr) ToLoggableStr(addr) #define ADDRESS_TO_LOGGABLE_CSTR(addr) ADDRESS_TO_LOGGABLE_STR(addr).c_str() + +#define PRIVATE_CELL(number) \ + (number \ + .replace( \ + 0, \ + (number.size() > 2) ? number.size() - 2 : 0, \ + (number.size() > 2) ? number.size() - 2 : 0, \ + '*') \ + .c_str()) + +#define PRIVATE_NAME(name) (name) diff --git a/system/gd/os/metrics.h b/system/gd/os/metrics.h index e16919fa5aaf5843576e86711bc12477af534f7d..c1703b6935609a2d0396f732f82a78995e4d0356 100644 --- a/system/gd/os/metrics.h +++ b/system/gd/os/metrics.h @@ -127,9 +127,24 @@ void LogMetricA2dpPlaybackEvent(const hci::Address& address, int playback_state, * @param address HFP device associated with this stats * @param num_decoded_frames number of decoded frames * @param packet_loss_ratio ratio of packet loss frames + * @param codec_id codec ID of the packet (mSBC=2, LC3=3) */ void LogMetricHfpPacketLossStats( - const hci::Address& address, int num_decoded_frames, double packet_loss_ratio); + const hci::Address& address, + int num_decoded_frames, + double packet_loss_ratio, + uint16_t codec_id); + +/** + * Log Mmc transcode round-trip time statistics + * + * @param maximum_rtt maximum round-trip time in this session + * @param mean_rtt the average of round-trip time in this session + * @param num_requests the number of transcoding requests in the session + * @param codec_type codec type used in this session + */ +void LogMetricMmcTranscodeRttStats( + int maximum_rtt, double mean_rtt, int num_requests, int codec_type); /** * Log read RSSI result diff --git a/system/gd/os/rand.h b/system/gd/os/rand.h index 3c38c746692d4f58a7f702bdbb39a0e0410ed63a..23d8bf08819a84e07dd646fb4c2936b7ffa74370 100644 --- a/system/gd/os/rand.h +++ b/system/gd/os/rand.h @@ -17,8 +17,12 @@ #pragma once #include +#include #include +#include + +#include "os/log.h" namespace bluetooth { namespace os { diff --git a/system/gd/os/utils.h b/system/gd/os/utils.h index 89fca66a9bc660dfc280c4662bd04a65ae99b5ce..a328afb48d63e984a297823b13f10161ccbc565e 100644 --- a/system/gd/os/utils.h +++ b/system/gd/os/utils.h @@ -15,7 +15,7 @@ */ #pragma once -#include +#include // A macro to re-try a syscall when it receives EINTR #ifndef RUN_NO_INTR diff --git a/system/gd/packet/endian_inserter.h b/system/gd/packet/endian_inserter.h index a0bc97015384506bf3302e592751b13815432169..c7f44d443a45f5dce9108966cb1923255a2464e4 100644 --- a/system/gd/packet/endian_inserter.h +++ b/system/gd/packet/endian_inserter.h @@ -38,15 +38,15 @@ class EndianInserter { virtual ~EndianInserter() = default; protected: - // Write sizeof(FixedWidthPODType) bytes using the iterator - template ::value, int>::type = 0> - void insert(FixedWidthPODType value, BitInserter& it) const { + // Write sizeof(T) bytes using the iterator + template ::value, int>::type = 0> + void insert(T value, BitInserter& it) const { uint8_t* raw_bytes = (uint8_t*)&value; - for (size_t i = 0; i < sizeof(FixedWidthPODType); i++) { + for (size_t i = 0; i < sizeof(T); i++) { if (little_endian == true) { it.insert_byte(raw_bytes[i]); } else { - it.insert_byte(raw_bytes[sizeof(FixedWidthPODType) - i - 1]); + it.insert_byte(raw_bytes[sizeof(T) - i - 1]); } } } @@ -67,10 +67,9 @@ class EndianInserter { } // Write num_bits bits using the iterator - template ::value, int>::type = 0> - void insert(FixedWidthIntegerType value, BitInserter& it, size_t num_bits) const { - ASSERT(num_bits <= (sizeof(FixedWidthIntegerType) * 8)); + template ::value, int>::type = 0> + void insert(T value, BitInserter& it, size_t num_bits) const { + ASSERT(num_bits <= (sizeof(T) * 8)); for (size_t i = 0; i < num_bits / 8; i++) { if (little_endian == true) { @@ -92,11 +91,12 @@ class EndianInserter { insert(static_cast(value), it); } - // Write a vector of FixedWidthIntegerType using the iterator - template - void insert_vector(const std::vector& vec, BitInserter& it) const { - static_assert(std::is_pod::value, - "EndianInserter::insert requires a vector with elements of a fixed-size."); + // Write a vector of T using the iterator + template ::value, int>::type = 0> + void insert_vector(const std::vector& vec, BitInserter& it) const { + static_assert( + std::is_trivial::value, + "EndianInserter::insert requires a vector with elements of a fixed-size."); for (const auto& element : vec) { insert(element, it); } diff --git a/system/gd/packet/iterator.h b/system/gd/packet/iterator.h index c1e9212dc721ee69bcbb52e695c0070bdcb87e94..0afdcd795d4deac33b3fd548c5bf1433680f56c8 100644 --- a/system/gd/packet/iterator.h +++ b/system/gd/packet/iterator.h @@ -76,15 +76,15 @@ class Iterator : public IteratorTraits { Iterator Subrange(size_t index, size_t length) const; - // Get the next sizeof(FixedWidthPODType) bytes and return the filled type - template ::value, int>::type = 0> - FixedWidthPODType extract() { - static_assert(std::is_pod::value, "Iterator::extract requires a fixed-width type."); - FixedWidthPODType extracted_value{}; + // Get the next sizeof(T) bytes and return the filled type + template ::value, int>::type = 0> + T extract() { + static_assert(std::is_trivial::value, "Iterator::extract requires a fixed-width type."); + T extracted_value{}; uint8_t* value_ptr = (uint8_t*)&extracted_value; - for (size_t i = 0; i < sizeof(FixedWidthPODType); i++) { - size_t index = (little_endian ? i : sizeof(FixedWidthPODType) - i - 1); + for (size_t i = 0; i < sizeof(T); i++) { + size_t index = (little_endian ? i : sizeof(T) - i - 1); value_ptr[index] = this->operator*(); this->operator++(); } diff --git a/system/gd/packet/parser/Android.bp b/system/gd/packet/parser/Android.bp index b506351621662483cd3ecd9f693a3b0e7ab1b6cb..21b9eb5cf66c7b721814c52f767e6c15f0d92e4e 100644 --- a/system/gd/packet/parser/Android.bp +++ b/system/gd/packet/parser/Android.bp @@ -36,7 +36,6 @@ cc_binary_host { "fields/variable_length_struct_field.cc", "fields/vector_field.cc", "gen_cpp.cc", - "gen_rust.cc", "language_l.ll", "language_y.yy", "main.cc", diff --git a/system/gd/packet/parser/BUILD.gn b/system/gd/packet/parser/BUILD.gn index c9ac6c35d97b213933957eced1720d4154fd82b7..ce2b820b1264b67d6c22f813abeb1089a9152b4a 100644 --- a/system/gd/packet/parser/BUILD.gn +++ b/system/gd/packet/parser/BUILD.gn @@ -59,7 +59,6 @@ executable("bluetooth_packetgen") { "fields/variable_length_struct_field.cc", "fields/vector_field.cc", "gen_cpp.cc", - "gen_rust.cc", "main.cc", "packet_def.cc", "packet_dependency.cc", diff --git a/system/gd/packet/parser/enum_def.h b/system/gd/packet/parser/enum_def.h index 69e8c618c6f0bfe4ddff45f0fc5e1904f1e93553..b17f1b1bb5b538284b6e9363125927ef34efe072 100644 --- a/system/gd/packet/parser/enum_def.h +++ b/system/gd/packet/parser/enum_def.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include diff --git a/system/gd/packet/parser/enum_gen.cc b/system/gd/packet/parser/enum_gen.cc index 1a2e9caa0dac0b6265b8d364c35b73bfa19bedd0..4bd5a261564dd17fafde7decf78e16e154298951 100644 --- a/system/gd/packet/parser/enum_gen.cc +++ b/system/gd/packet/parser/enum_gen.cc @@ -59,44 +59,3 @@ void EnumGen::GenLogging(std::ostream& stream) { stream << " return os << " << e_.name_ << "Text(param);"; stream << "}\n"; } - -void EnumGen::GenRustDef(std::ostream& stream) { - stream << "#[derive(FromPrimitive, ToPrimitive, Debug, Hash, Eq, PartialEq, Clone, Copy)]\n"; - stream << "#[repr(u64)]\n"; - stream << "pub enum " << e_.name_ << " {"; - for (const auto& pair : e_.constants_) { - stream << util::ConstantCaseToCamelCase(pair.second) << " = 0x" << std::hex << pair.first << std::dec << ","; - } - stream << "}"; - - stream << "impl fmt::Display for " << e_.name_ << " {"; - stream << "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {"; - stream << "match self {"; - for (const auto& pair : e_.constants_) { - stream << e_.name_ << "::" << util::ConstantCaseToCamelCase(pair.second) << " => " - << "write!(f, \"{:#0" << (util::RoundSizeUp(e_.size_) / 4) + 2 << "X} (" << pair.second << ")\", " - << "self.to_" << util::GetRustTypeForSize(e_.size_) << "().unwrap()),"; - } - stream << "}}}\n"; - - if (e_.try_from_enum_ != nullptr) { - std::vector other_items; - for (const auto& pair : e_.try_from_enum_->constants_) { - other_items.push_back(pair.second); - } - stream << "impl TryFrom<" << e_.try_from_enum_->name_ << "> for " << e_.name_ << " {"; - stream << "type Error = &'static str;"; - stream << "fn try_from(value: " << e_.try_from_enum_->name_ << ") -> std::result::Result {"; - stream << "match value {"; - for (const auto& pair : e_.constants_) { - if (std::find(other_items.begin(), other_items.end(), pair.second) == other_items.end()) { - continue; - } - auto constant_name = util::ConstantCaseToCamelCase(pair.second); - stream << e_.try_from_enum_->name_ << "::" << constant_name << " => Ok(" << e_.name_ << "::" << constant_name - << "),"; - } - stream << "_ => Err(\"No mapping for provided key\"),"; - stream << "}}}"; - } -} diff --git a/system/gd/packet/parser/enum_gen.h b/system/gd/packet/parser/enum_gen.h index 5586dfcdb679c0fc704cc265ef80fa515a31d9ff..be165598511dcec3260e36694a0371716f591ed6 100644 --- a/system/gd/packet/parser/enum_gen.h +++ b/system/gd/packet/parser/enum_gen.h @@ -31,7 +31,5 @@ class EnumGen { void GenLogging(std::ostream& stream); - void GenRustDef(std::ostream& stream); - EnumDef e_; }; diff --git a/system/gd/packet/parser/fields/array_field.cc b/system/gd/packet/parser/fields/array_field.cc index c95734d09869e36c9be4aa7f2b896b2da529e9cd..33cfb1be6b4e1bf800ad95b550bb2c9363fdd30f 100644 --- a/system/gd/packet/parser/fields/array_field.cc +++ b/system/gd/packet/parser/fields/array_field.cc @@ -195,19 +195,3 @@ void ArrayField::GenStringRepresentation(std::ostream& s, std::string accessor) s << ";}"; s << "ss << \"]\""; } - -std::string ArrayField::GetRustDataType() const { - return "[" + element_field_->GetRustDataType() + "; " + std::to_string(array_size_) + "]"; -} - -void ArrayField::GenRustGetter(std::ostream& s, Size start_offset, Size, std::string) const { - s << "let " << GetName() << " = "; - s << "bytes[" << start_offset.bytes() << ".."; - s << start_offset.bytes() + GetSize().bytes() << "].try_into()"; - s << ".map_err(|_| Error::InvalidPacketError)?;"; -} - -void ArrayField::GenRustWriter(std::ostream& s, Size start_offset, Size) const { - s << "&buffer[" << start_offset.bytes() << ".." << start_offset.bytes() + GetSize().bytes() - << "].copy_from_slice(&self." << GetName() << ");"; -} diff --git a/system/gd/packet/parser/fields/array_field.h b/system/gd/packet/parser/fields/array_field.h index d19a069edbbffa238c364001486d744bd17c2f88..e31e8de006a2dcddb3b864c8e57b5cfe19d984a0 100644 --- a/system/gd/packet/parser/fields/array_field.h +++ b/system/gd/packet/parser/fields/array_field.h @@ -64,12 +64,6 @@ class ArrayField : public PacketField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string parent_name) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - const std::string name_; const PacketField* element_field_{nullptr}; diff --git a/system/gd/packet/parser/fields/body_field.cc b/system/gd/packet/parser/fields/body_field.cc index d0d61dd52fd0d4c9755b4d75b30dcbef1cb3f469..cab1af529d98e38efb199c569519694fd833a1a8 100644 --- a/system/gd/packet/parser/fields/body_field.cc +++ b/system/gd/packet/parser/fields/body_field.cc @@ -75,11 +75,3 @@ void BodyField::GenValidator(std::ostream&) const { void BodyField::GenStringRepresentation(std::ostream& s, std::string accessor) const { s << "\"BODY REPRESENTATION_UNIMPLEMENTED " << accessor << " \""; } - -std::string BodyField::GetRustDataType() const { - return GetDataType(); -} - -void BodyField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} - -void BodyField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/body_field.h b/system/gd/packet/parser/fields/body_field.h index 2712bf0522b39e226dfd4670bed4f2d45622eb38..d8c4ee0b390cc940ee5de69a1b0ab1ef3f9fd051 100644 --- a/system/gd/packet/parser/fields/body_field.h +++ b/system/gd/packet/parser/fields/body_field.h @@ -52,13 +52,6 @@ class BodyField : public PacketField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - - void GenBoundsCheck(std::ostream&, Size, Size, std::string) const override{}; // Body fields can only be dynamically sized. const SizeField* size_field_{nullptr}; }; diff --git a/system/gd/packet/parser/fields/checksum_field.cc b/system/gd/packet/parser/fields/checksum_field.cc index 63444505632b1ec4d6184e8d6785c156a424baaf..67863c26d71d9e0ea971ed704ca4418bf625ac56 100644 --- a/system/gd/packet/parser/fields/checksum_field.cc +++ b/system/gd/packet/parser/fields/checksum_field.cc @@ -63,7 +63,3 @@ void ChecksumField::GenStringRepresentation(std::ostream& s, std::string) const // TODO: there is currently no way to get checksum value s << "\"CHECKSUM\""; } - -void ChecksumField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} - -void ChecksumField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/checksum_field.h b/system/gd/packet/parser/fields/checksum_field.h index 3a6908e98d989cbb04a0c81e4e4c61f8ead9c052..0e0a4c2ec2a073bb4e0ae75f7acb6279d5d2f871 100644 --- a/system/gd/packet/parser/fields/checksum_field.h +++ b/system/gd/packet/parser/fields/checksum_field.h @@ -48,10 +48,6 @@ class ChecksumField : public ScalarField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - private: std::string type_name_; }; diff --git a/system/gd/packet/parser/fields/checksum_start_field.cc b/system/gd/packet/parser/fields/checksum_start_field.cc index 22b2891679b059bc6ca955fe798a95d5d09a2bef..3f87db252f95ba529c357b9797e6a524ff7798f4 100644 --- a/system/gd/packet/parser/fields/checksum_start_field.cc +++ b/system/gd/packet/parser/fields/checksum_start_field.cc @@ -65,11 +65,3 @@ std::string ChecksumStartField::GetStartedFieldName() const { void ChecksumStartField::GenStringRepresentation(std::ostream&, std::string) const { // Print nothing for checksum start } - -std::string ChecksumStartField::GetRustDataType() const { - return GetDataType(); -} - -void ChecksumStartField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} - -void ChecksumStartField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/checksum_start_field.h b/system/gd/packet/parser/fields/checksum_start_field.h index 67ddc9568f7e51457120727a5801065f7be009f2..8c61a8219ca1a8ee380e18212f3709cce2dfdc0b 100644 --- a/system/gd/packet/parser/fields/checksum_start_field.h +++ b/system/gd/packet/parser/fields/checksum_start_field.h @@ -53,12 +53,6 @@ class ChecksumStartField : public PacketField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - private: std::string started_field_name_; }; diff --git a/system/gd/packet/parser/fields/count_field.cc b/system/gd/packet/parser/fields/count_field.cc index f4b3d907cf7cc81277617e142137597ac463d8f2..8e1cf090b64136616b820de085ce8a4f4bf63f5c 100644 --- a/system/gd/packet/parser/fields/count_field.cc +++ b/system/gd/packet/parser/fields/count_field.cc @@ -57,9 +57,3 @@ void CountField::GenValidator(std::ostream&) const { std::string CountField::GetSizedFieldName() const { return sized_field_name_; } - -void CountField::GenRustWriter(std::ostream& s, Size start_offset, Size) const { - s << "buffer[" << start_offset.bytes() << ".."; - s << start_offset.bytes() + GetSize().bytes() << "].copy_from_slice(&"; - s << "(self." << GetSizedFieldName() << ".len() as u8).to_le_bytes());"; -} diff --git a/system/gd/packet/parser/fields/count_field.h b/system/gd/packet/parser/fields/count_field.h index db7a4e71aa7db66d06d2f7c97efe9bb1385eb363..c9cb6739fc569b9396793cdeb18a95f70bf12f85 100644 --- a/system/gd/packet/parser/fields/count_field.h +++ b/system/gd/packet/parser/fields/count_field.h @@ -44,8 +44,6 @@ class CountField : public ScalarField { virtual std::string GetSizedFieldName() const; - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - private: int size_; std::string sized_field_name_; diff --git a/system/gd/packet/parser/fields/custom_field.cc b/system/gd/packet/parser/fields/custom_field.cc index 295fbf5ca53ab9bde1ed4ffba9b7b30502feef2f..6c5900df13bebe903e760b5730c58dfe54a0bbf5 100644 --- a/system/gd/packet/parser/fields/custom_field.cc +++ b/system/gd/packet/parser/fields/custom_field.cc @@ -99,11 +99,3 @@ void CustomField::GenStringRepresentation(std::ostream& s, std::string accessor) void CustomField::GenBuilderParameterFromView(std::ostream& s) const { s << "*view.Get" << util::UnderscoreToCamelCase(GetName()) << "()"; } - -std::string CustomField::GetRustDataType() const { - return type_name_; -} - -void CustomField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} - -void CustomField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/custom_field.h b/system/gd/packet/parser/fields/custom_field.h index 25e196d2bb5a783e48ec89d257ebc87088d526f9..8e4ae8a3ff4be9419dcc6d487e3d00a1fe02e791 100644 --- a/system/gd/packet/parser/fields/custom_field.h +++ b/system/gd/packet/parser/fields/custom_field.h @@ -53,12 +53,6 @@ class CustomField : public PacketField { virtual void GenBuilderParameterFromView(std::ostream& s) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - private: std::string type_name_; }; diff --git a/system/gd/packet/parser/fields/custom_field_fixed_size.cc b/system/gd/packet/parser/fields/custom_field_fixed_size.cc index a603259d30c8a5014169f9810df932d0ce745ac0..c296438c0d621d846a8c1b0026b1c1117deef717 100644 --- a/system/gd/packet/parser/fields/custom_field_fixed_size.cc +++ b/system/gd/packet/parser/fields/custom_field_fixed_size.cc @@ -31,10 +31,6 @@ std::string CustomFieldFixedSize::GetDataType() const { return type_name_; } -std::string CustomFieldFixedSize::GetRustDataType() const { - return type_name_; -} - int CustomFieldFixedSize::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const { if (!start_offset.empty()) { // Default to start if available. @@ -72,37 +68,3 @@ void CustomFieldFixedSize::GenStringRepresentation(std::ostream& s, std::string // We assume that custom fields will have a ToString() method s << accessor << ".ToString()"; } - -std::string CustomFieldFixedSize::GetRustParseDataType() const { - return "[u8; " + std::to_string(GetSize().bytes()) + "]"; -} - -void CustomFieldFixedSize::GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const { - Size size = GetSize(); - int num_leading_bits = GetRustBitOffset(s, start_offset, end_offset, GetSize()); - if (num_leading_bits != 0) { - ERROR(this) << "must be byte aligned"; - } - if (size.bits() % 8 != 0) { - ERROR(this) << "size must be in full bytes"; - } - - s << "let " << GetName() << " = bytes[" << start_offset.bytes() << ".."; - s << start_offset.bytes() + size.bytes() << "].try_into()"; - s << ".map_err(|_| Error::InvalidPacketError)?;"; -} - -void CustomFieldFixedSize::GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const { - Size size = GetSize(); - int num_leading_bits = GetRustBitOffset(s, start_offset, end_offset, GetSize()); - if (num_leading_bits != 0) { - ERROR(this) << "must be byte aligned"; - } - if (size.bits() % 8 != 0) { - ERROR(this) << "size must be in full bytes"; - } - - s << "let " << GetName() << ": " << GetRustParseDataType() << " = self." << GetName() << ".into();"; - s << "buffer[" << start_offset.bytes() << ".." << start_offset.bytes() + GetSize().bytes() << "].copy_from_slice(&" - << GetName() << ");"; -} diff --git a/system/gd/packet/parser/fields/custom_field_fixed_size.h b/system/gd/packet/parser/fields/custom_field_fixed_size.h index b21c5d8065a7667076833e48bf80b529a95a615a..c53f0b0aede621cdc30a5bf5be972035b9fabc74 100644 --- a/system/gd/packet/parser/fields/custom_field_fixed_size.h +++ b/system/gd/packet/parser/fields/custom_field_fixed_size.h @@ -43,13 +43,5 @@ class CustomFieldFixedSize : public ScalarField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - - virtual std::string GetRustDataType() const override; - - virtual std::string GetRustParseDataType() const override; - std::string type_name_; }; diff --git a/system/gd/packet/parser/fields/enum_field.cc b/system/gd/packet/parser/fields/enum_field.cc index 49584f1caba3f19b98d8e883b8687f1f5e36c1eb..8fe56c2ff1704b42dad676085d204fa55aa3b282 100644 --- a/system/gd/packet/parser/fields/enum_field.cc +++ b/system/gd/packet/parser/fields/enum_field.cc @@ -55,7 +55,3 @@ void EnumField::GenValidator(std::ostream&) const { void EnumField::GenStringRepresentation(std::ostream& s, std::string accessor) const { s << GetDataType() << "Text(" << accessor << ")"; } - -std::string EnumField::GetRustDataType() const { - return enum_def_.name_; -} diff --git a/system/gd/packet/parser/fields/enum_field.h b/system/gd/packet/parser/fields/enum_field.h index 7d00f658447a896df150ada704ef7479661d1e32..f413553a912ef10ee709c1be0ee2ab1d1f964a97 100644 --- a/system/gd/packet/parser/fields/enum_field.h +++ b/system/gd/packet/parser/fields/enum_field.h @@ -43,8 +43,6 @@ class EnumField : public ScalarField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - virtual std::string GetRustDataType() const override; - private: EnumDef enum_def_; std::string value_; diff --git a/system/gd/packet/parser/fields/fixed_scalar_field.cc b/system/gd/packet/parser/fields/fixed_scalar_field.cc index 123787fc58e4482284820f3c82d58a54fd0f0db4..a0a83004bae89aee0bf9b356d436e18a0434cdfb 100644 --- a/system/gd/packet/parser/fields/fixed_scalar_field.cc +++ b/system/gd/packet/parser/fields/fixed_scalar_field.cc @@ -37,13 +37,3 @@ void FixedScalarField::GenValue(std::ostream& s) const { void FixedScalarField::GenStringRepresentation(std::ostream& s, std::string) const { s << value_; } - -void FixedScalarField::GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const { - s << "let " << GetName() << ": " << GetRustDataType() << " = " << value_ << ";"; - FixedField::GenRustWriter(s, start_offset, end_offset); -} - -void FixedScalarField::GenRustGetter( - std::ostream& s, Size start_offset, Size end_offset, std::string parent_name) const { - FixedField::GenRustGetter(s, start_offset, end_offset, parent_name); -} diff --git a/system/gd/packet/parser/fields/fixed_scalar_field.h b/system/gd/packet/parser/fields/fixed_scalar_field.h index 595c96df7196694cde58a194a0d8fcfc0b03cb21..44a0fa58c308e3af3e0ade53891ae202a8f3f05c 100644 --- a/system/gd/packet/parser/fields/fixed_scalar_field.h +++ b/system/gd/packet/parser/fields/fixed_scalar_field.h @@ -39,10 +39,6 @@ class FixedScalarField : public FixedField { static const std::string field_type; - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - private: const int64_t value_; diff --git a/system/gd/packet/parser/fields/group_field.cc b/system/gd/packet/parser/fields/group_field.cc index 1de8fb75f7d9e6753d6d8abe3537c34dce2eabe5..6c9ade976ac6c7ba29134ee8abbf78e35173404b 100644 --- a/system/gd/packet/parser/fields/group_field.cc +++ b/system/gd/packet/parser/fields/group_field.cc @@ -82,11 +82,3 @@ void GroupField::GenValidator(std::ostream&) const { const std::list* GroupField::GetFields() const { return fields_; } - -std::string GroupField::GetRustDataType() const { - return GetDataType(); -} - -void GroupField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} - -void GroupField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/group_field.h b/system/gd/packet/parser/fields/group_field.h index f058f986f7e535798931a570b1f5c352cea570c0..57e01651de80966eada1cc4a3bc96a8492a1d6bd 100644 --- a/system/gd/packet/parser/fields/group_field.h +++ b/system/gd/packet/parser/fields/group_field.h @@ -55,12 +55,6 @@ class GroupField : public PacketField { const std::list* GetFields() const; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - private: std::list* fields_; }; diff --git a/system/gd/packet/parser/fields/packet_field.cc b/system/gd/packet/parser/fields/packet_field.cc index 608fb28bfb4f9402955243fc4360c757e7b624a3..b51999fdf6b86533d86a05a9c1940560f90a523b 100644 --- a/system/gd/packet/parser/fields/packet_field.cc +++ b/system/gd/packet/parser/fields/packet_field.cc @@ -104,43 +104,3 @@ const PacketField* PacketField::GetElementField() const { void PacketField::GenStringRepresentation(std::ostream& s, std::string accessor) const { s << "\"REPRESENTATION_UNIMPLEMENTED " << GetFieldType() << " " << accessor << "\""; } - -int PacketField::GetRustBitOffset( - std::ostream&, Size start_offset, Size end_offset, Size size) const { - // In order to find field_begin and field_end, we must have two of the three Sizes. - if ((start_offset.empty() && size.empty()) || (start_offset.empty() && end_offset.empty()) || - (end_offset.empty() && size.empty())) { - ERROR(this) << "GenBounds called without enough information. " - << start_offset << end_offset << size; - } - - if (start_offset.bits() % 8 != 0 || end_offset.bits() % 8 != 0) { - ERROR(this) << "Can not find the bounds of a field at a non byte-aligned offset." - << start_offset << end_offset; - } - - return 0; // num_leading_bits -} - -bool PacketField::GenRustNameAndType(std::ostream& s) const { - auto param_type = GetRustDataType(); - if (param_type.empty()) { - return false; - } - s << GetName() << ": " << param_type; - return true; -} - -void PacketField::GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string parent_name) const { - Size size = GetSize(); - if (size.bits() < 8) { - return; - } - s << "if bytes.len() < " << start_offset.bytes() + size.bytes() << " {"; - s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << parent_name << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " wanted: " << start_offset.bytes() + size.bytes() << ","; - s << " got: bytes.len()});"; - s << "}"; -} diff --git a/system/gd/packet/parser/fields/packet_field.h b/system/gd/packet/parser/fields/packet_field.h index c3df79b912df9a9df6740a10d003f9a8159af64d..44be3b14c95dba31264487183c29ab9e2ae22719 100644 --- a/system/gd/packet/parser/fields/packet_field.h +++ b/system/gd/packet/parser/fields/packet_field.h @@ -115,21 +115,6 @@ class PacketField : public Loggable { virtual std::string GetName() const; - // Generate the Rust variable/field name and type - virtual bool GenRustNameAndType(std::ostream& s) const; - - // Get the type of the field to be used in the member variables. - virtual std::string GetRustDataType() const = 0; - - virtual int GetRustBitOffset( - std::ostream& s, Size start_offset, Size end_offset, Size size) const; - - virtual void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const = 0; - - virtual void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const = 0; - - virtual void GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string) const; - virtual bool GetterIsByRef() const { return true; } diff --git a/system/gd/packet/parser/fields/padding_field.cc b/system/gd/packet/parser/fields/padding_field.cc index 155bed66226748654656df32dc670a931c9c3ca1..5f438f88e9c796ed642595d4f53f7a50f5423c80 100644 --- a/system/gd/packet/parser/fields/padding_field.cc +++ b/system/gd/packet/parser/fields/padding_field.cc @@ -61,11 +61,3 @@ void PaddingField::GenInserter(std::ostream&) const { } void PaddingField::GenValidator(std::ostream&) const {} - -std::string PaddingField::GetRustDataType() const { - return "There's no type for Padding fields"; -} - -void PaddingField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} - -void PaddingField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/padding_field.h b/system/gd/packet/parser/fields/padding_field.h index ca9664f4b59c99686e785aff0507cd9c92d22359..bb99d42a0bd8dd844b52fd4d25fa3c040cc80611 100644 --- a/system/gd/packet/parser/fields/padding_field.h +++ b/system/gd/packet/parser/fields/padding_field.h @@ -51,14 +51,6 @@ class PaddingField : public PacketField { virtual void GenValidator(std::ostream&) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - - void GenBoundsCheck(std::ostream&, Size, Size, std::string) const override{}; - private: Size size_; }; diff --git a/system/gd/packet/parser/fields/payload_field.cc b/system/gd/packet/parser/fields/payload_field.cc index db51de5ebf0ff21fc887d4a72c40f2ccbe584de2..6779dade3c553f8cb6752d88c046026888016d1e 100644 --- a/system/gd/packet/parser/fields/payload_field.cc +++ b/system/gd/packet/parser/fields/payload_field.cc @@ -104,41 +104,3 @@ void PayloadField::GenStringRepresentation(std::ostream& s, std::string) const { // TODO: we should parse the child packets s << "\"PAYLOAD[]\""; } - -std::string PayloadField::GetRustDataType() const { - return "Vec::"; -} - -void PayloadField::GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string parent_name) const { - if (size_field_ != nullptr) { - s << "let want_ = " << start_offset.bytes() << " + (" << size_field_->GetName() << " as usize)"; - if (!size_modifier_.empty()) { - s << " - " << size_modifier_.substr(1); - } - s << ";"; - s << "if bytes.len() < want_ {"; - s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << parent_name << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " wanted: want_,"; - s << " got: bytes.len()});"; - s << "}"; - if (!size_modifier_.empty()) { - s << "if (" << size_field_->GetName() << " as usize) < " << size_modifier_.substr(1) << " {"; - s << " return Err(Error::ImpossibleStructError);"; - s << "}"; - } - } -} - -void PayloadField::GenRustGetter(std::ostream& s, Size start_offset, Size, std::string) const { - s << "let " << GetName() << ": " << GetRustDataType() << " = "; - if (size_field_ == nullptr) { - s << "bytes[" << start_offset.bytes() << "..].into();"; - } else { - s << "bytes[" << start_offset.bytes() << "..("; - s << start_offset.bytes() << " + " << size_field_->GetName() << " as usize)].into();"; - } -} - -void PayloadField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/payload_field.h b/system/gd/packet/parser/fields/payload_field.h index aae05fb8430e51ac334b978fdbc31e6d04f25938..b4ead5bb1fd1bd979fa49d6037bec7d4c724bb2b 100644 --- a/system/gd/packet/parser/fields/payload_field.h +++ b/system/gd/packet/parser/fields/payload_field.h @@ -56,14 +56,6 @@ class PayloadField : public PacketField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - - void GenBoundsCheck(std::ostream&, Size, Size, std::string) const override; - // Payload fields can only be dynamically sized. const SizeField* size_field_; // Only used if the size of the payload is based on another field. diff --git a/system/gd/packet/parser/fields/reserved_field.cc b/system/gd/packet/parser/fields/reserved_field.cc index 76fdf631fbace3d4ea542f3fb7a924389810bece..0acf7b720c9550eac399dcded89e96a3351ed43d 100644 --- a/system/gd/packet/parser/fields/reserved_field.cc +++ b/system/gd/packet/parser/fields/reserved_field.cc @@ -67,11 +67,3 @@ void ReservedField::GenInserter(std::ostream& s) const { void ReservedField::GenValidator(std::ostream&) const { // There is no need to validate the value of a reserved field } - -std::string ReservedField::GetRustDataType() const { - return util::GetRustTypeForSize(size_); -} - -void ReservedField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} - -void ReservedField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/reserved_field.h b/system/gd/packet/parser/fields/reserved_field.h index f17418167b7ded1e04a286f96b62cb82e97bdc3b..7d363528a353762f97e7c039e53cf324227e8222 100644 --- a/system/gd/packet/parser/fields/reserved_field.h +++ b/system/gd/packet/parser/fields/reserved_field.h @@ -47,14 +47,6 @@ class ReservedField : public PacketField { virtual void GenValidator(std::ostream&) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - - void GenBoundsCheck(std::ostream&, Size, Size, std::string) const override{}; - private: std::string name_; int size_; diff --git a/system/gd/packet/parser/fields/scalar_field.cc b/system/gd/packet/parser/fields/scalar_field.cc index b44c211e75e026378393ad312927a1c1d9f41cb7..725fd3be198ddbc4c787cd6d04855ad2424c07d7 100644 --- a/system/gd/packet/parser/fields/scalar_field.cc +++ b/system/gd/packet/parser/fields/scalar_field.cc @@ -138,124 +138,3 @@ void ScalarField::GenStringRepresentation(std::ostream& s, std::string accessor) // characters otherwise. s << "static_cast(" << accessor << ")"; } - -std::string ScalarField::GetRustDataType() const { - return util::GetRustTypeForSize(size_); -} - -std::string ScalarField::GetRustParseDataType() const { - return util::GetRustTypeForSize(size_); -} - -int ScalarField::GetRustBitOffset( - std::ostream&, Size start_offset, Size end_offset, Size size) const { - int num_leading_bits = 0; - - if (!start_offset.empty()) { - // Default to start if available. - num_leading_bits = start_offset.bits() % 8; - } else if (!end_offset.empty()) { - num_leading_bits = GetShiftBits(end_offset.bits() + size.bits()); - Size byte_offset = Size(num_leading_bits + size.bits()) + end_offset; - } else { - ERROR(this) << "Ambiguous offset for field."; - } - return num_leading_bits; -} - -void ScalarField::GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string parent_name) const { - Size size = GetSize(); - - int num_leading_bits = GetRustBitOffset(s, start_offset, end_offset, GetSize()); - - s << "let " << GetName() << " = "; - auto offset = num_leading_bits == 0 ? 0 : -1; - s << GetRustParseDataType() << "::from_le_bytes(["; - int total_bytes; - if (size_ <= 8) { - total_bytes = 1; - } else if (size_ <= 16) { - total_bytes = 2; - } else if (size_ <= 32) { - total_bytes = 4; - } else { - total_bytes = 8; - } - for (int i = 0; i < total_bytes; i++) { - if (i > 0) { - s << ","; - } - if (i < size.bytes()) { - s << "bytes[" << start_offset.bytes() + i + offset << "]"; - } else { - s << 0; - } - } - s << "]);"; - - if (num_leading_bits != 0) { - s << "let " << GetName() << " = " << GetName() << " >> " << num_leading_bits << ";"; - } - - if (util::RoundSizeUp(size.bits()) != size.bits()) { - uint64_t mask = 0; - for (int i = 0; i < size.bits(); i++) { - mask <<= 1; - mask |= 1; - } - s << "let " << GetName() << " = "; - s << GetName() << " & 0x" << std::hex << mask << std::dec << ";"; - } - - // needs casting from primitive - if (GetRustParseDataType() != GetRustDataType()) { - s << "let " << GetName() << " = "; - s << GetRustDataType() << "::from_" << GetRustParseDataType() << "(" << GetName() << ").ok_or_else(||"; - s << "Error::InvalidEnumValueError {"; - s << " obj: \"" << parent_name << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " value: " << GetName() << " as u64,"; - s << " type_: \"" << GetRustDataType() << "\".to_string(),"; - s << "})?;"; - } -} - -void ScalarField::GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const { - Size size = GetSize(); - int num_leading_bits = GetRustBitOffset(s, start_offset, end_offset, GetSize()); - - if (GetFieldType() == SizeField::kFieldType || GetFieldType() == FixedScalarField::kFieldType) { - // Do nothing, the field access has already happened - } else if (GetRustParseDataType() != GetRustDataType()) { - // needs casting to primitive - s << "let " << GetName() << " = self." << GetName() << ".to_" << GetRustParseDataType() << "().unwrap();"; - } else { - s << "let " << GetName() << " = self." << GetName() << ";"; - } - if (util::RoundSizeUp(size.bits()) != size.bits()) { - uint64_t mask = 0; - for (int i = 0; i < size.bits(); i++) { - mask <<= 1; - mask |= 1; - } - s << "let " << GetName() << " = "; - s << GetName() << " & 0x" << std::hex << mask << std::dec << ";"; - } - - int access_offset = 0; - if (num_leading_bits != 0) { - access_offset = -1; - uint64_t mask = 0; - for (int i = 0; i < num_leading_bits; i++) { - mask <<= 1; - mask |= 1; - } - s << "let " << GetName() << " = (" << GetName() << " << " << num_leading_bits << ") | (" - << "(buffer[" << start_offset.bytes() + access_offset << "] as " << GetRustParseDataType() << ") & 0x" << std::hex - << mask << std::dec << ");"; - } - - s << "buffer[" << start_offset.bytes() + access_offset << ".." - << start_offset.bytes() + GetSize().bytes() + access_offset << "].copy_from_slice(&" << GetName() - << ".to_le_bytes()[0.." << size.bytes() << "]);"; -} diff --git a/system/gd/packet/parser/fields/scalar_field.h b/system/gd/packet/parser/fields/scalar_field.h index 09fd16e2363cfcd020a69ea03b787c97ca1d1580..a55417b98019ef56522c5cc69b2693aae00ed986 100644 --- a/system/gd/packet/parser/fields/scalar_field.h +++ b/system/gd/packet/parser/fields/scalar_field.h @@ -51,17 +51,6 @@ class ScalarField : public PacketField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - virtual std::string GetRustDataType() const override; - - virtual std::string GetRustParseDataType() const; - - virtual int GetRustBitOffset(std::ostream& s, Size start_offset, - Size end_offset, Size size) const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - virtual bool GetterIsByRef() const override { return false; } diff --git a/system/gd/packet/parser/fields/struct_field.cc b/system/gd/packet/parser/fields/struct_field.cc index 6555e60bb2eb673e7e2304bc959b3119b7520dd7..8013a7890ea39e406a29a5a8a90b9c9235a387a1 100644 --- a/system/gd/packet/parser/fields/struct_field.cc +++ b/system/gd/packet/parser/fields/struct_field.cc @@ -87,23 +87,3 @@ void StructField::GenValidator(std::ostream&) const { void StructField::GenStringRepresentation(std::ostream& s, std::string accessor) const { s << accessor << ".ToString()"; } - -std::string StructField::GetRustDataType() const { - return GetDataType(); -} - -void StructField::GenBoundsCheck(std::ostream&, Size, Size, std::string) const { - // implicitly checked by the struct parser -} - -void StructField::GenRustGetter(std::ostream& s, Size start_offset, Size, std::string) const { - s << "let " << GetName() << " = "; - s << GetRustDataType() << "::parse(&bytes[" << start_offset.bytes() << ".."; - s << start_offset.bytes() + GetSize().bytes() << "])?;"; -} - -void StructField::GenRustWriter(std::ostream& s, Size start_offset, Size) const { - s << "let " << GetName() << " = &mut buffer[" << start_offset.bytes(); - s << ".." << start_offset.bytes() + GetSize().bytes() << "];"; - s << "self." << GetName() << ".write_to(" << GetName() << ");"; -} diff --git a/system/gd/packet/parser/fields/struct_field.h b/system/gd/packet/parser/fields/struct_field.h index 051b9ef2d2067c2dcf40b29ccc964c7f020fbe2e..9d1d463b4d432447576efea86f53ed85015f73c4 100644 --- a/system/gd/packet/parser/fields/struct_field.h +++ b/system/gd/packet/parser/fields/struct_field.h @@ -51,14 +51,6 @@ class StructField : public PacketField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - - void GenBoundsCheck(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - private: std::string type_name_; diff --git a/system/gd/packet/parser/fields/variable_length_struct_field.cc b/system/gd/packet/parser/fields/variable_length_struct_field.cc index 6506d8f298ca7703300a2759813f56ddfa62e9b3..35f2f54cdd24cbd71f55becd139f16938b3196b0 100644 --- a/system/gd/packet/parser/fields/variable_length_struct_field.cc +++ b/system/gd/packet/parser/fields/variable_length_struct_field.cc @@ -90,12 +90,3 @@ void VariableLengthStructField::GenInserter(std::ostream& s) const { void VariableLengthStructField::GenValidator(std::ostream&) const { // Do nothing } - -std::string VariableLengthStructField::GetRustDataType() const { - std::string ret = "std::boxed::Box<" + type_name_ + ">"; - return ret; -} - -void VariableLengthStructField::GenRustGetter(std::ostream&, Size, Size, std::string) const {} - -void VariableLengthStructField::GenRustWriter(std::ostream&, Size, Size) const {} diff --git a/system/gd/packet/parser/fields/variable_length_struct_field.h b/system/gd/packet/parser/fields/variable_length_struct_field.h index a6c66d69eef48db8edc6c5bc02d38f2347379154..0b1b97f662797c7d5582c1c380644fead46b1422 100644 --- a/system/gd/packet/parser/fields/variable_length_struct_field.h +++ b/system/gd/packet/parser/fields/variable_length_struct_field.h @@ -51,12 +51,6 @@ class VariableLengthStructField : public PacketField { virtual void GenValidator(std::ostream&) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream&, Size, Size, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - private: std::string type_name_; }; diff --git a/system/gd/packet/parser/fields/vector_field.cc b/system/gd/packet/parser/fields/vector_field.cc index 370edf9795baf1adf76acd9f490b16cf1d21c227..a13ac3259a03c1c378bbcaf0a44bc1c068ee0976 100644 --- a/system/gd/packet/parser/fields/vector_field.cc +++ b/system/gd/packet/parser/fields/vector_field.cc @@ -249,132 +249,3 @@ void VectorField::GenStringRepresentation(std::ostream& s, std::string accessor) s << ";}"; s << "ss << \"]\""; } - -std::string VectorField::GetRustDataType() const { - return "Vec::<" + element_field_->GetRustDataType() + ">"; -} - -void VectorField::GenBoundsCheck(std::ostream& s, Size start_offset, Size, std::string parent_name) const { - auto element_field_type = GetElementField()->GetFieldType(); - auto element_field = GetElementField(); - auto element_size = element_field->GetSize(); - - if (size_field_ != nullptr && size_field_->GetFieldType() == SizeField::kFieldType) { - s << "let want_ = " << start_offset.bytes() << " + (" << size_field_->GetName() << " as usize)"; - if (GetSizeModifier() != "") { - s << " - " << GetSizeModifier().substr(1); - } - s << ";"; - s << "if bytes.len() < want_ {"; - s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << parent_name << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " wanted: want_,"; - s << " got: bytes.len()});"; - s << "}"; - if (GetSizeModifier() != "") { - s << "if (" << size_field_->GetName() << " as usize) < " << GetSizeModifier().substr(1) << " {"; - s << " return Err(Error::ImpossibleStructError);"; - s << "}"; - } - } else if ( - size_field_ != nullptr && size_field_->GetFieldType() == CountField::kFieldType && !element_size.empty() && - !element_size.has_dynamic()) { - s << "let want_ = " << start_offset.bytes() << " + ((" << size_field_->GetName() << " as usize) * " - << element_size.bytes() << ");"; - s << "if bytes.len() < want_ {"; - s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << parent_name << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " wanted: want_,"; - s << " got: bytes.len()});"; - s << "}"; - } else if (size_field_ == nullptr && element_field_type == ScalarField::kFieldType) { - s << "let rem_ = (bytes.len() - " << start_offset.bytes() << ") % " << element_size.bytes() << ";"; - s << "if rem_ != 0 {"; - s << " return Err(Error::InvalidLengthError{"; - s << " obj: \"" << parent_name << "\".to_string(),"; - s << " field: \"" << GetName() << "\".to_string(),"; - s << " wanted: bytes.len() + rem_,"; - s << " got: bytes.len()});"; - s << "}"; - } -} - -void VectorField::GenRustGetter(std::ostream& s, Size start_offset, Size, std::string) const { - auto element_field_type = GetElementField()->GetFieldType(); - auto element_field = GetElementField(); - auto element_size = element_field->GetSize().bytes(); - - if (element_field_type == ScalarField::kFieldType) { - s << "let " << GetName() << ": " << GetRustDataType() << " = "; - if (size_field_ == nullptr) { - s << "bytes[" << start_offset.bytes() << "..]"; - } else if (size_field_->GetFieldType() == CountField::kFieldType) { - s << "bytes[" << start_offset.bytes() << ".." << start_offset.bytes() << " + (("; - s << size_field_->GetName() << " as usize) * " << element_size << ")]"; - } else { - s << "bytes[" << start_offset.bytes() << "..("; - s << start_offset.bytes() << " + " << size_field_->GetName(); - s << " as usize)"; - if (GetSizeModifier() != "") { - s << " - " << GetSizeModifier().substr(1); - } - s << "]"; - } - - s << ".to_vec().chunks_exact(" << element_size << ").into_iter().map(|i| "; - s << element_field->GetRustDataType() << "::from_le_bytes(["; - - for (int j=0; j < element_size; j++) { - s << "i[" << j << "]"; - if (j != element_size - 1) { - s << ", "; - } - } - s << "])).collect();"; - } else { - s << "let mut " << GetName() << ": " << GetRustDataType() << " = Vec::new();"; - if (size_field_ == nullptr) { - s << "let mut parsable_ = &bytes[" << start_offset.bytes() << "..];"; - s << "while parsable_.len() > 0 {"; - } else if (size_field_->GetFieldType() == CountField::kFieldType) { - s << "let mut parsable_ = &bytes[" << start_offset.bytes() << "..];"; - s << "let count_ = " << size_field_->GetName() << " as usize;"; - s << "for _ in 0..count_ {"; - } else { - s << "let mut parsable_ = &bytes[" << start_offset.bytes() << ".." << start_offset.bytes() << " + (" - << size_field_->GetName() << " as usize)"; - if (GetSizeModifier() != "") { - s << " - " << GetSizeModifier().substr(1); - } - s << "];"; - s << "while parsable_.len() > 0 {"; - } - s << " match " << element_field->GetRustDataType() << "::parse(&parsable_) {"; - s << " Ok(parsed) => {"; - s << " parsable_ = &parsable_[parsed.get_total_size()..];"; - s << GetName() << ".push(parsed);"; - s << " },"; - s << " Err(Error::ImpossibleStructError) => break,"; - s << " Err(e) => return Err(e),"; - s << " }"; - s << "}"; - } -} - -void VectorField::GenRustWriter(std::ostream& s, Size start_offset, Size) const { - if (GetElementField()->GetFieldType() == ScalarField::kFieldType) { - s << "for (i, e) in self." << GetName() << ".iter().enumerate() {"; - s << "buffer[" << start_offset.bytes() << "+i.."; - s << start_offset.bytes() << "+i+" << GetElementField()->GetSize().bytes() << "]"; - s << ".copy_from_slice(&e.to_le_bytes())"; - s << "}"; - } else { - s << "let mut vec_buffer_ = &mut buffer[" << start_offset.bytes() << "..];"; - s << "for e_ in &self." << GetName() << " {"; - s << " e_.write_to(&mut vec_buffer_[0..e_.get_total_size()]);"; - s << " vec_buffer_ = &mut vec_buffer_[e_.get_total_size()..];"; - s << "}"; - } -} diff --git a/system/gd/packet/parser/fields/vector_field.h b/system/gd/packet/parser/fields/vector_field.h index aa53eb4991c435ff0cd7f990ab846b79a4499a83..827f71882e4241ff9ac658c8bbc188a9ef712387 100644 --- a/system/gd/packet/parser/fields/vector_field.h +++ b/system/gd/packet/parser/fields/vector_field.h @@ -69,14 +69,6 @@ class VectorField : public PacketField { virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override; - virtual std::string GetRustDataType() const override; - - void GenRustGetter(std::ostream& s, Size start_offset, Size end_offset, std::string) const override; - - void GenRustWriter(std::ostream& s, Size start_offset, Size end_offset) const override; - - void GenBoundsCheck(std::ostream& s, Size start_offset, Size end_offset, std::string parent_name) const override; - const std::string name_; const PacketField* element_field_{nullptr}; diff --git a/system/gd/packet/parser/gen_cpp.cc b/system/gd/packet/parser/gen_cpp.cc index b4dcc5cbe1959e2346fef4179e11e74a8afcf0d7..298100361555f3130557472f4ca6b4a7675d8da7 100644 --- a/system/gd/packet/parser/gen_cpp.cc +++ b/system/gd/packet/parser/gen_cpp.cc @@ -82,6 +82,7 @@ bool generate_cpp_headers_one_file( #include #include +#include #include #include #include diff --git a/system/gd/packet/parser/gen_rust.cc b/system/gd/packet/parser/gen_rust.cc deleted file mode 100644 index 1097083941966284f91aca140ad1d111219a6f51..0000000000000000000000000000000000000000 --- a/system/gd/packet/parser/gen_rust.cc +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include "declarations.h" - -void generate_rust_packet_preamble(std::ostream& s) { - s << - R"( -use bytes::{Bytes, BytesMut, BufMut}; -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::{FromPrimitive, ToPrimitive}; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use thiserror::Error; -use std::sync::Arc; - -type Result = std::result::Result; - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { - field: String, - value: u64, - }, - #[error("when parsing {obj}.{field} needed length of {wanted} but got {got}")] - InvalidLengthError { - obj: String, - field: String, - wanted: usize, - got: usize, - }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { - obj: String, - field: String, - value: u64, - type_: String, - }, -} - -#[derive(Debug, Error)] -#[error("{0}")] -pub struct TryFromError(&'static str); - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -)"; -} - -bool generate_rust_source_one_file( - const Declarations& decls, - const std::filesystem::path& input_file, - const std::filesystem::path& include_dir, - const std::filesystem::path& out_dir, - __attribute__((unused)) const std::string& root_namespace) { - auto gen_relative_path = input_file.lexically_relative(include_dir).parent_path(); - - auto input_filename = input_file.filename().string().substr(0, input_file.filename().string().find(".pdl")); - auto gen_path = out_dir / gen_relative_path; - - std::filesystem::create_directories(gen_path); - - auto gen_file = gen_path / (input_filename + ".rs"); - - std::cout << "generating " << gen_file << std::endl; - - std::ofstream out_file; - out_file.open(gen_file); - if (!out_file.is_open()) { - std::cerr << "can't open " << gen_file << std::endl; - return false; - } - - out_file << "// @generated rust packets from " << input_file.filename().string() << "\n\n"; - - generate_rust_packet_preamble(out_file); - if (input_filename == "hci_packets") { - out_file << "pub trait CommandExpectations { " - << "type ResponseType;" - << "fn _to_response_type(pkt: EventPacket) -> Self::ResponseType;" - << "}"; - - for (const auto& packet_def : decls.packet_defs_queue_) { - auto packet = packet_def.second; - if (!packet->HasAncestorNamed("Command")) { - continue; - } - auto constraint = packet->parent_constraints_.find("op_code"); - if (constraint == packet->parent_constraints_.end()) { - continue; - } - auto opcode = std::get(constraint->second); - for (const auto& other_packet_def : decls.packet_defs_queue_) { - auto other_packet = other_packet_def.second; - bool command_status = other_packet->HasAncestorNamed("CommandStatus"); - bool command_complete = other_packet->HasAncestorNamed("CommandComplete"); - if (!command_status && !command_complete) { - continue; - } - auto other_constraint = other_packet->parent_constraints_.find("command_op_code"); - if (other_constraint == other_packet->parent_constraints_.end()) { - continue; - } - - auto other_opcode = std::get(other_constraint->second); - if (opcode == other_opcode) { - packet->complement_ = other_packet; - break; - } - } - } - - EnumDef* opcode = nullptr; - EnumDef* opcode_index = nullptr; - for (const auto& e : decls.type_defs_queue_) { - if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) { - auto* enum_def = static_cast(e.second); - if (enum_def->name_ == "OpCode") { - opcode = enum_def; - } else if (enum_def->name_ == "OpCodeIndex") { - opcode_index = enum_def; - } - } - } - - if (opcode_index != nullptr && opcode != nullptr) { - opcode_index->try_from_enum_ = opcode; - } - } else if (input_filename == "nci_packets") { - out_file << "type EventPacket = NciPacket;" - << "pub trait CommandExpectations { " - << "type ResponseType;" - << "fn _to_response_type(pkt: EventPacket) -> Self::ResponseType;" - << "}"; - - for (const auto& packet_def : decls.packet_defs_queue_) { - auto packet = packet_def.second; - if (!packet->HasAncestorNamed("Command")) { - continue; - } - auto constraint = packet->parent_constraints_.find("op"); - if (constraint == packet->parent_constraints_.end()) { - continue; - } - auto opcode = std::get(constraint->second); - for (const auto& other_packet_def : decls.packet_defs_queue_) { - auto other_packet = other_packet_def.second; - bool command_response = other_packet->HasAncestorNamed("Response"); - bool command_notification = other_packet->HasAncestorNamed("Notification"); - if (!command_response && !command_notification) { - continue; - } - auto other_constraint = other_packet->parent_constraints_.find("cmd_op"); - if (other_constraint == other_packet->parent_constraints_.end()) { - continue; - } - - auto other_opcode = std::get(other_constraint->second); - if (opcode == other_opcode) { - packet->complement_ = other_packet; - break; - } - } - } - - EnumDef* opcode = nullptr; - EnumDef* opcode_index = nullptr; - for (const auto& e : decls.type_defs_queue_) { - if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) { - auto* enum_def = static_cast(e.second); - if (enum_def->name_ == "Opcode") { - opcode = enum_def; - } else if (enum_def->name_ == "OpCodeIndex") { - opcode_index = enum_def; - } - } - } - - if (opcode_index != nullptr && opcode != nullptr) { - opcode_index->try_from_enum_ = opcode; - } - } - - for (const auto& e : decls.type_defs_queue_) { - if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) { - const auto* enum_def = static_cast(e.second); - EnumGen gen(*enum_def); - gen.GenRustDef(out_file); - out_file << "\n\n"; - } - } - - for (auto& s : decls.type_defs_queue_) { - if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) { - const auto* struct_def = static_cast(s.second); - struct_def->GenRustDef(out_file); - out_file << "\n\n"; - } - } - - for (const auto& packet_def : decls.packet_defs_queue_) { - packet_def.second->GenRustDef(out_file); - out_file << "\n\n"; - } - - out_file.close(); - return true; -} diff --git a/system/gd/packet/parser/main.cc b/system/gd/packet/parser/main.cc index 5caaff7087f1c8c8f1fad19d5756d09219255f45..929fc9f5ecd70b41fb81ca5359346660178ac2ba 100644 --- a/system/gd/packet/parser/main.cc +++ b/system/gd/packet/parser/main.cc @@ -54,13 +54,6 @@ bool generate_pybind11_sources_one_file( const std::string& root_namespace, size_t num_shards); -bool generate_rust_source_one_file( - const Declarations& decls, - const std::filesystem::path& input_file, - const std::filesystem::path& include_dir, - const std::filesystem::path& out_dir, - const std::string& root_namespace); - bool parse_declarations_one_file(const std::filesystem::path& input_file, Declarations* declarations) { void* scanner; yylex_init(&scanner); @@ -135,7 +128,6 @@ int main(int argc, const char** argv) { std::string root_namespace = "bluetooth"; // Number of shards per output pybind11 cc file size_t num_shards = 1; - bool generate_rust = false; bool generate_fuzzing = false; bool generate_tests = false; std::queue input_files; @@ -144,7 +136,6 @@ int main(int argc, const char** argv) { const std::string arg_include = "--include="; const std::string arg_namespace = "--root_namespace="; const std::string arg_num_shards = "--num_shards="; - const std::string arg_rust = "--rust"; const std::string arg_fuzzing = "--fuzzing"; const std::string arg_testing = "--testing"; const std::string arg_source_root = "--source_root="; @@ -168,8 +159,6 @@ int main(int argc, const char** argv) { root_namespace = arg.substr(arg_namespace.size()); } else if (arg.find(arg_num_shards) == 0) { num_shards = std::stoul(arg.substr(arg_num_shards.size())); - } else if (arg.find(arg_rust) == 0) { - generate_rust = true; } else if (arg.find(arg_fuzzing) == 0) { generate_fuzzing = true; } else if (arg.find(arg_testing) == 0) { @@ -194,30 +183,22 @@ int main(int argc, const char** argv) { std::cerr << "Cannot parse " << input_files.front() << " correctly" << std::endl; return 2; } - if (generate_rust) { - std::cout << "generating rust" << std::endl; - if (!generate_rust_source_one_file(declarations, input_files.front(), include_dir, out_dir, root_namespace)) { - std::cerr << "Didn't generate rust source for " << input_files.front() << std::endl; - return 5; - } - } else { - std::cout << "generating c++ and pybind11" << std::endl; - if (!generate_cpp_headers_one_file( - declarations, - generate_fuzzing, - generate_tests, - input_files.front(), - include_dir, - out_dir, - root_namespace)) { - std::cerr << "Didn't generate cpp headers for " << input_files.front() << std::endl; - return 3; - } - if (!generate_pybind11_sources_one_file( - declarations, input_files.front(), include_dir, out_dir, root_namespace, num_shards)) { - std::cerr << "Didn't generate pybind11 sources for " << input_files.front() << std::endl; - return 4; - } + std::cout << "generating c++ and pybind11" << std::endl; + if (!generate_cpp_headers_one_file( + declarations, + generate_fuzzing, + generate_tests, + input_files.front(), + include_dir, + out_dir, + root_namespace)) { + std::cerr << "Didn't generate cpp headers for " << input_files.front() << std::endl; + return 3; + } + if (!generate_pybind11_sources_one_file( + declarations, input_files.front(), include_dir, out_dir, root_namespace, num_shards)) { + std::cerr << "Didn't generate pybind11 sources for " << input_files.front() << std::endl; + return 4; } input_files.pop(); } diff --git a/system/gd/packet/parser/packet_def.cc b/system/gd/packet/parser/packet_def.cc index 48760e8d4fb852da779b9d7b74da79cb2c70f8b5..eaf195925ae583df80ed53efb2b79f9a2654295d 100644 --- a/system/gd/packet/parser/packet_def.cc +++ b/system/gd/packet/parser/packet_def.cc @@ -44,9 +44,22 @@ void PacketDef::GenParserDefinition(std::ostream& s, bool generate_fuzzing, bool if (parent_ != nullptr) { s << "static " << name_ << "View Create(" << parent_->name_ << "View parent)"; s << "{ return " << name_ << "View(std::move(parent)); }"; + // CreateOptional + s << "static std::optional<" << name_ << "View> CreateOptional("; + s << parent_->name_ << "View parent)"; + s << "{ auto to_validate = " << name_ << "View::Create(std::move(parent));"; + s << "if (to_validate.IsValid()) { return to_validate; }"; + s << "else {return {};}}"; } else { - s << "static " << name_ << "View Create(PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> packet) "; + s << "static " << name_ << "View Create(PacketView<"; + s << (is_little_endian_ ? "" : "!") << "kLittleEndian> packet)"; s << "{ return " << name_ << "View(std::move(packet)); }"; + // CreateOptional + s << "static std::optional<" << name_ << "View> CreateOptional(PacketView<"; + s << (is_little_endian_ ? "" : "!") << "kLittleEndian> packet)"; + s << "{ auto to_validate = " << name_ << "View::Create(std::move(packet));"; + s << "if (to_validate.IsValid()) { return to_validate; }"; + s << "else {return {};}}"; } if (generate_fuzzing || generate_tests) { @@ -423,6 +436,7 @@ void PacketDef::GenTestingFromView(std::ostream& s) const { s << "#if defined(PACKET_FUZZ_TESTING) || defined(PACKET_TESTING) || defined(FUZZ_TARGET)\n"; s << "static std::unique_ptr<" << name_ << "Builder> FromView(" << name_ << "View view) {"; + s << "if (!view.IsValid()) return nullptr;"; s << "return " << name_ << "Builder::Create("; FieldList params = GetParamList().GetFieldsWithoutTypes({ BodyField::kFieldType, @@ -592,9 +606,7 @@ void PacketDef::GenBuilderCreatePybind11(std::ostream& s) const { s << ".def(py::init([]("; auto params = GetParamList(); std::vector constructor_args; - int i = 1; for (const auto& param : params) { - i++; std::stringstream ss; auto param_type = param->GetBuilderParameterType(); if (param_type.empty()) { @@ -794,677 +806,3 @@ void PacketDef::GenBuilderConstructor(std::ostream& s) const { s << "}\n"; } - -void PacketDef::GenRustChildEnums(std::ostream& s) const { - if (HasChildEnums()) { - bool payload = fields_.HasPayload(); - s << "#[derive(Debug)] "; - s << "enum " << name_ << "DataChild {"; - for (const auto& child : children_) { - s << child->name_ << "(Arc<" << child->name_ << "Data>),"; - } - if (payload) { - s << "Payload(Bytes),"; - } - s << "None,"; - s << "}\n"; - - s << "impl " << name_ << "DataChild {"; - s << "fn get_total_size(&self) -> usize {"; - s << "match self {"; - for (const auto& child : children_) { - s << name_ << "DataChild::" << child->name_ << "(value) => value.get_total_size(),"; - } - if (payload) { - s << name_ << "DataChild::Payload(p) => p.len(),"; - } - s << name_ << "DataChild::None => 0,"; - s << "}\n"; - s << "}\n"; - s << "}\n"; - - s << "#[derive(Debug)] "; - s << "pub enum " << name_ << "Child {"; - for (const auto& child : children_) { - s << child->name_ << "(" << child->name_ << "Packet),"; - } - if (payload) { - s << "Payload(Bytes),"; - } - s << "None,"; - s << "}\n"; - } -} - -void PacketDef::GenRustStructDeclarations(std::ostream& s) const { - s << "#[derive(Debug)] "; - s << "struct " << name_ << "Data {"; - - // Generate struct fields - GenRustStructFieldNameAndType(s); - if (HasChildEnums()) { - s << "child: " << name_ << "DataChild,"; - } - s << "}\n"; - - // Generate accessor struct - s << "#[derive(Debug, Clone)] "; - s << "pub struct " << name_ << "Packet {"; - auto lineage = GetAncestors(); - lineage.push_back(this); - for (auto it = lineage.begin(); it != lineage.end(); it++) { - auto def = *it; - s << util::CamelCaseToUnderScore(def->name_) << ": Arc<" << def->name_ << "Data>,"; - } - s << "}\n"; - - // Generate builder struct - s << "#[derive(Debug)] "; - s << "pub struct " << name_ << "Builder {"; - auto params = GetParamList().GetFieldsWithoutTypes({ - PayloadField::kFieldType, - BodyField::kFieldType, - }); - for (auto param : params) { - s << "pub "; - param->GenRustNameAndType(s); - s << ", "; - } - if (fields_.HasPayload()) { - s << "pub payload: Option,"; - } - s << "}\n"; -} - -bool PacketDef::GenRustStructFieldNameAndType(std::ostream& s) const { - auto fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - PayloadField::kFieldType, - FixedScalarField::kFieldType, - }); - if (fields.size() == 0) { - return false; - } - for (const auto& field : fields) { - field->GenRustNameAndType(s); - s << ", "; - } - return true; -} - -void PacketDef::GenRustStructFieldNames(std::ostream& s) const { - auto fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - PayloadField::kFieldType, - FixedScalarField::kFieldType, - }); - for (const auto field : fields) { - s << field->GetName(); - s << ", "; - } -} - -void PacketDef::GenRustStructImpls(std::ostream& s) const { - auto packet_dep = PacketDependency(GetRootDef()); - - s << "impl " << name_ << "Data {"; - // conforms function - s << "fn conforms(bytes: &[u8]) -> bool {"; - GenRustConformanceCheck(s); - - auto fields = fields_.GetFieldsWithTypes({ - StructField::kFieldType, - }); - - for (auto const& field : fields) { - auto start_offset = GetOffsetForField(field->GetName(), false); - auto end_offset = GetOffsetForField(field->GetName(), true); - - s << "if !" << field->GetRustDataType() << "::conforms(&bytes[" << start_offset.bytes(); - s << ".." << start_offset.bytes() + field->GetSize().bytes() << "]) { return false; }"; - } - - s << " true"; - s << "}"; - - auto parse_params = packet_dep.GetDependencies(name_); - s << "fn parse(bytes: &[u8]"; - for (auto field_name : parse_params) { - auto constraint_field = GetParamList().GetField(field_name); - auto constraint_type = constraint_field->GetRustDataType(); - s << ", " << field_name << ": " << constraint_type; - } - s << ") -> Result {"; - - fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - }); - - for (auto const& field : fields) { - auto start_field_offset = GetOffsetForField(field->GetName(), false); - auto end_field_offset = GetOffsetForField(field->GetName(), true); - - if (start_field_offset.empty() && end_field_offset.empty()) { - ERROR(field) << "Field location for " << field->GetName() << " is ambiguous, " - << "no method exists to determine field location from begin() or end().\n"; - } - - field->GenBoundsCheck(s, start_field_offset, end_field_offset, name_); - field->GenRustGetter(s, start_field_offset, end_field_offset, name_); - } - - auto payload_field = fields_.GetFieldsWithTypes({ - PayloadField::kFieldType, - }); - - Size payload_offset; - - if (payload_field.HasPayload()) { - payload_offset = GetOffsetForField(payload_field[0]->GetName(), false); - } - - if (children_.size() > 1) { - auto match_on_variables = packet_dep.GetChildrenDependencies(name_); - // If match_on_variables is empty, this means there are multiple abstract packets which will - // specialize to a child down the packet tree. - // In this case match variables will be the union of parent fields and parse params of children. - if (match_on_variables.empty()) { - for (auto& field : fields_) { - if (std::any_of(children_.begin(), children_.end(), [&](auto child) { - auto pass_me = packet_dep.GetDependencies(child->name_); - return std::find(pass_me.begin(), pass_me.end(), field->GetName()) != pass_me.end(); - })) { - match_on_variables.push_back(field->GetName()); - } - } - } - - s << "let child = match ("; - - for (auto var : match_on_variables) { - if (var == match_on_variables[match_on_variables.size() - 1]) { - s << var; - } else { - s << var << ", "; - } - } - s << ") {"; - - auto get_match_val = [&]( - std::string& match_var, - std::variant constraint) -> std::string { - auto constraint_field = GetParamList().GetField(match_var); - auto constraint_type = constraint_field->GetFieldType(); - - if (constraint_type == EnumField::kFieldType) { - auto type = std::get(constraint); - auto variant_name = type.substr(type.find("::") + 2, type.length()); - auto enum_type = type.substr(0, type.find("::")); - return enum_type + "::" + util::UnderscoreToCamelCase(util::ToLowerCase(variant_name)); - } - if (constraint_type == ScalarField::kFieldType) { - return std::to_string(std::get(constraint)); - } - return "_"; - }; - - for (auto& child : children_) { - s << "("; - for (auto var : match_on_variables) { - std::string match_val = "_"; - - if (child->parent_constraints_.find(var) != child->parent_constraints_.end()) { - match_val = get_match_val(var, child->parent_constraints_[var]); - } else { - auto dcs = child->FindDescendantsWithConstraint(var); - std::vector all_match_vals; - for (auto& desc : dcs) { - all_match_vals.push_back(get_match_val(var, desc.second)); - } - match_val = ""; - for (std::size_t i = 0; i < all_match_vals.size(); ++i) { - match_val += all_match_vals[i]; - if (i != all_match_vals.size() - 1) { - match_val += " | "; - } - } - match_val = (match_val == "") ? "_" : match_val; - } - - if (var == match_on_variables[match_on_variables.size() - 1]) { - s << match_val << ")"; - } else { - s << match_val << ", "; - } - } - s << " if " << child->name_ << "Data::conforms(&bytes[..])"; - s << " => {"; - s << name_ << "DataChild::"; - s << child->name_ << "(Arc::new("; - - auto child_parse_params = packet_dep.GetDependencies(child->name_); - if (child_parse_params.size() == 0) { - s << child->name_ << "Data::parse(&bytes[..]"; - } else { - s << child->name_ << "Data::parse(&bytes[..], "; - } - - for (auto var : child_parse_params) { - if (var == child_parse_params[child_parse_params.size() - 1]) { - s << var; - } else { - s << var << ", "; - } - } - s << ")?))"; - s << "}\n"; - } - - s << "("; - for (int i = 1; i <= match_on_variables.size(); i++) { - if (i == match_on_variables.size()) { - s << "_"; - } else { - s << "_, "; - } - } - s << ")"; - s << " => return Err(Error::InvalidPacketError),"; - s << "};\n"; - } else if (children_.size() == 1) { - auto child = children_.at(0); - auto params = packet_dep.GetDependencies(child->name_); - s << "let child = match " << child->name_ << "Data::parse(&bytes[..]"; - for (auto field_name : params) { - s << ", " << field_name; - } - s << ") {"; - s << " Ok(c) if " << child->name_ << "Data::conforms(&bytes[..]) => {"; - s << name_ << "DataChild::" << child->name_ << "(Arc::new(c))"; - s << " },"; - s << " Err(Error::InvalidLengthError { .. }) => " << name_ << "DataChild::None,"; - s << " _ => return Err(Error::InvalidPacketError),"; - s << "};"; - } else if (fields_.HasPayload()) { - s << "let child = if payload.len() > 0 {"; - s << name_ << "DataChild::Payload(Bytes::from(payload))"; - s << "} else {"; - s << name_ << "DataChild::None"; - s << "};"; - } - - s << "Ok(Self {"; - fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - PayloadField::kFieldType, - FixedScalarField::kFieldType, - }); - - if (fields.size() > 0) { - for (const auto& field : fields) { - auto field_type = field->GetFieldType(); - s << field->GetName(); - s << ", "; - } - } - - if (HasChildEnums()) { - s << "child,"; - } - s << "})\n"; - s << "}\n"; - - // write_to function - s << "fn write_to(&self, buffer: &mut BytesMut) {"; - GenRustWriteToFields(s); - - if (HasChildEnums()) { - s << "match &self.child {"; - for (const auto& child : children_) { - s << name_ << "DataChild::" << child->name_ << "(value) => value.write_to(buffer),"; - } - if (fields_.HasPayload()) { - auto offset = GetOffsetForField("payload"); - s << name_ << "DataChild::Payload(p) => buffer[" << offset.bytes() << "..].copy_from_slice(&p[..]),"; - } - s << name_ << "DataChild::None => {}"; - s << "}"; - } - - s << "}\n"; - - s << "fn get_total_size(&self) -> usize {"; - if (HasChildEnums()) { - s << "self.get_size() + self.child.get_total_size()"; - } else { - s << "self.get_size()"; - } - s << "}\n"; - - s << "fn get_size(&self) -> usize {"; - GenSizeRetVal(s); - s << "}\n"; - s << "}\n"; -} - -void PacketDef::GenRustAccessStructImpls(std::ostream& s) const { - if (complement_ != nullptr) { - auto complement_root = complement_->GetRootDef(); - auto complement_root_accessor = util::CamelCaseToUnderScore(complement_root->name_); - s << "impl CommandExpectations for " << name_ << "Packet {"; - s << " type ResponseType = " << complement_->name_ << "Packet;"; - s << " fn _to_response_type(pkt: EventPacket) -> Self::ResponseType { "; - s << complement_->name_ << "Packet::new(pkt." << complement_root_accessor << ".clone())" - << ".unwrap()"; - s << " }"; - s << "}"; - } - - s << "impl Packet for " << name_ << "Packet {"; - auto root = GetRootDef(); - auto root_accessor = util::CamelCaseToUnderScore(root->name_); - - s << "fn to_bytes(self) -> Bytes {"; - s << " let mut buffer = BytesMut::new();"; - s << " buffer.resize(self." << root_accessor << ".get_total_size(), 0);"; - s << " self." << root_accessor << ".write_to(&mut buffer);"; - s << " buffer.freeze()"; - s << "}\n"; - - s << "fn to_vec(self) -> Vec { self.to_bytes().to_vec() }\n"; - s << "}"; - - s << "impl From<" << name_ << "Packet" - << "> for Bytes {\n"; - s << "fn from(packet: " << name_ << "Packet" - << ") -> Self {\n"; - s << "packet.to_bytes()\n"; - s << "}\n"; - s << "}\n"; - - s << "impl From<" << name_ << "Packet" - << "> for Vec {\n"; - s << "fn from(packet: " << name_ << "Packet" - << ") -> Self {\n"; - s << "packet.to_vec()\n"; - s << "}\n"; - s << "}\n"; - - if (root != this) { - s << "impl TryFrom<" << root->name_ << "Packet" - << "> for " << name_ << "Packet {\n"; - s << "type Error = TryFromError;\n"; - s << "fn try_from(value: " << root->name_ << "Packet)" - << " -> std::result::Result {\n"; - s << "Self::new(value." << root_accessor << ").map_err(TryFromError)\n", s << "}\n"; - s << "}\n"; - } - - s << "impl " << name_ << "Packet {"; - if (parent_ == nullptr) { - s << "pub fn parse(bytes: &[u8]) -> Result { "; - s << "Ok(Self::new(Arc::new(" << name_ << "Data::parse(bytes)?)).unwrap())"; - s << "}"; - } - - if (HasChildEnums()) { - s << " pub fn specialize(&self) -> " << name_ << "Child {"; - s << " match &self." << util::CamelCaseToUnderScore(name_) << ".child {"; - for (const auto& child : children_) { - s << name_ << "DataChild::" << child->name_ << "(_) => " << name_ << "Child::" << child->name_ << "(" - << child->name_ << "Packet::new(self." << root_accessor << ".clone()).unwrap()),"; - } - if (fields_.HasPayload()) { - s << name_ << "DataChild::Payload(p) => " << name_ << "Child::Payload(p.clone()),"; - } - s << name_ << "DataChild::None => " << name_ << "Child::None,"; - s << "}}"; - } - auto lineage = GetAncestors(); - lineage.push_back(this); - const ParentDef* prev = nullptr; - - s << " fn new(root: Arc<" << root->name_ << "Data>) -> std::result::Result {"; - for (auto it = lineage.begin(); it != lineage.end(); it++) { - auto def = *it; - auto accessor_name = util::CamelCaseToUnderScore(def->name_); - if (prev == nullptr) { - s << "let " << accessor_name << " = root;"; - } else { - s << "let " << accessor_name << " = match &" << util::CamelCaseToUnderScore(prev->name_) << ".child {"; - s << prev->name_ << "DataChild::" << def->name_ << "(value) => (*value).clone(),"; - s << "_ => return Err(\"inconsistent state - child was not " << def->name_ << "\"),"; - s << "};"; - } - prev = def; - } - s << "Ok(Self {"; - for (auto it = lineage.begin(); it != lineage.end(); it++) { - auto def = *it; - s << util::CamelCaseToUnderScore(def->name_) << ","; - } - s << "})}"; - - for (auto it = lineage.begin(); it != lineage.end(); it++) { - auto def = *it; - auto fields = def->fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - PayloadField::kFieldType, - FixedScalarField::kFieldType, - }); - - for (auto const& field : fields) { - if (field->GetterIsByRef()) { - s << "pub fn get_" << field->GetName() << "(&self) -> &" << field->GetRustDataType() << "{"; - s << " &self." << util::CamelCaseToUnderScore(def->name_) << ".as_ref()." << field->GetName(); - s << "}\n"; - } else { - s << "pub fn get_" << field->GetName() << "(&self) -> " << field->GetRustDataType() << "{"; - s << " self." << util::CamelCaseToUnderScore(def->name_) << ".as_ref()." << field->GetName(); - s << "}\n"; - } - } - } - - s << "}\n"; - - lineage = GetAncestors(); - for (auto it = lineage.begin(); it != lineage.end(); it++) { - auto def = *it; - s << "impl Into<" << def->name_ << "Packet> for " << name_ << "Packet {"; - s << " fn into(self) -> " << def->name_ << "Packet {"; - s << def->name_ << "Packet::new(self." << util::CamelCaseToUnderScore(root->name_) << ")" - << ".unwrap()"; - s << " }"; - s << "}\n"; - } -} - -void PacketDef::GenRustBuilderStructImpls(std::ostream& s) const { - if (complement_ != nullptr) { - auto complement_root = complement_->GetRootDef(); - auto complement_root_accessor = util::CamelCaseToUnderScore(complement_root->name_); - s << "impl CommandExpectations for " << name_ << "Builder {"; - s << " type ResponseType = " << complement_->name_ << "Packet;"; - s << " fn _to_response_type(pkt: EventPacket) -> Self::ResponseType { "; - s << complement_->name_ << "Packet::new(pkt." << complement_root_accessor << ".clone())" - << ".unwrap()"; - s << " }"; - s << "}"; - } - - s << "impl " << name_ << "Builder {"; - s << "pub fn build(self) -> " << name_ << "Packet {"; - auto lineage = GetAncestors(); - lineage.push_back(this); - std::reverse(lineage.begin(), lineage.end()); - - auto all_constraints = GetAllConstraints(); - - const ParentDef* prev = nullptr; - for (auto ancestor : lineage) { - auto fields = ancestor->fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - PayloadField::kFieldType, - FixedScalarField::kFieldType, - }); - - auto accessor_name = util::CamelCaseToUnderScore(ancestor->name_); - s << "let " << accessor_name << "= Arc::new(" << ancestor->name_ << "Data {"; - for (auto field : fields) { - auto constraint = all_constraints.find(field->GetName()); - s << field->GetName() << ": "; - if (constraint != all_constraints.end()) { - if (field->GetFieldType() == ScalarField::kFieldType) { - s << std::get(constraint->second); - } else if (field->GetFieldType() == EnumField::kFieldType) { - auto value = std::get(constraint->second); - auto constant = value.substr(value.find("::") + 2, std::string::npos); - s << field->GetDataType() << "::" << util::ConstantCaseToCamelCase(constant); - ; - } else { - ERROR(field) << "Constraints on non enum/scalar fields should be impossible."; - } - } else { - s << "self." << field->GetName(); - } - s << ", "; - } - if (ancestor->HasChildEnums()) { - if (prev == nullptr) { - if (ancestor->fields_.HasPayload()) { - s << "child: match self.payload { "; - s << "None => " << name_ << "DataChild::None,"; - s << "Some(bytes) => " << name_ << "DataChild::Payload(bytes),"; - s << "},"; - } else { - s << "child: " << name_ << "DataChild::None,"; - } - } else { - s << "child: " << ancestor->name_ << "DataChild::" << prev->name_ << "(" - << util::CamelCaseToUnderScore(prev->name_) << "),"; - } - } - s << "});"; - prev = ancestor; - } - - s << name_ << "Packet::new(" << util::CamelCaseToUnderScore(prev->name_) << ").unwrap()"; - s << "}\n"; - - s << "}\n"; - for (const auto ancestor : GetAncestors()) { - s << "impl Into<" << ancestor->name_ << "Packet> for " << name_ << "Builder {"; - s << " fn into(self) -> " << ancestor->name_ << "Packet { self.build().into() }"; - s << "}\n"; - } -} - -void PacketDef::GenRustBuilderTest(std::ostream& s) const { - auto lineage = GetAncestors(); - lineage.push_back(this); - if (!lineage.empty() && !test_cases_.empty()) { - s << "macro_rules! " << util::CamelCaseToUnderScore(name_) << "_builder_tests { "; - s << "($($name:ident: $byte_string:expr,)*) => {"; - s << "$("; - s << "\n#[test]\n"; - s << "pub fn $name() { "; - s << "let raw_bytes = $byte_string;"; - for (size_t i = 0; i < lineage.size(); i++) { - s << "/* (" << i << ") */\n"; - if (i == 0) { - s << "match " << lineage[i]->name_ << "Packet::parse(raw_bytes) {"; - s << "Ok(" << util::CamelCaseToUnderScore(lineage[i]->name_) << "_packet) => {"; - s << "match " << util::CamelCaseToUnderScore(lineage[i]->name_) << "_packet.specialize() {"; - } else if (i != lineage.size() - 1) { - s << lineage[i - 1]->name_ << "Child::" << lineage[i]->name_ << "("; - s << util::CamelCaseToUnderScore(lineage[i]->name_) << "_packet) => {"; - s << "match " << util::CamelCaseToUnderScore(lineage[i]->name_) << "_packet.specialize() {"; - } else { - s << lineage[i - 1]->name_ << "Child::" << lineage[i]->name_ << "(packet) => {"; - s << "let rebuilder = " << lineage[i]->name_ << "Builder {"; - FieldList params = GetParamList(); - if (params.HasBody()) { - ERROR() << "Packets with body fields can't be auto-tested. Test a child."; - } - for (const auto param : params) { - s << param->GetName() << " : packet."; - if (param->GetFieldType() == VectorField::kFieldType) { - s << util::CamelCaseToUnderScore(param->GetGetterFunctionName()) << "().to_vec(),"; - } else if (param->GetFieldType() == ArrayField::kFieldType) { - const auto array_param = static_cast(param); - const auto element_field = array_param->GetElementField(); - if (element_field->GetFieldType() == StructField::kFieldType) { - s << util::CamelCaseToUnderScore(param->GetGetterFunctionName()) << "().to_vec(),"; - } else { - s << util::CamelCaseToUnderScore(param->GetGetterFunctionName()) << "().clone(),"; - } - } else if (param->GetFieldType() == StructField::kFieldType) { - s << util::CamelCaseToUnderScore(param->GetGetterFunctionName()) << "().clone(),"; - } else { - s << util::CamelCaseToUnderScore(param->GetGetterFunctionName()) << "(),"; - } - } - s << "};"; - s << "let rebuilder_base : " << lineage[0]->name_ << "Packet = rebuilder.into();"; - s << "let rebuilder_bytes : &[u8] = &rebuilder_base.to_bytes();"; - s << "assert_eq!(rebuilder_bytes, raw_bytes);"; - s << "}"; - } - } - for (size_t i = 1; i < lineage.size(); i++) { - s << "_ => {"; - s << "panic!(\"Couldn't parse " << util::CamelCaseToUnderScore(lineage[lineage.size() - i]->name_); - s << "\n {:#02x?}\", " << util::CamelCaseToUnderScore(lineage[lineage.size() - i - 1]->name_) << "_packet); "; - s << "}}}"; - } - - s << ","; - s << "Err(e) => panic!(\"could not parse " << lineage[0]->name_ << ": {:?} {:02x?}\", e, raw_bytes),"; - s << "}"; - s << "}"; - s << ")*"; - s << "}"; - s << "}"; - - s << util::CamelCaseToUnderScore(name_) << "_builder_tests! { "; - int number = 0; - for (const auto& test_case : test_cases_) { - s << util::CamelCaseToUnderScore(name_) << "_builder_test_"; - s << std::setfill('0') << std::setw(2) << number++ << ": "; - s << "b\"" << test_case << "\","; - } - s << "}"; - s << "\n"; - } -} - -void PacketDef::GenRustDef(std::ostream& s) const { - GenRustChildEnums(s); - GenRustStructDeclarations(s); - GenRustStructImpls(s); - GenRustAccessStructImpls(s); - GenRustBuilderStructImpls(s); - GenRustBuilderTest(s); -} diff --git a/system/gd/packet/parser/packet_def.h b/system/gd/packet/parser/packet_def.h index 7c534bbb84db876ff22e1dc36f4cbd3330ea5503..91fd85f020fe099b623fd8695e59a3d0f5d9d454 100644 --- a/system/gd/packet/parser/packet_def.h +++ b/system/gd/packet/parser/packet_def.h @@ -65,22 +65,4 @@ class PacketDef : public ParentDef { void GenBuilderConstructor(std::ostream& s) const; void GenTestingFromView(std::ostream& s) const; - - void GenRustChildEnums(std::ostream& s) const; - - void GenRustStructDeclarations(std::ostream& s) const; - - bool GenRustStructFieldNameAndType(std::ostream& s) const; - - void GenRustStructFieldNames(std::ostream& s) const; - - void GenRustStructImpls(std::ostream& s) const; - - void GenRustAccessStructImpls(std::ostream& s) const; - - void GenRustBuilderStructImpls(std::ostream& s) const; - - void GenRustBuilderTest(std::ostream& s) const; - - void GenRustDef(std::ostream& s) const; }; diff --git a/system/gd/packet/parser/packetgen.gni b/system/gd/packet/parser/packetgen.gni index 5156a4d983085fe0f0153c68cf83628b7a493b39..35e88de148046456dc2b86364496eb0c6f5b6de6 100644 --- a/system/gd/packet/parser/packetgen.gni +++ b/system/gd/packet/parser/packetgen.gni @@ -138,57 +138,3 @@ template("packetgen_headers") { } } } - -# Generate single Rust files for each pdl -# -# Parameters: -# include: Base include path (i.e. bt/gd) -# source_root: Root of source relative to current BUILD.gn -# sources: PDL files to use for generation. -template("packetgen_rust") { - action_name = "${target_name}_gen" - all_dependent_config_name = "_${target_name}_all_dependent_config" - config(all_dependent_config_name) { - include_dirs = [ "${root_gen_dir}" ] - } - - action(action_name) { - forward_variables_from(invoker, [ "include", "sources", "source_root" ]) - assert(defined(sources), "sources must be set") - assert(defined(include), "include must be set") - assert(defined(source_root), "source root must be set") - - outdir = rebase_path(root_gen_dir) - source_root = rebase_path(source_root) - - script = "//common-mk/file_generator_wrapper.py" - binfile = "${root_out_dir}/bluetooth_packetgen" - args = [ - binfile, - "--include=${include}", - "--out=${outdir}", - "--source_root=${source_root}", - "--rust", - ] - - outputs = [] - foreach (source, sources) { - rel_source = rebase_path(source, ".") - args += [ rebase_path(source, source_root) ] - outputs += [ string_replace("${outdir}/${rel_source}.rs", ".pdl", "") ] - } - } - - # TODO: Rust source_set is not supported by gn. - # source_set(target_name) { - # sources = get_target_outputs(":${action_name}") - # deps = [ ":${action_name}" ] - # all_dependent_configs = [":${all_dependent_config_name}"] - # if (defined(invoker.all_dependent_configs)) { - # all_dependent_configs += invoker.all_dependent_configs - # } - # if (defined(invoker.configs)) { - # configs += invoker.configs - # } - # } -} diff --git a/system/gd/packet/parser/parent_def.cc b/system/gd/packet/parser/parent_def.cc index d054df9be699d0dda0e53310f73c853de9a3620a..92e661df6f5e5bc6c3932809b5e0627aa0d8574e 100644 --- a/system/gd/packet/parser/parent_def.cc +++ b/system/gd/packet/parser/parent_def.cc @@ -605,135 +605,3 @@ std::vector ParentDef::FindPathToDescendant(std::string descen bool ParentDef::HasChildEnums() const { return !children_.empty() || fields_.HasPayload(); } - -void ParentDef::GenRustConformanceCheck(std::ostream& s) const { - auto fields = fields_.GetFieldsWithTypes({ - FixedScalarField::kFieldType, - }); - - s << "if bytes.len() < " << this->GetSize(false).bytes() << " { return false; }"; - - for (auto const& field : fields) { - auto start_offset = GetOffsetForField(field->GetName(), false); - auto end_offset = GetOffsetForField(field->GetName(), true); - - auto f = (FixedScalarField*)field; - f->GenRustGetter(s, start_offset, end_offset, name_); - s << "if " << f->GetName() << " != "; - f->GenValue(s); - s << " { return false; } "; - } -} - -void ParentDef::GenRustWriteToFields(std::ostream& s) const { - auto fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - }); - - for (auto const& field : fields) { - auto start_field_offset = GetOffsetForField(field->GetName(), false); - auto end_field_offset = GetOffsetForField(field->GetName(), true); - - if (start_field_offset.empty() && end_field_offset.empty()) { - ERROR(field) << "Field location for " << field->GetName() << " is ambiguous, " - << "no method exists to determine field location from begin() or end().\n"; - } - - if (field->GetFieldType() == SizeField::kFieldType) { - const auto& field_name = ((SizeField*)field)->GetSizedFieldName(); - const auto& sized_field = fields_.GetField(field_name); - if (sized_field == nullptr) { - ERROR(field) << __func__ << ": Can't find sized field named " << field_name; - } - if (sized_field->GetFieldType() == PayloadField::kFieldType) { - std::string modifier = ((PayloadField*)sized_field)->size_modifier_; - if (modifier != "") { - ERROR(field) << __func__ << ": size modifiers not implemented yet for " << field_name; - } - - s << "let " << field->GetName() << " = " << field->GetRustDataType() - << "::try_from(self.child.get_total_size()).expect(\"payload size did not fit\");"; - } else if (sized_field->GetFieldType() == BodyField::kFieldType) { - s << "let " << field->GetName() << " = " << field->GetRustDataType() - << "::try_from(self.get_total_size() - self.get_size()).expect(\"payload size did not fit\");"; - } else if (sized_field->GetFieldType() == VectorField::kFieldType) { - const auto& vector_name = field_name + "_bytes"; - const VectorField* vector = (VectorField*)sized_field; - if (vector->element_size_.empty() || vector->element_size_.has_dynamic()) { - s << "let " << vector_name + " = self." << field_name - << ".iter().fold(0, |acc, x| acc + x.get_total_size());"; - } else { - s << "let " << vector_name + " = self." << field_name << ".len() * ((" << vector->element_size_ << ") / 8);"; - } - std::string modifier = vector->GetSizeModifier(); - if (modifier != "") { - s << "let " << vector_name << " = " << vector_name << " + " << modifier.substr(1) << ";"; - } - - s << "let " << field->GetName() << " = " << field->GetRustDataType() << "::try_from(" << vector_name - << ").expect(\"payload size did not fit\");"; - } else { - ERROR(field) << __func__ << ": Unhandled sized field type for " << field_name; - } - } - - field->GenRustWriter(s, start_field_offset, end_field_offset); - } -} - -void ParentDef::GenSizeRetVal(std::ostream& s) const { - int size = 0; - auto fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - }); - const PacketField* padded_field = nullptr; - auto padding_fields = fields_.GetFieldsWithTypes({ - PaddingField::kFieldType, - }); - if (padding_fields.size()) { - PacketField* last_field = nullptr; - for (const auto field : fields) { - if (field->GetFieldType() == PaddingField::kFieldType) { - padded_field = last_field; - } - last_field = field; - } - } - - s << "let ret = 0;"; - for (const auto field : fields) { - bool is_vector = field->GetFieldType() == VectorField::kFieldType; - if (field != padded_field) { // Skip the size of padded fields - if (is_vector) { - if (size > 0) { - if (size % 8 != 0) { - ERROR() << "size is not a multiple of 8!\n"; - } - s << "let ret = ret + " << size / 8 << ";"; - size = 0; - } - - const VectorField* vector = (VectorField*)field; - if (vector->element_size_.empty() || vector->element_size_.has_dynamic()) { - s << "let ret = ret + self." << vector->GetName() << ".iter().fold(0, |acc, x| acc + x.get_total_size());"; - } else { - s << "let ret = ret + (self." << vector->GetName() << ".len() * ((" << vector->element_size_ << ") / 8));"; - } - } else { - size += field->GetSize().bits(); - } - } else { - s << "/* Skipping " << field->GetName() << " since it is padded */"; - } - } - if (size > 0) { - if (size % 8 != 0) { - ERROR() << "size is not a multiple of 8!\n"; - } - s << "let ret = ret + " << size / 8 << ";"; - } - - s << "ret"; -} diff --git a/system/gd/packet/parser/parent_def.h b/system/gd/packet/parser/parent_def.h index 851b7ff8597a53ba5f8b5db52bb25afce49c75a9..bf316cf5008ede197c6596e7846b63b0666a682d 100644 --- a/system/gd/packet/parser/parent_def.h +++ b/system/gd/packet/parser/parent_def.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -92,9 +93,5 @@ class ParentDef : public TypeDef { bool HasChildEnums() const; - void GenRustWriteToFields(std::ostream& s) const; - void GenSizeRetVal(std::ostream& s) const; - - void GenRustConformanceCheck(std::ostream& s) const; }; diff --git a/system/gd/packet/parser/struct_def.cc b/system/gd/packet/parser/struct_def.cc index 0be002c87364196aa02a147494452fbcd2e3db3a..82a4766de403859590556d3ad5dad02d09492828 100644 --- a/system/gd/packet/parser/struct_def.cc +++ b/system/gd/packet/parser/struct_def.cc @@ -357,7 +357,7 @@ void StructDef::GenConstructor(std::ostream& s) const { // Initialize remaining fields. add_comma = parent_ != nullptr; for (auto const& field : params) { - if (parent_params.GetField(field->GetName()) != nullptr) { + if (fields_.GetField(field->GetName()) == nullptr) { continue; } if (add_comma) { @@ -401,116 +401,3 @@ Size StructDef::GetStructOffsetForField(std::string field_name) const { return size; } - -void StructDef::GenRustFieldNameAndType(std::ostream& s, bool include_fixed) const { - auto fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - }); - for (const auto& field : fields) { - if (!include_fixed && field->GetFieldType() == FixedScalarField::kFieldType) { - continue; - } - field->GenRustNameAndType(s); - s << ", "; - } -} - -void StructDef::GenRustFieldNames(std::ostream& s) const { - auto fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - }); - for (const auto& field : fields) { - s << field->GetName(); - s << ", "; - } -} - -void StructDef::GenRustDeclarations(std::ostream& s) const { - s << "#[derive(Debug, Clone, PartialEq)] "; - s << "pub struct " << name_ << "{"; - - // Generate struct fields - auto fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - }); - for (const auto& field : fields) { - s << "pub "; - field->GenRustNameAndType(s); - s << ", "; - } - s << "}\n"; -} - -void StructDef::GenRustImpls(std::ostream& s) const { - s << "impl " << name_ << "{"; - - s << "fn conforms(bytes: &[u8]) -> bool {"; - GenRustConformanceCheck(s); - s << " true"; - s << "}"; - - s << "pub fn parse(bytes: &[u8]) -> Result {"; - auto fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - }); - - for (const auto& field : fields) { - auto start_field_offset = GetOffsetForField(field->GetName(), false); - auto end_field_offset = GetOffsetForField(field->GetName(), true); - - if (start_field_offset.empty() && end_field_offset.empty()) { - ERROR(field) << "Field location for " << field->GetName() << " is ambiguous, " - << "no method exists to determine field location from begin() or end().\n"; - } - - field->GenBoundsCheck(s, start_field_offset, end_field_offset, name_); - field->GenRustGetter(s, start_field_offset, end_field_offset, name_); - } - - fields = fields_.GetFieldsWithoutTypes({ - BodyField::kFieldType, - CountField::kFieldType, - PaddingField::kFieldType, - ReservedField::kFieldType, - SizeField::kFieldType, - }); - - s << "Ok(Self {"; - for (const auto& field : fields) { - if (field->GetFieldType() == FixedScalarField::kFieldType) { - s << field->GetName() << ": "; - static_cast(field)->GenValue(s); - } else { - s << field->GetName(); - } - s << ", "; - } - s << "})}\n"; - - // write_to function - s << "fn write_to(&self, buffer: &mut [u8]) {"; - GenRustWriteToFields(s); - s << "}\n"; - - s << "fn get_total_size(&self) -> usize {"; - GenSizeRetVal(s); - s << "}"; - s << "}\n"; -} - -void StructDef::GenRustDef(std::ostream& s) const { - GenRustDeclarations(s); - GenRustImpls(s); -} diff --git a/system/gd/packet/parser/struct_def.h b/system/gd/packet/parser/struct_def.h index 3620b3a88c823cc71886accb2339a41a5bb90fec..c5b81250ef988fcc6fa9756948790b538be2f717 100644 --- a/system/gd/packet/parser/struct_def.h +++ b/system/gd/packet/parser/struct_def.h @@ -51,16 +51,6 @@ class StructDef : public ParentDef { Size GetStructOffsetForField(std::string field_name) const; - void GenRustDeclarations(std::ostream& s) const; - - void GenRustImpls(std::ostream& s) const; - - void GenRustFieldNameAndType(std::ostream& s, bool include_fixed) const; - - void GenRustFieldNames(std::ostream& s) const; - - void GenRustDef(std::ostream& s) const; - private: Size total_size_; }; diff --git a/system/gd/packet/parser/test/generated_packet_test.cc b/system/gd/packet/parser/test/generated_packet_test.cc index a5f1c165e3ee33fa810c9a190cfcdf9b353fc412..2c85d687222dc973f77f191338ea9505fd448c41 100644 --- a/system/gd/packet/parser/test/generated_packet_test.cc +++ b/system/gd/packet/parser/test/generated_packet_test.cc @@ -1965,6 +1965,38 @@ TEST(GeneratedPacketTest, testToStringOneFixedTypesStruct) { view.ToString()); } +TEST(GeneratedPacketTest, testCreateOptional) { + auto packet = ChildTwoTwoThreeBuilder::Create(); + + ASSERT_EQ(child_two_two_three.size(), packet->size()); + + std::shared_ptr> packet_bytes = std::make_shared>(); + BitInserter it(*packet_bytes); + packet->Serialize(it); + + PacketView packet_bytes_view(packet_bytes); + auto wrong_view = ParentView::CreateOptional(packet_bytes_view); + ASSERT_FALSE(wrong_view.has_value()); + + auto parent_view = ParentTwoView::CreateOptional(packet_bytes_view); + ASSERT_EQ(FourBits::TWO, parent_view->GetFourBits()); + + auto child_view = ChildTwoTwoView::CreateOptional(*parent_view); + ASSERT_EQ(FourBits::THREE, child_view->GetMoreBits()); + + auto grandchild_view = ChildTwoTwoThreeView::CreateOptional(*child_view); + ASSERT_TRUE(grandchild_view.has_value()); +} + +TEST(GeneratedPacketTest, testStructWithShadowedNames) { + uint32_t four_bytes = 0x01020304; + StructType struct_type = StructType::TWO_BYTE; + auto ebs = AtLeastFourByteStruct(four_bytes, struct_type); + + ASSERT_EQ(ebs.four_bytes_, four_bytes); + ASSERT_EQ(ebs.struct_type_, struct_type); +} + } // namespace parser } // namespace packet } // namespace bluetooth diff --git a/system/gd/packet/parser/test/rust_test_packets.pdl b/system/gd/packet/parser/test/rust_test_packets.pdl deleted file mode 100644 index 38ee0258db6814eb97fc1e0934d40105e09bf161..0000000000000000000000000000000000000000 --- a/system/gd/packet/parser/test/rust_test_packets.pdl +++ /dev/null @@ -1,164 +0,0 @@ -little_endian_packets - -custom_field Boolean: 8 "Boolean" -enum Enum : 8 { - // Keep 0x0 as invalid value - ONE = 1, - TWO = 2, -} - -struct Struct { - v: Enum, - u: 8, -} - -packet TestEnum { - v: Enum, -} - -packet TestCustomField { - v: Boolean, -} - -packet TestArraySize { - _size_(array) : 8, - array : Struct[], -} - -packet TestArrayCount { - _count_(array) : 8, - array : Struct[], -} - -packet TestPayloadSize { - _size_(_payload_) : 8, - _payload_, -} - -packet TestBodySize { - _size_(_body_) : 8, - _body_, -} - -// Test Packets #1 -enum OpCode: 8 { - ADD_ERR = 0, - SUB_ERR = 1, - ADD_RES = 2, - SUB_RES = 3, - ADD = 4, - SUB = 5, -} - -packet Command { - op_code : OpCode, - _size_(_payload_) : 8, - _payload_, -} - -// Packets for interfaces - -packet ComputeCommand : Command { _payload_, } -packet ResCommand: Command { _payload_, } -packet ErrCommand: Command { _payload_, } - - -packet AddRes: ResCommand (op_code = ADD_RES) { -} - -packet SubRes: ResCommand (op_code = SUB_RES) { -} - -packet AddCommand: ComputeCommand (op_code = ADD) { -} - -packet SubCommand: ComputeCommand (op_code = SUB) { -} - -packet AddErr: ErrCommand(op_code = ADD_ERR) { -} - -packet SubErr: ErrCommand(op_code = SUB_ERR) { -} - -test AddRes { - "\x02\x00", -} - -test SubRes { - "\x03\x00", -} - -test AddCommand { - "\x04\x00", -} - -test SubCommand { - "\x05\x00", -} - -test AddErr { - "\x00\x00", -} - -test SubErr { - "\x01\x00", -} - - -// Test Packets #2 -enum Number : 8 { - ZERO = 0, - ONE = 1, - TWO = 2, - THREE = 3, - FOUR = 4, -} - -packet GrandParent { - field_one : Number, - field_two : Number, - field_three: Number, - field_x: Number, - _payload_, -} - -packet Parent : GrandParent { - field_four: Number, - field_five: Number, - field_y: Number, - _payload_, -} - - -packet ChildOneTwo: Parent (field_one = ONE, field_two = TWO) { -} - -packet ChildThreeFour : Parent (field_one = THREE, field_two = FOUR) { -} - -packet ChildThree: Parent(field_three = THREE) { - _fixed_ = 5 : 8, -} - -packet GrandChildThreeFive: ChildThree(field_five = ZERO) { -} - -packet GrandChildThreeY: ChildThree(field_y = FOUR) { -} - -test ChildOneTwo { - "\x01\x02\x03\x01\x01\x02\x03", -} - -test ChildThreeFour { - "\x03\x04\x03\x01\x03\x04\x03", -} - -test ChildThree { - "\x01\x04\x03\x04\x03\x00\x02\x05", -} - -test GrandChildThreeFive { - "\x01\x04\x03\x04\x03\x00\x02\x05", -} diff --git a/system/gd/packet/parser/util.h b/system/gd/packet/parser/util.h index 342e1c5bd4efe8317ec03868667683a2dd204ad5..f252ac6e5de141a3deb774786031d38016778957 100644 --- a/system/gd/packet/parser/util.h +++ b/system/gd/packet/parser/util.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -159,20 +160,6 @@ inline std::string StringFindAndReplaceAll(std::string text, const std::string& return text; } -inline std::string GetRustTypeForSize(int size) { - if (size > 64) { - ERROR() << __func__ << ": Cannot use a type larger than 64 bits. (" << size << ")\n"; - } - - if (size <= 8) return "u8"; - - if (size <= 16) return "u16"; - - if (size <= 32) return "u32"; - - return "u64"; -} - inline std::string ToLowerCase(std::string value) { if (value[0] < 'A' || value[0] > 'Z') { ERROR() << value << " doesn't look like CONSTANT_CASE"; diff --git a/system/gd/packet/python3_module.cc b/system/gd/packet/python3_module.cc index 743d7544dbe94a548bf865faaf99497023845728..3059114d191b104b3383fa9132f9e621b5adba28 100644 --- a/system/gd/packet/python3_module.cc +++ b/system/gd/packet/python3_module.cc @@ -19,8 +19,6 @@ #include #include -#include "hci/address.h" -#include "hci/class_of_device.h" #include "packet/base_packet_builder.h" #include "packet/bit_inserter.h" #include "packet/checksum_type_checker.h" @@ -38,14 +36,9 @@ namespace bluetooth { namespace l2cap { void define_l2cap_packets_submodule(py::module&); } -namespace security { -void define_smp_packets_submodule(py::module&); -} namespace packet { -using ::bluetooth::hci::Address; -using ::bluetooth::hci::ClassOfDevice; using ::bluetooth::packet::BasePacketBuilder; using ::bluetooth::packet::BaseStruct; using ::bluetooth::packet::BitInserter; @@ -104,8 +97,6 @@ PYBIND11_MODULE(bluetooth_packets_python3, m) { py::module l2cap_m = m.def_submodule("l2cap_packets", "A submodule of l2cap_packets"); bluetooth::l2cap::define_l2cap_packets_submodule(l2cap_m); - py::module security_m = m.def_submodule("security_packets", "A submodule of security_packets"); - bluetooth::security::define_smp_packets_submodule(security_m); } } // namespace packet diff --git a/system/gd/proto/Android.bp b/system/gd/proto/Android.bp index 538d8df347fc94a6d9f0e9a34302792e40887e00..6136cf84f6c4c2c0846f651137d87267af2c134c 100644 --- a/system/gd/proto/Android.bp +++ b/system/gd/proto/Android.bp @@ -14,7 +14,6 @@ java_library_static { type: "lite", }, srcs: [ - "bluetooth/bluetoothKeystore/keystore.proto", "bluetooth/metrics/bluetooth.proto", ], apex_available: [ @@ -24,21 +23,11 @@ java_library_static { sdk_version: "current", } -cc_library_static { - name: "libbt-protos-lite", - host_supported: true, - proto: { - export_proto_headers: true, - type: "lite", - }, +filegroup { + name: "bluetooth-metrics-proto", srcs: [ - "bluetooth/bluetoothKeystore/keystore.proto", "bluetooth/metrics/bluetooth.proto", ], - apex_available: [ - "com.android.btservices", - ], - min_sdk_version: "30", } cc_library_static { @@ -50,7 +39,6 @@ cc_library_static { include_dirs: ["external/protobuf/src"], }, srcs: [ - "bluetooth/bluetoothKeystore/keystore.proto", "bluetooth/metrics/bluetooth.proto", ], apex_available: [ diff --git a/system/gd/rust/common/Android.bp b/system/gd/rust/common/Android.bp index fd889115dfad4e555f21cc63bb034dc259eb1bf7..ea87f8b60f5020b20fc745a7552b971024f729d1 100644 --- a/system/gd/rust/common/Android.bp +++ b/system/gd/rust/common/Android.bp @@ -34,8 +34,34 @@ rust_library { ], }, }, + min_sdk_version: "Tiramisu", +} + +rust_library { + name: "libbt_common_only_init_flags", + defaults: ["gd_rust_defaults"], + crate_name: "bt_common", + srcs: ["src/lib_only_init_flags.rs"], + rustlibs: [ + "liblazy_static", + "liblog_rust", + ], + target: { + android: { + rustlibs: [ + "libandroid_logger", + ], + }, + host: { + rustlibs: [ + "libenv_logger", + ], + }, + }, + proc_macros: [ + "libpaste", + ], apex_available: [ - "//apex_available:platform", "com.android.btservices", ], min_sdk_version: "Tiramisu", @@ -80,9 +106,6 @@ rust_ffi_static { ], }, }, - apex_available: [ - "com.android.btservices", - ], min_sdk_version: "30", } @@ -110,10 +133,6 @@ cc_library_static { "-Wno-unused-const-variable", ], host_supported: true, - apex_available: [ - "//apex_available:platform", - "com.android.btservices", - ], shared_libs: [ "libchrome", ], @@ -137,10 +156,6 @@ cc_library_static { "libchrome", ], host_supported: true, - apex_available: [ - "//apex_available:platform", - "com.android.btservices", - ], min_sdk_version: "30", } @@ -148,10 +163,6 @@ cc_library_headers { name: "libbt_keystore_cc_headers", local_include_dirs: ["keystore"], host_supported: true, - apex_available: [ - "//apex_available:platform", - "com.android.btservices", - ], min_sdk_version: "30", } @@ -163,10 +174,6 @@ cc_library_static { "libbt_common_ffi", ], host_supported: true, - apex_available: [ - "//apex_available:platform", - "com.android.btservices", - ], min_sdk_version: "30", } diff --git a/system/gd/rust/common/Cargo.toml b/system/gd/rust/common/Cargo.toml index 40f53a2a337bc45acda4addec49f555a3011ce40..eb593779478bed19a52453b6979749275493c80b 100644 --- a/system/gd/rust/common/Cargo.toml +++ b/system/gd/rust/common/Cargo.toml @@ -25,7 +25,7 @@ futures = "0.3.13" grpcio = "0.9" lazy_static = "1.4" log = "0.4" -nix = "0.23" +nix = { version = "0.27.1", features = ["time", "user"] } tokio = { version = "1.0", features = ['bytes', 'macros', 'net', 'rt-multi-thread', 'time'] } # Proc Macro dependency diff --git a/system/gd/rust/common/src/bridge.rs b/system/gd/rust/common/src/bridge.rs index 6c3c281ee60b051e4bef61341e67223f58647f2c..974ee8363c6d376f0173f794d9ca82c3cec77adc 100644 --- a/system/gd/rust/common/src/bridge.rs +++ b/system/gd/rust/common/src/bridge.rs @@ -2,6 +2,7 @@ pub use crate::parameter_provider::*; +#[allow(unsafe_op_in_unsafe_fn)] #[cxx::bridge(namespace = "bluetooth::fake_bluetooth_keystore")] /// ffi extern module pub mod ffi { diff --git a/system/gd/rust/common/src/init_flags.rs b/system/gd/rust/common/src/init_flags.rs index 598346c16ec1e85bb32e75d2f8e42ca700bd663c..6a41c0f306b5138018e3727e6270e9a0e9db5c69 100644 --- a/system/gd/rust/common/src/init_flags.rs +++ b/system/gd/rust/common/src/init_flags.rs @@ -362,38 +362,27 @@ init_flags!( asha_phy_update_retry_limit: i32 = 5, always_send_services_if_gatt_disc_done = true, always_use_private_gatt_for_debugging, - asynchronously_start_l2cap_coc = true, - btaa_hci = true, + bluetooth_power_telemetry = false, bta_dm_clear_conn_id_on_client_close = true, btm_dm_flush_discovery_queue_on_search_cancel, + bta_dm_stop_discovery_on_search_cancel, classic_discovery_only, clear_hidd_interrupt_cid_on_disconnect = true, delay_hidh_cleanup_until_hidh_ready_start = true, device_iot_config_logging, dynamic_avrcp_version_enhancement = true, - finite_att_timeout = true, gatt_robust_caching_client = true, gatt_robust_caching_server, - gd_core, - gd_hal_snoop_logger_socket = true, - gd_hal_snoop_logger_filtering = true, - gd_l2cap, - gd_link_policy, - gd_remote_name_request, - gd_rust, hci_adapter: i32, hfp_dynamic_version = true, irk_rotation, leaudio_targeted_announcement_reconnection_mode = true, - pass_phy_update_callback = true, pbap_pse_dynamic_version_upgrade = false, periodic_advertising_adi = true, private_gatt = true, - queue_l2cap_coc_while_encrypting = true, - read_encryption_key_size = true, redact_log = true, rust_event_loop = true, - sco_codec_select_lc3, + sco_codec_select_lc3 = true, sco_codec_timeout_clear, sdp_serialization = true, sdp_skip_rnr_if_known = true, @@ -403,6 +392,9 @@ init_flags!( trigger_advertising_callbacks_on_first_resume_after_pause = true, use_unified_connection_manager, sdp_return_classic_services_when_le_discovery_fails = true, + use_rsi_from_cached_inqiry_results = false, + att_mtu_default: i32 = 517, + encryption_in_busy_state = true, } // dynamic flags can be updated at runtime and should be accessed directly // to check. @@ -471,10 +463,10 @@ mod tests { fn simple_flag() { let _guard = ASYNC_LOCK.lock().unwrap(); test_load(vec![ - "INIT_btaa_hci=false", //override a default flag + "INIT_private_gatt=false", //override a default flag "INIT_gatt_robust_caching_server=true", ]); - assert!(!btaa_hci_is_enabled()); + assert!(!private_gatt_is_enabled()); assert!(gatt_robust_caching_server_is_enabled()); } #[test] @@ -483,10 +475,10 @@ mod tests { test_load(vec![ "foo=bar=?", // vec length "foo=bar", // flag not save - "INIT_btaa_hci=not_false", // parse error but has default value + "INIT_private_gatt=not_false", // parse error but has default value "INIT_gatt_robust_caching_server=not_true", // parse error ]); - assert!(btaa_hci_is_enabled()); + assert!(private_gatt_is_enabled()); assert!(!gatt_robust_caching_server_is_enabled()); } #[test] @@ -532,8 +524,8 @@ mod tests { #[test] fn test_runtime_update() { let _guard = ASYNC_LOCK.lock().unwrap(); - test_load(vec!["INIT_btaa_hci=true", "INIT_default_log_level_str=LOG_WARN"]); - assert!(btaa_hci_is_enabled()); + test_load(vec!["INIT_private_gatt=true", "INIT_default_log_level_str=LOG_WARN"]); + assert!(private_gatt_is_enabled()); assert!(get_default_log_level() == LOG_TAG_WARN); update_default_log_level(LOG_TAG_DEBUG); diff --git a/system/gd/rust/common/src/lib.rs b/system/gd/rust/common/src/lib.rs index 095adfbb534075e0e85cbbf4e253c95a2a1e2cf1..50fd92087d0cb2401cc4433d32c178fa00e7ccda 100644 --- a/system/gd/rust/common/src/lib.rs +++ b/system/gd/rust/common/src/lib.rs @@ -1,10 +1,5 @@ //! Bluetooth common library -use init_flags::{ - get_log_level_for_tag, LOG_TAG_DEBUG, LOG_TAG_ERROR, LOG_TAG_FATAL, LOG_TAG_INFO, - LOG_TAG_NOTICE, LOG_TAG_VERBOSE, LOG_TAG_WARN, -}; - /// Provides waking timer abstractions pub mod time; @@ -26,38 +21,8 @@ pub mod init_flags; /// Provides runtime configured system properties. Stubbed for non-Android. pub mod sys_prop; -fn get_log_level() -> log::Level { - match get_log_level_for_tag("bluetooth_core") { - LOG_TAG_FATAL => log::Level::Error, - LOG_TAG_ERROR => log::Level::Error, - LOG_TAG_WARN => log::Level::Warn, - LOG_TAG_NOTICE => log::Level::Info, - LOG_TAG_INFO => log::Level::Info, - LOG_TAG_DEBUG => log::Level::Debug, - LOG_TAG_VERBOSE => log::Level::Trace, - _ => log::Level::Info, // default level - } -} - -/// Inits logging for Android -#[cfg(target_os = "android")] -pub fn init_logging() { - android_logger::init_once( - android_logger::Config::default().with_tag("bt").with_min_level(get_log_level()), - ); - log::set_max_level(get_log_level().to_level_filter()) -} - -/// Inits logging for host -#[cfg(not(target_os = "android"))] -pub fn init_logging() { - env_logger::Builder::new() - .filter(None, get_log_level().to_level_filter()) - .parse_default_env() - .try_init() - .ok(); - log::set_max_level(get_log_level().to_level_filter()) -} +mod logging; +pub use logging::*; /// Indicates the object can be converted to a GRPC service pub trait GrpcFacade { diff --git a/system/gd/rust/common/src/lib_only_init_flags.rs b/system/gd/rust/common/src/lib_only_init_flags.rs new file mode 100644 index 0000000000000000000000000000000000000000..c4001f575af16261d4485abe8a5acc01b4c4bcef --- /dev/null +++ b/system/gd/rust/common/src/lib_only_init_flags.rs @@ -0,0 +1,7 @@ +//! Bluetooth common library + +/// Provides runtime configured-at-startup flags +pub mod init_flags; + +mod logging; +pub use logging::*; diff --git a/system/gd/rust/common/src/logging.rs b/system/gd/rust/common/src/logging.rs new file mode 100644 index 0000000000000000000000000000000000000000..d51e5b3b66bf87d156568c2f30db9ea75da8da9f --- /dev/null +++ b/system/gd/rust/common/src/logging.rs @@ -0,0 +1,37 @@ +use crate::init_flags::{ + get_log_level_for_tag, LOG_TAG_DEBUG, LOG_TAG_ERROR, LOG_TAG_FATAL, LOG_TAG_INFO, + LOG_TAG_NOTICE, LOG_TAG_VERBOSE, LOG_TAG_WARN, +}; + +fn get_log_level() -> log::Level { + match get_log_level_for_tag("bluetooth_core") { + LOG_TAG_FATAL => log::Level::Error, + LOG_TAG_ERROR => log::Level::Error, + LOG_TAG_WARN => log::Level::Warn, + LOG_TAG_NOTICE => log::Level::Info, + LOG_TAG_INFO => log::Level::Info, + LOG_TAG_DEBUG => log::Level::Debug, + LOG_TAG_VERBOSE => log::Level::Trace, + _ => log::Level::Info, // default level + } +} + +/// Inits logging for Android +#[cfg(target_os = "android")] +pub fn init_logging() { + android_logger::init_once( + android_logger::Config::default().with_tag("bt").with_min_level(get_log_level()), + ); + log::set_max_level(get_log_level().to_level_filter()) +} + +/// Inits logging for host +#[cfg(not(target_os = "android"))] +pub fn init_logging() { + env_logger::Builder::new() + .filter(None, get_log_level().to_level_filter()) + .parse_default_env() + .try_init() + .ok(); + log::set_max_level(get_log_level().to_level_filter()) +} diff --git a/system/gd/rust/common/src/parameter_provider.rs b/system/gd/rust/common/src/parameter_provider.rs index d4d32a0295dd4d25f5e5e88d28289a70f978f572..50ac00fb5dbd5e2a81f3f87956462a71e2209b17 100644 --- a/system/gd/rust/common/src/parameter_provider.rs +++ b/system/gd/rust/common/src/parameter_provider.rs @@ -18,7 +18,11 @@ pub struct ParameterProvider { lock: Mutex, } +// SAFETY: Nothing about `BluetoothKeystoreInterface` is bound to a specific thread, and all other +// fields are `Send`. unsafe impl Send for ParameterProvider {} + +// SAFETY: Nothing about `BluetoothKeystoreInterface` is bound to a specific thread. unsafe impl Send for BluetoothKeystoreInterface {} impl ParameterProvider { @@ -243,6 +247,8 @@ mod tests { assert_eq!(now, "/data/misc/bluetooth/logs/btsnooz_hci.log"); } + // TODO(b/290018030): Remove this and add proper safety comments. + #[allow(clippy::undocumented_unsafe_blocks)] #[ignore] #[tokio::test] async fn test_bt_keystore_interface() { @@ -292,11 +298,20 @@ mod tests { } let current = (*param_provider.lock().await).get_bt_keystore_interface().await; - let address_current = format!("{:p}", ¤t); - let reality = *hex_to_dec(address_current); - let mut answer = *hex_to_dec(Arc::clone(&address1).lock().await.to_string()); + let reality = current as i64; + // TODO: Fix unsoundness. `address1` contains a string representation of a pointer to a + // `cxx::UniquePtr` on the stack; either `choice_ptr1` (which is still in scope, so it is + // valid) or to `ptr1` (which is in another task which may have finished, so may not be + // valid). If it were valid, then transmuting the `cxx::UniquePtr` to an `i64` is probably + // fine, though a dubious thing to do. + let mut answer = unsafe { *(hex_to_dec(&address1.lock().await) as *const i64) }; if *choice.lock().await == "2" { - answer = *hex_to_dec(Arc::clone(&address2).lock().await.to_string()); + // TODO: Fix unsoundness. `address2` contains a string representation of a pointer to a + // `cxx::UniquePtr` on the stack; either `choice_ptr2` (which is still in scope, so it + // is valid) or to `ptr2` (which is in another task which may have finished, so may not + // be valid). If it were valid, then transmuting the `cxx::UniquePtr` to an `i64` is + // probably fine, though a dubious thing to do. + answer = unsafe { *(hex_to_dec(&address2.lock().await) as *const i64) }; } assert_eq!(reality, answer); } @@ -382,11 +397,9 @@ mod tests { assert_eq!(now, 0b11); } - fn hex_to_dec(origin: String) -> &'static i64 { - let address = unsafe { - let origin = origin.trim_start_matches("0x"); - &*(usize::from_str_radix(origin, 16).unwrap() as *const i64) - }; - address + /// Converts a hex string to an integer + fn hex_to_dec(origin: &str) -> usize { + let origin = origin.trim_start_matches("0x"); + usize::from_str_radix(origin, 16).unwrap() } } diff --git a/system/gd/rust/common/src/time.rs b/system/gd/rust/common/src/time.rs index 2334604487594bdc29ab2dcaa35e92c1d262c96d..0fd2226a4a5e95bec158ff2f58c239d3c4c9a0a8 100644 --- a/system/gd/rust/common/src/time.rs +++ b/system/gd/rust/common/src/time.rs @@ -1,20 +1,45 @@ -///! Waking timers for Bluetooth. Implemented using timerfd, but supposed to feel similar to +//! Waking timers for Bluetooth. Implemented using timerfd, but supposed to feel similar to ///Tokio's time use nix::sys::time::TimeSpec; use nix::sys::timerfd::{ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags}; +use std::os::fd::{AsFd, AsRawFd, RawFd}; use std::time::Duration; use tokio::io::unix::AsyncFd; +/// A wrapper for `TimerFd` which implements `AsRawFd`. +#[derive(Debug)] +struct TimerFdWrapper(TimerFd); + +impl TimerFdWrapper { + fn get(&self) -> nix::Result> { + self.0.get() + } + + fn set(&self, expiration: Expiration, flags: TimerSetTimeFlags) -> nix::Result<()> { + self.0.set(expiration, flags) + } + + fn wait(&self) -> nix::Result<()> { + self.0.wait() + } +} + +impl AsRawFd for TimerFdWrapper { + fn as_raw_fd(&self) -> RawFd { + self.0.as_fd().as_raw_fd() + } +} + /// A single shot Alarm pub struct Alarm { - fd: AsyncFd, + fd: AsyncFd, } impl Alarm { /// Construct a new alarm pub fn new() -> Self { let timer = TimerFd::new(get_clock(), TimerFlags::empty()).unwrap(); - Self { fd: AsyncFd::new(timer).unwrap() } + Self { fd: AsyncFd::new(TimerFdWrapper(timer)).unwrap() } } /// Reset the alarm to duration, starting from now @@ -53,12 +78,12 @@ pub fn interval(period: Duration) -> Interval { let timer = TimerFd::new(get_clock(), TimerFlags::empty()).unwrap(); timer.set(Expiration::Interval(TimeSpec::from(period)), TimerSetTimeFlags::empty()).unwrap(); - Interval { fd: AsyncFd::new(timer).unwrap() } + Interval { fd: AsyncFd::new(TimerFdWrapper(timer)).unwrap() } } /// Future returned by interval() pub struct Interval { - fd: AsyncFd, + fd: AsyncFd, } impl Interval { diff --git a/system/gd/rust/facade/Android.bp b/system/gd/rust/facade/Android.bp index 4444ccfce342d2daa0c6e8f3c7a380345fd631cf..f416c5c9dffd0583de93b2488da0cc2ba28c675d 100644 --- a/system/gd/rust/facade/Android.bp +++ b/system/gd/rust/facade/Android.bp @@ -20,7 +20,7 @@ rust_library { "libgddi", "libgrpcio", "liblog_rust", - "libprotobuf_deprecated", + "libprotobuf", "libtokio", ], } @@ -75,11 +75,8 @@ rust_library { "libfutures", "libgrpcio", "liblog_rust", - "libprotobuf_deprecated", + "libprotobuf", "libtokio", ], - apex_available: [ - "com.android.btservices", - ], min_sdk_version: "30", } diff --git a/system/gd/rust/facade/helpers/lib.rs b/system/gd/rust/facade/helpers/lib.rs index f2b683842849f9328de143a1f517813a25aa5f7a..ea18c5218a9f9e17c82271baa8c2df4f522a32fd 100644 --- a/system/gd/rust/facade/helpers/lib.rs +++ b/system/gd/rust/facade/helpers/lib.rs @@ -41,8 +41,7 @@ impl> + Into + Send> RxAdapter { let clone_rx = self.rx.clone(); ctx.spawn(async move { while let Some(payload) = clone_rx.lock().await.recv().await { - let mut data = Data::default(); - data.set_payload(payload.into()); + let data = Data { payload: payload.into(), ..Default::default() }; if let Err(e) = sink.send((data, WriteFlags::default())).await { log::error!("failure sending data: {:?}", e); } diff --git a/system/gd/rust/facade/src/lib.rs b/system/gd/rust/facade/src/lib.rs index 973e9a2731f64740a09087748345e834c459a95a..db5d15abbb30ee56d85a1b93dd0fb67cca00148a 100644 --- a/system/gd/rust/facade/src/lib.rs +++ b/system/gd/rust/facade/src/lib.rs @@ -76,7 +76,7 @@ struct FacadeServer { impl FacadeServer { async fn start(stack: Stack, req: StartStackRequest, grpc_port: u16) -> Self { let mut services = Vec::new(); - match req.get_module_under_test() { + match req.module_under_test.unwrap() { BluetoothModule::HAL => { services.push(stack.get_grpc::().await); } @@ -88,12 +88,15 @@ impl FacadeServer { } let env = Arc::new(Environment::new(2)); - let mut builder = ServerBuilder::new(env).bind("0.0.0.0", grpc_port); + let mut builder = ServerBuilder::new(env); for service in services { builder = builder.register_service(service); } let mut server = builder.build().unwrap(); + let addr = format!("0.0.0.0:{}", grpc_port); + let creds = ServerCredentials::insecure(); + server.add_listening_port(addr, creds).unwrap(); server.start(); Self { server, stack } diff --git a/system/gd/rust/facade/src/main.rs b/system/gd/rust/facade/src/main.rs index 3bd53b05d4396b14e99b79497b96df535987fdbe..68df7deaef5b26ffa672a83071e7bc260c97e047 100644 --- a/system/gd/rust/facade/src/main.rs +++ b/system/gd/rust/facade/src/main.rs @@ -13,7 +13,8 @@ use std::sync::{Arc, Mutex}; use tokio::runtime::Runtime; fn main() { - let sigint = install_sigint(); + // SAFETY: There is no signal handler installed before this. + let sigint = unsafe { install_sigint() }; bt_common::init_logging(); let rt = Arc::new(Runtime::new().unwrap()); rt.block_on(async_main(Arc::clone(&rt), sigint)); @@ -60,9 +61,11 @@ async fn async_main(rt: Arc, mut sigint: mpsc::UnboundedReceiver<()>) { rootcanal_port, matches.get_one::("btsnoop").cloned(), )) - .bind("0.0.0.0", root_server_port) .build() .unwrap(); + let addr = format!("0.0.0.0:{}", root_server_port); + let creds = ServerCredentials::insecure(); + server.add_listening_port(addr, creds).unwrap(); server.start(); sigint.next().await; @@ -70,7 +73,10 @@ async fn async_main(rt: Arc, mut sigint: mpsc::UnboundedReceiver<()>) { } // TODO: remove as this is a temporary nix-based hack to catch SIGINT -fn install_sigint() -> mpsc::UnboundedReceiver<()> { +/// # Safety +/// +/// The old signal handler, if any, must be installed correctly. +unsafe fn install_sigint() -> mpsc::UnboundedReceiver<()> { let (tx, rx) = mpsc::unbounded(); *SIGINT_TX.lock().unwrap() = Some(tx); @@ -79,6 +85,10 @@ fn install_sigint() -> mpsc::UnboundedReceiver<()> { signal::SaFlags::empty(), signal::SigSet::empty(), ); + // SAFETY: The caller guarantees that the old signal handler was installed correctly. + // TODO(b/292218119): Make sure `handle_sigint` only makes system calls that are safe for signal + // handlers, and only accesses global state through atomics. In particular, it must not take any + // shared locks. unsafe { signal::sigaction(signal::SIGINT, &sig_action).unwrap(); } diff --git a/system/gd/rust/facade_proto/build.rs b/system/gd/rust/facade_proto/build.rs index 99645e17df3d524baa6f952230b972f09332fff4..87b9fe6d63e47737189476ba5089616d597a266a 100644 --- a/system/gd/rust/facade_proto/build.rs +++ b/system/gd/rust/facade_proto/build.rs @@ -13,9 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate protoc_grpcio; -extern crate protoc_rust; - use std::env; use std::fs; use std::io::Write; diff --git a/system/gd/rust/facade_proto/src/lib.rs b/system/gd/rust/facade_proto/src/lib.rs index 56f7f7077508c35336a9dbe6aec49a7a3c60ce59..c6acbb2b16e60ce4f07459bd19779172eb64406d 100644 --- a/system/gd/rust/facade_proto/src/lib.rs +++ b/system/gd/rust/facade_proto/src/lib.rs @@ -21,5 +21,5 @@ include!(concat!(env!("OUT_DIR"), "/grpc_out/mod.rs")); // empty.proto is missing so add a workaround // See github.com/stepancheg/grpc-rust/issues/156 pub mod empty { - pub use protobuf::well_known_types::Empty; + pub use protobuf::well_known_types::empty::Empty; } diff --git a/system/gd/rust/gddi/Android.bp b/system/gd/rust/gddi/Android.bp index ac8ed8b475a1d2a6885b5bfa936d047796a295b4..f004ba48455a81ab53a388ac77ae2e8f1ffec366 100644 --- a/system/gd/rust/gddi/Android.bp +++ b/system/gd/rust/gddi/Android.bp @@ -15,9 +15,6 @@ rust_library { edition: "2018", proc_macros: ["libgddi_macros"], rustlibs: ["libtokio"], - apex_available: [ - "com.android.btservices", - ], min_sdk_version: "30", } diff --git a/system/gd/rust/gddi/macros/Cargo.toml b/system/gd/rust/gddi/macros/Cargo.toml index 53978f6624ff201c54bc45857c3762a02ecd1e92..fbbdca166dbbd28311f670cb8d667b4a8eed727e 100644 --- a/system/gd/rust/gddi/macros/Cargo.toml +++ b/system/gd/rust/gddi/macros/Cargo.toml @@ -21,7 +21,7 @@ edition = "2018" [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = "1.0" +syn = "2.0.1" [lib] proc-macro = true diff --git a/system/gd/rust/gddi/macros/lib.rs b/system/gd/rust/gddi/macros/lib.rs index ea761386dbdf3309fd10d982af60a934fa7cb821..4121098ed4bd82a9eaac0586bd2ebf5c5fd9581f 100644 --- a/system/gd/rust/gddi/macros/lib.rs +++ b/system/gd/rust/gddi/macros/lib.rs @@ -12,6 +12,7 @@ use syn::{ /// Defines a provider function, with generated helper that implicitly fetches argument instances from the registry #[proc_macro_attribute] +#[allow(clippy::redundant_clone)] pub fn provides(_attr: TokenStream, item: TokenStream) -> TokenStream { let function: ItemFn = parse(item).expect("can only be applied to functions"); @@ -116,12 +117,12 @@ impl Parse for ModuleEntry { "providers" => { let entries; braced!(entries in input); - Ok(ModuleEntry::Providers(entries.parse_terminated(ProviderDef::parse)?)) + Ok(ModuleEntry::Providers(entries.parse_terminated(ProviderDef::parse, Token![,])?)) } "submodules" => { let entries; braced!(entries in input); - Ok(ModuleEntry::Submodules(entries.parse_terminated(Path::parse)?)) + Ok(ModuleEntry::Submodules(entries.parse_terminated(Path::parse, Token![,])?)) } keyword => { panic!("unexpected keyword: {}", keyword); @@ -132,6 +133,7 @@ impl Parse for ModuleEntry { /// Emits a module function that registers submodules & providers with the registry #[proc_macro] +#[allow(clippy::redundant_clone)] pub fn module(item: TokenStream) -> TokenStream { let module = parse_macro_input!(item as ModuleDef); let init_ident = module.name.clone(); @@ -152,7 +154,7 @@ pub fn module(item: TokenStream) -> TokenStream { #[allow(missing_docs)] pub fn #init_ident(builder: gddi::RegistryBuilder) -> gddi::RegistryBuilder { // Register all providers on this module - let ret = builder#(.register_provider::<#types>(Box::new(#provider_idents)))* + let ret = builder #(.register_provider::<#types>(Box::new(#provider_idents)))* // Register all submodules on this module #(.register_module(#submodule_idents))*; @@ -177,6 +179,7 @@ pub fn derive_nop_stop(item: TokenStream) -> TokenStream { /// Generates the code necessary to split up a type into its components #[proc_macro_attribute] +#[allow(clippy::redundant_clone)] pub fn part_out(_attr: TokenStream, item: TokenStream) -> TokenStream { let struct_: ItemStruct = parse(item).expect("can only be applied to struct definitions"); let struct_ident = struct_.ident.clone(); @@ -195,7 +198,7 @@ pub fn part_out(_attr: TokenStream, item: TokenStream) -> TokenStream { #struct_ fn #fn_ident(builder: gddi::RegistryBuilder) -> gddi::RegistryBuilder { - builder#(.register_provider::<#field_types>(Box::new( + builder #(.register_provider::<#field_types>(Box::new( |registry: std::sync::Arc| -> std::pin::Pin { Box::pin(async move { Box::new(async move { diff --git a/system/gd/rust/linux/OWNERS b/system/gd/rust/linux/OWNERS index 45bfdd2be4f3b49a5c0053e783ad429ded0c1be1..a823e6e1ddc6d3d153fe4acbd207c3b06ae03b10 100644 --- a/system/gd/rust/linux/OWNERS +++ b/system/gd/rust/linux/OWNERS @@ -1 +1 @@ -include platform/packages/modules/Bluetooth:/OWNERS_chromeos +include /OWNERS_chromeos diff --git a/system/gd/rust/linux/client/Cargo.toml b/system/gd/rust/linux/client/Cargo.toml index 79db28e647e0935490374a3340e254e78ceaa81c..c949f8fafa5586367f83423fcdbe0aa72fe9fa80 100644 --- a/system/gd/rust/linux/client/Cargo.toml +++ b/system/gd/rust/linux/client/Cargo.toml @@ -20,9 +20,10 @@ dbus_macros = { path = "../dbus_projection/dbus_macros" } futures = "0.3.13" num-traits = "0.2" shell-words = "1.1.0" -tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } +tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } clap = "2.33.3" +chrono = "0.4.24" bitflags = "1.2" hex = "0.4.3" [build-dependencies] diff --git a/system/gd/rust/linux/client/src/callbacks.rs b/system/gd/rust/linux/client/src/callbacks.rs index 1610daa0f9e8771b4837734353ef341ab7da61c5..ca73daa1882b21dc34e4b8c3faf9ab032e6ad372 100644 --- a/system/gd/rust/linux/client/src/callbacks.rs +++ b/system/gd/rust/linux/client/src/callbacks.rs @@ -3,13 +3,16 @@ use crate::dbus_iface::{ export_admin_policy_callback_dbus_intf, export_advertising_set_callback_dbus_intf, export_bluetooth_callback_dbus_intf, export_bluetooth_connection_callback_dbus_intf, export_bluetooth_gatt_callback_dbus_intf, export_bluetooth_manager_callback_dbus_intf, - export_gatt_server_callback_dbus_intf, export_scanner_callback_dbus_intf, - export_socket_callback_dbus_intf, export_suspend_callback_dbus_intf, + export_bluetooth_media_callback_dbus_intf, export_bluetooth_telephony_callback_dbus_intf, + export_gatt_server_callback_dbus_intf, export_qa_callback_dbus_intf, + export_scanner_callback_dbus_intf, export_socket_callback_dbus_intf, + export_suspend_callback_dbus_intf, }; use crate::ClientContext; use crate::{console_red, console_yellow, print_error, print_info}; use bt_topshim::btif::{BtBondState, BtPropertyType, BtSspVariant, BtStatus, Uuid128Bit}; use bt_topshim::profiles::gatt::{AdvertisingStatus, GattStatus, LePhy}; +use bt_topshim::profiles::hfp::HfpCodecId; use bt_topshim::profiles::sdp::BtSdpRecord; use btstack::bluetooth::{ BluetoothDevice, IBluetooth, IBluetoothCallback, IBluetoothConnectionCallback, @@ -20,6 +23,10 @@ use btstack::bluetooth_gatt::{ BluetoothGattService, IBluetoothGattCallback, IBluetoothGattServerCallback, IScannerCallback, ScanResult, }; +use btstack::bluetooth_media::{ + BluetoothAudioDevice, IBluetoothMediaCallback, IBluetoothTelephonyCallback, +}; +use btstack::bluetooth_qa::IBluetoothQACallback; use btstack::socket_manager::{ BluetoothServerSocket, BluetoothSocket, IBluetoothSocketManager, IBluetoothSocketManagerCallbacks, SocketId, @@ -27,10 +34,12 @@ use btstack::socket_manager::{ use btstack::suspend::ISuspendCallback; use btstack::uuid::UuidWrapper; use btstack::{RPCProxy, SuspendMode}; +use chrono::{TimeZone, Utc}; use dbus::nonblock::SyncConnection; use dbus_crossroads::Crossroads; use dbus_projection::DisconnectWatcher; use manager_service::iface_bluetooth_manager::IBluetoothManagerCallback; +use std::convert::TryFrom; use std::io::{Read, Write}; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -38,6 +47,10 @@ use std::time::Duration; const SOCKET_TEST_WRITE: &[u8] = b"01234567890123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +// Avoid 32, 40, 64 consecutive hex characters so CrOS feedback redact tool +// doesn't trim our dump. +const BINARY_PACKET_STATUS_WRAP: usize = 50; + /// Callback context for manager interface callbacks. pub(crate) struct BtManagerCallback { objpath: String, @@ -117,6 +130,14 @@ impl BtCallback { impl IBluetoothCallback for BtCallback { fn on_adapter_property_changed(&mut self, _prop: BtPropertyType) {} + fn on_device_properties_changed( + &mut self, + remote_device: BluetoothDevice, + props: Vec, + ) { + print_info!("Bluetooth properties {:?} changed for {:?}", props, remote_device); + } + fn on_address_changed(&mut self, addr: String) { print_info!("Address changed to {}", &addr); self.context.lock().unwrap().adapter_address = Some(addr); @@ -275,7 +296,14 @@ impl IBluetoothCallback for BtCallback { fn on_sdp_record_created(&mut self, record: BtSdpRecord, handle: i32) { print_info!("SDP record handle={} created", handle); if let BtSdpRecord::Mps(_) = record { - self.context.lock().unwrap().mps_sdp_handle = Some(handle); + let context = self.context.clone(); + // Callbacks first lock the DBus resource and then lock the context, + // while the command handlers lock them in the reversed order. + // `telephony enable` command happens to deadlock easily, + // so use async call to prevent deadlock here. + tokio::spawn(async move { + context.lock().unwrap().mps_sdp_handle = Some(handle); + }); } } } @@ -1214,3 +1242,229 @@ impl RPCProxy for SuspendCallback { cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self))); } } + +/// Callback container for suspend interface callbacks. +pub(crate) struct QACallback { + objpath: String, + _context: Arc>, + dbus_connection: Arc, + dbus_crossroads: Arc>, +} + +impl QACallback { + pub(crate) fn new( + objpath: String, + _context: Arc>, + dbus_connection: Arc, + dbus_crossroads: Arc>, + ) -> Self { + Self { objpath, _context, dbus_connection, dbus_crossroads } + } +} + +impl IBluetoothQACallback for QACallback { + fn on_fetch_discoverable_mode_completed(&mut self, mode: bt_topshim::btif::BtDiscMode) { + print_info!("Discoverable mode: {:?}", mode); + } + + fn on_fetch_connectable_completed(&mut self, connectable: bool) { + print_info!("Connectable mode: {:?}", connectable); + } + + fn on_set_connectable_completed(&mut self, succeed: bool) { + print_info!( + "Set connectable mode: {}", + match succeed { + true => "succeeded", + false => "failed", + } + ); + } + + fn on_fetch_alias_completed(&mut self, alias: String) { + print_info!("Alias: {}", alias); + } + + fn on_get_hid_report_completed(&mut self, status: BtStatus) { + print_info!("Get HID report: {:?}", status); + } + + fn on_set_hid_report_completed(&mut self, status: BtStatus) { + print_info!("Set HID report: {:?}", status); + } + + fn on_send_hid_data_completed(&mut self, status: BtStatus) { + print_info!("Send HID data: {:?}", status); + } +} + +impl RPCProxy for QACallback { + fn get_object_id(&self) -> String { + self.objpath.clone() + } + + fn export_for_rpc(self: Box) { + let cr = self.dbus_crossroads.clone(); + let iface = export_qa_callback_dbus_intf( + self.dbus_connection.clone(), + &mut cr.lock().unwrap(), + Arc::new(Mutex::new(DisconnectWatcher::new())), + ); + cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self))); + } +} + +pub(crate) struct MediaCallback { + objpath: String, + context: Arc>, + + dbus_connection: Arc, + dbus_crossroads: Arc>, +} + +impl MediaCallback { + pub(crate) fn new( + objpath: String, + context: Arc>, + dbus_connection: Arc, + dbus_crossroads: Arc>, + ) -> Self { + Self { objpath, context, dbus_connection, dbus_crossroads } + } +} + +fn timestamp_to_string(ts_in_us: u64) -> String { + i64::try_from(ts_in_us) + .and_then(|ts| Ok(Utc.timestamp_nanos(ts * 1000).to_rfc3339())) + .unwrap_or("UNKNOWN".to_string()) +} + +impl IBluetoothMediaCallback for MediaCallback { + fn on_bluetooth_audio_device_added(&mut self, _device: BluetoothAudioDevice) {} + fn on_bluetooth_audio_device_removed(&mut self, _addr: String) {} + fn on_absolute_volume_supported_changed(&mut self, _supported: bool) {} + fn on_absolute_volume_changed(&mut self, _volume: u8) {} + fn on_hfp_volume_changed(&mut self, _volume: u8, _addr: String) {} + fn on_hfp_audio_disconnected(&mut self, _addr: String) {} + fn on_hfp_debug_dump( + &mut self, + active: bool, + codec_id: u16, + total_num_decoded_frames: i32, + pkt_loss_ratio: f64, + begin_ts: u64, + end_ts: u64, + pkt_status_in_hex: String, + pkt_status_in_binary: String, + ) { + // Invoke run_callback so that the callback can be handled through + // ForegroundActions::RunCallback in main.rs. + self.context.lock().unwrap().run_callback(Box::new(move |_context| { + let is_wbs = codec_id == HfpCodecId::MSBC as u16; + let is_swb = codec_id == HfpCodecId::LC3 as u16; + let dump = if active && (is_wbs || is_swb) { + let mut to_split_binary = pkt_status_in_binary.clone(); + let mut wrapped_binary = String::new(); + while to_split_binary.len() > BINARY_PACKET_STATUS_WRAP { + let remaining = to_split_binary.split_off(BINARY_PACKET_STATUS_WRAP); + wrapped_binary.push_str(&to_split_binary); + wrapped_binary.push('\n'); + to_split_binary = remaining; + } + wrapped_binary.push_str(&to_split_binary); + format!( + "\n--------{} packet loss--------\n\ + Decoded Packets: {}, Packet Loss Ratio: {} \n\ + {} [begin]\n\ + {} [end]\n\ + In Hex format:\n\ + {}\n\ + In binary format:\n\ + {}", + if is_wbs { "WBS" } else { "SWB" }, + total_num_decoded_frames, + pkt_loss_ratio, + timestamp_to_string(begin_ts), + timestamp_to_string(end_ts), + pkt_status_in_hex, + wrapped_binary + ) + } else { + "".to_string() + }; + + print_info!( + "\n--------HFP debug dump---------\n\ + HFP SCO: {}, Codec: {}\ + {} + ", + if active { "active" } else { "inactive" }, + if is_wbs { + "mSBC" + } else if is_swb { + "LC3" + } else { + "CVSD" + }, + dump + ); + })); + } +} + +impl RPCProxy for MediaCallback { + fn get_object_id(&self) -> String { + self.objpath.clone() + } + + fn export_for_rpc(self: Box) { + let cr = self.dbus_crossroads.clone(); + let iface = export_bluetooth_media_callback_dbus_intf( + self.dbus_connection.clone(), + &mut cr.lock().unwrap(), + Arc::new(Mutex::new(DisconnectWatcher::new())), + ); + cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self))); + } +} + +pub(crate) struct TelephonyCallback { + objpath: String, + _context: Arc>, + + dbus_connection: Arc, + dbus_crossroads: Arc>, +} + +impl TelephonyCallback { + pub(crate) fn new( + objpath: String, + context: Arc>, + dbus_connection: Arc, + dbus_crossroads: Arc>, + ) -> Self { + Self { objpath, _context: context, dbus_connection, dbus_crossroads } + } +} + +impl IBluetoothTelephonyCallback for TelephonyCallback { + fn on_telephony_use(&mut self, addr: String, state: bool) { + print_info!("Telephony use changed: [{}] state: {}", addr, state); + } +} + +impl RPCProxy for TelephonyCallback { + fn get_object_id(&self) -> String { + self.objpath.clone() + } + + fn export_for_rpc(self: Box) { + let cr = self.dbus_crossroads.clone(); + let iface = export_bluetooth_telephony_callback_dbus_intf( + self.dbus_connection.clone(), + &mut cr.lock().unwrap(), + Arc::new(Mutex::new(DisconnectWatcher::new())), + ); + cr.lock().unwrap().insert(self.get_object_id(), &[iface], Arc::new(Mutex::new(self))); + } +} diff --git a/system/gd/rust/linux/client/src/command_handler.rs b/system/gd/rust/linux/client/src/command_handler.rs index bd3934015bce2aca161b987dc9991ae7a57f0d51..262ee4a604f831427c39bb539e2e00a548112670 100644 --- a/system/gd/rust/linux/client/src/command_handler.rs +++ b/system/gd/rust/linux/client/src/command_handler.rs @@ -9,13 +9,13 @@ use crate::bt_gatt::AuthReq; use crate::callbacks::{BtGattCallback, BtGattServerCallback}; use crate::ClientContext; use crate::{console_red, console_yellow, print_error, print_info}; -use bt_topshim::btif::{BtConnectionState, BtDiscMode, BtStatus, BtTransport}; +use bt_topshim::btif::{BtConnectionState, BtDiscMode, BtStatus, BtTransport, INVALID_RSSI}; use bt_topshim::profiles::hid_host::BthhReportType; use bt_topshim::profiles::sdp::{BtSdpMpsRecord, BtSdpRecord}; use bt_topshim::profiles::{gatt::LePhy, ProfileConnectionState}; -use btstack::bluetooth::{BluetoothDevice, IBluetooth, IBluetoothQALegacy}; -use btstack::bluetooth_gatt::{GattWriteType, IBluetoothGatt, ScanSettings, ScanType}; -use btstack::bluetooth_media::IBluetoothTelephony; +use btstack::bluetooth::{BluetoothDevice, IBluetooth}; +use btstack::bluetooth_gatt::{GattWriteType, IBluetoothGatt}; +use btstack::bluetooth_media::{IBluetoothMedia, IBluetoothTelephony}; use btstack::bluetooth_qa::IBluetoothQA; use btstack::socket_manager::{IBluetoothSocketManager, SocketResult}; use btstack::uuid::{Profile, UuidHelper, UuidWrapper}; @@ -155,6 +155,7 @@ fn build_commands() -> HashMap { String::from("device set-pairing-pin

    "), String::from("device set-pairing-passkey
    "), String::from("device set-alias
    "), + String::from("device get-rssi
    "), ], description: String::from("Take action on a remote device. (i.e. info)"), function_pointer: CommandHandler::cmd_device, @@ -251,7 +252,7 @@ fn build_commands() -> HashMap { String::from( "socket connect
    ", ), - String::from("socket disconnect "), + String::from("socket close "), String::from("socket set-on-connect-schedule "), ], description: String::from("Socket manager utilities."), @@ -325,6 +326,14 @@ fn build_commands() -> HashMap { function_pointer: CommandHandler::cmd_telephony, }, ); + command_options.insert( + String::from("media"), + CommandOption { + rules: vec![String::from("media log")], + description: String::from("Audio tools."), + function_pointer: CommandHandler::cmd_media, + }, + ); command_options.insert( String::from("quit"), CommandOption { @@ -358,29 +367,32 @@ impl CommandHandler { } /// Entry point for command and arguments - pub fn process_cmd_line(&mut self, command: &str, args: &Vec) { + pub fn process_cmd_line(&mut self, command: &str, args: &Vec) -> bool { // Ignore empty line match command { - "" => {} + "" => false, _ => match self.command_options.get(command) { Some(cmd) => { let rules = cmd.rules.clone(); match (cmd.function_pointer)(self, &args) { - Ok(()) => {} + Ok(()) => true, Err(CommandError::InvalidArgs) => { print_error!("Invalid arguments. Usage:\n{}", rules.join("\n")); + false } Err(CommandError::Failed(msg)) => { print_error!("Command failed: {}", msg); + false } } } None => { println!("'{}' is an invalid command!", command); self.cmd_help(&args).ok(); + false } }, - }; + } } fn lock_context(&self) -> std::sync::MutexGuard { @@ -481,15 +493,11 @@ impl CommandHandler { }; let context = self.lock_context(); let adapter_dbus = context.adapter_dbus.as_ref().unwrap(); - let qa_legacy_dbus = context.qa_legacy_dbus.as_ref().unwrap(); let qa_dbus = context.qa_dbus.as_ref().unwrap(); let name = adapter_dbus.get_name(); + let modalias = qa_dbus.get_modalias(); let uuids = adapter_dbus.get_uuids(); let is_discoverable = adapter_dbus.get_discoverable(); - let is_connectable = qa_legacy_dbus.get_connectable(); - let alias = qa_legacy_dbus.get_alias(); - let modalias = qa_legacy_dbus.get_modalias(); - let discoverable_mode = qa_dbus.get_discoverable_mode(); let discoverable_timeout = adapter_dbus.get_discoverable_timeout(); let cod = adapter_dbus.get_bluetooth_class(); let multi_adv_supported = adapter_dbus.is_multi_advertisement_supported(); @@ -507,15 +515,15 @@ impl CommandHandler { }) .filter(|(_prof, state)| state != &ProfileConnectionState::Disconnected) .collect(); + qa_dbus.fetch_connectable(); + qa_dbus.fetch_alias(); + qa_dbus.fetch_discoverable_mode(); print_info!("Address: {}", address); print_info!("Name: {}", name); - print_info!("Alias: {}", alias); print_info!("Modalias: {}", modalias); print_info!("State: {}", if enabled { "enabled" } else { "disabled" }); print_info!("Discoverable: {}", is_discoverable); - print_info!("Discoverable mode: {:?}", discoverable_mode); print_info!("DiscoverableTimeout: {}s", discoverable_timeout); - print_info!("Connectable: {}", is_connectable); print_info!("Class: {:#06x}", cod); print_info!("IsMultiAdvertisementSupported: {}", multi_adv_supported); print_info!("IsLeExtendedAdvertisingSupported: {}", le_ext_adv_supported); @@ -582,14 +590,10 @@ impl CommandHandler { }, "connectable" => match &get_arg(args, 1)?[..] { "on" => { - let ret = - self.lock_context().qa_legacy_dbus.as_mut().unwrap().set_connectable(true); - print_info!("Set connectable on {}", if ret { "succeeded" } else { "failed" }); + self.lock_context().qa_dbus.as_mut().unwrap().set_connectable(true); } "off" => { - let ret = - self.lock_context().qa_legacy_dbus.as_mut().unwrap().set_connectable(false); - print_info!("Set connectable off {}", if ret { "succeeded" } else { "failed" }); + self.lock_context().qa_dbus.as_mut().unwrap().set_connectable(false); } other => println!("Invalid argument for adapter connectable '{}'", other), }, @@ -678,7 +682,7 @@ impl CommandHandler { name: String::from("Classic Device"), }; - self.lock_context().adapter_dbus.as_ref().unwrap().remove_bond(device); + self.lock_context().adapter_dbus.as_mut().unwrap().remove_bond(device); } "cancel" => { let device = BluetoothDevice { @@ -686,7 +690,7 @@ impl CommandHandler { name: String::from("Classic Device"), }; - self.lock_context().adapter_dbus.as_ref().unwrap().cancel_bond_process(device); + self.lock_context().adapter_dbus.as_mut().unwrap().cancel_bond_process(device); } other => { println!("Invalid argument '{}'", other); @@ -752,6 +756,7 @@ impl CommandHandler { name, alias, device_type, + addr_type, class, appearance, bonded, @@ -764,6 +769,7 @@ impl CommandHandler { let name = adapter.get_remote_name(device.clone()); let device_type = adapter.get_remote_type(device.clone()); + let addr_type = adapter.get_remote_address_type(device.clone()); let alias = adapter.get_remote_alias(device.clone()); let class = adapter.get_remote_class(device.clone()); let appearance = adapter.get_remote_appearance(device.clone()); @@ -780,6 +786,7 @@ impl CommandHandler { name, alias, device_type, + addr_type, class, appearance, bonded, @@ -792,7 +799,8 @@ impl CommandHandler { print_info!("Address: {}", &device.address); print_info!("Name: {}", name); print_info!("Alias: {}", alias); - print_info!("Type: {:?}", device_type); + print_info!("Device Type: {:?}", device_type); + print_info!("Address Type: {:?}", addr_type); print_info!("Class: {}", class); print_info!("Appearance: {}", appearance); print_info!("Wake Allowed: {}", wake_allowed); @@ -889,6 +897,27 @@ impl CommandHandler { passkey, ); } + "get-rssi" => { + let device = BluetoothDevice { + address: String::from(get_arg(args, 1)?), + name: String::from(""), + }; + + match self + .lock_context() + .adapter_dbus + .as_mut() + .unwrap() + .get_remote_rssi(device.clone()) + { + INVALID_RSSI => { + println!("Invalid RSSI"); + } + rssi => { + println!("RSSI: {}", rssi); + } + }; + } other => { println!("Invalid argument '{}'", other); } @@ -908,6 +937,8 @@ impl CommandHandler { self.lock_context().manager_dbus.set_floss_enabled(false); } "show" => { + let (major, minor) = self.lock_context().get_floss_api_version(); + print_info!("Floss API version: {}.{}", major, minor); print_info!( "Floss enabled: {}", self.lock_context().manager_dbus.get_floss_enabled() @@ -1236,7 +1267,7 @@ impl CommandHandler { scanner_id, // TODO(b/254870159): Construct real settings and filters depending on // command line options. - ScanSettings { interval: 0, window: 0, scan_type: ScanType::Active }, + None, Some(btstack::bluetooth_gatt::ScanFilter { rssi_high_threshold: 0, rssi_low_threshold: 0, @@ -1536,7 +1567,7 @@ impl CommandHandler { let (addr, sock_type, psm_or_uuid) = (&get_arg(args, 1)?, &get_arg(args, 2)?, &get_arg(args, 3)?); let device = BluetoothDevice { - address: addr.clone().into(), + address: String::from(*addr), name: String::from("Socket Connect Device"), }; @@ -1558,7 +1589,7 @@ impl CommandHandler { match &sock_type[0..] { "l2cap" => { - let psm = match psm_or_uuid.clone().parse::() { + let psm = match psm_or_uuid.parse::() { Ok(v) => v, Err(e) => { return Err(CommandError::Failed(format!( @@ -1583,7 +1614,7 @@ impl CommandHandler { } } "rfcomm" => { - let uuid = match UuidHelper::parse_string(psm_or_uuid.clone()) { + let uuid = match UuidHelper::parse_string(*psm_or_uuid) { Some(uu) => uu, None => { return Err(CommandError::Failed(format!( @@ -1623,6 +1654,26 @@ impl CommandHandler { status, id, addr, sock_type, psm_or_uuid); } } + "close" => { + let sockid = String::from(get_arg(args, 1)?) + .parse::() + .or(Err("Failed parsing socket ID"))?; + let status = self + .context + .lock() + .unwrap() + .socket_manager_dbus + .as_mut() + .unwrap() + .close(callback_id, sockid); + if status != BtStatus::Success { + return Err(format!( + "Failed to close the listening socket, status = {:?}", + status, + ) + .into()); + } + } _ => return Err(CommandError::InvalidArgs), }; @@ -1652,7 +1703,7 @@ impl CommandHandler { .parse::() .or(Err("Failed parsing report_id"))?; - self.context.lock().unwrap().qa_legacy_dbus.as_mut().unwrap().get_hid_report( + self.context.lock().unwrap().qa_dbus.as_mut().unwrap().get_hid_report( addr, report_type, report_id, @@ -1670,7 +1721,7 @@ impl CommandHandler { }; let report_value = String::from(get_arg(args, 3)?); - self.context.lock().unwrap().qa_legacy_dbus.as_mut().unwrap().set_hid_report( + self.context.lock().unwrap().qa_dbus.as_mut().unwrap().set_hid_report( addr, report_type, report_value, @@ -1680,13 +1731,7 @@ impl CommandHandler { let addr = String::from(get_arg(args, 1)?); let data = String::from(get_arg(args, 2)?); - self.context - .lock() - .unwrap() - .qa_legacy_dbus - .as_mut() - .unwrap() - .send_hid_data(addr, data); + self.context.lock().unwrap().qa_dbus.as_mut().unwrap().send_hid_data(addr, data); } _ => return Err(CommandError::InvalidArgs), }; @@ -1803,7 +1848,7 @@ impl CommandHandler { } "enable" => { let mut context = self.lock_context(); - context.telephony_dbus.as_mut().unwrap().set_phone_ops_enabled(true); + context.telephony_dbus.as_mut().unwrap().set_mps_qualification_enabled(true); if context.mps_sdp_handle.is_none() { let success = context .adapter_dbus @@ -1817,7 +1862,7 @@ impl CommandHandler { } "disable" => { let mut context = self.lock_context(); - context.telephony_dbus.as_mut().unwrap().set_phone_ops_enabled(false); + context.telephony_dbus.as_mut().unwrap().set_mps_qualification_enabled(false); if let Some(handle) = context.mps_sdp_handle.take() { let success = context.adapter_dbus.as_mut().unwrap().remove_sdp_record(handle); if !success { @@ -1979,6 +2024,23 @@ impl CommandHandler { Ok(()) } + + fn cmd_media(&mut self, args: &Vec) -> CommandResult { + if !self.context.lock().unwrap().adapter_ready { + return Err(self.adapter_not_ready()); + } + + match &get_arg(args, 0)?[..] { + "log" => { + self.context.lock().unwrap().media_dbus.as_mut().unwrap().trigger_debug_dump(); + } + other => { + return Err(format!("Invalid argument '{}'", other).into()); + } + } + + Ok(()) + } } #[cfg(test)] diff --git a/system/gd/rust/linux/client/src/dbus_iface.rs b/system/gd/rust/linux/client/src/dbus_iface.rs index 18ae1ad166712d873d5c472e43c3e169f493bb2a..ebee9c011ccd93aef9468110e2bef2e1b0d53e86 100644 --- a/system/gd/rust/linux/client/src/dbus_iface.rs +++ b/system/gd/rust/linux/client/src/dbus_iface.rs @@ -1,10 +1,16 @@ //! D-Bus proxy implementations of the APIs. use bt_topshim::btif::{ - BtBondState, BtConnectionState, BtDeviceType, BtDiscMode, BtPropertyType, BtSspVariant, - BtStatus, BtTransport, Uuid, Uuid128Bit, + BtAddrType, BtBondState, BtConnectionState, BtDeviceType, BtDiscMode, BtPropertyType, + BtSspVariant, BtStatus, BtTransport, BtVendorProductInfo, Uuid, Uuid128Bit, }; +use bt_topshim::profiles::a2dp::{ + A2dpCodecBitsPerSample, A2dpCodecChannelMode, A2dpCodecConfig, A2dpCodecIndex, + A2dpCodecSampleRate, PresentationPosition, +}; +use bt_topshim::profiles::avrcp::PlayerMetadata; use bt_topshim::profiles::gatt::{AdvertisingStatus, GattStatus, LePhy}; +use bt_topshim::profiles::hfp::HfpCodecCapability; use bt_topshim::profiles::hid_host::BthhReportType; use bt_topshim::profiles::sdp::{ BtSdpDipRecord, BtSdpHeaderOverlay, BtSdpMasRecord, BtSdpMnsRecord, BtSdpMpsRecord, @@ -29,7 +35,10 @@ use btstack::bluetooth_gatt::{ IBluetoothGattServerCallback, IScannerCallback, ScanFilter, ScanFilterCondition, ScanFilterPattern, ScanResult, ScanSettings, ScanType, }; -use btstack::bluetooth_media::IBluetoothTelephony; +use btstack::bluetooth_media::{ + BluetoothAudioDevice, IBluetoothMedia, IBluetoothMediaCallback, IBluetoothTelephony, + IBluetoothTelephonyCallback, +}; use btstack::bluetooth_qa::IBluetoothQA; use btstack::socket_manager::{ BluetoothServerSocket, BluetoothSocket, CallbackId, IBluetoothSocketManager, @@ -42,9 +51,7 @@ use btstack::suspend::{ISuspend, ISuspendCallback, SuspendType}; use dbus::arg::RefArg; use dbus::nonblock::SyncConnection; -use dbus_projection::{ - dbus_generated, impl_dbus_arg_enum, impl_dbus_arg_from_into, ClientDBusProxy, DisconnectWatcher, -}; +use dbus_projection::prelude::*; use dbus_macros::{ dbus_method, dbus_propmap, generate_dbus_exporter, generate_dbus_interface_client, @@ -60,6 +67,8 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::sync::Arc; +use btstack::bluetooth_qa::IBluetoothQACallback; + use crate::dbus_arg::{DBusArg, DBusArgError, DirectDBus, RefArgToRust}; fn make_object_path(idx: i32, name: &str) -> dbus::Path { @@ -70,6 +79,7 @@ impl_dbus_arg_enum!(AdvertisingStatus); impl_dbus_arg_enum!(BtBondState); impl_dbus_arg_enum!(BtConnectionState); impl_dbus_arg_enum!(BtDeviceType); +impl_dbus_arg_enum!(BtAddrType); impl_dbus_arg_enum!(BtPropertyType); impl_dbus_arg_enum!(BtSspVariant); impl_dbus_arg_enum!(BtStatus); @@ -113,6 +123,11 @@ impl DBusArg for Uuid128Bit { fn to_dbus(data: [u8; 16]) -> Result, Box> { return Ok(data.to_vec()); } + + // We don't log in btclient. + fn log(_data: &[u8; 16]) -> String { + String::new() + } } impl_dbus_arg_enum!(BtSdpType); @@ -195,6 +210,14 @@ pub struct BtSdpMpsRecordDBus { supported_dependencies: SupportedDependencies, } +#[dbus_propmap(BtVendorProductInfo)] +pub struct BtVendorProductInfoDBus { + vendor_id_src: u8, + vendor_id: u16, + product_id: u16, + version: u16, +} + fn read_propmap_value( propmap: &dbus::arg::PropMap, key: &str, @@ -338,6 +361,11 @@ impl DBusArg for BtSdpRecord { } Ok(map) } + + // We don't log in btclient. + fn log(_data: &BtSdpRecord) -> String { + String::new() + } } #[dbus_propmap(BluetoothGattDescriptor)] @@ -387,6 +415,34 @@ struct ScanFilterPatternDBus { content: Vec, } +#[dbus_propmap(A2dpCodecConfig)] +pub struct A2dpCodecConfigDBus { + codec_type: i32, + codec_priority: i32, + sample_rate: i32, + bits_per_sample: i32, + channel_mode: i32, + codec_specific_1: i64, + codec_specific_2: i64, + codec_specific_3: i64, + codec_specific_4: i64, +} + +impl_dbus_arg_enum!(A2dpCodecIndex); +impl_dbus_arg_from_into!(A2dpCodecSampleRate, i32); +impl_dbus_arg_from_into!(A2dpCodecBitsPerSample, i32); +impl_dbus_arg_from_into!(A2dpCodecChannelMode, i32); + +impl_dbus_arg_from_into!(HfpCodecCapability, i32); +#[dbus_propmap(BluetoothAudioDevice)] +pub struct BluetoothAudioDeviceDBus { + address: String, + name: String, + a2dp_caps: Vec, + hfp_cap: HfpCodecCapability, + absolute_volume: bool, +} + // Manually converts enum variant from/into D-Bus. // // The ScanFilterCondition enum variant is represented as a D-Bus dictionary with one and only one @@ -462,6 +518,11 @@ impl DBusArg for ScanFilterCondition { } return Ok(map); } + + // We don't log in btclient. + fn log(_data: &ScanFilterCondition) -> String { + String::new() + } } #[dbus_propmap(ScanFilter)] @@ -492,6 +553,22 @@ struct ScanResultDBus { adv_data: Vec, } +#[dbus_propmap(PresentationPosition)] +struct PresentationPositionDBus { + remote_delay_report_ns: u64, + total_bytes_read: u64, + data_position_sec: i64, + data_position_nsec: i32, +} + +#[dbus_propmap(PlayerMetadata)] +struct PlayerMetadataDBus { + title: String, + artist: String, + album: String, + length_us: i64, +} + struct IBluetoothCallbackDBus {} impl RPCProxy for IBluetoothCallbackDBus {} @@ -501,28 +578,36 @@ impl RPCProxy for IBluetoothCallbackDBus {} "org.chromium.bluetooth.BluetoothCallback" )] impl IBluetoothCallback for IBluetoothCallbackDBus { - #[dbus_method("OnAdapterPropertyChanged")] + #[dbus_method("OnAdapterPropertyChanged", DBusLog::Disable)] fn on_adapter_property_changed(&mut self, prop: BtPropertyType) {} - #[dbus_method("OnAddressChanged")] + #[dbus_method("OnDevicePropertiesChanged", DBusLog::Disable)] + fn on_device_properties_changed( + &mut self, + remote_device: BluetoothDevice, + props: Vec, + ) { + } + + #[dbus_method("OnAddressChanged", DBusLog::Disable)] fn on_address_changed(&mut self, addr: String) {} - #[dbus_method("OnNameChanged")] + #[dbus_method("OnNameChanged", DBusLog::Disable)] fn on_name_changed(&mut self, name: String) {} - #[dbus_method("OnDiscoverableChanged")] + #[dbus_method("OnDiscoverableChanged", DBusLog::Disable)] fn on_discoverable_changed(&mut self, discoverable: bool) {} - #[dbus_method("OnDeviceFound")] + #[dbus_method("OnDeviceFound", DBusLog::Disable)] fn on_device_found(&mut self, remote_device: BluetoothDevice) {} - #[dbus_method("OnDeviceCleared")] + #[dbus_method("OnDeviceCleared", DBusLog::Disable)] fn on_device_cleared(&mut self, remote_device: BluetoothDevice) {} - #[dbus_method("OnDiscoveringChanged")] + #[dbus_method("OnDiscoveringChanged", DBusLog::Disable)] fn on_discovering_changed(&mut self, discovering: bool) {} - #[dbus_method("OnSspRequest")] + #[dbus_method("OnSspRequest", DBusLog::Disable)] fn on_ssp_request( &mut self, remote_device: BluetoothDevice, @@ -532,16 +617,16 @@ impl IBluetoothCallback for IBluetoothCallbackDBus { ) { } - #[dbus_method("OnPinRequest")] + #[dbus_method("OnPinRequest", DBusLog::Disable)] fn on_pin_request(&mut self, remote_device: BluetoothDevice, cod: u32, min_16_digit: bool) {} - #[dbus_method("OnPinDisplay")] + #[dbus_method("OnPinDisplay", DBusLog::Disable)] fn on_pin_display(&mut self, remote_device: BluetoothDevice, pincode: String) {} - #[dbus_method("OnBondStateChanged")] + #[dbus_method("OnBondStateChanged", DBusLog::Disable)] fn on_bond_state_changed(&mut self, status: u32, address: String, state: u32) {} - #[dbus_method("OnSdpSearchComplete")] + #[dbus_method("OnSdpSearchComplete", DBusLog::Disable)] fn on_sdp_search_complete( &mut self, remote_device: BluetoothDevice, @@ -550,7 +635,7 @@ impl IBluetoothCallback for IBluetoothCallbackDBus { ) { } - #[dbus_method("OnSdpRecordCreated")] + #[dbus_method("OnSdpRecordCreated", DBusLog::Disable)] fn on_sdp_record_created(&mut self, record: BtSdpRecord, handle: i32) {} } @@ -563,10 +648,10 @@ impl RPCProxy for IBluetoothConnectionCallbackDBus {} "org.chromium.bluetooth.BluetoothConnectionCallback" )] impl IBluetoothConnectionCallback for IBluetoothConnectionCallbackDBus { - #[dbus_method("OnDeviceConnected")] + #[dbus_method("OnDeviceConnected", DBusLog::Disable)] fn on_device_connected(&mut self, remote_device: BluetoothDevice) {} - #[dbus_method("OnDeviceDisconnected")] + #[dbus_method("OnDeviceDisconnected", DBusLog::Disable)] fn on_device_disconnected(&mut self, remote_device: BluetoothDevice) {} } @@ -579,27 +664,27 @@ impl RPCProxy for IScannerCallbackDBus {} "org.chromium.bluetooth.ScannerCallback" )] impl IScannerCallback for IScannerCallbackDBus { - #[dbus_method("OnScannerRegistered")] + #[dbus_method("OnScannerRegistered", DBusLog::Disable)] fn on_scanner_registered(&mut self, uuid: Uuid128Bit, scanner_id: u8, status: GattStatus) { dbus_generated!() } - #[dbus_method("OnScanResult")] + #[dbus_method("OnScanResult", DBusLog::Disable)] fn on_scan_result(&mut self, scan_result: ScanResult) { dbus_generated!() } - #[dbus_method("OnAdvertisementFound")] + #[dbus_method("OnAdvertisementFound", DBusLog::Disable)] fn on_advertisement_found(&mut self, scanner_id: u8, scan_result: ScanResult) { dbus_generated!() } - #[dbus_method("OnAdvertisementLost")] + #[dbus_method("OnAdvertisementLost", DBusLog::Disable)] fn on_advertisement_lost(&mut self, scanner_id: u8, scan_result: ScanResult) { dbus_generated!() } - #[dbus_method("OnSuspendModeChange")] + #[dbus_method("OnSuspendModeChange", DBusLog::Disable)] fn on_suspend_mode_change(&mut self, suspend_mode: SuspendMode) { dbus_generated!() } @@ -639,7 +724,12 @@ impl BluetoothDBus { #[generate_dbus_interface_client(BluetoothDBusRPC)] impl IBluetooth for BluetoothDBus { #[dbus_method("RegisterCallback")] - fn register_callback(&mut self, callback: Box) { + fn register_callback(&mut self, callback: Box) -> u32 { + dbus_generated!() + } + + #[dbus_method("UnregisterCallback")] + fn unregister_callback(&mut self, id: u32) -> bool { dbus_generated!() } @@ -656,6 +746,11 @@ impl IBluetooth for BluetoothDBus { dbus_generated!() } + fn init(&mut self, _init_flags: Vec) -> bool { + // Not implemented by server + true + } + fn enable(&mut self) -> bool { // Not implemented by server true @@ -666,6 +761,10 @@ impl IBluetooth for BluetoothDBus { true } + fn cleanup(&mut self) { + // Not implemented by server + } + #[dbus_method("GetAddress")] fn get_address(&self) -> String { dbus_generated!() @@ -747,12 +846,12 @@ impl IBluetooth for BluetoothDBus { } #[dbus_method("CancelBondProcess")] - fn cancel_bond_process(&self, device: BluetoothDevice) -> bool { + fn cancel_bond_process(&mut self, device: BluetoothDevice) -> bool { dbus_generated!() } #[dbus_method("RemoveBond")] - fn remove_bond(&self, device: BluetoothDevice) -> bool { + fn remove_bond(&mut self, device: BluetoothDevice) -> bool { dbus_generated!() } @@ -821,6 +920,21 @@ impl IBluetooth for BluetoothDBus { dbus_generated!() } + #[dbus_method("GetRemoteVendorProductInfo")] + fn get_remote_vendor_product_info(&self, _device: BluetoothDevice) -> BtVendorProductInfo { + dbus_generated!() + } + + #[dbus_method("GetRemoteAddressType")] + fn get_remote_address_type(&self, device: BluetoothDevice) -> BtAddrType { + dbus_generated!() + } + + #[dbus_method("GetRemoteRSSI")] + fn get_remote_rssi(&self, device: BluetoothDevice) -> i8 { + dbus_generated!() + } + #[dbus_method("GetConnectedDevices")] fn get_connected_devices(&self) -> Vec { dbus_generated!() @@ -1031,6 +1145,16 @@ impl IBluetoothManager for BluetoothManagerDBus { fn set_desired_default_adapter(&mut self, adapter: i32) { dbus_generated!() } + + #[dbus_method("GetFlossApiVersion")] + fn get_floss_api_version(&mut self) -> u32 { + dbus_generated!() + } + + #[dbus_method("SetTabletMode")] + fn set_tablet_mode(&mut self, tablet_mode: bool) { + dbus_generated!() + } } struct IBluetoothManagerCallbackDBus {} @@ -1042,13 +1166,13 @@ impl RPCProxy for IBluetoothManagerCallbackDBus {} "org.chromium.bluetooth.ManagerCallback" )] impl IBluetoothManagerCallback for IBluetoothManagerCallbackDBus { - #[dbus_method("OnHciDeviceChanged")] + #[dbus_method("OnHciDeviceChanged", DBusLog::Disable)] fn on_hci_device_changed(&mut self, hci_interface: i32, present: bool) {} - #[dbus_method("OnHciEnabledChanged")] + #[dbus_method("OnHciEnabledChanged", DBusLog::Disable)] fn on_hci_enabled_changed(&mut self, hci_interface: i32, enabled: bool) {} - #[dbus_method("OnDefaultAdapterChanged")] + #[dbus_method("OnDefaultAdapterChanged", DBusLog::Disable)] fn on_default_adapter_changed(&mut self, hci_interface: i32) {} } @@ -1062,7 +1186,7 @@ impl RPCProxy for IAdvertisingSetCallbackDBus {} "org.chromium.bluetooth.AdvertisingSetCallback" )] impl IAdvertisingSetCallback for IAdvertisingSetCallbackDBus { - #[dbus_method("OnAdvertisingSetStarted")] + #[dbus_method("OnAdvertisingSetStarted", DBusLog::Disable)] fn on_advertising_set_started( &mut self, reg_id: i32, @@ -1072,13 +1196,13 @@ impl IAdvertisingSetCallback for IAdvertisingSetCallbackDBus { ) { } - #[dbus_method("OnOwnAddressRead")] + #[dbus_method("OnOwnAddressRead", DBusLog::Disable)] fn on_own_address_read(&mut self, advertiser_id: i32, address_type: i32, address: String) {} - #[dbus_method("OnAdvertisingSetStopped")] + #[dbus_method("OnAdvertisingSetStopped", DBusLog::Disable)] fn on_advertising_set_stopped(&mut self, advertiser_id: i32) {} - #[dbus_method("OnAdvertisingEnabled")] + #[dbus_method("OnAdvertisingEnabled", DBusLog::Disable)] fn on_advertising_enabled( &mut self, advertiser_id: i32, @@ -1087,13 +1211,13 @@ impl IAdvertisingSetCallback for IAdvertisingSetCallbackDBus { ) { } - #[dbus_method("OnAdvertisingDataSet")] + #[dbus_method("OnAdvertisingDataSet", DBusLog::Disable)] fn on_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus) {} - #[dbus_method("OnScanResponseDataSet")] + #[dbus_method("OnScanResponseDataSet", DBusLog::Disable)] fn on_scan_response_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus) {} - #[dbus_method("OnAdvertisingParametersUpdated")] + #[dbus_method("OnAdvertisingParametersUpdated", DBusLog::Disable)] fn on_advertising_parameters_updated( &mut self, advertiser_id: i32, @@ -1102,7 +1226,7 @@ impl IAdvertisingSetCallback for IAdvertisingSetCallbackDBus { ) { } - #[dbus_method("OnPeriodicAdvertisingParametersUpdated")] + #[dbus_method("OnPeriodicAdvertisingParametersUpdated", DBusLog::Disable)] fn on_periodic_advertising_parameters_updated( &mut self, advertiser_id: i32, @@ -1110,10 +1234,10 @@ impl IAdvertisingSetCallback for IAdvertisingSetCallbackDBus { ) { } - #[dbus_method("OnPeriodicAdvertisingDataSet")] + #[dbus_method("OnPeriodicAdvertisingDataSet", DBusLog::Disable)] fn on_periodic_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus) {} - #[dbus_method("OnPeriodicAdvertisingEnabled")] + #[dbus_method("OnPeriodicAdvertisingEnabled", DBusLog::Disable)] fn on_periodic_advertising_enabled( &mut self, advertiser_id: i32, @@ -1122,7 +1246,7 @@ impl IAdvertisingSetCallback for IAdvertisingSetCallbackDBus { ) { } - #[dbus_method("OnSuspendModeChange")] + #[dbus_method("OnSuspendModeChange", DBusLog::Disable)] fn on_suspend_mode_change(&mut self, suspend_mode: SuspendMode) {} } @@ -1237,12 +1361,12 @@ impl RPCProxy for IBluetoothAdminPolicyCallbackDBus {} "org.chromium.bluetooth.AdminPolicyCallback" )] impl IBluetoothAdminPolicyCallback for IBluetoothAdminPolicyCallbackDBus { - #[dbus_method("OnServiceAllowlistChanged")] + #[dbus_method("OnServiceAllowlistChanged", DBusLog::Disable)] fn on_service_allowlist_changed(&mut self, allowed_list: Vec) { dbus_generated!() } - #[dbus_method("OnDevicePolicyEffectChanged")] + #[dbus_method("OnDevicePolicyEffectChanged", DBusLog::Disable)] fn on_device_policy_effect_changed( &mut self, device: BluetoothDevice, @@ -1314,7 +1438,7 @@ impl IBluetoothGatt for BluetoothGattDBus { fn start_scan( &mut self, _scanner_id: u8, - _settings: ScanSettings, + _settings: Option, _filter: Option, ) -> BtStatus { dbus_generated!() @@ -1340,7 +1464,7 @@ impl IBluetoothGatt for BluetoothGattDBus { } #[dbus_method("UnregisterAdvertiserCallback")] - fn unregister_advertiser_callback(&mut self, callback_id: u32) { + fn unregister_advertiser_callback(&mut self, callback_id: u32) -> bool { dbus_generated!() } @@ -1689,10 +1813,10 @@ impl RPCProxy for IBluetoothGattCallbackDBus {} "org.chromium.bluetooth.BluetoothGattCallback" )] impl IBluetoothGattCallback for IBluetoothGattCallbackDBus { - #[dbus_method("OnClientRegistered")] + #[dbus_method("OnClientRegistered", DBusLog::Disable)] fn on_client_registered(&mut self, status: GattStatus, client_id: i32) {} - #[dbus_method("OnClientConnectionState")] + #[dbus_method("OnClientConnectionState", DBusLog::Disable)] fn on_client_connection_state( &mut self, status: GattStatus, @@ -1702,13 +1826,13 @@ impl IBluetoothGattCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnPhyUpdate")] + #[dbus_method("OnPhyUpdate", DBusLog::Disable)] fn on_phy_update(&mut self, addr: String, tx_phy: LePhy, rx_phy: LePhy, status: GattStatus) {} - #[dbus_method("OnPhyRead")] + #[dbus_method("OnPhyRead", DBusLog::Disable)] fn on_phy_read(&mut self, addr: String, tx_phy: LePhy, rx_phy: LePhy, status: GattStatus) {} - #[dbus_method("OnSearchComplete")] + #[dbus_method("OnSearchComplete", DBusLog::Disable)] fn on_search_complete( &mut self, addr: String, @@ -1717,7 +1841,7 @@ impl IBluetoothGattCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnCharacteristicRead")] + #[dbus_method("OnCharacteristicRead", DBusLog::Disable)] fn on_characteristic_read( &mut self, addr: String, @@ -1727,13 +1851,13 @@ impl IBluetoothGattCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnCharacteristicWrite")] + #[dbus_method("OnCharacteristicWrite", DBusLog::Disable)] fn on_characteristic_write(&mut self, addr: String, status: GattStatus, handle: i32) {} - #[dbus_method("OnExecuteWrite")] + #[dbus_method("OnExecuteWrite", DBusLog::Disable)] fn on_execute_write(&mut self, addr: String, status: GattStatus) {} - #[dbus_method("OnDescriptorRead")] + #[dbus_method("OnDescriptorRead", DBusLog::Disable)] fn on_descriptor_read( &mut self, addr: String, @@ -1743,19 +1867,19 @@ impl IBluetoothGattCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnDescriptorWrite")] + #[dbus_method("OnDescriptorWrite", DBusLog::Disable)] fn on_descriptor_write(&mut self, addr: String, status: GattStatus, handle: i32) {} - #[dbus_method("OnNotify")] + #[dbus_method("OnNotify", DBusLog::Disable)] fn on_notify(&mut self, addr: String, handle: i32, value: Vec) {} - #[dbus_method("OnReadRemoteRssi")] + #[dbus_method("OnReadRemoteRssi", DBusLog::Disable)] fn on_read_remote_rssi(&mut self, addr: String, rssi: i32, status: GattStatus) {} - #[dbus_method("OnConfigureMtu")] + #[dbus_method("OnConfigureMtu", DBusLog::Disable)] fn on_configure_mtu(&mut self, addr: String, mtu: i32, status: GattStatus) {} - #[dbus_method("OnConnectionUpdated")] + #[dbus_method("OnConnectionUpdated", DBusLog::Disable)] fn on_connection_updated( &mut self, addr: String, @@ -1766,7 +1890,7 @@ impl IBluetoothGattCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnServiceChanged")] + #[dbus_method("OnServiceChanged", DBusLog::Disable)] fn on_service_changed(&mut self, addr: String) {} } @@ -1775,19 +1899,19 @@ impl IBluetoothGattCallback for IBluetoothGattCallbackDBus { "org.chromium.bluetooth.BluetoothGattServerCallback" )] impl IBluetoothGattServerCallback for IBluetoothGattCallbackDBus { - #[dbus_method("OnServerRegistered")] + #[dbus_method("OnServerRegistered", DBusLog::Disable)] fn on_server_registered(&mut self, status: GattStatus, client_id: i32) {} - #[dbus_method("OnServerConnectionState")] + #[dbus_method("OnServerConnectionState", DBusLog::Disable)] fn on_server_connection_state(&mut self, server_id: i32, connected: bool, addr: String) {} - #[dbus_method("OnServiceAdded")] + #[dbus_method("OnServiceAdded", DBusLog::Disable)] fn on_service_added(&mut self, status: GattStatus, service: BluetoothGattService) {} - #[dbus_method("OnServiceRemoved")] + #[dbus_method("OnServiceRemoved", DBusLog::Disable)] fn on_service_removed(&mut self, status: GattStatus, handle: i32) {} - #[dbus_method("OnCharacteristicReadRequest")] + #[dbus_method("OnCharacteristicReadRequest", DBusLog::Disable)] fn on_characteristic_read_request( &mut self, addr: String, @@ -1798,7 +1922,7 @@ impl IBluetoothGattServerCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnDescriptorReadRequest")] + #[dbus_method("OnDescriptorReadRequest", DBusLog::Disable)] fn on_descriptor_read_request( &mut self, addr: String, @@ -1809,7 +1933,7 @@ impl IBluetoothGattServerCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnCharacteristicWriteRequest")] + #[dbus_method("OnCharacteristicWriteRequest", DBusLog::Disable)] fn on_characteristic_write_request( &mut self, addr: String, @@ -1823,7 +1947,7 @@ impl IBluetoothGattServerCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnDescriptorWriteRequest")] + #[dbus_method("OnDescriptorWriteRequest", DBusLog::Disable)] fn on_descriptor_write_request( &mut self, addr: String, @@ -1837,22 +1961,22 @@ impl IBluetoothGattServerCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnExecuteWrite")] + #[dbus_method("OnExecuteWrite", DBusLog::Disable)] fn on_execute_write(&mut self, addr: String, trans_id: i32, exec_write: bool) {} - #[dbus_method("OnNotificationSent")] + #[dbus_method("OnNotificationSent", DBusLog::Disable)] fn on_notification_sent(&mut self, addr: String, status: GattStatus) {} - #[dbus_method("OnMtuChanged")] + #[dbus_method("OnMtuChanged", DBusLog::Disable)] fn on_mtu_changed(&mut self, addr: String, mtu: i32) {} - #[dbus_method("OnPhyUpdate")] + #[dbus_method("OnPhyUpdate", DBusLog::Disable)] fn on_phy_update(&mut self, addr: String, tx_phy: LePhy, rx_phy: LePhy, status: GattStatus) {} - #[dbus_method("OnPhyRead")] + #[dbus_method("OnPhyRead", DBusLog::Disable)] fn on_phy_read(&mut self, addr: String, tx_phy: LePhy, rx_phy: LePhy, status: GattStatus) {} - #[dbus_method("OnConnectionUpdated")] + #[dbus_method("OnConnectionUpdated", DBusLog::Disable)] fn on_connection_updated( &mut self, addr: String, @@ -1863,7 +1987,7 @@ impl IBluetoothGattServerCallback for IBluetoothGattCallbackDBus { ) { } - #[dbus_method("OnSubrateChange")] + #[dbus_method("OnSubrateChange", DBusLog::Disable)] fn on_subrate_change( &mut self, addr: String, @@ -1945,6 +2069,11 @@ impl IBluetoothSocketManager for BluetoothSocketManagerDBus { dbus_generated!() } + #[dbus_method("UnregisterCallback")] + fn unregister_callback(&mut self, callback: CallbackId) -> bool { + dbus_generated!() + } + #[dbus_method("ListenUsingInsecureL2capChannel")] fn listen_using_insecure_l2cap_channel(&mut self, callback: CallbackId) -> SocketResult { dbus_generated!() @@ -2077,17 +2206,17 @@ impl RPCProxy for IBluetoothSocketManagerCallbacksDBus {} "org.chromium.bluetooth.SocketManagerCallback" )] impl IBluetoothSocketManagerCallbacks for IBluetoothSocketManagerCallbacksDBus { - #[dbus_method("OnIncomingSocketReady")] + #[dbus_method("OnIncomingSocketReady", DBusLog::Disable)] fn on_incoming_socket_ready(&mut self, socket: BluetoothServerSocket, status: BtStatus) { dbus_generated!() } - #[dbus_method("OnIncomingSocketClosed")] + #[dbus_method("OnIncomingSocketClosed", DBusLog::Disable)] fn on_incoming_socket_closed(&mut self, listener_id: SocketId, reason: BtStatus) { dbus_generated!() } - #[dbus_method("OnHandleIncomingConnection")] + #[dbus_method("OnHandleIncomingConnection", DBusLog::Disable)] fn on_handle_incoming_connection( &mut self, listener_id: SocketId, @@ -2096,7 +2225,7 @@ impl IBluetoothSocketManagerCallbacks for IBluetoothSocketManagerCallbacksDBus { dbus_generated!() } - #[dbus_method("OnOutgoingConnectionResult")] + #[dbus_method("OnOutgoingConnectionResult", DBusLog::Disable)] fn on_outgoing_connection_result( &mut self, connecting_id: SocketId, @@ -2156,33 +2285,53 @@ impl RPCProxy for ISuspendCallbackDBus {} "org.chromium.bluetooth.SuspendCallback" )] impl ISuspendCallback for ISuspendCallbackDBus { - #[dbus_method("OnCallbackRegistered")] + #[dbus_method("OnCallbackRegistered", DBusLog::Disable)] fn on_callback_registered(&mut self, callback_id: u32) {} - #[dbus_method("OnSuspendReady")] + #[dbus_method("OnSuspendReady", DBusLog::Disable)] fn on_suspend_ready(&mut self, suspend_id: i32) {} - #[dbus_method("OnResumed")] + #[dbus_method("OnResumed", DBusLog::Disable)] fn on_resumed(&mut self, suspend_id: i32) {} } +pub(crate) struct BluetoothTelephonyDBusRPC { + client_proxy: ClientDBusProxy, +} + pub(crate) struct BluetoothTelephonyDBus { client_proxy: ClientDBusProxy, + pub rpc: BluetoothTelephonyDBusRPC, } impl BluetoothTelephonyDBus { + fn make_client_proxy(conn: Arc, index: i32) -> ClientDBusProxy { + ClientDBusProxy::new( + conn.clone(), + String::from("org.chromium.bluetooth"), + make_object_path(index, "telephony"), + String::from("org.chromium.bluetooth.BluetoothTelephony"), + ) + } + pub(crate) fn new(conn: Arc, index: i32) -> BluetoothTelephonyDBus { BluetoothTelephonyDBus { - client_proxy: ClientDBusProxy::new( - conn.clone(), - String::from("org.chromium.bluetooth"), - make_object_path(index, "telephony"), - String::from("org.chromium.bluetooth.BluetoothTelephony"), - ), + client_proxy: Self::make_client_proxy(conn.clone(), index), + rpc: BluetoothTelephonyDBusRPC { + client_proxy: Self::make_client_proxy(conn.clone(), index), + }, } } } -#[generate_dbus_interface_client] +#[generate_dbus_interface_client(BluetoothTelephonyDBusRPC)] impl IBluetoothTelephony for BluetoothTelephonyDBus { + #[dbus_method("RegisterTelephonyCallback")] + fn register_telephony_callback( + &mut self, + callback: Box, + ) -> bool { + dbus_generated!() + } + #[dbus_method("SetNetworkAvailable")] fn set_network_available(&mut self, network_available: bool) { dbus_generated!() @@ -2203,6 +2352,10 @@ impl IBluetoothTelephony for BluetoothTelephonyDBus { fn set_phone_ops_enabled(&mut self, enable: bool) { dbus_generated!() } + #[dbus_method("SetMpsQualificationEnabled")] + fn set_mps_qualification_enabled(&mut self, enable: bool) { + dbus_generated!() + } #[dbus_method("IncomingCall")] fn incoming_call(&mut self, number: String) -> bool { dbus_generated!() @@ -2249,25 +2402,58 @@ impl IBluetoothTelephony for BluetoothTelephonyDBus { } } +struct IBluetoothTelephonyCallbackDBus {} + +impl RPCProxy for IBluetoothTelephonyCallbackDBus {} + +#[generate_dbus_exporter( + export_bluetooth_telephony_callback_dbus_intf, + "org.chromium.bluetooth.BluetoothTelephonyCallback" +)] +impl IBluetoothTelephonyCallback for IBluetoothTelephonyCallbackDBus { + #[dbus_method("OnTelephonyUse")] + fn on_telephony_use(&mut self, addr: String, state: bool) { + dbus_generated!() + } +} + +pub(crate) struct BluetoothQADBusRPC { + client_proxy: ClientDBusProxy, +} + pub(crate) struct BluetoothQADBus { client_proxy: ClientDBusProxy, + pub rpc: BluetoothQADBusRPC, } impl BluetoothQADBus { + fn make_client_proxy(conn: Arc, index: i32) -> ClientDBusProxy { + ClientDBusProxy::new( + conn.clone(), + String::from("org.chromium.bluetooth"), + make_object_path(index, "qa"), + String::from("org.chromium.bluetooth.BluetoothQA"), + ) + } + pub(crate) fn new(conn: Arc, index: i32) -> BluetoothQADBus { BluetoothQADBus { - client_proxy: ClientDBusProxy::new( - conn.clone(), - String::from("org.chromium.bluetooth"), - make_object_path(index, "qa"), - String::from("org.chromium.bluetooth.BluetoothQA"), - ), + client_proxy: Self::make_client_proxy(conn.clone(), index), + rpc: BluetoothQADBusRPC { client_proxy: Self::make_client_proxy(conn.clone(), index) }, } } } -#[generate_dbus_interface_client] +#[generate_dbus_interface_client(BluetoothQADBusRPC)] impl IBluetoothQA for BluetoothQADBus { + #[dbus_method("RegisterQACallback")] + fn register_qa_callback(&mut self, callback: Box) -> u32 { + dbus_generated!() + } + #[dbus_method("UnregisterQACallback")] + fn unregister_qa_callback(&mut self, callback_id: u32) -> bool { + dbus_generated!() + } #[dbus_method("AddMediaPlayer")] fn add_media_player(&self, name: String, browsing_supported: bool) { dbus_generated!() @@ -2276,8 +2462,275 @@ impl IBluetoothQA for BluetoothQADBus { fn rfcomm_send_msc(&self, dlci: u8, addr: String) { dbus_generated!() } - #[dbus_method("GetDiscoverableMode")] - fn get_discoverable_mode(&self) -> BtDiscMode { + #[dbus_method("FetchDiscoverableMode")] + fn fetch_discoverable_mode(&self) { + dbus_generated!() + } + #[dbus_method("FetchConnectable")] + fn fetch_connectable(&self) { dbus_generated!() } + #[dbus_method("SetConnectable")] + fn set_connectable(&self, mode: bool) { + dbus_generated!() + } + #[dbus_method("FetchAlias")] + fn fetch_alias(&self) { + dbus_generated!() + } + #[dbus_method("GetModalias")] + fn get_modalias(&self) -> String { + dbus_generated!() + } + #[dbus_method("GetHIDReport")] + fn get_hid_report(&self, addr: String, report_type: BthhReportType, report_id: u8) { + dbus_generated!() + } + #[dbus_method("SetHIDReport")] + fn set_hid_report(&self, addr: String, report_type: BthhReportType, report: String) { + dbus_generated!() + } + #[dbus_method("SendHIDData")] + fn send_hid_data(&self, addr: String, data: String) { + dbus_generated!() + } +} + +struct IBluetoothQACallbackDBus {} + +impl RPCProxy for IBluetoothQACallbackDBus {} + +#[generate_dbus_exporter( + export_qa_callback_dbus_intf, + "org.chromium.bluetooth.QACallback", + DBusLog::Disable +)] +impl IBluetoothQACallback for IBluetoothQACallbackDBus { + #[dbus_method("OnFetchDiscoverableModeComplete", DBusLog::Disable)] + fn on_fetch_discoverable_mode_completed(&mut self, disc_mode: BtDiscMode) { + dbus_generated!() + } + #[dbus_method("OnFetchConnectableComplete", DBusLog::Disable)] + fn on_fetch_connectable_completed(&mut self, connectable: bool) { + dbus_generated!() + } + #[dbus_method("OnSetConnectableComplete", DBusLog::Disable)] + fn on_set_connectable_completed(&mut self, succeed: bool) { + dbus_generated!() + } + #[dbus_method("OnFetchAliasComplete", DBusLog::Disable)] + fn on_fetch_alias_completed(&mut self, alias: String) { + dbus_generated!() + } + #[dbus_method("OnGetHIDReportComplete", DBusLog::Disable)] + fn on_get_hid_report_completed(&mut self, status: BtStatus) { + dbus_generated!() + } + #[dbus_method("OnSetHIDReportComplete", DBusLog::Disable)] + fn on_set_hid_report_completed(&mut self, status: BtStatus) { + dbus_generated!() + } + #[dbus_method("OnSendHIDDataComplete", DBusLog::Disable)] + fn on_send_hid_data_completed(&mut self, status: BtStatus) { + dbus_generated!() + } +} + +pub(crate) struct BluetoothMediaDBusRPC { + client_proxy: ClientDBusProxy, +} + +pub(crate) struct BluetoothMediaDBus { + client_proxy: ClientDBusProxy, + pub rpc: BluetoothMediaDBusRPC, +} + +impl BluetoothMediaDBus { + fn make_client_proxy(conn: Arc, index: i32) -> ClientDBusProxy { + ClientDBusProxy::new( + conn.clone(), + String::from("org.chromium.bluetooth"), + make_object_path(index, "media"), + String::from("org.chromium.bluetooth.BluetoothMedia"), + ) + } + + pub(crate) fn new(conn: Arc, index: i32) -> BluetoothMediaDBus { + BluetoothMediaDBus { + client_proxy: Self::make_client_proxy(conn.clone(), index), + rpc: BluetoothMediaDBusRPC { + client_proxy: Self::make_client_proxy(conn.clone(), index), + }, + } + } +} + +#[generate_dbus_interface_client(BluetoothMediaDBusRPC)] +impl IBluetoothMedia for BluetoothMediaDBus { + #[dbus_method("RegisterCallback")] + fn register_callback(&mut self, callback: Box) -> bool { + dbus_generated!() + } + + #[dbus_method("Initialize")] + fn initialize(&mut self) -> bool { + dbus_generated!() + } + + #[dbus_method("Cleanup")] + fn cleanup(&mut self) -> bool { + dbus_generated!() + } + + #[dbus_method("Connect")] + fn connect(&mut self, address: String) { + dbus_generated!() + } + + #[dbus_method("Disconnect")] + fn disconnect(&mut self, address: String) { + dbus_generated!() + } + + #[dbus_method("SetActiveDevice")] + fn set_active_device(&mut self, address: String) { + dbus_generated!() + } + + #[dbus_method("ResetActiveDevice")] + fn reset_active_device(&mut self) { + dbus_generated!() + } + + #[dbus_method("SetHfpActiveDevice")] + fn set_hfp_active_device(&mut self, address: String) { + dbus_generated!() + } + + #[dbus_method("SetAudioConfig")] + fn set_audio_config( + &mut self, + address: String, + codec_type: A2dpCodecIndex, + sample_rate: A2dpCodecSampleRate, + bits_per_sample: A2dpCodecBitsPerSample, + channel_mode: A2dpCodecChannelMode, + ) -> bool { + dbus_generated!() + } + + #[dbus_method("SetVolume")] + fn set_volume(&mut self, volume: u8) { + dbus_generated!() + } + + #[dbus_method("SetHfpVolume")] + fn set_hfp_volume(&mut self, volume: u8, address: String) { + dbus_generated!() + } + + #[dbus_method("StartAudioRequest")] + fn start_audio_request(&mut self) -> bool { + dbus_generated!() + } + + #[dbus_method("GetA2dpAudioStarted")] + fn get_a2dp_audio_started(&mut self, address: String) -> bool { + dbus_generated!() + } + + #[dbus_method("StopAudioRequest")] + fn stop_audio_request(&mut self) { + dbus_generated!() + } + + #[dbus_method("StartScoCall")] + fn start_sco_call( + &mut self, + address: String, + sco_offload: bool, + disabled_codecs: HfpCodecCapability, + ) -> bool { + dbus_generated!() + } + + #[dbus_method("GetHfpAudioFinalCodecs")] + fn get_hfp_audio_final_codecs(&mut self, address: String) -> u8 { + dbus_generated!() + } + + #[dbus_method("StopScoCall")] + fn stop_sco_call(&mut self, address: String) { + dbus_generated!() + } + + #[dbus_method("GetPresentationPosition")] + fn get_presentation_position(&mut self) -> PresentationPosition { + dbus_generated!() + } + + // Temporary AVRCP-related meida DBUS APIs. The following APIs intercept between Chrome CRAS + // and cras_server as an expedited solution for AVRCP implementation. The APIs are subject to + // change when retiring Chrome CRAS. + #[dbus_method("SetPlayerPlaybackStatus")] + fn set_player_playback_status(&mut self, status: String) { + dbus_generated!() + } + + #[dbus_method("SetPlayerPosition")] + fn set_player_position(&mut self, position_us: i64) { + dbus_generated!() + } + + #[dbus_method("SetPlayerMetadata")] + fn set_player_metadata(&mut self, metadata: PlayerMetadata) { + dbus_generated!() + } + + #[dbus_method("TriggerDebugDump")] + fn trigger_debug_dump(&mut self) { + dbus_generated!() + } +} + +struct IBluetoothMediaCallbackDBus {} + +impl RPCProxy for IBluetoothMediaCallbackDBus {} + +#[generate_dbus_exporter( + export_bluetooth_media_callback_dbus_intf, + "org.chromium.bluetooth.BluetoothMediaCallback" +)] +impl IBluetoothMediaCallback for IBluetoothMediaCallbackDBus { + #[dbus_method("OnBluetoothAudioDeviceAdded", DBusLog::Disable)] + fn on_bluetooth_audio_device_added(&mut self, device: BluetoothAudioDevice) {} + + #[dbus_method("OnBluetoothAudioDeviceRemoved", DBusLog::Disable)] + fn on_bluetooth_audio_device_removed(&mut self, addr: String) {} + + #[dbus_method("OnAbsoluteVolumeSupportedChanged", DBusLog::Disable)] + fn on_absolute_volume_supported_changed(&mut self, supported: bool) {} + + #[dbus_method("OnAbsoluteVolumeChanged", DBusLog::Disable)] + fn on_absolute_volume_changed(&mut self, volume: u8) {} + + #[dbus_method("OnHfpVolumeChanged", DBusLog::Disable)] + fn on_hfp_volume_changed(&mut self, volume: u8, addr: String) {} + + #[dbus_method("OnHfpAudioDisconnected", DBusLog::Disable)] + fn on_hfp_audio_disconnected(&mut self, addr: String) {} + + #[dbus_method("OnHfpDebugDump", DBusLog::Disable)] + fn on_hfp_debug_dump( + &mut self, + active: bool, + codec_id: u16, + total_num_decoded_frames: i32, + pkt_loss_ratio: f64, + begin_ts: u64, + end_ts: u64, + pkt_status_in_hex: String, + pkt_status_in_binary: String, + ) { + } } diff --git a/system/gd/rust/linux/client/src/main.rs b/system/gd/rust/linux/client/src/main.rs index e36d1e0d81c98f1e09a42ddf3f1f30543aa491af..5793cc16f1d56df5b28a7d1ea521d60d7eb99a30 100644 --- a/system/gd/rust/linux/client/src/main.rs +++ b/system/gd/rust/linux/client/src/main.rs @@ -2,23 +2,27 @@ use clap::{value_t, App, Arg}; use std::collections::{HashMap, HashSet}; use std::sync::{Arc, Mutex}; +use std::time::Duration; use dbus::channel::MatchingReceiver; use dbus::message::MatchRule; use dbus::nonblock::SyncConnection; use dbus_crossroads::Crossroads; use tokio::sync::mpsc; +use tokio::time::{sleep, timeout}; use crate::bt_adv::AdvSet; use crate::bt_gatt::GattClientContext; use crate::callbacks::{ AdminCallback, AdvertisingSetCallback, BtCallback, BtConnectionCallback, BtManagerCallback, - BtSocketManagerCallback, ScannerCallback, SuspendCallback, + BtSocketManagerCallback, MediaCallback, QACallback, ScannerCallback, SuspendCallback, + TelephonyCallback, }; use crate::command_handler::{CommandHandler, SocketSchedule}; use crate::dbus_iface::{ - BluetoothAdminDBus, BluetoothDBus, BluetoothGattDBus, BluetoothManagerDBus, BluetoothQADBus, - BluetoothQALegacyDBus, BluetoothSocketManagerDBus, BluetoothTelephonyDBus, SuspendDBus, + BluetoothAdminDBus, BluetoothDBus, BluetoothGattDBus, BluetoothManagerDBus, BluetoothMediaDBus, + BluetoothQADBus, BluetoothQALegacyDBus, BluetoothSocketManagerDBus, BluetoothTelephonyDBus, + SuspendDBus, }; use crate::editor::AsyncEditor; use bt_topshim::topstack; @@ -95,6 +99,9 @@ pub(crate) struct ClientContext { /// Proxy for Telephony interface. pub(crate) telephony_dbus: Option, + /// Proxy for Media interface. + pub(crate) media_dbus: Option, + /// Channel to send actions to take in the foreground fg: mpsc::Sender, @@ -122,6 +129,9 @@ pub(crate) struct ClientContext { /// Identifies the callback to receive IBluetoothSocketManagerCallback method calls. socket_manager_callback_id: Option, + /// Identifies the callback to receive IBluetoothQACallback method calls. + qa_callback_id: Option, + /// Is btclient running in restricted mode? is_restricted: bool, @@ -133,6 +143,9 @@ pub(crate) struct ClientContext { /// The handle of the SDP record for MPS (Multi-Profile Specification). mps_sdp_handle: Option, + + /// The set of client commands that need to wait for callbacks. + client_commands_with_callbacks: Vec, } impl ClientContext { @@ -141,6 +154,7 @@ impl ClientContext { dbus_crossroads: Arc>, tx: mpsc::Sender, is_restricted: bool, + client_commands_with_callbacks: Vec, ) -> ClientContext { // Manager interface is almost always available but adapter interface // requires that the specific adapter is enabled. @@ -165,6 +179,7 @@ impl ClientContext { suspend_dbus: None, socket_manager_dbus: None, telephony_dbus: None, + media_dbus: None, fg: tx, dbus_connection, dbus_crossroads, @@ -174,10 +189,12 @@ impl ClientContext { active_scanner_ids: HashSet::new(), adv_sets: HashMap::new(), socket_manager_callback_id: None, + qa_callback_id: None, is_restricted, gatt_client_context: GattClientContext::new(), socket_test_schedule: None, mps_sdp_handle: None, + client_commands_with_callbacks, } } @@ -224,10 +241,15 @@ impl ClientContext { self.telephony_dbus = Some(BluetoothTelephonyDBus::new(conn.clone(), idx)); + self.media_dbus = Some(BluetoothMediaDBus::new(conn.clone(), idx)); + // Trigger callback registration in the foreground let fg = self.fg.clone(); tokio::spawn(async move { let adapter = String::from(format!("adapter{}", idx)); + // Floss won't export the interface until it is ready to be used. + // Wait 1 second before registering the callbacks. + sleep(Duration::from_millis(1000)).await; let _ = fg.send(ForegroundActions::RegisterAdapterCallback(adapter)).await; }); } @@ -279,6 +301,13 @@ impl ClientContext { result } + + fn get_floss_api_version(&mut self) -> (u32, u32) { + let ver = self.manager_dbus.get_floss_api_version(); + let major = (ver & 0xFFFF_0000) >> 16; + let minor = ver & 0x0000_FFFF; + (major, minor) + } } /// Actions to take on the foreground loop. This allows us to queue actions in @@ -294,10 +323,24 @@ enum ForegroundActions { fn main() -> Result<(), Box> { let matches = App::new("btclient") .arg(Arg::with_name("restricted").long("restricted").takes_value(false)) - .arg(Arg::with_name("command").short("c").long("command").takes_value(true)) + .arg( + Arg::with_name("command") + .short("c") + .long("command") + .takes_value(true) + .help("Executes a non-interactive command"), + ) + .arg( + Arg::with_name("timeout") + .short("t") + .long("timeout") + .takes_value(true) + .help("Specify a timeout in seconds for a non-interactive command"), + ) .get_matches(); let command = value_t!(matches, "command", String); let is_restricted = matches.is_present("restricted"); + let timeout_secs = value_t!(matches, "timeout", u64); topstack::get_runtime().block_on(async move { // Connect to D-Bus system bus. @@ -330,12 +373,18 @@ fn main() -> Result<(), Box> { // Accept foreground actions with mpsc let (tx, rx) = mpsc::channel::(10); + // Include the commands + // (1) that will be run as non-interactive client commands, and + // (2) that will need to wait for the callbacks to complete. + let client_commands_with_callbacks = vec!["media".to_string()]; + // Create the context needed for handling commands let context = Arc::new(Mutex::new(ClientContext::new( conn.clone(), cr.clone(), tx.clone(), is_restricted, + client_commands_with_callbacks, ))); // Check if manager interface is valid. We only print some help text before failing on the @@ -374,55 +423,77 @@ fn main() -> Result<(), Box> { } } - let mut handler = CommandHandler::new(context.clone()); - - // Allow command line arguments to be read - match command { - Ok(command) => { - let mut iter = command.split(' ').map(String::from); - handler.process_cmd_line( - &iter.next().unwrap_or(String::from("")), - &iter.collect::>(), - ); - } - _ => { - start_interactive_shell(handler, tx, rx, context).await?; + let handler = CommandHandler::new(context.clone()); + if let Ok(_) = command { + // Timeout applies only to non-interactive commands. + if let Ok(timeout_secs) = timeout_secs { + let timeout_duration = Duration::from_secs(timeout_secs); + match timeout( + timeout_duration, + handle_client_command(handler, tx, rx, context, command), + ) + .await + { + Ok(_) => { + return Result::Ok(()); + } + Err(_) => { + return Result::Err("btclient timeout".into()); + } + }; } - }; + } + // There are two scenarios in which handle_client_command is run without a timeout. + // - Interactive commands: none of these commands require a timeout. + // - Non-interactive commands that have not specified a timeout. + handle_client_command(handler, tx, rx, context, command).await?; return Result::Ok(()); }) } -async fn start_interactive_shell( +// If btclient runs without command arguments, the interactive shell +// actions are performed. +// If btclient runs with command arguments, the command is executed +// once. There are two cases to exit. +// Case 1: if the command does not need a callback, e.g., "help", +// it will exit after running handler.process_cmd_line(). +// Case 2: if the command needs a callback, e.g., "media log", +// it will exit after the callback has been run in the arm +// of ForegroundActions::RunCallback(callback). +async fn handle_client_command( mut handler: CommandHandler, tx: mpsc::Sender, mut rx: mpsc::Receiver, context: Arc>, + command: Result, ) -> Result<(), Box> { - let command_rule_list = handler.get_command_rule_list().clone(); - let context_for_closure = context.clone(); - let semaphore_fg = Arc::new(tokio::sync::Semaphore::new(1)); - // Async task to keep reading new lines from user - let semaphore = semaphore_fg.clone(); - let editor = AsyncEditor::new(command_rule_list, context_for_closure) - .map_err(|x| format!("creating async editor failed: {x}"))?; - tokio::spawn(async move { - loop { - // Wait until ForegroundAction::Readline finishes its task. - let permit = semaphore.acquire().await; - if permit.is_err() { - break; - }; - // Let ForegroundAction::Readline decide when it's done. - permit.unwrap().forget(); - - // It's good to do readline now. - let result = editor.readline().await; - let _ = tx.send(ForegroundActions::Readline(result)).await; - } - }); + // If there are no command arguments, start the interactive shell. + if let Err(_) = command { + let command_rule_list = handler.get_command_rule_list().clone(); + let context_for_closure = context.clone(); + + // Async task to keep reading new lines from user + let semaphore = semaphore_fg.clone(); + let editor = AsyncEditor::new(command_rule_list, context_for_closure) + .map_err(|x| format!("creating async editor failed: {x}"))?; + tokio::spawn(async move { + loop { + // Wait until ForegroundAction::Readline finishes its task. + let permit = semaphore.acquire().await; + if permit.is_err() { + break; + }; + // Let ForegroundAction::Readline decide when it's done. + permit.unwrap().forget(); + + // It's good to do readline now. + let result = editor.readline().await; + let _ = tx.send(ForegroundActions::Readline(result)).await; + } + }); + } 'readline: loop { let m = rx.recv().await; @@ -447,6 +518,11 @@ async fn start_interactive_shell( } ForegroundActions::RunCallback(callback) => { callback(context.clone()); + + // Break the loop as a non-interactive command is completed. + if let Ok(_) = command { + break; + } } // Once adapter is ready, register callbacks, get the address and mark it as ready ForegroundActions::RegisterAdapterCallback(adapter) => { @@ -464,6 +540,14 @@ async fn start_interactive_shell( format!("/org/chromium/bluetooth/client/{}/admin_callback", adapter); let socket_manager_cb_objpath: String = format!("/org/chromium/bluetooth/client/{}/socket_manager_callback", adapter); + let qa_cb_objpath: String = + format!("/org/chromium/bluetooth/client/{}/qa_manager_callback", adapter); + let media_cb_objpath: String = + format!("/org/chromium/bluetooth/client/{}/bluetooth_media_callback", adapter); + let telephony_cb_objpath: String = format!( + "/org/chromium/bluetooth/client/{}/bluetooth_telephony_callback", + adapter + ); let dbus_connection = context.lock().unwrap().dbus_connection.clone(); let dbus_crossroads = context.lock().unwrap().dbus_crossroads.clone(); @@ -568,6 +652,23 @@ async fn start_interactive_shell( context.lock().unwrap().socket_manager_callback_id = Some(socket_manager_callback_id); + let qa_callback_id = context + .lock() + .unwrap() + .qa_dbus + .as_mut() + .unwrap() + .rpc + .register_qa_callback(Box::new(QACallback::new( + qa_cb_objpath.clone(), + context.clone(), + dbus_connection.clone(), + dbus_crossroads.clone(), + ))) + .await + .expect("D-Bus error on IBluetoothQA::RegisterCallback"); + context.lock().unwrap().qa_callback_id = Some(qa_callback_id); + // When adapter is ready, Suspend API is also ready. Register as an observer. // TODO(b/224606285): Implement suspend debug utils in btclient. context.lock().unwrap().suspend_dbus.as_mut().unwrap().register_callback(Box::new( @@ -578,11 +679,60 @@ async fn start_interactive_shell( ), )); + context + .lock() + .unwrap() + .media_dbus + .as_mut() + .unwrap() + .rpc + .register_callback(Box::new(MediaCallback::new( + media_cb_objpath, + context.clone(), + dbus_connection.clone(), + dbus_crossroads.clone(), + ))) + .await + .expect("D-Bus error on IBluetoothMedia::RegisterCallback"); + + context + .lock() + .unwrap() + .telephony_dbus + .as_mut() + .unwrap() + .rpc + .register_telephony_callback(Box::new(TelephonyCallback::new( + telephony_cb_objpath, + context.clone(), + dbus_connection.clone(), + dbus_crossroads.clone(), + ))) + .await + .expect("D-Bus error on IBluetoothMedia::RegisterTelephonyCallback"); + context.lock().unwrap().adapter_ready = true; let adapter_address = context.lock().unwrap().update_adapter_address(); context.lock().unwrap().update_bonded_devices(); print_info!("Adapter {} is ready", adapter_address); + + // Run the command with the command arguments as the client is + // non-interactive. + if let Some(command) = command.as_ref().ok() { + let mut iter = command.split(' ').map(String::from); + let first = iter.next().unwrap_or(String::from("")); + if !handler.process_cmd_line(&first, &iter.collect::>()) { + // Break immediately if the command fails to execute. + break; + } + + // Break the loop immediately if there is no callback + // to wait for. + if !context.lock().unwrap().client_commands_with_callbacks.contains(&first) { + break; + } + } } ForegroundActions::Readline(result) => match result { Err(rustyline::error::ReadlineError::Interrupted) => { diff --git a/system/gd/rust/linux/dbus_projection/Cargo.toml b/system/gd/rust/linux/dbus_projection/Cargo.toml index 425b8e6b353b785b3eaf817dd19df63a40098d8c..954d9a2f1e94ebbc08f6fa54787e0481da5bfaa8 100644 --- a/system/gd/rust/linux/dbus_projection/Cargo.toml +++ b/system/gd/rust/linux/dbus_projection/Cargo.toml @@ -8,3 +8,4 @@ dbus_macros = { path = "dbus_macros" } dbus = "0.9.2" dbus-tokio = "0.7.6" futures = "0.3.13" +log = "0.4.14" diff --git a/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs b/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs index afcb397ae878c4dc99a0e5be4fb53cb00264d515..5a72a700393eede4276df5ec226e6e6ba479e787 100644 --- a/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs +++ b/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs @@ -13,7 +13,7 @@ use std::path::Path; use syn::parse::Parser; use syn::punctuated::Punctuated; use syn::token::Comma; -use syn::{Expr, FnArg, ImplItem, ItemImpl, ItemStruct, Meta, Pat, ReturnType, Type}; +use syn::{Expr, FnArg, ImplItem, ItemImpl, ItemStruct, Meta, NestedMeta, Pat, ReturnType, Type}; use crate::proc_macro::TokenStream; @@ -36,6 +36,17 @@ fn debug_output_to_file(gen: &proc_macro2::TokenStream, filename: String) { } /// Marks a method to be projected to a D-Bus method and specifies the D-Bus method name. +/// +/// Example: +/// `#[dbus_method("GetAdapterFoo")]` +/// `#[dbus_method("RegisterFoo", DBusLog::Enable(DBusLogOptions::LogAll, DBusLogVerbosity::Info))` +/// +/// # Args +/// +/// `dbus_method_name`: String. The D-Bus method name. +/// `dbus_logging`: enum DBusLog, optional. Whether to enable logging and the log verbosity. +/// Note that log is disabled by default for outgoing dbus messages, but enabled +/// by default with verbose level for incoming messages. #[proc_macro_attribute] pub fn dbus_method(_attr: TokenStream, item: TokenStream) -> TokenStream { let ori_item: proc_macro2::TokenStream = item.clone().into(); @@ -51,7 +62,7 @@ pub fn dbus_method(_attr: TokenStream, item: TokenStream) -> TokenStream { /// /// Example: /// `#[generate_dbus_exporter(export_foo_dbus_intf, "org.example.FooInterface")]` -/// `#[generate_dbus_exporter(export_foo_dbus_intf, "org.example.FooInterface", FooMixin, foo]` +/// `#[generate_dbus_exporter(export_foo_dbus_intf, "org.example.FooInterface", FooMixin, foo)]` /// /// This generates a method called `export_foo_dbus_intf` that will export a Rust object type into a /// interface token for `org.example.FooInterface`. This interface must then be inserted to an @@ -60,6 +71,9 @@ pub fn dbus_method(_attr: TokenStream, item: TokenStream) -> TokenStream { /// If the mixin parameter is provided, you must provide the mixin class when registering with /// crossroads (and that's the one that should be Arc>. /// +/// In order to use the interface via D-Bus calls, the Rust object needs to declare its methods with +/// the attribute #[dbus_method()]. +/// /// # Args /// /// `exporter`: Function name for outputted interface exporter. @@ -67,7 +81,7 @@ pub fn dbus_method(_attr: TokenStream, item: TokenStream) -> TokenStream { /// `mixin_type`: The name of the Mixin struct. Mixins should be used when /// exporting multiple interfaces and objects under a single object /// path. -/// `mixin`: Name of this object in the mixin where it's implemented. +/// `mixin_name`: Name of this object in the mixin where it's implemented. #[proc_macro_attribute] pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStream { let ori_item: proc_macro2::TokenStream = item.clone().into(); @@ -120,16 +134,21 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre continue; } - let attr_args = attr.parse_meta().unwrap(); - let dbus_method_name = if let Meta::List(meta_list) = attr_args { - Some(meta_list.nested[0].clone()) - } else { - None + let meta_list = match attr.parse_meta().unwrap() { + Meta::List(meta_list) => meta_list, + _ => continue, }; - if dbus_method_name.is_none() { - continue; - } + let dbus_method_name = meta_list.nested[0].clone(); + + // logging is default to verbose if not specified + let dbus_logging = if meta_list.nested.len() > 1 { + meta_list.nested[1].clone() + } else { + let token = + quote! { DBusLog::Enable(DBusLogOptions::LogAll, DBusLogVerbosity::Verbose) }; + syn::parse2::(token).unwrap() + }; let method_name = method.sig.ident; @@ -138,6 +157,8 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre let mut make_args = quote! {}; let mut dbus_input_vars = quote! {}; let mut dbus_input_types = quote! {}; + let mut args_debug = quote! {}; + let mut args_debug_format = String::new(); for input in method.sig.inputs { if let FnArg::Typed(ref typed) = input { @@ -183,6 +204,16 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre let #ident = #ident.unwrap(); }; + + args_debug = quote! { + #args_debug + <#arg_type as DBusArg>::log(&#ident), + }; + + if args_debug_format.len() != 0 { + args_debug_format.push_str(", "); + } + args_debug_format.push_str("{:?}"); } } } @@ -200,6 +231,11 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre output_names = quote! { "out", }; } + let debug = quote! { + let args_formatted = format!(#args_debug_format, #args_debug); + DBusLog::log(#dbus_logging, "dbus in", #dbus_iface_name, #dbus_method_name, args_formatted.as_str()); + }; + let method_call = match mixin_name { Some(name) => { quote! { @@ -223,6 +259,7 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre #dbus_input_args | -> Result<(#output_type), dbus_crossroads::MethodErr> { #make_args + #debug #method_call #ret }; @@ -667,6 +704,10 @@ pub fn dbus_propmap(attr: TokenStream, item: TokenStream) -> TokenStream { #insert_map_fields return Ok(map__); } + + fn log(data: &#struct_ident) -> String { + String::from(format!("{:?}", data)) + } } }; @@ -676,6 +717,16 @@ pub fn dbus_propmap(attr: TokenStream, item: TokenStream) -> TokenStream { } /// Generates a DBusArg implementation of a Remote RPC proxy object. +/// +/// Example: +/// `#[dbus_proxy_obj(FooCallback, "org.example.FooCallbackInterface")]` +/// +/// In order to call the remote methods, declare them with the attribute #[dbus_method()]. +/// +/// # Args +/// +/// `struct_ident`: A freeform name used to identify the object struct. +/// `dbus_iface_name`: Name of the interface where this object should be exported. #[proc_macro_attribute] pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream { let ori_item: proc_macro2::TokenStream = item.clone().into(); @@ -717,20 +768,26 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream { continue; } - let attr_args = attr.parse_meta().unwrap(); - let dbus_method_name = if let Meta::List(meta_list) = attr_args { - Some(meta_list.nested[0].clone()) - } else { - None + let meta_list = match attr.parse_meta().unwrap() { + Meta::List(meta_list) => meta_list, + _ => continue, }; - if dbus_method_name.is_none() { - continue; - } + let dbus_method_name = meta_list.nested[0].clone(); + + // logging is default to disabled if not specified + let dbus_logging = if meta_list.nested.len() > 1 { + meta_list.nested[1].clone() + } else { + let token = quote! { DBusLog::Disable }; + syn::parse2::(token).unwrap() + }; let method_sig = method.sig.clone(); let mut method_args = quote! {}; + let mut args_debug = quote! {}; + let mut args_debug_format = String::new(); for input in method.sig.inputs { if let FnArg::Typed(ref typed) = input { @@ -740,10 +797,24 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream { method_args = quote! { #method_args DBusArg::to_dbus(#ident).unwrap(), }; + + args_debug = quote! { + #args_debug &#ident, + }; + + if args_debug_format.len() != 0 { + args_debug_format.push_str(", "); + } + args_debug_format.push_str("{:?}"); } } } + let debug = quote! { + let args_formatted = format!(#args_debug_format, #args_debug); + DBusLog::log(#dbus_logging, "dbus out", #dbus_iface_name, #dbus_method_name, args_formatted.as_str()); + }; + method_impls = quote! { #method_impls #[allow(unused_variables)] @@ -752,12 +823,14 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream { let objpath__ = self.objpath.clone(); let conn__ = self.conn.clone(); + #debug + let proxy = dbus::nonblock::Proxy::new( - remote__, - objpath__, - std::time::Duration::from_secs(2), - conn__, - ); + remote__, + objpath__, + std::time::Duration::from_secs(2), + conn__, + ); let future: dbus::nonblock::MethodReply<()> = proxy.method_call( #dbus_iface_name, #dbus_method_name, @@ -900,6 +973,10 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream { // This impl represents a remote DBus object, so `to_dbus` does not make sense. panic!("not implemented"); } + + fn log(_data: &Box) -> String { + String::from(format!("Box")) + } } }; @@ -1104,7 +1181,7 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { } } - /// Trait describing how to convert to and from a D-Bus type. + /// Trait describing how to convert to and from a D-Bus type, and to log D-Bus transaction. /// /// All Rust structs that need to be serialized to and from D-Bus need /// to implement this trait. Basic and container types will have their @@ -1117,7 +1194,7 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { /// /// When implementing this trait for Rust container types (i.e. Option), /// you must first select the D-Bus container type used (i.e. array, property map, etc) and - /// then implement the `from_dbus` and `to_dbus` functions. + /// then implement the `from_dbus`, `to_dbus`, and `log` functions. pub(crate) trait DBusArg { type DBusType; @@ -1131,15 +1208,18 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { Self: Sized; fn to_dbus(x: Self) -> Result>; + + fn log(x: &Self) -> String; } // Types that implement dbus::arg::Append do not need any conversion. - pub(crate) trait DirectDBus: Clone {} + pub(crate) trait DirectDBus: Clone + std::fmt::Display {} impl DirectDBus for bool {} impl DirectDBus for i32 {} impl DirectDBus for u32 {} impl DirectDBus for i64 {} impl DirectDBus for u64 {} + impl DirectDBus for f64 {} impl DirectDBus for i16 {} impl DirectDBus for u16 {} impl DirectDBus for u8 {} @@ -1159,6 +1239,10 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { fn to_dbus(data: T) -> Result> { return Ok(data); } + + fn log(data: &T) -> String { + String::from(format!("{}", data)) + } } // Represent i8 as D-Bus's i16, since D-Bus only has unsigned type for BYTE. @@ -1179,9 +1263,13 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { fn to_dbus(data: std::fs::File) -> Result> { return Ok(data); } + + fn log(data: &std::fs::File) -> String { + String::from(format!("{:?}", data)) + } } - impl DBusArg for Vec { + impl DBusArg for Vec where T: std::fmt::Debug { type DBusType = Vec; fn from_dbus( @@ -1211,10 +1299,19 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { } Ok(list) } + + fn log(data: &Vec) -> String { + String::from(format!("{:?}", data)) + } } impl DBusArg for Option - where ::DBusType: dbus::arg::RefArg + 'static + RefArgToRust::DBusType> { + where + ::DBusType: dbus::arg::RefArg + + 'static + + RefArgToRust::DBusType>, + T: std::fmt::Debug + { type DBusType = dbus::arg::PropMap; fn from_dbus( @@ -1268,6 +1365,10 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { Ok(props) } + + fn log(data: &Option) -> String { + String::from(format!("{:?}", data)) + } } impl DBusArg for std::collections::HashMap @@ -1277,6 +1378,8 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { + Hash + dbus::arg::RefArg + RefArgToRust::DBusType>, + K: std::fmt::Debug, + V: std::fmt::Debug, { type DBusType = std::collections::HashMap; @@ -1318,6 +1421,10 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { } Ok(map) } + + fn log(data: &std::collections::HashMap) -> String { + String::from(format!("{:?}", data)) + } } }; diff --git a/system/gd/rust/linux/dbus_projection/src/lib.rs b/system/gd/rust/linux/dbus_projection/src/lib.rs index 40f9eff93b23d4c1e61e2f14801dda1edaa1ac24..d85f5b213bfb6b134be6e286ee5ad229c4337c6e 100644 --- a/system/gd/rust/linux/dbus_projection/src/lib.rs +++ b/system/gd/rust/linux/dbus_projection/src/lib.rs @@ -54,6 +54,13 @@ use dbus::strings::BusName; use std::collections::HashMap; use std::sync::{Arc, Mutex}; +pub mod prelude { + pub use super::{ + dbus_generated, impl_dbus_arg_enum, impl_dbus_arg_from_into, ClientDBusProxy, DBusLog, + DBusLogOptions, DBusLogVerbosity, DisconnectWatcher, + }; +} + /// A D-Bus "NameOwnerChanged" handler that continuously monitors client disconnects. /// /// When the watched bus address disconnects, all the callbacks associated with it are called with @@ -243,7 +250,7 @@ impl ClientDBusProxy { /// Implements `DBusArg` for an enum. /// -/// A Rust enum is converted to D-Bus INT32 type. +/// A Rust enum is converted to D-Bus UINT32 type. #[macro_export] macro_rules! impl_dbus_arg_enum { ($enum_type:ty) => { @@ -270,6 +277,10 @@ macro_rules! impl_dbus_arg_enum { fn to_dbus(data: $enum_type) -> Result> { return Ok(data.to_u32().unwrap()); } + + fn log(data: &$enum_type) -> String { + String::from(format!("{:?}", data)) + } } }; } @@ -308,6 +319,10 @@ macro_rules! impl_dbus_arg_from_into { Ok(result) => Ok(result), } } + + fn log(data: &$rust_type) -> String { + String::from(format!("{:?}", data)) + } } }; } @@ -321,3 +336,42 @@ macro_rules! dbus_generated { panic!("To be implemented by dbus_projection macros"); }; } + +pub enum DBusLogOptions { + LogAll, + LogMethodNameOnly, +} + +pub enum DBusLogVerbosity { + Error, + Warn, + Info, + Verbose, +} + +pub enum DBusLog { + Enable(DBusLogOptions, DBusLogVerbosity), + Disable, +} + +impl DBusLog { + pub fn log(logging: DBusLog, prefix: &str, iface_name: &str, func_name: &str, param: &str) { + match logging { + Self::Enable(option, verbosity) => { + let part_before_param = format!("{}: {}: {}", prefix, iface_name, func_name); + let output = match option { + DBusLogOptions::LogAll => format!("{}: {}", part_before_param, param), + DBusLogOptions::LogMethodNameOnly => part_before_param, + }; + + match verbosity { + DBusLogVerbosity::Error => log::error!("{}", output), + DBusLogVerbosity::Warn => log::warn!("{}", output), + DBusLogVerbosity::Info => log::info!("{}", output), + DBusLogVerbosity::Verbose => log::debug!("{}", output), + } + } + Self::Disable => {} + } + } +} diff --git a/system/gd/rust/linux/mgmt/Cargo.toml b/system/gd/rust/linux/mgmt/Cargo.toml index 831a34aa37b8de86a3048e5a276262983432aff0..042b25b00177e91392908e2d1464d20ec92798c6 100644 --- a/system/gd/rust/linux/mgmt/Cargo.toml +++ b/system/gd/rust/linux/mgmt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "manager_service" -version = "0.0.1" +version = "0.3.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/system/gd/rust/linux/mgmt/build.rs b/system/gd/rust/linux/mgmt/build.rs index 7f1152b486dfa0baceab38618ee334abfc2e7d54..6189dd7ca9842b8e9f2d5d113b0d604ba404093e 100644 --- a/system/gd/rust/linux/mgmt/build.rs +++ b/system/gd/rust/linux/mgmt/build.rs @@ -1,5 +1,3 @@ -extern crate protoc_rust; - use pkg_config::Config; use std::env; use std::fs; diff --git a/system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs b/system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs index b725b50ef141362739ae48d4376054619b7ab375..47011a10fb64f4de285e3b3523f9507fd933dab7 100644 --- a/system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs +++ b/system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs @@ -1,5 +1,5 @@ use dbus_macros::{dbus_method, generate_dbus_exporter}; -use dbus_projection::dbus_generated; +use dbus_projection::prelude::*; use crate::dbus_arg::DBusArg; use crate::iface_bluetooth_experimental::IBluetoothExperimental; @@ -17,7 +17,7 @@ struct BluetoothExperimentalDBus {} )] impl IBluetoothExperimental for BluetoothExperimentalDBus { #[dbus_method("SetLLPrivacy")] - fn set_ll_privacy(&mut self, enabled: bool) { + fn set_ll_privacy(&mut self, enabled: bool) -> bool { dbus_generated!() } diff --git a/system/gd/rust/linux/mgmt/src/bluetooth_manager.rs b/system/gd/rust/linux/mgmt/src/bluetooth_manager.rs index 535423a97b2c12bd9e4ce520790a2a7042645e1c..5fb1b33e5a712f9f6d4c2d4f9abe4e207610ca53 100644 --- a/system/gd/rust/linux/mgmt/src/bluetooth_manager.rs +++ b/system/gd/rust/linux/mgmt/src/bluetooth_manager.rs @@ -1,28 +1,37 @@ -use log::{error, info, warn}; +use log::{error, warn}; use std::collections::HashMap; use std::process::Command; +use std::sync::{Arc, Mutex}; + +use crate::powerd_suspend_manager::SuspendManagerContext; use crate::iface_bluetooth_experimental::IBluetoothExperimental; use crate::iface_bluetooth_manager::{ AdapterWithEnabled, IBluetoothManager, IBluetoothManagerCallback, }; use crate::state_machine::{ - state_to_enabled, AdapterState, Message, StateMachineProxy, VirtualHciIndex, + state_to_enabled, AdapterState, Message, ProcessState, StateMachineProxy, VirtualHciIndex, }; use crate::{config_util, migrate}; const BLUEZ_INIT_TARGET: &str = "bluetoothd"; +const INVALID_VER: u16 = 0xffff; /// Implementation of IBluetoothManager. pub struct BluetoothManager { proxy: StateMachineProxy, callbacks: HashMap>, + suspend_manager_context: Option>>, } impl BluetoothManager { pub fn new(proxy: StateMachineProxy) -> BluetoothManager { - BluetoothManager { proxy, callbacks: HashMap::new() } + BluetoothManager { proxy, callbacks: HashMap::new(), suspend_manager_context: None } + } + + pub fn set_suspend_manager_context(&mut self, context: Arc>) { + self.suspend_manager_context = Some(context); } fn is_adapter_enabled(&self, hci_device: VirtualHciIndex) -> bool { @@ -33,73 +42,93 @@ impl BluetoothManager { self.proxy.get_state(hci_device, move |a| Some(a.present)).unwrap_or(false) } - pub(crate) fn callback_hci_device_change(&mut self, hci_device: i32, present: bool) { + pub(crate) fn callback_hci_device_change(&mut self, hci: VirtualHciIndex, present: bool) { + if present { + warn!("Presence added: {}", hci); + } else { + warn!("Presence removed: {}", hci); + } for (_, callback) in &mut self.callbacks { - callback.on_hci_device_changed(hci_device, present); + callback.on_hci_device_changed(hci.to_i32(), present); } } - pub(crate) fn callback_hci_enabled_change(&mut self, hci_device: i32, enabled: bool) { + pub(crate) fn callback_hci_enabled_change(&mut self, hci: VirtualHciIndex, enabled: bool) { if enabled { - info!("Started {}", hci_device); + warn!("Started {}", hci); } else { - info!("Stopped {}", hci_device); + warn!("Stopped {}", hci); } for (_, callback) in &mut self.callbacks { - callback.on_hci_enabled_changed(hci_device, enabled); + callback.on_hci_enabled_changed(hci.to_i32(), enabled); } } - pub(crate) fn callback_default_adapter_change(&mut self, hci_device: i32) { + pub(crate) fn callback_default_adapter_change(&mut self, hci: VirtualHciIndex) { for (_, callback) in &mut self.callbacks { - callback.on_default_adapter_changed(hci_device); + callback.on_default_adapter_changed(hci.to_i32()); } } pub(crate) fn callback_disconnected(&mut self, id: u32) { self.callbacks.remove(&id); } + + /// Restarts all TurningOn/On adapters to make sure the configuration is reloaded. + pub(crate) fn restart_adapters(&mut self) { + self.proxy + .get_adapters() + .iter() + .filter(|a| a.state == ProcessState::TurningOn || a.state == ProcessState::On) + .for_each(|a| self.proxy.restart_bluetooth(a.virt_hci)); + } } impl IBluetoothManager for BluetoothManager { - fn start(&mut self, hci_interface: i32) { - info!("Starting {}", hci_interface); + fn start(&mut self, hci: i32) { + let hci = VirtualHciIndex(hci); + warn!("Starting {}", hci); - if !config_util::modify_hci_n_enabled(hci_interface, true) { - error!("Config is not successfully modified"); + if !config_util::modify_hci_n_enabled(hci, true) { + error!("{}: Config is not successfully modified", hci); } - let virt_hci = VirtualHciIndex(hci_interface); - // Store that this adapter is meant to be started in state machine. - self.proxy.modify_state(virt_hci, move |a: &mut AdapterState| a.config_enabled = true); + self.proxy.modify_state(hci, move |a: &mut AdapterState| a.config_enabled = true); // Ignore the request if adapter is already enabled or not present. - if self.is_adapter_enabled(virt_hci) || !self.is_adapter_present(virt_hci) { + if self.is_adapter_enabled(hci) { + warn!("{} is already enabled.", hci); + return; + } + + if !self.is_adapter_present(hci) { + warn!("{} is not present.", hci); return; } - self.proxy.start_bluetooth(virt_hci); + self.proxy.start_bluetooth(hci); } - fn stop(&mut self, hci_interface: i32) { - info!("Stopping {}", hci_interface); - if !config_util::modify_hci_n_enabled(hci_interface, false) { - error!("Config is not successfully modified"); - } + fn stop(&mut self, hci: i32) { + let hci = VirtualHciIndex(hci); + warn!("Stopping {}", hci); - let virt_hci = VirtualHciIndex(hci_interface); + if !config_util::modify_hci_n_enabled(hci, false) { + error!("{}: Config is not successfully modified", hci); + } // Store that this adapter is meant to be stopped in state machine. - self.proxy.modify_state(virt_hci, move |a: &mut AdapterState| a.config_enabled = false); + self.proxy.modify_state(hci, move |a: &mut AdapterState| a.config_enabled = false); // Ignore the request if adapter is already disabled. - if !self.is_adapter_enabled(virt_hci) { + if !self.is_adapter_enabled(hci) { + warn!("{} is already stopped", hci); return; } - self.proxy.stop_bluetooth(virt_hci); + self.proxy.stop_bluetooth(hci); } fn get_adapter_enabled(&mut self, hci_interface: i32) -> bool { @@ -124,6 +153,7 @@ impl IBluetoothManager for BluetoothManager { } fn set_floss_enabled(&mut self, enabled: bool) { + warn!("Set Floss Enabeld={}", enabled); let prev = self.proxy.set_floss_enabled(enabled); config_util::write_floss_enabled(enabled); @@ -132,15 +162,15 @@ impl IBluetoothManager for BluetoothManager { warn!("Failed to stop bluetoothd: {}", e); } migrate::migrate_bluez_devices(); - for hci in config_util::list_hci_devices() { + for hci in self.proxy.get_valid_adapters().iter().map(|a| a.virt_hci) { if config_util::is_hci_n_enabled(hci) { - let _ = self.proxy.start_bluetooth(VirtualHciIndex(hci)); + self.proxy.start_bluetooth(hci); } } } else if prev != enabled { - for hci in config_util::list_hci_devices() { + for hci in self.proxy.get_valid_adapters().iter().map(|a| a.virt_hci) { if config_util::is_hci_n_enabled(hci) { - let _ = self.proxy.stop_bluetooth(VirtualHciIndex(hci)); + self.proxy.stop_bluetooth(hci); } } migrate::migrate_floss_devices(); @@ -154,6 +184,8 @@ impl IBluetoothManager for BluetoothManager { self.proxy .get_valid_adapters() .iter() + // Don't present the queued device to the user. + .filter(|a| !a.has_queued_present) .map(|a| AdapterWithEnabled { hci_interface: a.virt_hci.to_i32(), enabled: state_to_enabled(a.state), @@ -168,28 +200,46 @@ impl IBluetoothManager for BluetoothManager { fn set_desired_default_adapter(&mut self, adapter_index: i32) { self.proxy.set_desired_default_adapter(VirtualHciIndex(adapter_index)); } + + fn get_floss_api_version(&mut self) -> u32 { + let major = env!("CARGO_PKG_VERSION_MAJOR").parse::().unwrap_or(INVALID_VER); + let minor = env!("CARGO_PKG_VERSION_MINOR").parse::().unwrap_or(INVALID_VER); + ((major as u32) << 16) | (minor as u32) + } + + fn set_tablet_mode(&mut self, tablet_mode: bool) { + match &self.suspend_manager_context { + Some(ctx) => ctx.lock().unwrap().tablet_mode = tablet_mode, + None => warn!("Context not available to set tablet mode."), + } + } } /// Implementation of IBluetoothExperimental impl IBluetoothExperimental for BluetoothManager { - fn set_ll_privacy(&mut self, enabled: bool) { + fn set_ll_privacy(&mut self, enabled: bool) -> bool { + warn!("Set Floss LL Privacy={}", enabled); let current_status = match config_util::read_floss_ll_privacy_enabled() { Ok(true) => true, _ => false, }; if current_status == enabled { - return; + return true; } if let Err(e) = config_util::write_floss_ll_privacy_enabled(enabled) { error!("Failed to write ll privacy status: {}", e); - return; + return false; } + + self.restart_adapters(); + + return true; } fn set_devcoredump(&mut self, enabled: bool) -> bool { - info!("Set floss devcoredump to {}", enabled); + warn!("Set Floss DevCoreDump={}", enabled); config_util::write_coredump_state_to_file(enabled) } } diff --git a/system/gd/rust/linux/mgmt/src/bluetooth_manager_dbus.rs b/system/gd/rust/linux/mgmt/src/bluetooth_manager_dbus.rs index dbd2fb5f82f99fe5f25e13022ff0e6c6e37ed59e..249a47629a33b05abb85e0263ad8b6c886ea3adb 100644 --- a/system/gd/rust/linux/mgmt/src/bluetooth_manager_dbus.rs +++ b/system/gd/rust/linux/mgmt/src/bluetooth_manager_dbus.rs @@ -2,7 +2,7 @@ use dbus::arg::RefArg; use dbus::strings::Path; use dbus_crossroads; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter}; -use dbus_projection::{dbus_generated, DisconnectWatcher}; +use dbus_projection::prelude::*; use btstack::RPCProxy; @@ -71,6 +71,16 @@ impl IBluetoothManager for BluetoothManagerDBus { fn set_desired_default_adapter(&mut self, hci_interface: i32) { dbus_generated!() } + + #[dbus_method("GetFlossApiVersion")] + fn get_floss_api_version(&mut self) -> u32 { + dbus_generated!() + } + + #[dbus_method("SetTabletMode")] + fn set_tablet_mode(&mut self, tablet_mode: bool) { + dbus_generated!() + } } /// D-Bus projection of IBluetoothManagerCallback. diff --git a/system/gd/rust/linux/mgmt/src/config_util.rs b/system/gd/rust/linux/mgmt/src/config_util.rs index c59d51a6d7cd19fcb24b94c0e974b3ec5a016b9a..8107d3f3afad8f565bf911bd44b907a4823fe919 100644 --- a/system/gd/rust/linux/mgmt/src/config_util.rs +++ b/system/gd/rust/linux/mgmt/src/config_util.rs @@ -1,3 +1,5 @@ +use crate::state_machine::{RealHciIndex, VirtualHciIndex}; + use log::LevelFilter; use serde_json::{Map, Value}; use std::convert::TryInto; @@ -25,7 +27,7 @@ const FLOSS_COREDUMP_CONF_PATH: &str = "/var/run/bluetooth/coredump_disabled"; const DEFAULT_ADAPTER_KEY: &str = "default_adapter"; /// In the absence of other values, default to hci0. -const DEFAULT_ADAPTER_VALUE: i32 = 0; +const DEFAULT_ADAPTER: VirtualHciIndex = VirtualHciIndex(0); pub fn is_floss_enabled() -> bool { match std::fs::read(BLUETOOTH_DAEMON_CURRENT) { @@ -69,17 +71,14 @@ fn get_log_level_internal(config: String) -> Option { } /// Returns whether hci N is enabled in config; defaults to true. -pub fn is_hci_n_enabled(n: i32) -> bool { - match read_config().ok().and_then(|config| is_hci_n_enabled_internal(config, n)) { - Some(v) => v, - _ => true, - } +pub fn is_hci_n_enabled(hci: VirtualHciIndex) -> bool { + read_config().ok().and_then(|config| is_hci_n_enabled_internal(config, hci)).unwrap_or(true) } -fn is_hci_n_enabled_internal(config: String, n: i32) -> Option { +fn is_hci_n_enabled_internal(config: String, hci: VirtualHciIndex) -> Option { serde_json::from_str::(config.as_str()) .ok()? - .get(format!("hci{}", n))? + .get(format!("hci{}", hci.to_i32()))? .as_object()? .get("enabled")? .as_bool() @@ -96,24 +95,25 @@ pub fn fix_config_file_format() -> bool { } } -pub fn modify_hci_n_enabled(n: i32, enabled: bool) -> bool { +pub fn modify_hci_n_enabled(hci: VirtualHciIndex, enabled: bool) -> bool { if !fix_config_file_format() { - false - } else { - match read_config() - .ok() - .and_then(|config| modify_hci_n_enabled_internal(config, n, enabled)) - { - Some(s) => std::fs::write(BTMANAGERD_CONF, s).is_ok(), - _ => false, - } + return false; + } + match read_config().ok().and_then(|config| modify_hci_n_enabled_internal(config, hci, enabled)) + { + Some(s) => std::fs::write(BTMANAGERD_CONF, s).is_ok(), + _ => false, } } -fn modify_hci_n_enabled_internal(config: String, n: i32, enabled: bool) -> Option { - let hci_interface = format!("hci{}", n); +fn modify_hci_n_enabled_internal( + config: String, + hci: VirtualHciIndex, + enabled: bool, +) -> Option { + let hci_str = format!("hci{}", hci.to_i32()); let mut o = serde_json::from_str::(config.as_str()).ok()?; - match o.get_mut(hci_interface.clone()) { + match o.get_mut(hci_str.clone()) { Some(section) => { section.as_object_mut()?.insert("enabled".to_string(), Value::Bool(enabled)); serde_json::ser::to_string_pretty(&o).ok() @@ -121,25 +121,31 @@ fn modify_hci_n_enabled_internal(config: String, n: i32, enabled: bool) -> Optio _ => { let mut entry_map = Map::new(); entry_map.insert("enabled".to_string(), Value::Bool(enabled)); - o.as_object_mut()?.insert(hci_interface, Value::Object(entry_map)); + o.as_object_mut()?.insert(hci_str, Value::Object(entry_map)); serde_json::ser::to_string_pretty(&o).ok() } } } -pub fn get_default_adapter() -> i32 { - match read_config().ok().and_then(|config| { - serde_json::from_str::(config.as_str()).ok()?.get(DEFAULT_ADAPTER_KEY)?.as_i64() - }) { - Some(v) => v.try_into().unwrap_or(DEFAULT_ADAPTER_VALUE), - None => DEFAULT_ADAPTER_VALUE, - } +pub fn get_default_adapter() -> VirtualHciIndex { + read_config() + .ok() + .and_then(|config| { + serde_json::from_str::(config.as_str()) + .ok()? + .get(DEFAULT_ADAPTER_KEY)? + .as_i64()? + .try_into() + .ok() + }) + .map(|i| VirtualHciIndex(i)) + .unwrap_or(DEFAULT_ADAPTER) } -pub fn set_default_adapter(adapter: i32) -> bool { +pub fn set_default_adapter(hci: VirtualHciIndex) -> bool { match read_config().ok().and_then(|config| { let mut cfg = serde_json::from_str::(config.as_str()).ok()?; - cfg[DEFAULT_ADAPTER_KEY] = serde_json::to_value(adapter).ok().unwrap(); + cfg[DEFAULT_ADAPTER_KEY] = serde_json::to_value(hci.to_i32()).ok().unwrap(); serde_json::ser::to_string_pretty(&cfg).ok() }) { Some(s) => std::fs::write(BTMANAGERD_CONF, s).is_ok(), @@ -147,10 +153,6 @@ pub fn set_default_adapter(adapter: i32) -> bool { } } -pub fn list_hci_devices() -> Vec { - hci_devices_string_to_int(list_hci_devices_string()) -} - fn list_hci_devices_string() -> Vec { match std::fs::read_dir(HCI_DEVICES_DIR) { Ok(entries) => entries @@ -161,29 +163,23 @@ fn list_hci_devices_string() -> Vec { } /// Check whether a certain hci device exists in sysfs. -pub fn check_hci_device_exists(hci: i32) -> bool { - Path::new(format!("{}/hci{}", HCI_DEVICES_DIR, hci).as_str()).exists() +pub fn check_hci_device_exists(hci: RealHciIndex) -> bool { + Path::new(format!("{}/hci{}", HCI_DEVICES_DIR, hci.to_i32()).as_str()).exists() } /// Get the devpath for a given hci index. This gives a stable path that can be /// used to identify a device even as the hci index fluctuates. -pub fn get_devpath_for_hci(hci: i32) -> Option { - match std::fs::canonicalize(format!("{}/hci{}/device", HCI_DEVICES_DIR, hci).as_str()) { +pub fn get_devpath_for_hci(hci: RealHciIndex) -> Option { + match std::fs::canonicalize(format!("{}/hci{}/device", HCI_DEVICES_DIR, hci.to_i32()).as_str()) + { Ok(p) => Some(p.into_os_string().into_string().ok()?), Err(e) => { - log::debug!("Failed to get devpath for hci{} with error: {}", hci, e); + log::debug!("Failed to get devpath for {} with error: {}", hci, e); None } } } -fn hci_devices_string_to_int(devices: Vec) -> Vec { - devices - .into_iter() - .filter_map(|e| if e.starts_with("hci") { e[3..].parse::().ok() } else { None }) - .collect() -} - pub fn list_pid_files(pid_dir: &str) -> Vec { match std::fs::read_dir(pid_dir) { Ok(entries) => entries @@ -194,8 +190,8 @@ pub fn list_pid_files(pid_dir: &str) -> Vec { } /// Calls the reset sysfs entry for an hci device. Returns True if the write succeeds. -pub fn reset_hci_device(hci: i32) -> bool { - let path = format!("/sys/class/bluetooth/hci{}/reset", hci); +pub fn reset_hci_device(hci: RealHciIndex) -> bool { + let path = format!("/sys/class/bluetooth/hci{}/reset", hci.to_i32()); std::fs::write(path, "1").is_ok() } @@ -259,7 +255,7 @@ mod tests { use super::*; fn is_hci_n_enabled_internal_wrapper(config: String, n: i32) -> bool { - is_hci_n_enabled_internal(config, n).or(Some(true)).unwrap() + is_hci_n_enabled_internal(config, VirtualHciIndex(n)).unwrap_or(true) } #[test] @@ -300,15 +296,19 @@ mod tests { #[test] fn modify_hci0_enabled() { - let modified_string = - modify_hci_n_enabled_internal("{\"hci0\":\n{\"enabled\": false}}".to_string(), 0, true) - .unwrap(); + let modified_string = modify_hci_n_enabled_internal( + "{\"hci0\":\n{\"enabled\": false}}".to_string(), + VirtualHciIndex(0), + true, + ) + .unwrap(); assert_eq!(is_hci_n_enabled_internal_wrapper(modified_string, 0), true); } #[test] fn modify_hci0_enabled_from_empty() { - let modified_string = modify_hci_n_enabled_internal("{}".to_string(), 0, true).unwrap(); + let modified_string = + modify_hci_n_enabled_internal("{}".to_string(), VirtualHciIndex(0), true).unwrap(); assert_eq!(is_hci_n_enabled_internal_wrapper(modified_string, 0), true); } @@ -327,22 +327,4 @@ mod tests { true ); } - - #[test] - fn test_hci_devices_string_to_int_none() { - assert_eq!(hci_devices_string_to_int(vec!["somethingelse".to_string()]), Vec::::new()); - } - - #[test] - fn test_hci_devices_string_to_int_one() { - assert_eq!(hci_devices_string_to_int(vec!["hci0".to_string()]), vec![0]); - } - - #[test] - fn test_hci_devices_string_to_int_two() { - assert_eq!( - hci_devices_string_to_int(vec!["hci0".to_string(), "hci1".to_string()]), - vec![0, 1] - ); - } } diff --git a/system/gd/rust/linux/mgmt/src/dbus_iface.rs b/system/gd/rust/linux/mgmt/src/dbus_iface.rs index a8cde16d730172cd0f5d7406c9049bc2fa1b8cda..f2110e1c5975d33d66d19e02a409d596d04328b6 100644 --- a/system/gd/rust/linux/mgmt/src/dbus_iface.rs +++ b/system/gd/rust/linux/mgmt/src/dbus_iface.rs @@ -4,7 +4,7 @@ use btstack::suspend::{ISuspend, ISuspendCallback, SuspendType}; use btstack::RPCProxy; use dbus::nonblock::SyncConnection; use dbus_macros::{dbus_method, generate_dbus_exporter, generate_dbus_interface_client}; -use dbus_projection::{impl_dbus_arg_enum, ClientDBusProxy}; +use dbus_projection::prelude::*; use num_traits::{FromPrimitive, ToPrimitive}; use std::sync::Arc; @@ -44,7 +44,7 @@ impl SuspendDBus { #[generate_dbus_interface_client(SuspendDBusRPC)] impl ISuspend for SuspendDBus { - #[dbus_method("RegisterCallback")] + #[dbus_method("RegisterCallback", DBusLog::Disable)] fn register_callback(&mut self, callback: Box) -> bool { dbus_generated!() } diff --git a/system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs b/system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs index 5af8d5fe964135eec63b16f64f91a40155a1e656..4a38e9ee1bab475a10f244308842dd269d0de23a 100644 --- a/system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs +++ b/system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs @@ -1,7 +1,7 @@ /// Bluetooth experimental feature API pub trait IBluetoothExperimental { /// Set LL privacy status - fn set_ll_privacy(&mut self, enabled: bool); + fn set_ll_privacy(&mut self, enabled: bool) -> bool; /// Set devcoredump status fn set_devcoredump(&mut self, enabled: bool) -> bool; diff --git a/system/gd/rust/linux/mgmt/src/iface_bluetooth_manager.rs b/system/gd/rust/linux/mgmt/src/iface_bluetooth_manager.rs index 7c6030d27058885c6b602ad6729540d71df36b9f..d516e005e0508eabd528897dfdf5a617bd00c9b6 100644 --- a/system/gd/rust/linux/mgmt/src/iface_bluetooth_manager.rs +++ b/system/gd/rust/linux/mgmt/src/iface_bluetooth_manager.rs @@ -47,6 +47,14 @@ pub trait IBluetoothManager { /// Set the preferred default adapter. fn set_desired_default_adapter(&mut self, hci_interface: i32); + + /// Returns Floss API verion.The MSB 16-bit is the major version and + /// LSB 16-bit is the minor version + fn get_floss_api_version(&mut self) -> u32; + + /// Set the tablet mode of the device. The device that is in tablet mode does not allow + /// wakeup by the HID devices. + fn set_tablet_mode(&mut self, tablet_mode: bool); } /// Interface of Bluetooth Manager callbacks. diff --git a/system/gd/rust/linux/mgmt/src/main.rs b/system/gd/rust/linux/mgmt/src/main.rs index da35b47a40ef298bc1478823415217c2e7638644..7c2d9633f49e9e654e7fbc4578ac7c7182b4a466 100644 --- a/system/gd/rust/linux/mgmt/src/main.rs +++ b/system/gd/rust/linux/mgmt/src/main.rs @@ -152,6 +152,11 @@ pub async fn main() -> Result<(), Box> { let mut powerd_suspend_manager = PowerdSuspendManager::new(conn.clone(), cr); + bluetooth_manager + .lock() + .unwrap() + .set_suspend_manager_context(powerd_suspend_manager.get_suspend_manager_context()); + tokio::spawn(async move { powerd_suspend_manager.init().await; powerd_suspend_manager.mainloop().await; diff --git a/system/gd/rust/linux/mgmt/src/migrate.rs b/system/gd/rust/linux/mgmt/src/migrate.rs index 591bf6a1b9ade57dec20d8155bd3dfcefc5af9ec..efecc7c24ce7e99fea89c4258447f443d7c778e9 100644 --- a/system/gd/rust/linux/mgmt/src/migrate.rs +++ b/system/gd/rust/linux/mgmt/src/migrate.rs @@ -246,9 +246,9 @@ fn reverse_endianness(str: String, uppercase: bool) -> Result { match u128::from_str_radix(&s, 16) { Ok(x) => { if uppercase { - Ok(format!("{:X}", x.swap_bytes())) + Ok(format!("{:0>32X}", x.swap_bytes())) } else { - Ok(format!("{:x}", x.swap_bytes())) + Ok(format!("{:0>32x}", x.swap_bytes())) } } Err(err) => Err(format!("Error converting link key: {}", err)), @@ -961,6 +961,11 @@ mod tests { key.apply_action("00112233445566778899AABBCCDDEE".to_string()), Ok("eeddccbbaa9988776655443322110000".to_string()) ); + // Conversion shouldn't lose leading zeros + assert_eq!( + key.apply_action("112233445566778899AABBCCDDEE0000".to_string()), + Ok("0000eeddccbbaa998877665544332211".to_string()) + ); } #[test] diff --git a/system/gd/rust/linux/mgmt/src/powerd_suspend_manager.rs b/system/gd/rust/linux/mgmt/src/powerd_suspend_manager.rs index 82d2e502f80d5bde6c95df49a24d949a7f947859..b6b1fae207ad811fa9152224e110abce52ed6821 100644 --- a/system/gd/rust/linux/mgmt/src/powerd_suspend_manager.rs +++ b/system/gd/rust/linux/mgmt/src/powerd_suspend_manager.rs @@ -168,6 +168,7 @@ pub struct SuspendManagerContext { powerd_session: Option, adapter_suspend_dbus: Option, pending_suspend_imminent: Option, + pub tablet_mode: bool, } /// Coordinates suspend events of Chromium OS's powerd with btadapter Suspend API. @@ -191,6 +192,7 @@ impl PowerdSuspendManager { powerd_session: None, adapter_suspend_dbus: None, pending_suspend_imminent: None, + tablet_mode: false, })), conn, tx, @@ -198,6 +200,10 @@ impl PowerdSuspendManager { } } + pub fn get_suspend_manager_context(&mut self) -> Arc> { + return self.context.clone(); + } + /// Sets up all required D-Bus listeners. pub async fn init(&mut self) { // Watch events of powerd appearing or disappearing. @@ -445,15 +451,26 @@ impl PowerdSuspendManager { // Anonymous block to contain locked `self.context` which needs to be called multiple // times in the `if let` block below. Prevent deadlock by locking only once. let mut context_locked = self.context.lock().unwrap(); + let tablet_mode = context_locked.tablet_mode; + if let Some(adapter_suspend_dbus) = &mut context_locked.adapter_suspend_dbus { let mut suspend_dbus_rpc = adapter_suspend_dbus.rpc.clone(); tokio::spawn(async move { let result = suspend_dbus_rpc .suspend( - match suspend_imminent.get_reason() { - SuspendImminent_Reason::IDLE => SuspendType::AllowWakeFromHid, - SuspendImminent_Reason::LID_CLOSED => SuspendType::NoWakesAllowed, - SuspendImminent_Reason::OTHER => SuspendType::Other, + match (tablet_mode, suspend_imminent.get_reason()) { + // No wakes allowed on tablet mode. + (true, _) => SuspendType::NoWakesAllowed, + + // When not in tablet mode, choose wake type based on suspend + // reason. + (false, SuspendImminent_Reason::IDLE) => { + SuspendType::AllowWakeFromHid + } + (false, SuspendImminent_Reason::LID_CLOSED) => { + SuspendType::NoWakesAllowed + } + (false, SuspendImminent_Reason::OTHER) => SuspendType::Other, }, suspend_imminent.get_suspend_id(), ) diff --git a/system/gd/rust/linux/mgmt/src/state_machine.rs b/system/gd/rust/linux/mgmt/src/state_machine.rs index d1365753702ac1be42a1ec9083b2e527ecda80a6..8647c68e8df66c5fa94e43298931454083cf1086 100644 --- a/system/gd/rust/linux/mgmt/src/state_machine.rs +++ b/system/gd/rust/linux/mgmt/src/state_machine.rs @@ -31,19 +31,26 @@ pub const RESET_ON_RESTART_COUNT: i32 = 2; /// the socket. pub const INDEX_REMOVED_DEBOUNCE_TIME: Duration = Duration::from_millis(150); +/// Period to check the PID existence. Ideally adapter should clean up the PID +/// file by itself and uses it as the stopped signal. This is a backup mechanism +/// to avoid dead process + PID not cleaned up from happening. +pub const PID_RUNNING_CHECK_PERIOD: Duration = Duration::from_secs(60); + #[derive(Debug, PartialEq, Copy, Clone)] #[repr(u32)] pub enum ProcessState { - Off = 0, // Bluetooth is not running or is not available. - TurningOn = 1, // We are not notified that the Bluetooth is running - On = 2, // Bluetooth is running - TurningOff = 3, // We are not notified that the Bluetooth is stopped + Off = 0, // Bluetooth is not running or is not available. + TurningOn = 1, // We are not notified that the Bluetooth is running + On = 2, // Bluetooth is running + TurningOff = 3, // We are not notified that the Bluetooth is stopped + PendingRestart = 4, // Bluetooth is turning on and will be restarted after started + Restarting = 5, // Bluetooth is turning off and will be started after stopped } /// Check whether adapter is enabled by checking internal state. pub fn state_to_enabled(state: ProcessState) -> bool { match state { - ProcessState::On => true, + ProcessState::On | ProcessState::TurningOff => true, _ => false, } } @@ -67,7 +74,7 @@ impl VirtualHciIndex { } impl Display for VirtualHciIndex { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - self.0.fmt(f) + write!(f, "VirtHci{}", self.0) } } @@ -81,7 +88,7 @@ impl RealHciIndex { } impl Display for RealHciIndex { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - self.0.fmt(f) + write!(f, "RealHci{}", self.0) } } @@ -90,8 +97,9 @@ impl Display for RealHciIndex { pub enum AdapterStateActions { StartBluetooth(VirtualHciIndex), StopBluetooth(VirtualHciIndex), - BluetoothStarted(i32, RealHciIndex), // PID and HCI - BluetoothStopped(RealHciIndex), + RestartBluetooth(VirtualHciIndex), + BluetoothStarted(i32, VirtualHciIndex), // PID and HCI + BluetoothStopped(VirtualHciIndex), HciDevicePresence(DevPath, RealHciIndex, bool), } @@ -133,7 +141,7 @@ impl StateMachineContext { /// `invoker` - What type of process manager to use. pub fn create_new_state_machine_context(invoker: Invoker) -> StateMachineContext { let floss_enabled = config_util::is_floss_enabled(); - let desired_adapter = VirtualHciIndex(config_util::get_default_adapter()); + let desired_adapter = config_util::get_default_adapter(); let process_manager = StateMachineInternal::make_process_manager(invoker); StateMachineContext::new(StateMachineInternal::new( @@ -186,6 +194,15 @@ impl StateMachineProxy { }); } + pub fn restart_bluetooth(&self, hci: VirtualHciIndex) { + let tx = self.tx.clone(); + tokio::spawn(async move { + let _ = tx + .send(Message::AdapterStateChange(AdapterStateActions::RestartBluetooth(hci))) + .await; + }); + } + /// Read state for an hci device. pub fn get_state(&self, hci: VirtualHciIndex, call: F) -> Option where @@ -228,6 +245,10 @@ impl StateMachineProxy { self.floss_enabled.swap(enabled, Ordering::Relaxed) } + pub fn get_adapters(&self) -> Vec { + self.state.lock().unwrap().iter().map(|(_, a)| a.clone()).collect::>() + } + pub fn get_valid_adapters(&self) -> Vec { self.state .lock() @@ -262,9 +283,9 @@ fn pid_inotify_async_fd() -> AsyncFd { } /// Given an pid path, returns the adapter index for that pid path. -fn get_hci_index_from_pid_path(path: &str) -> Option { +fn get_hci_index_from_pid_path(path: &str) -> Option { let re = Regex::new(r"bluetooth([0-9]+).pid").unwrap(); - re.captures(path)?.get(1)?.as_str().parse().ok().map(|v| RealHciIndex(v)) + re.captures(path)?.get(1)?.as_str().parse().ok().map(|v| VirtualHciIndex(v)) } fn event_name_to_string(name: Option<&std::ffi::OsStr>) -> Option { @@ -324,30 +345,9 @@ fn configure_pid(pid_tx: mpsc::Sender) { }); } -async fn start_hci_if_floss_enabled(hci: u16, floss_enabled: bool, tx: mpsc::Sender) { - // Initialize adapter states based on saved config only if floss is enabled. - if floss_enabled { - let is_enabled = config_util::is_hci_n_enabled(hci.into()); - debug!("Start hci {}: floss={}, enabled={}", hci, floss_enabled, is_enabled); - - if is_enabled { - // Sent on start-up so we can assume VirtualIndex == RealIndex. - let _ = tx - .send_timeout( - Message::AdapterStateChange(AdapterStateActions::StartBluetooth( - VirtualHciIndex(hci.into()), - )), - TX_SEND_TIMEOUT_DURATION, - ) - .await - .unwrap(); - } - } -} - // Configure the HCI socket listener and prepare the system to receive mgmt events for index added // and index removed. -fn configure_hci(hci_tx: mpsc::Sender, floss_enabled: bool) { +fn configure_hci(hci_tx: mpsc::Sender) { let mut btsock = BtSocket::new(); // If the bluetooth socket isn't available, the kernel module is not loaded and we can't @@ -415,64 +415,52 @@ fn configure_hci(hci_tx: mpsc::Sender, floss_enabled: bool) { } = response { for hci in interfaces { + let hci = RealHciIndex(hci.into()); debug!("IndexList response: {}", hci); - // We need devpath for an index or we don't use it. - let devpath = - match config_util::get_devpath_for_hci(hci.into()) { - Some(d) => d, - None => { - error!("Could not get devpath for {}", hci); - continue; - } - }; - - let _ = hci_tx - .send_timeout( - Message::AdapterStateChange( - AdapterStateActions::HciDevicePresence( - devpath.clone(), - RealHciIndex(hci.into()), - true, + if let Some(d) = config_util::get_devpath_for_hci(hci) { + let _ = hci_tx + .send_timeout( + Message::AdapterStateChange( + AdapterStateActions::HciDevicePresence( + d, hci, true, + ), ), - ), - TX_SEND_TIMEOUT_DURATION, - ) - .await - .unwrap(); - - // With a list of initial hci devices, make sure to - // enable them if they were previously enabled and we - // are using floss. - start_hci_if_floss_enabled( - hci.into(), - floss_enabled, - hci_tx.clone(), - ) - .await; + TX_SEND_TIMEOUT_DURATION, + ) + .await + .unwrap(); + } else { + error!("IndexList: Could not get devpath for {}", hci); + } } } } MgmtEvent::IndexAdded(hci) => { - let devpath = config_util::get_devpath_for_hci(hci.into()); - if let Some(d) = devpath { + let hci = RealHciIndex(hci.into()); + debug!("IndexAdded: {}", hci); + // We need devpath for an index or we don't use it. + if let Some(d) = config_util::get_devpath_for_hci(hci) { let _ = hci_tx .send_timeout( Message::AdapterStateChange( AdapterStateActions::HciDevicePresence( - d, - RealHciIndex(hci.into()), - true, + d, hci, true, ), ), TX_SEND_TIMEOUT_DURATION, ) .await .unwrap(); + } else { + error!("IndexAdded: Could not get devpath for {}", hci); } } MgmtEvent::IndexRemoved(hci) => { - let devpath = config_util::get_devpath_for_hci(hci.into()); + let hci = RealHciIndex(hci.into()); + debug!("IndexRemoved: {}", hci); + let devpath = + config_util::get_devpath_for_hci(hci).unwrap_or(String::new()); // Only send presence removed if the device is removed // and not when userchannel takes exclusive access. This needs to // be delayed a bit for when the socket legitimately disappears as @@ -484,14 +472,12 @@ fn configure_hci(hci_tx: mpsc::Sender, floss_enabled: bool) { let txl = hci_tx.clone(); tokio::spawn(async move { tokio::time::sleep(INDEX_REMOVED_DEBOUNCE_TIME).await; - if !config_util::check_hci_device_exists(hci.into()) { + if !config_util::check_hci_device_exists(hci) { let _ = txl .send_timeout( Message::AdapterStateChange( AdapterStateActions::HciDevicePresence( - devpath.unwrap_or(String::new()), - RealHciIndex(hci.into()), - false, + devpath, hci, false, ), ), TX_SEND_TIMEOUT_DURATION, @@ -615,7 +601,7 @@ pub async fn mainloop( // Set up an HCI device listener to emit HCI device inotify messages. // This is also responsible for configuring the initial list of HCI devices available on the // system. - configure_hci(context.tx.clone(), context.get_proxy().get_floss_enabled()); + configure_hci(context.tx.clone()); configure_pid(context.tx.clone()); // Listen for all messages and act on them @@ -623,7 +609,7 @@ pub async fn mainloop( let m = context.rx.recv().await; if m.is_none() { - info!("Exiting manager mainloop"); + warn!("Exiting manager mainloop"); break; } @@ -631,55 +617,60 @@ pub async fn mainloop( match m.unwrap() { // Adapter action has changed - Message::AdapterStateChange(action) => { + Message::AdapterStateChange(adapter_action) => { // Grab previous state from lock and release let hci: VirtualHciIndex; let next_state; let prev_state; - match &action { + match &adapter_action { AdapterStateActions::StartBluetooth(i) => { hci = *i; prev_state = context.state_machine.get_process_state(hci); - next_state = ProcessState::TurningOn; - let action = context.state_machine.action_start_bluetooth(hci); + let action; + (next_state, action) = context.state_machine.action_start_bluetooth(hci); cmd_timeout.lock().unwrap().handle_timeout_action(hci, action); } AdapterStateActions::StopBluetooth(i) => { hci = *i; prev_state = context.state_machine.get_process_state(hci); - next_state = ProcessState::TurningOff; - let action = context.state_machine.action_stop_bluetooth(hci); + let action; + (next_state, action) = context.state_machine.action_stop_bluetooth(hci); cmd_timeout.lock().unwrap().handle_timeout_action(hci, action); } - AdapterStateActions::BluetoothStarted(pid, real_hci) => { - hci = match context.state_machine.get_virtual_id_by_real_id(*real_hci) { - Some(v) => v, - None => context.state_machine.get_next_virtual_id( - *real_hci, - config_util::get_devpath_for_hci(real_hci.to_i32()), - ), - }; + AdapterStateActions::RestartBluetooth(i) => { + hci = *i; prev_state = context.state_machine.get_process_state(hci); - next_state = ProcessState::On; - let action = context.state_machine.action_on_bluetooth_started(*pid, hci); + let action; + (next_state, action) = context.state_machine.action_restart_bluetooth(hci); cmd_timeout.lock().unwrap().handle_timeout_action(hci, action); } - AdapterStateActions::BluetoothStopped(real_hci) => { - hci = match context.state_machine.get_virtual_id_by_real_id(*real_hci) { - Some(v) => v, - None => context.state_machine.get_next_virtual_id( - *real_hci, - config_util::get_devpath_for_hci(real_hci.to_i32()), - ), - }; + AdapterStateActions::BluetoothStarted(pid, i) => { + hci = *i; prev_state = context.state_machine.get_process_state(hci); - next_state = ProcessState::Off; - let action = context.state_machine.action_on_bluetooth_stopped(hci); + let action; + (next_state, action) = + context.state_machine.action_on_bluetooth_started(*pid, hci); + cmd_timeout.lock().unwrap().handle_timeout_action(hci, action); + + if context.state_machine.has_queued_present(hci) { + context.state_machine.modify_state(hci, |a: &mut AdapterState| { + a.has_queued_present = false; + }); + bluetooth_manager.lock().unwrap().callback_hci_device_change(hci, true); + } + } + AdapterStateActions::BluetoothStopped(i) => { + hci = *i; + prev_state = context.state_machine.get_process_state(hci); + + let action; + (next_state, action) = + context.state_machine.action_on_bluetooth_stopped(hci); cmd_timeout.lock().unwrap().handle_timeout_action(hci, action); } @@ -695,6 +686,13 @@ pub async fn mainloop( }; hci = context.state_machine.get_updated_virtual_id(devpath.clone(), *i); + // If this is really a new hci device, load the enabled state from the disk. + if previous_real_hci.is_none() { + context.state_machine.modify_state(hci, |a: &mut AdapterState| { + a.config_enabled = config_util::is_hci_n_enabled(hci); + }); + } + // If the real hci changed, we need to set the previous present to the // opposite of the current present so that we don't no-op the action. if previous_real_hci.is_some() @@ -709,10 +707,23 @@ pub async fn mainloop( } prev_state = context.state_machine.get_process_state(hci); + + // Don't bother the clients if presence is unchanged. But still execute the + // state machine here in case there is anything else to be done (e.g., + // verify the next state). + let presence_changed = *present + != context + .state_machine + .get_state(hci, |a: &AdapterState| Some(a.present)) + .unwrap_or(false); + let adapter_change_action; - (next_state, adapter_change_action) = + let timeout_action; + (next_state, adapter_change_action, timeout_action) = context.state_machine.action_on_hci_presence_changed(hci, *present); + cmd_timeout.lock().unwrap().handle_timeout_action(hci, timeout_action); + match adapter_change_action { AdapterChangeAction::NewDefaultAdapter(new_hci) => { context @@ -722,32 +733,48 @@ pub async fn mainloop( bluetooth_manager .lock() .unwrap() - .callback_default_adapter_change(new_hci.to_i32()); + .callback_default_adapter_change(new_hci); } AdapterChangeAction::DoNothing => (), }; - bluetooth_manager - .lock() - .unwrap() - .callback_hci_device_change(hci.to_i32(), *present); + if presence_changed { + // If present switched to true and we're turning on the adapter, + // defer the callback until the next BluetoothStarted or CommandTimeout + // so the clients won't get an unexpected state change after present. + let queue_present = *present && next_state == ProcessState::TurningOn; + + // Always modify_state to make sure it's reset on queue_present=false, + // e.g., when a hci is removed while its presence is still queued. + context.state_machine.modify_state(hci, |a: &mut AdapterState| { + a.has_queued_present = queue_present; + }); + + if !queue_present { + bluetooth_manager + .lock() + .unwrap() + .callback_hci_device_change(hci, *present); + } + } } }; - debug!( - "[hci{}]: Took action {:?} with prev_state({:?}) and next_state({:?})", - hci, action, prev_state, next_state + // All actions and the resulting state changes should be logged for debugging. + info!( + "{}: Action={:?}, Previous State({:?}), Next State({:?})", + hci, adapter_action, prev_state, next_state ); // Only emit enabled event for certain transitions - if next_state != prev_state - && (next_state == ProcessState::On || prev_state == ProcessState::On) - { + let prev_enabled = state_to_enabled(prev_state); + let next_enabled = state_to_enabled(next_state); + if prev_enabled != next_enabled { bluetooth_manager .lock() .unwrap() - .callback_hci_enabled_change(hci.to_i32(), next_state == ProcessState::On); + .callback_hci_enabled_change(hci, next_enabled); } } @@ -755,13 +782,16 @@ pub async fn mainloop( Message::PidChange(mask, filename) => match (mask, &filename) { (inotify::EventMask::CREATE, Some(fname)) => { let path = std::path::Path::new(PID_DIR).join(&fname); - match (get_hci_index_from_pid_path(&fname), tokio::fs::read(path).await.ok()) { + match ( + get_hci_index_from_pid_path(&fname), + tokio::fs::read(path.clone()).await.ok(), + ) { (Some(hci), Some(s)) => { let pid = String::from_utf8(s) .expect("invalid pid file") .parse::() .unwrap_or(0); - debug!("Sending bluetooth started action for pid={}, hci={}", pid, hci); + debug!("Sending bluetooth started action for {}, pid={}", hci, pid); let _ = context .tx .send_timeout( @@ -772,13 +802,52 @@ pub async fn mainloop( ) .await .unwrap(); + let handle = tokio::spawn(async move { + debug!("{}: Spawned process monitor", hci); + loop { + tokio::time::sleep(PID_RUNNING_CHECK_PERIOD).await; + // Check if process exists by sending kill -0. + match nix::sys::signal::kill(Pid::from_raw(pid), None) { + Err(nix::errno::Errno::ESRCH) => { + warn!("{}: Process died; Removing PID file", hci); + if let Err(e) = std::fs::remove_file(path) { + warn!("{}: Failed to remove: {}", hci, e); + } + break; + } + Err(e) => { + // Other errno should rarely happen: + // EINVAL: The value of the sig argument is an invalid + // or unsupported signal number. + // EPERM: The process does not have permission to send + // the signal to any receiving process. + error!("{}: Failed to send signal: {}", hci, e); + break; + } + _ => {} + } + } + }); + match context + .state_machine + .process_monitor + .lock() + .unwrap() + .insert(fname.clone(), handle) + { + Some(handle) => { + warn!("{}: Aborting old handler", hci); + handle.abort(); + } + None => {} + } } _ => debug!("Invalid pid path: {}", fname), } } (inotify::EventMask::DELETE, Some(fname)) => { if let Some(hci) = get_hci_index_from_pid_path(&fname) { - debug!("Sending bluetooth stopped action for hci={}", hci); + debug!("Sending bluetooth stopped action for {}", hci); context .tx .send_timeout( @@ -789,6 +858,12 @@ pub async fn mainloop( ) .await .unwrap(); + match context.state_machine.process_monitor.lock().unwrap().remove(fname) { + Some(handle) => handle.abort(), + None => { + warn!("{}: Process exited but process monitor not found", hci) + } + } } } _ => debug!("Ignored event {:?} - {:?}", mask, &filename), @@ -802,7 +877,7 @@ pub async fn mainloop( // Handle command timeouts Message::CommandTimeout(hci) => { debug!( - "Expired action on hci{:?} state{:?}", + "{}: Expired action, state={:?}", hci, context.state_machine.get_process_state(hci) ); @@ -811,6 +886,13 @@ pub async fn mainloop( StateMachineTimeoutActions::Noop => (), _ => cmd_timeout.lock().unwrap().set_next(hci), } + + if context.state_machine.has_queued_present(hci) { + context.state_machine.modify_state(hci, |a: &mut AdapterState| { + a.has_queued_present = false; + }); + bluetooth_manager.lock().unwrap().callback_hci_device_change(hci, true); + } } Message::SetDesiredDefaultAdapter(hci) => { @@ -821,10 +903,7 @@ pub async fn mainloop( .state_machine .default_adapter .store(new_hci.to_i32(), Ordering::Relaxed); - bluetooth_manager - .lock() - .unwrap() - .callback_default_adapter_change(new_hci.to_i32()); + bluetooth_manager.lock().unwrap().callback_default_adapter_change(new_hci); } AdapterChangeAction::DoNothing => (), } @@ -842,14 +921,14 @@ pub trait ProcessManager { /// * `virtual_hci` - Virtual index of adapter used for apis. /// * `real_hci` - Real index of the adapter on the system. This can /// change during a single boot. - fn start(&mut self, virtual_hci: String, real_hci: String); + fn start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex); /// Stop the adapter process. /// /// # Args /// * `virtual_hci` - Virtual index of adapter used for apis. /// * `real_hci` - Real index of the adapter on the system. - fn stop(&mut self, virtual_hci: String, real_hci: String); + fn stop(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex); } pub enum Invoker { @@ -871,16 +950,16 @@ impl NativeInvoker { } impl ProcessManager for NativeInvoker { - fn start(&mut self, virtual_hci: String, real_hci: String) { + fn start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) { let new_process = Command::new("/usr/bin/btadapterd") - .arg(format!("INDEX={} HCI={}", virtual_hci, real_hci)) + .arg(format!("INDEX={} HCI={}", virtual_hci.to_i32(), real_hci.to_i32())) .stdout(Stdio::piped()) .spawn() .expect("cannot open"); self.bluetooth_pid = new_process.id(); self.process_container = Some(new_process); } - fn stop(&mut self, _virtual_hci: String, _real_hci: String) { + fn stop(&mut self, _virtual_hci: VirtualHciIndex, _real_hci: RealHciIndex) { match self.process_container { Some(ref mut _p) => { signal::kill(Pid::from_raw(self.bluetooth_pid as i32), Signal::SIGTERM).unwrap(); @@ -902,13 +981,13 @@ impl UpstartInvoker { } impl ProcessManager for UpstartInvoker { - fn start(&mut self, virtual_hci: String, real_hci: String) { + fn start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) { if let Err(e) = Command::new("initctl") .args(&[ "start", "btadapterd", - format!("INDEX={}", virtual_hci).as_str(), - format!("HCI={}", real_hci).as_str(), + format!("INDEX={}", virtual_hci.to_i32()).as_str(), + format!("HCI={}", real_hci.to_i32()).as_str(), ]) .output() { @@ -916,13 +995,13 @@ impl ProcessManager for UpstartInvoker { } } - fn stop(&mut self, virtual_hci: String, real_hci: String) { + fn stop(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) { if let Err(e) = Command::new("initctl") .args(&[ "stop", "btadapterd", - format!("INDEX={}", virtual_hci).as_str(), - format!("HCI={}", real_hci).as_str(), + format!("INDEX={}", virtual_hci.to_i32()).as_str(), + format!("HCI={}", real_hci.to_i32()).as_str(), ]) .output() { @@ -940,16 +1019,24 @@ impl SystemdInvoker { } impl ProcessManager for SystemdInvoker { - fn start(&mut self, virtual_hci: String, real_hci: String) { + fn start(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) { Command::new("systemctl") - .args(&["restart", format!("btadapterd@{}_{}.service", virtual_hci, real_hci).as_str()]) + .args(&[ + "restart", + format!("btadapterd@{}_{}.service", virtual_hci.to_i32(), real_hci.to_i32()) + .as_str(), + ]) .output() .expect("failed to start bluetooth"); } - fn stop(&mut self, virtual_hci: String, real_hci: String) { + fn stop(&mut self, virtual_hci: VirtualHciIndex, real_hci: RealHciIndex) { Command::new("systemctl") - .args(&["stop", format!("btadapterd@{}_{}.service", virtual_hci, real_hci).as_str()]) + .args(&[ + "stop", + format!("btadapterd@{}_{}.service", virtual_hci.to_i32(), real_hci.to_i32()) + .as_str(), + ]) .output() .expect("failed to stop bluetooth"); } @@ -979,6 +1066,9 @@ pub struct AdapterState { /// Whether this hci device is listed as present. pub present: bool, + /// Whether the 'present' notification is being deferred until adapter is ready. + pub has_queued_present: bool, + /// Whether this hci device is configured to be enabled. pub config_enabled: bool, @@ -994,6 +1084,7 @@ impl AdapterState { real_hci, virt_hci, present: false, + has_queued_present: false, config_enabled: false, pid: 0, restart_count: 0, @@ -1016,6 +1107,9 @@ struct StateMachineInternal { /// we depend on ordering for |get_lowest_available_adapter|. state: Arc>>, + /// Trace the process existence for each pid file and clean it up if needed. + process_monitor: Arc>>>, + /// Process manager implementation. process_manager: Box, } @@ -1053,6 +1147,7 @@ impl StateMachineInternal { default_adapter: Arc::new(AtomicI32::new(desired_adapter.to_i32())), desired_adapter, state: Arc::new(Mutex::new(BTreeMap::new())), + process_monitor: Arc::new(Mutex::new(HashMap::new())), process_manager: process_manager, } } @@ -1198,6 +1293,10 @@ impl StateMachineInternal { }); } + fn has_queued_present(&self, hci: VirtualHciIndex) -> bool { + self.get_state(hci, |a: &AdapterState| Some(a.has_queued_present)).unwrap_or(false) + } + fn get_process_state(&self, hci: VirtualHciIndex) -> ProcessState { self.get_state(hci, move |a: &AdapterState| Some(a.state)).unwrap_or(ProcessState::Off) } @@ -1226,8 +1325,8 @@ impl StateMachineInternal { /// Attempt to reset an hci device. Always set the state to ProcessState::Stopped /// as we expect this device to disappear and reappear. fn reset_hci(&mut self, hci: RealHciIndex) { - if !config_util::reset_hci_device(hci.to_i32()) { - error!("Attempted reset recovery of hci{} and failed.", hci.to_i32()); + if !config_util::reset_hci_device(hci) { + error!("Attempted reset recovery of {} and failed.", hci); } } @@ -1243,8 +1342,9 @@ impl StateMachineInternal { .next() } - /// Set the desired default adapter. Returns true if the default adapter was changed as result - /// (meaning the newly desired adapter is either present or enabled). + /// Set the desired default adapter. Returns a NewDefaultAdapter action if the default + /// adapter was changed as a result (meaning the newly desired adapter is either present or + /// enabled). pub fn set_desired_default_adapter(&mut self, adapter: VirtualHciIndex) -> AdapterChangeAction { self.desired_adapter = adapter; @@ -1261,8 +1361,11 @@ impl StateMachineInternal { return AdapterChangeAction::DoNothing; } - /// Returns true if we are starting bluetooth process. - pub fn action_start_bluetooth(&mut self, hci: VirtualHciIndex) -> CommandTimeoutAction { + /// Returns the next state and an action to reset timer if we are starting bluetooth process. + pub fn action_start_bluetooth( + &mut self, + hci: VirtualHciIndex, + ) -> (ProcessState, CommandTimeoutAction) { let state = self.get_process_state(hci); let present = self.get_state(hci, move |a: &AdapterState| Some(a.present)).unwrap_or(false); let floss_enabled = self.get_floss_enabled(); @@ -1275,64 +1378,112 @@ impl StateMachineInternal { self.modify_state(hci, move |s: &mut AdapterState| { s.state = ProcessState::TurningOn }); - self.process_manager - .start(hci.to_string(), self.get_real_hci_by_virtual_id(hci).to_string()); - CommandTimeoutAction::ResetTimer + self.process_manager.start(hci, self.get_real_hci_by_virtual_id(hci)); + (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer) } - // Otherwise no op - _ => CommandTimeoutAction::DoNothing, + // Otherwise (enabled states) no op + _ => (state, CommandTimeoutAction::DoNothing), } } - /// Returns true if we are stopping bluetooth process. - pub fn action_stop_bluetooth(&mut self, hci: VirtualHciIndex) -> CommandTimeoutAction { + /// Returns the next state and an action to reset or cancel timer if we are stopping bluetooth + /// process. + pub fn action_stop_bluetooth( + &mut self, + hci: VirtualHciIndex, + ) -> (ProcessState, CommandTimeoutAction) { if !self.is_known(hci) { - warn!("Attempting to stop unknown hci{}", hci.to_i32()); - return CommandTimeoutAction::DoNothing; + warn!("Attempting to stop unknown device {}", hci); + return (ProcessState::Off, CommandTimeoutAction::DoNothing); } let state = self.get_process_state(hci); match state { - ProcessState::On => { + // If adapter is turning off and we get another stop request, we should just + // repeat the same action which resets the timeout mechanism. + ProcessState::On | ProcessState::TurningOff => { self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::TurningOff); - self.process_manager - .stop(hci.to_string(), self.get_real_hci_by_virtual_id(hci).to_string()); - CommandTimeoutAction::ResetTimer + self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci)); + (ProcessState::TurningOff, CommandTimeoutAction::ResetTimer) } - ProcessState::TurningOn => { - self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off); - self.process_manager - .stop(hci.to_string(), self.get_real_hci_by_virtual_id(hci).to_string()); - CommandTimeoutAction::CancelTimer + // Otherwise (disabled states) no op + _ => (state, CommandTimeoutAction::DoNothing), + } + } + + /// Returns the next state and an action to reset timer if we are restarting bluetooth process. + /// This action aims to make sure the configuration is reloaded. Only TurningOn/On states are + /// affected. + pub fn action_restart_bluetooth( + &mut self, + hci: VirtualHciIndex, + ) -> (ProcessState, CommandTimeoutAction) { + if !self.is_known(hci) { + warn!("Attempting to restart unknown device {}", hci); + return (ProcessState::Off, CommandTimeoutAction::DoNothing); + } + + let state = self.get_process_state(hci); + let present = self.get_state(hci, move |a: &AdapterState| Some(a.present)).unwrap_or(false); + let floss_enabled = self.get_floss_enabled(); + + match state { + ProcessState::On if present && floss_enabled => { + self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Restarting); + self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci)); + (ProcessState::Restarting, CommandTimeoutAction::ResetTimer) } - // Otherwise no op - _ => CommandTimeoutAction::DoNothing, + ProcessState::TurningOn if present && floss_enabled => { + self.modify_state(hci, |s: &mut AdapterState| { + s.state = ProcessState::PendingRestart + }); + (ProcessState::PendingRestart, CommandTimeoutAction::DoNothing) + } + _ => (state, CommandTimeoutAction::DoNothing), } } - /// Handles a bluetooth started event. Always returns true even with unknown interfaces. + /// Returns the next state and an action. Except a restart is pending, + /// always return the action to cancel timer even with unknown interfaces. pub fn action_on_bluetooth_started( &mut self, pid: i32, hci: VirtualHciIndex, - ) -> CommandTimeoutAction { + ) -> (ProcessState, CommandTimeoutAction) { if !self.is_known(hci) { - warn!("Unknown hci{} is started; capturing that process", hci.to_i32()); + warn!("Unknown device {} is started; capturing that process", hci); self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off); } + let state = self.get_process_state(hci); + let present = self.get_state(hci, move |a: &AdapterState| Some(a.present)).unwrap_or(false); + let floss_enabled = self.get_floss_enabled(); + + if state == ProcessState::PendingRestart && present && floss_enabled { + self.modify_state(hci, |s: &mut AdapterState| { + s.state = ProcessState::Restarting; + s.restart_count = 0; + s.pid = pid; + }); + self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci)); + return (ProcessState::Restarting, CommandTimeoutAction::ResetTimer); + } + self.modify_state(hci, |s: &mut AdapterState| { s.state = ProcessState::On; s.restart_count = 0; s.pid = pid; }); - - CommandTimeoutAction::CancelTimer + (ProcessState::On, CommandTimeoutAction::CancelTimer) } - /// Returns true if the event is expected. - /// If unexpected, Bluetooth probably crashed, returning false and starting the timer for restart timeout. - pub fn action_on_bluetooth_stopped(&mut self, hci: VirtualHciIndex) -> CommandTimeoutAction { + /// Returns the next state and an action to cancel (turned off) or reset timer (restarting). + /// If unexpected, Bluetooth probably crashed, returns an action to reset the timer to restart + /// timeout. + pub fn action_on_bluetooth_stopped( + &mut self, + hci: VirtualHciIndex, + ) -> (ProcessState, CommandTimeoutAction) { let state = self.get_process_state(hci); let (present, config_enabled) = self .get_state(hci, move |a: &AdapterState| Some((a.present, a.config_enabled))) @@ -1343,7 +1494,12 @@ impl StateMachineInternal { // Normal shut down behavior. ProcessState::TurningOff => { self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off); - CommandTimeoutAction::CancelTimer + (ProcessState::Off, CommandTimeoutAction::CancelTimer) + } + ProcessState::Restarting if floss_enabled && config_enabled => { + self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::TurningOn); + self.process_manager.start(hci, self.get_real_hci_by_virtual_id(hci)); + (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer) } // Running bluetooth stopped unexpectedly. ProcessState::On if floss_enabled && config_enabled => { @@ -1354,9 +1510,8 @@ impl StateMachineInternal { // of retrying a start. if restart_count >= RESET_ON_RESTART_COUNT { warn!( - "hci{} stopped unexpectedly. After {} restarts, trying a reset recovery.", - hci.to_i32(), - restart_count + "{} stopped unexpectedly. After {} restarts, trying a reset recovery.", + hci, restart_count ); // Reset the restart count since we're attempting a reset now. self.modify_state(hci, |s: &mut AdapterState| { @@ -1367,36 +1522,33 @@ impl StateMachineInternal { .get_state(hci, |a: &AdapterState| Some(a.real_hci)) .unwrap_or(RealHciIndex(hci.to_i32())); self.reset_hci(real_hci); - CommandTimeoutAction::CancelTimer + (ProcessState::Off, CommandTimeoutAction::CancelTimer) } else { warn!( - "hci{} stopped unexpectedly, try restarting (attempt #{})", - hci.to_i32(), + "{} stopped unexpectedly, try restarting (attempt #{})", + hci, restart_count + 1 ); self.modify_state(hci, |s: &mut AdapterState| { s.state = ProcessState::TurningOn; s.restart_count = s.restart_count + 1; }); - self.process_manager - .start(hci.to_string(), self.get_real_hci_by_virtual_id(hci).to_string()); - CommandTimeoutAction::ResetTimer + self.process_manager.start(hci, self.get_real_hci_by_virtual_id(hci)); + (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer) } } - ProcessState::On | ProcessState::TurningOn | ProcessState::Off => { + _ => { warn!( - "hci{} stopped unexpectedly from {:?}. Adapter present? {}", - hci.to_i32(), - state, - present + "{} stopped unexpectedly from {:?}. Adapter present={}, Floss enabled={}", + hci, state, present, floss_enabled ); self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off); - CommandTimeoutAction::CancelTimer + (ProcessState::Off, CommandTimeoutAction::CancelTimer) } } } - /// Triggered on Bluetooth start/stop timeout. Return the actions that the + /// Triggered on Bluetooth start/stop timeout. Return the actions that the /// state machine has taken, for the external context to reset the timer. pub fn action_on_command_timeout( &mut self, @@ -1411,16 +1563,15 @@ impl StateMachineInternal { match state { // If Floss is not enabled, just send |Stop| to process manager and end the state // machine actions. - ProcessState::TurningOn if !floss_enabled => { - info!("Timed out turning on but floss is disabled: {}", hci); + ProcessState::TurningOn | ProcessState::PendingRestart if !floss_enabled => { + warn!("{}: Timed out turning on but floss is disabled", hci); self.modify_state(hci, |s: &mut AdapterState| s.state = ProcessState::Off); - self.process_manager - .stop(hci.to_string(), self.get_real_hci_by_virtual_id(hci).to_string()); + self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci)); StateMachineTimeoutActions::Noop } // If turning on and hci is enabled, restart the process if we are below // the restart count. Otherwise, reset and mark turned off. - ProcessState::TurningOn if config_enabled => { + ProcessState::TurningOn | ProcessState::PendingRestart if config_enabled => { let restart_count = self.get_state(hci, |a: &AdapterState| Some(a.restart_count)).unwrap_or(0); @@ -1428,8 +1579,8 @@ impl StateMachineInternal { // of retrying a start. if restart_count >= RESET_ON_RESTART_COUNT { warn!( - "hci{} timed out while starting (present={}). After {} restarts, trying a reset recovery.", - hci.to_i32(), present, restart_count + "{} timed out while starting (present={}). After {} restarts, trying a reset recovery.", + hci, present, restart_count ); // Reset the restart count since we're attempting a reset now. self.modify_state(hci, |s: &mut AdapterState| { @@ -1443,8 +1594,8 @@ impl StateMachineInternal { StateMachineTimeoutActions::Noop } else { warn!( - "hci{} timed out while starting (present={}), try restarting (attempt #{})", - hci.to_i32(), + "{} timed out while starting (present={}), try restarting (attempt #{})", + hci, present, restart_count + 1 ); @@ -1452,17 +1603,14 @@ impl StateMachineInternal { s.state = ProcessState::TurningOn; s.restart_count = s.restart_count + 1; }); - self.process_manager - .stop(hci.to_string(), self.get_real_hci_by_virtual_id(hci).to_string()); - self.process_manager - .start(hci.to_string(), self.get_real_hci_by_virtual_id(hci).to_string()); + self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci)); + self.process_manager.start(hci, self.get_real_hci_by_virtual_id(hci)); StateMachineTimeoutActions::RetryStart } } - ProcessState::TurningOff => { + ProcessState::TurningOff | ProcessState::Restarting => { info!("Killing bluetooth {}", hci); - self.process_manager - .stop(hci.to_string(), self.get_real_hci_by_virtual_id(hci).to_string()); + self.process_manager.stop(hci, self.get_real_hci_by_virtual_id(hci)); StateMachineTimeoutActions::RetryStop } _ => StateMachineTimeoutActions::Noop, @@ -1479,19 +1627,19 @@ impl StateMachineInternal { &mut self, hci: VirtualHciIndex, present: bool, - ) -> (ProcessState, AdapterChangeAction) { + ) -> (ProcessState, AdapterChangeAction, CommandTimeoutAction) { let prev_present = self.get_state(hci, |a: &AdapterState| Some(a.present)).unwrap_or(false); let prev_state = self.get_process_state(hci); // No-op if same as previous present. if prev_present == present { - return (prev_state, AdapterChangeAction::DoNothing); + return (prev_state, AdapterChangeAction::DoNothing, CommandTimeoutAction::DoNothing); } self.modify_state(hci, |a: &mut AdapterState| a.present = present); let floss_enabled = self.get_floss_enabled(); - let next_state = + let (next_state, timeout_action) = match self.get_state(hci, |a: &AdapterState| Some((a.state, a.config_enabled))) { // Start the adapter if present, config is enabled and floss is enabled. Some((ProcessState::Off, true)) if floss_enabled && present => { @@ -1502,10 +1650,9 @@ impl StateMachineInternal { // Both should reset the restart count. self.modify_state(hci, |a: &mut AdapterState| a.restart_count = 0); - self.action_start_bluetooth(hci); - ProcessState::TurningOn + self.action_start_bluetooth(hci) } - _ => prev_state, + _ => (prev_state, CommandTimeoutAction::DoNothing), }; let default_adapter = VirtualHciIndex(self.default_adapter.load(Ordering::Relaxed)); @@ -1517,16 +1664,18 @@ impl StateMachineInternal { // 2) The current default adapter is no longer present or enabled. // * Switch to the lowest numbered adapter present or do nothing. // - return if present && hci == desired_adapter && hci != default_adapter { - (next_state, AdapterChangeAction::NewDefaultAdapter(desired_adapter)) + let adapter_change_action = if present && hci == desired_adapter && hci != default_adapter { + AdapterChangeAction::NewDefaultAdapter(desired_adapter) } else if !present && hci == default_adapter { match self.get_lowest_available_adapter() { - Some(v) => (next_state, AdapterChangeAction::NewDefaultAdapter(v)), - None => (next_state, AdapterChangeAction::DoNothing), + Some(v) => AdapterChangeAction::NewDefaultAdapter(v), + None => AdapterChangeAction::DoNothing, } } else { - (next_state, AdapterChangeAction::DoNothing) + AdapterChangeAction::DoNothing }; + + (next_state, adapter_change_action, timeout_action) } } @@ -1561,7 +1710,7 @@ mod tests { } impl ProcessManager for MockProcessManager { - fn start(&mut self, _virt: String, _real: String) { + fn start(&mut self, _virt: VirtualHciIndex, _real: RealHciIndex) { self.expectations.push(match self.last_command.pop_front() { Some(x) => { if x == ExecutedCommand::Start { @@ -1574,7 +1723,7 @@ mod tests { }); } - fn stop(&mut self, _virt: String, _real: String) { + fn stop(&mut self, _virt: VirtualHciIndex, _real: RealHciIndex) { self.expectations.push(match self.last_command.pop_front() { Some(x) => { if x == ExecutedCommand::Stop { @@ -1661,7 +1810,7 @@ mod tests { state_machine.action_start_bluetooth(DEFAULT_ADAPTER); assert_eq!( state_machine.action_start_bluetooth(DEFAULT_ADAPTER), - CommandTimeoutAction::ResetTimer + (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer) ); }) } @@ -1714,17 +1863,15 @@ mod tests { } #[test] - fn turningon_turnoff_should_turningoff_and_send_command() { + fn turningon_turnoff_should_noop() { tokio::runtime::Runtime::new().unwrap().block_on(async { let mut process_manager = MockProcessManager::new(); process_manager.expect_start(); - // Expect to send stop command - process_manager.expect_stop(); let mut state_machine = make_state_machine(process_manager); state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, true); state_machine.action_start_bluetooth(DEFAULT_ADAPTER); state_machine.action_stop_bluetooth(DEFAULT_ADAPTER); - assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off); + assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn); }) } @@ -1760,7 +1907,7 @@ mod tests { state_machine.action_on_bluetooth_started(0, DEFAULT_ADAPTER); assert_eq!( state_machine.action_on_bluetooth_stopped(DEFAULT_ADAPTER), - CommandTimeoutAction::ResetTimer + (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer) ); assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn); }); @@ -1779,7 +1926,7 @@ mod tests { state_machine.action_on_hci_presence_changed(DEFAULT_ADAPTER, false); assert_eq!( state_machine.action_on_bluetooth_stopped(DEFAULT_ADAPTER), - CommandTimeoutAction::ResetTimer + (ProcessState::TurningOn, CommandTimeoutAction::ResetTimer) ); assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::TurningOn); }); @@ -1795,7 +1942,7 @@ mod tests { state_machine.set_floss_enabled(false); assert_eq!( state_machine.action_on_bluetooth_stopped(DEFAULT_ADAPTER), - CommandTimeoutAction::CancelTimer + (ProcessState::Off, CommandTimeoutAction::CancelTimer) ); assert_eq!(state_machine.get_process_state(DEFAULT_ADAPTER), ProcessState::Off); }); @@ -1932,7 +2079,7 @@ mod tests { #[test] fn test_updated_virtual_id() { - let mut process_manager = MockProcessManager::new(); + let process_manager = MockProcessManager::new(); let mut state_machine = make_state_machine(process_manager); // Note: Test ordering matters here. When re-ordering, keep track of what @@ -2015,15 +2162,15 @@ mod tests { fn path_to_pid() { assert_eq!( get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth0.pid"), - Some(RealHciIndex(0)) + Some(VirtualHciIndex(0)) ); assert_eq!( get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth1.pid"), - Some(RealHciIndex(1)) + Some(VirtualHciIndex(1)) ); assert_eq!( get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth10.pid"), - Some(RealHciIndex(10)) + Some(VirtualHciIndex(10)) ); assert_eq!(get_hci_index_from_pid_path("/var/run/bluetooth/garbage"), None); } diff --git a/system/gd/rust/linux/service/Cargo.toml b/system/gd/rust/linux/service/Cargo.toml index 033b1349b658f8f6e505d3e5ee6f63d41ce0c4e1..a76a94b31aaef5f7ecbb13253655bd93c52f337b 100644 --- a/system/gd/rust/linux/service/Cargo.toml +++ b/system/gd/rust/linux/service/Cargo.toml @@ -19,7 +19,7 @@ lazy_static = "1.4" log = "0.4.14" nix = "0.23" num-traits = "0.2" -tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } +tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } [build-dependencies] pkg-config = "0.3.19" diff --git a/system/gd/rust/linux/service/README.md b/system/gd/rust/linux/service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6be82f1b921fe8edb07852ceb7a1399e89575439 --- /dev/null +++ b/system/gd/rust/linux/service/README.md @@ -0,0 +1,35 @@ +Floss +====== + +TODO: Fill in some more information about the Floss service + +# DBus API + +## Methods + +The Floss DBus API is created by Rust macro and the exact definition is spread +out across multiple source files. In general, you can find relevant information +in a few places: + +- Destination: this is always `org.chromium.bluetooth` +- Interface name: these are defined in each service's source file. For example, + `BatteryProviderManager` has a DBus definition in + `src/iface_battery_provider_manager.rs` and it's interface name is defined + above `impl IBatteryProviderManager for IBatteryProviderManagerDBus` + (`org.chromium.bluetooth.BatteryProviderManager`). +- Method name: these are also defined in the service source file, above the Rust + method implementation. Following the above example, just before the + `register_battery_provider` implementation is the declaration of its + corresponding DBus method (`RegisterBatteryProvider`) +- Object path: these are defined in `src/interface_manager.rs`. For most + services this is going to be `/org/chromium/bluetooth/hci{index}/{service}` + where `{index}` depends on which adapter is being used and `{service}` is + defined in `interface_manager.rs`. + +## Objects + +TODO: Explain the typical object structure + +## Full API + +TODO: List out all of the API diff --git a/system/gd/rust/linux/service/build.rs b/system/gd/rust/linux/service/build.rs index d505501cf36c35097c77ebe5cd0917ddad2babc3..1585a230befd490e2df093039979625a7197d6f3 100644 --- a/system/gd/rust/linux/service/build.rs +++ b/system/gd/rust/linux/service/build.rs @@ -13,8 +13,8 @@ fn main() { println!("cargo:rerun-if-changed={}", cxx_outdir.into_string().unwrap()); // A few dynamic links - println!("cargo:rustc-link-lib=dylib=flatbuffers"); - println!("cargo:rustc-link-lib=dylib=protobuf"); + Config::new().probe("flatbuffers").unwrap(); + Config::new().probe("protobuf").unwrap(); println!("cargo:rustc-link-lib=dylib=resolv"); // Clang requires -lc++ instead of -lstdc++ @@ -25,6 +25,7 @@ fn main() { Config::new().probe("libchrome").unwrap(); Config::new().probe("libmodp_b64").unwrap(); Config::new().probe("tinyxml2").unwrap(); + Config::new().probe("lc3").unwrap(); // Include ChromeOS-specific dependencies. if option_env!("TARGET_OS_VARIANT").unwrap_or("None").to_string() == "chromeos" { diff --git a/system/gd/rust/linux/service/src/iface_battery_manager.rs b/system/gd/rust/linux/service/src/iface_battery_manager.rs index 884e043e59a97aa5019e99d85e77efe74d056aef..cd813cd0b6b512278edad406eda9e0b90366caff 100644 --- a/system/gd/rust/linux/service/src/iface_battery_manager.rs +++ b/system/gd/rust/linux/service/src/iface_battery_manager.rs @@ -3,7 +3,7 @@ use btstack::RPCProxy; use dbus::arg::RefArg; use dbus::strings::Path; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter}; -use dbus_projection::{dbus_generated, DisconnectWatcher}; +use dbus_projection::prelude::*; use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust}; @@ -44,7 +44,7 @@ impl IBatteryManager for IBatteryManagerDBus { } #[dbus_method("UnregisterBatteryCallback")] - fn unregister_battery_callback(&mut self, callback_id: u32) { + fn unregister_battery_callback(&mut self, callback_id: u32) -> bool { dbus_generated!() } diff --git a/system/gd/rust/linux/service/src/iface_battery_provider_manager.rs b/system/gd/rust/linux/service/src/iface_battery_provider_manager.rs index f2ce28bd2bc9beb5e76da79bf1c9cfcd21c15592..a5d39eee5c8ad2a920094a619bb3ab6ed6ab0c5a 100644 --- a/system/gd/rust/linux/service/src/iface_battery_provider_manager.rs +++ b/system/gd/rust/linux/service/src/iface_battery_provider_manager.rs @@ -3,7 +3,7 @@ use btstack::battery_provider_manager::{IBatteryProviderCallback, IBatteryProvid use btstack::RPCProxy; use dbus::strings::Path; use dbus_macros::{dbus_method, dbus_proxy_obj, generate_dbus_exporter}; -use dbus_projection::{dbus_generated, DisconnectWatcher}; +use dbus_projection::prelude::*; use crate::dbus_arg::DBusArg; @@ -41,4 +41,9 @@ impl IBatteryProviderManager for IBatteryProviderManagerDBus { fn set_battery_info(&mut self, battery_provider_id: u32, battery_set: BatterySet) { dbus_generated!() } + + #[dbus_method("RemoveBatteryInfo")] + fn remove_battery_info(&mut self, battery_provider_id: u32, address: String, uuid: String) { + dbus_generated!() + } } diff --git a/system/gd/rust/linux/service/src/iface_bluetooth.rs b/system/gd/rust/linux/service/src/iface_bluetooth.rs index 720c869b411ff31639d471345ccbdc09f8ff0af5..6ed6ae99090ab337ffe00c5f77f282e279e974a3 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth.rs @@ -1,6 +1,6 @@ use bt_topshim::btif::{ - BtBondState, BtConnectionState, BtDeviceType, BtDiscMode, BtPropertyType, BtSspVariant, - BtStatus, BtTransport, Uuid, Uuid128Bit, + BtAddrType, BtBondState, BtConnectionState, BtDeviceType, BtDiscMode, BtPropertyType, + BtSspVariant, BtStatus, BtTransport, BtVendorProductInfo, Uuid, Uuid128Bit, }; use bt_topshim::profiles::socket::SocketType; use bt_topshim::profiles::ProfileConnectionState; @@ -29,8 +29,7 @@ use dbus::nonblock::SyncConnection; use dbus::strings::Path; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter}; -use dbus_projection::DisconnectWatcher; -use dbus_projection::{dbus_generated, impl_dbus_arg_enum, impl_dbus_arg_from_into}; +use dbus_projection::prelude::*; use num_traits::cast::{FromPrimitive, ToPrimitive}; @@ -57,6 +56,7 @@ impl_dbus_arg_from_into!(BtStatus, u32); /// A mixin of the several interfaces. The naming of the fields in the mixin must match /// what is listed in the `generate_dbus_exporter` invocation. +#[derive(Clone)] pub struct BluetoothMixin { pub adapter: Arc>>, pub qa: Arc>>, @@ -79,6 +79,14 @@ impl IBluetoothCallback for BluetoothCallbackDBus { fn on_adapter_property_changed(&mut self, prop: BtPropertyType) { dbus_generated!() } + #[dbus_method("OnDevicePropertiesChanged")] + fn on_device_properties_changed( + &mut self, + remote_device: BluetoothDevice, + props: Vec, + ) { + dbus_generated!() + } #[dbus_method("OnAddressChanged")] fn on_address_changed(&mut self, addr: String) { dbus_generated!() @@ -103,7 +111,10 @@ impl IBluetoothCallback for BluetoothCallbackDBus { fn on_discovering_changed(&mut self, discovering: bool) { dbus_generated!() } - #[dbus_method("OnSspRequest")] + #[dbus_method( + "OnSspRequest", + DBusLog::Enable(DBusLogOptions::LogAll, DBusLogVerbosity::Verbose) + )] fn on_ssp_request( &mut self, remote_device: BluetoothDevice, @@ -121,7 +132,10 @@ impl IBluetoothCallback for BluetoothCallbackDBus { fn on_pin_display(&mut self, remote_device: BluetoothDevice, pincode: String) { dbus_generated!() } - #[dbus_method("OnBondStateChanged")] + #[dbus_method( + "OnBondStateChanged", + DBusLog::Enable(DBusLogOptions::LogAll, DBusLogVerbosity::Verbose) + )] fn on_bond_state_changed(&mut self, status: u32, address: String, state: u32) { dbus_generated!() } @@ -143,6 +157,7 @@ impl IBluetoothCallback for BluetoothCallbackDBus { impl_dbus_arg_enum!(BtBondState); impl_dbus_arg_enum!(BtConnectionState); impl_dbus_arg_enum!(BtDeviceType); +impl_dbus_arg_enum!(BtAddrType); impl_dbus_arg_enum!(BtPropertyType); impl_dbus_arg_enum!(BtSspVariant); impl_dbus_arg_enum!(BtTransport); @@ -153,12 +168,18 @@ struct BluetoothConnectionCallbackDBus {} #[dbus_proxy_obj(BluetoothConnectionCallback, "org.chromium.bluetooth.BluetoothConnectionCallback")] impl IBluetoothConnectionCallback for BluetoothConnectionCallbackDBus { - #[dbus_method("OnDeviceConnected")] + #[dbus_method( + "OnDeviceConnected", + DBusLog::Enable(DBusLogOptions::LogAll, DBusLogVerbosity::Verbose) + )] fn on_device_connected(&mut self, remote_device: BluetoothDevice) { dbus_generated!() } - #[dbus_method("OnDeviceDisconnected")] + #[dbus_method( + "OnDeviceDisconnected", + DBusLog::Enable(DBusLogOptions::LogAll, DBusLogVerbosity::Verbose) + )] fn on_device_disconnected(&mut self, remote_device: BluetoothDevice) { dbus_generated!() } @@ -244,6 +265,14 @@ pub struct BtSdpMpsRecordDBus { supported_dependencies: SupportedDependencies, } +#[dbus_propmap(BtVendorProductInfo)] +pub struct BtVendorProductInfoDBus { + vendor_id_src: u8, + vendor_id: u16, + product_id: u16, + version: u16, +} + fn read_propmap_value( propmap: &dbus::arg::PropMap, key: &str, @@ -387,6 +416,10 @@ impl DBusArg for BtSdpRecord { } Ok(map) } + + fn log(record: &BtSdpRecord) -> String { + String::from(format!("{:?}", record)) + } } impl_dbus_arg_enum!(BtDiscMode); @@ -402,7 +435,12 @@ struct IBluetoothDBus {} )] impl IBluetooth for IBluetoothDBus { #[dbus_method("RegisterCallback")] - fn register_callback(&mut self, callback: Box) { + fn register_callback(&mut self, callback: Box) -> u32 { + dbus_generated!() + } + + #[dbus_method("UnregisterCallback")] + fn unregister_callback(&mut self, id: u32) -> bool { dbus_generated!() } @@ -419,28 +457,37 @@ impl IBluetooth for IBluetoothDBus { dbus_generated!() } + // Not exposed over D-Bus. The stack is automatically initialized when the daemon starts. + fn init(&mut self, _init_flags: Vec) -> bool { + dbus_generated!() + } + // Not exposed over D-Bus. The stack is automatically enabled when the daemon starts. fn enable(&mut self) -> bool { dbus_generated!() } // Not exposed over D-Bus. The stack is automatically disabled when the daemon exits. - // TODO(b/189495858): Handle shutdown properly when SIGTERM is received. fn disable(&mut self) -> bool { dbus_generated!() } - #[dbus_method("GetAddress")] + // Not exposed over D-Bus. The stack is automatically cleaned up when the daemon exits. + fn cleanup(&mut self) { + dbus_generated!() + } + + #[dbus_method("GetAddress", DBusLog::Disable)] fn get_address(&self) -> String { dbus_generated!() } - #[dbus_method("GetUuids")] + #[dbus_method("GetUuids", DBusLog::Disable)] fn get_uuids(&self) -> Vec { dbus_generated!() } - #[dbus_method("GetName")] + #[dbus_method("GetName", DBusLog::Disable)] fn get_name(&self) -> String { dbus_generated!() } @@ -450,7 +497,7 @@ impl IBluetooth for IBluetoothDBus { dbus_generated!() } - #[dbus_method("GetBluetoothClass")] + #[dbus_method("GetBluetoothClass", DBusLog::Disable)] fn get_bluetooth_class(&self) -> u32 { dbus_generated!() } @@ -460,12 +507,12 @@ impl IBluetooth for IBluetoothDBus { dbus_generated!() } - #[dbus_method("GetDiscoverable")] + #[dbus_method("GetDiscoverable", DBusLog::Disable)] fn get_discoverable(&self) -> bool { dbus_generated!() } - #[dbus_method("GetDiscoverableTimeout")] + #[dbus_method("GetDiscoverableTimeout", DBusLog::Disable)] fn get_discoverable_timeout(&self) -> u32 { dbus_generated!() } @@ -475,12 +522,12 @@ impl IBluetooth for IBluetoothDBus { dbus_generated!() } - #[dbus_method("IsMultiAdvertisementSupported")] + #[dbus_method("IsMultiAdvertisementSupported", DBusLog::Disable)] fn is_multi_advertisement_supported(&self) -> bool { dbus_generated!() } - #[dbus_method("IsLeExtendedAdvertisingSupported")] + #[dbus_method("IsLeExtendedAdvertisingSupported", DBusLog::Disable)] fn is_le_extended_advertising_supported(&self) -> bool { dbus_generated!() } @@ -495,12 +542,12 @@ impl IBluetooth for IBluetoothDBus { dbus_generated!() } - #[dbus_method("IsDiscovering")] + #[dbus_method("IsDiscovering", DBusLog::Disable)] fn is_discovering(&self) -> bool { dbus_generated!() } - #[dbus_method("GetDiscoveryEndMillis")] + #[dbus_method("GetDiscoveryEndMillis", DBusLog::Disable)] fn get_discovery_end_millis(&self) -> u64 { dbus_generated!() } @@ -511,21 +558,21 @@ impl IBluetooth for IBluetoothDBus { } #[dbus_method("CancelBondProcess")] - fn cancel_bond_process(&self, device: BluetoothDevice) -> bool { + fn cancel_bond_process(&mut self, device: BluetoothDevice) -> bool { dbus_generated!() } #[dbus_method("RemoveBond")] - fn remove_bond(&self, device: BluetoothDevice) -> bool { + fn remove_bond(&mut self, device: BluetoothDevice) -> bool { dbus_generated!() } - #[dbus_method("GetBondedDevices")] + #[dbus_method("GetBondedDevices", DBusLog::Disable)] fn get_bonded_devices(&self) -> Vec { dbus_generated!() } - #[dbus_method("GetBondState")] + #[dbus_method("GetBondState", DBusLog::Disable)] fn get_bond_state(&self, device: BluetoothDevice) -> BtBondState { dbus_generated!() } @@ -545,17 +592,17 @@ impl IBluetooth for IBluetoothDBus { dbus_generated!() } - #[dbus_method("GetRemoteName")] + #[dbus_method("GetRemoteName", DBusLog::Disable)] fn get_remote_name(&self, _device: BluetoothDevice) -> String { dbus_generated!() } - #[dbus_method("GetRemoteType")] + #[dbus_method("GetRemoteType", DBusLog::Disable)] fn get_remote_type(&self, _device: BluetoothDevice) -> BtDeviceType { dbus_generated!() } - #[dbus_method("GetRemoteAlias")] + #[dbus_method("GetRemoteAlias", DBusLog::Disable)] fn get_remote_alias(&self, _device: BluetoothDevice) -> String { dbus_generated!() } @@ -565,47 +612,62 @@ impl IBluetooth for IBluetoothDBus { dbus_generated!() } - #[dbus_method("GetRemoteClass")] + #[dbus_method("GetRemoteClass", DBusLog::Disable)] fn get_remote_class(&self, _device: BluetoothDevice) -> u32 { dbus_generated!() } - #[dbus_method("GetRemoteAppearance")] + #[dbus_method("GetRemoteAppearance", DBusLog::Disable)] fn get_remote_appearance(&self, _device: BluetoothDevice) -> u16 { dbus_generated!() } - #[dbus_method("GetRemoteConnected")] + #[dbus_method("GetRemoteConnected", DBusLog::Disable)] fn get_remote_connected(&self, _device: BluetoothDevice) -> bool { dbus_generated!() } - #[dbus_method("GetRemoteWakeAllowed")] + #[dbus_method("GetRemoteWakeAllowed", DBusLog::Disable)] fn get_remote_wake_allowed(&self, _device: BluetoothDevice) -> bool { dbus_generated!() } - #[dbus_method("GetConnectedDevices")] + #[dbus_method("GetRemoteVendorProductInfo", DBusLog::Disable)] + fn get_remote_vendor_product_info(&self, _device: BluetoothDevice) -> BtVendorProductInfo { + dbus_generated!() + } + + #[dbus_method("GetRemoteAddressType", DBusLog::Disable)] + fn get_remote_address_type(&self, device: BluetoothDevice) -> BtAddrType { + dbus_generated!() + } + + #[dbus_method("GetRemoteRSSI", DBusLog::Disable)] + fn get_remote_rssi(&self, device: BluetoothDevice) -> i8 { + dbus_generated!() + } + + #[dbus_method("GetConnectedDevices", DBusLog::Disable)] fn get_connected_devices(&self) -> Vec { dbus_generated!() } - #[dbus_method("GetConnectionState")] + #[dbus_method("GetConnectionState", DBusLog::Disable)] fn get_connection_state(&self, device: BluetoothDevice) -> BtConnectionState { dbus_generated!() } - #[dbus_method("GetProfileConnectionState")] + #[dbus_method("GetProfileConnectionState", DBusLog::Disable)] fn get_profile_connection_state(&self, profile: Uuid128Bit) -> ProfileConnectionState { dbus_generated!() } - #[dbus_method("GetRemoteUuids")] + #[dbus_method("GetRemoteUuids", DBusLog::Disable)] fn get_remote_uuids(&self, device: BluetoothDevice) -> Vec { dbus_generated!() } - #[dbus_method("FetchRemoteUuids")] + #[dbus_method("FetchRemoteUuids", DBusLog::Disable)] fn fetch_remote_uuids(&self, device: BluetoothDevice) -> bool { dbus_generated!() } @@ -635,12 +697,12 @@ impl IBluetooth for IBluetoothDBus { dbus_generated!() } - #[dbus_method("IsWbsSupported")] + #[dbus_method("IsWbsSupported", DBusLog::Disable)] fn is_wbs_supported(&self) -> bool { dbus_generated!() } - #[dbus_method("IsSwbSupported")] + #[dbus_method("IsSwbSupported", DBusLog::Disable)] fn is_swb_supported(&self) -> bool { dbus_generated!() } @@ -729,6 +791,11 @@ impl IBluetoothSocketManager for IBluetoothSocketManagerDBus { dbus_generated!() } + #[dbus_method("UnregisterCallback")] + fn unregister_callback(&mut self, callback: CallbackId) -> bool { + dbus_generated!() + } + #[dbus_method("ListenUsingInsecureL2capChannel")] fn listen_using_insecure_l2cap_channel(&mut self, callback: CallbackId) -> SocketResult { dbus_generated!() diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_admin.rs b/system/gd/rust/linux/service/src/iface_bluetooth_admin.rs index 4139faccf55dd0d8d662d41a2ca09e700e2459d8..2b525866c5417c305cfa727f62f9831c1a1d93dd 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth_admin.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth_admin.rs @@ -4,7 +4,7 @@ use dbus::arg::RefArg; use dbus::Path; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter}; -use dbus_projection::{dbus_generated, DisconnectWatcher}; +use dbus_projection::prelude::*; use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust}; diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs b/system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs index 9c996dbec3257cc09a8426a68bf18f178bf85d2f..2fed0ba02a3f9aeabaaf8230a064ed2167d234f8 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs @@ -20,8 +20,7 @@ use dbus::strings::Path; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter}; -use dbus_projection::DisconnectWatcher; -use dbus_projection::{dbus_generated, impl_dbus_arg_enum}; +use dbus_projection::prelude::*; use num_traits::cast::{FromPrimitive, ToPrimitive}; @@ -288,6 +287,10 @@ impl DBusArg for Uuid128Bit { fn to_dbus(data: [u8; 16]) -> Result, Box> { return Ok(data.to_vec()); } + + fn log(data: &[u8; 16]) -> String { + String::from(format!("{:?}", data)) + } } #[allow(dead_code)] @@ -464,6 +467,10 @@ impl DBusArg for ScanFilterCondition { } return Ok(map); } + + fn log(condition: &ScanFilterCondition) -> String { + String::from(format!("{:?}", condition)) + } } #[dbus_propmap(ScanFilter)] @@ -614,12 +621,12 @@ impl IBluetoothGatt for IBluetoothGattDBus { dbus_generated!() } - #[dbus_method("RegisterScanner")] + #[dbus_method("RegisterScanner", DBusLog::Disable)] fn register_scanner(&mut self, callback_id: u32) -> Uuid128Bit { dbus_generated!() } - #[dbus_method("UnregisterScanner")] + #[dbus_method("UnregisterScanner", DBusLog::Disable)] fn unregister_scanner(&mut self, scanner_id: u8) -> bool { dbus_generated!() } @@ -628,7 +635,7 @@ impl IBluetoothGatt for IBluetoothGattDBus { fn start_scan( &mut self, scanner_id: u8, - settings: ScanSettings, + settings: Option, filter: Option, ) -> BtStatus { dbus_generated!() @@ -655,7 +662,7 @@ impl IBluetoothGatt for IBluetoothGattDBus { } #[dbus_method("UnregisterAdvertiserCallback")] - fn unregister_advertiser_callback(&mut self, callback_id: u32) { + fn unregister_advertiser_callback(&mut self, callback_id: u32) -> bool { dbus_generated!() } @@ -679,7 +686,7 @@ impl IBluetoothGatt for IBluetoothGattDBus { dbus_generated!() } - #[dbus_method("GetOwnAddress")] + #[dbus_method("GetOwnAddress", DBusLog::Disable)] fn get_own_address(&mut self, advertiser_id: i32) { dbus_generated!() } @@ -784,27 +791,27 @@ impl IBluetoothGatt for IBluetoothGattDBus { dbus_generated!() } - #[dbus_method("DiscoverServices")] + #[dbus_method("DiscoverServices", DBusLog::Disable)] fn discover_services(&self, client_id: i32, addr: String) { dbus_generated!() } - #[dbus_method("DiscoverServiceByUuid")] + #[dbus_method("DiscoverServiceByUuid", DBusLog::Disable)] fn discover_service_by_uuid(&self, client_id: i32, addr: String, uuid: String) { dbus_generated!() } - #[dbus_method("BtifGattcDiscoverServiceByUuid")] + #[dbus_method("BtifGattcDiscoverServiceByUuid", DBusLog::Disable)] fn btif_gattc_discover_service_by_uuid(&self, client_id: i32, addr: String, uuid: String) { dbus_generated!() } - #[dbus_method("ReadCharacteristic")] + #[dbus_method("ReadCharacteristic", DBusLog::Disable)] fn read_characteristic(&self, client_id: i32, addr: String, handle: i32, auth_req: i32) { dbus_generated!() } - #[dbus_method("ReadUsingCharacteristicUuid")] + #[dbus_method("ReadUsingCharacteristicUuid", DBusLog::Disable)] fn read_using_characteristic_uuid( &self, client_id: i32, @@ -817,7 +824,7 @@ impl IBluetoothGatt for IBluetoothGattDBus { dbus_generated!() } - #[dbus_method("WriteCharacteristic")] + #[dbus_method("WriteCharacteristic", DBusLog::Disable)] fn write_characteristic( &self, client_id: i32, @@ -830,12 +837,12 @@ impl IBluetoothGatt for IBluetoothGattDBus { dbus_generated!() } - #[dbus_method("ReadDescriptor")] + #[dbus_method("ReadDescriptor", DBusLog::Disable)] fn read_descriptor(&self, client_id: i32, addr: String, handle: i32, auth_req: i32) { dbus_generated!() } - #[dbus_method("WriteDescriptor")] + #[dbus_method("WriteDescriptor", DBusLog::Disable)] fn write_descriptor( &self, client_id: i32, @@ -847,27 +854,27 @@ impl IBluetoothGatt for IBluetoothGattDBus { dbus_generated!() } - #[dbus_method("RegisterForNotification")] + #[dbus_method("RegisterForNotification", DBusLog::Disable)] fn register_for_notification(&self, client_id: i32, addr: String, handle: i32, enable: bool) { dbus_generated!() } - #[dbus_method("BeginReliableWrite")] + #[dbus_method("BeginReliableWrite", DBusLog::Disable)] fn begin_reliable_write(&mut self, client_id: i32, addr: String) { dbus_generated!() } - #[dbus_method("EndReliableWrite")] + #[dbus_method("EndReliableWrite", DBusLog::Disable)] fn end_reliable_write(&mut self, client_id: i32, addr: String, execute: bool) { dbus_generated!() } - #[dbus_method("ReadRemoteRssi")] + #[dbus_method("ReadRemoteRssi", DBusLog::Disable)] fn read_remote_rssi(&self, client_id: i32, addr: String) { dbus_generated!() } - #[dbus_method("ConfigureMtu")] + #[dbus_method("ConfigureMtu", DBusLog::Disable)] fn configure_mtu(&self, client_id: i32, addr: String, mtu: i32) { dbus_generated!() } @@ -952,7 +959,7 @@ impl IBluetoothGatt for IBluetoothGattDBus { dbus_generated!() } - #[dbus_method("SendResponse")] + #[dbus_method("SendResponse", DBusLog::Disable)] fn send_response( &self, server_id: i32, @@ -965,7 +972,7 @@ impl IBluetoothGatt for IBluetoothGattDBus { dbus_generated!() } - #[dbus_method("SendNotification")] + #[dbus_method("SendNotification", DBusLog::Disable)] fn send_notification( &self, server_id: i32, diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_media.rs b/system/gd/rust/linux/service/src/iface_bluetooth_media.rs index 28333077915cb4e6bc053c8a42366bb8d527eca8..cb575bd22afc958fa40c84bb6c610cc97d1de153 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth_media.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth_media.rs @@ -1,4 +1,7 @@ -use bt_topshim::profiles::a2dp::{A2dpCodecConfig, PresentationPosition}; +use bt_topshim::profiles::a2dp::{ + A2dpCodecBitsPerSample, A2dpCodecChannelMode, A2dpCodecConfig, A2dpCodecIndex, + A2dpCodecSampleRate, PresentationPosition, +}; use bt_topshim::profiles::avrcp::PlayerMetadata; use bt_topshim::profiles::hfp::HfpCodecCapability; use btstack::bluetooth_media::{BluetoothAudioDevice, IBluetoothMedia, IBluetoothMediaCallback}; @@ -10,11 +13,12 @@ use dbus::strings::Path; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter}; -use dbus_projection::DisconnectWatcher; -use dbus_projection::{dbus_generated, impl_dbus_arg_from_into}; +use dbus_projection::prelude::*; use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust}; +use num_traits::{FromPrimitive, ToPrimitive}; + use std::convert::{TryFrom, TryInto}; use std::sync::Arc; @@ -44,6 +48,10 @@ pub struct BluetoothAudioDeviceDBus { } impl_dbus_arg_from_into!(HfpCodecCapability, i32); +impl_dbus_arg_enum!(A2dpCodecIndex); +impl_dbus_arg_from_into!(A2dpCodecSampleRate, i32); +impl_dbus_arg_from_into!(A2dpCodecBitsPerSample, i32); +impl_dbus_arg_from_into!(A2dpCodecChannelMode, i32); #[dbus_proxy_obj(BluetoothMediaCallback, "org.chromium.bluetooth.BluetoothMediaCallback")] impl IBluetoothMediaCallback for BluetoothMediaCallbackDBus { @@ -76,6 +84,21 @@ impl IBluetoothMediaCallback for BluetoothMediaCallbackDBus { fn on_hfp_audio_disconnected(&mut self, addr: String) { dbus_generated!() } + + #[dbus_method("OnHfpDebugDump")] + fn on_hfp_debug_dump( + &mut self, + active: bool, + codec_id: u16, + total_num_decoded_frames: i32, + pkt_loss_ratio: f64, + begin_ts: u64, + end_ts: u64, + pkt_status_in_hex: String, + pkt_status_in_binary: String, + ) { + dbus_generated!() + } } #[allow(dead_code)] @@ -141,6 +164,10 @@ impl DBusArg for PlayerMetadata { ) -> Result> { Ok(std::collections::HashMap::new()) } + + fn log(metadata: &PlayerMetadata) -> String { + String::from(format!("{:?}", metadata)) + } } #[generate_dbus_exporter(export_bluetooth_media_dbus_intf, "org.chromium.bluetooth.BluetoothMedia")] @@ -180,7 +207,7 @@ impl IBluetoothMedia for IBluetoothMediaDBus { dbus_generated!() } - #[dbus_method("SetHfpActiveDevice")] + #[dbus_method("SetHfpActiveDevice", DBusLog::Disable)] fn set_hfp_active_device(&mut self, address: String) { dbus_generated!() } @@ -188,14 +215,16 @@ impl IBluetoothMedia for IBluetoothMediaDBus { #[dbus_method("SetAudioConfig")] fn set_audio_config( &mut self, - sample_rate: i32, - bits_per_sample: i32, - channel_mode: i32, + address: String, + codec_type: A2dpCodecIndex, + sample_rate: A2dpCodecSampleRate, + bits_per_sample: A2dpCodecBitsPerSample, + channel_mode: A2dpCodecChannelMode, ) -> bool { dbus_generated!() } - #[dbus_method("SetVolume")] + #[dbus_method("SetVolume", DBusLog::Disable)] fn set_volume(&mut self, volume: u8) { dbus_generated!() } @@ -210,18 +239,23 @@ impl IBluetoothMedia for IBluetoothMediaDBus { dbus_generated!() } - #[dbus_method("GetA2dpAudioStarted")] + #[dbus_method("GetA2dpAudioStarted", DBusLog::Disable)] fn get_a2dp_audio_started(&mut self, address: String) -> bool { dbus_generated!() } - #[dbus_method("StopAudioRequest")] + #[dbus_method("StopAudioRequest", DBusLog::Disable)] fn stop_audio_request(&mut self) { dbus_generated!() } #[dbus_method("StartScoCall")] - fn start_sco_call(&mut self, address: String, sco_offload: bool, force_cvsd: bool) -> bool { + fn start_sco_call( + &mut self, + address: String, + sco_offload: bool, + disabled_codecs: HfpCodecCapability, + ) -> bool { dbus_generated!() } @@ -235,7 +269,7 @@ impl IBluetoothMedia for IBluetoothMediaDBus { dbus_generated!() } - #[dbus_method("GetPresentationPosition")] + #[dbus_method("GetPresentationPosition", DBusLog::Disable)] fn get_presentation_position(&mut self) -> PresentationPosition { dbus_generated!() } @@ -243,12 +277,12 @@ impl IBluetoothMedia for IBluetoothMediaDBus { // Temporary AVRCP-related meida DBUS APIs. The following APIs intercept between Chrome CRAS // and cras_server as an expedited solution for AVRCP implementation. The APIs are subject to // change when retiring Chrome CRAS. - #[dbus_method("SetPlayerPlaybackStatus")] + #[dbus_method("SetPlayerPlaybackStatus", DBusLog::Disable)] fn set_player_playback_status(&mut self, status: String) { dbus_generated!() } - #[dbus_method("SetPlayerPosition")] + #[dbus_method("SetPlayerPosition", DBusLog::Disable)] fn set_player_position(&mut self, position_us: i64) { dbus_generated!() } @@ -257,4 +291,9 @@ impl IBluetoothMedia for IBluetoothMediaDBus { fn set_player_metadata(&mut self, metadata: PlayerMetadata) { dbus_generated!() } + + #[dbus_method("TriggerDebugDump")] + fn trigger_debug_dump(&mut self) { + dbus_generated!() + } } diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_qa.rs b/system/gd/rust/linux/service/src/iface_bluetooth_qa.rs index 3235601da919a60377e575e03b600fa4c0cbfbbe..4b8f63fab754f757980b609b801b46487b58d3a4 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth_qa.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth_qa.rs @@ -1,15 +1,28 @@ -use btstack::bluetooth_qa::IBluetoothQA; +use btstack::bluetooth_qa::{IBluetoothQA, IBluetoothQACallback}; use bt_topshim::btif::BtDiscMode; -use dbus_macros::{dbus_method, generate_dbus_exporter}; -use dbus_projection::dbus_generated; +use dbus_macros::{dbus_method, dbus_proxy_obj, generate_dbus_exporter}; +use dbus_projection::prelude::*; use crate::dbus_arg::DBusArg; +use bt_topshim::btif::BtStatus; +use bt_topshim::profiles::hid_host::BthhReportType; +use btstack::RPCProxy; +use dbus::Path; +struct IBluetoothQACallbackDBus {} struct IBluetoothQADBus {} #[generate_dbus_exporter(export_bluetooth_qa_dbus_intf, "org.chromium.bluetooth.BluetoothQA")] impl IBluetoothQA for IBluetoothQADBus { + #[dbus_method("RegisterQACallback")] + fn register_qa_callback(&mut self, callback: Box) -> u32 { + dbus_generated!() + } + #[dbus_method("UnregisterQACallback")] + fn unregister_qa_callback(&mut self, callback_id: u32) -> bool { + dbus_generated!() + } #[dbus_method("AddMediaPlayer")] fn add_media_player(&self, name: String, browsing_supported: bool) { dbus_generated!() @@ -18,8 +31,68 @@ impl IBluetoothQA for IBluetoothQADBus { fn rfcomm_send_msc(&self, dlci: u8, addr: String) { dbus_generated!() } - #[dbus_method("GetDiscoverableMode")] - fn get_discoverable_mode(&self) -> BtDiscMode { + #[dbus_method("FetchDiscoverableMode")] + fn fetch_discoverable_mode(&self) { + dbus_generated!() + } + #[dbus_method("FetchConnectable")] + fn fetch_connectable(&self) { + dbus_generated!() + } + #[dbus_method("SetConnectable")] + fn set_connectable(&self, mode: bool) { + dbus_generated!() + } + #[dbus_method("FetchAlias")] + fn fetch_alias(&self) { + dbus_generated!() + } + #[dbus_method("GetModalias")] + fn get_modalias(&self) -> String { + dbus_generated!() + } + #[dbus_method("FetchHIDReport")] + fn get_hid_report(&self, addr: String, report_type: BthhReportType, report_id: u8) { + dbus_generated!() + } + #[dbus_method("SetHIDReport")] + fn set_hid_report(&self, addr: String, report_type: BthhReportType, report: String) { + dbus_generated!() + } + #[dbus_method("SendHIDData")] + fn send_hid_data(&self, addr: String, data: String) { + dbus_generated!() + } +} + +#[dbus_proxy_obj(QACallback, "org.chromium.bluetooth.QACallback")] +impl IBluetoothQACallback for IBluetoothQACallbackDBus { + #[dbus_method("OnFetchDiscoverableModeComplete")] + fn on_fetch_discoverable_mode_completed(&mut self, disc_mode: BtDiscMode) { + dbus_generated!() + } + #[dbus_method("OnFetchConnectableComplete")] + fn on_fetch_connectable_completed(&mut self, connectable: bool) { + dbus_generated!() + } + #[dbus_method("OnSetConnectableComplete")] + fn on_set_connectable_completed(&mut self, succeed: bool) { + dbus_generated!() + } + #[dbus_method("OnFetchAliasComplete")] + fn on_fetch_alias_completed(&mut self, alias: String) { + dbus_generated!() + } + #[dbus_method("OnGetHIDReportComplete")] + fn on_get_hid_report_completed(&mut self, status: BtStatus) { + dbus_generated!() + } + #[dbus_method("OnSetHIDReportComplete")] + fn on_set_hid_report_completed(&mut self, status: BtStatus) { + dbus_generated!() + } + #[dbus_method("OnSendHIDDataComplete")] + fn on_send_hid_data_completed(&mut self, status: BtStatus) { dbus_generated!() } } diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_telephony.rs b/system/gd/rust/linux/service/src/iface_bluetooth_telephony.rs index 818e89d34d3aca29a23b7d3d0b13b318799a537b..1fc6a8a81b735f18842856c5a1578f7791ef987b 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth_telephony.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth_telephony.rs @@ -1,11 +1,25 @@ -use btstack::bluetooth_media::IBluetoothTelephony; +use btstack::bluetooth_media::{IBluetoothTelephony, IBluetoothTelephonyCallback}; +use btstack::RPCProxy; -use dbus_macros::{dbus_method, generate_dbus_exporter}; +use dbus::Path; -use dbus_projection::dbus_generated; +use dbus_macros::{dbus_method, dbus_proxy_obj, generate_dbus_exporter}; + +use dbus_projection::prelude::*; use crate::dbus_arg::DBusArg; +#[allow(dead_code)] +struct BluetoothTelephonyCallbackDBus {} + +#[dbus_proxy_obj(BluetoothTelephonyCallback, "org.chromium.bluetooth.BluetoothTelephonyCallback")] +impl IBluetoothTelephonyCallback for BluetoothTelephonyCallbackDBus { + #[dbus_method("OnTelephonyUse")] + fn on_telephony_use(&mut self, addr: String, state: bool) { + dbus_generated!() + } +} + #[allow(dead_code)] struct IBluetoothTelephonyDBus {} @@ -14,6 +28,14 @@ struct IBluetoothTelephonyDBus {} "org.chromium.bluetooth.BluetoothTelephony" )] impl IBluetoothTelephony for IBluetoothTelephonyDBus { + #[dbus_method("RegisterTelephonyCallback")] + fn register_telephony_callback( + &mut self, + callback: Box, + ) -> bool { + dbus_generated!() + } + #[dbus_method("SetNetworkAvailable")] fn set_network_available(&mut self, network_available: bool) { dbus_generated!() @@ -34,6 +56,10 @@ impl IBluetoothTelephony for IBluetoothTelephonyDBus { fn set_phone_ops_enabled(&mut self, enable: bool) { dbus_generated!() } + #[dbus_method("SetMpsQualificationEnabled")] + fn set_mps_qualification_enabled(&mut self, enable: bool) { + dbus_generated!() + } #[dbus_method("IncomingCall")] fn incoming_call(&mut self, number: String) -> bool { dbus_generated!() diff --git a/system/gd/rust/linux/service/src/iface_logging.rs b/system/gd/rust/linux/service/src/iface_logging.rs index fcbe67a15834715d6bfedd708f20da344760fb78..28a8e656bdfbb8f3fabd25a57880782a571db72f 100644 --- a/system/gd/rust/linux/service/src/iface_logging.rs +++ b/system/gd/rust/linux/service/src/iface_logging.rs @@ -2,7 +2,7 @@ use crate::dbus_arg::DBusArg; use btstack::bluetooth_logging::IBluetoothLogging; use dbus_macros::{dbus_method, generate_dbus_exporter}; -use dbus_projection::dbus_generated; +use dbus_projection::prelude::*; struct IBluetoothLoggingDBus {} diff --git a/system/gd/rust/linux/service/src/interface_manager.rs b/system/gd/rust/linux/service/src/interface_manager.rs new file mode 100644 index 0000000000000000000000000000000000000000..b12b38be292d922b6bfd91992601a298c7f1e382 --- /dev/null +++ b/system/gd/rust/linux/service/src/interface_manager.rs @@ -0,0 +1,239 @@ +use dbus::{channel::MatchingReceiver, message::MatchRule, nonblock::SyncConnection}; +use dbus_crossroads::Crossroads; +use dbus_projection::DisconnectWatcher; + +use std::sync::{Arc, Mutex}; +use tokio::sync::mpsc::{channel, Receiver, Sender}; + +use btstack::{ + battery_manager::BatteryManager, battery_provider_manager::BatteryProviderManager, + battery_service::BatteryService, bluetooth::Bluetooth, bluetooth_admin::BluetoothAdmin, + bluetooth_gatt::BluetoothGatt, bluetooth_logging::BluetoothLogging, + bluetooth_media::BluetoothMedia, bluetooth_qa::BluetoothQA, + socket_manager::BluetoothSocketManager, suspend::Suspend, APIMessage, BluetoothAPI, +}; + +use crate::iface_battery_manager; +use crate::iface_battery_provider_manager; +use crate::iface_bluetooth; +use crate::iface_bluetooth_admin; +use crate::iface_bluetooth_gatt; +use crate::iface_bluetooth_media; +use crate::iface_bluetooth_qa; +use crate::iface_bluetooth_telephony; +use crate::iface_logging; + +pub(crate) struct InterfaceManager {} + +impl InterfaceManager { + fn make_object_name(idx: i32, name: &str) -> String { + String::from(format!("/org/chromium/bluetooth/hci{}/{}", idx, name)) + } + + /// Creates an mpsc channel for passing messages to the main dispatch loop. + pub fn create_channel() -> (Sender, Receiver) { + channel::(1) + } + + pub async fn dispatch( + mut rx: Receiver, + virt_index: i32, + conn: Arc, + disconnect_watcher: Arc>, + bluetooth: Arc>>, + bluetooth_admin: Arc>>, + bluetooth_gatt: Arc>>, + battery_service: Arc>>, + battery_manager: Arc>>, + battery_provider_manager: Arc>>, + bluetooth_media: Arc>>, + bluetooth_qa: Arc>>, + bt_sock_mgr: Arc>>, + suspend: Arc>>, + logging: Arc>>, + ) { + // Prepare D-Bus interfaces. + let cr = Arc::new(Mutex::new(Crossroads::new())); + cr.lock().unwrap().set_async_support(Some(( + conn.clone(), + Box::new(|x| { + tokio::spawn(x); + }), + ))); + + // Announce the exported adapter objects so that clients can properly detect the readiness + // of the adapter APIs. + cr.lock().unwrap().set_object_manager_support(Some(conn.clone())); + let object_manager = cr.lock().unwrap().object_manager(); + cr.lock().unwrap().insert("/", &[object_manager], {}); + + // Set up handling of D-Bus methods. This must be done before exporting interfaces so that + // clients that rely on InterfacesAdded signal can rely on us being ready to handle methods + // on those exported interfaces. + let cr_clone = cr.clone(); + conn.start_receive( + MatchRule::new_method_call(), + Box::new(move |msg, conn| { + cr_clone.lock().unwrap().handle_message(msg, conn).unwrap(); + true + }), + ); + + // Register D-Bus method handlers of IBluetooth. + let adapter_iface = iface_bluetooth::export_bluetooth_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + let qa_iface = iface_bluetooth_qa::export_bluetooth_qa_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + let qa_legacy_iface = iface_bluetooth::export_bluetooth_qa_legacy_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + let socket_mgr_iface = iface_bluetooth::export_socket_mgr_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + let suspend_iface = iface_bluetooth::export_suspend_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + let logging_iface = iface_logging::export_bluetooth_logging_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + + // Register D-Bus method handlers of IBluetoothGatt. + let gatt_iface = iface_bluetooth_gatt::export_bluetooth_gatt_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + + let media_iface = iface_bluetooth_media::export_bluetooth_media_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + + let telephony_iface = iface_bluetooth_telephony::export_bluetooth_telephony_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + + let battery_provider_manager_iface = + iface_battery_provider_manager::export_battery_provider_manager_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + + let battery_manager_iface = iface_battery_manager::export_battery_manager_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + + let admin_iface = iface_bluetooth_admin::export_bluetooth_admin_dbus_intf( + conn.clone(), + &mut cr.lock().unwrap(), + disconnect_watcher.clone(), + ); + + // Create mixin object for Bluetooth + Suspend interfaces. + let mixin = Box::new(iface_bluetooth::BluetoothMixin { + adapter: bluetooth.clone(), + qa: bluetooth.clone(), + suspend: suspend.clone(), + socket_mgr: bt_sock_mgr.clone(), + }); + + loop { + let m = rx.recv().await; + + if m.is_none() { + eprintln!("APIMessage dispatch loop quit"); + break; + } + + match m.unwrap() { + APIMessage::IsReady(api) => match api { + BluetoothAPI::Adapter => { + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "adapter"), + &[adapter_iface, qa_legacy_iface, socket_mgr_iface, suspend_iface], + mixin.clone(), + ); + + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "admin"), + &[admin_iface], + bluetooth_admin.clone(), + ); + + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "logging"), + &[logging_iface], + logging.clone(), + ); + + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "qa"), + &[qa_iface], + bluetooth_qa.clone(), + ); + } + BluetoothAPI::Gatt => { + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "gatt"), + &[gatt_iface], + bluetooth_gatt.clone(), + ); + + // Battery service is on top of Gatt. Only initialize it after + // GATT is ready. + let bs = battery_service.clone(); + tokio::spawn(async move { + bs.lock().unwrap().init(); + }); + } + BluetoothAPI::Media => { + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "media"), + &[media_iface], + bluetooth_media.clone(), + ); + + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "telephony"), + &[telephony_iface], + bluetooth_media.clone(), + ); + } + BluetoothAPI::Battery => { + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "battery_provider_manager"), + &[battery_provider_manager_iface], + battery_provider_manager.clone(), + ); + + cr.lock().unwrap().insert( + Self::make_object_name(virt_index, "battery_manager"), + &[battery_manager_iface], + battery_manager.clone(), + ); + } + }, + } + } + } +} diff --git a/system/gd/rust/linux/service/src/main.rs b/system/gd/rust/linux/service/src/main.rs index 3a0810a277d144e834a0aae31d59b180b5a7ac69..3861df37c1a6cf8b0d8f66ea5599e57e670c49f9 100644 --- a/system/gd/rust/linux/service/src/main.rs +++ b/system/gd/rust/linux/service/src/main.rs @@ -1,7 +1,5 @@ -use btstack::bluetooth_qa::BluetoothQA; use clap::{App, AppSettings, Arg}; -use dbus::{channel::MatchingReceiver, message::MatchRule}; -use dbus_crossroads::Crossroads; +use dbus_projection::DisconnectWatcher; use dbus_tokio::connection; use futures::future; use lazy_static::lazy_static; @@ -9,7 +7,7 @@ use nix::sys::signal; use std::error::Error; use std::sync::{Arc, Condvar, Mutex}; use std::time::Duration; -use tokio::time; +use tokio::sync::mpsc::Sender; // Necessary to link right entries. #[allow(unused_imports)] @@ -20,18 +18,17 @@ use btstack::{ battery_manager::BatteryManager, battery_provider_manager::BatteryProviderManager, battery_service::BatteryService, - bluetooth::{get_bt_dispatcher, Bluetooth, IBluetooth}, + bluetooth::{Bluetooth, IBluetooth, SigData}, bluetooth_admin::BluetoothAdmin, bluetooth_gatt::BluetoothGatt, bluetooth_logging::BluetoothLogging, bluetooth_media::BluetoothMedia, + bluetooth_qa::BluetoothQA, dis::DeviceInformation, socket_manager::BluetoothSocketManager, suspend::Suspend, Message, Stack, }; -use dbus_projection::DisconnectWatcher; -use tokio::sync::mpsc::Sender; mod dbus_arg; mod iface_battery_manager; @@ -43,12 +40,15 @@ mod iface_bluetooth_media; mod iface_bluetooth_qa; mod iface_bluetooth_telephony; mod iface_logging; +mod interface_manager; const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth"; const ADMIN_SETTINGS_FILE_PATH: &str = "/var/lib/bluetooth/admin_policy.json"; // The maximum ACL disconnect timeout is 3.5s defined by BTA_DM_DISABLE_TIMER_MS // and BTA_DM_DISABLE_TIMER_RETRIAL_MS const STACK_TURN_OFF_TIMEOUT_MS: Duration = Duration::from_millis(4000); +// Time bt_stack_manager waits for cleanup +const STACK_CLEANUP_TIMEOUT_MS: Duration = Duration::from_millis(1000); const VERBOSE_ONLY_LOG_TAGS: &[&str] = &[ "bt_bta_av", // AV apis @@ -59,9 +59,7 @@ const VERBOSE_ONLY_LOG_TAGS: &[&str] = &[ "uipc", // Userspace IPC implementation ]; -fn make_object_name(idx: i32, name: &str) -> String { - String::from(format!("/org/chromium/bluetooth/hci{}/{}", idx, name)) -} +const INIT_LOGGING_MAX_RETRY: u8 = 3; /// Runs the Bluetooth daemon serving D-Bus IPC. fn main() -> Result<(), Box> { @@ -104,7 +102,7 @@ fn main() -> Result<(), Box> { let is_verbose_debug = matches.is_present("verbose-debug"); let log_output = matches.value_of("log-output").unwrap_or("syslog"); - let adapter_index = matches.value_of("index").map_or(0, |idx| idx.parse::().unwrap_or(0)); + let virt_index = matches.value_of("index").map_or(0, |idx| idx.parse::().unwrap_or(0)); let hci_index = matches.value_of("hci").map_or(0, |idx| idx.parse::().unwrap_or(0)); // The remaining flags are passed down to Fluoride as is. @@ -129,13 +127,28 @@ fn main() -> Result<(), Box> { // Forward --hci to Fluoride. init_flags.push(format!("--hci={}", hci_index)); + let logging = Arc::new(Mutex::new(Box::new(BluetoothLogging::new(is_debug, log_output)))); + // TODO(b/307171804): Investigate why connecting to unix syslog might fail. + // Retry it a few times. Ignore the failure if fails too many times. + for _ in 0..INIT_LOGGING_MAX_RETRY { + match logging.lock().unwrap().initialize() { + Ok(_) => break, + Err(_) => continue, + } + } // Always treat discovery as classic only init_flags.push(String::from("INIT_classic_discovery_only=true")); let (tx, rx) = Stack::create_channel(); - let sig_notifier = Arc::new((Mutex::new(false), Condvar::new())); + let (api_tx, api_rx) = interface_manager::InterfaceManager::create_channel(); + let sig_notifier = Arc::new(SigData { + enabled: Mutex::new(false), + enabled_notify: Condvar::new(), + thread_attached: Mutex::new(false), + thread_notify: Condvar::new(), + }); let intf = Arc::new(Mutex::new(get_btinterface().unwrap())); let bluetooth_gatt = @@ -146,6 +159,7 @@ fn main() -> Result<(), Box> { bluetooth_gatt.clone(), battery_provider_manager.clone(), tx.clone(), + api_tx.clone(), )))); let battery_manager = Arc::new(Mutex::new(Box::new(BatteryManager::new( battery_provider_manager.clone(), @@ -161,8 +175,10 @@ fn main() -> Result<(), Box> { tx.clone(), )))); let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new( - adapter_index, + virt_index, + hci_index, tx.clone(), + api_tx.clone(), sig_notifier.clone(), intf.clone(), bluetooth_admin.clone(), @@ -199,21 +215,6 @@ fn main() -> Result<(), Box> { // Request a service name and quit if not able to. conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?; - // Prepare D-Bus interfaces. - let cr = Arc::new(Mutex::new(Crossroads::new())); - cr.lock().unwrap().set_async_support(Some(( - conn.clone(), - Box::new(|x| { - tokio::spawn(x); - }), - ))); - - // Announce the exported adapter objects so that clients can properly detect the readiness - // of the adapter APIs. - cr.lock().unwrap().set_object_manager_support(Some(conn.clone())); - let object_manager = cr.lock().unwrap().object_manager(); - cr.lock().unwrap().insert("/", &[object_manager], {}); - // Run the stack main dispatch loop. topstack::get_runtime().spawn(Stack::dispatch( rx, @@ -234,191 +235,63 @@ fn main() -> Result<(), Box> { let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new())); disconnect_watcher.lock().unwrap().setup_watch(conn.clone()).await; - // Set up handling of D-Bus methods. This must be done before exporting interfaces so that - // clients that rely on InterfacesAdded signal can rely on us being ready to handle methods - // on those exported interfaces. - let cr_clone = cr.clone(); - conn.start_receive( - MatchRule::new_method_call(), - Box::new(move |msg, conn| { - cr_clone.lock().unwrap().handle_message(msg, conn).unwrap(); - true - }), - ); - - // Register D-Bus method handlers of IBluetooth. - let adapter_iface = iface_bluetooth::export_bluetooth_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - let qa_iface = iface_bluetooth_qa::export_bluetooth_qa_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - let qa_legacy_iface = iface_bluetooth::export_bluetooth_qa_legacy_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - let socket_mgr_iface = iface_bluetooth::export_socket_mgr_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - let suspend_iface = iface_bluetooth::export_suspend_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - let logging_iface = iface_logging::export_bluetooth_logging_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - - // Register D-Bus method handlers of IBluetoothGatt. - let gatt_iface = iface_bluetooth_gatt::export_bluetooth_gatt_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - - let media_iface = iface_bluetooth_media::export_bluetooth_media_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - - let telephony_iface = iface_bluetooth_telephony::export_bluetooth_telephony_dbus_intf( + tokio::spawn(interface_manager::InterfaceManager::dispatch( + api_rx, + virt_index, conn.clone(), - &mut cr.lock().unwrap(), disconnect_watcher.clone(), - ); - - let battery_provider_manager_iface = - iface_battery_provider_manager::export_battery_provider_manager_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - - let battery_manager_iface = iface_battery_manager::export_battery_manager_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - - let admin_iface = iface_bluetooth_admin::export_bluetooth_admin_dbus_intf( - conn.clone(), - &mut cr.lock().unwrap(), - disconnect_watcher.clone(), - ); - - // Create mixin object for Bluetooth + Suspend interfaces. - let mixin = Box::new(iface_bluetooth::BluetoothMixin { - adapter: bluetooth.clone(), - qa: bluetooth.clone(), - suspend: suspend.clone(), - socket_mgr: bt_sock_mgr.clone(), - }); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "adapter"), - &[adapter_iface, qa_legacy_iface, socket_mgr_iface, suspend_iface], - mixin, - ); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "gatt"), - &[gatt_iface], + bluetooth.clone(), + bluetooth_admin.clone(), bluetooth_gatt.clone(), - ); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "media"), - &[media_iface], - bluetooth_media.clone(), - ); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "telephony"), - &[telephony_iface], - bluetooth_media.clone(), - ); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "battery_provider_manager"), - &[battery_provider_manager_iface], - battery_provider_manager.clone(), - ); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "battery_manager"), - &[battery_manager_iface], + battery_service.clone(), battery_manager.clone(), - ); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "admin"), - &[admin_iface], - bluetooth_admin.clone(), - ); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "logging"), - &[logging_iface], - logging.clone(), - ); - - cr.lock().unwrap().insert( - make_object_name(adapter_index, "qa"), - &[qa_iface], + battery_provider_manager.clone(), + bluetooth_media.clone(), bluetooth_qa.clone(), - ); + bt_sock_mgr.clone(), + suspend.clone(), + logging.clone(), + )); // Hold locks and initialize all interfaces. This must be done AFTER DBus is // initialized so DBus can properly enforce user policies. { - intf.lock().unwrap().initialize(get_bt_dispatcher(tx.clone()), init_flags); - let adapter = bluetooth.clone(); bluetooth_media.lock().unwrap().set_adapter(adapter.clone()); bluetooth_admin.lock().unwrap().set_adapter(adapter.clone()); let mut bluetooth = bluetooth.lock().unwrap(); - bluetooth.init_profiles(); + bluetooth.init(init_flags); bluetooth.enable(); - bluetooth_gatt.lock().unwrap().init_profiles(tx.clone(), adapter.clone()); - // TODO(b/247093293): Gatt topshim api is only usable some - // time after init. Investigate why this delay is needed - // and make it a blocking part of init before removing - // this. - tokio::spawn(async move { - time::sleep(Duration::from_millis(500)).await; - battery_service.lock().unwrap().init(); - }); + bluetooth_gatt.lock().unwrap().init_profiles( + tx.clone(), + api_tx.clone(), + adapter.clone(), + ); bt_sock_mgr.lock().unwrap().initialize(intf.clone()); // Install SIGTERM handler so that we can properly shutdown *SIG_DATA.lock().unwrap() = Some((tx.clone(), sig_notifier.clone())); - let sig_action = signal::SigAction::new( + let sig_action_term = signal::SigAction::new( signal::SigHandler::Handler(handle_sigterm), signal::SaFlags::empty(), signal::SigSet::empty(), ); + let sig_action_int = signal::SigAction::new( + signal::SigHandler::Handler(handle_sigint), + signal::SaFlags::empty(), + signal::SigSet::empty(), + ); + unsafe { - signal::sigaction(signal::SIGTERM, &sig_action).unwrap(); + signal::sigaction(signal::SIGTERM, &sig_action_term).unwrap(); + signal::sigaction(signal::SIGINT, &sig_action_int).unwrap(); } } - // Initialize the bluetooth_qa - bluetooth.lock().unwrap().cache_discoverable_mode_into_qa(); - // Serve clients forever. future::pending::<()>().await; unreachable!() @@ -427,7 +300,7 @@ fn main() -> Result<(), Box> { lazy_static! { /// Data needed for signal handling. - static ref SIG_DATA: Mutex, Arc<(Mutex, Condvar)>)>> = Mutex::new(None); + static ref SIG_DATA: Mutex, Arc)>> = Mutex::new(None); } extern "C" fn handle_sigterm(_signum: i32) { @@ -440,13 +313,33 @@ extern "C" fn handle_sigterm(_signum: i32) { let _ = txl.send(Message::Shutdown).await; }); - let guard = notifier.0.lock().unwrap(); + let guard = notifier.enabled.lock().unwrap(); if *guard { log::debug!("Waiting for stack to turn off for {:?}", STACK_TURN_OFF_TIMEOUT_MS); - let _ = notifier.1.wait_timeout(guard, STACK_TURN_OFF_TIMEOUT_MS); + let _ = notifier.enabled_notify.wait_timeout(guard, STACK_TURN_OFF_TIMEOUT_MS); + } + + log::debug!("SIGTERM cleaning up the stack."); + let txl = tx.clone(); + tokio::spawn(async move { + // Send the cleanup message here. + let _ = txl.send(Message::Cleanup).await; + }); + + let guard = notifier.thread_attached.lock().unwrap(); + if *guard { + log::debug!("Waiting for stack to clean up for {:?}", STACK_CLEANUP_TIMEOUT_MS); + let _ = notifier.thread_notify.wait_timeout(guard, STACK_CLEANUP_TIMEOUT_MS); } } log::debug!("Sigterm completed"); std::process::exit(0); } + +extern "C" fn handle_sigint(_signum: i32) { + // Assumed this is from HAL Host, which is likely caused by chipset error. + // In this case, don't crash the daemon and don't try to power off the adapter. + log::debug!("Sigint completed"); + std::process::exit(0); +} diff --git a/system/gd/rust/linux/stack/Cargo.toml b/system/gd/rust/linux/stack/Cargo.toml index c3e2111d3b7fa63ea24af807f596a8d1caa4fce3..09414500e3ffce3f9e9c0d0f6ac0b5069d915117 100644 --- a/system/gd/rust/linux/stack/Cargo.toml +++ b/system/gd/rust/linux/stack/Cargo.toml @@ -22,7 +22,8 @@ num-traits = "0.2" rand = { version = "0.8.3", features = ["small_rng"] } serde_json = "1.0" syslog = "6" -tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } +tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } +log-panics = "2.1.0" [lib] path = "src/lib.rs" diff --git a/system/gd/rust/linux/stack/build.rs b/system/gd/rust/linux/stack/build.rs index 4b979d0825653b0acede9a0a3dafc5ab280a20c5..1ecdfad91705c77b73c8016d2ddba84ae623099d 100644 --- a/system/gd/rust/linux/stack/build.rs +++ b/system/gd/rust/linux/stack/build.rs @@ -11,6 +11,7 @@ fn main() { println!("cargo:rustc-link-lib=dylib=flatbuffers"); println!("cargo:rustc-link-lib=dylib=protobuf"); println!("cargo:rustc-link-lib=dylib=resolv"); + println!("cargo:rustc-link-lib=dylib=lc3"); println!("cargo:rerun-if-changed=build.rs"); } diff --git a/system/gd/rust/linux/stack/src/battery_manager.rs b/system/gd/rust/linux/stack/src/battery_manager.rs index 24deebadfa00dc11a4960f8f880669ef64e5bf6d..393761c448673d0f0099b764794ffb518d9dfdd3 100644 --- a/system/gd/rust/linux/stack/src/battery_manager.rs +++ b/system/gd/rust/linux/stack/src/battery_manager.rs @@ -3,6 +3,7 @@ use crate::callbacks::Callbacks; use crate::uuid; use crate::Message; use crate::RPCProxy; +use itertools::Itertools; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::Sender; @@ -49,7 +50,7 @@ pub trait IBatteryManager { ) -> u32; /// Unregister a callback. - fn unregister_battery_callback(&mut self, callback_id: u32); + fn unregister_battery_callback(&mut self, callback_id: u32) -> bool; /// Returns battery information for the remote, sourced from the highest priority origin. fn get_battery_information(&self, remote_address: String) -> Option; @@ -72,8 +73,8 @@ impl BatteryManager { } /// Remove a callback due to disconnection or unregistration. - pub fn remove_callback(&mut self, callback_id: u32) { - self.callbacks.remove_callback(callback_id); + pub fn remove_callback(&mut self, callback_id: u32) -> bool { + self.callbacks.remove_callback(callback_id) } /// Handles a BatterySet update. @@ -92,8 +93,8 @@ impl IBatteryManager for BatteryManager { self.callbacks.add_callback(battery_manager_callback) } - fn unregister_battery_callback(&mut self, callback_id: u32) { - self.remove_callback(callback_id); + fn unregister_battery_callback(&mut self, callback_id: u32) -> bool { + self.remove_callback(callback_id) } fn get_battery_information(&self, remote_address: String) -> Option { @@ -137,11 +138,22 @@ impl Batteries { } } + pub fn remove_battery_set(&mut self, uuid: &String) { + self.0.retain(|battery_set| &battery_set.source_uuid != uuid); + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + /// Returns the best BatterySet from among reported battery data. pub fn pick_best(&self) -> Option { self.0 .iter() - .find(|battery_set| battery_set.source_uuid == uuid::BAS) + .filter(|battery_set| !battery_set.batteries.is_empty()) + // Now we prefer BAS, but we might need to prioritize other sources first + // TODO (b/295577710): Make a preference list + .find_or_first(|battery_set| battery_set.source_uuid == uuid::BAS) .or_else(|| self.0.first()) .cloned() } diff --git a/system/gd/rust/linux/stack/src/battery_provider_manager.rs b/system/gd/rust/linux/stack/src/battery_provider_manager.rs index e9a0b942834ea18c1c8b49e73d9838b70da75348..a0138e2787c914784950b5e9bf076692a704af8f 100644 --- a/system/gd/rust/linux/stack/src/battery_provider_manager.rs +++ b/system/gd/rust/linux/stack/src/battery_provider_manager.rs @@ -1,6 +1,7 @@ use crate::battery_manager::{Batteries, BatterySet}; use crate::callbacks::Callbacks; use crate::{Message, RPCProxy}; +use log::debug; use std::collections::HashMap; use tokio::sync::mpsc::Sender; @@ -24,6 +25,9 @@ pub trait IBatteryProviderManager { /// Updates the battery information for the battery associated with battery_id. fn set_battery_info(&mut self, battery_provider_id: u32, battery_set: BatterySet); + + /// Removes the battery information for the battery associated with battery_id. + fn remove_battery_info(&mut self, battery_provider_id: u32, address: String, uuid: String); } /// Represents the BatteryProviderManager, a central point for collecting battery information from @@ -74,12 +78,34 @@ impl IBatteryProviderManager for BatteryProviderManager { self.remove_battery_provider_callback(battery_provider_id); } + fn remove_battery_info(&mut self, _battery_provider_id: u32, address: String, uuid: String) { + if let Some(batteries) = self.battery_info.get_mut(&address) { + batteries.remove_battery_set(&uuid); + + if batteries.is_empty() { + self.battery_info.remove(&address); + } + } + } + fn set_battery_info(&mut self, _battery_provider_id: u32, battery_set: BatterySet) { + debug!( + "BatteryProviderManager received BatterySet for [{}] from \"{}\": {:?}", + battery_set.address.clone(), + battery_set.source_info.clone(), + battery_set.clone() + ); + + if battery_set.batteries.is_empty() { + return; + } + let batteries = self .battery_info .entry(battery_set.address.clone()) .or_insert_with(|| Batteries::new()); batteries.add_or_update_battery_set(battery_set); + if let Some(best_battery_set) = batteries.pick_best() { let tx = self.tx.clone(); tokio::spawn(async move { diff --git a/system/gd/rust/linux/stack/src/battery_service.rs b/system/gd/rust/linux/stack/src/battery_service.rs index a3bbf80f5b5122984c489b1e4f45814763413701..72dd5313b17d70e189be2cebf9b9d204bbb244c7 100644 --- a/system/gd/rust/linux/stack/src/battery_service.rs +++ b/system/gd/rust/linux/stack/src/battery_service.rs @@ -7,10 +7,10 @@ use crate::bluetooth_gatt::{ BluetoothGatt, BluetoothGattService, IBluetoothGatt, IBluetoothGattCallback, }; use crate::callbacks::Callbacks; -use crate::uuid; use crate::uuid::UuidHelper; use crate::Message; use crate::RPCProxy; +use crate::{uuid, APIMessage, BluetoothAPI}; use bt_topshim::btif::BtTransport; use bt_topshim::profiles::gatt::{GattStatus, LePhy}; use log::debug; @@ -31,6 +31,8 @@ pub struct BatteryService { battery_provider_id: u32, /// Sender for callback communication with the main thread. tx: Sender, + /// Sender for callback communication with the api message thread. + api_tx: Sender, callbacks: Callbacks, /// The GATT client ID needed for GATT calls. client_id: Option, @@ -98,6 +100,7 @@ impl BatteryService { gatt: Arc>>, battery_provider_manager: Arc>>, tx: Sender, + api_tx: Sender, ) -> BatteryService { let tx = tx.clone(); let callbacks = Callbacks::new(tx.clone(), Message::BatteryServiceCallbackDisconnected); @@ -113,6 +116,7 @@ impl BatteryService { battery_provider_manager, battery_provider_id, tx, + api_tx, callbacks, client_id, battery_sets, @@ -126,7 +130,7 @@ impl BatteryService { self.gatt.lock().unwrap().register_client( // TODO(b/233101174): make dynamic or decide on a static UUID String::from("e4d2acffcfaa42198f494606b7412117"), - Box::new(GattCallback::new(self.tx.clone())), + Box::new(GattCallback::new(self.tx.clone(), self.api_tx.clone())), false, ); } @@ -243,7 +247,7 @@ impl BatteryService { fn set_battery_info(&mut self, remote_address: &String, value: &Vec) -> BatterySet { let level: Vec<_> = value.iter().cloned().chain(iter::repeat(0 as u8)).take(4).collect(); let level = u32::from_le_bytes(level.try_into().unwrap()); - debug!("Received battery level for {}: {}", remote_address.clone(), level); + debug!("BAS received battery level for {}: {}", remote_address.clone(), level); let battery_set = self.battery_sets.entry(remote_address.clone()).or_insert_with(|| { BatterySet::new( remote_address.clone(), @@ -284,14 +288,10 @@ impl BatteryService { None => return, } // Let BatteryProviderManager know that BAS no longer has a battery for this device. - self.battery_provider_manager.lock().unwrap().set_battery_info( + self.battery_provider_manager.lock().unwrap().remove_battery_info( self.battery_provider_id, - BatterySet::new( - remote_address.clone(), - uuid::BAS.to_string(), - "BAS".to_string(), - vec![], - ), + remote_address.clone(), + uuid::BAS.to_string(), ); self.battery_sets.remove(&remote_address); } @@ -373,11 +373,12 @@ impl RPCProxy for BatteryProviderCallback { struct GattCallback { tx: Sender, + api_tx: Sender, } impl GattCallback { - fn new(tx: Sender) -> Self { - Self { tx } + fn new(tx: Sender, api_tx: Sender) -> Self { + Self { tx, api_tx } } } @@ -388,12 +389,14 @@ impl IBluetoothGattCallback for GattCallback { fn on_client_registered(&mut self, status: GattStatus, client_id: i32) { let tx = self.tx.clone(); + let api_tx = self.api_tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryService(BatteryServiceActions::OnClientRegistered( status, client_id, ))) .await; + let _ = api_tx.send(APIMessage::IsReady(BluetoothAPI::Battery)).await; }); } diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs index 910d04af7846fb8b94ca962df3b849bca8687cd7..6514edf49bdc316c36e55e804ae27133b87c1b67 100644 --- a/system/gd/rust/linux/stack/src/bluetooth.rs +++ b/system/gd/rust/linux/stack/src/bluetooth.rs @@ -2,10 +2,10 @@ use bt_topshim::btif::{ BaseCallbacks, BaseCallbacksDispatcher, BluetoothInterface, BluetoothProperty, BtAclState, - BtBondState, BtConnectionDirection, BtConnectionState, BtDeviceType, BtDiscMode, + BtAddrType, BtBondState, BtConnectionDirection, BtConnectionState, BtDeviceType, BtDiscMode, BtDiscoveryState, BtHciErrorCode, BtPinCode, BtPropertyType, BtScanMode, BtSspVariant, BtState, - BtStatus, BtTransport, BtVendorProductInfo, DisplayAddress, RawAddress, ToggleableProfile, - Uuid, Uuid128Bit, + BtStatus, BtThreadEvent, BtTransport, BtVendorProductInfo, DisplayAddress, RawAddress, + ToggleableProfile, Uuid, Uuid128Bit, INVALID_RSSI, }; use bt_topshim::{ metrics, @@ -21,12 +21,13 @@ use bt_topshim::{ use bt_utils::array_utils; use bt_utils::cod::{is_cod_hid_combo, is_cod_hid_keyboard}; +use bt_utils::uhid::{UHid, BD_ADDR_DEFAULT}; use btif_macros::{btif_callback, btif_callbacks_dispatcher}; use log::{debug, warn}; use num_traits::cast::ToPrimitive; use num_traits::pow; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::fs::File; use std::hash::Hash; @@ -41,13 +42,16 @@ use tokio::time; use crate::battery_service::BatteryServiceActions; use crate::bluetooth_admin::{BluetoothAdmin, IBluetoothAdmin}; -use crate::bluetooth_gatt::{BluetoothGatt, IBluetoothGatt, IScannerCallback, ScanResult}; +use crate::bluetooth_gatt::{ + BluetoothGatt, GattActions, IBluetoothGatt, IScannerCallback, ScanResult, +}; use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions}; use crate::callbacks::Callbacks; +use crate::socket_manager::SocketActions; use crate::uuid::{Profile, UuidHelper, HOGP}; -use crate::{Message, RPCProxy, SuspendMode}; +use crate::{APIMessage, BluetoothAPI, Message, RPCProxy, SuspendMode}; -const FLOSS_VER: u16 = 0x0001; +pub(crate) const FLOSS_VER: u16 = 0x0001; const DEFAULT_DISCOVERY_TIMEOUT_MS: u64 = 12800; const MIN_ADV_INSTANCES_FOR_MULTI_ADV: u8 = 5; @@ -65,7 +69,10 @@ const PID_DIR: &str = "/var/run/bluetooth"; /// Defines the adapter API. pub trait IBluetooth { /// Adds a callback from a client who wishes to observe adapter events. - fn register_callback(&mut self, callback: Box); + fn register_callback(&mut self, callback: Box) -> u32; + + /// Removes registered callback. + fn unregister_callback(&mut self, callback_id: u32) -> bool; /// Adds a callback from a client who wishes to observe connection events. fn register_connection_callback( @@ -76,6 +83,9 @@ pub trait IBluetooth { /// Removes registered callback. fn unregister_connection_callback(&mut self, callback_id: u32) -> bool; + /// Inits the bluetooth interface. Should always be called before enable. + fn init(&mut self, init_flags: Vec) -> bool; + /// Enables the adapter. /// /// Returns true if the request is accepted. @@ -86,6 +96,9 @@ pub trait IBluetooth { /// Returns true if the request is accepted. fn disable(&mut self) -> bool; + /// Cleans up the bluetooth interface. Should always be called after disable. + fn cleanup(&mut self); + /// Returns the Bluetooth address of the local adapter. fn get_address(&self) -> String; @@ -136,10 +149,10 @@ pub trait IBluetooth { fn create_bond(&mut self, device: BluetoothDevice, transport: BtTransport) -> bool; /// Cancels any pending bond attempt on given device. - fn cancel_bond_process(&self, device: BluetoothDevice) -> bool; + fn cancel_bond_process(&mut self, device: BluetoothDevice) -> bool; /// Removes pairing for given device. - fn remove_bond(&self, device: BluetoothDevice) -> bool; + fn remove_bond(&mut self, device: BluetoothDevice) -> bool; /// Returns a list of known bonded devices. fn get_bonded_devices(&self) -> Vec; @@ -180,6 +193,15 @@ pub trait IBluetooth { /// Gets whether the remote device can wake the system. fn get_remote_wake_allowed(&self, device: BluetoothDevice) -> bool; + /// Gets the vendor and product information of the remote device. + fn get_remote_vendor_product_info(&self, device: BluetoothDevice) -> BtVendorProductInfo; + + /// Get the address type of the remote device. + fn get_remote_address_type(&self, device: BluetoothDevice) -> BtAddrType; + + /// Get the RSSI of the remote device. + fn get_remote_rssi(&self, device: BluetoothDevice) -> i8; + /// Returns a list of connected devices. fn get_connected_devices(&self) -> Vec; @@ -208,6 +230,8 @@ pub trait IBluetooth { fn connect_all_enabled_profiles(&mut self, device: BluetoothDevice) -> bool; /// Disconnect all profiles supported by device and enabled on adapter. + /// Note that it includes all custom profiles enabled by the users e.g. through SocketManager or + /// BluetoothGatt interfaces; The device shall be disconnected on baseband eventually. fn disconnect_all_enabled_profiles(&mut self, device: BluetoothDevice) -> bool; /// Returns whether WBS is supported. @@ -370,11 +394,27 @@ impl BluetoothDeviceContext { } } +/// Structure to track all the signals for SIGTERM. +pub struct SigData { + pub enabled: Mutex, + pub enabled_notify: Condvar, + + pub thread_attached: Mutex, + pub thread_notify: Condvar, +} + /// The interface for adapter callbacks registered through `IBluetooth::register_callback`. pub trait IBluetoothCallback: RPCProxy { /// When any adapter property changes. fn on_adapter_property_changed(&mut self, prop: BtPropertyType); + /// When any device properties change. + fn on_device_properties_changed( + &mut self, + remote_device: BluetoothDevice, + props: Vec, + ); + /// When any of the adapter local address is changed. fn on_address_changed(&mut self, addr: String); @@ -451,7 +491,8 @@ pub trait IBluetoothConnectionCallback: RPCProxy { pub struct Bluetooth { intf: Arc>, - adapter_index: i32, + virt_index: i32, + hci_index: i32, bonded_devices: HashMap, ble_scanner_id: Option, ble_scanner_uuid: Option, @@ -476,26 +517,34 @@ pub struct Bluetooth { sdp: Option, state: BtState, tx: Sender, + api_tx: Sender, // Internal API members discoverable_timeout: Option>, + cancelling_devices: HashSet, /// Used to notify signal handler that we have turned off the stack. - sig_notifier: Arc<(Mutex, Condvar)>, + sig_notifier: Arc, + + /// Virtual uhid device created to keep bluetooth as a wakeup source. + uhid_wakeup_source: UHid, } impl Bluetooth { /// Constructs the IBluetooth implementation. pub fn new( - adapter_index: i32, + virt_index: i32, + hci_index: i32, tx: Sender, - sig_notifier: Arc<(Mutex, Condvar)>, + api_tx: Sender, + sig_notifier: Arc, intf: Arc>, bluetooth_admin: Arc>>, bluetooth_gatt: Arc>>, bluetooth_media: Arc>>, ) -> Bluetooth { Bluetooth { - adapter_index, + virt_index, + hci_index, bonded_devices: HashMap::new(), callbacks: Callbacks::new(tx.clone(), Message::AdapterCallbackDisconnected), connection_callbacks: Callbacks::new( @@ -524,9 +573,12 @@ impl Bluetooth { sdp: None, state: BtState::Off, tx, + api_tx, // Internal API members discoverable_timeout: None, + cancelling_devices: HashSet::new(), sig_notifier, + uhid_wakeup_source: UHid::new(), } } @@ -592,8 +644,12 @@ impl Bluetooth { } } + pub(crate) fn get_hci_index(&self) -> u16 { + self.hci_index as u16 + } + pub fn toggle_enabled_profiles(&mut self, allowed_services: &Vec) { - for profile in UuidHelper::get_supported_profiles().clone() { + for profile in UuidHelper::get_ordered_supported_profiles().clone() { // Only toggle initializable profiles. if let Some(enabled) = self.is_profile_enabled(&profile) { let allowed = allowed_services.len() == 0 @@ -628,6 +684,8 @@ impl Bluetooth { } pub fn init_profiles(&mut self) { + self.bluetooth_gatt.lock().unwrap().enable(true); + let sdptx = self.tx.clone(); self.sdp = Some(Sdp::new(&self.intf.lock().unwrap())); self.sdp.as_mut().unwrap().initialize(SdpCallbacksDispatcher { @@ -767,14 +825,55 @@ impl Bluetooth { } } - /// Caches the discoverable mode into BluetoothQA. - pub fn cache_discoverable_mode_into_qa(&self) { - let disc_mode = self.get_discoverable_mode_internal(); + /// Returns adapter's alias. + pub(crate) fn get_alias_internal(&self) -> String { + let name = self.get_name(); + if !name.is_empty() { + return name; + } - let txl = self.tx.clone(); - tokio::spawn(async move { - let _ = txl.send(Message::QaOnDiscoverableModeChanged(disc_mode)).await; - }); + // If the adapter name is empty, generate one based on local BDADDR + // so that test programs can have a friendly name for the adapter. + match self.local_address { + None => "floss_0000".to_string(), + Some(addr) => format!("floss_{:02X}{:02X}", addr.address[4], addr.address[5]), + } + } + + pub(crate) fn get_hid_report_internal( + &mut self, + addr: String, + report_type: BthhReportType, + report_id: u8, + ) -> BtStatus { + if let Some(mut addr) = RawAddress::from_string(addr) { + self.hh.as_mut().unwrap().get_report(&mut addr, report_type, report_id, 128) + } else { + BtStatus::InvalidParam + } + } + + pub(crate) fn set_hid_report_internal( + &mut self, + addr: String, + report_type: BthhReportType, + report: String, + ) -> BtStatus { + if let Some(mut addr) = RawAddress::from_string(addr) { + let mut rb = report.clone().into_bytes(); + self.hh.as_mut().unwrap().set_report(&mut addr, report_type, rb.as_mut_slice()) + } else { + BtStatus::InvalidParam + } + } + + pub(crate) fn send_hid_data_internal(&mut self, addr: String, data: String) -> BtStatus { + if let Some(mut addr) = RawAddress::from_string(addr) { + let mut rb = data.clone().into_bytes(); + self.hh.as_mut().unwrap().send_data(&mut addr, rb.as_mut_slice()) + } else { + BtStatus::InvalidParam + } } /// Returns all bonded and connected devices. @@ -797,12 +896,6 @@ impl Bluetooth { /// Check whether found devices are still fresh. If they're outside the /// freshness window, send a notification to clear the device from clients. fn trigger_freshness_check(&mut self) { - if let Some(ref handle) = self.freshness_check { - // Abort and drop the previous JoinHandle. - handle.abort(); - self.freshness_check = None; - } - // A found device is considered fresh if: // * It was last seen less than |FOUND_DEVICE_FRESHNESS| ago. // * It is currently connected. @@ -829,18 +922,6 @@ impl Bluetooth { self.bluetooth_admin.lock().unwrap().on_device_cleared(&d); } - - // If we have any fresh devices remaining, re-queue a freshness check. - if self.found_devices.len() > 0 { - let txl = self.tx.clone(); - - self.freshness_check = Some(tokio::spawn(async move { - time::sleep(FOUND_DEVICE_FRESHNESS).await; - let _ = txl - .send(Message::DelayedAdapterActions(DelayedActions::DeviceFreshnessCheck)) - .await; - })); - } } /// Makes an LE_RAND call to the Bluetooth interface. @@ -954,7 +1035,7 @@ impl Bluetooth { /// Creates a file to notify btmanagerd the adapter is enabled. fn create_pid_file(&self) -> std::io::Result<()> { - let file_name = format!("{}/bluetooth{}.pid", PID_DIR, self.adapter_index); + let file_name = format!("{}/bluetooth{}.pid", PID_DIR, self.virt_index); let mut f = File::create(&file_name)?; f.write_all(process::id().to_string().as_bytes())?; Ok(()) @@ -962,7 +1043,7 @@ impl Bluetooth { /// Removes the file to notify btmanagerd the adapter is disabled. fn remove_pid_file(&self) -> std::io::Result<()> { - let file_name = format!("{}/bluetooth{}.pid", PID_DIR, self.adapter_index); + let file_name = format!("{}/bluetooth{}.pid", PID_DIR, self.virt_index); std::fs::remove_file(&file_name)?; Ok(()) } @@ -1021,11 +1102,43 @@ impl Bluetooth { /// Remove the paused flag to allow clients to begin discovery, and if there is already a /// pending request, start discovery. fn resume_discovery(&mut self) { + self.is_discovery_paused = false; if self.pending_discovery { self.pending_discovery = false; self.start_discovery(); } - self.is_discovery_paused = false; + } + + /// Return if there are wake-allowed device in bonded status. + fn get_wake_allowed_device_bonded(&self) -> bool { + self.get_bonded_devices().into_iter().any(|d| self.get_remote_wake_allowed(d)) + } + + /// Powerd recognizes bluetooth activities as valid wakeup sources if powerd keeps bluetooth in + /// the monitored path. This only happens if there is at least one valid wake-allowed BT device + /// connected during the suspending process. If there is no BT devices connected at any time + /// during the suspending process, the wakeup count will be lost, and system goes to dark + /// resume instead of full resume. + /// Bluetooth stack disconnects all physical bluetooth HID devices for suspend, so a virtual + /// uhid device is necessary to keep bluetooth as a valid wakeup source. + fn create_uhid_for_suspend_wakesource(&mut self) { + if !self.uhid_wakeup_source.is_empty() { + return; + } + let adapter_addr = self.get_address().to_lowercase(); + match self.uhid_wakeup_source.create( + "VIRTUAL_SUSPEND_UHID".to_string(), + adapter_addr, + String::from(BD_ADDR_DEFAULT), + ) { + Err(e) => log::error!("Fail to create uhid {}", e), + Ok(_) => (), + } + } + + /// Clear the UHID device. + fn clear_uhid(&mut self) { + self.uhid_wakeup_source.clear(); } } @@ -1106,6 +1219,9 @@ pub(crate) trait BtifBluetoothCallbacks { min_16_digit: bool, ) { } + + #[btif_callback(ThreadEvent)] + fn thread_event(&mut self, event: BtThreadEvent) {} } #[btif_callbacks_dispatcher(dispatch_hid_host_callbacks, HHCallbacks)] @@ -1172,15 +1288,20 @@ impl BtifBluetoothCallbacks for Bluetooth { _ => (), } + self.clear_uhid(); + // Let the signal notifier know we are turned off. - *self.sig_notifier.0.lock().unwrap() = false; - self.sig_notifier.1.notify_all(); + *self.sig_notifier.enabled.lock().unwrap() = false; + self.sig_notifier.enabled_notify.notify_all(); } BtState::On => { // Initialize media self.bluetooth_media.lock().unwrap().initialize(); + // Initialize core profiles + self.init_profiles(); + // Trigger properties update self.intf.lock().unwrap().get_adapter_properties(); @@ -1197,9 +1318,26 @@ impl BtifBluetoothCallbacks for Bluetooth { // Ensure device is connectable so that disconnected device can reconnect self.set_connectable(true); + // Spawn a freshness check job in the background. + self.freshness_check.take().map(|h| h.abort()); + let txl = self.tx.clone(); + self.freshness_check = Some(tokio::spawn(async move { + loop { + time::sleep(FOUND_DEVICE_FRESHNESS).await; + let _ = txl + .send(Message::DelayedAdapterActions( + DelayedActions::DeviceFreshnessCheck, + )) + .await; + } + })); + + if self.get_wake_allowed_device_bonded() { + self.create_uhid_for_suspend_wakesource(); + } // Notify the signal notifier that we are turned on. - *self.sig_notifier.0.lock().unwrap() = true; - self.sig_notifier.1.notify_all(); + *self.sig_notifier.enabled.lock().unwrap() = true; + self.sig_notifier.enabled_notify.notify_all(); // Signal that the stack is up and running. match self.create_pid_file() { @@ -1209,9 +1347,15 @@ impl BtifBluetoothCallbacks for Bluetooth { // Inform the rest of the stack we're ready. let txl = self.tx.clone(); + let api_txl = self.api_tx.clone(); tokio::spawn(async move { let _ = txl.send(Message::AdapterReady).await; }); + tokio::spawn(async move { + let _ = api_txl.send(APIMessage::IsReady(BluetoothAPI::Adapter)).await; + // TODO(b:300202052) make sure media interface is exposed after initialized + let _ = api_txl.send(APIMessage::IsReady(BluetoothAPI::Media)).await; + }); } } } @@ -1259,8 +1403,6 @@ impl BtifBluetoothCallbacks for Bluetooth { }); } BluetoothProperty::AdapterScanMode(mode) => { - self.cache_discoverable_mode_into_qa(); - self.callbacks.for_all_callbacks(|callback| { callback .on_discoverable_changed(*mode == BtScanMode::ConnectableDiscoverable); @@ -1330,13 +1472,6 @@ impl BtifBluetoothCallbacks for Bluetooth { callback.on_discovering_changed(state == BtDiscoveryState::Started); }); - // Stopped discovering and no freshness check is active. Immediately do - // freshness check which will schedule a recurring future until all - // entries are cleared. - if !is_discovering && self.freshness_check.is_none() { - self.trigger_freshness_check(); - } - // Start or stop BLE scanning based on discovering state if let Some(scanner_id) = self.ble_scanner_id { if is_discovering { @@ -1382,7 +1517,7 @@ impl BtifBluetoothCallbacks for Bluetooth { }; if is_cod_hid_keyboard(cod) || is_cod_hid_combo(cod) { - debug!("auto gen pin for device {} (cod={:#x})", device.address, cod); + debug!("auto gen pin for device {} (cod={:#x})", DisplayAddress(&remote_addr), cod); // generate a random pin code to display. let pin = rand::random::() % pow(10, digits); let display_pin = format!("{:06}", pin); @@ -1397,7 +1532,11 @@ impl BtifBluetoothCallbacks for Bluetooth { self.set_pin(device, true, pin_vec); } else { - debug!("sending pin request for device {} (cod={:#x}) to clients", device.address, cod); + debug!( + "sending pin request for device {} (cod={:#x}) to clients", + DisplayAddress(&remote_addr), + cod + ); // Currently this supports many agent because we accept many callbacks. // TODO(b/274706838): We need a way to select the default agent. self.callbacks.for_all_callbacks(|callback| { @@ -1426,6 +1565,9 @@ impl BtifBluetoothCallbacks for Bluetooth { self.found_devices .entry(address.clone()) .and_modify(|d| d.bond_state = bond_state.clone()); + if !self.get_wake_allowed_device_bonded() { + self.clear_uhid(); + } } // We will only insert into the bonded list after bonding is complete else if &bond_state == &BtBondState::Bonded && !self.bonded_devices.contains_key(&address) @@ -1452,6 +1594,9 @@ impl BtifBluetoothCallbacks for Bluetooth { device.services_resolved = false; self.bonded_devices.insert(address.clone(), device); self.fetch_remote_uuids(device_info); + if self.get_wake_allowed_device_bonded() { + self.create_uhid_for_suspend_wakesource(); + } } else { // If we're bonding, we need to update the found devices list self.found_devices @@ -1474,7 +1619,13 @@ impl BtifBluetoothCallbacks for Bluetooth { ); }); - metrics::bond_state_changed(addr, device_type, status, bond_state, fail_reason); + // Don't emit the metrics event if we were cancelling the bond. + // It is ok to not send the pairing complete event as the server should ignore the dangling + // pairing attempt event. + // This behavior aligns with BlueZ. + if !self.cancelling_devices.remove(&addr) { + metrics::bond_state_changed(addr, device_type, status, bond_state, fail_reason); + } } fn remote_device_properties_changed( @@ -1512,19 +1663,18 @@ impl BtifBluetoothCallbacks for Bluetooth { Bluetooth::send_metrics_remote_device_info(d); let info = d.info.clone(); - let has_uuids = d - .properties - .get(&BtPropertyType::Uuids) - .and_then(|prop| match prop { - BluetoothProperty::Uuids(uu) => Some(uu.len() > 0), - _ => None, - }) - .map_or(false, |v| v); - // Services are resolved when uuids are fetched. - d.services_resolved = has_uuids; + if !d.services_resolved { + let has_uuids = properties.iter().any(|prop| match prop { + BluetoothProperty::Uuids(uu) => uu.len() > 0, + _ => false, + }); - if d.wait_to_connect && has_uuids { + // Services are resolved when uuids are fetched. + d.services_resolved |= has_uuids; + } + + if d.wait_to_connect && d.services_resolved { d.wait_to_connect = false; let sent_info = info.clone(); @@ -1537,6 +1687,14 @@ impl BtifBluetoothCallbacks for Bluetooth { }); } + let info = &d.info.clone(); + self.callbacks.for_all_callbacks(|callback| { + callback.on_device_properties_changed( + info.clone(), + properties.clone().into_iter().map(|x| x.get_type()).collect(), + ); + }); + self.bluetooth_admin .lock() .unwrap() @@ -1563,7 +1721,7 @@ impl BtifBluetoothCallbacks for Bluetooth { if status != BtStatus::Success { warn!( "Connection to [{}] failed. Status: {:?}, Reason: {:?}", - addr.to_string(), + DisplayAddress(&addr), status, hci_reason ); @@ -1650,6 +1808,21 @@ impl BtifBluetoothCallbacks for Bluetooth { None => (), }; } + + fn thread_event(&mut self, event: BtThreadEvent) { + match event { + BtThreadEvent::Associate => { + // Let the signal notifier know stack is initialized. + *self.sig_notifier.thread_attached.lock().unwrap() = true; + self.sig_notifier.thread_notify.notify_all(); + } + BtThreadEvent::Disassociate => { + // Let the signal notifier know stack is done. + *self.sig_notifier.thread_attached.lock().unwrap() = false; + self.sig_notifier.thread_notify.notify_all(); + } + } + } } struct BleDiscoveryCallbacks { @@ -1699,8 +1872,12 @@ impl RPCProxy for BleDiscoveryCallbacks { // TODO: Add unit tests for this implementation impl IBluetooth for Bluetooth { - fn register_callback(&mut self, callback: Box) { - self.callbacks.add_callback(callback); + fn register_callback(&mut self, callback: Box) -> u32 { + self.callbacks.add_callback(callback) + } + + fn unregister_callback(&mut self, callback_id: u32) -> bool { + self.callbacks.remove_callback(callback_id) } fn register_connection_callback( @@ -1714,12 +1891,24 @@ impl IBluetooth for Bluetooth { self.connection_callbacks.remove_callback(callback_id) } + fn init(&mut self, init_flags: Vec) -> bool { + self.intf.lock().unwrap().initialize(get_bt_dispatcher(self.tx.clone()), init_flags) + } + fn enable(&mut self) -> bool { self.intf.lock().unwrap().enable() == 0 } fn disable(&mut self) -> bool { - self.intf.lock().unwrap().disable() == 0 + let success = self.intf.lock().unwrap().disable() == 0; + if success { + self.bluetooth_gatt.lock().unwrap().enable(false); + } + success + } + + fn cleanup(&mut self) { + self.intf.lock().unwrap().cleanup(); } fn get_address(&self) -> String { @@ -1947,6 +2136,12 @@ impl IBluetooth for Bluetooth { _ => self.get_remote_type(device.clone()), }; + // There could be a race between bond complete and bond cancel, which makes + // |cancelling_devices| in a wrong state. Remove the device just in case. + if self.cancelling_devices.remove(&address) { + warn!("Device {} is also cancelling the bond.", DisplayAddress(&address)); + } + // We explicitly log the attempt to start the bonding separate from logging the bond state. // The start of the attempt is critical to help identify a bonding/pairing session. metrics::bond_create_attempt(address, device_type.clone()); @@ -1978,7 +2173,7 @@ impl IBluetooth for Bluetooth { return true; } - fn cancel_bond_process(&self, device: BluetoothDevice) -> bool { + fn cancel_bond_process(&mut self, device: BluetoothDevice) -> bool { let addr = RawAddress::from_string(device.address.clone()); if addr.is_none() { @@ -1987,13 +2182,14 @@ impl IBluetooth for Bluetooth { } let address = addr.unwrap(); + if !self.cancelling_devices.insert(address.clone()) { + warn!("Device {} has been added to cancelling_device.", DisplayAddress(&address)); + } + self.intf.lock().unwrap().cancel_bond(&address) == 0 } - fn remove_bond(&self, device: BluetoothDevice) -> bool { - // Temporary for debugging b/255849761. Should change to debug after fix. - log::info!("Removing bond for {}", device.address); - + fn remove_bond(&mut self, device: BluetoothDevice) -> bool { let addr = RawAddress::from_string(device.address.clone()); if addr.is_none() { @@ -2002,6 +2198,14 @@ impl IBluetooth for Bluetooth { } let address = addr.unwrap(); + debug!("Removing bond for {}", DisplayAddress(&address)); + + // There could be a race between bond complete and bond cancel, which makes + // |cancelling_devices| in a wrong state. Remove the device just in case. + if self.cancelling_devices.remove(&address) { + warn!("Device {} is also cancelling the bond.", DisplayAddress(&address)); + } + let status = self.intf.lock().unwrap().remove_bond(&address); if status != 0 { @@ -2035,12 +2239,12 @@ impl IBluetooth for Bluetooth { } fn set_pin(&self, device: BluetoothDevice, accept: bool, pin_code: Vec) -> bool { - let addr = RawAddress::from_string(device.address.clone()); - - if addr.is_none() { + let addr = if let Some(addr) = RawAddress::from_string(device.address.clone()) { + addr + } else { warn!("Can't set pin. Address {} is not valid.", device.address); return false; - } + }; let is_bonding = match self.found_devices.get(&device.address) { Some(d) => d.bond_state == BtBondState::Bonding, @@ -2048,27 +2252,23 @@ impl IBluetooth for Bluetooth { }; if !is_bonding { - warn!("Can't set pin. Device {} isn't bonding.", device.address); + warn!("Can't set pin. Device {} isn't bonding.", DisplayAddress(&addr)); return false; } let mut btpin = BtPinCode { pin: array_utils::to_sized_array(&pin_code) }; - self.intf.lock().unwrap().pin_reply( - &addr.unwrap(), - accept as u8, - pin_code.len() as u8, - &mut btpin, - ) == 0 + self.intf.lock().unwrap().pin_reply(&addr, accept as u8, pin_code.len() as u8, &mut btpin) + == 0 } fn set_passkey(&self, device: BluetoothDevice, accept: bool, passkey: Vec) -> bool { - let addr = RawAddress::from_string(device.address.clone()); - - if addr.is_none() { + let addr = if let Some(addr) = RawAddress::from_string(device.address.clone()) { + addr + } else { warn!("Can't set passkey. Address {} is not valid.", device.address); return false; - } + }; let is_bonding = match self.found_devices.get(&device.address) { Some(d) => d.bond_state == BtBondState::Bonding, @@ -2076,7 +2276,7 @@ impl IBluetooth for Bluetooth { }; if !is_bonding { - warn!("Can't set passkey. Device {} isn't bonding.", device.address); + warn!("Can't set passkey. Device {} isn't bonding.", DisplayAddress(&addr)); return false; } @@ -2085,7 +2285,7 @@ impl IBluetooth for Bluetooth { let passkey = u32::from_ne_bytes(tmp); self.intf.lock().unwrap().ssp_reply( - &addr.unwrap(), + &addr, BtSspVariant::PasskeyEntry, accept as u8, passkey, @@ -2169,6 +2369,27 @@ impl IBluetooth for Bluetooth { } } + fn get_remote_vendor_product_info(&self, device: BluetoothDevice) -> BtVendorProductInfo { + match self.get_remote_device_property(&device, &BtPropertyType::VendorProductInfo) { + Some(BluetoothProperty::VendorProductInfo(p)) => p.clone(), + _ => BtVendorProductInfo { vendor_id_src: 0, vendor_id: 0, product_id: 0, version: 0 }, + } + } + + fn get_remote_address_type(&self, device: BluetoothDevice) -> BtAddrType { + match self.get_remote_device_property(&device, &BtPropertyType::RemoteAddrType) { + Some(BluetoothProperty::RemoteAddrType(addr_type)) => addr_type, + _ => BtAddrType::Unknown, + } + } + + fn get_remote_rssi(&self, device: BluetoothDevice) -> i8 { + match self.get_remote_device_property(&device, &BtPropertyType::RemoteRssi) { + Some(BluetoothProperty::RemoteRssi(rssi)) => rssi, + _ => INVALID_RSSI, + } + } + fn get_connected_devices(&self) -> Vec { let bonded_connected: HashMap = self .bonded_devices @@ -2236,7 +2457,7 @@ impl IBluetooth for Bluetooth { let device = match self.get_remote_device_if_found(&remote_device.address) { Some(v) => v, None => { - warn!("Won't fetch UUIDs on unknown device {}", remote_device.address); + warn!("Won't fetch UUIDs on unknown device"); return false; } }; @@ -2486,6 +2707,22 @@ impl IBluetooth for Bluetooth { } } + // Disconnect all socket connections + if let Some(raw_addr) = RawAddress::from_string(device.address.clone()) { + let txl = self.tx.clone(); + topstack::get_runtime().spawn(async move { + let _ = txl + .send(Message::SocketManagerActions(SocketActions::DisconnectAll(raw_addr))) + .await; + }); + } + + // Disconnect all GATT connections + let txl = self.tx.clone(); + topstack::get_runtime().spawn(async move { + let _ = txl.send(Message::GattActions(GattActions::Disconnect(device.clone()))).await; + }); + return true; } @@ -2536,15 +2773,21 @@ impl BtifSdpCallbacks for Bluetooth { callback.on_sdp_search_complete(device_info.clone(), uuid_to_send, records.clone()); }); debug!( - "Sdp search result found: Status({:?}) Address({:?}) Uuid({:?})", - status, address, uuid + "Sdp search result found: Status({:?}) Address({}) Uuid({:?})", + status, + DisplayAddress(&address), + uuid ); } } impl BtifHHCallbacks for Bluetooth { fn connection_state(&mut self, mut address: RawAddress, state: BthhConnectionState) { - debug!("Hid host connection state updated: Address({:?}) State({:?})", address, state); + debug!( + "Hid host connection state updated: Address({}) State({:?})", + DisplayAddress(&address), + state + ); // HID or HOG is not differentiated by the hid host when callback this function. Assume HOG // if the device is LE only and HID if classic only. And assume HOG if UUID said so when @@ -2579,42 +2822,42 @@ impl BtifHHCallbacks for Bluetooth { } fn hid_info(&mut self, address: RawAddress, info: BthhHidInfo) { - debug!("Hid host info updated: Address({:?}) Info({:?})", address, info); + debug!("Hid host info updated: Address({}) Info({:?})", DisplayAddress(&address), info); } fn protocol_mode(&mut self, address: RawAddress, status: BthhStatus, mode: BthhProtocolMode) { debug!( - "Hid host protocol mode updated: Address({:?}) Status({:?}) Mode({:?})", - address, status, mode + "Hid host protocol mode updated: Address({}) Status({:?}) Mode({:?})", + DisplayAddress(&address), + status, + mode ); } fn idle_time(&mut self, address: RawAddress, status: BthhStatus, idle_rate: i32) { debug!( - "Hid host idle time updated: Address({:?}) Status({:?}) Idle Rate({:?})", - address, status, idle_rate + "Hid host idle time updated: Address({}) Status({:?}) Idle Rate({:?})", + DisplayAddress(&address), + status, + idle_rate ); } - fn get_report( - &mut self, - mut address: RawAddress, - status: BthhStatus, - mut data: Vec, - size: i32, - ) { + fn get_report(&mut self, address: RawAddress, status: BthhStatus, _data: Vec, size: i32) { debug!( - "Hid host got report: Address({:?}) Status({:?}) Report Size({:?})", - address, status, size + "Hid host got report: Address({}) Status({:?}) Report Size({:?})", + DisplayAddress(&address), + status, + size ); - self.hh.as_ref().unwrap().get_report_reply(&mut address, status, &mut data, size as u16); } fn handshake(&mut self, address: RawAddress, status: BthhStatus) { - debug!("Hid host handshake: Address({:?}) Status({:?})", address, status); + debug!("Hid host handshake: Address({}) Status({:?})", DisplayAddress(&address), status); } } +// TODO(b/261143122): Remove these once we migrate to BluetoothQA entirely impl IBluetoothQALegacy for Bluetooth { fn get_connectable(&self) -> bool { self.get_connectable_internal() @@ -2625,17 +2868,7 @@ impl IBluetoothQALegacy for Bluetooth { } fn get_alias(&self) -> String { - let name = self.get_name(); - if !name.is_empty() { - return name; - } - - // If the adapter name is empty, generate one based on local BDADDR - // so that test programs can have a friendly name for the adapter. - match self.local_address { - None => "floss_0000".to_string(), - Some(addr) => format!("floss_{:02X}{:02X}", addr.address[4], addr.address[5]), - } + self.get_alias_internal() } fn get_modalias(&self) -> String { @@ -2648,11 +2881,7 @@ impl IBluetoothQALegacy for Bluetooth { report_type: BthhReportType, report_id: u8, ) -> BtStatus { - if let Some(mut addr) = RawAddress::from_string(addr) { - self.hh.as_mut().unwrap().get_report(&mut addr, report_type, report_id, 128) - } else { - BtStatus::InvalidParam - } + self.get_hid_report_internal(addr, report_type, report_id) } fn set_hid_report( @@ -2661,20 +2890,10 @@ impl IBluetoothQALegacy for Bluetooth { report_type: BthhReportType, report: String, ) -> BtStatus { - if let Some(mut addr) = RawAddress::from_string(addr) { - let mut rb = report.clone().into_bytes(); - self.hh.as_mut().unwrap().set_report(&mut addr, report_type, rb.as_mut_slice()) - } else { - BtStatus::InvalidParam - } + self.set_hid_report_internal(addr, report_type, report) } fn send_hid_data(&mut self, addr: String, data: String) -> BtStatus { - if let Some(mut addr) = RawAddress::from_string(addr) { - let mut rb = data.clone().into_bytes(); - self.hh.as_mut().unwrap().send_data(&mut addr, rb.as_mut_slice()) - } else { - BtStatus::InvalidParam - } + self.send_hid_data_internal(addr, data) } } diff --git a/system/gd/rust/linux/stack/src/bluetooth_admin.rs b/system/gd/rust/linux/stack/src/bluetooth_admin.rs index 96b43a0b57ffd61c9bbb94c5e4b5d92ca9d87b04..508aef5fbff31779c43ccd7178fd336528f69763 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_admin.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_admin.rs @@ -112,7 +112,7 @@ impl BluetoothAdmin { let mut file = File::open(&self.path)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; - let json = serde_json::from_str::(contents.as_str()).unwrap(); + let json = serde_json::from_str::(contents.as_str())?; if let Some(_res) = self.load_config_from_json(&json) { info!("Load settings from {} successfully", &self.path); } diff --git a/system/gd/rust/linux/stack/src/bluetooth_adv.rs b/system/gd/rust/linux/stack/src/bluetooth_adv.rs index af3688533098c5f3ab5958ca25e7c06595fc45ad..6dee294a2ab5800b59b10467b2851686d0211313 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_adv.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_adv.rs @@ -7,7 +7,6 @@ use itertools::Itertools; use log::warn; use num_traits::clamp; use std::collections::HashMap; -use std::sync::atomic::{AtomicIsize, Ordering}; use tokio::sync::mpsc::Sender; use crate::callbacks::Callbacks; @@ -194,6 +193,9 @@ const SOLICIT_AD_TYPES: [u8; 3] = [ LIST_128_BIT_SERVICE_SOLICITATION_UUIDS, ]; +const LEGACY_ADV_DATA_LEN_MAX: usize = 31; +const EXT_ADV_DATA_LEN_MAX: usize = 254; + // Invalid advertising set id. const INVALID_ADV_ID: i32 = 0xff; @@ -249,7 +251,7 @@ impl AdvertiseData { let mut uuid128_bytes = Vec::::new(); // For better transmission efficiency, we generate a compact - // advertisement data byconverting UUIDs into shorter binary forms + // advertisement data by converting UUIDs into shorter binary forms // and then group them by their length in order. // The data generated for UUIDs looks like: // [16-bit_UUID_LIST, 32-bit_UUID_LIST, 128-bit_UUID_LIST]. @@ -341,6 +343,29 @@ impl AdvertiseData { AdvertiseData::append_transport_discovery_data(&mut bytes, &self.transport_discovery_data); bytes } + + /// Validates the raw data as advertisement data. + pub fn validate_raw_data(is_legacy: bool, bytes: &Vec) -> bool { + bytes.len() <= if is_legacy { LEGACY_ADV_DATA_LEN_MAX } else { EXT_ADV_DATA_LEN_MAX } + } + + /// Checks if the advertisement can be upgraded to extended. + pub fn can_upgrade( + parameters: &mut AdvertisingSetParameters, + adv_bytes: &Vec, + is_le_extended_advertising_supported: bool, + ) -> bool { + if parameters.is_legacy + && is_le_extended_advertising_supported + && !AdvertiseData::validate_raw_data(true, adv_bytes) + { + log::info!("Auto upgrading advertisement to extended"); + parameters.is_legacy = false; + return true; + } + + false + } } impl Into @@ -367,9 +392,6 @@ impl Into } } -/// Monotonically increasing counter for reg_id. -static REG_ID_COUNTER: AtomicIsize = AtomicIsize::new(0); - // Keeps information of an advertising set. #[derive(Debug, PartialEq, Copy, Clone)] pub(crate) struct AdvertisingSetInfo { @@ -388,28 +410,40 @@ pub(crate) struct AdvertisingSetInfo { /// Whether the advertising set has been paused. paused: bool, + /// Whether the stop of advertising set is held. + /// This happens when an advertising set is stopped when the system is suspending. + /// The advertising set will be stopped on system resumed. + stopped: bool, + /// Advertising duration, in 10 ms unit. adv_timeout: u16, /// Maximum number of extended advertising events the controller /// shall attempt to send before terminating the extended advertising. adv_events: u8, + + /// Whether the legacy advertisement will be used. + legacy: bool, } impl AdvertisingSetInfo { - pub(crate) fn new(callback_id: CallbackId, adv_timeout: u16, adv_events: u8) -> Self { - let mut reg_id = REG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as RegId; - if reg_id == INVALID_REG_ID { - reg_id = REG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as RegId; - } + pub(crate) fn new( + callback_id: CallbackId, + adv_timeout: u16, + adv_events: u8, + legacy: bool, + reg_id: RegId, + ) -> Self { AdvertisingSetInfo { adv_id: None, callback_id, reg_id, enabled: false, paused: false, + stopped: false, adv_timeout, adv_events, + legacy, } } @@ -454,6 +488,16 @@ impl AdvertisingSetInfo { self.paused } + /// Marks the advertising set as stopped. + pub(crate) fn set_stopped(&mut self) { + self.stopped = true; + } + + /// Returns true if the advertising set has been stopped, false otherwise. + pub(crate) fn is_stopped(&self) -> bool { + self.stopped + } + /// Gets adv_timeout. pub(crate) fn adv_timeout(&self) -> u16 { self.adv_timeout @@ -463,6 +507,11 @@ impl AdvertisingSetInfo { pub(crate) fn adv_events(&self) -> u8 { self.adv_events } + + /// Returns whether the legacy advertisement will be used. + pub(crate) fn is_legacy(&self) -> bool { + self.legacy + } } // Manages advertising sets and the callbacks. @@ -481,6 +530,13 @@ impl Advertisers { } } + // Returns the minimum unoccupied register ID from 0. + pub(crate) fn new_reg_id(&mut self) -> RegId { + (0..) + .find(|id| !self.sets.contains_key(id)) + .expect("There must be an unoccupied register ID") + } + /// Adds an advertising set. pub(crate) fn add(&mut self, s: AdvertisingSetInfo) { if let Some(old) = self.sets.insert(s.reg_id(), s) { @@ -513,6 +569,11 @@ impl Advertisers { self.valid_sets_mut().filter(|s| s.is_paused()) } + /// Returns an iterator of stopped advertising sets. + pub(crate) fn stopped_sets(&self) -> impl Iterator { + self.valid_sets().filter(|s| s.is_stopped()) + } + fn find_reg_id(&self, adv_id: AdvertiserId) -> Option { for (_, s) in &self.sets { if s.adv_id == Some(adv_id) { @@ -624,7 +685,6 @@ impl Advertisers { #[cfg(test)] mod tests { use super::*; - use std::collections::HashSet; use std::iter::FromIterator; #[test] @@ -651,12 +711,31 @@ mod tests { } #[test] - fn test_new_advising_set_info() { - let mut uniq = HashSet::new(); - for callback_id in 0..256 { - let s = AdvertisingSetInfo::new(callback_id, 0, 0); - assert_eq!(s.callback_id(), callback_id); - assert_eq!(uniq.insert(s.reg_id()), true); + fn test_add_remove_advising_set_info() { + let (tx, _rx) = crate::Stack::create_channel(); + let mut advertisers = Advertisers::new(tx.clone()); + for i in 0..35 { + let reg_id = i * 2 as RegId; + let s = AdvertisingSetInfo::new(0 as CallbackId, 0, 0, false, reg_id); + advertisers.add(s); + } + for i in 0..35 { + let expected_reg_id = i * 2 + 1 as RegId; + let reg_id = advertisers.new_reg_id(); + assert_eq!(reg_id, expected_reg_id); + let s = AdvertisingSetInfo::new(0 as CallbackId, 0, 0, false, reg_id); + advertisers.add(s); + } + for i in 0..35 { + let reg_id = i * 2 as RegId; + assert!(advertisers.remove_by_reg_id(reg_id).is_some()); + } + for i in 0..35 { + let expected_reg_id = i * 2 as RegId; + let reg_id = advertisers.new_reg_id(); + assert_eq!(reg_id, expected_reg_id); + let s = AdvertisingSetInfo::new(0 as CallbackId, 0, 0, false, reg_id); + advertisers.add(s); } } @@ -669,7 +748,8 @@ mod tests { for i in 0..size { let callback_id: CallbackId = i as CallbackId; let adv_id: AdvertiserId = i as AdvertiserId; - let mut s = AdvertisingSetInfo::new(callback_id, 0, 0); + let reg_id = advertisers.new_reg_id(); + let mut s = AdvertisingSetInfo::new(callback_id, 0, 0, false, reg_id); s.set_adv_id(Some(adv_id)); advertisers.add(s); } diff --git a/system/gd/rust/linux/stack/src/bluetooth_gatt.rs b/system/gd/rust/linux/stack/src/bluetooth_gatt.rs index c9506116dafeba1c426884e22a892baaa0848135..0ee191f4ae44359606a3e9fd9d776d9fa62aa5c1 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_gatt.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_gatt.rs @@ -18,14 +18,14 @@ use bt_utils::adv_parser; use bt_utils::array_utils; use crate::async_helper::{AsyncHelper, CallbackSender}; -use crate::bluetooth::{Bluetooth, IBluetooth}; +use crate::bluetooth::{Bluetooth, BluetoothDevice, IBluetooth}; use crate::bluetooth_adv::{ - AdvertiseData, Advertisers, AdvertisingSetInfo, AdvertisingSetParameters, + AdvertiseData, AdvertiserId, Advertisers, AdvertisingSetInfo, AdvertisingSetParameters, IAdvertisingSetCallback, PeriodicAdvertisingParameters, INVALID_REG_ID, }; use crate::callbacks::Callbacks; use crate::uuid::UuidHelper; -use crate::{Message, RPCProxy, SuspendMode}; +use crate::{APIMessage, BluetoothAPI, Message, RPCProxy, SuspendMode}; use log::{debug, warn}; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::cast::{FromPrimitive, ToPrimitive}; @@ -33,9 +33,10 @@ use num_traits::clamp; use rand::rngs::SmallRng; use rand::{RngCore, SeedableRng}; use std::collections::{HashMap, HashSet}; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; use std::sync::{Arc, Mutex, MutexGuard}; use tokio::sync::mpsc::Sender; +use tokio::time; struct Client { id: Option, @@ -183,6 +184,14 @@ impl ContextMap { } } + fn get_client_ids_from_address(&self, address: &String) -> Vec { + self.connections + .iter() + .filter(|conn| conn.address == *address) + .map(|conn| conn.client_id) + .collect() + } + fn get_callback_from_callback_id( &mut self, callback_id: u32, @@ -327,6 +336,14 @@ impl ServerContextMap { .map(|conn| conn.conn_id); } + fn get_server_ids_from_address(&self, address: &String) -> Vec { + self.connections + .iter() + .filter(|conn| conn.address == *address) + .map(|conn| conn.server_id) + .collect() + } + fn get_address_from_conn_id(&self, conn_id: i32) -> Option { self.connections .iter() @@ -387,7 +404,7 @@ pub trait IBluetoothGatt { fn start_scan( &mut self, scanner_id: u8, - settings: ScanSettings, + settings: Option, filter: Option, ) -> BtStatus; @@ -406,7 +423,7 @@ pub trait IBluetoothGatt { ) -> u32; /// Unregisters callback for BLE advertising. - fn unregister_advertiser_callback(&mut self, callback_id: u32); + fn unregister_advertiser_callback(&mut self, callback_id: u32) -> bool; /// Creates a new BLE advertising set and start advertising. /// @@ -584,6 +601,8 @@ pub trait IBluetoothGatt { fn configure_mtu(&self, client_id: i32, addr: String, mtu: i32); /// Requests a connection parameter update. + /// This causes |on_connection_updated| to be called if there is already an existing + /// connection to |addr|; Otherwise the method won't generate any callbacks. fn connection_parameter_update( &self, client_id: i32, @@ -1144,7 +1163,7 @@ impl Default for GattWriteType { } } -#[derive(Debug, FromPrimitive, ToPrimitive)] +#[derive(Debug, FromPrimitive, ToPrimitive, Clone)] #[repr(u32)] /// Scan type configuration. pub enum ScanType { @@ -1162,13 +1181,31 @@ impl Default for ScanType { /// /// This configuration is general and supported on all Bluetooth hardware, irrelevant of the /// hardware filter offload (APCF or MSFT). -#[derive(Debug, Default)] +#[derive(Debug, Clone)] pub struct ScanSettings { pub interval: i32, pub window: i32, pub scan_type: ScanType, } +impl ScanSettings { + fn extract_scan_parameters(self) -> Option<(u16, u16)> { + let interval = u16::try_from(self.interval); + if interval.is_err() { + println!("Invalid scan interval {}", self.interval); + return None; + } + + let window = u16::try_from(self.window); + if window.is_err() { + println!("Invalid scan window {}", self.window); + return None; + } + + return Some((interval.unwrap(), window.unwrap())); + } +} + /// Represents scan result #[derive(Debug)] pub struct ScanResult { @@ -1312,13 +1349,22 @@ impl GattAsyncIntf { /// /// Note: this does not need to be async, but declared as async for consistency in this struct. /// May be converted into real async in the future if btif supports it. - async fn update_scan(&mut self) { + async fn update_scan(&mut self, scanner_id: u8, scan_settings: Option) { if self.scanners.lock().unwrap().values().find(|scanner| scanner.is_active).is_some() { // Toggle the scan off and on so that we reset the scan parameters based on whether // we have active scanners using hardware filtering. // TODO(b/266752123): We can do more bookkeeping to optimize when we really need to // toggle. Also improve toggling API into 1 operation that guarantees correct ordering. self.gatt.as_ref().unwrap().lock().unwrap().scanner.stop_scan(); + if let Some(settings) = scan_settings { + if let Some((scan_interval, scan_window)) = settings.extract_scan_parameters() { + self.gatt.as_ref().unwrap().lock().unwrap().scanner.set_scan_parameters( + scanner_id, + scan_interval, + scan_window, + ); + } + } self.gatt.as_ref().unwrap().lock().unwrap().scanner.start_scan(); } else { self.gatt.as_ref().unwrap().lock().unwrap().scanner.stop_scan(); @@ -1326,6 +1372,12 @@ impl GattAsyncIntf { } } +pub enum GattActions { + /// This disconnects all server and client connections to the device. + /// Params: remote_device + Disconnect(BluetoothDevice), +} + /// Implementation of the GATT API (IBluetoothGatt). pub struct BluetoothGatt { intf: Arc>, @@ -1353,6 +1405,7 @@ pub struct BluetoothGatt { small_rng: SmallRng, gatt_async: Arc>, + enabled: bool, } impl BluetoothGatt { @@ -1386,10 +1439,16 @@ impl BluetoothGatt { async_helper_msft_adv_monitor_remove, async_helper_msft_adv_monitor_enable, })), + enabled: false, } } - pub fn init_profiles(&mut self, tx: Sender, adapter: Arc>>) { + pub fn init_profiles( + &mut self, + tx: Sender, + api_tx: Sender, + adapter: Arc>>, + ) { self.gatt = Gatt::new(&self.intf.lock().unwrap()).map(|gatt| Arc::new(Mutex::new(gatt))); self.adapter = Some(adapter); @@ -1464,11 +1523,21 @@ impl BluetoothGatt { let gatt = self.gatt.clone(); let gatt_async = self.gatt_async.clone(); + let api_tx_clone = api_tx.clone(); tokio::spawn(async move { gatt_async.lock().await.gatt = gatt; + // TODO(b/247093293): Gatt topshim api is only usable some + // time after init. Investigate why this delay is needed + // and make it a blocking part before removing this. + time::sleep(time::Duration::from_millis(500)).await; + let _ = api_tx_clone.send(APIMessage::IsReady(BluetoothAPI::Gatt)).await; }); } + pub fn enable(&mut self, enabled: bool) { + self.enabled = enabled; + } + /// Remove a scanner callback and unregisters all scanners associated with that callback. pub fn remove_scanner_callback(&mut self, callback_id: u32) -> bool { let affected_scanner_ids: Vec = self @@ -1580,6 +1649,10 @@ impl BluetoothGatt { /// The resume_scan method is used to resume scanning after system suspension. /// It assumes that scanner.filter has already had the filter data. fn resume_scan(&mut self, scanner_id: u8) -> BtStatus { + if !self.enabled { + return BtStatus::Fail; + } + let scan_suspend_mode = self.get_scan_suspend_mode(); if scan_suspend_mode != SuspendMode::Normal && scan_suspend_mode != SuspendMode::Resuming { return BtStatus::Busy; @@ -1615,13 +1688,6 @@ impl BluetoothGatt { scanner_id: u8, filter: Option, ) -> BtStatus { - let has_active_unfiltered_scanner = self - .scanners - .lock() - .unwrap() - .iter() - .any(|(_uuid, scanner)| scanner.is_active && scanner.filter.is_none()); - let gatt_async = self.gatt_async.clone(); let scanners = self.scanners.clone(); let is_msft_supported = self.is_msft_supported(); @@ -1657,6 +1723,12 @@ impl BluetoothGatt { log::debug!("Added adv monitor handle = {}", monitor_handle); } + let has_active_unfiltered_scanner = scanners + .lock() + .unwrap() + .iter() + .any(|(_uuid, scanner)| scanner.is_active && scanner.filter.is_none()); + if !gatt_async .msft_adv_monitor_enable(!has_active_unfiltered_scanner) .await @@ -1670,7 +1742,10 @@ impl BluetoothGatt { } } - gatt_async.update_scan().await; + let scan_settings = Self::find_scanner_by_id(&mut scanners.lock().unwrap(), scanner_id) + .map_or(None, |s| s.scan_settings.clone()); + + gatt_async.update_scan(scanner_id, scan_settings).await; }); BtStatus::Success @@ -1737,6 +1812,10 @@ impl BluetoothGatt { /// Exits suspend mode for LE advertising. pub fn advertising_exit_suspend(&mut self) { + for id in self.advertisers.stopped_sets().map(|s| s.adv_id()).collect::>() { + self.gatt.as_ref().unwrap().lock().unwrap().advertiser.unregister(id); + self.advertisers.remove_by_advertiser_id(id as AdvertiserId); + } for s in self.advertisers.paused_sets_mut() { s.set_paused(false); self.gatt.as_ref().unwrap().lock().unwrap().advertiser.enable( @@ -1753,27 +1832,63 @@ impl BluetoothGatt { /// Start an active scan on given scanner id. This will look up and assign /// the correct ScanSettings for it as well. pub(crate) fn start_active_scan(&mut self, scanner_id: u8) -> BtStatus { - let interval: u16 = sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanInterval) - .try_into() - .expect("Bad value configured for LeInquiryScanInterval"); - let window: u16 = sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanWindow) - .try_into() - .expect("Bad value configured for LeInquiryScanWindow"); - - self.gatt - .as_ref() - .unwrap() - .lock() - .unwrap() - .scanner - .set_scan_parameters(scanner_id, interval, window); + let settings = ScanSettings { + interval: sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanInterval), + window: sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanWindow), + scan_type: ScanType::Active, + }; - self.start_scan(scanner_id, ScanSettings::default(), /*filter=*/ None) + self.start_scan(scanner_id, Some(settings), /*filter=*/ None) } pub(crate) fn stop_active_scan(&mut self, scanner_id: u8) -> BtStatus { self.stop_scan(scanner_id) } + + pub fn handle_action(&mut self, action: GattActions) { + match action { + GattActions::Disconnect(device) => { + let address = match RawAddress::from_string(&device.address) { + None => { + warn!( + "GattActions::Disconnect failed: Invalid device address={}", + device.address + ); + return; + } + Some(addr) => addr, + }; + for client_id in self.context_map.get_client_ids_from_address(&device.address) { + if let Some(conn_id) = + self.context_map.get_conn_id_from_address(client_id, &device.address) + { + self.gatt + .as_ref() + .unwrap() + .lock() + .unwrap() + .client + .disconnect(client_id, &address, conn_id); + } + } + for server_id in + self.server_context_map.get_server_ids_from_address(&device.address) + { + if let Some(conn_id) = + self.server_context_map.get_conn_id_from_address(server_id, &device.address) + { + self.gatt + .as_ref() + .unwrap() + .lock() + .unwrap() + .server + .disconnect(server_id, &address, conn_id); + } + } + } + } + } } #[derive(Debug, FromPrimitive, ToPrimitive)] @@ -1802,6 +1917,8 @@ struct ScannerInfo { monitor_handle: Option, // Used by start_scan() to determine if it is called because of system resuming. is_suspended: bool, + // The scan parameters to use + scan_settings: Option, } impl ScannerInfo { @@ -1813,6 +1930,7 @@ impl ScannerInfo { filter: None, monitor_handle: None, is_suspended: false, + scan_settings: None, } } } @@ -1895,14 +2013,25 @@ impl IBluetoothGatt for BluetoothGatt { fn start_scan( &mut self, scanner_id: u8, - _settings: ScanSettings, + settings: Option, filter: Option, ) -> BtStatus { + if !self.enabled { + return BtStatus::Fail; + } + let scan_suspend_mode = self.get_scan_suspend_mode(); if scan_suspend_mode != SuspendMode::Normal && scan_suspend_mode != SuspendMode::Resuming { return BtStatus::Busy; } + // If the client is not specifying scan settings, the default one will be used. + let settings = settings.unwrap_or_else(|| ScanSettings { + interval: sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanInterval), + window: sysprop::get_i32(sysprop::PropertyI32::LeInquiryScanWindow), + scan_type: ScanType::Active, + }); + // Multiplexing scanners happens at this layer. The implementations of start_scan // and stop_scan maintains the state of all registered scanners and based on the states // update the scanning and/or filter states of libbluetooth. @@ -1912,6 +2041,7 @@ impl IBluetoothGatt for BluetoothGatt { if let Some(scanner) = Self::find_scanner_by_id(&mut scanners_lock, scanner_id) { scanner.is_active = true; scanner.filter = filter.clone(); + scanner.scan_settings = Some(settings); } else { log::warn!("Scanner {} not found", scanner_id); return BtStatus::Fail; @@ -1922,6 +2052,10 @@ impl IBluetoothGatt for BluetoothGatt { } fn stop_scan(&mut self, scanner_id: u8) -> BtStatus { + if !self.enabled { + return BtStatus::Fail; + } + let scan_suspend_mode = self.get_scan_suspend_mode(); if scan_suspend_mode != SuspendMode::Normal && scan_suspend_mode != SuspendMode::Suspending { @@ -1941,14 +2075,8 @@ impl IBluetoothGatt for BluetoothGatt { } }; - let has_active_unfiltered_scanner = self - .scanners - .lock() - .unwrap() - .iter() - .any(|(_uuid, scanner)| scanner.is_active && scanner.filter.is_none()); - let gatt_async = self.gatt_async.clone(); + let scanners = self.scanners.clone(); let is_msft_supported = self.is_msft_supported(); tokio::spawn(async move { // The two operations below (monitor remove, update scan) happen one after another, and @@ -1963,6 +2091,12 @@ impl IBluetoothGatt for BluetoothGatt { let _res = gatt_async.msft_adv_monitor_remove(handle).await; } + let has_active_unfiltered_scanner = scanners + .lock() + .unwrap() + .iter() + .any(|(_uuid, scanner)| scanner.is_active && scanner.filter.is_none()); + if !gatt_async .msft_adv_monitor_enable(!has_active_unfiltered_scanner) .await @@ -1972,7 +2106,10 @@ impl IBluetoothGatt for BluetoothGatt { } } - gatt_async.update_scan().await; + let scan_settings = Self::find_scanner_by_id(&mut scanners.lock().unwrap(), scanner_id) + .map_or(None, |s| s.scan_settings.clone()); + + gatt_async.update_scan(scanner_id, scan_settings).await; }); BtStatus::Success @@ -1991,14 +2128,14 @@ impl IBluetoothGatt for BluetoothGatt { self.advertisers.add_callback(callback) } - fn unregister_advertiser_callback(&mut self, callback_id: u32) { + fn unregister_advertiser_callback(&mut self, callback_id: u32) -> bool { self.advertisers - .remove_callback(callback_id, &mut self.gatt.as_ref().unwrap().lock().unwrap()); + .remove_callback(callback_id, &mut self.gatt.as_ref().unwrap().lock().unwrap()) } fn start_advertising_set( &mut self, - parameters: AdvertisingSetParameters, + mut parameters: AdvertisingSetParameters, advertise_data: AdvertiseData, scan_response: Option, periodic_parameters: Option, @@ -2012,10 +2149,29 @@ impl IBluetoothGatt for BluetoothGatt { } let device_name = self.get_adapter_name(); - let params = parameters.into(); let adv_bytes = advertise_data.make_with(&device_name); + let is_le_extended_advertising_supported = match &self.adapter { + Some(adapter) => adapter.lock().unwrap().is_le_extended_advertising_supported(), + _ => false, + }; + // TODO(b/311417973): Remove this once we have more robust /device/bluetooth APIs to control extended advertising + let is_legacy = parameters.is_legacy + && !AdvertiseData::can_upgrade( + &mut parameters, + &adv_bytes, + is_le_extended_advertising_supported, + ); + let params = parameters.into(); + if !AdvertiseData::validate_raw_data(is_legacy, &adv_bytes) { + log::warn!("Failed to start advertising set with invalid advertise data"); + return INVALID_REG_ID; + } let scan_bytes = if let Some(d) = scan_response { d.make_with(&device_name) } else { Vec::::new() }; + if !AdvertiseData::validate_raw_data(is_legacy, &scan_bytes) { + log::warn!("Failed to start advertising set with invalid scan response"); + return INVALID_REG_ID; + } let periodic_params = if let Some(p) = periodic_parameters { p.into() } else { @@ -2023,11 +2179,15 @@ impl IBluetoothGatt for BluetoothGatt { }; let periodic_bytes = if let Some(d) = periodic_data { d.make_with(&device_name) } else { Vec::::new() }; + if !AdvertiseData::validate_raw_data(false, &periodic_bytes) { + log::warn!("Failed to start advertising set with invalid periodic data"); + return INVALID_REG_ID; + } let adv_timeout = clamp(duration, 0, 0xffff) as u16; let adv_events = clamp(max_ext_adv_events, 0, 0xff) as u8; - let s = AdvertisingSetInfo::new(callback_id, adv_timeout, adv_events); - let reg_id = s.reg_id(); + let reg_id = self.advertisers.new_reg_id(); + let s = AdvertisingSetInfo::new(callback_id, adv_timeout, adv_events, is_legacy, reg_id); self.advertisers.add(s); self.gatt.as_ref().unwrap().lock().unwrap().advertiser.start_advertising_set( @@ -2044,18 +2204,24 @@ impl IBluetoothGatt for BluetoothGatt { } fn stop_advertising_set(&mut self, advertiser_id: i32) { - if self.advertisers.suspend_mode() != SuspendMode::Normal { + let s = if let Some(s) = self.advertisers.get_by_advertiser_id(advertiser_id) { + s.clone() + } else { return; - } + }; - let s = self.advertisers.get_by_advertiser_id(advertiser_id); - if None == s { + if self.advertisers.suspend_mode() != SuspendMode::Normal { + if !s.is_stopped() { + warn!("Deferred advertisement unregistering due to suspending"); + self.advertisers.get_mut_by_advertiser_id(advertiser_id).unwrap().set_stopped(); + if let Some(cb) = self.advertisers.get_callback(&s) { + cb.on_advertising_set_stopped(advertiser_id); + } + } return; } - let s = s.unwrap().clone(); self.gatt.as_ref().unwrap().lock().unwrap().advertiser.unregister(s.adv_id()); - if let Some(cb) = self.advertisers.get_callback(&s) { cb.on_advertising_set_stopped(advertiser_id); } @@ -2105,6 +2271,10 @@ impl IBluetoothGatt for BluetoothGatt { let bytes = data.make_with(&device_name); if let Some(s) = self.advertisers.get_by_advertiser_id(advertiser_id) { + if !AdvertiseData::validate_raw_data(s.is_legacy(), &bytes) { + log::warn!("Advertiser {}: invalid advertise data to update", advertiser_id); + return; + } self.gatt.as_ref().unwrap().lock().unwrap().advertiser.set_data( s.adv_id(), false, @@ -2119,6 +2289,10 @@ impl IBluetoothGatt for BluetoothGatt { } if let Some(s) = self.advertisers.get_by_advertiser_id(advertiser_id) { + if !AdvertiseData::validate_raw_data(s.is_legacy(), &data) { + log::warn!("Advertiser {}: invalid raw advertise data to update", advertiser_id); + return; + } self.gatt.as_ref().unwrap().lock().unwrap().advertiser.set_data( s.adv_id(), false, @@ -2136,6 +2310,10 @@ impl IBluetoothGatt for BluetoothGatt { let bytes = data.make_with(&device_name); if let Some(s) = self.advertisers.get_by_advertiser_id(advertiser_id) { + if !AdvertiseData::validate_raw_data(s.is_legacy(), &bytes) { + log::warn!("Advertiser {}: invalid scan response to update", advertiser_id); + return; + } self.gatt.as_ref().unwrap().lock().unwrap().advertiser.set_data( s.adv_id(), true, @@ -2214,6 +2392,10 @@ impl IBluetoothGatt for BluetoothGatt { let bytes = data.make_with(&device_name); if let Some(s) = self.advertisers.get_by_advertiser_id(advertiser_id) { + if !AdvertiseData::validate_raw_data(false, &bytes) { + log::warn!("Advertiser {}: invalid periodic data to update", advertiser_id); + return; + } self.gatt .as_ref() .unwrap() @@ -2705,7 +2887,7 @@ impl IBluetoothGatt for BluetoothGatt { let handle = self.server_context_map.get_request_handle_from_id(request_id)?; let len = value.len() as u16; - let data: [u8; 600] = array_utils::to_sized_array(&value); + let data: [u8; 512] = array_utils::to_sized_array(&value); self.gatt.as_ref().unwrap().lock().unwrap().server.send_response( conn_id, @@ -3146,7 +3328,7 @@ impl BtifGattClientCallbacks for BluetoothGatt { } fn congestion_cb(&mut self, conn_id: i32, congested: bool) { - if let Some(mut client) = self.context_map.get_client_by_conn_id_mut(conn_id) { + if let Some(client) = self.context_map.get_client_by_conn_id_mut(conn_id) { client.is_congested = congested; if !client.is_congested { let cbid = client.cbid; @@ -3682,7 +3864,7 @@ impl BtifGattServerCallbacks for BluetoothGatt { } fn congestion_cb(&mut self, conn_id: i32, congested: bool) { - if let Some(mut server) = self.server_context_map.get_mut_by_conn_id(conn_id) { + if let Some(server) = self.server_context_map.get_mut_by_conn_id(conn_id) { server.is_congested = congested; if !server.is_congested { let cbid = server.cbid; @@ -4057,12 +4239,6 @@ impl BtifGattScannerCallbacks for BluetoothGatt { status ); - if status != GattStatus::Success { - log::error!("Error registering scanner UUID {}", uuid); - self.scanners.lock().unwrap().remove(&uuid); - return; - } - let mut scanners_lock = self.scanners.lock().unwrap(); let scanner_info = scanners_lock.get_mut(&uuid); @@ -4079,6 +4255,11 @@ impl BtifGattScannerCallbacks for BluetoothGatt { uuid ); } + + if status != GattStatus::Success { + log::error!("Error registering scanner UUID {}", uuid); + scanners_lock.remove(&uuid); + } } fn on_scan_result( diff --git a/system/gd/rust/linux/stack/src/bluetooth_logging.rs b/system/gd/rust/linux/stack/src/bluetooth_logging.rs index fdfd2452c31610196aa081e3361b67d5bf445641..2fbd181d5e1c83361820f4afdfc314fee235c8f8 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_logging.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_logging.rs @@ -1,6 +1,8 @@ use bt_common::init_flags; use log::LevelFilter; -use syslog::{BasicLogger, Facility, Formatter3164}; +use syslog::{BasicLogger, Error, Facility, Formatter3164}; + +use log_panics; /// API to modify log levels. pub trait IBluetoothLogging { @@ -14,13 +16,20 @@ pub trait IBluetoothLogging { /// Logging related implementation. pub struct BluetoothLogging { is_debug: bool, + is_stderr: bool, + is_initialized: bool, } impl BluetoothLogging { pub fn new(is_debug: bool, log_output: &str) -> Self { - let level = if is_debug { LevelFilter::Debug } else { LevelFilter::Info }; + let is_stderr = log_output == "stderr"; + Self { is_debug, is_stderr, is_initialized: false } + } + + pub fn initialize(&mut self) -> Result<(), Error> { + let level = if self.is_debug { LevelFilter::Debug } else { LevelFilter::Info }; - if log_output == "stderr" { + if self.is_stderr { env_logger::Builder::new().filter(None, level).init(); } else { let formatter = Formatter3164 { @@ -30,21 +39,26 @@ impl BluetoothLogging { pid: 0, }; - let logger = syslog::unix(formatter).expect("could not connect to syslog"); + let logger = syslog::unix(formatter)?; let _ = log::set_boxed_logger(Box::new(BasicLogger::new(logger))) .map(|()| log::set_max_level(level)); + log_panics::init(); } - - Self { is_debug } + self.is_initialized = true; + Ok(()) } } impl IBluetoothLogging for BluetoothLogging { fn is_debug_enabled(&self) -> bool { - self.is_debug + self.is_initialized && self.is_debug } fn set_debug_logging(&mut self, enabled: bool) { + if !self.is_initialized { + return; + } + self.is_debug = enabled; // Update log level in Linux stack. diff --git a/system/gd/rust/linux/stack/src/bluetooth_media.rs b/system/gd/rust/linux/stack/src/bluetooth_media.rs index 97c0405b49c5c9f40a8ce6a136dceb54770b2af7..e96c882f0612b339d8711f4b54f8d759ff455d3a 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_media.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_media.rs @@ -6,24 +6,32 @@ use bt_topshim::btif::{ }; use bt_topshim::profiles::a2dp::{ A2dp, A2dpCallbacks, A2dpCallbacksDispatcher, A2dpCodecBitsPerSample, A2dpCodecChannelMode, - A2dpCodecConfig, A2dpCodecSampleRate, BtavAudioState, BtavConnectionState, - PresentationPosition, + A2dpCodecConfig, A2dpCodecIndex, A2dpCodecPriority, A2dpCodecSampleRate, BtavAudioState, + BtavConnectionState, PresentationPosition, }; use bt_topshim::profiles::avrcp::{ Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher, PlayerMetadata, }; +use bt_topshim::profiles::hfp::interop_insert_call_when_sco_start; use bt_topshim::profiles::hfp::{ - BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallState, Hfp, HfpCallbacks, - HfpCallbacksDispatcher, HfpCodecCapability, PhoneState, TelephonyDeviceStatus, + BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallSource, CallState, Hfp, + HfpCallbacks, HfpCallbacksDispatcher, HfpCodecCapability, HfpCodecId, PhoneState, + TelephonyDeviceStatus, }; use bt_topshim::profiles::ProfileConnectionState; use bt_topshim::{metrics, topstack}; +use bt_utils::at_command_parser::{calculate_battery_percent, parse_at_command_data}; +use bt_utils::uhid_hfp::{ + OutputEvent, UHidHfp, BLUETOOTH_TELEPHONY_UHID_REPORT_ID, UHID_INPUT_HOOK_SWITCH, + UHID_INPUT_PHONE_MUTE, UHID_OUTPUT_MUTE, UHID_OUTPUT_NONE, UHID_OUTPUT_OFF_HOOK, + UHID_OUTPUT_RING, +}; use bt_utils::uinput::UInput; use itertools::Itertools; use log::{debug, info, warn}; use std::collections::{HashMap, HashSet}; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::sync::Arc; use std::sync::Mutex; @@ -42,8 +50,9 @@ use crate::uuid::Profile; use crate::{Message, RPCProxy}; // The timeout we have to wait for all supported profiles to connect after we -// receive the first profile connected event. The host shall disconnect the -// device after this many seconds of timeout. +// receive the first profile connected event. The host shall disconnect or +// force connect the potentially partially connected device after this many +// seconds of timeout. const PROFILE_DISCOVERY_TIMEOUT_SEC: u64 = 10; // The timeout we have to wait for the initiator peer device to complete the // initial profile connection. After this many seconds, we will begin to @@ -73,6 +82,9 @@ pub trait IBluetoothMedia { /// connect to available but missing media profiles fn connect(&mut self, address: String); + + /// disconnect all profiles from the device + /// NOTE: do not call this function from outside unless `is_complete_profiles_required` fn disconnect(&mut self, address: String); // Set the device as the active A2DP device @@ -86,9 +98,11 @@ pub trait IBluetoothMedia { fn set_audio_config( &mut self, - sample_rate: i32, - bits_per_sample: i32, - channel_mode: i32, + address: String, + codec_type: A2dpCodecIndex, + sample_rate: A2dpCodecSampleRate, + bits_per_sample: A2dpCodecBitsPerSample, + channel_mode: A2dpCodecChannelMode, ) -> bool; // Set the A2DP/AVRCP volume. Valid volume specified by the spec should be @@ -111,7 +125,12 @@ pub trait IBluetoothMedia { fn get_presentation_position(&mut self) -> PresentationPosition; /// Start the SCO setup to connect audio - fn start_sco_call(&mut self, address: String, sco_offload: bool, force_cvsd: bool) -> bool; + fn start_sco_call( + &mut self, + address: String, + sco_offload: bool, + disabled_codecs: HfpCodecCapability, + ) -> bool; fn stop_sco_call(&mut self, address: String); /// Set the current playback status: e.g., playing, paused, stopped, etc. The method is a copy @@ -124,6 +143,9 @@ pub trait IBluetoothMedia { /// copy of the existing CRAS API, hence not following Floss API conventions. PlayerMetadata is /// a custom data type that requires special handlng. fn set_player_metadata(&mut self, metadata: PlayerMetadata); + + // Trigger a debug log dump. + fn trigger_debug_dump(&mut self); } pub trait IBluetoothMediaCallback: RPCProxy { @@ -154,9 +176,29 @@ pub trait IBluetoothMediaCallback: RPCProxy { /// waiting for the audio client to issue a reconnection request. We need /// to notify audio client of this event for it to do appropriate handling. fn on_hfp_audio_disconnected(&mut self, addr: String); + + /// Triggered when there is a HFP dump is received. This should only be used + /// for debugging and testing purpose. + fn on_hfp_debug_dump( + &mut self, + active: bool, + codec_id: u16, + total_num_decoded_frames: i32, + pkt_loss_ratio: f64, + begin_ts: u64, + end_ts: u64, + pkt_status_in_hex: String, + pkt_status_in_binary: String, + ); } pub trait IBluetoothTelephony { + /// + fn register_telephony_callback( + &mut self, + callback: Box, + ) -> bool; + /// Sets whether the device is connected to the cellular network. fn set_network_available(&mut self, network_available: bool); /// Sets whether the device is roaming. @@ -166,8 +208,10 @@ pub trait IBluetoothTelephony { /// Sets the device battery level, 0 to 5. fn set_battery_level(&mut self, battery_level: i32) -> bool; /// Enables/disables phone operations. - /// The call state is fully reset whenever this is called. fn set_phone_ops_enabled(&mut self, enable: bool); + /// Enables/disables phone operations for mps qualification. + /// The call state is fully reset whenever this is called. + fn set_mps_qualification_enabled(&mut self, enable: bool); /// Acts like the AG received an incoming call. fn incoming_call(&mut self, number: String) -> bool; /// Acts like dialing a call from the AG. @@ -193,6 +237,10 @@ pub trait IBluetoothTelephony { fn audio_disconnect(&mut self, address: String); } +pub trait IBluetoothTelephonyCallback: RPCProxy { + fn on_telephony_use(&mut self, addr: String, state: bool); +} + /// Serializable device used in. #[derive(Debug, Default, Clone)] pub struct BluetoothAudioDevice { @@ -228,6 +276,13 @@ enum DeviceConnectionStates { ConnectingAfterRetry, // Host initiated requests to missing profiles after timeout FullyConnected, // All profiles (excluding AVRCP) are connected Disconnecting, // Working towards disconnection of each connected profile + WaitingConnection, // Waiting for new connections initiated by peer +} + +struct UHid { + pub handle: UHidHfp, + pub volume: u8, + pub muted: bool, } pub struct BluetoothMedia { @@ -236,6 +291,7 @@ pub struct BluetoothMedia { battery_provider_id: u32, initialized: bool, callbacks: Arc>>, + telephony_callbacks: Arc>>, tx: Sender, adapter: Option>>>, a2dp: Option, @@ -260,8 +316,10 @@ pub struct BluetoothMedia { phone_state: PhoneState, call_list: Vec, phone_ops_enabled: bool, + mps_qualification_enabled: bool, memory_dialing_number: Option, last_dialing_number: Option, + uhid: HashMap, } impl BluetoothMedia { @@ -283,6 +341,10 @@ impl BluetoothMedia { tx.clone(), Message::MediaCallbackDisconnected, ))), + telephony_callbacks: Arc::new(Mutex::new(Callbacks::new( + tx.clone(), + Message::TelephonyCallbackDisconnected, + ))), tx, adapter: None, a2dp: None, @@ -307,8 +369,10 @@ impl BluetoothMedia { phone_state: PhoneState { num_active: 0, num_held: 0, state: CallState::Idle }, call_list: vec![], phone_ops_enabled: false, + mps_qualification_enabled: false, memory_dialing_number: None, last_dialing_number: None, + uhid: HashMap::new(), } } @@ -350,6 +414,7 @@ impl BluetoothMedia { self.delay_volume_update.remove(&profile); if is_profile_critical && self.is_complete_profiles_required() { + BluetoothMedia::disconnect_device(self.tx.clone(), addr); self.notify_critical_profile_disconnected(addr); } @@ -458,9 +523,6 @@ impl BluetoothMedia { self.a2dp_caps.remove(&addr); self.a2dp_audio_state.remove(&addr); self.rm_connected_profile(addr, uuid::Profile::A2dpSink, true); - if self.is_complete_profiles_required() { - self.disconnect(addr.to_string()); - } } _ => { self.a2dp_states.insert(addr, state); @@ -478,6 +540,13 @@ impl BluetoothMedia { } } + fn disconnect_device(txl: Sender, addr: RawAddress) { + let device = BluetoothDevice::new(addr.to_string(), "".to_string()); + topstack::get_runtime().spawn(async move { + let _ = txl.send(Message::DisconnectDevice(device)).await; + }); + } + pub fn dispatch_avrcp_callbacks(&mut self, cb: AvrcpCallbacks) { match cb { AvrcpCallbacks::AvrcpDeviceConnected(addr, supported) => { @@ -572,7 +641,8 @@ impl BluetoothMedia { info!("[{}]: state {:?}", DisplayAddress(&addr), state); match state { DeviceConnectionStates::ConnectingBeforeRetry - | DeviceConnectionStates::ConnectingAfterRetry => { + | DeviceConnectionStates::ConnectingAfterRetry + | DeviceConnectionStates::WaitingConnection => { self.delay_volume_update.insert(Profile::AvrcpController, volume); } DeviceConnectionStates::FullyConnected => { @@ -597,7 +667,10 @@ impl BluetoothMedia { // Per MPS v1.0, on receiving a pause key through AVRCP, // central should pause the A2DP stream with an AVDTP suspend command. - if self.phone_ops_enabled && key == AVRCP_ID_PAUSE && value == AVRCP_STATE_PRESS { + if self.mps_qualification_enabled + && key == AVRCP_ID_PAUSE + && value == AVRCP_STATE_PRESS + { self.suspend_audio_request_impl(); } } @@ -644,20 +717,24 @@ impl BluetoothMedia { // Connect SCO if phone operations are enabled and an active call exists. // This is only used for Bluetooth HFP qualification. - if self.phone_ops_enabled && self.phone_state.num_active > 0 { + if self.mps_qualification_enabled && self.phone_state.num_active > 0 { debug!("[{}]: Connect SCO due to active call.", DisplayAddress(&addr)); - self.start_sco_call_impl(addr.to_string(), false, false); + self.start_sco_call_impl( + addr.to_string(), + false, + HfpCodecCapability::NONE, + ); } + + self.uhid_create(addr); } BthfConnectionState::Disconnected => { info!("[{}]: hfp disconnected.", DisplayAddress(&addr)); + self.uhid_destroy(&addr); self.hfp_states.remove(&addr); self.hfp_cap.remove(&addr); self.hfp_audio_state.remove(&addr); self.rm_connected_profile(addr, uuid::Profile::Hfp, true); - if self.is_complete_profiles_required() { - self.disconnect(addr.to_string()); - } } BthfConnectionState::Connecting => { info!("[{}]: hfp connecting.", DisplayAddress(&addr)); @@ -683,18 +760,19 @@ impl BluetoothMedia { self.hfp_audio_state.insert(addr, state); - // Change the phone state only when it's currently managed by media stack - // (I.e., phone operations are not enabled). - if !self.phone_ops_enabled && self.phone_state.num_active != 1 { + if self.should_insert_call_when_sco_start(addr) + && self.call_list.iter().all(|c| c.source != CallSource::CRAS) + { // This triggers a +CIEV command to set the call status for HFP devices. // It is required for some devices to provide sound. - self.phone_state.num_active = 1; - self.call_list = vec![CallInfo { - index: 1, + self.phone_state.num_active += 1; + self.call_list.push(CallInfo { + index: self.new_call_index(), dir_incoming: false, + source: CallSource::CRAS, state: CallState::Active, number: "".into(), - }]; + }); self.phone_state_change("".into()); } } @@ -710,11 +788,19 @@ impl BluetoothMedia { }); } - // Change the phone state only when it's currently managed by media stack - // (I.e., phone operations are not enabled). - if !self.phone_ops_enabled && self.phone_state.num_active != 0 { - self.phone_state.num_active = 0; - self.call_list = vec![]; + if !self.mps_qualification_enabled + && self.call_list.iter().any(|c| c.source == CallSource::CRAS) + { + for c in self.call_list.iter_mut() { + if c.source == CallSource::CRAS { + self.phone_state.num_active -= 1; + } + } + + self.call_list.retain(|x| match x.source { + CallSource::CRAS => false, + _ => true, + }); self.phone_state_change("".into()); } @@ -745,7 +831,8 @@ impl BluetoothMedia { ); match states.get(&addr).unwrap() { DeviceConnectionStates::ConnectingBeforeRetry - | DeviceConnectionStates::ConnectingAfterRetry => { + | DeviceConnectionStates::ConnectingAfterRetry + | DeviceConnectionStates::WaitingConnection => { self.delay_volume_update.insert(Profile::Hfp, volume); } DeviceConnectionStates::FullyConnected => { @@ -756,6 +843,60 @@ impl BluetoothMedia { _ => {} } } + HfpCallbacks::MicVolumeUpdate(volume, addr) => { + if !self.phone_ops_enabled { + return; + } + + if self.hfp_states.get(&addr).is_none() + || BthfConnectionState::SlcConnected != *self.hfp_states.get(&addr).unwrap() + { + warn!("[{}]: Unknown address hfp or slc not ready", addr.to_string()); + return; + } + + if let Some(uhid) = self.uhid.get_mut(&addr) { + if volume == 0 && !uhid.muted { + uhid.muted = true; + self.uhid_send_input_report(&addr); + } else if volume > 0 { + uhid.volume = volume; + if uhid.muted { + uhid.muted = false; + self.uhid_send_input_report(&addr); + } + } + } + } + HfpCallbacks::VendorSpecificAtCommand(at_string, addr) => { + let at_command = match parse_at_command_data(at_string) { + Ok(command) => command, + Err(e) => { + debug!("{}", e); + return; + } + }; + let battery_level = match calculate_battery_percent(at_command.clone()) { + Ok(level) => level, + Err(e) => { + debug!("{}", e); + return; + } + }; + let source_info = match at_command.vendor { + Some(vendor) => format!("HFP - {}", vendor), + _ => "HFP - UnknownAtCommand".to_string(), + }; + self.battery_provider_manager.lock().unwrap().set_battery_info( + self.battery_provider_id, + BatterySet::new( + addr.to_string(), + uuid::HFP.to_string(), + source_info, + vec![Battery { percentage: battery_level, variant: "".to_string() }], + ), + ); + } HfpCallbacks::BatteryLevelUpdate(battery_level, addr) => { let battery_set = BatterySet::new( addr.to_string(), @@ -851,8 +992,11 @@ impl BluetoothMedia { } self.phone_state_change("".into()); - debug!("[{}]: Start SCO call due to ATA", DisplayAddress(&addr)); - self.start_sco_call_impl(addr.to_string(), false, false); + if self.mps_qualification_enabled { + debug!("[{}]: Start SCO call due to ATA", DisplayAddress(&addr)); + self.start_sco_call_impl(addr.to_string(), false, HfpCodecCapability::NONE); + } + self.uhid_send_input_report(&addr); } HfpCallbacks::HangupCall(addr) => { if !self.hangup_call_impl() { @@ -860,6 +1004,7 @@ impl BluetoothMedia { return; } self.phone_state_change("".into()); + self.uhid_send_input_report(&addr); // Try resume the A2DP stream (per MPS v1.0) on rejecting an incoming call or an // outgoing call is rejected. @@ -907,6 +1052,7 @@ impl BluetoothMedia { if success { // Success means the call state has changed. Inform libbluetooth. self.phone_state_change("".into()); + self.uhid_send_input_report(&addr); } else { warn!( "[{}]: Unexpected or unsupported CHLD command {:?} from HF", @@ -915,6 +1061,43 @@ impl BluetoothMedia { ); } } + HfpCallbacks::DebugDump( + active, + codec_id, + total_num_decoded_frames, + pkt_loss_ratio, + begin_ts, + end_ts, + pkt_status_in_hex, + pkt_status_in_binary, + ) => { + let is_wbs = codec_id == HfpCodecId::MSBC as u16; + let is_swb = codec_id == HfpCodecId::LC3 as u16; + debug!("[HFP] DebugDump: active:{}, codec_id:{}", active, codec_id); + if is_wbs || is_swb { + debug!( + "total_num_decoded_frames:{} pkt_loss_ratio:{}", + total_num_decoded_frames, pkt_loss_ratio + ); + debug!("begin_ts:{} end_ts:{}", begin_ts, end_ts); + debug!( + "pkt_status_in_hex:{} pkt_status_in_binary:{}", + pkt_status_in_hex, pkt_status_in_binary + ); + } + self.callbacks.lock().unwrap().for_all_callbacks(|callback| { + callback.on_hfp_debug_dump( + active, + codec_id, + total_num_decoded_frames, + pkt_loss_ratio, + begin_ts, + end_ts, + pkt_status_in_hex.clone(), + pkt_status_in_binary.clone(), + ); + }); + } } } @@ -922,6 +1105,216 @@ impl BluetoothMedia { self.callbacks.lock().unwrap().remove_callback(id) } + pub fn remove_telephony_callback(&mut self, id: u32) -> bool { + self.telephony_callbacks.lock().unwrap().remove_callback(id) + } + + fn uhid_create(&mut self, addr: RawAddress) { + debug!( + "[{}]: UHID create: PhoneOpsEnabled {}", + DisplayAddress(&addr), + self.phone_ops_enabled, + ); + // To change the value of phone_ops_enabled, you need to toggle the BluetoothFlossTelephony feature flag on chrome://flags. + if !self.phone_ops_enabled { + return; + } + if self.uhid.contains_key(&addr) { + warn!("[{}]: UHID create: entry already created", DisplayAddress(&addr)); + return; + } + let adapter_addr = match &self.adapter { + Some(adapter) => adapter.lock().unwrap().get_address().to_lowercase(), + _ => "".to_string(), + }; + let txl = self.tx.clone(); + let remote_addr = addr.to_string(); + self.uhid.insert( + addr, + UHid { + handle: UHidHfp::create( + adapter_addr, + addr.to_string(), + self.adapter_get_remote_name(addr), + move |m| { + match m { + OutputEvent::Close => { + txl.blocking_send(Message::UHidTelephonyUseCallback( + remote_addr.clone(), + false, + )) + .unwrap(); + } + OutputEvent::Open => { + txl.blocking_send(Message::UHidTelephonyUseCallback( + remote_addr.clone(), + true, + )) + .unwrap(); + } + OutputEvent::Output { data } => { + txl.blocking_send(Message::UHidHfpOutputCallback( + remote_addr.clone(), + data[0], + data[1], + )) + .unwrap(); + } + _ => (), + }; + }, + ), + volume: 15, // By default use maximum volume in case microphone gain has not been received + muted: false, + }, + ); + } + + fn uhid_destroy(&mut self, addr: &RawAddress) { + if let Some(uhid) = self.uhid.get_mut(addr) { + debug!("[{}]: UHID destroy", DisplayAddress(&addr)); + match uhid.handle.destroy() { + Err(e) => log::error!( + "[{}]: UHID destroy: Fail to destroy uhid {}", + DisplayAddress(&addr), + e + ), + Ok(_) => (), + }; + self.uhid.remove(addr); + } else { + debug!("[{}]: UHID destroy: not a UHID device", DisplayAddress(&addr)); + } + } + + fn uhid_send_input_report(&mut self, addr: &RawAddress) { + // To change the value of phone_ops_enabled, you need to toggle the BluetoothFlossTelephony feature flag on chrome://flags. + if !self.phone_ops_enabled { + return; + } + if let Some(uhid) = self.uhid.get_mut(addr) { + let mut data = 0; + if self.call_list.iter().any(|c| c.source == CallSource::HID) { + data |= UHID_INPUT_HOOK_SWITCH; + } + if uhid.muted { + data |= UHID_INPUT_PHONE_MUTE; + } + debug!("[{}]: UHID: Send input report: {}", DisplayAddress(&addr), data); + match uhid.handle.send_input(data) { + Err(e) => log::error!( + "[{}]: UHID: Fail to send Input Report ({}) to uhid: {}", + DisplayAddress(&addr), + data, + e + ), + Ok(_) => (), + }; + }; + } + + pub fn dispatch_uhid_hfp_output_callback(&mut self, address: String, id: u8, data: u8) { + let addr = match RawAddress::from_string(address.clone()) { + None => { + warn!("UHID: Invalid device address for dispatch_uhid_hfp_output_callback"); + return; + } + Some(addr) => addr, + }; + + debug!( + "[{}]: UHID: Received output report: id {}, data {}", + DisplayAddress(&addr), + id, + data + ); + + let uhid = match self.uhid.get_mut(&addr) { + Some(uhid) => uhid, + None => { + warn!("[{}]: UHID: No valid UHID", DisplayAddress(&addr)); + return; + } + }; + + if id == BLUETOOTH_TELEPHONY_UHID_REPORT_ID { + let mute = data & UHID_OUTPUT_MUTE; + if mute == UHID_OUTPUT_MUTE && !uhid.muted { + uhid.muted = true; + self.set_hfp_mic_volume(0, addr); + } else if mute != UHID_OUTPUT_MUTE && uhid.muted { + uhid.muted = false; + let saved_volume = uhid.volume; + self.set_hfp_mic_volume(saved_volume, addr); + } + + let call_state = data & (UHID_OUTPUT_RING | UHID_OUTPUT_OFF_HOOK); + if call_state == UHID_OUTPUT_NONE { + self.hangup_call(); + } else if call_state == UHID_OUTPUT_RING { + self.incoming_call("".into()); + } else if call_state == UHID_OUTPUT_OFF_HOOK { + if self.call_list.iter().any(|c| c.source == CallSource::HID) { + return; + } + self.dialing_call("".into()); + self.answer_call(); + self.uhid_send_input_report(&addr); + } + } + } + + pub fn dispatch_uhid_telephony_use_callback(&mut self, address: String, state: bool) { + let addr = match RawAddress::from_string(address.clone()) { + None => { + warn!("UHID: Invalid device address for dispatch_uhid_telephony_use_callback"); + return; + } + Some(addr) => addr, + }; + + debug!("[{}]: UHID: Telephony use: {}", DisplayAddress(&addr), state); + if state == false { + // As there's a HID call for each WebHID call, even if it has been answered in the app + // or pre-exists, and that an app which disconnects from WebHID may not have trigger + // the UHID_OUTPUT_NONE, we need to remove all pending HID calls on telephony use + // release to keep lower HF layer in sync and not prevent A2DP streaming + self.hangup_call_impl(); + self.phone_state_change("".into()); + } + self.telephony_callbacks.lock().unwrap().for_all_callbacks(|callback| { + callback.on_telephony_use(address.to_string(), state); + }); + } + + fn set_hfp_mic_volume(&mut self, volume: u8, addr: RawAddress) { + let vol = match i8::try_from(volume) { + Ok(val) if val <= 15 => val, + _ => { + warn!("[{}]: Ignore invalid mic volume {}", DisplayAddress(&addr), volume); + return; + } + }; + + if self.hfp_states.get(&addr).is_none() { + warn!( + "[{}]: Ignore mic volume event for unconnected or disconnected HFP device", + DisplayAddress(&addr) + ); + return; + } + + match self.hfp.as_mut() { + Some(hfp) => { + let status = hfp.set_mic_volume(vol, addr); + if status != BtStatus::Success { + warn!("[{}]: Failed to set mic volume to {}", DisplayAddress(&addr), vol); + } + } + None => warn!("Uninitialized HFP to set mic volume"), + }; + } + fn notify_critical_profile_disconnected(&mut self, addr: RawAddress) { info!( "[{}]: Device connection state: {:?}.", @@ -995,6 +1388,15 @@ impl BluetoothMedia { let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts); sleep(sleep_duration).await; + Self::async_disconnect(fallback_tasks, device_states, txl, addr).await; + } + + async fn async_disconnect( + fallback_tasks: &Arc, Instant)>>>>, + device_states: &Arc>>, + txl: &Sender, + addr: &RawAddress, + ) { device_states.lock().unwrap().insert(*addr, DeviceConnectionStates::Disconnecting); fallback_tasks.lock().unwrap().insert(*addr, None); @@ -1013,12 +1415,22 @@ impl BluetoothMedia { first_conn_ts: Instant, ) { let now_ts = Instant::now(); - let total_duration = Duration::from_secs(CONNECT_MISSING_PROFILES_TIMEOUT_SEC); + let total_duration = Duration::from_secs(PROFILE_DISCOVERY_TIMEOUT_SEC); let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts); sleep(sleep_duration).await; let _ = txl.send(Message::Media(MediaActions::ForceEnterConnected(addr.to_string()))).await; } + fn is_bonded(&self, addr: &RawAddress) -> bool { + match &self.adapter { + Some(adapter) => { + BtBondState::Bonded + == adapter.lock().unwrap().get_bond_state_by_addr(&addr.to_string()) + } + _ => false, + } + } + fn notify_media_capability_updated(&mut self, addr: RawAddress) { let mut guard = self.fallback_tasks.lock().unwrap(); let mut states = self.device_states.lock().unwrap(); @@ -1035,8 +1447,22 @@ impl BluetoothMedia { guard.insert(addr, None); } else { // The device is already added or is disconnecting. - // Ignore unless all profiles are cleared. + // Ignore unless all profiles are cleared, where we need to do some clean up. if !is_profile_cleared { + // Unbonded device is special, we need to reject the connection from them. + if !self.is_bonded(&addr) { + let tasks = self.fallback_tasks.clone(); + let states = self.device_states.clone(); + let txl = self.tx.clone(); + let task = topstack::get_runtime().spawn(async move { + warn!( + "[{}]: Rejecting an unbonded device's attempt to connect media", + DisplayAddress(&addr) + ); + BluetoothMedia::async_disconnect(&tasks, &states, &txl, &addr).await; + }); + guard.insert(addr, Some((task, first_conn_ts))); + } return; } } @@ -1060,17 +1486,46 @@ impl BluetoothMedia { if states.get(&addr).is_none() { states.insert(addr, DeviceConnectionStates::ConnectingBeforeRetry); } - if missing_profiles.is_empty() - || missing_profiles == HashSet::from([Profile::AvrcpController]) - { - info!( - "[{}]: Fully connected, available profiles: {:?}, connected profiles: {:?}.", - DisplayAddress(&addr), - available_profiles, - connected_profiles - ); - states.insert(addr, DeviceConnectionStates::FullyConnected); + if states.get(&addr).unwrap() != &DeviceConnectionStates::FullyConnected { + if available_profiles.is_empty() { + // Some headsets may start initiating connections to audio profiles before they are + // exposed to the stack. In this case, wait for either all critical profiles have been + // connected or some timeout to enter the |FullyConnected| state. + if connected_profiles.contains(&Profile::Hfp) + && connected_profiles.contains(&Profile::A2dpSink) + { + info!( + "[{}]: Fully connected, available profiles: {:?}, connected profiles: {:?}.", + DisplayAddress(&addr), + available_profiles, + connected_profiles + ); + + states.insert(addr, DeviceConnectionStates::FullyConnected); + } else { + warn!( + "[{}]: Connected profiles: {:?}, waiting for peer to initiate remaining connections.", + DisplayAddress(&addr), + connected_profiles + ); + + states.insert(addr, DeviceConnectionStates::WaitingConnection); + } + } else { + if missing_profiles.is_empty() + || missing_profiles == HashSet::from([Profile::AvrcpController]) + { + info!( + "[{}]: Fully connected, available profiles: {:?}, connected profiles: {:?}.", + DisplayAddress(&addr), + available_profiles, + connected_profiles + ); + + states.insert(addr, DeviceConnectionStates::FullyConnected); + } + } } info!( @@ -1122,39 +1577,18 @@ impl BluetoothMedia { } DeviceConnectionStates::FullyConnected => { // Rejecting the unbonded connection after we finished our profile - // reconnectinglogic to avoid a collision. - if let Some(adapter) = &self.adapter { - if BtBondState::Bonded - != adapter.lock().unwrap().get_bond_state_by_addr(&addr.to_string()) - { - warn!( - "[{}]: Rejecting a unbonded device's attempt to connect to media profiles", - DisplayAddress(&addr)); - let fallback_tasks = self.fallback_tasks.clone(); - let device_states = self.device_states.clone(); - let txl = self.tx.clone(); - let task = topstack::get_runtime().spawn(async move { - { - device_states - .lock() - .unwrap() - .insert(addr, DeviceConnectionStates::Disconnecting); - fallback_tasks.lock().unwrap().insert(addr, None); - } - - debug!( - "[{}]: Device connection state: {:?}.", - DisplayAddress(&addr), - DeviceConnectionStates::Disconnecting - ); + // reconnecting logic to avoid a collision. + if !self.is_bonded(&addr) { + warn!( + "[{}]: Rejecting a unbonded device's attempt to connect to media profiles", + DisplayAddress(&addr) + ); - let _ = txl - .send(Message::Media(MediaActions::Disconnect(addr.to_string()))) - .await; - }); - guard.insert(addr, Some((task, first_conn_ts))); - return; - } + let task = topstack::get_runtime().spawn(async move { + BluetoothMedia::async_disconnect(&tasks, &device_states, &txl, &addr).await; + }); + guard.insert(addr, Some((task, ts))); + return; } let cur_a2dp_caps = self.a2dp_caps.get(&addr); @@ -1165,7 +1599,7 @@ impl BluetoothMedia { addr.to_string(), name.clone(), cur_a2dp_caps.unwrap_or(&Vec::new()).to_vec(), - *cur_hfp_cap.unwrap_or(&HfpCodecCapability::UNSUPPORTED), + *cur_hfp_cap.unwrap_or(&HfpCodecCapability::NONE), absolute_volume, ); @@ -1188,6 +1622,13 @@ impl BluetoothMedia { guard.insert(addr, None); } DeviceConnectionStates::Disconnecting => {} + DeviceConnectionStates::WaitingConnection => { + let task = topstack::get_runtime().spawn(async move { + BluetoothMedia::wait_retry(&tasks, &device_states, &txl, &addr, ts).await; + BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await; + }); + guard.insert(addr, Some((task, ts))); + } } } @@ -1331,7 +1772,7 @@ impl BluetoothMedia { } fn try_a2dp_resume(&mut self) { - if !self.phone_ops_enabled { + if !self.mps_qualification_enabled { return; } // Make sure there is no any SCO connection and then resume the A2DP stream. @@ -1344,7 +1785,7 @@ impl BluetoothMedia { } fn try_a2dp_suspend(&mut self) { - if !self.phone_ops_enabled { + if !self.mps_qualification_enabled { return; } // Suspend the A2DP stream if there is any. @@ -1358,7 +1799,7 @@ impl BluetoothMedia { &mut self, address: String, sco_offload: bool, - force_cvsd: bool, + disabled_codecs: HfpCodecCapability, ) -> bool { match (|| -> Result<(), &str> { let addr = RawAddress::from_string(address.clone()) @@ -1366,7 +1807,8 @@ impl BluetoothMedia { info!("Start sco call for {}", DisplayAddress(&addr)); let hfp = self.hfp.as_mut().ok_or("Uninitialized HFP to start the sco call")?; - if hfp.connect_audio(addr, sco_offload, force_cvsd) != 0 { + let disabled_codecs = disabled_codecs.try_into().expect("Can't parse disabled_codecs"); + if hfp.connect_audio(addr, sco_offload, disabled_codecs) != 0 { return Err("SCO connect_audio status failed"); } info!("SCO connect_audio status success"); @@ -1468,69 +1910,136 @@ impl BluetoothMedia { } fn answer_call_impl(&mut self) -> bool { - if !self.phone_ops_enabled || self.phone_state.state == CallState::Idle { - return false; - } - // There must be exactly one incoming/dialing call in the list. - for c in self.call_list.iter_mut() { - match c.state { - CallState::Incoming | CallState::Dialing | CallState::Alerting => { - c.state = CallState::Active; - break; + if self.mps_qualification_enabled { + if self.phone_state.state == CallState::Idle { + return false; + } + // There must be exactly one incoming/dialing call in the list. + for c in self.call_list.iter_mut() { + match c.state { + CallState::Incoming | CallState::Dialing | CallState::Alerting => { + c.state = CallState::Active; + break; + } + _ => {} + } + } + self.phone_state.state = CallState::Idle; + self.phone_state.num_active += 1; + return true; + } else if self.phone_ops_enabled { + if self.phone_state.state == CallState::Idle { + return false; + } + // There must be exactly one incoming/dialing call in the list. + for c in self.call_list.iter_mut() { + if c.source == CallSource::CRAS { + continue; + } + + match c.state { + CallState::Incoming | CallState::Dialing | CallState::Alerting => { + c.state = CallState::Active; + self.phone_state.state = CallState::Idle; + self.phone_state.num_active += 1; + return true; + } + _ => {} } - _ => {} } } - self.phone_state.state = CallState::Idle; - self.phone_state.num_active += 1; - true + + return false; } fn hangup_call_impl(&mut self) -> bool { - if !self.phone_ops_enabled { - return false; - } - match self.phone_state.state { - CallState::Idle if self.phone_state.num_active > 0 => { - self.phone_state.num_active -= 1; - } - CallState::Incoming | CallState::Dialing | CallState::Alerting => { - self.phone_state.state = CallState::Idle; - } - _ => { - return false; + if self.mps_qualification_enabled { + match self.phone_state.state { + CallState::Idle if self.phone_state.num_active > 0 => { + self.phone_state.num_active -= 1; + } + CallState::Incoming | CallState::Dialing | CallState::Alerting => { + self.phone_state.state = CallState::Idle; + } + _ => return false, + } + // At this point, there must be exactly one incoming/dialing/alerting/active call to be + // removed. + self.call_list.retain(|x| match x.state { + CallState::Active + | CallState::Incoming + | CallState::Dialing + | CallState::Alerting => false, + _ => true, + }); + return true; + } else if self.phone_ops_enabled { + let mut ret = false; + for c in self.call_list.iter_mut() { + if c.source == CallSource::CRAS { + continue; + } + + match c.state { + CallState::Incoming | CallState::Dialing | CallState::Alerting => { + ret = true; + } + CallState::Active => { + self.phone_state.num_active -= 1; + ret = true; + } + _ => {} + } } + + self.call_list.retain(|x| match x.source { + CallSource::HID => false, + _ => true, + }); + self.phone_state.state = CallState::Idle; + return ret; } - // At this point, there must be exactly one incoming/dialing/alerting/active call to be - // removed. - self.call_list.retain(|x| match x.state { - CallState::Active | CallState::Incoming | CallState::Dialing | CallState::Alerting => { - false - } - _ => true, - }); - true + + return false; } fn dialing_call_impl(&mut self, number: String) -> bool { - if !self.phone_ops_enabled + if !(self.phone_ops_enabled || self.mps_qualification_enabled) || self.phone_state.state != CallState::Idle - || self.phone_state.num_active > 0 { return false; } - self.call_list.push(CallInfo { - index: self.new_call_index(), - dir_incoming: false, - state: CallState::Dialing, - number: number.clone(), - }); + if self.mps_qualification_enabled { + if self.phone_state.num_active > 0 { + return false; + } + self.call_list.push(CallInfo { + index: self.new_call_index(), + dir_incoming: false, + source: CallSource::CRAS, + state: CallState::Dialing, + number: number.clone(), + }); + } else if self.phone_ops_enabled { + if self.call_list.iter().any(|c| c.source == CallSource::HID) { + return false; + } + self.call_list.push(CallInfo { + index: self.new_call_index(), + dir_incoming: false, + source: CallSource::HID, + state: CallState::Dialing, + number: number.clone(), + }); + } self.phone_state.state = CallState::Dialing; true } fn dialing_to_alerting(&mut self) -> bool { - if !self.phone_ops_enabled || self.phone_state.state != CallState::Dialing { + if !(self.phone_ops_enabled || self.mps_qualification_enabled) + || self.phone_state.state != CallState::Dialing + { return false; } for c in self.call_list.iter_mut() { @@ -1544,68 +2053,102 @@ impl BluetoothMedia { } fn release_held_impl(&mut self) -> bool { - if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle { + if !(self.phone_ops_enabled || self.mps_qualification_enabled) { return false; } - self.call_list.retain(|x| x.state != CallState::Held); - self.phone_state.num_held = 0; + + if self.mps_qualification_enabled { + if self.phone_state.state != CallState::Idle { + return false; + } + self.call_list.retain(|x| x.state != CallState::Held); + self.phone_state.num_held = 0; + } else if self.phone_ops_enabled { + if self.phone_state.state == CallState::Incoming { + self.call_list.retain(|x| x.state != CallState::Incoming); + self.phone_state.state = CallState::Idle; + } else { + return false; + } + } true } fn release_active_accept_held_impl(&mut self) -> bool { - if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle { + if !(self.phone_ops_enabled || self.mps_qualification_enabled) { return false; } self.call_list.retain(|x| x.state != CallState::Active); self.phone_state.num_active = 0; // Activate the first held call - for c in self.call_list.iter_mut() { - if c.state == CallState::Held { - c.state = CallState::Active; - self.phone_state.num_held -= 1; - self.phone_state.num_active += 1; - break; + if self.mps_qualification_enabled { + if self.phone_state.state != CallState::Idle { + return false; + } + for c in self.call_list.iter_mut() { + if c.state == CallState::Held { + c.state = CallState::Active; + self.phone_state.num_held -= 1; + self.phone_state.num_active += 1; + break; + } + } + } else if self.phone_ops_enabled { + for c in self.call_list.iter_mut() { + if c.state == CallState::Incoming && self.phone_state.state == CallState::Incoming { + c.state = CallState::Active; + self.phone_state.num_active += 1; + self.phone_state.state = CallState::Idle; + break; + } } } true } fn hold_active_accept_held_impl(&mut self) -> bool { - if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle { + if !(self.phone_ops_enabled || self.mps_qualification_enabled) { return false; } - self.phone_state.num_held += self.phone_state.num_active; - self.phone_state.num_active = 0; + if self.mps_qualification_enabled { + if self.phone_state.state != CallState::Idle { + return false; + } + self.phone_state.num_held += self.phone_state.num_active; + self.phone_state.num_active = 0; - for c in self.call_list.iter_mut() { - match c.state { - // Activate at most one held call - CallState::Held if self.phone_state.num_active == 0 => { - c.state = CallState::Active; - self.phone_state.num_held -= 1; - self.phone_state.num_active = 1; - } - CallState::Active => { - c.state = CallState::Held; + for c in self.call_list.iter_mut() { + match c.state { + // Activate at most one held call + CallState::Held if self.phone_state.num_active == 0 => { + c.state = CallState::Active; + self.phone_state.num_held -= 1; + self.phone_state.num_active = 1; + } + CallState::Active => { + c.state = CallState::Held; + } + _ => {} } - _ => {} } + } else if self.phone_ops_enabled { + return false; } true } // Per MPS v1.0 (Multi-Profile Specification), disconnecting or failing to connect // a profile should not affect the others. - // Allow partial profiles connection during qualification (phone operations are enabled). + // Allow partial profiles connection during qualification (MPS qualification mode is enabled). fn is_complete_profiles_required(&self) -> bool { - !self.phone_ops_enabled + !self.mps_qualification_enabled } // Force the media enters the FullyConnected state and then triggers a retry. - // This function is only used for qualification as a replacement of normal retry. - // Usually PTS initiates the connection of the necessary profiles, and Floss should notify - // CRAS of the new audio device regardless of the unconnected profiles. + // When this function is used for qualification as a replacement of normal retry, + // PTS could initiate the connection of the necessary profiles, and Floss should + // notify CRAS of the new audio device regardless of the unconnected profiles. // Still retry in the end because some test cases require that. fn force_enter_connected(&mut self, address: String) { let addr = match RawAddress::from_string(address.clone()) { @@ -1625,6 +2168,16 @@ impl BluetoothMedia { pub fn add_player(&mut self, name: String, browsing_supported: bool) { self.avrcp.as_mut().unwrap().add_player(&name, browsing_supported); } + + fn should_insert_call_when_sco_start(&self, address: RawAddress) -> bool { + if self.mps_qualification_enabled { + return false; + } + if !self.phone_ops_enabled { + return true; + } + return interop_insert_call_when_sco_start(address); + } } fn get_a2dp_dispatcher(tx: Sender) -> A2dpCallbacksDispatcher { @@ -1687,8 +2240,13 @@ impl IBluetoothMedia for BluetoothMedia { self.hfp = Some(Hfp::new(&self.intf.lock().unwrap())); self.hfp.as_mut().unwrap().initialize(hfp_dispatcher); - for profile in self.delay_enable_profiles.clone() { - self.enable_profile(&profile); + // TODO(b/284811956) A2DP needs to be enabled before AVRCP otherwise AVRCP gets memset'd. + // Iterate the delay_enable_profiles hashmap directly when this is fixed. + let profile_order = vec![Profile::A2dpSource, Profile::AvrcpTarget, Profile::Hfp]; + for profile in profile_order { + if self.delay_enable_profiles.contains(&profile) { + self.enable_profile(&profile); + } } true } @@ -1867,9 +2425,9 @@ impl IBluetoothMedia for BluetoothMedia { true } - // TODO(b/278963515): Currently this is designed to be called from both the - // UI and via disconnection callbacks. Remove this workaround once the - // proper fix has landed. + // This may not disconnect all media profiles at once, but once the stack + // is notified of the disconnection callback, `disconnect_device` will be + // invoked as necessary to ensure the device is removed. fn disconnect(&mut self, address: String) { let addr = match RawAddress::from_string(address.clone()) { None => { @@ -1895,6 +2453,7 @@ impl IBluetoothMedia for BluetoothMedia { uuid::Profile::A2dpSink => { // Some headsets (b/278963515) will try reconnecting to A2DP // when HFP is running but (requested to be) disconnected. + // TODO: Remove this workaround once proper fix lands. if connected_profiles.contains(&Profile::Hfp) { continue; } @@ -2059,21 +2618,71 @@ impl IBluetoothMedia for BluetoothMedia { fn set_audio_config( &mut self, - sample_rate: i32, - bits_per_sample: i32, - channel_mode: i32, + address: String, + codec_type: A2dpCodecIndex, + sample_rate: A2dpCodecSampleRate, + bits_per_sample: A2dpCodecBitsPerSample, + channel_mode: A2dpCodecChannelMode, ) -> bool { - if !A2dpCodecSampleRate::validate_bits(sample_rate) - || !A2dpCodecBitsPerSample::validate_bits(bits_per_sample) - || !A2dpCodecChannelMode::validate_bits(channel_mode) - { + let addr = match RawAddress::from_string(address.clone()) { + None => { + warn!("Invalid device address {}", address); + return false; + } + Some(addr) => addr, + }; + + if self.a2dp_states.get(&addr).is_none() { + warn!( + "[{}]: Ignore set config event for unconnected or disconnected A2DP device", + DisplayAddress(&addr) + ); return false; } match self.a2dp.as_mut() { Some(a2dp) => { - a2dp.set_audio_config(sample_rate, bits_per_sample, channel_mode); - true + let caps = self.a2dp_caps.get(&addr).unwrap_or(&Vec::new()).to_vec(); + + for cap in &caps { + if A2dpCodecIndex::from(cap.codec_type) == codec_type { + if (A2dpCodecSampleRate::from_bits(cap.sample_rate).unwrap() & sample_rate) + != sample_rate + { + warn!("Unsupported sample rate {:?}", sample_rate); + return false; + } + if (A2dpCodecBitsPerSample::from_bits(cap.bits_per_sample).unwrap() + & bits_per_sample) + != bits_per_sample + { + warn!("Unsupported bit depth {:?}", bits_per_sample); + return false; + } + if (A2dpCodecChannelMode::from_bits(cap.channel_mode).unwrap() + & channel_mode) + != channel_mode + { + warn!("Unsupported channel mode {:?}", channel_mode); + return false; + } + + let config = vec![A2dpCodecConfig { + codec_type: codec_type as i32, + codec_priority: A2dpCodecPriority::Highest as i32, + sample_rate: sample_rate.bits() as i32, + bits_per_sample: bits_per_sample.bits() as i32, + channel_mode: channel_mode.bits() as i32, + ..Default::default() + }]; + + a2dp.config_codec(addr, config); + return true; + } + } + + warn!("Unsupported codec type {:?}", codec_type); + false } None => { warn!("Uninitialized A2DP to set audio config"); @@ -2106,7 +2715,6 @@ impl IBluetoothMedia for BluetoothMedia { } Some(addr) => addr, }; - let vol = match i8::try_from(volume) { Ok(val) if val <= 15 => val, _ => { @@ -2136,11 +2744,6 @@ impl IBluetoothMedia for BluetoothMedia { } fn stop_audio_request(&mut self) { - if !self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) { - info!("No active stream on A2DP device, ignoring request to stop audio."); - return; - } - debug!("Stop audio request"); match self.a2dp.as_mut() { @@ -2149,8 +2752,13 @@ impl IBluetoothMedia for BluetoothMedia { }; } - fn start_sco_call(&mut self, address: String, sco_offload: bool, force_cvsd: bool) -> bool { - self.start_sco_call_impl(address, sco_offload, force_cvsd) + fn start_sco_call( + &mut self, + address: String, + sco_offload: bool, + disabled_codecs: HfpCodecCapability, + ) -> bool { + self.start_sco_call_impl(address, sco_offload, disabled_codecs) } fn stop_sco_call(&mut self, address: String) { @@ -2232,9 +2840,24 @@ impl IBluetoothMedia for BluetoothMedia { None => warn!("Uninitialized AVRCP to set player playback status"), }; } + + fn trigger_debug_dump(&mut self) { + match self.hfp.as_mut() { + Some(hfp) => hfp.debug_dump(), + None => warn!("Uninitialized HFP to dump debug log"), + }; + } } impl IBluetoothTelephony for BluetoothMedia { + fn register_telephony_callback( + &mut self, + callback: Box, + ) -> bool { + let _id = self.telephony_callbacks.lock().unwrap().add_callback(callback); + true + } + fn set_network_available(&mut self, network_available: bool) { if self.telephony_device_status.network_available == network_available { return; @@ -2282,6 +2905,7 @@ impl IBluetoothTelephony for BluetoothMedia { } fn set_phone_ops_enabled(&mut self, enable: bool) { + info!("Bluetooth HID telephony mode enabled"); if self.phone_ops_enabled == enable { return; } @@ -2294,35 +2918,83 @@ impl IBluetoothTelephony for BluetoothMedia { self.last_dialing_number = None; self.a2dp_has_interrupted_stream = false; - if !enable { - if self.hfp_states.values().any(|x| x == &BthfConnectionState::SlcConnected) { - self.call_list.push(CallInfo { - index: 1, - dir_incoming: false, - state: CallState::Active, - number: "".into(), - }); - self.phone_state.num_active = 1; - } + self.phone_ops_enabled = enable; + if self.hfp_audio_state.keys().any(|addr| self.should_insert_call_when_sco_start(*addr)) + && self.hfp_audio_state.values().any(|x| x == &BthfAudioState::Connected) + { + self.call_list.push(CallInfo { + index: 1, + dir_incoming: false, + source: CallSource::CRAS, + state: CallState::Active, + number: "".into(), + }); + self.phone_state.num_active = 1; + } + + self.phone_state_change("".into()); + } + + fn set_mps_qualification_enabled(&mut self, enable: bool) { + info!("MPS qualification mode enabled"); + if self.mps_qualification_enabled == enable { + return; + } + + self.call_list = vec![]; + self.phone_state.num_active = 0; + self.phone_state.num_held = 0; + self.phone_state.state = CallState::Idle; + self.memory_dialing_number = None; + self.last_dialing_number = None; + self.a2dp_has_interrupted_stream = false; + self.mps_qualification_enabled = enable; + + if self.hfp_audio_state.keys().any(|addr| self.should_insert_call_when_sco_start(*addr)) + && self.hfp_audio_state.values().any(|x| x == &BthfAudioState::Connected) + { + self.call_list.push(CallInfo { + index: 1, + dir_incoming: false, + source: CallSource::CRAS, + state: CallState::Active, + number: "".into(), + }); + self.phone_state.num_active = 1; } - self.phone_ops_enabled = enable; self.phone_state_change("".into()); } fn incoming_call(&mut self, number: String) -> bool { - if !self.phone_ops_enabled + if !(self.phone_ops_enabled || self.mps_qualification_enabled) || self.phone_state.state != CallState::Idle - || self.phone_state.num_active > 0 { return false; } - self.call_list.push(CallInfo { - index: self.new_call_index(), - dir_incoming: true, - state: CallState::Incoming, - number: number.clone(), - }); + if self.mps_qualification_enabled { + if self.phone_state.num_active > 0 { + return false; + } + self.call_list.push(CallInfo { + index: self.new_call_index(), + dir_incoming: true, + source: CallSource::CRAS, + state: CallState::Incoming, + number: number.clone(), + }); + } else if self.phone_ops_enabled { + if self.call_list.iter().any(|c| c.source == CallSource::HID) { + return false; + } + self.call_list.push(CallInfo { + index: self.new_call_index(), + dir_incoming: true, + source: CallSource::HID, + state: CallState::Incoming, + number: number.clone(), + }); + } self.phone_state.state = CallState::Incoming; self.phone_state_change(number); self.try_a2dp_suspend(); @@ -2347,16 +3019,18 @@ impl IBluetoothTelephony for BluetoothMedia { } self.phone_state_change("".into()); - // Find a connected HFP and try to establish an SCO. - if let Some(addr) = self.hfp_states.iter().find_map(|(addr, state)| { - if *state == BthfConnectionState::SlcConnected { - Some(addr.clone()) - } else { - None + if self.mps_qualification_enabled { + // Find a connected HFP and try to establish an SCO. + if let Some(addr) = self.hfp_states.iter().find_map(|(addr, state)| { + if *state == BthfConnectionState::SlcConnected { + Some(addr.clone()) + } else { + None + } + }) { + info!("Start SCO call due to call answered"); + self.start_sco_call_impl(addr.to_string(), false, HfpCodecCapability::NONE); } - }) { - info!("Start SCO call due to call answered"); - self.start_sco_call_impl(addr.to_string(), false, false); } true @@ -2376,7 +3050,7 @@ impl IBluetoothTelephony for BluetoothMedia { } fn set_memory_call(&mut self, number: Option) -> bool { - if !self.phone_ops_enabled { + if !(self.phone_ops_enabled || self.mps_qualification_enabled) { return false; } self.memory_dialing_number = number; @@ -2384,7 +3058,7 @@ impl IBluetoothTelephony for BluetoothMedia { } fn set_last_call(&mut self, number: Option) -> bool { - if !self.phone_ops_enabled { + if !(self.phone_ops_enabled || self.mps_qualification_enabled) { return false; } self.last_dialing_number = number; @@ -2416,7 +3090,7 @@ impl IBluetoothTelephony for BluetoothMedia { } fn audio_connect(&mut self, address: String) -> bool { - self.start_sco_call_impl(address, false, false) + self.start_sco_call_impl(address, false, HfpCodecCapability::NONE) } fn audio_disconnect(&mut self, address: String) { diff --git a/system/gd/rust/linux/stack/src/bluetooth_qa.rs b/system/gd/rust/linux/stack/src/bluetooth_qa.rs index ad4ac16cf6952778f9574bc8a627e05672672ca9..25b4fc1a5d5fe10adb0f452bf1a4843b57d32c4f 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_qa.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_qa.rs @@ -1,34 +1,114 @@ //! Anything related to the Qualification API (IBluetoothQA). -use crate::Message; -use bt_topshim::btif::BtDiscMode; +use crate::callbacks::Callbacks; +use crate::{bluetooth::FLOSS_VER, Message, RPCProxy}; +use bt_topshim::btif::{BtDiscMode, BtStatus}; +use bt_topshim::profiles::hid_host::BthhReportType; use tokio::sync::mpsc::Sender; /// Defines the Qualification API pub trait IBluetoothQA { + /// Register client callback + fn register_qa_callback(&mut self, callback: Box) -> u32; + /// Unregister a client callback + fn unregister_qa_callback(&mut self, callback_id: u32) -> bool; + /// Register a media player fn add_media_player(&self, name: String, browsing_supported: bool); + /// Send RFCOMM MSC command to the remote fn rfcomm_send_msc(&self, dlci: u8, addr: String); + /// Fetch adapter's discoverable mode. + /// Result will be returned in the callback |OnFetchDiscoverableModeComplete| + fn fetch_discoverable_mode(&self); + /// Fetch adapter's connectable mode. + /// Result will be returned in the callback |OnFetchConnectableComplete| + fn fetch_connectable(&self); + /// Set adapter's connectable mode. + /// Result will be returned in the callback |OnSetConnectableComplete| + fn set_connectable(&self, mode: bool); + /// Fetch the adapter's Bluetooth friendly name. + /// Result will be returned in the callback |OnFetchAliasComplete| + fn fetch_alias(&self); + /// Returns the adapter's Device ID information in modalias format + /// used by the kernel and udev. + fn get_modalias(&self) -> String; + /// Gets HID report on the peer. + /// Result will be returned in the callback |OnGetHIDReportComplete| + fn get_hid_report(&self, addr: String, report_type: BthhReportType, report_id: u8); + /// Sets HID report to the peer. + /// Result will be returned in the callback |OnSetHIDReportComplete| + fn set_hid_report(&self, addr: String, report_type: BthhReportType, report: String); + /// Snd HID data report to the peer. + /// Result will be returned in the callback |OnSendHIDDataComplete| + fn send_hid_data(&self, addr: String, data: String); +} - /// Returns adapter's discoverable mode. - fn get_discoverable_mode(&self) -> BtDiscMode; +pub trait IBluetoothQACallback: RPCProxy { + fn on_fetch_discoverable_mode_completed(&mut self, mode: BtDiscMode); + fn on_fetch_connectable_completed(&mut self, connectable: bool); + fn on_set_connectable_completed(&mut self, succeed: bool); + fn on_fetch_alias_completed(&mut self, alias: String); + fn on_get_hid_report_completed(&mut self, status: BtStatus); + fn on_set_hid_report_completed(&mut self, status: BtStatus); + fn on_send_hid_data_completed(&mut self, status: BtStatus); } pub struct BluetoothQA { tx: Sender, - disc_mode: BtDiscMode, + callbacks: Callbacks, } impl BluetoothQA { pub fn new(tx: Sender) -> BluetoothQA { - BluetoothQA { tx, disc_mode: BtDiscMode::NonDiscoverable } + BluetoothQA { + tx: tx.clone(), + callbacks: Callbacks::new(tx.clone(), Message::QaCallbackDisconnected), + } } - - pub fn handle_discoverable_mode_changed(&mut self, mode: BtDiscMode) { - self.disc_mode = mode; + pub fn on_fetch_discoverable_mode_completed(&mut self, mode: BtDiscMode) { + self.callbacks.for_all_callbacks(|cb| { + cb.on_fetch_discoverable_mode_completed(mode.clone()); + }); + } + pub fn on_fetch_connectable_completed(&mut self, connectable: bool) { + self.callbacks.for_all_callbacks(|cb| { + cb.on_fetch_connectable_completed(connectable); + }); + } + pub fn on_set_connectable_completed(&mut self, succeed: bool) { + self.callbacks.for_all_callbacks(|cb: &mut Box| { + cb.on_set_connectable_completed(succeed); + }); + } + pub fn on_fetch_alias_completed(&mut self, alias: String) { + self.callbacks.for_all_callbacks(|cb: &mut Box| { + cb.on_fetch_alias_completed(alias.clone()); + }); + } + pub fn on_get_hid_report_completed(&mut self, status: BtStatus) { + self.callbacks.for_all_callbacks(|cb: &mut Box| { + cb.on_get_hid_report_completed(status); + }); + } + pub fn on_set_hid_report_completed(&mut self, status: BtStatus) { + self.callbacks.for_all_callbacks(|cb: &mut Box| { + cb.on_set_hid_report_completed(status); + }); + } + pub fn on_send_hid_data_completed(&mut self, status: BtStatus) { + self.callbacks.for_all_callbacks(|cb: &mut Box| { + cb.on_send_hid_data_completed(status); + }); } } impl IBluetoothQA for BluetoothQA { + fn register_qa_callback(&mut self, callback: Box) -> u32 { + self.callbacks.add_callback(callback) + } + + fn unregister_qa_callback(&mut self, callback_id: u32) -> bool { + self.callbacks.remove_callback(callback_id) + } fn add_media_player(&self, name: String, browsing_supported: bool) { let txl = self.tx.clone(); tokio::spawn(async move { @@ -41,7 +121,49 @@ impl IBluetoothQA for BluetoothQA { let _ = txl.send(Message::QaRfcommSendMsc(dlci, addr)).await; }); } - fn get_discoverable_mode(&self) -> BtDiscMode { - self.disc_mode.clone() + fn fetch_discoverable_mode(&self) { + let txl = self.tx.clone(); + tokio::spawn(async move { + let _ = txl.send(Message::QaFetchDiscoverableMode).await; + }); + } + fn fetch_connectable(&self) { + let txl = self.tx.clone(); + tokio::spawn(async move { + let _ = txl.send(Message::QaFetchConnectable).await; + }); + } + fn set_connectable(&self, mode: bool) { + let txl = self.tx.clone(); + tokio::spawn(async move { + let _ = txl.send(Message::QaSetConnectable(mode)).await; + }); + } + fn fetch_alias(&self) { + let txl = self.tx.clone(); + tokio::spawn(async move { + let _ = txl.send(Message::QaFetchAlias).await; + }); + } + fn get_modalias(&self) -> String { + format!("bluetooth:v00E0pC405d{:04x}", FLOSS_VER) + } + fn get_hid_report(&self, addr: String, report_type: BthhReportType, report_id: u8) { + let txl = self.tx.clone(); + tokio::spawn(async move { + let _ = txl.send(Message::QaGetHidReport(addr, report_type, report_id)).await; + }); + } + fn set_hid_report(&self, addr: String, report_type: BthhReportType, report: String) { + let txl = self.tx.clone(); + tokio::spawn(async move { + let _ = txl.send(Message::QaSetHidReport(addr, report_type, report)).await; + }); + } + fn send_hid_data(&self, addr: String, data: String) { + let txl = self.tx.clone(); + tokio::spawn(async move { + let _ = txl.send(Message::QaSendHidData(addr, data)).await; + }); } } diff --git a/system/gd/rust/linux/stack/src/callbacks.rs b/system/gd/rust/linux/stack/src/callbacks.rs index 5f67648ac4ddb2330cea2f424cade3276e0e4bf5..c70c69955efbc7c62b0c847302a0f57925926a29 100644 --- a/system/gd/rust/linux/stack/src/callbacks.rs +++ b/system/gd/rust/linux/stack/src/callbacks.rs @@ -8,6 +8,7 @@ use crate::{Message, RPCProxy}; /// Utility for managing callbacks conveniently. pub struct Callbacks { callbacks: HashMap>, + object_id_to_cbid: HashMap, tx: Sender, disconnected_message: fn(u32) -> Message, } @@ -19,16 +20,26 @@ impl Callbacks { /// `tx`: Sender to use when notifying callback disconnect events. /// `disconnected_message`: Constructor of the message to be sent on callback disconnection. pub fn new(tx: Sender, disconnected_message: fn(u32) -> Message) -> Self { - Self { callbacks: HashMap::new(), tx, disconnected_message } + Self { + callbacks: HashMap::new(), + object_id_to_cbid: HashMap::new(), + tx, + disconnected_message, + } } - /// Stores a new callback and monitors for callback disconnect. + /// Stores a new callback and monitors for callback disconnect. If the callback object id + /// already exists, return the callback ID previously added. /// /// When the callback disconnects, a message is sent. This message should be handled and then /// the `remove_callback` function can be used. /// /// Returns the id of the callback. pub fn add_callback(&mut self, mut callback: Box) -> u32 { + if let Some(cbid) = self.object_id_to_cbid.get(&callback.get_object_id()) { + return *cbid; + } + let tx = self.tx.clone(); let disconnected_message = self.disconnected_message; let id = callback.register_disconnect(Box::new(move |cb_id| { @@ -38,6 +49,7 @@ impl Callbacks { }); })); + self.object_id_to_cbid.insert(callback.get_object_id(), id); self.callbacks.insert(id, callback); id } @@ -54,6 +66,7 @@ impl Callbacks { // Stop watching for disconnect. callback.unregister(id); // Remove the proxy object. + self.object_id_to_cbid.remove(&callback.get_object_id()); self.callbacks.remove(&id); true } @@ -78,3 +91,65 @@ impl Callbacks { } } } + +#[cfg(test)] +mod tests { + use std::sync::atomic::{AtomicU32, Ordering}; + + static CBID: AtomicU32 = AtomicU32::new(0); + + struct TestCallback { + id: String, + } + + impl TestCallback { + fn new(id: String) -> TestCallback { + TestCallback { id } + } + } + + impl RPCProxy for TestCallback { + fn get_object_id(&self) -> String { + self.id.clone() + } + fn register_disconnect(&mut self, _f: Box) -> u32 { + CBID.fetch_add(1, Ordering::SeqCst) + } + } + + use super::*; + + #[test] + fn test_add_and_remove() { + let (tx, _rx) = crate::Stack::create_channel(); + let mut callbacks = Callbacks::new(tx.clone(), Message::AdapterCallbackDisconnected); + + let cb_string = String::from("Test Callback"); + + // Test add + let cbid = callbacks.add_callback(Box::new(TestCallback::new(cb_string.clone()))); + let found = callbacks.get_by_id(cbid); + assert!(found.is_some()); + assert_eq!( + cb_string, + match found { + Some(c) => c.get_object_id(), + None => String::new(), + } + ); + + // Attempting to add another callback with same object id should return the same cbid + let cbid1 = callbacks.add_callback(Box::new(TestCallback::new(cb_string.clone()))); + assert_eq!(cbid, cbid1); + + // Test remove + let success = callbacks.remove_callback(cbid); + assert!(success); + let found = callbacks.get_by_id(cbid); + assert!(found.is_none()); + + // Attempting to add another callback with same object id should now return a new cbid + let cbid2 = callbacks.add_callback(Box::new(TestCallback::new(cb_string.clone()))); + assert_ne!(cbid, cbid2); + } +} diff --git a/system/gd/rust/linux/stack/src/lib.rs b/system/gd/rust/linux/stack/src/lib.rs index e1c12c2d4305133496db566f2117037f5c04beb4..12810d23ea50d485788490e1e425357246b4837e 100644 --- a/system/gd/rust/linux/stack/src/lib.rs +++ b/system/gd/rust/linux/stack/src/lib.rs @@ -20,8 +20,7 @@ pub mod socket_manager; pub mod suspend; pub mod uuid; -use bluetooth_qa::BluetoothQA; -use bt_topshim::btif::BtDiscMode; +use bluetooth_qa::{BluetoothQA, IBluetoothQA}; use log::debug; use num_derive::{FromPrimitive, ToPrimitive}; use std::sync::{Arc, Mutex}; @@ -39,6 +38,7 @@ use crate::bluetooth_admin::{BluetoothAdmin, IBluetoothAdmin}; use crate::bluetooth_gatt::{ dispatch_gatt_client_callbacks, dispatch_gatt_server_callbacks, dispatch_le_adv_callbacks, dispatch_le_scanner_callbacks, dispatch_le_scanner_inband_callbacks, BluetoothGatt, + GattActions, }; use crate::bluetooth_media::{BluetoothMedia, MediaActions}; use crate::dis::{DeviceInformation, ServiceCallbacks}; @@ -47,10 +47,17 @@ use crate::suspend::Suspend; use bt_topshim::{ btif::{BaseCallbacks, BtTransport}, profiles::{ - a2dp::A2dpCallbacks, avrcp::AvrcpCallbacks, gatt::GattAdvCallbacks, - gatt::GattAdvInbandCallbacks, gatt::GattClientCallbacks, gatt::GattScannerCallbacks, - gatt::GattScannerInbandCallbacks, gatt::GattServerCallbacks, hfp::HfpCallbacks, - hid_host::HHCallbacks, sdp::SdpCallbacks, + a2dp::A2dpCallbacks, + avrcp::AvrcpCallbacks, + gatt::GattAdvCallbacks, + gatt::GattAdvInbandCallbacks, + gatt::GattClientCallbacks, + gatt::GattScannerCallbacks, + gatt::GattScannerInbandCallbacks, + gatt::GattServerCallbacks, + hfp::HfpCallbacks, + hid_host::{BthhReportType, HHCallbacks}, + sdp::SdpCallbacks, }, }; @@ -58,6 +65,7 @@ use bt_topshim::{ pub enum Message { // Shuts down the stack. Shutdown, + Cleanup, // Adapter is enabled and ready. AdapterReady, @@ -79,6 +87,7 @@ pub enum Message { // Actions within the stack Media(MediaActions), MediaCallbackDisconnected(u32), + TelephonyCallbackDisconnected(u32), // Client callback disconnections AdapterCallbackDisconnected(u32), @@ -116,6 +125,7 @@ pub enum Message { BatteryServiceRefresh, BatteryManagerCallbackDisconnected(u32), + GattActions(GattActions), GattClientCallbackDisconnected(u32), GattServerCallbackDisconnected(u32), @@ -127,10 +137,35 @@ pub enum Message { // Dis callbacks Dis(ServiceCallbacks), + // Device removal + DisconnectDevice(BluetoothDevice), + // Qualification Only + QaCallbackDisconnected(u32), QaAddMediaPlayer(String, bool), QaRfcommSendMsc(u8, String), - QaOnDiscoverableModeChanged(BtDiscMode), + QaFetchDiscoverableMode, + QaFetchConnectable, + QaSetConnectable(bool), + QaFetchAlias, + QaGetHidReport(String, BthhReportType, u8), + QaSetHidReport(String, BthhReportType, String), + QaSendHidData(String, String), + + // UHid callbacks + UHidHfpOutputCallback(String, u8, u8), + UHidTelephonyUseCallback(String, bool), +} + +pub enum BluetoothAPI { + Adapter, + Battery, + Media, + Gatt, +} + +pub enum APIMessage { + IsReady(BluetoothAPI), } /// Represents suspend mode of a module. @@ -182,6 +217,10 @@ impl Stack { bluetooth.lock().unwrap().disable(); } + Message::Cleanup => { + bluetooth.lock().unwrap().cleanup(); + } + Message::AdapterReady => { // Initialize objects that need the adapter to be fully // enabled before running. @@ -250,6 +289,10 @@ impl Stack { bluetooth_media.lock().unwrap().remove_callback(cb_id); } + Message::TelephonyCallbackDisconnected(cb_id) => { + bluetooth_media.lock().unwrap().remove_telephony_callback(cb_id); + } + Message::AdapterCallbackDisconnected(id) => { bluetooth.lock().unwrap().adapter_callback_disconnected(id); } @@ -336,6 +379,9 @@ impl Stack { Message::BatteryManagerCallbackDisconnected(id) => { battery_manager.lock().unwrap().remove_callback(id); } + Message::GattActions(action) => { + bluetooth_gatt.lock().unwrap().handle_action(action); + } Message::GattClientCallbackDisconnected(id) => { bluetooth_gatt.lock().unwrap().remove_client_callback(id); } @@ -354,6 +400,9 @@ impl Stack { Message::Dis(callback) => { bluetooth_dis.lock().unwrap().handle_callbacks(&callback); } + Message::DisconnectDevice(addr) => { + bluetooth.lock().unwrap().disconnect_all_enabled_profiles(addr); + } // Qualification Only Message::QaAddMediaPlayer(name, browsing_supported) => { bluetooth_media.lock().unwrap().add_player(name, browsing_supported); @@ -361,8 +410,59 @@ impl Stack { Message::QaRfcommSendMsc(dlci, addr) => { bluetooth_socketmgr.lock().unwrap().rfcomm_send_msc(dlci, addr); } - Message::QaOnDiscoverableModeChanged(mode) => { - bluetooth_qa.lock().unwrap().handle_discoverable_mode_changed(mode); + Message::QaCallbackDisconnected(id) => { + bluetooth_qa.lock().unwrap().unregister_qa_callback(id); + } + Message::QaFetchDiscoverableMode => { + let mode = bluetooth.lock().unwrap().get_discoverable_mode_internal(); + bluetooth_qa.lock().unwrap().on_fetch_discoverable_mode_completed(mode); + } + Message::QaFetchConnectable => { + let connectable = bluetooth.lock().unwrap().get_connectable_internal(); + bluetooth_qa.lock().unwrap().on_fetch_connectable_completed(connectable); + } + Message::QaSetConnectable(mode) => { + let succeed = bluetooth.lock().unwrap().set_connectable_internal(mode); + bluetooth_qa.lock().unwrap().on_set_connectable_completed(succeed); + } + Message::QaFetchAlias => { + let alias = bluetooth.lock().unwrap().get_alias_internal(); + bluetooth_qa.lock().unwrap().on_fetch_alias_completed(alias); + } + Message::QaGetHidReport(addr, report_type, report_id) => { + let status = bluetooth.lock().unwrap().get_hid_report_internal( + addr, + report_type, + report_id, + ); + bluetooth_qa.lock().unwrap().on_get_hid_report_completed(status); + } + Message::QaSetHidReport(addr, report_type, report) => { + let status = bluetooth.lock().unwrap().set_hid_report_internal( + addr, + report_type, + report, + ); + bluetooth_qa.lock().unwrap().on_set_hid_report_completed(status); + } + Message::QaSendHidData(addr, data) => { + let status = bluetooth.lock().unwrap().send_hid_data_internal(addr, data); + bluetooth_qa.lock().unwrap().on_send_hid_data_completed(status); + } + + // UHid callbacks + Message::UHidHfpOutputCallback(addr, id, data) => { + bluetooth_media + .lock() + .unwrap() + .dispatch_uhid_hfp_output_callback(addr, id, data); + } + + Message::UHidTelephonyUseCallback(addr, state) => { + bluetooth_media + .lock() + .unwrap() + .dispatch_uhid_telephony_use_callback(addr, state); } } } diff --git a/system/gd/rust/linux/stack/src/socket_manager.rs b/system/gd/rust/linux/stack/src/socket_manager.rs index abebd730898470b624e956829f1ca0a383a699e9..5daa4e18554a46f44e65c0271710560a65b4c369 100644 --- a/system/gd/rust/linux/stack/src/socket_manager.rs +++ b/system/gd/rust/linux/stack/src/socket_manager.rs @@ -35,6 +35,7 @@ pub type CallbackId = u32; pub type SocketType = socket::SocketType; /// Result type for calls in `IBluetoothSocketManager`. +#[derive(Debug)] pub struct SocketResult { pub status: BtStatus, pub id: u64, @@ -56,7 +57,7 @@ pub const DYNAMIC_CHANNEL: i32 = -1; pub const INVALID_SOCKET_ID: SocketId = 0; /// Represents a listening socket. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct BluetoothServerSocket { pub id: SocketId, pub sock_type: SocketType, @@ -181,6 +182,7 @@ impl fmt::Display for BluetoothServerSocket { } /// Represents a connected socket. +#[derive(Debug)] pub struct BluetoothSocket { pub id: SocketId, pub remote_device: BluetoothDevice, @@ -295,6 +297,9 @@ pub trait IBluetoothSocketManager { callback: Box, ) -> CallbackId; + /// Unregister for socket callbacks. + fn unregister_callback(&mut self, callback: CallbackId) -> bool; + /// Create an insecure listening L2CAP socket. PSM is dynamically assigned. fn listen_using_insecure_l2cap_channel(&mut self, callback: CallbackId) -> SocketResult; @@ -400,6 +405,9 @@ struct InternalListeningSocket { /// Used by admin uuid: Option, + + /// Used for tracing task status + joinhandle: JoinHandle<()>, } impl InternalListeningSocket { @@ -408,22 +416,24 @@ impl InternalListeningSocket { socket_id: SocketId, tx: Sender, uuid: Option, + joinhandle: JoinHandle<()>, ) -> Self { - InternalListeningSocket { _callback_id, socket_id, tx, uuid } + InternalListeningSocket { _callback_id, socket_id, tx, uuid, joinhandle } } } /// Internal connecting socket data. struct InternalConnectingSocket { _callback_id: CallbackId, - socket_info: BluetoothSocket, - stream: Option, + socket_id: SocketId, + + /// Used for cleaning up + joinhandle: JoinHandle<()>, } impl InternalConnectingSocket { - fn new(_callback_id: CallbackId, socket_info: BluetoothSocket, fd: std::fs::File) -> Self { - let stream = file_to_unixstream(fd); - InternalConnectingSocket { _callback_id, socket_info, stream } + fn new(_callback_id: CallbackId, socket_id: SocketId, joinhandle: JoinHandle<()>) -> Self { + InternalConnectingSocket { _callback_id, socket_id, joinhandle } } } @@ -473,8 +483,11 @@ pub enum SocketActions { OnIncomingSocketClosed(CallbackId, SocketId, BtStatus), OnHandleIncomingConnection(CallbackId, SocketId, BluetoothSocket), - // Last event is for connecting socket. + // This event is for connecting socket. OnOutgoingConnectionResult(CallbackId, SocketId, BtStatus, Option), + + // Request to disconnect all sockets, e.g. when user disconnects the peer device. + DisconnectAll(RawAddress), } /// Implementation of the `IBluetoothSocketManager` api. @@ -485,8 +498,8 @@ pub struct BluetoothSocketManager { /// List of listening sockets. listening: HashMap>, - /// Current futures mapped by callback id (so we can drop if callback disconnects). - futures: HashMap>>, + /// List of connecting sockets with futures (so we can drop if callback disconnects). + connecting: HashMap>, /// Separate runtime for socket listeners (so they're not dependent on the /// same runtime as RPC). @@ -511,7 +524,7 @@ impl BluetoothSocketManager { pub fn new(tx: Sender, admin: Arc>>) -> Self { let callbacks = Callbacks::new(tx.clone(), Message::SocketManagerCallbackDisconnected); let socket_counter: u64 = 1000; - let futures = HashMap::new(); + let connecting = HashMap::new(); let listening = HashMap::new(); let runtime = Arc::new( Builder::new_multi_thread() @@ -524,7 +537,7 @@ impl BluetoothSocketManager { BluetoothSocketManager { callbacks, - futures, + connecting, listening, runtime, sock: None, @@ -567,6 +580,14 @@ impl BluetoothSocketManager { log::debug!("service {} is blocked by admin policy", uuid); return SocketResult::new(BtStatus::AuthRejected, INVALID_SOCKET_ID); } + if self + .listening + .iter() + .any(|(_, v)| v.iter().any(|s| s.uuid.map_or(false, |u| u == uuid))) + { + log::warn!("Service {} already exists", uuid); + return SocketResult::new(BtStatus::Fail, INVALID_SOCKET_ID); + } } // Create listener socket pair @@ -596,10 +617,7 @@ impl BluetoothSocketManager { let id = self.next_socket_id(); socket_info.id = id; let (runner_tx, runner_rx) = channel::(10); - - // Keep track of active listener sockets. - let listener = InternalListeningSocket::new(cbid, id, runner_tx, socket_info.uuid); - self.listening.entry(cbid).or_default().push(listener); + let uuid = socket_info.uuid.clone(); // Push a listening task to local runtime to wait for device to // start accepting or get closed. @@ -628,7 +646,11 @@ impl BluetoothSocketManager { .await; }); - self.futures.entry(cbid).or_default().push(joinhandle); + // Keep track of active listener sockets. + self.listening + .entry(cbid) + .or_default() + .push(InternalListeningSocket::new(cbid, id, runner_tx, uuid, joinhandle)); SocketResult::new(status, id) } @@ -694,7 +716,6 @@ impl BluetoothSocketManager { // callbacks. let id = self.next_socket_id(); socket_info.id = id; - let connector = InternalConnectingSocket::new(cbid, socket_info, file); // Push a connecting task to local runtime to wait for connection // completion. @@ -704,7 +725,8 @@ impl BluetoothSocketManager { cbid, id, tx, - connector, + socket_info, + file_to_unixstream(file), Duration::from_millis(CONNECT_COMPLETE_TIMEOUT_MS), ) .await; @@ -712,7 +734,10 @@ impl BluetoothSocketManager { // Keep track of these futures in case they need to be cancelled due to callback // disconnecting. - self.futures.entry(cbid).or_default().push(joinhandle); + self.connecting + .entry(cbid) + .or_default() + .push(InternalConnectingSocket::new(cbid, id, joinhandle)); SocketResult::new(status, id) } @@ -839,7 +864,7 @@ impl BluetoothSocketManager { SocketActions::OnIncomingSocketReady( cbid, cloned_socket_info, - BtStatus::Fail, + BtStatus::Timeout, ), )) .await; @@ -899,7 +924,7 @@ impl BluetoothSocketManager { Ok(None) } } - Err(e) => Ok(None), + Err(_) => Ok(None), }; } @@ -1027,12 +1052,13 @@ impl BluetoothSocketManager { cbid: CallbackId, socket_id: SocketId, tx: Sender, - connector: InternalConnectingSocket, + socket_info: BluetoothSocket, + stream: Option, connection_timeout: Duration, ) { // If the unixstream isn't available for this connection, immediately return // a failure. - let stream = match connector.stream { + let stream = match stream { Some(s) => s, None => { let _ = tx @@ -1057,7 +1083,7 @@ impl BluetoothSocketManager { if status != BtStatus::Success { log::info!( "Connecting socket to {} failed while trying to read channel from stream", - connector.socket_info + socket_info ); let _ = tx .send(Message::SocketManagerActions(SocketActions::OnOutgoingConnectionResult( @@ -1073,7 +1099,7 @@ impl BluetoothSocketManager { if status != BtStatus::Success { log::info!( "Connecting socket to {} failed while trying to read connect complete from stream", - connector.socket_info + socket_info ); let _ = tx .send(Message::SocketManagerActions(SocketActions::OnOutgoingConnectionResult( @@ -1097,7 +1123,7 @@ impl BluetoothSocketManager { )) .await; } else { - let mut sock = connector.socket_info; + let mut sock = socket_info; sock.fd = Some(unixstream_to_file(stream)); sock.port = cc.channel; sock.max_rx_size = cc.max_rx_packet_size.into(); @@ -1157,8 +1183,17 @@ impl BluetoothSocketManager { SocketActions::OnOutgoingConnectionResult(cbid, socket_id, status, socket) => { if let Some(callback) = self.callbacks.get_by_id_mut(cbid) { callback.on_outgoing_connection_result(socket_id, status, socket); + + // Also make sure to remove the socket from connecting list. + self.connecting + .entry(cbid) + .and_modify(|v| v.retain(|s| s.socket_id != socket_id)); } } + + SocketActions::DisconnectAll(addr) => { + self.sock.as_ref().expect("Socket Manager not initialized").disconnect_all(addr); + } } } @@ -1193,8 +1228,23 @@ impl BluetoothSocketManager { pub fn remove_callback(&mut self, callback: CallbackId) { // Remove any associated futures and sockets waiting to accept. - self.futures.remove(&callback); - self.listening.remove(&callback); + self.connecting.remove(&callback).map(|sockets| { + for s in sockets { + s.joinhandle.abort(); + } + }); + self.listening.remove(&callback).map(|sockets| { + for s in sockets { + if s.joinhandle.is_finished() { + continue; + } + let tx = s.tx.clone(); + let id = s.socket_id; + self.runtime.spawn(async move { + let _ = tx.send(SocketRunnerActions::Close(id)).await; + }); + } + }); self.callbacks.remove_callback(callback); } @@ -1228,6 +1278,10 @@ impl IBluetoothSocketManager for BluetoothSocketManager { self.callbacks.add_callback(callback) } + fn unregister_callback(&mut self, callback: CallbackId) -> bool { + self.callbacks.remove_callback(callback) + } + fn listen_using_insecure_l2cap_channel(&mut self, callback: CallbackId) -> SocketResult { if self.callbacks.get_by_id(callback).is_none() { return SocketResult::new(BtStatus::NotReady, INVALID_SOCKET_ID); diff --git a/system/gd/rust/linux/stack/src/suspend.rs b/system/gd/rust/linux/stack/src/suspend.rs index 53b3bf46960a8940a169bf738026bf52498b2d74..221ae2ae226d4a6394f945e1a5924c32215a0b7f 100644 --- a/system/gd/rust/linux/stack/src/suspend.rs +++ b/system/gd/rust/linux/stack/src/suspend.rs @@ -12,6 +12,8 @@ use num_derive::{FromPrimitive, ToPrimitive}; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::Sender; +use bt_utils::socket::{BtSocket, HciChannels, MgmtCommand, HCI_DEV_NONE}; + /// Defines the Suspend/Resume API. /// /// This API is exposed by `btadapterd` and independent of the suspend/resume detection mechanism @@ -63,7 +65,42 @@ const MASKED_EVENTS_FOR_SUSPEND: u64 = (1u64 << 4) | (1u64 << 19); /// However, we will need to delay a few seconds to avoid co-ex issues with Wi-Fi reconnection. const RECONNECT_AUDIO_ON_RESUME_DELAY_MS: u64 = 3000; -#[derive(FromPrimitive, ToPrimitive)] +/// TODO(b/286268874) Remove after the synchronization issue is resolved. +/// Delay sending suspend ready signal by some time. +const LE_RAND_CB_SUSPEND_READY_DELAY_MS: u64 = 100; + +fn notify_suspend_state(hci_index: u16, suspended: bool) { + log::debug!("Notify kernel suspend status: {} for hci{}", suspended, hci_index); + let mut btsock = BtSocket::new(); + match btsock.open() { + -1 => { + panic!( + "Bluetooth socket unavailable (errno {}). Try loading the kernel module first.", + std::io::Error::last_os_error().raw_os_error().unwrap_or(0) + ); + } + x => log::debug!("notify suspend Socket open at fd: {}", x), + } + // Bind to control channel (which is used for mgmt commands). We provide + // HCI_DEV_NONE because we don't actually need a valid HCI dev for some MGMT commands. + match btsock.bind_channel(HciChannels::Control, HCI_DEV_NONE) { + -1 => { + panic!( + "Failed to bind control channel with errno={}", + std::io::Error::last_os_error().raw_os_error().unwrap_or(0) + ); + } + _ => (), + }; + + let command = MgmtCommand::FlossNotifySuspendState(hci_index, suspended); + let bytes_written = btsock.write_mgmt_packet(command.into()); + if bytes_written <= 0 { + log::error!("Failed to notify suspend state on hci:{} to {}", hci_index, suspended); + } +} + +#[derive(Debug, FromPrimitive, ToPrimitive)] #[repr(u32)] pub enum SuspendType { NoWakesAllowed, @@ -150,6 +187,8 @@ impl Suspend { } pub(crate) fn suspend_ready(&mut self, suspend_id: i32) { + let hci_index = self.bt.lock().unwrap().get_hci_index(); + notify_suspend_state(hci_index, true); self.callbacks.for_all_callbacks(|callback| { callback.on_suspend_ready(suspend_id); }); @@ -246,7 +285,6 @@ impl ISuspend for Suspend { suspend_state.lock().unwrap().le_rand_expected = false; suspend_state.lock().unwrap().suspend_expected = false; - suspend_state.lock().unwrap().suspend_id = None; tokio::spawn(async move { let _result = tx.send(Message::SuspendReady(suspend_id)).await; }); @@ -254,6 +292,9 @@ impl ISuspend for Suspend { } fn resume(&mut self) -> bool { + let hci_index = self.bt.lock().unwrap().get_hci_index(); + notify_suspend_state(hci_index, false); + self.intf.lock().unwrap().set_default_event_mask_except(0u64, 0u64); // Restore event filter and accept list to normal. @@ -345,6 +386,10 @@ impl BtifBluetoothCallbacks for Suspend { self.suspend_state.lock().unwrap().suspend_expected = false; let tx = self.tx.clone(); tokio::spawn(async move { + tokio::time::sleep(tokio::time::Duration::from_millis( + LE_RAND_CB_SUSPEND_READY_DELAY_MS, + )) + .await; let _result = tx.send(Message::SuspendReady(suspend_id)).await; }); } diff --git a/system/gd/rust/linux/stack/src/uuid.rs b/system/gd/rust/linux/stack/src/uuid.rs index 32a8bb2c5f92bbbd7d4e4a4f347b07b9afbf60bf..f378ce4509a919623d2a33c783f4e8c7fe6b66c1 100644 --- a/system/gd/rust/linux/stack/src/uuid.rs +++ b/system/gd/rust/linux/stack/src/uuid.rs @@ -109,7 +109,10 @@ impl<'a> Display for KnownUuidWrapper<'a> { pub struct UuidHelper {} lazy_static! { - static ref SUPPORTED_PROFILES: HashSet = [ + // AVRCP fights with A2DP when initializing, so let's initiate profiles in a known good order. + // Specifically, A2DP must be initialized before AVRCP. + // TODO (b/286991526): remove after issue is resolved + static ref ORDERED_SUPPORTED_PROFILES: Vec = vec![ Profile::A2dpSink, Profile::A2dpSource, Profile::AvrcpController, @@ -125,10 +128,12 @@ lazy_static! { Profile::HearingAid, Profile::VolumeControl, Profile::CoordinatedSet, - ] - .iter() - .cloned() - .collect(); + ]; +} + +lazy_static! { + static ref SUPPORTED_PROFILES: HashSet = + ORDERED_SUPPORTED_PROFILES.iter().cloned().collect(); } lazy_static! { @@ -185,6 +190,12 @@ impl UuidHelper { PROFILES.get(uuid).cloned() } + // AVRCP fights with A2DP when initializing, so let's initiate profiles in a known good order. + // TODO (b/286991526): remove after issue is resolved + pub fn get_ordered_supported_profiles() -> Vec { + ORDERED_SUPPORTED_PROFILES.clone() + } + pub fn get_supported_profiles() -> HashSet { SUPPORTED_PROFILES.clone() } diff --git a/system/gd/rust/linux/utils/Cargo.toml b/system/gd/rust/linux/utils/Cargo.toml index 8328ed86113235397a802406fea25df0c8800e5a..c04d5cc8f52df02d0d64c3b2ab0609896099a3a1 100644 --- a/system/gd/rust/linux/utils/Cargo.toml +++ b/system/gd/rust/linux/utils/Cargo.toml @@ -25,6 +25,8 @@ log = "0.4.14" nix = "0.23" num-derive = "0.3" num-traits = "0.2" +uhid-virt = "0.0.6" +tokio = { version = "1", features = ['rt'] } [lib] crate-type = ["rlib"] diff --git a/system/gd/rust/linux/utils/src/at_command_parser.rs b/system/gd/rust/linux/utils/src/at_command_parser.rs new file mode 100644 index 0000000000000000000000000000000000000000..35d4faee20ea72bb25c10aa9c27bc430b5590fb1 --- /dev/null +++ b/system/gd/rust/linux/utils/src/at_command_parser.rs @@ -0,0 +1,443 @@ +// Helper methods for parsing HFP AT command codes. While most AT commands are processed at lower +// levels, some commands are not part of the HFP specification or need to be parsed within Floss for +// whatever reason. + +use std::collections::HashMap; + +/// The AT command type indicated. +#[derive(Clone, Debug, PartialEq)] +pub enum AtCommandType { + Set, + Query, + Test, + Execute, +} + +// Delimiters for AT commands. Execute has no delimiter. +const AT_COMMAND_DELIMITER_SET: &str = "="; +const AT_COMMAND_DELIMITER_QUERY: &str = "?"; +const AT_COMMAND_DELIMITER_TEST: &str = "=?"; + +// Strings for indicating which spec is being used. Apple's XAPL/IPHONEACCEV and Plantronics/Poly's +// XEVENT are supported. +const AT_COMMAND_VENDOR_APPLE: &str = "Apple"; +const AT_COMMAND_VENDOR_PLANTRONICS: &str = "Plantronics"; + +// Vendor-specific commands and attributes. +const AT_COMMAND_VENDOR_XAPL: &str = "XAPL"; +const AT_COMMAND_VENDOR_IPHONEACCEV: &str = "IPHONEACCEV"; +const AT_COMMAND_VENDOR_IPHONEACCEV_BATTERY: &str = "1"; +const AT_COMMAND_VENDOR_XEVENT: &str = "XEVENT"; + +/// Known types of data contained within commands. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum AtCommandDataType { + IPhoneAccevBatteryLevel, + XeventBatteryLevel, + XeventBatteryLevelRange, + XeventEvent, +} + +/// Details of an AtCommand broken into parts representing varying degrees of extraction and +/// interpretation. +#[derive(Clone)] +pub struct AtCommand { + // The original, unparsed, AT command + pub raw: String, + // The nature of the command according to AT command specifications + pub at_type: AtCommandType, + // The actual command being sent (AT+=?) + pub command: String, + // Unparsed arguments from the raw command string, in order + pub raw_args: Option>, + // For vendor-specific AT commands + pub vendor: Option, + // For commands with known value types + pub data: Option>, +} + +const AT_COMMAND_ARG_DELIMITER: &str = ","; + +/// Attempt to extract as much data as possible from the AT command. For commands of a known type, +/// attempt to extract known fields and validate the format. +pub fn parse_at_command_data(at_string: String) -> Result { + // All AT commands should be of the form AT+ but may be passed around as + or + // . We remove those here for convenience. + let clean_at_string = at_string.strip_prefix("+").unwrap_or(&at_string); + let clean_at_string = clean_at_string.strip_prefix("AT+").unwrap_or(&clean_at_string); + if clean_at_string.is_empty() { + return Err("Cannot parse empty AT command".to_string()); + } + let at_type = parse_at_command_type(clean_at_string.to_string()); + let at_type_delimiter = match at_type { + AtCommandType::Set => AT_COMMAND_DELIMITER_SET, + AtCommandType::Query => AT_COMMAND_DELIMITER_QUERY, + AtCommandType::Test => AT_COMMAND_DELIMITER_TEST, + AtCommandType::Execute => "", + }; + // We want to keep the flow of this method consistent, but AtCommandType::Execute commands do + // not have arguments. To resolve this we split those commands differently. + let mut command_parts = match at_type { + AtCommandType::Execute => clean_at_string.splitn(1, at_type_delimiter), + _ => clean_at_string.splitn(2, at_type_delimiter), + }; + let command = match command_parts.next() { + Some(command) => command, + // In practice this cannot happen as parse_at_command_type already found the delimiter. + None => return Err("No command supplied".to_string()), + }; + let vendor = match command { + AT_COMMAND_VENDOR_XAPL => Some(AT_COMMAND_VENDOR_APPLE.to_string()), + AT_COMMAND_VENDOR_IPHONEACCEV => Some(AT_COMMAND_VENDOR_APPLE.to_string()), + AT_COMMAND_VENDOR_XEVENT => Some(AT_COMMAND_VENDOR_PLANTRONICS.to_string()), + _ => None, + }; + let raw_args = match command_parts.next() { + Some(arg_string) => { + if arg_string == "" { + None + } else { + Some( + arg_string + .split(AT_COMMAND_ARG_DELIMITER) + .map(|arg| arg.to_string()) + .collect::>(), + ) + } + } + None => None, + }; + let data = match (raw_args.clone(), command) { + (Some(args), AT_COMMAND_VENDOR_IPHONEACCEV) => Some(extract_iphoneaccev_data(args)?), + (Some(args), AT_COMMAND_VENDOR_XEVENT) => Some(extract_xevent_data(args)?), + (Some(_), _) => None, + (None, _) => None, + }; + Ok(AtCommand { + raw: at_string.to_string(), + at_type: at_type, + command: command.to_string(), + raw_args: raw_args, + vendor: vendor, + data: data, + }) +} + +/// If present, battery data is extracted and returned as an integer in the range of [0, 100]. If +/// there is no battery data or the improperly formatted data, an error is returned. +pub fn calculate_battery_percent(at_command: AtCommand) -> Result { + match at_command.data { + Some(data) => { + match data.get(&AtCommandDataType::IPhoneAccevBatteryLevel) { + Some(battery_level) => match battery_level.parse::() { + Ok(level) => return Ok(level * 10), + Err(e) => return Err(e.to_string()), + }, + None => (), + } + match data.get(&AtCommandDataType::XeventBatteryLevel) { + Some(battery_level) => { + match data.get(&AtCommandDataType::XeventBatteryLevelRange) { + Some(battery_level_range) => { + match (battery_level.parse::(), battery_level_range.parse::()) + { + (Ok(level), Ok(range)) => { + if level > range { + return Err(format!( + "Invalid battery level {}/{}", + level, range + )); + } + // Mathematically it is not possible to represent anything + // meaningful if there are not at least two options for + // BatteryLevel. + if range < 2 { + return Err( + "BatteryLevelRange must be at least 2".to_string() + ); + } + return Ok((f64::from(level) / f64::from(range - 1) * 100.0) + .floor() + as u32); + } + (Err(e), _) => return Err(e.to_string()), + (Ok(_), Err(e)) => return Err(e.to_string()), + } + } + None => return Err("BatteryLevelRange missing".to_string()), + } + } + None => (), + } + } + None => return Err("No battery data found".to_string()), + } + Err("No battery data found".to_string()) +} + +fn parse_at_command_type(command: String) -> AtCommandType { + if command.contains(AT_COMMAND_DELIMITER_TEST) { + return AtCommandType::Test; + } + if command.contains(AT_COMMAND_DELIMITER_QUERY) { + return AtCommandType::Query; + } + if command.contains(AT_COMMAND_DELIMITER_SET) { + return AtCommandType::Set; + } + return AtCommandType::Execute; +} + +// Format: +// AT+IPHONEACCEV=[NumberOfIndicators],[IndicatorType],[IndicatorValue] +fn extract_iphoneaccev_data( + args: Vec, +) -> Result, String> { + let num_provided_args: u32 = match args.len().try_into() { + Ok(num) => num, + Err(e) => return Err(e.to_string()), + }; + let mut args = args.iter(); + match args.next() { + Some(num_claimed) => { + let num_claimed = match num_claimed.parse::() { + Ok(num) => num * 2 + 1, + Err(e) => return Err(e.to_string()), + }; + if num_claimed != num_provided_args { + return Err(format!( + "{} indicators were claimed but only {} were found", + num_claimed, num_provided_args + )); + } + } + None => return Err("Expected at least one argument (NumberOfIndicators)".to_string()), + }; + let mut data = HashMap::new(); + while let Some(indicator_type) = args.next() { + let indicator_value = args + .next() + .ok_or(format!("Failed to find matching value for indicator {}", indicator_type))?; + // We currently only support battery-related data + let indicator_type: &str = indicator_type; + match indicator_type { + AT_COMMAND_VENDOR_IPHONEACCEV_BATTERY => { + data.insert( + AtCommandDataType::IPhoneAccevBatteryLevel, + indicator_value.to_string(), + ); + } + _ => continue, + } + } + Ok(data) +} + +fn extract_xevent_data(args: Vec) -> Result, String> { + let mut data = HashMap::new(); + let mut args = args.iter(); + let xevent_type = match args.next() { + Some(event_type) => event_type, + None => return Err("Expected at least one argument".to_string()), + }; + data.insert(AtCommandDataType::XeventEvent, xevent_type.to_string()); + + // For now we only support BATTERY events. + if xevent_type != "BATTERY" { + return Ok(data); + } + // Format: + // AT+XEVENT=BATTERY,[Level],[NumberOfLevel],[MinutesOfTalk],[IsCharging] + // Battery percentage = 100 * ( Level / (NumberOfLevel - 1 ) ) + match args.next() { + Some(battery_level) => { + data.insert(AtCommandDataType::XeventBatteryLevel, battery_level.to_string()); + } + None => return Err("Expected BatteryLevel argument".to_string()), + } + match args.next() { + Some(battery_level_range) => { + data.insert( + AtCommandDataType::XeventBatteryLevelRange, + battery_level_range.to_string(), + ); + } + None => return Err("Expected BatterLevelRange".to_string()), + } + // There are more arguments but we don't yet use them. + Ok(data) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_empty_fails() { + let at_command = parse_at_command_data("".to_string()); + assert!(at_command.is_err()); + + let at_command = parse_at_command_data("+".to_string()); + assert!(at_command.is_err()); + + let at_command = parse_at_command_data("AT+".to_string()); + assert!(at_command.is_err()); + } + + #[test] + fn test_at_string_copied() { + // A basic command with + preceding + let at_command = parse_at_command_data("+CMD".to_string()).unwrap(); + assert_eq!(at_command.raw, "+CMD"); + } + + #[test] + fn test_parse_command_type() { + let at_command = parse_at_command_data("CMD=".to_string()).unwrap(); + assert_eq!(at_command.at_type, AtCommandType::Set); + + let at_command = parse_at_command_data("CMD?".to_string()).unwrap(); + assert_eq!(at_command.at_type, AtCommandType::Query); + + let at_command = parse_at_command_data("CMD=?".to_string()).unwrap(); + assert_eq!(at_command.at_type, AtCommandType::Test); + + let at_command = parse_at_command_data("CMD".to_string()).unwrap(); + assert_eq!(at_command.at_type, AtCommandType::Execute); + } + + #[test] + fn test_parse_command() { + // A basic command + let at_command = parse_at_command_data("CMD".to_string()).unwrap(); + assert_eq!(at_command.command, "CMD"); + + // A basic command with AT+ preceding + let at_command = parse_at_command_data("AT+CMD".to_string()).unwrap(); + assert_eq!(at_command.command, "CMD"); + + // A basic command with arguments + let at_command = parse_at_command_data("CMD=a,b,c".to_string()).unwrap(); + assert_eq!(at_command.command, "CMD"); + } + + #[test] + fn test_parse_args() { + // No args + let at_command = parse_at_command_data("AT+CMD".to_string()).unwrap(); + assert_eq!(at_command.raw_args, None); + + // With args + let at_command = parse_at_command_data("AT+CMD=a,b,c".to_string()).unwrap(); + assert_eq!( + at_command.raw_args, + Some(vec!["a".to_string(), "b".to_string(), "c".to_string()]) + ); + } + + #[test] + fn test_parse_vendor() { + // With no known vendor + let at_command = parse_at_command_data("AT+CMD".to_string()).unwrap(); + assert_eq!(at_command.vendor, None); + + // With XAPL + let at_command = parse_at_command_data("AT+XAPL".to_string()).unwrap(); + assert_eq!(at_command.vendor, Some(AT_COMMAND_VENDOR_APPLE.to_string())); + + // With IPHONEACCEV + let at_command = parse_at_command_data("AT+IPHONEACCEV".to_string()).unwrap(); + assert_eq!(at_command.vendor, Some(AT_COMMAND_VENDOR_APPLE.to_string())); + + // With XEVENT + let at_command = parse_at_command_data("AT+XEVENT".to_string()).unwrap(); + assert_eq!(at_command.vendor, Some(AT_COMMAND_VENDOR_PLANTRONICS.to_string())); + } + + #[test] + fn test_parse_iphoneaccev_data() { + // No args + let at_command = parse_at_command_data("AT+IPHONEACCEV=".to_string()).unwrap(); + assert_eq!(at_command.data, None); + + // Battery args + let at_command = parse_at_command_data("AT+IPHONEACCEV=1,1,2".to_string()).unwrap(); + assert_eq!( + at_command.data, + Some(HashMap::from([(AtCommandDataType::IPhoneAccevBatteryLevel, "2".to_string())])) + ); + + // Multiple args + let at_command = parse_at_command_data("AT+IPHONEACCEV=2,2,3,1,2".to_string()).unwrap(); + assert_eq!( + at_command.data, + Some(HashMap::from([(AtCommandDataType::IPhoneAccevBatteryLevel, "2".to_string())])) + ); + + // Invalid arg count + let at_command = parse_at_command_data("AT+IPHONEACCEV=3,1,2".to_string()); + assert!(at_command.is_err()); + } + + #[test] + fn test_parse_xevent_data() { + // No args + let at_command = parse_at_command_data("AT+XEVENT=".to_string()).unwrap(); + assert_eq!(at_command.data, None); + + // No args + let at_command = parse_at_command_data("AT+XEVENT=DON".to_string()).unwrap(); + assert_eq!( + at_command.data, + Some(HashMap::from([(AtCommandDataType::XeventEvent, "DON".to_string())])) + ); + } + + #[test] + fn test_parse_xevent_battery_data() { + // Missing args + let at_command = parse_at_command_data("AT+XEVENT=BATTERY".to_string()); + assert!(at_command.is_err()); + + let at_command = parse_at_command_data("AT+XEVENT=BATTERY,5,9,10,0".to_string()).unwrap(); + assert_eq!( + at_command.data, + Some(HashMap::from([ + (AtCommandDataType::XeventEvent, "BATTERY".to_string()), + (AtCommandDataType::XeventBatteryLevel, "5".to_string()), + (AtCommandDataType::XeventBatteryLevelRange, "9".to_string()), + ])) + ); + } + + #[test] + fn test_calculate_battery_percent() { + // Non-battery command + let at_command = parse_at_command_data("AT+CMD".to_string()); + assert!(!at_command.is_err()); + let battery_level = calculate_battery_percent(at_command.unwrap()); + assert!(battery_level.is_err()); + + // Apple - no battery + let at_command = parse_at_command_data("AT+IPHONEACCEV=1,2,3".to_string()); + assert!(!at_command.is_err()); + let battery_level = calculate_battery_percent(at_command.unwrap()); + assert!(battery_level.is_err()); + + // Apple + let at_command = parse_at_command_data("AT+IPHONEACCEV=1,1,2".to_string()); + assert!(!at_command.is_err()); + let battery_level = calculate_battery_percent(at_command.unwrap()).unwrap(); + assert_eq!(battery_level, 20); + + // Plantronics - missing args + let at_command = parse_at_command_data("AT+XEVENT=BATTERY".to_string()); + assert!(at_command.is_err()); + + // Plantronics + let at_command = parse_at_command_data("AT+XEVENT=BATTERY,5,11,10,0".to_string()); + assert!(!at_command.is_err()); + let battery_level = calculate_battery_percent(at_command.unwrap()).unwrap(); + assert_eq!(battery_level, 50); + } +} diff --git a/system/gd/rust/linux/utils/src/lib.rs b/system/gd/rust/linux/utils/src/lib.rs index 422414625229e3b5cb8baa23eeb43a5825ac08fa..bf7f815b14dd675b85ed39aa82fae4ffe5f8c8d6 100644 --- a/system/gd/rust/linux/utils/src/lib.rs +++ b/system/gd/rust/linux/utils/src/lib.rs @@ -2,6 +2,9 @@ pub mod adv_parser; pub mod array_utils; +pub mod at_command_parser; pub mod cod; pub mod socket; +pub mod uhid; +pub mod uhid_hfp; pub mod uinput; diff --git a/system/gd/rust/linux/utils/src/socket.rs b/system/gd/rust/linux/utils/src/socket.rs index 8df2b70d4ac1d4197afe9664cd0b4b46502bc879..5cd9e5ed0eed18d23e6f5ca46b3a6cb59705e2fc 100644 --- a/system/gd/rust/linux/utils/src/socket.rs +++ b/system/gd/rust/linux/utils/src/socket.rs @@ -76,6 +76,7 @@ impl MgmtPacket { #[derive(FromPrimitive, ToPrimitive)] pub enum MgmtCommandOpcode { ReadIndexList = 0x3, + FlossNotifySuspendState = 0x103, } impl From for u16 { @@ -97,6 +98,7 @@ impl TryFrom for MgmtCommandOpcode { pub enum MgmtCommand { ReadIndexList, + FlossNotifySuspendState(u16, bool), } impl From for MgmtPacket { @@ -108,6 +110,12 @@ impl From for MgmtPacket { len: 0, data: Vec::new(), }, + MgmtCommand::FlossNotifySuspendState(hci_index, suspended) => MgmtPacket { + opcode: MgmtCommandOpcode::FlossNotifySuspendState.into(), + index: HCI_DEV_NONE, + len: MGMT_NOTIFY_SUSPEND_STATE_SIZE, + data: MgmtCpNotifySuspendState::new(hci_index, u8::from(suspended)).to_data(), + }, } } } @@ -151,6 +159,27 @@ pub enum MgmtEvent { IndexRemoved(u16), } +#[derive(Debug)] +pub struct MgmtCpNotifySuspendState { + hci_id: u16, + suspended: u8, +} + +pub const MGMT_NOTIFY_SUSPEND_STATE_SIZE: u16 = 0x3; + +impl MgmtCpNotifySuspendState { + pub fn new(hci_id: u16, suspended: u8) -> Self { + MgmtCpNotifySuspendState { hci_id, suspended } + } + + pub fn to_data(&self) -> Vec { + let mut v: Vec = Vec::new(); + v.extend_from_slice(self.hci_id.to_le_bytes().as_slice()); + v.extend_from_slice(self.suspended.to_le_bytes().as_slice()); + v + } +} + impl TryFrom for MgmtEvent { type Error = (); @@ -200,6 +229,9 @@ impl TryFrom for MgmtEvent { MgmtCommandResponse::ReadIndexList { num_intf: len, interfaces } } + MgmtCommandOpcode::FlossNotifySuspendState => { + MgmtCommandResponse::DataUnused + } } } else { MgmtCommandResponse::DataUnused diff --git a/system/gd/rust/linux/utils/src/uhid.rs b/system/gd/rust/linux/utils/src/uhid.rs new file mode 100644 index 0000000000000000000000000000000000000000..9fca56314d84fe470b094ec164bba19eacaa33e2 --- /dev/null +++ b/system/gd/rust/linux/utils/src/uhid.rs @@ -0,0 +1,97 @@ +//! This library provides access to Linux uhid. + +use log::{debug, error}; +use std::fs::File; +use uhid_virt::{Bus, CreateParams, UHIDDevice}; + +const VID_DEFAULT: u32 = 0x0000; +const PID_DEFAULT: u32 = 0x0000; + +/// Default address for a virtual uhid device. +pub const BD_ADDR_DEFAULT: &str = "00:00:00:00:00:00"; + +// Report descriptor for a standard mouse +const RDESC: [u8; 50] = [ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +]; + +pub struct UHid { + /// Open UHID objects. + devices: Vec>, +} + +impl Drop for UHid { + fn drop(&mut self) { + self.clear(); + } +} + +impl UHid { + /// Create a new UHid struct that holds a vector of uhid objects. + pub fn new() -> Self { + UHid { devices: Vec::>::new() } + } + + /// Initialize a uhid device with kernel. + pub fn create(&mut self, name: String, phys: String, uniq: String) -> Result<(), String> { + debug!("Create a UHID {} with phys: {}, uniq: {}", name, phys, uniq); + let rd_data = RDESC.to_vec(); + let create_params = CreateParams { + name: name, + phys: phys, + uniq: uniq, + bus: Bus::BLUETOOTH, + vendor: VID_DEFAULT, + product: PID_DEFAULT, + version: 0, + country: 0, + rd_data, + }; + match UHIDDevice::create(create_params) { + Ok(d) => self.devices.push(d), + Err(e) => return Err(e.to_string()), + } + Ok(()) + } + + /// Destroy open UHID devices and clear the storage. + pub fn clear(&mut self) { + for device in self.devices.iter_mut() { + match device.destroy() { + Err(e) => error!("Fail to destroy uhid {}", e), + Ok(_) => (), + } + } + self.devices.clear(); + } + + /// Return if the UHID vector is empty. + pub fn is_empty(&self) -> bool { + self.devices.is_empty() + } +} diff --git a/system/gd/rust/linux/utils/src/uhid_hfp.rs b/system/gd/rust/linux/utils/src/uhid_hfp.rs new file mode 100644 index 0000000000000000000000000000000000000000..296a131f11bbb4d2ff5378e5a4ec9a66c335cd60 --- /dev/null +++ b/system/gd/rust/linux/utils/src/uhid_hfp.rs @@ -0,0 +1,164 @@ +//! This library provides UHID for HFP to interact with WebHID. + +use bt_topshim::topstack; +use log::debug; +use std::convert::TryFrom; +use std::fs::{File, OpenOptions}; +use std::io::{self, Read, Write}; +use std::os::unix::fs::OpenOptionsExt; +use std::path::Path; +pub use uhid_virt::OutputEvent; +use uhid_virt::{Bus, CreateParams, InputEvent, StreamError, UHID_EVENT_SIZE}; + +pub const BLUETOOTH_TELEPHONY_UHID_REPORT_ID: u8 = 1; +pub const UHID_INPUT_HOOK_SWITCH: u8 = 1 << 0; +pub const UHID_INPUT_PHONE_MUTE: u8 = 1 << 1; +pub const UHID_OUTPUT_NONE: u8 = 0; +pub const UHID_OUTPUT_RING: u8 = 1 << 0; +pub const UHID_OUTPUT_OFF_HOOK: u8 = 1 << 1; +pub const UHID_OUTPUT_MUTE: u8 = 1 << 2; + +const RDESC: [u8; 55] = [ + 0x05, + 0x0B, // Usage Page (Telephony) + 0x09, + 0x05, // Usage (Headset) + 0xA1, + 0x01, // Collection (Application) + 0x85, + BLUETOOTH_TELEPHONY_UHID_REPORT_ID, // Report ID (1) + 0x05, + 0x0B, // Usage Page (Telephony) + 0x15, + 0x00, // Logical Minimum (0) + 0x25, + 0x01, // Logical Maximum (1) + 0x09, + 0x20, // Usage (Hook Switch) + 0x09, + 0x2f, // Usage (Phone Mute) + 0x75, + 0x01, // Report Size (1) + 0x95, + 0x02, // Report Count (2) + 0x81, + 0x23, // Input + 0x75, + 0x01, // Report Size (1) + 0x95, + 0x06, // Report Count (6) + 0x81, + 0x01, // Input + 0x05, + 0x08, // Usage Page (LEDs) + 0x15, + 0x00, // Logical Minimum (0) + 0x25, + 0x01, // Logical Maximum (1) + 0x09, + 0x18, // Usage (Ring) + 0x09, + 0x17, // Usage (Off-Hook) + 0x09, + 0x09, // Usage (Mute) + 0x75, + 0x01, // Report Size (1) + 0x95, + 0x03, // Report Count (3) + 0x91, + 0x22, // Output + 0x75, + 0x01, // Report Size (1) + 0x95, + 0x05, // Report Count (5) + 0x91, + 0x01, // Output + 0xC0, // End Collection +]; + +pub struct UHidHfp { + handle: File, +} + +impl UHidHfp { + pub fn create( + adapter_addr: String, + remote_addr: String, + remote_name: String, + output_callback: F, + ) -> UHidHfp + where + F: Fn(OutputEvent) + std::marker::Send + 'static, + { + let rd_data = RDESC.to_vec(); + let create_params = CreateParams { + name: remote_name, + phys: adapter_addr, + uniq: remote_addr.clone(), + bus: Bus::BLUETOOTH, + vendor: 0, + product: 0, + version: 0, + country: 0, + rd_data, + }; + + let create_event: [u8; UHID_EVENT_SIZE] = InputEvent::Create(create_params).into(); + let mut options = OpenOptions::new(); + options.read(true); + options.write(true); + if cfg!(unix) { + options.custom_flags(libc::O_RDWR | libc::O_CLOEXEC); + } + let mut uhid_writer = options.open(Path::new("/dev/uhid")).unwrap(); + let mut uhid_reader = uhid_writer.try_clone().unwrap(); + uhid_writer.write_all(&create_event).unwrap(); + + topstack::get_runtime().spawn_blocking(move || { + let mut event = [0u8; UHID_EVENT_SIZE]; + debug!("UHID: reading loop start"); + loop { + match uhid_reader.read_exact(&mut event) { + Err(e) => { + log::error!("UHID: Read error: {:?}", e); + break; + } + Ok(_) => (), + } + match OutputEvent::try_from(event) { + Ok(m) => { + match m { + OutputEvent::Stop => break, + _ => (), + }; + + output_callback(m); + } + Err(e) => { + match e { + StreamError::Io(e) => log::error!("UHID: IO error: {}", e), + StreamError::UnknownEventType(e) => { + log::error!("UHID: Unknown event type: {}", e) + } + } + break; + } + } + } + debug!("UHID: reading loop completed"); + }); + + UHidHfp { handle: uhid_writer } + } + + pub fn destroy(&mut self) -> io::Result<()> { + let destroy_event: [u8; UHID_EVENT_SIZE] = InputEvent::Destroy.into(); + self.handle.write_all(&destroy_event) + } + + pub fn send_input(&mut self, report: u8) -> io::Result<()> { + let data: [u8; 2] = [BLUETOOTH_TELEPHONY_UHID_REPORT_ID, report]; + let input_event: [u8; UHID_EVENT_SIZE] = InputEvent::Input { data: &data }.into(); + self.handle.write_all(&input_event) + } +} diff --git a/system/gd/rust/packets/Cargo.toml b/system/gd/rust/packets/Cargo.toml index 0e364c40a811b2b9f9a20b7adf1eb7bfd2a6c0ad..efff02c87f5fce3b206cf241ae9210696f0e8d86 100644 --- a/system/gd/rust/packets/Cargo.toml +++ b/system/gd/rust/packets/Cargo.toml @@ -20,14 +20,17 @@ edition = "2018" build = "build.rs" [dependencies] - bindgen = "0.64" bytes = "1.0" num-derive = "0.3" num-traits = "0.2" +pdl-runtime = "0.2.2" thiserror = "1.0" walkdir = "2.2" +[build-dependencies] +pdl-compiler = "0.2.2" + [lib] path = "lib.rs" crate-types = ["rlib"] diff --git a/system/gd/rust/packets/build.rs b/system/gd/rust/packets/build.rs index 030fd67fa3c6e5a6209cd255cecbe33baaa0c0e0..d9d41a62cc1e58affd4e7281b49ed0e8ef9a52eb 100644 --- a/system/gd/rust/packets/build.rs +++ b/system/gd/rust/packets/build.rs @@ -13,76 +13,50 @@ // See the License for the specific language governing permissions and // limitations under the License. +use pdl_compiler; use std::env; +use std::fs::File; +use std::io::Write; use std::path::{Path, PathBuf}; -use std::process::Command; fn main() { + let pdl_root = match env::var("PLATFORM_SUBDIR") { + Ok(dir) => PathBuf::from(dir).join("bt/pdl"), + // Currently at //platform2/gd/rust/rust/packets + Err(_) => { + PathBuf::from(env::current_dir().unwrap()).join("../../../pdl").canonicalize().unwrap() + } + }; + + let in_file = pdl_root.join("hci/hci_packets.pdl"); + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let out_file = out_dir.join("hci_packets.rs"); + let packets_prebuilt = match env::var("HCI_PACKETS_PREBUILT") { Ok(dir) => PathBuf::from(dir), Err(_) => PathBuf::from("hci_packets.rs"), }; + if Path::new(packets_prebuilt.as_os_str()).exists() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let outputted = out_dir.join("../../hci/hci_packets.rs"); std::fs::copy( packets_prebuilt.as_os_str().to_str().unwrap(), - out_dir.join(outputted.file_name().unwrap()).as_os_str().to_str().unwrap(), + out_file.as_os_str().to_str().unwrap(), ) .unwrap(); } else { - generate_packets(); - } -} - -fn generate_packets() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - - let gd_root = match env::var("PLATFORM_SUBDIR") { - Ok(dir) => PathBuf::from(dir).join("bt/gd"), - // Currently at //platform2/gd/rust/rust/packets - Err(_) => PathBuf::from(env::current_dir().unwrap()).join("../..").canonicalize().unwrap(), - }; - - let input_files = [gd_root.join("hci/hci_packets.pdl")]; - let outputted = [out_dir.join("../../hci/hci_packets.rs")]; - - // Find the packetgen tool. Expecting it at CARGO_HOME/bin - let packetgen = match env::var("CARGO_HOME") { - Ok(dir) => PathBuf::from(dir).join("bin").join("bluetooth_packetgen"), - Err(_) => PathBuf::from("bluetooth_packetgen"), - }; - - if !Path::new(packetgen.as_os_str()).exists() { - panic!( - "Unable to locate bluetooth packet generator:{:?}", - packetgen.as_os_str().to_str().unwrap() - ); - } - - for i in 0..input_files.len() { - println!("cargo:rerun-if-changed={}", input_files[i].display()); - let output = Command::new(packetgen.as_os_str().to_str().unwrap()) - .arg("--source_root=".to_owned() + gd_root.as_os_str().to_str().unwrap()) - .arg("--out=".to_owned() + out_dir.as_os_str().to_str().unwrap()) - .arg("--include=bt/gd") - .arg("--rust") - .arg(input_files[i].as_os_str().to_str().unwrap()) - .output() - .unwrap(); + let mut sources = pdl_compiler::ast::SourceDatabase::new(); + let file = pdl_compiler::parser::parse_file( + &mut sources, + &in_file.into_os_string().into_string().unwrap(), + ) + .expect("failed to parse input pdl file"); + let file = + pdl_compiler::analyzer::analyze(&file).expect("failed to validate input pdl file"); + let generated = pdl_compiler::backends::rust::generate(&sources, &file); - println!( - "Status: {}, stdout: {}, stderr: {}", - output.status, - String::from_utf8_lossy(output.stdout.as_slice()), - String::from_utf8_lossy(output.stderr.as_slice()) - ); + let mut f = File::create(out_file).unwrap(); + f.write_all(generated.as_bytes()).unwrap(); - // File will be at ${OUT_DIR}/../../${input_files[i].strip('.pdl')}.rs - std::fs::rename( - outputted[i].as_os_str().to_str().unwrap(), - out_dir.join(outputted[i].file_name().unwrap()).as_os_str().to_str().unwrap(), - ) - .unwrap(); + println!("cargo:rerun-if-changed=build.rs"); } } diff --git a/system/gd/rust/packets/lib.rs b/system/gd/rust/packets/lib.rs index f43f69fbb91a780b08f10e1ae45699346d559549..9344aaf320d78a9a5291ee2eda60a5b737ca3f34 100644 --- a/system/gd/rust/packets/lib.rs +++ b/system/gd/rust/packets/lib.rs @@ -4,10 +4,623 @@ #![allow(unused)] #![allow(missing_docs)] -pub mod custom_types; - pub mod hci { - use crate::custom_types::*; - include!(concat!(env!("OUT_DIR"), "/hci_packets.rs")); + + pub const EMPTY_ADDRESS: Address = Address(0x000000000000); + pub const ANY_ADDRESS: Address = Address(0xffffffffffff); + + impl fmt::Display for Address { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let bytes = u64::to_le_bytes(self.0); + write!( + f, + "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0], + ) + } + } + + impl From<&[u8; 6]> for Address { + fn from(bytes: &[u8; 6]) -> Self { + Self(u64::from_le_bytes([ + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], 0, 0, + ])) + } + } + + impl From
    for [u8; 6] { + fn from(Address(addr): Address) -> Self { + let bytes = u64::to_le_bytes(addr); + bytes[0..6].try_into().unwrap() + } + } + + impl Address { + pub fn is_empty(&self) -> bool { + *self == EMPTY_ADDRESS + } + } + + impl fmt::Display for ClassOfDevice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{:03X}-{:01X}-{:02X}", + (self.0 >> 12) & 0xfff, + (self.0 >> 8) & 0xf, + self.0 & 0xff, + ) + } + } + + pub trait CommandExpectations { + type ResponseType; + fn _to_response_type(pkt: Event) -> Self::ResponseType; + } + + macro_rules! impl_command_expectations ( + ($cmd:ident, $evt:ident) => { + impl CommandExpectations for $cmd { + type ResponseType = $evt; + fn _to_response_type(pkt: Event) -> Self::ResponseType { + $evt::new(pkt.event.clone()).unwrap() + } + } + } + ); + + impl_command_expectations!(ResetBuilder, ResetComplete); + impl_command_expectations!(SetEventMaskBuilder, SetEventMaskComplete); + impl_command_expectations!(LeSetEventMaskBuilder, LeSetEventMaskComplete); + impl_command_expectations!(WriteSimplePairingModeBuilder, WriteSimplePairingModeComplete); + impl_command_expectations!(WriteLeHostSupportBuilder, WriteLeHostSupportComplete); + impl_command_expectations!(WriteLocalNameBuilder, WriteLocalNameComplete); + impl_command_expectations!(WriteLocalName, WriteLocalNameComplete); + impl_command_expectations!(ReadLocalNameBuilder, ReadLocalNameComplete); + impl_command_expectations!( + ReadLocalVersionInformationBuilder, + ReadLocalVersionInformationComplete + ); + impl_command_expectations!( + ReadLocalSupportedCommandsBuilder, + ReadLocalSupportedCommandsComplete + ); + impl_command_expectations!(ReadBufferSizeBuilder, ReadBufferSizeComplete); + impl_command_expectations!(LeReadBufferSizeV2Builder, LeReadBufferSizeV2Complete); + impl_command_expectations!(LeReadBufferSizeV1Builder, LeReadBufferSizeV1Complete); + impl_command_expectations!( + ReadLocalSupportedFeaturesBuilder, + ReadLocalSupportedFeaturesComplete + ); + impl_command_expectations!( + LeReadLocalSupportedFeaturesBuilder, + LeReadLocalSupportedFeaturesComplete + ); + impl_command_expectations!(LeReadSupportedStatesBuilder, LeReadSupportedStatesComplete); + impl_command_expectations!( + LeReadFilterAcceptListSizeBuilder, + LeReadFilterAcceptListSizeComplete + ); + impl_command_expectations!(LeReadResolvingListSizeBuilder, LeReadResolvingListSizeComplete); + impl_command_expectations!(LeReadMaximumDataLengthBuilder, LeReadMaximumDataLengthComplete); + impl_command_expectations!( + LeReadSuggestedDefaultDataLengthBuilder, + LeReadSuggestedDefaultDataLengthComplete + ); + impl_command_expectations!( + LeReadMaximumAdvertisingDataLengthBuilder, + LeReadMaximumAdvertisingDataLengthComplete + ); + impl_command_expectations!( + LeReadNumberOfSupportedAdvertisingSetsBuilder, + LeReadNumberOfSupportedAdvertisingSetsComplete + ); + impl_command_expectations!( + LeReadPeriodicAdvertiserListSizeBuilder, + LeReadPeriodicAdvertiserListSizeComplete + ); + impl_command_expectations!(LeSetHostFeatureBuilder, LeSetHostFeatureComplete); + impl_command_expectations!(ReadBdAddrBuilder, ReadBdAddrComplete); + impl_command_expectations!(ReadLocalExtendedFeaturesBuilder, ReadLocalExtendedFeaturesComplete); + impl_command_expectations!(CreateConnectionBuilder, CreateConnectionStatus); + impl_command_expectations!(CreateConnectionCancelBuilder, CreateConnectionCancelComplete); + impl_command_expectations!(DisconnectBuilder, DisconnectStatus); + impl_command_expectations!(RejectConnectionRequestBuilder, RejectConnectionRequestStatus); + impl_command_expectations!(AcceptConnectionRequestBuilder, AcceptConnectionRequestStatus); + + impl TryFrom for OpCodeIndex { + type Error = &'static str; + fn try_from(value: OpCode) -> std::result::Result { + match value { + OpCode::Inquiry => Ok(OpCodeIndex::Inquiry), + OpCode::InquiryCancel => Ok(OpCodeIndex::InquiryCancel), + OpCode::PeriodicInquiryMode => Ok(OpCodeIndex::PeriodicInquiryMode), + OpCode::ExitPeriodicInquiryMode => Ok(OpCodeIndex::ExitPeriodicInquiryMode), + OpCode::CreateConnection => Ok(OpCodeIndex::CreateConnection), + OpCode::Disconnect => Ok(OpCodeIndex::Disconnect), + OpCode::AddScoConnection => Ok(OpCodeIndex::AddScoConnection), + OpCode::CreateConnectionCancel => Ok(OpCodeIndex::CreateConnectionCancel), + OpCode::AcceptConnectionRequest => Ok(OpCodeIndex::AcceptConnectionRequest), + OpCode::RejectConnectionRequest => Ok(OpCodeIndex::RejectConnectionRequest), + OpCode::LinkKeyRequestReply => Ok(OpCodeIndex::LinkKeyRequestReply), + OpCode::LinkKeyRequestNegativeReply => Ok(OpCodeIndex::LinkKeyRequestNegativeReply), + OpCode::PinCodeRequestReply => Ok(OpCodeIndex::PinCodeRequestReply), + OpCode::PinCodeRequestNegativeReply => Ok(OpCodeIndex::PinCodeRequestNegativeReply), + OpCode::ChangeConnectionPacketType => Ok(OpCodeIndex::ChangeConnectionPacketType), + OpCode::AuthenticationRequested => Ok(OpCodeIndex::AuthenticationRequested), + OpCode::SetConnectionEncryption => Ok(OpCodeIndex::SetConnectionEncryption), + OpCode::ChangeConnectionLinkKey => Ok(OpCodeIndex::ChangeConnectionLinkKey), + OpCode::CentralLinkKey => Ok(OpCodeIndex::CentralLinkKey), + OpCode::RemoteNameRequest => Ok(OpCodeIndex::RemoteNameRequest), + OpCode::RemoteNameRequestCancel => Ok(OpCodeIndex::RemoteNameRequestCancel), + OpCode::ReadRemoteSupportedFeatures => Ok(OpCodeIndex::ReadRemoteSupportedFeatures), + OpCode::ReadRemoteExtendedFeatures => Ok(OpCodeIndex::ReadRemoteExtendedFeatures), + OpCode::ReadRemoteVersionInformation => { + Ok(OpCodeIndex::ReadRemoteVersionInformation) + } + OpCode::ReadClockOffset => Ok(OpCodeIndex::ReadClockOffset), + OpCode::ReadLmpHandle => Ok(OpCodeIndex::ReadLmpHandle), + OpCode::HoldMode => Ok(OpCodeIndex::HoldMode), + OpCode::SniffMode => Ok(OpCodeIndex::SniffMode), + OpCode::ExitSniffMode => Ok(OpCodeIndex::ExitSniffMode), + OpCode::QosSetup => Ok(OpCodeIndex::QosSetup), + OpCode::RoleDiscovery => Ok(OpCodeIndex::RoleDiscovery), + OpCode::SwitchRole => Ok(OpCodeIndex::SwitchRole), + OpCode::ReadLinkPolicySettings => Ok(OpCodeIndex::ReadLinkPolicySettings), + OpCode::WriteLinkPolicySettings => Ok(OpCodeIndex::WriteLinkPolicySettings), + OpCode::ReadDefaultLinkPolicySettings => { + Ok(OpCodeIndex::ReadDefaultLinkPolicySettings) + } + OpCode::WriteDefaultLinkPolicySettings => { + Ok(OpCodeIndex::WriteDefaultLinkPolicySettings) + } + OpCode::FlowSpecification => Ok(OpCodeIndex::FlowSpecification), + OpCode::SetEventMask => Ok(OpCodeIndex::SetEventMask), + OpCode::Reset => Ok(OpCodeIndex::Reset), + OpCode::SetEventFilter => Ok(OpCodeIndex::SetEventFilter), + OpCode::Flush => Ok(OpCodeIndex::Flush), + OpCode::ReadPinType => Ok(OpCodeIndex::ReadPinType), + OpCode::WritePinType => Ok(OpCodeIndex::WritePinType), + OpCode::ReadStoredLinkKey => Ok(OpCodeIndex::ReadStoredLinkKey), + OpCode::WriteStoredLinkKey => Ok(OpCodeIndex::WriteStoredLinkKey), + OpCode::DeleteStoredLinkKey => Ok(OpCodeIndex::DeleteStoredLinkKey), + OpCode::WriteLocalName => Ok(OpCodeIndex::WriteLocalName), + OpCode::ReadLocalName => Ok(OpCodeIndex::ReadLocalName), + OpCode::ReadConnectionAcceptTimeout => Ok(OpCodeIndex::ReadConnectionAcceptTimeout), + OpCode::WriteConnectionAcceptTimeout => { + Ok(OpCodeIndex::WriteConnectionAcceptTimeout) + } + OpCode::ReadPageTimeout => Ok(OpCodeIndex::ReadPageTimeout), + OpCode::WritePageTimeout => Ok(OpCodeIndex::WritePageTimeout), + OpCode::ReadScanEnable => Ok(OpCodeIndex::ReadScanEnable), + OpCode::WriteScanEnable => Ok(OpCodeIndex::WriteScanEnable), + OpCode::ReadPageScanActivity => Ok(OpCodeIndex::ReadPageScanActivity), + OpCode::WritePageScanActivity => Ok(OpCodeIndex::WritePageScanActivity), + OpCode::ReadInquiryScanActivity => Ok(OpCodeIndex::ReadInquiryScanActivity), + OpCode::WriteInquiryScanActivity => Ok(OpCodeIndex::WriteInquiryScanActivity), + OpCode::ReadAuthenticationEnable => Ok(OpCodeIndex::ReadAuthenticationEnable), + OpCode::WriteAuthenticationEnable => Ok(OpCodeIndex::WriteAuthenticationEnable), + OpCode::ReadClassOfDevice => Ok(OpCodeIndex::ReadClassOfDevice), + OpCode::WriteClassOfDevice => Ok(OpCodeIndex::WriteClassOfDevice), + OpCode::ReadVoiceSetting => Ok(OpCodeIndex::ReadVoiceSetting), + OpCode::WriteVoiceSetting => Ok(OpCodeIndex::WriteVoiceSetting), + OpCode::ReadAutomaticFlushTimeout => Ok(OpCodeIndex::ReadAutomaticFlushTimeout), + OpCode::WriteAutomaticFlushTimeout => Ok(OpCodeIndex::WriteAutomaticFlushTimeout), + OpCode::ReadNumBroadcastRetransmits => Ok(OpCodeIndex::ReadNumBroadcastRetransmits), + OpCode::WriteNumBroadcastRetransmits => { + Ok(OpCodeIndex::WriteNumBroadcastRetransmits) + } + OpCode::ReadHoldModeActivity => Ok(OpCodeIndex::ReadHoldModeActivity), + OpCode::WriteHoldModeActivity => Ok(OpCodeIndex::WriteHoldModeActivity), + OpCode::ReadTransmitPowerLevel => Ok(OpCodeIndex::ReadTransmitPowerLevel), + OpCode::ReadSynchronousFlowControlEnable => { + Ok(OpCodeIndex::ReadSynchronousFlowControlEnable) + } + OpCode::WriteSynchronousFlowControlEnable => { + Ok(OpCodeIndex::WriteSynchronousFlowControlEnable) + } + OpCode::SetControllerToHostFlowControl => { + Ok(OpCodeIndex::SetControllerToHostFlowControl) + } + OpCode::HostBufferSize => Ok(OpCodeIndex::HostBufferSize), + OpCode::HostNumberOfCompletedPackets => { + Ok(OpCodeIndex::HostNumberOfCompletedPackets) + } + OpCode::ReadLinkSupervisionTimeout => Ok(OpCodeIndex::ReadLinkSupervisionTimeout), + OpCode::WriteLinkSupervisionTimeout => Ok(OpCodeIndex::WriteLinkSupervisionTimeout), + OpCode::ReadNumberOfSupportedIac => Ok(OpCodeIndex::ReadNumberOfSupportedIac), + OpCode::ReadCurrentIacLap => Ok(OpCodeIndex::ReadCurrentIacLap), + OpCode::WriteCurrentIacLap => Ok(OpCodeIndex::WriteCurrentIacLap), + OpCode::SetAfhHostChannelClassification => { + Ok(OpCodeIndex::SetAfhHostChannelClassification) + } + OpCode::ReadInquiryScanType => Ok(OpCodeIndex::ReadInquiryScanType), + OpCode::WriteInquiryScanType => Ok(OpCodeIndex::WriteInquiryScanType), + OpCode::ReadInquiryMode => Ok(OpCodeIndex::ReadInquiryMode), + OpCode::WriteInquiryMode => Ok(OpCodeIndex::WriteInquiryMode), + OpCode::ReadPageScanType => Ok(OpCodeIndex::ReadPageScanType), + OpCode::WritePageScanType => Ok(OpCodeIndex::WritePageScanType), + OpCode::ReadAfhChannelAssessmentMode => { + Ok(OpCodeIndex::ReadAfhChannelAssessmentMode) + } + OpCode::WriteAfhChannelAssessmentMode => { + Ok(OpCodeIndex::WriteAfhChannelAssessmentMode) + } + OpCode::ReadLocalVersionInformation => Ok(OpCodeIndex::ReadLocalVersionInformation), + OpCode::ReadLocalSupportedFeatures => Ok(OpCodeIndex::ReadLocalSupportedFeatures), + OpCode::ReadLocalExtendedFeatures => Ok(OpCodeIndex::ReadLocalExtendedFeatures), + OpCode::ReadBufferSize => Ok(OpCodeIndex::ReadBufferSize), + OpCode::ReadBdAddr => Ok(OpCodeIndex::ReadBdAddr), + OpCode::ReadFailedContactCounter => Ok(OpCodeIndex::ReadFailedContactCounter), + OpCode::ResetFailedContactCounter => Ok(OpCodeIndex::ResetFailedContactCounter), + OpCode::ReadLinkQuality => Ok(OpCodeIndex::ReadLinkQuality), + OpCode::ReadRssi => Ok(OpCodeIndex::ReadRssi), + OpCode::ReadAfhChannelMap => Ok(OpCodeIndex::ReadAfhChannelMap), + OpCode::ReadClock => Ok(OpCodeIndex::ReadClock), + OpCode::ReadLoopbackMode => Ok(OpCodeIndex::ReadLoopbackMode), + OpCode::WriteLoopbackMode => Ok(OpCodeIndex::WriteLoopbackMode), + OpCode::EnableDeviceUnderTestMode => Ok(OpCodeIndex::EnableDeviceUnderTestMode), + OpCode::SetupSynchronousConnection => Ok(OpCodeIndex::SetupSynchronousConnection), + OpCode::AcceptSynchronousConnection => Ok(OpCodeIndex::AcceptSynchronousConnection), + OpCode::RejectSynchronousConnection => Ok(OpCodeIndex::RejectSynchronousConnection), + OpCode::ReadExtendedInquiryResponse => Ok(OpCodeIndex::ReadExtendedInquiryResponse), + OpCode::WriteExtendedInquiryResponse => { + Ok(OpCodeIndex::WriteExtendedInquiryResponse) + } + OpCode::RefreshEncryptionKey => Ok(OpCodeIndex::RefreshEncryptionKey), + OpCode::SniffSubrating => Ok(OpCodeIndex::SniffSubrating), + OpCode::ReadSimplePairingMode => Ok(OpCodeIndex::ReadSimplePairingMode), + OpCode::WriteSimplePairingMode => Ok(OpCodeIndex::WriteSimplePairingMode), + OpCode::ReadLocalOobData => Ok(OpCodeIndex::ReadLocalOobData), + OpCode::ReadInquiryResponseTransmitPowerLevel => { + Ok(OpCodeIndex::ReadInquiryResponseTransmitPowerLevel) + } + OpCode::WriteInquiryTransmitPowerLevel => { + Ok(OpCodeIndex::WriteInquiryTransmitPowerLevel) + } + OpCode::ReadDefaultErroneousDataReporting => { + Ok(OpCodeIndex::ReadDefaultErroneousDataReporting) + } + OpCode::WriteDefaultErroneousDataReporting => { + Ok(OpCodeIndex::WriteDefaultErroneousDataReporting) + } + OpCode::IoCapabilityRequestReply => Ok(OpCodeIndex::IoCapabilityRequestReply), + OpCode::UserConfirmationRequestReply => { + Ok(OpCodeIndex::UserConfirmationRequestReply) + } + OpCode::UserConfirmationRequestNegativeReply => { + Ok(OpCodeIndex::UserConfirmationRequestNegativeReply) + } + OpCode::UserPasskeyRequestReply => Ok(OpCodeIndex::UserPasskeyRequestReply), + OpCode::UserPasskeyRequestNegativeReply => { + Ok(OpCodeIndex::UserPasskeyRequestNegativeReply) + } + OpCode::RemoteOobDataRequestReply => Ok(OpCodeIndex::RemoteOobDataRequestReply), + OpCode::WriteSimplePairingDebugMode => Ok(OpCodeIndex::WriteSimplePairingDebugMode), + OpCode::EnhancedFlush => Ok(OpCodeIndex::EnhancedFlush), + OpCode::RemoteOobDataRequestNegativeReply => { + Ok(OpCodeIndex::RemoteOobDataRequestNegativeReply) + } + OpCode::SendKeypressNotification => Ok(OpCodeIndex::SendKeypressNotification), + OpCode::IoCapabilityRequestNegativeReply => { + Ok(OpCodeIndex::IoCapabilityRequestNegativeReply) + } + OpCode::ReadEncryptionKeySize => Ok(OpCodeIndex::ReadEncryptionKeySize), + OpCode::SetEventMaskPage2 => Ok(OpCodeIndex::SetEventMaskPage2), + OpCode::ReadFlowControlMode => Ok(OpCodeIndex::ReadFlowControlMode), + OpCode::WriteFlowControlMode => Ok(OpCodeIndex::WriteFlowControlMode), + OpCode::ReadDataBlockSize => Ok(OpCodeIndex::ReadDataBlockSize), + OpCode::ReadEnhancedTransmitPowerLevel => { + Ok(OpCodeIndex::ReadEnhancedTransmitPowerLevel) + } + OpCode::ReadLeHostSupport => Ok(OpCodeIndex::ReadLeHostSupport), + OpCode::WriteLeHostSupport => Ok(OpCodeIndex::WriteLeHostSupport), + OpCode::LeSetEventMask => Ok(OpCodeIndex::LeSetEventMask), + OpCode::LeReadBufferSizeV1 => Ok(OpCodeIndex::LeReadBufferSizeV1), + OpCode::LeReadLocalSupportedFeatures => { + Ok(OpCodeIndex::LeReadLocalSupportedFeatures) + } + OpCode::LeSetRandomAddress => Ok(OpCodeIndex::LeSetRandomAddress), + OpCode::LeSetAdvertisingParameters => Ok(OpCodeIndex::LeSetAdvertisingParameters), + OpCode::LeReadAdvertisingPhysicalChannelTxPower => { + Ok(OpCodeIndex::LeReadAdvertisingPhysicalChannelTxPower) + } + OpCode::LeSetAdvertisingData => Ok(OpCodeIndex::LeSetAdvertisingData), + OpCode::LeSetScanResponseData => Ok(OpCodeIndex::LeSetScanResponseData), + OpCode::LeSetAdvertisingEnable => Ok(OpCodeIndex::LeSetAdvertisingEnable), + OpCode::LeSetScanParameters => Ok(OpCodeIndex::LeSetScanParameters), + OpCode::LeSetScanEnable => Ok(OpCodeIndex::LeSetScanEnable), + OpCode::LeCreateConnection => Ok(OpCodeIndex::LeCreateConnection), + OpCode::LeCreateConnectionCancel => Ok(OpCodeIndex::LeCreateConnectionCancel), + OpCode::LeReadFilterAcceptListSize => Ok(OpCodeIndex::LeReadFilterAcceptListSize), + OpCode::LeClearFilterAcceptList => Ok(OpCodeIndex::LeClearFilterAcceptList), + OpCode::LeAddDeviceToFilterAcceptList => { + Ok(OpCodeIndex::LeAddDeviceToFilterAcceptList) + } + OpCode::LeRemoveDeviceFromFilterAcceptList => { + Ok(OpCodeIndex::LeRemoveDeviceFromFilterAcceptList) + } + OpCode::LeConnectionUpdate => Ok(OpCodeIndex::LeConnectionUpdate), + OpCode::LeSetHostChannelClassification => { + Ok(OpCodeIndex::LeSetHostChannelClassification) + } + OpCode::LeReadChannelMap => Ok(OpCodeIndex::LeReadChannelMap), + OpCode::LeReadRemoteFeatures => Ok(OpCodeIndex::LeReadRemoteFeatures), + OpCode::LeEncrypt => Ok(OpCodeIndex::LeEncrypt), + OpCode::LeRand => Ok(OpCodeIndex::LeRand), + OpCode::LeStartEncryption => Ok(OpCodeIndex::LeStartEncryption), + OpCode::LeLongTermKeyRequestReply => Ok(OpCodeIndex::LeLongTermKeyRequestReply), + OpCode::LeLongTermKeyRequestNegativeReply => { + Ok(OpCodeIndex::LeLongTermKeyRequestNegativeReply) + } + OpCode::LeReadSupportedStates => Ok(OpCodeIndex::LeReadSupportedStates), + OpCode::LeReceiverTestV1 => Ok(OpCodeIndex::LeReceiverTestV1), + OpCode::LeTransmitterTestV1 => Ok(OpCodeIndex::LeTransmitterTestV1), + OpCode::LeTestEnd => Ok(OpCodeIndex::LeTestEnd), + OpCode::EnhancedSetupSynchronousConnection => { + Ok(OpCodeIndex::EnhancedSetupSynchronousConnection) + } + OpCode::EnhancedAcceptSynchronousConnection => { + Ok(OpCodeIndex::EnhancedAcceptSynchronousConnection) + } + OpCode::ReadLocalSupportedCodecsV1 => Ok(OpCodeIndex::ReadLocalSupportedCodecsV1), + OpCode::SetMwsChannelParameters => Ok(OpCodeIndex::SetMwsChannelParameters), + OpCode::SetExternalFrameConfiguration => { + Ok(OpCodeIndex::SetExternalFrameConfiguration) + } + OpCode::SetMwsSignaling => Ok(OpCodeIndex::SetMwsSignaling), + OpCode::SetMwsTransportLayer => Ok(OpCodeIndex::SetMwsTransportLayer), + OpCode::SetMwsScanFrequencyTable => Ok(OpCodeIndex::SetMwsScanFrequencyTable), + OpCode::GetMwsTransportLayerConfiguration => { + Ok(OpCodeIndex::GetMwsTransportLayerConfiguration) + } + OpCode::SetMwsPatternConfiguration => Ok(OpCodeIndex::SetMwsPatternConfiguration), + OpCode::SetTriggeredClockCapture => Ok(OpCodeIndex::SetTriggeredClockCapture), + OpCode::TruncatedPage => Ok(OpCodeIndex::TruncatedPage), + OpCode::TruncatedPageCancel => Ok(OpCodeIndex::TruncatedPageCancel), + OpCode::SetConnectionlessPeripheralBroadcast => { + Ok(OpCodeIndex::SetConnectionlessPeripheralBroadcast) + } + OpCode::SetConnectionlessPeripheralBroadcastReceive => { + Ok(OpCodeIndex::SetConnectionlessPeripheralBroadcastReceive) + } + OpCode::StartSynchronizationTrain => Ok(OpCodeIndex::StartSynchronizationTrain), + OpCode::ReceiveSynchronizationTrain => Ok(OpCodeIndex::ReceiveSynchronizationTrain), + OpCode::SetReservedLtAddr => Ok(OpCodeIndex::SetReservedLtAddr), + OpCode::DeleteReservedLtAddr => Ok(OpCodeIndex::DeleteReservedLtAddr), + OpCode::SetConnectionlessPeripheralBroadcastData => { + Ok(OpCodeIndex::SetConnectionlessPeripheralBroadcastData) + } + OpCode::ReadSynchronizationTrainParameters => { + Ok(OpCodeIndex::ReadSynchronizationTrainParameters) + } + OpCode::WriteSynchronizationTrainParameters => { + Ok(OpCodeIndex::WriteSynchronizationTrainParameters) + } + OpCode::RemoteOobExtendedDataRequestReply => { + Ok(OpCodeIndex::RemoteOobExtendedDataRequestReply) + } + OpCode::ReadSecureConnectionsHostSupport => { + Ok(OpCodeIndex::ReadSecureConnectionsHostSupport) + } + OpCode::WriteSecureConnectionsHostSupport => { + Ok(OpCodeIndex::WriteSecureConnectionsHostSupport) + } + OpCode::ReadAuthenticatedPayloadTimeout => { + Ok(OpCodeIndex::ReadAuthenticatedPayloadTimeout) + } + OpCode::WriteAuthenticatedPayloadTimeout => { + Ok(OpCodeIndex::WriteAuthenticatedPayloadTimeout) + } + OpCode::ReadLocalOobExtendedData => Ok(OpCodeIndex::ReadLocalOobExtendedData), + OpCode::WriteSecureConnectionsTestMode => { + Ok(OpCodeIndex::WriteSecureConnectionsTestMode) + } + OpCode::ReadExtendedPageTimeout => Ok(OpCodeIndex::ReadExtendedPageTimeout), + OpCode::WriteExtendedPageTimeout => Ok(OpCodeIndex::WriteExtendedPageTimeout), + OpCode::ReadExtendedInquiryLength => Ok(OpCodeIndex::ReadExtendedInquiryLength), + OpCode::WriteExtendedInquiryLength => Ok(OpCodeIndex::WriteExtendedInquiryLength), + OpCode::LeRemoteConnectionParameterRequestReply => { + Ok(OpCodeIndex::LeRemoteConnectionParameterRequestReply) + } + OpCode::LeRemoteConnectionParameterRequestNegativeReply => { + Ok(OpCodeIndex::LeRemoteConnectionParameterRequestNegativeReply) + } + OpCode::LeSetDataLength => Ok(OpCodeIndex::LeSetDataLength), + OpCode::LeReadSuggestedDefaultDataLength => { + Ok(OpCodeIndex::LeReadSuggestedDefaultDataLength) + } + OpCode::LeWriteSuggestedDefaultDataLength => { + Ok(OpCodeIndex::LeWriteSuggestedDefaultDataLength) + } + OpCode::LeReadLocalP256PublicKey => Ok(OpCodeIndex::LeReadLocalP256PublicKey), + OpCode::LeGenerateDhkeyV1 => Ok(OpCodeIndex::LeGenerateDhkeyV1), + OpCode::LeAddDeviceToResolvingList => Ok(OpCodeIndex::LeAddDeviceToResolvingList), + OpCode::LeRemoveDeviceFromResolvingList => { + Ok(OpCodeIndex::LeRemoveDeviceFromResolvingList) + } + OpCode::LeClearResolvingList => Ok(OpCodeIndex::LeClearResolvingList), + OpCode::LeReadResolvingListSize => Ok(OpCodeIndex::LeReadResolvingListSize), + OpCode::LeReadPeerResolvableAddress => Ok(OpCodeIndex::LeReadPeerResolvableAddress), + OpCode::LeReadLocalResolvableAddress => { + Ok(OpCodeIndex::LeReadLocalResolvableAddress) + } + OpCode::LeSetAddressResolutionEnable => { + Ok(OpCodeIndex::LeSetAddressResolutionEnable) + } + OpCode::LeSetResolvablePrivateAddressTimeout => { + Ok(OpCodeIndex::LeSetResolvablePrivateAddressTimeout) + } + OpCode::LeReadMaximumDataLength => Ok(OpCodeIndex::LeReadMaximumDataLength), + OpCode::LeReadPhy => Ok(OpCodeIndex::LeReadPhy), + OpCode::LeSetDefaultPhy => Ok(OpCodeIndex::LeSetDefaultPhy), + OpCode::LeSetPhy => Ok(OpCodeIndex::LeSetPhy), + OpCode::LeReceiverTestV2 => Ok(OpCodeIndex::LeReceiverTestV2), + OpCode::LeTransmitterTestV2 => Ok(OpCodeIndex::LeTransmitterTestV2), + OpCode::LeSetAdvertisingSetRandomAddress => { + Ok(OpCodeIndex::LeSetAdvertisingSetRandomAddress) + } + OpCode::LeSetExtendedAdvertisingParameters => { + Ok(OpCodeIndex::LeSetExtendedAdvertisingParameters) + } + OpCode::LeSetExtendedAdvertisingData => { + Ok(OpCodeIndex::LeSetExtendedAdvertisingData) + } + OpCode::LeSetExtendedScanResponseData => { + Ok(OpCodeIndex::LeSetExtendedScanResponseData) + } + OpCode::LeSetExtendedAdvertisingEnable => { + Ok(OpCodeIndex::LeSetExtendedAdvertisingEnable) + } + OpCode::LeReadMaximumAdvertisingDataLength => { + Ok(OpCodeIndex::LeReadMaximumAdvertisingDataLength) + } + OpCode::LeReadNumberOfSupportedAdvertisingSets => { + Ok(OpCodeIndex::LeReadNumberOfSupportedAdvertisingSets) + } + OpCode::LeRemoveAdvertisingSet => Ok(OpCodeIndex::LeRemoveAdvertisingSet), + OpCode::LeClearAdvertisingSets => Ok(OpCodeIndex::LeClearAdvertisingSets), + OpCode::LeSetPeriodicAdvertisingParameters => { + Ok(OpCodeIndex::LeSetPeriodicAdvertisingParameters) + } + OpCode::LeSetPeriodicAdvertisingData => { + Ok(OpCodeIndex::LeSetPeriodicAdvertisingData) + } + OpCode::LeSetPeriodicAdvertisingEnable => { + Ok(OpCodeIndex::LeSetPeriodicAdvertisingEnable) + } + OpCode::LeSetExtendedScanParameters => Ok(OpCodeIndex::LeSetExtendedScanParameters), + OpCode::LeSetExtendedScanEnable => Ok(OpCodeIndex::LeSetExtendedScanEnable), + OpCode::LeExtendedCreateConnection => Ok(OpCodeIndex::LeExtendedCreateConnection), + OpCode::LePeriodicAdvertisingCreateSync => { + Ok(OpCodeIndex::LePeriodicAdvertisingCreateSync) + } + OpCode::LePeriodicAdvertisingCreateSyncCancel => { + Ok(OpCodeIndex::LePeriodicAdvertisingCreateSyncCancel) + } + OpCode::LePeriodicAdvertisingTerminateSync => { + Ok(OpCodeIndex::LePeriodicAdvertisingTerminateSync) + } + OpCode::LeAddDeviceToPeriodicAdvertiserList => { + Ok(OpCodeIndex::LeAddDeviceToPeriodicAdvertiserList) + } + OpCode::LeRemoveDeviceFromPeriodicAdvertiserList => { + Ok(OpCodeIndex::LeRemoveDeviceFromPeriodicAdvertiserList) + } + OpCode::LeClearPeriodicAdvertiserList => { + Ok(OpCodeIndex::LeClearPeriodicAdvertiserList) + } + OpCode::LeReadPeriodicAdvertiserListSize => { + Ok(OpCodeIndex::LeReadPeriodicAdvertiserListSize) + } + OpCode::LeReadTransmitPower => Ok(OpCodeIndex::LeReadTransmitPower), + OpCode::LeReadRfPathCompensationPower => { + Ok(OpCodeIndex::LeReadRfPathCompensationPower) + } + OpCode::LeWriteRfPathCompensationPower => { + Ok(OpCodeIndex::LeWriteRfPathCompensationPower) + } + OpCode::LeSetPrivacyMode => Ok(OpCodeIndex::LeSetPrivacyMode), + OpCode::LeReceiverTestV3 => Ok(OpCodeIndex::LeReceiverTestV3), + OpCode::LeTransmitterTestV3 => Ok(OpCodeIndex::LeTransmitterTestV3), + OpCode::LeSetConnectionlessCteTransmitParameters => { + Ok(OpCodeIndex::LeSetConnectionlessCteTransmitParameters) + } + OpCode::LeSetConnectionlessCteTransmitEnable => { + Ok(OpCodeIndex::LeSetConnectionlessCteTransmitEnable) + } + OpCode::LeSetConnectionlessIqSamplingEnable => { + Ok(OpCodeIndex::LeSetConnectionlessIqSamplingEnable) + } + OpCode::LeSetConnectionCteReceiveParameters => { + Ok(OpCodeIndex::LeSetConnectionCteReceiveParameters) + } + OpCode::LeSetConnectionCteTransmitParameters => { + Ok(OpCodeIndex::LeSetConnectionCteTransmitParameters) + } + OpCode::LeConnectionCteRequestEnable => { + Ok(OpCodeIndex::LeConnectionCteRequestEnable) + } + OpCode::LeConnectionCteResponseEnable => { + Ok(OpCodeIndex::LeConnectionCteResponseEnable) + } + OpCode::LeReadAntennaInformation => Ok(OpCodeIndex::LeReadAntennaInformation), + OpCode::LeSetPeriodicAdvertisingReceiveEnable => { + Ok(OpCodeIndex::LeSetPeriodicAdvertisingReceiveEnable) + } + OpCode::LePeriodicAdvertisingSyncTransfer => { + Ok(OpCodeIndex::LePeriodicAdvertisingSyncTransfer) + } + OpCode::LePeriodicAdvertisingSetInfoTransfer => { + Ok(OpCodeIndex::LePeriodicAdvertisingSetInfoTransfer) + } + OpCode::LeSetPeriodicAdvertisingSyncTransferParameters => { + Ok(OpCodeIndex::LeSetPeriodicAdvertisingSyncTransferParameters) + } + OpCode::LeSetDefaultPeriodicAdvertisingSyncTransferParameters => { + Ok(OpCodeIndex::LeSetDefaultPeriodicAdvertisingSyncTransferParameters) + } + OpCode::LeGenerateDhkeyV2 => Ok(OpCodeIndex::LeGenerateDhkeyV2), + OpCode::ReadLocalSimplePairingOptions => { + Ok(OpCodeIndex::ReadLocalSimplePairingOptions) + } + OpCode::LeModifySleepClockAccuracy => Ok(OpCodeIndex::LeModifySleepClockAccuracy), + OpCode::LeReadBufferSizeV2 => Ok(OpCodeIndex::LeReadBufferSizeV2), + OpCode::LeReadIsoTxSync => Ok(OpCodeIndex::LeReadIsoTxSync), + OpCode::LeSetCigParameters => Ok(OpCodeIndex::LeSetCigParameters), + OpCode::LeSetCigParametersTest => Ok(OpCodeIndex::LeSetCigParametersTest), + OpCode::LeCreateCis => Ok(OpCodeIndex::LeCreateCis), + OpCode::LeRemoveCig => Ok(OpCodeIndex::LeRemoveCig), + OpCode::LeAcceptCisRequest => Ok(OpCodeIndex::LeAcceptCisRequest), + OpCode::LeRejectCisRequest => Ok(OpCodeIndex::LeRejectCisRequest), + OpCode::LeCreateBig => Ok(OpCodeIndex::LeCreateBig), + OpCode::LeCreateBigTest => Ok(OpCodeIndex::LeCreateBigTest), + OpCode::LeTerminateBig => Ok(OpCodeIndex::LeTerminateBig), + OpCode::LeBigCreateSync => Ok(OpCodeIndex::LeBigCreateSync), + OpCode::LeBigTerminateSync => Ok(OpCodeIndex::LeBigTerminateSync), + OpCode::LeRequestPeerSca => Ok(OpCodeIndex::LeRequestPeerSca), + OpCode::LeSetupIsoDataPath => Ok(OpCodeIndex::LeSetupIsoDataPath), + OpCode::LeRemoveIsoDataPath => Ok(OpCodeIndex::LeRemoveIsoDataPath), + OpCode::LeIsoTransmitTest => Ok(OpCodeIndex::LeIsoTransmitTest), + OpCode::LeIsoReceiveTest => Ok(OpCodeIndex::LeIsoReceiveTest), + OpCode::LeIsoReadTestCounters => Ok(OpCodeIndex::LeIsoReadTestCounters), + OpCode::LeIsoTestEnd => Ok(OpCodeIndex::LeIsoTestEnd), + OpCode::LeSetHostFeature => Ok(OpCodeIndex::LeSetHostFeature), + OpCode::LeReadIsoLinkQuality => Ok(OpCodeIndex::LeReadIsoLinkQuality), + OpCode::LeEnhancedReadTransmitPowerLevel => { + Ok(OpCodeIndex::LeEnhancedReadTransmitPowerLevel) + } + OpCode::LeReadRemoteTransmitPowerLevel => { + Ok(OpCodeIndex::LeReadRemoteTransmitPowerLevel) + } + OpCode::LeSetPathLossReportingParameters => { + Ok(OpCodeIndex::LeSetPathLossReportingParameters) + } + OpCode::LeSetPathLossReportingEnable => { + Ok(OpCodeIndex::LeSetPathLossReportingEnable) + } + OpCode::LeSetTransmitPowerReportingEnable => { + Ok(OpCodeIndex::LeSetTransmitPowerReportingEnable) + } + OpCode::LeTransmitterTestV4 => Ok(OpCodeIndex::LeTransmitterTestV4), + OpCode::SetEcosystemBaseInterval => Ok(OpCodeIndex::SetEcosystemBaseInterval), + OpCode::ReadLocalSupportedCodecsV2 => Ok(OpCodeIndex::ReadLocalSupportedCodecsV2), + OpCode::ReadLocalSupportedCodecCapabilities => { + Ok(OpCodeIndex::ReadLocalSupportedCodecCapabilities) + } + OpCode::ReadLocalSupportedControllerDelay => { + Ok(OpCodeIndex::ReadLocalSupportedControllerDelay) + } + OpCode::ConfigureDataPath => Ok(OpCodeIndex::ConfigureDataPath), + OpCode::LeSetDataRelatedAddressChanges => { + Ok(OpCodeIndex::LeSetDataRelatedAddressChanges) + } + OpCode::SetMinEncryptionKeySize => Ok(OpCodeIndex::SetMinEncryptionKeySize), + OpCode::LeSetDefaultSubrate => Ok(OpCodeIndex::LeSetDefaultSubrate), + OpCode::LeSubrateRequest => Ok(OpCodeIndex::LeSubrateRequest), + _ => Err("No mapping for provided key"), + } + } + } } diff --git a/system/gd/rust/packets/test_lib.rs b/system/gd/rust/packets/test_lib.rs deleted file mode 100644 index db6fbe606549214374318fa278544f7808c020df..0000000000000000000000000000000000000000 --- a/system/gd/rust/packets/test_lib.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! reimport of generated packets (to go away once rust_genrule exists) - -#![allow(clippy::all)] -#![allow(unused)] -#![allow(missing_docs)] - -use std::convert::TryFrom; -use std::fmt; - -pub mod test_packets { - - // Custom boolean type - #[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] - pub struct Boolean { - pub value: u8, - } - - impl fmt::Display for Boolean { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:02x}", self.value) - } - } - - #[derive(Debug, Clone)] - pub struct InvalidBooleanError; - - impl TryFrom<&[u8]> for Boolean { - type Error = InvalidBooleanError; - - fn try_from(slice: &[u8]) -> std::result::Result { - if slice.len() != 1 || slice[0] > 1 { - Err(InvalidBooleanError) - } else { - Ok(Boolean { value: slice[0] }) - } - } - } - - impl From for [u8; 1] { - fn from(b: Boolean) -> [u8; 1] { - [b.value] - } - } - - include!(concat!(env!("OUT_DIR"), "/rust_test_packets.rs")); -} - -#[cfg(test)] -pub mod test { - use crate::test_packets::*; - - #[test] - fn test_invalid_enum_field_value() { - // 0x0 is not a recognized Enum value. - let input = [0x0]; - let res = TestEnumPacket::parse(&input); - assert!(res.is_err()); - } - - #[test] - fn test_invalid_custom_field_value() { - // 0x2 is not a recognized Boolean value. - let input = [0x2]; - let res = TestCustomFieldPacket::parse(&input); - assert!(res.is_err()); - } - - #[test] - fn test_invalid_array_size() { - // Size 4, have 2. - let input = [0x4, 0x0, 0x0]; - let res = TestArraySizePacket::parse(&input); - assert!(res.is_err()); - } - - #[test] - fn test_invalid_array_count() { - // Count 2, have 1. - let input = [0x2, 0x0, 0x0]; - let res = TestArrayCountPacket::parse(&input); - assert!(res.is_err()); - } - - #[test] - fn test_invalid_payload_size() { - // Size 2, have 1. - let input = [0x2, 0x0]; - let res = TestPayloadSizePacket::parse(&input); - assert!(res.is_err()); - } - - #[test] - fn test_invalid_body_size() { - // Size 2, have 1. - // Body does not have a concrete representation, - // the size and payload are both discarded. - let input = [0x2, 0x0]; - let res = TestBodySizePacket::parse(&input); - assert!(res.is_ok()); - } - - #[test] - fn test_invalid_grand_child_three_five_size() { - let input = [0x1, 0x4, 0x3, 0x4, 0x3, 0x0, 0x2 /*, 0x5*/]; - let res = GrandParentPacket::parse(&input); - assert!(res.is_err()); - } -} diff --git a/system/gd/rust/shim/Android.bp b/system/gd/rust/shim/Android.bp index 85dd49d8213ecb77a1f8e0530d9c0c0e064e5a34..0a14a8f6222685c6a53732da279e06fa0a73936e 100644 --- a/system/gd/rust/shim/Android.bp +++ b/system/gd/rust/shim/Android.bp @@ -32,17 +32,8 @@ rust_defaults { crate_name: "bt_shim", srcs: ["src/lib.rs"], rustlibs: [ - "libbluetooth_rs", - "libbt_common", - "libbt_facade_helpers", - "libbt_packets", + "libbt_common_only_init_flags", "libcxx", - "libfutures", - "liblazy_static", - "liblog_rust", - "libnix", - "libnum_traits", - "libtokio", ], proc_macros: [ "libpaste", @@ -67,7 +58,6 @@ cc_library_static { name: "libbt_shim_bridge", defaults: [ "gd_ffi_defaults", - "libchrome_support_defaults", ], generated_headers: [ "cxx-bridge-header", @@ -97,7 +87,6 @@ cc_library_static { name: "libbluetooth_rust_interop", defaults: [ "gd_ffi_defaults", - "libchrome_support_defaults", ], static_libs: [ "libbt_shim_bridge", diff --git a/system/gd/rust/shim/Cargo.toml b/system/gd/rust/shim/Cargo.toml index acf88f1f546a8b4a5f27c04571d32f302b9bb02b..01d508907bc2ddbbf00e4748c880ae1b32d133ee 100644 --- a/system/gd/rust/shim/Cargo.toml +++ b/system/gd/rust/shim/Cargo.toml @@ -38,6 +38,7 @@ log = "0.4" nix = "0.23" num-derive = "0.3" num-traits = "0.2" +pdl-runtime = "0.2.2" paste = "1.0" proc-macro2 = "1.0.24" protobuf = "2.0" @@ -45,9 +46,7 @@ protoc-grpcio = "2.0" protoc-rust = "2.0" quote = "1.0.8" thiserror = "1.0" -syn = { version = "1.0.58", features = ['default', 'full'] } -tokio = { version = "1.0", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } -tokio-stream = "0.1" +syn = { version = "2.0.1", features = ['default', 'full'] } walkdir = "2.2" [lib] diff --git a/system/gd/rust/shim/src/init_flags.rs b/system/gd/rust/shim/src/init_flags.rs index 3b1d3398b98b2d1f3d9274246863fcc4db03939a..d2275cfaa8bfc45702ffdf58149bbd3f9e25c3fc 100644 --- a/system/gd/rust/shim/src/init_flags.rs +++ b/system/gd/rust/shim/src/init_flags.rs @@ -1,4 +1,5 @@ #[cxx::bridge(namespace = bluetooth::common::init_flags)] +#[allow(unsafe_op_in_unsafe_fn)] mod ffi { struct InitFlagWithValue { flag: &'static str, @@ -13,24 +14,17 @@ mod ffi { fn always_send_services_if_gatt_disc_done_is_enabled() -> bool; fn always_use_private_gatt_for_debugging_is_enabled() -> bool; - fn asynchronously_start_l2cap_coc_is_enabled() -> bool; - fn btaa_hci_is_enabled() -> bool; fn bta_dm_clear_conn_id_on_client_close_is_enabled() -> bool; + fn bluetooth_power_telemetry_is_enabled() -> bool; fn delay_hidh_cleanup_until_hidh_ready_start_is_enabled() -> bool; - fn gd_hal_snoop_logger_filtering_is_enabled() -> bool; fn btm_dm_flush_discovery_queue_on_search_cancel_is_enabled() -> bool; + fn bta_dm_stop_discovery_on_search_cancel_is_enabled() -> bool; fn classic_discovery_only_is_enabled() -> bool; fn clear_hidd_interrupt_cid_on_disconnect_is_enabled() -> bool; fn device_iot_config_logging_is_enabled() -> bool; fn dynamic_avrcp_version_enhancement_is_enabled() -> bool; - fn finite_att_timeout_is_enabled() -> bool; fn gatt_robust_caching_client_is_enabled() -> bool; fn gatt_robust_caching_server_is_enabled() -> bool; - fn gd_core_is_enabled() -> bool; - fn gd_hal_snoop_logger_socket_is_enabled() -> bool; - fn gd_l2cap_is_enabled() -> bool; - fn gd_link_policy_is_enabled() -> bool; - fn gd_remote_name_request_is_enabled() -> bool; fn get_default_log_level() -> i32; fn get_hci_adapter() -> i32; fn get_log_level_for_tag(tag: &str) -> i32; @@ -39,12 +33,9 @@ mod ffi { fn hfp_dynamic_version_is_enabled() -> bool; fn irk_rotation_is_enabled() -> bool; fn leaudio_targeted_announcement_reconnection_mode_is_enabled() -> bool; - fn pass_phy_update_callback_is_enabled() -> bool; fn pbap_pse_dynamic_version_upgrade_is_enabled() -> bool; fn periodic_advertising_adi_is_enabled() -> bool; fn private_gatt_is_enabled() -> bool; - fn queue_l2cap_coc_while_encrypting_is_enabled() -> bool; - fn read_encryption_key_size_is_enabled() -> bool; fn redact_log_is_enabled() -> bool; fn rust_event_loop_is_enabled() -> bool; fn sco_codec_select_lc3_is_enabled() -> bool; @@ -57,6 +48,9 @@ mod ffi { fn trigger_advertising_callbacks_on_first_resume_after_pause_is_enabled() -> bool; fn use_unified_connection_manager_is_enabled() -> bool; fn sdp_return_classic_services_when_le_discovery_fails_is_enabled() -> bool; + fn use_rsi_from_cached_inqiry_results_is_enabled() -> bool; + fn get_att_mtu_default() -> i32; + fn encryption_in_busy_state_is_enabled() -> bool; } } diff --git a/system/gd/rust/stack/Android.bp b/system/gd/rust/stack/Android.bp index 6e0c5c67f8941d0092cc9a29cbbeeebdf1a54f89..1981cbb3ad0f5f67c3ab67c184795e5aaef9a243 100644 --- a/system/gd/rust/stack/Android.bp +++ b/system/gd/rust/stack/Android.bp @@ -27,7 +27,8 @@ rust_library { "liblazy_static", "liblog_rust", "libnum_traits", - "libprotobuf_deprecated", + "libpdl_runtime", + "libprotobuf", "libthiserror", "libtokio", "libtokio_stream", @@ -35,9 +36,6 @@ rust_library { proc_macros: [ "libnum_derive", ], - apex_available: [ - "com.android.btservices", - ], min_sdk_version: "30", target: { android: { @@ -75,7 +73,8 @@ rust_test_host { "liblazy_static", "liblog_rust", "libnum_traits", - "libprotobuf_deprecated", + "libpdl_runtime", + "libprotobuf", "libthiserror", "libtokio", "libtokio_stream", @@ -104,13 +103,16 @@ genrule { cc_library_static { name: "libbt_hidl_hal_cxx", defaults: [ - "fluoride_common_options", + "bluetooth_cflags", "gd_ffi_defaults", "rust_static_cc_lib_defaults", ], srcs: ["src/hal/ffi/hidl.cc"], local_include_dirs: ["src/hal/ffi"], - include_dirs: ["packages/modules/Bluetooth/system"], + include_dirs: [ + "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/gd", + ], generated_headers: [ "cxx-bridge-header", "libbt_hidl_hal_bridge_header", @@ -122,8 +124,5 @@ cc_library_static { "libhidlbase", "libutils", ], - apex_available: [ - "com.android.btservices", - ], min_sdk_version: "30", } diff --git a/system/gd/rust/stack/Cargo.toml b/system/gd/rust/stack/Cargo.toml index d18a6e45acf3a2a55d2a0429d3cc6d0c6443be99..13c3c3209baf7c9cb260a61686e20ce30b6e3007 100644 --- a/system/gd/rust/stack/Cargo.toml +++ b/system/gd/rust/stack/Cargo.toml @@ -35,6 +35,7 @@ lazy_static = "1.4" log = "0.4" nix = "0.23" num-traits = "0.2" +pdl-runtime = "0.2.2" protobuf = "2.0" thiserror = "1.0" tokio = "1.0" diff --git a/system/gd/rust/stack/src/hal/facade.rs b/system/gd/rust/stack/src/hal/facade.rs index bc242d926f047d6544f05ecea854f501452ccb91..ae6baaf84c721f2a80ac08520770c8890e593f4f 100644 --- a/system/gd/rust/stack/src/hal/facade.rs +++ b/system/gd/rust/stack/src/hal/facade.rs @@ -6,7 +6,7 @@ use bt_facade_helpers::RxAdapter; use bt_facade_proto::common::Data; use bt_facade_proto::empty::Empty; use bt_facade_proto::hal_facade_grpc::{create_hci_hal_facade, HciHalFacade}; -use bt_packets::hci::{AclPacket, CommandPacket, EventPacket, IsoPacket, ScoPacket}; +use bt_packets::hci::{Acl, Command, Event, Iso, Sco}; use gddi::{module, provides, Stoppable}; use grpcio::*; @@ -39,10 +39,10 @@ async fn provide_facade( /// HCI HAL facade service #[derive(Clone, Stoppable)] pub struct HciHalFacadeService { - evt_rx: RxAdapter, - acl_rx: RxAdapter, - iso_rx: RxAdapter, - sco_rx: RxAdapter, + evt_rx: RxAdapter, + acl_rx: RxAdapter, + iso_rx: RxAdapter, + sco_rx: RxAdapter, control: ControlHal, acl: AclHal, iso: IsoHal, @@ -56,34 +56,34 @@ impl GrpcFacade for HciHalFacadeService { } impl HciHalFacade for HciHalFacadeService { - fn send_command(&mut self, ctx: RpcContext<'_>, mut data: Data, sink: UnarySink) { + fn send_command(&mut self, ctx: RpcContext<'_>, data: Data, sink: UnarySink) { let cmd_tx = self.control.tx.clone(); ctx.spawn(async move { - cmd_tx.send(CommandPacket::parse(&data.take_payload()).unwrap()).await.unwrap(); + cmd_tx.send(Command::parse(&data.payload).unwrap()).await.unwrap(); sink.success(Empty::default()).await.unwrap(); }); } - fn send_acl(&mut self, ctx: RpcContext<'_>, mut data: Data, sink: UnarySink) { + fn send_acl(&mut self, ctx: RpcContext<'_>, data: Data, sink: UnarySink) { let acl_tx = self.acl.tx.clone(); ctx.spawn(async move { - acl_tx.send(AclPacket::parse(&data.take_payload()).unwrap()).await.unwrap(); + acl_tx.send(Acl::parse(&data.payload).unwrap()).await.unwrap(); sink.success(Empty::default()).await.unwrap(); }); } - fn send_sco(&mut self, ctx: RpcContext<'_>, mut data: Data, sink: UnarySink) { + fn send_sco(&mut self, ctx: RpcContext<'_>, data: Data, sink: UnarySink) { let sco_tx = self.sco.tx.clone(); ctx.spawn(async move { - sco_tx.send(ScoPacket::parse(&data.take_payload()).unwrap()).await.unwrap(); + sco_tx.send(Sco::parse(&data.payload).unwrap()).await.unwrap(); sink.success(Empty::default()).await.unwrap(); }); } - fn send_iso(&mut self, ctx: RpcContext<'_>, mut data: Data, sink: UnarySink) { + fn send_iso(&mut self, ctx: RpcContext<'_>, data: Data, sink: UnarySink) { let iso_tx = self.iso.tx.clone(); ctx.spawn(async move { - iso_tx.send(IsoPacket::parse(&data.take_payload()).unwrap()).await.unwrap(); + iso_tx.send(Iso::parse(&data.payload).unwrap()).await.unwrap(); sink.success(Empty::default()).await.unwrap(); }); } diff --git a/system/gd/rust/stack/src/hal/hidl_hal.rs b/system/gd/rust/stack/src/hal/hidl_hal.rs index 0d46edd0701d3f57bf09a44f4b4e0e10ac10891e..9070153af7a434abb2e0cb187302438a5336275d 100644 --- a/system/gd/rust/stack/src/hal/hidl_hal.rs +++ b/system/gd/rust/stack/src/hal/hidl_hal.rs @@ -1,8 +1,9 @@ //! Implementation of the HAl that talks to BT controller over Android's HIDL use crate::hal::internal::{InnerHal, RawHal}; -use bt_packets::hci::{AclPacket, CommandPacket, EventPacket, IsoPacket, Packet, ScoPacket}; +use bt_packets::hci::{Acl, Command, Event, Iso, Sco}; use gddi::{module, provides}; use lazy_static::lazy_static; +use pdl_runtime::Packet; use std::sync::Arc; use std::sync::Mutex; use tokio::runtime::Runtime; @@ -43,6 +44,7 @@ async fn provide_hidl_hal(rt: Arc) -> RawHal { #[cxx::bridge(namespace = bluetooth::hal)] // TODO Either use or remove these functions, this shouldn't be the long term state #[allow(dead_code)] +#[allow(unsafe_op_in_unsafe_fn)] mod ffi { unsafe extern "C++" { include!("src/hal/ffi/hidl.h"); @@ -65,10 +67,10 @@ mod ffi { struct Callbacks { init_tx: UnboundedSender<()>, - evt_tx: UnboundedSender, - acl_tx: UnboundedSender, - iso_tx: UnboundedSender, - sco_tx: UnboundedSender, + evt_tx: UnboundedSender, + acl_tx: UnboundedSender, + iso_tx: UnboundedSender, + sco_tx: UnboundedSender, } lazy_static! { @@ -83,7 +85,7 @@ fn on_init_complete() { fn on_event(data: &[u8]) { log::error!("got event: {:02x?}", data); let callbacks = CALLBACKS.lock().unwrap(); - match EventPacket::parse(data) { + match Event::parse(data) { Ok(p) => callbacks.as_ref().unwrap().evt_tx.send(p).unwrap(), Err(e) => log::error!("failure to parse event: {:?} data: {:02x?}", e, data), } @@ -91,7 +93,7 @@ fn on_event(data: &[u8]) { fn on_acl(data: &[u8]) { let callbacks = CALLBACKS.lock().unwrap(); - match AclPacket::parse(data) { + match Acl::parse(data) { Ok(p) => callbacks.as_ref().unwrap().acl_tx.send(p).unwrap(), Err(e) => log::error!("failure to parse incoming ACL: {:?} data: {:02x?}", e, data), } @@ -99,7 +101,7 @@ fn on_acl(data: &[u8]) { fn on_sco(data: &[u8]) { let callbacks = CALLBACKS.lock().unwrap(); - match ScoPacket::parse(data) { + match Sco::parse(data) { Ok(p) => callbacks.as_ref().unwrap().sco_tx.send(p).unwrap(), Err(e) => log::error!("failure to parse incoming SCO: {:?} data: {:02x?}", e, data), } @@ -107,17 +109,17 @@ fn on_sco(data: &[u8]) { fn on_iso(data: &[u8]) { let callbacks = CALLBACKS.lock().unwrap(); - match IsoPacket::parse(data) { + match Iso::parse(data) { Ok(p) => callbacks.as_ref().unwrap().iso_tx.send(p).unwrap(), Err(e) => log::error!("failure to parse incoming ISO: {:?} data: {:02x?}", e, data), } } async fn dispatch_outgoing( - mut cmd_rx: UnboundedReceiver, - mut acl_rx: UnboundedReceiver, - mut iso_rx: UnboundedReceiver, - mut sco_rx: UnboundedReceiver, + mut cmd_rx: UnboundedReceiver, + mut acl_rx: UnboundedReceiver, + mut iso_rx: UnboundedReceiver, + mut sco_rx: UnboundedReceiver, ) { loop { select! { diff --git a/system/gd/rust/stack/src/hal/mod.rs b/system/gd/rust/stack/src/hal/mod.rs index 3e42ced085d260e2927e69ca562ec16abd9787f2..11741b455ad3e50aee80c86c0bb8fbc7dc5c02ee 100644 --- a/system/gd/rust/stack/src/hal/mod.rs +++ b/system/gd/rust/stack/src/hal/mod.rs @@ -37,7 +37,7 @@ const H4_HEADER_SIZE: usize = 1; pub use snoop::{AclHal, ControlHal, IsoHal, ScoHal}; mod internal { - use bt_packets::hci::{AclPacket, CommandPacket, EventPacket, IsoPacket, ScoPacket}; + use bt_packets::hci::{Acl, Command, Event, Iso, Sco}; use gddi::Stoppable; use std::sync::Arc; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; @@ -45,25 +45,25 @@ mod internal { #[derive(Clone, Stoppable)] pub struct RawHal { - pub cmd_tx: UnboundedSender, - pub evt_rx: Arc>>, - pub acl_tx: UnboundedSender, - pub acl_rx: Arc>>, - pub iso_tx: UnboundedSender, - pub iso_rx: Arc>>, - pub sco_tx: UnboundedSender, - pub sco_rx: Arc>>, + pub cmd_tx: UnboundedSender, + pub evt_rx: Arc>>, + pub acl_tx: UnboundedSender, + pub acl_rx: Arc>>, + pub iso_tx: UnboundedSender, + pub iso_rx: Arc>>, + pub sco_tx: UnboundedSender, + pub sco_rx: Arc>>, } pub struct InnerHal { - pub cmd_rx: UnboundedReceiver, - pub evt_tx: UnboundedSender, - pub acl_rx: UnboundedReceiver, - pub acl_tx: UnboundedSender, - pub sco_rx: UnboundedReceiver, - pub sco_tx: UnboundedSender, - pub iso_rx: UnboundedReceiver, - pub iso_tx: UnboundedSender, + pub cmd_rx: UnboundedReceiver, + pub evt_tx: UnboundedSender, + pub acl_rx: UnboundedReceiver, + pub acl_tx: UnboundedSender, + pub sco_rx: UnboundedReceiver, + pub sco_tx: UnboundedSender, + pub iso_rx: UnboundedReceiver, + pub iso_tx: UnboundedSender, } impl InnerHal { diff --git a/system/gd/rust/stack/src/hal/rootcanal_hal.rs b/system/gd/rust/stack/src/hal/rootcanal_hal.rs index 71c4d14a4804bcf2458818eb39699e778eb9cbbc..b8dc2fc0b2e2b8a689804e9259dc3cbd2d298ba4 100644 --- a/system/gd/rust/stack/src/hal/rootcanal_hal.rs +++ b/system/gd/rust/stack/src/hal/rootcanal_hal.rs @@ -4,10 +4,11 @@ use crate::hal::internal::{InnerHal, RawHal}; use crate::hal::{Result, H4_HEADER_SIZE}; -use bt_packets::hci::{AclPacket, CommandPacket, EventPacket, IsoPacket, Packet, ScoPacket}; +use bt_packets::hci::{Acl, Command, Event, Iso, Sco}; use bytes::{BufMut, Bytes, BytesMut}; use gddi::{module, provides, Stoppable}; use num_derive::{FromPrimitive, ToPrimitive}; +use pdl_runtime::Packet; use std::net::{IpAddr, SocketAddr}; use std::str::FromStr; use std::sync::Arc; @@ -84,10 +85,10 @@ impl RootcanalConfig { /// Send HCI events received from the HAL to the HCI layer async fn dispatch_incoming( - evt_tx: UnboundedSender, - acl_tx: UnboundedSender, - iso_tx: UnboundedSender, - sco_tx: UnboundedSender, + evt_tx: UnboundedSender, + acl_tx: UnboundedSender, + iso_tx: UnboundedSender, + sco_tx: UnboundedSender, reader: R, ) -> Result<()> where @@ -107,7 +108,7 @@ where reader.read_exact(&mut payload).await?; buffer.unsplit(payload); let frozen = buffer.freeze(); - match EventPacket::parse(&frozen) { + match Event::parse(&frozen) { Ok(p) => evt_tx.send(p).unwrap(), Err(e) => log::error!("dropping invalid event packet: {}: {:02x}", e, frozen), } @@ -120,7 +121,7 @@ where reader.read_exact(&mut payload).await?; buffer.unsplit(payload); let frozen = buffer.freeze(); - match AclPacket::parse(&frozen) { + match Acl::parse(&frozen) { Ok(p) => acl_tx.send(p).unwrap(), Err(e) => log::error!("dropping invalid ACL packet: {}: {:02x}", e, frozen), } @@ -133,7 +134,7 @@ where reader.read_exact(&mut payload).await?; buffer.unsplit(payload); let frozen = buffer.freeze(); - match IsoPacket::parse(&frozen) { + match Iso::parse(&frozen) { Ok(p) => iso_tx.send(p).unwrap(), Err(e) => log::error!("dropping invalid ISO packet: {}: {:02x}", e, frozen), } @@ -146,7 +147,7 @@ where reader.read_exact(&mut payload).await?; buffer.unsplit(payload); let frozen = buffer.freeze(); - match ScoPacket::parse(&frozen) { + match Sco::parse(&frozen) { Ok(p) => sco_tx.send(p).unwrap(), Err(e) => log::error!("dropping invalid SCO packet: {}: {:02x}", e, frozen), } @@ -156,10 +157,10 @@ where /// Send commands received from the HCI later to rootcanal async fn dispatch_outgoing( - mut cmd_rx: UnboundedReceiver, - mut acl_rx: UnboundedReceiver, - mut iso_rx: UnboundedReceiver, - mut sco_rx: UnboundedReceiver, + mut cmd_rx: UnboundedReceiver, + mut acl_rx: UnboundedReceiver, + mut iso_rx: UnboundedReceiver, + mut sco_rx: UnboundedReceiver, mut writer: W, ) -> Result<()> where diff --git a/system/gd/rust/stack/src/hal/snoop.rs b/system/gd/rust/stack/src/hal/snoop.rs index b3188aae0b0ae43daeeec50e61c4e2cd5b23394f..06d85a595aea95fec4bb5c0f9fa8a091d12ede03 100644 --- a/system/gd/rust/stack/src/hal/snoop.rs +++ b/system/gd/rust/stack/src/hal/snoop.rs @@ -2,10 +2,11 @@ use crate::hal::internal::RawHal; use bt_common::sys_prop; -use bt_packets::hci::{AclPacket, CommandPacket, EventPacket, IsoPacket, Packet, ScoPacket}; +use bt_packets::hci::{Acl, Command, Event, Iso, Sco}; use bytes::{BufMut, Bytes, BytesMut}; use gddi::{module, part_out, provides, Stoppable}; use log::error; +use pdl_runtime::Packet; use std::convert::TryFrom; use std::sync::Arc; use std::time::SystemTime; @@ -29,36 +30,36 @@ struct Hal { #[derive(Clone, Stoppable)] pub struct ControlHal { /// Transmit end - pub tx: Sender, + pub tx: Sender, /// Receive end - pub rx: Arc>>, + pub rx: Arc>>, } /// Acl tx/rx #[derive(Clone, Stoppable)] pub struct AclHal { /// Transmit end - pub tx: Sender, + pub tx: Sender, /// Receive end - pub rx: Arc>>, + pub rx: Arc>>, } /// Sco tx/rx #[derive(Clone, Stoppable)] pub struct ScoHal { /// Transmit end - pub tx: Sender, + pub tx: Sender, /// Receive end - pub rx: Arc>>, + pub rx: Arc>>, } /// Iso tx/rx #[derive(Clone, Stoppable)] pub struct IsoHal { /// Transmit end - pub tx: Sender, + pub tx: Sender, /// Receive end - pub rx: Arc>>, + pub rx: Arc>>, } /// The different modes snoop logging can be in @@ -141,14 +142,14 @@ module! { #[provides] async fn provide_snooped_hal(config: SnoopConfig, raw_hal: RawHal, rt: Arc) -> Hal { - let (cmd_down_tx, mut cmd_down_rx) = channel::(10); - let (evt_up_tx, evt_up_rx) = channel::(10); - let (acl_down_tx, mut acl_down_rx) = channel::(10); - let (acl_up_tx, acl_up_rx) = channel::(10); - let (sco_down_tx, mut sco_down_rx) = channel::(10); - let (sco_up_tx, sco_up_rx) = channel::(10); - let (iso_down_tx, mut iso_down_rx) = channel::(10); - let (iso_up_tx, iso_up_rx) = channel::(10); + let (cmd_down_tx, mut cmd_down_rx) = channel::(10); + let (evt_up_tx, evt_up_rx) = channel::(10); + let (acl_down_tx, mut acl_down_rx) = channel::(10); + let (acl_up_tx, acl_up_rx) = channel::(10); + let (sco_down_tx, mut sco_down_rx) = channel::(10); + let (sco_up_tx, sco_up_rx) = channel::(10); + let (iso_down_tx, mut iso_down_rx) = channel::(10); + let (iso_up_tx, iso_up_rx) = channel::(10); rt.spawn(async move { let mut logger = SnoopLogger::new(config).await; diff --git a/system/gd/rust/stack/src/hci/controller.rs b/system/gd/rust/stack/src/hci/controller.rs index 284d726a13e0d9eb5f60638f170b26c31115e4a8..654c01dca0bb21ee15bf972f4afe1e3721523fc8 100644 --- a/system/gd/rust/stack/src/hci/controller.rs +++ b/system/gd/rust/stack/src/hci/controller.rs @@ -14,7 +14,6 @@ use bt_packets::hci::{ WriteLeHostSupportBuilder, WriteSimplePairingModeBuilder, }; use gddi::{module, provides, Stoppable}; -use num_traits::ToPrimitive; use std::convert::TryFrom; use std::sync::Arc; @@ -234,7 +233,7 @@ impl SupportedCommands { return false; } - let index = converted.unwrap().to_usize().unwrap(); + let index = u16::from(converted.unwrap()) as usize; // OpCodeIndex is encoded as octet * 10 + bit for readability self.supported[index / 10] & (1 << (index % 10)) == 1 diff --git a/system/gd/rust/stack/src/hci/controller_facade.rs b/system/gd/rust/stack/src/hci/controller_facade.rs index ec719fc6f47d2b9f08bcd42a1c9fdd41662f09ca..cd1bd21961afdfeb9f2a7abede3d48b25d229ad5 100644 --- a/system/gd/rust/stack/src/hci/controller_facade.rs +++ b/system/gd/rust/stack/src/hci/controller_facade.rs @@ -10,7 +10,7 @@ use bt_facade_proto::empty::Empty; use bt_packets::hci::{OpCode, ReadLocalNameBuilder, WriteLocalNameBuilder}; use gddi::{module, provides, Stoppable}; use grpcio::*; -use num_traits::FromPrimitive; +use std::convert::TryFrom; use std::sync::Arc; module! { @@ -49,7 +49,8 @@ impl ControllerFacade for ControllerFacadeService { let clone = self.clone(); ctx.spawn(async move { let mut address = BluetoothAddress::new(); - address.set_address(clone.exports.address.bytes.to_vec()); + let address_bytes: [u8; 6] = clone.exports.address.into(); + address.address = address_bytes.to_vec(); sink.success(address).await.unwrap(); }); } @@ -57,7 +58,7 @@ impl ControllerFacade for ControllerFacadeService { fn write_local_name(&mut self, ctx: RpcContext<'_>, req: NameMsg, sink: UnarySink) { let mut clone = self.clone(); let mut builder = WriteLocalNameBuilder { local_name: [0; 248] }; - builder.local_name[0..req.get_name().len()].copy_from_slice(req.get_name()); + builder.local_name[0..req.name.len()].copy_from_slice(&req.name); ctx.spawn(async move { clone.hci.commands.send(builder.build()).await; sink.success(Empty::default()).await.unwrap(); @@ -71,8 +72,7 @@ impl ControllerFacade for ControllerFacadeService { clone.hci.commands.send(ReadLocalNameBuilder {}).await.get_local_name(), ) .into_bytes(); - let mut msg = NameMsg::new(); - msg.set_name(local_name); + let msg = NameMsg { name: local_name, ..NameMsg::default() }; sink.success(msg).await.unwrap(); }); } @@ -84,10 +84,12 @@ impl ControllerFacade for ControllerFacadeService { sink: UnarySink, ) { let clone = self.clone(); - let opcode = OpCode::from_u32(op_code_msg.get_op_code()).unwrap(); + let opcode = OpCode::try_from(u16::try_from(op_code_msg.op_code).unwrap()).unwrap(); ctx.spawn(async move { - let mut supported_msg = SupportedMsg::new(); - supported_msg.set_supported(clone.exports.commands.is_supported(opcode)); + let supported_msg = SupportedMsg { + supported: clone.exports.commands.is_supported(opcode), + ..SupportedMsg::default() + }; sink.success(supported_msg).await.unwrap(); }); } @@ -100,8 +102,10 @@ impl ControllerFacade for ControllerFacadeService { ) { let clone = self.clone(); ctx.spawn(async move { - let mut msg = SingleValueMsg::new(); - msg.set_value(clone.exports.le_supported_advertising_sets.into()); + let msg = SingleValueMsg { + value: clone.exports.le_supported_advertising_sets.into(), + ..SingleValueMsg::default() + }; sink.success(msg).await.unwrap(); }); } @@ -342,8 +346,10 @@ impl ControllerFacade for ControllerFacadeService { ) { let clone = self.clone(); ctx.spawn(async move { - let mut supported_msg = SupportedMsg::new(); - supported_msg.set_supported(clone.exports.le_features.extended_advertising); + let supported_msg = SupportedMsg { + supported: clone.exports.le_features.extended_advertising, + ..SupportedMsg::default() + }; sink.success(supported_msg).await.unwrap(); }); } diff --git a/system/gd/rust/stack/src/hci/facade.rs b/system/gd/rust/stack/src/hci/facade.rs index d4a45d23896531b0843e4ea4ad1191734fa24ff6..95128ec757ee29324a0d4391ffd3fbaad714ed0a 100644 --- a/system/gd/rust/stack/src/hci/facade.rs +++ b/system/gd/rust/stack/src/hci/facade.rs @@ -8,13 +8,10 @@ use bt_facade_proto::common::Data; use bt_facade_proto::empty::Empty; use bt_facade_proto::hci_facade::EventRequest; use bt_facade_proto::hci_facade_grpc::{create_hci_facade, HciFacade}; -use bt_packets::hci::{ - AclPacket, CommandPacket, EventCode, EventPacket, IsoPacket, LeMetaEventPacket, ScoPacket, - SubeventCode, -}; +use bt_packets::hci::{Acl, Command, Event, EventCode, Iso, LeMetaEvent, Sco, SubeventCode}; use gddi::{module, provides, Stoppable}; use grpcio::*; -use num_traits::FromPrimitive; +use std::convert::TryFrom; use tokio::sync::mpsc::{channel, Sender}; module! { @@ -32,8 +29,8 @@ async fn provide_facade( sco: ScoHal, iso: IsoHal, ) -> HciFacadeService { - let (evt_tx, evt_rx) = channel::(10); - let (le_evt_tx, le_evt_rx) = channel::(10); + let (evt_tx, evt_rx) = channel::(10); + let (le_evt_tx, le_evt_rx) = channel::(10); HciFacadeService { commands, events, @@ -56,28 +53,36 @@ async fn provide_facade( pub struct HciFacadeService { pub commands: RawCommandSender, events: EventRegistry, - evt_tx: Sender, - pub evt_rx: RxAdapter, - le_evt_tx: Sender, - pub le_evt_rx: RxAdapter, - pub acl_tx: Sender, - pub acl_rx: RxAdapter, - pub sco_tx: Sender, - pub sco_rx: RxAdapter, - pub iso_tx: Sender, - pub iso_rx: RxAdapter, + evt_tx: Sender, + pub evt_rx: RxAdapter, + le_evt_tx: Sender, + pub le_evt_rx: RxAdapter, + pub acl_tx: Sender, + pub acl_rx: RxAdapter, + pub sco_tx: Sender, + pub sco_rx: RxAdapter, + pub iso_tx: Sender, + pub iso_rx: RxAdapter, } impl HciFacadeService { /// Register for the event & plug in the channel to get them back on pub async fn register_event(&mut self, code: u32) { - self.events.register(EventCode::from_u32(code).unwrap(), self.evt_tx.clone()).await; + self.events + .register( + EventCode::try_from(u8::try_from(code).unwrap()).unwrap(), + self.evt_tx.clone(), + ) + .await; } /// Register for the le event & plug in the channel to get them back on pub async fn register_le_event(&mut self, code: u32) { self.events - .register_le(SubeventCode::from_u32(code).unwrap(), self.le_evt_tx.clone()) + .register_le( + SubeventCode::try_from(u8::try_from(code).unwrap()).unwrap(), + self.le_evt_tx.clone(), + ) .await; } } @@ -89,8 +94,8 @@ impl GrpcFacade for HciFacadeService { } impl HciFacade for HciFacadeService { - fn send_command(&mut self, ctx: RpcContext<'_>, mut data: Data, sink: UnarySink) { - let packet = CommandPacket::parse(&data.take_payload()).unwrap(); + fn send_command(&mut self, ctx: RpcContext<'_>, data: Data, sink: UnarySink) { + let packet = Command::parse(&data.payload).unwrap(); let mut commands = self.commands.clone(); let evt_tx = self.evt_tx.clone(); ctx.spawn(async move { @@ -103,7 +108,7 @@ impl HciFacade for HciFacadeService { fn request_event(&mut self, ctx: RpcContext<'_>, req: EventRequest, sink: UnarySink) { let mut clone = self.clone(); ctx.spawn(async move { - clone.register_event(req.get_code()).await; + clone.register_event(req.code).await; sink.success(Empty::default()).await.unwrap(); }); } @@ -116,15 +121,15 @@ impl HciFacade for HciFacadeService { ) { let mut clone = self.clone(); ctx.spawn(async move { - clone.register_le_event(req.get_code()).await; + clone.register_le_event(req.code).await; sink.success(Empty::default()).await.unwrap(); }); } - fn send_acl(&mut self, ctx: RpcContext<'_>, mut packet: Data, sink: UnarySink) { + fn send_acl(&mut self, ctx: RpcContext<'_>, packet: Data, sink: UnarySink) { let acl_tx = self.acl_tx.clone(); ctx.spawn(async move { - acl_tx.send(AclPacket::parse(&packet.take_payload()).unwrap()).await.unwrap(); + acl_tx.send(Acl::parse(&packet.payload).unwrap()).await.unwrap(); sink.success(Empty::default()).await.unwrap(); }); } diff --git a/system/gd/rust/stack/src/hci/mod.rs b/system/gd/rust/stack/src/hci/mod.rs index 8f24f2adc4e835c6a7da6dc4cc9d44e96b2df0c5..6c996fb62b711e7bfbcac1fb826fb128a34fa30a 100644 --- a/system/gd/rust/stack/src/hci/mod.rs +++ b/system/gd/rust/stack/src/hci/mod.rs @@ -9,18 +9,18 @@ pub mod error; /// HCI layer facade service pub mod facade; -pub use bt_packets::custom_types::Address; +pub use bt_packets::hci::Address; pub use controller::ControllerExports; use crate::hal::ControlHal; use bt_common::time::Alarm; +use bt_packets::hci; use bt_packets::hci::EventChild::{ CommandComplete, CommandStatus, LeMetaEvent, MaxSlotsChange, PageScanRepetitionModeChange, VendorSpecificEvent, }; use bt_packets::hci::{ - CommandExpectations, CommandPacket, ErrorCode, EventCode, EventPacket, LeMetaEventPacket, - ResetBuilder, SubeventCode, + Command, CommandExpectations, ErrorCode, Event, EventCode, ResetBuilder, SubeventCode, }; use error::Result; use gddi::{module, part_out, provides, Stoppable}; @@ -80,8 +80,8 @@ async fn provide_hci(control: ControlHal, rt: Arc) -> Hci { #[derive(Debug)] struct QueuedCommand { - cmd: CommandPacket, - fut: oneshot::Sender, + cmd: Command, + fut: oneshot::Sender, } /// Sends raw commands. Only useful for facades & shims, or wrapped as a CommandSender. @@ -94,8 +94,8 @@ impl RawCommandSender { /// Send a command, but does not automagically associate the expected returning event type. /// /// Only really useful for facades & shims. - pub async fn send(&mut self, cmd: CommandPacket) -> Result { - let (tx, rx) = oneshot::channel::(); + pub async fn send(&mut self, cmd: Command) -> Result { + let (tx, rx) = oneshot::channel::(); self.cmd_tx.send(QueuedCommand { cmd, fut: tx }).await?; let event = rx.await?; Ok(event) @@ -110,7 +110,7 @@ pub struct CommandSender { impl CommandSender { /// Send a command to the controller, getting an expected response back - pub async fn send + CommandExpectations>( + pub async fn send + CommandExpectations>( &mut self, cmd: T, ) -> T::ResponseType { @@ -121,13 +121,13 @@ impl CommandSender { /// Provides ability to register and unregister for HCI events #[derive(Clone, Stoppable)] pub struct EventRegistry { - evt_handlers: Arc>>>, - le_evt_handlers: Arc>>>, + evt_handlers: Arc>>>, + le_evt_handlers: Arc>>>, } impl EventRegistry { /// Indicate interest in specific HCI events - pub async fn register(&mut self, code: EventCode, sender: Sender) { + pub async fn register(&mut self, code: EventCode, sender: Sender) { match code { EventCode::CommandStatus | EventCode::CommandComplete @@ -151,7 +151,7 @@ impl EventRegistry { } /// Indicate interest in specific LE events - pub async fn register_le(&mut self, code: SubeventCode, sender: Sender) { + pub async fn register_le(&mut self, code: SubeventCode, sender: Sender) { assert!( self.le_evt_handlers.lock().await.insert(code, sender).is_none(), "A handler for {:?} is already registered", @@ -166,10 +166,10 @@ impl EventRegistry { } async fn dispatch( - evt_handlers: Arc>>>, - le_evt_handlers: Arc>>>, - evt_rx: Arc>>, - cmd_tx: Sender, + evt_handlers: Arc>>>, + le_evt_handlers: Arc>>>, + evt_rx: Arc>>, + cmd_tx: Sender, mut cmd_rx: Receiver, ) { let mut pending: Option = None; @@ -187,8 +187,8 @@ async fn dispatch( error!("failure dispatching command status {:?}", e); } }, - Some(QueuedCommand{cmd, ..}) => panic!("Waiting for {}, got {}", cmd.get_op_code(), this_opcode), - None => panic!("Unexpected status event with opcode {}", this_opcode), + Some(QueuedCommand{cmd, ..}) => panic!("Waiting for {:?}, got {:?}", cmd.get_op_code(), this_opcode), + None => panic!("Unexpected status event with opcode {:?}", this_opcode), } }, CommandComplete(evt) => { @@ -200,8 +200,8 @@ async fn dispatch( error!("failure dispatching command complete {:?}", e); } }, - Some(QueuedCommand{cmd, ..}) => panic!("Waiting for {}, got {}", cmd.get_op_code(), this_opcode), - None => panic!("Unexpected complete event with opcode {}", this_opcode), + Some(QueuedCommand{cmd, ..}) => panic!("Waiting for {:?}, got {:?}", cmd.get_op_code(), this_opcode), + None => panic!("Unexpected complete event with opcode {:?}", this_opcode), } }, LeMetaEvent(evt) => { @@ -239,12 +239,12 @@ async fn dispatch( hci_timeout.reset(Duration::from_secs(2)); pending = Some(queued); }, - _ = hci_timeout.expired() => panic!("Timed out waiting for {}", pending.unwrap().cmd.get_op_code()), + _ = hci_timeout.expired() => panic!("Timed out waiting for {:?}", pending.unwrap().cmd.get_op_code()), else => break, } } } -async fn consume(evt_rx: &Arc>>) -> Option { +async fn consume(evt_rx: &Arc>>) -> Option { evt_rx.lock().await.recv().await } diff --git a/system/gd/rust/stack/src/link/acl/classic/mod.rs b/system/gd/rust/stack/src/link/acl/classic/mod.rs index c523864a20f0786cc8473839b1be56ea67996a88..7a57e9d265af1fb484f8332305a3a66256bb3f66 100644 --- a/system/gd/rust/stack/src/link/acl/classic/mod.rs +++ b/system/gd/rust/stack/src/link/acl/classic/mod.rs @@ -3,14 +3,15 @@ use crate::hci::{Address, CommandSender, EventRegistry}; use crate::link::acl::core; use bt_common::Bluetooth; +use bt_packets::hci; use bt_packets::hci::EventChild::{ AuthenticationComplete, ConnectionComplete, DisconnectionComplete, }; use bt_packets::hci::{ AcceptConnectionRequestBuilder, AcceptConnectionRequestRole, ClockOffsetValid, CreateConnectionBuilder, CreateConnectionCancelBuilder, CreateConnectionRoleSwitch, - DisconnectBuilder, DisconnectReason, ErrorCode, EventChild, EventCode, EventPacket, - PageScanRepetitionMode, RejectConnectionReason, RejectConnectionRequestBuilder, Role, + DisconnectBuilder, DisconnectReason, ErrorCode, EventChild, EventCode, PageScanRepetitionMode, + RejectConnectionReason, RejectConnectionRequestBuilder, Role, }; use bytes::Bytes; use gddi::{module, provides, Stoppable}; @@ -94,7 +95,7 @@ struct ConnectionInternal { addr: Address, #[allow(dead_code)] shared: Arc>, - hci_evt_tx: Sender, + hci_evt_tx: Sender, } #[derive(Debug)] @@ -261,7 +262,7 @@ fn build_create_connection(bd_addr: Address) -> CreateConnectionBuilder { async fn dispatch_to( handle: u16, connections: &Arc>>, - event: EventPacket, + event: hci::Event, ) { if let Some(c) = connections.lock().await.get_mut(&handle) { c.hci_evt_tx.send(event).await.unwrap(); diff --git a/system/gd/rust/stack/src/link/acl/core.rs b/system/gd/rust/stack/src/link/acl/core.rs index 697896fbcd23a53fecc51fdc6bb8d29fa7f9e8e3..92e90994aa341737a0999838b4fdffa8b46bab5d 100644 --- a/system/gd/rust/stack/src/link/acl/core.rs +++ b/system/gd/rust/stack/src/link/acl/core.rs @@ -5,7 +5,7 @@ use crate::hci::{ControllerExports, EventRegistry}; use crate::link::acl::fragment::{fragmenting_stream, Reassembler}; use bt_common::Bluetooth::{self, Classic, Le}; use bt_packets::hci::EventChild::{DisconnectionComplete, NumberOfCompletedPackets}; -use bt_packets::hci::{AclPacket, EventCode, EventPacket}; +use bt_packets::hci::{Acl, Event, EventCode}; use bytes::Bytes; use futures::stream::{SelectAll, StreamExt}; use gddi::{module, provides, Stoppable}; @@ -34,15 +34,15 @@ pub struct Connection { handle: u16, #[allow(dead_code)] requests: Sender, - pub evt_rx: Receiver, - pub evt_tx: Sender, + pub evt_rx: Receiver, + pub evt_tx: Sender, } struct ConnectionInternal { reassembler: Reassembler, bt: Bluetooth, close_tx: oneshot::Sender<()>, - evt_tx: Sender, + evt_tx: Sender, } /// Manages rx and tx for open ACL connections @@ -179,6 +179,6 @@ async fn provide_acl_dispatch( AclDispatch { requests: req_tx } } -async fn consume(rx: &Arc>>) -> Option { +async fn consume(rx: &Arc>>) -> Option { rx.lock().await.recv().await } diff --git a/system/gd/rust/stack/src/link/acl/fragment.rs b/system/gd/rust/stack/src/link/acl/fragment.rs index 6e52cd50c5577efe62ed3497a7eb2894953012bc..637e12ba3a4a4e2a3b2f95b45fae15d8a5dfb901 100644 --- a/system/gd/rust/stack/src/link/acl/fragment.rs +++ b/system/gd/rust/stack/src/link/acl/fragment.rs @@ -4,7 +4,7 @@ use bt_common::Bluetooth; use bt_packets::hci::PacketBoundaryFlag::{ ContinuingFragment, FirstAutomaticallyFlushable, FirstNonAutomaticallyFlushable, }; -use bt_packets::hci::{AclBuilder, AclChild, AclPacket, BroadcastFlag}; +use bt_packets::hci::{Acl, AclBuilder, AclChild, BroadcastFlag}; use bytes::{Buf, Bytes, BytesMut}; use futures::stream::{self, StreamExt}; use log::{error, info, warn}; @@ -27,7 +27,7 @@ impl Reassembler { } /// Injest the packet and send out if fully reassembled - pub async fn on_packet(&mut self, packet: AclPacket) { + pub async fn on_packet(&mut self, packet: Acl) { let payload = match packet.specialize() { AclChild::Payload(payload) => payload, AclChild::None => { @@ -94,7 +94,7 @@ pub fn fragmenting_stream( bt: Bluetooth, close_rx: oneshot::Receiver<()>, ) -> std::pin::Pin< - std::boxed::Box + std::marker::Send>, + std::boxed::Box + std::marker::Send>, > { rx.flat_map(move |data| { stream::iter( @@ -113,7 +113,7 @@ pub fn fragmenting_stream( } .build() }) - .collect::>(), + .collect::>(), ) }) .take_until(close_rx) diff --git a/system/gd/rust/topshim/Android.bp b/system/gd/rust/topshim/Android.bp index 839e9a6ec12549db0e141c4837bc1c3196a1de2a..5f3e6e8f7960f9fddabc9e2c015d3652f66dc4c8 100644 --- a/system/gd/rust/topshim/Android.bp +++ b/system/gd/rust/topshim/Android.bp @@ -45,7 +45,6 @@ cc_library_static { name: "libbt_topshim_cxx", defaults: [ "gd_ffi_defaults", - "libchrome_support_defaults", ], srcs: [ "btav/btav_shim.cc", @@ -71,6 +70,7 @@ cc_library_static { "packages/modules/Bluetooth/system/types", ], host_supported: true, + static_libs: ["libchrome"], } gensrcs { @@ -110,7 +110,8 @@ rust_bindgen { wrapper_src: "bindings/wrapper.hpp", crate_name: "bt_topshim_wrapper_bindgen", source_stem: "bindings", - cpp_std: "c++17", + defaults: ["bluetooth_cflags"], + c_std: "", host_supported: true, bindgen_flags: [ "--allowlist-function=bt_.*", @@ -130,7 +131,6 @@ rust_bindgen { "--allowlist-type=sock_connect_signal_t", "--enable-cxx-namespaces", "--opaque-type=std::.*", - "--size_t-is-usize", "--with-derive-default", "--with-derive-eq", "--with-derive-partialeq", diff --git a/system/gd/rust/topshim/BUILD.gn b/system/gd/rust/topshim/BUILD.gn index a0a71f0f57f13a629074ed0b0588093112bb5061..cde636eff0b0ccbdfa3e66a2b83edd10c3e6831a 100644 --- a/system/gd/rust/topshim/BUILD.gn +++ b/system/gd/rust/topshim/BUILD.gn @@ -46,7 +46,7 @@ cxxbridge_cc("btif_bridge_code") { ] deps = [ ":btif_bridge_header", - "//bt/system/gd:BluetoothGeneratedPackets_h", + "//bt/system/pdl:BluetoothGeneratedPackets_h", ] configs = [ "//bt/system/gd:gd_defaults" ] } @@ -66,8 +66,8 @@ source_set("btif_cxx_bridge_code") { deps = [ ":btif_bridge_header", - "//bt/system/gd:BluetoothGeneratedPackets_h", "//bt/system/gd/metrics:BluetoothMetricsSources", + "//bt/system/pdl:BluetoothGeneratedPackets_h", ] configs += [ "//bt/system/gd:gd_defaults" ] } diff --git a/system/gd/rust/topshim/Cargo.toml b/system/gd/rust/topshim/Cargo.toml index 4b47b45a1b64855ffb590d6829efcc6229e2f4ce..7373931b5aa1069b78f20313a9221f6290bed68f 100644 --- a/system/gd/rust/topshim/Cargo.toml +++ b/system/gd/rust/topshim/Cargo.toml @@ -31,7 +31,7 @@ log = "0.4" num-derive = "0.3" num-traits = "0.2" proc-macro2 = "1.0" -tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } +tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } tokio-stream = "0.1" bitflags ="1.2" diff --git a/system/gd/rust/topshim/OWNERS b/system/gd/rust/topshim/OWNERS index 45bfdd2be4f3b49a5c0053e783ad429ded0c1be1..a823e6e1ddc6d3d153fe4acbd207c3b06ae03b10 100644 --- a/system/gd/rust/topshim/OWNERS +++ b/system/gd/rust/topshim/OWNERS @@ -1 +1 @@ -include platform/packages/modules/Bluetooth:/OWNERS_chromeos +include /OWNERS_chromeos diff --git a/system/gd/rust/topshim/bindings/wrapper.hpp b/system/gd/rust/topshim/bindings/wrapper.hpp index 7139de421e22a2e8dab5aee0f1bb58a02b3008bd..4d6cde161e0b55476fc3787203e23e83e4da08d8 100644 --- a/system/gd/rust/topshim/bindings/wrapper.hpp +++ b/system/gd/rust/topshim/bindings/wrapper.hpp @@ -1,5 +1,3 @@ -#pragma once - // Base #include "hardware/bluetooth.h" #include "include/hal_util.h" diff --git a/system/gd/rust/topshim/btav/btav_shim.cc b/system/gd/rust/topshim/btav/btav_shim.cc index 338c854a31cb33fb5e992b80fcdf2bc6b0a98ff3..14a88b38caeb67a6f7ba3b24eb09db60a2831a62 100644 --- a/system/gd/rust/topshim/btav/btav_shim.cc +++ b/system/gd/rust/topshim/btav/btav_shim.cc @@ -246,7 +246,7 @@ static void audio_config_cb( } static bool mandatory_codec_preferred_cb(const RawAddress& addr) { rusty::mandatory_codec_preferred_callback(addr); - return true; + return false; } btav_source_callbacks_t g_callbacks = { diff --git a/system/gd/rust/topshim/build.rs b/system/gd/rust/topshim/build.rs index 318f5ebe9e64c63ecee7d681d5dddaa4c1749887..c7cacdf3a8d2e6a1cdb6c55ff3580382930f2f71 100644 --- a/system/gd/rust/topshim/build.rs +++ b/system/gd/rust/topshim/build.rs @@ -41,7 +41,7 @@ fn main() { } // "-x" and "c++" must be separate due to a bug - let clang_args: Vec<&str> = vec!["-x", "c++", "-std=c++17"]; + let clang_args: Vec<&str> = vec!["-x", "c++", "-std=c++20"]; // The bindgen::Builder is the main entry point // to bindgen, and lets you build up options for diff --git a/system/gd/rust/topshim/facade/Android.bp b/system/gd/rust/topshim/facade/Android.bp index 4b639daae8c0832fb7e14254707f9330e1d3ca63..09748982de5d4f5ee44fc1ec0ac6b6ed1823055e 100644 --- a/system/gd/rust/topshim/facade/Android.bp +++ b/system/gd/rust/topshim/facade/Android.bp @@ -11,7 +11,6 @@ rust_defaults { name: "bt_topshim_facade.defaults", defaults: [ "gd_rust_defaults", - "libchrome_support_defaults", ], crate_name: "bt_topshim_facade", srcs: ["src/main.rs"], @@ -47,20 +46,20 @@ rust_defaults { "libbluetooth-dumpsys", "libbluetooth-types", "libbluetooth_core_rs", + "libbluetooth_crypto_toolbox", "libbluetooth_gd", // Gabeldorsche "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", + "libbt-btu-main-thread", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", "libbt-stack-core", "libbt_shim_bridge", "libbt_topshim_cxx", - "libbt_topshim_cxx", "libbtcore", "libbtdevice", "libbte", @@ -83,6 +82,7 @@ rust_defaults { "libgrpc++", "libgrpc_wrap", "liblog", + "server_configurable_flags", ], proc_macros: [ "libpaste", diff --git a/system/gd/rust/topshim/facade/src/adapter_service.rs b/system/gd/rust/topshim/facade/src/adapter_service.rs index 94a29a2946925f518c45778f7da3a779b181a5c4..d9aed8dcdaa12b00d922273c36ff2b8b068e7668 100644 --- a/system/gd/rust/topshim/facade/src/adapter_service.rs +++ b/system/gd/rust/topshim/facade/src/adapter_service.rs @@ -118,7 +118,7 @@ impl AdapterService for AdapterServiceImpl { match event { BaseCallbacks::AdapterState(_state) => { let mut rsp = FetchEventsResponse::new(); - rsp.event_type = EventType::ADAPTER_STATE; + rsp.event_type = EventType::ADAPTER_STATE.into(); rsp.params.insert( String::from("state"), event_data_from_string(String::from("ON")), @@ -128,7 +128,7 @@ impl AdapterService for AdapterServiceImpl { BaseCallbacks::SspRequest(_, _, _, _, _) => {} BaseCallbacks::LeRandCallback(random) => { let mut rsp = FetchEventsResponse::new(); - rsp.event_type = EventType::LE_RAND; + rsp.event_type = EventType::LE_RAND.into(); rsp.params.insert( String::from("data"), event_data_from_string(random.to_string()), @@ -137,7 +137,7 @@ impl AdapterService for AdapterServiceImpl { } BaseCallbacks::GenerateLocalOobData(transport, data) => { let mut rsp = FetchEventsResponse::new(); - rsp.event_type = EventType::GENERATE_LOCAL_OOB_DATA; + rsp.event_type = EventType::GENERATE_LOCAL_OOB_DATA.into(); rsp.params.insert( String::from("is_valid"), event_data_from_string(String::from(if data.is_valid { @@ -166,7 +166,7 @@ impl AdapterService for AdapterServiceImpl { } BaseCallbacks::AdapterProperties(status, _, properties) => { let mut rsp = FetchEventsResponse::new(); - rsp.event_type = EventType::ADAPTER_PROPERTY; + rsp.event_type = EventType::ADAPTER_PROPERTY.into(); rsp.params.insert( String::from("status"), event_data_from_string(format!("{:?}", status)), @@ -182,7 +182,7 @@ impl AdapterService for AdapterServiceImpl { } BaseCallbacks::DiscoveryState(state) => { let mut rsp = FetchEventsResponse::new(); - rsp.event_type = EventType::DISCOVERY_STATE; + rsp.event_type = EventType::DISCOVERY_STATE.into(); rsp.params.insert( String::from("discovery_state"), event_data_from_string(format!("{:?}", state)), @@ -191,7 +191,7 @@ impl AdapterService for AdapterServiceImpl { } BaseCallbacks::DeviceFound(_, properties) => { let mut rsp = FetchEventsResponse::new(); - rsp.event_type = EventType::DEVICE_FOUND; + rsp.event_type = EventType::DEVICE_FOUND.into(); for property in properties.clone() { let (key, event_data) = bluetooth_property_to_event_data(property); if key == "skip" { @@ -203,7 +203,7 @@ impl AdapterService for AdapterServiceImpl { } BaseCallbacks::BondState(_, address, state, _) => { let mut rsp = FetchEventsResponse::new(); - rsp.event_type = EventType::BOND_STATE; + rsp.event_type = EventType::BOND_STATE.into(); rsp.params.insert( String::from("bond_state"), event_data_from_string(format!("{:?}", state)), diff --git a/system/gd/rust/topshim/facade/src/hfp_service.rs b/system/gd/rust/topshim/facade/src/hfp_service.rs index 73a92f13041e235d66a068ccbd89d6c3291b6918..4f08a44c5076274eaa8637a9cecfe16d39f9d7a1 100644 --- a/system/gd/rust/topshim/facade/src/hfp_service.rs +++ b/system/gd/rust/topshim/facade/src/hfp_service.rs @@ -111,7 +111,11 @@ impl HfpService for HfpServiceImpl { let addr_bytes = &req.connection.unwrap().cookie; let bt_addr = from_utf8(addr_bytes).unwrap(); if let Some(addr) = RawAddress::from_string(bt_addr) { - hfp.lock().unwrap().connect_audio(addr, req.is_sco_offload_enabled, req.force_cvsd); + hfp.lock().unwrap().connect_audio( + addr, + req.is_sco_offload_enabled, + req.disabled_codecs, + ); hfp.lock().unwrap().set_active_device(addr); sink.success(Empty::default()).await.unwrap(); } else { @@ -198,7 +202,7 @@ impl HfpService for HfpServiceImpl { while let Some(event) = rx.recv().await { if let HfpCallbacks::ConnectionState(state, address) = event { let mut rsp = FetchEventsResponse::new(); - rsp.event_type = EventType::HFP_CONNECTION_STATE; + rsp.event_type = EventType::HFP_CONNECTION_STATE.into(); rsp.data = format!("{:?}, {}", state, address.to_string()); sink.send((rsp, WriteFlags::default())).await.unwrap(); } diff --git a/system/gd/rust/topshim/facade/src/main.rs b/system/gd/rust/topshim/facade/src/main.rs index e5b4ce30c7371c5debb8928465ac361b504885e1..b50ba8487a5ad8b155d1c44dff9215edc431f85d 100644 --- a/system/gd/rust/topshim/facade/src/main.rs +++ b/system/gd/rust/topshim/facade/src/main.rs @@ -36,7 +36,8 @@ use bluetooth_core_rs_for_facade::*; use bt_shim::*; fn main() { - let sigint = install_sigint(); + // SAFETY: There is no signal handler installed before this. + let sigint = unsafe { install_sigint() }; bt_common::init_logging(); let rt = Arc::new(Runtime::new().unwrap()); rt.block_on(async_main(Arc::clone(&rt), sigint)); @@ -113,9 +114,11 @@ async fn async_main(rt: Arc, mut sigint: mpsc::UnboundedReceiver<()>) { .register_service(hf_client_service_impl) .register_service(hfp_service_impl) .register_service(media_service_impl) - .bind("0.0.0.0", grpc_port) .build() .unwrap(); + let addr = format!("0.0.0.0:{}", grpc_port); + let creds = ServerCredentials::insecure(); + server.add_listening_port(addr, creds).unwrap(); server.start(); sigint.next().await; @@ -123,7 +126,10 @@ async fn async_main(rt: Arc, mut sigint: mpsc::UnboundedReceiver<()>) { } // TODO: remove as this is a temporary nix-based hack to catch SIGINT -fn install_sigint() -> mpsc::UnboundedReceiver<()> { +/// # Safety +/// +/// The old signal handler, if any, must be installed correctly. +unsafe fn install_sigint() -> mpsc::UnboundedReceiver<()> { let (tx, rx) = mpsc::unbounded(); *SIGINT_TX.lock().unwrap() = Some(tx); @@ -132,6 +138,10 @@ fn install_sigint() -> mpsc::UnboundedReceiver<()> { signal::SaFlags::empty(), signal::SigSet::empty(), ); + // SAFETY: The caller guarantees that the old signal handler was installed correctly. + // TODO(b/292218119): Make sure `handle_sigint` only makes system calls that are safe for signal + // handlers, and only accesses global state through atomics. In particular, it must not take any + // shared locks. unsafe { signal::sigaction(signal::SIGINT, &sig_action).unwrap(); } diff --git a/system/gd/rust/topshim/gatt/gatt_ble_advertiser_shim.cc b/system/gd/rust/topshim/gatt/gatt_ble_advertiser_shim.cc index a47cfab4e8d76dbd214c7a13db2794eee4d86bd7..cb5b6d58493b5c6c1a84f3e138b876855406583c 100644 --- a/system/gd/rust/topshim/gatt/gatt_ble_advertiser_shim.cc +++ b/system/gd/rust/topshim/gatt/gatt_ble_advertiser_shim.cc @@ -176,6 +176,7 @@ void BleAdvertiserIntf::StartAdvertisingSet( std::copy(periodic_data.begin(), periodic_data.end(), std::back_inserter(converted_periodic_data)); adv_intf_->StartAdvertisingSet( + kAdvertiserClientIdJni, reg_id, base::Bind(&BleAdvertiserIntf::OnIdTxPowerStatusCallback, base::Unretained(this)), converted_params, diff --git a/system/gd/rust/topshim/hfp/hfp_shim.cc b/system/gd/rust/topshim/hfp/hfp_shim.cc index 2345c4e4fdcd094528dc076490f890d44c957ab8..a98d7949627dfa680fc93e381f5c106a1293dbc1 100644 --- a/system/gd/rust/topshim/hfp/hfp_shim.cc +++ b/system/gd/rust/topshim/hfp/hfp_shim.cc @@ -17,6 +17,8 @@ #include "gd/rust/topshim/hfp/hfp_shim.h" #include "btif/include/btif_hf.h" +#include "device/include/interop.h" +#include "gd/common/strings.h" #include "gd/os/log.h" #include "include/hardware/bt_hf.h" #include "src/profiles/hfp.rs.h" @@ -42,6 +44,14 @@ static void volume_update_cb(uint8_t volume, RawAddress* addr) { rusty::hfp_volume_update_callback(volume, *addr); } +static void mic_volume_update_cb(uint8_t volume, RawAddress* addr) { + rusty::hfp_mic_volume_update_callback(volume, *addr); +} + +static void vendor_specific_at_command_cb(char* at_string, RawAddress* addr) { + rusty::hfp_vendor_specific_at_command_callback(::rust::String{at_string}, *addr); +} + static void battery_level_update_cb(uint8_t battery_level, RawAddress* addr) { rusty::hfp_battery_level_update_callback(battery_level, *addr); } @@ -105,6 +115,26 @@ static headset::bthf_call_state_t from_rust_call_state(rusty::CallState state) { ASSERT_LOG(false, "Unhandled enum value from Rust"); } } + +static void debug_dump_cb( + bool active, + uint16_t codec_id, + int total_num_decoded_frames, + double packet_loss_ratio, + uint64_t begin_ts, + uint64_t end_ts, + const char* pkt_status_in_hex, + const char* pkt_status_in_binary) { + rusty::hfp_debug_dump_callback( + active, + codec_id, + total_num_decoded_frames, + packet_loss_ratio, + begin_ts, + end_ts, + ::rust::String{pkt_status_in_hex}, + ::rust::String{pkt_status_in_binary}); +} } // namespace internal class DBusHeadsetCallbacks : public headset::Callbacks { @@ -139,10 +169,17 @@ class DBusHeadsetCallbacks : public headset::Callbacks { } void VolumeControlCallback(headset::bthf_volume_type_t type, int volume, RawAddress* bd_addr) override { - if (type != headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK || volume < 0) return; + if (volume < 0) return; if (volume > 15) volume = 15; - LOG_INFO("VolumeControlCallback %d from %s", volume, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); - topshim::rust::internal::volume_update_cb(volume, bd_addr); + if (type == headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK) { + LOG_INFO( + "VolumeControlCallback (Spk) %d from %s", volume, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + topshim::rust::internal::volume_update_cb(volume, bd_addr); + } else if (type == headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_MIC) { + LOG_INFO( + "VolumeControlCallback (Mic) %d from %s", volume, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + topshim::rust::internal::mic_volume_update_cb(volume, bd_addr); + } } void DialCallCallback(char* number, RawAddress* bd_addr) override { @@ -159,9 +196,11 @@ class DBusHeadsetCallbacks : public headset::Callbacks { rusty::hfp_wbs_caps_update_callback(wbs == headset::BTHF_WBS_YES, *addr); } - void SwbCallback(headset::bthf_swb_config_t swb, RawAddress* addr) override { - LOG_INFO("SwbCallback %d from %s", swb, ADDRESS_TO_LOGGABLE_CSTR(*addr)); - rusty::hfp_swb_caps_update_callback(swb == headset::BTHF_SWB_YES, *addr); + void SwbCallback( + headset::bthf_swb_codec_t codec, headset::bthf_swb_config_t swb, RawAddress* addr) override { + LOG_INFO("SwbCallback codec:%d, swb:%d from %s", codec, swb, ADDRESS_TO_LOGGABLE_CSTR(*addr)); + rusty::hfp_swb_caps_update_callback( + (codec == headset::BTHF_SWB_CODEC_LC3 && swb == headset::BTHF_SWB_YES), *addr); } void AtChldCallback(headset::bthf_chld_type_t chld, RawAddress* bd_addr) override { @@ -189,8 +228,27 @@ class DBusHeadsetCallbacks : public headset::Callbacks { } void UnknownAtCallback(char* at_string, RawAddress* bd_addr) override { - LOG_WARN("Reply Error to UnknownAtCallback:%s", at_string); - headset_->AtResponse(headset::BTHF_AT_RESPONSE_ERROR, 0, bd_addr); + const std::string at_command = common::ToString(at_string); + // We are able to support +XAPL, +IPHONEACCEV, and +XEVENT commands, + // everything else will get an error reply. + const bool is_xapl = at_command.find("+XAPL") != std::string::npos; + const bool is_iphoneaccev = at_command.find("+IPHONEACCEV") != std::string::npos; + const bool is_xevent = at_command.find("+XEVENT") != std::string::npos; + if (!is_xapl && !is_iphoneaccev && !is_xevent) { + LOG_WARN("Reply Error to UnknownAtCallback:%s", at_string); + headset_->AtResponse(headset::BTHF_AT_RESPONSE_ERROR, 0, bd_addr); + return; + } + + if (is_xapl) { + // Respond that we support battery level reporting only (2). + headset_->FormattedAtResponse("+XAPL=iPhone,2", bd_addr); + } + + // Ack all supported commands and bubble commands up for further processing + // if desired. + topshim::rust::internal::vendor_specific_at_command_cb(at_string, bd_addr); + headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr); } void KeyPressedCallback([[maybe_unused]] RawAddress* bd_addr) override {} @@ -227,6 +285,36 @@ class DBusHeadsetCallbacks : public headset::Callbacks { battery, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); } + void DebugDumpCallback( + bool active, + uint16_t codec_id, + int total_num_decoded_frames, + double packet_loss_ratio, + uint64_t begin_ts, + uint64_t end_ts, + const char* pkt_status_in_hex, + const char* pkt_status_in_binary) override { + LOG_WARN( + "DebugDumpCallback %d %u %d %f %llu %llu %s %s", + active, + codec_id, + total_num_decoded_frames, + packet_loss_ratio, + (unsigned long long)begin_ts, + (unsigned long long)end_ts, + pkt_status_in_hex, + pkt_status_in_binary); + topshim::rust::internal::debug_dump_cb( + active, + codec_id, + total_num_decoded_frames, + packet_loss_ratio, + begin_ts, + end_ts, + pkt_status_in_hex, + pkt_status_in_binary); + } + private: headset::Interface* headset_; }; @@ -239,9 +327,9 @@ uint32_t HfpIntf::connect(RawAddress addr) { return intf_->Connect(&addr); } -int HfpIntf::connect_audio(RawAddress addr, bool sco_offload, bool force_cvsd) { +int HfpIntf::connect_audio(RawAddress addr, bool sco_offload, int disabled_codecs) { intf_->SetScoOffloadEnabled(sco_offload); - return intf_->ConnectAudio(&addr, force_cvsd); + return intf_->ConnectAudio(&addr, disabled_codecs); } int HfpIntf::set_active_device(RawAddress addr) { @@ -252,6 +340,10 @@ int HfpIntf::set_volume(int8_t volume, RawAddress addr) { return intf_->VolumeControl(headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK, volume, &addr); } +uint32_t HfpIntf::set_mic_volume(int8_t volume, RawAddress addr) { + return intf_->VolumeControl(headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_MIC, volume, &addr); +} + uint32_t HfpIntf::disconnect(RawAddress addr) { return intf_->Disconnect(&addr); } @@ -329,6 +421,10 @@ uint32_t HfpIntf::simple_at_response(bool ok, RawAddress addr) { (ok ? headset::BTHF_AT_RESPONSE_OK : headset::BTHF_AT_RESPONSE_ERROR), 0, &addr); } +void HfpIntf::debug_dump() { + intf_->DebugDump(); +} + void HfpIntf::cleanup() {} std::unique_ptr GetHfpProfile(const unsigned char* btif) { @@ -343,6 +439,10 @@ std::unique_ptr GetHfpProfile(const unsigned char* btif) { return hfpif; } +bool interop_insert_call_when_sco_start(RawAddress addr) { + return interop_match_addr(interop_feature_t::INTEROP_INSERT_CALL_WHEN_SCO_START, &addr); +} + } // namespace rust } // namespace topshim } // namespace bluetooth diff --git a/system/gd/rust/topshim/hfp/hfp_shim.h b/system/gd/rust/topshim/hfp/hfp_shim.h index a061420e9f7f10085a7f2211bc1749b6ab49c9ae..f17aec9c536667cfd73d7a01f52e1a7e61f1d9d5 100644 --- a/system/gd/rust/topshim/hfp/hfp_shim.h +++ b/system/gd/rust/topshim/hfp/hfp_shim.h @@ -37,9 +37,10 @@ class HfpIntf { int init(); uint32_t connect(RawAddress addr); - int connect_audio(RawAddress addr, bool sco_offload, bool force_cvsd); + int connect_audio(RawAddress addr, bool sco_offload, int disabled_codecs); int set_active_device(RawAddress addr); int set_volume(int8_t volume, RawAddress addr); + uint32_t set_mic_volume(int8_t volume, RawAddress addr); uint32_t disconnect(RawAddress addr); int disconnect_audio(RawAddress addr); uint32_t device_status_notification(TelephonyDeviceStatus status, RawAddress addr); @@ -49,6 +50,7 @@ class HfpIntf { uint32_t phone_state_change( PhoneState phone_state, const ::rust::String& number, RawAddress addr); uint32_t simple_at_response(bool ok, RawAddress addr); + void debug_dump(); void cleanup(); private: @@ -56,6 +58,7 @@ class HfpIntf { }; std::unique_ptr GetHfpProfile(const unsigned char* btif); +bool interop_insert_call_when_sco_start(RawAddress addr); } // namespace rust } // namespace topshim diff --git a/system/gd/rust/topshim/src/btif.rs b/system/gd/rust/topshim/src/btif.rs index 02e5559056f7ffdbd09d9e283dcd91c64e1e701d..012539284dbc78fa8df41af3f005221c66633af5 100644 --- a/system/gd/rust/topshim/src/btif.rs +++ b/system/gd/rust/topshim/src/btif.rs @@ -153,6 +153,12 @@ pub enum BtPropertyType { RemoteIsCoordinatedSetMember, Appearance, VendorProductInfo, + // Unimplemented: + // BT_PROPERTY_WL_MEDIA_PLAYERS_LIST, + // BT_PROPERTY_REMOTE_ASHA_CAPABILITY, + // BT_PROPERTY_REMOTE_ASHA_TRUNCATED_HISYNCID, + // BT_PROPERTY_REMOTE_MODEL_NUM, + RemoteAddrType = 0x18, Unknown = 0xFE, RemoteDeviceTimestamp = 0xFF, @@ -201,6 +207,7 @@ pub enum BtStatus { JniEnvironmentError, JniThreadAttachError, WakeLockError, + Timeout, // Any statuses that couldn't be cleanly converted Unknown = 0xff, @@ -329,6 +336,19 @@ impl Into for BtDiscMode { } } +#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] +#[repr(u32)] +pub enum BtThreadEvent { + Associate = 0, + Disassociate, +} + +impl From for BtThreadEvent { + fn from(item: bindings::bt_cb_thread_evt) -> Self { + BtThreadEvent::from_u32(item).unwrap_or(BtThreadEvent::Associate) + } +} + #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] #[repr(u32)] pub enum BtIoCap { @@ -347,6 +367,29 @@ impl From for BtIoCap { } } +#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] +#[repr(u32)] +pub enum BtAddrType { + Public, + Random, + PublicId, + RandomId, + Unknown = 0xfe, + Anonymous = 0xff, +} + +impl From for BtAddrType { + fn from(num: u32) -> Self { + BtAddrType::from_u32(num).unwrap_or(BtAddrType::Unknown) + } +} + +impl Into for BtAddrType { + fn into(self) -> u32 { + self.to_u32().unwrap_or(0) + } +} + pub type BtHciErrorCode = u8; pub type BtLocalLeFeatures = bindings::bt_local_le_features_t; pub type BtPinCode = bindings::bt_pin_code_t; @@ -453,11 +496,19 @@ pub enum BluetoothProperty { RemoteIsCoordinatedSetMember(bool), Appearance(u16), VendorProductInfo(BtVendorProductInfo), + RemoteAddrType(BtAddrType), RemoteDeviceTimestamp(), Unknown(), } +/// Unknown or invalid RSSI value. +/// Per Core v5.3, Vol 4, E, 7.5.4. Valid RSSI is represent in 1-byte with the range: +/// BR/EDR: -128 to 127 +/// LE: -127 to 20, 127 +/// Set 127 as invalid value also aligns with bluez. +pub const INVALID_RSSI: i8 = 127; + /// Wherever names are sent in bindings::bt_property_t, the size of the character /// arrays are 256. Keep one extra byte for null termination. const PROPERTY_NAME_MAX: usize = 255; @@ -489,6 +540,7 @@ impl BluetoothProperty { BluetoothProperty::Appearance(_) => BtPropertyType::Appearance, BluetoothProperty::VendorProductInfo(_) => BtPropertyType::VendorProductInfo, BluetoothProperty::RemoteDeviceTimestamp() => BtPropertyType::RemoteDeviceTimestamp, + BluetoothProperty::RemoteAddrType(_) => BtPropertyType::RemoteAddrType, BluetoothProperty::Unknown() => BtPropertyType::Unknown, } } @@ -519,6 +571,7 @@ impl BluetoothProperty { BluetoothProperty::RemoteIsCoordinatedSetMember(_) => mem::size_of::(), BluetoothProperty::Appearance(_) => mem::size_of::(), BluetoothProperty::VendorProductInfo(_) => mem::size_of::(), + BluetoothProperty::RemoteAddrType(_) => mem::size_of::(), // TODO(abps) - Figure out sizes for these BluetoothProperty::DynamicAudioBuffer() => 0, @@ -559,7 +612,7 @@ impl BluetoothProperty { // Do an unsafe cast to binding:: type and assign the values // The underlying memory location is provided by |data| which will // have enough space because it uses get_len() - let mut record = + let record = unsafe { &mut *(data.as_mut_ptr() as *mut bindings::bt_service_record_t) }; record.uuid = sr.uuid; record.channel = sr.channel; @@ -627,6 +680,11 @@ impl BluetoothProperty { }; data.copy_from_slice(&slice); } + BluetoothProperty::RemoteAddrType(addr_type) => { + data.copy_from_slice( + &BtAddrType::to_u32(addr_type).unwrap_or_default().to_ne_bytes(), + ); + } BluetoothProperty::DynamicAudioBuffer() => (), BluetoothProperty::RemoteDeviceTimestamp() => (), @@ -651,7 +709,7 @@ impl From for BluetoothProperty { } BtPropertyType::Uuids => { let count = len / mem::size_of::(); - BluetoothProperty::Uuids(ptr_to_vec(prop.val as *mut Uuid, count)) + BluetoothProperty::Uuids(ptr_to_vec(prop.val as *const Uuid, count)) } BtPropertyType::ClassOfDevice => { BluetoothProperty::ClassOfDevice(u32_from_bytes(slice)) @@ -660,7 +718,8 @@ impl From for BluetoothProperty { BtDeviceType::from_u32(u32_from_bytes(slice)).unwrap_or(BtDeviceType::Unknown), ), BtPropertyType::ServiceRecord => { - let v = unsafe { *(prop.val as *const bindings::bt_service_record_t) }; + let v = + unsafe { (prop.val as *const bindings::bt_service_record_t).read_unaligned() }; BluetoothProperty::ServiceRecord(BtServiceRecord::from(v)) } BtPropertyType::AdapterScanMode => BluetoothProperty::AdapterScanMode( @@ -669,7 +728,7 @@ impl From for BluetoothProperty { BtPropertyType::AdapterBondedDevices => { let count = len / mem::size_of::(); BluetoothProperty::AdapterBondedDevices(ptr_to_vec( - prop.val as *mut RawAddress, + prop.val as *const RawAddress, count, )) } @@ -681,11 +740,11 @@ impl From for BluetoothProperty { } BtPropertyType::RemoteRssi => BluetoothProperty::RemoteRssi(slice[0] as i8), BtPropertyType::RemoteVersionInfo => { - let v = unsafe { *(prop.val as *const BtRemoteVersion) }; + let v = unsafe { (prop.val as *const BtRemoteVersion).read_unaligned() }; BluetoothProperty::RemoteVersionInfo(v.clone()) } BtPropertyType::LocalLeFeatures => { - let v = unsafe { *(prop.val as *const BtLocalLeFeatures) }; + let v = unsafe { (prop.val as *const BtLocalLeFeatures).read_unaligned() }; BluetoothProperty::LocalLeFeatures(v.clone()) } BtPropertyType::LocalIoCaps => BluetoothProperty::LocalIoCaps( @@ -699,10 +758,12 @@ impl From for BluetoothProperty { } BtPropertyType::Appearance => BluetoothProperty::Appearance(u16_from_bytes(slice)), BtPropertyType::VendorProductInfo => { - let v = unsafe { *(prop.val as *const BtVendorProductInfo) }; + let v = unsafe { (prop.val as *const BtVendorProductInfo).read_unaligned() }; BluetoothProperty::VendorProductInfo(BtVendorProductInfo::from(v)) } - + BtPropertyType::RemoteAddrType => BluetoothProperty::RemoteAddrType( + BtAddrType::from_u32(u32_from_bytes(slice)).unwrap_or(BtAddrType::Unknown), + ), // TODO(abps) - Figure out if these values should actually have contents BtPropertyType::DynamicAudioBuffer => BluetoothProperty::DynamicAudioBuffer(), BtPropertyType::RemoteDeviceTimestamp => BluetoothProperty::RemoteDeviceTimestamp(), @@ -882,8 +943,10 @@ pub enum BaseCallbacks { BtConnectionDirection, u16, ), + ThreadEvent(BtThreadEvent), // Unimplemented so far: - // thread_evt_cb + // dut_mode_recv_cb + // le_test_mode_cb // energy_info_cb // link_quality_report_cb // switch_buffer_size_cb @@ -941,6 +1004,8 @@ cb_variant!(BaseCb, le_address_associate_cb -> BaseCallbacks::LeAddressAssociate let _1 = unsafe { *(_1 as *const RawAddress) }; }); +cb_variant!(BaseCb, thread_evt_cb -> BaseCallbacks::ThreadEvent, u32 -> BtThreadEvent); + cb_variant!(BaseCb, acl_state_cb -> BaseCallbacks::AclState, u32 -> BtStatus, *mut RawAddress, bindings::bt_acl_state_t -> BtAclState, i32 -> BtTransport, bindings::bt_hci_error_code_t -> BtHciErrorCode, bindings::bt_conn_direction_t -> BtConnectionDirection, u16 -> u16, { let _1 = unsafe { *(_1 as *const RawAddress) }; @@ -1069,7 +1134,9 @@ impl BluetoothInterface { address_consolidate_cb: Some(address_consolidate_cb), le_address_associate_cb: Some(le_address_associate_cb), acl_state_changed_cb: Some(acl_state_cb), - thread_evt_cb: None, + thread_evt_cb: Some(thread_evt_cb), + dut_mode_recv_cb: None, + le_test_mode_cb: None, energy_info_cb: None, link_quality_report_cb: None, generate_local_oob_data_cb: Some(generate_local_oob_data_cb), @@ -1104,7 +1171,6 @@ impl BluetoothInterface { // gd/rust/linux/stack. let mut callouts = Box::new(bindings::bt_os_callouts_t { size: std::mem::size_of::(), - set_wake_alarm: None, // Not used acquire_wake_lock: Some(wake_lock_noop), release_wake_lock: Some(wake_lock_noop), }); @@ -1319,7 +1385,9 @@ pub fn get_btinterface() -> Option { // Turns C-array T[] to Vec. pub(crate) fn ptr_to_vec>(start: *const T, length: usize) -> Vec { - unsafe { (0..length).map(|i| U::from(*start.offset(i as isize))).collect::>() } + unsafe { + (0..length).map(|i| U::from(start.offset(i as isize).read_unaligned())).collect::>() + } } #[cfg(test)] diff --git a/system/gd/rust/topshim/src/profiles/a2dp.rs b/system/gd/rust/topshim/src/profiles/a2dp.rs index a95aedc16f4abb402f7c573d61048b8b5b8c55bf..9d78a89d7a08cb3334ecf9fda87a7f4f84807256 100644 --- a/system/gd/rust/topshim/src/profiles/a2dp.rs +++ b/system/gd/rust/topshim/src/profiles/a2dp.rs @@ -4,6 +4,7 @@ use crate::topstack::get_dispatchers; use bitflags::bitflags; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::cast::FromPrimitive; +use std::convert::{TryFrom, TryInto}; use std::sync::{Arc, Mutex}; use topshim_macros::{cb_variant, profile_enabled_or, profile_enabled_or_default}; @@ -38,8 +39,8 @@ impl From for BtavAudioState { } } -#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)] -#[repr(u32)] +#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] +#[repr(i32)] pub enum A2dpCodecIndex { SrcSbc = 0, SrcAac, @@ -67,7 +68,7 @@ impl From for A2dpCodecIndex { } } -#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)] +#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] #[repr(i32)] pub enum A2dpCodecPriority { Disabled = -1, @@ -113,6 +114,20 @@ impl A2dpCodecSampleRate { } } +impl TryInto for A2dpCodecSampleRate { + type Error = (); + fn try_into(self) -> Result { + Ok(self.bits()) + } +} + +impl TryFrom for A2dpCodecSampleRate { + type Error = (); + fn try_from(val: i32) -> Result { + Self::from_bits(val).ok_or(()) + } +} + bitflags! { pub struct A2dpCodecBitsPerSample: i32 { const SAMPLE_NONE = 0x0; @@ -128,6 +143,20 @@ impl A2dpCodecBitsPerSample { } } +impl TryInto for A2dpCodecBitsPerSample { + type Error = (); + fn try_into(self) -> Result { + Ok(self.bits()) + } +} + +impl TryFrom for A2dpCodecBitsPerSample { + type Error = (); + fn try_from(val: i32) -> Result { + Self::from_bits(val).ok_or(()) + } +} + bitflags! { pub struct A2dpCodecChannelMode: i32 { const MODE_NONE = 0x0; @@ -142,6 +171,20 @@ impl A2dpCodecChannelMode { } } +impl TryInto for A2dpCodecChannelMode { + type Error = (); + fn try_into(self) -> Result { + Ok(self.bits()) + } +} + +impl TryFrom for A2dpCodecChannelMode { + type Error = (); + fn try_from(val: i32) -> Result { + Self::from_bits(val).ok_or(()) + } +} + #[cxx::bridge(namespace = bluetooth::topshim::rust)] pub mod ffi { unsafe extern "C++" { @@ -364,10 +407,8 @@ impl A2dp { } #[profile_enabled_or] - pub fn set_audio_config(&self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32) { - let config = - A2dpCodecConfig { sample_rate, bits_per_sample, channel_mode, ..Default::default() }; - self.internal.set_audio_config(config); + pub fn config_codec(&self, addr: RawAddress, config: Vec) { + self.internal.config_codec(addr, config); } #[profile_enabled_or(false)] diff --git a/system/gd/rust/topshim/src/profiles/hfp.rs b/system/gd/rust/topshim/src/profiles/hfp.rs index 217e7b2f8c082a58b868718b49606635302abbc7..3017986aa125cba6092954b0c6834ea0f024bebb 100644 --- a/system/gd/rust/topshim/src/profiles/hfp.rs +++ b/system/gd/rust/topshim/src/profiles/hfp.rs @@ -10,6 +10,14 @@ use topshim_macros::{cb_variant, profile_enabled_or}; use log::warn; +#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)] +pub enum HfpCodecId { + NONE = 0x00, + CVSD = 0x01, + MSBC = 0x02, + LC3 = 0x03, +} + #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)] #[repr(u32)] pub enum BthfConnectionState { @@ -44,7 +52,7 @@ impl From for BthfAudioState { bitflags! { #[derive(Default)] pub struct HfpCodecCapability: i32 { - const UNSUPPORTED = 0b00; + const NONE = 0b00; const CVSD = 0b01; const MSBC = 0b10; const LC3 = 0b100; @@ -90,10 +98,24 @@ pub mod ffi { Held, // Only used by CLCC response } + #[derive(Debug, Copy, Clone)] + /* + When a SCO is created, it is necessary to have at least one call in the call list. + Otherwise, some headsets may not be able to output sound. + + Therefore, we need to separate the call for CRAS from the call for the application so that + we can have a correct life cycle for the call list status. + */ + pub enum CallSource { + CRAS, + HID, + } + #[derive(Debug, Clone)] pub struct CallInfo { index: i32, dir_incoming: bool, + source: CallSource, state: CallState, number: String, } @@ -121,17 +143,18 @@ pub mod ffi { type HfpIntf; unsafe fn GetHfpProfile(btif: *const u8) -> UniquePtr; - + unsafe fn interop_insert_call_when_sco_start(bt_addr: RawAddress) -> bool; fn init(self: Pin<&mut HfpIntf>) -> i32; fn connect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32; fn connect_audio( self: Pin<&mut HfpIntf>, bt_addr: RawAddress, sco_offload: bool, - force_cvsd: bool, + disabled_codecs: i32, ) -> i32; fn set_active_device(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32; fn set_volume(self: Pin<&mut HfpIntf>, volume: i8, bt_addr: RawAddress) -> i32; + fn set_mic_volume(self: Pin<&mut HfpIntf>, volume: i8, bt_addr: RawAddress) -> u32; fn disconnect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32; fn disconnect_audio(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32; fn device_status_notification( @@ -157,6 +180,7 @@ pub mod ffi { addr: RawAddress, ) -> u32; fn simple_at_response(self: Pin<&mut HfpIntf>, ok: bool, addr: RawAddress) -> u32; + fn debug_dump(self: Pin<&mut HfpIntf>); fn cleanup(self: Pin<&mut HfpIntf>); } @@ -164,6 +188,8 @@ pub mod ffi { fn hfp_connection_state_callback(state: u32, addr: RawAddress); fn hfp_audio_state_callback(state: u32, addr: RawAddress); fn hfp_volume_update_callback(volume: u8, addr: RawAddress); + fn hfp_mic_volume_update_callback(volume: u8, addr: RawAddress); + fn hfp_vendor_specific_at_command_callback(at_string: String, addr: RawAddress); fn hfp_battery_level_update_callback(battery_level: u8, addr: RawAddress); fn hfp_wbs_caps_update_callback(wbs_supported: bool, addr: RawAddress); fn hfp_swb_caps_update_callback(swb_supported: bool, addr: RawAddress); @@ -173,9 +199,24 @@ pub mod ffi { fn hfp_hangup_call_callback(addr: RawAddress); fn hfp_dial_call_callback(number: String, addr: RawAddress); fn hfp_call_hold_callback(chld: CallHoldCommand, addr: RawAddress); + fn hfp_debug_dump_callback( + active: bool, + codec_id: u16, + total_num_decoded_frames: i32, + pkt_loss_ratio: f64, + begin_ts: u64, + end_ts: u64, + pkt_status_in_hex: String, + pkt_status_in_binary: String, + ); } } +pub fn interop_insert_call_when_sco_start(bt_addr: RawAddress) -> bool { + //Call an unsafe function in c++. This is necessary for bridge C++ interop API with floss(rust). + unsafe { return ffi::interop_insert_call_when_sco_start(bt_addr) } +} + pub type TelephonyDeviceStatus = ffi::TelephonyDeviceStatus; impl TelephonyDeviceStatus { @@ -190,6 +231,7 @@ impl TelephonyDeviceStatus { } pub type CallState = ffi::CallState; +pub type CallSource = ffi::CallSource; pub type CallInfo = ffi::CallInfo; pub type PhoneState = ffi::PhoneState; pub type CallHoldCommand = ffi::CallHoldCommand; @@ -199,6 +241,8 @@ pub enum HfpCallbacks { ConnectionState(BthfConnectionState, RawAddress), AudioState(BthfAudioState, RawAddress), VolumeUpdate(u8, RawAddress), + MicVolumeUpdate(u8, RawAddress), + VendorSpecificAtCommand(String, RawAddress), BatteryLevelUpdate(u8, RawAddress), WbsCapsUpdate(bool, RawAddress), SwbCapsUpdate(bool, RawAddress), @@ -208,6 +252,7 @@ pub enum HfpCallbacks { HangupCall(RawAddress), DialCall(String, RawAddress), CallHold(CallHoldCommand, RawAddress), + DebugDump(bool, u16, i32, f64, u64, u64, String, String), } pub struct HfpCallbacksDispatcher { @@ -231,6 +276,16 @@ cb_variant!( hfp_volume_update_callback -> HfpCallbacks::VolumeUpdate, u8, RawAddress); +cb_variant!( + HfpCb, + hfp_mic_volume_update_callback -> HfpCallbacks::MicVolumeUpdate, + u8, RawAddress); + +cb_variant!( + HfpCb, + hfp_vendor_specific_at_command_callback -> HfpCallbacks::VendorSpecificAtCommand, + String, RawAddress); + cb_variant!( HfpCb, hfp_battery_level_update_callback -> HfpCallbacks::BatteryLevelUpdate, @@ -276,6 +331,11 @@ cb_variant!( hfp_call_hold_callback -> HfpCallbacks::CallHold, CallHoldCommand, RawAddress); +cb_variant!( + HfpCb, + hfp_debug_dump_callback -> HfpCallbacks::DebugDump, + bool, u16, i32, f64, u64, u64, String, String); + pub struct Hfp { internal: cxx::UniquePtr, _is_init: bool, @@ -332,8 +392,13 @@ impl Hfp { } #[profile_enabled_or(BtStatus::NotReady.into())] - pub fn connect_audio(&mut self, addr: RawAddress, sco_offload: bool, force_cvsd: bool) -> i32 { - self.internal.pin_mut().connect_audio(addr, sco_offload, force_cvsd) + pub fn connect_audio( + &mut self, + addr: RawAddress, + sco_offload: bool, + disabled_codecs: i32, + ) -> i32 { + self.internal.pin_mut().connect_audio(addr, sco_offload, disabled_codecs) } #[profile_enabled_or(BtStatus::NotReady.into())] @@ -346,6 +411,11 @@ impl Hfp { self.internal.pin_mut().set_volume(volume, addr) } + #[profile_enabled_or(BtStatus::NotReady.into())] + pub fn set_mic_volume(&mut self, volume: i8, addr: RawAddress) -> BtStatus { + BtStatus::from(self.internal.pin_mut().set_mic_volume(volume, addr)) + } + #[profile_enabled_or(BtStatus::NotReady)] pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus { BtStatus::from(self.internal.pin_mut().disconnect(addr)) @@ -403,6 +473,11 @@ impl Hfp { BtStatus::from(self.internal.pin_mut().simple_at_response(ok, addr)) } + #[profile_enabled_or] + pub fn debug_dump(&mut self) { + self.internal.pin_mut().debug_dump(); + } + #[profile_enabled_or(false)] pub fn cleanup(&mut self) -> bool { self.internal.pin_mut().cleanup(); diff --git a/system/gd/rust/topshim/src/profiles/hid_host.rs b/system/gd/rust/topshim/src/profiles/hid_host.rs index ce60d93354c75a4b5f08ff624821f716bd80a8f5..c77fa9b4754653351e2648e448bb3446f00ec8fa 100644 --- a/system/gd/rust/topshim/src/profiles/hid_host.rs +++ b/system/gd/rust/topshim/src/profiles/hid_host.rs @@ -306,25 +306,6 @@ impl HidHost { )) } - #[profile_enabled_or(BtStatus::NotReady)] - pub fn get_report_reply( - &self, - addr: &mut RawAddress, - status: BthhStatus, - report: &mut [u8], - size: u16, - ) -> BtStatus { - let addr_ptr = LTCheckedPtrMut::from_ref(addr); - BtStatus::from(ccall!( - self, - get_report_reply, - addr_ptr.into(), - status as bindings::bthh_status_t, - report.as_mut_ptr() as *mut std::os::raw::c_char, - size - )) - } - #[profile_enabled_or(BtStatus::NotReady)] pub fn set_report( &self, diff --git a/system/gd/rust/topshim/src/profiles/socket.rs b/system/gd/rust/topshim/src/profiles/socket.rs index 243b9de7c466a927b4efaa953fcff2cae071db33..eddbd0d3670b3b46f59f0bf599d17399f3a67064 100644 --- a/system/gd/rust/topshim/src/profiles/socket.rs +++ b/system/gd/rust/topshim/src/profiles/socket.rs @@ -248,6 +248,10 @@ impl BtSocket { ) .into() } + + pub fn disconnect_all(&self, addr: RawAddress) -> BtStatus { + ccall!(self, disconnect_all, &addr).into() + } } #[cfg(test)] diff --git a/system/gd/security/channel/security_manager_channel.cc b/system/gd/security/channel/security_manager_channel.cc index 94fa9370aeaff211fa74564ca9ade5b9f54a5778..a6a2c198cce4d17cf9083ea1f7a6172502600237 100644 --- a/system/gd/security/channel/security_manager_channel.cc +++ b/system/gd/security/channel/security_manager_channel.cc @@ -114,7 +114,8 @@ void SecurityManagerChannel::OnLinkDisconnected(hci::Address address) { listener_->OnConnectionClosed(address); } -void SecurityManagerChannel::OnAuthenticationComplete(hci::ErrorCode hci_status, hci::Address remote) { +void SecurityManagerChannel::OnAuthenticationComplete( + hci::ErrorCode /* hci_status */, hci::Address remote) { ASSERT_LOG(l2cap_security_interface_ != nullptr, "L2cap Security Interface is null!"); auto entry = link_map_.find(remote); if (entry != link_map_.end()) { @@ -123,8 +124,7 @@ void SecurityManagerChannel::OnAuthenticationComplete(hci::ErrorCode hci_status, } } -void SecurityManagerChannel::OnEncryptionChange(hci::Address remote, bool encrypted) { -} +void SecurityManagerChannel::OnEncryptionChange(hci::Address /* remote */, bool /* encrypted */) {} } // namespace channel } // namespace security diff --git a/system/gd/security/facade.cc b/system/gd/security/facade.cc index 19b303462c667e376423e92d00339b90a3facb39..101f606cd2a9f99f8646a252f2404d32da36330f 100644 --- a/system/gd/security/facade.cc +++ b/system/gd/security/facade.cc @@ -20,6 +20,7 @@ #include "hci/address_with_type.h" #include "hci/le_address_manager.h" #include "hci/le_advertising_manager.h" +#include "hci/octets.h" #include "l2cap/classic/security_policy.h" #include "l2cap/le/l2cap_le_module.h" #include "os/handler.h" @@ -82,7 +83,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, void OnL2capRegistrationCompleteLe( l2cap::le::FixedChannelManager::RegistrationResult result, - std::unique_ptr le_smp_service) { + std::unique_ptr /* le_smp_service */) { ASSERT_LOG( result == bluetooth::l2cap::le::FixedChannelManager::RegistrationResult::SUCCESS, "Failed to register to LE SMP Fixed Channel Service"); @@ -95,7 +96,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, &SecurityModuleFacadeService::OnConnectionClosedLe, common::Unretained(this), channel->GetDevice())); } - void OnConnectionClosedLe(hci::AddressWithType address, hci::ErrorCode error_code) { + void OnConnectionClosedLe(hci::AddressWithType address, hci::ErrorCode /* error_code */) { SecurityHelperMsg disconnected; *disconnected.mutable_peer() = ToFacadeAddressWithType(address); disconnected.set_message_type(HelperMsgType::DEVICE_DISCONNECTED); @@ -103,9 +104,9 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, } ::grpc::Status CreateBond( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddressWithType* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address().address(), peer)); hci::AddressType peer_type = static_cast(request->type()); @@ -114,7 +115,9 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, } ::grpc::Status CreateBondOutOfBand( - ::grpc::ServerContext* context, const OobDataBondMessage* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const OobDataBondMessage* request, + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address().address().address(), peer)); hci::AddressType peer_type = static_cast(request->address().type()); @@ -138,9 +141,9 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, } ::grpc::Status GetOutOfBandData( - ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, - ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, + ::google::protobuf::Empty* /* response */) override { security_module_->GetSecurityManager()->GetOutOfBandData( security_handler_->BindOnceOn(this, &SecurityModuleFacadeService::OobDataEventOccurred)); return ::grpc::Status::OK; @@ -148,15 +151,15 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, ::grpc::Status FetchGetOutOfBandDataEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return oob_events_.RunLoop(context, writer); } ::grpc::Status CreateBondLe( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddressWithType* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address().address(), peer)); hci::AddressType peer_type = static_cast(request->type()); @@ -165,9 +168,9 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, } ::grpc::Status CancelBond( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddressWithType* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address().address(), peer)); hci::AddressType peer_type = hci::AddressType::PUBLIC_DEVICE_ADDRESS; @@ -176,9 +179,9 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, } ::grpc::Status RemoveBond( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::BluetoothAddressWithType* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address().address(), peer)); hci::AddressType peer_type = hci::AddressType::PUBLIC_DEVICE_ADDRESS; @@ -186,13 +189,17 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, return ::grpc::Status::OK; } - ::grpc::Status FetchUiEvents(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* writer) override { + ::grpc::Status FetchUiEvents( + ::grpc::ServerContext* context, + const ::google::protobuf::Empty* /* request */, + ::grpc::ServerWriter* writer) override { return ui_events_.RunLoop(context, writer); } - ::grpc::Status SendUiCallback(::grpc::ServerContext* context, const UiCallbackMsg* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SendUiCallback( + ::grpc::ServerContext* /* context */, + const UiCallbackMsg* request, + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address().address().address(), peer)); hci::AddressType remote_type = static_cast(request->address().type()); @@ -223,27 +230,33 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, return ::grpc::Status::OK; } - ::grpc::Status FetchBondEvents(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* writer) override { + ::grpc::Status FetchBondEvents( + ::grpc::ServerContext* context, + const ::google::protobuf::Empty* /* request */, + ::grpc::ServerWriter* writer) override { return bond_events_.RunLoop(context, writer); } ::grpc::Status FetchHelperEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return helper_events_.RunLoop(context, writer); } ::grpc::Status FetchAdvertisingCallbackEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { le_advertising_manager_->RegisterAdvertisingCallback(this); return advertising_callback_events_.RunLoop(context, writer); } - void OnAdvertisingSetStarted(int reg_id, uint8_t advertiser_id, int8_t tx_power, AdvertisingStatus status) { + void OnAdvertisingSetStarted( + int /* reg_id */, + uint8_t advertiser_id, + int8_t /* tx_power */, + AdvertisingStatus /* status */) { AdvertisingCallbackMsg advertising_set_started; advertising_set_started.set_message_type(AdvertisingCallbackMsgType::ADVERTISING_SET_STARTED); advertising_set_started.set_advertising_started(AdvertisingSetStarted::STARTED); @@ -251,69 +264,74 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, advertising_callback_events_.OnIncomingEvent(advertising_set_started); } - void OnAdvertisingEnabled(uint8_t advertiser_id, bool enable, uint8_t status) { + void OnAdvertisingEnabled(uint8_t /* advertiser_id */, bool /* enable */, uint8_t /* status */) { // Not used yet } - void OnAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) { + void OnAdvertisingDataSet(uint8_t /* advertiser_id */, uint8_t /* status */) { // Not used yet } - void OnScanResponseDataSet(uint8_t advertiser_id, uint8_t status) { + void OnScanResponseDataSet(uint8_t /* advertiser_id */, uint8_t /* status */) { // Not used yet } - void OnAdvertisingParametersUpdated(uint8_t advertiser_id, int8_t tx_power, uint8_t status) { + void OnAdvertisingParametersUpdated( + uint8_t /* advertiser_id */, int8_t /* tx_power */, uint8_t /* status */) { // Not used yet } - void OnPeriodicAdvertisingParametersUpdated(uint8_t advertiser_id, uint8_t status) { + void OnPeriodicAdvertisingParametersUpdated(uint8_t /* advertiser_id */, uint8_t /* status */) { // Not used yet } - void OnPeriodicAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) { + void OnPeriodicAdvertisingDataSet(uint8_t /* advertiser_id */, uint8_t /* status */) { // Not used yet } - void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool enable, uint8_t status) { + void OnPeriodicAdvertisingEnabled( + uint8_t /* advertiser_id */, bool /* enable */, uint8_t /* status */) { // Not used yet } - void OnOwnAddressRead(uint8_t advertiser_id, uint8_t address_type, Address address) { + void OnOwnAddressRead(uint8_t /* advertiser_id */, uint8_t /* address_type */, Address address) { AdvertisingCallbackMsg get_own_address; get_own_address.set_message_type(AdvertisingCallbackMsgType::OWN_ADDRESS_READ); get_own_address.mutable_address()->set_address(address.ToString()); advertising_callback_events_.OnIncomingEvent(get_own_address); } - ::grpc::Status SetIoCapability(::grpc::ServerContext* context, const IoCapabilityMessage* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SetIoCapability( + ::grpc::ServerContext* /* context */, + const IoCapabilityMessage* request, + ::google::protobuf::Empty* /* response */) override { security_module_->GetFacadeConfigurationApi()->SetIoCapability( static_cast(request->capability())); return ::grpc::Status::OK; } ::grpc::Status SetLeIoCapability( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const LeIoCapabilityMessage* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { security_module_->GetFacadeConfigurationApi()->SetLeIoCapability( static_cast(request->capabilities())); return ::grpc::Status::OK; } - ::grpc::Status SetAuthenticationRequirements(::grpc::ServerContext* context, - const AuthenticationRequirementsMessage* request, - ::google::protobuf::Empty* response) override { + ::grpc::Status SetAuthenticationRequirements( + ::grpc::ServerContext* /* context */, + const AuthenticationRequirementsMessage* request, + ::google::protobuf::Empty* /* response */) override { security_module_->GetFacadeConfigurationApi()->SetAuthenticationRequirements( static_cast(request->requirement())); return ::grpc::Status::OK; } ::grpc::Status SetLeAuthRequirements( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const LeAuthRequirementsMessage* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { uint8_t auth_req = request->bond() ? AUTH_REQ_BOND : AUTH_REQ_NO_BOND; if (request->mitm()) auth_req |= AUTH_REQ_MITM_MASK; @@ -327,27 +345,27 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, } ::grpc::Status SetLeMaximumEncryptionKeySize( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const LeMaximumEncryptionKeySizeMessage* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { security_module_->GetFacadeConfigurationApi()->SetLeMaximumEncryptionKeySize( request->maximum_encryption_key_size()); return ::grpc::Status::OK; } ::grpc::Status SetLeOobDataPresent( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const LeOobDataPresentMessage* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { security_module_->GetFacadeConfigurationApi()->SetLeOobDataPresent( static_cast(request->data_present())); return ::grpc::Status::OK; } ::grpc::Status SetLeInitiatorAddressPolicy( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const blueberry::facade::hci::PrivacyPolicy* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { Address address = Address::kEmpty; hci::LeAddressManager::AddressPolicy address_policy = static_cast(request->address_policy()); @@ -356,11 +374,11 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, ASSERT(Address::FromString(request->address_with_type().address().address(), address)); } hci::AddressWithType address_with_type(address, static_cast(request->address_with_type().type())); - crypto_toolbox::Octet16 irk = {}; + hci::Octet16 irk = {}; auto request_irk_length = request->rotation_irk().end() - request->rotation_irk().begin(); - if (request_irk_length == crypto_toolbox::OCTET16_LEN) { + if (request_irk_length == hci::kOctet16Length) { std::vector irk_data(request->rotation_irk().begin(), request->rotation_irk().end()); - std::copy_n(irk_data.begin(), crypto_toolbox::OCTET16_LEN, irk.begin()); + std::copy_n(irk_data.begin(), hci::kOctet16Length, irk.begin()); } else { ASSERT(request_irk_length == 0); } @@ -373,15 +391,15 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, ::grpc::Status FetchEnforceSecurityPolicyEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { return enforce_security_policy_events_.RunLoop(context, writer); } ::grpc::Status EnforceSecurityPolicy( - ::grpc::ServerContext* context, + ::grpc::ServerContext* /* context */, const SecurityPolicyMessage* request, - ::google::protobuf::Empty* response) override { + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address().address().address(), peer)); hci::AddressType peer_type = static_cast(request->address().type()); @@ -394,7 +412,9 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, } ::grpc::Status GetLeOutOfBandData( - ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, OobDataMessage* response) override { + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, + OobDataMessage* response) override { std::array le_sc_c; std::array le_sc_r; security_module_->GetFacadeConfigurationApi()->GetLeOutOfBandData(&le_sc_c, &le_sc_r); @@ -411,7 +431,9 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, } ::grpc::Status SetOutOfBandData( - ::grpc::ServerContext* context, const OobDataMessage* request, ::google::protobuf::Empty* response) override { + ::grpc::ServerContext* /* context */, + const OobDataMessage* request, + ::google::protobuf::Empty* /* response */) override { hci::Address peer; ASSERT(hci::Address::FromString(request->address().address().address(), peer)); hci::AddressType peer_type = static_cast(request->address().type()); @@ -433,7 +455,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, ::grpc::Status FetchDisconnectEvents( ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, + const ::google::protobuf::Empty* /* request */, ::grpc::ServerWriter* writer) override { security_module_->GetFacadeConfigurationApi()->SetDisconnectCallback( common::Bind(&SecurityModuleFacadeService::DisconnectEventOccurred, common::Unretained(this))); @@ -480,7 +502,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, disconnect_events_.OnIncomingEvent(msg); } - void DisplayPairingPrompt(const bluetooth::hci::AddressWithType& peer, std::string name) { + void DisplayPairingPrompt(const bluetooth::hci::AddressWithType& peer, std::string /* name */) { LOG_INFO("%s", ADDRESS_TO_LOGGABLE_CSTR(peer)); UiMsg display_yes_no; *display_yes_no.mutable_peer() = ToFacadeAddressWithType(peer); @@ -565,7 +587,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, bond_events_.OnIncomingEvent(bonded); } - void OnEncryptionStateChanged(hci::EncryptionChangeView encryption_change_view) override {} + void OnEncryptionStateChanged(hci::EncryptionChangeView /* encryption_change_view */) override {} void OnDeviceUnbonded(hci::AddressWithType peer) override { LOG_INFO("%s", ADDRESS_TO_LOGGABLE_CSTR(peer)); diff --git a/system/gd/security/initial_informations.h b/system/gd/security/initial_informations.h index c5982bd110706bb0201a4e1704be64ffa3c469f3..65540a52e5ef75e1ea9f6d7402df5d740340918a 100644 --- a/system/gd/security/initial_informations.h +++ b/system/gd/security/initial_informations.h @@ -21,14 +21,10 @@ #include #include -#include "common/bidi_queue.h" -#include "common/callback.h" -#include "crypto_toolbox/crypto_toolbox.h" #include "hci/address_with_type.h" #include "hci/le_security_interface.h" #include "os/handler.h" -#include "packet/base_packet_builder.h" -#include "packet/packet_view.h" +#include "os/queue.h" #include "security/ecdh_keys.h" #include "security/pairing_failure.h" #include "security/smp_packets.h" @@ -39,18 +35,18 @@ namespace security { struct DistributedKeys { /* LE Keys*/ - std::optional remote_ltk; + std::optional remote_ltk; std::optional remote_ediv; std::optional> remote_rand; std::optional remote_identity_address; - std::optional remote_irk; - std::optional remote_signature_key; - std::optional remote_link_key; /* BR/EDR Keys */ + std::optional remote_irk; + std::optional remote_signature_key; + std::optional remote_link_key; /* BR/EDR Keys */ - std::optional local_ltk; + std::optional local_ltk; std::optional local_ediv; std::optional> local_rand; - std::optional local_signature_key; + std::optional local_signature_key; }; /* This class represents the result of pairing, as returned from Pairing Handler */ @@ -70,8 +66,8 @@ struct MyOobData { * layers though */ std::array private_key; EcdhPublicKey public_key; - crypto_toolbox::Octet16 c; - crypto_toolbox::Octet16 r; + hci::Octet16 c; + hci::Octet16 r; }; /* This structure is filled and send to PairingHandlerLe to initiate the Pairing process with remote device */ @@ -80,7 +76,7 @@ struct InitialInformations { hci::AddressWithType my_connection_address; hci::AddressWithType my_identity_address; - crypto_toolbox::Octet16 my_identity_resolving_key; + hci::Octet16 my_identity_resolving_key; /* My capabilities, as in pairing request/response */ struct { @@ -102,10 +98,10 @@ struct InitialInformations { std::optional pairing_request; struct out_of_band_data { - crypto_toolbox::Octet16 le_sc_c; /* LE Secure Connections Confirmation Value */ - crypto_toolbox::Octet16 le_sc_r; /* LE Secure Connections Random Value */ + hci::Octet16 le_sc_c; /* LE Secure Connections Confirmation Value */ + hci::Octet16 le_sc_r; /* LE Secure Connections Random Value */ - crypto_toolbox::Octet16 security_manager_tk_value; /* OOB data for LE Legacy Pairing */ + hci::Octet16 security_manager_tk_value; /* OOB data for LE Legacy Pairing */ }; // If we received OOB data from remote device, this field contains it. diff --git a/system/gd/security/internal/security_manager_impl.cc b/system/gd/security/internal/security_manager_impl.cc index 565b25e4907d0e86478d55a5f4b2b8c30328c58e..74bd54d1c4541af552291abbdf47546252b521b2 100644 --- a/system/gd/security/internal/security_manager_impl.cc +++ b/system/gd/security/internal/security_manager_impl.cc @@ -17,17 +17,14 @@ */ #include "security_manager_impl.h" -#include - #include "common/bind.h" -#include "crypto_toolbox/crypto_toolbox.h" #include "hci/address_with_type.h" +#include "hci/octets.h" #include "os/log.h" #include "os/rand.h" #include "security/initial_informations.h" #include "security/internal/security_manager_impl.h" #include "security/pairing_handler_le.h" -#include "security/security_manager.h" #include "security/ui.h" namespace bluetooth { @@ -194,7 +191,7 @@ void SecurityManagerImpl::SetUserInterfaceHandler(UI* user_interface, os::Handle void SecurityManagerImpl::SetLeInitiatorAddressPolicyForTest( hci::LeAddressManager::AddressPolicy address_policy, hci::AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + hci::Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { acl_manager_->SetPrivacyPolicyForInitiatorAddressForTest( @@ -452,9 +449,10 @@ void SecurityManagerImpl::OnPairingHandlerComplete(hci::Address address, Pairing void SecurityManagerImpl::OnL2capRegistrationCompleteLe( l2cap::le::FixedChannelManager::RegistrationResult result, - std::unique_ptr le_smp_service) { - ASSERT_LOG(result == bluetooth::l2cap::le::FixedChannelManager::RegistrationResult::SUCCESS, - "Failed to register to LE SMP Fixed Channel Service"); + [[maybe_unused]] std::unique_ptr le_smp_service) { + ASSERT_LOG( + result == bluetooth::l2cap::le::FixedChannelManager::RegistrationResult::SUCCESS, + "Failed to register to LE SMP Fixed Channel Service"); } LeFixedChannelEntry* SecurityManagerImpl::FindStoredLeChannel(const hci::AddressWithType& device) { @@ -636,7 +634,8 @@ void SecurityManagerImpl::ConnectionIsReadyStartPairing(LeFixedChannelEntry* sto pending_le_pairing_.handler_ = std::make_unique(PairingHandlerLe::PHASE1, initial_informations); } -void SecurityManagerImpl::OnConnectionClosedLe(hci::AddressWithType address, hci::ErrorCode error_code) { +void SecurityManagerImpl::OnConnectionClosedLe( + hci::AddressWithType address, hci::ErrorCode /* error_code */) { if (pending_le_pairing_.address_ != address) { LeFixedChannelEntry* stored_chan = FindStoredLeChannel(address); if (!stored_chan) { @@ -866,7 +865,8 @@ void SecurityManagerImpl::EnforceSecurityPolicy( } void SecurityManagerImpl::EnforceLeSecurityPolicy( - hci::AddressWithType remote, l2cap::le::SecurityPolicy policy, + hci::AddressWithType /* remote */, + l2cap::le::SecurityPolicy policy, l2cap::le::SecurityEnforcementInterface::ResultCallback result_callback) { bool result = false; // TODO(jpawlowski): Implement for LE diff --git a/system/gd/security/internal/security_manager_impl.h b/system/gd/security/internal/security_manager_impl.h index 7181dfec166e3c901529e4dab9a5663a6a076329..cf9f7759ea310c66e568e732e9a97a857c75d5c7 100644 --- a/system/gd/security/internal/security_manager_impl.h +++ b/system/gd/security/internal/security_manager_impl.h @@ -17,11 +17,13 @@ #pragma once #include + #include #include #include "hci/acl_manager.h" #include "hci/controller.h" +#include "hci/octets.h" #include "l2cap/classic/security_enforcement_interface.h" #include "l2cap/le/l2cap_le_module.h" #include "l2cap/le/security_enforcement_interface.h" @@ -139,7 +141,7 @@ class SecurityManagerImpl : public channel::ISecurityManagerChannelListener, pub void SetLeInitiatorAddressPolicyForTest( hci::LeAddressManager::AddressPolicy address_policy, hci::AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + hci::Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time); @@ -266,11 +268,11 @@ class SecurityManagerImpl : public channel::ISecurityManagerChannelListener, pub OobDataFlag local_le_oob_data_present_ = OobDataFlag::NOT_PRESENT; std::optional local_le_oob_data_; std::optional remote_oob_data_address_; - std::optional remote_oob_data_le_sc_c_; - std::optional remote_oob_data_le_sc_r_; + std::optional remote_oob_data_le_sc_c_; + std::optional remote_oob_data_le_sc_r_; std::optional facade_disconnect_callback_; hci::AddressWithType local_identity_address_; - crypto_toolbox::Octet16 local_identity_resolving_key_; + hci::Octet16 local_identity_resolving_key_; struct PendingSecurityEnforcementEntry { l2cap::classic::SecurityPolicy policy_; diff --git a/system/gd/security/pairing/classic_pairing_handler.cc b/system/gd/security/pairing/classic_pairing_handler.cc index 82ac61a9e202df07b7f58cb2cdb6252e12e2fdf3..5db5f634c683f1453c814713960b368b9dca70da 100644 --- a/system/gd/security/pairing/classic_pairing_handler.cc +++ b/system/gd/security/pairing/classic_pairing_handler.cc @@ -73,12 +73,14 @@ void ClassicPairingHandler::NotifyUiDisplayCancel() { user_interface_handler_->CallOn(user_interface_, &UI::Cancel, *GetRecord()->GetPseudoAddress()); } -void ClassicPairingHandler::OnPairingPromptAccepted(const bluetooth::hci::AddressWithType& address, bool confirmed) { +void ClassicPairingHandler::OnPairingPromptAccepted( + const bluetooth::hci::AddressWithType& /* address */, bool /* confirmed */) { // NOTE: This is not used by Classic, only by LE LOG_ALWAYS_FATAL("This is not supported by Classic Pairing Handler, only LE"); } -void ClassicPairingHandler::OnConfirmYesNo(const bluetooth::hci::AddressWithType& address, bool confirmed) { +void ClassicPairingHandler::OnConfirmYesNo( + const bluetooth::hci::AddressWithType& /* address */, bool confirmed) { if (confirmed) { GetChannel()->SendCommand( hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress())); @@ -132,7 +134,7 @@ void ClassicPairingHandler::Initiate( } } -void ClassicPairingHandler::OnNameRequestComplete(hci::Address address, bool success) { +void ClassicPairingHandler::OnNameRequestComplete(hci::Address address, bool /* success */) { if (GetNameDbModule()->IsNameCached(address)) { auto remote_name = GetNameDbModule()->ReadCachedRemoteName(address); std::string tmp_name; diff --git a/system/gd/security/pairing_handler_le.cc b/system/gd/security/pairing_handler_le.cc index 556de53c33cad9e84f5ff1170cd9b0261fc2b9a7..fc980ce91e52fb73f8b787814dd4fa2d49ae8408 100644 --- a/system/gd/security/pairing_handler_le.cc +++ b/system/gd/security/pairing_handler_le.cc @@ -18,11 +18,14 @@ #include "security/pairing_handler_le.h" +#include "hci/octets.h" #include "os/rand.h" namespace bluetooth { namespace security { +using hci::Octet16; + MyOobData PairingHandlerLe::GenerateOobData() { MyOobData data{}; std::tie(data.private_key, data.public_key) = GenerateECDHKeyPair(); diff --git a/system/gd/security/pairing_handler_le.h b/system/gd/security/pairing_handler_le.h index ed29316250f43b057ce137ac08f1e8899c8e9900..23f485225dc99273aa177c37609f73dd2e072bcf 100644 --- a/system/gd/security/pairing_handler_le.h +++ b/system/gd/security/pairing_handler_le.h @@ -27,16 +27,12 @@ #include #include -#include "common/bind.h" -#include "crypto_toolbox/crypto_toolbox.h" #include "hci/hci_packets.h" #include "hci/le_security_interface.h" -#include "packet/packet_view.h" #include "security/ecdh_keys.h" #include "security/initial_informations.h" #include "security/pairing_failure.h" #include "security/smp_packets.h" -#include "security/ui.h" // Code generated by PDL does not allow us ot do || and && operations on bits // efficiently. Use those masks on fields requiring them until this is solved @@ -57,8 +53,6 @@ using bluetooth::hci::EncryptionKeyRefreshCompleteView; namespace bluetooth { namespace security { -using crypto_toolbox::Octet16; - /* This class represents an event send from other subsystems into SMP Pairing Handler, * i.e. user request from the UI, L2CAP or HCI interaction */ class PairingEvent { @@ -87,14 +81,14 @@ using Phase1Result = std::pair; using KeyExchangeResult = std::tuple /*dhkey*/>; -using Stage1Result = std::tuple; +using Stage1Result = std::tuple; using Stage1ResultOrFailure = std::variant; -using Stage2ResultOrFailure = std::variant; +using Stage2ResultOrFailure = std::variant; using DistributedKeysOrFailure = std::variant; -using LegacyStage1Result = Octet16 /*TK*/; +using LegacyStage1Result = hci::Octet16 /*TK*/; using LegacyStage1ResultOrFailure = std::variant; -using StkOrFailure = std::variant; +using StkOrFailure = std::variant; /* PairingHandlerLe takes care of the Pairing process. Pairing is strictly defined * exchange of messages and UI interactions, divided into PHASES. @@ -133,8 +127,12 @@ class PairingHandlerLe { i.proper_l2cap_interface->Enqueue(std::move(command), i.l2cap_handler); } - void SendHciLeStartEncryption(const InitialInformations& i, uint16_t conn_handle, const std::array& rand, - const uint16_t& ediv, const Octet16& ltk) { + void SendHciLeStartEncryption( + const InitialInformations& i, + uint16_t conn_handle, + const std::array& rand, + const uint16_t& ediv, + const hci::Octet16& ltk) { i.le_security_interface->EnqueueCommand(hci::LeStartEncryptionBuilder::Create(conn_handle, rand, ediv, ltk), i.l2cap_handler->BindOnce([](hci::CommandStatusView) { // TODO: handle command status. It's important - can show we are not @@ -145,7 +143,8 @@ class PairingHandlerLe { })); } - void SendHciLeLongTermKeyReply(const InitialInformations& i, uint16_t conn_handle, const Octet16& ltk) { + void SendHciLeLongTermKeyReply( + const InitialInformations& i, uint16_t conn_handle, const hci::Octet16& ltk) { i.le_security_interface->EnqueueCommand( hci::LeLongTermKeyRequestReplyBuilder::Create(conn_handle, ltk), i.l2cap_handler->BindOnce([](hci::CommandCompleteView) {})); @@ -247,12 +246,22 @@ class PairingHandlerLe { LegacyStage1ResultOrFailure LegacyJustWorks(); LegacyStage1ResultOrFailure LegacyPasskeyEntry(const InitialInformations& i, const IoCapability& my_iocaps, const IoCapability& remote_iocaps); - StkOrFailure DoLegacyStage2(const InitialInformations& i, const PairingRequestView& pairing_request, - const PairingResponseView& pairing_response, const Octet16& tk); - - void SendKeys(const InitialInformations& i, const uint8_t& keys_i_send, Octet16 ltk, uint16_t ediv, - std::array rand, Octet16 irk, Address identity_address, AddrType identity_addres_type, - Octet16 signature_key); + StkOrFailure DoLegacyStage2( + const InitialInformations& i, + const PairingRequestView& pairing_request, + const PairingResponseView& pairing_response, + const hci::Octet16& tk); + + void SendKeys( + const InitialInformations& i, + const uint8_t& keys_i_send, + hci::Octet16 ltk, + uint16_t ediv, + std::array rand, + hci::Octet16 irk, + Address identity_address, + AddrType identity_addres_type, + hci::Octet16 signature_key); /* This can be called from any thread to immediately finish the pairing in progress. */ void SendExitSignal() { diff --git a/system/gd/security/pairing_handler_le_legacy.cc b/system/gd/security/pairing_handler_le_legacy.cc index b5e8d88961a88c542d90a4b2a0047cd16f30bf10..bc0591024de46e27780ccb371131e76a22520ae8 100644 --- a/system/gd/security/pairing_handler_le_legacy.cc +++ b/system/gd/security/pairing_handler_le_legacy.cc @@ -16,17 +16,19 @@ * ******************************************************************************/ -#include "security/pairing_handler_le.h" +#include +#include "hci/octets.h" #include "os/rand.h" - -#include +#include "security/pairing_handler_le.h" using bluetooth::os::GenerateRandom; namespace bluetooth { namespace security { +using hci::Octet16; + LegacyStage1ResultOrFailure PairingHandlerLe::DoLegacyStage1(const InitialInformations& i, const PairingRequestView& pairing_request, const PairingResponseView& pairing_response) { diff --git a/system/gd/security/pairing_handler_le_secure_connections.cc b/system/gd/security/pairing_handler_le_secure_connections.cc index 3c774c33b76a98e92fc7920571fd6ff0c3d4934d..28345e4699877a177e6a5a7d0c68eb8313bd3136 100644 --- a/system/gd/security/pairing_handler_le_secure_connections.cc +++ b/system/gd/security/pairing_handler_le_secure_connections.cc @@ -16,16 +16,18 @@ * ******************************************************************************/ -#include "security/pairing_handler_le.h" +#include +#include "crypto_toolbox/crypto_toolbox.h" +#include "hci/octets.h" #include "os/rand.h" - -#include +#include "security/pairing_handler_le.h" using bluetooth::os::GenerateRandom; namespace bluetooth { namespace security { +using hci::Octet16; std::variant PairingHandlerLe::ExchangePublicKeys(const InitialInformations& i, OobDataFlag remote_have_oob_data) { @@ -131,12 +133,14 @@ Stage1ResultOrFailure PairingHandlerLe::DoSecureConnectionsStage1(const InitialI return SecureConnectionsPasskeyEntry(i, PKa, PKb, my_iocaps, remote_iocaps); } -Stage2ResultOrFailure PairingHandlerLe::DoSecureConnectionsStage2(const InitialInformations& i, - const EcdhPublicKey& PKa, const EcdhPublicKey& PKb, - const PairingRequestView& pairing_request, - const PairingResponseView& pairing_response, - const Stage1Result stage1result, - const std::array& dhkey) { +Stage2ResultOrFailure PairingHandlerLe::DoSecureConnectionsStage2( + const InitialInformations& i, + const EcdhPublicKey& /* PKa */, + const EcdhPublicKey& /* PKb */, + const PairingRequestView& pairing_request, + const PairingResponseView& pairing_response, + const Stage1Result stage1result, + const std::array& dhkey) { LOG_INFO("Authentication stage 2 started"); auto [Na, Nb, ra, rb] = stage1result; diff --git a/system/gd/security/record/security_record.h b/system/gd/security/record/security_record.h index 1de9f8f134c121ef5cb775485949e7102840d015..7b1783eda251971f9fb60ce9e408c134aa9b2bd0 100644 --- a/system/gd/security/record/security_record.h +++ b/system/gd/security/record/security_record.h @@ -18,12 +18,8 @@ #pragma once -#include -#include -#include - -#include "crypto_toolbox/crypto_toolbox.h" #include "hci/address_with_type.h" +#include "hci/octets.h" #include "storage/device.h" namespace bluetooth { @@ -126,15 +122,15 @@ class SecurityRecord { /* Identity Address */ std::optional identity_address_; - std::optional remote_ltk; + std::optional remote_ltk; uint8_t key_size; uint8_t security_level; std::optional remote_ediv; std::optional> remote_rand; - std::optional remote_irk; - std::optional remote_signature_key; + std::optional remote_irk; + std::optional remote_signature_key; - std::optional local_ltk; + std::optional local_ltk; std::optional local_ediv; std::optional> local_rand; }; diff --git a/system/gd/security/record/security_record_storage.cc b/system/gd/security/record/security_record_storage.cc index 021759dcca36eef135b4fe645f3a24743185ef98..8b452e4724699bbd55eb064f45f49ac0e347b90a 100644 --- a/system/gd/security/record/security_record_storage.cc +++ b/system/gd/security/record/security_record_storage.cc @@ -91,7 +91,10 @@ void SetLeData(storage::Mutation& mutation, std::shared_ptr record, storage::Device& device) { +void SetAuthenticationData( + storage::Mutation& /* mutation */, + std::shared_ptr record, + storage::Device& device) { device.SetIsAuthenticated((record->IsAuthenticated() ? 1 : 0)); device.SetIsEncryptionRequired((record->IsEncryptionRequired() ? 1 : 0)); device.SetRequiresMitmProtection(record->RequiresMitmProtection() ? 1 : 0); diff --git a/system/gd/security/record/security_record_storage_test.cc b/system/gd/security/record/security_record_storage_test.cc index bd1b748dcc79dfd0b299c1901ba5bad58ffd4dd4..5b2d6fdf81b243faf4b19f2a873c7943d620c26e 100644 --- a/system/gd/security/record/security_record_storage_test.cc +++ b/system/gd/security/record/security_record_storage_test.cc @@ -18,21 +18,26 @@ #include -#include "security/test/fake_storage_module.h" +#include "storage/storage_module.h" namespace bluetooth { namespace security { namespace record { namespace { +static const std::chrono::milliseconds kTestConfigSaveDelay = std::chrono::milliseconds(100); + +using storage::StorageModule; + class DISABLED_SecurityRecordStorageTest : public ::testing::Test { protected: void SetUp() override { - // Make Fake storage module - storage_module_ = new FakeStorageModule(); + // Make storage module + storage_module_ = + new StorageModule("/tmp/temp_config.txt", kTestConfigSaveDelay, 100, false, false); // Inject - fake_registry_.InjectTestModule(&storage::StorageModule::Factory, storage_module_); + fake_registry_.InjectTestModule(&StorageModule::Factory, storage_module_); // Make storage record_storage_ = new record::SecurityRecordStorage(storage_module_, handler_); @@ -45,13 +50,13 @@ class DISABLED_SecurityRecordStorageTest : public ::testing::Test { } void synchronize() { - fake_registry_.SynchronizeModuleHandler(&FakeStorageModule::Factory, std::chrono::milliseconds(20)); + fake_registry_.SynchronizeModuleHandler(&StorageModule::Factory, std::chrono::milliseconds(20)); } TestModuleRegistry fake_registry_; os::Thread& thread_ = fake_registry_.GetTestThread(); os::Handler* handler_ = nullptr; - FakeStorageModule* storage_module_; + StorageModule* storage_module_; record::SecurityRecordStorage* record_storage_; }; diff --git a/system/gd/security/security_manager.cc b/system/gd/security/security_manager.cc index 9e711aed0674d76609c837eea8e14d76e867314c..cb857608411bb34aba81e15b86f49faa923ba931 100644 --- a/system/gd/security/security_manager.cc +++ b/system/gd/security/security_manager.cc @@ -17,6 +17,7 @@ */ #include "security_manager.h" +#include "hci/octets.h" #include "os/log.h" namespace bluetooth { @@ -80,7 +81,7 @@ void SecurityManager::SetUserInterfaceHandler(UI* user_interface, os::Handler* h void SecurityManager::SetLeInitiatorAddressPolicyForTest( hci::LeAddressManager::AddressPolicy address_policy, hci::AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + hci::Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { security_handler_->Post(common::BindOnce( diff --git a/system/gd/security/security_manager.h b/system/gd/security/security_manager.h index 184276118753649f725c57a9459ee4cca9a28dba..1c7b49a9e58a5f4084463e971e44f091768f30f2 100644 --- a/system/gd/security/security_manager.h +++ b/system/gd/security/security_manager.h @@ -106,7 +106,7 @@ class SecurityManager : public UICallbacks { void SetLeInitiatorAddressPolicyForTest( hci::LeAddressManager::AddressPolicy address_policy, hci::AddressWithType fixed_address, - crypto_toolbox::Octet16 rotation_irk, + hci::Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time); diff --git a/system/gd/security/test/fake_storage_module.h b/system/gd/security/test/fake_storage_module.h deleted file mode 100644 index cf66a4bec78ba919cafa96142f61ec05fcf39bc3..0000000000000000000000000000000000000000 --- a/system/gd/security/test/fake_storage_module.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include "storage/storage_module.h" - -#include - -namespace bluetooth { -namespace security { - -static const std::chrono::milliseconds kTestConfigSaveDelay = std::chrono::milliseconds(100); - -class FakeStorageModule : public storage::StorageModule { - public: - FakeStorageModule() : storage::StorageModule("/tmp/temp_config.txt", kTestConfigSaveDelay, 100, false, false) {} - - storage::ConfigCache* GetConfigCachePublic() { - return StorageModule::GetConfigCache(); - } - - void SaveImmediatelyPublic() { - StorageModule::SaveImmediately(); - } -}; - -} // namespace security -} // namespace bluetooth diff --git a/system/gd/security/test/pairing_handler_le_pair_test.cc b/system/gd/security/test/pairing_handler_le_pair_test.cc index 2847a48b06320d13476de189824f81c76cb286ca..98a9f572f66459690b6c32c7ac8938bdf036b54c 100644 --- a/system/gd/security/test/pairing_handler_le_pair_test.cc +++ b/system/gd/security/test/pairing_handler_le_pair_test.cc @@ -23,6 +23,7 @@ #include "common/testing/wired_pair_of_bidi_queues.h" #include "hci/le_security_interface.h" +#include "hci/octets.h" #include "packet/raw_builder.h" #include "security/pairing_handler_le.h" #include "security/test/mocks.h" @@ -87,14 +88,14 @@ Address ADDRESS_CENTRAL{{0x26, 0x64, 0x76, 0x86, 0xab, 0xba}}; AddressType ADDRESS_TYPE_CENTRAL = AddressType::RANDOM_DEVICE_ADDRESS; Address IDENTITY_ADDRESS_CENTRAL{{0x12, 0x34, 0x56, 0x78, 0x90, 0xaa}}; AddressType IDENTITY_ADDRESS_TYPE_CENTRAL = AddressType::PUBLIC_DEVICE_ADDRESS; -crypto_toolbox::Octet16 IRK_CENTRAL = { +hci::Octet16 IRK_CENTRAL = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; Address ADDRESS_PERIPHERAL{{0x33, 0x58, 0x24, 0x76, 0x11, 0x89}}; AddressType ADDRESS_TYPE_PERIPHERAL = AddressType::RANDOM_DEVICE_ADDRESS; Address IDENTITY_ADDRESS_PERIPHERAL{{0x21, 0x43, 0x65, 0x87, 0x09, 0x44}}; AddressType IDENTITY_ADDRESS_TYPE_PERIPHERAL = AddressType::PUBLIC_DEVICE_ADDRESS; -crypto_toolbox::Octet16 IRK_PERIPHERAL = { +hci::Octet16 IRK_PERIPHERAL = { 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; std::optional pairing_result_central; diff --git a/system/gd/shim/dumpsys.cc b/system/gd/shim/dumpsys.cc index 92dcb986b194841551b65d5aa59787cccee0c4e5..4813a7545790275024b979ae529ce6dc8c4ee8e6 100644 --- a/system/gd/shim/dumpsys.cc +++ b/system/gd/shim/dumpsys.cc @@ -21,7 +21,9 @@ #include #include "dumpsys/filter.h" +#include "dumpsys_data_generated.h" #include "module.h" +#include "module_dumper.h" #include "os/log.h" #include "os/system_properties.h" #include "shim/dumpsys.h" @@ -113,7 +115,19 @@ std::string Dumpsys::impl::PrintAsJson(std::string* dumpsys_data) const { } std::string jsongen; + // GenerateText was renamed to GenText in 23.5.26 because the return behavior was changed. + // https://github.com/google/flatbuffers/commit/950a71ab893e96147c30dd91735af6db73f72ae0 +#if FLATBUFFERS_VERSION_MAJOR < 23 || \ + (FLATBUFFERS_VERSION_MAJOR == 23 && \ + (FLATBUFFERS_VERSION_MINOR < 5 || \ + (FLATBUFFERS_VERSION_MINOR == 5 && FLATBUFFERS_VERSION_REVISION < 26))) flatbuffers::GenerateText(parser, dumpsys_data->data(), &jsongen); +#else + const char* error = flatbuffers::GenText(parser, dumpsys_data->data(), &jsongen); + if (error != nullptr) { + LOG_WARN("%s", error); + } +#endif return jsongen; } @@ -164,7 +178,7 @@ os::Handler* Dumpsys::GetGdShimHandler() { /** * Module methods */ -void Dumpsys::ListDependencies(ModuleList* list) const {} +void Dumpsys::ListDependencies(ModuleList* /* list */) const {} void Dumpsys::Start() { pimpl_ = std::make_unique(*this, reflection_schema_); diff --git a/system/gd/shim/facade/facade.cc b/system/gd/shim/facade/facade.cc index de1466495d631454120ccb0940db8bc3fcc0d939..15d95148f1af2efd1c57933572336b93cc043864 100644 --- a/system/gd/shim/facade/facade.cc +++ b/system/gd/shim/facade/facade.cc @@ -45,9 +45,9 @@ class ShimFacadeService : public ShimFacade::Service { virtual ~ShimFacadeService() {} ::grpc::Status Dump( - ::grpc::ServerContext* context, - const ::google::protobuf::Empty* request, - ::grpc::ServerWriter* writer) override { + ::grpc::ServerContext* /* context */, + const ::google::protobuf::Empty* /* request */, + ::grpc::ServerWriter* /* writer */) override { dumpsys_layer_->Dump(0, nullptr); return ::grpc::Status::OK; } diff --git a/system/gd/stack_manager.cc b/system/gd/stack_manager.cc index a2afa80522d968e158ae3a4c5482a5ef7a093478..763311627f9b458a764ec9ba27a45f9de9d4d305 100644 --- a/system/gd/stack_manager.cc +++ b/system/gd/stack_manager.cc @@ -25,6 +25,7 @@ #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" @@ -45,7 +46,8 @@ void StackManager::StartUp(ModuleList* modules, Thread* stack_thread) { handler_->Post(common::BindOnce(&StackManager::handle_start_up, common::Unretained(this), modules, stack_thread, std::move(promise))); - auto init_status = future.wait_for(std::chrono::seconds(3)); + auto init_status = future.wait_for(std::chrono::milliseconds( + get_gd_stack_timeout_ms(/* is_start = */ true))); WakelockManager::Get().Release(); @@ -71,7 +73,8 @@ void StackManager::ShutDown() { auto future = promise.get_future(); handler_->Post(common::BindOnce(&StackManager::handle_shut_down, common::Unretained(this), std::move(promise))); - auto stop_status = future.wait_for(std::chrono::seconds(5)); + auto stop_status = future.wait_for(std::chrono::milliseconds( + get_gd_stack_timeout_ms(/* is_start = */ false))); WakelockManager::Get().Release(); WakelockManager::Get().CleanUp(); @@ -92,4 +95,13 @@ void StackManager::handle_shut_down(std::promise promise) { promise.set_value(); } +std::chrono::milliseconds StackManager::get_gd_stack_timeout_ms(bool is_start) { + auto gd_timeout = os::GetSystemPropertyUint32( + is_start ? "bluetooth.gd.start_timeout" : "bluetooth.gd.stop_timeout", + /* default_value = */ is_start ? 3000 : 5000); + return std::chrono::milliseconds( + gd_timeout * os::GetSystemPropertyUint32("ro.hw_timeout_multiplier", + /* default_value = */ 1)); +} + } // namespace bluetooth diff --git a/system/gd/stack_manager.h b/system/gd/stack_manager.h index c09a7f6a36d25251a6b79e8bc47cb91a46bcb0ba..85b0721ea706e31cc129979850fbdcbb0e007ed8 100644 --- a/system/gd/stack_manager.h +++ b/system/gd/stack_manager.h @@ -44,6 +44,7 @@ class StackManager { void handle_start_up(ModuleList* modules, os::Thread* stack_thread, std::promise promise); void handle_shut_down(std::promise promise); + static std::chrono::milliseconds get_gd_stack_timeout_ms(bool is_start); }; } // namespace bluetooth diff --git a/system/gd/stack_manager_unittest.cc b/system/gd/stack_manager_unittest.cc index 51645eae99104d96b98b5c75e2188d376174929a..282313d39b936a5a8f5b6c8b29f1eef80d08c56c 100644 --- a/system/gd/stack_manager_unittest.cc +++ b/system/gd/stack_manager_unittest.cc @@ -35,7 +35,7 @@ class TestModuleNoDependency : public Module { static const ModuleFactory Factory; protected: - void ListDependencies(ModuleList* list) const {} + void ListDependencies(ModuleList* /* list */) const {} void Start() override {} void Stop() override {} std::string ToString() const override { diff --git a/system/gd/storage/le_device.h b/system/gd/storage/le_device.h index aec4f301e8e29790d57157549cd06175177e661c..d87225f2ba4e2cdc4bac175a508b0cf96007ebb8 100644 --- a/system/gd/storage/le_device.h +++ b/system/gd/storage/le_device.h @@ -15,14 +15,11 @@ */ #pragma once -#include #include #include -#include "crypto_toolbox/crypto_toolbox.h" #include "hci/hci_packets.h" #include "storage/config_cache.h" -#include "storage/config_cache_helper.h" #include "storage/device.h" namespace bluetooth { diff --git a/system/gd/storage/storage_module.cc b/system/gd/storage/storage_module.cc index f9eab5fea3f6710d8f59d4a4b6ec35ce972fd50f..691436035c753cc1fd8bd26e3c57939771be8c4e 100644 --- a/system/gd/storage/storage_module.cc +++ b/system/gd/storage/storage_module.cc @@ -36,8 +36,6 @@ namespace bluetooth { namespace storage { -using common::ListMap; -using common::LruCache; using os::Alarm; using os::Handler; diff --git a/system/gd/sysprops/sysprops_module.cc b/system/gd/sysprops/sysprops_module.cc index 2f85e766fe2fdc02288e29b9e88a539a18297295..5b15d43e45b611187fd1f0b124d69ff34276b565 100644 --- a/system/gd/sysprops/sysprops_module.cc +++ b/system/gd/sysprops/sysprops_module.cc @@ -37,7 +37,7 @@ struct SyspropsModule::impl { os::Handler* sysprops_handler_; }; -void SyspropsModule::ListDependencies(ModuleList* list) const {} +void SyspropsModule::ListDependencies(ModuleList* /* list */) const {} void SyspropsModule::Start() { std::string file_path = os::ParameterProvider::SyspropsFilePath(); @@ -66,6 +66,7 @@ std::string SyspropsModule::ToString() const { void SyspropsModule::parse_config(std::string file_path) { const std::list supported_sysprops = { // General + "bluetooth.btm.sec.delay_auth_ms.value", "bluetooth.device.default_name", "bluetooth.core.gap.le.privacy.enabled", "bluetooth.core.gap.le.conn.only_init_1m_phy.enabled", @@ -74,6 +75,7 @@ void SyspropsModule::parse_config(std::string file_path) { "bluetooth.device_id.product_version", "bluetooth.device_id.vendor_id", "bluetooth.device_id.vendor_id_source", + "persist.bluetooth.inq_by_rssi", // BR/EDR "bluetooth.core.classic.page_scan_type", "bluetooth.core.classic.page_scan_interval", @@ -104,6 +106,7 @@ void SyspropsModule::parse_config(std::string file_path) { "bluetooth.core.le.vendor_capabilities.enabled", // SCO "bluetooth.sco.disable_enhanced_connection", + "bluetooth.sco.swb_supported", // Profile "persist.bluetooth.avrcpcontrolversion", }; diff --git a/system/hci/Android.bp b/system/hci/Android.bp index e84c1381e3e06059c19b7177bc315432e12390c4..8137d261be189bbf25c82f4ee4f97143b987e6c5 100644 --- a/system/hci/Android.bp +++ b/system/hci/Android.bp @@ -10,14 +10,13 @@ package { // HCI static library for target cc_library_static { name: "libbt-hci", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], srcs: [ "src/buffer_allocator.cc", "src/packet_fragmenter.cc", ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], local_include_dirs: [ "include", @@ -27,32 +26,34 @@ cc_library_static { "packages/modules/Bluetooth/system/bta/include", "packages/modules/Bluetooth/system/btif/include", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/stack/include", "system/libhwbinder/include", ], + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", + header_libs: ["libbluetooth_headers"], + static_libs: ["libbt_shim_bridge"], } // HCI unit tests for target cc_test { name: "net_test_hci", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", - "fluoride_basic_defaults", - "fluoride_test_defaults", + "fluoride_defaults", "mts_defaults", ], - host_supported: false, local_include_dirs: [ "include", ], include_dirs: [ "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/gd/rust/shim", + "packages/modules/Bluetooth/system/gd", + "packages/modules/Bluetooth/system/include", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/osi/test", "packages/modules/Bluetooth/system/stack/include", @@ -64,39 +65,22 @@ cc_test { shared_libs: [ "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", + "libbase", "libdl", + "liblog", ], static_libs: [ "libbluetooth-for-tests", + "libbluetooth-types", "libbt-hci", "libbtcore", "libchrome", + "libosi", ], -} - -cc_test { - name: "net_test_hci_fragmenter_native", - static_libs: [ - "libbase", - "libchrome", - ], - test_suites: ["device-tests"], - defaults: [ - "bluetooth_gtest_x86_asan_workaround", - "fluoride_test_defaults", - "mts_defaults", - ], - local_include_dirs: [ - "include", - ], - include_dirs: [ - "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/osi/test", - "packages/modules/Bluetooth/system/stack/include", - ], - srcs: [ - "src/buffer_allocator.cc", - "test/packet_fragmenter_host_test.cc", - ], + sanitize: { + address: true, + cfi: true, + misc_undefined: ["bounds"], + }, + cflags: ["-Wno-unused-parameter"], } diff --git a/system/hci/BUILD.gn b/system/hci/BUILD.gn index ef5bf6f5970d0f2b17e0c1323ac47844c2c18ba5..ebea9e65072760511c6f510537e5c5d9f02bc9d6 100644 --- a/system/hci/BUILD.gn +++ b/system/hci/BUILD.gn @@ -40,8 +40,6 @@ static_library("hci") { if (use.test) { executable("net_test_hci") { sources = [ - "//bt/system/osi/test/AllocationTestHarness.cc", - "//bt/system/osi/test/AlarmTestHarness.cc", "test/packet_fragmenter_test.cc", ] diff --git a/system/hci/include/btsnoop_mem.h b/system/hci/include/btsnoop_mem.h index c3372da4eb10ef1760a186b99ca123a3f1b005e6..660678e9a8c1a2641a2175acdc2e9fbbaebac6de 100644 --- a/system/hci/include/btsnoop_mem.h +++ b/system/hci/include/btsnoop_mem.h @@ -27,17 +27,10 @@ typedef void (*btsnoop_data_cb)(const uint16_t type, const uint8_t* p_data, const size_t len, const uint64_t timestamp_us); -// Callback invoked for each HCI packet when activity attribution is enabled. -typedef void (*activity_attribution_cb)(const uint16_t type, - const uint8_t* p_data, const size_t len, - const uint64_t timestamp_us); - // This call sets the (one and only) callback that will // be invoked once for each HCI packet/event. void btsnoop_mem_set_callback(btsnoop_data_cb cb); -void activity_attribution_set_callback(activity_attribution_cb cb); - // This function is invoked every time an HCI packet // is sent/received. Packets will be filtered and then // forwarded to the |btsnoop_data_cb|. diff --git a/system/hci/include/hci_layer.h b/system/hci/include/hci_layer.h index 38ce9bfa02bb443e16e096f93f5318d4f944b6c0..edfda11f57ebe3e87cfb51e4247b77513aaee6d8 100644 --- a/system/hci/include/hci_layer.h +++ b/system/hci/include/hci_layer.h @@ -44,8 +44,6 @@ typedef struct hci_t { command_complete_cb complete_callback, command_status_cb status_cb, void* context); - future_t* (*transmit_command_futured)(const BT_HDR* command); - // Send some data downward through the HCI layer void (*transmit_downward)(uint16_t type, void* data); } hci_t; diff --git a/system/hci/include/hci_layer_legacy.h b/system/hci/include/hci_layer_legacy.h index f4dfc41636ab9e9c10a467a59dc950529f6e536f..9bf8edcbd21497314aed2ac41601f1a6bae4512f 100644 --- a/system/hci/include/hci_layer_legacy.h +++ b/system/hci/include/hci_layer_legacy.h @@ -25,15 +25,11 @@ #define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */ /* Message event ID passed from Host/Controller lib to stack */ -#define MSG_HC_TO_STACK_HCI_ACL 0x1100 /* eq. BT_EVT_TO_BTU_HCI_ACL */ -#define MSG_HC_TO_STACK_HCI_SCO 0x1200 /* eq. BT_EVT_TO_BTU_HCI_SCO */ #define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */ #define MSG_HC_TO_STACK_HCI_ISO 0x1700 /* eq. BT_EVT_TO_BTU_HCI_ISO */ #define MSG_HC_TO_STACK_HCI_EVT 0x1000 /* eq. BT_EVT_TO_BTU_HCI_EVT */ /* Message event ID passed from stack to vendor lib */ -#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */ -#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */ #define MSG_STACK_TO_HC_HCI_ISO 0x2d00 /* eq. BT_EVT_TO_LM_HCI_ISO */ #define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */ diff --git a/system/hci/include/packet_fragmenter.h b/system/hci/include/packet_fragmenter.h index 29651a043dc92368770a28c0d2f4925cab5a93ac..65eefb1a98fcbbdb348fae4988897d91e0185cab 100644 --- a/system/hci/include/packet_fragmenter.h +++ b/system/hci/include/packet_fragmenter.h @@ -19,11 +19,9 @@ #pragma once #include "device/include/controller.h" -#include "hci_layer.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" -typedef void (*transmit_finished_cb)(BT_HDR* packet, bool all_fragments_sent); typedef void (*packet_reassembled_cb)(BT_HDR* packet); typedef void (*packet_fragmented_cb)(BT_HDR* packet, bool send_transmit_finished); @@ -34,10 +32,6 @@ typedef struct { // Called for every completely reassembled packet. packet_reassembled_cb reassembled; - - // Called when the fragmenter finishes sending all requested fragments, - // but the packet has not been entirely sent. - transmit_finished_cb transmit_finished; } packet_fragmenter_callbacks_t; typedef struct packet_fragmenter_t { @@ -51,10 +45,8 @@ typedef struct packet_fragmenter_t { // callback. void (*fragment_and_dispatch)(BT_HDR* packet); // If |packet| is a complete packet, forwards to the reassembled callback. - // Otherwise - // holds onto it until all fragments arrive, at which point the reassembled - // callback is called - // with the reassembled data. + // Otherwise holds onto it until all fragments arrive, at which point the + // reassembled callback is called with the reassembled data. void (*reassemble_and_dispatch)(BT_HDR* packet); } packet_fragmenter_t; diff --git a/system/hci/src/buffer_allocator.cc b/system/hci/src/buffer_allocator.cc index 1609eecd5b9441ef54afe435246ed8ece5f3fe1f..bd008dffeee83ebd1755ca9217e5e9d64d73dfa8 100644 --- a/system/hci/src/buffer_allocator.cc +++ b/system/hci/src/buffer_allocator.cc @@ -20,8 +20,7 @@ #include -#include "bt_target.h" -#include "check.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" static void* buffer_alloc(size_t size) { diff --git a/system/hci/src/packet_fragmenter.cc b/system/hci/src/packet_fragmenter.cc index 629652c87ba1941639b8110e6cc5d32f25e6987d..fc32f84994b0c7b4f9024b92bdf445a4e26a539a 100644 --- a/system/hci/src/packet_fragmenter.cc +++ b/system/hci/src/packet_fragmenter.cc @@ -25,16 +25,13 @@ #include -#include "bt_target.h" -#include "check.h" #include "device/include/controller.h" #include "hci/include/buffer_allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "hci/include/hci_layer.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "stack/include/bt_hdr.h" - -// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2) -#define HCI_ACL_PREAMBLE_SIZE 4 +#include "stack/include/bt_types.h" #define HCI_ISO_BF_FIRST_FRAGMENTED_PACKET (0) #define HCI_ISO_BF_CONTINUATION_FRAGMENT_PACKET (1) @@ -84,91 +81,21 @@ static const allocator_t* buffer_allocator; static const controller_t* controller; static const packet_fragmenter_callbacks_t* callbacks; -static std::unordered_map partial_packets; static std::unordered_map partial_iso_packets; static void init(const packet_fragmenter_callbacks_t* result_callbacks) { callbacks = result_callbacks; } -static void cleanup() { - partial_packets.clear(); - partial_iso_packets.clear(); -} - -static bool check_uint16_overflow(uint16_t a, uint16_t b) { - return (UINT16_MAX - a) < b; -} - -static void fragment_and_dispatch_acl(BT_HDR* packet); -static void fragment_and_dispatch_iso(BT_HDR* packet); +static void cleanup() { partial_iso_packets.clear(); } static void fragment_and_dispatch(BT_HDR* packet) { CHECK(packet != NULL); uint16_t event = packet->event & MSG_EVT_MASK; - if (event == MSG_STACK_TO_HC_HCI_ACL) { - fragment_and_dispatch_acl(packet); - } else if (event == MSG_HC_TO_STACK_HCI_SCO) { - callbacks->fragmented(packet, true); - } else if (event == MSG_STACK_TO_HC_HCI_ISO) { - fragment_and_dispatch_iso(packet); - } else { - callbacks->fragmented(packet, true); - } -} - -static void fragment_and_dispatch_acl(BT_HDR* packet) { - uint16_t max_data_size = - SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID - ? controller->get_acl_data_size_classic() - : controller->get_acl_data_size_ble(); - - uint16_t max_packet_size = max_data_size + HCI_ACL_PREAMBLE_SIZE; - uint16_t remaining_length = packet->len; - - uint8_t* stream = packet->data + packet->offset; - - uint16_t continuation_handle; - STREAM_TO_UINT16(continuation_handle, stream); - continuation_handle = APPLY_CONTINUATION_FLAG(continuation_handle); - - while (remaining_length > max_packet_size) { - // Make sure we use the right ACL packet size - stream = packet->data + packet->offset; - STREAM_SKIP_UINT16(stream); - UINT16_TO_STREAM(stream, max_data_size); - - packet->len = max_packet_size; - callbacks->fragmented(packet, false); - - packet->offset += max_data_size; - remaining_length -= max_data_size; - packet->len = remaining_length; - - // Write the ACL header for the next fragment - stream = packet->data + packet->offset; - UINT16_TO_STREAM(stream, continuation_handle); - UINT16_TO_STREAM(stream, remaining_length - HCI_ACL_PREAMBLE_SIZE); - - // Apparently L2CAP can set layer_specific to a max number of segments to - // transmit - if (packet->layer_specific) { - packet->layer_specific--; - - if (packet->layer_specific == 0) { - packet->event = BT_EVT_TO_BTU_L2C_SEG_XMIT; - callbacks->transmit_finished(packet, false); - return; - } - } - } - - callbacks->fragmented(packet, true); -} + CHECK(event == MSG_STACK_TO_HC_HCI_ISO); -static void fragment_and_dispatch_iso(BT_HDR* packet) { uint8_t* stream = packet->data + packet->offset; uint16_t max_data_size = controller->get_iso_data_size(); uint16_t max_packet_size = max_data_size + HCI_ISO_PREAMBLE_SIZE; @@ -214,7 +141,7 @@ static void fragment_and_dispatch_iso(BT_HDR* packet) { callbacks->fragmented(packet, true); } -static void reassemble_and_dispatch_iso(UNUSED_ATTR BT_HDR* packet) { +static void reassemble_and_dispatch(UNUSED_ATTR BT_HDR* packet) { uint8_t* stream = packet->data; uint16_t handle; uint16_t iso_length; @@ -222,6 +149,9 @@ static void reassemble_and_dispatch_iso(UNUSED_ATTR BT_HDR* packet) { BT_HDR* partial_packet; uint16_t iso_full_len; + uint16_t event = packet->event & MSG_EVT_MASK; + CHECK(event == MSG_HC_TO_STACK_HCI_ISO); + STREAM_TO_UINT16(handle, stream); STREAM_TO_UINT16(iso_length, stream); // last 2 bits is RFU @@ -395,139 +325,6 @@ static void reassemble_and_dispatch_iso(UNUSED_ATTR BT_HDR* packet) { } } -static void reassemble_and_dispatch(BT_HDR* packet) { - if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) { - uint8_t* stream = packet->data; - uint16_t handle; - uint16_t acl_length; - - STREAM_TO_UINT16(handle, stream); - STREAM_TO_UINT16(acl_length, stream); - - CHECK(acl_length == packet->len - HCI_ACL_PREAMBLE_SIZE); - - uint8_t boundary_flag = GET_BOUNDARY_FLAG(handle); - uint8_t broadcast_flag = GET_BROADCAST_FLAG(handle); - handle = handle & HANDLE_MASK; - - if (broadcast_flag != POINT_TO_POINT) { - LOG_WARN("dropping broadcast packet"); - buffer_allocator->free(packet); - return; - } - - if (boundary_flag == START_PACKET_BOUNDARY) { - if (acl_length < 2) { - LOG_WARN("%s invalid acl_length %d", __func__, acl_length); - buffer_allocator->free(packet); - return; - } - uint16_t l2cap_length; - STREAM_TO_UINT16(l2cap_length, stream); - auto map_iter = partial_packets.find(handle); - if (map_iter != partial_packets.end()) { - LOG_WARN( - "%s found unfinished packet for handle with start packet. " - "Dropping old.", - __func__); - - BT_HDR* hdl = map_iter->second; - partial_packets.erase(map_iter); - buffer_allocator->free(hdl); - } - - if (acl_length < L2CAP_HEADER_PDU_LEN_SIZE) { - LOG_WARN("%s L2CAP packet too small (%d < %d). Dropping it.", __func__, - packet->len, L2CAP_HEADER_PDU_LEN_SIZE); - buffer_allocator->free(packet); - return; - } - - uint16_t full_length = - l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE; - - // Check for buffer overflow and that the full packet size + BT_HDR size - // is less than the max buffer size - if (check_uint16_overflow(l2cap_length, - (L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE)) || - ((full_length + sizeof(BT_HDR)) > BT_DEFAULT_BUFFER_SIZE)) { - LOG_ERROR("%s Dropping L2CAP packet with invalid length (%d).", - __func__, l2cap_length); - buffer_allocator->free(packet); - return; - } - - if (full_length <= packet->len) { - if (full_length < packet->len) - LOG_WARN("%s found l2cap full length %d less than the hci length %d.", - __func__, l2cap_length, packet->len); - - callbacks->reassembled(packet); - return; - } - - BT_HDR* partial_packet = - (BT_HDR*)buffer_allocator->alloc(full_length + sizeof(BT_HDR)); - partial_packet->event = packet->event; - partial_packet->len = full_length; - partial_packet->offset = packet->len; - - memcpy(partial_packet->data, packet->data, packet->len); - - // Update the ACL data size to indicate the full expected length - stream = partial_packet->data; - STREAM_SKIP_UINT16(stream); // skip the handle - UINT16_TO_STREAM(stream, full_length - HCI_ACL_PREAMBLE_SIZE); - - partial_packets[handle] = partial_packet; - - // Free the old packet buffer, since we don't need it anymore - buffer_allocator->free(packet); - } else { - auto map_iter = partial_packets.find(handle); - if (map_iter == partial_packets.end()) { - LOG_WARN("%s got continuation for unknown packet. Dropping it.", - __func__); - buffer_allocator->free(packet); - return; - } - BT_HDR* partial_packet = map_iter->second; - - packet->offset = HCI_ACL_PREAMBLE_SIZE; - uint16_t projected_offset = - partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE); - if ((packet->len - packet->offset) > - (partial_packet->len - partial_packet->offset)) { - LOG_WARN( - "%s got packet which would exceed expected length of %d. " - "Truncating.", - __func__, partial_packet->len); - packet->len = (partial_packet->len - partial_packet->offset) + packet->offset; - projected_offset = partial_packet->len; - } - - memcpy(partial_packet->data + partial_packet->offset, - packet->data + packet->offset, packet->len - packet->offset); - - // Free the old packet buffer, since we don't need it anymore - buffer_allocator->free(packet); - partial_packet->offset = projected_offset; - - if (partial_packet->offset == partial_packet->len) { - partial_packets.erase(handle); - partial_packet->offset = 0; - callbacks->reassembled(partial_packet); - } - } - } else if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_SCO) { - callbacks->reassembled(packet); - } else if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ISO) { - reassemble_and_dispatch_iso(packet); - } else { - callbacks->reassembled(packet); - } -} - static const packet_fragmenter_t interface = {init, cleanup, fragment_and_dispatch, diff --git a/system/hci/test/packet_fragmenter_host_test.cc b/system/hci/test/packet_fragmenter_host_test.cc deleted file mode 100644 index 7c566f5b359dbe874f1ab1444a7080309a04cdb5..0000000000000000000000000000000000000000 --- a/system/hci/test/packet_fragmenter_host_test.cc +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include -#include - -#include "hci/src/packet_fragmenter.cc" -#include "osi/include/allocator.h" -#include "osi/test/AllocationTestHarness.h" -#include "stack/include/bt_hdr.h" - -void allocation_tracker_uninit(void); - -enum kPacketOrder { - kStart = 1, - kContinuation = 2, -}; - -struct AclPacketHeader { - struct { - uint16_t handle : 12; - uint16_t continuation : 1; - uint16_t start : 1; - uint16_t reserved : 2; - } s; - uint16_t length; - - uint16_t GetRawHandle() const { return *(uint16_t*)(this); } - - uint16_t GetHandle() const { return s.handle; } - uint16_t GetLength() const { return length; } -} __attribute__((packed)); - -struct L2capPacketHeader { - uint16_t length; - uint16_t cid; -} __attribute__((packed)); - -struct AclL2capPacketHeader { - struct AclPacketHeader acl_header; - struct L2capPacketHeader l2cap_header; -} __attribute__((packed)); - -namespace { - -constexpr uint16_t kHandle = 0x123; -constexpr uint16_t kCid = 0x4567; -constexpr uint16_t kMaxPacketSize = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR) - - L2CAP_HEADER_SIZE - HCI_ACL_PREAMBLE_SIZE; -constexpr size_t kTypicalPacketSizes[] = { - 1, 2, 3, 4, 8, 16, 32, 64, 127, 128, 129, 256, 1024, 2048, kMaxPacketSize}; -constexpr size_t kNumberOfTypicalPacketSizes = - sizeof(kTypicalPacketSizes) / sizeof(kTypicalPacketSizes[0]); - -void FreeBuffer(BT_HDR* bt_hdr) { osi_free(bt_hdr); } - -struct TestMutables { - struct { - int access_count_{0}; - } fragmented; - struct { - int access_count_{0}; - std::queue> queue; - } reassembled; - struct { - int access_count_{0}; - } transmit_finished; -}; - -TestMutables test_state_; - -void OnFragmented(BT_HDR* packet, bool send_transmit_finished) { - test_state_.fragmented.access_count_++; -} - -void OnReassembled(BT_HDR* packet) { - test_state_.reassembled.access_count_++; - test_state_.reassembled.queue.push( - std::unique_ptr(packet, &FreeBuffer)); -} - -void OnTransmitFinished(BT_HDR* packet, bool all_fragments_sent) { - test_state_.transmit_finished.access_count_++; -} - -packet_fragmenter_callbacks_t result_callbacks = { - .fragmented = OnFragmented, - .reassembled = OnReassembled, - .transmit_finished = OnTransmitFinished, -}; - -AclPacketHeader* AclHeader(BT_HDR* packet) { - return (AclPacketHeader*)packet->data; -} -L2capPacketHeader* L2capHeader(BT_HDR* packet) { - return &((AclL2capPacketHeader*)packet->data)->l2cap_header; -} - -uint8_t* Data(BT_HDR* packet) { - AclPacketHeader* acl_header = - reinterpret_cast(packet->data); - return acl_header->s.start - ? (uint8_t*)(packet->data + sizeof(AclL2capPacketHeader)) - : (uint8_t*)(packet->data + sizeof(AclPacketHeader)); -} - -} // namespace - -// Needed for linkage -const controller_t* controller_get_interface() { return nullptr; } - -/** - * Test class to test selected functionality in hci/src/hci_layer.cc - */ -class HciPacketFragmenterTest : public AllocationTestHarness { - protected: - void SetUp() override { - AllocationTestHarness::SetUp(); - // Disable our allocation tracker to allow ASAN full range - allocation_tracker_uninit(); - packet_fragmenter_ = packet_fragmenter_get_interface(); - packet_fragmenter_->init(&result_callbacks); - test_state_ = TestMutables(); - } - - void TearDown() override { - FlushPartialPackets(); - while (!test_state_.reassembled.queue.empty()) { - test_state_.reassembled.queue.pop(); - } - packet_fragmenter_->cleanup(); - AllocationTestHarness::TearDown(); - } - const packet_fragmenter_t* packet_fragmenter_; - - // Start acl packet - BT_HDR* AllocateL2capPacket(size_t l2cap_length, - const std::vector data) const { - auto packet = - AllocateAclPacket(data.size() + sizeof(L2capPacketHeader), kStart); - L2capHeader(packet)->length = l2cap_length; - L2capHeader(packet)->cid = kCid; - std::copy(data.cbegin(), data.cend(), Data(packet)); - return packet; - } - - // Continuation acl packet - BT_HDR* AllocateL2capPacket(const std::vector data) const { - auto packet = AllocateAclPacket(data.size(), kContinuation); - std::copy(data.cbegin(), data.cend(), Data(packet)); - return packet; - } - - const std::vector CreateData(size_t size) const { - CHECK(size > 0); - std::vector v(size); - uint8_t sum = 0; - for (size_t s = 0; s < size; s++) { - sum += v[s] = s; - } - v[0] = (~sum + 1); // First byte has sum complement - return v; - } - - // Verify packet integrity - bool VerifyData(const uint8_t* data, size_t size) const { - CHECK(size > 0); - uint8_t sum = 0; - for (size_t s = 0; s < size; s++) { - sum += data[s]; - } - return sum == 0; - } - - private: - BT_HDR* AllocateAclPacket(size_t acl_length, - kPacketOrder packet_order) const { - BT_HDR* packet = AllocatePacket(sizeof(AclPacketHeader) + acl_length, - MSG_HC_TO_STACK_HCI_ACL); - AclHeader(packet)->s.handle = kHandle; - AclHeader(packet)->length = acl_length; - switch (packet_order) { - case kStart: - AclHeader(packet)->s.start = 1; - break; - case kContinuation: - AclHeader(packet)->s.continuation = 1; - break; - } - return packet; - } - - BT_HDR* AllocatePacket(size_t packet_length, uint16_t event_mask) const { - BT_HDR* packet = - static_cast(osi_calloc(sizeof(BT_HDR) + packet_length)); - packet->event = event_mask; - packet->len = static_cast(packet_length); - return packet; - } - - void FlushPartialPackets() const { - while (!partial_packets.empty()) { - BT_HDR* partial_packet = partial_packets.at(kHandle); - partial_packets.erase(kHandle); - osi_free(partial_packet); - } - } -}; - -TEST_F(HciPacketFragmenterTest, TestStruct_Handle) { - AclPacketHeader acl_header; - memset(&acl_header, 0, sizeof(acl_header)); - - for (uint16_t h = 0; h < UINT16_MAX; h++) { - acl_header.s.handle = h; - CHECK(acl_header.GetHandle() == (h & HANDLE_MASK)); - CHECK(acl_header.s.continuation == 0); - CHECK(acl_header.s.start == 0); - CHECK(acl_header.s.reserved == 0); - - CHECK((acl_header.GetRawHandle() & HANDLE_MASK) == (h & HANDLE_MASK)); - GET_BOUNDARY_FLAG(acl_header.GetRawHandle() == 0); - } -} - -TEST_F(HciPacketFragmenterTest, TestStruct_Continuation) { - AclPacketHeader acl_header; - memset(&acl_header, 0, sizeof(acl_header)); - - for (uint16_t h = 0; h < UINT16_MAX; h++) { - acl_header.s.continuation = h; - CHECK(acl_header.GetHandle() == 0); - CHECK(acl_header.s.continuation == (h & 0x1)); - CHECK(acl_header.s.start == 0); - CHECK(acl_header.s.reserved == 0); - - CHECK((acl_header.GetRawHandle() & HANDLE_MASK) == 0); - GET_BOUNDARY_FLAG(acl_header.GetRawHandle() == (h & 0x3)); - } -} - -TEST_F(HciPacketFragmenterTest, TestStruct_Start) { - AclPacketHeader acl_header; - memset(&acl_header, 0, sizeof(acl_header)); - - for (uint16_t h = 0; h < UINT16_MAX; h++) { - acl_header.s.start = h; - CHECK(acl_header.GetHandle() == 0); - CHECK(acl_header.s.continuation == 0); - CHECK(acl_header.s.start == (h & 0x1)); - CHECK(acl_header.s.reserved == 0); - - CHECK((acl_header.GetRawHandle() & HANDLE_MASK) == 0); - GET_BOUNDARY_FLAG(acl_header.GetRawHandle() == (h & 0x3)); - } -} - -TEST_F(HciPacketFragmenterTest, TestStruct_Reserved) { - AclPacketHeader acl_header; - memset(&acl_header, 0, sizeof(acl_header)); - - for (uint16_t h = 0; h < UINT16_MAX; h++) { - acl_header.s.reserved = h; - CHECK(acl_header.GetHandle() == 0); - CHECK(acl_header.s.continuation == 0); - CHECK(acl_header.s.start == 0); - CHECK(acl_header.s.reserved == (h & 0x3)); - } -} -TEST_F(HciPacketFragmenterTest, CreateAndVerifyPackets) { - const size_t size_check[] = {1, 2, 3, 4, 8, 16, 32, - 64, 127, 128, 129, 256, 1024, 0xfff0}; - const std::vector sizes( - size_check, size_check + sizeof(size_check) / sizeof(size_check[0])); - - for (const auto packet_size : sizes) { - const std::vector data = CreateData(packet_size); - uint8_t buf[packet_size]; - std::copy(data.cbegin(), data.cend(), buf); - CHECK(VerifyData(buf, packet_size)); - } -} - -TEST_F(HciPacketFragmenterTest, OnePacket_Immediate) { - const std::vector sizes( - kTypicalPacketSizes, kTypicalPacketSizes + kNumberOfTypicalPacketSizes); - - int reassembled_access_count = 0; - for (const auto packet_size : sizes) { - const std::vector data = CreateData(packet_size); - reassemble_and_dispatch(AllocateL2capPacket(data.size(), data)); - - CHECK(partial_packets.size() == 0); - CHECK(test_state_.reassembled.access_count_ == ++reassembled_access_count); - auto packet = std::move(test_state_.reassembled.queue.front()); - test_state_.reassembled.queue.pop(); - CHECK(VerifyData(Data(packet.get()), packet_size)); - } -} - -TEST_F(HciPacketFragmenterTest, OnePacket_ImmediateTooBig) { - const size_t packet_size = kMaxPacketSize + 1; - const std::vector data = CreateData(packet_size); - reassemble_and_dispatch(AllocateL2capPacket(data.size(), data)); - - CHECK(partial_packets.size() == 0); - CHECK(test_state_.reassembled.access_count_ == 0); -} - -TEST_F(HciPacketFragmenterTest, ThreePackets_Immediate) { - const size_t packet_size = 512; - const std::vector data = CreateData(packet_size); - reassemble_and_dispatch(AllocateL2capPacket(data.size(), data)); - reassemble_and_dispatch(AllocateL2capPacket(data.size(), data)); - reassemble_and_dispatch(AllocateL2capPacket(data.size(), data)); - CHECK(partial_packets.size() == 0); - CHECK(test_state_.reassembled.access_count_ == 3); -} - -TEST_F(HciPacketFragmenterTest, OnePacket_SplitTwo) { - const std::vector sizes( - kTypicalPacketSizes, kTypicalPacketSizes + kNumberOfTypicalPacketSizes); - - int reassembled_access_count = 0; - for (auto packet_size : sizes) { - const std::vector data = CreateData(packet_size); - const std::vector part1(data.cbegin(), - data.cbegin() + packet_size / 2); - reassemble_and_dispatch(AllocateL2capPacket(data.size(), part1)); - - CHECK(partial_packets.size() == 1); - CHECK(test_state_.reassembled.access_count_ == reassembled_access_count); - - const std::vector part2(data.cbegin() + packet_size / 2, - data.cend()); - reassemble_and_dispatch(AllocateL2capPacket(part2)); - - CHECK(partial_packets.size() == 0); - CHECK(test_state_.reassembled.access_count_ == ++reassembled_access_count); - - auto packet = std::move(test_state_.reassembled.queue.front()); - test_state_.reassembled.queue.pop(); - CHECK(VerifyData(Data(packet.get()), packet_size)); - } -} - -TEST_F(HciPacketFragmenterTest, OnePacket_SplitALot) { - const size_t packet_size = 512; - const size_t stride = 2; - - const std::vector data = CreateData(packet_size); - const std::vector first_part(data.cbegin(), data.cbegin() + stride); - reassemble_and_dispatch(AllocateL2capPacket(data.size(), first_part)); - CHECK(partial_packets.size() == 1); - - for (size_t i = 2; i < packet_size - stride; i += stride) { - const std::vector middle_part(data.cbegin() + i, - data.cbegin() + i + stride); - reassemble_and_dispatch(AllocateL2capPacket(middle_part)); - } - CHECK(partial_packets.size() == 1); - CHECK(test_state_.reassembled.access_count_ == 0); - - const std::vector last_part(data.cbegin() + packet_size - stride, - data.cend()); - reassemble_and_dispatch(AllocateL2capPacket(last_part)); - - CHECK(partial_packets.size() == 0); - CHECK(test_state_.reassembled.access_count_ == 1); - auto packet = std::move(test_state_.reassembled.queue.front()); - CHECK(VerifyData(Data(packet.get()), packet_size)); -} - -TEST_F(HciPacketFragmenterTest, TwoPacket_InvalidLength) { - const size_t packet_size = UINT16_MAX; - const std::vector data = CreateData(packet_size); - const std::vector first_part(data.cbegin(), - data.cbegin() + packet_size / 2); - reassemble_and_dispatch(AllocateL2capPacket(data.size(), first_part)); - - CHECK(partial_packets.size() == 0); - CHECK(test_state_.reassembled.access_count_ == 0); - - const std::vector second_part(data.cbegin() + packet_size / 2, - data.cend()); - reassemble_and_dispatch(AllocateL2capPacket(second_part)); - - CHECK(partial_packets.size() == 0); - CHECK(test_state_.reassembled.access_count_ == 0); -} - -TEST_F(HciPacketFragmenterTest, TwoPacket_HugeBogusSecond) { - const size_t packet_size = kMaxPacketSize; - const std::vector data = CreateData(UINT16_MAX); - const std::vector first_part(data.cbegin(), - data.cbegin() + packet_size - 1); - reassemble_and_dispatch(AllocateL2capPacket(packet_size, first_part)); - - CHECK(partial_packets.size() == 1); - CHECK(test_state_.reassembled.access_count_ == 0); - - const std::vector second_part(data.cbegin() + packet_size - 1, - data.cend()); - reassemble_and_dispatch(AllocateL2capPacket(second_part)); - - CHECK(partial_packets.size() == 0); - CHECK(test_state_.reassembled.access_count_ == 1); -} diff --git a/system/hci/test/packet_fragmenter_test.cc b/system/hci/test/packet_fragmenter_test.cc index 2b08fa93337cf0450d8b3854de16dfdc57859627..2696b0b727e80ade0655542f9f40a4210b9c124a 100644 --- a/system/hci/test/packet_fragmenter_test.cc +++ b/system/hci/test/packet_fragmenter_test.cc @@ -21,17 +21,14 @@ #include #include -#include "AllocationTestHarness.h" #include "device/include/controller.h" +#include "hci/include/hci_layer.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "test_stubs.h" -#ifndef HCI_ACL_PREAMBLE_SIZE -#define HCI_ACL_PREAMBLE_SIZE 4 -#endif - #ifndef HCI_ISO_PREAMBLE_SIZE #define HCI_ISO_PREAMBLE_SIZE 4 #endif @@ -60,8 +57,6 @@ static const char* sample_data = "a breed from off the face of the earth.\""; static const char* small_sample_data = "\"What giants?\" said Sancho Panza."; -static const uint16_t test_handle_start = (0x1992 & 0xCFFF) | 0x2000; -static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000; static const uint16_t test_iso_handle_complete_with_ts = (0x0666 | (0x0002 << 12) | (0x0001 << 14)); static const uint16_t test_iso_handle_complete_without_ts = @@ -85,9 +80,7 @@ static BT_HDR* manufacture_packet_for_fragmentation(uint16_t event, const char* data) { uint16_t data_length = strlen(data); uint16_t size = data_length; - if (event == MSG_STACK_TO_HC_HCI_ACL) { - size += 4; // 2 for the handle, 2 for the length; - } else if (event == MSG_STACK_TO_HC_HCI_ISO) { + if (event == MSG_STACK_TO_HC_HCI_ISO) { size += 8; // handle (2), length (2), packet_seq (2), sdu_len(2) if (iso_has_ts) { size += 4; @@ -101,10 +94,7 @@ static BT_HDR* manufacture_packet_for_fragmentation(uint16_t event, packet->layer_specific = 0; uint8_t* packet_data = packet->data; - if (event == MSG_STACK_TO_HC_HCI_ACL) { - UINT16_TO_STREAM(packet_data, test_handle_start); - UINT16_TO_STREAM(packet_data, data_length); - } else if (event == MSG_STACK_TO_HC_HCI_ISO) { + if (event == MSG_STACK_TO_HC_HCI_ISO) { if (iso_has_ts) { packet->layer_specific |= BT_ISO_HDR_CONTAINS_TS; UINT16_TO_STREAM(packet_data, test_iso_handle_start_with_ts); @@ -129,28 +119,7 @@ static void expect_packet_fragmented(uint16_t event, int max_acl_data_size, int expected_data_offset; int length_to_check; - if (event == MSG_STACK_TO_HC_HCI_ACL) { - uint16_t handle; - uint16_t length; - STREAM_TO_UINT16(handle, data); - STREAM_TO_UINT16(length, data); - - if (packet_index == 0) - EXPECT_EQ(test_handle_start, handle); - else - EXPECT_EQ(test_handle_continuation, handle); - - int length_remaining = strlen(expected_data) - data_size_sum; - int packet_data_length = packet->len - HCI_ACL_PREAMBLE_SIZE; - EXPECT_EQ(packet_data_length, length); - - if (length_remaining > max_acl_data_size) - EXPECT_EQ(max_acl_data_size, packet_data_length); - - length_to_check = packet_data_length; - expected_data_offset = packet_index * max_acl_data_size; - packet_index++; - } else if (event == MSG_STACK_TO_HC_HCI_ISO) { + if (event == MSG_STACK_TO_HC_HCI_ISO) { uint16_t handle; uint16_t length; @@ -221,49 +190,12 @@ static void expect_packet_fragmented(uint16_t event, int max_acl_data_size, data_size_sum++; } - if (event == MSG_STACK_TO_HC_HCI_ISO || event == MSG_STACK_TO_HC_HCI_ACL) + if (event == MSG_STACK_TO_HC_HCI_ISO) EXPECT_TRUE(send_complete == (data_size_sum == strlen(expected_data))); if (send_complete) osi_free(packet); } -static void manufacture_acl_packet_and_then_reassemble(uint16_t event, - uint16_t acl_size, - const char* data) { - uint16_t data_length = strlen(data); - uint16_t total_length = data_length + 2; // 2 for l2cap length; - uint16_t length_sent = 0; - uint16_t l2cap_length = data_length - 2; // l2cap length field, 2 for the - // pretend channel id borrowed - // from the data - - do { - int length_to_send = (length_sent + (acl_size - 4) < total_length) - ? (acl_size - 4) - : (total_length - length_sent); - BT_HDR* packet = (BT_HDR*)osi_malloc(length_to_send + 4 + sizeof(BT_HDR)); - packet->len = length_to_send + 4; - packet->offset = 0; - packet->event = event; - packet->layer_specific = 0; - - uint8_t* packet_data = packet->data; - if (length_sent == 0) { // first packet - UINT16_TO_STREAM(packet_data, test_handle_start); - UINT16_TO_STREAM(packet_data, length_to_send); - UINT16_TO_STREAM(packet_data, l2cap_length); - memcpy(packet_data, data, length_to_send - 2); - } else { - UINT16_TO_STREAM(packet_data, test_handle_continuation); - UINT16_TO_STREAM(packet_data, length_to_send); - memcpy(packet_data, data + length_sent - 2, length_to_send); - } - - length_sent += length_to_send; - fragmenter->reassemble_and_dispatch(packet); - } while (length_sent < total_length); -} - static void manufacture_iso_packet_and_then_reassemble(uint16_t event, uint16_t iso_size, const char* data) { @@ -338,9 +270,7 @@ static void manufacture_packet_and_then_reassemble(uint16_t event, const char* data) { uint16_t data_length = strlen(data); - if (event == MSG_HC_TO_STACK_HCI_ACL) { - manufacture_acl_packet_and_then_reassemble(event, packet_size, data); - } else if (event == MSG_HC_TO_STACK_HCI_ISO) { + if (event == MSG_HC_TO_STACK_HCI_ISO) { manufacture_iso_packet_and_then_reassemble(event, packet_size, data); } else { BT_HDR* packet = (BT_HDR*)osi_malloc(data_length + sizeof(BT_HDR)); @@ -359,20 +289,6 @@ static void expect_packet_reassembled(uint16_t event, BT_HDR* packet, uint16_t expected_data_length = strlen(expected_data); uint8_t* data = packet->data + packet->offset; - if (event == MSG_HC_TO_STACK_HCI_ACL) { - uint16_t handle; - uint16_t length; - uint16_t l2cap_length; - STREAM_TO_UINT16(handle, data); - STREAM_TO_UINT16(length, data); - STREAM_TO_UINT16(l2cap_length, data); - - EXPECT_EQ(test_handle_start, handle); - EXPECT_EQ(expected_data_length + 2, length); - EXPECT_EQ(expected_data_length - 2, - l2cap_length); // -2 for the pretend channel id - } - for (int i = 0; i < expected_data_length; i++) { EXPECT_EQ(expected_data[i], data[i]); data_size_sum++; @@ -431,30 +347,6 @@ static void expect_packet_reassembled_iso(uint16_t event, BT_HDR* packet, } STUB_FUNCTION(void, fragmented_callback, (BT_HDR * packet, bool send_complete)) -DURING(no_fragmentation) AT_CALL(0) { - expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet, - small_sample_data, send_complete); - return; -} - -DURING(fragmentation) { - expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data, - send_complete); - return; -} - -DURING(ble_no_fragmentation) AT_CALL(0) { - expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet, - small_sample_data, send_complete); - return; -} - -DURING(ble_fragmentation) { - expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data, - send_complete); - return; -} - DURING(iso_fragmentation) { expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ISO, 10, packet, sample_data, send_complete); @@ -477,16 +369,6 @@ UNEXPECTED_CALL; } STUB_FUNCTION(void, reassembled_callback, (BT_HDR * packet)) -DURING(no_reassembly) AT_CALL(0) { - expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, small_sample_data); - return; -} - -DURING(reassembly) AT_CALL(0) { - expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, sample_data); - return; -} - DURING(iso_reassembly) AT_CALL(0) { expect_packet_reassembled_iso(MSG_HC_TO_STACK_HCI_ISO, packet, sample_data, iso_timestamp, iso_packet_seq); @@ -508,12 +390,6 @@ DURING(non_acl_passthrough_reassembly) AT_CALL(0) { UNEXPECTED_CALL; } -STUB_FUNCTION(void, transmit_finished_callback, - (UNUSED_ATTR BT_HDR * packet, - UNUSED_ATTR bool sent_all_fragments)) -UNEXPECTED_CALL; -} - STUB_FUNCTION(uint16_t, get_acl_data_size_classic, (void)) DURING(no_fragmentation, non_acl_passthrough_fragmentation, no_reassembly) return 42; @@ -543,17 +419,15 @@ return 0; static void reset_for(TEST_MODES_T next) { RESET_CALL_COUNT(fragmented_callback); RESET_CALL_COUNT(reassembled_callback); - RESET_CALL_COUNT(transmit_finished_callback); RESET_CALL_COUNT(get_acl_data_size_classic); RESET_CALL_COUNT(get_acl_data_size_ble); RESET_CALL_COUNT(get_iso_data_size); CURRENT_TEST_MODE = next; } -class PacketFragmenterTest : public AllocationTestHarness { +class PacketFragmenterTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); fragmenter = packet_fragmenter_get_test_interface(&controller, &allocator_malloc); @@ -562,7 +436,6 @@ class PacketFragmenterTest : public AllocationTestHarness { callbacks.fragmented = fragmented_callback; callbacks.reassembled = reassembled_callback; - callbacks.transmit_finished = transmit_finished_callback; controller.get_acl_data_size_classic = get_acl_data_size_classic; controller.get_acl_data_size_ble = get_acl_data_size_ble; controller.get_iso_data_size = get_iso_data_size; @@ -571,92 +444,12 @@ class PacketFragmenterTest : public AllocationTestHarness { fragmenter->init(&callbacks); } - void TearDown() override { - fragmenter->cleanup(); - AllocationTestHarness::TearDown(); - } + void TearDown() override { fragmenter->cleanup(); } controller_t controller; packet_fragmenter_callbacks_t callbacks; }; -TEST_F(PacketFragmenterTest, test_no_fragment_necessary) { - reset_for(no_fragmentation); - BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, - small_sample_data); - fragmenter->fragment_and_dispatch(packet); - - EXPECT_EQ(strlen(small_sample_data), data_size_sum); - EXPECT_CALL_COUNT(fragmented_callback, 1); -} - -TEST_F(PacketFragmenterTest, test_fragment_necessary) { - reset_for(fragmentation); - BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, - sample_data); - fragmenter->fragment_and_dispatch(packet); - - EXPECT_EQ(strlen(sample_data), data_size_sum); -} - -TEST_F(PacketFragmenterTest, test_ble_no_fragment_necessary) { - reset_for(ble_no_fragmentation); - BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, - small_sample_data); - packet->event |= LOCAL_BLE_CONTROLLER_ID; - fragmenter->fragment_and_dispatch(packet); - - EXPECT_EQ(strlen(small_sample_data), data_size_sum); - EXPECT_CALL_COUNT(fragmented_callback, 1); -} - -TEST_F(PacketFragmenterTest, test_ble_fragment_necessary) { - reset_for(ble_fragmentation); - BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, - sample_data); - packet->event |= LOCAL_BLE_CONTROLLER_ID; - fragmenter->fragment_and_dispatch(packet); - - EXPECT_EQ(strlen(sample_data), data_size_sum); -} - -TEST_F(PacketFragmenterTest, test_non_acl_passthrough_fragmentation) { - reset_for(non_acl_passthrough_fragmentation); - BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_CMD, - sample_data); - fragmenter->fragment_and_dispatch(packet); - - EXPECT_EQ(strlen(sample_data), data_size_sum); - EXPECT_CALL_COUNT(fragmented_callback, 1); -} - -TEST_F(PacketFragmenterTest, test_no_reassembly_necessary) { - reset_for(no_reassembly); - manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 1337, - small_sample_data); - - EXPECT_EQ(strlen(small_sample_data), data_size_sum); - EXPECT_CALL_COUNT(reassembled_callback, 1); -} - -TEST_F(PacketFragmenterTest, test_reassembly_necessary) { - reset_for(reassembly); - manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 42, - sample_data); - - EXPECT_EQ(strlen(sample_data), data_size_sum); - EXPECT_CALL_COUNT(reassembled_callback, 1); -} - -TEST_F(PacketFragmenterTest, test_non_acl_passthrough_reasseembly) { - reset_for(non_acl_passthrough_reassembly); - manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_EVT, 42, - sample_data); - - EXPECT_EQ(strlen(sample_data), data_size_sum); - EXPECT_CALL_COUNT(reassembled_callback, 1); -} - TEST_F(PacketFragmenterTest, test_iso_fragment_necessary) { reset_for(iso_fragmentation); iso_has_ts = true; diff --git a/system/include/Android.bp b/system/include/Android.bp index 0665fc4b251fc286f1bc67ca2589acf08fe68c4a..f76b6fcccbe4924ae7c1316afc868dacad36540d 100644 --- a/system/include/Android.bp +++ b/system/include/Android.bp @@ -9,13 +9,13 @@ package { cc_library_headers { name: "avrcp_headers", - defaults: ["libchrome_support_defaults"], export_include_dirs: ["./hardware/avrcp/"], header_libs: ["internal_include_headers"], export_header_lib_headers: ["internal_include_headers"], // We need this in case some file outside of the Bluetooth project includes // bluetooth.h but doesn't include libchrome which avrcp.h depends on. + static_libs: ["libchrome"], export_static_lib_headers: ["libchrome"], vendor_available: true, @@ -29,7 +29,6 @@ cc_library_headers { cc_library_headers { name: "libbluetooth_headers", - defaults: ["libchrome_support_defaults"], visibility: [ "//packages/apps/Test/connectivity/sl4n", "//packages/modules/Bluetooth:__subpackages__", diff --git a/system/include/abstract_message_loop.h b/system/include/abstract_message_loop.h index dff65b1677992bee324ee90dedc45508a6a5e312..4e04c259145bf532a7170ed20bd1ada48e69c10a 100644 --- a/system/include/abstract_message_loop.h +++ b/system/include/abstract_message_loop.h @@ -28,9 +28,9 @@ #endif #include #include +#include #include #include -#include #else #include #include @@ -43,14 +43,14 @@ namespace btbase { class AbstractMessageLoop : public base::SingleThreadTaskExecutor { public: static scoped_refptr current_task_runner() { - return base::ThreadTaskRunnerHandle::Get(); + return base::SingleThreadTaskRunner::GetCurrentDefault(); } }; class AbstractTestMessageLoop : public base::test::TaskEnvironment { public: static scoped_refptr current_task_runner() { - return base::ThreadTaskRunnerHandle::Get(); + return base::SingleThreadTaskRunner::GetCurrentDefault(); } }; diff --git a/system/include/hardware/avrcp/avrcp_logging_helper.h b/system/include/hardware/avrcp/avrcp_logging_helper.h index fafdfee481dd00b5efb9fe5cadce9bf40bd516f7..dc2d52354f816b059886aceb35c29b2ae195ce38 100644 --- a/system/include/hardware/avrcp/avrcp_logging_helper.h +++ b/system/include/hardware/avrcp/avrcp_logging_helper.h @@ -23,15 +23,12 @@ #include #include "avrcp_common.h" -#include "bt_trace.h" +#include "internal_include/bt_trace.h" +#include "macros.h" namespace bluetooth { namespace avrcp { -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string CTypeText(const CType& type) { switch (type) { CASE_RETURN_TEXT(CType::CONTROL); diff --git a/system/include/hardware/ble_advertiser.h b/system/include/hardware/ble_advertiser.h index 0d5415392dcb6c9818ae8bd5290b147d2d450f6c..69d8eff8117c5e3e4bcb3f51fc715c86fea8d227 100644 --- a/system/include/hardware/ble_advertiser.h +++ b/system/include/hardware/ble_advertiser.h @@ -26,6 +26,9 @@ #include "bt_common_types.h" #include "bt_gatt_types.h" +constexpr uint8_t kAdvertiserClientIdJni = 0xff; +constexpr uint8_t kAdvertiserClientIdLeAudio = 0x1; + struct AdvertiseParameters { uint16_t advertising_event_properties; uint32_t min_interval; @@ -118,10 +121,11 @@ class BleAdvertiserInterface { /** Start the advertising set. This include registering, setting all * parameters and data, and enabling it. |register_cb| is called when the set * is advertising. |timeout_cb| is called when the timeout_s have passed. - * |reg_id| is the callback id assigned from upper layer + * |reg_id| is the callback id assigned from upper or native layer. + * |client_id| is the callbacks client id for jni or native layer. */ virtual void StartAdvertisingSet( - int reg_id, IdTxPowerStatusCallback register_cb, + uint8_t client_id, int reg_id, IdTxPowerStatusCallback register_cb, AdvertiseParameters params, std::vector advertise_data, std::vector scan_response_data, PeriodicAdvertisingParameters periodic_params, @@ -140,6 +144,8 @@ class BleAdvertiserInterface { bool include_adi, StatusCallback cb) = 0; virtual void RegisterCallbacks(AdvertisingCallbacks* callbacks) = 0; + virtual void RegisterCallbacksNative(AdvertisingCallbacks* callbacks, + uint8_t client_id) = 0; }; #endif /* ANDROID_INCLUDE_BLE_ADVERTISER_H */ diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h index 2e2c413a14ee1542a78f08be17236aea18927906..a9e804fc9d6dc1a66ba3504ef1f8e14917cc5362 100644 --- a/system/include/hardware/bluetooth.h +++ b/system/include/hardware/bluetooth.h @@ -54,7 +54,6 @@ #define BT_PROFILE_HAP_CLIENT_ID "has_client" #define BT_PROFILE_LE_AUDIO_ID "le_audio" #define BT_KEYSTORE_ID "bluetooth_keystore" -#define BT_ACTIVITY_ATTRIBUTION_ID "activity_attribution" #define BT_PROFILE_VC_ID "volume_control" #define BT_PROFILE_CSIS_CLIENT_ID "csis_client" #define BT_PROFILE_LE_AUDIO_ID "le_audio" @@ -105,7 +104,8 @@ typedef enum { BT_STATUS_AUTH_REJECTED, BT_STATUS_JNI_ENVIRONMENT_ERROR, BT_STATUS_JNI_THREAD_ATTACH_ERROR, - BT_STATUS_WAKELOCK_ERROR + BT_STATUS_WAKELOCK_ERROR, + BT_STATUS_TIMEOUT } bt_status_t; inline std::string bt_status_text(const bt_status_t& status) { @@ -140,6 +140,8 @@ inline std::string bt_status_text(const bt_status_t& status) { return std::string("jni_thread_error"); case BT_STATUS_WAKELOCK_ERROR: return std::string("wakelock_error"); + case BT_STATUS_TIMEOUT: + return std::string("timeout_error"); default: return std::string("UNKNOWN"); } @@ -392,6 +394,13 @@ typedef enum { */ BT_PROPERTY_REMOTE_MODEL_NUM, + /** + * Description - Address type of the remote device - PUBLIC or REMOTE + * Access mode - GET. + * Data Type - uint8_t. + */ + BT_PROPERTY_REMOTE_ADDR_TYPE, + BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF, } bt_property_type_t; @@ -557,6 +566,18 @@ typedef enum { ASSOCIATE_JVM, DISASSOCIATE_JVM } bt_cb_thread_evt; * attach/detach to/from the JVM */ typedef void (*callback_thread_event)(bt_cb_thread_evt evt); +/** Bluetooth Test Mode Callback */ +/* Receive any HCI event from controller. Must be in DUT Mode for this callback + * to be received */ +typedef void (*dut_mode_recv_callback)(uint16_t opcode, uint8_t* buf, + uint8_t len); + +/* LE Test mode callbacks + * This callback shall be invoked whenever the le_tx_test, le_rx_test or + * le_test_end is invoked The num_packets is valid only for le_test_end command + */ +typedef void (*le_test_mode_callback)(bt_status_t status, uint16_t num_packets); + /** Callback invoked when energy details are obtained */ /* Ctrl_state-Current controller state-Active-1,scan-2,or idle-3 state as * defined by HCI spec. If the ctrl_state value is 0, it means the API call @@ -591,6 +612,8 @@ typedef struct { le_address_associate_callback le_address_associate_cb; acl_state_changed_callback acl_state_changed_cb; callback_thread_event thread_evt_cb; + dut_mode_recv_callback dut_mode_recv_cb; + le_test_mode_callback le_test_mode_cb; energy_info_callback energy_info_cb; link_quality_report_callback link_quality_report_cb; generate_local_oob_data_callback generate_local_oob_data_cb; @@ -599,9 +622,6 @@ typedef struct { le_rand_callback le_rand_cb; } bt_callbacks_t; -typedef void (*alarm_cb)(void* data); -typedef bool (*set_wake_alarm_callout)(uint64_t delay_millis, bool should_wake, - alarm_cb cb, void* data); typedef int (*acquire_wake_lock_callout)(const char* lock_name); typedef int (*release_wake_lock_callout)(const char* lock_name); @@ -613,7 +633,6 @@ typedef struct { /* set to sizeof(bt_os_callouts_t) */ size_t size; - set_wake_alarm_callout set_wake_alarm; acquire_wake_lock_callout acquire_wake_lock; release_wake_lock_callout release_wake_lock; } bt_os_callouts_t; @@ -743,6 +762,18 @@ typedef struct { /** Get Bluetooth profile interface */ const void* (*get_profile_interface)(const char* profile_id); + /** Bluetooth Test Mode APIs - Bluetooth must be enabled for these APIs */ + /* Configure DUT Mode - Use this mode to enter/exit DUT mode */ + int (*dut_mode_configure)(uint8_t enable); + + /* Send any test HCI (vendor-specific) command to the controller. Must be in + * DUT Mode */ + int (*dut_mode_send)(uint16_t opcode, uint8_t* buf, uint8_t len); + /** BLE Test Mode APIs */ + /* opcode MUST be one of: LE_Receiver_Test, LE_Transmitter_Test, LE_Test_End + */ + int (*le_test_mode)(uint16_t opcode, uint8_t* buf, uint8_t len); + /** Sets the OS call-out functions that bluedroid needs for alarms and wake * locks. This should be called immediately after a successful |init|. */ diff --git a/system/include/hardware/bluetooth_headset_callbacks.h b/system/include/hardware/bluetooth_headset_callbacks.h index 88596265cdf483abb08ba35be0eee19ad49ceeba..36ea13431d726a2e536d2ea788a2c719abfbb42e 100644 --- a/system/include/hardware/bluetooth_headset_callbacks.h +++ b/system/include/hardware/bluetooth_headset_callbacks.h @@ -117,10 +117,12 @@ class Callbacks { /** * Callback for AT+BCS and event from BAC * + * @param codec SWB codec * @param swb SWB enable, SWB disable * @param bd_addr remote device address */ - virtual void SwbCallback(bthf_swb_config_t swb, RawAddress* bd_addr) = 0; + virtual void SwbCallback(bthf_swb_codec_t codec, bthf_swb_config_t swb, + RawAddress* bd_addr) = 0; /** * Callback for call hold handling (AT+CHLD) @@ -204,6 +206,24 @@ class Callbacks { */ virtual void AtBiaCallback(bool service, bool roam, bool signal, bool battery, RawAddress* bd_addr) = 0; + + /** + * Callback for DebugDump. + * + * @param active whether the SCO is active + * @param codec_id the codec ID per spec: mSBC=2, LC3=3. + * @param total_num_decoded_frames the number of frames decoded. + * @param pkt_loss_ratio the ratio of lost frames + * @param begin_ts time of the packet status window starts in microseconds. + * @param end_ts time of the packet status window ends in microseconds. + * @param pkt_status_in_hex recorded packets' status in hex string. + * @param pkt_status_in_binary recorde packets' status in binary string. + */ + virtual void DebugDumpCallback(bool active, uint16_t codec_id, + int total_num_decoded_frames, + double pkt_loss_ratio, uint64_t begin_ts, + uint64_t end_ts, const char* pkt_status_in_hex, + const char* pkt_status_in_binary) = 0; }; } // namespace headset diff --git a/system/include/hardware/bluetooth_headset_interface.h b/system/include/hardware/bluetooth_headset_interface.h index 32c315949e9c155b66355f31e7ecb12a077eca2f..f58c09e94eb278eedd90afe874f92a22e4e467d6 100644 --- a/system/include/hardware/bluetooth_headset_interface.h +++ b/system/include/hardware/bluetooth_headset_interface.h @@ -63,10 +63,11 @@ class Interface { * Create an audio connection * * @param bd_addr remote device address - * @param focre_cvsd whether force to use fallback CVSD codec + * @param disabled_codecs bitset of disabled BTM_SCO_CODECs * @return BT_STATUS_SUCCESS on success */ - virtual bt_status_t ConnectAudio(RawAddress* bd_addr, bool force_cvsd) = 0; + virtual bt_status_t ConnectAudio(RawAddress* bd_addr, + int disabled_codecs) = 0; /** * Close the audio connection @@ -264,6 +265,11 @@ class Interface { * @param active_device_addr remote device address */ virtual bt_status_t SetActiveDevice(RawAddress* active_device_addr) = 0; + + /** + * Trigger a debug dump of the Headset Profile + */ + virtual bt_status_t DebugDump() = 0; }; } // namespace headset diff --git a/system/include/hardware/bt_activity_attribution.h b/system/include/hardware/bt_activity_attribution.h deleted file mode 100644 index a9c37c47516152f68a01f00c9610284129d05196..0000000000000000000000000000000000000000 --- a/system/include/hardware/bt_activity_attribution.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_INCLUDE_BT_ACTIVITY_ATTRIBUTION_H -#define ANDROID_INCLUDE_BT_ACTIVITY_ATTRIBUTION_H - -#include - -#include "raw_address.h" - -namespace bluetooth { -namespace activity_attribution { - -class ActivityAttributionCallbacks { - public: - enum class Activity : uint8_t { - UNKNOWN = 0, - ACL, - ADVERTISE, - CONNECT, - CONTROL, - HFP, - ISO, - SCAN, - VENDOR, - }; - - struct BtaaAggregationEntry { - RawAddress address; - Activity activity; - uint16_t wakeup_count; - uint32_t byte_count; - uint32_t wakelock_duration; - }; - - virtual ~ActivityAttributionCallbacks() = default; - - /** Callback when Bluetooth woke up the system */ - virtual void OnWakeup(const Activity activity, const RawAddress& address) = 0; - - /** Callback when Bluetooth activity logs are ready to be moved */ - virtual void OnActivityLogsReady( - const std::vector logs) = 0; -}; - -class ActivityAttributionInterface { - public: - virtual ~ActivityAttributionInterface() = default; - - /** Init the interface. */ - virtual void Init(void) = 0; - - /** Register JNI callbacks with the interface. */ - virtual void RegisterCallbacks(ActivityAttributionCallbacks* callbacks) = 0; - - /** Closes the interface. */ - virtual void Cleanup(void) = 0; - - /** Notify the UID and package name of the app, and the address of associated - * active device */ - virtual void NotifyActivityAttributionInfo( - int uid, const std::string& package_name, - const std::string& device_address) = 0; -}; - -} // namespace activity_attribution -} // namespace bluetooth - -#endif /* ANDROID_INCLUDE_BT_ACTIVITY_ATTRIBUTION_H */ diff --git a/system/include/hardware/bt_gatt_client.h b/system/include/hardware/bt_gatt_client.h index 8a99b79033b851a20e86b43ae59bd5c6bc497b55..ab436f32c4642cd1172dae00f55725df05325b7f 100644 --- a/system/include/hardware/bt_gatt_client.h +++ b/system/include/hardware/bt_gatt_client.h @@ -26,15 +26,9 @@ __BEGIN_DECLS -/** - * Buffer sizes for maximum attribute length and maximum read/write - * operation buffer size. - */ -#define BTGATT_MAX_ATTR_LEN 600 - /** Buffer type for unformatted reads/writes */ typedef struct { - uint8_t value[BTGATT_MAX_ATTR_LEN]; + uint8_t value[GATT_MAX_ATTR_LEN]; uint16_t len; } btgatt_unformatted_value_t; @@ -56,7 +50,7 @@ typedef struct { /** Attribute change notification parameters */ typedef struct { - uint8_t value[BTGATT_MAX_ATTR_LEN]; + uint8_t value[GATT_MAX_ATTR_LEN]; RawAddress bda; uint16_t handle; uint16_t len; diff --git a/system/include/hardware/bt_gatt_server.h b/system/include/hardware/bt_gatt_server.h index b815b24c008b43e1b7b80c2a48b9fe777887c23b..f80b2b9ae66be616199c6aea256816c6172a62a9 100644 --- a/system/include/hardware/bt_gatt_server.h +++ b/system/include/hardware/bt_gatt_server.h @@ -26,7 +26,7 @@ __BEGIN_DECLS /** GATT value type used in response to remote read requests */ typedef struct { - uint8_t value[BTGATT_MAX_ATTR_LEN]; + uint8_t value[GATT_MAX_ATTR_LEN]; uint16_t handle; uint16_t offset; uint16_t len; diff --git a/system/include/hardware/bt_gatt_types.h b/system/include/hardware/bt_gatt_types.h index cb279a7d76c15f7df3a87b3ed0c4dfce31cc9de1..3811928d3d3376e94d42624836feb5d0bf53821b 100644 --- a/system/include/hardware/bt_gatt_types.h +++ b/system/include/hardware/bt_gatt_types.h @@ -31,6 +31,12 @@ __BEGIN_DECLS #define BTGATT_SERVICE_TYPE_PRIMARY 0 #define BTGATT_SERVICE_TYPE_SECONDARY 1 +/** + * GATT max attribute length (Bluetooth Core Specification 5.4 Volume 3, Part F, + * section 3.2.9) + */ +#define GATT_MAX_ATTR_LEN 512 + /** GATT ID adding instance id tracking to the UUID */ typedef struct { bluetooth::Uuid uuid; diff --git a/system/include/hardware/bt_hf.h b/system/include/hardware/bt_hf.h index 9a72707d0b5ecfbb932706b29df08089ec4eea09..671e564084229ceb17179216b5e34625819fb8a1 100644 --- a/system/include/hardware/bt_hf.h +++ b/system/include/hardware/bt_hf.h @@ -56,8 +56,18 @@ typedef enum { BTHF_NREC_STOP, BTHF_NREC_START } bthf_nrec_t; /* WBS codec setting */ typedef enum { BTHF_WBS_NONE, BTHF_WBS_NO, BTHF_WBS_YES } bthf_wbs_config_t; +/* SWB codec */ +typedef enum { + BTHF_SWB_CODEC_LC3 = 0, + BTHF_SWB_CODEC_VENDOR_APTX +} bthf_swb_codec_t; + /* SWB codec setting */ -typedef enum { BTHF_SWB_NONE, BTHF_SWB_NO, BTHF_SWB_YES } bthf_swb_config_t; +typedef enum { + BTHF_SWB_NONE, + BTHF_SWB_NO, + BTHF_SWB_YES, +} bthf_swb_config_t; /* CHLD - Call held handling */ typedef enum { diff --git a/system/include/hardware/bt_hf_client.h b/system/include/hardware/bt_hf_client.h index 0adebbde9e6d664ff5b129506b04243e46de31aa..9e64dbb48193a56368b2556041b27e6fccfafed6 100644 --- a/system/include/hardware/bt_hf_client.h +++ b/system/include/hardware/bt_hf_client.h @@ -33,6 +33,7 @@ typedef enum { BTHF_CLIENT_AUDIO_STATE_CONNECTING, BTHF_CLIENT_AUDIO_STATE_CONNECTED, BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC, + BTHF_CLIENT_AUDIO_STATE_CONNECTED_LC3, } bthf_client_audio_state_t; typedef enum { diff --git a/system/include/hardware/bt_hh.h b/system/include/hardware/bt_hh.h index f6e6e83abd4a2b4effa36324eb9445e5f219f129..1be58aa0c0355410357a631295b9b426a16d1497 100644 --- a/system/include/hardware/bt_hh.h +++ b/system/include/hardware/bt_hh.h @@ -23,6 +23,8 @@ #include +#include "macros.h" + __BEGIN_DECLS #define BTHH_MAX_DSC_LEN 884 @@ -37,9 +39,6 @@ typedef enum { } bthh_connection_state_t; __END_DECLS -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code inline std::string bthh_connection_state_text( const bthh_connection_state_t& state) { @@ -53,7 +52,7 @@ inline std::string bthh_connection_state_text( return base::StringPrintf("UNKNOWN[%d]", state); } } -#undef CASE_RETURN_TEXT + __BEGIN_DECLS typedef enum { diff --git a/system/include/hardware/bt_le_audio.h b/system/include/hardware/bt_le_audio.h index f51d1e71fd3930873a63e908d46bb0bc6c90bf34..c7d3130d918ad05d190d7d5f7ee3aca8fe5e6dcf 100644 --- a/system/include/hardware/bt_le_audio.h +++ b/system/include/hardware/bt_le_audio.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "raw_address.h" @@ -27,6 +28,35 @@ namespace bluetooth { namespace le_audio { +enum class LeAudioHealthBasedAction { + NONE = 0, + DISABLE, + CONSIDER_DISABLING, + INACTIVATE_GROUP, +}; + +inline std::ostream& operator<<(std::ostream& os, + const LeAudioHealthBasedAction action) { + switch (action) { + case LeAudioHealthBasedAction::NONE: + os << "NONE"; + break; + case LeAudioHealthBasedAction::DISABLE: + os << "DISABLE"; + break; + case LeAudioHealthBasedAction::CONSIDER_DISABLING: + os << "CONSIDER_DISABLING"; + break; + case LeAudioHealthBasedAction::INACTIVATE_GROUP: + os << "INACTIVATE_GROUP"; + break; + default: + os << "UNKNOWN"; + break; + } + return os; +} + enum class ConnectionState { DISCONNECTED = 0, CONNECTING, @@ -56,18 +86,65 @@ enum class GroupNodeStatus { REMOVED, }; +enum class UnicastMonitorModeStatus { + STREAMING_REQUESTED = 0, + STREAMING, + STREAMING_SUSPENDED, +}; + typedef enum { LE_AUDIO_CODEC_INDEX_SOURCE_LC3 = 0, - LE_AUDIO_CODEC_INDEX_SOURCE_MAX + LE_AUDIO_CODEC_INDEX_SOURCE_INVALID = 1000 * 1000, } btle_audio_codec_index_t; typedef enum { QUALITY_STANDARD = 0, QUALITY_HIGH } btle_audio_quality_t; +typedef enum { + LE_AUDIO_SAMPLE_RATE_INDEX_NONE = 0, + LE_AUDIO_SAMPLE_RATE_INDEX_8000HZ = 0x01 << 0, + LE_AUDIO_SAMPLE_RATE_INDEX_16000HZ = 0x01 << 2, + LE_AUDIO_SAMPLE_RATE_INDEX_24000HZ = 0x01 << 4, + LE_AUDIO_SAMPLE_RATE_INDEX_32000HZ = 0x01 << 5, + LE_AUDIO_SAMPLE_RATE_INDEX_44100HZ = 0x01 << 6, + LE_AUDIO_SAMPLE_RATE_INDEX_48000HZ = 0x01 << 7 +} btle_audio_sample_rate_index_t; + +typedef enum { + LE_AUDIO_BITS_PER_SAMPLE_INDEX_NONE = 0, + LE_AUDIO_BITS_PER_SAMPLE_INDEX_16 = 0x01 << 0, + LE_AUDIO_BITS_PER_SAMPLE_INDEX_24 = 0x01 << 1, + LE_AUDIO_BITS_PER_SAMPLE_INDEX_32 = 0x01 << 3 +} btle_audio_bits_per_sample_index_t; + +typedef enum { + LE_AUDIO_CHANNEL_COUNT_INDEX_NONE = 0, + LE_AUDIO_CHANNEL_COUNT_INDEX_1 = 0x01 << 0, + LE_AUDIO_CHANNEL_COUNT_INDEX_2 = 0x01 << 1 +} btle_audio_channel_count_index_t; + +typedef enum { + LE_AUDIO_FRAME_DURATION_INDEX_NONE = 0, + LE_AUDIO_FRAME_DURATION_INDEX_7500US = 0x01 << 0, + LE_AUDIO_FRAME_DURATION_INDEX_10000US = 0x01 << 1 +} btle_audio_frame_duration_index_t; + typedef struct { btle_audio_codec_index_t codec_type; + btle_audio_sample_rate_index_t sample_rate; + btle_audio_bits_per_sample_index_t bits_per_sample; + btle_audio_channel_count_index_t channel_count; + btle_audio_frame_duration_index_t frame_duration; + uint16_t octets_per_frame; + int32_t codec_priority; std::string ToString() const { std::string codec_name_str; + std::string sample_rate_str; + std::string bits_per_sample_str; + std::string channel_count_str; + std::string frame_duration_str; + std::string octets_per_frame_str; + std::string codec_priority_str; switch (codec_type) { case LE_AUDIO_CODEC_INDEX_SOURCE_LC3: @@ -77,8 +154,108 @@ typedef struct { codec_name_str = "Unknown LE codec " + std::to_string(codec_type); break; } - return "codec: " + codec_name_str; + + switch (sample_rate) { + case LE_AUDIO_SAMPLE_RATE_INDEX_NONE: + sample_rate_str = "none"; + break; + case LE_AUDIO_SAMPLE_RATE_INDEX_8000HZ: + sample_rate_str = "8000 hz"; + break; + case LE_AUDIO_SAMPLE_RATE_INDEX_16000HZ: + sample_rate_str = "16000 hz"; + break; + case LE_AUDIO_SAMPLE_RATE_INDEX_24000HZ: + sample_rate_str = "24000 hz"; + break; + case LE_AUDIO_SAMPLE_RATE_INDEX_32000HZ: + sample_rate_str = "32000 hz"; + break; + case LE_AUDIO_SAMPLE_RATE_INDEX_44100HZ: + sample_rate_str = "44100 hz"; + break; + case LE_AUDIO_SAMPLE_RATE_INDEX_48000HZ: + sample_rate_str = "48000 hz"; + break; + default: + sample_rate_str = + "Unknown LE sample rate " + std::to_string(sample_rate); + break; + } + + switch (bits_per_sample) { + case LE_AUDIO_BITS_PER_SAMPLE_INDEX_NONE: + bits_per_sample_str = "none"; + break; + case LE_AUDIO_BITS_PER_SAMPLE_INDEX_16: + bits_per_sample_str = "16"; + break; + case LE_AUDIO_BITS_PER_SAMPLE_INDEX_24: + bits_per_sample_str = "24"; + break; + case LE_AUDIO_BITS_PER_SAMPLE_INDEX_32: + bits_per_sample_str = "32"; + break; + default: + bits_per_sample_str = + "Unknown LE bits per sample " + std::to_string(bits_per_sample); + break; + } + + switch (channel_count) { + case LE_AUDIO_CHANNEL_COUNT_INDEX_NONE: + channel_count_str = "none"; + break; + case LE_AUDIO_CHANNEL_COUNT_INDEX_1: + channel_count_str = "1"; + break; + case LE_AUDIO_CHANNEL_COUNT_INDEX_2: + channel_count_str = "2"; + break; + default: + channel_count_str = + "Unknown LE channel count " + std::to_string(channel_count); + break; + } + + switch (frame_duration) { + case LE_AUDIO_FRAME_DURATION_INDEX_NONE: + frame_duration_str = "none"; + break; + case LE_AUDIO_FRAME_DURATION_INDEX_7500US: + frame_duration_str = "7500 us"; + break; + case LE_AUDIO_FRAME_DURATION_INDEX_10000US: + frame_duration_str = "10000 us"; + break; + default: + frame_duration_str = + "Unknown LE frame duration " + std::to_string(frame_duration); + break; + } + + if (octets_per_frame < 0) { + octets_per_frame_str = + "Unknown LE octets per frame " + std::to_string(octets_per_frame); + } else { + octets_per_frame_str = std::to_string(octets_per_frame); + } + + if (codec_priority < -1) { + codec_priority_str = + "Unknown LE codec priority " + std::to_string(codec_priority); + } else { + codec_priority_str = std::to_string(codec_priority); + } + + return "codec: " + codec_name_str + ", sample rate: " + sample_rate_str + + ", bits per sample: " + bits_per_sample_str + + ", channel count: " + channel_count_str + + ", frame duration: " + frame_duration_str + + ", octets per frame: " + octets_per_frame_str + + ", codec priroty: " + codec_priority_str; } + } btle_audio_codec_config_t; class LeAudioClientCallbacks { @@ -110,12 +287,24 @@ class LeAudioClientCallbacks { virtual void OnAudioLocalCodecCapabilities( std::vector local_input_capa_codec_conf, std::vector local_output_capa_codec_conf) = 0; - /* Callback with group codec configurations */ - virtual void OnAudioGroupCodecConf( + /* Callback with current group codec configurations. Should change when PACs + * changes */ + virtual void OnAudioGroupCurrentCodecConf( int group_id, btle_audio_codec_config_t input_codec_conf, - btle_audio_codec_config_t output_codec_conf, + btle_audio_codec_config_t output_codec_conf) = 0; + /* Callback with selectable group codec configurations. Should change when + * context changes */ + virtual void OnAudioGroupSelectableCodecConf( + int group_id, std::vector input_selectable_codec_conf, std::vector output_selectable_codec_conf) = 0; + virtual void OnHealthBasedRecommendationAction( + const RawAddress& address, LeAudioHealthBasedAction action) = 0; + virtual void OnHealthBasedGroupRecommendationAction( + int group_id, LeAudioHealthBasedAction action) = 0; + + virtual void OnUnicastMonitorModeStatus(uint8_t direction, + UnicastMonitorModeStatus status) = 0; }; class LeAudioClientInterface { @@ -162,6 +351,9 @@ class LeAudioClientInterface { /* Set In call flag */ virtual void SetInCall(bool in_call) = 0; + /* Set Sink listening mode flag */ + virtual void SetUnicastMonitorMode(uint8_t direction, bool enable) = 0; + /* Sends a preferred audio profiles change */ virtual void SendAudioProfilePreferences( int group_id, bool is_output_preference_le_audio, @@ -189,16 +381,19 @@ constexpr uint8_t kLeAudioMetadataTypeLanguage = 0x04; constexpr uint8_t kLeAudioMetadataTypeCcidList = 0x05; /* Codec specific LTV Types */ -constexpr uint8_t kLeAudioCodecLC3TypeSamplingFreq = 0x01; -constexpr uint8_t kLeAudioCodecLC3TypeFrameDuration = 0x02; -constexpr uint8_t kLeAudioCodecLC3TypeAudioChannelAllocation = 0x03; -constexpr uint8_t kLeAudioCodecLC3TypeOctetPerFrame = 0x04; -constexpr uint8_t kLeAudioCodecLC3TypeCodecFrameBlocksPerSdu = 0x05; +constexpr uint8_t kLeAudioLtvTypeSamplingFreq = 0x01; +constexpr uint8_t kLeAudioLtvTypeFrameDuration = 0x02; +constexpr uint8_t kLeAudioLtvTypeAudioChannelAllocation = 0x03; +constexpr uint8_t kLeAudioLtvTypeOctetsPerCodecFrame = 0x04; +constexpr uint8_t kLeAudioLtvTypeCodecFrameBlocksPerSdu = 0x05; /* Audio quality configuration in public broadcast announcement */ constexpr uint8_t kLeAudioQualityStandard = 0x1 << 1; constexpr uint8_t kLeAudioQualityHigh = 0x1 << 2; +/* Unknown RSSI value 0x7F - 127 */ +constexpr uint8_t kLeAudioSourceRssiUnknown = 0x7F; + struct BasicAudioAnnouncementCodecConfig { /* 5 octets for the Codec ID */ uint8_t codec_id; @@ -225,7 +420,7 @@ struct BasicAudioAnnouncementSubgroup { struct BasicAudioAnnouncementData { /* Announcement Header fields */ - uint32_t presentation_delay; + uint32_t presentation_delay_us; /* Subgroup specific configurations */ std::vector subgroup_configs; diff --git a/system/include/hardware/bt_sock.h b/system/include/hardware/bt_sock.h index a60571fdfe8691977ad8feafa971163c4cc3420e..7d5060e00593fc9ac835b6c2d90671aaf84d0c91 100644 --- a/system/include/hardware/bt_sock.h +++ b/system/include/hardware/bt_sock.h @@ -101,6 +101,12 @@ typedef struct { uint8_t discard_buffers, uint8_t break_signal_seq, bool fc); + /** + * Disconnect all RFCOMM and L2CAP socket connections with the associated + * device address. + */ + bt_status_t (*disconnect_all)(const RawAddress* bd_addr); + } btsock_interface_t; __END_DECLS diff --git a/android/app/src/com/android/bluetooth/pbapclient/Utils.java b/system/include/macros.h similarity index 75% rename from android/app/src/com/android/bluetooth/pbapclient/Utils.java rename to system/include/macros.h index c59d8d57199368956edeb3a04d25c253f04b296d..6acd3df460ffe4a67c47290b2eb9182554e76668 100644 --- a/android/app/src/com/android/bluetooth/pbapclient/Utils.java +++ b/system/include/macros.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.bluetooth.pbapclient; +#pragma once -class Utils { - static final boolean DBG = false; - static final boolean VDBG = false; -} +#define CASE_RETURN_TEXT(code) \ + case code: \ + return #code diff --git a/system/include/platform_ssl_mem.h b/system/include/platform_ssl_mem.h new file mode 100644 index 0000000000000000000000000000000000000000..854be7bc14ea3d7afe1fd13843740a60cb55cfe0 --- /dev/null +++ b/system/include/platform_ssl_mem.h @@ -0,0 +1,25 @@ +// Copyright 2023 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 + +// TODO(b/306474821) - Floss currently expects to link to openssl instead of +// boringssl. Since openssl doesn't have , point to the right +// header. +#ifdef TARGET_FLOSS +#include +#else +#include +#endif diff --git a/system/internal_include/bt_target.h b/system/internal_include/bt_target.h index 0c21baa7ce84cfaa42239d0fd5afe50c7ca80639..87bb256d369d622764efd19f5b9039d9664e6aa7 100644 --- a/system/internal_include/bt_target.h +++ b/system/internal_include/bt_target.h @@ -24,7 +24,7 @@ #define BUILDCFG #endif -#include "bt_types.h" /* This must be defined AFTER buildcfg.h */ +#include "stack/include/bt_types.h" /* This must be defined AFTER buildcfg.h */ #ifndef FALSE #define FALSE false @@ -85,11 +85,6 @@ #define BTA_AV_RET_TOUT 15 #endif -/* TRUE to use SCMS-T content protection */ -#ifndef BTA_AV_CO_CP_SCMS_T -#define BTA_AV_CO_CP_SCMS_T FALSE -#endif - #ifndef BTA_DM_SDP_DB_SIZE #define BTA_DM_SDP_DB_SIZE 20000 #endif @@ -250,14 +245,14 @@ * Initial SCO TX credit ************************/ /* The size of buffer used for TX SCO data packets. The size should be divisible - * by BTM_MSBC_CODE_SIZE(240) */ + * by BTM_MSBC_CODE_SIZE(240) and BTM_LC3_CODE_SIZE(480). */ #ifndef BTM_SCO_DATA_SIZE_MAX -#define BTM_SCO_DATA_SIZE_MAX 240 +#define BTM_SCO_DATA_SIZE_MAX 480 #endif /* The size in bytes of the BTM inquiry database. */ #ifndef BTM_INQ_DB_SIZE -#define BTM_INQ_DB_SIZE 40 +#define BTM_INQ_DB_SIZE 80 #endif /* Sets the Page_Scan_Window: the length of time that the device is performing @@ -271,7 +266,6 @@ #ifndef BTM_DEFAULT_CONN_INTERVAL #define BTM_DEFAULT_CONN_INTERVAL 0x0400 #endif -#define BTM_PAGE_SCAN_INTERVAL_PROPERTY "bluetooth.btm.pagescan_interval" /* When automatic inquiry scan is enabled, this sets the inquiry scan window. */ #ifndef BTM_DEFAULT_DISC_WINDOW @@ -374,11 +368,6 @@ #define SC_MODE_INCLUDED TRUE #endif -/* Used for conformance testing ONLY */ -#ifndef BTM_BLE_CONFORMANCE_TESTING -#define BTM_BLE_CONFORMANCE_TESTING FALSE -#endif - /****************************************************************************** * * L2CAP @@ -499,14 +488,6 @@ #define LOCAL_BLE_CONTROLLER_ID 1 #endif -/* - * Toggles support for vendor specific extensions such as RPA offloading, - * feature discovery, multi-adv etc. - */ -#ifndef BLE_VND_INCLUDED -#define BLE_VND_INCLUDED TRUE -#endif - /* The maximum number of simultaneous applications that can register with LE * L2CAP. */ #ifndef BLE_MAX_L2CAP_CLIENTS @@ -807,10 +788,6 @@ #define PAN_INCLUDED TRUE #endif -#ifndef PANU_DISABLED -#define PANU_DISABLED FALSE -#endif - /* This will enable the PANU role */ #ifndef PAN_SUPPORTS_ROLE_PANU #define PAN_SUPPORTS_ROLE_PANU TRUE @@ -857,25 +834,11 @@ * *****************************************************************************/ -#ifndef GAP_INCLUDED -#define GAP_INCLUDED TRUE -#endif - /* The maximum number of simultaneous GAP L2CAP connections. */ #ifndef GAP_MAX_CONNECTIONS #define GAP_MAX_CONNECTIONS 30 #endif -/* keep the raw data received from SDP server in database. */ -#ifndef SDP_RAW_DATA_INCLUDED -#define SDP_RAW_DATA_INCLUDED TRUE -#endif - -/* Inquiry duration in 1.28 second units. */ -#ifndef SDP_DEBUG -#define SDP_DEBUG TRUE -#endif - /****************************************************************************** * * HID @@ -978,33 +941,12 @@ #define BTA_EIR_SERVER_NUM_CUSTOM_UUID 8 #endif -/* CHLD override */ -#ifndef BTA_AG_CHLD_VAL_ECC -#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3)" -#endif - -#ifndef BTA_AG_CHLD_VAL -#define BTA_AG_CHLD_VAL "(0,1,2,3)" -#endif - -/* Set the CIND to match HFP 1.5 */ -#ifndef BTA_AG_CIND_INFO -#define BTA_AG_CIND_INFO \ - "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-1)),(\"signal\",(0-" \ - "5)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2))" -#endif - /****************************************************************************** * * Tracing: Include trace header file here. * *****************************************************************************/ -/* Enable/disable BTSnoop memory logging */ -#ifndef BTSNOOP_MEM -#define BTSNOOP_MEM TRUE -#endif - -#include "bt_trace.h" +#include "internal_include/bt_trace.h" #endif /* BT_TARGET_H */ diff --git a/system/internal_include/bt_trace.h b/system/internal_include/bt_trace.h index e623fe77fdadc8cfcf3e75dbef62419cf2ee6497..c6a91d1433010d4074f782479a95efafe06d1eb1 100644 --- a/system/internal_include/bt_trace.h +++ b/system/internal_include/bt_trace.h @@ -24,719 +24,8 @@ extern "C" { #endif -/*****************************************************************************/ - -/* Define trace levels */ -typedef enum { - BT_TRACE_LEVEL_NONE = 0, /* No trace messages to be generated */ - BT_TRACE_LEVEL_ERROR = 1, /* Error condition trace messages */ - BT_TRACE_LEVEL_WARNING = 2, /* Warning condition trace messages */ - BT_TRACE_LEVEL_API = 3, /* API traces */ - BT_TRACE_LEVEL_EVENT = 4, /* Debug messages for events */ - BT_TRACE_LEVEL_DEBUG = 5, /* Full debug messages */ - BT_TRACE_LEVEL_VERBOSE = 6, /* Verbose debug messages */ -} tLEGACY_TRACE_LEVEL; - -#define TRACE_CTRL_GENERAL 0x00000000 - -#define TRACE_LAYER_MASK 0x00ff0000 -#define TRACE_GET_LAYER(x) ((((uint32_t)(x)) & TRACE_LAYER_MASK) >> 16) - -#define TRACE_LAYER_NONE 0x00000000 -#define TRACE_LAYER_HCI 0x00070000 -#define TRACE_LAYER_L2CAP 0x00080000 -#define TRACE_LAYER_RFCOMM 0x00090000 -#define TRACE_LAYER_SDP 0x000a0000 -#define TRACE_LAYER_BTM 0x000d0000 -#define TRACE_LAYER_BNEP 0x001b0000 -#define TRACE_LAYER_PAN 0x001c0000 -#define TRACE_LAYER_HID 0x001e0000 -#define TRACE_LAYER_AVP 0x00200000 -#define TRACE_LAYER_A2DP 0x00210000 -#define TRACE_LAYER_SMP 0x00260000 - -#define TRACE_LAYER_MAX_NUM 0x0031 - -#define TRACE_ORG_MASK 0x0000ff00 -#define TRACE_GET_ORG(x) ((((uint32_t)(x)) & TRACE_ORG_MASK) >> 8) - -#define TRACE_ORG_STACK 0x00000000 -#define TRACE_ORG_APPL 0x00000500 -#define TRACE_ORG_USER_SCR 0x00000800 - -#define TRACE_TYPE_MASK 0x000000ff -#define TRACE_GET_TYPE(x) (((uint32_t)(x)) & TRACE_TYPE_MASK) - -#define TRACE_TYPE_ERROR 0x00000000 -#define TRACE_TYPE_WARNING 0x00000001 -#define TRACE_TYPE_API 0x00000002 -#define TRACE_TYPE_EVENT 0x00000003 -#define TRACE_TYPE_DEBUG 0x00000004 -#define TRACE_TYPE_INFO 0x00000005 - static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; -/* BTE tracing IDs for debug purposes */ -/* LayerIDs for stack */ -#define BTTRC_ID_STK_GKI 1 -#define BTTRC_ID_STK_BTU 2 -#define BTTRC_ID_STK_HCI 3 -#define BTTRC_ID_STK_L2CAP 4 -#define BTTRC_ID_STK_RFCM_MX 5 -#define BTTRC_ID_STK_RFCM_PRT 6 -#define BTTRC_ID_STK_OBEX_C 7 -#define BTTRC_ID_STK_OBEX_S 8 -#define BTTRC_ID_STK_AVCT 9 -#define BTTRC_ID_STK_AVDT 10 -#define BTTRC_ID_STK_AVRC 11 -#define BTTRC_ID_STK_BIC 12 -#define BTTRC_ID_STK_BIS 13 -#define BTTRC_ID_STK_BNEP 14 -#define BTTRC_ID_STK_BPP 15 -#define BTTRC_ID_STK_BTM_ACL 16 -#define BTTRC_ID_STK_BTM_PM 17 -#define BTTRC_ID_STK_BTM_DEV_CTRL 18 -#define BTTRC_ID_STK_BTM_SVC_DSC 19 -#define BTTRC_ID_STK_BTM_INQ 20 -#define BTTRC_ID_STK_BTM_SCO 21 -#define BTTRC_ID_STK_BTM_SEC 22 -#define BTTRC_ID_STK_HID 24 -#define BTTRC_ID_STK_HSP2 25 -#define BTTRC_ID_STK_CTP 26 -#define BTTRC_ID_STK_FTC 27 -#define BTTRC_ID_STK_FTS 28 -#define BTTRC_ID_STK_HCRP 31 -#define BTTRC_ID_STK_ICP 32 -#define BTTRC_ID_STK_OPC 33 -#define BTTRC_ID_STK_OPS 34 -#define BTTRC_ID_STK_PAN 35 -#define BTTRC_ID_STK_SAP 36 -#define BTTRC_ID_STK_SDP 37 -#define BTTRC_ID_STK_SLIP 38 -#define BTTRC_ID_STK_SPP 39 -#define BTTRC_ID_STK_TCS 40 -#define BTTRC_ID_STK_VDP 41 -#define BTTRC_ID_STK_MCAP 42 /* OBSOLETE */ -#define BTTRC_ID_STK_GATT 43 -#define BTTRC_ID_STK_SMP 44 -#define BTTRC_ID_STK_NFC 45 -#define BTTRC_ID_STK_NCI 46 -#define BTTRC_ID_STK_IDEP 47 -#define BTTRC_ID_STK_NDEP 48 -#define BTTRC_ID_STK_LLCP 49 -#define BTTRC_ID_STK_RW 50 -#define BTTRC_ID_STK_CE 51 -#define BTTRC_ID_STK_SNEP 52 -#define BTTRC_ID_STK_NDEF 53 -#define BTTRC_ID_STK_HIDD 54 - -/* LayerIDs for BTA */ -#define BTTRC_ID_BTA_ACC 55 /* Advanced Camera Client */ -#define BTTRC_ID_BTA_AG 56 /* audio gateway */ -#define BTTRC_ID_BTA_AV 57 /* Advanced audio */ -#define BTTRC_ID_BTA_BIC 58 /* Basic Imaging Client */ -#define BTTRC_ID_BTA_BIS 59 /* Basic Imaging Server */ -#define BTTRC_ID_BTA_BP 60 /* Basic Printing Client */ -#define BTTRC_ID_BTA_CG 61 -#define BTTRC_ID_BTA_CT 62 /* cordless telephony terminal */ -#define BTTRC_ID_BTA_DG 63 /* data gateway */ -#define BTTRC_ID_BTA_DM 64 /* device manager */ -#define BTTRC_ID_BTA_DM_SRCH 65 /* device manager search */ -#define BTTRC_ID_BTA_DM_SEC 66 /* device manager security */ -#define BTTRC_ID_BTA_FM 67 -#define BTTRC_ID_BTA_FTC 68 /* file transfer client */ -#define BTTRC_ID_BTA_FTS 69 /* file transfer server */ -#define BTTRC_ID_BTA_HIDH 70 -#define BTTRC_ID_BTA_HIDD 71 -#define BTTRC_ID_BTA_JV 72 -#define BTTRC_ID_BTA_OPC 73 /* object push client */ -#define BTTRC_ID_BTA_OPS 74 /* object push server */ -#define BTTRC_ID_BTA_PAN 75 /* Personal Area Networking */ -#define BTTRC_ID_BTA_PR 76 /* Printer client */ -#define BTTRC_ID_BTA_SC 77 /* SIM Card Access server */ -#define BTTRC_ID_BTA_SS 78 /* synchronization server */ -#define BTTRC_ID_BTA_SYS 79 /* system manager */ -#define BTTRC_ID_AVDT_SCB 80 /* avdt scb */ -#define BTTRC_ID_AVDT_CCB 81 /* avdt ccb */ - -/* LayerIDs added for BTL-A. Probably should modify bte_logmsg.cc in future. */ -#define BTTRC_ID_STK_RFCOMM 82 -#define BTTRC_ID_STK_RFCOMM_DATA 83 -#define BTTRC_ID_STK_OBEX 84 -#define BTTRC_ID_STK_A2DP 85 -#define BTTRC_ID_STK_BIP 86 - -/* LayerIDs for BT APP */ -#define BTTRC_ID_BTAPP 87 -/* this is a temporary solution to allow dynamic enable/disable of - * BT_PROTOCOL_TRACE */ -#define BTTRC_ID_BT_PROTOCOL 88 -#define BTTRC_ID_MAX_ID BTTRC_ID_BT_PROTOCOL -#define BTTRC_ID_ALL_LAYERS 0xFF /* all trace layers */ - -/****************************************************************************** - * - * Trace Levels - * - * The following values may be used for different levels: - * BT_TRACE_LEVEL_NONE 0 * No trace messages to be generated - * BT_TRACE_LEVEL_ERROR 1 * Error condition trace messages - * BT_TRACE_LEVEL_WARNING 2 * Warning condition trace messages - * BT_TRACE_LEVEL_API 3 * API traces - * BT_TRACE_LEVEL_EVENT 4 * Debug messages for events - * BT_TRACE_LEVEL_DEBUG 5 * Debug messages (general) - *****************************************************************************/ - -/* Core Stack default trace levels */ -#ifndef HCI_INITIAL_TRACE_LEVEL -#define HCI_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef BTM_INITIAL_TRACE_LEVEL -#define BTM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef L2CAP_INITIAL_TRACE_LEVEL -#define L2CAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef RFCOMM_INITIAL_TRACE_LEVEL -#define RFCOMM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef BNEP_INITIAL_TRACE_LEVEL -#define BNEP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef PAN_INITIAL_TRACE_LEVEL -#define PAN_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef A2DP_INITIAL_TRACE_LEVEL -#define A2DP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef AVDT_INITIAL_TRACE_LEVEL -#define AVDT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef AVCT_INITIAL_TRACE_LEVEL -#define AVCT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef AVRC_INITIAL_TRACE_LEVEL -#define AVRC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef HID_INITIAL_TRACE_LEVEL -#define HID_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef APPL_INITIAL_TRACE_LEVEL -#define APPL_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef GATT_INITIAL_TRACE_LEVEL -#define GATT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#ifndef SMP_INITIAL_TRACE_LEVEL -#define SMP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING -#endif - -#define BT_TRACE(l, t, ...) \ - LogMsg((TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t)), ##__VA_ARGS__) - -/* Define tracing for the HCI unit */ -#define HCI_TRACE_ERROR(...) \ - { \ - if (btu_trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define HCI_TRACE_WARNING(...) \ - { \ - if (btu_trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define HCI_TRACE_EVENT(...) \ - { \ - if (btu_trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define HCI_TRACE_DEBUG(...) \ - { \ - if (btu_trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -/* Define tracing for BTM */ -#define BTM_TRACE_ERROR(...) \ - { \ - if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define BTM_TRACE_WARNING(...) \ - { \ - if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define BTM_TRACE_API(...) \ - { \ - if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define BTM_TRACE_EVENT(...) \ - { \ - if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define BTM_TRACE_DEBUG(...) \ - { \ - if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -/* Define tracing for the L2CAP unit */ -#define L2CAP_TRACE_ERROR(...) \ - { \ - if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define L2CAP_TRACE_WARNING(...) \ - { \ - if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define L2CAP_TRACE_API(...) \ - { \ - if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define L2CAP_TRACE_EVENT(...) \ - { \ - if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define L2CAP_TRACE_DEBUG(...) \ - { \ - if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -/* Define tracing for the SDP unit */ -#define SDP_TRACE_ERROR(...) \ - { \ - if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define SDP_TRACE_WARNING(...) \ - { \ - if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define SDP_TRACE_API(...) \ - { \ - if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define SDP_TRACE_EVENT(...) \ - { \ - if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define SDP_TRACE_DEBUG(...) \ - { \ - if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } -#define SDP_TRACE_INFO(...) \ - { \ - if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_INFO, ##__VA_ARGS__); \ - } - -/* Define tracing for the RFCOMM unit */ -#define RFCOMM_TRACE_ERROR(...) \ - { \ - if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define RFCOMM_TRACE_WARNING(...) \ - { \ - if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define RFCOMM_TRACE_API(...) \ - { \ - if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define RFCOMM_TRACE_EVENT(...) \ - { \ - if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define RFCOMM_TRACE_DEBUG(...) \ - { \ - if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -/* define traces for HID Host */ -#define HIDH_TRACE_ERROR(...) \ - { \ - if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define HIDH_TRACE_WARNING(...) \ - { \ - if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define HIDH_TRACE_API(...) \ - { \ - if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define HIDH_TRACE_EVENT(...) \ - { \ - if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define HIDH_TRACE_DEBUG(...) \ - { \ - if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -/* define traces for HID Device */ -#define HIDD_TRACE_ERROR(...) \ - { \ - if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define HIDD_TRACE_WARNING(...) \ - { \ - if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define HIDD_TRACE_API(...) \ - { \ - if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define HIDD_TRACE_EVENT(...) \ - { \ - if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define HIDD_TRACE_DEBUG(...) \ - { \ - if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } -#define HIDD_TRACE_VERBOSE(...) \ - { \ - if (hd_cb.trace_level >= BT_TRACE_LEVEL_VERBOSE) \ - BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -/* define traces for BNEP */ -#define BNEP_TRACE_ERROR(...) \ - { \ - if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define BNEP_TRACE_WARNING(...) \ - { \ - if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define BNEP_TRACE_API(...) \ - { \ - if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define BNEP_TRACE_EVENT(...) \ - { \ - if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define BNEP_TRACE_DEBUG(...) \ - { \ - if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -/* define traces for PAN */ -#define PAN_TRACE_ERROR(...) \ - { \ - if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define PAN_TRACE_WARNING(...) \ - { \ - if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define PAN_TRACE_API(...) \ - { \ - if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define PAN_TRACE_EVENT(...) \ - { \ - if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define PAN_TRACE_DEBUG(...) \ - { \ - if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -/* Define tracing for the A2DP profile */ -#define A2DP_TRACE_ERROR(...) \ - { \ - if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define A2DP_TRACE_WARNING(...) \ - { \ - if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define A2DP_TRACE_EVENT(...) \ - { \ - if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define A2DP_TRACE_DEBUG(...) \ - { \ - if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } -#define A2DP_TRACE_API(...) \ - { \ - if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_API, ##__VA_ARGS__); \ - } - -/* AVDTP */ -#define AVDT_TRACE_ERROR(...) \ - { \ - if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define AVDT_TRACE_WARNING(...) \ - { \ - if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define AVDT_TRACE_EVENT(...) \ - { \ - if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define AVDT_TRACE_DEBUG(...) \ - { \ - if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } -#define AVDT_TRACE_API(...) \ - { \ - if (avdtp_cb.TraceLevel() >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \ - } - -/* Define tracing for the AVCTP protocol */ -#define AVCT_TRACE_ERROR(...) \ - { \ - if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define AVCT_TRACE_WARNING(...) \ - { \ - if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define AVCT_TRACE_EVENT(...) \ - { \ - if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define AVCT_TRACE_DEBUG(...) \ - { \ - if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } -#define AVCT_TRACE_API(...) \ - { \ - if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \ - } - -/* Define tracing for the AVRCP profile */ -#define AVRC_TRACE_ERROR(...) \ - { \ - if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define AVRC_TRACE_WARNING(...) \ - { \ - if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define AVRC_TRACE_EVENT(...) \ - { \ - if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define AVRC_TRACE_DEBUG(...) \ - { \ - if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } -#define AVRC_TRACE_API(...) \ - { \ - if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \ - } - -/* Define tracing for the SMP unit */ -#define SMP_TRACE_ERROR(...) \ - { \ - if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ - BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \ - } -#define SMP_TRACE_WARNING(...) \ - { \ - if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \ - BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \ - } -#define SMP_TRACE_API(...) \ - { \ - if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) \ - BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_API, ##__VA_ARGS__); \ - } -#define SMP_TRACE_EVENT(...) \ - { \ - if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \ - BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \ - } -#define SMP_TRACE_DEBUG(...) \ - { \ - if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \ - BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \ - } - -extern uint8_t btif_trace_level; - -/* define traces for application */ -#define BTIF_TRACE_ERROR(...) \ - { \ - if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_ERROR, \ - ##__VA_ARGS__); \ - } -#define BTIF_TRACE_WARNING(...) \ - { \ - if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_WARNING, \ - ##__VA_ARGS__); \ - } -#define BTIF_TRACE_API(...) \ - { \ - if (btif_trace_level >= BT_TRACE_LEVEL_API) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_API, \ - ##__VA_ARGS__); \ - } -#define BTIF_TRACE_EVENT(...) \ - { \ - if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_EVENT, \ - ##__VA_ARGS__); \ - } -#define BTIF_TRACE_DEBUG(...) \ - { \ - if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_DEBUG, \ - ##__VA_ARGS__); \ - } -#define BTIF_TRACE_VERBOSE(...) \ - { \ - if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_DEBUG, \ - ##__VA_ARGS__); \ - } - -/* define traces for application */ -#define APPL_TRACE_ERROR(...) \ - { \ - if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_ERROR, \ - ##__VA_ARGS__); \ - } -#define APPL_TRACE_WARNING(...) \ - { \ - if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_WARNING, \ - ##__VA_ARGS__); \ - } -#define APPL_TRACE_API(...) \ - { \ - if (appl_trace_level >= BT_TRACE_LEVEL_API) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_API, \ - ##__VA_ARGS__); \ - } -#define APPL_TRACE_EVENT(...) \ - { \ - if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_EVENT, \ - ##__VA_ARGS__); \ - } -#define APPL_TRACE_DEBUG(...) \ - { \ - if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_DEBUG, \ - ##__VA_ARGS__); \ - } -#define APPL_TRACE_VERBOSE(...) \ - { \ - if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE) \ - LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \ - TRACE_TYPE_DEBUG, \ - ##__VA_ARGS__); \ - } - -typedef uint8_t tBTTRC_LAYER_ID; -typedef uint8_t(tBTTRC_SET_TRACE_LEVEL)(uint8_t); - -typedef struct { - const tBTTRC_LAYER_ID layer_id_start; - const tBTTRC_LAYER_ID layer_id_end; - tBTTRC_SET_TRACE_LEVEL* p_f; - const char* trc_name; - uint8_t trace_level; -} tBTTRC_FUNC_MAP; - -/* External declaration for appl_trace_level here to avoid to add the - * declaration in all the files using APPL_TRACExxx macros */ -extern uint8_t appl_trace_level; - -void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...); - #ifdef __cplusplus } #endif @@ -806,53 +95,4 @@ inline std::string& AppendField(std::string* p_result, bool append, return *p_result; } -// This object puts the stream in a state where every time that a new line -// occurs, the next line is indented a certain number of spaces. The stream is -// reset to its previous state when the object is destroyed. -class ScopedIndent { - public: - ScopedIndent(std::ostream& stream, int indent_size = DEFAULT_TAB) - : indented_buf_(stream, indent_size) { - old_stream_ = &stream; - old_stream_buf_ = stream.rdbuf(); - stream.rdbuf(&indented_buf_); - } - - ~ScopedIndent() { old_stream_->rdbuf(old_stream_buf_); } - - static const size_t DEFAULT_TAB = 2; - - private: - class IndentedStreamBuf : public std::streambuf { - public: - IndentedStreamBuf(std::ostream& stream, int indent_size) - : wrapped_buf_(stream.rdbuf()), - indent_size_(indent_size), - indent_next_line_(true){}; - - protected: - virtual int overflow(int character) override { - if (indent_next_line_ && character != '\n') { - for (int i = 0; i < indent_size_; i++) wrapped_buf_->sputc(' '); - } - - indent_next_line_ = false; - if (character == '\n') { - indent_next_line_ = true; - } - - return wrapped_buf_->sputc(character); - } - - private: - std::streambuf* wrapped_buf_; - int indent_size_; - bool indent_next_line_; - }; - - std::ostream* old_stream_; - std::streambuf* old_stream_buf_; - IndentedStreamBuf indented_buf_; -}; - #endif diff --git a/system/internal_include/stack_config.h b/system/internal_include/stack_config.h index efaec3f700ec3b64e2b4f408ab8a7949df9f6c70..febd2a37e242dff100faa7dc8c7af944e92b0bb7 100644 --- a/system/internal_include/stack_config.h +++ b/system/internal_include/stack_config.h @@ -26,7 +26,6 @@ static const char STACK_CONFIG_MODULE[] = "stack_config_module"; typedef struct { - bool (*get_trace_config_enabled)(void); bool (*get_pts_avrcp_test)(void); bool (*get_pts_secure_only_mode)(void); bool (*get_pts_conn_updates_disabled)(void); diff --git a/system/main/Android.bp b/system/main/Android.bp index 68586303bd5201c2d28eba40ab6d01e956785fcb..3242b155074a30059a9267e6e447a8d1f103ff3c 100644 --- a/system/main/Android.bp +++ b/system/main/Android.bp @@ -14,14 +14,13 @@ filegroup { "bte_conf.cc", "bte_init_cpp_logging.cc", "bte_logmsg.cc", - "bte_main.cc", "stack_config.cc", ], } cc_library_static { name: "libbte", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], srcs: [ ":LibBluetoothShimSources", ":LibBluetoothSources", @@ -37,7 +36,6 @@ cc_library_static { "packages/modules/Bluetooth/system/embdrv/sbc/decoder/include", "packages/modules/Bluetooth/system/embdrv/sbc/encoder/include", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/stack/a2dp", "packages/modules/Bluetooth/system/stack/avdt", @@ -45,16 +43,24 @@ cc_library_static { "packages/modules/Bluetooth/system/stack/include", "packages/modules/Bluetooth/system/stack/l2cap", "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/include", "system/security/keystore/include", ], generated_headers: [ "BluetoothGeneratedBundlerSchema_h_bfbs", "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", + ], + apex_available: [ + "com.android.btservices", ], host_supported: true, min_sdk_version: "Tiramisu", + static_libs: [ + "libbluetooth_gd", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + ], + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_library { @@ -64,7 +70,7 @@ cc_library { "//packages/modules/Bluetooth:__subpackages__", "//vendor:__subpackages__", ], - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], header_libs: ["libbluetooth_headers"], export_header_lib_headers: ["libbluetooth_headers"], include_dirs: [ @@ -84,13 +90,19 @@ cc_library { "packages/modules/Bluetooth/system/stack/include", "packages/modules/Bluetooth/system/stack/l2cap", "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/include", "system/security/keystore/include", ], shared_libs: [ "android.hardware.bluetooth@1.0", "android.hardware.bluetooth@1.1", ], + target: { + android: { + shared_libs: [ + "libstatssocket", + ], + }, + }, // Shared library link options. // References to global symbols and functions should bind to the library // itself. This is to avoid issues with some of the unit/system tests @@ -124,35 +136,37 @@ cc_library_static { "packages/modules/Bluetooth/system/bta/include", "packages/modules/Bluetooth/system/btif/include", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/stack/include", ], generated_headers: [ "BluetoothGeneratedBundlerSchema_h_bfbs", "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], shared_libs: [ - "libflatbuffers-cpp", ], whole_static_libs: [ "libbluetooth_gd", // Gabeldorsche ], + header_libs: ["libbluetooth_headers"], + static_libs: [ + "libbt-platform-protos-lite", + "libbt_shim_bridge", + ], } cc_test { name: "net_test_main_shim", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, }, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -168,6 +182,7 @@ cc_test { ":TestCommonMockFunctions", ":TestMockBta", ":TestMockBtif", + ":TestMockBtu", ":TestMockLegacyHciCommands", ":TestMockLegacyHciInterface", ":TestMockMainShimEntry", @@ -196,8 +211,14 @@ cc_test { ], static_libs: [ "libbluetooth-dumpsys", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_hci_pdl", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libchrome", "libevent", @@ -208,6 +229,7 @@ cc_test { ], shared_libs: [ "libcrypto", + "server_configurable_flags", ], sanitize: { address: true, @@ -222,7 +244,8 @@ cc_test { generated_headers: [ "BluetoothGeneratedBundlerSchema_h_bfbs", "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], min_sdk_version: "Tiramisu", + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/main/BUILD.gn b/system/main/BUILD.gn index 8d6e2cb4a6dbf113430175f07f7c759d66f62446..b71e538c1dcf8fb718fa527d783d903909d1ed73 100644 --- a/system/main/BUILD.gn +++ b/system/main/BUILD.gn @@ -48,7 +48,6 @@ target(lib_type, "bluetooth") { "bte_conf.cc", "bte_init_cpp_logging.cc", "bte_logmsg.cc", - "bte_main.cc", "stack_config.cc", ] @@ -69,7 +68,6 @@ target(lib_type, "bluetooth") { "//bt/system/udrv/include", "//bt/system/btif/include", "//bt/system/btif/co", - "//bt/system/hci/includ", "//bt/system/vnd/include", "//bt/system/brcm/include", "//bt/system/embdrv/sbc/encoder/include", diff --git a/system/main/bte_logmsg.cc b/system/main/bte_logmsg.cc index 07f8980ce3dc46215d4a5f5ee0b2cfc646159566..a27c5b1542edb2e45cf23fedde7407844f2afeac 100644 --- a/system/main/bte_logmsg.cc +++ b/system/main/bte_logmsg.cc @@ -24,118 +24,10 @@ #include "internal_include/bt_trace.h" #include "internal_include/stack_config.h" #include "main/main_int.h" -#include "osi/include/log.h" - -#ifndef BTE_LOG_BUF_SIZE -#define BTE_LOG_BUF_SIZE 256 -#endif - -#define BTE_LOG_MAX_SIZE (BTE_LOG_BUF_SIZE - 12) - -#define MSG_BUFFER_OFFSET 0 - -/* LayerIDs for BTA, currently everything maps onto appl_trace_level */ -static const char* const bt_layer_tags[] = { - "bt_btif", - "bt_usb", - "bt_serial", - "bt_socket", - "bt_rs232", - "bt_lc", - "bt_lm", - "bt_hci", - "bt_l2cap", - "bt_rfcomm", - "bt_sdp", - "bt_tcs", - "bt_obex", - "bt_btm", - "bt_gap", - "UNUSED", - "UNUSED", - "bt_icp", - "bt_hsp2", - "bt_spp", - "bt_ctp", - "bt_bpp", - "bt_hcrp", - "bt_ftp", - "bt_opp", - "bt_btu", - "bt_gki_deprecated", - "bt_bnep", - "bt_pan", - "bt_hfp", - "bt_hid", - "bt_bip", - "bt_avp", - "bt_a2d", - "bt_sap", - "bt_amp", - "bt_mca_deprecated", - "bt_att", - "bt_smp", - "bt_nfc", - "bt_nci", - "bt_idep", - "bt_ndep", - "bt_llcp", - "bt_rw", - "bt_ce", - "bt_snep", - "bt_ndef", - "bt_nfa", -}; - -void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) { - char buffer[BTE_LOG_BUF_SIZE]; - int trace_layer = TRACE_GET_LAYER(trace_set_mask); - if (trace_layer >= TRACE_LAYER_MAX_NUM) trace_layer = 0; - - va_list ap; - va_start(ap, fmt_str); - vsnprintf(&buffer[MSG_BUFFER_OFFSET], BTE_LOG_MAX_SIZE, fmt_str, ap); - va_end(ap); - -#undef LOG_TAG -#define LOG_TAG bt_layer_tags[trace_layer] - - switch (TRACE_GET_TYPE(trace_set_mask)) { - case TRACE_TYPE_ERROR: - LOG_ERROR("%s", buffer); - break; - case TRACE_TYPE_WARNING: - LOG_WARN("%s", buffer); - break; - case TRACE_TYPE_API: - case TRACE_TYPE_EVENT: - LOG_INFO("%s", buffer); - break; - case TRACE_TYPE_DEBUG: - LOG_INFO("%s", buffer); - break; - case TRACE_TYPE_INFO: - LOG_INFO("%s", buffer); - break; - default: - /* we should never get this */ - LOG_ERROR("!BAD TRACE TYPE! %s", buffer); - CHECK(TRACE_GET_TYPE(trace_set_mask) == TRACE_TYPE_ERROR); - break; - } -#undef LOG_TAG -#define LOG_TAG "bt_bte" -} static future_t* init(void) { const stack_config_t* stack_config = stack_config_get_interface(); - if (!stack_config->get_trace_config_enabled()) { - LOG_INFO("using compile default trace settings"); - return NULL; - } - init_cpp_logging(stack_config->get_all()); - return NULL; } diff --git a/system/main/bte_main.cc b/system/main/bte_main.cc deleted file mode 100644 index c9e93653e2ebca31259bea203df00f4ade29c471..0000000000000000000000000000000000000000 --- a/system/main/bte_main.cc +++ /dev/null @@ -1,111 +0,0 @@ -/****************************************************************************** - * - * Copyright 2009-2012 Broadcom Corporation - * - * 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. - * - ******************************************************************************/ - -/****************************************************************************** - * - * Filename: bte_main.cc - * - * Description: Contains BTE core stack initialization and shutdown code - * - ******************************************************************************/ - -#define LOG_TAG "bt_main" - -#include -#include - -#include "btcore/include/module.h" -#include "btif/include/btif_config.h" -#include "btu.h" -#include "hci/include/hci_layer.h" -#include "main/shim/hci_layer.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "shim/hci_layer.h" -#include "shim/shim.h" -#include "stack/include/bt_hdr.h" -#include "stack_config.h" - -/******************************************************************************* - * Static variables - ******************************************************************************/ -static const hci_t* hci; - -/******************************************************************************* - * Externs - ******************************************************************************/ -void btu_hci_msg_process(BT_HDR* p_msg); - -/******************************************************************************* - * Static functions - ******************************************************************************/ - -/****************************************************************************** - * - * Function post_to_hci_message_loop - * - * Description Post an HCI event to the main thread - * - * Returns None - * - *****************************************************************************/ -static void post_to_main_message_loop(const base::Location& from_here, - BT_HDR* p_msg) { - if (do_in_main_thread(from_here, base::Bind(&btu_hci_msg_process, p_msg)) != - BT_STATUS_SUCCESS) { - LOG(ERROR) << __func__ << ": do_in_main_thread failed from " - << from_here.ToString(); - } -} - -void bte_main_init(void) { - hci = bluetooth::shim::hci_layer_get_interface(); - if (!hci) { - LOG_ERROR("%s could not get hci layer interface.", __func__); - return; - } - - hci->set_data_cb(base::Bind(&post_to_main_message_loop)); -} - -/****************************************************************************** - * - * Function bte_main_hci_send - * - * Description BTE MAIN API - This function is called by the upper stack to - * send an HCI message. The function displays a protocol trace - * message (if enabled), and then calls the 'transmit' function - * associated with the currently selected HCI transport - * - * Returns None - * - *****************************************************************************/ -void bte_main_hci_send(BT_HDR* p_msg, uint16_t event) { - uint16_t sub_event = event & BT_SUB_EVT_MASK; /* local controller ID */ - - p_msg->event = event; - - if ((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || - (sub_event == LOCAL_BLE_CONTROLLER_ID)) { - hci->transmit_downward(event, p_msg); - } else { - APPL_TRACE_ERROR("Invalid Controller ID. Discarding message."); - osi_free(p_msg); - } -} diff --git a/system/main/shim/Android.bp b/system/main/shim/Android.bp index bf9a9ab060e2cb616b71a3e4af308b1133ad0434..ae14e4fc99a4445ecf85ceeb2d87a6ad071db2fa 100644 --- a/system/main/shim/Android.bp +++ b/system/main/shim/Android.bp @@ -13,7 +13,6 @@ filegroup { "acl.cc", "acl_api.cc", "acl_legacy_interface.cc", - "activity_attribution.cc", "btm.cc", "btm_api.cc", "config.cc", diff --git a/system/main/shim/BUILD.gn b/system/main/shim/BUILD.gn index 2bd11d78fa0d4ea186d4acc701788d3c18b023ed..fb6ba62a01217905b8404be1a80ec1c22b7fb85d 100644 --- a/system/main/shim/BUILD.gn +++ b/system/main/shim/BUILD.gn @@ -19,7 +19,6 @@ source_set("LibBluetoothShimSources") { "acl.cc", "acl_api.cc", "acl_legacy_interface.cc", - "activity_attribution.cc", "btm.cc", "btm_api.cc", "config.cc", @@ -50,7 +49,6 @@ source_set("LibBluetoothShimSources") { deps = [ "//bt/system/gd:BluetoothGeneratedDumpsysDataSchema_h", - "//bt/system/gd:BluetoothGeneratedPackets_h", "//bt/system/gd/common:BluetoothCommonSources", "//bt/system/gd/dumpsys/bundler:BluetoothGeneratedBundlerSchema_h_bfbs", "//bt/system/gd/hci:BluetoothHciSources", @@ -59,6 +57,7 @@ source_set("LibBluetoothShimSources") { "//bt/system/gd/rust/shim:libbluetooth_rust_interop", "//bt/system/gd/rust/topshim:libbluetooth_topshim", "//bt/system/osi", + "//bt/system/pdl:BluetoothGeneratedPackets_h", "//bt/system/stack", "//bt/system/types", ] diff --git a/system/main/shim/acl.cc b/system/main/shim/acl.cc index b44315227db6e8a71ba7921bd259f13ff15785be..04977b8e8732e8a67f2c43e8d29971d5c7b464ea 100644 --- a/system/main/shim/acl.cc +++ b/system/main/shim/acl.cc @@ -30,12 +30,9 @@ #include #include -#include "btif/include/btif_hh.h" #include "common/interfaces/ILoggable.h" #include "device/include/controller.h" -#include "gd/common/bidi_queue.h" #include "gd/common/bind.h" -#include "gd/common/init_flags.h" #include "gd/common/strings.h" #include "gd/common/sync_map_count.h" #include "gd/hci/acl_manager.h" @@ -44,14 +41,12 @@ #include "gd/hci/acl_manager/connection_management_callbacks.h" #include "gd/hci/acl_manager/le_acl_connection.h" #include "gd/hci/acl_manager/le_connection_management_callbacks.h" -#include "gd/hci/acl_manager/le_impl.h" #include "gd/hci/address.h" #include "gd/hci/address_with_type.h" #include "gd/hci/class_of_device.h" #include "gd/hci/controller.h" #include "gd/os/handler.h" -#include "gd/os/queue.h" -#include "main/shim/btm.h" +#include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" @@ -59,23 +54,16 @@ #include "osi/include/allocator.h" #include "stack/acl/acl.h" #include "stack/btm/btm_int_types.h" -#include "stack/include/acl_hci_link_interface.h" -#include "stack/include/ble_acl_interface.h" +#include "stack/btm/btm_sec_cb.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_api.h" -#include "stack/include/btm_status.h" -#include "stack/include/gatt_api.h" -#include "stack/include/pan_api.h" -#include "stack/include/sec_hci_link_interface.h" +#include "stack/include/btm_log_history.h" +#include "stack/include/main_thread.h" #include "stack/l2cap/l2c_int.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" extern tBTM_CB btm_cb; -bt_status_t do_in_main_thread(const base::Location& from_here, - base::OnceClosure task); - using namespace bluetooth; class ConnectAddressWithType : public bluetooth::common::IRedactableLoggable { @@ -373,13 +361,13 @@ void ValidateAclInterface(const shim::legacy::acl_interface_t& acl_interface) { } // namespace -#define TRY_POSTING_ON_MAIN(cb, ...) \ - do { \ - if (cb == nullptr) { \ - LOG_WARN("Dropping ACL event with no callback"); \ - } else { \ - do_in_main_thread(FROM_HERE, base::Bind(cb, ##__VA_ARGS__)); \ - } \ +#define TRY_POSTING_ON_MAIN(cb, ...) \ + do { \ + if (cb == nullptr) { \ + LOG_WARN("Dropping ACL event with no callback"); \ + } else { \ + do_in_main_thread(FROM_HERE, base::BindOnce(cb, ##__VA_ARGS__)); \ + } \ } while (0) constexpr HciHandle kInvalidHciHandle = 0xffff; @@ -439,7 +427,7 @@ class ShimAclConnection { LOG_WARN("Dropping ACL data with no callback"); osi_free(p_buf); } else if (do_in_main_thread(FROM_HERE, - base::Bind(send_data_upwards_, p_buf)) != + base::BindOnce(send_data_upwards_, p_buf)) != BT_STATUS_SUCCESS) { osi_free(p_buf); } @@ -763,6 +751,18 @@ class LeShimAclConnection return connection_->GetLocalAddress(); } + bluetooth::hci::AddressWithType GetLocalOtaAddressWithType() { + return connection_->GetLocalOtaAddress(); + } + + bluetooth::hci::AddressWithType GetPeerAddressWithType() { + return connection_->GetPeerAddress(); + } + + bluetooth::hci::AddressWithType GetPeerOtaAddressWithType() { + return connection_->GetPeerOtaAddress(); + } + std::optional GetAdvertisingSetConnectedTo() { return std::visit( [](auto&& data) { @@ -814,15 +814,9 @@ class LeShimAclConnection void OnPhyUpdate(hci::ErrorCode hci_status, uint8_t tx_phy, uint8_t rx_phy) override { - if (common::init_flags::pass_phy_update_callback_is_enabled()) { - TRY_POSTING_ON_MAIN( - interface_.on_phy_update, - static_cast(ToLegacyHciErrorCode(hci_status)), handle_, - tx_phy, rx_phy); - } else { - LOG_WARN("Not posting OnPhyUpdate callback since it is disabled: (tx:%x, rx:%x, status:%s)", - tx_phy, rx_phy, hci::ErrorCodeText(hci_status).c_str()); - } + TRY_POSTING_ON_MAIN(interface_.on_phy_update, + ToLegacyHciErrorCode(hci_status), handle_, tx_phy, + rx_phy); } void OnDisconnection(hci::ErrorCode reason) { @@ -1116,7 +1110,7 @@ struct shim::legacy::Acl::impl { } void le_rand(LeRandCallback cb ) { - controller_get_interface()->le_rand(cb); + controller_get_interface()->le_rand(std::move(cb)); } void AddToAddressResolution(const hci::AddressWithType& address_with_type, @@ -1312,14 +1306,14 @@ void DumpsysBtm(int fd) { void DumpsysRecord(int fd) { LOG_DUMPSYS_TITLE(fd, DUMPSYS_TAG); - if (btm_cb.sec_dev_rec == nullptr) { + if (btm_sec_cb.sec_dev_rec == nullptr) { LOG_DUMPSYS(fd, "Record is empty - no devices"); return; } unsigned cnt = 0; - list_node_t* end = list_end(btm_cb.sec_dev_rec); - for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end; + list_node_t* end = list_end(btm_sec_cb.sec_dev_rec); + for (list_node_t* node = list_begin(btm_sec_cb.sec_dev_rec); node != end; node = list_next(node)) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(list_node(node)); @@ -1523,19 +1517,41 @@ void shim::legacy::Acl::OnClassicLinkDisconnected(HciHandle handle, kBtmLogTag, ToRawAddress(remote_address), "Disconnected", base::StringPrintf("classic reason:%s", ErrorCodeText(reason).c_str())); pimpl_->connection_history_.Push( - std::move(std::make_unique( + std::make_unique( remote_address, creation_time, teardown_time, handle, - is_locally_initiated, reason))); + is_locally_initiated, reason)); } bluetooth::hci::AddressWithType shim::legacy::Acl::GetConnectionLocalAddress( - const RawAddress& remote_bda) { + uint16_t handle, bool ota_address) { bluetooth::hci::AddressWithType address_with_type; - auto remote_address = ToGdAddress(remote_bda); - for (auto& [handle, connection] : pimpl_->handle_to_le_connection_map_) { - if (connection->GetRemoteAddressWithType().GetAddress() == remote_address) { - return connection->GetLocalAddressWithType(); + + for (auto& [acl_handle, connection] : pimpl_->handle_to_le_connection_map_) { + if (acl_handle != handle) { + continue; + } + + if (ota_address) { + return connection->GetLocalOtaAddressWithType(); } + return connection->GetLocalAddressWithType(); + } + LOG_WARN("address not found!"); + return address_with_type; +} + +bluetooth::hci::AddressWithType shim::legacy::Acl::GetConnectionPeerAddress( + uint16_t handle, bool ota_address) { + bluetooth::hci::AddressWithType address_with_type; + for (auto& [acl_handle, connection] : pimpl_->handle_to_le_connection_map_) { + if (acl_handle != handle) { + continue; + } + + if (ota_address) { + return connection->GetPeerOtaAddressWithType(); + } + return connection->GetPeerAddressWithType(); } LOG_WARN("address not found!"); return address_with_type; @@ -1575,10 +1591,9 @@ void shim::legacy::Acl::OnLeLinkDisconnected(HciHandle handle, kBtmLogTag, ToLegacyAddressWithType(remote_address_with_type), "Disconnected", base::StringPrintf("Le reason:%s", ErrorCodeText(reason).c_str())); - pimpl_->connection_history_.Push( - std::move(std::make_unique( - remote_address_with_type, creation_time, teardown_time, handle, - is_locally_initiated, reason))); + pimpl_->connection_history_.Push(std::make_unique( + remote_address_with_type, creation_time, teardown_time, handle, + is_locally_initiated, reason)); } void shim::legacy::Acl::OnConnectSuccess( @@ -1900,7 +1915,7 @@ void shim::legacy::Acl::ClearFilterAcceptList() { } void shim::legacy::Acl::LeRand(LeRandCallback cb) { - handler_->CallOn(pimpl_.get(), &Acl::impl::le_rand, cb); + handler_->CallOn(pimpl_.get(), &Acl::impl::le_rand, std::move(cb)); } void shim::legacy::Acl::AddToAddressResolution( diff --git a/system/main/shim/acl.h b/system/main/shim/acl.h index 8a8c6266f64130f36f5628053215463cffa6c458..eadb465bd67a50ae22749e89133efd9f3b533d9f 100644 --- a/system/main/shim/acl.h +++ b/system/main/shim/acl.h @@ -29,10 +29,9 @@ #include "main/shim/acl_legacy_interface.h" #include "main/shim/link_connection_interface.h" #include "main/shim/link_policy_interface.h" -#include "stack/include/bt_types.h" #include "types/raw_address.h" -using LeRandCallback = base::Callback; +using LeRandCallback = base::OnceCallback; namespace bluetooth { namespace shim { @@ -69,8 +68,10 @@ class Acl : public hci::acl_manager::ConnectionCallbacks, std::unique_ptr) override; void OnLeConnectFail(hci::AddressWithType, hci::ErrorCode reason) override; void OnLeLinkDisconnected(uint16_t handle, hci::ErrorCode reason); - bluetooth::hci::AddressWithType GetConnectionLocalAddress( - const RawAddress& remote_bda); + bluetooth::hci::AddressWithType GetConnectionLocalAddress(uint16_t handle, + bool ota_address); + bluetooth::hci::AddressWithType GetConnectionPeerAddress(uint16_t handle, + bool ota_address); std::optional GetAdvertisingSetConnectedTo( const RawAddress& remote_bda); diff --git a/system/main/shim/acl_api.cc b/system/main/shim/acl_api.cc index f06df1e0984fbd275b68bede9a5661c1e581afef..e2db8dd4633e5c6e5d1dbb719b98062c341c2d01 100644 --- a/system/main/shim/acl_api.cc +++ b/system/main/shim/acl_api.cc @@ -16,14 +16,14 @@ #include "main/shim/acl_api.h" -#include +#include + #include #include #include #include "gd/hci/acl_manager.h" #include "gd/hci/remote_name_request.h" -#include "main/shim/dumpsys.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" #include "main/shim/stack.h" @@ -31,8 +31,8 @@ #include "stack/btm/btm_sec.h" #include "stack/btm/security_device_record.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" // do_in_main_thread #include "stack/include/inq_hci_link_interface.h" +#include "stack/include/main_thread.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" @@ -107,15 +107,31 @@ void bluetooth::shim::ACL_IgnoreAllLeConnections() { return Stack::GetInstance()->GetAcl()->ClearFilterAcceptList(); } -void bluetooth::shim::ACL_ReadConnectionAddress(const RawAddress& pseudo_addr, +void bluetooth::shim::ACL_ReadConnectionAddress(uint16_t handle, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address) { auto local_address = - Stack::GetInstance()->GetAcl()->GetConnectionLocalAddress(pseudo_addr); + Stack::GetInstance()->GetAcl()->GetConnectionLocalAddress(handle, + ota_address); + conn_addr = ToRawAddress(local_address.GetAddress()); *p_addr_type = static_cast(local_address.GetAddressType()); } +void bluetooth::shim::ACL_ReadPeerConnectionAddress(uint16_t handle, + RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address) { + auto remote_ota_address = + Stack::GetInstance()->GetAcl()->GetConnectionPeerAddress(handle, + ota_address); + + conn_addr = ToRawAddress(remote_ota_address.GetAddress()); + *p_addr_type = + static_cast(remote_ota_address.GetAddressType()); +} + std::optional bluetooth::shim::ACL_GetAdvertisingSetConnectedTo( const RawAddress& addr) { return Stack::GetInstance()->GetAcl()->GetAdvertisingSetConnectedTo(addr); @@ -175,7 +191,7 @@ void bluetooth::shim::ACL_RemoteNameRequest(const RawAddress& addr, if (status != hci::ErrorCode::SUCCESS) { do_in_main_thread( FROM_HERE, - base::Bind( + base::BindOnce( [](hci::ErrorCode status) { // NOTE: we intentionally don't supply the address, to match // the legacy behavior. @@ -193,15 +209,10 @@ void bluetooth::shim::ACL_RemoteNameRequest(const RawAddress& addr, GetGdShimHandler()->BindOnce( [](RawAddress addr, uint64_t features) { static_assert(sizeof(features) == 8); - auto addr_array = addr.ToArray(); - auto p = (uint8_t*)osi_malloc(addr_array.size() + sizeof(features)); - std::copy(addr_array.rbegin(), addr_array.rend(), p); - for (int i = 0; i != sizeof(features); ++i) { - p[addr_array.size() + i] = features & ((1 << 8) - 1); - features >>= 8; - } - do_in_main_thread(FROM_HERE, - base::Bind(btm_sec_rmt_host_support_feat_evt, p)); + do_in_main_thread( + FROM_HERE, + base::BindOnce(btm_sec_rmt_host_support_feat_evt, addr, + static_cast(features & 0xff))); }, addr), GetGdShimHandler()->BindOnce( @@ -209,7 +220,7 @@ void bluetooth::shim::ACL_RemoteNameRequest(const RawAddress& addr, std::array name) { do_in_main_thread( FROM_HERE, - base::Bind( + base::BindOnce( [](RawAddress addr, hci::ErrorCode status, std::array name) { auto p = (uint8_t*)osi_malloc(name.size()); diff --git a/system/main/shim/acl_api.h b/system/main/shim/acl_api.h index fd5de156cad516424238773bca52e0151cef3805..3c705cf8230749cc52d4768a95ab211c1f43a96f 100644 --- a/system/main/shim/acl_api.h +++ b/system/main/shim/acl_api.h @@ -19,7 +19,7 @@ #include #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" +#include "stack/include/bt_octets.h" #include "stack/include/hci_error_code.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" @@ -40,9 +40,12 @@ void ACL_ConfigureLePrivacy(bool is_le_privacy_enabled); void ACL_Shutdown(); void ACL_IgnoreAllLeConnections(); -void ACL_ReadConnectionAddress(const RawAddress& pseudo_addr, - RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type); +void ACL_ReadConnectionAddress(uint16_t handle, RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, bool ota_address); + +void ACL_ReadPeerConnectionAddress(uint16_t handle, RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address); std::optional ACL_GetAdvertisingSetConnectedTo(const RawAddress& addr); diff --git a/system/main/shim/acl_legacy_interface.cc b/system/main/shim/acl_legacy_interface.cc index 31297783ee28aaa09ae3b96dfcd54507aa0d9bf4..08454812b9a1c74978e037f38c939e326f5ddfdd 100644 --- a/system/main/shim/acl_legacy_interface.cc +++ b/system/main/shim/acl_legacy_interface.cc @@ -18,12 +18,11 @@ #include "stack/include/acl_hci_link_interface.h" #include "stack/include/ble_acl_interface.h" -#include "stack/include/gatt_api.h" #include "stack/include/sco_hci_link_interface.h" #include "stack/include/sec_hci_link_interface.h" struct tBTM_ESCO_DATA; -void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle, +void gatt_notify_phy_updated(tHCI_STATUS status, uint16_t handle, uint8_t tx_phy, uint8_t rx_phy); void gatt_notify_subrate_change(uint16_t handle, uint16_t subrate_factor, uint16_t latency, uint16_t cont_num, diff --git a/system/main/shim/acl_legacy_interface.h b/system/main/shim/acl_legacy_interface.h index 3c047c0c638e79954c3b7e2bfe635b0083512885..2cd3ce0ec132985be464cfdbfd96045d52951008 100644 --- a/system/main/shim/acl_legacy_interface.h +++ b/system/main/shim/acl_legacy_interface.h @@ -19,11 +19,8 @@ #include #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" -#include "stack/include/gatt_api.h" #include "stack/include/hci_error_code.h" #include "stack/include/hci_mode.h" -#include "stack/include/hcidefs.h" #include "types/ble_address_with_type.h" #include "types/class_of_device.h" #include "types/hci_role.h" @@ -127,7 +124,7 @@ typedef struct { void (*on_read_remote_version_information_complete)( tHCI_STATUS status, uint16_t handle, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version); - void (*on_phy_update)(tGATT_STATUS status, uint16_t handle, uint8_t tx_phy, + void (*on_phy_update)(tHCI_STATUS status, uint16_t handle, uint8_t tx_phy, uint8_t rx_phy); void (*on_le_subrate_change)(uint16_t handle, uint16_t subrate_factor, diff --git a/system/main/shim/activity_attribution.cc b/system/main/shim/activity_attribution.cc deleted file mode 100644 index 4695309b74123b1bde6aa6ea8055d8fa61b21947..0000000000000000000000000000000000000000 --- a/system/main/shim/activity_attribution.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "bt_shim_activity_attribution" -#include "activity_attribution.h" - -#include "btif/include/btif_common.h" -#include "gd/btaa/activity_attribution.h" -#include "helpers.h" -#include "main/shim/entry.h" -#include "types/raw_address.h" - -class ActivityAttributionInterfaceImpl - : public ActivityAttributionInterface, - public bluetooth::activity_attribution::ActivityAttributionCallback { - public: - ~ActivityAttributionInterfaceImpl() override = default; - - static ActivityAttributionInterfaceImpl* GetInstance() { - static ActivityAttributionInterfaceImpl* instance = - new ActivityAttributionInterfaceImpl(); - return instance; - } - - void Init() override { - bluetooth::shim::GetActivityAttribution() - ->RegisterActivityAttributionCallback(this); - } - - void RegisterCallbacks(ActivityAttributionCallbacks* callbacks) override { - this->callbacks = callbacks; - } - - void Cleanup(void) override{}; - - void NotifyActivityAttributionInfo( - int uid, const std::string& package_name, - const std::string& device_address) override { - bluetooth::shim::GetActivityAttribution()->NotifyActivityAttributionInfo( - uid, package_name, device_address); - } - - void OnWakeup(const Activity activity, - const bluetooth::hci::Address& address) override { - do_in_jni_thread( - FROM_HERE, base::Bind(&ActivityAttributionCallbacks::OnWakeup, - base::Unretained(callbacks), - (ActivityAttributionCallbacks::Activity)activity, - bluetooth::ToRawAddress(address))); - } - - void OnActivityLogsReady( - const std::vector logs) override { - std::vector - callback_logs; - for (auto& it : logs) { - ActivityAttributionCallbacks::BtaaAggregationEntry entry{ - bluetooth::ToRawAddress(it.address), - (ActivityAttributionCallbacks::Activity)it.activity, it.wakeup_count, - it.byte_count, it.wakelock_duration_ms}; - callback_logs.push_back(entry); - } - do_in_jni_thread( - FROM_HERE, - base::Bind(&ActivityAttributionCallbacks::OnActivityLogsReady, - base::Unretained(callbacks), callback_logs)); - } - - private: - // Private constructor to prevent construction. - ActivityAttributionInterfaceImpl() {} - - ActivityAttributionCallbacks* callbacks; -}; - -ActivityAttributionInterface* -bluetooth::shim::get_activity_attribution_instance() { - return ActivityAttributionInterfaceImpl::GetInstance(); -} - -void bluetooth::shim::init_activity_attribution() { - bluetooth::shim::get_activity_attribution_instance()->Init(); -} diff --git a/system/main/shim/btm.cc b/system/main/shim/btm.cc index 7614c05cd0beccb577b490ac81865233d4e70463..0274d4bba607cfc779fa60f1d2b926bf63604bff 100644 --- a/system/main/shim/btm.cc +++ b/system/main/shim/btm.cc @@ -20,14 +20,12 @@ #include -#include #include #include #include #include #include -#include "bta/include/bta_api.h" #include "gd/hci/le_advertising_manager.h" #include "gd/hci/le_scanning_manager.h" #include "gd/neighbor/connectability.h" @@ -38,11 +36,9 @@ #include "main/shim/controller.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" -#include "main/shim/shim.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_int_types.h" #include "types/ble_address_with_type.h" -#include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -138,7 +134,7 @@ void Btm::ScanningCallbacks::OnScanResult( extended_event_type, ble_address_type, raw_address, primary_phy, secondary_phy, advertising_sid, tx_power, rssi, periodic_advertising_interval, advertising_data.size(), - &advertising_data[0], original_bda); + advertising_data.data(), original_bda); } void Btm::ScanningCallbacks::OnTrackAdvFoundLost( @@ -175,73 +171,6 @@ Btm::Btm(os::Handler* handler, neighbor::InquiryModule* inquiry) : scanning_timer_(handler), observing_timer_(handler) { ASSERT(handler != nullptr); ASSERT(inquiry != nullptr); - bluetooth::neighbor::InquiryCallbacks inquiry_callbacks = { - .result = std::bind(&Btm::OnInquiryResult, this, std::placeholders::_1), - .result_with_rssi = - std::bind(&Btm::OnInquiryResultWithRssi, this, std::placeholders::_1), - .extended_result = - std::bind(&Btm::OnExtendedInquiryResult, this, std::placeholders::_1), - .complete = - std::bind(&Btm::OnInquiryComplete, this, std::placeholders::_1)}; - inquiry->RegisterCallbacks(std::move(inquiry_callbacks)); -} - -void Btm::OnInquiryResult(bluetooth::hci::InquiryResultView view) { - for (auto& response : view.GetResponses()) { - btm_api_process_inquiry_result( - ToRawAddress(response.bd_addr_), - static_cast(response.page_scan_repetition_mode_), - response.class_of_device_.data(), response.clock_offset_); - } -} - -void Btm::OnInquiryResultWithRssi( - bluetooth::hci::InquiryResultWithRssiView view) { - for (auto& response : view.GetResponses()) { - btm_api_process_inquiry_result_with_rssi( - ToRawAddress(response.address_), - static_cast(response.page_scan_repetition_mode_), - response.class_of_device_.data(), response.clock_offset_, - response.rssi_); - } -} - -void Btm::OnExtendedInquiryResult( - bluetooth::hci::ExtendedInquiryResultView view) { - constexpr size_t kMaxExtendedInquiryResponse = 240; - uint8_t gap_data_buffer[kMaxExtendedInquiryResponse]; - uint8_t* data = nullptr; - size_t data_len = 0; - - if (!view.GetExtendedInquiryResponse().empty()) { - bzero(gap_data_buffer, sizeof(gap_data_buffer)); - uint8_t* p = gap_data_buffer; - for (auto gap_data : view.GetExtendedInquiryResponse()) { - *p++ = gap_data.data_.size() + sizeof(gap_data.data_type_); - *p++ = static_cast(gap_data.data_type_); - p = (uint8_t*)memcpy(p, &gap_data.data_[0], gap_data.data_.size()) + - gap_data.data_.size(); - } - data = gap_data_buffer; - data_len = p - data; - } - - btm_api_process_extended_inquiry_result( - ToRawAddress(view.GetAddress()), - static_cast(view.GetPageScanRepetitionMode()), - view.GetClassOfDevice().data(), view.GetClockOffset(), view.GetRssi(), - data, data_len); -} - -void Btm::OnInquiryComplete(bluetooth::hci::ErrorCode status) { - limited_inquiry_active_ = false; - general_inquiry_active_ = false; - legacy_inquiry_complete_callback_((static_cast(status) == 0) - ? (BTM_SUCCESS) - : (BTM_ERR_PROCESSING), - active_inquiry_mode_); - - active_inquiry_mode_ = kInquiryModeOff; } void Btm::SetStandardInquiryResultMode() { diff --git a/system/main/shim/btm.h b/system/main/shim/btm.h index 42bce9d9bcf5565bcc11a8b9ec454b3b8529daaa..6083ae038d77e729fe91435d82d6c9f9e36d28c1 100644 --- a/system/main/shim/btm.h +++ b/system/main/shim/btm.h @@ -20,18 +20,16 @@ #include #include #include -#include #include +#include "bt_transport.h" #include "gd/common/callback.h" #include "gd/hci/le_advertising_manager.h" -#include "gd/hci/le_scanning_manager.h" +#include "gd/hci/le_scanning_callback.h" #include "gd/neighbor/inquiry.h" #include "gd/os/alarm.h" #include "hci/hci_packets.h" #include "stack/btm/neighbor_inquiry.h" -#include "stack/include/btm_api_types.h" -#include "types/bluetooth/uuid.h" #include "types/raw_address.h" // @@ -89,12 +87,6 @@ class Btm { Btm(os::Handler* handler, neighbor::InquiryModule* inquiry); ~Btm() = default; - // Inquiry result callbacks - void OnInquiryResult(bluetooth::hci::InquiryResultView view); - void OnInquiryResultWithRssi(bluetooth::hci::InquiryResultWithRssiView view); - void OnExtendedInquiryResult(bluetooth::hci::ExtendedInquiryResultView view); - void OnInquiryComplete(bluetooth::hci::ErrorCode status); - void SetStandardInquiryResultMode(); void SetInquiryWithRssiResultMode(); void SetExtendedInquiryResultMode(); diff --git a/system/main/shim/btm_api.cc b/system/main/shim/btm_api.cc index b377a0370e9ee1dc6143ca167f50886cc5da5e35..e92dea60d2a8cab6474a397c341a80b4e0aea1d5 100644 --- a/system/main/shim/btm_api.cc +++ b/system/main/shim/btm_api.cc @@ -21,763 +21,18 @@ #include #include -#include - -#include "common/metric_id_allocator.h" -#include "common/time_util.h" -#include "gd/common/callback.h" -#include "gd/os/log.h" -#include "gd/security/security_module.h" -#include "gd/security/ui.h" #include "main/shim/btm.h" #include "main/shim/controller.h" #include "main/shim/helpers.h" -#include "main/shim/metric_id_api.h" -#include "main/shim/shim.h" #include "main/shim/stack.h" -#include "osi/include/allocator.h" -#include "osi/include/osi.h" // UNUSED_ATTR -#include "osi/include/properties.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_int_types.h" -#include "stack/btm/btm_sec.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/bt_octets.h" -#include "stack/include/hci_error_code.h" -#include "types/ble_address_with_type.h" -#include "types/bluetooth/uuid.h" +#include "stack/btm/btm_ble_sec.h" #include "types/raw_address.h" -using bluetooth::common::MetricIdAllocator; - -#define BTIF_DM_DEFAULT_INQ_MAX_RESULTS 0 -#define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10 - -/** - * Legacy bluetooth module global control block state - * - * Mutex is used to synchronize access from the shim - * layer into the global control block. This is used - * by the shim despite potentially arbitrary - * unsynchronized access by the legacy stack. - */ -extern tBTM_CB btm_cb; -std::mutex btm_cb_mutex_; - -bool btm_inq_find_bdaddr(const RawAddress& p_bda); -extern tINQ_DB_ENT* btm_inq_db_find(const RawAddress& raw_address); -extern tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda); - -/** - * Legacy bluetooth btm stack entry points - */ -void btm_acl_update_inquiry_status(uint8_t status); -void btm_clear_all_pending_le_entry(void); -void btm_clr_inq_result_flt(void); -void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results); -void btm_sort_inq_result(void); -void btm_process_inq_complete(tHCI_STATUS status, uint8_t result_type); - -static bool is_classic_device(tBT_DEVICE_TYPE device_type) { - return device_type == BT_DEVICE_TYPE_BREDR; -} - -static bool has_classic_device(tBT_DEVICE_TYPE device_type) { - return device_type & BT_DEVICE_TYPE_BREDR; -} - -void btm_api_process_inquiry_result(const RawAddress& raw_address, - uint8_t page_scan_rep_mode, - DEV_CLASS device_class, - uint16_t clock_offset) { - tINQ_DB_ENT* p_i = btm_inq_db_find(raw_address); - - if (p_i == nullptr) { - p_i = btm_inq_db_new(raw_address); - CHECK(p_i != nullptr); - } else if (p_i->inq_count == btm_cb.btm_inq_vars.inq_counter && - is_classic_device(p_i->inq_info.results.device_type)) { - return; - } - - p_i->inq_info.results.page_scan_rep_mode = page_scan_rep_mode; - p_i->inq_info.results.page_scan_per_mode = 0; // RESERVED - p_i->inq_info.results.page_scan_mode = 0; // RESERVED - p_i->inq_info.results.dev_class[0] = device_class[0]; - p_i->inq_info.results.dev_class[1] = device_class[1]; - p_i->inq_info.results.dev_class[2] = device_class[2]; - p_i->inq_info.results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID; - p_i->inq_info.results.inq_result_type = BTM_INQ_RESULT_BR; - p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI; - - p_i->time_of_resp = bluetooth::common::time_get_os_boottime_ms(); - p_i->inq_count = btm_cb.btm_inq_vars.inq_counter; - p_i->inq_info.appl_knows_rem_name = false; - - if (p_i->inq_count != btm_cb.btm_inq_vars.inq_counter) { - p_i->inq_info.results.device_type = BT_DEVICE_TYPE_BREDR; - btm_cb.btm_inq_vars.inq_cmpl_info.num_resp++; - p_i->scan_rsp = false; - } else { - p_i->inq_info.results.device_type |= BT_DEVICE_TYPE_BREDR; - } - - if (btm_cb.btm_inq_vars.p_inq_results_cb == nullptr) { - return; - } - - (btm_cb.btm_inq_vars.p_inq_results_cb)(&p_i->inq_info.results, nullptr, 0); -} - -void btm_api_process_inquiry_result_with_rssi(RawAddress raw_address, - uint8_t page_scan_rep_mode, - DEV_CLASS device_class, - uint16_t clock_offset, - int8_t rssi) { - tINQ_DB_ENT* p_i = btm_inq_db_find(raw_address); - - bool update = false; - if (btm_inq_find_bdaddr(raw_address)) { - if (p_i != nullptr && - (rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi == 0 || - has_classic_device(p_i->inq_info.results.device_type))) { - update = true; - } - } - - bool is_new = true; - if (p_i == nullptr) { - p_i = btm_inq_db_new(raw_address); - CHECK(p_i != nullptr); - } else if (p_i->inq_count == btm_cb.btm_inq_vars.inq_counter && - is_classic_device(p_i->inq_info.results.device_type)) { - is_new = false; - } - - p_i->inq_info.results.rssi = rssi; - - if (is_new) { - p_i->inq_info.results.page_scan_rep_mode = page_scan_rep_mode; - p_i->inq_info.results.page_scan_per_mode = 0; // RESERVED - p_i->inq_info.results.page_scan_mode = 0; // RESERVED - p_i->inq_info.results.dev_class[0] = device_class[0]; - p_i->inq_info.results.dev_class[1] = device_class[1]; - p_i->inq_info.results.dev_class[2] = device_class[2]; - p_i->inq_info.results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID; - p_i->inq_info.results.inq_result_type = BTM_INQ_RESULT_BR; - - p_i->time_of_resp = bluetooth::common::time_get_os_boottime_ms(); - p_i->inq_count = btm_cb.btm_inq_vars.inq_counter; - p_i->inq_info.appl_knows_rem_name = false; - - if (p_i->inq_count != btm_cb.btm_inq_vars.inq_counter) { - p_i->inq_info.results.device_type = BT_DEVICE_TYPE_BREDR; - btm_cb.btm_inq_vars.inq_cmpl_info.num_resp++; - p_i->scan_rsp = false; - } else { - p_i->inq_info.results.device_type |= BT_DEVICE_TYPE_BREDR; - } - } - - if (btm_cb.btm_inq_vars.p_inq_results_cb == nullptr) { - return; - } - - if (is_new || update) { - (btm_cb.btm_inq_vars.p_inq_results_cb)(&p_i->inq_info.results, nullptr, 0); - } -} -void btm_api_process_extended_inquiry_result(RawAddress raw_address, - uint8_t page_scan_rep_mode, - DEV_CLASS device_class, - uint16_t clock_offset, int8_t rssi, - const uint8_t* eir_data, - size_t eir_len) { - tINQ_DB_ENT* p_i = btm_inq_db_find(raw_address); - - bool update = false; - if (btm_inq_find_bdaddr(raw_address) && p_i != nullptr) { - update = true; - } - - bool is_new = true; - if (p_i == nullptr) { - p_i = btm_inq_db_new(raw_address); - } else if (p_i->inq_count == btm_cb.btm_inq_vars.inq_counter && - (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BREDR)) { - is_new = false; - } - - p_i->inq_info.results.rssi = rssi; - - if (is_new) { - p_i->inq_info.results.page_scan_rep_mode = page_scan_rep_mode; - p_i->inq_info.results.page_scan_per_mode = 0; // RESERVED - p_i->inq_info.results.page_scan_mode = 0; // RESERVED - p_i->inq_info.results.dev_class[0] = device_class[0]; - p_i->inq_info.results.dev_class[1] = device_class[1]; - p_i->inq_info.results.dev_class[2] = device_class[2]; - p_i->inq_info.results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID; - p_i->inq_info.results.inq_result_type = BTM_INQ_RESULT_BR; - - p_i->time_of_resp = bluetooth::common::time_get_os_boottime_ms(); - p_i->inq_count = btm_cb.btm_inq_vars.inq_counter; - p_i->inq_info.appl_knows_rem_name = false; - - if (p_i->inq_count != btm_cb.btm_inq_vars.inq_counter) { - p_i->inq_info.results.device_type = BT_DEVICE_TYPE_BREDR; - btm_cb.btm_inq_vars.inq_cmpl_info.num_resp++; - p_i->scan_rsp = false; - } else { - p_i->inq_info.results.device_type |= BT_DEVICE_TYPE_BREDR; - } - } - - if (btm_cb.btm_inq_vars.p_inq_results_cb == nullptr) { - return; - } - - if (is_new || update) { - memset(p_i->inq_info.results.eir_uuid, 0, - BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS / 8)); - btm_set_eir_uuid(const_cast(eir_data), &p_i->inq_info.results); - uint8_t* p_eir_data = const_cast(eir_data); - (btm_cb.btm_inq_vars.p_inq_results_cb)(&p_i->inq_info.results, p_eir_data, - eir_len); - } -} - -namespace { -std::unordered_map - address_name_map_; - -std::unordered_map gd_legacy_io_caps_map_ = { - {bluetooth::hci::IoCapability::DISPLAY_ONLY, BTM_IO_CAP_OUT}, - {bluetooth::hci::IoCapability::DISPLAY_YES_NO, BTM_IO_CAP_IO}, - {bluetooth::hci::IoCapability::KEYBOARD_ONLY, BTM_IO_CAP_IN}, - {bluetooth::hci::IoCapability::NO_INPUT_NO_OUTPUT, BTM_IO_CAP_NONE}, -}; - -std::unordered_map - gd_legacy_auth_reqs_map_ = { - {bluetooth::hci::AuthenticationRequirements::NO_BONDING, - BTM_AUTH_SP_NO}, - {bluetooth::hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION, - BTM_AUTH_SP_YES}, - {bluetooth::hci::AuthenticationRequirements::DEDICATED_BONDING, - BTM_AUTH_AP_NO}, - {bluetooth::hci::AuthenticationRequirements:: - DEDICATED_BONDING_MITM_PROTECTION, - BTM_AUTH_AP_YES}, - {bluetooth::hci::AuthenticationRequirements::GENERAL_BONDING, - BTM_AUTH_SPGB_NO}, - {bluetooth::hci::AuthenticationRequirements:: - GENERAL_BONDING_MITM_PROTECTION, - BTM_AUTH_SPGB_YES}, -}; -} - -class ShimUi : public bluetooth::security::UI { - public: - static ShimUi* GetInstance() { - static ShimUi instance; - return &instance; - } - - ShimUi(const ShimUi&) = delete; - ShimUi& operator=(const ShimUi&) = delete; - - void SetBtaCallbacks(const tBTM_APPL_INFO* bta_callbacks) { - bta_callbacks_ = bta_callbacks; - if (bta_callbacks->p_pin_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s pin_callback", __func__); - } - - if (bta_callbacks->p_link_key_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s link_key_callback", __func__); - } - - if (bta_callbacks->p_auth_complete_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s auth_complete_callback", __func__); - } - - if (bta_callbacks->p_bond_cancel_cmpl_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s bond_cancel_complete_callback", __func__); - } - - if (bta_callbacks->p_le_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s le_callback", __func__); - } - - if (bta_callbacks->p_le_key_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s le_key_callback", __func__); - } - } - - void DisplayPairingPrompt(const bluetooth::hci::AddressWithType& address, - std::string name) { - waiting_for_pairing_prompt_ = true; - bt_bdname_t legacy_name{0}; - memcpy(legacy_name.name, name.data(), name.length()); - // TODO(optedoblivion): Handle callback to BTA for BLE - } - - void Cancel(const bluetooth::hci::AddressWithType& address) { - LOG(WARNING) << " â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â– â–  " << __func__; - } - - void HandleConfirm(bluetooth::security::ConfirmationData data) { - const bluetooth::hci::AddressWithType& address = data.GetAddressWithType(); - uint32_t numeric_value = data.GetNumericValue(); - bt_bdname_t legacy_name{0}; - memcpy(legacy_name.name, data.GetName().data(), data.GetName().length()); - - if (bta_callbacks_->p_sp_callback) { - // Call sp_cback for IO_REQ - tBTM_SP_IO_REQ io_req_evt_data; - io_req_evt_data.bd_addr = bluetooth::ToRawAddress(address.GetAddress()); - // Local IO Caps (Phone is always DisplayYesNo) - io_req_evt_data.io_cap = BTM_IO_CAP_IO; - // Local Auth Reqs (Phone is always DEDICATED_BONDING) - io_req_evt_data.auth_req = BTM_AUTH_AP_NO; - io_req_evt_data.oob_data = BTM_OOB_NONE; - (*bta_callbacks_->p_sp_callback)(BTM_SP_IO_REQ_EVT, - (tBTM_SP_EVT_DATA*)&io_req_evt_data); - - // Call sp_cback for IO_RSP - tBTM_SP_IO_RSP io_rsp_evt_data; - io_rsp_evt_data.bd_addr = bluetooth::ToRawAddress(address.GetAddress()); - io_rsp_evt_data.io_cap = gd_legacy_io_caps_map_[data.GetRemoteIoCaps()]; - io_rsp_evt_data.auth_req = - gd_legacy_auth_reqs_map_[data.GetRemoteAuthReqs()]; - io_rsp_evt_data.auth_req = BTM_AUTH_AP_YES; - io_rsp_evt_data.oob_data = BTM_OOB_NONE; - (*bta_callbacks_->p_sp_callback)(BTM_SP_IO_RSP_EVT, - (tBTM_SP_EVT_DATA*)&io_rsp_evt_data); - - // Call sp_cback for USER_CONFIRMATION - tBTM_SP_EVT_DATA user_cfm_req_evt_data; - user_cfm_req_evt_data.cfm_req.bd_addr = - bluetooth::ToRawAddress(address.GetAddress()); - user_cfm_req_evt_data.cfm_req.num_val = numeric_value; - // If we pop a dialog then it isn't just_works - user_cfm_req_evt_data.cfm_req.just_works = data.IsJustWorks(); - - address_name_map_.emplace(address, legacy_name); - memcpy((char*)user_cfm_req_evt_data.cfm_req.bd_name, legacy_name.name, - BD_NAME_LEN); - - (*bta_callbacks_->p_sp_callback)(BTM_SP_CFM_REQ_EVT, - &user_cfm_req_evt_data); - } - } - - void DisplayConfirmValue(bluetooth::security::ConfirmationData data) { - waiting_for_pairing_prompt_ = false; - data.SetJustWorks(false); - HandleConfirm(data); - } - - void DisplayYesNoDialog(bluetooth::security::ConfirmationData data) { - waiting_for_pairing_prompt_ = false; - data.SetJustWorks(true); - HandleConfirm(data); - } - - void DisplayEnterPasskeyDialog(bluetooth::security::ConfirmationData data) { - waiting_for_pairing_prompt_ = false; - LOG_WARN("UNIMPLEMENTED, Passkey not supported in GD"); - } - - void DisplayPasskey(bluetooth::security::ConfirmationData data) { - waiting_for_pairing_prompt_ = false; - LOG_WARN("UNIMPLEMENTED, Passkey not supported in GD"); - } - - void DisplayEnterPinDialog(bluetooth::security::ConfirmationData data) { - waiting_for_pairing_prompt_ = false; - LOG_WARN("UNIMPLEMENTED, PIN not supported in GD"); - } - - bool waiting_for_pairing_prompt_ = false; - - private: - ShimUi() : bta_callbacks_(nullptr) {} - ~ShimUi() {} - const tBTM_APPL_INFO* bta_callbacks_; -}; - -ShimUi* shim_ui_ = nullptr; - -class ShimBondListener : public bluetooth::security::ISecurityManagerListener { - public: - static ShimBondListener* GetInstance() { - static ShimBondListener instance; - return &instance; - } - - ShimBondListener(const ShimBondListener&) = delete; - ShimBondListener& operator=(const ShimBondListener&) = delete; - - void SetBtaCallbacks(const tBTM_APPL_INFO* bta_callbacks) { - bta_callbacks_ = bta_callbacks; - if (bta_callbacks->p_pin_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s pin_callback", __func__); - } - - if (bta_callbacks->p_link_key_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s link_key_callback", __func__); - } - - if (bta_callbacks->p_auth_complete_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s auth_complete_callback", __func__); - } - - if (bta_callbacks->p_bond_cancel_cmpl_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s bond_cancel_complete_callback", __func__); - } - - if (bta_callbacks->p_le_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s le_callback", __func__); - } - - if (bta_callbacks->p_le_key_callback == nullptr) { - LOG_INFO("UNIMPLEMENTED %s le_key_callback", __func__); - } - } - - void OnDeviceBonded(bluetooth::hci::AddressWithType device) override { - // Call sp_cback for LINK_KEY_NOTIFICATION - // Call AUTHENTICATION_COMPLETE callback - if (device.GetAddressType() == - bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS) { - auto it = address_name_map_.find(device); - bt_bdname_t tmp_name; - if (it != address_name_map_.end()) { - tmp_name = it->second; - } - BD_NAME name; - memcpy((char*)name, tmp_name.name, BD_NAME_LEN); - - if (*bta_callbacks_->p_link_key_callback) { - LinkKey key; // Never want to send the key to the stack - (*bta_callbacks_->p_link_key_callback)( - bluetooth::ToRawAddress(device.GetAddress()), 0, name, key, - BTM_LKEY_TYPE_COMBINATION, false /* is_ctkd */); - } - if (*bta_callbacks_->p_auth_complete_callback) { - (*bta_callbacks_->p_auth_complete_callback)( - bluetooth::ToRawAddress(device.GetAddress()), 0, name, HCI_SUCCESS); - } - } - bluetooth::shim::AllocateIdFromMetricIdAllocator( - bluetooth::ToRawAddress(device.GetAddress())); - bool is_saving_successful = bluetooth::shim::SaveDeviceOnMetricIdAllocator( - bluetooth::ToRawAddress(device.GetAddress())); - if (!is_saving_successful) { - LOG(FATAL) << __func__ << ": Fail to save metric id for device " - << bluetooth::ToRawAddress(device.GetAddress()); - } - } - - void OnDeviceUnbonded(bluetooth::hci::AddressWithType device) override { - if (bta_callbacks_->p_bond_cancel_cmpl_callback) { - (*bta_callbacks_->p_bond_cancel_cmpl_callback)(BTM_SUCCESS); - } - bluetooth::shim::ForgetDeviceFromMetricIdAllocator( - bluetooth::ToRawAddress(device.GetAddress())); - } - - void OnDeviceBondFailed(bluetooth::hci::AddressWithType device, - bluetooth::security::PairingFailure status) override { - auto it = address_name_map_.find(device); - bt_bdname_t tmp_name; - if (it != address_name_map_.end()) { - tmp_name = it->second; - } - BD_NAME name; - memcpy((char*)name, tmp_name.name, BD_NAME_LEN); - - if (bta_callbacks_->p_auth_complete_callback) { - (*bta_callbacks_->p_auth_complete_callback)( - bluetooth::ToRawAddress(device.GetAddress()), 0, name, - HCI_ERR_AUTH_FAILURE); - } - } - - void OnEncryptionStateChanged( - bluetooth::hci::EncryptionChangeView encryption_change_view) override { - // TODO(optedoblivion): Find BTA callback for this to call - } - - private: - ShimBondListener() : bta_callbacks_(nullptr) {} - ~ShimBondListener() {} - const tBTM_APPL_INFO* bta_callbacks_; -}; - -tBTM_STATUS bluetooth::shim::BTM_CancelRemoteDeviceName(void) { - return Stack::GetInstance()->GetBtm()->CancelAllReadRemoteDeviceName(); -} - -tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbRead(const RawAddress& p_bda) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - return nullptr; -} - -tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbFirst(void) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - return nullptr; -} - -tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbNext(tBTM_INQ_INFO* p_cur) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_cur != nullptr); - return nullptr; -} - -tBTM_STATUS bluetooth::shim::BTM_ClearInqDb(const RawAddress* p_bda) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - if (p_bda == nullptr) { - // clear all entries - } else { - // clear specific entry - } - return BTM_NO_RESOURCES; -} - -bool bluetooth::shim::BTM_HasEirService(const uint32_t* p_eir_uuid, - uint16_t uuid16) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_eir_uuid != nullptr); - return false; -} - -tBTM_EIR_SEARCH_RESULT bluetooth::shim::BTM_HasInquiryEirService( - tBTM_INQ_RESULTS* p_results, uint16_t uuid16) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_results != nullptr); - return BTM_EIR_UNKNOWN; -} - -void bluetooth::shim::BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_eir_uuid != nullptr); -} - -void bluetooth::shim::BTM_ReadConnectionAddr(const RawAddress& remote_bda, - RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_addr_type != nullptr); -} - -bool bluetooth::shim::BTM_ReadRemoteConnectionAddr( - const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_addr_type != nullptr); - return false; -} - -void bluetooth::shim::BTM_BleSetConnScanParams(uint32_t scan_interval, - uint32_t scan_window) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_ReadDevInfo(const RawAddress& remote_bda, - tBT_DEVICE_TYPE* p_dev_type, - tBLE_ADDR_TYPE* p_addr_type) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_dev_type != nullptr); - CHECK(p_addr_type != nullptr); -} - -bool bluetooth::shim::BTM_ReadConnectedTransportAddress( - RawAddress* remote_bda, tBT_TRANSPORT transport) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(remote_bda != nullptr); - return false; -} - -bool bluetooth::shim::BTM_GetLeSecurityState(const RawAddress& bd_addr, - uint8_t* p_le_dev_sec_flags, - uint8_t* p_le_key_size) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - CHECK(p_le_dev_sec_flags != nullptr); - CHECK(p_le_key_size != nullptr); - return false; -} - -bool bluetooth::shim::BTM_BleSecurityProcedureIsRunning( - const RawAddress& bd_addr) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - return false; -} - -uint8_t bluetooth::shim::BTM_BleGetSupportedKeySize(const RawAddress& bd_addr) { - LOG_INFO("UNIMPLEMENTED %s", __func__); - return 0; -} - -/** - * This function update(add,delete or clear) the adv local name filtering - * condition. - */ -void bluetooth::shim::BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector name, - tBTM_BLE_PF_CFG_CBACK cb) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_LE_PF_manu_data( - tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, - uint16_t company_id, uint16_t company_id_mask, std::vector data, - std::vector data_mask, tBTM_BLE_PF_CFG_CBACK cb) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_LE_PF_srvc_data_pattern( - tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector data, std::vector data_mask, - tBTM_BLE_PF_CFG_CBACK cb) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - tBLE_BD_ADDR addr, - tBTM_BLE_PF_CFG_CBACK cb) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_COND_TYPE filter_type, - const bluetooth::Uuid& uuid, - tBTM_BLE_PF_LOGIC_TYPE cond_logic, - const bluetooth::Uuid& uuid_mask, - tBTM_BLE_PF_CFG_CBACK cb) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector commands, - tBTM_BLE_PF_CFG_CBACK cb) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_CFG_CBACK cb) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_BleAdvFilterParamSetup( - tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, - std::unique_ptr p_filt_params, - tBTM_BLE_PF_PARAM_CB cb) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -void bluetooth::shim::BTM_BleEnableDisableFilterFeature( - uint8_t enable, tBTM_BLE_PF_STATUS_CBACK p_stat_cback) { - LOG_INFO("UNIMPLEMENTED %s", __func__); -} - -tBTM_STATUS bluetooth::shim::BTM_SecBond(const RawAddress& bd_addr, - tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, - tBT_DEVICE_TYPE device_type) { - return Stack::GetInstance()->GetBtm()->CreateBond(bd_addr, addr_type, - transport, device_type); -} - -bool bluetooth::shim::BTM_SecAddDevice(const RawAddress& bd_addr, - DEV_CLASS dev_class, - const BD_NAME& bd_name, - uint8_t* features, LinkKey* link_key, - uint8_t key_type, uint8_t pin_length) { - // Check if GD has a security record for the device - return BTM_SUCCESS; -} - -void bluetooth::shim::BTM_ConfirmReqReply(tBTM_STATUS res, - const RawAddress& bd_addr) { - // Send for both Classic and LE until we can determine the type - bool accept = res == BTM_SUCCESS; - hci::AddressWithType address = ToAddressWithType(bd_addr, BLE_ADDR_PUBLIC); - hci::AddressWithType address2 = ToAddressWithType(bd_addr, BLE_ADDR_RANDOM); - auto security_manager = - bluetooth::shim::GetSecurityModule()->GetSecurityManager(); - if (ShimUi::GetInstance()->waiting_for_pairing_prompt_) { - LOG(INFO) << "interpreting confirmation as pairing accept " << address; - security_manager->OnPairingPromptAccepted(address, accept); - security_manager->OnPairingPromptAccepted(address2, accept); - ShimUi::GetInstance()->waiting_for_pairing_prompt_ = false; - } else { - LOG(INFO) << "interpreting confirmation as yes/no confirmation " << address; - security_manager->OnConfirmYesNo(address, accept); - security_manager->OnConfirmYesNo(address2, accept); - } -} - uint16_t bluetooth::shim::BTM_GetHCIConnHandle(const RawAddress& remote_bda, tBT_TRANSPORT transport) { return Stack::GetInstance()->GetBtm()->GetAclHandle(remote_bda, transport); } -void bluetooth::shim::BTM_SecClearSecurityFlags(const RawAddress& bd_addr) { - // TODO(optedoblivion): Call RemoveBond on device address -} - -char* bluetooth::shim::BTM_SecReadDevName(const RawAddress& address) { - static char name[] = "TODO: See if this is needed"; - return name; -} - -bool bluetooth::shim::BTM_SecAddRmtNameNotifyCallback( - tBTM_RMT_NAME_CALLBACK* p_callback) { - // TODO(optedoblivion): keep track of callback - LOG_WARN("Unimplemented"); - return true; -} - -bool bluetooth::shim::BTM_SecDeleteRmtNameNotifyCallback( - tBTM_RMT_NAME_CALLBACK* p_callback) { - // TODO(optedoblivion): stop keeping track of callback - LOG_WARN("Unimplemented"); - return true; -} - -void bluetooth::shim::BTM_PINCodeReply(const RawAddress& bd_addr, - tBTM_STATUS res, uint8_t pin_len, - uint8_t* p_pin) { - ASSERT_LOG(!bluetooth::shim::is_gd_shim_enabled(), "Unreachable code path"); -} - -void bluetooth::shim::BTM_RemoteOobDataReply(tBTM_STATUS res, - const RawAddress& bd_addr, - const Octet16& c, - const Octet16& r) { - ASSERT_LOG(!bluetooth::shim::is_gd_shim_enabled(), "Unreachable code path"); -} - -tBTM_STATUS bluetooth::shim::BTM_SetDeviceClass(DEV_CLASS dev_class) { - // TODO(optedoblivion): see if we need this, I don't think we do - LOG_WARN("Unimplemented"); - return BTM_SUCCESS; -} - tBTM_STATUS bluetooth::shim::BTM_ClearEventFilter() { controller_get_interface()->clear_event_filter(); return BTM_SUCCESS; @@ -800,7 +55,7 @@ tBTM_STATUS bluetooth::shim::BTM_DisconnectAllAcls() { } tBTM_STATUS bluetooth::shim::BTM_LeRand(LeRandCallback cb) { - Stack::GetInstance()->GetAcl()->LeRand(cb); + Stack::GetInstance()->GetAcl()->LeRand(std::move(cb)); return BTM_SUCCESS; } diff --git a/system/main/shim/btm_api.h b/system/main/shim/btm_api.h index 948da468c8071a8acac4e1f1952676d3d426485d..a54dd6188eae02a4e428ecb87fa88ef730b0e27d 100644 --- a/system/main/shim/btm_api.h +++ b/system/main/shim/btm_api.h @@ -18,14 +18,9 @@ #include "base/functional/callback.h" #include "device/include/esco_parameters.h" -#include "stack/btm/btm_sec.h" #include "stack/btm/neighbor_inquiry.h" -#include "stack/include/acl_api_types.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/bt_octets.h" #include "stack/include/btm_api_types.h" #include "stack/include/btm_ble_api_types.h" -#include "types/bluetooth/uuid.h" #include "types/hci_role.h" #include "types/raw_address.h" @@ -320,23 +315,6 @@ tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda); ******************************************************************************/ bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16); -/******************************************************************************* - * - * Function BTM_HasInquiryEirService - * - * Description Return if a UUID is in the bit map of a UUID list. - * - * Parameters p_results - inquiry results - * uuid16 - UUID 16-bit - * - * Returns BTM_EIR_FOUND - if found - * BTM_EIR_NOT_FOUND - if not found and it is a complete list - * BTM_EIR_UNKNOWN - if not found and it is not complete list - * - ******************************************************************************/ -tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS* p_results, - uint16_t uuid16); - /******************************************************************************* * * Function BTM_AddEirService @@ -352,135 +330,45 @@ tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS* p_results, ******************************************************************************/ void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16); -/******************************************************************************* - * - * Function BTM_SecAddBleDevice - * - * Description Add/modify device. This function will be normally called - * during host startup to restore all required information - * for a LE device stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * dev_type - Remote device's device type. - * addr_type - LE device address type. - * - ******************************************************************************/ -void BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, - tBLE_ADDR_TYPE addr_type); - -/******************************************************************************* - * - * Function BTM_SecAddBleKey - * - * Description Add/modify LE device information. This function will be - * normally called during host startup to restore all required - * information stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * p_le_key - LE key values. - * key_type - LE SMP key type. - * - ******************************************************************************/ -void BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type); - -/******************************************************************************* - * - * Function BTM_BleLoadLocalKeys - * - * Description Local local identity key, encryption root or sign counter. - * - * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, - * BTM_BLE_KEY_TYPE_ER - * or BTM_BLE_KEY_TYPE_COUNTER. - * p_key: pointer to the key. - * - * Returns non2. - * - ******************************************************************************/ -void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key); - -/** Returns local device encryption root (ER) */ -const Octet16& BTM_GetDeviceEncRoot(); - -/** Returns local device identity root (IR) */ -const Octet16& BTM_GetDeviceIDRoot(); - -/** Return local device DHK. */ -const Octet16& BTM_GetDeviceDHK(); - /******************************************************************************* * * Function BTM_ReadConnectionAddr * - * Description Read the local device random address. + * Description Read the local device address. * + * pseudo_addr - pseudo address used by the stack + * conn_addr - returned addresss + * p_addr_type - returned address type + * ota_address - if set to true, function will provide RPA address + * if it was used during connection. e.g. It should + * be set to true by SMP module. * Returns void * ******************************************************************************/ -void BTM_ReadConnectionAddr(const RawAddress& remote_bda, +void BTM_ReadConnectionAddr(const RawAddress& pseudo_addr, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type); + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address = false); /******************************************************************************* * * Function BTM_ReadRemoteConnectionAddr * - * Description Read the remote device address currently used. + * Description Read the remote device address. + * pseudo_addr - pseudo address used by the stack + * conn_addr - returned addresss + * p_addr_type - returned address type + * ota_address - if set to true, function will provide RPA address + * if it was used during connection. It should be set + * to true by SMP module. * - * Returns void + * Returns true if remote address found, false otherwise. * ******************************************************************************/ bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type); - -/******************************************************************************* - * - * Function BTM_SecurityGrant - * - * Description This function is called to grant security process. - * - * Parameters bd_addr - peer device bd address. - * res - result of the operation BTM_SUCCESS if success. - * Otherwise, BTM_REPEATED_ATTEMPTS is too many - * attempts. - * - * Returns None - * - ******************************************************************************/ -void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res); - -/******************************************************************************* - * - * Function BTM_LeOobDataReply - * - * Description This function is called to provide the OOB data for - * SMP in response to BTM_LE_OOB_REQ_EVT - * - * Parameters: bd_addr - Address of the peer device - * res - result of the operation SMP_SUCCESS if success - * p_data - simple pairing Randomizer C. - * - ******************************************************************************/ -void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len, - uint8_t* p_data); - -/******************************************************************************* - * - * Function BTM_BleSecureConnectionOobDataReply - * - * Description This function is called to provide the OOB data for - * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection - * data is available - * - * Parameters: bd_addr - Address of the peer device - * p_c - pointer to Confirmation - * p_r - pointer to Randomizer. - * - ******************************************************************************/ -void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr, - uint8_t* p_c, uint8_t* p_r); + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address = false); /****************************************************************************** * @@ -519,21 +407,6 @@ void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int, uint16_t peripheral_latency, uint16_t supervision_tout); -/******************************************************************************* - * - * Function BTM_ReadDevInfo - * - * Description This function is called to read the device/address type - * of BD address. - * - * Parameter remote_bda: remote device address - * p_dev_type: output parameter to read the device type. - * p_addr_type: output parameter to read the address type. - * - ******************************************************************************/ -void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, - tBLE_ADDR_TYPE* p_addr_type); - /******************************************************************************* * * Function BTM_ReadConnectedTransportAddress @@ -551,161 +424,6 @@ void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda, tBT_TRANSPORT transport); -/******************************************************************************* - * - * Function BTM_UseLeLink - * - * Description Select the underlying physical link to use. - * - * Returns true to use LE, false use BR/EDR. - * - ******************************************************************************/ -bool BTM_UseLeLink(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_BleReadPhy - * - * Description To read the current PHYs for specified LE connection - * - * - * Returns BTM_SUCCESS if success; otherwise failed. - * - ******************************************************************************/ -void BTM_BleReadPhy( - const RawAddress& bd_addr, - base::Callback cb); - -/******************************************************************************* - * - * Function BTM_BleSetPhy - * - * Description To set PHY preferences for specified LE connection - * - * - * Returns BTM_SUCCESS if success; otherwise failed. - * BTM_MODE_UNSUPPORTED if local controller doesn't support LE - * 2M or LE Coded PHY, - * BTM_ILLEGAL_VALUE if specified remote doesn't support LE 2M - * or LE Coded PHY, - * BTM_WRONG_MODE if Device in wrong mode for request. - * - ******************************************************************************/ -void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys, - uint16_t phy_options); - -/******************************************************************************* - * - * Function BTM_BleDataSignature - * - * Description This function is called to sign the data using AES128 CMAC - * algorith. - * - * Parameter bd_addr: target device the data to be signed for. - * p_text: singing data - * len: length of the signing data - * signature: output parameter where data signature is going to - * be stored. - * - * Returns true if signing sucessul, otherwise false. - * - ******************************************************************************/ -bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text, - uint16_t len, BLE_SIGNATURE signature); - -/******************************************************************************* - * - * Function BTM_BleVerifySignature - * - * Description This function is called to verify the data signature - * - * Parameter bd_addr: target device the data to be signed for. - * p_orig: original data before signature. - * len: length of the signing data - * counter: counter used when doing data signing - * p_comp: signature to be compared against. - - * Returns true if signature verified correctly; otherwise false. - * - ******************************************************************************/ -bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig, - uint16_t len, uint32_t counter, uint8_t* p_comp); - -/******************************************************************************* - * - * Function BTM_GetLeSecurityState - * - * Description This function is called to get security mode 1 flags and - * encryption key size for LE peer. - * - * Returns bool true if LE device is found, false otherwise. - * - ******************************************************************************/ -bool BTM_GetLeSecurityState(const RawAddress& bd_addr, - uint8_t* p_le_dev_sec_flags, - uint8_t* p_le_key_size); - -/******************************************************************************* - * - * Function BTM_BleSecurityProcedureIsRunning - * - * Description This function indicates if LE security procedure is - * currently running with the peer. - * - * Returns bool true if security procedure is running, false otherwise. - * - ******************************************************************************/ -bool BTM_BleSecurityProcedureIsRunning(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_BleGetSupportedKeySize - * - * Description This function gets the maximum encryption key size in bytes - * the local device can suport. - * record. - * - * Returns the key size or 0 if the size can't be retrieved. - * - ******************************************************************************/ -uint8_t BTM_BleGetSupportedKeySize(const RawAddress& bd_addr); - -void BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector name, tBTM_BLE_PF_CFG_CBACK cb); - -void BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index); - -void BTM_LE_PF_manu_data(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, uint16_t company_id, - uint16_t company_id_mask, std::vector data, - std::vector data_mask, - tBTM_BLE_PF_CFG_CBACK cb); - -void BTM_LE_PF_srvc_data_pattern(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector data, - std::vector data_mask, - tBTM_BLE_PF_CFG_CBACK cb); - -void BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, tBLE_BD_ADDR addr, - tBTM_BLE_PF_CFG_CBACK cb); - -void BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_COND_TYPE filter_type, - const bluetooth::Uuid& uuid, - tBTM_BLE_PF_LOGIC_TYPE cond_logic, - const bluetooth::Uuid& uuid_mask, - tBTM_BLE_PF_CFG_CBACK cb); - -void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector commands, tBTM_BLE_PF_CFG_CBACK cb); -void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_CFG_CBACK cb); - /******************************************************************************* * * Function BTM_BleAdvFilterParamSetup @@ -719,30 +437,6 @@ void BTM_BleAdvFilterParamSetup( std::unique_ptr p_filt_params, tBTM_BLE_PF_PARAM_CB cb); -/******************************************************************************* - * - * Function BTM_BleUpdateAdvFilterPolicy - * - * Description This function update the filter policy of advertiser. - * - * Parameter adv_policy: advertising filter policy - * - * Return void - ******************************************************************************/ -void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy); - -/******************************************************************************* - * - * Function BTM_BleEnableDisableFilterFeature - * - * Description Enable or disable the APCF feature - * - * Parameters enable - true - enables APCF, false - disables APCF - * - ******************************************************************************/ -void BTM_BleEnableDisableFilterFeature(uint8_t enable, - tBTM_BLE_PF_STATUS_CBACK p_stat_cback); - /******************************************************************************* * * Function BTM_BleMaxMultiAdvInstanceCount @@ -858,68 +552,39 @@ void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len, /******************************************************************************* * - * Function BTM_AllocateSCN - * - * Description Look through the Server Channel Numbers for a free one to be - * used with an RFCOMM connection. - * - * Returns Allocated SCN number or 0 if none. - * - ******************************************************************************/ -uint8_t BTM_AllocateSCN(void); - -/******************************************************************************* - * - * Function BTM_TryAllocateSCN - * - * Description Try to allocate a fixed server channel - * - * Returns Returns true if server channel was available - * - ******************************************************************************/ -bool BTM_TryAllocateSCN(uint8_t scn); - -/******************************************************************************* - * - * Function BTM_FreeSCN - * - * Description Free the specified SCN. + * Function BTM_WritePageTimeout * - * Returns true if successful, false if SCN is not in use or invalid + * Description Send HCI Wite Page Timeout. * ******************************************************************************/ -bool BTM_FreeSCN(uint8_t scn); +void BTM_WritePageTimeout(uint16_t timeout); /******************************************************************************* * - * Function BTM_SetTraceLevel - * - * Description This function sets the trace level for BTM. If called with - * a value of 0xFF, it simply returns the current trace level. + * Function BTM_WriteVoiceSettings * - * Returns The new or current trace level + * Description Send HCI Write Voice Settings command. + * See hcidefs.h for settings bitmask values. * ******************************************************************************/ -uint8_t BTM_SetTraceLevel(uint8_t new_level); +void BTM_WriteVoiceSettings(uint16_t settings); /******************************************************************************* * - * Function BTM_WritePageTimeout + * Function BTM_EnableTestMode * - * Description Send HCI Wite Page Timeout. + * Description Send HCI the enable device under test command. * - ******************************************************************************/ -void BTM_WritePageTimeout(uint16_t timeout); - -/******************************************************************************* + * Note: Controller can only be taken out of this mode by + * resetting the controller. * - * Function BTM_WriteVoiceSettings + * Returns + * BTM_SUCCESS Command sent. + * BTM_NO_RESOURCES If out of resources to send the command. * - * Description Send HCI Write Voice Settings command. - * See hcidefs.h for settings bitmask values. * ******************************************************************************/ -void BTM_WriteVoiceSettings(uint16_t settings); +tBTM_STATUS BTM_EnableTestMode(void); /******************************************************************************* * @@ -1218,352 +883,17 @@ void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status, ******************************************************************************/ uint8_t BTM_GetNumScoLinks(void); -/***************************************************************************** - * SECURITY MANAGEMENT FUNCTIONS - ****************************************************************************/ -/******************************************************************************* - * - * Function BTM_SecRegister - * - * Description Application manager calls this function to register for - * security services. There can be one and only one - * application saving link keys. BTM allows only first - * registration. - * - * Returns true if registered OK, else false - * - ******************************************************************************/ -bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info); - -/******************************************************************************* - * - * Function BTM_SecAddRmtNameNotifyCallback - * - * Description Profiles can register to be notified when name of the - * remote device is resolved (up to - * BTM_SEC_MAX_RMT_NAME_CALLBACKS). - * - * Returns true if registered OK, else false - * - ******************************************************************************/ -bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback); - -/******************************************************************************* - * - * Function BTM_SecDeleteRmtNameNotifyCallback - * - * Description A profile can deregister notification when a new Link Key - * is generated per connection. - * - * Returns true if OK, else false - * - ******************************************************************************/ -bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback); - -/******************************************************************************* - * - * Function BTM_GetSecurityFlagsByTransport - * - * Description Get security flags for the device on a particular transport - * - * Parameters bd_addr: BD address of remote device - * p_sec_flags : Out parameter to be filled with security - * flags for the connection - * transport : Physical transport of the connection - * (BR/EDR or LE) - * - * Returns bool true or false is device found - * - ******************************************************************************/ -bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr, - uint8_t* p_sec_flags, - tBT_TRANSPORT transport); - -/******************************************************************************* - * - * Function BTM_SetPinType - * - * Description Set PIN type for the device. - * - * Returns void - * - ******************************************************************************/ -void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len); - -/******************************************************************************* - * - * Function BTM_SetSecurityLevel - * - * Description Register service security level with Security Manager. Each - * service must register its requirements regardless of the - * security level that is used. This API is called once for - * originators and again for acceptors of connections. - * - * Returns true if registered OK, else false - * - ******************************************************************************/ -bool BTM_SetSecurityLevel(bool is_originator, const char* p_name, - uint8_t service_id, uint16_t sec_level, uint16_t psm, - uint32_t mx_proto_id, uint32_t mx_chan_id); - -/******************************************************************************* - * - * Function BTM_SecClrService - * - * Description Removes specified service record(s) from the security - * database. All service records with the specified name are - * removed. Typically used only by devices with limited RAM - * so that it can reuse an old security service record. - * - * Returns Number of records that were freed. - * - ******************************************************************************/ -uint8_t BTM_SecClrService(uint8_t service_id); - -/******************************************************************************* - * - * Function BTM_SecAddDevice - * - * Description Add/modify device. This function will be normally called - * during host startup to restore all required information - * stored in the NVRAM. - * dev_class, bd_name, link_key, and features are NULL if - * unknown - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, - const BD_NAME& bd_name, uint8_t* features, - LinkKey* link_key, uint8_t key_type, uint8_t pin_length); - -/** Free resources associated with the device associated with |bd_addr| address. - * - * *** WARNING *** - * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function - * is called, also any of it's fields. i.e. if you use p_dev_rec->bd_addr, it is - * no longer valid! - * *** WARNING *** - * - * Returns true if removed OK, false if not found or ACL link is active. - */ -bool BTM_SecDeleteDevice(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_SecClearSecurityFlags - * - * Description Reset the security flags (mark as not-paired) for a given - * remove device. - * - ******************************************************************************/ -void BTM_SecClearSecurityFlags(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_SecGetDeviceLinkKeyType - * - * Description This function is called to obtain link key type for the - * device. - * it returns BTM_SUCCESS if link key is available, or - * BTM_UNKNOWN_ADDR if Security Manager does not know about - * the device or device record does not contain link key info - * - * Returns BTM_LKEY_TYPE_IGNORE if link key is unknown, link type - * otherwise. - * - ******************************************************************************/ -tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_PINCodeReply - * - * Description This function is called after Security Manager submitted - * PIN code request to the UI. - * - * Parameters: bd_addr - Address of the device for which PIN was - * requested - * res - result of the operation BTM_SUCCESS if - * success - * pin_len - length in bytes of the PIN Code - * p_pin - pointer to array with the PIN Code - * - * Returns void - * - ******************************************************************************/ -void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, - uint8_t pin_len, uint8_t* p_pin); - -/******************************************************************************* - * - * Function BTM_SecBond - * - * Description Perform bonding by designated transport - * - * Parameters: bd_addr - Address of the device to bond - * addr_type - address type for LE transport - * pin_len - length in bytes of the PIN Code - * p_pin - pointer to array with the PIN Code - * transport : Physical transport to use for bonding - * (BR/EDR or LE) - * - * Returns BTM_CMD_STARTED if successfully initiated, otherwise error - * - ******************************************************************************/ -tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type); - /******************************************************************************* * - * Function BTM_SecBondCancel + * Function BTM_GetScoDebugDump * - * Description This function is called to cancel ongoing bonding process - * with peer device. + * Description Get the status of SCO. This function is only used for + * testing and debugging purposes. * - * Returns BTM_CMD_STARTED if successfully initiated, otherwise error - * - ******************************************************************************/ -tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_SetEncryption - * - * Description This function is called to ensure that connection is - * encrypted. Should be called only on an open connection. - * Typically only needed for connections that first want to - * bring up unencrypted links, then later encrypt them. - * - * Parameters: bd_addr - Address of the peer device - * transport - Link transport - * p_callback - Pointer to callback function called if - * this function returns PENDING after required - * procedures are completed. Can be set to - * NULL if status is not desired. - * p_ref_data - pointer to any data the caller wishes to - * receive in the callback function upon - * completion. - * can be set to NULL if not used. - * sec_act - LE security action, unused for BR/EDR - * - * Returns BTM_SUCCESS - already encrypted - * BTM_PENDING - command will be returned in the callback - * BTM_WRONG_MODE- connection not up. - * BTM_BUSY - security procedures are currently active - * BTM_MODE_UNSUPPORTED - if security manager not linked in. - * - ******************************************************************************/ -tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, - tBT_TRANSPORT transport, - tBTM_SEC_CALLBACK* p_callback, void* p_ref_data, - tBTM_BLE_SEC_ACT sec_act); - -/******************************************************************************* - * - * Function BTM_ConfirmReqReply - * - * Description This function is called to confirm the numeric value for - * Simple Pairing in response to BTM_SP_CFM_REQ_EVT - * - * Parameters: res - result of the operation BTM_SUCCESS if - * success - * bd_addr - Address of the peer device - * - ******************************************************************************/ -void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_PasskeyReqReply - * - * Description This function is called to provide the passkey for - * Simple Pairing in response to BTM_SP_KEY_REQ_EVT - * - * Parameters: res - result of the operation BTM_SUCCESS if - * success - * bd_addr - Address of the peer device - * passkey - numeric value in the range of - * 0 - 999999(0xF423F). - * - ******************************************************************************/ -void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr, - uint32_t passkey); - -/******************************************************************************* - * - * Function BTM_IoCapRsp - * - * Description This function is called in response to BTM_SP_IO_REQ_EVT - * When the event data io_req.oob_data is set to - * BTM_OOB_UNKNOWN by the tBTM_SP_CALLBACK implementation, this - * function is called to provide the actual response - * - * Parameters: bd_addr - Address of the peer device - * io_cap - The IO capability of local device. - * oob - BTM_OOB_NONE or BTM_OOB_PRESENT. - * auth_req- MITM protection required or not. - * - ******************************************************************************/ -void BTM_IoCapRsp(const RawAddress& bd_addr, tBTM_IO_CAP io_cap, - tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req); - -/******************************************************************************* - * - * Function BTM_ReadLocalOobData - * - * Description This function is called to read the local OOB data from - * LM - * - ******************************************************************************/ -void BTM_ReadLocalOobData(void); - -/******************************************************************************* - * - * Function BTM_RemoteOobDataReply - * - * Description This function is called to provide the remote OOB data for - * Simple Pairing in response to BTM_SP_RMT_OOB_EVT - * - * Parameters: bd_addr - Address of the peer device - * c - simple pairing Hash C. - * r - simple pairing Randomizer C. - * - ******************************************************************************/ -void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr, - const Octet16& c, const Octet16& r); - -/******************************************************************************* - * - * Function BTM_BothEndsSupportSecureConnections - * - * Description This function is called to check if both the local device - * and the peer device specified by bd_addr support BR/EDR - * Secure Connections. - * - * Parameters: bd_addr - address of the peer - * - * Returns true if BR/EDR Secure Connections are supported by both - * local and the remote device. - * else false. + * Returns Data with SCO related debug dump. * ******************************************************************************/ -bool BTM_BothEndsSupportSecureConnections(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_PeerSupportsSecureConnections - * - * Description This function is called to check if the peer supports - * BR/EDR Secure Connections. - * - * Parameters: bd_addr - address of the peer - * - * Returns true if BR/EDR Secure Connections are supported by the peer, - * else false. - * - ******************************************************************************/ -bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr); +tBTM_SCO_DEBUG_DUMP BTM_GetScoDebugDump(void); /******************************************************************************* * @@ -1582,18 +912,6 @@ bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr); ******************************************************************************/ tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(const RawAddress& bd_addr); -/******************************************************************************* - * - * Function BTM_SecReadDevName - * - * Description Looks for the device name in the security database for the - * specified BD address. - * - * Returns Pointer to the name or NULL - * - ******************************************************************************/ -char* BTM_SecReadDevName(const RawAddress& bd_addr); - /******************************************************************************* * * Function BTM_GetHCIConnHandle @@ -1607,24 +925,6 @@ char* BTM_SecReadDevName(const RawAddress& bd_addr); uint16_t BTM_GetHCIConnHandle(const RawAddress& remote_bda, tBT_TRANSPORT transport); -/******************************************************************************* - * - * Function BTM_DeleteStoredLinkKey - * - * Description This function is called to delete link key for the specified - * device addresses from the NVRAM storage attached to the - * Bluetooth controller. - * - * Parameters: bd_addr - Addresses of the devices - * p_cb - Call back function to be called to return - * the results - * - ******************************************************************************/ -tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* bd_addr, - tBTM_CMPL_CB* p_cb); - -tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void); - /** * * BLE API @@ -1730,31 +1030,6 @@ uint16_t BTM_BleReadDiscoverability(); ******************************************************************************/ uint16_t BTM_BleReadConnectability(); -/******************************************************************************* - * - * Function BTM_BleConfigPrivacy - * - * Description This function is called to enable or disable the privacy in - * the local device. - * - * Parameters enable: true to enable it; false to disable it. - * - * Returns bool privacy mode set success; otherwise failed. - * - ******************************************************************************/ -bool BTM_BleConfigPrivacy(bool enable); - -/******************************************************************************* - * - * Function BTM_BleLocalPrivacyEnabled - * - * Description Checks if local device supports private address - * - * Returns Return true if local privacy is enabled else false - * - ******************************************************************************/ -bool BTM_BleLocalPrivacyEnabled(void); - /** * This functions are called to configure the adv data payload filter condition */ @@ -1826,7 +1101,7 @@ tBTM_STATUS BTM_DisconnectAllAcls(void); * Returns Return btm status * ******************************************************************************/ -using LeRandCallback = base::Callback; +using LeRandCallback = base::OnceCallback; tBTM_STATUS BTM_LeRand(LeRandCallback); /******************************************************************************* @@ -1904,11 +1179,5 @@ tBTM_STATUS BTM_BleResetId(void); */ void SendRemoteNameRequest(const RawAddress& raw_address); -tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, - bool is_originator, - uint16_t security_requirement, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data); - } // namespace shim } // namespace bluetooth diff --git a/system/main/shim/config.cc b/system/main/shim/config.cc index b99dc8a95f7431767ed4d61f1ee38d042ebae825..bc16ef84a4fd0fa38e866950de9ad58ac6fe1401 100644 --- a/system/main/shim/config.cc +++ b/system/main/shim/config.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include "gd/os/log.h" #include "gd/storage/storage_module.h" @@ -143,6 +142,10 @@ bool BtifConfigInterface::RemoveProperty(const std::string& section, return GetStorage()->RemoveProperty(section, property); } +void BtifConfigInterface::RemoveSection(const std::string& section) { + GetStorage()->RemoveSection(section); +} + std::vector BtifConfigInterface::GetPersistentDevices() { return GetStorage()->GetPersistentSections(); } diff --git a/system/main/shim/config.h b/system/main/shim/config.h index 082087dcf35b36888738b3941ccacf333f8ed108..2ee022c45ba8c5fb8ac2771f7ce2595619d10852 100644 --- a/system/main/shim/config.h +++ b/system/main/shim/config.h @@ -16,7 +16,6 @@ #pragma once -#include #include #include #include @@ -52,6 +51,7 @@ class BtifConfigInterface { const uint8_t* value, size_t length); static bool RemoveProperty(const std::string& section, const std::string& key); + static void RemoveSection(const std::string& section); static std::vector GetPersistentDevices(); static void ConvertEncryptOrDecryptKeyIfNeeded(); static void Clear(); diff --git a/system/main/shim/controller.cc b/system/main/shim/controller.cc index dc557f8a92eaf0ff045a4592c07582405478a158..10d130c80528e778d0535860d211acbda2aaa640 100644 --- a/system/main/shim/controller.cc +++ b/system/main/shim/controller.cc @@ -19,16 +19,13 @@ #include "main/shim/controller.h" #include "btcore/include/module.h" -#include "gd/common/contextual_callback.h" -#include "gd/common/init_flags.h" #include "gd/hci/controller.h" #include "hci/controller.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" #include "main/shim/shim.h" -#include "main/shim/stack.h" #include "osi/include/future.h" -#include "osi/include/log.h" +#include "stack/include/btm_status.h" #include "types/raw_address.h" using ::bluetooth::shim::GetController; @@ -286,7 +283,7 @@ static uint8_t controller_clear_event_mask() { static uint8_t controller_le_rand(LeRandCallback cb) { LOG_VERBOSE("Called!"); - bluetooth::shim::GetController()->LeRand(cb); + bluetooth::shim::GetController()->LeRand(std::move(cb)); return BTM_SUCCESS; } diff --git a/system/main/shim/dumpsys.h b/system/main/shim/dumpsys.h index 469989165320f65dd5b0c6f244b6168b87ea0e25..84f3ad70bea5d56a41f9f6a4d7166aad3c9cd0be 100644 --- a/system/main/shim/dumpsys.h +++ b/system/main/shim/dumpsys.h @@ -16,9 +16,8 @@ #pragma once +#include #include -#include -#include #define LOG_DUMPSYS(fd, fmt, args...) \ do { \ @@ -30,14 +29,6 @@ dprintf(fd, " ----- %s -----\n", title); \ } while (false) -#define PRIVATE_CELL(number) \ - (number \ - .replace(0, (number.size() > 2) ? number.size() - 2 : 0, \ - (number.size() > 2) ? number.size() - 2 : 0, '*') \ - .c_str()) - -#define PRIVATE_NAME(name) (name) - inline double ticks_to_seconds(uint16_t ticks) { return (static_cast(ticks) * 0.625 * 0.001); } diff --git a/system/main/shim/entry.cc b/system/main/shim/entry.cc index 61ac4ba582dc533a006c1932c8f63519672029a5..032c7a5ccee1cfbf13a5e3a2f9df5c5f0e6c59b6 100644 --- a/system/main/shim/entry.cc +++ b/system/main/shim/entry.cc @@ -16,7 +16,6 @@ #include "main/shim/entry.h" -#include "gd/btaa/activity_attribution.h" #include "gd/hal/snoop_logger.h" #include "gd/hci/controller.h" #include "gd/hci/distance_measurement_manager.h" @@ -147,12 +146,6 @@ hci::VendorSpecificEventManager* GetVendorSpecificEventManager() { ->GetInstance(); } -activity_attribution::ActivityAttribution* GetActivityAttribution() { - return Stack::GetInstance() - ->GetStackManager() - ->GetInstance(); -} - metrics::CounterMetrics* GetCounterMetrics() { return Stack::GetInstance() ->GetStackManager() diff --git a/system/main/shim/entry.h b/system/main/shim/entry.h index 86815f2da1122a5894064fd06bd4039ebd790e1d..560b9218ea7218511b0b743d43d3947fbcddf15c 100644 --- a/system/main/shim/entry.h +++ b/system/main/shim/entry.h @@ -29,15 +29,10 @@ * interfaces may be made here */ -#include "osi/include/future.h" - namespace bluetooth { namespace os { class Handler; } -namespace activity_attribution { -class ActivityAttribution; -} namespace neighbor { class ConnectabilityModule; class DiscoverabilityModule; @@ -104,7 +99,6 @@ hal::SnoopLogger* GetSnoopLogger(); storage::StorageModule* GetStorage(); hci::AclManager* GetAclManager(); hci::VendorSpecificEventManager* GetVendorSpecificEventManager(); -activity_attribution::ActivityAttribution* GetActivityAttribution(); metrics::CounterMetrics* GetCounterMetrics(); hci::MsftExtensionManager* GetMsftExtensionManager(); diff --git a/system/main/shim/hci_layer.cc b/system/main/shim/hci_layer.cc index bbd4157c4e68ca773a834f43a91f7d50bd707931..0b44f8773878f360e4c34c11f54feb3b50371874 100644 --- a/system/main/shim/hci_layer.cc +++ b/system/main/shim/hci_layer.cc @@ -16,23 +16,23 @@ #define LOG_TAG "bt_shim_hci" -#include "hci/hci_layer.h" +#include "main/shim/hci_layer.h" #include #include #include -#include "gd/common/init_flags.h" +#include "common/bidi_queue.h" +#include "common/init_flags.h" +#include "hci/acl_connection_interface.h" +#include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "hci/include/packet_fragmenter.h" -#include "hci/le_acl_connection_interface.h" #include "hci/vendor_specific_event_manager.h" -#include "main/shim/hci_layer.h" -#include "main/shim/shim.h" -#include "main/shim/stack.h" +#include "main/shim/entry.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/future.h" #include "packet/raw_builder.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" @@ -113,6 +113,7 @@ bool is_valid_event_code(bluetooth::hci::EventCode event_code) { return true; case bluetooth::hci::EventCode::VENDOR_SPECIFIC: case bluetooth::hci::EventCode::LE_META_EVENT: // Private to hci + case bluetooth::hci::EventCode::AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED: return false; } return false; @@ -171,10 +172,9 @@ static bool event_already_registered_in_hci_layer( case bluetooth::hci::EventCode::LE_META_EVENT: case bluetooth::hci::EventCode::DISCONNECTION_COMPLETE: case bluetooth::hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE: - return true; case bluetooth::hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION: case bluetooth::hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE: - return bluetooth::common::init_flags::gd_remote_name_request_is_enabled(); + return true; default: return false; } @@ -267,21 +267,11 @@ static bool event_already_registered_in_le_scanning_manager( } // namespace namespace cpp { -bluetooth::common::BidiQueueEnd* hci_queue_end = - nullptr; -bluetooth::common::BidiQueueEnd* hci_sco_queue_end = - nullptr; bluetooth::common::BidiQueueEnd* hci_iso_queue_end = nullptr; -static bluetooth::os::EnqueueBuffer* pending_data = - nullptr; static bluetooth::os::EnqueueBuffer* pending_iso_data = nullptr; -static bluetooth::os::EnqueueBuffer* - pending_sco_data = nullptr; static std::unique_ptr MakeUniquePacket( const uint8_t* data, size_t len) { @@ -324,6 +314,16 @@ static void subevent_callback( &le_meta_event_view)); } +static void vendor_specific_event_callback( + bluetooth::hci::VendorSpecificEventView vendor_specific_event_view) { + if (!send_data_upwards) { + return; + } + send_data_upwards.Run( + FROM_HERE, + WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &vendor_specific_event_view)); +} + void OnTransmitPacketCommandComplete(command_complete_cb complete_callback, void* context, bluetooth::hci::CommandCompleteView view) { @@ -381,47 +381,6 @@ static void transmit_command(const BT_HDR* command, } } -static void transmit_fragment(const uint8_t* stream, size_t length) { - uint16_t handle_with_flags; - STREAM_TO_UINT16(handle_with_flags, stream); - auto pb_flag = static_cast( - handle_with_flags >> 12 & 0b11); - auto bc_flag = - static_cast(handle_with_flags >> 14); - uint16_t handle = HCID_GET_HANDLE(handle_with_flags); - ASSERT_LOG(handle <= HCI_HANDLE_MAX, "Require handle <= 0x%X, but is 0x%X", - HCI_HANDLE_MAX, handle); - length -= 2; - // skip data total length - stream += 2; - length -= 2; - auto payload = MakeUniquePacket(stream, length); - auto acl_packet = bluetooth::hci::AclBuilder::Create(handle, pb_flag, bc_flag, - std::move(payload)); - pending_data->Enqueue(std::move(acl_packet), - bluetooth::shim::GetGdShimHandler()); -} - -static void transmit_sco_fragment(const uint8_t* stream, size_t length) { - uint16_t handle_with_flags; - STREAM_TO_UINT16(handle_with_flags, stream); - uint16_t handle = HCID_GET_HANDLE(handle_with_flags); - ASSERT_LOG(handle <= HCI_HANDLE_MAX, "Require handle <= 0x%X, but is 0x%X", - HCI_HANDLE_MAX, handle); - - length -= 2; - // skip data total length - stream += 1; - length -= 1; - auto payload = std::vector(stream, stream + length); - auto sco_packet = bluetooth::hci::ScoBuilder::Create( - handle, bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED, - std::move(payload)); - - pending_sco_data->Enqueue(std::move(sco_packet), - bluetooth::shim::GetGdShimHandler()); -} - static void transmit_iso_fragment(const uint8_t* stream, size_t length) { uint16_t handle_with_flags; STREAM_TO_UINT16(handle_with_flags, stream); @@ -456,23 +415,6 @@ static void register_le_event(bluetooth::hci::SubeventCode subevent_code) { subevent_code, handler->Bind(subevent_callback)); } -static void sco_data_callback() { - if (hci_sco_queue_end == nullptr) { - return; - } - auto packet = hci_sco_queue_end->TryDequeue(); - ASSERT(packet != nullptr); - if (!packet->IsValid()) { - LOG_INFO("Dropping invalid packet of size %zu", packet->size()); - return; - } - if (!send_data_upwards) { - return; - } - auto data = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_SCO, packet.get()); - packet_fragmenter->reassemble_and_dispatch(data); -} - static void iso_data_callback() { if (hci_iso_queue_end == nullptr) { return; @@ -490,16 +432,6 @@ static void iso_data_callback() { packet_fragmenter->reassemble_and_dispatch(data); } -static void register_for_sco() { - hci_sco_queue_end = bluetooth::shim::GetHciLayer()->GetScoQueueEnd(); - hci_sco_queue_end->RegisterDequeue( - bluetooth::shim::GetGdShimHandler(), - bluetooth::common::Bind(sco_data_callback)); - pending_sco_data = - new bluetooth::os::EnqueueBuffer( - hci_sco_queue_end); -} - static void register_for_iso() { hci_iso_queue_end = bluetooth::shim::GetHciLayer()->GetIsoQueueEnd(); hci_iso_queue_end->RegisterDequeue( @@ -511,44 +443,11 @@ static void register_for_iso() { } static void on_shutting_down() { - if (pending_data != nullptr) { - pending_data->Clear(); - delete pending_data; - pending_data = nullptr; - } - if (pending_sco_data != nullptr) { - pending_sco_data->Clear(); - delete pending_sco_data; - pending_sco_data = nullptr; - } if (pending_iso_data != nullptr) { pending_iso_data->Clear(); delete pending_iso_data; pending_iso_data = nullptr; } - if (hci_queue_end != nullptr) { - for (uint16_t event_code_raw = 0; event_code_raw < 0x100; - event_code_raw++) { - auto event_code = static_cast(event_code_raw); - if (!is_valid_event_code(event_code)) { - continue; - } - if (event_already_registered_in_hci_layer(event_code)) { - continue; - } else if (event_already_registered_in_le_advertising_manager( - event_code)) { - continue; - } else if (event_already_registered_in_le_scanning_manager(event_code)) { - continue; - } - bluetooth::shim::GetHciLayer()->UnregisterEventHandler(event_code); - } - hci_queue_end = nullptr; - } - if (hci_sco_queue_end != nullptr) { - hci_sco_queue_end->UnregisterDequeue(); - hci_sco_queue_end = nullptr; - } if (hci_iso_queue_end != nullptr) { hci_iso_queue_end->UnregisterDequeue(); hci_iso_queue_end = nullptr; @@ -572,24 +471,6 @@ static void transmit_command(const BT_HDR* command, cpp::transmit_command(command, complete_callback, status_callback, context); } -static void command_complete_callback(BT_HDR* response, void* context) { - auto future = static_cast(context); - future_ready(future, response); -} - -static void command_status_callback(uint8_t status, BT_HDR* command, - void* context) { - LOG_ALWAYS_FATAL( - "transmit_command_futured should only send command complete opcode"); -} - -static future_t* transmit_command_futured(const BT_HDR* command) { - future_t* future = future_new(); - transmit_command(command, command_complete_callback, command_status_callback, - future); - return future; -} - static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) { uint16_t event = packet->event & MSG_EVT_MASK; @@ -598,15 +479,7 @@ static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) { bool free_after_transmit = event != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished; - if (event == MSG_STACK_TO_HC_HCI_ACL) { - const uint8_t* stream = packet->data + packet->offset; - size_t length = packet->len; - cpp::transmit_fragment(stream, length); - } else if (event == MSG_STACK_TO_HC_HCI_SCO) { - const uint8_t* stream = packet->data + packet->offset; - size_t length = packet->len; - cpp::transmit_sco_fragment(stream, length); - } else if (event == MSG_STACK_TO_HC_HCI_ISO) { + if (event == MSG_STACK_TO_HC_HCI_ISO) { const uint8_t* stream = packet->data + packet->offset; size_t length = packet->len; cpp::transmit_iso_fragment(stream, length); @@ -617,25 +490,14 @@ static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) { } } static void dispatch_reassembled(BT_HDR* packet) { - // Events should already have been dispatched before this point - CHECK((packet->event & MSG_EVT_MASK) != MSG_HC_TO_STACK_HCI_EVT); + // Only ISO should be handled here + CHECK((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ISO); CHECK(!send_data_upwards.is_null()); send_data_upwards.Run(FROM_HERE, packet); } -static void fragmenter_transmit_finished(BT_HDR* packet, - bool all_fragments_sent) { - if (all_fragments_sent) { - osi_free(packet); - } else { - // This is kind of a weird case, since we're dispatching a partially sent - // packet up to a higher layer. - // TODO(zachoverflow): rework upper layer so this isn't necessary. - send_data_upwards.Run(FROM_HERE, packet); - } -} static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = { - transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished}; + transmit_fragment, dispatch_reassembled}; static void transmit_downward(uint16_t type, void* raw_data) { bluetooth::shim::GetGdShimHandler()->Call( @@ -644,7 +506,6 @@ static void transmit_downward(uint16_t type, void* raw_data) { static hci_t interface = {.set_data_cb = set_data_cb, .transmit_command = transmit_command, - .transmit_command_futured = transmit_command_futured, .transmit_downward = transmit_downward}; const hci_t* bluetooth::shim::hci_layer_get_interface() { @@ -690,7 +551,12 @@ void bluetooth::shim::hci_on_reset_complete() { cpp::register_le_event(subevent_code); } - cpp::register_for_sco(); + // TODO handle BQR event in GD + auto handler = bluetooth::shim::GetGdShimHandler(); + bluetooth::shim::GetVendorSpecificEventManager()->RegisterEventHandler( + bluetooth::hci::VseSubeventCode::BQR_EVENT, + handler->Bind(cpp::vendor_specific_event_callback)); + cpp::register_for_iso(); } diff --git a/system/main/shim/helpers.h b/system/main/shim/helpers.h index 7d023291eb7873220aef1fcd17898b9a2f152e85..bd1dd93204e2bc1b04e9e8b168b17020d4be3ab3 100644 --- a/system/main/shim/helpers.h +++ b/system/main/shim/helpers.h @@ -20,7 +20,6 @@ #include "hci/address_with_type.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "stack/include/hci_error_code.h" #include "stack/include/hci_mode.h" #include "stack/include/hcidefs.h" diff --git a/system/main/shim/l2c_api.cc b/system/main/shim/l2c_api.cc index 00214264951d67e1243837a884edf8a2f4f859d6..1afa5976c02ff1116cc4a493a7ddc4bd39e8d3f5 100644 --- a/system/main/shim/l2c_api.cc +++ b/system/main/shim/l2c_api.cc @@ -21,41 +21,30 @@ #include #include -#include -#include #include "bta/include/bta_dm_acl.h" #include "gd/l2cap/classic/l2cap_classic_module.h" #include "gd/l2cap/le/l2cap_le_module.h" #include "gd/os/log.h" #include "gd/os/queue.h" -#include "main/shim/acl_api.h" #include "main/shim/btm.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" -#include "main/shim/stack.h" #include "osi/include/allocator.h" #include "stack/btm/btm_ble_int.h" #include "stack/btm/btm_sec.h" -#include "stack/include/acl_hci_link_interface.h" +#include "stack/btm/power_mode.h" #include "stack/include/ble_acl_interface.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_api.h" -#include "stack/include/btu.h" +#include "stack/include/btu_hcif.h" #include "stack/include/gatt_api.h" -#include "stack/include/sco_hci_link_interface.h" +#include "stack/include/main_thread.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" -void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval, - uint16_t latency, uint16_t timeout, - tHCI_STATUS status); -void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle, +void gatt_notify_phy_updated(tHCI_STATUS status, uint16_t handle, uint8_t tx_phy, uint8_t rx_phy); -void process_ssr_event(tHCI_STATUS status, uint16_t handle, uint16_t max_tx_lat, - uint16_t max_rx_lat); - namespace bluetooth { namespace shim { @@ -66,9 +55,6 @@ using namespace bluetooth::l2cap; namespace { uint16_t classic_cid_token_counter_ = 0x41; -constexpr uint64_t kBrEdrNotSupportedMask = 0x0000002000000000; // Bit 37 -constexpr uint64_t kLeSupportedControllerMask = 0x0000004000000000; // Bit 38 -constexpr uint64_t kLeSupportedHostMask = 0x0000000000000002; // Bit 1 std::unordered_map classic_cid_token_to_channel_map_; @@ -163,8 +149,9 @@ struct ClassicDynamicChannelHelper { channel_enqueue_buffer_.erase(cid_token); channels_[cid_token]->GetQueueUpEnd()->UnregisterDequeue(); channels_.erase(cid_token); - do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_DisconnectInd_Cb, - cid_token, false)); + do_in_main_thread( + FROM_HERE, + base::BindOnce(appl_info_.pL2CA_DisconnectInd_Cb, cid_token, false)); remove_classic_cid_token_entry(cid_token); initiated_by_us_.erase(cid_token); @@ -193,24 +180,28 @@ struct ClassicDynamicChannelHelper { if (initiator_local) { do_in_main_thread( - FROM_HERE, base::Bind(appl_info_.pL2CA_ConnectCfm_Cb, cid_token, 0)); + FROM_HERE, + base::BindOnce(appl_info_.pL2CA_ConnectCfm_Cb, cid_token, 0)); tL2CAP_CFG_INFO cfg_info{}; - do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_ConfigCfm_Cb, - cid_token, L2CAP_INITIATOR_LOCAL, - base::Unretained(&cfg_info))); + do_in_main_thread( + FROM_HERE, + base::BindOnce(appl_info_.pL2CA_ConfigCfm_Cb, cid_token, + L2CAP_INITIATOR_LOCAL, base::Unretained(&cfg_info))); } else { if (appl_info_.pL2CA_ConnectInd_Cb == nullptr) { Disconnect(cid_token); return; } - do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_ConnectInd_Cb, - address, cid_token, psm_, 0)); + do_in_main_thread(FROM_HERE, + base::BindOnce(appl_info_.pL2CA_ConnectInd_Cb, address, + cid_token, psm_, 0)); tL2CAP_CFG_INFO cfg_info{}; - do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_ConfigCfm_Cb, - cid_token, L2CAP_INITIATOR_LOCAL, - base::Unretained(&cfg_info))); + do_in_main_thread( + FROM_HERE, + base::BindOnce(appl_info_.pL2CA_ConfigCfm_Cb, cid_token, + L2CAP_INITIATOR_LOCAL, base::Unretained(&cfg_info))); } channel->GetQueueUpEnd()->RegisterDequeue( @@ -235,8 +226,8 @@ struct ClassicDynamicChannelHelper { std::copy(packet_vector.begin(), packet_vector.end(), buffer->data); buffer->len = packet_vector.size(); if (do_in_main_thread(FROM_HERE, - base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token, - base::Unretained(buffer))) != + base::BindOnce(appl_info_.pL2CA_DataInd_Cb, cid_token, + base::Unretained(buffer))) != BT_STATUS_SUCCESS) { osi_free(buffer); } @@ -389,87 +380,6 @@ struct RemoteFeature { std::unordered_map remote_feature_map_; -struct LinkPropertyListenerShim - : public bluetooth::l2cap::classic::LinkPropertyListener { - std::unordered_map address_to_handle_; - - void OnLinkConnected(hci::Address remote, uint16_t handle) override { - address_to_handle_[remote] = handle; - } - - void OnLinkDisconnected(hci::Address remote) override { - address_to_handle_.erase(remote); - } - - void OnReadRemoteVersionInformation(hci::ErrorCode error_code, - hci::Address remote, uint8_t lmp_version, - uint16_t manufacturer_name, - uint16_t sub_version) override { - auto bda = bluetooth::ToRawAddress(remote); - auto& entry = remote_feature_map_[bda]; - entry.lmp_version = lmp_version; - entry.manufacturer_name = manufacturer_name; - entry.sub_version = sub_version; - entry.version_info_received = true; - } - - void OnReadRemoteExtendedFeatures(hci::Address remote, uint8_t page_number, - uint8_t max_page_number, - uint64_t features) override { - auto bda = bluetooth::ToRawAddress(remote); - auto& entry = remote_feature_map_[bda]; - if (page_number == 0) { - entry.received_page_0 = true; - if (features & 0x20) entry.role_switch_supported = true; - entry.br_edr_supported = !(features & kBrEdrNotSupportedMask); - entry.le_supported_controller = features & kLeSupportedControllerMask; - std::memcpy(entry.raw_remote_features, &features, 8); - } - if (page_number == 1) { - entry.received_page_1 = true; - if (features & 0x01) entry.ssp_supported = true; - entry.le_supported_host = features & kLeSupportedHostMask; - } - if (entry.received_page_0 && entry.received_page_1) { - const bool le_supported = - entry.le_supported_controller && entry.le_supported_host; - btm_sec_set_peer_sec_caps(address_to_handle_[remote], entry.ssp_supported, - false, entry.role_switch_supported, - entry.br_edr_supported, le_supported); - } - } - - void OnRoleChange(hci::ErrorCode error_code, hci::Address remote, - hci::Role role) override { - btm_rejectlist_role_change_device(ToRawAddress(remote), - ToLegacyHciErrorCode(error_code)); - btm_acl_role_changed(ToLegacyHciErrorCode(error_code), ToRawAddress(remote), - ToLegacyRole(role)); - } - - void OnReadClockOffset(hci::Address remote, uint16_t clock_offset) override { - btm_sec_update_clock_offset(address_to_handle_[remote], clock_offset); - } - - void OnModeChange(hci::ErrorCode error_code, hci::Address remote, - hci::Mode mode, uint16_t interval) override { - btm_sco_chk_pend_unpark(ToLegacyHciErrorCode(error_code), - address_to_handle_[remote]); - btm_pm_proc_mode_change(ToLegacyHciErrorCode(error_code), - address_to_handle_[remote], ToLegacyHciMode(mode), - interval); - } - - void OnSniffSubrating(hci::ErrorCode error_code, hci::Address remote, - uint16_t max_tx_lat, uint16_t max_rx_lat, - uint16_t min_remote_timeout, - uint16_t min_local_timeout) override { - process_ssr_event(ToLegacyHciErrorCode(error_code), - address_to_handle_[remote], max_tx_lat, max_rx_lat); - } - -} link_property_listener_shim_; - class SecurityListenerShim : public bluetooth::l2cap::classic::LinkSecurityInterfaceListener { public: @@ -601,7 +511,7 @@ struct LeLinkPropertyListenerShim void OnPhyUpdate(hci::AddressWithType remote, uint8_t tx_phy, uint8_t rx_phy) override { - gatt_notify_phy_updated(GATT_SUCCESS, info_[remote.GetAddress()].handle, + gatt_notify_phy_updated(HCI_SUCCESS, info_[remote.GetAddress()].handle, tx_phy, rx_phy); } @@ -686,30 +596,6 @@ uint8_t* L2CA_ReadRemoteFeatures(const RawAddress& addr) { return entry.raw_remote_features; } -static void on_sco_disconnect(uint16_t handle, uint8_t reason) { - GetGdShimHandler()->Post(base::BindOnce(base::IgnoreResult(&btm_sco_removed), - handle, - static_cast(reason))); -} - -void L2CA_UseLegacySecurityModule() { - LOG_INFO("GD L2cap is using legacy security module"); - GetL2capClassicModule()->SetLinkPropertyListener( - GetGdShimHandler(), &link_property_listener_shim_); - - GetL2capClassicModule()->InjectSecurityEnforcementInterface( - &security_enforcement_shim_); - security_interface_ = GetL2capClassicModule()->GetSecurityInterface( - GetGdShimHandler(), &security_listener_shim_); - - GetL2capLeModule()->SetLinkPropertyListener(GetGdShimHandler(), - &le_link_property_listener_shim_); - GetL2capLeModule()->InjectSecurityEnforcementInterface( - &le_security_enforcement_shim_); - - GetAclManager()->HACK_SetNonAclDisconnectCallback(on_sco_disconnect); -} - /** * Classic Service Registration APIs */ @@ -1365,8 +1251,9 @@ struct LeDynamicChannelHelper { channel_enqueue_buffer_.erase(cid_token); channels_[cid_token]->GetQueueUpEnd()->UnregisterDequeue(); channels_.erase(cid_token); - do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_DisconnectInd_Cb, - cid_token, false)); + do_in_main_thread( + FROM_HERE, + base::BindOnce(appl_info_.pL2CA_DisconnectInd_Cb, cid_token, false)); remove_le_cid_token_entry(cid_token); initiated_by_us_.erase(cid_token); @@ -1403,15 +1290,17 @@ struct LeDynamicChannelHelper { if (initiator_local) { do_in_main_thread( - FROM_HERE, base::Bind(appl_info_.pL2CA_ConnectCfm_Cb, cid_token, 0)); + FROM_HERE, + base::BindOnce(appl_info_.pL2CA_ConnectCfm_Cb, cid_token, 0)); } else { if (appl_info_.pL2CA_ConnectInd_Cb == nullptr) { Disconnect(cid_token); return; } - do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_ConnectInd_Cb, - address, cid_token, psm_, 0)); + do_in_main_thread(FROM_HERE, + base::BindOnce(appl_info_.pL2CA_ConnectInd_Cb, address, + cid_token, psm_, 0)); } } @@ -1428,8 +1317,8 @@ struct LeDynamicChannelHelper { std::copy(packet_vector.begin(), packet_vector.end(), buffer->data); buffer->len = packet_vector.size(); if (do_in_main_thread(FROM_HERE, - base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token, - base::Unretained(buffer))) != + base::BindOnce(appl_info_.pL2CA_DataInd_Cb, cid_token, + base::Unretained(buffer))) != BT_STATUS_SUCCESS) { osi_free(buffer); } diff --git a/system/main/shim/l2c_api.h b/system/main/shim/l2c_api.h index 5e74daf9dd8c08ed9eb26911dba295a3b521fd79..9f12916ca00bef04e72c95d95293d510283ddd25 100644 --- a/system/main/shim/l2c_api.h +++ b/system/main/shim/l2c_api.h @@ -16,8 +16,6 @@ #pragma once -#include -#include #include #include "stack/include/bt_hdr.h" @@ -256,18 +254,6 @@ bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid); bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout, tBT_TRANSPORT transport); -/******************************************************************************* - * - * Function L2CA_SetTraceLevel - * - * Description This function sets the trace level for L2CAP. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t L2CA_SetTraceLevel(uint8_t trace_level); - /******************************************************************************* * * Function L2CA_FlushChannel @@ -469,9 +455,6 @@ void L2CA_ConnectForSecurity(const RawAddress& bd_addr); // Set bonding state to acquire/release link refcount void L2CA_SetBondingState(const RawAddress& p_bd_addr, bool is_bonding); -// Indicated by shim stack manager that GD L2cap is enabled but Security is not -void L2CA_UseLegacySecurityModule(); - void L2CA_SwitchRoleToCentral(const RawAddress& addr); bool L2CA_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version, diff --git a/system/main/shim/le_advertising_manager.cc b/system/main/shim/le_advertising_manager.cc index cdaa636a06b160c9d362c19c008d5bea83b4107b..d04862ecedf7fd47d57512332b3b0faa83f32456 100644 --- a/system/main/shim/le_advertising_manager.cc +++ b/system/main/shim/le_advertising_manager.cc @@ -17,7 +17,6 @@ #define LOG_TAG "bt_shim_advertiser" #include "le_advertising_manager.h" -#include "utils.h" #include #include @@ -27,18 +26,13 @@ #include "btif/include/btif_common.h" #include "gd/common/init_flags.h" -#include "gd/hci/acl_manager.h" -#include "gd/hci/controller.h" #include "gd/hci/le_advertising_manager.h" -#include "gd/packet/packet_view.h" -#include "gd/storage/storage_module.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" -#include "stack/include/ble_advertiser.h" -#include "stack/include/btm_api.h" #include "stack/include/btm_log_history.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/main_thread.h" #include "types/raw_address.h" +#include "utils.h" using bluetooth::hci::Address; using bluetooth::hci::AddressType; @@ -81,6 +75,13 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, void Unregister(uint8_t advertiser_id) override { LOG(INFO) << __func__ << " in shim layer"; bluetooth::shim::GetAdvertising()->RemoveAdvertiser(advertiser_id); + int reg_id = + bluetooth::shim::GetAdvertising()->GetAdvertiserRegId(advertiser_id); + uint8_t client_id = is_native_advertiser(reg_id); + // if registered by native client, remove the register id + if (client_id != kAdvertiserClientIdJni) { + native_reg_id_map[client_id].erase(reg_id); + } BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le advert stopped", base::StringPrintf("advert_id:%d", advertiser_id)); } @@ -121,7 +122,7 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, AdvertiseParameters params, std::vector advertise_data, std::vector scan_response_data, int timeout_s, - MultiAdvCb timeout_cb) override { + StatusCallback timeout_cb) override { LOG(INFO) << __func__ << " in shim layer"; bluetooth::hci::AdvertisingConfig config{}; @@ -135,7 +136,8 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, set_terminated_callback, bluetooth::shim::GetGdShimHandler()); } - void StartAdvertisingSet(int reg_id, IdTxPowerStatusCallback register_cb, + void StartAdvertisingSet(uint8_t client_id, int reg_id, + IdTxPowerStatusCallback register_cb, AdvertiseParameters params, std::vector advertise_data, std::vector scan_response_data, @@ -154,12 +156,17 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, parse_gap_data(scan_response_data, config.scan_response); parse_gap_data(periodic_data, config.periodic_data); - bluetooth::shim::GetAdvertising()->ExtendedCreateAdvertiser( - reg_id, config, scan_callback, set_terminated_callback, duration, - maxExtAdvEvents, bluetooth::shim::GetGdShimHandler()); + // if registered by native client, add the register id + if (client_id != kAdvertiserClientIdJni) { + native_reg_id_map[client_id].insert(reg_id); + } - LOG(INFO) << "create advertising set, reg_id:" << reg_id; + bluetooth::shim::GetAdvertising()->ExtendedCreateAdvertiser( + client_id, reg_id, config, scan_callback, set_terminated_callback, + duration, maxExtAdvEvents, bluetooth::shim::GetGdShimHandler()); + LOG_INFO("create advertising set, client_id:%d, reg_id:%d", client_id, + reg_id); BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le advert started", base::StringPrintf("reg_id:%d", reg_id)); @@ -199,6 +206,11 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, advertising_callbacks_ = callbacks; } + void RegisterCallbacksNative(AdvertisingCallbacks* callbacks, + uint8_t client_id) { + native_adv_callbacks_map_[client_id] = callbacks; + } + void on_scan(Address address, AddressType address_type) { LOG(INFO) << __func__ << " in shim layer"; } @@ -220,47 +232,70 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, void OnAdvertisingSetStarted(int reg_id, uint8_t advertiser_id, int8_t tx_power, AdvertisingStatus status) override { + uint8_t client_id = is_native_advertiser(reg_id); + if (client_id != kAdvertiserClientIdJni) { + // Invoke callback for native client + do_in_main_thread( + FROM_HERE, + base::Bind(&AdvertisingCallbacks::OnAdvertisingSetStarted, + base::Unretained(native_adv_callbacks_map_[client_id]), + reg_id, advertiser_id, tx_power, status)); + return; + } do_in_jni_thread( - FROM_HERE, base::Bind(&AdvertisingCallbacks::OnAdvertisingSetStarted, - base::Unretained(advertising_callbacks_), reg_id, - advertiser_id, tx_power, status)); + FROM_HERE, + base::BindOnce(&AdvertisingCallbacks::OnAdvertisingSetStarted, + base::Unretained(advertising_callbacks_), reg_id, + advertiser_id, tx_power, status)); } void OnAdvertisingEnabled(uint8_t advertiser_id, bool enable, uint8_t status) { + int reg_id = + bluetooth::shim::GetAdvertising()->GetAdvertiserRegId(advertiser_id); + uint8_t client_id = is_native_advertiser(reg_id); + if (client_id != kAdvertiserClientIdJni) { + // Invoke callback for native client + do_in_main_thread( + FROM_HERE, + base::Bind(&AdvertisingCallbacks::OnAdvertisingEnabled, + base::Unretained(native_adv_callbacks_map_[client_id]), + advertiser_id, enable, status)); + return; + } do_in_jni_thread(FROM_HERE, - base::Bind(&AdvertisingCallbacks::OnAdvertisingEnabled, - base::Unretained(advertising_callbacks_), - advertiser_id, enable, status)); + base::BindOnce(&AdvertisingCallbacks::OnAdvertisingEnabled, + base::Unretained(advertising_callbacks_), + advertiser_id, enable, status)); } void OnAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) { do_in_jni_thread(FROM_HERE, - base::Bind(&AdvertisingCallbacks::OnAdvertisingDataSet, - base::Unretained(advertising_callbacks_), - advertiser_id, status)); + base::BindOnce(&AdvertisingCallbacks::OnAdvertisingDataSet, + base::Unretained(advertising_callbacks_), + advertiser_id, status)); } void OnScanResponseDataSet(uint8_t advertiser_id, uint8_t status) { - do_in_jni_thread(FROM_HERE, - base::Bind(&AdvertisingCallbacks::OnScanResponseDataSet, - base::Unretained(advertising_callbacks_), - advertiser_id, status)); + do_in_jni_thread( + FROM_HERE, base::BindOnce(&AdvertisingCallbacks::OnScanResponseDataSet, + base::Unretained(advertising_callbacks_), + advertiser_id, status)); } void OnAdvertisingParametersUpdated(uint8_t advertiser_id, int8_t tx_power, uint8_t status) { do_in_jni_thread( FROM_HERE, - base::Bind(&AdvertisingCallbacks::OnAdvertisingParametersUpdated, - base::Unretained(advertising_callbacks_), advertiser_id, - tx_power, status)); + base::BindOnce(&AdvertisingCallbacks::OnAdvertisingParametersUpdated, + base::Unretained(advertising_callbacks_), advertiser_id, + tx_power, status)); } void OnPeriodicAdvertisingParametersUpdated(uint8_t advertiser_id, uint8_t status) { do_in_jni_thread( FROM_HERE, - base::Bind( + base::BindOnce( &AdvertisingCallbacks::OnPeriodicAdvertisingParametersUpdated, base::Unretained(advertising_callbacks_), advertiser_id, status)); } @@ -268,18 +303,18 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, void OnPeriodicAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) { do_in_jni_thread( FROM_HERE, - base::Bind(&AdvertisingCallbacks::OnPeriodicAdvertisingDataSet, - base::Unretained(advertising_callbacks_), advertiser_id, - status)); + base::BindOnce(&AdvertisingCallbacks::OnPeriodicAdvertisingDataSet, + base::Unretained(advertising_callbacks_), advertiser_id, + status)); } void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool enable, uint8_t status) { do_in_jni_thread( FROM_HERE, - base::Bind(&AdvertisingCallbacks::OnPeriodicAdvertisingEnabled, - base::Unretained(advertising_callbacks_), advertiser_id, - enable, status)); + base::BindOnce(&AdvertisingCallbacks::OnPeriodicAdvertisingEnabled, + base::Unretained(advertising_callbacks_), advertiser_id, + enable, status)); } void OnOwnAddressRead(uint8_t advertiser_id, uint8_t address_type, @@ -291,12 +326,13 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, return; } do_in_jni_thread(FROM_HERE, - base::Bind(&AdvertisingCallbacks::OnOwnAddressRead, - base::Unretained(advertising_callbacks_), - advertiser_id, address_type, raw_address)); + base::BindOnce(&AdvertisingCallbacks::OnOwnAddressRead, + base::Unretained(advertising_callbacks_), + advertiser_id, address_type, raw_address)); } AdvertisingCallbacks* advertising_callbacks_; + std::map native_adv_callbacks_map_; private: void parse_parameter(bluetooth::hci::AdvertisingConfig& config, @@ -354,7 +390,19 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface, config.include_adi = periodic_params.include_adi; } + uint8_t is_native_advertiser(int reg_id) { + // Return client id if it's native advertiser, otherwise return jni id as + // default + for (auto const& entry : native_adv_callbacks_map_) { + if (native_reg_id_map[entry.first].count(reg_id)) { + return entry.first; + } + } + return kAdvertiserClientIdJni; + } + std::map address_callbacks_; + std::map> native_reg_id_map; }; BleAdvertiserInterfaceImpl* bt_le_advertiser_instance = nullptr; diff --git a/system/main/shim/le_advertising_manager.h b/system/main/shim/le_advertising_manager.h index d53c795caf6f89c52dda307fba93170ceecd8191..ad5093a340fa94653fcb7bb49330d1e1ae04a54f 100644 --- a/system/main/shim/le_advertising_manager.h +++ b/system/main/shim/le_advertising_manager.h @@ -19,7 +19,6 @@ */ #pragma once -#include "ble_advertiser.h" #include "include/hardware/ble_advertiser.h" namespace bluetooth { diff --git a/system/main/shim/le_scanning_manager.cc b/system/main/shim/le_scanning_manager.cc index 24ae7599e6d27258c81b38d23b750518638024d6..6fe1525649e7d02007c5d96e44e7882ab0096cfe 100644 --- a/system/main/shim/le_scanning_manager.cc +++ b/system/main/shim/le_scanning_manager.cc @@ -24,8 +24,6 @@ #include #include -#include - #include "advertise_data_parser.h" #include "btif/include/btif_common.h" #include "hci/address.h" @@ -33,11 +31,11 @@ #include "hci/msft.h" #include "include/hardware/ble_scanner.h" #include "main/shim/ble_scanner_interface_impl.h" -#include "main/shim/dumpsys.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" #include "main/shim/le_scanning_manager.h" #include "main/shim/shim.h" +#include "os/log.h" #include "stack/btm/btm_int_types.h" #include "stack/include/btm_log_history.h" #include "storage/device.h" @@ -192,8 +190,8 @@ void BleScannerInterfaceImpl::Scan(bool start) { } do_in_jni_thread(FROM_HERE, - base::Bind(&BleScannerInterfaceImpl::AddressCache::init, - base::Unretained(&address_cache_))); + base::BindOnce(&BleScannerInterfaceImpl::AddressCache::init, + base::Unretained(&address_cache_))); } /** Setup scan filter params */ @@ -233,7 +231,7 @@ void BleScannerInterfaceImpl::ScanFilterParamSetup( apcf_action, filter_index, advertising_filter_parameter); // TODO refactor callback mechanism do_in_jni_thread(FROM_HERE, - base::Bind(cb, 0, 0, btm_status_value(BTM_SUCCESS))); + base::BindOnce(cb, 0, 0, btm_status_value(BTM_SUCCESS))); } /** Configure a scan filter condition */ @@ -253,7 +251,7 @@ void BleScannerInterfaceImpl::ScanFilterAdd(int filter_index, } bluetooth::shim::GetScanning()->ScanFilterAdd(filter_index, new_filters); do_in_jni_thread(FROM_HERE, - base::Bind(cb, 0, 0, 0, btm_status_value(BTM_SUCCESS))); + base::BindOnce(cb, 0, 0, 0, btm_status_value(BTM_SUCCESS))); } /** Clear all scan filter conditions for specific filter index*/ @@ -270,7 +268,7 @@ void BleScannerInterfaceImpl::ScanFilterEnable(bool enable, EnableCallback cb) { uint8_t action = enable ? 1 : 0; do_in_jni_thread(FROM_HERE, - base::Bind(cb, action, btm_status_value(BTM_SUCCESS))); + base::BindOnce(cb, action, btm_status_value(BTM_SUCCESS))); } /** Is MSFT Extension supported? */ @@ -368,7 +366,8 @@ void BleScannerInterfaceImpl::BatchscanConfigStorage( bluetooth::shim::GetScanning()->BatchScanConifgStorage( batch_scan_full_max, batch_scan_trunc_max, batch_scan_notify_threshold, client_if); - do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); + do_in_jni_thread(FROM_HERE, + base::BindOnce(cb, btm_status_value(BTM_SUCCESS))); } /* Enable batchscan */ @@ -381,14 +380,16 @@ void BleScannerInterfaceImpl::BatchscanEnable(int scan_mode, int scan_interval, static_cast(discard_rule); bluetooth::shim::GetScanning()->BatchScanEnable( batch_scan_mode, scan_window, scan_interval, batch_scan_discard_rule); - do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); + do_in_jni_thread(FROM_HERE, + base::BindOnce(cb, btm_status_value(BTM_SUCCESS))); } /* Disable batchscan */ void BleScannerInterfaceImpl::BatchscanDisable(Callback cb) { LOG(INFO) << __func__ << " in shim layer"; bluetooth::shim::GetScanning()->BatchScanDisable(); - do_in_jni_thread(FROM_HERE, base::Bind(cb, btm_status_value(BTM_SUCCESS))); + do_in_jni_thread(FROM_HERE, + base::BindOnce(cb, btm_status_value(BTM_SUCCESS))); } /* Read out batchscan reports */ @@ -450,8 +451,10 @@ void BleScannerInterfaceImpl::TransferSync(RawAddress address, pa_source, BTM_MODE_UNSUPPORTED, address); return; } - bluetooth::shim::GetScanning()->TransferSync( - ToGdAddress(address), service_data, sync_handle, pa_source); + + bluetooth::shim::GetScanning()->TransferSync(ToGdAddress(address), + p_acl->Handle(), service_data, + sync_handle, pa_source); } void BleScannerInterfaceImpl::TransferSetInfo(RawAddress address, @@ -467,8 +470,10 @@ void BleScannerInterfaceImpl::TransferSetInfo(RawAddress address, pa_source, BTM_MODE_UNSUPPORTED, address); return; } - bluetooth::shim::GetScanning()->TransferSetInfo( - ToGdAddress(address), service_data, adv_handle, pa_source); + + bluetooth::shim::GetScanning()->TransferSetInfo(ToGdAddress(address), + p_acl->Handle(), service_data, + adv_handle, pa_source); } void BleScannerInterfaceImpl::SyncTxParameters(RawAddress addr, uint8_t mode, @@ -489,17 +494,18 @@ void BleScannerInterfaceImpl::OnScannerRegistered( ScanningStatus status) { auto uuid = bluetooth::Uuid::From128BitBE(app_uuid.To128BitBE()); do_in_jni_thread(FROM_HERE, - base::Bind(&ScanningCallbacks::OnScannerRegistered, - base::Unretained(scanning_callbacks_), uuid, - scanner_id, status)); + base::BindOnce(&ScanningCallbacks::OnScannerRegistered, + base::Unretained(scanning_callbacks_), uuid, + scanner_id, status)); } void BleScannerInterfaceImpl::OnSetScannerParameterComplete( bluetooth::hci::ScannerId scanner_id, ScanningStatus status) { do_in_jni_thread( FROM_HERE, - base::Bind(&ScanningCallbacks::OnSetScannerParameterComplete, - base::Unretained(scanning_callbacks_), scanner_id, status)); + base::BindOnce(&ScanningCallbacks::OnSetScannerParameterComplete, + base::Unretained(scanning_callbacks_), scanner_id, + status)); } void BleScannerInterfaceImpl::OnScanResult( @@ -775,21 +781,19 @@ void BleScannerInterfaceImpl::handle_remote_properties( if (!address_cache_.find(bd_addr)) { address_cache_.add(bd_addr); - if (p_eir_remote_name) { - if (remote_name_len > BD_NAME_LEN + 1 || - (remote_name_len == BD_NAME_LEN + 1 && - p_eir_remote_name[BD_NAME_LEN] != '\0')) { - LOG_INFO("%s dropping invalid packet - device name too long: %d", - __func__, remote_name_len); - return; - } - - memcpy(bdname.name, p_eir_remote_name, remote_name_len); - if (remote_name_len < BD_NAME_LEN + 1) - bdname.name[remote_name_len] = '\0'; - btif_dm_update_ble_remote_properties(bd_addr, bdname.name, NULL, - device_type); + if (remote_name_len > BD_NAME_LEN + 1 || + (remote_name_len == BD_NAME_LEN + 1 && + p_eir_remote_name[BD_NAME_LEN] != '\0')) { + LOG_INFO("%s dropping invalid packet - device name too long: %d", + __func__, remote_name_len); + return; } + + memcpy(bdname.name, p_eir_remote_name, remote_name_len); + if (remote_name_len < BD_NAME_LEN + 1) + bdname.name[remote_name_len] = '\0'; + btif_dm_update_ble_remote_properties(bd_addr, bdname.name, NULL, + device_type); } } diff --git a/system/main/shim/metric_id_api.cc b/system/main/shim/metric_id_api.cc index fa912bc328b21ca62f1bf0e2b22e7fc5735e476e..0573e6e1dadeff661e7a33c326d969b679fda4d8 100644 --- a/system/main/shim/metric_id_api.cc +++ b/system/main/shim/metric_id_api.cc @@ -13,14 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#include +#include "main/shim/metric_id_api.h" #include "gd/common/metric_id_manager.h" #include "gd/hci/address.h" #include "main/shim/helpers.h" -#include "main/shim/metric_id_api.h" -#include "main/shim/shim.h" #include "types/raw_address.h" using bluetooth::common::MetricIdManager; diff --git a/system/main/shim/metrics_api.cc b/system/main/shim/metrics_api.cc index 5ef1bd16a4282c9bcef049134fb478085fd584e9..296ecc3f8684eb320c0f50dfbf7521f9fe1eaa54 100644 --- a/system/main/shim/metrics_api.cc +++ b/system/main/shim/metrics_api.cc @@ -69,10 +69,17 @@ void LogMetricA2dpPlaybackEvent(const RawAddress& raw_address, void LogMetricHfpPacketLossStats(const RawAddress& raw_address, int num_decoded_frames, - double packet_loss_ratio) { + double packet_loss_ratio, + uint16_t codec_type) { Address address = bluetooth::ToGdAddress(raw_address); bluetooth::os::LogMetricHfpPacketLossStats(address, num_decoded_frames, - packet_loss_ratio); + packet_loss_ratio, codec_type); +} + +void LogMetricMmcTranscodeRttStats(int maximum_rtt, double mean_rtt, + int num_requests, int codec_type) { + bluetooth::os::LogMetricMmcTranscodeRttStats(maximum_rtt, mean_rtt, + num_requests, codec_type); } void LogMetricReadRssiResult(const RawAddress& raw_address, uint16_t handle, diff --git a/system/main/shim/metrics_api.h b/system/main/shim/metrics_api.h index 2540fbdc12e2efea4c9a56a9dd9516a8a3f7b0b8..04d6e985ce25c90f431292de6c90e2b047eee620 100644 --- a/system/main/shim/metrics_api.h +++ b/system/main/shim/metrics_api.h @@ -20,9 +20,8 @@ #include #include -#include +#include "os/metrics.h" #include "types/raw_address.h" -#include "metrics/metrics_state.h" namespace bluetooth { namespace shim { @@ -93,10 +92,22 @@ void LogMetricA2dpPlaybackEvent(const RawAddress& raw_address, * @param address HFP device associated with this stats * @param num_decoded_frames number of decoded frames * @param packet_loss_ratio ratio of packet loss frames + * @param codec_id codec ID of the packet (mSBC=2, LC3=3) */ void LogMetricHfpPacketLossStats(const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio); + double packet_loss_ratio, uint16_t codec_id); + +/** + * Log Mmc transcode round-trip time statistics + * + * @param maximum_rtt maximum round-trip time in this session + * @param mean_rtt the average of round-trip time in this session + * @param num_requests the number of transcoding requests in the session + * @param codec_type codec type used in this session + */ +void LogMetricMmcTranscodeRttStats(int maximum_rtt, double mean_rtt, + int num_requests, int codec_type); /** * Log read RSSI result diff --git a/system/main/shim/shim.cc b/system/main/shim/shim.cc index e97fc3490b02e7d7db38633b9aa8771dc3a5755c..990fbe5fb4eda8901cf6c6ef3841908a7ac049bc 100644 --- a/system/main/shim/shim.cc +++ b/system/main/shim/shim.cc @@ -17,13 +17,33 @@ #define LOG_TAG "bt_shim" #include "main/shim/shim.h" -#include "main/shim/entry.h" -#include "main/shim/stack.h" #include "gd/common/init_flags.h" #include "gd/os/log.h" +#include "main/shim/entry.h" +#include "main/shim/hci_layer.h" +#include "main/shim/stack.h" +#include "stack/include/main_thread.h" + +static const hci_t* hci; + +void btu_hci_msg_process(BT_HDR* p_msg); + +static void post_to_main_message_loop(const base::Location& from_here, + BT_HDR* p_msg) { + if (do_in_main_thread(from_here, base::Bind(&btu_hci_msg_process, p_msg)) != + BT_STATUS_SUCCESS) { + LOG_ERROR(": do_in_main_thread failed from %s", + from_here.ToString().c_str()); + } +} future_t* ShimModuleStartUp() { + hci = bluetooth::shim::hci_layer_get_interface(); + ASSERT_LOG(hci, "%s could not get hci layer interface.", __func__); + + hci->set_data_cb(base::Bind(&post_to_main_message_loop)); + bluetooth::shim::Stack::GetInstance()->StartEverything(); return kReturnImmediate; } @@ -41,18 +61,6 @@ EXPORT_SYMBOL extern const module_t gd_shim_module = { .clean_up = kUnusedModuleApi, .dependencies = {kUnusedModuleDependencies}}; -bool bluetooth::shim::is_gd_link_policy_enabled() { - return bluetooth::common::init_flags::gd_link_policy_is_enabled(); -} - -bool bluetooth::shim::is_gd_l2cap_enabled() { - return bluetooth::common::init_flags::gd_l2cap_is_enabled(); -} - -bool bluetooth::shim::is_gd_shim_enabled() { - return bluetooth::common::init_flags::gd_core_is_enabled(); -} - bool bluetooth::shim::is_gd_stack_started_up() { return bluetooth::shim::Stack::GetInstance()->IsRunning(); } @@ -61,10 +69,6 @@ bool bluetooth::shim::is_gd_dumpsys_module_started() { return bluetooth::shim::Stack::GetInstance()->IsDumpsysModuleStarted(); } -bool bluetooth::shim::is_gd_btaa_enabled() { - return bluetooth::common::init_flags::btaa_hci_is_enabled(); -} - bool bluetooth::shim::is_classic_discovery_only_enabled() { return bluetooth::common::init_flags::classic_discovery_only_is_enabled(); } diff --git a/system/main/shim/shim.h b/system/main/shim/shim.h index fb2c6269bc20c47c984e89299ec79532095ae45a..8fa166b603f53159b75668ef10a75fbeabcee1f8 100644 --- a/system/main/shim/shim.h +++ b/system/main/shim/shim.h @@ -20,7 +20,6 @@ * Gabeldorsche related legacy-only-stack-side expansion and support code. */ #include "btcore/include/module.h" -#include "main/shim/entry.h" #include "osi/include/future.h" static const char GD_SHIM_MODULE[] = "gd_shim_module"; @@ -32,23 +31,6 @@ constexpr char* kUnusedModuleDependencies = nullptr; namespace bluetooth { namespace shim { -/** - * Checks if the bluetooth stack is running in legacy or gd mode. - * - * This check is used throughout the legacy stack to determine which - * methods, classes or functions to invoke. The default (false) mode - * is the legacy mode which runs the original legacy bluetooth stack. - * When enabled (true) the core portion of the gd stack is invoked - * at key points to execute equivalent functionality using the - * gd core components. - * - * @return true if using gd shim core, false if using legacy. - */ -bool is_gd_link_policy_enabled(); -bool is_gd_l2cap_enabled(); -bool is_gd_shim_enabled(); -bool is_gd_btaa_enabled(); - /** * Checks if the bluetooth gd stack has been started up. * diff --git a/system/main/shim/stack.cc b/system/main/shim/stack.cc index 020b20935da90aaab28a33b9ce98049317033eb1..bffeb27915d1bceee4868e490c4a64f964f0f5b9 100644 --- a/system/main/shim/stack.cc +++ b/system/main/shim/stack.cc @@ -25,8 +25,6 @@ #include #include "device/include/controller.h" -#include "gd/att/att_module.h" -#include "gd/btaa/activity_attribution.h" #include "gd/common/init_flags.h" #include "gd/common/strings.h" #include "gd/hal/hci_hal.h" @@ -40,29 +38,16 @@ #include "gd/hci/msft.h" #include "gd/hci/remote_name_request.h" #include "gd/hci/vendor_specific_event_manager.h" -#include "gd/l2cap/classic/l2cap_classic_module.h" -#include "gd/l2cap/le/l2cap_le_module.h" #include "gd/metrics/counter_metrics.h" -#include "gd/neighbor/connectability.h" -#include "gd/neighbor/discoverability.h" -#include "gd/neighbor/inquiry.h" -#include "gd/neighbor/name_db.h" -#include "gd/neighbor/page.h" -#include "gd/neighbor/scan.h" #include "gd/os/log.h" -#include "gd/security/security_module.h" #include "gd/shim/dumpsys.h" #include "gd/storage/storage_module.h" #include "gd/sysprops/sysprops_module.h" #include "main/shim/acl_legacy_interface.h" -#include "main/shim/activity_attribution.h" #include "main/shim/distance_measurement_manager.h" #include "main/shim/hci_layer.h" -#include "main/shim/helpers.h" -#include "main/shim/l2c_api.h" #include "main/shim/le_advertising_manager.h" #include "main/shim/le_scanning_manager.h" -#include "main/shim/shim.h" namespace bluetooth { namespace shim { @@ -92,67 +77,29 @@ void Stack::StartEverything() { modules.add(); modules.add(); modules.add(); - if (common::init_flags::gd_remote_name_request_is_enabled()) { - modules.add(); - } - if (common::init_flags::gd_l2cap_is_enabled()) { - modules.add(); - modules.add(); - modules.add(); - } + modules.add(); modules.add(); modules.add(); modules.add(); modules.add(); - if (common::init_flags::btaa_hci_is_enabled()) { - modules.add(); - } - if (common::init_flags::gd_core_is_enabled()) { - modules.add(); - modules.add(); - modules.add(); - modules.add(); - modules.add(); - modules.add(); - modules.add(); - modules.add(); - } Start(&modules); is_running_ = true; // Make sure the leaf modules are started ASSERT(stack_manager_.GetInstance() != nullptr); ASSERT(stack_manager_.GetInstance() != nullptr); - if (common::init_flags::gd_core_is_enabled()) { - btm_ = new Btm(stack_handler_, - stack_manager_.GetInstance()); - } - if (!common::init_flags::gd_core_is_enabled()) { - if (stack_manager_.IsStarted()) { - acl_ = new legacy::Acl( - stack_handler_, legacy::GetAclInterface(), - controller_get_interface()->get_ble_acceptlist_size(), - controller_get_interface()->get_ble_resolving_list_max_size()); - } else { - LOG_ERROR( - "Unable to create shim ACL layer as Controller has not started"); - } - } - - if (!common::init_flags::gd_core_is_enabled()) { - bluetooth::shim::hci_on_reset_complete(); + if (stack_manager_.IsStarted()) { + acl_ = new legacy::Acl( + stack_handler_, legacy::GetAclInterface(), + controller_get_interface()->get_ble_acceptlist_size(), + controller_get_interface()->get_ble_resolving_list_max_size()); + } else { + LOG_ERROR("Unable to create shim ACL layer as Controller has not started"); } + bluetooth::shim::hci_on_reset_complete(); bluetooth::shim::init_advertising_manager(); bluetooth::shim::init_scanning_manager(); bluetooth::shim::init_distance_measurement_manager(); - - if (common::init_flags::gd_l2cap_is_enabled() && - !common::init_flags::gd_core_is_enabled()) { - L2CA_UseLegacySecurityModule(); - } - if (common::init_flags::btaa_hci_is_enabled()) { - bluetooth::shim::init_activity_attribution(); - } } void Stack::Start(ModuleList* modules) { @@ -170,9 +117,7 @@ void Stack::Start(ModuleList* modules) { void Stack::Stop() { std::lock_guard lock(mutex_); - if (!common::init_flags::gd_core_is_enabled()) { - bluetooth::shim::hci_on_shutting_down(); - } + bluetooth::shim::hci_on_shutting_down(); // Make sure gd acl flag is enabled and we started it up if (acl_ != nullptr) { diff --git a/system/main/shim/stack.h b/system/main/shim/stack.h index e2e1dbe655a1d3476e8ba5fa3f826738519f148e..8b04d84c6ef31cabb078fcf82938521ef8f929b4 100644 --- a/system/main/shim/stack.h +++ b/system/main/shim/stack.h @@ -22,7 +22,6 @@ #include "gd/module.h" #include "gd/os/handler.h" #include "gd/os/thread.h" -#include "gd/os/utils.h" #include "gd/stack_manager.h" #include "main/shim/acl.h" #include "main/shim/btm.h" diff --git a/system/main/stack_config.cc b/system/main/stack_config.cc index 63d35d436ff75aa100c00c7327690fd9b67d074f..8c69d1348c7379364b5f6905bca9596c5943e9b1 100644 --- a/system/main/stack_config.cc +++ b/system/main/stack_config.cc @@ -18,7 +18,7 @@ #define LOG_TAG "bt_stack_config" -#include "stack_config.h" +#include "internal_include/stack_config.h" #include @@ -26,7 +26,6 @@ #include "osi/include/log.h" namespace { -const char* TRACE_CONFIG_ENABLED_KEY = "TraceConf"; const char* PTS_AVRCP_TEST = "PTS_AvrcpTest"; const char* PTS_SECURE_ONLY_MODE = "PTS_SecurePairOnly"; const char* PTS_LE_CONN_UPDATED_DISABLED = "PTS_DisableConnUpdates"; @@ -94,11 +93,6 @@ EXPORT_SYMBOL extern const module_t stack_config_module = { .dependencies = {NULL}}; // Interface functions -static bool get_trace_config_enabled(void) { - return config_get_bool(*config, CONFIG_DEFAULT_SECTION, - TRACE_CONFIG_ENABLED_KEY, false); -} - static bool get_pts_avrcp_test(void) { return config_get_bool(*config, CONFIG_DEFAULT_SECTION, PTS_AVRCP_TEST, false); @@ -211,7 +205,6 @@ static bool get_pts_le_audio_disable_ases_before_stopping(void) { static config_t* get_all(void) { return config.get(); } const stack_config_t interface = { - get_trace_config_enabled, get_pts_avrcp_test, get_pts_secure_only_mode, get_pts_conn_updates_disabled, diff --git a/system/main/test/main_shim_test.cc b/system/main/test/main_shim_test.cc index fcaf32b4c50d3506f8531a07a28a22989c501a82..a0bcbc3a150be055a39e9a24af4ef2d946aafbaf 100644 --- a/system/main/test/main_shim_test.cc +++ b/system/main/test/main_shim_test.cc @@ -20,12 +20,13 @@ #include #include +#include #include #include #include #include +#include -#include "btaa/activity_attribution.h" #include "btif/include/btif_hh.h" #include "device/include/controller.h" #include "hal/hci_hal.h" @@ -44,12 +45,13 @@ #include "hci/le_advertising_manager_mock.h" #include "hci/le_scanning_manager_mock.h" #include "include/hardware/ble_scanner.h" -#include "include/hardware/bt_activity_attribution.h" #include "main/shim/acl.h" #include "main/shim/acl_legacy_interface.h" #include "main/shim/ble_scanner_interface_impl.h" +#include "main/shim/dumpsys.h" #include "main/shim/helpers.h" #include "main/shim/le_advertising_manager.h" +#include "main/shim/utils.h" #include "main/shim/le_scanning_manager.h" #include "os/handler.h" #include "os/mock_queue.h" @@ -57,9 +59,11 @@ #include "os/thread.h" #include "packet/packet_view.h" #include "stack/btm/btm_int_types.h" +#include "stack/btm/btm_sec_cb.h" #include "stack/include/acl_hci_link_interface.h" #include "stack/include/ble_acl_interface.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" #include "stack/include/hci_error_code.h" #include "stack/include/sco_hci_link_interface.h" #include "stack/include/sec_hci_link_interface.h" @@ -85,6 +89,7 @@ const uint8_t kMaxAddressResolutionSize = kMaxLeAcceptlistSize; tL2C_CB l2cb; tBTM_CB btm_cb; +tBTM_SEC_CB btm_sec_cb; btif_hh_cb_t btif_hh_cb; struct bluetooth::hci::LeScanningManager::impl @@ -345,23 +350,12 @@ class MockLeAclConnection namespace bluetooth { namespace shim { -void init_activity_attribution() {} - namespace testing { extern os::Handler* mock_handler_; } // namespace testing } // namespace shim -namespace activity_attribution { -ActivityAttributionInterface* get_activity_attribution_instance() { - return nullptr; -} - -const ModuleFactory ActivityAttribution::Factory = - ModuleFactory([]() { return nullptr; }); -} // namespace activity_attribution - namespace hal { const ModuleFactory HciHal::Factory = ModuleFactory([]() { return nullptr; }); } // namespace hal @@ -806,3 +800,15 @@ TEST_F(MainShimTest, DumpsysNeighbor) { DumpsysNeighbor(STDOUT_FILENO); } + +// test for b/277590580 + +using bluetooth::hci::GapData; +TEST(MainShimRegressionTest, OOB_In_StartAdvertisingSet) { + std::vector raw_data = {10, 0, 0, 0, 0}; + std::vector res; + + bluetooth::shim::parse_gap_data(raw_data, res); + + ASSERT_EQ(res.size(), (size_t) 0); +} diff --git a/system/mockcify_util.pl b/system/mockcify_util.pl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/system/osi/Android.bp b/system/osi/Android.bp index ab19f5c65a05b9add1f884bbbd0d24028b71f2d5..01ff6c3bb6f889bb4d2b75962d7e0fd65637d524 100644 --- a/system/osi/Android.bp +++ b/system/osi/Android.bp @@ -19,31 +19,6 @@ cc_defaults { ], } -// Static libraries required by other modules -cc_test_library { - name: "libosi-AllocationTestHarness", - defaults: ["fluoride_osi_defaults"], - srcs: [ - "test/AllocationTestHarness.cc", - ], - host_supported: true, - shared: { - enabled: false, - }, -} - -cc_test_library { - name: "libosi-AlarmTestHarness", - defaults: ["fluoride_osi_defaults"], - srcs: [ - "test/AlarmTestHarness.cc", - ], - host_supported: true, - shared: { - enabled: false, - }, -} - filegroup { name: "OsiCompatSources", srcs: [ @@ -65,18 +40,18 @@ cc_library_static { "include_internal", ], defaults: [ - "fluoride_basic_defaults", + "fluoride_defaults", "fluoride_osi_defaults", ], + whole_static_libs: [ + "bluetooth_flags_c_lib", + ], // TODO(mcchou): Remove socket_utils sources after platform specific // dependencies are abstracted. srcs: [ ":OsiCompatSources", "src/alarm.cc", - "src/allocation_tracker.cc", "src/allocator.cc", - "src/array.cc", - "src/buffer.cc", "src/config.cc", "src/fixed_queue.cc", "src/future.cc", @@ -90,6 +65,7 @@ cc_library_static { "src/socket.cc", "src/socket_utils/socket_local_client.cc", "src/socket_utils/socket_local_server.cc", + "src/stack_power_telemetry.cc", "src/thread.cc", "src/thread_scheduler.cc", "src/wakelock.cc", @@ -115,25 +91,25 @@ cc_library_static { apex_available: [ "com.android.btservices", ], + header_libs: ["libbluetooth_headers"], + static_libs: [ + "libbt-platform-protos-lite", + "libbt_shim_bridge", + ], } // libosi unit tests for target and host cc_test { name: "net_test_osi", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_osi_defaults", "mts_defaults", ], host_supported: true, srcs: [ - "test/AlarmTestHarness.cc", - "test/AllocationTestHarness.cc", "test/alarm_test.cc", - "test/allocation_tracker_test.cc", "test/allocator_test.cc", - "test/array_test.cc", "test/config_test.cc", "test/fixed_queue_test.cc", "test/future_test.cc", @@ -143,6 +119,7 @@ cc_test { "test/rand_test.cc", "test/reactor_test.cc", "test/ringbuffer_test.cc", + "test/stack_power_telemetry_test.cc", "test/thread_test.cc", "test/wakelock_test.cc", // test internal sources only used inside the libosi @@ -153,25 +130,41 @@ cc_test { "libcrypto", "libcutils", "liblog", + "server_configurable_flags", ], local_include_dirs: [ "include_internal", "test", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libc++fs", "libchrome", "libevent", "libgmock", "libosi", "libprotobuf-cpp-lite", + "libstatslog_bt", ], + target: { + android: { + shared_libs: [ + "libstatssocket", + ], + }, + }, cflags: [ "-DLIB_OSI_INTERNAL", + "-Wno-unused-parameter", ], sanitize: { + address: true, cfi: false, }, + header_libs: ["libbluetooth_headers"], } diff --git a/system/osi/BUILD.gn b/system/osi/BUILD.gn index 7574ce4753f686e21b8d8704a25c883d255825fd..730c1edca253119f1b56d52660591adaeb3dd880 100644 --- a/system/osi/BUILD.gn +++ b/system/osi/BUILD.gn @@ -17,10 +17,7 @@ static_library("osi") { sources = [ "src/alarm.cc", - "src/allocation_tracker.cc", "src/allocator.cc", - "src/array.cc", - "src/buffer.cc", "src/compat.cc", "src/config.cc", "src/fixed_queue.cc", @@ -38,6 +35,7 @@ static_library("osi") { # dependencies are abstracted. "src/socket_utils/socket_local_client.cc", "src/socket_utils/socket_local_server.cc", + "src/stack_power_telemetry.cc", "src/thread.cc", "src/wakelock.cc", @@ -70,12 +68,8 @@ static_library("osi") { if (use.test) { executable("net_test_osi") { sources = [ - "test/AlarmTestHarness.cc", - "test/AllocationTestHarness.cc", "test/alarm_test.cc", - "test/allocation_tracker_test.cc", "test/allocator_test.cc", - "test/array_test.cc", "test/config_test.cc", "test/future_test.cc", "test/hash_map_utils_test.cc", diff --git a/system/osi/include/allocation_tracker.h b/system/osi/include/allocation_tracker.h deleted file mode 100644 index a0196939a75ea443573ba6783806e9db679073bc..0000000000000000000000000000000000000000 --- a/system/osi/include/allocation_tracker.h +++ /dev/null @@ -1,59 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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 -#include -#include - -typedef struct allocation_tracker_t allocation_tracker_t; -typedef uint8_t allocator_id_t; - -// Initialize the allocation tracker. If you do not call this function, -// the allocation tracker functions do nothing but are still safe to call. -void allocation_tracker_init(void); - -// Reset the allocation tracker. Don't call this in the normal course of -// operations. Useful mostly for testing. -void allocation_tracker_reset(void); - -// Expects that there are no allocations at the time of this call. Dumps -// information about unfreed allocations to the log. Returns the amount of -// unallocated memory. -size_t allocation_tracker_expect_no_allocations(void); - -// Notify the tracker of a new allocation belonging to |allocator_id|. -// If |ptr| is NULL, this function does nothing. |requested_size| is the -// size of the allocation without any canaries. The caller must allocate -// enough memory for canaries; the total allocation size can be determined -// by calling |allocation_tracker_resize_for_canary|. Returns |ptr| offset -// to the the beginning of the uncanaried region. -void* allocation_tracker_notify_alloc(allocator_id_t allocator_id, void* ptr, - size_t requested_size); - -// Notify the tracker of an allocation that is being freed. |ptr| must be a -// pointer returned by a call to |allocation_tracker_notify_alloc| with the -// same |allocator_id|. If |ptr| is NULL, this function does nothing. Returns -// |ptr| offset to the real beginning of the allocation including any canary -// space. -void* allocation_tracker_notify_free(allocator_id_t allocator_id, void* ptr); - -// Get the full size for an allocation, taking into account the size of -// canaries. -size_t allocation_tracker_resize_for_canary(size_t size); diff --git a/system/osi/include/allocator.h b/system/osi/include/allocator.h index ea7e5ee442e4052792cfa7500c4c66811ecf046b..f4cfc3937008903c9386dc5675dcf639a0335e2b 100644 --- a/system/osi/include/allocator.h +++ b/system/osi/include/allocator.h @@ -47,11 +47,6 @@ void osi_free(void* ptr); // |p_ptr| cannot be NULL. void osi_free_and_reset(void** p_ptr); -// Dump allocation-related statistics and debug info to the |fd| file -// descriptor. -// The information is in user-readable text format. The |fd| must be valid. -void osi_allocator_debug_dump(int fd); - class OsiObject { public: OsiObject(void* ptr); diff --git a/system/osi/include/array.h b/system/osi/include/array.h deleted file mode 100644 index 4b496818cf2d995a6ceb7c3dbc3962cb4722ec53..0000000000000000000000000000000000000000 --- a/system/osi/include/array.h +++ /dev/null @@ -1,58 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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 -#include -#include - -typedef struct array_t array_t; - -// Returns a new array object that stores elements of size |element_size|. The -// returned object must be freed with |array_free|. |element_size| must be -// greater than 0. Returns NULL on failure. -array_t* array_new(size_t element_size); - -// Frees an array that was allocated with |array_new|. |array| may be NULL. -void array_free(array_t* array); - -// Returns a pointer to the first stored element in |array|. |array| must not be -// NULL. -void* array_ptr(const array_t* array); - -// Returns a pointer to the |index|th element of |array|. |index| must be less -// than the array's length. |array| must not be NULL. -void* array_at(const array_t* array, size_t index); - -// Returns the number of elements stored in |array|. |array| must not be NULL. -size_t array_length(const array_t* array); - -// Inserts an element to the end of |array| by value. For example, a caller -// may simply call array_append_value(array, 5) instead of storing 5 into a -// variable and then inserting by pointer. Although |value| is a uint32_t, -// only the lowest |element_size| bytes will be stored. |array| must not be -// NULL. Returns true if the element could be inserted into the array, false -// on error. -bool array_append_value(array_t* array, uint32_t value); - -// Inserts an element to the end of |array|. The value pointed to by |data| must -// be at least |element_size| bytes long and will be copied into the array. -// Neither |array| nor |data| may be NULL. Returns true if the element could be -// inserted into the array, false on error. -bool array_append_ptr(array_t* array, void* data); diff --git a/system/osi/include/buffer.h b/system/osi/include/buffer.h deleted file mode 100644 index a7b3b57f76734de7ef1ae3d16677ca8529123bf9..0000000000000000000000000000000000000000 --- a/system/osi/include/buffer.h +++ /dev/null @@ -1,56 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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 -#include - -typedef struct buffer_t buffer_t; - -// Returns a new buffer of |size| bytes. Returns NULL if a buffer could not be -// allocated. |size| must be non-zero. The caller must release this buffer with -// |buffer_free|. -buffer_t* buffer_new(size_t size); - -// Creates a new reference to the buffer |buf|. A reference is indistinguishable -// from the original: writes to the original will be reflected in the reference -// and vice versa. In other words, this function creates an alias to |buf|. The -// caller must release the returned buffer with |buffer_free|. Note that -// releasing the returned buffer does not release |buf|. |buf| must not be NULL. -buffer_t* buffer_new_ref(const buffer_t* buf); - -// Creates a new reference to the last |slice_size| bytes of |buf|. See -// |buffer_new_ref| for a description of references. |slice_size| must be -// greater than 0 and may be at most |buffer_length| -// (0 < slice_size <= buffer_length). |buf| must not be NULL. -buffer_t* buffer_new_slice(const buffer_t* buf, size_t slice_size); - -// Frees a buffer object. |buf| may be NULL. -void buffer_free(buffer_t* buf); - -// Returns a pointer to a writeable memory region for |buf|. All references -// and slices that share overlapping bytes will also be written to when -// writing to the returned pointer. The caller may safely write up to -// |buffer_length| consecutive bytes starting at the address returned by -// this function. |buf| must not be NULL. -void* buffer_ptr(const buffer_t* buf); - -// Returns the length of the writeable memory region referred to by |buf|. -// |buf| must not be NULL. -size_t buffer_length(const buffer_t* buf); diff --git a/system/osi/include/socket_utils/sockets.h b/system/osi/include/socket_utils/sockets.h index 22f598c06f59d4c7dc30b2f4bdae27607bdbc83d..9597c2a1ee79f41f4adfc27aa811454b538694e7 100644 --- a/system/osi/include/socket_utils/sockets.h +++ b/system/osi/include/socket_utils/sockets.h @@ -16,13 +16,14 @@ #pragma once -#include #include #include #include #include #include +#include + #define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_" #define ANDROID_SOCKET_DIR "/dev/socket" diff --git a/system/osi/include/stack_power_telemetry.h b/system/osi/include/stack_power_telemetry.h new file mode 100644 index 0000000000000000000000000000000000000000..2936797c26f128196904317f86b41f02543e4bfe --- /dev/null +++ b/system/osi/include/stack_power_telemetry.h @@ -0,0 +1,73 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +#include "types/raw_address.h" + +namespace power_telemetry { + +struct PowerTelemetryImpl; + +class PowerTelemetry { + public: + PowerTelemetry(); + + void RecordLogDataContainer(); + void LogScanStarted(); + + void LogHciCmdDetail(); + void LogHciEvtDetail(); + + void LogLinkDetails(uint16_t handle, const RawAddress& bdaddr, + bool isConnected, bool is_acl_link); + void LogRxAclPktData(uint16_t len); + void LogTxAclPktData(uint16_t len); + + void LogChannelConnected(uint16_t psm, int32_t src_id, int32_t dst_id, + const RawAddress& bd_addr); + void LogChannelDisconnected(uint16_t psm, int32_t src_id, int32_t dst_id, + const RawAddress& bd_addr); + void LogRxBytes(uint16_t psm, int32_t src_id, int32_t dst_id, + const RawAddress& bd_addr, int32_t num_bytes); + void LogTxBytes(uint16_t psm, int32_t src_id, int32_t dst_id, + const RawAddress& bd_addr, int32_t num_bytes); + + void LogSniffStarted(uint16_t handle, const RawAddress& bdaddr); + void LogSniffStopped(uint16_t handle, const RawAddress& bdaddr); + void LogAclTxPowerLevel(uint16_t handle, uint8_t txPower); + void LogInqScanStarted(); + void LogInqScanStopped(); + void LogBleScan(uint16_t num_resps); + void LogBleAdvStarted(); + void LogBleAdvStopped(); + + void LogTxPower(void* res); + void LogTrafficData(); + + void Dumpsys(int32_t fd); + + std::unique_ptr pimpl_; +}; + +PowerTelemetry& GetInstance(); + +} // namespace power_telemetry diff --git a/system/osi/src/alarm.cc b/system/osi/src/alarm.cc index 2f0a27ea71c1fde6e9d638e3064f08874250b7f5..408f4f3bee46eb4a20ee3a69edd4261da11829ce 100644 --- a/system/osi/src/alarm.cc +++ b/system/osi/src/alarm.cc @@ -16,37 +16,32 @@ * ******************************************************************************/ -#include "internal_include/bt_target.h" - #define LOG_TAG "bt_osi_alarm" #include "osi/include/alarm.h" #include #include -#include #include -#include +#include #include #include #include #include #include -#include - #include #include "check.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/fixed_queue.h" #include "osi/include/list.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "osi/include/thread.h" #include "osi/include/wakelock.h" #include "osi/semaphore.h" -#include "stack/include/btu.h" +#include "stack/include/main_thread.h" using base::Bind; using base::CancelableClosure; diff --git a/system/osi/src/allocation_tracker.cc b/system/osi/src/allocation_tracker.cc deleted file mode 100644 index 3ec710c902e6bc491792c041bfa39b50d5591a1e..0000000000000000000000000000000000000000 --- a/system/osi/src/allocation_tracker.cc +++ /dev/null @@ -1,187 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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. - * - ******************************************************************************/ - -#define LOG_TAG "bt_osi_allocation_tracker" - -#include "osi/include/allocation_tracker.h" - -#include -#include -#include -#include -#include - -#include "check.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" - -typedef struct { - uint8_t allocator_id; - void* ptr; - size_t size; - bool freed; -} allocation_t; - -static const size_t canary_size = 8; -static char canary[canary_size]; -static std::unordered_map allocations; -static std::mutex tracker_lock; -static bool enabled = false; - -// Memory allocation statistics -static size_t alloc_counter = 0; -static size_t free_counter = 0; -static size_t alloc_total_size = 0; -static size_t free_total_size = 0; - -void allocation_tracker_init(void) { - std::unique_lock lock(tracker_lock); - if (enabled) return; - - // randomize the canary contents - for (size_t i = 0; i < canary_size; i++) canary[i] = (char)osi_rand(); - - LOG_INFO("canary initialized"); - - enabled = true; -} - -// Test function only. Do not call in the normal course of operations. -void allocation_tracker_uninit(void) { - std::unique_lock lock(tracker_lock); - if (!enabled) return; - - allocations.clear(); - enabled = false; -} - -void allocation_tracker_reset(void) { - std::unique_lock lock(tracker_lock); - if (!enabled) return; - - allocations.clear(); -} - -size_t allocation_tracker_expect_no_allocations(void) { - std::unique_lock lock(tracker_lock); - if (!enabled) return 0; - - size_t unfreed_memory_size = 0; - - for (const auto& entry : allocations) { - allocation_t* allocation = entry.second; - if (!allocation->freed) { - unfreed_memory_size += - allocation->size; // Report back the unfreed byte count - LOG_ERROR("%s found unfreed allocation. address: 0x%zx size: %zd bytes", - __func__, (uintptr_t)allocation->ptr, allocation->size); - } - } - - return unfreed_memory_size; -} - -void* allocation_tracker_notify_alloc(uint8_t allocator_id, void* ptr, - size_t requested_size) { - char* return_ptr; - { - std::unique_lock lock(tracker_lock); - if (!enabled || !ptr) return ptr; - - // Keep statistics - alloc_counter++; - alloc_total_size += allocation_tracker_resize_for_canary(requested_size); - - return_ptr = ((char*)ptr) + canary_size; - - auto map_entry = allocations.find(return_ptr); - allocation_t* allocation; - if (map_entry != allocations.end()) { - allocation = map_entry->second; - CHECK(allocation->freed); // Must have been freed before - } else { - allocation = (allocation_t*)calloc(1, sizeof(allocation_t)); - allocations[return_ptr] = allocation; - } - - allocation->allocator_id = allocator_id; - allocation->freed = false; - allocation->size = requested_size; - allocation->ptr = return_ptr; - } - - // Add the canary on both sides - memcpy(return_ptr - canary_size, canary, canary_size); - memcpy(return_ptr + requested_size, canary, canary_size); - - return return_ptr; -} - -void* allocation_tracker_notify_free(UNUSED_ATTR uint8_t allocator_id, - void* ptr) { - std::unique_lock lock(tracker_lock); - - if (!enabled || !ptr) return ptr; - - auto map_entry = allocations.find(ptr); - CHECK(map_entry != allocations.end()); - allocation_t* allocation = map_entry->second; - CHECK(allocation); // Must have been tracked before - CHECK(!allocation->freed); // Must not be a double free - CHECK(allocation->allocator_id == - allocator_id); // Must be from the same allocator - - // Keep statistics - free_counter++; - free_total_size += allocation_tracker_resize_for_canary(allocation->size); - - allocation->freed = true; - - UNUSED_ATTR const char* beginning_canary = ((char*)ptr) - canary_size; - UNUSED_ATTR const char* end_canary = ((char*)ptr) + allocation->size; - - for (size_t i = 0; i < canary_size; i++) { - CHECK(beginning_canary[i] == canary[i]); - CHECK(end_canary[i] == canary[i]); - } - - // Free the hash map entry to avoid unlimited memory usage growth. - // Double-free of memory is detected with "assert(allocation)" above - // as the allocation entry will not be present. - allocations.erase(ptr); - free(allocation); - - return ((char*)ptr) - canary_size; -} - -size_t allocation_tracker_resize_for_canary(size_t size) { - return (!enabled) ? size : size + (2 * canary_size); -} - -void osi_allocator_debug_dump(int fd) { - dprintf(fd, "\nBluetooth Memory Allocation Statistics:\n"); - - std::unique_lock lock(tracker_lock); - - dprintf(fd, " Total allocated/free/used counts : %zu / %zu / %zu\n", - alloc_counter, free_counter, alloc_counter - free_counter); - dprintf(fd, " Total allocated/free/used octets : %zu / %zu / %zu\n", - alloc_total_size, free_total_size, - alloc_total_size - free_total_size); -} diff --git a/system/osi/src/allocator.cc b/system/osi/src/allocator.cc index 20c843b9505cdd874cea04e7c023b362b215883f..564e2f1560cf6c89d3510ea7f7d9e3ff5ba2b3fa 100644 --- a/system/osi/src/allocator.cc +++ b/system/osi/src/allocator.cc @@ -15,24 +15,19 @@ * limitations under the License. * ******************************************************************************/ +#include "osi/include/allocator.h" + #include #include #include #include "check.h" -#include "osi/include/allocation_tracker.h" -#include "osi/include/allocator.h" - -static const allocator_id_t alloc_allocator_id = 42; char* osi_strdup(const char* str) { size_t size = strlen(str) + 1; // + 1 for the null terminator - size_t real_size = allocation_tracker_resize_for_canary(size); - void* ptr = malloc(real_size); - CHECK(ptr); + char* new_string = (char*)malloc(size); + CHECK(new_string); - char* new_string = static_cast( - allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size)); if (!new_string) return NULL; memcpy(new_string, str, size); @@ -43,12 +38,9 @@ char* osi_strndup(const char* str, size_t len) { size_t size = strlen(str); if (len < size) size = len; - size_t real_size = allocation_tracker_resize_for_canary(size + 1); - void* ptr = malloc(real_size); - CHECK(ptr); + char* new_string = (char*)malloc(size + 1); + CHECK(new_string); - char* new_string = static_cast( - allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size + 1)); if (!new_string) return NULL; memcpy(new_string, str, size); @@ -58,23 +50,19 @@ char* osi_strndup(const char* str, size_t len) { void* osi_malloc(size_t size) { CHECK(static_cast(size) >= 0); - size_t real_size = allocation_tracker_resize_for_canary(size); - void* ptr = malloc(real_size); + void* ptr = malloc(size); CHECK(ptr); - return allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size); + return ptr; } void* osi_calloc(size_t size) { CHECK(static_cast(size) >= 0); - size_t real_size = allocation_tracker_resize_for_canary(size); - void* ptr = calloc(1, real_size); + void* ptr = calloc(1, size); CHECK(ptr); - return allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size); + return ptr; } -void osi_free(void* ptr) { - free(allocation_tracker_notify_free(alloc_allocator_id, ptr)); -} +void osi_free(void* ptr) { free(ptr); } void osi_free_and_reset(void** p_ptr) { CHECK(p_ptr != NULL); diff --git a/system/osi/src/array.cc b/system/osi/src/array.cc deleted file mode 100644 index 69b8b7ccc27ec9d917db536b92736e55939af943..0000000000000000000000000000000000000000 --- a/system/osi/src/array.cc +++ /dev/null @@ -1,112 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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. - * - ******************************************************************************/ - -#define LOG_TAG "bt_osi_array" - -#include "osi/include/array.h" - -#include -#include -#include - -#include "check.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" - -struct array_t { - size_t element_size; - size_t length; - size_t capacity; - uint8_t* data; - uint8_t internal_storage[]; -}; - -static bool grow(array_t* array); - -static const size_t INTERNAL_ELEMENTS = 16; - -array_t* array_new(size_t element_size) { - CHECK(element_size > 0); - - array_t* array = static_cast( - osi_calloc(sizeof(array_t) + element_size * INTERNAL_ELEMENTS)); - - array->element_size = element_size; - array->capacity = INTERNAL_ELEMENTS; - array->data = array->internal_storage; - return array; -} - -void array_free(array_t* array) { - if (!array) return; - - if (array->data != array->internal_storage) free(array->data); - - osi_free(array); -} - -void* array_ptr(const array_t* array) { return array_at(array, 0); } - -void* array_at(const array_t* array, size_t index) { - CHECK(array != NULL); - CHECK(index < array->length); - return array->data + (index * array->element_size); -} - -size_t array_length(const array_t* array) { - CHECK(array != NULL); - return array->length; -} - -bool array_append_value(array_t* array, uint32_t value) { - return array_append_ptr(array, &value); -} - -bool array_append_ptr(array_t* array, void* data) { - CHECK(array != NULL); - CHECK(data != NULL); - - if (array->length == array->capacity && !grow(array)) { - LOG_ERROR( - "%s unable to grow array past current capacity of %zu elements " - "of size %zu.", - __func__, array->capacity, array->element_size); - return false; - } - - ++array->length; - memcpy(array_at(array, array->length - 1), data, array->element_size); - return true; -} - -static bool grow(array_t* array) { - const size_t new_capacity = array->capacity + (array->capacity / 2); - const bool is_moving = (array->data == array->internal_storage); - - void* new_data = realloc(is_moving ? NULL : array->data, - new_capacity * array->element_size); - if (!new_data) return false; - - if (is_moving) - memcpy(new_data, array->internal_storage, - array->length * array->element_size); - - array->data = static_cast(new_data); - array->capacity = new_capacity; - return true; -} diff --git a/system/osi/src/buffer.cc b/system/osi/src/buffer.cc deleted file mode 100644 index da6ebfac13756ef89941ef4eb5fb47686e7e59d4..0000000000000000000000000000000000000000 --- a/system/osi/src/buffer.cc +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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. - * - ******************************************************************************/ - -#define LOG_TAG "bt_osi_buffer" - -#include "osi/include/buffer.h" - -#include -#include - -#include "check.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" - -struct buffer_t { - buffer_t* root; - size_t refcount; - size_t length; - uint8_t data[]; -}; - -buffer_t* buffer_new(size_t size) { - CHECK(size > 0); - - buffer_t* buffer = - static_cast(osi_calloc(sizeof(buffer_t) + size)); - - buffer->root = buffer; - buffer->refcount = 1; - buffer->length = size; - - return buffer; -} - -buffer_t* buffer_new_ref(const buffer_t* buf) { - CHECK(buf != NULL); - return buffer_new_slice(buf, buf->length); -} - -buffer_t* buffer_new_slice(const buffer_t* buf, size_t slice_size) { - CHECK(buf != NULL); - CHECK(slice_size > 0); - CHECK(slice_size <= buf->length); - - buffer_t* ret = static_cast(osi_calloc(sizeof(buffer_t))); - - ret->root = buf->root; - ret->refcount = SIZE_MAX; - ret->length = slice_size; - - ++buf->root->refcount; - - return ret; -} - -void buffer_free(buffer_t* buffer) { - if (!buffer) return; - - if (buffer->root != buffer) { - // We're a leaf node. Delete the root node if we're the last referent. - if (--buffer->root->refcount == 0) osi_free(buffer->root); - osi_free(buffer); - } else if (--buffer->refcount == 0) { - // We're a root node. Roots are only deleted when their refcount goes to 0. - osi_free(buffer); - } -} - -void* buffer_ptr(const buffer_t* buf) { - CHECK(buf != NULL); - return buf->root->data + buf->root->length - buf->length; -} - -size_t buffer_length(const buffer_t* buf) { - CHECK(buf != NULL); - return buf->length; -} diff --git a/system/osi/src/config.cc b/system/osi/src/config.cc index 038982c52534a521268dba6c1c7c89f0d92eaeb9..ec9516268fca44b6013798651edb20393fc52872 100644 --- a/system/osi/src/config.cc +++ b/system/osi/src/config.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -31,6 +30,7 @@ #include #include +#include #include #include diff --git a/system/osi/src/internal/semaphore.cc b/system/osi/src/internal/semaphore.cc index fb95e2b14a5c6e413df0750e4c9ed5635875691a..b5c6041d2853e4b5dd14f8a459514db8aafa541b 100644 --- a/system/osi/src/internal/semaphore.cc +++ b/system/osi/src/internal/semaphore.cc @@ -21,7 +21,6 @@ #include "osi/semaphore.h" #include -#include #include #include #include @@ -29,8 +28,8 @@ #include #include "check.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #if !defined(EFD_SEMAPHORE) diff --git a/system/osi/src/osi.cc b/system/osi/src/osi.cc index 1b0f3a23482d0e2ccc4bd20825460185e0b59323..33a3886aacd1a378980049b10f81679ceaf60d82 100644 --- a/system/osi/src/osi.cc +++ b/system/osi/src/osi.cc @@ -18,8 +18,9 @@ #define LOG_TAG "bt_osi_rand" +#include "osi/include/osi.h" + #include -#include #include #include #include @@ -28,8 +29,7 @@ #include #include "check.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "os/log.h" #define RANDOM_PATH "/dev/urandom" diff --git a/system/osi/src/reactor.cc b/system/osi/src/reactor.cc index 41233d227a38a283b055e056481023d402ee9d61..e16334e1520d4eacc6f5bc3bdb38330ab6eefc48 100644 --- a/system/osi/src/reactor.cc +++ b/system/osi/src/reactor.cc @@ -21,7 +21,6 @@ #include "osi/include/reactor.h" #include -#include #include #include #include @@ -32,9 +31,9 @@ #include #include "check.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/list.h" -#include "osi/include/log.h" #if !defined(EFD_SEMAPHORE) #define EFD_SEMAPHORE (1 << 0) diff --git a/system/osi/src/socket.cc b/system/osi/src/socket.cc index f9c4835fb9442687023da85f85159c9e5510716c..43b90eeb2341cc17ff6a2d595b2dc632d14c278a 100644 --- a/system/osi/src/socket.cc +++ b/system/osi/src/socket.cc @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -30,8 +29,8 @@ #include #include "check.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "osi/include/reactor.h" diff --git a/system/osi/src/socket_utils/socket_local_client.cc b/system/osi/src/socket_utils/socket_local_client.cc index 14f8b8386e1f0499ee024185df866cb35fa67f4d..7a0764d54165fc64d500b21e59feb3f54c7b2eaf 100644 --- a/system/osi/src/socket_utils/socket_local_client.cc +++ b/system/osi/src/socket_utils/socket_local_client.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include diff --git a/system/osi/src/socket_utils/socket_local_server.cc b/system/osi/src/socket_utils/socket_local_server.cc index 9710ab20608f50a1c2e65e9c60c06f60342aac7b..94ec4c1111f5aefa4a6a6be928dc99afb89200f8 100644 --- a/system/osi/src/socket_utils/socket_local_server.cc +++ b/system/osi/src/socket_utils/socket_local_server.cc @@ -14,11 +14,9 @@ * limitations under the License. */ -#include #include #include #include -#include #include #include #include diff --git a/system/osi/src/stack_power_telemetry.cc b/system/osi/src/stack_power_telemetry.cc new file mode 100644 index 0000000000000000000000000000000000000000..65aefebaf382c1810bfe705d87a4f655367cdc21 --- /dev/null +++ b/system/osi/src/stack_power_telemetry.cc @@ -0,0 +1,821 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "stack_power_tel" + +#include "osi/include/stack_power_telemetry.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "common/init_flags.h" +#include "os/log.h" +#include "osi/include/properties.h" +#include "stack/include/acl_api_types.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/btm_status.h" +#include "types/raw_address.h" + +time_t get_current_time() { return time(0); } + +namespace { + +constexpr int64_t kTrafficLogTime = 120; // 120seconds +constexpr uint8_t kLogEntriesSize{15}; +constexpr std::string_view kLogPerChannelProperty = + "bluetooth.powertelemetry.log_per_channel.enabled"; +bool power_telemerty_enabled_ = + bluetooth::common::init_flags::bluetooth_power_telemetry_is_enabled(); + +std::string GetTimeString(time_t tstamp) { + char buffer[15]; + tm* nTm = localtime(&tstamp); + strftime(buffer, 15, "%m-%d %H:%M:%S", nTm); + return std::string(buffer); +} + +enum class State { + kDisconnected = 0, + kConnected = 1, +}; + +enum class ChannelType { + kUnknown = 0, + kRfcomm = 1, + kL2cap = 2, +}; + +ChannelType PsmToChannelType(const uint16_t& psm) { + switch (psm) { + case BT_PSM_RFCOMM: + return ChannelType::kRfcomm; + break; + } + return ChannelType::kL2cap; +} + +struct Duration { + time_t begin; + time_t end; +}; + +struct DataTransfer { + struct { + int64_t bytes{0}; + } rx, tx; +}; + +struct LinkDetails { + RawAddress bd_addr; + uint16_t handle = 0; + Duration duration; + uint8_t tx_power_level = 0; +}; + +struct ChannelDetails { + RawAddress bd_addr; + int32_t psm = 0; + struct { + uint16_t cid = 0; + } src, dst; + State state = State::kDisconnected; + ChannelType channel_type = ChannelType::kUnknown; + DataTransfer data_transfer; + Duration duration; + struct { + time_t last_data_sent; + } rx, tx; +}; + +struct AclPacketDetails { + struct { + uint32_t pkt_count = 0; + int64_t byte_count = 0; + } rx, tx; +}; + +struct AdvDetails { + Duration active; +}; + +struct ScanDetails { + int32_t count = 0; +}; + +struct SniffData { + RawAddress bd_addr; + uint32_t sniff_count = 0, active_count = 0; + time_t sniff_duration_ts = 0, active_duration_ts = 0; + time_t last_mode_change_ts = get_current_time(); +}; + +class LogDataContainer { + public: + struct Duration lifetime; + std::map> channel_map; + DataTransfer l2c_data, rfc_data; + std::map sniff_activity_map; + struct { + std::map link_details_map; + std::list link_details_list; + } acl, sco; + std::list adv_list; + ScanDetails scan_details, inq_scan_details, le_scan_details; + AclPacketDetails acl_pkt_ds, hci_cmd_evt_ds; +}; + +} // namespace + +struct power_telemetry::PowerTelemetryImpl { + PowerTelemetryImpl() { + idx_containers = 0; + traffic_logged_ts_ = get_current_time(); + log_per_channel_ = osi_property_get_bool( + std::string(kLogPerChannelProperty).c_str(), false); + } + + LogDataContainer& GetCurrentLogDataContainer() { + return log_data_containers_[idx_containers]; + } + + void maybe_log_data() { + if ((get_current_time() - traffic_logged_ts_) >= kTrafficLogTime) { + LogDataTransfer(); + } + } + + void LogDataTransfer(); + void RecordLogDataContainer(); + + mutable std::mutex dumpsys_mutex_; + LogDataContainer log_data_containers_[kLogEntriesSize]; + std::atomic_int idx_containers; + time_t traffic_logged_ts_ = 0; + struct { + struct { + int64_t bytes_ = 0; + } rx, tx; + } l2c, rfc; + struct { + uint32_t pkt_ = 0; + int64_t len_ = 0; + } rx, tx; + + struct { + uint16_t count_; + } scan, inq_scan, ble_adv, ble_scan; + + struct { + uint32_t count_ = 0; + } cmd, event; + bool scan_timer_started_ = false; + bool log_per_channel_ = false; +}; + +void power_telemetry::PowerTelemetryImpl::LogDataTransfer() { + if (!power_telemerty_enabled_) return; + + LogDataContainer& ldc = GetCurrentLogDataContainer(); + + if ((l2c.rx.bytes_ != 0) || (l2c.tx.bytes_ != 0)) { + ldc.l2c_data = { + .rx = + { + .bytes = l2c.rx.bytes_, + }, + .tx = + { + .bytes = l2c.tx.bytes_, + }, + }; + l2c = {}; + } + + if ((rfc.rx.bytes_ != 0) || (rfc.tx.bytes_ != 0)) { + ldc.rfc_data = { + .rx = + { + .bytes = rfc.rx.bytes_, + }, + .tx = + { + .bytes = rfc.tx.bytes_, + }, + }; + rfc = {}; + } + + if (scan.count_ != 0) { + ldc.scan_details = { + .count = scan.count_, + }; + scan.count_ = 0; + } + + if (inq_scan.count_ != 0) { + ldc.inq_scan_details = { + .count = inq_scan.count_, + }; + inq_scan.count_ = 0; + } + + if ((rx.pkt_ != 0) || (tx.pkt_ != 0)) { + ldc.acl_pkt_ds = { + .rx = + { + .pkt_count = rx.pkt_, + .byte_count = rx.len_, + }, + .tx = + { + .pkt_count = tx.pkt_, + .byte_count = tx.len_, + }, + }; + rx.pkt_ = tx.pkt_ = rx.len_ = tx.len_ = 0; + } + + if ((cmd.count_ != 0) || (event.count_ != 0)) { + ldc.hci_cmd_evt_ds = { + .rx = + { + .pkt_count = event.count_, + }, + .tx = + { + .pkt_count = cmd.count_, + }, + }; + cmd.count_ = event.count_ = 0; + } + + if (ble_scan.count_ != 0) { + ldc.le_scan_details = { + .count = ble_scan.count_, + }; + ble_scan.count_ = 0; + } + + ldc.lifetime.begin = traffic_logged_ts_; + ldc.lifetime.end = get_current_time(); + + traffic_logged_ts_ = get_current_time(); + RecordLogDataContainer(); +} + +void power_telemetry::PowerTelemetryImpl::RecordLogDataContainer() { + if (!power_telemerty_enabled_) return; + + LogDataContainer& ldc = GetCurrentLogDataContainer(); + + LOG_INFO( + "bt_power: scan: %d, inqScan: %d, aclTx: %d, aclRx: %d, hciCmd: %d, " + "hciEvt: %d, bleScan: %d", + ldc.scan_details.count, ldc.inq_scan_details.count, + ldc.acl_pkt_ds.tx.pkt_count, ldc.acl_pkt_ds.rx.pkt_count, + ldc.hci_cmd_evt_ds.tx.pkt_count, ldc.hci_cmd_evt_ds.rx.pkt_count, + ldc.le_scan_details.count); + + idx_containers++; + if (idx_containers >= kLogEntriesSize) { + idx_containers = 0; + } + + log_data_containers_[idx_containers] = LogDataContainer(); +} + +power_telemetry::PowerTelemetry& power_telemetry::GetInstance() { + static power_telemetry::PowerTelemetry power_telemetry; + return power_telemetry; +} + +power_telemetry::PowerTelemetry::PowerTelemetry() { + pimpl_ = std::make_unique(); +} + +void power_telemetry::PowerTelemetry::LogInqScanStarted() { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->inq_scan.count_++; + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogInqScanStopped() { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogBleScan(uint16_t num_resps) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->ble_scan.count_ += num_resps; + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogBleAdvStarted() { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + const time_t current_time = get_current_time(); + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + ldc.adv_list.emplace_back(AdvDetails{.active.begin = current_time}); +} + +void power_telemetry::PowerTelemetry::LogBleAdvStopped() { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + const time_t current_time = get_current_time(); + + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + if (ldc.adv_list.size() == 0) { + LOG_WARN("Empty advList. Skip LogBleAdvDetails."); + return; + } + ldc.adv_list.back().active.end = current_time; +} + +void power_telemetry::PowerTelemetry::LogTxPower(void* res) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + tBTM_TX_POWER_RESULT* result = (tBTM_TX_POWER_RESULT*)res; + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + + if (result->status != BTM_SUCCESS) { + return; + } + + for (auto it : ldc.acl.link_details_map) { + uint16_t handle = it.first; + LinkDetails lds = it.second; + if (lds.bd_addr == result->rem_bda) { + lds.tx_power_level = result->tx_power; + ldc.acl.link_details_map[handle] = lds; + break; + } + } + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogLinkDetails(uint16_t handle, + const RawAddress& bd_addr, + bool is_connected, + bool is_acl_link) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + std::map& link_map = + is_acl_link ? ldc.acl.link_details_map : ldc.sco.link_details_map; + std::list& link_list = + is_acl_link ? ldc.acl.link_details_list : ldc.sco.link_details_list; + + if (is_connected == false && link_map.count(handle) != 0) { + LinkDetails link_details = link_map[handle]; + link_details.duration.end = get_current_time(); + link_list.push_back(link_details); + link_map.erase(handle); + } else if (is_connected == true) { + link_map[handle] = { + .bd_addr = bd_addr, + .handle = handle, + .duration.begin = get_current_time(), + .tx_power_level = 0, + }; + + if (is_acl_link) { + SniffData sniff_data; + if (ldc.sniff_activity_map.count(handle) != 0) { + ldc.sniff_activity_map.erase(handle); + } + sniff_data.bd_addr = bd_addr; + sniff_data.active_count = 1; + sniff_data.last_mode_change_ts = get_current_time(); + ldc.sniff_activity_map[handle] = sniff_data; + } + } + + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogHciCmdDetail() { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->cmd.count_++; + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogHciEvtDetail() { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->event.count_++; + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogSniffStarted( + uint16_t handle, const RawAddress& bd_addr) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + const time_t current_timestamp = get_current_time(); + SniffData sniff_data; + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + if (ldc.sniff_activity_map.count(handle) == 0) { + sniff_data.bd_addr = bd_addr; + } else { + sniff_data = ldc.sniff_activity_map[handle]; + } + sniff_data.sniff_count++; + sniff_data.active_duration_ts += + current_timestamp - sniff_data.last_mode_change_ts; + sniff_data.last_mode_change_ts = get_current_time(); + ldc.sniff_activity_map[handle] = sniff_data; + + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogSniffStopped( + uint16_t handle, const RawAddress& bd_addr) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + const time_t current_timestamp = get_current_time(); + SniffData sniff_data; + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + if (ldc.sniff_activity_map.count(handle) == 0) { + sniff_data.bd_addr = bd_addr; + } else { + sniff_data = ldc.sniff_activity_map[handle]; + } + sniff_data.active_count++; + sniff_data.sniff_duration_ts += + current_timestamp - sniff_data.last_mode_change_ts; + sniff_data.last_mode_change_ts = get_current_time(); + ldc.sniff_activity_map[handle] = sniff_data; + + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogScanStarted() { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->scan.count_++; + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogTxAclPktData(uint16_t len) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->tx.pkt_++; + pimpl_->tx.len_ += len; + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogRxAclPktData(uint16_t len) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->rx.pkt_++; + pimpl_->rx.len_ += len; + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogChannelConnected( + uint16_t psm, int32_t src_id, int32_t dst_id, const RawAddress& bd_addr) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + std::list channel_details_list; + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + const ChannelType channel_type = PsmToChannelType(psm); + ChannelDetails channel_details = { + .bd_addr = bd_addr, + .psm = psm, + .src.cid = static_cast(src_id), + .dst.cid = static_cast(dst_id), + .state = State::kConnected, + .channel_type = channel_type, + .data_transfer = {}, + .duration.begin = get_current_time(), + .rx = {}, + .tx = {}, + }; + + if (ldc.channel_map.count(bd_addr) == 0) { + ldc.channel_map.insert(std::pair>( + bd_addr, std::list({channel_details}))); + } else { + ldc.channel_map[bd_addr].emplace_back(channel_details); + } + + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogChannelDisconnected( + uint16_t psm, int32_t src_id, int32_t dst_id, const RawAddress& bd_addr) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + std::list channel_details_list; + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + if (ldc.channel_map.count(bd_addr) == 0) { + return; + } + + const ChannelType channel_type = PsmToChannelType(psm); + + for (auto& channel_detail : ldc.channel_map[bd_addr]) { + if (channel_detail.src.cid == src_id && channel_detail.dst.cid == dst_id && + channel_detail.channel_type == channel_type) { + channel_detail.state = State::kDisconnected; + channel_detail.duration.end = get_current_time(); + break; + } + } + + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogTxBytes(uint16_t psm, int32_t src_id, + int32_t dst_id, + const RawAddress& bd_addr, + int32_t num_bytes) { + if (!power_telemerty_enabled_) return; + + const ChannelType channel_type = PsmToChannelType(psm); + std::lock_guard lock(pimpl_->dumpsys_mutex_); + if (pimpl_->log_per_channel_ == true) { + std::list channel_details_list; + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + if (ldc.channel_map.count(bd_addr) == 0) { + return; + } + + for (auto& channel_details : ldc.channel_map[bd_addr]) { + if (channel_details.src.cid == src_id && + channel_details.dst.cid == dst_id && + channel_details.channel_type == channel_type) { + channel_details.data_transfer.tx.bytes += num_bytes; + channel_details.tx.last_data_sent = get_current_time(); + break; + } + } + } + if (channel_type == ChannelType::kRfcomm) { + pimpl_->rfc.tx.bytes_ += num_bytes; + } else { + pimpl_->l2c.tx.bytes_ += num_bytes; + } + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::LogRxBytes(uint16_t psm, int32_t src_id, + int32_t dst_id, + const RawAddress& bd_addr, + int32_t num_bytes) { + if (!power_telemerty_enabled_) return; + + const ChannelType channel_type = PsmToChannelType(psm); + std::lock_guard lock(pimpl_->dumpsys_mutex_); + if (pimpl_->log_per_channel_ == true) { + std::list channel_details_list; + LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer(); + if (ldc.channel_map.count(bd_addr) == 0) { + return; + } + + for (auto& channel_detail : ldc.channel_map[bd_addr]) { + if (channel_detail.src.cid == src_id && + channel_detail.dst.cid == dst_id && + channel_detail.channel_type == channel_type) { + channel_detail.data_transfer.rx.bytes += num_bytes; + channel_detail.rx.last_data_sent = get_current_time(); + break; + } + } + } + + switch (channel_type) { + case ChannelType::kRfcomm: + pimpl_->rfc.rx.bytes_ += num_bytes; + break; + case ChannelType::kL2cap: + pimpl_->l2c.rx.bytes_ += num_bytes; + break; + case ChannelType::kUnknown: + break; + } + + pimpl_->maybe_log_data(); +} + +void power_telemetry::PowerTelemetry::Dumpsys(int32_t fd) { + if (!power_telemerty_enabled_) return; + + std::lock_guard lock(pimpl_->dumpsys_mutex_); + pimpl_->RecordLogDataContainer(); + + dprintf(fd, "\nPower Telemetry Data:\n"); + dprintf(fd, "\nBR/EDR Scan Events:\n"); + dprintf(fd, "%-22s %-22s %-15s\n", "StartTimeStamp", "EndTimeStamp", + "Number of Scans"); + for (auto&& ldc : pimpl_->log_data_containers_) { + if (ldc.scan_details.count == 0) { + continue; + } + dprintf(fd, "%-22s %-22s %-15d\n", + GetTimeString(ldc.lifetime.begin).c_str(), + GetTimeString(ldc.lifetime.end).c_str(), ldc.scan_details.count); + } + dprintf(fd, "\nBR/EDR InqScan Events:\n"); + dprintf(fd, "%-22s %-22s %-15s\n", "StartTimeStamp", "EndTimeStamp", + "Number of InqScans"); + for (auto&& ldc : pimpl_->log_data_containers_) { + if (ldc.inq_scan_details.count == 0) { + continue; + } + dprintf( + fd, "%-22s %-22s %-15d\n", GetTimeString(ldc.lifetime.begin).c_str(), + GetTimeString(ldc.lifetime.end).c_str(), ldc.inq_scan_details.count); + } + + dprintf(fd, "\nACL Packet Details:\n"); + dprintf(fd, "%-22s %-22s %-12s %-12s %-12s %-12s\n", "StartTimeStamp", + "EndTimeStamp", "Tx Packets", "Tx Bytes", "Rx Packets", "Rx Bytes"); + for (auto&& ldc : pimpl_->log_data_containers_) { + if ((ldc.acl_pkt_ds.tx.byte_count == 0) && + (ldc.acl_pkt_ds.rx.byte_count == 0)) { + continue; + } + dprintf(fd, "%-22s %-22s %-12d %-12ld %-12d %-12ld\n", + GetTimeString(ldc.lifetime.begin).c_str(), + GetTimeString(ldc.lifetime.end).c_str(), + ldc.acl_pkt_ds.tx.pkt_count, (long)ldc.acl_pkt_ds.tx.byte_count, + ldc.acl_pkt_ds.rx.pkt_count, (long)ldc.acl_pkt_ds.rx.byte_count); + } + + dprintf(fd, "\nHCI CMD/EVT Details:\n"); + dprintf(fd, "%-22s %-22s %-14s %-14s\n", "StartTimeStamp", "EndTimeStamp", + "HCI Commands", "HCI Events"); + for (auto&& ldc : pimpl_->log_data_containers_) { + if ((ldc.hci_cmd_evt_ds.tx.pkt_count == 0) && + (ldc.hci_cmd_evt_ds.rx.pkt_count == 0)) { + continue; + } + dprintf(fd, "%-22s %-22s %-14d %-14d\n", + GetTimeString(ldc.lifetime.begin).c_str(), + GetTimeString(ldc.lifetime.end).c_str(), + ldc.hci_cmd_evt_ds.tx.pkt_count, ldc.hci_cmd_evt_ds.rx.pkt_count); + } + dprintf(fd, "\nBLE Scan Details:\n"); + dprintf(fd, "%-22s %-22s %-14s\n", "StartTimeStamp", "EndTimeStamp", + "Number of scans"); + for (auto&& ldc : pimpl_->log_data_containers_) { + if (ldc.le_scan_details.count == 0) { + continue; + } + dprintf(fd, "%-22s %-22s %-14d\n", + GetTimeString(ldc.lifetime.begin).c_str(), + GetTimeString(ldc.lifetime.end).c_str(), ldc.le_scan_details.count); + } + dprintf(fd, "\nL2CAP/RFCOMM Channel Events:\n"); + dprintf(fd, "%-19s %-7s %-7s %-7s %-8s %-22s", "RemoteAddress", "Type", + "SrcId", "DstId", "PSM", "ConnectedTimeStamp"); + dprintf(fd, " %-22s %-14s ", "DisconnectedTimeStamp", "State"); + if (pimpl_->log_per_channel_ == true) { + dprintf(fd, " %-10s %-10s %-22s %-22s", "TxBytes", "RxBytes", + "LastTxTimeStamp", "LastRxTimeStamp"); + } + dprintf(fd, "\n"); + for (auto&& ldc : pimpl_->log_data_containers_) { + for (auto& itr : ldc.channel_map) { + const RawAddress& bd_addr = itr.first; + std::list channel_details_list = itr.second; + for (auto& channel_details : channel_details_list) { + dprintf(fd, "%-19s ", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + dprintf(fd, "%-7s %-7d %-7d %-8d %-22s %-22s %-14s", + (channel_details.channel_type == ChannelType::kRfcomm) + ? "RFCOMM" + : "L2CAP", + channel_details.src.cid, channel_details.dst.cid, + channel_details.psm, + GetTimeString(channel_details.duration.begin).c_str(), + GetTimeString(channel_details.duration.end).c_str(), + (channel_details.state == State::kDisconnected) ? "DISCONNECTED" + : "CONNECTED"); + if (pimpl_->log_per_channel_ == true) { + dprintf(fd, "%-10ld %-10ld %-22s %-22s", + (long)channel_details.data_transfer.tx.bytes, + (long)channel_details.data_transfer.rx.bytes, + GetTimeString(channel_details.tx.last_data_sent).c_str(), + GetTimeString(channel_details.rx.last_data_sent).c_str()); + } + dprintf(fd, "\n"); + } + } + } + + dprintf(fd, "\n\nBluetooth Data Traffic Details\n"); + dprintf(fd, "L2cap Data Traffic\n"); + dprintf(fd, "%-22s %-22s %-10s %-10s\n", "StartTime", "EndTime", "TxBytes", + "RxBytes"); + for (auto&& ldc : pimpl_->log_data_containers_) { + if (ldc.l2c_data.tx.bytes == 0 && ldc.l2c_data.rx.bytes) { + continue; + } + dprintf(fd, "%-22s %-22s %-10ld %-10ld\n", + GetTimeString(ldc.lifetime.begin).c_str(), + GetTimeString(ldc.lifetime.end).c_str(), + (long)ldc.l2c_data.tx.bytes, (long)ldc.l2c_data.rx.bytes); + } + + dprintf(fd, "\nRfcomm Data Traffic\n"); + dprintf(fd, "%-22s %-22s %-10s %-10s\n", "StartTime", "EndTime", "TxBytes", + "RxBytes"); + for (auto&& ldc : pimpl_->log_data_containers_) { + if (ldc.rfc_data.tx.bytes == 0 && ldc.rfc_data.rx.bytes == 0) { + continue; + } + dprintf(fd, "%-22s %-22s %-10ld %-10ld\n", + GetTimeString(ldc.lifetime.begin).c_str(), + GetTimeString(ldc.lifetime.end).c_str(), + (long)ldc.rfc_data.tx.bytes, (long)ldc.rfc_data.rx.bytes); + } + + dprintf(fd, "\n\nSniff Activity Details\n"); + dprintf(fd, "%-8s %-19s %-19s %-24s %-19s %-24s\n", "Handle", "BDADDR", + "ActiveModeCount", "ActiveModeDuration(sec)", "SniffModeCount", + "SniffModeDuration(sec)"); + for (auto&& ldc : pimpl_->log_data_containers_) { + for (auto itr : ldc.sniff_activity_map) { + uint16_t handle = itr.first; + SniffData sniff_data = itr.second; + dprintf(fd, "%-8d %-19s %-19d %-24ld %-19d %-24ld\n", handle, + ADDRESS_TO_LOGGABLE_CSTR(sniff_data.bd_addr), + sniff_data.active_count, (long)sniff_data.active_duration_ts, + sniff_data.sniff_count, (long)sniff_data.sniff_duration_ts); + } + } + + dprintf(fd, "\n\nACL Link Details\n"); + dprintf(fd, "%-6s %-19s %-22s %-22s %-8s\n", "handle", "BDADDR", + "ConnectedTimeStamp", "DisconnectedTimeStamp", "TxPower"); + for (auto&& ldc : pimpl_->log_data_containers_) { + for (auto it : ldc.acl.link_details_map) { + uint16_t handle = it.first; + LinkDetails lds = it.second; + dprintf(fd, "%-6d %-19s %-22s %-22s %-8d\n", handle, + ADDRESS_TO_LOGGABLE_CSTR(lds.bd_addr), + GetTimeString(lds.duration.begin).c_str(), + GetTimeString(lds.duration.end).c_str(), lds.tx_power_level); + } + + for (auto& it : ldc.acl.link_details_list) { + dprintf(fd, "%-6d %-19s %-22s %-22s %-8d\n", it.handle, + ADDRESS_TO_LOGGABLE_CSTR(it.bd_addr), + GetTimeString(it.duration.begin).c_str(), + GetTimeString(it.duration.end).c_str(), it.tx_power_level); + } + } + dprintf(fd, "\nSCO Link Details\n"); + dprintf(fd, "%-6s %-19s %-22s %-22s\n", "handle", "BDADDR", + "ConnectedTimeStamp", "DisconnectedTimeStamp"); + for (auto&& ldc : pimpl_->log_data_containers_) { + for (auto& it : ldc.sco.link_details_list) { + dprintf(fd, "%-6d %-19s %-22s %-22s\n", it.handle, + ADDRESS_TO_LOGGABLE_CSTR(it.bd_addr), + GetTimeString(it.duration.begin).c_str(), + GetTimeString(it.duration.end).c_str()); + } + } + + dprintf(fd, "\n\n"); +} diff --git a/system/osi/src/thread.cc b/system/osi/src/thread.cc index d4528c96d95b3e9798fd89f3210e30d929e04988..093ba7663bf571736e27ff876d0b378a69763fa0 100644 --- a/system/osi/src/thread.cc +++ b/system/osi/src/thread.cc @@ -20,10 +20,7 @@ #include "osi/include/thread.h" -#include - #include -#include #include #include #include @@ -32,11 +29,14 @@ #include #include +#include +#include + #include "check.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "osi/include/fixed_queue.h" -#include "osi/include/log.h" #include "osi/include/reactor.h" #include "osi/semaphore.h" diff --git a/system/osi/src/wakelock.cc b/system/osi/src/wakelock.cc index 3b57077ae4b6c369a5db9792d718f2e84f2e8ed9..34e0885e175165e186268becf8b8ade2c20dd1bb 100644 --- a/system/osi/src/wakelock.cc +++ b/system/osi/src/wakelock.cc @@ -18,11 +18,10 @@ #define LOG_TAG "bt_osi_wakelock" -#include +#include "osi/include/wakelock.h" + #include #include -#include -#include #include #include #include @@ -34,14 +33,9 @@ #include #include "base/logging.h" -#include "check.h" #include "common/metrics.h" -#include "osi/include/alarm.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/osi.h" -#include "osi/include/thread.h" -#include "osi/include/wakelock.h" using bluetooth::common::BluetoothMetricsLogger; diff --git a/system/osi/test/AlarmTestHarness.cc b/system/osi/test/AlarmTestHarness.cc deleted file mode 100644 index ad890c4100d557bd754fd0623f78a405012c33d4..0000000000000000000000000000000000000000 --- a/system/osi/test/AlarmTestHarness.cc +++ /dev/null @@ -1,57 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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. - * - ******************************************************************************/ - -#include "AlarmTestHarness.h" - -#include - -#include "osi/include/alarm.h" -#include "osi/include/wakelock.h" - -static bool is_wake_lock_acquired = false; - -static int acquire_wake_lock_cb(const char* lock_name) { - is_wake_lock_acquired = true; - return BT_STATUS_SUCCESS; -} - -static int release_wake_lock_cb(const char* lock_name) { - is_wake_lock_acquired = false; - return BT_STATUS_SUCCESS; -} - -static bt_os_callouts_t bt_wakelock_callouts = { - sizeof(bt_os_callouts_t), NULL, acquire_wake_lock_cb, release_wake_lock_cb}; - -void AlarmTestHarness::SetUp() { - AllocationTestHarness::SetUp(); - - TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 500; - - wakelock_set_os_callouts(&bt_wakelock_callouts); -} - -void AlarmTestHarness::TearDown() { - alarm_cleanup(); - wakelock_cleanup(); - wakelock_set_os_callouts(NULL); - - AllocationTestHarness::TearDown(); -} - -bool AlarmTestHarness::WakeLockHeld() { return is_wake_lock_acquired; } diff --git a/system/osi/test/AllocationTestHarness.cc b/system/osi/test/AllocationTestHarness.cc deleted file mode 100644 index a858242458eb24a95db3ffc0f79337c13fb10869..0000000000000000000000000000000000000000 --- a/system/osi/test/AllocationTestHarness.cc +++ /dev/null @@ -1,33 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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. - * - ******************************************************************************/ - -#include - -#include "osi/test/AllocationTestHarness.h" - -#include "osi/include/allocation_tracker.h" - -void AllocationTestHarness::SetUp() { - allocation_tracker_init(); - allocation_tracker_reset(); -} - -void AllocationTestHarness::TearDown() { - EXPECT_EQ(0U, allocation_tracker_expect_no_allocations()) - << "not all memory freed"; -} diff --git a/system/osi/test/AllocationTestHarness.h b/system/osi/test/AllocationTestHarness.h deleted file mode 100644 index 0c6b98e4e7a9db695c5dd81eeb45356d284b6818..0000000000000000000000000000000000000000 --- a/system/osi/test/AllocationTestHarness.h +++ /dev/null @@ -1,27 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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 - -class AllocationTestHarness : public ::testing::Test { - protected: - virtual void SetUp(); - virtual void TearDown(); -}; diff --git a/system/osi/test/alarm_test.cc b/system/osi/test/alarm_test.cc index 7b42bbc9fe963282cee6ea3faa01ef2932c4901c..f0e4d71da71ec360e86987ddfa4632185445c3ea 100644 --- a/system/osi/test/alarm_test.cc +++ b/system/osi/test/alarm_test.cc @@ -16,15 +16,16 @@ * ******************************************************************************/ +#include "osi/include/alarm.h" + #include #include - -#include "AlarmTestHarness.h" +#include #include "common/message_loop_thread.h" -#include "osi/include/alarm.h" #include "osi/include/fixed_queue.h" #include "osi/include/osi.h" +#include "osi/include/wakelock.h" #include "osi/semaphore.h" using base::Closure; @@ -43,10 +44,30 @@ static MessageLoopThread* thread_; bluetooth::common::MessageLoopThread* get_main_thread() { return thread_; } -class AlarmTest : public AlarmTestHarness { +extern int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS; + +static bool is_wake_lock_acquired = false; + +static int acquire_wake_lock_cb(const char* lock_name) { + is_wake_lock_acquired = true; + return BT_STATUS_SUCCESS; +} + +static int release_wake_lock_cb(const char* lock_name) { + is_wake_lock_acquired = false; + return BT_STATUS_SUCCESS; +} + +static bt_os_callouts_t bt_wakelock_callouts = { + sizeof(bt_os_callouts_t), acquire_wake_lock_cb, release_wake_lock_cb}; + +class AlarmTest : public ::testing::Test { protected: void SetUp() override { - AlarmTestHarness::SetUp(); + TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 500; + + wakelock_set_os_callouts(&bt_wakelock_callouts); + cb_counter = 0; cb_misordered_counter = 0; @@ -55,7 +76,9 @@ class AlarmTest : public AlarmTestHarness { void TearDown() override { semaphore_free(semaphore); - AlarmTestHarness::TearDown(); + alarm_cleanup(); + wakelock_cleanup(); + wakelock_set_os_callouts(NULL); } }; @@ -93,7 +116,7 @@ TEST_F(AlarmTest, test_cancel) { msleep(10 + EPSILON_MS); EXPECT_EQ(cb_counter, 0); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm); } @@ -112,12 +135,12 @@ TEST_F(AlarmTest, test_set_short) { alarm_set(alarm, 10, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_TRUE(WakeLockHeld()); + EXPECT_TRUE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm); } @@ -128,16 +151,16 @@ TEST_F(AlarmTest, test_set_short_periodic) { alarm_set(alarm, 10, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_TRUE(WakeLockHeld()); + EXPECT_TRUE(is_wake_lock_acquired); for (int i = 1; i <= 10; i++) { semaphore_wait(semaphore); EXPECT_GE(cb_counter, i); - EXPECT_TRUE(WakeLockHeld()); + EXPECT_TRUE(is_wake_lock_acquired); } alarm_cancel(alarm); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm); } @@ -147,16 +170,16 @@ TEST_F(AlarmTest, test_set_zero_periodic) { alarm_set(alarm, 0, cb, NULL); - EXPECT_TRUE(WakeLockHeld()); + EXPECT_TRUE(is_wake_lock_acquired); for (int i = 1; i <= 10; i++) { semaphore_wait(semaphore); EXPECT_GE(cb_counter, i); - EXPECT_TRUE(WakeLockHeld()); + EXPECT_TRUE(is_wake_lock_acquired); } alarm_cancel(alarm); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm); } @@ -166,12 +189,12 @@ TEST_F(AlarmTest, test_set_long) { alarm_set(alarm, TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm); } @@ -181,20 +204,20 @@ TEST_F(AlarmTest, test_set_short_short) { alarm_new("alarm_test.test_set_short_short_1")}; alarm_set(alarm[0], 10, cb, NULL); - alarm_set(alarm[1], 20, cb, NULL); + alarm_set(alarm[1], 200, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_TRUE(WakeLockHeld()); + EXPECT_TRUE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_TRUE(WakeLockHeld()); + EXPECT_TRUE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 2); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm[0]); alarm_free(alarm[1]); @@ -209,17 +232,17 @@ TEST_F(AlarmTest, test_set_short_long) { NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_TRUE(WakeLockHeld()); + EXPECT_TRUE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 2); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm[0]); alarm_free(alarm[1]); @@ -234,17 +257,17 @@ TEST_F(AlarmTest, test_set_long_long) { NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 2); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm[0]); alarm_free(alarm[1]); @@ -259,13 +282,13 @@ TEST_F(AlarmTest, test_is_scheduled) { EXPECT_TRUE(alarm_is_scheduled(alarm)); EXPECT_EQ(cb_counter, 0); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); semaphore_wait(semaphore); EXPECT_FALSE(alarm_is_scheduled(alarm)); EXPECT_EQ(cb_counter, 1); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); alarm_free(alarm); } @@ -293,7 +316,7 @@ TEST_F(AlarmTest, test_callback_ordering) { for (int i = 0; i < 100; i++) alarm_free(alarms[i]); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); } // Test whether the callbacks are involed in the expected order on a @@ -329,7 +352,7 @@ TEST_F(AlarmTest, test_callback_ordering_on_mloop) { for (int i = 0; i < 100; i++) alarm_free(alarms[i]); message_loop_thread.ShutDown(); - EXPECT_FALSE(WakeLockHeld()); + EXPECT_FALSE(is_wake_lock_acquired); } // Try to catch any race conditions between the timer callback and |alarm_free|. diff --git a/system/osi/test/allocation_tracker_test.cc b/system/osi/test/allocation_tracker_test.cc deleted file mode 100644 index 6ce0e691139d94dc3979a0f8d4238e22ec905b9e..0000000000000000000000000000000000000000 --- a/system/osi/test/allocation_tracker_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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. - * - ******************************************************************************/ - -#include - -#include "osi/include/allocation_tracker.h" - -void allocation_tracker_uninit(void); - -static const allocator_id_t allocator_id = 5; - -TEST(AllocationTrackerTest, test_uninit_no_bad_effects) { - void* dummy_allocation = malloc(4); - - // Ensure uninitialized state (previous tests may have called init) - allocation_tracker_uninit(); - - EXPECT_EQ(4U, allocation_tracker_resize_for_canary(4)); - allocation_tracker_notify_alloc(allocator_id, dummy_allocation, 4); - EXPECT_EQ(0U, allocation_tracker_expect_no_allocations()); // should not have - // registered an - // allocation - allocation_tracker_notify_free(allocator_id, dummy_allocation); - EXPECT_EQ(0U, allocation_tracker_expect_no_allocations()); - - free(dummy_allocation); -} - -TEST(AllocationTrackerTest, test_canaries_on) { - allocation_tracker_uninit(); - allocation_tracker_init(); - - size_t with_canary_size = allocation_tracker_resize_for_canary(4); - EXPECT_TRUE(with_canary_size > 4); - - void* dummy_allocation = malloc(with_canary_size); - void* useable_ptr = - allocation_tracker_notify_alloc(allocator_id, dummy_allocation, 4); - EXPECT_TRUE(useable_ptr > dummy_allocation); - EXPECT_EQ(4U, allocation_tracker_expect_no_allocations()); // should have - // registered the - // allocation - void* freeable_ptr = - allocation_tracker_notify_free(allocator_id, useable_ptr); - EXPECT_EQ(dummy_allocation, freeable_ptr); - EXPECT_EQ(0U, allocation_tracker_expect_no_allocations()); - - free(dummy_allocation); -} diff --git a/system/osi/test/allocator_test.cc b/system/osi/test/allocator_test.cc index 1e09f71e0269667aefd49fc7bddf60ceb457643e..a9a99ec01b973a55c2cfbb1b7ccc6f4943dbb33f 100644 --- a/system/osi/test/allocator_test.cc +++ b/system/osi/test/allocator_test.cc @@ -15,15 +15,13 @@ * limitations under the License * ******************************************************************************/ -#include +#include "osi/include/allocator.h" #include -#include "AllocationTestHarness.h" - -#include "osi/include/allocator.h" +#include -class AllocatorTest : public AllocationTestHarness {}; +class AllocatorTest : public ::testing::Test {}; TEST_F(AllocatorTest, test_osi_strndup) { char str[] = "IloveBluetooth"; diff --git a/system/osi/test/array_test.cc b/system/osi/test/array_test.cc deleted file mode 100644 index 5d97602c30d7d7c0aff0a2989af7f4e81c37b2bc..0000000000000000000000000000000000000000 --- a/system/osi/test/array_test.cc +++ /dev/null @@ -1,82 +0,0 @@ -#include "osi/include/array.h" - -#include -#include - -#include "AllocationTestHarness.h" - -class ArrayTest : public AllocationTestHarness {}; - -using ArrayDeathTest = ArrayTest; - -TEST_F(ArrayTest, test_new_free_simple) { - array_t* array = array_new(4); - ASSERT_TRUE(array != NULL); - array_free(array); -} - -TEST_F(ArrayTest, test_free_null) { array_free(NULL); } - -TEST_F(ArrayDeathTest, test_invalid_ptr) { - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - array_t* array = array_new(4); - { - // this will silent SIGABRT sent in EXPECT_DEATH below - ScopedSilentDeath _silentDeath; - - ASSERT_DEATH(array_ptr(array), ""); - } - array_free(array); -} - -TEST_F(ArrayDeathTest, test_invalid_at) { - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - array_t* array = array_new(4); - { - // this will silent SIGABRT sent in EXPECT_DEATH below - ScopedSilentDeath _silentDeath; - - ASSERT_DEATH(array_at(array, 1), ""); - } - array_free(array); -} - -TEST_F(ArrayTest, test_append_value) { - array_t* array = array_new(sizeof(int)); - for (int i = 0; i < 100; ++i) { - array_append_value(array, i * i); - } - for (int i = 0; i < 100; ++i) { - EXPECT_EQ(*(int*)array_at(array, i), i * i); - } - array_free(array); -} - -TEST_F(ArrayTest, test_append_ptr) { - int items[100]; - array_t* array = array_new(sizeof(int)); - for (int i = 0; i < 100; ++i) { - items[i] = i * i; - array_append_ptr(array, &items[i]); - } - for (int i = 0; i < 100; ++i) { - EXPECT_EQ(*(int*)array_at(array, i), i * i); - } - array_free(array); -} - -TEST_F(ArrayTest, test_large_element) { - char strings[][128] = { - "string 1", "string 2", "string 3", "string 4", - "string 5", "string 6", "string 7", "string 8", - }; - - array_t* array = array_new(128); - for (int i = 0; i < 100; ++i) { - array_append_ptr(array, strings[i % 8]); - } - for (int i = 0; i < 100; ++i) { - EXPECT_TRUE(!memcmp(array_at(array, i), strings[i % 8], 128)); - } - array_free(array); -} diff --git a/system/osi/test/config_test.cc b/system/osi/test/config_test.cc index e16cd8a81a1112205cf031ee6dacc93bdbbfc4b6..a6d414194790e661291139874f7de37544a013b2 100644 --- a/system/osi/test/config_test.cc +++ b/system/osi/test/config_test.cc @@ -21,8 +21,6 @@ #include -#include "AllocationTestHarness.h" - static const std::filesystem::path kConfigFile = std::filesystem::temp_directory_path() / "config_test.conf"; static const char* CONFIG_FILE = kConfigFile.c_str(); @@ -70,10 +68,9 @@ HiSyncId = 18446744073709551615 HiSyncId2 = 15001900 \n\ "; -class ConfigTest : public AllocationTestHarness { +class ConfigTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); FILE* fp = fopen(CONFIG_FILE, "wt"); ASSERT_NE(fp, nullptr); ASSERT_EQ(fwrite(CONFIG_FILE_CONTENT, 1, sizeof(CONFIG_FILE_CONTENT), fp), @@ -83,7 +80,6 @@ class ConfigTest : public AllocationTestHarness { void TearDown() override { EXPECT_TRUE(std::filesystem::remove(kConfigFile)); - AllocationTestHarness::TearDown(); } }; diff --git a/system/osi/test/fixed_queue_test.cc b/system/osi/test/fixed_queue_test.cc index 56917efdf9df2e9a5bed6339e6c8f37dce8d9ea7..c34b5409e57d07a177fc738256b66d6c6c035adc 100644 --- a/system/osi/test/fixed_queue_test.cc +++ b/system/osi/test/fixed_queue_test.cc @@ -1,11 +1,10 @@ +#include "osi/include/fixed_queue.h" + #include #include -#include "AllocationTestHarness.h" - #include "osi/include/allocator.h" -#include "osi/include/fixed_queue.h" #include "osi/include/future.h" #include "osi/include/osi.h" #include "osi/include/thread.h" @@ -49,7 +48,7 @@ static void test_queue_entry_free_cb(void* data) { test_queue_entry_free_counter++; } -class FixedQueueTest : public AllocationTestHarness {}; +class FixedQueueTest : public ::testing::Test {}; TEST_F(FixedQueueTest, test_fixed_queue_new_free) { fixed_queue_t* queue; diff --git a/system/osi/test/future_test.cc b/system/osi/test/future_test.cc index 5e787392775c004650326a8394188bf1662a58e3..8babd591b967126135016f3659cc2723b4b54df4 100644 --- a/system/osi/test/future_test.cc +++ b/system/osi/test/future_test.cc @@ -16,12 +16,11 @@ * ******************************************************************************/ -#include +#include "osi/include/future.h" -#include "AllocationTestHarness.h" +#include #include "common/message_loop_thread.h" -#include "osi/include/future.h" #include "osi/include/osi.h" using bluetooth::common::MessageLoopThread; @@ -30,7 +29,7 @@ static const char* pass_back_data0 = "fancy a sandwich? it's a fancy sandwich"; static const char* pass_back_data1 = "what kind of ice cream truck plays the worst christmas song of all time?"; -class FutureTest : public AllocationTestHarness {}; +class FutureTest : public ::testing::Test {}; static void post_to_future(void* context) { future_ready((future_t*)context, (void*)pass_back_data0); diff --git a/system/osi/test/fuzzers/alarm/Android.bp b/system/osi/test/fuzzers/alarm/Android.bp index 15a4710fe9bf215e7887ea6272159270c54b99be..4a409c03058c0d05fa2b12e205df922f1bbc5dd1 100644 --- a/system/osi/test/fuzzers/alarm/Android.bp +++ b/system/osi/test/fuzzers/alarm/Android.bp @@ -15,17 +15,20 @@ cc_fuzz { "fuzz_alarm.cc", ], shared_libs: [ - "libcrypto", "libcutils", "liblog", "libprotobuf-cpp-lite", + "libstatssocket", ], static_libs: [ "libbt-common", - "libbt-protos-lite", "libchrome", "libgmock", "libosi", ], - cflags: ["-Wno-unused-function"], + cflags: [ + "-Wno-unused-function", + "-Wno-unused-parameter", + ], + header_libs: ["libbluetooth_headers"], } diff --git a/system/osi/test/fuzzers/alarm/fuzz_alarm.cc b/system/osi/test/fuzzers/alarm/fuzz_alarm.cc index 126078ded39b30a1d94b5c6566d089bd8ea4f633..de3054e6f527d580f3e14a00142e355abd2c6404 100644 --- a/system/osi/test/fuzzers/alarm/fuzz_alarm.cc +++ b/system/osi/test/fuzzers/alarm/fuzz_alarm.cc @@ -135,6 +135,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { // Alarm must be non-null, or set() will trigger assert if (alarm) { if (!fuzz_set_alarm(alarm, MAX_ALARM_DURATION, cb, &dataProvider)) { + alarm_free(alarm); return 0; } alarm_cancel(alarm); @@ -150,8 +151,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { for (int i = 0; i < num_alarms; i++) { uint64_t interval = dataProvider.ConsumeIntegralInRange(0, MAX_ALARM_DURATION); - if (fuzz_set_alarm(alarm, interval, cb, &dataProvider)) { - return 0; + if (!fuzz_set_alarm(alarm, interval, cb, &dataProvider)) { + num_alarms = i; + break; } alarm_get_remaining_ms(alarm); } diff --git a/system/osi/test/fuzzers/allocation_tracker/Android.bp b/system/osi/test/fuzzers/allocation_tracker/Android.bp deleted file mode 100644 index 3e36a071924610836715da643efac57fc1437155..0000000000000000000000000000000000000000 --- a/system/osi/test/fuzzers/allocation_tracker/Android.bp +++ /dev/null @@ -1,27 +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_fuzz { - name: "libosi_fuzz_allocation_tracker", - defaults: ["libosi_fuzz_defaults"], - host_supported: true, - srcs: [ - "fuzz_allocation_tracker.cc", - ], - shared_libs: [ - "liblog", - ], - static_libs: [ - "libchrome", - "libosi", - ], - corpus: [ - "corpus/checkfail-regression-156805580", - ], -} diff --git a/system/osi/test/fuzzers/allocation_tracker/corpus/checkfail-regression-156805580 b/system/osi/test/fuzzers/allocation_tracker/corpus/checkfail-regression-156805580 deleted file mode 100644 index 044c5b0f57eba8a8fa23ffc6820b0a574a019365..0000000000000000000000000000000000000000 --- a/system/osi/test/fuzzers/allocation_tracker/corpus/checkfail-regression-156805580 +++ /dev/null @@ -1 +0,0 @@ -þÿÿÿÿ¸ diff --git a/system/osi/test/fuzzers/allocation_tracker/fuzz_allocation_tracker.cc b/system/osi/test/fuzzers/allocation_tracker/fuzz_allocation_tracker.cc deleted file mode 100644 index 966e87cc5f31973040f1b30d980c01b3b4d53798..0000000000000000000000000000000000000000 --- a/system/osi/test/fuzzers/allocation_tracker/fuzz_allocation_tracker.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "osi/include/allocation_tracker.h" - -#define MAX_NUM_FUNCTIONS 512 -#define MAX_BUF_SIZE 256 - -// Add a tracker_initialized bool to track if we initialized or not -// (This is to handle a call to allocation_tracker_notify_alloc immediately -// returning the provided pointer if the allocator is not ready, and -// notify_free on the same ptr failing as the allocator did not -// track that allocation) -bool tracker_initialized = false; - -struct alloc_struct { - allocator_id_t alloc_id; - void* ptr; -}; - -void freeAllocationVector(std::vector* alloc_vector) { - // Free our allocated buffers - for (const auto& alloc : *alloc_vector) { - void* real_ptr = allocation_tracker_notify_free(alloc.alloc_id, alloc.ptr); - if (real_ptr) { - free(real_ptr); - } - } - alloc_vector->clear(); -} - -void callArbitraryFunction(std::vector* alloc_vector, - FuzzedDataProvider* dataProvider) { - // Get our function identifier - switch (dataProvider->ConsumeIntegralInRange(0, 6)) { - // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer - // (This will likely bias whatever action is here to run more often) - case 0: - return; - // Init - case 1: - allocation_tracker_init(); - tracker_initialized = true; - return; - case 2: - // NOTE: This will print to stderr if allocations exist. May clutter logs - allocation_tracker_expect_no_allocations(); - return; - case 3: { - alloc_struct alloc; - // Determine allocator ID & buffer size (without canaries) - alloc.alloc_id = dataProvider->ConsumeIntegral(); - size_t size = - dataProvider->ConsumeIntegralInRange(1, MAX_BUF_SIZE); - if (size == 0) { - return; - } - // Get our size with canaries & allocate - size_t real_size = allocation_tracker_resize_for_canary(size); - void* tmp_ptr = malloc(real_size); - if (tmp_ptr == nullptr) { - return; - } - alloc.ptr = - allocation_tracker_notify_alloc(alloc.alloc_id, tmp_ptr, size); - // Put our id/ptr pair in our tracking vector to be freed later - if (tracker_initialized && alloc.ptr) { - alloc_vector->push_back(alloc); - } else { - free(tmp_ptr); - } - } - return; - case 4: { - // Grab a ptr from our tracking vector & free it - if (!alloc_vector->empty()) { - size_t index = dataProvider->ConsumeIntegralInRange( - 0, alloc_vector->size() - 1); - alloc_struct alloc = alloc_vector->at(index); - void* real_ptr = - allocation_tracker_notify_free(alloc.alloc_id, alloc.ptr); - if (real_ptr) { - free(real_ptr); - } - alloc_vector->erase(alloc_vector->begin() + index); - } - } - return; - case 5: { - size_t size = - dataProvider->ConsumeIntegralInRange(0, MAX_BUF_SIZE); - allocation_tracker_resize_for_canary(size); - } - return; - // Reset - // NOTE: Should this be exempted from fuzzing? Header says to not call this, - // but it's still exposed. It also doesn't perform a full reset. - case 6: - // Have to actually free the mem first as reset doesn't do it - freeAllocationVector(alloc_vector); - allocation_tracker_reset(); - return; - default: - return; - } -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { - // Init our wrapper - FuzzedDataProvider dataProvider(Data, Size); - - // Keep a vector of our allocated pointers - std::vector alloc_vector; - - // How many functions are we going to call? - size_t num_functions = - dataProvider.ConsumeIntegralInRange(0, MAX_NUM_FUNCTIONS); - for (size_t i = 0; i < num_functions; i++) { - callArbitraryFunction(&alloc_vector, &dataProvider); - } - - // Free anything we've allocated over the course of the fuzzer loop - freeAllocationVector(&alloc_vector); - - // Reset our tracker for the next run - allocation_tracker_reset(); - return 0; -} diff --git a/system/osi/test/fuzzers/array/fuzz_array.cc b/system/osi/test/fuzzers/array/fuzz_array.cc deleted file mode 100644 index eeabf952d50710d632aebbb6c08ffbd9fe0da52b..0000000000000000000000000000000000000000 --- a/system/osi/test/fuzzers/array/fuzz_array.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "osi/include/array.h" - -// Capping the element size at sizeof(uint32_t)+1 -// because it looks like there's a buffer overread -#define MAX_ELEMENT_SIZE sizeof(uint32_t) -#define MAX_ARRAY_LEN 1024 - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { - // Init our wrapper - FuzzedDataProvider dataProvider(Data, Size); - - // Attempt to init an array - size_t element_size = - dataProvider.ConsumeIntegralInRange(1, MAX_ELEMENT_SIZE); - array_t* arr = array_new(element_size); - - // Functions can only be called on a non-null array_t, according to the .h - if (arr != nullptr) { - // How large do we want our array? - size_t arr_len = - dataProvider.ConsumeIntegralInRange(0, MAX_ARRAY_LEN); - if (arr_len > 0) { - for (size_t i = 0; i < arr_len; i++) { - uint32_t new_val = dataProvider.ConsumeIntegral(); - // append_value() just derefs and calls append_ptr(), - // so no need to fuzz separately - array_append_value(arr, new_val); - } - - // Pull the ptr to an element in the array - size_t get_index = - dataProvider.ConsumeIntegralInRange(0, array_length(arr) - 1); - array_at(arr, get_index); - - // Grab the array pointer - array_ptr(arr); - } - } - - // Free the array (this can be performed on a nullptr) - array_free(arr); - - return 0; -} diff --git a/system/osi/test/fuzzers/buffer/Android.bp b/system/osi/test/fuzzers/buffer/Android.bp deleted file mode 100644 index 568fa42a5d4d11550b71ff9572d01bec4c4408cb..0000000000000000000000000000000000000000 --- a/system/osi/test/fuzzers/buffer/Android.bp +++ /dev/null @@ -1,24 +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_fuzz { - name: "libosi_fuzz_buffer", - defaults: ["libosi_fuzz_defaults"], - host_supported: true, - srcs: [ - "fuzz_buffer.cc", - ], - shared_libs: [ - "liblog", - ], - static_libs: [ - "libchrome", - "libosi", - ], -} diff --git a/system/osi/test/fuzzers/buffer/fuzz_buffer.cc b/system/osi/test/fuzzers/buffer/fuzz_buffer.cc deleted file mode 100644 index b781a3171ce3a1b4984ae21a0ee6b64ce729c612..0000000000000000000000000000000000000000 --- a/system/osi/test/fuzzers/buffer/fuzz_buffer.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "osi/include/buffer.h" - -#define MAX_BUFFER_SIZE 4096 -#define MAX_NUM_SLICES 100 - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { - // Init our wrapper - FuzzedDataProvider dataProvider(Data, Size); - - // Create our buffer - size_t buf_size = - dataProvider.ConsumeIntegralInRange(1, MAX_BUFFER_SIZE); - buffer_t* buf = buffer_new(buf_size); - - // These functions require a non-null buffer, according to the header - // The size also needs to be over 1 to make slices - if (buf != nullptr && buf_size > 1) { - std::vector slices; - - // Make a bunch of refs to various slices of the buffer - size_t num_slices = - dataProvider.ConsumeIntegralInRange(0, MAX_NUM_SLICES); - for (size_t i = 0; i < num_slices; i++) { - // If slice_size is zero or GT buf_size, lib throws an exception - size_t slice_size = - dataProvider.ConsumeIntegralInRange(1, buf_size - 1); - if (slice_size > 0) { - buffer_t* new_slice = nullptr; - if (slice_size == buf_size) { - new_slice = buffer_new_ref(buf); - } else { - new_slice = buffer_new_slice(buf, slice_size); - } - - // Add the slice to our vector so we can free it later - slices.push_back(new_slice); - } - } - - // Retrieve the buffer ptr - buffer_ptr(buf); - - // Free the slices - for (const auto& slice : slices) { - buffer_free(slice); - } - } - - // Free the root buffer - buffer_free(buf); - - return 0; -} diff --git a/system/osi/test/fuzzers/compat/Android.bp b/system/osi/test/fuzzers/compat/Android.bp index 50a680a49251031d9551ec3adaf80630adedea7b..b462b1aed24c930ea98b4f6911741b16301b519f 100644 --- a/system/osi/test/fuzzers/compat/Android.bp +++ b/system/osi/test/fuzzers/compat/Android.bp @@ -21,4 +21,5 @@ cc_fuzz { static_libs: [ "libosi", ], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/osi/test/fuzzers/fixed_queue/Android.bp b/system/osi/test/fuzzers/fixed_queue/Android.bp index 60846b017bc83c294f12021c56e422b766bde99e..10cc65658c3bfd472844035e8ca096d47d5939db 100644 --- a/system/osi/test/fuzzers/fixed_queue/Android.bp +++ b/system/osi/test/fuzzers/fixed_queue/Android.bp @@ -22,4 +22,5 @@ cc_fuzz { "libchrome", "libosi", ], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/osi/test/fuzzers/list/Android.bp b/system/osi/test/fuzzers/list/Android.bp index b3b46449393dbbb40f0601445a69b76cd0ca60c2..ff867651738dd9adbceaddb5f08476c8e6bdc7c5 100644 --- a/system/osi/test/fuzzers/list/Android.bp +++ b/system/osi/test/fuzzers/list/Android.bp @@ -19,4 +19,5 @@ cc_fuzz { "liblog", "libosi", ], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/osi/test/hash_map_utils_test.cc b/system/osi/test/hash_map_utils_test.cc index d5df2d774d6b5beb3f479eeb4f84f4c8634e8260..23241d438f70f4ea0814f6ffb4fc555217e43081 100644 --- a/system/osi/test/hash_map_utils_test.cc +++ b/system/osi/test/hash_map_utils_test.cc @@ -15,23 +15,17 @@ * limitations under the License. * ******************************************************************************/ -#include +#include "osi/include/hash_map_utils.h" #include -#include "AllocationTestHarness.h" - -#include "osi/include/hash_map_utils.h" +#include #include "osi/include/allocator.h" -class HashMapUtilsTest : public AllocationTestHarness { +class HashMapUtilsTest : public ::testing::Test { protected: - void SetUp() override { AllocationTestHarness::SetUp(); } - void TearDown() override { - map.clear(); - AllocationTestHarness::TearDown(); - } + void TearDown() override { map.clear(); } std::unordered_map map; }; diff --git a/system/osi/test/internal/semaphore_test.cc b/system/osi/test/internal/semaphore_test.cc index 41851811d2ddd4c3ca8d0815c8c1ca62f53f9cbe..a54d1e22f688665d32f96fd32fdeac280272b982 100644 --- a/system/osi/test/internal/semaphore_test.cc +++ b/system/osi/test/internal/semaphore_test.cc @@ -1,15 +1,13 @@ -#include - -#include "AllocationTestHarness.h" +#include "osi/semaphore.h" #include +#include #include #include #include "common/message_loop_thread.h" #include "osi/include/osi.h" #include "osi/include/reactor.h" -#include "osi/semaphore.h" using bluetooth::common::MessageLoopThread; @@ -30,7 +28,7 @@ void sleep_then_increment_counter(void* context) { } } // namespace -class SemaphoreTest : public AllocationTestHarness {}; +class SemaphoreTest : public ::testing::Test {}; TEST_F(SemaphoreTest, test_new_simple) { semaphore_t* semaphore = semaphore_new(0); diff --git a/system/osi/test/list_test.cc b/system/osi/test/list_test.cc index d5a438f485efb0ae722da3192cfc309fe9f15ddb..dfea6a0eb51b5b14030f9626551ae78b90c46257 100644 --- a/system/osi/test/list_test.cc +++ b/system/osi/test/list_test.cc @@ -1,13 +1,11 @@ -#include +#include "osi/include/list.h" #include +#include -#include "AllocationTestHarness.h" - -#include "osi/include/list.h" #include "osi/include/osi.h" -class ListTest : public AllocationTestHarness {}; +class ListTest : public ::testing::Test {}; TEST_F(ListTest, test_new_free_simple) { list_t* list = list_new(NULL); diff --git a/system/osi/test/properties_test.cc b/system/osi/test/properties_test.cc index b295a1d8036a48478e0bf581ee4b96d2397339a1..20ebbcd1c5a63341bbe9108416bcceaed131169e 100644 --- a/system/osi/test/properties_test.cc +++ b/system/osi/test/properties_test.cc @@ -16,13 +16,11 @@ * ******************************************************************************/ -#include - -#include "AllocationTestHarness.h" - #include "osi/include/properties.h" -class PropertiesTest : public AllocationTestHarness {}; +#include + +class PropertiesTest : public ::testing::Test {}; TEST_F(PropertiesTest, test_default_value) { char value[PROPERTY_VALUE_MAX] = {0}; diff --git a/system/osi/test/rand_test.cc b/system/osi/test/rand_test.cc index 720617b6bf8c34bcd30d3ed79fcf37435aa8f588..2dea819bd2865847d36bc98e12b725fb73bdac0b 100644 --- a/system/osi/test/rand_test.cc +++ b/system/osi/test/rand_test.cc @@ -1,10 +1,8 @@ #include -#include "AllocationTestHarness.h" - #include "osi/include/osi.h" -class RandTest : public AllocationTestHarness {}; +class RandTest : public ::testing::Test {}; TEST_F(RandTest, test_rand) { // We can't guarantee any distribution diff --git a/system/osi/test/reactor_test.cc b/system/osi/test/reactor_test.cc index 016422732d51a5a7495125bbb297ef6bae391ae7..7bee086d862ab7892f4401b789fa19a086089ad9 100644 --- a/system/osi/test/reactor_test.cc +++ b/system/osi/test/reactor_test.cc @@ -1,14 +1,12 @@ +#include "osi/include/reactor.h" + #include #include #include #include #include -#include "AllocationTestHarness.h" - -#include "osi/include/reactor.h" - -class ReactorTest : public AllocationTestHarness {}; +class ReactorTest : public ::testing::Test {}; static pthread_t thread; static volatile bool thread_running; diff --git a/system/osi/test/stack_power_telemetry_test.cc b/system/osi/test/stack_power_telemetry_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..8c0a83a27afb858f81e309361be07203e500234e --- /dev/null +++ b/system/osi/test/stack_power_telemetry_test.cc @@ -0,0 +1,363 @@ +#include "osi/include/stack_power_telemetry.h" + +#include + +#include "osi/src/stack_power_telemetry.cc" +#include "types/raw_address.h" + +class PowerTelemetryTest : public ::testing::Test { + protected: + uint16_t handle = 123; + RawAddress bdaddr; + bool isConnected = true; + + void reset() { + power_telemetry::GetInstance().pimpl_->LogDataTransfer(); + power_telemetry::GetInstance().pimpl_->idx_containers = 0; + for (int i = 0; i < kLogEntriesSize; i++) { + power_telemetry::GetInstance().pimpl_->log_data_containers_[i] = + LogDataContainer(); + } + } + + void SetUp() override { + // Enable the feature flag + power_telemerty_enabled_ = true; + RawAddress::FromString("00:00:00:00:00:00", bdaddr); + } +}; + +TEST_F(PowerTelemetryTest, test_getCurrentLogDataContainer) { + reset(); + + // Record smth, log index move to 1 + power_telemetry::GetInstance().pimpl_->RecordLogDataContainer(); + ASSERT_EQ(1, power_telemetry::GetInstance().pimpl_->idx_containers); +} + +TEST_F(PowerTelemetryTest, test_recordLogDataContainer) { + reset(); + + // Create maximum number of nodes + for (int i = 0; i < kLogEntriesSize - 1; i++) { + power_telemetry::GetInstance().pimpl_->RecordLogDataContainer(); + ASSERT_EQ(i + 1, power_telemetry::GetInstance().pimpl_->idx_containers); + } + + // Create 1 more node. index integer should be 0 + power_telemetry::GetInstance().pimpl_->RecordLogDataContainer(); + ASSERT_EQ(0, power_telemetry::GetInstance().pimpl_->idx_containers); +} + +TEST_F(PowerTelemetryTest, test_LogInqScanDetails) { + reset(); + + power_telemetry::GetInstance().LogInqScanStopped(); + ASSERT_EQ(0, power_telemetry::GetInstance().pimpl_->inq_scan.count_); + + power_telemetry::GetInstance().LogInqScanStarted(); + ASSERT_EQ(1, power_telemetry::GetInstance().pimpl_->inq_scan.count_); +} + +TEST_F(PowerTelemetryTest, test_LogBleScan) { + reset(); + + power_telemetry::GetInstance().LogBleScan(10); + ASSERT_EQ(10, (int)power_telemetry::GetInstance().pimpl_->ble_scan.count_); +} + +TEST_F(PowerTelemetryTest, test_LogBleAdvDetails) { + reset(); + + LogDataContainer& ldc = + power_telemetry::GetInstance().pimpl_->GetCurrentLogDataContainer(); + + // Failed Case. Shouldn't crash if run false first + power_telemetry::GetInstance().LogBleAdvStopped(); + ASSERT_EQ(0, (int)ldc.adv_list.size()); + + // Add new BleAdv data + power_telemetry::GetInstance().LogBleAdvStarted(); + ASSERT_EQ(1, (int)ldc.adv_list.size()); + ASSERT_NE(0, ldc.adv_list.back().active.begin); + + // BleAdv data update endTime + power_telemetry::GetInstance().LogBleAdvStopped(); + ASSERT_EQ(1, (int)ldc.adv_list.size()); + ASSERT_NE(0, ldc.adv_list.back().active.end); + + // Add new BleAdv data + power_telemetry::GetInstance().LogBleAdvStarted(); + ASSERT_EQ(2, (int)ldc.adv_list.size()); +} + +TEST_F(PowerTelemetryTest, test_LogTxPower) { + reset(); + + LogDataContainer& ldc = + power_telemetry::GetInstance().pimpl_->GetCurrentLogDataContainer(); + tBTM_TX_POWER_RESULT dummy_res; + dummy_res.rem_bda = bdaddr; + + // Failed Case. Shouldn't crash if no init data + dummy_res.status = BTM_SUCCESS; + void* p = &dummy_res; + power_telemetry::GetInstance().LogTxPower(p); + + // init data + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + true); + + // Successful case + dummy_res.tx_power = 100; + power_telemetry::GetInstance().LogTxPower(p); + ASSERT_EQ(dummy_res.tx_power, + ldc.acl.link_details_map[handle].tx_power_level); + + // Failed case + dummy_res.tx_power = 99; + dummy_res.status = BTM_UNDEFINED; + power_telemetry::GetInstance().LogTxPower(p); + ASSERT_NE(dummy_res.tx_power, + ldc.acl.link_details_map[handle].tx_power_level); +} + +TEST_F(PowerTelemetryTest, test_LogAclLinkDetails) { + reset(); + LogDataContainer& ldc = + power_telemetry::GetInstance().pimpl_->GetCurrentLogDataContainer(); + + // Failed Case. Shouldn't crash if first invoke function with false + isConnected = false; + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + true); + ASSERT_EQ(0, (int)ldc.acl.link_details_list.size()); + + // Successful case + isConnected = true; + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + true); + ASSERT_EQ(1, (int)ldc.acl.link_details_map.count(handle)); + ASSERT_EQ(0, (int)ldc.acl.link_details_list.size()); + ASSERT_EQ(1, (int)ldc.sniff_activity_map.count(handle)); + + isConnected = false; + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + true); + ASSERT_EQ(0, (int)ldc.acl.link_details_map.count(handle)); + ASSERT_EQ(1, (int)ldc.acl.link_details_list.size()); +} + +TEST_F(PowerTelemetryTest, test_LogScoLinkDetails) { + reset(); + LogDataContainer& ldc = + power_telemetry::GetInstance().pimpl_->GetCurrentLogDataContainer(); + + // Failed Case. Shouldn't crash if first invoke function with false + isConnected = false; + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + false); + ASSERT_EQ(0, (int)ldc.sco.link_details_list.size()); + + // Successful case + isConnected = true; + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + false); + ASSERT_EQ(1, (int)ldc.sco.link_details_map.count(handle)); + ASSERT_EQ(0, (int)ldc.sco.link_details_list.size()); + + isConnected = false; + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + false); + ASSERT_EQ(0, (int)ldc.sco.link_details_map.count(handle)); + ASSERT_EQ(1, (int)ldc.sco.link_details_list.size()); +} + +TEST_F(PowerTelemetryTest, test_LogHciCmdEvtDetails) { + reset(); + + // After log hci_cmd, the number of it should be 1 + power_telemetry::GetInstance().LogHciCmdDetail(); + ASSERT_EQ(1, (int)power_telemetry::GetInstance().pimpl_->cmd.count_); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->event.count_); + + // After log hci_evt, the number of it should be 1 + power_telemetry::GetInstance().LogHciEvtDetail(); + ASSERT_EQ(1, (int)power_telemetry::GetInstance().pimpl_->cmd.count_); + ASSERT_EQ(1, (int)power_telemetry::GetInstance().pimpl_->event.count_); +} + +TEST_F(PowerTelemetryTest, test_LogSniffActivity) { + reset(); + LogDataContainer& ldc = + power_telemetry::GetInstance().pimpl_->GetCurrentLogDataContainer(); + + power_telemetry::GetInstance().LogSniffStarted(handle, bdaddr); + ASSERT_EQ(1, (int)ldc.sniff_activity_map[handle].sniff_count); + ASSERT_EQ(0, (int)ldc.sniff_activity_map[handle].active_count); + + power_telemetry::GetInstance().LogSniffStopped(handle, bdaddr); + ASSERT_EQ(1, (int)ldc.sniff_activity_map[handle].sniff_count); + ASSERT_EQ(1, (int)ldc.sniff_activity_map[handle].active_count); +} + +TEST_F(PowerTelemetryTest, test_LogDataTransfer) { + reset(); + + // We should create new record. index should be 1 + power_telemetry::GetInstance().pimpl_->LogDataTransfer(); + ASSERT_EQ(1, (int)power_telemetry::GetInstance().pimpl_->idx_containers); +} + +TEST_F(PowerTelemetryTest, test_LogScanStarted) { + reset(); + + power_telemetry::GetInstance().LogScanStarted(); + ASSERT_EQ(1, (int)power_telemetry::GetInstance().pimpl_->scan.count_); +} + +TEST_F(PowerTelemetryTest, test_LogAclPktDetails) { + reset(); + + // scanCount should be 1 + power_telemetry::GetInstance().LogTxAclPktData(10); + ASSERT_EQ(1, (int)power_telemetry::GetInstance().pimpl_->tx.pkt_); + ASSERT_EQ(10, (int)power_telemetry::GetInstance().pimpl_->tx.len_); + + power_telemetry::GetInstance().LogRxAclPktData(11); + ASSERT_EQ(1, (int)power_telemetry::GetInstance().pimpl_->rx.pkt_); + ASSERT_EQ(11, (int)power_telemetry::GetInstance().pimpl_->rx.len_); +} + +TEST_F(PowerTelemetryTest, test_LogChannelConnected) { + reset(); + LogDataContainer& ldc = + power_telemetry::GetInstance().pimpl_->GetCurrentLogDataContainer(); + + power_telemetry::GetInstance().LogChannelConnected(BT_PSM_RFCOMM, 0, 0, + bdaddr); + ASSERT_EQ(1, (int)ldc.channel_map[bdaddr].size()); + ASSERT_EQ(State::kConnected, ldc.channel_map[bdaddr].back().state); + + power_telemetry::GetInstance().LogChannelConnected(BT_PSM_RFCOMM, 0, 0, + bdaddr); + ASSERT_EQ(2, (int)ldc.channel_map[bdaddr].size()); + ASSERT_EQ(State::kConnected, ldc.channel_map[bdaddr].back().state); +} + +TEST_F(PowerTelemetryTest, test_LogChannelDisconnected) { + reset(); + LogDataContainer& ldc = + power_telemetry::GetInstance().pimpl_->GetCurrentLogDataContainer(); + + power_telemetry::GetInstance().LogChannelConnected(0, 0, 0, bdaddr); + power_telemetry::GetInstance().LogChannelDisconnected(0, 0, 0, bdaddr); + ASSERT_EQ(State::kDisconnected, ldc.channel_map[bdaddr].back().state); + + RawAddress dummyAddr; + RawAddress::FromString("00:00:00:00:00:11", dummyAddr); + power_telemetry::GetInstance().LogChannelDisconnected(0, 0, 0, bdaddr); + ASSERT_EQ(1, (int)ldc.channel_map[bdaddr].size()); +} + +TEST_F(PowerTelemetryTest, test_LogTxBytes) { + reset(); + + power_telemetry::GetInstance().LogTxBytes(BT_PSM_RFCOMM, 0, 0, bdaddr, 10); + ASSERT_EQ(10, (int)power_telemetry::GetInstance().pimpl_->rfc.tx.bytes_); + + power_telemetry::GetInstance().LogTxBytes(0, 0, 0, bdaddr, 11); + ASSERT_EQ(11, (int)power_telemetry::GetInstance().pimpl_->l2c.tx.bytes_); +} + +TEST_F(PowerTelemetryTest, test_LogRxBytes) { + reset(); + + power_telemetry::GetInstance().LogRxBytes(BT_PSM_RFCOMM, 0, 0, bdaddr, 10); + ASSERT_EQ(10, (int)power_telemetry::GetInstance().pimpl_->rfc.rx.bytes_); + + power_telemetry::GetInstance().LogRxBytes(0, 0, 0, bdaddr, 11); + ASSERT_EQ(11, (int)power_telemetry::GetInstance().pimpl_->l2c.rx.bytes_); +} + +TEST_F(PowerTelemetryTest, test_feature_flag) { + reset(); + + // init data + isConnected = true; + LogDataContainer& ldc = + power_telemetry::GetInstance().pimpl_->GetCurrentLogDataContainer(); + tBTM_TX_POWER_RESULT dummy_res; + dummy_res.rem_bda = bdaddr; + dummy_res.status = BTM_SUCCESS; + void* p = &dummy_res; + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + true); + + // Set feature flag to false + // All function shouldn't work if flag is false + power_telemerty_enabled_ = false; + + power_telemetry::GetInstance().Dumpsys(0); + ASSERT_EQ(0, power_telemetry::GetInstance().pimpl_->idx_containers); + + power_telemetry::GetInstance().LogRxBytes(BT_PSM_RFCOMM, 0, 0, bdaddr, 87); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->rfc.rx.bytes_); + + power_telemetry::GetInstance().LogTxBytes(BT_PSM_RFCOMM, 0, 0, bdaddr, 10); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->rfc.tx.bytes_); + + power_telemetry::GetInstance().LogChannelConnected(0, 0, 0, bdaddr); + ASSERT_EQ(0, (int)ldc.channel_map.count(bdaddr)); + + power_telemetry::GetInstance().LogChannelDisconnected(0, 0, 0, bdaddr); + ASSERT_EQ(0, (int)ldc.channel_map.count(bdaddr)); + + power_telemetry::GetInstance().LogTxAclPktData(10); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->tx.pkt_); + + power_telemetry::GetInstance().LogRxAclPktData(11); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->rx.pkt_); + + power_telemetry::GetInstance().LogScanStarted(); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->scan.count_); + + power_telemetry::GetInstance().pimpl_->LogDataTransfer(); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->idx_containers); + + power_telemetry::GetInstance().LogSniffStarted(handle, bdaddr); + ASSERT_EQ(0, (int)ldc.sniff_activity_map[handle].sniff_count); + + power_telemetry::GetInstance().LogHciCmdDetail(); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->cmd.count_); + + power_telemetry::GetInstance().LogHciEvtDetail(); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->event.count_); + + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + false); + ASSERT_EQ(0, (int)ldc.sco.link_details_map.count(handle)); + + // Set to 1 because of fake data + power_telemetry::GetInstance().LogLinkDetails(handle, bdaddr, isConnected, + true); + ASSERT_EQ(1, (int)ldc.acl.link_details_map.count(handle)); + + dummy_res.tx_power = 100; + power_telemetry::GetInstance().LogTxPower(p); + ASSERT_EQ(0, ldc.acl.link_details_map[handle].tx_power_level); + + power_telemetry::GetInstance().LogBleScan(10); + ASSERT_EQ(0, (int)power_telemetry::GetInstance().pimpl_->ble_scan.count_); + + power_telemetry::GetInstance().LogBleAdvStarted(); + ASSERT_EQ(0, (int)ldc.adv_list.size()); + + power_telemetry::GetInstance().LogInqScanStarted(); + ASSERT_EQ(0, power_telemetry::GetInstance().pimpl_->inq_scan.count_); + + power_telemetry::GetInstance().pimpl_->RecordLogDataContainer(); + ASSERT_EQ(0, power_telemetry::GetInstance().pimpl_->idx_containers); + + power_telemerty_enabled_ = true; +} diff --git a/system/osi/test/thread_test.cc b/system/osi/test/thread_test.cc index debf250d8fd23206a18251d1033b3178dbb4c6a4..9fe4b7474a73e0161e6ccb1a11bc1f6a15a5be9c 100644 --- a/system/osi/test/thread_test.cc +++ b/system/osi/test/thread_test.cc @@ -1,14 +1,12 @@ -#include - -#include "AllocationTestHarness.h" +#include "osi/include/thread.h" +#include #include #include "osi/include/osi.h" #include "osi/include/reactor.h" -#include "osi/include/thread.h" -class ThreadTest : public AllocationTestHarness {}; +class ThreadTest : public ::testing::Test {}; TEST_F(ThreadTest, test_new_simple) { thread_t* thread = thread_new("test_thread"); diff --git a/system/osi/test/wakelock_test.cc b/system/osi/test/wakelock_test.cc index 02e50283b4ee754f3ae7d51550927596e83dfcf1..25fa4ce429ce6a5ca007dddeb502dc21b492912a 100644 --- a/system/osi/test/wakelock_test.cc +++ b/system/osi/test/wakelock_test.cc @@ -26,8 +26,6 @@ #include "osi/include/wakelock.h" -#include "AllocationTestHarness.h" - static bool is_wake_lock_acquired = false; static int acquire_wake_lock_cb(const char* lock_name) { @@ -41,13 +39,11 @@ static int release_wake_lock_cb(const char* lock_name) { } static bt_os_callouts_t bt_wakelock_callouts = { - sizeof(bt_os_callouts_t), NULL, acquire_wake_lock_cb, release_wake_lock_cb}; + sizeof(bt_os_callouts_t), acquire_wake_lock_cb, release_wake_lock_cb}; -class WakelockTest : public AllocationTestHarness { +class WakelockTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); - // TODO (jamuraa): maybe use base::CreateNewTempDirectory instead? #ifdef __ANDROID__ tmp_dir_ = "/data/local/tmp/btwlXXXXXX"; @@ -84,8 +80,6 @@ class WakelockTest : public AllocationTestHarness { close(lock_path_fd); close(unlock_path_fd); - - AllocationTestHarness::TearDown(); } // diff --git a/system/packet/Android.bp b/system/packet/Android.bp index 26c69424fa80ecd50b7cb4b0e412e7001f19d416..6fa932d7b74ce2773cc4123901b0eb423c87cb8e 100644 --- a/system/packet/Android.bp +++ b/system/packet/Android.bp @@ -9,7 +9,7 @@ package { cc_library_static { name: "lib-bt-packets", - defaults: ["libchrome_support_defaults"], + defaults: ["bluetooth_cflags"], host_supported: true, export_include_dirs: [ "./", @@ -28,11 +28,10 @@ cc_library_static { cc_test { name: "net_test_btpackets", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, @@ -40,6 +39,7 @@ cc_test { local_include_dirs: ["tests"], include_dirs: [ "packages/modules/Bluetooth/system/", + "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/include", ], srcs: [ @@ -72,7 +72,7 @@ cc_test { shared_libs: [ "libbase", "libbinder_ndk", - "libcrypto", + "liblog", ], static_libs: [ "lib-bt-packets", @@ -83,6 +83,7 @@ cc_test { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], target: { android: { diff --git a/system/packet/avrcp/Android.bp b/system/packet/avrcp/Android.bp index 63de109539da9f463e2396512fb3b9b9db87bc9d..4e3190811ea64e0fc6ab220777789f28e2f50a36 100644 --- a/system/packet/avrcp/Android.bp +++ b/system/packet/avrcp/Android.bp @@ -9,13 +9,14 @@ package { cc_library_static { name: "lib-bt-packets-avrcp", - defaults: ["libchrome_support_defaults"], + defaults: ["bluetooth_cflags"], header_libs: ["avrcp_headers"], export_header_lib_headers: ["avrcp_headers"], export_include_dirs: ["."], host_supported: true, include_dirs: [ "packages/modules/Bluetooth/system/", + "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/include", ], srcs: [ @@ -44,6 +45,7 @@ cc_library_static { ], static_libs: [ "lib-bt-packets-base", + "libchrome", ], apex_available: [ "com.android.btservices", diff --git a/system/packet/base/Android.bp b/system/packet/base/Android.bp index 114af2cd23715cec772c32964d4e44fd33fbb461..cb255c28b157e936e003a98d789e1b44d0bdbb0c 100644 --- a/system/packet/base/Android.bp +++ b/system/packet/base/Android.bp @@ -9,7 +9,7 @@ package { cc_library_static { name: "lib-bt-packets-base", - defaults: ["libchrome_support_defaults"], + defaults: ["bluetooth_cflags"], export_include_dirs: ["./"], host_supported: true, include_dirs: ["packages/modules/Bluetooth/system/include"], @@ -22,4 +22,5 @@ cc_library_static { "com.android.btservices", ], min_sdk_version: "30", + static_libs: ["libchrome"], } diff --git a/system/packet/tests/fuzzers/Android.bp b/system/packet/tests/fuzzers/Android.bp index ef196019eb1a37835d5b02b4d0e43b401d321cf9..ed273405415b5d4bd3803cc3de4910234991913c 100644 --- a/system/packet/tests/fuzzers/Android.bp +++ b/system/packet/tests/fuzzers/Android.bp @@ -14,6 +14,7 @@ cc_fuzz { 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", @@ -36,7 +37,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -46,6 +49,7 @@ cc_fuzz { 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", @@ -69,7 +73,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -79,6 +85,7 @@ cc_fuzz { 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", @@ -102,7 +109,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -112,6 +121,7 @@ cc_fuzz { 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", @@ -135,7 +145,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -145,6 +157,7 @@ cc_fuzz { 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", @@ -168,7 +181,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -178,6 +193,7 @@ cc_fuzz { 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", @@ -201,7 +217,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -211,6 +229,7 @@ cc_fuzz { 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", @@ -234,7 +253,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -244,6 +265,7 @@ cc_fuzz { 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", @@ -267,7 +289,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -277,6 +301,7 @@ cc_fuzz { 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", @@ -300,7 +325,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -310,6 +337,7 @@ cc_fuzz { 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", @@ -333,7 +361,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -343,6 +373,7 @@ cc_fuzz { 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", @@ -366,7 +397,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -376,6 +409,7 @@ cc_fuzz { 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", @@ -399,7 +433,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -409,6 +445,7 @@ cc_fuzz { 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", @@ -432,7 +469,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -442,6 +481,7 @@ cc_fuzz { 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", @@ -465,7 +505,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -475,6 +517,7 @@ cc_fuzz { 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", @@ -498,7 +541,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -508,6 +553,7 @@ cc_fuzz { 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", @@ -531,7 +577,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -541,6 +589,7 @@ cc_fuzz { 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", @@ -564,7 +613,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -574,6 +625,7 @@ cc_fuzz { 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", @@ -597,7 +649,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -607,6 +661,7 @@ cc_fuzz { 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", @@ -630,7 +685,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -640,6 +697,7 @@ cc_fuzz { 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", @@ -663,7 +721,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -673,6 +733,7 @@ cc_fuzz { 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", @@ -696,7 +757,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -706,6 +769,7 @@ cc_fuzz { 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", @@ -729,7 +793,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -739,6 +805,7 @@ cc_fuzz { 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", @@ -762,7 +829,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -772,6 +841,7 @@ cc_fuzz { 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", @@ -795,7 +865,9 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } cc_fuzz { @@ -805,6 +877,7 @@ cc_fuzz { 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", @@ -828,5 +901,7 @@ cc_fuzz { ], cflags: [ "-DBUILDCFG", + "-Wno-unused-parameter", ], + shared_libs: ["liblog"], } diff --git a/system/pdl/Android.bp b/system/pdl/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..c315c81182858fa02424e734a813bece86d3e886 --- /dev/null +++ b/system/pdl/Android.bp @@ -0,0 +1,31 @@ +genrule_defaults { + name: "BluetoothGeneratedPackets_default", + tools: ["bluetooth_packetgen"], + cmd: "$(location bluetooth_packetgen) --fuzzing --testing --include=packages/modules/Bluetooth/system/pdl --out=$(genDir) $(in)", + defaults_visibility: [":__subpackages__"], +} + +// TODO get rid of this by converting the l2cap cert tests (or deprecating them) +genrule { + name: "BluetoothGeneratedPackets_python3_cc", + tools: [ + "bluetooth_packetgen", + ], + cmd: "$(location bluetooth_packetgen) --include=packages/modules/Bluetooth/system/pdl --out=$(genDir) --num_shards=10 $(in)", + srcs: [ + "l2cap/l2cap_packets.pdl", + ], + out: [ + "l2cap/l2cap_packets_python3.cc", + "l2cap/l2cap_packets_python3_shard_0.cc", + "l2cap/l2cap_packets_python3_shard_1.cc", + "l2cap/l2cap_packets_python3_shard_2.cc", + "l2cap/l2cap_packets_python3_shard_3.cc", + "l2cap/l2cap_packets_python3_shard_4.cc", + "l2cap/l2cap_packets_python3_shard_5.cc", + "l2cap/l2cap_packets_python3_shard_6.cc", + "l2cap/l2cap_packets_python3_shard_7.cc", + "l2cap/l2cap_packets_python3_shard_8.cc", + "l2cap/l2cap_packets_python3_shard_9.cc", + ], +} diff --git a/system/pdl/BUILD.gn b/system/pdl/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ac6dca44e96da2ef56f4ee844eee3acf61fdd43c --- /dev/null +++ b/system/pdl/BUILD.gn @@ -0,0 +1,27 @@ +# +# Copyright 2023 Google, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//bt/system/gd/packet/parser/packetgen.gni") + +packetgen_headers("BluetoothGeneratedPackets_h") { + sources = [ + "hci/hci_packets.pdl", + "l2cap/l2cap_packets.pdl", + "security/smp_packets.pdl", + ] + + include = "system/pdl" + source_root = "../.." +} diff --git a/system/pdl/hci/Android.bp b/system/pdl/hci/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..25b1583848cefb95ee5b02d73acf557e10ff9e01 --- /dev/null +++ b/system/pdl/hci/Android.bp @@ -0,0 +1,78 @@ +genrule { + name: "BluetoothGeneratedPacketsHci_h", + defaults: ["BluetoothGeneratedPackets_default"], + srcs: ["hci_packets.pdl"], + out: ["hci/hci_packets.h"], + visibility: ["//visibility:private"], +} + +genrule { + name: "BluetoothGeneratedPackets_rust", + defaults: ["pdl_rust_generator_defaults"], + srcs: ["hci_packets.pdl"], + out: ["hci/hci_packets.rs"], +} + +cc_library_headers { + name: "libbluetooth_hci_pdl_header", + vendor_available: true, + export_include_dirs: [ + "include", + ], + generated_headers: [ + "BluetoothGeneratedPacketsHci_h", + ], + export_generated_headers: [ + "BluetoothGeneratedPacketsHci_h", + ], + host_supported: true, + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "33", +} + +cc_library_static { + name: "libbluetooth_hci_pdl", + vendor_available: true, + srcs: [ + "address.cc", + "class_of_device.cc", + ], + header_libs: [ + "libbluetooth_hci_pdl_header", + ], + export_header_lib_headers: [ + "libbluetooth_hci_pdl_header", + ], + // TODO remove this + // Directly add the common library + the os library as a dependency that export their header_libs + include_dirs: [ + "packages/modules/Bluetooth/system/gd", + ], + host_supported: true, + visibility: [ + "//hardware/interfaces/bluetooth/aidl/vts", + "//packages/modules/Bluetooth/system:__subpackages__", + "//vendor:__subpackages__", + ], + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "33", +} + +// Generate the python parser+serializer backend +genrule { + name: "gd_hci_packets_python3_gen", + defaults: ["pdl_python_generator_defaults"], + cmd: "$(location :pdlc) $(in) |" + + " $(location :pdl_python_generator)" + + " --output $(out) --custom-type-location blueberry.utils.bluetooth", + srcs: [ + "hci_packets.pdl", + ], + out: [ + "hci_packets.py", + ], +} diff --git a/system/pdl/hci/address.cc b/system/pdl/hci/address.cc new file mode 100644 index 0000000000000000000000000000000000000000..8736c16de8d8612fe9ad522dc1e4856087a2570e --- /dev/null +++ b/system/pdl/hci/address.cc @@ -0,0 +1,139 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "hci/address.h" + +#include +#include +#include +#include +#include + +namespace bluetooth { +namespace hci { + +const Address Address::kAny{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; +const Address Address::kEmpty{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +// Address cannot initialize member variables as it is a POD type +// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) +Address::Address(const uint8_t (&addr)[6]) { + std::copy(addr, addr + kLength, data()); +} + +Address::Address(std::initializer_list l) { + std::copy(l.begin(), std::min(l.begin() + kLength, l.end()), data()); +} + +std::string Address::_ToMaskedColonSepHexString(int bytes_to_mask) const { + std::stringstream ss; + int count = 0; + for (auto it = address.rbegin(); it != address.rend(); it++) { + if (count++ < bytes_to_mask) { + ss << "xx"; + } else { + ss << std::nouppercase << std::hex << std::setw(2) << std::setfill('0') + << +*it; + } + if (std::next(it) != address.rend()) { + ss << ':'; + } + } + return ss.str(); +} + +std::string Address::ToString() const { return _ToMaskedColonSepHexString(0); } + +std::string Address::ToColonSepHexString() const { + return _ToMaskedColonSepHexString(0); +} + +std::string Address::ToStringForLogging() const { + return _ToMaskedColonSepHexString(0); +} + +std::string Address::ToRedactedStringForLogging() const { + return _ToMaskedColonSepHexString(4); +} + +std::string Address::ToLegacyConfigString() const { return ToString(); } + +std::optional
    Address::FromLegacyConfigString(const std::string& str) { + return FromString(str); +} + +std::optional
    Address::FromString(const std::string& from) { + if (from.length() != 17) { + return std::nullopt; + } + + Address addr{}; + std::istringstream stream(from); + std::string token; + int index = 0; + while (getline(stream, token, ':')) { + if (index >= 6) { + return std::nullopt; + } + + if (token.length() != 2) { + return std::nullopt; + } + + char* temp = nullptr; + addr.address.at(5 - index) = std::strtol(token.c_str(), &temp, 16); + if (temp == token.c_str()) { + // string token is empty or has wrong format + return std::nullopt; + } + if (temp != (token.c_str() + token.size())) { + // cannot parse whole string + return std::nullopt; + } + + index++; + } + + if (index != 6) { + return std::nullopt; + } + + return addr; +} + +bool Address::FromString(const std::string& from, Address& to) { + auto addr = FromString(from); + if (!addr) { + to = {}; + return false; + } + to = std::move(*addr); + return true; +} + +size_t Address::FromOctets(const uint8_t* from) { + std::copy(from, from + kLength, data()); + return kLength; +}; + +bool Address::IsValidAddress(const std::string& address) { + return Address::FromString(address).has_value(); +} + +} // namespace hci +} // namespace bluetooth diff --git a/tools/rootcanal/lib/hci/class_of_device.cc b/system/pdl/hci/class_of_device.cc similarity index 69% rename from tools/rootcanal/lib/hci/class_of_device.cc rename to system/pdl/hci/class_of_device.cc index 97ab807a2194cf137990b53fa572c61651796940..c4506f5dc6744309bac425719cbe28d3c529439e 100644 --- a/tools/rootcanal/lib/hci/class_of_device.cc +++ b/system/pdl/hci/class_of_device.cc @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright 2022 The Android Open Source Project + * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,6 @@ #include #include -#include "log.h" - namespace bluetooth { namespace hci { @@ -34,11 +32,7 @@ namespace hci { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) ClassOfDevice::ClassOfDevice(const uint8_t (&class_of_device)[kLength]) { std::copy(class_of_device, class_of_device + kLength, cod.data()); -} - -uint32_t ClassOfDevice::ToUint32() const { - return (cod[2]) | (cod[1] << 8) | (cod[0] << 16); -} +}; std::string ClassOfDevice::ToString() const { char buffer[] = "000-0-00"; @@ -49,6 +43,10 @@ std::string ClassOfDevice::ToString() const { return str; } +std::string ClassOfDevice::ToLegacyConfigString() const { + return std::to_string(ToUint32Legacy()); +} + std::optional ClassOfDevice::FromString(const std::string& str) { if (str.length() != 8) { return std::nullopt; @@ -67,11 +65,9 @@ std::optional ClassOfDevice::FromString(const std::string& str) { if (index == 0 && token.length() != 3) { return std::nullopt; - } - if (index == 1 && token.length() != 1) { + } else if (index == 1 && token.length() != 1) { return std::nullopt; - } - if (index == 2 && token.length() != 2) { + } else if (index == 2 && token.length() != 2) { return std::nullopt; } char* temp = nullptr; @@ -104,9 +100,38 @@ bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) { return true; } -bool ClassOfDevice::IsValid(const std::string& class_of_device) { - return ClassOfDevice::FromString(class_of_device).has_value(); +std::optional ClassOfDevice::FromUint32Legacy(uint32_t cod_int) { + if (cod_int != 0 && (cod_int >> 24) != 0) { + return std::nullopt; + } + ClassOfDevice result = {}; + result.cod[2] = static_cast(cod_int); + result.cod[1] = static_cast(cod_int >> 8); + result.cod[0] = static_cast(cod_int >> 16); + return result; +} + +std::optional ClassOfDevice::FromLegacyConfigString( + const std::string& str) { + char* ptr = nullptr; + auto num = std::strtoull(str.data(), &ptr, 10); + if (num > 0xffffff) { + return std::nullopt; + } + return FromUint32Legacy(static_cast(num)); +} + +uint32_t ClassOfDevice::ToUint32Legacy() const { + return (cod[2]) | (cod[1] << 8) | (cod[0] << 16); } +size_t ClassOfDevice::FromOctets(const uint8_t* from) { + std::copy(from, from + kLength, data()); + return kLength; +}; + +bool ClassOfDevice::IsValid(const std::string& cod) { + return ClassOfDevice::FromString(cod).has_value(); +} } // namespace hci } // namespace bluetooth diff --git a/system/gd/hci/hci_packets.pdl b/system/pdl/hci/hci_packets.pdl similarity index 91% rename from system/gd/hci/hci_packets.pdl rename to system/pdl/hci/hci_packets.pdl index 11d5b86f651cfa920ad508e28638160c39010f8d..53193d45d09274d5dcb65a95e81c0bf3455fafd5 100644 --- a/system/gd/hci/hci_packets.pdl +++ b/system/pdl/hci/hci_packets.pdl @@ -163,6 +163,8 @@ enum OpCode : 16 { HOLD_MODE = 0x0801, SNIFF_MODE = 0x0803, EXIT_SNIFF_MODE = 0x0804, + PARK_STATE = 0x0805, + EXIT_PARK_STATE = 0x0806, QOS_SETUP = 0x0807, ROLE_DISCOVERY = 0x0809, SWITCH_ROLE = 0x080B, @@ -427,6 +429,20 @@ enum OpCode : 16 { LE_SET_DATA_RELATED_ADDRESS_CHANGES = 0x207C, LE_SET_DEFAULT_SUBRATE = 0x207D, LE_SUBRATE_REQUEST = 0x207E, + LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES = 0xFBE9, + LE_CS_SET_PROCEDURE_PARAMETERS = 0xFBEA, + LE_CS_TEST_END = 0xFBEB, + LE_CS_TEST = 0xFBEC, + LE_CS_PROCEDURE_ENABLE = 0xFBF1, + LE_CS_SET_CHANNEL_CLASSIFICATION = 0xFBF2, + LE_CS_REMOVE_CONFIG = 0xFBF3, + LE_CS_CREATE_CONFIG = 0xFBF4, + LE_CS_READ_REMOTE_FAE_TABLE = 0xFBF6, + LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE = 0xFBF7, + LE_CS_SET_DEFAULT_SETTINGS = 0xFBF8, + LE_CS_SECURITY_ENABLE = 0xFBF9, + LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES = 0xFBFA, + LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES = 0xFBFB, // VENDOR_SPECIFIC // MSFT_OPCODE_xxxx below is needed for the tests. @@ -477,6 +493,8 @@ enum OpCodeIndex : 16 { HOLD_MODE = 41, SNIFF_MODE = 42, EXIT_SNIFF_MODE = 43, + PARK_STATE = 44, + EXIT_PARK_STATE = 45, QOS_SETUP = 46, ROLE_DISCOVERY = 47, SWITCH_ROLE = 50, @@ -716,7 +734,7 @@ enum OpCodeIndex : 16 { LE_READ_BUFFER_SIZE_V2 = 415, LE_READ_ISO_TX_SYNC = 416, LE_SET_CIG_PARAMETERS = 417, - LE_SET_CIG_PARAMETERS_TEST = 418, + LE_SET_CIG_PARAMETERS_TEST = 420, LE_CREATE_CIS = 421, LE_REMOVE_CIG = 422, LE_ACCEPT_CIS_REQUEST = 423, @@ -770,6 +788,7 @@ packet LeScanningCommand : Command { _payload_, } packet LeConnectionManagementCommand : AclCommand { _payload_, } packet LeSecurityCommand : Command { _payload_, } packet LeIsoCommand : Command { _payload_, } +packet DistanceMeasurementCommand : Command { _payload_, } packet VendorCommand : Command { _payload_, } // HCI Event Packets @@ -827,6 +846,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, VENDOR_SPECIFIC = 0xFF, } @@ -874,6 +894,14 @@ enum SubeventCode : 8 { TRANSMIT_POWER_REPORTING = 0x21, BIG_INFO_ADVERTISING_REPORT = 0x22, LE_SUBRATE_CHANGE = 0x23, + LE_CS_TEST_END_COMPLETE = 0xF5, + LE_CS_SUBEVENT_RESULT_CONTINUE = 0xF6, + LE_CS_SUBEVENT_RESULT = 0xF7, + LE_CS_PROCEDURE_ENABLE_COMPLETE = 0xF8, + LE_CS_CONFIG_COMPLETE = 0xF9, + LE_CS_SECURITY_ENABLE_COMPLETE = 0xFA, + LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE = 0xFB, + LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE = 0xFC, } // Vendor specific events @@ -892,6 +920,7 @@ enum FeatureFlag : 1 { SUPPORTED = 1, } +// Vol 1, Part F: Controller Error Codes enum ErrorCode: 8 { STATUS_UNKNOWN = 0xFF, SUCCESS = 0x00, @@ -930,12 +959,32 @@ enum ErrorCode: 8 { ROLE_CHANGE_NOT_ALLOWED = 0x21, TRANSACTION_RESPONSE_TIMEOUT = 0x22, LINK_LAYER_COLLISION = 0x23, + LMP_PDU_NOT_ALLOWED = 0x24, ENCRYPTION_MODE_NOT_ACCEPTABLE = 0x25, + LINK_KEY_CANNOT_BE_CHANGED = 0x26, + REQUESTED_QOS_NOT_SUPPORTED = 0x27, + INSTANT_PASSED = 0x28, + PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED = 0x29, + DIFFERENT_TRANSACTION_COLLISION = 0x2A, + QOS_UNACCEPTABLE_PARAMETERS = 0x2C, + QOS_REJECTED = 0x2D, + CHANNEL_ASSESSMENT_NOT_SUPPORTED = 0x2E, + INSUFFICIENT_SECURITY = 0x2F, + PARAMETER_OUT_OF_MANDATORY_RANGE = 0x30, + ROLE_SWITCH_PENDING = 0x32, + RESERVED_SLOT_VIOLATION = 0x34, ROLE_SWITCH_FAILED = 0x35, - HOST_BUSY = 0x38, + EXTENDED_INQUIRY_RESPONSE_TOO_LARGE = 0x36, + SECURE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST = 0x37, + HOST_BUSY_PAIRING = 0x38, + CONNECTION_REJECTED_NO_SUITABLE_CHANNEL_FOUND = 0x39, CONTROLLER_BUSY = 0x3A, + UNACCEPTABLE_CONNECTION_PARAMETERS = 0x3B, ADVERTISING_TIMEOUT = 0x3C, + CONNECTION_TERMINATED_DUE_TO_MIC_FAILURE = 0x3D, CONNECTION_FAILED_ESTABLISHMENT = 0x3E, + COARSE_CLOCK_ADJUSTMENT_REJECTED = 0x40, + TYPE0_SUBMAP_NOT_DEFINED = 0x41, UNKNOWN_ADVERTISING_IDENTIFIER = 0x42, LIMIT_REACHED = 0x43, OPERATION_CANCELLED_BY_HOST = 0x44, @@ -1608,7 +1657,6 @@ packet HoldMode : ConnectionManagementCommand (op_code = HOLD_MODE) { packet HoldModeStatus : CommandStatus (command_op_code = HOLD_MODE) { } - packet SniffMode : ConnectionManagementCommand (op_code = SNIFF_MODE) { connection_handle : 12, _reserved_ : 4, @@ -1630,6 +1678,26 @@ packet ExitSniffMode : ConnectionManagementCommand (op_code = EXIT_SNIFF_MODE) { packet ExitSniffModeStatus : CommandStatus (command_op_code = EXIT_SNIFF_MODE) { } +// ParkState and ExitParkState are deprecated +packet ParkState : ConnectionManagementCommand (op_code = PARK_STATE) { + connection_handle : 12, + _reserved_ : 4, + beacon_max_interval: 16, // 0x000E-0x1000 (8.75ms-40.9s) + beacon_min_interval: 16, // 0x000E-0x1000 (8.75ms-40.9s) +} + +packet ParkStateStatus : CommandStatus (command_op_code = PARK_STATE) { +} + + +packet ExitParkState : ConnectionManagementCommand (op_code = EXIT_PARK_STATE) { + connection_handle : 12, + _reserved_ : 4, +} + +packet ExitParkStateStatus : CommandStatus (command_op_code = EXIT_PARK_STATE) { +} + enum ServiceType : 8 { NO_TRAFFIC = 0x00, BEST_EFFORT = 0x01, @@ -3954,8 +4022,8 @@ packet LeSetExtendedAdvertisingDataRaw : LeAdvertisingCommand (op_code = LE_SET_ _reserved_ : 5, fragment_preference : FragmentPreference, _reserved_ : 7, - _size_(advertising_data) : 8, - advertising_data : 8[], + _size_(_payload_) : 8, + _payload_, } packet LeSetExtendedAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_ADVERTISING_DATA) { @@ -3982,8 +4050,8 @@ packet LeSetExtendedScanResponseDataRaw : LeAdvertisingCommand (op_code = LE_SET _reserved_ : 5, fragment_preference : FragmentPreference, _reserved_ : 7, - _size_(scan_response_data) : 8, - scan_response_data : 8[], + _size_(_payload_) : 8, + _payload_, } packet LeSetExtendedScanResponseDataComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_SCAN_RESPONSE_DATA) { @@ -4099,8 +4167,8 @@ packet LeSetPeriodicAdvertisingDataRaw : LeAdvertisingCommand (op_code = LE_SET_ advertising_handle : 8, operation : Operation, _reserved_ : 5, - _size_(advertising_data) : 8, - advertising_data : 8[], + _size_(_payload_) : 8, + _payload_, } packet LeSetPeriodicAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_PERIODIC_ADVERTISING_DATA) { @@ -4483,7 +4551,7 @@ packet LeSetCigParameters : LeIsoCommand (op_code = LE_SET_CIG_PARAMETERS) { cig_id : 8, sdu_interval_m_to_s : 24, sdu_interval_s_to_m : 24, - peripherals_clock_accuracy : ClockAccuracy, + worst_case_sca : ClockAccuracy, packing : Packing, framing : Enable, max_transport_latency_m_to_s : 16, @@ -4519,7 +4587,7 @@ packet LeSetCigParametersTest : LeIsoCommand (op_code = LE_SET_CIG_PARAMETERS_TE ft_m_to_s : 8, ft_s_to_m : 8, iso_interval : 16, - peripherals_clock_accuracy : ClockAccuracy, + worst_case_sca : ClockAccuracy, packing : Packing, framing : Enable, _count_(cis_config) : 8, @@ -4818,6 +4886,390 @@ packet LeSubrateRequest : AclCommand (op_code = LE_SUBRATE_REQUEST) { } packet LeSubrateRequestStatus : CommandStatus (command_op_code = LE_SUBRATE_REQUEST) { +} + +packet LeCsReadLocalSupportedCapabilities : DistanceMeasurementCommand (op_code = LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES) { + +} + +struct CsRoleSupported { + initiator : 1, + reflector : 1, + _reserved_ : 6, +} + +struct CsOptionalModesSupported { + mode_3 : 1, + _reserved_ : 7, +} + +struct CsRttCapability { + rtt_aa_only_n : 1, + rtt_sounding_n : 1, + rtt_random_payload_n : 1, + _reserved_ : 5, +} + +struct CsOptionalNadmSoundingCapability { + normalized_attack_detector_metric : 1, + _reserved_ : 15, +} + +struct CsOptionalNadmRandomCapability { + normalized_attack_detector_metric : 1, + _reserved_ : 15, +} + +struct CsOptionalCsSyncPhysSupported { + le_2m_phy : 1, + _reserved_ : 7, +} + +struct CsOptionalSubfeaturesSupported { + companion_signal : 1, + frequency_actuation_error : 1, + channel_selection_algorithm : 1, + phase_based_ranging : 1, + _reserved_ : 12, +} + +struct CsOptionalTIp1TimesSupported { + support_10_microsecond : 1, + support_20_microsecond : 1, + support_30_microsecond : 1, + support_40_microsecond : 1, + support_50_microsecond : 1, + support_60_microsecond : 1, + support_80_microsecond : 1, + _reserved_ : 9, +} + +struct CsOptionalTIp2TimesSupported { + support_10_microsecond : 1, + support_20_microsecond : 1, + support_30_microsecond : 1, + support_40_microsecond : 1, + support_50_microsecond : 1, + support_60_microsecond : 1, + support_80_microsecond : 1, + _reserved_ : 9, +} + +struct CsOptionalTFcsTimesSupported { + support_15_microsecond : 1, + support_20_microsecond : 1, + support_30_microsecond : 1, + support_40_microsecond : 1, + support_50_microsecond : 1, + support_60_microsecond : 1, + support_80_microsecond : 1, + support_100_microsecond : 1, + support_120_microsecond : 1, + _reserved_ : 7, +} + +struct CsOptionalTPmTimesSupported { + support_10_microsecond : 1, + support_20_microsecond : 1, + _reserved_ : 14, +} + +packet LeCsReadLocalSupportedCapabilitiesComplete : CommandComplete (command_op_code = LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES) { + status : ErrorCode, + num_config_supported: 8, + max_consecutive_procedures_supported : 16, + num_antennas_supported : 8, + max_antenna_paths_supported : 8, + roles_supported : CsRoleSupported, + optional_modes_supported : CsOptionalModesSupported, + rtt_capability : CsRttCapability, + rtt_aa_only_n : 8, + rtt_sounding_n : 8, + rtt_random_payload_n : 8, + optional_nadm_sounding_capability : CsOptionalNadmSoundingCapability, + optional_nadm_random_capability : CsOptionalNadmRandomCapability, + optional_cs_sync_phys_supported : CsOptionalCsSyncPhysSupported, + optional_subfeatures_supported : CsOptionalSubfeaturesSupported, + optional_t_ip1_times_supported : CsOptionalTIp1TimesSupported, + optional_t_ip2_times_supported : CsOptionalTIp2TimesSupported, + optional_t_fcs_times_supported : CsOptionalTFcsTimesSupported, + optional_t_pm_times_supported : CsOptionalTPmTimesSupported, + t_sw_time_supported : 8, +} + +packet LeCsReadRemoteSupportedCapabilities : DistanceMeasurementCommand (op_code = LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES) { + connection_handle: 12, + _reserved_ : 4, +} + +packet LeCsReadRemoteSupportedCapabilitiesStatus : CommandStatus (command_op_code = LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES) { +} + +packet LeCsWriteCachedRemoteSupportedCapabilities : DistanceMeasurementCommand (op_code = LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES) { + connection_handle: 12, + _reserved_ : 4, + num_config_supported: 8, + max_consecutive_procedures_supported : 16, + num_antennas_supported : 8, + max_antenna_paths_supported : 8, + roles_supported : CsRoleSupported, + optional_modes_supported : CsOptionalModesSupported, + rtt_capability : CsRttCapability, + rtt_aa_only_n : 8, + rtt_sounding_n : 8, + rtt_random_payload_n : 8, + optional_nadm_sounding_capability : CsOptionalNadmSoundingCapability, + optional_nadm_random_capability : CsOptionalNadmRandomCapability, + optional_cs_sync_phys_supported : CsOptionalCsSyncPhysSupported, + optional_subfeatures_supported : CsOptionalSubfeaturesSupported, + optional_t_ip1_times_supported : CsOptionalTIp1TimesSupported, + optional_t_ip2_times_supported : CsOptionalTIp2TimesSupported, + optional_t_fcs_times_supported : CsOptionalTFcsTimesSupported, + optional_t_pm_times_supported : CsOptionalTPmTimesSupported, + t_sw_time_supported : 8, +} + +packet LeCsWriteCachedRemoteSupportedCapabilitiesComplete : CommandComplete (command_op_code = LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES) { + status : ErrorCode, + connection_handle: 12, + _reserved_ : 4, +} + +packet LeCsSecurityEnable : DistanceMeasurementCommand (op_code = LE_CS_SECURITY_ENABLE) { + connection_handle: 12, + _reserved_ : 4, +} + +packet LeCsSecurityEnableStatus : CommandStatus (command_op_code = LE_CS_SECURITY_ENABLE) { +} + +enum CsSyncAntennaSelection : 8 { + ANTENNA_1 = 0x01, + ANTENNA_2 = 0x02, + ANTENNA_3 = 0x03, + ANTENNA_4 = 0x04, + ANTENNAS_IN_ORDER = 0xFE, + NO_RECOMMENDATION = 0xFF, +} + +packet LeCsSetDefaultSettings : DistanceMeasurementCommand (op_code = LE_CS_SET_DEFAULT_SETTINGS) { + connection_handle: 12, + _reserved_ : 4, + role_enable : 8, + cs_sync_antenna_selection : CsSyncAntennaSelection, + max_tx_power : 8, +} + +packet LeCsSetDefaultSettingsComplete : CommandComplete (command_op_code = LE_CS_SET_DEFAULT_SETTINGS) { + status : ErrorCode, + connection_handle: 12, + _reserved_ : 4, +} + +packet LeCsReadRemoteFaeTable : DistanceMeasurementCommand (op_code = LE_CS_READ_REMOTE_FAE_TABLE) { + connection_handle: 12, + _reserved_ : 4, +} + +packet LeCsReadRemoteFaeTableStatus : CommandStatus (command_op_code = LE_CS_READ_REMOTE_FAE_TABLE) { +} + +packet LeCsWriteCachedRemoteFaeTable : DistanceMeasurementCommand (op_code = LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE) { + connection_handle: 12, + _reserved_ : 4, + remote_fae_table : 8[9], +} + +packet LeCsWriteCachedRemoteFaeTableComplete : CommandComplete (command_op_code = LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE) { + status : ErrorCode, + connection_handle: 12, + _reserved_ : 4, +} + +enum CsCreateContext: 8 { + LOCAL_CONTROLLER_ONLY = 0x00, + BOTH_LOCAL_AND_REMOTE_CONTROLLER = 0x01, +} + +enum CsMainModeType: 8 { + MODE_1 = 0x01, + MODE_2 = 0x02, + MODE_3 = 0x03, +} + +enum CsSubModeType: 8 { + MODE_1 = 0x01, + MODE_2 = 0x02, + MODE_3 = 0x03, + UNUSED = 0xff, +} + +enum CsRole : 8 { + INITIATOR = 0x00, + REFLECTOR = 0x01, +} + +enum CsConfigRttType : 8 { + 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, + RTT_WITH_64_BIT_RANDOM_SEQUENCE = 0x04, + RTT_WITH_96_BIT_RANDOM_SEQUENCE = 0x05, + RTT_WITH_128_BIT_RANDOM_SEQUENCE = 0x06, +} + +enum CsSyncPhy : 8 { + LE_1M_PHY = 0x01, + LE_2M_PHY = 0x02, +} + +enum CsChannelSelectionType : 8 { + TYPE_3B = 0x00, + TYPE_3C = 0x01, +} + +enum CsCh3cShape : 8 { + HAT_SHAPE = 0x00, + X_SHAPE = 0x01, +} + +packet LeCsCreateConfig : DistanceMeasurementCommand (op_code = LE_CS_CREATE_CONFIG) { + connection_handle: 12, + _reserved_ : 4, + config_id : 2, + _reserved_ : 6, + create_context : CsCreateContext, + main_mode_type : CsMainModeType, + sub_mode_type : CsSubModeType, + main_mode_min_steps : 8, + main_mode_max_steps : 8, + main_mode_repetition : 2, + _reserved_ : 6, + mode_0_steps : 2, + _reserved_ : 6, + role : CsRole, + rtt_type : CsConfigRttType, + cs_sync_phy : CsSyncPhy, + channel_map : 8[10], + channel_map_repetition : 8, + channel_selection_type : CsChannelSelectionType, + ch3c_shape : CsCh3cShape, + ch3c_jump : 8, + companion_signal_enable : Enable, +} + +packet LeCsCreateConfigStatus : CommandStatus (command_op_code = LE_CS_CREATE_CONFIG) { + +} + +packet LeCsRemoveConfig : DistanceMeasurementCommand (op_code = LE_CS_REMOVE_CONFIG) { + connection_handle: 12, + _reserved_ : 4, + config_id : 2, + _reserved_ : 6, +} + +packet LeCsRemoveConfigStatus : CommandStatus (command_op_code = LE_CS_REMOVE_CONFIG) { + +} + +packet LeCsSetChannelClassification : DistanceMeasurementCommand (op_code = LE_CS_SET_CHANNEL_CLASSIFICATION) { + channel_classification : 8[10], +} + +packet LeCsSetChannelClassificationComplete : CommandComplete (command_op_code = LE_CS_SET_CHANNEL_CLASSIFICATION) { +} + +enum CsPhy : 8 { + LE_1M_PHY = 0x01, + LE_2M_PHY = 0x02, +} + +struct CsPreferredPeerAntenna { + use_first_ordered_antenna_element : 1, + use_second_ordered_antenna_element : 1, + use_third_ordered_antenna_element : 1, + use_fourth_ordered_antenna_element : 1, + _reserved_ : 4, +} + +packet LeCsSetProcedureParameters : DistanceMeasurementCommand (op_code = LE_CS_SET_PROCEDURE_PARAMETERS) { + connection_handle: 12, + _reserved_ : 4, + config_id : 2, + _reserved_ : 6, + max_procedure_duration : 16, + min_procedure_interval : 16, + max_procedure_interval : 16, + max_procedure_count : 16, + min_subevent_len : 24, + max_subevent_len : 24, + tone_antenna_config_selection : 8, + phy : CsPhy, + tx_pwr_delta : 8, + preferred_peer_antenna : CsPreferredPeerAntenna, +} + +packet LeCsSetProcedureParametersComplete : CommandComplete (command_op_code = LE_CS_SET_PROCEDURE_PARAMETERS) { + status : ErrorCode, + connection_handle: 12, + _reserved_ : 4, +} + +packet LeCsProcedureEnable : DistanceMeasurementCommand (op_code = LE_CS_PROCEDURE_ENABLE) { + connection_handle: 12, + _reserved_ : 4, + config_id : 2, + _reserved_ : 6, + procedure_enable : Enable, +} + +packet LeCsProcedureEnableStatus : CommandStatus (command_op_code = LE_CS_PROCEDURE_ENABLE) { +} + +packet LeCsTest : DistanceMeasurementCommand (op_code = LE_CS_TEST) { + main_mode_type : 8, + sub_mode_type : 8, + main_mode_steps : 8, + main_mode_repetition : 8, + mode_0_steps : 8, + role : 8, + rtt_type : 8, + cs_sync_phy : 8, + cs_sync_antenna_selection : 8, + cs_sync_aa_initiator : 32, + cs_sync_aa_reflector : 32, + cs_sync_random : 8[16], + cs_sync_user_payload_pattern : 8, + cs_subevent_length : 24, + cs_subevent_interval : 16, + transmit_power_level : 8, + t_ip1_time : 8, + t_ip2_time : 8, + t_fcs_time : 8, + t_pm_time : 8, + t_sw_time : 8, + t_pm_tone_ext : 8, + ss_marker1_position: 8, + ss_marker2_position: 8, + ss_marker_value : 8, + companion_signal_enable : 8, + tone_antenna_config : 8, + tone_antenna_permutation : 8, + channel_map_repetition: 8, + _size_(channel) : 8, + channel : 8[], +} + +packet LeCsTestComplete : CommandComplete (command_op_code = LE_CS_TEST) { + status : ErrorCode, +} + +packet LeCsTestEnd : DistanceMeasurementCommand (op_code = LE_CS_TEST_END) { +} + +packet LeCsTestEndStatus : CommandStatus (command_op_code = LE_CS_TEST_END) { } // VENDOR_SPECIFIC @@ -5364,7 +5816,6 @@ packet ConnectionComplete : Event (event_code = CONNECTION_COMPLETE) { } enum ConnectionRequestLinkType : 8 { - UNKNOWN = 0xFF, SCO = 0x00, ACL = 0x01, ESCO = 0x02, @@ -5732,14 +6183,10 @@ packet LinkSupervisionTimeoutChanged : Event (event_code = LINK_SUPERVISION_TIME link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s) } -enum FlushablePacketType : 8 { - AUTOMATICALLY_FLUSHABLE_ONLY = 0, -} - packet EnhancedFlush : Command (op_code = ENHANCED_FLUSH) { connection_handle : 12, _reserved_ : 4, - packet_type : FlushablePacketType, + _reserved_ : 8, // Automatically flushable only (0x00) } test EnhancedFlush { @@ -5784,6 +6231,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, @@ -6226,6 +6678,159 @@ packet LeSubrateChange : LeMetaEvent (subevent_code = LE_SUBRATE_CHANGE) { _reserved_ : 4, } +packet LeCsReadRemoteSupportedCapabilitiesComplete : LeMetaEvent (subevent_code = LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + num_config_supported: 8, + max_consecutive_procedures_supported : 16, + num_antennas_supported : 8, + max_antenna_paths_supported : 8, + roles_supported : CsRoleSupported, + optional_modes_supported : 8, + rtt_capability : CsRttCapability, + rtt_aa_only_n : 8, + rtt_sounding_n : 8, + rtt_random_payload_n : 8, + optional_nadm_sounding_capability : CsOptionalNadmSoundingCapability, + optional_nadm_random_capability : CsOptionalNadmRandomCapability, + optional_cs_sync_phys_supported : CsOptionalCsSyncPhysSupported, + optional_subfeatures_supported : CsOptionalSubfeaturesSupported, + optional_t_ip1_times_supported : CsOptionalTIp1TimesSupported, + optional_t_ip2_times_supported : CsOptionalTIp2TimesSupported, + optional_t_fcs_times_supported : CsOptionalTFcsTimesSupported, + optional_t_pm_times_supported : CsOptionalTPmTimesSupported, + t_sw_time_supported : 8, +} + +packet LeCsReadRemoteFaeTableComplete : LeMetaEvent (subevent_code = LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + remote_fae_table : 8[9], +} + +packet LeCsSecurityEnableComplete : LeMetaEvent (subevent_code = LE_CS_SECURITY_ENABLE_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, +} + +enum CsRttType : 8 { + RTT_AA_ONLY = 0x00, + RTT_WITH_32_BIT_SOUNDING_SEQUENCE = 0x01, + RTT_WITH_96_BIT_SOUNDING_SEQUENCE = 0x02, + RTT_WITH_32_BIT_RANDOM_SEQUENCE = 0x03, + RTT_WITH_64_BIT_RANDOM_SEQUENCE = 0x04, + RTT_WITH_96_BIT_RANDOM_SEQUENCE = 0x05, + RTT_WITH_128_BIT_RANDOM_SEQUENCE = 0x06, +} + +enum CsAction : 8 { + CONFIG_REMOVED = 0x00, + CONFIG_CREATED = 0x01, +} + +packet LeCsConfigComplete : LeMetaEvent (subevent_code = LE_CS_CONFIG_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + config_id : 2, + _reserved_ : 6, + action : CsAction, + main_mode_type : CsMainModeType, + sub_mode_type : CsSubModeType, + min_main_mode_steps : 8, + max_main_mode_steps : 8, + main_mode_repetition : 2, + _reserved_ : 6, + mode_0_steps : 2, + _reserved_ : 6, + role : CsRole, + rtt_type : CsRttType, + cs_sync_phy : CsSyncPhy, + channel_map : 8[10], + channel_map_repetition : 8, + channel_selection_type : CsChannelSelectionType, + ch3c_shape : CsCh3cShape, + ch3c_jump : 8, + companion_signal_enable : Enable, + t_ip1_time : 8, + t_ip2_time : 8, + t_fcs_time : 8, + t_pm_time : 8, +} + +packet LeCsProcedureEnableComplete : LeMetaEvent (subevent_code = LE_CS_PROCEDURE_ENABLE_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + config_id : 2, + _reserved_ : 6, + state : Enable, + tone_antenna_config_selection : 8, + selected_tx_power : 8, + subevent_len : 24, + subevents_per_event : 8, + subevent_interval : 16, + event_interval : 16, + procedure_interval : 16, + procedure_count : 16, +} + +enum CsProcedureDoneStatus : 4 { + ALL_RESULTS_COMPLETE = 0x0, + PARTIAL_RESULTS = 0x1, + ABORTED = 0xF, +} + +enum CsSubeventDoneStatus : 4 { + ALL_RESULTS_COMPLETE = 0x0, + PARTIAL_RESULTS = 0x1, + ABORTED = 0xF, +} + +struct LeCsResultDataStructure { + step_mode : 8, + step_channel : 8, + _size_(step_data) : 8, + step_data : 8[], +} + +packet LeCsSubeventResult : LeMetaEvent (subevent_code = LE_CS_SUBEVENT_RESULT) { + connection_handle : 12, + _reserved_ : 4, + config_id : 2, + _reserved_ : 6, + start_acl_conn_event : 16, + procedure_counter : 16, + frequency_compensation : 16, + reference_power_level : 8, + procedure_done_status : CsProcedureDoneStatus, + _reserved_ : 4, + subevent_done_status : CsSubeventDoneStatus, + _reserved_ : 4, + abort_reason : 8, + num_antenna_paths : 8, + _count_(result_data_structures) : 8, + result_data_structures : LeCsResultDataStructure[], +} + +packet LeCsSubeventResultContinue : LeMetaEvent (subevent_code = LE_CS_SUBEVENT_RESULT_CONTINUE) { + connection_handle : 12, + _reserved_ : 4, + config_id : 2, + _reserved_ : 6, + procedure_done_status : CsProcedureDoneStatus, + _reserved_ : 4, + subevent_done_status : CsSubeventDoneStatus, + _reserved_ : 4, + abort_reason : 8, + num_antenna_paths : 8, + _count_(result_data_structures) : 8, + result_data_structures : LeCsResultDataStructure[], +} + // Vendor specific events packet VendorSpecificEvent : Event (event_code = VENDOR_SPECIFIC) { @@ -6414,7 +7019,7 @@ enum IsoPacketStatusFlag : 2 { packet IsoWithTimestamp : Iso (ts_flag = PRESENT) { time_stamp : 32, packet_sequence_number : 16, - _size_(_payload_) : 12, // iso_sdu_length + iso_sdu_length : 12, _reserved_ : 2, packet_status_flag : IsoPacketStatusFlag, _payload_, @@ -6422,7 +7027,7 @@ packet IsoWithTimestamp : Iso (ts_flag = PRESENT) { packet IsoWithoutTimestamp : Iso (ts_flag = NOT_PRESENT) { packet_sequence_number : 16, - _size_(_payload_) : 12, // iso_sdu_length + iso_sdu_length : 12, _reserved_ : 2, packet_status_flag : IsoPacketStatusFlag, _payload_, diff --git a/system/pdl/hci/include/hci/address.h b/system/pdl/hci/include/hci/address.h new file mode 100644 index 0000000000000000000000000000000000000000..283c9c3bafbafd06f6b3d880325d0e8760863d5b --- /dev/null +++ b/system/pdl/hci/include/hci/address.h @@ -0,0 +1,112 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "common/interfaces/ILoggable.h" +#include "packet/custom_field_fixed_size_interface.h" +#include "storage/serializable.h" + +namespace bluetooth { +namespace hci { + +class Address final : public packet::CustomFieldFixedSizeInterface
    , + public storage::Serializable
    , + public bluetooth::common::IRedactableLoggable { + public: + static constexpr size_t kLength = 6; + + // Bluetooth MAC address bytes saved in little endian format. + // The address MSB is address[5], the address LSB is address[0]. + // Note that the textual representation follows the big endian format, + // ie. Address{0, 1, 2, 3, 4, 5} is represented as 05:04:03:02:01:00. + std::array address = {}; + + Address() = default; + Address(const uint8_t (&addr)[kLength]); + Address(std::initializer_list l); + + // CustomFieldFixedSizeInterface methods + inline uint8_t* data() override { return address.data(); } + inline const uint8_t* data() const override { return address.data(); } + + // storage::Serializable methods + std::string ToString() const override; + std::string ToColonSepHexString() const; + std::string ToStringForLogging() const override; + std::string ToRedactedStringForLogging() const override; + + static std::optional
    FromString(const std::string& from); + std::string ToLegacyConfigString() const override; + static std::optional
    FromLegacyConfigString(const std::string& str); + + bool operator<(const Address& rhs) const { return address < rhs.address; } + bool operator==(const Address& rhs) const { return address == rhs.address; } + bool operator>(const Address& rhs) const { return (rhs < *this); } + bool operator<=(const Address& rhs) const { return !(*this > rhs); } + bool operator>=(const Address& rhs) const { return !(*this < rhs); } + bool operator!=(const Address& rhs) const { return !(*this == rhs); } + + bool IsEmpty() const { return *this == kEmpty; } + + // Converts |string| to Address and places it in |to|. If |from| does + // not represent a Bluetooth address, |to| is not modified and this function + // returns false. Otherwise, it returns true. + static bool FromString(const std::string& from, Address& to); + + // Copies |from| raw Bluetooth address octets to the local object. + // Returns the number of copied octets - should be always Address::kLength + size_t FromOctets(const uint8_t* from); + + static bool IsValidAddress(const std::string& address); + + static const Address kEmpty; // 00:00:00:00:00:00 + static const Address kAny; // FF:FF:FF:FF:FF:FF + private: + std::string _ToMaskedColonSepHexString(int bytes_to_mask) const; +}; + +// TODO: to fine-tune this. +// we need an interface between the logger and ILoggable +inline std::ostream& operator<<(std::ostream& os, const Address& a) { + os << a.ToString(); + return os; +} + +} // namespace hci +} // namespace bluetooth + +namespace std { +template <> +struct hash { + std::size_t operator()(const bluetooth::hci::Address& val) const { + static_assert(sizeof(uint64_t) >= bluetooth::hci::Address::kLength); + uint64_t int_addr = 0; + memcpy(reinterpret_cast(&int_addr), val.data(), + bluetooth::hci::Address::kLength); + return std::hash{}(int_addr); + } +}; +} // namespace std diff --git a/tools/rootcanal/include/hci/class_of_device.h b/system/pdl/hci/include/hci/class_of_device.h similarity index 80% rename from tools/rootcanal/include/hci/class_of_device.h rename to system/pdl/hci/include/hci/class_of_device.h index 8a1d1f04dffa19939e1bcf8cb4035597bcf16f8e..a310ba9c66184c940248855c8f92e6537dbee544 100644 --- a/tools/rootcanal/include/hci/class_of_device.h +++ b/system/pdl/hci/include/hci/class_of_device.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright 2022 The Android Open Source Project + * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,12 +23,14 @@ #include #include "packet/custom_field_fixed_size_interface.h" +#include "storage/serializable.h" namespace bluetooth { namespace hci { class ClassOfDevice final - : public packet::CustomFieldFixedSizeInterface { + : public packet::CustomFieldFixedSizeInterface, + public storage::Serializable { public: static constexpr size_t kLength = 3; @@ -41,9 +43,12 @@ class ClassOfDevice final inline uint8_t* data() override { return cod.data(); } inline const uint8_t* data() const override { return cod.data(); } - uint32_t ToUint32() const; + // storage::Serializable methods std::string ToString() const; static std::optional FromString(const std::string& str); + std::string ToLegacyConfigString() const override; + static std::optional FromLegacyConfigString( + const std::string& str); bool operator<(const ClassOfDevice& rhs) const { return cod < rhs.cod; } bool operator==(const ClassOfDevice& rhs) const { return cod == rhs.cod; } @@ -57,6 +62,13 @@ class ClassOfDevice final // returns false. Otherwise, it returns true. static bool FromString(const std::string& from, ClassOfDevice& to); + // Converts uint32_t encoded class of device to ClassOfDevice object + // uint32_t encoding: + // uint8_t(cod[0]) | uint8_t(cod[1]) | uint8_t(cod[2]) + // Only used in legacy stack device config + static std::optional FromUint32Legacy(uint32_t cod_int); + uint32_t ToUint32Legacy() const; + // Copies |from| raw Class of Device octets to the local object. // Returns the number of copied octets (always ClassOfDevice::kLength) size_t FromOctets(const uint8_t* from); diff --git a/system/pdl/l2cap/Android.bp b/system/pdl/l2cap/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..d55935995c7d691d659f1f5eaa4d62a6fa6e5af3 --- /dev/null +++ b/system/pdl/l2cap/Android.bp @@ -0,0 +1,37 @@ +genrule { + name: "BluetoothGeneratedPacketsL2cap_h", + defaults: ["BluetoothGeneratedPackets_default"], + srcs: ["l2cap_packets.pdl"], + out: ["l2cap/l2cap_packets.h"], + visibility: ["//visibility:private"], +} + +cc_library_headers { + name: "libbluetooth_l2cap_pdl_header", + generated_headers: [ + "BluetoothGeneratedPacketsL2cap_h", + ], + export_generated_headers: [ + "BluetoothGeneratedPacketsL2cap_h", + ], + host_supported: true, + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "33", +} + +cc_library_static { + name: "libbluetooth_l2cap_pdl", + header_libs: [ + "libbluetooth_l2cap_pdl_header", + ], + export_header_lib_headers: [ + "libbluetooth_l2cap_pdl_header", + ], + host_supported: true, + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "33", +} diff --git a/system/gd/l2cap/l2cap_packets.pdl b/system/pdl/l2cap/l2cap_packets.pdl similarity index 100% rename from system/gd/l2cap/l2cap_packets.pdl rename to system/pdl/l2cap/l2cap_packets.pdl diff --git a/system/pdl/security/Android.bp b/system/pdl/security/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..ebd5a3d8db33e9f083a7ebb00e12ab1a2975b7da --- /dev/null +++ b/system/pdl/security/Android.bp @@ -0,0 +1,52 @@ +genrule { + name: "BluetoothGeneratedPacketsSmp_h", + defaults: ["BluetoothGeneratedPackets_default"], + srcs: ["smp_packets.pdl"], + out: ["security/smp_packets.h"], + visibility: ["//visibility:private"], +} + +cc_library_headers { + name: "libbluetooth_smp_pdl_header", + generated_headers: [ + "BluetoothGeneratedPacketsSmp_h", + ], + export_generated_headers: [ + "BluetoothGeneratedPacketsSmp_h", + ], + host_supported: true, + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "33", +} + +cc_library_static { + name: "libbluetooth_smp_pdl", + header_libs: [ + "libbluetooth_smp_pdl_header", + ], + export_header_lib_headers: [ + "libbluetooth_smp_pdl_header", + ], + host_supported: true, + apex_available: [ + "com.android.btservices", + ], + min_sdk_version: "33", +} + +// Generate the python parser+serializer backend +genrule { + name: "gd_smp_packets_python3_gen", + defaults: ["pdl_python_generator_defaults"], + cmd: "$(location :pdlc) $(in) |" + + " $(location :pdl_python_generator)" + + " --output $(out) --custom-type-location blueberry.utils.bluetooth", + srcs: [ + "smp_packets.pdl", + ], + out: [ + "smp_packets.py", + ], +} diff --git a/system/gd/security/smp_packets.pdl b/system/pdl/security/smp_packets.pdl similarity index 100% rename from system/gd/security/smp_packets.pdl rename to system/pdl/security/smp_packets.pdl diff --git a/system/profile/avrcp/Android.bp b/system/profile/avrcp/Android.bp index 941296560b76fc3e5eab7433e6cecbc605e6bb71..34e3d1df48f5a267fb0bcc6bb54e9bd5cf4ca0a3 100644 --- a/system/profile/avrcp/Android.bp +++ b/system/profile/avrcp/Android.bp @@ -11,13 +11,11 @@ cc_library_static { name: "avrcp-target-service", defaults: [ "fluoride_defaults", - "libchrome_support_defaults", ], host_supported: true, include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/stack/include", ], @@ -29,8 +27,12 @@ cc_library_static { static_libs: [ "lib-bt-packets", "libbluetooth-types", + "libbt_shim_bridge", "libosi", ], + whole_static_libs: [ + "libcom.android.sysprop.bluetooth.wrapped", + ], shared_libs: [ "liblog", ], @@ -38,15 +40,15 @@ cc_library_static { "com.android.btservices", ], min_sdk_version: "Tiramisu", + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_avrcp", test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", - "libchrome_support_defaults", "mts_defaults", ], host_supported: true, @@ -55,6 +57,7 @@ cc_test { }, include_dirs: [ "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/stack/include", ], @@ -68,8 +71,14 @@ cc_test { "lib-bt-packets-avrcp", "lib-bt-packets-base", "libbase", + "libbluetooth-types", + "libbluetooth_gd", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", + "libchrome", "libcutils", + "libevent", "libgmock", "liblog", "libosi", @@ -78,21 +87,25 @@ cc_test { cfi: false, }, - cflags: ["-DBUILDCFG"], + cflags: [ + "-DBUILDCFG", + "-Wno-unused-parameter", + ], + header_libs: ["libbluetooth_headers"], } cc_fuzz { name: "avrcp_device_fuzz", host_supported: true, defaults: [ - "fluoride_defaults_fuzzable", - "libchrome_support_defaults", + "fluoride_defaults", ], srcs: [ "tests/avrcp_device_fuzz/avrcp_device_fuzz.cc", ], include_dirs: [ "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/packet/tests", "packages/modules/Bluetooth/system/stack/include", @@ -103,7 +116,11 @@ cc_fuzz { "lib-bt-packets-avrcp", "lib-bt-packets-base", "libbase", + "libbluetooth-types", "libbluetooth_gd", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libchrome", "libcutils", "libevent", "liblog", @@ -119,4 +136,5 @@ cc_fuzz { enabled: false, }, }, + cflags: ["-Wno-unused-parameter"], } diff --git a/system/profile/avrcp/connection_handler.cc b/system/profile/avrcp/connection_handler.cc index 11966460c6ab1b7796c40e792c2767f4e89c338b..4f2e4a97a2cca1c89bb83907a82bb305230f8954 100644 --- a/system/profile/avrcp/connection_handler.cc +++ b/system/profile/avrcp/connection_handler.cc @@ -20,9 +20,11 @@ #include #include +#include #include "avrc_defs.h" #include "avrcp_message_converter.h" +#include "internal_include/bt_target.h" #include "packet/avrcp/avrcp_packet.h" // TODO (apanicke): Remove dependency on this header once we cleanup feature // handling. @@ -31,13 +33,25 @@ #include "osi/include/allocator.h" #include "osi/include/properties.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_uuid16.h" #include "types/raw_address.h" +extern bool btif_av_peer_is_connected_sink(const RawAddress& peer_address); +extern bool btif_av_peer_is_connected_source(const RawAddress& peer_address); +extern bool btif_av_both_enable(void); +extern bool btif_av_src_sink_coexist_enabled(void); +extern bool btif_av_peer_is_source(const RawAddress& peer_address); + namespace bluetooth { namespace avrcp { ConnectionHandler* ConnectionHandler::instance_ = nullptr; +// ConnectionHandler::CleanUp take the lock and calls +// ConnectionHandler::AcceptorControlCB with AVRC_CLOSE_IND_EVT +// which also takes the lock, so use a recursive_mutex. +std::recursive_mutex device_map_lock; + ConnectionHandler* ConnectionHandler::Get() { CHECK(instance_); @@ -86,6 +100,7 @@ bool ConnectionHandler::CleanUp() { CHECK(instance_ != nullptr); // TODO (apanicke): Cleanup the SDP Entries here + std::lock_guard lock(device_map_lock); for (auto entry = instance_->device_map_.begin(); entry != instance_->device_map_.end();) { auto curr = entry; @@ -165,6 +180,7 @@ void ConnectionHandler::SetBipClientStatus(const RawAddress& bdaddr, std::vector> ConnectionHandler::GetListOfDevices() const { std::vector> list; + std::lock_guard lock(device_map_lock); for (const auto& device : device_map_) { list.push_back(device.second); } @@ -214,8 +230,8 @@ bool ConnectionHandler::AvrcpConnect(bool initiator, const RawAddress& bdaddr) { : AVRC_CONN_ACP; // 0 if initiator, 1 if 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; + 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); @@ -254,8 +270,8 @@ void ConnectionHandler::InitiatorControlCb(uint8_t handle, uint8_t event, // devices SDP is completed after the device connects AVRCP so that // information isn't very useful when trying to control our // capabilities. For now always use AVRCP 1.6. - auto&& callback = base::Bind(&ConnectionHandler::SendMessage, - base::Unretained(this), handle); + auto&& callback = base::BindRepeating(&ConnectionHandler::SendMessage, + base::Unretained(this), handle); auto&& ctrl_mtu = avrc_->GetPeerMtu(handle) - AVCT_HDR_LEN; auto&& browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN; std::shared_ptr newDevice = std::make_shared( @@ -267,10 +283,14 @@ void ConnectionHandler::InitiatorControlCb(uint8_t handle, uint8_t event, // interfaces it needs. connection_cb_.Run(newDevice); - if (feature_iter->second & BTA_AV_FEAT_ADV_CTRL) { - newDevice->RegisterVolumeChanged(); - } else if (instance_->vol_ != nullptr) { - instance_->vol_->DeviceConnected(newDevice->GetAddress()); + if (!btif_av_src_sink_coexist_enabled() || + (btif_av_src_sink_coexist_enabled() && + btif_av_peer_is_connected_sink(newDevice->GetAddress()))) { + if (feature_iter->second & BTA_AV_FEAT_ADV_CTRL) { + newDevice->RegisterVolumeChanged(); + } else if (instance_->vol_ != nullptr) { + instance_->vol_->DeviceConnected(newDevice->GetAddress()); + } } } break; @@ -283,6 +303,7 @@ void ConnectionHandler::InitiatorControlCb(uint8_t handle, uint8_t event, << "Connection Close received from device that doesn't exist"; return; } + std::lock_guard lock(device_map_lock); avrc_->Close(handle); feature_map_.erase(device_map_[handle]->GetAddress()); device_map_[handle]->DeviceDisconnected(); @@ -324,9 +345,25 @@ void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event, switch (event) { case AVRC_OPEN_IND_EVT: { LOG(INFO) << __PRETTY_FUNCTION__ << ": Connection Opened Event"; - - auto&& callback = base::Bind(&ConnectionHandler::SendMessage, - weak_ptr_factory_.GetWeakPtr(), handle); + if (peer_addr == NULL) { + return; + } + if (btif_av_src_sink_coexist_enabled() && + btif_av_peer_is_connected_source(*peer_addr)) { + LOG(WARNING) << "peer is src, close new avrcp cback"; + if (device_map_.find(handle) != device_map_.end()) { + std::lock_guard lock(device_map_lock); + feature_map_.erase(device_map_[handle]->GetAddress()); + device_map_[handle]->DeviceDisconnected(); + device_map_.erase(handle); + } + avrc_->Close(handle); + AvrcpConnect(false, RawAddress::kAny); + return; + } + auto&& callback = + base::BindRepeating(&ConnectionHandler::SendMessage, + weak_ptr_factory_.GetWeakPtr(), handle); auto&& ctrl_mtu = avrc_->GetPeerMtu(handle) - AVCT_HDR_LEN; auto&& browse_mtu = avrc_->GetBrowseMtu(handle) - AVCT_HDR_LEN; std::shared_ptr newDevice = std::make_shared( @@ -353,16 +390,30 @@ void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event, // TODO (apanicke): Report to the VolumeInterface that a new Device is // connected that doesn't support absolute volume. - if (features & BTA_AV_FEAT_ADV_CTRL) { - device->RegisterVolumeChanged(); - } else if (instance_->vol_ != nullptr) { - instance_->vol_->DeviceConnected(device->GetAddress()); + if (!btif_av_src_sink_coexist_enabled() || + (btif_av_src_sink_coexist_enabled() && + btif_av_peer_is_connected_sink(device->GetAddress()))) { + if (features & BTA_AV_FEAT_ADV_CTRL) { + device->RegisterVolumeChanged(); + } else if (instance_->vol_ != nullptr) { + instance_->vol_->DeviceConnected(device->GetAddress()); + } } }; - SdpLookup(*peer_addr, base::Bind(sdp_lambda, this, handle), false); - - avrc_->OpenBrowse(handle, AVCT_ACP); + if (SdpLookup(*peer_addr, base::Bind(sdp_lambda, this, handle), false)) { + avrc_->OpenBrowse(handle, AVCT_ACP); + } 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 + // connection. + LOG(ERROR) << __PRETTY_FUNCTION__ + << ": SDP search failed for handle: " << loghex(handle) + << ", closing connection"; + DisconnectDevice(*peer_addr); + } + // Open for the next incoming connection. The handle will not be the same + // as this one which will be closed when the device is disconnected. AvrcpConnect(false, RawAddress::kAny); } break; @@ -374,10 +425,13 @@ void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event, << "Connection Close received from device that doesn't exist"; return; } + { + std::lock_guard lock(device_map_lock); + feature_map_.erase(device_map_[handle]->GetAddress()); + device_map_[handle]->DeviceDisconnected(); + device_map_.erase(handle); + } avrc_->Close(handle); - feature_map_.erase(device_map_[handle]->GetAddress()); - device_map_[handle]->DeviceDisconnected(); - device_map_.erase(handle); } break; case AVRC_BROWSE_OPEN_IND_EVT: { @@ -414,6 +468,12 @@ void ConnectionHandler::MessageCb(uint8_t handle, uint8_t label, uint8_t opcode, auto pkt = AvrcpMessageConverter::Parse(p_msg); if (opcode == AVRC_OP_BROWSE) { + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + if (p_msg->browse.hdr.ctype == AVCT_RSP) { + VLOG(2) << "ignore response handle " << (unsigned int)handle; + return; + } + } VLOG(4) << "Browse Message received on handle " << (unsigned int)handle; device_map_[handle]->BrowseMessageReceived(label, BrowsePacket::Parse(pkt)); return; @@ -570,7 +630,8 @@ void ConnectionHandler::SendMessage( // the packet so none of these layer specific fields will be used. pkt->event = 0xFFFF; /* Handle for AVRCP fragment */ - uint16_t op_code = (uint16_t)(::bluetooth::Packet::Specialize(packet)->GetOpcode()); + uint16_t op_code = + (uint16_t)(::bluetooth::Packet::Specialize(packet)->GetOpcode()); if (!browse && (op_code == (uint16_t)(Opcode::VENDOR))) { pkt->event = op_code; } @@ -591,5 +652,20 @@ void ConnectionHandler::SendMessage( avrc_->MsgReq(handle, label, ctype, pkt); } +void ConnectionHandler::RegisterVolChanged(const RawAddress& bdaddr) { + LOG(INFO) << "Attempting to RegisterVolChanged device " << bdaddr; + for (auto it = device_map_.begin(); it != device_map_.end(); it++) { + if (bdaddr == it->second->GetAddress()) { + const auto& feature_iter = feature_map_.find(bdaddr); + if (feature_iter->second & BTA_AV_FEAT_ADV_CTRL) { + it->second->RegisterVolumeChanged(); + } else if (instance_->vol_ != nullptr) { + instance_->vol_->DeviceConnected(bdaddr); + } + break; + } + } +} + } // namespace avrcp } // namespace bluetooth diff --git a/system/profile/avrcp/connection_handler.h b/system/profile/avrcp/connection_handler.h index 58c3bbe511dc59c24642de446f0a0576615ccafd..961ed4a768fe98de7ec4a6ec35b68acbe18c0efb 100644 --- a/system/profile/avrcp/connection_handler.h +++ b/system/profile/avrcp/connection_handler.h @@ -127,6 +127,8 @@ class ConnectionHandler { */ static void InitForTesting(ConnectionHandler* handler); + virtual void RegisterVolChanged(const RawAddress& bdaddr); + private: AvrcpInterface* avrc_; SdpInterface* sdp_; diff --git a/system/profile/avrcp/device.cc b/system/profile/avrcp/device.cc index 4a8817d6546f062f385eec69cea1d6dcb19fd244..2a4cd96c147cd1338b2f3bb6386627bebca3f09a 100644 --- a/system/profile/avrcp/device.cc +++ b/system/profile/avrcp/device.cc @@ -15,9 +15,12 @@ */ #include "device.h" +#include + #include "abstract_message_loop.h" #include "avrcp_common.h" #include "connection_handler.h" +#include "internal_include/stack_config.h" #include "packet/avrcp/avrcp_reject_packet.h" #include "packet/avrcp/general_reject_packet.h" #include "packet/avrcp/get_current_player_application_setting_value.h" @@ -28,9 +31,12 @@ #include "packet/avrcp/set_absolute_volume.h" #include "packet/avrcp/set_addressed_player.h" #include "packet/avrcp/set_player_application_setting_value.h" -#include "stack_config.h" #include "types/raw_address.h" +extern bool btif_av_peer_is_connected_sink(const RawAddress& peer_address); +extern bool btif_av_both_enable(void); +extern bool btif_av_src_sink_coexist_enabled(void); + namespace bluetooth { namespace avrcp { @@ -42,12 +48,12 @@ namespace avrcp { #define VOL_NOT_SUPPORTED -1 #define VOL_REGISTRATION_FAILED -2 -Device::Device( - const RawAddress& bdaddr, bool avrcp13_compatibility, - base::Callback message)> - send_msg_cb, - uint16_t ctrl_mtu, uint16_t browse_mtu) + send_msg_cb, + uint16_t ctrl_mtu, uint16_t browse_mtu) : weak_ptr_factory_(this), address_(bdaddr), avrcp13_compatibility_(avrcp13_compatibility), @@ -68,9 +74,7 @@ void Device::RegisterInterfaces( player_settings_interface_ = player_settings_interface; } -base::WeakPtr Device::Get() { - return weak_ptr_factory_.GetWeakPtr(); -} +base::WeakPtr Device::Get() { return weak_ptr_factory_.GetWeakPtr(); } void Device::SetBrowseMtu(uint16_t browse_mtu) { DEVICE_LOG(INFO) << __PRETTY_FUNCTION__ << ": browse_mtu = " << browse_mtu; @@ -82,9 +86,7 @@ void Device::SetBipClientStatus(bool connected) { has_bip_client_ = connected; } -bool Device::HasBipClient() const { - return has_bip_client_; -} +bool Device::HasBipClient() const { return has_bip_client_; } void filter_cover_art(SongInfo& s) { for (auto it = s.attributes.begin(); it != s.attributes.end(); it++) { @@ -110,7 +112,8 @@ void Device::VendorPacketHandler(uint8_t label, if (!pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = RejectBuilder::MakeBuilder(static_cast(0), Status::INVALID_COMMAND); + auto response = RejectBuilder::MakeBuilder(static_cast(0), + Status::INVALID_COMMAND); send_message(label, false, std::move(response)); return; } @@ -127,11 +130,13 @@ void Device::VendorPacketHandler(uint8_t label, auto register_notification = Packet::Specialize(pkt); - if (!register_notification->IsValid()) { + if ((!btif_av_src_sink_coexist_enabled() || + (btif_av_src_sink_coexist_enabled() && + register_notification->GetEvent() == Event::VOLUME_CHANGED)) && + !register_notification->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = - RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), - Status::INVALID_PARAMETER); + auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), + Status::INVALID_PARAMETER); send_message(label, false, std::move(response)); active_labels_.erase(label); volume_interface_ = nullptr; @@ -173,16 +178,19 @@ void Device::VendorPacketHandler(uint8_t label, } break; case CommandPdu::GET_ELEMENT_ATTRIBUTES: { - auto get_element_attributes_request_pkt = Packet::Specialize(pkt); + auto get_element_attributes_request_pkt = + Packet::Specialize(pkt); if (!get_element_attributes_request_pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER); + auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), + Status::INVALID_PARAMETER); send_message(label, false, std::move(response)); return; } - media_interface_->GetSongInfo(base::Bind(&Device::GetElementAttributesResponse, weak_ptr_factory_.GetWeakPtr(), - label, get_element_attributes_request_pkt)); + media_interface_->GetSongInfo(base::Bind( + &Device::GetElementAttributesResponse, weak_ptr_factory_.GetWeakPtr(), + label, get_element_attributes_request_pkt)); } break; case CommandPdu::GET_PLAY_STATUS: { @@ -200,17 +208,20 @@ void Device::VendorPacketHandler(uint8_t label, // this currently since the current implementation only has one // player and the player will never change, but we need it for a // more complete implementation. - auto set_addressed_player_request = Packet::Specialize(pkt); + auto set_addressed_player_request = + Packet::Specialize(pkt); if (!set_addressed_player_request->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER); + auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), + Status::INVALID_PARAMETER); send_message(label, false, std::move(response)); return; } - media_interface_->GetMediaPlayerList(base::Bind(&Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(), - label, set_addressed_player_request)); + media_interface_->GetMediaPlayerList(base::Bind( + &Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(), + label, set_addressed_player_request)); } break; case CommandPdu::LIST_PLAYER_APPLICATION_SETTING_ATTRIBUTES: { @@ -393,7 +404,8 @@ void Device::HandleGetCapabilities( if (!pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER); + auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), + Status::INVALID_PARAMETER); send_message(label, false, std::move(response)); return; } @@ -568,8 +580,8 @@ void Device::HandleVolumeChanged( if (pkt->GetCType() == CType::REJECTED) { // Disable Absolute Volume active_labels_.erase(label); - volume_interface_ = nullptr; volume_ = VOL_REGISTRATION_FAILED; + volume_interface_->DeviceConnected(GetAddress()); return; } @@ -857,7 +869,8 @@ void Device::GetElementAttributesResponse( void Device::MessageReceived(uint8_t label, std::shared_ptr pkt) { if (!pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = RejectBuilder::MakeBuilder(static_cast(0), Status::INVALID_COMMAND); + auto response = RejectBuilder::MakeBuilder(static_cast(0), + Status::INVALID_COMMAND); send_message(label, false, std::move(response)); return; } @@ -873,15 +886,17 @@ void Device::MessageReceived(uint8_t label, std::shared_ptr pkt) { } break; case Opcode::PASS_THROUGH: { /** Newavrcp not passthrough response pkt. @{ */ - if (pkt->GetCType() == CType::ACCEPTED || pkt->GetCType() == CType::REJECTED - || pkt->GetCType() == CType::NOT_IMPLEMENTED) + if (pkt->GetCType() == CType::ACCEPTED || + pkt->GetCType() == CType::REJECTED || + pkt->GetCType() == CType::NOT_IMPLEMENTED) break; /** @} */ auto pass_through_packet = Packet::Specialize(pkt); if (!pass_through_packet->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = RejectBuilder::MakeBuilder(static_cast(0), Status::INVALID_COMMAND); + auto response = RejectBuilder::MakeBuilder(static_cast(0), + Status::INVALID_COMMAND); send_message(label, false, std::move(response)); return; } @@ -938,7 +953,8 @@ void Device::HandlePlayItem(uint8_t label, if (!pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER); + auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), + Status::INVALID_PARAMETER); send_message(label, false, std::move(response)); return; } @@ -1104,7 +1120,8 @@ void Device::BrowseMessageReceived(uint8_t label, break; default: DEVICE_LOG(WARNING) << __func__ << ": " << pkt->GetPdu(); - auto response = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND); + auto response = + GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND); send_message(label, true, std::move(response)); break; @@ -1115,9 +1132,10 @@ void Device::HandleGetFolderItems(uint8_t label, std::shared_ptr pkt) { if (!pkt->IsValid()) { // The specific get folder items builder is unimportant on failure. - DEVICE_LOG(WARNING) << __func__ << ": Get folder items request packet is not valid"; - auto response = - GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0x0000, browse_mtu_); + DEVICE_LOG(WARNING) << __func__ + << ": Get folder items request packet is not valid"; + auto response = GetFolderItemsResponseBuilder::MakePlayerListBuilder( + Status::INVALID_PARAMETER, 0x0000, browse_mtu_); send_message(label, true, std::move(response)); return; } @@ -1143,7 +1161,8 @@ void Device::HandleGetFolderItems(uint8_t label, break; default: DEVICE_LOG(ERROR) << __func__ << ": " << pkt->GetScope(); - auto response = GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0, browse_mtu_); + auto response = GetFolderItemsResponseBuilder::MakePlayerListBuilder( + Status::INVALID_PARAMETER, 0, browse_mtu_); send_message(label, true, std::move(response)); break; } @@ -1153,7 +1172,8 @@ void Device::HandleGetTotalNumberOfItems( uint8_t label, std::shared_ptr pkt) { if (!pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0); + auto response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder( + Status::INVALID_PARAMETER, 0x0000, 0); send_message(label, true, std::move(response)); return; } @@ -1215,7 +1235,8 @@ void Device::HandleChangePath(uint8_t label, std::shared_ptr pkt) { if (!pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = ChangePathResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0); + auto response = + ChangePathResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0); send_message(label, true, std::move(response)); return; } @@ -1272,7 +1293,8 @@ void Device::HandleGetItemAttributes( uint8_t label, std::shared_ptr pkt) { if (!pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto builder = GetItemAttributesResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, browse_mtu_); + auto builder = GetItemAttributesResponseBuilder::MakeBuilder( + Status::INVALID_PARAMETER, browse_mtu_); send_message(label, true, std::move(builder)); return; } @@ -1586,7 +1608,8 @@ void Device::HandleSetBrowsedPlayer( uint8_t label, std::shared_ptr pkt) { if (!pkt->IsValid()) { DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid"; - auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0, 0, ""); + auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder( + Status::INVALID_PARAMETER, 0x0000, 0, 0, ""); send_message(label, true, std::move(response)); return; } @@ -1839,6 +1862,11 @@ void Device::DeviceDisconnected() { // remove these conditionals. if (volume_interface_ != nullptr) volume_interface_->DeviceDisconnected(GetAddress()); + // The volume at connection is set by the remote device when indicating + // that it supports absolute volume, in case it's not, we need + // to reset the local volume var to be sure we send the correct value + // to the remote device on the next connection. + volume_ = VOL_NOT_SUPPORTED; } static std::string volumeToStr(int8_t volume) { @@ -1850,29 +1878,25 @@ static std::string volumeToStr(int8_t volume) { std::ostream& operator<<(std::ostream& out, const Device& d) { // TODO: whether this should be turned into LOGGABLE STRING? - out << ADDRESS_TO_LOGGABLE_STR(d.address_); + out << " " << ADDRESS_TO_LOGGABLE_STR(d.address_); if (d.IsActive()) out << " "; out << std::endl; - ScopedIndent indent(out); - out << "Current Volume: " << volumeToStr(d.volume_) << std::endl; - out << "Current Browsed Player ID: " << d.curr_browsed_player_id_ + out << " Current Volume: " << volumeToStr(d.volume_) << std::endl; + out << " Current Browsed Player ID: " << d.curr_browsed_player_id_ << std::endl; - out << "Registered Notifications:\n"; - { - ScopedIndent indent(out); - if (d.track_changed_.first) out << "Track Changed\n"; - if (d.play_status_changed_.first) out << "Play Status\n"; - if (d.play_pos_changed_.first) out << "Play Position\n"; - if (d.player_setting_changed_.first) out << "Player Setting Changed\n"; - if (d.now_playing_changed_.first) out << "Now Playing\n"; - if (d.addr_player_changed_.first) out << "Addressed Player\n"; - if (d.avail_players_changed_.first) out << "Available Players\n"; - if (d.uids_changed_.first) out << "UIDs Changed\n"; - } - out << "Last Play State: " << d.last_play_status_.state << std::endl; - out << "Last Song Sent ID: \"" << d.last_song_info_.media_id << "\"\n"; - out << "Current Folder: \"" << d.CurrentFolder() << "\"\n"; - out << "MTU Sizes: CTRL=" << d.ctrl_mtu_ << " BROWSE=" << d.browse_mtu_ + out << " Registered Notifications:\n"; + if (d.track_changed_.first) out << " Track Changed\n"; + if (d.play_status_changed_.first) out << " Play Status\n"; + if (d.play_pos_changed_.first) out << " Play Position\n"; + if (d.player_setting_changed_.first) out << " Player Setting Changed\n"; + if (d.now_playing_changed_.first) out << " Now Playing\n"; + if (d.addr_player_changed_.first) out << " Addressed Player\n"; + if (d.avail_players_changed_.first) out << " Available Players\n"; + if (d.uids_changed_.first) out << " UIDs Changed\n"; + out << " Last Play State: " << d.last_play_status_.state << std::endl; + out << " Last Song Sent ID: \"" << d.last_song_info_.media_id << "\"\n"; + out << " Current Folder: \"" << d.CurrentFolder() << "\"\n"; + out << " MTU Sizes: CTRL=" << d.ctrl_mtu_ << " BROWSE=" << d.browse_mtu_ << std::endl; // TODO (apanicke): Add supported features as well as media keys return out; diff --git a/system/profile/avrcp/device.h b/system/profile/avrcp/device.h index c3d6e4df74604d789d67a7b593e42d50e9545beb..e056d021ad6081f44abed870eef6bfb3badd5eef 100644 --- a/system/profile/avrcp/device.h +++ b/system/profile/avrcp/device.h @@ -63,12 +63,12 @@ class Device { */ friend class ConnectionHandler; - Device( - const RawAddress& bdaddr, bool avrcp13_compatibility, - base::Callback message)> - send_msg_cb, - uint16_t ctrl_mtu, uint16_t browse_mtu); + Device(const RawAddress& bdaddr, bool avrcp13_compatibility, + base::RepeatingCallback< + void(uint8_t label, bool browse, + std::unique_ptr<::bluetooth::PacketBuilder> message)> + send_msg_cb, + uint16_t ctrl_mtu, uint16_t browse_mtu); Device(const Device&) = delete; Device& operator=(const Device&) = delete; @@ -334,8 +334,9 @@ class Device { // Enables AVRCP 1.3 Compatibility mode. This disables any AVRCP 1.4+ features // such as browsing and playlists but has the highest chance of working. bool avrcp13_compatibility_ = false; - base::Callback message)> + base::RepeatingCallback message)> send_message_cb_; uint16_t ctrl_mtu_; uint16_t browse_mtu_; diff --git a/system/profile/avrcp/tests/avrcp_connection_handler_test.cc b/system/profile/avrcp/tests/avrcp_connection_handler_test.cc index 9a02d8eb3d69a0fd1ec28a9e88e8302821eeb2c2..4dbc79338b7d76d3769e23925a37fd97f0252e3f 100644 --- a/system/profile/avrcp/tests/avrcp_connection_handler_test.cc +++ b/system/profile/avrcp/tests/avrcp_connection_handler_test.cc @@ -35,6 +35,14 @@ using ::testing::SaveArgPointee; using ::testing::SetArgPointee; using ::testing::StrictMock; +bool btif_av_peer_is_connected_sink(const RawAddress& peer_address) { + return true; +} +bool btif_av_peer_is_connected_source(const RawAddress& peer_address) { + return false; +} +bool btif_av_both_enable(void) { return false; } + namespace bluetooth { namespace avrcp { @@ -159,8 +167,10 @@ TEST_F(AvrcpConnectionHandlerTest, disconnectAfterCleanupTest) { conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny); }; -// Check that we can handle having a remote device connect to us, start SDP, and -// open another acceptor connection +/** + * Check that we can handle having a remote device connect to us, start SDP, and + * open another acceptor connection. + */ TEST_F(AvrcpConnectionHandlerTest, remoteDeviceConnectionTest) { // Set an Expectation that Open will be called twice as an acceptor and save // the connection callback once it is called. @@ -203,8 +213,10 @@ TEST_F(AvrcpConnectionHandlerTest, remoteDeviceConnectionTest) { ConnectionHandler::CleanUp(); } -// Check that when a device does not support absolute volume, that the -// handler reports that via the volume interface. +/** + * Check that when a device does not support absolute volume, that the + * handler reports that via the volume interface. + */ TEST_F(AvrcpConnectionHandlerTest, noAbsoluteVolumeTest) { // Set an Expectation that Open will be called twice as an acceptor and save // the connection callback once it is called. @@ -239,8 +251,10 @@ TEST_F(AvrcpConnectionHandlerTest, noAbsoluteVolumeTest) { ConnectionHandler::CleanUp(); } -// Check that when a device does support absolute volume, that the handler -// doesn't report it. Instead that will be left up to the device. +/** + * Check that when a device does support absolute volume, that the handler + * doesn't report it. Instead that will be left up to the device. + */ TEST_F(AvrcpConnectionHandlerTest, absoluteVolumeTest) { // Set an Expectation that Open will be called twice as an acceptor and save // the connection callback once it is called. @@ -307,8 +321,10 @@ TEST_F(AvrcpConnectionHandlerTest, disconnectTest) { ConnectionHandler::CleanUp(); } -// Check that we can handle having a remote device connect to us, start SDP, and -// open another acceptor connection +/** + * Check that we can handle having a remote device connect to us, start SDP, and + * open another acceptor connection. + */ TEST_F(AvrcpConnectionHandlerTest, multipleRemoteDeviceConnectionTest) { // Set an Expectation that Open will be called three times as an acceptor and // save the connection callback once it is called. @@ -527,5 +543,105 @@ TEST_F(AvrcpConnectionHandlerTest, disconnectWhileDoingSdpTest) { ConnectionHandler::CleanUp(); } +/** + * Check that when an incoming connection happens at the same time as the + * that the SDP search for initiator is running the collision is handled. + */ +TEST_F(AvrcpConnectionHandlerTest, connectionCollisionTest) { + tAVRC_CONN_CB conn_cb; + EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny)) + .Times(2) + .WillOnce( + DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0))) + .WillOnce( + DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0))); + + // Initialize the interface + auto bound_callback = base::Bind(&MockFunction::Call, + base::Unretained(&device_cb)); + ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_, + &mock_sdp_, &mock_volume_)); + connection_handler_ = ConnectionHandler::Get(); + + // Check that the callback was sent with us as the acceptor + ASSERT_EQ(conn_cb.conn, 1); + + // Set an Expectations that SDP will be performed + tAVRC_FIND_CBACK sdp_cb; + SetUpSdp(&sdp_cb, false, false); + + connection_handler_->ConnectDevice(RawAddress::kAny); + + // Set an expectation that a device will be created + EXPECT_CALL(device_cb, Call(_)).Times(1); + + // Set an Expectations that SDP search will be performed again but will fail + EXPECT_CALL(mock_avrcp_, FindService(_, _, _, _)) + .Times(1) + .WillOnce(DoAll(SaveArg<3>(&sdp_cb), Return(1))); + + // Set an expectation that the incoming connection will be closed + EXPECT_CALL(mock_avrcp_, Close(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); + + // Set an expectation that cleanup will close the last connection + EXPECT_CALL(mock_avrcp_, Close(_)); + + // Run the SDP callback with status success + sdp_cb.Run(0); + + connection_handler_ = nullptr; + ConnectionHandler::CleanUp(); +} + +/** + * Check that we are not proceeding with the connection if the SDP search + * failed. + */ +TEST_F(AvrcpConnectionHandlerTest, acceptorSdpSearchFailTest) { + // Set an Expectation that Open will be called twice as an acceptor and + // save the connection callback once it is called. + tAVRC_CONN_CB conn_cb; + EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny)) + .Times(2) + .WillOnce( + DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0))) + .WillOnce( + DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0))); + + // Initialize the interface + auto bound_callback = base::Bind(&MockFunction::Call, + base::Unretained(&device_cb)); + ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_, + &mock_sdp_, &mock_volume_)); + connection_handler_ = ConnectionHandler::Get(); + + // Check that the callback was sent with us as the acceptor + ASSERT_EQ(conn_cb.conn, 1); + + // Set an expectation that a device will be created + EXPECT_CALL(device_cb, Call(_)).Times(1); + + // Set an expectation that SDP search will be performed but will fail + tAVRC_FIND_CBACK sdp_cb; + EXPECT_CALL(mock_avrcp_, FindService(_, _, _, _)) + .Times(1) + .WillOnce(DoAll(SaveArg<3>(&sdp_cb), Return(1))); + + // Set an expectation that the incoming connection will be closed + EXPECT_CALL(mock_avrcp_, Close(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); + + // Set an expectation that cleanup will close the last connection + EXPECT_CALL(mock_avrcp_, Close(_)); + + connection_handler_ = nullptr; + ConnectionHandler::CleanUp(); +} + } // namespace avrcp } // namespace bluetooth diff --git a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc index 763acc14905bd1ad735e3410cb4e9fa713274291..df91e77b3943dcf10e93b38139c70bfbc34e9b04 100644 --- a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc +++ b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc @@ -3,10 +3,12 @@ #include "avrcp_packet.h" #include "device.h" +#include "internal_include/stack_config.h" #include "packet_test_helper.h" -#include "stack_config.h" #include "types/raw_address.h" +bool btif_av_src_sink_coexist_enabled(void) { return true; } + namespace bluetooth { namespace avrcp { class FakeMediaInterface : public MediaInterface { @@ -67,17 +69,27 @@ class FakeA2dpInterface : public A2dpInterface { bool get_pts_avrcp_test(void) { return false; } -const stack_config_t interface = {nullptr, get_pts_avrcp_test, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, +const stack_config_t interface = {get_pts_avrcp_test, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, nullptr}; void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {} @@ -89,10 +101,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { FakePlayerSettingsInterface fpsi; std::vector Packet(Data, Data + Size); - Device device(RawAddress::kAny, true, - base::Bind([](uint8_t, bool, - std::unique_ptr<::bluetooth::PacketBuilder>) {}), - 0xFFFF, 0xFFFF); + Device device( + RawAddress::kAny, true, + base::BindRepeating( + [](uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}), + 0xFFFF, 0xFFFF); device.RegisterInterfaces(&fmi, &fai, &fvi, &fpsi); auto browse_request = TestPacketType::Make(Packet); diff --git a/system/profile/avrcp/tests/avrcp_device_test.cc b/system/profile/avrcp/tests/avrcp_device_test.cc index ab6e355c5320dbb663dc4f15e51ed924a59ea451..7216a5dbf025919175b59bc37954984db99e133f 100644 --- a/system/profile/avrcp/tests/avrcp_device_test.cc +++ b/system/profile/avrcp/tests/avrcp_device_test.cc @@ -26,11 +26,13 @@ #include "avrcp_packet.h" #include "avrcp_test_helper.h" #include "device.h" -#include "stack_config.h" +#include "internal_include/stack_config.h" #include "tests/avrcp/avrcp_test_packets.h" #include "tests/packet_test_helper.h" #include "types/raw_address.h" +bool btif_av_src_sink_coexist_enabled(void) { return true; } + namespace bluetooth { namespace avrcp { @@ -50,17 +52,27 @@ using ::testing::SaveArg; bool get_pts_avrcp_test(void) { return false; } -const stack_config_t interface = {nullptr, get_pts_avrcp_test, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, - nullptr, nullptr, +const stack_config_t interface = {get_pts_avrcp_test, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, nullptr}; // TODO (apanicke): All the tests below are just basic positive unit tests. @@ -71,10 +83,11 @@ class AvrcpDeviceTest : public ::testing::Test { // NOTE: We use a wrapper lambda for the MockFunction in order to // add a const qualifier to the response. Otherwise the MockFunction // type doesn't match the callback type and a compiler error occurs. - base::Callback cb = base::Bind( - [](MockFunction* a, - uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, - &response_cb); + base::RepeatingCallback cb = + base::BindRepeating( + [](MockFunction* a, + uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, + &response_cb); // TODO (apanicke): Test setting avrc13 to false once we have full // functionality. @@ -112,10 +125,11 @@ class AvrcpDeviceTest : public ::testing::Test { }; TEST_F(AvrcpDeviceTest, addressTest) { - base::Callback cb = - base::Bind([](MockFunction* a, - uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, - &response_cb); + base::RepeatingCallback cb = + base::BindRepeating( + [](MockFunction* a, + uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, + &response_cb); Device device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF); ASSERT_EQ(device.GetAddress(), RawAddress::kAny); @@ -791,10 +805,11 @@ TEST_F(AvrcpDeviceTest, getElementAttributesMtuTest) { MockMediaInterface interface; NiceMock a2dp_interface; - base::Callback cb = - base::Bind([](MockFunction* a, - uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, - &response_cb); + base::RepeatingCallback cb = + base::BindRepeating( + [](MockFunction* a, + uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, + &response_cb); Device device(RawAddress::kAny, true, cb, truncated_packet->size(), 0xFFFF); device.RegisterInterfaces(&interface, &a2dp_interface, nullptr, nullptr); @@ -1014,10 +1029,11 @@ TEST_F(AvrcpDeviceTest, getFolderItemsMtuTest) { MockMediaInterface interface; NiceMock a2dp_interface; - base::Callback cb = - base::Bind([](MockFunction* a, - uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, - &response_cb); + base::RepeatingCallback cb = + base::BindRepeating( + [](MockFunction* a, + uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, + &response_cb); Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size() + FolderItem::kHeaderSize() + 5); @@ -1255,10 +1271,11 @@ TEST_F(AvrcpDeviceTest, getItemAttributesMtuTest) { MockMediaInterface interface; NiceMock a2dp_interface; - base::Callback cb = - base::Bind([](MockFunction* a, - uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, - &response_cb); + base::RepeatingCallback cb = + base::BindRepeating( + [](MockFunction* a, + uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, + &response_cb); Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size()); device.RegisterInterfaces(&interface, &a2dp_interface, nullptr, nullptr); @@ -1462,6 +1479,21 @@ TEST_F(AvrcpDeviceTest, setVolumeOnceTest) { test_device->SetVolume(vol); } +TEST_F(AvrcpDeviceTest, setVolumeAfterReconnectionTest) { + int vol = 0x48; + + auto set_abs_vol = SetAbsoluteVolumeRequestBuilder::MakeBuilder(vol); + + // Ensure that SetVolume is called twice as DeviceDisconnected will + // reset the previous stored volume. + EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(set_abs_vol)))) + .Times(2); + + test_device->SetVolume(vol); + test_device->DeviceDisconnected(); + test_device->SetVolume(vol); +} + TEST_F(AvrcpDeviceTest, playPushedActiveDeviceTest) { MockMediaInterface interface; NiceMock a2dp_interface; diff --git a/system/profile/sdp/Android.bp b/system/profile/sdp/Android.bp index 8bc5e1d1d0e8040a21b0351b0c6ad2cd44a0731b..a076f462f9ebdf50137efa817eb9b426b9020594 100644 --- a/system/profile/sdp/Android.bp +++ b/system/profile/sdp/Android.bp @@ -15,6 +15,7 @@ cc_library_static { host_supported: true, include_dirs: [ "packages/modules/Bluetooth/system/", + "packages/modules/Bluetooth/system/gd", ], srcs: [ "common/data_element_reader.cc", @@ -23,13 +24,13 @@ cc_library_static { "lib-bt-packets", "libbluetooth-types", ], + header_libs: ["libbluetooth_headers"], } cc_test { name: "bluetooth_test_sdp", test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -49,4 +50,5 @@ cc_test { "libgmock", "sdp_service", ], + shared_libs: ["liblog"], } diff --git a/system/profile/sdp/common/data_element_reader.h b/system/profile/sdp/common/data_element_reader.h index 13346bd8838e88c2e99bcf9051f819ed3e2382a8..5b4d770a2685a6ab437a42b4c3e60b2f39718489 100644 --- a/system/profile/sdp/common/data_element_reader.h +++ b/system/profile/sdp/common/data_element_reader.h @@ -22,7 +22,7 @@ #include "bluetooth/uuid.h" #include "packet.h" #include "sdp_common.h" -#include "stack/include/bt_types.h" +#include "stack/include/bt_octets.h" namespace bluetooth { namespace sdp { diff --git a/system/profile/sdp/sdp_logging_helper.h b/system/profile/sdp/sdp_logging_helper.h index e94732986856a968dc4efcc553bf9d9cf0d1cf3f..253ce925c3c86b2b6904586ee8bf1619428eecef 100644 --- a/system/profile/sdp/sdp_logging_helper.h +++ b/system/profile/sdp/sdp_logging_helper.h @@ -22,18 +22,13 @@ #include #include -#include "bt_trace.h" +#include "internal_include/bt_trace.h" +#include "macros.h" #include "sdp_common.h" namespace bluetooth { namespace sdp { -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string PduIdText(const PduId& id) { switch (id) { CASE_RETURN_TEXT(PduId::RESERVED); diff --git a/system/rust/Android.bp b/system/rust/Android.bp index 153d5e9490a881f919e89b7642e596bfc075d6e7..925ec1bd3ecec3286f01d3a0237110b0a5fa95b0 100644 --- a/system/rust/Android.bp +++ b/system/rust/Android.bp @@ -36,7 +36,7 @@ rust_defaults { rustlibs: [ "libanyhow", "libbitflags", - "libbt_common", + "libbt_common_only_init_flags", "libcxx", "liblog_rust", "libscopeguard", @@ -109,9 +109,7 @@ rust_test_host { cc_library_static { name: "libbluetooth_core_rs_bridge", - defaults: [ - "libchrome_support_defaults", - ], + defaults: ["bluetooth_cflags"], srcs: [ "src/connection/ffi/connection_shim.cc", "src/core/ffi/module.cc", @@ -120,7 +118,6 @@ cc_library_static { include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/include", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/stack/include", @@ -128,9 +125,10 @@ cc_library_static { ], export_include_dirs: ["."], static_libs: [ + "libbluetooth_hci_pdl", "libbt_shim_bridge", "libbt_shim_ffi", - + "libchrome", "libflatbuffers-cpp", ], generated_headers: [ @@ -139,7 +137,6 @@ cc_library_static { "BluetoothGeneratedBundlerSchema_h_bfbs", "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], export_generated_headers: [ "libbluetooth_core_rs_bridge_codegen_header", diff --git a/system/rust/BUILD.gn b/system/rust/BUILD.gn index f61804a10dcf6832e8fac45e5cd700794ed4da0e..bc6e7912a5be5c70d44db1625b2c038cd880bf37 100644 --- a/system/rust/BUILD.gn +++ b/system/rust/BUILD.gn @@ -42,7 +42,7 @@ static_library("core_rs") { deps = [ ":cxxlibheader", "//bt/system/gd/rust/shim:init_flags_bridge_header", - "//bt/system/gd:BluetoothGeneratedPackets_h", + "//bt/system/pdl:BluetoothGeneratedPackets_h", ] defines = [ diff --git a/system/rust/Cargo.toml b/system/rust/Cargo.toml index 3067f27d1e250fd471812cccc298bafba79b46a3..995749f781d4463bc99b6b31b82373a5b190397d 100644 --- a/system/rust/Cargo.toml +++ b/system/rust/Cargo.toml @@ -31,10 +31,14 @@ android_logger = "*" jni = "*" paste = "*" async-trait = "*" +pdl-runtime = "0.2.2" tokio-test = "0.4.2" tokio = { version = "1.23.0", features = ["macros"] } scopeguard = "1.1.0" +[build-dependencies] +pdl-compiler = "0.2.2" + [lib] crate-type = ["rlib"] diff --git a/system/rust/build.rs b/system/rust/build.rs index c4ccf5c05e2d71107758b8de7fc2b1c84634eeb9..c296fb8e0ba972f2bf8e9639825eb5c7a754c8ee 100644 --- a/system/rust/build.rs +++ b/system/rust/build.rs @@ -1,33 +1,22 @@ //! Build file to generate packets //! -//! Run `cargo install .` in `tools/pdl` to ensure `pdl` is in your -//! path. -use std::{ - env, - fs::File, - path::Path, - process::{Command, Stdio}, -}; +//! Run `cargo install --path .` in `external/rust/crates/pdl-compiler` to ensure `pdlc` +//! is in your path. +use pdl_compiler; +use std::{env, fs::File, io::Write, path::Path}; fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("_packets.rs"); - let dest_file = File::create(dest_path).unwrap(); + let mut dest_file = File::create(dest_path).unwrap(); - let pdl = Command::new("pdl") - .args(["--output-format", "rust_no_alloc", "src/packets.pdl"]) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); + let mut sources = pdl_compiler::ast::SourceDatabase::new(); + let file = pdl_compiler::parser::parse_file(&mut sources, "src/packets.pdl") + .expect("failed to parse input pdl file"); + let schema = pdl_compiler::backends::intermediate::generate(&file).unwrap(); - let mut rustfmt = - Command::new("rustfmt").stdin(pdl.stdout.unwrap()).stdout(dest_file).spawn().unwrap(); - - rustfmt.wait().unwrap(); - - if let Some(err) = rustfmt.stderr { - panic!("{err:?}"); - } + let generated = pdl_compiler::backends::rust_no_allocation::generate(&file, &schema).unwrap(); + dest_file.write_all(generated.as_bytes()).unwrap(); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=src/packets.pdl"); diff --git a/system/rust/src/connection/ffi.rs b/system/rust/src/connection/ffi.rs index 651af1ff36f4a2917a003026476d533465f28000..012045f0e304a82cc8dc6eab4f43a67533d87ae9 100644 --- a/system/rust/src/connection/ffi.rs +++ b/system/rust/src/connection/ffi.rs @@ -11,7 +11,7 @@ use tokio::{ task::spawn_local, }; -use crate::{core::address::AddressWithType, do_in_rust_thread}; +use crate::do_in_rust_thread; use super::{ attempt_manager::ConnectionMode, @@ -19,12 +19,14 @@ use super::{ ConnectionManagerClient, LeConnection, }; +// SAFETY: `LeAclManagerShim` can be passed between threads. unsafe impl Send for LeAclManagerShim {} #[cxx::bridge] #[allow(clippy::needless_lifetimes)] #[allow(clippy::too_many_arguments)] #[allow(missing_docs)] +#[allow(unsafe_op_in_unsafe_fn)] mod inner { impl UniquePtr {} diff --git a/system/rust/src/connection/ffi/connection_shim.cc b/system/rust/src/connection/ffi/connection_shim.cc index ab7247c46c893f30fbf40f49ea90b1b3ae43a04d..5c5b227aeefc8418c60e14b06b09f59540d154c4 100644 --- a/system/rust/src/connection/ffi/connection_shim.cc +++ b/system/rust/src/connection/ffi/connection_shim.cc @@ -29,9 +29,6 @@ #include "src/core/ffi/types.h" #include "stack/btm/btm_dev.h" -extern const tBLE_BD_ADDR convert_to_address_with_type( - const RawAddress& bd_addr, const tBTM_SEC_DEV_REC* p_dev_rec); - namespace bluetooth { namespace connection { @@ -177,8 +174,7 @@ void RegisterRustApis( } core::AddressWithType ResolveRawAddress(RawAddress bd_addr) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - tBLE_BD_ADDR address = convert_to_address_with_type(bd_addr, p_dev_rec); + tBLE_BD_ADDR address = BTM_Sec_GetAddressWithType(bd_addr); return core::ToRustAddress(address); } diff --git a/system/rust/src/core/ffi.rs b/system/rust/src/core/ffi.rs index 83d10d06733f3c97f25fe9466f3d51ab792630fc..e69002def94c210c9cfd39c1482169078e2e686d 100644 --- a/system/rust/src/core/ffi.rs +++ b/system/rust/src/core/ffi.rs @@ -12,12 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +// TODO(b/290018030): Remove this and add proper safety comments. +#![allow(clippy::undocumented_unsafe_blocks)] + use crate::core::{start, stop}; use cxx::{type_id, ExternType}; pub use inner::*; +// SAFETY: `GattServerCallbacks` can be passed between threads. unsafe impl Send for GattServerCallbacks {} + +// SAFETY: `future_t` can be passed between threads. unsafe impl Send for Future {} unsafe impl ExternType for Uuid { @@ -30,7 +36,7 @@ unsafe impl ExternType for AddressWithType { type Kind = cxx::kind::Trivial; } -#[allow(dead_code, missing_docs)] +#[allow(dead_code, missing_docs, unsafe_op_in_unsafe_fn)] #[cxx::bridge] mod inner { #[derive(Debug)] diff --git a/system/rust/src/gatt/arbiter.rs b/system/rust/src/gatt/arbiter.rs index 26a8d3319eb385a4f67844bbb2b6b381b7783228..77a3867d02ace02cc14a9cc3abc9e13012a21164 100644 --- a/system/rust/src/gatt/arbiter.rs +++ b/system/rust/src/gatt/arbiter.rs @@ -1,9 +1,10 @@ //! This module handles "arbitration" of ATT packets, to determine whether they -//! should be handled by the primary stack or by the "Private GATT" stack +//! should be handled by the primary stack or by the Rust stack -use std::{collections::HashMap, sync::Mutex}; +use std::sync::{Arc, Mutex}; -use log::{error, info, trace}; +use log::{error, trace, warn}; +use std::sync::RwLock; use crate::{ do_in_rust_thread, @@ -12,25 +13,20 @@ use crate::{ use super::{ ffi::{InterceptAction, StoreCallbacksFromRust}, - ids::{AdvertiserId, ConnectionId, ServerId, TransportIndex}, + ids::{AdvertiserId, TransportIndex}, mtu::MtuEvent, opcode_types::{classify_opcode, OperationType}, + server::isolation_manager::IsolationManager, }; -static ARBITER: Mutex> = Mutex::new(None); - -/// This class is responsible for tracking which connections and advertising we -/// own, and using this information to decide what packets should be -/// intercepted, and which should be forwarded to the legacy stack. -#[derive(Default)] -pub struct Arbiter { - advertiser_to_server: HashMap, - transport_to_owned_connection: HashMap, -} +static ARBITER: RwLock>>> = RwLock::new(None); /// Initialize the Arbiter -pub fn initialize_arbiter() { - *ARBITER.lock().unwrap() = Some(Arbiter::new()); +pub fn initialize_arbiter() -> Arc> { + let arbiter = Arc::new(Mutex::new(IsolationManager::new())); + let mut lock = ARBITER.write().unwrap(); + assert!(lock.is_none(), "Rust stack should only start up once"); + *lock = Some(arbiter.clone()); StoreCallbacksFromRust( on_le_connect, @@ -40,121 +36,57 @@ pub fn initialize_arbiter() { |tcb_idx, mtu| on_mtu_event(TransportIndex(tcb_idx), MtuEvent::IncomingResponse(mtu)), |tcb_idx, mtu| on_mtu_event(TransportIndex(tcb_idx), MtuEvent::IncomingRequest(mtu)), ); + + arbiter +} + +/// Clean the Arbiter +pub fn clean_arbiter() { + let mut lock = ARBITER.write().unwrap(); + *lock = None } /// Acquire the mutex holding the Arbiter and provide a mutable reference to the /// supplied closure -pub fn with_arbiter(f: impl FnOnce(&mut Arbiter) -> T) -> T { - f(ARBITER.lock().unwrap().as_mut().unwrap()) +pub fn with_arbiter(f: impl FnOnce(&mut IsolationManager) -> T) -> T { + f(ARBITER.read().unwrap().as_ref().expect("Rust stack is not started").lock().as_mut().unwrap()) } -impl Arbiter { - /// Constructor - pub fn new() -> Self { - Arbiter { - advertiser_to_server: HashMap::new(), - transport_to_owned_connection: HashMap::new(), - } - } - - /// Link a given GATT server to an LE advertising set, so incoming - /// connections to this advertiser will be visible only by the linked - /// server - pub fn associate_server_with_advertiser( - &mut self, - server_id: ServerId, - advertiser_id: AdvertiserId, - ) { - info!("associating server {server_id:?} with advertising set {advertiser_id:?}"); - let old = self.advertiser_to_server.insert(advertiser_id, server_id); - if let Some(old) = old { - error!("new server {server_id:?} associated with same advertiser {advertiser_id:?}, displacing old server {old:?}"); - } - } +/// Check if the Arbiter is initialized. +pub fn has_arbiter() -> bool { + ARBITER.read().unwrap().is_some() +} - /// Remove all linked advertising sets from the provided server - pub fn clear_server(&mut self, server_id: ServerId) { - info!("clearing advertisers associated with {server_id:?}"); - self.advertiser_to_server.retain(|_, server| *server != server_id); - } +/// Test to see if a buffer contains a valid ATT packet with an opcode we +/// are interested in intercepting (those intended for servers that are isolated) +fn try_parse_att_server_packet( + isolation_manager: &IsolationManager, + tcb_idx: TransportIndex, + packet: Box<[u8]>, +) -> Option { + isolation_manager.get_server_id(tcb_idx)?; - /// Clear the server associated with this advertiser, if one exists - pub fn clear_advertiser(&mut self, advertiser_id: AdvertiserId) { - info!("removing server (if any) associated with advertiser {advertiser_id:?}"); - self.advertiser_to_server.remove(&advertiser_id); - } + let att = OwnedAttView::try_parse(packet).ok()?; - /// Check if this conn_id is currently owned by the Rust stack - pub fn is_connection_isolated(&self, conn_id: ConnectionId) -> bool { - self.transport_to_owned_connection.values().any(|owned_conn_id| *owned_conn_id == conn_id) + if att.view().get_opcode() == AttOpcode::EXCHANGE_MTU_REQUEST { + // special case: this server opcode is handled by legacy stack, and we snoop + // on its handling, since the MTU is shared between the client + server + return None; } - /// Test to see if a buffer contains a valid ATT packet with an opcode we - /// are interested in intercepting (those intended for servers that are isolated) - pub fn try_parse_att_server_packet( - &self, - tcb_idx: TransportIndex, - packet: Box<[u8]>, - ) -> Option { - if !self.transport_to_owned_connection.contains_key(&tcb_idx) { - return None; - } - - let att = OwnedAttView::try_parse(packet).ok()?; - - if att.view().get_opcode() == AttOpcode::EXCHANGE_MTU_REQUEST { - // special case: this server opcode is handled by legacy stack, and we snoop - // on its handling, since the MTU is shared between the client + server - return None; - } - - match classify_opcode(att.view().get_opcode()) { - OperationType::Command | OperationType::Request | OperationType::Confirmation => { - Some(att) - } - _ => None, - } - } - - /// Check if an incoming connection should be intercepted and, if so, on - /// what conn_id - pub fn on_le_connect( - &mut self, - tcb_idx: TransportIndex, - advertiser: AdvertiserId, - ) -> Option { - info!( - "processing incoming connection on transport {tcb_idx:?} to advertiser {advertiser:?}" - ); - let server_id = *self.advertiser_to_server.get(&advertiser)?; - info!("connection is isolated to server {server_id:?}"); - - let conn_id = ConnectionId::new(tcb_idx, server_id); - let old = self.transport_to_owned_connection.insert(tcb_idx, conn_id); - if old.is_some() { - error!("new server {server_id:?} on transport {tcb_idx:?} displacing existing registered connection {conn_id:?}") - } - Some(conn_id) - } - - /// Handle a disconnection, if any, and return whether the disconnection was registered - pub fn on_le_disconnect(&mut self, tcb_idx: TransportIndex) -> bool { - info!("processing disconnection on transport {tcb_idx:?}"); - self.transport_to_owned_connection.remove(&tcb_idx).is_some() - } - - /// Look up the conn_id for a given tcb_idx, if present - pub fn get_conn_id(&self, tcb_idx: TransportIndex) -> Option { - self.transport_to_owned_connection.get(&tcb_idx).copied() + match classify_opcode(att.view().get_opcode()) { + OperationType::Command | OperationType::Request | OperationType::Confirmation => Some(att), + _ => None, } } fn on_le_connect(tcb_idx: u8, advertiser: u8) { - if let Some(conn_id) = with_arbiter(|arbiter| { - arbiter.on_le_connect(TransportIndex(tcb_idx), AdvertiserId(advertiser)) - }) { + let tcb_idx = TransportIndex(tcb_idx); + let advertiser = AdvertiserId(advertiser); + let is_isolated = with_arbiter(|arbiter| arbiter.is_advertiser_isolated(advertiser)); + if is_isolated { do_in_rust_thread(move |modules| { - if let Err(err) = modules.gatt_module.on_le_connect(conn_id) { + if let Err(err) = modules.gatt_module.on_le_connect(tcb_idx, Some(advertiser)) { error!("{err:?}") } }) @@ -162,8 +94,17 @@ fn on_le_connect(tcb_idx: u8, advertiser: u8) { } fn on_le_disconnect(tcb_idx: u8) { + // Events may be received after a FactoryReset + // is initiated for Bluetooth and the rust arbiter is taken + // down. + if !has_arbiter() { + warn!("arbiter is not yet initialized"); + return; + } + let tcb_idx = TransportIndex(tcb_idx); - if with_arbiter(|arbiter| arbiter.on_le_disconnect(tcb_idx)) { + let was_isolated = with_arbiter(|arbiter| arbiter.is_connection_isolated(tcb_idx)); + if was_isolated { do_in_rust_thread(move |modules| { if let Err(err) = modules.gatt_module.on_le_disconnect(tcb_idx) { error!("{err:?}") @@ -173,9 +114,17 @@ fn on_le_disconnect(tcb_idx: u8) { } fn intercept_packet(tcb_idx: u8, packet: Vec) -> InterceptAction { + // Events may be received after a FactoryReset + // is initiated for Bluetooth and the rust arbiter is taken + // down. + if !has_arbiter() { + warn!("arbiter is not yet initialized"); + return InterceptAction::Drop; + } + let tcb_idx = TransportIndex(tcb_idx); if let Some(att) = with_arbiter(|arbiter| { - arbiter.try_parse_att_server_packet(tcb_idx, packet.into_boxed_slice()) + try_parse_att_server_packet(arbiter, tcb_idx, packet.into_boxed_slice()) }) { do_in_rust_thread(move |modules| { trace!("pushing packet to GATT"); @@ -192,7 +141,7 @@ fn intercept_packet(tcb_idx: u8, packet: Vec) -> InterceptAction { } fn on_mtu_event(tcb_idx: TransportIndex, event: MtuEvent) { - if with_arbiter(|arbiter| arbiter.get_conn_id(tcb_idx)).is_some() { + if with_arbiter(|arbiter| arbiter.is_connection_isolated(tcb_idx)) { do_in_rust_thread(move |modules| { let Some(bearer) = modules.gatt_module.get_bearer(tcb_idx) else { error!("Bearer for {tcb_idx:?} not found"); @@ -210,7 +159,7 @@ mod test { use super::*; use crate::{ - gatt::ids::AttHandle, + gatt::ids::{AttHandle, ServerId}, packets::{ AttBuilder, AttExchangeMtuRequestBuilder, AttOpcode, AttReadRequestBuilder, Serializable, @@ -218,260 +167,84 @@ mod test { }; const TCB_IDX: TransportIndex = TransportIndex(1); - const ANOTHER_TCB_IDX: TransportIndex = TransportIndex(2); const ADVERTISER_ID: AdvertiserId = AdvertiserId(3); const SERVER_ID: ServerId = ServerId(4); - const CONN_ID: ConnectionId = ConnectionId::new(TCB_IDX, SERVER_ID); - - const ANOTHER_ADVERTISER_ID: AdvertiserId = AdvertiserId(5); - - #[test] - fn test_non_isolated_connect() { - let mut arbiter = Arbiter::new(); - - let conn_id = arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - - assert!(conn_id.is_none()) - } - - #[test] - fn test_isolated_connect() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - - let conn_id = arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - - assert_eq!(conn_id, Some(CONN_ID)); - } - - #[test] - fn test_non_isolated_connect_with_isolated_advertiser() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - - let conn_id = arbiter.on_le_connect(TCB_IDX, ANOTHER_ADVERTISER_ID); - - assert!(conn_id.is_none()) - } - - #[test] - fn test_non_isolated_disconnect() { - let mut arbiter = Arbiter::new(); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - - let ok = arbiter.on_le_disconnect(TCB_IDX); - - assert!(!ok) - } - - #[test] - fn test_isolated_disconnect() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - - let ok = arbiter.on_le_disconnect(TCB_IDX); - - assert!(ok) - } - - #[test] - fn test_advertiser_id_reuse() { - let mut arbiter = Arbiter::new(); - // start an advertiser associated with the server, then kill the advertiser - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.clear_advertiser(ADVERTISER_ID); - - // a new advertiser appeared with the same ID and got a connection - let conn_id = arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - - // but we should not be isolated since this is a new advertiser reusing the old - // ID - assert!(conn_id.is_none()) - } - - #[test] - fn test_server_closed() { - let mut arbiter = Arbiter::new(); - // start an advertiser associated with the server, then kill the server - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.clear_server(SERVER_ID); - - // then afterwards we get a connection to this advertiser - let conn_id = arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - - // since the server is gone, we should not capture the connection - assert!(conn_id.is_none()) - } - - #[test] - fn test_connection_isolated() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - let conn_id = arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID).unwrap(); - - let is_isolated = arbiter.is_connection_isolated(conn_id); - - assert!(is_isolated) - } - - #[test] - fn test_connection_isolated_after_advertiser_stops() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - let conn_id = arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID).unwrap(); - arbiter.clear_advertiser(ADVERTISER_ID); - - let is_isolated = arbiter.is_connection_isolated(conn_id); - - assert!(is_isolated) - } - - #[test] - fn test_connection_isolated_after_server_stops() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - let conn_id = arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID).unwrap(); - arbiter.clear_server(SERVER_ID); - - let is_isolated = arbiter.is_connection_isolated(conn_id); - - assert!(is_isolated) + fn create_manager_with_isolated_connection( + tcb_idx: TransportIndex, + server_id: ServerId, + ) -> IsolationManager { + let mut isolation_manager = IsolationManager::new(); + isolation_manager.associate_server_with_advertiser(server_id, ADVERTISER_ID); + isolation_manager.on_le_connect(tcb_idx, Some(ADVERTISER_ID)); + isolation_manager } #[test] fn test_packet_capture_when_isolated() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); + let isolation_manager = create_manager_with_isolated_connection(TCB_IDX, SERVER_ID); let packet = AttBuilder { opcode: AttOpcode::READ_REQUEST, _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(), }; - let out = arbiter.try_parse_att_server_packet(TCB_IDX, packet.to_vec().unwrap().into()); + let out = try_parse_att_server_packet( + &isolation_manager, + TCB_IDX, + packet.to_vec().unwrap().into(), + ); assert!(out.is_some()); } #[test] fn test_packet_bypass_when_isolated() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); + let isolation_manager = create_manager_with_isolated_connection(TCB_IDX, SERVER_ID); let packet = AttBuilder { opcode: AttOpcode::ERROR_RESPONSE, _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(), }; - let out = arbiter.try_parse_att_server_packet(TCB_IDX, packet.to_vec().unwrap().into()); + let out = try_parse_att_server_packet( + &isolation_manager, + TCB_IDX, + packet.to_vec().unwrap().into(), + ); assert!(out.is_none()); } #[test] fn test_mtu_bypass() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); + let isolation_manager = create_manager_with_isolated_connection(TCB_IDX, SERVER_ID); let packet = AttBuilder { opcode: AttOpcode::EXCHANGE_MTU_REQUEST, _child_: AttExchangeMtuRequestBuilder { mtu: 64 }.into(), }; - let out = arbiter.try_parse_att_server_packet(TCB_IDX, packet.to_vec().unwrap().into()); + let out = try_parse_att_server_packet( + &isolation_manager, + TCB_IDX, + packet.to_vec().unwrap().into(), + ); assert!(out.is_none()); } #[test] fn test_packet_bypass_when_not_isolated() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ANOTHER_ADVERTISER_ID); + let isolation_manager = IsolationManager::new(); let packet = AttBuilder { opcode: AttOpcode::READ_REQUEST, _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(), }; - let out = arbiter.try_parse_att_server_packet(TCB_IDX, packet.to_vec().unwrap().into()); - - assert!(out.is_none()); - } - - #[test] - fn test_packet_bypass_when_different_connection() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - arbiter.on_le_connect(ANOTHER_TCB_IDX, ANOTHER_ADVERTISER_ID); - let packet = AttBuilder { - opcode: AttOpcode::READ_REQUEST, - _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(), - }; - - let out = - arbiter.try_parse_att_server_packet(ANOTHER_TCB_IDX, packet.to_vec().unwrap().into()); + let out = try_parse_att_server_packet( + &isolation_manager, + TCB_IDX, + packet.to_vec().unwrap().into(), + ); assert!(out.is_none()); } - - #[test] - fn test_packet_capture_when_isolated_after_advertiser_closes() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - let packet = AttBuilder { - opcode: AttOpcode::READ_REQUEST, - _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(), - }; - arbiter.clear_advertiser(ADVERTISER_ID); - - let out = arbiter.try_parse_att_server_packet(TCB_IDX, packet.to_vec().unwrap().into()); - - assert!(out.is_some()); - } - - #[test] - fn test_packet_capture_when_isolated_after_server_closes() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - let packet = AttBuilder { - opcode: AttOpcode::READ_REQUEST, - _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(), - }; - arbiter.clear_server(SERVER_ID); - - let out = arbiter.try_parse_att_server_packet(TCB_IDX, packet.to_vec().unwrap().into()); - - assert!(out.is_some()); - } - - #[test] - fn test_not_isolated_after_disconnection() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - - arbiter.on_le_disconnect(TCB_IDX); - let is_isolated = arbiter.is_connection_isolated(CONN_ID); - - assert!(!is_isolated); - } - - #[test] - fn test_tcb_idx_reuse_after_isolated() { - let mut arbiter = Arbiter::new(); - arbiter.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - arbiter.clear_advertiser(ADVERTISER_ID); - arbiter.on_le_disconnect(TCB_IDX); - - let conn_id = arbiter.on_le_connect(TCB_IDX, ADVERTISER_ID); - - assert!(conn_id.is_none()); - assert!(!arbiter.is_connection_isolated(CONN_ID)); - } } diff --git a/system/rust/src/gatt/callbacks.rs b/system/rust/src/gatt/callbacks.rs index f8958d7e0594c80fea4dde293b4fcb3d474e796d..a90e55c73473e2573a15eb60b4aaff52e4cf8fec 100644 --- a/system/rust/src/gatt/callbacks.rs +++ b/system/rust/src/gatt/callbacks.rs @@ -203,7 +203,7 @@ impl RawGattDatastore for T { /// Execute or cancel any prepared writes async fn execute(&self, _: TransportIndex, _: TransactionDecision) -> Result<(), AttErrorCode> { // we never do prepared writes, so who cares - return Ok(()); + Ok(()) } } diff --git a/system/rust/src/gatt/ffi.rs b/system/rust/src/gatt/ffi.rs index 8f86efe4ca123f3c425c45eb2654163d711c3589..5a0f3b548ec7d5e74d4d1d29fbff29ba4e899c96 100644 --- a/system/rust/src/gatt/ffi.rs +++ b/system/rust/src/gatt/ffi.rs @@ -21,7 +21,7 @@ use crate::{ }; use super::{ - arbiter::{self, with_arbiter}, + arbiter::with_arbiter, callbacks::{GattWriteRequestType, GattWriteType, TransactionDecision}, channel::AttTransport, ids::{AdvertiserId, AttHandle, ConnectionId, ServerId, TransactionId, TransportIndex}, @@ -39,6 +39,7 @@ use super::{ #[allow(clippy::needless_lifetimes)] #[allow(clippy::too_many_arguments)] #[allow(missing_docs)] +#[allow(unsafe_op_in_unsafe_fn)] mod inner { impl UniquePtr {} @@ -288,13 +289,13 @@ fn open_server(server_id: u8) { let server_id = ServerId(server_id); - if always_use_private_gatt_for_debugging_is_enabled() { - with_arbiter(|arbiter| { - arbiter.associate_server_with_advertiser(server_id, AdvertiserId(0)) - }); - } - do_in_rust_thread(move |modules| { + if always_use_private_gatt_for_debugging_is_enabled() { + modules + .gatt_module + .get_isolation_manager() + .associate_server_with_advertiser(server_id, AdvertiserId(0)) + } if let Err(err) = modules.gatt_module.open_gatt_server(server_id) { error!("{err:?}") } @@ -308,10 +309,6 @@ fn close_server(server_id: u8) { let server_id = ServerId(server_id); - if !always_use_private_gatt_for_debugging_is_enabled() { - with_arbiter(move |arbiter| arbiter.clear_server(server_id)); - } - do_in_rust_thread(move |modules| { if let Err(err) = modules.gatt_module.close_gatt_server(server_id) { error!("{err:?}") @@ -435,7 +432,7 @@ fn is_connection_isolated(conn_id: u16) -> bool { return false; } - with_arbiter(|arbiter| arbiter.is_connection_isolated(ConnectionId(conn_id))) + with_arbiter(|arbiter| arbiter.is_connection_isolated(ConnectionId(conn_id).get_tcb_idx())) } fn send_response(_server_id: u8, conn_id: u16, trans_id: u32, status: u8, value: &[u8]) { @@ -495,8 +492,13 @@ fn associate_server_with_advertiser(server_id: u8, advertiser_id: u8) { return; } - arbiter::with_arbiter(move |arbiter| { - arbiter.associate_server_with_advertiser(ServerId(server_id), AdvertiserId(advertiser_id)) + let server_id = ServerId(server_id); + let advertiser_id = AdvertiserId(advertiser_id); + do_in_rust_thread(move |modules| { + modules + .gatt_module + .get_isolation_manager() + .associate_server_with_advertiser(server_id, advertiser_id); }) } @@ -505,7 +507,11 @@ fn clear_advertiser(advertiser_id: u8) { return; } - arbiter::with_arbiter(move |arbiter| arbiter.clear_advertiser(AdvertiserId(advertiser_id))) + let advertiser_id = AdvertiserId(advertiser_id); + + do_in_rust_thread(move |modules| { + modules.gatt_module.get_isolation_manager().clear_advertiser(advertiser_id); + }) } #[cfg(test)] diff --git a/system/rust/src/gatt/ffi/gatt_shim.cc b/system/rust/src/gatt/ffi/gatt_shim.cc index 42415c8bccef8fb340d5349c89c71ccf60f7976d..c85ca58b24d55c21c237aff654406c6a6f64c429 100644 --- a/system/rust/src/gatt/ffi/gatt_shim.cc +++ b/system/rust/src/gatt/ffi/gatt_shim.cc @@ -66,14 +66,14 @@ void GattServerCallbacks::OnServerRead(uint16_t conn_id, uint32_t trans_id, case AttributeBackingType::CHARACTERISTIC: do_in_jni_thread( FROM_HERE, - base::Bind(callbacks.request_read_characteristic_cb, conn_id, - trans_id, addr.value(), attr_handle, offset, is_long)); + base::BindOnce(callbacks.request_read_characteristic_cb, conn_id, + trans_id, addr.value(), attr_handle, offset, is_long)); break; case AttributeBackingType::DESCRIPTOR: do_in_jni_thread( FROM_HERE, - base::Bind(callbacks.request_read_descriptor_cb, conn_id, trans_id, - addr.value(), attr_handle, offset, is_long)); + base::BindOnce(callbacks.request_read_descriptor_cb, conn_id, + trans_id, addr.value(), attr_handle, offset, is_long)); break; default: LOG_ALWAYS_FATAL("Unexpected backing type %d", attr_type); @@ -99,16 +99,18 @@ void GattServerCallbacks::OnServerWrite( case AttributeBackingType::CHARACTERISTIC: do_in_jni_thread( FROM_HERE, - base::Bind(callbacks.request_write_characteristic_cb, conn_id, - trans_id, addr.value(), attr_handle, offset, need_response, - is_prepare, base::Owned(buf), value.size())); + base::BindOnce(callbacks.request_write_characteristic_cb, conn_id, + trans_id, addr.value(), attr_handle, offset, + need_response, is_prepare, base::Owned(buf), + value.size())); break; case AttributeBackingType::DESCRIPTOR: do_in_jni_thread( FROM_HERE, - base::Bind(callbacks.request_write_descriptor_cb, conn_id, trans_id, - addr.value(), attr_handle, offset, need_response, - is_prepare, base::Owned(buf), value.size())); + base::BindOnce(callbacks.request_write_descriptor_cb, conn_id, + trans_id, addr.value(), attr_handle, offset, + need_response, is_prepare, base::Owned(buf), + value.size())); break; default: LOG_ALWAYS_FATAL("Unexpected backing type %hhu", attr_type); @@ -117,8 +119,8 @@ void GattServerCallbacks::OnServerWrite( void GattServerCallbacks::OnIndicationSentConfirmation(uint16_t conn_id, int status) const { - do_in_jni_thread(FROM_HERE, - base::Bind(callbacks.indication_sent_cb, conn_id, status)); + do_in_jni_thread( + FROM_HERE, base::BindOnce(callbacks.indication_sent_cb, conn_id, status)); } void GattServerCallbacks::OnExecute(uint16_t conn_id, uint32_t trans_id, @@ -130,9 +132,9 @@ void GattServerCallbacks::OnExecute(uint16_t conn_id, uint32_t trans_id, return; } - do_in_jni_thread( - FROM_HERE, base::Bind(callbacks.request_exec_write_cb, conn_id, trans_id, - addr.value(), execute)); + do_in_jni_thread(FROM_HERE, + base::BindOnce(callbacks.request_exec_write_cb, conn_id, + trans_id, addr.value(), execute)); } } // namespace gatt diff --git a/system/rust/src/gatt/server.rs b/system/rust/src/gatt/server.rs index 09fd87964b78560eb166b39eafea69542d302dd1..ee35a7ce30f3a3ebca9369750880bf11bcb44f21 100644 --- a/system/rust/src/gatt/server.rs +++ b/system/rust/src/gatt/server.rs @@ -10,29 +10,36 @@ pub mod services; mod transactions; mod command_handler; +pub mod isolation_manager; #[cfg(test)] mod test; -use std::{collections::HashMap, rc::Rc}; +use std::{ + collections::HashMap, + rc::Rc, + sync::{Arc, Mutex, MutexGuard}, +}; use crate::{ core::shared_box::{SharedBox, WeakBox, WeakBoxRef}, - gatt::{ids::ConnectionId, server::gatt_database::GattDatabase}, + gatt::server::gatt_database::GattDatabase, }; use self::{ super::ids::ServerId, att_server_bearer::AttServerBearer, gatt_database::{AttDatabaseImpl, GattServiceWithHandle}, + isolation_manager::IsolationManager, services::register_builtin_services, }; use super::{ callbacks::RawGattDatastore, channel::AttTransport, - ids::{AttHandle, TransportIndex}, + ids::{AdvertiserId, AttHandle, TransportIndex}, }; use anyhow::{anyhow, bail, Result}; +use bt_common::init_flags::always_use_private_gatt_for_debugging_is_enabled; use log::info; pub use indication_handler::IndicationError; @@ -42,6 +49,10 @@ pub struct GattModule { connections: HashMap, databases: HashMap>, transport: Rc, + // NOTE: this is logically owned by the GattModule. We share it behind a Mutex just so we + // can use it as part of the Arbiter. Once the Arbiter is removed, this should be owned + // fully by the GattModule. + isolation_manager: Arc>, } struct GattConnection { @@ -51,24 +62,35 @@ struct GattConnection { impl GattModule { /// Constructor. - pub fn new(transport: Rc) -> Self { - Self { connections: HashMap::new(), databases: HashMap::new(), transport } + pub fn new( + transport: Rc, + isolation_manager: Arc>, + ) -> Self { + Self { + connections: HashMap::new(), + databases: HashMap::new(), + transport, + isolation_manager, + } } /// Handle LE link connect - pub fn on_le_connect(&mut self, conn_id: ConnectionId) -> Result<()> { - info!("connected on conn_id {conn_id:?}"); - let database = self.databases.get(&conn_id.get_server_id()); + pub fn on_le_connect( + &mut self, + tcb_idx: TransportIndex, + advertiser_id: Option, + ) -> Result<()> { + info!("connected on tcb_idx {tcb_idx:?}"); + self.isolation_manager.lock().unwrap().on_le_connect(tcb_idx, advertiser_id); + + let Some(server_id) = self.isolation_manager.lock().unwrap().get_server_id(tcb_idx) else { + bail!("non-isolated servers are not yet supported (b/274945531)") + }; + let database = self.databases.get(&server_id); let Some(database) = database else { - bail!( - "got connection to conn_id {conn_id:?} (server_id {:?}) but this server does not exist!", - conn_id.get_server_id(), - ); + bail!("got connection to {server_id:?} but this server does not exist!"); }; - // TODO(aryarahul): do not pass in conn_id at all, derive it using the IsolationManager instead - let tcb_idx = conn_id.get_tcb_idx(); - let transport = self.transport.clone(); let bearer = SharedBox::new(AttServerBearer::new( database.get_att_database(tcb_idx), @@ -82,6 +104,7 @@ impl GattModule { /// Handle an LE link disconnect pub fn on_le_disconnect(&mut self, tcb_idx: TransportIndex) -> Result<()> { info!("disconnected conn_id {tcb_idx:?}"); + self.isolation_manager.lock().unwrap().on_le_disconnect(tcb_idx); let connection = self.connections.remove(&tcb_idx); let Some(connection) = connection else { bail!("got disconnection from {tcb_idx:?} but bearer does not exist"); @@ -134,6 +157,10 @@ impl GattModule { bail!("GATT server {server_id:?} did not exist") }; + if !always_use_private_gatt_for_debugging_is_enabled() { + self.isolation_manager.lock().unwrap().clear_server(server_id); + } + Ok(()) } @@ -144,4 +171,9 @@ impl GattModule { ) -> Option>> { self.connections.get(&tcb_idx).map(|x| x.bearer.as_ref()) } + + /// Get the IsolationManager to manage associations between servers + advertisers + pub fn get_isolation_manager(&mut self) -> MutexGuard<'_, IsolationManager> { + self.isolation_manager.lock().unwrap() + } } diff --git a/system/rust/src/gatt/server/att_database.rs b/system/rust/src/gatt/server/att_database.rs index db2d7318826becf2253c90f0e100b43668c97362..2235fd81f59b767724b5374e519ee452458fd95b 100644 --- a/system/rust/src/gatt/server/att_database.rs +++ b/system/rust/src/gatt/server/att_database.rs @@ -34,6 +34,7 @@ bitflags! { /// /// These values are from Core Spec 5.3 Vol 3G 3.3.1.1 Characteristic Properties, /// and also match what Android uses in JNI. + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct AttPermissions : u8 { /// Attribute can be read using READ_REQ const READABLE = 0x02; diff --git a/system/rust/src/gatt/server/gatt_database.rs b/system/rust/src/gatt/server/gatt_database.rs index 00cda0df235a2e4c6f8d89393cf82d6b0634887d..2f7a3f4220441664d777cd0e068d12ef9bbe96a4 100644 --- a/system/rust/src/gatt/server/gatt_database.rs +++ b/system/rust/src/gatt/server/gatt_database.rs @@ -264,7 +264,7 @@ impl GattDatabase { } // if we made it here, we successfully loaded the new service - static_data.attributes.extend(attributes.clone().into_iter()); + static_data.attributes.extend(attributes.clone()); // re-entrancy via the listeners is possible, so we prevent it by dropping here drop(static_data); diff --git a/system/rust/src/gatt/server/isolation_manager.rs b/system/rust/src/gatt/server/isolation_manager.rs new file mode 100644 index 0000000000000000000000000000000000000000..b7f32a7b79bda85bf7a41a27fdc62d978508af23 --- /dev/null +++ b/system/rust/src/gatt/server/isolation_manager.rs @@ -0,0 +1,225 @@ +//! This module determines which GATT server should be exposed to a given connection. + +use std::collections::HashMap; + +use log::{error, info}; + +use crate::gatt::ids::{AdvertiserId, ServerId, TransportIndex}; + +/// This class is responsible for tracking which connections and advertising we +/// own, and using this information to decide what servers should be exposed to +/// a given connetion. +#[derive(Default)] +pub struct IsolationManager { + advertiser_to_server: HashMap, + transport_to_server: HashMap, +} + +impl IsolationManager { + /// Constructor + pub fn new() -> Self { + IsolationManager { + advertiser_to_server: HashMap::new(), + transport_to_server: HashMap::new(), + } + } + + /// Link a given GATT server to an LE advertising set, so incoming + /// connections to this advertiser will be visible only by the linked + /// server + pub fn associate_server_with_advertiser( + &mut self, + server_id: ServerId, + advertiser_id: AdvertiserId, + ) { + info!("associating server {server_id:?} with advertising set {advertiser_id:?}"); + let old = self.advertiser_to_server.insert(advertiser_id, server_id); + if let Some(old) = old { + error!("new server {server_id:?} associated with same advertiser {advertiser_id:?}, displacing old server {old:?}"); + } + } + + /// Clear the server associated with this advertiser, if one exists + pub fn clear_advertiser(&mut self, advertiser_id: AdvertiserId) { + info!("removing server (if any) associated with advertiser {advertiser_id:?}"); + self.advertiser_to_server.remove(&advertiser_id); + } + + /// Check if this transport is currently owned by the Rust stack + pub fn is_connection_isolated(&self, tcb_idx: TransportIndex) -> bool { + self.transport_to_server.contains_key(&tcb_idx) + } + + /// Check if this advertiser is tied to a private server + pub fn is_advertiser_isolated(&self, advertiser_id: AdvertiserId) -> bool { + self.advertiser_to_server.contains_key(&advertiser_id) + } + + /// Look up the server_id tied to a given tcb_idx, if one exists + pub fn get_server_id(&self, tcb_idx: TransportIndex) -> Option { + self.transport_to_server.get(&tcb_idx).copied() + } + + /// Remove all linked advertising sets from the provided server + /// + /// This is invoked by the GATT server module, not separately from the upper layer. + pub fn clear_server(&mut self, server_id: ServerId) { + info!("clearing advertisers associated with {server_id:?}"); + self.advertiser_to_server.retain(|_, server| *server != server_id); + } + + /// Handles an incoming connection + /// + /// This event should be supplied from the enclosing module, not directly from the upper layer. + pub fn on_le_connect(&mut self, tcb_idx: TransportIndex, advertiser: Option) { + info!( + "processing incoming connection on transport {tcb_idx:?} to advertiser {advertiser:?}" + ); + let Some(advertiser) = advertiser else { + info!("processing outgoing connection, granting access to all servers"); + return; + }; + let Some(server_id) = self.advertiser_to_server.get(&advertiser).copied() else { + info!("connection can access all servers"); + return; + }; + info!("connection is isolated to server {server_id:?}"); + let old = self.transport_to_server.insert(tcb_idx, server_id); + if old.is_some() { + error!("new server {server_id:?} on transport {tcb_idx:?} displacing existing server {server_id:?}") + } + } + + /// Handle a disconnection + /// + /// This event should be supplied from the enclosing module, not directly from the upper layer. + pub fn on_le_disconnect(&mut self, tcb_idx: TransportIndex) { + info!("processing disconnection on transport {tcb_idx:?}"); + self.transport_to_server.remove(&tcb_idx); + } +} + +#[cfg(test)] +mod test { + use super::*; + + const TCB_IDX: TransportIndex = TransportIndex(1); + const ADVERTISER_ID: AdvertiserId = AdvertiserId(3); + const SERVER_ID: ServerId = ServerId(4); + + const ANOTHER_ADVERTISER_ID: AdvertiserId = AdvertiserId(5); + + #[test] + fn test_non_isolated_connect() { + let mut isolation_manager = IsolationManager::new(); + + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + let server_id = isolation_manager.get_server_id(TCB_IDX); + + assert!(server_id.is_none()) + } + + #[test] + fn test_isolated_connect() { + let mut isolation_manager = IsolationManager::new(); + isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + let server_id = isolation_manager.get_server_id(TCB_IDX); + + assert_eq!(server_id, Some(SERVER_ID)); + } + + #[test] + fn test_non_isolated_connect_with_isolated_advertiser() { + let mut isolation_manager = IsolationManager::new(); + isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + + isolation_manager.on_le_connect(TCB_IDX, Some(ANOTHER_ADVERTISER_ID)); + let server_id = isolation_manager.get_server_id(TCB_IDX); + + assert!(server_id.is_none()) + } + + #[test] + fn test_advertiser_id_reuse() { + let mut isolation_manager = IsolationManager::new(); + // start an advertiser associated with the server, then kill the advertiser + isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + isolation_manager.clear_advertiser(ADVERTISER_ID); + + // a new advertiser appeared with the same ID and got a connection + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + let server_id = isolation_manager.get_server_id(TCB_IDX); + + // but we should not be isolated since this is a new advertiser reusing the old + // ID + assert!(server_id.is_none()) + } + + #[test] + fn test_server_closed() { + let mut isolation_manager = IsolationManager::new(); + // start an advertiser associated with the server, then kill the server + isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + isolation_manager.clear_server(SERVER_ID); + + // then afterwards we get a connection to this advertiser + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + let server_id = isolation_manager.get_server_id(TCB_IDX); + + // since the server is gone, we should not capture the connection + assert!(server_id.is_none()) + } + + #[test] + fn test_connection_isolated_after_advertiser_stops() { + let mut isolation_manager = IsolationManager::new(); + isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + isolation_manager.clear_advertiser(ADVERTISER_ID); + + let is_isolated = isolation_manager.is_connection_isolated(TCB_IDX); + + assert!(is_isolated) + } + + #[test] + fn test_connection_isolated_after_server_stops() { + let mut isolation_manager = IsolationManager::new(); + isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + isolation_manager.clear_server(SERVER_ID); + + let is_isolated = isolation_manager.is_connection_isolated(TCB_IDX); + + assert!(is_isolated) + } + + #[test] + fn test_not_isolated_after_disconnection() { + let mut isolation_manager = IsolationManager::new(); + isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + + isolation_manager.on_le_disconnect(TCB_IDX); + let is_isolated = isolation_manager.is_connection_isolated(TCB_IDX); + + assert!(!is_isolated); + } + + #[test] + fn test_tcb_idx_reuse_after_isolated() { + let mut isolation_manager = IsolationManager::new(); + isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + isolation_manager.clear_advertiser(ADVERTISER_ID); + isolation_manager.on_le_disconnect(TCB_IDX); + + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); + let server_id = isolation_manager.get_server_id(TCB_IDX); + + assert!(server_id.is_none()); + assert!(!isolation_manager.is_connection_isolated(TCB_IDX)); + } +} diff --git a/system/rust/src/gatt/server/services/gatt.rs b/system/rust/src/gatt/server/services/gatt.rs index edd146d600d4d36f0171a6a2ad76e3da17acff4f..a1ca4a448d39e060937e2cbacde9084553f04896 100644 --- a/system/rust/src/gatt/server/services/gatt.rs +++ b/system/rust/src/gatt/server/services/gatt.rs @@ -94,7 +94,7 @@ impl GattDatastore for GattService { })?; let mut clients = self.clients.borrow_mut(); let state = clients.get_mut(&tcb_idx); - let Some(mut state) = state else { + let Some(state) = state else { error!("Received write request from disconnected client..."); return Err(AttErrorCode::UNLIKELY_ERROR); }; diff --git a/system/rust/src/lib.rs b/system/rust/src/lib.rs index d944e0214e380e5862ea85e5ef1425cc86cd5153..4693320516ddc5e32642dfc581d0bcd02b184a12 100644 --- a/system/rust/src/lib.rs +++ b/system/rust/src/lib.rs @@ -86,15 +86,15 @@ impl GlobalModuleRegistry { assert!(prev_registry.is_none()); // First, setup FFI and C++ modules - gatt::arbiter::initialize_arbiter(); + let arbiter = gatt::arbiter::initialize_arbiter(); connection::register_callbacks(); // Now enter the runtime - local.block_on(&rt, async { + local.block_on(&rt, async move { // Then follow the pure-Rust modules let gatt_incoming_callbacks = Rc::new(gatt::callbacks::CallbackTransactionManager::new(gatt_callbacks.clone())); - let gatt_module = &mut gatt::server::GattModule::new(att_transport.clone()); + let gatt_module = &mut gatt::server::GattModule::new(att_transport.clone(), arbiter); let connection_manager = connection::ConnectionManager::new(le_acl_manager); @@ -118,13 +118,14 @@ impl GlobalModuleRegistry { match message { MainThreadTxMessage::Callback(f) => f(&mut modules), MainThreadTxMessage::Stop => { - GLOBAL_MODULE_REGISTRY.lock().unwrap().take(); break; } } } }); warn!("Rust thread queue has stopped, shutting down executor thread"); + GLOBAL_MODULE_REGISTRY.lock().unwrap().take(); + gatt::arbiter::clean_arbiter(); } } diff --git a/system/rust/tests/gatt_server_test.rs b/system/rust/tests/gatt_server_test.rs index 8ec91f74e494fbdd1f99a9834b030d7f4a9a594c..20532ab8352dec73f98bd30c6987214ce45b470e 100644 --- a/system/rust/tests/gatt_server_test.rs +++ b/system/rust/tests/gatt_server_test.rs @@ -1,11 +1,14 @@ -use std::rc::Rc; +use std::{ + rc::Rc, + sync::{Arc, Mutex}, +}; use bluetooth_core::{ core::uuid::Uuid, gatt::{ self, ffi::AttributeBackingType, - ids::{AttHandle, ConnectionId, ServerId, TransportIndex}, + ids::{AdvertiserId, AttHandle, ServerId, TransportIndex}, mocks::{ mock_datastore::{MockDatastore, MockDatastoreEvents}, mock_transport::MockAttTransport, @@ -15,6 +18,7 @@ use bluetooth_core::{ AttPermissions, GattCharacteristicWithHandle, GattDescriptorWithHandle, GattServiceWithHandle, CHARACTERISTIC_UUID, PRIMARY_SERVICE_DECLARATION_UUID, }, + isolation_manager::IsolationManager, services::{ gap::DEVICE_NAME_UUID, gatt::{ @@ -48,11 +52,11 @@ mod utils; const TCB_IDX: TransportIndex = TransportIndex(1); const SERVER_ID: ServerId = ServerId(2); -const CONN_ID: ConnectionId = ConnectionId::new(TCB_IDX, SERVER_ID); +const ADVERTISER_ID: AdvertiserId = AdvertiserId(3); const ANOTHER_TCB_IDX: TransportIndex = TransportIndex(2); const ANOTHER_SERVER_ID: ServerId = ServerId(3); -const ANOTHER_CONN_ID: ConnectionId = ConnectionId::new(ANOTHER_TCB_IDX, ANOTHER_SERVER_ID); +const ANOTHER_ADVERTISER_ID: AdvertiserId = AdvertiserId(4); const SERVICE_HANDLE: AttHandle = AttHandle(6); const CHARACTERISTIC_HANDLE: AttHandle = AttHandle(8); @@ -68,7 +72,8 @@ const ANOTHER_DATA: [u8; 4] = [5, 6, 7, 8]; fn start_gatt_module() -> (gatt::server::GattModule, UnboundedReceiver<(TransportIndex, AttBuilder)>) { let (transport, transport_rx) = MockAttTransport::new(); - let gatt = GattModule::new(Rc::new(transport)); + let arbiter = IsolationManager::new(); + let gatt = GattModule::new(Rc::new(transport), Arc::new(Mutex::new(arbiter))); (gatt, transport_rx) } @@ -99,7 +104,8 @@ fn create_server_and_open_connection( datastore, ) .unwrap(); - gatt.on_le_connect(CONN_ID).unwrap(); + gatt.get_isolation_manager().associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + gatt.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)).unwrap(); data_rx } @@ -400,7 +406,9 @@ fn test_multiple_servers() { datastore, ) .unwrap(); - gatt.on_le_connect(ANOTHER_CONN_ID).unwrap(); + gatt.get_isolation_manager() + .associate_server_with_advertiser(ANOTHER_SERVER_ID, ANOTHER_ADVERTISER_ID); + gatt.on_le_connect(ANOTHER_TCB_IDX, Some(ANOTHER_ADVERTISER_ID)).unwrap(); // act: read from both connections gatt.get_bearer(TCB_IDX).unwrap().handle_packet( @@ -613,3 +621,37 @@ fn test_service_change_indication() { ); }); } + +#[test] +fn test_closing_gatt_server_unisolates_advertiser() { + start_test(async move { + // arrange + let (mut gatt, _) = start_gatt_module(); + gatt.open_gatt_server(SERVER_ID).unwrap(); + gatt.get_isolation_manager().associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + + // act + gatt.close_gatt_server(SERVER_ID).unwrap(); + + // assert + let is_advertiser_isolated = + gatt.get_isolation_manager().is_advertiser_isolated(ADVERTISER_ID); + assert!(!is_advertiser_isolated); + }); +} + +#[test] +fn test_disconnection_unisolates_connection() { + start_test(async move { + // arrange + let (mut gatt, _) = start_gatt_module(); + create_server_and_open_connection(&mut gatt); + + // act + gatt.on_le_disconnect(TCB_IDX).unwrap(); + + // assert + let is_connection_isolated = gatt.get_isolation_manager().is_connection_isolated(TCB_IDX); + assert!(!is_connection_isolated); + }); +} diff --git a/system/stack/Android.bp b/system/stack/Android.bp index 5326cfe98a9f492f79484c5b5a0e778f1e3d5c53..06e7c2f28319e0470cd495d094eaa8c7891285b7 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -8,27 +8,35 @@ package { default_applicable_licenses: ["system_bt_license"], } -crypto_toolbox_srcs = [ - "crypto_toolbox/aes.cc", - "crypto_toolbox/aes_cmac.cc", - "crypto_toolbox/crypto_toolbox.cc", -] - -cc_test_library { - name: "crypto_toolbox_for_tests", - static_libs: ["libchrome"], +cc_library_static { + name: "libbt-btu-main-thread", defaults: ["fluoride_defaults"], - host_supported: true, + srcs: ["btu/main_thread.cc"], include_dirs: [ "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/gd", + "packages/modules/Bluetooth/system/include", + "packages/modules/Bluetooth/system/internal_include", + "packages/modules/Bluetooth/system/stack/include", + "packages/modules/Bluetooth/system/types", + ], + static_libs: [ + "libbt_shim_bridge", + ], + shared_libs: [ + "libchrome", ], - srcs: crypto_toolbox_srcs, + apex_available: [ + "com.android.btservices", + ], + host_supported: true, + min_sdk_version: "Tiramisu", } // Bluetooth stack static library for target cc_library_static { name: "libbt-stack", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], local_include_dirs: [ "avct", "avdt", @@ -64,17 +72,13 @@ cc_library_static { "packages/modules/Bluetooth/system/device/include", "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/gd/hal", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/ble", - "packages/modules/Bluetooth/system/vnd/include", ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], - srcs: crypto_toolbox_srcs + [ + srcs: [ "a2dp/a2dp_aac.cc", "a2dp/a2dp_aac_decoder.cc", "a2dp/a2dp_aac_encoder.cc", @@ -121,6 +125,8 @@ cc_library_static { "bnep/bnep_api.cc", "bnep/bnep_main.cc", "bnep/bnep_utils.cc", + "btm/hfp_lc3_decoder.cc", + "btm/hfp_lc3_encoder.cc", "btm/hfp_msbc_decoder.cc", "btm/hfp_msbc_encoder.cc", "hid/hidd_api.cc", @@ -132,18 +138,28 @@ cc_library_static { "pan/pan_utils.cc", ], static_libs: [ + "libbluetooth_crypto_toolbox", + "libbluetooth_hci_pdl", + "libbt-btu-main-thread", "libbt-hci", + "libbt-platform-protos-lite", "libbt-stack-core", + "libbt_shim_bridge", + "liblc3", ], whole_static_libs: [ "libaptx_enc", "libaptxhd_enc", - "libcom.android.sysprop.bluetooth", + "libcom.android.sysprop.bluetooth.wrapped", "libldacBT_abr", "libldacBT_enc", ], + apex_available: [ + "com.android.btservices", + ], host_supported: true, min_sdk_version: "Tiramisu", + cflags: ["-Wno-unused-parameter"], } filegroup { @@ -160,7 +176,7 @@ filegroup { cc_library_static { name: "libbt-stack-core", - defaults: ["fluoride_basic_defaults"], + defaults: ["fluoride_defaults"], local_include_dirs: [ "avct", "avdt", @@ -188,13 +204,10 @@ cc_library_static { "packages/modules/Bluetooth/system/bta/sys", "packages/modules/Bluetooth/system/btif/include", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/gd/rust/shim", "packages/modules/Bluetooth/system/internal_include", "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/ble", - "packages/modules/Bluetooth/system/vnd/include", ], - srcs: crypto_toolbox_srcs + [ + srcs: [ ":LegacyStackSdp", "acl/acl.cc", "acl/ble_acl.cc", @@ -202,7 +215,6 @@ cc_library_static { "acl/btm_ble_connection_establishment.cc", "acl/btm_pm.cc", "arbiter/acl_arbiter.cc", - "btm/ble_advertiser_hci_interface.cc", "btm/ble_scanner_hci_interface.cc", "btm/btm_ble.cc", "btm/btm_ble_addr.cc", @@ -211,9 +223,9 @@ cc_library_static { "btm/btm_ble_bgconn.cc", "btm/btm_ble_cont_energy.cc", "btm/btm_ble_gap.cc", - "btm/btm_ble_multi_adv.cc", "btm/btm_ble_privacy.cc", "btm/btm_ble_scanner.cc", + "btm/btm_ble_sec.cc", "btm/btm_client_interface.cc", "btm/btm_dev.cc", "btm/btm_devctl.cc", @@ -221,13 +233,14 @@ cc_library_static { "btm/btm_iot_config.cc", "btm/btm_iso.cc", "btm/btm_main.cc", - "btm/btm_scn.cc", "btm/btm_sco.cc", "btm/btm_sco_hci.cc", "btm/btm_sco_hfp_hal.cc", "btm/btm_sec.cc", + "btm/btm_sec_cb.cc", + "btm/btm_security_client_interface.cc", + "btu/btu_event.cc", "btu/btu_hcif.cc", - "btu/btu_task.cc", "eatt/eatt.cc", "gap/gap_ble.cc", "gap/gap_conn.cc", @@ -278,26 +291,368 @@ cc_library_static { "BluetoothGeneratedDumpsysDataSchema_h", ], cflags: [ + "-Wno-unused-parameter", /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/ "-fvisibility=default", ], static_libs: [ "libbluetooth_core_rs", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_hci_pdl", "libbt-hci", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libcom.android.sysprop.bluetooth.wrapped", + ], + shared_libs: [ + "libPlatformProperties", + "libcrypto", + ], + apex_available: [ + "com.android.btservices", ], host_supported: true, min_sdk_version: "Tiramisu", } +cc_defaults { + name: "btstack_fuzzer_default", + host_supported: true, + cflags: [ + "-DHAS_NO_BDROID_BUILDCFG", + "-Wall", + "-Werror", + "-Wextra", + // Mocked components have too many unused parameters + "-Wno-unused-parameter", + ], + include_dirs: [ + "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/gd", + "packages/modules/Bluetooth/system/include", + "packages/modules/Bluetooth/system/internal_include", + "packages/modules/Bluetooth/system/stack/include", + "packages/modules/Bluetooth/system/test/common", + "packages/modules/Bluetooth/system/types", + ], + static_libs: [ + "libchrome", + ], + shared_libs: [ + "liblog", + ], + target: { + darwin: { + enabled: false, + }, + android: { + shared_libs: [ + "libcutils", + "libutils", + ], + }, + host: { + cflags: [ + "-DOS_GENERIC", + ], + }, + }, + fuzz_config: { + // Options for performance improvement + libfuzzer_options: [ + // This disables the stdout and stderr + "close_fd_mask=3", + // This limits the maximum corpus size to 4KB + "max_len=4096", + // TODO: b/280300628 for fixing memory leaks. Until it's fixed leak + // detection needs to be turned off to unblock fuzzing. + "detect_leaks=0", + ], + cc: [ + "android-bluetooth-security@google.com", + "android-security-assurance-redteam@google.com", + ], + componentid: 27441, // Android > Android OS & Apps > Systems > bluetooth + hotlists: [ + "3705175", // ASA Red Team Discovered Issues + "4810445", // ASA Red Team: Bluetooth Engagement Issues + ], + acknowledgement: [ + "Android Bluetooth Team of Google", + "Android Red Team of Google", + ], + }, +} + +cc_fuzz { + name: "sdp-fuzzer", + defaults: [ + "btstack_fuzzer_default", + "fluoride_defaults", + ], + include_dirs: [ + "packages/modules/Bluetooth/system/stack/btm", + ], + srcs: [ + ":LegacyStackSdp", + ":TestCommonMockFunctions", + ":TestFakeOsi", + ":TestMockBtif", + ":TestMockDevice", + ":TestMockGdOsLoggingLogRedaction", + ":TestMockStackBtm", + ":TestMockStackL2cap", + ":TestMockStackMetrics", + "fuzzers/sdp_fuzzer.cc", + ], + static_libs: [ + "libbluetooth-types", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", + ], +} + +cc_fuzz { + name: "gatt-fuzzer", + defaults: [ + "btstack_fuzzer_default", + "fluoride_defaults", + ], + include_dirs: [ + "external/flatbuffers/include", + "external/rust/crates/quiche/deps/boringssl/src/include", + "packages/modules/Bluetooth/system/stack/btm", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", + ], + srcs: [ + ":TestCommonMockFunctions", + ":TestCommonStackConfig", + ":TestFakeOsi", + ":TestMockBtif", + ":TestMockDevice", + ":TestMockGdOsLoggingLogRedaction", + ":TestMockMainShim", + ":TestMockRustFfi", + ":TestMockSrvcDis", + ":TestMockStackAcl", + ":TestMockStackArbiter", + ":TestMockStackBtm", + ":TestMockStackHcic", + ":TestMockStackL2cap", + ":TestMockStackMetrics", + ":TestMockStackSdp", + "eatt/*.cc", + "fuzzers/gatt_fuzzer.cc", + "gatt/*.cc", + ], + static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", + "libbluetooth_smp_pdl", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libgmock", + ], +} + +cc_fuzz { + name: "smp-fuzzer", + defaults: [ + "btstack_fuzzer_default", + "fluoride_defaults", + ], + include_dirs: [ + "external/flatbuffers/include", + "external/rust/crates/quiche/deps/boringssl/src/include", + "packages/modules/Bluetooth/system/stack/btm", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", + ], + srcs: [ + ":TestCommonMockFunctions", + ":TestCommonStackConfig", + ":TestFakeOsi", + ":TestMockBtif", + ":TestMockDevice", + ":TestMockGdOsLoggingLogRedaction", + ":TestMockMainShim", + ":TestMockStackAcl", + ":TestMockStackBtm", + ":TestMockStackHcic", + ":TestMockStackL2cap", + ":TestMockStackMetrics", + "fuzzers/smp_fuzzer.cc", + "smp/*.cc", // add other sources files (p256 related) under smp into this test + ], + static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", + "libbluetooth_smp_pdl", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libgmock", + ], +} + +cc_fuzz { + name: "bnep-fuzzer", + defaults: [ + "btstack_fuzzer_default", + "fluoride_defaults", + ], + include_dirs: [ + "external/flatbuffers/include", + "external/rust/crates/quiche/deps/boringssl/src/include", + "packages/modules/Bluetooth/system/stack/btm", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", + ], + srcs: [ + ":TestCommonMockFunctions", + ":TestCommonStackConfig", + ":TestFakeOsi", + ":TestMockBtif", + ":TestMockDevice", + ":TestMockGdOsLoggingLogRedaction", + ":TestMockMainShim", + ":TestMockStackAcl", + ":TestMockStackBtm", + ":TestMockStackHcic", + ":TestMockStackL2cap", + ":TestMockStackMetrics", + "bnep/*.cc", + "fuzzers/bnep_fuzzer.cc", + ], + static_libs: [ + "libbluetooth-types", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", + "libbluetooth_smp_pdl", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libgmock", + ], +} + +cc_fuzz { + name: "avrc-fuzzer", + defaults: [ + "btstack_fuzzer_default", + "fluoride_defaults", + ], + include_dirs: [ + "external/flatbuffers/include", + "external/rust/crates/quiche/deps/boringssl/src/include", + "packages/modules/Bluetooth/system/stack/btm", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", + ], + srcs: [ + ":TestCommonMockFunctions", + ":TestCommonStackConfig", + ":TestFakeOsi", + ":TestMockBtif", + ":TestMockDevice", + ":TestMockGdOsLoggingLogRedaction", + ":TestMockMainShim", + ":TestMockStackAcl", + ":TestMockStackBtm", + ":TestMockStackHcic", + ":TestMockStackL2cap", + ":TestMockStackMetrics", + ":TestMockStackSdp", + "avct/*.cc", + "avrc/*.cc", + "fuzzers/avrc_fuzzer.cc", + ], + static_libs: [ + "libbase", + "libbluetooth-types", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", + "libbluetooth_smp_pdl", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libcom.android.sysprop.bluetooth.wrapped", + "libgmock", + ], +} + +cc_fuzz { + name: "l2cap-fuzzer", + defaults: [ + "btstack_fuzzer_default", + "fluoride_defaults", + ], + include_dirs: [ + "external/flatbuffers/include", + "external/rust/crates/quiche/deps/boringssl/src/include", + "packages/modules/Bluetooth/system/stack/btm", + ], + generated_headers: [ + "BluetoothGeneratedDumpsysDataSchema_h", + ], + srcs: [ + ":TestCommonMockFunctions", + ":TestCommonStackConfig", + ":TestFakeOsi", + ":TestMockBtif", + ":TestMockDevice", + ":TestMockGdOsLoggingLogRedaction", + ":TestMockMainShim", + ":TestMockStackAcl", + ":TestMockStackBtm", + ":TestMockStackHcic", + ":TestMockStackMetrics", + "fuzzers/l2cap_fuzzer.cc", + "l2cap/*.cc", + ], + static_libs: [ + "libbluetooth-types", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", + "libbluetooth_smp_pdl", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", + "libgmock", + "libosi", + ], + target: { + android: { + shared_libs: [ + "libPlatformProperties", + ], + }, + }, +} + // Bluetooth stack unit tests for target cc_test { name: "net_test_stack", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", + "latest_android_hardware_audio_common_ndk_static", + "latest_android_hardware_bluetooth_audio_ndk_shared", + "latest_android_media_audio_common_types_ndk_static", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], local_include_dirs: [ "include", ], @@ -323,32 +678,34 @@ cc_test { "libfmq", "libhidlbase", "liblog", + "libstatssocket", "libutils", "libz", + "server_configurable_flags", ], static_libs: [ "android.hardware.bluetooth.a2dp@1.0", - "android.hardware.audio.common-V2-ndk", - "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth@1.0", "android.hardware.bluetooth@1.1", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", - "android.media.audio.common.types-V2-ndk", "android.system.suspend.control-V1-ndk", "libFraunhoferAAC", "libbluetooth-dumpsys", + "libbluetooth-types", "libbluetooth_core_rs", + "libbluetooth_crypto_toolbox", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", + "libbt-btu-main-thread", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", "libbt-stack-core", + "libbt_shim_bridge", "libbtcore", "libbtdevice", "libbtif", @@ -359,21 +716,22 @@ cc_test { "libopus", "libosi", "libprotobuf-cpp-lite", + "libstatslog_bt", "libudrv-uipc", ], whole_static_libs: [ "libbluetooth-for-tests", ], + header_libs: ["libbluetooth_headers"], } cc_test { name: "net_test_stack_rfcomm", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, local_include_dirs: [ "btm", @@ -390,7 +748,6 @@ cc_test { "packages/modules/Bluetooth/system/internal_include", ], srcs: [ - ":TestCommonLogMsg", ":TestCommonMockFunctions", ":TestMockHci", ":TestMockMainShim", @@ -415,38 +772,54 @@ cc_test { ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], shared_libs: [ "libcrypto", "libcutils", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", + "libbluetooth_smp_pdl", + "libbt-btu-main-thread", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", "libprotobuf-cpp-lite", + "libstatslog_bt", ], + target: { + android: { + shared_libs: [ + "libstatssocket", + ], + }, + }, sanitize: { cfi: false, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } // Bluetooth stack smp unit tests for target cc_test { name: "net_test_stack_smp", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], host_supported: true, - test_suites: ["device-tests"], + test_suites: ["general-tests"], local_include_dirs: [ "btm", "include", @@ -456,14 +829,13 @@ cc_test { include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/gd", + "packages/modules/Bluetooth/system/include", "packages/modules/Bluetooth/system/internal_include", ], - srcs: crypto_toolbox_srcs + [ - ":TestCommonLogMsg", + srcs: [ ":TestCommonMainHandler", ":TestCommonMockFunctions", ":TestMockBtif", - ":TestMockCommon", ":TestMockDevice", ":TestMockMainShim", ":TestMockStackAcl", @@ -481,77 +853,53 @@ cc_test { "smp/smp_l2c.cc", "smp/smp_main.cc", "smp/smp_utils.cc", - "test/crypto_toolbox_test.cc", "test/stack_smp_test.cc", ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], shared_libs: [ "libcrypto", "libcutils", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_hci_pdl", + "libbluetooth_l2cap_pdl", + "libbluetooth_smp_pdl", + "libbt-btu-main-thread", + "libbt-common", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", + "libstatslog_bt", ], -} - -// Bluetooth stack multi-advertising unit tests for target -cc_test { - name: "net_test_stack_multi_adv", - defaults: [ - "bluetooth_gtest_x86_asan_workaround", - "fluoride_defaults", - "mts_defaults", - ], - test_suites: ["device-tests"], - local_include_dirs: [ - "btm", - "include", - ], - include_dirs: [ - "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/internal_include", - "packages/modules/Bluetooth/system/internal_include", - ], - srcs: [ - ":TestMockDevice", - "btm/btm_ble_multi_adv.cc", - "test/ble_advertiser_test.cc", - ], - shared_libs: [ - "libbinder_ndk", - "libcrypto", - "libcutils", - ], - static_libs: [ - "android.system.suspend.control-V1-ndk", - "libbluetooth-types", - "libchrome", - "libgmock", - "liblog", - ], - sanitize: { - cfi: false, + target: { + android: { + shared_libs: [ + "libstatssocket", + ], + }, }, + // header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } // Bluetooth stack advertise data parsing unit tests for target cc_test { name: "net_test_stack_ad_parser", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], local_include_dirs: [ "include", ], @@ -574,7 +922,6 @@ cc_test { cc_test { name: "net_test_gatt_conn_multiplexing", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -601,7 +948,10 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libbt-common", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", "libgmock", @@ -610,16 +960,17 @@ cc_test { sanitize: { cfi: false, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_gatt_native", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, @@ -649,30 +1000,42 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", "libgmock", "liblog", "libosi", - "libosi-AllocationTestHarness", + "libstatslog_bt", ], + target: { + android: { + shared_libs: [ + "libstatssocket", + ], + }, + }, sanitize: { address: true, cfi: true, misc_undefined: ["bounds"], }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_avdtp", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, @@ -684,7 +1047,6 @@ cc_test { "packages/modules/Bluetooth/system/stack/include", ], srcs: [ - ":TestCommonLogMsg", ":TestCommonMockFunctions", ":TestMockBta", ":TestMockDevice", @@ -707,33 +1069,44 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", "liblog", "libosi", - "libosi-AllocationTestHarness", "libprotobuf-cpp-lite", + "libstatslog_bt", ], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + }, sanitize: { address: true, cfi: true, misc_undefined: ["bounds"], }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_a2dp_codecs_native", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], cflags: [ "-DUNIT_TESTS", + "-Wno-unused-parameter", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, @@ -811,16 +1184,19 @@ cc_test { ], static_libs: [ "libFraunhoferAAC", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libgmock", "liblog", "libopus", "libosi", - "libosi-AllocationTestHarness", ], whole_static_libs: [ "libaptx_enc", @@ -833,16 +1209,16 @@ cc_test { cfi: true, misc_undefined: ["bounds"], }, + header_libs: ["libbluetooth_headers"], } cc_test { name: "net_test_stack_a2dp_native", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, @@ -863,29 +1239,30 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth_crypto_toolbox", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", "libchrome", "liblog", "libosi", - "libosi-AllocationTestHarness", ], sanitize: { address: true, cfi: true, misc_undefined: ["bounds"], }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } // gatt sr hash test cc_test { name: "net_test_stack_gatt_sr_hash_native", defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, include_dirs: [ "packages/modules/Bluetooth/system", @@ -894,11 +1271,16 @@ cc_test { "packages/modules/Bluetooth/system/stack/eatt", "packages/modules/Bluetooth/system/stack/include", ], - srcs: crypto_toolbox_srcs + [ + srcs: [ + ":LegacyStackSdp", ":TestCommonMainHandler", ":TestCommonMockFunctions", + ":TestMockBtif", + ":TestMockDevice", ":TestMockRustFfi", ":TestMockStackBtm", + ":TestMockStackL2cap", + ":TestMockStackMetrics", "gatt/gatt_db.cc", "gatt/gatt_sr_hash.cc", "gatt/gatt_utils.cc", @@ -913,26 +1295,38 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", "libgmock", "liblog", "libosi", + "libstatslog_bt", ], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } // Iso manager unit tests cc_test { name: "net_test_btm_iso", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, }, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -954,7 +1348,9 @@ cc_test { "test/common/mock_hcic_layer.cc", ], static_libs: [ + "libbluetooth-types", "libbt-common", + "libbt_shim_bridge", "libchrome", "libgmock", "liblog", @@ -970,18 +1366,19 @@ cc_test { undefined: true, }, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } // EATT unit tests cc_test { name: "net_test_eatt", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, }, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1015,29 +1412,39 @@ cc_test { "libcutils", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libevent", "libgmock", "liblog", "libosi", "libprotobuf-cpp-lite", + "libstatslog_bt", ], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + }, sanitize: { cfi: false, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_btm", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, test_options: { unit_test: true, }, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1050,20 +1457,19 @@ cc_test { "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/device/include", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/vnd/ble", ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], - srcs: crypto_toolbox_srcs + [ - ":BluetoothBtaaSources_host", + srcs: [ ":BluetoothHalSources_hci_host", ":BluetoothOsSources_host", - ":TestCommonLogMsg", + ":OsiCompatSources", ":TestCommonMainHandler", ":TestCommonMockFunctions", ":TestCommonStackConfig", + ":TestFakeLooper", + ":TestFakeThread", ":TestMockBta", ":TestMockBtif", ":TestMockDevice", @@ -1083,7 +1489,6 @@ cc_test { "acl/btm_acl.cc", "acl/btm_ble_connection_establishment.cc", "acl/btm_pm.cc", - "btm/ble_advertiser_hci_interface.cc", "btm/ble_scanner_hci_interface.cc", "btm/btm_ble.cc", "btm/btm_ble_addr.cc", @@ -1092,9 +1497,9 @@ cc_test { "btm/btm_ble_bgconn.cc", "btm/btm_ble_cont_energy.cc", "btm/btm_ble_gap.cc", - "btm/btm_ble_multi_adv.cc", "btm/btm_ble_privacy.cc", "btm/btm_ble_scanner.cc", + "btm/btm_ble_sec.cc", "btm/btm_client_interface.cc", "btm/btm_dev.cc", "btm/btm_devctl.cc", @@ -1102,31 +1507,44 @@ cc_test { "btm/btm_iot_config.cc", "btm/btm_iso.cc", "btm/btm_main.cc", - "btm/btm_scn.cc", "btm/btm_sco.cc", "btm/btm_sco_hci.cc", "btm/btm_sco_hfp_hal.cc", "btm/btm_sec.cc", + "btm/btm_sec_cb.cc", + "btm/btm_security_client_interface.cc", + "btm/hfp_lc3_decoder.cc", + "btm/hfp_lc3_encoder.cc", "btm/hfp_msbc_decoder.cc", "btm/hfp_msbc_encoder.cc", "metrics/stack_metrics_logging.cc", "test/btm/peer_packet_types_test.cc", "test/btm/sco_hci_test.cc", + "test/btm/sco_pkt_status_test.cc", + "test/btm/stack_btm_power_mode_test.cc", "test/btm/stack_btm_regression_tests.cc", + "test/btm/stack_btm_sec_test.cc", "test/btm/stack_btm_test.cc", "test/common/mock_eatt.cc", "test/stack_include_test.cc", ], static_libs: [ + "libbase", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libchrome", + "libcom.android.sysprop.bluetooth.wrapped", "libevent", - "libflatbuffers-cpp", "libgmock", + "liblc3", "liblog", "libosi", "libprotobuf-cpp-lite", @@ -1134,6 +1552,7 @@ cc_test { ], shared_libs: [ "libcrypto", + "server_configurable_flags", ], sanitize: { address: true, @@ -1145,14 +1564,15 @@ cc_test { undefined: true, }, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_hci", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1164,15 +1584,15 @@ cc_test { include_dirs: [ "packages/modules/Bluetooth/system", "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/vnd/ble", ], - srcs: crypto_toolbox_srcs + [ + srcs: [ ":TestCommonMockFunctions", "test/hci/stack_hci_test.cc", ], static_libs: [ + "libbluetooth_crypto_toolbox", "libbt-common", - "libbt-protos-lite", + "libbt_shim_bridge", "libbtdevice", "libbte", "libchrome", @@ -1193,14 +1613,14 @@ cc_test { undefined: true, }, }, + header_libs: ["libbluetooth_headers"], } cc_test { name: "net_test_stack_hid", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1213,13 +1633,12 @@ cc_test { "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/stack/btm", ], - srcs: crypto_toolbox_srcs + [ + srcs: [ ":TestCommonMockFunctions", ":TestMockStackBtm", ":TestMockStackL2cap", ":TestMockStackMetrics", ":TestMockStackSdp", - ":TestStubLegacyTrace", "hid/hidd_api.cc", "hid/hidd_conn.cc", "hid/hidh_api.cc", @@ -1227,8 +1646,12 @@ cc_test { "test/hid/stack_hid_test.cc", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libbte", "libchrome", @@ -1241,6 +1664,11 @@ cc_test { shared_libs: [ "libcrypto", ], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + }, sanitize: { address: true, all_undefined: true, @@ -1251,14 +1679,15 @@ cc_test { undefined: true, }, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_btu", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1273,10 +1702,8 @@ cc_test { ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], srcs: [ - ":TestCommonLogMsg", ":TestCommonMockFunctions", ":TestMockBta", ":TestMockBtif", @@ -1289,17 +1716,21 @@ cc_test { ":TestMockStackL2cap", ":TestMockStackMetrics", ":TestMockStackSmp", + "btu/btu_event.cc", "btu/btu_hcif.cc", - "btu/btu_task.cc", + "btu/main_thread.cc", "test/stack_btu_test.cc", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", @@ -1318,14 +1749,15 @@ cc_test { undefined: true, }, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_gatt", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1340,7 +1772,6 @@ cc_test { ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], srcs: [ ":OsiCompatSources", @@ -1356,7 +1787,6 @@ cc_test { ":TestMockSrvcDis", ":TestMockStackAcl", ":TestMockStackBtm", - ":TestMockStackCryptotoolbox", ":TestMockStackL2cap", ":TestMockStackSdp", ":TestMockStackSmp", @@ -1376,21 +1806,32 @@ cc_test { "test/gatt/stack_gatt_test.cc", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", "libprotobuf-cpp-lite", + "libstatslog_bt", ], shared_libs: [ "libbinder_ndk", "libcrypto", + "libcutils", ], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + }, sanitize: { address: true, all_undefined: true, @@ -1401,14 +1842,15 @@ cc_test { undefined: true, }, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_l2cap", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1423,11 +1865,9 @@ cc_test { ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], srcs: [ ":OsiCompatSources", - ":TestCommonLogMsg", ":TestCommonMainHandler", ":TestCommonMockFunctions", ":TestCommonStackConfig", @@ -1438,7 +1878,6 @@ cc_test { ":TestMockMainShim", ":TestMockStackAcl", ":TestMockStackBtm", - ":TestMockStackCryptotoolbox", ":TestMockStackHcic", ":TestMockStackSdp", ":TestMockStackSmp", @@ -1452,25 +1891,33 @@ cc_test { "test/stack_l2cap_test.cc", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libchrome", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", "libprotobuf-cpp-lite", + "libstatslog_bt", ], shared_libs: [ + "libbase", "libbinder_ndk", "libcrypto", + "libcutils", + "server_configurable_flags", ], target: { android: { shared_libs: [ "libPlatformProperties", + "libstatssocket", ], }, }, @@ -1484,14 +1931,15 @@ cc_test { undefined: true, }, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } cc_test { name: "net_test_stack_acl", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1506,11 +1954,9 @@ cc_test { ], generated_headers: [ "BluetoothGeneratedDumpsysDataSchema_h", - "BluetoothGeneratedPackets_h", ], srcs: [ ":OsiCompatSources", - ":TestCommonLogMsg", ":TestCommonMainHandler", ":TestCommonMockFunctions", ":TestCommonStackConfig", @@ -1524,7 +1970,6 @@ cc_test { ":TestMockRustFfi", ":TestMockStackBtm", ":TestMockStackBtu", - ":TestMockStackCryptotoolbox", ":TestMockStackGatt", ":TestMockStackHcic", ":TestMockStackL2cap", @@ -1536,20 +1981,32 @@ cc_test { "test/stack_acl_test.cc", ], static_libs: [ + "libbluetooth-types", + "libbluetooth_gd", "libbt-common", - "libbt-protos-lite", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libbtdevice", "libchrome", + "libcutils", "libevent", - "libflatbuffers-cpp", "libgmock", "liblog", "libosi", + "libstatslog_bt", ], shared_libs: [ + "libbase", "libbinder_ndk", "libcrypto", + "server_configurable_flags", ], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + }, sanitize: { address: true, all_undefined: true, @@ -1560,15 +2017,16 @@ cc_test { undefined: true, }, }, + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } // Bluetooth stack connection multiplexing cc_test { name: "net_test_stack_sdp", - test_suites: ["device-tests"], + test_suites: ["general-tests"], host_supported: true, defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -1585,7 +2043,6 @@ cc_test { ], srcs: [ ":LegacyStackSdp", - ":TestCommonLogMsg", ":TestCommonMockFunctions", ":TestMockBtif", ":TestMockOsi", @@ -1600,9 +2057,15 @@ cc_test { ], static_libs: [ "libbluetooth-types", + "libbluetooth_gd", "libbt-common", + "libbt-platform-protos-lite", + "libbt_shim_bridge", + "libbt_shim_ffi", "libchrome", "libgmock", "liblog", ], + header_libs: ["libbluetooth_headers"], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/stack/BUILD.gn b/system/stack/BUILD.gn index ed5317f5e6422618841941db7c9a687e2734bd9f..4592e3629ee8d6692a97ada98784197158c887a4 100644 --- a/system/stack/BUILD.gn +++ b/system/stack/BUILD.gn @@ -14,48 +14,39 @@ # limitations under the License. # -static_library("crypto_toolbox") { - sources = [ - "crypto_toolbox/aes.cc", - "crypto_toolbox/aes_cmac.cc", - "crypto_toolbox/crypto_toolbox.cc", - ] - - include_dirs = [ "//bt/system/" ] - - configs += [ "//bt/system:target_defaults" ] -} - +# Nonstandard codecs are associated with 3P libs and must be contained in MMC source_set("nonstandard_codecs") { if (defined(use.bt_nonstandard_codecs) && use.bt_nonstandard_codecs) { sources = [ "a2dp/a2dp_aac.cc", - "a2dp/a2dp_aac_decoder.cc", - "a2dp/a2dp_aac_encoder.cc", + "a2dp/a2dp_aac_decoder_linux.cc", + "a2dp/a2dp_aac_encoder_linux.cc", "a2dp/a2dp_vendor.cc", - "a2dp/a2dp_vendor_aptx.cc", - "a2dp/a2dp_vendor_aptx_encoder.cc", - "a2dp/a2dp_vendor_aptx_hd.cc", - "a2dp/a2dp_vendor_aptx_hd_encoder.cc", - "a2dp/a2dp_vendor_ldac.cc", - "a2dp/a2dp_vendor_ldac_decoder.cc", - "a2dp/a2dp_vendor_ldac_encoder.cc", + # Following are unimplemented + "a2dp/a2dp_vendor_aptx_linux.cc", + "a2dp/a2dp_vendor_aptx_hd_linux.cc", + "a2dp/a2dp_vendor_ldac_linux.cc", + "a2dp/a2dp_vendor_opus_linux.cc", ] include_dirs = [ "//bt/system", "//bt/system/bta/include", "//bt/system/btif/include", + "//bt/system/include", "//bt/system/internal_include", + "//bt/system/stack", "//bt/system/stack/include", + "//bt/system/utils/include", ] - deps = [ "//bt/system/gd/rust/shim:init_flags_bridge_header" ] + deps = [ + "//bt/system/gd/rust/shim:init_flags_bridge_header", + "//bt/system/stack/mmc", + ] configs += [ "//bt/system:target_defaults", - "//bt/system:external_libldac", - "//bt/system:external_aac", ] } } @@ -100,7 +91,6 @@ source_set("stack") { "bnep/bnep_api.cc", "bnep/bnep_main.cc", "bnep/bnep_utils.cc", - "btm/ble_advertiser_hci_interface.cc", "btm/ble_scanner_hci_interface.cc", "btm/btm_ble.cc", "btm/btm_ble_addr.cc", @@ -109,9 +99,9 @@ source_set("stack") { "btm/btm_ble_bgconn.cc", "btm/btm_ble_cont_energy.cc", "btm/btm_ble_gap.cc", - "btm/btm_ble_multi_adv.cc", "btm/btm_ble_privacy.cc", "btm/btm_ble_scanner.cc", + "btm/btm_ble_sec.cc", "btm/btm_client_interface.cc", "btm/btm_dev.cc", "btm/btm_devctl.cc", @@ -119,15 +109,19 @@ source_set("stack") { "btm/btm_iot_config.cc", "btm/btm_iso.cc", "btm/btm_main.cc", - "btm/btm_scn.cc", "btm/btm_sco.cc", "btm/btm_sco_hci.cc", "btm/btm_sco_hfp_hal_linux.cc", "btm/btm_sec.cc", + "btm/btm_sec_cb.cc", + "btm/btm_security_client_interface.cc", + "btm/hfp_lc3_encoder_linux.cc", + "btm/hfp_lc3_decoder_linux.cc", "btm/hfp_msbc_encoder.cc", "btm/hfp_msbc_decoder.cc", + "btu/btu_event.cc", "btu/btu_hcif.cc", - "btu/btu_task.cc", + "btu/main_thread.cc", "eatt/eatt.cc", "gap/gap_ble.cc", "gap/gap_conn.cc", @@ -223,15 +217,18 @@ source_set("stack") { ] deps = [ - ":crypto_toolbox", + "//bt/system/gd/crypto_toolbox:crypto_toolbox", ":nonstandard_codecs", "//bt/system:libbt-platform-protos-lite", "//bt/system/gd/rust/shim:init_flags_bridge_header", + "//bt/system/stack/mmc", "//bt/system/types", "//bt/system/types", ] - configs += [ "//bt/system:target_defaults" ] + configs += [ + "//bt/system:target_defaults", + ] } if (use.test) { @@ -313,19 +310,6 @@ if (defined(use.android) && use.android) { ] } - executable("net_test_stack_crypto_toolbox") { - sources = [ "test/crypto_toolbox_test.cc" ] - - include_dirs = [ "//bt/system/" ] - - deps = [ ":crypto_toolbox" ] - - configs += [ - "//bt/system:external_gmock_main", - "//bt/system:target_defaults", - ] - } - executable("net_test_stack_smp") { sources = [ "smp/p_256_curvepara.cc", @@ -363,7 +347,7 @@ if (defined(use.android) && use.android) { ] deps = [ - ":crypto_toolbox", + "//bt/system/gd:crypto_toolbox", "//bt/system/osi", "//bt/system/types", ] @@ -374,33 +358,4 @@ if (defined(use.android) && use.android) { "//bt/system:target_defaults", ] } - - executable("net_test_stack_multi_adv") { - sources = [ - "btm/btm_ble_multi_adv.cc", - "test/ble_advertiser_test.cc", - ] - - include_dirs = [ - "include", - "//bt/system/", - "//bt/system/internal_include", - "//bt/system/stack/btm", - ] - - libs = [ - "dl", - "pthread", - "resolv", - "rt", - "z", - ] - - deps = [ "//bt/system/types" ] - - configs += [ - "//bt/system:external_gmock_main", - "//bt/system:target_defaults", - ] - } } diff --git a/system/stack/a2dp/a2dp_aac.cc b/system/stack/a2dp/a2dp_aac.cc index 01cf293307a7f13ca941fbf0e8380777c1b2a1a6..4cb21dec8dafd9a6106871ac7962432600f6f3a8 100644 --- a/system/stack/a2dp/a2dp_aac.cc +++ b/system/stack/a2dp/a2dp_aac.cc @@ -30,7 +30,7 @@ #include "a2dp_aac_decoder.h" #include "a2dp_aac_encoder.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/osi.h" #include "osi/include/properties.h" #include "stack/include/bt_hdr.h" @@ -732,14 +732,6 @@ bool A2DP_InitCodecConfigAac(AvdtpSepConfig* p_cfg) { return false; } -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - /* Content protection info - support SCMS-T */ - uint8_t* p = p_cfg->protect_info; - *p++ = AVDT_CP_LOSC; - UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID); - p_cfg->num_protect = 1; -#endif - return true; } diff --git a/system/stack/a2dp/a2dp_aac_decoder.cc b/system/stack/a2dp/a2dp_aac_decoder.cc index 9c40f612c4b8fc9861c4d1927a17ebbaebe4f04f..639512b0c1b38ff3ee6c78997000a618e09066f5 100644 --- a/system/stack/a2dp/a2dp_aac_decoder.cc +++ b/system/stack/a2dp/a2dp_aac_decoder.cc @@ -21,9 +21,8 @@ #include #include -#include "a2dp_aac.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/include/bt_hdr.h" #define DECODE_BUF_LEN (8 * 2 * 1024) diff --git a/system/test/mock/mock_stack_crypto_toolbox_aes_cmac.cc b/system/stack/a2dp/a2dp_aac_decoder_linux.cc similarity index 51% rename from system/test/mock/mock_stack_crypto_toolbox_aes_cmac.cc rename to system/stack/a2dp/a2dp_aac_decoder_linux.cc index d6ff8d2110bf07b1cb31a93ff139048650ba0142..bad594c57db30d470a601b04e8f035667caaddcd 100644 --- a/system/test/mock/mock_stack_crypto_toolbox_aes_cmac.cc +++ b/system/stack/a2dp/a2dp_aac_decoder_linux.cc @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,26 +14,25 @@ * limitations under the License. */ -/* - * Generated mock file from original source file - * Functions generated:1 - */ +#define LOG_TAG "a2dp_aac_decoder" + +#include -#include -#include +#include "a2dp_aac_decoder.h" +#include "stack/include/bt_hdr.h" -#include "stack/crypto_toolbox/aes.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" -#include "test/common/mock_functions.h" +typedef struct { + decoded_data_callback_t decode_callback; +} tA2DP_AAC_DECODER_CB; -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +bool A2DP_LoadDecoderAac(void) { return false; } -namespace crypto_toolbox { -Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) { - inc_func_call_count(__func__); - Octet16 octet16; - return octet16; +void A2DP_UnloadDecoderAac(void) {} + +bool a2dp_aac_decoder_init(decoded_data_callback_t decode_callback) { + return false; } -} // namespace crypto_toolbox + +void a2dp_aac_decoder_cleanup(void) {} + +bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf) { return false; } diff --git a/system/stack/a2dp/a2dp_aac_encoder.cc b/system/stack/a2dp/a2dp_aac_encoder.cc index 550b1a295bc793407cf7f783275d50b1b172d3f9..1dd893e6a7b2c7a4b5d797af48b6bf05f5e1f411 100644 --- a/system/stack/a2dp/a2dp_aac_encoder.cc +++ b/system/stack/a2dp/a2dp_aac_encoder.cc @@ -26,9 +26,9 @@ #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 "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" // @@ -39,11 +39,7 @@ #define A2DP_AAC_ENCODER_INTERVAL_MS 20 // offset -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -#define A2DP_AAC_OFFSET (AVDT_MEDIA_OFFSET + 1) -#else #define A2DP_AAC_OFFSET AVDT_MEDIA_OFFSET -#endif typedef struct { uint32_t sample_rate; @@ -135,10 +131,7 @@ void a2dp_aac_encoder_init(const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, a2dp_aac_encoder_cb.peer_params = *p_peer_params; a2dp_aac_encoder_cb.timestamp = 0; - a2dp_aac_encoder_cb.use_SCMS_T = false; // TODO: should be a parameter -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - a2dp_aac_encoder_cb.use_SCMS_T = true; -#endif + a2dp_aac_encoder_cb.use_SCMS_T = false; // NOTE: Ignore the restart_input / restart_output flags - this initization // happens when the audio session is (re)started. diff --git a/system/stack/a2dp/a2dp_aac_encoder_linux.cc b/system/stack/a2dp/a2dp_aac_encoder_linux.cc new file mode 100644 index 0000000000000000000000000000000000000000..8c1b9c2729bfba69d8f9e9182263232a269a2b0e --- /dev/null +++ b/system/stack/a2dp/a2dp_aac_encoder_linux.cc @@ -0,0 +1,447 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "a2dp_aac_encoder" + +#include +#include +#include + +#include + +#include "a2dp_aac.h" +#include "a2dp_aac_encoder.h" +#include "common/time_util.h" +#include "internal_include/bt_target.h" +#include "mmc/codec_client/codec_client.h" +#include "mmc/proto/mmc_config.pb.h" +#include "os/log.h" +#include "os/rand.h" +#include "osi/include/allocator.h" +#include "stack/include/bt_hdr.h" + +const int A2DP_AAC_HEADER_LEN = 9; +const int A2DP_AAC_MAX_LEN_REPR = 4; +const int A2DP_AAC_MAX_PREFIX_SIZE = + AVDT_MEDIA_HDR_SIZE + A2DP_AAC_HEADER_LEN + A2DP_AAC_MAX_LEN_REPR; + +class FFmpegInterface { + public: + // Updates the context and configures codec parameters. + // + // Returns: + // The (fixed) input pcm frame size that the encoder accepts. + // Otherwise a negative errno on error. + int prepare_context(int sample_rate, int channel_count, int bit_rate, + int bit_depth, int effective_frame_size) { + clear_context(); + client = new mmc::CodecClient; + + mmc::AacEncoderParam param; + param.set_sample_rate(sample_rate); + param.set_channel_count(channel_count); + param.set_bit_rate(bit_rate); + param.set_bit_depth(bit_depth); + param.set_effective_frame_size(effective_frame_size); + + mmc::ConfigParam config; + *config.mutable_a2dp_aac_encoder_param() = param; + + int rc = client->init(config); + if (rc < 0) { + LOG_ERROR("%s: Init failed with error message, %s", __func__, + strerror(-rc)); + } + return rc; + } + + void clear_context() { + if (client) { + client->cleanup(); + delete client; + client = nullptr; + } + } + + // Returns a negative errno if the encoded frame was not produced. + // Otherwise returns the length of the encoded frame stored in `o_buf`. + int encode_pcm(uint8_t* i_buf, int i_len, uint8_t* o_buf, int o_len) { + if (i_buf == nullptr || o_buf == nullptr) { + LOG_ERROR("%s: Buffer is null", __func__); + return -EINVAL; + } + + if (!client) { + LOG_ERROR("%s: CodecClient does not init", __func__); + return -ENOENT; + } + + int rc = client->transcode(i_buf, i_len, o_buf, o_len); + + if (rc < 0) { + LOG_ERROR("%s: Encode failed with error message, %s", __func__, + strerror(-rc)); + } + return rc; + } + + private: + mmc::CodecClient* client = nullptr; +}; + +typedef struct { + float counter; + uint32_t bytes_per_tick; /* pcm bytes read for each media task tick */ + uint64_t last_frame_us; +} tA2DP_AAC_FEEDING_STATE; + +typedef struct { + uint64_t session_start_us; + size_t media_read_total_expected_packets; + size_t media_read_total_expected_reads_count; + size_t media_read_total_expected_read_bytes; + size_t media_read_total_dropped_packets; + size_t media_read_total_actual_reads_count; + size_t media_read_total_actual_read_bytes; +} a2dp_aac_encoder_stats_t; + +typedef struct { + a2dp_source_read_callback_t read_callback; + a2dp_source_enqueue_callback_t enqueue_callback; + tA2DP_ENCODER_INIT_PEER_PARAMS peer_params; + tA2DP_FEEDING_PARAMS feeding_params; + tA2DP_AAC_FEEDING_STATE aac_feeding_state; + uint16_t TxAaMtuSize; + uint32_t timestamp; // Timestamp embedded into the BT frames + uint32_t pcm_samples_per_frame; + uint32_t encoder_interval_ms; + a2dp_aac_encoder_stats_t stats; +} tA2DP_AAC_ENCODER_CB; + +static void a2dp_aac_get_num_frame_iteration(uint8_t* num_of_iterations, + uint8_t* num_of_frames, + uint64_t timestamp_us); +static void a2dp_aac_encode_frames(uint8_t nb_frame); +static bool a2dp_aac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read); +static uint16_t adjust_effective_mtu( + const tA2DP_ENCODER_INIT_PEER_PARAMS& peer_params); + +namespace { +tA2DP_AAC_ENCODER_CB a2dp_aac_encoder_cb; +FFmpegInterface codec_intf; +} // namespace + +bool A2DP_LoadEncoderAac() { return true; } + +void A2DP_UnloadEncoderAac(void) { + codec_intf.clear_context(); + a2dp_aac_encoder_cb = tA2DP_AAC_ENCODER_CB{}; +} + +void a2dp_aac_encoder_init(const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, + A2dpCodecConfig* a2dp_codec_config, + a2dp_source_read_callback_t read_callback, + a2dp_source_enqueue_callback_t enqueue_callback) { + uint8_t codec_info[AVDT_CODEC_SIZE]; + if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) { + LOG_ERROR( + "%s: Cannot update the codec encoder for %s: " + "invalid codec config", + __func__, a2dp_codec_config->name().c_str()); + return; + } + + uint16_t mtu = adjust_effective_mtu(*p_peer_params); + + int max_bit_rate = + A2DP_ComputeMaxBitRateAac(codec_info, mtu - A2DP_AAC_MAX_PREFIX_SIZE) / + 8 * 8; + int bit_rate = std::min(A2DP_GetBitRateAac(codec_info) / 8 * 8, max_bit_rate); + + tA2DP_SAMPLE_RATE sample_rate = A2DP_GetTrackSampleRateAac(codec_info); + tA2DP_CHANNEL_COUNT channel_count = A2DP_GetTrackChannelCountAac(codec_info); + tA2DP_BITS_PER_SAMPLE bits_per_sample = + a2dp_codec_config->getAudioBitsPerSample(); + + int pcm_samples_per_frame = codec_intf.prepare_context( + sample_rate, channel_count, bit_rate, bits_per_sample, mtu); + + if (pcm_samples_per_frame < 0) { + LOG_ERROR("%s: Failed to prepare context: %d", __func__, + pcm_samples_per_frame); + codec_intf.clear_context(); + return; // TODO(b/294165759): need to return an error + } + + uint32_t encoder_interval_ms = pcm_samples_per_frame * 1000 / sample_rate; + + a2dp_aac_encoder_cb = tA2DP_AAC_ENCODER_CB{ + .read_callback = read_callback, + .enqueue_callback = enqueue_callback, + .TxAaMtuSize = mtu, + .peer_params = *p_peer_params, + .timestamp = bluetooth::os::GenerateRandom(), // (RFC 6416) + .feeding_params = + { + .sample_rate = sample_rate, + .bits_per_sample = bits_per_sample, + .channel_count = channel_count, + }, + .aac_feeding_state = + tA2DP_AAC_FEEDING_STATE{ + .bytes_per_tick = (sample_rate * bits_per_sample / 8 * + channel_count * encoder_interval_ms) / + 1000, + }, + .pcm_samples_per_frame = static_cast(pcm_samples_per_frame), + .encoder_interval_ms = encoder_interval_ms, + .stats = + a2dp_aac_encoder_stats_t{ + .session_start_us = bluetooth::common::time_get_os_boottime_us(), + }, + }; +} + +void a2dp_aac_encoder_cleanup() { + codec_intf.clear_context(); + a2dp_aac_encoder_cb = tA2DP_AAC_ENCODER_CB{}; +} + +void a2dp_aac_feeding_reset() { + auto frame_length = a2dp_aac_encoder_cb.pcm_samples_per_frame; + auto sample_rate = a2dp_aac_encoder_cb.feeding_params.sample_rate; + if (sample_rate == 0) { + LOG_WARN("%s: Sample rate is not configured", __func__); + return; + } + + a2dp_aac_encoder_cb.encoder_interval_ms = frame_length * 1000 / sample_rate; + + a2dp_aac_encoder_cb.aac_feeding_state = tA2DP_AAC_FEEDING_STATE{ + .bytes_per_tick = (a2dp_aac_encoder_cb.feeding_params.sample_rate * + a2dp_aac_encoder_cb.feeding_params.bits_per_sample / + 8 * a2dp_aac_encoder_cb.feeding_params.channel_count * + a2dp_aac_encoder_cb.encoder_interval_ms) / + 1000, + }; + + LOG_WARN("%s: PCM bytes %d per tick (%dms)", __func__, + a2dp_aac_encoder_cb.aac_feeding_state.bytes_per_tick, + a2dp_aac_encoder_cb.encoder_interval_ms); +} + +void a2dp_aac_feeding_flush() { + a2dp_aac_encoder_cb.aac_feeding_state.counter = 0.0f; +} + +uint64_t a2dp_aac_get_encoder_interval_ms() { + return a2dp_aac_encoder_cb.encoder_interval_ms; +} + +int a2dp_aac_get_effective_frame_size() { + return a2dp_aac_encoder_cb.TxAaMtuSize; +} + +void a2dp_aac_send_frames(uint64_t timestamp_us) { + uint8_t nb_frame = 0; + uint8_t nb_iterations = 0; + + a2dp_aac_get_num_frame_iteration(&nb_iterations, &nb_frame, timestamp_us); + if (nb_frame == 0) return; + + for (uint8_t counter = 0; counter < nb_iterations; counter++) { + a2dp_aac_encode_frames(nb_frame); + } +} + +// Obtains the number of frames to send and number of iterations +// to be used. |num_of_iterations| and |num_of_frames| parameters +// are used as output param for returning the respective values. +static void a2dp_aac_get_num_frame_iteration(uint8_t* num_of_iterations, + uint8_t* num_of_frames, + uint64_t timestamp_us) { + uint32_t result = 0; + uint8_t nof = 0; + uint8_t noi = 1; + + uint32_t pcm_bytes_per_frame = + a2dp_aac_encoder_cb.pcm_samples_per_frame * + a2dp_aac_encoder_cb.feeding_params.channel_count * + a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8; + LOG_VERBOSE("%s: pcm_bytes_per_frame %u", __func__, pcm_bytes_per_frame); + + uint32_t us_this_tick = a2dp_aac_encoder_cb.encoder_interval_ms * 1000; + uint64_t now_us = timestamp_us; + if (a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us != 0) + us_this_tick = + (now_us - a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us); + a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us = now_us; + + a2dp_aac_encoder_cb.aac_feeding_state.counter += + (float)a2dp_aac_encoder_cb.aac_feeding_state.bytes_per_tick * + us_this_tick / (a2dp_aac_encoder_cb.encoder_interval_ms * 1000); + + result = a2dp_aac_encoder_cb.aac_feeding_state.counter / pcm_bytes_per_frame; + a2dp_aac_encoder_cb.aac_feeding_state.counter -= result * pcm_bytes_per_frame; + nof = result; + + LOG_VERBOSE("%s: effective num of frames %u, iterations %u", __func__, nof, + noi); + + *num_of_frames = nof; + *num_of_iterations = noi; +} + +static void a2dp_aac_encode_frames(uint8_t nb_frame) { + uint8_t read_buffer[BT_DEFAULT_BUFFER_SIZE]; + int pcm_bytes_per_frame = a2dp_aac_encoder_cb.pcm_samples_per_frame * + a2dp_aac_encoder_cb.feeding_params.channel_count * + a2dp_aac_encoder_cb.feeding_params.bits_per_sample / + 8; + CHECK(pcm_bytes_per_frame <= static_cast(sizeof(read_buffer))); + + while (nb_frame) { + a2dp_aac_encoder_cb.stats.media_read_total_expected_packets++; + + uint32_t bytes_read = 0; + if (!a2dp_aac_read_feeding(read_buffer, &bytes_read)) { + LOG_WARN("%s: Underflow %u", __func__, nb_frame); + a2dp_aac_encoder_cb.aac_feeding_state.counter += + nb_frame * a2dp_aac_encoder_cb.pcm_samples_per_frame * + a2dp_aac_encoder_cb.feeding_params.channel_count * + a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8; + return; + } + + BT_HDR* p_buf = (BT_HDR*)osi_calloc(BT_DEFAULT_BUFFER_SIZE); + p_buf->offset = AVDT_MEDIA_OFFSET; + p_buf->len = 0; + p_buf->layer_specific = 0; + + int written = codec_intf.encode_pcm( + read_buffer, bytes_read, (uint8_t*)(p_buf + 1) + p_buf->offset, + BT_DEFAULT_BUFFER_SIZE - 1 - p_buf->offset); + + if (written < 0) { + a2dp_aac_encoder_cb.stats.media_read_total_dropped_packets++; + osi_free(p_buf); + return; + } + + if (written == 0) { + LOG_INFO("%s: Dropped a frame, likely due to buffering", __func__); + a2dp_aac_encoder_cb.stats.media_read_total_dropped_packets++; + osi_free(p_buf); + continue; + } + + p_buf->layer_specific++; + p_buf->len += written; + --nb_frame; + + *((uint32_t*)(p_buf + 1)) = a2dp_aac_encoder_cb.timestamp; + + a2dp_aac_encoder_cb.timestamp += + p_buf->layer_specific * a2dp_aac_encoder_cb.pcm_samples_per_frame; + + if (!a2dp_aac_encoder_cb.enqueue_callback(p_buf, 1, bytes_read)) return; + } +} + +static bool a2dp_aac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read) { + uint32_t read_size = a2dp_aac_encoder_cb.pcm_samples_per_frame * + a2dp_aac_encoder_cb.feeding_params.channel_count * + a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8; + + a2dp_aac_encoder_cb.stats.media_read_total_expected_reads_count++; + a2dp_aac_encoder_cb.stats.media_read_total_expected_read_bytes += read_size; + + /* Read Data from UIPC channel */ + uint32_t nb_byte_read = + a2dp_aac_encoder_cb.read_callback(read_buffer, read_size); + a2dp_aac_encoder_cb.stats.media_read_total_actual_read_bytes += nb_byte_read; + *bytes_read = nb_byte_read; + + if (nb_byte_read < read_size) { + if (nb_byte_read == 0) return false; + + /* Fill the unfilled part of the read buffer with silence (0) */ + std::fill_n((uint8_t*)read_buffer + nb_byte_read, read_size - nb_byte_read, + 0x00); + nb_byte_read = read_size; + } + a2dp_aac_encoder_cb.stats.media_read_total_actual_reads_count++; + + return true; +} + +static uint16_t adjust_effective_mtu( + const tA2DP_ENCODER_INIT_PEER_PARAMS& peer_params) { + uint16_t mtu_size = + BT_DEFAULT_BUFFER_SIZE - AVDT_MEDIA_OFFSET - sizeof(BT_HDR); + if (mtu_size > peer_params.peer_mtu) { + mtu_size = peer_params.peer_mtu; + } + LOG_VERBOSE("%s: original AVDTP MTU size: %d", __func__, mtu_size); + if (peer_params.is_peer_edr && !peer_params.peer_supports_3mbps) { + // This condition would be satisfied only if the remote device is + // EDR and supports only 2 Mbps, but the effective AVDTP MTU size + // exceeds the 2DH5 packet size. + LOG_VERBOSE("%s: The remote device is EDR but does not support 3 Mbps", + __func__); + if (mtu_size > MAX_2MBPS_AVDTP_MTU) { + LOG_WARN("%s: Restricting AVDTP MTU size from %d to %d", __func__, + mtu_size, MAX_2MBPS_AVDTP_MTU); + mtu_size = MAX_2MBPS_AVDTP_MTU; + } + } + return mtu_size; +} + +void A2dpCodecConfigAacSource::debug_codec_dump(int fd) { + a2dp_aac_encoder_stats_t* stats = &a2dp_aac_encoder_cb.stats; + + A2dpCodecConfig::debug_codec_dump(fd); + + auto codec_specific_1 = getCodecConfig().codec_specific_1; + dprintf( + fd, + " AAC bitrate mode : %s " + "(0x%" PRIx64 ")\n", + ((codec_specific_1 & ~A2DP_AAC_VARIABLE_BIT_RATE_MASK) == 0 ? "Constant" + : "Variable"), + codec_specific_1); + dprintf(fd, " Encoder interval (ms): %" PRIu64 "\n", + a2dp_aac_get_encoder_interval_ms()); + dprintf(fd, " Effective MTU: %d\n", a2dp_aac_get_effective_frame_size()); + dprintf(fd, + " Packet counts (expected/dropped) : %zu / " + "%zu\n", + stats->media_read_total_expected_packets, + stats->media_read_total_dropped_packets); + + dprintf(fd, + " PCM read counts (expected/actual) : %zu / " + "%zu\n", + stats->media_read_total_expected_reads_count, + stats->media_read_total_actual_reads_count); + + dprintf(fd, + " PCM read bytes (expected/actual) : %zu / " + "%zu\n", + stats->media_read_total_expected_read_bytes, + stats->media_read_total_actual_read_bytes); +} diff --git a/system/stack/a2dp/a2dp_api.cc b/system/stack/a2dp/a2dp_api.cc index a5a3140a12a764645d3a8f1d27b4dd6e3e6d81de..13bda9fded61e7ebf8327ca915e2dc7e226c9a00 100644 --- a/system/stack/a2dp/a2dp_api.cc +++ b/system/stack/a2dp/a2dp_api.cc @@ -30,15 +30,19 @@ #include "a2dp_int.h" #include "avdt_api.h" -#include "bt_target.h" -#include "main/shim/dumpsys.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" +#include "osi/include/osi.h" // UNUSED_ATTR #include "sdpdefs.h" #include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + using bluetooth::Uuid; /***************************************************************************** @@ -66,7 +70,8 @@ static uint16_t a2dp_attr_list[] = { * Returns Nothing. * *****************************************************************************/ -static void a2dp_sdp_cback(tSDP_STATUS status) { +static void a2dp_sdp_cback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status) { tSDP_DISC_REC* p_rec = NULL; tSDP_DISC_ATTR* p_attr; bool found = false; @@ -80,7 +85,7 @@ static void a2dp_sdp_cback(tSDP_STATUS status) { /* loop through all records we found */ do { /* get next record; if none found, we're done */ - if ((p_rec = SDP_FindServiceInDb( + if ((p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( a2dp_cb.find.p_db, a2dp_cb.find.service_uuid, p_rec)) == NULL) { break; } @@ -88,7 +93,8 @@ static void a2dp_sdp_cback(tSDP_STATUS status) { peer_address = p_rec->remote_bd_addr; /* get service name */ - if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) { + if ((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_SERVICE_NAME)) != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { a2dp_svc.p_service_name = (char*)p_attr->attr_value.v.array; a2dp_svc.service_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); @@ -100,8 +106,8 @@ static void a2dp_sdp_cback(tSDP_STATUS status) { } /* get provider name */ - if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PROVIDER_NAME)) != - NULL) { + if ((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_PROVIDER_NAME)) != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { a2dp_svc.p_provider_name = (char*)p_attr->attr_value.v.array; a2dp_svc.provider_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); @@ -113,7 +119,7 @@ static void a2dp_sdp_cback(tSDP_STATUS status) { } /* get supported features */ - if ((p_attr = SDP_FindAttributeInRec( + if ((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -126,7 +132,8 @@ static void a2dp_sdp_cback(tSDP_STATUS status) { } /* get AVDTP version */ - if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem)) { + if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, UUID_PROTOCOL_AVDTP, &elem)) { a2dp_svc.avdt_version = elem.params[0]; LOG_VERBOSE("avdt_version: 0x%x", a2dp_svc.avdt_version); } @@ -208,7 +215,8 @@ tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name, return A2DP_INVALID_PARAMS; /* add service class id list */ - result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList( + sdp_handle, 1, &service_uuid); memset((void*)proto_list, 0, A2DP_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM)); @@ -221,38 +229,40 @@ tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name, proto_list[1].num_params = 1; proto_list[1].params[0] = a2dp_cb.avdt_sdp_ver; - result &= SDP_AddProtocolList(sdp_handle, A2DP_NUM_PROTO_ELEMS, proto_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList( + sdp_handle, A2DP_NUM_PROTO_ELEMS, proto_list); /* add profile descriptor list */ - result &= SDP_AddProfileDescriptorList( + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList( sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2DP_VERSION); /* add supported feature */ if (features != 0) { p = temp; UINT16_TO_BE_STREAM(p, features); - result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, - UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, (uint32_t)2, + (uint8_t*)temp); } /* add provider name */ if (p_provider_name != NULL) { - result &= SDP_AddAttribute( + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_provider_name) + 1), (uint8_t*)p_provider_name); } /* add service name */ if (p_service_name != NULL) { - result &= SDP_AddAttribute( + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name); } /* add browse group list */ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; - result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, - browse_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence( + sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); return (result ? A2DP_SUCCESS : A2DP_FAIL); } @@ -319,8 +329,9 @@ tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, const RawAddress& bd_addr, a2dp_cb.find.p_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_db->db_len); Uuid uuid_list = Uuid::From16Bit(service_uuid); - if (!SDP_InitDiscoveryDb(a2dp_cb.find.p_db, p_db->db_len, 1, &uuid_list, - p_db->num_attr, p_db->p_attrs)) { + if (!get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + a2dp_cb.find.p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr, + p_db->p_attrs)) { osi_free_and_reset((void**)&a2dp_cb.find.p_db); LOG_ERROR("Unable to initialize SDP discovery for peer %s UUID 0x%04X", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), service_uuid); @@ -332,8 +343,8 @@ tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, const RawAddress& bd_addr, a2dp_cb.find.p_cback = p_cback; /* perform service search */ - if (!SDP_ServiceSearchAttributeRequest(bd_addr, a2dp_cb.find.p_db, - a2dp_sdp_cback)) { + if (!get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest( + bd_addr, a2dp_cb.find.p_db, a2dp_sdp_cback)) { a2dp_cb.find.service_uuid = 0; a2dp_cb.find.p_cback = NULL; osi_free_and_reset((void**)&a2dp_cb.find.p_db); @@ -346,33 +357,6 @@ tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, const RawAddress& bd_addr, return A2DP_SUCCESS; } -/****************************************************************************** - * - * Function A2DP_SetTraceLevel - * - * Description Sets the trace level for A2D. If 0xff is passed, the - * current trace level is returned. - * - * Input Parameters: - * new_level: The level to set the A2DP tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new trace level or current trace level if - * the input parameter is 0xff. - * - *****************************************************************************/ -uint8_t A2DP_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) a2dp_cb.trace_level = new_level; - - return (a2dp_cb.trace_level); -} - /****************************************************************************** * Function A2DP_BitsSet * @@ -403,12 +387,6 @@ void A2DP_Init(void) { memset(&a2dp_cb, 0, sizeof(tA2DP_CB)); a2dp_cb.avdt_sdp_ver = AVDT_VERSION; - -#if defined(A2DP_INITIAL_TRACE_LEVEL) - a2dp_cb.trace_level = A2DP_INITIAL_TRACE_LEVEL; -#else - a2dp_cb.trace_level = BT_TRACE_LEVEL_NONE; -#endif } uint16_t A2DP_GetAvdtpVersion() { return a2dp_cb.avdt_sdp_ver; } diff --git a/system/stack/a2dp/a2dp_codec_config.cc b/system/stack/a2dp/a2dp_codec_config.cc index beb8a71e65ecda9aadb03933c5085da492529956..8cd18594879bfa20e9e310c4f7f3ddc403259b5f 100644 --- a/system/stack/a2dp/a2dp_codec_config.cc +++ b/system/stack/a2dp/a2dp_codec_config.cc @@ -20,12 +20,10 @@ #define LOG_TAG "a2dp_codec" -#include "a2dp_codec_api.h" - #include -#include #include "a2dp_aac.h" +#include "a2dp_codec_api.h" #include "a2dp_sbc.h" #include "a2dp_vendor.h" diff --git a/system/stack/a2dp/a2dp_int.h b/system/stack/a2dp/a2dp_int.h index 0a718e195e9c5ff8906cca3f29df384a18004c3a..fd0e2bf6553c81b0dd62b262895de210cb46b6bb 100644 --- a/system/stack/a2dp/a2dp_int.h +++ b/system/stack/a2dp/a2dp_int.h @@ -50,7 +50,6 @@ typedef struct { typedef struct { tA2DP_FIND_CB find; /* find service control block */ - uint8_t trace_level; uint16_t avdt_sdp_ver; /* AVDTP version */ } tA2DP_CB; diff --git a/system/stack/a2dp/a2dp_sbc.cc b/system/stack/a2dp/a2dp_sbc.cc index 77acfb7cb2d8234a35df5895852cb6da8141a49c..e05ab913009d7c13960ce6a4f1e49199215d0471 100644 --- a/system/stack/a2dp/a2dp_sbc.cc +++ b/system/stack/a2dp/a2dp_sbc.cc @@ -33,7 +33,7 @@ #include "a2dp_sbc_decoder.h" #include "a2dp_sbc_encoder.h" #include "embdrv/sbc/encoder/include/sbc_encoder.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" @@ -825,14 +825,6 @@ bool A2DP_InitCodecConfigSbc(AvdtpSepConfig* p_cfg) { return false; } -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - /* Content protection info - support SCMS-T */ - uint8_t* p = p_cfg->protect_info; - *p++ = AVDT_CP_LOSC; - UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID); - p_cfg->num_protect = 1; -#endif - return true; } diff --git a/system/stack/a2dp/a2dp_sbc_decoder.cc b/system/stack/a2dp/a2dp_sbc_decoder.cc index 7fd8f5038cdb8544494c4f49da82615d8595af4d..da28cacc48607baed90aea3c18e2de50c7f9ded8 100644 --- a/system/stack/a2dp/a2dp_sbc_decoder.cc +++ b/system/stack/a2dp/a2dp_sbc_decoder.cc @@ -22,7 +22,7 @@ #include "embdrv/sbc/decoder/include/oi_codec_sbc.h" #include "embdrv/sbc/decoder/include/oi_status.h" -#include "osi/include/log.h" +#include "os/log.h" #include "stack/include/bt_hdr.h" typedef struct { diff --git a/system/stack/a2dp/a2dp_sbc_encoder.cc b/system/stack/a2dp/a2dp_sbc_encoder.cc index 6bd683817ccec29a9e7497139b0576bcff61b159..977198425332366b30a6d43926ff9cda2abccce0 100644 --- a/system/stack/a2dp/a2dp_sbc_encoder.cc +++ b/system/stack/a2dp/a2dp_sbc_encoder.cc @@ -29,9 +29,9 @@ #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/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" /* Buffer pool */ @@ -58,14 +58,8 @@ #define A2DP_SBC_SCALE_FACTOR_BITS 4 // A2DP Spec v1.3, 12.4, Table 12.13 /* offset */ -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -/* A2DP header will contain a CP header of size 1 */ -#define A2DP_HDR_SIZE 2 -#define A2DP_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_SBC_MPL_HDR_LEN + 1) -#else #define A2DP_HDR_SIZE 1 #define A2DP_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_SBC_MPL_HDR_LEN) -#endif typedef struct { uint32_t aa_frame_counter; diff --git a/system/stack/a2dp/a2dp_vendor.cc b/system/stack/a2dp/a2dp_vendor.cc index d0a44232058526a600372cf4286c972e20d8abaa..8cb171c9e0869ffd72e216d0daf651cdad1f593c 100644 --- a/system/stack/a2dp/a2dp_vendor.cc +++ b/system/stack/a2dp/a2dp_vendor.cc @@ -26,9 +26,6 @@ #include "a2dp_vendor_aptx_hd.h" #include "a2dp_vendor_ldac.h" #include "a2dp_vendor_opus.h" -#include "bt_target.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" bool A2DP_IsVendorSourceCodecValid(const uint8_t* p_codec_info) { diff --git a/system/stack/a2dp/a2dp_vendor_aptx.cc b/system/stack/a2dp/a2dp_vendor_aptx.cc index 6590a8449f69bf535758d30933776c457d7b61eb..4d6ec80def7e2eafb678ba92161bc746da7e8085 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx.cc @@ -31,7 +31,8 @@ #include "a2dp_vendor.h" #include "a2dp_vendor_aptx_encoder.h" #include "btif_av_co.h" -#include "osi/include/log.h" +#include "internal_include/bt_trace.h" +#include "os/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" @@ -229,12 +230,8 @@ static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAptx( bool A2DP_VendorUsesRtpHeaderAptx(UNUSED_ATTR bool content_protection_enabled, UNUSED_ATTR const uint8_t* p_codec_info) { -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - return true; -#else // no RTP header for aptX classic and no Copy Protection byte return false; -#endif } const char* A2DP_VendorCodecNameAptx(UNUSED_ATTR const uint8_t* p_codec_info) { @@ -422,14 +419,6 @@ bool A2DP_VendorInitCodecConfigAptx(AvdtpSepConfig* p_cfg) { return false; } -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - /* Content protection info - support SCMS-T */ - uint8_t* p = p_cfg->protect_info; - *p++ = AVDT_CP_LOSC; - UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID); - p_cfg->num_protect = 1; -#endif - return true; } diff --git a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc index 5a3785c0f944fe3413d58d6b9c22ead8423a9f48..3568492f0a35c606bb898c4fb196203aa4c5dea3 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc @@ -27,9 +27,9 @@ #include "a2dp_vendor_aptx.h" #include "aptXbtenc.h" #include "common/time_util.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" // @@ -43,12 +43,8 @@ static const tAPTX_API aptx_api = { }; // offset -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -#define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET + 1) -#else // no RTP header for aptX classic #define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET - AVDT_MEDIA_HDR_SIZE) -#endif #define A2DP_APTX_MAX_PCM_BYTES_PER_READ 4096 @@ -139,10 +135,7 @@ void a2dp_vendor_aptx_encoder_init( a2dp_aptx_encoder_cb.timestamp = 0; /* aptX encoder config */ - a2dp_aptx_encoder_cb.use_SCMS_T = false; // TODO: should be a parameter -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - a2dp_aptx_encoder_cb.use_SCMS_T = true; -#endif + a2dp_aptx_encoder_cb.use_SCMS_T = false; a2dp_aptx_encoder_cb.aptx_encoder_state = osi_malloc(aptx_api.sizeof_params_func()); diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd.cc index 1260a296fa1afb406092b89e56c69b637641ef93..78c3cf8c4fb3d2cb656bb23385427e7f9f9d73e3 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_hd.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_hd.cc @@ -31,7 +31,8 @@ #include "a2dp_vendor.h" #include "a2dp_vendor_aptx_hd_encoder.h" #include "btif_av_co.h" -#include "osi/include/log.h" +#include "internal_include/bt_trace.h" +#include "os/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" @@ -440,14 +441,6 @@ bool A2DP_VendorInitCodecConfigAptxHd(AvdtpSepConfig* p_cfg) { return false; } -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - /* Content protection info - support SCMS-T */ - uint8_t* p = p_cfg->protect_info; - *p++ = AVDT_CP_LOSC; - UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID); - p_cfg->num_protect = 1; -#endif - return true; } diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc index 749ffdf463c215f37d716f9f75b071f8427814ea..bfef8c2b5ff92eea458ad172c31129466bec6e10 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc @@ -27,9 +27,9 @@ #include "a2dp_vendor_aptx_hd.h" #include "aptXHDbtenc.h" #include "common/time_util.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" // @@ -43,11 +43,7 @@ static const tAPTX_HD_API aptx_hd_api = { }; // offset -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -#define A2DP_APTX_HD_OFFSET (AVDT_MEDIA_OFFSET + 1) -#else #define A2DP_APTX_HD_OFFSET AVDT_MEDIA_OFFSET -#endif #define A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ 4096 @@ -139,10 +135,7 @@ void a2dp_vendor_aptx_hd_encoder_init( a2dp_aptx_hd_encoder_cb.timestamp = 0; /* aptX-HD encoder config */ - a2dp_aptx_hd_encoder_cb.use_SCMS_T = false; // TODO: should be a parameter -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - a2dp_aptx_hd_encoder_cb.use_SCMS_T = true; -#endif + a2dp_aptx_hd_encoder_cb.use_SCMS_T = false; a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state = osi_malloc(aptx_hd_api.sizeof_params_func()); diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd_linux.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd_linux.cc new file mode 100644 index 0000000000000000000000000000000000000000..923d40035db997329a147ef8eb34e25efe65b908 --- /dev/null +++ b/system/stack/a2dp/a2dp_vendor_aptx_hd_linux.cc @@ -0,0 +1,138 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Stubbed non-standard codec + +#include + +#include "a2dp_vendor_aptx_hd.h" + +bool A2DP_IsVendorSourceCodecValidAptxHd(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorPeerSinkCodecValidAptxHd(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_VendorUsesRtpHeaderAptxHd(bool content_protection_enabled, + const uint8_t* p_codec_info) { + return false; +} + +const char* A2DP_VendorCodecNameAptxHd(const uint8_t* p_codec_info) { + return "AptxHd"; +} + +bool A2DP_VendorCodecTypeEqualsAptxHd(const uint8_t* p_codec_info_a, + const uint8_t* p_codec_info_b) { + return false; +} + +bool A2DP_VendorCodecEqualsAptxHd(const uint8_t* p_codec_info_a, + const uint8_t* p_codec_info_b) { + return false; +} + +int A2DP_VendorGetBitRateAptxHd(const uint8_t* p_codec_info) { return -1; } + +int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetTrackChannelCountAptxHd(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetSinkTrackChannelTypeAptxHd(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetChannelModeCodeAptxHd(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetFrameSizeAptxHd(const uint8_t* p_codec_info) { return -1; } + +bool A2DP_VendorGetPacketTimestampAptxHd(const uint8_t* p_codec_info, + const uint8_t* p_data, + uint32_t* p_timestamp) { + return false; +} + +bool A2DP_VendorBuildCodecHeaderAptxHd(const uint8_t* p_codec_info, + BT_HDR* p_buf, + uint16_t frames_per_packet) { + return false; +} + +std::string A2DP_VendorCodecInfoStringAptxHd(const uint8_t* p_codec_info) { + return "Unsupported codec: AptxHd"; +} + +const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptxHd( + const uint8_t* p_codec_info) { + return nullptr; +} + +const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceAptxHd( + const uint8_t* p_codec_info) { + return nullptr; +} + +bool A2DP_VendorAdjustCodecAptxHd(uint8_t* p_codec_info) { return false; } + +btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexAptxHd( + const uint8_t* p_codec_info) { + return BTAV_A2DP_CODEC_INDEX_MAX; +} + +btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexAptxHd( + const uint8_t* p_codec_info) { + return BTAV_A2DP_CODEC_INDEX_MAX; +} + +const char* A2DP_VendorCodecIndexStrAptxHd(void) { return "AptxHd"; } + +bool A2DP_VendorInitCodecConfigAptxHd(AvdtpSepConfig* p_cfg) { return false; } + +A2dpCodecConfigAptxHd::A2dpCodecConfigAptxHd( + btav_a2dp_codec_priority_t codec_priority) + : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, + A2DP_VendorCodecIndexStrAptxHd(), codec_priority) {} + +A2dpCodecConfigAptxHd::~A2dpCodecConfigAptxHd() {} + +bool A2dpCodecConfigAptxHd::init() { return false; } + +bool A2dpCodecConfigAptxHd::useRtpHeaderMarkerBit() const { return false; } + +void A2dpCodecConfigAptxHd::debug_codec_dump(int fd) {} + +bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info, + bool is_capability, + uint8_t* p_result_codec_config) { + return false; +} + +bool A2dpCodecConfigAptxHd::setPeerCodecCapabilities( + const uint8_t* p_peer_codec_capabilities) { + return false; +} diff --git a/system/stack/a2dp/a2dp_vendor_aptx_linux.cc b/system/stack/a2dp/a2dp_vendor_aptx_linux.cc new file mode 100644 index 0000000000000000000000000000000000000000..24a68229ee02130989b57b604207bde2d205c297 --- /dev/null +++ b/system/stack/a2dp/a2dp_vendor_aptx_linux.cc @@ -0,0 +1,137 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Stubbed non-standard codec + +#include + +#include "a2dp_vendor_aptx.h" + +bool A2DP_IsVendorSourceCodecValidAptx(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorPeerSinkCodecValidAptx(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_VendorUsesRtpHeaderAptx(bool content_protection_enabled, + const uint8_t* p_codec_info) { + return false; +} + +const char* A2DP_VendorCodecNameAptx(const uint8_t* p_codec_info) { + return "Aptx"; +} + +bool A2DP_VendorCodecTypeEqualsAptx(const uint8_t* p_codec_info_a, + const uint8_t* p_codec_info_b) { + return false; +} + +bool A2DP_VendorCodecEqualsAptx(const uint8_t* p_codec_info_a, + const uint8_t* p_codec_info_b) { + return false; +} + +int A2DP_VendorGetBitRateAptx(const uint8_t* p_codec_info) { return -1; } + +int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetTrackChannelCountAptx(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetSinkTrackChannelTypeAptx(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetChannelModeCodeAptx(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetFrameSizeAptx(const uint8_t* p_codec_info) { return -1; } + +bool A2DP_VendorGetPacketTimestampAptx(const uint8_t* p_codec_info, + const uint8_t* p_data, + uint32_t* p_timestamp) { + return false; +} + +bool A2DP_VendorBuildCodecHeaderAptx(const uint8_t* p_codec_info, BT_HDR* p_buf, + uint16_t frames_per_packet) { + return false; +} + +std::string A2DP_VendorCodecInfoStringAptx(const uint8_t* p_codec_info) { + return "Unsupported codec: Aptx"; +} + +const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptx( + const uint8_t* p_codec_info) { + return nullptr; +} + +const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceAptx( + const uint8_t* p_codec_info) { + return nullptr; +} + +bool A2DP_VendorAdjustCodecAptx(uint8_t* p_codec_info) { return false; } + +btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexAptx( + const uint8_t* p_codec_info) { + return BTAV_A2DP_CODEC_INDEX_MAX; +} + +btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexAptx( + const uint8_t* p_codec_info) { + return BTAV_A2DP_CODEC_INDEX_MAX; +} + +const char* A2DP_VendorCodecIndexStrAptx(void) { return "Aptx"; } + +bool A2DP_VendorInitCodecConfigAptx(AvdtpSepConfig* p_cfg) { return false; } + +A2dpCodecConfigAptx::A2dpCodecConfigAptx( + btav_a2dp_codec_priority_t codec_priority) + : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, + A2DP_VendorCodecIndexStrAptx(), codec_priority) {} + +A2dpCodecConfigAptx::~A2dpCodecConfigAptx() {} + +bool A2dpCodecConfigAptx::init() { return false; } + +bool A2dpCodecConfigAptx::useRtpHeaderMarkerBit() const { return false; } + +void A2dpCodecConfigAptx::debug_codec_dump(int fd) {} + +bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info, + bool is_capability, + uint8_t* p_result_codec_config) { + return false; +} + +bool A2dpCodecConfigAptx::setPeerCodecCapabilities( + const uint8_t* p_peer_codec_capabilities) { + return false; +} diff --git a/system/stack/a2dp/a2dp_vendor_ldac.cc b/system/stack/a2dp/a2dp_vendor_ldac.cc index 7bb098f5bc75042ea88ba96965b17181c741b773..65e899177829337345174fe7c0e5be1ce63977d0 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac.cc @@ -28,11 +28,11 @@ #include #include -#include "a2dp_vendor.h" #include "a2dp_vendor_ldac_decoder.h" #include "a2dp_vendor_ldac_encoder.h" #include "btif_av_co.h" -#include "osi/include/log.h" +#include "internal_include/bt_trace.h" +#include "os/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" @@ -622,14 +622,6 @@ bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) { return false; } -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - /* Content protection info - support SCMS-T */ - uint8_t* p = p_cfg->protect_info; - *p++ = AVDT_CP_LOSC; - UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID); - p_cfg->num_protect = 1; -#endif - return true; } diff --git a/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc index f6dbd46a6e4c6c23cf2320cf3c3f496e3527cb19..3b734520a5c03bbaae7b0f24c12537bfd5fb3cfa 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc @@ -20,17 +20,14 @@ #include #include -#include #include #include #include #include #include -#include "a2dp_vendor.h" #include "a2dp_vendor_ldac.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "os/log.h" #include "stack/include/bt_hdr.h" // @@ -74,11 +71,7 @@ static tLDAC_BCO_SUSPEND ldac_BCO_suspend_func; static tLDAC_BCO_CONFIGURE ldac_BCO_configure_func; // offset -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN + 1) -#else #define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN) -#endif typedef struct { uint32_t sample_rate; diff --git a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc index c2a1f886d39495ed3992be0262bca15114c0e7fa..d7f1ce8af64305af465f06b731b2a9edaf08865d 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc @@ -28,12 +28,11 @@ #include #include -#include "a2dp_vendor.h" #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/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" // @@ -48,11 +47,7 @@ #define A2DP_LDAC_MEDIA_BYTES_PER_FRAME 128 // offset -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN + 1) -#else #define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN) -#endif typedef struct { uint32_t sample_rate; @@ -152,10 +147,7 @@ void a2dp_vendor_ldac_encoder_init( a2dp_ldac_encoder_cb.last_ldac_abr_eqmid = -1; a2dp_ldac_encoder_cb.ldac_abr_adjustments = 0; - a2dp_ldac_encoder_cb.use_SCMS_T = false; // TODO: should be a parameter -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - a2dp_ldac_encoder_cb.use_SCMS_T = true; -#endif + a2dp_ldac_encoder_cb.use_SCMS_T = false; // NOTE: Ignore the restart_input / restart_output flags - this initization // happens when the audio session is (re)started. diff --git a/system/stack/a2dp/a2dp_vendor_ldac_linux.cc b/system/stack/a2dp/a2dp_vendor_ldac_linux.cc new file mode 100644 index 0000000000000000000000000000000000000000..e856cd9a8fb527d95449c60c9562d42744429bd3 --- /dev/null +++ b/system/stack/a2dp/a2dp_vendor_ldac_linux.cc @@ -0,0 +1,167 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Stubbed non-standard codec. + +#include "a2dp_vendor_ldac.h" + +bool A2DP_IsVendorSourceCodecValidLdac(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorSinkCodecValidLdac(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorPeerSourceCodecValidLdac(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorPeerSinkCodecValidLdac(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorSinkCodecSupportedLdac(const uint8_t* p_codec_info) { + return false; +} +bool A2DP_IsPeerSourceCodecSupportedLdac(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_VendorUsesRtpHeaderLdac(bool content_protection_enabled, + const uint8_t* p_codec_info) { + return false; +} + +const char* A2DP_VendorCodecNameLdac(const uint8_t* p_codec_info) { + return "Ldac"; +} + +bool A2DP_VendorCodecTypeEqualsLdac(const uint8_t* p_codec_info_a, + const uint8_t* p_codec_info_b) { + return false; +} + +bool A2DP_VendorCodecEqualsLdac(const uint8_t* p_codec_info_a, + const uint8_t* p_codec_info_b) { + return false; +} + +int A2DP_VendorGetBitRateLdac(const uint8_t* p_codec_info) { return -1; } + +int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetSinkTrackChannelTypeLdac(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetChannelModeCodeLdac(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetFrameSizeLdac(const uint8_t* p_codec_info) { return -1; } + +bool A2DP_VendorGetPacketTimestampLdac(const uint8_t* p_codec_info, + const uint8_t* p_data, + uint32_t* p_timestamp) { + return false; +} + +bool A2DP_VendorBuildCodecHeaderLdac(const uint8_t* p_codec_info, BT_HDR* p_buf, + uint16_t frames_per_packet) { + return false; +} + +std::string A2DP_VendorCodecInfoStringLdac(const uint8_t* p_codec_info) { + return "Unsupported codec: Ldac"; +} + +const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac( + const uint8_t* p_codec_info) { + return nullptr; +} + +const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceLdac( + const uint8_t* p_codec_info) { + return nullptr; +} + +bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info) { return false; } + +btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac( + const uint8_t* p_codec_info) { + return BTAV_A2DP_CODEC_INDEX_MAX; +} + +btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexLdac( + const uint8_t* p_codec_info) { + return BTAV_A2DP_CODEC_INDEX_MAX; +} + +const char* A2DP_VendorCodecIndexStrLdac(void) { return "Ldac"; } + +const char* A2DP_VendorCodecIndexStrLdacSink(void) { return "Ldac SINK"; } + +bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) { return false; } + +bool A2DP_VendorInitCodecConfigLdacSink(AvdtpSepConfig* p_cfg) { return false; } + +A2dpCodecConfigLdacSource::A2dpCodecConfigLdacSource( + btav_a2dp_codec_priority_t codec_priority) + : A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, + A2DP_VendorCodecIndexStrLdac(), codec_priority, + true) {} + +A2dpCodecConfigLdacSource::~A2dpCodecConfigLdacSource() {} + +bool A2dpCodecConfigLdacSource::init() { return false; } + +bool A2dpCodecConfigLdacSource::useRtpHeaderMarkerBit() const { return false; } + +void A2dpCodecConfigLdacSource::debug_codec_dump(int fd) {} + +bool A2dpCodecConfigLdacBase::setCodecConfig(const uint8_t* p_peer_codec_info, + bool is_capability, + uint8_t* p_result_codec_config) { + return false; +} + +bool A2dpCodecConfigLdacBase::setPeerCodecCapabilities( + const uint8_t* p_peer_codec_capabilities) { + return false; +} + +A2dpCodecConfigLdacSink::A2dpCodecConfigLdacSink( + btav_a2dp_codec_priority_t codec_priority) + : A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SINK_LDAC, + A2DP_VendorCodecIndexStrLdacSink(), + codec_priority, false) {} + +A2dpCodecConfigLdacSink::~A2dpCodecConfigLdacSink() {} + +bool A2dpCodecConfigLdacSink::init() { return false; } + +bool A2dpCodecConfigLdacSink::useRtpHeaderMarkerBit() const { return false; } diff --git a/system/stack/a2dp/a2dp_vendor_opus.cc b/system/stack/a2dp/a2dp_vendor_opus.cc index a8222ad068269ca6fff3f1bb263a9e0172a1f8b8..0ce0e7ac401f54190495d1a730e6302d24255868 100644 --- a/system/stack/a2dp/a2dp_vendor_opus.cc +++ b/system/stack/a2dp/a2dp_vendor_opus.cc @@ -28,12 +28,10 @@ #include #include -#include "a2dp_vendor.h" #include "a2dp_vendor_opus_decoder.h" #include "a2dp_vendor_opus_encoder.h" -#include "bt_target.h" -#include "btif_av_co.h" -#include "osi/include/log.h" +#include "internal_include/bt_trace.h" +#include "os/log.h" #include "osi/include/osi.h" // data type for the Opus Codec Information Element */ @@ -665,14 +663,6 @@ bool A2DP_VendorInitCodecConfigOpus(AvdtpSepConfig* p_cfg) { return false; } -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - /* Content protection info - support SCMS-T */ - uint8_t* p = p_cfg->protect_info; - *p++ = AVDT_CP_LOSC; - UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID); - p_cfg->num_protect = 1; -#endif - return true; } diff --git a/system/stack/a2dp/a2dp_vendor_opus_encoder.cc b/system/stack/a2dp/a2dp_vendor_opus_encoder.cc index 83390b362bf352de23020d68ffaed9b26b6d9e6b..7c85b9005c1e7592bccf265bfee5af2eae762230 100644 --- a/system/stack/a2dp/a2dp_vendor_opus_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_opus_encoder.cc @@ -108,12 +108,8 @@ void a2dp_vendor_opus_encoder_cleanup(void) { bluetooth::common::time_get_os_boottime_us(); a2dp_opus_encoder_cb.timestamp = 0; - -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - a2dp_opus_encoder_cb.use_SCMS_T = true; -#else a2dp_opus_encoder_cb.use_SCMS_T = false; -#endif + return; } diff --git a/system/stack/a2dp/a2dp_vendor_opus_linux.cc b/system/stack/a2dp/a2dp_vendor_opus_linux.cc new file mode 100644 index 0000000000000000000000000000000000000000..15a3a123cb5a509b8fb427b3ddb96fe282c3b315 --- /dev/null +++ b/system/stack/a2dp/a2dp_vendor_opus_linux.cc @@ -0,0 +1,174 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Stubbed non-standard codec. + +#include "a2dp_vendor.h" +#include "a2dp_vendor_opus.h" + +bool A2DP_IsVendorSourceCodecValidOpus(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorSinkCodecValidOpus(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorPeerSourceCodecValidOpus(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorPeerSinkCodecValidOpus(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_IsVendorSinkCodecSupportedOpus(const uint8_t* p_codec_info) { + return false; +} +bool A2DP_IsPeerSourceCodecSupportedOpus(const uint8_t* p_codec_info) { + return false; +} + +bool A2DP_VendorUsesRtpHeaderOpus(bool content_protection_enabled, + const uint8_t* p_codec_info) { + return false; +} + +const char* A2DP_VendorCodecNameOpus(const uint8_t* p_codec_info) { + return "Opus"; +} + +bool A2DP_VendorCodecTypeEqualsOpus(const uint8_t* p_codec_info_a, + const uint8_t* p_codec_info_b) { + return false; +} + +bool A2DP_VendorCodecEqualsOpus(const uint8_t* p_codec_info_a, + const uint8_t* p_codec_info_b) { + return false; +} + +int A2DP_VendorGetBitRateOpus(const uint8_t* p_codec_info) { return -1; } + +int A2DP_VendorGetTrackSampleRateOpus(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetTrackBitsPerSampleOpus(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetTrackChannelCountOpus(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetSinkTrackChannelTypeOpus(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetChannelModeCodeOpus(const uint8_t* p_codec_info) { + return -1; +} + +int A2DP_VendorGetFrameSizeOpus(const uint8_t* p_codec_info) { return -1; } + +bool A2DP_VendorGetPacketTimestampOpus(const uint8_t* p_codec_info, + const uint8_t* p_data, + uint32_t* p_timestamp) { + return false; +} + +bool A2DP_VendorBuildCodecHeaderOpus(const uint8_t* p_codec_info, BT_HDR* p_buf, + uint16_t frames_per_packet) { + return false; +} + +std::string A2DP_VendorCodecInfoStringOpus(const uint8_t* p_codec_info) { + return "Unsupported codec: Opus"; +} + +const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceOpus( + const uint8_t* p_codec_info) { + return nullptr; +} + +const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceOpus( + const uint8_t* p_codec_info) { + return nullptr; +} + +bool A2DP_VendorAdjustCodecOpus(uint8_t* p_codec_info) { return false; } + +btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexOpus( + const uint8_t* p_codec_info) { + return BTAV_A2DP_CODEC_INDEX_MAX; +} + +btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexOpus( + const uint8_t* p_codec_info) { + return BTAV_A2DP_CODEC_INDEX_MAX; +} + +const char* A2DP_VendorCodecIndexStrOpus(void) { return "Opus"; } + +const char* A2DP_VendorCodecIndexStrOpusSink(void) { return "Opus SINK"; } + +bool A2DP_VendorInitCodecConfigOpus(AvdtpSepConfig* p_cfg) { return false; } + +bool A2DP_VendorInitCodecConfigOpusSink(AvdtpSepConfig* p_cfg) { return false; } + +A2dpCodecConfigOpusSource::A2dpCodecConfigOpusSource( + btav_a2dp_codec_priority_t codec_priority) + : A2dpCodecConfigOpusBase(BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS, + A2DP_VendorCodecIndexStrOpus(), codec_priority, + true) {} + +A2dpCodecConfigOpusSource::~A2dpCodecConfigOpusSource() {} + +bool A2dpCodecConfigOpusSource::init() { return false; } + +bool A2dpCodecConfigOpusSource::useRtpHeaderMarkerBit() const { return false; } + +void A2dpCodecConfigOpusSource::debug_codec_dump(int fd) {} + +bool A2dpCodecConfigOpusBase::setCodecConfig(const uint8_t* p_peer_codec_info, + bool is_capability, + uint8_t* p_result_codec_config) { + return false; +} + +bool A2dpCodecConfigOpusBase::setPeerCodecCapabilities( + const uint8_t* p_peer_codec_capabilities) { + return false; +} + +A2dpCodecConfigOpusSink::A2dpCodecConfigOpusSink( + btav_a2dp_codec_priority_t codec_priority) + : A2dpCodecConfigOpusBase(BTAV_A2DP_CODEC_INDEX_SINK_OPUS, + A2DP_VendorCodecIndexStrOpusSink(), + codec_priority, false) {} + +A2dpCodecConfigOpusSink::~A2dpCodecConfigOpusSink() {} + +bool A2dpCodecConfigOpusSink::init() { return false; } + +bool A2dpCodecConfigOpusSink::useRtpHeaderMarkerBit() const { return false; } + +bool A2dpCodecConfigOpusSink::updateEncoderUserConfig( + const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input, + bool* p_restart_output, bool* p_config_updated) { + return false; +} diff --git a/system/stack/acl/acl.cc b/system/stack/acl/acl.cc index 193f2e8b98293dd0338985839b35ea86f11e5ed9..8342ad9751f691a3cfe6e89e1173c355c0d3ab3f 100644 --- a/system/stack/acl/acl.cc +++ b/system/stack/acl/acl.cc @@ -14,14 +14,11 @@ * limitations under the License. */ -#include - -#include "main/shim/dumpsys.h" -#include "osi/include/log.h" #include "stack/acl/acl.h" #include "types/raw_address.h" void tACL_CONN::Reset() { + remote_version_received = false; memset(peer_le_features, 0, sizeof(peer_le_features)); peer_le_features_valid = false; memset(peer_lmp_feature_pages, 0, sizeof(peer_lmp_feature_pages)); diff --git a/system/stack/acl/acl.h b/system/stack/acl/acl.h index d3697164011442922b8f3e13ccedbd21fe5cc099..5fbc10c9fec0e914a4fe78acfdafaddeebe40ef4 100644 --- a/system/stack/acl/acl.h +++ b/system/stack/acl/acl.h @@ -18,17 +18,17 @@ #include #include -#include -#include +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" #include "stack/acl/peer_packet_types.h" -#include "stack/include/acl_api_types.h" -#include "stack/include/bt_types.h" -#include "stack/include/btm_api_types.h" +#include "stack/btm/power_mode.h" +#include "stack/include/btm_status.h" #include "stack/include/hcimsgs.h" #include "types/bt_transport.h" #include "types/hci_role.h" #include "types/raw_address.h" +#include "types/remote_version_type.h" enum btm_acl_encrypt_state_t { BTM_ACL_ENCRYPT_STATE_IDLE = 0, @@ -46,11 +46,6 @@ enum btm_acl_swkey_state_t { BTM_ACL_SWKEY_STATE_IN_PROGRESS = 5, }; -enum btm_data_direction { - HOST_TO_CONTROLLER = 0, - CONTROLLER_TO_HOST = 1, -}; - /* Policy settings status */ typedef enum : uint16_t { HCI_DISABLE_ALL_LM_MODES = 0, @@ -142,7 +137,7 @@ typedef struct { } tSSR_PARAMS; #define BTM_PM_REC_NOT_USED 0 -typedef struct { +typedef struct tBTM_PM_RCB { tBTM_PM_STATUS_CBACK* cback = nullptr; /* to notify the registered party of mode change event */ uint8_t mask = 0; /* registered request mask. 0, if this entry is not used */ @@ -180,6 +175,9 @@ struct tACL_CONN { BD_FEATURES peer_lmp_feature_pages[HCI_EXT_FEATURES_PAGE_MAX + 1]; bool peer_lmp_feature_valid[HCI_EXT_FEATURES_PAGE_MAX + 1]; + /* Whether "Read Remote Version Information Complete" was received */ + bool remote_version_received{false}; + RawAddress active_remote_addr; tBLE_ADDR_TYPE active_remote_addr_type; @@ -311,66 +309,8 @@ struct tACL_CONN { uint8_t sca; /* Sleep clock accuracy */ void Reset(); - - struct tPolicy { - tBTM_PM_MODE Mode() const { return this->mode.mode_; } - struct { - bool IsPending() const { return pending_ != BTM_PM_MD_UNKNOWN; } - tBTM_PM_MODE Pending() const { return pending_; } - uint16_t Interval() const { return interval_; } - - private: - tBTM_PM_MODE mode_{BTM_PM_MD_ACTIVE}; - tBTM_PM_MODE pending_{BTM_PM_MD_UNKNOWN}; - uint16_t interval_{0}; - friend tBTM_STATUS bluetooth::shim::BTM_SetPowerMode( - uint16_t, const tBTM_PM_PWR_MD& new_mode); - friend void bluetooth::shim::btm_pm_on_mode_change(tHCI_STATUS status, - uint16_t handle, - tHCI_MODE hci_mode, - uint16_t interval); - friend void tACL_CONN::Reset(); - friend tBTM_PM_MODE tACL_CONN::tPolicy::Mode() const; - } mode; - - hci_role_t Role() const { return this->role.role_; } - struct { - unsigned RoleSwitchFailedCount() const { return role_switch_failed_cnt_; } - - private: - hci_role_t role_{HCI_ROLE_CENTRAL}; - unsigned role_switch_failed_cnt_{0}; - friend void tACL_CONN::Reset(); - friend hci_role_t tACL_CONN::tPolicy::Role() const; - } role; - - struct { - bool IsPending() const { return pending_; } - - private: - bool pending_{false}; - friend tBTM_STATUS bluetooth::shim::BTM_SetSsrParams(uint16_t handle, - uint16_t max_lat, - uint16_t min_rmt_to, - uint16_t min_loc_to); - friend void bluetooth::shim::btm_pm_on_sniff_subrating( - tHCI_STATUS status, uint16_t handle, - uint16_t maximum_transmit_latency, uint16_t maximum_receive_latency, - uint16_t minimum_remote_timeout, uint16_t minimum_local_timeout); - friend void tACL_CONN::Reset(); - } sniff_subrating; - - tLINK_POLICY Settings() const { return settings_; } - - private: - tLINK_POLICY settings_{kAllLinkPoliciesEnabled}; - friend void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy); - friend void tACL_CONN::Reset(); - } policy; }; -struct controller_t; - /**************************************************** ** ACL Management API ****************************************************/ diff --git a/system/stack/acl/ble_acl.cc b/system/stack/acl/ble_acl.cc index 076941bd0699987d19bfbe96fd77c559f1c02c4d..1d42c7af1ccfda3e9c26925bbc7ed56434990129 100644 --- a/system/stack/acl/ble_acl.cc +++ b/system/stack/acl/ble_acl.cc @@ -14,26 +14,27 @@ * limitations under the License. */ +#define LOG_TAG "acl" + #include -#include "osi/include/log.h" +#include "gd/common/init_flags.h" +#include "os/log.h" #include "stack/btm/btm_ble_int.h" #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/include/acl_api.h" -#include "stack/include/bt_types.h" +#include "stack/include/btm_ble_addr.h" +#include "stack/include/btm_ble_privacy.h" #include "stack/include/l2cap_hci_link_interface.h" #include "types/raw_address.h" extern tBTM_CB btm_cb; -void btm_ble_advertiser_notify_terminated_legacy(uint8_t status, - uint16_t connection_handle); void btm_ble_increment_link_topology_mask(uint8_t link_role); -bool maybe_resolve_address(RawAddress* bda, tBLE_ADDR_TYPE* bda_type); - static bool acl_ble_common_connection( const tBLE_BD_ADDR& address_with_type, uint16_t handle, tHCI_ROLE role, bool is_in_security_db, uint16_t conn_interval, uint16_t conn_latency, @@ -86,12 +87,9 @@ void acl_ble_enhanced_connection_complete( } if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT) - btm_ble_refresh_peer_resolvable_private_addr( - address_with_type.bda, peer_rpa, tBTM_SEC_BLE::BTM_BLE_ADDR_RRA); + btm_ble_refresh_peer_resolvable_private_addr(address_with_type.bda, + peer_rpa, BTM_BLE_ADDR_RRA); btm_ble_update_mode_operation(role, &address_with_type.bda, HCI_SUCCESS); - - if (role == HCI_ROLE_PERIPHERAL) - btm_ble_advertiser_notify_terminated_legacy(HCI_SUCCESS, handle); } static bool maybe_resolve_received_address( @@ -184,3 +182,11 @@ void acl_ble_data_length_change_event(uint16_t handle, uint16_t max_tx_octets, handle, max_tx_octets, max_tx_time, max_rx_octets, max_rx_time); l2cble_process_data_length_change_event(handle, max_tx_octets, max_rx_octets); } + +uint64_t btm_get_next_private_addrress_interval_ms() { + /* 7 minutes minimum, 15 minutes maximum for random address refreshing */ + const uint64_t interval_min_ms = (7 * 60 * 1000); + const uint64_t interval_random_part_max_ms = (8 * 60 * 1000); + + return interval_min_ms + std::rand() % interval_random_part_max_ms; +} diff --git a/system/stack/acl/btm_acl.cc b/system/stack/acl/btm_acl.cc index 75e3fcda89bc0c013329e5483ea8ab5daa63c9b8..1f0631880f75773265e6ea6c7ed625d63d5ac05e 100644 --- a/system/stack/acl/btm_acl.cc +++ b/system/stack/acl/btm_acl.cc @@ -40,24 +40,22 @@ #include "bta/include/bta_dm_acl.h" #include "bta/sys/bta_sys.h" #include "btif/include/btif_acl.h" +#include "common/init_flags.h" #include "common/metrics.h" #include "device/include/controller.h" #include "device/include/device_iot_config.h" #include "device/include/interop.h" -#include "gd/metrics/metrics_state.h" #include "include/l2cap_hci_link_interface.h" +#include "internal_include/bt_target.h" #include "main/shim/acl_api.h" -#include "main/shim/btm_api.h" #include "main/shim/controller.h" #include "main/shim/dumpsys.h" -#include "main/shim/l2c_api.h" -#include "main/shim/metrics_api.h" -#include "main/shim/shim.h" +#include "os/log.h" #include "os/parameter_provider.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "osi/include/properties.h" +#include "osi/include/stack_power_telemetry.h" #include "rust/src/connection/ffi/connection_shim.h" #include "rust/src/core/ffi/types.h" #include "stack/acl/acl.h" @@ -66,30 +64,35 @@ #include "stack/btm/btm_int_types.h" #include "stack/btm/btm_sec.h" #include "stack/btm/security_device_record.h" -#include "stack/gatt/connection_manager.h" #include "stack/include/acl_api.h" +#include "stack/include/acl_api_types.h" #include "stack/include/acl_hci_link_interface.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" #include "stack/include/btm_api.h" +#include "stack/include/btm_ble_api.h" #include "stack/include/btm_iso_api.h" -#include "stack/include/btu.h" #include "stack/include/hci_error_code.h" +#include "stack/include/hcimsgs.h" #include "stack/include/l2cap_acl_interface.h" +#include "stack/include/l2cdefs.h" +#include "stack/include/main_thread.h" #include "stack/include/sco_hci_link_interface.h" #include "types/hci_role.h" #include "types/raw_address.h" -#include "os/metrics.h" #ifndef PROPERTY_LINK_SUPERVISION_TIMEOUT #define PROPERTY_LINK_SUPERVISION_TIMEOUT \ "bluetooth.core.acl.link_supervision_timeout" #endif +using bluetooth::legacy::hci::GetInterface; + void BTM_update_version_info(const RawAddress& bd_addr, const remote_version_info& remote_version_info); -void gatt_find_in_device_record(const RawAddress& bd_addr, - tBLE_BD_ADDR* address_with_type); +static void find_in_device_record(const RawAddress& bd_addr, + tBLE_BD_ADDR* address_with_type); void l2c_link_hci_conn_comp(tHCI_STATUS status, uint16_t handle, const RawAddress& p_bda); @@ -125,9 +128,6 @@ struct RoleChangeView { namespace { StackAclBtmAcl internal_; std::unique_ptr delayed_role_change_ = nullptr; -const bluetooth::legacy::hci::Interface& GetLegacyHciInterface() { - return bluetooth::legacy::hci::GetInterface(); -} } typedef struct { @@ -148,7 +148,7 @@ constexpr uint16_t BTM_ACL_EXCEPTION_PKTS_MASK = HCI_PKT_TYPES_MASK_NO_2_DH3 | HCI_PKT_TYPES_MASK_NO_3_DH3 | HCI_PKT_TYPES_MASK_NO_2_DH5 | HCI_PKT_TYPES_MASK_NO_3_DH5); -inline bool IsEprAvailable(const tACL_CONN& p_acl) { +static bool IsEprAvailable(const tACL_CONN& p_acl) { if (!p_acl.peer_lmp_feature_valid[0]) { LOG_WARN("Checking incomplete feature page read"); return false; @@ -198,33 +198,20 @@ void NotifyAclFeaturesReadComplete(tACL_CONN& p_acl, } // namespace -static void hci_btsnd_hcic_disconnect(tACL_CONN& p_acl, tHCI_STATUS reason, - std::string comment) { +static void disconnect_acl(tACL_CONN& p_acl, tHCI_STATUS reason, + std::string comment) { LOG_INFO("Disconnecting peer:%s reason:%s comment:%s", ADDRESS_TO_LOGGABLE_CSTR(p_acl.remote_addr), hci_error_code_text(reason).c_str(), comment.c_str()); p_acl.disconnect_reason = reason; - if (bluetooth::common::init_flags:: - use_unified_connection_manager_is_enabled()) { - if (!p_acl.is_transport_br_edr()) { - // TODO(aryarahul): this should be moved into GATT, so when a client - // disconnects, it removes its request to autoConnect, even if the ACL - // link stays up due to the presence of other clients. - bluetooth::connection::GetConnectionManager() - .stop_all_connections_to_device(bluetooth::core::ToRustAddress( - tBLE_BD_ADDR{.bda = p_acl.active_remote_addr, - .type = p_acl.active_remote_addr_type})); - } - } - return bluetooth::shim::ACL_Disconnect( p_acl.hci_handle, p_acl.is_transport_br_edr(), reason, comment); } void StackAclBtmAcl::hci_start_role_switch_to_central(tACL_CONN& p_acl) { - GetLegacyHciInterface().StartRoleSwitch( - p_acl.remote_addr, static_cast(HCI_ROLE_CENTRAL)); + GetInterface().StartRoleSwitch(p_acl.remote_addr, + static_cast(HCI_ROLE_CENTRAL)); p_acl.set_switch_role_in_progress(); p_acl.rs_disc_pending = BTM_SEC_RS_PENDING; } @@ -494,17 +481,6 @@ void btm_acl_create_failed(const RawAddress& bda, tBT_TRANSPORT transport, BTA_dm_acl_up_failed(bda, transport, hci_status); } -void btm_configure_data_path(uint8_t direction, uint8_t path_id, - std::vector vendor_config) { - if (direction != btm_data_direction::CONTROLLER_TO_HOST && - direction != btm_data_direction::HOST_TO_CONTROLLER) { - LOG_WARN("Unknown data direction"); - return; - } - - btsnd_hcic_configure_data_path(direction, path_id, vendor_config); -} - /******************************************************************************* * * Function btm_acl_removed @@ -551,8 +527,6 @@ void btm_acl_device_down(void) { BTM_db_reset(); } -void btm_acl_set_paging(bool value) { btm_cb.is_paging = value; } - void btm_acl_update_inquiry_status(uint8_t status) { btm_cb.is_inquiry = status == BTM_INQUIRY_STARTED; BTIF_dm_report_inquiry_status_change(status); @@ -592,10 +566,6 @@ tBTM_STATUS BTM_GetRole(const RawAddress& remote_bd_addr, tHCI_ROLE* p_role) { * ******************************************************************************/ tBTM_STATUS BTM_SwitchRoleToCentral(const RawAddress& remote_bd_addr) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - bluetooth::shim::L2CA_SwitchRoleToCentral(remote_bd_addr); - return BTM_SUCCESS; - } if (!controller_get_interface()->supports_central_peripheral_role_switch()) { LOG_INFO("Local controller does not support role switching"); return BTM_MODE_UNSUPPORTED; @@ -725,9 +695,8 @@ void btm_acl_encrypt_change(uint16_t handle, uint8_t status, /* If a disconnect is pending, issue it now that role switch has completed */ if (p->rs_disc_pending == BTM_SEC_DISC_PENDING) { - hci_btsnd_hcic_disconnect( - *p, HCI_ERR_PEER_USER, - "stack::acl::btm_acl::encrypt after role switch"); + disconnect_acl(*p, HCI_ERR_PEER_USER, + "stack::acl::btm_acl::encrypt after role switch"); } p->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ } @@ -840,6 +809,9 @@ void BTM_default_block_role_switch() { ~HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH); } +extern void bta_gattc_continue_discovery_if_needed(const RawAddress& bd_addr, + uint16_t acl_handle); + /******************************************************************************* * * Function btm_read_remote_version_complete @@ -862,6 +834,8 @@ static void maybe_chain_more_commands_after_read_remote_version_complete( case BT_TRANSPORT_LE: l2cble_notify_le_connection(p_acl_cb->remote_addr); l2cble_use_preferred_conn_params(p_acl_cb->remote_addr); + bta_gattc_continue_discovery_if_needed(p_acl_cb->remote_addr, + p_acl_cb->Handle()); break; case BT_TRANSPORT_BR_EDR: /** @@ -889,6 +863,7 @@ void btm_process_remote_version_complete(uint8_t status, uint16_t handle, LOG_WARN("Received remote version complete for unknown acl"); return; } + p_acl_cb->remote_version_received = true; if (status == HCI_SUCCESS) { p_acl_cb->remote_version_info.lmp_version = lmp_version; @@ -960,51 +935,9 @@ void btm_process_remote_ext_features(tACL_CONN* p_acl_cb, * ******************************************************************************/ void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - // GD L2cap reads this automatically - return; - } btsnd_hcic_rmt_ext_features(handle, page_number); } -void btm_read_remote_features_complete(uint16_t handle, uint8_t* features) { - tACL_CONN* p_acl_cb = internal_.acl_get_connection_from_handle(handle); - if (p_acl_cb == nullptr) { - LOG_WARN("Unable to find active acl"); - return; - } - - /* Copy the received features page */ - STREAM_TO_ARRAY(p_acl_cb->peer_lmp_feature_pages[0], features, - HCI_FEATURE_BYTES_PER_PAGE); - p_acl_cb->peer_lmp_feature_valid[0] = true; - - /* save remote supported features to iot conf file */ - std::string key = IOT_CONF_KEY_RT_SUPP_FEATURES "_" + std::to_string(0); - - DEVICE_IOT_CONFIG_ADDR_SET_BIN(p_acl_cb->remote_addr, key, - p_acl_cb->peer_lmp_feature_pages[0], - BD_FEATURES_LEN); - - if ((HCI_LMP_EXTENDED_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[0])) && - (controller_get_interface() - ->supports_reading_remote_extended_features())) { - /* if the remote controller has extended features and local controller - supports HCI_Read_Remote_Extended_Features command then start reading - these feature starting with extended features page 1 */ - LOG_DEBUG("Start reading remote extended features"); - btm_read_remote_ext_features(handle, 1); - return; - } - - /* Remote controller has no extended features. Process remote controller - supported features (features page 0). */ - btm_process_remote_ext_features(p_acl_cb, 0); - - /* Continue with HCI connection establishment */ - internal_.btm_establish_continue(p_acl_cb); -} - /******************************************************************************* * * Function btm_read_remote_ext_features_complete @@ -1220,19 +1153,11 @@ tBTM_STATUS BTM_SetLinkSuperTout(const RawAddress& remote_bda, bool BTM_IsAclConnectionUp(const RawAddress& remote_bda, tBT_TRANSPORT transport) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_IsLinkEstablished(remote_bda, transport); - } - return internal_.btm_bda_to_acl(remote_bda, transport) != nullptr; } bool BTM_IsAclConnectionUpAndHandleValid(const RawAddress& remote_bda, tBT_TRANSPORT transport) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_IsLinkEstablished(remote_bda, transport); - } - tACL_CONN* p_acl = internal_.btm_bda_to_acl(remote_bda, transport); if (p_acl == nullptr) { LOG_WARN("Unable to find active acl"); @@ -1256,9 +1181,6 @@ bool BTM_IsAclConnectionUpFromHandle(uint16_t hci_handle) { * ******************************************************************************/ uint16_t BTM_GetNumAclLinks(void) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_GetNumLinks(); - } return static_cast(btm_cb.acl_cb_.NumberOfActiveLinks()); } @@ -1302,10 +1224,6 @@ bool btm_is_acl_locally_initiated(void) { ******************************************************************************/ uint16_t BTM_GetHCIConnHandle(const RawAddress& remote_bda, tBT_TRANSPORT transport) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::BTM_GetHCIConnHandle(remote_bda, transport); - } - tACL_CONN* p; p = internal_.btm_bda_to_acl(remote_bda, transport); if (p != (tACL_CONN*)NULL) { @@ -1327,10 +1245,10 @@ uint16_t BTM_GetHCIConnHandle(const RawAddress& remote_bda, ******************************************************************************/ bool BTM_IsPhy2mSupported(const RawAddress& remote_bda, tBT_TRANSPORT transport) { tACL_CONN* p; - BTM_TRACE_DEBUG("BTM_IsPhy2mSupported"); + LOG_VERBOSE("BTM_IsPhy2mSupported"); p = internal_.btm_bda_to_acl(remote_bda, transport); if (p == (tACL_CONN*)NULL) { - BTM_TRACE_DEBUG("BTM_IsPhy2mSupported: no connection"); + LOG_VERBOSE("BTM_IsPhy2mSupported: no connection"); return false; } @@ -1527,8 +1445,8 @@ void StackAclBtmAcl::btm_acl_role_changed(tHCI_STATUS hci_status, /* If a disconnect is pending, issue it now that role switch has completed */ if (p_acl->rs_disc_pending == BTM_SEC_DISC_PENDING) { - hci_btsnd_hcic_disconnect(*p_acl, HCI_ERR_PEER_USER, - "stack::acl::btm_acl::role after role switch"); + disconnect_acl(*p_acl, HCI_ERR_PEER_USER, + "stack::acl::btm_acl::role after role switch"); } p_acl->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ } @@ -1590,8 +1508,7 @@ bool StackAclBtmAcl::change_connection_packet_types( } link.pkt_types_mask = packet_type_mask; - bluetooth::legacy::hci::GetInterface().ChangeConnectionPacketType( - link.Handle(), link.pkt_types_mask); + GetInterface().ChangeConnectionPacketType(link.Handle(), link.pkt_types_mask); LOG_DEBUG("Started change connection packet type:0x%04x address:%s", link.pkt_types_mask, ADDRESS_TO_LOGGABLE_CSTR(link.RemoteAddress())); return true; @@ -1662,6 +1579,23 @@ uint16_t BTM_GetMaxPacketSize(const RawAddress& addr) { return (pkt_size); } +/******************************************************************************* + * + * Function BTM_IsRemoteVersionReceived + * + * Returns Returns true if "LE Read remote version info" was already + * received on LE transport for this device. + * + ******************************************************************************/ +bool BTM_IsRemoteVersionReceived(const RawAddress& addr) { + const tACL_CONN* p_acl = internal_.btm_bda_to_acl(addr, BT_TRANSPORT_LE); + if (p_acl == nullptr) { + return false; + } + + return p_acl->remote_version_received; +} + /******************************************************************************* * * Function BTM_ReadRemoteVersion @@ -1671,11 +1605,6 @@ uint16_t BTM_GetMaxPacketSize(const RawAddress& addr) { ******************************************************************************/ bool BTM_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version, uint16_t* manufacturer, uint16_t* lmp_sub_version) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ReadRemoteVersion( - addr, lmp_version, manufacturer, lmp_sub_version); - } - const tACL_CONN* p_acl = internal_.btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR); if (p_acl == nullptr) { p_acl = internal_.btm_bda_to_acl(addr, BT_TRANSPORT_LE); @@ -1708,9 +1637,6 @@ bool BTM_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version, * ******************************************************************************/ uint8_t* BTM_ReadRemoteFeatures(const RawAddress& addr) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ReadRemoteFeatures(addr); - } tACL_CONN* p = internal_.btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR); if (p == NULL) { LOG_WARN("Unable to find active acl"); @@ -1822,7 +1748,7 @@ tBTM_STATUS BTM_ReadTxPower(const RawAddress& remote_bda, #define BTM_READ_RSSI_TYPE_CUR 0x00 #define BTM_READ_RSSI_TYPE_MAX 0X01 - VLOG(2) << __func__ << ": RemBdAddr: " << remote_bda; + VLOG(2) << __func__ << ": RemBdAddr: " << ADDRESS_TO_LOGGABLE_STR(remote_bda); /* If someone already waiting on the version, do not allow another */ if (btm_cb.devcb.p_tx_power_cmpl_cb) return (BTM_BUSY); @@ -2194,14 +2120,6 @@ err_out: * ******************************************************************************/ tBTM_STATUS btm_remove_acl(const RawAddress& bd_addr, tBT_TRANSPORT transport) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - if (transport == BT_TRANSPORT_LE) { - LOG(ERROR) << __func__ << ": Unsupported"; - } - bluetooth::shim::L2CA_DisconnectLink(bd_addr); - return BTM_SUCCESS; - } - tACL_CONN* p_acl = internal_.btm_bda_to_acl(bd_addr, transport); if (p_acl == nullptr) { LOG_WARN("Unable to find active acl"); @@ -2223,27 +2141,11 @@ tBTM_STATUS btm_remove_acl(const RawAddress& bd_addr, tBT_TRANSPORT transport) { return BTM_SUCCESS; } - hci_btsnd_hcic_disconnect(*p_acl, HCI_ERR_PEER_USER, - "stack::acl::btm_acl::btm_remove_acl"); + disconnect_acl(*p_acl, HCI_ERR_PEER_USER, + "stack::acl::btm_acl::btm_remove_acl"); return BTM_SUCCESS; } -/******************************************************************************* - * - * Function BTM_SetTraceLevel - * - * Description This function sets the trace level for BTM. If called with - * a value of 0xFF, it simply returns the current trace level. - * - * Returns The new or current trace level - * - ******************************************************************************/ -uint8_t BTM_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) btm_cb.trace_level = new_level; - - return (btm_cb.trace_level); -} - void btm_cont_rswitch_from_handle(uint16_t hci_handle) { tACL_CONN* p = internal_.acl_get_connection_from_handle(hci_handle); if (p == nullptr) { @@ -2272,78 +2174,6 @@ void btm_cont_rswitch_from_handle(uint16_t hci_handle) { } } -/******************************************************************************* - * - * Function btm_acl_resubmit_page - * - * Description send pending page request - * - ******************************************************************************/ -void btm_acl_resubmit_page(void) { - BT_HDR* p_buf; - uint8_t* pp; - /* If there were other page request schedule can start the next one */ - p_buf = (BT_HDR*)fixed_queue_try_dequeue(btm_cb.page_queue); - if (p_buf != NULL) { - /* skip 3 (2 bytes opcode and 1 byte len) to get to the bd_addr - * for both create_conn and rmt_name */ - pp = (uint8_t*)(p_buf + 1) + p_buf->offset + 3; - - RawAddress bda; - STREAM_TO_BDADDR(bda, pp); - - btm_cb.connecting_bda = bda; - memcpy(btm_cb.connecting_dc, btm_get_dev_class(bda), DEV_CLASS_LEN); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p_buf); - } else { - btm_cb.paging = false; - } -} - -/******************************************************************************* - * - * Function btm_acl_reset_paging - * - * Description set paging to false and free the page queue - called at - * hci_reset - * - ******************************************************************************/ -void btm_acl_reset_paging(void) { - BT_HDR* p; - /* If we sent reset we are definitely not paging any more */ - while ((p = (BT_HDR*)fixed_queue_try_dequeue(btm_cb.page_queue)) != NULL) - osi_free(p); - - btm_cb.paging = false; -} - -/******************************************************************************* - * - * Function btm_acl_paging - * - * Description send a paging command or queue it in btm_cb - * - ******************************************************************************/ -void btm_acl_paging(BT_HDR* p, const RawAddress& bda) { - if (!BTM_IsAclConnectionUp(bda, BT_TRANSPORT_BR_EDR)) { - VLOG(1) << "connecting_bda: " << btm_cb.connecting_bda; - if (btm_cb.paging && bda == btm_cb.connecting_bda) { - fixed_queue_enqueue(btm_cb.page_queue, p); - } else { - btm_cb.connecting_bda = bda; - memcpy(btm_cb.connecting_dc, btm_get_dev_class(bda), DEV_CLASS_LEN); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); - } - - btm_cb.paging = true; - } else /* ACL is already up */ - { - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); - } -} - /******************************************************************************* * * Function btm_acl_notif_conn_collision @@ -2353,7 +2183,7 @@ void btm_acl_paging(BT_HDR* p, const RawAddress& bda) { * ******************************************************************************/ void btm_acl_notif_conn_collision(const RawAddress& bda) { - do_in_main_thread(FROM_HERE, base::Bind(bta_sys_notify_collision, bda)); + do_in_main_thread(FROM_HERE, base::BindOnce(bta_sys_notify_collision, bda)); } bool BTM_BLE_IS_RESOLVE_BDA(const RawAddress& x) { @@ -2363,7 +2193,7 @@ bool BTM_BLE_IS_RESOLVE_BDA(const RawAddress& x) { bool acl_refresh_remote_address(const RawAddress& identity_address, tBLE_ADDR_TYPE identity_address_type, const RawAddress& bda, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type, + tBLE_RAND_ADDR_TYPE rra_type, const RawAddress& rpa) { tACL_CONN* p_acl = internal_.btm_bda_to_acl(bda, BT_TRANSPORT_LE); if (p_acl == nullptr) { @@ -2371,7 +2201,7 @@ bool acl_refresh_remote_address(const RawAddress& identity_address, return false; } - if (rra_type == tBTM_SEC_BLE::BTM_BLE_ADDR_PSEUDO) { + if (rra_type == BTM_BLE_ADDR_PSEUDO) { /* use identity address, resolvable_private_addr is empty */ if (rpa.IsEmpty()) { p_acl->active_remote_addr_type = identity_address_type; @@ -2419,7 +2249,7 @@ bool acl_peer_supports_sniff_subrating(const RawAddress& remote_bda) { } bool acl_peer_supports_ble_connection_subrating(const RawAddress& remote_bda) { - tACL_CONN* p_acl = internal_.btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR); + tACL_CONN* p_acl = internal_.btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE); if (p_acl == nullptr) { LOG_WARN("Unable to find active acl"); return false; @@ -2434,7 +2264,7 @@ bool acl_peer_supports_ble_connection_subrating(const RawAddress& remote_bda) { bool acl_peer_supports_ble_connection_subrating_host( const RawAddress& remote_bda) { - tACL_CONN* p_acl = internal_.btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR); + tACL_CONN* p_acl = internal_.btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE); if (p_acl == nullptr) { LOG_WARN("Unable to find active acl"); return false; @@ -2451,7 +2281,7 @@ bool acl_peer_supports_ble_connection_subrating_host( * * Function BTM_ReadConnectionAddr * - * Description This function is called to get the local device address + * Description This function is called to get the local LE device address * information. * * Returns void @@ -2459,21 +2289,16 @@ bool acl_peer_supports_ble_connection_subrating_host( ******************************************************************************/ void BTM_ReadConnectionAddr(const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - if (bluetooth::shim::is_gd_shim_enabled()) { - return bluetooth::shim::BTM_ReadConnectionAddr(remote_bda, local_conn_addr, - p_addr_type); - } - - if (bluetooth::shim::is_gd_l2cap_enabled()) { - bluetooth::shim::L2CA_ReadConnectionAddr(remote_bda, local_conn_addr, - p_addr_type); - return; - } else { - bluetooth::shim::ACL_ReadConnectionAddress(remote_bda, local_conn_addr, - p_addr_type); + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { + tBTM_SEC_DEV_REC* p_sec_rec = btm_find_dev(remote_bda); + if (p_sec_rec == nullptr) { + LOG_WARN("No matching known device %s in record", + ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); return; } + + bluetooth::shim::ACL_ReadConnectionAddress( + p_sec_rec->ble_hci_handle, local_conn_addr, p_addr_type, ota_address); } /******************************************************************************* @@ -2487,14 +2312,6 @@ void BTM_ReadConnectionAddr(const RawAddress& remote_bda, * ******************************************************************************/ bool BTM_IsBleConnection(uint16_t hci_handle) { - if (bluetooth::shim::is_gd_shim_enabled()) { - ASSERT_LOG(false, "This should not be invoked from code path"); - } - - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_IsLeLink(hci_handle); - } - const tACL_CONN* p_acl = internal_.acl_get_connection_from_handle(hci_handle); if (p_acl == nullptr) return false; return p_acl->is_transport_ble(); @@ -2508,39 +2325,6 @@ const RawAddress acl_address_from_handle(uint16_t handle) { return p_acl->remote_addr; } -bool sco_peer_supports_esco_2m_phy(const RawAddress& remote_bda) { - uint8_t* features = BTM_ReadRemoteFeatures(remote_bda); - if (features == nullptr) { - LOG_WARN( - "Checking remote features but remote feature read is " - "incomplete"); - return false; - } - return HCI_EDR_ESCO_2MPS_SUPPORTED(features); -} - -bool sco_peer_supports_esco_3m_phy(const RawAddress& remote_bda) { - uint8_t* features = BTM_ReadRemoteFeatures(remote_bda); - if (features == nullptr) { - LOG_WARN( - "Checking remote features but remote feature read is " - "incomplete"); - return false; - } - return HCI_EDR_ESCO_3MPS_SUPPORTED(features); -} - -bool sco_peer_supports_esco_ev3(const RawAddress& remote_bda) { - uint8_t* features = BTM_ReadRemoteFeatures(remote_bda); - if (features == nullptr) { - LOG_WARN( - "Checking remote features but remote feature read is " - "incomplete"); - return false; - } - return HCI_ESCO_EV3_SUPPORTED(features); -} - bool acl_is_switch_role_idle(const RawAddress& bd_addr, tBT_TRANSPORT transport) { tACL_CONN* p_acl = internal_.btm_bda_to_acl(bd_addr, transport); @@ -2555,40 +2339,33 @@ bool acl_is_switch_role_idle(const RawAddress& bd_addr, * * Function BTM_ReadRemoteConnectionAddr * - * Description This function is read the remote device address currently used + * Description This function is read the LE remote device address used in + * connection establishment * * Parameters pseudo_addr: pseudo random address available * conn_addr:connection address used * p_addr_type : BD Address type, Public or Random of the address * used + * ota_address: When use if remote used RPA in OTA it will be + *returned. * * Returns bool, true if connection to remote device exists, else false * ******************************************************************************/ bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - if (bluetooth::shim::is_gd_shim_enabled()) { - return bluetooth::shim::BTM_ReadRemoteConnectionAddr(pseudo_addr, conn_addr, - p_addr_type); - } - - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ReadRemoteConnectionAddr( - pseudo_addr, conn_addr, p_addr_type); - } - - bool st = true; - tACL_CONN* p_acl = internal_.btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE); - - if (p_acl == NULL) { - LOG_WARN("Unable to find active acl"); + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address) { + tBTM_SEC_DEV_REC* p_sec_rec = btm_find_dev(pseudo_addr); + if (p_sec_rec == nullptr) { + LOG_WARN("No matching known device %s in record", + ADDRESS_TO_LOGGABLE_CSTR(pseudo_addr)); return false; } - conn_addr = p_acl->active_remote_addr; - *p_addr_type = p_acl->active_remote_addr_type; - return st; + bluetooth::shim::ACL_ReadPeerConnectionAddress( + p_sec_rec->ble_hci_handle, conn_addr, p_addr_type, ota_address); + return true; } uint8_t acl_link_role_from_handle(uint16_t handle) { @@ -2676,6 +2453,7 @@ bool acl_set_peer_le_features_from_handle(uint16_t hci_handle, void on_acl_br_edr_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, bool locally_initiated) { + power_telemetry::GetInstance().LogLinkDetails(handle, bda, true, true); if (delayed_role_change_ != nullptr && delayed_role_change_->bd_addr == bda) { btm_sec_connected(bda, handle, HCI_SUCCESS, enc_mode, delayed_role_change_->new_role); @@ -2683,7 +2461,6 @@ void on_acl_br_edr_connected(const RawAddress& bda, uint16_t handle, btm_sec_connected(bda, handle, HCI_SUCCESS, enc_mode); } delayed_role_change_ = nullptr; - btm_acl_set_paging(false); l2c_link_hci_conn_comp(HCI_SUCCESS, handle, bda); uint16_t link_supervision_timeout = osi_property_get_int32(PROPERTY_LINK_SUPERVISION_TIMEOUT, 8000); @@ -2717,7 +2494,6 @@ void on_acl_br_edr_failed(const RawAddress& bda, tHCI_STATUS status, btm_sec_connected(bda, HCI_INVALID_HANDLE, status, false); } delayed_role_change_ = nullptr; - btm_acl_set_paging(false); l2c_link_hci_conn_comp(status, HCI_INVALID_HANDLE, bda); acl_set_locally_initiated(locally_initiated); @@ -2728,6 +2504,7 @@ void btm_acl_connected(const RawAddress& bda, uint16_t handle, tHCI_STATUS status, uint8_t enc_mode) { switch (status) { case HCI_SUCCESS: + power_telemetry::GetInstance().LogLinkDetails(handle, bda, true, true); return on_acl_br_edr_connected(bda, handle, enc_mode, true /* locally_initiated */); default: @@ -2747,7 +2524,8 @@ void btm_acl_disconnected(tHCI_STATUS status, uint16_t handle, LOG_WARN("Received disconnect with error:%s", hci_error_code_text(status).c_str()); } - + power_telemetry::GetInstance().LogLinkDetails(handle, RawAddress::kEmpty, + false, true); /* There can be a case when we rejected PIN code authentication */ /* otherwise save a new reason */ if (btm_get_acl_disc_reason_code() != HCI_ERR_HOST_REJECT_SECURITY) { @@ -2775,22 +2553,18 @@ void btm_connection_request(const RawAddress& bda, const bluetooth::types::ClassOfDevice& cod) { // Copy Cod information DEV_CLASS dc; - dc[0] = cod.cod[2], dc[1] = cod.cod[1], dc[2] = cod.cod[0]; - btm_sec_conn_req(bda, dc); -} - -void btm_acl_connection_request(const RawAddress& bda, uint8_t* dc) { - btm_sec_conn_req(bda, dc); - l2c_link_hci_conn_req(bda); -} + /* Some device may request a connection before we are done with the HCI_Reset + * sequence */ + if (!controller_get_interface()->get_is_ready()) { + LOG_VERBOSE("Security Manager: connect request when device not ready"); + btsnd_hcic_reject_conn(bda, HCI_ERR_HOST_REJECT_DEVICE); + return; + } -void acl_accept_connection_request(const RawAddress& bd_addr, uint8_t role) { - btsnd_hcic_accept_conn(bd_addr, role); -} + dc[0] = cod.cod[2], dc[1] = cod.cod[1], dc[2] = cod.cod[0]; -void acl_reject_connection_request(const RawAddress& bd_addr, uint8_t reason) { - btsnd_hcic_reject_conn(bd_addr, reason); + btm_sec_conn_req(bda, dc); } void acl_disconnect_from_handle(uint16_t handle, tHCI_STATUS reason, @@ -2798,12 +2572,41 @@ void acl_disconnect_from_handle(uint16_t handle, tHCI_STATUS reason, acl_disconnect_after_role_switch(handle, reason, comment); } +// BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 4, Part E +// 7.1.6 Disconnect command +// Only a subset of reasons are valid and will be accepted +// by the controller +bool is_disconnect_reason_valid(const tHCI_REASON& reason) { + switch (reason) { + case HCI_ERR_AUTH_FAILURE: + case HCI_ERR_PEER_USER: + case HCI_ERR_REMOTE_LOW_RESOURCE: + case HCI_ERR_REMOTE_POWER_OFF: + case HCI_ERR_UNSUPPORTED_REM_FEATURE: + case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED: + case HCI_ERR_UNACCEPT_CONN_INTERVAL: + return true; + default: + break; + } + return false; +} + void acl_disconnect_after_role_switch(uint16_t conn_handle, tHCI_STATUS reason, std::string comment) { + if (!is_disconnect_reason_valid(reason)) { + LOG_WARN( + "Controller will not accept invalid reason parameter:%s" + " instead sending:%s", + hci_error_code_text(reason).c_str(), + hci_error_code_text(HCI_ERR_PEER_USER).c_str()); + reason = HCI_ERR_PEER_USER; + } + tACL_CONN* p_acl = internal_.acl_get_connection_from_handle(conn_handle); if (p_acl == nullptr) { LOG_ERROR("Sending disconnect for unknown acl:%hu PLEASE FIX", conn_handle); - GetLegacyHciInterface().Disconnect(conn_handle, reason); + GetInterface().Disconnect(conn_handle, reason); return; } @@ -2818,7 +2621,7 @@ void acl_disconnect_after_role_switch(uint16_t conn_handle, tHCI_STATUS reason, } else { LOG_DEBUG("Sending acl disconnect reason:%s [%hu]", hci_error_code_text(reason).c_str(), reason); - hci_btsnd_hcic_disconnect(*p_acl, reason, comment); + disconnect_acl(*p_acl, reason, comment); } } @@ -2830,6 +2633,7 @@ void acl_send_data_packet_br_edr(const RawAddress& bd_addr, BT_HDR* p_buf) { osi_free(p_buf); return; } + power_telemetry::GetInstance().LogTxAclPktData(p_buf->len); return bluetooth::shim::ACL_WriteData(p_acl->hci_handle, p_buf); } @@ -2841,6 +2645,7 @@ void acl_send_data_packet_ble(const RawAddress& bd_addr, BT_HDR* p_buf) { osi_free(p_buf); return; } + power_telemetry::GetInstance().LogTxAclPktData(p_buf->len); return bluetooth::shim::ACL_WriteData(p_acl->hci_handle, p_buf); } @@ -2865,11 +2670,11 @@ void acl_write_automatic_flush_timeout(const RawAddress& bd_addr, bool acl_create_le_connection_with_id(uint8_t id, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) { tBLE_BD_ADDR address_with_type{ - .bda = bd_addr, .type = addr_type, + .bda = bd_addr, }; - gatt_find_in_device_record(bd_addr, &address_with_type); + find_in_device_record(bd_addr, &address_with_type); LOG_DEBUG("Creating le direct connection to:%s type:%s (initial type: %s)", ADDRESS_TO_LOGGABLE_CSTR(address_with_type), @@ -2884,15 +2689,6 @@ bool acl_create_le_connection_with_id(uint8_t id, const RawAddress& bd_addr, return false; } - // argument list - auto argument_list = std::vector>(); - - bluetooth::shim::LogMetricBluetoothLEConnectionMetricEvent( - bd_addr, android::bluetooth::le::LeConnectionOriginType::ORIGIN_NATIVE, - android::bluetooth::le::LeConnectionType::CONNECTION_TYPE_LE_ACL, - android::bluetooth::le::LeConnectionState::STATE_LE_ACL_START, - argument_list); - if (bluetooth::common::init_flags:: use_unified_connection_manager_is_enabled()) { bluetooth::connection::GetConnectionManager().start_direct_connection( @@ -2922,6 +2718,7 @@ void acl_rcv_acl_data(BT_HDR* p_msg) { STREAM_TO_UINT16(acl_header.handle, p); acl_header.handle = HCID_GET_HANDLE(acl_header.handle); + power_telemetry::GetInstance().LogRxAclPktData(p_msg->len); STREAM_TO_UINT16(acl_header.hci_len, p); if (acl_header.hci_len < L2CAP_PKT_OVERHEAD || acl_header.hci_len != p_msg->len - sizeof(acl_header)) { @@ -2933,10 +2730,6 @@ void acl_rcv_acl_data(BT_HDR* p_msg) { l2c_rcv_acl_data(p_msg); } -void acl_link_segments_xmitted(BT_HDR* p_msg) { - l2c_link_segments_xmitted(p_msg); -} - void acl_packets_completed(uint16_t handle, uint16_t credits) { l2c_packets_completed(handle, credits); bluetooth::hci::IsoManager::GetInstance()->HandleGdNumComplDataPkts(handle, @@ -3018,39 +2811,6 @@ bool ACL_SupportTransparentSynchronousData(const RawAddress& bd_addr) { return HCI_LMP_TRANSPNT_SUPPORTED(p_acl->peer_lmp_feature_pages[0]); } -/** - * Confusingly, immutable device features are stored in the - * ephemeral connection data structure while connection security - * is stored in the device record. - * - * This HACK allows legacy security protocols to work as intended under - * those conditions. - */ -void HACK_acl_check_sm4(tBTM_SEC_DEV_REC& record) { - // Return if we already know this info - if ((record.sm4 & BTM_SM4_TRUE) != BTM_SM4_UNKNOWN) return; - - tACL_CONN* p_acl = - internal_.btm_bda_to_acl(record.RemoteAddress(), BT_TRANSPORT_BR_EDR); - if (p_acl == nullptr) { - LOG_WARN("Unable to find active acl for authentication device:%s", - ADDRESS_TO_LOGGABLE_CSTR(record.RemoteAddress())); - return; - } - - // If we have not received the SSP feature record - // we have to wait - if (!p_acl->peer_lmp_feature_valid[1]) { - LOG_WARN( - "Authentication started without extended feature page 1 request " - "response"); - return; - } - record.sm4 = (HCI_SSP_HOST_SUPPORTED(p_acl->peer_lmp_feature_pages[1])) - ? BTM_SM4_TRUE - : BTM_SM4_KNOWN; -} - tACL_CONN* btm_acl_for_bda(const RawAddress& bd_addr, tBT_TRANSPORT transport) { tACL_CONN* p_acl = internal_.btm_bda_to_acl(bd_addr, transport); if (p_acl == nullptr) { @@ -3059,3 +2819,23 @@ tACL_CONN* btm_acl_for_bda(const RawAddress& bd_addr, tBT_TRANSPORT transport) { } return p_acl; } + +void find_in_device_record(const RawAddress& bd_addr, + tBLE_BD_ADDR* address_with_type) { + const tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec == nullptr) { + return; + } + + if (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) { + if (p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { + *address_with_type = {.type = p_dev_rec->ble.AddressType(), + .bda = bd_addr}; + return; + } + *address_with_type = p_dev_rec->ble.identity_address_with_type; + return; + } + *address_with_type = {.type = BLE_ADDR_PUBLIC, .bda = bd_addr}; + return; +} diff --git a/system/stack/acl/btm_ble_connection_establishment.cc b/system/stack/acl/btm_ble_connection_establishment.cc index 0f8d8162dff461c5ef421ec63e4894419dd3b13a..b339e92c573f05abd89373e5fdbc768b36f7e84b 100644 --- a/system/stack/acl/btm_ble_connection_establishment.cc +++ b/system/stack/acl/btm_ble_connection_establishment.cc @@ -16,33 +16,16 @@ * ******************************************************************************/ +#include #include #include -#include - -#include "common/metrics.h" -#include "device/include/controller.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" #include "stack/btm/btm_ble_int.h" -#include "stack/gatt/connection_manager.h" -#include "stack/include/acl_api.h" -#include "stack/include/ble_acl_interface.h" +#include "stack/btm/btm_int_types.h" #include "stack/include/ble_hci_link_interface.h" -#include "stack/include/l2cap_hci_link_interface.h" -#include "stack/include/stack_metrics_logging.h" -#include "types/raw_address.h" - -#include extern tBTM_CB btm_cb; -void btm_ble_advertiser_notify_terminated_legacy(uint8_t status, - uint16_t connection_handle); - -bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, - const RawAddress& new_pseudo_addr); /** LE connection complete. */ void btm_ble_create_ll_conn_complete(tHCI_STATUS status) { if (status == HCI_SUCCESS) return; @@ -60,41 +43,3 @@ void btm_ble_create_ll_conn_complete(tHCI_STATUS status) { btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status); } } - -bool maybe_resolve_address(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { - bool is_in_security_db = false; - tBLE_ADDR_TYPE peer_addr_type = *bda_type; - bool addr_is_rpa = - (peer_addr_type == BLE_ADDR_RANDOM && BTM_BLE_IS_RESOLVE_BDA(*bda)); - - /* We must translate whatever address we received into the "pseudo" address. - * i.e. if we bonded with device that was using RPA for first connection, - * "pseudo" address is equal to this RPA. If it later decides to use Public - * address, or Random Static Address, we convert it into the "pseudo" - * address here. */ - if (!addr_is_rpa || peer_addr_type & BLE_ADDR_TYPE_ID_BIT) { - is_in_security_db = btm_identity_addr_to_random_pseudo(bda, bda_type, true); - } - - /* possiblly receive connection complete with resolvable random while - the device has been paired */ - if (!is_in_security_db && addr_is_rpa) { - tBTM_SEC_DEV_REC* match_rec = btm_ble_resolve_random_addr(*bda); - if (match_rec) { - LOG(INFO) << __func__ << ": matched and resolved random address"; - is_in_security_db = true; - match_rec->ble.active_addr_type = tBTM_SEC_BLE::BTM_BLE_ADDR_RRA; - match_rec->ble.cur_rand_addr = *bda; - if (!btm_ble_init_pseudo_addr(match_rec, *bda)) { - /* assign the original address to be the current report address */ - *bda = match_rec->ble.pseudo_addr; - *bda_type = match_rec->ble.AddressType(); - } else { - *bda = match_rec->bd_addr; - } - } else { - LOG(INFO) << __func__ << ": unable to match and resolve random address"; - } - } - return is_in_security_db; -} diff --git a/system/stack/acl/btm_pm.cc b/system/stack/acl/btm_pm.cc index 706d441b18ca57507f0a394de0ded86e40375e2e..d80d73cbb33131512a81b26a9e68f5b2f2a544ab 100644 --- a/system/stack/acl/btm_pm.cc +++ b/system/stack/acl/btm_pm.cc @@ -35,16 +35,16 @@ #include #include -#include "bt_target.h" #include "device/include/controller.h" #include "device/include/interop.h" +#include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/osi.h" // UNUSED_ATTR +#include "osi/include/stack_power_telemetry.h" #include "stack/btm/btm_int_types.h" -#include "stack/include/btm_api.h" -#include "stack/include/btm_api_types.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_log_history.h" #include "stack/include/btm_status.h" #include "types/raw_address.h" @@ -94,6 +94,12 @@ const uint8_t static void send_sniff_subrating(uint16_t handle, const RawAddress& addr, uint16_t max_lat, uint16_t min_rmt_to, uint16_t min_loc_to) { + uint16_t new_max_lat = 0; + if (interop_match_addr_get_max_lat(INTEROP_UPDATE_HID_SSR_MAX_LAT, &addr, + &new_max_lat)) { + max_lat = new_max_lat; + } + btsnd_hcic_sniff_sub_rate(handle, max_lat, min_rmt_to, min_loc_to); BTM_LogHistory(kBtmLogTag, addr, "Sniff subrating", base::StringPrintf( @@ -122,12 +128,6 @@ static tBTM_STATUS btm_pm_snd_md_req(uint16_t handle, uint8_t pm_id, ******************************************************************************/ tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id, tBTM_PM_STATUS_CBACK* p_cb) { - if (bluetooth::shim::is_gd_link_policy_enabled()) { - ASSERT(p_pm_id != nullptr); - ASSERT(p_cb != nullptr); - return BTM_NO_RESOURCES; - } - /* de-register */ if (mask & BTM_PM_DEREG) { if (*p_pm_id >= BTM_MAX_PM_RECORDS) return BTM_ILLEGAL_VALUE; @@ -727,6 +727,10 @@ void btm_pm_proc_mode_change(tHCI_STATUS hci_status, uint16_t hci_handle, l2c_OnHciModeChangeSendPendingPackets(p_cb->bda_); } + (mode != BTM_PM_ST_ACTIVE) + ? power_telemetry::GetInstance().LogSniffStarted(hci_handle, p_cb->bda_) + : power_telemetry::GetInstance().LogSniffStopped(hci_handle, p_cb->bda_); + /* set req_mode HOLD mode->ACTIVE */ if ((mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode.mode == BTM_PM_MD_HOLD)) p_cb->req_mode.mode = BTM_PM_MD_ACTIVE; @@ -838,7 +842,7 @@ static bool btm_pm_device_in_active_or_sniff_mode(void) { /* Check BLE states */ if (!btm_cb.ble_ctr_cb.is_connection_state_idle()) { - BTM_TRACE_DEBUG("%s - BLE state is not idle", __func__); + LOG_VERBOSE("%s - BLE state is not idle", __func__); return true; } @@ -859,15 +863,12 @@ static bool btm_pm_device_in_scan_state(void) { /* Scan state-paging, inquiry, and trying to connect */ /* Check for paging */ - if (btm_cb.is_paging || !fixed_queue_is_empty(btm_cb.page_queue)) { - BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- paging"); - return true; - } + // TODO: Get this information from connection manager? /* Check for inquiry */ if ((btm_cb.btm_inq_vars.inq_active & (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)) != 0) { - BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- Inq active"); + LOG_VERBOSE("btm_pm_device_in_scan_state- Inq active"); return true; } diff --git a/system/stack/acl/peer_packet_types.h b/system/stack/acl/peer_packet_types.h index 952cf63dda5b523dcb764c80a6fe53f3b3d1d1f7..78aa94668665134172aabaffafb58a76bf133bad 100644 --- a/system/stack/acl/peer_packet_types.h +++ b/system/stack/acl/peer_packet_types.h @@ -16,7 +16,6 @@ #pragma once -#include "stack/include/bt_types.h" #include "stack/include/hcidefs.h" #define BD_FEATURES_LEN 8 diff --git a/system/stack/arbiter/acl_arbiter.cc b/system/stack/arbiter/acl_arbiter.cc index d1a03f27bc0f065d54fca08c52c9793e61348a32..f1321c127d8b61ecb871423cf6421855c32d7c61 100644 --- a/system/stack/arbiter/acl_arbiter.cc +++ b/system/stack/arbiter/acl_arbiter.cc @@ -19,14 +19,12 @@ #include #include -#include -#include "common/init_flags.h" #include "os/log.h" #include "osi/include/allocator.h" #include "stack/gatt/gatt_int.h" -#include "stack/include/btu.h" // do_in_main_thread #include "stack/include/l2c_api.h" +#include "stack/include/main_thread.h" namespace bluetooth { namespace shim { @@ -157,9 +155,9 @@ void StoreCallbacksFromRust( void SendPacketToPeer(uint8_t tcb_idx, ::rust::Vec buffer) { do_in_main_thread(FROM_HERE, - base::Bind(&RustGattAclArbiter::SendPacketToPeer, - base::Unretained(&RustGattAclArbiter::Get()), - tcb_idx, std::move(buffer))); + base::BindOnce(&RustGattAclArbiter::SendPacketToPeer, + base::Unretained(&RustGattAclArbiter::Get()), + tcb_idx, std::move(buffer))); } AclArbiter& GetArbiter() { diff --git a/system/stack/avct/avct_api.cc b/system/stack/avct/avct_api.cc index 1a8d6c6637afdfc157aadeddd2f0caabec90d86c..8be7cc88dc25e06b232097f3b378eaf7ff7a51f8 100644 --- a/system/stack/avct/avct_api.cc +++ b/system/stack/avct/avct_api.cc @@ -27,20 +27,17 @@ #include #include "avct_int.h" -#include "bt_target.h" -#include "bta/include/bta_api.h" -#include "btm_api.h" +#include "bta/include/bta_sec_api.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "l2cdefs.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/osi.h" -#include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" /* Control block for AVCT */ tAVCT_CB avct_cb; -uint8_t avct_trace_level = AVCT_INITIAL_TRACE_LEVEL; /******************************************************************************* * @@ -57,7 +54,7 @@ uint8_t avct_trace_level = AVCT_INITIAL_TRACE_LEVEL; * ******************************************************************************/ void AVCT_Register() { - AVCT_TRACE_API("AVCT_Register"); + LOG_VERBOSE("AVCT_Register"); /* initialize AVCTP data structures */ memset(&avct_cb, 0, sizeof(tAVCT_CB)); @@ -73,8 +70,6 @@ void AVCT_Register() { L2CA_Register2(AVCT_BR_PSM, avct_l2c_br_appl, true /*enable_snoop*/, &ertm_info, kAvrcBrMtu, AVCT_MIN_BROWSE_MTU, BTA_SEC_AUTHENTICATE); - - avct_cb.trace_level = avct_trace_level; } /******************************************************************************* @@ -92,7 +87,7 @@ void AVCT_Register() { * ******************************************************************************/ void AVCT_Deregister(void) { - AVCT_TRACE_API("AVCT_Deregister"); + LOG_VERBOSE("AVCT_Deregister"); /* deregister PSM with L2CAP */ L2CA_Deregister(AVCT_PSM); @@ -121,7 +116,7 @@ uint16_t AVCT_CreateConn(uint8_t* p_handle, tAVCT_CC* p_cc, tAVCT_CCB* p_ccb; tAVCT_LCB* p_lcb; - AVCT_TRACE_API("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control); + LOG_VERBOSE("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control); /* Allocate ccb; if no ccbs, return failure */ p_ccb = avct_ccb_alloc(p_cc); @@ -152,7 +147,7 @@ uint16_t AVCT_CreateConn(uint8_t* p_handle, tAVCT_CC* p_cc, if (result == AVCT_SUCCESS) { /* bind lcb to ccb */ p_ccb->p_lcb = p_lcb; - AVCT_TRACE_DEBUG("ch_state: %d", p_lcb->ch_state); + LOG_VERBOSE("ch_state: %d", p_lcb->ch_state); tAVCT_LCB_EVT avct_lcb_evt; avct_lcb_evt.p_ccb = p_ccb; avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, &avct_lcb_evt); @@ -179,7 +174,7 @@ uint16_t AVCT_RemoveConn(uint8_t handle) { uint16_t result = AVCT_SUCCESS; tAVCT_CCB* p_ccb; - AVCT_TRACE_API("AVCT_RemoveConn"); + LOG_VERBOSE("AVCT_RemoveConn"); /* map handle to ccb */ p_ccb = avct_ccb_by_idx(handle); @@ -222,7 +217,7 @@ uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role) { tAVCT_BCB* p_bcb; int index; - AVCT_TRACE_API("AVCT_CreateBrowse: %d", role); + LOG_VERBOSE("AVCT_CreateBrowse: %d", role); /* map handle to ccb */ p_ccb = avct_ccb_by_idx(handle); @@ -256,7 +251,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; - AVCT_TRACE_DEBUG("ch_state: %d", p_bcb->ch_state); + LOG_VERBOSE("ch_state: %d", 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); @@ -283,7 +278,7 @@ uint16_t AVCT_RemoveBrowse(uint8_t handle) { uint16_t result = AVCT_SUCCESS; tAVCT_CCB* p_ccb; - AVCT_TRACE_API("AVCT_RemoveBrowse"); + LOG_VERBOSE("AVCT_RemoveBrowse"); /* map handle to ccb */ p_ccb = avct_ccb_by_idx(handle); @@ -374,14 +369,14 @@ uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR* p_msg) { tAVCT_CCB* p_ccb; tAVCT_UL_MSG ul_msg; - AVCT_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* verify p_msg parameter */ if (p_msg == NULL) { return AVCT_NO_RESOURCES; } - AVCT_TRACE_API("%s len: %d layer_specific: %d", __func__, p_msg->len, - p_msg->layer_specific); + LOG_VERBOSE("%s len: %d layer_specific: %d", __func__, p_msg->len, + p_msg->layer_specific); /* map handle to ccb */ p_ccb = avct_ccb_by_idx(handle); @@ -423,31 +418,3 @@ uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR* p_msg) { } return result; } - -/****************************************************************************** - * - * Function AVCT_SetTraceLevel - * - * Description Sets the trace level for AVCT. If 0xff is passed, the - * current trace level is returned. - * - * Input Parameters: - * new_level: The level to set the AVCT tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new trace level or current trace level if - * the input parameter is 0xff. - * - *****************************************************************************/ -uint8_t AVCT_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) { - avct_cb.trace_level = avct_trace_level = new_level; - } - return avct_trace_level; -} diff --git a/system/stack/avct/avct_bcb_act.cc b/system/stack/avct/avct_bcb_act.cc index 2503d81562df5708d55fd5da75d8e8471f430dd9..6a27097e9c675bdd61d4786de57081d94f688fa9 100644 --- a/system/stack/avct/avct_bcb_act.cc +++ b/system/stack/avct/avct_bcb_act.cc @@ -27,18 +27,19 @@ #define LOG_TAG "bluetooth" +#include #include #include "avct_api.h" #include "avct_int.h" -#include "bt_target.h" -#include "bta/include/bta_api.h" -#include "btm_api.h" +#include "bta/include/bta_sec_api.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" -#include "stack/btm/btm_sec.h" +#include "stack/avct/avct_defs.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" /* action function list */ const tAVCT_BCB_ACTION avct_bcb_action[] = { @@ -87,8 +88,7 @@ static BT_HDR* avct_bcb_msg_asmbl(UNUSED_ATTR 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); - AVCT_TRACE_WARNING("Pkt type=%d - fragmentation not allowed. drop it", - pkt_type); + LOG_WARN("Pkt type=%d - fragmentation not allowed. drop it", pkt_type); } return p_buf; } @@ -422,8 +422,8 @@ void avct_bcb_discard_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { (p_data->ul_msg.cr << 8) + p_data->ul_msg.label; /* the channel is closed, opening or closing - open it again */ - AVCT_TRACE_DEBUG("ch_state: %d, allocated:%d->%d", p_bcb->ch_state, - p_bcb->allocated, p_data->ul_msg.p_ccb->p_lcb->allocated); + LOG_VERBOSE("ch_state: %d, allocated:%d->%d", 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); @@ -452,8 +452,8 @@ 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)) { - AVCT_TRACE_ERROR("%s msg len (%d) exceeds peer mtu(%d-%d)!!", __func__, - curr_msg_len, p_bcb->peer_mtu, AVCT_HDR_LEN_SINGLE); + LOG_ERROR("%s msg len (%d) exceeds peer mtu(%d-%d)!!", __func__, + curr_msg_len, p_bcb->peer_mtu, AVCT_HDR_LEN_SINGLE); osi_free_and_reset((void**)&p_data->ul_msg.p_buf); return; } @@ -510,7 +510,7 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb); if ((p_data == NULL) || (p_data->p_buf == NULL)) { - AVCT_TRACE_WARNING("%s p_data is NULL, returning!", __func__); + LOG_WARN("%s p_data is NULL, returning!", __func__); return; } @@ -527,8 +527,8 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { } if (p_data->p_buf->len < AVCT_HDR_LEN_SINGLE) { - AVCT_TRACE_WARNING("Invalid AVCTP packet length %d: must be at least %d", - p_data->p_buf->len, AVCT_HDR_LEN_SINGLE); + LOG_WARN("Invalid AVCTP packet length %d: must be at least %d", + p_data->p_buf->len, AVCT_HDR_LEN_SINGLE); osi_free_and_reset((void**)&p_data->p_buf); return; } @@ -537,28 +537,36 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { /* parse header byte */ AVCT_PARSE_HDR(p, label, type, cr_ipid); + /* parse PID */ + BE_STREAM_TO_UINT16(pid, p); /* check for invalid cr_ipid */ if (cr_ipid == AVCT_CR_IPID_INVALID) { - AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid); + LOG_WARN("Invalid cr_ipid %d", cr_ipid); osi_free_and_reset((void**)&p_data->p_buf); return; } - /* parse and lookup PID */ - BE_STREAM_TO_UINT16(pid, p); - p_ccb = avct_lcb_has_pid(p_lcb, pid); - if (p_ccb) { - /* PID found; send msg up, adjust bt hdr and call msg callback */ - p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE; - p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE; - (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, - p_data->p_buf); - return; + bool bind = false; + if (GET_SYSPROP(A2dp, src_sink_coexist, false)) { + bind = avct_msg_ind_for_src_sink_coexist(p_lcb, p_data, label, cr_ipid); + osi_free_and_reset((void**)&p_data->p_buf); + if (bind) return; + } else { + /* lookup PID */ + p_ccb = avct_lcb_has_pid(p_lcb, pid); + if (p_ccb) { + /* PID found; send msg up, adjust bt hdr and call msg callback */ + p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE; + p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE; + (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, + p_data->p_buf); + return; + } } /* PID not found; drop message */ - AVCT_TRACE_WARNING("No ccb for PID=%x", pid); + LOG_WARN("No ccb for PID=%x", pid); osi_free_and_reset((void**)&p_data->p_buf); /* if command send reject */ @@ -587,13 +595,13 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { void avct_bcb_dealloc(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) { tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; - AVCT_TRACE_DEBUG("%s %d", __func__, p_bcb->allocated); + LOG_VERBOSE("%s %d", __func__, 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; - AVCT_TRACE_DEBUG("%s used by ccb: %d", __func__, idx); + LOG_VERBOSE("%s used by ccb: %d", __func__, idx); break; } } @@ -684,12 +692,13 @@ tAVCT_BCB* avct_bcb_by_lcid(uint16_t lcid) { int idx; for (idx = 0; idx < AVCT_NUM_LINKS; idx++, p_bcb++) { - if (p_bcb->allocated && (p_bcb->ch_lcid == lcid)) { + if (p_bcb->allocated && + ((p_bcb->ch_lcid == lcid) || (p_bcb->conflict_lcid == lcid))) { return p_bcb; } } /* out of lcbs */ - AVCT_TRACE_WARNING("No bcb for lcid %x", lcid); + LOG_WARN("No bcb for lcid %x", lcid); return NULL; } diff --git a/system/stack/avct/avct_ccb.cc b/system/stack/avct/avct_ccb.cc index 09871cba73ed563caff4ac27d9878c6dfd6e5059..7f916c694f89ab390041080ae5ee51b432017521 100644 --- a/system/stack/avct/avct_ccb.cc +++ b/system/stack/avct/avct_ccb.cc @@ -23,11 +23,14 @@ * ******************************************************************************/ +#define LOG_TAG "avctp" + #include #include "avct_api.h" #include "avct_int.h" -#include "bt_target.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "types/raw_address.h" /******************************************************************************* @@ -48,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)); - AVCT_TRACE_DEBUG("avct_ccb_alloc %d", i); + LOG_VERBOSE("avct_ccb_alloc %d", i); break; } } @@ -56,7 +59,7 @@ tAVCT_CCB* avct_ccb_alloc(tAVCT_CC* p_cc) { if (i == AVCT_NUM_CONN) { /* out of ccbs */ p_ccb = NULL; - AVCT_TRACE_WARNING("Out of ccbs"); + LOG_WARN("Out of ccbs"); } return p_ccb; } @@ -76,7 +79,7 @@ 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; - AVCT_TRACE_DEBUG("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb)); + LOG_VERBOSE("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb)); if (p_ccb->p_bcb == NULL) { memset(p_ccb, 0, sizeof(tAVCT_CCB)); @@ -128,11 +131,11 @@ tAVCT_CCB* avct_ccb_by_idx(uint8_t idx) { /* verify ccb is allocated */ if (!p_ccb->allocated) { p_ccb = NULL; - AVCT_TRACE_WARNING("ccb %d not allocated", idx); + LOG_WARN("ccb %d not allocated", idx); } } else { p_ccb = NULL; - AVCT_TRACE_WARNING("No ccb for idx %d", idx); + LOG_WARN("No ccb for idx %d", idx); } return p_ccb; } diff --git a/system/stack/avct/avct_int.h b/system/stack/avct/avct_int.h index 3139dbce3ad1bfdd42f4a13aec82a69b069269ab..50a53f2ced2362a5e1e6ef21649fd87159b08d24 100644 --- a/system/stack/avct/avct_int.h +++ b/system/stack/avct/avct_int.h @@ -25,7 +25,7 @@ #define AVCT_INT_H #include "avct_api.h" -#include "avct_defs.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "osi/include/fixed_queue.h" #include "stack/include/bt_hdr.h" @@ -92,9 +92,10 @@ typedef struct { uint8_t allocated; /* 0, not allocated. index+1, otherwise. */ uint8_t state; /* The state machine state */ uint8_t ch_state; /* L2CAP channel state */ - BT_HDR* p_tx_msg; /* Message to be sent - in case the browsing channel is not - open when MsgReg is called */ - uint8_t ch_close; /* CCB index+1, if CCB initiated channel close */ + uint16_t conflict_lcid; /* L2CAP channel LCID */ + BT_HDR* p_tx_msg; /* Message to be sent - in case the browsing channel is not + open when MsgReg is called */ + uint8_t ch_close; /* CCB index+1, if CCB initiated channel close */ RawAddress peer_addr; /* BD address of peer */ } tAVCT_BCB; @@ -132,7 +133,6 @@ typedef struct { tAVCT_LCB lcb[AVCT_NUM_LINKS]; /* link control blocks */ tAVCT_BCB bcb[AVCT_NUM_LINKS]; /* browse control blocks */ tAVCT_CCB ccb[AVCT_NUM_CONN]; /* connection control blocks */ - uint8_t trace_level; /* trace level */ } tAVCT_CB; /***************************************************************************** @@ -201,6 +201,10 @@ void avct_ccb_dealloc(tAVCT_CCB* p_ccb, uint8_t event, uint16_t result, uint8_t avct_ccb_to_idx(tAVCT_CCB* p_ccb); 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); + /***************************************************************************** * global data ****************************************************************************/ diff --git a/system/stack/avct/avct_l2c.cc b/system/stack/avct/avct_l2c.cc index 7634a65653739bfad64c3019d128e63168fd7454..b8b65fe93461b9dca64c455d6188f8ca0a2b50dd 100644 --- a/system/stack/avct/avct_l2c.cc +++ b/system/stack/avct/avct_l2c.cc @@ -21,19 +21,22 @@ * This AVCTP module interfaces to L2CAP * ******************************************************************************/ +#define LOG_TAG "avctp" + +#include +#include #include "avct_api.h" #include "avct_int.h" -#include "bt_target.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "l2cdefs.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" -#include - /* callback function declarations */ void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16_t psm, uint8_t id); @@ -81,7 +84,7 @@ static bool avct_l2c_is_passive(tAVCT_LCB* p_lcb) { for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { - AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control); + LOG_VERBOSE("avct_l2c_is_ct control:x%x", p_ccb->cc.control); if (p_ccb->cc.control & AVCT_PASSIVE) { is_passive = true; break; @@ -125,14 +128,14 @@ void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, /* TG role only - accept the connection from CT. move the channel ID to * the conflict list */ p_lcb->conflict_lcid = p_lcb->ch_lcid; - AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x", - p_lcb->conflict_lcid); + LOG_VERBOSE("avct_l2c_connect_ind_cback conflict_lcid:0x%x", + p_lcb->conflict_lcid); } } if (p_lcb) { - AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d", - lcid, result, p_lcb->ch_state); + LOG_VERBOSE("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d", lcid, + result, p_lcb->ch_state); } /* If we reject the connection, send DisconnectReq */ @@ -142,6 +145,18 @@ void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, /* if result ok, proceed with connection */ if (result == L2CAP_CONN_OK) { + if (GET_SYSPROP(A2dp, src_sink_coexist, false)) { + 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)) { + p_ccb->p_lcb = p_lcb; + LOG_VERBOSE( + "ACP bind %d ccb to lcb, alloc %d, lcb %p, role %d, pid 0x%x", i, + p_ccb->allocated, p_ccb->p_lcb, p_ccb->cc.role, p_ccb->cc.pid); + } + } + } /* store LCID */ p_lcb->ch_lcid = lcid; @@ -149,15 +164,15 @@ void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, p_lcb->ch_state = AVCT_CH_CFG; } - if (p_lcb) AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state); + if (p_lcb) LOG_VERBOSE("ch_state cni: %d ", p_lcb->ch_state); } static void avct_on_l2cap_error(uint16_t lcid, uint16_t result) { tAVCT_LCB* p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb == nullptr) return; if (p_lcb->ch_state == AVCT_CH_CONN) { - AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", - p_lcb->conflict_lcid); + LOG_VERBOSE("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", + p_lcb->conflict_lcid); if (p_lcb->conflict_lcid == lcid) { p_lcb->conflict_lcid = 0; } else { @@ -166,8 +181,8 @@ static void avct_on_l2cap_error(uint16_t lcid, uint16_t result) { avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt); } } else if (p_lcb->ch_state == AVCT_CH_CFG) { - AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", - p_lcb->ch_state); + LOG_VERBOSE("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", + p_lcb->ch_state); /* store result value */ p_lcb->ch_result = result; @@ -192,7 +207,7 @@ void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) { /* look up lcb for this channel */ p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb != NULL) { - AVCT_TRACE_DEBUG( + LOG_VERBOSE( "avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, " "conflict_lcid:0x%x", lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid); @@ -209,9 +224,8 @@ void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) { } } else if (p_lcb->conflict_lcid == lcid) { /* we must be in AVCT_CH_CFG state for the ch_lcid channel */ - AVCT_TRACE_DEBUG( - "avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", - p_lcb->ch_state, p_lcb->conflict_lcid); + LOG_VERBOSE("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", + p_lcb->ch_state, p_lcb->conflict_lcid); if (result == L2CAP_CONN_OK) { /* just in case the peer also accepts our connection - Send L2CAP * disconnect req */ @@ -219,7 +233,7 @@ void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) { } p_lcb->conflict_lcid = 0; } - AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state); + LOG_VERBOSE("ch_state cnc: %d ", p_lcb->ch_state); } } @@ -242,14 +256,14 @@ void avct_l2c_config_cfm_cback(uint16_t lcid, uint16_t initiator, /* look up lcb for this channel */ p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb != NULL) { - AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d,", lcid, - p_lcb->ch_state); + LOG_VERBOSE("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d,", 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); } - AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state); + LOG_VERBOSE("ch_state cfc: %d ", p_lcb->ch_state); } } @@ -269,8 +283,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) { - AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, - p_lcb->ch_state); + LOG_VERBOSE("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, + p_lcb->ch_state); /* store the mtu in tbl */ if (p_cfg->mtu_present) { p_lcb->peer_mtu = p_cfg->mtu; @@ -297,12 +311,12 @@ void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) { /* look up lcb for this channel */ p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb != NULL) { - AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, - p_lcb->ch_state); + LOG_VERBOSE("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, + p_lcb->ch_state); tAVCT_LCB_EVT avct_lcb_evt; avct_lcb_evt.result = result; avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt); - AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state); + LOG_VERBOSE("ch_state di: %d ", p_lcb->ch_state); } } @@ -315,9 +329,8 @@ void avct_l2c_disconnect(uint16_t lcid, uint16_t result) { /* look up lcb for this channel */ p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb != NULL) { - AVCT_TRACE_DEBUG( - "avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d", lcid, - p_lcb->ch_state, result); + LOG_VERBOSE("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d", + lcid, p_lcb->ch_state, result); /* result value may be previously stored */ res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result; p_lcb->ch_result = 0; @@ -325,7 +338,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); - AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state); + LOG_VERBOSE("ch_state dc: %d ", p_lcb->ch_state); } } @@ -342,7 +355,7 @@ void avct_l2c_disconnect(uint16_t lcid, uint16_t result) { void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) { tAVCT_LCB* p_lcb; - AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid); + LOG_VERBOSE("avct_l2c_congestion_ind_cback: 0x%x", lcid); /* look up lcb for this channel */ p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb != NULL) { @@ -365,14 +378,14 @@ 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; - AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid); + LOG_VERBOSE("avct_l2c_data_ind_cback: 0x%x", lcid); /* look up lcb for this channel */ 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 */ { - AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer"); + 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 57bc501bfdf54faf36e3151e9ac2b39ca6a112c7..70b4b5e0f294a2136e6732b97de40ca491338942 100644 --- a/system/stack/avct/avct_l2c_br.cc +++ b/system/stack/avct/avct_l2c_br.cc @@ -24,18 +24,22 @@ * *****************************************************************************/ +#define LOG_TAG "avctp" + +#include + #include "avct_api.h" #include "avct_int.h" #include "bt_target.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "l2cdefs.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" -#include - /* callback function declarations */ void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16_t psm, uint8_t id); @@ -64,6 +68,36 @@ const tL2CAP_APPL_INFO avct_l2c_br_appl = {avct_l2c_br_connect_ind_cback, NULL, NULL}; +/******************************************************************************* + * + * Function avct_l2c_br_is_passive + * + * Description check is the CCB associated with the given BCB was created + * as passive + * + * Returns true, if the given CCB is created as AVCT_PASSIVE + * + ******************************************************************************/ +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); + int i; + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { + LOG_VERBOSE("Is bcb associated ccb control passive :0x%x", + p_ccb->cc.control); + if (p_ccb->cc.control & AVCT_PASSIVE) { + is_passive = true; + break; + } + } + } + return is_passive; +} + /******************************************************************************* * * Function avct_l2c_br_connect_ind_cback @@ -94,6 +128,16 @@ void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, p_bcb->allocated = p_lcb->allocated; /* copy the index from lcb */ result = L2CAP_CONN_OK; + } else { + if (!avct_l2c_br_is_passive(p_bcb) || (p_bcb->ch_state == AVCT_CH_OPEN)) { + /* this BCB included CT role - reject */ + result = L2CAP_CONN_NO_RESOURCES; + } else { + /* add channel ID to conflict ID */ + p_bcb->conflict_lcid = p_bcb->ch_lcid; + result = L2CAP_CONN_OK; + LOG_VERBOSE("Detected conflict_lcid:0x%x", p_bcb->conflict_lcid); + } } } /* else no control channel yet, reject */ @@ -103,6 +147,7 @@ void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, /* If we reject the connection, send DisconnectReq */ if (result != L2CAP_CONN_OK) { + LOG_VERBOSE("Connection rejected to lcid:0x%x", lcid); L2CA_DisconnectReq(lcid); } @@ -117,11 +162,16 @@ void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, } void avct_br_on_l2cap_error(uint16_t lcid, uint16_t result) { - tAVCT_BCB* p_lcb = avct_bcb_by_lcid(lcid); - if (p_lcb == nullptr) return; + tAVCT_BCB* p_bcb = avct_bcb_by_lcid(lcid); + if (p_bcb == nullptr) return; + if (p_bcb->ch_state == AVCT_CH_CONN && p_bcb->conflict_lcid == lcid) { + LOG_VERBOSE("Reset conflict_lcid:0x%x", p_bcb->conflict_lcid); + p_bcb->conflict_lcid = 0; + return; + } /* store result value */ - p_lcb->ch_result = result; + p_bcb->ch_result = result; /* Send L2CAP disconnect req */ avct_l2c_br_disconnect(lcid, 0); @@ -138,20 +188,35 @@ void avct_br_on_l2cap_error(uint16_t lcid, uint16_t result) { * ******************************************************************************/ void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result) { - tAVCT_BCB* p_lcb; + tAVCT_BCB* p_bcb; - /* look up lcb for this channel */ - p_lcb = avct_bcb_by_lcid(lcid); - if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CONN)) return; + /* look up bcb for this channel */ + p_bcb = avct_bcb_by_lcid(lcid); - if (result != L2CAP_CONN_OK) { - LOG(ERROR) << __func__ << ": invoked with non OK status"; + if (p_bcb == NULL) { return; } - - /* result is successful */ - /* set channel state */ - p_lcb->ch_state = AVCT_CH_CFG; + /* if in correct state */ + if (p_bcb->ch_state == AVCT_CH_CONN) { + /* if result successful */ + if (result == L2CAP_CONN_OK) { + /* set channel state */ + p_bcb->ch_state = AVCT_CH_CFG; + } + /* else failure */ + else { + LOG_ERROR("Invoked with non OK status"); + } + } else if (p_bcb->conflict_lcid == lcid) { + /* we must be in AVCT_CH_CFG state for the ch_lcid channel */ + if (result == L2CAP_CONN_OK) { + /* just in case the peer also accepts our connection - Send L2CAP + * disconnect req */ + LOG_VERBOSE("Disconnect conflict_lcid:0x%x", p_bcb->conflict_lcid); + L2CA_DisconnectReq(lcid); + } + p_bcb->conflict_lcid = 0; + } } /******************************************************************************* @@ -206,7 +271,7 @@ void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { p_lcb->peer_mtu = max_mtu; } - AVCT_TRACE_DEBUG("%s peer_mtu:%d use:%d", __func__, p_lcb->peer_mtu, max_mtu); + LOG_VERBOSE("%s peer_mtu:%d use:%d", __func__, p_lcb->peer_mtu, max_mtu); } /******************************************************************************* diff --git a/system/stack/avct/avct_lcb.cc b/system/stack/avct/avct_lcb.cc index 623966ca5b3e76080deb8b9ffda9613cfa2b1f4a..6a3aebd3bb94b726f03840d1228fde0548d52c76 100644 --- a/system/stack/avct/avct_lcb.cc +++ b/system/stack/avct/avct_lcb.cc @@ -23,13 +23,16 @@ * ******************************************************************************/ +#define LOG_TAG "avctp" + #include #include #include "avct_api.h" #include "avct_int.h" -#include "bt_target.h" #include "device/include/device_iot_config.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" @@ -167,8 +170,8 @@ void avct_lcb_event(tAVCT_LCB* p_lcb, uint8_t event, tAVCT_LCB_EVT* p_data) { uint8_t action; int i; - AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated, - avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]); + LOG_VERBOSE("LCB lcb=%d event=%s state=%s", p_lcb->allocated, + avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]); /* look up the state table for the current state */ state_table = avct_lcb_st_tbl[p_lcb->state]; @@ -206,8 +209,8 @@ void avct_bcb_event(tAVCT_BCB* p_bcb, uint8_t event, tAVCT_LCB_EVT* p_data) { uint8_t action; int i; - AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated, - avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]); + LOG_VERBOSE("BCB lcb=%d event=%s state=%s", 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]; @@ -251,7 +254,7 @@ tAVCT_LCB* avct_lcb_by_bd(const RawAddress& bd_addr) { /* if no lcb found */ p_lcb = NULL; - VLOG(1) << "No lcb for addr " << bd_addr; + VLOG(1) << "No lcb for addr " << ADDRESS_TO_LOGGABLE_STR(bd_addr); } return p_lcb; } @@ -274,7 +277,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; - AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated); + LOG_VERBOSE("avct_lcb_alloc %d", p_lcb->allocated); p_lcb->tx_q = fixed_queue_new(SIZE_MAX); p_lcb->peer_mtu = L2CAP_LE_MIN_MTU; break; @@ -284,7 +287,7 @@ tAVCT_LCB* avct_lcb_alloc(const RawAddress& bd_addr) { if (i == AVCT_NUM_LINKS) { /* out of lcbs */ p_lcb = NULL; - AVCT_TRACE_WARNING("Out of lcbs"); + LOG_WARN("Out of lcbs"); } return p_lcb; } @@ -300,21 +303,21 @@ tAVCT_LCB* avct_lcb_alloc(const RawAddress& bd_addr) { * ******************************************************************************/ void avct_lcb_dealloc(tAVCT_LCB* p_lcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) { - AVCT_TRACE_DEBUG("%s allocated: %d", __func__, p_lcb->allocated); + LOG_VERBOSE("%s allocated: %d", __func__, 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) { - AVCT_TRACE_DEBUG("%s LCB in use; lcb index: %d", __func__, i); + LOG_VERBOSE("%s LCB in use; lcb index: %zu", __func__, i); return; } } // If not, de-allocate now... - AVCT_TRACE_DEBUG("%s Freeing LCB", __func__); + LOG_VERBOSE("%s Freeing LCB", __func__); osi_free(p_lcb->p_rx_msg); fixed_queue_free(p_lcb->tx_q, NULL); memset(p_lcb, 0, sizeof(tAVCT_LCB)); @@ -344,7 +347,7 @@ tAVCT_LCB* avct_lcb_by_lcid(uint16_t lcid) { if (i == AVCT_NUM_LINKS) { /* out of lcbs */ p_lcb = NULL; - AVCT_TRACE_WARNING("No lcb for lcid %x", lcid); + LOG_WARN("No lcb for lcid %x", lcid); } return p_lcb; @@ -386,11 +389,10 @@ bool avct_lcb_last_ccb(tAVCT_LCB* p_lcb, tAVCT_CCB* p_ccb_last) { tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; int i; - AVCT_TRACE_WARNING("avct_lcb_last_ccb"); + LOG_WARN("avct_lcb_last_ccb"); for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { - AVCT_TRACE_WARNING("%x: aloc:%d, lcb:0x%x/0x%x, ccb:0x%x/0x%x", i, - p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb, - p_ccb_last); + LOG_WARN("%x: aloc:%d, lcb:0x%p/0x%p, ccb:0x%p/0x%p", i, p_ccb->allocated, + p_ccb->p_lcb, p_lcb, p_ccb, p_ccb_last); 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 99f1d6b9697270aea22e348a4337b493a7191b84..32cdb1ede1c2807ce8668ecbaf83be6042aeeb26 100644 --- a/system/stack/avct/avct_lcb_act.cc +++ b/system/stack/avct/avct_lcb_act.cc @@ -21,20 +21,21 @@ * This module contains action functions of the link control state machine. * ******************************************************************************/ - +#include #include #include "avct_api.h" #include "avct_int.h" #include "bt_target.h" -#include "bta/include/bta_api.h" -#include "btm_api.h" +#include "bta/include/bta_sec_api.h" #include "device/include/device_iot_config.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" -#include "stack/btm/btm_sec.h" +#include "stack/avct/avct_defs.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" /* packet header length lookup table */ const uint8_t avct_lcb_pkt_type_len[] = {AVCT_HDR_LEN_SINGLE, @@ -71,14 +72,13 @@ static BT_HDR* avct_lcb_msg_asmbl(tAVCT_LCB* p_lcb, BT_HDR* p_buf) { if (p_buf->len < avct_lcb_pkt_type_len[pkt_type] || (sizeof(BT_HDR) + p_buf->offset + p_buf->len) > BT_DEFAULT_BUFFER_SIZE) { osi_free(p_buf); - AVCT_TRACE_WARNING("Bad length during reassembly"); + LOG_WARN("Bad length during reassembly"); p_ret = NULL; } /* single packet */ else if (pkt_type == AVCT_PKT_TYPE_SINGLE) { /* if reassembly in progress drop message and process new single */ - if (p_lcb->p_rx_msg != NULL) - AVCT_TRACE_WARNING("Got single during reassembly"); + if (p_lcb->p_rx_msg != NULL) LOG_WARN("Got single during reassembly"); osi_free_and_reset((void**)&p_lcb->p_rx_msg); @@ -87,8 +87,7 @@ static BT_HDR* avct_lcb_msg_asmbl(tAVCT_LCB* p_lcb, BT_HDR* p_buf) { /* start packet */ else if (pkt_type == AVCT_PKT_TYPE_START) { /* if reassembly in progress drop message and process new start */ - if (p_lcb->p_rx_msg != NULL) - AVCT_TRACE_WARNING("Got start during reassembly"); + if (p_lcb->p_rx_msg != NULL) LOG_WARN("Got start during reassembly"); osi_free_and_reset((void**)&p_lcb->p_rx_msg); @@ -127,7 +126,7 @@ static BT_HDR* avct_lcb_msg_asmbl(tAVCT_LCB* p_lcb, BT_HDR* p_buf) { /* if no reassembly in progress drop message */ if (p_lcb->p_rx_msg == NULL) { osi_free(p_buf); - AVCT_TRACE_WARNING("Pkt type=%d out of order", pkt_type); + LOG_WARN("Pkt type=%d out of order", pkt_type); p_ret = NULL; } else { /* get size of buffer holding assembled message */ @@ -144,7 +143,7 @@ static BT_HDR* avct_lcb_msg_asmbl(tAVCT_LCB* p_lcb, BT_HDR* p_buf) { /* verify length */ if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len) { /* won't fit; free everything */ - AVCT_TRACE_WARNING("%s: Fragmented message too big!", __func__); + LOG_WARN("%s: Fragmented message too big!", __func__); osi_free_and_reset((void**)&p_lcb->p_rx_msg); osi_free(p_buf); p_ret = NULL; @@ -226,25 +225,76 @@ void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { int i; bool bind = false; - for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { - /* if ccb allocated and */ - if (p_ccb->allocated) { - /* if bound to this lcb send connect confirm event */ - if (p_ccb->p_lcb == p_lcb) { - bind = true; - L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH); - p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT, 0, - &p_lcb->peer_addr); + if (GET_SYSPROP(A2dp, src_sink_coexist, false)) { + 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) { + LOG_VERBOSE("%s, find int handle %d", __func__, i); + is_originater = true; } - /* 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) && - (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; - L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH); - p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT, 0, - &p_lcb->peer_addr); + } + + p_ccb = &avct_cb.ccb[0]; + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + /* if ccb allocated and */ + /** M: to avoid avctp collision, make sure the collision can be checked @{ + */ + LOG_VERBOSE("%s, %d ccb to lcb, alloc %d, lcb %p, role %d, pid 0x%x", + __func__, i, p_ccb->allocated, p_ccb->p_lcb, 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) { + /** @} */ + bind = true; + L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH); + p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT, + 0, &p_lcb->peer_addr); + } + /* if unbound acceptor and lcb doesn't already have a ccb for this PID + */ + /** 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)) { + /* bind ccb to lcb and send connect ind event */ + if (is_originater) { + LOG_ERROR("%s, int exist, unbind acp handle:%d", __func__, i); + p_ccb->p_lcb = NULL; + } else { + bind = true; + p_ccb->p_lcb = p_lcb; + L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH); + p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT, + 0, &p_lcb->peer_addr); + } + } + } + } + } else { + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + /* if ccb allocated and */ + if (p_ccb->allocated) { + /* if bound to this lcb send connect confirm event */ + if (p_ccb->p_lcb == p_lcb) { + bind = true; + L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH); + p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT, + 0, &p_lcb->peer_addr); + } + /* 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) && + (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; + L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH); + p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT, + 0, &p_lcb->peer_addr); + } } } } @@ -466,7 +516,7 @@ void avct_lcb_cong_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { * ******************************************************************************/ void avct_lcb_discard_msg(UNUSED_ATTR tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { - AVCT_TRACE_WARNING("%s Dropping message", __func__); + LOG_WARN("%s Dropping message", __func__); osi_free_and_reset((void**)&p_data->ul_msg.p_buf); } @@ -564,8 +614,7 @@ void avct_lcb_send_msg(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { pkt_type = AVCT_PKT_TYPE_END; } } - AVCT_TRACE_DEBUG("%s tx_q_count:%d", __func__, - fixed_queue_length(p_lcb->tx_q)); + LOG_VERBOSE("%s tx_q_count:%zu", __func__, fixed_queue_length(p_lcb->tx_q)); return; } @@ -618,28 +667,36 @@ void avct_lcb_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { /* parse header byte */ AVCT_PARSE_HDR(p, label, type, cr_ipid); + /* parse PID */ + BE_STREAM_TO_UINT16(pid, p); /* check for invalid cr_ipid */ if (cr_ipid == AVCT_CR_IPID_INVALID) { - AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid); + LOG_WARN("Invalid cr_ipid %d", cr_ipid); osi_free_and_reset((void**)&p_data->p_buf); return; } - /* parse and lookup PID */ - BE_STREAM_TO_UINT16(pid, p); - p_ccb = avct_lcb_has_pid(p_lcb, pid); - if (p_ccb) { - /* PID found; send msg up, adjust bt hdr and call msg callback */ - p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE; - p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE; - (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, - p_data->p_buf); - return; + bool bind = false; + if (GET_SYSPROP(A2dp, src_sink_coexist, false)) { + bind = avct_msg_ind_for_src_sink_coexist(p_lcb, p_data, label, cr_ipid); + osi_free_and_reset((void**)&p_data->p_buf); + if (bind) return; + } else { + /* lookup PID */ + p_ccb = avct_lcb_has_pid(p_lcb, pid); + if (p_ccb) { + /* PID found; send msg up, adjust bt hdr and call msg callback */ + p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE; + p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE; + (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, + p_data->p_buf); + return; + } } /* PID not found; drop message */ - AVCT_TRACE_WARNING("No ccb for PID=%x", pid); + LOG_WARN("No ccb for PID=%x", pid); osi_free_and_reset((void**)&p_data->p_buf); /* if command send reject */ @@ -653,3 +710,34 @@ void avct_lcb_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { L2CA_DataWrite(p_lcb->ch_lcid, p_buf); } } + +bool avct_msg_ind_for_src_sink_coexist(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data, + uint8_t label, uint8_t cr_ipid) { + bool bind = false; + tAVCT_CCB* p_ccb; + int p_buf_len; + uint8_t* p; + uint16_t pid; + + p = (uint8_t*)(p_data->p_buf + 1) + p_data->p_buf->offset; + + BE_STREAM_TO_UINT16(pid, p); + + p_ccb = &avct_cb.ccb[0]; + p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE; + p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE; + p_buf_len = BT_HDR_SIZE + p_data->p_buf->offset + p_data->p_buf->len; + + for (int i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid)) { + /* PID found; send msg up, adjust bt hdr and call msg callback */ + bind = true; + BT_HDR* p_tmp_buf = (BT_HDR*)osi_malloc(p_buf_len); + memcpy(p_tmp_buf, p_data->p_buf, p_buf_len); + (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, + p_tmp_buf); + } + } + + return bind; +} diff --git a/system/stack/avdt/avdt_ad.cc b/system/stack/avdt/avdt_ad.cc index 947c5e0c2cc0baf9e389e5676a700345c349c5b1..5d72382b80c26efe8cd9474045d20ab53cefd873 100644 --- a/system/stack/avdt/avdt_ad.cc +++ b/system/stack/avdt/avdt_ad.cc @@ -27,30 +27,28 @@ #include "avdt_api.h" #include "avdt_int.h" -#include "avdtc_api.h" -#include "bt_target.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "l2cdefs.h" #include "osi/include/allocator.h" -#include "osi/include/osi.h" -#include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" +#include "stack/include/btm_sec_api_types.h" AvdtpScb* AvdtpAdaptationLayer::LookupAvdtpScb( const AvdtpTransportChannel& tc) { if (tc.ccb_idx >= AVDT_NUM_LINKS) { - AVDT_TRACE_ERROR("%s: AvdtpScb entry not found: invalid ccb_idx:%d", - __func__, tc.ccb_idx); + LOG_ERROR("%s: AvdtpScb entry not found: invalid ccb_idx:%d", __func__, + tc.ccb_idx); return nullptr; } if (tc.tcid >= AVDT_NUM_RT_TBL) { - AVDT_TRACE_ERROR("%s: AvdtpScb entry not found: invalid tcid:%d", __func__, - tc.tcid); + LOG_ERROR("%s: AvdtpScb entry not found: invalid tcid:%d", __func__, + tc.tcid); return nullptr; } const AvdtpRoutingEntry& re = rt_tbl[tc.ccb_idx][tc.tcid]; - AVDT_TRACE_DEBUG("%s: ccb_idx:%d tcid:%d scb_hdl:%d", __func__, tc.ccb_idx, - tc.tcid, re.scb_hdl); + LOG_VERBOSE("%s: ccb_idx:%d tcid:%d scb_hdl:%d", __func__, tc.ccb_idx, + tc.tcid, re.scb_hdl); return avdt_scb_by_hdl(re.scb_hdl); } @@ -75,7 +73,7 @@ uint8_t avdt_ad_type_to_tcid(uint8_t type, AvdtpScb* p_scb) { // There are AVDT_CHAN_NUM_TYPES channel types per SEP. Here we compute // the type index (TCID) from the SEP index and the type itself. uint8_t tcid = (scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type; - AVDT_TRACE_DEBUG("%s: type:%d, tcid: %d", __func__, type, tcid); + LOG_VERBOSE("%s: type:%d, tcid: %d", __func__, type, tcid); return tcid; } @@ -102,7 +100,7 @@ static uint8_t avdt_ad_tcid_to_type(uint8_t tcid) { */ type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1; } - AVDT_TRACE_DEBUG("tcid: %d, type: %d", tcid, type); + LOG_VERBOSE("tcid: %d, type: %d", tcid, type); return type; } @@ -276,7 +274,7 @@ AvdtpTransportChannel* avdt_ad_tc_tbl_alloc(AvdtpCcb* p_ccb) { * ******************************************************************************/ uint8_t avdt_ad_tc_tbl_to_idx(AvdtpTransportChannel* p_tbl) { - AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdtp_cb.ad.tc_tbl)); + LOG_VERBOSE("avdt_ad_tc_tbl_to_idx: %ld", (long)(p_tbl - avdtp_cb.ad.tc_tbl)); /* use array arithmetic to determine index */ return (uint8_t)(p_tbl - avdtp_cb.ad.tc_tbl); } @@ -306,8 +304,8 @@ void avdt_ad_tc_close_ind(AvdtpTransportChannel* p_tbl) { p_tbl->cfg_flags = 0; p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; - AVDT_TRACE_DEBUG("%s: tcid: %d, old: %d", __func__, p_tbl->tcid, - close.old_tc_state); + LOG_VERBOSE("%s: tcid: %d, old: %d", __func__, p_tbl->tcid, + close.old_tc_state); /* if signaling channel, notify ccb that channel open */ if (p_tbl->tcid == 0) { p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); @@ -318,8 +316,8 @@ void avdt_ad_tc_close_ind(AvdtpTransportChannel* p_tbl) { /* look up scb in stream routing table by ccb, tcid */ p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl); if (p_scb == nullptr) { - AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", - __func__, p_tbl->ccb_idx, p_tbl->tcid); + LOG_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", __func__, + p_tbl->ccb_idx, p_tbl->tcid); return; } close.tcid = p_tbl->tcid; @@ -347,9 +345,9 @@ void avdt_ad_tc_open_ind(AvdtpTransportChannel* p_tbl) { tAVDT_OPEN open; tAVDT_EVT_HDR evt; - AVDT_TRACE_DEBUG("%s: p_tbl:%p state:%d ccb_idx:%d tcid:%d scb_hdl:%d", - __func__, p_tbl, p_tbl->state, p_tbl->ccb_idx, p_tbl->tcid, - avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); + LOG_VERBOSE("%s: p_tbl:%p state:%d ccb_idx:%d tcid:%d scb_hdl:%d", __func__, + p_tbl, p_tbl->state, p_tbl->ccb_idx, p_tbl->tcid, + avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); p_tbl->state = AVDT_AD_ST_OPEN; @@ -375,8 +373,8 @@ void avdt_ad_tc_open_ind(AvdtpTransportChannel* p_tbl) { /* look up scb in stream routing table by ccb, tcid */ p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl); if (p_scb == nullptr) { - AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", - __func__, p_tbl->ccb_idx, p_tbl->tcid); + LOG_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", __func__, + p_tbl->ccb_idx, p_tbl->tcid); return; } /* put lcid in event data */ @@ -418,8 +416,8 @@ void avdt_ad_tc_cong_ind(AvdtpTransportChannel* p_tbl, bool is_congested) { /* look up scb in stream routing table by ccb, tcid */ p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl); if (p_scb == nullptr) { - AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", - __func__, p_tbl->ccb_idx, p_tbl->tcid); + LOG_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", __func__, + p_tbl->ccb_idx, p_tbl->tcid); return; } tAVDT_SCB_EVT avdt_scb_evt; @@ -455,10 +453,10 @@ void avdt_ad_tc_data_ind(AvdtpTransportChannel* p_tbl, BT_HDR* p_buf) { /* if media or other channel, send event to scb */ p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl); if (p_scb == nullptr) { - AVDT_TRACE_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", - __func__, p_tbl->ccb_idx, p_tbl->tcid); + LOG_ERROR("%s: Cannot find AvdtScb entry: ccb_idx:%d tcid:%d", __func__, + p_tbl->ccb_idx, p_tbl->tcid); osi_free(p_buf); - AVDT_TRACE_ERROR("%s: buffer freed", __func__); + LOG_ERROR("%s: buffer freed", __func__); return; } avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT*)&p_buf); @@ -514,13 +512,13 @@ void avdt_ad_open_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb, p_tbl = avdt_ad_tc_tbl_alloc(p_ccb); if (p_tbl == NULL) { - AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl"); + LOG_ERROR("avdt_ad_open_req: Cannot allocate p_tbl"); return; } p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb); - AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d", type, role, - p_tbl->tcid); + LOG_VERBOSE("avdt_ad_open_req: type: %d, role: %d, tcid:%d", type, role, + p_tbl->tcid); if (type == AVDT_CHAN_SIG) { /* if signaling, get mtu from registration control block */ @@ -532,9 +530,8 @@ void avdt_ad_open_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb, /* also set scb_hdl in rt_tbl */ avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = avdt_scb_to_hdl(p_scb); - AVDT_TRACE_DEBUG("avdtp_cb.ad.rt_tbl[%d][%d].scb_hdl = %d", - avdt_ccb_to_idx(p_ccb), p_tbl->tcid, - avdt_scb_to_hdl(p_scb)); + LOG_VERBOSE("avdtp_cb.ad.rt_tbl[%d][%d].scb_hdl = %d", + avdt_ccb_to_idx(p_ccb), p_tbl->tcid, avdt_scb_to_hdl(p_scb)); } /* if we're acceptor, we're done; just sit back and listen */ @@ -551,12 +548,12 @@ void avdt_ad_open_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb, if (lcid != 0) { /* if connect req ok, store tcid in lcid table */ avdtp_cb.ad.lcid_tbl[lcid] = avdt_ad_tc_tbl_to_idx(p_tbl); - AVDT_TRACE_DEBUG("avdtp_cb.ad.lcid_tbl[%d] = %d", (lcid), - avdt_ad_tc_tbl_to_idx(p_tbl)); + LOG_VERBOSE("avdtp_cb.ad.lcid_tbl[%d] = %d", (lcid), + avdt_ad_tc_tbl_to_idx(p_tbl)); avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid; - AVDT_TRACE_DEBUG("avdtp_cb.ad.rt_tbl[%d][%d].lcid = 0x%x", - avdt_ccb_to_idx(p_ccb), p_tbl->tcid, lcid); + LOG_VERBOSE("avdtp_cb.ad.rt_tbl[%d][%d].lcid = 0x%x", + avdt_ccb_to_idx(p_ccb), p_tbl->tcid, lcid); } else { /* if connect req failed, call avdt_ad_tc_close_ind() */ avdt_ad_tc_close_ind(p_tbl); @@ -581,7 +578,7 @@ void avdt_ad_close_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb) { AvdtpTransportChannel* p_tbl; p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb); - AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d", p_tbl->state); + LOG_VERBOSE("avdt_ad_close_req state: %d", p_tbl->state); switch (p_tbl->state) { case AVDT_AD_ST_UNUSED: diff --git a/system/stack/avdt/avdt_api.cc b/system/stack/avdt/avdt_api.cc index 13f73a648f26f900986ea52412aee2e8151d88f7..60518de3c7b35aae1aa781a7696447229fc1f48a 100644 --- a/system/stack/avdt/avdt_api.cc +++ b/system/stack/avdt/avdt_api.cc @@ -29,13 +29,10 @@ #include "avdt_int.h" #include "avdtc_api.h" -#include "bt_target.h" -#include "bta/include/bta_api.h" -#include "btm_api.h" +#include "bta/include/bta_sec_api.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" -#include "main/shim/dumpsys.h" -#include "osi/include/log.h" -#include "stack/btm/btm_sec.h" +#include "os/log.h" #include "stack/include/a2dp_codec_api.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" @@ -129,14 +126,14 @@ void AVDT_Deregister(void) { } void AVDT_AbortReq(uint8_t handle) { - AVDT_TRACE_WARNING("%s: avdt_handle=%d", __func__, handle); + LOG_WARN("%s: avdt_handle=%d", __func__, handle); AvdtpScb* p_scb = avdt_scb_by_hdl(handle); if (p_scb != NULL) { avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_REQ_EVT, NULL); } else { - AVDT_TRACE_ERROR("%s Improper avdp_handle=%d, can not abort the stream", - __func__, handle); + LOG_ERROR("%s Improper avdp_handle=%d, can not abort the stream", __func__, + handle); } } @@ -201,7 +198,7 @@ uint16_t AVDT_RemoveStream(uint8_t handle) { uint16_t result = AVDT_SUCCESS; AvdtpScb* p_scb; - AVDT_TRACE_DEBUG("%s: avdt_handle=%d", __func__, handle); + LOG_VERBOSE("%s: avdt_handle=%d", __func__, handle); /* look up scb */ p_scb = avdt_scb_by_hdl(handle); @@ -213,7 +210,7 @@ uint16_t AVDT_RemoveStream(uint8_t handle) { } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); + LOG_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); } return result; @@ -252,7 +249,7 @@ uint16_t AVDT_DiscoverReq(const RawAddress& bd_addr, uint8_t channel_index, uint16_t result = AVDT_SUCCESS; tAVDT_CCB_EVT evt; - AVDT_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* find channel control block for this bd addr; if none, allocate one */ p_ccb = avdt_ccb_by_bd(bd_addr); @@ -279,8 +276,8 @@ uint16_t AVDT_DiscoverReq(const RawAddress& bd_addr, uint8_t channel_index, } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d address=%s", __func__, result, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_ERROR("%s: result=%d address=%s", __func__, result, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } return result; } @@ -300,12 +297,12 @@ static uint16_t avdt_get_cap_req(const RawAddress& bd_addr, AvdtpCcb* p_ccb = NULL; uint16_t result = AVDT_SUCCESS; - AVDT_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* verify SEID */ if ((p_evt->single.seid < AVDT_SEID_MIN) || (p_evt->single.seid > AVDT_SEID_MAX)) { - AVDT_TRACE_ERROR("seid: %d", p_evt->single.seid); + LOG_ERROR("seid: %d", p_evt->single.seid); result = AVDT_BAD_PARAMS; } /* find channel control block for this bd addr; if none, allocate one */ @@ -332,8 +329,8 @@ static uint16_t avdt_get_cap_req(const RawAddress& bd_addr, } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d address=%s", __func__, result, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_ERROR("%s: result=%d address=%s", __func__, result, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } return result; } @@ -368,7 +365,7 @@ uint16_t AVDT_GetCapReq(const RawAddress& bd_addr, uint8_t channel_index, tAVDT_CCB_API_GETCAP getcap; uint16_t result = AVDT_SUCCESS; - AVDT_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); getcap.single.seid = seid; if (get_all_cap) { @@ -381,8 +378,8 @@ uint16_t AVDT_GetCapReq(const RawAddress& bd_addr, uint8_t channel_index, result = avdt_get_cap_req(bd_addr, channel_index, &getcap); if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d address=%s", __func__, result, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_ERROR("%s: result=%d address=%s", __func__, result, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); } return result; } @@ -403,8 +400,8 @@ uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay) { uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; - AVDT_TRACE_DEBUG("%s: avdt_handle=%d seid=%d delay=%d", __func__, handle, - seid, delay); + LOG_VERBOSE("%s: avdt_handle=%d seid=%d delay=%d", __func__, handle, seid, + delay); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); @@ -419,8 +416,8 @@ uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay) { } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d avdt_handle=%d seid=%d", __func__, result, - handle, seid); + LOG_ERROR("%s: result=%d avdt_handle=%d seid=%d", __func__, result, handle, + seid); } return result; } @@ -447,8 +444,8 @@ uint16_t AVDT_OpenReq(uint8_t handle, const RawAddress& bd_addr, uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; - AVDT_TRACE_API("%s: address=%s avdt_handle=%d seid=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), handle, seid); + LOG_VERBOSE("%s: address=%s avdt_handle=%d seid=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), handle, seid); /* verify SEID */ if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX)) { @@ -475,8 +472,8 @@ uint16_t AVDT_OpenReq(uint8_t handle, const RawAddress& bd_addr, /* send event to scb */ if (result == AVDT_SUCCESS) { - AVDT_TRACE_DEBUG("%s: codec: %s", __func__, - A2DP_CodecInfoString(p_cfg->codec_info).c_str()); + LOG_VERBOSE("%s: codec: %s", __func__, + A2DP_CodecInfoString(p_cfg->codec_info).c_str()); evt.msg.config_cmd.hdr.seid = seid; evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb); @@ -484,8 +481,8 @@ uint16_t AVDT_OpenReq(uint8_t handle, const RawAddress& bd_addr, evt.msg.config_cmd.p_cfg = p_cfg; avdt_scb_event(p_scb, AVDT_SCB_API_SETCONFIG_REQ_EVT, &evt); } else { - AVDT_TRACE_ERROR("%s: result=%d address=%s avdt_handle=%d", __func__, - result, ADDRESS_TO_LOGGABLE_CSTR(bd_addr), handle); + LOG_ERROR("%s: result=%d address=%s avdt_handle=%d", __func__, result, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), handle); } return result; @@ -510,8 +507,8 @@ uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code, uint16_t result = AVDT_SUCCESS; uint8_t event_code; - AVDT_TRACE_DEBUG("%s: avdt_handle=%d label=%d error_code=0x%x category=%d", - __func__, handle, label, error_code, category); + LOG_VERBOSE("%s: avdt_handle=%d label=%d error_code=0x%x category=%d", + __func__, handle, label, error_code, category); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); @@ -538,7 +535,7 @@ uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code, } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); + LOG_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); } return result; } @@ -564,7 +561,7 @@ uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles) { uint16_t result = AVDT_SUCCESS; int i; - AVDT_TRACE_DEBUG("%s: num_handles=%d", __func__, num_handles); + LOG_VERBOSE("%s: num_handles=%d", __func__, num_handles); if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) { result = AVDT_BAD_PARAMS; @@ -592,12 +589,11 @@ uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles) { if (result != AVDT_SUCCESS) { if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) { - AVDT_TRACE_ERROR("%s: result=%d num_handles=%d invalid", __func__, result, - num_handles); + LOG_ERROR("%s: result=%d num_handles=%d invalid", __func__, result, + num_handles); } else { - AVDT_TRACE_ERROR( - "%s: result=%d avdt_handle=%d", __func__, result, - (i < num_handles ? p_handles[i] : p_handles[num_handles - 1])); + LOG_ERROR("%s: result=%d avdt_handle=%d", __func__, result, + (i < num_handles ? p_handles[i] : p_handles[num_handles - 1])); } } return result; @@ -624,7 +620,7 @@ uint16_t AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles) { uint16_t result = AVDT_SUCCESS; int i; - AVDT_TRACE_DEBUG("%s: num_handles=%d", __func__, num_handles); + LOG_VERBOSE("%s: num_handles=%d", __func__, num_handles); if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) { result = AVDT_BAD_PARAMS; @@ -652,12 +648,11 @@ uint16_t AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles) { if (result != AVDT_SUCCESS) { if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) { - AVDT_TRACE_ERROR("%s: result=%d num_handles=%d invalid", __func__, result, - num_handles); + LOG_ERROR("%s: result=%d num_handles=%d invalid", __func__, result, + num_handles); } else { - AVDT_TRACE_ERROR( - "%s: result=%d avdt_handle=%d", __func__, result, - (i < num_handles ? p_handles[i] : p_handles[num_handles - 1])); + LOG_ERROR("%s: result=%d avdt_handle=%d", __func__, result, + (i < num_handles ? p_handles[i] : p_handles[num_handles - 1])); } } return result; @@ -681,7 +676,7 @@ uint16_t AVDT_CloseReq(uint8_t handle) { AvdtpScb* p_scb; uint16_t result = AVDT_SUCCESS; - AVDT_TRACE_API("%s: avdt_handle=%d", __func__, handle); + LOG_VERBOSE("%s: avdt_handle=%d", __func__, handle); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); @@ -694,7 +689,7 @@ uint16_t AVDT_CloseReq(uint8_t handle) { } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); + LOG_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); } return result; } @@ -721,7 +716,7 @@ uint16_t AVDT_ReconfigReq(uint8_t handle, AvdtpSepConfig* p_cfg) { uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; - AVDT_TRACE_DEBUG("%s: avdt_handle=%d", __func__, handle); + LOG_VERBOSE("%s: avdt_handle=%d", __func__, handle); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); @@ -737,7 +732,7 @@ uint16_t AVDT_ReconfigReq(uint8_t handle, AvdtpSepConfig* p_cfg) { } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); + LOG_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); } return result; } @@ -761,7 +756,7 @@ uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len) { uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; - AVDT_TRACE_DEBUG("%s: avdt_handle=%d len=%d", __func__, handle, len); + LOG_VERBOSE("%s: avdt_handle=%d len=%d", __func__, handle, len); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); @@ -776,7 +771,7 @@ uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len) { } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); + LOG_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); } return result; } @@ -801,8 +796,8 @@ uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code, uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; - AVDT_TRACE_DEBUG("%s: avdt_handle=%d label=%d error_code=0x%x len=%d", - __func__, handle, label, error_code, len); + LOG_VERBOSE("%s: avdt_handle=%d label=%d error_code=0x%x len=%d", __func__, + handle, label, error_code, len); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); @@ -819,7 +814,7 @@ uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code, } if (result != AVDT_SUCCESS) { - AVDT_TRACE_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); + LOG_ERROR("%s: result=%d avdt_handle=%d", __func__, result, handle); } return result; } @@ -867,8 +862,8 @@ uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp, tAVDT_SCB_EVT evt; uint16_t result = AVDT_SUCCESS; - AVDT_TRACE_DEBUG("%s: avdt_handle=%d timestamp=%d m_pt=0x%x opt=0x%x", - __func__, handle, time_stamp, m_pt, opt); + LOG_VERBOSE("%s: avdt_handle=%d timestamp=%d m_pt=0x%x opt=0x%x", __func__, + handle, time_stamp, m_pt, opt); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); @@ -882,7 +877,7 @@ uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp, avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt); } - AVDT_TRACE_DEBUG("%s: result=%d avdt_handle=%d", __func__, result, handle); + LOG_VERBOSE("%s: result=%d avdt_handle=%d", __func__, result, handle); return result; } @@ -907,8 +902,8 @@ uint16_t AVDT_ConnectReq(const RawAddress& bd_addr, uint8_t channel_index, uint16_t result = AVDT_SUCCESS; tAVDT_CCB_EVT evt; - AVDT_TRACE_WARNING("%s: address=%s channel_index=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), channel_index); + LOG_WARN("%s: address=%s channel_index=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), channel_index); /* find channel control block for this bd addr; if none, allocate one */ p_ccb = avdt_ccb_by_bd(bd_addr); @@ -919,7 +914,7 @@ uint16_t AVDT_ConnectReq(const RawAddress& bd_addr, uint8_t channel_index, result = AVDT_NO_RESOURCES; } } else if (!p_ccb->ll_opened) { - AVDT_TRACE_WARNING("AVDT_ConnectReq: CCB LL is in the middle of opening"); + LOG_WARN("AVDT_ConnectReq: CCB LL is in the middle of opening"); /* ccb was already allocated for the incoming signalling. */ result = AVDT_BUSY; @@ -931,8 +926,8 @@ uint16_t AVDT_ConnectReq(const RawAddress& bd_addr, uint8_t channel_index, avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt); } - AVDT_TRACE_WARNING("%s: address=%s result=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), result); + LOG_WARN("%s: address=%s result=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), result); return result; } @@ -997,36 +992,7 @@ uint16_t AVDT_GetL2CapChannel(uint8_t handle) { return (lcid); } -/****************************************************************************** - * - * Function AVDT_SetTraceLevel - * - * Description Sets the trace level for AVDT. If 0xff is passed, the - * current trace level is returned. - * - * Input Parameters: - * new_level: The level to set the AVDT tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new trace level or current trace level if - * the input parameter is 0xff. - * - *****************************************************************************/ -uint8_t AVDT_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) avdtp_cb.SetTraceLevel(new_level); - - return avdtp_cb.TraceLevel(); -} - void stack_debug_avdtp_api_dump(int fd) { - if (appl_trace_level < BT_TRACE_LEVEL_DEBUG) return; - dprintf(fd, "\nAVDTP Stack State:\n"); dprintf(fd, " AVDTP signalling L2CAP channel MTU: %d\n", avdtp_cb.rcb.ctrl_mtu); diff --git a/system/stack/avdt/avdt_ccb.cc b/system/stack/avdt/avdt_ccb.cc index e145d8ab107156958a3e1e78275706dd11cc4fff..2083b3888f9a15b171d0b73ae10cf073b689d6a8 100644 --- a/system/stack/avdt/avdt_ccb.cc +++ b/system/stack/avdt/avdt_ccb.cc @@ -23,17 +23,14 @@ * ******************************************************************************/ +#include // VLOG #include -#include "avdt_api.h" #include "avdt_int.h" -#include "avdtc_api.h" -#include "bt_target.h" +#include "internal_include/bt_target.h" #include "osi/include/osi.h" #include "types/raw_address.h" -#include - /***************************************************************************** * state machine constants and types ****************************************************************************/ @@ -370,9 +367,9 @@ void avdt_ccb_event(AvdtpCcb* p_ccb, uint8_t event, tAVDT_CCB_EVT* p_data) { int i; #if (AVDT_DEBUG == TRUE) - AVDT_TRACE_EVENT("%s: CCB ccb=%d event=%s state=%s p_ccb=%p", __func__, - avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event], - avdt_ccb_st_str[p_ccb->state], p_ccb); + LOG_VERBOSE("%s: CCB ccb=%d event=%s state=%s p_ccb=%p", __func__, + avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event], + avdt_ccb_st_str[p_ccb->state], p_ccb); #endif /* look up the state table for the current state */ @@ -386,9 +383,8 @@ void avdt_ccb_event(AvdtpCcb* p_ccb, uint8_t event, tAVDT_CCB_EVT* p_data) { /* execute action functions */ for (i = 0; i < AVDT_CCB_ACTIONS; i++) { action = state_table[event][i]; - AVDT_TRACE_DEBUG("%s: event=%s state=%s action=%d", __func__, - avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state], - action); + LOG_VERBOSE("%s: event=%s state=%s action=%d", __func__, + avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state], action); if (action != AVDT_CCB_IGNORE) { (*avdtp_cb.p_ccb_act[action])(p_ccb, p_data); } else { @@ -443,13 +439,13 @@ AvdtpCcb* avdt_ccb_alloc(const RawAddress& bd_addr) { for (int i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++) { if (!p_ccb->allocated) { p_ccb->Allocate(bd_addr); - AVDT_TRACE_DEBUG("%s: allocated (index %d) for peer %s", __func__, i, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("%s: allocated (index %d) for peer %s", __func__, i, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); return p_ccb; } } - AVDT_TRACE_WARNING("%s: out of AvdtpCcb entries", __func__); + LOG_WARN("%s: out of AvdtpCcb entries", __func__); return nullptr; } @@ -457,21 +453,19 @@ AvdtpCcb* avdt_ccb_alloc_by_channel_index(const RawAddress& bd_addr, uint8_t channel_index) { // Allocate the entry for the specified channel index if (channel_index >= AVDT_NUM_LINKS) { - AVDT_TRACE_ERROR("%s: peer %s invalid channel index %d (max %d)", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), channel_index, - AVDT_NUM_LINKS); + LOG_ERROR("%s: peer %s invalid channel index %d (max %d)", __func__, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), channel_index, AVDT_NUM_LINKS); return nullptr; } AvdtpCcb* p_ccb = &avdtp_cb.ccb[channel_index]; if (p_ccb->allocated) { - AVDT_TRACE_ERROR("%s: peer %s channel index %d already allocated", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), channel_index); + LOG_ERROR("%s: peer %s channel index %d already allocated", __func__, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), channel_index); return nullptr; } p_ccb->Allocate(bd_addr); - AVDT_TRACE_DEBUG("%s: allocated (index %d) peer=%s p_ccb=%p", __func__, - channel_index, ADDRESS_TO_LOGGABLE_CSTR(p_ccb->peer_addr), - p_ccb); + LOG_VERBOSE("%s: allocated (index %d) peer=%s p_ccb=%p", __func__, + channel_index, ADDRESS_TO_LOGGABLE_CSTR(p_ccb->peer_addr), p_ccb); return p_ccb; } @@ -497,9 +491,9 @@ void AvdtpCcb::Allocate(const RawAddress& peer_address) { * ******************************************************************************/ void avdt_ccb_dealloc(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { - AVDT_TRACE_DEBUG("%s: deallocated (index %d) peer=%s p_ccb=%p", __func__, - avdt_ccb_to_idx(p_ccb), - ADDRESS_TO_LOGGABLE_CSTR(p_ccb->peer_addr), p_ccb); + LOG_VERBOSE("%s: deallocated (index %d) peer=%s p_ccb=%p", __func__, + avdt_ccb_to_idx(p_ccb), + ADDRESS_TO_LOGGABLE_CSTR(p_ccb->peer_addr), p_ccb); p_ccb->ResetCcb(); } @@ -536,7 +530,7 @@ AvdtpCcb* avdt_ccb_by_idx(uint8_t idx) { p_ccb = &avdtp_cb.ccb[idx]; } else { p_ccb = NULL; - AVDT_TRACE_WARNING("No ccb for idx %d", idx); + LOG_WARN("No ccb for idx %d", idx); } return p_ccb; } diff --git a/system/stack/avdt/avdt_ccb_act.cc b/system/stack/avdt/avdt_ccb_act.cc index f23a80a89a69099dac88a9aa8dc8f08b55398eb0..e1cbeba33399993128da84827d316959aa5be834 100644 --- a/system/stack/avdt/avdt_ccb_act.cc +++ b/system/stack/avdt/avdt_ccb_act.cc @@ -145,7 +145,7 @@ void avdt_ccb_hdl_discover_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) { tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS]; AvdtpScb* p_scb = &(p_ccb->scb[0]); - AVDT_TRACE_DEBUG("%s: p_ccb index=%d", __func__, avdt_ccb_to_idx(p_ccb)); + LOG_VERBOSE("%s: p_ccb index=%d", __func__, avdt_ccb_to_idx(p_ccb)); p_data->msg.discover_rsp.p_sep_info = sep_info; p_data->msg.discover_rsp.num_seps = 0; @@ -493,7 +493,7 @@ void avdt_ccb_snd_start_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) { tAVDT_MSG avdt_msg; uint8_t seid_list[AVDT_NUM_SEPS]; - AVDT_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* make copy of our seid list */ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps); @@ -503,7 +503,7 @@ void avdt_ccb_snd_start_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) { avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code); if (avdt_msg.hdr.err_param == 0) { - AVDT_TRACE_DEBUG("%s: AVDT_SIG_START", __func__); + LOG_VERBOSE("%s: AVDT_SIG_START", __func__); /* set peer seid list in messsage */ avdt_scb_peer_seid_list(&p_data->msg.multi); @@ -515,7 +515,7 @@ void avdt_ccb_snd_start_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) { for (i = 0; i < p_data->msg.multi.num_seps; i++) { p_scb = avdt_scb_by_hdl(seid_list[i]); if (p_scb != NULL) { - AVDT_TRACE_DEBUG("%s: AVDT_SCB_MSG_START_REJ_EVT: i=%d", __func__, i); + LOG_VERBOSE("%s: AVDT_SCB_MSG_START_REJ_EVT: i=%d", __func__, i); tAVDT_SCB_EVT avdt_scb_evt; avdt_scb_evt.msg.hdr = avdt_msg.hdr; avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT, &avdt_scb_evt); @@ -960,7 +960,7 @@ void avdt_ccb_set_conn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) { ******************************************************************************/ void avdt_ccb_set_disconn(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) { /* - AVDT_TRACE_EVENT("avdt_ccb_set_disconn:conn:x%x, api:x%x", + LOG_VERBOSE("avdt_ccb_set_disconn:conn:x%x, api:x%x", p_ccb->p_conn_cback, p_data->disconnect.p_cback); */ /* save callback */ @@ -1000,8 +1000,8 @@ void avdt_ccb_ll_closed(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { tAVDT_CTRL_CBACK* p_cback; tAVDT_CTRL avdt_ctrl; - AVDT_TRACE_DEBUG("%s peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_ccb->peer_addr)); + LOG_VERBOSE("%s peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_ccb->peer_addr)); /* clear any pending commands */ avdt_ccb_clear_cmds(p_ccb, NULL); @@ -1036,9 +1036,9 @@ void avdt_ccb_ll_closed(AvdtpCcb* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { void avdt_ccb_ll_opened(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) { tAVDT_CTRL avdt_ctrl; - AVDT_TRACE_DEBUG("%s peer %s BtaAvScbIndex=%d p_ccb=%p", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_ccb->peer_addr), - p_ccb->BtaAvScbIndex(), p_ccb); + LOG_VERBOSE("%s peer %s BtaAvScbIndex=%d p_ccb=%p", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_ccb->peer_addr), + p_ccb->BtaAvScbIndex(), p_ccb); p_ccb->ll_opened = true; if (!p_ccb->p_conn_cback) p_ccb->p_conn_cback = avdtp_cb.p_conn_cback; diff --git a/system/stack/avdt/avdt_int.h b/system/stack/avdt/avdt_int.h index acfc89d9ee08570003ead3f7e0b8509a0c50dda1..0d476bc8c202249445c600d4c44df6d5d2d8d746 100644 --- a/system/stack/avdt/avdt_int.h +++ b/system/stack/avdt/avdt_int.h @@ -29,7 +29,7 @@ #include "avdt_api.h" #include "avdt_defs.h" #include "avdtc_api.h" -#include "btm_api.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "osi/include/alarm.h" #include "osi/include/fixed_queue.h" @@ -735,8 +735,7 @@ class AvdtpCb { : p_conf_cback(nullptr), p_ccb_act(nullptr), p_scb_act(nullptr), - p_conn_cback(nullptr), - trace_level_(0) {} + p_conn_cback(nullptr) {} void Reset() { rcb.Reset(); @@ -748,7 +747,6 @@ class AvdtpCb { p_ccb_act = nullptr; p_scb_act = nullptr; p_conn_cback = nullptr; - trace_level_ = 0; } AvdtpRcb rcb; // Registration control block @@ -780,23 +778,6 @@ class AvdtpCb { } return 0; // Not found } - - /** - * Get the current trace level used for logging. - * - * @return the current trace level - */ - uint8_t TraceLevel() const { return trace_level_; } - - /** - * Set the current trace level used for logging. - * - * @param trace_level the trace level to set. Should be in the range [1, 6]. - */ - void SetTraceLevel(uint8_t trace_level) { trace_level_ = trace_level; } - - private: - uint8_t trace_level_; /* trace level */ }; /***************************************************************************** diff --git a/system/stack/avdt/avdt_l2c.cc b/system/stack/avdt/avdt_l2c.cc index 3e93d3717841565aa3998ea25cc37f09b48b14b3..1d50681109067dc0e105f7d15b953f68baeb9a09 100644 --- a/system/stack/avdt/avdt_l2c.cc +++ b/system/stack/avdt/avdt_l2c.cc @@ -111,7 +111,7 @@ static void avdt_sec_check_complete_orig(const RawAddress* bd_addr, AvdtpCcb* p_ccb = NULL; AvdtpTransportChannel* p_tbl; - AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d", res); + LOG_VERBOSE("avdt_sec_check_complete_orig res: %d", res); if (bd_addr) p_ccb = avdt_ccb_by_bd(*bd_addr); p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT); if (p_tbl == NULL) return; @@ -238,8 +238,7 @@ void avdt_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) { AvdtpTransportChannel* p_tbl; AvdtpCcb* p_ccb; - AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d", lcid, - result); + LOG_VERBOSE("avdt_l2c_connect_cfm_cback lcid: %d, result: %d", lcid, result); /* look up info for this channel */ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid); if (p_tbl != NULL) { @@ -301,7 +300,7 @@ void avdt_l2c_config_cfm_cback(uint16_t lcid, uint16_t initiator, AvdtpTransportChannel* p_tbl; - AVDT_TRACE_DEBUG("%s: lcid: %d", __func__, lcid); + LOG_VERBOSE("%s: lcid: %d", __func__, lcid); /* look up info for this channel */ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid); @@ -328,7 +327,7 @@ void avdt_l2c_config_cfm_cback(uint16_t lcid, uint16_t initiator, void avdt_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { AvdtpTransportChannel* p_tbl; - AVDT_TRACE_DEBUG("%s: lcid: %d", __func__, lcid); + LOG_VERBOSE("%s: lcid: %d", __func__, lcid); /* look up info for this channel */ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid); @@ -339,8 +338,7 @@ void avdt_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { } else { p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; } - AVDT_TRACE_DEBUG("%s: peer_mtu: %d, lcid: %d", __func__, p_tbl->peer_mtu, - lcid); + LOG_VERBOSE("%s: peer_mtu: %d, lcid: %d", __func__, p_tbl->peer_mtu, lcid); } } @@ -357,8 +355,8 @@ void avdt_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { void avdt_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) { AvdtpTransportChannel* p_tbl; - AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d", - lcid, ack_needed); + LOG_VERBOSE("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d", lcid, + ack_needed); /* look up info for this channel */ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid); if (p_tbl != NULL) { @@ -370,7 +368,7 @@ void avdt_l2c_disconnect(uint16_t lcid) { L2CA_DisconnectReq(lcid); AvdtpTransportChannel* p_tbl; - AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d", lcid); + LOG_VERBOSE("avdt_l2c_disconnect_cfm_cback lcid: %d", lcid); /* look up info for this channel */ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid); if (p_tbl != NULL) { diff --git a/system/stack/avdt/avdt_msg.cc b/system/stack/avdt/avdt_msg.cc index 9844cd9436366c6d83d7188f1f0f7558a06bdec4..29e566234b459aeb975abe40bad0e08e77821d7c 100644 --- a/system/stack/avdt/avdt_msg.cc +++ b/system/stack/avdt/avdt_msg.cc @@ -33,9 +33,9 @@ #include "avdt_api.h" #include "avdt_int.h" #include "avdtc_api.h" -#include "bt_target.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" @@ -531,7 +531,7 @@ static uint8_t avdt_msg_prs_cfg(AvdtpSepConfig* p_cfg, uint8_t* p, uint16_t len, uint8_t protect_offset = 0; if (!p_cfg) { - AVDT_TRACE_ERROR("not expecting this cfg"); + LOG_ERROR("not expecting this cfg"); return AVDT_ERR_BAD_STATE; } @@ -568,8 +568,8 @@ static uint8_t avdt_msg_prs_cfg(AvdtpSepConfig* p_cfg, uint8_t* p, uint16_t len, { /* Skip unknown categories. */ p += elem_len; - AVDT_TRACE_DEBUG("skipping unknown service category=%d len: %d", elem, - elem_len); + LOG_VERBOSE("skipping unknown service category=%d len: %d", elem, + elem_len); continue; } } @@ -582,8 +582,8 @@ static uint8_t avdt_msg_prs_cfg(AvdtpSepConfig* p_cfg, uint8_t* p, uint16_t len, /* add element to psc mask, but mask out codec or protect */ p_cfg->psc_mask |= (1 << elem); - AVDT_TRACE_DEBUG("elem=%d elem_len: %d psc_mask=0x%x", elem, elem_len, - p_cfg->psc_mask); + LOG_VERBOSE("elem=%d elem_len: %d psc_mask=0x%x", elem, elem_len, + p_cfg->psc_mask); /* parse individual information elements with additional parameters */ switch (elem) { @@ -646,8 +646,7 @@ static uint8_t avdt_msg_prs_cfg(AvdtpSepConfig* p_cfg, uint8_t* p, uint16_t len, break; case AVDT_CAT_DELAY_RPT: - AVDT_TRACE_DEBUG("%s: Remote device supports delay reporting", - __func__); + LOG_VERBOSE("%s: Remote device supports delay reporting", __func__); break; default: @@ -656,8 +655,7 @@ static uint8_t avdt_msg_prs_cfg(AvdtpSepConfig* p_cfg, uint8_t* p, uint16_t len, } /* switch */ } /* while ! err, !end*/ *p_elem = elem; - AVDT_TRACE_DEBUG("err=0x%x, elem:0x%x psc_mask=0x%x", err, elem, - p_cfg->psc_mask); + LOG_VERBOSE("err=0x%x, elem:0x%x psc_mask=0x%x", err, elem, p_cfg->psc_mask); return err; } @@ -791,8 +789,8 @@ static uint8_t avdt_msg_prs_reconfig_cmd(tAVDT_MSG* p_msg, uint8_t* p, /* verify no protocol service capabilities in parameters */ if (!err) { - AVDT_TRACE_DEBUG("avdt_msg_prs_reconfig_cmd psc_mask=0x%x/0x%x", - p_msg->config_cmd.p_cfg->psc_mask, AVDT_MSG_PSC_MASK); + LOG_VERBOSE("avdt_msg_prs_reconfig_cmd psc_mask=0x%x/0x%x", + p_msg->config_cmd.p_cfg->psc_mask, AVDT_MSG_PSC_MASK); if ((p_msg->config_cmd.p_cfg->psc_mask != 0) || (p_msg->config_cmd.p_cfg->num_codec == 0 && p_msg->config_cmd.p_cfg->num_protect == 0)) { @@ -1025,8 +1023,8 @@ static uint8_t avdt_msg_prs_delay_rpt(tAVDT_MSG* p_msg, uint8_t* p, /* verify len */ if (len != AVDT_LEN_DELAY_RPT) { - AVDT_TRACE_WARNING("avdt_msg_prs_delay_rpt expected len: %u got: %u", - AVDT_LEN_DELAY_RPT, len); + LOG_WARN("avdt_msg_prs_delay_rpt expected len: %u got: %u", + AVDT_LEN_DELAY_RPT, len); err = AVDT_ERR_LENGTH; } else { /* get seid */ @@ -1036,8 +1034,8 @@ static uint8_t avdt_msg_prs_delay_rpt(tAVDT_MSG* p_msg, uint8_t* p, err = AVDT_ERR_SEID; } else { BE_STREAM_TO_UINT16(p_msg->delay_rpt_cmd.delay, p); - AVDT_TRACE_DEBUG("avdt_msg_prs_delay_rpt delay: %u", - p_msg->delay_rpt_cmd.delay); + LOG_VERBOSE("avdt_msg_prs_delay_rpt delay: %u", + p_msg->delay_rpt_cmd.delay); } } return err; @@ -1137,7 +1135,7 @@ bool avdt_msg_send(AvdtpCcb* p_ccb, BT_HDR* p_msg) { label = AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_msg->layer_specific); msg = AVDT_LAYERSPEC_MSG(p_ccb->p_curr_msg->layer_specific); sig = (uint8_t)p_ccb->p_curr_msg->event; - AVDT_TRACE_DEBUG("avdt_msg_send label:%d, msg:%d, sig:%d", label, msg, sig); + LOG_VERBOSE("avdt_msg_send label:%d, msg:%d, sig:%d", label, msg, sig); /* keep track of how much of msg we've sent */ curr_msg_len -= p_buf->len; @@ -1220,14 +1218,13 @@ BT_HDR* avdt_msg_asmbl(AvdtpCcb* p_ccb, BT_HDR* p_buf) { /* quick sanity check on length */ if (p_buf->len < avdt_msg_pkt_type_len[pkt_type]) { osi_free(p_buf); - AVDT_TRACE_WARNING("Bad length during reassembly"); + LOG_WARN("Bad length during reassembly"); p_ret = NULL; } /* single packet */ else if (pkt_type == AVDT_PKT_TYPE_SINGLE) { /* if reassembly in progress drop message and process new single */ - if (p_ccb->p_rx_msg != NULL) - AVDT_TRACE_WARNING("Got single during reassembly"); + if (p_ccb->p_rx_msg != NULL) LOG_WARN("Got single during reassembly"); osi_free_and_reset((void**)&p_ccb->p_rx_msg); @@ -1236,8 +1233,7 @@ BT_HDR* avdt_msg_asmbl(AvdtpCcb* p_ccb, BT_HDR* p_buf) { /* start packet */ else if (pkt_type == AVDT_PKT_TYPE_START) { /* if reassembly in progress drop message and process new single */ - if (p_ccb->p_rx_msg != NULL) - AVDT_TRACE_WARNING("Got start during reassembly"); + if (p_ccb->p_rx_msg != NULL) LOG_WARN("Got start during reassembly"); osi_free_and_reset((void**)&p_ccb->p_rx_msg); @@ -1276,7 +1272,7 @@ BT_HDR* avdt_msg_asmbl(AvdtpCcb* p_ccb, BT_HDR* p_buf) { /* if no reassembly in progress drop message */ if (p_ccb->p_rx_msg == NULL) { osi_free(p_buf); - AVDT_TRACE_WARNING("Pkt type=%d out of order", pkt_type); + LOG_WARN("Pkt type=%d out of order", pkt_type); p_ret = NULL; } else { /* get size of buffer holding assembled message */ @@ -1293,7 +1289,7 @@ BT_HDR* avdt_msg_asmbl(AvdtpCcb* p_ccb, BT_HDR* p_buf) { /* verify length */ if (((size_t) p_ccb->p_rx_msg->offset + (size_t) p_buf->len) > buf_len) { /* won't fit; free everything */ - AVDT_TRACE_WARNING("%s: Fragmented message too big!", __func__); + LOG_WARN("%s: Fragmented message too big!", __func__); osi_free_and_reset((void**)&p_ccb->p_rx_msg); osi_free(p_buf); p_ret = NULL; @@ -1452,7 +1448,7 @@ void avdt_msg_send_rej(AvdtpCcb* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) { /* add the error code */ AVDT_MSG_BLD_ERR(p, p_params->hdr.err_code); } - AVDT_TRACE_DEBUG("avdt_msg_send_rej"); + LOG_VERBOSE("avdt_msg_send_rej"); /* calculate length */ p_buf->len = (uint16_t)(p - p_start); @@ -1498,7 +1494,7 @@ void avdt_msg_send_grej(AvdtpCcb* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) { p_buf->event = sig_id; AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_GRJ, p_params->hdr.label); - AVDT_TRACE_DEBUG(__func__); + LOG_VERBOSE("%s", __func__); /* queue message and trigger ccb to send it */ fixed_queue_enqueue(p_ccb->rsp_q, p_buf); @@ -1546,14 +1542,14 @@ void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) { /* parse the message header */ AVDT_MSG_PRS_HDR(p, label, pkt_type, msg_type); - AVDT_TRACE_DEBUG("msg_type=%d, sig=%d", msg_type, sig); + LOG_VERBOSE("msg_type=%d, sig=%d", msg_type, sig); /* set up label and ccb_idx in message hdr */ msg.hdr.label = label; msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb); /* verify msg type */ if (msg_type == AVDT_MSG_TYPE_GRJ) { - AVDT_TRACE_WARNING("Dropping msg msg_type=%d", msg_type); + LOG_WARN("Dropping msg msg_type=%d", msg_type); ok = false; } /* check for general reject */ @@ -1572,7 +1568,7 @@ void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) { AVDT_MSG_PRS_SIG(p, sig); msg.hdr.sig_id = sig; if ((sig == 0) || (sig > AVDT_SIG_MAX)) { - AVDT_TRACE_WARNING("Dropping msg sig=%d msg_type:%d", sig, msg_type); + LOG_WARN("Dropping msg sig=%d msg_type:%d", sig, msg_type); ok = false; /* send a general reject */ @@ -1623,7 +1619,7 @@ void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) { /* if parsing failed */ if (err != 0) { - AVDT_TRACE_WARNING("Parsing failed sig=%d err=0x%x", sig, err); + LOG_WARN("Parsing failed sig=%d err=0x%x", sig, err); /* if its a rsp or rej, drop it; if its a cmd, send a rej; ** note special case for abort; never send abort reject @@ -1655,7 +1651,7 @@ void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) { handle_rsp = true; } else { ok = false; - AVDT_TRACE_WARNING("Cmd not found for rsp sig=%d label=%d", sig, label); + LOG_WARN("Cmd not found for rsp sig=%d label=%d", sig, label); } } } diff --git a/system/stack/avdt/avdt_scb.cc b/system/stack/avdt/avdt_scb.cc index ec3d9deee900d2ce3156a69e6b71ce62e2db9a68..bd0b682295c59666f8ba7c038157d9a954227fe6 100644 --- a/system/stack/avdt/avdt_scb.cc +++ b/system/stack/avdt/avdt_scb.cc @@ -24,10 +24,11 @@ ******************************************************************************/ #include + #include "avdt_api.h" #include "avdt_int.h" #include "avdtc_api.h" -#include "bt_target.h" +#include "internal_include/bt_target.h" #include "osi/include/osi.h" /***************************************************************************** @@ -757,10 +758,10 @@ void avdt_scb_event(AvdtpScb* p_scb, uint8_t event, tAVDT_SCB_EVT* p_data) { uint8_t action; #if (AVDT_DEBUG == TRUE) - AVDT_TRACE_EVENT( - "%s: SCB hdl=%d event=%d/%s state=%s p_avdt_scb=%p scb_index=%d", - __func__, avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event], - avdt_scb_st_str[p_scb->state], p_scb, p_scb->stream_config.scb_index); + LOG_VERBOSE("%s: SCB hdl=%d event=%d/%s state=%s p_avdt_scb=%p scb_index=%d", + __func__, avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event], + avdt_scb_st_str[p_scb->state], p_scb, + p_scb->stream_config.scb_index); #endif /* Check that we only send AVDT_SCB_API_WRITE_REQ_EVT to the active stream @@ -787,7 +788,7 @@ void avdt_scb_event(AvdtpScb* p_scb, uint8_t event, tAVDT_SCB_EVT* p_data) { avdtp_cb.ccb[ccb_index].scb[scb_index].curr_stream = true; } else if (num_st_streams > 1 && !p_scb->curr_stream && event == AVDT_SCB_API_WRITE_REQ_EVT) { - AVDT_TRACE_ERROR("%s: ignore AVDT_SCB_API_WRITE_REQ_EVT", __func__); + LOG_ERROR("%s: ignore AVDT_SCB_API_WRITE_REQ_EVT", __func__); avdt_scb_free_pkt(p_scb, p_data); return; } @@ -853,14 +854,13 @@ AvdtpScb* avdt_scb_alloc(uint8_t peer_id, for (int i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { if (!p_scb->allocated) { p_scb->Allocate(&avdtp_cb.ccb[peer_id], avdtp_stream_config); - AVDT_TRACE_DEBUG("%s: allocated (handle=%d, psc_mask:0x%x)", __func__, - p_scb->ScbHandle(), avdtp_stream_config.cfg.psc_mask); + LOG_VERBOSE("%s: allocated (handle=%d, psc_mask:0x%x)", __func__, + p_scb->ScbHandle(), avdtp_stream_config.cfg.psc_mask); return p_scb; } } - AVDT_TRACE_WARNING("%s: out of AvdtScb entries for peer_id %d", __func__, - peer_id); + LOG_WARN("%s: out of AvdtScb entries for peer_id %d", __func__, peer_id); return nullptr; } @@ -885,7 +885,7 @@ void AvdtpScb::Allocate(AvdtpCcb* p_avdtp_ccb, * ******************************************************************************/ void avdt_scb_dealloc(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) { - AVDT_TRACE_DEBUG("%s: hdl=%d", __func__, avdt_scb_to_hdl(p_scb)); + LOG_VERBOSE("%s: hdl=%d", __func__, avdt_scb_to_hdl(p_scb)); p_scb->Recycle(); } @@ -915,7 +915,7 @@ uint8_t avdt_scb_to_hdl(AvdtpScb* p_scb) { return p_scb->ScbHandle(); } AvdtpScb* avdt_scb_by_hdl(uint8_t hdl) { // Verify the index if ((hdl < 1) || (hdl > AVDT_NUM_LINKS * AVDT_NUM_SEPS)) { - AVDT_TRACE_WARNING("%s: SCB handle %d out of range", __func__, hdl); + LOG_WARN("%s: SCB handle %d out of range", __func__, hdl); return nullptr; } @@ -926,12 +926,12 @@ AvdtpScb* avdt_scb_by_hdl(uint8_t hdl) { AvdtpScb* p_scb = &avdtp_cb.ccb[i].scb[j]; // Verify the whether the scb is allocated if (!p_scb->allocated) { - AVDT_TRACE_WARNING("%s: SCB handle %d not allocated", __func__, hdl); + LOG_WARN("%s: SCB handle %d not allocated", __func__, hdl); return nullptr; } - AVDT_TRACE_DEBUG("%s: SCB for handle %d found: p_scb=%p scb_index=%d", - __func__, hdl, p_scb, p_scb->stream_config.scb_index); + LOG_VERBOSE("%s: SCB for handle %d found: p_scb=%p scb_index=%d", __func__, + hdl, p_scb, p_scb->stream_config.scb_index); return p_scb; } @@ -947,7 +947,7 @@ AvdtpScb* avdt_scb_by_hdl(uint8_t hdl) { ******************************************************************************/ uint8_t avdt_scb_verify(AvdtpCcb* p_ccb, uint8_t state, uint8_t* p_seid, uint16_t num_seid, uint8_t* p_err_code) { - AVDT_TRACE_DEBUG("avdt_scb_verify state %d", state); + LOG_VERBOSE("avdt_scb_verify state %d", state); /* set nonsupported command mask */ /* translate public state into private state */ uint8_t nsc_mask = 0; diff --git a/system/stack/avdt/avdt_scb_act.cc b/system/stack/avdt/avdt_scb_act.cc index d8fa102f22fe41271332929e134b30c962e549ae..9920f016d42f279cf6e26f14f2f12c15bf71ed02 100644 --- a/system/stack/avdt/avdt_scb_act.cc +++ b/system/stack/avdt/avdt_scb_act.cc @@ -30,10 +30,9 @@ #include "a2dp_codec_api.h" #include "avdt_api.h" #include "avdt_int.h" -#include "avdtc_api.h" -#include "bt_target.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" @@ -275,7 +274,7 @@ void avdt_scb_hdl_pkt_no_frag(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { /* do sanity check */ if (pad_len >= (len - offset)) { - AVDT_TRACE_WARNING("Got bad media packet"); + LOG_WARN("Got bad media packet"); osi_free_and_reset((void**)&p_data->p_pkt); } /* adjust offset and length and send it up */ @@ -295,8 +294,8 @@ void avdt_scb_hdl_pkt_no_frag(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { } return; length_error: - AVDT_TRACE_WARNING("%s: hdl packet length %d too short: must be at least %d", - __func__, len, offset); + LOG_WARN("%s: hdl packet length %d too short: must be at least %d", __func__, + len, offset); osi_free_and_reset((void**)&p_data->p_pkt); } @@ -318,14 +317,13 @@ uint8_t* avdt_scb_hdl_report(AvdtpScb* p_scb, uint8_t* p, uint16_t len) { AVDT_REPORT_TYPE pt; tAVDT_REPORT_DATA report; - AVDT_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (p_scb->stream_config.p_report_cback) { /* parse report packet header */ min_len += 8; if (min_len > len) { - AVDT_TRACE_WARNING( - "%s: hdl packet length %d too short: must be at least %d", __func__, - len, min_len); + LOG_WARN("%s: hdl packet length %d too short: must be at least %d", + __func__, len, min_len); goto avdt_scb_hdl_report_exit; } AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc); @@ -337,9 +335,8 @@ uint8_t* avdt_scb_hdl_report(AvdtpScb* p_scb, uint8_t* p, uint16_t len) { case AVDT_RTCP_PT_SR: /* the packet type - SR (Sender Report) */ min_len += 20; if (min_len > len) { - AVDT_TRACE_WARNING( - "%s: hdl packet length %d too short: must be at least %d", - __func__, len, min_len); + LOG_WARN("%s: hdl packet length %d too short: must be at least %d", + __func__, len, min_len); goto avdt_scb_hdl_report_exit; } BE_STREAM_TO_UINT32(report.sr.ntp_sec, p); @@ -352,9 +349,8 @@ uint8_t* avdt_scb_hdl_report(AvdtpScb* p_scb, uint8_t* p, uint16_t len) { case AVDT_RTCP_PT_RR: /* the packet type - RR (Receiver Report) */ min_len += 20; if (min_len > len) { - AVDT_TRACE_WARNING( - "%s: hdl packet length %d too short: must be at least %d", - __func__, len, min_len); + LOG_WARN("%s: hdl packet length %d too short: must be at least %d", + __func__, len, min_len); goto avdt_scb_hdl_report_exit; } report.rr.frag_lost = *p; @@ -370,9 +366,8 @@ uint8_t* avdt_scb_hdl_report(AvdtpScb* p_scb, uint8_t* p, uint16_t len) { uint8_t sdes_type; min_len += 1; if (min_len > len) { - AVDT_TRACE_WARNING( - "%s: hdl packet length %d too short: must be at least %d", - __func__, len, min_len); + LOG_WARN("%s: hdl packet length %d too short: must be at least %d", + __func__, len, min_len); goto avdt_scb_hdl_report_exit; } BE_STREAM_TO_UINT8(sdes_type, p); @@ -380,9 +375,8 @@ uint8_t* avdt_scb_hdl_report(AvdtpScb* p_scb, uint8_t* p, uint16_t len) { uint8_t name_length; min_len += 1; if (min_len > len) { - AVDT_TRACE_WARNING( - "%s: hdl packet length %d too short: must be at least %d", - __func__, len, min_len); + LOG_WARN("%s: hdl packet length %d too short: must be at least %d", + __func__, len, min_len); goto avdt_scb_hdl_report_exit; } BE_STREAM_TO_UINT8(name_length, p); @@ -394,19 +388,18 @@ uint8_t* avdt_scb_hdl_report(AvdtpScb* p_scb, uint8_t* p, uint16_t len) { } } else { if (min_len + 1 > len) { - AVDT_TRACE_WARNING( - "%s: hdl packet length %d too short: must be at least %d", - __func__, len, min_len); + LOG_WARN("%s: hdl packet length %d too short: must be at least %d", + __func__, len, min_len); goto avdt_scb_hdl_report_exit; } - AVDT_TRACE_WARNING("%s: SDES SSRC=0x%08x sc=%d %d len=%d", __func__, - ssrc, o_cc, sdes_type, *p); + LOG_WARN("%s: SDES SSRC=0x%08x sc=%d %d len=%d", __func__, ssrc, o_cc, + sdes_type, *p); result = AVDT_BUSY; } break; default: - AVDT_TRACE_ERROR("Bad Report pkt - packet type: %d", pt); + LOG_ERROR("Bad Report pkt - packet type: %d", pt); result = AVDT_BAD_PARAMS; } @@ -449,7 +442,7 @@ void avdt_scb_hdl_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { * ******************************************************************************/ void avdt_scb_drop_pkt(UNUSED_ATTR AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { - AVDT_TRACE_ERROR("%s dropped incoming media packet", __func__); + LOG_ERROR("%s dropped incoming media packet", __func__); osi_free_and_reset((void**)&p_data->p_pkt); } @@ -567,14 +560,14 @@ void avdt_scb_hdl_security_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { * ******************************************************************************/ void avdt_scb_hdl_setconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { - AVDT_TRACE_DEBUG("%s: p_scb->in_use=%d p_avdt_scb=%p scb_index=%d", __func__, - p_scb->in_use, p_scb, p_scb->stream_config.scb_index); + LOG_VERBOSE("%s: p_scb->in_use=%d p_avdt_scb=%p scb_index=%d", __func__, + p_scb->in_use, p_scb, p_scb->stream_config.scb_index); if (!p_scb->in_use) { - AVDT_TRACE_DEBUG( + LOG_VERBOSE( "%s: codec: %s", __func__, A2DP_CodecInfoString(p_scb->stream_config.cfg.codec_info).c_str()); - AVDT_TRACE_DEBUG( + LOG_VERBOSE( "%s: codec: %s", __func__, A2DP_CodecInfoString(p_data->msg.config_cmd.p_cfg->codec_info).c_str()); AvdtpSepConfig* p_cfg = p_data->msg.config_cmd.p_cfg; @@ -583,7 +576,7 @@ void avdt_scb_hdl_setconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { /* copy info to scb */ AvdtpCcb* p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx); if (p_scb->p_ccb != p_ccb) { - AVDT_TRACE_ERROR( + LOG_ERROR( "%s: mismatch in AVDTP SCB/CCB state: (p_scb->p_ccb=%p != " "p_ccb=%p): " "p_scb=%p scb_handle=%d ccb_idx=%d", @@ -611,7 +604,7 @@ void avdt_scb_hdl_setconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { p_data->msg.hdr.sig_id, &p_data->msg); } } else { - AVDT_TRACE_DEBUG("%s: calling avdt_scb_rej_in_use()", __func__); + LOG_VERBOSE("%s: calling avdt_scb_rej_in_use()", __func__); avdt_scb_rej_in_use(p_scb, p_data); } } @@ -939,9 +932,9 @@ void avdt_scb_hdl_tc_open(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { (p_scb->role == AVDT_OPEN_INT) ? AVDT_OPEN_CFM_EVT : AVDT_OPEN_IND_EVT; p_data->open.hdr.err_code = 0; - AVDT_TRACE_DEBUG("%s: psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x", __func__, - p_scb->stream_config.cfg.psc_mask, p_scb->req_cfg.psc_mask, - p_scb->curr_cfg.psc_mask); + LOG_VERBOSE("%s: psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x", __func__, + p_scb->stream_config.cfg.psc_mask, p_scb->req_cfg.psc_mask, + p_scb->curr_cfg.psc_mask); if (p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) { /* open the reporting channel, if both devices support it */ role = (p_scb->role == AVDT_OPEN_INT) ? AVDT_INT : AVDT_ACP; @@ -1001,7 +994,7 @@ void avdt_scb_hdl_write_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { /* free packet we're holding, if any; to be replaced with new */ if (p_scb->p_pkt != NULL) { /* this shouldn't be happening */ - AVDT_TRACE_WARNING("Dropped media packet; congested"); + LOG_WARN("Dropped media packet; congested"); } osi_free_and_reset((void**)&p_scb->p_pkt); @@ -1049,7 +1042,7 @@ void avdt_scb_snd_abort_req(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) { tAVDT_EVT_HDR hdr; - AVDT_TRACE_DEBUG("%s: p_scb->p_ccb=%p", __func__, p_scb->p_ccb); + LOG_VERBOSE("%s: p_scb->p_ccb=%p", __func__, p_scb->p_ccb); if (p_scb->p_ccb != NULL) { p_scb->role = AVDT_CLOSE_INT; @@ -1213,9 +1206,9 @@ void avdt_scb_snd_open_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { * ******************************************************************************/ void avdt_scb_snd_reconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { - AVDT_TRACE_DEBUG("%s: p_scb->peer_seid=%d p_data->msg.hdr.seid=%d", __func__, - p_scb->peer_seid, p_data->msg.hdr.seid); - AVDT_TRACE_DEBUG( + LOG_VERBOSE("%s: p_scb->peer_seid=%d p_data->msg.hdr.seid=%d", __func__, + p_scb->peer_seid, p_data->msg.hdr.seid); + LOG_VERBOSE( "%s: codec: %s", __func__, A2DP_CodecInfoString(p_data->msg.config_cmd.p_cfg->codec_info).c_str()); @@ -1319,7 +1312,7 @@ void avdt_scb_snd_setconfig_rej(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { * ******************************************************************************/ void avdt_scb_snd_setconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { - AVDT_TRACE_DEBUG( + LOG_VERBOSE( "%s: codec: %s", __func__, A2DP_CodecInfoString(p_data->msg.config_cmd.p_cfg->codec_info).c_str()); @@ -1327,7 +1320,7 @@ void avdt_scb_snd_setconfig_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { AvdtpCcb* p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx); if (p_scb->p_ccb != p_ccb) { - AVDT_TRACE_ERROR( + LOG_ERROR( "%s: mismatch in AVDTP SCB/CCB state: (p_scb->p_ccb=%p != p_ccb=%p): " "p_scb=%p scb_handle=%d ccb_idx=%d", __func__, p_scb->p_ccb, p_ccb, p_scb, p_scb->ScbHandle(), @@ -1501,7 +1494,7 @@ void avdt_scb_free_pkt(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) { osi_free_and_reset((void**)&p_data->apiwrite.p_buf); - AVDT_TRACE_WARNING("Dropped media packet"); + LOG_WARN("Dropped media packet"); /* we need to call callback to keep data flow going */ (*p_scb->stream_config.p_avdt_ctrl_cback)( @@ -1540,7 +1533,7 @@ void avdt_scb_clr_pkt(AvdtpScb* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) { if (p_scb->p_pkt != NULL) { osi_free_and_reset((void**)&p_scb->p_pkt); - AVDT_TRACE_DEBUG("Dropped stored media packet"); + LOG_VERBOSE("Dropped stored media packet"); /* we need to call callback to keep data flow going */ (*p_scb->stream_config.p_avdt_ctrl_cback)( diff --git a/system/stack/avrc/avrc_api.cc b/system/stack/avrc/avrc_api.cc index fff1b150d88cd9bc537b0e52a5009dcef472a32d..1f71c31b3f395e40910856cac0d196d86d2a5cb5 100644 --- a/system/stack/avrc/avrc_api.cc +++ b/system/stack/avrc/avrc_api.cc @@ -23,20 +23,21 @@ ******************************************************************************/ #include "avrc_api.h" -#ifdef __ANDROID__ -#include -#endif +#include #include #include #include "avrc_int.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/log.h" -#include "osi/include/osi.h" #include "osi/include/properties.h" +#include "stack/avct/avct_defs.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "types/raw_address.h" /***************************************************************************** @@ -88,13 +89,7 @@ static const uint8_t avrc_ctrl_event_map[] = { * *****************************************************************************/ bool avrcp_absolute_volume_is_enabled() { -#ifdef __ANDROID__ - static const bool absolute_volume = - android::sysprop::bluetooth::Avrcp::absolute_volume().value_or(true); - return absolute_volume; -#else - return true; -#endif + return GET_SYSPROP(Avrcp, absolute_volume, true); } /****************************************************************************** @@ -138,7 +133,7 @@ static void avrc_ctrl_cback(uint8_t handle, uint8_t event, uint16_t result, * *****************************************************************************/ void avrc_flush_cmd_q(uint8_t handle) { - AVRC_TRACE_DEBUG("AVRC: Flushing command queue for handle=0x%02x", handle); + LOG_VERBOSE("AVRC: Flushing command queue for handle=0x%02x", handle); avrc_cb.ccb_int[handle].flags &= ~AVRC_CB_FLAGS_RSP_PENDING; alarm_cancel(avrc_cb.ccb_int[handle].tle); @@ -158,8 +153,8 @@ void avrc_flush_cmd_q(uint8_t handle) { void avrc_process_timeout(void* data) { tAVRC_PARAM* param = (tAVRC_PARAM*)data; - AVRC_TRACE_DEBUG("AVRC: command timeout (handle=0x%02x, label=0x%02x)", - param->handle, param->label); + LOG_VERBOSE("AVRC: command timeout (handle=0x%02x, label=0x%02x)", + param->handle, param->label); /* Notify app */ if (avrc_cb.ccb[param->handle].ctrl_cback) { @@ -193,9 +188,8 @@ void avrc_send_next_vendor_cmd(uint8_t handle) { next_label = (p_next_cmd->layer_specific) >> 8; /* extract label */ p_next_cmd->layer_specific &= 0xFF; /* AVCT_DATA_CTRL or AVCT_DATA_BROWSE */ - AVRC_TRACE_DEBUG( - "AVRC: Dequeuing command 0x%08x (handle=0x%02x, label=0x%02x)", - p_next_cmd, handle, next_label); + LOG_VERBOSE("AVRC: Dequeuing command 0x%p (handle=0x%02x, label=0x%02x)", + p_next_cmd, handle, next_label); /* Send the message */ if ((AVCT_MsgReq(handle, next_label, AVCT_CMD, p_next_cmd)) == @@ -228,8 +222,8 @@ void avrc_start_cmd_timer(uint8_t handle, uint8_t label, uint8_t msg_mask) { param->label = label; param->msg_mask = msg_mask; - AVRC_TRACE_DEBUG("AVRC: starting timer (handle=0x%02x, label=0x%02x)", handle, - label); + LOG_VERBOSE("AVRC: starting timer (handle=0x%02x, label=0x%02x)", handle, + label); alarm_set_on_mloop(avrc_cb.ccb_int[handle].tle, AVRC_CMD_TOUT_MS, avrc_process_timeout, param); @@ -288,7 +282,7 @@ static void avrc_prep_end_frag(uint8_t handle) { uint8_t *p_data, *p_orig_data; uint8_t rsp_type; - AVRC_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); p_fcb = &avrc_cb.fcb[handle]; /* The response type of the end fragment should be the same as the the PDU of @@ -335,8 +329,8 @@ static uint16_t avrc_send_continue_frag(uint8_t handle, uint8_t label) { p_fcb = &avrc_cb.fcb[handle]; p_pkt = p_fcb->p_fmsg; - AVRC_TRACE_DEBUG("%s handle = %u label = %u len = %d", __func__, handle, - label, p_pkt->len); + LOG_VERBOSE("%s handle = %u label = %u len = %d", __func__, handle, label, + p_pkt->len); if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) { int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset); p_pkt_old = p_fcb->p_fmsg; @@ -392,7 +386,7 @@ static BT_HDR* avrc_proc_vendor_command(uint8_t handle, uint8_t label, if (pkt_type != AVRC_PKT_SINGLE) { /* reject - commands can only be in single packets at AVRCP level */ - AVRC_TRACE_ERROR("commands must be in single packet pdu:0x%x", *p_data); + LOG_ERROR("commands must be in single packet pdu:0x%x", *p_data); /* use the current GKI buffer to send the reject */ status = AVRC_STS_BAD_CMD; } @@ -426,7 +420,7 @@ static BT_HDR* avrc_proc_vendor_command(uint8_t handle, uint8_t label, } else { /* the pdu id does not match - reject the command using the current * GKI buffer */ - AVRC_TRACE_ERROR( + LOG_ERROR( "%s continue pdu: 0x%x does not match the current pdu: 0x%x", __func__, *(p_data + 4), p_fcb->frag_pdu); status = AVRC_STS_BAD_PARAM; @@ -495,7 +489,7 @@ static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr, p_data += AVRC_VENDOR_HDR_SIZE; pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK; - AVRC_TRACE_DEBUG("pkt_type %d", pkt_type); + LOG_VERBOSE("pkt_type %d", pkt_type); p_rcb = &avrc_cb.rcb[handle]; /* check if the message needs to be re-assembled */ @@ -538,9 +532,9 @@ static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr, } else if (p_rcb->p_rmsg == NULL) { /* Received a CONTINUE/END, but no corresponding START (or previous fragmented response was dropped) */ - AVRC_TRACE_DEBUG( - "Received a CONTINUE/END without no corresponding START \ - (or previous fragmented response was dropped)"); + LOG_VERBOSE( + "Received a CONTINUE/END without no corresponding START" + " (or previous fragmented response was dropped)"); drop_code = 5; osi_free(p_pkt); *pp_pkt = NULL; @@ -556,8 +550,7 @@ static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr, p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE); /* verify length */ if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len) { - AVRC_TRACE_WARNING( - "Fragmented message too big! - report the partial message"); + LOG_WARN("Fragmented message too big! - report the partial message"); p_pkt->len = buf_len - p_rcb->p_rmsg->offset; pkt_type = AVRC_PKT_END; buf_overflow = true; @@ -582,8 +575,8 @@ static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr, *p_data++ = AVRC_PKT_SINGLE; UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE)); - AVRC_TRACE_DEBUG("end frag:%d, total len:%d, offset:%d", p_pkt->len, - p_pkt_new->len, p_pkt_new->offset); + LOG_VERBOSE("end frag:%d, total len:%d, offset:%d", p_pkt->len, + p_pkt_new->len, p_pkt_new->offset); } else { p_rcb->p_rmsg->offset += p_pkt->len; p_rcb->p_rmsg->len += p_pkt->len; @@ -626,7 +619,7 @@ static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr, avrc_command.continu = avrc_cmd; status = AVRC_BldCommand(&avrc_command, &p_cmd); if (status == AVRC_STS_NO_ERROR) { - AVRC_MsgReq(handle, (uint8_t)(label), AVRC_CMD_CTRL, p_cmd); + AVRC_MsgReq(handle, (uint8_t)(label), AVRC_CMD_CTRL, p_cmd, false); } } @@ -660,8 +653,8 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr, if (cr == AVCT_CMD && (p_pkt->layer_specific & AVCT_DATA_CTRL && p_pkt->len > AVRC_PACKET_LEN)) { - AVRC_TRACE_WARNING("%s: Command length %d too long: must be at most %d", - __func__, p_pkt->len, AVRC_PACKET_LEN); + LOG_WARN("%s: Command length %d too long: must be at most %d", __func__, + p_pkt->len, AVRC_PACKET_LEN); osi_free(p_pkt); return; } @@ -674,7 +667,7 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr, return; } else if (cr == AVCT_RSP) { /* Received response. Stop command timeout timer */ - AVRC_TRACE_DEBUG("AVRC: stopping timer (handle=0x%02x)", handle); + LOG_VERBOSE("AVRC: stopping timer (handle=0x%02x)", handle); alarm_cancel(avrc_cb.ccb_int[handle].tle); } @@ -689,14 +682,14 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr, msg.browse.p_browse_pkt = p_pkt; } else { if (p_pkt->len < AVRC_AVC_HDR_SIZE) { - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d", - __func__, p_pkt->len, AVRC_AVC_HDR_SIZE); + LOG_WARN("%s: message length %d too short: must be at least %d", __func__, + p_pkt->len, AVRC_AVC_HDR_SIZE); osi_free(p_pkt); return; } msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK; - AVRC_TRACE_DEBUG("%s handle:%d, ctype:%d, offset:%d, len: %d", __func__, - handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len); + LOG_VERBOSE("%s handle:%d, ctype:%d, offset:%d, len: %d", __func__, handle, + msg.hdr.ctype, p_pkt->offset, p_pkt->len); msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT; msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK; @@ -728,9 +721,8 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr, } else { /* parse response */ if (p_pkt->len < AVRC_OP_UNIT_INFO_RSP_LEN) { - AVRC_TRACE_WARNING( - "%s: message length %d too short: must be at least %d", - __func__, p_pkt->len, AVRC_OP_UNIT_INFO_RSP_LEN); + LOG_WARN("%s: message length %d too short: must be at least %d", + __func__, p_pkt->len, AVRC_OP_UNIT_INFO_RSP_LEN); drop = true; p_drop_msg = "UNIT_INFO_RSP too short"; break; @@ -765,9 +757,8 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr, } else { /* parse response */ if (p_pkt->len < AVRC_OP_SUB_UNIT_INFO_RSP_LEN) { - AVRC_TRACE_WARNING( - "%s: message length %d too short: must be at least %d", - __func__, p_pkt->len, AVRC_OP_SUB_UNIT_INFO_RSP_LEN); + LOG_WARN("%s: message length %d too short: must be at least %d", + __func__, p_pkt->len, AVRC_OP_SUB_UNIT_INFO_RSP_LEN); drop = true; p_drop_msg = "SUB_UNIT_INFO_RSP too short"; break; @@ -912,9 +903,8 @@ static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr, msg.hdr.opcode = opcode; avrc_cb.ccb[handle].msg_cback.Run(handle, label, opcode, &msg); } else { - AVRC_TRACE_WARNING("%s %s msg handle:%d, control:%d, cr:%d, opcode:x%x", - __func__, p_drop_msg, handle, - avrc_cb.ccb[handle].control, cr, opcode); + LOG_WARN("%s %s msg handle:%d, control:%d, cr:%d, opcode:x%x", __func__, + p_drop_msg, handle, avrc_cb.ccb[handle].control, cr, opcode); } if (opcode == AVRC_OP_BROWSE && msg.browse.p_browse_pkt == NULL) { @@ -1098,8 +1088,8 @@ uint16_t AVRC_Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb, avrc_cb.ccb_int[*p_handle].tle = alarm_new("avrcp.commandTimer"); avrc_cb.ccb_int[*p_handle].cmd_q = fixed_queue_new(SIZE_MAX); } - AVRC_TRACE_DEBUG("%s role: %d, control:%d status:%d, handle:%d", __func__, - cc.role, cc.control, status, *p_handle); + LOG_VERBOSE("%s role: %d, control:%d status:%d, handle:%d", __func__, cc.role, + cc.control, status, *p_handle); return status; } @@ -1123,7 +1113,7 @@ uint16_t AVRC_Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb, * *****************************************************************************/ uint16_t AVRC_Close(uint8_t handle) { - AVRC_TRACE_DEBUG("%s handle:%d", __func__, handle); + LOG_VERBOSE("%s handle:%d", __func__, handle); avrc_flush_cmd_q(handle); return AVCT_RemoveConn(handle); } @@ -1179,8 +1169,9 @@ uint16_t AVRC_CloseBrowse(uint8_t handle) { return AVCT_RemoveBrowse(handle); } * AVRC_BAD_HANDLE if handle is invalid. * *****************************************************************************/ +/* legacy and new avrcp send the different packet format for VENDOR op */ uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, - BT_HDR* p_pkt) { + BT_HDR* p_pkt, bool is_new_avrcp) { uint8_t* p_data; uint8_t cr = AVCT_CMD; bool chk_frag = true; @@ -1193,10 +1184,12 @@ uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, if (!p_pkt) return AVRC_BAD_PARAM; - AVRC_TRACE_DEBUG("%s handle = %u label = %u ctype = %u len = %d", __func__, - handle, label, ctype, p_pkt->len); + LOG_VERBOSE("%s handle = %u label = %u ctype = %u len = %d", __func__, handle, + label, ctype, p_pkt->len); /* Handle for AVRCP fragment */ - bool is_new_avrcp = osi_property_get_bool("bluetooth.profile.avrcp.target.enabled", false); + if (!GET_SYSPROP(A2dp, src_sink_coexist, false)) + is_new_avrcp = + osi_property_get_bool("bluetooth.profile.avrcp.target.enabled", false); if (ctype >= AVRC_RSP_NOT_IMPL) cr = AVCT_RSP; if (p_pkt->event == AVRC_OP_VENDOR) { @@ -1243,9 +1236,8 @@ uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, peer_mtu = AVCT_GetPeerMtu(handle); } if (p_pkt->len > (peer_mtu - AVCT_HDR_LEN_SINGLE)) { - AVRC_TRACE_ERROR( - "%s bigger than peer mtu (p_pkt->len(%d) > peer_mtu(%d-%d))", - __func__, p_pkt->len, peer_mtu, AVCT_HDR_LEN_SINGLE); + LOG_ERROR("%s bigger than peer mtu (p_pkt->len(%d) > peer_mtu(%d-%d))", + __func__, p_pkt->len, peer_mtu, AVCT_HDR_LEN_SINGLE); osi_free(p_pkt); return AVRC_MSG_TOO_BIG; } @@ -1255,7 +1247,7 @@ uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, p_fcb = &avrc_cb.fcb[handle]; if (p_fcb == NULL) { - AVRC_TRACE_ERROR("%s p_fcb is NULL", __func__); + LOG_ERROR("%s p_fcb is NULL", __func__); osi_free(p_pkt); return AVRC_NOT_OPEN; } @@ -1297,11 +1289,11 @@ uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, /* prepare the left over for as an end fragment */ avrc_prep_end_frag(handle); - AVRC_TRACE_DEBUG("%s p_pkt len:%d/%d, next len:%d", __func__, - p_pkt->len, len, p_fcb->p_fmsg->len); + LOG_VERBOSE("%s p_pkt len:%d/%d, next len:%d", __func__, p_pkt->len, + len, p_fcb->p_fmsg->len); } else { /* TODO: Is this "else" block valid? Remove it? */ - AVRC_TRACE_ERROR("%s no buffers for fragmentation", __func__); + LOG_ERROR("%s no buffers for fragmentation", __func__); osi_free(p_pkt); return AVRC_NO_RESOURCES; } @@ -1315,9 +1307,8 @@ uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, * command * is received (exception is continuation request command * must sent that to get additional response frags) */ - AVRC_TRACE_DEBUG( - "AVRC: Enqueuing command 0x%08x (handle=0x%02x, label=0x%02x)", p_pkt, - handle, label); + LOG_VERBOSE("AVRC: Enqueuing command 0x%p (handle=0x%02x, label=0x%02x)", + p_pkt, handle, label); /* label in BT_HDR (will need this later when the command is dequeued) */ p_pkt->layer_specific = (label << 8) | (p_pkt->layer_specific & 0xFF); @@ -1455,3 +1446,12 @@ void AVRC_SaveControllerVersion(const RawAddress& bdaddr, ADDRESS_TO_LOGGABLE_CSTR(bdaddr)); } } + +void AVRC_UpdateCcb(RawAddress* addr, uint32_t company_id) { + for (uint8_t i = 0; i < AVCT_NUM_CONN; i++) { + LOG_INFO("%s: handle:%d, update cback:0x%0x", __func__, i, company_id); + if (avrc_cb.ccb[i].company_id == company_id) { + avrc_cb.ccb[i].ctrl_cback.Run(i, AVRC_CLOSE_IND_EVT, 0, addr); + } + } +} diff --git a/system/stack/avrc/avrc_bld_ct.cc b/system/stack/avrc/avrc_bld_ct.cc index 5eb5d3b0676e0bb2adf5b4352ba0d03e6a2f8b52..8ac25692cfb018acbb1d0ba4c16d8d678d23fff1 100644 --- a/system/stack/avrc/avrc_bld_ct.cc +++ b/system/stack/avrc/avrc_bld_ct.cc @@ -15,13 +15,19 @@ * limitations under the License. * ******************************************************************************/ + +#define LOG_TAG "avrcp" + #include #include "avrc_api.h" #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" /***************************************************************************** * Global data @@ -40,7 +46,7 @@ static tAVRC_STS avrc_bld_next_cmd(tAVRC_NEXT_CMD* p_cmd, BT_HDR* p_pkt) { uint8_t *p_data, *p_start; - AVRC_TRACE_API("avrc_bld_next_cmd"); + LOG_VERBOSE("avrc_bld_next_cmd"); /* get the existing length, if any, and also the num attributes */ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; @@ -72,7 +78,7 @@ static tAVRC_STS avrc_bld_set_abs_volume_cmd(tAVRC_SET_VOLUME_CMD* p_cmd, BT_HDR* p_pkt) { uint8_t *p_data, *p_start; - AVRC_TRACE_API("avrc_bld_set_abs_volume_cmd"); + LOG_VERBOSE("avrc_bld_set_abs_volume_cmd"); /* get the existing length, if any, and also the num attributes */ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_start + 2; /* pdu + rsvd */ @@ -97,7 +103,7 @@ static tAVRC_STS avrc_bld_register_notifn(BT_HDR* p_pkt, uint8_t event_id, uint32_t event_param) { uint8_t *p_data, *p_start; - AVRC_TRACE_API("avrc_bld_register_notifn"); + LOG_VERBOSE("avrc_bld_register_notifn"); /* get the existing length, if any, and also the num attributes */ // Set the notify value p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; @@ -121,7 +127,7 @@ static tAVRC_STS avrc_bld_register_notifn(BT_HDR* p_pkt, uint8_t event_id, * ******************************************************************************/ static tAVRC_STS avrc_bld_get_capability_cmd(BT_HDR* p_pkt, uint8_t cap_id) { - AVRC_TRACE_API("avrc_bld_get_capability_cmd"); + LOG_VERBOSE("avrc_bld_get_capability_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ /* add fixed length 1 -*/ @@ -142,7 +148,7 @@ static tAVRC_STS avrc_bld_get_capability_cmd(BT_HDR* p_pkt, uint8_t cap_id) { * ******************************************************************************/ static tAVRC_STS avrc_bld_list_player_app_attr_cmd(BT_HDR* p_pkt) { - AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd"); + LOG_VERBOSE("avrc_bld_list_player_app_attr_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ /* add fixed length 1 -*/ @@ -163,7 +169,7 @@ static tAVRC_STS avrc_bld_list_player_app_attr_cmd(BT_HDR* p_pkt) { ******************************************************************************/ static tAVRC_STS avrc_bld_list_player_app_values_cmd(BT_HDR* p_pkt, uint8_t attrib_id) { - AVRC_TRACE_API("avrc_bld_list_player_app_values_cmd"); + LOG_VERBOSE("avrc_bld_list_player_app_values_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ /* add fixed length 1 -*/ @@ -186,7 +192,7 @@ static tAVRC_STS avrc_bld_list_player_app_values_cmd(BT_HDR* p_pkt, ******************************************************************************/ static tAVRC_STS avrc_bld_get_current_player_app_values_cmd( BT_HDR* p_pkt, uint8_t num_attrib_id, uint8_t* attrib_ids) { - AVRC_TRACE_API("avrc_bld_get_current_player_app_values_cmd"); + LOG_VERBOSE("avrc_bld_get_current_player_app_values_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ uint8_t param_len = @@ -214,7 +220,7 @@ static tAVRC_STS avrc_bld_get_current_player_app_values_cmd( ******************************************************************************/ static tAVRC_STS avrc_bld_set_current_player_app_values_cmd( BT_HDR* p_pkt, uint8_t num_attrib_id, tAVRC_APP_SETTING* p_val) { - AVRC_TRACE_API("avrc_bld_set_current_player_app_values_cmd"); + LOG_VERBOSE("avrc_bld_set_current_player_app_values_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ /* we have to store attrib- value pair @@ -245,7 +251,7 @@ static tAVRC_STS avrc_bld_set_current_player_app_values_cmd( ******************************************************************************/ static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd( BT_HDR* p_pkt, tAVRC_GET_APP_ATTR_TXT_CMD* p_cmd) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ @@ -274,7 +280,7 @@ static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd( ******************************************************************************/ static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd( BT_HDR* p_pkt, tAVRC_GET_APP_VAL_TXT_CMD* p_cmd) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ @@ -303,7 +309,7 @@ static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd( static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR* p_pkt, uint8_t num_attrib, uint32_t* attrib_ids) { - AVRC_TRACE_API("avrc_bld_get_element_attr_cmd"); + LOG_VERBOSE("avrc_bld_get_element_attr_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ /* we have to store attrib- value pair @@ -335,7 +341,7 @@ static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR* p_pkt, ******************************************************************************/ static tAVRC_STS avrc_bld_play_item_cmd(BT_HDR* p_pkt, uint8_t scope, uint8_t* uid, uint16_t uid_counter) { - AVRC_TRACE_API("avrc_bld_get_element_attr_cmd"); + LOG_VERBOSE("avrc_bld_get_element_attr_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ /* add fixed length 11 */ @@ -361,7 +367,7 @@ static tAVRC_STS avrc_bld_play_item_cmd(BT_HDR* p_pkt, uint8_t scope, * ******************************************************************************/ static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR* p_pkt) { - AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd"); + LOG_VERBOSE("avrc_bld_list_player_app_attr_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ /* add fixed length 0 -*/ @@ -382,7 +388,7 @@ static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR* p_pkt) { ******************************************************************************/ static tAVRC_STS avrc_bld_get_folder_items_cmd(BT_HDR* p_pkt, const tAVRC_GET_ITEMS_CMD* cmd) { - AVRC_TRACE_API( + LOG_VERBOSE( "avrc_bld_get_folder_items_cmd scope %d, start_item %d, end_item %d", cmd->scope, cmd->start_item, cmd->end_item); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; @@ -414,7 +420,7 @@ static tAVRC_STS avrc_bld_get_folder_items_cmd(BT_HDR* p_pkt, ******************************************************************************/ static tAVRC_STS avrc_bld_change_folder_cmd(BT_HDR* p_pkt, const tAVRC_CHG_PATH_CMD* cmd) { - AVRC_TRACE_API("avrc_bld_change_folder_cmd"); + LOG_VERBOSE("avrc_bld_change_folder_cmd"); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; /* This is where the PDU specific for AVRC starts * AVRCP Spec 1.4 section 22.19 */ @@ -432,7 +438,7 @@ static tAVRC_STS avrc_bld_change_folder_cmd(BT_HDR* p_pkt, } static tAVRC_STS avrc_bld_get_item_attributes_cmd( BT_HDR* p_pkt, const tAVRC_GET_ATTRS_CMD* cmd) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; /* This is where the PDU specific for AVRC starts * AVRCP Spec 1.4 section 22.19 */ @@ -460,7 +466,7 @@ static tAVRC_STS avrc_bld_get_item_attributes_cmd( ******************************************************************************/ static tAVRC_STS avrc_bld_set_browsed_player_cmd( BT_HDR* p_pkt, const tAVRC_SET_BR_PLAYER_CMD* cmd) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; /* This is where the PDU specific for AVRC starts * AVRCP Spec 1.4 section 22.19 */ @@ -487,7 +493,7 @@ static tAVRC_STS avrc_bld_set_browsed_player_cmd( ******************************************************************************/ static tAVRC_STS avrc_bld_set_addressed_player_cmd( BT_HDR* p_pkt, const tAVRC_SET_ADDR_PLAYER_CMD* cmd) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* get the existing length, if any, and also the num attributes */ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; uint8_t* p_data = p_start + 2; /* pdu + rsvd */ @@ -515,8 +521,8 @@ static tAVRC_STS avrc_bld_set_addressed_player_cmd( static BT_HDR* avrc_bld_init_cmd_buffer(tAVRC_COMMAND* p_cmd) { uint16_t chnl = AVCT_DATA_CTRL; uint8_t opcode = avrc_opcode_from_pdu(p_cmd->pdu); - AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, - opcode); + LOG_VERBOSE("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, + opcode); uint16_t offset = 0; switch (opcode) { @@ -577,10 +583,10 @@ static BT_HDR* avrc_bld_init_cmd_buffer(tAVRC_COMMAND* p_cmd) { tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { tAVRC_STS status = AVRC_STS_BAD_PARAM; bool alloc = false; - AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, - p_cmd->cmd.status); + LOG_VERBOSE("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, + p_cmd->cmd.status); if (!p_cmd || !pp_pkt) { - AVRC_TRACE_API( + LOG_VERBOSE( "AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p", p_cmd, pp_pkt); return AVRC_STS_BAD_PARAM; @@ -589,7 +595,7 @@ tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { if (*pp_pkt == NULL) { *pp_pkt = avrc_bld_init_cmd_buffer(p_cmd); if (*pp_pkt == NULL) { - AVRC_TRACE_API("AVRC_BldCommand: Failed to initialize command buffer"); + LOG_VERBOSE("AVRC_BldCommand: Failed to initialize command buffer"); return AVRC_STS_INTERNAL_ERR; } alloc = true; @@ -678,6 +684,6 @@ tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { osi_free(p_pkt); *pp_pkt = NULL; } - AVRC_TRACE_API("AVRC_BldCommand: returning %d", status); + LOG_VERBOSE("AVRC_BldCommand: returning %d", status); return status; } diff --git a/system/stack/avrc/avrc_bld_tg.cc b/system/stack/avrc/avrc_bld_tg.cc index 3c01ee756a70ee017ea56f13652b36b35d1ee349..6ce63765974656b4e8d36534232a923a9bbab3de 100644 --- a/system/stack/avrc/avrc_bld_tg.cc +++ b/system/stack/avrc/avrc_bld_tg.cc @@ -15,15 +15,21 @@ * limitations under the License. * ******************************************************************************/ +#define LOG_TAG "avrcp" + #include #include #include "avrc_api.h" #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" /***************************************************************************** * Global data @@ -58,12 +64,12 @@ static tAVRC_STS avrc_bld_get_capability_rsp(tAVRC_GET_CAPS_RSP* p_rsp, tAVRC_STS status = AVRC_STS_NO_ERROR; if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id))) { - AVRC_TRACE_ERROR("%s bad parameter. p_rsp: %x", __func__, p_rsp); + LOG_ERROR("%s bad parameter. p_rsp: %p", __func__, p_rsp); status = AVRC_STS_BAD_PARAM; return status; } - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* get the existing length, if any, and also the num attributes */ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ @@ -122,7 +128,7 @@ static tAVRC_STS avrc_bld_list_app_settings_attr_rsp( uint16_t len = 0; uint8_t xx; - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* get the existing length, if any, and also the num attributes */ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ @@ -168,7 +174,7 @@ static tAVRC_STS avrc_bld_list_app_settings_values_rsp( uint8_t xx; uint16_t len; - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ @@ -213,11 +219,11 @@ static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp( uint8_t xx; if (!p_rsp->p_vals) { - AVRC_TRACE_ERROR("%s NULL parameter", __func__); + LOG_ERROR("%s NULL parameter", __func__); return AVRC_STS_BAD_PARAM; } - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* get the existing length, if any, and also the num attributes */ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ @@ -261,7 +267,7 @@ static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp( static tAVRC_STS avrc_bld_set_app_setting_value_rsp( UNUSED_ATTR tAVRC_RSP* p_rsp, UNUSED_ATTR BT_HDR* p_pkt) { /* nothing to be added. */ - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return AVRC_STS_NO_ERROR; } @@ -285,7 +291,7 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp( uint8_t num_added = 0; if (!p_rsp->p_attrs) { - AVRC_TRACE_ERROR("%s NULL parameter", __func__); + LOG_ERROR("%s NULL parameter", __func__); return AVRC_STS_BAD_PARAM; } /* get the existing length, if any, and also the num attributes */ @@ -310,14 +316,14 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp( for (xx = 0; xx < p_rsp->num_attr; xx++) { if (len_left < (p_rsp->p_attrs[xx].str_len + 4)) { - AVRC_TRACE_ERROR("%s out of room (str_len:%d, left:%d)", __func__, xx, - p_rsp->p_attrs[xx].str_len, len_left); + LOG_ERROR("%s out of room (str_len:%d, left:%d)", __func__, + p_rsp->p_attrs[xx].str_len, len_left); p_rsp->num_attr = num_added; sts = AVRC_STS_INTERNAL_ERR; break; } if (!p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str) { - AVRC_TRACE_ERROR("%s NULL attr text[%d]", __func__, xx); + LOG_ERROR("%s NULL attr text[%d]", __func__, xx); continue; } UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id); @@ -348,7 +354,7 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp( ******************************************************************************/ static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp( tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp, BT_HDR* p_pkt) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt); } @@ -365,7 +371,7 @@ static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp( ******************************************************************************/ static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp( tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp, BT_HDR* p_pkt) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt); } @@ -383,7 +389,7 @@ static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp( static tAVRC_STS avrc_bld_inform_charset_rsp(UNUSED_ATTR tAVRC_RSP* p_rsp, UNUSED_ATTR BT_HDR* p_pkt) { /* nothing to be added. */ - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return AVRC_STS_NO_ERROR; } @@ -401,7 +407,7 @@ static tAVRC_STS avrc_bld_inform_charset_rsp(UNUSED_ATTR tAVRC_RSP* p_rsp, static tAVRC_STS avrc_bld_inform_battery_status_rsp( UNUSED_ATTR tAVRC_RSP* p_rsp, UNUSED_ATTR BT_HDR* p_pkt) { /* nothing to be added. */ - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return AVRC_STS_NO_ERROR; } @@ -410,13 +416,12 @@ static void avrc_build_attribute_entries(int num_attrs, int remaining_buffer_capacity, uint8_t** pp_data, uint8_t* p_attribute_count) { - AVRC_TRACE_DEBUG("%s num_attrs: %d, remaining_buffer_capacity: %d", __func__, - num_attrs, remaining_buffer_capacity); + LOG_VERBOSE("%s num_attrs: %d, remaining_buffer_capacity: %d", __func__, + num_attrs, remaining_buffer_capacity); uint8_t* p_data = *pp_data; /* Fill in the Attribute ID, Character Set, Length and Values */ for (int index = 0; index < num_attrs; index++) { - AVRC_TRACE_DEBUG("%s attr id[%d]: %d", __func__, index, - p_attrs[index].attr_id); + LOG_VERBOSE("%s attr id[%d]: %d", __func__, index, p_attrs[index].attr_id); CHECK(AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attrs[index].attr_id)); if (!p_attrs[index].name.p_str) { p_attrs[index].name.str_len = 0; @@ -424,14 +429,14 @@ static void avrc_build_attribute_entries(int num_attrs, /* 8 is the size of attr_id, char set and str_len */ remaining_buffer_capacity -= 8; if (remaining_buffer_capacity < 0) { - AVRC_TRACE_WARNING( + LOG_WARN( "%s not enough buffer space for attr_id[%d]: %d," " skipping %d attributes", __func__, index, p_attrs[index].attr_id, num_attrs - index); break; } if (remaining_buffer_capacity < p_attrs[index].name.str_len) { - AVRC_TRACE_WARNING( + LOG_WARN( "%s not enough buffer space for attr_id[%d]: %d," " truncating attribute", __func__, index, p_attrs[index].attr_id); @@ -447,8 +452,8 @@ static void avrc_build_attribute_entries(int num_attrs, (*p_attribute_count)++; } *pp_data = p_data; - AVRC_TRACE_DEBUG("%s filled attributes, remaining_buffer_capacity: %d", - __func__, num_attrs, remaining_buffer_capacity); + LOG_VERBOSE("%s filled attributes, remaining_buffer_capacity: %d", __func__, + remaining_buffer_capacity); } /******************************************************************************* @@ -464,17 +469,17 @@ static void avrc_build_attribute_entries(int num_attrs, ******************************************************************************/ static tAVRC_STS avrc_bld_get_elem_attrs_rsp(tAVRC_GET_ATTRS_RSP* p_rsp, BT_HDR* p_pkt) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!p_rsp->p_attrs) { - AVRC_TRACE_ERROR("%s NULL p_attrs", __func__); + LOG_ERROR("%s NULL p_attrs", __func__); return AVRC_STS_BAD_PARAM; } /* Figure out how much we have left in current buffer */ int remaining_buffer_capacity = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE - p_pkt->offset; if (remaining_buffer_capacity < 5) { - AVRC_TRACE_ERROR("%s not enough buffer for packet header", - remaining_buffer_capacity); + LOG_ERROR("%d not enough buffer for packet header", + remaining_buffer_capacity); return AVRC_STS_INTERNAL_ERR; } /* Get to the beginning of PDU */ @@ -498,7 +503,7 @@ static tAVRC_STS avrc_bld_get_elem_attrs_rsp(tAVRC_GET_ATTRS_RSP* p_rsp, remaining_buffer_capacity -= p_data - p_pdu_start; ; if (remaining_buffer_capacity < 0) { - AVRC_TRACE_ERROR("%s not enough buffer capacity for response"); + LOG_ERROR("%s not enough buffer capacity for response", __func__); return AVRC_STS_BAD_PARAM; } /* Fill in the Attribute ID, Character Set, Length and Values */ @@ -526,7 +531,7 @@ static tAVRC_STS avrc_bld_get_play_status_rsp(tAVRC_GET_PLAY_STATUS_RSP* p_rsp, BT_HDR* p_pkt) { uint8_t *p_data, *p_start; - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_start + 2; @@ -558,7 +563,7 @@ static tAVRC_STS avrc_bld_notify_rsp(tAVRC_REG_NOTIF_RSP* p_rsp, uint8_t xx; tAVRC_STS status = AVRC_STS_NO_ERROR; - AVRC_TRACE_API("%s event_id %d", __func__, p_rsp->event_id); + LOG_VERBOSE("%s event_id %d", __func__, p_rsp->event_id); p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 2; /* pdu + rsvd */ @@ -573,7 +578,7 @@ static tAVRC_STS avrc_bld_notify_rsp(tAVRC_REG_NOTIF_RSP* p_rsp, UINT8_TO_BE_STREAM(p_data, p_rsp->param.play_status); len = 2; } else { - AVRC_TRACE_ERROR("%s bad play state", __func__); + LOG_ERROR("%s bad play state", __func__); status = AVRC_STS_BAD_PARAM; } break; @@ -600,7 +605,7 @@ static tAVRC_STS avrc_bld_notify_rsp(tAVRC_REG_NOTIF_RSP* p_rsp, UINT8_TO_BE_STREAM(p_data, p_rsp->param.battery_status); len = 2; } else { - AVRC_TRACE_ERROR("%s bad battery status", __func__); + LOG_ERROR("%s bad battery status", __func__); status = AVRC_STS_BAD_PARAM; } break; @@ -610,7 +615,7 @@ static tAVRC_STS avrc_bld_notify_rsp(tAVRC_REG_NOTIF_RSP* p_rsp, UINT8_TO_BE_STREAM(p_data, p_rsp->param.system_status); len = 2; } else { - AVRC_TRACE_ERROR("%s bad system status", __func__); + LOG_ERROR("%s bad system status", __func__); status = AVRC_STS_BAD_PARAM; } break; @@ -630,8 +635,7 @@ static tAVRC_STS avrc_bld_notify_rsp(tAVRC_REG_NOTIF_RSP* p_rsp, UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_value[xx]); } else { - AVRC_TRACE_ERROR("%s bad player app seeting attribute or value", - __func__); + LOG_ERROR("%s bad player app seeting attribute or value", __func__); status = AVRC_STS_BAD_PARAM; break; } @@ -659,7 +663,7 @@ static tAVRC_STS avrc_bld_notify_rsp(tAVRC_REG_NOTIF_RSP* p_rsp, default: status = AVRC_STS_BAD_PARAM; - AVRC_TRACE_ERROR("%s unknown event_id", __func__); + LOG_ERROR("%s unknown event_id", __func__); } UINT16_TO_BE_STREAM(p_len, len); @@ -686,7 +690,7 @@ static tAVRC_STS avrc_bld_next_rsp(tAVRC_NEXT_RSP* p_rsp, BT_HDR* p_pkt) { UINT16_TO_BE_STREAM(p_data, 0x0001); /* only one attribute to be sent */ UINT8_TO_BE_STREAM(p_data, p_rsp->target_pdu); - AVRC_TRACE_API("%s: target_pdu: 0x%02x", __func__, p_rsp->target_pdu); + LOG_VERBOSE("%s: target_pdu: 0x%02x", __func__, p_rsp->target_pdu); return AVRC_STS_NO_ERROR; } @@ -701,7 +705,7 @@ static tAVRC_STS avrc_bld_next_rsp(tAVRC_NEXT_RSP* p_rsp, BT_HDR* p_pkt) { *****************************************************************************/ static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol, BT_HDR* p_pkt) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; /* To calculate length */ uint8_t* p_data = p_start + 2; @@ -725,10 +729,10 @@ static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol, ******************************************************************************/ tAVRC_STS avrc_bld_group_navigation_rsp(uint16_t navi_id, BT_HDR* p_pkt) { if (!AVRC_IS_VALID_GROUP(navi_id)) { - AVRC_TRACE_ERROR("%s bad navigation op id: %d", __func__, navi_id); + LOG_ERROR("%s bad navigation op id: %d", __func__, navi_id); return AVRC_STS_BAD_PARAM; } - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); uint8_t* p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset; UINT16_TO_BE_STREAM(p_data, navi_id); p_pkt->len = 2; @@ -749,8 +753,8 @@ static tAVRC_STS avrc_bld_rejected_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { uint8_t* p_data; uint8_t opcode = p_rsp->opcode; - AVRC_TRACE_API("%s: status=%d, pdu:x%x, opcode=%x", __func__, p_rsp->status, - p_rsp->pdu, opcode); + LOG_VERBOSE("%s: status=%d, pdu:x%x, opcode=%x", __func__, p_rsp->status, + p_rsp->pdu, opcode); if (opcode == AVRC_OP_BROWSE) { p_data = p_start + 1; @@ -764,7 +768,7 @@ static tAVRC_STS avrc_bld_rejected_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { } else { p_data = p_start + 2; } - AVRC_TRACE_DEBUG("%s pdu:x%x, Opcode:%x", __func__, *p_start, opcode); + LOG_VERBOSE("%s pdu:x%x, Opcode:%x", __func__, *p_start, opcode); UINT16_TO_BE_STREAM(p_data, 1); UINT8_TO_BE_STREAM(p_data, p_rsp->status); p_pkt->len = p_data - p_start; @@ -787,7 +791,7 @@ static tAVRC_STS avrc_bld_rejected_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { ******************************************************************************/ static tAVRC_STS avrc_bld_ctrl_status_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; - AVRC_TRACE_DEBUG("pdu:x%x", *p_start); + LOG_VERBOSE("pdu:x%x", *p_start); /* To calculate length */ uint8_t* p_data = p_start + 2; /* pdu + rsvd */ @@ -810,7 +814,7 @@ static tAVRC_STS avrc_bld_ctrl_status_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { * ******************************************************************************/ static tAVRC_STS avrc_bld_set_addr_player_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt); } @@ -844,7 +848,7 @@ static tAVRC_STS avrc_bld_set_browsed_player_rsp(tAVRC_SET_BR_PLAYER_RSP* p_rsp, len_left = mtu; } len_left = len_left - p_pkt->offset - p_pkt->len; - AVRC_TRACE_DEBUG("len_left:%d, mtu:%d ", len_left, mtu); + LOG_VERBOSE("len_left:%d, mtu:%d ", len_left, mtu); /* get the existing length, if any, and also the num attributes */ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; @@ -920,7 +924,7 @@ static tAVRC_STS avrc_bld_get_folder_items_rsp(tAVRC_GET_ITEMS_RSP* p_rsp, uint16_t item_count; uint16_t mtu; bool multi_items_add_fail = false; - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* make sure the given buffer can accomodate this response */ len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE; @@ -932,7 +936,7 @@ static tAVRC_STS avrc_bld_get_folder_items_rsp(tAVRC_GET_ITEMS_RSP* p_rsp, // Version 5.3 | Vol 3, Part A, Chapter 5 // MTU may be controlled by the peer if (len_left < p_pkt->offset + p_pkt->len) { - AVRC_TRACE_ERROR("memory not enough (len_left=%d)", len_left); + LOG_ERROR("memory not enough (len_left=%d)", len_left); return AVRC_STS_INTERNAL_ERR; } @@ -954,7 +958,7 @@ static tAVRC_STS avrc_bld_get_folder_items_rsp(tAVRC_GET_ITEMS_RSP* p_rsp, len = 5; if (len_left < 5) { - AVRC_TRACE_ERROR("memory not enough (len_left=%d)", len_left); + LOG_ERROR("memory not enough (len_left=%d)", len_left); return AVRC_STS_INTERNAL_ERR; } @@ -964,7 +968,7 @@ static tAVRC_STS avrc_bld_get_folder_items_rsp(tAVRC_GET_ITEMS_RSP* p_rsp, p = p_num; BE_STREAM_TO_UINT16(item_count, p); } - AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d", len, len_left, item_count); + LOG_VERBOSE("len:%d, len_left:%d, num:%d", len, len_left, item_count); /* min len required = item_type(1) + item len(2) + min item (14) = 17 */ for (xx = 0; @@ -1087,8 +1091,8 @@ static tAVRC_STS avrc_bld_get_folder_items_rsp(tAVRC_GET_ITEMS_RSP* p_rsp, status = AVRC_STS_BAD_PARAM; break; } - AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d, item_len:%d", len, len_left, - item_count, item_len); + LOG_VERBOSE("len:%d, len_left:%d, num:%d, item_len:%zu", len, len_left, + item_count, item_len); } /* for item_count */ UINT16_TO_BE_STREAM(p_num, item_count); @@ -1142,9 +1146,9 @@ static tAVRC_STS avrc_bld_change_path_rsp(tAVRC_CHG_PATH_RSP* p_rsp, ******************************************************************************/ static tAVRC_STS avrc_bld_get_item_attrs_rsp(tAVRC_GET_ATTRS_RSP* p_rsp, BT_HDR* p_pkt) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!p_rsp->p_attrs) { - AVRC_TRACE_ERROR("%s NULL p_attrs", __func__); + LOG_ERROR("%s NULL p_attrs", __func__); return AVRC_STS_BAD_PARAM; } /* Figure out how much we have left in current buffer */ @@ -1158,11 +1162,11 @@ static tAVRC_STS avrc_bld_get_item_attrs_rsp(tAVRC_GET_ATTRS_RSP* p_rsp, if (remaining_buffer_capacity > mtu) { remaining_buffer_capacity = mtu; } - AVRC_TRACE_DEBUG("%s: remaining_buffer_capacity:%d, mtu:%d", __func__, - remaining_buffer_capacity, mtu); + LOG_VERBOSE("%s: remaining_buffer_capacity:%d, mtu:%d", __func__, + remaining_buffer_capacity, mtu); if (remaining_buffer_capacity < 5) { - AVRC_TRACE_ERROR("%s: not enough space for packet header, remaining:%d < 5", - __func__, remaining_buffer_capacity); + LOG_ERROR("%s: not enough space for packet header, remaining:%d < 5", + __func__, remaining_buffer_capacity); return AVRC_STS_INTERNAL_ERR; } /* Get to the beginning of PDU */ @@ -1220,7 +1224,7 @@ static tAVRC_STS avrc_bld_get_num_of_item_rsp(tAVRC_GET_NUM_OF_ITEMS_RSP* p_rsp, BT_HDR* p_pkt) { uint8_t *p_data, *p_start, *p_len; - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* get the existing length, if any, and also the num attributes */ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 1; /* pdu */ @@ -1257,7 +1261,7 @@ static tAVRC_STS avrc_bld_get_num_of_item_rsp(tAVRC_GET_NUM_OF_ITEMS_RSP* p_rsp, static tAVRC_STS avrc_bld_search_rsp(tAVRC_SEARCH_RSP* p_rsp, BT_HDR* p_pkt) { uint8_t *p_data, *p_start, *p_len; - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); /* get the existing length, if any, and also the num attributes */ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_data = p_len = p_start + 1; /* pdu */ @@ -1282,7 +1286,7 @@ static tAVRC_STS avrc_bld_search_rsp(tAVRC_SEARCH_RSP* p_rsp, BT_HDR* p_pkt) { * ******************************************************************************/ static tAVRC_STS avrc_bld_play_item_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt); } @@ -1298,7 +1302,7 @@ static tAVRC_STS avrc_bld_play_item_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { ******************************************************************************/ static tAVRC_STS avrc_bld_add_to_now_playing_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) { - AVRC_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt); } @@ -1317,12 +1321,12 @@ static BT_HDR* avrc_bld_init_rsp_buffer(tAVRC_RESPONSE* p_rsp) { uint16_t chnl = AVCT_DATA_CTRL; uint8_t opcode = avrc_opcode_from_pdu(p_rsp->pdu); - AVRC_TRACE_API("%s: pdu=%x, opcode=%x/%x", __func__, p_rsp->pdu, opcode, - p_rsp->rsp.opcode); + LOG_VERBOSE("%s: pdu=%x, opcode=%x/%x", __func__, p_rsp->pdu, opcode, + p_rsp->rsp.opcode); if (opcode != p_rsp->rsp.opcode && p_rsp->rsp.status != AVRC_STS_NO_ERROR && avrc_is_valid_opcode(p_rsp->rsp.opcode)) { opcode = p_rsp->rsp.opcode; - AVRC_TRACE_API("%s opcode=%x", __func__, opcode); + LOG_VERBOSE("%s opcode=%x", __func__, opcode); } switch (opcode) { @@ -1390,15 +1394,15 @@ tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp, uint16_t peer_mtu; if (!p_rsp || !pp_pkt) { - AVRC_TRACE_API("%s Invalid parameters passed. p_rsp=%p, pp_pkt=%p", - __func__, p_rsp, pp_pkt); + LOG_VERBOSE("%s Invalid parameters passed. p_rsp=%p, pp_pkt=%p", __func__, + p_rsp, pp_pkt); return AVRC_STS_BAD_PARAM; } if (*pp_pkt == NULL) { *pp_pkt = avrc_bld_init_rsp_buffer(p_rsp); if (*pp_pkt == NULL) { - AVRC_TRACE_API("%s Failed to initialize response buffer", __func__); + LOG_VERBOSE("%s Failed to initialize response buffer", __func__); return AVRC_STS_INTERNAL_ERR; } @@ -1413,8 +1417,8 @@ tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp, status = AVRC_STS_NO_ERROR; p_pkt = *pp_pkt; - AVRC_TRACE_API("%s pdu=%x status=%x", __func__, p_rsp->rsp.pdu, - p_rsp->rsp.status); + LOG_VERBOSE("%s pdu=%x status=%x", __func__, p_rsp->rsp.pdu, + p_rsp->rsp.status); if (p_rsp->rsp.status != AVRC_STS_NO_ERROR) { return (avrc_bld_rejected_rsp(&p_rsp->rsp, p_pkt)); } @@ -1532,6 +1536,6 @@ tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp, osi_free(p_pkt); *pp_pkt = NULL; } - AVRC_TRACE_API("%s returning %d", __func__, status); + LOG_VERBOSE("%s returning %d", __func__, status); return status; } diff --git a/system/stack/avrc/avrc_int.h b/system/stack/avrc/avrc_int.h index fd30965f4c3a7c9952c06986b207ad2ecc3fddf9..b1b4e0a11bdc9cfec6c028a3dfd2d8dee6abde9a 100644 --- a/system/stack/avrc/avrc_int.h +++ b/system/stack/avrc/avrc_int.h @@ -25,9 +25,9 @@ #ifndef AVRC_INT_H #define AVRC_INT_H +#include "internal_include/bt_target.h" #include "osi/include/alarm.h" #include "osi/include/fixed_queue.h" -#include "stack/avct/avct_defs.h" #include "stack/include/avrc_api.h" #include "stack/include/bt_hdr.h" @@ -151,7 +151,6 @@ typedef struct { tAVRC_FIND_CBACK find_cback; /* sdp discovery callback */ tSDP_DISCOVERY_DB* p_db; /* pointer to discovery database */ uint16_t service_uuid; /* service UUID to search */ - uint8_t trace_level; } tAVRC_CB; /****************************************************************************** diff --git a/system/stack/avrc/avrc_opt.cc b/system/stack/avrc/avrc_opt.cc index 87c685c2c495ab5c6c8e58f8183e378154b923f7..ec097bf17ccd409b026948478ee3aacba8c4fb96 100644 --- a/system/stack/avrc/avrc_opt.cc +++ b/system/stack/avrc/avrc_opt.cc @@ -26,6 +26,7 @@ #include "avrc_api.h" #include "avrc_int.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/avrc/avrc_pars_ct.cc b/system/stack/avrc/avrc_pars_ct.cc index 6a45b8c48bb726f6055c0870f9a0ebb4d9bc543f..aa4f3fcba508014512d02c612707e9033f5d43b7 100644 --- a/system/stack/avrc/avrc_pars_ct.cc +++ b/system/stack/avrc/avrc_pars_ct.cc @@ -20,9 +20,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/log.h" #include "osi/include/osi.h" +#include "stack/include/bt_types.h" /***************************************************************************** * Global data @@ -54,27 +55,26 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, if (p_msg->p_vendor_data == NULL) return AVRC_STS_INTERNAL_ERR; if (p_msg->vendor_len < 4) { - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4", - __func__, p_msg->vendor_len); + LOG_WARN("%s: message length %d too short: must be at least 4", __func__, + p_msg->vendor_len); return AVRC_STS_INTERNAL_ERR; } p = p_msg->p_vendor_data; BE_STREAM_TO_UINT8(p_result->pdu, p); p++; /* skip the reserved/packe_type byte */ BE_STREAM_TO_UINT16(len, p); - AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d/0x%x vendor_len=0x%x", - __func__, p_msg->hdr.ctype, p_result->pdu, len, len, - p_msg->vendor_len); + LOG_VERBOSE("%s ctype:0x%x pdu:0x%x, len:%d/0x%x vendor_len=0x%x", __func__, + p_msg->hdr.ctype, p_result->pdu, len, len, p_msg->vendor_len); if (p_msg->vendor_len < len + 4) { - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d", - __func__, p_msg->vendor_len, len + 4); + LOG_WARN("%s: message length %d too short: must be at least %d", __func__, + p_msg->vendor_len, len + 4); return AVRC_STS_INTERNAL_ERR; } if (p_msg->hdr.ctype == AVRC_RSP_REJ) { if (len < 1) { - AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least 1", - __func__, len); + LOG_WARN("%s: invalid parameter length %d: must be at least 1", __func__, + len); return AVRC_STS_INTERNAL_ERR; } p_result->rsp.status = *p; @@ -101,9 +101,8 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, break; } if (len < 1) { - AVRC_TRACE_WARNING( - "%s: invalid parameter length %d: must be at least 1", __func__, - len); + LOG_WARN("%s: invalid parameter length %d: must be at least 1", + __func__, len); return AVRC_STS_INTERNAL_ERR; } BE_STREAM_TO_UINT8(eventid, p); @@ -113,17 +112,16 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, AVRC_RSP_REJ == p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL == p_msg->hdr.ctype)) { if (len < 2) { - AVRC_TRACE_WARNING( - "%s: invalid parameter length %d: must be at least 2", __func__, - len); + LOG_WARN("%s: invalid parameter length %d: must be at least 2", + __func__, len); return AVRC_STS_INTERNAL_ERR; } p_result->reg_notif.status = p_msg->hdr.ctype; p_result->reg_notif.event_id = eventid; BE_STREAM_TO_UINT8(p_result->reg_notif.param.volume, p); } - AVRC_TRACE_DEBUG("%s PDU reg notif response:event %x, volume %x", - __func__, eventid, p_result->reg_notif.param.volume); + LOG_VERBOSE("%s PDU reg notif response:event %x, volume %x", __func__, + eventid, p_result->reg_notif.param.volume); break; default: status = AVRC_STS_BAD_CMD; @@ -203,8 +201,8 @@ tAVRC_STS avrc_parse_notification_rsp(uint8_t* p_stream, uint16_t len, return AVRC_STS_NO_ERROR; length_error: - AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least %d", - __func__, len, min_len); + LOG_WARN("%s: invalid parameter length %d: must be at least %d", __func__, + len, min_len); return AVRC_STS_INTERNAL_ERR; } @@ -214,7 +212,7 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, uint8_t pdu; if (p_msg->browse_len == 0) { - AVRC_TRACE_ERROR("%s length ", p_msg->browse_len); + LOG_ERROR("%s length %d", __func__, p_msg->browse_len); return AVRC_STS_BAD_PARAM; } @@ -222,8 +220,8 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, /* read the pdu */ if (p_msg->browse_len < 3) { - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 3", - __func__, p_msg->browse_len); + LOG_WARN("%s: message length %d too short: must be at least 3", __func__, + p_msg->browse_len); return AVRC_STS_BAD_PARAM; } BE_STREAM_TO_UINT8(pdu, p); @@ -232,11 +230,11 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, /* read the entire packet len */ BE_STREAM_TO_UINT16(pkt_len, p); - AVRC_TRACE_DEBUG("%s pdu:%d, pkt_len:%d", __func__, pdu, pkt_len); + LOG_VERBOSE("%s pdu:%d, pkt_len:%d", __func__, pdu, pkt_len); if (p_msg->browse_len < (pkt_len + 3)) { - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d", - __func__, p_msg->browse_len, pkt_len + 3); + LOG_WARN("%s: message length %d too short: must be at least %d", __func__, + p_msg->browse_len, pkt_len + 3); return AVRC_STS_INTERNAL_ERR; } @@ -251,8 +249,7 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, /* read the status */ BE_STREAM_TO_UINT8(get_item_rsp->status, p); if (get_item_rsp->status != AVRC_STS_NO_ERROR) { - AVRC_TRACE_WARNING("%s returning error %d", __func__, - get_item_rsp->status); + LOG_WARN("%s returning error %d", __func__, get_item_rsp->status); return get_item_rsp->status; } @@ -263,10 +260,9 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, /* read the number of items */ BE_STREAM_TO_UINT16(get_item_rsp->item_count, p); - AVRC_TRACE_DEBUG( - "%s pdu %d status %d pkt_len %d uid counter %d item count %d", - __func__, get_item_rsp->pdu, get_item_rsp->status, pkt_len, - get_item_rsp->uid_counter, get_item_rsp->item_count); + LOG_VERBOSE("%s pdu %d status %d pkt_len %d uid counter %d item count %d", + __func__, get_item_rsp->pdu, get_item_rsp->status, pkt_len, + get_item_rsp->uid_counter, get_item_rsp->item_count); /* get each of the items */ get_item_rsp->p_item_list = (tAVRC_ITEM*)osi_calloc( @@ -276,7 +272,7 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, min_len += 1; if (pkt_len < min_len) goto browse_length_error; BE_STREAM_TO_UINT8(curr_item->item_type, p); - AVRC_TRACE_DEBUG("%s item type %d", __func__, curr_item->item_type); + LOG_VERBOSE("%s item type %d", __func__, curr_item->item_type); switch (curr_item->item_type) { case AVRC_ITEM_PLAYER: { /* Handle player */ @@ -301,7 +297,7 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, player->name.p_str = (uint8_t*)osi_calloc( (player->name.str_len + 1) * sizeof(uint8_t)); BE_STREAM_TO_ARRAY(p, player->name.p_str, player->name.str_len); - AVRC_TRACE_DEBUG( + LOG_VERBOSE( "%s type %d id %d mtype %d stype %d ps %d cs %d name len %d", __func__, curr_item->item_type, player->player_id, player->major_type, player->sub_type, player->play_status, @@ -329,9 +325,9 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, folder->name.p_str = (uint8_t*)osi_calloc( (folder->name.str_len + 1) * sizeof(uint8_t)); BE_STREAM_TO_ARRAY(p, folder->name.p_str, folder->name.str_len); - AVRC_TRACE_DEBUG("%s type %d playable %d cs %d name len %d", - __func__, folder->type, folder->playable, - folder->name.charset_id, folder->name.str_len); + LOG_VERBOSE("%s type %d playable %d cs %d name len %d", __func__, + folder->type, folder->playable, folder->name.charset_id, + folder->name.str_len); } break; case AVRC_ITEM_MEDIA: { @@ -355,9 +351,9 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, BE_STREAM_TO_ARRAY(p, media->name.p_str, media->name.str_len); BE_STREAM_TO_UINT8(media->attr_count, p); - AVRC_TRACE_DEBUG("%s media type %d charset id %d len %d attr ct %d", - __func__, media->type, media->name.charset_id, - media->name.str_len, media->attr_count); + LOG_VERBOSE("%s media type %d charset id %d len %d attr ct %d", + __func__, media->type, media->name.charset_id, + media->name.str_len, media->attr_count); media->p_attr_list = (tAVRC_ATTR_ENTRY*)osi_calloc( media->attr_count * sizeof(tAVRC_ATTR_ENTRY)); @@ -376,21 +372,19 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, attr_entry->name.str_len * sizeof(uint8_t)); BE_STREAM_TO_ARRAY(p, attr_entry->name.p_str, attr_entry->name.str_len); - AVRC_TRACE_DEBUG("%s media attr id %d cs %d name len %d", - __func__, attr_entry->attr_id, - attr_entry->name.charset_id, - attr_entry->name.str_len); + LOG_VERBOSE("%s media attr id %d cs %d name len %d", __func__, + attr_entry->attr_id, attr_entry->name.charset_id, + attr_entry->name.str_len); } } break; default: - AVRC_TRACE_ERROR("%s item type not handled %d", __func__, - curr_item->item_type); + LOG_ERROR("%s item type not handled %d", __func__, + curr_item->item_type); return AVRC_STS_INTERNAL_ERR; } - AVRC_TRACE_DEBUG("%s pkt_len %d min_len %d", __func__, pkt_len, - min_len); + LOG_VERBOSE("%s pkt_len %d min_len %d", __func__, pkt_len, min_len); /* advance to populate the next item */ curr_item++; @@ -409,9 +403,9 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, /* Read the number of items in folder */ BE_STREAM_TO_UINT32(change_path_rsp->num_items, p); - AVRC_TRACE_DEBUG("%s pdu %d status %d item count %d", __func__, - change_path_rsp->pdu, change_path_rsp->status, - change_path_rsp->num_items); + LOG_VERBOSE("%s pdu %d status %d item count %d", __func__, + change_path_rsp->pdu, change_path_rsp->status, + change_path_rsp->num_items); break; } @@ -438,9 +432,9 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, attr_entry->name.p_str = (uint8_t*)osi_malloc(attr_entry->name.str_len * sizeof(uint8_t)); BE_STREAM_TO_ARRAY(p, attr_entry->name.p_str, attr_entry->name.str_len); - AVRC_TRACE_DEBUG("%s media attr id %d cs %d name len %d", __func__, - attr_entry->attr_id, attr_entry->name.charset_id, - attr_entry->name.str_len); + LOG_VERBOSE("%s media attr id %d cs %d name len %d", __func__, + attr_entry->attr_id, attr_entry->name.charset_id, + attr_entry->name.str_len); } break; @@ -456,7 +450,7 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, BE_STREAM_TO_UINT8(set_br_pl_rsp->status, p); if (set_br_pl_rsp->status != AVRC_STS_NO_ERROR) { - AVRC_TRACE_ERROR( + LOG_ERROR( "%s Stopping further parsing because player not browsable sts %d", __func__, set_br_pl_rsp->status); break; @@ -465,7 +459,7 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, BE_STREAM_TO_UINT32(set_br_pl_rsp->num_items, p); BE_STREAM_TO_UINT16(set_br_pl_rsp->charset_id, p); BE_STREAM_TO_UINT8(set_br_pl_rsp->folder_depth, p); - AVRC_TRACE_DEBUG( + LOG_VERBOSE( "%s AVRC_PDU_SET_BROWSED_PLAYER status %d items %d cs %d depth %d", __func__, set_br_pl_rsp->status, set_br_pl_rsp->num_items, set_br_pl_rsp->charset_id, set_br_pl_rsp->folder_depth); @@ -481,8 +475,8 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, BE_STREAM_TO_UINT16(folder_name->str_len, p); min_len += folder_name->str_len; if (pkt_len < min_len) goto browse_length_error; - AVRC_TRACE_DEBUG("%s AVRC_PDU_SET_BROWSED_PLAYER item: %d len: %d", - __func__, i, folder_name->str_len); + LOG_VERBOSE("%s AVRC_PDU_SET_BROWSED_PLAYER item: %d len: %d", __func__, + i, folder_name->str_len); folder_name->p_str = (uint8_t*)osi_calloc((folder_name->str_len + 1) * sizeof(uint8_t)); BE_STREAM_TO_ARRAY(p, folder_name->p_str, folder_name->str_len); @@ -491,14 +485,14 @@ static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg, } default: - AVRC_TRACE_ERROR("%s pdu %d not handled", __func__, pdu); + LOG_ERROR("%s pdu %d not handled", __func__, pdu); } return status; browse_length_error: - AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least %d", - __func__, pkt_len, min_len); + LOG_WARN("%s: invalid parameter length %d: must be at least %d", __func__, + pkt_len, min_len); return AVRC_STS_BAD_CMD; } @@ -518,8 +512,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, tAVRC_RESPONSE* p_result, uint8_t* p_buf, uint16_t* buf_len) { if (p_msg->vendor_len < 4) { - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4", - __func__, p_msg->vendor_len); + LOG_WARN("%s: message length %d too short: must be at least 4", __func__, + p_msg->vendor_len); return AVRC_STS_INTERNAL_ERR; } @@ -530,11 +524,11 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, uint16_t len; uint32_t min_len = 0; BE_STREAM_TO_UINT16(len, p); - AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d vendor_len=0x%x", __func__, - p_msg->hdr.ctype, p_result->pdu, len, p_msg->vendor_len); + LOG_VERBOSE("%s ctype:0x%x pdu:0x%x, len:%d vendor_len=0x%x", __func__, + p_msg->hdr.ctype, p_result->pdu, len, p_msg->vendor_len); if (p_msg->vendor_len < len + 4) { - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d", - __func__, p_msg->vendor_len, len + 4); + LOG_WARN("%s: message length %d too short: must be at least %d", __func__, + p_msg->vendor_len, len + 4); return AVRC_STS_INTERNAL_ERR; } /* Todo: Issue in handling reject, check */ @@ -563,9 +557,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, if (len < min_len) goto length_error; BE_STREAM_TO_UINT8(p_result->get_caps.capability_id, p); BE_STREAM_TO_UINT8(p_result->get_caps.count, p); - AVRC_TRACE_DEBUG("%s cap id = %d, cap_count = %d ", __func__, - p_result->get_caps.capability_id, - p_result->get_caps.count); + LOG_VERBOSE("%s cap id = %d, cap_count = %d ", __func__, + p_result->get_caps.capability_id, p_result->get_caps.count); if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID) { if (p_result->get_caps.count > AVRC_CAP_MAX_NUM_COMP_ID) { return AVRC_STS_INTERNAL_ERR; @@ -599,8 +592,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, } min_len += 1; BE_STREAM_TO_UINT8(p_result->list_app_attr.num_attr, p); - AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, - p_result->list_app_attr.num_attr); + LOG_VERBOSE("%s attr count = %d ", __func__, + p_result->list_app_attr.num_attr); if (p_result->list_app_attr.num_attr > AVRC_MAX_APP_ATTR_SIZE) { p_result->list_app_attr.num_attr = AVRC_MAX_APP_ATTR_SIZE; @@ -624,8 +617,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, p_result->list_app_values.num_val = AVRC_MAX_APP_ATTR_SIZE; } - AVRC_TRACE_DEBUG("%s value count = %d ", __func__, - p_result->list_app_values.num_val); + LOG_VERBOSE("%s value count = %d ", __func__, + p_result->list_app_values.num_val); min_len += p_result->list_app_values.num_val; if (len < min_len) goto length_error; for (int xx = 0; xx < p_result->list_app_values.num_val; xx++) { @@ -640,8 +633,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, } min_len += 1; BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_val, p); - AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, - p_result->get_cur_app_val.num_val); + LOG_VERBOSE("%s attr count = %d ", __func__, + p_result->get_cur_app_val.num_val); if (p_result->get_cur_app_val.num_val > AVRC_MAX_APP_ATTR_SIZE) { p_result->get_cur_app_val.num_val = AVRC_MAX_APP_ATTR_SIZE; @@ -673,8 +666,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, if (num_attrs > AVRC_MAX_APP_ATTR_SIZE) { num_attrs = AVRC_MAX_APP_ATTR_SIZE; } - AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, - p_result->get_app_attr_txt.num_attr); + LOG_VERBOSE("%s attr count = %d ", __func__, + p_result->get_app_attr_txt.num_attr); p_result->get_app_attr_txt.num_attr = num_attrs; p_result->get_app_attr_txt.p_attrs = (tAVRC_APP_SETTING_TEXT*)osi_calloc( @@ -727,8 +720,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, num_vals = AVRC_MAX_APP_ATTR_SIZE; } p_result->get_app_val_txt.num_attr = num_vals; - AVRC_TRACE_DEBUG("%s value count = %d ", __func__, - p_result->get_app_val_txt.num_attr); + LOG_VERBOSE("%s value count = %d ", __func__, + p_result->get_app_val_txt.num_attr); p_result->get_app_val_txt.p_attrs = (tAVRC_APP_SETTING_TEXT*)osi_calloc( num_vals * sizeof(tAVRC_APP_SETTING_TEXT)); @@ -831,7 +824,7 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, case AVRC_PDU_SET_ADDRESSED_PLAYER: if (len != 1) { - AVRC_TRACE_ERROR("%s pdu: %d len %d", __func__, p_result->pdu, len); + LOG_ERROR("%s pdu: %d len %d", __func__, p_result->pdu, len); return AVRC_STS_BAD_CMD; } BE_STREAM_TO_UINT8(p_result->rsp.status, p); @@ -843,8 +836,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, return AVRC_STS_NO_ERROR; length_error: - AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least %d", - __func__, len, min_len); + LOG_WARN("%s: invalid parameter length %d: must be at least %d", __func__, + len, min_len); return AVRC_STS_INTERNAL_ERR; } @@ -874,7 +867,7 @@ tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result, break; default: - AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode); + LOG_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode); break; } p_result->rsp.opcode = p_msg->hdr.opcode; @@ -915,7 +908,7 @@ tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result, break; default: - AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode); + LOG_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode); break; } p_result->rsp.opcode = p_msg->hdr.opcode; diff --git a/system/stack/avrc/avrc_pars_tg.cc b/system/stack/avrc/avrc_pars_tg.cc index a250af279c04324c2ef2270ee5944a9eb4b68326..a6ae9a62d03ccaa0e056775e7bf98d81600e1a46 100644 --- a/system/stack/avrc/avrc_pars_tg.cc +++ b/system/stack/avrc/avrc_pars_tg.cc @@ -20,8 +20,8 @@ #include "avrc_api.h" #include "avrc_defs.h" #include "avrc_int.h" - -#include "osi/include/log.h" +#include "os/log.h" +#include "stack/include/bt_types.h" /***************************************************************************** * Global data @@ -44,15 +44,15 @@ static tAVRC_STS avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg, tAVRC_STS status = AVRC_STS_NO_ERROR; if (p_msg->vendor_len < 4) { // 4 == pdu + reserved byte + len as uint16 - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4", - __func__, p_msg->vendor_len); + LOG_WARN("%s: message length %d too short: must be at least 4", __func__, + p_msg->vendor_len); return AVRC_STS_INTERNAL_ERR; } uint8_t* p = p_msg->p_vendor_data; p_result->pdu = *p++; - AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu); + LOG_VERBOSE("%s pdu:0x%x", __func__, p_result->pdu); if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) { - AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__); + LOG_VERBOSE("%s detects wrong AV/C type!", __func__); status = AVRC_STS_BAD_CMD; } @@ -123,25 +123,24 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg, if (p_msg->p_vendor_data == NULL) return AVRC_STS_INTERNAL_ERR; if (p_msg->vendor_len < 4) { - AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4", - __func__, p_msg->vendor_len); + LOG_WARN("%s: message length %d too short: must be at least 4", __func__, + p_msg->vendor_len); return AVRC_STS_INTERNAL_ERR; } p = p_msg->p_vendor_data; p_result->pdu = *p++; - AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu); + LOG_VERBOSE("%s pdu:0x%x", __func__, p_result->pdu); if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) { - AVRC_TRACE_DEBUG("%s detects wrong AV/C type(0x%x)!", __func__, - p_msg->hdr.ctype); + LOG_VERBOSE("%s detects wrong AV/C type(0x%x)!", __func__, + p_msg->hdr.ctype); status = AVRC_STS_BAD_CMD; } p++; /* skip the reserved byte */ BE_STREAM_TO_UINT16(len, p); if ((len + 4) != (p_msg->vendor_len)) { - AVRC_TRACE_ERROR("%s incorrect length :%d, %d", __func__, len, - p_msg->vendor_len); + LOG_ERROR("%s incorrect length :%d, %d", __func__, len, p_msg->vendor_len); status = AVRC_STS_INTERNAL_ERR; } @@ -212,14 +211,14 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg, status = AVRC_STS_BAD_PARAM; } if (xx != p_result->set_app_val.num_val) { - AVRC_TRACE_ERROR( + LOG_ERROR( "%s AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig " "num_val:%d", __func__, xx, p_result->set_app_val.num_val); p_result->set_app_val.num_val = xx; } } else { - AVRC_TRACE_ERROR( + LOG_ERROR( "%s AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len", __func__); status = AVRC_STS_INTERNAL_ERR; @@ -321,8 +320,8 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg, else { BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p); if (!AVRC_IS_VALID_EVENT_ID(p_result->reg_notif.event_id)) { - AVRC_TRACE_ERROR("%s: Invalid event id: %d", __func__, - p_result->reg_notif.event_id); + LOG_ERROR("%s: Invalid event id: %d", __func__, + p_result->reg_notif.event_id); return AVRC_STS_BAD_PARAM; } @@ -353,8 +352,7 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg, case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */ if (len != 2) { - AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d", - len); + LOG_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d", len); return AVRC_STS_INTERNAL_ERR; } BE_STREAM_TO_UINT16(p_result->addr_player.player_id, p); @@ -402,19 +400,19 @@ tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) { break; default: - AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode); + LOG_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode); break; } p_result->cmd.opcode = p_msg->hdr.opcode; p_result->cmd.status = status; } - AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status); + LOG_VERBOSE("%s return status:0x%x", __func__, status); return status; } #define RETURN_STATUS_IF_FALSE(_status_, _b_, _msg_, ...) \ if (!(_b_)) { \ - AVRC_TRACE_DEBUG(_msg_, ##__VA_ARGS__); \ + LOG_VERBOSE(_msg_, ##__VA_ARGS__); \ return _status_; \ } @@ -442,7 +440,7 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg, "msg too short"); p_result->pdu = *p++; - AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu); + LOG_VERBOSE("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu); /* skip over len */ p += 2; @@ -623,12 +621,12 @@ tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result, break; default: - AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode); + LOG_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode); break; } p_result->cmd.opcode = p_msg->hdr.opcode; p_result->cmd.status = status; } - AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status); + LOG_VERBOSE("%s return status:0x%x", __func__, status); return status; } diff --git a/system/stack/avrc/avrc_sdp.cc b/system/stack/avrc/avrc_sdp.cc index 753f8d2e82a5f0dd1005193966b0120725173545..e6f46717c008d297860f50d848498769d4fd5c0f 100644 --- a/system/stack/avrc/avrc_sdp.cc +++ b/system/stack/avrc/avrc_sdp.cc @@ -21,13 +21,23 @@ * AVRCP SDP related functions * ******************************************************************************/ +#define LOG_TAG "avrcp" + #include #include "avrc_api.h" #include "avrc_int.h" +#include "os/log.h" +#include "osi/include/osi.h" // UNUSED_ATTR +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/sdp_api.h" +#include "stack/include/sdpdefs.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + using bluetooth::Uuid; /***************************************************************************** @@ -55,8 +65,9 @@ static uint16_t a2dp_attr_list_sdp[] = { * Returns Nothing. * *****************************************************************************/ -static void avrc_sdp_cback(tSDP_STATUS status) { - AVRC_TRACE_API("%s status: %d", __func__, status); +static void avrc_sdp_cback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_STATUS status) { + LOG_VERBOSE("%s status: %d", __func__, status); /* reset service_uuid, so can start another find service */ avrc_cb.service_uuid = 0; @@ -111,7 +122,7 @@ uint16_t AVRC_FindService(uint16_t service_uuid, const RawAddress& bd_addr, const tAVRC_FIND_CBACK& find_cback) { bool result = true; - AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid); + LOG_VERBOSE("%s uuid: %x", __func__, service_uuid); if ((service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) || p_db == NULL || p_db->p_db == NULL || find_cback.is_null()) @@ -129,8 +140,8 @@ uint16_t AVRC_FindService(uint16_t service_uuid, const RawAddress& bd_addr, } Uuid uuid_list = Uuid::From16Bit(service_uuid); - result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, - p_db->num_attr, p_db->p_attrs); + result = get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr, p_db->p_attrs); if (result) { /* store service_uuid and discovery db pointer */ @@ -140,12 +151,13 @@ uint16_t AVRC_FindService(uint16_t service_uuid, const RawAddress& bd_addr, /* perform service search */ result = - SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback); + get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest( + bd_addr, p_db->p_db, avrc_sdp_cback); if (!result) { - AVRC_TRACE_ERROR("%s: Failed to init SDP for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - avrc_sdp_cback(SDP_GENERIC_ERROR); + LOG_ERROR("%s: Failed to init SDP for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + avrc_sdp_cback(bd_addr, SDP_GENERIC_ERROR); } } @@ -158,7 +170,8 @@ uint16_t AVRC_FindService(uint16_t service_uuid, const RawAddress& bd_addr, * * Description This function is called to build an AVRCP SDP record. * Prior to calling this function the application must - * call SDP_CreateRecord() to create an SDP record. + * call get_legacy_stack_sdp_api()->handle.SDP_CreateRecord() + * to create an SDP record. * * Input Parameters: * service_uuid: Indicates @@ -166,16 +179,17 @@ uint16_t AVRC_FindService(uint16_t service_uuid, const RawAddress& bd_addr, * or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL) * * p_service_name: Pointer to a null-terminated character - * string containing the service name. + * string containing the service name. * If service name is not used set this to NULL. * * p_provider_name: Pointer to a null-terminated character - * string containing the provider name. + * string containing the provider name. * If provider name is not used set this to NULL. * * categories: Supported categories. * - * sdp_handle: SDP handle returned by SDP_CreateRecord(). + * sdp_handle: SDP handle returned by + * get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(). * * browse_supported: browse support info. * @@ -204,9 +218,10 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, uint8_t index = 0; uint16_t class_list[2]; - AVRC_TRACE_API("%s: Add AVRCP SDP record, uuid: %x, profile_version: 0x%x, " - "supported_features: 0x%x, psm: 0x%x", __func__, service_uuid, - profile_version, categories, cover_art_psm); + LOG_VERBOSE( + "%s: Add AVRCP SDP record, uuid: %x, profile_version: 0x%x, " + "supported_features: 0x%x, psm: 0x%x", + __func__, service_uuid, profile_version, categories, cover_art_psm); if (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) @@ -219,7 +234,8 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL; count = 2; } - result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList( + sdp_handle, count, class_list); uint16_t protocol_reported_version; /* AVRCP versions 1.3 to 1.5 report (version - 1) in the protocol @@ -243,8 +259,8 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, avrc_proto_desc_list[index].params[0] = protocol_reported_version; avrc_proto_desc_list[index].params[1] = 0; } - result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS, - &avrc_proto_desc_list[0]); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList( + sdp_handle, AVRC_NUM_PROTO_ELEMS, &avrc_proto_desc_list[0]); /* additional protocal descriptor, required only for version > 1.3 */ if (profile_version > AVRC_REV_1_3) { @@ -254,8 +270,10 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, /* If we support browsing then add the list */ if (browse_supported) { - AVRC_TRACE_API("%s: Add Browsing PSM to additonal protocol descriptor" - " lists", __func__); + LOG_VERBOSE( + "%s: Add Browsing PSM to additional protocol descriptor" + " lists", + __func__); num_additional_protocols++; avrc_add_proto_desc_lists[i].num_elems = 2; avrc_add_proto_desc_lists[i].list_elem[0].num_params = 1; @@ -276,8 +294,10 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, if (profile_version >= AVRC_REV_1_6 && service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET && cover_art_psm > 0) { - AVRC_TRACE_API("%s: Add AVRCP BIP PSM to additonal protocol descriptor" - " lists, psm: 0x%x", __func__, cover_art_psm); + LOG_VERBOSE( + "%s: Add AVRCP BIP PSM to additional protocol descriptor" + " lists, psm: 0x%x", + __func__, cover_art_psm); num_additional_protocols++; avrc_add_proto_desc_lists[i].num_elems = 2; avrc_add_proto_desc_lists[i].list_elem[0].num_params = 1; @@ -294,40 +314,41 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, /* Add the additional lists if we support any */ if (num_additional_protocols > 0) { - AVRC_TRACE_API("%s: Add %d additonal protocol descriptor lists", - __func__, num_additional_protocols); - result &= SDP_AddAdditionProtoLists(sdp_handle, num_additional_protocols, - avrc_add_proto_desc_lists); + LOG_VERBOSE("%s: Add %d additional protocol descriptor lists", __func__, + num_additional_protocols); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAdditionProtoLists( + sdp_handle, num_additional_protocols, avrc_add_proto_desc_lists); } } /* add profile descriptor list */ - result &= SDP_AddProfileDescriptorList( + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList( sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, profile_version); /* add supported categories */ p = temp; UINT16_TO_BE_STREAM(p, categories); - result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, - UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, (uint32_t)2, + (uint8_t*)temp); /* add provider name */ if (p_provider_name != NULL) { - result &= SDP_AddAttribute( + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_provider_name) + 1), (uint8_t*)p_provider_name); } /* add service name */ if (p_service_name != NULL) { - result &= SDP_AddAttribute( + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name); } /* add browse group list */ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; - result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, - browse_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence( + sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); return (result ? AVRC_SUCCESS : AVRC_FAIL); } @@ -346,38 +367,11 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, * *******************************************************************************/ uint16_t AVRC_RemoveRecord(uint32_t sdp_handle) { - AVRC_TRACE_API("%s: remove AVRCP SDP record", __func__); - bool result = SDP_DeleteRecord(sdp_handle); + LOG_VERBOSE("%s: remove AVRCP SDP record", __func__); + bool result = get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(sdp_handle); return (result ? AVRC_SUCCESS : AVRC_FAIL); } -/****************************************************************************** - * - * Function AVRC_SetTraceLevel - * - * Description Sets the trace level for AVRC. If 0xff is passed, the - * current trace level is returned. - * - * Input Parameters: - * new_level: The level to set the AVRC tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new trace level or current trace level if - * the input parameter is 0xff. - * - *****************************************************************************/ -uint8_t AVRC_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) avrc_cb.trace_level = new_level; - - return (avrc_cb.trace_level); -} - /******************************************************************************* * * Function AVRC_Init @@ -391,10 +385,4 @@ uint8_t AVRC_SetTraceLevel(uint8_t new_level) { ******************************************************************************/ void AVRC_Init(void) { memset(&avrc_cb, 0, sizeof(tAVRC_CB)); - -#if defined(AVRC_INITIAL_TRACE_LEVEL) - avrc_cb.trace_level = AVRC_INITIAL_TRACE_LEVEL; -#else - avrc_cb.trace_level = BT_TRACE_LEVEL_NONE; -#endif } diff --git a/system/stack/avrc/avrc_utils.cc b/system/stack/avrc/avrc_utils.cc index db84354f0e9dbe96de98da5d340e78aaa5601bf2..1d0247eb997296e707960290807a4526253ee9c1 100644 --- a/system/stack/avrc/avrc_utils.cc +++ b/system/stack/avrc/avrc_utils.cc @@ -15,10 +15,13 @@ * limitations under the License. * ******************************************************************************/ -#include + +#define LOG_TAG "avrcp" #include "avrc_api.h" #include "avrc_int.h" +#include "os/log.h" +#include "stack/include/bt_types.h" /************************************************************************** * @@ -110,8 +113,8 @@ bool avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value) { if (attrib >= AVRC_PLAYER_SETTING_LOW_MENU_EXT) result = true; if (!result) { - AVRC_TRACE_ERROR(" %s found not matching attrib(x%x)-value(x%x) pair!", - __func__, attrib, value); + LOG_ERROR(" %s found not matching attrib(x%x)-value(x%x) pair!", __func__, + attrib, value); } return result; } diff --git a/system/stack/bnep/bnep_api.cc b/system/stack/bnep/bnep_api.cc index fb2f94716034f07b07e2ba5ae34681e54fb95163..96d1ad770051b87ab198a3ab235b7edbf19df6b9 100644 --- a/system/stack/bnep/bnep_api.cc +++ b/system/stack/bnep/bnep_api.cc @@ -24,18 +24,19 @@ #include "bnep_api.h" +#include #include #include "bnep_int.h" -#include "bta/include/bta_api.h" +#include "bta/include/bta_sec_api.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#include - using bluetooth::Uuid; /******************************************************************************* @@ -51,12 +52,6 @@ using bluetooth::Uuid; ******************************************************************************/ void BNEP_Init(void) { memset(&bnep_cb, 0, sizeof(tBNEP_CB)); - -#if defined(BNEP_INITIAL_TRACE_LEVEL) - bnep_cb.trace_level = BNEP_INITIAL_TRACE_LEVEL; -#else - bnep_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ -#endif } /******************************************************************************* @@ -167,8 +162,8 @@ tBNEP_RESULT BNEP_Connect(const RawAddress& p_rem_bda, const Uuid& src_uuid, */ p_bcb->con_state = BNEP_STATE_SEC_CHECKING; - BNEP_TRACE_API("BNEP initiating security procedures for src uuid %s", - p_bcb->src_uuid.ToString().c_str()); + LOG_VERBOSE("BNEP initiating security procedures for src uuid %s", + p_bcb->src_uuid.ToString().c_str()); bnep_sec_check_complete(&p_bcb->rem_bda, BT_TRANSPORT_BR_EDR, p_bcb); } else { @@ -182,7 +177,7 @@ tBNEP_RESULT BNEP_Connect(const RawAddress& p_rem_bda, const Uuid& src_uuid, p_bcb->l2cap_cid = cid; } else { - BNEP_TRACE_ERROR("BNEP - Originate failed"); + LOG_ERROR("BNEP - Originate failed"); if (bnep_cb.p_conn_state_cb) (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false); @@ -240,7 +235,7 @@ tBNEP_RESULT BNEP_ConnectResp(uint16_t handle, tBNEP_RESULT resp) { else resp_code = BNEP_SETUP_CONN_NOT_ALLOWED; - bnep_send_conn_responce(p_bcb, resp_code); + bnep_send_conn_response(p_bcb, resp_code); p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD); if (resp == BNEP_SUCCESS) @@ -299,7 +294,7 @@ tBNEP_RESULT BNEP_Disconnect(uint16_t handle) { if (p_bcb->con_state == BNEP_STATE_IDLE) return (BNEP_WRONG_HANDLE); - BNEP_TRACE_API("BNEP_Disconnect() for handle %d", handle); + LOG_VERBOSE("BNEP_Disconnect() for handle %d", handle); L2CA_DisconnectReq(p_bcb->l2cap_cid); @@ -345,8 +340,8 @@ tBNEP_RESULT BNEP_WriteBuf(uint16_t handle, const RawAddress& p_dest_addr, p_bcb = &(bnep_cb.bcb[handle - 1]); /* Check MTU size */ if (p_buf->len > BNEP_MTU_SIZE) { - BNEP_TRACE_ERROR("%s length %d exceeded MTU %d", __func__, p_buf->len, - BNEP_MTU_SIZE); + LOG_ERROR("%s length %d exceeded MTU %d", __func__, p_buf->len, + BNEP_MTU_SIZE); osi_free(p_buf); return (BNEP_MTU_EXCEDED); } @@ -388,7 +383,10 @@ tBNEP_RESULT BNEP_WriteBuf(uint16_t handle, const RawAddress& p_dest_addr, protocol = 0; else { new_len += 4; - if (new_len > org_len) return BNEP_IGNORE_CMD; + if (new_len > org_len) { + osi_free(p_buf); + return BNEP_IGNORE_CMD; + } p_data[2] = 0; p_data[3] = 0; } @@ -447,8 +445,7 @@ tBNEP_RESULT BNEP_Write(uint16_t handle, const RawAddress& p_dest_addr, /* Check MTU size. Consider the possibility of having extension headers */ if (len > BNEP_MTU_SIZE) { - BNEP_TRACE_ERROR("%s length %d exceeded MTU %d", __func__, len, - BNEP_MTU_SIZE); + LOG_ERROR("%s length %d exceeded MTU %d", __func__, len, BNEP_MTU_SIZE); return (BNEP_MTU_EXCEDED); } @@ -634,20 +631,3 @@ tBNEP_RESULT BNEP_SetMulticastFilters(uint16_t handle, uint16_t num_filters, return (BNEP_SUCCESS); } - -/******************************************************************************* - * - * Function BNEP_SetTraceLevel - * - * Description This function sets the trace level for BNEP. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t BNEP_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) bnep_cb.trace_level = new_level; - - return (bnep_cb.trace_level); -} - diff --git a/system/stack/bnep/bnep_int.h b/system/stack/bnep/bnep_int.h index 4b70863258415449fbfc26e669bda6ee6ee5639b..b932c48a6563cbf904292aa4e5a12d209e55bd11 100644 --- a/system/stack/bnep/bnep_int.h +++ b/system/stack/bnep/bnep_int.h @@ -26,7 +26,7 @@ #define BNEP_INT_H #include "bnep_api.h" -#include "bt_target.h" +#include "internal_include/bt_target.h" #include "osi/include/alarm.h" #include "osi/include/fixed_queue.h" #include "stack/include/bt_hdr.h" @@ -154,7 +154,6 @@ typedef struct { tL2CAP_APPL_INFO reg_info; bool profile_registered; /* true when we got our BD addr */ - uint8_t trace_level; } tBNEP_CB; @@ -194,7 +193,7 @@ void bnepu_process_peer_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filters, void bnepu_process_peer_filter_rsp(tBNEP_CONN* p_bcb, uint8_t* p_data); void bnepu_process_multicast_filter_rsp(tBNEP_CONN* p_bcb, uint8_t* p_data); void bnep_send_conn_req(tBNEP_CONN* p_bcb); -void bnep_send_conn_responce(tBNEP_CONN* p_bcb, uint16_t resp_code); +void bnep_send_conn_response(tBNEP_CONN* p_bcb, uint16_t resp_code); void bnep_process_setup_conn_req(tBNEP_CONN* p_bcb, uint8_t* p_setup, uint8_t len); void bnep_process_setup_conn_responce(tBNEP_CONN* p_bcb, uint8_t* p_setup); diff --git a/system/stack/bnep/bnep_main.cc b/system/stack/bnep/bnep_main.cc index e918e041c7341e06b8ec6f04992b0aba72f19b00..65bea68e32d99d138bd998eab28b41602721bf40 100644 --- a/system/stack/bnep/bnep_main.cc +++ b/system/stack/bnep/bnep_main.cc @@ -24,24 +24,24 @@ #define LOG_TAG "bluetooth" +#include #include #include "bnep_api.h" #include "bnep_int.h" -#include "bt_target.h" -#include "bta/include/bta_api.h" -#include "btm_api.h" +#include "bta/include/bta_sec_api.h" #include "device/include/controller.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "l2cdefs.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/bt_types.h" #include "types/raw_address.h" -#include - /******************************************************************************/ /* G L O B A L B N E P D A T A */ /******************************************************************************/ @@ -90,7 +90,7 @@ tBNEP_RESULT bnep_register_with_l2cap(void) { if (!L2CA_Register2(BT_PSM_BNEP, bnep_cb.reg_info, false /* enable_snoop */, nullptr, BNEP_MTU_SIZE, BNEP_MTU_SIZE, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { - BNEP_TRACE_ERROR("BNEP - Registration failed"); + LOG_ERROR("BNEP - Registration failed"); return BNEP_SECURITY_FAIL; } diff --git a/system/stack/bnep/bnep_utils.cc b/system/stack/bnep/bnep_utils.cc index df22a1782500ad6b74f4acb2fbffb6288e896718..aeff8e236077c29cead88f8d1c20ddfd7d7888c6 100644 --- a/system/stack/bnep/bnep_utils.cc +++ b/system/stack/bnep/bnep_utils.cc @@ -22,21 +22,20 @@ * ******************************************************************************/ +#include #include #include #include "bnep_int.h" #include "device/include/controller.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#include - using bluetooth::Uuid; /******************************************************************************/ @@ -170,8 +169,8 @@ void bnep_send_conn_req(tBNEP_CONN* p_bcb) { BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE); uint8_t *p, *p_start; - BNEP_TRACE_DEBUG("%s: sending setup req with dst uuid %s", __func__, - p_bcb->dst_uuid.ToString().c_str()); + LOG_VERBOSE("%s: sending setup req with dst uuid %s", __func__, + p_bcb->dst_uuid.ToString().c_str()); p_buf->offset = L2CAP_MIN_OFFSET; p = p_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -199,9 +198,9 @@ void bnep_send_conn_req(tBNEP_CONN* p_bcb) { memcpy(p, p_bcb->src_uuid.To128BitBE().data(), Uuid::kNumBytes128); p += Uuid::kNumBytes128; } else { - BNEP_TRACE_ERROR("%s: uuid: %s, invalid length: %zu", __func__, - p_bcb->dst_uuid.ToString().c_str(), - p_bcb->dst_uuid.GetShortestRepresentationSize()); + LOG_ERROR("%s: uuid: %s, invalid length: %zu", __func__, + p_bcb->dst_uuid.ToString().c_str(), + p_bcb->dst_uuid.GetShortestRepresentationSize()); } p_buf->len = (uint16_t)(p - p_start); @@ -211,18 +210,18 @@ void bnep_send_conn_req(tBNEP_CONN* p_bcb) { /******************************************************************************* * - * Function bnep_send_conn_responce + * Function bnep_send_conn_response * * Description This function sends a BNEP setup response to peer * * Returns void * ******************************************************************************/ -void bnep_send_conn_responce(tBNEP_CONN* p_bcb, uint16_t resp_code) { +void bnep_send_conn_response(tBNEP_CONN* p_bcb, uint16_t resp_code) { BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE); uint8_t* p; - LOG_DEBUG("BNEP - bnep_send_conn_responce for CID: 0x%x", p_bcb->l2cap_cid); + LOG_DEBUG("BNEP - bnep_send_conn_response for CID: 0x%x", p_bcb->l2cap_cid); p_buf->offset = L2CAP_MIN_OFFSET; p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -254,7 +253,7 @@ void bnepu_send_peer_our_filters(tBNEP_CONN* p_bcb) { uint8_t* p; uint16_t xx; - BNEP_TRACE_DEBUG("BNEP sending peer our filters"); + LOG_VERBOSE("BNEP sending peer our filters"); p_buf->offset = L2CAP_MIN_OFFSET; p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -296,7 +295,7 @@ void bnepu_send_peer_our_multi_filters(tBNEP_CONN* p_bcb) { uint8_t* p; uint16_t xx; - BNEP_TRACE_DEBUG("BNEP sending peer our multicast filters"); + LOG_VERBOSE("BNEP sending peer our multicast filters"); p_buf->offset = L2CAP_MIN_OFFSET; p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -339,7 +338,7 @@ void bnepu_send_peer_filter_rsp(tBNEP_CONN* p_bcb, uint16_t response_code) { BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE); uint8_t* p; - BNEP_TRACE_DEBUG("BNEP sending filter response"); + LOG_VERBOSE("BNEP sending filter response"); p_buf->offset = L2CAP_MIN_OFFSET; p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -370,9 +369,8 @@ void bnep_send_command_not_understood(tBNEP_CONN* p_bcb, uint8_t cmd_code) { BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE); uint8_t* p; - BNEP_TRACE_EVENT( - "BNEP - bnep_send_command_not_understood for CID: 0x%x, cmd 0x%x", - p_bcb->l2cap_cid, cmd_code); + LOG_VERBOSE("BNEP - bnep_send_command_not_understood for CID: 0x%x, cmd 0x%x", + p_bcb->l2cap_cid, cmd_code); p_buf->offset = L2CAP_MIN_OFFSET; p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -536,7 +534,7 @@ void bnep_process_setup_conn_req(tBNEP_CONN* p_bcb, uint8_t* p_setup, p_bcb->con_state != BNEP_STATE_SEC_CHECKING && p_bcb->con_state != BNEP_STATE_CONNECTED) { LOG_ERROR("BNEP - setup request in bad state %d", p_bcb->con_state); - bnep_send_conn_responce(p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED); + bnep_send_conn_response(p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED); return; } @@ -554,7 +552,7 @@ void bnep_process_setup_conn_req(tBNEP_CONN* p_bcb, uint8_t* p_setup, (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) { LOG_ERROR("BNEP - setup request when we are originator state:%hu", p_bcb->con_state); - bnep_send_conn_responce(p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED); + bnep_send_conn_response(p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED); return; } @@ -577,7 +575,7 @@ void bnep_process_setup_conn_req(tBNEP_CONN* p_bcb, uint8_t* p_setup, if (p_bcb->con_state == BNEP_STATE_CONNECTED && p_bcb->src_uuid == p_bcb->prv_src_uuid && p_bcb->dst_uuid == p_bcb->prv_dst_uuid) { - bnep_send_conn_responce(p_bcb, BNEP_SETUP_CONN_OK); + bnep_send_conn_response(p_bcb, BNEP_SETUP_CONN_OK); return; } } else if (len == Uuid::kNumBytes32) { @@ -596,7 +594,7 @@ void bnep_process_setup_conn_req(tBNEP_CONN* p_bcb, uint8_t* p_setup, p_setup += len; } else { LOG_ERROR("BNEP - Bad UID len %d in ConnReq", len); - bnep_send_conn_responce(p_bcb, BNEP_SETUP_INVALID_UUID_SIZE); + bnep_send_conn_response(p_bcb, BNEP_SETUP_INVALID_UUID_SIZE); return; } @@ -623,18 +621,17 @@ void bnep_process_setup_conn_responce(tBNEP_CONN* p_bcb, uint8_t* p_setup) { tBNEP_RESULT resp; uint16_t resp_code; - BNEP_TRACE_DEBUG("BNEP received setup responce"); + LOG_VERBOSE("BNEP received setup responce"); /* The state should be either SETUP or CONNECTED */ if (p_bcb->con_state != BNEP_STATE_CONN_SETUP) { /* Should we disconnect ? */ - BNEP_TRACE_ERROR("BNEP - setup response in bad state %d", p_bcb->con_state); + LOG_ERROR("BNEP - setup response in bad state %d", p_bcb->con_state); return; } /* Check if we are the originator */ if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) { - BNEP_TRACE_ERROR("BNEP - setup response when we are not originator", - p_bcb->con_state); + LOG_ERROR("BNEP - setup response when we are not originator"); return; } @@ -662,7 +659,7 @@ void bnep_process_setup_conn_responce(tBNEP_CONN* p_bcb, uint8_t* p_setup) { /* Check the responce code */ if (resp_code != BNEP_SETUP_CONN_OK) { if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) { - BNEP_TRACE_EVENT("BNEP - role change response is %d", resp_code); + LOG_VERBOSE("BNEP - role change response is %d", resp_code); /* Restore the earlier BNEP status */ p_bcb->con_state = BNEP_STATE_CONNECTED; @@ -680,7 +677,7 @@ void bnep_process_setup_conn_responce(tBNEP_CONN* p_bcb, uint8_t* p_setup) { return; } else { - BNEP_TRACE_ERROR("BNEP - setup response %d is not OK", resp_code); + LOG_ERROR("BNEP - setup response %d is not OK", resp_code); L2CA_DisconnectReq(p_bcb->l2cap_cid); @@ -715,8 +712,8 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, if (p == NULL || rem_len == NULL) { if (rem_len != NULL) *rem_len = 0; - BNEP_TRACE_DEBUG("%s: invalid packet: p = %p rem_len = %p", __func__, p, - rem_len); + LOG_VERBOSE("%s: invalid packet: p = %p rem_len = %p", __func__, p, + rem_len); return NULL; } uint16_t rem_len_orig = *rem_len; @@ -731,19 +728,19 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, control_type = *p++; *rem_len = *rem_len - 1; - BNEP_TRACE_EVENT( + LOG_VERBOSE( "%s: BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d", __func__, *rem_len, is_ext, control_type); switch (control_type) { case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD: if (*rem_len < 1) { - BNEP_TRACE_ERROR( + LOG_ERROR( "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD with bad length", __func__); goto bad_packet_length; } - BNEP_TRACE_ERROR( + LOG_ERROR( "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD for pkt type: %d", __func__, *p); p++; @@ -752,14 +749,14 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, case BNEP_SETUP_CONNECTION_REQUEST_MSG: if (*rem_len < 1) { - BNEP_TRACE_ERROR( + LOG_ERROR( "%s: Received BNEP_SETUP_CONNECTION_REQUEST_MSG with bad length", __func__); goto bad_packet_length; } len = *p++; if (*rem_len < ((2 * len) + 1)) { - BNEP_TRACE_ERROR( + LOG_ERROR( "%s: Received BNEP_SETUP_CONNECTION_REQUEST_MSG with bad length", __func__); goto bad_packet_length; @@ -771,7 +768,7 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, case BNEP_SETUP_CONNECTION_RESPONSE_MSG: if (*rem_len < 2) { - BNEP_TRACE_ERROR( + LOG_ERROR( "%s: Received BNEP_SETUP_CONNECTION_RESPONSE_MSG with bad length", __func__); goto bad_packet_length; @@ -783,16 +780,14 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, case BNEP_FILTER_NET_TYPE_SET_MSG: if (*rem_len < 2) { - BNEP_TRACE_ERROR( - "%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length", - __func__); + LOG_ERROR("%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length", + __func__); goto bad_packet_length; } BE_STREAM_TO_UINT16(len, p); if (*rem_len < (len + 2)) { - BNEP_TRACE_ERROR( - "%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length", - __func__); + LOG_ERROR("%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length", + __func__); goto bad_packet_length; } bnepu_process_peer_filter_set(p_bcb, p, len); @@ -802,7 +797,7 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, case BNEP_FILTER_NET_TYPE_RESPONSE_MSG: if (*rem_len < 2) { - BNEP_TRACE_ERROR( + LOG_ERROR( "%s: Received BNEP_FILTER_NET_TYPE_RESPONSE_MSG with bad length", __func__); goto bad_packet_length; @@ -814,16 +809,14 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, case BNEP_FILTER_MULTI_ADDR_SET_MSG: if (*rem_len < 2) { - BNEP_TRACE_ERROR( - "%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length", - __func__); + LOG_ERROR("%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length", + __func__); goto bad_packet_length; } BE_STREAM_TO_UINT16(len, p); if (*rem_len < (len + 2)) { - BNEP_TRACE_ERROR( - "%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length", - __func__); + LOG_ERROR("%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length", + __func__); goto bad_packet_length; } bnepu_process_peer_multicast_filter_set(p_bcb, p, len); @@ -833,7 +826,7 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG: if (*rem_len < 2) { - BNEP_TRACE_ERROR( + LOG_ERROR( "%s: Received BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG with bad length", __func__); goto bad_packet_length; @@ -844,8 +837,7 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, break; default: - BNEP_TRACE_ERROR("%s: BNEP - bad ctl pkt type: %d", __func__, - control_type); + LOG_ERROR("%s: BNEP - bad ctl pkt type: %d", __func__, control_type); bnep_send_command_not_understood(p_bcb, control_type); if (is_ext && (ext_len > 0)) { if (*rem_len < (ext_len - 1)) { @@ -859,8 +851,8 @@ uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p, return p; bad_packet_length: - BNEP_TRACE_ERROR("%s: bad control packet length: original=%d remaining=%d", - __func__, rem_len_orig, *rem_len); + LOG_ERROR("%s: bad control packet length: original=%d remaining=%d", __func__, + rem_len_orig, *rem_len); *rem_len = 0; return NULL; } @@ -885,15 +877,15 @@ void bnepu_process_peer_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filters, if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) { - BNEP_TRACE_DEBUG( + LOG_VERBOSE( "BNEP received filter set from peer when there is no connection"); return; } - BNEP_TRACE_DEBUG("BNEP received filter set from peer"); + LOG_VERBOSE("BNEP received filter set from peer"); /* Check for length not a multiple of 4 */ if (len & 3) { - BNEP_TRACE_EVENT("BNEP - bad filter len: %d", len); + LOG_VERBOSE("BNEP - bad filter len: %d", len); bnepu_send_peer_filter_rsp(p_bcb, BNEP_FILTER_CRL_BAD_RANGE); return; } @@ -949,18 +941,17 @@ void bnepu_process_peer_filter_rsp(tBNEP_CONN* p_bcb, uint8_t* p_data) { uint16_t resp_code; tBNEP_RESULT result; - BNEP_TRACE_DEBUG("BNEP received filter responce"); + LOG_VERBOSE("BNEP received filter responce"); /* The state should be CONNECTED */ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) { - BNEP_TRACE_ERROR("BNEP - filter response in bad state %d", - p_bcb->con_state); + LOG_ERROR("BNEP - filter response in bad state %d", p_bcb->con_state); return; } /* Check if we are the originator */ if (!(p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND)) { - BNEP_TRACE_ERROR("BNEP - filter response when not expecting"); + LOG_ERROR("BNEP - filter response when not expecting"); return; } @@ -992,18 +983,18 @@ void bnepu_process_multicast_filter_rsp(tBNEP_CONN* p_bcb, uint8_t* p_data) { uint16_t resp_code; tBNEP_RESULT result; - BNEP_TRACE_DEBUG("BNEP received multicast filter responce"); + LOG_VERBOSE("BNEP received multicast filter responce"); /* The state should be CONNECTED */ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) { - BNEP_TRACE_ERROR("BNEP - multicast filter response in bad state %d", - p_bcb->con_state); + LOG_ERROR("BNEP - multicast filter response in bad state %d", + p_bcb->con_state); return; } /* Check if we are the originator */ if (!(p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND)) { - BNEP_TRACE_ERROR("BNEP - multicast filter response when not expecting"); + LOG_ERROR("BNEP - multicast filter response when not expecting"); return; } @@ -1040,20 +1031,20 @@ void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb, if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) { - BNEP_TRACE_DEBUG( + LOG_VERBOSE( "BNEP received multicast filter set from peer when there is no " "connection"); return; } if (len % 12) { - BNEP_TRACE_EVENT("BNEP - bad filter len: %d", len); + LOG_VERBOSE("BNEP - bad filter len: %d", len); bnepu_send_peer_multicast_filter_rsp(p_bcb, BNEP_FILTER_CRL_BAD_RANGE); return; } if (len > (BNEP_MAX_MULTI_FILTERS * 2 * BD_ADDR_LEN)) { - BNEP_TRACE_EVENT("BNEP - Too many filters"); + LOG_VERBOSE("BNEP - Too many filters"); bnepu_send_peer_multicast_filter_rsp(p_bcb, BNEP_FILTER_CRL_MAX_REACHED); return; } @@ -1076,11 +1067,12 @@ void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb, } p_bcb->rcvd_mcast_filters = num_filters; + p_temp_filters = p_filters; for (xx = 0; xx < num_filters; xx++) { - memcpy(p_bcb->rcvd_mcast_filter_start[xx].address, p_filters, BD_ADDR_LEN); - memcpy(p_bcb->rcvd_mcast_filter_end[xx].address, p_filters + BD_ADDR_LEN, + memcpy(p_bcb->rcvd_mcast_filter_start[xx].address, p_temp_filters, BD_ADDR_LEN); + memcpy(p_bcb->rcvd_mcast_filter_end[xx].address, p_temp_filters + BD_ADDR_LEN, BD_ADDR_LEN); - p_filters += (BD_ADDR_LEN * 2); + p_temp_filters += (BD_ADDR_LEN * 2); /* Check if any of the ranges have all zeros as both starting and ending * addresses */ @@ -1093,7 +1085,7 @@ void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb, } } - BNEP_TRACE_EVENT("BNEP multicast filters %d", p_bcb->rcvd_mcast_filters); + LOG_VERBOSE("BNEP multicast filters %d", p_bcb->rcvd_mcast_filters); bnepu_send_peer_multicast_filter_rsp(p_bcb, resp_code); if (bnep_cb.p_mfilter_ind_cb) @@ -1114,7 +1106,7 @@ void bnepu_send_peer_multicast_filter_rsp(tBNEP_CONN* p_bcb, BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE); uint8_t* p; - BNEP_TRACE_DEBUG("BNEP sending multicast filter response %d", response_code); + LOG_VERBOSE("BNEP sending multicast filter response %d", response_code); p_buf->offset = L2CAP_MIN_OFFSET; p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -1155,9 +1147,8 @@ void bnep_sec_check_complete(const RawAddress* bd_addr, tBT_TRANSPORT trasnport, /* check if the port is still waiting for security to complete */ if (p_bcb->con_state != BNEP_STATE_SEC_CHECKING) { - BNEP_TRACE_ERROR( - "BNEP Connection in wrong state %d when security is completed", - p_bcb->con_state); + LOG_ERROR("BNEP Connection in wrong state %d when security is completed", + p_bcb->con_state); return; } @@ -1179,7 +1170,7 @@ void bnep_sec_check_complete(const RawAddress* bd_addr, tBT_TRANSPORT trasnport, p_bcb->src_uuid, is_role_change); } else { /* Profile didn't register connection indication call back */ - bnep_send_conn_responce(p_bcb, resp_code); + bnep_send_conn_response(p_bcb, resp_code); bnep_connected(p_bcb); } } @@ -1236,7 +1227,7 @@ tBNEP_RESULT bnep_is_packet_allowed(tBNEP_CONN* p_bcb, } if (i == p_bcb->rcvd_num_filters) { - BNEP_TRACE_DEBUG("Ignoring protocol 0x%x in BNEP data write", proto); + LOG_VERBOSE("Ignoring protocol 0x%x in BNEP data write", proto); return BNEP_IGNORE_CMD; } } diff --git a/system/stack/btm/ble_advertiser_hci_interface.cc b/system/stack/btm/ble_advertiser_hci_interface.cc deleted file mode 100644 index 1f12ef11cbb916f94f6829cd70717fce7a834918..0000000000000000000000000000000000000000 --- a/system/stack/btm/ble_advertiser_hci_interface.cc +++ /dev/null @@ -1,801 +0,0 @@ -/****************************************************************************** - * - * Copyright 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "ble_advertiser_hci_interface.h" - -#include -#include -#include -#include - -#include -#include - -#include "btm_api.h" -#include "btm_ble_api.h" -#include "btm_int_types.h" -#include "device/include/controller.h" -#include "osi/include/log.h" -#include "types/raw_address.h" - -#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8 -#define BTM_BLE_MULTI_ADV_ENB_LEN 3 -#define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24 -#define BTM_BLE_AD_DATA_LEN 31 -#define BTM_BLE_MULTI_ADV_WRITE_DATA_LEN (BTM_BLE_AD_DATA_LEN + 3) - -#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE 1 -#define HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD 6 -#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS 15 -#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP 31 -#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA 31 - -using status_cb = BleAdvertiserHciInterface::status_cb; - -using hci_cmd_cb = base::OnceCallback; -void btu_hcif_send_cmd_with_cb(const base::Location& posted_from, - uint16_t opcode, uint8_t* params, - uint8_t params_len, hci_cmd_cb cb); - -namespace { -BleAdvertiserHciInterface* instance = nullptr; - -void btm_ble_multi_adv_vsc_cmpl_cback(uint8_t expected_opcode, - status_cb command_complete, - uint8_t* param, uint16_t param_len) { - uint8_t status, subcode; - - // All multi-adv commands respond with status and inst_id. - LOG_ASSERT(param_len == 2) << "Received bad response length to multi-adv VSC"; - - STREAM_TO_UINT8(status, param); - STREAM_TO_UINT8(subcode, param); - - VLOG(1) << "subcode = " << +subcode << ", status: " << +status; - - if (expected_opcode != subcode) { - LOG(ERROR) << "unexpected VSC cmpl, expect: " << +subcode - << " get: " << +expected_opcode; - return; - } - - command_complete.Run(status); -} - -void parameters_response_parser(BleAdvertiserHciInterface::parameters_cb cb, - uint8_t* ret_params, uint16_t ret_params_len) { - uint8_t status; - int8_t tx_power; - - uint8_t* pp = ret_params; - if (ret_params_len < 2) { - LOG(ERROR) << "unexpected ret_params_len: " << ret_params_len; - return; - } - - STREAM_TO_UINT8(status, pp); - STREAM_TO_INT8(tx_power, pp); - - cb.Run(status, tx_power); -} - -void known_tx_pwr(BleAdvertiserHciInterface::parameters_cb cb, int8_t tx_power, - uint8_t status) { - cb.Run(status, tx_power); -} - -class BleAdvertiserVscHciInterfaceImpl : public BleAdvertiserHciInterface { - void SendAdvCmd(const base::Location& posted_from, uint8_t param_len, - uint8_t* param_buf, status_cb command_complete) { - btu_hcif_send_cmd_with_cb(posted_from, HCI_BLE_MULTI_ADV, param_buf, - param_len, - base::Bind(&btm_ble_multi_adv_vsc_cmpl_cback, - param_buf[0], command_complete)); - } - - void ReadInstanceCount( - base::Callback cb) override { - cb.Run(BTM_BleMaxMultiAdvInstanceCount()); - } - - void SetAdvertisingEventObserver( - AdvertisingEventObserver* observer) override { - this->advertising_event_observer = observer; - } - - void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min, - uint32_t adv_int_max, uint8_t channel_map, - uint8_t own_address_type, const RawAddress& own_address, - uint8_t peer_address_type, const RawAddress& peer_address, - uint8_t filter_policy, int8_t tx_power, - uint8_t primary_phy, uint8_t secondary_max_skip, - uint8_t secondary_phy, uint8_t advertising_sid, - uint8_t scan_request_notify_enable, - parameters_cb command_complete) override { - VLOG(1) << __func__; - uint8_t param[BTM_BLE_MULTI_ADV_SET_PARAM_LEN]; - memset(param, 0, BTM_BLE_MULTI_ADV_SET_PARAM_LEN); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_PARAM); - UINT16_TO_STREAM(pp, adv_int_min); - UINT16_TO_STREAM(pp, adv_int_max); - - if (properties == 0x0013) { - UINT8_TO_STREAM(pp, 0x00); // ADV_IND - } else if (properties == 0x0012) { - UINT8_TO_STREAM(pp, 0x02); // ADV_SCAN_IND - } else if (properties == 0x0010) { - UINT8_TO_STREAM(pp, 0x03); // ADV_NONCONN_IND - } else { - LOG(ERROR) << "Unsupported advertisement type selected:" << std::hex - << properties; - command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT, 0); - return; - } - - UINT8_TO_STREAM(pp, own_address_type); - BDADDR_TO_STREAM(pp, own_address); - UINT8_TO_STREAM(pp, peer_address_type); - BDADDR_TO_STREAM(pp, peer_address); - UINT8_TO_STREAM(pp, channel_map); - UINT8_TO_STREAM(pp, filter_policy); - UINT8_TO_STREAM(pp, handle); - INT8_TO_STREAM(pp, tx_power); - - SendAdvCmd( - FROM_HERE, BTM_BLE_MULTI_ADV_SET_PARAM_LEN, param, - base::Bind(&known_tx_pwr, std::move(command_complete), tx_power)); - } - - void SetAdvertisingData(uint8_t handle, uint8_t operation, - uint8_t fragment_preference, uint8_t data_length, - uint8_t* data, status_cb command_complete) override { - VLOG(1) << __func__; - uint8_t param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN]; - memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN); - - if (data_length > BTM_BLE_AD_DATA_LEN) { - LOG(ERROR) << __func__ - << ": data_length=" << static_cast(data_length) - << ", is longer than size limit " << BTM_BLE_AD_DATA_LEN; - data_length = BTM_BLE_AD_DATA_LEN; - } - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_WRITE_ADV_DATA); - UINT8_TO_STREAM(pp, data_length); - ARRAY_TO_STREAM(pp, data, data_length); - param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1] = handle; - - SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, param, - command_complete); - } - - void SetScanResponseData(uint8_t handle, uint8_t operation, - uint8_t fragment_preference, - uint8_t scan_response_data_length, - uint8_t* scan_response_data, - status_cb command_complete) override { - VLOG(1) << __func__; - uint8_t param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN]; - memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN); - - if (scan_response_data_length > BTM_BLE_AD_DATA_LEN) { - LOG(ERROR) << __func__ << ": scan_response_data_length=" - << static_cast(scan_response_data_length) - << ", is longer than size limit " << BTM_BLE_AD_DATA_LEN; - scan_response_data_length = BTM_BLE_AD_DATA_LEN; - } - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA); - UINT8_TO_STREAM(pp, scan_response_data_length); - ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length); - param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1] = handle; - - SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, param, - command_complete); - } - - void SetRandomAddress(uint8_t handle, const RawAddress& random_address, - status_cb command_complete) override { - VLOG(1) << __func__; - uint8_t param[BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN]; - memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR); - BDADDR_TO_STREAM(pp, random_address); - UINT8_TO_STREAM(pp, handle); - - SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN, param, - command_complete); - } - - void Enable(uint8_t enable, std::vector sets, - status_cb command_complete) override { - VLOG(1) << __func__; - - if (sets.size() != 1) { - LOG(ERROR) << "Trying to enable multiple sets in VSC implemenetation!"; - command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT); - return; - } - SetEnableData& set = sets[0]; - - if (set.max_extended_advertising_events) { - command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT); - return; - } - - uint8_t param[BTM_BLE_MULTI_ADV_ENB_LEN]; - memset(param, 0, BTM_BLE_MULTI_ADV_ENB_LEN); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_ENB); - UINT8_TO_STREAM(pp, enable); - UINT8_TO_STREAM(pp, set.handle); - - SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_ENB_LEN, param, - command_complete); - } - - void SetPeriodicAdvertisingParameters(uint8_t, uint16_t, uint16_t, uint16_t, - status_cb command_complete) override { - LOG(INFO) << __func__ << " VSC can't do periodic advertising"; - command_complete.Run(HCI_ERR_ILLEGAL_COMMAND); - } - - void SetPeriodicAdvertisingData(uint8_t, uint8_t, uint8_t, uint8_t*, - status_cb command_complete) override { - LOG(INFO) << __func__ << " VSC can't do periodic advertising"; - command_complete.Run(HCI_ERR_ILLEGAL_COMMAND); - } - - void SetPeriodicAdvertisingEnable(bool, bool, uint8_t, - status_cb command_complete) override { - LOG(INFO) << __func__ << " VSC can't do periodic advertising"; - command_complete.Run(HCI_ERR_ILLEGAL_COMMAND); - } - - bool QuirkAdvertiserZeroHandle() override { - // Android BT HCI Requirements version 0.96 and below specify that handle 0 - // is equal to standard HCI interface, and should be accessed using non-VSC - // commands. - LOG(INFO) << "QuirkAdvertiserZeroHandle in use"; - return true; - } - - void RemoveAdvertisingSet(uint8_t handle, - status_cb command_complete) override { - // VSC Advertising don't have remove method. - command_complete.Run(0); - } - - public: - static void VendorSpecificEventCback(uint8_t length, const uint8_t* p) { - VLOG(1) << __func__; - - LOG_ASSERT(p); - uint8_t sub_event, adv_inst, change_reason; - uint16_t conn_handle; - - if (length < 1) { - return; - } - - STREAM_TO_UINT8(sub_event, p); - length--; - - if (sub_event != HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG || length < 4) { - return; - } - - STREAM_TO_UINT8(adv_inst, p); - STREAM_TO_UINT8(change_reason, p); - STREAM_TO_UINT16(conn_handle, p); - - AdvertisingEventObserver* observer = - ((BleAdvertiserVscHciInterfaceImpl*)BleAdvertiserHciInterface::Get()) - ->advertising_event_observer; - if (observer) - observer->OnAdvertisingSetTerminated(change_reason, adv_inst, conn_handle, - 0x00); - } - - private: - AdvertisingEventObserver* advertising_event_observer = nullptr; -}; - -void adv_cmd_cmpl_cback(status_cb cb, uint8_t* return_parameters, - uint16_t return_parameters_length) { - uint8_t status = *return_parameters; - cb.Run(status); -} - -class BleAdvertiserLegacyHciInterfaceImpl : public BleAdvertiserHciInterface { - void SendAdvCmd(const base::Location& posted_from, uint16_t opcode, - uint8_t* param_buf, uint8_t param_buf_len, - status_cb command_complete) { - btu_hcif_send_cmd_with_cb( - posted_from, opcode, param_buf, param_buf_len, - base::Bind(&adv_cmd_cmpl_cback, command_complete)); - } - - void ReadInstanceCount( - base::Callback cb) override { - cb.Run(1); - } - - void SetAdvertisingEventObserver( - AdvertisingEventObserver* observer) override { - this->advertising_event_observer = observer; - } - - void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min, - uint32_t adv_int_max, uint8_t channel_map, - uint8_t own_address_type, - const RawAddress& /* own_address */, - uint8_t peer_address_type, const RawAddress& peer_address, - uint8_t filter_policy, int8_t tx_power, - uint8_t primary_phy, uint8_t secondary_max_skip, - uint8_t secondary_phy, uint8_t advertising_sid, - uint8_t scan_request_notify_enable, - parameters_cb command_complete) override { - VLOG(1) << __func__; - - uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS]; - - uint8_t* pp = param; - UINT16_TO_STREAM(pp, adv_int_min); - UINT16_TO_STREAM(pp, adv_int_max); - - if (properties == 0x0013) { - UINT8_TO_STREAM(pp, 0x00); // ADV_IND - } else if (properties == 0x0012) { - UINT8_TO_STREAM(pp, 0x02); // ADV_SCAN_IND - } else if (properties == 0x0010) { - UINT8_TO_STREAM(pp, 0x03); // ADV_NONCONN_IND - } else { - LOG(ERROR) << "Unsupported advertisement type selected:" << std::hex - << properties; - command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT, 0); - return; - } - - UINT8_TO_STREAM(pp, own_address_type); - UINT8_TO_STREAM(pp, peer_address_type); - BDADDR_TO_STREAM(pp, peer_address); - UINT8_TO_STREAM(pp, channel_map); - UINT8_TO_STREAM(pp, filter_policy); - - SendAdvCmd( - FROM_HERE, HCI_BLE_WRITE_ADV_PARAMS, param, - HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS, - base::Bind(&known_tx_pwr, std::move(command_complete), (int8_t)0)); - } - - void SetAdvertisingData(uint8_t handle, uint8_t operation, - uint8_t fragment_preference, uint8_t data_length, - uint8_t* data, status_cb command_complete) override { - VLOG(1) << __func__; - - uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1]; - - if (data_length > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA) { - LOG(ERROR) << __func__ - << ": data_length=" << static_cast(data_length) - << ", is longer than size limit " - << HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA; - data_length = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA; - } - - uint8_t* pp = param; - memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1); - UINT8_TO_STREAM(pp, data_length); - ARRAY_TO_STREAM(pp, data, data_length); - - SendAdvCmd(FROM_HERE, HCI_BLE_WRITE_ADV_DATA, param, - HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1, command_complete); - } - - void SetScanResponseData(uint8_t handle, uint8_t operation, - uint8_t fragment_preference, - uint8_t scan_response_data_length, - uint8_t* scan_response_data, - status_cb command_complete) override { - VLOG(1) << __func__; - uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1]; - - if (scan_response_data_length > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA) { - LOG(ERROR) << __func__ << ": scan_response_data_length=" - << static_cast(scan_response_data_length) - << ", is longer than size limit " - << HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA; - scan_response_data_length = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA; - } - - uint8_t* pp = param; - memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1); - UINT8_TO_STREAM(pp, scan_response_data_length); - ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length); - - SendAdvCmd(FROM_HERE, HCI_BLE_WRITE_SCAN_RSP_DATA, param, - HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1, command_complete); - } - - void SetRandomAddress(uint8_t handle, const RawAddress& random_address, - status_cb command_complete) override { - VLOG(1) << __func__; - - uint8_t param[HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD]; - - uint8_t* pp = param; - BDADDR_TO_STREAM(pp, random_address); - - SendAdvCmd(FROM_HERE, HCI_BLE_WRITE_RANDOM_ADDR, param, - HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD, command_complete); - } - - void Enable(uint8_t enable, std::vector sets, - status_cb command_complete) override { - VLOG(1) << __func__; - - if (sets.size() != 1) { - LOG(ERROR) << "Trying to enable multiple sets in legacy implemenetation!"; - command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT); - return; - } - - SetEnableData& set = sets[0]; - if (set.max_extended_advertising_events) { - command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT); - return; - } - - uint8_t param[HCIC_PARAM_SIZE_WRITE_ADV_ENABLE]; - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, enable); - - SendAdvCmd(FROM_HERE, HCI_BLE_WRITE_ADV_ENABLE, param, - HCIC_PARAM_SIZE_WRITE_ADV_ENABLE, command_complete); - } - - void SetPeriodicAdvertisingParameters(uint8_t, uint16_t, uint16_t, uint16_t, - status_cb command_complete) override { - LOG(INFO) << __func__ << "Legacy can't do periodic advertising"; - command_complete.Run(HCI_ERR_ILLEGAL_COMMAND); - } - - void SetPeriodicAdvertisingData(uint8_t, uint8_t, uint8_t, uint8_t*, - status_cb command_complete) override { - LOG(INFO) << __func__ << "Legacy can't do periodic advertising"; - command_complete.Run(HCI_ERR_ILLEGAL_COMMAND); - } - - void SetPeriodicAdvertisingEnable(bool, bool, uint8_t, - status_cb command_complete) override { - LOG(INFO) << __func__ << "Legacy can't do periodic advertising"; - command_complete.Run(HCI_ERR_ILLEGAL_COMMAND); - } - - void RemoveAdvertisingSet(uint8_t handle, - status_cb command_complete) override { - // Legacy Advertising don't have remove method. - command_complete.Run(0); - } - - public: - void OnAdvertisingSetTerminated(uint8_t status, uint16_t connection_handle) { - VLOG(1) << __func__; - - AdvertisingEventObserver* observer = this->advertising_event_observer; - if (observer) - observer->OnAdvertisingSetTerminated(status, 0 /*advertising_handle*/, - connection_handle, 0); - } - - private: - AdvertisingEventObserver* advertising_event_observer = nullptr; -}; - -class BleAdvertiserHciExtendedImpl : public BleAdvertiserHciInterface { - void SendAdvCmd(const base::Location& posted_from, uint16_t opcode, - uint8_t* param_buf, uint8_t param_buf_len, - status_cb command_complete) { - btu_hcif_send_cmd_with_cb( - posted_from, opcode, param_buf, param_buf_len, - base::Bind(&adv_cmd_cmpl_cback, command_complete)); - } - - void ReadInstanceCount( - base::Callback cb) override { - cb.Run(controller_get_interface() - ->get_ble_number_of_supported_advertising_sets()); - } - - void SetAdvertisingEventObserver( - AdvertisingEventObserver* observer) override { - this->advertising_event_observer = observer; - } - - void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min, - uint32_t adv_int_max, uint8_t channel_map, - uint8_t own_address_type, - const RawAddress& /* own_address */, - uint8_t peer_address_type, const RawAddress& peer_address, - uint8_t filter_policy, int8_t tx_power, - uint8_t primary_phy, uint8_t secondary_max_skip, - uint8_t secondary_phy, uint8_t advertising_sid, - uint8_t scan_request_notify_enable, - parameters_cb command_complete) override { - VLOG(1) << __func__; - const uint16_t HCI_LE_SET_EXT_ADVERTISING_PARAM_LEN = 25; - uint8_t param[HCI_LE_SET_EXT_ADVERTISING_PARAM_LEN]; - memset(param, 0, HCI_LE_SET_EXT_ADVERTISING_PARAM_LEN); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, handle); - UINT16_TO_STREAM(pp, properties); - UINT24_TO_STREAM(pp, adv_int_min); - UINT24_TO_STREAM(pp, adv_int_max); - UINT8_TO_STREAM(pp, channel_map); - UINT8_TO_STREAM(pp, own_address_type); - UINT8_TO_STREAM(pp, peer_address_type); - BDADDR_TO_STREAM(pp, peer_address); - UINT8_TO_STREAM(pp, filter_policy); - INT8_TO_STREAM(pp, tx_power); - UINT8_TO_STREAM(pp, primary_phy); - UINT8_TO_STREAM(pp, secondary_max_skip); - UINT8_TO_STREAM(pp, secondary_phy); - UINT8_TO_STREAM(pp, advertising_sid); - UINT8_TO_STREAM(pp, scan_request_notify_enable); - - btu_hcif_send_cmd_with_cb( - FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_PARAM, param, - HCI_LE_SET_EXT_ADVERTISING_PARAM_LEN, - base::Bind(parameters_response_parser, std::move(command_complete))); - } - - void SetAdvertisingData(uint8_t handle, uint8_t operation, - uint8_t fragment_preference, uint8_t data_length, - uint8_t* data, status_cb command_complete) override { - VLOG(1) << __func__; - - const uint16_t cmd_length = 4 + data_length; - uint8_t param[cmd_length]; - memset(param, 0, cmd_length); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, handle); - UINT8_TO_STREAM(pp, operation); - UINT8_TO_STREAM(pp, fragment_preference); - UINT8_TO_STREAM(pp, data_length); - ARRAY_TO_STREAM(pp, data, data_length); - - SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_DATA, param, cmd_length, - command_complete); - } - - void SetScanResponseData(uint8_t handle, uint8_t operation, - uint8_t fragment_preference, - uint8_t scan_response_data_length, - uint8_t* scan_response_data, - status_cb command_complete) override { - VLOG(1) << __func__; - - const uint16_t cmd_length = 4 + scan_response_data_length; - uint8_t param[cmd_length]; - memset(param, 0, cmd_length); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, handle); - UINT8_TO_STREAM(pp, operation); - UINT8_TO_STREAM(pp, fragment_preference); - UINT8_TO_STREAM(pp, scan_response_data_length); - ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length); - - SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_SCAN_RESP, param, - cmd_length, command_complete); - } - - void SetRandomAddress(uint8_t handle, const RawAddress& random_address, - status_cb command_complete) override { - VLOG(1) << __func__; - const int LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN = 7; - - uint8_t param[LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN]; - memset(param, 0, LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, handle); - BDADDR_TO_STREAM(pp, random_address); - - SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_RANDOM_ADDRESS, param, - LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN, command_complete); - } - - void Enable(uint8_t enable, std::vector sets, - status_cb command_complete) override { - VLOG(1) << __func__; - - /* cmd_length = header_size + num_of_of_advertiser * size_per_advertiser */ - const uint16_t cmd_length = 2 + sets.size() * 4; - uint8_t param[cmd_length]; - memset(param, 0, cmd_length); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, enable); - - UINT8_TO_STREAM(pp, sets.size()); - for (const SetEnableData& set : sets) { - UINT8_TO_STREAM(pp, set.handle); - UINT16_TO_STREAM(pp, set.duration); - UINT8_TO_STREAM(pp, set.max_extended_advertising_events); - } - - SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_ENABLE, param, cmd_length, - command_complete); - } - - void SetPeriodicAdvertisingParameters(uint8_t handle, - uint16_t periodic_adv_int_min, - uint16_t periodic_adv_int_max, - uint16_t periodic_properties, - status_cb command_complete) override { - VLOG(1) << __func__; - const uint16_t HCI_LE_SET_PRIODIC_ADVERTISING_PARAM_LEN = 7; - uint8_t param[HCI_LE_SET_PRIODIC_ADVERTISING_PARAM_LEN]; - memset(param, 0, HCI_LE_SET_PRIODIC_ADVERTISING_PARAM_LEN); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, handle); - UINT16_TO_STREAM(pp, periodic_adv_int_min); - UINT16_TO_STREAM(pp, periodic_adv_int_max); - UINT16_TO_STREAM(pp, periodic_properties); - - SendAdvCmd(FROM_HERE, HCI_LE_SET_PERIODIC_ADVERTISING_PARAM, param, - HCI_LE_SET_PRIODIC_ADVERTISING_PARAM_LEN, command_complete); - } - - void SetPeriodicAdvertisingData(uint8_t handle, uint8_t operation, - uint8_t adv_data_length, uint8_t* adv_data, - status_cb command_complete) override { - VLOG(1) << __func__; - const uint16_t HCI_LE_SET_PRIODIC_ADVERTISING_DATA_LEN = - 3 + adv_data_length; - uint8_t param[HCI_LE_SET_PRIODIC_ADVERTISING_DATA_LEN]; - memset(param, 0, HCI_LE_SET_PRIODIC_ADVERTISING_DATA_LEN); - uint8_t* pp = param; - UINT8_TO_STREAM(pp, handle); - UINT8_TO_STREAM(pp, operation); - UINT8_TO_STREAM(pp, adv_data_length); - ARRAY_TO_STREAM(pp, adv_data, adv_data_length); - SendAdvCmd(FROM_HERE, HCI_LE_SET_PERIODIC_ADVERTISING_DATA, param, - HCI_LE_SET_PRIODIC_ADVERTISING_DATA_LEN, command_complete); - } - - void SetPeriodicAdvertisingEnable(bool enable, bool include_adi, - uint8_t handle, - status_cb command_complete) override { - VLOG(1) << __func__; - const uint16_t HCI_LE_ENABLE_PRIODIC_ADVERTISEMENT_LEN = 2; - uint8_t param[HCI_LE_ENABLE_PRIODIC_ADVERTISEMENT_LEN]; - memset(param, 0, HCI_LE_ENABLE_PRIODIC_ADVERTISEMENT_LEN); - uint8_t* pp = param; - const uint8_t enable_field = - (enable ? 1 : 0) | ((include_adi ? 1 : 0) << 1); - UINT8_TO_STREAM(pp, enable_field); - UINT8_TO_STREAM(pp, handle); - SendAdvCmd(FROM_HERE, HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE, param, - HCI_LE_ENABLE_PRIODIC_ADVERTISEMENT_LEN, command_complete); - } - - void RemoveAdvertisingSet(uint8_t handle, - status_cb command_complete) override { - VLOG(1) << __func__; - - const uint16_t cmd_length = 1; - uint8_t param[cmd_length]; - memset(param, 0, cmd_length); - - uint8_t* pp = param; - UINT8_TO_STREAM(pp, handle); - - SendAdvCmd(FROM_HERE, HCI_LE_REMOVE_ADVERTISING_SET, param, cmd_length, - command_complete); - } - - public: - void OnAdvertisingSetTerminated(uint8_t length, uint8_t* p) { - VLOG(1) << __func__; - LOG_ASSERT(p); - uint8_t status, advertising_handle, num_completed_extended_adv_events; - uint16_t conn_handle; - - STREAM_TO_UINT8(status, p); - STREAM_TO_UINT8(advertising_handle, p); - STREAM_TO_UINT16(conn_handle, p); - STREAM_TO_UINT8(num_completed_extended_adv_events, p); - - conn_handle = conn_handle & 0x0FFF; // only 12 bits meaningful - - AdvertisingEventObserver* observer = this->advertising_event_observer; - if (observer) - observer->OnAdvertisingSetTerminated(status, advertising_handle, - conn_handle, - num_completed_extended_adv_events); - } - - private: - AdvertisingEventObserver* advertising_event_observer = nullptr; -}; - -} // namespace - -void btm_le_on_advertising_set_terminated(uint8_t* p, uint16_t length) { - if (BleAdvertiserHciInterface::Get()) { - ((BleAdvertiserHciExtendedImpl*)BleAdvertiserHciInterface::Get()) - ->OnAdvertisingSetTerminated(length, p); - } -} - -bool legacy_advertising_in_use = false; -void btm_ble_advertiser_notify_terminated_legacy(uint8_t status, - uint16_t connection_handle) { - if (BleAdvertiserHciInterface::Get() && legacy_advertising_in_use) { - ((BleAdvertiserLegacyHciInterfaceImpl*)BleAdvertiserHciInterface::Get()) - ->OnAdvertisingSetTerminated(status, connection_handle); - } -} - -void BleAdvertiserHciInterface::Initialize() { - VLOG(1) << __func__; - LOG_ASSERT(instance == nullptr) << "Was already initialized."; - - if (controller_get_interface()->supports_ble_extended_advertising()) { - LOG(INFO) << "Extended advertising will be in use"; - instance = new BleAdvertiserHciExtendedImpl(); - } else if (BTM_BleMaxMultiAdvInstanceCount()) { - LOG(INFO) << "VSC advertising will be in use"; - instance = new BleAdvertiserVscHciInterfaceImpl(); - BTM_RegisterForVSEvents( - BleAdvertiserVscHciInterfaceImpl::VendorSpecificEventCback, true); - } else { - LOG(INFO) << "Legacy advertising will be in use"; - instance = new BleAdvertiserLegacyHciInterfaceImpl(); - legacy_advertising_in_use = true; - } -} - -BleAdvertiserHciInterface* BleAdvertiserHciInterface::Get() { return instance; } - -void BleAdvertiserHciInterface::CleanUp() { - VLOG(1) << __func__; - - if (BTM_BleMaxMultiAdvInstanceCount()) { - BTM_RegisterForVSEvents( - BleAdvertiserVscHciInterfaceImpl::VendorSpecificEventCback, false); - } - - delete instance; - instance = nullptr; -} diff --git a/system/stack/btm/ble_advertiser_hci_interface.h b/system/stack/btm/ble_advertiser_hci_interface.h deleted file mode 100644 index 0b95cf9a6c82445513917d5b9321fd5c7c77a6af..0000000000000000000000000000000000000000 --- a/system/stack/btm/ble_advertiser_hci_interface.h +++ /dev/null @@ -1,115 +0,0 @@ -/****************************************************************************** - * - * Copyright 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#ifndef BLE_ADVERTISER_HCI_INTERFACE_H -#define BLE_ADVERTISER_HCI_INTERFACE_H - -#include - -#include - -#include "stack/include/bt_types.h" -#include "types/raw_address.h" - -/* This class is an abstraction of HCI commands used for managing - * advertisements. Please see VSC HCI SPEC at - * https://static.googleusercontent.com/media/source.android.com/en//devices/Android-6.0-Bluetooth-HCI-Reqs.pdf - * and Bluetooth 5.0 "Advertising Extension" feature for more details */ -class BleAdvertiserHciInterface { - public: - using status_cb = base::Callback; - using parameters_cb = - base::Callback; - - static void Initialize(); - static BleAdvertiserHciInterface* Get(); - static void CleanUp(); - - virtual ~BleAdvertiserHciInterface() = default; - - class AdvertisingEventObserver { - public: - virtual ~AdvertisingEventObserver() = default; - virtual void OnAdvertisingSetTerminated( - uint8_t status, uint8_t advertising_handle, uint16_t connection_handle, - uint8_t num_completed_extended_adv_events) = 0; - }; - - virtual void SetAdvertisingEventObserver( - AdvertisingEventObserver* observer) = 0; - virtual void ReadInstanceCount( - base::Callback cb) = 0; - virtual void SetParameters( - uint8_t handle, uint16_t properties, uint32_t adv_int_min, - uint32_t adv_int_max, uint8_t channel_map, uint8_t own_address_type, - const RawAddress& own_address, uint8_t peer_address_type, - const RawAddress& peer_address, uint8_t filter_policy, int8_t tx_power, - uint8_t primary_phy, uint8_t secondary_max_skip, uint8_t secondary_phy, - uint8_t advertising_sid, uint8_t scan_request_notify_enable, - parameters_cb command_complete) = 0; - virtual void SetAdvertisingData(uint8_t handle, uint8_t operation, - uint8_t fragment_preference, - uint8_t data_length, uint8_t* data, - status_cb command_complete) = 0; - virtual void SetScanResponseData(uint8_t handle, uint8_t operation, - uint8_t fragment_preference, - uint8_t scan_response_data_length, - uint8_t* scan_response_data, - status_cb command_complete) = 0; - virtual void SetRandomAddress(uint8_t handle, - const RawAddress& random_address, - status_cb command_complete) = 0; - - struct SetEnableData { - uint8_t handle; - uint16_t duration; - uint8_t max_extended_advertising_events; - }; - virtual void Enable(uint8_t enable, std::vector sets, - status_cb command_complete) = 0; - - void Enable(uint8_t enable, uint8_t handle, uint16_t duration, - uint8_t max_extended_advertising_events, - status_cb command_complete) { - std::vector enableData; - enableData.emplace_back(SetEnableData{ - .handle = handle, - .duration = duration, - .max_extended_advertising_events = max_extended_advertising_events}); - Enable(enable, enableData, command_complete); - }; - virtual void SetPeriodicAdvertisingParameters(uint8_t handle, - uint16_t periodic_adv_int_min, - uint16_t periodic_adv_int_max, - uint16_t periodic_properties, - status_cb command_complete) = 0; - virtual void SetPeriodicAdvertisingData(uint8_t handle, uint8_t operation, - uint8_t adv_data_length, - uint8_t* adv_data, - status_cb command_complete) = 0; - virtual void SetPeriodicAdvertisingEnable(bool enable, bool include_adi, - uint8_t handle, - status_cb command_complete) = 0; - virtual void RemoveAdvertisingSet(uint8_t handle, - status_cb command_complete) = 0; - - // Some implementation don't behave well when handle value 0 is used. - virtual bool QuirkAdvertiserZeroHandle() { return 0; } -}; - -#endif // BLE_ADVERTISER_HCI_INTERFACE_H diff --git a/system/stack/btm/ble_scanner_hci_interface.cc b/system/stack/btm/ble_scanner_hci_interface.cc index a5ca993c847d3fa5ab2bf98694aebef7fe8bf05e..79842d9a0357b5a67739feed753a9e532cd05825 100644 --- a/system/stack/btm/ble_scanner_hci_interface.cc +++ b/system/stack/btm/ble_scanner_hci_interface.cc @@ -20,10 +20,10 @@ #include #include -#include "acl_api.h" #include "btm_api.h" #include "device/include/controller.h" -#include "osi/include/log.h" +#include "stack/include/bt_types.h" +#include "stack/include/hcimsgs.h" #include "types/raw_address.h" namespace { @@ -36,7 +36,6 @@ static void status_callback(base::Callback cb, uint8_t* data, LOG_ASSERT(len == 1) << "Received bad response length: " << len; STREAM_TO_UINT8(status, data); - DVLOG(1) << __func__ << " Received status_cb"; cb.Run(status); } @@ -55,9 +54,8 @@ static void status_handle_callback(base::Callback cb, STREAM_TO_UINT16(handle, pp); handle = handle & 0x0EFF; - DVLOG(1) << __func__ << " Received status_handle_callback"; } else { - DVLOG(1) << __func__ << " hci response error code: " << int{status}; + VLOG(1) << __func__ << " hci response error code: " << int{status}; } cb.Run(status, handle); } @@ -73,7 +71,6 @@ static void status_handle_callback(base::Callback cb, class BleScannerImplBase : public BleScannerHciInterface { public: void SetScanEventObserver(ScanEventObserver* observer) override { - VLOG(1) << __func__; // TODO: Support multiple observers if ever needed. scan_event_observer = observer; } @@ -82,28 +79,24 @@ class BleScannerImplBase : public BleScannerHciInterface { const RawAddress& adv_addr, uint16_t skip_num, uint16_t sync_timeout, uint8_t sync_cte_type) override { - VLOG(1) << __func__; btsnd_hcic_ble_periodic_advertising_create_sync( options, set_id, adv_addr_type, adv_addr, skip_num, sync_timeout, sync_cte_type); } void PeriodicScanCancelStart(status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hcic_ble_periodic_advertising_create_sync_cancel( base::Bind(&status_callback, std::move(command_complete))); } void PeriodicScanTerminate(uint16_t sync_handle, status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hcic_ble_periodic_advertising_terminate_sync( sync_handle, base::Bind(&status_callback, std::move(command_complete))); } void PeriodicScanResultEvtEnable(uint16_t sync_handle, bool enable, status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hcic_ble_set_periodic_advertising_receive_enable( sync_handle, enable, base::Bind(&status_callback, std::move(command_complete))); @@ -111,7 +104,6 @@ class BleScannerImplBase : public BleScannerHciInterface { void PeriodicAdvertiserListGetSize( BleScannerHciInterface::list_size_cb command_complete) override { - VLOG(1) << __func__; command_complete.Run( controller_get_interface()->get_ble_periodic_advertiser_list_size()); } @@ -119,7 +111,6 @@ class BleScannerImplBase : public BleScannerHciInterface { void PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type, RawAddress& adv_addr, uint8_t set_id, status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hci_ble_add_device_to_periodic_advertiser_list( adv_addr_type, adv_addr, set_id, base::Bind(&status_callback, std::move(command_complete))); @@ -128,14 +119,12 @@ class BleScannerImplBase : public BleScannerHciInterface { void PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type, RawAddress& adv_addr, uint8_t set_id, status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hci_ble_remove_device_from_periodic_advertiser_list( adv_addr_type, adv_addr, set_id, base::Bind(&status_callback, std::move(command_complete))); } void PeriodicAdvertiserListClear(status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hci_ble_clear_periodic_advertiser_list( base::Bind(&status_callback, std::move(command_complete))); }; @@ -143,7 +132,6 @@ class BleScannerImplBase : public BleScannerHciInterface { void PeriodicAdvSyncTransfer( const RawAddress& bd_addr, uint16_t service_data, uint16_t sync_handle, BleScannerHciInterface::handle_cb command_complete) override { - VLOG(1) << __func__; uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE); if (acl_handle == HCI_INVALID_HANDLE) { @@ -160,7 +148,6 @@ class BleScannerImplBase : public BleScannerHciInterface { void PeriodicAdvSetInfoTransfer(const RawAddress& bd_addr, uint16_t service_data, uint8_t adv_handle, handle_cb command_complete) override { - VLOG(1) << __func__; uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE); if (acl_handle == HCI_INVALID_HANDLE) { @@ -178,7 +165,6 @@ class BleScannerImplBase : public BleScannerHciInterface { uint16_t skip, uint16_t sync_timeout, uint8_t cte_type, bool set_defaults, status_cb command_complete) override { - VLOG(1) << __func__; uint16_t acl_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE); if (acl_handle == HCI_INVALID_HANDLE) { @@ -234,7 +220,6 @@ class BleScannerListImpl : public virtual BleScannerImplBase { void PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type, RawAddress& adv_addr, uint8_t set_id, status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hci_ble_add_device_to_periodic_advertiser_list( adv_addr_type, adv_addr, set_id, base::Bind(&status_callback, std::move(command_complete))); @@ -243,14 +228,12 @@ class BleScannerListImpl : public virtual BleScannerImplBase { void PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type, RawAddress& adv_addr, uint8_t set_id, status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hci_ble_remove_device_from_periodic_advertiser_list( adv_addr_type, adv_addr, set_id, base::Bind(&status_callback, std::move(command_complete))); } void PeriodicAdvertiserListClear(status_cb command_complete) override { - VLOG(1) << __func__; btsnd_hci_ble_clear_periodic_advertiser_list( base::Bind(&status_callback, std::move(command_complete))); }; @@ -320,7 +303,6 @@ class BleScannerCompleteImpl : public BleScannerListImpl, } // namespace void BleScannerHciInterface::Initialize() { - VLOG(1) << __func__; LOG_ASSERT(instance == nullptr) << "Was already initialized."; if ((controller_get_interface()->get_ble_periodic_advertiser_list_size()) && @@ -344,89 +326,6 @@ void BleScannerHciInterface::Initialize() { BleScannerHciInterface* BleScannerHciInterface::Get() { return instance; } void BleScannerHciInterface::CleanUp() { - VLOG(1) << __func__; - delete instance; instance = nullptr; } - -void btm_ble_process_periodic_adv_sync_est_evt(uint8_t data_len, - const uint8_t* data) { - uint16_t sync_handle, adv_interval; - uint8_t status, adv_sid, adv_addr_type, adv_phy, adv_clock_accuracy; - RawAddress adv_addr; - - VLOG(1) << __func__; - - LOG_ASSERT(data_len == 15) - << "Malformed LE Periodic Advertising Sync Est. Event from controller"; - - STREAM_TO_UINT8(status, data); - STREAM_TO_UINT16(sync_handle, data); - STREAM_TO_UINT8(adv_sid, data); - STREAM_TO_UINT8(adv_addr_type, data); - STREAM_TO_BDADDR(adv_addr, data); - STREAM_TO_UINT8(adv_phy, data); - STREAM_TO_UINT16(adv_interval, data); - STREAM_TO_UINT8(adv_clock_accuracy, data); - - if (BleScannerHciInterface::Get()) { - static_cast(BleScannerHciInterface::Get()) - ->OnPeriodicAdvSyncEstablished(status, sync_handle, adv_sid, - adv_addr_type, adv_addr, adv_phy, - adv_interval, adv_clock_accuracy); - } -} - -void btm_ble_process_periodic_adv_pkt(uint8_t data_len, const uint8_t* data) { - const uint8_t* p = data; - uint16_t sync_handle; - uint8_t tx_power, cte_type, pkt_data_status, pkt_data_len; - int8_t rssi; - - LOG_ASSERT(data_len >= 7) - << "Malformed LE Periodic Advertising Report Event from controller"; - - STREAM_TO_UINT16(sync_handle, p); - STREAM_TO_UINT8(tx_power, p); - STREAM_TO_INT8(rssi, p); - STREAM_TO_UINT8(cte_type, p); - STREAM_TO_UINT8(pkt_data_status, p); - STREAM_TO_UINT8(pkt_data_len, p); - - const uint8_t* pkt_data = p; - p += pkt_data_len; - - if (p > data + data_len) { - LOG(ERROR) << __func__ << " Invalid pkt_data_len: " << int{pkt_data_len}; - return; - } - - if (rssi >= 21 && rssi <= 126) { - LOG(ERROR) << __func__ - << " bad rssi value in advertising report: " << int{rssi}; - } - - if (BleScannerHciInterface::Get()) { - static_cast(BleScannerHciInterface::Get()) - ->OnPeriodicScanResult(sync_handle, tx_power, rssi, cte_type, - pkt_data_status, pkt_data_len, pkt_data); - } -} - -void btm_ble_process_periodic_adv_sync_lost_evt(uint8_t data_len, - uint8_t* data) { - uint16_t sync_handle; - - if (data_len < 2) { - LOG(ERROR) << "Bogus event packet, too short"; - return; - } - - STREAM_TO_UINT16(sync_handle, data); - - if (BleScannerHciInterface::Get()) { - static_cast(BleScannerHciInterface::Get()) - ->OnPeriodicSyncLost(sync_handle); - } -} diff --git a/system/stack/btm/ble_scanner_hci_interface.h b/system/stack/btm/ble_scanner_hci_interface.h index 31080016a400928f5ac02663ff80778af87d465a..7a2e19910d1a3d24ce02bdaa7de4ed128d0eb91d 100644 --- a/system/stack/btm/ble_scanner_hci_interface.h +++ b/system/stack/btm/ble_scanner_hci_interface.h @@ -22,7 +22,6 @@ #include -#include "stack/include/bt_types.h" #include "types/raw_address.h" class BleScannerHciInterface { diff --git a/system/stack/btm/btm_ble.cc b/system/stack/btm/btm_ble.cc index be985574f2c455ffcf43902d824cb054a84f131e..7fba96985ace838f5b8814ec49864a449d0acc3f 100644 --- a/system/stack/btm/btm_ble.cc +++ b/system/stack/btm/btm_ble.cc @@ -23,568 +23,86 @@ * ******************************************************************************/ -#define LOG_TAG "bt_btm_ble" - -#include -#include +#define LOG_TAG "ble" #include -#include "btif/include/btif_storage.h" -#include "device/include/controller.h" -#include "main/shim/btm_api.h" -#include "main/shim/l2c_api.h" -#include "main/shim/shim.h" -#include "openssl/mem.h" -#include "osi/include/allocator.h" -#include "osi/include/properties.h" -#include "stack/btm/btm_dev.h" +#include "base/functional/bind.h" +#include "os/log.h" #include "stack/btm/btm_int_types.h" -#include "stack/btm/security_device_record.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" -#include "stack/eatt/eatt.h" +#include "stack/gatt/gatt_int.h" #include "stack/include/acl_api.h" -#include "stack/include/bt_octets.h" #include "stack/include/bt_types.h" -#include "stack/include/btm_api.h" -#include "stack/include/btm_log_history.h" -#include "stack/include/btu.h" +#include "stack/include/btm_ble_api.h" +#include "stack/include/btu_hcif.h" #include "stack/include/gatt_api.h" -#include "stack/include/l2cap_security_interface.h" -#include "stack/include/l2cdefs.h" -#include "stack/include/smp_api.h" -#include "stack/include/smp_api_types.h" -#include "types/raw_address.h" +#include "stack/include/hcimsgs.h" extern tBTM_CB btm_cb; -bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, - const RawAddress& new_pseudo_addr); -void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle, - uint8_t tx_phy, uint8_t rx_phy); - -#ifndef PROPERTY_BLE_PRIVACY_ENABLED -#define PROPERTY_BLE_PRIVACY_ENABLED "bluetooth.core.gap.le.privacy.enabled" -#endif - -namespace { -constexpr char kBtmLogTag[] = "SEC"; -} - -// Pairing parameters defined in Vol 3, Part H, Chapter 3.5.1 - 3.5.2 -// All present in the exact decimal values, not hex -// Ex: bluetooth.core.smp.le.ctkd.initiator_key_distribution 15(0x0f) -static const char kPropertyCtkdAuthRequest[] = - "bluetooth.core.smp.le.ctkd.auth_request"; -static const char kPropertyCtkdIoCapabilities[] = - "bluetooth.core.smp.le.ctkd.io_capabilities"; -// Vol 3, Part H, Chapter 3.6.1, Figure 3.11 -// |EncKey(1)|IdKey(1)|SignKey(1)|LinkKey(1)|Reserved(4)| -static const char kPropertyCtkdInitiatorKeyDistribution[] = - "bluetooth.core.smp.le.ctkd.initiator_key_distribution"; -static const char kPropertyCtkdResponderKeyDistribution[] = - "bluetooth.core.smp.le.ctkd.responder_key_distribution"; -static const char kPropertyCtkdMaxKeySize[] = - "bluetooth.core.smp.le.ctkd.max_key_size"; - -/******************************************************************************/ -/* External Function to be called by other modules */ -/******************************************************************************/ -void BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, - tBLE_ADDR_TYPE addr_type) { - LOG_DEBUG("dev_type=0x%x", dev_type); - - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (!p_dev_rec) { - p_dev_rec = btm_sec_allocate_dev_rec(); - - p_dev_rec->bd_addr = bd_addr; - p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR); - p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE); - - /* update conn params, use default value for background connection params */ - p_dev_rec->conn_params.min_conn_int = BTM_BLE_CONN_PARAM_UNDEF; - p_dev_rec->conn_params.max_conn_int = BTM_BLE_CONN_PARAM_UNDEF; - p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_PARAM_UNDEF; - p_dev_rec->conn_params.peripheral_latency = BTM_BLE_CONN_PARAM_UNDEF; - - LOG_DEBUG("Device added, handle=0x%x, p_dev_rec=%p, bd_addr=%s", - p_dev_rec->ble_hci_handle, p_dev_rec, ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - } - - memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME)); - - p_dev_rec->device_type |= dev_type; - if (is_ble_addr_type_known(addr_type)) { - p_dev_rec->ble.SetAddressType(addr_type); - } else { - LOG_WARN( - "Please do not update device record from anonymous le advertisement"); - } - - /* sync up with the Inq Data base*/ - tBTM_INQ_INFO* p_info = BTM_InqDbRead(bd_addr); - if (p_info) { - p_info->results.ble_addr_type = p_dev_rec->ble.AddressType(); - p_dev_rec->device_type |= p_info->results.device_type; - LOG_DEBUG("InqDb device_type =0x%x addr_type=0x%x", p_dev_rec->device_type, - p_info->results.ble_addr_type); - p_info->results.device_type = p_dev_rec->device_type; - } -} - -/******************************************************************************* - * - * Function BTM_GetRemoteDeviceName - * - * Description This function is called to get the dev name of remote device - * from NV - * - * Returns TRUE if success; otherwise failed. - * - ******************************************************************************/ -bool BTM_GetRemoteDeviceName(const RawAddress& bd_addr, BD_NAME bd_name) { - BTM_TRACE_DEBUG("%s", __func__); - bool ret = FALSE; - bt_bdname_t bdname; - bt_property_t prop_name; - BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME, - sizeof(bt_bdname_t), &bdname); - - if (btif_storage_get_remote_device_property(&bd_addr, &prop_name) == - BT_STATUS_SUCCESS) { - APPL_TRACE_DEBUG("%s, NV name = %s", __func__, bdname.name); - strncpy((char*)bd_name, (char*)bdname.name, BD_NAME_LEN + 1); - ret = TRUE; - } - return ret; -} - -/******************************************************************************* - * - * Function BTM_SecAddBleKey - * - * Description Add/modify LE device information. This function will be - * normally called during host startup to restore all required - * information stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * p_le_key - LE key values. - * key_type - LE SMP key type. -* - * Returns true if added OK, else false - * - ******************************************************************************/ -void BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (!p_dev_rec || !p_le_key || - (key_type != BTM_LE_KEY_PENC && key_type != BTM_LE_KEY_PID && - key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC && - key_type != BTM_LE_KEY_LCSRK && key_type != BTM_LE_KEY_LID)) { - LOG(WARNING) << __func__ - << " Wrong Type, or No Device record for bdaddr: " << bd_addr - << ", Type: " << key_type; - return; - } - - LOG_DEBUG("Adding BLE key device:%s key_type:%hhu", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), - key_type); - - btm_sec_save_le_key(bd_addr, key_type, p_le_key, false); - // Only set peer irk. Local irk is always the same. - if (key_type == BTM_LE_KEY_PID) { - btm_ble_resolving_list_load_dev(*p_dev_rec); - } -} - -/******************************************************************************* - * - * Function BTM_BleLoadLocalKeys - * - * Description Local local identity key, encryption root or sign counter. - * - * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, - * BTM_BLE_KEY_TYPE_ER - * or BTM_BLE_KEY_TYPE_COUNTER. - * p_key: pointer to the key. - * - * Returns non2. - * - ******************************************************************************/ -void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) { - tBTM_DEVCB* p_devcb = &btm_cb.devcb; - BTM_TRACE_DEBUG("%s", __func__); - if (p_key != NULL) { - switch (key_type) { - case BTM_BLE_KEY_TYPE_ID: - memcpy(&p_devcb->id_keys, &p_key->id_keys, - sizeof(tBTM_BLE_LOCAL_ID_KEYS)); - break; - - case BTM_BLE_KEY_TYPE_ER: - p_devcb->ble_encryption_key_value = p_key->er; - break; - - default: - BTM_TRACE_ERROR("unknow local key type: %d", key_type); - break; - } - } -} - -/** Returns local device encryption root (ER) */ -const Octet16& BTM_GetDeviceEncRoot() { - return btm_cb.devcb.ble_encryption_key_value; -} - -/** Returns local device identity root (IR). */ -const Octet16& BTM_GetDeviceIDRoot() { return btm_cb.devcb.id_keys.irk; } - -/** Return local device DHK. */ -const Octet16& BTM_GetDeviceDHK() { return btm_cb.devcb.id_keys.dhk; } - -/******************************************************************************* - * - * Function BTM_SecurityGrant - * - * Description This function is called to grant security process. - * - * Parameters bd_addr - peer device bd address. - * res - result of the operation BTM_SUCCESS if success. - * Otherwise, BTM_REPEATED_ATTEMPTS if too many - * attempts. - * - * Returns None - * - ******************************************************************************/ -void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res) { - const tSMP_STATUS res_smp = - (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS; - BTM_LogHistory(kBtmLogTag, bd_addr, "Granted", - base::StringPrintf("passkey_status:%s", - smp_status_text(res_smp).c_str())); - - BTM_TRACE_DEBUG("BTM_SecurityGrant"); - SMP_SecurityGrant(bd_addr, res_smp); -} - -/******************************************************************************* - * - * Function BTM_BlePasskeyReply - * - * Description This function is called after Security Manager submitted - * passkey request to the application. - * - * Parameters: bd_addr - Address of the device for which passkey was - * requested - * res - result of the operation BTM_SUCCESS if success - * key_len - length in bytes of the Passkey - * p_passkey - pointer to array with the passkey - * - ******************************************************************************/ -void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res, - uint32_t passkey) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec == NULL) { - BTM_TRACE_ERROR("Passkey reply to Unknown device"); - return; - } - - const tSMP_STATUS res_smp = - (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL; - BTM_LogHistory(kBtmLogTag, bd_addr, "Passkey reply", - base::StringPrintf("transport:%s authenticate_status:%s", - bt_transport_text(BT_TRANSPORT_LE).c_str(), - smp_status_text(res_smp).c_str())); - - p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; - BTM_TRACE_DEBUG("BTM_BlePasskeyReply"); - SMP_PasskeyReply(bd_addr, res_smp, passkey); -} - -/******************************************************************************* - * - * Function BTM_BleConfirmReply - * - * Description This function is called after Security Manager submitted - * numeric comparison request to the application. - * - * Parameters: bd_addr - Address of the device with which numeric - * comparison was requested - * res - comparison result BTM_SUCCESS if success - * - ******************************************************************************/ -void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec == NULL) { - BTM_TRACE_ERROR("Passkey reply to Unknown device"); - return; - } - const tSMP_STATUS res_smp = - (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL; - - BTM_LogHistory(kBtmLogTag, bd_addr, "Confirm reply", - base::StringPrintf( - "transport:%s numeric_comparison_authenticate_status:%s", - bt_transport_text(BT_TRANSPORT_LE).c_str(), - smp_status_text(res_smp).c_str())); - - p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; - BTM_TRACE_DEBUG("%s", __func__); - SMP_ConfirmReply(bd_addr, res_smp); -} - /******************************************************************************* * - * Function BTM_BleOobDataReply + * Function BTM_BleReceiverTest * - * Description This function is called to provide the OOB data for - * SMP in response to BTM_LE_OOB_REQ_EVT + * Description This function is called to start the LE Receiver test * - * Parameters: bd_addr - Address of the peer device - * res - result of the operation SMP_SUCCESS if success - * p_data - oob data, depending on transport and - * capabilities. - * Might be "Simple Pairing Randomizer", or - * "Security Manager TK Value". + * Parameter rx_freq - Frequency Range + * p_cmd_cmpl_cback - Command Complete callback * ******************************************************************************/ -void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len, - uint8_t* p_data) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec == NULL) { - BTM_TRACE_ERROR("%s: Unknown device", __func__); - return; - } - - const tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL; - BTM_LogHistory(kBtmLogTag, bd_addr, "Oob data reply", - base::StringPrintf("transport:%s authenticate_status:%s", - bt_transport_text(BT_TRANSPORT_LE).c_str(), - smp_status_text(res_smp).c_str())); +void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback) { + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; - p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; - SMP_OobDataReply(bd_addr, res_smp, len, p_data); + btsnd_hcic_ble_receiver_test(rx_freq); } /******************************************************************************* * - * Function BTM_BleSecureConnectionOobDataReply - * - * Description This function is called to provide the OOB data for - * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection - * data is available - * - * Parameters: bd_addr - Address of the peer device - * p_c - pointer to Confirmation. - * p_r - pointer to Randomizer + * Function BTM_BleTransmitterTest * - ******************************************************************************/ -void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr, - uint8_t* p_c, uint8_t* p_r) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec == NULL) { - BTM_TRACE_ERROR("%s: Unknown device", __func__); - return; - } - - BTM_LogHistory( - kBtmLogTag, bd_addr, "Oob data reply", - base::StringPrintf("transport:%s", - bt_transport_text(BT_TRANSPORT_LE).c_str())); - - p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; - - tSMP_SC_OOB_DATA oob; - memset(&oob, 0, sizeof(tSMP_SC_OOB_DATA)); - - oob.peer_oob_data.present = true; - memcpy(&oob.peer_oob_data.randomizer, p_r, OCTET16_LEN); - memcpy(&oob.peer_oob_data.commitment, p_c, OCTET16_LEN); - oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.AddressType(); - oob.peer_oob_data.addr_rcvd_from.bda = bd_addr; - - SMP_SecureConnectionOobDataReply((uint8_t*)&oob); -} - -/******************************************************** - * - * Function BTM_BleSetPrefConnParams - * - * Description Set a peripheral's preferred connection parameters + * Description This function is called to start the LE Transmitter test * - * Parameters: bd_addr - BD address of the peripheral - * scan_interval: scan interval - * scan_window: scan window - * min_conn_int - minimum preferred connection interval - * max_conn_int - maximum preferred connection interval - * peripheral_latency - preferred peripheral latency - * supervision_tout - preferred supervision timeout - * - * Returns void + * Parameter tx_freq - Frequency Range + * test_data_len - Length in bytes of payload data in each + * packet + * packet_payload - Pattern to use in the payload + * p_cmd_cmpl_cback - Command Complete callback * ******************************************************************************/ -void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int, - uint16_t max_conn_int, - uint16_t peripheral_latency, - uint16_t supervision_tout) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - - BTM_TRACE_API( - "BTM_BleSetPrefConnParams min: %u max: %u latency: %u \ - tout: %u", - min_conn_int, max_conn_int, peripheral_latency, supervision_tout); - - if (BTM_BLE_ISVALID_PARAM(min_conn_int, BTM_BLE_CONN_INT_MIN, - BTM_BLE_CONN_INT_MAX) && - BTM_BLE_ISVALID_PARAM(max_conn_int, BTM_BLE_CONN_INT_MIN, - BTM_BLE_CONN_INT_MAX) && - BTM_BLE_ISVALID_PARAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN, - BTM_BLE_CONN_SUP_TOUT_MAX) && - (peripheral_latency <= BTM_BLE_CONN_LATENCY_MAX || - peripheral_latency == BTM_BLE_CONN_PARAM_UNDEF)) { - if (p_dev_rec) { - /* expect conn int and stout and peripheral latency to be updated all - * together - */ - if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF || - max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) { - if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) - p_dev_rec->conn_params.min_conn_int = min_conn_int; - else - p_dev_rec->conn_params.min_conn_int = max_conn_int; - - if (max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) - p_dev_rec->conn_params.max_conn_int = max_conn_int; - else - p_dev_rec->conn_params.max_conn_int = min_conn_int; - - if (peripheral_latency != BTM_BLE_CONN_PARAM_UNDEF) - p_dev_rec->conn_params.peripheral_latency = peripheral_latency; - else - p_dev_rec->conn_params.peripheral_latency = - BTM_BLE_CONN_PERIPHERAL_LATENCY_DEF; - - if (supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) - p_dev_rec->conn_params.supervision_tout = supervision_tout; - else - p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF; - } - - } else { - BTM_TRACE_ERROR("Unknown Device, setting rejected"); - } - } else { - BTM_TRACE_ERROR("Illegal Connection Parameters"); - } +void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len, + uint8_t packet_payload, + tBTM_CMPL_CB* p_cmd_cmpl_cback) { + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; + btsnd_hcic_ble_transmitter_test(tx_freq, test_data_len, packet_payload); } /******************************************************************************* * - * Function BTM_ReadDevInfo + * Function BTM_BleTestEnd * - * Description This function is called to read the device/address type - * of BD address. + * Description This function is called to stop the in-progress TX or RX + * test * - * Parameter remote_bda: remote device address - * p_dev_type: output parameter to read the device type. - * p_addr_type: output parameter to read the address type. + * Parameter p_cmd_cmpl_cback - Command complete callback * ******************************************************************************/ -void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, - tBLE_ADDR_TYPE* p_addr_type) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(remote_bda); - tBTM_INQ_INFO* p_inq_info = BTM_InqDbRead(remote_bda); +void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) { + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; - *p_addr_type = BLE_ADDR_PUBLIC; - - if (!p_dev_rec) { - *p_dev_type = BT_DEVICE_TYPE_BREDR; - /* Check with the BT manager if details about remote device are known */ - if (p_inq_info != NULL) { - *p_dev_type = p_inq_info->results.device_type; - *p_addr_type = p_inq_info->results.ble_addr_type; - } else { - /* unknown device, assume BR/EDR */ - BTM_TRACE_DEBUG("btm_find_dev_type - unknown device, BR/EDR assumed"); - } - } else /* there is a security device record exisitng */ - { - /* new inquiry result, merge device type in security device record */ - if (p_inq_info) { - p_dev_rec->device_type |= p_inq_info->results.device_type; - if (is_ble_addr_type_known(p_inq_info->results.ble_addr_type)) - p_dev_rec->ble.SetAddressType(p_inq_info->results.ble_addr_type); - else - LOG_WARN( - "Please do not update device record from anonymous le " - "advertisement"); - } - - if (p_dev_rec->bd_addr == remote_bda && - p_dev_rec->ble.pseudo_addr == remote_bda) { - *p_dev_type = p_dev_rec->device_type; - *p_addr_type = p_dev_rec->ble.AddressType(); - } else if (p_dev_rec->ble.pseudo_addr == remote_bda) { - *p_dev_type = BT_DEVICE_TYPE_BLE; - *p_addr_type = p_dev_rec->ble.AddressType(); - } else /* matching static adddress only */ { - if (p_dev_rec->device_type != BT_DEVICE_TYPE_UNKNOWN) { - *p_dev_type = p_dev_rec->device_type; - } else { - LOG_WARN("device_type not set; assuming BR/EDR"); - *p_dev_type = BT_DEVICE_TYPE_BREDR; - } - *p_addr_type = BLE_ADDR_PUBLIC; - } - } - LOG_DEBUG("Determining device_type:%s addr_type:%s", - DeviceTypeText(*p_dev_type).c_str(), - AddressTypeText(*p_addr_type).c_str()); + btsnd_hcic_ble_test_end(); } /******************************************************************************* - * - * Function BTM_ReadConnectedTransportAddress - * - * Description This function is called to read the paired device/address - * type of other device paired corresponding to the BD_address - * - * Parameter remote_bda: remote device address, carry out the transport - * address - * transport: active transport - * - * Return true if an active link is identified; false otherwise - * + * Internal Functions ******************************************************************************/ -bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda, - tBT_TRANSPORT transport) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(*remote_bda); +void btm_ble_test_command_complete(uint8_t* p) { + tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_le_test_cmd_cmpl_cb; - /* if no device can be located, return */ - if (p_dev_rec == NULL) return false; + btm_cb.devcb.p_le_test_cmd_cmpl_cb = NULL; - if (transport == BT_TRANSPORT_BR_EDR) { - if (BTM_IsAclConnectionUp(p_dev_rec->bd_addr, transport)) { - *remote_bda = p_dev_rec->bd_addr; - return true; - } else if (p_dev_rec->device_type & BT_DEVICE_TYPE_BREDR) { - *remote_bda = p_dev_rec->bd_addr; - } else - *remote_bda = RawAddress::kEmpty; - return false; - } - - if (transport == BT_TRANSPORT_LE) { - *remote_bda = p_dev_rec->ble.pseudo_addr; - if (BTM_IsAclConnectionUp(p_dev_rec->ble.pseudo_addr, transport)) - return true; - else - return false; + if (p_cb) { + (*p_cb)(p); } - - return false; } /******************************************************************************* @@ -610,70 +128,6 @@ bool BTM_UseLeLink(const RawAddress& bd_addr) { return (dev_type == BT_DEVICE_TYPE_BLE); } -tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr, - uint16_t tx_pdu_length) { - if (!controller_get_interface()->supports_ble_packet_extension()) { - LOG_INFO("Local controller unable to support le packet extension"); - return BTM_ILLEGAL_VALUE; - } - - LOG_INFO("%s, %d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), tx_pdu_length); - - auto p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec == NULL) { - LOG_ERROR("Device %s not found", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - return BTM_UNKNOWN_ADDR; - } - - if (tx_pdu_length > BTM_BLE_DATA_SIZE_MAX) - tx_pdu_length = BTM_BLE_DATA_SIZE_MAX; - else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN) - tx_pdu_length = BTM_BLE_DATA_SIZE_MIN; - - if (p_dev_rec->get_suggested_tx_octets() >= tx_pdu_length) { - LOG_INFO(" Suggested TX octect already set to controller %d >= %d", - p_dev_rec->get_suggested_tx_octets(), tx_pdu_length); - return BTM_SUCCESS; - } - - uint16_t tx_time = BTM_BLE_DATA_TX_TIME_MAX_LEGACY; - - if (controller_get_interface()->get_bt_version()->hci_version >= - HCI_PROTO_VERSION_5_0) - tx_time = BTM_BLE_DATA_TX_TIME_MAX; - - if (!BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) { - LOG_INFO( - "Unable to set data length because no le acl link connected to device"); - return BTM_WRONG_MODE; - } - - if (bluetooth::shim::is_gd_l2cap_enabled()) { - uint16_t handle = bluetooth::shim::L2CA_GetLeHandle(bd_addr); - btsnd_hcic_ble_set_data_length(handle, tx_pdu_length, tx_time); - p_dev_rec->set_suggested_tx_octect(tx_pdu_length); - return BTM_SUCCESS; - } - - uint16_t hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE); - - if (!acl_peer_supports_ble_packet_extension(hci_handle)) { - LOG_INFO("Remote device unable to support le packet extension"); - return BTM_ILLEGAL_VALUE; - } - - tx_pdu_length = std::min( - tx_pdu_length, - controller_get_interface()->get_ble_maximum_tx_data_length()); - tx_time = std::min( - tx_time, controller_get_interface()->get_ble_maximum_tx_time()); - - btsnd_hcic_ble_set_data_length(hci_handle, tx_pdu_length, tx_time); - p_dev_rec->set_suggested_tx_octect(tx_pdu_length); - - return BTM_SUCCESS; -} - void read_phy_cb( base::Callback cb, uint8_t* data, uint16_t len) { @@ -688,7 +142,6 @@ void read_phy_cb( STREAM_TO_UINT8(tx_phy, pp); STREAM_TO_UINT8(rx_phy, pp); - DVLOG(1) << __func__ << " Received read_phy_cb"; cb.Run(tx_phy, rx_phy, status); } @@ -708,11 +161,10 @@ void read_phy_cb( void BTM_BleReadPhy( const RawAddress& bd_addr, base::Callback cb) { - BTM_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) { - BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported", - __func__); + LOG_ERROR("%s: Wrong mode: no LE link exist or LE not supported", __func__); cb.Run(0, 0, HCI_ERR_NO_CONNECTION); return; } @@ -720,8 +172,8 @@ void BTM_BleReadPhy( // checking if local controller supports it! if (!controller_get_interface()->supports_ble_2m_phy() && !controller_get_interface()->supports_ble_coded_phy()) { - BTM_TRACE_ERROR("%s failed, request not supported in local controller!", - __func__); + LOG_ERROR("%s failed, request not supported in local controller!", + __func__); cb.Run(0, 0, GATT_REQ_NOT_SUPPORTED); return; } @@ -758,14 +210,16 @@ void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys, if (!controller_get_interface()->supports_ble_2m_phy() && !controller_get_interface()->supports_ble_coded_phy()) { LOG_INFO("Local controller unable to support setting of le phy parameters"); - gatt_notify_phy_updated(GATT_REQ_NOT_SUPPORTED, handle, tx_phys, rx_phys); + gatt_notify_phy_updated(static_cast(GATT_REQ_NOT_SUPPORTED), + handle, tx_phys, rx_phys); return; } if (!acl_peer_supports_ble_2m_phy(handle) && !acl_peer_supports_ble_coded_phy(handle)) { LOG_INFO("Remote device unable to support setting of le phy parameter"); - gatt_notify_phy_updated(GATT_REQ_NOT_SUPPORTED, handle, tx_phys, rx_phys); + gatt_notify_phy_updated(static_cast(GATT_REQ_NOT_SUPPORTED), + handle, tx_phys, rx_phys); return; } @@ -780,1431 +234,3 @@ void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys, btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_SET_PHY, data, len, base::Bind(doNothing)); } - -/******************************************************************************* - * - * Function btm_ble_determine_security_act - * - * Description This function checks the security of current LE link - * and returns the appropriate action that needs to be - * taken to achieve the required security. - * - * Parameter is_originator - True if outgoing connection - * bdaddr: remote device address - * security_required: Security required for the service. - * - * Returns The appropriate security action required. - * - ******************************************************************************/ -tBTM_SEC_ACTION btm_ble_determine_security_act(bool is_originator, - const RawAddress& bdaddr, - uint16_t security_required) { - tBTM_LE_AUTH_REQ auth_req = 0x00; - - if (is_originator) { - if ((security_required & BTM_SEC_OUT_FLAGS) == 0 && - (security_required & BTM_SEC_OUT_MITM) == 0) { - BTM_TRACE_DEBUG("%s No security required for outgoing connection", - __func__); - return BTM_SEC_OK; - } - - if (security_required & BTM_SEC_OUT_MITM) auth_req |= BTM_LE_AUTH_REQ_MITM; - } else { - if ((security_required & BTM_SEC_IN_FLAGS) == 0 && - (security_required & BTM_SEC_IN_MITM) == 0) { - BTM_TRACE_DEBUG("%s No security required for incoming connection", - __func__); - return BTM_SEC_OK; - } - - if (security_required & BTM_SEC_IN_MITM) auth_req |= BTM_LE_AUTH_REQ_MITM; - } - - tBTM_BLE_SEC_REQ_ACT ble_sec_act = { BTM_BLE_SEC_REQ_ACT_NONE }; - btm_ble_link_sec_check(bdaddr, auth_req, &ble_sec_act); - - BTM_TRACE_DEBUG("%s ble_sec_act %d", __func__, ble_sec_act); - - if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD) return BTM_SEC_ENC_PENDING; - - if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_NONE) return BTM_SEC_OK; - - bool is_link_encrypted = BTM_IsEncrypted(bdaddr, BT_TRANSPORT_LE); - bool is_key_mitm = BTM_IsLinkKeyAuthed(bdaddr, BT_TRANSPORT_LE); - - if (auth_req & BTM_LE_AUTH_REQ_MITM) { - if (!is_key_mitm) { - return BTM_SEC_ENCRYPT_MITM; - } else { - if (is_link_encrypted) - return BTM_SEC_OK; - else - return BTM_SEC_ENCRYPT; - } - } else { - if (is_link_encrypted) - return BTM_SEC_OK; - else - return BTM_SEC_ENCRYPT_NO_MITM; - } - - return BTM_SEC_OK; -} - -/******************************************************************************* - * - * Function btm_ble_start_sec_check - * - * Description This function is to check and set the security required for - * LE link for LE COC. - * - * Parameter bdaddr: remote device address. - * psm : PSM of the LE COC sevice. - * is_originator: true if outgoing connection. - * p_callback : Pointer to the callback function. - * p_ref_data : Pointer to be returned along with the callback. - * - * Returns Returns - L2CAP LE Connection Response Result Code. - * - ******************************************************************************/ -tL2CAP_LE_RESULT_CODE btm_ble_start_sec_check(const RawAddress& bd_addr, - uint16_t psm, bool is_originator, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data) { - /* Find the service record for the PSM */ - tBTM_SEC_SERV_REC* p_serv_rec = btm_sec_find_first_serv(is_originator, psm); - - /* If there is no application registered with this PSM do not allow connection - */ - if (!p_serv_rec) { - LOG_WARN("PSM: %d no application registered", psm); - (*p_callback)(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED); - return L2CAP_LE_RESULT_NO_PSM; - } - - bool is_encrypted = BTM_IsEncrypted(bd_addr, BT_TRANSPORT_LE); - bool is_link_key_authed = BTM_IsLinkKeyAuthed(bd_addr, BT_TRANSPORT_LE); - bool is_authenticated = BTM_IsAuthenticated(bd_addr, BT_TRANSPORT_LE); - - if (!is_originator) { - if ((p_serv_rec->security_flags & BTM_SEC_IN_ENCRYPT) && !is_encrypted) { - LOG_ERROR( - "L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP. service " - "security_flags=0x%x, ", - p_serv_rec->security_flags); - return L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP; - } else if ((p_serv_rec->security_flags & BTM_SEC_IN_AUTHENTICATE) && - !(is_link_key_authed || is_authenticated)) { - LOG_ERROR( - "L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION. service " - "security_flags=0x%x, ", - p_serv_rec->security_flags); - return L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION; - } - /* TODO: When security is required, then must check that the key size of our - service is equal or smaller than the incoming connection key size. */ - } - - tBTM_SEC_ACTION sec_act = btm_ble_determine_security_act( - is_originator, bd_addr, p_serv_rec->security_flags); - - tBTM_BLE_SEC_ACT ble_sec_act = BTM_BLE_SEC_NONE; - tL2CAP_LE_RESULT_CODE result = L2CAP_LE_RESULT_CONN_OK; - - switch (sec_act) { - case BTM_SEC_OK: - LOG_DEBUG("Security met"); - p_callback(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_SUCCESS); - result = L2CAP_LE_RESULT_CONN_OK; - break; - - case BTM_SEC_ENCRYPT: - LOG_DEBUG("Encryption needs to be done"); - ble_sec_act = BTM_BLE_SEC_ENCRYPT; - break; - - case BTM_SEC_ENCRYPT_MITM: - LOG_DEBUG("Pairing with MITM needs to be done"); - ble_sec_act = BTM_BLE_SEC_ENCRYPT_MITM; - break; - - case BTM_SEC_ENCRYPT_NO_MITM: - LOG_DEBUG("Pairing with No MITM needs to be done"); - ble_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM; - break; - - case BTM_SEC_ENC_PENDING: - LOG_DEBUG("Ecryption pending"); - break; - } - - if (ble_sec_act == BTM_BLE_SEC_NONE) { - if (bluetooth::common::init_flags::queue_l2cap_coc_while_encrypting_is_enabled()) { - if (sec_act != BTM_SEC_ENC_PENDING) { - return result; - } - } else { - return result; - } - } else { - l2cble_update_sec_act(bd_addr, sec_act); - } - - BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, p_callback, p_ref_data, - ble_sec_act); - - return L2CAP_LE_RESULT_CONN_OK; -} - -/******************************************************************************* - * - * Function btm_ble_rand_enc_complete - * - * Description This function is the callback functions for HCI_Rand command - * and HCI_Encrypt command is completed. - * This message is received from the HCI. - * - * Returns void - * - ******************************************************************************/ -void btm_ble_rand_enc_complete(uint8_t* p, uint16_t evt_len, - uint16_t op_code, - tBTM_RAND_ENC_CB* p_enc_cplt_cback) { - tBTM_RAND_ENC params; - uint8_t* p_dest = params.param_buf; - - BTM_TRACE_DEBUG("btm_ble_rand_enc_complete"); - - memset(¶ms, 0, sizeof(tBTM_RAND_ENC)); - - /* If there was a callback address for vcs complete, call it */ - if (p_enc_cplt_cback && p) { - - if (evt_len < 1) { - goto err_out; - } - - /* Pass paramters to the callback function */ - STREAM_TO_UINT8(params.status, p); /* command status */ - - if (params.status == HCI_SUCCESS) { - params.opcode = op_code; - - if (op_code == HCI_BLE_RAND) - params.param_len = BT_OCTET8_LEN; - else - params.param_len = OCTET16_LEN; - - if (evt_len < 1 + params.param_len) { - goto err_out; - } - - /* Fetch return info from HCI event message */ - memcpy(p_dest, p, params.param_len); - } - if (p_enc_cplt_cback) /* Call the Encryption complete callback function */ - (*p_enc_cplt_cback)(¶ms); - } - - return; - -err_out: - BTM_TRACE_ERROR("%s malformatted event packet, too short", __func__); -} - -/******************************************************************************* - * - * Function btm_ble_get_enc_key_type - * - * Description This function is to increment local sign counter - * Returns None - * - ******************************************************************************/ -void btm_ble_increment_sign_ctr(const RawAddress& bd_addr, bool is_local) { - tBTM_SEC_DEV_REC* p_dev_rec; - - BTM_TRACE_DEBUG("btm_ble_increment_sign_ctr is_local=%d", is_local); - - p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec != NULL) { - if (is_local) - p_dev_rec->ble.keys.local_counter++; - else - p_dev_rec->ble.keys.counter++; - BTM_TRACE_DEBUG("is_local=%d local sign counter=%d peer sign counter=%d", - is_local, p_dev_rec->ble.keys.local_counter, - p_dev_rec->ble.keys.counter); - } -} - -/******************************************************************************* - * - * Function btm_ble_get_enc_key_type - * - * Description This function is to get the BLE key type that has been - * exchanged betweem the local device and the peer device. - * - * Returns p_key_type: output parameter to carry the key type value. - * - ******************************************************************************/ -bool btm_ble_get_enc_key_type(const RawAddress& bd_addr, uint8_t* p_key_types) { - tBTM_SEC_DEV_REC* p_dev_rec; - - BTM_TRACE_DEBUG("btm_ble_get_enc_key_type"); - - p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec != NULL) { - *p_key_types = p_dev_rec->ble.key_type; - return true; - } - return false; -} - -/******************************************************************************* - * - * Function btm_get_local_div - * - * Description This function is called to read the local DIV - * - * Returns TURE - if a valid DIV is availavle - ******************************************************************************/ -bool btm_get_local_div(const RawAddress& bd_addr, uint16_t* p_div) { - tBTM_SEC_DEV_REC* p_dev_rec; - bool status = false; - VLOG(1) << __func__ << " bd_addr: " << bd_addr; - - *p_div = 0; - p_dev_rec = btm_find_dev(bd_addr); - - if (p_dev_rec && p_dev_rec->ble.keys.div) { - status = true; - *p_div = p_dev_rec->ble.keys.div; - } - BTM_TRACE_DEBUG("btm_get_local_div status=%d (1-OK) DIV=0x%x", status, - *p_div); - return status; -} - -/******************************************************************************* - * - * Function btm_sec_save_le_key - * - * Description This function is called by the SMP to update - * an BLE key. SMP is internal, whereas all the keys shall - * be sent to the application. The function is also called - * when application passes ble key stored in NVRAM to the - * btm_sec. - * pass_to_application parameter is false in this case. - * - * Returns void - * - ******************************************************************************/ -void btm_sec_save_le_key(const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type, - tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) { - tBTM_SEC_DEV_REC* p_rec; - tBTM_LE_EVT_DATA cb_data; - - BTM_TRACE_DEBUG("btm_sec_save_le_key key_type=0x%x pass_to_application=%d", - key_type, pass_to_application); - /* Store the updated key in the device database */ - - VLOG(1) << "bd_addr:" << bd_addr; - - if ((p_rec = btm_find_dev(bd_addr)) != NULL && - (p_keys || key_type == BTM_LE_KEY_LID)) { - btm_ble_init_pseudo_addr(p_rec, bd_addr); - - switch (key_type) { - case BTM_LE_KEY_PENC: - p_rec->ble.keys.pltk = p_keys->penc_key.ltk; - memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN); - p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level; - p_rec->ble.keys.ediv = p_keys->penc_key.ediv; - p_rec->ble.keys.key_size = p_keys->penc_key.key_size; - p_rec->ble.key_type |= BTM_LE_KEY_PENC; - p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN; - if (p_keys->penc_key.sec_level == SMP_SEC_AUTHENTICATED) - p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED; - else - p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED; - BTM_TRACE_DEBUG( - "BTM_LE_KEY_PENC key_type=0x%x sec_flags=0x%x sec_leve=0x%x", - p_rec->ble.key_type, p_rec->sec_flags, p_rec->ble.keys.sec_level); - break; - - case BTM_LE_KEY_PID: - p_rec->ble.keys.irk = p_keys->pid_key.irk; - p_rec->ble.identity_address_with_type.bda = - p_keys->pid_key.identity_addr; - p_rec->ble.identity_address_with_type.type = - p_keys->pid_key.identity_addr_type; - p_rec->ble.key_type |= BTM_LE_KEY_PID; - BTM_TRACE_DEBUG( - "%s: BTM_LE_KEY_PID key_type=0x%x save peer IRK, change bd_addr=%s " - "to id_addr=%s id_addr_type=0x%x", - __func__, p_rec->ble.key_type, - ADDRESS_TO_LOGGABLE_CSTR(p_rec->bd_addr), - ADDRESS_TO_LOGGABLE_CSTR(p_keys->pid_key.identity_addr), - p_keys->pid_key.identity_addr_type); - /* update device record address as identity address */ - p_rec->bd_addr = p_keys->pid_key.identity_addr; - /* combine DUMO device security record if needed */ - btm_consolidate_dev(p_rec); - break; - - case BTM_LE_KEY_PCSRK: - p_rec->ble.keys.pcsrk = p_keys->pcsrk_key.csrk; - p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level; - p_rec->ble.keys.counter = p_keys->pcsrk_key.counter; - p_rec->ble.key_type |= BTM_LE_KEY_PCSRK; - p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN; - if (p_keys->pcsrk_key.sec_level == SMP_SEC_AUTHENTICATED) - p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED; - else - p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED; - - BTM_TRACE_DEBUG( - "BTM_LE_KEY_PCSRK key_type=0x%x sec_flags=0x%x sec_level=0x%x " - "peer_counter=%d", - p_rec->ble.key_type, p_rec->sec_flags, - p_rec->ble.keys.srk_sec_level, p_rec->ble.keys.counter); - break; - - case BTM_LE_KEY_LENC: - p_rec->ble.keys.lltk = p_keys->lenc_key.ltk; - p_rec->ble.keys.div = p_keys->lenc_key.div; /* update DIV */ - p_rec->ble.keys.sec_level = p_keys->lenc_key.sec_level; - p_rec->ble.keys.key_size = p_keys->lenc_key.key_size; - p_rec->ble.key_type |= BTM_LE_KEY_LENC; - - BTM_TRACE_DEBUG( - "BTM_LE_KEY_LENC key_type=0x%x DIV=0x%x key_size=0x%x " - "sec_level=0x%x", - p_rec->ble.key_type, p_rec->ble.keys.div, p_rec->ble.keys.key_size, - p_rec->ble.keys.sec_level); - break; - - case BTM_LE_KEY_LCSRK: /* local CSRK has been delivered */ - p_rec->ble.keys.lcsrk = p_keys->lcsrk_key.csrk; - p_rec->ble.keys.div = p_keys->lcsrk_key.div; /* update DIV */ - p_rec->ble.keys.local_csrk_sec_level = p_keys->lcsrk_key.sec_level; - p_rec->ble.keys.local_counter = p_keys->lcsrk_key.counter; - p_rec->ble.key_type |= BTM_LE_KEY_LCSRK; - BTM_TRACE_DEBUG( - "BTM_LE_KEY_LCSRK key_type=0x%x DIV=0x%x scrk_sec_level=0x%x " - "local_counter=%d", - p_rec->ble.key_type, p_rec->ble.keys.div, - p_rec->ble.keys.local_csrk_sec_level, - p_rec->ble.keys.local_counter); - break; - - case BTM_LE_KEY_LID: - p_rec->ble.key_type |= BTM_LE_KEY_LID; - break; - default: - BTM_TRACE_WARNING("btm_sec_save_le_key (Bad key_type 0x%02x)", - key_type); - return; - } - - VLOG(1) << "BLE key type 0x" << loghex(key_type) - << " updated for BDA: " << bd_addr << " (btm_sec_save_le_key)"; - - /* Notify the application that one of the BLE keys has been updated - If link key is in progress, it will get sent later.*/ - if (pass_to_application && btm_cb.api.p_le_callback) { - cb_data.key.p_key_value = p_keys; - cb_data.key.key_type = key_type; - - (*btm_cb.api.p_le_callback)(BTM_LE_KEY_EVT, bd_addr, &cb_data); - } - return; - } - - LOG(WARNING) << "BLE key type 0x" << loghex(key_type) - << " called for Unknown BDA or type: " << bd_addr - << "(btm_sec_save_le_key)"; - - if (p_rec) { - BTM_TRACE_DEBUG("sec_flags=0x%x", p_rec->sec_flags); - } -} - -/******************************************************************************* - * - * Function btm_ble_update_sec_key_size - * - * Description update the current lin kencryption key size - * - * Returns void - * - ******************************************************************************/ -void btm_ble_update_sec_key_size(const RawAddress& bd_addr, - uint8_t enc_key_size) { - tBTM_SEC_DEV_REC* p_rec; - - BTM_TRACE_DEBUG("btm_ble_update_sec_key_size enc_key_size = %d", - enc_key_size); - - p_rec = btm_find_dev(bd_addr); - if (p_rec != NULL) { - p_rec->enc_key_size = enc_key_size; - } -} - -/******************************************************************************* - * - * Function btm_ble_read_sec_key_size - * - * Description update the current lin kencryption key size - * - * Returns void - * - ******************************************************************************/ -uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr) { - tBTM_SEC_DEV_REC* p_rec; - - p_rec = btm_find_dev(bd_addr); - if (p_rec != NULL) { - return p_rec->enc_key_size; - } else - return 0; -} - -/******************************************************************************* - * - * Function btm_ble_link_sec_check - * - * Description Check BLE link security level match. - * - * Returns true: check is OK and the *p_sec_req_act contain the action - * - ******************************************************************************/ -void btm_ble_link_sec_check(const RawAddress& bd_addr, - tBTM_LE_AUTH_REQ auth_req, - tBTM_BLE_SEC_REQ_ACT* p_sec_req_act) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - uint8_t req_sec_level = SMP_SEC_NONE, cur_sec_level = SMP_SEC_NONE; - - BTM_TRACE_DEBUG("btm_ble_link_sec_check auth_req =0x%x", auth_req); - - if (p_dev_rec == NULL) { - BTM_TRACE_ERROR("btm_ble_link_sec_check received for unknown device"); - return; - } - - if (p_dev_rec->is_security_state_encrypting() || - p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) { - /* race condition: discard the security request while central is encrypting - * the link */ - *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD; - } else { - req_sec_level = SMP_SEC_UNAUTHENTICATE; - if (auth_req & BTM_LE_AUTH_REQ_MITM) { - req_sec_level = SMP_SEC_AUTHENTICATED; - } - - BTM_TRACE_DEBUG("dev_rec sec_flags=0x%x", p_dev_rec->sec_flags); - - /* currently encrpted */ - if (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED) { - if (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED) - cur_sec_level = SMP_SEC_AUTHENTICATED; - else - cur_sec_level = SMP_SEC_UNAUTHENTICATE; - } else /* unencrypted link */ - { - /* if bonded, get the key security level */ - if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC) - cur_sec_level = p_dev_rec->ble.keys.sec_level; - else - cur_sec_level = SMP_SEC_NONE; - } - - if (cur_sec_level >= req_sec_level) { - /* To avoid re-encryption on an encrypted link for an equal condition - * encryption */ - *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT; - } else { - /* start the pariring process to upgrade the keys*/ - *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_PAIR; - } - } - - BTM_TRACE_DEBUG("cur_sec_level=%d req_sec_level=%d sec_req_act=%d", - cur_sec_level, req_sec_level, *p_sec_req_act); -} - -/******************************************************************************* - * - * Function btm_ble_set_encryption - * - * Description This function is called to ensure that LE connection is - * encrypted. Should be called only on an open connection. - * Typically only needed for connections that first want to - * bring up unencrypted links, then later encrypt them. - * - * Returns void - * the local device ER is copied into er - * - ******************************************************************************/ -tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr, - tBTM_BLE_SEC_ACT sec_act, - uint8_t link_role) { - tBTM_STATUS cmd = BTM_NO_RESOURCES; - tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr); - tBTM_BLE_SEC_REQ_ACT sec_req_act; - tBTM_LE_AUTH_REQ auth_req; - - if (p_rec == NULL) { - BTM_TRACE_WARNING( - "btm_ble_set_encryption (NULL device record!! sec_act=0x%x", sec_act); - return (BTM_WRONG_MODE); - } - - BTM_TRACE_DEBUG("btm_ble_set_encryption sec_act=0x%x role_central=%d", - sec_act, p_rec->role_central); - - if (sec_act == BTM_BLE_SEC_ENCRYPT_MITM) { - p_rec->security_required |= BTM_SEC_IN_MITM; - } - - switch (sec_act) { - case BTM_BLE_SEC_ENCRYPT: - if (link_role == HCI_ROLE_CENTRAL) { - /* start link layer encryption using the security info stored */ - cmd = btm_ble_start_encrypt(bd_addr, false, NULL); - break; - } - /* if salve role then fall through to call SMP_Pair below which will send - a sec_request to request the central to encrypt the link */ - FALLTHROUGH_INTENDED; /* FALLTHROUGH */ - case BTM_BLE_SEC_ENCRYPT_NO_MITM: - case BTM_BLE_SEC_ENCRYPT_MITM: - auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM) - ? SMP_AUTH_BOND - : (SMP_AUTH_BOND | SMP_AUTH_YN_BIT); - btm_ble_link_sec_check(bd_addr, auth_req, &sec_req_act); - if (sec_req_act == BTM_BLE_SEC_REQ_ACT_NONE || - sec_req_act == BTM_BLE_SEC_REQ_ACT_DISCARD) { - BTM_TRACE_DEBUG("%s, no action needed. Ignore", __func__); - cmd = BTM_SUCCESS; - break; - } - if (link_role == HCI_ROLE_CENTRAL) { - if (sec_req_act == BTM_BLE_SEC_REQ_ACT_ENCRYPT) { - cmd = btm_ble_start_encrypt(bd_addr, false, NULL); - break; - } - } - - if (SMP_Pair(bd_addr) == SMP_STARTED) { - cmd = BTM_CMD_STARTED; - p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; - } - break; - - default: - cmd = BTM_WRONG_MODE; - break; - } - return cmd; -} - -/******************************************************************************* - * - * Function btm_ble_ltk_request - * - * Description This function is called when encryption request is received - * on a peripheral device. - * - * - * Returns void - * - ******************************************************************************/ -void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv) { - tBTM_CB* p_cb = &btm_cb; - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle); - - BTM_TRACE_DEBUG("btm_ble_ltk_request"); - - p_cb->ediv = ediv; - - memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN); - - if (p_dev_rec != NULL) { - if (!smp_proc_ltk_request(p_dev_rec->bd_addr)) { - btm_ble_ltk_request_reply(p_dev_rec->bd_addr, false, Octet16{0}); - } - } -} - -/** This function is called to start LE encryption. - * Returns BTM_SUCCESS if encryption was started successfully - */ -tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk, - Octet16* p_stk) { - tBTM_CB* p_cb = &btm_cb; - tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda); - BT_OCTET8 dummy_rand = {0}; - - BTM_TRACE_DEBUG("btm_ble_start_encrypt"); - - if (!p_rec) { - BTM_TRACE_ERROR("Link is not active, can not encrypt!"); - return BTM_WRONG_MODE; - } - - if (p_rec->is_security_state_encrypting()) { - BTM_TRACE_WARNING("Link Encryption is active, Busy!"); - return BTM_BUSY; - } - - p_cb->enc_handle = p_rec->ble_hci_handle; - - if (use_stk) { - btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, *p_stk); - } else if (p_rec->ble.key_type & BTM_LE_KEY_PENC) { - btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, p_rec->ble.keys.rand, - p_rec->ble.keys.ediv, p_rec->ble.keys.pltk); - } else { - BTM_TRACE_ERROR("No key available to encrypt the link"); - return BTM_NO_RESOURCES; - } - - if (p_rec->sec_state == BTM_SEC_STATE_IDLE) - p_rec->sec_state = BTM_SEC_STATE_LE_ENCRYPTING; - - return BTM_CMD_STARTED; -} - -/******************************************************************************* - * - * Function btm_ble_link_encrypted - * - * Description This function is called when LE link encrption status is - * changed. - * - * Returns void - * - ******************************************************************************/ -void btm_ble_link_encrypted(const RawAddress& bd_addr, uint8_t encr_enable) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - bool enc_cback; - - if (!p_dev_rec) { - BTM_TRACE_WARNING( - "btm_ble_link_encrypted (No Device Found!) encr_enable=%d", - encr_enable); - return; - } - - BTM_TRACE_DEBUG("btm_ble_link_encrypted encr_enable=%d", encr_enable); - - enc_cback = p_dev_rec->is_security_state_le_encrypting(); - - smp_link_encrypted(bd_addr, encr_enable); - - BTM_TRACE_DEBUG(" p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags); - - if (encr_enable && p_dev_rec->enc_key_size == 0) - p_dev_rec->enc_key_size = p_dev_rec->ble.keys.key_size; - - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; - if (p_dev_rec->p_callback && enc_cback) { - if (encr_enable) - btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS, true); - else if (p_dev_rec->sec_flags & ~BTM_SEC_LE_LINK_KEY_KNOWN) { - btm_sec_dev_rec_cback_event(p_dev_rec, BTM_FAILED_ON_SECURITY, true); - } - /* LTK missing on peripheral */ - else if (p_dev_rec->role_central && (p_dev_rec->sec_status == HCI_ERR_KEY_MISSING)) { - btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_KEY_MISSING, true); - } - else if (p_dev_rec->role_central) - btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, true); - } - - if (encr_enable) { - /* Link is encrypted, start EATT */ - bluetooth::eatt::EattExtension::GetInstance()->Connect( - p_dev_rec->ble.pseudo_addr); - } - - /* to notify GATT to send data if any request is pending */ - gatt_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr); -} - -/******************************************************************************* - * - * Function btm_ble_ltk_request_reply - * - * Description This function is called to send a LTK request reply on a - * peripheral - * device. - * - * Returns void - * - ******************************************************************************/ -void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk, - const Octet16& stk) { - tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda); - tBTM_CB* p_cb = &btm_cb; - - if (p_rec == NULL) { - BTM_TRACE_ERROR("btm_ble_ltk_request_reply received for unknown device"); - return; - } - - BTM_TRACE_DEBUG("btm_ble_ltk_request_reply"); - p_cb->enc_handle = p_rec->ble_hci_handle; - p_cb->key_size = p_rec->ble.keys.key_size; - - BTM_TRACE_ERROR("key size = %d", p_rec->ble.keys.key_size); - if (use_stk) { - btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, stk); - return; - } - /* calculate LTK using peer device */ - if (p_rec->ble.key_type & BTM_LE_KEY_LENC) { - btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p_rec->ble.keys.lltk); - return; - } - - p_rec = btm_find_dev_with_lenc(bda); - if (!p_rec) { - btsnd_hcic_ble_ltk_req_neg_reply(btm_cb.enc_handle); - return; - } - - LOG_INFO("Found second sec_dev_rec for device that have LTK"); - /* This can happen when remote established LE connection using RPA to this - * device, but then pair with us using Classing transport while still keeping - * LE connection. If remote attempts to encrypt the LE connection, we might - * end up here. We will eventually consolidate both entries, this is to avoid - * race conditions. */ - - LOG_ASSERT(p_rec->ble.key_type & BTM_LE_KEY_LENC); - p_cb->key_size = p_rec->ble.keys.key_size; - btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p_rec->ble.keys.lltk); -} - -/******************************************************************************* - * - * Function btm_ble_io_capabilities_req - * - * Description This function is called to handle SMP get IO capability - * request. - * - * Returns void - * - ******************************************************************************/ -uint8_t btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC* p_dev_rec, - tBTM_LE_IO_REQ* p_data) { - uint8_t callback_rc = BTM_SUCCESS; - BTM_TRACE_DEBUG("btm_ble_io_capabilities_req"); - if (btm_cb.api.p_le_callback) { - /* the callback function implementation may change the IO capability... */ - callback_rc = (*btm_cb.api.p_le_callback)( - BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA*)p_data); - } - if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != p_data->oob_data)) { -#if (BTM_BLE_CONFORMANCE_TESTING == TRUE) - if (btm_cb.devcb.keep_rfu_in_auth_req) { - BTM_TRACE_DEBUG("btm_ble_io_capabilities_req keep_rfu_in_auth_req = %u", - btm_cb.devcb.keep_rfu_in_auth_req); - p_data->auth_req &= BTM_LE_AUTH_REQ_MASK_KEEP_RFU; - btm_cb.devcb.keep_rfu_in_auth_req = false; - } else { /* default */ - p_data->auth_req &= BTM_LE_AUTH_REQ_MASK; - } -#else - p_data->auth_req &= BTM_LE_AUTH_REQ_MASK; -#endif - - BTM_TRACE_DEBUG( - "btm_ble_io_capabilities_req 1: p_dev_rec->security_required = %d " - "auth_req:%d", - p_dev_rec->security_required, p_data->auth_req); - BTM_TRACE_DEBUG( - "btm_ble_io_capabilities_req 2: i_keys=0x%x r_keys=0x%x (bit 0-LTK " - "1-IRK 2-CSRK)", - p_data->init_keys, p_data->resp_keys); - - /* if authentication requires MITM protection, put on the mask */ - if (p_dev_rec->security_required & BTM_SEC_IN_MITM) - p_data->auth_req |= BTM_LE_AUTH_REQ_MITM; - - if (!(p_data->auth_req & SMP_AUTH_BOND)) { - BTM_TRACE_DEBUG("Non bonding: No keys should be exchanged"); - p_data->init_keys = 0; - p_data->resp_keys = 0; - } - - BTM_TRACE_DEBUG("btm_ble_io_capabilities_req 3: auth_req:%d", - p_data->auth_req); - BTM_TRACE_DEBUG("btm_ble_io_capabilities_req 4: i_keys=0x%x r_keys=0x%x", - p_data->init_keys, p_data->resp_keys); - - BTM_TRACE_DEBUG( - "btm_ble_io_capabilities_req 5: p_data->io_cap = %d auth_req:%d", - p_data->io_cap, p_data->auth_req); - - /* remove MITM protection requirement if IO cap does not allow it */ - if ((p_data->io_cap == BTM_IO_CAP_NONE) && p_data->oob_data == SMP_OOB_NONE) - p_data->auth_req &= ~BTM_LE_AUTH_REQ_MITM; - - if (!(p_data->auth_req & SMP_SC_SUPPORT_BIT)) { - /* if Secure Connections are not supported then remove LK derivation, - ** and keypress notifications. - */ - BTM_TRACE_DEBUG( - "%s-SC not supported -> No LK derivation, no keypress notifications", - __func__); - p_data->auth_req &= ~SMP_KP_SUPPORT_BIT; - p_data->init_keys &= ~SMP_SEC_KEY_TYPE_LK; - p_data->resp_keys &= ~SMP_SEC_KEY_TYPE_LK; - } - - BTM_TRACE_DEBUG( - "btm_ble_io_capabilities_req 6: IO_CAP:%d oob_data:%d auth_req:0x%02x", - p_data->io_cap, p_data->oob_data, p_data->auth_req); - } - return callback_rc; -} - -/******************************************************************************* - * - * Function btm_ble_br_keys_req - * - * Description This function is called to handle SMP request for keys sent - * over BR/EDR. - * - * Returns void - * - ******************************************************************************/ -uint8_t btm_ble_br_keys_req(tBTM_SEC_DEV_REC* p_dev_rec, - tBTM_LE_IO_REQ* p_data) { - uint8_t callback_rc = BTM_SUCCESS; - BTM_TRACE_DEBUG("%s", __func__); - p_data->io_cap = - osi_property_get_int32(kPropertyCtkdIoCapabilities, BTM_IO_CAP_UNKNOWN); - p_data->auth_req = osi_property_get_int32(kPropertyCtkdAuthRequest, - BTM_LE_AUTH_REQ_SC_MITM_BOND); - p_data->init_keys = osi_property_get_int32( - kPropertyCtkdInitiatorKeyDistribution, SMP_BR_SEC_DEFAULT_KEY); - p_data->resp_keys = osi_property_get_int32( - kPropertyCtkdResponderKeyDistribution, SMP_BR_SEC_DEFAULT_KEY); - p_data->max_key_size = - osi_property_get_int32(kPropertyCtkdMaxKeySize, BTM_BLE_MAX_KEY_SIZE); - // No OOB data for BR/EDR - p_data->oob_data = false; - - return callback_rc; -} - -/******************************************************************************* - * - * Function btm_ble_connected - * - * Description This function is when a LE connection to the peer device is - * establsihed - * - * Returns void - * - ******************************************************************************/ -void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, - uint8_t role, tBLE_ADDR_TYPE addr_type, - bool addr_matched, - bool can_read_discoverable_characteristics) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda); - if (!p_dev_rec) { - LOG_INFO("Creating new device record for new ble connection"); - p_dev_rec = btm_sec_alloc_dev(bda); - if (p_dev_rec == nullptr) { - LOG_WARN("Unable to create device record for new ble connection"); - return; - } - } else { - LOG_INFO("Updating device record timestamp for existing ble connection"); - // TODO() Why is timestamp a counter ? - p_dev_rec->timestamp = btm_cb.dev_rec_count++; - } - - if (is_ble_addr_type_known(addr_type)) - p_dev_rec->ble.SetAddressType(addr_type); - else - LOG_WARN( - "Please do not update device record from anonymous le advertisement"); - - p_dev_rec->ble.pseudo_addr = bda; - p_dev_rec->ble_hci_handle = handle; - p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE; - p_dev_rec->role_central = (role == HCI_ROLE_CENTRAL) ? true : false; - p_dev_rec->can_read_discoverable = can_read_discoverable_characteristics; - - if (!addr_matched) { - p_dev_rec->ble.active_addr_type = tBTM_SEC_BLE::BTM_BLE_ADDR_PSEUDO; - if (p_dev_rec->ble.AddressType() == BLE_ADDR_RANDOM) { - p_dev_rec->ble.cur_rand_addr = bda; - } - } - btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_ADV_IND_EVT; -} - -/***************************************************************************** - * Function btm_proc_smp_cback - * - * Description This function is the SMP callback handler. - * - *****************************************************************************/ -tBTM_STATUS btm_proc_smp_cback(tSMP_EVT event, const RawAddress& bd_addr, - const tSMP_EVT_DATA* p_data) { - BTM_TRACE_DEBUG("btm_proc_smp_cback event = %d", event); - - if (event == SMP_SC_LOC_OOB_DATA_UP_EVT) { - btm_sec_cr_loc_oob_data_cback_event(RawAddress{}, p_data->loc_oob_data); - return BTM_SUCCESS; - } - - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - tBTM_STATUS res = BTM_SUCCESS; - - if (p_dev_rec != NULL) { - switch (event) { - case SMP_IO_CAP_REQ_EVT: - btm_ble_io_capabilities_req(p_dev_rec, - (tBTM_LE_IO_REQ*)&p_data->io_req); - break; - - case SMP_BR_KEYS_REQ_EVT: - btm_ble_br_keys_req(p_dev_rec, (tBTM_LE_IO_REQ*)&p_data->io_req); - break; - - case SMP_PASSKEY_REQ_EVT: - case SMP_PASSKEY_NOTIF_EVT: - case SMP_OOB_REQ_EVT: - case SMP_NC_REQ_EVT: - case SMP_SC_OOB_REQ_EVT: - p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; - FALLTHROUGH_INTENDED; /* FALLTHROUGH */ - - case SMP_CONSENT_REQ_EVT: - case SMP_SEC_REQUEST_EVT: - if (event == SMP_SEC_REQUEST_EVT && - btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) { - BTM_TRACE_DEBUG("%s: Ignoring SMP Security request", __func__); - break; - } - btm_cb.pairing_bda = bd_addr; - if (event != SMP_CONSENT_REQ_EVT) { - p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; - } - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE; - FALLTHROUGH_INTENDED; /* FALLTHROUGH */ - - case SMP_COMPLT_EVT: - if (btm_cb.api.p_le_callback) { - /* the callback function implementation may change the IO - * capability... */ - BTM_TRACE_DEBUG("btm_cb.api.p_le_callback=0x%x", - btm_cb.api.p_le_callback); - (*btm_cb.api.p_le_callback)(event, bd_addr, - (tBTM_LE_EVT_DATA*)p_data); - } - - if (event == SMP_COMPLT_EVT) { - p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec == NULL) { - BTM_TRACE_ERROR("%s: p_dev_rec is NULL", __func__); - return BTM_SUCCESS; - } - BTM_TRACE_DEBUG( - "evt=SMP_COMPLT_EVT before update sec_level=0x%x sec_flags=0x%x", - p_data->cmplt.sec_level, p_dev_rec->sec_flags); - - res = (p_data->cmplt.reason == SMP_SUCCESS) ? BTM_SUCCESS - : BTM_ERR_PROCESSING; - - BTM_TRACE_DEBUG( - "after update result=%d sec_level=0x%x sec_flags=0x%x", res, - p_data->cmplt.sec_level, p_dev_rec->sec_flags); - - if (p_data->cmplt.is_pair_cancel && - btm_cb.api.p_bond_cancel_cmpl_callback) { - BTM_TRACE_DEBUG("Pairing Cancel completed"); - (*btm_cb.api.p_bond_cancel_cmpl_callback)(BTM_SUCCESS); - } -#if (BTM_BLE_CONFORMANCE_TESTING == TRUE) - if (res != BTM_SUCCESS) { - if (!btm_cb.devcb.no_disc_if_pair_fail && - p_data->cmplt.reason != SMP_CONN_TOUT) { - BTM_TRACE_DEBUG("Pairing failed - prepare to remove ACL"); - l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle); - } else { - BTM_TRACE_DEBUG("Pairing failed - Not Removing ACL"); - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; - } - } -#else - if (res != BTM_SUCCESS && p_data->cmplt.reason != SMP_CONN_TOUT) { - BTM_TRACE_DEBUG("Pairing failed - prepare to remove ACL"); - l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle); - } -#endif - - BTM_TRACE_DEBUG( - "btm_cb pairing_state=%x pairing_flags=%x pin_code_len=%x", - btm_cb.pairing_state, btm_cb.pairing_flags, btm_cb.pin_code_len); - VLOG(1) << "btm_cb.pairing_bda: " << btm_cb.pairing_bda; - - /* Reset btm state only if the callback address matches pairing - * address*/ - if (bd_addr == btm_cb.pairing_bda) { - btm_cb.pairing_bda = RawAddress::kAny; - btm_cb.pairing_state = BTM_PAIR_STATE_IDLE; - btm_cb.pairing_flags = 0; - } - - if (res == BTM_SUCCESS) { - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; - /* add all bonded device into resolving list if IRK is available*/ - btm_ble_resolving_list_load_dev(*p_dev_rec); - } - - btm_sec_dev_rec_cback_event(p_dev_rec, res, true); - } - break; - - case SMP_LE_ADDR_ASSOC_EVT: - if (btm_cb.api.p_le_callback) { - BTM_TRACE_DEBUG("btm_cb.api.p_le_callback=0x%x", - btm_cb.api.p_le_callback); - (*btm_cb.api.p_le_callback)(event, bd_addr, - (tBTM_LE_EVT_DATA*)p_data); - } - break; - - default: - BTM_TRACE_DEBUG("unknown event = %d", event); - break; - } - } else { - LOG_WARN("Unexpected event '%d' for unknown device.", event); - } - - return BTM_SUCCESS; -} - -/******************************************************************************* - * - * Function BTM_BleDataSignature - * - * Description This function is called to sign the data using AES128 CMAC - * algorith. - * - * Parameter bd_addr: target device the data to be signed for. - * p_text: singing data - * len: length of the data to be signed. - * signature: output parameter where data signature is going to - * be stored. - * - * Returns true if signing sucessul, otherwise false. - * - ******************************************************************************/ -bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text, - uint16_t len, BLE_SIGNATURE signature) { - tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr); - - BTM_TRACE_DEBUG("%s", __func__); - if (p_rec == NULL) { - BTM_TRACE_ERROR("%s-data signing can not be done from unknown device", - __func__); - return false; - } - - uint8_t* p_mac = (uint8_t*)signature; - uint8_t* pp; - uint8_t* p_buf = (uint8_t*)osi_malloc(len + 4); - - BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__); - pp = p_buf; - /* prepare plain text */ - if (p_text) { - memcpy(p_buf, p_text, len); - pp = (p_buf + len); - } - - UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter); - UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter); - - crypto_toolbox::aes_cmac(p_rec->ble.keys.lcsrk, p_buf, (uint16_t)(len + 4), - BTM_CMAC_TLEN_SIZE, p_mac); - btm_ble_increment_sign_ctr(bd_addr, true); - - BTM_TRACE_DEBUG("%s p_mac = %d", __func__, p_mac); - BTM_TRACE_DEBUG( - "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = " - "0x%02x", - *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3)); - BTM_TRACE_DEBUG( - "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = " - "0x%02x", - *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7)); - osi_free(p_buf); - return true; -} - -/******************************************************************************* - * - * Function BTM_BleVerifySignature - * - * Description This function is called to verify the data signature - * - * Parameter bd_addr: target device the data to be signed for. - * p_orig: original data before signature. - * len: length of the signing data - * counter: counter used when doing data signing - * p_comp: signature to be compared against. - - * Returns true if signature verified correctly; otherwise false. - * - ******************************************************************************/ -bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig, - uint16_t len, uint32_t counter, uint8_t* p_comp) { - bool verified = false; - tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr); - uint8_t p_mac[BTM_CMAC_TLEN_SIZE]; - - if (p_rec == NULL || (p_rec && !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK))) { - BTM_TRACE_ERROR("can not verify signature for unknown device"); - } else if (counter < p_rec->ble.keys.counter) { - BTM_TRACE_ERROR("signature received with out dated sign counter"); - } else if (p_orig == NULL) { - BTM_TRACE_ERROR("No signature to verify"); - } else { - BTM_TRACE_DEBUG("%s rcv_cnt=%d >= expected_cnt=%d", __func__, counter, - p_rec->ble.keys.counter); - - crypto_toolbox::aes_cmac(p_rec->ble.keys.pcsrk, p_orig, len, - BTM_CMAC_TLEN_SIZE, p_mac); - if (CRYPTO_memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) { - btm_ble_increment_sign_ctr(bd_addr, false); - verified = true; - } - } - return verified; -} - -/******************************************************************************* - * Utility functions for LE device IR/ER generation - ******************************************************************************/ -/** This function is to notify application new keys have been generated. */ -static void btm_notify_new_key(uint8_t key_type) { - tBTM_BLE_LOCAL_KEYS* p_local_keys = NULL; - - BTM_TRACE_DEBUG("btm_notify_new_key key_type=%d", key_type); - - if (btm_cb.api.p_le_key_callback) { - switch (key_type) { - case BTM_BLE_KEY_TYPE_ID: - BTM_TRACE_DEBUG("BTM_BLE_KEY_TYPE_ID"); - p_local_keys = (tBTM_BLE_LOCAL_KEYS*)&btm_cb.devcb.id_keys; - break; - - case BTM_BLE_KEY_TYPE_ER: - BTM_TRACE_DEBUG("BTM_BLE_KEY_TYPE_ER"); - p_local_keys = - (tBTM_BLE_LOCAL_KEYS*)&btm_cb.devcb.ble_encryption_key_value; - break; - - default: - BTM_TRACE_ERROR("unknown key type: %d", key_type); - break; - } - if (p_local_keys != NULL) - (*btm_cb.api.p_le_key_callback)(key_type, p_local_keys); - } -} - -/** implementation of btm_ble_reset_id */ -static void btm_ble_reset_id_impl(const Octet16& rand1, const Octet16& rand2) { - /* Regenerate Identity Root */ - btm_cb.devcb.id_keys.ir = rand1; - uint8_t btm_ble_dhk_pt = 0x03; - - /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */ - btm_cb.devcb.id_keys.dhk = - crypto_toolbox::aes_128(btm_cb.devcb.id_keys.ir, &btm_ble_dhk_pt, 1); - - uint8_t btm_ble_irk_pt = 0x01; - /* IRK = D1(IR, 1) */ - btm_cb.devcb.id_keys.irk = - crypto_toolbox::aes_128(btm_cb.devcb.id_keys.ir, &btm_ble_irk_pt, 1); - - btm_notify_new_key(BTM_BLE_KEY_TYPE_ID); - - /* if privacy is enabled, new RPA should be calculated */ - if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) { - btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low)); - } - - /* proceed generate ER */ - btm_cb.devcb.ble_encryption_key_value = rand2; - btm_notify_new_key(BTM_BLE_KEY_TYPE_ER); - - /* if privacy is enabled, update the irk and RPA in the LE address manager */ - if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) { - BTM_BleConfigPrivacy(true); - } -} - -struct reset_id_data { - Octet16 rand1; - Octet16 rand2; -}; - -/** This function is called to reset LE device identity. */ -void btm_ble_reset_id(void) { - BTM_TRACE_DEBUG("btm_ble_reset_id"); - - /* In order to reset identity, we need four random numbers. Make four nested - * calls to generate them first, then proceed to perform the actual reset in - * btm_ble_reset_id_impl. */ - btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand) { - reset_id_data tmp; - memcpy(tmp.rand1.data(), rand, BT_OCTET8_LEN); - btsnd_hcic_ble_rand(base::Bind( - [](reset_id_data tmp, BT_OCTET8 rand) { - memcpy(tmp.rand1.data() + 8, rand, BT_OCTET8_LEN); - btsnd_hcic_ble_rand(base::Bind( - [](reset_id_data tmp, BT_OCTET8 rand) { - memcpy(tmp.rand2.data(), rand, BT_OCTET8_LEN); - btsnd_hcic_ble_rand(base::Bind( - [](reset_id_data tmp, BT_OCTET8 rand) { - memcpy(tmp.rand2.data() + 8, rand, BT_OCTET8_LEN); - // when all random numbers are ready, do the actual reset. - btm_ble_reset_id_impl(tmp.rand1, tmp.rand2); - }, - tmp)); - }, - tmp)); - }, - tmp)); - })); -} - -/******************************************************************************* - * - * Function btm_ble_get_acl_remote_addr - * - * Description This function reads the active remote address used for the - * connection. - * - * Returns success return true, otherwise false. - * - ******************************************************************************/ -bool btm_ble_get_acl_remote_addr(uint16_t hci_handle, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle); - if (p_dev_rec == nullptr) { - LOG_WARN("Unable to find security device record hci_handle:%hu", - hci_handle); - // TODO Release acl resource - return false; - } - - bool st = true; - - switch (p_dev_rec->ble.active_addr_type) { - case tBTM_SEC_BLE::BTM_BLE_ADDR_PSEUDO: - conn_addr = p_dev_rec->bd_addr; - *p_addr_type = p_dev_rec->ble.AddressType(); - break; - - case tBTM_SEC_BLE::BTM_BLE_ADDR_RRA: - conn_addr = p_dev_rec->ble.cur_rand_addr; - *p_addr_type = BLE_ADDR_RANDOM; - break; - - case tBTM_SEC_BLE::BTM_BLE_ADDR_STATIC: - conn_addr = p_dev_rec->ble.identity_address_with_type.bda; - *p_addr_type = p_dev_rec->ble.identity_address_with_type.type; - break; - - default: - LOG_WARN("Unable to find record with active address type: %d", - p_dev_rec->ble.active_addr_type); - st = false; - break; - } - return st; -} - -#if BTM_BLE_CONFORMANCE_TESTING == TRUE -/******************************************************************************* - * - * Function btm_ble_set_no_disc_if_pair_fail - * - * Description This function indicates whether no disconnect of the ACL - * should be used if pairing failed - * - * Returns void - * - ******************************************************************************/ -void btm_ble_set_no_disc_if_pair_fail(bool disable_disc) { - BTM_TRACE_DEBUG("btm_ble_set_disc_enable_if_pair_fail disable_disc=%d", - disable_disc); - btm_cb.devcb.no_disc_if_pair_fail = disable_disc; -} - -/******************************************************************************* - * - * Function btm_ble_set_test_mac_value - * - * Description This function set test MAC value - * - * Returns void - * - ******************************************************************************/ -void btm_ble_set_test_mac_value(bool enable, uint8_t* p_test_mac_val) { - BTM_TRACE_DEBUG("btm_ble_set_test_mac_value enable=%d", enable); - btm_cb.devcb.enable_test_mac_val = enable; - memcpy(btm_cb.devcb.test_mac, p_test_mac_val, BT_OCTET8_LEN); -} - -/******************************************************************************* - * - * Function btm_ble_set_test_local_sign_cntr_value - * - * Description This function set test local sign counter value - * - * Returns void - * - ******************************************************************************/ -void btm_ble_set_test_local_sign_cntr_value(bool enable, - uint32_t test_local_sign_cntr) { - BTM_TRACE_DEBUG( - "btm_ble_set_test_local_sign_cntr_value enable=%d local_sign_cntr=%d", - enable, test_local_sign_cntr); - btm_cb.devcb.enable_test_local_sign_cntr = enable; - btm_cb.devcb.test_local_sign_cntr = test_local_sign_cntr; -} - -/******************************************************************************* - * - * Function btm_ble_set_keep_rfu_in_auth_req - * - * Description This function indicates if RFU bits have to be kept as is - * (by default they have to be set to 0 by the sender). - * - * Returns void - * - ******************************************************************************/ -void btm_ble_set_keep_rfu_in_auth_req(bool keep_rfu) { - BTM_TRACE_DEBUG("btm_ble_set_keep_rfu_in_auth_req keep_rfus=%d", keep_rfu); - btm_cb.devcb.keep_rfu_in_auth_req = keep_rfu; -} - -#endif /* BTM_BLE_CONFORMANCE_TESTING */ diff --git a/system/stack/btm/btm_ble_addr.cc b/system/stack/btm/btm_ble_addr.cc index 524adbf8efb4bae5c214193732b536c202b77af1..8234ecdfc6a7d53d4381a1958f2cca8f34b2ee04 100644 --- a/system/stack/btm/btm_ble_addr.cc +++ b/system/stack/btm/btm_ble_addr.cc @@ -22,18 +22,24 @@ * ******************************************************************************/ +#define LOG_TAG "ble" + +#include "stack/include/btm_ble_addr.h" + #include #include #include "btm_ble_int.h" +#include "btm_dev.h" +#include "btm_sec_cb.h" +#include "crypto_toolbox/crypto_toolbox.h" #include "device/include/controller.h" -#include "gap_api.h" -#include "main/shim/shim.h" -#include "osi/include/osi.h" // UNUSED_ATTR -#include "stack/btm/btm_dev.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" +#include "os/log.h" +#include "stack/btm/btm_int_types.h" #include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" +#include "stack/include/btm_ble_privacy.h" +#include "stack/include/btm_ble_sec_api.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" @@ -52,7 +58,11 @@ static RawAddress generate_rpa_from_irk_and_rand(const Octet16& irk, address.address[0] = random[2]; /* encrypt with IRK */ - Octet16 p = crypto_toolbox::aes_128(irk, random, 3); + Octet16 r{}; + r[0] = random[0]; + r[1] = random[1]; + r[2] = random[2]; + Octet16 p = crypto_toolbox::aes_128(irk, r); /* set hash to be LSB of rpAddress */ address.address[5] = p[0]; @@ -81,14 +91,6 @@ void btm_gen_resolvable_private_addr( std::move(cb))); } -uint64_t btm_get_next_private_addrress_interval_ms() { - /* 7 minutes minimum, 15 minutes maximum for random address refreshing */ - const uint64_t interval_min_ms = (7 * 60 * 1000); - const uint64_t interval_random_part_max_ms = (8 * 60 * 1000); - - return interval_min_ms + std::rand() % interval_random_part_max_ms; -} - /******************************************************************************* * Utility functions for Random address resolving ******************************************************************************/ @@ -117,19 +119,19 @@ bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, * Resolving Key |irk| */ static bool rpa_matches_irk(const RawAddress& rpa, const Octet16& irk) { /* use the 3 MSB of bd address as prand */ - uint8_t rand[3]; + Octet16 rand{}; rand[0] = rpa.address[2]; rand[1] = rpa.address[1]; rand[2] = rpa.address[0]; /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */ - Octet16 x = crypto_toolbox::aes_128(irk, &rand[0], 3); + Octet16 x = crypto_toolbox::aes_128(irk, rand); rand[0] = rpa.address[5]; rand[1] = rpa.address[4]; rand[2] = rpa.address[3]; - if (memcmp(x.data(), &rand[0], 3) == 0) { + if (memcmp(x.data(), rand.data(), 3) == 0) { // match return true; } @@ -145,8 +147,8 @@ bool btm_ble_addr_resolvable(const RawAddress& rpa, if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) return false; if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) && - (p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) { - if (rpa_matches_irk(rpa, p_dev_rec->ble.keys.irk)) { + (p_dev_rec->sec_rec.ble_keys.key_type & BTM_LE_KEY_PID)) { + if (rpa_matches_irk(rpa, p_dev_rec->sec_rec.ble_keys.irk)) { btm_ble_init_pseudo_addr(p_dev_rec, rpa); return true; } @@ -162,11 +164,11 @@ static bool btm_ble_match_random_bda(void* data, void* context) { RawAddress* random_bda = static_cast(context); if (!(p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) || - !(p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) + !(p_dev_rec->sec_rec.ble_keys.key_type & BTM_LE_KEY_PID)) // Match fails preconditions return true; - if (rpa_matches_irk(*random_bda, p_dev_rec->ble.keys.irk)) { + if (rpa_matches_irk(*random_bda, p_dev_rec->sec_rec.ble_keys.irk)) { // Matched return false; } @@ -180,9 +182,9 @@ static bool btm_ble_match_random_bda(void* data, void* context) { * matched to. */ tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(const RawAddress& random_bda) { - if (btm_cb.sec_dev_rec == nullptr) return nullptr; - list_node_t* n = list_foreach(btm_cb.sec_dev_rec, btm_ble_match_random_bda, - (void*)&random_bda); + if (btm_sec_cb.sec_dev_rec == nullptr) return nullptr; + list_node_t* n = list_foreach(btm_sec_cb.sec_dev_rec, + btm_ble_match_random_bda, (void*)&random_bda); return (n == nullptr) ? (nullptr) : (static_cast(list_node(n))); } @@ -193,20 +195,19 @@ tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(const RawAddress& random_bda) { /** Find the security record whose LE identity address is matching */ static tBTM_SEC_DEV_REC* btm_find_dev_by_identity_addr( const RawAddress& bd_addr, uint8_t addr_type) { - if (btm_cb.sec_dev_rec == nullptr) return nullptr; + if (btm_sec_cb.sec_dev_rec == nullptr) return nullptr; - list_node_t* end = list_end(btm_cb.sec_dev_rec); - for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end; + list_node_t* end = list_end(btm_sec_cb.sec_dev_rec); + for (list_node_t* node = list_begin(btm_sec_cb.sec_dev_rec); node != end; node = list_next(node)) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(list_node(node)); if (p_dev_rec->ble.identity_address_with_type.bda == bd_addr) { if ((p_dev_rec->ble.identity_address_with_type.type & (~BLE_ADDR_TYPE_ID_BIT)) != (addr_type & (~BLE_ADDR_TYPE_ID_BIT))) - BTM_TRACE_WARNING( - "%s find pseudo->random match with diff addr type: %d vs %d", - __func__, p_dev_rec->ble.identity_address_with_type.type, - addr_type); + LOG_WARN("%s find pseudo->random match with diff addr type: %d vs %d", + __func__, p_dev_rec->ble.identity_address_with_type.type, + addr_type); /* found the match */ return p_dev_rec; @@ -290,7 +291,7 @@ bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo, ******************************************************************************/ void btm_ble_refresh_peer_resolvable_private_addr( const RawAddress& pseudo_bda, const RawAddress& rpa, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type) { + tBLE_RAND_ADDR_TYPE rra_type) { tBTM_SEC_DEV_REC* p_sec_rec = btm_find_dev(pseudo_bda); if (p_sec_rec == nullptr) { LOG_WARN("%s No matching known device in record", __func__); @@ -299,10 +300,9 @@ void btm_ble_refresh_peer_resolvable_private_addr( p_sec_rec->ble.cur_rand_addr = rpa; - if (rra_type == tBTM_SEC_BLE::BTM_BLE_ADDR_PSEUDO) { - p_sec_rec->ble.active_addr_type = rpa.IsEmpty() - ? tBTM_SEC_BLE::BTM_BLE_ADDR_STATIC - : tBTM_SEC_BLE::BTM_BLE_ADDR_RRA; + if (rra_type == BTM_BLE_ADDR_PSEUDO) { + p_sec_rec->ble.active_addr_type = + rpa.IsEmpty() ? BTM_BLE_ADDR_STATIC : BTM_BLE_ADDR_RRA; } else { p_sec_rec->ble.active_addr_type = rra_type; } @@ -321,3 +321,41 @@ void btm_ble_refresh_peer_resolvable_private_addr( } } } + +bool maybe_resolve_address(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { + bool is_in_security_db = false; + tBLE_ADDR_TYPE peer_addr_type = *bda_type; + bool addr_is_rpa = + (peer_addr_type == BLE_ADDR_RANDOM && BTM_BLE_IS_RESOLVE_BDA(*bda)); + + /* We must translate whatever address we received into the "pseudo" address. + * i.e. if we bonded with device that was using RPA for first connection, + * "pseudo" address is equal to this RPA. If it later decides to use Public + * address, or Random Static Address, we convert it into the "pseudo" + * address here. */ + if (!addr_is_rpa || peer_addr_type & BLE_ADDR_TYPE_ID_BIT) { + is_in_security_db = btm_identity_addr_to_random_pseudo(bda, bda_type, true); + } + + /* possiblly receive connection complete with resolvable random while + the device has been paired */ + if (!is_in_security_db && addr_is_rpa) { + tBTM_SEC_DEV_REC* match_rec = btm_ble_resolve_random_addr(*bda); + if (match_rec) { + LOG(INFO) << __func__ << ": matched and resolved random address"; + is_in_security_db = true; + match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA; + match_rec->ble.cur_rand_addr = *bda; + if (!btm_ble_init_pseudo_addr(match_rec, *bda)) { + /* assign the original address to be the current report address */ + *bda = match_rec->ble.pseudo_addr; + *bda_type = match_rec->ble.AddressType(); + } else { + *bda = match_rec->bd_addr; + } + } else { + LOG(INFO) << __func__ << ": unable to match and resolve random address"; + } + } + return is_in_security_db; +} diff --git a/system/stack/btm/btm_ble_adv_filter.cc b/system/stack/btm/btm_ble_adv_filter.cc index ecceef799c1c3ae7e41431270080bf86aff09d64..1c0cfe7226479fdba4193d5d4de45d076f8cd940 100644 --- a/system/stack/btm/btm_ble_adv_filter.cc +++ b/system/stack/btm/btm_ble_adv_filter.cc @@ -19,19 +19,14 @@ #define LOG_TAG "bt_btm_ble" #include -#include -#include -#include -#include - -#include "bind_helpers.h" -#include "bt_target.h" #include "btm_ble_api.h" -#include "btm_dev.h" -#include "btu.h" +#include "os/log.h" +#include "osi/include/allocator.h" #include "stack/btm/btm_ble_int.h" #include "stack/btm/btm_int_types.h" +#include "stack/include/bt_types.h" +#include "stack/include/btu_hcif.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -83,14 +78,6 @@ static bool is_filtering_supported() { return cmn_ble_vsc_cb.filter_support != 0 && cmn_ble_vsc_cb.max_filter != 0; } -static bool is_empty_128bit(const std::array data) { - int i, len = 16; - for (i = 0; i < len; i++) { - if (data[i] != (uint8_t)0) return false; - } - return true; -} - /******************************************************************************* * * Function btm_ble_ocf_to_condtype @@ -138,7 +125,7 @@ static uint8_t btm_ble_ocf_to_condtype(uint8_t ocf) { static void btm_flt_update_cb(uint8_t expected_ocf, tBTM_BLE_PF_CFG_CBACK cb, uint8_t* p, uint16_t evt_len) { if (evt_len != 4) { - BTM_TRACE_ERROR("%s: bad length: %d", __func__, evt_len); + LOG_ERROR("%s: bad length: %d", __func__, evt_len); return; } @@ -149,8 +136,8 @@ static void btm_flt_update_cb(uint8_t expected_ocf, tBTM_BLE_PF_CFG_CBACK cb, STREAM_TO_UINT8(num_avail, p); if (expected_ocf != op_subcode) { - BTM_TRACE_ERROR("%s: Incorrect opcode: 0x%02x, expected: 0x%02x", __func__, - expected_ocf, op_subcode); + LOG_ERROR("%s: Incorrect opcode: 0x%02x, expected: 0x%02x", __func__, + expected_ocf, op_subcode); return; } @@ -162,8 +149,8 @@ static void btm_flt_update_cb(uint8_t expected_ocf, tBTM_BLE_PF_CFG_CBACK cb, } uint8_t cond_type = btm_ble_ocf_to_condtype(expected_ocf); - BTM_TRACE_DEBUG("%s: Recd: %d, %d, %d, %d, %d", __func__, op_subcode, - expected_ocf, action, status, num_avail); + LOG_VERBOSE("%s: Recd: %d, %d, %d, %d, %d", __func__, op_subcode, + expected_ocf, action, status, num_avail); if (HCI_SUCCESS == status) { if (btm_ble_adv_filt_cb.cur_filter_target.bda.IsEmpty()) btm_ble_cs_update_pf_counter(static_cast(action), @@ -263,141 +250,6 @@ static bool btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR* p_bd_addr, return found; } -/** - * This function update(add,delete or clear) the adv local name filtering - * condition. - */ -static void BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector name, - tBTM_BLE_PF_CFG_CBACK cb) { - uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; - - uint8_t len_max = len + BTM_BLE_PF_STR_LEN_MAX; - uint8_t param[len_max]; - memset(param, 0, len_max); - - uint8_t* p = param; - UINT8_TO_STREAM(p, BTM_BLE_META_PF_LOCAL_NAME); - UINT8_TO_STREAM(p, action); - UINT8_TO_STREAM(p, filt_index); - - if (action != BTM_BLE_SCAN_COND_CLEAR) { - int size = std::min(name.size(), (size_t)BTM_BLE_PF_STR_LEN_MAX); - ARRAY_TO_STREAM(p, name.data(), size); - len += size; - } - - /* send local name filter */ - btu_hcif_send_cmd_with_cb( - FROM_HERE, HCI_BLE_ADV_FILTER, param, len, - base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_LOCAL_NAME, cb)); - - memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); -} - -/** - * this function update(add/remove) service data change filter. - */ -static void BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index) { - uint8_t num_avail = (action == BTM_BLE_SCAN_COND_ADD) ? 0 : 1; - - btm_ble_cs_update_pf_counter(action, BTM_BLE_PF_SRVC_DATA, nullptr, - num_avail); -} - -/** - * This function update(add,delete or clear) the adv manufacturer data filtering - * condition. - */ -static void BTM_LE_PF_manu_data(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - uint16_t company_id, uint16_t company_id_mask, - std::vector data, - std::vector data_mask, - tBTM_BLE_PF_CFG_CBACK cb) { - uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; - int len_max = len + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX; - - uint8_t param[len_max]; - memset(param, 0, len_max); - - uint8_t* p = param; - UINT8_TO_STREAM(p, BTM_BLE_META_PF_MANU_DATA); - UINT8_TO_STREAM(p, action); - UINT8_TO_STREAM(p, filt_index); - - if (action != BTM_BLE_SCAN_COND_CLEAR) { - uint8_t size = std::min(data.size(), (size_t)(BTM_BLE_PF_STR_LEN_MAX - 2)); - - UINT16_TO_STREAM(p, company_id); - if (size > 0 && data_mask.size() != 0) { - ARRAY_TO_STREAM(p, data.data(), size); - len += size + 2; - } else - len += 2; - - if (company_id_mask != 0) { - UINT16_TO_STREAM(p, company_id_mask); - } else { - UINT16_TO_STREAM(p, (uint16_t)0xFFFF); - } - len += 2; - - if (size > 0 && data_mask.size() != 0) { - ARRAY_TO_STREAM(p, data_mask.data(), size); - len += (size); - } - - BTM_TRACE_DEBUG("Manuf data length: %d", len); - } - - btu_hcif_send_cmd_with_cb( - FROM_HERE, HCI_BLE_ADV_FILTER, param, len, - base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_MANU_DATA, cb)); - - memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); -} - -/** - * This function update(add,delete or clear) the service data filtering - * condition. - **/ -static void BTM_LE_PF_srvc_data_pattern(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector data, - std::vector data_mask, - tBTM_BLE_PF_CFG_CBACK cb) { - uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; - int len_max = len + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX; - - uint8_t param[len_max]; - memset(param, 0, len_max); - - uint8_t* p = param; - UINT8_TO_STREAM(p, BTM_BLE_META_PF_SRVC_DATA); - UINT8_TO_STREAM(p, action); - UINT8_TO_STREAM(p, filt_index); - - if (action != BTM_BLE_SCAN_COND_CLEAR) { - uint8_t size = std::min(data.size(), (size_t)(BTM_BLE_PF_STR_LEN_MAX - 2)); - - if (size > 0) { - ARRAY_TO_STREAM(p, data.data(), size); - len += size; - ARRAY_TO_STREAM(p, data_mask.data(), size); - len += size; - } - } - - btu_hcif_send_cmd_with_cb( - FROM_HERE, HCI_BLE_ADV_FILTER, param, len, - base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_SRVC_DATA, cb)); - - memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); -} - /******************************************************************************* * * Function btm_ble_cs_update_pf_counter @@ -417,7 +269,7 @@ static uint8_t btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, uint8_t* p_counter = NULL; if (cond_type > BTM_BLE_PF_TYPE_ALL) { - BTM_TRACE_ERROR("unknown PF filter condition type %d", cond_type); + LOG_ERROR("unknown PF filter condition type %d", cond_type); return BTM_BLE_INVALID_COUNTER; } @@ -448,354 +300,18 @@ static uint8_t btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, p_counter = p_addr_filter->pf_counter; if (num_available > 0) p_counter[cond_type] += 1; - BTM_TRACE_DEBUG("counter = %d, maxfilt = %d, num_avbl=%d", - p_counter[cond_type], cmn_ble_vsc_cb.max_filter, - num_available); + LOG_VERBOSE("counter = %d, maxfilt = %d, num_avbl=%d", + p_counter[cond_type], cmn_ble_vsc_cb.max_filter, + num_available); return p_counter[cond_type]; } } else { - BTM_TRACE_ERROR("no matching filter counter found"); + LOG_ERROR("no matching filter counter found"); } /* no matching filter located and updated */ return BTM_BLE_INVALID_COUNTER; } -/** - * This function updates the address filter of adv. - */ -static void BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - tBLE_BD_ADDR addr, tBTM_BLE_PF_CFG_CBACK cb) { - const uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN; - - uint8_t param[len]; - memset(param, 0, len); - - uint8_t* p = param; - UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR); - UINT8_TO_STREAM(p, action); - UINT8_TO_STREAM(p, filt_index); - - if (action != BTM_BLE_SCAN_COND_CLEAR) { - LOG(INFO) << __func__ << " Filter address " << addr.bda - << " has DEVICE_TYPE_ALL, try to get identity address"; - /* - * Always do the pseudo to id address check! - * - * In the happy path case this should be checking only random types. - * - * However, the Java layer only knows PUBLIC and RANDOM which leaves us with - * 0 and 1 respectively. - * - * In the native host stack we have 4 values. - *  - Public = 0 - *  - Random = 1 - *  - Public ID = 2 - *  - Random ID = 3 - * - * So we should really only need to do it for Random = 1. - * - * The app layer won't know the ID address since it didn't see it when it - * was scanning. - * - * Two possible CUJ: - * 1. app scans, finds RPA, bonds. App will only know RPA (pseudo address) - * 2. app knows the (preshared) ID address (e.g. DCK+OOB+IRK) - * - * We cannot lock it to RANDOM here otherwise we break CUJ #1. - * - * Thus, we must always try to do the conversion. - */ - btm_random_pseudo_to_identity_addr(&addr.bda, &addr.type); - - LOG(INFO) << __func__ - << " Adding scan filter with peer address: " << addr.bda; - - BDADDR_TO_STREAM(p, addr.bda); - /* - * DANGER: Thar be dragons! - * - * The vendor command (APCF Filtering 0x0157) takes Public (0) or Random (1) - * or Any (2). - * - * Advertising results have four types: - *  - Public = 0 - *  - Random = 1 - *  - Public ID = 2 - *  - Random ID = 3 - * - * e.g. specifying PUBLIC (0) will only return results with a public - * address. It will ignore resolved addresses, since they return PUBLIC - * IDENTITY (2). For this, Any (0x02) must be specified. This should also - * cover if the RPA is derived from RANDOM STATIC. - */ - /* ALWAYS FORCE 2 for this vendor command! */ - uint8_t addr_type = - 0x02; // Really, you will break scanning if you change this. - UINT8_TO_STREAM(p, addr_type); - } - - /* send address filter */ - btu_hcif_send_cmd_with_cb( - FROM_HERE, HCI_BLE_ADV_FILTER, param, len, - base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_ADDR, cb)); - - memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); -} - -/** - * This function updates(adds, deletes or clears) the service UUID filter. - */ -static void BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_COND_TYPE filter_type, - const bluetooth::Uuid& uuid, - tBTM_BLE_PF_LOGIC_TYPE cond_logic, - const bluetooth::Uuid& uuid_mask, - tBTM_BLE_PF_CFG_CBACK cb) { - uint8_t evt_type; - - if (BTM_BLE_PF_SRVC_UUID == filter_type) { - evt_type = BTM_BLE_META_PF_UUID; - } else { - evt_type = BTM_BLE_META_PF_SOL_UUID; - } - - uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; - uint8_t max_len = len + BTM_BLE_META_UUID_LEN; - uint8_t param[max_len]; - memset(param, 0, max_len); - uint8_t* p = param; - - UINT8_TO_STREAM(p, evt_type); - UINT8_TO_STREAM(p, action); - UINT8_TO_STREAM(p, filt_index); - - uint8_t uuid_len = uuid.GetShortestRepresentationSize(); - if (action != BTM_BLE_SCAN_COND_CLEAR) { - if (uuid_len == Uuid::kNumBytes16) { - UINT16_TO_STREAM(p, uuid.As16Bit()); - len += Uuid::kNumBytes16; - } else if (uuid_len == Uuid::kNumBytes32) { - UINT32_TO_STREAM(p, uuid.As32Bit()); - len += Uuid::kNumBytes32; - } else if (uuid_len == Uuid::kNumBytes128) { - const auto& tmp = uuid.To128BitLE(); - ARRAY_TO_STREAM(p, tmp.data(), (int)Uuid::kNumBytes128); - len += Uuid::kNumBytes128; - } else { - BTM_TRACE_ERROR("illegal UUID length: %d", uuid_len); - cb.Run(0, BTM_BLE_PF_CONFIG, BTM_ILLEGAL_VALUE); - return; - } - - if (!uuid_mask.IsEmpty()) { - if (uuid_len == Uuid::kNumBytes16) { - UINT16_TO_STREAM(p, uuid_mask.As16Bit()); - len += Uuid::kNumBytes16; - } else if (uuid_len == Uuid::kNumBytes32) { - UINT32_TO_STREAM(p, uuid_mask.As32Bit()); - len += Uuid::kNumBytes32; - } else if (uuid_len == Uuid::kNumBytes128) { - const auto& tmp = uuid_mask.To128BitLE(); - ARRAY_TO_STREAM(p, tmp.data(), (int)Uuid::kNumBytes128); - len += Uuid::kNumBytes128; - } - } else { - memset(p, 0xff, uuid_len); - len += uuid_len; - } - } - - /* send UUID filter update */ - btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER, param, len, - base::Bind(&btm_flt_update_cb, evt_type, cb)); - memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); -} - -/* - * Used to remove device records for devices setting scan filters with address, - * type and IRK. Flow: - * - ScanFilter comes in with IRK. - * - Check IRK for empty, if empty ignore setting to resolving list. - * - Otherwise we set it to the resolving list via BTM_SecAddBleKey. - * - Then on clear we need to check if the device is paired and if it isn't we - * remove it referencing this map. - * - */ -static std::unordered_map - remove_me_later_map; - -void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector commands, - tBTM_BLE_PF_CFG_CBACK cb) { - if (!is_filtering_supported()) { - cb.Run(0, BTM_BLE_PF_ENABLE, BTM_MODE_UNSUPPORTED); - return; - } - - tBTM_BLE_SCAN_COND_OP action = BTM_BLE_SCAN_COND_ADD; - for (const ApcfCommand& cmd : commands) { - /* If data is passed, both mask and data have to be the same length */ - if (cmd.data.size() != cmd.data_mask.size() && cmd.data.size() != 0 && - cmd.data_mask.size() != 0) { - LOG(ERROR) << __func__ << " data(" << cmd.data.size() << ") and mask(" - << cmd.data_mask.size() << ") are of different size"; - continue; - } - - switch (cmd.type) { - case BTM_BLE_PF_ADDR_FILTER: { - tBLE_BD_ADDR target_addr; - target_addr.bda = cmd.address; - target_addr.type = (cmd.addr_type & (~BLE_ADDR_TYPE_ID_BIT)); - - BTM_LE_PF_addr_filter(action, filt_index, target_addr, - base::DoNothing()); - if (!is_empty_128bit(cmd.irk)) { - // Save index and addr - auto entry = remove_me_later_map.find(filt_index); - if (entry != remove_me_later_map.end()) { - LOG_WARN("Replacing existing filter index entry with new address"); - // If device is not bonded, then try removing the device - // If the device doesn't get removed then it is currently connected - // (may be pairing?) If we do delete the device we want to erase the - // filter index so we can replace it If the device is bonded, we - // want to erase the filter index so we don't delete it in the later - // BTM_LE_PF_clear call. - if (!btm_sec_is_a_bonded_dev(entry->second)) { - if (!BTM_SecDeleteDevice(entry->second)) { - LOG_WARN("Unable to remove device, still connected."); - return; - } - } - remove_me_later_map.erase(filt_index); - } - if (btm_find_dev(cmd.address) != nullptr) { - // Unless the user tries to bond with a device in between the - // scanner app starting a scan, then crashing, then being restarted - // and we get to this same point with the same filt_index (whose - // value is managed by the Java layer) then we might have a device - // record here, in which case something else is managing the device - // and we do not want to interfere with that experience. - LOG_WARN("Address record already exists...this is unexpected..."); - return; - } - // Allocate a new "temporary" device record - - btm_sec_alloc_dev(cmd.address); - remove_me_later_map.emplace(filt_index, cmd.address); - // Set the IRK - tBTM_LE_PID_KEYS pid_keys; - pid_keys.irk = cmd.irk; - pid_keys.identity_addr_type = - (cmd.addr_type & (~BLE_ADDR_TYPE_ID_BIT)); - pid_keys.identity_addr = cmd.address; - // Add it to the union to pass to SecAddBleKey - tBTM_LE_KEY_VALUE le_key; - le_key.pid_key = pid_keys; - BTM_SecAddBleKey(cmd.address, &le_key, BTM_LE_KEY_PID); - } - break; - } - - case BTM_BLE_PF_SRVC_DATA: - BTM_LE_PF_srvc_data(action, filt_index); - break; - - case BTM_BLE_PF_SRVC_UUID: - case BTM_BLE_PF_SRVC_SOL_UUID: { - BTM_LE_PF_uuid_filter(action, filt_index, cmd.type, cmd.uuid, - BTM_BLE_PF_LOGIC_AND, cmd.uuid_mask, - base::DoNothing()); - break; - } - - case BTM_BLE_PF_LOCAL_NAME: { - BTM_LE_PF_local_name(action, filt_index, cmd.name, base::DoNothing()); - break; - } - - case BTM_BLE_PF_MANU_DATA: { - BTM_LE_PF_manu_data(action, filt_index, cmd.company, cmd.company_mask, - cmd.data, cmd.data_mask, base::DoNothing()); - break; - } - - case BTM_BLE_PF_SRVC_DATA_PATTERN: { - BTM_LE_PF_srvc_data_pattern(action, filt_index, cmd.data, cmd.data_mask, - base::DoNothing()); - break; - } - - default: - LOG(ERROR) << __func__ << ": Unknown filter type: " << +cmd.type; - break; - } - } - cb.Run(0, 0, BTM_SUCCESS); -} - -/** - * all adv payload filter by de-selecting all the adv pf feature bits - */ -void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_CFG_CBACK cb) { - if (!is_filtering_supported()) { - cb.Run(0, BTM_BLE_PF_ENABLE, BTM_MODE_UNSUPPORTED); - return; - } - - /* clear the general filter entry */ - { - tBTM_BLE_PF_CFG_CBACK fDoNothing; - - /* clear manufactuer data filter */ - BTM_LE_PF_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, 0, 0, {}, {}, - fDoNothing); - - /* clear local name filter */ - BTM_LE_PF_local_name(BTM_BLE_SCAN_COND_CLEAR, filt_index, {}, fDoNothing); - - /* update the counter for service data */ - BTM_LE_PF_srvc_data(BTM_BLE_SCAN_COND_CLEAR, filt_index); - - /* clear UUID filter */ - BTM_LE_PF_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index, - BTM_BLE_PF_SRVC_UUID, {}, 0, Uuid::kEmpty, - fDoNothing); - - BTM_LE_PF_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index, - BTM_BLE_PF_SRVC_SOL_UUID, {}, 0, Uuid::kEmpty, - fDoNothing); - - /* clear service data filter */ - BTM_LE_PF_srvc_data_pattern(BTM_BLE_SCAN_COND_CLEAR, filt_index, {}, {}, - fDoNothing); - } - - uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_PF_FEAT_SEL_LEN; - uint8_t param[len]; - memset(param, 0, len); - - uint8_t* p = param; - - /* select feature based on control block settings */ - UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); - UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR); - UINT8_TO_STREAM(p, filt_index); - /* set PCF selection */ - UINT32_TO_STREAM(p, BTM_BLE_PF_SELECT_NONE); - /* set logic condition as OR as default */ - UINT8_TO_STREAM(p, BTM_BLE_PF_LOGIC_OR); - - btu_hcif_send_cmd_with_cb( - FROM_HERE, HCI_BLE_ADV_FILTER, param, len, - base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb)); - - memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); -} - /******************************************************************************* * * Function BTM_BleAdvFilterParamSetup @@ -825,17 +341,17 @@ void BTM_BleAdvFilterParamSetup( p = param; memset(param, 0, len); - BTM_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); if (BTM_BLE_SCAN_COND_ADD == action) { p_bda_filter = btm_ble_find_addr_filter_counter(nullptr); if (NULL == p_bda_filter) { - BTM_TRACE_ERROR("BD Address not found!"); + LOG_ERROR("BD Address not found!"); cb.Run(0, BTM_BLE_PF_ENABLE, btm_status_value(BTM_UNKNOWN_ADDR)); return; } - BTM_TRACE_DEBUG("%s : Feat mask:%d", __func__, p_filt_params->feat_seln); + LOG_VERBOSE("%s : Feat mask:%d", __func__, p_filt_params->feat_seln); /* select feature based on control block settings */ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_ADD); @@ -904,59 +420,6 @@ void BTM_BleAdvFilterParamSetup( } } -static void enable_cmpl_cback(tBTM_BLE_PF_STATUS_CBACK p_stat_cback, uint8_t* p, - uint16_t evt_len) { - uint8_t status, op_subcode, action; - - if (evt_len != 3) { - BTM_TRACE_ERROR("%s: APCF callback length = %d", __func__, evt_len); - return; - } - - STREAM_TO_UINT8(status, p); - STREAM_TO_UINT8(op_subcode, p); - STREAM_TO_UINT8(action, p); - - if (op_subcode != BTM_BLE_META_PF_ENABLE) { - BTM_TRACE_ERROR("%s :bad subcode: 0x%02x", __func__, op_subcode); - return; - } - - tBTM_STATUS btm_status = (status == 0) ? BTM_SUCCESS : BTM_ERR_PROCESSING; - p_stat_cback.Run(action, btm_status); -} - -/******************************************************************************* - * - * Function BTM_BleEnableDisableFilterFeature - * - * Description This function is called to enable / disable the APCF feature - * - * Parameters enable: enable or disable the filter condition - * p_stat_cback - Status callback pointer - * - ******************************************************************************/ -void BTM_BleEnableDisableFilterFeature(uint8_t enable, - tBTM_BLE_PF_STATUS_CBACK p_stat_cback) { - if (!is_filtering_supported()) { - if (p_stat_cback) - p_stat_cback.Run(BTM_BLE_PF_ENABLE, - BTM_MODE_UNSUPPORTED /* BTA_FAILURE */); - return; - } - - uint8_t param[20]; - memset(param, 0, 20); - - uint8_t* p = param; - UINT8_TO_STREAM(p, BTM_BLE_META_PF_ENABLE); - UINT8_TO_STREAM(p, enable); - - btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER, param, - BTM_BLE_PCF_ENABLE_LEN, - base::Bind(&enable_cmpl_cback, p_stat_cback)); -} - /******************************************************************************* * * Function btm_ble_adv_filter_init diff --git a/system/stack/btm/btm_ble_batchscan.cc b/system/stack/btm/btm_ble_batchscan.cc index 8c1886b4e7967721cc2248cab1a83ed3b39b4a16..bccdcc4b5b87437ae1dda598294f8272e0a23ecc 100644 --- a/system/stack/btm/btm_ble_batchscan.cc +++ b/system/stack/btm/btm_ble_batchscan.cc @@ -15,17 +15,23 @@ * limitations under the License. * ******************************************************************************/ +#define LOG_TAG "ble_batchscan" + #include #include #include #include + #include -#include "bt_target.h" #include "btm_ble_api.h" -#include "btu.h" #include "device/include/controller.h" +#include "os/log.h" +#include "osi/include/allocator.h" #include "stack/btm/btm_int_types.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_client_interface.h" +#include "stack/include/btu_hcif.h" extern tBTM_CB btm_cb; @@ -69,7 +75,7 @@ void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len, STREAM_TO_UINT8(sub_event, p); len -= 1; - BTM_TRACE_EVENT( + LOG_VERBOSE( "btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x", sub_event); if (HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT == sub_event && @@ -145,13 +151,13 @@ void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len, STREAM_TO_UINT8(adv_data.advertiser_state, p); } - BTM_TRACE_EVENT("track_adv_vse_cback called: %d, %d, %d", - adv_data.filt_index, adv_data.addr_type, - adv_data.advertiser_state); + LOG_VERBOSE("track_adv_vse_cback called: %d, %d, %d", adv_data.filt_index, + adv_data.addr_type, adv_data.advertiser_state); // Make sure the device is known - BTM_SecAddBleDevice(adv_data.bd_addr, BT_DEVICE_TYPE_BLE, - to_ble_addr_type(adv_data.addr_type)); + get_btm_client_interface().security.BTM_SecAddBleDevice( + adv_data.bd_addr, BT_DEVICE_TYPE_BLE, + to_ble_addr_type(adv_data.addr_type)); ble_advtrack_cb.p_track_cback(&adv_data); } @@ -159,7 +165,7 @@ void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len, return; err_out: - BTM_TRACE_ERROR("malformatted packet detected"); + LOG_ERROR("malformatted packet detected"); osi_free_and_reset((void **) &adv_data.p_adv_pkt_data); osi_free_and_reset((void **) &adv_data.p_scan_rsp_data); @@ -167,7 +173,7 @@ err_out: void feat_enable_cb(uint8_t* p, uint16_t len) { if (len < 2) { - BTM_TRACE_ERROR("%s: wrong length", __func__); + LOG_ERROR("%s: wrong length", __func__); return; } @@ -177,13 +183,13 @@ void feat_enable_cb(uint8_t* p, uint16_t len) { uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE; if (subcode != expected_opcode) { - BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__, - expected_opcode, subcode); + LOG_ERROR("%s: bad subcode, expected: %d got: %d", __func__, + expected_opcode, subcode); return; } if (ble_batchscan_cb.cur_state != BTM_BLE_SCAN_ENABLE_CALLED) - BTM_TRACE_ERROR("%s: state should be ENABLE_CALLED", __func__); + LOG_ERROR("%s: state should be ENABLE_CALLED", __func__); ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLED_STATE; } @@ -191,7 +197,7 @@ void feat_enable_cb(uint8_t* p, uint16_t len) { void storage_config_cb(Callback cb, uint8_t* p, uint16_t len) { if (len < 2) { - BTM_TRACE_ERROR("%s: wrong length", __func__); + LOG_ERROR("%s: wrong length", __func__); return; } @@ -201,8 +207,8 @@ void storage_config_cb(Callback cb, uint8_t* p, uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM; if (subcode != expected_opcode) { - BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__, - expected_opcode, subcode); + LOG_ERROR("%s: bad subcode, expected: %d got: %d", __func__, + expected_opcode, subcode); return; } @@ -212,7 +218,7 @@ void storage_config_cb(Callback cb, uint8_t* p, void param_enable_cb(Callback cb, uint8_t* p, uint16_t len) { if (len < 2) { - BTM_TRACE_ERROR("%s: wrong length", __func__); + LOG_ERROR("%s: wrong length", __func__); return; } @@ -222,8 +228,8 @@ void param_enable_cb(Callback cb, uint8_t* p, uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_PARAMS; if (subcode != expected_opcode) { - BTM_TRACE_ERROR("%s: bad subcode: 0x%02x 0x%02x", __func__, expected_opcode, - subcode); + LOG_ERROR("%s: bad subcode: 0x%02x 0x%02x", __func__, expected_opcode, + subcode); return; } @@ -233,7 +239,7 @@ void param_enable_cb(Callback cb, uint8_t* p, void disable_cb(base::Callback cb, uint8_t* p, uint16_t len) { if (len < 2) { - BTM_TRACE_ERROR("%s: wrong length", __func__); + LOG_ERROR("%s: wrong length", __func__); return; } @@ -243,19 +249,19 @@ void disable_cb(base::Callback cb, uint8_t* p, uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_PARAMS; if (subcode != expected_opcode) { - BTM_TRACE_ERROR("%s: bad subcode: 0x%02x 0x%02x", __func__, expected_opcode, - subcode); + LOG_ERROR("%s: bad subcode: 0x%02x 0x%02x", __func__, expected_opcode, + subcode); return; } if (ble_batchscan_cb.cur_state != BTM_BLE_SCAN_DISABLE_CALLED) { - BTM_TRACE_ERROR("%s: state should be DISABLE_CALLED", __func__); + LOG_ERROR("%s: state should be DISABLE_CALLED", __func__); } if (BTM_SUCCESS == status) { ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE; } else { - BTM_TRACE_ERROR("%s: Invalid state after disabled", __func__); + LOG_ERROR("%s: Invalid state after disabled", __func__); ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE; } @@ -284,7 +290,7 @@ void btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, void read_reports_cb(std::vector data_all, uint8_t num_records_all, tBTM_BLE_SCAN_REP_CBACK cb, uint8_t* p, uint16_t len) { if (len < 2) { - BTM_TRACE_ERROR("%s: wrong length", __func__); + LOG_ERROR("%s: wrong length", __func__); return; } @@ -294,13 +300,13 @@ void read_reports_cb(std::vector data_all, uint8_t num_records_all, uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_READ_RESULTS; if (subcode != expected_opcode) { - BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__, - expected_opcode, subcode); + LOG_ERROR("%s: bad subcode, expected: %d got: %d", __func__, + expected_opcode, subcode); return; } if (len < 4) { - BTM_TRACE_ERROR("%s: wrong length", __func__); + LOG_ERROR("%s: wrong length", __func__); return; } @@ -308,8 +314,8 @@ void read_reports_cb(std::vector data_all, uint8_t num_records_all, STREAM_TO_UINT8(report_format, p); STREAM_TO_UINT8(num_records, p); - BTM_TRACE_DEBUG("%s: status=%d,len=%d,rec=%d", __func__, status, len - 4, - num_records); + LOG_VERBOSE("%s: status=%d,len=%d,rec=%d", __func__, status, len - 4, + num_records); if (num_records == 0) { cb.Run(BTM_SUCCESS, report_format, num_records_all, data_all); @@ -421,9 +427,9 @@ void BTM_BleSetStorageConfig(uint8_t batch_scan_full_max, return; } - BTM_TRACE_EVENT("%s: %d, %d, %d, %d, %d", __func__, - ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max, - batch_scan_trunc_max, batch_scan_notify_threshold); + LOG_VERBOSE("%s: %d, %d, %d, %d, %d", __func__, ble_batchscan_cb.cur_state, + ref_value, batch_scan_full_max, batch_scan_trunc_max, + batch_scan_notify_threshold); ble_batchscan_cb.p_thres_cback = p_thres_cback; ble_batchscan_cb.ref_value = ref_value; @@ -431,7 +437,7 @@ void BTM_BleSetStorageConfig(uint8_t batch_scan_full_max, if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX || batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX || batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX) { - BTM_TRACE_ERROR("Illegal set storage config params"); + LOG_ERROR("Illegal set storage config params"); cb.Run(BTM_ILLEGAL_VALUE); return; } @@ -455,16 +461,16 @@ void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode, tBLE_ADDR_TYPE addr_type, tBTM_BLE_DISCARD_RULE discard_rule, Callback cb) { - BTM_TRACE_EVENT("%s: %d, %d, %d, %d, %d, %d", __func__, scan_mode, - scan_interval, scan_window, addr_type, discard_rule); + LOG_VERBOSE("%s: %d, %d, %d, %d, %d", __func__, scan_mode, scan_interval, + scan_window, addr_type, discard_rule); if (!can_do_batch_scan()) { cb.Run(BTM_ERR_PROCESSING); return; } - BTM_TRACE_DEBUG("%s: %d, %x, %x, %d, %d", __func__, scan_mode, scan_interval, - scan_window, discard_rule, ble_batchscan_cb.cur_state); + LOG_VERBOSE("%s: %d, %x, %x, %d, %d", __func__, scan_mode, scan_interval, + scan_window, discard_rule, ble_batchscan_cb.cur_state); /* Only 16 bits will be used for scan interval and scan window as per * agreement with Google */ @@ -479,7 +485,7 @@ void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode, (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule || BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule)) { } else { - BTM_TRACE_ERROR("%s: Illegal enable scan params", __func__); + LOG_ERROR("%s: Illegal enable scan params", __func__); cb.Run(BTM_ILLEGAL_VALUE); return; } @@ -503,7 +509,7 @@ void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode, /* This function is called to disable batch scanning */ void BTM_BleDisableBatchScan(base::Callback cb) { - BTM_TRACE_EVENT(" BTM_BleDisableBatchScan"); + LOG_VERBOSE(" BTM_BleDisableBatchScan"); if (!can_do_batch_scan()) { cb.Run(BTM_ERR_PROCESSING); @@ -522,10 +528,10 @@ void BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, tBTM_BLE_SCAN_REP_CBACK cb) { uint8_t read_scan_mode = 0; - BTM_TRACE_EVENT("%s; %d", __func__, scan_mode); + LOG_VERBOSE("%s; %d", __func__, scan_mode); if (!can_do_batch_scan()) { - BTM_TRACE_ERROR("Controller does not support batch scan"); + LOG_ERROR("Controller does not support batch scan"); cb.Run(BTM_ERR_PROCESSING, 0, 0, {}); return; } @@ -539,8 +545,8 @@ void BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, * scan */ if (scan_mode != BTM_BLE_BATCH_SCAN_MODE_PASS && scan_mode != BTM_BLE_BATCH_SCAN_MODE_ACTI) { - BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, - scan_mode, ble_batchscan_cb.cur_state); + LOG_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, scan_mode, + ble_batchscan_cb.cur_state); cb.Run(BTM_ILLEGAL_VALUE, 0, 0, {}); return; } @@ -553,10 +559,10 @@ void BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, /* This function is called to setup the callback for tracking */ void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback, tBTM_BLE_REF_VALUE ref_value) { - BTM_TRACE_EVENT("%s:", __func__); + LOG_VERBOSE("%s:", __func__); if (!can_do_batch_scan()) { - BTM_TRACE_ERROR("Controller does not support batch scan"); + LOG_ERROR("Controller does not support batch scan"); tBTM_BLE_TRACK_ADV_DATA track_adv_data; memset(&track_adv_data, 0, sizeof(tBTM_BLE_TRACK_ADV_DATA)); @@ -576,7 +582,7 @@ void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback, * This function initialize the batch scan control block. **/ void btm_ble_batchscan_init(void) { - BTM_TRACE_EVENT(" btm_ble_batchscan_init"); + LOG_VERBOSE(" btm_ble_batchscan_init"); memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB)); memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB)); BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, true); diff --git a/system/stack/btm/btm_ble_bgconn.cc b/system/stack/btm/btm_ble_bgconn.cc index 30437263b0f5140ba6c9c643f1d34ba393d07028..d1c70db45a7db082d0ffd05ffd8140d0adedcaaa 100644 --- a/system/stack/btm/btm_ble_bgconn.cc +++ b/system/stack/btm/btm_ble_bgconn.cc @@ -22,28 +22,23 @@ * ******************************************************************************/ -#include -#include +#define LOG_TAG "ble_bgconn" + +#include "stack/btm/btm_ble_bgconn.h" #include #include #include "device/include/controller.h" #include "main/shim/acl_api.h" -#include "main/shim/shim.h" +#include "os/log.h" +#include "stack/btm/btm_ble_int.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_int_types.h" -#include "stack/btm/security_device_record.h" -#include "stack/include/bt_types.h" #include "types/raw_address.h" extern tBTM_CB btm_cb; -namespace { - - -} // namespace - // Unfortunately (for now?) we have to maintain a copy of the device acceptlist // on the host to determine if a device is pending to be connected or not. This // controls whether the host should keep trying to scan for acceptlisted @@ -68,34 +63,6 @@ struct BgConnHash { static std::unordered_map background_connections; -const tBLE_BD_ADDR convert_to_address_with_type( - const RawAddress& bd_addr, const tBTM_SEC_DEV_REC* p_dev_rec) { - if (p_dev_rec == nullptr || !p_dev_rec->is_device_type_has_ble()) { - return { - .type = BLE_ADDR_PUBLIC, - .bda = bd_addr, - }; - } - - if (p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { - return { - .type = p_dev_rec->ble.AddressType(), - .bda = bd_addr, - }; - } else { - // Floss doesn't support LL Privacy (yet). To expedite ARC testing, always - // connect to the latest LE random address rather than redesign. - // TODO(b/235218533): Remove when LL Privacy is implemented. -#if TARGET_FLOSS - return { - .type = BLE_ADDR_RANDOM, - .bda = p_dev_rec->ble.cur_rand_addr.address, - }; -#endif - return p_dev_rec->ble.identity_address_with_type; - } -} - /******************************************************************************* * * Function btm_update_scanner_filter_policy @@ -110,7 +77,7 @@ void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) { uint32_t scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window; - BTM_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); p_inq->sfp = scan_policy; p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE @@ -156,29 +123,6 @@ bool btm_ble_resume_bg_conn(void) { return true; } -bool BTM_BackgroundConnectAddressKnown(const RawAddress& address) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); - - // not a known device, or a classic device, we assume public address - if (p_dev_rec == NULL || (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == 0) - return true; - - // bonded device with identity address known - if (!p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { - return true; - } - - // Public address, Random Static, or Random Non-Resolvable Address known - if (p_dev_rec->ble.AddressType() == BLE_ADDR_PUBLIC || - !BTM_BLE_IS_RESOLVE_BDA(address)) { - return true; - } - - // Only Resolvable Private Address (RPA) is known, we don't allow it into - // the background connection procedure. - return false; -} - /** Adds the device into acceptlist. Returns false if acceptlist is full and * device can't be added, true otherwise. */ bool BTM_AcceptlistAdd(const RawAddress& address) { @@ -194,10 +138,8 @@ bool BTM_AcceptlistAdd(const RawAddress& address, bool is_direct) { return false; } - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); - return bluetooth::shim::ACL_AcceptLeConnectionFrom( - convert_to_address_with_type(address, p_dev_rec), is_direct); + BTM_Sec_GetAddressWithType(address), is_direct); } /** Removes the device from acceptlist */ @@ -207,10 +149,8 @@ void BTM_AcceptlistRemove(const RawAddress& address) { return; } - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); - bluetooth::shim::ACL_IgnoreLeConnectionFrom( - convert_to_address_with_type(address, p_dev_rec)); + BTM_Sec_GetAddressWithType(address)); return; } diff --git a/system/stack/btm/btm_ble_cont_energy.cc b/system/stack/btm/btm_ble_cont_energy.cc index 0d7f45888ef69fc6f7c9e9aa4b7a29b658e404e9..ef7600382e4520a8754550448fcec333dc29d262 100644 --- a/system/stack/btm/btm_ble_cont_energy.cc +++ b/system/stack/btm/btm_ble_cont_energy.cc @@ -16,11 +16,16 @@ * ******************************************************************************/ +#define LOG_TAG "btm_ble_cont_energy" + +#include #include -#include "bt_target.h" +#include "bt_target.h" #include "btm_ble_api.h" +#include "os/log.h" #include "stack/btm/btm_int_types.h" +#include "stack/include/bt_types.h" extern tBTM_CB btm_cb; @@ -44,7 +49,7 @@ static void btm_ble_cont_energy_cmpl_cback(tBTM_VSC_CMPL* p_params) { total_energy_used = 0; if (len < 17) { - BTM_TRACE_ERROR("wrong length for btm_ble_cont_energy_cmpl_cback"); + LOG_ERROR("wrong length for btm_ble_cont_energy_cmpl_cback"); return; } @@ -56,9 +61,10 @@ static void btm_ble_cont_energy_cmpl_cback(tBTM_VSC_CMPL* p_params) { STREAM_TO_UINT32(total_idle_time, p); STREAM_TO_UINT32(total_energy_used, p); - BTM_TRACE_DEBUG( - "energy_info status=%d,tx_t=%ld, rx_t=%ld, ener_used=%ld, idle_t=%ld", - status, total_tx_time, total_rx_time, total_energy_used, total_idle_time); + LOG_VERBOSE("energy_info status=%d,tx_t=%" PRId32 ", rx_t=%" PRId32 + ", ener_used=%" PRId32 ", idle_t=%" PRId32, + status, total_tx_time, total_rx_time, total_energy_used, + total_idle_time); if (NULL != ble_energy_info_cb.p_ener_cback) ble_energy_info_cb.p_ener_cback(total_tx_time, total_rx_time, @@ -84,10 +90,10 @@ tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback) { BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); - BTM_TRACE_EVENT("BTM_BleGetEnergyInfo"); + LOG_VERBOSE("BTM_BleGetEnergyInfo"); if (0 == cmn_ble_vsc_cb.energy_support) { - BTM_TRACE_ERROR("Controller does not support get energy info"); + LOG_ERROR("Controller does not support get energy info"); return BTM_ERR_PROCESSING; } diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc index 3458443aa103718767f7cba146431bbc100214c4..ac24e99a216c50be92756829453f5d10f1758380 100644 --- a/system/stack/btm/btm_ble_gap.cc +++ b/system/stack/btm/btm_ble_gap.cc @@ -24,6 +24,7 @@ #define LOG_TAG "bt_btm_ble" +#include #include #include #include @@ -32,28 +33,34 @@ #include #include #include +#include #include #include "bta/include/bta_api.h" #include "common/time_util.h" #include "device/include/controller.h" #include "main/shim/acl_api.h" -#include "main/shim/btm_api.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" +#include "osi/include/allocator.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "osi/include/properties.h" +#include "osi/include/stack_power_telemetry.h" #include "stack/acl/acl.h" #include "stack/btm/btm_ble_int.h" #include "stack/btm/btm_ble_int_types.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_int_types.h" +#include "stack/btm/btm_sec.h" +#include "stack/btm/btm_sec_cb.h" #include "stack/gatt/gatt_int.h" #include "stack/include/acl_api.h" #include "stack/include/advertise_data_parser.h" #include "stack/include/ble_scanner.h" #include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_api_types.h" +#include "stack/include/btm_ble_addr.h" +#include "stack/include/btm_ble_privacy.h" +#include "stack/include/btm_log_history.h" #include "stack/include/gap_api.h" #include "stack/include/hci_error_code.h" #include "stack/include/inq_hci_link_interface.h" @@ -63,15 +70,8 @@ extern tBTM_CB btm_cb; void btm_inq_remote_name_timer_timeout(void* data); -bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, - const RawAddress& new_pseudo_addr); -bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr, - tBLE_ADDR_TYPE* p_addr_type, - bool refresh); void btm_ble_batchscan_init(void); void btm_ble_adv_filter_init(void); -extern const tBLE_BD_ADDR convert_to_address_with_type( - const RawAddress& bd_addr, const tBTM_SEC_DEV_REC* p_dev_rec); #define BTM_EXT_BLE_RMT_NAME_TIMEOUT_MS (30 * 1000) #define MIN_ADV_LENGTH 2 @@ -184,9 +184,12 @@ AdvertisingCache cache; } // namespace -#if (BLE_VND_INCLUDED == TRUE) +bool ble_vnd_is_included() { + // replace build time config BLE_VND_INCLUDED with runtime + return GET_SYSPROP(Ble, vnd_included, true); +} + static tBTM_BLE_CTRL_FEATURES_CBACK* p_ctrl_le_feature_rd_cmpl_cback = NULL; -#endif /**********PAST & PS *******************/ using StartSyncCb = base::Callbackscan_type, - scan_interval, scan_window); + LOG_VERBOSE("%s : scan_type:%d, %d, %d", __func__, p_inq->scan_type, + scan_interval, scan_window); if (!controller_get_interface()->supports_ble()) return BTM_ILLEGAL_VALUE; @@ -534,12 +537,12 @@ tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration, if (alarm_is_scheduled(btm_cb.ble_ctr_cb.observer_timer)) { alarm_cancel(btm_cb.ble_ctr_cb.observer_timer); } else { - BTM_TRACE_ERROR("%s Scan with no duration started twice!", __func__); + LOG_ERROR("%s Scan with no duration started twice!", __func__); } } else { if (!low_latency_scan && alarm_is_scheduled(btm_cb.ble_ctr_cb.observer_timer)) { - BTM_TRACE_ERROR("%s Scan with duration started twice!", __func__); + LOG_ERROR("%s Scan with duration started twice!", __func__); } } /* @@ -551,8 +554,8 @@ tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration, p_inq->scan_interval == BTM_BLE_GAP_DISC_SCAN_INT && p_inq->scan_window == BTM_BLE_LOW_LATENCY_SCAN_WIN; if (!low_latency_scan || is_ongoing_low_latency) { - BTM_TRACE_WARNING("%s Observer was already active, is_low_latency: %d", - __func__, is_ongoing_low_latency); + LOG_WARN("%s Observer was already active, is_low_latency: %d", __func__, + is_ongoing_low_latency); return BTM_CMD_STARTED; } // stop any scan without low latency config @@ -606,14 +609,12 @@ tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration, status = BTM_CMD_STARTED; btm_ble_stop_observe(); } else { - BTM_TRACE_ERROR("%s Observe not active", __func__); + LOG_ERROR("%s Observe not active", __func__); } return status; } -#if (BLE_VND_INCLUDED == TRUE) - static void btm_get_dynamic_audio_buffer_vsc_cmpl_cback( tBTM_VSC_CMPL* p_vsc_cmpl_params) { LOG(INFO) << __func__; @@ -678,7 +679,7 @@ static void btm_get_dynamic_audio_buffer_vsc_cmpl_cback( ******************************************************************************/ static void btm_ble_vendor_capability_vsc_cmpl_cback( tBTM_VSC_CMPL* p_vcs_cplt_params) { - BTM_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* Check status of command complete event */ CHECK(p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP); @@ -690,7 +691,7 @@ static void btm_ble_vendor_capability_vsc_cmpl_cback( tHCI_STATUS status = to_hci_status_code(raw_status); if (status != HCI_SUCCESS) { - BTM_TRACE_DEBUG("%s: Status = 0x%02x (0 is success)", __func__, status); + LOG_VERBOSE("%s: Status = 0x%02x (0 is success)", __func__, status); return; } CHECK(p_vcs_cplt_params->param_len >= BTM_VSC_CHIP_CAPABILITY_RSP_LEN); @@ -763,14 +764,12 @@ static void btm_ble_vendor_capability_vsc_cmpl_cback( btm_cb.cmn_ble_vsc_cb.values_read = true; - BTM_TRACE_DEBUG( - "%s: stat=%d, irk=%d, ADV ins:%d, rpa=%d, ener=%d, ext_scan=%d", __func__, - status, btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, - btm_cb.cmn_ble_vsc_cb.adv_inst_max, btm_cb.cmn_ble_vsc_cb.rpa_offloading, - btm_cb.cmn_ble_vsc_cb.energy_support, - btm_cb.cmn_ble_vsc_cb.extended_scan_support); - - btm_ble_adv_init(); + LOG_VERBOSE("%s: stat=%d, irk=%d, ADV ins:%d, rpa=%d, ener=%d, ext_scan=%d", + __func__, status, btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, + btm_cb.cmn_ble_vsc_cb.adv_inst_max, + btm_cb.cmn_ble_vsc_cb.rpa_offloading, + btm_cb.cmn_ble_vsc_cb.energy_support, + btm_cb.cmn_ble_vsc_cb.extended_scan_support); if (btm_cb.cmn_ble_vsc_cb.max_filter > 0) btm_ble_adv_filter_init(); @@ -786,7 +785,6 @@ static void btm_ble_vendor_capability_vsc_cmpl_cback( if (p_ctrl_le_feature_rd_cmpl_cback != NULL) p_ctrl_le_feature_rd_cmpl_cback(static_cast(status)); } -#endif /* (BLE_VND_INCLUDED == TRUE) */ /******************************************************************************* * @@ -807,7 +805,7 @@ void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb) { void BTM_BleGetDynamicAudioBuffer( tBTM_BT_DYNAMIC_AUDIO_BUFFER_CB p_dynamic_audio_buffer_cb[]) { - BTM_TRACE_DEBUG("BTM_BleGetDynamicAudioBuffer"); + LOG_VERBOSE("BTM_BleGetDynamicAudioBuffer"); if (NULL != p_dynamic_audio_buffer_cb) { for (int i = 0; i < 32; i++) { @@ -828,20 +826,17 @@ void BTM_BleGetDynamicAudioBuffer( * Returns void * ******************************************************************************/ -#if (BLE_VND_INCLUDED == TRUE) void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) { + if (!ble_vnd_is_included()) return; + if (btm_cb.cmn_ble_vsc_cb.values_read) return; - BTM_TRACE_DEBUG("BTM_BleReadControllerFeatures"); + LOG_VERBOSE("BTM_BleReadControllerFeatures"); p_ctrl_le_feature_rd_cmpl_cback = p_vsc_cback; BTM_VendorSpecificCommand(HCI_BLE_VENDOR_CAP, 0, NULL, btm_ble_vendor_capability_vsc_cmpl_cback); } -#else -void BTM_BleReadControllerFeatures( - UNUSED_ATTR tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) {} -#endif /******************************************************************************* * @@ -858,7 +853,7 @@ void BTM_BleReadControllerFeatures( bool BTM_BleConfigPrivacy(bool privacy_mode) { tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb; - BTM_TRACE_WARNING("%s %d", __func__, (int)privacy_mode); + LOG_WARN("%s %d", __func__, (int)privacy_mode); /* if LE is not supported, return error */ if (!controller_get_interface()->supports_ble()) return false; @@ -1173,7 +1168,7 @@ void btm_ble_periodic_adv_sync_established(uint8_t status, uint16_t sync_handle, adv_clock_accuracy); /*if (param_len != ADV_SYNC_ESTB_EVT_LEN) { - BTM_TRACE_ERROR("[PSync]%s: Invalid event length",__func__); + LOG_ERROR("[PSync]%s: Invalid event length",__func__); STREAM_TO_UINT8(status, param); if (status == BTM_SUCCESS) { STREAM_TO_UINT16(sync_handle, param); @@ -1194,10 +1189,9 @@ void btm_ble_periodic_adv_sync_established(uint8_t status, uint16_t sync_handle, } int index = btm_ble_get_psync_index(adv_sid, bda); if (index == MAX_SYNC_TRANSACTION) { - BTM_TRACE_WARNING("[PSync]%s: Invalid index for sync established", - __func__); + LOG_WARN("[PSync]%s: Invalid index for sync established", __func__); if (status == BTM_SUCCESS) { - BTM_TRACE_WARNING("%s: Terminate sync", __func__); + LOG_WARN("%s: Terminate sync", __func__); if (BleScanningManager::IsInitialized()) { BleScanningManager::Get()->PeriodicScanTerminate(sync_handle); } @@ -1406,24 +1400,23 @@ void BTM_BlePeriodicSyncTransfer(RawAddress addr, uint16_t service_data, uint16_t sync_handle, SyncTransferCb cb) { uint16_t conn_handle = BTM_GetHCIConnHandle(addr, BT_TRANSPORT_LE); tACL_CONN* p_acl = btm_acl_for_bda(addr, BT_TRANSPORT_LE); - BTM_TRACE_DEBUG("[PAST]%s for connection_handle = %x", __func__, conn_handle); + LOG_VERBOSE("[PAST]%s for connection_handle = %x", __func__, conn_handle); if (conn_handle == 0xFFFF || p_acl == NULL) { - BTM_TRACE_ERROR("[PAST]%s:Invalid connection handle or no LE ACL link", - __func__); + LOG_ERROR("[PAST]%s:Invalid connection handle or no LE ACL link", __func__); cb.Run(BTM_UNKNOWN_ADDR, addr); return; } if (!HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT( p_acl->peer_le_features)) { - BTM_TRACE_ERROR("[PAST]%s:Remote doesn't support PAST", __func__); + LOG_ERROR("[PAST]%s:Remote doesn't support PAST", __func__); cb.Run(BTM_MODE_UNSUPPORTED, addr); return; } int index = btm_ble_get_free_sync_transfer_index(); if (index == MAX_SYNC_TRANSACTION) { - BTM_TRACE_ERROR("Failed to get sync transfer index"); + LOG_ERROR("Failed to get sync transfer index"); cb.Run(BTM_ILLEGAL_VALUE, addr); return; } @@ -1468,7 +1461,7 @@ void BTM_BlePeriodicSyncSetInfo(RawAddress addr, uint16_t service_data, int index = btm_ble_get_free_sync_transfer_index(); if (index == MAX_SYNC_TRANSACTION) { - BTM_TRACE_ERROR("Failed to get sync transfer index"); + LOG_ERROR("Failed to get sync transfer index"); cb.Run(BTM_ILLEGAL_VALUE, addr); return; } @@ -1493,7 +1486,7 @@ void BTM_BlePeriodicSyncSetInfo(RawAddress addr, uint16_t service_data, * Description Host receives this event when synced PA has BIGInfo * ******************************************************************************/ -void btm_ble_biginfo_adv_report_rcvd(uint8_t* p, uint16_t param_len) { +void btm_ble_biginfo_adv_report_rcvd(const uint8_t* p, uint16_t param_len) { LOG_DEBUG("[PAST]: BIGINFO report received, len=%u", param_len); uint16_t sync_handle, iso_interval, max_pdu, max_sdu; uint8_t num_bises, nse, bn, pto, irc, phy, framing, encryption; @@ -1548,7 +1541,7 @@ void btm_ble_biginfo_adv_report_rcvd(uint8_t* p, uint16_t param_len) { * synced to PA associated with sync handle * ******************************************************************************/ -void btm_ble_periodic_adv_sync_tx_rcvd(uint8_t* p, uint16_t param_len) { +void btm_ble_periodic_adv_sync_tx_rcvd(const uint8_t* p, uint16_t param_len) { LOG_DEBUG("[PAST]: PAST received, param_len=%u", param_len); if (param_len < 19) { LOG_ERROR("%s", "Insufficient data"); @@ -1567,7 +1560,7 @@ void btm_ble_periodic_adv_sync_tx_rcvd(uint8_t* p, uint16_t param_len) { STREAM_TO_UINT8(adv_phy, p); STREAM_TO_UINT16(pa_int, p); STREAM_TO_UINT8(clk_acc, p); - BTM_TRACE_DEBUG( + LOG_VERBOSE( "[PAST]: status = %u, conn_handle = %u, service_data = %u," " sync_handle = %u, adv_sid = %u, address_type = %u, addr = %s," " adv_phy = %u, pa_int = %u, clk_acc = %u", @@ -1631,15 +1624,17 @@ static uint8_t btm_set_conn_mode_adv_init_addr( if (evt_type == BTM_BLE_CONNECT_EVT) { CHECK(p_peer_addr_type != nullptr); const tBLE_BD_ADDR ble_bd_addr = { - .bda = p_peer_addr_ptr, .type = *p_peer_addr_type, + .bda = p_peer_addr_ptr, }; LOG_DEBUG("Received BLE connect event %s", ADDRESS_TO_LOGGABLE_CSTR(ble_bd_addr)); evt_type = p_cb->directed_conn; - if (p_cb->directed_conn == BTM_BLE_CONNECT_DIR_EVT || - p_cb->directed_conn == BTM_BLE_CONNECT_LO_DUTY_DIR_EVT) { + if (static_cast>( + p_cb->directed_conn) == BTM_BLE_CONNECT_DIR_EVT || + static_cast>( + p_cb->directed_conn) == BTM_BLE_CONNECT_LO_DUTY_DIR_EVT) { /* for privacy 1.2, convert peer address as static, own address set as ID * addr */ if (btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_1_2 || @@ -1667,7 +1662,7 @@ static uint8_t btm_set_conn_mode_adv_init_addr( p_cb->afp != AP_SCAN_CONN_ALL) || btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_MIXED) { list_node_t* n = - list_foreach(btm_cb.sec_dev_rec, is_resolving_list_bit_set, NULL); + list_foreach(btm_sec_cb.sec_dev_rec, is_resolving_list_bit_set, NULL); if (n) { /* if enhanced privacy is required, set Identity address and matching IRK * peer */ @@ -1694,44 +1689,6 @@ static uint8_t btm_set_conn_mode_adv_init_addr( return evt_type; } -/** - * This function is called to set scan parameters. |cb| is called with operation - * status - **/ -void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window, - tBLE_SCAN_MODE scan_mode, - base::Callback cb) { - if (!controller_get_interface()->supports_ble()) { - LOG_INFO("Controller does not support ble"); - return; - } - - uint32_t max_scan_interval = BTM_BLE_EXT_SCAN_INT_MAX; - uint32_t max_scan_window = BTM_BLE_EXT_SCAN_WIN_MAX; - if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) { - max_scan_interval = BTM_BLE_SCAN_INT_MAX; - max_scan_window = BTM_BLE_SCAN_WIN_MAX; - } - - tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var; - if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, - max_scan_interval) && - BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, - max_scan_window) && - (scan_mode == BTM_BLE_SCAN_MODE_ACTI || - scan_mode == BTM_BLE_SCAN_MODE_PASS)) { - p_cb->scan_type = scan_mode; - p_cb->scan_interval = scan_interval; - p_cb->scan_window = scan_window; - - cb.Run(BTM_SUCCESS); - } else { - cb.Run(BTM_ILLEGAL_VALUE); - LOG_WARN("Illegal params: scan_interval = %d scan_window = %d", - scan_interval, scan_window); - } -} - /******************************************************************************* * * Function BTM__BLEReadDiscoverability @@ -1744,7 +1701,7 @@ void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window, * ******************************************************************************/ uint16_t BTM_BleReadDiscoverability() { - BTM_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return (btm_cb.ble_ctr_cb.inq_var.discoverable_mode); } @@ -1760,7 +1717,7 @@ uint16_t BTM_BleReadDiscoverability() { * ******************************************************************************/ uint16_t BTM_BleReadConnectability() { - BTM_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return (btm_cb.ble_ctr_cb.inq_var.connectable_mode); } @@ -1894,8 +1851,8 @@ tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode) { own_addr_type = p_addr_cb->own_addr_type; uint16_t adv_int_min, adv_int_max; - BTM_TRACE_EVENT("%s mode=0x%0x combined_mode=0x%x", __func__, mode, - combined_mode); + LOG_VERBOSE("%s mode=0x%0x combined_mode=0x%x", __func__, mode, + combined_mode); /*** Check mode parameter ***/ if (mode > BTM_BLE_MAX_DISCOVERABLE) return (BTM_ILLEGAL_VALUE); @@ -1914,8 +1871,7 @@ tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode) { alarm_cancel(p_cb->fast_adv_timer); /* update adv params if start advertising */ - BTM_TRACE_EVENT("evt_type=0x%x p-cb->evt_type=0x%x ", evt_type, - p_cb->evt_type); + LOG_VERBOSE("evt_type=0x%x p-cb->evt_type=0x%x ", evt_type, p_cb->evt_type); if (new_mode == BTM_BLE_ADV_ENABLE) { btm_ble_set_adv_flag(btm_cb.btm_inq_vars.connectable_mode, combined_mode); @@ -1949,8 +1905,8 @@ tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode) { /* set up stop advertising timer */ if (status == BTM_SUCCESS && mode == BTM_BLE_LIMITED_DISCOVERABLE) { - BTM_TRACE_EVENT("start timer for limited disc mode duration=%d ms", - BTM_BLE_GAP_LIM_TIMEOUT_MS); + LOG_VERBOSE("start timer for limited disc mode duration=%d ms", + BTM_BLE_GAP_LIM_TIMEOUT_MS); /* start Tgap(lim_timeout) */ alarm_set_on_mloop(p_cb->inquiry_timer, BTM_BLE_GAP_LIM_TIMEOUT_MS, btm_ble_inquiry_timer_gap_limited_discovery_timeout, @@ -1982,8 +1938,8 @@ tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode) { own_addr_type = p_addr_cb->own_addr_type; uint16_t adv_int_min, adv_int_max; - BTM_TRACE_EVENT("%s mode=0x%0x combined_mode=0x%x", __func__, mode, - combined_mode); + LOG_VERBOSE("%s mode=0x%0x combined_mode=0x%x", __func__, mode, + combined_mode); /*** Check mode parameter ***/ if (mode > BTM_BLE_MAX_CONNECTABLE) return (BTM_ILLEGAL_VALUE); @@ -2065,9 +2021,9 @@ static void btm_ble_scan_filt_param_cfg_evt(uint8_t avbl_space, tBTM_BLE_SCAN_COND_OP action_type, tBTM_STATUS btm_status) { if (btm_status != btm_status_value(BTM_SUCCESS)) { - BTM_TRACE_ERROR("%s, %d", __func__, btm_status); + LOG_ERROR("%s, %d", __func__, btm_status); } else { - BTM_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); } } @@ -2089,13 +2045,13 @@ tBTM_STATUS btm_ble_start_inquiry(uint8_t duration) { tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb; tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - BTM_TRACE_DEBUG("btm_ble_start_inquiry: inq_active = 0x%02x", - btm_cb.btm_inq_vars.inq_active); + LOG_VERBOSE("btm_ble_start_inquiry: inq_active = 0x%02x", + btm_cb.btm_inq_vars.inq_active); /* if selective connection is active, or inquiry is already active, reject it */ if (p_ble_cb->is_ble_inquiry_active()) { - BTM_TRACE_ERROR("LE Inquiry is active, can not start inquiry"); + LOG_ERROR("LE Inquiry is active, can not start inquiry"); return (BTM_BUSY); } @@ -2129,8 +2085,7 @@ tBTM_STATUS btm_ble_start_inquiry(uint8_t duration) { btm_ble_start_scan(); } else if ((p_ble_cb->inq_var.scan_interval != scan_interval) || (p_ble_cb->inq_var.scan_window != scan_window)) { - BTM_TRACE_DEBUG("%s, restart LE scan with low latency scan params", - __func__); + LOG_VERBOSE("%s, restart LE scan with low latency scan params", __func__); btm_send_hci_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE); btm_send_hci_set_scan_params( BTM_BLE_SCAN_MODE_ACTI, scan_interval, scan_window, @@ -2141,8 +2096,7 @@ tBTM_STATUS btm_ble_start_inquiry(uint8_t duration) { p_inq->inq_active |= BTM_BLE_GENERAL_INQUIRY; p_ble_cb->set_ble_inquiry_active(); - BTM_TRACE_DEBUG("btm_ble_start_inquiry inq_active = 0x%02x", - p_inq->inq_active); + LOG_VERBOSE("btm_ble_start_inquiry inq_active = 0x%02x", p_inq->inq_active); if (duration != 0) { /* start inquiry timer */ @@ -2208,7 +2162,7 @@ tBTM_STATUS btm_ble_read_remote_name(const RawAddress& remote_bda, tINQ_DB_ENT* p_i = btm_inq_db_find(remote_bda); if (p_i && !ble_evt_type_is_connectable(p_i->inq_info.results.ble_evt_type)) { - BTM_TRACE_DEBUG("name request to non-connectable device failed."); + LOG_VERBOSE("name request to non-connectable device failed."); return BTM_ERR_PROCESSING; } @@ -2268,10 +2222,10 @@ static void btm_ble_update_adv_flag(uint8_t flag) { tBTM_BLE_LOCAL_ADV_DATA* p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data; uint8_t* p; - BTM_TRACE_DEBUG("btm_ble_update_adv_flag new=0x%x", flag); + LOG_VERBOSE("btm_ble_update_adv_flag new=0x%x", flag); if (p_adv_data->p_flags != NULL) { - BTM_TRACE_DEBUG("btm_ble_update_adv_flag old=0x%x", *p_adv_data->p_flags); + LOG_VERBOSE("btm_ble_update_adv_flag old=0x%x", *p_adv_data->p_flags); *p_adv_data->p_flags = flag; } else /* no FLAGS in ADV data*/ { @@ -2602,7 +2556,7 @@ void btm_ble_process_adv_addr(RawAddress& bda, tBLE_ADDR_TYPE* addr_type) { if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) { tBTM_SEC_DEV_REC* match_rec = btm_ble_resolve_random_addr(bda); if (match_rec) { - match_rec->ble.active_addr_type = tBTM_SEC_BLE::BTM_BLE_ADDR_RRA; + match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA; match_rec->ble.cur_rand_addr = bda; if (btm_ble_init_pseudo_addr(match_rec, bda)) { @@ -2677,8 +2631,7 @@ void btm_ble_process_ext_adv_pkt(uint8_t data_len, const uint8_t* data) { } if (rssi >= 21 && rssi <= 126) { - BTM_TRACE_ERROR("%s: bad rssi value in advertising report: %d", __func__, - rssi); + LOG_ERROR("%s: bad rssi value in advertising report: %d", __func__, rssi); } // Store this to pass up the callback chain to GattService#onScanResult for @@ -2750,8 +2703,7 @@ void btm_ble_process_adv_pkt(uint8_t data_len, const uint8_t* data) { STREAM_TO_INT8(rssi, p); if (rssi >= 21 && rssi <= 126) { - BTM_TRACE_ERROR("%s: bad rssi value in advertising report: ", __func__, - pkt_data_len, rssi); + LOG_ERROR("%s: bad rssi value in advertising report: %d", __func__, rssi); } // Pass up the address to GattService#onScanResult to use in @@ -2779,7 +2731,7 @@ void btm_ble_process_adv_pkt(uint8_t data_len, const uint8_t* data) { (1 << BLE_EVT_SCANNABLE_BIT) | (1 << BLE_EVT_SCAN_RESPONSE_BIT); } else { - BTM_TRACE_ERROR( + LOG_ERROR( "Malformed LE Advertising Report Event - unsupported " "legacy_event_type 0x%02x", legacy_evt_type); @@ -2836,7 +2788,7 @@ void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type, if (!data_complete) { // If we didn't receive whole adv data yet, don't report the device. - DVLOG(1) << "Data not complete yet, waiting for more " << bda; + VLOG(1) << "Data not complete yet, waiting for more " << bda; return; } @@ -2844,13 +2796,13 @@ void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type, btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI; if (is_active_scan && is_scannable && !is_scan_resp) { // If we didn't receive scan response yet, don't report the device. - DVLOG(1) << " Waiting for scan response " << bda; + VLOG(1) << " Waiting for scan response " << bda; return; } if (!AdvertiseDataParser::IsValid(adv_data)) { - DVLOG(1) << __func__ << "Dropping bad advertisement packet: " - << base::HexEncode(adv_data.data(), adv_data.size()); + VLOG(1) << __func__ << "Dropping bad advertisement packet: " + << base::HexEncode(adv_data.data(), adv_data.size()); cache.Clear(addr_type, bda); return; } @@ -2883,7 +2835,7 @@ void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type, /* If existing entry, use that, else get a new one (possibly reusing the * oldest) */ if (p_i == NULL) { - p_i = btm_inq_db_new(bda); + p_i = btm_inq_db_new(bda, true); if (p_i != NULL) { p_inq->inq_cmpl_info.num_resp++; p_i->time_of_resp = bluetooth::common::time_get_os_boottime_ms(); @@ -2989,7 +2941,7 @@ void btm_ble_process_adv_pkt_cont_for_inquiry( /* If existing entry, use that, else get a new one (possibly reusing the * oldest) */ if (p_i == NULL) { - p_i = btm_inq_db_new(bda); + p_i = btm_inq_db_new(bda, true); if (p_i != NULL) { p_inq->inq_cmpl_info.num_resp++; p_i->time_of_resp = bluetooth::common::time_get_os_boottime_ms(); @@ -3058,7 +3010,7 @@ void btm_ble_process_phy_update_pkt(uint8_t len, uint8_t* data) { STREAM_TO_UINT8(tx_phy, p); STREAM_TO_UINT8(rx_phy, p); - gatt_notify_phy_updated(static_cast(status), handle, tx_phy, + gatt_notify_phy_updated(static_cast(status), handle, tx_phy, rx_phy); } @@ -3153,14 +3105,14 @@ void btm_ble_stop_inquiry(void) { } else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) || (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) { - BTM_TRACE_DEBUG("%s: setting default params for ongoing observe", __func__); + LOG_VERBOSE("%s: setting default params for ongoing observe", __func__); btm_ble_stop_scan(); btm_ble_start_scan(); } /* If we have a callback registered for inquiry complete, call it */ - BTM_TRACE_DEBUG("BTM Inq Compl Callback: status 0x%02x, num results %d", - p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp); + LOG_VERBOSE("BTM Inq Compl Callback: status 0x%02x, num results %d", + p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp); btm_process_inq_complete( HCI_SUCCESS, (uint8_t)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK)); @@ -3227,7 +3179,7 @@ static bool btm_ble_adv_states_operation(BTM_TOPOLOGY_FUNC_PTR* p_handler, break; default: - BTM_TRACE_ERROR("unknown adv event : %d", adv_evt); + LOG_ERROR("unknown adv event : %d", adv_evt); break; } @@ -3252,6 +3204,8 @@ static tBTM_STATUS btm_ble_start_adv(void) { btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_ENABLE); p_cb->adv_mode = BTM_BLE_ADV_ENABLE; btm_ble_adv_states_operation(btm_ble_set_topology_mask, p_cb->evt_type); + power_telemetry::GetInstance().LogBleAdvStarted(); + return BTM_SUCCESS; } @@ -3272,9 +3226,9 @@ static tBTM_STATUS btm_ble_stop_adv(void) { p_cb->fast_adv_on = false; p_cb->adv_mode = BTM_BLE_ADV_DISABLE; - /* clear all adv states */ btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK); + power_telemetry::GetInstance().LogBleAdvStopped(); } return BTM_SUCCESS; } @@ -3531,8 +3485,8 @@ void btm_ble_update_mode_operation(uint8_t link_role, const RawAddress* bd_addr, if (btm_cb.ble_ctr_cb.is_connection_state_idle() && status != HCI_ERR_HOST_REJECT_RESOURCES && status != HCI_ERR_MAX_NUM_OF_CONNECTIONS) { - LOG_DEBUG("Resuming le background connections"); - btm_ble_resume_bg_conn(); + LOG_DEBUG("Resuming le background connections"); + btm_ble_resume_bg_conn(); } } @@ -3548,7 +3502,7 @@ void btm_ble_update_mode_operation(uint8_t link_role, const RawAddress* bd_addr, void btm_ble_init(void) { tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb; - BTM_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); alarm_free(p_cb->observer_timer); alarm_free(p_cb->inq_var.fast_adv_timer); @@ -3575,9 +3529,9 @@ void btm_ble_init(void) { alarm_new("btm_ble_addr.refresh_raddr_timer"); btm_ble_pa_sync_cb = {}; sync_timeout_alarm = alarm_new("btm.sync_start_task"); -#if (BLE_VND_INCLUDED == FALSE) - btm_ble_adv_filter_init(); -#endif + if (!ble_vnd_is_included()) { + btm_ble_adv_filter_init(); + } } // Clean up btm ble control block @@ -3607,7 +3561,7 @@ bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask) { if (request_state_mask == BTM_BLE_STATE_INVALID || request_state_mask > BTM_BLE_STATE_SCAN_ADV_BIT || (request_state_mask & (request_state_mask - 1)) != 0) { - BTM_TRACE_ERROR("illegal state requested: %d", request_state_mask); + LOG_ERROR("illegal state requested: %d", request_state_mask); return rt; } @@ -3622,7 +3576,7 @@ bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask) { controller_get_interface()->get_ble_supported_states(); if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, bit_num)) { - BTM_TRACE_ERROR("state requested not supported: %d", request_state); + LOG_ERROR("state requested not supported: %d", request_state); return rt; } diff --git a/system/stack/btm/btm_ble_int.h b/system/stack/btm/btm_ble_int.h index 788fad5ccd6023f018ce961be5c8d13be5a56452..0dafe2f75192022d367ce3a54baab921823eb4d8 100644 --- a/system/stack/btm/btm_ble_int.h +++ b/system/stack/btm/btm_ble_int.h @@ -26,18 +26,12 @@ #ifndef BTM_BLE_INT_H #define BTM_BLE_INT_H -#include "bt_target.h" -#include "btm_ble_api.h" -#include "btm_ble_int_types.h" -#include "btm_int_types.h" -#include "smp_api.h" +#include "stack/btm/btm_ble_int_types.h" +#include "stack/btm/security_device_record.h" #include "stack/include/hci_error_code.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" -void btm_ble_process_periodic_adv_sync_est_evt(uint8_t len, const uint8_t* p); -void btm_ble_process_periodic_adv_pkt(uint8_t len, const uint8_t* p); -void btm_ble_process_periodic_adv_sync_lost_evt(uint8_t len, uint8_t* p); void btm_send_hci_set_scan_params(uint8_t scan_type, uint16_t scan_int, uint16_t scan_win, tBLE_ADDR_TYPE addr_type_own, @@ -50,32 +44,6 @@ void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, bool addr_matched, bool can_read_discoverable_characteristics); -/* LE security function from btm_sec.cc */ -void btm_ble_link_sec_check(const RawAddress& bd_addr, - tBTM_LE_AUTH_REQ auth_req, - tBTM_BLE_SEC_REQ_ACT* p_sec_req_act); -void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk, - const Octet16& stk); -tBTM_STATUS btm_proc_smp_cback(tSMP_EVT event, const RawAddress& bd_addr, - const tSMP_EVT_DATA* p_data); -tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr, - tBTM_BLE_SEC_ACT sec_act, uint8_t link_role); -tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk, - Octet16* p_stk); -void btm_ble_link_encrypted(const RawAddress& bd_addr, uint8_t encr_enable); - -/* LE device management functions */ -void btm_ble_reset_id(void); - -bool btm_get_local_div(const RawAddress& bd_addr, uint16_t* p_div); -bool btm_ble_get_enc_key_type(const RawAddress& bd_addr, uint8_t* p_key_types); - -void btm_sec_save_le_key(const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type, - tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application); -void btm_ble_update_sec_key_size(const RawAddress& bd_addr, - uint8_t enc_key_size); -uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr); - /* acceptlist function */ void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy); @@ -90,26 +58,7 @@ void btm_gen_resolvable_private_addr( tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(const RawAddress& random_bda); void btm_gen_resolve_paddr_low(const RawAddress& address); -uint64_t btm_get_next_private_addrress_interval_ms(); - -/* privacy function */ -/* BLE address mapping with CS feature */ -bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo, - tBLE_ADDR_TYPE* p_identity_addr_type); -void btm_ble_refresh_peer_resolvable_private_addr( - const RawAddress& pseudo_bda, const RawAddress& rra, - tBTM_SEC_BLE::tADDRESS_TYPE type); -bool btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec); -bool btm_ble_addr_resolvable(const RawAddress& rpa, - tBTM_SEC_DEV_REC* p_dev_rec); - -void btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC& p_dev_rec); -void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec); -void btm_ble_resolving_list_init(uint8_t max_irk_list_sz); - -void btm_ble_adv_init(void); -void btm_ble_multi_adv_cleanup(void); void btm_ble_batchscan_init(void); void btm_ble_adv_filter_init(void); bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request); @@ -119,12 +68,4 @@ bool btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state); void btm_ble_scanner_init(void); void btm_ble_scanner_cleanup(void); -#if (BTM_BLE_CONFORMANCE_TESTING == TRUE) -void btm_ble_set_no_disc_if_pair_fail(bool disble_disc); -void btm_ble_set_test_mac_value(bool enable, uint8_t* p_test_mac_val); -void btm_ble_set_test_local_sign_cntr_value(bool enable, - uint32_t test_local_sign_cntr); -void btm_ble_set_keep_rfu_in_auth_req(bool keep_rfu); -#endif - #endif diff --git a/system/stack/btm/btm_ble_int_types.h b/system/stack/btm/btm_ble_int_types.h index f4b780b33c2a5e60afa80e89224c7a6dc9c58aa3..443fc799529c53213aa45d473116cfe4d6d7eb0d 100644 --- a/system/stack/btm/btm_ble_int_types.h +++ b/system/stack/btm/btm_ble_int_types.h @@ -19,6 +19,7 @@ #ifndef BTM_BLE_INT_TYPES_H #define BTM_BLE_INT_TYPES_H +#include "macros.h" #include "osi/include/alarm.h" #include "stack/btm/neighbor_inquiry.h" #include "stack/include/btm_ble_api_types.h" @@ -45,10 +46,10 @@ #define BTM_BLE_GAP_ADV_INT 512 /* Tgap(lim_timeout) = 180s max */ #define BTM_BLE_GAP_LIM_TIMEOUT_MS (180 * 1000) -/* Interval(scan_int) = 5s= 8000 * 0.625 ms */ -#define BTM_BLE_LOW_LATENCY_SCAN_INT 8000 -/* scan_window = 5s= 8000 * 0.625 ms */ -#define BTM_BLE_LOW_LATENCY_SCAN_WIN 8000 +/* Interval(scan_int) = 100ms= 160 * 0.625 ms */ +#define BTM_BLE_LOW_LATENCY_SCAN_INT 160 +/* scan_window = 100ms= 160 * 0.625 ms */ +#define BTM_BLE_LOW_LATENCY_SCAN_WIN 160 /* TGAP(adv_fast_interval1) = 30(used) ~ 60 ms = 48 *0.625 */ #define BTM_BLE_GAP_ADV_FAST_INT_1 48 @@ -63,33 +64,6 @@ #define BTM_BLE_GAP_FAST_ADV_TIMEOUT_MS (30 * 1000) -typedef enum : uint8_t { - BTM_BLE_SEC_REQ_ACT_NONE = 0, - /* encrypt the link using current key or key refresh */ - BTM_BLE_SEC_REQ_ACT_ENCRYPT = 1, - BTM_BLE_SEC_REQ_ACT_PAIR = 2, - /* discard the sec request while encryption is started but not completed */ - BTM_BLE_SEC_REQ_ACT_DISCARD = 3, -} tBTM_BLE_SEC_REQ_ACT; - -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - -inline std::string btm_ble_sec_req_act_text( - const tBTM_BLE_SEC_REQ_ACT& action) { - switch (action) { - CASE_RETURN_TEXT(BTM_BLE_SEC_REQ_ACT_NONE); - CASE_RETURN_TEXT(BTM_BLE_SEC_REQ_ACT_ENCRYPT); - CASE_RETURN_TEXT(BTM_BLE_SEC_REQ_ACT_PAIR); - CASE_RETURN_TEXT(BTM_BLE_SEC_REQ_ACT_DISCARD); - } -} - -#undef CASE_RETURN_TEXT - #define BTM_VSC_CHIP_CAPABILITY_L_VERSION 55 #define BTM_VSC_CHIP_CAPABILITY_M_VERSION 95 #define BTM_VSC_CHIP_CAPABILITY_S_VERSION 98 diff --git a/system/stack/btm/btm_ble_multi_adv.cc b/system/stack/btm/btm_ble_multi_adv.cc deleted file mode 100644 index 09354421febe902b0df047740773402cc0796d03..0000000000000000000000000000000000000000 --- a/system/stack/btm/btm_ble_multi_adv.cc +++ /dev/null @@ -1,1165 +0,0 @@ -/****************************************************************************** - * - * Copyright 2017 The Android Open Source Project - * Copyright 2014 Broadcom Corporation - * - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bind_helpers.h" -#include "ble_advertiser.h" -#include "ble_advertiser_hci_interface.h" -#include "bt_target.h" -#include "btm_int_types.h" -#include "device/include/controller.h" -#include "osi/include/alarm.h" -#include "stack/btm/btm_ble_int.h" -#include "types/raw_address.h" - -using base::Bind; -using base::TimeDelta; -using base::TimeTicks; -using RegisterCb = - base::Callback; -using IdTxPowerStatusCb = base::Callback; -using SetEnableData = BleAdvertiserHciInterface::SetEnableData; -void btm_gen_resolvable_private_addr( - base::Callback cb); - -constexpr int ADV_DATA_LEN_MAX = 251; - -namespace { - -bool is_connectable(uint16_t advertising_event_properties) { - return advertising_event_properties & 0x01; -} - -struct AdvertisingInstance { - uint8_t inst_id; - bool in_use; - uint8_t advertising_event_properties; - alarm_t* adv_raddr_timer; - int8_t tx_power; - uint16_t duration; // 1 unit is 10ms - uint8_t maxExtAdvEvents; - alarm_t* timeout_timer; - uint8_t own_address_type; - RawAddress own_address; - MultiAdvCb timeout_cb; - bool address_update_required; - bool periodic_enabled; - bool periodic_include_adi; - uint32_t advertising_interval; // 1 unit is 0.625 ms - - /* When true, advertising set is enabled, or last scheduled call to "LE Set - * Extended Advertising Set Enable" is to enable this advertising set. Any - * command scheduled when in this state will execute when the set is enabled, - * unless enabling fails. - * - * When false, advertising set is disabled, or last scheduled call to "LE Set - * Extended Advertising Set Enable" is to disable this advertising set. Any - * command scheduled when in this state will execute when the set is disabled. - */ - bool enable_status; - TimeTicks enable_time; - - bool IsEnabled() { return enable_status; } - - bool IsConnectable() { return is_connectable(advertising_event_properties); } - - AdvertisingInstance(int inst_id) - : inst_id(inst_id), - in_use(false), - advertising_event_properties(0), - tx_power(0), - duration(0), - timeout_timer(nullptr), - own_address_type(0), - own_address(RawAddress::kEmpty), - address_update_required(false), - periodic_enabled(false), - periodic_include_adi(false), - enable_status(false) { - adv_raddr_timer = alarm_new_periodic("btm_ble.adv_raddr_timer"); - } - - ~AdvertisingInstance() { - alarm_free(adv_raddr_timer); - adv_raddr_timer = nullptr; - if (timeout_timer) { - alarm_free(timeout_timer); - timeout_timer = nullptr; - } - } -}; - -void btm_ble_adv_raddr_timer_timeout(void* data); - -struct closure_data { - base::Closure user_task; - base::Location posted_from; -}; - -static void alarm_closure_cb(void* p) { - closure_data* data = (closure_data*)p; - VLOG(1) << "executing timer scheduled at %s" << data->posted_from.ToString(); - data->user_task.Run(); - delete data; -} - -// Periodic alarms are not supported, because we clean up data in callback -static void alarm_set_closure(const base::Location& posted_from, alarm_t* alarm, - uint64_t interval_ms, base::Closure user_task) { - closure_data* data = new closure_data; - data->posted_from = posted_from; - data->user_task = std::move(user_task); - VLOG(1) << "scheduling timer %s" << data->posted_from.ToString(); - alarm_set_on_mloop(alarm, interval_ms, alarm_closure_cb, data); -} - -class BleAdvertisingManagerImpl; - -/* a temporary type for holding all the data needed in callbacks below*/ -struct CreatorParams { - uint8_t inst_id; - base::WeakPtr self; - IdTxPowerStatusCb cb; - tBTM_BLE_ADV_PARAMS params; - std::vector advertise_data; - std::vector scan_response_data; - tBLE_PERIODIC_ADV_PARAMS periodic_params; - std::vector periodic_data; - uint16_t duration; - uint8_t maxExtAdvEvents; - RegisterCb timeout_cb; -}; - -using c_type = std::unique_ptr; - -BleAdvertisingManager* instance; -base::WeakPtr instance_weakptr; - -class BleAdvertisingManagerImpl - : public BleAdvertisingManager, - public BleAdvertiserHciInterface::AdvertisingEventObserver { - public: - BleAdvertisingManagerImpl(BleAdvertiserHciInterface* interface) - : hci_interface(interface), weak_factory_(this) { - hci_interface->ReadInstanceCount( - base::Bind(&BleAdvertisingManagerImpl::ReadInstanceCountCb, - weak_factory_.GetWeakPtr())); - } - - ~BleAdvertisingManagerImpl() override { adv_inst.clear(); } - - void GetOwnAddress(uint8_t inst_id, GetAddressCallback cb) override { - cb.Run(adv_inst[inst_id].own_address_type, adv_inst[inst_id].own_address); - } - - void ReadInstanceCountCb(uint8_t instance_count) { - this->inst_count = instance_count; - adv_inst.reserve(inst_count); - /* Initialize adv instance indices and IDs. */ - for (uint8_t i = 0; i < inst_count; i++) { - adv_inst.emplace_back(i); - } - } - - void GenerateRpa(base::Callback cb) { - btm_gen_resolvable_private_addr(std::move(cb)); - } - - void ConfigureRpa(AdvertisingInstance* p_inst, MultiAdvCb configuredCb) { - /* Connectable advertising set must be disabled when updating RPA */ - bool restart = p_inst->IsEnabled() && p_inst->IsConnectable(); - - // If there is any form of timeout on the set, schedule address update when - // the set stops, because there is no good way to compute new timeout value. - // Maximum duration value is around 10 minutes, so this is safe. - if (restart && (p_inst->duration || p_inst->maxExtAdvEvents)) { - p_inst->address_update_required = true; - configuredCb.Run(0x01); - return; - } - - GenerateRpa(Bind( - [](AdvertisingInstance* p_inst, MultiAdvCb configuredCb, - const RawAddress& bda) { - /* Connectable advertising set must be disabled when updating RPA */ - bool restart = p_inst->IsEnabled() && p_inst->IsConnectable(); - - if (!instance_weakptr.get()) return; - auto hci_interface = instance_weakptr.get()->GetHciInterface(); - - if (restart) { - p_inst->enable_status = false; - hci_interface->Enable(false, p_inst->inst_id, 0x00, 0x00, - base::DoNothing()); - } - - /* set it to controller */ - hci_interface->SetRandomAddress( - p_inst->inst_id, bda, - Bind( - [](AdvertisingInstance* p_inst, RawAddress bda, - MultiAdvCb configuredCb, uint8_t status) { - p_inst->own_address = bda; - configuredCb.Run(0x00); - }, - p_inst, bda, configuredCb)); - - if (restart) { - p_inst->enable_status = true; - hci_interface->Enable(true, p_inst->inst_id, 0x00, 0x00, - base::DoNothing()); - } - }, - p_inst, std::move(configuredCb))); - } - - void RegisterAdvertiser( - base::Callback cb) - override { - int own_address_type = - BTM_BleLocalPrivacyEnabled() ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC; - RegisterAdvertiserImpl(own_address_type, cb); - } - - void RegisterAdvertiserImpl( - int own_address_type, - base::Callback cb) { - AdvertisingInstance* p_inst = &adv_inst[0]; - for (uint8_t i = 0; i < inst_count; i++, p_inst++) { - if (p_inst->in_use) continue; - - p_inst->in_use = true; - p_inst->own_address_type = own_address_type; - - // set up periodic timer to update address. - if (own_address_type != BLE_ADDR_PUBLIC) { - GenerateRpa(Bind( - [](AdvertisingInstance* p_inst, - base::Callback - cb, - const RawAddress& bda) { - p_inst->own_address = bda; - - alarm_set_on_mloop(p_inst->adv_raddr_timer, - btm_get_next_private_addrress_interval_ms(), - btm_ble_adv_raddr_timer_timeout, p_inst); - cb.Run(p_inst->inst_id, BTM_BLE_MULTI_ADV_SUCCESS); - }, - p_inst, cb)); - } else { - p_inst->own_address = *controller_get_interface()->get_address(); - - cb.Run(p_inst->inst_id, BTM_BLE_MULTI_ADV_SUCCESS); - } - return; - } - - LOG(INFO) << "no free advertiser instance"; - cb.Run(0xFF, ADVERTISE_FAILED_TOO_MANY_ADVERTISERS); - } - - void StartAdvertising(uint8_t advertiser_id, MultiAdvCb cb, - tBTM_BLE_ADV_PARAMS* params, - std::vector advertise_data, - std::vector scan_response_data, int duration, - MultiAdvCb timeout_cb) override { - /* a temporary type for holding all the data needed in callbacks below*/ - struct CreatorParams { - uint8_t inst_id; - base::WeakPtr self; - MultiAdvCb cb; - tBTM_BLE_ADV_PARAMS params; - std::vector advertise_data; - std::vector scan_response_data; - int duration; - MultiAdvCb timeout_cb; - }; - - std::unique_ptr c; - c.reset(new CreatorParams()); - - c->self = weak_factory_.GetWeakPtr(); - c->cb = std::move(cb); - c->params = *params; - c->advertise_data = std::move(advertise_data); - c->scan_response_data = std::move(scan_response_data); - c->duration = duration; - c->timeout_cb = std::move(timeout_cb); - c->inst_id = advertiser_id; - - using c_type = std::unique_ptr; - - // this code is intentionally left formatted this way to highlight the - // asynchronous flow - // clang-format off - c->self->SetParameters(c->inst_id, &c->params, Bind( - [](c_type c, uint8_t status, int8_t tx_power) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status) { - LOG(ERROR) << "setting parameters failed, status: " << +status; - c->cb.Run(status); - return; - } - - c->self->adv_inst[c->inst_id].tx_power = tx_power; - - const RawAddress& rpa = c->self->adv_inst[c->inst_id].own_address; - c->self->GetHciInterface()->SetRandomAddress(c->inst_id, rpa, Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - LOG(ERROR) << "setting random address failed, status: " << +status; - c->cb.Run(status); - return; - } - - c->self->SetData(c->inst_id, false, std::move(c->advertise_data), Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - LOG(ERROR) << "setting advertise data failed, status: " << +status; - c->cb.Run(status); - return; - } - - c->self->SetData(c->inst_id, true, std::move(c->scan_response_data), Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - LOG(ERROR) << "setting scan response data failed, status: " << +status; - c->cb.Run(status); - return; - } - - c->self->Enable(c->inst_id, true, c->cb, c->duration, 0, std::move(c->timeout_cb)); - - }, base::Passed(&c))); - }, base::Passed(&c))); - }, base::Passed(&c))); - }, base::Passed(&c))); - // clang-format on - } - - void StartAdvertisingSet(IdTxPowerStatusCb cb, tBTM_BLE_ADV_PARAMS* params, - std::vector advertise_data, - std::vector scan_response_data, - tBLE_PERIODIC_ADV_PARAMS* periodic_params, - std::vector periodic_data, - uint16_t duration, uint8_t maxExtAdvEvents, - RegisterCb timeout_cb) override { - std::unique_ptr c; - c.reset(new CreatorParams()); - - c->self = weak_factory_.GetWeakPtr(); - c->cb = std::move(cb); - c->params = *params; - c->advertise_data = std::move(advertise_data); - c->scan_response_data = std::move(scan_response_data); - c->periodic_params = *periodic_params; - c->periodic_data = std::move(periodic_data); - c->duration = duration; - c->maxExtAdvEvents = maxExtAdvEvents; - c->timeout_cb = std::move(timeout_cb); - - int own_address_type = - BTM_BleLocalPrivacyEnabled() ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC; - if (params->own_address_type != BLE_ADDR_ANONYMOUS) { - own_address_type = params->own_address_type; - } - - // this code is intentionally left formatted this way to highlight the - // asynchronous flow - // clang-format off - c->self->RegisterAdvertiserImpl(own_address_type, Bind( - [](c_type c, uint8_t advertiser_id, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - LOG(ERROR) << " failed, status: " << +status; - c->cb.Run(0, 0, status); - return; - } - - c->inst_id = advertiser_id; - - c->self->SetParameters(c->inst_id, &c->params, Bind( - [](c_type c, uint8_t status, int8_t tx_power) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - c->self->Unregister(c->inst_id); - LOG(ERROR) << "setting parameters failed, status: " << +status; - c->cb.Run(0, 0, status); - return; - } - - c->self->adv_inst[c->inst_id].tx_power = tx_power; - - if (c->self->adv_inst[c->inst_id].own_address_type == BLE_ADDR_PUBLIC) { - auto self = c->self; - self->StartAdvertisingSetAfterAddressPart(std::move(c)); - return; - } - - //own_address_type == BLE_ADDR_RANDOM - const RawAddress& rpa = c->self->adv_inst[c->inst_id].own_address; - c->self->GetHciInterface()->SetRandomAddress(c->inst_id, rpa, Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - c->self->Unregister(c->inst_id); - LOG(ERROR) << "setting random address failed, status: " << +status; - c->cb.Run(0, 0, status); - return; - } - - auto self = c->self; - self->StartAdvertisingSetAfterAddressPart(std::move(c)); - }, base::Passed(&c))); - }, base::Passed(&c))); - }, base::Passed(&c))); - // clang-format on - } - - void StartAdvertisingSetAfterAddressPart(c_type c) { - c->self->SetData( - c->inst_id, false, std::move(c->advertise_data), - Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - c->self->Unregister(c->inst_id); - LOG(ERROR) << "setting advertise data failed, status: " - << +status; - c->cb.Run(0, 0, status); - return; - } - - c->self->SetData( - c->inst_id, true, std::move(c->scan_response_data), - Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - c->self->Unregister(c->inst_id); - LOG(ERROR) - << "setting scan response data failed, status: " - << +status; - c->cb.Run(0, 0, status); - return; - } - - auto self = c->self; - if (c->periodic_params.enable) { - self->StartAdvertisingSetPeriodicPart(std::move(c)); - } else { - self->StartAdvertisingSetFinish(std::move(c)); - } - }, - base::Passed(&c))); - }, - base::Passed(&c))); - } - - void StartAdvertisingSetPeriodicPart(c_type c) { - // this code is intentionally left formatted this way to highlight the - // asynchronous flow - // clang-format off - c->self->SetPeriodicAdvertisingParameters(c->inst_id, &c->periodic_params, Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - c->self->Unregister(c->inst_id); - LOG(ERROR) << "setting periodic parameters failed, status: " << +status; - c->cb.Run(0, 0, status); - return; - } - - c->self->SetPeriodicAdvertisingData(c->inst_id, std::move(c->periodic_data), Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - c->self->Unregister(c->inst_id); - LOG(ERROR) << "setting periodic parameters failed, status: " << +status; - c->cb.Run(0, 0, status); - return; - } - - c->self->SetPeriodicAdvertisingEnable(c->inst_id, c->periodic_params.enable, - c->periodic_params.include_adi, Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - c->self->Unregister(c->inst_id); - LOG(ERROR) << "enabling periodic advertising failed, status: " << +status; - c->cb.Run(0, 0, status); - return; - } - - auto self = c->self; - self->StartAdvertisingSetFinish(std::move(c)); - - }, base::Passed(&c))); - }, base::Passed(&c))); - }, base::Passed(&c))); - // clang-format on - } - - void StartAdvertisingSetFinish(c_type c) { - uint8_t inst_id = c->inst_id; - uint16_t duration = c->duration; - uint8_t maxExtAdvEvents = c->maxExtAdvEvents; - RegisterCb timeout_cb = std::move(c->timeout_cb); - base::WeakPtr self = c->self; - MultiAdvCb enable_cb = Bind( - [](c_type c, uint8_t status) { - if (!c->self) { - LOG(INFO) << "Stack was shut down"; - return; - } - - if (status != 0) { - c->self->Unregister(c->inst_id); - LOG(ERROR) << "enabling advertiser failed, status: " << +status; - c->cb.Run(0, 0, status); - return; - } - int8_t tx_power = c->self->adv_inst[c->inst_id].tx_power; - c->cb.Run(c->inst_id, tx_power, status); - }, - base::Passed(&c)); - - self->Enable(inst_id, true, std::move(enable_cb), duration, maxExtAdvEvents, - Bind(std::move(timeout_cb), inst_id)); - } - - void EnableWithTimerCb(uint8_t inst_id, MultiAdvCb enable_cb, int duration, - MultiAdvCb timeout_cb, uint8_t status) { - VLOG(1) << __func__ << " inst_id: " << +inst_id; - AdvertisingInstance* p_inst = &adv_inst[inst_id]; - - // Run the regular enable callback - enable_cb.Run(status); - - p_inst->timeout_timer = alarm_new("btm_ble.adv_timeout"); - - base::Closure cb = Bind( - &BleAdvertisingManagerImpl::Enable, weak_factory_.GetWeakPtr(), inst_id, - 0 /* disable */, std::move(timeout_cb), 0, 0, base::DoNothing()); - - // schedule disable when the timeout passes - alarm_set_closure(FROM_HERE, p_inst->timeout_timer, duration * 10, - std::move(cb)); - } - - void Enable(uint8_t inst_id, bool enable, MultiAdvCb cb, uint16_t duration, - uint8_t maxExtAdvEvents, MultiAdvCb timeout_cb) override { - VLOG(1) << __func__ << " inst_id: " << +inst_id; - if (inst_id >= inst_count) { - LOG(ERROR) << "bad instance id " << +inst_id; - return; - } - - AdvertisingInstance* p_inst = &adv_inst[inst_id]; - VLOG(1) << __func__ << " enable: " << enable << ", duration: " << +duration; - if (!p_inst->in_use) { - LOG(ERROR) << "Invalid or no active instance"; - cb.Run(BTM_BLE_MULTI_ADV_FAILURE); - return; - } - - if (enable && (duration || maxExtAdvEvents)) { - p_inst->timeout_cb = std::move(timeout_cb); - } - - p_inst->duration = duration; - p_inst->maxExtAdvEvents = maxExtAdvEvents; - - if (enable && p_inst->address_update_required) { - p_inst->address_update_required = false; - ConfigureRpa(p_inst, base::Bind(&BleAdvertisingManagerImpl::EnableFinish, - weak_factory_.GetWeakPtr(), p_inst, - enable, std::move(cb))); - return; - } - - EnableFinish(p_inst, enable, std::move(cb), 0); - } - - void EnableFinish(AdvertisingInstance* p_inst, bool enable, MultiAdvCb cb, - uint8_t status) { - MultiAdvCb myCb; - if (enable && p_inst->duration) { - // TODO(jpawlowski): HCI implementation that can't do duration should - // emulate it, not EnableWithTimerCb. - myCb = Bind(&BleAdvertisingManagerImpl::EnableWithTimerCb, - weak_factory_.GetWeakPtr(), p_inst->inst_id, std::move(cb), - p_inst->duration, p_inst->timeout_cb); - } else { - myCb = std::move(cb); - - if (p_inst->timeout_timer) { - alarm_cancel(p_inst->timeout_timer); - alarm_free(p_inst->timeout_timer); - p_inst->timeout_timer = nullptr; - } - } - - if (enable) p_inst->enable_time = TimeTicks::Now(); - p_inst->enable_status = enable; - GetHciInterface()->Enable(enable, p_inst->inst_id, p_inst->duration, - p_inst->maxExtAdvEvents, std::move(myCb)); - } - - void SetParameters(uint8_t inst_id, tBTM_BLE_ADV_PARAMS* p_params, - ParametersCb cb) override { - VLOG(1) << __func__ << " inst_id: " << +inst_id; - if (inst_id >= inst_count) { - LOG(ERROR) << "bad instance id " << +inst_id; - return; - } - - AdvertisingInstance* p_inst = &adv_inst[inst_id]; - if (!p_inst->in_use) { - LOG(ERROR) << "adv instance not in use" << +inst_id; - cb.Run(BTM_BLE_MULTI_ADV_FAILURE, 0); - return; - } - - // TODO: disable only if was enabled, currently no use scenario needs - // that, - // we always set parameters before enabling - // GetHciInterface()->Enable(false, inst_id, base::DoNothing()); - p_inst->advertising_event_properties = - p_params->advertising_event_properties; - p_inst->tx_power = p_params->tx_power; - p_inst->advertising_interval = p_params->adv_int_min; - const RawAddress& peer_address = RawAddress::kEmpty; - - // sid must be in range 0x00 to 0x0F. Since no controller supports more than - // 16 advertisers, it's safe to make sid equal to inst_id. - uint8_t sid = p_inst->inst_id % 0x0F; - - GetHciInterface()->SetParameters( - p_inst->inst_id, p_params->advertising_event_properties, - p_params->adv_int_min, p_params->adv_int_max, p_params->channel_map, - p_inst->own_address_type, p_inst->own_address, 0x00, peer_address, - p_params->adv_filter_policy, p_inst->tx_power, - p_params->primary_advertising_phy, 0x00, - p_params->secondary_advertising_phy, sid, - p_params->scan_request_notification_enable, cb); - - // TODO: re-enable only if it was enabled, properly call - // SetParamsCallback - // currently no use scenario needs that - // GetHciInterface()->Enable(true, inst_id, BTM_BleUpdateAdvInstParamCb); - } - - void SetData(uint8_t inst_id, bool is_scan_rsp, std::vector data, - MultiAdvCb cb) override { - VLOG(1) << __func__ << " inst_id: " << +inst_id; - if (inst_id >= inst_count) { - LOG(ERROR) << "bad instance id " << +inst_id; - return; - } - - AdvertisingInstance* p_inst = &adv_inst[inst_id]; - VLOG(1) << "is_scan_rsp = " << is_scan_rsp; - - if (!is_scan_rsp && is_connectable(p_inst->advertising_event_properties)) { - uint8_t flags_val = BTM_GENERAL_DISCOVERABLE; - - if (p_inst->duration) flags_val = BTM_LIMITED_DISCOVERABLE; - - std::vector flags; - flags.push_back(2); // length - flags.push_back(HCI_EIR_FLAGS_TYPE); - flags.push_back(flags_val); - - data.insert(data.begin(), flags.begin(), flags.end()); - } - - // Find and fill TX Power with the correct value. - // The TX Power section is a 3 byte section. - for (size_t i = 0; (i + 2) < data.size();) { - if (data[i + 1] == HCI_EIR_TX_POWER_LEVEL_TYPE) { - data[i + 2] = adv_inst[inst_id].tx_power; - } - i += data[i] + 1; - } - - VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size()); - DivideAndSendData( - inst_id, data, cb, - base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender, - weak_factory_.GetWeakPtr(), is_scan_rsp)); - } - - void SetDataAdvDataSender(uint8_t is_scan_rsp, uint8_t inst_id, - uint8_t operation, uint8_t length, uint8_t* data, - MultiAdvCb cb) { - if (is_scan_rsp) - GetHciInterface()->SetScanResponseData(inst_id, operation, 0x01, length, - data, cb); - else - GetHciInterface()->SetAdvertisingData(inst_id, operation, 0x01, length, - data, cb); - } - - using DataSender = base::Callback; - - void DivideAndSendData(int inst_id, std::vector data, - MultiAdvCb done_cb, DataSender sender) { - DivideAndSendDataRecursively(true, inst_id, std::move(data), 0, - std::move(done_cb), std::move(sender), 0); - } - - static void DivideAndSendDataRecursively(bool isFirst, int inst_id, - std::vector data, - int offset, MultiAdvCb done_cb, - DataSender sender, uint8_t status) { - constexpr uint8_t INTERMEDIATE = - 0x00; // Intermediate fragment of fragmented data - constexpr uint8_t FIRST = 0x01; // First fragment of fragmented data - constexpr uint8_t LAST = 0x02; // Last fragment of fragmented data - constexpr uint8_t COMPLETE = 0x03; // Complete extended advertising data - - int dataSize = (int)data.size(); - if (status != 0 || (!isFirst && offset == dataSize)) { - /* if we got error writing data, or reached the end of data */ - done_cb.Run(status); - return; - } - - bool moreThanOnePacket = dataSize - offset > ADV_DATA_LEN_MAX; - uint8_t operation = isFirst ? moreThanOnePacket ? FIRST : COMPLETE - : moreThanOnePacket ? INTERMEDIATE : LAST; - int length = moreThanOnePacket ? ADV_DATA_LEN_MAX : dataSize - offset; - int newOffset = offset + length; - - auto dataData = data.data(); - sender.Run( - inst_id, operation, length, dataData + offset, - Bind(&BleAdvertisingManagerImpl::DivideAndSendDataRecursively, false, - inst_id, std::move(data), newOffset, std::move(done_cb), sender)); - } - - void SetPeriodicAdvertisingParameters(uint8_t inst_id, - tBLE_PERIODIC_ADV_PARAMS* params, - MultiAdvCb cb) override { - VLOG(1) << __func__ << " inst_id: " << +inst_id; - - GetHciInterface()->SetPeriodicAdvertisingParameters( - inst_id, params->min_interval, params->max_interval, - params->periodic_advertising_properties, cb); - } - - void SetPeriodicAdvertisingData(uint8_t inst_id, std::vector data, - MultiAdvCb cb) override { - VLOG(1) << __func__ << " inst_id: " << +inst_id; - - VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size()); - - DivideAndSendData( - inst_id, data, cb, - base::Bind(&BleAdvertiserHciInterface::SetPeriodicAdvertisingData, - base::Unretained(GetHciInterface()))); - } - - void SetPeriodicAdvertisingEnable(uint8_t inst_id, bool enable, - bool include_adi, MultiAdvCb cb) override { - VLOG(1) << __func__ << " inst_id: " << +inst_id << ", enable: " << +enable; - - AdvertisingInstance* p_inst = &adv_inst[inst_id]; - if (!p_inst->in_use) { - LOG(ERROR) << "Invalid or not active instance"; - cb.Run(BTM_BLE_MULTI_ADV_FAILURE); - return; - } - - MultiAdvCb enable_cb = Bind( - [](AdvertisingInstance* p_inst, bool enable, bool include_adi, - MultiAdvCb cb, uint8_t status) { - VLOG(1) << "periodc adv enable cb: inst_id: " << +p_inst->inst_id - << ", enable: " << enable << ", include_adi: " << include_adi - << ", status: " << std::hex << +status; - if (!status) { - p_inst->periodic_enabled = enable; - p_inst->periodic_include_adi = include_adi; - } - - cb.Run(status); - }, - p_inst, enable, include_adi, std::move(cb)); - - GetHciInterface()->SetPeriodicAdvertisingEnable( - enable, include_adi, inst_id, std::move(enable_cb)); - } - - void Unregister(uint8_t inst_id) override { - AdvertisingInstance* p_inst = &adv_inst[inst_id]; - - VLOG(1) << __func__ << " inst_id: " << +inst_id; - if (inst_id >= inst_count) { - LOG(ERROR) << "bad instance id " << +inst_id; - return; - } - - if (adv_inst[inst_id].IsEnabled()) { - p_inst->enable_status = false; - GetHciInterface()->Enable(false, inst_id, 0x00, 0x00, base::DoNothing()); - } - - if (p_inst->periodic_enabled) { - p_inst->periodic_enabled = false; - p_inst->periodic_include_adi = false; - GetHciInterface()->SetPeriodicAdvertisingEnable(false, false, inst_id, - base::DoNothing()); - } - - alarm_cancel(p_inst->adv_raddr_timer); - p_inst->in_use = false; - GetHciInterface()->RemoveAdvertisingSet(inst_id, base::DoNothing()); - p_inst->address_update_required = false; - } - - void RecomputeTimeout(AdvertisingInstance* inst, TimeTicks now) { - TimeDelta duration = now - inst->enable_time; - bool cb_fired = false; - if (inst->duration) { - int durationDone = (duration.InMilliseconds() / 10); - if (durationDone + 1 >= inst->duration) { - inst->enable_status = false; - inst->timeout_cb.Run(0 /* TODO: STATUS HERE?*/); - cb_fired = true; - } else { - inst->duration = inst->duration - durationDone; - } - } - - if (inst->maxExtAdvEvents && !cb_fired) { - int eventsDone = - (duration.InMilliseconds() / (inst->advertising_interval * 5 / 8)); - - if (eventsDone + 1 >= inst->maxExtAdvEvents) { - inst->enable_status = false; - inst->timeout_cb.Run(0 /* TODO: STATUS HERE?*/); - } else { - inst->maxExtAdvEvents = inst->maxExtAdvEvents - eventsDone; - } - } - } - - void Suspend() override { - std::vector sets; - - for (AdvertisingInstance& inst : adv_inst) { - if (!inst.in_use || !inst.enable_status) continue; - - if (inst.duration || inst.maxExtAdvEvents) - RecomputeTimeout(&inst, TimeTicks::Now()); - - sets.emplace_back(SetEnableData{.handle = inst.inst_id}); - } - - if (!sets.empty()) - GetHciInterface()->Enable(false, sets, base::DoNothing()); - } - - void Resume() override { - std::vector sets; - - for (const AdvertisingInstance& inst : adv_inst) { - if (inst.in_use && inst.enable_status) { - sets.emplace_back(SetEnableData{ - .handle = inst.inst_id, - .duration = inst.duration, - .max_extended_advertising_events = inst.maxExtAdvEvents}); - } - } - - if (!sets.empty()) GetHciInterface()->Enable(true, sets, base::DoNothing()); - } - - void OnAdvertisingSetTerminated( - uint8_t status, uint8_t advertising_handle, uint16_t connection_handle, - uint8_t num_completed_extended_adv_events) override { - AdvertisingInstance* p_inst = &adv_inst[advertising_handle]; - VLOG(1) << __func__ << "status: " << loghex(status) - << ", advertising_handle: " << loghex(advertising_handle) - << ", connection_handle: " << loghex(connection_handle); - - if (status == HCI_ERR_LIMIT_REACHED || - status == HCI_ERR_ADVERTISING_TIMEOUT) { - // either duration elapsed, or maxExtAdvEvents reached - p_inst->enable_status = false; - - if (p_inst->timeout_cb.is_null()) { - LOG(INFO) << __func__ << "No timeout callback"; - return; - } - - p_inst->timeout_cb.Run(status); - return; - } - - VLOG(1) << "reneabling advertising"; - - if (p_inst->in_use) { - // TODO(jpawlowski): we don't really allow to do directed advertising - // right now. This should probably be removed, check with Andre. - if ((p_inst->advertising_event_properties & 0x0C) == 0) { - /* directed advertising bits not set */ - - RecomputeTimeout(p_inst, TimeTicks::Now()); - if (p_inst->enable_status) { - GetHciInterface()->Enable(true, advertising_handle, p_inst->duration, - p_inst->maxExtAdvEvents, base::DoNothing()); - } - - } else { - /* mark directed adv as disabled if adv has been stopped */ - p_inst->in_use = false; - } - } - } - - base::WeakPtr GetWeakPtr() { - return weak_factory_.GetWeakPtr(); - } - - void CancelAdvAlarms() { - AdvertisingInstance* p_inst = &adv_inst[0]; - for (uint8_t i = 0; i < inst_count; i++, p_inst++) { - if (p_inst->timeout_timer) { - alarm_cancel(p_inst->timeout_timer); - } - if (p_inst->adv_raddr_timer) { - alarm_cancel(p_inst->adv_raddr_timer); - } - } - } - - private: - BleAdvertiserHciInterface* GetHciInterface() { return hci_interface; } - - BleAdvertiserHciInterface* hci_interface = nullptr; - std::vector adv_inst; - uint8_t inst_count; - - // Member variables should appear before the WeakPtrFactory, to ensure - // that any WeakPtrs are invalidated before its members - // variable's destructors are executed, rendering them invalid. - base::WeakPtrFactory weak_factory_; -}; - -void btm_ble_adv_raddr_timer_timeout(void* data) { - BleAdvertisingManagerImpl* ptr = instance_weakptr.get(); - if (ptr) ptr->ConfigureRpa((AdvertisingInstance*)data, base::DoNothing()); -} -} // namespace - -void BleAdvertisingManager::Initialize(BleAdvertiserHciInterface* interface) { - instance = new BleAdvertisingManagerImpl(interface); - instance_weakptr = ((BleAdvertisingManagerImpl*)instance)->GetWeakPtr(); -} - -bool BleAdvertisingManager::IsInitialized() { return instance; } - -base::WeakPtr BleAdvertisingManager::Get() { - return instance_weakptr; -}; - -void BleAdvertisingManager::CleanUp() { - if (instance_weakptr.get()) instance_weakptr.get()->CancelAdvAlarms(); - - delete instance; - instance = nullptr; -}; - -/** - * This function initialize the advertising manager. - **/ -void btm_ble_adv_init() { - BleAdvertiserHciInterface::Initialize(); - BleAdvertisingManager::Initialize(BleAdvertiserHciInterface::Get()); - BleAdvertiserHciInterface::Get()->SetAdvertisingEventObserver( - (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get()); - - if (BleAdvertiserHciInterface::Get()->QuirkAdvertiserZeroHandle()) { - // If handle 0 can't be used, register advertiser for it, but never use it. - // TODO: avoid generating/rotating RPA for it - BleAdvertisingManager::Get().get()->RegisterAdvertiser(base::DoNothing()); - } -} - -/******************************************************************************* - * - * Function btm_ble_multi_adv_cleanup - * - * Description This function cleans up multi adv control block. - * - * Parameters - * Returns void - * - ******************************************************************************/ -void btm_ble_multi_adv_cleanup(void) { - BleAdvertisingManager::CleanUp(); - BleAdvertiserHciInterface::CleanUp(); -} - -// TODO(jpawlowski): Find a nicer way to test RecomputeTimeout without exposing -// AdvertisingInstance -bool timeout_triggered = false; -void test_timeout_cb(uint8_t status) { timeout_triggered = true; } - -// verify that if duration passed, or is about to pass, recomputation will shut -// down the advertiser completly -void testRecomputeTimeout1() { - auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get(); - - TimeTicks start = TimeTicks::Now(); -#if BASE_VER < 931007 - TimeTicks end = start + TimeDelta::FromMilliseconds(111); -#else - TimeTicks end = start + base::Milliseconds(111); -#endif - AdvertisingInstance test1(0); - test1.enable_status = true; - test1.enable_time = start; - test1.duration = 12 /*120ms*/; - test1.timeout_cb = Bind(&test_timeout_cb); - - manager->RecomputeTimeout(&test1, end); - - CHECK(timeout_triggered); - timeout_triggered = false; - CHECK(!test1.enable_status); -} - -// verify that duration and maxExtAdvEvents are properly adjusted when -// recomputing. -void testRecomputeTimeout2() { - auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get(); - - TimeTicks start = TimeTicks::Now(); -#if BASE_VER < 931007 - TimeTicks end = start + TimeDelta::FromMilliseconds(250); -#else - TimeTicks end = start + base::Milliseconds(250); -#endif - AdvertisingInstance test1(0); - test1.enable_status = true; - test1.enable_time = start; - test1.duration = 50 /*500ms*/; - test1.maxExtAdvEvents = 50; - test1.advertising_interval = 16 /* 10 ms */; - test1.timeout_cb = Bind(&test_timeout_cb); - - manager->RecomputeTimeout(&test1, end); - - CHECK(!timeout_triggered); - CHECK(test1.enable_status); - CHECK(test1.duration == 25); - CHECK(test1.maxExtAdvEvents == 25); -} - -// verify that if maxExtAdvEvents were sent, or are close to end, recomputation -// wil shut down the advertiser completly -void testRecomputeTimeout3() { - auto manager = (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get().get(); - - TimeTicks start = TimeTicks::Now(); -#if BASE_VER < 931007 - TimeTicks end = start + TimeDelta::FromMilliseconds(495); -#else - TimeTicks end = start + base::Milliseconds(495); -#endif - AdvertisingInstance test1(0); - test1.enable_status = true; - test1.enable_time = start; - test1.maxExtAdvEvents = 50; - test1.advertising_interval = 16 /* 10 ms */; - test1.timeout_cb = Bind(&test_timeout_cb); - - manager->RecomputeTimeout(&test1, end); - - CHECK(timeout_triggered); - timeout_triggered = false; - CHECK(!test1.enable_status); -} diff --git a/system/stack/btm/btm_ble_privacy.cc b/system/stack/btm/btm_ble_privacy.cc index 986c89eff871669a0fbd76bcd1c3fa144623aaa6..4c527c8e74839ea596577aeb096cc0cd8aa8dcdd 100644 --- a/system/stack/btm/btm_ble_privacy.cc +++ b/system/stack/btm/btm_ble_privacy.cc @@ -21,21 +21,28 @@ * This file contains functions for BLE controller based privacy. * ******************************************************************************/ -#include -#include +#define LOG_TAG "ble_priv" -#include "ble_advertiser.h" -#include "bt_target.h" +#include "stack/include/btm_ble_privacy.h" + +#include "btm_dev.h" +#include "btm_sec_cb.h" +#include "btm_sec_int_types.h" #include "device/include/controller.h" #include "main/shim/acl_api.h" -#include "stack/btm/btm_dev.h" +#include "os/log.h" +#include "osi/include/allocator.h" +#include "stack/btm/btm_int_types.h" #include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_api.h" #include "types/raw_address.h" -#include "vendor_hcidefs.h" extern tBTM_CB btm_cb; /* RPA offload VSC specifics */ +#define HCI_VENDOR_BLE_RPA_VSC (0x0155 | HCI_GRP_VENDOR_SPECIFIC) + #define BTM_BLE_META_IRK_ENABLE 0x01 #define BTM_BLE_META_ADD_IRK_ENTRY 0x02 #define BTM_BLE_META_REMOVE_IRK_ENTRY 0x03 @@ -174,7 +181,7 @@ static uint8_t btm_ble_find_irk_index(void) { i++; } - BTM_TRACE_ERROR("%s failed, list full", __func__); + LOG_ERROR("%s failed, list full", __func__); return i; } @@ -226,13 +233,13 @@ void btm_ble_clear_resolving_list_complete(uint8_t* p, uint16_t evt_len) { uint8_t status = 0; if (evt_len < 1) { - BTM_TRACE_ERROR("malformatted event packet: containing zero bytes"); + LOG_ERROR("malformatted event packet: containing zero bytes"); return; } STREAM_TO_UINT8(status, p); - BTM_TRACE_DEBUG("%s status=%d", __func__, status); + LOG_VERBOSE("%s status=%d", __func__, status); if (status == HCI_SUCCESS) { if (evt_len >= 3) { @@ -255,10 +262,10 @@ void btm_ble_clear_resolving_list_complete(uint8_t* p, uint16_t evt_len) { btm_cb.ble_ctr_cb.resolving_list_avail_size = controller_get_interface()->get_ble_resolving_list_max_size(); - BTM_TRACE_DEBUG("%s resolving_list_avail_size=%d", __func__, - btm_cb.ble_ctr_cb.resolving_list_avail_size); + LOG_VERBOSE("%s resolving_list_avail_size=%d", __func__, + btm_cb.ble_ctr_cb.resolving_list_avail_size); - list_foreach(btm_cb.sec_dev_rec, clear_resolving_list_bit, NULL); + list_foreach(btm_sec_cb.sec_dev_rec, clear_resolving_list_bit, NULL); } } @@ -276,17 +283,17 @@ void btm_ble_add_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) { uint8_t status; if (evt_len < 1) { - BTM_TRACE_ERROR("malformatted event packet: containing zero byte"); + LOG_ERROR("malformatted event packet: containing zero byte"); return; } STREAM_TO_UINT8(status, p); - BTM_TRACE_DEBUG("%s status = %d", __func__, status); + LOG_VERBOSE("%s status = %d", __func__, status); RawAddress pseudo_bda; if (!btm_ble_deq_resolving_pending(pseudo_bda)) { - BTM_TRACE_DEBUG("no pending resolving list operation"); + LOG_VERBOSE("no pending resolving list operation"); return; } @@ -303,7 +310,7 @@ void btm_ble_add_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) { HCI_ERR_MEMORY_FULL) /* BT_ERROR_CODE_MEMORY_CAPACITY_EXCEEDED */ { btm_cb.ble_ctr_cb.resolving_list_avail_size = 0; - BTM_TRACE_DEBUG("%s Resolving list Full ", __func__); + LOG_VERBOSE("%s Resolving list Full ", __func__); } } @@ -324,10 +331,10 @@ void btm_ble_remove_resolving_list_entry_complete(uint8_t* p, STREAM_TO_UINT8(status, p); - BTM_TRACE_DEBUG("%s status = %d", __func__, status); + LOG_VERBOSE("%s status = %d", __func__, status); if (!btm_ble_deq_resolving_pending(pseudo_bda)) { - BTM_TRACE_ERROR("%s no pending resolving list operation", __func__); + LOG_ERROR("%s no pending resolving list operation", __func__); return; } @@ -358,10 +365,10 @@ void btm_ble_read_resolving_list_entry_complete(const uint8_t* p, STREAM_TO_UINT8(status, p); - BTM_TRACE_DEBUG("%s status = %d", __func__, status); + LOG_VERBOSE("%s status = %d", __func__, status); if (!btm_ble_deq_resolving_pending(pseudo_bda)) { - BTM_TRACE_ERROR("no pending resolving list operation"); + LOG_ERROR("no pending resolving list operation"); return; } @@ -377,7 +384,7 @@ void btm_ble_read_resolving_list_entry_complete(const uint8_t* p, STREAM_TO_BDADDR(rra, p); } btm_ble_refresh_peer_resolvable_private_addr( - pseudo_bda, rra, tBTM_SEC_BLE::tADDRESS_TYPE::BTM_BLE_ADDR_PSEUDO); + pseudo_bda, rra, tBLE_RAND_ADDR_TYPE::BTM_BLE_ADDR_PSEUDO); } } /******************************************************************************* @@ -400,7 +407,7 @@ static void btm_ble_resolving_list_vsc_op_cmpl(tBTM_VSC_CMPL* p_params) { op_subcode = *(p + 1); - BTM_TRACE_DEBUG("%s op_subcode = %d", __func__, op_subcode); + LOG_VERBOSE("%s op_subcode = %d", __func__, op_subcode); if (op_subcode == BTM_BLE_META_CLEAR_IRK_LIST) { btm_ble_clear_resolving_list_complete(p, evt_len); @@ -427,7 +434,8 @@ static void btm_ble_resolving_list_vsc_op_cmpl(tBTM_VSC_CMPL* p_params) { * Returns status * ******************************************************************************/ -tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) { +static tBTM_STATUS btm_ble_remove_resolving_list_entry( + tBTM_SEC_DEV_REC* p_dev_rec) { /* if controller does not support RPA offloading or privacy 1.2, skip */ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) return BTM_WRONG_MODE; @@ -461,7 +469,7 @@ tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) { * Parameters None. * ******************************************************************************/ -void btm_ble_clear_resolving_list(void) { +static void btm_ble_clear_resolving_list(void) { if (controller_get_interface()->supports_ble_privacy()) { bluetooth::shim::ACL_ClearAddressResolution(); } else { @@ -487,6 +495,10 @@ void btm_ble_clear_resolving_list(void) { * ******************************************************************************/ bool btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) { + if (btm_cb.ble_ctr_cb.privacy_mode < BTM_PRIVACY_1_2) { + LOG_DEBUG("Privacy 1.2 is not enabled"); + return false; + } if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT)) { LOG_INFO("%s Unable to read resolving list entry as resolving bit not set", __func__); @@ -520,7 +532,7 @@ static void btm_ble_ble_unsupported_resolving_list_load_dev( uint8_t* p = param; UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY); - ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, OCTET16_LEN); + ARRAY_TO_STREAM(p, p_dev_rec->sec_rec.ble_keys.irk, OCTET16_LEN); UINT8_TO_STREAM(p, p_dev_rec->ble.identity_address_with_type.type); BDADDR_TO_STREAM(p, p_dev_rec->ble.identity_address_with_type.bda); @@ -533,12 +545,16 @@ static void btm_ble_ble_unsupported_resolving_list_load_dev( } static bool is_peer_identity_key_valid(const tBTM_SEC_DEV_REC& dev_rec) { - return dev_rec.ble.key_type & BTM_LE_KEY_PID; + return dev_rec.sec_rec.ble_keys.key_type & BTM_LE_KEY_PID; } -static Octet16 get_local_irk() { return btm_cb.devcb.id_keys.irk; } +static Octet16 get_local_irk() { return btm_sec_cb.devcb.id_keys.irk; } void btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC& dev_rec) { + if (btm_cb.ble_ctr_cb.privacy_mode < BTM_PRIVACY_1_2) { + LOG_DEBUG("Privacy 1.2 is not enabled"); + return; + } if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) { LOG_INFO("Controller does not support RPA offloading or privacy 1.2"); return; @@ -561,16 +577,22 @@ void btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC& dev_rec) { return; } - const Octet16& peer_irk = dev_rec.ble.keys.irk; + const Octet16& peer_irk = dev_rec.sec_rec.ble_keys.irk; const Octet16& local_irk = get_local_irk(); if (dev_rec.ble.identity_address_with_type.bda.IsEmpty()) { dev_rec.ble.identity_address_with_type = { - .bda = dev_rec.bd_addr, .type = dev_rec.ble.AddressType(), + .bda = dev_rec.bd_addr, }; } + if (!is_ble_addr_type_known(dev_rec.ble.identity_address_with_type.type)) { + LOG_ERROR("Adding unknown address type(%d) to Address Resolving list.", + dev_rec.ble.identity_address_with_type.type); + return; + } + bluetooth::shim::ACL_AddToAddressResolution( dev_rec.ble.identity_address_with_type, peer_irk, local_irk); @@ -592,7 +614,11 @@ void btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC& dev_rec) { * ******************************************************************************/ void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec) { - BTM_TRACE_EVENT("%s", __func__); + if (btm_cb.ble_ctr_cb.privacy_mode < BTM_PRIVACY_1_2) { + LOG_DEBUG("Privacy 1.2 is not enabled"); + return; + } + LOG_VERBOSE("%s", __func__); if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) && !btm_ble_brcm_find_resolving_pending_entry( @@ -600,7 +626,7 @@ void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec) { btm_ble_update_resolving_list(p_dev_rec->bd_addr, false); btm_ble_remove_resolving_list_entry(p_dev_rec); } else { - BTM_TRACE_DEBUG("Device not in resolving list"); + LOG_VERBOSE("Device not in resolving list"); } } @@ -632,7 +658,7 @@ void btm_ble_resolving_list_init(uint8_t max_irk_list_sz) { // NOTE: This memory is never freed btm_cb.ble_ctr_cb.irk_list_mask = (uint8_t*)osi_malloc(irk_mask_size); - BTM_TRACE_DEBUG("%s max_irk_list_sz = %d", __func__, max_irk_list_sz); + LOG_VERBOSE("%s max_irk_list_sz = %d", __func__, max_irk_list_sz); } controller_get_interface()->set_ble_resolving_list_max_size(max_irk_list_sz); diff --git a/system/stack/btm/btm_ble_scanner.cc b/system/stack/btm/btm_ble_scanner.cc index 9c667c83def6dfec9b1b740396a9e5d20cd574b5..c4523179b19f88bdf36303ab8c1ab69cea16acfd 100644 --- a/system/stack/btm/btm_ble_scanner.cc +++ b/system/stack/btm/btm_ble_scanner.cc @@ -25,9 +25,9 @@ #include "bt_target.h" #include "btm_int_types.h" #include "device/include/controller.h" +#include "internal_include/stack_config.h" #include "osi/include/alarm.h" #include "stack/btm/btm_ble_int.h" -#include "stack_config.h" std::mutex lock1; diff --git a/system/stack/btm/btm_ble_sec.cc b/system/stack/btm/btm_ble_sec.cc new file mode 100644 index 0000000000000000000000000000000000000000..6d4c06f696fbcd888e41f990395247ba553ff055 --- /dev/null +++ b/system/stack/btm/btm_ble_sec.cc @@ -0,0 +1,2013 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#define LOG_TAG "ble_sec" + +#include "stack/btm/btm_ble_sec.h" + +#include + +#include +#include +#include + +#include "btif/include/btif_storage.h" +#include "crypto_toolbox/crypto_toolbox.h" +#include "device/include/controller.h" +#include "device/include/interop.h" +#include "device/include/interop_config.h" +#include "os/log.h" +#include "osi/include/allocator.h" +#include "osi/include/properties.h" +#include "platform_ssl_mem.h" +#include "stack/btm/btm_ble_int.h" +#include "stack/btm/btm_dev.h" +#include "stack/btm/btm_int_types.h" +#include "stack/btm/btm_sec.h" +#include "stack/btm/btm_sec_cb.h" +#include "stack/btm/btm_sec_int_types.h" +#include "stack/btm/security_device_record.h" +#include "stack/eatt/eatt.h" +#include "stack/include/acl_api.h" +#include "stack/include/bt_name.h" +#include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_api.h" +#include "stack/include/btm_ble_addr.h" +#include "stack/include/btm_ble_privacy.h" +#include "stack/include/btm_ble_sec_api.h" +#include "stack/include/btm_log_history.h" +#include "stack/include/btm_status.h" +#include "stack/include/gatt_api.h" +#include "stack/include/l2cap_security_interface.h" +#include "stack/include/smp_api.h" +#include "stack/include/smp_api_types.h" +#include "types/raw_address.h" + +extern tBTM_CB btm_cb; + +bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, + const RawAddress& new_pseudo_addr); + +namespace { +constexpr char kBtmLogTag[] = "SEC"; +} + +static constexpr char kPropertyCtkdDisableCsrkDistribution[] = + "bluetooth.core.smp.le.ctkd.quirk_disable_csrk_distribution"; + +/******************************************************************************/ +/* External Function to be called by other modules */ +/******************************************************************************/ +void BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, + tBLE_ADDR_TYPE addr_type) { + LOG_DEBUG("dev_type=0x%x", dev_type); + + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + if (!p_dev_rec) { + p_dev_rec = btm_sec_allocate_dev_rec(); + + p_dev_rec->bd_addr = bd_addr; + p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR); + p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE); + + /* update conn params, use default value for background connection params */ + p_dev_rec->conn_params.min_conn_int = BTM_BLE_CONN_PARAM_UNDEF; + p_dev_rec->conn_params.max_conn_int = BTM_BLE_CONN_PARAM_UNDEF; + p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_PARAM_UNDEF; + p_dev_rec->conn_params.peripheral_latency = BTM_BLE_CONN_PARAM_UNDEF; + + LOG_DEBUG("Device added, handle=0x%x, p_dev_rec=%p, bd_addr=%s", + p_dev_rec->ble_hci_handle, p_dev_rec, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + } + + memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME)); + + p_dev_rec->device_type |= dev_type; + if (is_ble_addr_type_known(addr_type)) { + p_dev_rec->ble.SetAddressType(addr_type); + } else { + LOG_WARN( + "Please do not update device record from anonymous le advertisement"); + } + + /* sync up with the Inq Data base*/ + tBTM_INQ_INFO* p_info = BTM_InqDbRead(bd_addr); + if (p_info) { + p_info->results.ble_addr_type = p_dev_rec->ble.AddressType(); + p_dev_rec->device_type |= p_info->results.device_type; + LOG_DEBUG("InqDb device_type =0x%x addr_type=0x%x", p_dev_rec->device_type, + p_info->results.ble_addr_type); + p_info->results.device_type = p_dev_rec->device_type; + } +} + +/******************************************************************************* + * + * Function BTM_GetRemoteDeviceName + * + * Description This function is called to get the dev name of remote device + * from NV + * + * Returns TRUE if success; otherwise failed. + * + ******************************************************************************/ +bool BTM_GetRemoteDeviceName(const RawAddress& bd_addr, BD_NAME bd_name) { + LOG_VERBOSE("bd_addr:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + + bool ret = FALSE; + bt_bdname_t bdname; + bt_property_t prop_name; + BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME, + sizeof(bt_bdname_t), &bdname); + + if (btif_storage_get_remote_device_property(&bd_addr, &prop_name) == + BT_STATUS_SUCCESS) { + LOG_VERBOSE("NV name=%s", bdname.name); + strncpy((char*)bd_name, (char*)bdname.name, BD_NAME_LEN + 1); + ret = TRUE; + } + return ret; +} + +/******************************************************************************* + * + * Function BTM_SecAddBleKey + * + * Description Add/modify LE device information. This function will be + * normally called during host startup to restore all required + * information stored in the NVRAM. + * + * Parameters: bd_addr - BD address of the peer + * p_le_key - LE key values. + * key_type - LE SMP key type. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +void BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key, + tBTM_LE_KEY_TYPE key_type) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + if (!p_dev_rec || !p_le_key || + (key_type != BTM_LE_KEY_PENC && key_type != BTM_LE_KEY_PID && + key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC && + key_type != BTM_LE_KEY_LCSRK && key_type != BTM_LE_KEY_LID)) { + LOG_WARN("Wrong Type, or No Device record for bdaddr:%s, Type:0%hhu", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), key_type); + return; + } + + LOG_DEBUG("Adding BLE key device:%s key_type:%hhu", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), key_type); + + btm_sec_save_le_key(bd_addr, key_type, p_le_key, false); + // Only set peer irk. Local irk is always the same. + if (key_type == BTM_LE_KEY_PID) { + btm_ble_resolving_list_load_dev(*p_dev_rec); + } +} + +/******************************************************************************* + * + * Function BTM_BleLoadLocalKeys + * + * Description Local local identity key, encryption root or sign counter. + * + * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, + * BTM_BLE_KEY_TYPE_ER + * or BTM_BLE_KEY_TYPE_COUNTER. + * p_key: pointer to the key. + * + * Returns non2. + * + ******************************************************************************/ +void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) { + tBTM_SEC_DEVCB* p_devcb = &btm_sec_cb.devcb; + LOG_VERBOSE("type:%d", key_type); + if (p_key != NULL) { + switch (key_type) { + case BTM_BLE_KEY_TYPE_ID: + memcpy(&p_devcb->id_keys, &p_key->id_keys, + sizeof(tBTM_BLE_LOCAL_ID_KEYS)); + break; + + case BTM_BLE_KEY_TYPE_ER: + p_devcb->ble_encryption_key_value = p_key->er; + break; + + default: + LOG_ERROR("unknown key type:%d", key_type); + break; + } + } +} + +/** Returns local device encryption root (ER) */ +const Octet16& BTM_GetDeviceEncRoot() { + return btm_sec_cb.devcb.ble_encryption_key_value; +} + +/** Returns local device identity root (IR). */ +const Octet16& BTM_GetDeviceIDRoot() { return btm_sec_cb.devcb.id_keys.irk; } + +/** Return local device DHK. */ +const Octet16& BTM_GetDeviceDHK() { return btm_sec_cb.devcb.id_keys.dhk; } + +/******************************************************************************* + * + * Function BTM_SecurityGrant + * + * Description This function is called to grant security process. + * + * Parameters bd_addr - peer device bd address. + * res - result of the operation BTM_SUCCESS if success. + * Otherwise, BTM_REPEATED_ATTEMPTS if too many + * attempts. + * + * Returns None + * + ******************************************************************************/ +void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res) { + const tSMP_STATUS res_smp = + (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS; + LOG_VERBOSE("bd_addr:%s, res:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + smp_status_text(res_smp).c_str()); + BTM_LogHistory(kBtmLogTag, bd_addr, "Granted", + base::StringPrintf("passkey_status:%s", + smp_status_text(res_smp).c_str())); + + SMP_SecurityGrant(bd_addr, res_smp); +} + +/******************************************************************************* + * + * Function BTM_BlePasskeyReply + * + * Description This function is called after Security Manager submitted + * passkey request to the application. + * + * Parameters: bd_addr - Address of the device for which passkey was + * requested + * res - result of the operation BTM_SUCCESS if success + * key_len - length in bytes of the Passkey + * p_passkey - pointer to array with the passkey + * + ******************************************************************************/ +void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res, + uint32_t passkey) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + LOG_VERBOSE("bd_addr:%s, res:%d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), res); + if (p_dev_rec == NULL) { + LOG_ERROR("Unknown device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return; + } + + const tSMP_STATUS res_smp = + (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL; + BTM_LogHistory(kBtmLogTag, bd_addr, "Passkey reply", + base::StringPrintf("transport:%s authenticate_status:%s", + bt_transport_text(BT_TRANSPORT_LE).c_str(), + smp_status_text(res_smp).c_str())); + + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED; + SMP_PasskeyReply(bd_addr, res_smp, passkey); +} + +/******************************************************************************* + * + * Function BTM_BleConfirmReply + * + * Description This function is called after Security Manager submitted + * numeric comparison request to the application. + * + * Parameters: bd_addr - Address of the device with which numeric + * comparison was requested + * res - comparison result BTM_SUCCESS if success + * + ******************************************************************************/ +void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + LOG_VERBOSE("bd_addr:%s, res:%d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), res); + if (p_dev_rec == NULL) { + LOG_ERROR("Unknown device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return; + } + const tSMP_STATUS res_smp = + (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL; + + BTM_LogHistory(kBtmLogTag, bd_addr, "Confirm reply", + base::StringPrintf( + "transport:%s numeric_comparison_authenticate_status:%s", + bt_transport_text(BT_TRANSPORT_LE).c_str(), + smp_status_text(res_smp).c_str())); + + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED; + SMP_ConfirmReply(bd_addr, res_smp); +} + +/******************************************************************************* + * + * Function BTM_BleOobDataReply + * + * Description This function is called to provide the OOB data for + * SMP in response to BTM_LE_OOB_REQ_EVT + * + * Parameters: bd_addr - Address of the peer device + * res - result of the operation SMP_SUCCESS if success + * p_data - oob data, depending on transport and + * capabilities. + * Might be "Simple Pairing Randomizer", or + * "Security Manager TK Value". + * + ******************************************************************************/ +void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len, + uint8_t* p_data) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec == NULL) { + LOG_ERROR("Unknown device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return; + } + + const tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL; + BTM_LogHistory(kBtmLogTag, bd_addr, "Oob data reply", + base::StringPrintf("transport:%s authenticate_status:%s", + bt_transport_text(BT_TRANSPORT_LE).c_str(), + smp_status_text(res_smp).c_str())); + + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED; + SMP_OobDataReply(bd_addr, res_smp, len, p_data); +} + +/******************************************************************************* + * + * Function BTM_BleSecureConnectionOobDataReply + * + * Description This function is called to provide the OOB data for + * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection + * data is available + * + * Parameters: bd_addr - Address of the peer device + * p_c - pointer to Confirmation. + * p_r - pointer to Randomizer + * + ******************************************************************************/ +void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr, + uint8_t* p_c, uint8_t* p_r) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec == NULL) { + LOG_ERROR("Unknown device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return; + } + + BTM_LogHistory( + kBtmLogTag, bd_addr, "Oob data reply", + base::StringPrintf("transport:%s", + bt_transport_text(BT_TRANSPORT_LE).c_str())); + + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED; + + tSMP_SC_OOB_DATA oob; + memset(&oob, 0, sizeof(tSMP_SC_OOB_DATA)); + + oob.peer_oob_data.present = true; + memcpy(&oob.peer_oob_data.randomizer, p_r, OCTET16_LEN); + memcpy(&oob.peer_oob_data.commitment, p_c, OCTET16_LEN); + oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.AddressType(); + oob.peer_oob_data.addr_rcvd_from.bda = bd_addr; + + SMP_SecureConnectionOobDataReply((uint8_t*)&oob); +} + +/******************************************************** + * + * Function BTM_BleSetPrefConnParams + * + * Description Set a peripheral's preferred connection parameters + * + * Parameters: bd_addr - BD address of the peripheral + * scan_interval: scan interval + * scan_window: scan window + * min_conn_int - minimum preferred connection interval + * max_conn_int - maximum preferred connection interval + * peripheral_latency - preferred peripheral latency + * supervision_tout - preferred supervision timeout + * + * Returns void + * + ******************************************************************************/ +void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int, + uint16_t max_conn_int, + uint16_t peripheral_latency, + uint16_t supervision_tout) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + + LOG_VERBOSE("min:%u,max:%u,latency:%u,tout:%u", min_conn_int, max_conn_int, + peripheral_latency, supervision_tout); + + if (BTM_BLE_ISVALID_PARAM(min_conn_int, BTM_BLE_CONN_INT_MIN, + BTM_BLE_CONN_INT_MAX) && + BTM_BLE_ISVALID_PARAM(max_conn_int, BTM_BLE_CONN_INT_MIN, + BTM_BLE_CONN_INT_MAX) && + BTM_BLE_ISVALID_PARAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN, + BTM_BLE_CONN_SUP_TOUT_MAX) && + (peripheral_latency <= BTM_BLE_CONN_LATENCY_MAX || + peripheral_latency == BTM_BLE_CONN_PARAM_UNDEF)) { + if (p_dev_rec) { + /* expect conn int and stout and peripheral latency to be updated all + * together + */ + if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF || + max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) { + if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) + p_dev_rec->conn_params.min_conn_int = min_conn_int; + else + p_dev_rec->conn_params.min_conn_int = max_conn_int; + + if (max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) + p_dev_rec->conn_params.max_conn_int = max_conn_int; + else + p_dev_rec->conn_params.max_conn_int = min_conn_int; + + if (peripheral_latency != BTM_BLE_CONN_PARAM_UNDEF) + p_dev_rec->conn_params.peripheral_latency = peripheral_latency; + else + p_dev_rec->conn_params.peripheral_latency = + BTM_BLE_CONN_PERIPHERAL_LATENCY_DEF; + + if (supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) + p_dev_rec->conn_params.supervision_tout = supervision_tout; + else + p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF; + } + + } else { + LOG_ERROR("Unknown Device, setting rejected"); + } + } else { + LOG_ERROR("Illegal Connection Parameters"); + } +} + +/******************************************************************************* + * + * Function BTM_ReadDevInfo + * + * Description This function is called to read the device/address type + * of BD address. + * + * Parameter remote_bda: remote device address + * p_dev_type: output parameter to read the device type. + * p_addr_type: output parameter to read the address type. + * + ******************************************************************************/ +void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, + tBLE_ADDR_TYPE* p_addr_type) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(remote_bda); + tBTM_INQ_INFO* p_inq_info = BTM_InqDbRead(remote_bda); + + *p_addr_type = BLE_ADDR_PUBLIC; + + if (!p_dev_rec) { + *p_dev_type = BT_DEVICE_TYPE_BREDR; + /* Check with the BT manager if details about remote device are known */ + if (p_inq_info != NULL) { + *p_dev_type = p_inq_info->results.device_type; + *p_addr_type = p_inq_info->results.ble_addr_type; + } else { + /* unknown device, assume BR/EDR */ + LOG_VERBOSE("unknown device, BR/EDR assumed"); + } + } else /* there is a security device record existing */ + { + /* new inquiry result, merge device type in security device record */ + if (p_inq_info) { + p_dev_rec->device_type |= p_inq_info->results.device_type; + if (is_ble_addr_type_known(p_inq_info->results.ble_addr_type)) + p_dev_rec->ble.SetAddressType(p_inq_info->results.ble_addr_type); + else + LOG_WARN( + "Please do not update device record from anonymous le " + "advertisement"); + } + + if (p_dev_rec->bd_addr == remote_bda && + p_dev_rec->ble.pseudo_addr == remote_bda) { + *p_dev_type = p_dev_rec->device_type; + *p_addr_type = p_dev_rec->ble.AddressType(); + } else if (p_dev_rec->ble.pseudo_addr == remote_bda) { + *p_dev_type = BT_DEVICE_TYPE_BLE; + *p_addr_type = p_dev_rec->ble.AddressType(); + } else /* matching static address only */ { + if (p_dev_rec->device_type != BT_DEVICE_TYPE_UNKNOWN) { + *p_dev_type = p_dev_rec->device_type; + } else { + LOG_WARN("device_type not set; assuming BR/EDR"); + *p_dev_type = BT_DEVICE_TYPE_BREDR; + } + *p_addr_type = BLE_ADDR_PUBLIC; + } + } + LOG_DEBUG("Determined device_type:%s addr_type:%s", + DeviceTypeText(*p_dev_type).c_str(), + AddressTypeText(*p_addr_type).c_str()); +} + +/******************************************************************************* + * + * Function BTM_ReadConnectedTransportAddress + * + * Description This function is called to read the paired device/address + * type of other device paired corresponding to the BD_address + * + * Parameter remote_bda: remote device address, carry out the transport + * address + * transport: active transport + * + * Return true if an active link is identified; false otherwise + * + ******************************************************************************/ +bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda, + tBT_TRANSPORT transport) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(*remote_bda); + + /* if no device can be located, return */ + if (p_dev_rec == NULL) return false; + + if (transport == BT_TRANSPORT_BR_EDR) { + if (BTM_IsAclConnectionUp(p_dev_rec->bd_addr, transport)) { + *remote_bda = p_dev_rec->bd_addr; + return true; + } else if (p_dev_rec->device_type & BT_DEVICE_TYPE_BREDR) { + *remote_bda = p_dev_rec->bd_addr; + } else + *remote_bda = RawAddress::kEmpty; + return false; + } + + if (transport == BT_TRANSPORT_LE) { + *remote_bda = p_dev_rec->ble.pseudo_addr; + if (BTM_IsAclConnectionUp(p_dev_rec->ble.pseudo_addr, transport)) + return true; + else + return false; + } + + return false; +} + +tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr, + uint16_t tx_pdu_length) { + if (!controller_get_interface()->supports_ble_packet_extension()) { + LOG_INFO("Local controller does not support le packet extension"); + return BTM_ILLEGAL_VALUE; + } + + LOG_INFO("bd_addr:%s, tx_pdu_length:%d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + tx_pdu_length); + + auto p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec == NULL) { + LOG_ERROR("Device %s not found", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return BTM_UNKNOWN_ADDR; + } + + if (tx_pdu_length > BTM_BLE_DATA_SIZE_MAX) + tx_pdu_length = BTM_BLE_DATA_SIZE_MAX; + else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN) + tx_pdu_length = BTM_BLE_DATA_SIZE_MIN; + + if (p_dev_rec->get_suggested_tx_octets() >= tx_pdu_length) { + LOG_INFO("Suggested TX octect already set to controller %d >= %d", + p_dev_rec->get_suggested_tx_octets(), tx_pdu_length); + return BTM_SUCCESS; + } + + uint16_t tx_time = BTM_BLE_DATA_TX_TIME_MAX_LEGACY; + + if (controller_get_interface()->get_bt_version()->hci_version >= + HCI_PROTO_VERSION_5_0) + tx_time = BTM_BLE_DATA_TX_TIME_MAX; + + if (!BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) { + LOG_INFO( + "Unable to set data length because no le acl link connected to device"); + return BTM_WRONG_MODE; + } + + uint16_t hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE); + + if (!acl_peer_supports_ble_packet_extension(hci_handle)) { + LOG_INFO("Remote device unable to support le packet extension"); + return BTM_ILLEGAL_VALUE; + } + + tx_pdu_length = std::min( + tx_pdu_length, + controller_get_interface()->get_ble_maximum_tx_data_length()); + tx_time = std::min( + tx_time, controller_get_interface()->get_ble_maximum_tx_time()); + + btsnd_hcic_ble_set_data_length(hci_handle, tx_pdu_length, tx_time); + p_dev_rec->set_suggested_tx_octect(tx_pdu_length); + + return BTM_SUCCESS; +} + +/******************************************************************************* + * + * Function btm_ble_determine_security_act + * + * Description This function checks the security of current LE link + * and returns the appropriate action that needs to be + * taken to achieve the required security. + * + * Parameter is_originator - True if outgoing connection + * bdaddr: remote device address + * security_required: Security required for the service. + * + * Returns The appropriate security action required. + * + ******************************************************************************/ +static tBTM_SEC_ACTION btm_ble_determine_security_act( + bool is_originator, const RawAddress& bdaddr, uint16_t security_required) { + tBTM_LE_AUTH_REQ auth_req = 0x00; + + if (is_originator) { + if ((security_required & BTM_SEC_OUT_FLAGS) == 0 && + (security_required & BTM_SEC_OUT_MITM) == 0) { + LOG_INFO("No security required for outgoing connection"); + return BTM_SEC_OK; + } + + if (security_required & BTM_SEC_OUT_MITM) auth_req |= BTM_LE_AUTH_REQ_MITM; + } else { + if ((security_required & BTM_SEC_IN_FLAGS) == 0 && + (security_required & BTM_SEC_IN_MITM) == 0) { + LOG_VERBOSE("No security required for incoming connection"); + return BTM_SEC_OK; + } + + if (security_required & BTM_SEC_IN_MITM) auth_req |= BTM_LE_AUTH_REQ_MITM; + } + + tBTM_BLE_SEC_REQ_ACT ble_sec_act = {BTM_BLE_SEC_REQ_ACT_NONE}; + btm_ble_link_sec_check(bdaddr, auth_req, &ble_sec_act); + + LOG_VERBOSE("ble_sec_act %d", ble_sec_act); + + if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD) return BTM_SEC_ENC_PENDING; + + if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_NONE) return BTM_SEC_OK; + + bool is_link_encrypted = BTM_IsEncrypted(bdaddr, BT_TRANSPORT_LE); + bool is_key_mitm = BTM_IsLinkKeyAuthed(bdaddr, BT_TRANSPORT_LE); + + if (auth_req & BTM_LE_AUTH_REQ_MITM) { + if (!is_key_mitm) { + return BTM_SEC_ENCRYPT_MITM; + } else { + if (is_link_encrypted) + return BTM_SEC_OK; + else + return BTM_SEC_ENCRYPT; + } + } else { + if (is_link_encrypted) + return BTM_SEC_OK; + else + return BTM_SEC_ENCRYPT_NO_MITM; + } + + return BTM_SEC_OK; +} + +/******************************************************************************* + * + * Function btm_ble_start_sec_check + * + * Description This function is to check and set the security required for + * LE link for LE COC. + * + * Parameter bdaddr: remote device address. + * psm : PSM of the LE COC service. + * is_originator: true if outgoing connection. + * p_callback : Pointer to the callback function. + * p_ref_data : Pointer to be returned along with the callback. + * + * Returns Returns - tBTM_STATUS + * + ******************************************************************************/ +tBTM_STATUS btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm, + bool is_originator, + tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data) { + /* Find the service record for the PSM */ + tBTM_SEC_SERV_REC* p_serv_rec = + btm_sec_cb.find_first_serv_rec(is_originator, psm); + + /* If there is no application registered with this PSM do not allow connection + */ + if (!p_serv_rec) { + LOG_WARN("PSM: %d no application registered", psm); + (*p_callback)(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED); + return BTM_ILLEGAL_VALUE; + } + + bool is_encrypted = BTM_IsEncrypted(bd_addr, BT_TRANSPORT_LE); + bool is_link_key_authed = BTM_IsLinkKeyAuthed(bd_addr, BT_TRANSPORT_LE); + bool is_authenticated = BTM_IsAuthenticated(bd_addr, BT_TRANSPORT_LE); + + if (!is_originator) { + if ((p_serv_rec->security_flags & BTM_SEC_IN_ENCRYPT) && !is_encrypted) { + LOG_ERROR("BTM_NOT_ENCRYPTED. service security_flags=0x%x", + p_serv_rec->security_flags); + return BTM_NOT_ENCRYPTED; + } else if ((p_serv_rec->security_flags & BTM_SEC_IN_AUTHENTICATE) && + !(is_link_key_authed || is_authenticated)) { + LOG_ERROR("BTM_NOT_AUTHENTICATED. service security_flags=0x%x", + p_serv_rec->security_flags); + return BTM_NOT_AUTHENTICATED; + } + /* TODO: When security is required, then must check that the key size of our + service is equal or smaller than the incoming connection key size. */ + } + + tBTM_SEC_ACTION sec_act = btm_ble_determine_security_act( + is_originator, bd_addr, p_serv_rec->security_flags); + + tBTM_BLE_SEC_ACT ble_sec_act = BTM_BLE_SEC_NONE; + + switch (sec_act) { + case BTM_SEC_OK: + LOG_DEBUG("Security met"); + p_callback(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_SUCCESS); + break; + + case BTM_SEC_ENCRYPT: + LOG_DEBUG("Encryption needs to be done"); + ble_sec_act = BTM_BLE_SEC_ENCRYPT; + break; + + case BTM_SEC_ENCRYPT_MITM: + LOG_DEBUG("Pairing with MITM needs to be done"); + ble_sec_act = BTM_BLE_SEC_ENCRYPT_MITM; + break; + + case BTM_SEC_ENCRYPT_NO_MITM: + LOG_DEBUG("Pairing with No MITM needs to be done"); + ble_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM; + break; + + case BTM_SEC_ENC_PENDING: + LOG_DEBUG("Ecryption pending"); + break; + } + + if (ble_sec_act == BTM_BLE_SEC_NONE && sec_act != BTM_SEC_ENC_PENDING) { + return BTM_SUCCESS; + } + + l2cble_update_sec_act(bd_addr, sec_act); + + BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, p_callback, p_ref_data, + ble_sec_act); + + return BTM_SUCCESS; +} + +/******************************************************************************* + * + * Function increment_sign_counter + * + * Description This method is to increment the (local or peer) sign counter + * Returns None + * + ******************************************************************************/ +void tBTM_SEC_REC::increment_sign_counter(bool local) { + if (local) { + ble_keys.local_counter++; + } else { + ble_keys.counter++; + } + + LOG_VERBOSE("local=%d local sign counter=%d peer sign counter=%d", local, + ble_keys.local_counter, ble_keys.counter); +} + +/******************************************************************************* + * + * Function btm_ble_get_enc_key_type + * + * Description This function is to get the BLE key type that has been + * exchanged between the local device and the peer device. + * + * Returns p_key_type: output parameter to carry the key type value. + * + ******************************************************************************/ +bool btm_ble_get_enc_key_type(const RawAddress& bd_addr, uint8_t* p_key_types) { + tBTM_SEC_DEV_REC* p_dev_rec; + + LOG_VERBOSE("bd_addr:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + + p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec != NULL) { + *p_key_types = p_dev_rec->sec_rec.ble_keys.key_type; + return true; + } + return false; +} + +/******************************************************************************* + * + * Function btm_get_local_div + * + * Description This function is called to read the local DIV + * + * Returns TRUE - if a valid DIV is availavle + ******************************************************************************/ +bool btm_get_local_div(const RawAddress& bd_addr, uint16_t* p_div) { + tBTM_SEC_DEV_REC* p_dev_rec; + bool status = false; + + *p_div = 0; + p_dev_rec = btm_find_dev(bd_addr); + + if (p_dev_rec && p_dev_rec->sec_rec.ble_keys.div) { + status = true; + *p_div = p_dev_rec->sec_rec.ble_keys.div; + } + LOG_VERBOSE("status=%d (1-OK) DIV=0x%x", status, *p_div); + return status; +} + +/******************************************************************************* + * + * Function btm_sec_save_le_key + * + * Description This function is called by the SMP to update + * an BLE key. SMP is internal, whereas all the keys shall + * be sent to the application. The function is also called + * when application passes ble key stored in NVRAM to the + * btm_sec. + * pass_to_application parameter is false in this case. + * + * Returns void + * + ******************************************************************************/ +void btm_sec_save_le_key(const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type, + tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) { + tBTM_SEC_DEV_REC* p_rec; + tBTM_LE_EVT_DATA cb_data; + + LOG_VERBOSE("key_type=0x%x pass_to_application=%d", key_type, + pass_to_application); + /* Store the updated key in the device database */ + + if ((p_rec = btm_find_dev(bd_addr)) != NULL && + (p_keys || key_type == BTM_LE_KEY_LID)) { + btm_ble_init_pseudo_addr(p_rec, bd_addr); + + switch (key_type) { + case BTM_LE_KEY_PENC: + p_rec->sec_rec.ble_keys.pltk = p_keys->penc_key.ltk; + memcpy(p_rec->sec_rec.ble_keys.rand, p_keys->penc_key.rand, + BT_OCTET8_LEN); + p_rec->sec_rec.ble_keys.sec_level = p_keys->penc_key.sec_level; + p_rec->sec_rec.ble_keys.ediv = p_keys->penc_key.ediv; + p_rec->sec_rec.ble_keys.key_size = p_keys->penc_key.key_size; + p_rec->sec_rec.ble_keys.key_type |= BTM_LE_KEY_PENC; + p_rec->sec_rec.sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN; + if (p_keys->penc_key.sec_level == SMP_SEC_AUTHENTICATED) + p_rec->sec_rec.sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED; + else + p_rec->sec_rec.sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED; + LOG_VERBOSE( + "BTM_LE_KEY_PENC key_type=0x%x sec_flags=0x%x sec_leve=0x%x", + p_rec->sec_rec.ble_keys.key_type, p_rec->sec_rec.sec_flags, + p_rec->sec_rec.ble_keys.sec_level); + break; + + case BTM_LE_KEY_PID: + p_rec->sec_rec.ble_keys.irk = p_keys->pid_key.irk; + p_rec->ble.identity_address_with_type.bda = + p_keys->pid_key.identity_addr; + p_rec->ble.identity_address_with_type.type = + p_keys->pid_key.identity_addr_type; + p_rec->sec_rec.ble_keys.key_type |= BTM_LE_KEY_PID; + LOG_VERBOSE( + "BTM_LE_KEY_PID key_type=0x%x save peer IRK, change bd_addr=%s " + "to id_addr=%s id_addr_type=0x%x", + p_rec->sec_rec.ble_keys.key_type, + ADDRESS_TO_LOGGABLE_CSTR(p_rec->bd_addr), + ADDRESS_TO_LOGGABLE_CSTR(p_keys->pid_key.identity_addr), + p_keys->pid_key.identity_addr_type); + /* update device record address as identity address */ + p_rec->bd_addr = p_keys->pid_key.identity_addr; + /* combine DUMO device security record if needed */ + btm_consolidate_dev(p_rec); + break; + + case BTM_LE_KEY_PCSRK: + p_rec->sec_rec.ble_keys.pcsrk = p_keys->pcsrk_key.csrk; + p_rec->sec_rec.ble_keys.srk_sec_level = p_keys->pcsrk_key.sec_level; + p_rec->sec_rec.ble_keys.counter = p_keys->pcsrk_key.counter; + p_rec->sec_rec.ble_keys.key_type |= BTM_LE_KEY_PCSRK; + p_rec->sec_rec.sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN; + if (p_keys->pcsrk_key.sec_level == SMP_SEC_AUTHENTICATED) + p_rec->sec_rec.sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED; + else + p_rec->sec_rec.sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED; + + LOG_VERBOSE( + "BTM_LE_KEY_PCSRK key_type=0x%x sec_flags=0x%x sec_level=0x%x " + "peer_counter=%d", + p_rec->sec_rec.ble_keys.key_type, p_rec->sec_rec.sec_flags, + p_rec->sec_rec.ble_keys.srk_sec_level, + p_rec->sec_rec.ble_keys.counter); + break; + + case BTM_LE_KEY_LENC: + p_rec->sec_rec.ble_keys.lltk = p_keys->lenc_key.ltk; + p_rec->sec_rec.ble_keys.div = p_keys->lenc_key.div; /* update DIV */ + p_rec->sec_rec.ble_keys.sec_level = p_keys->lenc_key.sec_level; + p_rec->sec_rec.ble_keys.key_size = p_keys->lenc_key.key_size; + p_rec->sec_rec.ble_keys.key_type |= BTM_LE_KEY_LENC; + + LOG_VERBOSE( + "BTM_LE_KEY_LENC key_type=0x%x DIV=0x%x key_size=0x%x " + "sec_level=0x%x", + p_rec->sec_rec.ble_keys.key_type, p_rec->sec_rec.ble_keys.div, + p_rec->sec_rec.ble_keys.key_size, + p_rec->sec_rec.ble_keys.sec_level); + break; + + case BTM_LE_KEY_LCSRK: /* local CSRK has been delivered */ + p_rec->sec_rec.ble_keys.lcsrk = p_keys->lcsrk_key.csrk; + p_rec->sec_rec.ble_keys.div = p_keys->lcsrk_key.div; /* update DIV */ + p_rec->sec_rec.ble_keys.local_csrk_sec_level = + p_keys->lcsrk_key.sec_level; + p_rec->sec_rec.ble_keys.local_counter = p_keys->lcsrk_key.counter; + p_rec->sec_rec.ble_keys.key_type |= BTM_LE_KEY_LCSRK; + LOG_VERBOSE( + "BTM_LE_KEY_LCSRK key_type=0x%x DIV=0x%x scrk_sec_level=0x%x " + "local_counter=%d", + p_rec->sec_rec.ble_keys.key_type, p_rec->sec_rec.ble_keys.div, + p_rec->sec_rec.ble_keys.local_csrk_sec_level, + p_rec->sec_rec.ble_keys.local_counter); + break; + + case BTM_LE_KEY_LID: + p_rec->sec_rec.ble_keys.key_type |= BTM_LE_KEY_LID; + break; + default: + LOG_WARN("btm_sec_save_le_key (Bad key_type 0x%02x)", key_type); + return; + } + + LOG_VERBOSE("BLE key type 0x%x, updated for BDA:%s", key_type, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + + /* Notify the application that one of the BLE keys has been updated + If link key is in progress, it will get sent later.*/ + if (pass_to_application && btm_sec_cb.api.p_le_callback) { + cb_data.key.p_key_value = p_keys; + cb_data.key.key_type = key_type; + + (*btm_sec_cb.api.p_le_callback)(BTM_LE_KEY_EVT, bd_addr, &cb_data); + } + return; + } + + LOG_WARN("BLE key type 0x%x, called for Unknown BDA or type:%s", key_type, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + + if (p_rec) { + LOG_VERBOSE("sec_flags=0x%x", p_rec->sec_rec.sec_flags); + } +} + +/******************************************************************************* + * + * Function btm_ble_update_sec_key_size + * + * Description update the current lin kencryption key size + * + * Returns void + * + ******************************************************************************/ +void btm_ble_update_sec_key_size(const RawAddress& bd_addr, + uint8_t enc_key_size) { + tBTM_SEC_DEV_REC* p_rec; + + LOG_VERBOSE("bd_addr:%s, enc_key_size=%d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + enc_key_size); + + p_rec = btm_find_dev(bd_addr); + if (p_rec != NULL) { + p_rec->sec_rec.enc_key_size = enc_key_size; + } +} + +/******************************************************************************* + * + * Function btm_ble_read_sec_key_size + * + * Description update the current lin kencryption key size + * + * Returns void + * + ******************************************************************************/ +uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr) { + tBTM_SEC_DEV_REC* p_rec; + + p_rec = btm_find_dev(bd_addr); + if (p_rec != NULL) { + return p_rec->sec_rec.enc_key_size; + } else + return 0; +} + +/******************************************************************************* + * + * Function btm_ble_link_sec_check + * + * Description Check BLE link security level match. + * + * Returns true: check is OK and the *p_sec_req_act contain the action + * + ******************************************************************************/ +void btm_ble_link_sec_check(const RawAddress& bd_addr, + tBTM_LE_AUTH_REQ auth_req, + tBTM_BLE_SEC_REQ_ACT* p_sec_req_act) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + uint8_t req_sec_level = SMP_SEC_NONE, cur_sec_level = SMP_SEC_NONE; + + LOG_VERBOSE("bd_addr:%s, auth_req=0x%x", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + auth_req); + + if (p_dev_rec == NULL) { + LOG_ERROR("received for unknown device"); + return; + } + + if (p_dev_rec->sec_rec.is_security_state_encrypting() || + p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_AUTHENTICATING) { + /* race condition: discard the security request while central is encrypting + * the link */ + *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD; + } else { + req_sec_level = SMP_SEC_UNAUTHENTICATE; + if (auth_req & BTM_LE_AUTH_REQ_MITM) { + req_sec_level = SMP_SEC_AUTHENTICATED; + } + + LOG_VERBOSE("dev_rec sec_flags=0x%x", p_dev_rec->sec_rec.sec_flags); + + /* currently encrpted */ + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_ENCRYPTED) { + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_AUTHENTICATED) + cur_sec_level = SMP_SEC_AUTHENTICATED; + else + cur_sec_level = SMP_SEC_UNAUTHENTICATE; + } else /* unencrypted link */ + { + /* if bonded, get the key security level */ + if (p_dev_rec->sec_rec.ble_keys.key_type & BTM_LE_KEY_PENC) + cur_sec_level = p_dev_rec->sec_rec.ble_keys.sec_level; + else + cur_sec_level = SMP_SEC_NONE; + } + + if (cur_sec_level >= req_sec_level) { + /* To avoid re-encryption on an encrypted link for an equal condition + * encryption */ + *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT; + } else { + /* start the pariring process to upgrade the keys*/ + *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_PAIR; + } + } + + LOG_VERBOSE("cur_sec_level=%d req_sec_level=%d sec_req_act=%d", cur_sec_level, + req_sec_level, *p_sec_req_act); +} + +/******************************************************************************* + * + * Function btm_ble_set_encryption + * + * Description This function is called to ensure that LE connection is + * encrypted. Should be called only on an open connection. + * Typically only needed for connections that first want to + * bring up unencrypted links, then later encrypt them. + * + * Returns void + * the local device ER is copied into er + * + ******************************************************************************/ +tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr, + tBTM_BLE_SEC_ACT sec_act, + uint8_t link_role) { + tBTM_STATUS cmd = BTM_NO_RESOURCES; + tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr); + tBTM_BLE_SEC_REQ_ACT sec_req_act; + tBTM_LE_AUTH_REQ auth_req; + + if (p_rec == NULL) { + LOG_WARN("NULL device record!! sec_act=0x%x", sec_act); + return (BTM_WRONG_MODE); + } + + LOG_VERBOSE("sec_act=0x%x role_central=%d", sec_act, p_rec->role_central); + + if (sec_act == BTM_BLE_SEC_ENCRYPT_MITM) { + p_rec->sec_rec.security_required |= BTM_SEC_IN_MITM; + } + + switch (sec_act) { + case BTM_BLE_SEC_ENCRYPT: + if (link_role == HCI_ROLE_CENTRAL) { + /* start link layer encryption using the security info stored */ + cmd = btm_ble_start_encrypt(bd_addr, false, NULL); + break; + } + /* if salve role then fall through to call SMP_Pair below which will send + a sec_request to request the central to encrypt the link */ + FALLTHROUGH_INTENDED; /* FALLTHROUGH */ + case BTM_BLE_SEC_ENCRYPT_NO_MITM: + case BTM_BLE_SEC_ENCRYPT_MITM: + auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM) + ? SMP_AUTH_BOND + : (SMP_AUTH_BOND | SMP_AUTH_YN_BIT); + btm_ble_link_sec_check(bd_addr, auth_req, &sec_req_act); + if (sec_req_act == BTM_BLE_SEC_REQ_ACT_NONE || + sec_req_act == BTM_BLE_SEC_REQ_ACT_DISCARD) { + LOG_VERBOSE("no action needed. Ignore"); + cmd = BTM_SUCCESS; + break; + } + if (link_role == HCI_ROLE_CENTRAL) { + if (sec_req_act == BTM_BLE_SEC_REQ_ACT_ENCRYPT) { + cmd = btm_ble_start_encrypt(bd_addr, false, NULL); + break; + } + } + + if (SMP_Pair(bd_addr) == SMP_STARTED) { + cmd = BTM_CMD_STARTED; + p_rec->sec_rec.sec_state = BTM_SEC_STATE_AUTHENTICATING; + } + break; + + default: + cmd = BTM_WRONG_MODE; + break; + } + return cmd; +} + +/******************************************************************************* + * + * Function btm_ble_ltk_request + * + * Description This function is called when encryption request is received + * on a peripheral device. + * + * + * Returns void + * + ******************************************************************************/ +void btm_ble_ltk_request(uint16_t handle, BT_OCTET8 rand, uint16_t ediv) { + tBTM_SEC_CB* p_cb = &btm_sec_cb; + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle); + + LOG_VERBOSE("handle:0x%x", handle); + + p_cb->ediv = ediv; + + memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN); + + if (p_dev_rec != NULL) { + if (!smp_proc_ltk_request(p_dev_rec->bd_addr)) { + btm_ble_ltk_request_reply(p_dev_rec->bd_addr, false, Octet16{0}); + } + } +} + +/** This function is called to start LE encryption. + * Returns BTM_SUCCESS if encryption was started successfully + */ +tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk, + Octet16* p_stk) { + tBTM_SEC_CB* p_cb = &btm_sec_cb; + tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda); + BT_OCTET8 dummy_rand = {0}; + + LOG_VERBOSE("bd_addr:%s, use_stk:%d", ADDRESS_TO_LOGGABLE_CSTR(bda), use_stk); + + if (!p_rec) { + LOG_ERROR("Link is not active, can not encrypt!"); + return BTM_WRONG_MODE; + } + + if (p_rec->sec_rec.is_security_state_encrypting()) { + LOG_WARN("Link Encryption is active, Busy!"); + return BTM_BUSY; + } + + p_cb->enc_handle = p_rec->ble_hci_handle; + + if (use_stk) { + btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, *p_stk); + } else if (p_rec->sec_rec.ble_keys.key_type & BTM_LE_KEY_PENC) { + btsnd_hcic_ble_start_enc( + p_rec->ble_hci_handle, p_rec->sec_rec.ble_keys.rand, + p_rec->sec_rec.ble_keys.ediv, p_rec->sec_rec.ble_keys.pltk); + } else { + LOG_ERROR("No key available to encrypt the link"); + return BTM_ERR_KEY_MISSING; + } + + if (p_rec->sec_rec.sec_state == BTM_SEC_STATE_IDLE) + p_rec->sec_rec.sec_state = BTM_SEC_STATE_LE_ENCRYPTING; + + return BTM_CMD_STARTED; +} + +/******************************************************************************* + * + * Function btm_ble_notify_enc_cmpl + * + * Description This function is called to connect EATT and notify GATT to + * send data if any request is pending. This either happens on + * encryption complete event, or if bond is pending, after SMP + * notifies that bonding is complete. + * + * Returns void + * + ******************************************************************************/ +static void btm_ble_notify_enc_cmpl(const RawAddress& bd_addr, + bool encr_enable) { + if (encr_enable) { + uint8_t remote_lmp_version = 0; + if (!BTM_ReadRemoteVersion(bd_addr, &remote_lmp_version, nullptr, + nullptr) || + remote_lmp_version == 0) { + LOG_WARN("BLE Unable to determine remote version"); + } + + if (remote_lmp_version == 0 || + remote_lmp_version >= HCI_PROTO_VERSION_5_0) { + /* Link is encrypted, start EATT if remote LMP version is unknown, or 5.2 + * or greater */ + bluetooth::eatt::EattExtension::GetInstance()->Connect(bd_addr); + } + } + + /* to notify GATT to send data if any request is pending */ + gatt_notify_enc_cmpl(bd_addr); +} + +/******************************************************************************* + * + * Function btm_ble_link_encrypted + * + * Description This function is called when LE link encrption status is + * changed. + * + * Returns void + * + ******************************************************************************/ +void btm_ble_link_encrypted(const RawAddress& bd_addr, uint8_t encr_enable) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + bool enc_cback; + + LOG_VERBOSE("bd_addr:%s, encr_enable=%d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + encr_enable); + + if (!p_dev_rec) { + LOG_WARN("No Device Found!"); + return; + } + + enc_cback = p_dev_rec->sec_rec.is_security_state_le_encrypting(); + + smp_link_encrypted(bd_addr, encr_enable); + + LOG_VERBOSE("p_dev_rec->sec_rec.sec_flags=0x%x", + p_dev_rec->sec_rec.sec_flags); + + if (encr_enable && p_dev_rec->sec_rec.enc_key_size == 0) + p_dev_rec->sec_rec.enc_key_size = p_dev_rec->sec_rec.ble_keys.key_size; + + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; + if (p_dev_rec->sec_rec.p_callback && enc_cback) { + if (encr_enable) btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS, true); + /* LTK missing on peripheral */ + else if (p_dev_rec->role_central && + (p_dev_rec->sec_rec.sec_status == HCI_ERR_KEY_MISSING)) { + btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_KEY_MISSING, true); + } else if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN)) { + btm_sec_dev_rec_cback_event(p_dev_rec, BTM_FAILED_ON_SECURITY, true); + } else if (p_dev_rec->role_central) + btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, true); + } + + tBTM_BD_NAME remote_name = {}; + /* to notify GATT to send data if any request is pending, + or if IOP matched, delay notifying until SMP_CMPLT_EVT */ + if (BTM_GetRemoteDeviceName(p_dev_rec->ble.pseudo_addr, remote_name) && + interop_match_name(INTEROP_SUSPEND_ATT_TRAFFIC_DURING_PAIRING, + (const char*)remote_name) && + (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_LE_ACTIVE) && + btm_sec_cb.pairing_bda == p_dev_rec->ble.pseudo_addr) { + LOG_INFO( + "INTEROP_DELAY_ATT_TRAFFIC_DURING_PAIRING: Waiting for bonding to " + "complete to notify enc complete"); + } else { + btm_ble_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr, encr_enable); + } +} + +/******************************************************************************* + * + * Function btm_ble_ltk_request_reply + * + * Description This function is called to send a LTK request reply on a + * peripheral + * device. + * + * Returns void + * + ******************************************************************************/ +void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk, + const Octet16& stk) { + tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda); + tBTM_SEC_CB* p_cb = &btm_sec_cb; + + LOG_VERBOSE("bd_addr:%s, use_stk:%d", ADDRESS_TO_LOGGABLE_CSTR(bda), use_stk); + + if (p_rec == NULL) { + LOG_ERROR("unknown device"); + return; + } + + p_cb->enc_handle = p_rec->ble_hci_handle; + p_cb->key_size = p_rec->sec_rec.ble_keys.key_size; + + LOG_ERROR("key size=%d", p_rec->sec_rec.ble_keys.key_size); + if (use_stk) { + btsnd_hcic_ble_ltk_req_reply(btm_sec_cb.enc_handle, stk); + return; + } + /* calculate LTK using peer device */ + if (p_rec->sec_rec.ble_keys.key_type & BTM_LE_KEY_LENC) { + btsnd_hcic_ble_ltk_req_reply(btm_sec_cb.enc_handle, + p_rec->sec_rec.ble_keys.lltk); + return; + } + + p_rec = btm_find_dev_with_lenc(bda); + if (!p_rec) { + btsnd_hcic_ble_ltk_req_neg_reply(btm_sec_cb.enc_handle); + return; + } + + LOG_INFO("Found second sec_dev_rec for device that have LTK"); + /* This can happen when remote established LE connection using RPA to this + * device, but then pair with us using Classing transport while still keeping + * LE connection. If remote attempts to encrypt the LE connection, we might + * end up here. We will eventually consolidate both entries, this is to avoid + * race conditions. */ + + LOG_ASSERT(p_rec->sec_rec.ble_keys.key_type & BTM_LE_KEY_LENC); + p_cb->key_size = p_rec->sec_rec.ble_keys.key_size; + btsnd_hcic_ble_ltk_req_reply(btm_sec_cb.enc_handle, + p_rec->sec_rec.ble_keys.lltk); +} + +/******************************************************************************* + * + * Function btm_ble_io_capabilities_req + * + * Description This function is called to handle SMP get IO capability + * request. + * + * Returns void + * + ******************************************************************************/ +static uint8_t btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC* p_dev_rec, + tBTM_LE_IO_REQ* p_data) { + uint8_t callback_rc = BTM_SUCCESS; + LOG_VERBOSE("p_dev_rec->bd_addr:%s", + ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->bd_addr)); + if (btm_sec_cb.api.p_le_callback) { + /* the callback function implementation may change the IO capability... */ + callback_rc = (*btm_sec_cb.api.p_le_callback)( + BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA*)p_data); + } + if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != p_data->oob_data)) { + p_data->auth_req &= BTM_LE_AUTH_REQ_MASK; + + LOG_VERBOSE("1:p_dev_rec->sec_rec.security_required=%d, auth_req:%d", + p_dev_rec->sec_rec.security_required, p_data->auth_req); + LOG_VERBOSE("2:i_keys=0x%x r_keys=0x%x (bit 0-LTK 1-IRK 2-CSRK)", + p_data->init_keys, p_data->resp_keys); + + /* if authentication requires MITM protection, put on the mask */ + if (p_dev_rec->sec_rec.security_required & BTM_SEC_IN_MITM) + p_data->auth_req |= BTM_LE_AUTH_REQ_MITM; + + if (!(p_data->auth_req & SMP_AUTH_BOND)) { + LOG_VERBOSE("Non bonding: No keys should be exchanged"); + p_data->init_keys = 0; + p_data->resp_keys = 0; + } + + LOG_VERBOSE("3:auth_req:%d", p_data->auth_req); + LOG_VERBOSE("4:i_keys=0x%x r_keys=0x%x", p_data->init_keys, + p_data->resp_keys); + + LOG_VERBOSE("5:p_data->io_cap=%d auth_req:%d", p_data->io_cap, + p_data->auth_req); + + /* remove MITM protection requirement if IO cap does not allow it */ + if ((p_data->io_cap == BTM_IO_CAP_NONE) && p_data->oob_data == SMP_OOB_NONE) + p_data->auth_req &= ~BTM_LE_AUTH_REQ_MITM; + + if (!(p_data->auth_req & SMP_SC_SUPPORT_BIT)) { + /* if Secure Connections are not supported then remove LK derivation, + ** and keypress notifications. + */ + LOG_VERBOSE( + "SC not supported -> No LK derivation, no keypress notifications"); + p_data->auth_req &= ~SMP_KP_SUPPORT_BIT; + p_data->init_keys &= ~SMP_SEC_KEY_TYPE_LK; + p_data->resp_keys &= ~SMP_SEC_KEY_TYPE_LK; + } + + LOG_VERBOSE("6:IO_CAP:%d oob_data:%d auth_req:0x%02x", p_data->io_cap, + p_data->oob_data, p_data->auth_req); + } + return callback_rc; +} + +/******************************************************************************* + * + * Function btm_ble_br_keys_req + * + * Description This function is called to handle SMP request for keys sent + * over BR/EDR. + * + * Returns void + * + ******************************************************************************/ +static uint8_t btm_ble_br_keys_req(tBTM_SEC_DEV_REC* p_dev_rec, + tBTM_LE_IO_REQ* p_data) { + uint8_t callback_rc = BTM_SUCCESS; + LOG_VERBOSE("p_dev_rec->bd_addr:%s", + ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->bd_addr)); + *p_data = tBTM_LE_IO_REQ{ + .io_cap = BTM_IO_CAP_UNKNOWN, + .oob_data = false, + .auth_req = BTM_LE_AUTH_REQ_SC_MITM_BOND, + .max_key_size = BTM_BLE_MAX_KEY_SIZE, + .init_keys = SMP_BR_SEC_DEFAULT_KEY, + .resp_keys = SMP_BR_SEC_DEFAULT_KEY, + }; + + if (osi_property_get_bool(kPropertyCtkdDisableCsrkDistribution, false)) { + p_data->init_keys &= (~SMP_SEC_KEY_TYPE_CSRK); + p_data->resp_keys &= (~SMP_SEC_KEY_TYPE_CSRK); + } + + return callback_rc; +} + +/******************************************************************************* + * + * Function btm_ble_connected + * + * Description This function is when a LE connection to the peer device is + * establsihed + * + * Returns void + * + ******************************************************************************/ +void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, + uint8_t role, tBLE_ADDR_TYPE addr_type, + bool addr_matched, + bool can_read_discoverable_characteristics) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda); + + LOG_INFO("Update timestamp for ble connection:%s", + ADDRESS_TO_LOGGABLE_CSTR(bda)); + // TODO() Why is timestamp a counter ? + p_dev_rec->timestamp = btm_sec_cb.dev_rec_count++; + + if (is_ble_addr_type_known(addr_type)) + p_dev_rec->ble.SetAddressType(addr_type); + else + LOG_WARN( + "Please do not update device record from anonymous le advertisement"); + + p_dev_rec->ble.pseudo_addr = bda; + p_dev_rec->ble_hci_handle = handle; + p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE; + p_dev_rec->role_central = (role == HCI_ROLE_CENTRAL) ? true : false; + p_dev_rec->can_read_discoverable = can_read_discoverable_characteristics; + + if (!addr_matched) { + p_dev_rec->ble.active_addr_type = BTM_BLE_ADDR_PSEUDO; + if (p_dev_rec->ble.AddressType() == BLE_ADDR_RANDOM) { + p_dev_rec->ble.cur_rand_addr = bda; + } + } + btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_ADV_IND_EVT; +} + +/***************************************************************************** + * Function btm_proc_smp_cback + * + * Description This function is the SMP callback handler. + * + *****************************************************************************/ +tBTM_STATUS btm_proc_smp_cback(tSMP_EVT event, const RawAddress& bd_addr, + const tSMP_EVT_DATA* p_data) { + LOG_VERBOSE("bd_addr:%s, event=%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + smp_evt_to_text(event).c_str()); + + if (event == SMP_SC_LOC_OOB_DATA_UP_EVT) { + btm_sec_cr_loc_oob_data_cback_event(RawAddress{}, p_data->loc_oob_data); + return BTM_SUCCESS; + } + + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + tBTM_STATUS res = BTM_SUCCESS; + + if (p_dev_rec != NULL) { + switch (event) { + case SMP_IO_CAP_REQ_EVT: + btm_ble_io_capabilities_req(p_dev_rec, + (tBTM_LE_IO_REQ*)&p_data->io_req); + break; + + case SMP_BR_KEYS_REQ_EVT: + btm_ble_br_keys_req(p_dev_rec, (tBTM_LE_IO_REQ*)&p_data->io_req); + break; + + case SMP_PASSKEY_REQ_EVT: + case SMP_PASSKEY_NOTIF_EVT: + case SMP_OOB_REQ_EVT: + case SMP_NC_REQ_EVT: + case SMP_SC_OOB_REQ_EVT: + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED; + FALLTHROUGH_INTENDED; /* FALLTHROUGH */ + + case SMP_CONSENT_REQ_EVT: + case SMP_SEC_REQUEST_EVT: + if (event == SMP_SEC_REQUEST_EVT && + btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) { + LOG_VERBOSE("Ignoring SMP Security request"); + break; + } + btm_sec_cb.pairing_bda = bd_addr; + if (event != SMP_CONSENT_REQ_EVT) { + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_AUTHENTICATING; + } + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE; + FALLTHROUGH_INTENDED; /* FALLTHROUGH */ + + case SMP_COMPLT_EVT: + if (btm_sec_cb.api.p_le_callback) { + /* the callback function implementation may change the IO + * capability... */ + LOG_VERBOSE("btm_sec_cb.api.p_le_callback=0x%p", + btm_sec_cb.api.p_le_callback); + (*btm_sec_cb.api.p_le_callback)(event, bd_addr, + (tBTM_LE_EVT_DATA*)p_data); + } + + if (event == SMP_COMPLT_EVT) { + p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec == NULL) { + LOG_ERROR("p_dev_rec is NULL"); + return BTM_SUCCESS; + } + LOG_VERBOSE("before update sec_level=0x%x sec_flags=0x%x", + p_data->cmplt.sec_level, p_dev_rec->sec_rec.sec_flags); + + res = (p_data->cmplt.reason == SMP_SUCCESS) ? BTM_SUCCESS + : BTM_ERR_PROCESSING; + + LOG_VERBOSE("after update result=%d sec_level=0x%x sec_flags=0x%x", + res, p_data->cmplt.sec_level, + p_dev_rec->sec_rec.sec_flags); + + if (p_data->cmplt.is_pair_cancel && + btm_sec_cb.api.p_bond_cancel_cmpl_callback) { + LOG_VERBOSE("Pairing Cancel completed"); + (*btm_sec_cb.api.p_bond_cancel_cmpl_callback)(BTM_SUCCESS); + } + + if (res != BTM_SUCCESS && p_data->cmplt.reason != SMP_CONN_TOUT) { + LOG_VERBOSE("Pairing failed - prepare to remove ACL"); + l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle); + } + + LOG_VERBOSE( + "btm_sec_cb.pairing_state=%x pairing_flags=%x pin_code_len=%x", + btm_sec_cb.pairing_state, btm_sec_cb.pairing_flags, + btm_sec_cb.pin_code_len); + + /* Reset btm state only if the callback address matches pairing + * address*/ + if (bd_addr == btm_sec_cb.pairing_bda) { + btm_sec_cb.pairing_bda = RawAddress::kAny; + btm_sec_cb.pairing_state = BTM_PAIR_STATE_IDLE; + btm_sec_cb.pairing_flags = 0; + } + + if (res == BTM_SUCCESS) { + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; + + if (p_dev_rec->sec_rec.bond_type != BOND_TYPE_TEMPORARY) { + // Add all bonded device into resolving list if IRK is available. + btm_ble_resolving_list_load_dev(*p_dev_rec); + } else if (p_dev_rec->ble_hci_handle == HCI_INVALID_HANDLE) { + // At this point LTK should have been dropped by btif. + // Reset the flags here if LE is not connected (over BR), + // otherwise they would be reset on disconnected. + LOG_DEBUG( + "SMP over BR triggered by temporary bond has completed," + " resetting the LK flags"); + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LE_LINK_KEY_KNOWN); + p_dev_rec->sec_rec.ble_keys.key_type = BTM_LE_KEY_NONE; + } + } + tBTM_BD_NAME remote_name = {}; + if (BTM_GetRemoteDeviceName(p_dev_rec->ble.pseudo_addr, + remote_name) && + interop_match_name(INTEROP_SUSPEND_ATT_TRAFFIC_DURING_PAIRING, + (const char*)remote_name)) { + LOG_DEBUG("Notifying encryption cmpl delayed due to IOP match"); + btm_ble_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr, true); + } + + btm_sec_dev_rec_cback_event(p_dev_rec, res, true); + } + break; + + case SMP_LE_ADDR_ASSOC_EVT: + if (btm_sec_cb.api.p_le_callback) { + LOG_VERBOSE("btm_sec_cb.api.p_le_callback=0x%p", + btm_sec_cb.api.p_le_callback); + (*btm_sec_cb.api.p_le_callback)(event, bd_addr, + (tBTM_LE_EVT_DATA*)p_data); + } + break; + + case SMP_SIRK_VERIFICATION_REQ_EVT: + res = (*btm_sec_cb.api.p_sirk_verification_callback)(bd_addr); + LOG_DEBUG("SMP SIRK verification result:%s", + btm_status_text(res).c_str()); + if (res != BTM_CMD_STARTED) { + return res; + } + + break; + + default: + LOG_VERBOSE("unknown event=%s", smp_evt_to_text(event).c_str()); + break; + } + } else { + LOG_WARN("Unexpected event '%s' for unknown device.", + smp_evt_to_text(event).c_str()); + } + + return BTM_SUCCESS; +} + +/******************************************************************************* + * + * Function BTM_BleDataSignature + * + * Description This function is called to sign the data using AES128 CMAC + * algorithm. + * + * Parameter bd_addr: target device the data to be signed for. + * p_text: singing data + * len: length of the data to be signed. + * signature: output parameter where data signature is going to + * be stored. + * + * Returns true if signing sucessul, otherwise false. + * + ******************************************************************************/ +bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text, + uint16_t len, BLE_SIGNATURE signature) { + tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr); + + if (p_rec == NULL) { + LOG_ERROR("data signing can not be done from unknown device"); + return false; + } + + uint8_t* p_mac = (uint8_t*)signature; + uint8_t* pp; + uint8_t* p_buf = (uint8_t*)osi_malloc(len + 4); + + pp = p_buf; + /* prepare plain text */ + if (p_text) { + memcpy(p_buf, p_text, len); + pp = (p_buf + len); + } + + UINT32_TO_STREAM(pp, p_rec->sec_rec.ble_keys.local_counter); + UINT32_TO_STREAM(p_mac, p_rec->sec_rec.ble_keys.local_counter); + + crypto_toolbox::aes_cmac(p_rec->sec_rec.ble_keys.lcsrk, p_buf, + (uint16_t)(len + 4), BTM_CMAC_TLEN_SIZE, p_mac); + p_rec->sec_rec.increment_sign_counter(true); + + LOG_VERBOSE("p_mac = %p", p_mac); + LOG_VERBOSE( + "p_mac[0]=0x%02x p_mac[1]=0x%02x p_mac[2]=0x%02x p_mac[3]=" + "0x%02x", + *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3)); + LOG_VERBOSE( + "p_mac[4]=0x%02x p_mac[5]=0x%02x p_mac[6]=0x%02x p_mac[7]=" + "0x%02x", + *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7)); + osi_free(p_buf); + return true; +} + +/******************************************************************************* + * + * Function BTM_BleVerifySignature + * + * Description This function is called to verify the data signature + * + * Parameter bd_addr: target device the data to be signed for. + * p_orig: original data before signature. + * len: length of the signing data + * counter: counter used when doing data signing + * p_comp: signature to be compared against. + + * Returns true if signature verified correctly; otherwise false. + * + ******************************************************************************/ +bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig, + uint16_t len, uint32_t counter, uint8_t* p_comp) { + bool verified = false; + tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr); + uint8_t p_mac[BTM_CMAC_TLEN_SIZE]; + + if (p_rec == NULL || + (p_rec && !(p_rec->sec_rec.ble_keys.key_type & BTM_LE_KEY_PCSRK))) { + LOG_ERROR("can not verify signature for unknown device"); + } else if (counter < p_rec->sec_rec.ble_keys.counter) { + LOG_ERROR("signature received with out dated sign counter"); + } else if (p_orig == NULL) { + LOG_ERROR("No signature to verify"); + } else { + LOG_VERBOSE("rcv_cnt=%d >= expected_cnt=%d", counter, + p_rec->sec_rec.ble_keys.counter); + + crypto_toolbox::aes_cmac(p_rec->sec_rec.ble_keys.pcsrk, p_orig, len, + BTM_CMAC_TLEN_SIZE, p_mac); + if (CRYPTO_memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) { + p_rec->sec_rec.increment_sign_counter(false); + verified = true; + } + } + return verified; +} + +/******************************************************************************* + * + * Function BTM_BleSirkConfirmDeviceReply + * + * Description This procedure confirms requested to validate set device. + * + * Parameter bd_addr - BD address of the peer + * res - confirmation result BTM_SUCCESS if success + * + * Returns void + * + ******************************************************************************/ +void BTM_BleSirkConfirmDeviceReply(const RawAddress& bd_addr, uint8_t res) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_FAIL; + + LOG_INFO("bd_addr:%s, result:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + smp_status_text(res_smp).c_str()); + + if (p_dev_rec == NULL) { + LOG_ERROR("Confirmation of Unknown device"); + return; + } + + BTM_LogHistory( + kBtmLogTag, bd_addr, "SIRK confirmation", + base::StringPrintf("status:%s", smp_status_text(res_smp).c_str())); + SMP_SirkConfirmDeviceReply(bd_addr, res_smp); +} + +/******************************************************************************* + * Utility functions for LE device IR/ER generation + ******************************************************************************/ +/** This function is to notify application new keys have been generated. */ +static void btm_notify_new_key(uint8_t key_type) { + tBTM_BLE_LOCAL_KEYS* p_local_keys = NULL; + + LOG_VERBOSE("key_type=%d", key_type); + + if (btm_sec_cb.api.p_le_key_callback) { + switch (key_type) { + case BTM_BLE_KEY_TYPE_ID: + LOG_VERBOSE("BTM_BLE_KEY_TYPE_ID"); + p_local_keys = (tBTM_BLE_LOCAL_KEYS*)&btm_sec_cb.devcb.id_keys; + break; + + case BTM_BLE_KEY_TYPE_ER: + LOG_VERBOSE("BTM_BLE_KEY_TYPE_ER"); + p_local_keys = + (tBTM_BLE_LOCAL_KEYS*)&btm_sec_cb.devcb.ble_encryption_key_value; + break; + + default: + LOG_ERROR("unknown key type: %d", key_type); + break; + } + if (p_local_keys != NULL) + (*btm_sec_cb.api.p_le_key_callback)(key_type, p_local_keys); + } +} + +/** implementation of btm_ble_reset_id */ +static void btm_ble_reset_id_impl(const Octet16& rand1, const Octet16& rand2) { + /* Regenerate Identity Root */ + btm_sec_cb.devcb.id_keys.ir = rand1; + Octet16 btm_ble_dhk_pt{}; + btm_ble_dhk_pt[0] = 0x03; + + /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */ + btm_sec_cb.devcb.id_keys.dhk = + crypto_toolbox::aes_128(btm_sec_cb.devcb.id_keys.ir, btm_ble_dhk_pt); + + Octet16 btm_ble_irk_pt{}; + btm_ble_irk_pt[0] = 0x01; + /* IRK = D1(IR, 1) */ + btm_sec_cb.devcb.id_keys.irk = + crypto_toolbox::aes_128(btm_sec_cb.devcb.id_keys.ir, btm_ble_irk_pt); + + btm_notify_new_key(BTM_BLE_KEY_TYPE_ID); + + /* if privacy is enabled, new RPA should be calculated */ + if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) { + btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low)); + } + + /* proceed generate ER */ + btm_sec_cb.devcb.ble_encryption_key_value = rand2; + btm_notify_new_key(BTM_BLE_KEY_TYPE_ER); + + /* if privacy is enabled, update the irk and RPA in the LE address manager */ + if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) { + BTM_BleConfigPrivacy(true); + } +} + +struct reset_id_data { + Octet16 rand1; + Octet16 rand2; +}; + +/** This function is called to reset LE device identity. */ +void btm_ble_reset_id(void) { + LOG_VERBOSE("btm_ble_reset_id"); + + /* In order to reset identity, we need four random numbers. Make four nested + * calls to generate them first, then proceed to perform the actual reset in + * btm_ble_reset_id_impl. */ + btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand) { + reset_id_data tmp; + memcpy(tmp.rand1.data(), rand, BT_OCTET8_LEN); + btsnd_hcic_ble_rand(base::Bind( + [](reset_id_data tmp, BT_OCTET8 rand) { + memcpy(tmp.rand1.data() + 8, rand, BT_OCTET8_LEN); + btsnd_hcic_ble_rand(base::Bind( + [](reset_id_data tmp, BT_OCTET8 rand) { + memcpy(tmp.rand2.data(), rand, BT_OCTET8_LEN); + btsnd_hcic_ble_rand(base::Bind( + [](reset_id_data tmp, BT_OCTET8 rand) { + memcpy(tmp.rand2.data() + 8, rand, BT_OCTET8_LEN); + // when all random numbers are ready, do the actual reset. + btm_ble_reset_id_impl(tmp.rand1, tmp.rand2); + }, + tmp)); + }, + tmp)); + }, + tmp)); + })); +} + +/******************************************************************************* + * + * Function btm_ble_get_acl_remote_addr + * + * Description This function reads the active remote address used for the + * connection. + * + * Returns success return true, otherwise false. + * + ******************************************************************************/ +bool btm_ble_get_acl_remote_addr(uint16_t hci_handle, RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle); + if (p_dev_rec == nullptr) { + LOG_WARN("Unable to find security device record hci_handle:%hu", + hci_handle); + // TODO Release acl resource + return false; + } + + bool st = true; + + switch (p_dev_rec->ble.active_addr_type) { + case BTM_BLE_ADDR_PSEUDO: + conn_addr = p_dev_rec->bd_addr; + *p_addr_type = p_dev_rec->ble.AddressType(); + break; + + case BTM_BLE_ADDR_RRA: + conn_addr = p_dev_rec->ble.cur_rand_addr; + *p_addr_type = BLE_ADDR_RANDOM; + break; + + case BTM_BLE_ADDR_STATIC: + conn_addr = p_dev_rec->ble.identity_address_with_type.bda; + *p_addr_type = p_dev_rec->ble.identity_address_with_type.type; + break; + + default: + LOG_WARN("Unable to find record with active address type:%d", + p_dev_rec->ble.active_addr_type); + st = false; + break; + } + return st; +} + +std::optional BTM_BleGetPeerLTK(const RawAddress address) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); + if (p_dev_rec == nullptr) { + return std::nullopt; + } + + return p_dev_rec->sec_rec.ble_keys.pltk; +} + +std::optional BTM_BleGetPeerIRK(const RawAddress address) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); + if (p_dev_rec == nullptr) { + return std::nullopt; + } + + return p_dev_rec->sec_rec.ble_keys.irk; +} + +bool BTM_BleIsLinkKeyKnown(const RawAddress address) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); + return p_dev_rec != nullptr && p_dev_rec->sec_rec.is_le_link_key_known(); +} + +std::optional BTM_BleGetIdentityAddress( + const RawAddress address) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); + if (p_dev_rec == nullptr) { + return std::nullopt; + } + + return p_dev_rec->ble.identity_address_with_type; +} diff --git a/system/stack/btm/btm_ble_sec.h b/system/stack/btm/btm_ble_sec.h new file mode 100644 index 0000000000000000000000000000000000000000..98edf6a5a8fe815c5a68ce78df65b38d9ab2c659 --- /dev/null +++ b/system/stack/btm/btm_ble_sec.h @@ -0,0 +1,74 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "macros.h" +#include "stack/include/btm_ble_sec_api_types.h" +#include "stack/include/btm_sec_api_types.h" +#include "stack/include/btm_status.h" +#include "types/raw_address.h" + +typedef enum : uint8_t { + BTM_BLE_SEC_REQ_ACT_NONE = 0, + /* encrypt the link using current key or key refresh */ + BTM_BLE_SEC_REQ_ACT_ENCRYPT = 1, + BTM_BLE_SEC_REQ_ACT_PAIR = 2, + /* discard the sec request while encryption is started but not completed */ + BTM_BLE_SEC_REQ_ACT_DISCARD = 3, +} tBTM_BLE_SEC_REQ_ACT; + +inline std::string btm_ble_sec_req_act_text(const tBTM_BLE_SEC_REQ_ACT action) { + switch (action) { + CASE_RETURN_TEXT(BTM_BLE_SEC_REQ_ACT_NONE); + CASE_RETURN_TEXT(BTM_BLE_SEC_REQ_ACT_ENCRYPT); + CASE_RETURN_TEXT(BTM_BLE_SEC_REQ_ACT_PAIR); + CASE_RETURN_TEXT(BTM_BLE_SEC_REQ_ACT_DISCARD); + default: + return "UNKNOWN ACTION"; + } +} +/* LE security function from btm_sec.cc */ +void btm_ble_link_sec_check(const RawAddress& bd_addr, + tBTM_LE_AUTH_REQ auth_req, + tBTM_BLE_SEC_REQ_ACT* p_sec_req_act); +void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk, + const Octet16& stk); +tBTM_STATUS btm_proc_smp_cback(tSMP_EVT event, const RawAddress& bd_addr, + const tSMP_EVT_DATA* p_data); +tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr, + tBTM_BLE_SEC_ACT sec_act, uint8_t link_role); +tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk, + Octet16* p_stk); +void btm_ble_link_encrypted(const RawAddress& bd_addr, uint8_t encr_enable); + +void btm_ble_reset_id(void); + +bool btm_get_local_div(const RawAddress& bd_addr, uint16_t* p_div); +bool btm_ble_get_enc_key_type(const RawAddress& bd_addr, uint8_t* p_key_types); + +void btm_sec_save_le_key(const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type, + tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application); +void btm_ble_update_sec_key_size(const RawAddress& bd_addr, + uint8_t enc_key_size); +uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr); + +tBTM_STATUS btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm, + bool is_originator, + tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data); diff --git a/system/stack/btm/btm_client_interface.cc b/system/stack/btm/btm_client_interface.cc index f97555f896f77464d0cd8ddf30fce19e99943a22..6b7950ba364ca7bc99e915d10b40da51949d47a0 100644 --- a/system/stack/btm/btm_client_interface.cc +++ b/system/stack/btm/btm_client_interface.cc @@ -16,24 +16,18 @@ #include "stack/include/btm_client_interface.h" -#include - -#include "main/shim/btm_api.h" -#include "stack/btm/btm_dev.h" +#include "security_client_callbacks.h" +#include "stack/btm/btm_ble_int.h" #include "stack/include/acl_api.h" #include "stack/include/btm_api.h" #include "stack/include/btm_ble_api.h" -#include "stack/include/btm_client_interface.h" -#include "stack/include/hci_error_code.h" -#include "types/bluetooth/uuid.h" -#include "types/bt_transport.h" -#include "types/raw_address.h" +#include "stack/include/btm_ble_sec_api.h" struct btm_client_interface_t btm_client_interface = { .lifecycle = { - .BTM_GetHCIConnHandle = BTM_GetHCIConnHandle, .BTM_PmRegister = BTM_PmRegister, + .BTM_GetHCIConnHandle = BTM_GetHCIConnHandle, .BTM_VendorSpecificCommand = BTM_VendorSpecificCommand, .ACL_RegisterClient = ACL_RegisterClient, .ACL_UnregisterClient = ACL_UnregisterClient, @@ -44,27 +38,6 @@ struct btm_client_interface_t btm_client_interface = { .BTM_reset_complete = BTM_reset_complete, }, - .scn = - { - .BTM_AllocateSCN = BTM_AllocateSCN, - .BTM_TryAllocateSCN = BTM_TryAllocateSCN, - .BTM_FreeSCN = BTM_FreeSCN, - }, - - .neighbor = - { - .BTM_CancelInquiry = BTM_CancelInquiry, - .BTM_ClearInqDb = BTM_ClearInqDb, - .BTM_InqDbNext = BTM_InqDbNext, - .BTM_SetConnectability = BTM_SetConnectability, - .BTM_SetDiscoverability = BTM_SetDiscoverability, - .BTM_StartInquiry = BTM_StartInquiry, - .BTM_IsInquiryActive = BTM_IsInquiryActive, - .BTM_SetInquiryMode = BTM_SetInquiryMode, - .BTM_EnableInterlacedInquiryScan = BTM_EnableInterlacedInquiryScan, - .BTM_EnableInterlacedPageScan = BTM_EnableInterlacedPageScan, - }, - // Acl peer and lifecycle .peer = { @@ -74,13 +47,13 @@ struct btm_client_interface_t btm_client_interface = { ACL_SupportTransparentSynchronousData, }, - .BTM_CancelRemoteDeviceName = BTM_CancelRemoteDeviceName, .BTM_IsAclConnectionUp = BTM_IsAclConnectionUp, .BTM_ReadConnectedTransportAddress = BTM_ReadConnectedTransportAddress, - .BTM_ReadDevInfo = BTM_ReadDevInfo, + .BTM_CancelRemoteDeviceName = BTM_CancelRemoteDeviceName, .BTM_ReadRemoteDeviceName = BTM_ReadRemoteDeviceName, .BTM_ReadRemoteFeatures = BTM_ReadRemoteFeatures, + .BTM_ReadDevInfo = BTM_ReadDevInfo, .BTM_GetMaxPacketSize = BTM_GetMaxPacketSize, .BTM_ReadRemoteVersion = BTM_ReadRemoteVersion, }, @@ -91,12 +64,12 @@ struct btm_client_interface_t btm_client_interface = { .BTM_SetPowerMode = BTM_SetPowerMode, .BTM_SetSsrParams = BTM_SetSsrParams, .BTM_SwitchRoleToCentral = BTM_SwitchRoleToCentral, - .BTM_WritePageTimeout = BTM_WritePageTimeout, .BTM_block_role_switch_for = BTM_block_role_switch_for, .BTM_block_sniff_mode_for = BTM_block_sniff_mode_for, .BTM_default_unblock_role_switch = BTM_default_unblock_role_switch, .BTM_unblock_role_switch_for = BTM_unblock_role_switch_for, .BTM_unblock_sniff_mode_for = BTM_unblock_sniff_mode_for, + .BTM_WritePageTimeout = BTM_WritePageTimeout, }, .link_controller = @@ -105,73 +78,50 @@ struct btm_client_interface_t btm_client_interface = { .BTM_ReadRSSI = BTM_ReadRSSI, }, - .security = - { - .BTM_ConfirmReqReply = BTM_ConfirmReqReply, - .BTM_PINCodeReply = BTM_PINCodeReply, - .BTM_RemoteOobDataReply = BTM_RemoteOobDataReply, - .BTM_SecAddBleDevice = BTM_SecAddBleDevice, - .BTM_SecAddBleKey = BTM_SecAddBleKey, - .BTM_SecAddDevice = BTM_SecAddDevice, - .BTM_SecAddRmtNameNotifyCallback = BTM_SecAddRmtNameNotifyCallback, - .BTM_SecBond = BTM_SecBond, - .BTM_SecBondCancel = BTM_SecBondCancel, - .BTM_SecClearSecurityFlags = BTM_SecClearSecurityFlags, - .BTM_SecClrService = BTM_SecClrService, - .BTM_SecClrServiceByPsm = BTM_SecClrServiceByPsm, - .BTM_SecDeleteDevice = BTM_SecDeleteDevice, - .BTM_SecDeleteRmtNameNotifyCallback = - BTM_SecDeleteRmtNameNotifyCallback, - .BTM_SecReadDevName = BTM_SecReadDevName, - .BTM_SecRegister = BTM_SecRegister, - .BTM_SetEncryption = BTM_SetEncryption, - .BTM_IsEncrypted = BTM_IsEncrypted, - .BTM_SecIsSecurityPending = BTM_SecIsSecurityPending, - .BTM_IsLinkKeyKnown = BTM_IsLinkKeyKnown, - }, + .security = get_security_client_interface(), .ble = { - .BTM_BleConfirmReply = BTM_BleConfirmReply, .BTM_BleGetEnergyInfo = BTM_BleGetEnergyInfo, - .BTM_BleLoadLocalKeys = BTM_BleLoadLocalKeys, .BTM_BleObserve = BTM_BleObserve, + .BTM_SetBleDataLength = BTM_SetBleDataLength, + .BTM_BleConfirmReply = BTM_BleConfirmReply, + .BTM_BleLoadLocalKeys = BTM_BleLoadLocalKeys, .BTM_BlePasskeyReply = BTM_BlePasskeyReply, .BTM_BleReadControllerFeatures = BTM_BleReadControllerFeatures, .BTM_BleSetPhy = BTM_BleSetPhy, .BTM_BleSetPrefConnParams = BTM_BleSetPrefConnParams, - .BTM_SetBleDataLength = BTM_SetBleDataLength, .BTM_UseLeLink = BTM_UseLeLink, }, .sco = { .BTM_CreateSco = BTM_CreateSco, - .BTM_EScoConnRsp = BTM_EScoConnRsp, - .BTM_GetNumScoLinks = BTM_GetNumScoLinks, .BTM_RegForEScoEvts = BTM_RegForEScoEvts, .BTM_RemoveSco = BTM_RemoveSco, - .BTM_SetEScoMode = BTM_SetEScoMode, .BTM_WriteVoiceSettings = BTM_WriteVoiceSettings, + .BTM_EScoConnRsp = BTM_EScoConnRsp, + .BTM_GetNumScoLinks = BTM_GetNumScoLinks, + .BTM_SetEScoMode = BTM_SetEScoMode, }, .local = { .BTM_ReadLocalDeviceNameFromController = BTM_ReadLocalDeviceNameFromController, - .BTM_SetDeviceClass = BTM_SetDeviceClass, .BTM_SetLocalDeviceName = BTM_SetLocalDeviceName, + .BTM_SetDeviceClass = BTM_SetDeviceClass, .BTM_IsDeviceUp = BTM_IsDeviceUp, .BTM_ReadDeviceClass = BTM_ReadDeviceClass, }, .eir = { + .BTM_WriteEIR = BTM_WriteEIR, .BTM_GetEirSupportedServices = BTM_GetEirSupportedServices, .BTM_GetEirUuidList = BTM_GetEirUuidList, .BTM_AddEirService = BTM_AddEirService, .BTM_RemoveEirService = BTM_RemoveEirService, - .BTM_WriteEIR = BTM_WriteEIR, }, .db = { diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc index 80d16af792e742e6801c1450b6fce95630f5ad45..ead44de7ff48b955c84caa9c74c7845da1aca71b 100644 --- a/system/stack/btm/btm_dev.cc +++ b/system/stack/btm/btm_dev.cc @@ -22,25 +22,29 @@ * ******************************************************************************/ +#define LOG_TAG "btm_dev" + #include "stack/btm/btm_dev.h" -#include -#include -#include -#include +#include #include "btm_api.h" -#include "btm_ble_int.h" +#include "btm_int_types.h" +#include "btm_sec_api.h" +#include "btm_sec_cb.h" +#include "common/init_flags.h" #include "device/include/controller.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" -#include "main/shim/btm_api.h" -#include "main/shim/dumpsys.h" -#include "main/shim/shim.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "rust/src/connection/ffi/connection_shim.h" +#include "stack/btm/btm_sec.h" #include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" +#include "stack/include/btm_ble_privacy.h" +#include "stack/include/btm_log_history.h" #include "types/raw_address.h" extern tBTM_CB btm_cb; @@ -52,6 +56,12 @@ constexpr char kBtmLogTag[] = "BOND"; } +static void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec) { + p_dev_rec->sec_rec.link_key.fill(0); + memset(&p_dev_rec->sec_rec.ble_keys, 0, sizeof(tBTM_SEC_BLE_KEYS)); + list_remove(btm_sec_cb.sec_dev_rec, p_dev_rec); +} + /******************************************************************************* * * Function BTM_SecAddDevice @@ -94,7 +104,7 @@ bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, ADDRESS_TO_LOGGABLE_CSTR(bd_addr), key_type); /* "Bump" timestamp for existing record */ - p_dev_rec->timestamp = btm_cb.dev_rec_count++; + p_dev_rec->timestamp = btm_sec_cb.dev_rec_count++; /* TODO(eisenbach): * Small refactor, but leaving original logic for now. @@ -102,7 +112,7 @@ bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, * bond state for an existing device here? This logic should be verified * as part of a larger refactor. */ - p_dev_rec->bond_type = tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN; + p_dev_rec->sec_rec.bond_type = BOND_TYPE_UNKNOWN; } if (dev_class) memcpy(p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN); @@ -112,39 +122,33 @@ bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, if (bd_name && bd_name[0]) { LOG_DEBUG(" Remote name known for device:%s name:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bd_name); - p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_NAME_KNOWN; strlcpy((char*)p_dev_rec->sec_bd_name, (char*)bd_name, BTM_MAX_REM_BD_NAME_LEN + 1); } if (p_link_key) { LOG_DEBUG(" Link key known for device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN; - p_dev_rec->link_key = *p_link_key; - p_dev_rec->link_key_type = key_type; - p_dev_rec->pin_code_length = pin_length; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LINK_KEY_KNOWN; + p_dev_rec->sec_rec.link_key = *p_link_key; + p_dev_rec->sec_rec.link_key_type = key_type; + p_dev_rec->sec_rec.pin_code_length = pin_length; if (pin_length >= 16 || key_type == BTM_LKEY_TYPE_AUTH_COMB || key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { // Set the flag if the link key was made by using either a 16 digit // pin or MITM. - p_dev_rec->sec_flags |= + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED | BTM_SEC_LINK_KEY_AUTHED; } } - p_dev_rec->rmt_io_caps = BTM_IO_CAP_OUT; + p_dev_rec->sec_rec.rmt_io_caps = BTM_IO_CAP_OUT; p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR; return true; } -void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec) { - p_dev_rec->link_key.fill(0); - memset(&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS)); - list_remove(btm_cb.sec_dev_rec, p_dev_rec); -} - /** Removes the device from acceptlist */ void BTM_AcceptlistRemove(const RawAddress& address); @@ -159,46 +163,51 @@ void BTM_AcceptlistRemove(const RawAddress& address); * Returns true if removed OK, false if not found or ACL link is active. */ bool BTM_SecDeleteDevice(const RawAddress& bd_addr) { - if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) || - BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR)) { - LOG_WARN("%s FAILED: Cannot Delete when connection to %s is active", - __func__, ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - return false; + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec == NULL) { + LOG_WARN("Unable to delete link key for unknown device %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return true; } - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec != NULL) { - RawAddress bda = p_dev_rec->bd_addr; + /* Invalidate bonded status */ + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN; + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_LE_LINK_KEY_KNOWN; - LOG_INFO("Remove device %s from filter accept list before delete record", + if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) || + BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR)) { + LOG_WARN("FAILED: Cannot Delete when connection to %s is active", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - if (bluetooth::common::init_flags:: - use_unified_connection_manager_is_enabled()) { - bluetooth::connection::GetConnectionManager() - .stop_all_connections_to_device( - bluetooth::connection::ResolveRawAddress(p_dev_rec->bd_addr)); - } else { - BTM_AcceptlistRemove(p_dev_rec->bd_addr); - } + return false; + } - const auto device_type = p_dev_rec->device_type; - const auto bond_type = p_dev_rec->bond_type; + RawAddress bda = p_dev_rec->bd_addr; - /* Clear out any saved BLE keys */ - btm_sec_clear_ble_keys(p_dev_rec); - wipe_secrets_and_remove(p_dev_rec); - /* Tell controller to get rid of the link key, if it has one stored */ - BTM_DeleteStoredLinkKey(&bda, NULL); - LOG_INFO("%s %s complete", __func__, ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - BTM_LogHistory(kBtmLogTag, bd_addr, "Device removed", - base::StringPrintf("device_type:%s bond_type:%s", - DeviceTypeText(device_type).c_str(), - bond_type_text(bond_type).c_str())); + LOG_INFO("Remove device %s from filter accept list before delete record", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + if (bluetooth::common::init_flags:: + use_unified_connection_manager_is_enabled()) { + bluetooth::connection::GetConnectionManager() + .stop_all_connections_to_device( + bluetooth::connection::ResolveRawAddress(p_dev_rec->bd_addr)); } else { - LOG_WARN("%s Unable to delete link key for unknown device %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + BTM_AcceptlistRemove(p_dev_rec->bd_addr); } + const auto device_type = p_dev_rec->device_type; + const auto bond_type = p_dev_rec->sec_rec.bond_type; + + /* Clear out any saved BLE keys */ + btm_sec_clear_ble_keys(p_dev_rec); + wipe_secrets_and_remove(p_dev_rec); + /* Tell controller to get rid of the link key, if it has one stored */ + BTM_DeleteStoredLinkKey(&bda, NULL); + LOG_INFO("%s complete", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + BTM_LogHistory(kBtmLogTag, bd_addr, "Device removed", + base::StringPrintf("device_type:%s bond_type:%s", + DeviceTypeText(device_type).c_str(), + bond_type_text(bond_type).c_str())); + return true; } @@ -214,8 +223,8 @@ void BTM_SecClearSecurityFlags(const RawAddress& bd_addr) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); if (p_dev_rec == NULL) return; - p_dev_rec->sec_flags = 0; - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->sec_rec.sec_flags = 0; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; p_dev_rec->sm4 = BTM_SM4_UNKNOWN; } @@ -229,12 +238,12 @@ void BTM_SecClearSecurityFlags(const RawAddress& bd_addr) { * Returns Pointer to the name or NULL * ******************************************************************************/ -char* BTM_SecReadDevName(const RawAddress& bd_addr) { - char* p_name = NULL; - tBTM_SEC_DEV_REC* p_srec; +const char* BTM_SecReadDevName(const RawAddress& bd_addr) { + const char* p_name = NULL; + const tBTM_SEC_DEV_REC* p_srec; p_srec = btm_find_dev(bd_addr); - if (p_srec != NULL) p_name = (char*)p_srec->sec_bd_name; + if (p_srec != NULL) p_name = (const char*)p_srec->sec_bd_name; return (p_name); } @@ -243,8 +252,9 @@ char* BTM_SecReadDevName(const RawAddress& bd_addr) { * * Function btm_sec_alloc_dev * - * Description Look for the record in the device database for the record - * with specified address + * Description Allocate a security device record with specified address, + * fill device type and device class from inquiry database or + * btm_sec_cb (if the address is the connecting device) * * Returns Pointer to the record or NULL * @@ -269,8 +279,8 @@ tBTM_SEC_DEV_REC* btm_sec_alloc_dev(const RawAddress& bd_addr) { LOG_WARN( "Please do not update device record from anonymous le advertisement"); - } else if (bd_addr == btm_cb.connecting_bda) - memcpy(p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN); + } else if (bd_addr == btm_sec_cb.connecting_bda) + memcpy(p_dev_rec->dev_class, btm_sec_cb.connecting_dc, DEV_CLASS_LEN); /* update conn params, use default value for background connection params */ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS)); @@ -298,39 +308,38 @@ tBTM_SEC_DEV_REC* btm_sec_alloc_dev(const RawAddress& bd_addr) { ******************************************************************************/ bool btm_dev_support_role_switch(const RawAddress& bd_addr) { if (BTM_IsScoActiveByBdaddr(bd_addr)) { - BTM_TRACE_DEBUG("%s Role switch is not allowed if a SCO is up", __func__); + LOG_VERBOSE("%s Role switch is not allowed if a SCO is up", __func__); return false; } tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); if (p_dev_rec == nullptr) { - BTM_TRACE_DEBUG("%s Unknown address for role switch", __func__); + LOG_VERBOSE("%s Unknown address for role switch", __func__); return false; } if (!controller_get_interface()->supports_central_peripheral_role_switch()) { - BTM_TRACE_DEBUG("%s Local controller does not support role switch", - __func__); + LOG_VERBOSE("%s Local controller does not support role switch", __func__); return false; } if (p_dev_rec->remote_supports_hci_role_switch) { - BTM_TRACE_DEBUG("%s Peer controller supports role switch", __func__); + LOG_VERBOSE("%s Peer controller supports role switch", __func__); return true; } if (!p_dev_rec->remote_feature_received) { - BTM_TRACE_DEBUG( + LOG_VERBOSE( "%s Unknown peer capabilities, assuming peer supports role switch", __func__); return true; } - BTM_TRACE_DEBUG("%s Peer controller does not support role switch", __func__); + LOG_VERBOSE("%s Peer controller does not support role switch", __func__); return false; } -bool is_handle_equal(void* data, void* context) { +static bool is_handle_equal(void* data, void* context) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(data); uint16_t* handle = static_cast(context); @@ -351,13 +360,14 @@ bool is_handle_equal(void* data, void* context) { * ******************************************************************************/ tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle) { - list_node_t* n = list_foreach(btm_cb.sec_dev_rec, is_handle_equal, &handle); + list_node_t* n = + list_foreach(btm_sec_cb.sec_dev_rec, is_handle_equal, &handle); if (n) return static_cast(list_node(n)); return NULL; } -bool is_address_equal(void* data, void* context) { +static bool is_address_equal(void* data, void* context) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(data); const RawAddress* bd_addr = ((RawAddress*)context); @@ -380,10 +390,10 @@ bool is_address_equal(void* data, void* context) { * ******************************************************************************/ tBTM_SEC_DEV_REC* btm_find_dev(const RawAddress& bd_addr) { - if (btm_cb.sec_dev_rec == nullptr) return nullptr; + if (btm_sec_cb.sec_dev_rec == nullptr) return nullptr; list_node_t* n = - list_foreach(btm_cb.sec_dev_rec, is_address_equal, (void*)&bd_addr); + list_foreach(btm_sec_cb.sec_dev_rec, is_address_equal, (void*)&bd_addr); if (n) return static_cast(list_node(n)); return NULL; @@ -391,7 +401,7 @@ tBTM_SEC_DEV_REC* btm_find_dev(const RawAddress& bd_addr) { static bool has_lenc_and_address_is_equal(void* data, void* context) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(data); - if (!(p_dev_rec->ble.key_type & BTM_LE_KEY_LENC)) return true; + if (!(p_dev_rec->sec_rec.ble_keys.key_type & BTM_LE_KEY_LENC)) return true; return is_address_equal(data, context); } @@ -407,10 +417,10 @@ static bool has_lenc_and_address_is_equal(void* data, void* context) { * ******************************************************************************/ tBTM_SEC_DEV_REC* btm_find_dev_with_lenc(const RawAddress& bd_addr) { - if (btm_cb.sec_dev_rec == nullptr) return nullptr; + if (btm_sec_cb.sec_dev_rec == nullptr) return nullptr; - list_node_t* n = list_foreach(btm_cb.sec_dev_rec, has_lenc_and_address_is_equal, - (void*)&bd_addr); + list_node_t* n = list_foreach(btm_sec_cb.sec_dev_rec, + has_lenc_and_address_is_equal, (void*)&bd_addr); if (n) return static_cast(list_node(n)); return NULL; @@ -418,7 +428,7 @@ tBTM_SEC_DEV_REC* btm_find_dev_with_lenc(const RawAddress& bd_addr) { /******************************************************************************* * * Function btm_consolidate_dev -5** + * * Description combine security records if identified as same peer * * Returns none @@ -427,10 +437,10 @@ tBTM_SEC_DEV_REC* btm_find_dev_with_lenc(const RawAddress& bd_addr) { void btm_consolidate_dev(tBTM_SEC_DEV_REC* p_target_rec) { tBTM_SEC_DEV_REC temp_rec = *p_target_rec; - BTM_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); - list_node_t* end = list_end(btm_cb.sec_dev_rec); - list_node_t* node = list_begin(btm_cb.sec_dev_rec); + list_node_t* end = list_end(btm_sec_cb.sec_dev_rec); + list_node_t* node = list_begin(btm_sec_cb.sec_dev_rec); while (node != end) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(list_node(node)); @@ -443,15 +453,16 @@ void btm_consolidate_dev(tBTM_SEC_DEV_REC* p_target_rec) { if (p_dev_rec->bd_addr == p_target_rec->bd_addr) { memcpy(p_target_rec, p_dev_rec, sizeof(tBTM_SEC_DEV_REC)); p_target_rec->ble = temp_rec.ble; + p_target_rec->sec_rec.ble_keys = temp_rec.sec_rec.ble_keys; p_target_rec->ble_hci_handle = temp_rec.ble_hci_handle; - p_target_rec->enc_key_size = temp_rec.enc_key_size; + p_target_rec->sec_rec.enc_key_size = temp_rec.sec_rec.enc_key_size; p_target_rec->conn_params = temp_rec.conn_params; p_target_rec->device_type |= temp_rec.device_type; - p_target_rec->sec_flags |= temp_rec.sec_flags; + p_target_rec->sec_rec.sec_flags |= temp_rec.sec_rec.sec_flags; - p_target_rec->new_encryption_key_is_p256 = - temp_rec.new_encryption_key_is_p256; - p_target_rec->bond_type = temp_rec.bond_type; + p_target_rec->sec_rec.new_encryption_key_is_p256 = + temp_rec.sec_rec.new_encryption_key_is_p256; + p_target_rec->sec_rec.bond_type = temp_rec.sec_rec.bond_type; /* remove the combined record */ wipe_secrets_and_remove(p_dev_rec); @@ -472,7 +483,7 @@ void btm_consolidate_dev(tBTM_SEC_DEV_REC* p_target_rec) { } } -BTM_CONSOLIDATION_CB* btm_consolidate_cb = nullptr; +static BTM_CONSOLIDATION_CB* btm_consolidate_cb = nullptr; void BTM_SetConsolidationCallback(BTM_CONSOLIDATION_CB* cb) { btm_consolidate_cb = cb; @@ -494,8 +505,8 @@ void btm_dev_consolidate_existing_connections(const RawAddress& bd_addr) { LOG_INFO("%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - list_node_t* end = list_end(btm_cb.sec_dev_rec); - list_node_t* node = list_begin(btm_cb.sec_dev_rec); + list_node_t* end = list_end(btm_sec_cb.sec_dev_rec); + list_node_t* node = list_begin(btm_sec_cb.sec_dev_rec); while (node != end) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(list_node(node)); @@ -545,14 +556,15 @@ void btm_dev_consolidate_existing_connections(const RawAddress& bd_addr) { * Function btm_find_or_alloc_dev * * Description Look for the record in the device database for the record - * with specified BD address + * with specified BD address, if not found, allocate a new + * record * * Returns Pointer to the record or NULL * ******************************************************************************/ tBTM_SEC_DEV_REC* btm_find_or_alloc_dev(const RawAddress& bd_addr) { tBTM_SEC_DEV_REC* p_dev_rec; - BTM_TRACE_EVENT("btm_find_or_alloc_dev"); + LOG_VERBOSE("btm_find_or_alloc_dev"); p_dev_rec = btm_find_dev(bd_addr); if (p_dev_rec == NULL) { /* Allocate a new device record or reuse the oldest one */ @@ -565,7 +577,7 @@ tBTM_SEC_DEV_REC* btm_find_or_alloc_dev(const RawAddress& bd_addr) { * * Function btm_find_oldest_dev_rec * - * Description Locates the oldest device in use. It first looks for + * Description Locates the oldest device record in use. It first looks for * the oldest non-paired device. If all devices are paired it * returns the oldest paired device. * @@ -578,13 +590,13 @@ static tBTM_SEC_DEV_REC* btm_find_oldest_dev_rec(void) { tBTM_SEC_DEV_REC* p_oldest_paired = NULL; uint32_t ts_oldest_paired = 0xFFFFFFFF; - list_node_t* end = list_end(btm_cb.sec_dev_rec); - for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end; + list_node_t* end = list_end(btm_sec_cb.sec_dev_rec); + for (list_node_t* node = list_begin(btm_sec_cb.sec_dev_rec); node != end; node = list_next(node)) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(list_node(node)); - if ((p_dev_rec->sec_flags & + if ((p_dev_rec->sec_rec.sec_flags & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN)) == 0) { // Device is not paired if (p_dev_rec->timestamp < ts_oldest) { @@ -621,20 +633,20 @@ static tBTM_SEC_DEV_REC* btm_find_oldest_dev_rec(void) { tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void) { tBTM_SEC_DEV_REC* p_dev_rec = NULL; - if (list_length(btm_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS) { + if (list_length(btm_sec_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS) { p_dev_rec = btm_find_oldest_dev_rec(); wipe_secrets_and_remove(p_dev_rec); } p_dev_rec = static_cast(osi_calloc(sizeof(tBTM_SEC_DEV_REC))); - list_append(btm_cb.sec_dev_rec, p_dev_rec); + list_append(btm_sec_cb.sec_dev_rec, p_dev_rec); // Initialize defaults - p_dev_rec->sec_flags = BTM_SEC_IN_USE; - p_dev_rec->bond_type = tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN; - p_dev_rec->timestamp = btm_cb.dev_rec_count++; - p_dev_rec->rmt_io_caps = BTM_IO_CAP_UNKNOWN; + p_dev_rec->sec_rec.sec_flags = BTM_SEC_IN_USE; + p_dev_rec->sec_rec.bond_type = BOND_TYPE_UNKNOWN; + p_dev_rec->timestamp = btm_sec_cb.dev_rec_count++; + p_dev_rec->sec_rec.rmt_io_caps = BTM_IO_CAP_UNKNOWN; p_dev_rec->suggested_tx_octets = 0; return p_dev_rec; @@ -650,13 +662,12 @@ tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void) { * Returns The device bond type if known, otherwise BOND_TYPE_UNKNOWN * ******************************************************************************/ -tBTM_SEC_DEV_REC::tBTM_BOND_TYPE btm_get_bond_type_dev( - const RawAddress& bd_addr) { +tBTM_BOND_TYPE btm_get_bond_type_dev(const RawAddress& bd_addr) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec == NULL) return tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN; + if (p_dev_rec == NULL) return BOND_TYPE_UNKNOWN; - return p_dev_rec->bond_type; + return p_dev_rec->sec_rec.bond_type; } /******************************************************************************* @@ -670,12 +681,12 @@ tBTM_SEC_DEV_REC::tBTM_BOND_TYPE btm_get_bond_type_dev( * ******************************************************************************/ bool btm_set_bond_type_dev(const RawAddress& bd_addr, - tBTM_SEC_DEV_REC::tBTM_BOND_TYPE bond_type) { + tBTM_BOND_TYPE bond_type) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); if (p_dev_rec == NULL) return false; - p_dev_rec->bond_type = bond_type; + p_dev_rec->sec_rec.bond_type = bond_type; return true; } @@ -683,16 +694,16 @@ bool btm_set_bond_type_dev(const RawAddress& bd_addr, * * Function btm_get_sec_dev_rec * - * Description Get security device records satisfying given filter + * Description Get all security device records * - * Returns A vector containing pointers of security device records + * Returns A vector containing pointers to all security device records * ******************************************************************************/ std::vector btm_get_sec_dev_rec() { std::vector result{}; - list_node_t* end = list_end(btm_cb.sec_dev_rec); - for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end; + list_node_t* end = list_end(btm_sec_cb.sec_dev_rec); + for (list_node_t* node = list_begin(btm_sec_cb.sec_dev_rec); node != end; node = list_next(node)) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(list_node(node)); @@ -700,3 +711,97 @@ std::vector btm_get_sec_dev_rec() { } return result; } + +/******************************************************************************* + * + * Function BTM_Sec_AddressKnown + * + * Description Query the secure device database and check + * whether the device associated with address has + * its address resolved + * + * Returns True if + * - the device is unknown, or + * - the device is classic, or + * - the device is ble and has a public address + * - the device is ble with a resolved identity address + * False, otherwise + * + ******************************************************************************/ +bool BTM_Sec_AddressKnown(const RawAddress& address) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address); + + // not a known device, or a classic device, we assume public address + if (p_dev_rec == NULL || (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == 0) + return true; + + LOG_WARN("%s, device type not BLE: 0x%02x", ADDRESS_TO_LOGGABLE_CSTR(address), + p_dev_rec->device_type); + + // bonded device with identity address known + if (!p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { + return true; + } + + // Public address, Random Static, or Random Non-Resolvable Address known + if (p_dev_rec->ble.AddressType() == BLE_ADDR_PUBLIC || + !BTM_BLE_IS_RESOLVE_BDA(address)) { + return true; + } + + LOG_WARN("%s, the address type is 0x%02x", ADDRESS_TO_LOGGABLE_CSTR(address), + p_dev_rec->ble.AddressType()); + + // Only Resolvable Private Address (RPA) is known, we don't allow it into + // the background connection procedure. + return false; +} + +const tBLE_BD_ADDR BTM_Sec_GetAddressWithType(const RawAddress& bd_addr) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec == nullptr || !p_dev_rec->is_device_type_has_ble()) { + return { + .type = BLE_ADDR_PUBLIC, + .bda = bd_addr, + }; + } + + if (p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { + return { + .type = p_dev_rec->ble.AddressType(), + .bda = bd_addr, + }; + } else { + // Floss doesn't support LL Privacy (yet). To expedite ARC testing, always + // connect to the latest LE random address (if available and LL Privacy is + // not enabled) rather than redesign. + // TODO(b/235218533): Remove when LL Privacy is implemented. +#if TARGET_FLOSS + if (!p_dev_rec->ble.cur_rand_addr.IsEmpty() && + btm_cb.ble_ctr_cb.privacy_mode < BTM_PRIVACY_1_2) { + return { + .type = BLE_ADDR_RANDOM, + .bda = p_dev_rec->ble.cur_rand_addr, + }; + } +#endif + return p_dev_rec->ble.identity_address_with_type; + } +} + +bool BTM_IsRemoteNameKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + return (p_dev_rec == nullptr) ? false : p_dev_rec->sec_rec.is_name_known(); +} + +namespace bluetooth { +namespace testing { +namespace legacy { + +void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec) { + ::wipe_secrets_and_remove(p_dev_rec); +} + +} // namespace legacy +} // namespace testing +} // namespace bluetooth diff --git a/system/stack/btm/btm_dev.h b/system/stack/btm/btm_dev.h index 84d73e721361c93934c952864e15cac45c08479f..424d865199edd97e8fc65a4e26df3582b7d3f9ab 100644 --- a/system/stack/btm/btm_dev.h +++ b/system/stack/btm/btm_dev.h @@ -14,17 +14,12 @@ * limitations under the License. */ -#include +#pragma once -#include "osi/include/log.h" -#include "stack/btm/btm_ble_int.h" #include "stack/btm/security_device_record.h" -#include "stack/include/acl_api.h" -#include "stack/include/bt_octets.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" -void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec); - /** Free resources associated with the device associated with |bd_addr| address. * * *** WARNING *** @@ -57,13 +52,13 @@ void BTM_SecClearSecurityFlags(const RawAddress& bd_addr); * Returns Pointer to the name or NULL * ******************************************************************************/ -char* BTM_SecReadDevName(const RawAddress& bd_addr); +const char* BTM_SecReadDevName(const RawAddress& bd_addr); /******************************************************************************* * * Function btm_sec_alloc_dev * - * Description Look for the record in the device database for the record + * Description Allocate a record in the device database * with specified address * * Returns Pointer to the record or NULL @@ -97,8 +92,6 @@ bool btm_dev_support_role_switch(const RawAddress& bd_addr); ******************************************************************************/ tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle); -bool is_address_equal(void* data, void* context); - /******************************************************************************* * * Function btm_find_dev @@ -184,8 +177,7 @@ tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void); * Returns The device bond type if known, otherwise BOND_TYPE_UNKNOWN * ******************************************************************************/ -tBTM_SEC_DEV_REC::tBTM_BOND_TYPE btm_get_bond_type_dev( - const RawAddress& bd_addr); +tBTM_BOND_TYPE btm_get_bond_type_dev(const RawAddress& bd_addr); /******************************************************************************* * @@ -197,8 +189,7 @@ tBTM_SEC_DEV_REC::tBTM_BOND_TYPE btm_get_bond_type_dev( * Returns true on success, otherwise false * ******************************************************************************/ -bool btm_set_bond_type_dev(const RawAddress& bd_addr, - tBTM_SEC_DEV_REC::tBTM_BOND_TYPE bond_type); +bool btm_set_bond_type_dev(const RawAddress& bd_addr, tBTM_BOND_TYPE bond_type); /******************************************************************************* * @@ -210,3 +201,8 @@ bool btm_set_bond_type_dev(const RawAddress& bd_addr, * ******************************************************************************/ std::vector btm_get_sec_dev_rec(); + +bool BTM_Sec_AddressKnown(const RawAddress& address); +const tBLE_BD_ADDR BTM_Sec_GetAddressWithType(const RawAddress& bd_addr); + +bool BTM_IsRemoteNameKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport); diff --git a/system/stack/btm/btm_devctl.cc b/system/stack/btm/btm_devctl.cc index f41d1d52193798bf790473eaeda17f4e3f9d8384..61a208b246dc2abd22cba5be0ac3d2231e9c35f8 100644 --- a/system/stack/btm/btm_devctl.cc +++ b/system/stack/btm/btm_devctl.cc @@ -23,28 +23,27 @@ * ******************************************************************************/ +#define LOG_TAG "devctl" #include #include #include #include -#include "bta/dm/bta_dm_int.h" -#include "bta/sys/bta_sys.h" -#include "btcore/include/module.h" +#include "acl_api_types.h" #include "btif/include/btif_bqr.h" -#include "common/message_loop_thread.h" -#include "hci/include/hci_layer.h" +#include "btm_sec_cb.h" +#include "btm_sec_int_types.h" +#include "internal_include/bt_target.h" #include "main/shim/btm_api.h" -#include "main/shim/controller.h" -#include "main/shim/entry.h" -#include "main/shim/hci_layer.h" -#include "main/shim/shim.h" -#include "osi/include/compat.h" -#include "osi/include/osi.h" -#include "stack/btm/btm_ble_int.h" +#include "os/log.h" +#include "stack/btm/btm_int_types.h" +#include "stack/btm/btm_sec.h" #include "stack/gatt/connection_manager.h" #include "stack/include/acl_api.h" -#include "stack/include/bt_hdr.h" +#include "stack/include/acl_api_types.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_api.h" +#include "stack/include/btm_ble_privacy.h" #include "stack/include/l2cap_controller_interface.h" #include "types/raw_address.h" @@ -86,7 +85,7 @@ static void BTM_BT_Quality_Report_VSE_CBack(uint8_t length, ******************************************************************************/ void btm_dev_init() { /* Initialize nonzero defaults */ - memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME)); + memset(btm_sec_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME)); btm_cb.devcb.read_local_name_timer = alarm_new("btm.read_local_name_timer"); btm_cb.devcb.read_rssi_timer = alarm_new("btm.read_rssi_timer"); @@ -163,7 +162,7 @@ void BTM_db_reset(void) { static bool set_sec_state_idle(void* data, void* context) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(data); - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; return true; } @@ -174,7 +173,7 @@ void BTM_reset_complete() { l2cu_device_reset(); /* Clear current security state */ - list_foreach(btm_cb.sec_dev_rec, set_sec_state_idle, NULL); + list_foreach(btm_sec_cb.sec_dev_rec, set_sec_state_idle, NULL); /* After the reset controller should restore all parameters to defaults. */ btm_cb.btm_inq_vars.inq_counter = 1; @@ -212,8 +211,8 @@ void BTM_reset_complete() { l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble()); } - BTM_SetPinType(btm_cb.cfg.pin_type, btm_cb.cfg.pin_code, - btm_cb.cfg.pin_code_len); + BTM_SetPinType(btm_sec_cb.cfg.pin_type, btm_sec_cb.cfg.pin_code, + btm_sec_cb.cfg.pin_code_len); decode_controller_support(); } @@ -290,8 +289,8 @@ static void decode_controller_support() { } } - BTM_TRACE_DEBUG("Local supported SCO packet types: 0x%04x", - btm_cb.btm_sco_pkt_types_supported); + LOG_VERBOSE("Local supported SCO packet types: 0x%04x", + btm_cb.btm_sco_pkt_types_supported); BTM_acl_after_controller_started(controller_get_interface()); btm_sec_dev_reset(); @@ -325,9 +324,9 @@ tBTM_STATUS BTM_SetLocalDeviceName(const char* p_name) { if (!controller_get_interface()->get_is_ready()) return (BTM_DEV_RESET); /* Save the device name if local storage is enabled */ - p = (uint8_t*)btm_cb.cfg.bd_name; + p = (uint8_t*)btm_sec_cb.cfg.bd_name; if (p != (uint8_t*)p_name) - strlcpy((char*)btm_cb.cfg.bd_name, p_name, BTM_MAX_LOC_BD_NAME_LEN + 1); + strlcpy((char*)btm_sec_cb.cfg.bd_name, p_name, BTM_MAX_LOC_BD_NAME_LEN + 1); btsnd_hcic_change_name(p); return (BTM_CMD_STARTED); @@ -347,7 +346,7 @@ tBTM_STATUS BTM_SetLocalDeviceName(const char* p_name) { * ******************************************************************************/ tBTM_STATUS BTM_ReadLocalDeviceName(const char** p_name) { - *p_name = (const char*)btm_cb.cfg.bd_name; + *p_name = (const char*)btm_sec_cb.cfg.bd_name; return (BTM_SUCCESS); } @@ -453,41 +452,11 @@ uint8_t* BTM_ReadDeviceClass(void) { ******************************************************************************/ void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len, uint8_t* p_param_buf, tBTM_VSC_CMPL_CB* p_cb) { - /* Allocate a buffer to hold HCI command plus the callback function */ - void* p_buf = osi_malloc(sizeof(BT_HDR) + sizeof(tBTM_CMPL_CB*) + param_len + - HCIC_PREAMBLE_SIZE); - - BTM_TRACE_EVENT("BTM: %s: Opcode: 0x%04X, ParamLen: %i.", __func__, opcode, - param_len); + LOG_VERBOSE("BTM: %s: Opcode: 0x%04X, ParamLen: %i.", __func__, opcode, + param_len); /* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */ - btsnd_hcic_vendor_spec_cmd(p_buf, opcode, param_len, p_param_buf, - (void*)p_cb); -} - -/******************************************************************************* - * - * Function btm_vsc_complete - * - * Description This function is called when local HCI Vendor Specific - * Command complete message is received from the HCI. - * - * Returns void - * - ******************************************************************************/ -void btm_vsc_complete(uint8_t* p, uint16_t opcode, uint16_t evt_len, - tBTM_VSC_CMPL_CB* p_vsc_cplt_cback) { - tBTM_VSC_CMPL vcs_cplt_params; - - /* If there was a callback address for vcs complete, call it */ - if (p_vsc_cplt_cback) { - /* Pass paramters to the callback function */ - vcs_cplt_params.opcode = opcode; /* Number of bytes in return info */ - vcs_cplt_params.param_len = evt_len; /* Number of bytes in return info */ - vcs_cplt_params.p_param_buf = p; - (*p_vsc_cplt_cback)( - &vcs_cplt_params); /* Call the VSC complete callback function */ - } + btsnd_hcic_vendor_spec_cmd(opcode, param_len, p_param_buf, p_cb); } /******************************************************************************* @@ -518,7 +487,7 @@ tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* p_cb, bool is_register) { /* Found callback in lookup table. If deregistering, clear the entry. */ if (!is_register) { btm_cb.devcb.p_vend_spec_cb[i] = NULL; - BTM_TRACE_EVENT("BTM Deregister For VSEvents is successfully"); + LOG_VERBOSE("BTM Deregister For VSEvents is successfully"); } return (BTM_SUCCESS); } @@ -528,10 +497,10 @@ tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* p_cb, bool is_register) { if (is_register) { if (free_idx < BTM_MAX_VSE_CALLBACKS) { btm_cb.devcb.p_vend_spec_cb[free_idx] = p_cb; - BTM_TRACE_EVENT("BTM Register For VSEvents is successfully"); + LOG_VERBOSE("BTM Register For VSEvents is successfully"); } else { /* No free entries available */ - BTM_TRACE_ERROR("BTM_RegisterForVSEvents: too many callbacks registered"); + LOG_ERROR("BTM_RegisterForVSEvents: too many callbacks registered"); retval = BTM_NO_RESOURCES; } @@ -552,7 +521,7 @@ tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* p_cb, bool is_register) { void btm_vendor_specific_evt(const uint8_t* p, uint8_t evt_len) { uint8_t i; - BTM_TRACE_DEBUG("BTM Event: Vendor Specific event from controller"); + LOG_VERBOSE("BTM Event: Vendor Specific event from controller"); // Handle BQR events const uint8_t* bqr_ptr = p; @@ -611,7 +580,7 @@ void btm_vendor_specific_evt(const uint8_t* p, uint8_t evt_len) { * ******************************************************************************/ void BTM_WritePageTimeout(uint16_t timeout) { - BTM_TRACE_EVENT("BTM: BTM_WritePageTimeout: Timeout: %d.", timeout); + LOG_VERBOSE("BTM: BTM_WritePageTimeout: Timeout: %d.", timeout); /* Send the HCI command */ btsnd_hcic_write_page_tout(timeout); @@ -626,12 +595,56 @@ void BTM_WritePageTimeout(uint16_t timeout) { * ******************************************************************************/ void BTM_WriteVoiceSettings(uint16_t settings) { - BTM_TRACE_EVENT("BTM: BTM_WriteVoiceSettings: Settings: 0x%04x.", settings); + LOG_VERBOSE("BTM: BTM_WriteVoiceSettings: Settings: 0x%04x.", settings); /* Send the HCI command */ btsnd_hcic_write_voice_settings((uint16_t)(settings & 0x03ff)); } +/******************************************************************************* + * + * Function BTM_EnableTestMode + * + * Description Send HCI the enable device under test command. + * + * Note: Controller can only be taken out of this mode by + * resetting the controller. + * + * Returns + * BTM_SUCCESS Command sent. + * BTM_NO_RESOURCES If out of resources to send the command. + * + * + ******************************************************************************/ +tBTM_STATUS BTM_EnableTestMode(void) { + uint8_t cond; + + LOG_VERBOSE("BTM: BTM_EnableTestMode"); + + /* set auto accept connection as this is needed during test mode */ + /* Allocate a buffer to hold HCI command */ + cond = HCI_DO_AUTO_ACCEPT_CONNECT; + btsnd_hcic_set_event_filter(HCI_FILTER_CONNECTION_SETUP, + HCI_FILTER_COND_NEW_DEVICE, &cond, sizeof(cond)); + + /* put device to connectable mode */ + if (BTM_SetConnectability(BTM_CONNECTABLE) != BTM_SUCCESS) { + return BTM_NO_RESOURCES; + } + + /* put device to discoverable mode */ + if (BTM_SetDiscoverability(BTM_GENERAL_DISCOVERABLE) != BTM_SUCCESS) { + return BTM_NO_RESOURCES; + } + + /* mask off all of event from controller */ + bluetooth::shim::BTM_ClearEventMask(); + + /* Send the HCI command */ + btsnd_hcic_enable_test_mode(); + return (BTM_SUCCESS); +} + /******************************************************************************* * * Function BTM_DeleteStoredLinkKey @@ -653,14 +666,14 @@ tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* bd_addr, */ #if !defined(TARGET_FLOSS) /* Check if the previous command is completed */ - if (btm_cb.devcb.p_stored_link_key_cmpl_cb) return (BTM_BUSY); + if (btm_sec_cb.devcb.p_stored_link_key_cmpl_cb) return (BTM_BUSY); bool delete_all_flag = !bd_addr; - BTM_TRACE_EVENT("BTM: BTM_DeleteStoredLinkKey: delete_all_flag: %s", - delete_all_flag ? "true" : "false"); + LOG_VERBOSE("BTM: BTM_DeleteStoredLinkKey: delete_all_flag: %s", + delete_all_flag ? "true" : "false"); - btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb; + btm_sec_cb.devcb.p_stored_link_key_cmpl_cb = p_cb; if (!bd_addr) { /* This is to delete all link keys */ /* We don't care the BD address. Just pass a non zero pointer */ @@ -686,11 +699,11 @@ tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* bd_addr, * ******************************************************************************/ void btm_delete_stored_link_key_complete(uint8_t* p, uint16_t evt_len) { - tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb; + tBTM_CMPL_CB* p_cb = btm_sec_cb.devcb.p_stored_link_key_cmpl_cb; tBTM_DELETE_STORED_LINK_KEY_COMPLETE result; /* If there was a callback registered for read stored link key, call it */ - btm_cb.devcb.p_stored_link_key_cmpl_cb = NULL; + btm_sec_cb.devcb.p_stored_link_key_cmpl_cb = NULL; if (p_cb) { /* Set the call back event to indicate command complete */ diff --git a/system/stack/btm/btm_inq.cc b/system/stack/btm/btm_inq.cc index 27621304525cad07dbd5d76d0c8406072c7bede5..9245f7a421d5aeb08b4b27522fe10fc019a85cae 100644 --- a/system/stack/btm/btm_inq.cc +++ b/system/stack/btm/btm_inq.cc @@ -36,28 +36,55 @@ #include #include "advertise_data_parser.h" +#include "btif/include/btif_config.h" #include "common/time_util.h" #include "device/include/controller.h" -#include "main/shim/btm_api.h" +#include "internal_include/bt_target.h" #include "main/shim/shim.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "osi/include/properties.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_dev.h" +#include "osi/include/stack_power_telemetry.h" #include "stack/btm/btm_int_types.h" +#include "stack/btm/btm_sec.h" #include "stack/include/acl_api.h" +#include "stack/include/acl_api_types.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_lap.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_api.h" #include "stack/include/btm_ble_api.h" +#include "stack/include/btm_log_history.h" +#include "stack/include/hcimsgs.h" #include "stack/include/inq_hci_link_interface.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +/* MACRO to set the service bit mask in a bit stream */ +#define BTM_EIR_SET_SERVICE(p, service) \ + (((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] |= \ + ((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) + +/* MACRO to clear the service bit mask in a bit stream */ +#define BTM_EIR_CLR_SERVICE(p, service) \ + (((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] &= \ + ~((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) + +/* MACRO to check the service bit mask in a bit stream */ +#define BTM_EIR_HAS_SERVICE(p, service) \ + ((((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] & \ + ((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) >> \ + (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS)) + namespace { constexpr char kBtmLogTag[] = "SCAN"; +struct { + bool inq_by_rssi{false}; +} internal_; + void btm_log_history_scan_mode(uint8_t scan_mode) { static uint8_t scan_mode_cached_ = 0xff; if (scan_mode_cached_ == scan_mode) return; @@ -84,7 +111,7 @@ uint16_t max_bd_entries_; /* Maximum number of entries that can be stored */ } // namespace extern tBTM_CB btm_cb; - +void btm_inq_db_set_inq_by_rssi(void); void btm_inq_remote_name_timer_timeout(void* data); tBTM_STATUS btm_ble_read_remote_name(const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb); @@ -129,6 +156,10 @@ using bluetooth::Uuid; #define PROPERTY_INQ_SCAN_WINDOW "bluetooth.core.classic.inq_scan_window" #endif +#ifndef PROPERTY_INQ_BY_RSSI +#define PROPERTY_INQ_BY_RSSI "persist.bluetooth.inq_by_rssi" +#endif + #define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10 /******************************************************************************/ @@ -234,10 +265,8 @@ tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode) { LAP temp_lap[2]; bool is_limited; bool cod_limited; - uint16_t window = BTM_DEFAULT_DISC_WINDOW; - uint16_t interval = BTM_DEFAULT_DISC_INTERVAL; - BTM_TRACE_API("BTM_SetDiscoverability"); + LOG_VERBOSE(""); if (controller_get_interface()->supports_ble()) { if (btm_ble_set_discoverability((uint16_t)(inq_mode)) == BTM_SUCCESS) { btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK); @@ -254,8 +283,10 @@ tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode) { if (!controller_get_interface()->get_is_ready()) return (BTM_DEV_RESET); /* If the window and/or interval is '0', set to default values */ - BTM_TRACE_API("BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2]", - inq_mode); + LOG_VERBOSE("mode %d [NonDisc-0, Lim-1, Gen-2]", inq_mode); + (inq_mode != BTM_NON_DISCOVERABLE) + ? power_telemetry::GetInstance().LogInqScanStarted() + : power_telemetry::GetInstance().LogInqScanStopped(); /* Set the IAC if needed */ if (inq_mode != BTM_NON_DISCOVERABLE) { @@ -272,10 +303,10 @@ tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode) { scan_mode |= HCI_INQUIRY_SCAN_ENABLED; } - window = + const uint16_t window = osi_property_get_int32(PROPERTY_INQ_SCAN_WINDOW, BTM_DEFAULT_DISC_WINDOW); - interval = osi_property_get_int32(PROPERTY_INQ_SCAN_INTERVAL, - BTM_DEFAULT_DISC_INTERVAL); + const uint16_t interval = osi_property_get_int32(PROPERTY_INQ_SCAN_INTERVAL, + BTM_DEFAULT_DISC_INTERVAL); /* Send down the inquiry scan window and period if changed */ if ((window != btm_cb.btm_inq_vars.inq_scan_window) || @@ -314,7 +345,7 @@ tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode) { } void BTM_EnableInterlacedInquiryScan() { - BTM_TRACE_API("BTM_EnableInterlacedInquiryScan"); + LOG_VERBOSE(""); uint16_t inq_scan_type = osi_property_get_int32(PROPERTY_INQ_SCAN_TYPE, BTM_SCAN_TYPE_INTERLACED); @@ -330,7 +361,7 @@ void BTM_EnableInterlacedInquiryScan() { } void BTM_EnableInterlacedPageScan() { - BTM_TRACE_API("BTM_EnableInterlacedPageScan"); + LOG_VERBOSE(""); uint16_t page_scan_type = osi_property_get_int32(PROPERTY_PAGE_SCAN_TYPE, BTM_SCAN_TYPE_INTERLACED); @@ -362,7 +393,7 @@ void BTM_EnableInterlacedPageScan() { ******************************************************************************/ tBTM_STATUS BTM_SetInquiryMode(uint8_t mode) { const controller_t* controller = controller_get_interface(); - BTM_TRACE_API("BTM_SetInquiryMode"); + LOG_VERBOSE(""); if (mode == BTM_INQ_RESULT_STANDARD) { /* mandatory mode */ } else if (mode == BTM_INQ_RESULT_WITH_RSSI) { @@ -397,21 +428,14 @@ tBTM_STATUS BTM_SetInquiryMode(uint8_t mode) { ******************************************************************************/ tBTM_STATUS BTM_SetConnectability(uint16_t page_mode) { uint8_t scan_mode = 0; - uint16_t window = BTM_DEFAULT_CONN_WINDOW; - uint16_t interval = (uint16_t)osi_property_get_int32( - BTM_PAGE_SCAN_INTERVAL_PROPERTY, BTM_DEFAULT_CONN_INTERVAL); - - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - - BTM_TRACE_API("BTM_SetConnectability page scan interval = (%d * 0.625)ms", - interval); if (controller_get_interface()->supports_ble()) { if (btm_ble_set_connectability(page_mode) != BTM_SUCCESS) { return BTM_NO_RESOURCES; } - p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK); - p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK); + btm_cb.btm_inq_vars.connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK); + btm_cb.btm_inq_vars.connectable_mode |= + (page_mode & BTM_BLE_CONNECTABLE_MASK); } page_mode &= ~BTM_BLE_CONNECTABLE_MASK; @@ -422,34 +446,34 @@ tBTM_STATUS BTM_SetConnectability(uint16_t page_mode) { /* Make sure the controller is active */ if (!controller_get_interface()->get_is_ready()) return (BTM_DEV_RESET); - BTM_TRACE_API("BTM_SetConnectability: mode %d [NonConn-0, Conn-1]", - page_mode); - /*** Only check window and duration if mode is connectable ***/ if (page_mode == BTM_CONNECTABLE) { scan_mode |= HCI_PAGE_SCAN_ENABLED; } - window = osi_property_get_int32(PROPERTY_PAGE_SCAN_WINDOW, - BTM_DEFAULT_CONN_WINDOW); - interval = osi_property_get_int32(PROPERTY_PAGE_SCAN_INTERVAL, - BTM_DEFAULT_CONN_INTERVAL); + const uint16_t window = osi_property_get_int32(PROPERTY_PAGE_SCAN_WINDOW, + BTM_DEFAULT_CONN_WINDOW); + const uint16_t interval = osi_property_get_int32(PROPERTY_PAGE_SCAN_INTERVAL, + BTM_DEFAULT_CONN_INTERVAL); + + LOG_VERBOSE("mode=%d [NonConn-0, Conn-1], page scan interval=(%d * 0.625)ms", + page_mode, interval); - if ((window != p_inq->page_scan_window) || - (interval != p_inq->page_scan_period)) { - p_inq->page_scan_window = window; - p_inq->page_scan_period = interval; + if ((window != btm_cb.btm_inq_vars.page_scan_window) || + (interval != btm_cb.btm_inq_vars.page_scan_period)) { + btm_cb.btm_inq_vars.page_scan_window = window; + btm_cb.btm_inq_vars.page_scan_period = interval; btsnd_hcic_write_pagescan_cfg(interval, window); } /* Keep the inquiry scan as previouosly set */ - if (p_inq->discoverable_mode & BTM_DISCOVERABLE_MASK) + if (btm_cb.btm_inq_vars.discoverable_mode & BTM_DISCOVERABLE_MASK) scan_mode |= HCI_INQUIRY_SCAN_ENABLED; btm_log_history_scan_mode(scan_mode); btsnd_hcic_write_scan_enable(scan_mode); - p_inq->connectable_mode &= (~BTM_CONNECTABLE_MASK); - p_inq->connectable_mode |= page_mode; + btm_cb.btm_inq_vars.connectable_mode &= (~BTM_CONNECTABLE_MASK); + btm_cb.btm_inq_vars.connectable_mode |= page_mode; return (BTM_SUCCESS); } @@ -465,7 +489,7 @@ tBTM_STATUS BTM_SetConnectability(uint16_t page_mode) { * ******************************************************************************/ uint16_t BTM_IsInquiryActive(void) { - BTM_TRACE_API("BTM_IsInquiryActive"); + LOG_VERBOSE(""); return (btm_cb.btm_inq_vars.inq_active); } @@ -478,8 +502,7 @@ uint16_t BTM_IsInquiryActive(void) { * ******************************************************************************/ void BTM_CancelInquiry(void) { - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - BTM_TRACE_API("BTM_CancelInquiry called"); + LOG_VERBOSE(""); CHECK(BTM_IsDeviceUp()); @@ -506,29 +529,31 @@ void BTM_CancelInquiry(void) { (end_time_ms - btm_cb.neighbor.classic_inquiry.start_time_ms) / 1000.0, btm_cb.neighbor.classic_inquiry.results, - p_inq->inq_cmpl_info.resp_type[BTM_INQ_RESULT_STANDARD], - p_inq->inq_cmpl_info.resp_type[BTM_INQ_RESULT_WITH_RSSI], - p_inq->inq_cmpl_info.resp_type[BTM_INQ_RESULT_EXTENDED])); + btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_STANDARD], + btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_WITH_RSSI], + btm_cb.btm_inq_vars.inq_cmpl_info + .resp_type[BTM_INQ_RESULT_EXTENDED])); btm_cb.neighbor.classic_inquiry = {}; /* Only cancel if not in periodic mode, otherwise the caller should call * BTM_CancelPeriodicMode */ - if ((p_inq->inq_active & BTM_INQUIRY_ACTIVE_MASK) != 0) { - p_inq->inq_active = BTM_INQUIRY_INACTIVE; - p_inq->state = BTM_INQ_INACTIVE_STATE; - p_inq->p_inq_results_cb = NULL; /* Do not notify caller anymore */ - p_inq->p_inq_cmpl_cb = NULL; /* Do not notify caller anymore */ - - if ((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0) { + if ((btm_cb.btm_inq_vars.inq_active & BTM_INQUIRY_ACTIVE_MASK) != 0) { + btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE; + btm_cb.btm_inq_vars.state = BTM_INQ_INACTIVE_STATE; + btm_cb.btm_inq_vars.p_inq_results_cb = + NULL; /* Do not notify caller anymore */ + btm_cb.btm_inq_vars.p_inq_cmpl_cb = NULL; /* Do not notify caller anymore */ + + if ((btm_cb.btm_inq_vars.inqparms.mode & BTM_BR_INQUIRY_MASK) != 0) { bluetooth::legacy::hci::GetInterface().InquiryCancel(); } if (!bluetooth::shim::is_classic_discovery_only_enabled()) { - if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) + if ((btm_cb.btm_inq_vars.inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) btm_ble_stop_inquiry(); } - p_inq->inq_counter++; + btm_cb.btm_inq_vars.inq_counter++; btm_clr_inq_result_flt(); } } @@ -594,7 +619,7 @@ tBTM_STATUS BTM_StartInquiry(tBTM_INQ_RESULTS_CB* p_results_cb, /*** Make sure the device is ready ***/ if (!BTM_IsDeviceUp()) { - LOG(ERROR) << __func__ << ": adapter is not up"; + LOG_ERROR("adapter is not up"); btm_cb.neighbor.inquiry_history_->Push({ .status = tBTM_INQUIRY_CMPL::NOT_STARTED, }); @@ -726,28 +751,21 @@ tBTM_STATUS BTM_ReadRemoteDeviceName(const RawAddress& remote_bda, * ******************************************************************************/ tBTM_STATUS BTM_CancelRemoteDeviceName(void) { - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - - BTM_TRACE_API("BTM_CancelRemoteDeviceName()"); + LOG_VERBOSE(""); /* Make sure there is not already one in progress */ - if (p_inq->remname_active) { - if (BTM_UseLeLink(p_inq->remname_bda)) { + if (btm_cb.btm_inq_vars.remname_active) { + if (BTM_UseLeLink(btm_cb.btm_inq_vars.remname_bda)) { /* Cancel remote name request for LE device, and process remote name * callback. */ btm_inq_rmt_name_failed_cancelled(); } else - btsnd_hcic_rmt_name_req_cancel(p_inq->remname_bda); + btsnd_hcic_rmt_name_req_cancel(btm_cb.btm_inq_vars.remname_bda); return (BTM_CMD_STARTED); } else return (BTM_WRONG_MODE); } -bool BTM_IsRemoteNameKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - return (p_dev_rec == nullptr) ? false : p_dev_rec->is_name_known(); -} - /******************************************************************************* * * Function BTM_InqDbRead @@ -837,10 +855,8 @@ tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur) { * ******************************************************************************/ tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda) { - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - /* If an inquiry or remote name is in progress return busy */ - if (p_inq->inq_active != BTM_INQUIRY_INACTIVE) return (BTM_BUSY); + if (btm_cb.btm_inq_vars.inq_active != BTM_INQUIRY_INACTIVE) return (BTM_BUSY); btm_clr_inq_db(p_bda); @@ -891,56 +907,56 @@ void btm_clear_all_pending_le_entry(void) { ******************************************************************************/ void btm_inq_db_reset(void) { tBTM_REMOTE_DEV_NAME rem_name = {}; - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; uint8_t num_responses; uint8_t temp_inq_active; LOG_DEBUG("Resetting inquiry database"); /* If an inquiry or periodic inquiry is active, reset the mode to inactive */ - if (p_inq->inq_active != BTM_INQUIRY_INACTIVE) { - temp_inq_active = p_inq->inq_active; /* Save so state can change BEFORE - callback is called */ - p_inq->inq_active = BTM_INQUIRY_INACTIVE; + if (btm_cb.btm_inq_vars.inq_active != BTM_INQUIRY_INACTIVE) { + temp_inq_active = + btm_cb.btm_inq_vars.inq_active; /* Save so state can change BEFORE + callback is called */ + btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE; /* If not a periodic inquiry, the complete callback must be called to notify * caller */ if (temp_inq_active == BTM_GENERAL_INQUIRY_ACTIVE) { - if (p_inq->p_inq_cmpl_cb) { + if (btm_cb.btm_inq_vars.p_inq_cmpl_cb) { num_responses = 0; - (*p_inq->p_inq_cmpl_cb)(&num_responses); + (*btm_cb.btm_inq_vars.p_inq_cmpl_cb)(&num_responses); } } } /* Cancel a remote name request if active, and notify the caller (if waiting) */ - if (p_inq->remname_active) { - alarm_cancel(p_inq->remote_name_timer); - p_inq->remname_active = false; - p_inq->remname_bda = RawAddress::kEmpty; + if (btm_cb.btm_inq_vars.remname_active) { + alarm_cancel(btm_cb.btm_inq_vars.remote_name_timer); + btm_cb.btm_inq_vars.remname_active = false; + btm_cb.btm_inq_vars.remname_bda = RawAddress::kEmpty; - if (p_inq->p_remname_cmpl_cb) { + if (btm_cb.btm_inq_vars.p_remname_cmpl_cb) { rem_name.status = BTM_DEV_RESET; rem_name.hci_status = HCI_SUCCESS; - (*p_inq->p_remname_cmpl_cb)(&rem_name); - p_inq->p_remname_cmpl_cb = NULL; + (*btm_cb.btm_inq_vars.p_remname_cmpl_cb)(&rem_name); + btm_cb.btm_inq_vars.p_remname_cmpl_cb = NULL; } } - p_inq->state = BTM_INQ_INACTIVE_STATE; - p_inq->p_inq_results_cb = NULL; + btm_cb.btm_inq_vars.state = BTM_INQ_INACTIVE_STATE; + btm_cb.btm_inq_vars.p_inq_results_cb = NULL; btm_clr_inq_db(NULL); /* Clear out all the entries in the database */ btm_clr_inq_result_flt(); - p_inq->discoverable_mode = BTM_NON_DISCOVERABLE; - p_inq->connectable_mode = BTM_NON_CONNECTABLE; - p_inq->page_scan_type = BTM_SCAN_TYPE_STANDARD; - p_inq->inq_scan_type = BTM_SCAN_TYPE_STANDARD; + btm_cb.btm_inq_vars.discoverable_mode = BTM_NON_DISCOVERABLE; + btm_cb.btm_inq_vars.connectable_mode = BTM_NON_CONNECTABLE; + btm_cb.btm_inq_vars.page_scan_type = BTM_SCAN_TYPE_STANDARD; + btm_cb.btm_inq_vars.inq_scan_type = BTM_SCAN_TYPE_STANDARD; - p_inq->discoverable_mode |= BTM_BLE_NON_DISCOVERABLE; - p_inq->connectable_mode |= BTM_BLE_NON_CONNECTABLE; + btm_cb.btm_inq_vars.discoverable_mode |= BTM_BLE_NON_DISCOVERABLE; + btm_cb.btm_inq_vars.connectable_mode |= BTM_BLE_NON_CONNECTABLE; return; } @@ -959,12 +975,17 @@ void btm_inq_db_init(void) { btm_cb.btm_inq_vars.remote_name_timer = alarm_new("btm_inq.remote_name_timer"); btm_cb.btm_inq_vars.no_inc_ssp = BTM_NO_SSP_ON_INQUIRY; + btm_inq_db_set_inq_by_rssi(); } void btm_inq_db_free(void) { alarm_free(btm_cb.btm_inq_vars.remote_name_timer); } +void btm_inq_db_set_inq_by_rssi(void) { + internal_.inq_by_rssi = osi_property_get_bool(PROPERTY_INQ_BY_RSSI, false); +} + /******************************************************************************* * * Function btm_inq_stop_on_ssp @@ -978,10 +999,9 @@ void btm_inq_stop_on_ssp(void) { uint8_t normal_active = (BTM_GENERAL_INQUIRY_ACTIVE); #if (BTM_INQ_DEBUG == TRUE) - BTM_TRACE_DEBUG( - "btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d ", - btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active, - btm_cb.btm_inq_vars.state); + LOG_VERBOSE("btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d ", + btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active, + btm_cb.btm_inq_vars.state); #endif if (btm_cb.btm_inq_vars.no_inc_ssp) { if (btm_cb.btm_inq_vars.state == BTM_INQ_ACTIVE_STATE) { @@ -1026,8 +1046,8 @@ void btm_clr_inq_db(const RawAddress* p_bda) { uint16_t xx; #if (BTM_INQ_DEBUG == TRUE) - BTM_TRACE_DEBUG("btm_clr_inq_db: inq_active:0x%x state:%d", - btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state); + LOG_VERBOSE("btm_clr_inq_db: inq_active:0x%x state:%d", + btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state); #endif std::lock_guard lock(inq_db_lock_); tINQ_DB_ENT* p_ent = inq_db_; @@ -1040,8 +1060,8 @@ void btm_clr_inq_db(const RawAddress* p_bda) { } } #if (BTM_INQ_DEBUG == TRUE) - BTM_TRACE_DEBUG("inq_active:0x%x state:%d", btm_cb.btm_inq_vars.inq_active, - btm_cb.btm_inq_vars.state); + LOG_VERBOSE("inq_active:0x%x state:%d", btm_cb.btm_inq_vars.inq_active, + btm_cb.btm_inq_vars.state); #endif } @@ -1147,15 +1167,19 @@ tINQ_DB_ENT* btm_inq_db_find(const RawAddress& p_bda) { * Returns pointer to entry * ******************************************************************************/ -tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda) { - uint16_t xx; - uint64_t ot = UINT64_MAX; +tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda, bool is_ble) { + uint16_t xx = 0, yy = 0; + uint32_t ot = 0xFFFFFFFF; + int8_t i_rssi = 0; + + if (is_ble) yy = BTM_INQ_DB_SIZE / 2; + else yy = 0; std::lock_guard lock(inq_db_lock_); - tINQ_DB_ENT* p_ent = inq_db_; - tINQ_DB_ENT* p_old = inq_db_; + tINQ_DB_ENT* p_ent = &inq_db_[yy]; + tINQ_DB_ENT* p_old = &inq_db_[yy]; - for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) { + for (xx = 0; xx < BTM_INQ_DB_SIZE / 2; xx++, p_ent++) { if (!p_ent->in_use) { memset(p_ent, 0, sizeof(tINQ_DB_ENT)); p_ent->inq_info.results.remote_bd_addr = p_bda; @@ -1164,9 +1188,16 @@ tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda) { return (p_ent); } - if (p_ent->time_of_resp < ot) { - p_old = p_ent; - ot = p_ent->time_of_resp; + if (internal_.inq_by_rssi) { + if (p_ent->inq_info.results.rssi < i_rssi) { + p_old = p_ent; + i_rssi = p_ent->inq_info.results.rssi; + } + } else { + if (p_ent->time_of_resp < ot) { + p_old = p_ent; + ot = p_ent->time_of_resp; + } } } @@ -1203,8 +1234,7 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, bool is_new = true; bool update = false; int8_t i_rssi; - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - tBTM_INQ_RESULTS_CB* p_inq_results_cb = p_inq->p_inq_results_cb; + tBTM_INQ_RESULTS_CB* p_inq_results_cb = btm_cb.btm_inq_vars.p_inq_results_cb; uint8_t page_scan_rep_mode = 0; uint8_t page_scan_per_mode = 0; uint8_t page_scan_mode = 0; @@ -1217,7 +1247,7 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state); /* Only process the results if the BR inquiry is still active */ - if (!(p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK)) { + if (!(btm_cb.btm_inq_vars.inq_active & BTM_BR_INQ_ACTIVE_MASK)) { LOG_INFO("Inquiry is inactive so dropping inquiry result"); return; } @@ -1226,23 +1256,20 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, if (inq_res_mode == BTM_INQ_RESULT_EXTENDED) { if (num_resp > 1) { - BTM_TRACE_ERROR("btm_process_inq_results() extended results (%d) > 1", - num_resp); + LOG_ERROR("extended results (%d) > 1", num_resp); return; } constexpr uint16_t extended_inquiry_result_size = 254; if (hci_evt_len - 1 != extended_inquiry_result_size) { - BTM_TRACE_ERROR("%s: can't fit %d results in %d bytes", __func__, - num_resp, hci_evt_len); + LOG_ERROR("can't fit %d results in %d bytes", num_resp, hci_evt_len); return; } } else if (inq_res_mode == BTM_INQ_RESULT_STANDARD || inq_res_mode == BTM_INQ_RESULT_WITH_RSSI) { constexpr uint16_t inquiry_result_size = 14; if (hci_evt_len < num_resp * inquiry_result_size) { - BTM_TRACE_ERROR("%s: can't fit %d results in %d bytes", __func__, - num_resp, hci_evt_len); + LOG_ERROR("can't fit %d results in %d bytes", num_resp, hci_evt_len); return; } } @@ -1269,7 +1296,7 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, /* Check if this address has already been processed for this inquiry */ if (btm_inq_find_bdaddr(bda)) { - /* BTM_TRACE_DEBUG("BDA seen before %s", ADDRESS_TO_LOGGABLE_CSTR(bda)); + /* LOG_VERBOSE("BDA seen before %s", ADDRESS_TO_LOGGABLE_CSTR(bda)); */ /* By default suppose no update needed */ @@ -1283,7 +1310,7 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, || (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0)) { p_cur = &p_i->inq_info.results; - BTM_TRACE_DEBUG("update RSSI new:%d, old:%d", i_rssi, p_cur->rssi); + LOG_VERBOSE("update RSSI new:%d, old:%d", i_rssi, p_cur->rssi); p_cur->rssi = i_rssi; update = true; } @@ -1302,7 +1329,7 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, /* If existing entry, use that, else get a new one (possibly reusing the * oldest) */ if (p_i == NULL) { - p_i = btm_inq_db_new(bda); + p_i = btm_inq_db_new(bda, false); is_new = true; } @@ -1312,7 +1339,7 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, same inquiry. */ - else if (p_i->inq_count == p_inq->inq_counter && + else if (p_i->inq_count == btm_cb.btm_inq_vars.inq_counter && (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BREDR)) is_new = false; @@ -1335,7 +1362,7 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, p_i->time_of_resp = bluetooth::common::time_get_os_boottime_ms(); - if (p_i->inq_count != p_inq->inq_counter) { + if (p_i->inq_count != btm_cb.btm_inq_vars.inq_counter) { /* A new response was found */ btm_cb.btm_inq_vars.inq_cmpl_info.num_resp++; switch (static_cast(inq_res_mode)) { @@ -1352,12 +1379,13 @@ void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, } p_cur->inq_result_type |= BTM_INQ_RESULT_BR; - if (p_i->inq_count != p_inq->inq_counter) { + if (p_i->inq_count != btm_cb.btm_inq_vars.inq_counter) { p_cur->device_type = BT_DEVICE_TYPE_BREDR; p_i->scan_rsp = false; } else p_cur->device_type |= BT_DEVICE_TYPE_BREDR; - p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */ + p_i->inq_count = + btm_cb.btm_inq_vars.inq_counter; /* Mark entry for current inquiry */ /* Initialize flag to false. This flag is set/used by application */ p_i->inq_info.appl_knows_rem_name = false; @@ -1436,10 +1464,8 @@ void btm_sort_inq_result(void) { * ******************************************************************************/ void btm_process_inq_complete(tHCI_STATUS status, uint8_t mode) { - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - - p_inq->inqparms.mode &= ~(mode); - const auto inq_active = p_inq->inq_active; + btm_cb.btm_inq_vars.inqparms.mode &= ~(mode); + const auto inq_active = btm_cb.btm_inq_vars.inq_active; btm_acl_update_inquiry_status(BTM_INQUIRY_COMPLETE); @@ -1449,17 +1475,17 @@ void btm_process_inq_complete(tHCI_STATUS status, uint8_t mode) { } /* Ignore any stray or late complete messages if the inquiry is not active */ - if (p_inq->inq_active) { - p_inq->inq_cmpl_info.hci_status = status; + if (btm_cb.btm_inq_vars.inq_active) { + btm_cb.btm_inq_vars.inq_cmpl_info.hci_status = status; /* Notify caller that the inquiry has completed; (periodic inquiries do not * send completion events */ - if (p_inq->inqparms.mode == 0) { + if (btm_cb.btm_inq_vars.inqparms.mode == 0) { btm_clear_all_pending_le_entry(); - p_inq->state = BTM_INQ_INACTIVE_STATE; + btm_cb.btm_inq_vars.state = BTM_INQ_INACTIVE_STATE; /* Increment so the start of a next inquiry has a new count */ - p_inq->inq_counter++; + btm_cb.btm_inq_vars.inq_counter++; btm_clr_inq_result_flt(); @@ -1470,7 +1496,7 @@ void btm_process_inq_complete(tHCI_STATUS status, uint8_t mode) { if (btm_cb.btm_inq_vars.p_inq_cmpl_cb) { (btm_cb.btm_inq_vars.p_inq_cmpl_cb)( - (tBTM_INQUIRY_CMPL*)&p_inq->inq_cmpl_info); + (tBTM_INQUIRY_CMPL*)&btm_cb.btm_inq_vars.inq_cmpl_info); } else { LOG_WARN("No callback to return inquiry result"); } @@ -1498,16 +1524,19 @@ void btm_process_inq_complete(tHCI_STATUS status, uint8_t mode) { (end_time_ms - btm_cb.neighbor.classic_inquiry.start_time_ms) / 1000.0, btm_cb.neighbor.classic_inquiry.results, inq_active, - p_inq->inq_cmpl_info.resp_type[BTM_INQ_RESULT_STANDARD], - p_inq->inq_cmpl_info.resp_type[BTM_INQ_RESULT_WITH_RSSI], - p_inq->inq_cmpl_info.resp_type[BTM_INQ_RESULT_EXTENDED], + btm_cb.btm_inq_vars.inq_cmpl_info + .resp_type[BTM_INQ_RESULT_STANDARD], + btm_cb.btm_inq_vars.inq_cmpl_info + .resp_type[BTM_INQ_RESULT_WITH_RSSI], + btm_cb.btm_inq_vars.inq_cmpl_info + .resp_type[BTM_INQ_RESULT_EXTENDED], hci_error_code_text(status).c_str())); btm_cb.neighbor.classic_inquiry.start_time_ms = 0; /* Clear the results callback if set */ - p_inq->p_inq_results_cb = NULL; - p_inq->inq_active = BTM_INQUIRY_INACTIVE; - p_inq->p_inq_cmpl_cb = NULL; + btm_cb.btm_inq_vars.p_inq_results_cb = NULL; + btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE; + btm_cb.btm_inq_vars.p_inq_cmpl_cb = NULL; } else { LOG_INFO( @@ -1559,37 +1588,47 @@ void btm_process_cancel_complete(tHCI_STATUS status, uint8_t mode) { tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda, uint8_t origin, uint64_t timeout_ms, tBTM_NAME_CMPL_CB* p_cb) { - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - /*** Make sure the device is ready ***/ if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE); if (origin == BTM_RMT_NAME_EXT) { - if (p_inq->remname_active) { + if (btm_cb.btm_inq_vars.remname_active) { return (BTM_BUSY); } else { /* If there is no remote name request running,call the callback function * and start timer */ - p_inq->p_remname_cmpl_cb = p_cb; - p_inq->remname_bda = remote_bda; + btm_cb.btm_inq_vars.p_remname_cmpl_cb = p_cb; + btm_cb.btm_inq_vars.remname_bda = remote_bda; - alarm_set_on_mloop(p_inq->remote_name_timer, timeout_ms, + alarm_set_on_mloop(btm_cb.btm_inq_vars.remote_name_timer, timeout_ms, btm_inq_remote_name_timer_timeout, NULL); /* If the database entry exists for the device, use its clock offset */ tINQ_DB_ENT* p_i = btm_inq_db_find(remote_bda); if (p_i && (p_i->inq_info.results.inq_result_type & BTM_INQ_RESULT_BR)) { tBTM_INQ_INFO* p_cur = &p_i->inq_info; + uint16_t clock_offset = p_cur->results.clock_offset | BTM_CLOCK_OFFSET_VALID; + int clock_offset_in_cfg = 0; + if (0 == (p_cur->results.clock_offset & BTM_CLOCK_OFFSET_VALID)) { + if (btif_get_device_clockoffset(remote_bda, &clock_offset_in_cfg)) { + clock_offset = clock_offset_in_cfg; + } + } + btsnd_hcic_rmt_name_req( remote_bda, p_cur->results.page_scan_rep_mode, - p_cur->results.page_scan_mode, - (uint16_t)(p_cur->results.clock_offset | BTM_CLOCK_OFFSET_VALID)); + p_cur->results.page_scan_mode, clock_offset); } else { + uint16_t clock_offset = 0; + int clock_offset_in_cfg = 0; + if (btif_get_device_clockoffset(remote_bda, &clock_offset_in_cfg)) { + clock_offset = clock_offset_in_cfg; + } /* Otherwise use defaults and mark the clock offset as invalid */ btsnd_hcic_rmt_name_req(remote_bda, HCI_PAGE_SCAN_REP_MODE_R1, - HCI_MANDATARY_PAGE_SCAN_MODE, 0); + HCI_MANDATARY_PAGE_SCAN_MODE, clock_offset); } - p_inq->remname_active = true; + btm_cb.btm_inq_vars.remname_active = true; return BTM_CMD_STARTED; } } else { @@ -1611,8 +1650,7 @@ tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda, uint8_t origin, void btm_process_remote_name(const RawAddress* bda, const BD_NAME bdn, uint16_t evt_len, tHCI_STATUS hci_status) { tBTM_REMOTE_DEV_NAME rem_name; - tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars; - tBTM_NAME_CMPL_CB* p_cb = p_inq->p_remname_cmpl_cb; + tBTM_NAME_CMPL_CB* p_cb = btm_cb.btm_inq_vars.p_remname_cmpl_cb; uint8_t* p_n1; uint16_t temp_evt_len; @@ -1626,17 +1664,18 @@ void btm_process_remote_name(const RawAddress* bda, const BD_NAME bdn, LOG_INFO("btm_process_remote_name for %s", ADDRESS_TO_LOGGABLE_CSTR(rem_name.bd_addr)); - VLOG(2) << "Inquire BDA " << p_inq->remname_bda; + VLOG(2) << "Inquire BDA " << btm_cb.btm_inq_vars.remname_bda; /* If the inquire BDA and remote DBA are the same, then stop the timer and set * the active to false */ - if ((p_inq->remname_active) && (!bda || (*bda == p_inq->remname_bda))) { - if (BTM_UseLeLink(p_inq->remname_bda)) { + if ((btm_cb.btm_inq_vars.remname_active) && + (!bda || (*bda == btm_cb.btm_inq_vars.remname_bda))) { + if (BTM_UseLeLink(btm_cb.btm_inq_vars.remname_bda)) { if (hci_status == HCI_ERR_UNSPECIFIED) - btm_ble_cancel_remote_name(p_inq->remname_bda); + btm_ble_cancel_remote_name(btm_cb.btm_inq_vars.remname_bda); } - alarm_cancel(p_inq->remote_name_timer); - p_inq->remname_active = false; + alarm_cancel(btm_cb.btm_inq_vars.remote_name_timer); + btm_cb.btm_inq_vars.remname_active = false; /* Clean up and return the status if the command was not successful */ /* Note: If part of the inquiry, the name is not stored, and the */ /* inquiry complete callback is called. */ @@ -1666,9 +1705,9 @@ void btm_process_remote_name(const RawAddress* bda, const BD_NAME bdn, rem_name.remote_bd_name[0] = 0; } /* Reset the remote BAD to zero and call callback if possible */ - p_inq->remname_bda = RawAddress::kEmpty; + btm_cb.btm_inq_vars.remname_bda = RawAddress::kEmpty; - p_inq->p_remname_cmpl_cb = NULL; + btm_cb.btm_inq_vars.p_remname_cmpl_cb = NULL; if (p_cb) (p_cb)(&rem_name); } } @@ -1689,8 +1728,7 @@ void btm_inq_remote_name_timer_timeout(UNUSED_ATTR void* data) { * ******************************************************************************/ void btm_inq_rmt_name_failed_cancelled(void) { - BTM_TRACE_ERROR("btm_inq_rmt_name_failed_cancelled() remname_active=%d", - btm_cb.btm_inq_vars.remname_active); + LOG_ERROR("remname_active=%d", btm_cb.btm_inq_vars.remname_active); if (btm_cb.btm_inq_vars.remname_active) { btm_process_remote_name(&btm_cb.btm_inq_vars.remname_bda, NULL, 0, @@ -1715,7 +1753,7 @@ void btm_inq_rmt_name_failed_cancelled(void) { ******************************************************************************/ tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff) { if (controller_get_interface()->supports_extended_inquiry_response()) { - BTM_TRACE_API("Write Extended Inquiry Response to controller"); + LOG_VERBOSE("Write Extended Inquiry Response to controller"); btsnd_hcic_write_ext_inquiry_response(p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED); return BTM_SUCCESS; } else { @@ -1770,31 +1808,6 @@ bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16) { return (false); } -/******************************************************************************* - * - * Function BTM_HasInquiryEirService - * - * Description This function is called to know if UUID in bit map of UUID - * list. - * - * Parameters p_results - inquiry results - * uuid16 - UUID 16-bit - * - * Returns BTM_EIR_FOUND - if found - * BTM_EIR_NOT_FOUND - if not found and it is complete list - * BTM_EIR_UNKNOWN - if not found and it is not complete list - * - ******************************************************************************/ -tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS* p_results, - uint16_t uuid16) { - if (BTM_HasEirService(p_results->eir_uuid, uuid16)) { - return BTM_EIR_FOUND; - } else if (p_results->eir_complete_list) { - return BTM_EIR_NOT_FOUND; - } else - return BTM_EIR_UNKNOWN; -} - /******************************************************************************* * * Function BTM_AddEirService @@ -1916,23 +1929,22 @@ uint8_t BTM_GetEirUuidList(const uint8_t* p_eir, size_t eir_len, } if (*p_num_uuid > max_num_uuid) { - BTM_TRACE_WARNING("%s: number of uuid in EIR = %d, size of uuid list = %d", - __func__, *p_num_uuid, max_num_uuid); + LOG_WARN("number of uuid in EIR = %d, size of uuid list = %d", *p_num_uuid, + max_num_uuid); *p_num_uuid = max_num_uuid; } - BTM_TRACE_DEBUG("%s: type = %02X, number of uuid = %d", __func__, type, - *p_num_uuid); + LOG_VERBOSE("type = %02X, number of uuid = %d", type, *p_num_uuid); if (uuid_size == Uuid::kNumBytes16) { for (yy = 0; yy < *p_num_uuid; yy++) { STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data); - BTM_TRACE_DEBUG(" 0x%04X", *(p_uuid16 + yy)); + LOG_VERBOSE(" 0x%04X", *(p_uuid16 + yy)); } } else if (uuid_size == Uuid::kNumBytes32) { for (yy = 0; yy < *p_num_uuid; yy++) { STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data); - BTM_TRACE_DEBUG(" 0x%08X", *(p_uuid32 + yy)); + LOG_VERBOSE(" 0x%08X", *(p_uuid32 + yy)); } } else if (uuid_size == Uuid::kNumBytes128) { for (yy = 0; yy < *p_num_uuid; yy++) { @@ -1940,7 +1952,7 @@ uint8_t BTM_GetEirUuidList(const uint8_t* p_eir, size_t eir_len, for (xx = 0; xx < Uuid::kNumBytes128; xx++) snprintf(buff + xx * 2, sizeof(buff) - xx * 2, "%02X", *(p_uuid_list + yy * Uuid::kNumBytes128 + xx)); - BTM_TRACE_DEBUG(" 0x%s", buff); + LOG_VERBOSE(" 0x%s", buff); } } @@ -2053,7 +2065,7 @@ static uint16_t btm_convert_uuid_to_uuid16(const uint8_t* p_uuid, } break; default: - BTM_TRACE_WARNING("btm_convert_uuid_to_uuid16 invalid uuid size"); + LOG_WARN("btm_convert_uuid_to_uuid16 invalid uuid size"); break; } @@ -2089,8 +2101,7 @@ void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) { p_results->eir_complete_list = false; } - BTM_TRACE_API("btm_set_eir_uuid eir_complete_list=0x%02X", - p_results->eir_complete_list); + LOG_VERBOSE("eir_complete_list=0x%02X", p_results->eir_complete_list); if (p_uuid_data) { for (yy = 0; yy < num_uuid; yy++) { @@ -2119,3 +2130,12 @@ void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) { } } } + +namespace bluetooth { +namespace legacy { +namespace testing { +void btm_clr_inq_db(const RawAddress* p_bda) { ::btm_clr_inq_db(p_bda); } +uint16_t btm_get_num_bd_entries() { return num_bd_entries_; } +} // namespace testing +} // namespace legacy +} // namespace bluetooth diff --git a/system/stack/btm/btm_int_types.h b/system/stack/btm/btm_int_types.h index b5785e70212413f70e5e0740ba7758300ebe47e9..b3a99b75dbc268bd13c5e64d72b682e037de4f10 100644 --- a/system/stack/btm/btm_int_types.h +++ b/system/stack/btm/btm_int_types.h @@ -18,26 +18,23 @@ #ifndef BTM_INT_TYPES_H #define BTM_INT_TYPES_H +#include + #include #include #include #include "gd/common/circular_buffer.h" -#include "osi/include/allocator.h" +#include "internal_include/bt_target.h" #include "osi/include/fixed_queue.h" -#include "osi/include/list.h" #include "stack/acl/acl.h" #include "stack/btm/btm_ble_int_types.h" #include "stack/btm/btm_sco.h" #include "stack/btm/neighbor_inquiry.h" -#include "stack/btm/security_device_record.h" -#include "stack/include/bt_octets.h" #include "stack/include/btm_ble_api_types.h" #include "stack/include/security_client_callbacks.h" #include "types/raw_address.h" -#define BTM_MAX_SCN_ 31 // PORT_MAX_RFC_PORTS packages/modules/Bluetooth/system/stack/include/rfcdefs.h - constexpr size_t kMaxLogSize = 255; constexpr size_t kBtmLogHistoryBufferSize = 200; constexpr size_t kMaxInquiryScanHistory = 10; @@ -64,79 +61,15 @@ class TimestampedStringCircularBuffer } }; -/* - * Local device configuration - */ -typedef struct { - tBTM_LOC_BD_NAME bd_name; /* local Bluetooth device name */ - bool pin_type; /* true if PIN type is fixed */ - uint8_t pin_code_len; /* Bonding information */ - PIN_CODE pin_code; /* PIN CODE if pin type is fixed */ -} tBTM_CFG; - -/* Pairing State */ -enum { - BTM_PAIR_STATE_IDLE, /* Idle */ - BTM_PAIR_STATE_GET_REM_NAME, /* Getting the remote name (to check for SM4) */ - BTM_PAIR_STATE_WAIT_PIN_REQ, /* Started authentication, waiting for PIN req - (PIN is pre-fetched) */ - BTM_PAIR_STATE_WAIT_LOCAL_PIN, /* Waiting for local PIN code */ - BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM, /* Waiting user 'yes' to numeric - confirmation */ - BTM_PAIR_STATE_KEY_ENTRY, /* Key entry state (we are a keyboard) */ - BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP, /* Waiting for local response to peer OOB - data */ - BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS, /* Waiting for local IO capabilities and OOB - data */ - BTM_PAIR_STATE_INCOMING_SSP, /* Incoming SSP (got peer IO caps when idle) */ - BTM_PAIR_STATE_WAIT_AUTH_COMPLETE, /* All done, waiting authentication - cpmplete */ - BTM_PAIR_STATE_WAIT_DISCONNECT /* Waiting to disconnect the ACL */ -}; -typedef uint8_t tBTM_PAIRING_STATE; - -#define BTM_PAIR_FLAGS_WE_STARTED_DD \ - 0x01 /* We want to do dedicated bonding */ -#define BTM_PAIR_FLAGS_PEER_STARTED_DD \ - 0x02 /* Peer initiated dedicated bonding */ -#define BTM_PAIR_FLAGS_DISC_WHEN_DONE 0x04 /* Disconnect when done */ -#define BTM_PAIR_FLAGS_PIN_REQD \ - 0x08 /* set this bit when pin_callback is called */ -#define BTM_PAIR_FLAGS_PRE_FETCH_PIN \ - 0x10 /* set this bit when pre-fetch pin */ -#define BTM_PAIR_FLAGS_REJECTED_CONNECT \ - 0x20 /* set this bit when rejected incoming connection */ -#define BTM_PAIR_FLAGS_WE_CANCEL_DD \ - 0x40 /* set this bit when cancelling a bonding procedure */ -#define BTM_PAIR_FLAGS_LE_ACTIVE \ - 0x80 /* use this bit when SMP pairing is active */ - -typedef struct { - bool is_mux; - RawAddress bd_addr; - uint16_t psm; - bool is_orig; - tBTM_SEC_CALLBACK* p_callback; - void* p_ref_data; - uint16_t rfcomm_security_requirement; - tBT_TRANSPORT transport; - tBTM_BLE_SEC_ACT sec_act; -} tBTM_SEC_QUEUE_ENTRY; - /* Define a structure to hold all the BTM data */ -#define BTM_STATE_BUFFER_SIZE 5 /* size of state buffer */ - /* Define the Device Management control structure */ typedef struct tBTM_DEVCB { tBTM_VS_EVT_CB* p_vend_spec_cb[BTM_MAX_VSE_CALLBACKS]; /* Register for vendor specific events */ - tBTM_CMPL_CB* - p_stored_link_key_cmpl_cb; /* Read/Write/Delete stored link key */ - alarm_t* read_local_name_timer; /* Read local name timer */ tBTM_CMPL_CB* p_rln_cmpl_cb; /* Callback function to be called when */ /* read local name function complete */ @@ -165,21 +98,11 @@ typedef struct tBTM_DEVCB { DEV_CLASS dev_class; /* Local device class */ - RawAddress read_tx_pwr_addr; /* read TX power target address */ - - tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */ - Octet16 ble_encryption_key_value; /* BLE encryption key */ - -#if (BTM_BLE_CONFORMANCE_TESTING == TRUE) - bool no_disc_if_pair_fail; - bool enable_test_mac_val; - BT_OCTET8 test_mac; - bool enable_test_local_sign_cntr; - uint32_t test_local_sign_cntr; -#endif + tBTM_CMPL_CB* + p_le_test_cmd_cmpl_cb; /* Callback function to be called when + LE test mode command has been sent successfully */ - tBTM_IO_CAP loc_io_caps; /* IO capability of the local device */ - tBTM_AUTH_REQ loc_auth_req; /* the auth_req flag */ + RawAddress read_tx_pwr_addr; /* read TX power target address */ void Init() { read_local_name_timer = alarm_new("btm.read_local_name_timer"); @@ -203,35 +126,16 @@ typedef struct tBTM_DEVCB { } tBTM_DEVCB; typedef struct tBTM_CB { - tBTM_CFG cfg; /* Device configuration */ - /***************************************************** - ** Device control + ** Control block for local device *****************************************************/ tBTM_DEVCB devcb; /***************************************************** - ** BLE Device controllers + ** Control block for local LE device *****************************************************/ tBTM_BLE_CB ble_ctr_cb; - private: - friend void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk, - const Octet16& stk); - friend tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk, - Octet16* p_stk); - friend void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk, - const Octet16& stk); - uint16_t enc_handle{0}; - - friend void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], - uint16_t ediv); - BT_OCTET8 enc_rand; /* received rand value from LTK request*/ - - uint16_t ediv{0}; /* received ediv value from LTK request */ - - uint8_t key_size{0}; - public: tBTM_BLE_VSC_CB cmn_ble_vsc_cb; @@ -248,52 +152,12 @@ typedef struct tBTM_CB { *****************************************************/ tSCO_CB sco_cb; - /***************************************************** - ** Security Management - *****************************************************/ - tBTM_APPL_INFO api; - #define BTM_SEC_MAX_RMT_NAME_CALLBACKS 2 tBTM_RMT_NAME_CALLBACK* p_rmt_name_callback[BTM_SEC_MAX_RMT_NAME_CALLBACKS]; - tBTM_SEC_DEV_REC* p_collided_dev_rec{nullptr}; - alarm_t* sec_collision_timer{nullptr}; - uint64_t collision_start_time{0}; - uint32_t dev_rec_count{0}; /* Counter used for device record timestamp */ - uint8_t security_mode{0}; - bool pairing_disabled{false}; - bool security_mode_changed{false}; /* mode changed during bonding */ - bool pin_type_changed{false}; /* pin type changed during bonding */ - bool sec_req_pending{false}; /* true if a request is pending */ - - uint8_t pin_code_len{0}; /* for legacy devices */ - PIN_CODE pin_code; /* for legacy devices */ - tBTM_PAIRING_STATE pairing_state{ - BTM_PAIR_STATE_IDLE}; /* The current pairing state */ - uint8_t pairing_flags{0}; /* The current pairing flags */ - RawAddress pairing_bda; /* The device currently pairing */ - alarm_t* pairing_timer{nullptr}; /* Timer for pairing process */ - alarm_t* execution_wait_timer{nullptr}; /* To avoid concurrent auth request */ uint16_t disc_handle{0}; /* for legacy devices */ uint8_t disc_reason{0}; /* for legacy devices */ - tBTM_SEC_SERV_REC sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS]; - list_t* sec_dev_rec{nullptr}; /* list of tBTM_SEC_DEV_REC */ - tBTM_SEC_SERV_REC* p_out_serv{nullptr}; - tBTM_MKEY_CALLBACK* mkey_cback{nullptr}; - - RawAddress connecting_bda; - DEV_CLASS connecting_dc; - uint8_t trace_level; - bool is_paging{false}; /* true, if paging is in progess */ bool is_inquiry{false}; /* true, if inquiry is in progess */ - fixed_queue_t* page_queue{nullptr}; - - bool paging{false}; - void set_paging() { paging = true; } - void reset_paging() { paging = false; } - bool is_paging_active() const { - return paging; - } // TODO remove all this paging state fixed_queue_t* sec_pending_q{nullptr}; /* pending sequrity requests in tBTM_SEC_QUEUE_ENTRY format */ @@ -321,45 +185,17 @@ typedef struct tBTM_CB { kMaxInquiryScanHistory); } neighbor; - void Init(uint8_t initial_security_mode) { - memset(&cfg, 0, sizeof(cfg)); + void Init() { memset(&devcb, 0, sizeof(devcb)); memset(&ble_ctr_cb, 0, sizeof(ble_ctr_cb)); - memset(&enc_rand, 0, sizeof(enc_rand)); memset(&cmn_ble_vsc_cb, 0, sizeof(cmn_ble_vsc_cb)); memset(&btm_inq_vars, 0, sizeof(btm_inq_vars)); memset(&sco_cb, 0, sizeof(sco_cb)); - memset(&api, 0, sizeof(api)); memset(p_rmt_name_callback, 0, sizeof(p_rmt_name_callback)); - memset(&pin_code, 0, sizeof(pin_code)); - memset(sec_serv_rec, 0, sizeof(sec_serv_rec)); - - connecting_bda = RawAddress::kEmpty; - memset(&connecting_dc, 0, sizeof(connecting_dc)); acl_cb_ = {}; neighbor = {}; - page_queue = fixed_queue_new(SIZE_MAX); - sec_pending_q = fixed_queue_new(SIZE_MAX); - sec_collision_timer = alarm_new("btm.sec_collision_timer"); - pairing_timer = alarm_new("btm.pairing_timer"); - execution_wait_timer = alarm_new("btm.execution_wait_timer"); - -#if defined(BTM_INITIAL_TRACE_LEVEL) - trace_level = BTM_INITIAL_TRACE_LEVEL; -#else - trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ -#endif - security_mode = initial_security_mode; - pairing_bda = RawAddress::kAny; - sec_dev_rec = list_new([](void* ptr) { - // Invoke destructor for all record objects and reset to default - // initialized value so memory may be properly freed - *((tBTM_SEC_DEV_REC*)ptr) = {}; - osi_free(ptr); - }); - /* Initialize BTM component structures */ btm_inq_vars.Init(); /* Inquiry Database and Structures */ sco_cb.Init(); /* SCO Database and Structures (If included) */ @@ -369,7 +205,6 @@ typedef struct tBTM_CB { kBtmLogHistoryBufferSize); CHECK(history_ != nullptr); history_->Push(std::string("Initialized btm history")); - btm_available_index = 1; } void Free() { @@ -378,41 +213,7 @@ typedef struct tBTM_CB { devcb.Free(); sco_cb.Free(); btm_inq_vars.Free(); - - fixed_queue_free(page_queue, nullptr); - page_queue = nullptr; - - fixed_queue_free(sec_pending_q, nullptr); - sec_pending_q = nullptr; - - list_free(sec_dev_rec); - sec_dev_rec = nullptr; - - alarm_free(sec_collision_timer); - sec_collision_timer = nullptr; - - alarm_free(pairing_timer); - pairing_timer = nullptr; - - alarm_free(execution_wait_timer); - execution_wait_timer = nullptr; } - - private: - friend uint8_t BTM_AllocateSCN(void); - friend bool BTM_TryAllocateSCN(uint8_t scn); - friend bool BTM_FreeSCN(uint8_t scn); - uint8_t btm_scn[BTM_MAX_SCN_]; - uint8_t btm_available_index; } tBTM_CB; -/* security action for L2CAP COC channels */ -#define BTM_SEC_OK 1 -#define BTM_SEC_ENCRYPT 2 /* encrypt the link with current key */ -#define BTM_SEC_ENCRYPT_NO_MITM 3 /* unauthenticated encryption or better */ -#define BTM_SEC_ENCRYPT_MITM 4 /* authenticated encryption */ -#define BTM_SEC_ENC_PENDING 5 /* wait for link encryption pending */ - -typedef uint8_t tBTM_SEC_ACTION; - #endif // BTM_INT_TYPES_H diff --git a/system/stack/btm/btm_iot_config.cc b/system/stack/btm/btm_iot_config.cc index be80f43a23362c8935178b8f6c67dca79583fbfe..de64ba090a17a31a16ebf1135cc6cf2d6fd4635b 100644 --- a/system/stack/btm/btm_iot_config.cc +++ b/system/stack/btm/btm_iot_config.cc @@ -16,12 +16,15 @@ * ******************************************************************************/ +#define LOG_TAG "btm_iot" + #include "bt_target.h" #include "btif/include/btif_storage.h" #include "btif/include/btif_util.h" #include "btm_ble_api.h" #include "btm_int_types.h" #include "device/include/device_iot_config.h" +#include "osi/include/log.h" /******************************************************************************* * @@ -51,9 +54,9 @@ void btm_iot_save_remote_properties(tACL_CONN* p_acl_cb) { sizeof(cod), &cod); if (btif_storage_get_remote_device_property(&p_acl_cb->remote_addr, &prop_name) == BT_STATUS_SUCCESS) - BTIF_TRACE_DEBUG("%s cod retrieved from storage is 0x%06x", __func__, cod); + LOG_VERBOSE("%s cod retrieved from storage is 0x%06x", __func__, cod); if (cod == 0) { - BTIF_TRACE_DEBUG("%s cod is 0, set as unclassified", __func__); + LOG_VERBOSE("%s cod is 0, set as unclassified", __func__); cod = (0x1F) << 8; } diff --git a/system/stack/btm/btm_iso.cc b/system/stack/btm/btm_iso.cc index 1839e11a132c2395e2d4517e21842c2eba13060f..81bd22e665073375f9156413ff0c1bea4ee83901 100644 --- a/system/stack/btm/btm_iso.cc +++ b/system/stack/btm/btm_iso.cc @@ -112,7 +112,8 @@ void IsoManager::CreateBig(uint8_t big_id, } void IsoManager::TerminateBig(uint8_t big_id, uint8_t reason) { - pimpl_->iso_impl_->terminate_big(big_id, reason); + if (pimpl_->IsRunning()) + pimpl_->iso_impl_->terminate_big(big_id, reason); } void IsoManager::HandleIsoData(void* p_msg) { diff --git a/system/stack/btm/btm_iso_impl.h b/system/stack/btm/btm_iso_impl.h index 9944bb85064e5affb198e18efcf9bde0ed60f9d7..2bbc3fffb31cdc671c55da4093edd41650d1ac6a 100644 --- a/system/stack/btm/btm_iso_impl.h +++ b/system/stack/btm/btm_iso_impl.h @@ -21,29 +21,29 @@ #include #include #include -#include #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/logging.h" -#include "bind_helpers.h" #include "btm_dev.h" #include "btm_iso_api.h" #include "common/time_util.h" #include "device/include/controller.h" #include "hci/include/hci_layer.h" #include "internal_include/stack_config.h" +#include "main/shim/hci_layer.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" #include "stack/include/btm_log_history.h" #include "stack/include/hci_error_code.h" #include "stack/include/hcidefs.h" +#include "stack/include/hcimsgs.h" namespace bluetooth { namespace hci { namespace iso_manager { -static constexpr uint8_t kIsoDataInTsBtHdrOffset = 0x0C; static constexpr uint8_t kIsoHeaderWithTsLen = 12; static constexpr uint8_t kIsoHeaderWithoutTsLen = 8; @@ -56,7 +56,6 @@ static constexpr uint8_t kStateFlagIsBroadcast = 0x10; constexpr char kBtmLogTag[] = "ISO"; struct iso_sync_info { - uint32_t first_sync_ts; uint16_t seq_nb; }; @@ -94,9 +93,11 @@ struct iso_impl { iso_impl() { iso_credits_ = controller_get_interface()->get_iso_buffer_count(); iso_buffer_size_ = controller_get_interface()->get_iso_data_size(); + LOG_INFO("%p created, iso credits: %d, buffer size: %d.", this, + iso_credits_.load(), iso_buffer_size_); } - ~iso_impl() {} + ~iso_impl() { LOG_INFO("%p removed.", this); } void handle_register_cis_callbacks(CigCallbacks* callbacks) { LOG_ASSERT(callbacks != nullptr) << "Invalid CIG callbacks"; @@ -161,7 +162,7 @@ struct iso_impl { auto cis = std::unique_ptr(new iso_cis()); cis->cig_id = cig_id; cis->sdu_itv = sdu_itv_mtos; - cis->sync_info = {.first_sync_ts = 0, .seq_nb = 0}; + cis->sync_info = {.seq_nb = 0}; cis->used_credits = 0; cis->state_flags = kStateFlagsNone; conn_hdl_to_cis_map_[conn_handle] = std::move(cis); @@ -189,7 +190,7 @@ struct iso_impl { cig_params.sca, cig_params.packing, cig_params.framing, cig_params.max_trans_lat_stom, cig_params.max_trans_lat_mtos, cig_params.cis_cfgs.size(), cig_params.cis_cfgs.data(), - base::BindOnce(&iso_impl::on_set_cig_params, base::Unretained(this), + base::BindOnce(&iso_impl::on_set_cig_params, weak_factory_.GetWeakPtr(), cig_id, cig_params.sdu_itv_mtos)); BTM_LogHistory( @@ -207,7 +208,7 @@ struct iso_impl { cig_params.sca, cig_params.packing, cig_params.framing, cig_params.max_trans_lat_stom, cig_params.max_trans_lat_mtos, cig_params.cis_cfgs.size(), cig_params.cis_cfgs.data(), - base::BindOnce(&iso_impl::on_set_cig_params, base::Unretained(this), + base::BindOnce(&iso_impl::on_set_cig_params, weak_factory_.GetWeakPtr(), cig_id, cig_params.sdu_itv_mtos)); } @@ -255,7 +256,7 @@ struct iso_impl { } btsnd_hcic_remove_cig(cig_id, base::BindOnce(&iso_impl::on_remove_cig, - base::Unretained(this))); + weak_factory_.GetWeakPtr())); BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "CIG Remove", base::StringPrintf("cig_id:0x%02x (f:%d)", cig_id, force)); } @@ -300,7 +301,10 @@ struct iso_impl { LOG_ASSERT(cis) << "No such cis: " << +el.cis_conn_handle; LOG_ASSERT(!(cis->state_flags & (kStateFlagIsConnected | kStateFlagIsConnecting))) - << "Already connected or connecting"; + << "cis: " << +el.cis_conn_handle + << " is already connected or connecting flags: " << +cis->state_flags + << ", num of cis params: " << +conn_params.conn_pairs.size(); + cis->state_flags |= kStateFlagIsConnecting; tBTM_SEC_DEV_REC* p_rec = btm_find_dev_by_handle(el.acl_conn_handle); @@ -310,10 +314,10 @@ struct iso_impl { base::StringPrintf("handle:0x%04x", el.acl_conn_handle)); } } - btsnd_hcic_create_cis(conn_params.conn_pairs.size(), - conn_params.conn_pairs.data(), - base::BindOnce(&iso_impl::on_status_establish_cis, - base::Unretained(this), conn_params)); + btsnd_hcic_create_cis( + conn_params.conn_pairs.size(), conn_params.conn_pairs.data(), + base::BindOnce(&iso_impl::on_status_establish_cis, + weak_factory_.GetWeakPtr(), conn_params)); } void disconnect_cis(uint16_t cis_handle, uint8_t reason) { @@ -379,7 +383,7 @@ struct iso_impl { path_params.codec_id_vendor, path_params.controller_delay, std::move(path_params.codec_conf), base::BindOnce(&iso_impl::on_setup_iso_data_path, - base::Unretained(this))); + weak_factory_.GetWeakPtr())); BTM_LogHistory( kBtmLogTag, cis_hdl_to_addr[conn_handle], "Setup data path", base::StringPrintf( @@ -434,7 +438,8 @@ struct iso_impl { btsnd_hcic_remove_iso_data_path( iso_handle, data_path_dir, base::BindOnce(&iso_impl::on_remove_iso_data_path, - base::Unretained(this))); + weak_factory_.GetWeakPtr())); + BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[iso_handle], "Remove data path", base::StringPrintf("handle:0x%04x, dir:0x%02x", iso_handle, data_path_dir)); @@ -499,13 +504,13 @@ struct iso_impl { btsnd_hcic_read_iso_link_quality( iso_handle, base::BindOnce(&iso_impl::on_iso_link_quality_read, - base::Unretained(this))); + weak_factory_.GetWeakPtr())); } - BT_HDR* prepare_ts_hci_packet(uint16_t iso_handle, uint32_t ts, - uint16_t seq_nb, uint16_t data_len) { - /* Add 2 for packet seq., 2 for length, 4 for the timestamp */ - uint16_t iso_data_load_len = data_len + 8; + BT_HDR* prepare_hci_packet(uint16_t iso_handle, uint16_t seq_nb, + uint16_t data_len) { + /* Add 2 for packet seq., 2 for length */ + uint16_t iso_data_load_len = data_len + 4; /* Add 2 for handle, 2 for length */ uint16_t iso_full_len = iso_data_load_len + 4; @@ -519,19 +524,12 @@ struct iso_impl { UINT16_TO_STREAM(packet_data, iso_handle); UINT16_TO_STREAM(packet_data, iso_data_load_len); - packet->layer_specific |= BT_ISO_HDR_CONTAINS_TS; - UINT32_TO_STREAM(packet_data, ts); - UINT16_TO_STREAM(packet_data, seq_nb); UINT16_TO_STREAM(packet_data, data_len); return packet; } - void send_iso_data_hci_packet(BT_HDR* packet) { - bte_main_hci_send(packet, MSG_STACK_TO_HC_HCI_ISO | 0x0001); - } - void send_iso_data(uint16_t iso_handle, const uint8_t* data, uint16_t data_len) { iso_base* iso = GetIsoIfKnown(iso_handle); @@ -554,8 +552,8 @@ struct iso_impl { /* Calculate sequence number for the ISO data packet. * It should be incremented by 1 every SDU Interval. */ - uint32_t ts = bluetooth::common::time_get_os_boottime_us(); - iso->sync_info.seq_nb = (ts - iso->sync_info.first_sync_ts) / iso->sdu_itv; + uint16_t seq_nb = iso->sync_info.seq_nb; + iso->sync_info.seq_nb = (seq_nb + 1) & 0xffff; if (iso_credits_ == 0 || data_len > iso_buffer_size_) { iso->cr_stats.credits_underflow_bytes += data_len; @@ -573,10 +571,11 @@ struct iso_impl { iso_credits_--; iso->used_credits++; - BT_HDR* packet = - prepare_ts_hci_packet(iso_handle, ts, iso->sync_info.seq_nb, data_len); - memcpy(packet->data + kIsoDataInTsBtHdrOffset, data, data_len); - send_iso_data_hci_packet(packet); + BT_HDR* packet = prepare_hci_packet(iso_handle, seq_nb, data_len); + memcpy(packet->data + kIsoHeaderWithoutTsLen, data, data_len); + auto hci = bluetooth::shim::hci_layer_get_interface(); + packet->event = MSG_STACK_TO_HC_HCI_ISO | 0x0001; + hci->transmit_downward(packet->event, packet); } void process_cis_est_pkt(uint8_t len, uint8_t* data) { @@ -597,8 +596,6 @@ struct iso_impl { "cis_handle:0x%04x status:%s", evt.cis_conn_hdl, hci_error_code_text((tHCI_STATUS)(evt.status)).c_str())); - cis->sync_info.first_sync_ts = bluetooth::common::time_get_os_boottime_us(); - STREAM_TO_UINT24(evt.cig_sync_delay, data); STREAM_TO_UINT24(evt.cis_sync_delay, data); STREAM_TO_UINT24(evt.trans_lat_mtos, data); @@ -644,8 +641,8 @@ struct iso_impl { if (cis->state_flags & kStateFlagIsConnected) { cis_disconnected_evt evt = { .reason = reason, - .cis_conn_hdl = handle, .cig_id = cis->cig_id, + .cis_conn_hdl = handle, }; cig_callbacks_->OnCisEvent(kIsoEventCisDisconnected, &evt); @@ -730,7 +727,6 @@ struct iso_impl { LOG_ASSERT(len == (18 + num_bis * sizeof(uint16_t))) << "Invalid packet length: " << len << ". Number of bis: " << +num_bis; - uint32_t ts = bluetooth::common::time_get_os_boottime_us(); for (auto i = 0; i < num_bis; ++i) { uint16_t conn_handle; STREAM_TO_UINT16(conn_handle, data); @@ -741,7 +737,7 @@ struct iso_impl { auto bis = std::unique_ptr(new iso_bis()); bis->big_handle = evt.big_id; bis->sdu_itv = last_big_create_req_sdu_itv_; - bis->sync_info = {.first_sync_ts = ts, .seq_nb = 0}; + bis->sync_info = {.seq_nb = 0}; bis->used_credits = 0; bis->state_flags = kStateFlagIsBroadcast; conn_hdl_to_bis_map_[conn_handle] = std::move(bis); @@ -870,34 +866,18 @@ struct iso_impl { STREAM_TO_UINT16(seq_nb, stream); - uint32_t ts = bluetooth::common::time_get_os_boottime_us(); - uint32_t new_calc_seq_nb = - (ts - iso->sync_info.first_sync_ts) / iso->sdu_itv; - if (new_calc_seq_nb <= iso->sync_info.seq_nb) - new_calc_seq_nb = iso->sync_info.seq_nb + 1; - - if (iso->sync_info.seq_nb == 0) { - evt.evt_lost = 0; - } else { - evt.evt_lost = new_calc_seq_nb - iso->sync_info.seq_nb - 1; - if (evt.evt_lost > 0) { - iso->evt_stats.evt_lost_count += evt.evt_lost; - iso->evt_stats.evt_last_lost_us = - bluetooth::common::time_get_os_boottime_us(); + uint16_t expected_seq_nb = iso->sync_info.seq_nb; + iso->sync_info.seq_nb = (seq_nb + 1) & 0xffff; - LOG(WARNING) << evt.evt_lost << " packets possibly lost."; - } - - if (new_calc_seq_nb != seq_nb) { - LOG(WARNING) << "Sequence number mismatch. " - "Adjusting own time reference point."; - iso->sync_info.first_sync_ts = ts - (seq_nb * iso->sdu_itv); - new_calc_seq_nb = seq_nb; + evt.evt_lost = ((1 << 16) + seq_nb - expected_seq_nb) & 0xffff; + if (evt.evt_lost > 0) { + iso->evt_stats.evt_lost_count += evt.evt_lost; + iso->evt_stats.evt_last_lost_us = + bluetooth::common::time_get_os_boottime_us(); - iso->evt_stats.seq_nb_mismatch_count++; - } + LOG(WARNING) << evt.evt_lost << " packets lost."; + iso->evt_stats.seq_nb_mismatch_count++; } - iso->sync_info.seq_nb = new_calc_seq_nb; evt.p_msg = p_msg; evt.cig_id = iso->cig_id; @@ -1016,6 +996,7 @@ struct iso_impl { BigCallbacks* big_callbacks_ = nullptr; std::mutex on_iso_traffic_active_callbacks_list_mutex_; std::list on_iso_traffic_active_callbacks_list_; + base::WeakPtrFactory weak_factory_{this}; }; } // namespace iso_manager diff --git a/system/stack/btm/btm_main.cc b/system/stack/btm/btm_main.cc index ececad2c4886f097b58337bd78c4e0682c97b6d9..a1f72526af681b45f9e19c72415d1c6bcee0817e 100644 --- a/system/stack/btm/btm_main.cc +++ b/system/stack/btm/btm_main.cc @@ -26,11 +26,13 @@ #include #include "bt_target.h" +#include "btm_int_types.h" +#include "btm_sec_cb.h" #include "main/shim/dumpsys.h" #include "osi/include/log.h" -#include "stack/btm/btm_int_types.h" #include "stack/include/btm_client_interface.h" -#include "stack_config.h" +#include "stack/include/inq_hci_link_interface.h" +#include "stack/include/security_client_callbacks.h" #include "types/raw_address.h" /* Global BTM control block structure @@ -50,13 +52,19 @@ tBTM_CB btm_cb; * ******************************************************************************/ void btm_init(void) { - btm_cb.Init(stack_config_get_interface()->get_pts_secure_only_mode() - ? BTM_SEC_MODE_SC - : BTM_SEC_MODE_SP); + btm_cb.Init(); + get_security_client_interface().BTM_Sec_Init(); + +#ifdef TARGET_FLOSS + // Need to set inquery by rssi flag for Floss since Floss doesn't do + // btm_inq_db_init + btm_inq_db_set_inq_by_rssi(); +#endif } /** This function is called to free dynamic memory and system resource allocated by btm_init */ void btm_free(void) { + get_security_client_interface().BTM_Sec_Free(); btm_cb.Free(); } diff --git a/system/stack/btm/btm_scn.cc b/system/stack/btm/btm_scn.cc deleted file mode 100644 index feec0f5fe75bc94443b76b2f0b3bf55c80d9dc72..0000000000000000000000000000000000000000 --- a/system/stack/btm/btm_scn.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "btm" - -#include -#include "stack/btm/btm_int_types.h" // tBTM_CB -#include "stack/include/rfcdefs.h" // PORT_MAX_RFC_PORTS - -extern tBTM_CB btm_cb; - -/******************************************************************************* - * - * Function BTM_AllocateSCN - * - * Description Look through the Server Channel Numbers for a free one. - * - * Returns Allocated SCN number or 0 if none. - * - ******************************************************************************/ -uint8_t BTM_AllocateSCN(void) { - BTM_TRACE_DEBUG("BTM_AllocateSCN"); - - // stack reserves scn 1 for HFP, HSP we still do the correct way - for (uint8_t x = btm_cb.btm_available_index; x < PORT_MAX_RFC_PORTS; x++) { - if (!btm_cb.btm_scn[x]) { - btm_cb.btm_scn[x] = true; - btm_cb.btm_available_index = (x + 1); - return (x + 1); - } - } - - // In order to avoid OOB, btm_available_index must be less than or equal to - // PORT_MAX_RFC_PORTS - btm_cb.btm_available_index = - std::min(btm_cb.btm_available_index, (uint8_t)PORT_MAX_RFC_PORTS); - - // If there's no empty SCN from _last_index to BTM_MAX_SCN. - for (uint8_t y = 1; y < btm_cb.btm_available_index; y++) { - if (!btm_cb.btm_scn[y]) { - btm_cb.btm_scn[y] = true; - btm_cb.btm_available_index = (y + 1); - return (y + 1); - } - } - - return (0); /* No free ports */ -} - -/******************************************************************************* - * - * Function BTM_TryAllocateSCN - * - * Description Try to allocate a fixed server channel - * - * Returns Returns true if server channel was available - * - ******************************************************************************/ - -bool BTM_TryAllocateSCN(uint8_t scn) { - /* Make sure we don't exceed max port range. - * Stack reserves scn 1 for HFP, HSP we still do the correct way. - */ - if ((scn >= PORT_MAX_RFC_PORTS) || (scn == 1) || (scn == 0)) return false; - - /* check if this port is available */ - if (!btm_cb.btm_scn[scn - 1]) { - btm_cb.btm_scn[scn - 1] = true; - return true; - } - - return (false); /* Port was busy */ -} - -/******************************************************************************* - * - * Function BTM_FreeSCN - * - * Description Free the specified SCN. - * - * Returns true or false - * - ******************************************************************************/ -bool BTM_FreeSCN(uint8_t scn) { - BTM_TRACE_DEBUG("BTM_FreeSCN "); - if (scn <= PORT_MAX_RFC_PORTS && scn > 0) { - btm_cb.btm_scn[scn - 1] = false; - return (true); - } else { - return (false); /* Illegal SCN passed in */ - } -} diff --git a/system/stack/btm/btm_sco.cc b/system/stack/btm/btm_sco.cc index 6668e31f8f8d23fd2b68da4a2d1cb4b5561c546b..0e88190f66afeb10056436dba8c0dad6fc8949b4 100644 --- a/system/stack/btm/btm_sco.cc +++ b/system/stack/btm/btm_sco.cc @@ -23,6 +23,10 @@ * ******************************************************************************/ +#define LOG_TAG "btm_sco" + +#include "stack/btm/btm_sco.h" + #include #include @@ -30,24 +34,27 @@ #include #include -#define LOG_TAG "btm_sco" - +#include "common/bidi_queue.h" #include "device/include/controller.h" #include "device/include/device_iot_config.h" -#include "embdrv/sbc/decoder/include/oi_codec_sbc.h" -#include "embdrv/sbc/decoder/include/oi_status.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "gd/hci/hci_layer.h" +#include "hci/hci_packets.h" +#include "hci/include/hci_layer.h" +#include "internal_include/bt_target.h" +#include "main/shim/entry.h" #include "osi/include/properties.h" +#include "osi/include/stack_power_telemetry.h" +#include "stack/btm/btm_int_types.h" #include "stack/btm/btm_sco_hfp_hal.h" #include "stack/btm/btm_sec.h" -#include "stack/btm/security_device_record.h" #include "stack/include/acl_api.h" -#include "stack/include/bt_hdr.h" #include "stack/include/btm_api.h" #include "stack/include/btm_api_types.h" +#include "stack/include/btm_log_history.h" #include "stack/include/hci_error_code.h" +#include "stack/include/hcimsgs.h" +#include "stack/include/main_thread.h" +#include "stack/include/sdpdefs.h" #include "stack/include/stack_metrics_logging.h" #include "types/class_of_device.h" #include "types/raw_address.h" @@ -62,14 +69,81 @@ static const char kPropertyDisableEnhancedConnection[] = "bluetooth.sco.disable_enhanced_connection"; namespace { + +/* Structure passed with SCO change command and events. + * Used by both Sync and Enhanced sync messaging + */ +typedef struct { + uint16_t max_latency_ms; + uint16_t packet_types; + uint8_t retransmission_effort; +} tBTM_CHG_ESCO_PARAMS; + constexpr char kBtmLogTag[] = "SCO"; -const bluetooth::legacy::hci::Interface& GetLegacyHciInterface() { - return bluetooth::legacy::hci::GetInterface(); +}; // namespace + +using bluetooth::legacy::hci::GetInterface; + +// forward declaration for dequeueing packets +static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet); + +namespace cpp { +bluetooth::common::BidiQueueEnd* hci_sco_queue_end = + nullptr; +static bluetooth::os::EnqueueBuffer* + pending_sco_data = nullptr; + +static void sco_data_callback() { + if (hci_sco_queue_end == nullptr) { + return; + } + auto packet = hci_sco_queue_end->TryDequeue(); + ASSERT(packet != nullptr); + if (!packet->IsValid()) { + LOG_INFO("Dropping invalid packet of size %zu", packet->size()); + return; + } + if (do_in_main_thread(FROM_HERE, base::Bind(&btm_route_sco_data, *packet)) != + BT_STATUS_SUCCESS) { + LOG_ERROR("do_in_main_thread failed from sco_data_callback"); + } +} +static void register_for_sco() { + hci_sco_queue_end = bluetooth::shim::GetHciLayer()->GetScoQueueEnd(); + hci_sco_queue_end->RegisterDequeue( + bluetooth::shim::GetGdShimHandler(), + bluetooth::common::Bind(sco_data_callback)); + pending_sco_data = + new bluetooth::os::EnqueueBuffer( + hci_sco_queue_end); } -}; // namespace +static void shut_down_sco() { + if (pending_sco_data != nullptr) { + pending_sco_data->Clear(); + delete pending_sco_data; + pending_sco_data = nullptr; + } + if (hci_sco_queue_end != nullptr) { + hci_sco_queue_end->UnregisterDequeue(); + hci_sco_queue_end = nullptr; + } +} +}; // namespace cpp + +void tSCO_CB::Init() { + hfp_hal_interface::init(); + def_esco_parms = esco_parameters_for_codec( + ESCO_CODEC_CVSD_S3, hfp_hal_interface::get_offload_enabled()); + cpp::register_for_sco(); +} +void tSCO_CB::Free() { + cpp::shut_down_sco(); + bluetooth::audio::sco::cleanup(); +} /******************************************************************************/ /* L O C A L D A T A D E F I N I T I O N S */ /******************************************************************************/ @@ -164,7 +238,7 @@ static void btm_esco_conn_rsp(uint16_t sco_inx, uint8_t hci_status, ->supports_enhanced_setup_synchronous_connection() && !osi_property_get_bool(kPropertyDisableEnhancedConnection, kDefaultDisableEnhancedConnection)) { - BTM_TRACE_DEBUG( + LOG_VERBOSE( "%s: txbw 0x%x, rxbw 0x%x, lat 0x%x, retrans 0x%02x, " "pkt 0x%04x, path %u", __func__, p_setup->transmit_bandwidth, p_setup->receive_bandwidth, @@ -209,95 +283,82 @@ static tSCO_CONN* btm_get_active_sco() { * Returns void * ******************************************************************************/ -void btm_route_sco_data(BT_HDR* p_msg) { - uint8_t* payload = p_msg->data; - if (p_msg->len < 3) { - LOG_ERROR("Received incomplete SCO header"); - osi_free(p_msg); - return; - } - - uint8_t data_len = 0; - uint16_t handle_with_flags = 0; - STREAM_TO_UINT16(handle_with_flags, payload); - STREAM_TO_UINT8(data_len, payload); - if (p_msg->len != data_len + 3) { - LOG_ERROR("Received invalid SCO data of size: %hhu, dropping", data_len); - osi_free(p_msg); - return; - } - - uint16_t handle = HCID_GET_HANDLE(handle_with_flags); +static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { + uint16_t handle = valid_packet.GetHandle(); if (handle > HCI_HANDLE_MAX) { - LOG_ERROR( - "Receive invalid SCO data with handle: 0x%X, required to be <= 0x%X, " - "dropping", - handle, HCI_HANDLE_MAX); - osi_free(p_msg); + LOG_ERROR("Dropping SCO data with invalid handle: 0x%X > 0x%X, ", handle, + HCI_HANDLE_MAX); return; } tSCO_CONN* active_sco = btm_get_active_sco(); if (active_sco == nullptr) { LOG_ERROR("Received SCO data when there is no active SCO connection"); - osi_free(p_msg); return; } if (active_sco->hci_handle != handle) { - LOG_ERROR( - "Drop packet with handle(0x%X) different from the active handle(0x%X)", - handle, active_sco->hci_handle); - osi_free(p_msg); + LOG_ERROR("Dropping packet with handle(0x%X) != active handle(0x%X)", + handle, active_sco->hci_handle); return; } + const auto codec_type = active_sco->get_codec_type(); + const std::string codec = sco_codec_type_text(codec_type); + + auto data = valid_packet.GetData(); + auto rx_data = data.data(); const uint8_t* decoded = nullptr; size_t written = 0, rc = 0; - if (active_sco->is_wbs()) { - uint16_t status = HCID_GET_PKT_STATUS(handle_with_flags); + if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) { + auto status = valid_packet.GetPacketStatusFlag(); - if (status > 0) LOG_DEBUG("Packet corrupted with status(0x%X)", status); - rc = bluetooth::audio::sco::wbs::enqueue_packet(payload, data_len, - status > 0); - if (rc != data_len) LOG_DEBUG("Failed to enqueue packet"); + if (status != bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED) { + LOG_DEBUG("%s packet corrupted with status(%s)", codec.c_str(), + PacketStatusFlagText(status).c_str()); + } + auto enqueue_packet = codec_type == BTM_SCO_CODEC_LC3 + ? &bluetooth::audio::sco::swb::enqueue_packet + : &bluetooth::audio::sco::wbs::enqueue_packet; + rc = enqueue_packet( + data, status != bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED); + if (!rc) LOG_DEBUG("Failed to enqueue %s packet", codec.c_str()); while (rc) { - rc = bluetooth::audio::sco::wbs::decode(&decoded); - if (rc == 0) { - LOG_DEBUG("Failed to decode frames"); - break; - } + auto decode = codec_type == BTM_SCO_CODEC_LC3 + ? &bluetooth::audio::sco::swb::decode + : &bluetooth::audio::sco::wbs::decode; + rc = decode(&decoded); + if (rc == 0) break; written += bluetooth::audio::sco::write(decoded, rc); } } else { - written = bluetooth::audio::sco::write(payload, data_len); + written = bluetooth::audio::sco::write(rx_data, data.size()); } - osi_free(p_msg); /* For Chrome OS, we send the outgoing data after receiving an incoming one. * server, so that we can keep the data read/write rate balanced */ size_t read = 0, avail = 0; const uint8_t* encoded = nullptr; - if (active_sco->is_wbs()) { + if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) { while (written) { avail = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset; if (avail) { - data_len = written < avail ? written : avail; + size_t to_read = written < avail ? written : avail; read = bluetooth::audio::sco::read( - (uint8_t*)btm_pcm_buf + btm_pcm_buf_write_offset, data_len); - if (read != data_len) { + (uint8_t*)btm_pcm_buf + btm_pcm_buf_write_offset, to_read); + if (read != to_read) { ASSERT_LOG(btm_pcm_buf_write_offset + read <= BTM_SCO_DATA_SIZE_MAX, - "Read more data (%lu) than available buffer (%lu) guarded " - "by read", - (unsigned long)read, + "Read more %s data (%lu) than available buffer (%lu) " + "guarded by read", + codec.c_str(), (unsigned long)read, (unsigned long)(BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset)); LOG_INFO( - "Requested to read %lu bytes of data but got %lu bytes of PCM " - "data from audio server: WriteOffset:%lu ReadOffset:%lu", - (unsigned long)data_len, (unsigned long)read, + "Requested to read %lu bytes of %s data but got %lu bytes of " + "PCM data from audio server: WriteOffset:%lu ReadOffset:%lu", + (unsigned long)to_read, codec.c_str(), (unsigned long)read, (unsigned long)btm_pcm_buf_write_offset, (unsigned long)btm_pcm_buf_read_offset); if (read == 0) break; @@ -307,32 +368,38 @@ void btm_route_sco_data(BT_HDR* p_msg) { } else { /* We don't break here so that we can still decode the data in the * buffer to spare the buffer space when the buffer is full */ - LOG_WARN("Buffer is full when we try to read from audio server"); + LOG_WARN( + "Buffer is full when we try to read %s packet from audio server", + codec.c_str()); ASSERT_LOG(btm_pcm_buf_write_offset - btm_pcm_buf_read_offset >= - BTM_MSBC_CODE_SIZE, - "PCM buffer is full but fails to encode a mSBC packet. " + (codec_type == BTM_SCO_CODEC_MSBC ? BTM_MSBC_CODE_SIZE + : BTM_LC3_CODE_SIZE), + "PCM buffer is full but fails to encode an %s packet. " "This is abnormal and can cause busy loop: " "WriteOffset:%lu, ReadOffset:%lu, BufferSize:%lu", - (unsigned long)btm_pcm_buf_write_offset, + codec.c_str(), (unsigned long)btm_pcm_buf_write_offset, (unsigned long)btm_pcm_buf_read_offset, (unsigned long)sizeof(btm_pcm_buf)); } btm_pcm_buf_write_offset += read; - rc = bluetooth::audio::sco::wbs::encode( - &btm_pcm_buf[btm_pcm_buf_read_offset / sizeof(*btm_pcm_buf)], - btm_pcm_buf_write_offset - btm_pcm_buf_read_offset); + + auto encode = codec_type == BTM_SCO_CODEC_LC3 + ? &bluetooth::audio::sco::swb::encode + : &bluetooth::audio::sco::wbs::encode; + rc = encode(&btm_pcm_buf[btm_pcm_buf_read_offset / sizeof(*btm_pcm_buf)], + btm_pcm_buf_write_offset - btm_pcm_buf_read_offset); if (!rc) LOG_DEBUG( - "Failed to encode data starting at ReadOffset:%lu to " + "Failed to encode %s data starting at ReadOffset:%lu to " "WriteOffset:%lu", - (unsigned long)btm_pcm_buf_read_offset, + codec.c_str(), (unsigned long)btm_pcm_buf_read_offset, (unsigned long)btm_pcm_buf_write_offset); /* The offsets should reset some time as the buffer length should always - * divisible by BTM_MSBC_CODE_SIZE(240) and wbs::encode only returns - * BTM_MSBC_CODE_SIZE or 0 */ + * divisible by 480 and `encode` only returns 480(LC3), 240(MSBC), or 0. + */ btm_pcm_buf_read_offset += rc; if (btm_pcm_buf_write_offset == btm_pcm_buf_read_offset) { btm_pcm_buf_write_offset = 0; @@ -341,7 +408,10 @@ void btm_route_sco_data(BT_HDR* p_msg) { /* Send all of the available SCO packets buffered in the queue */ while (1) { - rc = bluetooth::audio::sco::wbs::dequeue_packet(&encoded); + auto dequeue_packet = codec_type == BTM_SCO_CODEC_LC3 + ? &bluetooth::audio::sco::swb::dequeue_packet + : &bluetooth::audio::sco::wbs::dequeue_packet; + rc = dequeue_packet(&encoded); if (!rc) break; auto data = std::vector(encoded, encoded + rc); @@ -378,23 +448,20 @@ void btm_send_sco_packet(std::vector data) { if (active_sco == nullptr || data.empty()) { return; } - BT_HDR* packet = btm_sco_make_packet(std::move(data), active_sco->hci_handle); - bte_main_hci_send(packet, BT_EVT_TO_LM_HCI_SCO); -} - -// Build a SCO packet from uint8 -BT_HDR* btm_sco_make_packet(std::vector data, uint16_t sco_handle) { ASSERT_LOG(data.size() <= BTM_SCO_DATA_SIZE_MAX, "Invalid SCO data size: %lu", (unsigned long)data.size()); - BT_HDR* p_buf = (BT_HDR*)osi_calloc(BT_SMALL_BUFFER_SIZE); - p_buf->event = BT_EVT_TO_LM_HCI_SCO; - // SCO header size is 3 per Core 5.2 Vol 4 Part E 5.4.3 figure 5.3 - p_buf->len = data.size() + 3; - uint8_t* payload = p_buf->data; - UINT16_TO_STREAM(payload, sco_handle); - UINT8_TO_STREAM(payload, data.size()); - ARRAY_TO_STREAM(payload, data.data(), static_cast(data.size())); - return p_buf; + + uint16_t handle_with_flags = active_sco->hci_handle; + uint16_t handle = HCID_GET_HANDLE(handle_with_flags); + ASSERT_LOG(handle <= HCI_HANDLE_MAX, "Require handle <= 0x%X, but is 0x%X", + HCI_HANDLE_MAX, handle); + + auto sco_packet = bluetooth::hci::ScoBuilder::Create( + handle, bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED, + std::move(data)); + + cpp::pending_sco_data->Enqueue(std::move(sco_packet), + bluetooth::shim::GetGdShimHandler()); } /******************************************************************************* @@ -434,18 +501,18 @@ static tBTM_STATUS btm_send_connect_request(uint16_t acl_handle, /* UPF25: Only SCO was brought up in this case */ const RawAddress bd_addr = acl_address_from_handle(acl_handle); if (bd_addr != RawAddress::kEmpty) { - if (!sco_peer_supports_esco_2m_phy(bd_addr)) { - BTM_TRACE_DEBUG("BTM Remote does not support 2-EDR eSCO"); + if (!btm_peer_supports_esco_2m_phy(bd_addr)) { + LOG_VERBOSE("BTM Remote does not support 2-EDR eSCO"); temp_packet_types |= (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5); } - if (!sco_peer_supports_esco_3m_phy(bd_addr)) { - BTM_TRACE_DEBUG("BTM Remote does not support 3-EDR eSCO"); + if (!btm_peer_supports_esco_3m_phy(bd_addr)) { + LOG_VERBOSE("BTM Remote does not support 3-EDR eSCO"); temp_packet_types |= (ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV5); } - if (!sco_peer_supports_esco_ev3(bd_addr)) { - BTM_TRACE_DEBUG("BTM Remote does not support EV3 eSCO"); + if (!btm_peer_supports_esco_ev3(bd_addr)) { + LOG_VERBOSE("BTM Remote does not support EV3 eSCO"); // If EV3 is not supported, EV4 and EV% are not supported, either. temp_packet_types &= ~BTM_ESCO_LINK_ONLY_MASK; p_setup->retransmission_effort = ESCO_RETRANSMISSION_OFF; @@ -661,8 +728,8 @@ tBTM_STATUS BTM_CreateSco(const RawAddress* remote_bda, bool is_orig, /* If role change is in progress, do not proceed with SCO setup * Wait till role change is complete */ if (!acl_is_switch_role_idle(*remote_bda, BT_TRANSPORT_BR_EDR)) { - BTM_TRACE_API("Role Change is in progress for ACL handle 0x%04x", - acl_handle); + LOG_VERBOSE("Role Change is in progress for ACL handle 0x%04x", + acl_handle); p->state = SCO_ST_PEND_ROLECHANGE; } } @@ -757,7 +824,7 @@ void btm_sco_chk_pend_rolechange(uint16_t hci_handle) { p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle)) { - BTM_TRACE_API( + LOG_VERBOSE( "btm_sco_chk_pend_rolechange -> (e)SCO Link for ACL handle 0x%04x", acl_handle); @@ -867,8 +934,7 @@ void btm_sco_conn_req(const RawAddress& bda, const DEV_CLASS& dev_class, } /* If here, no one wants the SCO connection. Reject it */ - BTM_TRACE_WARNING("%s: rejecting SCO for %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(bda)); + LOG_WARN("%s: rejecting SCO for %s", __func__, ADDRESS_TO_LOGGABLE_CSTR(bda)); btm_esco_conn_rsp(BTM_MAX_SCO_LINKS, HCI_ERR_HOST_REJECT_RESOURCES, bda, nullptr); } @@ -898,6 +964,8 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, BTM_LogHistory( kBtmLogTag, bda, "Connection created", base::StringPrintf("sco_idx:%hu handle:0x%04x ", xx, hci_handle)); + power_telemetry::GetInstance().LogLinkDetails(hci_handle, bda, true, + false); if (p->state == SCO_ST_LISTENING) spt = true; @@ -907,6 +975,8 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, BTM_LogHistory(kBtmLogTag, bda, "Connection success", base::StringPrintf("handle:0x%04x %s", hci_handle, (spt) ? "listener" : "initiator")); + LOG_DEBUG("Connected SCO link handle:0x%04x peer:%s", hci_handle, + ADDRESS_TO_LOGGABLE_CSTR(bda)); if (!btm_cb.sco_cb.esco_supported) { p->esco.data.link_type = BTM_LINK_TYPE_SCO; @@ -931,11 +1001,15 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, /* In-band (non-offload) data path */ if (p->is_inband()) { - if (p->is_wbs()) { + const auto codec_type = p->get_codec_type(); + if (codec_type == BTM_SCO_CODEC_MSBC || + codec_type == BTM_SCO_CODEC_LC3) { btm_pcm_buf_read_offset = 0; btm_pcm_buf_write_offset = 0; - bluetooth::audio::sco::wbs::init( - hfp_hal_interface::get_packet_size(codec)); + auto init = codec_type == BTM_SCO_CODEC_LC3 + ? &bluetooth::audio::sco::swb::init + : &bluetooth::audio::sco::wbs::init; + init(hfp_hal_interface::get_packet_size(codec)); } std::fill(std::begin(btm_pcm_buf), std::end(btm_pcm_buf), 0); @@ -1028,7 +1102,7 @@ tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) { tSCO_CONN* p = &btm_cb.sco_cb.sco_db[sco_inx]; tBTM_PM_STATE state = BTM_PM_ST_INVALID; - BTM_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (BTM_MAX_SCO_LINKS == 0) { return BTM_NO_RESOURCES; @@ -1048,8 +1122,8 @@ tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) { if (BTM_ReadPowerMode(p->esco.data.bd_addr, &state) && (state == BTM_PM_ST_PENDING)) { - BTM_TRACE_DEBUG("%s: BTM_PM_ST_PENDING for ACL mapped with SCO Link 0x%04x", - __func__, p->hci_handle); + LOG_VERBOSE("%s: BTM_PM_ST_PENDING for ACL mapped with SCO Link 0x%04x", + __func__, p->hci_handle); p->state = SCO_ST_PEND_MODECHANGE; return (BTM_CMD_STARTED); } @@ -1057,7 +1131,7 @@ tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) { tSCO_STATE old_state = p->state; p->state = SCO_ST_DISCONNECTING; - GetLegacyHciInterface().Disconnect(p->Handle(), HCI_ERR_PEER_USER); + GetInterface().Disconnect(p->Handle(), HCI_ERR_PEER_USER); LOG_DEBUG("Disconnecting link sco_handle:0x%04x peer:%s", p->Handle(), ADDRESS_TO_LOGGABLE_CSTR(p->esco.data.bd_addr)); @@ -1097,6 +1171,8 @@ bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason) { for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) { if ((p->state != SCO_ST_UNUSED) && (p->state != SCO_ST_LISTENING) && (p->hci_handle == hci_handle)) { + power_telemetry::GetInstance().LogLinkDetails( + hci_handle, RawAddress::kEmpty, false, false); RawAddress bda(p->esco.data.bd_addr); p->state = SCO_ST_UNUSED; p->hci_handle = HCI_INVALID_HANDLE; @@ -1169,18 +1245,32 @@ void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) { p_sco->esco.setup.transmit_coding_format.coding_format)); if (p_sco->is_inband()) { - if (p_sco->is_wbs()) { + const auto codec_type = p_sco->get_codec_type(); + if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) { + auto fill_plc_stats = codec_type == BTM_SCO_CODEC_LC3 + ? bluetooth::audio::sco::swb::fill_plc_stats + : bluetooth::audio::sco::wbs::fill_plc_stats; + int num_decoded_frames; double packet_loss_ratio; - if (bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames, - &packet_loss_ratio)) { + if (fill_plc_stats(&num_decoded_frames, &packet_loss_ratio)) { + const int16_t codec_id = sco_codec_type_to_id(codec_type); + const std::string codec = sco_codec_type_text(codec_type); log_hfp_audio_packet_loss_stats(bd_addr, num_decoded_frames, - packet_loss_ratio); + packet_loss_ratio, codec_id); + LOG_DEBUG( + "Stopped SCO codec:%s, num_decoded_frames:%d, " + "packet_loss_ratio:%lf", + codec.c_str(), num_decoded_frames, packet_loss_ratio); } else { LOG_WARN("Failed to get the packet loss stats"); } - bluetooth::audio::sco::wbs::cleanup(); + auto cleanup = codec_type == BTM_SCO_CODEC_LC3 + ? bluetooth::audio::sco::swb::cleanup + : bluetooth::audio::sco::wbs::cleanup; + + cleanup(); } bluetooth::audio::sco::cleanup(); @@ -1353,14 +1443,14 @@ static tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx, p_parms->packet_types & (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_LINK_ONLY_MASK); - BTM_TRACE_API("%s: SCO Link for handle 0x%04x, pkt 0x%04x", __func__, - p_sco->hci_handle, p_setup->packet_types); + LOG_VERBOSE("%s: SCO Link for handle 0x%04x, pkt 0x%04x", __func__, + p_sco->hci_handle, p_setup->packet_types); - BTM_TRACE_API("%s: SCO Link for handle 0x%04x, pkt 0x%04x", __func__, - p_sco->hci_handle, p_setup->packet_types); + LOG_VERBOSE("%s: SCO Link for handle 0x%04x, pkt 0x%04x", __func__, + p_sco->hci_handle, p_setup->packet_types); - btsnd_hcic_change_conn_type(p_sco->hci_handle, - BTM_ESCO_2_SCO(p_setup->packet_types)); + GetInterface().ChangeConnectionPacketType( + p_sco->hci_handle, BTM_ESCO_2_SCO(p_setup->packet_types)); } else /* eSCO is supported and the link type is eSCO */ { uint16_t temp_packet_types = @@ -1373,13 +1463,12 @@ static tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx, (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK)); p_setup->packet_types = temp_packet_types; - BTM_TRACE_API("%s -> eSCO Link for handle 0x%04x", __func__, - p_sco->hci_handle); - BTM_TRACE_API( - " txbw 0x%x, rxbw 0x%x, lat 0x%x, retrans 0x%02x, pkt 0x%04x", - p_setup->transmit_bandwidth, p_setup->receive_bandwidth, - p_parms->max_latency_ms, p_parms->retransmission_effort, - temp_packet_types); + LOG_VERBOSE("%s -> eSCO Link for handle 0x%04x", __func__, + p_sco->hci_handle); + LOG_VERBOSE(" txbw 0x%x, rxbw 0x%x, lat 0x%x, retrans 0x%02x, pkt 0x%04x", + p_setup->transmit_bandwidth, p_setup->receive_bandwidth, + p_parms->max_latency_ms, p_parms->retransmission_effort, + temp_packet_types); /* Use Enhanced Synchronous commands if supported */ if (controller_get_interface() @@ -1400,7 +1489,7 @@ static tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx, p_setup->packet_types); } - BTM_TRACE_API( + LOG_VERBOSE( "%s: txbw 0x%x, rxbw 0x%x, lat 0x%x, retrans 0x%02x, pkt 0x%04x", __func__, p_setup->transmit_bandwidth, p_setup->receive_bandwidth, p_parms->max_latency_ms, p_parms->retransmission_effort, @@ -1595,6 +1684,7 @@ static uint16_t btm_sco_voice_settings_to_legacy(enh_esco_params_t* p_params) { case ESCO_CODING_FORMAT_TRANSPNT: case ESCO_CODING_FORMAT_MSBC: + case ESCO_CODING_FORMAT_LC3: voice_settings |= HCI_AIR_CODING_FORMAT_TRANSPNT; break; @@ -1612,8 +1702,85 @@ static uint16_t btm_sco_voice_settings_to_legacy(enh_esco_params_t* p_params) { else /* Use 8 bit for all others */ voice_settings |= HCI_INP_SAMPLE_SIZE_8BIT; - BTM_TRACE_DEBUG("%s: voice setting for legacy 0x%03x", __func__, - voice_settings); + LOG_VERBOSE("%s: voice setting for legacy 0x%03x", __func__, voice_settings); return (voice_settings); } +/******************************************************************************* + * + * Function BTM_GetScoDebugDump + * + * Description Get the status of SCO. This function is only used for + * testing and debugging purposes. + * + * Returns Data with SCO related debug dump. + * + ******************************************************************************/ +tBTM_SCO_DEBUG_DUMP BTM_GetScoDebugDump() { + tSCO_CONN* active_sco = btm_get_active_sco(); + tBTM_SCO_DEBUG_DUMP debug_dump = {}; + + debug_dump.is_active = active_sco != nullptr; + if (!debug_dump.is_active) return debug_dump; + + tBTM_SCO_CODEC_TYPE codec_type = active_sco->get_codec_type(); + debug_dump.codec_id = sco_codec_type_to_id(codec_type); + if (debug_dump.codec_id != UUID_CODEC_MSBC && + debug_dump.codec_id != UUID_CODEC_LC3) + return debug_dump; + + auto fill_plc_stats = debug_dump.codec_id == UUID_CODEC_LC3 + ? &bluetooth::audio::sco::swb::fill_plc_stats + : &bluetooth::audio::sco::wbs::fill_plc_stats; + + if (!fill_plc_stats(&debug_dump.total_num_decoded_frames, + &debug_dump.pkt_loss_ratio)) + return debug_dump; + + auto get_pkt_status = debug_dump.codec_id == UUID_CODEC_LC3 + ? &bluetooth::audio::sco::swb::get_pkt_status + : &bluetooth::audio::sco::wbs::get_pkt_status; + + tBTM_SCO_PKT_STATUS* pkt_status = get_pkt_status(); + if (pkt_status == nullptr) return debug_dump; + + tBTM_SCO_PKT_STATUS_DATA* data = &debug_dump.latest_data; + data->begin_ts_raw_us = pkt_status->begin_ts_raw_us(); + data->end_ts_raw_us = pkt_status->end_ts_raw_us(); + data->status_in_hex = pkt_status->data_to_hex_string(); + data->status_in_binary = pkt_status->data_to_binary_string(); + return debug_dump; +} + +bool btm_peer_supports_esco_2m_phy(RawAddress remote_bda) { + uint8_t* features = BTM_ReadRemoteFeatures(remote_bda); + if (features == nullptr) { + LOG_WARN( + "Checking remote features but remote feature read is " + "incomplete"); + return false; + } + return HCI_EDR_ESCO_2MPS_SUPPORTED(features); +} + +bool btm_peer_supports_esco_3m_phy(RawAddress remote_bda) { + uint8_t* features = BTM_ReadRemoteFeatures(remote_bda); + if (features == nullptr) { + LOG_WARN( + "Checking remote features but remote feature read is " + "incomplete"); + return false; + } + return HCI_EDR_ESCO_3MPS_SUPPORTED(features); +} + +bool btm_peer_supports_esco_ev3(RawAddress remote_bda) { + uint8_t* features = BTM_ReadRemoteFeatures(remote_bda); + if (features == nullptr) { + LOG_WARN( + "Checking remote features but remote feature read is " + "incomplete"); + return false; + } + return HCI_ESCO_EV3_SUPPORTED(features); +} diff --git a/system/stack/btm/btm_sco.h b/system/stack/btm/btm_sco.h index c4e286c279795480bd0bc999b6f4215dabb4f2e4..2ee6ecc2288686fe6c8723902bed8e7641cbe79a 100644 --- a/system/stack/btm/btm_sco.h +++ b/system/stack/btm/btm_sco.h @@ -19,11 +19,16 @@ #include #include -#include "btm_sco_hfp_hal.h" #include "device/include/esco_parameters.h" +#include "include/check.h" +#include "internal_include/bt_target.h" +#include "macros.h" +#include "raw_address.h" +#include "stack/btm/sco_pkt_status.h" #include "stack/include/btm_api_types.h" #define BTM_MSBC_CODE_SIZE 240 +#define BTM_LC3_CODE_SIZE 480 constexpr uint16_t kMaxScoLinks = static_cast(BTM_MAX_SCO_LINKS); @@ -75,14 +80,12 @@ bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio); /* Try to enqueue a packet to a buffer. * Args: - * data - Pointer to received packet data bytes. - * pkt_size - Length of input packet. Passing packet with inconsistent size - * from the pkt_size set in init() will fail the call. + * data - Vector of received packet data bytes. * corrupted - If the current mSBC packet read is corrupted. * Returns: - * The length of enqueued bytes. 0 if failed. + * true if enqueued, false if it failed. */ -size_t enqueue_packet(const uint8_t* data, size_t pkt_size, bool corrupted); +bool enqueue_packet(const std::vector& data, bool corrupted); /* Try to decode mSBC frames from the packets in the buffer. * Args: @@ -110,13 +113,81 @@ size_t encode(int16_t* data, size_t len); */ size_t dequeue_packet(const uint8_t** output); +/* Get mSBC packets' status record. + * Returns: + * Pointer to the record struct, nullptr if not valid. + */ +tBTM_SCO_PKT_STATUS* get_pkt_status(); } // namespace bluetooth::audio::sco::wbs -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif +/* SCO-over-HCI audio HFP SWB related definitions */ +namespace bluetooth::audio::sco::swb { + +/* Initialize struct used for storing SWB related information. + * Args: + * pkt_size - Length of the SCO packet. It is determined based on the BT-USB + * adapter's capability and alt mode setting. The value should be queried + * from HAL interface. It will be used to determine the size of the SCO + * packet buffer. Currently, the stack only supports 60 and 72. + * Returns: + * The selected packet size. Will fallback to the typical LC3 packet + * length(60) if the pkt_size argument is not supported. + */ +size_t init(size_t pkt_size); + +/* Clean up when the SCO connection is done */ +void cleanup(); + +/* Fill in packet loss stats + * Args: + * num_decoded_frames - Output argument for the number of decode frames + * packet_loss_ratio - Output argument for the ratio of lost frames + * Returns: + * False for invalid arguments or unreasonable stats. True otherwise. + */ +bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio); + +/* Try to enqueue a packet to a buffer. + * Args: + * data - Vector of received packet data bytes. + * corrupted - If the current LC3 packet read is corrupted. + * Returns: + * true if enqueued, false if it failed. + */ +bool enqueue_packet(const std::vector& data, bool corrupted); + +/* Try to decode LC3 frames from the packets in the buffer. + * Args: + * output - Pointer to the decoded PCM bytes caller can read from. + * Returns: + * The length of decoded bytes. 0 if failed. + */ +size_t decode(const uint8_t** output); + +/* Try to encode PCM data into one SCO packet and put the packets in the buffer. + * Args: + * data - Pointer to the input PCM bytes for the encoder to encode. + * len - Length of the input data. + * Returns: + * The length of input data that is encoded. 0 if failed. + */ +size_t encode(int16_t* data, size_t len); + +/* Dequeue a SCO packet with encoded LC3 data if possible. The length of the + * packet is determined by the pkt_size set by the init(). + * Args: + * output - Pointer to output LC3 packets encoded by the encoder. + * Returns: + * The length of dequeued packet. 0 if failed. + */ +size_t dequeue_packet(const uint8_t** output); + +/* Get LC3 packets' status record. + * Returns: + * Pointer to the record struct, nullptr if not valid. + */ +tBTM_SCO_PKT_STATUS* get_pkt_status(); +} // namespace bluetooth::audio::sco::swb /* Define the structures needed by sco */ typedef enum : uint16_t { @@ -148,8 +219,6 @@ inline std::string sco_state_text(const tSCO_STATE& state) { } } -#undef CASE_RETURN_TEXT - /* Define the structure that contains (e)SCO data */ typedef struct { tBTM_ESCO_CBACK* p_esco_cback; /* Callback for eSCO events */ @@ -171,11 +240,17 @@ typedef struct { bool is_inband() const { return esco.setup.input_data_path == ESCO_DATA_PATH_HCI; } - bool is_wbs() const { - return esco.setup.transmit_coding_format.coding_format == - ESCO_CODING_FORMAT_TRANSPNT || - esco.setup.transmit_coding_format.coding_format == - ESCO_CODING_FORMAT_MSBC; + tBTM_SCO_CODEC_TYPE get_codec_type() const { + switch (esco.setup.coding_format) { + case ESCO_CODING_FORMAT_CVSD: + return BTM_SCO_CODEC_CVSD; + case ESCO_CODING_FORMAT_MSBC: + return BTM_SCO_CODEC_MSBC; + case ESCO_CODING_FORMAT_LC3: + return BTM_SCO_CODEC_LC3; + default: + return BTM_SCO_CODEC_NONE; + } } uint16_t Handle() const { return hci_handle; } @@ -204,13 +279,9 @@ typedef struct { return nullptr; } - void Init() { - hfp_hal_interface::init(); - def_esco_parms = esco_parameters_for_codec( - ESCO_CODEC_CVSD_S3, hfp_hal_interface::get_offload_enabled()); - } + void Init(); - void Free() { bluetooth::audio::sco::cleanup(); } + void Free(); uint16_t get_index(const tSCO_CONN* p_sco) const { CHECK(p_sco != nullptr); @@ -228,8 +299,9 @@ typedef struct { void btm_sco_chk_pend_rolechange(uint16_t hci_handle); void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle); -/* Visible for test only */ -BT_HDR* btm_sco_make_packet(std::vector data, uint16_t sco_handle); - /* Send a SCO packet */ void btm_send_sco_packet(std::vector data); + +bool btm_peer_supports_esco_2m_phy(RawAddress remote_bda); +bool btm_peer_supports_esco_3m_phy(RawAddress remote_bda); +bool btm_peer_supports_esco_ev3(RawAddress remote_bda); diff --git a/system/stack/btm/btm_sco_hci.cc b/system/stack/btm/btm_sco_hci.cc index ff2be98af922c345fab8e3ac4f8258b72122e3ee..a7e39ce8c58a6419d41db312e2130f469514f148 100644 --- a/system/stack/btm/btm_sco_hci.cc +++ b/system/stack/btm/btm_sco_hci.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -28,8 +27,8 @@ #include "btif/include/core_callbacks.h" #include "btif/include/stack_manager.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/btm/btm_sco.h" #include "udrv/include/uipc.h" @@ -38,7 +37,7 @@ // TODO(b/198260375): Make SCO data owner group configurable. #define SCO_HOST_DATA_GROUP "bluetooth-audio" -/* Per Bluetooth Core v5.0 and HFP 1.7 specification. */ +/* Per Bluetooth Core v5.0 and HFP 1.9 specification. */ #define BTM_MSBC_H2_HEADER_0 0x01 #define BTM_MSBC_H2_HEADER_LEN 2 #define BTM_MSBC_PKT_LEN 60 @@ -61,6 +60,12 @@ #define BTM_PLC_WINDOW_SIZE 5 #define BTM_PLC_PL_THRESHOLD 1 +/* LC3 definitions */ +#define BTM_LC3_H2_HEADER_0 0x01 +#define BTM_LC3_H2_HEADER_LEN 2 +#define BTM_LC3_PKT_LEN 60 +#define BTM_LC3_FS 240 /* Frame Size */ + namespace { std::unique_ptr sco_uipc = nullptr; @@ -405,6 +410,7 @@ struct tBTM_MSBC_INFO { uint8_t num_encoded_msbc_pkts; /* Number of the encoded mSBC packets */ tBTM_MSBC_PLC* plc; /* PLC component to handle the packet loss of input */ + tBTM_SCO_PKT_STATUS* pkt_status; /* Record of mSBC packet status */ static size_t get_supported_packet_size(size_t pkt_size, size_t* buffer_size) { int i; @@ -457,6 +463,11 @@ struct tBTM_MSBC_INFO { } plc = (tBTM_MSBC_PLC*)osi_calloc(sizeof(*plc)); plc->init(); + + if (pkt_status) osi_free(pkt_status); + pkt_status = (tBTM_SCO_PKT_STATUS*)osi_calloc(sizeof(*pkt_status)); + pkt_status->init(); + return packet_size; } @@ -467,6 +478,7 @@ struct tBTM_MSBC_INFO { plc->deinit(); osi_free_and_reset((void**)&plc); } + if (pkt_status) osi_free_and_reset((void**)&pkt_status); } size_t decodable() { return decode_buf_wo - decode_buf_ro; } @@ -484,19 +496,18 @@ struct tBTM_MSBC_INFO { } } - size_t write(const uint8_t* input, size_t len) { - if (len > buf_size - decode_buf_wo) { + size_t write(const std::vector& input) { + if (input.size() > buf_size - decode_buf_wo) { return 0; } - std::copy(input, input + len, msbc_decode_buf + decode_buf_wo); - decode_buf_wo += len; - return len; + std::copy(input.begin(), input.end(), msbc_decode_buf + decode_buf_wo); + decode_buf_wo += input.size(); + return input.size(); } const uint8_t* find_msbc_pkt_head() { if (read_corrupted) { - LOG_DEBUG("Skip corrupted mSBC packets"); read_corrupted = false; return nullptr; } @@ -543,11 +554,6 @@ struct tBTM_MSBC_INFO { } size_t mark_pkt_dequeued() { - LOG_DEBUG( - "Try to mark an encoded packet dequeued: ro:%lu wo:%lu pkt_size:%lu", - (unsigned long)encode_buf_ro, (unsigned long)encode_buf_wo, - (unsigned long)packet_size); - if (encode_buf_wo - encode_buf_ro < packet_size) return 0; encode_buf_ro += packet_size; @@ -561,7 +567,8 @@ struct tBTM_MSBC_INFO { const uint8_t* sco_pkt_read_ptr() { if (encode_buf_wo - encode_buf_ro < packet_size) { - LOG_DEBUG("Insufficient data as a SCO packet to read."); + LOG_DEBUG("Insufficient data to dequeue. buf_wo:%zu, buf_ro:%zu", + encode_buf_wo, encode_buf_ro); return nullptr; } @@ -608,33 +615,26 @@ bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio) { return true; } -size_t enqueue_packet(const uint8_t* data, size_t pkt_size, bool corrupted) { +bool enqueue_packet(const std::vector& data, bool corrupted) { if (msbc_info == nullptr) { LOG_WARN("mSBC buffer uninitialized or cleaned"); - return 0; + return false; } - if (pkt_size != msbc_info->packet_size) { + if (data.size() != msbc_info->packet_size) { LOG_WARN( "Ignoring the coming packet with size %lu that is inconsistent with " "the HAL reported packet size %lu", - (unsigned long)pkt_size, (unsigned long)msbc_info->packet_size); - return 0; - } - - if (data == nullptr) { - LOG_WARN("Invalid data to enqueue"); - return 0; + (unsigned long)data.size(), (unsigned long)msbc_info->packet_size); + return false; } msbc_info->read_corrupted |= corrupted; - if (msbc_info->write(data, pkt_size) != pkt_size) { - LOG_DEBUG("Fail to write packet with size %lu to buffer", - (unsigned long)pkt_size); - return 0; + if (msbc_info->write(data) != data.size()) { + return false; } - return pkt_size; + return true; } size_t decode(const uint8_t** out_data) { @@ -651,15 +651,11 @@ size_t decode(const uint8_t** out_data) { } if (msbc_info->decodable() < BTM_MSBC_PKT_LEN) { - LOG_DEBUG("No complete mSBC packet to decode"); return 0; } frame_head = msbc_info->find_msbc_pkt_head(); if (frame_head == nullptr) { - LOG_DEBUG("No valid mSBC packet to decode %lu, %lu", - (unsigned long)msbc_info->decode_buf_ro, - (unsigned long)msbc_info->decode_buf_wo); /* Done with parsing the raw bytes just read. If we couldn't find a valid * mSBC frame head, we shall treat the existing BTM_MSBC_PKT_LEN length * of mSBC data as a corrupted packet and conduct the PLC. */ @@ -669,17 +665,18 @@ size_t decode(const uint8_t** out_data) { if (!GetInterfaceToProfiles()->msbcCodec->decodePacket( frame_head, msbc_info->decoded_pcm_buf, sizeof(msbc_info->decoded_pcm_buf))) { - LOG_DEBUG("Decoding mSBC packet failed"); goto packet_loss; } msbc_info->plc->handle_good_frames(msbc_info->decoded_pcm_buf); + msbc_info->pkt_status->update(false); *out_data = (const uint8_t*)msbc_info->decoded_pcm_buf; msbc_info->mark_pkt_decoded(); return BTM_MSBC_CODE_SIZE; packet_loss: msbc_info->plc->handle_bad_frames(out_data); + msbc_info->pkt_status->update(true); msbc_info->mark_pkt_decoded(); return BTM_MSBC_CODE_SIZE; } @@ -698,16 +695,11 @@ size_t encode(int16_t* data, size_t len) { } if (len < BTM_MSBC_CODE_SIZE) { - LOG_DEBUG( - "PCM frames with size %lu is insufficient to be encoded into a mSBC " - "packet", - (unsigned long)len); return 0; } pkt_body = msbc_info->fill_msbc_pkt_template(); if (pkt_body == nullptr) { - LOG_DEBUG("Failed to fill the template to fill the mSBC packet"); return 0; } @@ -735,15 +727,357 @@ size_t dequeue_packet(const uint8_t** output) { *output = msbc_info->sco_pkt_read_ptr(); if (*output == nullptr) { - LOG_DEBUG("Insufficient data to dequeue."); return 0; } return msbc_info->mark_pkt_dequeued(); } +tBTM_SCO_PKT_STATUS* get_pkt_status() { + if (msbc_info == nullptr) { + return nullptr; + } + return msbc_info->pkt_status; +} + } // namespace wbs +// TODO(b/269970706): fill `pkt_status` and allow `debug_dump` +namespace swb { + +/* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits + * sequence number 0000, 0011, 1100, 1111. */ +constexpr uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; + +/* Supported SCO packet sizes for LC3. The SWB-LC3 frame parsing + * code ties to limited packet size values. Specifically list them out + * to check against when setting packet size. The first entry is the default + * value as a fallback. */ +constexpr size_t btm_swb_supported_pkt_size[] = {BTM_LC3_PKT_LEN, 72, 0}; + +/* Buffer size should be set to least common multiple of SCO packet size and + * BTM_LC3_PKT_LEN for optimizing buffer copy. */ +constexpr size_t btm_swb_lc3_buffer_size[] = {BTM_LC3_PKT_LEN, 360, 0}; + +/* Define the structure that contains LC3 data */ +struct tBTM_LC3_INFO { + size_t packet_size; /* SCO LC3 packet size supported by lower layer */ + size_t buf_size; /* The size of the buffer, determined by the packet_size. */ + + uint8_t* lc3_decode_buf; /* Buffer to store LC3 packets to decode */ + size_t decode_buf_wo; /* Write offset of the decode buffer */ + size_t decode_buf_ro; /* Read offset of the decode buffer */ + bool read_corrupted; /* If the current LC3 packet read is corrupted */ + + uint8_t* lc3_encode_buf; /* Buffer to store the encoded SCO packets */ + size_t encode_buf_wo; /* Write offset of the encode buffer */ + size_t encode_buf_ro; /* Read offset of the encode buffer */ + + int16_t decoded_pcm_buf[BTM_LC3_FS]; /* Buffer to store decoded PCM */ + + uint8_t num_encoded_lc3_pkts; /* Number of the encoded LC3 packets */ + + tBTM_SCO_PKT_STATUS* pkt_status; /* Record of LC3 packet status */ + + static size_t get_supported_packet_size(size_t pkt_size, + size_t* buffer_size) { + int i; + for (i = 0; btm_swb_supported_pkt_size[i] != 0 && + btm_swb_supported_pkt_size[i] != pkt_size; + i++) + ; + /* In case of unsupported value, error log and fallback to + * BTM_LC3_PKT_LEN(60). */ + if (btm_swb_supported_pkt_size[i] == 0) { + LOG_WARN("Unsupported packet size %lu", (unsigned long)pkt_size); + i = 0; + } + + if (buffer_size) { + *buffer_size = btm_swb_lc3_buffer_size[i]; + } + return btm_swb_supported_pkt_size[i]; + } + + bool verify_h2_header_seq_num(const uint8_t num) { + for (int i = 0; i < 4; i++) { + if (num == btm_h2_header_frames_count[i]) { + return true; + } + } + return false; + } + + public: + size_t init(size_t pkt_size) { + decode_buf_wo = 0; + decode_buf_ro = 0; + encode_buf_wo = 0; + encode_buf_ro = 0; + + pkt_size = get_supported_packet_size(pkt_size, &buf_size); + if (pkt_size == packet_size) return packet_size; + packet_size = pkt_size; + + if (lc3_decode_buf) osi_free(lc3_decode_buf); + lc3_decode_buf = (uint8_t*)osi_calloc(buf_size); + + if (lc3_encode_buf) osi_free(lc3_encode_buf); + lc3_encode_buf = (uint8_t*)osi_calloc(buf_size); + + if (pkt_status) osi_free(pkt_status); + pkt_status = (tBTM_SCO_PKT_STATUS*)osi_calloc(sizeof(*pkt_status)); + pkt_status->init(); + + return packet_size; + } + + void deinit() { + if (lc3_decode_buf) osi_free(lc3_decode_buf); + if (lc3_encode_buf) osi_free(lc3_encode_buf); + if (pkt_status) osi_free_and_reset((void**)&pkt_status); + } + + size_t decodable() { return decode_buf_wo - decode_buf_ro; } + + uint8_t* fill_lc3_pkt_template() { + uint8_t* wp = &lc3_encode_buf[encode_buf_wo]; + if (buf_size - encode_buf_wo < BTM_LC3_PKT_LEN) { + LOG_DEBUG("Packet queue can't accommodate more packets."); + return nullptr; + } + + wp[0] = BTM_LC3_H2_HEADER_0; + wp[1] = btm_h2_header_frames_count[num_encoded_lc3_pkts % 4]; + encode_buf_wo += BTM_LC3_PKT_LEN; + + num_encoded_lc3_pkts++; + return wp + BTM_LC3_H2_HEADER_LEN; + } + + void mark_pkt_decoded() { + if (decode_buf_ro + BTM_LC3_PKT_LEN > decode_buf_wo) { + LOG_ERROR("Trying to mark read offset beyond write offset."); + return; + } + + decode_buf_ro += BTM_LC3_PKT_LEN; + if (decode_buf_ro == decode_buf_wo) { + decode_buf_ro = 0; + decode_buf_wo = 0; + } + } + + size_t write(const std::vector& input) { + if (input.size() > buf_size - decode_buf_wo) { + return 0; + } + + std::copy(input.begin(), input.end(), lc3_decode_buf + decode_buf_wo); + decode_buf_wo += input.size(); + return input.size(); + } + + const uint8_t* find_lc3_pkt_head() { + if (read_corrupted) { + read_corrupted = false; + return nullptr; + } + + size_t rp = 0; + while (rp < BTM_LC3_PKT_LEN && + decode_buf_wo - (decode_buf_ro + rp) >= BTM_LC3_PKT_LEN) { + if ((lc3_decode_buf[decode_buf_ro + rp] != BTM_LC3_H2_HEADER_0) || + !verify_h2_header_seq_num(lc3_decode_buf[decode_buf_ro + rp + 1])) { + rp++; + continue; + } + + if (rp != 0) { + LOG_WARN("Skipped %lu bytes of LC3 data ahead of a valid LC3 frame", + (unsigned long)rp); + decode_buf_ro += rp; + } + return &lc3_decode_buf[decode_buf_ro]; + } + + return nullptr; + } + + size_t mark_pkt_dequeued() { + if (encode_buf_wo - encode_buf_ro < packet_size) return 0; + + encode_buf_ro += packet_size; + if (encode_buf_ro == encode_buf_wo) { + encode_buf_ro = 0; + encode_buf_wo = 0; + } + + return packet_size; + } + + const uint8_t* sco_pkt_read_ptr() { + if (encode_buf_wo - encode_buf_ro < packet_size) { + LOG_DEBUG("Insufficient data to dequeue. buf_wo:%zu, buf_ro:%zu", + encode_buf_wo, encode_buf_ro); + return nullptr; + } + + return &lc3_encode_buf[encode_buf_ro]; + } +}; + +static tBTM_LC3_INFO* lc3_info; +static int decoded_frames; +static int lost_frames; + +size_t init(size_t pkt_size) { + GetInterfaceToProfiles()->lc3Codec->initialize(); + + decoded_frames = 0; + lost_frames = 0; + + if (lc3_info) { + LOG_WARN("Re-initiating LC3 buffer that is active or not cleaned"); + lc3_info->deinit(); + osi_free(lc3_info); + } + + lc3_info = (tBTM_LC3_INFO*)osi_calloc(sizeof(*lc3_info)); + return lc3_info->init(pkt_size); +} + +void cleanup() { + GetInterfaceToProfiles()->lc3Codec->cleanup(); + + decoded_frames = 0; + lost_frames = 0; + + if (lc3_info == nullptr) return; + + lc3_info->deinit(); + osi_free_and_reset((void**)&lc3_info); +} + +bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio) { + if (lc3_info == NULL || num_decoded_frames == NULL || + packet_loss_ratio == NULL) + return false; + + if (decoded_frames <= 0 || lost_frames < 0 || lost_frames > decoded_frames) + return false; + + *num_decoded_frames = decoded_frames; + *packet_loss_ratio = (double)lost_frames / decoded_frames; + return true; +} + +bool enqueue_packet(const std::vector& data, bool corrupted) { + if (lc3_info == nullptr) { + LOG_WARN("LC3 buffer uninitialized or cleaned"); + return false; + } + + if (data.size() != lc3_info->packet_size) { + LOG_WARN( + "Ignoring the coming packet with size %lu that is inconsistent with " + "the HAL reported packet size %lu", + (unsigned long)data.size(), (unsigned long)lc3_info->packet_size); + return false; + } + + lc3_info->read_corrupted |= corrupted; + if (lc3_info->write(data) != data.size()) { + return false; + } + + return true; +} + +size_t decode(const uint8_t** out_data) { + const uint8_t* frame_head = nullptr; + + if (lc3_info == nullptr) { + LOG_WARN("LC3 buffer uninitialized or cleaned"); + return 0; + } + + if (out_data == nullptr) { + LOG_WARN("%s Invalid output pointer", __func__); + return 0; + } + + if (lc3_info->decodable() < BTM_LC3_PKT_LEN) { + return 0; + } + + frame_head = lc3_info->find_lc3_pkt_head(); + + bool plc_conducted = !GetInterfaceToProfiles()->lc3Codec->decodePacket( + frame_head, lc3_info->decoded_pcm_buf, sizeof(lc3_info->decoded_pcm_buf)); + + lc3_info->pkt_status->update(plc_conducted); + + ++decoded_frames; + lost_frames += plc_conducted; + + *out_data = (const uint8_t*)lc3_info->decoded_pcm_buf; + lc3_info->mark_pkt_decoded(); + + return BTM_LC3_CODE_SIZE; +} + +size_t encode(int16_t* data, size_t len) { + uint8_t* pkt_body = nullptr; + if (lc3_info == nullptr) { + LOG_WARN("LC3 buffer uninitialized or cleaned"); + return 0; + } + + if (data == nullptr) { + LOG_WARN("Invalid data to encode"); + return 0; + } + + if (len < BTM_LC3_CODE_SIZE) { + return 0; + } + + pkt_body = lc3_info->fill_lc3_pkt_template(); + if (pkt_body == nullptr) { + return 0; + } + + return GetInterfaceToProfiles()->lc3Codec->encodePacket(data, pkt_body); +} + +size_t dequeue_packet(const uint8_t** output) { + if (lc3_info == nullptr) { + LOG_WARN("LC3 buffer uninitialized or cleaned"); + return 0; + } + + if (output == nullptr) { + LOG_WARN("%s Invalid output pointer", __func__); + return 0; + } + + *output = lc3_info->sco_pkt_read_ptr(); + if (*output == nullptr) { + return 0; + } + + return lc3_info->mark_pkt_dequeued(); +} + +tBTM_SCO_PKT_STATUS* get_pkt_status() { + if (lc3_info == nullptr) { + return nullptr; + } + return lc3_info->pkt_status; +} +} // namespace swb + } // namespace sco } // namespace audio } // namespace bluetooth diff --git a/system/stack/btm/btm_sco_hfp_hal.cc b/system/stack/btm/btm_sco_hfp_hal.cc index 664068b59066d670d27b88885f36ac51ea127a61..9e2496ebd0e45dd16695146e2effc0d68450162a 100644 --- a/system/stack/btm/btm_sco_hfp_hal.cc +++ b/system/stack/btm/btm_sco_hfp_hal.cc @@ -20,6 +20,7 @@ #include "common/init_flags.h" #include "device/include/esco_parameters.h" +#include "internal_include/bt_target.h" #include "osi/include/properties.h" namespace hfp_hal_interface { @@ -84,7 +85,7 @@ bool enable_offload(bool enable) { } // On Android, this is a no-op because the settings default to offloaded case. -void set_codec_datapath(esco_coding_format_t coding_format) {} +void set_codec_datapath(int codec_uuid) {} // No packet size limits on Android since it will be offloaded. int get_packet_size(int codec) { return kDefaultPacketSize; } diff --git a/system/stack/btm/btm_sco_hfp_hal.h b/system/stack/btm/btm_sco_hfp_hal.h index 1a2a720183245bcea3cda6e0fc5da99169662827..c72ebe2daa25be9175324bd001b6924e9e78f5ae 100644 --- a/system/stack/btm/btm_sco_hfp_hal.h +++ b/system/stack/btm/btm_sco_hfp_hal.h @@ -33,6 +33,7 @@ enum codec : uint64_t { CVSD = 1 << 0, MSBC_TRANSPARENT = 1 << 1, MSBC = 1 << 2, + LC3 = 1 << 3, }; struct bt_codec { @@ -55,6 +56,8 @@ constexpr inline int esco_coding_to_codec(esco_coding_format_t esco_coding) { return codec::MSBC_TRANSPARENT; case ESCO_CODING_FORMAT_MSBC: return codec::MSBC; + case ESCO_CODING_FORMAT_LC3: + return codec::LC3; // Default to CVSD encoding if unknown format. case ESCO_CODING_FORMAT_CVSD: @@ -85,7 +88,7 @@ bool get_offload_enabled(); bool enable_offload(bool enable); // Notify the codec datapath to lower layer for offload mode. -void set_codec_datapath(esco_coding_format_t coding_format); +void set_codec_datapath(int codec_uuid); // Get the maximum supported packet size from the lower layer. int get_packet_size(int codec); diff --git a/system/stack/btm/btm_sco_hfp_hal_linux.cc b/system/stack/btm/btm_sco_hfp_hal_linux.cc index 9d3db4ca607e090f86967ce37e08ec9ffac3f6c2..4853ac0aa31467a00a390c523397f2f407cfa52a 100644 --- a/system/stack/btm/btm_sco_hfp_hal_linux.cc +++ b/system/stack/btm/btm_sco_hfp_hal_linux.cc @@ -23,8 +23,11 @@ #include "btm_sco_hfp_hal.h" #include "gd/common/init_flags.h" #include "osi/include/log.h" -#include "stack/acl/acl.h" -#include "stack/include/acl_api.h" +#include "osi/include/properties.h" +#include "stack/include/hcimsgs.h" +#include "stack/include/sdpdefs.h" + +using bluetooth::legacy::hci::GetInterface; namespace hfp_hal_interface { namespace { @@ -307,8 +310,16 @@ bool get_wbs_supported() { return false; } -// Here SWB default to be false at linux, change if needed -bool get_swb_supported() { return false; } +// Check if super-wideband speech is supported on local device +bool get_swb_supported() { + for (cached_codec_info c : cached_codecs) { + // SWB runs on the same path as MSBC non-offload. + if (c.inner.codec == MSBC_TRANSPARENT) { + return true; + } + } + return false; +} // Checks the supported codecs bt_codecs get_codec_capabilities(uint64_t codecs) { @@ -354,59 +365,64 @@ static bool get_single_codec(int codec, bt_codec** out) { constexpr uint8_t OFFLOAD_DATAPATH = 0x01; // Notify the codec datapath to lower layer for offload mode -void set_codec_datapath(esco_coding_format_t coding_format) { +void set_codec_datapath(int codec_uuid) { bool found; bt_codec* codec; uint8_t codec_id; - switch (coding_format) { - case BTM_SCO_CODEC_CVSD: + if (codec_uuid == UUID_CODEC_LC3 && get_offload_enabled()) { + LOG_ERROR("Offload path for LC3 is not implemented."); + return; + } + + switch (codec_uuid) { + case UUID_CODEC_CVSD: codec_id = codec::CVSD; break; - case BTM_SCO_CODEC_MSBC: + case UUID_CODEC_MSBC: codec_id = get_offload_enabled() ? codec::MSBC : codec::MSBC_TRANSPARENT; break; + case UUID_CODEC_LC3: + codec_id = get_offload_enabled() ? codec::LC3 : codec::MSBC_TRANSPARENT; + break; default: - LOG_WARN("Unsupported format (%u). Won't set datapath.", coding_format); + LOG_WARN("Unsupported codec (%d). Won't set datapath.", codec_uuid); return; } found = get_single_codec(codec_id, &codec); if (!found) { - LOG_ERROR( - "Failed to find codec config for format (%u). Won't set datapath.", - coding_format); + LOG_ERROR("Failed to find codec config for codec (%d). Won't set datapath.", + codec_uuid); return; } - LOG_INFO("Configuring datapath for codec (%u)", codec->codec); + LOG_INFO("Configuring datapath for codec (%d)", codec_uuid); if (codec->codec == codec::MSBC && !get_offload_enabled()) { LOG_ERROR( - "Tried to configure offload data path for format (%u) with offload " + "Tried to configure offload data path for format (%d) with offload " "disabled. Won't set datapath.", - coding_format); + codec_uuid); return; } if (get_offload_enabled()) { - /* TODO(b/237373343): expect the data content to be represented differently - */ std::vector data; - switch (coding_format) { - case BTM_SCO_CODEC_CVSD: + switch (codec_uuid) { + case UUID_CODEC_CVSD: data = {0x00}; break; - case BTM_SCO_CODEC_MSBC: + case UUID_CODEC_MSBC: data = {0x01}; break; default: break; } - btm_configure_data_path(btm_data_direction::CONTROLLER_TO_HOST, - OFFLOAD_DATAPATH, data); - btm_configure_data_path(btm_data_direction::HOST_TO_CONTROLLER, - OFFLOAD_DATAPATH, data); + GetInterface().ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, + OFFLOAD_DATAPATH, data); + GetInterface().ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, + OFFLOAD_DATAPATH, data); } } @@ -429,13 +445,22 @@ void notify_sco_connection_change(RawAddress device, bool is_connected, return; } - // Default to cvsd and try to convert codec. - int converted_codec = MGMT_SCO_CODEC_CVSD; + if (codec == codec::LC3) { + LOG_ERROR("Offload path for LC3 is not implemented."); + return; + } - if (codec == codec::MSBC) { - converted_codec = MGMT_SCO_CODEC_MSBC; - } else if (codec == codec::MSBC_TRANSPARENT) { - converted_codec = MGMT_SCO_CODEC_MSBC_TRANSPARENT; + int converted_codec; + + switch (codec) { + case codec::MSBC: + converted_codec = MGMT_SCO_CODEC_MSBC; + break; + case codec::MSBC_TRANSPARENT: + converted_codec = MGMT_SCO_CODEC_MSBC_TRANSPARENT; + break; + default: + converted_codec = MGMT_SCO_CODEC_CVSD; } int ret = mgmt_notify_sco_connection_change(fd, hci, device, is_connected, diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc index c07875a8eb141790489be15e258c4a78bd460efb..67e643ebb3521d0a6de26d70bf166ef00890d86e 100644 --- a/system/stack/btm/btm_sec.cc +++ b/system/stack/btm/btm_sec.cc @@ -26,35 +26,49 @@ #include "stack/btm/btm_sec.h" +#include +#include #include #include #include #include -#include +#include +#include + +#include "bt_dev_class.h" #include "btif/include/btif_storage.h" +#include "common/init_flags.h" #include "common/metrics.h" #include "common/time_util.h" #include "device/include/controller.h" #include "device/include/device_iot_config.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" -#include "main/shim/btm_api.h" -#include "main/shim/dumpsys.h" -#include "main/shim/shim.h" #include "osi/include/allocator.h" -#include "osi/include/compat.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "osi/include/properties.h" +#include "stack/btm/btm_ble_int.h" +#include "stack/btm/btm_ble_sec.h" #include "stack/btm/btm_dev.h" +#include "stack/btm/btm_int_types.h" +#include "stack/btm/btm_sec_cb.h" +#include "stack/btm/btm_sec_int_types.h" #include "stack/btm/security_device_record.h" #include "stack/include/acl_api.h" -#include "stack/include/acl_hci_link_interface.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_api.h" +#include "stack/include/btm_ble_addr.h" +#include "stack/include/btm_ble_api.h" +#include "stack/include/btm_ble_privacy.h" +#include "stack/include/btm_log_history.h" +#include "stack/include/btm_sec_api.h" #include "stack/include/btm_status.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/hci_error_code.h" #include "stack/include/l2cap_security_interface.h" +#include "stack/include/main_thread.h" +#include "stack/include/smp_api.h" #include "stack/include/stack_metrics_logging.h" -#include "stack/smp/smp_int.h" #include "types/raw_address.h" namespace { @@ -77,19 +91,11 @@ extern tBTM_CB btm_cb; BTM_SEC_LE_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_AUTHED) void btm_inq_stop_on_ssp(void); -void btm_ble_advertiser_notify_terminated_legacy(uint8_t status, - uint16_t connection_handle); bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr); void bta_dm_remove_device(const RawAddress& bd_addr); void bta_dm_process_remove_device(const RawAddress& bd_addr); void btm_inq_clear_ssp(void); -void HACK_acl_check_sm4(tBTM_SEC_DEV_REC& p_dev_rec); - -/******************************************************************************* - * L O C A L F U N C T I O N P R O T O T Y P E S * - ******************************************************************************/ -tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm); static tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec); static bool btm_sec_start_get_name(tBTM_SEC_DEV_REC* p_dev_rec); @@ -99,9 +105,6 @@ static void btm_sec_collision_timeout(void* data); static void btm_restore_mode(void); static void btm_sec_pairing_timeout(void* data); static tBTM_STATUS btm_sec_dd_create_conn(tBTM_SEC_DEV_REC* p_dev_rec); -static void btm_sec_change_pairing_state(tBTM_PAIRING_STATE new_state); - -static const char* btm_pair_state_descr(tBTM_PAIRING_STATE state); static void btm_sec_check_pending_reqs(void); static bool btm_sec_queue_mx_request(const RawAddress& bd_addr, uint16_t psm, @@ -116,10 +119,9 @@ static tBTM_STATUS btm_sec_send_hci_disconnect(tBTM_SEC_DEV_REC* p_dev_rec, tHCI_STATUS reason, uint16_t conn_handle, std::string comment); -tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state); -static bool btm_dev_authenticated(tBTM_SEC_DEV_REC* p_dev_rec); -static bool btm_dev_encrypted(tBTM_SEC_DEV_REC* p_dev_rec); +static bool btm_dev_authenticated(const tBTM_SEC_DEV_REC* p_dev_rec); +static bool btm_dev_encrypted(const tBTM_SEC_DEV_REC* p_dev_rec); static uint16_t btm_sec_set_serv_level4_flags(uint16_t cur_security, bool is_originator); @@ -148,8 +150,8 @@ static const bool btm_sec_io_map[BTM_IO_CAP_MAX][BTM_IO_CAP_MAX] = { static void NotifyBondingChange(tBTM_SEC_DEV_REC& p_dev_rec, tHCI_STATUS status) { - if (btm_cb.api.p_auth_complete_callback != nullptr) { - (*btm_cb.api.p_auth_complete_callback)( + if (btm_sec_cb.api.p_auth_complete_callback != nullptr) { + (*btm_sec_cb.api.p_auth_complete_callback)( p_dev_rec.bd_addr, static_cast(p_dev_rec.dev_class), p_dev_rec.sec_bd_name, status); } @@ -176,8 +178,8 @@ static bool handleUnexpectedEncryptionChange() { } void NotifyBondingCanceled(tBTM_STATUS btm_status) { - if (btm_cb.api.p_bond_cancel_cmpl_callback) { - btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS); + if (btm_sec_cb.api.p_bond_cancel_cmpl_callback) { + btm_sec_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS); } } @@ -185,49 +187,67 @@ void NotifyBondingCanceled(tBTM_STATUS btm_status) { * * Function btm_dev_authenticated * - * Description check device is authenticated + * Description check device is authenticated on BR/EDR * * Returns bool true or false * ******************************************************************************/ -static bool btm_dev_authenticated(tBTM_SEC_DEV_REC* p_dev_rec) { - if (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) { - return (true); - } - return (false); +static bool btm_dev_authenticated(const tBTM_SEC_DEV_REC* p_dev_rec) { + return p_dev_rec->sec_rec.sec_flags & BTM_SEC_AUTHENTICATED; } /******************************************************************************* * * Function btm_dev_encrypted * - * Description check device is encrypted + * Description check device is encrypted on BR/EDR * * Returns bool true or false * ******************************************************************************/ -static bool btm_dev_encrypted(tBTM_SEC_DEV_REC* p_dev_rec) { - if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) { - return (true); - } - return (false); +static bool btm_dev_encrypted(const tBTM_SEC_DEV_REC* p_dev_rec) { + return p_dev_rec->sec_rec.sec_flags & BTM_SEC_ENCRYPTED; } /******************************************************************************* * * Function btm_dev_16_digit_authenticated * - * Description check device is authenticated by using 16 digit pin or MITM + * Description check device is authenticated by using 16 digit pin or MITM (BR/EDR) * * Returns bool true or false * ******************************************************************************/ -static bool btm_dev_16_digit_authenticated(tBTM_SEC_DEV_REC* p_dev_rec) { +static bool btm_dev_16_digit_authenticated(const tBTM_SEC_DEV_REC* p_dev_rec) { // BTM_SEC_16_DIGIT_PIN_AUTHED is set if MITM or 16 digit pin is used - if (p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) { - return (true); - } - return (false); + return p_dev_rec->sec_rec.sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED; +} + +static bool is_sec_state_equal(void* data, void* context) { + tBTM_SEC_DEV_REC* p_dev_rec = static_cast(data); + uint8_t* state = static_cast(context); + + if (p_dev_rec->sec_rec.sec_state == *state) return false; + + return true; +} + +/******************************************************************************* + * + * Function btm_sec_find_dev_by_sec_state + * + * Description Look for the record in the device database for the device + * which is being authenticated or encrypted + * + * Returns Pointer to the record or NULL + * + ******************************************************************************/ +static tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state) { + list_node_t* n = + list_foreach(btm_sec_cb.sec_dev_rec, is_sec_state_equal, &state); + if (n) return static_cast(list_node(n)); + + return nullptr; } /******************************************************************************* @@ -245,8 +265,8 @@ static bool access_secure_service_from_temp_bond(const tBTM_SEC_DEV_REC* p_dev_r bool locally_initiated, uint16_t security_req) { return !locally_initiated && (security_req & BTM_SEC_IN_AUTHENTICATE) && - p_dev_rec->is_device_authenticated() && - p_dev_rec->is_bond_type_temporary(); + p_dev_rec->sec_rec.is_device_authenticated() && + p_dev_rec->sec_rec.is_bond_type_temporary(); } /******************************************************************************* @@ -262,26 +282,23 @@ static bool access_secure_service_from_temp_bond(const tBTM_SEC_DEV_REC* p_dev_r * ******************************************************************************/ bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) { - BTM_TRACE_EVENT("%s application registered", __func__); - - LOG_INFO("%s p_cb_info->p_le_callback == 0x%p", __func__, - p_cb_info->p_le_callback); + LOG_INFO("p_cb_info->p_le_callback == 0x%p", p_cb_info->p_le_callback); if (p_cb_info->p_le_callback) { - BTM_TRACE_EVENT("%s SMP_Register( btm_proc_smp_cback )", __func__); + LOG_VERBOSE("SMP_Register( btm_proc_smp_cback )"); SMP_Register(btm_proc_smp_cback); Octet16 zero{0}; /* if no IR is loaded, need to regenerate all the keys */ - if (btm_cb.devcb.id_keys.ir == zero) { + if (btm_sec_cb.devcb.id_keys.ir == zero) { btm_ble_reset_id(); } } else { - LOG_WARN("%s p_cb_info->p_le_callback == NULL", __func__); + LOG_WARN("p_cb_info->p_le_callback == NULL"); } - btm_cb.api = *p_cb_info; - LOG_INFO("%s btm_cb.api.p_le_callback = 0x%p ", __func__, - btm_cb.api.p_le_callback); - BTM_TRACE_EVENT("%s application registered", __func__); + btm_sec_cb.api = *p_cb_info; + LOG_INFO("btm_sec_cb.api.p_le_callback = 0x%p ", + btm_sec_cb.api.p_le_callback); + LOG_VERBOSE("application registered"); return (true); } @@ -332,27 +349,19 @@ bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) { } bool BTM_IsEncrypted(const RawAddress& bd_addr, tBT_TRANSPORT transport) { - uint8_t flags = 0; - BTM_GetSecurityFlagsByTransport(bd_addr, &flags, transport); - return (flags & BTM_SEC_FLAG_ENCRYPTED) != 0; + return btm_sec_cb.IsDeviceEncrypted(bd_addr, transport); } bool BTM_IsLinkKeyAuthed(const RawAddress& bd_addr, tBT_TRANSPORT transport) { - uint8_t flags = 0; - BTM_GetSecurityFlagsByTransport(bd_addr, &flags, transport); - return (flags & BTM_SEC_FLAG_LKEY_AUTHED) != 0; + return btm_sec_cb.IsLinkKeyAuthenticated(bd_addr, transport); } bool BTM_IsLinkKeyKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) { - uint8_t flags = 0; - BTM_GetSecurityFlagsByTransport(bd_addr, &flags, transport); - return (flags & BTM_SEC_FLAG_LKEY_KNOWN) != 0; + return btm_sec_cb.IsLinkKeyKnown(bd_addr, transport); } bool BTM_IsAuthenticated(const RawAddress& bd_addr, tBT_TRANSPORT transport) { - uint8_t flags = 0; - BTM_GetSecurityFlagsByTransport(bd_addr, &flags, transport); - return (flags & BTM_SEC_AUTHENTICATED) != 0; + return btm_sec_cb.IsDeviceAuthenticated(bd_addr, transport); } bool BTM_CanReadDiscoverableCharacteristics(const RawAddress& bd_addr) { @@ -367,33 +376,6 @@ bool BTM_CanReadDiscoverableCharacteristics(const RawAddress& bd_addr) { } } -/******************************************************************************* - * - * Function BTM_GetSecurityFlagsByTransport - * - * Description Get security flags for the device on a particular transport - * - * Returns bool true or false is device found - * - ******************************************************************************/ -bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr, - uint8_t* p_sec_flags, - tBT_TRANSPORT transport) { - tBTM_SEC_DEV_REC* p_dev_rec; - - p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec != NULL) { - if (transport == BT_TRANSPORT_BR_EDR) - *p_sec_flags = (uint8_t)p_dev_rec->sec_flags; - else - *p_sec_flags = (uint8_t)(p_dev_rec->sec_flags >> 8); - - return (true); - } - BTM_TRACE_ERROR("BTM_GetSecurityFlags false"); - return (false); -} - /******************************************************************************* * * Function BTM_SetPinType @@ -404,23 +386,21 @@ bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr, * ******************************************************************************/ void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len) { - BTM_TRACE_API( + LOG_VERBOSE( "BTM_SetPinType: pin type %d [variable-0, fixed-1], code %s, length %d", pin_type, (char*)pin_code, pin_code_len); /* If device is not up security mode will be set as a part of startup */ - if ((btm_cb.cfg.pin_type != pin_type) && + if ((btm_sec_cb.cfg.pin_type != pin_type) && controller_get_interface()->get_is_ready()) { btsnd_hcic_write_pin_type(pin_type); } - btm_cb.cfg.pin_type = pin_type; - btm_cb.cfg.pin_code_len = pin_code_len; - memcpy(btm_cb.cfg.pin_code, pin_code, pin_code_len); + btm_sec_cb.cfg.pin_type = pin_type; + btm_sec_cb.cfg.pin_code_len = pin_code_len; + memcpy(btm_sec_cb.cfg.pin_code, pin_code, pin_code_len); } -#define BTM_NO_AVAIL_SEC_SERVICES ((uint16_t)0xffff) - /******************************************************************************* * * Function BTM_SetSecurityLevel @@ -444,119 +424,8 @@ void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len) { bool BTM_SetSecurityLevel(bool is_originator, const char* p_name, uint8_t service_id, uint16_t sec_level, uint16_t psm, uint32_t mx_proto_id, uint32_t mx_chan_id) { - tBTM_SEC_SERV_REC* p_srec; - uint16_t index; - uint16_t first_unused_record = BTM_NO_AVAIL_SEC_SERVICES; - bool record_allocated = false; - - BTM_TRACE_API("%s : sec: 0x%x", __func__, sec_level); - - /* See if the record can be reused (same service name, psm, mx_proto_id, - service_id, and mx_chan_id), or obtain the next unused record */ - - p_srec = &btm_cb.sec_serv_rec[0]; - - for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++) { - /* Check if there is already a record for this service */ - if (p_srec->security_flags & BTM_SEC_IN_USE) { - if (p_srec->psm == psm && p_srec->mx_proto_id == mx_proto_id && - service_id == p_srec->service_id && p_name && - (!strncmp(p_name, (char*)p_srec->orig_service_name, - /* strlcpy replaces end char with termination char*/ - BT_MAX_SERVICE_NAME_LEN - 1) || - !strncmp(p_name, (char*)p_srec->term_service_name, - /* strlcpy replaces end char with termination char*/ - BT_MAX_SERVICE_NAME_LEN - 1))) { - record_allocated = true; - break; - } - } - /* Mark the first available service record */ - else if (!record_allocated) { - memset(p_srec, 0, sizeof(tBTM_SEC_SERV_REC)); - record_allocated = true; - first_unused_record = index; - } - } - - if (!record_allocated) { - BTM_TRACE_WARNING("BTM_SEC_REG: Out of Service Records (%d)", - BTM_SEC_MAX_SERVICE_RECORDS); - return (record_allocated); - } - - /* Process the request if service record is valid */ - /* If a duplicate service wasn't found, use the first available */ - if (index >= BTM_SEC_MAX_SERVICE_RECORDS) { - index = first_unused_record; - p_srec = &btm_cb.sec_serv_rec[index]; - } - - p_srec->psm = psm; - p_srec->service_id = service_id; - p_srec->mx_proto_id = mx_proto_id; - - if (is_originator) { - p_srec->orig_mx_chan_id = mx_chan_id; - strlcpy((char*)p_srec->orig_service_name, p_name, - BT_MAX_SERVICE_NAME_LEN + 1); - /* clear out the old setting, just in case it exists */ - { - p_srec->security_flags &= - ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM); - } - - /* Parameter validation. Originator should not set requirements for - * incoming connections */ - sec_level &= ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | - BTM_SEC_IN_MITM | BTM_SEC_IN_MIN_16_DIGIT_PIN); - - if (btm_cb.security_mode == BTM_SEC_MODE_SP || - btm_cb.security_mode == BTM_SEC_MODE_SC) { - if (sec_level & BTM_SEC_OUT_AUTHENTICATE) sec_level |= BTM_SEC_OUT_MITM; - } - - /* Make sure the authenticate bit is set, when encrypt bit is set */ - if (sec_level & BTM_SEC_OUT_ENCRYPT) sec_level |= BTM_SEC_OUT_AUTHENTICATE; - - /* outgoing connections usually set the security level right before - * the connection is initiated. - * set it to be the outgoing service */ - btm_cb.p_out_serv = p_srec; - } else { - p_srec->term_mx_chan_id = mx_chan_id; - strlcpy((char*)p_srec->term_service_name, p_name, - BT_MAX_SERVICE_NAME_LEN + 1); - /* clear out the old setting, just in case it exists */ - { - p_srec->security_flags &= - ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM | - BTM_SEC_IN_MIN_16_DIGIT_PIN); - } - - /* Parameter validation. Acceptor should not set requirements for outgoing - * connections */ - sec_level &= - ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM); - - if (btm_cb.security_mode == BTM_SEC_MODE_SP || - btm_cb.security_mode == BTM_SEC_MODE_SC) { - if (sec_level & BTM_SEC_IN_AUTHENTICATE) sec_level |= BTM_SEC_IN_MITM; - } - - /* Make sure the authenticate bit is set, when encrypt bit is set */ - if (sec_level & BTM_SEC_IN_ENCRYPT) sec_level |= BTM_SEC_IN_AUTHENTICATE; - } - - p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE); - - LOG_DEBUG( - "[%d]: id:%d, is_orig:%s psm:0x%04x proto_id:%d chan_id:%d" - " : sec:0x%x service_name:[%s] (up to %d chars saved)", - index, service_id, logbool(is_originator).c_str(), psm, mx_proto_id, - mx_chan_id, p_srec->security_flags, p_name, BT_MAX_SERVICE_NAME_LEN); - - return (record_allocated); + return btm_sec_cb.AddService(is_originator, p_name, service_id, sec_level, + psm, mx_proto_id, mx_chan_id); } /******************************************************************************* @@ -578,22 +447,7 @@ bool BTM_SetSecurityLevel(bool is_originator, const char* p_name, * ******************************************************************************/ uint8_t BTM_SecClrService(uint8_t service_id) { - tBTM_SEC_SERV_REC* p_srec = &btm_cb.sec_serv_rec[0]; - uint8_t num_freed = 0; - int i; - - for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) { - /* Delete services with specified name (if in use and not SDP) */ - if ((p_srec->security_flags & BTM_SEC_IN_USE) && - (p_srec->psm != BT_PSM_SDP) && - (!service_id || (service_id == p_srec->service_id))) { - BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d", i, service_id); - p_srec->security_flags = 0; - num_freed++; - } - } - - return (num_freed); + return btm_sec_cb.RemoveServiceById(service_id); } /******************************************************************************* @@ -613,21 +467,7 @@ uint8_t BTM_SecClrService(uint8_t service_id) { * ******************************************************************************/ uint8_t BTM_SecClrServiceByPsm(uint16_t psm) { - tBTM_SEC_SERV_REC* p_srec = &btm_cb.sec_serv_rec[0]; - uint8_t num_freed = 0; - int i; - - for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) { - /* Delete services with specified name (if in use and not SDP) */ - if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm)) { - BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d ", i, p_srec->service_id); - p_srec->security_flags = 0; - num_freed++; - } - } - BTM_TRACE_API("BTM_SecClrServiceByPsm psm:0x%x num_freed:%d", psm, num_freed); - - return (num_freed); + return btm_sec_cb.RemoveServiceByPsm(psm); } /******************************************************************************* @@ -649,27 +489,26 @@ void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, uint8_t pin_len, uint8_t* p_pin) { tBTM_SEC_DEV_REC* p_dev_rec; - BTM_TRACE_API( + LOG_VERBOSE( "BTM_PINCodeReply(): PairState: %s PairFlags: 0x%02x PinLen:%d " "Result:%d", - btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, pin_len, - res); + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + btm_sec_cb.pairing_flags, pin_len, res); /* If timeout already expired or has been canceled, ignore the reply */ - if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) { - BTM_TRACE_WARNING("BTM_PINCodeReply() - Wrong State: %d", - btm_cb.pairing_state); + if (btm_sec_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) { + LOG_WARN("BTM_PINCodeReply() - Wrong State: %d", btm_sec_cb.pairing_state); return; } - if (bd_addr != btm_cb.pairing_bda) { - BTM_TRACE_ERROR("BTM_PINCodeReply() - Wrong BD Addr"); + if (bd_addr != btm_sec_cb.pairing_bda) { + LOG_ERROR("BTM_PINCodeReply() - Wrong BD Addr"); return; } p_dev_rec = btm_find_dev(bd_addr); if (p_dev_rec == NULL) { - BTM_TRACE_ERROR("BTM_PINCodeReply() - no dev CB"); + LOG_ERROR("BTM_PINCodeReply() - no dev CB"); return; } @@ -679,35 +518,35 @@ void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, if (res != BTM_SUCCESS) { /* if peer started dd OR we started dd and pre-fetch pin was not used send * negative reply */ - if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) || - ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && - (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE))) { + if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) || + ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && + (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE))) { /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed * event */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); acl_set_disconnect_reason(HCI_ERR_HOST_REJECT_SECURITY); btsnd_hcic_pin_code_neg_reply(bd_addr); } else { - p_dev_rec->security_required = BTM_SEC_NONE; - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + p_dev_rec->sec_rec.security_required = BTM_SEC_NONE; + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); } return; } - p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED; - p_dev_rec->pin_code_length = pin_len; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LINK_KEY_AUTHED; + p_dev_rec->sec_rec.pin_code_length = pin_len; if (pin_len >= 16) { - p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; } - if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && + if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && (p_dev_rec->hci_handle == HCI_INVALID_HANDLE) && - (!btm_cb.security_mode_changed)) { + (!btm_sec_cb.security_mode_changed)) { /* This is start of the dedicated bonding if local device is 2.0 */ - btm_cb.pin_code_len = pin_len; - memcpy(btm_cb.pin_code, p_pin, pin_len); + btm_sec_cb.pin_code_len = pin_len; + memcpy(btm_sec_cb.pin_code, p_pin, pin_len); - btm_cb.security_mode_changed = true; + btm_sec_cb.security_mode_changed = true; btsnd_hcic_write_auth_enable(true); acl_set_disconnect_reason(HCI_ERR_UNDEFINED); @@ -715,31 +554,31 @@ void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, /* if we rejected incoming connection request, we have to wait * HCI_Connection_Complete event */ /* before originating */ - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) { - BTM_TRACE_WARNING( + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) { + LOG_WARN( "BTM_PINCodeReply(): waiting HCI_Connection_Complete after rejected " "incoming connection"); /* we change state little bit early so btm_sec_connected() will originate * connection */ /* when existing ACL link is down completely */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); } /* if we already accepted incoming connection from pairing device */ else if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) { - BTM_TRACE_WARNING( + LOG_WARN( "BTM_PINCodeReply(): link is connecting so wait pin code request " "from peer"); - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); } else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) { - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); - p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED; + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED; NotifyBondingChange(*p_dev_rec, HCI_ERR_AUTH_FAILURE); } return; } - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); acl_set_disconnect_reason(HCI_SUCCESS); btsnd_hcic_pin_code_req_reply(bd_addr, pin_len, p_pin); @@ -752,68 +591,61 @@ void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, * Description this is the bond function that will start either SSP or SMP. * * Parameters: bd_addr - Address of the device to bond - * pin_len - length in bytes of the PIN Code - * p_pin - pointer to array with the PIN Code + * addr_type - type of the address + * transport - transport on which to create bond * * Note: After 2.1 parameters are not used and preserved here not to change API ******************************************************************************/ tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, uint8_t pin_len, - uint8_t* p_pin) { + tBT_TRANSPORT transport) { tBTM_SEC_DEV_REC* p_dev_rec; tBTM_STATUS status; - VLOG(1) << __func__ << " BDA: " << bd_addr; - - BTM_TRACE_DEBUG("%s: Transport used %d, bd_addr=%s", __func__, transport, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_INFO("Transport used %d, bd_addr=%s", transport, + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); /* Other security process is in progress */ - if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) { - BTM_TRACE_ERROR("BTM_SecBond: already busy in state: %s", - btm_pair_state_descr(btm_cb.pairing_state)); + if (btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) { + LOG_ERROR("BTM_SecBond: already busy in state: %s", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state)); return (BTM_WRONG_MODE); } p_dev_rec = btm_find_or_alloc_dev(bd_addr); if (p_dev_rec == NULL) { + LOG_ERROR("No memory to allocate new p_dev_rec"); return (BTM_NO_RESOURCES); } if (!controller_get_interface()->get_is_ready()) { - BTM_TRACE_ERROR("%s controller module is not ready", __func__); + LOG_ERROR("controller module is not ready"); return (BTM_NO_RESOURCES); } - BTM_TRACE_DEBUG("before update sec_flags=0x%x", p_dev_rec->sec_flags); + LOG_VERBOSE("before update sec_flags=0x%x", p_dev_rec->sec_rec.sec_flags); /* Finished if connection is active and already paired */ if (((p_dev_rec->hci_handle != HCI_INVALID_HANDLE) && transport == BT_TRANSPORT_BR_EDR && - (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) || + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_AUTHENTICATED)) || ((p_dev_rec->ble_hci_handle != HCI_INVALID_HANDLE) && transport == BT_TRANSPORT_LE && - (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))) { - BTM_TRACE_WARNING("BTM_SecBond -> Already Paired"); + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_AUTHENTICATED))) { + LOG_WARN("BTM_SecBond -> Already Paired"); return (BTM_SUCCESS); } /* Tell controller to get rid of the link key if it has one stored */ - if ((BTM_DeleteStoredLinkKey(&bd_addr, NULL)) != BTM_SUCCESS) + if ((BTM_DeleteStoredLinkKey(&bd_addr, NULL)) != BTM_SUCCESS) { + LOG_ERROR("Failed to delete stored link keys"); return (BTM_NO_RESOURCES); - - /* Save the PIN code if we got a valid one */ - if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0)) { - btm_cb.pin_code_len = pin_len; - p_dev_rec->pin_code_length = pin_len; - memcpy(btm_cb.pin_code, p_pin, PIN_CODE_LEN); } - btm_cb.pairing_bda = bd_addr; + btm_sec_cb.pairing_bda = bd_addr; - btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD; + btm_sec_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD; - p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE; + p_dev_rec->sec_rec.security_required = BTM_SEC_OUT_AUTHENTICATE; p_dev_rec->is_originator = true; BTM_LogHistory(kBtmLogTag, bd_addr, "Bonding initiated", @@ -821,24 +653,24 @@ tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, if (transport == BT_TRANSPORT_LE) { btm_ble_init_pseudo_addr(p_dev_rec, bd_addr); - p_dev_rec->sec_flags &= ~BTM_SEC_LE_MASK; + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_LE_MASK; if (SMP_Pair(bd_addr, addr_type) == SMP_STARTED) { - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE; - p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_AUTHENTICATING; + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); return BTM_CMD_STARTED; } - btm_cb.pairing_flags = 0; + btm_sec_cb.pairing_flags = 0; return (BTM_NO_RESOURCES); } - p_dev_rec->sec_flags &= + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED); - BTM_TRACE_DEBUG("after update sec_flags=0x%x", p_dev_rec->sec_flags); + LOG_VERBOSE("after update sec_flags=0x%x", p_dev_rec->sec_rec.sec_flags); if (!controller_get_interface()->supports_simple_pairing()) { /* The special case when we authenticate keyboard. Set pin type to fixed */ /* It would be probably better to do it from the application, but it is */ @@ -846,63 +678,62 @@ tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL) && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD) && - (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) { - btm_cb.pin_type_changed = true; + (btm_sec_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) { + btm_sec_cb.pin_type_changed = true; btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED); } } - BTM_TRACE_EVENT("BTM_SecBond: Remote sm4: 0x%x HCI Handle: 0x%04x", - p_dev_rec->sm4, p_dev_rec->hci_handle); + LOG_VERBOSE("BTM_SecBond: Remote sm4: 0x%x HCI Handle: 0x%04x", + p_dev_rec->sm4, p_dev_rec->hci_handle); #if (BTM_SEC_FORCE_RNR_FOR_DBOND == TRUE) - p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN; + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_NAME_KNOWN; #endif /* If connection already exists... */ if (BTM_IsAclConnectionUpAndHandleValid(bd_addr, transport)) { btm_sec_wait_and_start_authentication(p_dev_rec); - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); /* Mark lcb as bonding */ l2cu_update_lcb_4_bonding(bd_addr, true); return (BTM_CMD_STARTED); } - BTM_TRACE_DEBUG("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4); + LOG_VERBOSE("sec mode: %d sm4:x%x", btm_sec_cb.security_mode, p_dev_rec->sm4); if (!controller_get_interface()->supports_simple_pairing() || (p_dev_rec->sm4 == BTM_SM4_KNOWN)) { if (btm_sec_check_prefetch_pin(p_dev_rec)) return (BTM_CMD_STARTED); } - if ((btm_cb.security_mode == BTM_SEC_MODE_SP || - btm_cb.security_mode == BTM_SEC_MODE_SC) && + if ((btm_sec_cb.security_mode == BTM_SEC_MODE_SP || + btm_sec_cb.security_mode == BTM_SEC_MODE_SC) && BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) { /* local is 2.1 and peer is unknown */ if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) { /* we are not accepting connection request from peer * -> RNR (to learn if peer is 2.1) * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME); status = BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR); } else { /* We are accepting connection request from peer */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); status = BTM_CMD_STARTED; } - BTM_TRACE_DEBUG("State:%s sm4: 0x%x sec_state:%d", - btm_pair_state_descr(btm_cb.pairing_state), p_dev_rec->sm4, - p_dev_rec->sec_state); + LOG_VERBOSE("State:%s sm4: 0x%x sec_state:%d", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + p_dev_rec->sm4, p_dev_rec->sec_rec.sec_state); } else { /* both local and peer are 2.1 */ status = btm_sec_dd_create_conn(p_dev_rec); } if (status != BTM_CMD_STARTED) { - BTM_TRACE_ERROR( - "%s BTM_ReadRemoteDeviceName or btm_sec_dd_create_conn error: 0x%x", - __func__, (int)status); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + LOG_ERROR("BTM_ReadRemoteDeviceName or btm_sec_dd_create_conn error: 0x%x", + (int)status); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); } return status; @@ -918,14 +749,11 @@ tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, * * Parameters: bd_addr - Address of the device to bond * transport - doing SSP over BR/EDR or SMP over LE - * pin_len - length in bytes of the PIN Code - * p_pin - pointer to array with the PIN Code * * Note: After 2.1 parameters are not used and preserved here not to change API ******************************************************************************/ tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type, - uint8_t pin_len, uint8_t* p_pin) { + tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) { if (transport == BT_TRANSPORT_AUTO) { if (addr_type == BLE_ADDR_PUBLIC) { transport = @@ -942,10 +770,12 @@ tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, if ((transport == BT_TRANSPORT_LE && (dev_type & BT_DEVICE_TYPE_BLE) == 0) || (transport == BT_TRANSPORT_BR_EDR && (dev_type & BT_DEVICE_TYPE_BREDR) == 0)) { + LOG_WARN( + "Can't start bonding - requested transport and transport we've seen " + "device on don't match"); return BTM_ILLEGAL_ACTION; } - return btm_sec_bond_by_transport(bd_addr, addr_type, transport, pin_len, - p_pin); + return btm_sec_bond_by_transport(bd_addr, addr_type, transport); } /******************************************************************************* @@ -962,17 +792,17 @@ tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr) { tBTM_SEC_DEV_REC* p_dev_rec; - BTM_TRACE_API("BTM_SecBondCancel() State: %s flags:0x%x", - btm_pair_state_descr(btm_cb.pairing_state), - btm_cb.pairing_flags); + LOG_VERBOSE("BTM_SecBondCancel() State: %s flags:0x%x", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + btm_sec_cb.pairing_flags); p_dev_rec = btm_find_dev(bd_addr); - if (!p_dev_rec || btm_cb.pairing_bda != bd_addr) { + if (!p_dev_rec || btm_sec_cb.pairing_bda != bd_addr) { return BTM_UNKNOWN_ADDR; } - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_LE_ACTIVE) { - if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) { - BTM_TRACE_DEBUG("Cancel LE pairing"); + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_LE_ACTIVE) { + if (p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_AUTHENTICATING) { + LOG_VERBOSE("Cancel LE pairing"); if (SMP_PairCancel(bd_addr)) { return BTM_CMD_STARTED; } @@ -980,27 +810,27 @@ tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr) { return BTM_WRONG_MODE; } - BTM_TRACE_DEBUG("hci_handle:0x%x sec_state:%d", p_dev_rec->hci_handle, - p_dev_rec->sec_state); - if (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state && - BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) { + LOG_VERBOSE("hci_handle:0x%x sec_state:%d", p_dev_rec->hci_handle, + p_dev_rec->sec_rec.sec_state); + if (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_sec_cb.pairing_state && + BTM_PAIR_FLAGS_WE_STARTED_DD & btm_sec_cb.pairing_flags) { /* pre-fetching pin for dedicated bonding */ btm_sec_bond_cancel_complete(); return BTM_SUCCESS; } /* If this BDA is in a bonding procedure */ - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) { + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) { /* If the HCI link is up */ if (p_dev_rec->hci_handle != HCI_INVALID_HANDLE) { /* If some other thread disconnecting, we do not send second command */ - if ((p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING) || - (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH)) + if ((p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_DISCONNECTING) || + (p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH)) return (BTM_CMD_STARTED); /* If the HCI link was set up by Bonding process */ - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) return btm_sec_send_hci_disconnect( p_dev_rec, HCI_ERR_PEER_USER, p_dev_rec->hci_handle, "stack::btm::btm_sec::BTM_SecBondCancel"); @@ -1011,13 +841,13 @@ tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr) { } else /*HCI link is not up */ { /* If the HCI link creation was started by Bonding process */ - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) { + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) { btsnd_hcic_create_conn_cancel(bd_addr); return BTM_CMD_STARTED; } - if (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) { + if (btm_sec_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) { BTM_CancelRemoteDeviceName(); - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_WE_CANCEL_DD; + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_WE_CANCEL_DD; return BTM_CMD_STARTED; } return BTM_NOT_AUTHORIZED; @@ -1044,8 +874,9 @@ tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr) { tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if ((p_dev_rec != NULL) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) { - return p_dev_rec->link_key_type; + if ((p_dev_rec != NULL) && + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_KNOWN)) { + return p_dev_rec->sec_rec.link_key_type; } return BTM_LKEY_TYPE_IGNORE; } @@ -1096,21 +927,21 @@ tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, "transport:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); if (p_callback) { - do_in_main_thread(FROM_HERE, - base::Bind(p_callback, std::move(owned_bd_addr), - transport, p_ref_data, BTM_WRONG_MODE)); + do_in_main_thread( + FROM_HERE, base::BindOnce(p_callback, std::move(owned_bd_addr), + transport, p_ref_data, BTM_WRONG_MODE)); } return BTM_WRONG_MODE; } - if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) { + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_ENCRYPTED) { LOG_DEBUG( "Security Manager: BTM_SetEncryption already encrypted peer:%s " "transport:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); if (p_callback) { do_in_main_thread(FROM_HERE, - base::Bind(p_callback, std::move(owned_bd_addr), - transport, p_ref_data, BTM_SUCCESS)); + base::BindOnce(p_callback, std::move(owned_bd_addr), + transport, p_ref_data, BTM_SUCCESS)); } return BTM_SUCCESS; } @@ -1123,21 +954,21 @@ tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, "transport:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); if (p_callback) { - do_in_main_thread(FROM_HERE, - base::Bind(p_callback, std::move(owned_bd_addr), - transport, p_ref_data, BTM_WRONG_MODE)); + do_in_main_thread( + FROM_HERE, base::BindOnce(p_callback, std::move(owned_bd_addr), + transport, p_ref_data, BTM_WRONG_MODE)); } return BTM_WRONG_MODE; } - if (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED) { + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_ENCRYPTED) { LOG_DEBUG( "Security Manager: BTM_SetEncryption already encrypted peer:%s " "transport:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); if (p_callback) { do_in_main_thread(FROM_HERE, - base::Bind(p_callback, std::move(owned_bd_addr), - transport, p_ref_data, BTM_SUCCESS)); + base::BindOnce(p_callback, std::move(owned_bd_addr), + transport, p_ref_data, BTM_SUCCESS)); } return BTM_SUCCESS; } @@ -1148,18 +979,58 @@ tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, break; } - /* enqueue security request if security is active */ - if (p_dev_rec->p_callback || (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE)) { - LOG_WARN("Security Manager: BTM_SetEncryption busy, enqueue request"); - btm_sec_queue_encrypt_request(bd_addr, transport, p_callback, p_ref_data, - sec_act); - LOG_INFO("Queued start encryption"); - return BTM_CMD_STARTED; + /* Enqueue security request if security is active */ + if (bluetooth::common::init_flags::encryption_in_busy_state_is_enabled()) { + bool enqueue = false; + switch (p_dev_rec->sec_rec.sec_state) { + case BTM_SEC_STATE_AUTHENTICATING: + case BTM_SEC_STATE_DISCONNECTING_BOTH: + /* Applicable for both transports */ + enqueue = true; + break; + + case BTM_SEC_STATE_ENCRYPTING: + case BTM_SEC_STATE_DISCONNECTING: + if (transport == BT_TRANSPORT_BR_EDR) { + enqueue = true; + } + break; + + case BTM_SEC_STATE_LE_ENCRYPTING: + case BTM_SEC_STATE_DISCONNECTING_BLE: + if (transport == BT_TRANSPORT_LE) { + enqueue = true; + } + break; + + default: + if (p_dev_rec->sec_rec.p_callback != nullptr) { + enqueue = true; + } + break; + } + + if (enqueue) { + LOG_WARN("Security Manager: Enqueue request in state:%s", + security_state_text(p_dev_rec->sec_rec.sec_state).c_str()); + btm_sec_queue_encrypt_request(bd_addr, transport, p_callback, p_ref_data, + sec_act); + return BTM_CMD_STARTED; + } + } else { + if (p_dev_rec->sec_rec.p_callback || + (p_dev_rec->sec_rec.sec_state != BTM_SEC_STATE_IDLE)) { + LOG_WARN("Security Manager: BTM_SetEncryption busy, enqueue request"); + btm_sec_queue_encrypt_request(bd_addr, transport, p_callback, p_ref_data, + sec_act); + LOG_INFO("Queued start encryption"); + return BTM_CMD_STARTED; + } } - p_dev_rec->p_callback = p_callback; - p_dev_rec->p_ref_data = p_ref_data; - p_dev_rec->security_required |= + p_dev_rec->sec_rec.p_callback = p_callback; + p_dev_rec->sec_rec.p_ref_data = p_ref_data; + p_dev_rec->sec_rec.security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT); p_dev_rec->is_originator = false; @@ -1167,9 +1038,9 @@ tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, "Security Manager: BTM_SetEncryption classic_handle:0x%04x " "ble_handle:0x%04x state:%d flags:0x%x " "required:0x%x p_callback=%c", - p_dev_rec->hci_handle, p_dev_rec->ble_hci_handle, p_dev_rec->sec_state, - p_dev_rec->sec_flags, p_dev_rec->security_required, - (p_callback) ? 'T' : 'F'); + p_dev_rec->hci_handle, p_dev_rec->ble_hci_handle, + p_dev_rec->sec_rec.sec_state, p_dev_rec->sec_rec.sec_flags, + p_dev_rec->sec_rec.security_required, (p_callback) ? 'T' : 'F'); tBTM_STATUS rc = BTM_SUCCESS; switch (transport) { @@ -1202,10 +1073,11 @@ tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, LOG_DEBUG("Executing encryption callback peer:%s transport:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); - p_dev_rec->p_callback = nullptr; - do_in_main_thread(FROM_HERE, - base::Bind(p_callback, std::move(owned_bd_addr), - transport, p_dev_rec->p_ref_data, rc)); + p_dev_rec->sec_rec.p_callback = nullptr; + do_in_main_thread( + FROM_HERE, + base::BindOnce(p_callback, std::move(owned_bd_addr), transport, + p_dev_rec->sec_rec.p_ref_data, rc)); } break; } @@ -1214,8 +1086,9 @@ tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, bool BTM_SecIsSecurityPending(const RawAddress& bd_addr) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - return p_dev_rec && (p_dev_rec->is_security_state_encrypting() || - p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING); + return p_dev_rec && + (p_dev_rec->sec_rec.is_security_state_encrypting() || + p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_AUTHENTICATING); } /******************************************************************************* @@ -1226,7 +1099,7 @@ static tBTM_STATUS btm_sec_send_hci_disconnect(tBTM_SEC_DEV_REC* p_dev_rec, uint16_t conn_handle, std::string comment) { const tSECURITY_STATE old_state = - static_cast(p_dev_rec->sec_state); + static_cast(p_dev_rec->sec_rec.sec_state); const tBTM_STATUS status = BTM_CMD_STARTED; /* send HCI_Disconnect on a transport only once */ @@ -1237,7 +1110,7 @@ static tBTM_STATUS btm_sec_send_hci_disconnect(tBTM_SEC_DEV_REC* p_dev_rec, return status; } // Prepare to send disconnect on le transport - p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH; break; case BTM_SEC_STATE_DISCONNECTING_BLE: @@ -1246,7 +1119,7 @@ static tBTM_STATUS btm_sec_send_hci_disconnect(tBTM_SEC_DEV_REC* p_dev_rec, return status; } // Prepare to send disconnect on classic transport - p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH; break; case BTM_SEC_STATE_DISCONNECTING_BOTH: @@ -1254,9 +1127,9 @@ static tBTM_STATUS btm_sec_send_hci_disconnect(tBTM_SEC_DEV_REC* p_dev_rec, return status; default: - p_dev_rec->sec_state = (conn_handle == p_dev_rec->hci_handle) - ? BTM_SEC_STATE_DISCONNECTING - : BTM_SEC_STATE_DISCONNECTING_BLE; + p_dev_rec->sec_rec.sec_state = (conn_handle == p_dev_rec->hci_handle) + ? BTM_SEC_STATE_DISCONNECTING + : BTM_SEC_STATE_DISCONNECTING_BLE; break; } @@ -1281,22 +1154,24 @@ static tBTM_STATUS btm_sec_send_hci_disconnect(tBTM_SEC_DEV_REC* p_dev_rec, * ******************************************************************************/ void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr) { - BTM_TRACE_EVENT("BTM_ConfirmReqReply() State: %s Res: %u", - btm_pair_state_descr(btm_cb.pairing_state), res); + LOG_VERBOSE("BTM_ConfirmReqReply() State: %s Res: %u", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), res); /* If timeout already expired or has been canceled, ignore the reply */ - if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM) || - (btm_cb.pairing_bda != bd_addr)) { + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM) || + (btm_sec_cb.pairing_bda != bd_addr)) { LOG_WARN( - "Ignore confirm request reply as bonding has been canceled or timer " - "expired"); + "Unexpected pairing confirm for %s, pairing_state: %s, pairing_bda: %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + ADDRESS_TO_LOGGABLE_CSTR(btm_sec_cb.pairing_bda)); return; } BTM_LogHistory(kBtmLogTag, bd_addr, "Confirm reply", base::StringPrintf("status:%s", btm_status_text(res).c_str())); - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); if ((res == BTM_SUCCESS) || (res == BTM_SUCCESS_NO_SECURITY)) { acl_set_disconnect_reason(HCI_SUCCESS); @@ -1326,16 +1201,16 @@ void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr) { ******************************************************************************/ void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr, uint32_t passkey) { - BTM_TRACE_API("BTM_PasskeyReqReply: State: %s res:%d", - btm_pair_state_descr(btm_cb.pairing_state), res); + LOG_VERBOSE("BTM_PasskeyReqReply: State: %s res:%d", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), res); - if ((btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) || - (btm_cb.pairing_bda != bd_addr)) { + if ((btm_sec_cb.pairing_state == BTM_PAIR_STATE_IDLE) || + (btm_sec_cb.pairing_bda != bd_addr)) { return; } /* If timeout already expired or has been canceled, ignore the reply */ - if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) && + if ((btm_sec_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) && (res != BTM_SUCCESS)) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); if (p_dev_rec != NULL) { @@ -1348,18 +1223,18 @@ void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr, else BTM_SecBondCancel(bd_addr); - p_dev_rec->sec_flags &= + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_LINK_KEY_KNOWN); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); return; } - } else if (btm_cb.pairing_state != BTM_PAIR_STATE_KEY_ENTRY) + } else if (btm_sec_cb.pairing_state != BTM_PAIR_STATE_KEY_ENTRY) return; if (passkey > BTM_MAX_PASSKEY_VAL) res = BTM_ILLEGAL_VALUE; - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); if (res != BTM_SUCCESS) { /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed @@ -1396,13 +1271,13 @@ void BTM_ReadLocalOobData(void) { btsnd_hcic_read_local_oob_data(); } ******************************************************************************/ void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr, const Octet16& c, const Octet16& r) { - BTM_TRACE_EVENT("%s() - State: %s res: %d", __func__, - btm_pair_state_descr(btm_cb.pairing_state), res); + LOG_VERBOSE("State: %s res: %d", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), res); /* If timeout already expired or has been canceled, ignore the reply */ - if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP) return; + if (btm_sec_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP) return; - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); if (res != BTM_SUCCESS) { /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed @@ -1452,7 +1327,7 @@ bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr) { p_dev_rec = btm_find_dev(bd_addr); if (p_dev_rec == NULL) { - LOG(WARNING) << __func__ << ": unknown BDA: " << bd_addr; + LOG_WARN("unknown BDA: %s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); return false; } @@ -1493,6 +1368,16 @@ tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(const RawAddress& bd_addr) { return BT_DEVICE_TYPE_BREDR; } +/******************************************************************************* + * + * Function BTM_GetInitialSecurityMode + * + * Description This function is called to retrieve the configured + * security mode. + * + ******************************************************************************/ +uint8_t BTM_GetSecurityMode() { return btm_sec_cb.security_mode; } + /************************************************************************ * I N T E R N A L F U N C T I O N S ************************************************************************/ @@ -1511,19 +1396,22 @@ static bool btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC* p_dev_rec, uint16_t mtm_check = is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM; bool is_possible = true; - if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) { + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_KNOWN) { is_possible = false; /* Already have a link key to the connected peer. Is the link key secure *enough? ** Is a link key upgrade even possible? */ - if ((p_dev_rec->security_required & mtm_check) /* needs MITM */ - && ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) || - (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) + if ((p_dev_rec->sec_rec.security_required & mtm_check) /* needs MITM */ + && + ((p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) || + (p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) /* has unauthenticated link key */ - && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX) /* a valid peer IO cap */ - && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps])) + && (p_dev_rec->sec_rec.rmt_io_caps < + BTM_IO_CAP_MAX) /* a valid peer IO cap */ + && (btm_sec_io_map[p_dev_rec->sec_rec.rmt_io_caps] + [btm_sec_cb.devcb.loc_io_caps])) /* authenticated link key is possible */ { @@ -1534,8 +1422,8 @@ static bool btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC* p_dev_rec, is_possible = true; } } - BTM_TRACE_DEBUG("%s() is_possible: %d sec_flags: 0x%x", __func__, is_possible, - p_dev_rec->sec_flags); + LOG_VERBOSE("is_possible: %d sec_flags: 0x%x", is_possible, + p_dev_rec->sec_rec.sec_flags); return is_possible; } @@ -1551,20 +1439,21 @@ static bool btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC* p_dev_rec, ******************************************************************************/ static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC* p_dev_rec, bool is_originator) { - BTM_TRACE_DEBUG("%s()", __func__); + LOG_VERBOSE("verify whether the link key should be upgraded"); /* Only check if link key already exists */ - if (!(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) return; + if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_KNOWN)) return; if (btm_sec_is_upgrade_possible(p_dev_rec, is_originator)) { - BTM_TRACE_DEBUG("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_flags); + LOG_VERBOSE("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_rec.sec_flags); /* if the application confirms the upgrade, set the upgrade bit */ p_dev_rec->sm4 |= BTM_SM4_UPGRADE; /* Clear the link key known to go through authentication/pairing again */ - p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED); - p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED; - BTM_TRACE_DEBUG("sec_flags:0x%x", p_dev_rec->sec_flags); + p_dev_rec->sec_rec.sec_flags &= + ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED); + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_AUTHENTICATED; + LOG_VERBOSE("sec_flags:0x%x", p_dev_rec->sec_rec.sec_flags); } } @@ -1610,12 +1499,12 @@ tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( /* there are some devices (moto KRZR) which connects to several services at * the same time */ /* we will process one after another */ - if ((p_dev_rec->p_callback) || - (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)) { + if ((p_dev_rec->sec_rec.p_callback) || + (btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE)) { LOG_DEBUG("security_flags:x%x, sec_flags:x%x", security_required, - p_dev_rec->sec_flags); + p_dev_rec->sec_rec.sec_flags); rc = BTM_CMD_STARTED; - if ((btm_cb.security_mode == BTM_SEC_MODE_SERVICE) || + if ((btm_sec_cb.security_mode == BTM_SEC_MODE_SERVICE) || (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && (!btm_sec_is_upgrade_possible(p_dev_rec, is_originator)))) { @@ -1650,7 +1539,7 @@ tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( } if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) && - (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { + (p_dev_rec->sec_rec.link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { rc = BTM_CMD_STARTED; } @@ -1662,20 +1551,20 @@ tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( if (p_callback) (*p_callback)(&bd_addr, transport, (void*)p_ref_data, rc); - return (rc); + return rc; } } - btm_cb.sec_req_pending = true; + btm_sec_cb.sec_req_pending = true; return (BTM_CMD_STARTED); } /* Save the security requirements in case a pairing is needed */ - p_dev_rec->required_security_flags_for_pairing = security_required; + p_dev_rec->sec_rec.required_security_flags_for_pairing = security_required; /* Modify security_required in btm_sec_l2cap_access_req for Lisbon */ - if (btm_cb.security_mode == BTM_SEC_MODE_SP || - btm_cb.security_mode == BTM_SEC_MODE_SC) { + if (btm_sec_cb.security_mode == BTM_SEC_MODE_SP || + btm_sec_cb.security_mode == BTM_SEC_MODE_SC) { if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) { if (is_originator) { /* SM4 to SM4 -> always encrypt */ @@ -1692,32 +1581,32 @@ tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( /* the remote features are not known yet */ LOG_DEBUG( "Remote features have not yet been received sec_flags:0x%02x %s", - p_dev_rec->sec_flags, (is_originator) ? "initiator" : "acceptor"); + p_dev_rec->sec_rec.sec_flags, + (is_originator) ? "initiator" : "acceptor"); p_dev_rec->sm4 |= BTM_SM4_REQ_PEND; return (BTM_CMD_STARTED); } } - BTM_TRACE_DEBUG( - "%s() sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d", __func__, - p_dev_rec->sm4, p_dev_rec->sec_flags, security_required, - chk_acp_auth_done); + LOG_VERBOSE("sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d", + p_dev_rec->sm4, p_dev_rec->sec_rec.sec_flags, security_required, + chk_acp_auth_done); - p_dev_rec->security_required = security_required; - p_dev_rec->p_ref_data = p_ref_data; + p_dev_rec->sec_rec.security_required = security_required; + p_dev_rec->sec_rec.p_ref_data = p_ref_data; p_dev_rec->is_originator = is_originator; if (chk_acp_auth_done) { - BTM_TRACE_DEBUG( + LOG_VERBOSE( "(SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x%x, enc: " "x%x", - (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED), - (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)); + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_AUTHENTICATED), + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_ENCRYPTED)); /* SM4, but we do not know for sure which level of security we need. * as long as we have a link key, it's OK */ - if ((0 == (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) || - (0 == (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) { + if ((0 == (p_dev_rec->sec_rec.sec_flags & BTM_SEC_AUTHENTICATED)) || + (0 == (p_dev_rec->sec_rec.sec_flags & BTM_SEC_ENCRYPTED))) { rc = BTM_DELAY_CHECK; /* 2046 may report HCI_Encryption_Change and L2C Connection Request out of @@ -1725,31 +1614,29 @@ tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( because of data path issues. Delay this disconnect a little bit */ LOG_INFO( - - "%s peer should have initiated security process by now (SM4 to SM4)", - __func__); - p_dev_rec->p_callback = p_callback; - p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC; + "peer should have initiated security process by now (SM4 to SM4)"); + p_dev_rec->sec_rec.p_callback = p_callback; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_DELAY_FOR_ENC; (*p_callback)(&bd_addr, transport, p_ref_data, rc); return BTM_SUCCESS; } } - p_dev_rec->p_callback = p_callback; + p_dev_rec->sec_rec.p_callback = p_callback; if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) { - if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && - (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { + if ((p_dev_rec->sec_rec.security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->sec_rec.link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */ - if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) { + if ((p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) { p_dev_rec->sm4 |= BTM_SM4_UPGRADE; } - p_dev_rec->sec_flags &= + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_AUTHENTICATED); - BTM_TRACE_DEBUG("%s: sec_flags:0x%x", __func__, p_dev_rec->sec_flags); + LOG_VERBOSE("sec_flags:0x%x", p_dev_rec->sec_rec.sec_flags); } else { /* If we already have a link key to the connected peer, is it secure * enough? */ @@ -1759,10 +1646,10 @@ tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( rc = btm_sec_execute_procedure(p_dev_rec); if (rc != BTM_CMD_STARTED) { - BTM_TRACE_DEBUG("%s: p_dev_rec=%p, clearing callback. old p_callback=%p", - __func__, p_dev_rec, p_dev_rec->p_callback); - p_dev_rec->p_callback = NULL; - (*p_callback)(&bd_addr, transport, p_dev_rec->p_ref_data, rc); + LOG_VERBOSE("p_dev_rec=%p, clearing callback. old p_callback=%p", p_dev_rec, + p_dev_rec->sec_rec.p_callback); + p_dev_rec->sec_rec.p_callback = NULL; + (*p_callback)(&bd_addr, transport, p_dev_rec->sec_rec.p_ref_data, rc); } return (rc); @@ -1796,7 +1683,8 @@ tBTM_STATUS btm_sec_l2cap_access_req(const RawAddress& bd_addr, uint16_t psm, LOG_DEBUG("is_originator:%d, psm=0x%04x", is_originator, psm); // Find the service record for the PSM - tBTM_SEC_SERV_REC* p_serv_rec = btm_sec_find_first_serv(is_originator, psm); + tBTM_SEC_SERV_REC* p_serv_rec = + btm_sec_cb.find_first_serv_rec(is_originator, psm); // If there is no application registered with this PSM do not allow connection if (!p_serv_rec) { @@ -1813,7 +1701,7 @@ tBTM_STATUS btm_sec_l2cap_access_req(const RawAddress& bd_addr, uint16_t psm, } uint16_t security_required; - if (btm_cb.security_mode == BTM_SEC_MODE_SC) { + if (btm_sec_cb.security_mode == BTM_SEC_MODE_SC) { security_required = btm_sec_set_serv_level4_flags( p_serv_rec->security_flags, is_originator); } else { @@ -1864,14 +1752,14 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, /* there are some devices (moto phone) which connects to several services at * the same time */ /* we will process one after another */ - if ((p_dev_rec->p_callback) || - (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)) { + if ((p_dev_rec->sec_rec.p_callback) || + (btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE)) { LOG_DEBUG("Pairing in progress pairing_state:%s", - btm_pair_state_descr(btm_cb.pairing_state)); + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state)); rc = BTM_CMD_STARTED; - if ((btm_cb.security_mode == BTM_SEC_MODE_SERVICE) || + if ((btm_sec_cb.security_mode == BTM_SEC_MODE_SERVICE) || (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && (!btm_sec_is_upgrade_possible(p_dev_rec, is_originator)))) { @@ -1905,13 +1793,13 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, } } if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) && - (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { + (p_dev_rec->sec_rec.link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { rc = BTM_CMD_STARTED; } } /* the new security request */ - if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE) { + if (p_dev_rec->sec_rec.sec_state != BTM_SEC_STATE_IDLE) { LOG_DEBUG("A pending security procedure in progress"); rc = BTM_CMD_STARTED; } @@ -1922,7 +1810,7 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, { if (access_secure_service_from_temp_bond(p_dev_rec, is_originator, security_required)) { - LOG_ERROR("Trying to access a secure rfcomm service from a temp bonding, reject"); + LOG_ERROR("Trying to access a secure rfcomm service from a temp bonding, rejecting"); rc = BTM_FAILED_ON_SECURITY; } if (p_callback) { @@ -1934,7 +1822,7 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, } if ((!is_originator) && ((security_required & BTM_SEC_MODE4_LEVEL4) || - (btm_cb.security_mode == BTM_SEC_MODE_SC))) { + (btm_sec_cb.security_mode == BTM_SEC_MODE_SC))) { bool local_supports_sc = controller_get_interface()->supports_secure_connections(); /* acceptor receives service connection establishment Request for */ @@ -1960,24 +1848,24 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, security_required |= BTM_SEC_IN_MITM; } - p_dev_rec->required_security_flags_for_pairing = security_required; - p_dev_rec->security_required = security_required; + p_dev_rec->sec_rec.required_security_flags_for_pairing = security_required; + p_dev_rec->sec_rec.security_required = security_required; - if (btm_cb.security_mode == BTM_SEC_MODE_SP || - btm_cb.security_mode == BTM_SEC_MODE_SC) { + if (btm_sec_cb.security_mode == BTM_SEC_MODE_SP || + btm_sec_cb.security_mode == BTM_SEC_MODE_SC) { if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) { - if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && - (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { + if ((p_dev_rec->sec_rec.security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->sec_rec.link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */ - if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) { + if ((p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) { p_dev_rec->sm4 |= BTM_SM4_UPGRADE; } - p_dev_rec->sec_flags &= + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_AUTHENTICATED); - BTM_TRACE_DEBUG("%s: sec_flags:0x%x", __func__, p_dev_rec->sec_flags); + LOG_VERBOSE("sec_flags:0x%x", p_dev_rec->sec_rec.sec_flags); } else { LOG_DEBUG("Already have link key; checking if link key is sufficient"); btm_sec_check_upgrade(p_dev_rec, is_originator); @@ -1986,8 +1874,8 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, } p_dev_rec->is_originator = is_originator; - p_dev_rec->p_callback = p_callback; - p_dev_rec->p_ref_data = p_ref_data; + p_dev_rec->sec_rec.p_callback = p_callback; + p_dev_rec->sec_rec.p_ref_data = p_ref_data; rc = btm_sec_execute_procedure(p_dev_rec); LOG_DEBUG("Started security procedure peer:%s btm_status:%s", @@ -1995,7 +1883,7 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, btm_status_text(rc).c_str()); if (rc != BTM_CMD_STARTED) { if (p_callback) { - p_dev_rec->p_callback = NULL; + p_dev_rec->sec_rec.p_callback = NULL; (*p_callback)(&bd_addr, transport, p_ref_data, rc); } } @@ -2013,38 +1901,26 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, * Returns void * ******************************************************************************/ -void btm_sec_conn_req(const RawAddress& bda, uint8_t* dc) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda); - - /* Some device may request a connection before we are done with the HCI_Reset - * sequence */ - if (!controller_get_interface()->get_is_ready()) { - BTM_TRACE_EVENT("Security Manager: connect request when device not ready"); - btsnd_hcic_reject_conn(bda, HCI_ERR_HOST_REJECT_DEVICE); - return; - } +void btm_sec_conn_req(const RawAddress& bda, const DEV_CLASS dc) { + tBTM_SEC_DEV_REC* p_dev_rec = nullptr; - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && - (btm_cb.pairing_bda == bda)) { - BTM_TRACE_EVENT( - "Security Manager: reject connect request from bonding device"); + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && + (btm_sec_cb.pairing_bda == bda)) { + LOG_VERBOSE("Security Manager: reject connect request from bonding device"); /* incoming connection from bonding device is rejected */ - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_REJECTED_CONNECT; + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_REJECTED_CONNECT; btsnd_hcic_reject_conn(bda, HCI_ERR_HOST_REJECT_DEVICE); return; } /* Host is not interested or approved connection. Save BDA and DC and */ /* pass request to L2CAP */ - btm_cb.connecting_bda = bda; - memcpy(btm_cb.connecting_dc, dc, DEV_CLASS_LEN); + btm_sec_cb.connecting_bda = bda; + memcpy(btm_sec_cb.connecting_dc, &dc, DEV_CLASS_LEN); - if (!p_dev_rec) { - /* accept the connection -> allocate a device record */ - p_dev_rec = btm_sec_alloc_dev(bda); - } + p_dev_rec = btm_find_or_alloc_dev(bda); p_dev_rec->sm4 |= BTM_SM4_CONN_PEND; } @@ -2061,11 +1937,11 @@ void btm_sec_conn_req(const RawAddress& bda, uint8_t* dc) { static void btm_sec_bond_cancel_complete(void) { tBTM_SEC_DEV_REC* p_dev_rec; - if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) || - (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state && - BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) || - (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME && - BTM_PAIR_FLAGS_WE_CANCEL_DD & btm_cb.pairing_flags)) { + if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) || + (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_sec_cb.pairing_state && + BTM_PAIR_FLAGS_WE_STARTED_DD & btm_sec_cb.pairing_flags) || + (btm_sec_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME && + BTM_PAIR_FLAGS_WE_CANCEL_DD & btm_sec_cb.pairing_flags)) { /* for dedicated bonding in legacy mode, authentication happens at "link * level" * btm_sec_connected is called with failed status. @@ -2075,13 +1951,13 @@ static void btm_sec_bond_cancel_complete(void) { * btm_sec_connected would not know * this function also needs to do proper clean up. */ - p_dev_rec = btm_find_dev(btm_cb.pairing_bda); - if (p_dev_rec != NULL) p_dev_rec->security_required = BTM_SEC_NONE; - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + p_dev_rec = btm_find_dev(btm_sec_cb.pairing_bda); + if (p_dev_rec != NULL) p_dev_rec->sec_rec.security_required = BTM_SEC_NONE; + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); /* Notify application that the cancel succeeded */ - if (btm_cb.api.p_bond_cancel_cmpl_callback) - btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS); + if (btm_sec_cb.api.p_bond_cancel_cmpl_callback) + btm_sec_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS); } } @@ -2096,19 +1972,10 @@ static void btm_sec_bond_cancel_complete(void) { * Returns void * ******************************************************************************/ -void btm_create_conn_cancel_complete(const uint8_t* p, uint16_t evt_len) { - uint8_t status; - - if (evt_len < 1 + BD_ADDR_LEN) { - BTM_TRACE_ERROR("%s malformatted event packet, too short", __func__); - return; - } - - STREAM_TO_UINT8(status, p); - RawAddress bd_addr; - STREAM_TO_BDADDR(bd_addr, p); - BTM_TRACE_EVENT("btm_create_conn_cancel_complete(): in State: %s status:%d", - btm_pair_state_descr(btm_cb.pairing_state), status); +void btm_create_conn_cancel_complete(uint8_t status, const RawAddress bd_addr) { + LOG_VERBOSE("btm_create_conn_cancel_complete(): in State: %s status:%d", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + status); log_link_layer_connection_event( &bd_addr, bluetooth::common::kUnknownConnectionHandle, android::bluetooth::DIRECTION_OUTGOING, android::bluetooth::LINK_TYPE_ACL, @@ -2128,8 +1995,8 @@ void btm_create_conn_cancel_complete(const uint8_t* p, uint16_t evt_len) { case HCI_ERR_NO_CONNECTION: default: /* Notify application of the error */ - if (btm_cb.api.p_bond_cancel_cmpl_callback) - btm_cb.api.p_bond_cancel_cmpl_callback(BTM_ERR_PROCESSING); + if (btm_sec_cb.api.p_bond_cancel_cmpl_callback) + btm_sec_cb.api.p_bond_cancel_cmpl_callback(BTM_ERR_PROCESSING); break; } } @@ -2146,25 +2013,24 @@ void btm_create_conn_cancel_complete(const uint8_t* p, uint16_t evt_len) { * ******************************************************************************/ void btm_sec_check_pending_reqs(void) { - if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) { + if (btm_sec_cb.pairing_state == BTM_PAIR_STATE_IDLE) { /* First, resubmit L2CAP requests */ - if (btm_cb.sec_req_pending) { - btm_cb.sec_req_pending = false; + if (btm_sec_cb.sec_req_pending) { + btm_sec_cb.sec_req_pending = false; l2cu_resubmit_pending_sec_req(nullptr); } /* Now, re-submit anything in the mux queue */ - fixed_queue_t* bq = btm_cb.sec_pending_q; + fixed_queue_t* bq = btm_sec_cb.sec_pending_q; - btm_cb.sec_pending_q = fixed_queue_new(SIZE_MAX); + btm_sec_cb.sec_pending_q = fixed_queue_new(SIZE_MAX); tBTM_SEC_QUEUE_ENTRY* p_e; while ((p_e = (tBTM_SEC_QUEUE_ENTRY*)fixed_queue_try_dequeue(bq)) != NULL) { /* Check that the ACL is still up before starting security procedures */ if (BTM_IsAclConnectionUp(p_e->bd_addr, p_e->transport)) { if (p_e->psm != 0) { - BTM_TRACE_EVENT("%s PSM:0x%04x Is_Orig:%u", __func__, p_e->psm, - p_e->is_orig); + LOG_VERBOSE("PSM:0x%04x Is_Orig:%u", p_e->psm, p_e->is_orig); btm_sec_mx_access_request(p_e->bd_addr, p_e->is_orig, p_e->rfcomm_security_requirement, @@ -2191,19 +2057,17 @@ void btm_sec_check_pending_reqs(void) { * ******************************************************************************/ void btm_sec_dev_reset(void) { - if (controller_get_interface()->supports_simple_pairing()) { - /* set the default IO capabilities */ - btm_cb.devcb.loc_io_caps = btif_storage_get_local_io_caps(); - /* add mx service to use no security */ - BTM_SetSecurityLevel(false, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, - BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0); - BTM_SetSecurityLevel(true, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, BTM_SEC_NONE, - BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0); - } else { - btm_cb.security_mode = BTM_SEC_MODE_SERVICE; - } - - BTM_TRACE_DEBUG("btm_sec_dev_reset sec mode: %d", btm_cb.security_mode); + ASSERT_LOG(controller_get_interface()->supports_simple_pairing(), + "only controllers with SSP is supported"); + + /* set the default IO capabilities */ + btm_sec_cb.devcb.loc_io_caps = btif_storage_get_local_io_caps(); + /* add mx service to use no security */ + BTM_SetSecurityLevel(false, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, + BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0); + BTM_SetSecurityLevel(true, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, BTM_SEC_NONE, + BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0); + LOG_VERBOSE("btm_sec_dev_reset sec mode: %d", btm_sec_cb.security_mode); } /******************************************************************************* @@ -2223,53 +2087,81 @@ void btm_sec_abort_access_req(const RawAddress& bd_addr) { if (!p_dev_rec) return; - if ((p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING) && - (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING)) + if ((p_dev_rec->sec_rec.sec_state != BTM_SEC_STATE_AUTHORIZING) && + (p_dev_rec->sec_rec.sec_state != BTM_SEC_STATE_AUTHENTICATING)) return; - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; - BTM_TRACE_DEBUG("%s: clearing callback. p_dev_rec=%p, p_callback=%p", - __func__, p_dev_rec, p_dev_rec->p_callback); - p_dev_rec->p_callback = NULL; + LOG_VERBOSE("clearing callback. p_dev_rec=%p, p_callback=%p", p_dev_rec, + p_dev_rec->sec_rec.p_callback); + p_dev_rec->sec_rec.p_callback = NULL; } /******************************************************************************* * * Function btm_sec_dd_create_conn * - * Description This function is called to create the ACL connection for - * the dedicated boding process + * Description This function is called to create an ACL connection for + * the dedicated bonding process * - * Returns void + * Returns BTM_SUCCESS if an ACL connection is already up + * BTM_CMD_STARTED if the ACL connection has been requested + * BTM_NO_RESOURCES if failed to start the ACL connection * ******************************************************************************/ static tBTM_STATUS btm_sec_dd_create_conn(tBTM_SEC_DEV_REC* p_dev_rec) { tBTM_STATUS status = l2cu_ConnectAclForSecurity(p_dev_rec->bd_addr); if (status == BTM_CMD_STARTED) { - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); + /* If already connected, start pending security procedure */ + if (BTM_IsAclConnectionUp(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR)) { + return BTM_SUCCESS; + } + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); return BTM_CMD_STARTED; } else if (status == BTM_NO_RESOURCES) { return BTM_NO_RESOURCES; } /* set up the control block to indicated dedicated bonding */ - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE; + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE; - VLOG(1) << "Security Manager: " << p_dev_rec->bd_addr; + LOG_INFO("Security Manager: %s", + ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->bd_addr)); - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ); return (BTM_CMD_STARTED); } -bool is_state_getting_name(void* data, void* context) { - tBTM_SEC_DEV_REC* p_dev_rec = static_cast(data); +static void call_registered_rmt_name_callbacks(const RawAddress* p_bd_addr, + uint8_t* pdev_class, + uint8_t* p_bd_name, + tHCI_STATUS status) { + int i; - if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME) { - return false; + if (p_bd_addr == nullptr) { + // TODO Still need to send status back to get SDP state machine + // running + LOG_ERROR("Unable to issue callback with unknown address status:%s", + hci_status_code_text(status).c_str()); + return; + } + + if (pdev_class == nullptr) { + pdev_class = (uint8_t*)kDevClassEmpty; + } + if (p_bd_name == nullptr) { + p_bd_name = (uint8_t*)kBtmBdNameEmpty; + } + + /* Notify all clients waiting for name to be resolved even if not found so + * clients can continue */ + for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) { + if (btm_cb.p_rmt_name_callback[i]) { + (*btm_cb.p_rmt_name_callback[i])(*p_bd_addr, pdev_class, p_bd_name); + } } - return true; } /******************************************************************************* @@ -2286,18 +2178,15 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, const uint8_t* p_bd_name, tHCI_STATUS status) { tBTM_SEC_DEV_REC* p_dev_rec = nullptr; - - int i; uint8_t old_sec_state; LOG_INFO("btm_sec_rmt_name_request_complete for %s", p_bd_addr ? ADDRESS_TO_LOGGABLE_CSTR(*p_bd_addr) : "null"); - if ((!p_bd_addr && - !BTM_IsAclConnectionUp(btm_cb.connecting_bda, BT_TRANSPORT_BR_EDR)) || + if ((!p_bd_addr && !BTM_IsAclConnectionUp(btm_sec_cb.connecting_bda, + BT_TRANSPORT_BR_EDR)) || (p_bd_addr && !BTM_IsAclConnectionUp(*p_bd_addr, BT_TRANSPORT_BR_EDR))) { LOG_WARN("Remote read request complete with no underlying link connection"); - btm_acl_resubmit_page(); } /* If remote name request failed, p_bd_addr is null and we need to search */ @@ -2308,121 +2197,94 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, LOG_INFO( "Remote read request complete with no address so searching device " "database"); - list_node_t* node = - list_foreach(btm_cb.sec_dev_rec, is_state_getting_name, NULL); - if (node != NULL) { - p_dev_rec = static_cast(list_node(node)); + p_dev_rec = btm_sec_find_dev_by_sec_state(BTM_SEC_STATE_GETTING_NAME); + if (p_dev_rec) { p_bd_addr = &p_dev_rec->bd_addr; } } if (!p_bd_name) p_bd_name = (const uint8_t*)""; - if (p_dev_rec != nullptr) { - old_sec_state = p_dev_rec->sec_state; - if (status == HCI_SUCCESS) { - LOG_DEBUG( - "Remote read request complete for known device pairing_state:%s " - "name:%s sec_state:%s", - btm_pair_state_descr(btm_cb.pairing_state), p_bd_name, - security_state_text(p_dev_rec->sec_state).c_str()); - - strlcpy((char*)p_dev_rec->sec_bd_name, (const char*)p_bd_name, - BTM_MAX_REM_BD_NAME_LEN + 1); - p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN; - BTM_TRACE_EVENT("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x", - p_dev_rec->sec_flags); - } else { - LOG_WARN( - "Remote read request failed for known device pairing_state:%s " - "status:%s name:%s sec_state:%s", - btm_pair_state_descr(btm_cb.pairing_state), - hci_status_code_text(status).c_str(), p_bd_name, - security_state_text(p_dev_rec->sec_state).c_str()); - - /* Notify all clients waiting for name to be resolved even if it failed so - * clients can continue */ - p_dev_rec->sec_bd_name[0] = 0; - } - - if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME) - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; - - /* Notify all clients waiting for name to be resolved */ - for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) { - if (btm_cb.p_rmt_name_callback[i]) { - if (p_bd_addr) { - (*btm_cb.p_rmt_name_callback[i])(*p_bd_addr, p_dev_rec->dev_class, - p_dev_rec->sec_bd_name); - } else { - // TODO Still need to send status back to get SDP state machine - // running - LOG_ERROR("Unable to issue callback with unknown address status:%s", - hci_status_code_text(status).c_str()); - } - } - } - } else { + if (p_dev_rec == nullptr) { LOG_DEBUG( "Remote read request complete for unknown device pairing_state:%s " "status:%s name:%s", - btm_pair_state_descr(btm_cb.pairing_state), + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), hci_status_code_text(status).c_str(), p_bd_name); - /* Notify all clients waiting for name to be resolved even if not found so - * clients can continue */ - for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) { - if (btm_cb.p_rmt_name_callback[i]) { - if (p_bd_addr) { - (*btm_cb.p_rmt_name_callback[i])(*p_bd_addr, (uint8_t*)kDevClassEmpty, - (uint8_t*)kBtmBdNameEmpty); - } else { - // TODO Still need to send status back to get SDP state machine - // running - LOG_ERROR("Unable to issue callback with unknown address status:%s", - hci_status_code_text(status).c_str()); - } - } - } + call_registered_rmt_name_callbacks(p_bd_addr, nullptr, nullptr, status); return; } - /* If we were delaying asking UI for a PIN because name was not resolved, ask - * now */ - if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) && p_bd_addr && - (btm_cb.pairing_bda == *p_bd_addr)) { - BTM_TRACE_EVENT( - "%s() delayed pin now being requested flags:0x%x, " + old_sec_state = p_dev_rec->sec_rec.sec_state; + if (status == HCI_SUCCESS) { + LOG_DEBUG( + "Remote read request complete for known device pairing_state:%s " + "name:%s sec_state:%s", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), p_bd_name, + security_state_text(p_dev_rec->sec_rec.sec_state).c_str()); + + strlcpy((char*)p_dev_rec->sec_bd_name, (const char*)p_bd_name, + BTM_MAX_REM_BD_NAME_LEN + 1); + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_NAME_KNOWN; + LOG_VERBOSE("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x", + p_dev_rec->sec_rec.sec_flags); + } else { + LOG_WARN( + "Remote read request failed for known device pairing_state:%s " + "status:%s name:%s sec_state:%s", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + hci_status_code_text(status).c_str(), p_bd_name, + security_state_text(p_dev_rec->sec_rec.sec_state).c_str()); + + /* Notify all clients waiting for name to be resolved even if it failed so + * clients can continue */ + p_dev_rec->sec_bd_name[0] = 0; + } + + if (p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_GETTING_NAME) + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; + + /* Notify all clients waiting for name to be resolved */ + call_registered_rmt_name_callbacks(p_bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, status); + + /* If we were delaying asking UI for a PIN because name was not resolved, + * ask now */ + if ((btm_sec_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) && + p_bd_addr && (btm_sec_cb.pairing_bda == *p_bd_addr)) { + LOG_VERBOSE( + "delayed pin now being requested flags:0x%x, " "(p_pin_callback=0x%p)", - __func__, btm_cb.pairing_flags, btm_cb.api.p_pin_callback); + btm_sec_cb.pairing_flags, btm_sec_cb.api.p_pin_callback); - if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0 && - btm_cb.api.p_pin_callback) { - BTM_TRACE_EVENT("%s() calling pin_callback", __func__); - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; - (*btm_cb.api.p_pin_callback)( + if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0 && + btm_sec_cb.api.p_pin_callback) { + LOG_VERBOSE("calling pin_callback"); + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; + (*btm_sec_cb.api.p_pin_callback)( p_dev_rec->bd_addr, p_dev_rec->dev_class, p_bd_name, - (p_dev_rec->required_security_flags_for_pairing & + (p_dev_rec->sec_rec.required_security_flags_for_pairing & BTM_SEC_IN_MIN_16_DIGIT_PIN)); } /* Set the same state again to force the timer to be restarted */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN); return; } /* Check if we were delaying bonding because name was not resolved */ - if (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) { - if (p_bd_addr && btm_cb.pairing_bda == *p_bd_addr) { - BTM_TRACE_EVENT("%s() continue bonding sm4: 0x%04x, status:0x%x", - __func__, p_dev_rec->sm4, status); - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_CANCEL_DD) { + if (btm_sec_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) { + if (p_bd_addr && btm_sec_cb.pairing_bda == *p_bd_addr) { + LOG_VERBOSE("continue bonding sm4: 0x%04x, status:0x%x", p_dev_rec->sm4, + status); + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_CANCEL_DD) { btm_sec_bond_cancel_complete(); return; } if (status != HCI_SUCCESS) { - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); return NotifyBondingChange(*p_dev_rec, status); } @@ -2433,18 +2295,17 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, /* set the KNOWN flag only if BTM_PAIR_FLAGS_REJECTED_CONNECT is not * set.*/ /* If it is set, there may be a race condition */ - BTM_TRACE_DEBUG("%s IS_SM4_UNKNOWN Flags:0x%04x", __func__, - btm_cb.pairing_flags); - if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0) + LOG_VERBOSE("IS_SM4_UNKNOWN Flags:0x%04x", btm_sec_cb.pairing_flags); + if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0) p_dev_rec->sm4 |= BTM_SM4_KNOWN; } - BTM_TRACE_DEBUG("%s, SM4 Value: %x, Legacy:%d,IS SM4:%d, Unknown:%d", - __func__, p_dev_rec->sm4, - BTM_SEC_IS_SM4_LEGACY(p_dev_rec->sm4), - BTM_SEC_IS_SM4(p_dev_rec->sm4), - BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)); + LOG_VERBOSE("SM4 Value: %x, Legacy:%d,IS SM4:%d, Unknown:%d", + p_dev_rec->sm4, BTM_SEC_IS_SM4_LEGACY(p_dev_rec->sm4), + BTM_SEC_IS_SM4(p_dev_rec->sm4), + BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)); + bool await_connection = true; /* BT 2.1 or carkit, bring up the connection to force the peer to request *PIN. ** Else prefetch (btm_sec_check_prefetch_pin will do the prefetching if @@ -2455,26 +2316,34 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, /* if we rejected incoming connection request, we have to wait * HCI_Connection_Complete event */ /* before originating */ - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) { - BTM_TRACE_WARNING( - "%s: waiting HCI_Connection_Complete after rejecting connection", - __func__); + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) { + LOG_WARN( + "waiting HCI_Connection_Complete after rejecting connection"); } /* Both we and the peer are 2.1 - continue to create connection */ - else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) { - BTM_TRACE_WARNING("%s: failed to start connection", __func__); + else { + tBTM_STATUS req_status = btm_sec_dd_create_conn(p_dev_rec); + if (req_status == BTM_SUCCESS) { + await_connection = false; + } else if (req_status != BTM_CMD_STARTED) { + LOG_WARN("failed to start connection"); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); - NotifyBondingChange(*p_dev_rec, HCI_ERR_MEMORY_FULL); + NotifyBondingChange(*p_dev_rec, HCI_ERR_MEMORY_FULL); + } } } - return; + + if (await_connection) { + LOG_DEBUG("Wait for connection to begin pairing"); + return; + } } else { - BTM_TRACE_WARNING("%s: wrong BDA, retry with pairing BDA", __func__); - if (BTM_ReadRemoteDeviceName(btm_cb.pairing_bda, NULL, + LOG_WARN("wrong BDA, retry with pairing BDA"); + if (BTM_ReadRemoteDeviceName(btm_sec_cb.pairing_bda, NULL, BT_TRANSPORT_BR_EDR) != BTM_CMD_STARTED) { - BTM_TRACE_ERROR("%s: failed to start remote name request", __func__); + LOG_ERROR("failed to start remote name request"); NotifyBondingChange(*p_dev_rec, HCI_ERR_MEMORY_FULL); }; return; @@ -2483,19 +2352,19 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, /* check if we were delaying link_key_callback because name was not resolved */ - if (p_dev_rec->link_key_not_sent) { + if (p_dev_rec->sec_rec.link_key_not_sent) { /* If HCI connection complete has not arrived, wait for it */ if (p_dev_rec->hci_handle == HCI_INVALID_HANDLE) return; - p_dev_rec->link_key_not_sent = false; + p_dev_rec->sec_rec.link_key_not_sent = false; btm_send_link_key_notif(p_dev_rec); } /* If this is a bonding procedure can disconnect the link now */ - if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && - (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) { - BTM_TRACE_WARNING("btm_sec_rmt_name_request_complete (none/ce)"); - p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHENTICATE); + if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_AUTHENTICATED)) { + LOG_WARN("btm_sec_rmt_name_request_complete (none/ce)"); + p_dev_rec->sec_rec.security_required &= ~(BTM_SEC_OUT_AUTHENTICATE); l2cu_start_post_bond_timer(p_dev_rec->hci_handle); return; } @@ -2509,7 +2378,7 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, } if (p_dev_rec->sm4 & BTM_SM4_REQ_PEND) { - BTM_TRACE_EVENT("waiting for remote features!!"); + LOG_VERBOSE("waiting for remote features!!"); return; } @@ -2534,29 +2403,25 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, * Returns void * ******************************************************************************/ -void btm_sec_rmt_host_support_feat_evt(const uint8_t* p) { +void btm_sec_rmt_host_support_feat_evt(const RawAddress bd_addr, + uint8_t features_0) { tBTM_SEC_DEV_REC* p_dev_rec; - RawAddress bd_addr; /* peer address */ - BD_FEATURES features; - STREAM_TO_BDADDR(bd_addr, p); p_dev_rec = btm_find_or_alloc_dev(bd_addr); LOG_INFO("Got btm_sec_rmt_host_support_feat_evt from %s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - BTM_TRACE_EVENT("btm_sec_rmt_host_support_feat_evt sm4: 0x%x p[0]: 0x%x", - p_dev_rec->sm4, p[0]); + LOG_VERBOSE("btm_sec_rmt_host_support_feat_evt sm4: 0x%x p[0]: 0x%x", + p_dev_rec->sm4, features_0); if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) { p_dev_rec->sm4 = BTM_SM4_KNOWN; - STREAM_TO_ARRAY(features, p, HCI_FEATURE_BYTES_PER_PAGE); - if (HCI_SSP_HOST_SUPPORTED(features)) { + if (HCI_SSP_HOST_SUPPORTED((std::array({features_0})))) { p_dev_rec->sm4 = BTM_SM4_TRUE; } - BTM_TRACE_EVENT( - "btm_sec_rmt_host_support_feat_evt sm4: 0x%x features[0]: 0x%x", - p_dev_rec->sm4, features[0]); + LOG_VERBOSE("btm_sec_rmt_host_support_feat_evt sm4: 0x%x features[0]: 0x%x", + p_dev_rec->sm4, features_0); } } @@ -2571,20 +2436,20 @@ void btm_sec_rmt_host_support_feat_evt(const uint8_t* p) { * Returns void * ******************************************************************************/ -void btm_io_capabilities_req(const RawAddress& p) { +void btm_io_capabilities_req(RawAddress p) { if (btm_sec_is_a_bonded_dev(p)) { - BTM_TRACE_WARNING( - "%s: Incoming bond request, but %s is already bonded (removing)", - __func__, ADDRESS_TO_LOGGABLE_CSTR(p)); + LOG_WARN("Incoming bond request, but %s is already bonded (removing)", + ADDRESS_TO_LOGGABLE_CSTR(p)); bta_dm_process_remove_device(p); } tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(p); - if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && + if ((btm_sec_cb.security_mode == BTM_SEC_MODE_SC) && (!p_dev_rec->remote_feature_received)) { - BTM_TRACE_EVENT("%s: Device security mode is SC only.", - "To continue need to know remote features.", __func__); + LOG_VERBOSE( + "Device security mode is SC only." + "To continue need to know remote features."); // ACL calls back to btm_sec_set_peer_sec_caps after it gets data p_dev_rec->remote_features_needed = true; @@ -2597,36 +2462,31 @@ void btm_io_capabilities_req(const RawAddress& p) { /* setup the default response according to compile options */ /* assume that the local IO capability does not change * loc_io_caps is initialized with the default value */ - evt_data.io_cap = btm_cb.devcb.loc_io_caps; + evt_data.io_cap = btm_sec_cb.devcb.loc_io_caps; // TODO(optedoblivion): Inject OOB_DATA_PRESENT Flag evt_data.oob_data = BTM_OOB_NONE; evt_data.auth_req = BTM_AUTH_SP_NO; - BTM_TRACE_EVENT("%s: State: %s", __func__, - btm_pair_state_descr(btm_cb.pairing_state)); - - BTM_TRACE_DEBUG("%s:Security mode: %d", __func__, btm_cb.security_mode); - p_dev_rec->sm4 |= BTM_SM4_TRUE; - BTM_TRACE_EVENT("%s: State: %s Flags: 0x%04x", __func__, - btm_pair_state_descr(btm_cb.pairing_state), - btm_cb.pairing_flags); + LOG_VERBOSE("State: %s, Security Mode: %d, Device security Flags: 0x%04x", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + btm_sec_cb.security_mode, btm_sec_cb.pairing_flags); uint8_t err_code = 0; bool is_orig = true; - switch (btm_cb.pairing_state) { + switch (btm_sec_cb.pairing_state) { /* initiator connecting */ case BTM_PAIR_STATE_IDLE: // TODO: Handle Idle pairing state - // security_required = p_dev_rec->security_required; + // security_required = p_dev_rec->sec_rec.security_required; break; /* received IO capability response already->acceptor */ case BTM_PAIR_STATE_INCOMING_SSP: is_orig = false; - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) { + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) { /* acceptor in dedicated bonding */ evt_data.auth_req = BTM_AUTH_AP_YES; } @@ -2635,7 +2495,7 @@ void btm_io_capabilities_req(const RawAddress& p) { /* initiator, at this point it is expected to be dedicated bonding initiated by local device */ case BTM_PAIR_STATE_WAIT_PIN_REQ: - if (evt_data.bd_addr == btm_cb.pairing_bda) { + if (evt_data.bd_addr == btm_sec_cb.pairing_bda) { evt_data.auth_req = BTM_AUTH_AP_YES; } else { err_code = HCI_ERR_HOST_BUSY_PAIRING; @@ -2645,16 +2505,16 @@ void btm_io_capabilities_req(const RawAddress& p) { /* any other state is unexpected */ default: err_code = HCI_ERR_HOST_BUSY_PAIRING; - BTM_TRACE_ERROR("%s: Unexpected Pairing state received %d", __func__, - btm_cb.pairing_state); + LOG_ERROR("Unexpected Pairing state received %d", + btm_sec_cb.pairing_state); break; } - if (btm_cb.pairing_disabled) { + if (btm_sec_cb.pairing_disabled) { /* pairing is not allowed */ - BTM_TRACE_DEBUG("%s: Pairing is not allowed -> fail pairing.", __func__); + LOG_VERBOSE("Pairing is not allowed -> fail pairing."); err_code = HCI_ERR_PAIRING_NOT_ALLOWED; - } else if (btm_cb.security_mode == BTM_SEC_MODE_SC) { + } else if (btm_sec_cb.security_mode == BTM_SEC_MODE_SC) { bool local_supports_sc = controller_get_interface()->supports_secure_connections(); /* device in Secure Connections Only mode */ @@ -2678,15 +2538,16 @@ void btm_io_capabilities_req(const RawAddress& p) { if (is_orig) { /* local device initiated the pairing non-bonding -> use * required_security_flags_for_pairing */ - if (!(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && - (p_dev_rec->required_security_flags_for_pairing & + if (!(btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && + (p_dev_rec->sec_rec.required_security_flags_for_pairing & BTM_SEC_OUT_AUTHENTICATE)) { - if (btm_cb.security_mode == BTM_SEC_MODE_SC) { + if (btm_sec_cb.security_mode == BTM_SEC_MODE_SC) { /* SC only mode device requires MITM protection */ evt_data.auth_req = BTM_AUTH_SP_YES; } else { evt_data.auth_req = - (p_dev_rec->required_security_flags_for_pairing & BTM_SEC_OUT_MITM) + (p_dev_rec->sec_rec.required_security_flags_for_pairing & + BTM_SEC_OUT_MITM) ? BTM_AUTH_SP_YES : BTM_AUTH_SP_NO; } @@ -2696,12 +2557,12 @@ void btm_io_capabilities_req(const RawAddress& p) { /* Notify L2CAP to increase timeout */ l2c_pin_code_request(evt_data.bd_addr); - btm_cb.pairing_bda = evt_data.bd_addr; + btm_sec_cb.pairing_bda = evt_data.bd_addr; - if (evt_data.bd_addr == btm_cb.connecting_bda) - memcpy(p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN); + if (evt_data.bd_addr == btm_sec_cb.connecting_bda) + memcpy(p_dev_rec->dev_class, btm_sec_cb.connecting_dc, DEV_CLASS_LEN); - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS); if (p_dev_rec->sm4 & BTM_SM4_UPGRADE) { p_dev_rec->sm4 &= ~BTM_SM4_UPGRADE; @@ -2709,35 +2570,35 @@ void btm_io_capabilities_req(const RawAddress& p) { /* link key upgrade: always use SPGB_YES - assuming we want to save the link * key */ evt_data.auth_req = BTM_AUTH_SPGB_YES; - } else if (btm_cb.api.p_sp_callback) { + } else if (btm_sec_cb.api.p_sp_callback) { /* the callback function implementation may change the IO capability... */ - (*btm_cb.api.p_sp_callback)(BTM_SP_IO_REQ_EVT, - (tBTM_SP_EVT_DATA*)&evt_data); + (*btm_sec_cb.api.p_sp_callback)(BTM_SP_IO_REQ_EVT, + (tBTM_SP_EVT_DATA*)&evt_data); } - if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) { + if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) { evt_data.auth_req = (BTM_AUTH_DD_BOND | (evt_data.auth_req & BTM_AUTH_YN_BIT)); } - if (btm_cb.security_mode == BTM_SEC_MODE_SC) { + if (btm_sec_cb.security_mode == BTM_SEC_MODE_SC) { /* At this moment we know that both sides are SC capable, device in */ /* SC only mode requires MITM for any service so let's set MITM bit */ evt_data.auth_req |= BTM_AUTH_YN_BIT; - BTM_TRACE_DEBUG("%s: for device in \"SC only\" mode set auth_req to 0x%02x", - __func__, evt_data.auth_req); + LOG_VERBOSE("for device in \"SC only\" mode set auth_req to 0x%02x", + evt_data.auth_req); } /* if the user does not indicate "reply later" by setting the oob_data to * unknown */ /* send the response right now. Save the current IO capability in the * control block */ - btm_cb.devcb.loc_auth_req = evt_data.auth_req; - btm_cb.devcb.loc_io_caps = evt_data.io_cap; + btm_sec_cb.devcb.loc_auth_req = evt_data.auth_req; + btm_sec_cb.devcb.loc_io_caps = evt_data.io_cap; - BTM_TRACE_EVENT("%s: State: %s IO_CAP:%d oob_data:%d auth_req:%d", __func__, - btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap, - evt_data.oob_data, evt_data.auth_req); + LOG_VERBOSE("State: %s IO_CAP:%d oob_data:%d auth_req:%d", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + evt_data.io_cap, evt_data.oob_data, evt_data.auth_req); btsnd_hcic_io_cap_req_reply(evt_data.bd_addr, evt_data.io_cap, evt_data.oob_data, evt_data.auth_req); @@ -2753,23 +2614,17 @@ void btm_io_capabilities_req(const RawAddress& p) { * Returns void * ******************************************************************************/ -void btm_io_capabilities_rsp(const uint8_t* p) { +void btm_io_capabilities_rsp(const tBTM_SP_IO_RSP evt_data) { tBTM_SEC_DEV_REC* p_dev_rec; - tBTM_SP_IO_RSP evt_data; - - STREAM_TO_BDADDR(evt_data.bd_addr, p); - STREAM_TO_UINT8(evt_data.io_cap, p); - STREAM_TO_UINT8(evt_data.oob_data, p); - STREAM_TO_UINT8(evt_data.auth_req, p); /* Allocate a new device record or reuse the oldest one */ p_dev_rec = btm_find_or_alloc_dev(evt_data.bd_addr); /* If no security is in progress, this indicates incoming security */ - if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) { - btm_cb.pairing_bda = evt_data.bd_addr; + if (btm_sec_cb.pairing_state == BTM_PAIR_STATE_IDLE) { + btm_sec_cb.pairing_bda = evt_data.bd_addr; - btm_sec_change_pairing_state(BTM_PAIR_STATE_INCOMING_SSP); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_INCOMING_SSP); /* work around for FW bug */ btm_inq_stop_on_ssp(); @@ -2780,26 +2635,26 @@ void btm_io_capabilities_rsp(const uint8_t* p) { /* We must have a device record here. * Use the connecting device's CoD for the connection */ - if (evt_data.bd_addr == btm_cb.connecting_bda) - memcpy(p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN); + if (evt_data.bd_addr == btm_sec_cb.connecting_bda) + memcpy(p_dev_rec->dev_class, btm_sec_cb.connecting_dc, DEV_CLASS_LEN); /* peer sets dedicated bonding bit and we did not initiate dedicated bonding */ - if (btm_cb.pairing_state == + if (btm_sec_cb.pairing_state == BTM_PAIR_STATE_INCOMING_SSP /* peer initiated bonding */ && (evt_data.auth_req & BTM_AUTH_DD_BOND)) /* and dedicated bonding bit is set */ { - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PEER_STARTED_DD; + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_PEER_STARTED_DD; } /* save the IO capability in the device record */ - p_dev_rec->rmt_io_caps = evt_data.io_cap; - p_dev_rec->rmt_auth_req = evt_data.auth_req; + p_dev_rec->sec_rec.rmt_io_caps = evt_data.io_cap; + p_dev_rec->sec_rec.rmt_auth_req = evt_data.auth_req; - if (btm_cb.api.p_sp_callback) - (*btm_cb.api.p_sp_callback)(BTM_SP_IO_RSP_EVT, - (tBTM_SP_EVT_DATA*)&evt_data); + if (btm_sec_cb.api.p_sp_callback) + (*btm_sec_cb.api.p_sp_callback)(BTM_SP_IO_RSP_EVT, + (tBTM_SP_EVT_DATA*)&evt_data); } /******************************************************************************* @@ -2814,21 +2669,22 @@ void btm_io_capabilities_rsp(const uint8_t* p) { * Returns void * ******************************************************************************/ -void btm_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p) { +void btm_proc_sp_req_evt(tBTM_SP_EVT event, const RawAddress bda, + const uint32_t value) { tBTM_STATUS status = BTM_ERR_PROCESSING; tBTM_SP_EVT_DATA evt_data; RawAddress& p_bda = evt_data.cfm_req.bd_addr; tBTM_SEC_DEV_REC* p_dev_rec; - /* All events start with bd_addr */ - STREAM_TO_BDADDR(p_bda, p); - - VLOG(2) << " BDA: " << p_bda << " event: 0x" << std::hex << +event - << " State: " << btm_pair_state_descr(btm_cb.pairing_state); + p_bda = bda; + LOG_VERBOSE("BDA: %s, event: 0x%x, state: %s", + ADDRESS_TO_LOGGABLE_CSTR(p_bda), event, + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state)); p_dev_rec = btm_find_dev(p_bda); - if ((p_dev_rec != NULL) && (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - (btm_cb.pairing_bda == p_bda)) { + if ((p_dev_rec != NULL) && + (btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (btm_sec_cb.pairing_bda == p_bda)) { evt_data.cfm_req.bd_addr = p_dev_rec->bd_addr; memcpy(evt_data.cfm_req.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN); @@ -2838,32 +2694,31 @@ void btm_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p) { switch (event) { case BTM_SP_CFM_REQ_EVT: /* Numeric confirmation. Need user to conf the passkey */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM); /* The device record must be allocated in the "IO cap exchange" step */ - STREAM_TO_UINT32(evt_data.cfm_req.num_val, p); - BTM_TRACE_DEBUG("BTM_SP_CFM_REQ_EVT: num_val: %u", - evt_data.cfm_req.num_val); + evt_data.cfm_req.num_val = value; + LOG_VERBOSE("BTM_SP_CFM_REQ_EVT: num_val: %u", + evt_data.cfm_req.num_val); evt_data.cfm_req.just_works = true; /* process user confirm req in association with the auth_req param */ - if (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) { - if (p_dev_rec->rmt_io_caps == BTM_IO_CAP_UNKNOWN) { - BTM_TRACE_ERROR( - "%s did not receive IO cap response prior" - " to BTM_SP_CFM_REQ_EVT, failing pairing request", - __func__); + if (btm_sec_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) { + if (p_dev_rec->sec_rec.rmt_io_caps == BTM_IO_CAP_UNKNOWN) { + LOG_ERROR( + "did not receive IO cap response prior" + " to BTM_SP_CFM_REQ_EVT, failing pairing request"); status = BTM_WRONG_MODE; BTM_ConfirmReqReply(status, p_bda); return; } - if ((p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO || - p_dev_rec->rmt_io_caps == BTM_IO_CAP_OUT) && - (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) && - ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) || - (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES))) { + if ((p_dev_rec->sec_rec.rmt_io_caps == BTM_IO_CAP_IO || + p_dev_rec->sec_rec.rmt_io_caps == BTM_IO_CAP_OUT) && + (btm_sec_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) && + ((p_dev_rec->sec_rec.rmt_auth_req & BTM_AUTH_SP_YES) || + (btm_sec_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES))) { /* Use Numeric Comparison if * 1. Local IO capability is DisplayYesNo, * 2. Remote IO capability is DisplayOnly or DiaplayYesNo, and @@ -2872,38 +2727,38 @@ void btm_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p) { } } - BTM_TRACE_DEBUG( + LOG_VERBOSE( "btm_proc_sp_req_evt() just_works:%d, io loc:%d, rmt:%d, auth " "loc:%d, rmt:%d", - evt_data.cfm_req.just_works, btm_cb.devcb.loc_io_caps, - p_dev_rec->rmt_io_caps, btm_cb.devcb.loc_auth_req, - p_dev_rec->rmt_auth_req); - - evt_data.cfm_req.loc_auth_req = btm_cb.devcb.loc_auth_req; - evt_data.cfm_req.rmt_auth_req = p_dev_rec->rmt_auth_req; - evt_data.cfm_req.loc_io_caps = btm_cb.devcb.loc_io_caps; - evt_data.cfm_req.rmt_io_caps = p_dev_rec->rmt_io_caps; + evt_data.cfm_req.just_works, btm_sec_cb.devcb.loc_io_caps, + p_dev_rec->sec_rec.rmt_io_caps, btm_sec_cb.devcb.loc_auth_req, + p_dev_rec->sec_rec.rmt_auth_req); + + evt_data.cfm_req.loc_auth_req = btm_sec_cb.devcb.loc_auth_req; + evt_data.cfm_req.rmt_auth_req = p_dev_rec->sec_rec.rmt_auth_req; + evt_data.cfm_req.loc_io_caps = btm_sec_cb.devcb.loc_io_caps; + evt_data.cfm_req.rmt_io_caps = p_dev_rec->sec_rec.rmt_io_caps; break; case BTM_SP_KEY_NOTIF_EVT: /* Passkey notification (other side is a keyboard) */ - STREAM_TO_UINT32(evt_data.key_notif.passkey, p); - BTM_TRACE_DEBUG("BTM_SP_KEY_NOTIF_EVT: passkey: %u", - evt_data.key_notif.passkey); + evt_data.key_notif.passkey = value; + LOG_VERBOSE("BTM_SP_KEY_NOTIF_EVT: passkey: %u", + evt_data.key_notif.passkey); - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); break; case BTM_SP_KEY_REQ_EVT: - if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) { + if (btm_sec_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) { /* HCI_USER_PASSKEY_REQUEST_EVT */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_KEY_ENTRY); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_KEY_ENTRY); } break; } - if (btm_cb.api.p_sp_callback) { - status = (*btm_cb.api.p_sp_callback)(event, &evt_data); + if (btm_sec_cb.api.p_sp_callback) { + status = (*btm_sec_cb.api.p_sp_callback)(event, &evt_data); if (status != BTM_NOT_AUTHORIZED) { return; } @@ -2915,9 +2770,9 @@ void btm_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p) { } if (event == BTM_SP_CFM_REQ_EVT) { - BTM_TRACE_DEBUG("calling BTM_ConfirmReqReply with status: %d", status); + LOG_VERBOSE("calling BTM_ConfirmReqReply with status: %d", status); BTM_ConfirmReqReply(status, p_bda); - } else if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE && + } else if (btm_sec_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE && event == BTM_SP_KEY_REQ_EVT) { BTM_PasskeyReqReply(status, p_bda, 0); } @@ -2943,7 +2798,7 @@ void btm_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p) { p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE, "stack::btm::btm_sec::btm_proc_sp_req_evt Security failure"); } - } else if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) { + } else if (btm_sec_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) { btsnd_hcic_user_passkey_neg_reply(p_bda); } } @@ -2958,39 +2813,35 @@ void btm_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p) { * Returns void * ******************************************************************************/ -void btm_simple_pair_complete(const uint8_t* p) { - RawAddress bd_addr; +void btm_simple_pair_complete(const RawAddress bd_addr, uint8_t status) { tBTM_SEC_DEV_REC* p_dev_rec; - uint8_t status; bool disc = false; - status = *p++; - STREAM_TO_BDADDR(bd_addr, p); - p_dev_rec = btm_find_dev(bd_addr); if (p_dev_rec == NULL) { - LOG(ERROR) << __func__ << " with unknown BDA: " << bd_addr; + LOG_ERROR("unknown BDA: %s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); return; } - BTM_TRACE_EVENT( + LOG_VERBOSE( "btm_simple_pair_complete() Pair State: %s Status:%d sec_state: %u", - btm_pair_state_descr(btm_cb.pairing_state), status, p_dev_rec->sec_state); + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), status, + p_dev_rec->sec_rec.sec_state); if (status == HCI_SUCCESS) { - p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_AUTHENTICATED; } else if (status == HCI_ERR_PAIRING_NOT_ALLOWED) { /* The test spec wants the peer device to get this failure code. */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_DISCONNECT); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_DISCONNECT); /* Change the timer to 1 second */ - alarm_set_on_mloop(btm_cb.pairing_timer, BT_1SEC_TIMEOUT_MS, + alarm_set_on_mloop(btm_sec_cb.pairing_timer, BT_1SEC_TIMEOUT_MS, btm_sec_pairing_timeout, NULL); - } else if (btm_cb.pairing_bda == bd_addr) { + } else if (btm_sec_cb.pairing_bda == bd_addr) { /* stop the timer */ - alarm_cancel(btm_cb.pairing_timer); + alarm_cancel(btm_sec_cb.pairing_timer); - if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) { + if (p_dev_rec->sec_rec.sec_state != BTM_SEC_STATE_AUTHENTICATING) { /* the initiating side: will receive auth complete event. disconnect ACL * at that time */ disc = true; @@ -3021,27 +2872,26 @@ void btm_simple_pair_complete(const uint8_t* p) { * Returns void * ******************************************************************************/ -void btm_rem_oob_req(const uint8_t* p) { +void btm_rem_oob_req(const RawAddress bd_addr) { tBTM_SP_RMT_OOB evt_data; tBTM_SEC_DEV_REC* p_dev_rec; Octet16 c; Octet16 r; + evt_data.bd_addr = bd_addr; RawAddress& p_bda = evt_data.bd_addr; - STREAM_TO_BDADDR(p_bda, p); - - VLOG(2) << __func__ << " BDA: " << p_bda; + LOG_VERBOSE("BDA: %s", ADDRESS_TO_LOGGABLE_CSTR(p_bda)); p_dev_rec = btm_find_dev(p_bda); - if ((p_dev_rec != NULL) && btm_cb.api.p_sp_callback) { + if ((p_dev_rec != NULL) && btm_sec_cb.api.p_sp_callback) { evt_data.bd_addr = p_dev_rec->bd_addr; memcpy(evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN); strlcpy((char*)evt_data.bd_name, (char*)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN + 1); - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP); - if ((*btm_cb.api.p_sp_callback)(BTM_SP_RMT_OOB_EVT, - (tBTM_SP_EVT_DATA*)&evt_data) == + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP); + if ((*btm_sec_cb.api.p_sp_callback)(BTM_SP_RMT_OOB_EVT, + (tBTM_SP_EVT_DATA*)&evt_data) == BTM_NOT_AUTHORIZED) { BTM_RemoteOobDataReply(static_cast(true), p_bda, c, r); } @@ -3063,38 +2913,14 @@ void btm_rem_oob_req(const uint8_t* p) { * Returns void * ******************************************************************************/ -void btm_read_local_oob_complete(uint8_t* p, uint16_t evt_len) { - tBTM_SP_LOC_OOB evt_data; - uint8_t status; - if (evt_len < 1) { - goto err_out; - } - - STREAM_TO_UINT8(status, p); - - BTM_TRACE_EVENT("btm_read_local_oob_complete:%d", status); - if (status == HCI_SUCCESS) { - evt_data.status = BTM_SUCCESS; - - if (evt_len < 32 + 1) { - goto err_out; - } - - STREAM_TO_ARRAY16(evt_data.c.data(), p); - STREAM_TO_ARRAY16(evt_data.r.data(), p); - } else - evt_data.status = BTM_ERR_PROCESSING; +void btm_read_local_oob_complete(const tBTM_SP_LOC_OOB evt_data) { + LOG_VERBOSE("btm_read_local_oob_complete:%d", evt_data.status); - if (btm_cb.api.p_sp_callback) { + if (btm_sec_cb.api.p_sp_callback) { tBTM_SP_EVT_DATA btm_sp_evt_data; btm_sp_evt_data.loc_oob = evt_data; - (*btm_cb.api.p_sp_callback)(BTM_SP_LOC_OOB_EVT, &btm_sp_evt_data); + (*btm_sec_cb.api.p_sp_callback)(BTM_SP_LOC_OOB_EVT, &btm_sp_evt_data); } - - return; - -err_out: - BTM_TRACE_ERROR("%s: bogus event packet, too short", __func__); } /******************************************************************************* @@ -3110,11 +2936,12 @@ err_out: static void btm_sec_auth_collision(uint16_t handle) { tBTM_SEC_DEV_REC* p_dev_rec; - if (!btm_cb.collision_start_time) - btm_cb.collision_start_time = bluetooth::common::time_get_os_boottime_ms(); + if (!btm_sec_cb.collision_start_time) + btm_sec_cb.collision_start_time = + bluetooth::common::time_get_os_boottime_ms(); if ((bluetooth::common::time_get_os_boottime_ms() - - btm_cb.collision_start_time) < BTM_SEC_MAX_COLLISION_DELAY) { + btm_sec_cb.collision_start_time) < BTM_SEC_MAX_COLLISION_DELAY) { if (handle == HCI_INVALID_HANDLE) { p_dev_rec = btm_sec_find_dev_by_sec_state(BTM_SEC_STATE_AUTHENTICATING); if (p_dev_rec == NULL) @@ -3123,16 +2950,15 @@ static void btm_sec_auth_collision(uint16_t handle) { p_dev_rec = btm_find_dev_by_handle(handle); if (p_dev_rec != NULL) { - BTM_TRACE_DEBUG( - "btm_sec_auth_collision: state %d (retrying in a moment...)", - p_dev_rec->sec_state); + LOG_VERBOSE("btm_sec_auth_collision: state %d (retrying in a moment...)", + p_dev_rec->sec_rec.sec_state); /* We will restart authentication after timeout */ - if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING || - p_dev_rec->is_security_state_bredr_encrypting()) - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + if (p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_AUTHENTICATING || + p_dev_rec->sec_rec.is_security_state_bredr_encrypting()) + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; - btm_cb.p_collided_dev_rec = p_dev_rec; - alarm_set_on_mloop(btm_cb.sec_collision_timer, BT_1SEC_TIMEOUT_MS, + btm_sec_cb.p_collided_dev_rec = p_dev_rec; + alarm_set_on_mloop(btm_sec_cb.sec_collision_timer, BT_1SEC_TIMEOUT_MS, btm_sec_collision_timeout, NULL); } } @@ -3156,25 +2982,25 @@ static bool btm_sec_auth_retry(uint16_t handle, uint8_t status) { uint8_t old_sm4 = p_dev_rec->sm4; p_dev_rec->sm4 &= ~BTM_SM4_RETRY; - if ((btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) && + if ((btm_sec_cb.pairing_state == BTM_PAIR_STATE_IDLE) && ((old_sm4 & BTM_SM4_RETRY) == 0) && (HCI_ERR_KEY_MISSING == status) && BTM_SEC_IS_SM4(p_dev_rec->sm4)) { /* This retry for missing key is for Lisbon or later only. Legacy device do not need this. the controller will drive the retry automatically set the retry bit */ - btm_cb.collision_start_time = 0; + btm_sec_cb.collision_start_time = 0; btm_restore_mode(); p_dev_rec->sm4 |= BTM_SM4_RETRY; - p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN; - BTM_TRACE_DEBUG("%s Retry for missing key sm4:x%x sec_flags:0x%x", __func__, - p_dev_rec->sm4, p_dev_rec->sec_flags); + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN; + LOG_VERBOSE("Retry for missing key sm4:x%x sec_flags:0x%x", p_dev_rec->sm4, + p_dev_rec->sec_rec.sec_flags); /* With BRCM controller, we do not need to delete the stored link key in controller. If the stack may sit on top of other controller, we may need this BTM_DeleteStoredLinkKey (bd_addr, NULL); */ - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; btm_sec_execute_procedure(p_dev_rec); return true; } @@ -3183,22 +3009,22 @@ static bool btm_sec_auth_retry(uint16_t handle, uint8_t status) { } void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { - tBTM_PAIRING_STATE old_state = btm_cb.pairing_state; + tBTM_PAIRING_STATE old_state = btm_sec_cb.pairing_state; tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle); bool are_bonding = false; bool was_authenticating = false; if (p_dev_rec) { - VLOG(2) << __func__ << ": Security Manager: in state: " - << btm_pair_state_descr(btm_cb.pairing_state) - << " handle:" << handle << " status:" << status - << "dev->sec_state:" << p_dev_rec->sec_state - << " bda:" << p_dev_rec->bd_addr - << "RName:" << p_dev_rec->sec_bd_name; + LOG_VERBOSE( + "Security Manager: in state: %s, handle: %d, status: %d, " + "dev->sec_rec.sec_state:%d, bda: %s, RName: %s", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), handle, + status, p_dev_rec->sec_rec.sec_state, + ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->bd_addr), p_dev_rec->sec_bd_name); } else { - VLOG(2) << __func__ << ": Security Manager: in state: " - << btm_pair_state_descr(btm_cb.pairing_state) - << " handle:" << handle << " status:" << status; + LOG_VERBOSE("Security Manager: in state: %s, handle: %d, status: %d", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + handle, status); } /* For transaction collision we need to wait and repeat. There is no need */ @@ -3211,24 +3037,24 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { return; } - btm_cb.collision_start_time = 0; + btm_sec_cb.collision_start_time = 0; btm_restore_mode(); /* Check if connection was made just to do bonding. If we authenticate the connection that is up, this is the last event received. */ - if (p_dev_rec && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && - !(btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)) { - p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + if (p_dev_rec && (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && + !(btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)) { + p_dev_rec->sec_rec.security_required &= ~BTM_SEC_OUT_AUTHENTICATE; l2cu_start_post_bond_timer(p_dev_rec->hci_handle); } if (!p_dev_rec) return; - if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) { - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + if (p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_AUTHENTICATING) { + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; was_authenticating = true; /* There can be a race condition, when we are starting authentication * and the peer device is doing encryption. @@ -3238,21 +3064,22 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { * encrypted link, so device is correct. */ if ((status == HCI_ERR_COMMAND_DISALLOWED) && - ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) == + ((p_dev_rec->sec_rec.sec_flags & + (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) == (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) { status = HCI_SUCCESS; } if (status == HCI_SUCCESS) { - p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_AUTHENTICATED; } } - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - (p_dev_rec->bd_addr == btm_cb.pairing_bda)) { - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) { + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (p_dev_rec->bd_addr == btm_sec_cb.pairing_bda)) { + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) { are_bonding = true; } - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); } if (was_authenticating == false) { @@ -3264,17 +3091,17 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { /* Currently we do not notify user if it is a keyboard which connects */ /* User probably Disabled the keyboard while it was asleap. Let them try */ - if (btm_cb.api.p_auth_complete_callback) { + if (btm_sec_cb.api.p_auth_complete_callback) { /* report the suthentication status */ if ((old_state != BTM_PAIR_STATE_IDLE) || (status != HCI_SUCCESS)) - (*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr, - p_dev_rec->dev_class, - p_dev_rec->sec_bd_name, status); + (*btm_sec_cb.api.p_auth_complete_callback)( + p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, + status); } /* If this is a bonding procedure can disconnect the link now */ if (are_bonding) { - p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + p_dev_rec->sec_rec.security_required &= ~BTM_SEC_OUT_AUTHENTICATE; if (status != HCI_SUCCESS) { if (((status != HCI_ERR_PEER_USER) && @@ -3296,9 +3123,8 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { } else if (p_dev_rec->IsLocallyInitiated()) { // Encryption will be set in role_changed callback LOG_INFO( - "%s auth completed in role=peripheral, try to switch role and " - "encrypt", - __func__); + "auth completed in role=peripheral, try to switch role and " + "encrypt"); BTM_SwitchRoleToCentral(p_dev_rec->RemoteAddress()); } @@ -3312,7 +3138,7 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { if (status != HCI_SUCCESS) { btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, false); - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) { + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) { btm_sec_send_hci_disconnect( p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle, "stack::btm::btm_sec::btm_sec_auth_retry Auth failed"); @@ -3320,12 +3146,12 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { return; } - if (p_dev_rec->pin_code_length >= 16 || - p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB || - p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + if (p_dev_rec->sec_rec.pin_code_length >= 16 || + p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB || + p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { // If we have MITM protection we have a higher level of security than // provided by 16 digits PIN - p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; } /* Authentication succeeded, execute the next security procedure, if any */ @@ -3358,7 +3184,7 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, btm_sec_auth_collision(handle); return; } - btm_cb.collision_start_time = 0; + btm_sec_cb.collision_start_time = 0; tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle); if (p_dev_rec == nullptr) { @@ -3377,27 +3203,24 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, " request:%s state:%s sec_flags:0x%x", hci_status_code_text(status).c_str(), (encr_enable) ? "encrypt" : "unencrypt", - (p_dev_rec->sec_state) ? "encrypted" : "unencrypted", - p_dev_rec->sec_flags); + (p_dev_rec->sec_rec.sec_state) ? "encrypted" : "unencrypted", + p_dev_rec->sec_rec.sec_flags); if (status == HCI_SUCCESS) { if (encr_enable) { if (p_dev_rec->hci_handle == handle) { // classic - if ((p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) && - (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)) { - LOG_INFO( - "Link is authenticated & encrypted, ignoring this enc change " - "event"); - return; - } - p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED); - if (p_dev_rec->pin_code_length >= 16 || - p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB || - p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { - p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + p_dev_rec->sec_rec.sec_flags |= + (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED); + if (p_dev_rec->sec_rec.pin_code_length >= 16 || + p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB || + p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; } } else if (p_dev_rec->ble_hci_handle == handle) { // BLE - p_dev_rec->sec_flags |= BTM_SEC_LE_ENCRYPTED; + p_dev_rec->sec_rec.set_le_device_encrypted(); + if (p_dev_rec->sec_rec.is_le_link_key_authenticated()) { + p_dev_rec->sec_rec.set_le_device_authenticated(); + } } else { LOG_ERROR( "Received encryption change for unknown device handle:0x%04x " @@ -3410,9 +3233,9 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, /* mark link not to be encrypted, so that when we execute security next * time it will kick in again */ if (p_dev_rec->hci_handle == handle) { // clasic - p_dev_rec->sec_flags &= ~BTM_SEC_ENCRYPTED; + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_ENCRYPTED; } else if (p_dev_rec->ble_hci_handle == handle) { // BLE - p_dev_rec->sec_flags &= ~BTM_SEC_LE_ENCRYPTED; + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_LE_ENCRYPTED; } else { LOG_ERROR( "Received encryption change for unknown device handle:0x%04x " @@ -3422,8 +3245,8 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, } } - const bool is_encrypted = - p_dev_rec->is_le_device_encrypted() || p_dev_rec->is_device_encrypted(); + const bool is_encrypted = p_dev_rec->sec_rec.is_le_device_encrypted() || + p_dev_rec->sec_rec.is_device_encrypted(); BTM_LogHistory( kBtmLogTag, (transport == BT_TRANSPORT_LE) ? p_dev_rec->ble.pseudo_addr @@ -3434,67 +3257,68 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, bt_transport_text(transport).c_str(), is_encrypted ? 'T' : 'F')); - LOG_DEBUG("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags); + LOG_DEBUG("after update p_dev_rec->sec_rec.sec_flags=0x%x", + p_dev_rec->sec_rec.sec_flags); btm_sec_check_pending_enc_req(p_dev_rec, transport, encr_enable); if (transport == BT_TRANSPORT_LE) { if (status == HCI_ERR_KEY_MISSING || status == HCI_ERR_AUTH_FAILURE || status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) { - p_dev_rec->sec_flags &= ~(BTM_SEC_LE_LINK_KEY_KNOWN); - p_dev_rec->ble.key_type = BTM_LE_KEY_NONE; + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LE_LINK_KEY_KNOWN); + p_dev_rec->sec_rec.ble_keys.key_type = BTM_LE_KEY_NONE; } - p_dev_rec->sec_status = status; + p_dev_rec->sec_rec.sec_status = status; btm_ble_link_encrypted(p_dev_rec->ble.pseudo_addr, encr_enable); return; } else { /* BR/EDR connection, update the encryption key size to be 16 as always */ - p_dev_rec->enc_key_size = 16; + p_dev_rec->sec_rec.enc_key_size = 16; } - LOG_DEBUG("in new_encr_key_256 is %d", p_dev_rec->new_encryption_key_is_p256); + LOG_DEBUG("in new_encr_key_256 is %d", + p_dev_rec->sec_rec.new_encryption_key_is_p256); if ((status == HCI_SUCCESS) && encr_enable && (p_dev_rec->hci_handle == handle)) { /* if BR key is temporary no need for LE LTK derivation */ bool derive_ltk = true; - if (p_dev_rec->rmt_auth_req == BTM_AUTH_SP_NO && - btm_cb.devcb.loc_auth_req == BTM_AUTH_SP_NO) { + if (p_dev_rec->sec_rec.rmt_auth_req == BTM_AUTH_SP_NO && + btm_sec_cb.devcb.loc_auth_req == BTM_AUTH_SP_NO) { derive_ltk = false; - BTM_TRACE_DEBUG("%s: BR key is temporary, skip derivation of LE LTK", - __func__); + LOG_VERBOSE("BR key is temporary, skip derivation of LE LTK"); } tHCI_ROLE role = HCI_ROLE_UNKNOWN; BTM_GetRole(p_dev_rec->bd_addr, &role); - if (p_dev_rec->new_encryption_key_is_p256) { + if (p_dev_rec->sec_rec.new_encryption_key_is_p256) { if (btm_sec_use_smp_br_chnl(p_dev_rec) && role == HCI_ROLE_CENTRAL && /* if LE key is not known, do deriving */ - (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) || + (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) || /* or BR key is higher security than existing LE keys */ - (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) && - (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED))) && + (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) && + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_AUTHED))) && derive_ltk) { /* BR/EDR is encrypted with LK that can be used to derive LE LTK */ - p_dev_rec->new_encryption_key_is_p256 = false; + p_dev_rec->sec_rec.new_encryption_key_is_p256 = false; - BTM_TRACE_DEBUG("%s start SM over BR/EDR", __func__); + LOG_VERBOSE("start SM over BR/EDR"); SMP_BR_PairWith(p_dev_rec->bd_addr); } } } /* If this encryption was started by peer do not need to do anything */ - if (!p_dev_rec->is_security_state_bredr_encrypting()) { - if (BTM_SEC_STATE_DELAY_FOR_ENC == p_dev_rec->sec_state) { - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; - BTM_TRACE_DEBUG("%s: clearing callback. p_dev_rec=%p, p_callback=%p", - __func__, p_dev_rec, p_dev_rec->p_callback); - p_dev_rec->p_callback = NULL; + if (!p_dev_rec->sec_rec.is_security_state_bredr_encrypting()) { + if (BTM_SEC_STATE_DELAY_FOR_ENC == p_dev_rec->sec_rec.sec_state) { + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; + LOG_VERBOSE("clearing callback. p_dev_rec=%p, p_callback=%p", p_dev_rec, + p_dev_rec->sec_rec.p_callback); + p_dev_rec->sec_rec.p_callback = NULL; l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr); return; } else if (!concurrentPeerAuthIsEnabled() && - p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) { - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_AUTHENTICATING) { + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; return; } if (!handleUnexpectedEncryptionChange()) { @@ -3502,7 +3326,7 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, } } - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; /* If encryption setup failed, notify the waiting layer */ if (status != HCI_SUCCESS) { btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, false); @@ -3513,7 +3337,8 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, tBTM_STATUS btm_status = btm_sec_execute_procedure(p_dev_rec); /* If there is no next procedure, or procedure failed to start, notify the * caller */ - if (status != BTM_CMD_STARTED) + if (static_cast>(status) != + BTM_CMD_STARTED) btm_sec_dev_rec_cback_event(p_dev_rec, btm_status, false); } @@ -3521,23 +3346,23 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, * * Function btm_sec_connect_after_reject_timeout * - * Description Connection for bonding could not start because of the - * collision. Initiate outgoing connection + * Description This function is used to re-initiate an outgoing ACL + * connection in case the ACL connection for bonding failed, + * e.g., because of the collision. * - * Returns Pointer to the TLE struct + * Returns void * ******************************************************************************/ -static void btm_sec_connect_after_reject_timeout(UNUSED_ATTR void* data) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_cb.p_collided_dev_rec; +static void btm_sec_connect_after_reject_timeout(void* /* data */) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_sec_cb.p_collided_dev_rec; - BTM_TRACE_EVENT("%s", __func__); - btm_cb.p_collided_dev_rec = 0; + LOG_VERBOSE("restarting ACL connection"); + btm_sec_cb.p_collided_dev_rec = 0; if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) { - BTM_TRACE_WARNING("Security Manager: %s: failed to start connection", - __func__); + LOG_WARN("Security Manager: failed to start connection"); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); NotifyBondingChange(*p_dev_rec, HCI_ERR_MEMORY_FULL); } @@ -3547,8 +3372,8 @@ static void btm_sec_connect_after_reject_timeout(UNUSED_ATTR void* data) { * * Function btm_sec_connected * - * Description This function is when a connection to the peer device is - * established + * Description This function is called when a (BR/EDR) ACL connection to + * the peer device is established * * Returns void * @@ -3561,15 +3386,14 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, bool addr_matched; uint8_t bit_shift = 0; - btm_acl_resubmit_page(); - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda); if (!p_dev_rec) { LOG_DEBUG( "Connected to new device state:%s handle:0x%04x status:%s " "enc_mode:%hhu bda:%s", - btm_pair_state_descr(btm_cb.pairing_state), handle, - hci_status_code_text(status).c_str(), enc_mode, ADDRESS_TO_LOGGABLE_CSTR(bda)); + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), handle, + hci_status_code_text(status).c_str(), enc_mode, + ADDRESS_TO_LOGGABLE_CSTR(bda)); if (status == HCI_SUCCESS) { p_dev_rec = btm_sec_alloc_dev(bda); @@ -3578,60 +3402,65 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, } else { /* If the device matches with stored paring address * reset the paring state to idle */ - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - btm_cb.pairing_bda == bda) { + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + btm_sec_cb.pairing_bda == bda) { LOG_WARN("Connection failed during bonding attempt peer:%s reason:%s", ADDRESS_TO_LOGGABLE_CSTR(bda), hci_error_code_text(status).c_str()); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); } LOG_DEBUG("Ignoring failed device connection peer:%s reason:%s", ADDRESS_TO_LOGGABLE_CSTR(bda), hci_error_code_text(status).c_str()); return; } - } else /* Update the timestamp for this device */ - { + } else { LOG_DEBUG( "Connected to known device state:%s handle:0x%04x status:%s " "enc_mode:%hhu bda:%s RName:%s", - btm_pair_state_descr(btm_cb.pairing_state), handle, - hci_status_code_text(status).c_str(), enc_mode, ADDRESS_TO_LOGGABLE_CSTR(bda), - p_dev_rec->sec_bd_name); + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), handle, + hci_status_code_text(status).c_str(), enc_mode, + ADDRESS_TO_LOGGABLE_CSTR(bda), p_dev_rec->sec_bd_name); bit_shift = (handle == p_dev_rec->ble_hci_handle) ? 8 : 0; - p_dev_rec->timestamp = btm_cb.dev_rec_count++; + /* Update the timestamp for this device */ + p_dev_rec->timestamp = btm_sec_cb.dev_rec_count++; if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) { - /* tell L2CAP it's a bonding connection. */ - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - (btm_cb.pairing_bda == p_dev_rec->bd_addr) && - (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) { - /* if incoming connection failed while pairing, then try to connect and - * continue */ + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (btm_sec_cb.pairing_bda == p_dev_rec->bd_addr) && + (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) { + /* if incoming acl connection failed while pairing, then try to connect + * and continue */ /* Motorola S9 disconnects without asking pin code */ if ((status != HCI_SUCCESS) && - (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ)) { - BTM_TRACE_WARNING( - "Security Manager: btm_sec_connected: incoming connection failed " + (btm_sec_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ)) { + LOG_WARN( + "Security Manager: btm_sec_connected: incoming connection " + "failed " "without asking PIN"); p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND; - if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) { + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_NAME_KNOWN) { + /* remote device name is known, start a new acl connection */ + /* Start timer with 0 to initiate connection with new LCB */ /* because L2CAP will delete current LCB with this event */ - btm_cb.p_collided_dev_rec = p_dev_rec; - alarm_set_on_mloop(btm_cb.sec_collision_timer, 0, + btm_sec_cb.p_collided_dev_rec = p_dev_rec; + alarm_set_on_mloop(btm_sec_cb.sec_collision_timer, 0, btm_sec_connect_after_reject_timeout, NULL); } else { - btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME); + /* remote device name is unknowm, start getting remote name first */ + + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME); if (BTM_ReadRemoteDeviceName(p_dev_rec->bd_addr, NULL, BT_TRANSPORT_BR_EDR) != BTM_CMD_STARTED) { - BTM_TRACE_ERROR("%s cannot read remote name", __func__); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + LOG_ERROR("cannot read remote name"); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); } } return; } else { + /* tell L2CAP it's a bonding connection. */ l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, true); } } @@ -3642,35 +3471,35 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR; - addr_matched = (btm_cb.pairing_bda == bda); + addr_matched = (btm_sec_cb.pairing_bda == bda); - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && addr_matched) { + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && addr_matched) { /* if we rejected incoming connection from bonding device */ if ((status == HCI_ERR_HOST_REJECT_DEVICE) && - (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)) { - BTM_TRACE_WARNING( + (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)) { + LOG_WARN( "Security Manager: btm_sec_connected: HCI_Conn_Comp Flags:0x%04x, " "sm4: 0x%x", - btm_cb.pairing_flags, p_dev_rec->sm4); + btm_sec_cb.pairing_flags, p_dev_rec->sm4); - btm_cb.pairing_flags &= ~BTM_PAIR_FLAGS_REJECTED_CONNECT; + btm_sec_cb.pairing_flags &= ~BTM_PAIR_FLAGS_REJECTED_CONNECT; if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) { /* Try again: RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME); if (BTM_ReadRemoteDeviceName(bda, NULL, BT_TRANSPORT_BR_EDR) != BTM_CMD_STARTED) { - BTM_TRACE_ERROR("%s cannot read remote name", __func__); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + LOG_ERROR("cannot read remote name"); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); } return; } /* if we already have pin code */ - if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) { + if (btm_sec_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) { /* Start timer with 0 to initiate connection with new LCB */ /* because L2CAP will delete current LCB with this event */ - btm_cb.p_collided_dev_rec = p_dev_rec; - alarm_set_on_mloop(btm_cb.sec_collision_timer, 0, + btm_sec_cb.p_collided_dev_rec = p_dev_rec; + alarm_set_on_mloop(btm_sec_cb.sec_collision_timer, 0, btm_sec_connect_after_reject_timeout, NULL); } @@ -3678,7 +3507,7 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, } /* wait for incoming connection without resetting pairing state */ else if (status == HCI_ERR_CONNECTION_EXISTS) { - BTM_TRACE_WARNING( + LOG_WARN( "Security Manager: btm_sec_connected: Wait for incoming connection"); return; } @@ -3693,12 +3522,13 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, if (status != HCI_SUCCESS) { /* If connection failed because of during pairing, need to tell user */ if (is_pairing_device) { - p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; - p_dev_rec->sec_flags &= + p_dev_rec->sec_rec.security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + p_dev_rec->sec_rec.sec_flags &= ~((BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED) << bit_shift); - BTM_TRACE_DEBUG("security_required:%x ", p_dev_rec->security_required); + LOG_VERBOSE("security_required:%x ", + p_dev_rec->sec_rec.security_required); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); /* We need to notify host that the key is not known any more */ NotifyBondingChange(*p_dev_rec, status); @@ -3709,7 +3539,7 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, 2. Link key for the remote device is present. 3. Remote is SSP capable. */ - else if ((p_dev_rec->link_key_type <= BTM_LKEY_TYPE_REMOTE_UNIT) && + else if ((p_dev_rec->sec_rec.link_key_type <= BTM_LKEY_TYPE_REMOTE_UNIT) && (((status == HCI_ERR_AUTH_FAILURE) || (status == HCI_ERR_KEY_MISSING) || (status == HCI_ERR_HOST_REJECT_SECURITY) || @@ -3718,8 +3548,8 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, (status == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) || (status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) || (status == HCI_ERR_REPEATED_ATTEMPTS)))) { - p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; - p_dev_rec->sec_flags &= ~(BTM_SEC_LE_LINK_KEY_KNOWN << bit_shift); + p_dev_rec->sec_rec.security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LE_LINK_KEY_KNOWN << bit_shift); #ifdef BRCM_NOT_4_BTE /* If we rejected pairing, pass this special result code */ @@ -3737,10 +3567,10 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, p_dev_rec = btm_find_dev(bda); if (!p_dev_rec) { /* Don't callback when device security record was removed */ - VLOG(1) << __func__ - << ": device security record associated with this bda has been " - "removed! bda=" - << bda << ", do not callback!"; + LOG_DEBUG( + "device security record associated with this bda has been " + "removed! bda=%s, do not callback", + ADDRESS_TO_LOGGABLE_CSTR(bda)); return; } @@ -3760,18 +3590,19 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, * the authenticate requirement bit. Reset the pairing state machine * and inform l2cap if the directed bonding was initiated. */ - if (is_pairing_device && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) { - if (p_dev_rec->link_key_not_sent) { - p_dev_rec->link_key_not_sent = false; + if (is_pairing_device && + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_KNOWN)) { + if (p_dev_rec->sec_rec.link_key_not_sent) { + p_dev_rec->sec_rec.link_key_not_sent = false; btm_send_link_key_notif(p_dev_rec); } - p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + p_dev_rec->sec_rec.security_required &= ~BTM_SEC_OUT_AUTHENTICATE; /* remember flag before it is initialized */ const bool is_pair_flags_we_started_dd = - btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD; - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD; + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); if (is_pair_flags_we_started_dd) { /* Let l2cap start bond timer */ @@ -3782,7 +3613,7 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, BTM_LogHistory(kBtmLogTag, bda, "Dedicated bonding", base::StringPrintf("Initiated:%c pairing_flag:0x%02x", (is_pair_flags_we_started_dd) ? 'T' : 'F', - p_dev_rec->sec_flags)); + p_dev_rec->sec_rec.sec_flags)); } p_dev_rec->hci_handle = handle; @@ -3802,18 +3633,18 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, /* Initialize security flags. We need to do that because some */ /* authorization complete could have come after the connection is dropped */ /* and that would set wrong flag that link has been authorized already */ - p_dev_rec->sec_flags &= + p_dev_rec->sec_rec.sec_flags &= ~((BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED) << bit_shift); if (enc_mode != HCI_ENCRYPT_MODE_DISABLED) - p_dev_rec->sec_flags |= + p_dev_rec->sec_rec.sec_flags |= ((BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED) << bit_shift); - if (p_dev_rec->pin_code_length >= 16 || - p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB || - p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { - p_dev_rec->sec_flags |= (BTM_SEC_16_DIGIT_PIN_AUTHED << bit_shift); + if (p_dev_rec->sec_rec.pin_code_length >= 16 || + p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB || + p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + p_dev_rec->sec_rec.sec_flags |= (BTM_SEC_16_DIGIT_PIN_AUTHED << bit_shift); } /* After connection is established we perform security if we do not know */ @@ -3821,13 +3652,12 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, /* been scheduled while connection was down */ LOG_DEBUG("Is connection locally initiated:%s", logbool(p_dev_rec->is_originator).c_str()); - if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || + if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator) { res = btm_sec_execute_procedure(p_dev_rec); if (res != BTM_CMD_STARTED) btm_sec_dev_rec_cback_event(p_dev_rec, res, false); } - return; } tBTM_STATUS btm_sec_disconnect(uint16_t handle, tHCI_STATUS reason, @@ -3844,11 +3674,11 @@ tBTM_STATUS btm_sec_disconnect(uint16_t handle, tHCI_STATUS reason, /* If we are in the process of bonding we need to tell client that auth failed */ - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - (btm_cb.pairing_bda == p_dev_rec->bd_addr) && - (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) { + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (btm_sec_cb.pairing_bda == p_dev_rec->bd_addr) && + (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) { /* we are currently doing bonding. Link will be disconnected when done */ - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE; + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE; return (BTM_BUSY); } @@ -3863,8 +3693,6 @@ void btm_sec_disconnected(uint16_t handle, tHCI_REASON reason, hci_error_code_text(reason).c_str(), handle, comment.c_str()); } - btm_acl_resubmit_page(); - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle); if (p_dev_rec == nullptr) { LOG_WARN("Got disconnect for unknown device record handle:0x%04x", handle); @@ -3879,13 +3707,13 @@ void btm_sec_disconnected(uint16_t handle, tHCI_REASON reason, /* If we are in the process of bonding we need to tell client that auth failed */ - const uint8_t old_pairing_flags = btm_cb.pairing_flags; - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - (btm_cb.pairing_bda == p_dev_rec->bd_addr)) { + const uint8_t old_pairing_flags = btm_sec_cb.pairing_flags; + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (btm_sec_cb.pairing_bda == p_dev_rec->bd_addr)) { LOG_DEBUG("Disconnected while pairing process active handle:0x%04x", handle); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); - p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN; + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); + p_dev_rec->sec_rec.sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN; /* If the disconnection reason is REPEATED_ATTEMPTS, send this error message to complete callback function @@ -3905,7 +3733,7 @@ void btm_sec_disconnected(uint16_t handle, tHCI_REASON reason, p_dev_rec = btm_find_dev_by_handle(handle); if (p_dev_rec == nullptr) { - // |btm_cb.api.p_auth_complete_callback| may cause |p_dev_rec| to be + // |btm_sec_cb.api.p_auth_complete_callback| may cause |p_dev_rec| to be // deallocated. LOG_WARN("Device record was deallocated after user callback"); return; @@ -3915,8 +3743,9 @@ void btm_sec_disconnected(uint16_t handle, tHCI_REASON reason, LOG_DEBUG( "Disconnection complete device:%s name:%s state:%s reason:%s sec_req:%x", ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->bd_addr), p_dev_rec->sec_bd_name, - btm_pair_state_descr(btm_cb.pairing_state), - hci_reason_code_text(reason).c_str(), p_dev_rec->security_required); + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), + hci_reason_code_text(reason).c_str(), + p_dev_rec->sec_rec.security_required); // TODO Should this be gated by the transport check below ? btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, &p_dev_rec->bd_addr, @@ -3925,61 +3754,56 @@ void btm_sec_disconnected(uint16_t handle, tHCI_REASON reason, if (transport == BT_TRANSPORT_LE) { p_dev_rec->ble_hci_handle = HCI_INVALID_HANDLE; - p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED | - BTM_SEC_ROLE_SWITCHED); - p_dev_rec->enc_key_size = 0; + p_dev_rec->sec_rec.sec_flags &= + ~(BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED | + BTM_SEC_ROLE_SWITCHED); + p_dev_rec->sec_rec.enc_key_size = 0; p_dev_rec->suggested_tx_octets = 0; - if ((p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) == 0) { - p_dev_rec->sec_flags &= + if ((p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) == 0) { + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LE_LINK_KEY_AUTHED | BTM_SEC_LE_AUTHENTICATED); } - - // This is for chips that don't support being in connected and advertising - // state at same time. - if (!p_dev_rec->IsLocallyInitiated()) { - btm_ble_advertiser_notify_terminated_legacy(HCI_SUCCESS, handle); - } } else { p_dev_rec->hci_handle = HCI_INVALID_HANDLE; - p_dev_rec->sec_flags &= + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED); // Remove temporary key. - if (p_dev_rec->bond_type == tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY) - p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN); + if (p_dev_rec->sec_rec.bond_type == BOND_TYPE_TEMPORARY) + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN); } /* Some devices hardcode sample LTK value from spec, instead of generating * one. Treat such devices as insecure, and remove such bonds on * disconnection. */ - if (is_sample_ltk(p_dev_rec->ble.keys.pltk)) { - LOG(INFO) << __func__ << " removing bond to device that used sample LTK: " - << p_dev_rec->bd_addr; + if (is_sample_ltk(p_dev_rec->sec_rec.ble_keys.pltk)) { + LOG_INFO("removing bond to device that used sample LTK: %s", + ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->bd_addr)); bta_dm_remove_device(p_dev_rec->bd_addr); return; } - if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH) { + if (p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH) { LOG_DEBUG("Waiting for other transport to disconnect current:%s", bt_transport_text(transport).c_str()); - p_dev_rec->sec_state = (transport == BT_TRANSPORT_LE) - ? BTM_SEC_STATE_DISCONNECTING - : BTM_SEC_STATE_DISCONNECTING_BLE; + p_dev_rec->sec_rec.sec_state = (transport == BT_TRANSPORT_LE) + ? BTM_SEC_STATE_DISCONNECTING + : BTM_SEC_STATE_DISCONNECTING_BLE; return; } - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; - p_dev_rec->security_required = BTM_SEC_NONE; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->sec_rec.security_required = BTM_SEC_NONE; - if (p_dev_rec->p_callback != nullptr) { - tBTM_SEC_CALLBACK* p_callback = p_dev_rec->p_callback; + if (p_dev_rec->sec_rec.p_callback != nullptr) { + tBTM_SEC_CALLBACK* p_callback = p_dev_rec->sec_rec.p_callback; /* when the peer device time out the authentication before we do, this call back must be reset here */ - p_dev_rec->p_callback = nullptr; - (*p_callback)(&p_dev_rec->bd_addr, transport, p_dev_rec->p_ref_data, + p_dev_rec->sec_rec.p_callback = nullptr; + (*p_callback)(&p_dev_rec->bd_addr, transport, p_dev_rec->sec_rec.p_ref_data, BTM_ERR_PROCESSING); LOG_DEBUG("Cleaned up pending security state device:%s transport:%s", ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->bd_addr), @@ -4001,6 +3825,54 @@ void btm_sec_role_changed(tHCI_STATUS hci_status, const RawAddress& bd_addr, } } +constexpr uint8_t MIN_KEY_SIZE = 7; + +static void read_encryption_key_size_complete_after_key_refresh( + uint8_t status, uint16_t handle, uint8_t key_size) { + if (status == HCI_ERR_INSUFFCIENT_SECURITY) { + /* If remote device stop the encryption before we call "Read Encryption Key + * Size", we might receive Insufficient Security, which means that link is + * no longer encrypted. */ + LOG_INFO("encryption stopped on link: 0x%x ", handle); + return; + } + + if (status != HCI_SUCCESS) { + LOG_INFO("disconnecting, status: 0x%x", status); + acl_disconnect_from_handle(handle, HCI_ERR_PEER_USER, + "stack::btu_hcif Key size fail"); + return; + } + + if (key_size < MIN_KEY_SIZE) { + LOG_ERROR( + "encryption key too short, disconnecting. handle: 0x%x key_size %d", + handle, key_size); + + acl_disconnect_from_handle(handle, HCI_ERR_HOST_REJECT_SECURITY, + "stack::btu::btu_hcif::read_encryption_key_size_" + "complete_after_key_refresh Key size too small"); + return; + } + + btm_sec_encrypt_change(handle, static_cast(status), + 1 /* enc_enable */); +} + +void btm_sec_encryption_key_refresh_complete(uint16_t handle, + tHCI_STATUS status) { + if (status != HCI_SUCCESS || BTM_IsBleConnection(handle) || + // Skip encryption key size check when using set_min_encryption_key_size + controller_get_interface()->supports_set_min_encryption_key_size()) { + btm_sec_encrypt_change(handle, static_cast(status), + (status == HCI_SUCCESS) ? 1 : 0); + } else { + btsnd_hcic_read_encryption_key_size( + handle, + base::Bind(&read_encryption_key_size_complete_after_key_refresh)); + } +} + /** This function is called when a new connection link key is generated */ void btm_sec_link_key_notification(const RawAddress& p_bda, const Octet16& link_key, uint8_t key_type) { @@ -4021,48 +3893,48 @@ void btm_sec_link_key_notification(const RawAddress& p_bda, btm_restore_mode(); if (key_type != BTM_LKEY_TYPE_CHANGED_COMB) - p_dev_rec->link_key_type = key_type; + p_dev_rec->sec_rec.link_key_type = key_type; - p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LINK_KEY_KNOWN; /* * Until this point in time, we do not know if MITM was enabled, hence we * add the extended security flag here. */ - if (p_dev_rec->pin_code_length >= 16 || - p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB || - p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { - p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED; - p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + if (p_dev_rec->sec_rec.pin_code_length >= 16 || + p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB || + p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LINK_KEY_AUTHED; + p_dev_rec->sec_rec.sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; } /* BR/EDR connection, update the encryption key size to be 16 as always */ - p_dev_rec->enc_key_size = 16; - p_dev_rec->link_key = link_key; + p_dev_rec->sec_rec.enc_key_size = 16; + p_dev_rec->sec_rec.link_key = link_key; - if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && - (btm_cb.pairing_bda == p_bda)) { - if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (btm_sec_cb.pairing_bda == p_bda)) { + if (btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) we_are_bonding = true; else - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); } /* save LTK derived LK no matter what */ if (ltk_derived_lk) { - if (btm_cb.api.p_link_key_callback) { - BTM_TRACE_DEBUG("%s() Save LTK derived LK (key_type = %d)", __func__, - p_dev_rec->link_key_type); - (*btm_cb.api.p_link_key_callback)( + if (btm_sec_cb.api.p_link_key_callback) { + LOG_VERBOSE("Save LTK derived LK (key_type = %d)", + p_dev_rec->sec_rec.link_key_type); + (*btm_sec_cb.api.p_link_key_callback)( p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, link_key, - p_dev_rec->link_key_type, true /* is_ctkd */); + p_dev_rec->sec_rec.link_key_type, true /* is_ctkd */); } } else { - if ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) || - (p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)) { - p_dev_rec->new_encryption_key_is_p256 = true; - BTM_TRACE_DEBUG("%s set new_encr_key_256 to %d", __func__, - p_dev_rec->new_encryption_key_is_p256); + if ((p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) || + (p_dev_rec->sec_rec.link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)) { + p_dev_rec->sec_rec.new_encryption_key_is_p256 = true; + LOG_VERBOSE("set new_encr_key_256 to %d", + p_dev_rec->sec_rec.new_encryption_key_is_p256); } } @@ -4070,13 +3942,14 @@ void btm_sec_link_key_notification(const RawAddress& p_bda, */ /* resolved. Unless it is a HID Device and we really need to send all link * keys. */ - if ((!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) && + if ((!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_NAME_KNOWN) && ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) != BTM_COD_MAJOR_PERIPHERAL)) && !ltk_derived_lk) { - VLOG(2) << __func__ << " Delayed BDA: " << p_bda << " Type:" << +key_type; + LOG_VERBOSE("Delayed BDA: %s, Type: %d", ADDRESS_TO_LOGGABLE_CSTR(p_bda), + key_type); - p_dev_rec->link_key_not_sent = true; + p_dev_rec->sec_rec.link_key_not_sent = true; /* If it is for bonding nothing else will follow, so we need to start name * resolution */ @@ -4084,28 +3957,28 @@ void btm_sec_link_key_notification(const RawAddress& p_bda, SendRemoteNameRequest(p_bda); } - BTM_TRACE_EVENT("rmt_io_caps:%d, sec_flags:x%x, dev_class[1]:x%02x", - p_dev_rec->rmt_io_caps, p_dev_rec->sec_flags, - p_dev_rec->dev_class[1]) + LOG_VERBOSE("rmt_io_caps:%d, sec_flags:x%x, dev_class[1]:x%02x", + p_dev_rec->sec_rec.rmt_io_caps, p_dev_rec->sec_rec.sec_flags, + p_dev_rec->dev_class[1]); return; } /* We will save link key only if the user authorized it - BTE report link key in * all cases */ #ifdef BRCM_NONE_BTE - if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED) + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_AUTHED) #endif { - if (btm_cb.api.p_link_key_callback) { + if (btm_sec_cb.api.p_link_key_callback) { if (ltk_derived_lk) { - BTM_TRACE_DEBUG( + LOG_VERBOSE( "btm_sec_link_key_notification() LTK derived LK is saved already" " (key_type = %d)", - p_dev_rec->link_key_type); + p_dev_rec->sec_rec.link_key_type); } else { - (*btm_cb.api.p_link_key_callback)( + (*btm_sec_cb.api.p_link_key_callback)( p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, link_key, - p_dev_rec->link_key_type, false /* is_ctkd */); + p_dev_rec->sec_rec.link_key_type, false /* is_ctkd */); } } } @@ -4120,29 +3993,26 @@ void btm_sec_link_key_notification(const RawAddress& p_bda, * Returns Pointer to the record or NULL * ******************************************************************************/ -void btm_sec_link_key_request(const uint8_t* p_event) { - RawAddress bda; - - STREAM_TO_BDADDR(bda, p_event); +void btm_sec_link_key_request(const RawAddress bda) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda); - VLOG(2) << __func__ << " bda: " << bda; + LOG_VERBOSE("bda: %s", ADDRESS_TO_LOGGABLE_CSTR(bda)); if (!concurrentPeerAuthIsEnabled()) { - p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_AUTHENTICATING; } - if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) && - (btm_cb.collision_start_time != 0) && - (btm_cb.p_collided_dev_rec->bd_addr == bda)) { - BTM_TRACE_EVENT( + if ((btm_sec_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) && + (btm_sec_cb.collision_start_time != 0) && + (btm_sec_cb.p_collided_dev_rec->bd_addr == bda)) { + LOG_VERBOSE( "btm_sec_link_key_request() rejecting link key req " - "State: %d START_TIMEOUT : %d", - btm_cb.pairing_state, btm_cb.collision_start_time); + "State: %d START_TIMEOUT : %" PRIu64, + btm_sec_cb.pairing_state, btm_sec_cb.collision_start_time); btsnd_hcic_link_key_neg_reply(bda); return; } - if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) { - btsnd_hcic_link_key_req_reply(bda, p_dev_rec->link_key); + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_KNOWN) { + btsnd_hcic_link_key_req_reply(bda, p_dev_rec->sec_rec.link_key); return; } @@ -4163,19 +4033,19 @@ void btm_sec_link_key_request(const uint8_t* p_event) { * Returns Pointer to the TLE struct * ******************************************************************************/ -static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) { - tBTM_CB* p_cb = &btm_cb; +static void btm_sec_pairing_timeout(void* /* data */) { + tBTM_SEC_CB* p_cb = &btm_sec_cb; tBTM_SEC_DEV_REC* p_dev_rec; - tBTM_AUTH_REQ auth_req = (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_NONE) + tBTM_AUTH_REQ auth_req = (btm_sec_cb.devcb.loc_io_caps == BTM_IO_CAP_NONE) ? BTM_AUTH_AP_NO : BTM_AUTH_AP_YES; BD_NAME name; p_dev_rec = btm_find_dev(p_cb->pairing_bda); - BTM_TRACE_EVENT("%s State: %s Flags: %u", __func__, - btm_pair_state_descr(p_cb->pairing_state), - p_cb->pairing_flags); + LOG_VERBOSE("State: %s Flags: %u", + tBTM_SEC_CB::btm_pair_state_descr(p_cb->pairing_state), + p_cb->pairing_flags); switch (p_cb->pairing_state) { case BTM_PAIR_STATE_WAIT_PIN_REQ: @@ -4183,15 +4053,15 @@ static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) { break; case BTM_PAIR_STATE_WAIT_LOCAL_PIN: - if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PRE_FETCH_PIN) == 0) + if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_PRE_FETCH_PIN) == 0) btsnd_hcic_pin_code_neg_reply(p_cb->pairing_bda); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); /* We need to notify the UI that no longer need the PIN */ - if (btm_cb.api.p_auth_complete_callback) { + if (btm_sec_cb.api.p_auth_complete_callback) { if (p_dev_rec == NULL) { name[0] = 0; - (*btm_cb.api.p_auth_complete_callback)(p_cb->pairing_bda, NULL, name, - HCI_ERR_CONNECTION_TOUT); + (*btm_sec_cb.api.p_auth_complete_callback)( + p_cb->pairing_bda, NULL, name, HCI_ERR_CONNECTION_TOUT); } else NotifyBondingChange(*p_dev_rec, HCI_ERR_CONNECTION_TOUT); } @@ -4199,27 +4069,28 @@ static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) { case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM: btsnd_hcic_user_conf_reply(p_cb->pairing_bda, false); - /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */ + /* btm_sec_cb.change_pairing_state (BTM_PAIR_STATE_IDLE); */ break; case BTM_PAIR_STATE_KEY_ENTRY: - if (btm_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) { + if (btm_sec_cb.devcb.loc_io_caps != BTM_IO_CAP_NONE) { btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda); } else { - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); } break; case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS: // TODO(optedoblivion): Inject OOB_DATA_PRESENT Flag - btsnd_hcic_io_cap_req_reply(p_cb->pairing_bda, btm_cb.devcb.loc_io_caps, - BTM_OOB_NONE, auth_req); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btsnd_hcic_io_cap_req_reply(p_cb->pairing_bda, + btm_sec_cb.devcb.loc_io_caps, BTM_OOB_NONE, + auth_req); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); break; case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP: btsnd_hcic_rem_oob_neg_reply(p_cb->pairing_bda); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); break; case BTM_PAIR_STATE_WAIT_DISCONNECT: @@ -4227,27 +4098,26 @@ static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) { * complete. * now it's time to tear down the ACL link*/ if (p_dev_rec == NULL) { - LOG(ERROR) << __func__ - << " BTM_PAIR_STATE_WAIT_DISCONNECT unknown BDA: " - << p_cb->pairing_bda; + LOG_ERROR("BTM_PAIR_STATE_WAIT_DISCONNECT unknown BDA: %s", + ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); break; } btm_sec_send_hci_disconnect( p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle, "stack::btm::btm_sec::btm_sec_pairing_timeout"); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); break; case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE: case BTM_PAIR_STATE_GET_REM_NAME: /* We need to notify the UI that timeout has happened while waiting for * authentication*/ - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); - if (btm_cb.api.p_auth_complete_callback) { + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); + if (btm_sec_cb.api.p_auth_complete_callback) { if (p_dev_rec == NULL) { name[0] = 0; - (*btm_cb.api.p_auth_complete_callback)(p_cb->pairing_bda, NULL, name, - HCI_ERR_CONNECTION_TOUT); + (*btm_sec_cb.api.p_auth_complete_callback)( + p_cb->pairing_bda, NULL, name, HCI_ERR_CONNECTION_TOUT); } else { NotifyBondingChange(*p_dev_rec, HCI_ERR_CONNECTION_TOUT); } @@ -4255,9 +4125,9 @@ static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) { break; default: - BTM_TRACE_WARNING("%s not processed state: %s", __func__, - btm_pair_state_descr(btm_cb.pairing_state)); - btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + LOG_WARN("not processed state: %s", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state)); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_IDLE); break; } } @@ -4271,19 +4141,17 @@ static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) { * Returns Pointer to the record or NULL * ******************************************************************************/ -void btm_sec_pin_code_request(const uint8_t* p_event) { +void btm_sec_pin_code_request(const RawAddress p_bda) { tBTM_SEC_DEV_REC* p_dev_rec; - tBTM_CB* p_cb = &btm_cb; - RawAddress p_bda; - - STREAM_TO_BDADDR(p_bda, p_event); + tBTM_SEC_CB* p_cb = &btm_sec_cb; /* Tell L2CAP that there was a PIN code request, */ /* it may need to stretch timeouts */ l2c_pin_code_request(p_bda); LOG_DEBUG("Controller requests PIN code device:%s state:%s", - ADDRESS_TO_LOGGABLE_CSTR(p_bda), btm_pair_state_descr(btm_cb.pairing_state)); + ADDRESS_TO_LOGGABLE_CSTR(p_bda), + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state)); RawAddress local_bd_addr = *controller_get_interface()->get_address(); if (p_bda == local_bd_addr) { @@ -4291,15 +4159,15 @@ void btm_sec_pin_code_request(const uint8_t* p_event) { return; } - if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) { - if ((p_bda == btm_cb.pairing_bda) && - (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE)) { + if (btm_sec_cb.pairing_state != BTM_PAIR_STATE_IDLE) { + if ((p_bda == btm_sec_cb.pairing_bda) && + (btm_sec_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE)) { btsnd_hcic_pin_code_neg_reply(p_bda); return; - } else if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_PIN_REQ) || - p_bda != btm_cb.pairing_bda) { - BTM_TRACE_WARNING("btm_sec_pin_code_request() rejected - state: %s", - btm_pair_state_descr(btm_cb.pairing_state)); + } else if ((btm_sec_cb.pairing_state != BTM_PAIR_STATE_WAIT_PIN_REQ) || + p_bda != btm_sec_cb.pairing_bda) { + LOG_WARN("btm_sec_pin_code_request() rejected - state: %s", + tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state)); btsnd_hcic_pin_code_neg_reply(p_bda); return; } @@ -4309,15 +4177,15 @@ void btm_sec_pin_code_request(const uint8_t* p_event) { /* received PIN code request. must be non-sm4 */ p_dev_rec->sm4 = BTM_SM4_KNOWN; - if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) { - btm_cb.pairing_bda = p_bda; + if (btm_sec_cb.pairing_state == BTM_PAIR_STATE_IDLE) { + btm_sec_cb.pairing_bda = p_bda; - btm_cb.pairing_flags = BTM_PAIR_FLAGS_PEER_STARTED_DD; + btm_sec_cb.pairing_flags = BTM_PAIR_FLAGS_PEER_STARTED_DD; } if (!p_cb->pairing_disabled && (p_cb->cfg.pin_type == HCI_PIN_TYPE_FIXED)) { - BTM_TRACE_EVENT("btm_sec_pin_code_request fixed pin replying"); - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + LOG_VERBOSE("btm_sec_pin_code_request fixed pin replying"); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); btsnd_hcic_pin_code_req_reply(p_bda, p_cb->cfg.pin_code_len, p_cb->cfg.pin_code); return; @@ -4330,19 +4198,20 @@ void btm_sec_pin_code_request(const uint8_t* p_event) { memcpy(p_dev_rec->dev_class, p_cb->connecting_dc, DEV_CLASS_LEN); /* We could have started connection after asking user for the PIN code */ - if (btm_cb.pin_code_len != 0) { - BTM_TRACE_EVENT("btm_sec_pin_code_request bonding sending reply"); - btsnd_hcic_pin_code_req_reply(p_bda, btm_cb.pin_code_len, p_cb->pin_code); + if (btm_sec_cb.pin_code_len != 0) { + LOG_VERBOSE("btm_sec_pin_code_request bonding sending reply"); + btsnd_hcic_pin_code_req_reply(p_bda, btm_sec_cb.pin_code_len, + p_cb->pin_code); /* Mark that we forwarded received from the user PIN code */ - btm_cb.pin_code_len = 0; + btm_sec_cb.pin_code_len = 0; /* We can change mode back right away, that other connection being * established */ /* is not forced to be secure - found a FW issue, so we can not do this btm_restore_mode(); */ - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); } /* If pairing disabled OR (no PIN callback and not bonding) */ @@ -4360,16 +4229,16 @@ void btm_sec_pin_code_request(const uint8_t* p_event) { ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL) && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD))) { - BTM_TRACE_WARNING( - "btm_sec_pin_code_request(): Pairing disabled:%d; PIN callback:%x, Dev " - "Rec:%x!", + LOG_WARN( + "btm_sec_pin_code_request(): Pairing disabled:%d; PIN callback:%p, Dev " + "Rec:%p!", p_cb->pairing_disabled, p_cb->api.p_pin_callback, p_dev_rec); btsnd_hcic_pin_code_neg_reply(p_bda); } /* Notify upper layer of PIN request and start expiration timer */ else { - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN); /* Pin code request can not come at the same time as connection request */ p_cb->connecting_bda = p_bda; memcpy(p_cb->connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN); @@ -4380,18 +4249,18 @@ void btm_sec_pin_code_request(const uint8_t* p_event) { /* device, so HCI level is flow controlled */ /* Also cannot send remote name request while paging, i.e. connection is not * completed */ - if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) { - BTM_TRACE_EVENT("btm_sec_pin_code_request going for callback"); + if (p_dev_rec->sec_rec.sec_flags & BTM_SEC_NAME_KNOWN) { + LOG_VERBOSE("btm_sec_pin_code_request going for callback"); - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; if (p_cb->api.p_pin_callback) { (*p_cb->api.p_pin_callback)( p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, - (p_dev_rec->required_security_flags_for_pairing & + (p_dev_rec->sec_rec.required_security_flags_for_pairing & BTM_SEC_IN_MIN_16_DIGIT_PIN)); } } else { - BTM_TRACE_EVENT("btm_sec_pin_code_request going for remote name"); + LOG_VERBOSE("btm_sec_pin_code_request going for remote name"); /* We received PIN code request for the device with unknown name */ /* it is not user friendly just to ask for the PIN without name */ @@ -4455,20 +4324,21 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) { CHECK(p_dev_rec != nullptr); LOG_DEBUG( "security_required:0x%x security_flags:0x%x security_state:%s[%hhu]", - p_dev_rec->security_required, p_dev_rec->sec_flags, - security_state_text(static_cast(p_dev_rec->sec_state)) + p_dev_rec->sec_rec.security_required, p_dev_rec->sec_rec.sec_flags, + security_state_text( + static_cast(p_dev_rec->sec_rec.sec_state)) .c_str(), - p_dev_rec->sec_state); + p_dev_rec->sec_rec.sec_state); - if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE && - p_dev_rec->sec_state != BTM_SEC_STATE_LE_ENCRYPTING) { + if (p_dev_rec->sec_rec.sec_state != BTM_SEC_STATE_IDLE && + p_dev_rec->sec_rec.sec_state != BTM_SEC_STATE_LE_ENCRYPTING) { LOG_INFO("No immediate action taken in busy state: %s", - security_state_text(p_dev_rec->sec_state).c_str()); + security_state_text(p_dev_rec->sec_rec.sec_state).c_str()); return (BTM_CMD_STARTED); } /* If any security is required, get the name first */ - if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) && + if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_NAME_KNOWN) && (p_dev_rec->hci_handle != HCI_INVALID_HANDLE)) { LOG_DEBUG("Security Manager: Start get name"); if (!btm_sec_start_get_name(p_dev_rec)) { @@ -4484,23 +4354,21 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) { bool start_auth = false; // Check link status of BR/EDR - if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) { + if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_AUTHENTICATED)) { if (p_dev_rec->IsLocallyInitiated()) { - if (p_dev_rec->security_required & - (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) { - LOG_DEBUG("Outgoing authentication/encryption Required"); + if (p_dev_rec->sec_rec.security_required & BTM_SEC_OUT_AUTHENTICATE) { + LOG_DEBUG("Outgoing authentication Required"); start_auth = true; } } else { - if (p_dev_rec->security_required & - (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) { - LOG_DEBUG("Incoming authentication/encryption Required"); + if (p_dev_rec->sec_rec.security_required & BTM_SEC_IN_AUTHENTICATE) { + LOG_DEBUG("Incoming authentication Required"); start_auth = true; } } } - if (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)) { + if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)) { /* * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use, * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the @@ -4508,7 +4376,8 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) { * authenticated connections, hence we cannot distinguish here. */ if (!p_dev_rec->IsLocallyInitiated()) { - if (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) { + if (p_dev_rec->sec_rec.security_required & + BTM_SEC_IN_MIN_16_DIGIT_PIN) { LOG_DEBUG("BTM_SEC_IN_MIN_16_DIGIT_PIN Required"); start_auth = true; } @@ -4529,11 +4398,12 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) { * or even IOP issues, if a reconnect causes a new connection that * requires an upgrade. */ - if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) && - (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) && - (!p_dev_rec->IsLocallyInitiated() && - (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) { - p_dev_rec->sec_flags &= + if ((p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_KNOWN) && + (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) && + (!p_dev_rec->IsLocallyInitiated() && + (p_dev_rec->sec_rec.security_required & + BTM_SEC_IN_MIN_16_DIGIT_PIN)))) { + p_dev_rec->sec_rec.sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_AUTHENTICATED); } @@ -4545,42 +4415,43 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) { /* If connection is not encrypted and encryption is required */ /* start encryption and return PENDING to the caller */ - if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) && + if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_ENCRYPTED) && ((p_dev_rec->IsLocallyInitiated() && - (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT)) || + (p_dev_rec->sec_rec.security_required & BTM_SEC_OUT_ENCRYPT)) || (!p_dev_rec->IsLocallyInitiated() && - (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT))) && + (p_dev_rec->sec_rec.security_required & BTM_SEC_IN_ENCRYPT))) && (p_dev_rec->hci_handle != HCI_INVALID_HANDLE)) { - BTM_TRACE_EVENT("Security Manager: Start encryption"); + LOG_VERBOSE("Security Manager: Start encryption"); btsnd_hcic_set_conn_encrypt(p_dev_rec->hci_handle, true); - p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_ENCRYPTING; return (BTM_CMD_STARTED); } else { LOG_DEBUG("Encryption not required"); } - if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && - (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { - BTM_TRACE_EVENT( - "%s: Security Manager: SC only service, but link key type is 0x%02x -", - "security failure", __func__, p_dev_rec->link_key_type); + if ((p_dev_rec->sec_rec.security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->sec_rec.link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) { + LOG_VERBOSE( + "Security Manager: SC only service, but link key type is 0x%02x -" + "security failure", + p_dev_rec->sec_rec.link_key_type); return (BTM_FAILED_ON_SECURITY); } - if (access_secure_service_from_temp_bond(p_dev_rec, - p_dev_rec->IsLocallyInitiated(), - p_dev_rec->security_required)) { + if (access_secure_service_from_temp_bond( + p_dev_rec, p_dev_rec->IsLocallyInitiated(), + p_dev_rec->sec_rec.security_required)) { LOG_ERROR("Trying to access a secure service from a temp bonding, rejecting"); return (BTM_FAILED_ON_SECURITY); } /* All required security procedures already established */ - p_dev_rec->security_required &= + p_dev_rec->sec_rec.security_required &= ~(BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT); - BTM_TRACE_EVENT("Security Manager: access granted"); + LOG_VERBOSE("Security Manager: access granted"); return (BTM_SUCCESS); } @@ -4597,7 +4468,7 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) { static bool btm_sec_start_get_name(tBTM_SEC_DEV_REC* p_dev_rec) { if (!BTM_IsDeviceUp()) return false; - p_dev_rec->sec_state = BTM_SEC_STATE_GETTING_NAME; + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_GETTING_NAME; /* 0 and NULL are as timeout and callback params because they are not used in * security get name case */ @@ -4627,8 +4498,7 @@ static void btm_sec_wait_and_start_authentication(tBTM_SEC_DEV_REC* p_dev_rec) { base::Milliseconds(delay_auth)); #endif if (status != BT_STATUS_SUCCESS) { - LOG(ERROR) << __func__ - << ": do_in_main_thread_delayed failed. directly calling."; + LOG_ERROR("do_in_main_thread_delayed failed. directly calling"); btm_sec_auth_timer_timeout(addr); } } @@ -4645,47 +4515,23 @@ static void btm_sec_auth_timer_timeout(void* data) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(*p_addr); delete p_addr; if (p_dev_rec == NULL) { - LOG_INFO("%s: invalid device or not found", __func__); + LOG_INFO("invalid device or not found"); } else if (btm_dev_authenticated(p_dev_rec)) { - LOG_INFO("%s: device is already authenticated", __func__); - } else if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) { - LOG_INFO("%s: device is in the process of authenticating", __func__); + LOG_INFO("device is already authenticated"); + if (p_dev_rec->sec_rec.p_callback) { + (*p_dev_rec->sec_rec.p_callback)(&p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, + p_dev_rec->sec_rec.p_ref_data, + BTM_SUCCESS); + } + } else if (p_dev_rec->sec_rec.sec_state == BTM_SEC_STATE_AUTHENTICATING) { + LOG_INFO("device is in the process of authenticating"); } else { - LOG_INFO("%s: starting authentication", __func__); - p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; + LOG_INFO("starting authentication"); + p_dev_rec->sec_rec.sec_state = BTM_SEC_STATE_AUTHENTICATING; btsnd_hcic_auth_request(p_dev_rec->hci_handle); } } -/******************************************************************************* - * - * Function btm_sec_find_first_serv - * - * Description Look for the first record in the service database - * with specified PSM - * - * Returns Pointer to the record or NULL - * - ******************************************************************************/ -tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm) { - tBTM_SEC_SERV_REC* p_serv_rec = &btm_cb.sec_serv_rec[0]; - int i; - - if (is_originator && btm_cb.p_out_serv && btm_cb.p_out_serv->psm == psm) { - /* If this is outgoing connection and the PSM matches p_out_serv, - * use it as the current service */ - return btm_cb.p_out_serv; - } - - /* otherwise, just find the first record with the specified PSM */ - for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) { - if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) && - (p_serv_rec->psm == psm)) - return (p_serv_rec); - } - return (NULL); -} - /******************************************************************************* * * Function btm_sec_collision_timeout @@ -4696,16 +4542,16 @@ tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm) { * Returns Pointer to the TLE struct * ******************************************************************************/ -static void btm_sec_collision_timeout(UNUSED_ATTR void* data) { - BTM_TRACE_EVENT("%s()", __func__); +static void btm_sec_collision_timeout(void* /* data */) { + LOG_VERBOSE("restaring security process after collision"); - tBTM_STATUS status = btm_sec_execute_procedure(btm_cb.p_collided_dev_rec); + tBTM_STATUS status = btm_sec_execute_procedure(btm_sec_cb.p_collided_dev_rec); /* If result is pending reply from the user or from the device is pending */ if (status != BTM_CMD_STARTED) { /* There is no next procedure or start of procedure failed, notify the * waiting layer */ - btm_sec_dev_rec_cback_event(btm_cb.p_collided_dev_rec, status, false); + btm_sec_dev_rec_cback_event(btm_sec_cb.p_collided_dev_rec, status, false); } } @@ -4719,10 +4565,10 @@ static void btm_sec_collision_timeout(UNUSED_ATTR void* data) { * ******************************************************************************/ static void btm_send_link_key_notif(tBTM_SEC_DEV_REC* p_dev_rec) { - if (btm_cb.api.p_link_key_callback) - (*btm_cb.api.p_link_key_callback)( + if (btm_sec_cb.api.p_link_key_callback) + (*btm_sec_cb.api.p_link_key_callback)( p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, - p_dev_rec->link_key, p_dev_rec->link_key_type, false); + p_dev_rec->sec_rec.link_key, p_dev_rec->sec_rec.link_key_type, false); } /******************************************************************************* @@ -4737,85 +4583,60 @@ static void btm_send_link_key_notif(tBTM_SEC_DEV_REC* p_dev_rec) { * ******************************************************************************/ static void btm_restore_mode(void) { - if (btm_cb.security_mode_changed) { - btm_cb.security_mode_changed = false; + if (btm_sec_cb.security_mode_changed) { + btm_sec_cb.security_mode_changed = false; btsnd_hcic_write_auth_enable(false); } - if (btm_cb.pin_type_changed) { - btm_cb.pin_type_changed = false; - btsnd_hcic_write_pin_type(btm_cb.cfg.pin_type); + if (btm_sec_cb.pin_type_changed) { + btm_sec_cb.pin_type_changed = false; + btsnd_hcic_write_pin_type(btm_sec_cb.cfg.pin_type); } } -bool is_sec_state_equal(void* data, void* context) { - tBTM_SEC_DEV_REC* p_dev_rec = static_cast(data); - uint8_t* state = static_cast(context); - - if (p_dev_rec->sec_state == *state) return false; - - return true; -} - -/******************************************************************************* - * - * Function btm_sec_find_dev_by_sec_state - * - * Description Look for the record in the device database for the device - * which is being authenticated or encrypted - * - * Returns Pointer to the record or NULL - * - ******************************************************************************/ -tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state) { - list_node_t* n = list_foreach(btm_cb.sec_dev_rec, is_sec_state_equal, &state); - if (n) return static_cast(list_node(n)); - - return NULL; -} - /******************************************************************************* * - * Function btm_sec_change_pairing_state + * Function change_pairing_state * * Description This function is called to change pairing state * ******************************************************************************/ -static void btm_sec_change_pairing_state(tBTM_PAIRING_STATE new_state) { - tBTM_PAIRING_STATE old_state = btm_cb.pairing_state; +void tBTM_SEC_CB::change_pairing_state(tBTM_PAIRING_STATE new_state) { + tBTM_PAIRING_STATE old_state = pairing_state; LOG_DEBUG("Pairing state changed %s => %s pairing_flags:0x%x", - btm_pair_state_descr(btm_cb.pairing_state), - btm_pair_state_descr(new_state), btm_cb.pairing_flags); + tBTM_SEC_CB::btm_pair_state_descr(pairing_state), + tBTM_SEC_CB::btm_pair_state_descr(new_state), pairing_flags); - if (btm_cb.pairing_state != new_state) { - BTM_LogHistory(kBtmLogTag, btm_cb.pairing_bda, "Pairing state changed", - base::StringPrintf( - "%s => %s", btm_pair_state_descr(btm_cb.pairing_state), - btm_pair_state_descr(new_state))); + if (pairing_state != new_state) { + BTM_LogHistory( + kBtmLogTag, btm_sec_cb.pairing_bda, "Pairing state changed", + base::StringPrintf("%s => %s", + tBTM_SEC_CB::btm_pair_state_descr(pairing_state), + tBTM_SEC_CB::btm_pair_state_descr(new_state))); } - btm_cb.pairing_state = new_state; + pairing_state = new_state; if (new_state == BTM_PAIR_STATE_IDLE) { - alarm_cancel(btm_cb.pairing_timer); + alarm_cancel(pairing_timer); - btm_cb.pairing_flags = 0; - btm_cb.pin_code_len = 0; + pairing_flags = 0; + pin_code_len = 0; /* Make sure the the lcb shows we are not bonding */ - l2cu_update_lcb_4_bonding(btm_cb.pairing_bda, false); + l2cu_update_lcb_4_bonding(pairing_bda, false); btm_restore_mode(); btm_sec_check_pending_reqs(); btm_inq_clear_ssp(); - btm_cb.pairing_bda = RawAddress::kAny; + pairing_bda = RawAddress::kAny; } else { /* If transitioning out of idle, mark the lcb as bonding */ if (old_state == BTM_PAIR_STATE_IDLE) - l2cu_update_lcb_4_bonding(btm_cb.pairing_bda, true); + l2cu_update_lcb_4_bonding(pairing_bda, true); - alarm_set_on_mloop(btm_cb.pairing_timer, BTM_SEC_TIMEOUT_VALUE * 1000, + alarm_set_on_mloop(btm_sec_cb.pairing_timer, BTM_SEC_TIMEOUT_VALUE * 1000, btm_sec_pairing_timeout, NULL); } } @@ -4827,7 +4648,7 @@ static void btm_sec_change_pairing_state(tBTM_PAIRING_STATE new_state) { * Description Return state description for tracing * ******************************************************************************/ -static const char* btm_pair_state_descr(tBTM_PAIRING_STATE state) { +const char* tBTM_SEC_CB::btm_pair_state_descr(tBTM_PAIRING_STATE state) { switch (state) { case BTM_PAIR_STATE_IDLE: return ("IDLE"); @@ -4872,15 +4693,15 @@ void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec, LOG_DEBUG("transport=%s, btm_status=%s", is_le_transport ? "le" : "classic", btm_status_text(btm_status).c_str()); - tBTM_SEC_CALLBACK* p_callback = p_dev_rec->p_callback; - p_dev_rec->p_callback = NULL; + tBTM_SEC_CALLBACK* p_callback = p_dev_rec->sec_rec.p_callback; + p_dev_rec->sec_rec.p_callback = NULL; if (p_callback != nullptr) { if (is_le_transport) { (*p_callback)(&p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE, - p_dev_rec->p_ref_data, btm_status); + p_dev_rec->sec_rec.p_ref_data, btm_status); } else { (*p_callback)(&p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, - p_dev_rec->p_ref_data, btm_status); + p_dev_rec->sec_rec.p_ref_data, btm_status); } } @@ -4892,8 +4713,8 @@ void btm_sec_cr_loc_oob_data_cback_event(const RawAddress& address, tBTM_LE_EVT_DATA evt_data = { .local_oob_data = loc_oob_data, }; - if (btm_cb.api.p_le_callback) { - (*btm_cb.api.p_le_callback)(BTM_LE_SC_LOC_OOB_EVT, address, &evt_data); + if (btm_sec_cb.api.p_le_callback) { + (*btm_sec_cb.api.p_le_callback)(BTM_LE_SC_LOC_OOB_EVT, address, &evt_data); } } @@ -4920,10 +4741,10 @@ static bool btm_sec_queue_mx_request(const RawAddress& bd_addr, uint16_t psm, p_e->bd_addr = bd_addr; p_e->rfcomm_security_requirement = security_required; - BTM_TRACE_EVENT("%s() PSM: 0x%04x Is_Orig: %u security_required: 0x%x", - __func__, psm, is_orig, security_required); + LOG_VERBOSE("PSM: 0x%04x Is_Orig: %u security_required: 0x%x", psm, is_orig, + security_required); - fixed_queue_enqueue(btm_cb.sec_pending_q, p_e); + fixed_queue_enqueue(btm_sec_cb.sec_pending_q, p_e); return true; } @@ -4936,32 +4757,32 @@ static bool btm_sec_check_prefetch_pin(tBTM_SEC_DEV_REC* p_dev_rec) { if ((major == BTM_COD_MAJOR_AUDIO) && ((minor == BTM_COD_MINOR_CONFM_HANDSFREE) || (minor == BTM_COD_MINOR_CAR_AUDIO))) { - BTM_TRACE_EVENT( - "%s() Skipping pre-fetch PIN for carkit COD Major: 0x%02x Minor: " + LOG_VERBOSE( + "Skipping pre-fetch PIN for carkit COD Major: 0x%02x Minor: " "0x%02x", - __func__, major, minor); + major, minor); - if (!btm_cb.security_mode_changed) { - btm_cb.security_mode_changed = true; + if (!btm_sec_cb.security_mode_changed) { + btm_sec_cb.security_mode_changed = true; btsnd_hcic_write_auth_enable(true); } } else { - btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN); + btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN); /* If we got a PIN, use that, else try to get one */ - if (btm_cb.pin_code_len) { - BTM_PINCodeReply(p_dev_rec->bd_addr, BTM_SUCCESS, btm_cb.pin_code_len, - btm_cb.pin_code); + if (btm_sec_cb.pin_code_len) { + BTM_PINCodeReply(p_dev_rec->bd_addr, BTM_SUCCESS, btm_sec_cb.pin_code_len, + btm_sec_cb.pin_code); } else { /* pin was not supplied - pre-fetch pin code now */ - if (btm_cb.api.p_pin_callback && - ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0)) { - BTM_TRACE_DEBUG("%s() PIN code callback called", __func__); + if (btm_sec_cb.api.p_pin_callback && + ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0)) { + LOG_VERBOSE("PIN code callback called"); if (BTM_IsAclConnectionUp(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR)) - btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; - (btm_cb.api.p_pin_callback)( + btm_sec_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; + (btm_sec_cb.api.p_pin_callback)( p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, - (p_dev_rec->required_security_flags_for_pairing & + (p_dev_rec->sec_rec.required_security_flags_for_pairing & BTM_SEC_IN_MIN_16_DIGIT_PIN)); } } @@ -4994,7 +4815,7 @@ static void btm_sec_queue_encrypt_request(const RawAddress& bd_addr, p_e->transport = transport; p_e->sec_act = sec_act; p_e->bd_addr = bd_addr; - fixed_queue_enqueue(btm_cb.sec_pending_q, p_e); + fixed_queue_enqueue(btm_sec_cb.sec_pending_q, p_e); } /******************************************************************************* @@ -5010,10 +4831,10 @@ static void btm_sec_queue_encrypt_request(const RawAddress& bd_addr, static void btm_sec_check_pending_enc_req(tBTM_SEC_DEV_REC* p_dev_rec, tBT_TRANSPORT transport, uint8_t encr_enable) { - if (fixed_queue_is_empty(btm_cb.sec_pending_q)) return; + if (fixed_queue_is_empty(btm_sec_cb.sec_pending_q)) return; const tBTM_STATUS res = encr_enable ? BTM_SUCCESS : BTM_ERR_PROCESSING; - list_t* list = fixed_queue_get_list(btm_cb.sec_pending_q); + list_t* list = fixed_queue_get_list(btm_sec_cb.sec_pending_q); for (const list_node_t* node = list_begin(list); node != list_end(list);) { tBTM_SEC_QUEUE_ENTRY* p_e = (tBTM_SEC_QUEUE_ENTRY*)list_node(node); node = list_next(node); @@ -5024,11 +4845,12 @@ static void btm_sec_check_pending_enc_req(tBTM_SEC_DEV_REC* p_dev_rec, p_e->sec_act == BTM_BLE_SEC_ENCRYPT || p_e->sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM || (p_e->sec_act == BTM_BLE_SEC_ENCRYPT_MITM && - p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED)) { + p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_AUTHENTICATED)) { if (p_e->p_callback) (*p_e->p_callback)(&p_dev_rec->bd_addr, transport, p_e->p_ref_data, res); - fixed_queue_try_remove_from_queue(btm_cb.sec_pending_q, (void*)p_e); + fixed_queue_try_remove_from_queue(btm_sec_cb.sec_pending_q, (void*)p_e); + osi_free(p_e); } } } @@ -5065,9 +4887,8 @@ static uint16_t btm_sec_set_serv_level4_flags(uint16_t cur_security, * ******************************************************************************/ void btm_sec_clear_ble_keys(tBTM_SEC_DEV_REC* p_dev_rec) { - BTM_TRACE_DEBUG("%s() Clearing BLE Keys", __func__); - p_dev_rec->ble.key_type = BTM_LE_KEY_NONE; - memset(&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS)); + LOG_VERBOSE("Clearing BLE Keys"); + memset(&p_dev_rec->sec_rec.ble_keys, 0, sizeof(tBTM_SEC_BLE_KEYS)); btm_ble_resolving_list_remove_dev(p_dev_rec); } @@ -5077,22 +4898,13 @@ void btm_sec_clear_ble_keys(tBTM_SEC_DEV_REC* p_dev_rec) { * Function btm_sec_is_a_bonded_dev * * Description Is the specified device is a bonded device + * (either on BR/EDR or LE) * * Returns true - dev is bonded * ******************************************************************************/ bool btm_sec_is_a_bonded_dev(const RawAddress& bda) { - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda); - bool is_bonded = false; - - if (p_dev_rec && ((p_dev_rec->ble.key_type && - (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN)) || - (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))) { - is_bonded = true; - } - LOG_DEBUG("Device record bonded check peer:%s is_bonded:%s", - ADDRESS_TO_LOGGABLE_CSTR(bda), logbool(is_bonded).c_str()); - return is_bonded; + return btm_sec_cb.IsDeviceBonded(bda); } /******************************************************************************* @@ -5113,11 +4925,10 @@ static bool btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC* p_dev_rec) { uint32_t ext_feat; uint8_t chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE]; - BTM_TRACE_DEBUG("%s() link_key_type = 0x%x", __func__, - p_dev_rec->link_key_type); + LOG_VERBOSE("link_key_type = 0x%x", p_dev_rec->sec_rec.link_key_type); - if ((p_dev_rec->link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256) && - (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + if ((p_dev_rec->sec_rec.link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256) && + (p_dev_rec->sec_rec.link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) return false; if (!L2CA_GetPeerFeatures(p_dev_rec->bd_addr, &ext_feat, chnl_mask)) @@ -5150,7 +4961,7 @@ void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported, uint8_t req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND); - if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || + if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator) { tBTM_STATUS btm_status = btm_sec_execute_procedure(p_dev_rec); if (btm_status != BTM_CMD_STARTED) { @@ -5161,8 +4972,8 @@ void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported, } /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */ - if ((btm_cb.security_mode == BTM_SEC_MODE_SP || - btm_cb.security_mode == BTM_SEC_MODE_SC) && + if ((btm_sec_cb.security_mode == BTM_SEC_MODE_SP || + btm_sec_cb.security_mode == BTM_SEC_MODE_SC) && ssp_supported) { p_dev_rec->sm4 = BTM_SM4_TRUE; p_dev_rec->remote_supports_secure_connections = sc_supported; diff --git a/system/stack/btm/btm_sec.h b/system/stack/btm/btm_sec.h index 2647f0764d5ee46f459a28d1369ac7e8c6d41709..05938e2ee2e63dfc8cccd83a95b1c33ae9a5d2db 100644 --- a/system/stack/btm/btm_sec.h +++ b/system/stack/btm/btm_sec.h @@ -24,24 +24,23 @@ #pragma once #include +#include #include "stack/btm/security_device_record.h" #include "stack/include/bt_device_type.h" -#include "stack/include/btm_api_types.h" +#include "stack/include/bt_octets.h" +#include "stack/include/btm_sec_api_types.h" +#include "stack/include/btm_status.h" #include "stack/include/hci_error_code.h" #include "stack/include/security_client_callbacks.h" +#include "stack/include/smp_api_types.h" +#include "types/ble_address_with_type.h" +#include "types/bt_transport.h" #include "types/hci_role.h" #include "types/raw_address.h" #define BTM_SEC_MAX_COLLISION_DELAY (5000) -/******************************************************************************* - * L O C A L F U N C T I O N P R O T O T Y P E S * - ******************************************************************************/ -tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm); - -tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state); - /******************************************************************************* * * Function BTM_SecRegister @@ -80,19 +79,6 @@ bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback); ******************************************************************************/ bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback); -/******************************************************************************* - * - * Function BTM_GetSecurityFlagsByTransport - * - * Description Get security flags for the device on a particular transport - * - * Returns bool true or false is device found - * - ******************************************************************************/ -bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr, - uint8_t* p_sec_flags, - tBT_TRANSPORT transport); - bool BTM_IsEncrypted(const RawAddress& bd_addr, tBT_TRANSPORT transport); bool BTM_IsLinkKeyAuthed(const RawAddress& bd_addr, tBT_TRANSPORT transport); bool BTM_IsLinkKeyKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport); @@ -204,8 +190,7 @@ void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, ******************************************************************************/ tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, uint8_t pin_len, - uint8_t* p_pin); + tBT_TRANSPORT transport); /******************************************************************************* * @@ -217,14 +202,11 @@ tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, * * Parameters: bd_addr - Address of the device to bond * transport - doing SSP over BR/EDR or SMP over LE - * pin_len - length in bytes of the PIN Code - * p_pin - pointer to array with the PIN Code * * Note: After 2.1 parameters are not used and preserved here not to change API ******************************************************************************/ tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type, - uint8_t pin_len, uint8_t* p_pin); + tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type); /******************************************************************************* * @@ -279,6 +261,7 @@ tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr); * BTM_PENDING - command will be returned in the callback * BTM_WRONG_MODE- connection not up. * BTM_BUSY - security procedures are currently active + * BTM_ERR_KEY_MISSING - link key is missing. * BTM_MODE_UNSUPPORTED - if security manager not linked in. * ******************************************************************************/ @@ -376,6 +359,16 @@ bool BTM_BothEndsSupportSecureConnections(const RawAddress& bd_addr); ******************************************************************************/ bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr); +/******************************************************************************* + * + * Function BTM_GetInitialSecurityMode + * + * Description This function is called to retrieve the configured + * security mode. + * + ******************************************************************************/ +uint8_t BTM_GetSecurityMode(); + /******************************************************************************* * * Function btm_sec_l2cap_access_req @@ -442,7 +435,7 @@ tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, * Returns void * ******************************************************************************/ -void btm_sec_conn_req(const RawAddress& bda, uint8_t* dc); +void btm_sec_conn_req(const RawAddress& bda, const DEV_CLASS dc); /******************************************************************************* * @@ -455,7 +448,8 @@ void btm_sec_conn_req(const RawAddress& bda, uint8_t* dc); * Returns void * ******************************************************************************/ -void btm_create_conn_cancel_complete(const uint8_t* p, uint16_t evt_len); +void btm_create_conn_cancel_complete(uint8_t status, const RawAddress bd_addr, + uint32_t value); /******************************************************************************* * @@ -482,8 +476,6 @@ void btm_sec_dev_reset(void); ******************************************************************************/ void btm_sec_abort_access_req(const RawAddress& bd_addr); -bool is_state_getting_name(void* data, void* context); - /******************************************************************************* * * Function btm_sec_rmt_name_request_complete @@ -508,7 +500,8 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, * Returns void * ******************************************************************************/ -void btm_sec_rmt_host_support_feat_evt(const uint8_t* p); +void btm_sec_rmt_host_support_feat_evt(const RawAddress bd_addr, + uint8_t features_0); /******************************************************************************* * @@ -521,7 +514,7 @@ void btm_sec_rmt_host_support_feat_evt(const uint8_t* p); * Returns void * ******************************************************************************/ -void btm_io_capabilities_req(const RawAddress& p); +void btm_io_capabilities_req(RawAddress p); /******************************************************************************* * @@ -533,7 +526,7 @@ void btm_io_capabilities_req(const RawAddress& p); * Returns void * ******************************************************************************/ -void btm_io_capabilities_rsp(const uint8_t* p); +void btm_io_capabilities_rsp(const tBTM_SP_IO_RSP evt_data); /******************************************************************************* * @@ -547,7 +540,8 @@ void btm_io_capabilities_rsp(const uint8_t* p); * Returns void * ******************************************************************************/ -void btm_proc_sp_req_evt(tBTM_SP_EVT event, uint8_t* p); +void btm_proc_sp_req_evt(tBTM_SP_EVT event, const RawAddress bda, + uint32_t value); /******************************************************************************* * @@ -559,7 +553,7 @@ void btm_proc_sp_req_evt(tBTM_SP_EVT event, uint8_t* p); * Returns void * ******************************************************************************/ -void btm_simple_pair_complete(const uint8_t* p); +void btm_simple_pair_complete(const RawAddress bd_addr, uint8_t status); /******************************************************************************* * @@ -571,7 +565,7 @@ void btm_simple_pair_complete(const uint8_t* p); * Returns void * ******************************************************************************/ -void btm_rem_oob_req(const uint8_t* p); +void btm_rem_oob_req(const RawAddress bd_addr); /******************************************************************************* * @@ -583,7 +577,7 @@ void btm_rem_oob_req(const uint8_t* p); * Returns void * ******************************************************************************/ -void btm_read_local_oob_complete(uint8_t* p, uint16_t evt_len); +void btm_read_local_oob_complete(const tBTM_SP_LOC_OOB evt_data); /******************************************************************************* * @@ -666,6 +660,10 @@ void btm_sec_role_changed(tHCI_STATUS hci_status, const RawAddress& bd_addr, void btm_sec_link_key_notification(const RawAddress& p_bda, const Octet16& link_key, uint8_t key_type); +/** This function is called for each encryption key refresh complete event */ +void btm_sec_encryption_key_refresh_complete(uint16_t handle, + tHCI_STATUS status); + /******************************************************************************* * * Function btm_sec_link_key_request @@ -675,7 +673,7 @@ void btm_sec_link_key_notification(const RawAddress& p_bda, * Returns Pointer to the record or NULL * ******************************************************************************/ -void btm_sec_link_key_request(const uint8_t* p_event); +void btm_sec_link_key_request(const RawAddress bda); /******************************************************************************* * @@ -686,7 +684,7 @@ void btm_sec_link_key_request(const uint8_t* p_event); * Returns Pointer to the record or NULL * ******************************************************************************/ -void btm_sec_pin_code_request(const uint8_t* p_event); +void btm_sec_pin_code_request(const RawAddress bda); /******************************************************************************* * @@ -699,32 +697,6 @@ void btm_sec_pin_code_request(const uint8_t* p_event); ******************************************************************************/ void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset); -/******************************************************************************* - * - * Function btm_sec_find_first_serv - * - * Description Look for the first record in the service database - * with specified PSM - * - * Returns Pointer to the record or NULL - * - ******************************************************************************/ -tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm); - -bool is_sec_state_equal(void* data, void* context); - -/******************************************************************************* - * - * Function btm_sec_find_dev_by_sec_state - * - * Description Look for the record in the device database for the device - * which is being authenticated or encrypted - * - * Returns Pointer to the record or NULL - * - ******************************************************************************/ -tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state); - /******************************************************************************* * * Function btm_sec_dev_rec_cback_event diff --git a/system/stack/btm/btm_sec_cb.cc b/system/stack/btm/btm_sec_cb.cc new file mode 100644 index 0000000000000000000000000000000000000000..7fee5aa6e90fb4d80b2bff0851349e5db74ca5b6 --- /dev/null +++ b/system/stack/btm/btm_sec_cb.cc @@ -0,0 +1,357 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#define LOG_TAG "SEC_CB" + +#include "stack/btm/btm_sec_cb.h" + +#include + +#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" +#include "stack/btm/btm_dev.h" +#include "stack/btm/security_device_record.h" +#include "stack/include/bt_psm_types.h" +#include "types/raw_address.h" + +void tBTM_SEC_CB::Init(uint8_t initial_security_mode) { + memset(&cfg, 0, sizeof(cfg)); + memset(&devcb, 0, sizeof(devcb)); + memset(&enc_rand, 0, sizeof(enc_rand)); + memset(&api, 0, sizeof(api)); + memset(&pin_code, 0, sizeof(pin_code)); + memset(sec_serv_rec, 0, sizeof(sec_serv_rec)); + connecting_bda = RawAddress::kEmpty; + memset(&connecting_dc, 0, sizeof(connecting_dc)); + + sec_pending_q = fixed_queue_new(SIZE_MAX); + sec_collision_timer = alarm_new("btm.sec_collision_timer"); + pairing_timer = alarm_new("btm.pairing_timer"); + execution_wait_timer = alarm_new("btm.execution_wait_timer"); + + security_mode = initial_security_mode; + pairing_bda = RawAddress::kAny; + sec_dev_rec = list_new([](void* ptr) { + // Invoke destructor for all record objects and reset to default + // initialized value so memory may be properly freed + *((tBTM_SEC_DEV_REC*)ptr) = {}; + osi_free(ptr); + }); +} + +void tBTM_SEC_CB::Free() { + fixed_queue_free(sec_pending_q, nullptr); + sec_pending_q = nullptr; + + list_free(sec_dev_rec); + sec_dev_rec = nullptr; + + alarm_free(sec_collision_timer); + sec_collision_timer = nullptr; + + alarm_free(pairing_timer); + pairing_timer = nullptr; + + alarm_free(execution_wait_timer); + execution_wait_timer = nullptr; +} + +tBTM_SEC_CB btm_sec_cb; + +void BTM_Sec_Init() { + btm_sec_cb.Init(stack_config_get_interface()->get_pts_secure_only_mode() + ? BTM_SEC_MODE_SC + : BTM_SEC_MODE_SP); +} + +void BTM_Sec_Free() { btm_sec_cb.Free(); } + +/******************************************************************************* + * + * Function find_first_serv_rec + * + * Description Look for the first record in the service database + * with specified PSM + * + * Returns Pointer to the record or NULL + * + ******************************************************************************/ +tBTM_SEC_SERV_REC* tBTM_SEC_CB::find_first_serv_rec(bool is_originator, + uint16_t psm) { + tBTM_SEC_SERV_REC* p_serv_rec = &sec_serv_rec[0]; + int i; + + if (is_originator && p_out_serv && p_out_serv->psm == psm) { + /* If this is outgoing connection and the PSM matches p_out_serv, + * use it as the current service */ + return p_out_serv; + } + + /* otherwise, just find the first record with the specified PSM */ + for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) { + if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) && + (p_serv_rec->psm == psm)) + return (p_serv_rec); + } + return (NULL); +} + +tBTM_SEC_REC* tBTM_SEC_CB::getSecRec(const RawAddress bd_addr) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + if (p_dev_rec) { + return &p_dev_rec->sec_rec; + } + return nullptr; +} + +bool tBTM_SEC_CB::IsDeviceEncrypted(const RawAddress bd_addr, + tBT_TRANSPORT transport) { + tBTM_SEC_REC* sec_rec = getSecRec(bd_addr); + if (sec_rec) { + if (transport == BT_TRANSPORT_BR_EDR) { + return sec_rec->is_device_encrypted(); + } else if (transport == BT_TRANSPORT_LE) { + return sec_rec->is_le_device_encrypted(); + } + LOG_ERROR("unknown transport:%s", bt_transport_text(transport).c_str()); + return false; + } + + LOG_ERROR("unknown device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return false; +} + +bool tBTM_SEC_CB::IsLinkKeyAuthenticated(const RawAddress bd_addr, + tBT_TRANSPORT transport) { + tBTM_SEC_REC* sec_rec = getSecRec(bd_addr); + if (sec_rec) { + if (transport == BT_TRANSPORT_BR_EDR) { + return sec_rec->is_link_key_authenticated(); + } else if (transport == BT_TRANSPORT_LE) { + return sec_rec->is_le_link_key_authenticated(); + } + LOG_ERROR("unknown transport:%s", bt_transport_text(transport).c_str()); + return false; + } + + LOG_ERROR("unknown device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return false; +} + +bool tBTM_SEC_CB::IsDeviceAuthenticated(const RawAddress bd_addr, + tBT_TRANSPORT transport) { + tBTM_SEC_REC* sec_rec = getSecRec(bd_addr); + if (sec_rec) { + if (transport == BT_TRANSPORT_BR_EDR) { + return sec_rec->is_device_authenticated(); + } else if (transport == BT_TRANSPORT_LE) { + return sec_rec->is_le_device_authenticated(); + } + LOG_ERROR("unknown transport:%s", bt_transport_text(transport).c_str()); + return false; + } + + LOG_ERROR("unknown device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return false; +} + +bool tBTM_SEC_CB::IsLinkKeyKnown(const RawAddress bd_addr, + tBT_TRANSPORT transport) { + tBTM_SEC_REC* sec_rec = getSecRec(bd_addr); + if (sec_rec) { + if (transport == BT_TRANSPORT_BR_EDR) { + return sec_rec->is_link_key_known(); + } else if (transport == BT_TRANSPORT_LE) { + return sec_rec->is_le_link_key_known(); + } + LOG_ERROR("unknown transport:%s", bt_transport_text(transport).c_str()); + return false; + } + + LOG_ERROR("unknown device:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + return false; +} + +bool tBTM_SEC_CB::IsDeviceBonded(const RawAddress bd_addr) { + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); + bool is_bonded = false; + + if (p_dev_rec && ((p_dev_rec->sec_rec.ble_keys.key_type && + p_dev_rec->sec_rec.is_le_link_key_known()) || + p_dev_rec->sec_rec.is_link_key_known())) { + is_bonded = true; + } + LOG_DEBUG("Device record bonded check peer:%s is_bonded:%s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), logbool(is_bonded).c_str()); + return is_bonded; +} + +#define BTM_NO_AVAIL_SEC_SERVICES ((uint16_t)0xffff) +bool tBTM_SEC_CB::AddService(bool is_originator, const char* p_name, + uint8_t service_id, uint16_t sec_level, + uint16_t psm, uint32_t mx_proto_id, + uint32_t mx_chan_id) { + tBTM_SEC_SERV_REC* p_srec; + uint16_t index; + uint16_t first_unused_record = BTM_NO_AVAIL_SEC_SERVICES; + bool record_allocated = false; + + LOG_VERBOSE("sec_level:0x%x", sec_level); + + /* See if the record can be reused (same service name, psm, mx_proto_id, + service_id, and mx_chan_id), or obtain the next unused record */ + + p_srec = &sec_serv_rec[0]; + + for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++) { + /* Check if there is already a record for this service */ + if (p_srec->security_flags & BTM_SEC_IN_USE) { + if (p_srec->psm == psm && p_srec->mx_proto_id == mx_proto_id && + service_id == p_srec->service_id && p_name && + (!strncmp(p_name, (char*)p_srec->orig_service_name, + /* strlcpy replaces end char with termination char*/ + BT_MAX_SERVICE_NAME_LEN - 1) || + !strncmp(p_name, (char*)p_srec->term_service_name, + /* strlcpy replaces end char with termination char*/ + BT_MAX_SERVICE_NAME_LEN - 1))) { + record_allocated = true; + break; + } + } + /* Mark the first available service record */ + else if (!record_allocated) { + *p_srec = {}; + record_allocated = true; + first_unused_record = index; + } + } + + if (!record_allocated) { + LOG_WARN("Out of Service Records (%d)", BTM_SEC_MAX_SERVICE_RECORDS); + return (record_allocated); + } + + /* Process the request if service record is valid */ + /* If a duplicate service wasn't found, use the first available */ + if (index >= BTM_SEC_MAX_SERVICE_RECORDS) { + index = first_unused_record; + p_srec = &sec_serv_rec[index]; + } + + p_srec->psm = psm; + p_srec->service_id = service_id; + p_srec->mx_proto_id = mx_proto_id; + + if (is_originator) { + p_srec->orig_mx_chan_id = mx_chan_id; + strlcpy((char*)p_srec->orig_service_name, p_name, + BT_MAX_SERVICE_NAME_LEN + 1); + /* clear out the old setting, just in case it exists */ + { + p_srec->security_flags &= + ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM); + } + + /* Parameter validation. Originator should not set requirements for + * incoming connections */ + sec_level &= ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | + BTM_SEC_IN_MITM | BTM_SEC_IN_MIN_16_DIGIT_PIN); + + if (security_mode == BTM_SEC_MODE_SP || security_mode == BTM_SEC_MODE_SC) { + if (sec_level & BTM_SEC_OUT_AUTHENTICATE) sec_level |= BTM_SEC_OUT_MITM; + } + + /* Make sure the authenticate bit is set, when encrypt bit is set */ + if (sec_level & BTM_SEC_OUT_ENCRYPT) sec_level |= BTM_SEC_OUT_AUTHENTICATE; + + /* outgoing connections usually set the security level right before + * the connection is initiated. + * set it to be the outgoing service */ + p_out_serv = p_srec; + } else { + p_srec->term_mx_chan_id = mx_chan_id; + strlcpy((char*)p_srec->term_service_name, p_name, + BT_MAX_SERVICE_NAME_LEN + 1); + /* clear out the old setting, just in case it exists */ + { + p_srec->security_flags &= + ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM | + BTM_SEC_IN_MIN_16_DIGIT_PIN); + } + + /* Parameter validation. Acceptor should not set requirements for outgoing + * connections */ + sec_level &= + ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM); + + if (security_mode == BTM_SEC_MODE_SP || security_mode == BTM_SEC_MODE_SC) { + if (sec_level & BTM_SEC_IN_AUTHENTICATE) sec_level |= BTM_SEC_IN_MITM; + } + + /* Make sure the authenticate bit is set, when encrypt bit is set */ + if (sec_level & BTM_SEC_IN_ENCRYPT) sec_level |= BTM_SEC_IN_AUTHENTICATE; + } + + p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE); + + LOG_DEBUG( + "[%d]: id:%d, is_orig:%s psm:0x%04x proto_id:%d chan_id:%d" + " : sec:0x%x service_name:[%s] (up to %d chars saved)", + index, service_id, logbool(is_originator).c_str(), psm, mx_proto_id, + mx_chan_id, p_srec->security_flags, p_name, BT_MAX_SERVICE_NAME_LEN); + + return (record_allocated); +} + +uint8_t tBTM_SEC_CB::RemoveServiceById(uint8_t service_id) { + tBTM_SEC_SERV_REC* p_srec = &sec_serv_rec[0]; + uint8_t num_freed = 0; + int i; + + for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) { + /* Delete services with specified name (if in use and not SDP) */ + if ((p_srec->security_flags & BTM_SEC_IN_USE) && + (p_srec->psm != BT_PSM_SDP) && + (!service_id || (service_id == p_srec->service_id))) { + LOG_VERBOSE("BTM_SEC_CLR[%d]: id:%d", i, service_id); + p_srec->security_flags = 0; + num_freed++; + } + } + return (num_freed); +} + +uint8_t tBTM_SEC_CB::RemoveServiceByPsm(uint16_t psm) { + tBTM_SEC_SERV_REC* p_srec = &sec_serv_rec[0]; + uint8_t num_freed = 0; + int i; + + for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) { + /* Delete services with specified name (if in use and not SDP) */ + if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm)) { + LOG_VERBOSE("BTM_SEC_CLR[%d]: id %d ", i, p_srec->service_id); + p_srec->security_flags = 0; + num_freed++; + } + } + LOG_VERBOSE("psm:0x%x num_freed:%d", psm, num_freed); + + return (num_freed); +} diff --git a/system/stack/btm/btm_sec_cb.h b/system/stack/btm/btm_sec_cb.h new file mode 100644 index 0000000000000000000000000000000000000000..0a827c1dc2d7f08fcba1514f0f43e5349adb189f --- /dev/null +++ b/system/stack/btm/btm_sec_cb.h @@ -0,0 +1,113 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include + +#include "internal_include/bt_target.h" +#include "osi/include/alarm.h" +#include "osi/include/fixed_queue.h" +#include "osi/include/list.h" +#include "stack/btm/btm_sec_int_types.h" +#include "stack/btm/security_device_record.h" +#include "stack/include/bt_octets.h" +#include "stack/include/security_client_callbacks.h" +#include "types/raw_address.h" + +class tBTM_SEC_CB { + public: + tBTM_CFG cfg; /* Device configuration */ + + /***************************************************** + ** Local Device control block (on security) + *****************************************************/ + tBTM_SEC_DEVCB devcb; + + uint16_t enc_handle{0}; + BT_OCTET8 enc_rand; /* received rand value from LTK request*/ + uint16_t ediv{0}; /* received ediv value from LTK request */ + uint8_t key_size{0}; + + public: + /***************************************************** + ** Security Management + *****************************************************/ + tBTM_APPL_INFO api; + + tBTM_SEC_DEV_REC* p_collided_dev_rec{nullptr}; + alarm_t* sec_collision_timer{nullptr}; + uint64_t collision_start_time{0}; + uint32_t dev_rec_count{0}; /* Counter used for device record timestamp */ + uint8_t security_mode{0}; + bool pairing_disabled{false}; + bool security_mode_changed{false}; /* mode changed during bonding */ + bool pin_type_changed{false}; /* pin type changed during bonding */ + bool sec_req_pending{false}; /* true if a request is pending */ + + uint8_t pin_code_len{0}; /* for legacy devices */ + PIN_CODE pin_code; /* for legacy devices */ + tBTM_PAIRING_STATE pairing_state{ + BTM_PAIR_STATE_IDLE}; /* The current pairing state */ + uint8_t pairing_flags{0}; /* The current pairing flags */ + RawAddress pairing_bda; /* The device currently pairing */ + alarm_t* pairing_timer{nullptr}; /* Timer for pairing process */ + alarm_t* execution_wait_timer{nullptr}; /* To avoid concurrent auth request */ + list_t* sec_dev_rec{nullptr}; /* list of tBTM_SEC_DEV_REC */ + tBTM_SEC_SERV_REC* p_out_serv{nullptr}; + tBTM_MKEY_CALLBACK* mkey_cback{nullptr}; + + RawAddress connecting_bda; + + fixed_queue_t* sec_pending_q{nullptr}; /* pending sequrity requests in + tBTM_SEC_QUEUE_ENTRY format */ + + tBTM_SEC_SERV_REC sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS]; + + DEV_CLASS connecting_dc; + + void Init(uint8_t initial_security_mode); + void Free(); + + tBTM_SEC_SERV_REC* find_first_serv_rec(bool is_originator, uint16_t psm); + + bool IsDeviceBonded(const RawAddress bd_addr); + bool IsDeviceEncrypted(const RawAddress bd_addr, tBT_TRANSPORT transport); + bool IsDeviceAuthenticated(const RawAddress bd_addr, tBT_TRANSPORT transport); + bool IsLinkKeyAuthenticated(const RawAddress bd_addr, + tBT_TRANSPORT transport); + + bool IsLinkKeyKnown(const RawAddress bd_addr, tBT_TRANSPORT transport); + + tBTM_SEC_REC* getSecRec(const RawAddress bd_addr); + + bool AddService(bool is_originator, const char* p_name, uint8_t service_id, + uint16_t sec_level, uint16_t psm, uint32_t mx_proto_id, + uint32_t mx_chan_id); + uint8_t RemoveServiceById(uint8_t service_id); + uint8_t RemoveServiceByPsm(uint16_t psm); + + void change_pairing_state(tBTM_PAIRING_STATE new_state); + + // misc static methods + static const char* btm_pair_state_descr(tBTM_PAIRING_STATE state); +}; + +extern tBTM_SEC_CB btm_sec_cb; + +void BTM_Sec_Init(); +void BTM_Sec_Free(); diff --git a/system/stack/btm/btm_sec_int_types.h b/system/stack/btm/btm_sec_int_types.h new file mode 100644 index 0000000000000000000000000000000000000000..4f8d84d9cb936b6111e2a3de25fd22339bb905e3 --- /dev/null +++ b/system/stack/btm/btm_sec_int_types.h @@ -0,0 +1,107 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include + +#include "stack/include/bt_octets.h" +#include "stack/include/btm_api_types.h" // tBTM_CMPL_CB +#include "stack/include/btm_ble_sec_api_types.h" +#include "stack/include/btm_sec_api_types.h" +#include "types/raw_address.h" + +/* + * Local device configuration + */ +typedef struct { + tBTM_LOC_BD_NAME bd_name; /* local Bluetooth device name */ + bool pin_type; /* true if PIN type is fixed */ + uint8_t pin_code_len; /* Bonding information */ + PIN_CODE pin_code; /* PIN CODE if pin type is fixed */ +} tBTM_CFG; + +/* Pairing State */ +enum tBTM_PAIRING_STATE : uint8_t { + BTM_PAIR_STATE_IDLE, /* Idle */ + BTM_PAIR_STATE_GET_REM_NAME, /* Getting the remote name (to check for SM4) */ + BTM_PAIR_STATE_WAIT_PIN_REQ, /* Started authentication, waiting for PIN req + (PIN is pre-fetched) */ + BTM_PAIR_STATE_WAIT_LOCAL_PIN, /* Waiting for local PIN code */ + BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM, /* Waiting user 'yes' to numeric + confirmation */ + BTM_PAIR_STATE_KEY_ENTRY, /* Key entry state (we are a keyboard) */ + BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP, /* Waiting for local response to peer OOB + data */ + BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS, /* Waiting for local IO capabilities and OOB + data */ + BTM_PAIR_STATE_INCOMING_SSP, /* Incoming SSP (got peer IO caps when idle) */ + BTM_PAIR_STATE_WAIT_AUTH_COMPLETE, /* All done, waiting authentication + complete */ + BTM_PAIR_STATE_WAIT_DISCONNECT /* Waiting to disconnect the ACL */ +}; + +#define BTM_PAIR_FLAGS_WE_STARTED_DD \ + 0x01 /* We want to do dedicated bonding */ +#define BTM_PAIR_FLAGS_PEER_STARTED_DD \ + 0x02 /* Peer initiated dedicated bonding */ +#define BTM_PAIR_FLAGS_DISC_WHEN_DONE 0x04 /* Disconnect when done */ +#define BTM_PAIR_FLAGS_PIN_REQD \ + 0x08 /* set this bit when pin_callback is called */ +#define BTM_PAIR_FLAGS_PRE_FETCH_PIN \ + 0x10 /* set this bit when pre-fetch pin */ +#define BTM_PAIR_FLAGS_REJECTED_CONNECT \ + 0x20 /* set this bit when rejected incoming connection */ +#define BTM_PAIR_FLAGS_WE_CANCEL_DD \ + 0x40 /* set this bit when cancelling a bonding procedure */ +#define BTM_PAIR_FLAGS_LE_ACTIVE \ + 0x80 /* use this bit when SMP pairing is active */ + +typedef struct { + bool is_mux; + RawAddress bd_addr; + uint16_t psm; + bool is_orig; + tBTM_SEC_CALLBACK* p_callback; + tSMP_SIRK_CALLBACK* p_sirk_callback; + void* p_ref_data; + uint16_t rfcomm_security_requirement; + tBT_TRANSPORT transport; + tBTM_BLE_SEC_ACT sec_act; +} tBTM_SEC_QUEUE_ENTRY; + +/* Define the Device Management control structure + */ +typedef struct tBTM_SEC_DEVCB { + tBTM_CMPL_CB* + p_stored_link_key_cmpl_cb; /* Read/Write/Delete stored link key */ + + tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */ + Octet16 ble_encryption_key_value; /* BLE encryption key */ + + tBTM_IO_CAP loc_io_caps; /* IO capability of the local device */ + tBTM_AUTH_REQ loc_auth_req; /* the auth_req flag */ +} tBTM_SEC_DEVCB; + +/* security action for L2CAP COC channels */ +#define BTM_SEC_OK 1 +#define BTM_SEC_ENCRYPT 2 /* encrypt the link with current key */ +#define BTM_SEC_ENCRYPT_NO_MITM 3 /* unauthenticated encryption or better */ +#define BTM_SEC_ENCRYPT_MITM 4 /* authenticated encryption */ +#define BTM_SEC_ENC_PENDING 5 /* wait for link encryption pending */ + +typedef uint8_t tBTM_SEC_ACTION; diff --git a/system/stack/btm/btm_security_client_interface.cc b/system/stack/btm/btm_security_client_interface.cc new file mode 100644 index 0000000000000000000000000000000000000000..f3b9f5a72b04457c9ff841ef5a1ca80e4147c74b --- /dev/null +++ b/system/stack/btm/btm_security_client_interface.cc @@ -0,0 +1,54 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "stack/btm/btm_dev.h" +#include "stack/btm/btm_sec.h" +#include "stack/btm/btm_sec_cb.h" +#include "stack/include/btm_ble_sec_api.h" +#include "stack/include/btm_sec_api.h" +#include "stack/include/security_client_callbacks.h" + +static SecurityClientInterface security = { + .BTM_Sec_Init = BTM_Sec_Init, + .BTM_Sec_Free = BTM_Sec_Free, + .BTM_SecAddDevice = BTM_SecAddDevice, + .BTM_SecAddRmtNameNotifyCallback = BTM_SecAddRmtNameNotifyCallback, + .BTM_SecDeleteDevice = BTM_SecDeleteDevice, + .BTM_SecRegister = BTM_SecRegister, + .BTM_SecReadDevName = BTM_SecReadDevName, + .BTM_SecBond = BTM_SecBond, + .BTM_SecBondCancel = BTM_SecBondCancel, + .BTM_SecAddBleKey = BTM_SecAddBleKey, + .BTM_SecAddBleDevice = BTM_SecAddBleDevice, + .BTM_SecClearSecurityFlags = BTM_SecClearSecurityFlags, + .BTM_SecClrService = BTM_SecClrService, + .BTM_SecClrServiceByPsm = BTM_SecClrServiceByPsm, + .BTM_RemoteOobDataReply = BTM_RemoteOobDataReply, + .BTM_PINCodeReply = BTM_PINCodeReply, + .BTM_ConfirmReqReply = BTM_ConfirmReqReply, + .BTM_SecDeleteRmtNameNotifyCallback = BTM_SecDeleteRmtNameNotifyCallback, + .BTM_SetEncryption = BTM_SetEncryption, + .BTM_IsEncrypted = BTM_IsEncrypted, + .BTM_SecIsSecurityPending = BTM_SecIsSecurityPending, + .BTM_IsLinkKeyKnown = BTM_IsLinkKeyKnown, + .BTM_BleSirkConfirmDeviceReply = BTM_BleSirkConfirmDeviceReply, + .BTM_GetSecurityMode = BTM_GetSecurityMode, +}; + +const SecurityClientInterface& get_security_client_interface() { + return security; +} diff --git a/system/stack/btm/hfp_lc3_decoder.cc b/system/stack/btm/hfp_lc3_decoder.cc new file mode 100644 index 0000000000000000000000000000000000000000..dd828596945d8571bb046ed4646af06b627ecffb --- /dev/null +++ b/system/stack/btm/hfp_lc3_decoder.cc @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hfp_lc3_decoder" + +#include "hfp_lc3_decoder.h" + +#include +#include + +#include + +#include "osi/include/allocator.h" +#include "osi/include/log.h" + +const int HFP_LC3_H2_HEADER_LEN = 2; +const int HFP_LC3_PKT_FRAME_LEN = 58; +const int HFP_LC3_PCM_BYTES = 480; + +static void* hfp_lc3_decoder_mem; +static lc3_decoder_t hfp_lc3_decoder; + +bool hfp_lc3_decoder_init() { + if (hfp_lc3_decoder_mem) { + LOG_WARN("%s: The decoder instance should have had been released.", + __func__); + osi_free(hfp_lc3_decoder_mem); + } + + const int dt_us = 7500; + const int sr_hz = 32000; + const int sr_pcm_hz = 32000; + const unsigned dec_size = lc3_decoder_size(dt_us, sr_pcm_hz); + + hfp_lc3_decoder_mem = osi_malloc(dec_size); + hfp_lc3_decoder = + lc3_setup_decoder(dt_us, sr_hz, sr_pcm_hz, hfp_lc3_decoder_mem); + + return true; +} + +void hfp_lc3_decoder_cleanup() { + if (hfp_lc3_decoder_mem) { + osi_free_and_reset((void**)&hfp_lc3_decoder_mem); + } +} + +bool hfp_lc3_decoder_decode_packet(const uint8_t* i_buf, int16_t* o_buf, + size_t out_len) { + if (o_buf == nullptr || out_len < HFP_LC3_PCM_BYTES) { + LOG_ERROR("%s: Output buffer size %zu is less than LC3 frame size %d", + __func__, out_len, HFP_LC3_PCM_BYTES); + return false; + } + + const uint8_t* frame = i_buf ? i_buf + HFP_LC3_H2_HEADER_LEN : nullptr; + + /* Note this only fails when wrong parameters are supplied. */ + int rc = lc3_decode(hfp_lc3_decoder, frame, HFP_LC3_PKT_FRAME_LEN, + LC3_PCM_FORMAT_S16, o_buf, 1); + + ASSERT(rc == 0 || rc == 1); + + return !rc; +} diff --git a/system/stack/btm/hfp_lc3_decoder_linux.cc b/system/stack/btm/hfp_lc3_decoder_linux.cc new file mode 100644 index 0000000000000000000000000000000000000000..52d3d4513fde399c5fc8c417178e7de467e7a32a --- /dev/null +++ b/system/stack/btm/hfp_lc3_decoder_linux.cc @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hfp_lc3_decoder" + +#include + +#include "hfp_lc3_decoder.h" +#include "mmc/codec_client/codec_client.h" +#include "mmc/proto/mmc_config.pb.h" +#include "osi/include/log.h" + +const int HFP_LC3_H2_HEADER_LEN = 2; +const int HFP_LC3_PKT_FRAME_LEN = 58; +const int HFP_LC3_PCM_BYTES = 480; + +static mmc::CodecClient* client = nullptr; +static const uint8_t plc_buf[HFP_LC3_H2_HEADER_LEN + HFP_LC3_PKT_FRAME_LEN] = { + 0}; + +bool hfp_lc3_decoder_init() { + hfp_lc3_decoder_cleanup(); + client = new mmc::CodecClient; + + const int dt_us = 7500; + const int sr_hz = 32000; + const int sr_pcm_hz = 32000; + + mmc::Lc3Param param; + param.set_dt_us(dt_us); + param.set_sr_hz(sr_hz); + param.set_sr_pcm_hz(sr_pcm_hz); + param.set_stride(1); + param.set_fmt(mmc::Lc3Param::kLc3PcmFormatS16); + + mmc::ConfigParam config; + *config.mutable_hfp_lc3_decoder_param() = param; + + int ret = client->init(config); + if (ret < 0) { + LOG_ERROR("%s: Init failed with error message, %s", __func__, + strerror(-ret)); + return false; + } + + return true; +} + +void hfp_lc3_decoder_cleanup() { + if (client) { + client->cleanup(); + delete client; + client = nullptr; + } +} + +bool hfp_lc3_decoder_decode_packet(const uint8_t* i_buf, int16_t* o_buf, + size_t out_len) { + if (o_buf == nullptr || out_len < HFP_LC3_PCM_BYTES) { + LOG_ERROR("%s: Output buffer size %zu is less than LC3 frame size %d", + __func__, out_len, HFP_LC3_PCM_BYTES); + return false; + } + + if (!client) { + LOG_ERROR("%s: CodecClient has not been initialized", __func__); + return false; + } + + // Pass zeros to MMC when i_buf is nullptr. + const uint8_t* frame = i_buf ? i_buf : plc_buf; + + // One extra byte in the beginning to indicate whether PLC was conducted. + uint8_t* o_packet = new uint8_t[out_len + 1]; + + int rc = client->transcode((uint8_t*)frame, + HFP_LC3_PKT_FRAME_LEN + HFP_LC3_H2_HEADER_LEN, + o_packet, out_len + 1); + + if (rc < 0) { + LOG_WARN("%s: Decode failed with error message, %s", __func__, + strerror(-rc)); + return false; + } + + bool plc_conducted = o_packet[0]; + + std::copy(o_packet + 1, o_packet + 1 + out_len, (uint8_t*)o_buf); + + delete[] o_packet; + return !plc_conducted; +} diff --git a/system/stack/btm/hfp_lc3_encoder.cc b/system/stack/btm/hfp_lc3_encoder.cc new file mode 100644 index 0000000000000000000000000000000000000000..f9685132829d71c1016f7355e3fcb10ec97ca992 --- /dev/null +++ b/system/stack/btm/hfp_lc3_encoder.cc @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hfp_lc3_encoder" + +#include "hfp_lc3_encoder.h" + +#include + +#include + +#include "osi/include/allocator.h" +#include "osi/include/log.h" + +const int HFP_LC3_PCM_BYTES = 480; +const int HFP_LC3_PKT_FRAME_LEN = 58; + +static void* hfp_lc3_encoder_mem; +static lc3_encoder_t hfp_lc3_encoder; + +void hfp_lc3_encoder_init() { + if (hfp_lc3_encoder_mem) { + LOG_WARN("%s: The encoder instance should have had been released.", + __func__); + osi_free(hfp_lc3_encoder_mem); + } + + const int dt_us = 7500; + const int sr_hz = 32000; + const int sr_pcm_hz = 32000; + const unsigned enc_size = lc3_encoder_size(dt_us, sr_pcm_hz); + + hfp_lc3_encoder_mem = osi_malloc(enc_size); + hfp_lc3_encoder = + lc3_setup_encoder(dt_us, sr_hz, sr_pcm_hz, hfp_lc3_encoder_mem); +} + +void hfp_lc3_encoder_cleanup() { + if (hfp_lc3_encoder_mem) { + osi_free_and_reset((void**)&hfp_lc3_encoder_mem); + } +} + +uint32_t hfp_lc3_encode_frames(int16_t* input, uint8_t* output) { + if (input == nullptr || output == nullptr) { + LOG_ERROR("%s: Buffer is null.", __func__); + return 0; + } + + /* Note this only fails when wrong parameters are supplied. */ + int rc = lc3_encode(hfp_lc3_encoder, LC3_PCM_FORMAT_S16, input, 1, + HFP_LC3_PKT_FRAME_LEN, output); + + ASSERT(rc == 0); + + return HFP_LC3_PCM_BYTES; +} diff --git a/system/stack/btm/hfp_lc3_encoder_linux.cc b/system/stack/btm/hfp_lc3_encoder_linux.cc new file mode 100644 index 0000000000000000000000000000000000000000..722501477640d532158f8c62adf2c9334d8f48bb --- /dev/null +++ b/system/stack/btm/hfp_lc3_encoder_linux.cc @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hfp_lc3_encoder" + +#include "hfp_lc3_encoder.h" +#include "mmc/codec_client/codec_client.h" +#include "mmc/proto/mmc_config.pb.h" +#include "osi/include/log.h" + +const int HFP_LC3_PCM_BYTES = 480; +const int HFP_LC3_PKT_FRAME_LEN = 58; + +static mmc::CodecClient* client = nullptr; + +void hfp_lc3_encoder_init() { + hfp_lc3_encoder_cleanup(); + client = new mmc::CodecClient; + + const int dt_us = 7500; + const int sr_hz = 32000; + const int sr_pcm_hz = 32000; + + mmc::Lc3Param param; + param.set_dt_us(dt_us); + param.set_sr_hz(sr_hz); + param.set_sr_pcm_hz(sr_pcm_hz); + param.set_stride(1); + param.set_fmt(mmc::Lc3Param::kLc3PcmFormatS16); + + mmc::ConfigParam config; + *config.mutable_hfp_lc3_encoder_param() = param; + + int ret = client->init(config); + if (ret < 0) { + LOG_ERROR("%s: Init failed with error message, %s", __func__, + strerror(-ret)); + } + return; +} + +void hfp_lc3_encoder_cleanup() { + if (client) { + client->cleanup(); + delete client; + client = nullptr; + } +} + +uint32_t hfp_lc3_encode_frames(int16_t* input, uint8_t* output) { + if (input == nullptr || output == nullptr) { + LOG_ERROR("%s: Buffer is null", __func__); + return 0; + } + + if (!client) { + LOG_ERROR("%s: CodecClient has not been initialized", __func__); + return 0; + } + + int rc = client->transcode((uint8_t*)input, HFP_LC3_PCM_BYTES, output, + HFP_LC3_PKT_FRAME_LEN); + + if (rc < 0) { + LOG_WARN("%s: Encode failed with error message, %s", __func__, + strerror(-rc)); + return 0; + } + + return HFP_LC3_PCM_BYTES; +} diff --git a/system/stack/btm/neighbor_inquiry.h b/system/stack/btm/neighbor_inquiry.h index 2ef6e828e78a02ffccced62725b1dee1b22d434e..a9400671bf15f32e5f085f819b432d4a388de8b9 100644 --- a/system/stack/btm/neighbor_inquiry.h +++ b/system/stack/btm/neighbor_inquiry.h @@ -18,9 +18,13 @@ #include +#include "internal_include/bt_target.h" +#include "macros.h" #include "osi/include/alarm.h" #include "stack/include/bt_device_type.h" +#include "stack/include/bt_name.h" #include "stack/include/btm_api_types.h" +#include "stack/include/btm_status.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" @@ -156,9 +160,7 @@ typedef struct { duplicate store of inquiry results */ uint16_t remote_name_len; tBTM_BD_NAME remote_name; - uint8_t remote_name_state; uint8_t remote_name_type; - } tBTM_INQ_INFO; typedef struct { @@ -196,12 +198,6 @@ typedef struct { long long start_time_ms; } tBTM_INQUIRY_CMPL; -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string btm_inquiry_cmpl_status_text( const tBTM_INQUIRY_CMPL::STATUS& status) { switch (status) { @@ -214,7 +210,6 @@ inline std::string btm_inquiry_cmpl_status_text( std::string("]"); } } -#undef CASE_RETURN_TEXT /* Structure returned with remote name request */ typedef struct { @@ -285,12 +280,6 @@ typedef struct { } tBTM_INQUIRY_VAR_ST; -typedef union /* contains the inquiry filter condition */ -{ - RawAddress bdaddr_cond; - tBTM_COD_COND cod_cond; -} tBTM_INQ_FILT_COND; - #define BTM_INQ_RESULT_BR 0x01 #define BTM_INQ_RESULT_BLE 0x02 diff --git a/system/stack/btm/power_mode.h b/system/stack/btm/power_mode.h new file mode 100644 index 0000000000000000000000000000000000000000..eb98945ab06dd8ec7801927cda34f92825bd78ee --- /dev/null +++ b/system/stack/btm/power_mode.h @@ -0,0 +1,201 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +#include "stack/include/btm_status.h" +#include "stack/include/hci_error_code.h" +#include "stack/include/hci_mode.h" +#include "types/raw_address.h" + +/* BTM Power manager status codes */ +enum : uint8_t { + BTM_PM_STS_ACTIVE = HCI_MODE_ACTIVE, // 0x00 + BTM_PM_STS_HOLD = HCI_MODE_HOLD, // 0x01 + BTM_PM_STS_SNIFF = HCI_MODE_SNIFF, // 0x02 + BTM_PM_STS_PARK = HCI_MODE_PARK, // 0x03 + BTM_PM_STS_SSR, /* report the SSR parameters in HCI_SNIFF_SUB_RATE_EVT */ + BTM_PM_STS_PENDING, /* when waiting for status from controller */ + BTM_PM_STS_ERROR /* when HCI command status returns error */ +}; +typedef uint8_t tBTM_PM_STATUS; + +inline std::string power_mode_status_text(tBTM_PM_STATUS status) { + switch (status) { + case BTM_PM_STS_ACTIVE: + return std::string("active"); + case BTM_PM_STS_HOLD: + return std::string("hold"); + case BTM_PM_STS_SNIFF: + return std::string("sniff"); + case BTM_PM_STS_PARK: + return std::string("park"); + case BTM_PM_STS_SSR: + return std::string("sniff_subrating"); + case BTM_PM_STS_PENDING: + return std::string("pending"); + case BTM_PM_STS_ERROR: + return std::string("error"); + default: + return std::string("UNKNOWN"); + } +} + +/* BTM Power manager modes */ +enum : uint8_t { + BTM_PM_MD_ACTIVE = HCI_MODE_ACTIVE, // 0x00 + BTM_PM_MD_HOLD = HCI_MODE_HOLD, // 0x01 + BTM_PM_MD_SNIFF = HCI_MODE_SNIFF, // 0x02 + BTM_PM_MD_PARK = HCI_MODE_PARK, // 0x03 + BTM_PM_MD_FORCE = 0x10, /* OR this to force ACL link to a certain mode */ + BTM_PM_MD_UNKNOWN = 0xEF, +}; + +typedef uint8_t tBTM_PM_MODE; +#define HCI_TO_BTM_POWER_MODE(mode) (static_cast(mode)) + +inline bool is_legal_power_mode(tBTM_PM_MODE mode) { + switch (mode & ~BTM_PM_MD_FORCE) { + case BTM_PM_MD_ACTIVE: + case BTM_PM_MD_HOLD: + case BTM_PM_MD_SNIFF: + case BTM_PM_MD_PARK: + return true; + default: + return false; + } +} + +inline std::string power_mode_text(tBTM_PM_MODE mode) { + std::string s = base::StringPrintf((mode & BTM_PM_MD_FORCE) ? "" : "forced:"); + switch (mode & ~BTM_PM_MD_FORCE) { + case BTM_PM_MD_ACTIVE: + return s + std::string("active"); + case BTM_PM_MD_HOLD: + return s + std::string("hold"); + case BTM_PM_MD_SNIFF: + return s + std::string("sniff"); + case BTM_PM_MD_PARK: + return s + std::string("park"); + default: + return s + std::string("UNKNOWN"); + } +} + +#define BTM_PM_SET_ONLY_ID 0x80 + +/* Operation codes */ +typedef enum : uint8_t { + /* The module wants to set the desired power mode */ + BTM_PM_REG_SET = (1u << 0), + /* The module does not want to involve with PM anymore */ + BTM_PM_DEREG = (1u << 2), +} tBTM_PM_REGISTER; + +typedef struct { + uint16_t max = 0; + uint16_t min = 0; + uint16_t attempt = 0; + uint16_t timeout = 0; + tBTM_PM_MODE mode = BTM_PM_MD_ACTIVE; // 0 +} tBTM_PM_PWR_MD; + +typedef void(tBTM_PM_STATUS_CBACK)(const RawAddress& p_bda, + tBTM_PM_STATUS status, uint16_t value, + tHCI_STATUS hci_status); + +#define BTM_CONTRL_UNKNOWN 0 +/* ACL link on, SCO link ongoing, sniff mode */ +#define BTM_CONTRL_ACTIVE 1 +/* Scan state - paging/inquiry/trying to connect*/ +#define BTM_CONTRL_SCAN 2 +/* Idle state - page scan, LE advt, inquiry scan */ +#define BTM_CONTRL_IDLE 3 + +typedef uint8_t tBTM_CONTRL_STATE; + +/******************************************************************************* + * + * Function BTM_PmRegister + * + * Description register or deregister with power manager + * + * Returns BTM_SUCCESS if successful, + * BTM_NO_RESOURCES if no room to hold registration + * BTM_ILLEGAL_VALUE + * + ******************************************************************************/ +tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id, + tBTM_PM_STATUS_CBACK* p_cb); + +// Notified by ACL that a new link is connected +void BTM_PM_OnConnected(uint16_t handle, const RawAddress& remote_bda); + +// Notified by ACL that a link is disconnected +void BTM_PM_OnDisconnected(uint16_t handle); + +/******************************************************************************* + * + * Function BTM_SetPowerMode + * + * Description store the mode in control block or + * alter ACL connection behavior. + * + * Returns BTM_SUCCESS if successful, + * BTM_UNKNOWN_ADDR if bd addr is not active or bad + * + ******************************************************************************/ +tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda, + const tBTM_PM_PWR_MD* p_mode); +bool BTM_SetLinkPolicyActiveMode(const RawAddress& remote_bda); + +/******************************************************************************* + * + * Function BTM_SetSsrParams + * + * Description This sends the given SSR parameters for the given ACL + * connection if it is in ACTIVE mode. + * + * Input Param remote_bda - device address of desired ACL connection + * max_lat - maximum latency (in 0.625ms)(0-0xFFFE) + * min_rmt_to - minimum remote timeout + * min_loc_to - minimum local timeout + * + * + * Returns BTM_SUCCESS if the HCI command is issued successful, + * BTM_UNKNOWN_ADDR if bd addr is not active or bad + * BTM_CMD_STORED if the command is stored + * + ******************************************************************************/ +tBTM_STATUS BTM_SetSsrParams(const RawAddress& remote_bda, uint16_t max_lat, + uint16_t min_rmt_to, uint16_t min_loc_to); + +/******************************************************************************* + * + * Function BTM_PM_ReadControllerState + * + * Description This function is called to obtain the controller state + * + * Returns Controller state (BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and + * BTM_CONTRL_IDLE) + * + ******************************************************************************/ +tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void); diff --git a/system/stack/btm/sco_pkt_status.h b/system/stack/btm/sco_pkt_status.h new file mode 100644 index 0000000000000000000000000000000000000000..233bacf5e6c35c42d5ff912fb1a48a3f6e52943c --- /dev/null +++ b/system/stack/btm/sco_pkt_status.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "common/time_util.h" + +#define BTM_PKT_STATUS_LEN 64 +#define BTM_PKT_STATUS_WBS_FRAME_US 7500 + +/* Object to log consecutive packets' status */ +typedef struct { + // Bytes to store packets' status. + uint8_t data[BTM_PKT_STATUS_LEN]; + // Total number of bits in |data|. + int size; + // Position of the next bit to log packet status. + int offset; + // Whether the ring buffer is full to be wrapped. + bool is_full; + // The timestamp of the first bit of |data|'s last update. + uint64_t ts; + + public: + void init() { + std::fill(std::begin(data), std::end(data), 0); + size = BTM_PKT_STATUS_LEN * 8; + offset = 0; + is_full = false; + ts = 0; + } + + void update(bool is_lost) { + if (is_lost) { + data[offset / 8] |= 1UL << (offset % 8); + } else { + data[offset / 8] &= ~(1UL << (offset % 8)); + } + if (offset == 0) { + ts = bluetooth::common::time_gettimeofday_us(); + } + offset++; + if (offset == size) { + offset = 0; + is_full = true; + } + } + + /* Rewinds logger's time stamp to calculate the beginning. + * If logger's ring buffer hasn't wrapped, simply return ts. + * Otherwise begin_ts = ts - WBS_FRAME_US * (size - offset) + */ + uint64_t begin_ts_raw_us() { + return !is_full ? ts : ts - BTM_PKT_STATUS_WBS_FRAME_US * (size - offset); + } + + /* Fast-forwards the logger's time stamp to calculate the end. + * In other words, end_ts = logger_ts + WBS_FRAME_US * wp + */ + uint64_t end_ts_raw_us() { return ts + BTM_PKT_STATUS_WBS_FRAME_US * offset; } + + std::string data_to_hex_string() { + int i; + int len = is_full ? size : offset; + int head = is_full ? offset : 0; + uint8_t byte = 0; + std::stringstream oss; + + for (i = 0; i < len; ++i) { + int j = (head + i) % size; + byte |= (1U << (j % 8)) & data[j / 8]; + + if ((i + 1) % 8 == 0) { + // +(byte) to prevent an uint8_t to be interpreted as a char + oss << std::hex << std::setw(2) << std::setfill('0') << +(byte); + byte = 0; + } + } + + if (i % 8) oss << std::hex << std::setw(2) << std::setfill('0') << +(byte); + + return oss.str(); + } + + std::string data_to_binary_string() { + int head = is_full ? offset : 0; + int len = is_full ? size : offset; + std::string s; + + for (int i = 0; i < len; ++i) { + int j = (head + i) % size; + s += std::to_string(((data[j / 8] >> (j % 8)) & 1U)); + } + + return s; + } +} tBTM_SCO_PKT_STATUS; diff --git a/system/stack/btm/security_device_record.h b/system/stack/btm/security_device_record.h index 55f2c9eb5213d4fe510517dd0dcf5eb0a9547676..ea25c87e1976731dad55277740b569fdd48f0edd 100644 --- a/system/stack/btm/security_device_record.h +++ b/system/stack/btm/security_device_record.h @@ -20,19 +20,23 @@ #include #include -#include #include #include -#include "gd/crypto_toolbox/crypto_toolbox.h" -#include "main/shim/dumpsys.h" -#include "osi/include/alarm.h" +#include "internal_include/bt_target.h" +#include "macros.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" -#include "stack/include/btm_api_types.h" +#include "stack/include/btm_sec_api_types.h" +#include "stack/include/btm_status.h" +#include "stack/include/hci_error_code.h" +#include "types/ble_address_with_type.h" #include "types/hci_role.h" #include "types/raw_address.h" +#include "types/remote_version_type.h" typedef struct { uint16_t min_conn_int; @@ -91,14 +95,21 @@ typedef struct { uint32_t counter; /* peer sign counter for verifying rcv signed cmd */ uint32_t local_counter; /* local sign counter for sending signed write cmd*/ + + tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */ } tBTM_SEC_BLE_KEYS; -struct tBTM_SEC_BLE { +// TODO: move it to btm_ble_addr.h +enum tBLE_RAND_ADDR_TYPE : uint8_t { + BTM_BLE_ADDR_PSEUDO = 0, + BTM_BLE_ADDR_RRA = 1, + BTM_BLE_ADDR_STATIC = 2, +}; + +class tBTM_BLE_ADDR_INFO { + public: RawAddress pseudo_addr; /* LE pseudo address of the device if different from device address */ - private: - tBLE_ADDR_TYPE ble_addr_type_; /* LE device type: public or random address */ - public: tBLE_ADDR_TYPE AddressType() const { return ble_addr_type_; } void SetAddressType(tBLE_ADDR_TYPE ble_addr_type) { @@ -117,17 +128,11 @@ struct tBTM_SEC_BLE { uint8_t resolving_list_index; RawAddress cur_rand_addr; /* current random address */ - typedef enum : uint8_t { - BTM_BLE_ADDR_PSEUDO = 0, - BTM_BLE_ADDR_RRA = 1, - BTM_BLE_ADDR_STATIC = 2, - } tADDRESS_TYPE; - tADDRESS_TYPE active_addr_type; + tBLE_RAND_ADDR_TYPE active_addr_type; - tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */ - tBTM_SEC_BLE_KEYS keys; /* LE device security info in peripheral rode */ + private: + tBLE_ADDR_TYPE ble_addr_type_; /* LE device type: public or random address */ }; -typedef struct tBTM_SEC_BLE tBTM_SEC_BLE; enum : uint16_t { BTM_SEC_AUTHENTICATED = 0x0002, @@ -152,10 +157,6 @@ enum : uint16_t { BTM_SEC_16_DIGIT_PIN_AUTHED = 0x4000, }; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - typedef enum : uint8_t { BTM_SEC_STATE_IDLE = 0, BTM_SEC_STATE_AUTHENTICATING = 1, @@ -205,63 +206,43 @@ typedef enum : uint8_t { be cleared on \ btm_acl_created */ } tBTM_SM4_BIT; -inline std::string class_of_device_text(const DEV_CLASS& cod) { - return base::StringPrintf("0x%02x%02x%02x", cod[2], cod[1], cod[0]); -} - /* * Define structure for Security Device Record. * A record exists for each device authenticated with this device */ -struct tBTM_SEC_DEV_REC { - /* Peering bond type */ - typedef enum : uint8_t { - BOND_TYPE_UNKNOWN = 0, - BOND_TYPE_PERSISTENT = 1, - BOND_TYPE_TEMPORARY = 2 - } tBTM_BOND_TYPE; +struct tBTM_SEC_REC { + tSECURITY_STATE sec_state; /* Operating state */ + tHCI_STATUS sec_status; /* Status in encryption change event */ + uint16_t sec_flags; /* Current device security state */ + + uint8_t pin_code_length; /* Length of the pin_code used for pairing */ uint32_t required_security_flags_for_pairing; + uint16_t security_required; /* Security required for connection */ + // security callback and its argument tBTM_SEC_CALLBACK* p_callback; void* p_ref_data; - uint32_t timestamp; /* Timestamp of the last connection */ - uint16_t hci_handle; /* Handle to connection when exists */ - uint16_t suggested_tx_octets; /* Recently suggested tx octects for data length - extension */ - uint16_t clock_offset; /* Latest known clock offset */ - RawAddress bd_addr; /* BD_ADDR of the device */ - DEV_CLASS dev_class; /* DEV_CLASS of the device */ - LinkKey link_key; /* Device link key */ - tHCI_STATUS sec_status; /* Status in encryption change event */ - public: - RawAddress RemoteAddress() const { return bd_addr; } - uint16_t get_br_edr_hci_handle() const { return hci_handle; } + bool link_key_not_sent; /* link key notification has not been sent waiting for + name */ + tBTM_IO_CAP rmt_io_caps; /* IO capability of the peer device */ + tBTM_AUTH_REQ rmt_auth_req; /* the auth_req flag as in the IO caps rsp evt */ + bool new_encryption_key_is_p256; /* Set to true when the newly generated LK + ** is generated from P-256. + ** Link encrypted with such LK can be used + ** for SM over BR/EDR. */ - private: - friend bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, - const BD_NAME& bd_name, uint8_t* features, - LinkKey* p_link_key, uint8_t key_type, - uint8_t pin_length); - friend void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, - uint8_t pin_len, uint8_t* p_pin); - friend void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status); - friend void btm_sec_connected(const RawAddress& bda, uint16_t handle, - tHCI_STATUS status, uint8_t enc_mode, - tHCI_ROLE); - friend void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, - uint8_t encr_enable); - friend void btm_sec_link_key_notification(const RawAddress& p_bda, - const Octet16& link_key, - uint8_t key_type); - friend tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, - tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, - uint8_t pin_len, uint8_t* p_pin); - uint8_t pin_code_length; /* Length of the pin_code used for paring */ + // BREDR Link Key Info + LinkKey link_key; /* Device link key */ + uint8_t link_key_type; /* Type of key used in pairing */ + uint8_t enc_key_size; /* current link encryption key size */ + + // LE Link Key Info + tBTM_SEC_BLE_KEYS ble_keys; + + tBTM_BOND_TYPE bond_type; /* bond type */ public: - uint16_t sec_flags; /* Current device security state */ bool is_device_authenticated() const { return sec_flags & BTM_SEC_AUTHENTICATED; } @@ -326,10 +307,6 @@ struct tBTM_SEC_DEV_REC { sec_flags &= ~BTM_SEC_16_DIGIT_PIN_AUTHED; } - tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be - truncated to save space in dev_rec table) */ - - tSECURITY_STATE sec_state; /* Operating state */ bool is_security_state_idle() const { return sec_state == BTM_SEC_STATE_IDLE; } @@ -368,74 +345,34 @@ struct tBTM_SEC_DEV_REC { return sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH; } - /* Data length extension */ - void set_suggested_tx_octect(uint16_t octets) { - suggested_tx_octets = octets; + bool is_bond_type_unknown() const { return bond_type == BOND_TYPE_UNKNOWN; } + bool is_bond_type_persistent() const { + return bond_type == BOND_TYPE_PERSISTENT; + } + bool is_bond_type_temporary() const { + return bond_type == BOND_TYPE_TEMPORARY; } - uint16_t get_suggested_tx_octets() const { return suggested_tx_octets; } + uint8_t get_encryption_key_size() const { return enc_key_size; } - private: - bool is_originator; /* true if device is originating connection */ - friend tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, - tBT_TRANSPORT transport, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data, - tBTM_BLE_SEC_ACT sec_act); - friend tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( - const RawAddress& bd_addr, uint16_t security_required, bool is_originator, - tBTM_SEC_CALLBACK* p_callback, void* p_ref_data); - friend tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, - bool is_originator, - uint16_t security_required, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data); + void increment_sign_counter(bool local); +}; +class tBTM_SEC_DEV_REC { public: - // whether the peer device can read GAP characteristics only visible in - // "discoverable" mode - bool can_read_discoverable{true}; - - bool IsLocallyInitiated() const { return is_originator; } - - bool role_central; /* true if current mode is central */ - uint16_t security_required; /* Security required for connection */ - bool link_key_not_sent; /* link key notification has not been sent waiting for - name */ - uint8_t link_key_type; /* Type of key used in pairing */ - - uint8_t sm4; /* BTM_SM4_TRUE, if the peer supports SM4 */ - tBTM_IO_CAP rmt_io_caps; /* IO capability of the peer device */ - tBTM_AUTH_REQ rmt_auth_req; /* the auth_req flag as in the IO caps rsp evt */ - - bool remote_supports_secure_connections; - friend void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported, - bool sc_supported, - bool hci_role_switch_supported, - bool br_edr_supported, - bool le_supported); + RawAddress RemoteAddress() const { return bd_addr; } - public: - bool SupportsSecureConnections() const { - return remote_supports_secure_connections; + /* Data length extension */ + void set_suggested_tx_octect(uint16_t octets) { + suggested_tx_octets = octets; } - bool remote_features_needed; /* set to true if the local device is in */ - /* "Secure Connections Only" mode and it receives */ - /* HCI_IO_CAPABILITY_REQUEST_EVT from the peer before */ - /* it knows peer's support for Secure Connections */ - bool remote_supports_hci_role_switch = false; - bool remote_supports_bredr; - bool remote_supports_ble; - bool remote_feature_received = false; + uint16_t get_suggested_tx_octets() const { return suggested_tx_octets; } + bool IsLocallyInitiated() const { return is_originator; } - uint16_t ble_hci_handle; /* use in DUMO connection */ + uint16_t get_br_edr_hci_handle() const { return hci_handle; } uint16_t get_ble_hci_handle() const { return ble_hci_handle; } - uint8_t enc_key_size; /* current link encryption key size */ - uint8_t get_encryption_key_size() const { return enc_key_size; } - - tBT_DEVICE_TYPE device_type; bool is_device_type_br_edr() const { return device_type == BT_DEVICE_TYPE_BREDR; } @@ -447,43 +384,59 @@ struct tBTM_SEC_DEV_REC { bool is_device_type_has_ble() const { return device_type & BT_DEVICE_TYPE_BLE; } - bool new_encryption_key_is_p256; /* Set to true when the newly generated LK - ** is generated from P-256. - ** Link encrypted with such LK can be used - ** for SM over BR/EDR. - */ - tBTM_BOND_TYPE bond_type; /* peering bond type */ - bool is_bond_type_unknown() const { return bond_type == BOND_TYPE_UNKNOWN; } - bool is_bond_type_persistent() const { - return bond_type == BOND_TYPE_PERSISTENT; - } - bool is_bond_type_temporary() const { - return bond_type == BOND_TYPE_TEMPORARY; - } - - tBTM_SEC_BLE ble; - tBTM_LE_CONN_PRAMS conn_params; - tREMOTE_VERSION_INFO remote_version_info; + bool SupportsSecureConnections() const { + return remote_supports_secure_connections; + } std::string ToString() const { return base::StringPrintf( "%s %6s cod:%s remote_info:%-14s sm4:0x%02x SecureConn:%c name:\"%s\"", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), DeviceTypeText(device_type).c_str(), - class_of_device_text(dev_class).c_str(), + dev_class_text(dev_class).c_str(), remote_version_info.ToString().c_str(), sm4, (remote_supports_secure_connections) ? 'T' : 'F', PRIVATE_NAME(sec_bd_name)); } -}; -inline std::string bond_type_text( - const tBTM_SEC_DEV_REC::tBTM_BOND_TYPE& bond_type) { - switch (bond_type) { - CASE_RETURN_TEXT(tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN); - CASE_RETURN_TEXT(tBTM_SEC_DEV_REC::BOND_TYPE_PERSISTENT); - CASE_RETURN_TEXT(tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY); - default: - return base::StringPrintf("UNKNOWN[%hhu]", bond_type); - } -} + public: + RawAddress bd_addr; /* BD_ADDR of the device */ + tBTM_BLE_ADDR_INFO ble; + tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be + truncated to save space in dev_rec table) */ + DEV_CLASS dev_class; /* DEV_CLASS of the device */ + tBT_DEVICE_TYPE device_type; + + uint32_t timestamp; /* Timestamp of the last connection */ + uint16_t hci_handle; /* Handle to BR/EDR ACL connection when exists */ + uint16_t ble_hci_handle; /* use in DUMO connection */ + + uint16_t suggested_tx_octets; /* Recently suggested tx octects for data length + extension */ + uint16_t clock_offset; /* Latest known clock offset */ + + // whether the peer device can read GAP characteristics only visible in + // "discoverable" mode + bool can_read_discoverable{true}; + + bool remote_features_needed; /* set to true if the local device is in */ + /* "Secure Connections Only" mode and it receives */ + /* HCI_IO_CAPABILITY_REQUEST_EVT from the peer before */ + /* it knows peer's support for Secure Connections */ + uint8_t sm4; /* BTM_SM4_TRUE, if the peer supports SM4 */ + bool remote_supports_hci_role_switch = false; + bool remote_supports_bredr; + bool remote_supports_ble; + bool remote_supports_secure_connections; + bool remote_feature_received = false; + + tREMOTE_VERSION_INFO remote_version_info; + + bool role_central; /* true if current mode is central (BLE) */ + bool is_originator; /* true if device is originating ACL connection */ + + // BLE connection parameters + tBTM_LE_CONN_PRAMS conn_params; + // security related properties + tBTM_SEC_REC sec_rec; +}; diff --git a/system/stack/btu/btu_event.cc b/system/stack/btu/btu_event.cc new file mode 100644 index 0000000000000000000000000000000000000000..d1bfc5b2caac3d71c7cc2abaca258482760b9c4f --- /dev/null +++ b/system/stack/btu/btu_event.cc @@ -0,0 +1,42 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "btm_iso_api.h" +#include "osi/include/allocator.h" +#include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" +#include "stack/include/btu_hcif.h" + +using bluetooth::hci::IsoManager; + +void btu_hci_msg_process(BT_HDR* p_msg) { + /* Determine the input message type. */ + switch (p_msg->event & BT_EVT_MASK) { + case BT_EVT_TO_BTU_HCI_EVT: + btu_hcif_process_event((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg); + osi_free(p_msg); + break; + + case BT_EVT_TO_BTU_HCI_ISO: + IsoManager::GetInstance()->HandleIsoData(p_msg); + osi_free(p_msg); + break; + + default: + osi_free(p_msg); + break; + } +} diff --git a/system/stack/btu/btu_hcif.cc b/system/stack/btu/btu_hcif.cc index 605e95e15d3dd148235dd68a3d4f4b34a078f619..7aa290e056b54a3952f2c066b386facffe579bca 100644 --- a/system/stack/btu/btu_hcif.cc +++ b/system/stack/btu/btu_hcif.cc @@ -27,31 +27,38 @@ #define LOG_TAG "bt_btu_hcif" +#include "stack/include/btu_hcif.h" + #include #include #include #include -#include "btif/include/btif_config.h" +#include "common/init_flags.h" #include "common/metrics.h" #include "device/include/controller.h" -#include "gd/common/init_flags.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" #include "main/shim/hci_layer.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" +#include "stack/btm/neighbor_inquiry.h" #include "stack/include/acl_hci_link_interface.h" #include "stack/include/ble_acl_interface.h" #include "stack/include/ble_hci_link_interface.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_ble_addr.h" +#include "stack/include/btm_ble_api.h" #include "stack/include/btm_iso_api.h" -#include "stack/include/btu.h" +#include "stack/include/btm_sec_api_types.h" #include "stack/include/dev_hci_link_interface.h" -#include "stack/include/gatt_api.h" #include "stack/include/hci_error_code.h" #include "stack/include/hci_evt_length.h" #include "stack/include/inq_hci_link_interface.h" #include "stack/include/l2cap_hci_link_interface.h" +#include "stack/include/main_thread.h" #include "stack/include/sco_hci_link_interface.h" #include "stack/include/sec_hci_link_interface.h" #include "stack/include/stack_metrics_logging.h" @@ -88,8 +95,23 @@ static void btu_hcif_read_clock_off_comp_evt(uint8_t* p); static void btu_hcif_esco_connection_comp_evt(const uint8_t* p); static void btu_hcif_esco_connection_chg_evt(uint8_t* p); +/* Parsing functions for btm functions */ + +static void btu_hcif_sec_pin_code_request(const uint8_t* p); +static void btu_hcif_sec_link_key_request(const uint8_t* p); +static void btu_hcif_sec_rmt_host_support_feat_evt(const uint8_t* p); +static void btu_hcif_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p); +static void btu_hcif_rem_oob_req(const uint8_t* p); +static void btu_hcif_simple_pair_complete(const uint8_t* p); +static void btu_hcif_proc_sp_req_evt(const tBTM_SP_EVT event, const uint8_t* p); +static void btu_hcif_create_conn_cancel_complete(const uint8_t* p, + uint16_t evt_len); +static void btu_hcif_read_local_oob_complete(const uint8_t* p, + uint16_t evt_len); + /* Simple Pairing Events */ static void btu_hcif_io_cap_request_evt(const uint8_t* p); +static void btu_hcif_io_cap_response_evt(const uint8_t* p); static void btu_ble_ll_conn_param_upd_evt(uint8_t* p, uint16_t evt_len); static void btu_ble_proc_ltk_req(uint8_t* p, uint16_t evt_len); @@ -102,7 +124,8 @@ static void btu_ble_rc_param_req_evt(uint8_t* p, uint8_t len); * @param evt_code event code * @param p_event pointer to event parameter, skipping paremter length */ -void btu_hcif_log_event_metrics(uint8_t evt_code, const uint8_t* p_event) { +static void btu_hcif_log_event_metrics(uint8_t evt_code, + const uint8_t* p_event) { uint32_t cmd = android::bluetooth::hci::CMD_UNKNOWN; uint16_t status = android::bluetooth::hci::STATUS_UNKNOWN; uint16_t reason = android::bluetooth::hci::STATUS_UNKNOWN; @@ -169,9 +192,12 @@ void btu_hcif_log_event_metrics(uint8_t evt_code, const uint8_t* p_event) { android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason); break; } - case HCI_BLE_EVENT: { + // Ignore these events + case HCI_BLE_EVENT: break; - } + case HCI_VENDOR_SPECIFIC_EVT: + break; + case HCI_CONNECTION_COMP_EVT: // EventCode::CONNECTION_COMPLETE case HCI_CONNECTION_REQUEST_EVT: // EventCode::CONNECTION_REQUEST case HCI_DISCONNECTION_COMP_EVT: // EventCode::DISCONNECTION_COMPLETE @@ -204,8 +230,8 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, // validate event size if (hci_evt_len < hci_event_parameters_minimum_length[hci_evt_code]) { - HCI_TRACE_WARNING("%s: evt:0x%2X, malformed event of size %hhd", __func__, - hci_evt_code, hci_evt_len); + LOG_WARN("%s: evt:0x%2X, malformed event of size %hhd", __func__, + hci_evt_code, hci_evt_len); return; } @@ -258,10 +284,10 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, btu_hcif_mode_change_evt(p); break; case HCI_PIN_CODE_REQUEST_EVT: - btm_sec_pin_code_request(p); + btu_hcif_sec_pin_code_request(p); break; case HCI_LINK_KEY_REQUEST_EVT: - btm_sec_link_key_request(p); + btu_hcif_sec_link_key_request(p); break; case HCI_LINK_KEY_NOTIFICATION_EVT: btu_hcif_link_key_notification_evt(p); @@ -279,28 +305,28 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, btm_pm_proc_ssr_evt(p, hci_evt_len); break; case HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT: - btm_sec_rmt_host_support_feat_evt(p); + btu_hcif_sec_rmt_host_support_feat_evt(p); break; case HCI_IO_CAPABILITY_REQUEST_EVT: btu_hcif_io_cap_request_evt(p); break; case HCI_IO_CAPABILITY_RESPONSE_EVT: - btm_io_capabilities_rsp(p); + btu_hcif_io_cap_response_evt(p); break; case HCI_USER_CONFIRMATION_REQUEST_EVT: - btm_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p); + btu_hcif_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p); break; case HCI_USER_PASSKEY_REQUEST_EVT: - btm_proc_sp_req_evt(BTM_SP_KEY_REQ_EVT, p); + btu_hcif_proc_sp_req_evt(BTM_SP_KEY_REQ_EVT, p); break; case HCI_REMOTE_OOB_DATA_REQUEST_EVT: - btm_rem_oob_req(p); + btu_hcif_rem_oob_req(p); break; case HCI_SIMPLE_PAIRING_COMPLETE_EVT: - btm_simple_pair_complete(p); + btu_hcif_simple_pair_complete(p); break; case HCI_USER_PASSKEY_NOTIFY_EVT: - btm_proc_sp_req_evt(BTM_SP_KEY_NOTIF_EVT, p); + btu_hcif_proc_sp_req_evt(BTM_SP_KEY_NOTIF_EVT, p); break; case HCI_BLE_EVENT: { @@ -335,28 +361,10 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, btm_ble_process_ext_adv_pkt(hci_evt_len, p); break; - case HCI_LE_ADVERTISING_SET_TERMINATED_EVT: - btm_le_on_advertising_set_terminated(p, hci_evt_len); - break; - case HCI_BLE_REQ_PEER_SCA_CPL_EVT: btm_acl_process_sca_cmpl_pkt(ble_evt_len, p); break; - case HCI_BLE_PERIODIC_ADV_SYNC_EST_EVT: - btm_ble_process_periodic_adv_sync_est_evt( - ble_evt_len, const_cast(p)); - break; - - case HCI_BLE_PERIODIC_ADV_REPORT_EVT: - btm_ble_process_periodic_adv_pkt(ble_evt_len, - const_cast(p)); - break; - - case HCI_BLE_PERIODIC_ADV_SYNC_LOST_EVT: - btm_ble_process_periodic_adv_sync_lost_evt(ble_evt_len, p); - break; - case HCI_BLE_CIS_EST_EVT: case HCI_BLE_CREATE_BIG_CPL_EVT: case HCI_BLE_TERM_BIG_CPL_EVT: @@ -636,25 +644,16 @@ void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, const BT_HDR* p_buf) { uint16_t opcode; const uint8_t* stream = p_buf->data + p_buf->offset; - void* vsc_callback = NULL; STREAM_TO_UINT16(opcode, stream); - // Eww...horrible hackery here - /* If command was a VSC, then extract command_complete callback */ - if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC || - (opcode == HCI_BLE_RAND) || (opcode == HCI_BLE_ENCRYPT)) { - vsc_callback = *((void**)(p_buf + 1)); - } - // Skip parameter length before logging stream++; btu_hcif_log_command_metrics(opcode, stream, android::bluetooth::hci::STATUS_UNKNOWN, false); bluetooth::shim::hci_layer_get_interface()->transmit_command( - p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt, - vsc_callback); + p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt, NULL); } using hci_cmd_cb = base::OnceCallbackposted_from.ToString().c_str()); + LOG_VERBOSE("command complete for: %s", + cb_wrapper->posted_from.ToString().c_str()); // 2 for event header: event code (1) + parameter length (1) // 3 for command complete header: num_hci_pkt (1) + opcode (2) uint16_t param_len = static_cast(event->len - 5); @@ -751,9 +750,9 @@ static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event, static void btu_hcif_command_complete_evt_with_cb(BT_HDR* response, void* context) { - do_in_main_thread(FROM_HERE, - base::Bind(btu_hcif_command_complete_evt_with_cb_on_task, - response, context)); + do_in_main_thread( + FROM_HERE, base::BindOnce(btu_hcif_command_complete_evt_with_cb_on_task, + response, context)); } static void btu_hcif_command_status_evt_with_cb_on_task(uint8_t status, @@ -771,8 +770,8 @@ static void btu_hcif_command_status_evt_with_cb_on_task(uint8_t status, // report command status error cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context; - HCI_TRACE_DEBUG("command status for: %s", - cb_wrapper->posted_from.ToString().c_str()); + LOG_VERBOSE("command status for: %s", + cb_wrapper->posted_from.ToString().c_str()); std::move(cb_wrapper->cb).Run(&status, sizeof(uint16_t)); cmd_with_cb_data_cleanup(cb_wrapper); osi_free(cb_wrapper); @@ -788,9 +787,9 @@ static void btu_hcif_command_status_evt_with_cb(uint8_t status, BT_HDR* command, return; } - do_in_main_thread( - FROM_HERE, base::Bind(btu_hcif_command_status_evt_with_cb_on_task, status, - command, context)); + do_in_main_thread(FROM_HERE, + base::BindOnce(btu_hcif_command_status_evt_with_cb_on_task, + status, command, context)); } /* This function is called to send commands to the Host Controller. |cb| is @@ -944,8 +943,7 @@ static void btu_hcif_encryption_change_evt(uint8_t* p) { if (status != HCI_SUCCESS || encr_enable == 0 || BTM_IsBleConnection(handle) || - (bluetooth::common::init_flags::read_encryption_key_size_is_enabled() && - !controller_get_interface()->supports_read_encryption_key_size()) || + !controller_get_interface()->supports_read_encryption_key_size() || // Skip encryption key size check when using set_min_encryption_key_size (bluetooth::common::init_flags::set_min_encryption_is_enabled() && controller_get_interface()->supports_set_min_encryption_key_size())) { @@ -1070,8 +1068,7 @@ static void btu_hcif_esco_connection_chg_evt(uint8_t* p) { * ******************************************************************************/ static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p, - uint16_t evt_len, - void* p_cplt_cback) { + uint16_t evt_len) { switch (opcode) { case HCI_INQUIRY_CANCEL: /* Tell inquiry processing that we are done */ @@ -1109,22 +1106,16 @@ static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p, break; case HCI_CREATE_CONNECTION_CANCEL: - btm_create_conn_cancel_complete(p, evt_len); + btu_hcif_create_conn_cancel_complete(p, evt_len); break; case HCI_READ_LOCAL_OOB_DATA: - btm_read_local_oob_complete(p, evt_len); + btu_hcif_read_local_oob_complete(p, evt_len); break; case HCI_READ_INQ_TX_POWER_LEVEL: break; - /* BLE Commands sComplete*/ - case HCI_BLE_RAND: - case HCI_BLE_ENCRYPT: - btm_ble_rand_enc_complete(p, evt_len, opcode, (tBTM_RAND_ENC_CB*)p_cplt_cback); - break; - case HCI_BLE_READ_ADV_CHNL_TX_POWER: btm_read_tx_power_complete(p, evt_len, true); break; @@ -1139,6 +1130,12 @@ static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p, LOG(ERROR) << "No command complete expected, but received!"; break; + case HCI_BLE_TRANSMITTER_TEST: + case HCI_BLE_RECEIVER_TEST: + case HCI_BLE_TEST_END: + btm_ble_test_command_complete(p); + break; + case HCI_BLE_ADD_DEV_RESOLVING_LIST: btm_ble_add_resolving_list_entry_complete(p, evt_len); break; @@ -1155,21 +1152,28 @@ static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p, btm_ble_read_resolving_list_entry_complete(p, evt_len); break; + // Explicitly handled command complete events case HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL: case HCI_BLE_SET_ADDR_RESOLUTION_ENABLE: case HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT: + case HCI_CHANGE_LOCAL_NAME: + case HCI_WRITE_CLASS_OF_DEVICE: + case HCI_WRITE_DEF_POLICY_SETTINGS: + case HCI_WRITE_EXT_INQ_RESPONSE: + case HCI_WRITE_INQSCAN_TYPE: + case HCI_WRITE_INQUIRYSCAN_CFG: + case HCI_WRITE_INQUIRY_MODE: + case HCI_WRITE_LINK_SUPER_TOUT: + case HCI_WRITE_PAGESCAN_CFG: + case HCI_WRITE_PAGESCAN_TYPE: + case HCI_WRITE_PAGE_TOUT: + case HCI_WRITE_SCAN_ENABLE: + case HCI_WRITE_VOICE_SETTINGS: break; - case HCI_BLE_CREATE_CONN_CANCEL: - LOG_ERROR( - "Unexpectedly received command complete for opcode:0x%02x that " - "should not be " - "handled here", - opcode); - break; default: - if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) - btm_vsc_complete(p, opcode, evt_len, (tBTM_VSC_CMPL_CB*)p_cplt_cback); + LOG_ERROR("Command complete for opcode:0x%02x should not be handled here", + opcode); break; } } @@ -1183,8 +1187,7 @@ static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p, * Returns void * ******************************************************************************/ -static void btu_hcif_command_complete_evt_on_task(BT_HDR* event, - void* context) { +static void btu_hcif_command_complete_evt_on_task(BT_HDR* event) { command_opcode_t opcode; // 2 for event header: event code (1) + parameter length (1) // 1 for num_hci_pkt command credit @@ -1195,14 +1198,16 @@ static void btu_hcif_command_complete_evt_on_task(BT_HDR* event, // 2 for event header: event code (1) + parameter length (1) // 3 for command complete header: num_hci_pkt (1) + opcode (2) uint16_t param_len = static_cast(event->len - 5); - btu_hcif_hdl_command_complete(opcode, stream, param_len, context); + btu_hcif_hdl_command_complete(opcode, stream, param_len); osi_free(event); } -static void btu_hcif_command_complete_evt(BT_HDR* response, void* context) { - do_in_main_thread(FROM_HERE, base::Bind(btu_hcif_command_complete_evt_on_task, - response, context)); +static void btu_hcif_command_complete_evt(BT_HDR* response, + void* /* context */) { + do_in_main_thread( + FROM_HERE, + base::BindOnce(btu_hcif_command_complete_evt_on_task, response)); } /******************************************************************************* @@ -1215,11 +1220,12 @@ static void btu_hcif_command_complete_evt(BT_HDR* response, void* context) { * ******************************************************************************/ static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status, - const uint8_t* p_cmd, - void* p_vsc_status_cback) { + const uint8_t* p_cmd) { CHECK_NE(p_cmd, nullptr) << "Null command for opcode 0x" << loghex(opcode); p_cmd++; // Skip parameter total length + const tHCI_STATUS hci_status = to_hci_status_code(status); + RawAddress bd_addr; uint16_t handle; @@ -1228,48 +1234,41 @@ static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status, case HCI_INQUIRY: if (status != HCI_SUCCESS) { // Tell inquiry processing that we are done - btm_process_inq_complete(to_hci_status_code(status), - BTM_BR_INQUIRY_MASK); + btm_process_inq_complete(hci_status, BTM_BR_INQUIRY_MASK); } break; case HCI_SWITCH_ROLE: if (status != HCI_SUCCESS) { // Tell BTM that the command failed STREAM_TO_BDADDR(bd_addr, p_cmd); - btm_acl_role_changed(static_cast(status), bd_addr, - HCI_ROLE_UNKNOWN); + btm_acl_role_changed(hci_status, bd_addr, HCI_ROLE_UNKNOWN); } break; case HCI_CREATE_CONNECTION: if (status != HCI_SUCCESS) { STREAM_TO_BDADDR(bd_addr, p_cmd); - btm_acl_connected(bd_addr, HCI_INVALID_HANDLE, - static_cast(status), 0); + btm_acl_connected(bd_addr, HCI_INVALID_HANDLE, hci_status, 0); } break; case HCI_AUTHENTICATION_REQUESTED: if (status != HCI_SUCCESS) { // Device refused to start authentication // This is treated as an authentication failure - btm_sec_auth_complete(HCI_INVALID_HANDLE, - static_cast(status)); + btm_sec_auth_complete(HCI_INVALID_HANDLE, hci_status); } break; case HCI_SET_CONN_ENCRYPTION: if (status != HCI_SUCCESS) { // Device refused to start encryption // This is treated as an encryption failure - btm_sec_encrypt_change(HCI_INVALID_HANDLE, - static_cast(status), false); + btm_sec_encrypt_change(HCI_INVALID_HANDLE, hci_status, false); } break; case HCI_RMT_NAME_REQUEST: if (status != HCI_SUCCESS) { // Tell inquiry processing that we are done - btm_process_remote_name(nullptr, nullptr, 0, - to_hci_status_code(status)); - btm_sec_rmt_name_request_complete(nullptr, nullptr, - to_hci_status_code(status)); + btm_process_remote_name(nullptr, nullptr, 0, hci_status); + btm_sec_rmt_name_request_complete(nullptr, nullptr, hci_status); } break; case HCI_READ_RMT_EXT_FEATURES: @@ -1283,8 +1282,7 @@ static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status, if (status != HCI_SUCCESS) { STREAM_TO_UINT16(handle, p_cmd); RawAddress addr(RawAddress::kEmpty); - btm_sco_connection_failed(static_cast(status), addr, - handle, nullptr); + btm_sco_connection_failed(hci_status, addr, handle, nullptr); } break; @@ -1292,7 +1290,7 @@ static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status, case HCI_BLE_CREATE_LL_CONN: case HCI_LE_EXTENDED_CREATE_CONNECTION: if (status != HCI_SUCCESS) { - btm_ble_create_ll_conn_complete(static_cast(status)); + btm_ble_create_ll_conn_complete(hci_status); } break; case HCI_BLE_START_ENC: @@ -1310,27 +1308,35 @@ static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status, if (status != HCI_SUCCESS) { // Allow SCO initiation to continue if waiting for change mode event STREAM_TO_UINT16(handle, p_cmd); - btm_sco_chk_pend_unpark(static_cast(status), handle); + btm_sco_chk_pend_unpark(hci_status, handle); } FALLTHROUGH_INTENDED; /* FALLTHROUGH */ case HCI_HOLD_MODE: case HCI_SNIFF_MODE: case HCI_PARK_MODE: - btm_pm_proc_cmd_status(static_cast(status)); + btm_pm_proc_cmd_status(hci_status); break; - default: - if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) { - btm_vsc_complete(&status, opcode, 1, - (tBTM_VSC_CMPL_CB*)p_vsc_status_cback); + // Command status event not handled by a specialized module + case HCI_READ_RMT_CLOCK_OFFSET: // 0x041f + case HCI_CHANGE_CONN_PACKET_TYPE: // 0x040f + if (hci_status != HCI_SUCCESS) { + LOG_WARN("Received bad command status for opcode:0x%02x status:%s", + opcode, hci_status_code_text(hci_status).c_str()); } + break; + + default: + LOG_ERROR( + "Command status for opcode:0x%02x should not be handled here " + "status:%s", + opcode, hci_status_code_text(hci_status).c_str()); } } void bluetooth::legacy::testing::btu_hcif_hdl_command_status( - uint16_t opcode, uint8_t status, const uint8_t* p_cmd, - void* p_vsc_status_cback) { - ::btu_hcif_hdl_command_status(opcode, status, p_cmd, p_vsc_status_cback); + uint16_t opcode, uint8_t status, const uint8_t* p_cmd) { + ::btu_hcif_hdl_command_status(opcode, status, p_cmd); } /******************************************************************************* @@ -1342,8 +1348,7 @@ void bluetooth::legacy::testing::btu_hcif_hdl_command_status( * Returns void * ******************************************************************************/ -static void btu_hcif_command_status_evt_on_task(uint8_t status, BT_HDR* event, - void* context) { +static void btu_hcif_command_status_evt_on_task(uint8_t status, BT_HDR* event) { command_opcode_t opcode; uint8_t* stream = event->data + event->offset; STREAM_TO_UINT16(opcode, stream); @@ -1352,14 +1357,15 @@ static void btu_hcif_command_status_evt_on_task(uint8_t status, BT_HDR* event, // No need to check length since stream is written by us btu_hcif_log_command_metrics(opcode, stream + 1, status, true); - btu_hcif_hdl_command_status(opcode, status, stream, context); + btu_hcif_hdl_command_status(opcode, status, stream); osi_free(event); } static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command, - void* context) { - do_in_main_thread(FROM_HERE, base::Bind(btu_hcif_command_status_evt_on_task, - status, command, context)); + void* /* context */) { + do_in_main_thread( + FROM_HERE, + base::BindOnce(btu_hcif_command_status_evt_on_task, status, command)); } /******************************************************************************* @@ -1405,6 +1411,93 @@ static void btu_hcif_mode_change_evt(uint8_t* p) { #endif } +/* Parsing functions for btm functions */ + +void btu_hcif_sec_pin_code_request(const uint8_t* p) { + RawAddress bda; + + STREAM_TO_BDADDR(bda, p); + btm_sec_pin_code_request(bda); +} +void btu_hcif_sec_link_key_request(const uint8_t* p) { + RawAddress bda; + STREAM_TO_BDADDR(bda, p); + btm_sec_link_key_request(bda); +} +void btu_hcif_rem_oob_req(const uint8_t* p) { + RawAddress bda; + STREAM_TO_BDADDR(bda, p); + btm_rem_oob_req(bda); +} +void btu_hcif_simple_pair_complete(const uint8_t* p) { + RawAddress bd_addr; + uint8_t status; + status = *p++; + STREAM_TO_BDADDR(bd_addr, p); + btm_simple_pair_complete(bd_addr, status); +} +void btu_hcif_sec_rmt_host_support_feat_evt(const uint8_t* p) { + RawAddress bd_addr; /* peer address */ + uint8_t features_0; + + STREAM_TO_BDADDR(bd_addr, p); + STREAM_TO_UINT8(features_0, p); + btm_sec_rmt_host_support_feat_evt(bd_addr, features_0); +} +void btu_hcif_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p) { + RawAddress bda; + uint32_t value = 0; + + /* All events start with bd_addr */ + STREAM_TO_BDADDR(bda, p); + switch (event) { + case BTM_SP_CFM_REQ_EVT: + case BTM_SP_KEY_NOTIF_EVT: + STREAM_TO_UINT32(value, p); + break; + case BTM_SP_KEY_REQ_EVT: + // No value needed. + break; + } + btm_proc_sp_req_evt(event, bda, value); +} +void btu_hcif_create_conn_cancel_complete(const uint8_t* p, uint16_t evt_len) { + uint8_t status; + + if (evt_len < 1 + BD_ADDR_LEN) { + LOG_ERROR("%s malformatted event packet, too short", __func__); + return; + } + + STREAM_TO_UINT8(status, p); + RawAddress bd_addr; + STREAM_TO_BDADDR(bd_addr, p); + btm_create_conn_cancel_complete(status, bd_addr); +} +void btu_hcif_read_local_oob_complete(const uint8_t* p, uint16_t evt_len) { + tBTM_SP_LOC_OOB evt_data; + uint8_t status; + if (evt_len < 1) { + goto err_out; + } + STREAM_TO_UINT8(status, p); + if (status == HCI_SUCCESS) { + evt_data.status = BTM_SUCCESS; + } else { + evt_data.status = BTM_ERR_PROCESSING; + } + if (evt_len < 32 + 1) { + goto err_out; + } + STREAM_TO_ARRAY16(evt_data.c.data(), p); + STREAM_TO_ARRAY16(evt_data.r.data(), p); + btm_read_local_oob_complete(evt_data); + return; + +err_out: + LOG_ERROR("%s: bogus event packet, too short", __func__); +} + /******************************************************************************* * * Function btu_hcif_link_key_notification_evt @@ -1472,40 +1565,33 @@ static void btu_hcif_io_cap_request_evt(const uint8_t* p) { btm_io_capabilities_req(bda); } -/********************************************** - * End of Simple Pairing Events - **********************************************/ - -static void read_encryption_key_size_complete_after_key_refresh(uint8_t status, uint16_t handle, uint8_t key_size) { - if (status == HCI_ERR_INSUFFCIENT_SECURITY) { - /* If remote device stop the encryption before we call "Read Encryption Key - * Size", we might receive Insufficient Security, which means that link is - * no longer encrypted. */ - LOG(INFO) << __func__ << ": encryption stopped on link: " << loghex(handle); - return; - } - - if (status != HCI_SUCCESS) { - LOG(INFO) << __func__ << ": disconnecting, status: " << loghex(status); - acl_disconnect_from_handle(handle, HCI_ERR_PEER_USER, - "stack::btu_hcif Key size fail"); - return; - } +/******************************************************************************* + * + * Function btu_hcif_io_cap_request_evt + * + * Description Process event HCI_IO_CAPABILITY_REQUEST_EVT + * + * Returns void + * + ******************************************************************************/ +static void btu_hcif_io_cap_response_evt(const uint8_t* p) { + tBTM_SP_IO_RSP evt_data; - if (key_size < MIN_KEY_SIZE) { - LOG(ERROR) << __func__ << " encryption key too short, disconnecting. handle: " << loghex(handle) - << " key_size: " << +key_size; + STREAM_TO_BDADDR(evt_data.bd_addr, p); - acl_disconnect_from_handle(handle, HCI_ERR_HOST_REJECT_SECURITY, - "stack::btu::btu_hcif::read_encryption_key_size_" - "complete_after_key_refresh Key size too small"); - return; - } + uint8_t io_cap; + STREAM_TO_UINT8(io_cap, p); + evt_data.io_cap = static_cast(io_cap); - btm_sec_encrypt_change(handle, static_cast(status), - 1 /* enc_enable */); + STREAM_TO_UINT8(evt_data.oob_data, p); + STREAM_TO_UINT8(evt_data.auth_req, p); + btm_io_capabilities_rsp(evt_data); } +/********************************************** + * End of Simple Pairing Events + **********************************************/ + static void btu_hcif_encryption_key_refresh_cmpl_evt(uint8_t* p) { uint8_t status; uint16_t handle; @@ -1513,14 +1599,8 @@ static void btu_hcif_encryption_key_refresh_cmpl_evt(uint8_t* p) { STREAM_TO_UINT8(status, p); STREAM_TO_UINT16(handle, p); - if (status != HCI_SUCCESS || BTM_IsBleConnection(handle) || - // Skip encryption key size check when using set_min_encryption_key_size - controller_get_interface()->supports_set_min_encryption_key_size()) { - btm_sec_encrypt_change(handle, static_cast(status), - (status == HCI_SUCCESS) ? 1 : 0); - } else { - btsnd_hcic_read_encryption_key_size(handle, base::Bind(&read_encryption_key_size_complete_after_key_refresh)); - } + btm_sec_encryption_key_refresh_complete(handle, + static_cast(status)); } /********************************************** @@ -1581,7 +1661,7 @@ static void btu_ble_data_length_change_evt(uint8_t* p, uint16_t evt_len) { uint16_t rx_data_len; if (!controller_get_interface()->supports_ble_packet_extension()) { - HCI_TRACE_WARNING("%s, request not supported", __func__); + LOG_WARN("%s, request not supported", __func__); return; } diff --git a/system/stack/btu/btu_task.cc b/system/stack/btu/main_thread.cc similarity index 51% rename from system/stack/btu/btu_task.cc rename to system/stack/btu/main_thread.cc index 2aa2510c04606b0297d996eb3364a7f189afa96e..b41a56bcfbdb2033a63cfcc7f9cd8af4815c027c 100644 --- a/system/stack/btu/btu_task.cc +++ b/system/stack/btu/main_thread.cc @@ -16,75 +16,22 @@ * ******************************************************************************/ -#define LOG_TAG "bt_btu_task" +#define LOG_TAG "bt_main_thread" + +#include "stack/include/main_thread.h" #include #include #include #include -#include -#include -#include -#include -#include "bta/sys/bta_sys.h" -#include "btcore/include/module.h" -#include "btif/include/btif_common.h" -#include "btm_iso_api.h" #include "common/message_loop_thread.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "stack/include/acl_hci_link_interface.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" +#include "include/hardware/bluetooth.h" +#include "os/log.h" using bluetooth::common::MessageLoopThread; -using bluetooth::hci::IsoManager; - -void btm_route_sco_data(BT_HDR* p_msg); - -/* Define BTU storage area */ -uint8_t btu_trace_level = HCI_INITIAL_TRACE_LEVEL; - -static MessageLoopThread main_thread("bt_main_thread", true); - -void btu_hci_msg_process(BT_HDR* p_msg) { - /* Determine the input message type. */ - switch (p_msg->event & BT_EVT_MASK) { - case BT_EVT_TO_BTU_HCI_ACL: - /* All Acl Data goes to ACL */ - acl_rcv_acl_data(p_msg); - break; - - case BT_EVT_TO_BTU_L2C_SEG_XMIT: - /* L2CAP segment transmit complete */ - acl_link_segments_xmitted(p_msg); - break; - - case BT_EVT_TO_BTU_HCI_SCO: - btm_route_sco_data(p_msg); - break; - - case BT_EVT_TO_BTU_HCI_EVT: - btu_hcif_process_event((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg); - osi_free(p_msg); - break; - case BT_EVT_TO_BTU_HCI_CMD: - btu_hcif_send_cmd((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg); - break; - - case BT_EVT_TO_BTU_HCI_ISO: - IsoManager::GetInstance()->HandleIsoData(p_msg); - osi_free(p_msg); - break; - - default: - osi_free(p_msg); - break; - } -} +static MessageLoopThread main_thread("bt_main_thread"); bluetooth::common::MessageLoopThread* get_main_thread() { return &main_thread; } @@ -110,8 +57,8 @@ bt_status_t do_in_main_thread_delayed(const base::Location& from_here, static void do_post_on_bt_main(BtMainClosure closure) { closure(); } void post_on_bt_main(BtMainClosure closure) { - ASSERT(do_in_main_thread( - FROM_HERE, base::Bind(do_post_on_bt_main, std::move(closure))) == + ASSERT(do_in_main_thread(FROM_HERE, base::BindOnce(do_post_on_bt_main, + std::move(closure))) == BT_STATUS_SUCCESS); } @@ -130,22 +77,3 @@ void main_thread_start_up() { } void main_thread_shut_down() { main_thread.ShutDown(); } - -bool is_on_main_thread() { - // Pthreads doesn't have the concept of a thread ID, so we have to reach down - // into the kernel. -#if defined(OS_MACOSX) - return main_thread.GetThreadId() == pthread_mach_thread_np(pthread_self()); -#elif defined(OS_LINUX) -#include /* For SYS_xxx definitions */ -#include - return main_thread.GetThreadId() == syscall(__NR_gettid); -#elif defined(__ANDROID__) -#include -#include - return main_thread.GetThreadId() == gettid(); -#else - LOG(ERROR) << __func__ << "Unable to determine if on main thread"; - return true; -#endif -} diff --git a/system/stack/crypto_toolbox/aes.cc b/system/stack/crypto_toolbox/aes.cc deleted file mode 100644 index f53894e4a4a78470dc07f6a501536b7e3143c36c..0000000000000000000000000000000000000000 --- a/system/stack/crypto_toolbox/aes.cc +++ /dev/null @@ -1,950 +0,0 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The redistribution and use of this software (with or without changes) - is allowed without the payment of fees or royalties provided that: - - 1. source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - 2. binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation; - - 3. the name of the copyright holder is not used to endorse products - built using this software without specific written permission. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue 09/09/2006 - - This is an AES implementation that uses only 8-bit byte operations on the - cipher state (there are options to use 32-bit types if available). - - The combination of mix columns and byte substitution used here is based on - that developed by Karl Malbrain. His contribution is acknowledged. - */ - -/* define if you have a fast memcpy function on your system */ -#if 1 -#define HAVE_MEMCPY -#include -#if 0 -#if defined(_MSC_VER) -#include -#pragma intrinsic(memcpy) -#endif -#endif -#endif - -#include -#include - -/* define if you have fast 32-bit types on your system */ -#if 1 -#define HAVE_UINT_32T -#endif - -/* define if you don't want any tables */ -#if 1 -#define USE_TABLES -#endif - -/* On Intel Core 2 duo VERSION_1 is faster */ - -/* alternative versions (test for performance on your system) */ -#if 1 -#define VERSION_1 -#endif - -#include "aes.h" - -#if defined(HAVE_UINT_32T) -typedef uint32_t uint_32t; -#endif - -/* functions for finite field multiplication in the AES Galois field */ - -#define WPOLY 0x011b -#define BPOLY 0x1b -#define DPOLY 0x008d - -#define f1(x) (x) -#define f2(x) (((x) << 1) ^ ((((x) >> 7) & 1) * WPOLY)) -#define f4(x) \ - (((x) << 2) ^ ((((x) >> 6) & 1) * WPOLY) ^ ((((x) >> 6) & 2) * WPOLY)) -#define f8(x) \ - (((x) << 3) ^ ((((x) >> 5) & 1) * WPOLY) ^ ((((x) >> 5) & 2) * WPOLY) ^ \ - ((((x) >> 5) & 4) * WPOLY)) -#define d2(x) (((x) >> 1) ^ ((x)&1 ? DPOLY : 0)) - -#define f3(x) (f2(x) ^ (x)) -#define f9(x) (f8(x) ^ (x)) -#define fb(x) (f8(x) ^ f2(x) ^ (x)) -#define fd(x) (f8(x) ^ f4(x) ^ (x)) -#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) - -#if defined(USE_TABLES) - -#define sb_data(w) \ - { /* S Box data values */ \ - w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), \ - w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), \ - w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), \ - w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), \ - w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), w(0x26), \ - w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), w(0xe5), \ - w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), w(0xc7), \ - w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), w(0x07), \ - w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \ - w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), \ - w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), \ - w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), \ - w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), w(0x39), \ - w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), w(0xaa), \ - w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), w(0xf9), \ - w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), w(0x51), \ - w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5), \ - w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), \ - w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), \ - w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), \ - w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), w(0xdc), \ - w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), w(0xb8), \ - w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), w(0x32), \ - w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), w(0xc2), \ - w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79), \ - w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), \ - w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), \ - w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), \ - w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), w(0x1f), \ - w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), w(0xb5), \ - w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), w(0x35), \ - w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), w(0xe1), \ - w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), \ - w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), \ - w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), \ - w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), \ - w(0x54), w(0xbb), w(0x16) \ - } - -#define isb_data(w) \ - { /* inverse S Box data values */ \ - w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), \ - w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), \ - w(0xfb), w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), \ - w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), \ - w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), w(0x32), \ - w(0xa6), w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), w(0x95), \ - w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e), w(0x08), w(0x2e), \ - w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2), w(0x76), \ - w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \ - w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), \ - w(0x16), w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), \ - w(0xb6), w(0x92), w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), \ - w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), w(0x57), \ - w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), w(0xab), \ - w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), w(0xe4), \ - w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06), w(0xd0), \ - w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02), \ - w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), \ - w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), \ - w(0xdc), w(0xea), w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), \ - w(0xb4), w(0xe6), w(0x73), w(0x96), w(0xac), w(0x74), w(0x22), \ - w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), w(0x37), \ - w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), w(0xf1), \ - w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), w(0x6f), \ - w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b), \ - w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), \ - w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), \ - w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), \ - w(0x07), w(0xc7), w(0x31), w(0xb1), w(0x12), w(0x10), w(0x59), \ - w(0x27), w(0x80), w(0xec), w(0x5f), w(0x60), w(0x51), w(0x7f), \ - w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), w(0xe5), \ - w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), w(0xa0), \ - w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), \ - w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), \ - w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), \ - w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), \ - w(0x21), w(0x0c), w(0x7d) \ - } - -#define mm_data(w) \ - { /* basic data for forming finite field tables */ \ - w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), \ - w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), \ - w(0x0f), w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), \ - w(0x16), w(0x17), w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), \ - w(0x1d), w(0x1e), w(0x1f), w(0x20), w(0x21), w(0x22), w(0x23), \ - w(0x24), w(0x25), w(0x26), w(0x27), w(0x28), w(0x29), w(0x2a), \ - w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f), w(0x30), w(0x31), \ - w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37), w(0x38), \ - w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \ - w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), \ - w(0x47), w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), \ - w(0x4e), w(0x4f), w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), \ - w(0x55), w(0x56), w(0x57), w(0x58), w(0x59), w(0x5a), w(0x5b), \ - w(0x5c), w(0x5d), w(0x5e), w(0x5f), w(0x60), w(0x61), w(0x62), \ - w(0x63), w(0x64), w(0x65), w(0x66), w(0x67), w(0x68), w(0x69), \ - w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f), w(0x70), \ - w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77), \ - w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), \ - w(0x7f), w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), \ - w(0x86), w(0x87), w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), \ - w(0x8d), w(0x8e), w(0x8f), w(0x90), w(0x91), w(0x92), w(0x93), \ - w(0x94), w(0x95), w(0x96), w(0x97), w(0x98), w(0x99), w(0x9a), \ - w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), w(0xa0), w(0xa1), \ - w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), w(0xa8), \ - w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf), \ - w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), \ - w(0xb7), w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), \ - w(0xbe), w(0xbf), w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), \ - w(0xc5), w(0xc6), w(0xc7), w(0xc8), w(0xc9), w(0xca), w(0xcb), \ - w(0xcc), w(0xcd), w(0xce), w(0xcf), w(0xd0), w(0xd1), w(0xd2), \ - w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), w(0xd8), w(0xd9), \ - w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), w(0xe0), \ - w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), \ - w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), \ - w(0xef), w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), \ - w(0xf6), w(0xf7), w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), \ - w(0xfd), w(0xfe), w(0xff) \ - } - -static const uint_8t sbox[256] = sb_data(f1); -static const uint_8t isbox[256] = isb_data(f1); - -static const uint_8t gfm2_sbox[256] = sb_data(f2); -static const uint_8t gfm3_sbox[256] = sb_data(f3); - -static const uint_8t gfmul_9[256] = mm_data(f9); -static const uint_8t gfmul_b[256] = mm_data(fb); -static const uint_8t gfmul_d[256] = mm_data(fd); -static const uint_8t gfmul_e[256] = mm_data(fe); - -#define s_box(x) sbox[(x)] -#define is_box(x) isbox[(x)] -#define gfm2_sb(x) gfm2_sbox[(x)] -#define gfm3_sb(x) gfm3_sbox[(x)] -#define gfm_9(x) gfmul_9[(x)] -#define gfm_b(x) gfmul_b[(x)] -#define gfm_d(x) gfmul_d[(x)] -#define gfm_e(x) gfmul_e[(x)] - -#else - -/* this is the high bit of x right shifted by 1 */ -/* position. Since the starting polynomial has */ -/* 9 bits (0x11b), this right shift keeps the */ -/* values of all top bits within a byte */ - -static uint_8t hibit(const uint_8t x) { - uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); - - r |= (r >> 2); - r |= (r >> 4); - return (r + 1) >> 1; -} - -/* return the inverse of the finite field element x */ - -static uint_8t gf_inv(const uint_8t x) { - uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; - - if (x < 2) return x; - - for (;;) { - if (n1) - while (n2 >= n1) /* divide polynomial p2 by p1 */ - { - n2 /= n1; /* shift smaller polynomial left */ - p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ - v2 ^= (v1 * n2); /* shift accumulated value and */ - n2 = hibit(p2); /* add into result */ - } - else - return v1; - - if (n2) /* repeat with values swapped */ - while (n1 >= n2) { - n1 /= n2; - p1 ^= p2 * n1; - v1 ^= v2 * n1; - n1 = hibit(p1); - } - else - return v2; - } -} - -/* The forward and inverse affine transformations used in the S-box */ -uint_8t fwd_affine(const uint_8t x) { -#if defined(HAVE_UINT_32T) - uint_32t w = x; - w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); - return 0x63 ^ ((w ^ (w >> 8)) & 0xff); -#else - return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) ^ (x >> 7) ^ - (x >> 6) ^ (x >> 5) ^ (x >> 4); -#endif -} - -uint_8t inv_affine(const uint_8t x) { -#if defined(HAVE_UINT_32T) - uint_32t w = x; - w = (w << 1) ^ (w << 3) ^ (w << 6); - return 0x05 ^ ((w ^ (w >> 8)) & 0xff); -#else - return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) ^ (x >> 7) ^ (x >> 5) ^ (x >> 2); -#endif -} - -#define s_box(x) fwd_affine(gf_inv(x)) -#define is_box(x) gf_inv(inv_affine(x)) -#define gfm2_sb(x) f2(s_box(x)) -#define gfm3_sb(x) f3(s_box(x)) -#define gfm_9(x) f9(x) -#define gfm_b(x) fb(x) -#define gfm_d(x) fd(x) -#define gfm_e(x) fe(x) - -#endif - -#if defined(HAVE_MEMCPY) -#define block_copy_nn(d, s, l) memcpy(d, s, l) -#define block_copy(d, s) memcpy(d, s, N_BLOCK) -#else -#define block_copy_nn(d, s, l) copy_block_nn(d, s, l) -#define block_copy(d, s) copy_block(d, s) -#endif - -#if !defined(HAVE_MEMCPY) -static void copy_block(void* d, const void* s) { -#if defined(HAVE_UINT_32T) - ((uint_32t*)d)[0] = ((uint_32t*)s)[0]; - ((uint_32t*)d)[1] = ((uint_32t*)s)[1]; - ((uint_32t*)d)[2] = ((uint_32t*)s)[2]; - ((uint_32t*)d)[3] = ((uint_32t*)s)[3]; -#else - ((uint_8t*)d)[0] = ((uint_8t*)s)[0]; - ((uint_8t*)d)[1] = ((uint_8t*)s)[1]; - ((uint_8t*)d)[2] = ((uint_8t*)s)[2]; - ((uint_8t*)d)[3] = ((uint_8t*)s)[3]; - ((uint_8t*)d)[4] = ((uint_8t*)s)[4]; - ((uint_8t*)d)[5] = ((uint_8t*)s)[5]; - ((uint_8t*)d)[6] = ((uint_8t*)s)[6]; - ((uint_8t*)d)[7] = ((uint_8t*)s)[7]; - ((uint_8t*)d)[8] = ((uint_8t*)s)[8]; - ((uint_8t*)d)[9] = ((uint_8t*)s)[9]; - ((uint_8t*)d)[10] = ((uint_8t*)s)[10]; - ((uint_8t*)d)[11] = ((uint_8t*)s)[11]; - ((uint_8t*)d)[12] = ((uint_8t*)s)[12]; - ((uint_8t*)d)[13] = ((uint_8t*)s)[13]; - ((uint_8t*)d)[14] = ((uint_8t*)s)[14]; - ((uint_8t*)d)[15] = ((uint_8t*)s)[15]; -#endif -} - -static void copy_block_nn(void* d, const void* s, uint_8t nn) { - while (nn--) *((uint_8t*)d)++ = *((uint_8t*)s)++; -} -#endif - -static void xor_block(void* d, const void* s) { -#if defined(HAVE_UINT_32T) - ((uint_32t*)d)[0] ^= ((uint_32t*)s)[0]; - ((uint_32t*)d)[1] ^= ((uint_32t*)s)[1]; - ((uint_32t*)d)[2] ^= ((uint_32t*)s)[2]; - ((uint_32t*)d)[3] ^= ((uint_32t*)s)[3]; -#else - ((uint_8t*)d)[0] ^= ((uint_8t*)s)[0]; - ((uint_8t*)d)[1] ^= ((uint_8t*)s)[1]; - ((uint_8t*)d)[2] ^= ((uint_8t*)s)[2]; - ((uint_8t*)d)[3] ^= ((uint_8t*)s)[3]; - ((uint_8t*)d)[4] ^= ((uint_8t*)s)[4]; - ((uint_8t*)d)[5] ^= ((uint_8t*)s)[5]; - ((uint_8t*)d)[6] ^= ((uint_8t*)s)[6]; - ((uint_8t*)d)[7] ^= ((uint_8t*)s)[7]; - ((uint_8t*)d)[8] ^= ((uint_8t*)s)[8]; - ((uint_8t*)d)[9] ^= ((uint_8t*)s)[9]; - ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10]; - ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11]; - ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12]; - ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13]; - ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14]; - ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15]; -#endif -} - -static void copy_and_key(void* d, const void* s, const void* k) { -#if defined(HAVE_UINT_32T) - ((uint_32t*)d)[0] = ((uint_32t*)s)[0] ^ ((uint_32t*)k)[0]; - ((uint_32t*)d)[1] = ((uint_32t*)s)[1] ^ ((uint_32t*)k)[1]; - ((uint_32t*)d)[2] = ((uint_32t*)s)[2] ^ ((uint_32t*)k)[2]; - ((uint_32t*)d)[3] = ((uint_32t*)s)[3] ^ ((uint_32t*)k)[3]; -#elif 1 - ((uint_8t*)d)[0] = ((uint_8t*)s)[0] ^ ((uint_8t*)k)[0]; - ((uint_8t*)d)[1] = ((uint_8t*)s)[1] ^ ((uint_8t*)k)[1]; - ((uint_8t*)d)[2] = ((uint_8t*)s)[2] ^ ((uint_8t*)k)[2]; - ((uint_8t*)d)[3] = ((uint_8t*)s)[3] ^ ((uint_8t*)k)[3]; - ((uint_8t*)d)[4] = ((uint_8t*)s)[4] ^ ((uint_8t*)k)[4]; - ((uint_8t*)d)[5] = ((uint_8t*)s)[5] ^ ((uint_8t*)k)[5]; - ((uint_8t*)d)[6] = ((uint_8t*)s)[6] ^ ((uint_8t*)k)[6]; - ((uint_8t*)d)[7] = ((uint_8t*)s)[7] ^ ((uint_8t*)k)[7]; - ((uint_8t*)d)[8] = ((uint_8t*)s)[8] ^ ((uint_8t*)k)[8]; - ((uint_8t*)d)[9] = ((uint_8t*)s)[9] ^ ((uint_8t*)k)[9]; - ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10]; - ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11]; - ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12]; - ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13]; - ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14]; - ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15]; -#else - block_copy(d, s); - xor_block(d, k); -#endif -} - -static void add_round_key(uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK]) { - xor_block(d, k); -} - -static void shift_sub_rows(uint_8t st[N_BLOCK]) { - uint_8t tt; - - st[0] = s_box(st[0]); - st[4] = s_box(st[4]); - st[8] = s_box(st[8]); - st[12] = s_box(st[12]); - - tt = st[1]; - st[1] = s_box(st[5]); - st[5] = s_box(st[9]); - st[9] = s_box(st[13]); - st[13] = s_box(tt); - - tt = st[2]; - st[2] = s_box(st[10]); - st[10] = s_box(tt); - tt = st[6]; - st[6] = s_box(st[14]); - st[14] = s_box(tt); - - tt = st[15]; - st[15] = s_box(st[11]); - st[11] = s_box(st[7]); - st[7] = s_box(st[3]); - st[3] = s_box(tt); -} - -static void inv_shift_sub_rows(uint_8t st[N_BLOCK]) { - uint_8t tt; - - st[0] = is_box(st[0]); - st[4] = is_box(st[4]); - st[8] = is_box(st[8]); - st[12] = is_box(st[12]); - - tt = st[13]; - st[13] = is_box(st[9]); - st[9] = is_box(st[5]); - st[5] = is_box(st[1]); - st[1] = is_box(tt); - - tt = st[2]; - st[2] = is_box(st[10]); - st[10] = is_box(tt); - tt = st[6]; - st[6] = is_box(st[14]); - st[14] = is_box(tt); - - tt = st[3]; - st[3] = is_box(st[7]); - st[7] = is_box(st[11]); - st[11] = is_box(st[15]); - st[15] = is_box(tt); -} - -#if defined(VERSION_1) -static void mix_sub_columns(uint_8t dt[N_BLOCK]) { - uint_8t st[N_BLOCK]; - block_copy(st, dt); -#else -static void mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) { -#endif - dt[0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]); - dt[1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]); - dt[2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]); - dt[3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]); - - dt[4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]); - dt[5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]); - dt[6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]); - dt[7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]); - - dt[8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]); - dt[9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]); - dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]); - dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]); - - dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]); - dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]); - dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]); - dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]); -} - -#if defined(VERSION_1) -static void inv_mix_sub_columns(uint_8t dt[N_BLOCK]) { - uint_8t st[N_BLOCK]; - block_copy(st, dt); -#else -static void inv_mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) { -#endif - dt[0] = is_box(gfm_e(st[0]) ^ gfm_b(st[1]) ^ gfm_d(st[2]) ^ gfm_9(st[3])); - dt[5] = is_box(gfm_9(st[0]) ^ gfm_e(st[1]) ^ gfm_b(st[2]) ^ gfm_d(st[3])); - dt[10] = is_box(gfm_d(st[0]) ^ gfm_9(st[1]) ^ gfm_e(st[2]) ^ gfm_b(st[3])); - dt[15] = is_box(gfm_b(st[0]) ^ gfm_d(st[1]) ^ gfm_9(st[2]) ^ gfm_e(st[3])); - - dt[4] = is_box(gfm_e(st[4]) ^ gfm_b(st[5]) ^ gfm_d(st[6]) ^ gfm_9(st[7])); - dt[9] = is_box(gfm_9(st[4]) ^ gfm_e(st[5]) ^ gfm_b(st[6]) ^ gfm_d(st[7])); - dt[14] = is_box(gfm_d(st[4]) ^ gfm_9(st[5]) ^ gfm_e(st[6]) ^ gfm_b(st[7])); - dt[3] = is_box(gfm_b(st[4]) ^ gfm_d(st[5]) ^ gfm_9(st[6]) ^ gfm_e(st[7])); - - dt[8] = is_box(gfm_e(st[8]) ^ gfm_b(st[9]) ^ gfm_d(st[10]) ^ gfm_9(st[11])); - dt[13] = is_box(gfm_9(st[8]) ^ gfm_e(st[9]) ^ gfm_b(st[10]) ^ gfm_d(st[11])); - dt[2] = is_box(gfm_d(st[8]) ^ gfm_9(st[9]) ^ gfm_e(st[10]) ^ gfm_b(st[11])); - dt[7] = is_box(gfm_b(st[8]) ^ gfm_d(st[9]) ^ gfm_9(st[10]) ^ gfm_e(st[11])); - - dt[12] = - is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15])); - dt[1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15])); - dt[6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15])); - dt[11] = - is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15])); -} - -#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED) - -/* Set the cipher key for the pre-keyed version */ -/* NOTE: If the length_type used for the key length is an - unsigned 8-bit character, a key length of 256 bits must - be entered as a length in bytes (valid inputs are hence - 128, 192, 16, 24 and 32). -*/ - -return_type aes_set_key(const unsigned char key[], length_type keylen, - aes_context ctx[1]) { - uint_8t cc, rc, hi; - - switch (keylen) { - case 16: - case 128: /* length in bits (128 = 8*16) */ - keylen = 16; - break; - case 24: - case 192: /* length in bits (192 = 8*24) */ - keylen = 24; - break; - case 32: - /* case 256: length in bits (256 = 8*32) */ - keylen = 32; - break; - default: - ctx->rnd = 0; - return (return_type)-1; - } - block_copy_nn(ctx->ksch, key, keylen); - hi = (keylen + 28) << 2; - ctx->rnd = (hi >> 4) - 1; - for (cc = keylen, rc = 1; cc < hi; cc += 4) { - uint_8t tt, t0, t1, t2, t3; - - t0 = ctx->ksch[cc - 4]; - t1 = ctx->ksch[cc - 3]; - t2 = ctx->ksch[cc - 2]; - t3 = ctx->ksch[cc - 1]; - if (cc % keylen == 0) { - tt = t0; - t0 = s_box(t1) ^ rc; - t1 = s_box(t2); - t2 = s_box(t3); - t3 = s_box(tt); - rc = f2(rc); - } else if (keylen > 24 && cc % keylen == 16) { - t0 = s_box(t0); - t1 = s_box(t1); - t2 = s_box(t2); - t3 = s_box(t3); - } - tt = cc - keylen; - ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0; - ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1; - ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2; - ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3; - } - return 0; -} - -#endif - -#if defined(AES_ENC_PREKEYED) - -/* Encrypt a single block of 16 bytes */ - -return_type aes_encrypt(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], const aes_context ctx[1]) { - if (ctx->rnd) { - uint_8t s1[N_BLOCK], r; - copy_and_key(s1, in, ctx->ksch); - - for (r = 1; r < ctx->rnd; ++r) -#if defined(VERSION_1) - { - mix_sub_columns(s1); - add_round_key(s1, ctx->ksch + r * N_BLOCK); - } -#else - { - uint_8t s2[N_BLOCK]; - mix_sub_columns(s2, s1); - copy_and_key(s1, s2, ctx->ksch + r * N_BLOCK); - } -#endif - shift_sub_rows(s1); - copy_and_key(out, s1, ctx->ksch + r * N_BLOCK); - } else - return (return_type)-1; - return 0; -} - -/* CBC encrypt a number of blocks (input and return an IV) */ - -return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out, - int n_block, unsigned char iv[N_BLOCK], - const aes_context ctx[1]) { - while (n_block--) { - xor_block(iv, in); - if (aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; - memcpy(out, iv, N_BLOCK); - in += N_BLOCK; - out += N_BLOCK; - } - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_DEC_PREKEYED) - -/* Decrypt a single block of 16 bytes */ - -return_type aes_decrypt(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], const aes_context ctx[1]) { - if (ctx->rnd) { - uint_8t s1[N_BLOCK], r; - copy_and_key(s1, in, ctx->ksch + ctx->rnd * N_BLOCK); - inv_shift_sub_rows(s1); - - for (r = ctx->rnd; --r;) -#if defined(VERSION_1) - { - add_round_key(s1, ctx->ksch + r * N_BLOCK); - inv_mix_sub_columns(s1); - } -#else - { - uint_8t s2[N_BLOCK]; - copy_and_key(s2, s1, ctx->ksch + r * N_BLOCK); - inv_mix_sub_columns(s1, s2); - } -#endif - copy_and_key(out, s1, ctx->ksch); - } else - return (return_type)-1; - return 0; -} - -/* CBC decrypt a number of blocks (input and return an IV) */ - -return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out, - int n_block, unsigned char iv[N_BLOCK], - const aes_context ctx[1]) { - while (n_block--) { - uint_8t tmp[N_BLOCK]; - - memcpy(tmp, in, N_BLOCK); - if (aes_decrypt(in, out, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; - xor_block(out, iv); - memcpy(iv, tmp, N_BLOCK); - in += N_BLOCK; - out += N_BLOCK; - } - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_ENC_128_OTFK) - -/* The 'on the fly' encryption key update for for 128 bit keys */ - -static void update_encrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) { - uint_8t cc; - - k[0] ^= s_box(k[13]) ^ *rc; - k[1] ^= s_box(k[14]); - k[2] ^= s_box(k[15]); - k[3] ^= s_box(k[12]); - *rc = f2(*rc); - - for (cc = 4; cc < 16; cc += 4) { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } -} - -/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ - -void aes_encrypt_128(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], - const unsigned char key[N_BLOCK], - unsigned char o_key[N_BLOCK]) { - uint_8t s1[N_BLOCK], r, rc = 1; - - if (o_key != key) block_copy(o_key, key); - copy_and_key(s1, in, o_key); - - for (r = 1; r < 10; ++r) -#if defined(VERSION_1) - { - mix_sub_columns(s1); - update_encrypt_key_128(o_key, &rc); - add_round_key(s1, o_key); - } -#else - { - uint_8t s2[N_BLOCK]; - mix_sub_columns(s2, s1); - update_encrypt_key_128(o_key, &rc); - copy_and_key(s1, s2, o_key); - } -#endif - - shift_sub_rows(s1); - update_encrypt_key_128(o_key, &rc); - copy_and_key(out, s1, o_key); -} - -#endif - -#if defined(AES_DEC_128_OTFK) - -/* The 'on the fly' decryption key update for for 128 bit keys */ - -static void update_decrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) { - uint_8t cc; - - for (cc = 12; cc > 0; cc -= 4) { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } - *rc = d2(*rc); - k[0] ^= s_box(k[13]) ^ *rc; - k[1] ^= s_box(k[14]); - k[2] ^= s_box(k[15]); - k[3] ^= s_box(k[12]); -} - -/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ - -void aes_decrypt_128(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], - const unsigned char key[N_BLOCK], - unsigned char o_key[N_BLOCK]) { - uint_8t s1[N_BLOCK], r, rc = 0x6c; - if (o_key != key) block_copy(o_key, key); - - copy_and_key(s1, in, o_key); - inv_shift_sub_rows(s1); - - for (r = 10; --r;) -#if defined(VERSION_1) - { - update_decrypt_key_128(o_key, &rc); - add_round_key(s1, o_key); - inv_mix_sub_columns(s1); - } -#else - { - uint_8t s2[N_BLOCK]; - update_decrypt_key_128(o_key, &rc); - copy_and_key(s2, s1, o_key); - inv_mix_sub_columns(s1, s2); - } -#endif - update_decrypt_key_128(o_key, &rc); - copy_and_key(out, s1, o_key); -} - -#endif - -#if defined(AES_ENC_256_OTFK) - -/* The 'on the fly' encryption key update for for 256 bit keys */ - -static void update_encrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) { - uint_8t cc; - - k[0] ^= s_box(k[29]) ^ *rc; - k[1] ^= s_box(k[30]); - k[2] ^= s_box(k[31]); - k[3] ^= s_box(k[28]); - *rc = f2(*rc); - - for (cc = 4; cc < 16; cc += 4) { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } - - k[16] ^= s_box(k[12]); - k[17] ^= s_box(k[13]); - k[18] ^= s_box(k[14]); - k[19] ^= s_box(k[15]); - - for (cc = 20; cc < 32; cc += 4) { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } -} - -/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */ - -void aes_encrypt_256(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], - const unsigned char key[2 * N_BLOCK], - unsigned char o_key[2 * N_BLOCK]) { - uint_8t s1[N_BLOCK], r, rc = 1; - if (o_key != key) { - block_copy(o_key, key); - block_copy(o_key + 16, key + 16); - } - copy_and_key(s1, in, o_key); - - for (r = 1; r < 14; ++r) -#if defined(VERSION_1) - { - mix_sub_columns(s1); - if (r & 1) - add_round_key(s1, o_key + 16); - else { - update_encrypt_key_256(o_key, &rc); - add_round_key(s1, o_key); - } - } -#else - { - uint_8t s2[N_BLOCK]; - mix_sub_columns(s2, s1); - if (r & 1) - copy_and_key(s1, s2, o_key + 16); - else { - update_encrypt_key_256(o_key, &rc); - copy_and_key(s1, s2, o_key); - } - } -#endif - - shift_sub_rows(s1); - update_encrypt_key_256(o_key, &rc); - copy_and_key(out, s1, o_key); -} - -#endif - -#if defined(AES_DEC_256_OTFK) - -/* The 'on the fly' encryption key update for for 256 bit keys */ - -static void update_decrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) { - uint_8t cc; - - for (cc = 28; cc > 16; cc -= 4) { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } - - k[16] ^= s_box(k[12]); - k[17] ^= s_box(k[13]); - k[18] ^= s_box(k[14]); - k[19] ^= s_box(k[15]); - - for (cc = 12; cc > 0; cc -= 4) { - k[cc + 0] ^= k[cc - 4]; - k[cc + 1] ^= k[cc - 3]; - k[cc + 2] ^= k[cc - 2]; - k[cc + 3] ^= k[cc - 1]; - } - - *rc = d2(*rc); - k[0] ^= s_box(k[29]) ^ *rc; - k[1] ^= s_box(k[30]); - k[2] ^= s_box(k[31]); - k[3] ^= s_box(k[28]); -} - -/* Decrypt a single block of 16 bytes with 'on the fly' - 256 bit keying -*/ -void aes_decrypt_256(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], - const unsigned char key[2 * N_BLOCK], - unsigned char o_key[2 * N_BLOCK]) { - uint_8t s1[N_BLOCK], r, rc = 0x80; - - if (o_key != key) { - block_copy(o_key, key); - block_copy(o_key + 16, key + 16); - } - - copy_and_key(s1, in, o_key); - inv_shift_sub_rows(s1); - - for (r = 14; --r;) -#if defined(VERSION_1) - { - if ((r & 1)) { - update_decrypt_key_256(o_key, &rc); - add_round_key(s1, o_key + 16); - } else - add_round_key(s1, o_key); - inv_mix_sub_columns(s1); - } -#else - { - uint_8t s2[N_BLOCK]; - if ((r & 1)) { - update_decrypt_key_256(o_key, &rc); - copy_and_key(s2, s1, o_key + 16); - } else - copy_and_key(s2, s1, o_key); - inv_mix_sub_columns(s1, s2); - } -#endif - copy_and_key(out, s1, o_key); -} - -#endif diff --git a/system/stack/crypto_toolbox/aes.h b/system/stack/crypto_toolbox/aes.h deleted file mode 100644 index 2ff6fbde028caebbfec7cf59bf1c1d0cabdfb419..0000000000000000000000000000000000000000 --- a/system/stack/crypto_toolbox/aes.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The redistribution and use of this software (with or without changes) - is allowed without the payment of fees or royalties provided that: - - 1. source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - 2. binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation; - - 3. the name of the copyright holder is not used to endorse products - built using this software without specific written permission. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue 09/09/2006 - - This is an AES implementation that uses only 8-bit byte operations on the - cipher state. - */ - -#ifndef AES_H -#define AES_H - -#if 1 -#define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */ -#endif -#if 1 -#define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */ -#endif -#if 1 -#define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */ -#endif -#if 1 -#define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */ -#endif -#if 1 -#define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */ -#endif -#if 1 -#define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */ -#endif - -#define N_ROW 4 -#define N_COL 4 -#define N_BLOCK (N_ROW * N_COL) -#define N_MAX_ROUNDS 14 - -typedef unsigned char uint_8t; - -typedef uint_8t return_type; - -/* Warning: The key length for 256 bit keys overflows a byte - (see comment below) -*/ - -typedef uint_8t length_type; - -typedef struct { - uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK]; - uint_8t rnd; -} aes_context; - -/* The following calls are for a precomputed key schedule - - NOTE: If the length_type used for the key length is an - unsigned 8-bit character, a key length of 256 bits must - be entered as a length in bytes (valid inputs are hence - 128, 192, 16, 24 and 32). -*/ - -#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED) - -return_type aes_set_key(const unsigned char key[], length_type keylen, - aes_context ctx[1]); -#endif - -#if defined(AES_ENC_PREKEYED) - -return_type aes_encrypt(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], const aes_context ctx[1]); - -return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out, - int n_block, unsigned char iv[N_BLOCK], - const aes_context ctx[1]); -#endif - -#if defined(AES_DEC_PREKEYED) - -return_type aes_decrypt(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], const aes_context ctx[1]); - -return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out, - int n_block, unsigned char iv[N_BLOCK], - const aes_context ctx[1]); -#endif - -/* The following calls are for 'on the fly' keying. In this case the - encryption and decryption keys are different. - - The encryption subroutines take a key in an array of bytes in - key[L] where L is 16, 24 or 32 bytes for key lengths of 128, - 192, and 256 bits respectively. They then encrypts the input - data, in[] with this key and put the reult in the output array - out[]. In addition, the second key array, o_key[L], is used - to output the key that is needed by the decryption subroutine - to reverse the encryption operation. The two key arrays can - be the same array but in this case the original key will be - overwritten. - - In the same way, the decryption subroutines output keys that - can be used to reverse their effect when used for encryption. - - Only 128 and 256 bit keys are supported in these 'on the fly' - modes. -*/ - -#if defined(AES_ENC_128_OTFK) -void aes_encrypt_128(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], - const unsigned char key[N_BLOCK], uint_8t o_key[N_BLOCK]); -#endif - -#if defined(AES_DEC_128_OTFK) -void aes_decrypt_128(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], - const unsigned char key[N_BLOCK], - unsigned char o_key[N_BLOCK]); -#endif - -#if defined(AES_ENC_256_OTFK) -void aes_encrypt_256(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], - const unsigned char key[2 * N_BLOCK], - unsigned char o_key[2 * N_BLOCK]); -#endif - -#if defined(AES_DEC_256_OTFK) -void aes_decrypt_256(const unsigned char in[N_BLOCK], - unsigned char out[N_BLOCK], - const unsigned char key[2 * N_BLOCK], - unsigned char o_key[2 * N_BLOCK]); -#endif - -#endif diff --git a/system/stack/crypto_toolbox/aes_cmac.cc b/system/stack/crypto_toolbox/aes_cmac.cc deleted file mode 100644 index c738a340979f49725139a8e413db42e27dc0dbe8..0000000000000000000000000000000000000000 --- a/system/stack/crypto_toolbox/aes_cmac.cc +++ /dev/null @@ -1,220 +0,0 @@ -/****************************************************************************** - * - * Copyright 2008-2012 Broadcom Corporation - * - * 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. - * - ******************************************************************************/ - -/****************************************************************************** - * - * This file contains the implementation of the AES128 and AES CMAC algorithm. - * - ******************************************************************************/ - -#include -#include - -#include "check.h" -#include "stack/crypto_toolbox/aes.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" -#include "stack/include/bt_octets.h" - -namespace crypto_toolbox { - -namespace { - -typedef struct { - uint8_t* text; - uint16_t len; - uint16_t round; -} tCMAC_CB; - -thread_local tCMAC_CB cmac_cb; - -/* Rb for AES-128 as block cipher, LSB as [0] */ -Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -/** utility function to do an biteise exclusive-OR of two bit strings of the - * length of OCTET16_LEN. Result is stored in first argument. - */ -static void xor_128(Octet16* a, const Octet16& b) { - CHECK(a); - uint8_t i, *aa = a->data(); - const uint8_t* bb = b.data(); - - for (i = 0; i < OCTET16_LEN; i++) { - aa[i] = aa[i] ^ bb[i]; - } -} -} // namespace - -/* This function computes AES_128(key, message) */ -Octet16 aes_128(const Octet16& key, const Octet16& message) { - Octet16 key_reversed; - Octet16 message_reversed; - Octet16 output; - - std::reverse_copy(key.begin(), key.end(), key_reversed.begin()); - std::reverse_copy(message.begin(), message.end(), message_reversed.begin()); - - aes_context ctx; - aes_set_key(key_reversed.data(), key_reversed.size(), &ctx); - aes_encrypt(message_reversed.data(), output.data(), &ctx); - - std::reverse(output.begin(), output.end()); - return output; -} - -/** utility function to padding the given text to be a 128 bits data. The - * parameter dest is input and output parameter, it must point to a - * OCTET16_LEN memory space; where include length bytes valid data. */ -static void padding(Octet16* dest, uint8_t length) { - uint8_t i, *p = dest->data(); - /* original last block */ - for (i = length; i < OCTET16_LEN; i++) - p[OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0; -} - -/** utility function to left shift one bit for a 128 bits value. */ -static void leftshift_onebit(uint8_t* input, uint8_t* output) { - uint8_t i, overflow = 0, next_overflow = 0; - DVLOG(2) << __func__; - /* input[0] is LSB */ - for (i = 0; i < OCTET16_LEN; i++) { - next_overflow = (input[i] & 0x80) ? 1 : 0; - output[i] = (input[i] << 1) | overflow; - overflow = next_overflow; - } - return; -} - -/** This function is the calculation of block cipher using AES-128. */ -static Octet16 cmac_aes_k_calculate(const Octet16& key) { - Octet16 output; - Octet16 x{0}; // zero initialized - - DVLOG(2) << __func__; - - uint16_t i = 1; - while (i <= cmac_cb.round) { - /* Mi' := Mi (+) X */ - xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], x); - - output = aes_128(key, &cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], - OCTET16_LEN); - x = output; - i++; - } - - return output; -} - -/** This function proceeed to prepare the last block of message Mn depending on - * the size of the message. - */ -static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) { - // uint8_t x[16] = {0}; - bool flag; - - DVLOG(2) << __func__; - /* last block is a complete block set flag to 1 */ - flag = ((cmac_cb.len % OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false; - - DVLOG(2) << "flag=" << flag << " round=" << cmac_cb.round; - - if (flag) { /* last block is complete block */ - xor_128((Octet16*)&cmac_cb.text[0], k1); - } else /* padding then xor with k2 */ - { - padding((Octet16*)&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16)); - - xor_128((Octet16*)&cmac_cb.text[0], k2); - } -} - -/** This is the function to generate the two subkeys. - * |key| is CMAC key, expect SRK when used by SMP. - */ -static void cmac_generate_subkey(const Octet16& key) { - DVLOG(2) << __func__; - - Octet16 zero{}; - Octet16 p = aes_128(key, zero.data(), OCTET16_LEN); - - Octet16 k1, k2; - uint8_t* pp = p.data(); - - /* If MSB(L) = 0, then K1 = L << 1 */ - if ((pp[OCTET16_LEN - 1] & 0x80) != 0) { - /* Else K1 = ( L << 1 ) (+) Rb */ - leftshift_onebit(pp, k1.data()); - xor_128(&k1, const_Rb); - } else { - leftshift_onebit(pp, k1.data()); - } - - if ((k1[OCTET16_LEN - 1] & 0x80) != 0) { - /* K2 = (K1 << 1) (+) Rb */ - leftshift_onebit(k1.data(), k2.data()); - xor_128(&k2, const_Rb); - } else { - /* If MSB(K1) = 0, then K2 = K1 << 1 */ - leftshift_onebit(k1.data(), k2.data()); - } - - cmac_prepare_last_block(k1, k2); -} - -/** key - CMAC key in little endian order - * input - text to be signed in little endian byte order. - * length - length of the input in byte. - */ -Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) { - uint32_t len; - uint16_t diff; - /* n is number of rounds */ - uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN; - - DVLOG(2) << __func__; - - if (n == 0) n = 1; - len = n * OCTET16_LEN; - - DVLOG(2) << "AES128_CMAC started, allocate buffer size=" << len; - /* allocate a memory space of multiple of 16 bytes to hold text */ - cmac_cb.text = (uint8_t*)alloca(len); - cmac_cb.round = n; - diff = len - length; - - if (input != NULL && length > 0) { - memcpy(&cmac_cb.text[diff], input, (int)length); - cmac_cb.len = length; - } else { - cmac_cb.len = 0; - } - - /* prepare calculation for subkey s and last block of data */ - cmac_generate_subkey(key); - /* start calculation */ - Octet16 signature = cmac_aes_k_calculate(key); - - /* clean up */ - memset(&cmac_cb, 0, sizeof(tCMAC_CB)); - // cmac_cb.text is auto-freed by alloca - - return signature; -} - -} // namespace crypto_toolbox diff --git a/system/stack/crypto_toolbox/crypto_toolbox.cc b/system/stack/crypto_toolbox/crypto_toolbox.cc deleted file mode 100644 index 45f816af53f316a04a87f0f54fcd31daca7df5d4..0000000000000000000000000000000000000000 --- a/system/stack/crypto_toolbox/crypto_toolbox.cc +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 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 "stack/crypto_toolbox/crypto_toolbox.h" - -#include -#include - -#include - -#include "stack/crypto_toolbox/aes.h" -#include "stack/include/bt_octets.h" - -using base::HexEncode; - -namespace crypto_toolbox { - -Octet16 h6(const Octet16& w, std::array keyid) { - return aes_cmac(w, keyid.data(), keyid.size()); -} - -Octet16 h7(const Octet16& salt, const Octet16& w) { - return aes_cmac(salt, w.data(), w.size()); -} - -Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z) { - constexpr size_t msg_len = BT_OCTET32_LEN /* U size */ + - BT_OCTET32_LEN /* V size */ + 1 /* Z size */; - - DVLOG(2) << "U=" << HexEncode(u, BT_OCTET32_LEN) - << ", V=" << HexEncode(v, BT_OCTET32_LEN) - << ", X=" << HexEncode(x.data(), x.size()) << ", Z=" << std::hex - << +z; - - std::array msg; - auto it = msg.begin(); - it = std::copy(&z, &z + 1, it); - it = std::copy(v, v + BT_OCTET32_LEN, it); - it = std::copy(u, u + BT_OCTET32_LEN, it); - return aes_cmac(x, msg.data(), msg.size()); -} - -/** helper for f5 */ -static Octet16 calculate_mac_key_or_ltk(const Octet16& t, uint8_t counter, - uint8_t* key_id, const Octet16& n1, - const Octet16& n2, uint8_t* a1, - uint8_t* a2, uint8_t* length) { - constexpr size_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ + - OCTET16_LEN /* N1 size */ + - OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ + - 7 /* A2 size*/ + 2 /* Length size */; - std::array msg; - auto it = msg.begin(); - it = std::copy(length, length + 2, it); - it = std::copy(a2, a2 + 7, it); - it = std::copy(a1, a1 + 7, it); - it = std::copy(n2.begin(), n2.end(), it); - it = std::copy(n1.begin(), n1.end(), it); - it = std::copy(key_id, key_id + 4, it); - it = std::copy(&counter, &counter + 1, it); - - return aes_cmac(t, msg.data(), msg.size()); -} - -void f5(const uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, - uint8_t* a2, Octet16* mac_key, Octet16* ltk) { - DVLOG(2) << __func__ << "W=" << HexEncode(w, BT_OCTET32_LEN) - << ", N1=" << HexEncode(n1.data(), n1.size()) - << ", N2=" << HexEncode(n2.data(), n2.size()) - << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2, 7); - - const Octet16 salt{0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60, - 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C}; - Octet16 t = aes_cmac(salt, w, BT_OCTET32_LEN); - - DVLOG(2) << "T=" << HexEncode(t.data(), t.size()); - - uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62}; /* 0x62746c65 */ - uint8_t length[2] = {0x00, 0x01}; /* 0x0100 */ - - *mac_key = calculate_mac_key_or_ltk(t, 0, key_id, n1, n2, a1, a2, length); - - *ltk = calculate_mac_key_or_ltk(t, 1, key_id, n1, n2, a1, a2, length); - - DVLOG(2) << "mac_key=" << HexEncode(mac_key->data(), mac_key->size()); - DVLOG(2) << "ltk=" << HexEncode(ltk->data(), ltk->size()); -} - -Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2, - const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2) { - const uint8_t msg_len = OCTET16_LEN /* N1 size */ + - OCTET16_LEN /* N2 size */ + OCTET16_LEN /* R size */ + - 3 /* IOcap size */ + 7 /* A1 size*/ - + 7 /* A2 size*/; - - DVLOG(2) << __func__ << "W=" << HexEncode(w.data(), w.size()) - << ", N1=" << HexEncode(n1.data(), n1.size()) - << ", N2=" << HexEncode(n2.data(), n2.size()) - << ", R=" << HexEncode(r.data(), r.size()) - << ", IOcap=" << HexEncode(iocap, 3) << ", A1=" << HexEncode(a1, 7) - << ", A2=" << HexEncode(a2, 7); - - std::array msg; - auto it = msg.begin(); - it = std::copy(a2, a2 + 7, it); - it = std::copy(a1, a1 + 7, it); - it = std::copy(iocap, iocap + 3, it); - it = std::copy(r.begin(), r.end(), it); - it = std::copy(n2.begin(), n2.end(), it); - it = std::copy(n1.begin(), n1.end(), it); - - return aes_cmac(w, msg.data(), msg.size()); -} - -uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x, - const Octet16& y) { - constexpr size_t msg_len = BT_OCTET32_LEN /* U size */ + - BT_OCTET32_LEN /* V size */ - + OCTET16_LEN /* Y size */; - - DVLOG(2) << __func__ << "U=" << HexEncode(u, BT_OCTET32_LEN) - << ", V=" << HexEncode(v, BT_OCTET32_LEN) - << ", X=" << HexEncode(x.data(), x.size()) - << ", Y=" << HexEncode(y.data(), y.size()); - - std::array msg; - auto it = msg.begin(); - it = std::copy(y.begin(), y.end(), it); - it = std::copy(v, v + BT_OCTET32_LEN, it); - it = std::copy(u, u + BT_OCTET32_LEN, it); - - Octet16 cmac = aes_cmac(x, msg.data(), msg.size()); - - /* vres = cmac mod 2**32 mod 10**6 */ - uint32_t vres; - uint8_t* p = cmac.data(); - STREAM_TO_UINT32(vres, p); - - vres = vres % 1000000; - return vres; -} - -Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7) { - Octet16 ilk; /* intermidiate link key */ - if (use_h7) { - constexpr Octet16 salt{0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - ilk = h7(salt, ltk); - } else { - /* "tmp1" mapping to extended ASCII, little endian*/ - constexpr std::array keyID_tmp1 = {0x31, 0x70, 0x6D, 0x74}; - ilk = h6(ltk, keyID_tmp1); - } - - /* "lebr" mapping to extended ASCII, little endian */ - constexpr std::array keyID_lebr = {0x72, 0x62, 0x65, 0x6c}; - return h6(ilk, keyID_lebr); -} - -Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7) { - Octet16 iltk; /* intermidiate long term key */ - if (use_h7) { - constexpr Octet16 salt{0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - iltk = h7(salt, link_key); - } else { - /* "tmp2" mapping to extended ASCII, little endian */ - constexpr std::array keyID_tmp2 = {0x32, 0x70, 0x6D, 0x74}; - iltk = h6(link_key, keyID_tmp2); - } - - /* "brle" mapping to extended ASCII, little endian */ - constexpr std::array keyID_brle = {0x65, 0x6c, 0x72, 0x62}; - return h6(iltk, keyID_brle); -} - -} // namespace crypto_toolbox diff --git a/system/stack/crypto_toolbox/crypto_toolbox.h b/system/stack/crypto_toolbox/crypto_toolbox.h deleted file mode 100644 index 08a3b9015b34c9cac7bfba9cbc13cdaf07fcaeb8..0000000000000000000000000000000000000000 --- a/system/stack/crypto_toolbox/crypto_toolbox.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 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 - -#include "check.h" -#include "stack/include/bt_octets.h" -#include "stack/include/bt_types.h" - -namespace crypto_toolbox { - -Octet16 aes_128(const Octet16& key, const Octet16& message); -Octet16 aes_cmac(const Octet16& key, const uint8_t* message, uint16_t length); -Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z); -void f5(const uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, - uint8_t* a2, Octet16* mac_key, Octet16* ltk); -Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2, - const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2); -Octet16 h6(const Octet16& w, std::array keyid); -Octet16 h7(const Octet16& salt, const Octet16& w); -uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x, - const Octet16& y); -Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7); -Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7); - -/* This function computes AES_128(key, message). |key| must be 128bit. - * |message| can be at most 16 bytes long, it's length in bytes is given in - * |length| */ -inline Octet16 aes_128(const Octet16& key, const uint8_t* message, - const uint8_t length) { - CHECK(length <= OCTET16_LEN) << "you tried aes_128 more than 16 bytes!"; - Octet16 msg{0}; - std::copy(message, message + length, msg.begin()); - return aes_128(key, msg); -} - -// |tlen| - lenth of mac desired -// |p_signature| - data pointer to where signed data to be stored, tlen long. -inline void aes_cmac(const Octet16& key, const uint8_t* message, - uint16_t length, uint16_t tlen, uint8_t* p_signature) { - Octet16 signature = aes_cmac(key, message, length); - - uint8_t* p_mac = signature.data() + (OCTET16_LEN - tlen); - memcpy(p_signature, p_mac, tlen); -} - -inline Octet16 aes_cmac(const Octet16& key, const Octet16& message) { - return aes_cmac(key, message.data(), message.size()); -} - -} // namespace crypto_toolbox diff --git a/system/stack/eatt/eatt.cc b/system/stack/eatt/eatt.cc index 8e88be96bcbe193b940110b9a8d439a8db8a5af2..9bd17d8a66545553723f10396a61f65c2ad97321 100644 --- a/system/stack/eatt/eatt.cc +++ b/system/stack/eatt/eatt.cc @@ -15,13 +15,13 @@ * limitations under the License. */ +#include + #include "eatt_impl.h" #include "stack/include/bt_hdr.h" -#include "stack/l2cap/l2c_int.h" +#include "stack/include/bt_psm_types.h" #include "types/raw_address.h" -#include - using bluetooth::eatt::eatt_impl; namespace bluetooth { diff --git a/system/stack/eatt/eatt_impl.h b/system/stack/eatt/eatt_impl.h index ad7592f88b3dc31e0d6037da8b80cbf372bc6a37..240ac7e57bedc52adab912ada3c3b703e127e86d 100644 --- a/system/stack/eatt/eatt_impl.h +++ b/system/stack/eatt/eatt_impl.h @@ -18,24 +18,21 @@ #include #include -#include -#include "acl_api.h" #include "bind_helpers.h" #include "device/include/controller.h" #include "eatt.h" -#include "gd/common/init_flags.h" -#include "gd/common/strings.h" #include "internal_include/stack_config.h" #include "l2c_api.h" +#include "os/log.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "stack/btm/btm_sec.h" +#include "stack/include/btm_sec_api.h" #include "stack/gatt/gatt_int.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" // do_in_main_thread -#include "stack/l2cap/l2c_int.h" -#include "types/raw_address.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/main_thread.h" namespace bluetooth { namespace eatt { @@ -827,7 +824,7 @@ struct eatt_impl { std::vector cids = {cid}; - tL2CAP_LE_CFG_INFO cfg = {.mps = eatt_dev->rx_mps_, .mtu = new_mtu}; + tL2CAP_LE_CFG_INFO cfg = {.mtu = new_mtu, .mps = eatt_dev->rx_mps_}; if (!L2CA_ReconfigCreditBasedConnsReq(eatt_dev->bda_, cids, &cfg)) { LOG(ERROR) << __func__ << "Could not start reconfig cid: " << loghex(cid) @@ -867,7 +864,7 @@ struct eatt_impl { return; } - tL2CAP_LE_CFG_INFO cfg = {.mps = eatt_dev->rx_mps_, .mtu = new_mtu}; + tL2CAP_LE_CFG_INFO cfg = {.mtu = new_mtu, .mps = eatt_dev->rx_mps_}; if (!L2CA_ReconfigCreditBasedConnsReq(eatt_dev->bda_, cids, &cfg)) { LOG(ERROR) << __func__ << "Could not start reconfig for device " diff --git a/system/stack/fuzzers/README.md b/system/stack/fuzzers/README.md new file mode 100644 index 0000000000000000000000000000000000000000..35a33835ef353e40d291a305c89402978cb265ae --- /dev/null +++ b/system/stack/fuzzers/README.md @@ -0,0 +1,95 @@ +# Bluetooth Stack Fuzzers + +## Overview +Bluetooth stack implements very complex wireless communication protocols and +scenarios. It's been a hotspot for security researchers and attackers. Fuzzing +has been used as a popular approach to look for security vulnerabilities in +Bluetooth stack. + +Due to the complex architecture of the Android Bluetooth stack, fuzzing the +entire stack with pure software is very difficult and impractical. Instead, +multiple fuzzers are created to target different areas of the BT stack. Fuzzers +in this directory focuses on the components under `system/stack`. + +## Attack surface selection +For security purpose, remote attack surfaces usually take higher priority since +they can cause much severe damage comparing to local attacks. This makes the +incoming BT message handlers our focus. The goal is to be able to pipe randomly +generated data packets to those message handlers to explore the code path each +component contains. This helps flushing out any memory/logic issues in the +remote message handling routine. + +Components requiring no authentication, or dealing with messages before +authentication have a higher fuzzing priority. This includes the SDP, GATT, SMP +and L2CAP components. A couple post authentication components such as BNEP, +AVRC, AVCT are also covered by different fuzzers. + +## Bluetooth stack overview +According to Bluetooth spec and the source code, most of the components we care +here work above the L2CAP layer. In general they work with the following +sequences: +1. At initialization, a component registers itself to L2CAP with a set of +callback functions, which, usually contains at least one function handling the +incoming Bluetooth packets. +2. Each component also exposes certain APIs to upper layers, which can be higher +level Bluetooth framework, or even applications. Bluetooth framework or +applications use these APIs to configure the stack, and issue requests. +3. Upper layer also registers callbacks into each component. When a component +receives a response, it parses and validates the response, extracts the payload +data, and passes data to upper layer using those callbacks. +4. Many Bluetooth components work in both server mode and client mode with +different sets of APIs and processing logics. +5. It's common for a Bluetooth stack component to use state machines. The state +transition happens when APIs are called, or incoming packets are handled. + +## Fuzzer design +The fuzzers are designed to simulate how a component is used in the real world, +but with a lot of simplifications. Here is how they work in general: +1. First a fuzzer should mock the L2CAP APIs to capture the registration call +from the target component. +2. At each fuzzing iteration, the fuzzer initializes the target component using +its initialization function. This will cause the component to register itself to +L2CAP. Because L2CAP APIs are mocked, the fuzzer will capture the registration +information, most importantly, the message handler callback function. +3. The fuzzer then calls necessary APIs and callbacks exposed to L2CAP to +further initialize the target component into either server mode or client mode. +4. Starting from here, the fuzzer splits the input data into multiple packets, +and feeds them to the target component using the previously captured message +handler callback. +5. It's common that a fuzzer also needs to call certain APIs to trigger state +transition of the target component. The fuzzer might use fixed data or data +derived from fuzzing input to make those API calls. +6. Once all the data is consumed, the target is cleaned up so next iteration can +start cleanly. It's important to cleanup all the data so there is no state +pollution between two iterations, otherwise it will be very difficult to +reproduce a crash. + +## Mocking dependencies +For maximium fuzzing efficiency, the fuzzers are created to include the target +component and minimium number of other Bluetooth components. This means any +dependencies from other Bluetooth components need to be mocked. The mocks are +implemented with a balance of reaching maximium target code coverage and +minimium development effort. Some of the mocks are simply not implemented. + +## Future improvement +These fuzzers are still far from perfect, with the following possible +improvements: +1. Code coverage + + It's very important to review the code coverage of each fuzzer. Any big + coverage gaps should be analyzed and improved. This can be done by adding + additional logic in the fuzzing loop, such as calling certain APIs, + providing upper layer callbacks, or changing the mock behaviors. + +2. Performance + + The fuzzers are designed to run as fast as possible. But there might still + be some room to improve the performance. Profiling can be done to figure + out the performance bottlenecks, which might be sleeps, tight for loops, or + computational heavy operations, such as crypto functions. + +3. Component coverage + + Currently only 3 fuzzers are created. More should be added so we can cover + most of the stack components. With the mocks and design patterns it + shouldn't be too difficult. diff --git a/system/stack/fuzzers/avrc_fuzzer.cc b/system/stack/fuzzers/avrc_fuzzer.cc new file mode 100644 index 0000000000000000000000000000000000000000..70743e9cc7009384709682e54623b536c9159155 --- /dev/null +++ b/system/stack/fuzzers/avrc_fuzzer.cc @@ -0,0 +1,221 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include + +#include "osi/include/allocator.h" +#include "stack/include/avct_api.h" +#include "stack/include/avrc_api.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" + +using bluetooth::Uuid; + +// Verify the passed data is readable +static void ConsumeData(const uint8_t* data, size_t size) { + volatile uint8_t checksum = 0; + for (size_t i = 0; i < size; i++) { + checksum ^= data[i]; + } +} + +namespace { + +constexpr uint16_t kDummyCid = 0x1234; +constexpr uint8_t kDummyId = 0x77; +constexpr uint8_t kDummyRemoteAddr[] = {0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC}; + +// Set up default callback structure +static tL2CAP_APPL_INFO avct_appl, avct_br_appl; + +class FakeBtStack { + public: + FakeBtStack() { + test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t cid, + BT_HDR* hdr) { + CHECK(cid == kDummyCid); + ConsumeData((const uint8_t*)hdr, hdr->offset + hdr->len); + osi_free(hdr); + return L2CAP_DW_SUCCESS; + }; + test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t cid) { + CHECK(cid == kDummyCid); + return true; + }; + test::mock::stack_l2cap_api::L2CA_ConnectReq2.body = + [](uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level) { + CHECK(p_bd_addr == kDummyRemoteAddr); + return kDummyCid; + }; + test::mock::stack_l2cap_api::L2CA_Register2.body = + [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop, + tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, + uint16_t required_remote_mtu, uint16_t sec_level) { + CHECK(psm == AVCT_PSM || psm == AVCT_BR_PSM); + if (psm == AVCT_PSM) { + avct_appl = p_cb_info; + } else if (psm == AVCT_BR_PSM) { + avct_br_appl = p_cb_info; + } + return psm; + }; + test::mock::stack_l2cap_api::L2CA_Deregister.body = [](uint16_t psm) {}; + } + + ~FakeBtStack() { + test::mock::stack_l2cap_api::L2CA_DataWrite = {}; + test::mock::stack_l2cap_api::L2CA_ConnectReq2 = {}; + test::mock::stack_l2cap_api::L2CA_DisconnectReq = {}; + test::mock::stack_l2cap_api::L2CA_Register2 = {}; + test::mock::stack_l2cap_api::L2CA_Deregister = {}; + } +}; + +class Fakes { + public: + test::fake::FakeOsi fake_osi; + FakeBtStack fake_stack; +}; + +} // namespace + +#ifdef __ANDROID__ +namespace android { +namespace sysprop { +namespace bluetooth { +namespace Avrcp { +std::optional absolute_volume() { return true; } +} // namespace Avrcp + +namespace Bta { +std::optional disable_delay() { return 200; } +} // namespace Bta + +namespace Pan { +std::optional nap() { return false; } +} // namespace Pan +} // namespace bluetooth +} // namespace sysprop +} // namespace android +#endif + +static void ctrl_cb(uint8_t handle, uint8_t event, uint16_t result, + const RawAddress* peer_addr) {} + +static void msg_cb(uint8_t handle, uint8_t label, uint8_t opcode, + tAVRC_MSG* p_msg) { + uint8_t scratch_buf[512]; + tAVRC_STS status; + + if (p_msg->hdr.ctype == AVCT_CMD) { + tAVRC_COMMAND cmd = {0}; + memset(scratch_buf, 0, sizeof(scratch_buf)); + status = AVRC_ParsCommand(p_msg, &cmd, scratch_buf, sizeof(scratch_buf)); + if (status == AVRC_STS_NO_ERROR) { + BT_HDR* p_pkt = (BT_HDR*)nullptr; + status = AVRC_BldCommand(&cmd, &p_pkt); + if (status == AVRC_STS_NO_ERROR && p_pkt) { + osi_free(p_pkt); + } + } + } else if (p_msg->hdr.ctype == AVCT_RSP) { + tAVRC_RESPONSE rsp = {0}; + memset(scratch_buf, 0, sizeof(scratch_buf)); + status = AVRC_ParsResponse(p_msg, &rsp, scratch_buf, sizeof(scratch_buf)); + if (status == AVRC_STS_NO_ERROR) { + BT_HDR* p_pkt = (BT_HDR*)nullptr; + status = AVRC_BldResponse(handle, &rsp, &p_pkt); + if (status == AVRC_STS_NO_ERROR && p_pkt) { + osi_free(p_pkt); + } + } + + uint16_t buf_len = sizeof(scratch_buf); + memset(scratch_buf, 0, sizeof(scratch_buf)); + status = AVRC_Ctrl_ParsResponse(p_msg, &rsp, scratch_buf, &buf_len); + if (status == AVRC_STS_NO_ERROR) { + BT_HDR* p_pkt = (BT_HDR*)nullptr; + status = AVRC_BldResponse(handle, &rsp, &p_pkt); + if (status == AVRC_STS_NO_ERROR && p_pkt) { + osi_free(p_pkt); + } + } + } +} + +static void Fuzz(const uint8_t* data, size_t size) { + FuzzedDataProvider fdp(data, size); + bool is_initiator = fdp.ConsumeBool(); + bool is_controller = fdp.ConsumeBool(); + bool is_br = fdp.ConsumeBool(); + + AVCT_Register(); + AVRC_Init(); + + tL2CAP_APPL_INFO* appl_info = is_br ? &avct_br_appl : &avct_appl; + + 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), + .control = (uint8_t)(is_controller ? AVCT_CONTROL : AVCT_TARGET), + }; + + appl_info->pL2CA_ConnectInd_Cb(kDummyRemoteAddr, kDummyCid, 0, kDummyId); + + uint8_t handle; + if (AVCT_SUCCESS != AVRC_Open(&handle, &ccb, kDummyRemoteAddr)) { + return; + } + + tL2CAP_CFG_INFO cfg; + appl_info->pL2CA_ConfigCfm_Cb(kDummyCid, is_initiator, &cfg); + + // Feeding input packets + constexpr uint16_t kMaxPacketSize = 1024; + while (fdp.remaining_bytes() > 0) { + auto size = fdp.ConsumeIntegralInRange(0, kMaxPacketSize); + auto bytes = fdp.ConsumeBytes(size); + BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size()); + hdr->len = bytes.size(); + std::copy(bytes.cbegin(), bytes.cend(), hdr->data); + appl_info->pL2CA_DataInd_Cb(kDummyCid, hdr); + } + + AVRC_Close(handle); + + // Simulating disconnecting event + appl_info->pL2CA_DisconnectInd_Cb(kDummyCid, false); + + AVCT_Deregister(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + auto fakes = std::make_unique(); + Fuzz(Data, Size); + return 0; +} diff --git a/system/stack/fuzzers/bnep_fuzzer.cc b/system/stack/fuzzers/bnep_fuzzer.cc new file mode 100644 index 0000000000000000000000000000000000000000..f4da8de8eceda2e4642401dbef46c4b312bc5416 --- /dev/null +++ b/system/stack/fuzzers/bnep_fuzzer.cc @@ -0,0 +1,173 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +#include "osi/include/allocator.h" +#include "stack/include/bnep_api.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" + +using bluetooth::Uuid; + +namespace { + +constexpr uint16_t kDummyCid = 0x1234; +constexpr uint8_t kDummyId = 0x77; +constexpr uint8_t kDummyRemoteAddr[] = {0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC}; +constexpr uint8_t kDummySrcUuid[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, + 0xcc, 0xdd, 0xee, 0xff}; +constexpr uint8_t kDummyDstUuid[] = {0x00, 0x00, 0x00, 0x00, 0x22, 0x22, + 0x22, 0x22, 0x33, 0x33, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x59}; + +// Set up default callback structure +static tL2CAP_APPL_INFO appl_info; + +class FakeBtStack { + public: + FakeBtStack() { + test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t cid, + BT_HDR* p_data) { + CHECK(cid == kDummyCid); + osi_free(p_data); + return L2CAP_DW_SUCCESS; + }; + test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t cid) { + CHECK(cid == kDummyCid); + return true; + }; + test::mock::stack_l2cap_api::L2CA_ConnectReq2.body = + [](uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level) { + CHECK(p_bd_addr == kDummyRemoteAddr); + return kDummyCid; + }; + test::mock::stack_l2cap_api::L2CA_Register2.body = + [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop, + tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, + uint16_t required_remote_mtu, uint16_t sec_level) { + appl_info = p_cb_info; + return psm; + }; + test::mock::stack_l2cap_api::L2CA_Deregister.body = [](uint16_t psm) {}; + } + + ~FakeBtStack() { + test::mock::stack_l2cap_api::L2CA_DataWrite = {}; + test::mock::stack_l2cap_api::L2CA_ConnectReq2 = {}; + test::mock::stack_l2cap_api::L2CA_DisconnectReq = {}; + test::mock::stack_l2cap_api::L2CA_Register2 = {}; + test::mock::stack_l2cap_api::L2CA_Deregister = {}; + } +}; + +class Fakes { + public: + test::fake::FakeOsi fake_osi; + FakeBtStack fake_stack; +}; + +} // namespace + +// Verify the passed data is readable +static void ConsumeData(const uint8_t* data, size_t size) { + volatile uint8_t checksum = 0; + for (size_t i = 0; i < size; i++) { + checksum ^= data[i]; + } +} + +static void Fuzz(const uint8_t* data, size_t size) { + tBNEP_REGISTER reg = { + .p_conn_ind_cb = + [](uint16_t handle, const RawAddress& bd_addr, + const bluetooth::Uuid& remote_uuid, + const bluetooth::Uuid& local_uuid, + bool is_role_change) { BNEP_ConnectResp(handle, BNEP_SUCCESS); }, + .p_conn_state_cb = [](uint16_t handle, const RawAddress& rem_bda, + tBNEP_RESULT result, bool is_role_change) {}, + .p_data_ind_cb = [](uint16_t handle, const RawAddress& src, + const RawAddress& dst, uint16_t protocol, + uint8_t* p_data, uint16_t len, + bool fw_ext_present) { ConsumeData(p_data, len); }, + .p_tx_data_flow_cb = [](uint16_t handle, tBNEP_RESULT event) {}, + .p_filter_ind_cb = + [](uint16_t handle, bool indication, tBNEP_RESULT result, + uint16_t num_filters, + uint8_t* p_filters) { ConsumeData(p_filters, num_filters); }, + .p_mfilter_ind_cb = + [](uint16_t handle, bool indication, tBNEP_RESULT result, + uint16_t num_mfilters, + uint8_t* p_mfilters) { ConsumeData(p_mfilters, num_mfilters); }, + }; + + BNEP_Init(); + if (BNEP_SUCCESS != BNEP_Register(®)) { + return; + } + + FuzzedDataProvider fdp(data, size); + bool is_server = fdp.ConsumeBool(); + if (is_server) { + // Simulating an inbound connection event + appl_info.pL2CA_ConnectInd_Cb(kDummyRemoteAddr, kDummyCid, 0, kDummyId); + } else { + // Initiating an outbound connection + uint16_t handle; + BNEP_Connect(kDummyRemoteAddr, Uuid::From128BitBE(kDummySrcUuid), + Uuid::From128BitBE(kDummyDstUuid), &handle, 0); + + // Simulating outbound connection confirm event + appl_info.pL2CA_ConnectCfm_Cb(kDummyCid, L2CAP_CONN_OK); + } + + // Simulating configuration confirmation event + tL2CAP_CFG_INFO cfg = {}; + appl_info.pL2CA_ConfigCfm_Cb(kDummyCid, 0, &cfg); + + // Feeding input packets + constexpr uint16_t kMaxPacketSize = 1024; + while (fdp.remaining_bytes() > 0) { + auto size = fdp.ConsumeIntegralInRange(0, kMaxPacketSize); + auto bytes = fdp.ConsumeBytes(size); + BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size()); + hdr->len = bytes.size(); + std::copy(bytes.cbegin(), bytes.cend(), hdr->data); + appl_info.pL2CA_DataInd_Cb(kDummyCid, hdr); + } + + // Simulating disconnecting event + appl_info.pL2CA_DisconnectInd_Cb(kDummyCid, false); + + BNEP_Deregister(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + auto fakes = std::make_unique(); + Fuzz(Data, Size); + return 0; +} diff --git a/system/stack/fuzzers/gatt_fuzzer.cc b/system/stack/fuzzers/gatt_fuzzer.cc new file mode 100644 index 0000000000000000000000000000000000000000..6444e5a870efa41d10ca0d61f35f2a612b7eee24 --- /dev/null +++ b/system/stack/fuzzers/gatt_fuzzer.cc @@ -0,0 +1,304 @@ +#include +#include + +#include +#include + +#include "osi/include/allocator.h" +#include "stack/include/bt_hdr.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/gatt_api.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" + +using bluetooth::Uuid; +bt_status_t do_in_main_thread(base::Location const&, + base::OnceCallback) { + // this is not properly mocked, so we use abort to catch if this is used in + // any test cases + abort(); +} +bt_status_t do_in_main_thread_delayed(base::Location const&, + base::OnceCallback, + base::TimeDelta const&) { + // this is not properly mocked, so we use abort to catch if this is used in + // any test cases + abort(); +} + +namespace bluetooth { +namespace os { +bool GetSystemPropertyBool(const std::string& property, bool default_value) { + return default_value; +} +} // namespace os +} // namespace bluetooth + +constexpr uint8_t kDummyAddr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; +constexpr uint16_t kMaxPacketSize = 1024; +namespace { + +tL2CAP_FIXED_CHNL_REG fixed_chnl_reg; +tL2CAP_APPL_INFO appl_info; +tBTM_SEC_DEV_REC btm_sec_dev_rec; + +class FakeBtStack { + public: + FakeBtStack() { + test::mock::stack_btm_dev::btm_find_dev.body = [](const RawAddress&) { + return &btm_sec_dev_rec; + }; + + test::mock::stack_l2cap_ble::L2CA_GetBleConnRole.body = + [](const RawAddress&) { return HCI_ROLE_CENTRAL; }; + + test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr.body = + [](const RawAddress&, uint16_t, uint8_t) { return true; }; + test::mock::stack_l2cap_api::L2CA_RemoveFixedChnl.body = + [](uint16_t lcid, const RawAddress&) { + CHECK(lcid == L2CAP_ATT_CID); + return true; + }; + test::mock::stack_l2cap_api::L2CA_ConnectFixedChnl.body = + [](uint16_t, const RawAddress&) { return true; }; + test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t lcid, + BT_HDR* hdr) { + osi_free(hdr); + return L2CAP_DW_SUCCESS; + }; + test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t) { + return true; + }; + test::mock::stack_l2cap_api::L2CA_SendFixedChnlData.body = + [](uint16_t cid, const RawAddress& addr, BT_HDR* hdr) { + osi_free(hdr); + return L2CAP_DW_SUCCESS; + }; + test::mock::stack_l2cap_api::L2CA_RegisterFixedChannel.body = + [](uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg) { + fixed_chnl_reg = *p_freg; + return true; + }; + test::mock::stack_l2cap_api::L2CA_Register2.body = + [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop, + tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, + uint16_t required_remote_mtu, uint16_t sec_level) { + appl_info = p_cb_info; + return psm; + }; + test::mock::stack_l2cap_api::L2CA_RegisterLECoc.body = + [](uint16_t psm, const tL2CAP_APPL_INFO& p_fixed_chnl_reg, + uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) { return psm; }; + + test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr.body = + [](const RawAddress&, uint16_t, uint8_t) { return true; }; + test::mock::stack_l2cap_api::L2CA_SetLeGattTimeout.body = + [](const RawAddress&, uint16_t) { return true; }; + } + + ~FakeBtStack() { + test::mock::stack_btm_dev::btm_find_dev = {}; + + test::mock::stack_l2cap_ble::L2CA_GetBleConnRole = {}; + + test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr = {}; + test::mock::stack_l2cap_api::L2CA_RemoveFixedChnl = {}; + test::mock::stack_l2cap_api::L2CA_ConnectFixedChnl = {}; + test::mock::stack_l2cap_api::L2CA_DisconnectReq = {}; + test::mock::stack_l2cap_api::L2CA_SendFixedChnlData = {}; + test::mock::stack_l2cap_api::L2CA_RegisterFixedChannel = {}; + test::mock::stack_l2cap_api::L2CA_Register2 = {}; + test::mock::stack_l2cap_api::L2CA_RegisterLECoc = {}; + test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr = {}; + test::mock::stack_l2cap_api::L2CA_SetLeGattTimeout = {}; + } +}; + +class Fakes { + public: + test::fake::FakeOsi fake_osi; + FakeBtStack fake_stack; +}; + +} // namespace + +static uint16_t s_ConnId; +static tGATT_IF s_AppIf; + +static void GattInit() { + s_ConnId = 0; + s_AppIf = 0; + + gatt_init(); + + /* Fill our internal UUID with a fixed pattern 0x82 */ + std::array tmp; + tmp.fill(0x82); + Uuid app_uuid = Uuid::From128BitBE(tmp); + + tGATT_CBACK gap_cback = { + .p_conn_cb = [](tGATT_IF, const RawAddress&, uint16_t conn_id, + bool connected, tGATT_DISCONN_REASON, + tBT_TRANSPORT) { s_ConnId = conn_id; }, + .p_cmpl_cb = [](uint16_t, tGATTC_OPTYPE, tGATT_STATUS, + tGATT_CL_COMPLETE*) {}, + .p_disc_res_cb = nullptr, + .p_disc_cmpl_cb = nullptr, + .p_req_cb = [](uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type, + tGATTS_DATA* p_data) {}, + .p_enc_cmpl_cb = nullptr, + .p_congestion_cb = nullptr, + .p_phy_update_cb = nullptr, + .p_conn_update_cb = nullptr, + .p_subrate_chg_cb = nullptr, + }; + + s_AppIf = GATT_Register(app_uuid, "Gap", &gap_cback, false); + GATT_StartIf(s_AppIf); +} + +static void ServerInit() { + GattInit(); + + tGATT_APPL_INFO appl_info = { + .p_nv_save_callback = [](bool, tGATTS_HNDL_RANGE*) {}, + .p_srv_chg_callback = [](tGATTS_SRV_CHG_CMD, tGATTS_SRV_CHG_REQ*, + tGATTS_SRV_CHG_RSP*) { return true; }, + }; + GATTS_NVRegister(&appl_info); + + Uuid svc_uuid = Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER); + Uuid name_uuid = Uuid::From16Bit(GATT_UUID_GAP_DEVICE_NAME); + Uuid icon_uuid = Uuid::From16Bit(GATT_UUID_GAP_ICON); + Uuid addr_res_uuid = Uuid::From16Bit(GATT_UUID_GAP_CENTRAL_ADDR_RESOL); + + btgatt_db_element_t service[] = { + { + .uuid = svc_uuid, + .type = BTGATT_DB_PRIMARY_SERVICE, + }, + {.uuid = name_uuid, + .type = BTGATT_DB_CHARACTERISTIC, + .properties = GATT_CHAR_PROP_BIT_READ, + .permissions = GATT_PERM_READ_IF_ENCRYPTED_OR_DISCOVERABLE}, + {.uuid = icon_uuid, + .type = BTGATT_DB_CHARACTERISTIC, + .properties = GATT_CHAR_PROP_BIT_READ, + .permissions = GATT_PERM_READ}, + {.uuid = addr_res_uuid, + .type = BTGATT_DB_CHARACTERISTIC, + .properties = GATT_CHAR_PROP_BIT_READ, + .permissions = GATT_PERM_READ}}; + + /* Add a GAP service */ + GATTS_AddService(s_AppIf, service, + sizeof(service) / sizeof(btgatt_db_element_t)); +} + +static void ServerCleanup() { + GATT_Deregister(s_AppIf); + gatt_free(); +} + +static void FuzzAsServer(const uint8_t* data, size_t size) { + ServerInit(); + fixed_chnl_reg.pL2CA_FixedConn_Cb(L2CAP_ATT_CID, kDummyAddr, true, 0, + BT_TRANSPORT_LE); + + FuzzedDataProvider fdp(data, size); + while (fdp.remaining_bytes() > 0) { + auto size = fdp.ConsumeIntegralInRange(0, kMaxPacketSize); + auto bytes = fdp.ConsumeBytes(size); + BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size()); + hdr->len = bytes.size(); + std::copy(bytes.cbegin(), bytes.cend(), hdr->data); + fixed_chnl_reg.pL2CA_FixedData_Cb(L2CAP_ATT_CID, kDummyAddr, hdr); + } + + ServerCleanup(); +} + +static void ClientInit() { + GattInit(); + GATT_Connect(s_AppIf, kDummyAddr, BTM_BLE_DIRECT_CONNECTION, BT_TRANSPORT_LE, + false); +} + +static void ClientCleanup() { + GATT_CancelConnect(s_AppIf, kDummyAddr, true); + GATT_Deregister(s_AppIf); + gatt_free(); +} + +static void FuzzAsClient(const uint8_t* data, size_t size) { + ClientInit(); + fixed_chnl_reg.pL2CA_FixedConn_Cb(L2CAP_ATT_CID, kDummyAddr, true, 0, + BT_TRANSPORT_LE); + + FuzzedDataProvider fdp(data, size); + while (fdp.remaining_bytes() > 0) { + auto op = fdp.ConsumeIntegral(); + switch (op) { + case GATTC_OPTYPE_CONFIG: { + auto mtu = fdp.ConsumeIntegral(); + GATTC_ConfigureMTU(s_ConnId, mtu); + break; + } + case GATTC_OPTYPE_DISCOVERY: { + auto type = (tGATT_DISC_TYPE)fdp.ConsumeIntegralInRange( + 0, GATT_DISC_MAX); + uint16_t start = fdp.ConsumeIntegral(); + uint16_t end = fdp.ConsumeIntegral(); + GATTC_Discover(s_ConnId, type, start, end); + break; + } + case GATTC_OPTYPE_READ: { + auto type = (tGATT_READ_TYPE)fdp.ConsumeIntegralInRange( + 0, GATT_READ_MAX); + tGATT_READ_PARAM param = {}; + fdp.ConsumeData(¶m, sizeof(param)); + GATTC_Read(s_ConnId, type, ¶m); + break; + } + case GATTC_OPTYPE_WRITE: { + auto type = (tGATT_WRITE_TYPE)fdp.ConsumeIntegralInRange( + 0, GATT_WRITE_PREPARE + 1); + tGATT_VALUE value = {}; + value.len = + fdp.ConsumeIntegralInRange(0, sizeof(value.value)); + value.len = fdp.ConsumeData(&value.value, value.len); + GATTC_Write(s_ConnId, type, &value); + break; + } + case GATTC_OPTYPE_EXE_WRITE: { + auto type = fdp.ConsumeBool(); + GATTC_ExecuteWrite(s_ConnId, type); + break; + } + default: + break; + } + auto size = fdp.ConsumeIntegralInRange(0, kMaxPacketSize); + auto bytes = fdp.ConsumeBytes(size); + BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size()); + hdr->len = bytes.size(); + std::copy(bytes.cbegin(), bytes.cend(), hdr->data); + fixed_chnl_reg.pL2CA_FixedData_Cb(L2CAP_ATT_CID, kDummyAddr, hdr); + } + + fixed_chnl_reg.pL2CA_FixedConn_Cb(L2CAP_ATT_CID, kDummyAddr, false, 0, + BT_TRANSPORT_LE); + ClientCleanup(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + auto fakes = std::make_unique(); + + FuzzAsServer(Data, Size); + FuzzAsClient(Data, Size); + return 0; +} diff --git a/system/stack/fuzzers/l2cap_fuzzer.cc b/system/stack/fuzzers/l2cap_fuzzer.cc new file mode 100644 index 0000000000000000000000000000000000000000..01d7d7de308807d3590abddb62c61d71ac84209e --- /dev/null +++ b/system/stack/fuzzers/l2cap_fuzzer.cc @@ -0,0 +1,252 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +#include "btif/include/stack_manager.h" +#include "gd/hal/snoop_logger.h" +#include "osi/include/allocator.h" +#include "stack/btm/btm_int_types.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/l2c_api.h" +#include "stack/include/l2cap_acl_interface.h" +#include "stack/include/l2cap_controller_interface.h" +#include "stack/include/l2cap_hci_link_interface.h" +#include "test/fake/fake_osi.h" +#include "test/mock/mock_device_controller.h" +#include "test/mock/mock_stack_acl.h" +#include "test/mock/mock_stack_btm_devctl.h" + +using bluetooth::Uuid; + +// Verify the passed data is readable +static void ConsumeData(const uint8_t* data, size_t size) { + volatile uint8_t checksum = 0; + for (size_t i = 0; i < size; i++) { + checksum ^= data[i]; + } +} + +tBTM_CB btm_cb; + +bt_status_t do_in_main_thread(base::Location const&, + base::OnceCallback) { + // this is not properly mocked, so we use abort to catch if this is used in + // any test cases + abort(); +} +bt_status_t do_in_main_thread_delayed(base::Location const&, + base::OnceCallback, + base::TimeDelta const&) { + // this is not properly mocked, so we use abort to catch if this is used in + // any test cases + abort(); +} + +namespace bluetooth { +namespace os { +uint32_t GetSystemPropertyUint32Base(const std::string& property, + uint32_t default_value, int base) { + return default_value; +} +} // namespace os + +namespace hal { +class SnoopLogger; + +const std::string SnoopLogger::kBtSnoopLogModeFiltered = "filtered"; + +std::string SnoopLogger::GetBtSnoopMode() { return "filtered"; } +void SnoopLogger::AcceptlistL2capChannel(uint16_t, uint16_t, uint16_t) {} +void SnoopLogger::AddA2dpMediaChannel(uint16_t, uint16_t, uint16_t) {} +void SnoopLogger::AddRfcommL2capChannel(uint16_t, uint16_t, uint16_t) {} +void SnoopLogger::ClearL2capAcceptlist(uint16_t, uint16_t, uint16_t) {} +void SnoopLogger::RemoveA2dpMediaChannel(uint16_t, uint16_t) {} +void SnoopLogger::SetL2capChannelClose(uint16_t, uint16_t, uint16_t) {} +void SnoopLogger::SetL2capChannelOpen(uint16_t, uint16_t, uint16_t, uint16_t, + bool) {} +} // namespace hal +} // namespace bluetooth + +namespace { + +class FakeBtStack { + public: + FakeBtStack() { + test::mock::stack_btm_devctl::BTM_IsDeviceUp.body = []() { return true; }; + test::mock::stack_acl::acl_create_le_connection.body = + [](const RawAddress& bd_addr) { return true; }; + test::mock::stack_acl::acl_create_classic_connection.body = + [](const RawAddress& bd_addr, bool there_are_high_priority_channels, + bool is_bonding) { return true; }; + + test::mock::stack_acl::acl_send_data_packet_br_edr.body = + [](const RawAddress& bd_addr, BT_HDR* hdr) { + ConsumeData((const uint8_t*)hdr, hdr->offset + hdr->len); + osi_free(hdr); + }; + test::mock::stack_acl::acl_send_data_packet_ble.body = + [](const RawAddress& bd_addr, BT_HDR* hdr) { + ConsumeData((const uint8_t*)hdr, hdr->offset + hdr->len); + osi_free(hdr); + }; + + GetInterfaceToProfiles()->profileSpecific_HACK->GetHearingAidDeviceCount = + []() { return 1; }; + + test::mock::device_controller::ble_supported = true; + test::mock::device_controller::acl_data_size_classic = 512; + test::mock::device_controller::acl_data_size_ble = 512; + test::mock::device_controller::iso_data_size = 512; + test::mock::device_controller::ble_suggested_default_data_length = 512; + } + + ~FakeBtStack() { + test::mock::stack_btm_devctl::BTM_IsDeviceUp = {}; + test::mock::stack_acl::acl_create_le_connection = {}; + test::mock::stack_acl::acl_create_classic_connection = {}; + test::mock::stack_acl::acl_send_data_packet_br_edr = {}; + test::mock::stack_acl::acl_send_data_packet_ble = {}; + } +}; + +class Fakes { + public: + test::fake::FakeOsi fake_osi; + FakeBtStack fake_stack; +}; + +} // namespace + +constexpr uint8_t kAttAddr[] = {0x11, 0x78, 0x78, 0x78, 0x78, 0x78}; +constexpr uint16_t kAttHndl = 0x0111; + +constexpr uint8_t kEattAddr[] = {0x22, 0x78, 0x78, 0x78, 0x78, 0x78}; + +constexpr uint8_t kSmpBrAddr[] = {0x33, 0x78, 0x78, 0x78, 0x78, 0x78}; +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)); + + l2c_init(); + + l2c_link_init(kNumClassicAclBuffer); + l2c_link_processs_ble_num_bufs(kNumLeAclBuffer); + + tL2CAP_FIXED_CHNL_REG reg = { + .pL2CA_FixedConn_Cb = [](uint16_t, const RawAddress&, bool, uint16_t, + tBT_TRANSPORT) {}, + .pL2CA_FixedData_Cb = + [](uint16_t, const RawAddress&, BT_HDR* hdr) { + ConsumeData((const uint8_t*)hdr, hdr->offset + hdr->len); + }, + .pL2CA_FixedCong_Cb = [](const RawAddress&, bool) {}, + .default_idle_tout = 1000, + }; + + tL2CAP_APPL_INFO appl_info = { + .pL2CA_ConnectInd_Cb = [](const RawAddress&, uint16_t, uint16_t, + uint8_t) {}, + .pL2CA_ConnectCfm_Cb = [](uint16_t, uint16_t) {}, + .pL2CA_ConfigInd_Cb = [](uint16_t, tL2CAP_CFG_INFO*) {}, + .pL2CA_ConfigCfm_Cb = [](uint16_t, uint16_t, tL2CAP_CFG_INFO*) {}, + .pL2CA_DisconnectInd_Cb = [](uint16_t, bool) {}, + .pL2CA_DisconnectCfm_Cb = [](uint16_t, uint16_t) {}, + .pL2CA_DataInd_Cb = + [](uint16_t, BT_HDR* hdr) { + ConsumeData((const uint8_t*)hdr, hdr->offset + hdr->len); + }, + .pL2CA_CongestionStatus_Cb = [](uint16_t, bool) {}, + .pL2CA_TxComplete_Cb = [](uint16_t, uint16_t) {}, + .pL2CA_Error_Cb = [](uint16_t, uint16_t) {}, + .pL2CA_CreditBasedConnectInd_Cb = [](const RawAddress&, + std::vector&, uint16_t, + uint16_t, uint8_t) {}, + .pL2CA_CreditBasedConnectCfm_Cb = [](const RawAddress&, uint16_t, + uint16_t, uint16_t) {}, + .pL2CA_CreditBasedReconfigCompleted_Cb = [](const RawAddress&, uint16_t, + bool, tL2CAP_LE_CFG_INFO*) {}, + .pL2CA_CreditBasedCollisionInd_Cb = [](const RawAddress&) {}, + }; + CHECK(L2CA_Register2(BT_PSM_ATT, appl_info, false, nullptr, L2CAP_MTU_SIZE, 0, + BTM_SEC_NONE)); + CHECK(L2CA_RegisterLECoc(BT_PSM_EATT, appl_info, BTM_SEC_NONE, {})); + + CHECK(L2CA_RegisterFixedChannel(L2CAP_ATT_CID, ®)); + CHECK(L2CA_ConnectFixedChnl(L2CAP_ATT_CID, kAttAddr)); + CHECK(l2cble_conn_comp(kAttHndl, HCI_ROLE_CENTRAL, kAttAddr, BLE_ADDR_PUBLIC, + 100, 100, 100)); + + CHECK(L2CA_RegisterFixedChannel(L2CAP_SMP_BR_CID, ®)); + CHECK(L2CA_ConnectFixedChnl(L2CAP_SMP_BR_CID, kSmpBrAddr)); + l2c_link_hci_conn_comp(HCI_SUCCESS, kSmpBrHndl, kSmpBrAddr); + + auto att_cid = L2CA_ConnectReq(BT_PSM_ATT, kAttAddr); + CHECK(att_cid != 0); + + tL2CAP_LE_CFG_INFO cfg; + auto eatt_cid = L2CA_ConnectLECocReq(BT_PSM_EATT, kEattAddr, &cfg, 0); + CHECK(eatt_cid != 0); + + FuzzedDataProvider fdp(data, size); + + // Feeding input packets + constexpr uint16_t kMinPacketSize = 4 + L2CAP_PKT_OVERHEAD; + constexpr uint16_t kMaxPacketSize = 1024; + for (;;) { + auto size = + fdp.ConsumeIntegralInRange(kMinPacketSize, kMaxPacketSize); + auto bytes = fdp.ConsumeBytes(size); + if (bytes.size() < kMinPacketSize) { + break; + } + + BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size()); + hdr->len = bytes.size(); + std::copy(bytes.cbegin(), bytes.cend(), hdr->data); + l2c_rcv_acl_data(hdr); + } + + L2CA_DisconnectReq(att_cid); + L2CA_DisconnectLECocReq(eatt_cid); + + L2CA_RemoveFixedChnl(L2CAP_SMP_BR_CID, kSmpBrAddr); + l2c_link_hci_disc_comp(kSmpBrHndl, HCI_SUCCESS); + + L2CA_RemoveFixedChnl(L2CAP_ATT_CID, kAttAddr); + l2c_link_hci_disc_comp(kAttHndl, HCI_SUCCESS); + + l2cu_device_reset(); + l2c_free(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + auto fakes = std::make_unique(); + Fuzz(Data, Size); + return 0; +} diff --git a/system/stack/fuzzers/sdp_fuzzer.cc b/system/stack/fuzzers/sdp_fuzzer.cc new file mode 100644 index 0000000000000000000000000000000000000000..cdb8aa9ed639dd453a8eceaf911e4b732454b255 --- /dev/null +++ b/system/stack/fuzzers/sdp_fuzzer.cc @@ -0,0 +1,255 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +#include "osi/include/allocator.h" +#include "stack/include/bt_hdr.h" +#include "stack/include/sdpdefs.h" +#include "stack/sdp/internal/sdp_api.h" +#include "stack/sdp/sdpint.h" +#include "test/fake/fake_osi.h" +#include "test/mock/mock_btif_config.h" +#include "test/mock/mock_stack_l2cap_api.h" +#include "types/bluetooth/uuid.h" + +namespace { + +#define SDP_DB_SIZE 0x10000 + +constexpr uint16_t kDummyCID = 0x1234; +constexpr uint16_t kDummyPSM = 0x7788; +constexpr uint8_t kDummyID = 0x99; +constexpr uint8_t kDummyAddr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + +// Set up default callback structure +tL2CAP_APPL_INFO cb_info = { + .pL2CA_ConnectInd_Cb = [](const RawAddress& bd_addr, uint16_t lcid, + uint16_t psm, + uint8_t id) {}, // tL2CA_CONNECT_IND_CB + .pL2CA_ConnectCfm_Cb = [](uint16_t lcid, + uint16_t result) {}, // tL2CA_CONNECT_CFM_CB + .pL2CA_ConfigInd_Cb = [](uint16_t lcid, + tL2CAP_CFG_INFO* p_cfg) {}, // tL2CA_CONFIG_IND_CB + .pL2CA_ConfigCfm_Cb = [](uint16_t lcid, uint16_t initiator, + tL2CAP_CFG_INFO* p_cfg) {}, // tL2CA_CONFIG_CFM_CB + .pL2CA_DisconnectInd_Cb = + [](uint16_t lcid, bool should_ack) {}, // tL2CA_DISCONNECT_IND_CB + .pL2CA_DisconnectCfm_Cb = + [](uint16_t lcid, uint16_t result) {}, // tL2CA_DISCONNECT_CFM_CB + .pL2CA_DataInd_Cb = [](uint16_t lcid, + BT_HDR* data) {}, // tL2CA_DATA_IND_CB + .pL2CA_CongestionStatus_Cb = + [](uint16_t lcid, bool is_congested) {}, // tL2CA_CONGESTION_STATUS_CB + .pL2CA_TxComplete_Cb = [](uint16_t lcid, + uint16_t num_sdu) {}, // tL2CA_TX_COMPLETE_CB + .pL2CA_Error_Cb = [](uint16_t lcid, + uint16_t error_type) {}, // tL2CA_ERROR_CB + .pL2CA_CreditBasedConnectInd_Cb = + [](const RawAddress& bdaddr, std::vector& lcids, uint16_t psm, + uint16_t peer_mtu, + uint8_t identifier) {}, // tL2CA_CREDIT_BASED_CONNECT_IND_CB + .pL2CA_CreditBasedConnectCfm_Cb = + [](const RawAddress& bdaddr, uint16_t lcid, uint16_t peer_mtu, + uint16_t result) {}, // tL2CA_CREDIT_BASED_CONNECT_CFM_CB + .pL2CA_CreditBasedReconfigCompleted_Cb = + [](const RawAddress& bdaddr, uint16_t lcid, bool is_local_cfg, + tL2CAP_LE_CFG_INFO* p_cfg) { + }, // tL2CA_CREDIT_BASED_RECONFIG_COMPLETED_CB + .pL2CA_CreditBasedCollisionInd_Cb = + [](const RawAddress& bdaddr) {}, // tL2CA_CREDIT_BASED_COLLISION_IND_CB +}; + +class FakeL2cap { + public: + FakeL2cap() { + test::mock::stack_l2cap_api::L2CA_ConnectReq.body = + [](uint16_t psm, const RawAddress& raw_address) { return kDummyCID; }; + test::mock::stack_l2cap_api::L2CA_ConnectReq2.body = + [](uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level) { + return L2CA_ConnectReq(psm, p_bd_addr); + }; + test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t cid, + BT_HDR* p_data) { + auto len = p_data->len; + osi_free(p_data); + return (uint8_t)len; + }; + test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t lcid) { + return true; + }; + test::mock::stack_l2cap_api::L2CA_Register2.body = + [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop, + tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, + uint16_t required_remote_mtu, uint16_t sec_level) { + cb_info = p_cb_info; + return psm; + }; + } + + ~FakeL2cap() { + test::mock::stack_l2cap_api::L2CA_ConnectReq = {}; + test::mock::stack_l2cap_api::L2CA_ConnectReq2 = {}; + test::mock::stack_l2cap_api::L2CA_DataWrite = {}; + test::mock::stack_l2cap_api::L2CA_DisconnectReq = {}; + test::mock::stack_l2cap_api::L2CA_Register2 = {}; + } +}; + +class FakeBtifConfig { + public: + FakeBtifConfig() { + test::mock::btif_config::btif_config_set_bin.body = + [](const std::string&, const std::string&, const uint8_t*, size_t) { + // This function is not properly mocked. The abort here allows us to + // catch any cases using this mock. + abort(); + return true; + }; + test::mock::btif_config::btif_config_set_int.body = + [](const std::string& section, const std::string& key, int value) { + // This function is not properly mocked. The abort here allows us to + // catch any cases using this mock. + abort(); + return true; + }; + } + + ~FakeBtifConfig() { + test::mock::btif_config::btif_config_set_bin = {}; + test::mock::btif_config::btif_config_set_int = {}; + } +}; + +class Fakes { + public: + test::fake::FakeOsi fake_osi; + FakeL2cap fake_l2cap; + FakeBtifConfig fake_btif_config; +}; + +} // namespace + +static void FuzzAsServer(const uint8_t* data, size_t size) { + FuzzedDataProvider fdp(data, size); + std::vector> attrs; + + sdp_init(); + auto rec_num = fdp.ConsumeIntegralInRange(0, 10); + for (uint8_t i = 0; i < rec_num; i++) { + auto handle = SDP_CreateRecord(); + auto attr_num = fdp.ConsumeIntegralInRange(0, 10); + for (uint8_t s = 0; s < attr_num; s++) { + auto id = (i == 0) ? ATTR_ID_BT_PROFILE_DESC_LIST + : fdp.ConsumeIntegral(); + auto type = fdp.ConsumeIntegral(); + auto len = fdp.ConsumeIntegralInRange(1, 512); + auto data = fdp.ConsumeBytes(len); + + if (data.size() == 0) { + break; + } + + attrs.push_back(data); + SDP_AddAttribute(handle, id, type, data.size(), data.data()); + } + } + + cb_info.pL2CA_ConnectInd_Cb(RawAddress(kDummyAddr), kDummyCID, kDummyPSM, + kDummyID); + + tL2CAP_CFG_INFO cfg = {}; + cb_info.pL2CA_ConfigCfm_Cb(kDummyCID, 0, &cfg); + + while (fdp.remaining_bytes() > 0) { + auto size = fdp.ConsumeIntegralInRange(0, 1024); + auto bytes = fdp.ConsumeBytes(size); + BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size()); + hdr->len = bytes.size(); + std::copy(bytes.cbegin(), bytes.cend(), hdr->data); + cb_info.pL2CA_DataInd_Cb(kDummyCID, hdr); + } + + cb_info.pL2CA_DisconnectInd_Cb(kDummyCID, false); + sdp_free(); +} + +static void FuzzAsClient(const uint8_t* data, size_t size) { + FuzzedDataProvider fdp(data, size); + std::shared_ptr p_db( + (tSDP_DISCOVERY_DB*)malloc(SDP_DB_SIZE), free); + + std::vector init_uuids; + std::vector init_attrs; + + sdp_init(); + + uint8_t num_uuid = + fdp.ConsumeIntegralInRange(0, SDP_MAX_UUID_FILTERS); + uint8_t num_attr = + fdp.ConsumeIntegralInRange(0, SDP_MAX_ATTR_FILTERS); + + for (uint8_t i = 0; i < num_uuid; i++) { + init_uuids.push_back( + bluetooth::Uuid::From16Bit(fdp.ConsumeIntegral())); + } + + for (uint8_t i = 0; i < num_attr; i++) { + init_attrs.push_back(fdp.ConsumeIntegral()); + } + + SDP_InitDiscoveryDb(p_db.get(), SDP_DB_SIZE, init_uuids.size(), + init_uuids.data(), init_attrs.size(), init_attrs.data()); + + bool is_di_discover = fdp.ConsumeBool(); + if (is_di_discover) { + SDP_ServiceSearchRequest( + kDummyAddr, p_db.get(), + [](const RawAddress& bd_addr, tSDP_RESULT result) {}); + } else { + SDP_ServiceSearchAttributeRequest( + kDummyAddr, p_db.get(), + [](const RawAddress& bd_addr, tSDP_RESULT result) {}); + } + cb_info.pL2CA_ConnectCfm_Cb(kDummyCID, L2CAP_CONN_OK); + + tL2CAP_CFG_INFO cfg = {}; + cb_info.pL2CA_ConfigCfm_Cb(kDummyCID, 0, &cfg); + + while (fdp.remaining_bytes() > 0) { + auto size = fdp.ConsumeIntegralInRange(0, 1024); + auto bytes = fdp.ConsumeBytes(size); + BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size()); + hdr->len = bytes.size(); + std::copy(bytes.cbegin(), bytes.cend(), hdr->data); + cb_info.pL2CA_DataInd_Cb(kDummyCID, hdr); + } + + cb_info.pL2CA_DisconnectInd_Cb(kDummyCID, false); + sdp_free(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + auto fakes = std::make_unique(); + + FuzzAsServer(Data, Size); + FuzzAsClient(Data, Size); + return 0; +} diff --git a/system/stack/fuzzers/smp_fuzzer.cc b/system/stack/fuzzers/smp_fuzzer.cc new file mode 100644 index 0000000000000000000000000000000000000000..6a23254f452a6554dad00d3ddbb5befea7b38f5b --- /dev/null +++ b/system/stack/fuzzers/smp_fuzzer.cc @@ -0,0 +1,227 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +#include "osi/include/allocator.h" +#include "stack/btm/btm_int_types.h" +#include "stack/include/bt_hdr.h" +#include "stack/include/sdpdefs.h" +#include "stack/include/smp_api.h" +#include "stack/smp/p_256_ecc_pp.h" +#include "stack/smp/smp_int.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" + +namespace { + +#define SDP_DB_SIZE 0x10000 + +constexpr uint8_t kDummyAddr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; +constexpr uint8_t kDummyRemoteAddr[] = {0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC}; + +// Set up default callback structure +tL2CAP_FIXED_CHNL_REG fixed_chnl_reg = { + .pL2CA_FixedConn_Cb = [](uint16_t, const RawAddress&, bool, uint16_t, + tBT_TRANSPORT) {}, + .pL2CA_FixedData_Cb = [](uint16_t, const RawAddress&, BT_HDR*) {}, +}; + +tL2CAP_FIXED_CHNL_REG fixed_chnl_br_reg = { + .pL2CA_FixedConn_Cb = [](uint16_t, const RawAddress&, bool, uint16_t, + tBT_TRANSPORT) {}, + .pL2CA_FixedData_Cb = [](uint16_t, const RawAddress&, BT_HDR*) {}, +}; + +tBTM_SEC_DEV_REC dev_rec; +bool is_peripheral; + +class FakeBtStack { + public: + FakeBtStack() { + test::mock::stack_acl::BTM_ReadConnectionAddr.body = + [](const RawAddress& remote_bda, RawAddress& local_conn_addr, + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { + local_conn_addr = kDummyAddr; + *p_addr_type = BLE_ADDR_PUBLIC; + }; + test::mock::stack_acl::BTM_ReadRemoteConnectionAddr.body = + [](const RawAddress& pseudo_addr, RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { + conn_addr = kDummyRemoteAddr; + *p_addr_type = BLE_ADDR_PUBLIC; + return true; + }; + test::mock::stack_btm_dev::btm_find_dev.body = [](const RawAddress&) { + return &dev_rec; + }; + + test::mock::stack_l2cap_ble::L2CA_GetBleConnRole.body = + [](const RawAddress&) { + return is_peripheral ? HCI_ROLE_PERIPHERAL : HCI_ROLE_CENTRAL; + }; + + test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr.body = + [](const RawAddress&, uint16_t, uint8_t) { return true; }; + test::mock::stack_l2cap_api::L2CA_RemoveFixedChnl.body = + [](uint16_t, const RawAddress&) { return true; }; + test::mock::stack_l2cap_api::L2CA_ConnectFixedChnl.body = + [](uint16_t, const RawAddress&) { return true; }; + test::mock::stack_l2cap_api::L2CA_SendFixedChnlData.body = + [](uint16_t cid, const RawAddress& addr, BT_HDR* hdr) { + osi_free(hdr); + return L2CAP_DW_SUCCESS; + }; + test::mock::stack_l2cap_api::L2CA_RegisterFixedChannel.body = + [](uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg) { + if (fixed_cid == L2CAP_SMP_CID) { + fixed_chnl_reg = *p_freg; + } else if (fixed_cid == L2CAP_SMP_BR_CID) { + fixed_chnl_br_reg = *p_freg; + } else { + abort(); + } + return true; + }; + } + + ~FakeBtStack() { + test::mock::stack_acl::BTM_ReadConnectionAddr = {}; + test::mock::stack_acl::BTM_ReadRemoteConnectionAddr = {}; + + test::mock::stack_btm_dev::btm_find_dev = {}; + + test::mock::stack_l2cap_ble::L2CA_GetBleConnRole = {}; + + test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr = {}; + test::mock::stack_l2cap_api::L2CA_RemoveFixedChnl = {}; + test::mock::stack_l2cap_api::L2CA_ConnectFixedChnl = {}; + test::mock::stack_l2cap_api::L2CA_SendFixedChnlData = {}; + test::mock::stack_l2cap_api::L2CA_RegisterFixedChannel = {}; + } +}; + +class Fakes { + public: + test::fake::FakeOsi fake_osi; + FakeBtStack fake_stack; +}; + +} // namespace + +uint8_t oob_data[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00}; +tSMP_IO_REQ io_req = {}; + +tBTM_STATUS smp_callback(tSMP_EVT event, const RawAddress& bd_addr, + const tSMP_EVT_DATA* p_data) { + switch (event) { + case SMP_IO_CAP_REQ_EVT: + case SMP_BR_KEYS_REQ_EVT: { + tSMP_IO_REQ* p_req = (tSMP_IO_REQ*)p_data; + memcpy(p_req, &io_req, sizeof(io_req)); + } break; + + case SMP_PASSKEY_REQ_EVT: { + SMP_PasskeyReply(kDummyAddr, SMP_SUCCESS, 1234); + } break; + + case SMP_NC_REQ_EVT: { + SMP_ConfirmReply(kDummyAddr, SMP_SUCCESS); + } break; + + case SMP_OOB_REQ_EVT: { + SMP_OobDataReply(kDummyAddr, SMP_SUCCESS, sizeof(oob_data), oob_data); + } break; + + case SMP_SC_OOB_REQ_EVT: { + tSMP_SC_OOB_DATA oob_data = {}; + SMP_SecureConnectionOobDataReply((uint8_t*)&oob_data); + } break; + case SMP_CONSENT_REQ_EVT: { + SMP_SecurityGrant(kDummyAddr, SMP_SUCCESS); + } break; + default: + break; + } + return BTM_SUCCESS; +} + +void Fuzz(const uint8_t* data, size_t size) { + FuzzedDataProvider fdp(data, size); + uint16_t cid; + tBT_TRANSPORT transport; + tL2CAP_FIXED_CHNL_REG* chnl_reg; + + SMP_Init(BTM_SEC_MODE_SP); + SMP_Register(smp_callback); + SMP_ClearLocScOobData(); + + auto is_br = fdp.ConsumeBool(); + auto is_initiator = fdp.ConsumeBool(); + is_peripheral = fdp.ConsumeBool(); + fdp.ConsumeData(&io_req, sizeof(io_req)); + + if (is_br) { + cid = L2CAP_SMP_BR_CID; + chnl_reg = &fixed_chnl_br_reg; + transport = BT_TRANSPORT_BR_EDR; + if (is_initiator) SMP_BR_PairWith(kDummyAddr); + } else { + cid = L2CAP_SMP_CID; + chnl_reg = &fixed_chnl_reg; + transport = BT_TRANSPORT_LE; + if (is_initiator) SMP_Pair(kDummyAddr); + } + + // Simulating connection establaishing event + chnl_reg->pL2CA_FixedConn_Cb(cid, kDummyAddr, true, 0, transport); + + constexpr uint16_t kMaxPacketSize = 1024; + while (fdp.remaining_bytes() > 0) { + auto size = fdp.ConsumeIntegralInRange(0, kMaxPacketSize); + auto bytes = fdp.ConsumeBytes(size); + BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size()); + hdr->len = bytes.size(); + std::copy(bytes.cbegin(), bytes.cend(), hdr->data); + + // Simulating incoming data packet event + chnl_reg->pL2CA_FixedData_Cb(cid, kDummyAddr, hdr); + } + + // Simulating disconnecting event + chnl_reg->pL2CA_FixedConn_Cb(cid, kDummyAddr, false, 0, transport); + + // Final cleanups to avoid memory leak + alarm_free(smp_cb.smp_rsp_timer_ent); + alarm_free(smp_cb.delayed_auth_timer_ent); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + auto fakes = std::make_unique(); + Fuzz(Data, Size); + return 0; +} diff --git a/system/stack/gap/gap_ble.cc b/system/stack/gap/gap_ble.cc index 43b33f0ffce3a1dbc3571743050fa93558fa67db..b5801105a465554f32d619e0e850a97c799dc330 100644 --- a/system/stack/gap/gap_ble.cc +++ b/system/stack/gap/gap_ble.cc @@ -21,14 +21,15 @@ #include #include -#include #include +#include "common/init_flags.h" #include "gap_api.h" #include "gatt_api.h" -#include "main/shim/dumpsys.h" -#include "osi/include/log.h" +#include "hardware/bt_gatt_types.h" +#include "os/log.h" #include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -151,7 +152,6 @@ tGATT_STATUS read_attr_value(uint16_t handle, tGATT_VALUE* p_value, p_value->len -= offset; p_dev_name += offset; ARRAY_TO_STREAM(p, p_dev_name, p_value->len); - DVLOG(1) << "GATT_UUID_GAP_DEVICE_NAME len=" << +p_value->len; } break; @@ -204,8 +204,6 @@ void server_attr_request_cback(uint16_t conn_id, uint32_t trans_id, tGATT_STATUS status = GATT_INVALID_PDU; bool ignore = false; - DVLOG(1) << StringPrintf("%s: recv type (0x%02x)", __func__, type); - tGATTS_RSP rsp_msg; memset(&rsp_msg, 0, sizeof(tGATTS_RSP)); @@ -224,17 +222,17 @@ void server_attr_request_cback(uint16_t conn_id, uint32_t trans_id, case GATTS_REQ_TYPE_WRITE_EXEC: ignore = true; - DVLOG(1) << "Ignore GATTS_REQ_TYPE_WRITE_EXEC"; + VLOG(1) << "Ignore GATTS_REQ_TYPE_WRITE_EXEC"; break; case GATTS_REQ_TYPE_MTU: - DVLOG(1) << "Get MTU exchange new mtu size: " << +p_data->mtu; + VLOG(1) << "Get MTU exchange new mtu size: " << +p_data->mtu; ignore = true; break; default: - DVLOG(1) << StringPrintf("Unknown/unexpected LE GAP ATT request: 0x%02x", - type); + VLOG(1) << StringPrintf("Unknown/unexpected LE GAP ATT request: 0x%02x", + type); break; } @@ -275,13 +273,10 @@ void cl_op_cmpl(tGAP_CLCB& clcb, bool status, uint16_t len, uint8_t* p_name) { tGAP_BLE_CMPL_CBACK* p_cback = clcb.p_cback; uint16_t op = clcb.cl_op_uuid; - DVLOG(1) << StringPrintf("%s: status: %d", __func__, status); - clcb.cl_op_uuid = 0; clcb.p_cback = NULL; if (p_cback && op) { - DVLOG(1) << __func__ << ": calling"; (*p_cback)(status, clcb.bda, len, (char*)p_name); } @@ -333,9 +328,6 @@ void client_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, op_type = p_clcb->cl_op_uuid; - DVLOG(1) << StringPrintf( - "%s: - op_code: 0x%02x status: 0x%02x read_type: 0x%04x", __func__, op, - status, op_type); /* Currently we only issue read commands */ if (op != GATTC_OPTYPE_READ) return; @@ -379,9 +371,6 @@ bool accept_client_operation(const RawAddress& peer_bda, uint16_t uuid, p_clcb = clcb_alloc(peer_bda); } - DVLOG(1) << __func__ << ": BDA: " << ADDRESS_TO_LOGGABLE_STR(peer_bda) - << StringPrintf(" cl_op_uuid: 0x%04x", uuid); - if (GATT_GetConnIdIfConnected(gatt_if, peer_bda, &p_clcb->conn_id, BT_TRANSPORT_LE)) p_clcb->connected = true; @@ -411,8 +400,6 @@ bool accept_client_operation(const RawAddress& peer_bda, uint16_t uuid, * ******************************************************************************/ void gap_attr_db_init(void) { - uint16_t service_handle; - /* Fill our internal UUID with a fixed pattern 0x82 */ std::array tmp; tmp.fill(0x82); @@ -457,9 +444,6 @@ void gap_attr_db_init(void) { /* Add a GAP service */ GATTS_AddService(gatt_if, service, sizeof(service) / sizeof(btgatt_db_element_t)); - service_handle = service[0].attribute_handle; - - DVLOG(1) << __func__ << ": service_handle = " << +service_handle; gatt_attr[0].uuid = GATT_UUID_GAP_DEVICE_NAME; gatt_attr[0].handle = service[1].attribute_handle; @@ -491,12 +475,8 @@ void gap_attr_db_init(void) { * ******************************************************************************/ void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE* p_value) { - DVLOG(1) << StringPrintf("%s: attr_uuid=0x%04x", __func__, attr_uuid); - for (tGAP_ATTR& db_attr : gatt_attr) { if (db_attr.uuid == attr_uuid) { - DVLOG(1) << StringPrintf("Found attr_uuid=0x%04x", attr_uuid); - switch (attr_uuid) { case GATT_UUID_GAP_ICON: db_attr.attr_value.icon = p_value->icon; @@ -564,10 +544,6 @@ bool GAP_BleReadPeerDevName(const RawAddress& peer_bda, bool GAP_BleCancelReadPeerDevName(const RawAddress& peer_bda) { tGAP_CLCB* p_clcb = find_clcb_by_bd_addr(peer_bda); - DVLOG(1) << __func__ << ": BDA: " << ADDRESS_TO_LOGGABLE_STR(peer_bda) - << StringPrintf(" cl_op_uuid: 0x%04x", - (p_clcb == NULL) ? 0 : p_clcb->cl_op_uuid); - if (p_clcb == NULL) { LOG(ERROR) << "Cannot cancel current op is not get dev name"; return false; diff --git a/system/stack/gap/gap_conn.cc b/system/stack/gap/gap_conn.cc index 1fa3f6a17d866f69f36685323366163419907678..36df97466fb362371257ba1d06086916edcf9a60 100644 --- a/system/stack/gap/gap_conn.cc +++ b/system/stack/gap/gap_conn.cc @@ -20,9 +20,9 @@ #include #include -#include "bt_target.h" #include "device/include/controller.h" #include "gap_api.h" +#include "internal_include//bt_target.h" #include "l2c_api.h" #include "l2cdefs.h" #include "osi/include/allocator.h" @@ -172,8 +172,6 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id, tGAP_CCB* p_ccb; uint16_t cid; - DVLOG(1) << "GAP_CONN - Open Request"; - /* Allocate a new CCB. Return if none available. */ p_ccb = gap_allocate_ccb(); if (p_ccb == NULL) return (GAP_INVALID_HANDLE); @@ -218,10 +216,6 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id, le_mps = max_mps; } p_ccb->local_coc_cfg.mps = le_mps; - - VLOG(2) << __func__ << ": credits=" << p_ccb->local_coc_cfg.credits - << ", mps=" << p_ccb->local_coc_cfg.mps - << ", mtu=" << p_ccb->local_coc_cfg.mtu; } p_ccb->p_callback = p_cb; @@ -320,8 +314,6 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id, uint16_t GAP_ConnClose(uint16_t gap_handle) { tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle); - DVLOG(1) << StringPrintf("GAP_CONN - close handle: 0x%x", gap_handle); - if (p_ccb) { /* Check if we have a connection ID */ if (p_ccb->con_state != GAP_CCB_STATE_LISTENING) { @@ -395,10 +387,6 @@ uint16_t GAP_ConnReadData(uint16_t gap_handle, uint8_t* p_data, mutex_global_unlock(); - DVLOG(1) << StringPrintf( - "GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d", - p_ccb->rx_queue_size, *p_len); - return (BT_PASS); } @@ -428,9 +416,6 @@ int GAP_GetRxQueueCnt(uint16_t handle, uint32_t* p_rx_queue_count) { } else rc = GAP_INVALID_HANDLE; - DVLOG(1) << StringPrintf("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", - rc, *p_rx_queue_count); - return (rc); } @@ -493,8 +478,6 @@ uint16_t GAP_ConnWriteData(uint16_t gap_handle, BT_HDR* msg) { return GAP_ERR_ILL_PARM; } - DVLOG(1) << StringPrintf("GAP_WriteData %d bytes", msg->len); - fixed_queue_enqueue(p_ccb->tx_queue, msg); if (!gap_try_write_queued_data(p_ccb)) return GAP_ERR_BAD_STATE; @@ -518,14 +501,9 @@ uint16_t GAP_ConnWriteData(uint16_t gap_handle, BT_HDR* msg) { const RawAddress* GAP_ConnGetRemoteAddr(uint16_t gap_handle) { tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle); - DVLOG(1) << __func__ << " gap_handle = " << gap_handle; - if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING)) { - DVLOG(1) << __func__ << " BDA: " - << ADDRESS_TO_LOGGABLE_STR(p_ccb->rem_dev_address); return &p_ccb->rem_dev_address; } else { - DVLOG(1) << __func__ << " return Error "; return nullptr; } } @@ -587,7 +565,6 @@ void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent) { if (p_ccb == NULL) return; if ((p_ccb->con_state == GAP_CCB_STATE_CONNECTED) && (sdu_sent == 0xFFFF)) { - DVLOG(1) << StringPrintf("%s: GAP_EVT_TX_EMPTY", __func__); p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_TX_EMPTY, nullptr); } } @@ -648,9 +625,6 @@ static void gap_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid, p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE; gap_checks_con_flags(p_ccb); } - - DVLOG(1) << StringPrintf("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x", - p_ccb->connection_id); } /******************************************************************************* @@ -664,7 +638,6 @@ static void gap_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid, * ******************************************************************************/ static void gap_checks_con_flags(tGAP_CCB* p_ccb) { - DVLOG(1) << __func__ << " conn_flags:0x" << +p_ccb->con_flags; /* if all the required con_flags are set, report the OPEN event now */ if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) { p_ccb->con_state = GAP_CCB_STATE_CONNECTED; @@ -825,8 +798,6 @@ static void gap_config_cfm(uint16_t l2cap_cid, uint16_t initiator, static void gap_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) { tGAP_CCB* p_ccb; - DVLOG(1) << StringPrintf("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); - /* Find CCB based on CID */ p_ccb = gap_find_ccb_by_cid(l2cap_cid); if (p_ccb == NULL) return; @@ -859,7 +830,7 @@ static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) { p_ccb->rx_queue_size += p_msg->len; /* - DVLOG(1) << StringPrintf ("gap_data_ind - rx_queue_size=%d, msg len=%d", + VLOG(1) << StringPrintf ("gap_data_ind - rx_queue_size=%d, msg len=%d", p_ccb->rx_queue_size, p_msg->len); */ @@ -878,9 +849,6 @@ static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) { * ******************************************************************************/ static void gap_congestion_ind(uint16_t lcid, bool is_congested) { - DVLOG(1) << StringPrintf("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x", - is_congested, lcid); - tGAP_CCB* p_ccb = gap_find_ccb_by_cid(lcid); /* Find CCB based on CID */ if (!p_ccb) return; @@ -1004,8 +972,6 @@ static void gap_release_ccb(tGAP_CCB* p_ccb) { for (uint16_t i = 0; i < GAP_MAX_CONNECTIONS; i++, p_ccb_local++) { if ((p_ccb_local->con_state != GAP_CCB_STATE_IDLE) && (p_ccb_local->psm == p_ccb->psm)) { - DVLOG(1) << __func__ << " : " << +p_ccb_local->psm - << " PSM is still in use, do not deregister"; return; } } diff --git a/system/stack/gatt/att_protocol.cc b/system/stack/gatt/att_protocol.cc index da3cf51e0e872731aa2099ceda8562b14939df2f..be04498139e070fc05aa4560761580c9fbf43c23 100644 --- a/system/stack/gatt/att_protocol.cc +++ b/system/stack/gatt/att_protocol.cc @@ -24,12 +24,11 @@ #include -#include "bt_target.h" #include "gatt_int.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" #include "types/bluetooth/uuid.h" @@ -287,46 +286,80 @@ static BT_HDR* attp_build_opcode_cmd(uint8_t op_code) { static BT_HDR* attp_build_value_cmd(uint16_t payload_size, uint8_t op_code, uint16_t handle, uint16_t offset, uint16_t len, uint8_t* p_data) { - uint8_t *p, *pp, pair_len, *p_pair_len; + uint8_t *p, *pp, *p_pair_len; + size_t pair_len; + size_t size_now = 1; + +#define CHECK_SIZE() \ + do { \ + if (size_now > payload_size) { \ + LOG_ERROR("payload size too small"); \ + osi_free(p_buf); \ + return nullptr; \ + } \ + } while (false) + BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET); p = pp = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; + + CHECK_SIZE(); UINT8_TO_STREAM(p, op_code); p_buf->offset = L2CAP_MIN_OFFSET; - p_buf->len = 1; if (op_code == GATT_RSP_READ_BY_TYPE) { - p_pair_len = p; + p_pair_len = p++; pair_len = len + 2; - UINT8_TO_STREAM(p, pair_len); - p_buf->len += 1; + size_now += 1; + CHECK_SIZE(); + // this field will be backfilled in the end of this function } + if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) { + size_now += 2; + CHECK_SIZE(); UINT16_TO_STREAM(p, handle); - p_buf->len += 2; } if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE) { + size_now += 2; + CHECK_SIZE(); UINT16_TO_STREAM(p, offset); - p_buf->len += 2; } if (len > 0 && p_data != NULL) { /* ensure data not exceed MTU size */ - if (payload_size - p_buf->len < len) { - len = payload_size - p_buf->len; + if (payload_size - size_now < len) { + len = payload_size - size_now; /* update handle value pair length */ - if (op_code == GATT_RSP_READ_BY_TYPE) *p_pair_len = (len + 2); + if (op_code == GATT_RSP_READ_BY_TYPE) { + pair_len = (len + 2); + } LOG(WARNING) << StringPrintf( "attribute value too long, to be truncated to %d", len); } + size_now += len; + CHECK_SIZE(); ARRAY_TO_STREAM(p, p_data, len); - p_buf->len += len; } + // backfill pair len field + if (op_code == GATT_RSP_READ_BY_TYPE) { + if (pair_len > UINT8_MAX) { + LOG_ERROR("pair_len greater than %d", UINT8_MAX); + osi_free(p_buf); + return nullptr; + } + + *p_pair_len = (uint8_t)pair_len; + } + +#undef CHECK_SIZE + + p_buf->len = (uint16_t)size_now; return p_buf; } @@ -442,10 +475,15 @@ static tGATT_STATUS attp_cl_send_cmd(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, if (gatt_tcb_is_cid_busy(tcb, p_clcb->cid) && cmd_code != GATT_HANDLE_VALUE_CONF) { - gatt_cmd_enq(tcb, p_clcb, true, cmd_code, p_cmd); - LOG_DEBUG("Enqueued ATT command %p conn_id=0x%04x, cid=%d", p_clcb, - p_clcb->conn_id, p_clcb->cid); - return GATT_CMD_STARTED; + if (gatt_cmd_enq(tcb, p_clcb, true, cmd_code, p_cmd)) { + LOG_DEBUG("Enqueued ATT command %p conn_id=0x%04x, cid=%d", p_clcb, + p_clcb->conn_id, p_clcb->cid); + return GATT_CMD_STARTED; + } + + LOG_ERROR("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), p_clcb->cid); + return GATT_INTERNAL_ERROR; } LOG_DEBUG( @@ -466,7 +504,12 @@ static tGATT_STATUS attp_cl_send_cmd(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, LOG_DEBUG("Starting ATT response timer %p conn_id=0x%04x, cid=%d", p_clcb, p_clcb->conn_id, p_clcb->cid); gatt_start_rsp_timer(p_clcb); - gatt_cmd_enq(tcb, p_clcb, false, cmd_code, NULL); + if (!gatt_cmd_enq(tcb, p_clcb, false, cmd_code, NULL)) { + LOG_ERROR("Could not queue sent request. %s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), p_clcb->cid); + return GATT_INTERNAL_ERROR; + } + return att_ret; } @@ -525,7 +568,7 @@ tGATT_STATUS attp_send_cl_msg(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, return GATT_ILLEGAL_PARAMETER; } - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, p_clcb->cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, p_clcb->cid); switch (op_code) { case GATT_REQ_MTU: @@ -535,8 +578,6 @@ tGATT_STATUS attp_send_cl_msg(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, op_code); return GATT_ILLEGAL_PARAMETER; } - - tcb.payload_size = p_msg->mtu; p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu); break; diff --git a/system/stack/gatt/connection_manager.cc b/system/stack/gatt/connection_manager.cc index d55afe0450770b4b8be558e6b1964e064640f97d..047988e4ae9dc312ef4652f80d46843228b43b5e 100644 --- a/system/stack/gatt/connection_manager.cc +++ b/system/stack/gatt/connection_manager.cc @@ -27,18 +27,16 @@ #include #include -#include "bind_helpers.h" #include "internal_include/bt_trace.h" #include "main/shim/le_scanning_manager.h" -#include "main/shim/shim.h" #include "os/log.h" #include "osi/include/alarm.h" -#include "osi/include/log.h" #include "stack/btm/btm_ble_bgconn.h" #include "stack/include/advertise_data_parser.h" +#include "stack/include/bt_types.h" #include "stack/include/btm_ble_api.h" -#include "stack/include/btu.h" // do_in_main_thread -#include "stack/include/l2c_api.h" +#include "stack/include/btm_log_history.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" #define DIRECT_CONNECT_TIMEOUT (30 * 1000) /* 30 seconds */ @@ -270,10 +268,6 @@ bool background_connect_targeted_announcement_add(tAPP_ID app_id, bool background_connect_add(uint8_t app_id, const RawAddress& address) { LOG_DEBUG("app_id=%d, address=%s", static_cast(app_id), ADDRESS_TO_LOGGABLE_CSTR(address)); - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return L2CA_ConnectFixedChnl(L2CAP_ATT_CID, address); - } - auto it = bgconn_dev.find(address); bool in_acceptlist = false; bool is_targeted_announcement_enabled = false; @@ -441,6 +435,7 @@ void on_connection_complete(const RawAddress& address) { } void on_connection_timed_out_from_shim(const RawAddress& address) { + LOG_INFO("Connection failed %s", ADDRESS_TO_LOGGABLE_CSTR(address)); on_connection_timed_out(0x00, address); } @@ -461,7 +456,7 @@ void wl_direct_connect_timeout_cb(uint8_t app_id, const RawAddress& address) { // TODO: this would free the timer, from within the timer callback, which is // bad. - direct_connect_remove(app_id, address); + direct_connect_remove(app_id, address, true); } /** Add a device to the direct connection list. Returns true if device @@ -469,10 +464,6 @@ void wl_direct_connect_timeout_cb(uint8_t app_id, const RawAddress& address) { bool direct_connect_add(uint8_t app_id, const RawAddress& address) { LOG_DEBUG("app_id=%d, address=%s", static_cast(app_id), ADDRESS_TO_LOGGABLE_CSTR(address)); - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return L2CA_ConnectFixedChnl(L2CAP_ATT_CID, address); - } - bool in_acceptlist = false; auto it = bgconn_dev.find(address); if (it != bgconn_dev.end()) { @@ -517,7 +508,8 @@ static void schedule_direct_connect_add(uint8_t app_id, direct_connect_add(app_id, address); } -bool direct_connect_remove(uint8_t app_id, const RawAddress& address) { +bool direct_connect_remove(uint8_t app_id, const RawAddress& address, + bool connection_timeout) { LOG_DEBUG("app_id=%d, address=%s", static_cast(app_id), ADDRESS_TO_LOGGABLE_CSTR(address)); auto it = bgconn_dev.find(address); @@ -542,6 +534,18 @@ bool direct_connect_remove(uint8_t app_id, const RawAddress& address) { it->second.doing_direct_conn.erase(app_it); if (is_anyone_interested_to_use_accept_list(it)) { + if (connection_timeout) { + /* In such case we need to add device back to allow list because, + * when connection timeout out, the lower layer removes device from + * the allow list. + */ + if (!BTM_AcceptlistAdd(address)) { + LOG_WARN( + "Failed to re-add device %s to accept list after connection " + "timeout", + ADDRESS_TO_LOGGABLE_CSTR(address)); + } + } return true; } diff --git a/system/stack/gatt/connection_manager.h b/system/stack/gatt/connection_manager.h index 0af1679f8e26b13188c2da87fcfc3144d11b63e6..07dfa3ebfa5d9b7417cdf25ea3212097685dfbb5 100644 --- a/system/stack/gatt/connection_manager.h +++ b/system/stack/gatt/connection_manager.h @@ -51,7 +51,8 @@ void on_connection_complete(const RawAddress& address); std::set get_apps_connecting_to(const RawAddress& remote_bda); bool direct_connect_add(tAPP_ID app_id, const RawAddress& address); -bool direct_connect_remove(tAPP_ID app_id, const RawAddress& address); +bool direct_connect_remove(tAPP_ID app_id, const RawAddress& address, + bool connection_timeout = false); void dump(int fd); diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc index 9549cff0398c9102c35d4e80453b3e2f292d9ead..bbe6875f62f95f40e4008be4d74b5fff271d9b3a 100644 --- a/system/stack/gatt/gatt_api.cc +++ b/system/stack/gatt/gatt_api.cc @@ -21,36 +21,39 @@ * this file contains GATT interface functions * ******************************************************************************/ +#define LOG_TAG "gatt_api" + #include "stack/include/gatt_api.h" -#include #include -#include #include -#include "bt_target.h" #include "device/include/controller.h" #include "gd/os/system_properties.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" #include "internal_include/stack_config.h" #include "l2c_api.h" -#include "main/shim/dumpsys.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/list.h" -#include "osi/include/log.h" #include "rust/src/connection/ffi/connection_shim.h" #include "stack/arbiter/acl_arbiter.h" #include "stack/btm/btm_dev.h" #include "stack/gatt/connection_manager.h" #include "stack/gatt/gatt_int.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + using bluetooth::Uuid; -bool BTM_BackgroundConnectAddressKnown(const RawAddress& address); /** * Add an service handle range to the list in decending order of the start * handle. Return reference to the newly added element. @@ -418,7 +421,7 @@ void GATTS_StopService(uint16_t service_handle) { } if (it->sdp_handle) { - SDP_DeleteRecord(it->sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(it->sdp_handle); } gatt_cb.srv_list_info->erase(it); @@ -475,7 +478,7 @@ tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle, tGATT_SR_MSG gatt_sr_msg; gatt_sr_msg.attr_value = indication; - uint16_t payload_size = gatt_tcb_get_payload_size_tx(*p_tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(*p_tcb, cid); BT_HDR* p_msg = attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_IND, &gatt_sr_msg, payload_size); if (!p_msg) return GATT_NO_RESOURCES; @@ -494,7 +497,7 @@ static tGATT_STATUS GATTS_HandleMultileValueNotification( LOG_INFO(""); uint16_t cid = gatt_tcb_get_att_cid(*p_tcb, true /* eatt support */); - uint16_t payload_size = gatt_tcb_get_payload_size_tx(*p_tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(*p_tcb, cid); /* TODO Handle too big packet size here. Not needed now for testing. */ /* Just build the message. */ @@ -608,7 +611,7 @@ tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id, gatt_sr_msg.attr_value = notif; uint16_t cid = gatt_tcb_get_att_cid(*p_tcb, p_reg->eatt_support); - uint16_t payload_size = gatt_tcb_get_payload_size_tx(*p_tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(*p_tcb, cid); BT_HDR* p_buf = attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_NOTIF, &gatt_sr_msg, payload_size); @@ -721,8 +724,8 @@ tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) { /* Since GATT MTU Exchange can be done only once, and it is impossible to * predict what MTU will be requested by other applications, let's use - * max possible MTU in the request. */ - gatt_cl_msg.mtu = GATT_MAX_MTU_SIZE; + * default MTU in the request. */ + gatt_cl_msg.mtu = gatt_get_local_mtu(); LOG_INFO("Configuring ATT mtu size conn_id:%hu mtu:%hu user mtu %hu", conn_id, gatt_cl_msg.mtu, mtu); @@ -967,8 +970,7 @@ tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type, p_clcb->op_subtype = type; p_clcb->auth_req = p_read->by_handle.auth_req; p_clcb->counter = 0; - p_clcb->read_req_current_mtu = - gatt_tcb_get_payload_size_tx(*p_tcb, p_clcb->cid); + p_clcb->read_req_current_mtu = gatt_tcb_get_payload_size(*p_tcb, p_clcb->cid); switch (type) { case GATT_READ_BY_TYPE: @@ -977,7 +979,8 @@ tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type, p_clcb->e_handle = p_read->service.e_handle; p_clcb->uuid = p_read->service.uuid; break; - case GATT_READ_MULTIPLE: { + case GATT_READ_MULTIPLE: + case GATT_READ_MULTIPLE_VAR_LEN: { p_clcb->s_handle = 0; /* copy multiple handles in CB */ tGATT_READ_MULTI* p_read_multi = @@ -1439,7 +1442,7 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, } else { LOG_DEBUG("Starting background connect gatt_if=%u address=%s", gatt_if, ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); - if (!BTM_BackgroundConnectAddressKnown(bd_addr)) { + if (!BTM_Sec_AddressKnown(bd_addr)) { // RPA can rotate, causing address to "expire" in the background // connection list. RPA is allowed for direct connect, as such request // times out after 30 seconds @@ -1681,13 +1684,12 @@ void gatt_load_bonded(void) { return; } for (tBTM_SEC_DEV_REC* p_dev_rec : btm_get_sec_dev_rec()) { - if (p_dev_rec->is_link_key_known()) { + if (p_dev_rec->sec_rec.is_link_key_known()) { LOG_VERBOSE("Add bonded BR/EDR transport %s", ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->bd_addr)); gatt_bonded_check_add_address(p_dev_rec->bd_addr); } - if (p_dev_rec->is_le_link_key_known()) { - VLOG(1) << " add bonded BLE " << p_dev_rec->ble.pseudo_addr; + if (p_dev_rec->sec_rec.is_le_link_key_known()) { LOG_VERBOSE("Add bonded BLE %s", ADDRESS_TO_LOGGABLE_CSTR(p_dev_rec->ble.pseudo_addr)); gatt_bonded_check_add_address(p_dev_rec->ble.pseudo_addr); diff --git a/system/stack/gatt/gatt_attr.cc b/system/stack/gatt/gatt_attr.cc index 50b61aeea412de454fac3446595008c9068551ed..3fa164776a3c4612ae3e425121681801e045adab 100644 --- a/system/stack/gatt/gatt_attr.cc +++ b/system/stack/gatt/gatt_attr.cc @@ -23,23 +23,27 @@ * ******************************************************************************/ +#include + +#include #include #include "base/functional/callback.h" -#include "bt_target.h" #include "btif/include/btif_storage.h" #include "eatt/eatt.h" #include "gatt_api.h" #include "gatt_int.h" -#include "gd/common/init_flags.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" +#include "os/log.h" +#include "os/logging/log_adapter.h" +#include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/btm_sec_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#include - using base::StringPrintf; using bluetooth::Uuid; @@ -54,13 +58,16 @@ using bluetooth::Uuid; using gatt_sr_supported_feat_cb = base::OnceCallback; +using gatt_sirk_cb = base::OnceCallback; typedef struct { uint16_t op_uuid; gatt_sr_supported_feat_cb cb; + gatt_sirk_cb sirk_cb; } gatt_op_cb_data; -static std::map OngoingOps; +static std::map> OngoingOps; static void gatt_request_cback(uint16_t conn_id, uint32_t trans_id, uint8_t op_code, tGATTS_DATA* p_data); @@ -84,6 +91,11 @@ static bool gatt_sr_is_robust_caching_enabled(); static bool read_sr_supported_feat_req( uint16_t conn_id, base::OnceCallback cb); +static bool read_sr_sirk_req( + uint16_t conn_id, + base::OnceCallback + cb); static tGATT_STATUS gatt_sr_read_db_hash(uint16_t conn_id, tGATT_VALUE* p_value); @@ -382,6 +394,8 @@ void gatt_profile_db_init(void) { std::array tmp; tmp.fill(0x81); + OngoingOps.clear(); + /* Create a GATT profile service */ gatt_cb.gatt_if = GATT_Register(Uuid::From128BitBE(tmp), "GattProfileDb", &gatt_profile_cback, false); @@ -406,14 +420,14 @@ void gatt_profile_db_init(void) { .permissions = 0, }, { - .type = BTGATT_DB_CHARACTERISTIC, .uuid = svr_sup_feat_uuid, + .type = BTGATT_DB_CHARACTERISTIC, .properties = GATT_CHAR_PROP_BIT_READ, .permissions = GATT_PERM_READ, }, { - .type = BTGATT_DB_CHARACTERISTIC, .uuid = cl_sup_feat_uuid, + .type = BTGATT_DB_CHARACTERISTIC, .properties = GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE, .permissions = GATT_PERM_READ | GATT_PERM_WRITE, }, @@ -514,8 +528,7 @@ static void gatt_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type, gatt_cl_start_config_ccc(p_clcb); } -static bool gatt_svc_read_cl_supp_feat_req(uint16_t conn_id, - gatt_op_cb_data* cb) { +static bool gatt_svc_read_cl_supp_feat_req(uint16_t conn_id) { tGATT_READ_PARAM param; memset(¶m, 0, sizeof(tGATT_READ_PARAM)); @@ -533,7 +546,13 @@ static bool gatt_svc_read_cl_supp_feat_req(uint16_t conn_id, return false; } - cb->op_uuid = GATT_UUID_CLIENT_SUP_FEAT; + gatt_op_cb_data cb_data; + + cb_data.cb = + base::BindOnce([](const RawAddress& bdaddr, uint8_t support) { return; }); + cb_data.op_uuid = GATT_UUID_CLIENT_SUP_FEAT; + OngoingOps[conn_id].emplace_back(std::move(cb_data)); + return true; } @@ -580,21 +599,19 @@ static void gatt_cl_op_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, return; } - if (iter == OngoingOps.end()) { + if (iter == OngoingOps.end() || (iter->second.size() == 0)) { /* If OngoingOps is empty it means we are not interested in the result here. */ LOG_DEBUG("Unexpected read complete"); return; } - gatt_op_cb_data* operation_callback_data = &iter->second; - uint16_t cl_op_uuid = operation_callback_data->op_uuid; - operation_callback_data->op_uuid = 0; + uint16_t cl_op_uuid = iter->second.front().op_uuid; if (op == GATTC_OPTYPE_WRITE) { if (cl_op_uuid == GATT_UUID_GATT_SRV_CHGD) { LOG_DEBUG("Write response from Service Changed CCC"); - OngoingOps.erase(iter); + iter->second.pop_front(); /* Read server supported features here supported */ read_sr_supported_feat_req( conn_id, base::BindOnce([](const RawAddress& bdaddr, @@ -605,6 +622,7 @@ static void gatt_cl_op_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, return; } + /* Handle Read operations */ uint8_t* pp = p_data->att_value.value; VLOG(1) << __func__ << " cl_op_uuid " << loghex(cl_op_uuid); @@ -614,6 +632,9 @@ static void gatt_cl_op_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx]; + auto operation_callback_data = std::move(iter->second.front()); + iter->second.pop_front(); + /* Check if EATT is supported */ if (status == GATT_SUCCESS) { STREAM_TO_UINT8(tcb.sr_supp_feat, pp); @@ -621,28 +642,39 @@ static void gatt_cl_op_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, } /* Notify user about the supported features */ - std::move(operation_callback_data->cb) - .Run(tcb.peer_bda, tcb.sr_supp_feat); + std::move(operation_callback_data.cb).Run(tcb.peer_bda, tcb.sr_supp_feat); /* If server supports EATT lets try to find handle for the * client supported features characteristic, where we could write * our supported features as a client. */ if (tcb.sr_supp_feat & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK) { - /* If read succeed, return here */ - if (gatt_svc_read_cl_supp_feat_req(conn_id, operation_callback_data)) - return; + gatt_svc_read_cl_supp_feat_req(conn_id); } - /* Could not read client supported charcteristic or eatt is not - * supported. Erase callback data now. - */ - OngoingOps.erase(iter); + break; + } + case GATT_UUID_CSIS_SIRK: { + uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx]; + + auto operation_callback_data = std::move(iter->second.front()); + iter->second.pop_front(); + tcb.gatt_status = status; + + if (status == GATT_SUCCESS) { + STREAM_TO_UINT8(tcb.sirk_type, pp); + STREAM_TO_ARRAY(tcb.sirk.data(), pp, 16); + } + + std::move(operation_callback_data.sirk_cb) + .Run(tcb.gatt_status, tcb.peer_bda, tcb.sirk_type, tcb.sirk); + break; } case GATT_UUID_CLIENT_SUP_FEAT: /*We don't need callback data anymore */ - OngoingOps.erase(iter); + iter->second.pop_front(); if (status != GATT_SUCCESS) { LOG(INFO) << __func__ @@ -698,7 +730,7 @@ static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb) { cb_data.cb = base::BindOnce( [](const RawAddress& bdaddr, uint8_t support) { return; }); cb_data.op_uuid = GATT_UUID_GATT_SRV_CHGD; - OngoingOps[p_clcb->conn_id] = std::move(cb_data); + OngoingOps[p_clcb->conn_id].emplace_back(std::move(cb_data)); break; } @@ -777,7 +809,35 @@ static bool read_sr_supported_feat_req( cb_data.cb = std::move(cb); cb_data.op_uuid = GATT_UUID_SERVER_SUP_FEAT; - OngoingOps[conn_id] = std::move(cb_data); + OngoingOps[conn_id].emplace_back(std::move(cb_data)); + + return true; +} + +static bool read_sr_sirk_req( + uint16_t conn_id, + base::OnceCallback + cb) { + tGATT_READ_PARAM param = {}; + + param.service.s_handle = 1; + param.service.e_handle = 0xFFFF; + param.service.auth_req = 0; + + param.service.uuid = bluetooth::Uuid::From16Bit(GATT_UUID_CSIS_SIRK); + + if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, ¶m) != GATT_SUCCESS) { + LOG_ERROR("Read GATT Support features GATT_Read Failed, conn_id: %d", + static_cast(conn_id)); + return false; + } + + gatt_op_cb_data cb_data; + + cb_data.sirk_cb = std::move(cb); + cb_data.op_uuid = GATT_UUID_CSIS_SIRK; + OngoingOps[conn_id].emplace_back(std::move(cb_data)); return true; } @@ -817,15 +877,57 @@ bool gatt_cl_read_sr_supp_feat_req( } auto it = OngoingOps.find(conn_id); - if (it != OngoingOps.end()) { - LOG(ERROR) << __func__ << " There is ongoing operation for conn_id: " - << loghex(conn_id); - return false; + if (it == OngoingOps.end()) { + OngoingOps[conn_id] = std::deque(); } return read_sr_supported_feat_req(conn_id, std::move(cb)); } +/******************************************************************************* + * + * Function gatt_cl_read_sirk_req + * + * Description Read remote SIRK if it's a set member device. + * + * Returns bool + * + ******************************************************************************/ +bool gatt_cl_read_sirk_req( + const RawAddress& peer_bda, + base::OnceCallback + cb) { + tGATT_PROFILE_CLCB* p_clcb; + uint16_t conn_id; + + if (!cb) return false; + + LOG_DEBUG("BDA: %s, read SIRK", ADDRESS_TO_LOGGABLE_CSTR(peer_bda)); + + GATT_GetConnIdIfConnected(gatt_cb.gatt_if, peer_bda, &conn_id, + BT_TRANSPORT_LE); + if (conn_id == GATT_INVALID_CONN_ID) return false; + + p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id); + if (!p_clcb) { + p_clcb = gatt_profile_clcb_alloc(conn_id, peer_bda, BT_TRANSPORT_LE); + } + + if (!p_clcb) { + LOG_VERBOSE("p_clcb is NULL, conn_id: %04x", conn_id); + return false; + } + + auto it = OngoingOps.find(conn_id); + + if (it == OngoingOps.end()) { + OngoingOps[conn_id] = std::deque(); + } + + return read_sr_sirk_req(conn_id, std::move(cb)); +} + /******************************************************************************* * * Function gatt_profile_get_eatt_support diff --git a/system/stack/gatt/gatt_auth.cc b/system/stack/gatt/gatt_auth.cc index e2a433395dbf5aa62e6a30ca648411fe53104362..126baebbf37d3cb28f1848fb67c3231b989d5875 100644 --- a/system/stack/gatt/gatt_auth.cc +++ b/system/stack/gatt/gatt_auth.cc @@ -21,6 +21,7 @@ * this file contains GATT authentication handling functions * ******************************************************************************/ +#include #include #include "bt_target.h" @@ -28,14 +29,13 @@ #include "gatt_int.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_ble_int_types.h" +#include "stack/btm/btm_ble_sec.h" #include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_ble_sec_api.h" #include "types/raw_address.h" -#include - using base::StringPrintf; /******************************************************************************* diff --git a/system/stack/gatt/gatt_cl.cc b/system/stack/gatt/gatt_cl.cc index 2b7c27a2b38b00dca97baf1ed14b04b97ada83bf..69df1ea9fa874826748b9548ce2be82a7b6083ef 100644 --- a/system/stack/gatt/gatt_cl.cc +++ b/system/stack/gatt/gatt_cl.cc @@ -24,21 +24,20 @@ #define LOG_TAG "bluetooth" +#include #include -#include "bt_target.h" #include "gatt_int.h" -#include "l2c_api.h" +#include "hardware/bt_gatt_types.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "stack/arbiter/acl_arbiter.h" #include "stack/eatt/eatt.h" #include "stack/include/bt_types.h" #include "types/bluetooth/uuid.h" -#include - #define GATT_WRITE_LONG_HDR_SIZE 5 /* 1 opcode + 2 handle + 2 offset */ #define GATT_READ_CHAR_VALUE_HDL (GATT_READ_CHAR_VALUE | 0x80) #define GATT_READ_INC_SRV_UUID128 (GATT_DISC_INC_SRVC | 0x90) @@ -230,7 +229,7 @@ void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act) { CHECK(p_clcb->p_attr_buf); tGATT_VALUE& attr = *((tGATT_VALUE*)p_clcb->p_attr_buf); - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, p_clcb->cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, p_clcb->cid); switch (p_clcb->op_subtype) { case GATT_WRITE_NO_RSP: { @@ -351,7 +350,7 @@ void gatt_send_prepare_write(tGATT_TCB& tcb, tGATT_CLCB* p_clcb) { VLOG(1) << __func__ << StringPrintf(" type=0x%x", type); uint16_t to_send = p_attr->len - p_attr->offset; - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, p_clcb->cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, p_clcb->cid); if (to_send > (payload_size - GATT_WRITE_LONG_HDR_SIZE)) /* 2 = uint16_t offset bytes */ to_send = payload_size - GATT_WRITE_LONG_HDR_SIZE; @@ -814,7 +813,7 @@ void gatt_process_read_by_type_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, } STREAM_TO_UINT8(value_len, p); - uint16_t payload_size = gatt_tcb_get_payload_size_rx(tcb, p_clcb->cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, p_clcb->cid); if ((value_len > (payload_size - 2)) || (value_len > (len - 1))) { /* this is an error case that server's response containing a value length which is larger than MTU-2 @@ -1004,7 +1003,7 @@ void gatt_process_read_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint16_t offset = p_clcb->counter; uint8_t* p = p_data; - uint16_t payload_size = gatt_tcb_get_payload_size_rx(tcb, p_clcb->cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, p_clcb->cid); if (p_clcb->operation == GATTC_OPTYPE_READ) { if (p_clcb->op_subtype != GATT_READ_BY_HANDLE) { @@ -1112,11 +1111,11 @@ void gatt_process_mtu_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint16_t len, tcb.pending_user_mtu_exchange_value, tcb.peer_bda.ToString().c_str(), mtu); - /* Aim for MAX as we did in the request */ + /* Aim for default as we did in the request */ if (mtu < GATT_DEF_BLE_MTU_SIZE) { tcb.payload_size = GATT_DEF_BLE_MTU_SIZE; } else { - tcb.payload_size = std::min(mtu, (uint16_t)(GATT_MAX_MTU_SIZE)); + tcb.payload_size = std::min(mtu, (uint16_t)(gatt_get_local_mtu())); } bluetooth::shim::arbiter::GetArbiter().OnIncomingMtuResp(tcb.tcb_idx, @@ -1127,6 +1126,8 @@ void gatt_process_mtu_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint16_t len, if (tcb.pending_user_mtu_exchange_value > tcb.max_user_mtu) { tcb.max_user_mtu = std::min(tcb.pending_user_mtu_exchange_value, tcb.payload_size); + } else if (tcb.pending_user_mtu_exchange_value == 0) { + tcb.max_user_mtu = tcb.payload_size; } tcb.pending_user_mtu_exchange_value = 0; @@ -1216,7 +1217,7 @@ void gatt_client_handle_server_rsp(tGATT_TCB& tcb, uint16_t cid, uint8_t* p_data) { VLOG(1) << __func__ << " opcode: " << loghex(op_code) << " cid" << +cid; - uint16_t payload_size = gatt_tcb_get_payload_size_rx(tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid); if (op_code == GATT_HANDLE_VALUE_IND || op_code == GATT_HANDLE_VALUE_NOTIF || op_code == GATT_HANDLE_MULTI_VALUE_NOTIF) { diff --git a/system/stack/gatt/gatt_db.cc b/system/stack/gatt/gatt_db.cc index f48977f595f06c02f9f7584c15c8f654e977e999..30aee99766cd84c486e9c2a59bbb0b353c7fb8e7 100644 --- a/system/stack/gatt/gatt_db.cc +++ b/system/stack/gatt/gatt_db.cc @@ -27,15 +27,11 @@ #include #include -#include "bt_target.h" -#include "bt_trace.h" #include "gatt_int.h" #include "l2c_api.h" #include "osi/include/osi.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_sec.h" -#include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" #include "types/bluetooth/uuid.h" using base::StringPrintf; diff --git a/system/stack/gatt/gatt_int.h b/system/stack/gatt/gatt_int.h index e88942e6ac78efc1e1fa6b5b1c4a01577723de23..1e4867ce25fb3f60711900070d6f6a30ac270b05 100644 --- a/system/stack/gatt/gatt_int.h +++ b/system/stack/gatt/gatt_int.h @@ -21,18 +21,16 @@ #include #include -#include #include #include -#include #include #include -#include "bt_target.h" -#include "btm_ble_api.h" -#include "btu.h" +#include "common/init_flags.h" #include "gatt_api.h" +#include "internal_include/bt_target.h" +#include "macros.h" #include "osi/include/fixed_queue.h" #include "stack/include/bt_hdr.h" #include "types/bluetooth/uuid.h" @@ -56,10 +54,6 @@ typedef enum : uint8_t { GATT_SEC_ENC_PENDING = 6, /* wait for link encryption pending */ } tGATT_SEC_ACTION; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string gatt_security_action_text(const tGATT_SEC_ACTION& action) { switch (action) { CASE_RETURN_TEXT(GATT_SEC_NONE); @@ -74,8 +68,6 @@ inline std::string gatt_security_action_text(const tGATT_SEC_ACTION& action) { } } -#undef CASE_RETURN_TEXT - #define GATT_INDEX_INVALID 0xff #define GATT_WRITE_CMD_MASK 0xc0 /*0x1100-0000*/ @@ -246,10 +238,6 @@ typedef enum : uint8_t { GATT_CH_OPEN = 4, } tGATT_CH_STATE; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string gatt_channel_state_text(const tGATT_CH_STATE& state) { switch (state) { CASE_RETURN_TEXT(GATT_CH_CLOSE); @@ -261,7 +249,6 @@ inline std::string gatt_channel_state_text(const tGATT_CH_STATE& state) { return base::StringPrintf("UNKNOWN[%hhu]", state); } } -#undef CASE_RETURN_TEXT // If you change these values make sure to look at b/262219144 before. // Some platform rely on this to never changes @@ -340,6 +327,11 @@ typedef struct { /* Use for server. if false, should handle database out of sync. */ bool is_robust_cache_change_aware; + /* SIRK read related data */ + tGATT_STATUS gatt_status; + uint8_t sirk_type; + Octet16 sirk; + bool in_use; uint8_t tcb_idx; @@ -503,6 +495,11 @@ void gatt_cl_init_sr_status(tGATT_TCB& tcb); bool gatt_cl_read_sr_supp_feat_req( const RawAddress& peer_bda, base::OnceCallback cb); +bool gatt_cl_read_sirk_req( + const RawAddress& peer_bda, + base::OnceCallback + cb); bool gatt_sr_is_cl_multi_variable_len_notif_supported(tGATT_TCB& tcb); bool gatt_sr_is_cl_change_aware(tGATT_TCB& tcb); @@ -520,6 +517,7 @@ tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB& tcb, uint16_t cid, BT_HDR* p_toL2CAP); /* utility functions */ +uint16_t gatt_get_local_mtu(void); uint8_t* gatt_dbg_op_name(uint8_t op_code); uint32_t gatt_add_sdp_record(const bluetooth::Uuid& uuid, uint16_t start_hdl, uint16_t end_hdl); @@ -578,7 +576,7 @@ void gatt_sr_send_req_callback(uint16_t conn_id, uint32_t trans_id, uint32_t gatt_sr_enqueue_cmd(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, uint16_t handle); bool gatt_cancel_open(tGATT_IF gatt_if, const RawAddress& bda); -void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle, +void gatt_notify_phy_updated(tHCI_STATUS status, uint16_t handle, uint8_t tx_phy, uint8_t rx_phy); void gatt_notify_subrate_change(uint16_t handle, uint16_t subrate_factor, uint16_t latency, uint16_t cont_num, @@ -598,8 +596,7 @@ bool gatt_tcb_get_cid_available_for_indication(tGATT_TCB* p_tcb, bool gatt_tcb_find_indicate_handle(tGATT_TCB& tcb, uint16_t cid, uint16_t* indicated_handle_p); uint16_t gatt_tcb_get_att_cid(tGATT_TCB& tcb, bool eatt_support); -uint16_t gatt_tcb_get_payload_size_tx(tGATT_TCB& tcb, uint16_t cid); -uint16_t gatt_tcb_get_payload_size_rx(tGATT_TCB& tcb, uint16_t cid); +uint16_t gatt_tcb_get_payload_size(tGATT_TCB& tcb, uint16_t cid); void gatt_clcb_invalidate(tGATT_TCB* p_tcb, const tGATT_CLCB* p_clcb); uint16_t gatt_get_mtu(const RawAddress& bda, tBT_TRANSPORT transport); bool gatt_is_pending_mtu_exchange(tGATT_TCB* p_tcb); @@ -641,7 +638,7 @@ void gatt_act_discovery(tGATT_CLCB* p_clcb); void gatt_act_read(tGATT_CLCB* p_clcb, uint16_t offset); void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act); tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB& tcb, uint16_t cid, uint8_t* p_opcode); -void gatt_cmd_enq(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, bool to_send, +bool gatt_cmd_enq(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, bool to_send, uint8_t op_code, BT_HDR* p_buf); void gatt_client_handle_server_rsp(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, uint16_t len, diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc index fb40e2724bfdab6d636133178796fb92d9f08775..0e78432dae7cfd203c14b850ab933645932f42c2 100644 --- a/system/stack/gatt/gatt_main.cc +++ b/system/stack/gatt/gatt_main.cc @@ -24,14 +24,12 @@ #include -#include "bt_target.h" #include "btif/include/btif_dm.h" #include "btif/include/btif_storage.h" #include "btif/include/stack_manager.h" #include "connection_manager.h" #include "device/include/interop.h" -#include "gd/common/init_flags.h" -#include "hardware/bt_gatt_types.h" +#include "internal_include/bt_target.h" #include "internal_include/stack_config.h" #include "l2c_api.h" #include "main/shim/acl_api.h" @@ -40,12 +38,13 @@ #include "osi/include/properties.h" #include "rust/src/connection/ffi/connection_shim.h" #include "stack/arbiter/acl_arbiter.h" -#include "stack/btm/btm_ble_int.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" #include "stack/eatt/eatt.h" #include "stack/gatt/gatt_int.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/bt_types.h" #include "stack/include/l2cap_acl_interface.h" #include "stack/include/srvc_api.h" // tDIS_VALUE #include "types/raw_address.h" @@ -200,26 +199,6 @@ void gatt_free(void) { EattExtension::GetInstance()->Stop(); } -void gatt_find_in_device_record(const RawAddress& bd_addr, - tBLE_BD_ADDR* address_with_type) { - const tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); - if (p_dev_rec == nullptr) { - return; - } - - if (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) { - if (p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { - *address_with_type = {.type = p_dev_rec->ble.AddressType(), - .bda = bd_addr}; - return; - } - *address_with_type = p_dev_rec->ble.identity_address_with_type; - return; - } - *address_with_type = {.type = BLE_ADDR_PUBLIC, .bda = bd_addr}; - return; -} - /******************************************************************************* * * Function gatt_connect @@ -648,7 +627,7 @@ static void gatt_channel_congestion(tGATT_TCB* p_tcb, bool congested) { } } -void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle, +void gatt_notify_phy_updated(tHCI_STATUS status, uint16_t handle, uint8_t tx_phy, uint8_t rx_phy) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle); if (!p_dev_rec) { @@ -660,12 +639,15 @@ void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle, gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE); if (!p_tcb) return; + // TODO: Clean up this status conversion. + tGATT_STATUS gatt_status = static_cast(status); + for (int i = 0; i < GATT_MAX_APPS; i++) { tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) { uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); (*p_reg->app_cb.p_phy_update_cb)(p_reg->gatt_if, conn_id, tx_phy, rx_phy, - status); + gatt_status); } } } @@ -970,10 +952,8 @@ static void gatt_send_conn_cback(tGATT_TCB* p_tcb) { GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport, true /* is_active */); } else { - if (bluetooth::common::init_flags::finite_att_timeout_is_enabled()) { - GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, - p_tcb->transport, false /* is_active */); - } + GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, + p_tcb->transport, false /* is_active */); } } } diff --git a/system/stack/gatt/gatt_sr.cc b/system/stack/gatt/gatt_sr.cc index ad8f254054052086d82820087fdd6053f36204fb..3f55c6a84ff25256284aa64cd9472324958ee2ac 100644 --- a/system/stack/gatt/gatt_sr.cc +++ b/system/stack/gatt/gatt_sr.cc @@ -21,11 +21,14 @@ * this file contains the GATT server functions * ******************************************************************************/ -#include +#include #include -#include "bt_target.h" +#include + #include "gatt_int.h" +#include "hardware/bt_gatt_types.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "osi/include/allocator.h" #include "osi/include/log.h" @@ -36,7 +39,6 @@ #include "stack/include/bt_types.h" #include "stack/l2cap/l2c_int.h" #include "types/bluetooth/uuid.h" -#include #define GATT_MTU_REQ_MIN_LEN 2 #define L2CAP_PKT_OVERHEAD 4 @@ -65,6 +67,12 @@ uint32_t gatt_sr_enqueue_cmd(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return 0; + } + p_cmd = &channel->server_outstanding_cmd_; } @@ -105,6 +113,11 @@ bool gatt_sr_cmd_empty(tGATT_TCB& tcb, uint16_t cid) { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return false; + } return (channel->server_outstanding_cmd_.op_code == 0); } @@ -126,6 +139,11 @@ void gatt_dequeue_sr_cmd(tGATT_TCB& tcb, uint16_t cid) { } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return; + } p_cmd = &channel->server_outstanding_cmd_; } @@ -296,7 +314,7 @@ tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB& tcb, tGATT_IF gatt_if, tGATTS_RSP* p_msg, tGATT_SR_CMD* sr_res_p) { tGATT_STATUS ret_code = GATT_SUCCESS; - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, sr_res_p->cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, sr_res_p->cid); VLOG(1) << __func__ << " gatt_if=" << +gatt_if; @@ -429,6 +447,11 @@ void gatt_process_read_multi_req(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, VLOG(1) << __func__; tGATT_READ_MULTI* multi_req = gatt_sr_get_read_multi(tcb, cid); + if (multi_req == nullptr) { + LOG_ERROR("Could not proceed request. %s, 0x%02x", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return; + } multi_req->num_handles = 0; multi_req->variable_len = (op_code == GATT_REQ_READ_MULTI_VAR); gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size); @@ -479,7 +502,12 @@ void gatt_process_read_multi_req(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, trans_id = gatt_sr_enqueue_cmd(tcb, cid, op_code, multi_req->handles[0]); if (trans_id != 0) { tGATT_SR_CMD* sr_cmd_p = gatt_sr_get_cmd_by_cid(tcb, cid); - + if (sr_cmd_p == nullptr) { + LOG_ERROR( + "Could not send response on CID were request arrived. %s, 0x%02x", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return; + } gatt_sr_reset_cback_cnt(tcb, cid); /* read multiple use multi_rsp_q's count*/ @@ -530,7 +558,7 @@ static tGATT_STATUS gatt_build_primary_service_rsp( uint8_t* p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET; - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid); for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) { if (el.s_hdl < s_hdl || el.s_hdl > e_hdl || @@ -725,7 +753,7 @@ void gatts_process_primary_service_req(tGATT_TCB& tcb, uint16_t cid, } } - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid); uint16_t msg_len = (uint16_t)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET); @@ -761,7 +789,7 @@ static void gatts_process_find_info(tGATT_TCB& tcb, uint16_t cid, return; } - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid); uint16_t buf_len = (uint16_t)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET); @@ -829,11 +857,11 @@ static void gatts_process_mtu_req(tGATT_TCB& tcb, uint16_t cid, uint16_t len, if (mtu < GATT_DEF_BLE_MTU_SIZE) { tcb.payload_size = GATT_DEF_BLE_MTU_SIZE; } else { - tcb.payload_size = std::min(mtu, (uint16_t)(GATT_MAX_MTU_SIZE)); + tcb.payload_size = std::min(mtu, (uint16_t)(gatt_get_local_mtu())); } - /* Always say to remote our real MAX MTU. */ - gatt_sr_msg.mtu = GATT_MAX_MTU_SIZE; + /* Always say to remote our default MTU. */ + gatt_sr_msg.mtu = gatt_get_local_mtu(); LOG_INFO("MTU %d request from remote (%s), resulted MTU %d", mtu, tcb.peer_bda.ToString().c_str(), tcb.payload_size); @@ -900,7 +928,7 @@ static void gatts_process_read_by_type_req(tGATT_TCB& tcb, uint16_t cid, return; } - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid); size_t msg_len = sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET; BT_HDR* p_msg = (BT_HDR*)osi_calloc(msg_len); @@ -1047,7 +1075,7 @@ static void gatts_process_read_req(tGATT_TCB& tcb, uint16_t cid, tGATT_SRV_LIST_ELEM& el, uint8_t op_code, uint16_t handle, uint16_t len, uint8_t* p_data) { - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid); size_t buf_len = sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET; uint16_t offset = 0; @@ -1364,7 +1392,7 @@ void gatt_server_handle_client_req(tGATT_TCB& tcb, uint16_t cid, /* The message has to be smaller than the agreed MTU, len does not include op * code */ - uint16_t payload_size = gatt_tcb_get_payload_size_rx(tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid); if (len >= payload_size) { LOG(ERROR) << StringPrintf("server receive invalid PDU size:%d pdu size:%d", len + 1, payload_size); diff --git a/system/stack/gatt/gatt_sr_hash.cc b/system/stack/gatt/gatt_sr_hash.cc index a7df0c51ca36b429681fe706eb2b68c60ca4949d..660ffe1172b92579379ec2765b46646b1fae9026 100644 --- a/system/stack/gatt/gatt_sr_hash.cc +++ b/system/stack/gatt/gatt_sr_hash.cc @@ -21,8 +21,9 @@ #include +#include "crypto_toolbox/crypto_toolbox.h" #include "gatt_int.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" +#include "stack/include/bt_types.h" #include "types/bluetooth/uuid.h" using bluetooth::Uuid; diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc index e833d4343d313ef9ee660ef018242e230c13aaf7..0e8bf7e6aeb3492c776794924061c16360df389f 100644 --- a/system/stack/gatt/gatt_utils.cc +++ b/system/stack/gatt/gatt_utils.cc @@ -29,16 +29,19 @@ #include #include -#include "bt_target.h" // Must be first to define build configuration +#include "hardware/bt_gatt_types.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "rust/src/connection/ffi/connection_shim.h" #include "stack/btm/btm_sec.h" #include "stack/eatt/eatt.h" #include "stack/gatt/connection_manager.h" #include "stack/gatt/gatt_int.h" -#include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/l2cdefs.h" #include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" @@ -46,6 +49,8 @@ uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr); +using namespace bluetooth::legacy::stack::sdp; + using base::StringPrintf; using bluetooth::Uuid; using bluetooth::eatt::EattExtension; @@ -89,6 +94,16 @@ const char* const op_code_name[] = {"UNKNOWN", "ATT_HANDLE_VALUE_CONF", "ATT_OP_CODE_MAX"}; +uint16_t gatt_get_local_mtu(void) { + /* Default ATT MTU must not be greater than GATT_MAX_MTU_SIZE, nor smaller + * than GATT_DEF_BLE_MTU_SIZE */ + const static uint16_t ATT_MTU_DEFAULT = + std::max(std::min(bluetooth::common::init_flags::get_att_mtu_default(), + GATT_MAX_MTU_SIZE), + GATT_DEF_BLE_MTU_SIZE); + return ATT_MTU_DEFAULT; +} + /******************************************************************************* * * Function gatt_free_pending_ind @@ -851,7 +866,7 @@ tGATT_STATUS gatt_send_error_rsp(tGATT_TCB& tcb, uint16_t cid, uint8_t err_code, msg.error.reason = err_code; msg.error.handle = handle; - uint16_t payload_size = gatt_tcb_get_payload_size_tx(tcb, cid); + uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid); p_buf = attp_build_sr_msg(tcb, GATT_RSP_ERROR, &msg, payload_size); if (p_buf != NULL) { status = attp_send_sr_msg(tcb, cid, p_buf); @@ -881,13 +896,14 @@ uint32_t gatt_add_sdp_record(const Uuid& uuid, uint16_t start_hdl, VLOG(1) << __func__ << StringPrintf(" s_hdl=0x%x s_hdl=0x%x", start_hdl, end_hdl); - uint32_t sdp_handle = SDP_CreateRecord(); + uint32_t sdp_handle = get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); if (sdp_handle == 0) return 0; switch (uuid.GetShortestRepresentationSize()) { case Uuid::kNumBytes16: { uint16_t tmp = uuid.As16Bit(); - SDP_AddServiceClassIdList(sdp_handle, 1, &tmp); + get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList(sdp_handle, + 1, &tmp); break; } @@ -895,16 +911,18 @@ uint32_t gatt_add_sdp_record(const Uuid& uuid, uint16_t start_hdl, UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES); uint32_t tmp = uuid.As32Bit(); UINT32_TO_BE_STREAM(p, tmp); - SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, - DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - buff), buff); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, DATA_ELE_SEQ_DESC_TYPE, + (uint32_t)(p - buff), buff); break; } case Uuid::kNumBytes128: UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES); ARRAY_TO_BE_STREAM(p, uuid.To128BitBE().data(), (int)Uuid::kNumBytes128); - SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, - DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - buff), buff); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, DATA_ELE_SEQ_DESC_TYPE, + (uint32_t)(p - buff), buff); break; } @@ -918,11 +936,13 @@ uint32_t gatt_add_sdp_record(const Uuid& uuid, uint16_t start_hdl, proto_elem_list[1].params[0] = start_hdl; proto_elem_list[1].params[1] = end_hdl; - SDP_AddProtocolList(sdp_handle, 2, proto_elem_list); + get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList(sdp_handle, 2, + proto_elem_list); /* Make the service browseable */ uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; - SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list); + get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence( + sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list); return (sdp_handle); } @@ -991,7 +1011,11 @@ bool gatt_tcb_is_cid_busy(tGATT_TCB& tcb, uint16_t cid) { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); - if (!channel) return false; + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return false; + } return !channel->cl_cmd_q_.empty(); } @@ -1119,39 +1143,26 @@ uint16_t gatt_tcb_get_att_cid(tGATT_TCB& tcb, bool eatt_support) { /******************************************************************************* * - * Function gatt_tcb_get_payload_size_tx - * - * Description This function gets payload size for the GATT operation - * - * Returns Payload size for sending data - * - ******************************************************************************/ -uint16_t gatt_tcb_get_payload_size_tx(tGATT_TCB& tcb, uint16_t cid) { - if (!tcb.eatt || (cid == tcb.att_lcid)) return tcb.payload_size; - - EattChannel* channel = - EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); - - return channel->tx_mtu_; -} - -/******************************************************************************* - * - * Function gatt_tcb_get_payload_size_rx + * Function gatt_tcb_get_payload_size * * Description This function gets payload size for the GATT operation * - * Returns Payload size for receiving data + * Returns Payload size for sending/receiving data * ******************************************************************************/ - -uint16_t gatt_tcb_get_payload_size_rx(tGATT_TCB& tcb, uint16_t cid) { +uint16_t gatt_tcb_get_payload_size(tGATT_TCB& tcb, uint16_t cid) { if (!tcb.eatt || (cid == tcb.att_lcid)) return tcb.payload_size; EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return 0; + } - return channel->rx_mtu_; + /* ATT MTU for EATT is min from tx and rx mtu*/ + return std::min(channel->tx_mtu_, channel->rx_mtu_); } /******************************************************************************* @@ -1208,6 +1219,8 @@ void gatt_clcb_invalidate(tGATT_TCB* p_tcb, const tGATT_CLCB* p_clcb) { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid( p_tcb->peer_bda, cid); if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(p_tcb->peer_bda), cid); return; } cl_cmd_q_p = &channel->cl_cmd_q_; @@ -1354,6 +1367,11 @@ void gatt_sr_reset_cback_cnt(tGATT_TCB& tcb, uint16_t cid) { } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return; + } channel->server_outstanding_cmd_.cback_cnt[i] = 0; } } @@ -1384,6 +1402,12 @@ tGATT_SR_CMD* gatt_sr_get_cmd_by_cid(tGATT_TCB& tcb, uint16_t cid) { } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return nullptr; + } + sr_cmd_p = &channel->server_outstanding_cmd_; } @@ -1400,6 +1424,11 @@ tGATT_READ_MULTI* gatt_sr_get_read_multi(tGATT_TCB& tcb, uint16_t cid) { } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return nullptr; + } read_multi_p = &channel->server_outstanding_cmd_.multi_req; } @@ -1425,6 +1454,11 @@ void gatt_sr_update_cback_cnt(tGATT_TCB& tcb, uint16_t cid, tGATT_IF gatt_if, } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return; + } sr_cmd_p = &channel->server_outstanding_cmd_; } @@ -1519,7 +1553,7 @@ bool gatt_cancel_open(tGATT_IF gatt_if, const RawAddress& bda) { } /** Enqueue this command */ -void gatt_cmd_enq(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, bool to_send, +bool gatt_cmd_enq(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, bool to_send, uint8_t op_code, BT_HDR* p_buf) { tGATT_CMD_Q cmd; cmd.to_send = to_send; /* waiting to be sent */ @@ -1533,9 +1567,15 @@ void gatt_cmd_enq(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, bool to_send, } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cmd.cid); - CHECK(channel); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cmd.cid); + return false; + } channel->cl_cmd_q_.push_back(cmd); } + + return true; } /** dequeue the command in the client CCB command queue */ @@ -1547,7 +1587,12 @@ tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB& tcb, uint16_t cid, uint8_t* p_op_code) { } else { EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); - CHECK(channel); + if (channel == nullptr) { + LOG_WARN("%s, cid 0x%02x already disconnected", + ADDRESS_TO_LOGGABLE_CSTR(tcb.peer_bda), cid); + return nullptr; + } + cl_cmd_q_p = &channel->cl_cmd_q_; } diff --git a/system/stack/hcic/hciblecmds.cc b/system/stack/hcic/hciblecmds.cc index 7a363a81604613c0790d004dede70be6b0d06c81..a17c78b99476baa4b856b847dfbf8aa6d0e1abce 100644 --- a/system/stack/hcic/hciblecmds.cc +++ b/system/stack/hcic/hciblecmds.cc @@ -29,13 +29,14 @@ #include -#include "bt_target.h" -#include "btu.h" #include "hcidefs.h" #include "hcimsgs.h" +#include "internal_include/bt_target.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/btu_hcif.h" #include "types/raw_address.h" /******************************************************************************* @@ -109,34 +110,6 @@ #define HCIC_PARAM_SIZE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMS 8 #define HCIC_PARAM_SIZE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMS 8 -void btsnd_hcic_ble_set_local_used_feat(uint8_t feat_set[8]) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_USED_FEAT_CMD; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_WRITE_LOCAL_SPT_FEAT); - ARRAY_TO_STREAM(pp, feat_set, HCIC_PARAM_SIZE_SET_USED_FEAT_CMD); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - -void btsnd_hcic_ble_set_random_addr(const RawAddress& random_bda) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_WRITE_RANDOM_ADDR); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD); - - BDADDR_TO_STREAM(pp, random_bda); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - void btsnd_hcic_ble_write_adv_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type, tBLE_ADDR_TYPE addr_type_own, @@ -199,29 +172,6 @@ void btsnd_hcic_ble_set_adv_data(uint8_t data_len, uint8_t* p_data) { } btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -void btsnd_hcic_ble_set_scan_rsp_data(uint8_t data_len, uint8_t* p_scan_rsp) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_WRITE_SCAN_RSP_DATA); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1); - - memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP); - - if (p_scan_rsp != NULL && data_len > 0) { - if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP) - data_len = HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP; - - UINT8_TO_STREAM(pp, data_len); - - ARRAY_TO_STREAM(pp, p_scan_rsp, data_len); - } - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} void btsnd_hcic_ble_set_adv_enable(uint8_t adv_enable) { BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); @@ -274,56 +224,6 @@ void btsnd_hcic_ble_set_scan_enable(uint8_t scan_enable, uint8_t duplicate) { btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -/* link layer connection management commands */ -void btsnd_hcic_ble_create_ll_conn(uint16_t scan_int, uint16_t scan_win, - uint8_t init_filter_policy, - tBLE_ADDR_TYPE addr_type_peer, - const RawAddress& bda_peer, - tBLE_ADDR_TYPE addr_type_own, - uint16_t conn_int_min, uint16_t conn_int_max, - uint16_t conn_latency, uint16_t conn_timeout, - uint16_t min_ce_len, uint16_t max_ce_len) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_CREATE_LL_CONN); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN); - - UINT16_TO_STREAM(pp, scan_int); - UINT16_TO_STREAM(pp, scan_win); - UINT8_TO_STREAM(pp, init_filter_policy); - - UINT8_TO_STREAM(pp, addr_type_peer); - BDADDR_TO_STREAM(pp, bda_peer); - UINT8_TO_STREAM(pp, addr_type_own); - - UINT16_TO_STREAM(pp, conn_int_min); - UINT16_TO_STREAM(pp, conn_int_max); - UINT16_TO_STREAM(pp, conn_latency); - UINT16_TO_STREAM(pp, conn_timeout); - - UINT16_TO_STREAM(pp, min_ce_len); - UINT16_TO_STREAM(pp, max_ce_len); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - -void btsnd_hcic_ble_create_conn_cancel(void) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_CREATE_CONN_CANCEL); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - void btsnd_hcic_ble_upd_ll_conn_params(uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency, @@ -351,37 +251,6 @@ void btsnd_hcic_ble_upd_ll_conn_params(uint16_t handle, uint16_t conn_int_min, btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -void btsnd_hcic_ble_set_host_chnl_class( - uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE]) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_SET_HOST_CHNL_CLASS); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS); - - ARRAY_TO_STREAM(pp, chnl_map, HCIC_BLE_CHNL_MAP_SIZE); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - -void btsnd_hcic_ble_read_chnl_map(uint16_t handle) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CHNL_MAP; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_READ_CHNL_MAP); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CHNL_MAP); - - UINT16_TO_STREAM(pp, handle); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - void btsnd_hcic_ble_read_remote_feat(uint16_t handle) { BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); uint8_t* pp = (uint8_t*)(p + 1); @@ -460,14 +329,47 @@ void btsnd_hcic_ble_ltk_req_neg_reply(uint16_t handle) { btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -void btsnd_hcic_ble_read_host_supported(void) { +void btsnd_hcic_ble_receiver_test(uint8_t rx_freq) { + BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); + uint8_t* pp = (uint8_t*)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM(pp, HCI_BLE_RECEIVER_TEST); + UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM(pp, rx_freq); + + btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); +} + +void btsnd_hcic_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len, + uint8_t payload) { + BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); + uint8_t* pp = (uint8_t*)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3; + p->offset = 0; + + UINT16_TO_STREAM(pp, HCI_BLE_TRANSMITTER_TEST); + UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM3); + + UINT8_TO_STREAM(pp, tx_freq); + UINT8_TO_STREAM(pp, test_data_len); + UINT8_TO_STREAM(pp, payload); + + btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); +} + +void btsnd_hcic_ble_test_end(void) { BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); uint8_t* pp = (uint8_t*)(p + 1); p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; p->offset = 0; - UINT16_TO_STREAM(pp, HCI_READ_LE_HOST_SUPPORT); + UINT16_TO_STREAM(pp, HCI_BLE_TEST_END); UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CMD); btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); @@ -531,36 +433,6 @@ void btsnd_hcic_ble_read_resolvable_addr_peer(uint8_t addr_type_peer, btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -void btsnd_hcic_ble_read_resolvable_addr_local(uint8_t addr_type_peer, - const RawAddress& bda_peer) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL); - UINT8_TO_STREAM(pp, addr_type_peer); - BDADDR_TO_STREAM(pp, bda_peer); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - -void btsnd_hcic_ble_set_addr_resolution_enable(uint8_t addr_resolution_enable) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_BLE_SET_ADDR_RESOLUTION_ENABLE); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE); - UINT8_TO_STREAM(pp, addr_resolution_enable); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - void btsnd_hcic_ble_set_rand_priv_addr_timeout(uint16_t rpa_timout) { BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); uint8_t* pp = (uint8_t*)(p + 1); @@ -681,61 +553,6 @@ void btsnd_hcic_ble_set_extended_scan_enable(uint8_t enable, btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -void btsnd_hcic_ble_ext_create_conn(uint8_t init_filter_policy, - tBLE_ADDR_TYPE addr_type_own, - tBLE_ADDR_TYPE addr_type_peer, - const RawAddress& bda_peer, - uint8_t initiating_phys, - EXT_CONN_PHY_CFG* phy_cfg) { - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - int phy_cnt = - std::bitset::digits>(initiating_phys) - .count(); - - /* param_len = initial_params + size_per_channel * num_of_channels */ - uint8_t param_len = 10 + (16 * phy_cnt); - - p->len = HCIC_PREAMBLE_SIZE + param_len; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_LE_EXTENDED_CREATE_CONNECTION); - UINT8_TO_STREAM(pp, param_len); - - UINT8_TO_STREAM(pp, init_filter_policy); - UINT8_TO_STREAM(pp, addr_type_own); - UINT8_TO_STREAM(pp, addr_type_peer); - BDADDR_TO_STREAM(pp, bda_peer); - - UINT8_TO_STREAM(pp, initiating_phys); - - for (int i = 0; i < phy_cnt; i++) { - UINT16_TO_STREAM(pp, phy_cfg[i].scan_int); - UINT16_TO_STREAM(pp, phy_cfg[i].scan_win); - UINT16_TO_STREAM(pp, phy_cfg[i].conn_int_min); - UINT16_TO_STREAM(pp, phy_cfg[i].conn_int_max); - UINT16_TO_STREAM(pp, phy_cfg[i].conn_latency); - UINT16_TO_STREAM(pp, phy_cfg[i].sup_timeout); - UINT16_TO_STREAM(pp, phy_cfg[i].min_ce_len); - UINT16_TO_STREAM(pp, phy_cfg[i].max_ce_len); - } - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); -} - -void btsnd_hcic_read_iso_tx_sync( - uint16_t iso_handle, base::OnceCallback cb) { - const int params_len = 2; - uint8_t param[params_len]; - uint8_t* pp = param; - - UINT16_TO_STREAM(pp, iso_handle); - - btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_LE_READ_ISO_TX_SYNC, param, - params_len, std::move(cb)); -} - void btsnd_hcic_set_cig_params( uint8_t cig_id, uint32_t sdu_itv_mtos, uint32_t sdu_itv_stom, uint8_t sca, uint8_t packing, uint8_t framing, uint16_t max_trans_lat_stom, @@ -893,18 +710,6 @@ void btsnd_hcic_term_big(uint8_t big_handle, uint8_t reason) { btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -void btsnd_hcic_big_term_sync(uint8_t big_handle, - base::OnceCallback cb) { - const int params_len = 1; - uint8_t param[params_len]; - uint8_t* pp = param; - - UINT8_TO_STREAM(pp, big_handle); - - btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_LE_BIG_TERM_SYNC, param, params_len, - std::move(cb)); -} - void btsnd_hcic_setup_iso_data_path( uint16_t iso_handle, uint8_t data_path_dir, uint8_t data_path_id, uint8_t codec_id_format, uint16_t codec_id_company, @@ -1036,13 +841,6 @@ void btsnd_hci_ble_clear_periodic_advertiser_list( HCIC_PARAM_SIZE_CLEAR_PERIODIC_ADVERTISER_LIST, std::move(cb)); } -void btsnd_hci_ble_read_periodic_advertiser_list_size( - base::OnceCallback cb) { - btu_hcif_send_cmd_with_cb( - FROM_HERE, HCI_BLE_READ_PERIODIC_ADVERTISER_LIST_SIZE, nullptr, - HCIC_PARAM_SIZE_READ_PERIODIC_ADVERTISER_LIST_SIZE, std::move(cb)); -} - void btsnd_hcic_ble_set_periodic_advertising_receive_enable( uint16_t sync_handle, bool enable, base::OnceCallback cb) { diff --git a/system/stack/hcic/hcicmds.cc b/system/stack/hcic/hcicmds.cc index c49cd713ba24c9c066812fc8b8f4c9c84af9d468..40b008b8369d28f8a6fde9d38bfdfe7be777c605 100644 --- a/system/stack/hcic/hcicmds.cc +++ b/system/stack/hcic/hcicmds.cc @@ -23,26 +23,23 @@ * ******************************************************************************/ +#include #include -#include #include #include "bt_target.h" -#include "btu.h" -#include "device/include/device_iot_config.h" #include "device/include/esco_parameters.h" -#include "gd/common/init_flags.h" #include "hcidefs.h" #include "hcimsgs.h" #include "main/shim/acl_api.h" #include "osi/include/allocator.h" -#include "stack/include/acl_hci_link_interface.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_lap.h" #include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/btu_hcif.h" #include "types/raw_address.h" -void bte_main_hci_send(BT_HDR* p_msg, uint16_t event); - /* Message by message.... */ #define HCIC_PARAM_SIZE_INQUIRY 5 @@ -710,47 +707,12 @@ void btsnd_hcic_set_conn_encrypt(uint16_t handle, bool enable) { void btsnd_hcic_rmt_name_req(const RawAddress& bd_addr, uint8_t page_scan_rep_mode, uint8_t page_scan_mode, uint16_t clock_offset) { - if (bluetooth::common::init_flags::gd_remote_name_request_is_enabled()) { - bluetooth::shim::ACL_RemoteNameRequest(bd_addr, page_scan_rep_mode, - page_scan_mode, clock_offset); - return; - } - - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_RMT_NAME_REQUEST); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_RMT_NAME_REQ); - - BDADDR_TO_STREAM(pp, bd_addr); - UINT8_TO_STREAM(pp, page_scan_rep_mode); - UINT8_TO_STREAM(pp, page_scan_mode); - UINT16_TO_STREAM(pp, clock_offset); - - btm_acl_paging(p, bd_addr); + bluetooth::shim::ACL_RemoteNameRequest(bd_addr, page_scan_rep_mode, + page_scan_mode, clock_offset); } void btsnd_hcic_rmt_name_req_cancel(const RawAddress& bd_addr) { - if (bluetooth::common::init_flags::gd_remote_name_request_is_enabled()) { - bluetooth::shim::ACL_CancelRemoteNameRequest(bd_addr); - return; - } - - BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL; - p->offset = 0; - - UINT16_TO_STREAM(pp, HCI_RMT_NAME_REQUEST_CANCEL); - UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL); - - BDADDR_TO_STREAM(pp, bd_addr); - - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); + bluetooth::shim::ACL_CancelRemoteNameRequest(bd_addr); } void btsnd_hcic_rmt_ext_features(uint16_t handle, uint8_t page_num) { @@ -997,6 +959,47 @@ void btsnd_hcic_write_def_policy_set(uint16_t settings) { btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } +void btsnd_hcic_set_event_filter(uint8_t filt_type, uint8_t filt_cond_type, + uint8_t* filt_cond, uint8_t filt_cond_len) { + BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); + uint8_t* pp = (uint8_t*)(p + 1); + + p->offset = 0; + + UINT16_TO_STREAM(pp, HCI_SET_EVENT_FILTER); + + if (filt_type) { + p->len = (uint16_t)(HCIC_PREAMBLE_SIZE + 2 + filt_cond_len); + UINT8_TO_STREAM(pp, (uint8_t)(2 + filt_cond_len)); + + UINT8_TO_STREAM(pp, filt_type); + UINT8_TO_STREAM(pp, filt_cond_type); + + if (filt_cond_type == HCI_FILTER_COND_DEVICE_CLASS) { + DEVCLASS_TO_STREAM(pp, filt_cond); + filt_cond += DEV_CLASS_LEN; + DEVCLASS_TO_STREAM(pp, filt_cond); + filt_cond += DEV_CLASS_LEN; + + filt_cond_len -= (2 * DEV_CLASS_LEN); + } else if (filt_cond_type == HCI_FILTER_COND_BD_ADDR) { + BDADDR_TO_STREAM(pp, *((RawAddress*)filt_cond)); + filt_cond += BD_ADDR_LEN; + + filt_cond_len -= BD_ADDR_LEN; + } + + if (filt_cond_len) ARRAY_TO_STREAM(pp, filt_cond, filt_cond_len); + } else { + p->len = (uint16_t)(HCIC_PREAMBLE_SIZE + 1); + UINT8_TO_STREAM(pp, 1); + + UINT8_TO_STREAM(pp, filt_type); + } + + btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); +} + void btsnd_hcic_write_pin_type(uint8_t type) { BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); uint8_t* pp = (uint8_t*)(p + 1); @@ -1581,6 +1584,19 @@ void btsnd_hcic_read_failed_contact_counter(uint16_t handle) { btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } +void btsnd_hcic_enable_test_mode(void) { + BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); + uint8_t* pp = (uint8_t*)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; + p->offset = 0; + + UINT16_TO_STREAM(pp, HCI_ENABLE_DEV_UNDER_TEST_MODE); + UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CMD); + + btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); +} + void btsnd_hcic_write_inqscan_type(uint8_t type) { BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); uint8_t* pp = (uint8_t*)(p + 1); @@ -1626,31 +1642,31 @@ void btsnd_hcic_write_pagescan_type(uint8_t type) { btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -/* Must have room to store BT_HDR + max VSC length + callback pointer */ -#if (HCI_CMD_BUF_SIZE < 268) -#error "HCI_CMD_BUF_SIZE must be larger than 268" -#endif - -void btsnd_hcic_vendor_spec_cmd(void* buffer, uint16_t opcode, uint8_t len, - uint8_t* p_data, void* p_cmd_cplt_cback) { - BT_HDR* p = (BT_HDR*)buffer; - uint8_t* pp = (uint8_t*)(p + 1); - - p->len = HCIC_PREAMBLE_SIZE + len; - p->offset = sizeof(void*); - - *((void**)pp) = - p_cmd_cplt_cback; /* Store command complete callback in buffer */ - pp += sizeof(void*); /* Skip over callback pointer */ +static void btsnd_hcic_vendor_spec_complete(tBTM_VSC_CMPL_CB* p_vsc_cplt_cback, + uint16_t opcode, uint8_t* data, + uint16_t len) { + /* If there was a callback address for vcs complete, call it */ + if (p_vsc_cplt_cback) { + tBTM_VSC_CMPL vcs_cplt_params; + vcs_cplt_params.opcode = opcode; + vcs_cplt_params.param_len = len; + vcs_cplt_params.p_param_buf = data; + /* Call the VSC complete callback function */ + (*p_vsc_cplt_cback)(&vcs_cplt_params); + } +} - UINT16_TO_STREAM(pp, HCI_GRP_VENDOR_SPECIFIC | opcode); - UINT8_TO_STREAM(pp, len); - ARRAY_TO_STREAM(pp, p_data, len); +void btsnd_hcic_vendor_spec_cmd(uint16_t opcode, uint8_t len, uint8_t* p_data, + tBTM_VSC_CMPL_CB* p_cmd_cplt_cback) { + uint16_t v_opcode = HCI_GRP_VENDOR_SPECIFIC | opcode; - btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); + btu_hcif_send_cmd_with_cb( + FROM_HERE, v_opcode, p_data, len, + base::BindOnce(&btsnd_hcic_vendor_spec_complete, + base::Unretained(p_cmd_cplt_cback), v_opcode)); } -void btsnd_hcic_configure_data_path(uint8_t data_path_direction, +void btsnd_hcic_configure_data_path(hci_data_direction_t data_path_direction, uint8_t data_path_id, std::vector vendor_config) { BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE); @@ -1671,16 +1687,34 @@ void btsnd_hcic_configure_data_path(uint8_t data_path_direction, btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } -bluetooth::legacy::hci::Interface interface_ = { - // LINK_CONTROL - .StartInquiry = btsnd_hcic_inquiry, // OCF 0x0401 - .InquiryCancel = btsnd_hcic_inq_cancel, // OCF 0x0402 - .Disconnect = btsnd_hcic_disconnect, // OCF 0x0406 - .ChangeConnectionPacketType = btsnd_hcic_change_conn_type, // OCF 0x040F, - .StartRoleSwitch = btsnd_hcic_switch_role, // OCF 0x080B, +namespace bluetooth::legacy::hci { +class InterfaceImpl : public Interface { + void StartInquiry(const uint8_t* inq_lap, uint8_t duration, + uint8_t response_cnt) const override { + btsnd_hcic_inquiry(inq_lap, duration, response_cnt); + } + void InquiryCancel() const override { btsnd_hcic_inq_cancel(); } + void Disconnect(uint16_t handle, uint8_t reason) const override { + btsnd_hcic_disconnect(handle, reason); + } + void ChangeConnectionPacketType(uint16_t handle, + uint16_t packet_types) const override { + btsnd_hcic_change_conn_type(handle, packet_types); + } + void StartRoleSwitch(const RawAddress& bd_addr, uint8_t role) const override { + btsnd_hcic_switch_role(bd_addr, role); + } + void ConfigureDataPath(hci_data_direction_t data_path_direction, + uint8_t data_path_id, + std::vector vendor_config) const override { + btsnd_hcic_configure_data_path(data_path_direction, data_path_id, + vendor_config); + } }; -const bluetooth::legacy::hci::Interface& -bluetooth::legacy::hci::GetInterface() { - return interface_; +namespace { +const InterfaceImpl interface_; } + +const Interface& GetInterface() { return interface_; } +} // namespace bluetooth::legacy::hci diff --git a/system/stack/hid/hid_conn.h b/system/stack/hid/hid_conn.h index 88c754486f5c0afba024b8d2fa8a83cbef245b8c..22e9b9dc8a9aac68bbd79fd0c9ec3fc6c7363c1c 100644 --- a/system/stack/hid/hid_conn.h +++ b/system/stack/hid/hid_conn.h @@ -27,6 +27,7 @@ #include +#include "macros.h" #include "osi/include/alarm.h" typedef enum : uint8_t { @@ -44,10 +45,6 @@ typedef enum : uint8_t { typedef struct hid_conn { tHID_CONN_STATE conn_state; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - static inline std::string state_text(const tHID_CONN_STATE& state) { switch (state) { CASE_RETURN_TEXT(HID_CONN_STATE_UNUSED); @@ -61,7 +58,6 @@ typedef struct hid_conn { return base::StringPrintf("UNKNOWN[%hhu]", state); } } -#undef CASE_RETURN_TEXT #define HID_CONN_FLAGS_IS_ORIG (0x01) #define HID_CONN_FLAGS_CONGESTED (0x20) diff --git a/system/stack/hid/hidd_api.cc b/system/stack/hid/hidd_api.cc index 4281ac81fb599bf079f73760aa4d653363d0f9fe..fad8e977ad077adc4c6dc1cb95bf979bc6b19fb0 100644 --- a/system/stack/hid/hidd_api.cc +++ b/system/stack/hid/hidd_api.cc @@ -23,6 +23,8 @@ * ******************************************************************************/ +#define LOG_TAG "hid" + #include "hidd_api.h" #include @@ -30,16 +32,20 @@ #include #include -#include "btm_api.h" #include "hidd_int.h" #include "hiddefs.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "stack/btm/btm_sec.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" +#include "stack/include/sdpdefs.h" #include "stack/include/stack_metrics_logging.h" -#include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + tHID_DEV_CTB hd_cb; /******************************************************************************* @@ -52,29 +58,9 @@ tHID_DEV_CTB hd_cb; * ******************************************************************************/ void HID_DevInit(void) { - uint8_t log_level = hd_cb.trace_level; - - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); memset(&hd_cb, 0, sizeof(tHID_DEV_CTB)); - hd_cb.trace_level = log_level; -} - -/******************************************************************************* - * - * Function HID_DevSetTraceLevel - * - * Description This function sets the trace level for HID Dev. If called -*with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t HID_DevSetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) hd_cb.trace_level = new_level; - - return (hd_cb.trace_level); } /******************************************************************************* @@ -89,7 +75,7 @@ uint8_t HID_DevSetTraceLevel(uint8_t new_level) { tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) { tHID_STATUS st; - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (hd_cb.reg_flag) { log_counter_metrics( @@ -130,7 +116,7 @@ tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) { * ******************************************************************************/ tHID_STATUS HID_DevDeregister(void) { - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!hd_cb.reg_flag) { log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: @@ -160,12 +146,13 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, uint16_t desc_len, uint8_t* p_desc_data) { bool result = TRUE; - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); // Service Class ID List if (result) { uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE; - result &= SDP_AddServiceClassIdList(handle, 1, &uuid); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList( + handle, 1, &uuid); } // Protocol Descriptor List @@ -179,14 +166,15 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP; proto_list[1].num_params = 0; - result &= SDP_AddProtocolList(handle, 2, proto_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList( + handle, 2, proto_list); } // Language Base Attribute ID List if (result) { - result &= SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH, - LANG_ID_CHAR_ENCODE_UTF8, - LANGUAGE_BASE_ID); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddLanguageBaseAttrIDList( + handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8, + LANGUAGE_BASE_ID); } // Additional Protocol Descriptor List @@ -200,7 +188,8 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP; add_proto_list.list_elem[1].num_params = 0; - result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAdditionProtoLists( + handle, 1, &add_proto_list); } // Service Name (O) @@ -211,16 +200,17 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, const char* srv_desc = p_description; const char* provider_name = p_provider; - result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, - strlen(srv_name) + 1, (uint8_t*)srv_name); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, strlen(srv_name) + 1, + (uint8_t*)srv_name); - result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION, - TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1, - (uint8_t*)srv_desc); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE, + strlen(srv_desc) + 1, (uint8_t*)srv_desc); - result &= - SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, - strlen(provider_name) + 1, (uint8_t*)provider_name); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, + strlen(provider_name) + 1, (uint8_t*)provider_name); } // Bluetooth Profile Descriptor List @@ -228,7 +218,8 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE; const uint16_t version = 0x0100; - result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList( + handle, profile_uuid, version); } // HID Parser Version @@ -245,25 +236,29 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, p = (uint8_t*)&temp; UINT16_TO_BE_STREAM(p, rel_num); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM, - UINT_DESC_TYPE, 2, (uint8_t*)&temp); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_DEVICE_RELNUM, UINT_DESC_TYPE, 2, (uint8_t*)&temp); p = (uint8_t*)&temp; UINT16_TO_BE_STREAM(p, parser_version); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION, - UINT_DESC_TYPE, 2, (uint8_t*)&temp); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_PARSER_VERSION, UINT_DESC_TYPE, 2, (uint8_t*)&temp); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS, - UINT_DESC_TYPE, 1, (uint8_t*)&dev_subclass); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_DEVICE_SUBCLASS, UINT_DESC_TYPE, 1, + (uint8_t*)&dev_subclass); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE, - 1, (uint8_t*)&country_code); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE, 1, + (uint8_t*)&country_code); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE, - BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_VIRTUAL_CABLE, BOOLEAN_DESC_TYPE, 1, + (uint8_t*)&bool_true); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE, - BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_RECONNECT_INITIATE, BOOLEAN_DESC_TYPE, 1, + (uint8_t*)&bool_true); { static uint8_t cdt = 0x22; @@ -271,8 +266,8 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, uint8_t seq_len = 4 + desc_len; if (desc_len > HIDD_APP_DESCRIPTOR_LEN) { - HIDD_TRACE_ERROR("%s: descriptor length = %d, larger than max %d", - __func__, desc_len, HIDD_APP_DESCRIPTOR_LEN); + LOG_ERROR("%s: descriptor length = %d, larger than max %d", __func__, + desc_len, HIDD_APP_DESCRIPTOR_LEN); log_counter_metrics( android::bluetooth::CodePathCounterKeyEnum:: HIDD_ERR_NOT_REGISTERED_DUE_TO_DESCRIPTOR_LENGTH, @@ -283,8 +278,7 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, p_buf = (uint8_t*)osi_malloc(HIDD_APP_DESCRIPTOR_LEN + 6); if (p_buf == NULL) { - HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ", - __func__); + LOG_ERROR("%s: Buffer allocation failure for size = 2048 ", __func__); log_counter_metrics( android::bluetooth::CodePathCounterKeyEnum:: HIDD_ERR_NOT_REGISTERED_DUE_TO_BUFFER_ALLOCATION, @@ -305,8 +299,9 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, UINT8_TO_BE_STREAM(p, desc_len); ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST, - DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_DESCRIPTOR_LIST, DATA_ELE_SEQ_DESC_TYPE, + p - p_buf, p_buf); osi_free(p_buf); } @@ -322,37 +317,42 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, UINT16_TO_BE_STREAM(p, lang_english); UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID); - result &= - SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE, - DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_LANGUAGE_ID_BASE, DATA_ELE_SEQ_DESC_TYPE, + p - lang_buf, lang_buf); } - result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER, - BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_BATTERY_POWER, BOOLEAN_DESC_TYPE, 1, + (uint8_t*)&bool_true); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE, - BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_false); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_REMOTE_WAKE, BOOLEAN_DESC_TYPE, 1, + (uint8_t*)&bool_false); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE, - BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_NORMALLY_CONNECTABLE, BOOLEAN_DESC_TYPE, 1, + (uint8_t*)&bool_true); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE, - BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_BOOT_DEVICE, BOOLEAN_DESC_TYPE, 1, + (uint8_t*)&bool_true); p = (uint8_t*)&temp; UINT16_TO_BE_STREAM(p, prof_ver); - result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION, - UINT_DESC_TYPE, 2, (uint8_t*)&temp); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + handle, ATTR_ID_HID_PROFILE_VERSION, UINT_DESC_TYPE, 2, + (uint8_t*)&temp); } if (result) { uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; - result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1, - &browse_group); + result &= get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence( + handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_group); } if (!result) { - HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__); + LOG_ERROR("%s: failed to complete SDP record", __func__); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: HIDD_ERR_NOT_REGISTERED_AT_SDP, 1); @@ -373,8 +373,8 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, ******************************************************************************/ tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id, uint16_t len, uint8_t* p_data) { - HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel, - type, id, len); + LOG_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel, type, + id, len); if (channel == HID_CHANNEL_CTRL) { return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len, @@ -402,7 +402,7 @@ tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id, * ******************************************************************************/ tHID_STATUS HID_DevVirtualCableUnplug(void) { - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL, HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL); @@ -549,7 +549,7 @@ tHID_STATUS HID_DevSetIncomingPolicy(bool allow) { tHID_STATUS HID_DevReportError(uint8_t error) { uint8_t handshake_param; - HIDD_TRACE_API("%s: error = %d", __func__, error); + LOG_VERBOSE("%s: error = %d", __func__, error); switch (error) { case HID_PAR_HANDSHAKE_RSP_SUCCESS: @@ -580,7 +580,7 @@ tHID_STATUS HID_DevReportError(uint8_t error) { * ******************************************************************************/ tHID_STATUS HID_DevGetDevice(RawAddress* addr) { - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (hd_cb.device.in_use) { *addr = hd_cb.device.addr; @@ -607,7 +607,7 @@ tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation) { - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); hd_cb.use_in_qos = TRUE; @@ -634,7 +634,7 @@ tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation) { - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); hd_cb.l2cap_intr_cfg.qos_present = TRUE; diff --git a/system/stack/hid/hidd_conn.cc b/system/stack/hid/hidd_conn.cc index 56d3073e529b8cac8a126739f1be58839db3a6e8..9b9129f19b60db7746ab154d5fdd6158cbee546d 100644 --- a/system/stack/hid/hidd_conn.cc +++ b/system/stack/hid/hidd_conn.cc @@ -29,13 +29,14 @@ #include -#include "bta/include/bta_api.h" -#include "btif/include/btif_hd.h" -#include "gd/common/init_flags.h" +#include "bta/include/bta_sec_api.h" +#include "common/init_flags.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "stack/hid/hidd_int.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/stack_metrics_logging.h" #include "types/raw_address.h" @@ -106,13 +107,12 @@ static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid, tHID_DEV_DEV_CTB* p_dev; bool accept = TRUE; // accept by default - HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x", __func__, psm, cid); + LOG_VERBOSE("%s: psm=%04x cid=%04x", __func__, psm, cid); p_dev = &hd_cb.device; if (!hd_cb.allow_incoming) { - HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting", - __func__); + LOG_WARN("%s: incoming connections not allowed, rejecting", __func__); L2CA_DisconnectReq(cid); return; @@ -124,14 +124,13 @@ static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid, case HID_PSM_INTERRUPT: if (p_hcon->ctrl_cid == 0) { accept = FALSE; - HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting", - __func__); + LOG_WARN("%s: incoming INTR without CTRL, rejecting", __func__); } if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) { accept = FALSE; - HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting", - __func__, p_hcon->conn_state); + LOG_WARN("%s: incoming INTR in invalid state (%d), rejecting", __func__, + p_hcon->conn_state); } break; @@ -139,15 +138,15 @@ static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid, case HID_PSM_CONTROL: if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) { accept = FALSE; - HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting", - __func__, p_hcon->conn_state); + LOG_WARN("%s: incoming CTRL in invalid state (%d), rejecting", __func__, + p_hcon->conn_state); } break; default: accept = FALSE; - HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__); + LOG_ERROR("%s: received invalid PSM, rejecting", __func__); break; } @@ -177,8 +176,7 @@ static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid, } static void hidd_on_l2cap_error(uint16_t lcid, uint16_t result) { - HIDD_TRACE_WARNING("%s: connection of config failed, now disconnect", - __func__); + LOG_WARN("%s: connection of config failed, now disconnect", __func__); hidd_conn_disconnect(); @@ -199,10 +197,10 @@ static void hidd_on_l2cap_error(uint16_t lcid, uint16_t result) { static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) { tHID_CONN* p_hcon = &hd_cb.device.conn; - HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result); + LOG_VERBOSE("%s: cid=%04x result=%d", __func__, cid, result); if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + LOG_WARN("%s: unknown cid", __func__); return; } @@ -211,7 +209,7 @@ static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) { (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) || ((cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR))) { - HIDD_TRACE_WARNING("%s: unexpected", __func__); + LOG_WARN("%s: unexpected", __func__); return; } @@ -241,12 +239,12 @@ static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) { * ******************************************************************************/ static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) { - HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid); + LOG_VERBOSE("%s: cid=%04x", __func__, cid); tHID_CONN* p_hcon = &hd_cb.device.conn; if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + LOG_WARN("%s: unknown cid", __func__); return; } @@ -269,13 +267,12 @@ static void hidd_l2cif_config_cfm(uint16_t cid, uint16_t initiator, tL2CAP_CFG_INFO* p_cfg) { hidd_l2cif_config_ind(cid, p_cfg); - - HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid); + LOG_VERBOSE("%s: cid=%04x", __func__, cid); tHID_CONN* p_hcon = &hd_cb.device.conn; if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + LOG_WARN("%s: unknown cid", __func__); return; } @@ -289,8 +286,7 @@ static void hidd_l2cif_config_cfm(uint16_t cid, uint16_t initiator, hidd_conn_disconnect(); p_hcon->conn_state = HID_CONN_STATE_UNUSED; - HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", - __func__); + LOG_WARN("%s: could not start L2CAP connection for INTR", __func__); hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: @@ -316,14 +312,13 @@ static void hidd_l2cif_config_cfm(uint16_t cid, uint16_t initiator, * ******************************************************************************/ static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) { - - HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed); + LOG_VERBOSE("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed); tHID_CONN* p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + LOG_WARN("%s: unknown cid", __func__); return; } @@ -335,7 +330,7 @@ static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) { p_hcon->intr_cid = 0; if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) { - HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__); + LOG_VERBOSE("%s: INTR and CTRL disconnected", __func__); // clean any outstanding data on intr if (hd_cb.pending_data) { @@ -354,13 +349,13 @@ static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) { static void hidd_l2cif_disconnect(uint16_t cid) { L2CA_DisconnectReq(cid); - HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid); + LOG_VERBOSE("%s: cid=%04x", __func__, cid); tHID_CONN* p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + LOG_WARN("%s: unknown cid", __func__); return; } @@ -378,7 +373,7 @@ static void hidd_l2cif_disconnect(uint16_t cid) { } if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) { - HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__); + LOG_VERBOSE("%s: INTR and CTRL disconnected", __func__); hd_cb.device.state = HIDD_DEV_NO_CONN; p_hcon->conn_state = HID_CONN_STATE_UNUSED; @@ -404,14 +399,13 @@ static void hidd_l2cif_disconnect(uint16_t cid) { * ******************************************************************************/ static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) { - - HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested); + LOG_VERBOSE("%s: cid=%04x congested=%d", __func__, cid, congested); tHID_CONN* p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + LOG_WARN("%s: unknown cid", __func__); return; } @@ -436,10 +430,10 @@ static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) { uint8_t msg_type, param; bool err = FALSE; - HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid); + LOG_VERBOSE("%s: cid=%04x", __func__, cid); if (p_msg->len < 1) { - HIDD_TRACE_ERROR("Invalid data length, ignore"); + LOG_ERROR("Invalid data length, ignore"); osi_free(p_msg); return; } @@ -448,7 +442,7 @@ static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) { if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + LOG_WARN("%s: unknown cid", __func__); osi_free(p_msg); return; } @@ -487,17 +481,15 @@ static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) { case HID_TRANS_SET_IDLE: if (p_msg->len != 2) { - HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received", - __func__, p_msg->len); + LOG_ERROR("%s: invalid len (%d) set idle request received", __func__, + p_msg->len); err = TRUE; } else { hd_cb.device.idle_time = p_data[1]; - HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__, - hd_cb.device.idle_time); + LOG_VERBOSE("%s: idle_time = %d", __func__, hd_cb.device.idle_time); if (hd_cb.device.idle_time) { - HIDD_TRACE_WARNING( - "%s: idle_time of %d ms not supported by HID Device", __func__, - (hd_cb.device.idle_time * 4)); + LOG_WARN("%s: idle_time of %d ms not supported by HID Device", + __func__, (hd_cb.device.idle_time * 4)); err = TRUE; } } @@ -552,7 +544,7 @@ static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) { case HID_TRANS_DATA: default: - HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type); + LOG_WARN("%s: got unsupported msg (%d)", __func__, msg_type); hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0, NULL); @@ -571,7 +563,7 @@ static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) { * ******************************************************************************/ tHID_STATUS hidd_conn_reg(void) { - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO)); @@ -584,7 +576,7 @@ tHID_STATUS hidd_conn_reg(void) { if (!L2CA_Register2(HID_PSM_CONTROL, dev_reg_info, false /* enable_snoop */, nullptr, HID_DEV_MTU_SIZE, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { - HIDD_TRACE_ERROR("HID Control (device) registration failed"); + LOG_ERROR("HID Control (device) registration failed"); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: HIDD_ERR_L2CAP_FAILED_CONTROL, 1); @@ -595,7 +587,7 @@ tHID_STATUS hidd_conn_reg(void) { nullptr, HID_DEV_MTU_SIZE, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { L2CA_Deregister(HID_PSM_CONTROL); - HIDD_TRACE_ERROR("HID Interrupt (device) registration failed"); + LOG_ERROR("HID Interrupt (device) registration failed"); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: HIDD_ERR_L2CAP_FAILED_INTERRUPT, 1); @@ -615,7 +607,7 @@ tHID_STATUS hidd_conn_reg(void) { * ******************************************************************************/ void hidd_conn_dereg(void) { - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); L2CA_Deregister(HID_PSM_CONTROL); L2CA_Deregister(HID_PSM_INTERRUPT); @@ -633,10 +625,10 @@ void hidd_conn_dereg(void) { tHID_STATUS hidd_conn_initiate(void) { tHID_DEV_DEV_CTB* p_dev = &hd_cb.device; - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!p_dev->in_use) { - HIDD_TRACE_WARNING("%s: no virtual cable established", __func__); + LOG_WARN("%s: no virtual cable established", __func__); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: HIDD_ERR_NOT_REGISTERED_AT_INITIATE, 1); @@ -644,7 +636,7 @@ tHID_STATUS hidd_conn_initiate(void) { } if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) { - HIDD_TRACE_WARNING("%s: connection already in progress", __func__); + LOG_WARN("%s: connection already in progress", __func__); log_counter_metrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_CONN_IN_PROCESS, 1); @@ -661,7 +653,7 @@ tHID_STATUS hidd_conn_initiate(void) { if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq2(HID_PSM_CONTROL, p_dev->addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) == 0) { - HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__); + LOG_WARN("%s: could not start L2CAP connection", __func__); hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: @@ -684,8 +676,7 @@ tHID_STATUS hidd_conn_initiate(void) { * ******************************************************************************/ tHID_STATUS hidd_conn_disconnect(void) { - - HIDD_TRACE_API("%s", __func__); + LOG_VERBOSE("%s", __func__); // clean any outstanding data on intr if (hd_cb.pending_data) { @@ -708,7 +699,7 @@ tHID_STATUS hidd_conn_disconnect(void) { hidd_l2cif_disconnect(p_hcon->ctrl_cid); } } else { - HIDD_TRACE_WARNING("%s: already disconnected", __func__); + LOG_WARN("%s: already disconnected", __func__); p_hcon->conn_state = HID_CONN_STATE_UNUSED; } @@ -732,8 +723,8 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint16_t cid; uint16_t buf_size; - HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, - channel, msg_type, len); + LOG_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, channel, + msg_type, len); tHID_CONN* p_hcon = &hd_cb.device.conn; @@ -819,10 +810,10 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, #ifdef REPORT_TRANSFER_TIMESTAMP if (report_transfer) { - HIDD_TRACE_ERROR("%s: report sent", __func__); + LOG_ERROR("%s: report sent", __func__); } #endif - HIDD_TRACE_VERBOSE("%s: report sent", __func__); + LOG_VERBOSE("%s: report sent", __func__); if (!L2CA_DataWrite(cid, p_buf)) { log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: diff --git a/system/stack/hid/hidd_int.h b/system/stack/hid/hidd_int.h index b647853e7216557c5fecbed19a3a46b8fcddf486..2d862afcdf65c0f15d67b2662989e8486262a316 100644 --- a/system/stack/hid/hidd_int.h +++ b/system/stack/hid/hidd_int.h @@ -60,7 +60,6 @@ typedef struct dev_ctb { FLOW_SPEC in_qos; bool reg_flag; - uint8_t trace_level; bool allow_incoming; diff --git a/system/stack/hid/hidh_api.cc b/system/stack/hid/hidh_api.cc index f0efd29f433fa00906388ddf41402ef955184f0b..0bb7926a6841f22c55d5af276459a40680584a24 100644 --- a/system/stack/hid/hidh_api.cc +++ b/system/stack/hid/hidh_api.cc @@ -22,6 +22,8 @@ * ******************************************************************************/ +#define LOG_TAG "hidh" + #include "hidh_api.h" #include @@ -29,23 +31,26 @@ #include #include -#include "btif/include/btif_hh.h" -#include "btm_api.h" #include "hiddefs.h" #include "hidh_int.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "stack/btm/btm_dev.h" -#include "stack/btm/btm_sec.h" +#include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/sdpdefs.h" #include "stack/include/stack_metrics_logging.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; using bluetooth::Uuid; tHID_HOST_CTB hh_cb; -static void hidh_search_callback(tSDP_RESULT sdp_result); +static void hidh_search_callback(const RawAddress& bd_addr, + tSDP_RESULT sdp_result); /******************************************************************************* * @@ -67,9 +72,11 @@ tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr, hh_cb.p_sdp_db = p_db; Uuid uuid_list = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE); - SDP_InitDiscoveryDb(p_db, db_len, 1, &uuid_list, 0, NULL); + get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb(p_db, db_len, 1, + &uuid_list, 0, NULL); - if (SDP_ServiceSearchRequest(addr, p_db, hidh_search_callback)) { + if (get_legacy_stack_sdp_api()->service.SDP_ServiceSearchRequest( + addr, p_db, hidh_search_callback)) { hh_cb.sdp_cback = sdp_cback; hh_cb.sdp_busy = true; return HID_SUCCESS; @@ -86,7 +93,8 @@ void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len, tSDP_DISC_ATTR* p_attr; uint16_t name_len; - p_attr = SDP_FindAttributeInRec(p_rec, attr_id); + p_attr = + get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(p_rec, attr_id); if (p_attr != NULL) { if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) { name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); @@ -105,7 +113,8 @@ void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len, str[0] = '\0'; } -static void hidh_search_callback(tSDP_RESULT sdp_result) { +static void hidh_search_callback(UNUSED_ATTR const RawAddress& bd_addr, + tSDP_RESULT sdp_result) { tSDP_DISCOVERY_DB* p_db = hh_cb.p_sdp_db; tSDP_DISC_REC* p_rec; tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc; @@ -121,7 +130,8 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { } Uuid hid_uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE); - p_rec = SDP_FindServiceUUIDInDb(p_db, hid_uuid, NULL); + p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceUUIDInDb(p_db, hid_uuid, + NULL); if (p_rec == NULL) { hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL); return; @@ -130,8 +140,8 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { memset(&hh_cb.sdp_rec, 0, sizeof(tHID_DEV_SDP_INFO)); /* First, verify the mandatory fields we care about */ - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) == - NULL) || + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) == NULL) || (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) || ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL) || (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) != @@ -147,15 +157,15 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { if (p_nvi->dscp_info.dl_len != 0) p_nvi->dscp_info.dsc_list = (uint8_t*)&p_repdesc->attr_value; - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) != - NULL) && + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 && (p_attr->attr_value.v.u8)) { attr_mask |= HID_VIRTUAL_CABLE; } - if (((p_attr = SDP_FindAttributeInRec( + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 && @@ -163,7 +173,7 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { attr_mask |= HID_RECONN_INIT; } - if (((p_attr = SDP_FindAttributeInRec( + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 && @@ -171,24 +181,25 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { attr_mask |= HID_NORMALLY_CONNECTABLE; } - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_SDP_DISABLE)) != - NULL) && + // this attribute is deprecated, should we still keep it? + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_SDP_DISABLE)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 && (p_attr->attr_value.v.u8)) { attr_mask |= HID_SDP_DISABLE; } - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_BATTERY_POWER)) != - NULL) && + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_BATTERY_POWER)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 && (p_attr->attr_value.v.u8)) { attr_mask |= HID_BATTERY_POWER; } - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_REMOTE_WAKE)) != - NULL) && + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_REMOTE_WAKE)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 && (p_attr->attr_value.v.u8)) { @@ -202,35 +213,35 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { hidh_get_str_attr(p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN, p_nvi->prov_name); - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DEVICE_RELNUM)) != - NULL) && + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_DEVICE_RELNUM)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { p_nvi->rel_num = p_attr->attr_value.v.u16; } - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_COUNTRY_CODE)) != - NULL) && + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_COUNTRY_CODE)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) { p_nvi->ctry_code = p_attr->attr_value.v.u8; } - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) != - NULL) && + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) { p_nvi->sub_class = p_attr->attr_value.v.u8; } - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_PARSER_VERSION)) != - NULL) && + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_PARSER_VERSION)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { p_nvi->hpars_ver = p_attr->attr_value.v.u16; } - if (((p_attr = SDP_FindAttributeInRec( + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -238,8 +249,8 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { p_nvi->sup_timeout = p_attr->attr_value.v.u16; } - if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) != - NULL) && + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { attr_mask |= HID_SSR_MAX_LATENCY; @@ -247,7 +258,7 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { } else p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID; - if (((p_attr = SDP_FindAttributeInRec( + if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL) && SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE && SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) { @@ -271,25 +282,7 @@ static void hidh_search_callback(tSDP_RESULT sdp_result) { * ******************************************************************************/ void HID_HostInit(void) { - uint8_t log_level = hh_cb.trace_level; memset(&hh_cb, 0, sizeof(tHID_HOST_CTB)); - hh_cb.trace_level = log_level; -} - -/******************************************************************************* - * - * Function HID_HostSetTraceLevel - * - * Description This function sets the trace level for HID Host. If called - * with 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t HID_HostSetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) hh_cb.trace_level = new_level; - - return (hh_cb.trace_level); } /******************************************************************************* @@ -351,6 +344,7 @@ tHID_STATUS HID_HostDeregister(void) { for (i = 0; i < HID_HOST_MAX_DEVICES; i++) { HID_HostRemoveDev(i); alarm_free(hh_cb.devices[i].conn.process_repage_timer); + hh_cb.devices[i].conn.process_repage_timer = NULL; } hidh_conn_dereg(); @@ -359,6 +353,25 @@ tHID_STATUS HID_HostDeregister(void) { return (HID_SUCCESS); } +/******************************************************************************* + * + * Function HID_HostSDPDisable + * + * Description This is called to check if the device has the HIDSDPDisable + * attribute. + * + * Returns bool + * + ******************************************************************************/ +bool HID_HostSDPDisable(const RawAddress& addr) { + for (int i = 0; i < HID_HOST_MAX_DEVICES; i++) { + if (hh_cb.devices[i].in_use && (hh_cb.devices[i].addr == addr)) { + return (hh_cb.devices[i].attr_mask & HID_SDP_DISABLE); + } + } + return false; +} + /******************************************************************************* * * Function HID_HostAddDev @@ -398,7 +411,7 @@ tHID_STATUS HID_HostAddDev(const RawAddress& addr, uint16_t attr_mask, hh_cb.devices[i].conn_tries = 0; } - if (attr_mask != HID_ATTR_MASK_IGNORE) hh_cb.devices[i].attr_mask = attr_mask; + hh_cb.devices[i].attr_mask = attr_mask; *handle = i; @@ -483,13 +496,13 @@ tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param, tHID_STATUS status = HID_SUCCESS; if (!hh_cb.reg_flag) { - HIDH_TRACE_ERROR("HID_ERR_NOT_REGISTERED"); + LOG_ERROR("HID_ERR_NOT_REGISTERED"); status = HID_ERR_NOT_REGISTERED; } if ((dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use)) { - HIDH_TRACE_ERROR("HID_ERR_INVALID_PARAM"); + LOG_ERROR("HID_ERR_INVALID_PARAM"); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: HIDH_ERR_INVALID_PARAM_AT_HOST_WRITE_DEV, 1); @@ -497,7 +510,7 @@ tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param, } else if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) { - HIDH_TRACE_ERROR("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle); + LOG_ERROR("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: HIDH_ERR_NO_CONNECTION_AT_HOST_WRITE_DEV, 1); diff --git a/system/stack/hid/hidh_conn.cc b/system/stack/hid/hidh_conn.cc index 108f5a70970420bc373ccec0396be0d51d3db04c..b9da24ebe2001f0b79837c6d2fc0d42ea4583b25 100644 --- a/system/stack/hid/hidh_conn.cc +++ b/system/stack/hid/hidh_conn.cc @@ -28,19 +28,20 @@ #include #include -#include "bta/include/bta_api.h" +#include "bta/include/bta_sec_api.h" #include "hiddefs.h" #include "hidh_api.h" #include "hidh_int.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" #include "l2cdefs.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" -#include "stack/btm/btm_sec.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_api.h" // BTM_LogHistory +#include "stack/include/bt_psm_types.h" +#include "stack/include/btm_log_history.h" #include "stack/include/stack_metrics_logging.h" #include "types/raw_address.h" @@ -107,7 +108,7 @@ tHID_STATUS hidh_conn_reg(void) { if (!L2CA_Register2(HID_PSM_CONTROL, hst_reg_info, false /* enable_snoop */, nullptr, HID_HOST_MTU, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { - HIDH_TRACE_ERROR("HID-Host Control Registration failed"); + LOG_ERROR("HID-Host Control Registration failed"); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: HIDH_ERR_L2CAP_FAILED_AT_REGISTER_CONTROL, 1); @@ -117,7 +118,7 @@ tHID_STATUS hidh_conn_reg(void) { nullptr, HID_HOST_MTU, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { L2CA_Deregister(HID_PSM_CONTROL); - HIDH_TRACE_ERROR("HID-Host Interrupt Registration failed"); + LOG_ERROR("HID-Host Interrupt Registration failed"); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: HIDH_ERR_L2CAP_FAILED_AT_REGISTER_INTERRUPT, 1); @@ -182,8 +183,8 @@ static void hidh_l2cif_connect_ind(const RawAddress& bd_addr, bool bAccept = true; uint8_t i = kHID_HOST_MAX_DEVICES; - HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm, - l2cap_cid); + LOG_VERBOSE("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm, + l2cap_cid); /* always add incoming connection device into HID database by default */ if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS) { @@ -202,13 +203,12 @@ static void hidh_l2cif_connect_ind(const RawAddress& bd_addr, /* Check we are in the correct state for this */ if (psm == HID_PSM_INTERRUPT) { if (p_hcon->ctrl_cid == 0) { - HIDH_TRACE_WARNING( - "HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel"); + LOG_WARN("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel"); bAccept = false; } if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) { - HIDH_TRACE_WARNING("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d", - p_hcon->conn_state); + LOG_WARN("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d", + p_hcon->conn_state); bAccept = false; } } else /* CTRL channel */ @@ -218,8 +218,8 @@ static void hidh_l2cif_connect_ind(const RawAddress& bd_addr, p_hcon->conn_state = HID_CONN_STATE_UNUSED; #else if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) { - HIDH_TRACE_WARNING("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d", - p_hcon->conn_state); + LOG_WARN("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d", + p_hcon->conn_state); bAccept = false; } #endif @@ -246,7 +246,7 @@ static void hidh_l2cif_connect_ind(const RawAddress& bd_addr, p_hcon->conn_state = HID_CONN_STATE_CONFIG; p_hcon->intr_cid = l2cap_cid; - HIDH_TRACE_EVENT( + LOG_VERBOSE( "HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x", psm, l2cap_cid); } @@ -336,8 +336,7 @@ static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result) { ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING))) { - HIDH_TRACE_WARNING("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", - l2cap_cid); + LOG_WARN("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid); return; } @@ -387,12 +386,11 @@ static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) { } if (p_hcon == NULL) { - HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", - l2cap_cid); + LOG_WARN("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); return; } - HIDH_TRACE_EVENT("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid); + LOG_VERBOSE("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid); /* Remember the remote MTU size */ if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU)) @@ -419,15 +417,14 @@ static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, uint16_t initiator, tHID_CONN* p_hcon = NULL; uint32_t reason; - HIDH_TRACE_EVENT("HID-Host Rcvd cfg cfm, CID: 0x%x", l2cap_cid); + LOG_VERBOSE("HID-Host Rcvd cfg cfm, CID: 0x%x", l2cap_cid); /* Find CCB based on CID */ dhandle = find_conn_by_cid(l2cap_cid); if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; if (p_hcon == NULL) { - HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", - l2cap_cid); + LOG_WARN("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); return; } @@ -442,7 +439,7 @@ static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, uint16_t initiator, L2CA_ConnectReq2(HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); if (p_hcon->intr_cid == 0) { - HIDH_TRACE_WARNING("HID-Host INTR Originate failed"); + LOG_WARN("HID-Host INTR Originate failed"); reason = HID_L2CAP_REQ_FAIL; p_hcon->conn_state = HID_CONN_STATE_UNUSED; BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Failed"); @@ -499,12 +496,11 @@ static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) { if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; if (p_hcon == NULL) { - HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", - l2cap_cid); + LOG_WARN("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid); return; } - HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); + LOG_VERBOSE("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING; BTM_LogHistory( @@ -580,7 +576,7 @@ static void hidh_l2cif_disconnect(uint16_t l2cap_cid) { } else { p_hcon->intr_cid = 0; if (p_hcon->ctrl_cid) { - HIDH_TRACE_EVENT("HID-Host Initiating L2CAP Ctrl disconnection"); + LOG_VERBOSE("HID-Host Initiating L2CAP Ctrl disconnection"); L2CA_DisconnectReq(p_hcon->ctrl_cid); p_hcon->ctrl_cid = 0; } @@ -613,13 +609,13 @@ static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested) { if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; if (p_hcon == NULL) { - HIDH_TRACE_WARNING( - "HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid); + LOG_WARN("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", + l2cap_cid); return; } - HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", - l2cap_cid, congested); + LOG_VERBOSE("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", + l2cap_cid, congested); if (congested) p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED; @@ -650,23 +646,20 @@ static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) { uint8_t dhandle; tHID_CONN* p_hcon = NULL; - HIDH_TRACE_DEBUG("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", - l2cap_cid); + LOG_VERBOSE("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid); /* Find CCB based on CID */ dhandle = find_conn_by_cid(l2cap_cid); if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; if (p_hcon == NULL) { - HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", - l2cap_cid); + LOG_WARN("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid); osi_free(p_msg); return; } if (p_msg->len < 1) { - HIDH_TRACE_WARNING("Rcvd L2CAP data, invalid length %d, should be >= 1", - p_msg->len); + LOG_WARN("Rcvd L2CAP data, invalid length %d, should be >= 1", p_msg->len); osi_free(p_msg); return; } @@ -891,7 +884,7 @@ tHID_STATUS hidh_conn_initiate(uint8_t dhandle) { p_dev->conn.ctrl_cid = L2CA_ConnectReq2( HID_PSM_CONTROL, p_dev->addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); if (p_dev->conn.ctrl_cid == 0) { - HIDH_TRACE_WARNING("HID-Host Originate failed"); + LOG_WARN("HID-Host Originate failed"); hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL); log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: diff --git a/system/stack/hid/hidh_int.h b/system/stack/hid/hidh_int.h index ca5142b9fbce49c6d2aa142ecdf796142ee94db4..5a19834e6270f4f1580192c4ef59be765692fac3 100644 --- a/system/stack/hid/hidh_int.h +++ b/system/stack/hid/hidh_int.h @@ -27,6 +27,7 @@ #include +#include "internal_include/bt_target.h" #include "stack/hid/hid_conn.h" #include "stack/include/bt_hdr.h" #include "stack/include/hidh_api.h" @@ -60,7 +61,6 @@ typedef struct host_ctb { tSDP_DISCOVERY_DB* p_sdp_db; tHID_DEV_SDP_INFO sdp_rec; bool reg_flag; - uint8_t trace_level; } tHID_HOST_CTB; tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type, diff --git a/system/stack/include/a2dp_api.h b/system/stack/include/a2dp_api.h index d7cfa18b677bbeb5fffff712e23a4201cc26e87f..7f2ab98e24151c8b1cf42d03d3bbcdb3eb9a0ebb 100644 --- a/system/stack/include/a2dp_api.h +++ b/system/stack/include/a2dp_api.h @@ -173,29 +173,6 @@ tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, const RawAddress& bd_addr, *****************************************************************************/ uint16_t A2DP_GetAvdtpVersion(void); -/****************************************************************************** - * - * Function A2DP_SetTraceLevel - * - * Description Sets the trace level for A2D. If 0xff is passed, the - * current trace level is returned. - * - * Input Parameters: - * new_level: The level to set the A2DP tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new trace level or current trace level if - * the input parameter is 0xff. - * - *****************************************************************************/ -uint8_t A2DP_SetTraceLevel(uint8_t new_level); - /****************************************************************************** * Function A2DP_BitsSet * diff --git a/system/stack/include/a2dp_vendor_ldac.h b/system/stack/include/a2dp_vendor_ldac.h index c025d2c014be3d8a43ae8a5acb195dfb2f92f741..0c9734a5024a2a3d1facebc88a51e41973c2774f 100644 --- a/system/stack/include/a2dp_vendor_ldac.h +++ b/system/stack/include/a2dp_vendor_ldac.h @@ -44,7 +44,7 @@ class A2dpCodecConfigLdacBase : public A2dpCodecConfig { const uint8_t* p_peer_codec_capabilities) override; private: - bool is_source_; // True if local is Source + [[maybe_unused]] bool is_source_; // True if local is Source }; class A2dpCodecConfigLdacSource : public A2dpCodecConfigLdacBase { diff --git a/system/stack/include/a2dp_vendor_opus.h b/system/stack/include/a2dp_vendor_opus.h index 08a0b7b660f2ede8478d9e9aed7d540099be9df0..16831259199c159a9cfeabc57d8734b8c3bb615c 100644 --- a/system/stack/include/a2dp_vendor_opus.h +++ b/system/stack/include/a2dp_vendor_opus.h @@ -39,7 +39,7 @@ class A2dpCodecConfigOpusBase : public A2dpCodecConfig { const uint8_t* p_peer_codec_capabilities) override; private: - bool is_source_; // True if local is Source + [[maybe_unused]] bool is_source_; // True if local is Source }; class A2dpCodecConfigOpusSource : public A2dpCodecConfigOpusBase { diff --git a/system/stack/include/a2dp_vendor_opus_constants.h b/system/stack/include/a2dp_vendor_opus_constants.h index 272b04c48d3dea7a62ac3b30e48d22864774e5ef..5cb7f09e235f8b782899e70c7c258f46c47baebb 100644 --- a/system/stack/include/a2dp_vendor_opus_constants.h +++ b/system/stack/include/a2dp_vendor_opus_constants.h @@ -52,11 +52,7 @@ // Length of the Opus Media Payload header #define A2DP_OPUS_MPL_HDR_LEN 1 -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -#define A2DP_OPUS_OFFSET (AVDT_MEDIA_OFFSET + A2DP_OPUS_MPL_HDR_LEN + 1) -#else #define A2DP_OPUS_OFFSET (AVDT_MEDIA_OFFSET + A2DP_OPUS_MPL_HDR_LEN) -#endif #define A2DP_OPUS_HDR_F_MSK 0x80 #define A2DP_OPUS_HDR_S_MSK 0x40 diff --git a/system/stack/include/acl_api.h b/system/stack/include/acl_api.h index 87fe58345ce69aa26272bf61955416e4aa8ef194..68f1ec6a8d5bbfd371b5c8646ee298683a6eb277 100644 --- a/system/stack/include/acl_api.h +++ b/system/stack/include/acl_api.h @@ -17,11 +17,15 @@ #include -#include "stack/btm/btm_int_types.h" -#include "stack/include/acl_api_types.h" -#include "stack/include/bt_types.h" +#include "device/include/controller.h" +#include "stack/acl/acl.h" +#include "stack/btm/security_device_record.h" +#include "stack/include/btm_api_types.h" #include "stack/include/btm_status.h" #include "stack/include/hci_error_code.h" +#include "types/ble_address_with_type.h" +#include "types/bt_transport.h" +#include "types/hci_role.h" #include "types/raw_address.h" // Note: From stack/include/btm_api.h @@ -193,7 +197,7 @@ bool BTM_BLE_IS_RESOLVE_BDA(const RawAddress& x); bool acl_refresh_remote_address(const RawAddress& identity_address, tBLE_ADDR_TYPE identity_address_type, const RawAddress& remote_bda, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type, + tBLE_RAND_ADDR_TYPE rra_type, const RawAddress& rpa); void btm_establish_continue_from_address(const RawAddress& remote_bda, @@ -202,10 +206,6 @@ void btm_establish_continue_from_address(const RawAddress& remote_bda, bool acl_peer_supports_ble_connection_parameters_request( const RawAddress& remote_bda); -bool sco_peer_supports_esco_2m_phy(const RawAddress& remote_bda); -bool sco_peer_supports_esco_3m_phy(const RawAddress& remote_bda); -bool sco_peer_supports_esco_ev3(const RawAddress& remote_bda); - bool acl_peer_supports_ble_packet_extension(uint16_t hci_handle); bool acl_peer_supports_ble_2m_phy(uint16_t hci_handle); bool acl_peer_supports_ble_coded_phy(uint16_t hci_handle); @@ -226,7 +226,8 @@ bool acl_peer_supports_ble_packet_extension(uint16_t hci_handle); ******************************************************************************/ void BTM_ReadConnectionAddr(const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type); + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address = false); /******************************************************************************* * @@ -262,9 +263,6 @@ tBTM_STATUS btm_read_power_mode_state(const RawAddress& remote_bda, void btm_acl_notif_conn_collision(const RawAddress& bda); -void btm_configure_data_path(uint8_t direction, uint8_t path_id, - std::vector vendor_config); - /******************************************************************************* * * Function BTM_ReadPowerMode @@ -304,8 +302,6 @@ bool acl_peer_supports_ble_connection_subrating(const RawAddress& remote_bda); bool acl_peer_supports_ble_connection_subrating_host( const RawAddress& remote_bda); -void btm_acl_set_paging(bool value); - void btm_process_cancel_complete(uint8_t status, uint8_t mode); uint8_t btm_handle_to_acl_index(uint16_t hci_handle); diff --git a/system/stack/include/acl_api_types.h b/system/stack/include/acl_api_types.h index 860f100496efe1fd6afc4d435f2ff7ec52d918cd..432c839ced5f357ca0c59eaf3120fd8182c75cf9 100644 --- a/system/stack/include/acl_api_types.h +++ b/system/stack/include/acl_api_types.h @@ -18,7 +18,6 @@ #include -#include "stack/include/bt_types.h" #include "stack/include/btm_status.h" #include "types/raw_address.h" diff --git a/system/stack/include/acl_hci_link_interface.h b/system/stack/include/acl_hci_link_interface.h index 885d15c9de723dcc638c1e779042fc61c93342e6..e6a1ce1386b5c0d913fed7c9c8a88d5860bc95ed 100644 --- a/system/stack/include/acl_hci_link_interface.h +++ b/system/stack/include/acl_hci_link_interface.h @@ -20,7 +20,6 @@ #include #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" #include "stack/include/hci_error_code.h" #include "stack/include/hci_mode.h" #include "stack/include/hcidefs.h" @@ -32,7 +31,6 @@ // void btm_connection_request(const RawAddress& bda, const bluetooth::types::ClassOfDevice& cod); -void btm_acl_connection_request(const RawAddress& bda, uint8_t* dc); void btm_acl_connected(const RawAddress& bda, uint16_t handle, tHCI_STATUS status, uint8_t enc_mode); void on_acl_br_edr_connected(const RawAddress& bda, uint16_t handle, @@ -44,8 +42,6 @@ void btm_acl_disconnected(tHCI_STATUS status, uint16_t handle, void btm_acl_iso_disconnected(uint16_t handle, tHCI_STATUS reason); void btm_acl_encrypt_change(uint16_t handle, uint8_t status, uint8_t encr_enable); -void btm_acl_paging(BT_HDR* p, const RawAddress& dest); -void btm_acl_resubmit_page(void); void btm_acl_role_changed(tHCI_STATUS hci_status, const RawAddress& bd_addr, tHCI_ROLE new_role); void btm_rejectlist_role_change_device(const RawAddress& bd_addr, @@ -61,7 +57,6 @@ void btm_read_remote_ext_features_complete_raw(uint8_t* p, uint8_t evt_len); void btm_read_remote_ext_features_complete(uint16_t handle, uint8_t page_num, uint8_t max_page, uint8_t* features); void btm_read_remote_ext_features_failed(uint8_t status, uint16_t handle); -void btm_read_remote_features_complete(uint16_t handle, uint8_t* features); void btm_read_remote_version_complete(tHCI_STATUS status, uint16_t handle, uint8_t lmp_version, uint16_t manufacturer, @@ -70,7 +65,6 @@ void btm_read_rssi_complete(uint8_t* p, uint16_t evt_len); void btm_read_tx_power_complete(uint8_t* p, uint16_t evt_len, bool is_ble); void acl_rcv_acl_data(BT_HDR* p_msg); -void acl_link_segments_xmitted(BT_HDR* p_msg); void acl_packets_completed(uint16_t handle, uint16_t num_packets); void acl_process_supported_features(uint16_t handle, uint64_t features); void acl_process_extended_features(uint16_t handle, uint8_t current_page_number, diff --git a/system/stack/include/avct_api.h b/system/stack/include/avct_api.h index d711ff738134550320a0404a042ff5cd5766007d..41fb60cc214c902e9292bbc3e5fac0cadb04f5f9 100644 --- a/system/stack/include/avct_api.h +++ b/system/stack/include/avct_api.h @@ -275,27 +275,4 @@ 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_SetTraceLevel - * - * Description Sets the trace level for AVCT. If 0xff is passed, the - * current trace level is returned. - * - * Input Parameters: - * new_level: The level to set the AVCT tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new trace level or current trace level if - * the input parameter is 0xff. - * - *****************************************************************************/ -uint8_t AVCT_SetTraceLevel(uint8_t new_level); - #endif /* AVCT_API_H */ diff --git a/system/stack/include/avdt_api.h b/system/stack/include/avdt_api.h index 47bd80ffb08599489a3952bf3fbb77cbda6fb015..606bc62295752eefc3ac2403a87741d0883d3180 100644 --- a/system/stack/include/avdt_api.h +++ b/system/stack/include/avdt_api.h @@ -31,6 +31,7 @@ #include #include "bt_target.h" +#include "macros.h" #include "osi/include/log.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" @@ -61,10 +62,6 @@ inline tAVDT_RESULT ToAvdtResult(uint16_t result) { return static_cast(result); } -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string avdt_result_text(const tAVDT_RESULT& result) { switch (result) { CASE_RETURN_TEXT(AVDT_SUCCESS); @@ -77,7 +74,6 @@ inline std::string avdt_result_text(const tAVDT_RESULT& result) { return base::StringPrintf("UNKNOWN[%hu]", result); } } -#undef CASE_RETURN_TEXT /* The index to access the codec type in codec_info[]. */ #define AVDT_CODEC_TYPE_INDEX 2 @@ -911,29 +907,6 @@ uint16_t AVDT_DisconnectReq(const RawAddress& bd_addr, ******************************************************************************/ uint16_t AVDT_GetL2CapChannel(uint8_t handle); -/****************************************************************************** - * - * Function AVDT_SetTraceLevel - * - * Description Sets the trace level for AVDT. If 0xff is passed, the - * current trace level is returned. - * - * Input Parameters: - * new_level: The level to set the AVDT tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new trace level or current trace level if - * the input parameter is 0xff. - * - *****************************************************************************/ -uint8_t AVDT_SetTraceLevel(uint8_t new_level); - /** * Dump debug-related information for the Stack AVDTP module. * diff --git a/system/stack/include/avrc_api.h b/system/stack/include/avrc_api.h index 8f5d9dd1142d0222b833321ff3cb76438fff56a9..2e3a031d630884f1237695a4730abf69d0fae4c3 100644 --- a/system/stack/include/avrc_api.h +++ b/system/stack/include/avrc_api.h @@ -237,11 +237,11 @@ using tAVRC_MSG_CBACK = base::Callback; 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) */ - uint8_t control; /* Control role (Control/Target) */ + 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) */ + uint8_t control; /* Control role (Control/Target) */ } tAVRC_CONN_CB; typedef struct { @@ -510,7 +510,7 @@ uint16_t AVRC_CloseBrowse(uint8_t handle); * *****************************************************************************/ uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, - BT_HDR* p_pkt); + BT_HDR* p_pkt, bool is_new_avrcp); /****************************************************************************** * @@ -689,29 +689,6 @@ uint16_t AVRC_VendorCmd(uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR* p_msg); *****************************************************************************/ uint16_t AVRC_VendorRsp(uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR* p_msg); -/****************************************************************************** - * - * Function AVRC_SetTraceLevel - * - * Description Sets the trace level for AVRC. If 0xff is passed, the - * current trace level is returned. - * - * Input Parameters: - * new_level: The level to set the AVRC tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new trace level or current trace level if - * the input parameter is 0xff. - * - *****************************************************************************/ -uint8_t AVRC_SetTraceLevel(uint8_t new_level); - /******************************************************************************* * * Function AVRC_Init @@ -833,4 +810,6 @@ bool AVRC_IsValidAvcType(uint8_t pdu_id, uint8_t avc_type); ******************************************************************************/ bool AVRC_IsValidPlayerAttr(uint8_t attr); +void AVRC_UpdateCcb(RawAddress* addr, uint32_t company_id); + #endif /* AVRC_API_H */ diff --git a/system/stack/include/avrc_defs.h b/system/stack/include/avrc_defs.h index 864eef01d555774375d5845c0c8a2d33947f594d..ca9fd7ea5e9e9e2f6b91d0962ca88d84c433d4a2 100644 --- a/system/stack/include/avrc_defs.h +++ b/system/stack/include/avrc_defs.h @@ -27,7 +27,6 @@ #include #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" /***************************************************************************** * constants diff --git a/system/stack/include/ble_acl_interface.h b/system/stack/include/ble_acl_interface.h index 128dfbffbcc8f1853bea21ac1498eaebbf5b8ddb..244e13b1268072fb03a9b9ea202d77662b2b9476 100644 --- a/system/stack/include/ble_acl_interface.h +++ b/system/stack/include/ble_acl_interface.h @@ -18,8 +18,9 @@ #include -#include "stack/include/bt_types.h" #include "stack/include/hci_error_code.h" +#include "types/ble_address_with_type.h" +#include "types/hci_role.h" #include "types/raw_address.h" void acl_ble_enhanced_connection_complete( diff --git a/system/stack/include/ble_advertiser.h b/system/stack/include/ble_advertiser.h deleted file mode 100644 index 4464413ac1ad012638f67c6fed10a3fb1e699da8..0000000000000000000000000000000000000000 --- a/system/stack/include/ble_advertiser.h +++ /dev/null @@ -1,174 +0,0 @@ -/****************************************************************************** - * - * Copyright 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#ifndef BLE_ADVERTISER_H -#define BLE_ADVERTISER_H - -#include -#include - -#include -#include - -#include "btm_ble_api.h" -#include "types/raw_address.h" - -#define BTM_BLE_MULTI_ADV_SUCCESS 0 -#define BTM_BLE_MULTI_ADV_FAILURE 1 -#define ADVERTISE_FAILED_TOO_MANY_ADVERTISERS 0x02 - -using MultiAdvCb = base::Callback; -using ParametersCb = - base::Callback; - -// methods we must have defined -void btm_ble_update_dmt_flag_bits(uint8_t* flag_value, - const uint16_t connect_mode, - const uint16_t disc_mode); - -// methods we expose to c code: -void btm_ble_multi_adv_cleanup(void); -void btm_ble_multi_adv_init(); - -typedef struct { - uint16_t advertising_event_properties; - uint32_t adv_int_min; - uint32_t adv_int_max; - tBTM_BLE_ADV_CHNL_MAP channel_map; - tBTM_BLE_AFP adv_filter_policy; - int8_t tx_power; - uint8_t primary_advertising_phy; - uint8_t secondary_advertising_phy; - uint8_t scan_request_notification_enable; - uint8_t own_address_type; -} tBTM_BLE_ADV_PARAMS; - -typedef struct { - bool enable; - bool include_adi; - uint16_t min_interval; - uint16_t max_interval; - uint16_t periodic_advertising_properties; -} tBLE_PERIODIC_ADV_PARAMS; - -class BleAdvertiserHciInterface; - -class BleAdvertisingManager { - public: - virtual ~BleAdvertisingManager() = default; - - static const uint16_t advertising_prop_legacy_connectable = 0x0011; - static const uint16_t advertising_prop_legacy_non_connectable = 0x0010; - - static void Initialize(BleAdvertiserHciInterface* interface); - static void CleanUp(); - static bool IsInitialized(); - static base::WeakPtr Get(); - - /* Register an advertising instance, status will be returned in |cb| - * callback, with assigned id, if operation succeeds. Instance is freed when - * advertising is disabled by calling |BTM_BleDisableAdvInstance|, or when any - * of the operations fails. - * The instance will have data set to |advertise_data|, scan response set to - * |scan_response_data|, and will be enabled. - */ - virtual void StartAdvertising(uint8_t advertiser_id, MultiAdvCb cb, - tBTM_BLE_ADV_PARAMS* params, - std::vector advertise_data, - std::vector scan_response_data, - int duration, MultiAdvCb timeout_cb) = 0; - - /* Register an advertising instance, status will be returned in |cb| - * callback, with assigned id, if operation succeeds. Instance is freed when - * advertising is disabled by calling |BTM_BleDisableAdvInstance|, or when any - * of the operations fails. - * The instance will have data set to |advertise_data|, scan response set to - * |scan_response_data|, periodic data set to |periodic_data| and will be - * enabled. - */ - virtual void StartAdvertisingSet( - base::Callback - cb, - tBTM_BLE_ADV_PARAMS* params, std::vector advertise_data, - std::vector scan_response_data, - tBLE_PERIODIC_ADV_PARAMS* periodic_params, - std::vector periodic_data, uint16_t duration, - uint8_t maxExtAdvEvents, - base::Callback - timeout_cb) = 0; - - /* Register an advertising instance, status will be returned in |cb| - * callback, with assigned id, if operation succeeds. Instance is freed when - * advertising is disabled by calling |BTM_BleDisableAdvInstance|, or when any - * of the operations fails. */ - virtual void RegisterAdvertiser( - base::Callback) = 0; - - /* This function enables/disables an advertising instance. Operation status is - * returned in |cb| */ - virtual void Enable(uint8_t inst_id, bool enable, MultiAdvCb cb, - uint16_t duration, uint8_t maxExtAdvEvents, - MultiAdvCb timeout_cb) = 0; - - /* This function update a Multi-ADV instance with the specififed adv - * parameters. */ - virtual void SetParameters(uint8_t inst_id, tBTM_BLE_ADV_PARAMS* p_params, - ParametersCb cb) = 0; - - /* This function configure a Multi-ADV instance with the specified adv data or - * scan response data.*/ - virtual void SetData(uint8_t inst_id, bool is_scan_rsp, - std::vector data, MultiAdvCb cb) = 0; - - /* This function configure instance with the specified periodic parameters */ - virtual void SetPeriodicAdvertisingParameters( - uint8_t inst_id, tBLE_PERIODIC_ADV_PARAMS* params, MultiAdvCb cb) = 0; - - /* This function configure instance with the specified periodic data */ - virtual void SetPeriodicAdvertisingData(uint8_t inst_id, - std::vector data, - MultiAdvCb cb) = 0; - - /* This function enables/disables periodic advertising on selected instance */ - virtual void SetPeriodicAdvertisingEnable(uint8_t inst_id, bool enable, - bool include_adi, - MultiAdvCb cb) = 0; - - /* This function disable a Multi-ADV instance */ - virtual void Unregister(uint8_t inst_id) = 0; - - /* When resolving list is used, we need to suspend and resume all advertising - * instances for the time of operation. Suspend() saves current state, - * Resume() resumes the advertising. - */ - virtual void Suspend() = 0; - virtual void Resume() = 0; - - /* This method is a member of BleAdvertiserHciInterface, and is exposed here - * just for tests. It should never be called from upper layers*/ - virtual void OnAdvertisingSetTerminated( - uint8_t status, uint8_t advertising_handle, uint16_t connection_handle, - uint8_t num_completed_extended_adv_events) = 0; - - using GetAddressCallback = - base::Callback; - virtual void GetOwnAddress(uint8_t inst_id, GetAddressCallback cb) = 0; -}; - -#endif // BLE_ADVERTISER_H diff --git a/system/stack/include/ble_hci_link_interface.h b/system/stack/include/ble_hci_link_interface.h index 4a903abf23df027c59250a61fd3c8c57304050a1..4c10c8f3401f1bc62204462c95fbde2df3966909 100644 --- a/system/stack/include/ble_hci_link_interface.h +++ b/system/stack/include/ble_hci_link_interface.h @@ -19,32 +19,19 @@ #include -#include "osi/include/osi.h" // UNUSED_ATTR -#include "types/ble_address_with_type.h" -#include "types/raw_address.h" +#include "stack/include/hci_error_code.h" // This header contains functions for HCI-ble to invoke void btm_ble_process_adv_pkt(uint8_t len, const uint8_t* p); void btm_ble_process_ext_adv_pkt(uint8_t len, const uint8_t* p); void btm_ble_process_phy_update_pkt(uint8_t len, uint8_t* p); void btm_ble_read_remote_features_complete(uint8_t* p, uint8_t length); -void btm_le_on_advertising_set_terminated(uint8_t* p, uint16_t length); void btm_ble_write_adv_enable_complete(uint8_t* p, uint16_t evt_len); void btm_ble_create_ll_conn_complete(tHCI_STATUS status); void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv); void btm_ble_test_command_complete(uint8_t* p); -void btm_ble_rand_enc_complete(uint8_t* p, uint16_t evt_len, uint16_t op_code, - tBTM_RAND_ENC_CB* p_enc_cplt_cback); -bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr, - tBLE_ADDR_TYPE* p_addr_type, - bool refresh); -bool btm_identity_addr_to_random_pseudo_from_address_with_type( - tBLE_BD_ADDR* address_with_type, bool refresh); void btm_ble_read_resolving_list_entry_complete(const uint8_t* p, uint16_t evt_len); void btm_ble_remove_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len); void btm_ble_add_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len); void btm_ble_clear_resolving_list_complete(uint8_t* p, uint16_t evt_len); -void btm_ble_process_periodic_adv_pkt(uint8_t len, const uint8_t* p); -void btm_ble_process_periodic_adv_sync_est_evt(uint8_t len, const uint8_t* p); -void btm_ble_process_periodic_adv_sync_lost_evt(uint8_t len, uint8_t* p); diff --git a/system/stack/include/bnep_api.h b/system/stack/include/bnep_api.h index bf3f70e7dcc172ad0544a55f8e92b9ccca54c966..c32449a237ef453fe817dca5320e47b9fb45141c 100644 --- a/system/stack/include/bnep_api.h +++ b/system/stack/include/bnep_api.h @@ -371,18 +371,6 @@ tBNEP_RESULT BNEP_SetMulticastFilters(uint16_t handle, uint16_t num_filters, uint8_t* p_start_array, uint8_t* p_end_array); -/******************************************************************************* - * - * Function BNEP_SetTraceLevel - * - * Description This function sets the trace level for BNEP. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t BNEP_SetTraceLevel(uint8_t new_level); - /******************************************************************************* * * Function BNEP_Init diff --git a/system/stack/include/bt_dev_class.h b/system/stack/include/bt_dev_class.h index b19c7a04c248cef0fbcb3b3054255efb92610a6b..a0d182db56255dcf1fbd28c4b98f1c6ac7825524 100644 --- a/system/stack/include/bt_dev_class.h +++ b/system/stack/include/bt_dev_class.h @@ -123,6 +123,12 @@ inline constexpr DEV_CLASS kDevClassEmpty = {}; } #ifdef __cplusplus +inline void dev_class_copy(DEV_CLASS& dst, const DEV_CLASS& src) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; +} + #include inline std::string dev_class_text(const DEV_CLASS& dev_class) { std::ostringstream oss; diff --git a/system/stack/include/bt_lap.h b/system/stack/include/bt_lap.h new file mode 100644 index 0000000000000000000000000000000000000000..a2a40b80b3d80f29b92c49f59e5a15b202a28274 --- /dev/null +++ b/system/stack/include/bt_lap.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#define LAP_LEN 3 +typedef uint8_t LAP[LAP_LEN]; /* IAC as passed to Inquiry (LAP) */ diff --git a/system/stack/include/bt_name.h b/system/stack/include/bt_name.h index 6fcf8f9c9e8728e782f69f12a3cb122f45a32cf0..5d71549cf671272a2dd12a56e996757333306105 100644 --- a/system/stack/include/bt_name.h +++ b/system/stack/include/bt_name.h @@ -44,5 +44,33 @@ typedef uint8_t tBTM_BD_NAME[BTM_MAX_REM_BD_NAME_LEN + 1]; typedef uint8_t tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1]; #ifdef __cplusplus +#include "osi/include/compat.h" // strlcpy inline constexpr tBTM_BD_NAME kBtmBdNameEmpty = {}; +constexpr size_t kBdNameLength = static_cast(BD_NAME_LEN); + +inline size_t bd_name_copy(BD_NAME bd_name_dest, const char* src) { + return strlcpy(reinterpret_cast(bd_name_dest), const_cast(src), + kBdNameLength + 1); +} +inline size_t bd_name_copy(BD_NAME bd_name_dest, const BD_NAME bd_name_src) { + return strlcpy(reinterpret_cast(bd_name_dest), + reinterpret_cast(bd_name_src), kBdNameLength + 1); +} +inline void bd_name_clear(BD_NAME bd_name) { *bd_name = {0}; } +inline bool bd_name_is_empty(const BD_NAME bd_name) { + return bd_name[0] == '\0'; +} + +inline void bd_name_from_char_pointer(BD_NAME bd_name_dest, + const char* bd_name_char) { + if (bd_name_char != nullptr) { + strlcpy(reinterpret_cast(bd_name_dest), bd_name_char, + kBdNameLength + 1); + } +} +inline bool bd_name_is_equal(const BD_NAME bd_name1, const BD_NAME bd_name2) { + return memcmp(reinterpret_cast(const_cast(bd_name1)), + reinterpret_cast(const_cast(bd_name2)), + kBdNameLength + 1) == 0; +} #endif diff --git a/system/stack/include/bt_octets.h b/system/stack/include/bt_octets.h index 36c9e07ab8a8d1462f6c03d2156fb19916e6e4a4..3a90164e1d7e5239f243ae4e7717eb5f6f990a0a 100644 --- a/system/stack/include/bt_octets.h +++ b/system/stack/include/bt_octets.h @@ -16,17 +16,13 @@ #pragma once -/* Some C files include this header file */ -#ifdef __cplusplus - -#include #include -constexpr int OCTET16_LEN = 16; -typedef std::array Octet16; +#include "gd/hci/octets.h" -constexpr int LINK_KEY_LEN = OCTET16_LEN; -typedef Octet16 LinkKey; /* Link Key */ +using Octet16 = bluetooth::hci::Octet16; +using LinkKey = bluetooth::hci::Octet16; /* Link Key */ +static constexpr int OCTET16_LEN = bluetooth::hci::kOctet16Length; /* Sample LTK from BT Spec 5.1 | Vol 6, Part C 1 * 0x4C68384139F574D836BCF34E9DFB01BF */ @@ -34,8 +30,6 @@ constexpr Octet16 SAMPLE_LTK = {0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36, 0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c}; inline bool is_sample_ltk(const Octet16& ltk) { return ltk == SAMPLE_LTK; } -#endif - #define BT_OCTET8_LEN 8 typedef uint8_t BT_OCTET8[BT_OCTET8_LEN]; /* octet array: size 16 */ diff --git a/system/stack/include/bt_psm_types.h b/system/stack/include/bt_psm_types.h new file mode 100644 index 0000000000000000000000000000000000000000..97dcd04e2e8a3b561bc4e2db061be87d603c8dba --- /dev/null +++ b/system/stack/include/bt_psm_types.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +enum { + BT_PSM_SDP = 0x0001, + BT_PSM_RFCOMM = 0x0003, + BT_PSM_TCS = 0x0005, + BT_PSM_CTP = 0x0007, + BT_PSM_BNEP = 0x000F, + BT_PSM_HIDC = 0x0011, + HID_PSM_CONTROL = 0x0011, + BT_PSM_HIDI = 0x0013, + HID_PSM_INTERRUPT = 0x0013, + 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_EATT = 0x0027, + /* We will not allocate a PSM in the reserved range to 3rd party apps + */ + BRCM_RESERVED_PSM_START = 0x5AE1, + BRCM_RESERVED_PSM_END = 0x5AFF, +}; diff --git a/system/stack/include/bt_types.h b/system/stack/include/bt_types.h index 6a7ab4d9c188b49ad565736d77bcd69b86cc0e0b..1831b83dd808a16d8a7e4171e15365149b2c207c 100644 --- a/system/stack/include/bt_types.h +++ b/system/stack/include/bt_types.h @@ -20,18 +20,13 @@ #define BT_TYPES_H #include -#include -#ifdef __cplusplus -#include -#endif // __cplusplus #include "stack/include/bt_dev_class.h" #include "stack/include/bt_device_type.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_name.h" -#include "stack/include/bt_octets.h" #ifdef __cplusplus #include "include/hardware/bluetooth.h" +#include "stack/include/bt_octets.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" #endif // __cplusplus @@ -52,8 +47,6 @@ /************************************/ /* HCI Event */ #define BT_EVT_TO_BTU_HCI_EVT 0x1000 -/* ACL Data from HCI */ -#define BT_EVT_TO_BTU_HCI_ACL 0x1100 /* SCO Data from HCI */ #define BT_EVT_TO_BTU_HCI_SCO 0x1200 /* HCI Transport Error */ @@ -62,15 +55,9 @@ /* Serial Port Data */ #define BT_EVT_TO_BTU_SP_DATA 0x1500 -/* HCI command from upper layer */ -#define BT_EVT_TO_BTU_HCI_CMD 0x1600 - /* ISO Data from HCI */ #define BT_EVT_TO_BTU_HCI_ISO 0x1700 -/* L2CAP segment(s) transmitted */ -#define BT_EVT_TO_BTU_L2C_SEG_XMIT 0x1900 - /* To LM */ /************************************/ /* HCI Command */ @@ -92,30 +79,6 @@ #define BT_ISO_HDR_CONTAINS_TS (0x0001) #define BT_ISO_HDR_OFFSET_POINTS_DATA (0x0002) -enum { - BT_PSM_SDP = 0x0001, - BT_PSM_RFCOMM = 0x0003, - BT_PSM_TCS = 0x0005, - BT_PSM_CTP = 0x0007, - BT_PSM_BNEP = 0x000F, - BT_PSM_HIDC = 0x0011, - HID_PSM_CONTROL = 0x0011, - BT_PSM_HIDI = 0x0013, - HID_PSM_INTERRUPT = 0x0013, - 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_EATT = 0x0027, - /* We will not allocate a PSM in the reserved range to 3rd party apps - */ - BRCM_RESERVED_PSM_START = 0x5AE1, - BRCM_RESERVED_PSM_END = 0x5AFF, -}; - /******************************************************************************* * Macros to get and put bytes to and from a stream (Little Endian format). */ @@ -331,9 +294,6 @@ enum { /* Common Bluetooth field definitions */ -#define LAP_LEN 3 -typedef uint8_t LAP[LAP_LEN]; /* IAC as passed to Inquiry (LAP) */ - #define BT_1SEC_TIMEOUT_MS (1 * 1000) /* 1 second */ #endif diff --git a/system/stack/include/bt_uuid16.h b/system/stack/include/bt_uuid16.h new file mode 100644 index 0000000000000000000000000000000000000000..4449363bfe44348940c0f77cdc656e703b611b13 --- /dev/null +++ b/system/stack/include/bt_uuid16.h @@ -0,0 +1,132 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* Define common 16-bit protocol UUIDs + */ +#define UUID_PROTOCOL_RFCOMM 0x0003 +#define UUID_PROTOCOL_OBEX 0x0008 +#define UUID_PROTOCOL_BNEP 0x000F +#define UUID_PROTOCOL_HIDP 0x0011 +#define UUID_PROTOCOL_AVCTP 0x0017 +#define UUID_PROTOCOL_AVDTP 0x0019 +#define UUID_PROTOCOL_L2CAP 0x0100 +#define UUID_PROTOCOL_ATT 0x0007 + +/* Define common 16-bit service class UUIDs + */ +#define UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER 0X1000 +#define UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR 0X1001 +#define UUID_SERVCLASS_PUBLIC_BROWSE_GROUP 0X1002 +#define UUID_SERVCLASS_SERIAL_PORT 0X1101 +#define UUID_SERVCLASS_LAN_ACCESS_USING_PPP 0X1102 +#define UUID_SERVCLASS_DIALUP_NETWORKING 0X1103 +#define UUID_SERVCLASS_IRMC_SYNC 0X1104 +#define UUID_SERVCLASS_OBEX_OBJECT_PUSH 0X1105 +#define UUID_SERVCLASS_OBEX_FILE_TRANSFER 0X1106 +#define UUID_SERVCLASS_IRMC_SYNC_COMMAND 0X1107 +#define UUID_SERVCLASS_HEADSET 0X1108 +#define UUID_SERVCLASS_CORDLESS_TELEPHONY 0X1109 +#define UUID_SERVCLASS_AUDIO_SOURCE 0X110A +#define UUID_SERVCLASS_AUDIO_SINK 0X110B +/* Audio/Video Control profile */ +#define UUID_SERVCLASS_AV_REM_CTRL_TARGET 0X110C +/* Advanced Audio Distribution profile */ +#define UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION 0X110D +/* Audio/Video Control profile */ +#define UUID_SERVCLASS_AV_REMOTE_CONTROL 0X110E +/* Audio/Video Control profile */ +#define UUID_SERVCLASS_AV_REM_CTRL_CONTROL 0X110F +#define UUID_SERVCLASS_INTERCOM 0X1110 +#define UUID_SERVCLASS_FAX 0X1111 +#define UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY 0X1112 +#define UUID_SERVCLASS_WAP 0X1113 +#define UUID_SERVCLASS_WAP_CLIENT 0X1114 +#define UUID_SERVCLASS_PANU 0X1115 /* PAN profile */ +#define UUID_SERVCLASS_NAP 0X1116 /* PAN profile */ +#define UUID_SERVCLASS_GN 0X1117 /* PAN profile */ +#define UUID_SERVCLASS_DIRECT_PRINTING 0X1118 /* BPP profile */ +#define UUID_SERVCLASS_REFERENCE_PRINTING 0X1119 /* BPP profile */ +#define UUID_SERVCLASS_IMAGING 0X111A /* Imaging profile */ +#define UUID_SERVCLASS_IMAGING_RESPONDER 0X111B /* Imaging profile */ +#define UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE 0X111C /* Imaging profile */ +#define UUID_SERVCLASS_IMAGING_REF_OBJECTS 0X111D /* Imaging profile */ +#define UUID_SERVCLASS_HF_HANDSFREE 0X111E /* Handsfree profile */ +#define UUID_SERVCLASS_AG_HANDSFREE 0X111F /* Handsfree profile */ +#define UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE 0X1120 /* BPP profile */ +#define UUID_SERVCLASS_REFLECTED_UI 0X1121 /* BPP profile */ +#define UUID_SERVCLASS_BASIC_PRINTING 0X1122 /* BPP profile */ +#define UUID_SERVCLASS_PRINTING_STATUS 0X1123 /* BPP profile */ +#define UUID_SERVCLASS_HUMAN_INTERFACE 0X1124 /* HID profile */ +#define UUID_SERVCLASS_CABLE_REPLACEMENT 0X1125 /* HCRP profile */ +#define UUID_SERVCLASS_HCRP_PRINT 0X1126 /* HCRP profile */ +#define UUID_SERVCLASS_HCRP_SCAN 0X1127 /* HCRP profile */ +/* CAPI Message Transport Protocol*/ +#define UUID_SERVCLASS_COMMON_ISDN_ACCESS 0X1128 +/* Video Conferencing profile */ +#define UUID_SERVCLASS_VIDEO_CONFERENCING_GW 0X1129 +/* Unrestricted Digital Information profile */ +#define UUID_SERVCLASS_UDI_MT 0X112A +/* Unrestricted Digital Information profile */ +#define UUID_SERVCLASS_UDI_TA 0X112B +#define UUID_SERVCLASS_VCP 0X112C /* Video Conferencing profile */ +#define UUID_SERVCLASS_SAP 0X112D /* SIM Access profile */ +#define UUID_SERVCLASS_PBAP_PCE 0X112E /* Phonebook Access - PCE */ +#define UUID_SERVCLASS_PBAP_PSE 0X112F /* Phonebook Access - PSE */ +#define UUID_SERVCLASS_PHONE_ACCESS 0x1130 +#define UUID_SERVCLASS_HEADSET_HS 0x1131 /* Headset - HS, from HSP v1.2 */ +#define UUID_SERVCLASS_MPS_PROFILE \ + 0x113A /* Multi-Profile Specification - Profile */ +#define UUID_SERVCLASS_MPS_SC \ + 0x113B /* Multi-Profile Specification - Service Class */ +#define UUID_SERVCLASS_PNP_INFORMATION 0X1200 /* Device Identification */ +#define UUID_SERVCLASS_GENERIC_NETWORKING 0X1201 +#define UUID_SERVCLASS_GENERIC_FILETRANSFER 0X1202 +#define UUID_SERVCLASS_GENERIC_AUDIO 0X1203 +#define UUID_SERVCLASS_GENERIC_TELEPHONY 0X1204 +#define UUID_SERVCLASS_UPNP_SERVICE 0X1205 /* UPNP_Service [ESDP] */ +#define UUID_SERVCLASS_UPNP_IP_SERVICE 0X1206 /* UPNP_IP_Service [ESDP] */ +#define UUID_SERVCLASS_ESDP_UPNP_IP_PAN 0X1300 /* UPNP_IP_PAN [ESDP] */ +#define UUID_SERVCLASS_ESDP_UPNP_IP_LAP 0X1301 /* UPNP_IP_LAP [ESDP] */ +#define UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP 0X1302 /* UPNP_L2CAP [ESDP] */ + +/* Video Distribution Profile (VDP) */ +#define UUID_SERVCLASS_VIDEO_SOURCE 0X1303 +#define UUID_SERVCLASS_VIDEO_SINK 0X1304 +#define UUID_SERVCLASS_VIDEO_DISTRIBUTION 0X1305 + +#define UUID_SERVCLASS_HDP_PROFILE 0X1400 /* Health Device profile (HDP) */ +#define UUID_SERVCLASS_HDP_SOURCE 0X1401 /* Health Device profile (HDP) */ +#define UUID_SERVCLASS_HDP_SINK 0X1402 /* Health Device profile (HDP) */ +#define UUID_SERVCLASS_MAP_PROFILE 0X1134 /* MAP profile */ +#define UUID_SERVCLASS_MESSAGE_ACCESS 0X1132 /* Message Access Service */ +#define UUID_SERVCLASS_MESSAGE_NOTIFICATION \ + 0X1133 /* Message Notification Service */ + +#define UUID_SERVCLASS_GAP_SERVER 0x1800 +#define UUID_SERVCLASS_GATT_SERVER 0x1801 +#define UUID_SERVCLASS_DEVICE_INFO 0x180A /* device info service */ +#define UUID_SERVCLASS_LE_HID 0x1812 /* HID over LE */ +#define UUID_SERVCLASS_SCAN_PARAM 0x1813 /* Scan Parameter service */ + +#define UUID_SERVCLASS_VOLUME_CONTROL_SERVER 0x1844 +#define UUID_SERVCLASS_GMCS_SERVER 0x1849 /* Generic Media Control Service */ +#define UUID_SERVCLASS_GTBS_SERVER \ + 0x184c /* Generic Telephony Bearer \ + Service*/ +#define UUID_SERVCLASS_TMAS_SERVER \ + 0x1855 /* Telephone and Media Audio Service */ diff --git a/system/stack/include/btm_api.h b/system/stack/include/btm_api.h index 72f680d85531b9cc6905853718421e25284040ee..24fe955de8f65a32a6c4fb9e2d8b9c2cdaf43990 100644 --- a/system/stack/include/btm_api.h +++ b/system/stack/include/btm_api.h @@ -28,14 +28,8 @@ #include "device/include/esco_parameters.h" #include "stack/btm/neighbor_inquiry.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/bt_octets.h" #include "stack/include/btm_api_types.h" -#include "stack/include/btm_log_history.h" #include "stack/include/btm_status.h" -#include "stack/include/sco_client_callbacks.h" -#include "stack/include/sdp_api.h" -#include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -157,68 +151,39 @@ void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len, /******************************************************************************* * - * Function BTM_AllocateSCN - * - * Description Look through the Server Channel Numbers for a free one to be - * used with an RFCOMM connection. - * - * Returns Allocated SCN number or 0 if none. - * - ******************************************************************************/ -uint8_t BTM_AllocateSCN(void); - -/******************************************************************************* - * - * Function BTM_TryAllocateSCN - * - * Description Try to allocate a fixed server channel + * Function BTM_WritePageTimeout * - * Returns Returns true if server channel was available + * Description Send HCI Wite Page Timeout. * ******************************************************************************/ -bool BTM_TryAllocateSCN(uint8_t scn); +void BTM_WritePageTimeout(uint16_t timeout); /******************************************************************************* * - * Function BTM_FreeSCN - * - * Description Free the specified SCN. + * Function BTM_WriteVoiceSettings * - * Returns true if successful, false if SCN is not in use or invalid + * Description Send HCI Write Voice Settings command. + * See hcidefs.h for settings bitmask values. * ******************************************************************************/ -bool BTM_FreeSCN(uint8_t scn); +void BTM_WriteVoiceSettings(uint16_t settings); /******************************************************************************* * - * Function BTM_SetTraceLevel - * - * Description This function sets the trace level for BTM. If called with - * a value of 0xFF, it simply returns the current trace level. - * - * Returns The new or current trace level - * - ******************************************************************************/ -uint8_t BTM_SetTraceLevel(uint8_t new_level); - -/******************************************************************************* + * Function BTM_EnableTestMode * - * Function BTM_WritePageTimeout + * Description Send HCI the enable device under test command. * - * Description Send HCI Wite Page Timeout. + * Note: Controller can only be taken out of this mode by + * resetting the controller. * - ******************************************************************************/ -void BTM_WritePageTimeout(uint16_t timeout); - -/******************************************************************************* + * Returns + * BTM_SUCCESS Command sent. + * BTM_NO_RESOURCES If out of resources to send the command. * - * Function BTM_WriteVoiceSettings - * - * Description Send HCI Write Voice Settings command. - * See hcidefs.h for settings bitmask values. * ******************************************************************************/ -void BTM_WriteVoiceSettings(uint16_t settings); +tBTM_STATUS BTM_EnableTestMode(void); /******************************************************************************* * DEVICE DISCOVERY FUNCTIONS - Inquiry, Remote Name, Discovery, Class of Device @@ -387,19 +352,13 @@ tBTM_STATUS BTM_CancelRemoteDeviceName(void); /******************************************************************************* * - * Function BTM_IsRemoteNameKnown - * - * Description This function checks if the remote name is known. + * Function BTM_IsRemoteVersionReceived * - * Input Params: bd_addr: Address of remote - * transport: Transport, auto if unknown - * - * Returns - * true if name is known, false otherwise + * Returns Returns true if "LE Read remote version info" was already + * received on LE transport for this device. * ******************************************************************************/ -bool BTM_IsRemoteNameKnown(const RawAddress& remote_bda, - tBT_TRANSPORT transport); +bool BTM_IsRemoteVersionReceived(const RawAddress& remote_bda); /******************************************************************************* * @@ -594,59 +553,17 @@ void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status, ******************************************************************************/ uint8_t BTM_GetNumScoLinks(void); -/***************************************************************************** - * SECURITY MANAGEMENT FUNCTIONS - ****************************************************************************/ - -/******************************************************************************* - * - * Function BTM_SecAddDevice - * - * Description Add/modify device. This function will be normally called - * during host startup to restore all required information - * stored in the NVRAM. - * dev_class, bd_name, link_key, and features are NULL if - * unknown - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, - const BD_NAME& bd_name, uint8_t* features, - LinkKey* link_key, uint8_t key_type, uint8_t pin_length); - -/** Free resources associated with the device associated with |bd_addr| address. - * - * *** WARNING *** - * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function - * is called, also any of it's fields. i.e. if you use p_dev_rec->bd_addr, it is - * no longer valid! - * *** WARNING *** - * - * Returns true if removed OK, false if not found or ACL link is active. - */ -bool BTM_SecDeleteDevice(const RawAddress& bd_addr); - -/******************************************************************************* - * - * Function BTM_SecClearSecurityFlags - * - * Description Reset the security flags (mark as not-paired) for a given - * remove device. - * - ******************************************************************************/ -void BTM_SecClearSecurityFlags(const RawAddress& bd_addr); - /******************************************************************************* * - * Function btm_sec_is_a_bonded_dev + * Function BTM_GetScoDebugDump * - * Description Is the specified device is a bonded device + * Description Get the status of SCO. This function is only used for + * testing and debugging purposes. * - * Returns true - dev is bonded + * Returns Data with SCO related debug dump. * ******************************************************************************/ -bool btm_sec_is_a_bonded_dev(const RawAddress& bda); +tBTM_SCO_DEBUG_DUMP BTM_GetScoDebugDump(void); /******************************************************************************* * @@ -665,65 +582,6 @@ bool btm_sec_is_a_bonded_dev(const RawAddress& bda); ******************************************************************************/ tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(const RawAddress& bd_addr); -/***************************************************************************** - * POWER MANAGEMENT FUNCTIONS - ****************************************************************************/ -/******************************************************************************* - * - * Function BTM_PmRegister - * - * Description register or deregister with power manager - * - * Returns BTM_SUCCESS if successful, - * BTM_NO_RESOURCES if no room to hold registration - * BTM_ILLEGAL_VALUE - * - ******************************************************************************/ -tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id, - tBTM_PM_STATUS_CBACK* p_cb); - -// Notified by ACL that a new link is connected -void BTM_PM_OnConnected(uint16_t handle, const RawAddress& remote_bda); - -// Notified by ACL that a link is disconnected -void BTM_PM_OnDisconnected(uint16_t handle); - -/******************************************************************************* - * - * Function BTM_SetPowerMode - * - * Description store the mode in control block or - * alter ACL connection behavior. - * - * Returns BTM_SUCCESS if successful, - * BTM_UNKNOWN_ADDR if bd addr is not active or bad - * - ******************************************************************************/ -tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda, - const tBTM_PM_PWR_MD* p_mode); -bool BTM_SetLinkPolicyActiveMode(const RawAddress& remote_bda); - -/******************************************************************************* - * - * Function BTM_SetSsrParams - * - * Description This sends the given SSR parameters for the given ACL - * connection if it is in ACTIVE mode. - * - * Input Param remote_bda - device address of desired ACL connection - * max_lat - maximum latency (in 0.625ms)(0-0xFFFE) - * min_rmt_to - minimum remote timeout - * min_loc_to - minimum local timeout - * - * - * Returns BTM_SUCCESS if the HCI command is issued successful, - * BTM_UNKNOWN_ADDR if bd addr is not active or bad - * BTM_CMD_STORED if the command is stored - * - ******************************************************************************/ -tBTM_STATUS BTM_SetSsrParams(const RawAddress& remote_bda, uint16_t max_lat, - uint16_t min_rmt_to, uint16_t min_loc_to); - /******************************************************************************* * * Function BTM_GetHCIConnHandle @@ -770,22 +628,6 @@ void BTM_RequestPeerSCA(const RawAddress& remote_bda, tBT_TRANSPORT transport); ******************************************************************************/ uint8_t BTM_GetPeerSCA(const RawAddress& remote_bda, tBT_TRANSPORT transport); -/******************************************************************************* - * - * Function BTM_DeleteStoredLinkKey - * - * Description This function is called to delete link key for the specified - * device addresses from the NVRAM storage attached to the - * Bluetooth controller. - * - * Parameters: bd_addr - Addresses of the devices - * p_cb - Call back function to be called to return - * the results - * - ******************************************************************************/ -tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* bd_addr, - tBTM_CMPL_CB* p_cb); - /******************************************************************************* * * Function BTM_WriteEIR @@ -816,23 +658,6 @@ tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff); ******************************************************************************/ bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16); -/******************************************************************************* - * - * Function BTM_HasInquiryEirService - * - * Description Return if a UUID is in the bit map of a UUID list. - * - * Parameters p_results - inquiry results - * uuid16 - UUID 16-bit - * - * Returns BTM_EIR_FOUND - if found - * BTM_EIR_NOT_FOUND - if not found and it is a complete list - * BTM_EIR_UNKNOWN - if not found and it is not complete list - * - ******************************************************************************/ -tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS* p_results, - uint16_t uuid16); - /******************************************************************************* * * Function BTM_AddEirService @@ -910,18 +735,6 @@ uint8_t BTM_GetEirUuidList(const uint8_t* p_eir, size_t eir_len, uint8_t uuid_size, uint8_t* p_num_uuid, uint8_t* p_uuid_list, uint8_t max_num_uuid); -/******************************************************************************* - * - * Function BTM_PM_ReadControllerState - * - * Description This function is called to obtain the controller state - * - * Returns Controller state (BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and - * BTM_CONTRL_IDLE) - * - ******************************************************************************/ -tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void); - /** * Send remote name request, either to legacy HCI, or to GD shim Name module */ @@ -937,8 +750,6 @@ uint16_t BTM_GetMaxPacketSize(const RawAddress& addr); tBTM_STATUS BTM_BT_Quality_Report_VSE_Register( bool is_register, tBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver); -uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr); - typedef void(BTM_CONSOLIDATION_CB)(const RawAddress& identity_addr, const RawAddress& rpa); void BTM_SetConsolidationCallback(BTM_CONSOLIDATION_CB* cb); diff --git a/system/stack/include/btm_api_types.h b/system/stack/include/btm_api_types.h index 5113bd678d47fdd938d4017764655f323852f3fa..be170ca65b7bf5ee1b8c036a0900a03a7c020633 100644 --- a/system/stack/include/btm_api_types.h +++ b/system/stack/include/btm_api_types.h @@ -24,17 +24,10 @@ #include #include -#include "internal_include/bt_target.h" #include "stack/include/bt_dev_class.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_name.h" -#include "stack/include/bt_octets.h" -#include "stack/include/btm_status.h" -#include "stack/include/hci_mode.h" #include "stack/include/hcidefs.h" -#include "stack/include/smp_api_types.h" -#include "types/ble_address_with_type.h" -#include "types/bt_transport.h" +#include "stack/include/sdpdefs.h" #include "types/raw_address.h" /* Structure returned with Vendor Specific Command complete callback */ @@ -80,21 +73,6 @@ typedef void(tBTM_VSC_CMPL_CB)(tBTM_VSC_CMPL* p1); */ #define BTM_EIR_MAX_SERVICES 46 -/* search result in EIR of inquiry database */ -#define BTM_EIR_FOUND 0 -#define BTM_EIR_NOT_FOUND 1 -#define BTM_EIR_UNKNOWN 2 - -typedef uint8_t tBTM_EIR_SEARCH_RESULT; - -typedef enum : uint8_t { - BTM_BLE_SEC_NONE = 0, - /* encrypt the link using current key */ - BTM_BLE_SEC_ENCRYPT = 1, - BTM_BLE_SEC_ENCRYPT_NO_MITM = 2, - BTM_BLE_SEC_ENCRYPT_MITM = 3, -} tBTM_BLE_SEC_ACT; - /******************************************************************************* * BTM Services MACROS handle array of uint32_t bits for more than 32 services ******************************************************************************/ @@ -104,22 +82,6 @@ typedef enum : uint8_t { (((uint32_t)BTM_EIR_MAX_SERVICES / BTM_EIR_ARRAY_BITS) + \ (((uint32_t)BTM_EIR_MAX_SERVICES % BTM_EIR_ARRAY_BITS) ? 1 : 0)) -/* MACRO to set the service bit mask in a bit stream */ -#define BTM_EIR_SET_SERVICE(p, service) \ - (((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] |= \ - ((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) - -/* MACRO to clear the service bit mask in a bit stream */ -#define BTM_EIR_CLR_SERVICE(p, service) \ - (((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] &= \ - ~((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) - -/* MACRO to check the service bit mask in a bit stream */ -#define BTM_EIR_HAS_SERVICE(p, service) \ - ((((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] & \ - ((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) >> \ - (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS)) - /* start of EIR in HCI buffer, 4 bytes = HCI Command(2) + Length(1) + FEC_Req(1) */ #define BTM_HCI_EIR_OFFSET (BT_HDR_SIZE + 4) @@ -129,12 +91,6 @@ typedef enum : uint8_t { ***************************/ /* Definitions of the parameters passed to BTM_StartInquiry. */ -typedef struct /* contains the two device class condition fields */ -{ - DEV_CLASS dev_class; - DEV_CLASS dev_class_mask; -} tBTM_COD_COND; - constexpr uint8_t BLE_EVT_CONNECTABLE_BIT = 0; constexpr uint8_t BLE_EVT_SCANNABLE_BIT = 1; constexpr uint8_t BLE_EVT_DIRECTED_BIT = 2; @@ -149,15 +105,6 @@ constexpr uint8_t PHY_LE_CODED = 0x04; constexpr uint8_t NO_ADI_PRESENT = 0xFF; constexpr uint8_t TX_POWER_NOT_PRESENT = 0x7F; -typedef struct { - uint8_t pcm_intf_rate; /* PCM interface rate: 0: 128kbps, 1: 256 kbps; - 2:512 bps; 3: 1024kbps; 4: 2048kbps */ - uint8_t frame_type; /* frame type: 0: short; 1: long */ - uint8_t sync_mode; /* sync mode: 0: peripheral; 1: central */ - uint8_t clock_mode; /* clock mode: 0: peripheral; 1: central */ - -} tBTM_SCO_PCM_PARAM; - /***************************************************************************** * ACL CHANNEL MANAGEMENT ****************************************************************************/ @@ -173,9 +120,6 @@ typedef struct { /* Define an invalid SCO index and an invalid HCI handle */ #define BTM_INVALID_SCO_INDEX 0xFFFF -/* Define an invalid SCO disconnect reason */ -#define BTM_INVALID_SCO_DISC_REASON 0xFFFF - #define BTM_SCO_LINK_ONLY_MASK \ (ESCO_PKT_TYPES_MASK_HV1 | ESCO_PKT_TYPES_MASK_HV2 | ESCO_PKT_TYPES_MASK_HV3) @@ -192,29 +136,24 @@ typedef uint8_t tBTM_SCO_TYPE; /******************* * SCO Codec Types *******************/ -// TODO(google) This should use common definitions +// TODO(b/285458890) This should use common definitions #define BTM_SCO_CODEC_NONE 0x0000 #define BTM_SCO_CODEC_CVSD 0x0001 #define BTM_SCO_CODEC_MSBC 0x0002 #define BTM_SCO_CODEC_LC3 0x0004 +#define BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK 0x0008 +#define BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK 0x0016 +#define BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK 0x0032 +#define BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK 0x0064 typedef uint16_t tBTM_SCO_CODEC_TYPE; /******************* * SCO Voice Settings *******************/ -#define BTM_VOICE_SETTING_CVSD \ - ((uint16_t)(HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | \ - HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_CVSD)) - -#define BTM_VOICE_SETTING_TRANS \ - ((uint16_t)(HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | \ - HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_TRANSPNT)) /******************* * SCO Data Status *******************/ -typedef uint8_t tBTM_SCO_DATA_FLAG; - /*************************** * SCO Callback Functions ***************************/ @@ -227,15 +166,6 @@ typedef void(tBTM_SCO_CB)(uint16_t sco_inx); #define BTM_ESCO_CONN_REQ_EVT 2 typedef uint8_t tBTM_ESCO_EVT; -/* Structure passed with SCO change command and events. - * Used by both Sync and Enhanced sync messaging - */ -typedef struct { - uint16_t max_latency_ms; - uint16_t packet_types; - uint8_t retransmission_effort; -} tBTM_CHG_ESCO_PARAMS; - /* Returned by BTM_ReadEScoLinkParms() */ struct tBTM_ESCO_DATA { RawAddress bd_addr; @@ -258,573 +188,69 @@ typedef union { ***************************/ typedef void(tBTM_ESCO_CBACK)(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA* p_data); -/***************************************************************************** - * SECURITY MANAGEMENT - ****************************************************************************/ -/******************************* - * Security Manager Constants - *******************************/ - -typedef enum : uint8_t { - BTM_SEC_MODE_SERVICE = 2, - BTM_SEC_MODE_SP = 4, - BTM_SEC_MODE_SC = 6, -} tSECURITY_MODE; - -inline std::string security_mode_text(const tSECURITY_MODE& security_mode) { - switch (security_mode) { - case BTM_SEC_MODE_SERVICE: - return std::string("service"); - case BTM_SEC_MODE_SP: - return std::string("simple pairing"); - case BTM_SEC_MODE_SC: - return std::string("secure connections only"); - default: - return base::StringPrintf("UNKNOWN[%hhu]", security_mode); - } -} - -/* BTM_SEC security masks */ -enum : uint16_t { - /* Nothing required */ - BTM_SEC_NONE = 0x0000, - /* Inbound call requires authentication */ - BTM_SEC_IN_AUTHENTICATE = 0x0002, - /* Inbound call requires encryption */ - BTM_SEC_IN_ENCRYPT = 0x0004, - /* Outbound call requires authentication */ - BTM_SEC_OUT_AUTHENTICATE = 0x0010, - /* Outbound call requires encryption */ - BTM_SEC_OUT_ENCRYPT = 0x0020, - /* Secure Connections Only Mode */ - BTM_SEC_MODE4_LEVEL4 = 0x0040, - /* Need to switch connection to be central */ - BTM_SEC_FORCE_CENTRAL = 0x0100, - /* Need to switch connection to be central */ - BTM_SEC_ATTEMPT_CENTRAL = 0x0200, - /* Need to switch connection to be peripheral */ - BTM_SEC_FORCE_PERIPHERAL = 0x0400, - /* Try to switch connection to be peripheral */ - BTM_SEC_ATTEMPT_PERIPHERAL = 0x0800, - /* inbound Do man in the middle protection */ - BTM_SEC_IN_MITM = 0x1000, - /* outbound Do man in the middle protection */ - BTM_SEC_OUT_MITM = 0x2000, - /* enforce a minimum of 16 digit for sec mode 2 */ - BTM_SEC_IN_MIN_16_DIGIT_PIN = 0x4000, -}; - -/* Security Flags [bit mask] (BTM_GetSecurityFlags) -*/ -#define BTM_SEC_FLAG_AUTHENTICATED 0x02 -#define BTM_SEC_FLAG_ENCRYPTED 0x04 -#define BTM_SEC_FLAG_LKEY_KNOWN 0x10 -#define BTM_SEC_FLAG_LKEY_AUTHED 0x20 - -/* Link Key types used to generate the new link key. - * returned in link key notification callback function -*/ -#define BTM_LKEY_TYPE_COMBINATION HCI_LKEY_TYPE_COMBINATION -#define BTM_LKEY_TYPE_REMOTE_UNIT HCI_LKEY_TYPE_REMOTE_UNIT -#define BTM_LKEY_TYPE_DEBUG_COMB HCI_LKEY_TYPE_DEBUG_COMB -#define BTM_LKEY_TYPE_UNAUTH_COMB HCI_LKEY_TYPE_UNAUTH_COMB -#define BTM_LKEY_TYPE_AUTH_COMB HCI_LKEY_TYPE_AUTH_COMB -#define BTM_LKEY_TYPE_CHANGED_COMB HCI_LKEY_TYPE_CHANGED_COMB - -#define BTM_LKEY_TYPE_UNAUTH_COMB_P_256 HCI_LKEY_TYPE_UNAUTH_COMB_P_256 -#define BTM_LKEY_TYPE_AUTH_COMB_P_256 HCI_LKEY_TYPE_AUTH_COMB_P_256 - -inline std::string linkkey_type_text(const int linkkey_type) { - switch (linkkey_type) { - case BTM_LKEY_TYPE_COMBINATION: - return std::string("COMBINATION"); - case BTM_LKEY_TYPE_REMOTE_UNIT: - return std::string("REMOTE_UNIT"); - case BTM_LKEY_TYPE_DEBUG_COMB: - return std::string("DEBUG_COMB"); - case BTM_LKEY_TYPE_UNAUTH_COMB: - return std::string("UNAUTH_COMB"); - case BTM_LKEY_TYPE_AUTH_COMB: - return std::string("AUTH_COMB"); - case BTM_LKEY_TYPE_CHANGED_COMB: - return std::string("CHANGED_COMB"); - case BTM_LKEY_TYPE_UNAUTH_COMB_P_256: - return std::string("UNAUTH_COMB_P_256"); - case BTM_LKEY_TYPE_AUTH_COMB_P_256: - return std::string("AUTH_COMB_P_256"); - default: - return base::StringPrintf("UNKNOWN[0x%02x]", linkkey_type); - } -} - -/* "easy" requirements for LK derived from LTK */ -#define BTM_LTK_DERIVED_LKEY_OFFSET 0x20 -#define BTM_LKEY_TYPE_IGNORE \ - 0xff /* used when event is response from \ - hci return link keys request */ - -typedef uint8_t tBTM_LINK_KEY_TYPE; - -/* Protocol level security (BTM_SetSecurityLevel) */ -#define BTM_SEC_PROTO_RFCOMM 3 -#define BTM_SEC_PROTO_BNEP 5 -#define BTM_SEC_PROTO_HID 6 /* HID */ -#define BTM_SEC_PROTO_AVDT 7 - -#define BTM_SEC_SERVICE_HEADSET 8 -#define BTM_SEC_SERVICE_HEADSET_AG 12 -#define BTM_SEC_SERVICE_AG_HANDSFREE 29 -#define BTM_SEC_SERVICE_RFC_MUX 42 -#define BTM_SEC_SERVICE_HEARING_AID_LEFT 54 -#define BTM_SEC_SERVICE_HEARING_AID_RIGHT 55 -#define BTM_SEC_SERVICE_EATT 56 +/************************** + * SCO Types for Debugging and Testing + **************************/ -/* Update these as services are added */ -#define BTM_SEC_SERVICE_FIRST_EMPTY 57 - -#ifndef BTM_SEC_MAX_SERVICES -#define BTM_SEC_MAX_SERVICES 75 -#endif - -/******************************************************************************* - * Security Services MACROS handle array of uint32_t bits for more than 32 - * trusted services - ******************************************************************************/ +/* Define the structure for the WBS/SWB packet status dump. */ +typedef struct { + uint64_t begin_ts_raw_us; + uint64_t end_ts_raw_us; + std::string status_in_hex; + std::string status_in_binary; +} tBTM_SCO_PKT_STATUS_DATA; -enum { - BTM_SP_IO_REQ_EVT, /* received IO_CAPABILITY_REQUEST event */ - BTM_SP_IO_RSP_EVT, /* received IO_CAPABILITY_RESPONSE event */ - BTM_SP_CFM_REQ_EVT, /* received USER_CONFIRMATION_REQUEST event */ - BTM_SP_KEY_NOTIF_EVT, /* received USER_PASSKEY_NOTIFY event */ - BTM_SP_KEY_REQ_EVT, /* received USER_PASSKEY_REQUEST event */ - BTM_SP_LOC_OOB_EVT, /* received result for READ_LOCAL_OOB_DATA command */ - BTM_SP_RMT_OOB_EVT, /* received REMOTE_OOB_DATA_REQUEST event */ -}; -typedef uint8_t tBTM_SP_EVT; - -enum : uint8_t { - BTM_IO_CAP_OUT = 0, /* DisplayOnly */ - BTM_IO_CAP_IO = 1, /* DisplayYesNo */ - BTM_IO_CAP_IN = 2, /* KeyboardOnly */ - BTM_IO_CAP_NONE = 3, /* NoInputNoOutput */ - BTM_IO_CAP_KBDISP = 4, /* Keyboard display */ - BTM_IO_CAP_MAX = 5, - BTM_IO_CAP_UNKNOWN = 0xFF /* Unknown value */ -}; -typedef uint8_t tBTM_IO_CAP; - -inline std::string io_capabilities_text(const tBTM_IO_CAP& io_caps) { - switch (io_caps) { - case BTM_IO_CAP_OUT: - return std::string("Display only"); - case BTM_IO_CAP_IO: - return std::string("Display yes-no"); - case BTM_IO_CAP_IN: - return std::string("Keyboard Only"); - case BTM_IO_CAP_NONE: - return std::string("No input or output"); - case BTM_IO_CAP_KBDISP: - return std::string("Keyboard-Display"); +/* Returned by BTM_GetScoDebugDump */ +typedef struct { + bool is_active; + uint16_t codec_id; + int total_num_decoded_frames; + double pkt_loss_ratio; + tBTM_SCO_PKT_STATUS_DATA latest_data; +} tBTM_SCO_DEBUG_DUMP; + +inline std::string sco_codec_type_text(tBTM_SCO_CODEC_TYPE codec_type) { + switch (codec_type) { + case BTM_SCO_CODEC_CVSD: + return "CVSD"; + case BTM_SCO_CODEC_MSBC: + return "MSBC"; + case BTM_SCO_CODEC_LC3: + return "LC3"; default: - return base::StringPrintf("UNKNOWN[%hhu]", io_caps); + return "UNKNOWN"; } } -#define BTM_MAX_PASSKEY_VAL (999999) - -typedef enum : uint8_t { - /* MITM Protection Not Required - Single Profile/non-bonding Numeric - * comparison with automatic accept allowed */ - // NO_BONDING - BTM_AUTH_SP_NO = 0, - /* MITM Protection Required - Single Profile/non-bonding. Use IO Capabilities - * to determine authentication procedure */ - // NO_BONDING_MITM_PROTECTION - BTM_AUTH_SP_YES = 1, - /* MITM Protection Not Required - All Profiles/dedicated bonding Numeric - * comparison with automatic accept allowed */ - // DEDICATED_BONDING - BTM_AUTH_AP_NO = 2, - /* MITM Protection Required - All Profiles/dedicated bonding Use IO - * Capabilities to determine authentication procedure */ - // DEDICATED_BONDING_MITM_PROTECTION - BTM_AUTH_AP_YES = 3, - /* MITM Protection Not Required - Single Profiles/general bonding Numeric - * comparison with automatic accept allowed */ - // GENERAL_BONDING - BTM_AUTH_SPGB_NO = 4, - /* MITM Protection Required - Single Profiles/general bonding Use IO - * Capabilities to determine authentication procedure */ - // GENERAL_BONDING_MITM_PROTECTION - BTM_AUTH_SPGB_YES = 5, -} tBTM_AUTH; - -/* this bit is ORed with BTM_AUTH_SP_* when IO exchange for dedicated bonding */ -#define BTM_AUTH_DD_BOND 2 -#define BTM_AUTH_BONDS 6 /* the general/dedicated bonding bits */ -#define BTM_AUTH_YN_BIT 1 /* this is the Yes or No bit */ - -#define BTM_BLE_INITIATOR_KEY_SIZE 15 -#define BTM_BLE_RESPONDER_KEY_SIZE 15 -#define BTM_BLE_MAX_KEY_SIZE 16 - -typedef uint8_t tBTM_AUTH_REQ; - -enum { - BTM_OOB_NONE, - BTM_OOB_PRESENT_192, - BTM_OOB_PRESENT_256, - BTM_OOB_PRESENT_192_AND_256, - BTM_OOB_UNKNOWN -}; - -typedef uint8_t tBTM_OOB_DATA; - -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - -inline std::string btm_oob_data_text(const tBTM_OOB_DATA& data) { - switch (data) { - CASE_RETURN_TEXT(BTM_OOB_NONE); - CASE_RETURN_TEXT(BTM_OOB_PRESENT_192); - CASE_RETURN_TEXT(BTM_OOB_PRESENT_256); - CASE_RETURN_TEXT(BTM_OOB_PRESENT_192_AND_256); - CASE_RETURN_TEXT(BTM_OOB_UNKNOWN); +inline uint16_t sco_codec_type_to_id(tBTM_SCO_CODEC_TYPE codec_type) { + switch (codec_type) { + case BTM_SCO_CODEC_CVSD: + return UUID_CODEC_CVSD; + case BTM_SCO_CODEC_MSBC: + return UUID_CODEC_MSBC; + case BTM_SCO_CODEC_LC3: + return UUID_CODEC_LC3; default: - return std::string("UNKNOWN[") + std::to_string(data) + std::string("]"); + return 0; } } -#undef CASE_RETURN_TEXT - -/* data type for BTM_SP_IO_REQ_EVT */ -typedef struct { - RawAddress bd_addr; /* peer address */ - tBTM_IO_CAP io_cap; /* local IO capabilities */ - tBTM_OOB_DATA oob_data; /* OOB data present (locally) for the peer device */ - tBTM_AUTH_REQ auth_req; /* Authentication required (for local device) */ - bool is_orig; /* true, if local device initiated the SP process */ -} tBTM_SP_IO_REQ; - -/* data type for BTM_SP_IO_RSP_EVT */ -typedef struct { - RawAddress bd_addr; /* peer address */ - tBTM_IO_CAP io_cap; /* peer IO capabilities */ - tBTM_OOB_DATA - oob_data; /* OOB data present at peer device for the local device */ - tBTM_AUTH_REQ auth_req; /* Authentication required for peer device */ -} tBTM_SP_IO_RSP; - -/* data type for BTM_SP_CFM_REQ_EVT */ -typedef struct { - RawAddress bd_addr; /* peer address */ - DEV_CLASS dev_class; /* peer CoD */ - tBTM_BD_NAME bd_name; /* peer device name */ - uint32_t num_val; /* the numeric value for comparison. If just_works, do not - show this number to UI */ - bool just_works; /* true, if "Just Works" association model */ - tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */ - tBTM_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */ - tBTM_IO_CAP loc_io_caps; /* IO Capabilities of the local device */ - tBTM_IO_CAP rmt_io_caps; /* IO Capabilities of the remot device */ -} tBTM_SP_CFM_REQ; - -/* data type for BTM_SP_KEY_REQ_EVT */ -typedef struct { - RawAddress bd_addr; /* peer address */ - DEV_CLASS dev_class; /* peer CoD */ - tBTM_BD_NAME bd_name; /* peer device name */ -} tBTM_SP_KEY_REQ; - -/* data type for BTM_SP_KEY_NOTIF_EVT */ -typedef struct { - RawAddress bd_addr; /* peer address */ - DEV_CLASS dev_class; /* peer CoD */ - tBTM_BD_NAME bd_name; /* peer device name */ - uint32_t passkey; /* passkey */ -} tBTM_SP_KEY_NOTIF; - -/* data type for BTM_SP_LOC_OOB_EVT */ -typedef struct { - tBTM_STATUS status; /* */ - Octet16 c; /* Simple Pairing Hash C */ - Octet16 r; /* Simple Pairing Randomnizer R */ -} tBTM_SP_LOC_OOB; - -/* data type for BTM_SP_RMT_OOB_EVT */ -typedef struct { - RawAddress bd_addr; /* peer address */ - DEV_CLASS dev_class; /* peer CoD */ - tBTM_BD_NAME bd_name; /* peer device name */ -} tBTM_SP_RMT_OOB; - -typedef union { - tBTM_SP_IO_REQ io_req; /* BTM_SP_IO_REQ_EVT */ - tBTM_SP_IO_RSP io_rsp; /* BTM_SP_IO_RSP_EVT */ - tBTM_SP_CFM_REQ cfm_req; /* BTM_SP_CFM_REQ_EVT */ - tBTM_SP_KEY_NOTIF key_notif; /* BTM_SP_KEY_NOTIF_EVT */ - tBTM_SP_KEY_REQ key_req; /* BTM_SP_KEY_REQ_EVT */ - tBTM_SP_LOC_OOB loc_oob; /* BTM_SP_LOC_OOB_EVT */ - tBTM_SP_RMT_OOB rmt_oob; /* BTM_SP_RMT_OOB_EVT */ -} tBTM_SP_EVT_DATA; - -/* Simple Pairing Events. Called by the stack when Simple Pairing related - * events occur. -*/ -typedef tBTM_STATUS(tBTM_SP_CALLBACK)(tBTM_SP_EVT event, - tBTM_SP_EVT_DATA* p_data); - -typedef void(tBTM_MKEY_CALLBACK)(const RawAddress& bd_addr, uint8_t status, - uint8_t key_flag); - -/* Encryption enabled/disabled complete: Optionally passed with - * BTM_SetEncryption. - * Parameters are - * BD Address of remote - * optional data passed in by BTM_SetEncryption - * tBTM_STATUS - result of the operation -*/ -typedef void(tBTM_SEC_CALLBACK)(const RawAddress* bd_addr, - tBT_TRANSPORT trasnport, void* p_ref_data, - tBTM_STATUS result); -typedef tBTM_SEC_CALLBACK tBTM_SEC_CALLBACK; - -/* Bond Cancel complete. Parameters are - * Result of the cancel operation - * -*/ -typedef void(tBTM_BOND_CANCEL_CMPL_CALLBACK)(tBTM_STATUS result); - -/* LE related event and data structure */ -/* received IO_CAPABILITY_REQUEST event */ -#define BTM_LE_IO_REQ_EVT SMP_IO_CAP_REQ_EVT -/* security request event */ -#define BTM_LE_SEC_REQUEST_EVT SMP_SEC_REQUEST_EVT -/* received USER_PASSKEY_NOTIFY event */ -#define BTM_LE_KEY_NOTIF_EVT SMP_PASSKEY_NOTIF_EVT -/* received USER_PASSKEY_REQUEST event */ -#define BTM_LE_KEY_REQ_EVT SMP_PASSKEY_REQ_EVT -/* OOB data request event */ -#define BTM_LE_OOB_REQ_EVT SMP_OOB_REQ_EVT -/* Numeric Comparison request event */ -#define BTM_LE_NC_REQ_EVT SMP_NC_REQ_EVT -/* Peer keypress notification recd event */ -#define BTM_LE_PR_KEYPR_NOT_EVT SMP_PEER_KEYPR_NOT_EVT -/* SC OOB request event (both local and peer OOB data) can be expected in - * response */ -#define BTM_LE_SC_OOB_REQ_EVT SMP_SC_OOB_REQ_EVT -/* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */ -#define BTM_LE_SC_LOC_OOB_EVT SMP_SC_LOC_OOB_DATA_UP_EVT -/* SMP complete event */ -#define BTM_LE_COMPLT_EVT SMP_COMPLT_EVT -#define BTM_LE_LAST_FROM_SMP SMP_BR_KEYS_REQ_EVT -/* KEY update event */ -#define BTM_LE_KEY_EVT (BTM_LE_LAST_FROM_SMP + 1) -#define BTM_LE_CONSENT_REQ_EVT SMP_CONSENT_REQ_EVT -/* Identity address associate event */ -#define BTM_LE_ADDR_ASSOC_EVT SMP_LE_ADDR_ASSOC_EVT -typedef uint8_t tBTM_LE_EVT; - -enum : uint8_t { - BTM_LE_KEY_NONE = 0, - BTM_LE_KEY_PENC = SMP_SEC_KEY_TYPE_ENC, - /* identity key of the peer device */ - BTM_LE_KEY_PID = SMP_SEC_KEY_TYPE_ID, - /* peer SRK */ - BTM_LE_KEY_PCSRK = SMP_SEC_KEY_TYPE_CSRK, - BTM_LE_KEY_PLK = SMP_SEC_KEY_TYPE_LK, - BTM_LE_KEY_LLK = (SMP_SEC_KEY_TYPE_LK << 4), - /* master role security information:div */ - BTM_LE_KEY_LENC = (SMP_SEC_KEY_TYPE_ENC << 4), - /* master device ID key */ - BTM_LE_KEY_LID = (SMP_SEC_KEY_TYPE_ID << 4), - /* local CSRK has been deliver to peer */ - BTM_LE_KEY_LCSRK = (SMP_SEC_KEY_TYPE_CSRK << 4), -}; -typedef uint8_t tBTM_LE_KEY_TYPE; - -#define BTM_LE_AUTH_REQ_NO_BOND SMP_AUTH_NO_BOND /* 0 */ -#define BTM_LE_AUTH_REQ_BOND SMP_AUTH_BOND /* 1 << 0 */ -#define BTM_LE_AUTH_REQ_MITM SMP_AUTH_YN_BIT /* 1 << 2 */ -typedef uint8_t tBTM_LE_AUTH_REQ; -#define BTM_LE_SC_SUPPORT_BIT SMP_SC_SUPPORT_BIT /* (1 << 3) */ -#define BTM_LE_KP_SUPPORT_BIT SMP_KP_SUPPORT_BIT /* (1 << 4) */ -#define BTM_LE_H7_SUPPORT_BIT SMP_H7_SUPPORT_BIT /* (1 << 5) */ - -#define BTM_LE_AUTH_REQ_SC_ONLY SMP_AUTH_SC_ENC_ONLY /* 00101000 */ -#define BTM_LE_AUTH_REQ_SC_BOND SMP_AUTH_SC_GB /* 00101001 */ -#define BTM_LE_AUTH_REQ_SC_MITM SMP_AUTH_SC_MITM_NB /* 00101100 */ -#define BTM_LE_AUTH_REQ_SC_MITM_BOND SMP_AUTH_SC_MITM_GB /* 00101101 */ -#define BTM_LE_AUTH_REQ_MASK SMP_AUTH_MASK /* 0x3D */ - -typedef struct { - /* local IO capabilities */ - tBTM_IO_CAP io_cap; - /* OOB data present (locally) for the peer device */ - uint8_t oob_data; - /* Authentication request (for local device) containing bonding and MITM - * info */ - tBTM_LE_AUTH_REQ auth_req; - uint8_t max_key_size; /* max encryption key size */ - tBTM_LE_KEY_TYPE init_keys; /* keys to be distributed, bit mask */ - tBTM_LE_KEY_TYPE resp_keys; /* keys to be distributed, bit mask */ -} tBTM_LE_IO_REQ; - -/* data type for tBTM_LE_COMPLT */ -typedef struct { - uint8_t reason; - uint8_t sec_level; - bool is_pair_cancel; - bool smp_over_br; -} tBTM_LE_COMPLT; - /***************************************************************************** * POWER MANAGEMENT ****************************************************************************/ /**************************** * Power Manager Constants ****************************/ -/* BTM Power manager status codes */ -enum : uint8_t { - BTM_PM_STS_ACTIVE = HCI_MODE_ACTIVE, // 0x00 - BTM_PM_STS_HOLD = HCI_MODE_HOLD, // 0x01 - BTM_PM_STS_SNIFF = HCI_MODE_SNIFF, // 0x02 - BTM_PM_STS_PARK = HCI_MODE_PARK, // 0x03 - BTM_PM_STS_SSR, /* report the SSR parameters in HCI_SNIFF_SUB_RATE_EVT */ - BTM_PM_STS_PENDING, /* when waiting for status from controller */ - BTM_PM_STS_ERROR /* when HCI command status returns error */ -}; -typedef uint8_t tBTM_PM_STATUS; - -inline std::string power_mode_status_text(tBTM_PM_STATUS status) { - switch (status) { - case BTM_PM_STS_ACTIVE: - return std::string("active"); - case BTM_PM_STS_HOLD: - return std::string("hold"); - case BTM_PM_STS_SNIFF: - return std::string("sniff"); - case BTM_PM_STS_PARK: - return std::string("park"); - case BTM_PM_STS_SSR: - return std::string("sniff_subrating"); - case BTM_PM_STS_PENDING: - return std::string("pending"); - case BTM_PM_STS_ERROR: - return std::string("error"); - default: - return std::string("UNKNOWN"); - } -} - -/* BTM Power manager modes */ -enum : uint8_t { - BTM_PM_MD_ACTIVE = HCI_MODE_ACTIVE, // 0x00 - BTM_PM_MD_HOLD = HCI_MODE_HOLD, // 0x01 - BTM_PM_MD_SNIFF = HCI_MODE_SNIFF, // 0x02 - BTM_PM_MD_PARK = HCI_MODE_PARK, // 0x03 - BTM_PM_MD_FORCE = 0x10, /* OR this to force ACL link to a certain mode */ - BTM_PM_MD_UNKNOWN = 0xEF, -}; -typedef uint8_t tBTM_PM_MODE; -#define HCI_TO_BTM_POWER_MODE(mode) (static_cast(mode)) - -inline bool is_legal_power_mode(tBTM_PM_MODE mode) { - switch (mode & ~BTM_PM_MD_FORCE) { - case BTM_PM_MD_ACTIVE: - case BTM_PM_MD_HOLD: - case BTM_PM_MD_SNIFF: - case BTM_PM_MD_PARK: - return true; - default: - return false; - } -} - -inline std::string power_mode_text(tBTM_PM_MODE mode) { - std::string s = base::StringPrintf((mode & BTM_PM_MD_FORCE) ? "" : "forced:"); - switch (mode & ~BTM_PM_MD_FORCE) { - case BTM_PM_MD_ACTIVE: - return s + std::string("active"); - case BTM_PM_MD_HOLD: - return s + std::string("hold"); - case BTM_PM_MD_SNIFF: - return s + std::string("sniff"); - case BTM_PM_MD_PARK: - return s + std::string("park"); - default: - return s + std::string("UNKNOWN"); - } -} - -#define BTM_PM_SET_ONLY_ID 0x80 - -/* Operation codes */ -typedef enum : uint8_t { - /* The module wants to set the desired power mode */ - BTM_PM_REG_SET = (1u << 0), - /* The module does not want to involve with PM anymore */ - BTM_PM_DEREG = (1u << 2), -} tBTM_PM_REGISTER; /************************ * Power Manager Types ************************/ -typedef struct { - uint16_t max = 0; - uint16_t min = 0; - uint16_t attempt = 0; - uint16_t timeout = 0; - tBTM_PM_MODE mode = BTM_PM_MD_ACTIVE; // 0 -} tBTM_PM_PWR_MD; /************************************* * Power Manager Callback Functions *************************************/ -typedef void(tBTM_PM_STATUS_CBACK)(const RawAddress& p_bda, - tBTM_PM_STATUS status, uint16_t value, - tHCI_STATUS hci_status); - -/************************ - * Stored Linkkey Types - ************************/ -#define BTM_CB_EVT_DELETE_STORED_LINK_KEYS 4 - -typedef struct { - uint8_t event; - uint8_t status; - uint16_t num_keys; - -} tBTM_DELETE_STORED_LINK_KEY_COMPLETE; - -#define BTM_CONTRL_UNKNOWN 0 -/* ACL link on, SCO link ongoing, sniff mode */ -#define BTM_CONTRL_ACTIVE 1 -/* Scan state - paging/inquiry/trying to connect*/ -#define BTM_CONTRL_SCAN 2 -/* Idle state - page scan, LE advt, inquiry scan */ -#define BTM_CONTRL_IDLE 3 - -typedef uint8_t tBTM_CONTRL_STATE; // Bluetooth Quality Report - Report receiver typedef void(tBTM_BT_QUALITY_REPORT_RECEIVER)(uint8_t len, const uint8_t* p_stream); - -struct tREMOTE_VERSION_INFO { - uint8_t lmp_version{0}; - uint16_t lmp_subversion{0}; - uint16_t manufacturer{0}; - bool valid{false}; - std::string ToString() const { - return (valid) ? base::StringPrintf("%02hhu-%05hu-%05hu", lmp_version, - lmp_subversion, manufacturer) - : std::string("UNKNOWN"); - } -}; -using remote_version_info = tREMOTE_VERSION_INFO; - #endif // BTM_API_TYPES_H diff --git a/system/stack/include/btm_ble_addr.h b/system/stack/include/btm_ble_addr.h new file mode 100644 index 0000000000000000000000000000000000000000..ddb9675079c19e12d1e2dae4eeb492f5de19199c --- /dev/null +++ b/system/stack/include/btm_ble_addr.h @@ -0,0 +1,56 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include "stack/btm/security_device_record.h" +#include "types/ble_address_with_type.h" +#include "types/raw_address.h" + +/******************************************************************************* + * + * Function btm_ble_init_pseudo_addr + * + * Description This function is used to initialize pseudo address. + * If pseudo address is not available, use dummy address + * + * Returns true is updated; false otherwise. + * + ******************************************************************************/ +bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, + const RawAddress& new_pseudo_addr); + +/******************************************************************************* + * + * Function btm_identity_addr_to_random_pseudo + * + * Description This function map a static BD address to a pseudo random + * address in security database. + * + ******************************************************************************/ +bool btm_identity_addr_to_random_pseudo(RawAddress* bd_addr, + tBLE_ADDR_TYPE* p_addr_type, + bool refresh); + +bool btm_identity_addr_to_random_pseudo_from_address_with_type( + tBLE_BD_ADDR* address_with_type, bool refresh); + +bool maybe_resolve_address(RawAddress* bda, tBLE_ADDR_TYPE* bda_type); + +/* BLE address mapping with CS feature */ +bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo, + tBLE_ADDR_TYPE* p_identity_addr_type); diff --git a/system/stack/include/btm_ble_api.h b/system/stack/include/btm_ble_api.h index d204dc2582b17ac8ae51a36a19810fdd3c2129b4..2260a2257f224261a9e60eed1d005e5a50f01607 100644 --- a/system/stack/include/btm_ble_api.h +++ b/system/stack/include/btm_ble_api.h @@ -33,7 +33,6 @@ #include "btm_api.h" #include "btm_ble_api_types.h" -#include "osi/include/alarm.h" #include "stack/btm/neighbor_inquiry.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -44,45 +43,6 @@ void btm_ble_free(); /***************************************************************************** * EXTERNAL FUNCTION DECLARATIONS ****************************************************************************/ -/******************************************************************************* - * - * Function BTM_SecAddBleDevice - * - * Description Add/modify device. This function will be normally called - * during host startup to restore all required information - * for a LE device stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * dev_type - Remote device's device type. - * addr_type - LE device address type. - * - ******************************************************************************/ -void BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, - tBLE_ADDR_TYPE addr_type); - -/******************************************************************************* - * - * Function BTM_SecAddBleKey - * - * Description Add/modify LE device information. This function will be - * normally called during host startup to restore all required - * information stored in the NVRAM. - * - * Parameters: bd_addr - BD address of the peer - * p_le_key - LE key values. - * key_type - LE SMP key type. -* - ******************************************************************************/ -void BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type); - -/** - * This function is called to set scan parameters. |cb| is called with operation - * status - **/ -void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window, - tBLE_SCAN_MODE scan_type, - base::Callback cb); /******************************************************************************* * @@ -213,131 +173,6 @@ void BTM_BleOpportunisticObserve(bool enable, void BTM_BleTargetAnnouncementObserve(bool enable, tBTM_INQ_RESULTS_CB* p_results_cb); -/** Returns local device encryption root (ER) */ -const Octet16& BTM_GetDeviceEncRoot(); - -/** Returns local device identity root (IR) */ -const Octet16& BTM_GetDeviceIDRoot(); - -/** Return local device DHK. */ -const Octet16& BTM_GetDeviceDHK(); - -/******************************************************************************* - * - * Function BTM_SecurityGrant - * - * Description This function is called to grant security process. - * - * Parameters bd_addr - peer device bd address. - * res - result of the operation BTM_SUCCESS if success. - * Otherwise, BTM_REPEATED_ATTEMPTS is too many - * attempts. - * - * Returns None - * - ******************************************************************************/ -void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res); - -/******************************************************************************* - * - * Function BTM_BlePasskeyReply - * - * Description This function is called after Security Manager submitted - * passkey request to the application. - * - * Parameters: bd_addr - Address of the device for which passkey was - * requested - * res - result of the operation SMP_SUCCESS if success - * passkey - numeric value in the range of - * BTM_MIN_PASSKEY_VAL(0) - - * BTM_MAX_PASSKEY_VAL(999999(0xF423F)). - * - ******************************************************************************/ -void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res, - uint32_t passkey); - -/******************************************************************************* - * - * Function BTM_BleConfirmReply - * - * Description This function is called after Security Manager submitted - * numeric comparison request to the application. - * - * Parameters: bd_addr - Address of the device with which numeric - * comparison was requested - * res - comparison result BTM_SUCCESS if success - * - ******************************************************************************/ -void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res); - -/******************************************************************************* - * - * Function BTM_LeOobDataReply - * - * Description This function is called to provide the OOB data for - * SMP in response to BTM_LE_OOB_REQ_EVT - * - * Parameters: bd_addr - Address of the peer device - * res - result of the operation SMP_SUCCESS if success - * p_data - simple pairing Randomizer C. - * - ******************************************************************************/ -void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len, - uint8_t* p_data); - -/******************************************************************************* - * - * Function BTM_BleSecureConnectionOobDataReply - * - * Description This function is called to provide the OOB data for - * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection - * data is available - * - * Parameters: bd_addr - Address of the peer device - * p_c - pointer to Confirmation - * p_r - pointer to Randomizer. - * - ******************************************************************************/ -void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr, - uint8_t* p_c, uint8_t* p_r); - -/******************************************************************************* - * - * Function BTM_BleDataSignature - * - * Description This function is called to sign the data using AES128 CMAC - * algorith. - * - * Parameter bd_addr: target device the data to be signed for. - * p_text: singing data - * len: length of the signing data - * signature: output parameter where data signature is going to - * be stored. - * - * Returns true if signing sucessul, otherwise false. - * - ******************************************************************************/ -bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text, - uint16_t len, BLE_SIGNATURE signature); - -/******************************************************************************* - * - * Function BTM_BleVerifySignature - * - * Description This function is called to verify the data signature - * - * Parameter bd_addr: target device the data to be signed for. - * p_orig: original data before signature. - * len: length of the signing data - * counter: counter used when doing data signing - * p_comp: signature to be compared against. - - * Returns true if signature verified correctly; otherwise false. - * - ******************************************************************************/ -bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig, - uint16_t len, uint32_t counter, uint8_t* p_comp); - /******************************************************************************* * * Function BTM_IsBleConnection @@ -361,23 +196,9 @@ bool BTM_IsBleConnection(uint16_t conn_handle); ******************************************************************************/ bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type); + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address); -/******************************************************************************* - * - * Function BTM_BleLoadLocalKeys - * - * Description Local local identity key, encryption root or sign counter. - * - * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, - * BTM_BLE_KEY_TYPE_ER - * or BTM_BLE_KEY_TYPE_COUNTER. - * p_key: pointer to the key. -* - * Returns non2. - * - ******************************************************************************/ -void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key); #include "stack/btm/btm_ble_bgconn.h" @@ -489,40 +310,55 @@ bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda, /******************************************************************************* * - * Function BTM_BleConfigPrivacy + * Function BTM_BleMaxMultiAdvInstanceCount * - * Description This function is called to enable or disable the privacy in - * the local device. + * Description Returns the maximum number of multi adv instances supported + * by the controller. * - * Parameters enable: true to enable it; false to disable it. + * Returns Max multi adv instance count * - * Returns bool privacy mode set success; otherwise failed. + ******************************************************************************/ +uint8_t BTM_BleMaxMultiAdvInstanceCount(); + +/******************************************************************************* + * + * Function BTM_BleReceiverTest + * + * Description This function is called to start the LE Receiver test + * + * Parameter rx_freq - Frequency Range + * p_cmd_cmpl_cback - Command Complete callback * ******************************************************************************/ -bool BTM_BleConfigPrivacy(bool enable); +void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback); /******************************************************************************* * - * Function BTM_BleLocalPrivacyEnabled + * Function BTM_BleTransmitterTest * - * Description Checks if local device supports private address + * Description This function is called to start the LE Transmitter test * - * Returns Return true if local privacy is enabled else false + * Parameter tx_freq - Frequency Range + * test_data_len - Length in bytes of payload data in each + * packet + * packet_payload - Pattern to use in the payload + * p_cmd_cmpl_cback - Command Complete callback * ******************************************************************************/ -bool BTM_BleLocalPrivacyEnabled(void); +void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len, + uint8_t packet_payload, + tBTM_CMPL_CB* p_cmd_cmpl_cback); /******************************************************************************* * - * Function BTM_BleMaxMultiAdvInstanceCount + * Function BTM_BleTestEnd * - * Description Returns the maximum number of multi adv instances supported - * by the controller. + * Description This function is called to stop the in-progress TX or RX test * - * Returns Max multi adv instance count + * Parameter p_cmd_cmpl_cback - Command complete callback * ******************************************************************************/ -uint8_t BTM_BleMaxMultiAdvInstanceCount(); +void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback); /******************************************************************************* * @@ -548,26 +384,6 @@ void BTM_BleAdvFilterParamSetup( std::unique_ptr p_filt_params, tBTM_BLE_PF_PARAM_CB cb); -/** - * This functions are called to configure the adv data payload filter condition - */ -void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector commands, tBTM_BLE_PF_CFG_CBACK cb); -void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_CFG_CBACK cb); - -/******************************************************************************* - * - * Function BTM_BleEnableDisableFilterFeature - * - * Description Enable or disable the APCF feature - * - * Parameters enable - true - enables APCF, false - disables APCF - * - ******************************************************************************/ -void BTM_BleEnableDisableFilterFeature(uint8_t enable, - tBTM_BLE_PF_STATUS_CBACK p_stat_cback); - /******************************************************************************* * * Function BTM_BleGetEnergyInfo @@ -620,8 +436,6 @@ void BTM_BleReadPhy( void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys, uint16_t phy_options); -void btm_ble_multi_adv_cleanup(void); - /******************************************************************************* * * Function btm_ble_get_acl_remote_addr @@ -657,8 +471,9 @@ void btm_ble_periodic_adv_report(uint16_t sync_handle, uint8_t tx_power, const uint8_t* periodic_data); void btm_ble_periodic_adv_sync_lost(uint16_t sync_handle); -void btm_ble_biginfo_adv_report_rcvd(uint8_t* param, uint16_t param_len); -void btm_ble_periodic_adv_sync_tx_rcvd(uint8_t* param, uint16_t param_len); +void btm_ble_biginfo_adv_report_rcvd(const uint8_t* param, uint16_t param_len); +void btm_ble_periodic_adv_sync_tx_rcvd(const uint8_t* param, + uint16_t param_len); /******************************************************************************* * * Function BTM_BleStartPeriodicSync @@ -759,4 +574,29 @@ void BTM_BlePeriodicSyncTxParameters(RawAddress addr, uint8_t mode, uint16_t skip, uint16_t timeout, StartSyncCb syncCb); +/******************************************************************************* + * + * Function BTM_BleConfigPrivacy + * + * Description This function is called to enable or disable the privacy in + * the local device. + * + * Parameters enable: true to enable it; false to disable it. + * + * Returns bool privacy mode set success; otherwise failed. + * + ******************************************************************************/ +bool BTM_BleConfigPrivacy(bool enable); + +/******************************************************************************* + * + * Function BTM_BleLocalPrivacyEnabled + * + * Description Checks if local device supports private address + * + * Returns Return true if local privacy is enabled else false + * + ******************************************************************************/ +bool BTM_BleLocalPrivacyEnabled(void); + #endif diff --git a/system/stack/include/btm_ble_api_types.h b/system/stack/include/btm_ble_api_types.h index 483dc918912e955367f129dc326c9b60ea44e4bd..07f5bd9963026598d2362c0d23ae95af65667db6 100644 --- a/system/stack/include/btm_ble_api_types.h +++ b/system/stack/include/btm_ble_api_types.h @@ -26,7 +26,6 @@ #include #include "stack/include/bt_octets.h" -#include "stack/include/btm_api_types.h" #include "stack/include/btm_status.h" #include "stack/include/hci_error_code.h" #include "types/ble_address_with_type.h" @@ -514,97 +513,4 @@ typedef struct { typedef void(tBTM_BLE_CTRL_FEATURES_CBACK)(tHCI_STATUS status); -/* BLE encryption keys */ -typedef struct { - Octet16 ltk; - BT_OCTET8 rand; - uint16_t ediv; - uint8_t sec_level; - uint8_t key_size; -} tBTM_LE_PENC_KEYS; - -/* BLE CSRK keys */ -typedef struct { - uint32_t counter; - Octet16 csrk; - uint8_t sec_level; -} tBTM_LE_PCSRK_KEYS; - -/* BLE Encryption reproduction keys */ -typedef struct { - Octet16 ltk; - uint16_t div; - uint8_t key_size; - uint8_t sec_level; -} tBTM_LE_LENC_KEYS; - -/* BLE SRK keys */ -typedef struct { - uint32_t counter; - uint16_t div; - uint8_t sec_level; - Octet16 csrk; -} tBTM_LE_LCSRK_KEYS; - -typedef struct { - Octet16 irk; - tBLE_ADDR_TYPE identity_addr_type; - RawAddress identity_addr; -} tBTM_LE_PID_KEYS; - -typedef union { - tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */ - tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */ - tBTM_LE_PID_KEYS pid_key; /* peer device ID key */ - tBTM_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys - * LTK = = d1(ER,DIV,0) */ - tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ -} tBTM_LE_KEY_VALUE; - -typedef struct { - tBTM_LE_KEY_TYPE key_type; - tBTM_LE_KEY_VALUE* p_key_value; -} tBTM_LE_KEY; - -typedef union { - tBTM_LE_IO_REQ io_req; /* BTM_LE_IO_REQ_EVT */ - uint32_t key_notif; /* BTM_LE_KEY_NOTIF_EVT */ - /* BTM_LE_NC_REQ_EVT */ - /* no callback data for - * BTM_LE_KEY_REQ_EVT - * and BTM_LE_OOB_REQ_EVT */ - tBTM_LE_COMPLT complt; /* BTM_LE_COMPLT_EVT */ - tSMP_OOB_DATA_TYPE req_oob_type; - tBTM_LE_KEY key; - tSMP_LOC_OOB_DATA local_oob_data; - RawAddress id_addr; -} tBTM_LE_EVT_DATA; - -/* Simple Pairing Events. Called by the stack when Simple Pairing related - * events occur. - */ -typedef uint8_t(tBTM_LE_CALLBACK)(tBTM_LE_EVT event, const RawAddress& bda, - tBTM_LE_EVT_DATA* p_data); - -#define BTM_BLE_KEY_TYPE_ID 1 -#define BTM_BLE_KEY_TYPE_ER 2 -#define BTM_BLE_KEY_TYPE_COUNTER 3 // tobe obsolete - -typedef struct { - Octet16 ir; - Octet16 irk; - Octet16 dhk; - -} tBTM_BLE_LOCAL_ID_KEYS; - -typedef union { - tBTM_BLE_LOCAL_ID_KEYS id_keys; - Octet16 er; -} tBTM_BLE_LOCAL_KEYS; - -/* New LE identity key for local device. - */ -typedef void(tBTM_LE_KEY_CALLBACK)(uint8_t key_type, - tBTM_BLE_LOCAL_KEYS* p_key); - #endif // BTM_BLE_API_TYPES_H diff --git a/system/stack/include/btm_ble_privacy.h b/system/stack/include/btm_ble_privacy.h new file mode 100644 index 0000000000000000000000000000000000000000..7fccf097235835fbc7ee86dd0534df899f1d94c4 --- /dev/null +++ b/system/stack/include/btm_ble_privacy.h @@ -0,0 +1,36 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include "stack/btm/security_device_record.h" +#include "types/raw_address.h" + +void btm_ble_resolving_list_init(uint8_t max_irk_list_sz); + +void btm_ble_refresh_peer_resolvable_private_addr(const RawAddress& pseudo_bda, + const RawAddress& rra, + tBLE_RAND_ADDR_TYPE type); +bool btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec); + +bool btm_ble_addr_resolvable(const RawAddress& rpa, + tBTM_SEC_DEV_REC* p_dev_rec); + +void btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC& p_dev_rec); +void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec); + +uint64_t btm_get_next_private_addrress_interval_ms(); diff --git a/system/stack/include/btm_ble_sec_api.h b/system/stack/include/btm_ble_sec_api.h new file mode 100644 index 0000000000000000000000000000000000000000..f3481a0d14a60f7760a751ac5a663e68725983f4 --- /dev/null +++ b/system/stack/include/btm_ble_sec_api.h @@ -0,0 +1,268 @@ +/* + * + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include +#include + +#include +#include + +#include "btm_ble_api_types.h" +#include "btm_ble_sec_api_types.h" +#include "stack/include/bt_device_type.h" +#include "types/raw_address.h" + +/******************************************************************************* + * + * Function BTM_SecAddBleDevice + * + * Description Add/modify device. This function will be normally called + * during host startup to restore all required information + * for a LE device stored in the NVRAM. + * + * Parameters: bd_addr - BD address of the peer + * dev_type - Remote device's device type. + * addr_type - LE device address type. + * + ******************************************************************************/ +void BTM_SecAddBleDevice(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, + tBLE_ADDR_TYPE addr_type); + +/******************************************************************************* + * + * Function BTM_SecAddBleKey + * + * Description Add/modify LE device information. This function will be + * normally called during host startup to restore all required + * information stored in the NVRAM. + * + * Parameters: bd_addr - BD address of the peer + * p_le_key - LE key values. + * key_type - LE SMP key type. +* + ******************************************************************************/ +void BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key, + tBTM_LE_KEY_TYPE key_type); + +/** Returns local device encryption root (ER) */ +const Octet16& BTM_GetDeviceEncRoot(); + +/** Returns local device identity root (IR) */ +const Octet16& BTM_GetDeviceIDRoot(); + +/** Return local device DHK. */ +const Octet16& BTM_GetDeviceDHK(); + +/******************************************************************************* + * + * Function BTM_SecurityGrant + * + * Description This function is called to grant security process. + * + * Parameters bd_addr - peer device bd address. + * res - result of the operation BTM_SUCCESS if success. + * Otherwise, BTM_REPEATED_ATTEMPTS is too many + * attempts. + * + * Returns None + * + ******************************************************************************/ +void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res); + +/******************************************************************************* + * + * Function BTM_BlePasskeyReply + * + * Description This function is called after Security Manager submitted + * passkey request to the application. + * + * Parameters: bd_addr - Address of the device for which passkey was + * requested + * res - result of the operation SMP_SUCCESS if success + * passkey - numeric value in the range of + * BTM_MIN_PASSKEY_VAL(0) - + * BTM_MAX_PASSKEY_VAL(999999(0xF423F)). + * + ******************************************************************************/ +void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res, + uint32_t passkey); + +/******************************************************************************* + * + * Function BTM_BleConfirmReply + * + * Description This function is called after Security Manager submitted + * numeric comparison request to the application. + * + * Parameters: bd_addr - Address of the device with which numeric + * comparison was requested + * res - comparison result BTM_SUCCESS if success + * + ******************************************************************************/ +void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res); + +/******************************************************************************* + * + * Function BTM_LeOobDataReply + * + * Description This function is called to provide the OOB data for + * SMP in response to BTM_LE_OOB_REQ_EVT + * + * Parameters: bd_addr - Address of the peer device + * res - result of the operation SMP_SUCCESS if success + * p_data - simple pairing Randomizer C. + * + ******************************************************************************/ +void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len, + uint8_t* p_data); + +/******************************************************************************* + * + * Function BTM_BleSecureConnectionOobDataReply + * + * Description This function is called to provide the OOB data for + * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection + * data is available + * + * Parameters: bd_addr - Address of the peer device + * p_c - pointer to Confirmation + * p_r - pointer to Randomizer. + * + ******************************************************************************/ +void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr, + uint8_t* p_c, uint8_t* p_r); + +/******************************************************************************* + * + * Function BTM_BleDataSignature + * + * Description This function is called to sign the data using AES128 CMAC + * algorithm. + * + * Parameter bd_addr: target device the data to be signed for. + * p_text: singing data + * len: length of the signing data + * signature: output parameter where data signature is going to + * be stored. + * + * Returns true if signing sucessul, otherwise false. + * + ******************************************************************************/ +bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text, + uint16_t len, BLE_SIGNATURE signature); + +/******************************************************************************* + * + * Function BTM_BleVerifySignature + * + * Description This function is called to verify the data signature + * + * Parameter bd_addr: target device the data to be signed for. + * p_orig: original data before signature. + * len: length of the signing data + * counter: counter used when doing data signing + * p_comp: signature to be compared against. + + * Returns true if signature verified correctly; otherwise false. + * + ******************************************************************************/ +bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig, + uint16_t len, uint32_t counter, uint8_t* p_comp); + + + +/******************************************************************************* + * + * Function BTM_BleLoadLocalKeys + * + * Description Local local identity key, encryption root or sign counter. + * + * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, + * BTM_BLE_KEY_TYPE_ER + * or BTM_BLE_KEY_TYPE_COUNTER. + * p_key: pointer to the key. +* + * Returns non2. + * + ******************************************************************************/ +void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key); + +/******************************************************************************* + * + * Function BTM_BleGetPeerLTK + * + * Description This function is used to get the long term key of + * a bonded peer (LE) device. + * + * Parameters: address: address of the peer device + * + * Returns the ltk contained in std::optional if the remote device + * is present in security database + * std::nullopt if the device is not present + * + ******************************************************************************/ +std::optional BTM_BleGetPeerLTK(const RawAddress address); + +/******************************************************************************* + * + * Function BTM_BleGetPeerIRK + * + * Description This function is used to get the IRK of a bonded + * peer (LE) device. + * + * Parameters: address: address of the peer device + * + * Returns the ltk contained in std::optional if the remote device + * is present in security database + * std::nullopt if the device is not present + * + ******************************************************************************/ +std::optional BTM_BleGetPeerIRK(const RawAddress address); + +/******************************************************************************* + * + * Function BTM_BleIsLinkKeyKnown + * + * Description This function is used to check whether the link key + * of a peer (LE) device is known or not + * + * Parameters: address: address of the peer device + * + * Returns true if the link key is known + * false otherwise + * + ******************************************************************************/ +bool BTM_BleIsLinkKeyKnown(const RawAddress address); + +/******************************************************************************* + * + * Function BTM_BleGetIdentityAddress + * + * Description This function is called to get the identity address + * (with type) of a peer (LE) device. + * + * Parameters: address: address of the peer device + * + * Returns the identity address in std::optional if the remote device + * is present in security database + * std::nullopt if the device is not present + * + ******************************************************************************/ +std::optional BTM_BleGetIdentityAddress(const RawAddress address); diff --git a/system/stack/include/btm_ble_sec_api_types.h b/system/stack/include/btm_ble_sec_api_types.h new file mode 100644 index 0000000000000000000000000000000000000000..dd1f919b11c2ca79eca4cad4e0e0014868f78a16 --- /dev/null +++ b/system/stack/include/btm_ble_sec_api_types.h @@ -0,0 +1,120 @@ +/* + * + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include +#include "stack/include/bt_octets.h" +#include "stack/include/btm_sec_api_types.h" + +////////////////////////////////////////////////////////// +////// from btm_ble_api_types.h +///////////////////////////////////////////////////////// +/* BLE encryption keys */ +typedef struct { + Octet16 ltk; + BT_OCTET8 rand; + uint16_t ediv; + uint8_t sec_level; + uint8_t key_size; +} tBTM_LE_PENC_KEYS; + +/* BLE CSRK keys */ +typedef struct { + uint32_t counter; + Octet16 csrk; + uint8_t sec_level; +} tBTM_LE_PCSRK_KEYS; + +/* BLE Encryption reproduction keys */ +typedef struct { + Octet16 ltk; + uint16_t div; + uint8_t key_size; + uint8_t sec_level; +} tBTM_LE_LENC_KEYS; + +/* BLE SRK keys */ +typedef struct { + uint32_t counter; + uint16_t div; + uint8_t sec_level; + Octet16 csrk; +} tBTM_LE_LCSRK_KEYS; + +typedef struct { + Octet16 irk; + tBLE_ADDR_TYPE identity_addr_type; + RawAddress identity_addr; +} tBTM_LE_PID_KEYS; + +typedef union { + tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */ + tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */ + tBTM_LE_PID_KEYS pid_key; /* peer device ID key */ + tBTM_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys + * LTK = = d1(ER,DIV,0) */ + tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ +} tBTM_LE_KEY_VALUE; + +typedef struct { + tBTM_LE_KEY_TYPE key_type; + tBTM_LE_KEY_VALUE* p_key_value; +} tBTM_LE_KEY; + +typedef union { + tBTM_LE_IO_REQ io_req; /* BTM_LE_IO_REQ_EVT */ + uint32_t key_notif; /* BTM_LE_KEY_NOTIF_EVT */ + /* BTM_LE_NC_REQ_EVT */ + /* no callback data for + * BTM_LE_KEY_REQ_EVT + * and BTM_LE_OOB_REQ_EVT */ + tBTM_LE_COMPLT complt; /* BTM_LE_COMPLT_EVT */ + tSMP_OOB_DATA_TYPE req_oob_type; + tBTM_LE_KEY key; + tSMP_LOC_OOB_DATA local_oob_data; + RawAddress id_addr; +} tBTM_LE_EVT_DATA; + +/* Simple Pairing Events. Called by the stack when Simple Pairing related + * events occur. + */ +typedef uint8_t(tBTM_LE_CALLBACK)(tBTM_LE_EVT event, const RawAddress& bda, + tBTM_LE_EVT_DATA* p_data); + +#define BTM_BLE_KEY_TYPE_ID 1 +#define BTM_BLE_KEY_TYPE_ER 2 +#define BTM_BLE_KEY_TYPE_COUNTER 3 // tobe obsolete + +typedef struct { + Octet16 ir; + Octet16 irk; + Octet16 dhk; + +} tBTM_BLE_LOCAL_ID_KEYS; + +typedef union { + tBTM_BLE_LOCAL_ID_KEYS id_keys; + Octet16 er; +} tBTM_BLE_LOCAL_KEYS; + +/* New LE identity key for local device. + */ +typedef void(tBTM_LE_KEY_CALLBACK)(uint8_t key_type, + tBTM_BLE_LOCAL_KEYS* p_key); + diff --git a/system/stack/include/btm_client_interface.h b/system/stack/include/btm_client_interface.h index 24669beef29b7a48744b84fbe8171c9ac04645bc..da6dc02d1d4a662576422f18366196ada3f8a8ae 100644 --- a/system/stack/include/btm_client_interface.h +++ b/system/stack/include/btm_client_interface.h @@ -20,15 +20,14 @@ #include "device/include/esco_parameters.h" #include "stack/btm/neighbor_inquiry.h" +#include "stack/btm/power_mode.h" #include "stack/include/acl_client_callbacks.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_octets.h" #include "stack/include/btm_api_types.h" #include "stack/include/btm_ble_api_types.h" #include "stack/include/btm_status.h" -#include "stack/include/hci_error_code.h" #include "stack/include/security_client_callbacks.h" -#include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -50,28 +49,6 @@ struct btm_client_interface_t { void (*BTM_reset_complete)(); } lifecycle; - struct { - // Server channel number - uint8_t (*BTM_AllocateSCN)(void); - bool (*BTM_TryAllocateSCN)(uint8_t scn); - bool (*BTM_FreeSCN)(uint8_t scn); - } scn; - - // Neighbor - struct { - void (*BTM_CancelInquiry)(); - tBTM_INQ_INFO* (*BTM_InqDbNext)(tBTM_INQ_INFO* p_cur); - tBTM_STATUS (*BTM_ClearInqDb)(const RawAddress* p_bda); - tBTM_STATUS (*BTM_SetDiscoverability)(uint16_t inq_mode); - tBTM_STATUS (*BTM_SetConnectability)(uint16_t page_mode); - tBTM_STATUS (*BTM_StartInquiry)(tBTM_INQ_RESULTS_CB* p_results_cb, - tBTM_CMPL_CB* p_cmpl_cb); - uint16_t (*BTM_IsInquiryActive)(void); - tBTM_STATUS (*BTM_SetInquiryMode)(uint8_t mode); - void (*BTM_EnableInterlacedInquiryScan)(); - void (*BTM_EnableInterlacedPageScan)(); - } neighbor; - // Acl peer and lifecycle struct { struct { @@ -118,50 +95,7 @@ struct btm_client_interface_t { tBTM_STATUS (*BTM_ReadRSSI)(const RawAddress& bd_addr, tBTM_CMPL_CB* p_cb); } link_controller; - struct { - bool (*BTM_SecAddDevice)(const RawAddress& bd_addr, DEV_CLASS dev_class, - const BD_NAME& bd_name, uint8_t* features, - LinkKey* link_key, uint8_t key_type, - uint8_t pin_length); - bool (*BTM_SecAddRmtNameNotifyCallback)(tBTM_RMT_NAME_CALLBACK* p_callback); - bool (*BTM_SecDeleteDevice)(const RawAddress& bd_addr); - bool (*BTM_SecDeleteRmtNameNotifyCallbac)( - tBTM_RMT_NAME_CALLBACK* p_callback); - bool (*BTM_SecRegister)(const tBTM_APPL_INFO* p_cb_info); - char* (*BTM_SecReadDevName)(const RawAddress& bd_addr); - tBTM_STATUS (*BTM_SecBond)(const RawAddress& bd_addr, - tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, - tBT_DEVICE_TYPE device_type, uint8_t pin_len, - uint8_t* p_pin); - tBTM_STATUS (*BTM_SecBondCancel)(const RawAddress& bd_addr); - void (*BTM_SecAddBleKey)(const RawAddress& bd_addr, - tBTM_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type); - void (*BTM_SecAddBleDevice)(const RawAddress& bd_addr, - tBT_DEVICE_TYPE dev_type, - tBLE_ADDR_TYPE addr_type); - void (*BTM_SecClearSecurityFlags)(const RawAddress& bd_addr); - uint8_t (*BTM_SecClrService)(uint8_t service_id); - uint8_t (*BTM_SecClrServiceByPsm)(uint16_t psm); - void (*BTM_RemoteOobDataReply)(tBTM_STATUS res, const RawAddress& bd_addr, - const Octet16& c, const Octet16& r); - void (*BTM_PINCodeReply)(const RawAddress& bd_addr, tBTM_STATUS res, - uint8_t pin_len, uint8_t* p_pin); - void (*BTM_ConfirmReqReply)(tBTM_STATUS res, const RawAddress& bd_addr); - bool (*BTM_SecDeleteRmtNameNotifyCallback)( - tBTM_RMT_NAME_CALLBACK* p_callback); - tBTM_STATUS (*BTM_SetEncryption)(const RawAddress& bd_addr, - tBT_TRANSPORT transport, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data, - tBTM_BLE_SEC_ACT sec_act); - bool (*BTM_IsEncrypted)(const RawAddress& bd_addr, tBT_TRANSPORT transport); - bool (*BTM_SecIsSecurityPending)(const RawAddress& bd_addr); - bool (*BTM_IsLinkKeyKnown)(const RawAddress& bd_addr, - tBT_TRANSPORT transport); - } security; - + SecurityClientInterface security; struct { tBTM_STATUS (*BTM_BleGetEnergyInfo)(tBTM_BLE_ENERGY_INFO_CBACK* callback); tBTM_STATUS (*BTM_BleObserve)(bool start, uint8_t duration, diff --git a/system/stack/include/btm_iso_api_types.h b/system/stack/include/btm_iso_api_types.h index 63ca700a8d9dcda67387cf5a939a3d7d4db12175..16cb1ca6faa2843ec505403b4bb141ed680f4413 100644 --- a/system/stack/include/btm_iso_api_types.h +++ b/system/stack/include/btm_iso_api_types.h @@ -21,7 +21,6 @@ #include "hcimsgs.h" #include "stack/include/bt_hdr.h" -#include "stack/include/bt_octets.h" namespace bluetooth { namespace hci { diff --git a/system/stack/include/btm_sec_api.h b/system/stack/include/btm_sec_api.h new file mode 100644 index 0000000000000000000000000000000000000000..3997733bab31498dc47f7bb3b8871f22ab8f42bc --- /dev/null +++ b/system/stack/include/btm_sec_api.h @@ -0,0 +1,130 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include + +#include "stack/include/bt_dev_class.h" +#include "stack/include/bt_name.h" +#include "stack/include/bt_octets.h" +#include "stack/include/btm_api_types.h" +#include "stack/include/btm_status.h" +#include "types/bt_transport.h" +#include "types/raw_address.h" + +/***************************************************************************** + * SECURITY MANAGEMENT FUNCTIONS + ****************************************************************************/ + +/******************************************************************************* + * + * Function BTM_SecAddDevice + * + * Description Add/modify device. This function will be normally called + * during host startup to restore all required information + * stored in the NVRAM. + * dev_class, bd_name, link_key, and features are NULL if + * unknown + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, + const BD_NAME& bd_name, uint8_t* features, + LinkKey* link_key, uint8_t key_type, uint8_t pin_length); + +/** Free resources associated with the device associated with |bd_addr| address. + * + * *** WARNING *** + * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function + * is called, also any of its fields. i.e. if you use p_dev_rec->bd_addr, it is + * no longer valid! + * *** WARNING *** + * + * Returns true if removed OK, false if not found or ACL link is active. + */ +bool BTM_SecDeleteDevice(const RawAddress& bd_addr); + +/******************************************************************************* + * + * Function BTM_SecClearSecurityFlags + * + * Description Reset the security flags (mark as not-paired) for a given + * remove device. + * + ******************************************************************************/ +void BTM_SecClearSecurityFlags(const RawAddress& bd_addr); + +/******************************************************************************* + * + * Function btm_sec_is_a_bonded_dev + * + * Description Is the specified device is a bonded device + * + * Returns true - dev is bonded + * + ******************************************************************************/ +bool btm_sec_is_a_bonded_dev(const RawAddress& bda); + +/******************************************************************************* + * + * Function BTM_DeleteStoredLinkKey + * + * Description This function is called to delete link key for the specified + * device addresses from the NVRAM storage attached to the + * Bluetooth controller. + * + * Parameters: bd_addr - Addresses of the devices + * p_cb - Call back function to be called to return + * the results + * + ******************************************************************************/ +tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* bd_addr, + tBTM_CMPL_CB* p_cb); + +/******************************************************************************* + * + * Function BTM_BleSirkConfirmDeviceReply + * + * Description This procedure confirms requested to validate set device. + * + * Parameter bd_addr - BD address of the peer + * res - confirmation result BTM_SUCCESS if success + * + * Returns void + * + ******************************************************************************/ +void BTM_BleSirkConfirmDeviceReply(const RawAddress& bd_addr, uint8_t res); + +uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr); + +/******************************************************************************* + * + * Function BTM_IsRemoteNameKnown + * + * Description This function checks if the remote name is known. + * + * Input Params: bd_addr: Address of remote + * transport: Transport, auto if unknown + * + * Returns + * true if name is known, false otherwise + * + ******************************************************************************/ +bool BTM_IsRemoteNameKnown(const RawAddress& remote_bda, + tBT_TRANSPORT transport); diff --git a/system/stack/include/btm_sec_api_types.h b/system/stack/include/btm_sec_api_types.h new file mode 100644 index 0000000000000000000000000000000000000000..21ea173c0116d113f61221215e3f0ab3c0833412 --- /dev/null +++ b/system/stack/include/btm_sec_api_types.h @@ -0,0 +1,483 @@ +/* + * + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include + +#include +#include + +#include "macros.h" +#include "stack/include/bt_dev_class.h" +#include "stack/include/bt_name.h" +#include "stack/include/bt_octets.h" +#include "stack/include/hcidefs.h" +#include "stack/include/smp_api_types.h" +#include "types/bt_transport.h" +#include "types/raw_address.h" + +typedef enum : uint8_t { + BTM_BLE_SEC_NONE = 0, + /* encrypt the link using current key */ + BTM_BLE_SEC_ENCRYPT = 1, + BTM_BLE_SEC_ENCRYPT_NO_MITM = 2, + BTM_BLE_SEC_ENCRYPT_MITM = 3, +} tBTM_BLE_SEC_ACT; + +/***************************************************************************** + * SECURITY MANAGEMENT + ****************************************************************************/ +/******************************* + * Security Manager Constants + *******************************/ + +typedef enum : uint8_t { + BTM_SEC_MODE_SERVICE = 2, + BTM_SEC_MODE_SP = 4, + BTM_SEC_MODE_SC = 6, +} tSECURITY_MODE; + +inline std::string security_mode_text(const tSECURITY_MODE& security_mode) { + switch (security_mode) { + case BTM_SEC_MODE_SERVICE: + return std::string("service"); + case BTM_SEC_MODE_SP: + return std::string("simple pairing"); + case BTM_SEC_MODE_SC: + return std::string("secure connections only"); + default: + return base::StringPrintf("UNKNOWN[%hhu]", security_mode); + } +} + +/* BTM_SEC security masks */ +enum : uint16_t { + /* Nothing required */ + BTM_SEC_NONE = 0x0000, + /* Inbound call requires authentication */ + BTM_SEC_IN_AUTHENTICATE = 0x0002, + /* Inbound call requires encryption */ + BTM_SEC_IN_ENCRYPT = 0x0004, + /* Outbound call requires authentication */ + BTM_SEC_OUT_AUTHENTICATE = 0x0010, + /* Outbound call requires encryption */ + BTM_SEC_OUT_ENCRYPT = 0x0020, + /* Secure Connections Only Mode */ + BTM_SEC_MODE4_LEVEL4 = 0x0040, + /* Need to switch connection to be central */ + BTM_SEC_FORCE_CENTRAL = 0x0100, + /* Need to switch connection to be central */ + BTM_SEC_ATTEMPT_CENTRAL = 0x0200, + /* Need to switch connection to be peripheral */ + BTM_SEC_FORCE_PERIPHERAL = 0x0400, + /* Try to switch connection to be peripheral */ + BTM_SEC_ATTEMPT_PERIPHERAL = 0x0800, + /* inbound Do man in the middle protection */ + BTM_SEC_IN_MITM = 0x1000, + /* outbound Do man in the middle protection */ + BTM_SEC_OUT_MITM = 0x2000, + /* enforce a minimum of 16 digit for sec mode 2 */ + BTM_SEC_IN_MIN_16_DIGIT_PIN = 0x4000, +}; + +/* Security Flags [bit mask] (BTM_GetSecurityFlags) +*/ +#define BTM_SEC_FLAG_AUTHENTICATED 0x02 +#define BTM_SEC_FLAG_ENCRYPTED 0x04 +#define BTM_SEC_FLAG_LKEY_KNOWN 0x10 +#define BTM_SEC_FLAG_LKEY_AUTHED 0x20 + +/* Link Key types used to generate the new link key. + * returned in link key notification callback function +*/ +#define BTM_LKEY_TYPE_COMBINATION HCI_LKEY_TYPE_COMBINATION +#define BTM_LKEY_TYPE_REMOTE_UNIT HCI_LKEY_TYPE_REMOTE_UNIT +#define BTM_LKEY_TYPE_DEBUG_COMB HCI_LKEY_TYPE_DEBUG_COMB +#define BTM_LKEY_TYPE_UNAUTH_COMB HCI_LKEY_TYPE_UNAUTH_COMB +#define BTM_LKEY_TYPE_AUTH_COMB HCI_LKEY_TYPE_AUTH_COMB +#define BTM_LKEY_TYPE_CHANGED_COMB HCI_LKEY_TYPE_CHANGED_COMB + +#define BTM_LKEY_TYPE_UNAUTH_COMB_P_256 HCI_LKEY_TYPE_UNAUTH_COMB_P_256 +#define BTM_LKEY_TYPE_AUTH_COMB_P_256 HCI_LKEY_TYPE_AUTH_COMB_P_256 + +inline std::string linkkey_type_text(const int linkkey_type) { + switch (linkkey_type) { + case BTM_LKEY_TYPE_COMBINATION: + return std::string("COMBINATION"); + case BTM_LKEY_TYPE_REMOTE_UNIT: + return std::string("REMOTE_UNIT"); + case BTM_LKEY_TYPE_DEBUG_COMB: + return std::string("DEBUG_COMB"); + case BTM_LKEY_TYPE_UNAUTH_COMB: + return std::string("UNAUTH_COMB"); + case BTM_LKEY_TYPE_AUTH_COMB: + return std::string("AUTH_COMB"); + case BTM_LKEY_TYPE_CHANGED_COMB: + return std::string("CHANGED_COMB"); + case BTM_LKEY_TYPE_UNAUTH_COMB_P_256: + return std::string("UNAUTH_COMB_P_256"); + case BTM_LKEY_TYPE_AUTH_COMB_P_256: + return std::string("AUTH_COMB_P_256"); + default: + return base::StringPrintf("UNKNOWN[0x%02x]", linkkey_type); + } +} + +/* "easy" requirements for LK derived from LTK */ +#define BTM_LTK_DERIVED_LKEY_OFFSET 0x20 +#define BTM_LKEY_TYPE_IGNORE \ + 0xff /* used when event is response from \ + hci return link keys request */ + +typedef uint8_t tBTM_LINK_KEY_TYPE; + +/* Protocol level security (BTM_SetSecurityLevel) */ +#define BTM_SEC_PROTO_RFCOMM 3 +#define BTM_SEC_PROTO_BNEP 5 +#define BTM_SEC_PROTO_HID 6 /* HID */ +#define BTM_SEC_PROTO_AVDT 7 + +#define BTM_SEC_SERVICE_HEADSET 8 +#define BTM_SEC_SERVICE_HEADSET_AG 12 +#define BTM_SEC_SERVICE_AG_HANDSFREE 29 +#define BTM_SEC_SERVICE_RFC_MUX 42 +#define BTM_SEC_SERVICE_HEARING_AID_LEFT 54 +#define BTM_SEC_SERVICE_HEARING_AID_RIGHT 55 +#define BTM_SEC_SERVICE_EATT 56 + +/* Update these as services are added */ +#define BTM_SEC_SERVICE_FIRST_EMPTY 57 + +#ifndef BTM_SEC_MAX_SERVICES +#define BTM_SEC_MAX_SERVICES 75 +#endif + +/******************************************************************************* + * Security Services MACROS handle array of uint32_t bits for more than 32 + * trusted services + ******************************************************************************/ + +enum { + BTM_SP_IO_REQ_EVT, /* received IO_CAPABILITY_REQUEST event */ + BTM_SP_IO_RSP_EVT, /* received IO_CAPABILITY_RESPONSE event */ + BTM_SP_CFM_REQ_EVT, /* received USER_CONFIRMATION_REQUEST event */ + BTM_SP_KEY_NOTIF_EVT, /* received USER_PASSKEY_NOTIFY event */ + BTM_SP_KEY_REQ_EVT, /* received USER_PASSKEY_REQUEST event */ + BTM_SP_LOC_OOB_EVT, /* received result for READ_LOCAL_OOB_DATA command */ + BTM_SP_RMT_OOB_EVT, /* received REMOTE_OOB_DATA_REQUEST event */ +}; +typedef uint8_t tBTM_SP_EVT; + +enum : uint8_t { + BTM_IO_CAP_OUT = 0, /* DisplayOnly */ + BTM_IO_CAP_IO = 1, /* DisplayYesNo */ + BTM_IO_CAP_IN = 2, /* KeyboardOnly */ + BTM_IO_CAP_NONE = 3, /* NoInputNoOutput */ + BTM_IO_CAP_KBDISP = 4, /* Keyboard display */ + BTM_IO_CAP_MAX = 5, + BTM_IO_CAP_UNKNOWN = 0xFF /* Unknown value */ +}; +typedef uint8_t tBTM_IO_CAP; + +inline std::string io_capabilities_text(const tBTM_IO_CAP& io_caps) { + switch (io_caps) { + case BTM_IO_CAP_OUT: + return std::string("Display only"); + case BTM_IO_CAP_IO: + return std::string("Display yes-no"); + case BTM_IO_CAP_IN: + return std::string("Keyboard Only"); + case BTM_IO_CAP_NONE: + return std::string("No input or output"); + case BTM_IO_CAP_KBDISP: + return std::string("Keyboard-Display"); + default: + return base::StringPrintf("UNKNOWN[%hhu]", io_caps); + } +} + +#define BTM_MAX_PASSKEY_VAL (999999) + +typedef enum : uint8_t { + /* MITM Protection Not Required - Single Profile/non-bonding Numeric + * comparison with automatic accept allowed */ + // NO_BONDING + BTM_AUTH_SP_NO = 0, + /* MITM Protection Required - Single Profile/non-bonding. Use IO Capabilities + * to determine authentication procedure */ + // NO_BONDING_MITM_PROTECTION + BTM_AUTH_SP_YES = 1, + /* MITM Protection Not Required - All Profiles/dedicated bonding Numeric + * comparison with automatic accept allowed */ + // DEDICATED_BONDING + BTM_AUTH_AP_NO = 2, + /* MITM Protection Required - All Profiles/dedicated bonding Use IO + * Capabilities to determine authentication procedure */ + // DEDICATED_BONDING_MITM_PROTECTION + BTM_AUTH_AP_YES = 3, + /* MITM Protection Not Required - Single Profiles/general bonding Numeric + * comparison with automatic accept allowed */ + // GENERAL_BONDING + BTM_AUTH_SPGB_NO = 4, + /* MITM Protection Required - Single Profiles/general bonding Use IO + * Capabilities to determine authentication procedure */ + // GENERAL_BONDING_MITM_PROTECTION + BTM_AUTH_SPGB_YES = 5, +} tBTM_AUTH; + +/* this bit is ORed with BTM_AUTH_SP_* when IO exchange for dedicated bonding */ +#define BTM_AUTH_DD_BOND 2 +#define BTM_AUTH_BONDS 6 /* the general/dedicated bonding bits */ +#define BTM_AUTH_YN_BIT 1 /* this is the Yes or No bit */ + +#define BTM_BLE_INITIATOR_KEY_SIZE 15 +#define BTM_BLE_RESPONDER_KEY_SIZE 15 +#define BTM_BLE_MAX_KEY_SIZE 16 + +typedef uint8_t tBTM_AUTH_REQ; + +enum { + BTM_OOB_NONE, + BTM_OOB_PRESENT_192, + BTM_OOB_PRESENT_256, + BTM_OOB_PRESENT_192_AND_256, + BTM_OOB_UNKNOWN +}; + +typedef uint8_t tBTM_OOB_DATA; + +inline std::string btm_oob_data_text(const tBTM_OOB_DATA& data) { + switch (data) { + CASE_RETURN_TEXT(BTM_OOB_NONE); + CASE_RETURN_TEXT(BTM_OOB_PRESENT_192); + CASE_RETURN_TEXT(BTM_OOB_PRESENT_256); + CASE_RETURN_TEXT(BTM_OOB_PRESENT_192_AND_256); + CASE_RETURN_TEXT(BTM_OOB_UNKNOWN); + default: + return std::string("UNKNOWN[") + std::to_string(data) + std::string("]"); + } +} + +/* data type for BTM_SP_IO_REQ_EVT */ +typedef struct { + RawAddress bd_addr; /* peer address */ + tBTM_IO_CAP io_cap; /* local IO capabilities */ + tBTM_OOB_DATA oob_data; /* OOB data present (locally) for the peer device */ + tBTM_AUTH_REQ auth_req; /* Authentication required (for local device) */ + bool is_orig; /* true, if local device initiated the SP process */ +} tBTM_SP_IO_REQ; + +/* data type for BTM_SP_IO_RSP_EVT */ +typedef struct { + RawAddress bd_addr; /* peer address */ + tBTM_IO_CAP io_cap; /* peer IO capabilities */ + tBTM_OOB_DATA + oob_data; /* OOB data present at peer device for the local device */ + tBTM_AUTH_REQ auth_req; /* Authentication required for peer device */ +} tBTM_SP_IO_RSP; + +/* data type for BTM_SP_CFM_REQ_EVT */ +typedef struct { + RawAddress bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ + uint32_t num_val; /* the numeric value for comparison. If just_works, do not + show this number to UI */ + bool just_works; /* true, if "Just Works" association model */ + tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */ + tBTM_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */ + tBTM_IO_CAP loc_io_caps; /* IO Capabilities of the local device */ + tBTM_IO_CAP rmt_io_caps; /* IO Capabilities of the remot device */ +} tBTM_SP_CFM_REQ; + +/* data type for BTM_SP_KEY_REQ_EVT */ +typedef struct { + RawAddress bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ +} tBTM_SP_KEY_REQ; + +/* data type for BTM_SP_KEY_NOTIF_EVT */ +typedef struct { + RawAddress bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ + uint32_t passkey; /* passkey */ +} tBTM_SP_KEY_NOTIF; + +/* data type for BTM_SP_LOC_OOB_EVT */ +typedef struct { + tBTM_STATUS status; /* */ + Octet16 c; /* Simple Pairing Hash C */ + Octet16 r; /* Simple Pairing Randomnizer R */ +} tBTM_SP_LOC_OOB; + +/* data type for BTM_SP_RMT_OOB_EVT */ +typedef struct { + RawAddress bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ +} tBTM_SP_RMT_OOB; + +typedef union { + tBTM_SP_IO_REQ io_req; /* BTM_SP_IO_REQ_EVT */ + tBTM_SP_IO_RSP io_rsp; /* BTM_SP_IO_RSP_EVT */ + tBTM_SP_CFM_REQ cfm_req; /* BTM_SP_CFM_REQ_EVT */ + tBTM_SP_KEY_NOTIF key_notif; /* BTM_SP_KEY_NOTIF_EVT */ + tBTM_SP_KEY_REQ key_req; /* BTM_SP_KEY_REQ_EVT */ + tBTM_SP_LOC_OOB loc_oob; /* BTM_SP_LOC_OOB_EVT */ + tBTM_SP_RMT_OOB rmt_oob; /* BTM_SP_RMT_OOB_EVT */ +} tBTM_SP_EVT_DATA; + +/* Simple Pairing Events. Called by the stack when Simple Pairing related + * events occur. +*/ +typedef tBTM_STATUS(tBTM_SP_CALLBACK)(tBTM_SP_EVT event, + tBTM_SP_EVT_DATA* p_data); + +typedef void(tBTM_MKEY_CALLBACK)(const RawAddress& bd_addr, uint8_t status, + uint8_t key_flag); + +/* Encryption enabled/disabled complete: Optionally passed with + * BTM_SetEncryption. + * Parameters are + * BD Address of remote + * optional data passed in by BTM_SetEncryption + * tBTM_STATUS - result of the operation +*/ +typedef void(tBTM_SEC_CALLBACK)(const RawAddress* bd_addr, + tBT_TRANSPORT trasnport, void* p_ref_data, + tBTM_STATUS result); +typedef tBTM_SEC_CALLBACK tBTM_SEC_CALLBACK; + +/* Bond Cancel complete. Parameters are + * Result of the cancel operation + * +*/ +typedef void(tBTM_BOND_CANCEL_CMPL_CALLBACK)(tBTM_STATUS result); + +/* LE related event and data structure */ +/* received IO_CAPABILITY_REQUEST event */ +#define BTM_LE_IO_REQ_EVT SMP_IO_CAP_REQ_EVT +/* security request event */ +#define BTM_LE_SEC_REQUEST_EVT SMP_SEC_REQUEST_EVT +/* received USER_PASSKEY_NOTIFY event */ +#define BTM_LE_KEY_NOTIF_EVT SMP_PASSKEY_NOTIF_EVT +/* received USER_PASSKEY_REQUEST event */ +#define BTM_LE_KEY_REQ_EVT SMP_PASSKEY_REQ_EVT +/* OOB data request event */ +#define BTM_LE_OOB_REQ_EVT SMP_OOB_REQ_EVT +/* Numeric Comparison request event */ +#define BTM_LE_NC_REQ_EVT SMP_NC_REQ_EVT +/* Peer keypress notification recd event */ +#define BTM_LE_PR_KEYPR_NOT_EVT SMP_PEER_KEYPR_NOT_EVT +/* SC OOB request event (both local and peer OOB data) can be expected in + * response */ +#define BTM_LE_SC_OOB_REQ_EVT SMP_SC_OOB_REQ_EVT +/* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */ +#define BTM_LE_SC_LOC_OOB_EVT SMP_SC_LOC_OOB_DATA_UP_EVT +/* SMP complete event */ +#define BTM_LE_COMPLT_EVT SMP_COMPLT_EVT +#define BTM_LE_LAST_FROM_SMP SMP_BR_KEYS_REQ_EVT +/* KEY update event */ +#define BTM_LE_KEY_EVT (BTM_LE_LAST_FROM_SMP + 1) +#define BTM_LE_CONSENT_REQ_EVT SMP_CONSENT_REQ_EVT +/* Identity address associate event */ +#define BTM_LE_ADDR_ASSOC_EVT SMP_LE_ADDR_ASSOC_EVT +typedef uint8_t tBTM_LE_EVT; + +enum : uint8_t { + BTM_LE_KEY_NONE = 0, + BTM_LE_KEY_PENC = SMP_SEC_KEY_TYPE_ENC, + /* identity key of the peer device */ + BTM_LE_KEY_PID = SMP_SEC_KEY_TYPE_ID, + /* peer SRK */ + BTM_LE_KEY_PCSRK = SMP_SEC_KEY_TYPE_CSRK, + BTM_LE_KEY_PLK = SMP_SEC_KEY_TYPE_LK, + BTM_LE_KEY_LLK = (SMP_SEC_KEY_TYPE_LK << 4), + /* master role security information:div */ + BTM_LE_KEY_LENC = (SMP_SEC_KEY_TYPE_ENC << 4), + /* master device ID key */ + BTM_LE_KEY_LID = (SMP_SEC_KEY_TYPE_ID << 4), + /* local CSRK has been deliver to peer */ + BTM_LE_KEY_LCSRK = (SMP_SEC_KEY_TYPE_CSRK << 4), +}; +typedef uint8_t tBTM_LE_KEY_TYPE; + +#define BTM_LE_AUTH_REQ_NO_BOND SMP_AUTH_NO_BOND /* 0 */ +#define BTM_LE_AUTH_REQ_BOND SMP_AUTH_BOND /* 1 << 0 */ +#define BTM_LE_AUTH_REQ_MITM SMP_AUTH_YN_BIT /* 1 << 2 */ +typedef uint8_t tBTM_LE_AUTH_REQ; +#define BTM_LE_SC_SUPPORT_BIT SMP_SC_SUPPORT_BIT /* (1 << 3) */ +#define BTM_LE_KP_SUPPORT_BIT SMP_KP_SUPPORT_BIT /* (1 << 4) */ +#define BTM_LE_H7_SUPPORT_BIT SMP_H7_SUPPORT_BIT /* (1 << 5) */ + +#define BTM_LE_AUTH_REQ_SC_ONLY SMP_AUTH_SC_ENC_ONLY /* 00101000 */ +#define BTM_LE_AUTH_REQ_SC_BOND SMP_AUTH_SC_GB /* 00101001 */ +#define BTM_LE_AUTH_REQ_SC_MITM SMP_AUTH_SC_MITM_NB /* 00101100 */ +#define BTM_LE_AUTH_REQ_SC_MITM_BOND SMP_AUTH_SC_MITM_GB /* 00101101 */ +#define BTM_LE_AUTH_REQ_MASK SMP_AUTH_MASK /* 0x3D */ + +typedef struct { + /* local IO capabilities */ + tBTM_IO_CAP io_cap; + /* OOB data present (locally) for the peer device */ + uint8_t oob_data; + /* Authentication request (for local device) containing bonding and MITM + * info */ + tBTM_LE_AUTH_REQ auth_req; + uint8_t max_key_size; /* max encryption key size */ + tBTM_LE_KEY_TYPE init_keys; /* keys to be distributed, bit mask */ + tBTM_LE_KEY_TYPE resp_keys; /* keys to be distributed, bit mask */ +} tBTM_LE_IO_REQ; + +/* data type for tBTM_LE_COMPLT */ +typedef struct { + uint8_t reason; + uint8_t sec_level; + bool is_pair_cancel; + bool smp_over_br; +} tBTM_LE_COMPLT; + +/************************ + * Stored Linkkey Types + ************************/ +#define BTM_CB_EVT_DELETE_STORED_LINK_KEYS 4 + +typedef struct { + uint8_t event; + uint8_t status; + uint16_t num_keys; +} tBTM_DELETE_STORED_LINK_KEY_COMPLETE; + +enum tBTM_BOND_TYPE : uint8_t { + BOND_TYPE_UNKNOWN = 0, + BOND_TYPE_PERSISTENT = 1, + BOND_TYPE_TEMPORARY = 2 +}; + +inline std::string bond_type_text(const tBTM_BOND_TYPE& bond_type) { + switch (bond_type) { + CASE_RETURN_TEXT(BOND_TYPE_UNKNOWN); + CASE_RETURN_TEXT(BOND_TYPE_PERSISTENT); + CASE_RETURN_TEXT(BOND_TYPE_TEMPORARY); + default: + return base::StringPrintf("UNKNOWN[%hhu]", bond_type); + } +} diff --git a/system/stack/include/btm_status.h b/system/stack/include/btm_status.h index 8e2db305258aeb5186e29009315eadc3c24ea68e..cc0c822764e31bcef456d41c4e7c4c471c990e73 100644 --- a/system/stack/include/btm_status.h +++ b/system/stack/include/btm_status.h @@ -17,8 +17,11 @@ #pragma once #include + #include +#include "macros.h" + /* BTM application return status codes */ enum : uint8_t { BTM_SUCCESS = 0, /* 0 Command succeeded */ @@ -41,11 +44,15 @@ enum : uint8_t { BTM_SUCCESS_NO_SECURITY, /* 17 security passed, no security set */ BTM_FAILED_ON_SECURITY, /* 18 security failed */ BTM_REPEATED_ATTEMPTS, /* 19 repeated attempts for LE security requests */ - BTM_MODE4_LEVEL4_NOT_SUPPORTED, /* 20 Secure Connections Only Mode can't be - supported */ - BTM_DEV_RESTRICT_LISTED, /* 21 The device is restrict listed */ - BTM_ERR_KEY_MISSING, /* 22 Handle for Pin or Key Missing */ - BTM_MAX_STATUS_VALUE = BTM_DEV_RESTRICT_LISTED, + BTM_MODE4_LEVEL4_NOT_SUPPORTED, /* 20 Secure Connections Only Mode can't be + supported */ + BTM_DEV_RESTRICT_LISTED, /* 21 The device is restrict listed */ + BTM_ERR_KEY_MISSING, /* 22 Handle for Pin or Key Missing */ + BTM_NOT_AUTHENTICATED, /* 23 the link is not authenticated */ + BTM_NOT_ENCRYPTED, /* 24 the link is not encrypted */ + BTM_INSUFFICIENT_ENCRYPT_KEY_SIZE, /* 25 the encrypt key size not sufficient + */ + BTM_MAX_STATUS_VALUE, BTM_UNDEFINED = 0xFF, }; typedef uint8_t tBTM_STATUS; @@ -55,14 +62,10 @@ inline uint8_t btm_status_value(const tBTM_STATUS& status) { } inline tBTM_STATUS to_btm_status(const uint8_t& value) { - if (value > BTM_MAX_STATUS_VALUE) return BTM_UNDEFINED; + if (value >= BTM_MAX_STATUS_VALUE) return BTM_UNDEFINED; return static_cast(value); } -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string btm_status_text(const tBTM_STATUS& status) { switch (status) { CASE_RETURN_TEXT(BTM_SUCCESS); @@ -88,9 +91,10 @@ inline std::string btm_status_text(const tBTM_STATUS& status) { CASE_RETURN_TEXT(BTM_MODE4_LEVEL4_NOT_SUPPORTED); CASE_RETURN_TEXT(BTM_DEV_RESTRICT_LISTED); CASE_RETURN_TEXT(BTM_ERR_KEY_MISSING); + CASE_RETURN_TEXT(BTM_NOT_AUTHENTICATED); + CASE_RETURN_TEXT(BTM_NOT_ENCRYPTED); + CASE_RETURN_TEXT(BTM_INSUFFICIENT_ENCRYPT_KEY_SIZE); default: return base::StringPrintf("UNKNOWN[%hhu]", status); } } - -#undef CASE_RETURN_TEXT diff --git a/system/stack/include/btu.h b/system/stack/include/btu.h deleted file mode 100644 index bc25ca3adac520b3a084d493981565dc03558235..0000000000000000000000000000000000000000 --- a/system/stack/include/btu.h +++ /dev/null @@ -1,76 +0,0 @@ -/****************************************************************************** - * - * Copyright 1999-2012 Broadcom Corporation - * - * 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. - * - ******************************************************************************/ - -/****************************************************************************** - * - * this file contains the main Bluetooth Upper Layer definitions. The Broadcom - * implementations of L2CAP RFCOMM, SDP and the BTIf run as one GKI task. The - * btu_task switches between them. - * - ******************************************************************************/ - -#ifndef BTU_H -#define BTU_H - -#include -#include -#include - -#include - -#include "bt_target.h" -#include "common/message_loop_thread.h" -#include "include/hardware/bluetooth.h" -#include "osi/include/alarm.h" -#include "osi/include/osi.h" // UNUSED_ATTR -#include "stack/include/bt_hdr.h" - -/* Global BTU data */ -extern uint8_t btu_trace_level; - -/* Functions provided by btu_hcif.cc - *********************************** -*/ -void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, - const BT_HDR* p_buf); -void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, const BT_HDR* p_msg); -void btu_hcif_send_cmd_with_cb(const base::Location& posted_from, - uint16_t opcode, uint8_t* params, - uint8_t params_len, - base::OnceCallback cb); -namespace bluetooth::legacy::testing { -void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status, - const uint8_t* p_cmd, - void* p_vsc_status_cback); -} // namespace bluetooth::legacy::testing - -/* Functions provided by btu_task.cc - *********************************** -*/ -bluetooth::common::MessageLoopThread* get_main_thread(); -bt_status_t do_in_main_thread(const base::Location& from_here, - base::OnceClosure task); -bt_status_t do_in_main_thread_delayed(const base::Location& from_here, - base::OnceClosure task, - const base::TimeDelta& delay); - -bool is_on_main_thread(); -using BtMainClosure = std::function; -void post_on_bt_main(BtMainClosure closure); - -#endif diff --git a/system/stack/include/btu_hcif.h b/system/stack/include/btu_hcif.h new file mode 100644 index 0000000000000000000000000000000000000000..dc1c0378776c8ab66b5078270182eed13cbffdd4 --- /dev/null +++ b/system/stack/include/btu_hcif.h @@ -0,0 +1,41 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include "include/hardware/bluetooth.h" +#include "osi/include/osi.h" // UNUSED_ATTR +#include "stack/include/bt_hdr.h" + +/* Functions provided by btu_hcif.cc + *********************************** + */ +void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, + const BT_HDR* p_buf); +void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, const BT_HDR* p_msg); +void btu_hcif_send_cmd_with_cb(const base::Location& posted_from, + uint16_t opcode, uint8_t* params, + uint8_t params_len, + base::OnceCallback cb); +namespace bluetooth::legacy::testing { +void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status, + const uint8_t* p_cmd); +} // namespace bluetooth::legacy::testing \ No newline at end of file diff --git a/system/stack/include/dev_hci_link_interface.h b/system/stack/include/dev_hci_link_interface.h index 7260098e20040f81cfdb009b1c160f2dca03e5ce..81cd138a20dbd0fc242c3e68005bd561c8f7592e 100644 --- a/system/stack/include/dev_hci_link_interface.h +++ b/system/stack/include/dev_hci_link_interface.h @@ -25,6 +25,4 @@ void btm_delete_stored_link_key_complete(uint8_t* p, uint16_t evt_len); void btm_vendor_specific_evt(const uint8_t* p, uint8_t evt_len); -void btm_vsc_complete(uint8_t* p, uint16_t cc_opcode, uint16_t evt_len, - tBTM_VSC_CMPL_CB* p_vsc_cplt_cback); void btm_read_local_name_complete(uint8_t* p, uint16_t evt_len); diff --git a/system/stack/include/gatt_api.h b/system/stack/include/gatt_api.h index 2e02190ca08ba2d56b59dedc8c03fc6ccc4b0d7c..942cea1f287d2921b5ae047402840636d0e6163d 100644 --- a/system/stack/include/gatt_api.h +++ b/system/stack/include/gatt_api.h @@ -27,6 +27,8 @@ #include "bt_target.h" #include "btm_ble_api.h" #include "gattdefs.h" +#include "hardware/bt_gatt_types.h" +#include "macros.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -87,12 +89,6 @@ typedef enum GattStatus : uint8_t { GATT_OUT_OF_RANGE = 0xFF, } tGATT_STATUS; -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string gatt_status_text(const tGATT_STATUS& status) { switch (status) { CASE_RETURN_TEXT(GATT_SUCCESS); // Also GATT_ENCRYPED_MITM @@ -143,8 +139,6 @@ inline std::string gatt_status_text(const tGATT_STATUS& status) { } } -#undef CASE_RETURN_TEXT - typedef enum : uint8_t { GATT_RSP_ERROR = 0x01, GATT_REQ_MTU = 0x02, @@ -286,10 +280,6 @@ typedef enum : uint16_t { } tGATT_DISCONN_REASON; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string gatt_disconnection_reason_text( const tGATT_DISCONN_REASON& reason) { switch (reason) { @@ -306,7 +296,6 @@ inline std::string gatt_disconnection_reason_text( return base::StringPrintf("UNKNOWN[%hu]", reason); } } -#undef CASE_RETURN_TEXT /* MAX GATT MTU size */ @@ -314,12 +303,6 @@ inline std::string gatt_disconnection_reason_text( #define GATT_MAX_MTU_SIZE 517 #endif -/* max legth of an attribute value -*/ -#ifndef GATT_MAX_ATTR_LEN -#define GATT_MAX_ATTR_LEN 512 -#endif - /* default GATT MTU size over LE link */ #define GATT_DEF_BLE_MTU_SIZE 23 diff --git a/system/stack/include/gattdefs.h b/system/stack/include/gattdefs.h index a483d6a44c1b30de0c2649298220fdea7fbaf2f9..76f0790f749b9281c1a87d44a3e8a0cc9e03cb33 100644 --- a/system/stack/include/gattdefs.h +++ b/system/stack/include/gattdefs.h @@ -138,4 +138,7 @@ /* Database Hash characteristic */ #define GATT_UUID_DATABASE_HASH 0x2B2A +/* CSIS SIRK characteristic */ +#define GATT_UUID_CSIS_SIRK 0x2B84 + #endif diff --git a/system/stack/include/hci_error_code.h b/system/stack/include/hci_error_code.h index b728f679f5b057c3e6efd22726e7cf65d8629129..20acb745868d657f87fe01aa1002786002faf66d 100644 --- a/system/stack/include/hci_error_code.h +++ b/system/stack/include/hci_error_code.h @@ -21,6 +21,8 @@ #include #include +#include "macros.h" + /* * Definitions for HCI Error Codes that are passed in the events */ @@ -72,12 +74,6 @@ typedef enum : uint8_t { #define HCI_ERR_MAX_ERR _HCI_ERR_MAX_ERR // HACK for now for SMP -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string hci_error_code_text(const tHCI_ERROR_CODE& error_code) { switch (error_code) { CASE_RETURN_TEXT(HCI_SUCCESS); @@ -125,8 +121,6 @@ inline std::string hci_error_code_text(const tHCI_ERROR_CODE& error_code) { } } -#undef CASE_RETURN_TEXT - // Context equivalence using tHCI_STATUS = tHCI_ERROR_CODE; inline std::string hci_status_code_text(const tHCI_STATUS& status_code) { diff --git a/system/stack/include/hcidefs.h b/system/stack/include/hcidefs.h index 4fc3d48f6cf8f9c6c878ba99ff9c0587b1d60a04..a8ad4499bffbe9ed0523f903e163210882d5ea57 100644 --- a/system/stack/include/hcidefs.h +++ b/system/stack/include/hcidefs.h @@ -30,6 +30,7 @@ #define HCI_PROTO_VERSION_4_1 0x07 /* Version for BT spec 4.1 */ #define HCI_PROTO_VERSION_4_2 0x08 /* Version for BT spec 4.2 */ #define HCI_PROTO_VERSION_5_0 0x09 /* Version for BT spec 5.0 */ +#define HCI_PROTO_VERSION_5_2 0x0B /* Version for BT spec 5.2 */ /* * Definitions for HCI groups @@ -915,6 +916,9 @@ typedef struct { // TODO Remove this once all UNISOC specific hacks are removed. #define LMP_COMPID_UNISOC 0x073F +// TODO Remove this once all Mediatek specific hacks are removed. +#define LMP_COMPID_MEDIATEK 0x0046 + /* Parameter information for HCI_SYNA_SET_ACL_PRIORITY */ #define HCI_SYNA_ACL_PRIORITY_PARAM_SIZE 3 #define HCI_SYNA_ACL_NORMAL_PRIORITY 0xF0 @@ -928,6 +932,12 @@ typedef struct { #define HCI_UNISOC_ACL_NORMAL_PRIORITY 0x00 #define HCI_UNISOC_ACL_HIGH_PRIORITY 0xFF +/* Parameter information for HCI_MTK_SET_ACL_PRIORITY */ +#define HCI_MTK_ACL_PRIORITY_PARAM_SIZE 1 +#define HCI_MTK_SET_ACL_PRIORITY (0xFD95 | HCI_GRP_VENDOR_SPECIFIC) +#define HCI_MTK_ACL_NORMAL_PRIORITY 0x00 +#define HCI_MTK_ACL_HIGH_PRIORITY 0x01 + /* * Define packet size */ diff --git a/system/stack/include/hcimsgs.h b/system/stack/include/hcimsgs.h index ac9deb17e62a8ab039638b5918921e76707ce928..2638220996749c7d55d28c1db6dd1feaffbeedf8 100644 --- a/system/stack/include/hcimsgs.h +++ b/system/stack/include/hcimsgs.h @@ -22,38 +22,43 @@ #include #include +#include -#include "bt_target.h" #include "device/include/esco_parameters.h" -#include "stack/include/bt_hdr.h" +#include "stack/include/bt_lap.h" +#include "stack/include/bt_name.h" #include "stack/include/bt_octets.h" +#include "stack/include/btm_api_types.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" -void bte_main_hci_send(BT_HDR* p_msg, uint16_t event); - /* Message by message.... */ +enum hci_data_direction_t { + HOST_TO_CONTROLLER = 0, + CONTROLLER_TO_HOST = 1, +}; + /* Disconnect */ -namespace bluetooth { -namespace legacy { -namespace hci { -struct Interface { - // LINK_CONTROL 0x04xx - void (*StartInquiry)(const LAP inq_lap, uint8_t duration, - uint8_t response_cnt); - void (*InquiryCancel)(); - void (*Disconnect)(uint16_t handle, uint8_t reason); - void (*ChangeConnectionPacketType)(uint16_t handle, uint16_t packet_types); - void (*StartRoleSwitch)(const RawAddress& bd_addr, uint8_t role); +namespace bluetooth::legacy::hci { +class Interface { + public: + virtual void StartInquiry(const LAP inq_lap, uint8_t duration, + uint8_t response_cnt) const = 0; + virtual void InquiryCancel() const = 0; + virtual void Disconnect(uint16_t handle, uint8_t reason) const = 0; + virtual void ChangeConnectionPacketType(uint16_t handle, + uint16_t packet_types) const = 0; + virtual void StartRoleSwitch(const RawAddress& bd_addr, + uint8_t role) const = 0; + virtual void ConfigureDataPath(hci_data_direction_t data_path_direction, + uint8_t data_path_id, + std::vector vendor_config) const = 0; + virtual ~Interface() = default; }; const Interface& GetInterface(); -} // namespace hci -} // namespace legacy -} // namespace bluetooth - -/* Disconnect */ +} // namespace bluetooth::legacy::hci /* Add SCO Connection */ void btsnd_hcic_add_SCO_conn(uint16_t handle, uint16_t packet_types); @@ -203,6 +208,12 @@ void btsnd_hcic_enhanced_flush(uint16_t handle, uint8_t packet_type); /**** end of Simple Pairing Commands ****/ +extern void btsnd_hcic_set_event_filter(uint8_t filt_type, + uint8_t filt_cond_type, + uint8_t* filt_cond, + uint8_t filt_cond_len); +/* Set Event Filter */ + /* Delete Stored Key */ void btsnd_hcic_delete_stored_key(const RawAddress& bd_addr, bool delete_all_flag); @@ -253,6 +264,7 @@ void btsnd_hcic_read_rssi(uint16_t handle); /* Read RSSI */ using ReadEncKeySizeCb = base::OnceCallback; void btsnd_hcic_read_encryption_key_size(uint16_t handle, ReadEncKeySizeCb cb); void btsnd_hcic_read_failed_contact_counter(uint16_t handle); +void btsnd_hcic_enable_test_mode(void); /* Enable Device Under Test Mode */ void btsnd_hcic_write_pagescan_type(uint8_t type); /* Write Page Scan Type */ void btsnd_hcic_write_inqscan_type(uint8_t type); /* Write Inquiry Scan Type */ void btsnd_hcic_write_inquiry_mode(uint8_t type); /* Write Inquiry Mode */ @@ -281,8 +293,8 @@ void btsnd_hcic_enhanced_accept_synchronous_connection( #define HCID_GET_EVENT(u16) \ (uint8_t)(((u16) >> HCI_DATA_EVENT_OFFSET) & HCI_DATA_EVENT_MASK) -void btsnd_hcic_vendor_spec_cmd(void* buffer, uint16_t opcode, uint8_t len, - uint8_t* p_data, void* p_cmd_cplt_cback); +void btsnd_hcic_vendor_spec_cmd(uint16_t opcode, uint8_t len, uint8_t* p_data, + tBTM_VSC_CMPL_CB* p_cmd_cplt_cback); /******************************************************************************* * BLE Commands @@ -298,8 +310,6 @@ void btsnd_hcic_vendor_spec_cmd(void* buffer, uint16_t opcode, uint8_t len, /* ULP HCI command */ void btsnd_hcic_ble_set_local_used_feat(uint8_t feat_set[8]); -void btsnd_hcic_ble_set_random_addr(const RawAddress& random_addr); - void btsnd_hcic_ble_write_adv_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type, tBLE_ADDR_TYPE addr_type_own, @@ -312,8 +322,6 @@ void btsnd_hcic_ble_read_adv_chnl_tx_power(void); void btsnd_hcic_ble_set_adv_data(uint8_t data_len, uint8_t* p_data); -void btsnd_hcic_ble_set_scan_rsp_data(uint8_t data_len, uint8_t* p_scan_rsp); - void btsnd_hcic_ble_set_adv_enable(uint8_t adv_enable); void btsnd_hcic_ble_set_scan_params(uint8_t scan_type, uint16_t scan_int, @@ -322,17 +330,6 @@ void btsnd_hcic_ble_set_scan_params(uint8_t scan_type, uint16_t scan_int, void btsnd_hcic_ble_set_scan_enable(uint8_t scan_enable, uint8_t duplicate); -void btsnd_hcic_ble_create_ll_conn(uint16_t scan_int, uint16_t scan_win, - uint8_t init_filter_policy, - tBLE_ADDR_TYPE addr_type_peer, - const RawAddress& bda_peer, - tBLE_ADDR_TYPE addr_type_own, - uint16_t conn_int_min, uint16_t conn_int_max, - uint16_t conn_latency, uint16_t conn_timeout, - uint16_t min_ce_len, uint16_t max_ce_len); - -void btsnd_hcic_ble_create_conn_cancel(void); - void btsnd_hcic_ble_read_acceptlist_size(void); void btsnd_hcic_ble_upd_ll_conn_params(uint16_t handle, uint16_t conn_int_min, @@ -341,11 +338,6 @@ void btsnd_hcic_ble_upd_ll_conn_params(uint16_t handle, uint16_t conn_int_min, uint16_t conn_timeout, uint16_t min_len, uint16_t max_len); -void btsnd_hcic_ble_set_host_chnl_class( - uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE]); - -void btsnd_hcic_ble_read_chnl_map(uint16_t handle); - void btsnd_hcic_ble_read_remote_feat(uint16_t handle); void btsnd_hcic_ble_rand(base::Callback cb); @@ -360,10 +352,11 @@ void btsnd_hcic_ble_ltk_req_neg_reply(uint16_t handle); void btsnd_hcic_ble_read_supported_states(void); -void btsnd_hcic_ble_write_host_supported(uint8_t le_host_spt, - uint8_t simul_le_host_spt); +void btsnd_hcic_ble_receiver_test(uint8_t rx_freq); -void btsnd_hcic_ble_read_host_supported(void); +void btsnd_hcic_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len, + uint8_t payload); +void btsnd_hcic_ble_test_end(void); void btsnd_hcic_ble_rc_param_req_reply(uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max, @@ -404,21 +397,9 @@ struct EXT_CONN_PHY_CFG { uint16_t max_ce_len; }; -void btsnd_hcic_ble_ext_create_conn(uint8_t init_filter_policy, - uint8_t addr_type_own, - uint8_t addr_type_peer, - const RawAddress& bda_peer, - uint8_t initiating_phys, - EXT_CONN_PHY_CFG* phy_cfg); - void btsnd_hcic_ble_read_resolvable_addr_peer(uint8_t addr_type_peer, const RawAddress& bda_peer); -void btsnd_hcic_ble_read_resolvable_addr_local(uint8_t addr_type_peer, - const RawAddress& bda_peer); - -void btsnd_hcic_ble_set_addr_resolution_enable(uint8_t addr_resolution_enable); - void btsnd_hcic_ble_set_rand_priv_addr_timeout(uint16_t rpa_timout); void btsnd_hcic_read_authenticated_payload_tout(uint16_t handle); @@ -426,9 +407,6 @@ void btsnd_hcic_read_authenticated_payload_tout(uint16_t handle); void btsnd_hcic_write_authenticated_payload_tout(uint16_t handle, uint16_t timeout); -void btsnd_hcic_read_iso_tx_sync( - uint16_t iso_handle, base::OnceCallback cb); - struct EXT_CIS_CFG { uint8_t cis_id; uint16_t max_sdu_size_mtos; @@ -488,9 +466,6 @@ void btsnd_hcic_create_big(uint8_t big_handle, uint8_t adv_handle, void btsnd_hcic_term_big(uint8_t big_handle, uint8_t reason); -void btsnd_hcic_big_term_sync(uint8_t big_handle, - base::OnceCallback cb); - void btsnd_hcic_setup_iso_data_path( uint16_t iso_handle, uint8_t data_path_dir, uint8_t data_path_id, uint8_t codec_id_format, uint16_t codec_id_company, @@ -527,9 +502,6 @@ void btsnd_hci_ble_remove_device_from_periodic_advertiser_list( void btsnd_hci_ble_clear_periodic_advertiser_list( base::OnceCallback cb); -void btsnd_hci_ble_read_periodic_advertiser_list_size( - base::OnceCallback cb); - void btsnd_hcic_ble_set_periodic_advertising_receive_enable( uint16_t sync_handle, bool enable, base::OnceCallback cb); @@ -550,7 +522,7 @@ void btsnd_hcic_ble_set_default_periodic_advertising_sync_transfer_params( uint16_t conn_handle, uint8_t mode, uint16_t skip, uint16_t sync_timeout, uint8_t cte_type, base::OnceCallback cb); -void btsnd_hcic_configure_data_path(uint8_t data_path_direction, +void btsnd_hcic_configure_data_path(hci_data_direction_t data_path_direction, uint8_t data_path_id, std::vector vendor_config); diff --git a/system/stack/include/hfp_lc3_decoder.h b/system/stack/include/hfp_lc3_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..82a6168e63ee5d85eec232c375e667381ed669e5 --- /dev/null +++ b/system/stack/include/hfp_lc3_decoder.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Interface to the HFP LC3 Decoder +// + +#ifndef HFP_LC3_DECODER_H +#define HFP_LC3_DECODER_H + +#include +#include + +// Initialize the HFP LC3 decoder. +bool hfp_lc3_decoder_init(); + +// Cleanup the HFP LC3 decoder. +void hfp_lc3_decoder_cleanup(); + +// Decodes |i_buf| into |o_buf| with size |out_len| in bytes. |i_buf| should +// point to a complete LC3 packet with 60 bytes of data including the header, +// otherwise PLC will be conducted. +bool hfp_lc3_decoder_decode_packet(const uint8_t* i_buf, int16_t* o_buf, + size_t out_len); + +#endif // HFP_LC3_DECODER_H diff --git a/system/stack/include/hfp_lc3_encoder.h b/system/stack/include/hfp_lc3_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..da826390c84256039690d34b8ab532a4ca064480 --- /dev/null +++ b/system/stack/include/hfp_lc3_encoder.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Interface to the HFP LC3 Encoder +// + +#ifndef HFP_LC3_ENCODER_H +#define HFP_LC3_ENCODER_H + +#include + +// Initialize the HFP LC3 encoder. +void hfp_lc3_encoder_init(); + +// Cleanup the HFP LC3 encoder. +void hfp_lc3_encoder_cleanup(); + +// Encode the frame. +// Returns number of PCM bytes consumed (should always be 480). +uint32_t hfp_lc3_encode_frames(int16_t* input, uint8_t* output); + +#endif // HFP_LC3_ENCODER_H diff --git a/system/stack/include/hidd_api.h b/system/stack/include/hidd_api.h index 032db8806937f48a7c9315ee61637ff22fa2db97..8a642daa6483fb73d096945d2fe9e6d2672cf014 100644 --- a/system/stack/include/hidd_api.h +++ b/system/stack/include/hidd_api.h @@ -235,18 +235,6 @@ tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation); -/******************************************************************************* - * - * Function HID_DevSetTraceLevel - * - * Description This function sets the trace level for HID Dev. If called - * with a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t HID_DevSetTraceLevel(uint8_t new_level); - #ifdef __cplusplus } #endif diff --git a/system/stack/include/hiddefs.h b/system/stack/include/hiddefs.h index 39cd8a17088544765a69014c7431bdbb52f82b4a..aadafdb49109f2a1ce76180f91faf7808d134de5 100644 --- a/system/stack/include/hiddefs.h +++ b/system/stack/include/hiddefs.h @@ -29,6 +29,7 @@ #include +#include "macros.h" #include "stack/include/sdp_api.h" /* * tHID_STATUS: HID result codes, returned by HID and device and host functions. @@ -57,10 +58,6 @@ typedef enum : uint8_t { HID_ERR_INVALID = 0xFF } tHID_STATUS; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string hid_status_text(const tHID_STATUS& status) { switch (status) { CASE_RETURN_TEXT(HID_SUCCESS); @@ -86,7 +83,6 @@ inline std::string hid_status_text(const tHID_STATUS& status) { return base::StringPrintf("UNKNOWN[%hhu]", status); } } -#undef CASE_RETURN_TEXT #define HID_L2CAP_CONN_FAIL \ (0x0100) /* Connection Attempt was made but failed */ diff --git a/system/stack/include/hidh_api.h b/system/stack/include/hidh_api.h index 1436a351aa4e02d4e20a9900f991571bedae9625..b2f0b162fec1aa25828b94544a2fe5a3f31881e8 100644 --- a/system/stack/include/hidh_api.h +++ b/system/stack/include/hidh_api.h @@ -124,6 +124,18 @@ tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* dev_cback); ******************************************************************************/ tHID_STATUS HID_HostDeregister(void); +/******************************************************************************* + * + * Function HID_HostSDPDisable + * + * Description This is called to check if the device has the HIDSDPDisable + * attribute. + * + * Returns bool + * + ******************************************************************************/ +bool HID_HostSDPDisable(const RawAddress& addr); + /******************************************************************************* * * Function HID_HostAddDev @@ -192,16 +204,4 @@ tHID_STATUS HID_HostCloseDev(uint8_t dev_handle); ******************************************************************************/ void HID_HostInit(void); -/******************************************************************************* - * - * Function HID_HostSetTraceLevel - * - * Description Set the trace level for HID Host. If called with the value - * 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t HID_HostSetTraceLevel(uint8_t new_level); - #endif /* HIDH_API_H */ diff --git a/system/stack/include/inq_hci_link_interface.h b/system/stack/include/inq_hci_link_interface.h index 1f56ce6c623a76681871b21031e95eb02f871149..5f712c399bba91672a98540e55ec9c96016c45a5 100644 --- a/system/stack/include/inq_hci_link_interface.h +++ b/system/stack/include/inq_hci_link_interface.h @@ -33,4 +33,5 @@ void btm_process_inq_complete(tHCI_STATUS status, uint8_t mode); void btm_process_cancel_complete(tHCI_STATUS status, uint8_t mode); void btm_acl_process_sca_cmpl_pkt(uint8_t len, uint8_t* data); -tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda); +tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda, bool is_ble); +void btm_inq_db_set_inq_by_rssi(void); diff --git a/system/stack/include/l2c_api.h b/system/stack/include/l2c_api.h index fb6d5a1a1bd2f5fdc1501138a71cd134aa9e27ad..b744acf376c158d8f48dab1d5581f3e83271dc8e 100644 --- a/system/stack/include/l2c_api.h +++ b/system/stack/include/l2c_api.h @@ -607,18 +607,6 @@ bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid); bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout, tBT_TRANSPORT transport); -/******************************************************************************* - * - * Function L2CA_SetTraceLevel - * - * Description This function sets the trace level for L2CAP. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t L2CA_SetTraceLevel(uint8_t trace_level); - /******************************************************************************* * * Function L2CA_FlushChannel diff --git a/system/stack/include/l2cap_acl_interface.h b/system/stack/include/l2cap_acl_interface.h index c464b179eaa8f24094edbf70af755c8c76df41bb..a40cd927d490164c514f8bcdb974ffdd8fb2ba7a 100644 --- a/system/stack/include/l2cap_acl_interface.h +++ b/system/stack/include/l2cap_acl_interface.h @@ -25,7 +25,6 @@ // This header contains functions for L2cap-ACL to invoke // -void acl_accept_connection_request(const RawAddress& bd_addr, uint8_t role); void acl_create_classic_connection(const RawAddress& bd_addr, bool there_are_high_priority_channels, bool is_bonding); @@ -33,7 +32,6 @@ bool acl_create_le_connection(const RawAddress& bd_addr); bool acl_create_le_connection_with_id(uint8_t id, const RawAddress& bd_addr); bool acl_create_le_connection_with_id(uint8_t id, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type); -void acl_reject_connection_request(const RawAddress& bd_addr, uint8_t reason); void acl_send_data_packet_br_edr(const RawAddress& bd_addr, BT_HDR* p_buf); void acl_send_data_packet_ble(const RawAddress& bd_addr, BT_HDR* p_buf); void acl_write_automatic_flush_timeout(const RawAddress& bd_addr, @@ -45,8 +43,6 @@ 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 l2c_link_hci_conn_req(const RawAddress& bd_addr); - 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 3b75cc63ac81169b7b4c06ad13e74c6f433f4449..86f06aebc77ea3c3289916d90b096d53004dfef8 100644 --- a/system/stack/include/l2cap_hci_link_interface.h +++ b/system/stack/include/l2cap_hci_link_interface.h @@ -20,6 +20,7 @@ #include #include "stack/include/hci_error_code.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" // This header contains functions for HCI-LinkManagement to invoke @@ -33,10 +34,6 @@ bool l2cble_conn_comp(uint16_t handle, uint8_t role, const RawAddress& bda, tBLE_ADDR_TYPE type, uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout); -bool l2cble_conn_comp_from_address_with_type( - uint16_t handle, uint8_t role, const tBLE_BD_ADDR& address_with_type, - uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout); - void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status, uint16_t interval, uint16_t latency, uint16_t timeout); diff --git a/system/stack/include/l2cap_security_interface.h b/system/stack/include/l2cap_security_interface.h index c3d14762613d4ef39c85a4e5f82fe55e81caf883..8d8b22c3ea09a44f64084d841d641ab611d1f29d 100644 --- a/system/stack/include/l2cap_security_interface.h +++ b/system/stack/include/l2cap_security_interface.h @@ -18,6 +18,7 @@ #pragma once #include +#include "stack/include/btm_status.h" #include "types/raw_address.h" // This header contains functions for Security Module to invoke diff --git a/system/stack/include/l2cdefs.h b/system/stack/include/l2cdefs.h index 1923c058904284299092b2bdc93538d45e9f3fde..be9e1f23deded761beaa97d2c0eb0b64c8c15e90 100644 --- a/system/stack/include/l2cdefs.h +++ b/system/stack/include/l2cdefs.h @@ -20,6 +20,9 @@ #define L2CDEFS_H #include + +#include "macros.h" + /* L2CAP command codes */ #define L2CAP_CMD_REJECT 0x01 @@ -156,12 +159,6 @@ typedef enum : uint16_t { L2CAP_CONN_LE_MASK + L2CAP_LE_RESULT_INVALID_PARAMETERS, } tL2CAP_CONN; -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string l2cap_result_code_text(const tL2CAP_CONN& result) { switch (result) { CASE_RETURN_TEXT(L2CAP_CONN_OK); @@ -188,7 +185,36 @@ inline std::string l2cap_result_code_text(const tL2CAP_CONN& result) { std::string("]"); } } -#undef CASE_RETURN_TEXT + +static inline std::string l2cap_command_code_text(uint8_t cmd) { + switch (cmd) { + CASE_RETURN_TEXT(L2CAP_CMD_REJECT); + CASE_RETURN_TEXT(L2CAP_CMD_CONN_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_CONN_RSP); + CASE_RETURN_TEXT(L2CAP_CMD_CONFIG_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_CONFIG_RSP); + CASE_RETURN_TEXT(L2CAP_CMD_DISC_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_DISC_RSP); + CASE_RETURN_TEXT(L2CAP_CMD_ECHO_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_ECHO_RSP); + CASE_RETURN_TEXT(L2CAP_CMD_INFO_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_INFO_RSP); + CASE_RETURN_TEXT(L2CAP_CMD_AMP_CONN_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_AMP_MOVE_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_BLE_UPDATE_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_BLE_UPDATE_RSP); + CASE_RETURN_TEXT(L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES); + CASE_RETURN_TEXT(L2CAP_CMD_BLE_FLOW_CTRL_CREDIT); + CASE_RETURN_TEXT(L2CAP_CMD_CREDIT_BASED_CONN_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_CREDIT_BASED_CONN_RES); + CASE_RETURN_TEXT(L2CAP_CMD_CREDIT_BASED_RECONFIG_REQ); + CASE_RETURN_TEXT(L2CAP_CMD_CREDIT_BASED_RECONFIG_RES); + default: + return std::string("UNKNOWN L2CAP CMD[") + std::to_string(cmd) + + std::string("]"); + } +} inline tL2CAP_CONN to_l2cap_result_code(uint16_t result) { return static_cast(result); diff --git a/system/stack/include/main_thread.h b/system/stack/include/main_thread.h new file mode 100644 index 0000000000000000000000000000000000000000..454c0db696da096aea0f37f0f7675f0695ce6b11 --- /dev/null +++ b/system/stack/include/main_thread.h @@ -0,0 +1,37 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "common/message_loop_thread.h" +#include "include/hardware/bluetooth.h" + +using BtMainClosure = std::function; +using bluetooth::common::MessageLoopThread; + +bluetooth::common::MessageLoopThread* get_main_thread(); +bt_status_t do_in_main_thread(const base::Location& from_here, + base::OnceClosure task); +bt_status_t do_in_main_thread_delayed(const base::Location& from_here, + base::OnceClosure task, + const base::TimeDelta& delay); +void post_on_bt_main(BtMainClosure closure); +void main_thread_start_up(); +void main_thread_shut_down(); diff --git a/system/stack/include/pan_api.h b/system/stack/include/pan_api.h index aac7cf446e2d0df65023dd1de349da4d9574e863..2a020a8d2121ceec84c6a6e414def21b677d337a 100644 --- a/system/stack/include/pan_api.h +++ b/system/stack/include/pan_api.h @@ -29,6 +29,7 @@ #include #include "bnep_api.h" +#include "macros.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" @@ -97,10 +98,6 @@ typedef enum : uint8_t { PAN_HOTSPOT_DISABLED = 20, /* Hotspot disabled */ } tPAN_RESULT; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline const std::string pan_result_text(const tPAN_RESULT& result) { switch (result) { CASE_RETURN_TEXT(PAN_SUCCESS); @@ -129,8 +126,6 @@ inline const std::string pan_result_text(const tPAN_RESULT& result) { } } -#undef CASE_RETURN_TEXT - /***************************************************************** * Callback Function Prototypes ****************************************************************/ @@ -431,18 +426,6 @@ tPAN_RESULT PAN_SetMulticastFilters(uint16_t handle, uint16_t num_mcast_filters, uint8_t* p_start_array, uint8_t* p_end_array); -/******************************************************************************* - * - * Function PAN_SetTraceLevel - * - * Description This function sets the trace level for PAN. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t PAN_SetTraceLevel(uint8_t new_level); - /******************************************************************************* * * Function PAN_Init diff --git a/system/stack/include/port_api.h b/system/stack/include/port_api.h index 21c15b0da21f3fa8bc3dc886eed43f896788a36e..f9c7062a49d497472302f098165401071eabe7bc 100644 --- a/system/stack/include/port_api.h +++ b/system/stack/include/port_api.h @@ -427,18 +427,6 @@ int PORT_WriteDataCO(uint16_t handle, int* p_len); ******************************************************************************/ void RFCOMM_Init(void); -/******************************************************************************* - * - * Function PORT_SetTraceLevel - * - * Description Set the trace level for RFCOMM. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t PORT_SetTraceLevel(uint8_t new_level); - /******************************************************************************* * * Function PORT_GetResultString diff --git a/system/stack/include/rfcdefs.h b/system/stack/include/rfcdefs.h index f5c952b0344143641f735fcaefaa8cd095cd6277..e3e287b2d943711639ba75c786d43120a378eabb 100644 --- a/system/stack/include/rfcdefs.h +++ b/system/stack/include/rfcdefs.h @@ -24,8 +24,10 @@ #ifndef RFCDEFS_H #define RFCDEFS_H - -#define PORT_MAX_RFC_PORTS 31 +/* + * Server Channel Numbers (SCN) range between 1 and 30, inclusive + */ +#define RFCOMM_MAX_SCN 30 /* * If nothing is negotiated MTU should be 127 diff --git a/system/stack/include/sco_hci_link_interface.h b/system/stack/include/sco_hci_link_interface.h index cd9d8f9e6b4f7af03a0df0923209b1f49bc3744c..34dc174113dfb2e7e5c159464546fdfed80c0857 100644 --- a/system/stack/include/sco_hci_link_interface.h +++ b/system/stack/include/sco_hci_link_interface.h @@ -19,6 +19,7 @@ #include +#include "stack/include/bt_dev_class.h" #include "stack/include/hci_error_code.h" #include "types/class_of_device.h" #include "types/raw_address.h" diff --git a/system/stack/include/sdp_api.h b/system/stack/include/sdp_api.h index 8cceb04ded32bb035ce7eecc069e0a57100b2c03..c2adbefc9cd20431c2bc4c0b87fd739ac1c85ccc 100644 --- a/system/stack/include/sdp_api.h +++ b/system/stack/include/sdp_api.h @@ -23,621 +23,15 @@ #include #include "bt_target.h" -#include "sdpdefs.h" +#include "stack/include/sdp_callback.h" +#include "stack/include/sdp_device_id.h" +#include "stack/include/sdp_status.h" +#include "stack/include/sdpdefs.h" +#include "stack/sdp/internal/sdp_api.h" +#include "stack/sdp/sdp_discovery_db.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -/***************************************************************************** - * Constants - ****************************************************************************/ - -/* Success code and error codes */ -typedef enum : uint16_t { - SDP_SUCCESS = 0x0000, - SDP_INVALID_VERSION = 0x0001, - SDP_INVALID_SERV_REC_HDL = 0x0002, - SDP_INVALID_REQ_SYNTAX = 0x0003, - SDP_INVALID_PDU_SIZE = 0x0004, - SDP_INVALID_CONT_STATE = 0x0005, - SDP_NO_RESOURCES = 0x0006, - SDP_DI_REG_FAILED = 0x0007, - SDP_DI_DISC_FAILED = 0x0008, - SDP_NO_DI_RECORD_FOUND = 0x0009, - SDP_ERR_ATTR_NOT_PRESENT = 0x000A, - SDP_ILLEGAL_PARAMETER = 0x000B, - - HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER + 1), - HID_SDP_MANDATORY_MISSING, - - SDP_NO_RECS_MATCH = 0xFFF0, - SDP_CONN_FAILED = 0xFFF1, - SDP_CFG_FAILED = 0xFFF2, - SDP_GENERIC_ERROR = 0xFFF3, - SDP_DB_FULL = 0xFFF4, - SDP_CANCEL = 0xFFF8, -} tSDP_STATUS; -using tSDP_RESULT = tSDP_STATUS; -using tSDP_REASON = tSDP_STATUS; - -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - -inline std::string sdp_status_text(const tSDP_STATUS& status) { - switch (status) { - CASE_RETURN_TEXT(SDP_SUCCESS); - CASE_RETURN_TEXT(SDP_INVALID_VERSION); - CASE_RETURN_TEXT(SDP_INVALID_SERV_REC_HDL); - CASE_RETURN_TEXT(SDP_INVALID_REQ_SYNTAX); - CASE_RETURN_TEXT(SDP_INVALID_PDU_SIZE); - CASE_RETURN_TEXT(SDP_INVALID_CONT_STATE); - CASE_RETURN_TEXT(SDP_NO_RESOURCES); - CASE_RETURN_TEXT(SDP_DI_REG_FAILED); - CASE_RETURN_TEXT(SDP_DI_DISC_FAILED); - CASE_RETURN_TEXT(SDP_NO_DI_RECORD_FOUND); - CASE_RETURN_TEXT(SDP_ERR_ATTR_NOT_PRESENT); - CASE_RETURN_TEXT(SDP_ILLEGAL_PARAMETER); - - CASE_RETURN_TEXT(HID_SDP_NO_SERV_UUID); - CASE_RETURN_TEXT(HID_SDP_MANDATORY_MISSING); - - CASE_RETURN_TEXT(SDP_NO_RECS_MATCH); - CASE_RETURN_TEXT(SDP_CONN_FAILED); - CASE_RETURN_TEXT(SDP_CFG_FAILED); - CASE_RETURN_TEXT(SDP_GENERIC_ERROR); - CASE_RETURN_TEXT(SDP_DB_FULL); - CASE_RETURN_TEXT(SDP_CANCEL); - default: - return base::StringPrintf("UNKNOWN[%hu]", status); - } -} -const auto sdp_result_text = sdp_status_text; - -#undef CASE_RETURN_TEXT - -/* Masks for attr_value field of tSDP_DISC_ATTR */ -#define SDP_DISC_ATTR_LEN_MASK 0x0FFF -#define SDP_DISC_ATTR_TYPE(len_type) ((len_type) >> 12) -#define SDP_DISC_ATTR_LEN(len_type) ((len_type)&SDP_DISC_ATTR_LEN_MASK) - -/* Maximum number of protocol list items (list_elem in tSDP_PROTOCOL_ELEM) */ -#define SDP_MAX_LIST_ELEMS 3 - -/***************************************************************************** - * Type Definitions - ****************************************************************************/ - -/* Define a callback function for when discovery is complete. */ -typedef void(tSDP_DISC_CMPL_CB)(tSDP_RESULT result); -typedef void(tSDP_DISC_CMPL_CB2)(tSDP_RESULT result, const void* user_data); - -typedef struct { - RawAddress peer_addr; - uint16_t peer_mtu; -} tSDP_DR_OPEN; - -typedef struct { - uint8_t* p_data; - uint16_t data_len; -} tSDP_DR_DATA; - -typedef union { - tSDP_DR_OPEN open; - tSDP_DR_DATA data; -} tSDP_DATA; - -/* Define a structure to hold the discovered service information. */ -typedef struct { - union { - uint8_t u8; /* 8-bit integer */ - uint16_t u16; /* 16-bit integer */ - uint32_t u32; /* 32-bit integer */ - struct t_sdp_disc_attr* p_sub_attr; /* Addr of first sub-attr (list)*/ - uint8_t array[]; /* Variable length field */ - /* flexible array member */ - /* requiring backing store */ - /* from SDP DB */ - } v; - -} tSDP_DISC_ATVAL; - -typedef struct t_sdp_disc_attr { - struct t_sdp_disc_attr* p_next_attr; /* Addr of next linked attr */ - uint16_t attr_id; /* Attribute ID */ - uint16_t attr_len_type; /* Length and type fields */ - tSDP_DISC_ATVAL attr_value; /* Variable length entry data */ -} tSDP_DISC_ATTR; - -typedef struct t_sdp_disc_rec { - tSDP_DISC_ATTR* p_first_attr; /* First attribute of record */ - struct t_sdp_disc_rec* p_next_rec; /* Addr of next linked record */ - uint32_t time_read; /* The time the record was read */ - RawAddress remote_bd_addr; /* Remote BD address */ -} tSDP_DISC_REC; - -typedef struct { - uint32_t mem_size; /* Memory size of the DB */ - uint32_t mem_free; /* Memory still available */ - tSDP_DISC_REC* p_first_rec; /* Addr of first record in DB */ - uint16_t num_uuid_filters; /* Number of UUIds to filter */ - bluetooth::Uuid uuid_filters[SDP_MAX_UUID_FILTERS]; /* UUIDs to filter */ - uint16_t num_attr_filters; /* Number of attribute filters */ - uint16_t attr_filters[SDP_MAX_ATTR_FILTERS]; /* Attributes to filter */ - uint8_t* p_free_mem; /* Pointer to free memory */ - uint8_t* - raw_data; /* Received record from server. allocated/released by client */ - uint32_t raw_size; /* size of raw_data */ - uint32_t raw_used; /* length of raw_data used */ -} tSDP_DISCOVERY_DB; - -/* This structure is used to add protocol lists and find protocol elements */ -typedef struct { - uint16_t protocol_uuid; - uint16_t num_params; - uint16_t params[SDP_MAX_PROTOCOL_PARAMS]; -} tSDP_PROTOCOL_ELEM; - -typedef struct { - uint16_t num_elems; - tSDP_PROTOCOL_ELEM list_elem[SDP_MAX_LIST_ELEMS]; -} tSDP_PROTO_LIST_ELEM; - -/* Device Identification (DI) data structure -*/ -/* Used to set the DI record */ -typedef struct t_sdp_di_record { - uint16_t vendor; - uint16_t vendor_id_source; - uint16_t product; - uint16_t version; - bool primary_record; - char client_executable_url[SDP_MAX_ATTR_LEN]; /* optional */ - char service_description[SDP_MAX_ATTR_LEN]; /* optional */ - char documentation_url[SDP_MAX_ATTR_LEN]; /* optional */ -} tSDP_DI_RECORD; - -/* Used to get the DI record */ -typedef struct t_sdp_di_get_record { - uint16_t spec_id; - tSDP_DI_RECORD rec; -} tSDP_DI_GET_RECORD; - -/* API into the SDP layer for service discovery. */ - -/******************************************************************************* - * - * Function SDP_InitDiscoveryDb - * - * Description This function is called to initialize a discovery database. - * - * Returns true if successful, false if one or more parameters are bad - * - ******************************************************************************/ -bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len, - uint16_t num_uuid, const bluetooth::Uuid* p_uuid_list, - uint16_t num_attr, const uint16_t* p_attr_list); - -/******************************************************************************* - * - * Function SDP_CancelServiceSearch - * - * Description This function cancels an active query to an SDP server. - * - * Returns true if discovery cancelled, false if a matching activity is - * not found. - * - ******************************************************************************/ -bool SDP_CancelServiceSearch(const tSDP_DISCOVERY_DB* p_db); - -/******************************************************************************* - * - * Function SDP_ServiceSearchRequest - * - * Description This function queries an SDP server for information. - * - * Returns true if discovery started, false if failed. - * - ******************************************************************************/ -bool SDP_ServiceSearchRequest(const RawAddress& p_bd_addr, - tSDP_DISCOVERY_DB* p_db, tSDP_DISC_CMPL_CB* p_cb); - -/******************************************************************************* - * - * Function SDP_ServiceSearchAttributeRequest - * - * Description This function queries an SDP server for information. - * - * The difference between this API function and the function - * SDP_ServiceSearchRequest is that this one does a - * combined ServiceSearchAttributeRequest SDP function. - * - * Returns true if discovery started, false if failed. - * - ******************************************************************************/ -bool SDP_ServiceSearchAttributeRequest(const RawAddress& p_bd_addr, - tSDP_DISCOVERY_DB* p_db, - tSDP_DISC_CMPL_CB* p_cb); - -/******************************************************************************* - * - * Function SDP_ServiceSearchAttributeRequest2 - * - * Description This function queries an SDP server for information. - * - * The difference between this API function and the function - * SDP_ServiceSearchRequest is that this one does a - * combined ServiceSearchAttributeRequest SDP function with the - * user data piggyback - * - * Returns true if discovery started, false if failed. - * - ******************************************************************************/ -bool SDP_ServiceSearchAttributeRequest2(const RawAddress& p_bd_addr, - tSDP_DISCOVERY_DB* p_db, - tSDP_DISC_CMPL_CB2* p_cb, - const void* user_data); - -/* API of utilities to find data in the local discovery database */ - -/******************************************************************************* - * - * Function SDP_FindAttributeInRec - * - * Description This function searches an SDP discovery record for a - * specific attribute. - * - * Returns Pointer to matching attribute entry, or NULL - * - ******************************************************************************/ -tSDP_DISC_ATTR* SDP_FindAttributeInRec(const tSDP_DISC_REC* p_rec, - uint16_t attr_id); - -/******************************************************************************* - * - * Function SDP_FindServiceInDb - * - * Description This function queries an SDP database for a specific - * service. If the p_start_rec pointer is NULL, it looks from - * the beginning of the database, else it continues from the - * next record after p_start_rec. - * - * Returns Pointer to record containing service class, or NULL - * - ******************************************************************************/ -tSDP_DISC_REC* SDP_FindServiceInDb(const tSDP_DISCOVERY_DB* p_db, - uint16_t service_uuid, - tSDP_DISC_REC* p_start_rec); - -/******************************************************************************* - * - * Function SDP_FindServiceUUIDInDb - * - * Description This function queries an SDP database for a specific - * service. If the p_start_rec pointer is NULL, it looks from - * the beginning of the database, else it continues from the - * next record after p_start_rec. - * - * NOTE the only difference between this function and the previous - * function "SDP_FindServiceInDb()" is that this function takes - * a Uuid input. - * - * Returns Pointer to record containing service class, or NULL - * - ******************************************************************************/ -tSDP_DISC_REC* SDP_FindServiceUUIDInDb(const tSDP_DISCOVERY_DB* p_db, - const bluetooth::Uuid& uuid, - tSDP_DISC_REC* p_start_rec); - -/******************************************************************************* - * - * Function SDP_FindServiceUUIDInRec_128bit - * - * Description Read the 128-bit service UUID within a record, - * if there is any. - * - * Parameters: p_rec - pointer to a SDP record. - * p_uuid - output parameter to save the UUID found. - * - * Returns true if found, otherwise false. - * - ******************************************************************************/ -bool SDP_FindServiceUUIDInRec_128bit(const tSDP_DISC_REC* p_rec, - bluetooth::Uuid* p_uuid); - -/******************************************************************************* - * - * Function SDP_FindServiceInDb_128bit - * - * Description Query an SDP database for a specific service. - * If the p_start_rec pointer is NULL, look from the beginning - * of the database, else continue from the next record after - * p_start_rec. - * - * Returns Pointer to record containing service class, or NULL - * - ******************************************************************************/ -tSDP_DISC_REC* SDP_FindServiceInDb_128bit(const tSDP_DISCOVERY_DB* p_db, - tSDP_DISC_REC* p_start_rec); - -/******************************************************************************* - * - * Function SDP_FindProtocolListElemInRec - * - * Description This function looks at a specific discovery record for a - * protocol list element. - * - * Returns true if found, false if not - * If found, the passed protocol list element is filled in. - * - ******************************************************************************/ -bool SDP_FindProtocolListElemInRec(const tSDP_DISC_REC* p_rec, - uint16_t layer_uuid, - tSDP_PROTOCOL_ELEM* p_elem); - -/******************************************************************************* - * - * Function SDP_FindProfileVersionInRec - * - * Description This function looks at a specific discovery record for the - * Profile list descriptor, and pulls out the version number. - * The version number consists of an 8-bit major version and - * an 8-bit minor version. - * - * Returns true if found, false if not - * If found, the major and minor version numbers that were - * passed in are filled in. - * - ******************************************************************************/ -bool SDP_FindProfileVersionInRec(const tSDP_DISC_REC* p_rec, - uint16_t profile_uuid, uint16_t* p_version); - -/* API into SDP for local service database updates */ - -/******************************************************************************* - * - * Function SDP_CreateRecord - * - * Description This function is called to create a record in the database. - * This would be through the SDP database maintenance API. The - * record is created empty, teh application should then call - * "add_attribute" to add the record's attributes. - * - * Returns Record handle if OK, else 0. - * - ******************************************************************************/ -uint32_t SDP_CreateRecord(void); - -/******************************************************************************* - * - * Function SDP_DeleteRecord - * - * Description This function is called to add a record (or all records) - * from the database. This would be through the SDP database - * maintenance API. - * - * If a record handle of 0 is passed, all records are deleted. - * - * Returns true if succeeded, else false - * - ******************************************************************************/ -bool SDP_DeleteRecord(uint32_t handle); - -/******************************************************************************* - * - * Function SDP_AddAttribute - * - * Description This function is called to add an attribute to a record. - * This would be through the SDP database maintenance API. - * If the attribute already exists in the record, it is - * replaced with the new value. - * - * NOTE Attribute values must be passed as a Big Endian stream. - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, - uint32_t attr_len, uint8_t* p_val); - -/******************************************************************************* - * - * Function SDP_AddSequence - * - * Description This function is called to add a sequence to a record. - * This would be through the SDP database maintenance API. - * If the sequence already exists in the record, it is replaced - * with the new sequence. - * - * NOTE Element values must be passed as a Big Endian stream. - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem, - uint8_t type[], uint8_t len[], uint8_t* p_val[]); - -/******************************************************************************* - * - * Function SDP_AddUuidSequence - * - * Description This function is called to add a UUID sequence to a record. - * This would be through the SDP database maintenance API. - * If the sequence already exists in the record, it is replaced - * with the new sequence. - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids, - uint16_t* p_uuids); - -/******************************************************************************* - * - * Function SDP_AddProtocolList - * - * Description This function is called to add a protocol descriptor list to - * a record. This would be through the SDP database - * maintenance API. If the protocol list already exists in the - * record, it is replaced with the new list. - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem, - tSDP_PROTOCOL_ELEM* p_elem_list); - -/******************************************************************************* - * - * Function SDP_AddAdditionProtoLists - * - * Description This function is called to add a protocol descriptor list to - * a record. This would be through the SDP database maintenance - * API. If the protocol list already exists in the record, it - * is replaced with the new list. - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool SDP_AddAdditionProtoLists(uint32_t handle, uint16_t num_elem, - tSDP_PROTO_LIST_ELEM* p_proto_list); - -/******************************************************************************* - * - * Function SDP_AddProfileDescriptorList - * - * Description This function is called to add a profile descriptor list to - * a record. This would be through the SDP database maintenance - * API. If the version already exists in the record, it is - * replaced with the new one. - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid, - uint16_t version); - -/******************************************************************************* - * - * Function SDP_AddLanguageBaseAttrIDList - * - * Description This function is called to add a language base attr list to - * a record. This would be through the SDP database maintenance - * API. If the version already exists in the record, it is - * replaced with the new one. - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool SDP_AddLanguageBaseAttrIDList(uint32_t handle, uint16_t lang, - uint16_t char_enc, uint16_t base_id); - -/******************************************************************************* - * - * Function SDP_AddServiceClassIdList - * - * Description This function is called to add a service list to a record. - * This would be through the SDP database maintenance API. - * If the service list already exists in the record, it is - * replaced with the new list. - * - * Returns true if added OK, else false - * - ******************************************************************************/ -bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services, - uint16_t* p_service_uuids); - -/******************************************************************************* - * - * Function SDP_DeleteAttribute - * - * Description Delete an attribute from a record. - * This would be through the SDP database maintenance API. - * - * Returns true if deleted OK, else false if not found - * - ******************************************************************************/ -bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id); - -/* Device Identification APIs */ - -/******************************************************************************* - * - * Function SDP_SetLocalDiRecord - * - * Description This function adds a DI record to the local SDP database. - * - * Returns Returns SDP_SUCCESS if record added successfully, else error - * - ******************************************************************************/ -uint16_t SDP_SetLocalDiRecord(const tSDP_DI_RECORD* device_info, - uint32_t* p_handle); - -/******************************************************************************* - * - * Function SDP_DiDiscover - * - * Description This function queries a remote device for DI information. - * - * Returns SDP_SUCCESS if query started successfully, else error - * - ******************************************************************************/ -tSDP_STATUS SDP_DiDiscover(const RawAddress& remote_device, - tSDP_DISCOVERY_DB* p_db, uint32_t len, - tSDP_DISC_CMPL_CB* p_cb); - -/******************************************************************************* - * - * Function SDP_GetNumDiRecords - * - * Description Searches specified database for DI records - * - * Returns number of DI records found - * - ******************************************************************************/ -uint8_t SDP_GetNumDiRecords(const tSDP_DISCOVERY_DB* p_db); - -/******************************************************************************* - * - * Function SDP_GetDiRecord - * - * Description This function retrieves a remote device's DI record from - * the specified database. - * - * Returns SDP_SUCCESS if record retrieved, else error - * - ******************************************************************************/ -uint16_t SDP_GetDiRecord(uint8_t getRecordIndex, - tSDP_DI_GET_RECORD* device_info, - const tSDP_DISCOVERY_DB* p_db); - -/******************************************************************************* - * - * Function SDP_SetTraceLevel - * - * Description This function sets the trace level for SDP. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t SDP_SetTraceLevel(uint8_t new_level); - -/******************************************************************************* - * - * Function SDP_FindServiceUUIDInRec - * - * Description Read the service UUID within a record, - * if there is any. - * - * Parameters: p_rec - pointer to a SDP record. - * p_uuid - pointer to a UUID - * - * Returns true if found, otherwise false. - * - ******************************************************************************/ -bool SDP_FindServiceUUIDInRec(const tSDP_DISC_REC* p_rec, - bluetooth::Uuid* p_uuid); - namespace bluetooth { namespace legacy { namespace stack { @@ -1099,21 +493,6 @@ struct tSdpApi { ******************************************************************************/ bool (*SDP_AddServiceClassIdList)(uint32_t handle, uint16_t num_services, uint16_t* p_service_uuids); - - /******************************************************************************* - - Function SDP_DeleteAttribute - - Description Delete an attribute from a record. - This would be through the SDP database maintenance API. - - Parameters: handle - (input) Handle to add - attr_id - (input) attribute id to delete - - Returns true if deleted OK, else false if not found - - ******************************************************************************/ - bool (*SDP_DeleteAttribute)(uint32_t handle, uint16_t attr_id); } handle; struct { @@ -1198,8 +577,9 @@ struct tSdpApi { const struct tSdpApi* get_legacy_stack_sdp_api(); struct tLegacyStackSdbCallback { - void(tSDP_DISC_CMPL_CB)(tSDP_RESULT result); - void(tSDP_DISC_CMPL_CB2)(tSDP_RESULT result, const void* user_data); + void(tSDP_DISC_CMPL_CB)(const RawAddress& bd_addr, tSDP_RESULT result); + void(tSDP_DISC_CMPL_CB2)(const RawAddress& bd_addr, tSDP_RESULT result, + const void* user_data); }; } // namespace sdp diff --git a/system/embdrv/sbc/encoder/include/sbc_types.h b/system/stack/include/sdp_callback.h similarity index 68% rename from system/embdrv/sbc/encoder/include/sbc_types.h rename to system/stack/include/sdp_callback.h index 1877d032b4e764abf4e391ae2aca08f905a4e9d1..5ebd2789afe44594b029face20389e9064a334cc 100644 --- a/system/embdrv/sbc/encoder/include/sbc_types.h +++ b/system/stack/include/sdp_callback.h @@ -16,19 +16,12 @@ * ******************************************************************************/ -/****************************************************************************** - * - * Data type declarations. - * - ******************************************************************************/ - -#ifndef SBC_TYPES_H -#define SBC_TYPES_H - -#include - -#include "bt_target.h" +#pragma once -#define abs32(x) (((x) >= 0) ? (x) : (-(x))) +#include "stack/include/sdp_status.h" +#include "types/raw_address.h" -#endif +/* Define a callback function for when discovery is complete. */ +typedef void(tSDP_DISC_CMPL_CB)(const RawAddress& bd_addr, tSDP_RESULT result); +typedef void(tSDP_DISC_CMPL_CB2)(const RawAddress& bd_addr, tSDP_RESULT result, + const void* user_data); diff --git a/system/btif/src/btif_debug_btsnoop.cc b/system/stack/include/sdp_device_id.h similarity index 54% rename from system/btif/src/btif_debug_btsnoop.cc rename to system/stack/include/sdp_device_id.h index 72f0eda97c4e63ea5a33353e5b99578c114a8dfa..da1a673f33d1f108d3553fd8a201dd99222adde3 100644 --- a/system/btif/src/btif_debug_btsnoop.cc +++ b/system/stack/include/sdp_device_id.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright 2015 Google Inc. + * Copyright 1999-2012 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,28 @@ * ******************************************************************************/ -#include +#pragma once -#include -#include -#include +#include #include "internal_include/bt_target.h" -#include "osi/include/properties.h" -#include "osi/include/ringbuffer.h" -#define REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type) ((type) >> 8) +/* Device Identification (DI) data structure + */ +/* Used to set the DI record */ +typedef struct t_sdp_di_record { + uint16_t vendor; + uint16_t vendor_id_source; + uint16_t product; + uint16_t version; + bool primary_record; + char client_executable_url[SDP_MAX_ATTR_LEN]; /* optional */ + char service_description[SDP_MAX_ATTR_LEN]; /* optional */ + char documentation_url[SDP_MAX_ATTR_LEN]; /* optional */ +} tSDP_DI_RECORD; -// Total btsnoop memory log buffer size -#ifndef BTSNOOP_MEM_BUFFER_SIZE -#endif - -#ifndef __ANDROID__ -#else -#endif +/* Used to get the DI record */ +typedef struct t_sdp_di_get_record { + uint16_t spec_id; + tSDP_DI_RECORD rec; +} tSDP_DI_GET_RECORD; diff --git a/system/stack/include/sdp_status.h b/system/stack/include/sdp_status.h new file mode 100644 index 0000000000000000000000000000000000000000..cfb81f8efad95a0a242cf7efccb437955b6dc299 --- /dev/null +++ b/system/stack/include/sdp_status.h @@ -0,0 +1,87 @@ +/****************************************************************************** + * + * Copyright 1999-2012 Broadcom Corporation + * + * 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 + +#include + +#include "macros.h" + +/***************************************************************************** + * Constants + ****************************************************************************/ + +/* Success code and error codes */ +typedef enum : uint16_t { + SDP_SUCCESS = 0x0000, + SDP_INVALID_VERSION = 0x0001, + SDP_INVALID_SERV_REC_HDL = 0x0002, + SDP_INVALID_REQ_SYNTAX = 0x0003, + SDP_INVALID_PDU_SIZE = 0x0004, + SDP_INVALID_CONT_STATE = 0x0005, + SDP_NO_RESOURCES = 0x0006, + SDP_DI_REG_FAILED = 0x0007, + SDP_DI_DISC_FAILED = 0x0008, + SDP_NO_DI_RECORD_FOUND = 0x0009, + SDP_ERR_ATTR_NOT_PRESENT = 0x000A, + SDP_ILLEGAL_PARAMETER = 0x000B, + + HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER + 1), + HID_SDP_MANDATORY_MISSING, + + SDP_NO_RECS_MATCH = 0xFFF0, + SDP_CONN_FAILED = 0xFFF1, + SDP_CFG_FAILED = 0xFFF2, + SDP_GENERIC_ERROR = 0xFFF3, + SDP_DB_FULL = 0xFFF4, + SDP_CANCEL = 0xFFF8, +} tSDP_STATUS; +using tSDP_RESULT = tSDP_STATUS; +using tSDP_REASON = tSDP_STATUS; + +inline std::string sdp_status_text(const tSDP_STATUS& status) { + switch (status) { + CASE_RETURN_TEXT(SDP_SUCCESS); + CASE_RETURN_TEXT(SDP_INVALID_VERSION); + CASE_RETURN_TEXT(SDP_INVALID_SERV_REC_HDL); + CASE_RETURN_TEXT(SDP_INVALID_REQ_SYNTAX); + CASE_RETURN_TEXT(SDP_INVALID_PDU_SIZE); + CASE_RETURN_TEXT(SDP_INVALID_CONT_STATE); + CASE_RETURN_TEXT(SDP_NO_RESOURCES); + CASE_RETURN_TEXT(SDP_DI_REG_FAILED); + CASE_RETURN_TEXT(SDP_DI_DISC_FAILED); + CASE_RETURN_TEXT(SDP_NO_DI_RECORD_FOUND); + CASE_RETURN_TEXT(SDP_ERR_ATTR_NOT_PRESENT); + CASE_RETURN_TEXT(SDP_ILLEGAL_PARAMETER); + + CASE_RETURN_TEXT(HID_SDP_NO_SERV_UUID); + CASE_RETURN_TEXT(HID_SDP_MANDATORY_MISSING); + + CASE_RETURN_TEXT(SDP_NO_RECS_MATCH); + CASE_RETURN_TEXT(SDP_CONN_FAILED); + CASE_RETURN_TEXT(SDP_CFG_FAILED); + CASE_RETURN_TEXT(SDP_GENERIC_ERROR); + CASE_RETURN_TEXT(SDP_DB_FULL); + CASE_RETURN_TEXT(SDP_CANCEL); + default: + return base::StringPrintf("UNKNOWN[%hu]", status); + } +} +const auto sdp_result_text = sdp_status_text; diff --git a/system/stack/include/sdpdefs.h b/system/stack/include/sdpdefs.h index dd42d407f79db36b68e206fc4bc2675840dd87f3..cf78f56371d4f24a9db016f39f2de29ea94dfa1e 100644 --- a/system/stack/include/sdpdefs.h +++ b/system/stack/include/sdpdefs.h @@ -99,118 +99,6 @@ #define ATTR_ID_HID_SSR_HOST_MAX_LAT 0x020F #define ATTR_ID_HID_SSR_HOST_MIN_TOUT 0x0210 -/* Define common 16-bit protocol UUIDs -*/ -#define UUID_PROTOCOL_RFCOMM 0x0003 -#define UUID_PROTOCOL_OBEX 0x0008 -#define UUID_PROTOCOL_BNEP 0x000F -#define UUID_PROTOCOL_HIDP 0x0011 -#define UUID_PROTOCOL_AVCTP 0x0017 -#define UUID_PROTOCOL_AVDTP 0x0019 -#define UUID_PROTOCOL_L2CAP 0x0100 -#define UUID_PROTOCOL_ATT 0x0007 - -/* Define common 16-bit service class UUIDs -*/ -#define UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER 0X1000 -#define UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR 0X1001 -#define UUID_SERVCLASS_PUBLIC_BROWSE_GROUP 0X1002 -#define UUID_SERVCLASS_SERIAL_PORT 0X1101 -#define UUID_SERVCLASS_LAN_ACCESS_USING_PPP 0X1102 -#define UUID_SERVCLASS_DIALUP_NETWORKING 0X1103 -#define UUID_SERVCLASS_IRMC_SYNC 0X1104 -#define UUID_SERVCLASS_OBEX_OBJECT_PUSH 0X1105 -#define UUID_SERVCLASS_OBEX_FILE_TRANSFER 0X1106 -#define UUID_SERVCLASS_IRMC_SYNC_COMMAND 0X1107 -#define UUID_SERVCLASS_HEADSET 0X1108 -#define UUID_SERVCLASS_CORDLESS_TELEPHONY 0X1109 -#define UUID_SERVCLASS_AUDIO_SOURCE 0X110A -#define UUID_SERVCLASS_AUDIO_SINK 0X110B -/* Audio/Video Control profile */ -#define UUID_SERVCLASS_AV_REM_CTRL_TARGET 0X110C -/* Advanced Audio Distribution profile */ -#define UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION 0X110D -/* Audio/Video Control profile */ -#define UUID_SERVCLASS_AV_REMOTE_CONTROL 0X110E -/* Audio/Video Control profile */ -#define UUID_SERVCLASS_AV_REM_CTRL_CONTROL 0X110F -#define UUID_SERVCLASS_INTERCOM 0X1110 -#define UUID_SERVCLASS_FAX 0X1111 -#define UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY 0X1112 -#define UUID_SERVCLASS_WAP 0X1113 -#define UUID_SERVCLASS_WAP_CLIENT 0X1114 -#define UUID_SERVCLASS_PANU 0X1115 /* PAN profile */ -#define UUID_SERVCLASS_NAP 0X1116 /* PAN profile */ -#define UUID_SERVCLASS_GN 0X1117 /* PAN profile */ -#define UUID_SERVCLASS_DIRECT_PRINTING 0X1118 /* BPP profile */ -#define UUID_SERVCLASS_REFERENCE_PRINTING 0X1119 /* BPP profile */ -#define UUID_SERVCLASS_IMAGING 0X111A /* Imaging profile */ -#define UUID_SERVCLASS_IMAGING_RESPONDER 0X111B /* Imaging profile */ -#define UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE 0X111C /* Imaging profile */ -#define UUID_SERVCLASS_IMAGING_REF_OBJECTS 0X111D /* Imaging profile */ -#define UUID_SERVCLASS_HF_HANDSFREE 0X111E /* Handsfree profile */ -#define UUID_SERVCLASS_AG_HANDSFREE 0X111F /* Handsfree profile */ -#define UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE 0X1120 /* BPP profile */ -#define UUID_SERVCLASS_REFLECTED_UI 0X1121 /* BPP profile */ -#define UUID_SERVCLASS_BASIC_PRINTING 0X1122 /* BPP profile */ -#define UUID_SERVCLASS_PRINTING_STATUS 0X1123 /* BPP profile */ -#define UUID_SERVCLASS_HUMAN_INTERFACE 0X1124 /* HID profile */ -#define UUID_SERVCLASS_CABLE_REPLACEMENT 0X1125 /* HCRP profile */ -#define UUID_SERVCLASS_HCRP_PRINT 0X1126 /* HCRP profile */ -#define UUID_SERVCLASS_HCRP_SCAN 0X1127 /* HCRP profile */ -/* CAPI Message Transport Protocol*/ -#define UUID_SERVCLASS_COMMON_ISDN_ACCESS 0X1128 -/* Video Conferencing profile */ -#define UUID_SERVCLASS_VIDEO_CONFERENCING_GW 0X1129 -/* Unrestricted Digital Information profile */ -#define UUID_SERVCLASS_UDI_MT 0X112A -/* Unrestricted Digital Information profile */ -#define UUID_SERVCLASS_UDI_TA 0X112B -#define UUID_SERVCLASS_VCP 0X112C /* Video Conferencing profile */ -#define UUID_SERVCLASS_SAP 0X112D /* SIM Access profile */ -#define UUID_SERVCLASS_PBAP_PCE 0X112E /* Phonebook Access - PCE */ -#define UUID_SERVCLASS_PBAP_PSE 0X112F /* Phonebook Access - PSE */ -#define UUID_SERVCLASS_PHONE_ACCESS 0x1130 -#define UUID_SERVCLASS_HEADSET_HS 0x1131 /* Headset - HS, from HSP v1.2 */ -#define UUID_SERVCLASS_MPS_PROFILE \ - 0x113A /* Multi-Profile Specification - Profile */ -#define UUID_SERVCLASS_MPS_SC \ - 0x113B /* Multi-Profile Specification - Service Class */ -#define UUID_SERVCLASS_PNP_INFORMATION 0X1200 /* Device Identification */ -#define UUID_SERVCLASS_GENERIC_NETWORKING 0X1201 -#define UUID_SERVCLASS_GENERIC_FILETRANSFER 0X1202 -#define UUID_SERVCLASS_GENERIC_AUDIO 0X1203 -#define UUID_SERVCLASS_GENERIC_TELEPHONY 0X1204 -#define UUID_SERVCLASS_UPNP_SERVICE 0X1205 /* UPNP_Service [ESDP] */ -#define UUID_SERVCLASS_UPNP_IP_SERVICE 0X1206 /* UPNP_IP_Service [ESDP] */ -#define UUID_SERVCLASS_ESDP_UPNP_IP_PAN 0X1300 /* UPNP_IP_PAN [ESDP] */ -#define UUID_SERVCLASS_ESDP_UPNP_IP_LAP 0X1301 /* UPNP_IP_LAP [ESDP] */ -#define UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP 0X1302 /* UPNP_L2CAP [ESDP] */ - -/* Video Distribution Profile (VDP) */ -#define UUID_SERVCLASS_VIDEO_SOURCE 0X1303 -#define UUID_SERVCLASS_VIDEO_SINK 0X1304 -#define UUID_SERVCLASS_VIDEO_DISTRIBUTION 0X1305 - -#define UUID_SERVCLASS_HDP_PROFILE 0X1400 /* Health Device profile (HDP) */ -#define UUID_SERVCLASS_HDP_SOURCE 0X1401 /* Health Device profile (HDP) */ -#define UUID_SERVCLASS_HDP_SINK 0X1402 /* Health Device profile (HDP) */ -#define UUID_SERVCLASS_MAP_PROFILE 0X1134 /* MAP profile */ -#define UUID_SERVCLASS_MESSAGE_ACCESS 0X1132 /* Message Access Service */ -#define UUID_SERVCLASS_MESSAGE_NOTIFICATION \ - 0X1133 /* Message Notification Service */ - -#define UUID_SERVCLASS_GAP_SERVER 0x1800 -#define UUID_SERVCLASS_GATT_SERVER 0x1801 -#define UUID_SERVCLASS_DEVICE_INFO 0x180A /* device info service */ -#define UUID_SERVCLASS_LE_HID 0x1812 /* HID over LE */ -#define UUID_SERVCLASS_SCAN_PARAM 0x1813 /* Scan Parameter service */ - -#define UUID_SERVCLASS_GMCS_SERVER 0x1849 /* Generic Media Control Service */ -#define UUID_SERVCLASS_GTBS_SERVER 0x184c /* Generic Telephony Bearer Service*/ -#define UUID_SERVCLASS_TMAS_SERVER \ - 0x1855 /* Telephone and Media Audio Service */ - #define UUID_CODEC_CVSD 0x0001 /* CVSD */ #define UUID_CODEC_MSBC 0x0002 /* mSBC */ #define UUID_CODEC_LC3 0x0003 /* LC3 */ diff --git a/system/stack/include/sec_hci_link_interface.h b/system/stack/include/sec_hci_link_interface.h index dce3c479fd8afaf02ccaf25e6d1e12bc456a1990..cc85265630f0d33e43d23a70e7aa03f2da477b99 100644 --- a/system/stack/include/sec_hci_link_interface.h +++ b/system/stack/include/sec_hci_link_interface.h @@ -19,31 +19,33 @@ #include -#include "stack/include/bt_types.h" -#include "stack/include/btm_api_types.h" +#include "stack/include/btm_sec_api_types.h" #include "types/raw_address.h" // This header contains functions for HCIF-Security Management to invoke // -void btm_create_conn_cancel_complete(const uint8_t* p, uint16_t evt_len); -void btm_io_capabilities_req(const RawAddress& p); -void btm_io_capabilities_rsp(const uint8_t* p); -void btm_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p); -void btm_read_inq_tx_power_complete(uint8_t* p); -void btm_read_local_oob_complete(uint8_t* p, uint16_t evt_len); -void btm_rem_oob_req(const uint8_t* p); +void btm_create_conn_cancel_complete(uint8_t status, const RawAddress bd_addr); +void btm_io_capabilities_req(RawAddress p); +void btm_io_capabilities_rsp(const tBTM_SP_IO_RSP evt_data); +void btm_proc_sp_req_evt(tBTM_SP_EVT event, const RawAddress bda, + uint32_t value); +void btm_read_local_oob_complete(const tBTM_SP_LOC_OOB evt_data); +void btm_rem_oob_req(const RawAddress bd_addr); void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status); void btm_sec_disconnected(uint16_t handle, tHCI_STATUS reason, std::string); void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, uint8_t encr_enable); +void btm_sec_encryption_key_refresh_complete(uint16_t handle, + tHCI_STATUS status); void btm_sec_link_key_notification(const RawAddress& p_bda, const Octet16& link_key, uint8_t key_type); -void btm_sec_link_key_request(const uint8_t* p_event); -void btm_sec_pin_code_request(const uint8_t* p_event); -void btm_sec_rmt_host_support_feat_evt(const uint8_t* p); +void btm_sec_link_key_request(const RawAddress bda); +void btm_sec_pin_code_request(const RawAddress p_bda); +void btm_sec_rmt_host_support_feat_evt(const RawAddress bd_addr, + uint8_t features_0); void btm_sec_rmt_name_request_complete(const RawAddress* bd_addr, const uint8_t* bd_name, tHCI_STATUS status); void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset); -void btm_simple_pair_complete(const uint8_t* p); +void btm_simple_pair_complete(const RawAddress bd_addr, uint8_t status); diff --git a/system/stack/include/security_client_callbacks.h b/system/stack/include/security_client_callbacks.h index d6070cd050f60b463a1c38b3c65051916d810b59..efffe164bbdc93e1e21ca9df2805e89e9fbdcfeb 100644 --- a/system/stack/include/security_client_callbacks.h +++ b/system/stack/include/security_client_callbacks.h @@ -18,9 +18,11 @@ #include +#include "stack/include/bt_dev_class.h" +#include "stack/include/bt_device_type.h" +#include "stack/include/bt_name.h" #include "stack/include/bt_octets.h" -#include "stack/include/btm_api_types.h" -#include "stack/include/btm_ble_api_types.h" +#include "stack/include/btm_ble_sec_api_types.h" #include "stack/include/hci_error_code.h" #include "types/raw_address.h" @@ -73,6 +75,11 @@ typedef void(tBTM_AUTH_COMPLETE_CALLBACK)(const RawAddress& bd_addr, tBTM_BD_NAME bd_name, tHCI_REASON reason); +/* Request SIRK verification for found member. Parameters are + * BD Address of remote + */ +typedef uint8_t(tBTM_SIRK_VERIFICATION_CALLBACK)(const RawAddress& bd_addr); + struct tBTM_APPL_INFO { tBTM_PIN_CALLBACK* p_pin_callback{nullptr}; tBTM_LINK_KEY_CALLBACK* p_link_key_callback{nullptr}; @@ -81,4 +88,50 @@ struct tBTM_APPL_INFO { tBTM_SP_CALLBACK* p_sp_callback{nullptr}; tBTM_LE_CALLBACK* p_le_callback{nullptr}; tBTM_LE_KEY_CALLBACK* p_le_key_callback{nullptr}; + tBTM_SIRK_VERIFICATION_CALLBACK* p_sirk_verification_callback{nullptr}; }; + +typedef struct { + void (*BTM_Sec_Init)(); + void (*BTM_Sec_Free)(); + bool (*BTM_SecAddDevice)(const RawAddress& bd_addr, DEV_CLASS dev_class, + const BD_NAME& bd_name, uint8_t* features, + LinkKey* link_key, uint8_t key_type, + uint8_t pin_length); + bool (*BTM_SecAddRmtNameNotifyCallback)(tBTM_RMT_NAME_CALLBACK* p_callback); + bool (*BTM_SecDeleteDevice)(const RawAddress& bd_addr); + bool (*BTM_SecRegister)(const tBTM_APPL_INFO* p_cb_info); + const char* (*BTM_SecReadDevName)(const RawAddress& bd_addr); + tBTM_STATUS (*BTM_SecBond)(const RawAddress& bd_addr, + tBLE_ADDR_TYPE addr_type, tBT_TRANSPORT transport, + tBT_DEVICE_TYPE device_type); + tBTM_STATUS (*BTM_SecBondCancel)(const RawAddress& bd_addr); + void (*BTM_SecAddBleKey)(const RawAddress& bd_addr, + tBTM_LE_KEY_VALUE* p_le_key, + tBTM_LE_KEY_TYPE key_type); + void (*BTM_SecAddBleDevice)(const RawAddress& bd_addr, + tBT_DEVICE_TYPE dev_type, + tBLE_ADDR_TYPE addr_type); + void (*BTM_SecClearSecurityFlags)(const RawAddress& bd_addr); + uint8_t (*BTM_SecClrService)(uint8_t service_id); + uint8_t (*BTM_SecClrServiceByPsm)(uint16_t psm); + void (*BTM_RemoteOobDataReply)(tBTM_STATUS res, const RawAddress& bd_addr, + const Octet16& c, const Octet16& r); + void (*BTM_PINCodeReply)(const RawAddress& bd_addr, tBTM_STATUS res, + uint8_t pin_len, uint8_t* p_pin); + void (*BTM_ConfirmReqReply)(tBTM_STATUS res, const RawAddress& bd_addr); + bool (*BTM_SecDeleteRmtNameNotifyCallback)( + tBTM_RMT_NAME_CALLBACK* p_callback); + tBTM_STATUS (*BTM_SetEncryption)(const RawAddress& bd_addr, + tBT_TRANSPORT transport, + tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data, tBTM_BLE_SEC_ACT sec_act); + bool (*BTM_IsEncrypted)(const RawAddress& bd_addr, tBT_TRANSPORT transport); + bool (*BTM_SecIsSecurityPending)(const RawAddress& bd_addr); + bool (*BTM_IsLinkKeyKnown)(const RawAddress& bd_addr, + tBT_TRANSPORT transport); + void (*BTM_BleSirkConfirmDeviceReply)(const RawAddress& bd_addr, uint8_t res); + uint8_t (*BTM_GetSecurityMode)(); +} SecurityClientInterface; + +const SecurityClientInterface& get_security_client_interface(); diff --git a/system/stack/include/smp_api.h b/system/stack/include/smp_api.h index 67b488d24da20a9d09616713958bc45618cf0456..5d0b8101a8082c5f9fac5b796efb33c68bdd1b55 100644 --- a/system/stack/include/smp_api.h +++ b/system/stack/include/smp_api.h @@ -26,9 +26,8 @@ #include -#include "bt_target.h" #include "smp_api_types.h" -#include "types/bt_transport.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" /***************************************************************************** @@ -45,19 +44,7 @@ * Returns void * ******************************************************************************/ -void SMP_Init(void); - -/******************************************************************************* - * - * Function SMP_SetTraceLevel - * - * Description This function sets the trace level for SMP. If called with - * a value of 0xFF, it simply returns the current trace level. - * - * Returns The new or current trace level - * - ******************************************************************************/ -uint8_t SMP_SetTraceLevel(uint8_t new_level); +void SMP_Init(uint8_t init_security_mode); /******************************************************************************* * @@ -200,6 +187,20 @@ bool SMP_CrLocScOobData(); ******************************************************************************/ void SMP_ClearLocScOobData(); +/******************************************************************************* + * + * Function SMP_SirkConfirmDeviceReply + * + * Description This function is called after Security Manager submitted + * verification of device with CSIP. + * + * Parameters: bd_addr - Address of the device with which verification + * was requested + * res - comparison result SMP_SUCCESS if success + * + ******************************************************************************/ +void SMP_SirkConfirmDeviceReply(const RawAddress& bd_addr, uint8_t res); + // Called when LTK request is received from controller. bool smp_proc_ltk_request(const RawAddress& bda); diff --git a/system/stack/include/smp_api_types.h b/system/stack/include/smp_api_types.h index 12b64f35c997f3f201a36969dda375f3b020c26d..de56be94be82d6af1f334a638a7a4aa4bc6dc845 100644 --- a/system/stack/include/smp_api_types.h +++ b/system/stack/include/smp_api_types.h @@ -22,87 +22,65 @@ #include #include +#include -#include "bt_target.h" // Must be first to define build configuration +#include "macros.h" #include "stack/include/bt_octets.h" #include "stack/include/btm_status.h" #include "stack/include/smp_status.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" -/* SMP command code */ -typedef enum : uint8_t { - SMP_OPCODE_PAIRING_REQ = 0x01, - SMP_OPCODE_PAIRING_RSP = 0x02, - SMP_OPCODE_CONFIRM = 0x03, - SMP_OPCODE_RAND = 0x04, - SMP_OPCODE_PAIRING_FAILED = 0x05, - SMP_OPCODE_ENCRYPT_INFO = 0x06, - SMP_OPCODE_CENTRAL_ID = 0x07, - SMP_OPCODE_IDENTITY_INFO = 0x08, - SMP_OPCODE_ID_ADDR = 0x09, - SMP_OPCODE_SIGN_INFO = 0x0A, - SMP_OPCODE_SEC_REQ = 0x0B, - SMP_OPCODE_PAIR_PUBLIC_KEY = 0x0C, - SMP_OPCODE_PAIR_DHKEY_CHECK = 0x0D, - SMP_OPCODE_PAIR_KEYPR_NOTIF = 0x0E, - SMP_OPCODE_MAX = SMP_OPCODE_PAIR_KEYPR_NOTIF, - SMP_OPCODE_MIN = SMP_OPCODE_PAIRING_REQ, - // NOTE: For some reason this is outside the MAX/MIN values - SMP_OPCODE_PAIR_COMMITM = 0x0F, -} tSMP_OPCODE; - -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - -inline std::string smp_opcode_text(const tSMP_OPCODE& opcode) { - switch (opcode) { - CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_REQ); - CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_RSP); - CASE_RETURN_TEXT(SMP_OPCODE_CONFIRM); - CASE_RETURN_TEXT(SMP_OPCODE_RAND); - CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_FAILED); - CASE_RETURN_TEXT(SMP_OPCODE_ENCRYPT_INFO); - CASE_RETURN_TEXT(SMP_OPCODE_CENTRAL_ID); - CASE_RETURN_TEXT(SMP_OPCODE_IDENTITY_INFO); - CASE_RETURN_TEXT(SMP_OPCODE_ID_ADDR); - CASE_RETURN_TEXT(SMP_OPCODE_SIGN_INFO); - CASE_RETURN_TEXT(SMP_OPCODE_SEC_REQ); - CASE_RETURN_TEXT(SMP_OPCODE_PAIR_PUBLIC_KEY); - CASE_RETURN_TEXT(SMP_OPCODE_PAIR_DHKEY_CHECK); - CASE_RETURN_TEXT(SMP_OPCODE_PAIR_KEYPR_NOTIF); - CASE_RETURN_TEXT(SMP_OPCODE_PAIR_COMMITM); - default: - return base::StringPrintf("UNKNOWN[%hhu]", opcode); - } -} -#undef CASE_RETURN_TEXT - /* SMP event type */ typedef enum : uint8_t { - SMP_EVT_NONE = 0, /* Default no event */ - SMP_IO_CAP_REQ_EVT = 1, /* IO capability request event */ - SMP_SEC_REQUEST_EVT = 2, /* SMP pairing request */ - SMP_PASSKEY_NOTIF_EVT = 3, /* passkey notification event */ - SMP_PASSKEY_REQ_EVT = 4, /* passkey request event */ - SMP_OOB_REQ_EVT = 5, /* OOB request event */ - SMP_NC_REQ_EVT = 6, /* Numeric Comparison request event */ - SMP_COMPLT_EVT = 7, /* SMP complete event */ - SMP_PEER_KEYPR_NOT_EVT = 8, /* Peer keypress notification */ + SMP_EVT_NONE, /* Default no event */ + SMP_IO_CAP_REQ_EVT, /* IO capability request event */ + SMP_SEC_REQUEST_EVT, /* SMP pairing request */ + SMP_PASSKEY_NOTIF_EVT, /* passkey notification event */ + SMP_PASSKEY_REQ_EVT, /* passkey request event */ + SMP_OOB_REQ_EVT, /* OOB request event */ + SMP_NC_REQ_EVT, /* Numeric Comparison request event */ + SMP_COMPLT_EVT, /* SMP complete event */ + SMP_PEER_KEYPR_NOT_EVT, /* Peer keypress notification */ /* SC OOB request event (both local and peer OOB data can be expected in * response) */ - SMP_SC_OOB_REQ_EVT = 9, - /* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */ - SMP_SC_LOC_OOB_DATA_UP_EVT = 10, - SMP_UNUSED11 = 11, - SMP_BR_KEYS_REQ_EVT = 12, /* SMP over BR keys request event */ - SMP_UNUSED13 = 13, - SMP_CONSENT_REQ_EVT = 14, /* Consent request event */ - SMP_LE_ADDR_ASSOC_EVT = 15, /* Identity address association event */ + SMP_SC_OOB_REQ_EVT, + /* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) + */ + SMP_SC_LOC_OOB_DATA_UP_EVT, + SMP_UNUSED11, + SMP_BR_KEYS_REQ_EVT, /* SMP over BR keys request event */ + SMP_UNUSED13, + SMP_CONSENT_REQ_EVT, /* Consent request event */ + SMP_LE_ADDR_ASSOC_EVT, /* Identity address association event */ + SMP_SIRK_VERIFICATION_REQ_EVT, /* SIRK verification request event */ } tSMP_EVT; +inline std::string smp_evt_to_text(const tSMP_EVT evt) { + switch (evt) { + CASE_RETURN_TEXT(SMP_EVT_NONE); + CASE_RETURN_TEXT(SMP_IO_CAP_REQ_EVT); + CASE_RETURN_TEXT(SMP_SEC_REQUEST_EVT); + CASE_RETURN_TEXT(SMP_PASSKEY_NOTIF_EVT); + CASE_RETURN_TEXT(SMP_PASSKEY_REQ_EVT); + CASE_RETURN_TEXT(SMP_OOB_REQ_EVT); + CASE_RETURN_TEXT(SMP_NC_REQ_EVT); + CASE_RETURN_TEXT(SMP_COMPLT_EVT); + CASE_RETURN_TEXT(SMP_PEER_KEYPR_NOT_EVT); + CASE_RETURN_TEXT(SMP_SC_OOB_REQ_EVT); + CASE_RETURN_TEXT(SMP_SC_LOC_OOB_DATA_UP_EVT); + CASE_RETURN_TEXT(SMP_UNUSED11); + CASE_RETURN_TEXT(SMP_BR_KEYS_REQ_EVT); + CASE_RETURN_TEXT(SMP_UNUSED13); + CASE_RETURN_TEXT(SMP_CONSENT_REQ_EVT); + CASE_RETURN_TEXT(SMP_LE_ADDR_ASSOC_EVT); + CASE_RETURN_TEXT(SMP_SIRK_VERIFICATION_REQ_EVT); + default: + return "UNKNOWN SMP EVENT"; + } +} + /* Device IO capability */ #define SMP_IO_CAP_IO BTM_IO_CAP_IO /* DisplayYesNo */ #define SMP_IO_CAP_KBDISP BTM_IO_CAP_KBDISP /* Keyboard Display */ @@ -243,5 +221,8 @@ typedef struct { * events occur.*/ typedef tBTM_STATUS(tSMP_CALLBACK)(tSMP_EVT event, const RawAddress& bd_addr, const tSMP_EVT_DATA* p_data); +/* Security Manager SIRK verification event - Called by the stack when Security + * Manager requires verification from CSIP.*/ +typedef tBTM_STATUS(tSMP_SIRK_CALLBACK)(const RawAddress& bd_addr); #endif // SMP_API_TYPES_H diff --git a/system/stack/include/smp_status.h b/system/stack/include/smp_status.h index 10c6e59483f3d7ca1e5f396e6c7fc6075cb5bfc0..821dd0e18440782f0818b5e55a79f0925ea72ffd 100644 --- a/system/stack/include/smp_status.h +++ b/system/stack/include/smp_status.h @@ -22,6 +22,8 @@ #include +#include "macros.h" + /* pairing failure reason code */ typedef enum : uint8_t { SMP_SUCCESS = 0, @@ -55,15 +57,11 @@ typedef enum : uint8_t { /* Unspecified failure reason */ SMP_FAIL = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0A), /* 0x18 */ - SMP_CONN_TOUT = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B), /* 0x19 */ + SMP_CONN_TOUT = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B), /* 0x19 */ + SMP_SIRK_DEVICE_INVALID = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0C), /* 0x1a */ + SMP_USER_CANCELLED = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0D), /* 0x1b */ } tSMP_STATUS; -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string smp_status_text(const tSMP_STATUS& status) { switch (status) { CASE_RETURN_TEXT(SMP_SUCCESS); @@ -89,8 +87,9 @@ inline std::string smp_status_text(const tSMP_STATUS& status) { CASE_RETURN_TEXT(SMP_RSP_TIMEOUT); CASE_RETURN_TEXT(SMP_FAIL); CASE_RETURN_TEXT(SMP_CONN_TOUT); + CASE_RETURN_TEXT(SMP_SIRK_DEVICE_INVALID); + CASE_RETURN_TEXT(SMP_USER_CANCELLED); default: return base::StringPrintf("UNKNOWN[%hhu]", status); } } -#undef CASE_RETURN_TEXT diff --git a/system/stack/include/stack_metrics_logging.h b/system/stack/include/stack_metrics_logging.h index aab41328672b0dfe059e8d85f50e187e27b5e078..b8b8179f7c2cd3b5c7aa9d06dbaac0b8e89d93e4 100644 --- a/system/stack/include/stack_metrics_logging.h +++ b/system/stack/include/stack_metrics_logging.h @@ -56,4 +56,8 @@ void log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum key, void log_hfp_audio_packet_loss_stats(const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio); + double packet_loss_ratio, + uint16_t codec_type); + +void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, + int num_requests, int codec_type); diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc index 0e08fb543f5b0fbf6419425a52aafaedb8efb7a4..1c90cc2b26f706409778af9df0fb21006695432f 100644 --- a/system/stack/l2cap/l2c_api.cc +++ b/system/stack/l2cap/l2c_api.cc @@ -24,28 +24,30 @@ #define LOG_TAG "bt_l2cap" -#include "main/shim/l2c_api.h" +#include "stack/include/l2c_api.h" +#include #include #include #include #include +#include "common/init_flags.h" #include "device/include/controller.h" // TODO Remove -#include "gd/common/init_flags.h" #include "gd/hal/snoop_logger.h" #include "gd/os/system_properties.h" -#include "gd/os/metrics.h" -#include "hci/include/btsnoop.h" -#include "main/shim/shim.h" -#include "main/shim/metrics_api.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" +#include "main/shim/entry.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btu.h" // do_in_main_thread +#include "stack/include/bt_psm_types.h" +#include "stack/include/btm_api.h" #include "stack/include/l2c_api.h" +#include "stack/include/main_thread.h" #include "stack/l2cap/l2c_int.h" #include "types/raw_address.h" @@ -114,12 +116,6 @@ uint16_t L2CA_Register(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) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_Register(psm, p_cb_info, enable_snoop, - p_ertm_info, my_mtu, - required_remote_mtu, sec_level); - } - const bool config_cfm_cb = (p_cb_info.pL2CA_ConfigCfm_Cb != nullptr); const bool config_ind_cb = (p_cb_info.pL2CA_ConfigInd_Cb != nullptr); const bool data_ind_cb = (p_cb_info.pL2CA_DataInd_Cb != nullptr); @@ -194,16 +190,12 @@ uint16_t L2CA_Register(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, * ******************************************************************************/ void L2CA_Deregister(uint16_t psm) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_Deregister(psm); - } - tL2C_RCB* p_rcb; tL2C_CCB* p_ccb; tL2C_LCB* p_lcb; int ii; - L2CAP_TRACE_API("L2CAP - L2CA_Deregister() called for PSM: 0x%04x", psm); + LOG_VERBOSE("L2CAP - L2CA_Deregister() called for PSM: 0x%04x", psm); p_rcb = l2cu_find_rcb_by_psm(psm); if (p_rcb != NULL) { @@ -228,8 +220,7 @@ void L2CA_Deregister(uint16_t psm) { } l2cu_release_rcb(p_rcb); } else { - L2CAP_TRACE_WARNING("L2CAP - PSM: 0x%04x not found for deregistration", - psm); + LOG_WARN("L2CAP - PSM: 0x%04x not found for deregistration", psm); } } @@ -243,19 +234,15 @@ void L2CA_Deregister(uint16_t psm) { * ******************************************************************************/ uint16_t L2CA_AllocateLePSM(void) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_AllocateLePSM(); - } - bool done = false; uint16_t psm = l2cb.le_dyn_psm; uint16_t count = 0; - L2CAP_TRACE_API("%s: last psm=%d", __func__, psm); + LOG_VERBOSE("%s: last psm=%d", __func__, psm); while (!done) { count++; if (count > LE_DYNAMIC_PSM_RANGE) { - L2CAP_TRACE_ERROR("%s: Out of free BLE PSM", __func__); + LOG_ERROR("%s: Out of free BLE PSM", __func__); return 0; } @@ -267,13 +254,13 @@ uint16_t L2CA_AllocateLePSM(void) { if (!l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START]) { /* make sure the newly allocated psm is not used right now */ if (l2cu_find_ble_rcb_by_psm(psm)) { - L2CAP_TRACE_WARNING("%s: supposedly-free PSM=%d have allocated rcb!", - __func__, psm); + LOG_WARN("%s: supposedly-free PSM=%d have allocated rcb!", __func__, + psm); continue; } l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START] = true; - L2CAP_TRACE_DEBUG("%s: assigned PSM=%d", __func__, psm); + LOG_VERBOSE("%s: assigned PSM=%d", __func__, psm); done = true; break; } @@ -293,19 +280,15 @@ uint16_t L2CA_AllocateLePSM(void) { * ******************************************************************************/ void L2CA_FreeLePSM(uint16_t psm) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_FreeLePSM(psm); - } - - L2CAP_TRACE_API("%s: to free psm=%d", __func__, psm); + LOG_VERBOSE("%s: to free psm=%d", __func__, psm); if ((psm < LE_DYNAMIC_PSM_START) || (psm > LE_DYNAMIC_PSM_END)) { - L2CAP_TRACE_ERROR("%s: Invalid PSM=%d value!", __func__, psm); + LOG_ERROR("%s: Invalid PSM=%d value!", __func__, psm); return; } if (!l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START]) { - L2CAP_TRACE_WARNING("%s: PSM=%d was not allocated!", __func__, psm); + LOG_WARN("%s: PSM=%d was not allocated!", __func__, psm); } l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START] = false; } @@ -330,11 +313,7 @@ uint16_t L2CA_ConnectReq2(uint16_t psm, const RawAddress& p_bd_addr, * ******************************************************************************/ uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ConnectReq(psm, p_bd_addr); - } - - VLOG(1) << __func__ << "BDA " << p_bd_addr + VLOG(1) << __func__ << "BDA " << ADDRESS_TO_LOGGABLE_STR(p_bd_addr) << StringPrintf(" PSM: 0x%04x", psm); /* Fail if we have not established communications with the controller */ @@ -387,14 +366,14 @@ uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) { * ccb will be automatically retried after link disconnect * arrives */ - L2CAP_TRACE_DEBUG("L2CAP API - link disconnecting: RETRY LATER"); + LOG_VERBOSE("L2CAP API - link disconnecting: RETRY LATER"); /* Save ccb so it can be started after disconnect is finished */ p_lcb->p_pending_ccb = p_ccb; } - L2CAP_TRACE_API("L2CAP - L2CA_conn_req(psm: 0x%04x) returned CID: 0x%04x", - psm, p_ccb->local_cid); + LOG_VERBOSE("L2CAP - L2CA_conn_req(psm: 0x%04x) returned CID: 0x%04x", psm, + p_ccb->local_cid); /* Return the local CID as our handle */ return p_ccb->local_cid; @@ -416,10 +395,6 @@ uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) { ******************************************************************************/ uint16_t L2CA_RegisterLECoc(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_RegisterLECoc(psm, p_cb_info, sec_level, cfg); - } - if (p_cb_info.pL2CA_ConnectInd_Cb != nullptr || psm < LE_DYNAMIC_PSM_START) { // If we register LE COC for outgoing connection only, don't register with // BTM_Sec, because it's handled by L2CA_ConnectLECocReq. @@ -488,16 +463,11 @@ uint16_t L2CA_RegisterLECoc(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, * ******************************************************************************/ void L2CA_DeregisterLECoc(uint16_t psm) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_DeregisterLECoc(psm); - } - - L2CAP_TRACE_API("%s called for PSM: 0x%04x", __func__, psm); + LOG_VERBOSE("%s called for PSM: 0x%04x", __func__, psm); tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm); if (p_rcb == NULL) { - L2CAP_TRACE_WARNING("%s PSM: 0x%04x not found for deregistration", __func__, - psm); + LOG_WARN("%s PSM: 0x%04x not found for deregistration", __func__, psm); return; } @@ -538,25 +508,21 @@ void L2CA_DeregisterLECoc(uint16_t psm) { ******************************************************************************/ uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ConnectLECocReq(psm, p_bd_addr, p_cfg); - } - BTM_SetSecurityLevel(true, "", 0, sec_level, psm, 0, 0); - VLOG(1) << __func__ << " BDA: " << p_bd_addr + VLOG(1) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(p_bd_addr) << StringPrintf(" PSM: 0x%04x", psm); /* Fail if we have not established communications with the controller */ if (!BTM_IsDeviceUp()) { - L2CAP_TRACE_WARNING("%s BTU not ready", __func__); + LOG_WARN("%s BTU not ready", __func__); return 0; } /* Fail if the PSM is not registered */ tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm); if (p_rcb == NULL) { - L2CAP_TRACE_WARNING("%s No BLE RCB, PSM: 0x%04x", __func__, psm); + LOG_WARN("%s No BLE RCB, PSM: 0x%04x", __func__, psm); return 0; } @@ -568,8 +534,8 @@ uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, if ((p_lcb == NULL) /* currently use BR/EDR for ERTM mode l2cap connection */ || (!l2cu_create_conn_le(p_lcb))) { - L2CAP_TRACE_WARNING("%s conn not started for PSM: 0x%04x p_lcb: 0x%08x", - __func__, psm, p_lcb); + LOG_WARN("%s conn not started for PSM: 0x%04x p_lcb: 0x%p", __func__, + psm, p_lcb); return 0; } } @@ -577,7 +543,7 @@ uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, /* Allocate a channel control block */ tL2C_CCB* p_ccb = l2cu_allocate_ccb(p_lcb, 0); if (p_ccb == NULL) { - L2CAP_TRACE_WARNING("%s no CCB, PSM: 0x%04x", __func__, psm); + LOG_WARN("%s no CCB, PSM: 0x%04x", __func__, psm); return 0; } @@ -595,17 +561,12 @@ uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, /* If link is up, start the L2CAP connection */ if (p_lcb->link_state == LST_CONNECTED) { if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) { - L2CAP_TRACE_DEBUG("%s LE Link is up", __func__); + LOG_VERBOSE("%s LE Link is up", __func__); // post this asynchronously to avoid out-of-order callback invocation // should this operation fail - if (bluetooth::common::init_flags:: - asynchronously_start_l2cap_coc_is_enabled()) { - do_in_main_thread(FROM_HERE, - base::Bind(&l2c_csm_execute, base::Unretained(p_ccb), - L2CEVT_L2CA_CONNECT_REQ, nullptr)); - } else { - l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL); - } + do_in_main_thread( + FROM_HERE, base::BindOnce(&l2c_csm_execute, base::Unretained(p_ccb), + L2CEVT_L2CA_CONNECT_REQ, nullptr)); } } @@ -616,14 +577,14 @@ uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, * arrives */ else if (p_lcb->link_state == LST_DISCONNECTING) { - L2CAP_TRACE_DEBUG("%s link disconnecting: RETRY LATER", __func__); + LOG_VERBOSE("%s link disconnecting: RETRY LATER", __func__); /* Save ccb so it can be started after disconnect is finished */ p_lcb->p_pending_ccb = p_ccb; } - L2CAP_TRACE_API("%s(psm: 0x%04x) returned CID: 0x%04x", __func__, psm, - p_ccb->local_cid); + LOG_VERBOSE("%s(psm: 0x%04x) returned CID: 0x%04x", __func__, psm, + p_ccb->local_cid); /* Return the local CID as our handle */ return p_ccb->local_cid; @@ -643,15 +604,11 @@ uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, * ******************************************************************************/ bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_GetPeerLECocConfig(lcid, peer_cfg); - } - - L2CAP_TRACE_API("%s CID: 0x%04x", __func__, lcid); + LOG_VERBOSE("%s CID: 0x%04x", __func__, lcid); tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid); if (p_ccb == NULL) { - L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid); + LOG_ERROR("%s No CCB for CID:0x%04x", __func__, lcid); return false; } @@ -676,13 +633,13 @@ uint16_t L2CA_GetPeerLECocCredit(const RawAddress& bd_addr, uint16_t lcid) { tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE); if (p_lcb == NULL) { /* No link. Get an LCB and start link establishment */ - L2CAP_TRACE_WARNING("%s no LCB", __func__); + LOG_WARN("%s no LCB", __func__); return L2CAP_LE_CREDIT_MAX; } tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid); if (p_ccb == NULL) { - L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid); + LOG_ERROR("%s No CCB for CID:0x%04x", __func__, lcid); return L2CAP_LE_CREDIT_MAX; } @@ -708,12 +665,7 @@ uint16_t L2CA_GetPeerLECocCredit(const RawAddress& bd_addr, uint16_t lcid) { bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id, std::vector& accepted_lcids, uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ConnectCreditBasedRsp( - p_bd_addr, id, accepted_lcids, result, p_cfg); - } - - VLOG(1) << __func__ << " BDA: " << p_bd_addr + VLOG(1) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(p_bd_addr) << StringPrintf(" num of cids: %d Result: %d", int(accepted_lcids.size()), +result); @@ -721,7 +673,7 @@ bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id, tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_LE); if (p_lcb == NULL) { /* No link. Get an LCB and start link establishment */ - L2CAP_TRACE_WARNING("%s no LCB", __func__); + LOG_WARN("%s no LCB", __func__); return false; } @@ -729,10 +681,15 @@ bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id, */ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, p_lcb->pending_lead_cid); + if (!p_ccb) { + LOG_ERROR("%s No CCB for CID:0x%04x", __func__, p_lcb->pending_lead_cid); + return false; + } + for (uint16_t cid : accepted_lcids) { tL2C_CCB* temp_p_ccb = l2cu_find_ccb_by_cid(p_lcb, cid); if (temp_p_ccb == NULL) { - L2CAP_TRACE_WARNING("%s no CCB", __func__); + LOG_WARN("%s no CCB", __func__); return false; } @@ -744,8 +701,8 @@ bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id, /* The IDs must match */ if (p_ccb->remote_id != id) { - L2CAP_TRACE_WARNING("%s bad id. Expected: %d Got: %d", __func__, - p_ccb->remote_id, id); + LOG_WARN("%s bad id. Expected: %d Got: %d", __func__, p_ccb->remote_id, + id); return false; } @@ -780,47 +737,42 @@ bool L2CA_ConnectCreditBasedRsp(const RawAddress& p_bd_addr, uint8_t id, std::vector L2CA_ConnectCreditBasedReq(uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ConnectCreditBasedReq(psm, p_bd_addr, p_cfg); - } - - VLOG(1) << __func__ << " BDA: " << p_bd_addr + VLOG(1) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(p_bd_addr) << StringPrintf(" PSM: 0x%04x", psm); std::vector allocated_cids; /* Fail if we have not established communications with the controller */ if (!BTM_IsDeviceUp()) { - L2CAP_TRACE_WARNING("%s BTU not ready", __func__); + LOG_WARN("%s BTU not ready", __func__); return allocated_cids; } if (!p_cfg) { - L2CAP_TRACE_WARNING("%s p_cfg is NULL", __func__); + LOG_WARN("%s p_cfg is NULL", __func__); return allocated_cids; } /* Fail if the PSM is not registered */ tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm); if (p_rcb == NULL) { - L2CAP_TRACE_WARNING("%s No BLE RCB, PSM: 0x%04x", __func__, psm); + LOG_WARN("%s No BLE RCB, PSM: 0x%04x", __func__, psm); return allocated_cids; } /* First, see if we already have a le link to the remote */ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_LE); if (p_lcb == NULL) { - L2CAP_TRACE_WARNING("%s No link available", __func__); + LOG_WARN("%s No link available", __func__); return allocated_cids; } if (p_lcb->link_state != LST_CONNECTED) { - L2CAP_TRACE_WARNING("%s incorrect link state: %d", __func__, - p_lcb->link_state); + LOG_WARN("%s incorrect link state: %d", __func__, p_lcb->link_state); return allocated_cids; } - L2CAP_TRACE_DEBUG("%s LE Link is up", __func__); + LOG_VERBOSE("%s LE Link is up", __func__); /* Check if there is no ongoing connection request */ if (p_lcb->pending_ecoc_conn_cnt > 0) { @@ -838,10 +790,11 @@ std::vector L2CA_ConnectCreditBasedReq(uint16_t psm, for (int i = 0; i < p_cfg->number_of_channels; i++) { /* Allocate a channel control block */ - tL2C_CCB* p_ccb = l2cu_allocate_ccb(p_lcb, 0); + tL2C_CCB* p_ccb = + l2cu_allocate_ccb(p_lcb, 0, psm == BT_PSM_EATT /* is_eatt */); if (p_ccb == NULL) { if (i == 0) { - L2CAP_TRACE_WARNING("%s no CCB, PSM: 0x%04x", __func__, psm); + LOG_WARN("%s no CCB, PSM: 0x%04x", __func__, psm); return allocated_cids; } else { break; @@ -873,8 +826,8 @@ std::vector L2CA_ConnectCreditBasedReq(uint16_t psm, p_lcb->pending_ecoc_conn_cnt = (uint16_t)(allocated_cids.size()); l2c_csm_execute(p_ccb_primary, L2CEVT_L2CA_CREDIT_BASED_CONNECT_REQ, NULL); - L2CAP_TRACE_API("%s(psm: 0x%04x) returned CID: 0x%04x", __func__, psm, - p_ccb_primary->local_cid); + LOG_VERBOSE("%s(psm: 0x%04x) returned CID: 0x%04x", __func__, psm, + p_ccb_primary->local_cid); return allocated_cids; } @@ -886,7 +839,7 @@ std::vector L2CA_ConnectCreditBasedReq(uint16_t psm, * Description Start reconfigure procedure on Connection Oriented Channel. * * Parameters: Vector of channels for which configuration should be - *changed New local channel configuration + * changed to new local channel configuration * * Return value: true if peer is connected * @@ -895,16 +848,12 @@ std::vector L2CA_ConnectCreditBasedReq(uint16_t psm, bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bda, std::vector& lcids, tL2CAP_LE_CFG_INFO* p_cfg) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ReconfigCreditBasedConnsReq(bda, lcids, p_cfg); - } - tL2C_CCB* p_ccb; - L2CAP_TRACE_API("L2CA_ReconfigCreditBasedConnsReq() "); + LOG_VERBOSE("L2CA_ReconfigCreditBasedConnsReq() "); if (lcids.empty()) { - L2CAP_TRACE_WARNING("L2CAP - no lcids given to %s", __func__); + LOG_WARN("L2CAP - no lcids given to %s", __func__); return (false); } @@ -912,25 +861,25 @@ bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bda, p_ccb = l2cu_find_ccb_by_cid(NULL, cid); if (!p_ccb) { - L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_cfg_req, CID: %d", cid); + LOG_WARN("L2CAP - no CCB for L2CA_cfg_req, CID: %d", cid); return (false); } if ((p_ccb->local_conn_cfg.mtu > p_cfg->mtu) || (p_ccb->local_conn_cfg.mps > p_cfg->mps)) { - L2CAP_TRACE_WARNING("L2CAP - MPS or MTU reduction, CID: %d", cid); + LOG_WARN("L2CAP - MPS or MTU reduction, CID: %d", cid); return (false); } } if (p_cfg->mtu > L2CAP_MTU_SIZE) { - L2CAP_TRACE_WARNING("L2CAP - adjust MTU: %u too large", p_cfg->mtu); + LOG_WARN("L2CAP - adjust MTU: %u too large", p_cfg->mtu); p_cfg->mtu = L2CAP_MTU_SIZE; } /* Mark all the p_ccbs which going to be reconfigured */ for (uint16_t cid : lcids) { - L2CAP_TRACE_API(" cid: %d", cid); + LOG_VERBOSE(" cid: %d", cid); p_ccb = l2cu_find_ccb_by_cid(NULL, cid); if (!p_ccb) { LOG(ERROR) << __func__ << "Missing cid? " << int(cid); @@ -967,10 +916,6 @@ bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bda, * ******************************************************************************/ bool L2CA_DisconnectReq(uint16_t cid) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_DisconnectReq(cid); - } - tL2C_CCB* p_ccb; /* Find the channel control block. We don't know the link it is on. */ @@ -987,18 +932,9 @@ bool L2CA_DisconnectReq(uint16_t cid) { return (true); } -bool L2CA_DisconnectLECocReq(uint16_t cid) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_DisconnectLECocReq(cid); - } - return L2CA_DisconnectReq(cid); -} +bool L2CA_DisconnectLECocReq(uint16_t cid) { return L2CA_DisconnectReq(cid); } bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_GetRemoteCid(lcid, rcid); - } - tL2C_CCB* control_block = l2cu_find_ccb_by_cid(NULL, lcid); if (!control_block) return false; @@ -1028,11 +964,6 @@ bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) { ******************************************************************************/ bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout, tBT_TRANSPORT transport) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_SetIdleTimeoutByBdAddr(bd_addr, timeout, - transport); - } - tL2C_LCB* p_lcb; if (RawAddress::kAny != bd_addr) { @@ -1059,22 +990,6 @@ bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout, return true; } -/******************************************************************************* - * - * Function L2CA_SetTraceLevel - * - * Description This function sets the trace level for L2CAP. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t L2CA_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) l2cb.l2cap_trace_level = new_level; - - return (l2cb.l2cap_trace_level); -} - /******************************************************************************* * * Function L2CA_UseLatencyMode @@ -1089,10 +1004,10 @@ bool L2CA_UseLatencyMode(const RawAddress& bd_addr, bool use_latency_mode) { tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR); if (p_lcb == nullptr) { LOG_WARN("L2CAP - no LCB for L2CA_SetUseLatencyMode, BDA: %s", - bd_addr.ToString().c_str()); + ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); return false; } - LOG_INFO("BDA: %s, use_latency_mode: %s", bd_addr.ToString().c_str(), + LOG_INFO("BDA: %s, use_latency_mode: %s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), use_latency_mode ? "true" : "false"); p_lcb->use_latency_mode = use_latency_mode; return true; @@ -1110,11 +1025,7 @@ bool L2CA_UseLatencyMode(const RawAddress& bd_addr, bool use_latency_mode) { * ******************************************************************************/ bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_SetAclPriority(bd_addr, priority); - } - - VLOG(1) << __func__ << " BDA: " << bd_addr + VLOG(1) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(bd_addr) << ", priority: " << std::to_string(priority); return (l2cu_set_acl_priority(bd_addr, priority, false)); } @@ -1129,7 +1040,7 @@ bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) { * ******************************************************************************/ bool L2CA_SetAclLatency(const RawAddress& bd_addr, tL2CAP_LATENCY latency) { - LOG_INFO("BDA: %s, latency: %s", bd_addr.ToString().c_str(), + LOG_INFO("BDA: %s, latency: %s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), std::to_string(latency).c_str()); return l2cu_set_acl_latency(bd_addr, latency); } @@ -1144,19 +1055,14 @@ bool L2CA_SetAclLatency(const RawAddress& bd_addr, tL2CAP_LATENCY latency) { * ******************************************************************************/ bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_SetTxPriority(cid, priority); - } - tL2C_CCB* p_ccb; - L2CAP_TRACE_API("L2CA_SetTxPriority() CID: 0x%04x, priority:%d", cid, - priority); + LOG_VERBOSE("L2CA_SetTxPriority() CID: 0x%04x, priority:%d", cid, priority); /* Find the channel control block. We don't know the link it is on. */ p_ccb = l2cu_find_ccb_by_cid(NULL, cid); if (p_ccb == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_SetTxPriority, CID: %d", cid); + LOG_WARN("L2CAP - no CCB for L2CA_SetTxPriority, CID: %d", cid); return (false); } @@ -1181,21 +1087,16 @@ bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) { ******************************************************************************/ bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat, uint8_t* p_chnl_mask) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_GetPeerFeatures(bd_addr, p_ext_feat, - p_chnl_mask); - } - tL2C_LCB* p_lcb; /* We must already have a link to the remote */ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR); if (p_lcb == NULL) { - LOG(WARNING) << __func__ << " No BDA: " << bd_addr; + LOG(WARNING) << __func__ << " No BDA: " << ADDRESS_TO_LOGGABLE_STR(bd_addr); return false; } - VLOG(1) << __func__ << " BDA: " << bd_addr + VLOG(1) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(bd_addr) << StringPrintf(" ExtFea: 0x%08x Chnl_Mask[0]: 0x%02x", p_lcb->peer_ext_fea, p_lcb->peer_chnl_mask[0]); @@ -1241,10 +1142,6 @@ static std::string fixed_channel_text(const uint16_t& fixed_cid) { bool L2CA_RegisterFixedChannel(uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_RegisterFixedChannel(fixed_cid, p_freg); - } - if ((fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)) { LOG_ERROR("Invalid fixed CID: 0x%04x", fixed_cid); @@ -1270,10 +1167,6 @@ bool L2CA_RegisterFixedChannel(uint16_t fixed_cid, * ******************************************************************************/ bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_ConnectFixedChnl(fixed_cid, rem_bda); - } - tL2C_LCB* p_lcb; tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; @@ -1356,16 +1249,6 @@ bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) { } if (transport == BT_TRANSPORT_LE) { - auto argument_list = std::vector>(); - argument_list.push_back(std::make_pair(bluetooth::os::ArgumentType::L2CAP_CID, fixed_cid)); - - bluetooth::shim::LogMetricBluetoothLEConnectionMetricEvent( - rem_bda, - android::bluetooth::le::LeConnectionOriginType::ORIGIN_NATIVE, - android::bluetooth::le::LeConnectionType::CONNECTION_TYPE_LE_ACL, - android::bluetooth::le::LeConnectionState::STATE_LE_ACL_START, - argument_list); - bool ret = l2cu_create_conn_le(p_lcb); if (!ret) { LOG_WARN("Unable to create fixed channel le connection fixed_cid:0x%04x", @@ -1395,10 +1278,6 @@ bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) { ******************************************************************************/ uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda, BT_HDR* p_buf) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_buf); - } - tL2C_LCB* p_lcb; tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; @@ -1501,10 +1380,6 @@ uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda, * ******************************************************************************/ bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_RemoveFixedChnl(fixed_cid, rem_bda); - } - tL2C_LCB* p_lcb; tL2C_CCB* p_ccb; tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; @@ -1514,7 +1389,7 @@ bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) { (fixed_cid > L2CAP_LAST_FIXED_CHNL) || (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL)) { - L2CAP_TRACE_ERROR("L2CA_RemoveFixedChnl() Invalid CID: 0x%04x", fixed_cid); + LOG_ERROR("L2CA_RemoveFixedChnl() Invalid CID: 0x%04x", fixed_cid); return (false); } @@ -1526,12 +1401,12 @@ bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) { if (((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL])) { - LOG(WARNING) << __func__ << " BDA: " << rem_bda + LOG(WARNING) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(rem_bda) << StringPrintf(" CID: 0x%04x not connected", fixed_cid); return (false); } - VLOG(2) << __func__ << " BDA: " << rem_bda + VLOG(2) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(rem_bda) << StringPrintf(" CID: 0x%04x", fixed_cid); /* Release the CCB, starting an inactivity timeout on the LCB if no other CCBs @@ -1571,17 +1446,13 @@ bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) { * ******************************************************************************/ bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda, uint16_t idle_tout) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_SetLeGattTimeout(rem_bda, idle_tout); - } - constexpr uint16_t kAttCid = 4; /* Is a fixed channel connected to the remote BDA ?*/ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE); if (((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[kAttCid - L2CAP_FIRST_FIXED_CHNL])) { - LOG(WARNING) << __func__ << " BDA: " << rem_bda + LOG(WARNING) << __func__ << " BDA: " << ADDRESS_TO_LOGGABLE_STR(rem_bda) << StringPrintf(" CID: 0x%04x not connected", kAttCid); return (false); } @@ -1604,7 +1475,8 @@ bool L2CA_MarkLeLinkAsActive(const RawAddress& rem_bda) { if (p_lcb == NULL) { return false; } - LOG(INFO) << __func__ << "setting link to " << rem_bda << " as active"; + LOG(INFO) << __func__ << "setting link to " + << ADDRESS_TO_LOGGABLE_STR(rem_bda) << " as active"; p_lcb->with_active_local_clients = true; return true; } @@ -1622,19 +1494,11 @@ bool L2CA_MarkLeLinkAsActive(const RawAddress& rem_bda) { * ******************************************************************************/ uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_DataWrite(cid, p_data); - } - - L2CAP_TRACE_API("L2CA_DataWrite() CID: 0x%04x Len: %d", cid, p_data->len); + LOG_VERBOSE("L2CA_DataWrite() CID: 0x%04x Len: %d", cid, p_data->len); return l2c_data_write(cid, p_data, L2CAP_FLUSHABLE_CH_BASED); } uint8_t L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_LECocDataWrite(cid, p_data); - } - return L2CA_DataWrite(cid, p_data); } @@ -1649,24 +1513,19 @@ uint8_t L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) { * ******************************************************************************/ bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_SetChnlFlushability(cid, is_flushable); - } - tL2C_CCB* p_ccb; /* Find the channel control block. We don't know the link it is on. */ p_ccb = l2cu_find_ccb_by_cid(NULL, cid); if (p_ccb == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_SetChnlFlushability, CID: %d", - cid); + LOG_WARN("L2CAP - no CCB for L2CA_SetChnlFlushability, CID: %d", cid); return (false); } p_ccb->is_flushable = is_flushable; - L2CAP_TRACE_API("L2CA_SetChnlFlushability() CID: 0x%04x is_flushable: %d", - cid, is_flushable); + LOG_VERBOSE("L2CA_SetChnlFlushability() CID: 0x%04x is_flushable: %d", cid, + is_flushable); return (true); } @@ -1686,10 +1545,6 @@ bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) { * ******************************************************************************/ uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_FlushChannel(lcid, num_to_flush); - } - tL2C_CCB* p_ccb; tL2C_LCB* p_lcb; uint16_t num_left = 0, num_flushed1 = 0, num_flushed2 = 0; @@ -1697,20 +1552,19 @@ uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) { p_ccb = l2cu_find_ccb_by_cid(NULL, lcid); if (!p_ccb || (p_ccb->p_lcb == NULL)) { - L2CAP_TRACE_WARNING( - "L2CA_FlushChannel() abnormally returning 0 CID: 0x%04x", lcid); + LOG_WARN("L2CA_FlushChannel() abnormally returning 0 CID: 0x%04x", lcid); return (0); } p_lcb = p_ccb->p_lcb; if (num_to_flush != L2CAP_FLUSH_CHANS_GET) { - L2CAP_TRACE_API( - "L2CA_FlushChannel (FLUSH) CID: 0x%04x NumToFlush: %d QC: %u " - "pFirst: 0x%08x", + LOG_VERBOSE( + "L2CA_FlushChannel (FLUSH) CID: 0x%04x NumToFlush: %d QC: %zu " + "pFirst: 0x%p", lcid, num_to_flush, fixed_queue_length(p_ccb->xmit_hold_q), fixed_queue_try_peek_first(p_ccb->xmit_hold_q)); } else { - L2CAP_TRACE_API("L2CA_FlushChannel (QUERY) CID: 0x%04x", lcid); + LOG_VERBOSE("L2CA_FlushChannel (QUERY) CID: 0x%04x", lcid); } /* Cannot flush eRTM buffers once they have a sequence number */ @@ -1768,8 +1622,8 @@ uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) { num_left += fixed_queue_length(p_ccb->xmit_hold_q); /* Return the local number of buffers left for the CID */ - L2CAP_TRACE_DEBUG("L2CA_FlushChannel() flushed: %u + %u, num_left: %u", - num_flushed1, num_flushed2, num_left); + LOG_VERBOSE("L2CA_FlushChannel() flushed: %u + %u, num_left: %u", + num_flushed1, num_flushed2, num_left); /* If we were congested, and now we are not, tell the app */ l2cu_check_channel_congestion(p_ccb); @@ -1779,10 +1633,6 @@ uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) { bool L2CA_IsLinkEstablished(const RawAddress& bd_addr, tBT_TRANSPORT transport) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_IsLinkEstablished(bd_addr, transport); - } - return l2cu_find_lcb_by_bd_addr(bd_addr, transport) != nullptr; } @@ -1826,8 +1676,7 @@ void L2CA_SetMediaStreamChannel(uint16_t local_media_cid, bool status) { } if (set_channel < 0) { - L2CAP_TRACE_ERROR("%s: No empty slot found to set media channel", - __func__); + LOG_ERROR("%s: No empty slot found to set media channel", __func__); return; } @@ -1845,7 +1694,7 @@ void L2CA_SetMediaStreamChannel(uint16_t local_media_cid, bool status) { av_media_channels[set_channel].local_cid, av_media_channels[set_channel].p_ccb->remote_cid); - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "%s: Set A2DP media snoop filtering for local_cid: %d, remote_cid: %d", __func__, local_media_cid, av_media_channels[set_channel].p_ccb->remote_cid); @@ -1859,8 +1708,8 @@ void L2CA_SetMediaStreamChannel(uint16_t local_media_cid, bool status) { } if (set_channel < 0) { - L2CAP_TRACE_ERROR("%s: The channel %d not found in active media channels", - __func__, local_media_cid); + LOG_ERROR("%s: The channel %d not found in active media channels", + __func__, local_media_cid); return; } @@ -1873,8 +1722,8 @@ void L2CA_SetMediaStreamChannel(uint16_t local_media_cid, bool status) { av_media_channels[set_channel].p_ccb->p_lcb->Handle(), av_media_channels[set_channel].local_cid); - L2CAP_TRACE_EVENT("%s: Reset A2DP media snoop filtering for local_cid: %d", - __func__, local_media_cid); + LOG_VERBOSE("%s: Reset A2DP media snoop filtering for local_cid: %d", + __func__, local_media_cid); } av_media_channels[set_channel].is_active = status; diff --git a/system/stack/l2cap/l2c_ble.cc b/system/stack/l2cap/l2c_ble.cc index 7379be42601069d38223c6db129492e4bb051468..ff5445a0cda9a4f591caa46b16c31bf178901235 100644 --- a/system/stack/l2cap/l2c_ble.cc +++ b/system/stack/l2cap/l2c_ble.cc @@ -32,25 +32,29 @@ #include #endif -#include "bt_target.h" -#include "bta/include/bta_hearing_aid_api.h" #include "btif/include/core_callbacks.h" #include "btif/include/stack_manager.h" #include "device/include/controller.h" +#include "internal_include/bt_target.h" +#include "internal_include/stack_config.h" #include "main/shim/acl_api.h" -#include "main/shim/l2c_api.h" -#include "main/shim/shim.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "osi/include/properties.h" +#include "stack/btm/btm_ble_sec.h" #include "stack/btm/btm_dev.h" +#include "stack/btm/btm_int_types.h" #include "stack/btm/btm_sec.h" +#include "stack/btm/btm_sec_int_types.h" #include "stack/include/acl_api.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_ble_api.h" +#include "stack/include/btm_log_history.h" #include "stack/include/l2c_api.h" +#include "stack/include/l2cap_acl_interface.h" #include "stack/include/l2cdefs.h" #include "stack/l2cap/l2c_int.h" -#include "stack_config.h" #include "types/raw_address.h" namespace { @@ -59,20 +63,12 @@ constexpr char kBtmLogTag[] = "L2CAP"; } -tL2CAP_LE_RESULT_CODE btm_ble_start_sec_check(const RawAddress& bd_addr, - uint16_t psm, bool is_originator, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data); - extern tBTM_CB btm_cb; using base::StringPrintf; static void l2cble_start_conn_update(tL2C_LCB* p_lcb); static void l2cble_start_subrate_change(tL2C_LCB* p_lcb); -void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval, - uint16_t latency, uint16_t timeout, - tHCI_STATUS status); /******************************************************************************* * @@ -89,12 +85,6 @@ bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int, uint16_t latency, uint16_t timeout, uint16_t min_ce_len, uint16_t max_ce_len) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - bluetooth::shim::L2CA_LeConnectionUpdate(rem_bda, min_int, max_int, latency, - timeout, min_ce_len, max_ce_len); - return true; - } - tL2C_LCB* p_lcb; /* See if we have a link control block for the remote device */ @@ -111,9 +101,9 @@ bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int, return (false); } - VLOG(2) << __func__ << ": BD_ADDR=" << rem_bda << ", min_int=" << min_int - << ", max_int=" << max_int << ", min_ce_len=" << min_ce_len - << ", max_ce_len=" << max_ce_len; + VLOG(2) << __func__ << ": BD_ADDR=" << ADDRESS_TO_LOGGABLE_STR(rem_bda) + << ", min_int=" << min_int << ", max_int=" << max_int + << ", min_ce_len=" << min_ce_len << ", max_ce_len=" << max_ce_len; p_lcb->min_interval = min_int; p_lcb->max_interval = max_int; @@ -140,10 +130,6 @@ bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int, * ******************************************************************************/ bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_EnableUpdateBleConnParams(rem_bda, enable); - } - if (stack_config_get_interface()->get_pts_conn_updates_disabled()) return false; @@ -157,13 +143,14 @@ bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable) { return false; } - VLOG(2) << __func__ << " - BD_ADDR " << rem_bda + VLOG(2) << __func__ << " - BD_ADDR " << ADDRESS_TO_LOGGABLE_STR(rem_bda) << StringPrintf(" enable %d current upd state 0x%02x", enable, p_lcb->conn_update_mask); if (p_lcb->transport != BT_TRANSPORT_LE) { - LOG(WARNING) << __func__ << " - BD_ADDR " << rem_bda - << " not LE, link role " << p_lcb->LinkRole(); + LOG(WARNING) << __func__ << " - BD_ADDR " + << ADDRESS_TO_LOGGABLE_STR(rem_bda) << " not LE, link role " + << p_lcb->LinkRole(); return false; } @@ -193,10 +180,6 @@ void L2CA_Consolidate(const RawAddress& identity_addr, const RawAddress& rpa) { } hci_role_t L2CA_GetBleConnRole(const RawAddress& bd_addr) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return bluetooth::shim::L2CA_GetBleConnRole(bd_addr); - } - tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE); if (p_lcb == nullptr) { return HCI_ROLE_UNKNOWN; @@ -261,6 +244,7 @@ bool l2cble_conn_comp(uint16_t handle, uint8_t role, const RawAddress& bda, return false; } } + p_lcb->link_state = LST_CONNECTING; } else if (role == HCI_ROLE_CENTRAL && p_lcb->link_state != LST_CONNECTING) { LOG_ERROR( "Received le acl connection as role central but not in connecting " @@ -311,14 +295,6 @@ bool l2cble_conn_comp(uint16_t handle, uint8_t role, const RawAddress& bda, return true; } -bool l2cble_conn_comp_from_address_with_type( - uint16_t handle, uint8_t role, const tBLE_BD_ADDR& address_with_type, - uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout) { - return l2cble_conn_comp(handle, role, address_with_type.bda, - address_with_type.type, conn_interval, conn_latency, - conn_timeout); -} - /******************************************************************************* * * Function l2cble_start_conn_update @@ -422,27 +398,27 @@ static void l2cble_start_conn_update(tL2C_LCB* p_lcb) { void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status, uint16_t interval, uint16_t latency, uint16_t timeout) { - L2CAP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* See if we have a link control block for the remote device */ tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle); if (!p_lcb) { - L2CAP_TRACE_WARNING("%s: Invalid handle: %d", __func__, handle); + LOG_WARN("%s: Invalid handle: %d", __func__, handle); return; } p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PENDING; if (status != HCI_SUCCESS) { - L2CAP_TRACE_WARNING("%s: Error status: %d", __func__, status); + LOG_WARN("%s: Error status: %d", __func__, status); } l2cble_start_conn_update(p_lcb); l2cble_start_subrate_change(p_lcb); - L2CAP_TRACE_DEBUG("%s: conn_update_mask=%d , subrate_req_mask=%d", __func__, - p_lcb->conn_update_mask, p_lcb->subrate_req_mask); + LOG_VERBOSE("%s: conn_update_mask=%d , subrate_req_mask=%d", __func__, + p_lcb->conn_update_mask, p_lcb->subrate_req_mask); } /******************************************************************************* @@ -504,9 +480,8 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { /* Check command length does not exceed packet length */ if ((p + cmd_len) > p_pkt_end) { - L2CAP_TRACE_WARNING( - "L2CAP - LE - format error, pkt_len: %d cmd_len: %d code: %d", - pkt_len, cmd_len, cmd_code); + LOG_WARN("L2CAP - LE - format error, pkt_len: %d cmd_len: %d code: %d", + pkt_len, cmd_len, cmd_code); return; } @@ -548,8 +523,10 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { STREAM_TO_UINT16(timeout, p); /* 0x000A - 0x0C80 */ /* If we are a central, the peripheral wants to update the parameters */ if (p_lcb->IsLinkRoleCentral()) { - L2CA_AdjustConnectionIntervals(&min_interval, &max_interval, - BTM_BLE_CONN_INT_MIN_LIMIT); + L2CA_AdjustConnectionIntervals( + &min_interval, &max_interval, + osi_property_get_int32("bluetooth.core.le.min_connection_interval", + BTM_BLE_CONN_INT_MIN_LIMIT)); if (min_interval < BTM_BLE_CONN_INT_MIN || min_interval > BTM_BLE_CONN_INT_MAX || @@ -663,7 +640,8 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { L2CAP_LE_RESULT_SOURCE_CID_ALREADY_ALLOCATED; } else { /* Allocate a ccb for this.*/ - temp_p_ccb = l2cu_allocate_ccb(p_lcb, 0); + temp_p_ccb = l2cu_allocate_ccb( + p_lcb, 0, con_info.psm == BT_PSM_EATT /* is_eatt */); if (temp_p_ccb == NULL) { LOG_ERROR("L2CAP - unable to allocate CCB"); p_lcb->pending_ecoc_connection_cids[i] = 0; @@ -718,7 +696,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { return; } - L2CAP_TRACE_DEBUG("Recv L2CAP_CMD_CREDIT_BASED_CONN_RES"); + LOG_VERBOSE("Recv L2CAP_CMD_CREDIT_BASED_CONN_RES"); /* For all channels, see whose identifier matches this id */ for (temp_p_ccb = p_lcb->ccb_queue.p_first_ccb; temp_p_ccb; temp_p_ccb = temp_p_ccb->p_next_ccb) { @@ -729,7 +707,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { } if (!p_ccb) { - L2CAP_TRACE_DEBUG(" Cannot find matching connection req"); + LOG_VERBOSE(" Cannot find matching connection req"); con_info.l2cap_result = L2CAP_LE_RESULT_INVALID_SOURCE_CID; l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info); return; @@ -750,8 +728,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { con_info.l2cap_result == L2CAP_LE_RESULT_INSUFFICIENT_AUTHORIZATION || con_info.l2cap_result == L2CAP_LE_RESULT_UNACCEPTABLE_PARAMETERS || con_info.l2cap_result == L2CAP_LE_RESULT_INVALID_PARAMETERS) { - L2CAP_TRACE_ERROR("L2CAP - not accepted. Status %d", - con_info.l2cap_result); + LOG_ERROR("L2CAP - not accepted. Status %d", con_info.l2cap_result); l2cble_handle_connect_rsp_neg(p_lcb, &con_info); return; } @@ -759,7 +736,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { /* validate the parameters */ if (mtu < L2CAP_CREDIT_BASED_MIN_MTU || mps < L2CAP_CREDIT_BASED_MIN_MPS || mps > L2CAP_LE_MAX_MPS) { - L2CAP_TRACE_ERROR("L2CAP - invalid params"); + LOG_ERROR("L2CAP - invalid params"); con_info.l2cap_result = L2CAP_LE_RESULT_INVALID_PARAMETERS; l2cble_handle_connect_rsp_neg(p_lcb, &con_info); return; @@ -769,15 +746,15 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { * good*/ num_of_channels = (p_pkt_end - p) / sizeof(uint16_t); if (num_of_channels != p_lcb->pending_ecoc_conn_cnt) { - L2CAP_TRACE_ERROR( + LOG_ERROR( "Incorrect response." - "expected num of channels = %d", - "received num of channels = %d", num_of_channels, - p_lcb->pending_ecoc_conn_cnt); + "expected num of channels = %d" + "received num of channels = %d", + num_of_channels, p_lcb->pending_ecoc_conn_cnt); return; } - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "mtu = %d, " "mps = %d, " "initial_credit = %d, " @@ -806,7 +783,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { */ temp_p_ccb = l2cu_find_ccb_by_remote_cid(p_lcb, rcid); if (temp_p_ccb != nullptr) { - L2CAP_TRACE_ERROR( + LOG_ERROR( "Already Allocated Destination cid. " "rcid = %d " "send peer_disc_req", @@ -826,7 +803,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { temp_p_ccb = l2cu_find_ccb_by_cid(p_lcb, cid); temp_p_ccb->remote_cid = rcid; - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "local cid = %d " "remote cid = %d", cid, temp_p_ccb->remote_cid); @@ -865,7 +842,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { /* validate the parameters */ if (mtu < L2CAP_CREDIT_BASED_MIN_MTU || mps < L2CAP_CREDIT_BASED_MIN_MPS || mps > L2CAP_LE_MAX_MPS) { - L2CAP_TRACE_ERROR("L2CAP - invalid params"); + LOG_ERROR("L2CAP - invalid params"); l2cu_send_ble_reconfig_rsp(p_lcb, id, L2CAP_RECONFIG_UNACCAPTED_PARAM); return; } @@ -873,7 +850,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { /* Check how many channels remote side wants to reconfigure */ num_of_channels = (p_pkt_end - p) / sizeof(uint16_t); - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "Recv L2CAP_CMD_CREDIT_BASED_RECONFIG_REQ with " "mtu = %d, " "mps = %d, " @@ -885,14 +862,14 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { STREAM_TO_UINT16(rcid, p_tmp); p_ccb = l2cu_find_ccb_by_remote_cid(p_lcb, rcid); if (!p_ccb) { - L2CAP_TRACE_WARNING( - "L2CAP - rcvd config req for non existing cid: 0x%04x", rcid); + LOG_WARN("L2CAP - rcvd config req for non existing cid: 0x%04x", + rcid); l2cu_send_ble_reconfig_rsp(p_lcb, id, L2CAP_RECONFIG_INVALID_DCID); return; } if (p_ccb->peer_conn_cfg.mtu > mtu) { - L2CAP_TRACE_WARNING( + LOG_WARN( "L2CAP - rcvd config req mtu reduction new mtu < mtu (%d < %d)", mtu, p_ccb->peer_conn_cfg.mtu); l2cu_send_ble_reconfig_rsp(p_lcb, id, @@ -901,7 +878,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { } if (p_ccb->peer_conn_cfg.mps > mps && num_of_channels > 1) { - L2CAP_TRACE_WARNING( + LOG_WARN( "L2CAP - rcvd config req mps reduction new mps < mps (%d < %d)", mtu, p_ccb->peer_conn_cfg.mtu); l2cu_send_ble_reconfig_rsp(p_lcb, id, @@ -939,7 +916,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { } STREAM_TO_UINT16(result, p); - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "Recv L2CAP_CMD_CREDIT_BASED_RECONFIG_RES for " "result = 0x%04x", result); @@ -977,7 +954,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { STREAM_TO_UINT16(mps, p); STREAM_TO_UINT16(initial_credit, p); - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "Recv L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ with " "mtu = %d, " "mps = %d, " @@ -986,8 +963,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { p_ccb = l2cu_find_ccb_by_remote_cid(p_lcb, rcid); if (p_ccb) { - L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for duplicated cid: 0x%04x", - rcid); + LOG_WARN("L2CAP - rcvd conn req for duplicated cid: 0x%04x", rcid); l2cu_reject_ble_coc_connection( p_lcb, id, L2CAP_LE_RESULT_SOURCE_CID_ALREADY_ALLOCATED); break; @@ -995,24 +971,23 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { p_rcb = l2cu_find_ble_rcb_by_psm(con_info.psm); if (p_rcb == NULL) { - L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for unknown PSM: 0x%04x", - con_info.psm); + LOG_WARN("L2CAP - rcvd conn req for unknown PSM: 0x%04x", con_info.psm); l2cu_reject_ble_coc_connection(p_lcb, id, L2CAP_LE_RESULT_NO_PSM); break; } else { if (!p_rcb->api.pL2CA_ConnectInd_Cb) { - L2CAP_TRACE_WARNING( - "L2CAP - rcvd conn req for outgoing-only connection PSM: %d", - con_info.psm); + LOG_WARN("L2CAP - rcvd conn req for outgoing-only connection PSM: %d", + con_info.psm); l2cu_reject_ble_coc_connection(p_lcb, id, L2CAP_CONN_NO_PSM); break; } } /* Allocate a ccb for this.*/ - p_ccb = l2cu_allocate_ccb(p_lcb, 0); + p_ccb = l2cu_allocate_ccb(p_lcb, 0, + con_info.psm == BT_PSM_EATT /* is_eatt */); if (p_ccb == NULL) { - L2CAP_TRACE_ERROR("L2CAP - unable to allocate CCB"); + LOG_ERROR("L2CAP - unable to allocate CCB"); l2cu_reject_ble_connection(p_ccb, id, L2CAP_CONN_NO_RESOURCES); break; } @@ -1020,7 +995,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { /* validate the parameters */ if (mtu < L2CAP_LE_MIN_MTU || mps < L2CAP_LE_MIN_MPS || mps > L2CAP_LE_MAX_MPS) { - L2CAP_TRACE_ERROR("L2CAP do not like the params"); + LOG_ERROR("L2CAP do not like the params"); l2cu_reject_ble_connection(p_ccb, id, L2CAP_CONN_NO_RESOURCES); break; } @@ -1051,7 +1026,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { break; case L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES: - L2CAP_TRACE_DEBUG("Recv L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES"); + LOG_VERBOSE("Recv L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES"); /* For all channels, see whose identifier matches this id */ for (temp_p_ccb = p_lcb->ccb_queue.p_first_ccb; temp_p_ccb; temp_p_ccb = temp_p_ccb->p_next_ccb) { @@ -1061,7 +1036,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { } } if (p_ccb) { - L2CAP_TRACE_DEBUG("I remember the connection req"); + LOG_VERBOSE("I remember the connection req"); if (p + 10 > p_pkt_end) { LOG(ERROR) << "invalid read"; return; @@ -1074,7 +1049,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { STREAM_TO_UINT16(con_info.l2cap_result, p); con_info.remote_cid = p_ccb->remote_cid; - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "remote_cid = %d, " "mtu = %d, " "mps = %d, " @@ -1088,7 +1063,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { if (p_ccb->peer_conn_cfg.mtu < L2CAP_LE_MIN_MTU || p_ccb->peer_conn_cfg.mps < L2CAP_LE_MIN_MPS || p_ccb->peer_conn_cfg.mps > L2CAP_LE_MAX_MPS) { - L2CAP_TRACE_ERROR("L2CAP do not like the params"); + LOG_ERROR("L2CAP do not like the params"); con_info.l2cap_result = L2CAP_LE_RESULT_NO_RESOURCES; l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info); break; @@ -1105,7 +1080,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { else l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info); } else { - L2CAP_TRACE_DEBUG("I DO NOT remember the connection req"); + LOG_VERBOSE("I DO NOT remember the connection req"); con_info.l2cap_result = L2CAP_LE_RESULT_INVALID_SOURCE_CID; l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info); } @@ -1120,14 +1095,14 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { STREAM_TO_UINT16(lcid, p); p_ccb = l2cu_find_ccb_by_remote_cid(p_lcb, lcid); if (p_ccb == NULL) { - L2CAP_TRACE_DEBUG("%s Credit received for unknown channel id %d", - __func__, lcid); + LOG_VERBOSE("%s Credit received for unknown channel id %d", __func__, + lcid); break; } STREAM_TO_UINT16(credit, p); l2c_csm_execute(p_ccb, L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT, &credit); - L2CAP_TRACE_DEBUG("%s Credit received", __func__); + LOG_VERBOSE("%s Credit received", __func__); break; case L2CAP_CMD_DISC_REQ: @@ -1164,7 +1139,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { break; default: - L2CAP_TRACE_WARNING("L2CAP - LE - unknown cmd code: %d", cmd_code); + LOG_WARN("L2CAP - LE - unknown cmd code: %d", cmd_code); l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0); break; } @@ -1198,10 +1173,6 @@ bool l2cble_create_conn(tL2C_LCB* p_lcb) { * ******************************************************************************/ void l2c_link_processs_ble_num_bufs(uint16_t num_lm_ble_bufs) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return; - } - if (num_lm_ble_bufs == 0) { num_lm_ble_bufs = L2C_DEF_NUM_BLE_BUF_SHARED; l2cb.num_lm_acl_bufs -= L2C_DEF_NUM_BLE_BUF_SHARED; @@ -1283,7 +1254,7 @@ void l2c_ble_link_adjust_allocation(void) { l2cb.ble_round_robin_unacked = 0; qq = qq_remainder = 0; } - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "l2c_ble_link_adjust_allocation num_hipri: %u num_lowpri: %u " "low_quota: %u round_robin_quota: %u qq: %u", num_hipri_links, num_lowpri_links, low_quota, l2cb.ble_round_robin_quota, @@ -1310,12 +1281,12 @@ void l2c_ble_link_adjust_allocation(void) { } } - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "l2c_ble_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d", yy, p_lcb->acl_priority, p_lcb->link_xmit_quota); - L2CAP_TRACE_EVENT(" SentNotAcked: %d RRUnacked: %d", - p_lcb->sent_not_acked, l2cb.round_robin_unacked); + LOG_VERBOSE(" SentNotAcked: %d RRUnacked: %d", + p_lcb->sent_not_acked, l2cb.round_robin_unacked); /* There is a special case where we have readjusted the link quotas and */ /* this link may have sent anything but some other link sent packets so */ @@ -1356,14 +1327,14 @@ void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min, btsnd_hcic_ble_rc_param_req_reply(handle, int_min, int_max, latency, timeout, 0, 0); } else { - L2CAP_TRACE_EVENT("L2CAP - LE - update currently disabled"); + LOG_VERBOSE("L2CAP - LE - update currently disabled"); p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; btsnd_hcic_ble_rc_param_req_neg_reply(handle, HCI_ERR_UNACCEPT_CONN_INTERVAL); } } else { - L2CAP_TRACE_WARNING("No link to update connection parameter") + LOG_WARN("No link to update connection parameter"); } } @@ -1380,7 +1351,7 @@ void l2cble_update_data_length(tL2C_LCB* p_lcb) { uint16_t tx_mtu = 0; uint16_t i = 0; - L2CAP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* See if we have a link control block for the connection */ if (p_lcb == NULL) return; @@ -1463,7 +1434,7 @@ void l2cble_credit_based_conn_req(tL2C_CCB* p_ccb) { if (!p_ccb) return; if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE) { - L2CAP_TRACE_WARNING("LE link doesn't exist"); + LOG_WARN("LE link doesn't exist"); return; } @@ -1489,7 +1460,7 @@ void l2cble_credit_based_conn_res(tL2C_CCB* p_ccb, uint16_t result) { if (!p_ccb) return; if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE) { - L2CAP_TRACE_WARNING("LE link doesn't exist"); + LOG_WARN("LE link doesn't exist"); return; } @@ -1511,7 +1482,7 @@ void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb, uint16_t credit_value) { if (!p_ccb) return; if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE) { - L2CAP_TRACE_WARNING("LE link doesn't exist"); + LOG_WARN("LE link doesn't exist"); return; } @@ -1530,11 +1501,11 @@ void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb, uint16_t credit_value) { * ******************************************************************************/ void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb) { - L2CAP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!p_ccb) return; if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE) { - L2CAP_TRACE_WARNING("LE link doesn't exist"); + LOG_WARN("LE link doesn't exist"); return; } @@ -1560,8 +1531,8 @@ void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport, uint8_t sec_act; if (!p_lcb) { - L2CAP_TRACE_WARNING("%s: security complete for unknown device. bda=%s", - __func__, ADDRESS_TO_LOGGABLE_CSTR(*bda)); + LOG_WARN("%s: security complete for unknown device. bda=%s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(*bda)); return; } @@ -1571,37 +1542,35 @@ void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport, if (!fixed_queue_is_empty(p_lcb->le_sec_pending_q)) { p_buf = (tL2CAP_SEC_DATA*)fixed_queue_dequeue(p_lcb->le_sec_pending_q); if (!p_buf) { - L2CAP_TRACE_WARNING( - "%s Security complete for request not initiated from L2CAP", - __func__); + LOG_WARN("%s Security complete for request not initiated from L2CAP", + __func__); return; } if (status != BTM_SUCCESS) { - (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status); + (*(p_buf->p_callback))(bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status); osi_free(p_buf); } else { if (sec_act == BTM_SEC_ENCRYPT_MITM) { if (BTM_IsLinkKeyAuthed(p_bda, transport)) - (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, + (*(p_buf->p_callback))(bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status); else { - L2CAP_TRACE_DEBUG("%s MITM Protection Not present", __func__); - (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, + LOG_VERBOSE("%s MITM Protection Not present", __func__); + (*(p_buf->p_callback))(bda, BT_TRANSPORT_LE, p_buf->p_ref_data, BTM_FAILED_ON_SECURITY); } } else { - L2CAP_TRACE_DEBUG("%s MITM Protection not required sec_act = %d", - __func__, p_lcb->sec_act); + LOG_VERBOSE("%s MITM Protection not required sec_act = %d", __func__, + p_lcb->sec_act); - (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, - status); + (*(p_buf->p_callback))(bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status); } osi_free(p_buf); } } else { - L2CAP_TRACE_WARNING( - "%s Security complete for request not initiated from L2CAP", __func__); + LOG_WARN("%s Security complete for request not initiated from L2CAP", + __func__); return; } @@ -1609,7 +1578,7 @@ void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport, p_buf = (tL2CAP_SEC_DATA*)fixed_queue_dequeue(p_lcb->le_sec_pending_q); if (status != BTM_SUCCESS) { - (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status); + (*(p_buf->p_callback))(bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status); osi_free(p_buf); } else { @@ -1634,9 +1603,8 @@ void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport, ******************************************************************************/ tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm, bool is_originator, - tL2CAP_SEC_CBACK* p_callback, + tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) { - tL2CAP_LE_RESULT_CODE result; tL2C_LCB* p_lcb = NULL; if (!p_callback) { @@ -1648,7 +1616,7 @@ tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, if (!p_lcb) { LOG_ERROR("Security check for unknown device"); - p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_UNKNOWN_ADDR); + p_callback(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_UNKNOWN_ADDR); return L2CAP_LE_RESULT_NO_RESOURCES; } @@ -1656,7 +1624,7 @@ tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, (tL2CAP_SEC_DATA*)osi_malloc((uint16_t)sizeof(tL2CAP_SEC_DATA)); if (!p_buf) { LOG_ERROR("No resources for connection"); - p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_NO_RESOURCES); + p_callback(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_NO_RESOURCES); return L2CAP_LE_RESULT_NO_RESOURCES; } @@ -1665,10 +1633,26 @@ tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, p_buf->p_callback = p_callback; p_buf->p_ref_data = p_ref_data; fixed_queue_enqueue(p_lcb->le_sec_pending_q, p_buf); - result = btm_ble_start_sec_check(bd_addr, psm, is_originator, - &l2cble_sec_comp, p_ref_data); - - return result; + tBTM_STATUS result = btm_ble_start_sec_check(bd_addr, psm, is_originator, + &l2cble_sec_comp, p_ref_data); + + switch (result) { + case BTM_SUCCESS: + return L2CAP_LE_RESULT_CONN_OK; + case BTM_ILLEGAL_VALUE: + return L2CAP_LE_RESULT_NO_PSM; + case BTM_NOT_AUTHENTICATED: + return L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION; + case BTM_NOT_ENCRYPTED: + return L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP; + case BTM_NOT_AUTHORIZED: + return L2CAP_LE_RESULT_INSUFFICIENT_AUTHORIZATION; + case BTM_INSUFFICIENT_ENCRYPT_KEY_SIZE: + return L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP_KEY_SIZE; + default: + LOG_ERROR("unexpected return value: %s", btm_status_text(result).c_str()); + return L2CAP_LE_RESULT_INVALID_PARAMETERS; + } } /* This function is called to adjust the connection intervals based on various @@ -1694,13 +1678,13 @@ void L2CA_AdjustConnectionIntervals(uint16_t* min_interval, // When there are bonded Hearing Aid devices, we will constrained this // minimum interval. phone_min_interval = BTM_BLE_CONN_INT_MIN_HEARINGAID; - L2CAP_TRACE_DEBUG("%s: Have Hearing Aids. Min. interval is set to %d", - __func__, phone_min_interval); + LOG_VERBOSE("%s: Have Hearing Aids. Min. interval is set to %d", __func__, + phone_min_interval); } if (*min_interval < phone_min_interval) { - L2CAP_TRACE_DEBUG("%s: requested min_interval=%d too small. Set to %d", - __func__, *min_interval, phone_min_interval); + LOG_VERBOSE("%s: requested min_interval=%d too small. Set to %d", __func__, + *min_interval, phone_min_interval); *min_interval = phone_min_interval; } @@ -1709,8 +1693,8 @@ void L2CA_AdjustConnectionIntervals(uint16_t* min_interval, // to remain established. // In other words, this is a workaround for certain peripherals. if (*max_interval < phone_min_interval) { - L2CAP_TRACE_DEBUG("%s: requested max_interval=%d too small. Set to %d", - __func__, *max_interval, phone_min_interval); + LOG_VERBOSE("%s: requested max_interval=%d too small. Set to %d", __func__, + *max_interval, phone_min_interval); *max_interval = phone_min_interval; } } @@ -1733,7 +1717,7 @@ void l2cble_use_preferred_conn_params(const RawAddress& bda) { (p_lcb->min_interval > p_dev_rec->conn_params.max_conn_int) || (p_lcb->latency > p_dev_rec->conn_params.peripheral_latency) || (p_lcb->timeout > p_dev_rec->conn_params.supervision_tout))) { - BTM_TRACE_DEBUG( + LOG_VERBOSE( "%s: HANDLE=%d min_conn_int=%d max_conn_int=%d peripheral_latency=%d " "supervision_tout=%d", __func__, p_lcb->Handle(), p_dev_rec->conn_params.min_conn_int, @@ -1775,16 +1759,16 @@ static void l2cble_start_subrate_change(tL2C_LCB* p_lcb) { btm_find_or_alloc_dev(p_lcb->remote_bd_addr); - L2CAP_TRACE_DEBUG("%s: subrate_req_mask=%d conn_update_mask=%d", __func__, - p_lcb->subrate_req_mask, p_lcb->conn_update_mask); + LOG_VERBOSE("%s: subrate_req_mask=%d conn_update_mask=%d", __func__, + p_lcb->subrate_req_mask, p_lcb->conn_update_mask); if (p_lcb->subrate_req_mask & L2C_BLE_SUBRATE_REQ_PENDING) { - L2CAP_TRACE_DEBUG("%s: returning L2C_BLE_SUBRATE_REQ_PENDING ", __func__); + LOG_VERBOSE("%s: returning L2C_BLE_SUBRATE_REQ_PENDING ", __func__); return; } if (p_lcb->subrate_req_mask & L2C_BLE_SUBRATE_REQ_DISABLE) { - L2CAP_TRACE_DEBUG("%s: returning L2C_BLE_SUBRATE_REQ_DISABLE ", __func__); + LOG_VERBOSE("%s: returning L2C_BLE_SUBRATE_REQ_DISABLE ", __func__); return; } @@ -1792,15 +1776,14 @@ static void l2cble_start_subrate_change(tL2C_LCB* p_lcb) { if (!(p_lcb->subrate_req_mask & L2C_BLE_NEW_SUBRATE_PARAM) || (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PENDING) || (p_lcb->conn_update_mask & L2C_BLE_NEW_CONN_PARAM)) { - L2CAP_TRACE_DEBUG("%s: returning L2C_BLE_NEW_SUBRATE_PARAM", __func__); + LOG_VERBOSE("%s: returning L2C_BLE_NEW_SUBRATE_PARAM", __func__); return; } - if (!controller_get_interface()->supports_ble_connection_subrating_host() || - !controller_get_interface()->supports_ble_connection_subrating() || + if (!controller_get_interface()->supports_ble_connection_subrating() || !acl_peer_supports_ble_connection_subrating(p_lcb->remote_bd_addr) || !acl_peer_supports_ble_connection_subrating_host(p_lcb->remote_bd_addr)) { - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "%s: returning L2C_BLE_NEW_SUBRATE_PARAM local_host_sup=%d, " "local_conn_subrarte_sup=%d, peer_subrate_sup=%d, peer_host_sup=%d", __func__, @@ -1811,7 +1794,7 @@ static void l2cble_start_subrate_change(tL2C_LCB* p_lcb) { return; } - L2CAP_TRACE_DEBUG("%s: Sending HCI cmd for subrate req", __func__); + LOG_VERBOSE("%s: Sending HCI cmd for subrate req", __func__); bluetooth::shim::ACL_LeSubrateRequest( p_lcb->Handle(), p_lcb->subrate_min, p_lcb->subrate_max, p_lcb->max_latency, p_lcb->cont_num, p_lcb->supervision_tout); @@ -1914,25 +1897,25 @@ void l2cble_process_subrate_change_evt(uint16_t handle, uint8_t status, uint16_t subrate_factor, uint16_t peripheral_latency, uint16_t cont_num, uint16_t timeout) { - L2CAP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); /* See if we have a link control block for the remote device */ tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle); if (!p_lcb) { - L2CAP_TRACE_WARNING("%s: Invalid handle: %d", __func__, handle); + LOG_WARN("%s: Invalid handle: %d", __func__, handle); return; } p_lcb->subrate_req_mask &= ~L2C_BLE_SUBRATE_REQ_PENDING; if (status != HCI_SUCCESS) { - L2CAP_TRACE_WARNING("%s: Error status: %d", __func__, status); + LOG_WARN("%s: Error status: %d", __func__, status); } l2cble_start_conn_update(p_lcb); l2cble_start_subrate_change(p_lcb); - L2CAP_TRACE_DEBUG("%s: conn_update_mask=%d , subrate_req_mask=%d", __func__, - p_lcb->conn_update_mask, p_lcb->subrate_req_mask); + LOG_VERBOSE("%s: conn_update_mask=%d , subrate_req_mask=%d", __func__, + p_lcb->conn_update_mask, p_lcb->subrate_req_mask); } diff --git a/system/stack/l2cap/l2c_csm.cc b/system/stack/l2cap/l2c_csm.cc index 32c8ab9a55d433358d0c7b9b70a6a2d923acaf20..b64571d3bcf740656e786e4922253004ed1b9a8f 100644 --- a/system/stack/l2cap/l2c_csm.cc +++ b/system/stack/l2cap/l2c_csm.cc @@ -29,16 +29,17 @@ #include -#include "bt_target.h" -#include "common/time_util.h" -#include "gd/hal/snoop_logger.h" +#include "hal/snoop_logger.h" +#include "internal_include/bt_target.h" +#include "main/shim/entry.h" #include "main/shim/metrics_api.h" -#include "main/shim/shim.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" +#include "osi/include/stack_power_telemetry.h" #include "stack/btm/btm_sec.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" #include "stack/include/l2cdefs.h" #include "stack/l2cap/l2c_int.h" @@ -100,14 +101,21 @@ static void l2c_csm_indicate_connection_open(tL2C_CCB* p_ccb) { if (p_ccb->connection_initiator == L2CAP_INITIATOR_LOCAL) { (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(p_ccb->local_cid, L2CAP_CONN_OK); } else { - (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb)( - p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid, p_ccb->p_rcb->psm, - p_ccb->remote_id); + if (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) { + (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb)( + p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid, p_ccb->p_rcb->psm, + p_ccb->remote_id); + } else { + LOG_WARN("pL2CA_ConnectInd_Cb is null"); + } } if (p_ccb->chnl_state == CST_OPEN && !p_ccb->p_lcb->is_transport_ble()) { (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)( p_ccb->local_cid, p_ccb->connection_initiator, &p_ccb->peer_cfg); } + power_telemetry::GetInstance().LogChannelConnected( + p_ccb->p_rcb->psm, p_ccb->local_cid, p_ccb->remote_id, + p_ccb->p_lcb->remote_bd_addr); } /******************************************************************************* @@ -216,7 +224,7 @@ static void l2c_csm_closed(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) { if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) { p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP; l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, - true, &l2c_link_sec_comp2, p_ccb); + true, &l2c_link_sec_comp, p_ccb); } else { p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP; btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, @@ -244,7 +252,7 @@ static void l2c_csm_closed(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) { if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) { p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP; l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, - true, &l2c_link_sec_comp2, p_ccb); + true, &l2c_link_sec_comp, p_ccb); } else { if (!BTM_SetLinkPolicyActiveMode(p_ccb->p_lcb->remote_bd_addr)) { LOG_WARN("Unable to set link policy active"); @@ -303,7 +311,7 @@ static void l2c_csm_closed(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) { p_ccb->chnl_state = CST_TERM_W4_SEC_COMP; tL2CAP_LE_RESULT_CODE result = l2ble_sec_access_req( p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, false, - &l2c_link_sec_comp2, p_ccb); + &l2c_link_sec_comp, p_ccb); switch (result) { case L2CAP_LE_RESULT_INSUFFICIENT_AUTHORIZATION: @@ -400,7 +408,7 @@ static void l2c_csm_orig_w4_sec_comp(tL2C_CCB* p_ccb, tL2CEVT event, case L2CEVT_LP_CONNECT_CFM: /* Link came up */ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) { l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, - false, &l2c_link_sec_comp2, p_ccb); + false, &l2c_link_sec_comp, p_ccb); } else { btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, true, &l2c_link_sec_comp, @@ -1292,6 +1300,9 @@ static void l2c_csm_open(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) { case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ LOG_DEBUG("Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + power_telemetry::GetInstance().LogChannelDisconnected( + p_ccb->p_rcb->psm, p_ccb->local_cid, p_ccb->remote_id, + p_ccb->p_lcb->remote_bd_addr); l2cu_release_ccb(p_ccb); if (p_ccb->p_rcb) (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, false); @@ -1360,15 +1371,25 @@ static void l2c_csm_open(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) { l2c_ccb_timer_timeout, p_ccb); LOG_DEBUG("Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid); + power_telemetry::GetInstance().LogChannelDisconnected( + p_ccb->p_rcb->psm, p_ccb->local_cid, p_ccb->remote_id, + p_ccb->p_lcb->remote_bd_addr); (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, true); l2c_csm_send_disconnect_rsp(p_ccb); break; case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ - if (p_data && (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb)) { - p_ccb->metrics.rx(static_cast(p_data)->len); - (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, - (BT_HDR*)p_data); + if (p_data && (p_ccb->p_rcb)) { + uint16_t package_len = ((BT_HDR*)p_data)->len; + if (p_ccb->p_rcb->api.pL2CA_DataInd_Cb) { + p_ccb->metrics.rx(static_cast(p_data)->len); + (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, + (BT_HDR*)p_data); + } + + power_telemetry::GetInstance().LogRxBytes( + p_ccb->p_rcb->psm, p_ccb->local_cid, p_ccb->remote_id, + p_ccb->p_lcb->remote_bd_addr, package_len); } break; @@ -1379,7 +1400,9 @@ static void l2c_csm_open(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) { LOG_WARN("Unable to set link policy active"); } } - + power_telemetry::GetInstance().LogChannelDisconnected( + p_ccb->p_rcb->psm, p_ccb->local_cid, p_ccb->remote_id, + p_ccb->p_lcb->remote_bd_addr); if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) l2cble_send_peer_disc_req(p_ccb); else @@ -1392,8 +1415,12 @@ static void l2c_csm_open(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) { case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ if (p_data) { + uint16_t package_len = ((BT_HDR*)p_data)->len; l2c_enqueue_peer_data(p_ccb, (BT_HDR*)p_data); l2c_link_check_send_pkts(p_ccb->p_lcb, 0, NULL); + power_telemetry::GetInstance().LogTxBytes( + p_ccb->p_rcb->psm, p_ccb->local_cid, p_ccb->remote_id, + p_ccb->p_lcb->remote_bd_addr, package_len); } break; diff --git a/system/stack/l2cap/l2c_fcr.cc b/system/stack/l2cap/l2c_fcr.cc index 665ed103c512e55effbbf39eccf43ea95192c316..ccbd2967fde22b7020b8a096dbc783ffc60b5934 100644 --- a/system/stack/l2cap/l2c_fcr.cc +++ b/system/stack/l2cap/l2c_fcr.cc @@ -28,9 +28,9 @@ #include #include -#include "common/time_util.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" #include "stack/include/l2c_api.h" @@ -348,7 +348,7 @@ static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, p_buf->len += L2CAP_FCS_LEN; if (is_retransmission) { - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "L2CAP eRTM ReTx I-frame CID: 0x%04x Len: %u SAR: %s TxSeq: %u " "ReqSeq: %u F: %u", p_ccb->local_cid, p_buf->len, @@ -357,7 +357,7 @@ static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); } else { - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "L2CAP eRTM Tx I-frame CID: 0x%04x Len: %u SAR: %-12s TxSeq: %u " "ReqSeq: %u F: %u", p_ccb->local_cid, p_buf->len, @@ -426,7 +426,7 @@ void l2c_fcr_send_S_frame(tL2C_CCB* p_ccb, uint16_t function_code, if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1) || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) { - L2CAP_TRACE_WARNING( + LOG_WARN( "L2CAP eRTM Tx S-frame CID: 0x%04x ctrlword: 0x%04x Type: %s " "ReqSeq: %u P: %u F: %u", p_ccb->local_cid, ctrl_word, @@ -434,9 +434,9 @@ void l2c_fcr_send_S_frame(tL2C_CCB* p_ccb, uint16_t function_code, (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT, (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); - L2CAP_TRACE_WARNING(" Buf Len: %u", p_buf->len); + LOG_WARN(" Buf Len: %u", p_buf->len); } else { - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "L2CAP eRTM Tx S-frame CID: 0x%04x ctrlword: 0x%04x Type: %s " "ReqSeq: %u P: %u F: %u", p_ccb->local_cid, ctrl_word, @@ -444,7 +444,7 @@ void l2c_fcr_send_S_frame(tL2C_CCB* p_ccb, uint16_t function_code, (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT, (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); - L2CAP_TRACE_EVENT(" Buf Len: %u", p_buf->len); + LOG_VERBOSE(" Buf Len: %u", p_buf->len); } l2c_link_check_send_pkts(p_ccb->p_lcb, 0, p_buf); @@ -477,8 +477,8 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { min_pdu_len = (uint16_t)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD); if (p_buf->len < min_pdu_len) { - L2CAP_TRACE_WARNING("Rx L2CAP PDU: CID: 0x%04x Len too short: %u", - p_ccb->local_cid, p_buf->len); + LOG_WARN("Rx L2CAP PDU: CID: 0x%04x Len too short: %u", p_ccb->local_cid, + p_buf->len); osi_free(p_buf); return; } @@ -491,7 +491,7 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1) || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) { /* REJ or SREJ */ - L2CAP_TRACE_WARNING( + LOG_WARN( "L2CAP eRTM Rx S-frame: cid: 0x%04x Len: %u Type: %s ReqSeq: %u " "P: %u F: %u", p_ccb->local_cid, p_buf->len, @@ -500,7 +500,7 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT, (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); } else { - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "L2CAP eRTM Rx S-frame: cid: 0x%04x Len: %u Type: %s ReqSeq: %u " "P: %u F: %u", p_ccb->local_cid, p_buf->len, @@ -510,7 +510,7 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); } } else { - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "L2CAP eRTM Rx I-frame: cid: 0x%04x Len: %u SAR: %-12s TxSeq: %u " "ReqSeq: %u F: %u", p_ccb->local_cid, p_buf->len, @@ -520,9 +520,9 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); } - L2CAP_TRACE_EVENT( + LOG_VERBOSE( " eRTM Rx Nxt_tx_seq %u, Lst_rx_ack %u, Nxt_seq_exp %u, Lst_ack_snt " - "%u, wt_q.cnt %u, tries %u", + "%u, wt_q.cnt %zu, tries %u", p_ccb->fcrb.next_tx_seq, p_ccb->fcrb.last_rx_ack, p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent, fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q), p_ccb->fcrb.num_tries); @@ -535,7 +535,7 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { p_buf->len -= L2CAP_FCS_LEN; if (l2c_fcr_rx_get_fcs(p_buf) != fcs) { - L2CAP_TRACE_WARNING("Rx L2CAP PDU: CID: 0x%04x BAD FCS", p_ccb->local_cid); + LOG_WARN("Rx L2CAP PDU: CID: 0x%04x BAD FCS", p_ccb->local_cid); osi_free(p_buf); return; } @@ -618,7 +618,7 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { STREAM_TO_UINT16(ctrl_word, p); - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "l2c_fcr_proc_pdu() CID: 0x%04x Process Buffer from SREJ_Hold_Q " "TxSeq: %u Expected_Seq: %u", p_ccb->local_cid, @@ -646,7 +646,7 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { (p_ccb->fcrb.next_seq_expected != p_ccb->fcrb.last_ack_sent)) l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, 0); else { - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "l2c_fcr_proc_pdu() not sending RR CID: 0x%04x local_busy:%d " "rej_sent:%d srej_sent:%d Expected_Seq:%u Last_Ack:%u", p_ccb->local_cid, 0, p_ccb->fcrb.rej_sent, p_ccb->fcrb.srej_sent, @@ -692,8 +692,8 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { if (p_ccb->is_first_seg) { if (p_buf->len < sizeof(sdu_length)) { - L2CAP_TRACE_ERROR("%s: buffer length=%d too small. Need at least 2.", - __func__, p_buf->len); + LOG_ERROR("%s: buffer length=%d too small. Need at least 2.", __func__, + p_buf->len); /* Discard the buffer */ osi_free(p_buf); return; @@ -714,7 +714,7 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { p_buf->offset += sizeof(sdu_length); if (sdu_length < p_buf->len) { - L2CAP_TRACE_ERROR("%s: Invalid sdu_length: %d", __func__, sdu_length); + LOG_ERROR("%s: Invalid sdu_length: %d", __func__, sdu_length); /* Discard the buffer */ osi_free(p_buf); return; @@ -729,7 +729,7 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { p_ccb->ble_sdu = p_data; p_data->len = 0; p_ccb->ble_sdu_length = sdu_length; - L2CAP_TRACE_DEBUG("%s SDU Length = %d", __func__, sdu_length); + LOG_VERBOSE("%s SDU Length = %d", __func__, sdu_length); p_data->offset = 0; } else { @@ -739,9 +739,8 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { return; } if (p_buf->len > (p_ccb->ble_sdu_length - p_data->len)) { - L2CAP_TRACE_ERROR("%s: buffer length=%d too big. max=%d. Dropped", - __func__, p_data->len, - (p_ccb->ble_sdu_length - p_data->len)); + LOG_ERROR("%s: buffer length=%d too big. max=%d. Dropped", __func__, + p_data->len, (p_ccb->ble_sdu_length - p_data->len)); osi_free(p_buf); /* Throw away all pending fragments and disconnects */ @@ -782,9 +781,9 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { ******************************************************************************/ void l2c_fcr_proc_tout(tL2C_CCB* p_ccb) { CHECK(p_ccb != NULL); - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "l2c_fcr_proc_tout: CID: 0x%04x num_tries: %u (max: %u) wait_ack: %u " - "ack_q_count: %u", + "ack_q_count: %zu", p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit, p_ccb->fcrb.wait_ack, fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q)); @@ -809,7 +808,7 @@ void l2c_fcr_proc_tout(tL2C_CCB* p_ccb) { ******************************************************************************/ void l2c_fcr_proc_ack_tout(tL2C_CCB* p_ccb) { CHECK(p_ccb != NULL); - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "l2c_fcr_proc_ack_tout: CID: 0x%04x State: %u Wack:%u Rq:%d Acked:%d", p_ccb->local_cid, p_ccb->chnl_state, p_ccb->fcrb.wait_ack, p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent); @@ -858,9 +857,9 @@ static bool process_reqseq(tL2C_CCB* p_ccb, uint16_t ctrl_word) { /* Verify the request sequence is in range before proceeding */ if (num_bufs_acked > fixed_queue_length(p_fcrb->waiting_for_ack_q)) { /* The channel is closed if ReqSeq is not in range */ - L2CAP_TRACE_WARNING( + LOG_WARN( "L2CAP eRTM Frame BAD Req_Seq - ctrl_word: 0x%04x req_seq 0x%02x " - "last_rx_ack: 0x%02x QCount: %u", + "last_rx_ack: 0x%02x QCount: %zu", ctrl_word, req_seq, p_fcrb->last_rx_ack, fixed_queue_length(p_fcrb->waiting_for_ack_q)); @@ -931,11 +930,11 @@ static void process_s_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, bool all_ok = true; if (p_buf->len != 0) { - L2CAP_TRACE_WARNING("Incorrect S-frame Length (%d)", p_buf->len); + LOG_WARN("Incorrect S-frame Length (%d)", p_buf->len); } - L2CAP_TRACE_DEBUG("process_s_frame ctrl_word 0x%04x fcrb_remote_busy:%d", - ctrl_word, p_fcrb->remote_busy); + LOG_VERBOSE("process_s_frame ctrl_word 0x%04x fcrb_remote_busy:%d", ctrl_word, + p_fcrb->remote_busy); if (ctrl_word & L2CAP_FCR_P_BIT) { p_fcrb->rej_sent = false; /* After checkpoint, we can send anoher REJ */ @@ -981,7 +980,7 @@ static void process_s_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, p_fcrb->send_f_rsp = false; } } else { - L2CAP_TRACE_DEBUG("process_s_frame hit_max_retries"); + LOG_VERBOSE("process_s_frame hit_max_retries"); } osi_free(p_buf); @@ -1023,13 +1022,13 @@ static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word, /* Is the frame a duplicate ? If so, just drop it */ if (num_lost >= p_ccb->our_cfg.fcr.tx_win_sz) { /* Duplicate - simply drop it */ - L2CAP_TRACE_WARNING( + LOG_WARN( "process_i_frame() Dropping Duplicate Frame tx_seq:%u ExpectedTxSeq " "%u", tx_seq, p_fcrb->next_seq_expected); osi_free(p_buf); } else { - L2CAP_TRACE_WARNING( + LOG_WARN( "process_i_frame() CID: 0x%04x Lost: %u tx_seq:%u ExpTxSeq %u " "Rej: %u SRej: %u", p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, @@ -1047,7 +1046,7 @@ static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word, if ((tx_seq == next_srej) && (fixed_queue_length(p_fcrb->srej_rcv_hold_q) < p_ccb->our_cfg.fcr.tx_win_sz)) { - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "process_i_frame() Lost: %u tx_seq:%u ExpTxSeq %u Rej: %u " "SRej1", num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent); @@ -1055,9 +1054,9 @@ static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word, p_buf->layer_specific = tx_seq; fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf); } else { - L2CAP_TRACE_WARNING( + LOG_WARN( "process_i_frame() CID: 0x%04x frame dropped in Srej Sent " - "next_srej:%u hold_q.count:%u win_sz:%u", + "next_srej:%u hold_q.count:%zu win_sz:%u", p_ccb->local_cid, next_srej, fixed_queue_length(p_fcrb->srej_rcv_hold_q), p_ccb->our_cfg.fcr.tx_win_sz); @@ -1066,7 +1065,7 @@ static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word, osi_free(p_buf); } } else if (p_fcrb->rej_sent) { - L2CAP_TRACE_WARNING( + LOG_WARN( "process_i_frame() CID: 0x%04x Lost: %u tx_seq:%u ExpTxSeq %u " "Rej: 1 SRej: %u", p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, @@ -1075,7 +1074,7 @@ static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word, /* If REJ sent, just drop the frame */ osi_free(p_buf); } else { - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "process_i_frame() CID: 0x%04x tx_seq:%u ExpTxSeq %u Rej: %u", p_ccb->local_cid, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent); @@ -1087,9 +1086,9 @@ static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word, l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_REJ, 0); } else { if (!fixed_queue_is_empty(p_fcrb->srej_rcv_hold_q)) { - L2CAP_TRACE_ERROR( + LOG_ERROR( "process_i_frame() CID: 0x%04x sending SREJ tx_seq:%d " - "hold_q.count:%u", + "hold_q.count:%zu", p_ccb->local_cid, tx_seq, fixed_queue_length(p_fcrb->srej_rcv_hold_q)); } @@ -1115,8 +1114,8 @@ static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word, /* If any SAR problem in eRTM mode, spec says disconnect. */ if (!do_sar_reassembly(p_ccb, p_buf, ctrl_word)) { - L2CAP_TRACE_WARNING("process_i_frame() CID: 0x%04x reassembly failed", - p_ccb->local_cid); + LOG_WARN("process_i_frame() CID: 0x%04x reassembly failed", + p_ccb->local_cid); l2cu_disconnect_chnl(p_ccb); return; } @@ -1168,7 +1167,7 @@ static bool do_sar_reassembly(tL2C_CCB* p_ccb, BT_HDR* p_buf, /* Check if the SAR state is correct */ if ((sar_type == L2CAP_FCR_UNSEG_SDU) || (sar_type == L2CAP_FCR_START_SDU)) { if (p_fcrb->p_rx_sdu != NULL) { - L2CAP_TRACE_WARNING( + LOG_WARN( "SAR - got unexpected unsegmented or start SDU Expected len: %u " "Got so far: %u", p_fcrb->rx_sdu_len, p_fcrb->p_rx_sdu->len); @@ -1178,12 +1177,12 @@ static bool do_sar_reassembly(tL2C_CCB* p_ccb, BT_HDR* p_buf, /* Check the length of the packet */ if ((sar_type == L2CAP_FCR_START_SDU) && (p_buf->len < L2CAP_SDU_LEN_OVERHEAD)) { - L2CAP_TRACE_WARNING("SAR start packet too short: %u", p_buf->len); + LOG_WARN("SAR start packet too short: %u", p_buf->len); packet_ok = false; } } else { if (p_fcrb->p_rx_sdu == NULL) { - L2CAP_TRACE_WARNING("SAR - got unexpected cont or end SDU"); + LOG_WARN("SAR - got unexpected cont or end SDU"); packet_ok = false; } } @@ -1199,8 +1198,8 @@ static bool do_sar_reassembly(tL2C_CCB* p_ccb, BT_HDR* p_buf, p_buf->len -= 2; if (p_fcrb->rx_sdu_len > p_ccb->max_rx_mtu) { - L2CAP_TRACE_WARNING("SAR - SDU len: %u larger than MTU: %u", - p_fcrb->rx_sdu_len, p_ccb->max_rx_mtu); + LOG_WARN("SAR - SDU len: %u larger than MTU: %u", p_fcrb->rx_sdu_len, + p_ccb->max_rx_mtu); packet_ok = false; } else { p_fcrb->p_rx_sdu = (BT_HDR*)osi_malloc( @@ -1212,15 +1211,14 @@ static bool do_sar_reassembly(tL2C_CCB* p_ccb, BT_HDR* p_buf, if (packet_ok) { if ((p_fcrb->p_rx_sdu->len + p_buf->len) > p_fcrb->rx_sdu_len) { - L2CAP_TRACE_ERROR( - "SAR - SDU len exceeded Type: %u Lengths: %u %u %u", sar_type, - p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len); + LOG_ERROR("SAR - SDU len exceeded Type: %u Lengths: %u %u %u", + sar_type, p_fcrb->p_rx_sdu->len, p_buf->len, + p_fcrb->rx_sdu_len); packet_ok = false; } else if ((sar_type == L2CAP_FCR_END_SDU) && ((p_fcrb->p_rx_sdu->len + p_buf->len) != p_fcrb->rx_sdu_len)) { - L2CAP_TRACE_WARNING("SAR - SDU end rcvd but SDU incomplete: %u %u %u", - p_fcrb->p_rx_sdu->len, p_buf->len, - p_fcrb->rx_sdu_len); + LOG_WARN("SAR - SDU end rcvd but SDU incomplete: %u %u %u", + p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len); packet_ok = false; } else { memcpy(((uint8_t*)(p_fcrb->p_rx_sdu + 1)) + p_fcrb->p_rx_sdu->offset + @@ -1278,9 +1276,9 @@ static bool retransmit_i_frames(tL2C_CCB* p_ccb, uint8_t tx_seq) { if ((!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q)) && (p_ccb->peer_cfg.fcr.max_transmit != 0) && (p_ccb->fcrb.num_tries >= p_ccb->peer_cfg.fcr.max_transmit)) { - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "Max Tries Exceeded: (last_acq: %d CID: 0x%04x num_tries: %u (max: " - "%u) ack_q_count: %u", + "%u) ack_q_count: %zu", p_ccb->fcrb.last_rx_ack, p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit, fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q)); @@ -1311,18 +1309,16 @@ static bool retransmit_i_frames(tL2C_CCB* p_ccb, uint8_t tx_seq) { buf_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT; - L2CAP_TRACE_DEBUG( - "retransmit_i_frames() cur seq: %u looking for: %u", buf_seq, - tx_seq); + LOG_VERBOSE("retransmit_i_frames() cur seq: %u looking for: %u", + buf_seq, tx_seq); if (tx_seq == buf_seq) break; } } if (!p_buf) { - L2CAP_TRACE_ERROR("retransmit_i_frames() UNKNOWN seq: %u q_count: %u", - tx_seq, - fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q)); + LOG_ERROR("retransmit_i_frames() UNKNOWN seq: %u q_count: %zu", tx_seq, + fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q)); return (true); } } else { @@ -1442,8 +1438,8 @@ BT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb, } else /* Should never happen if the application has configured buffers correctly */ { - L2CAP_TRACE_ERROR( - "L2CAP - cannot get buffer for segmentation, max_pdu: %u", max_pdu); + LOG_ERROR("L2CAP - cannot get buffer for segmentation, max_pdu: %u", + max_pdu); return (NULL); } } else /* Use the original buffer if no segmentation, or the last segment */ @@ -1498,9 +1494,8 @@ BT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb, l2c_fcr_clone_buf(p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len); if (!p_wack) { - L2CAP_TRACE_ERROR( - "L2CAP - no buffer for xmit cloning, CID: 0x%04x Length: %u", - p_ccb->local_cid, p_xmit->len); + LOG_ERROR("L2CAP - no buffer for xmit cloning, CID: 0x%04x Length: %u", + p_ccb->local_cid, p_xmit->len); /* We will not save the FCS in case we reconfigure and change options */ p_xmit->len -= L2CAP_FCS_LEN; @@ -1604,8 +1599,7 @@ uint8_t l2c_fcr_chk_chan_modes(tL2C_CCB* p_ccb) { /* Remove nonbasic options that the peer does not support */ if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_ENH_RETRANS) && p_ccb->p_rcb->ertm_info.preferred_mode == L2CAP_FCR_ERTM_MODE) { - L2CAP_TRACE_WARNING( - "L2CAP - Peer does not support our desired channel types"); + LOG_WARN("L2CAP - Peer does not support our desired channel types"); p_ccb->p_rcb->ertm_info.preferred_mode = 0; return false; } @@ -1641,7 +1635,7 @@ void l2c_fcr_adj_monitor_retran_timeout(tL2C_CCB* p_ccb) { p_ccb->our_cfg.fcr.rtrans_tout = 0; } - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "l2c_fcr_adj_monitor_retran_timeout: mon_tout:%d, rtrans_tout:%d", p_ccb->our_cfg.fcr.mon_tout, p_ccb->our_cfg.fcr.rtrans_tout); } @@ -1672,9 +1666,8 @@ void l2c_fcr_adj_our_rsp_options(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { * adjust it. For now, respond with our own tx_wnd_sz. */ /* Note: peer is not guaranteed to obey our adjustment */ if (p_ccb->peer_cfg.fcr.tx_win_sz > p_ccb->our_cfg.fcr.tx_win_sz) { - L2CAP_TRACE_DEBUG("%s: adjusting requested tx_win_sz from %i to %i", - __func__, p_ccb->peer_cfg.fcr.tx_win_sz, - p_ccb->our_cfg.fcr.tx_win_sz); + LOG_VERBOSE("%s: adjusting requested tx_win_sz from %i to %i", __func__, + p_ccb->peer_cfg.fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz); p_ccb->peer_cfg.fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz; } @@ -1718,7 +1711,7 @@ bool l2c_fcr_renegotiate_chan(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { if (p_ccb->our_cfg.fcr.mode != peer_mode) { if ((--p_ccb->fcr_cfg_tries) == 0) { p_cfg->result = L2CAP_CFG_FAILED_NO_REASON; - L2CAP_TRACE_WARNING("l2c_fcr_renegotiate_chan (Max retries exceeded)"); + LOG_WARN("l2c_fcr_renegotiate_chan (Max retries exceeded)"); } can_renegotiate = false; @@ -1729,7 +1722,7 @@ bool l2c_fcr_renegotiate_chan(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { case L2CAP_FCR_ERTM_MODE: /* We can try basic for any other peer mode because it's always * supported */ - L2CAP_TRACE_DEBUG("%s(Trying Basic)", __func__); + LOG_VERBOSE("%s(Trying Basic)", __func__); can_renegotiate = true; p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE; break; @@ -1748,7 +1741,7 @@ bool l2c_fcr_renegotiate_chan(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { /* Basic Mode uses ACL Data Pool, make sure the MTU fits */ if ((p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE)) { - L2CAP_TRACE_WARNING("L2CAP - adjust MTU: %u too large", p_cfg->mtu); + LOG_WARN("L2CAP - adjust MTU: %u too large", p_cfg->mtu); p_cfg->mtu = L2CAP_MTU_SIZE; } } @@ -1764,8 +1757,8 @@ bool l2c_fcr_renegotiate_chan(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { /* Disconnect if the channels do not match */ if (p_ccb->our_cfg.fcr.mode != peer_mode) { - L2CAP_TRACE_WARNING("L2C CFG: Channels incompatible (local %d, peer %d)", - p_ccb->our_cfg.fcr.mode, peer_mode); + LOG_WARN("L2C CFG: Channels incompatible (local %d, peer %d)", + p_ccb->our_cfg.fcr.mode, peer_mode); l2cu_disconnect_chnl(p_ccb); } @@ -1793,7 +1786,7 @@ uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { p_ccb->p_lcb->w4_info_rsp = false; /* Handles T61x SonyEricsson Bug in Info Request */ - L2CAP_TRACE_EVENT( + LOG_VERBOSE( "l2c_fcr_process_peer_cfg_req() CFG fcr_present:%d fcr.mode:%d CCB FCR " "mode:%d preferred: %u", p_cfg->fcr_present, p_cfg->fcr.mode, p_ccb->our_cfg.fcr.mode, @@ -1852,8 +1845,8 @@ uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { /* Ensure the MPS is not bigger than our retransmission buffer */ if (p_cfg->fcr.mps > max_retrans_size) { - L2CAP_TRACE_DEBUG("CFG: Overriding MPS to %d (orig %d)", - max_retrans_size, p_cfg->fcr.mps); + LOG_VERBOSE("CFG: Overriding MPS to %d (orig %d)", max_retrans_size, + p_cfg->fcr.mps); p_cfg->fcr.mps = max_retrans_size; p_ccb->out_cfg_fcr_present = true; diff --git a/system/stack/l2cap/l2c_int.h b/system/stack/l2cap/l2c_int.h index 14a0a20202d182f5b416fc9de7cce80466013097..778261acb7eb3342ab774057eae0cc7c86699753 100644 --- a/system/stack/l2cap/l2c_int.h +++ b/system/stack/l2cap/l2c_int.h @@ -29,18 +29,15 @@ #include -#include "btm_api.h" -#include "btm_ble_api.h" +#include "internal_include/bt_target.h" #include "l2c_api.h" -#include "l2cap_acl_interface.h" -#include "l2cap_controller_interface.h" -#include "l2cap_hci_link_interface.h" -#include "l2cap_security_interface.h" #include "l2cdefs.h" +#include "macros.h" #include "osi/include/alarm.h" #include "osi/include/fixed_queue.h" #include "osi/include/list.h" #include "stack/include/bt_hdr.h" +#include "stack/include/btm_sec_api_types.h" #include "stack/include/hci_error_code.h" #include "types/hci_role.h" #include "types/raw_address.h" @@ -85,10 +82,6 @@ typedef enum { CST_W4_L2CA_DISCONNECT_RSP /* Waiting for upper layer disc rsp */ } tL2C_CHNL_STATE; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string channel_state_text(const tL2C_CHNL_STATE& state) { switch (state) { CASE_RETURN_TEXT(CST_CLOSED); @@ -104,7 +97,6 @@ inline std::string channel_state_text(const tL2C_CHNL_STATE& state) { return base::StringPrintf("UNKNOWN[%d]", state); } } -#undef CASE_RETURN_TEXT /* Define the possible L2CAP link states */ @@ -271,15 +263,11 @@ typedef struct { #define L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA 100 #endif -typedef void(tL2CAP_SEC_CBACK)(const RawAddress& bd_addr, - tBT_TRANSPORT trasnport, void* p_ref_data, - tBTM_STATUS result); - typedef struct { uint16_t psm; tBT_TRANSPORT transport; bool is_originator; - tL2CAP_SEC_CBACK* p_callback; + tBTM_SEC_CALLBACK* p_callback; void* p_ref_data; } tL2CAP_SEC_DATA; @@ -590,7 +578,6 @@ typedef struct t_l2c_linkcb { /* Define the L2CAP control structure */ typedef struct { - uint8_t l2cap_trace_level; uint16_t controller_xmit_window; /* Total ACL window for all links */ uint16_t round_robin_quota; /* Round-robin link quota */ @@ -719,7 +706,8 @@ void l2cu_enqueue_ccb(tL2C_CCB* p_ccb); void l2cu_dequeue_ccb(tL2C_CCB* p_ccb); void l2cu_change_pri_ccb(tL2C_CCB* p_ccb, tL2CAP_CHNL_PRIORITY priority); -tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid); +tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid, + bool is_eatt = false); void l2cu_release_ccb(tL2C_CCB* p_ccb); tL2C_CCB* l2cu_find_ccb_by_cid(tL2C_LCB* p_lcb, uint16_t local_cid); tL2C_CCB* l2cu_find_ccb_by_remote_cid(tL2C_LCB* p_lcb, uint16_t remote_cid); @@ -817,8 +805,6 @@ void l2c_link_adjust_allocation(void); void l2c_link_sec_comp(const RawAddress* p_bda, tBT_TRANSPORT trasnport, void* p_ref_data, tBTM_STATUS status); -void l2c_link_sec_comp2(const RawAddress& p_bda, tBT_TRANSPORT trasnport, - void* p_ref_data, tBTM_STATUS status); void l2c_link_adjust_chnl_allocation(void); #if (L2CAP_CONFORMANCE_TESTING == TRUE) @@ -873,7 +859,7 @@ void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb); void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb, uint16_t credit_value); tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm, bool is_originator, - tL2CAP_SEC_CBACK* p_callback, + tBTM_SEC_CALLBACK* p_callback, void* p_ref_data); void l2cble_update_data_length(tL2C_LCB* p_lcb); diff --git a/system/stack/l2cap/l2c_link.cc b/system/stack/l2cap/l2c_link.cc index 8ae0f2327df1e1ce5552e662c68c866a3d59a14c..9cf7d74496831986e56584e23656520551eb1c8f 100644 --- a/system/stack/l2cap/l2c_link.cc +++ b/system/stack/l2cap/l2c_link.cc @@ -28,16 +28,18 @@ #include #include "device/include/device_iot_config.h" -#include "main/shim/l2c_api.h" -#include "main/shim/shim.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "stack/btm/btm_int_types.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" #include "stack/include/hci_error_code.h" +#include "stack/include/l2cap_acl_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" @@ -51,97 +53,14 @@ tBTM_STATUS btm_sec_disconnect(uint16_t handle, tHCI_STATUS reason, void btm_acl_created(const RawAddress& bda, uint16_t hci_handle, uint8_t link_role, tBT_TRANSPORT transport); void btm_acl_removed(uint16_t handle); -void btm_acl_set_paging(bool value); void btm_ble_decrement_link_topology_mask(uint8_t link_role); void btm_sco_acl_removed(const RawAddress* bda); static void l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf); static BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb); -/******************************************************************************* - * - * Function l2c_link_hci_conn_req - * - * Description This function is called when an HCI Connection Request - * event is received. - * - ******************************************************************************/ -void l2c_link_hci_conn_req(const RawAddress& bd_addr) { - tL2C_LCB* p_lcb; - tL2C_LCB* p_lcb_cur; - int xx; - bool no_links; - - /* See if we have a link control block for the remote device */ - p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR); - - /* If we don't have one, create one and accept the connection. */ - if (!p_lcb) { - p_lcb = l2cu_allocate_lcb(bd_addr, false, BT_TRANSPORT_BR_EDR); - if (!p_lcb) { - btsnd_hcic_reject_conn(bd_addr, HCI_ERR_HOST_REJECT_RESOURCES); - LOG_ERROR("L2CAP failed to allocate LCB"); - return; - } - - no_links = true; - - /* If we already have connection, accept as a central */ - for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; - xx++, p_lcb_cur++) { - if (p_lcb_cur == p_lcb) continue; - - if (p_lcb_cur->in_use) { - no_links = false; - p_lcb->SetLinkRoleAsCentral(); - break; - } - } - - if (no_links) { - if (!btm_dev_support_role_switch(bd_addr)) - p_lcb->SetLinkRoleAsPeripheral(); - else - p_lcb->SetLinkRoleAsCentral(); - } - - /* Tell the other side we accept the connection */ - acl_accept_connection_request(bd_addr, p_lcb->LinkRole()); - - p_lcb->link_state = LST_CONNECTING; - - /* Start a timer waiting for connect complete */ - alarm_set_on_mloop(p_lcb->l2c_lcb_timer, L2CAP_LINK_CONNECT_TIMEOUT_MS, - l2c_lcb_timer_timeout, p_lcb); - return; - } - - /* We already had a link control block. Check what state it is in - */ - if ((p_lcb->link_state == LST_CONNECTING) || - (p_lcb->link_state == LST_CONNECT_HOLDING)) { - if (!btm_dev_support_role_switch(bd_addr)) - p_lcb->SetLinkRoleAsPeripheral(); - else - p_lcb->SetLinkRoleAsCentral(); - - acl_accept_connection_request(bd_addr, p_lcb->LinkRole()); - - p_lcb->link_state = LST_CONNECTING; - } else if (p_lcb->link_state == LST_DISCONNECTING) { - acl_reject_connection_request(bd_addr, HCI_ERR_HOST_REJECT_DEVICE); - } else { - LOG_ERROR("L2CAP got conn_req while connected (state:%d). Reject it", - p_lcb->link_state); - acl_reject_connection_request(bd_addr, HCI_ERR_CONNECTION_EXISTS); - } -} - void l2c_link_hci_conn_comp(tHCI_STATUS status, uint16_t handle, const RawAddress& p_bda) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return; - } tL2C_CONN_INFO ci; tL2C_LCB* p_lcb; tL2C_CCB* p_ccb; @@ -265,19 +184,13 @@ void l2c_link_hci_conn_comp(tHCI_STATUS status, uint16_t handle, void l2c_link_sec_comp(const RawAddress* p_bda, UNUSED_ATTR tBT_TRANSPORT transport, void* p_ref_data, tBTM_STATUS status) { - l2c_link_sec_comp2(*p_bda, transport, p_ref_data, status); -} - -void l2c_link_sec_comp2(const RawAddress& p_bda, - UNUSED_ATTR tBT_TRANSPORT transport, void* p_ref_data, - tBTM_STATUS status) { tL2C_CONN_INFO ci; tL2C_LCB* p_lcb; tL2C_CCB* p_ccb; tL2C_CCB* p_next_ccb; LOG_DEBUG("btm_status=%s, BD_ADDR=%s, transport=%s", - btm_status_text(status).c_str(), ADDRESS_TO_LOGGABLE_CSTR(p_bda), + btm_status_text(status).c_str(), ADDRESS_TO_LOGGABLE_CSTR(*p_bda), bt_transport_text(transport).c_str()); if (status == BTM_SUCCESS_NO_SECURITY) { @@ -286,9 +199,9 @@ void l2c_link_sec_comp2(const RawAddress& p_bda, /* Save the parameters */ ci.status = status; - ci.bd_addr = p_bda; + ci.bd_addr = *p_bda; - p_lcb = l2cu_find_lcb_by_bd_addr(p_bda, transport); + p_lcb = l2cu_find_lcb_by_bd_addr(*p_bda, transport); /* If we don't have one, this is an error */ if (!p_lcb) { @@ -318,7 +231,6 @@ void l2c_link_sec_comp2(const RawAddress& p_bda, l2c_csm_execute(p_ccb, L2CEVT_SEC_COMP_NEG, &ci); break; } - break; } } } @@ -364,10 +276,6 @@ static void l2c_link_iot_store_disc_reason(RawAddress& bda, uint8_t reason) { * ******************************************************************************/ bool l2c_link_hci_disc_comp(uint16_t handle, tHCI_REASON reason) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return false; - } - tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle); tL2C_CCB* p_ccb; bool status = true; @@ -769,11 +677,6 @@ void l2c_link_adjust_chnl_allocation(void) { } void l2c_link_init(const uint16_t acl_buffer_count_classic) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - // GD L2cap gets this info through GD ACL - return; - } - l2cb.num_lm_acl_bufs = acl_buffer_count_classic; l2cb.controller_xmit_window = acl_buffer_count_classic; } @@ -1056,7 +959,7 @@ void l2c_OnHciModeChangeSendPendingPackets(RawAddress remote) { if (p_lcb != NULL) { /* There might be any pending packets due to SNIFF or PENDING state */ /* Trigger L2C to start transmission of the pending packets. */ - BTM_TRACE_DEBUG( + LOG_VERBOSE( "btm mode change to active; check l2c_link for outgoing packets"); l2c_link_check_send_pkts(p_lcb, 0, NULL); } @@ -1197,11 +1100,6 @@ void l2c_link_segments_xmitted(BT_HDR* p_msg) { } tBTM_STATUS l2cu_ConnectAclForSecurity(const RawAddress& bd_addr) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - bluetooth::shim::L2CA_ConnectForSecurity(bd_addr); - return BTM_SUCCESS; - } - 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)) { @@ -1217,7 +1115,6 @@ tBTM_STATUS l2cu_ConnectAclForSecurity(const RawAddress& bd_addr) { } l2cu_create_conn_br_edr(p_lcb); - btm_acl_set_paging(true); return BTM_SUCCESS; } diff --git a/system/stack/l2cap/l2c_main.cc b/system/stack/l2cap/l2c_main.cc index a273422e21e7fddb9dd7d07c0de88eca9b10ef3d..588ba3989d4cddb8f4257d83a1fdb80652e93b0f 100644 --- a/system/stack/l2cap/l2c_main.cc +++ b/system/stack/l2cap/l2c_main.cc @@ -26,15 +26,18 @@ #include -#include "bt_target.h" +#include "common/init_flags.h" #include "gd/hal/snoop_logger.h" #include "hcimsgs.h" // HCID_GET_ -#include "main/shim/shim.h" +#include "internal_include/bt_target.h" +#include "main/shim/entry.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/bt_types.h" #include "stack/include/l2c_api.h" +#include "stack/include/l2cap_hci_link_interface.h" #include "stack/include/l2cdefs.h" #include "stack/l2cap/l2c_int.h" @@ -70,7 +73,7 @@ void l2c_rcv_acl_data(BT_HDR* p_msg) { /* Since the HCI Transport is putting segmented packets back together, we */ /* should never get a valid packet with the type set to "continuation" */ if (pkt_type == L2CAP_PKT_CONTINUE) { - L2CAP_TRACE_WARNING("L2CAP - received packet continuation"); + LOG_WARN("L2CAP - received packet continuation"); osi_free(p_msg); return; } @@ -79,7 +82,7 @@ void l2c_rcv_acl_data(BT_HDR* p_msg) { STREAM_TO_UINT16(hci_len, p); if (hci_len < L2CAP_PKT_OVERHEAD || hci_len != p_msg->len - 4) { /* Remote-declared packet size must match HCI_ACL size - ACL header (4) */ - L2CAP_TRACE_WARNING("L2CAP - got incorrect hci header"); + LOG_WARN("L2CAP - got incorrect hci header"); osi_free(p_msg); return; } @@ -114,7 +117,7 @@ void l2c_rcv_acl_data(BT_HDR* p_msg) { if (rcv_cid >= L2CAP_BASE_APPL_CID) { p_ccb = l2cu_find_ccb_by_cid(p_lcb, rcv_cid); if (!p_ccb) { - L2CAP_TRACE_WARNING("L2CAP - unknown CID: 0x%04x", rcv_cid); + LOG_WARN("L2CAP - unknown CID: 0x%04x", rcv_cid); osi_free(p_msg); return; } @@ -124,8 +127,8 @@ void l2c_rcv_acl_data(BT_HDR* p_msg) { p_msg->offset += L2CAP_PKT_OVERHEAD; if (l2cap_len != p_msg->len) { - L2CAP_TRACE_WARNING("L2CAP - bad length in pkt. Exp: %d Act: %d", - l2cap_len, p_msg->len); + LOG_WARN("L2CAP - bad length in pkt. Exp: %d Act: %d", l2cap_len, + p_msg->len); osi_free(p_msg); return; } @@ -287,7 +290,8 @@ static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { break; } - LOG_DEBUG("cmd_code: %d, id:%d, cmd_len:%d", cmd_code, id, cmd_len); + LOG_DEBUG("cmd: %s, id:%d, cmd_len:%d", + l2cap_command_code_text(cmd_code).c_str(), id, cmd_len); /* Bad L2CAP packet length, look for cmd to reject */ if (pkt_size_rej) { @@ -833,11 +837,6 @@ static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { * ******************************************************************************/ void l2c_init(void) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - // L2CAP init should be handled by GD stack manager - return; - } - int16_t xx; memset(&l2cb, 0, sizeof(tL2C_CB)); @@ -859,12 +858,6 @@ void l2c_init(void) { /* Set the default idle timeout */ l2cb.idle_timeout = L2CAP_LINK_INACTIVITY_TOUT; -#if defined(L2CAP_INITIAL_TRACE_LEVEL) - l2cb.l2cap_trace_level = L2CAP_INITIAL_TRACE_LEVEL; -#else - l2cb.l2cap_trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ -#endif - #if (L2CAP_CONFORMANCE_TESTING == TRUE) /* Conformance testing needs a dynamic response */ l2cb.test_info_resp = L2CAP_EXTFEA_SUPPORTED_MASK; @@ -877,12 +870,7 @@ void l2c_init(void) { L2CAP_FIXED_CHNL_SMP_BIT; } -void l2c_free(void) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - // L2CAP cleanup should be handled by GD stack manager - return; - } -} +void l2c_free(void) {} void l2c_ccb_timer_timeout(void* data) { tL2C_CCB* p_ccb = (tL2C_CCB*)data; @@ -918,7 +906,7 @@ uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flags) { /* Find the channel control block. We don't know the link it is on. */ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, cid); if (!p_ccb) { - L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid); + LOG_WARN("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid); osi_free(p_data); return (L2CAP_DW_FAILED); } @@ -932,7 +920,7 @@ uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flags) { mtu = p_ccb->peer_cfg.mtu; if (p_data->len > mtu) { - L2CAP_TRACE_WARNING( + LOG_WARN( "L2CAP - CID: 0x%04x cannot send message bigger than peer's mtu size: " "len=%u mtu=%u", cid, p_data->len, mtu); @@ -945,9 +933,9 @@ uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flags) { /* If already congested, do not accept any more packets */ if (p_ccb->cong_sent) { - L2CAP_TRACE_ERROR( + LOG_ERROR( "L2CAP - CID: 0x%04x cannot send, already congested " - "xmit_hold_q.count: %u buff_quota: %u", + "xmit_hold_q.count: %zu buff_quota: %u", p_ccb->local_cid, fixed_queue_length(p_ccb->xmit_hold_q), p_ccb->buff_quota); diff --git a/system/stack/l2cap/l2c_utils.cc b/system/stack/l2cap/l2c_utils.cc index e02a9470b834b1ac701e0a27378da9d3ffa606f1..7b722f426a233bfb9d23d0bf18e6bc81dc78cf9e 100644 --- a/system/stack/l2cap/l2c_utils.cc +++ b/system/stack/l2cap/l2c_utils.cc @@ -29,17 +29,20 @@ #include "device/include/controller.h" #include "gd/hal/snoop_logger.h" -#include "main/shim/l2c_api.h" -#include "main/shim/shim.h" +#include "internal_include/bt_target.h" +#include "main/shim/entry.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/btm/btm_sec.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" #include "stack/include/btm_api.h" #include "stack/include/hci_error_code.h" #include "stack/include/hcidefs.h" #include "stack/include/l2c_api.h" +#include "stack/include/l2cap_acl_interface.h" +#include "stack/include/l2cap_hci_link_interface.h" #include "stack/include/l2cdefs.h" #include "stack/l2cap/l2c_int.h" #include "types/raw_address.h" @@ -121,11 +124,6 @@ void l2cu_set_lcb_handle(struct t_l2c_linkcb& p_lcb, uint16_t handle) { * ******************************************************************************/ void l2cu_update_lcb_4_bonding(const RawAddress& p_bd_addr, bool is_bonding) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - bluetooth::shim::L2CA_SetBondingState(p_bd_addr, is_bonding); - return; - } - tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR); if (p_lcb) { @@ -219,7 +217,7 @@ void l2cu_release_lcb(tL2C_LCB* p_lcb) { tL2CAP_SEC_DATA* p_buf = (tL2CAP_SEC_DATA*)fixed_queue_try_dequeue(p_lcb->le_sec_pending_q); if (p_buf->p_callback) - p_buf->p_callback(p_lcb->remote_bd_addr, p_lcb->transport, + p_buf->p_callback(&p_lcb->remote_bd_addr, p_lcb->transport, p_buf->p_ref_data, BTM_DEV_RESET); osi_free(p_buf); } @@ -279,7 +277,7 @@ bool l2c_is_cmd_rejected(uint8_t cmd_code, uint8_t signal_id, tL2C_LCB* p_lcb) { case L2CAP_CMD_BLE_UPDATE_REQ: l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_MTU_EXCEEDED, signal_id, L2CAP_DEFAULT_MTU, 0); - L2CAP_TRACE_WARNING("Dumping first Command (%d)", cmd_code); + LOG_WARN("Dumping first Command (%d)", cmd_code); return true; default: /* Otherwise a response */ @@ -374,7 +372,7 @@ void l2cu_send_peer_cmd_reject(tL2C_LCB* p_lcb, uint16_t reason, uint8_t rem_id, p_buf = l2cu_build_header(p_lcb, (uint16_t)(L2CAP_CMD_REJECT_LEN + param_len), L2CAP_CMD_REJECT, rem_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer cmd_rej"); + LOG_WARN("L2CAP - no buffer cmd_rej"); return; } @@ -413,7 +411,7 @@ void l2cu_send_peer_connect_req(tL2C_CCB* p_ccb) { p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_CONN_REQ_LEN, L2CAP_CMD_CONN_REQ, p_ccb->local_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_req"); + LOG_WARN("L2CAP - no buffer for conn_req"); return; } @@ -485,7 +483,7 @@ void l2cu_reject_connection(tL2C_LCB* p_lcb, uint16_t remote_cid, p_buf = l2cu_build_header(p_lcb, L2CAP_CONN_RSP_LEN, L2CAP_CMD_CONN_RSP, rem_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_req"); + LOG_WARN("L2CAP - no buffer for conn_req"); return; } @@ -530,15 +528,15 @@ void l2cu_send_credit_based_reconfig_req(tL2C_CCB* p_ccb, p_buf = l2cu_build_header(p_lcb, cmd_len, L2CAP_CMD_CREDIT_BASED_RECONFIG_REQ, p_lcb->signal_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_send_reconfig_req - no buffer"); + LOG_WARN("l2cu_send_reconfig_req - no buffer"); return; } p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; - L2CAP_TRACE_DEBUG("l2cu_send_reconfig_req number of cids: %d mtu:%d mps:%d", - p_lcb->pending_ecoc_reconfig_cnt, p_cfg->mtu, p_cfg->mps); + LOG_VERBOSE("l2cu_send_reconfig_req number of cids: %d mtu:%d mps:%d", + p_lcb->pending_ecoc_reconfig_cnt, p_cfg->mtu, p_cfg->mps); UINT16_TO_STREAM(p, p_cfg->mtu); UINT16_TO_STREAM(p, p_cfg->mps); @@ -591,7 +589,7 @@ void l2cu_send_peer_config_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { (uint16_t)(L2CAP_CONFIG_REQ_LEN + cfg_len), L2CAP_CMD_CONFIG_REQ, p_ccb->local_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_req"); + LOG_WARN("L2CAP - no buffer for conn_req"); return; } @@ -685,7 +683,7 @@ void l2cu_send_peer_config_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { (uint16_t)(L2CAP_CONFIG_RSP_LEN + cfg_len), L2CAP_CMD_CONFIG_RSP, p_ccb->remote_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_req"); + LOG_WARN("L2CAP - no buffer for conn_req"); return; } @@ -760,15 +758,14 @@ void l2cu_send_peer_config_rej(tL2C_CCB* p_ccb, uint8_t* p_data, uint8_t *p, *p_hci_len, *p_data_end; uint8_t cfg_code; - L2CAP_TRACE_DEBUG("l2cu_send_peer_config_rej: data_len=%d, rej_len=%d", - data_len, rej_len); + LOG_VERBOSE("l2cu_send_peer_config_rej: data_len=%d, rej_len=%d", data_len, + rej_len); len = BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN; len1 = 0xFFFF - len; if (rej_len > len1) { - L2CAP_TRACE_ERROR( - "L2CAP - cfg_rej pkt size exceeds buffer design max limit."); + LOG_ERROR("L2CAP - cfg_rej pkt size exceeds buffer design max limit."); return; } @@ -835,7 +832,7 @@ void l2cu_send_peer_config_rej(tL2C_CCB* p_ccb, uint8_t* p_data, p += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; buf_space -= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD); } else { - L2CAP_TRACE_WARNING("L2CAP - cfg_rej exceeds allocated buffer"); + LOG_WARN("L2CAP - cfg_rej exceeds allocated buffer"); p_data = p_data_end; /* force loop exit */ break; } @@ -855,8 +852,8 @@ void l2cu_send_peer_config_rej(tL2C_CCB* p_ccb, uint8_t* p_data, p_buf->len = len + 4; - L2CAP_TRACE_DEBUG("L2CAP - cfg_rej pkt hci_len=%d, l2cap_len=%d", len, - (L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN + rej_len)); + LOG_VERBOSE("L2CAP - cfg_rej pkt hci_len=%d, l2cap_len=%d", len, + (L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN + rej_len)); l2c_link_check_send_pkts(p_ccb->p_lcb, 0, p_buf); } @@ -876,7 +873,7 @@ void l2cu_send_peer_disc_req(tL2C_CCB* p_ccb) { uint8_t* p; if ((!p_ccb) || (p_ccb->p_lcb == NULL)) { - L2CAP_TRACE_ERROR("%s L2CAP - ccb or lcb invalid", __func__); + LOG_ERROR("%s L2CAP - ccb or lcb invalid", __func__); return; } @@ -889,7 +886,7 @@ void l2cu_send_peer_disc_req(tL2C_CCB* p_ccb) { p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_DISC_REQ_LEN, L2CAP_CMD_DISC_REQ, p_ccb->local_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for disc_req"); + LOG_WARN("L2CAP - no buffer for disc_req"); return; } @@ -935,7 +932,7 @@ void l2cu_send_peer_disc_rsp(tL2C_LCB* p_lcb, uint8_t remote_id, p_buf = l2cu_build_header(p_lcb, L2CAP_DISC_RSP_LEN, L2CAP_CMD_DISC_RSP, remote_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for disc_rsp"); + LOG_WARN("L2CAP - no buffer for disc_rsp"); return; } @@ -967,8 +964,7 @@ void l2cu_send_peer_echo_rsp(tL2C_LCB* p_lcb, uint8_t signal_id, * checking) */ if (!signal_id || signal_id == p_lcb->cur_echo_id) { /* Dump this request since it is illegal */ - L2CAP_TRACE_WARNING("L2CAP ignoring duplicate echo request (%d)", - signal_id); + LOG_WARN("L2CAP ignoring duplicate echo request (%d)", signal_id); return; } else p_lcb->cur_echo_id = signal_id; @@ -990,7 +986,7 @@ void l2cu_send_peer_echo_rsp(tL2C_LCB* p_lcb, uint8_t signal_id, p_buf = l2cu_build_header(p_lcb, (uint16_t)(L2CAP_ECHO_RSP_LEN + data_len), L2CAP_CMD_ECHO_RSP, signal_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for echo_rsp"); + LOG_WARN("L2CAP - no buffer for echo_rsp"); return; } @@ -1023,11 +1019,11 @@ void l2cu_send_peer_info_req(tL2C_LCB* p_lcb, uint16_t info_type) { p_buf = l2cu_build_header(p_lcb, 2, L2CAP_CMD_INFO_REQ, p_lcb->signal_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for info_req"); + LOG_WARN("L2CAP - no buffer for info_req"); return; } - L2CAP_TRACE_EVENT("l2cu_send_peer_info_req: type 0x%04x", info_type); + LOG_VERBOSE("l2cu_send_peer_info_req: type 0x%04x", info_type); p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; @@ -1081,7 +1077,7 @@ void l2cu_send_peer_info_rsp(tL2C_LCB* p_lcb, uint8_t remote_id, p_buf = l2cu_build_header(p_lcb, len, L2CAP_CMD_INFO_RSP, remote_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no buffer for info_rsp"); + LOG_WARN("L2CAP - no buffer for info_rsp"); return; } @@ -1167,13 +1163,13 @@ void l2cu_enqueue_ccb(tL2C_CCB* p_ccb) { if (p_ccb->p_lcb != NULL) p_q = &p_ccb->p_lcb->ccb_queue; if ((!p_ccb->in_use) || (p_q == NULL)) { - L2CAP_TRACE_ERROR("%s: CID: 0x%04x ERROR in_use: %u p_lcb: %p", __func__, - p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb); + LOG_ERROR("%s: CID: 0x%04x ERROR in_use: %u p_lcb: %p", __func__, + p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb); return; } - L2CAP_TRACE_DEBUG("l2cu_enqueue_ccb CID: 0x%04x priority: %d", - p_ccb->local_cid, p_ccb->ccb_priority); + LOG_VERBOSE("l2cu_enqueue_ccb CID: 0x%04x priority: %d", p_ccb->local_cid, + p_ccb->ccb_priority); /* If the queue is empty, we go at the front */ if (!p_q->p_first_ccb) { @@ -1241,16 +1237,16 @@ void l2cu_enqueue_ccb(tL2C_CCB* p_ccb) { void l2cu_dequeue_ccb(tL2C_CCB* p_ccb) { tL2C_CCB_Q* p_q = NULL; - L2CAP_TRACE_DEBUG("l2cu_dequeue_ccb CID: 0x%04x", p_ccb->local_cid); + LOG_VERBOSE("l2cu_dequeue_ccb CID: 0x%04x", p_ccb->local_cid); /* Find out which queue the channel is on */ if (p_ccb->p_lcb != NULL) p_q = &p_ccb->p_lcb->ccb_queue; if ((!p_ccb->in_use) || (p_q == NULL) || (p_q->p_first_ccb == NULL)) { - L2CAP_TRACE_ERROR( - "l2cu_dequeue_ccb CID: 0x%04x ERROR in_use: %u p_lcb: 0x%08x p_q: " - "0x%08x p_q->p_first_ccb: 0x%08x", + LOG_ERROR( + "l2cu_dequeue_ccb CID: 0x%04x ERROR in_use: %u p_lcb: 0x%p p_q: " + "0x%p p_q->p_first_ccb: 0x%p", p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb, p_q, p_q ? p_q->p_first_ccb : 0); return; @@ -1314,7 +1310,7 @@ void l2cu_change_pri_ccb(tL2C_CCB* p_ccb, tL2CAP_CHNL_PRIORITY priority) { if (p_ccb->ccb_priority != priority) { /* If CCB is not the only guy on the queue */ if ((p_ccb->p_next_ccb != NULL) || (p_ccb->p_prev_ccb != NULL)) { - L2CAP_TRACE_DEBUG("Update CCB list in logical link"); + LOG_VERBOSE("Update CCB list in logical link"); /* Remove CCB from queue and re-queue it at new priority */ l2cu_dequeue_ccb(p_ccb); @@ -1351,7 +1347,7 @@ void l2cu_change_pri_ccb(tL2C_CCB* p_ccb, tL2CAP_CHNL_PRIORITY priority) { * Returns pointer to CCB, or NULL if none * ******************************************************************************/ -tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid) { +tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid, bool is_eatt) { LOG_DEBUG("is_dynamic = %d, cid 0x%04x", p_lcb != nullptr, cid); if (!l2cb.p_free_ccb_first) { LOG_ERROR("First free ccb is null for cid 0x%04x", cid); @@ -1471,7 +1467,12 @@ tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid) { if (p_lcb != NULL) { // once a dynamic channel is opened, timeouts become active - p_lcb->with_active_local_clients = true; + // the exception for this is EATT, since that is managed by GATT clients, + // not by the L2CAP layer (GATT will keep the idle timeout at infinity while + // clients are active) + if (!is_eatt) { + p_lcb->with_active_local_clients = true; + } } return p_ccb; @@ -1491,10 +1492,6 @@ tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid) { * ******************************************************************************/ bool l2cu_start_post_bond_timer(uint16_t handle) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return true; - } - tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle); if (p_lcb == nullptr) { LOG_WARN("Unable to find link control block for handle:0x%04x", handle); @@ -1551,8 +1548,8 @@ void l2cu_release_ccb(tL2C_CCB* p_ccb) { tL2C_LCB* p_lcb = p_ccb->p_lcb; tL2C_RCB* p_rcb = p_ccb->p_rcb; - L2CAP_TRACE_DEBUG("l2cu_release_ccb: cid 0x%04x in_use: %u", - p_ccb->local_cid, p_ccb->in_use); + LOG_VERBOSE("l2cu_release_ccb: cid 0x%04x in_use: %u", p_ccb->local_cid, + p_ccb->in_use); /* If already released, could be race condition */ if (!p_ccb->in_use) return; @@ -1626,7 +1623,7 @@ void l2cu_release_ccb(tL2C_CCB* p_ccb) { if (!p_lcb->ccb_queue.p_first_ccb) { if (p_lcb->transport == BT_TRANSPORT_LE && p_ccb->local_cid == L2CAP_ATT_CID) { - L2CAP_TRACE_WARNING("%s - disconnecting the LE link", __func__); + LOG_WARN("%s - disconnecting the LE link", __func__); l2cu_no_dynamic_ccbs(p_lcb); } } @@ -1756,7 +1753,7 @@ void l2cu_disconnect_chnl(tL2C_CCB* p_ccb) { tL2CA_DISCONNECT_IND_CB* p_disc_cb = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; - L2CAP_TRACE_WARNING("L2CAP - disconnect_chnl CID: 0x%04x", local_cid); + LOG_WARN("L2CAP - disconnect_chnl CID: 0x%04x", local_cid); l2cu_send_peer_disc_req(p_ccb); @@ -1765,7 +1762,7 @@ void l2cu_disconnect_chnl(tL2C_CCB* p_ccb) { (*p_disc_cb)(local_cid, false); } else { /* failure on the AMP channel, probably need to disconnect ACL */ - L2CAP_TRACE_ERROR("L2CAP - disconnect_chnl CID: 0x%04x Ignored", local_cid); + LOG_ERROR("L2CAP - disconnect_chnl CID: 0x%04x Ignored", local_cid); } } @@ -1968,7 +1965,7 @@ void l2cu_process_peer_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { else p_ccb->fcrb.max_held_acks = p_ccb->our_cfg.fcr.tx_win_sz / 3; - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "l2cu_process_peer_cfg_rsp(): peer tx_win_sz: %d, our tx_win_sz: %d, " "max_held_acks: %d", p_cfg->fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz, @@ -2055,10 +2052,6 @@ void l2cu_process_our_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { * ******************************************************************************/ void l2cu_device_reset(void) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return; - } - int xx; tL2C_LCB* p_lcb = &l2cb.lcb_pool[0]; @@ -2092,8 +2085,8 @@ void l2cu_create_conn_br_edr(tL2C_LCB* p_lcb) { if (p_lcb_cur == p_lcb) continue; if (!p_lcb_cur->in_use) continue; if (BTM_IsScoActiveByBdaddr(p_lcb_cur->remote_bd_addr)) { - L2CAP_TRACE_DEBUG( - "%s Central peripheral switch not allowed when SCO active", __func__); + LOG_VERBOSE("%s Central peripheral switch not allowed when SCO active", + __func__); continue; } if (p_lcb->IsLinkRoleCentral()) continue; @@ -2345,6 +2338,34 @@ static void l2cu_set_acl_priority_unisoc(tL2C_LCB* p_lcb, HCI_UNISOC_ACL_PRIORITY_PARAM_SIZE, command, NULL); } +/******************************************************************************* + * + * Function l2cu_set_acl_priority_latency_mtk + * + * Description Sends a VSC to set the ACL priority and recorded latency on + * Mediatek chip. + * + * Returns void + * + ******************************************************************************/ + +static void l2cu_set_acl_priority_latency_mtk(tL2C_LCB* p_lcb, + tL2CAP_PRIORITY priority) { + uint8_t vs_param; + if (priority == L2CAP_PRIORITY_HIGH) { + // priority to high, if using latency mode check preset latency + LOG_INFO("Set ACL priority: High Priority Mode"); + vs_param = HCI_MTK_ACL_HIGH_PRIORITY; + } else { + // priority to normal + LOG_INFO("Set ACL priority: Normal Mode"); + vs_param = HCI_MTK_ACL_NORMAL_PRIORITY; + } + + BTM_VendorSpecificCommand(HCI_MTK_SET_ACL_PRIORITY, + HCI_MTK_ACL_PRIORITY_PARAM_SIZE, &vs_param, NULL); +} + /******************************************************************************* * * Function l2cu_set_acl_priority @@ -2361,12 +2382,12 @@ bool l2cu_set_acl_priority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority, bool reset_after_rs) { tL2C_LCB* p_lcb; - APPL_TRACE_EVENT("SET ACL PRIORITY %d", priority); + LOG_VERBOSE("SET ACL PRIORITY %d", priority); /* Find the link control block for the acl channel */ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR); if (p_lcb == NULL) { - L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_SetAclPriority"); + LOG_WARN("L2CAP - no LCB for L2CA_SetAclPriority"); return (false); } @@ -2389,6 +2410,10 @@ bool l2cu_set_acl_priority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority, l2cu_set_acl_priority_unisoc(p_lcb, priority); break; + case LMP_COMPID_MEDIATEK: + l2cu_set_acl_priority_latency_mtk(p_lcb, priority); + break; + default: /* Not supported/required for other vendors */ break; @@ -2509,10 +2534,6 @@ bool l2cu_set_acl_latency(const RawAddress& bd_addr, tL2CAP_LATENCY latency) { * ******************************************************************************/ void l2cu_set_non_flushable_pbf(bool is_supported) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - return; - } - if (is_supported) l2cb.non_flushable_pbf = (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT); @@ -2531,17 +2552,12 @@ void l2cu_set_non_flushable_pbf(bool is_supported) { * ******************************************************************************/ void l2cu_resubmit_pending_sec_req(const RawAddress* p_bda) { - if (bluetooth::shim::is_gd_l2cap_enabled()) { - // GD L2cap will enforce security when condition changed - return; - } - tL2C_LCB* p_lcb; tL2C_CCB* p_ccb; tL2C_CCB* p_next_ccb; int xx; - L2CAP_TRACE_DEBUG("l2cu_resubmit_pending_sec_req p_bda: 0x%08x", p_bda); + LOG_VERBOSE("l2cu_resubmit_pending_sec_req p_bda: 0x%p", p_bda); /* If we are called with a BDA, only resubmit for that BDA */ if (p_bda) { @@ -2555,7 +2571,7 @@ void l2cu_resubmit_pending_sec_req(const RawAddress* p_bda) { l2c_csm_execute(p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL); } } else { - L2CAP_TRACE_WARNING("l2cu_resubmit_pending_sec_req - unknown BD_ADDR"); + LOG_WARN("l2cu_resubmit_pending_sec_req - unknown BD_ADDR"); } } else { /* No BDA pasesed in, so check all links */ @@ -2604,9 +2620,8 @@ void l2cu_adjust_out_mps(tL2C_CCB* p_ccb) { if (packet_size <= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN)) { /* something is very wrong */ - L2CAP_TRACE_ERROR( - "l2cu_adjust_out_mps bad packet size: %u will use MPS: %u", - packet_size, p_ccb->peer_cfg.fcr.mps); + LOG_ERROR("l2cu_adjust_out_mps bad packet size: %u will use MPS: %u", + packet_size, p_ccb->peer_cfg.fcr.mps); p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps; } else { packet_size -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + @@ -2628,7 +2643,7 @@ void l2cu_adjust_out_mps(tL2C_CCB* p_ccb) { else p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps; - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "l2cu_adjust_out_mps use %d Based on peer_cfg.fcr.mps: %u " "packet_size: %u", p_ccb->tx_mps, p_ccb->peer_cfg.fcr.mps, packet_size); @@ -2660,7 +2675,12 @@ bool l2cu_initialize_fixed_ccb(tL2C_LCB* p_lcb, uint16_t fixed_cid) { p_ccb = l2cu_allocate_ccb(NULL, 0); if (p_ccb == NULL) return (false); - alarm_cancel(p_lcb->l2c_lcb_timer); + if (p_lcb->link_state == LST_DISCONNECTED) { + alarm_cancel(p_lcb->l2c_lcb_timer); + } else { + LOG_WARN("Unable to cancel link control block for link connection to device %s", + ADDRESS_TO_LOGGABLE_CSTR(p_lcb->remote_bd_addr)); + } /* Set CID for the connection */ p_ccb->local_cid = fixed_cid; @@ -2705,8 +2725,8 @@ void l2cu_no_dynamic_ccbs(tL2C_LCB* p_lcb) { (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000 > timeout_ms)) { if (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout == L2CAP_NO_IDLE_TIMEOUT) { - L2CAP_TRACE_DEBUG("%s NO IDLE timeout set for fixed cid 0x%04x", - __func__, p_lcb->p_fixed_ccbs[xx]->local_cid); + LOG_VERBOSE("%s NO IDLE timeout set for fixed cid 0x%04x", __func__, + p_lcb->p_fixed_ccbs[xx]->local_cid); start_timeout = false; } timeout_ms = p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000; @@ -2716,20 +2736,18 @@ void l2cu_no_dynamic_ccbs(tL2C_LCB* p_lcb) { /* If the link is pairing, do not mess with the timeouts */ if (p_lcb->IsBonding()) return; - L2CAP_TRACE_DEBUG("l2cu_no_dynamic_ccbs() with_active_local_clients=%d", - p_lcb->with_active_local_clients); + LOG_VERBOSE("l2cu_no_dynamic_ccbs() with_active_local_clients=%d", + p_lcb->with_active_local_clients); // Inactive connections should not timeout, since the ATT channel might still // be in use even without a GATT client. We only timeout if either a dynamic // channel or a GATT client was used, since then we expect the client to // manage the lifecycle of the connection. - if (bluetooth::common::init_flags::finite_att_timeout_is_enabled() && - !p_lcb->with_active_local_clients) { + if (!p_lcb->with_active_local_clients) { return; } if (timeout_ms == 0) { - L2CAP_TRACE_DEBUG( - "l2cu_no_dynamic_ccbs() IDLE timer 0, disconnecting link"); + LOG_VERBOSE("l2cu_no_dynamic_ccbs() IDLE timer 0, disconnecting link"); rc = btm_sec_disconnect( p_lcb->Handle(), HCI_ERR_PEER_USER, @@ -2879,7 +2897,7 @@ void l2cu_send_peer_ble_par_req(tL2C_LCB* p_lcb, uint16_t min_int, p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_UPD_REQ_LEN, L2CAP_CMD_BLE_UPDATE_REQ, p_lcb->signal_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_send_peer_ble_par_req - no buffer"); + LOG_WARN("l2cu_send_peer_ble_par_req - no buffer"); return; } @@ -2912,7 +2930,7 @@ void l2cu_send_peer_ble_par_rsp(tL2C_LCB* p_lcb, uint16_t reason, p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_UPD_RSP_LEN, L2CAP_CMD_BLE_UPDATE_RSP, rem_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_send_peer_ble_par_rsp - no buffer"); + LOG_WARN("l2cu_send_peer_ble_par_rsp - no buffer"); return; } @@ -2955,7 +2973,7 @@ void l2cu_send_peer_ble_credit_based_conn_req(tL2C_CCB* p_ccb) { l2cu_build_header(p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ_LEN, L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ, p_lcb->signal_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_send_peer_ble_credit_based_conn_req - no buffer"); + LOG_WARN("l2cu_send_peer_ble_credit_based_conn_req - no buffer"); return; } @@ -2966,9 +2984,9 @@ void l2cu_send_peer_ble_credit_based_conn_req(tL2C_CCB* p_ccb) { mps = p_ccb->local_conn_cfg.mps; initial_credit = p_ccb->local_conn_cfg.credits; - L2CAP_TRACE_DEBUG( - "l2cu_send_peer_ble_credit_based_conn_req PSM:0x%04x local_cid:%d\ - mtu:%d mps:%d initial_credit:%d", + LOG_VERBOSE( + "l2cu_send_peer_ble_credit_based_conn_req PSM:0x%04x local_cid:%d" + " mtu:%d mps:%d initial_credit:%d", p_ccb->p_rcb->real_psm, p_ccb->local_cid, mtu, mps, initial_credit); UINT16_TO_STREAM(p, p_ccb->p_rcb->real_psm); @@ -3013,7 +3031,7 @@ void l2cu_send_peer_credit_based_conn_req(tL2C_CCB* p_ccb) { 2 * p_lcb->pending_ecoc_conn_cnt, L2CAP_CMD_CREDIT_BASED_CONN_REQ, p_ccb->local_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("%s - no buffer", __func__); + LOG_WARN("%s - no buffer", __func__); return; } @@ -3024,10 +3042,9 @@ void l2cu_send_peer_credit_based_conn_req(tL2C_CCB* p_ccb) { mps = p_ccb->local_conn_cfg.mps; initial_credit = p_ccb->local_conn_cfg.credits; - L2CAP_TRACE_DEBUG( - "%s PSM:0x%04x mtu:%d mps:%d initial_credit:%d, cids_cnt %d", __func__, - p_ccb->p_rcb->real_psm, mtu, mps, initial_credit, - p_lcb->pending_ecoc_conn_cnt); + LOG_VERBOSE("%s PSM:0x%04x mtu:%d mps:%d initial_credit:%d, cids_cnt %d", + __func__, p_ccb->p_rcb->real_psm, mtu, mps, initial_credit, + p_lcb->pending_ecoc_conn_cnt); UINT16_TO_STREAM(p, p_ccb->p_rcb->real_psm); UINT16_TO_STREAM(p, mtu); @@ -3036,7 +3053,7 @@ void l2cu_send_peer_credit_based_conn_req(tL2C_CCB* p_ccb) { for (int i = 0; i < p_lcb->pending_ecoc_conn_cnt; i++) { uint16_t cid = p_lcb->pending_ecoc_connection_cids[i]; - L2CAP_TRACE_DEBUG("\n\t cid: ", cid); + LOG_VERBOSE("\n\t cid: %d", cid); UINT16_TO_STREAM(p, cid); } @@ -3062,7 +3079,7 @@ void l2cu_reject_ble_coc_connection(tL2C_LCB* p_lcb, uint8_t rem_id, p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES, rem_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_reject_ble_coc_connection - no buffer"); + LOG_WARN("l2cu_reject_ble_coc_connection - no buffer"); return; } @@ -3099,7 +3116,7 @@ void l2cu_reject_credit_based_conn_req(tL2C_LCB* p_lcb, uint8_t rem_id, p_buf = l2cu_build_header(p_lcb, rsp_len, L2CAP_CMD_CREDIT_BASED_CONN_RES, rem_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_reject_credit_based_conn_req - no buffer"); + LOG_WARN("l2cu_reject_credit_based_conn_req - no buffer"); return; } @@ -3132,14 +3149,14 @@ void l2cu_send_peer_credit_based_conn_res(tL2C_CCB* p_ccb, BT_HDR* p_buf; uint8_t* p; - L2CAP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); uint8_t rsp_len = L2CAP_CMD_CREDIT_BASED_CONN_RES_MIN_LEN + p_ccb->p_lcb->pending_ecoc_conn_cnt * sizeof(uint16_t); p_buf = l2cu_build_header(p_ccb->p_lcb, rsp_len, L2CAP_CMD_CREDIT_BASED_CONN_RES, p_ccb->remote_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("%s - no buffer", __func__); + LOG_WARN("%s - no buffer", __func__); return; } @@ -3221,12 +3238,12 @@ void l2cu_send_ble_reconfig_rsp(tL2C_LCB* p_lcb, uint8_t rem_id, BT_HDR* p_buf; uint8_t* p; - L2CAP_TRACE_DEBUG("l2cu_send_ble_reconfig_rsp result 0x04%x", result); + LOG_VERBOSE("l2cu_send_ble_reconfig_rsp result 0x04%x", result); p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_CREDIT_BASED_RECONFIG_RES_LEN, L2CAP_CMD_CREDIT_BASED_RECONFIG_RES, rem_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_send_peer_ble_credit_based_conn_res - no buffer"); + LOG_WARN("l2cu_send_peer_ble_credit_based_conn_res - no buffer"); return; } @@ -3255,12 +3272,12 @@ void l2cu_send_peer_ble_credit_based_conn_res(tL2C_CCB* p_ccb, BT_HDR* p_buf; uint8_t* p; - L2CAP_TRACE_DEBUG("l2cu_send_peer_ble_credit_based_conn_res"); + LOG_VERBOSE("l2cu_send_peer_ble_credit_based_conn_res"); p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES, p_ccb->remote_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_send_peer_ble_credit_based_conn_res - no buffer"); + LOG_WARN("l2cu_send_peer_ble_credit_based_conn_res - no buffer"); return; } @@ -3304,7 +3321,7 @@ void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB* p_ccb, p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_FLOW_CTRL_CREDIT_LEN, L2CAP_CMD_BLE_FLOW_CTRL_CREDIT, p_lcb->signal_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING("l2cu_send_peer_ble_credit_based_conn_req - no buffer"); + LOG_WARN("l2cu_send_peer_ble_credit_based_conn_req - no buffer"); return; } @@ -3331,7 +3348,7 @@ void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB* p_ccb) { BT_HDR* p_buf; uint8_t* p; tL2C_LCB* p_lcb = NULL; - L2CAP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", __func__); if (!p_ccb) return; p_lcb = p_ccb->p_lcb; @@ -3344,8 +3361,7 @@ void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB* p_ccb) { p_buf = l2cu_build_header(p_lcb, L2CAP_DISC_REQ_LEN, L2CAP_CMD_DISC_REQ, p_lcb->signal_id); if (p_buf == NULL) { - L2CAP_TRACE_WARNING( - "l2cu_send_peer_ble_credit_based_disconn_req - no buffer"); + LOG_WARN("l2cu_send_peer_ble_credit_based_disconn_req - no buffer"); return; } @@ -3475,9 +3491,9 @@ static void send_congestion_status_to_all_clients(tL2C_CCB* p_ccb, p_ccb->cong_sent = status; if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) { - L2CAP_TRACE_DEBUG( + LOG_VERBOSE( "L2CAP - Calling CongestionStatus_Cb (%d), CID: 0x%04x " - "xmit_hold_q.count: %u buff_quota: %u", + "xmit_hold_q.count: %zu buff_quota: %u", status, p_ccb->local_cid, fixed_queue_length(p_ccb->xmit_hold_q), p_ccb->buff_quota); diff --git a/system/stack/metrics/stack_metrics_logging.cc b/system/stack/metrics/stack_metrics_logging.cc index 7980e032a4afcc03180b279c2196d29d25019de1..8c29ae93dcf3f7022a6c248b9b3906c7b5fcf1b4 100644 --- a/system/stack/metrics/stack_metrics_logging.cc +++ b/system/stack/metrics/stack_metrics_logging.cc @@ -76,7 +76,14 @@ void log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum key, void log_hfp_audio_packet_loss_stats(const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio) { + double packet_loss_ratio, + uint16_t codec_type) { bluetooth::shim::LogMetricHfpPacketLossStats(address, num_decoded_frames, - packet_loss_ratio); + packet_loss_ratio, codec_type); +} + +void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, + int num_requests, int codec_type) { + bluetooth::shim::LogMetricMmcTranscodeRttStats(maximum_rtt, mean_rtt, + num_requests, codec_type); } diff --git a/system/stack/mmc/BUILD.gn b/system/stack/mmc/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a3a85edf72a32b9303af8331f7b6b0b027d6a355 --- /dev/null +++ b/system/stack/mmc/BUILD.gn @@ -0,0 +1,154 @@ +# +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import("//common-mk/install_config.gni") + +group("mmc") { + deps = [ + ":install_dbus_config", + ":install_init", + ":install_minijail_config", + ":install_system_service", + ":install_tmpfiles_config", + ":mmc_service", + "//bt/system/stack/mmc/codec_client:libcodec_client", + "//bt/system/stack/mmc/proto:mmc_config_proto", + ] + if (use.test) { + deps += [ + ":hfp_lc3_mmc_encoder_test", + ":hfp_lc3_mmc_decoder_test", + ] + } +} + +pkg_config("target_defaults") { + include_dirs = [ + "//bt/system", + "//bt/system/include", + "//bt/system/stack", + "//bt/system/stack/include", + ] + pkg_deps = [ + "libchrome", + ] + if (use.fuzzer) { + pkg_deps += [ "protobuf" ] + } else { + pkg_deps += [ "protobuf-lite" ] + } + if (!(defined(use.bt_nonstandard_codecs) && use.bt_nonstandard_codecs)) { + defines = [ "EXCLUDE_NONSTANDARD_CODECS" ] + } +} + +install_config("install_dbus_config") { + sources = [ "dbus_permissions/org.chromium.mmc.CodecManager.conf" ] + install_path = "/etc/dbus-1/system.d" +} + +install_config("install_system_service") { + sources = [ "dbus_service/org.chromium.mmc.CodecManager.service" ] + install_path = "/usr/share/dbus-1/system-services" +} + +install_config("install_init") { + sources = [ "init/mmc_service.conf" ] + install_path = "/etc/init" +} + +install_config("install_tmpfiles_config") { + sources = [ "tmpfiles.d/mmc.conf" ] + install_path = "/usr/lib/tmpfiles.d" +} + +install_config("install_minijail_config") { + sources = [ "minijail/mmc.conf" ] + install_path = "/usr/share/minijail" +} + +source_set("libmmc") { + configs += [ ":target_defaults" ] + sources = [ + "daemon/service.cc", + ] + deps = [ + "//bt/system/common", + "//bt/system/stack/mmc/proto:mmc_service_proto", + "//bt/system/stack/mmc/codec_server:libcodec_server_hfp_lc3", + ] + if (defined(use.bt_nonstandard_codecs) && use.bt_nonstandard_codecs) { + deps += [ "//bt/system/stack/mmc/codec_server:libcodec_server_a2dp_aac" ] + } +} + +executable("mmc_service") { + configs += [ ":target_defaults" ] + deps = [ ":libmmc" ] + sources = [ "main.cc" ] +} + +if (use.test) { + executable("hfp_lc3_mmc_encoder_test") { + sources = [ + "codec_server/hfp_lc3_mmc_encoder.cc", + "test/hfp_lc3_mmc_encoder_test.cc", + "test/mock/mock_embdrv_lc3.cc", + "//bt/system/test/mock/mock_common_address_obfuscator.cc", + "//bt/system/test/mock/mock_osi_allocator.cc", + "//bt/system/test/common/mock_functions.cc", + ] + include_dirs = [ + "//bt/system/gd", + "//bt/system/types", + ] + configs += [ + ":target_defaults", + "//bt/system:external_gtest_main", + ] + deps = [ + "//bt/system/stack/mmc/proto:mmc_config_proto", + "//bt/system/common", + "//bt/system/osi", + "//bt/system/types", + ] + } + + executable("hfp_lc3_mmc_decoder_test") { + sources = [ + "codec_server/hfp_lc3_mmc_decoder.cc", + "test/hfp_lc3_mmc_decoder_test.cc", + "test/mock/mock_embdrv_lc3.cc", + "//bt/system/test/mock/mock_common_address_obfuscator.cc", + "//bt/system/test/mock/mock_osi_allocator.cc", + "//bt/system/test/common/mock_functions.cc", + ] + include_dirs = [ + "//bt/system/gd", + "//bt/system/types", + ] + configs += [ + ":target_defaults", + "//bt/system:external_gtest_main", + ] + deps = [ + "//bt/system/stack/mmc/proto:mmc_config_proto", + "//bt/system/common", + "//bt/system/osi", + "//bt/system/types", + ] + } +} diff --git a/system/stack/mmc/OWNERS b/system/stack/mmc/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..a823e6e1ddc6d3d153fe4acbd207c3b06ae03b10 --- /dev/null +++ b/system/stack/mmc/OWNERS @@ -0,0 +1 @@ +include /OWNERS_chromeos diff --git a/system/stack/mmc/README.md b/system/stack/mmc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e864d72fe88f62b05785ef352ee656b58a94a4e6 --- /dev/null +++ b/system/stack/mmc/README.md @@ -0,0 +1,45 @@ +# Minijailed Media Codec (MMC) + +MMC is a service running in minijail that isolates codec implementations from +the Bluetooth process and system resources. It is an independent daemon that +spawns codec servers on demand to communicate with their corresponding codec +clients living in Floss. + +## Steps to Apply MMC to a New Codec + +### 1. Implement codec server + + * Wraps third party library codes. + * Codec server should inherit [MMC Interface](https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/system/stack/mmc/mmc_interface/mmc_interface.h). + * public methods: `init`, `cleanup`, `transcode`. + * `init`: set up transcoder and return frame size accepted by the transcoder. + * `cleanup`: clear the transcoder context. + * `transcode`: transcode input data, store result in the given output buffer, + and return the transcoded data length. + +### 2. Add codec proto message in [mmc_config.proto](https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/system/stack/mmc/proto/mmc_config.proto) + + * Define a proto message for the new codec, generally, it may include: + * Init configuration. + * Transcode arguments or params. + * Library-specific enum mappings. + * Append an entry to [`ConfigParam`](https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/system/stack/mmc/proto/mmc_config.proto;drc=1e6b2d44402d18cce637f4b02d4da25133924662;l=99). + +### 3. Add codec support in MMC daemon + + * Match the new `ConfigParam` to create its corresponding server in [`CodecInit`](https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/system/stack/mmc/daemon/service.cc;drc=e9fcc3a7897c6af3df4163534688290778e2333b;l=186). + +### 4. Access the interface via [`CodecClient`](https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/system/stack/mmc/codec_client/codec_client.h) from within the BT process + + * BT process accesses codec implementations via `CodecClient`. + * `init`: set up `ConfigParam` and pass it to `CodecClient`. + * `transcode`: pass input and output buffer, and specify the input data size + and the output buffer capacity. `transcode` returns transcoded + data length on success, and negative error number otherwise. + * `cleanup`: when a session ends, `cleanup` should be called. + +## Related links + +* Design doc: go/floss-mmc +* Slides: go/floss-mmc-presentation +* Performance evaluation: go/floss-mmc-experiment diff --git a/system/build/secondary/third_party/libldac/BUILD.gn b/system/stack/mmc/codec_client/BUILD.gn similarity index 52% rename from system/build/secondary/third_party/libldac/BUILD.gn rename to system/stack/mmc/codec_client/BUILD.gn index 23b191dee1aa37eedd334d7c9e4b4529b368000b..6fe2df8b4b82b37378368d8531dce91e581f9e5d 100644 --- a/system/build/secondary/third_party/libldac/BUILD.gn +++ b/system/stack/mmc/codec_client/BUILD.gn @@ -1,5 +1,5 @@ # -# Copyright 2017 Google, Inc. +# Copyright 2023 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,35 +14,15 @@ # limitations under the License. # -config("libldacBT_enc_config") { - include_dirs = [ "inc" ] -} - -config("libldacBT_abr_config") { - include_dirs = [ "abr/inc", "inc" ] -} - -shared_library("libldacBT_enc") { +source_set("libcodec_client"){ + configs += [ "//bt/system/stack/mmc:target_defaults" ] sources = [ - "src/ldaclib.c", - "src/ldacBT.c", + "codec_client.cc", ] - public_configs = [ ":libldacBT_enc_config" ] - - cflags = [ "-O2" ] - - defines = [ "EXPORT_SYMBOL=" ] -} - -shared_library("libldacBT_abr") { - sources = [ - "abr/src/ldacBT_abr.c", + deps = [ + "//bt/system/stack/mmc/proto:mmc_service_proto", + "//bt/system/stack/mmc/proto:mmc_config_proto", + "//bt/system/stack/mmc/metrics:libmmc_metrics", ] - - public_configs = [ ":libldacBT_abr_config" ] - - cflags = [ "-O2" ] - - defines = [ "EXPORT_SYMBOL=" ] } diff --git a/system/stack/mmc/codec_client/codec_client.cc b/system/stack/mmc/codec_client/codec_client.cc new file mode 100644 index 0000000000000000000000000000000000000000..648b2d45659b42b52358c76dbb53a8b17f558d5c --- /dev/null +++ b/system/stack/mmc/codec_client/codec_client.cc @@ -0,0 +1,256 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mmc/codec_client/codec_client.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mmc/daemon/constants.h" +#include "mmc/metrics/mmc_rtt_logger.h" +#include "mmc/proto/mmc_config.pb.h" +#include "mmc/proto/mmc_service.pb.h" + +namespace mmc { +namespace { + +// Codec param field number in |ConfigParam| +const int kUnsupportedType = -1; +const int kHfpLc3EncoderId = 1; +const int kHfpLc3DecoderId = 2; +const int kA2dpAacEncoderId = 5; + +// Maps |ConfigParam| proto field to int, because proto-lite does not support +// reflection. +int CodecId(const ConfigParam& config) { + if (config.has_hfp_lc3_encoder_param()) { + return kHfpLc3EncoderId; + } else if (config.has_hfp_lc3_decoder_param()) { + return kHfpLc3DecoderId; + } else if (config.has_a2dp_aac_encoder_param()) { + return kA2dpAacEncoderId; + } else { + LOG(WARNING) << "Unsupported codec type is used."; + return kUnsupportedType; + } +} +} // namespace + +CodecClient::CodecClient() { + skt_fd_ = -1; + codec_manager_ = nullptr; + record_logger_ = nullptr; + + // Set up DBus connection. + dbus::Bus::Options options; + options.bus_type = dbus::Bus::SYSTEM; + bus_ = new dbus::Bus(options); + + if (!bus_->Connect()) { + LOG(ERROR) << "Failed to connect system bus"; + return; + } + + // Get proxy to send DBus method call. + codec_manager_ = bus_->GetObjectProxy(mmc::kMmcServiceName, + dbus::ObjectPath(mmc::kMmcServicePath)); + if (!codec_manager_) { + LOG(ERROR) << "Failed to get object proxy"; + return; + } +} + +CodecClient::~CodecClient() { + cleanup(); + if (bus_) bus_->ShutdownAndBlock(); +} + +int CodecClient::init(const ConfigParam config) { + cleanup(); + + // Set up record logger. + record_logger_ = std::make_unique(CodecId(config)); + + dbus::MethodCall method_call(mmc::kMmcServiceInterface, + mmc::kCodecInitMethod); + dbus::MessageWriter writer(&method_call); + + mmc::CodecInitRequest request; + *request.mutable_config() = config; + if (!writer.AppendProtoAsArrayOfBytes(request)) { + LOG(ERROR) << "Failed to encode CodecInitRequest protobuf"; + return -EINVAL; + } + + std::unique_ptr dbus_response = + codec_manager_ + ->CallMethodAndBlock(&method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) +// TODO(b/297976471): remove the build flag once libchrome uprev is done. +#if BASE_VER >= 1170299 + .value_or(nullptr) +#endif + ; + + if (!dbus_response) { + LOG(ERROR) << "CodecInit failed"; + return -ECOMM; + } + + dbus::MessageReader reader(dbus_response.get()); + mmc::CodecInitResponse response; + if (!reader.PopArrayOfBytesAsProto(&response)) { + LOG(ERROR) << "Failed to parse response protobuf"; + return -EINVAL; + } + + if (response.socket_token().empty()) { + LOG(ERROR) << "CodecInit returned empty socket token"; + return -EBADMSG; + } + + if (response.input_frame_size() < 0) { + LOG(ERROR) << "CodecInit returned negative frame size"; + return -EBADMSG; + } + + // Create socket. + skt_fd_ = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (skt_fd_ < 0) { + LOG(ERROR) << "Failed to create socket: " << strerror(errno); + return -errno; + } + + struct sockaddr_un addr = {}; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, response.socket_token().c_str(), + sizeof(addr.sun_path) - 1); + + // Connect to socket for transcoding. + int rc = + connect(skt_fd_, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)); + if (rc < 0) { + LOG(ERROR) << "Failed to connect socket: " << strerror(errno); + return -errno; + } + unlink(addr.sun_path); + return response.input_frame_size(); +} + +void CodecClient::cleanup() { + if (skt_fd_ >= 0) { + close(skt_fd_); + skt_fd_ = -1; + } + + // Upload Rtt statics when the session ends. + if (record_logger_.get() != nullptr) { + record_logger_->UploadTranscodeRttStatics(); + record_logger_.release(); + } + + dbus::MethodCall method_call(mmc::kMmcServiceInterface, + mmc::kCodecCleanUpMethod); + + std::unique_ptr dbus_response = + codec_manager_ + ->CallMethodAndBlock(&method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) +// TODO(b/297976471): remove the build flag once libchrome uprev is done. +#if BASE_VER >= 1170299 + .value_or(nullptr) +#endif + ; + + if (!dbus_response) { + LOG(WARNING) << "CodecCleanUp failed"; + } + return; +} + +int CodecClient::transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, + int o_len) { + // Start Timer + base::ElapsedTimer timer; + + // i_buf and o_buf cannot be null. + if (i_buf == nullptr || o_buf == nullptr) { + LOG(ERROR) << "Buffer is null"; + return -EINVAL; + } + + if (i_len <= 0 || o_len <= 0) { + LOG(ERROR) << "Non-positive buffer length"; + return -EINVAL; + } + + // Use MSG_NOSIGNAL to ignore SIGPIPE. + int rc = send(skt_fd_, i_buf, i_len, MSG_NOSIGNAL); + + if (rc < 0) { + LOG(ERROR) << "Failed to send data: " << strerror(errno); + return -errno; + } + // Full packet should be sent under SOCK_SEQPACKET setting. + if (rc < i_len) { + LOG(ERROR) << "Failed to send full packet"; + return -EIO; + } + + struct pollfd pfd; + pfd.fd = skt_fd_; + pfd.events = POLLIN; + + int pollret = poll(&pfd, 1, -1); + if (pollret < 0) { + LOG(ERROR) << "Failed to poll: " << strerror(errno); + return -errno; + } + + if (pfd.revents & (POLLHUP | POLLNVAL)) { + LOG(ERROR) << "Socket closed remotely."; + return -EIO; + } + + // POLLIN is returned.. + rc = recv(skt_fd_, o_buf, o_len, MSG_NOSIGNAL); + if (rc < 0) { + LOG(ERROR) << "Failed to recv data: " << strerror(errno); + return -errno; + } + // Should be able to recv data when POLLIN is returned. + if (rc == 0) { + LOG(ERROR) << "Failed to recv data"; + return -EIO; + } + + // End timer + record_logger_->RecordRtt(timer.Elapsed().InMicroseconds()); + + return rc; +} + +} // namespace mmc diff --git a/system/stack/mmc/codec_client/codec_client.h b/system/stack/mmc/codec_client/codec_client.h new file mode 100644 index 0000000000000000000000000000000000000000..2882b558adff1f67001c410afe9fa73aea519224 --- /dev/null +++ b/system/stack/mmc/codec_client/codec_client.h @@ -0,0 +1,72 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_CODEC_CLIENT_CODEC_CLIENT_H_ +#define MMC_CODEC_CLIENT_CODEC_CLIENT_H_ + +#include +#include + +#include + +#include "mmc/metrics/mmc_rtt_logger.h" +#include "mmc/mmc_interface/mmc_interface.h" +#include "mmc/proto/mmc_service.pb.h" + +namespace mmc { + +// Implementation of MmcInterface. +// CodecClient serves as proxy of MMC codec service. +class CodecClient : public MmcInterface { + public: + // Connects to DBus. + explicit CodecClient(); + + // Calls |cleanup|. + ~CodecClient(); + + // CodecClient is neither copyable nor movable. + CodecClient(const CodecClient&) = delete; + CodecClient& operator=(const CodecClient&) = delete; + + // Calls MMC DBus method |CodecInit| with |CodecInitRequest|, opens the socket + // for transcoding. + // + // Returns: + // Input frame size accepted by the transcoder, if init succeeded. + // Negative errno on error, otherwise. + int init(const ConfigParam config) override; + + // Closes the socket, and calls MMC DBus method |CodecCleanUp|. + void cleanup() override; + + // Transfers PCM data between caller and the MMC codec service. + // + // Returns: + // Transcoded data length, if transcode succeeded. + // Negative errno on error, otherwise. + int transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, int o_len) override; + + private: + int skt_fd_; + dbus::ObjectProxy* codec_manager_; // Owned by the Bus object. + scoped_refptr bus_; + std::unique_ptr record_logger_; +}; + +} // namespace mmc + +#endif // MMC_CODEC_CLIENT_CODEC_CLIENT_H_ diff --git a/system/stack/mmc/codec_server/BUILD.gn b/system/stack/mmc/codec_server/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ed575ed3e8d351e14996107d8d09e9ff1c17dc77 --- /dev/null +++ b/system/stack/mmc/codec_server/BUILD.gn @@ -0,0 +1,62 @@ +# +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +source_set("libcodec_server_a2dp_aac") { + configs += [ + "//bt/system:target_defaults", + "//bt/system/stack/mmc:target_defaults", + ] + include_dirs = [ + "//bt/system", + "//bt/system/include", + "//bt/system/internal_include", + "//bt/system/stack", + "//bt/system/stack/include", + ] + deps = [ + "//bt/system/gd/rust/shim:init_flags_bridge_header", + "//bt/system/stack/mmc/proto:mmc_config_proto", + ] + sources = [ "a2dp_aac_mmc_encoder.cc" ] + libs = [ + # Following are for AAC using FFmpeg + "avcodec", + "avformat", + "avutil", + ] +} + +source_set("libcodec_server_hfp_lc3"){ + configs += [ "//bt/system/stack/mmc:target_defaults" ] + include_dirs = [ + "//bt/system", + "//bt/system/include", + "//bt/system/stack", + "//bt/system/stack/include", + ] + libs = [ + "lc3", + ] + + deps = [ + "//bt/system/stack/mmc/proto:mmc_config_proto", + "//bt/system/osi", + ] + sources = [ + "hfp_lc3_mmc_encoder.cc", + "hfp_lc3_mmc_decoder.cc", + ] +} diff --git a/system/stack/mmc/codec_server/a2dp_aac_mmc_encoder.cc b/system/stack/mmc/codec_server/a2dp_aac_mmc_encoder.cc new file mode 100644 index 0000000000000000000000000000000000000000..612aa9fc5f215e93d55bee2ce41f5f3358f50f10 --- /dev/null +++ b/system/stack/mmc/codec_server/a2dp_aac_mmc_encoder.cc @@ -0,0 +1,248 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mmc/codec_server/a2dp_aac_mmc_encoder.h" + +extern "C" { +#include +#include +#include +#include +#include +} + +#include + +#include "a2dp_aac.h" +#include "mmc/proto/mmc_config.pb.h" + +namespace mmc { +namespace { + +const int A2DP_AAC_HEADER_LEN = 9; +const int A2DP_AAC_MAX_LEN_REPR = 4; +const int A2DP_AAC_MAX_PREFIX_SIZE = + AVDT_MEDIA_HDR_SIZE + A2DP_AAC_HEADER_LEN + A2DP_AAC_MAX_LEN_REPR; + +constexpr uint8_t A2DP_AAC_HEADER_44100[A2DP_AAC_HEADER_LEN] = { + 0x47, 0xfc, 0x00, 0x00, 0xb0, 0x90, 0x80, 0x03, 0x00, +}; +constexpr uint8_t A2DP_AAC_HEADER_48000[A2DP_AAC_HEADER_LEN] = { + 0x47, 0xfc, 0x00, 0x00, 0xb0, 0x8c, 0x80, 0x03, 0x00, +}; +} // namespace + +A2dpAacEncoder::A2dpAacEncoder() : avctx_(nullptr) {} + +A2dpAacEncoder::~A2dpAacEncoder() { cleanup(); } + +int A2dpAacEncoder::init(ConfigParam config) { + if (!config.has_a2dp_aac_encoder_param()) { + LOG(ERROR) << "A2DP AAC Encoder params are not set"; + return -EINVAL; + } + + const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_AAC); + if (!codec) { + LOG(ERROR) << "Codec not found"; + return -ENOENT; + } + + if (!avctx_) { + avctx_ = avcodec_alloc_context3(codec); + if (!avctx_) { + LOG(ERROR) << "Cannot allocate context"; + return -EINVAL; + } + } + + param_ = config.a2dp_aac_encoder_param(); + const int channel_count = param_.channel_count(); + const int sample_rate = param_.sample_rate(); + const int bit_rate = param_.bit_rate(); + + if (channel_count == 1) { + AVChannelLayout mono = AV_CHANNEL_LAYOUT_MONO; + av_channel_layout_copy(&avctx_->ch_layout, &mono); + } else if (channel_count == 2) { + AVChannelLayout stereo = AV_CHANNEL_LAYOUT_STEREO; + av_channel_layout_copy(&avctx_->ch_layout, &stereo); + } else { + LOG(ERROR) << "Invalid number of channels: " << channel_count; + return -EINVAL; + } + + if (sample_rate != 44100 && sample_rate != 48000) { + LOG(ERROR) << "Unsupported sample rate: " << sample_rate; + return -EINVAL; + } + + avctx_->sample_rate = sample_rate; + avctx_->bit_rate = bit_rate; + avctx_->bit_rate_tolerance = 0; + avctx_->sample_fmt = AV_SAMPLE_FMT_FLTP; + + int rc = avcodec_open2(avctx_, codec, NULL); + if (rc < 0) { + LOG(ERROR) << "Could not open context: " << rc; + return -EINVAL; + } + + return avctx_->frame_size; +} + +void A2dpAacEncoder::cleanup() { + if (avctx_) { + avcodec_free_context(&avctx_); + avctx_ = nullptr; + } +} + +int A2dpAacEncoder::transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, + int o_len) { + int rc; + + AVFrame* frame = av_frame_alloc(); + if (!frame) { + LOG(ERROR) << "Could not alloc frame"; + return -ENOMEM; + } + + frame->nb_samples = avctx_->frame_size; + frame->format = avctx_->sample_fmt; + frame->sample_rate = avctx_->sample_rate; + + rc = av_channel_layout_copy(&frame->ch_layout, &avctx_->ch_layout); + if (rc < 0) { + LOG(ERROR) << "Failed to copy channel layout: " << rc; + av_frame_free(&frame); + return -EINVAL; + } + + rc = av_frame_get_buffer(frame, 0); + if (rc < 0) { + LOG(ERROR) << "Failed to get buffer for frame: " << rc; + av_frame_free(&frame); + return -EIO; + } + + rc = av_frame_make_writable(frame); + if (rc < 0) { + LOG(ERROR) << "Failed to make frame writable: " << rc; + av_frame_free(&frame); + return -EIO; + } + + const int bit_depth = param_.bit_depth(); + const int bytes_per_sample = bit_depth / 8; + const float scaling_factor = (float)1 / (1 << (bit_depth - 1)); + + uint8_t* buff = i_buf; + float* data[] = {(float*)frame->data[0], (float*)frame->data[1]}; + + auto read_pcm = [](uint8_t* buff, int nbits) -> int { + int pcm = 0; + + switch (nbits) { + case 16: + pcm = *((int16_t*)buff); + break; + case 24: + pcm = *buff | *(buff + 1) << 8 | *(buff + 2) << 16; + pcm |= pcm & 0x00800000 ? 0xff000000 : 0; + break; + case 32: + pcm = *((int32_t*)buff); + break; + default: + LOG_ASSERT(false) << "Attempting to read " << nbits + << " bits as bit depth"; + } + + return pcm; + }; + + for (int i = 0; i < i_len / bytes_per_sample; ++i) { + *data[i & 1]++ = read_pcm(buff, bit_depth) * scaling_factor; + buff += bytes_per_sample; + } + + AVPacket* pkt = av_packet_alloc(); + if (!pkt) { + LOG(ERROR) << "Could not alloc packet"; + return -ENOMEM; + } + + rc = avcodec_send_frame(avctx_, frame); + if (rc < 0) { + LOG(ERROR) << "Failed to send frame: " << rc; + av_frame_free(&frame); + av_packet_free(&pkt); + return -EIO; + } + + rc = avcodec_receive_packet(avctx_, pkt); + if (rc < 0 && rc != -EAGAIN) { + LOG(ERROR) << "Failed to receive packet: " << rc; + av_frame_free(&frame); + av_packet_free(&pkt); + return -EIO; + } + + uint8_t* dst = o_buf; + + const uint8_t* header = avctx_->sample_rate == 44100 ? A2DP_AAC_HEADER_44100 + : A2DP_AAC_HEADER_48000; + + std::copy(header, header + A2DP_AAC_HEADER_LEN, dst); + + int written = A2DP_AAC_HEADER_LEN; + dst += written; + + int cap = param_.effective_frame_size(); + if (rc == -EAGAIN || cap < pkt->size + A2DP_AAC_MAX_PREFIX_SIZE) { + if (rc != -EAGAIN) { + LOG(WARNING) << "Dropped pkt: size=" << pkt->size << ", cap=" << cap; + } + static uint8_t silent_frame[7] = { + 0x06, 0x21, 0x10, 0x04, 0x60, 0x8c, 0x1c, + }; + std::copy(silent_frame, std::end(silent_frame), dst); + dst += sizeof(silent_frame); + written += sizeof(silent_frame); + } else { + int fsize = pkt->size; + + while (fsize >= 255) { + *(dst++) = 0xff; + fsize -= 255; + ++written; + } + *(dst++) = fsize; + ++written; + + std::copy(pkt->data, pkt->data + pkt->size, dst); + written += pkt->size; + } + + av_packet_unref(pkt); + av_frame_free(&frame); + av_packet_free(&pkt); + + return written; +} + +} // namespace mmc diff --git a/system/stack/mmc/codec_server/a2dp_aac_mmc_encoder.h b/system/stack/mmc/codec_server/a2dp_aac_mmc_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..f88f136188a1ad51e19b7976c148fd31aabb7dc5 --- /dev/null +++ b/system/stack/mmc/codec_server/a2dp_aac_mmc_encoder.h @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_CODEC_SERVER_A2DP_AAC_MMC_ENCODER_LINUX_H_ +#define MMC_CODEC_SERVER_A2DP_AAC_MMC_ENCODER_LINUX_H_ + +extern "C" { +#include +} + +#include "mmc/mmc_interface/mmc_interface.h" +#include "mmc/proto/mmc_config.pb.h" + +namespace mmc { + +// Implementation of MmcInterface. +// A2dpAacEncoder wraps FFmpeg encode libraries. +class A2dpAacEncoder : public MmcInterface { + public: + explicit A2dpAacEncoder(); + ~A2dpAacEncoder(); + + // A2dpAacEncoder is neither copyable nor movable. + A2dpAacEncoder(const A2dpAacEncoder&) = delete; + A2dpAacEncoder& operator=(const A2dpAacEncoder&) = delete; + + // Inits encoder instance. + // + // Returns: + // Input pcm frame size accepted by the encoder, if init succeeded. + // Negative errno on error, otherwise. + int init(ConfigParam config) override; + + // Releases encoder instance. + void cleanup() override; + + // Encodes data from |i_buf|, and stores the result to |o_buf|. + // + // Returns: + // Encoded data length, if encode succeeded. + // Negative errno on error, otherwise. + int transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, int o_len) override; + + private: + AVCodecContext* avctx_; + AacEncoderParam param_; +}; + +} // namespace mmc + +#endif // MMC_CODEC_SERVER_A2DP_AAC_MMC_ENCODER_LINUX_H_ diff --git a/system/stack/mmc/codec_server/hfp_lc3_mmc_decoder.cc b/system/stack/mmc/codec_server/hfp_lc3_mmc_decoder.cc new file mode 100644 index 0000000000000000000000000000000000000000..d68459441f1303c14d2bcd944dec151bb6b8f896 --- /dev/null +++ b/system/stack/mmc/codec_server/hfp_lc3_mmc_decoder.cc @@ -0,0 +1,92 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mmc/codec_server/hfp_lc3_mmc_decoder.h" + +#include +#include + +#include "mmc/codec_server/lc3_utils.h" +#include "mmc/proto/mmc_config.pb.h" +#include "osi/include/allocator.h" + +namespace mmc { + +HfpLc3Decoder::HfpLc3Decoder() : hfp_lc3_decoder_mem_(nullptr) {} + +HfpLc3Decoder::~HfpLc3Decoder() { cleanup(); } + +int HfpLc3Decoder::init(ConfigParam config) { + cleanup(); + + if (!config.has_hfp_lc3_decoder_param()) { + LOG(ERROR) << "HFP LC3 decoder params are not set"; + return -EINVAL; + } + + param_ = config.hfp_lc3_decoder_param(); + int dt_us = param_.dt_us(); + int sr_hz = param_.sr_hz(); + int sr_pcm_hz = param_.sr_pcm_hz(); + const unsigned dec_size = lc3_decoder_size(dt_us, sr_pcm_hz); + + hfp_lc3_decoder_mem_ = osi_malloc(dec_size); + + hfp_lc3_decoder_ = + lc3_setup_decoder(dt_us, sr_hz, sr_pcm_hz, hfp_lc3_decoder_mem_); + + if (hfp_lc3_decoder_ == nullptr) { + LOG(ERROR) << "Wrong parameters provided"; + return -EINVAL; + } + + return HFP_LC3_PKT_FRAME_LEN; +} + +void HfpLc3Decoder::cleanup() { + if (hfp_lc3_decoder_mem_) { + osi_free_and_reset((void**)&hfp_lc3_decoder_mem_); + LOG(INFO) << "Released the decoder instance"; + } +} + +int HfpLc3Decoder::transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, + int o_len) { + if (o_buf == nullptr || o_len < HFP_LC3_PCM_BYTES + 1) { + LOG(ERROR) << "Output buffer size is less than LC3 frame size"; + return -EINVAL; + } + + // Check header to decide whether it's PLC. + uint8_t* in_frame = + (i_buf[0] || i_buf[1]) ? i_buf + HFP_LC3_H2_HEADER_LEN : nullptr; + + // First byte is reserved to indicate PLC. + uint8_t* out_frame = o_buf + 1; + + /* Note this only fails when wrong parameters are supplied. */ + int rc = lc3_decode(hfp_lc3_decoder_, in_frame, HFP_LC3_PKT_FRAME_LEN, + MapLc3PcmFmt(param_.fmt()), out_frame, param_.stride()); + + if (rc != 0 && rc != 1) { + LOG(WARNING) << "Wrong decode parameters"; + std::fill(o_buf, o_buf + o_len, 0); + } else + o_buf[0] = rc; + return HFP_LC3_PCM_BYTES + 1; +} + +} // namespace mmc diff --git a/system/stack/mmc/codec_server/hfp_lc3_mmc_decoder.h b/system/stack/mmc/codec_server/hfp_lc3_mmc_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..27b83e95b5df20a321ddf112632cac2f7696766f --- /dev/null +++ b/system/stack/mmc/codec_server/hfp_lc3_mmc_decoder.h @@ -0,0 +1,63 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_CODEC_SERVER_HFP_LC3_MMC_DECODER_H_ +#define MMC_CODEC_SERVER_HFP_LC3_MMC_DECODER_H_ + +#include + +#include "mmc/mmc_interface/mmc_interface.h" +#include "mmc/proto/mmc_config.pb.h" + +namespace mmc { + +// Implementation of MmcInterface. +// HfpLc3Decoder wraps lc3 decode libraries. +class HfpLc3Decoder : public MmcInterface { + public: + explicit HfpLc3Decoder(); + ~HfpLc3Decoder(); + + // HfpLc3Decoder is neither copyable nor movable. + HfpLc3Decoder(const HfpLc3Decoder&) = delete; + HfpLc3Decoder& operator=(const HfpLc3Decoder&) = delete; + + // Inits decoder instance. + // + // Returns: + // Input packet size accepted by the decoder, if init succeeded. + // Negative errno on error, otherwise. + int init(ConfigParam config) override; + + // Releases decoder instance. + void cleanup() override; + + // Decodes data from |i_buf| and stores the result in |o_buf|. + // + // Returns: + // Decoded data length, if decode succeeded. + // Negative errno on error, otherwise. + int transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, int o_len) override; + + private: + void* hfp_lc3_decoder_mem_; + lc3_decoder_t hfp_lc3_decoder_; + Lc3Param param_; +}; + +} // namespace mmc + +#endif // MMC_CODEC_SERVER_HFP_LC3_MMC_DECODER_H_ diff --git a/system/stack/mmc/codec_server/hfp_lc3_mmc_encoder.cc b/system/stack/mmc/codec_server/hfp_lc3_mmc_encoder.cc new file mode 100644 index 0000000000000000000000000000000000000000..cbdc72840f22ccb32d4774327ea612f2383800b8 --- /dev/null +++ b/system/stack/mmc/codec_server/hfp_lc3_mmc_encoder.cc @@ -0,0 +1,87 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mmc/codec_server/hfp_lc3_mmc_encoder.h" + +#include +#include + +#include + +#include "mmc/codec_server/lc3_utils.h" +#include "mmc/proto/mmc_config.pb.h" +#include "osi/include/allocator.h" + +namespace mmc { + +HfpLc3Encoder::HfpLc3Encoder() : hfp_lc3_encoder_mem_(nullptr) {} + +HfpLc3Encoder::~HfpLc3Encoder() { cleanup(); } + +int HfpLc3Encoder::init(ConfigParam config) { + cleanup(); + + if (!config.has_hfp_lc3_encoder_param()) { + LOG(ERROR) << "HFP LC3 encoder params are not set"; + return -EINVAL; + } + + param_ = config.hfp_lc3_encoder_param(); + int dt_us = param_.dt_us(); + int sr_hz = param_.sr_hz(); + int sr_pcm_hz = param_.sr_pcm_hz(); + const unsigned enc_size = lc3_encoder_size(dt_us, sr_pcm_hz); + + hfp_lc3_encoder_mem_ = osi_malloc(enc_size); + + hfp_lc3_encoder_ = + lc3_setup_encoder(dt_us, sr_hz, sr_pcm_hz, hfp_lc3_encoder_mem_); + + if (hfp_lc3_encoder_ == nullptr) { + LOG(ERROR) << "Wrong parameters provided"; + return -EINVAL; + } + + return HFP_LC3_PCM_BYTES; +} + +void HfpLc3Encoder::cleanup() { + if (hfp_lc3_encoder_mem_) { + osi_free_and_reset((void**)&hfp_lc3_encoder_mem_); + LOG(INFO) << "Released the encoder instance"; + } +} + +int HfpLc3Encoder::transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, + int o_len) { + if (i_buf == nullptr || o_buf == nullptr) { + LOG(ERROR) << "Buffer is null"; + return -EINVAL; + } + + /* Note this only fails when wrong parameters are supplied. */ + int rc = lc3_encode(hfp_lc3_encoder_, MapLc3PcmFmt(param_.fmt()), i_buf, + param_.stride(), HFP_LC3_PKT_FRAME_LEN, o_buf); + + if (rc != 0) { + LOG(WARNING) << "Wrong encode parameters"; + std::fill(o_buf, o_buf + o_len, 0); + } + + return HFP_LC3_PKT_FRAME_LEN; +} + +} // namespace mmc diff --git a/system/stack/mmc/codec_server/hfp_lc3_mmc_encoder.h b/system/stack/mmc/codec_server/hfp_lc3_mmc_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..b9e66da70ec7dbfbde477c283fb62ee96dca9aab --- /dev/null +++ b/system/stack/mmc/codec_server/hfp_lc3_mmc_encoder.h @@ -0,0 +1,63 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_CODEC_SERVER_HFP_LC3_MMC_ENCODER_H_ +#define MMC_CODEC_SERVER_HFP_LC3_MMC_ENCODER_H_ + +#include + +#include "mmc/mmc_interface/mmc_interface.h" +#include "mmc/proto/mmc_config.pb.h" + +namespace mmc { + +// Implementation of MmcInterface. +// HfpLc3Encoder wraps lc3 encode libraries. +class HfpLc3Encoder : public MmcInterface { + public: + explicit HfpLc3Encoder(); + ~HfpLc3Encoder(); + + // HfpLc3Encoder is neither copyable nor movable. + HfpLc3Encoder(const HfpLc3Encoder&) = delete; + HfpLc3Encoder& operator=(const HfpLc3Encoder&) = delete; + + // Inits encoder instance. + // + // Returns: + // Input pcm frame size accepted by the encoder, if init succeeded. + // Negative errno on error, otherwise. + int init(ConfigParam config) override; + + // Releases encoder instance. + void cleanup() override; + + // Encodes data from |i_buf|, and stores the result to |o_buf|. + // + // Returns: + // Encoded data length, if encode succeeded. + // Negative errno on error, otherwise. + int transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, int o_len) override; + + private: + void* hfp_lc3_encoder_mem_; + lc3_encoder_t hfp_lc3_encoder_; + Lc3Param param_; +}; + +} // namespace mmc + +#endif // MMC_CODEC_SERVER_HFP_LC3_MMC_ENCODER_H_ diff --git a/system/stack/mmc/codec_server/lc3_utils.h b/system/stack/mmc/codec_server/lc3_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..1cba2efc1db1705b6661097e6c37ce42bf3e2e0a --- /dev/null +++ b/system/stack/mmc/codec_server/lc3_utils.h @@ -0,0 +1,47 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_CODEC_SERVER_LC3_UTILS_H_ +#define MMC_CODEC_SERVER_LC3_UTILS_H_ + +#include +#include + +#include "mmc/proto/mmc_config.pb.h" + +namespace mmc { + +// HFP LC3 constants. +const int HFP_LC3_H2_HEADER_LEN = 2; +const int HFP_LC3_PKT_FRAME_LEN = 58; +const int HFP_LC3_PCM_BYTES = 480; + +// Helper that maps MMC pcm format to lc3 pcm format. +inline lc3_pcm_format MapLc3PcmFmt(Lc3Param_PcmFmt fmt) { + switch (fmt) { + case Lc3Param::kLc3PcmFormatS16: + return LC3_PCM_FORMAT_S16; + case Lc3Param::kLc3PcmFormatS24: + return LC3_PCM_FORMAT_S24; + default: + LOG(INFO) + << "No corresponding LC3 PCM format, return `LC3_PCM_FORMAT_S16`."; + return LC3_PCM_FORMAT_S16; + } +} + +} // namespace mmc +#endif // MMC_CODEC_SERVER_LC3_UTILS_H_ diff --git a/system/stack/mmc/daemon/constants.h b/system/stack/mmc/daemon/constants.h new file mode 100644 index 0000000000000000000000000000000000000000..abcd07d33fc2d37e28b7a1e6145c09f0425a4714 --- /dev/null +++ b/system/stack/mmc/daemon/constants.h @@ -0,0 +1,43 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_DAEMON_DBUS_CONSTANTS_H_ +#define MMC_DAEMON_DBUS_CONSTANTS_H_ + +namespace mmc { + +// DBus constants. +constexpr char kMmcServiceName[] = "org.chromium.mmc.CodecManager"; +constexpr char kMmcServiceInterface[] = "org.chromium.mmc.CodecManager"; +constexpr char kMmcServicePath[] = "/org/chromium/mmc/CodecManager"; +const char kMmcServiceError[] = "org.chromium.mmc.CodecManager.Error"; +constexpr char kCodecInitMethod[] = "CodecInit"; +constexpr char kCodecCleanUpMethod[] = "CodecCleanUp"; + +// Socket constants. +const char kMmcSocketName[] = "/run/mmc/sockets/"; +// The maximum number of socket pending connections. +// MMC daemon expects at most two clients, decoder and encoder of one codec. +constexpr int kClientMaximum = 2; +// Socket default maximum buffer size. +constexpr int kMaximumBufferSize = 32768; + +// Thread constants. +constexpr char kWorkerThreadName[] = "bt_mmc_worker_thread"; +constexpr int kThreadCheckTimeout = 1; +} // namespace mmc + +#endif // MMC_DAEMON_DBUS_CONSTANTS_H_ diff --git a/system/stack/mmc/daemon/service.cc b/system/stack/mmc/daemon/service.cc new file mode 100644 index 0000000000000000000000000000000000000000..31ba2e152fd441164f4c61ac56028f3d897dedd7 --- /dev/null +++ b/system/stack/mmc/daemon/service.cc @@ -0,0 +1,319 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mmc/daemon/service.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/message_loop_thread.h" +#include "mmc/codec_server/hfp_lc3_mmc_decoder.h" +#include "mmc/codec_server/hfp_lc3_mmc_encoder.h" +#include "mmc/daemon/constants.h" +#include "mmc/mmc_interface/mmc_interface.h" +#include "mmc/proto/mmc_service.pb.h" + +#if !defined(EXCLUDE_NONSTANDARD_CODECS) +#include "mmc/codec_server/a2dp_aac_mmc_encoder.h" +#endif + +namespace mmc { +namespace { +// Task that would run on the thread. +void StartSocketListener(int fd, struct sockaddr_un addr, + std::promise task_ended, + std::unique_ptr codec_server) { + socklen_t addr_size = sizeof(struct sockaddr_un); + int client_fd = accept(fd, (struct sockaddr*)&addr, &addr_size); + // |fd| is only used for accept. + close(fd); + + if (client_fd < 0) { + LOG(ERROR) << "Failed to accept: " << strerror(errno); + codec_server.release(); + task_ended.set_value(); + return; + } + + std::array i_buf = {}; + std::array o_buf = {}; + + struct pollfd pfd; + pfd.fd = client_fd; + pfd.events = POLLIN; + + while (1) { + // Blocking poll. + int poll_ret = poll(&pfd, 1, -1); + if (poll_ret <= 0) { + LOG(ERROR) << "Poll failed: " << strerror(errno); + break; + } + + // Ignore remaining data in the closed socket. + if (pfd.revents & (POLLHUP | POLLNVAL)) { + LOG(INFO) << "Socket disconnected"; + break; + } + + int i_data_len = + recv(client_fd, i_buf.data(), kMaximumBufferSize, MSG_NOSIGNAL); + if (i_data_len <= 0) { + LOG(ERROR) << "Failed to recv data: " << strerror(errno); + break; + } + + // Start transcode. + int o_data_len = codec_server->transcode(i_buf.data(), i_data_len, + o_buf.data(), kMaximumBufferSize); + if (o_data_len < 0) { + LOG(ERROR) << "Failed to transcode: " << strerror(-o_data_len); + break; + } + + int sent_rc = send(client_fd, o_buf.data(), o_data_len, MSG_NOSIGNAL); + if (sent_rc <= 0) { + LOG(ERROR) << "Failed to send data: " << strerror(errno); + break; + } + o_buf.fill(0); + } + close(client_fd); + unlink(addr.sun_path); + codec_server.release(); + task_ended.set_value(); + return; +} + +} // namespace + +Service::Service(base::OnceClosure shutdown_callback) + : shutdown_callback_(std::move(shutdown_callback)), + weak_ptr_factory_(this) {} + +bool Service::Init() { + // Set up the dbus service. + dbus::Bus::Options opts; + opts.bus_type = dbus::Bus::SYSTEM; + bus_ = new dbus::Bus(std::move(opts)); + + if (!bus_->Connect()) { + LOG(ERROR) << "Failed to connect to system bus"; + return false; + } + + exported_object_ = bus_->GetExportedObject(dbus::ObjectPath(kMmcServicePath)); + if (!exported_object_) { + LOG(ERROR) << "Failed to export " << kMmcServicePath << " object"; + return false; + } + + using ServiceMethod = void (Service::*)(dbus::MethodCall*, + dbus::ExportedObject::ResponseSender); + const std::map kServiceMethods = { + {kCodecInitMethod, &Service::CodecInit}, + {kCodecCleanUpMethod, &Service::CodecCleanUp}, + }; + + for (const auto& iter : kServiceMethods) { + bool ret = exported_object_->ExportMethodAndBlock( + kMmcServiceInterface, iter.first, + base::BindRepeating(iter.second, weak_ptr_factory_.GetWeakPtr())); + if (!ret) { + LOG(ERROR) << "Failed to export method: " << iter.first; + return false; + } + } + + if (!bus_->RequestOwnershipAndBlock(kMmcServiceName, + dbus::Bus::REQUIRE_PRIMARY)) { + LOG(ERROR) << "Failed to take ownership of " << kMmcServiceName; + return false; + } + return true; +} + +void Service::CodecInit(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender sender) { + dbus::MessageReader reader(method_call); + auto dbus_response = dbus::Response::FromMethodCall(method_call); + + dbus::MessageWriter writer(dbus_response.get()); + + CodecInitRequest request; + CodecInitResponse response; + + if (!reader.PopArrayOfBytesAsProto(&request)) { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, + "Unable to parse CodecInitRequest from message")); + return; + } + + if (!request.has_config()) { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, "'Config Param' must be set")); + return; + } + + // Create codec server instance. + std::unique_ptr codec_server; + if (request.config().has_hfp_lc3_decoder_param()) { + codec_server = std::make_unique(); + } else if (request.config().has_hfp_lc3_encoder_param()) { + codec_server = std::make_unique(); + } +#if !defined(EXCLUDE_NONSTANDARD_CODECS) + else if (request.config().has_a2dp_aac_encoder_param()) { + codec_server = std::make_unique(); + } +#endif + else { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, "Codec type must be specified")); + return; + } + + int frame_size = codec_server->init(request.config()); + if (frame_size < 0) { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, + "Init codec server failed: " + std::string(strerror(-frame_size)))); + return; + } + response.set_input_frame_size(frame_size); + + // Generate socket name for client. + std::string socket_path = + std::string(kMmcSocketName) + base::UnguessableToken::Create().ToString(); + response.set_socket_token(socket_path); + + int skt_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (skt_fd < 0) { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, + "Create socket failed: " + std::string(strerror(errno)))); + return; + } + + struct sockaddr_un addr = {}; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, response.socket_token().c_str(), + sizeof(addr.sun_path) - 1); + unlink(addr.sun_path); + + if (bind(skt_fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) == -1) { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, + "Bind socket failed: " + std::string(strerror(errno)))); + return; + } + + // mmc_service group can read/write the socket. + int rc = chmod(addr.sun_path, 0770); + if (rc < 0) { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, + "Chmod socket failed: " + std::string(strerror(errno)))); + return; + } + + if (listen(skt_fd, kClientMaximum) == -1) { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, + "Listen socket failed: " + std::string(strerror(errno)))); + return; + } + + // Create a thread and pass codec server and socket fd to it. + if (!StartWorkerThread(skt_fd, std::move(addr), std::move(codec_server))) { + std::move(sender).Run(dbus::ErrorResponse::FromMethodCall( + method_call, kMmcServiceError, "No free thread available")); + return; + } + + writer.AppendProtoAsArrayOfBytes(response); + std::move(sender).Run(std::move(dbus_response)); + return; +} + +void Service::CodecCleanUp(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender sender) { + auto dbus_response = dbus::Response::FromMethodCall(method_call); + RemoveIdleThread(); + std::move(sender).Run(std::move(dbus_response)); + return; +} + +bool Service::StartWorkerThread(int fd, struct sockaddr_un addr, + std::unique_ptr codec_server) { + // Each thread has its associated future to indicate task completion. + std::promise task_ended; + thread_pool_.push_back(std::make_pair( + std::make_unique(kWorkerThreadName), + std::make_unique>(task_ended.get_future()))); + + // Start up thread and assign task to it. + thread_pool_.back().first->StartUp(); + if (!thread_pool_.back().first->IsRunning()) { + LOG(ERROR) << "Failed to start thread"; + return false; + } + + // Real-time scheduling increases thread priority. + // Without it, the thread still works. + if (!thread_pool_.back().first->EnableRealTimeScheduling()) { + LOG(WARNING) << "Failed to enable real time scheduling"; + } + + if (!thread_pool_.back().first->DoInThread( + FROM_HERE, + base::BindOnce(&StartSocketListener, fd, std::move(addr), + std::move(task_ended), std::move(codec_server)))) { + LOG(ERROR) << "Failed to run task"; + return false; + } + + return true; +} + +void Service::RemoveIdleThread() { + for (auto thread = thread_pool_.begin(); thread != thread_pool_.end();) { + if (thread->second->wait_for(std::chrono::milliseconds( + kThreadCheckTimeout)) == std::future_status::ready) { + // The task is over, close the thread and remove it from the thread pool. + thread->first->ShutDown(); + thread = thread_pool_.erase(thread); + } else { + thread++; + } + } +} + +} // namespace mmc diff --git a/system/stack/mmc/daemon/service.h b/system/stack/mmc/daemon/service.h new file mode 100644 index 0000000000000000000000000000000000000000..129161e91746b9d1ce20d4542ddc9b3bb9a22b77 --- /dev/null +++ b/system/stack/mmc/daemon/service.h @@ -0,0 +1,92 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_DAEMON_SERVICE_H_ +#define MMC_DAEMON_SERVICE_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/message_loop_thread.h" +#include "mmc/mmc_interface/mmc_interface.h" + +namespace mmc { + +class Service final { + public: + explicit Service(base::OnceClosure shutdown_callback); + + // Service is neither copyable nor movable. + Service(const Service&) = delete; + Service& operator=(const Service&) = delete; + + // Connects to DBus and exports methods for client to call. + bool Init(); + + private: + /* DBus Methods */ + // Main thread creates a codec server instance and a socket, + // and calls |StartWorkerThread| to let one thread start listening on the + // socket. + // + // Expected input message: + // |CodecInitRequest| with |ConfigParam| set. + // Response: + // |CodecInitResponse|, if |CodecInit| succeeded. + // ErrorResponse, otherwise. + void CodecInit(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender sender); + + // Main thread removes idle threads from the thread poll. + // + // No input message needed. + // Response: + // dbus::Response, implying |CodecCleanUp| finished. + void CodecCleanUp(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender sender); + + /* Thread Management*/ + // Adds a thread to the thread pool and makes it listen on the socket fd. + bool StartWorkerThread(int fd, struct sockaddr_un addr, + std::unique_ptr codec_server); + + // Removes idle threads from the thread pool. + void RemoveIdleThread(); + + base::OnceClosure shutdown_callback_; + + scoped_refptr bus_; + dbus::ExportedObject* exported_object_; // Owned by the Bus object. + + std::vector, + std::unique_ptr>>> + thread_pool_; + + base::WeakPtrFactory weak_ptr_factory_; +}; + +} // namespace mmc + +#endif // MMC_DAEMON_SERVICE_H_ diff --git a/system/stack/mmc/dbus_permissions/org.chromium.mmc.CodecManager.conf b/system/stack/mmc/dbus_permissions/org.chromium.mmc.CodecManager.conf new file mode 100644 index 0000000000000000000000000000000000000000..a63e4e6d555945d28c8f22ebefa5ed266bfe32e6 --- /dev/null +++ b/system/stack/mmc/dbus_permissions/org.chromium.mmc.CodecManager.conf @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/system/stack/mmc/dbus_service/org.chromium.mmc.CodecManager.service b/system/stack/mmc/dbus_service/org.chromium.mmc.CodecManager.service new file mode 100644 index 0000000000000000000000000000000000000000..af0fb6b296684b6ef42b2218e362603c81129798 --- /dev/null +++ b/system/stack/mmc/dbus_service/org.chromium.mmc.CodecManager.service @@ -0,0 +1,20 @@ +# +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# D-Bus on-demand service specification for CodecManager. +# Will be installed into /usr/share/dbus-1/system-services/. +[D-BUS Service] +Name=org.chromium.mmc.CodecManager +Exec=/sbin/start mmc_service +User=root diff --git a/system/stack/mmc/init/mmc_service.conf b/system/stack/mmc/init/mmc_service.conf new file mode 100644 index 0000000000000000000000000000000000000000..fb32089425e58ad3824c136b96f1228b24f3cfff --- /dev/null +++ b/system/stack/mmc/init/mmc_service.conf @@ -0,0 +1,45 @@ +# +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +description "Start daemon for Minijailed Media Codec (MMC) Service" +author "ChromeOS BT " + +# Mmc Codec Manager can recover by restarting. +oom score -100 + +# This service is started by D-Bus service activation through +# org.chromium.mmc.CodecManager.service +stop on stopping boot-services + +# Minijail forks off the desired process and exits after forking. +expect fork + +pre-start script + # Check if Boot-services is still running before starting mmc_service. + # This is to prevent new dbus-activated instances from getting + # started once the system is beginning to shut down. + if ! initctl status boot-services | grep -q running; then + stop + exit 0 + fi +end script + +exec minijail0 --config /usr/share/minijail/mmc.conf \ + -- /usr/bin/mmc_service + +# Wait until DBus service becomes available. +post-start exec minijail0 -u mmc_service -g mmc_service /usr/bin/gdbus \ + wait --system --timeout 15 org.chromium.mmc.CodecManager diff --git a/system/stack/mmc/main.cc b/system/stack/mmc/main.cc new file mode 100644 index 0000000000000000000000000000000000000000..e040ebefae5950c9053ee817596bbf69a7e2db40 --- /dev/null +++ b/system/stack/mmc/main.cc @@ -0,0 +1,106 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mmc/daemon/service.h" + +// syslog.h and base/logging.h both try to #define LOG_INFO and LOG_WARNING. +// We need to #undef at least these two before including base/logging.h. The +// others are included to be consistent. +namespace { +const int kSyslogDebug = LOG_DEBUG; +const int kSyslogInfo = LOG_INFO; +const int kSyslogWarning = LOG_WARNING; +const int kSyslogError = LOG_ERR; +const int kSyslogCritical = LOG_CRIT; + +#undef LOG_INFO +#undef LOG_WARNING +#undef LOG_ERR +#undef LOG_CRIT +} // namespace + +#include + +static bool MessageHandler(int severity, const char* file, int line, + size_t message_start, const std::string& message) { + const auto str = base::StringPrintf("%s:%d - %s", file, line, + message.substr(message_start).c_str()); + + switch (severity) { + case logging::LOGGING_INFO: + severity = kSyslogInfo; + break; + + case logging::LOGGING_WARNING: + severity = kSyslogWarning; + break; + + case logging::LOGGING_ERROR: + severity = kSyslogError; + break; + + case logging::LOGGING_FATAL: + severity = kSyslogCritical; + break; + + default: + severity = kSyslogDebug; + break; + } + + syslog(severity, "%s", str.c_str()); + + if (severity == kSyslogCritical) abort(); + + return true; +} + +int main(int argc, char* argv[]) { + // Set up syslog to stderr. + logging::LoggingSettings settings; + settings.logging_dest = + logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR; + logging::SetLogItems(false, false, false, false); + logging::InitLogging(settings); + logging::SetLogMessageHandler(MessageHandler); + + LOG(INFO) << "Start MMC daemon"; + + // These are needed to send D-Bus signals and receive messages. + // Even though they are not used directly, they set up some global state + // needed by the D-Bus library. + base::SingleThreadTaskExecutor task_executor(base::MessagePumpType::IO); + base::FileDescriptorWatcher watcher(task_executor.task_runner()); + base::AtExitManager at_exit_manager; + + base::RunLoop run_loop; + + auto service = std::make_unique(run_loop.QuitClosure()); + CHECK(service->Init()); + + run_loop.Run(); + + return 0; +} diff --git a/system/gd/btaa/BUILD.gn b/system/stack/mmc/metrics/BUILD.gn similarity index 69% rename from system/gd/btaa/BUILD.gn rename to system/stack/mmc/metrics/BUILD.gn index 9beaf1e5acbaf5f3be15865379f59e2e1a7dfe30..276693cb37738022dd7cfecdb76f08c4e8690691 100644 --- a/system/gd/btaa/BUILD.gn +++ b/system/stack/mmc/metrics/BUILD.gn @@ -1,5 +1,5 @@ # -# Copyright 2021 Google, Inc. +# Copyright 2023 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,9 +14,12 @@ # limitations under the License. # -source_set("BluetoothBtaaSources_linux") { - sources = [ "linux/activity_attribution.cc" ] - - configs += [ "//bt/system/gd:gd_defaults" ] - deps = [ "//bt/system/gd:gd_default_deps" ] +source_set("libmmc_metrics"){ + configs += [ "//bt/system/stack/mmc:target_defaults" ] + sources = [ + "mmc_rtt_logger.cc", + ] + deps = [ + "//bt/system:libbt-platform-protos-lite", + ] } diff --git a/system/stack/mmc/metrics/mmc_rtt_logger.cc b/system/stack/mmc/metrics/mmc_rtt_logger.cc new file mode 100644 index 0000000000000000000000000000000000000000..b697dbbe4be1722e20b7c14643adcf337dc27ef2 --- /dev/null +++ b/system/stack/mmc/metrics/mmc_rtt_logger.cc @@ -0,0 +1,52 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mmc/metrics/mmc_rtt_logger.h" + +#include + +#include +#include +#include + +#include "stack/include/stack_metrics_logging.h" + +namespace mmc { + +MmcRttLogger::MmcRttLogger(int codec_type) + : codec_type_(codec_type), num_requests_(0), rtt_sum_(0), maximum_rtt_(0) {} + +MmcRttLogger::~MmcRttLogger() {} + +void MmcRttLogger::RecordRtt(int64_t elapsed_time) { + if (elapsed_time <= 0) return; + num_requests_ += 1; + rtt_sum_ += elapsed_time; + maximum_rtt_ = std::max(maximum_rtt_, elapsed_time); + return; +} + +void MmcRttLogger::UploadTranscodeRttStatics() { + if (num_requests_ == 0) return; + log_mmc_transcode_rtt_stats(maximum_rtt_, rtt_sum_ / num_requests_, + num_requests_, codec_type_); + num_requests_ = 0; + rtt_sum_ = 0; + maximum_rtt_ = 0; + return; +} + +} // namespace mmc diff --git a/system/stack/mmc/metrics/mmc_rtt_logger.h b/system/stack/mmc/metrics/mmc_rtt_logger.h new file mode 100644 index 0000000000000000000000000000000000000000..1987c20004c876f1441459178d0598a79969efcb --- /dev/null +++ b/system/stack/mmc/metrics/mmc_rtt_logger.h @@ -0,0 +1,53 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_METRICS_MMC_RTT_LOGGER_H_ +#define MMC_METRICS_MMC_RTT_LOGGER_H_ + +#include +#include + +namespace mmc { + +// MmcRttLogger computes and uploads below rtt stats: +// Maximum rtt, mean rtt, num requests, codec type. +class MmcRttLogger { + public: + explicit MmcRttLogger(int codec_type); + ~MmcRttLogger(); + + // MmcRttLogger is neither copyable nor movable. + MmcRttLogger(const MmcRttLogger&) = delete; + MmcRttLogger& operator=(const MmcRttLogger&) = delete; + + // Records elapsed_time (in microseconds). + // Elapsed time should be positive, otherwise it won't be recorded. + void RecordRtt(int64_t elapsed_time); + + // Computes transcode rtt statics, uploads record via bluetooth metrics api, + // and clears the record. Empty record will be ignored. + void UploadTranscodeRttStatics(); + + private: + int codec_type_; + int64_t num_requests_; + double rtt_sum_; // for computing mean rtt + int64_t maximum_rtt_; +}; + +} // namespace mmc + +#endif // MMC_METRICS_MMC_RTT_LOGGER_H_ diff --git a/system/stack/mmc/minijail/mmc.conf b/system/stack/mmc/minijail/mmc.conf new file mode 100644 index 0000000000000000000000000000000000000000..427162b2dde9cdea46eafafedc5981fe82725013 --- /dev/null +++ b/system/stack/mmc/minijail/mmc.conf @@ -0,0 +1,37 @@ +% minijail-config-file v0 + +# Used jailing parameters: +# -e: enter new network namespace (for process that +# doesn't need network access); +# -i: minijail0 exits right after forking. +# -l: new IPC namespace (isolates IPC resources). +# -N: new cgroup namespace. +# -n: set no new privileges (no_new_privs bit). +# -p: Enter new pid namespace (implies -vr). +# --profile=minimalistic-mountns: Enables mount and process namespace +# which includes /var/empty, /, proc (RO), /dev/log, /tmp (tmpfs). +# -u: change userid to . +# -g: change gid to . +# -G: inherit supplementary groups from new uid. +# -c: cap_sys_nice=e (1 << 23). +# --uts: enters new UTS namespace. It makes changes to the host/domain +# name not affect the rest of the system. +# -k: regular mount (source, target, filesystemtype, mountflags, data) +# -b /run/dbus: mount /run/dbus to be able to communicate with D-bus. +# -b /run/mmc/sockets: mount /run/mmc/sockets to be able to create sockets. + +e +i +l +N +n +p +uts +u = mmc_service +g = mmc_service +G +c = cap_sys_nice=e +profile = minimalistic-mountns +mount = tmpfs,/run,tmpfs,MS_NODEV|MS_NOSUID|MS_NOEXEC,mode=755,size=10M +bind-mount = /run/dbus +bind-mount = /run/mmc/sockets,/run/mmc/sockets,1 diff --git a/system/stack/mmc/mmc_interface/mmc_interface.h b/system/stack/mmc/mmc_interface/mmc_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..a6c35f0c6cb44d18814d6047872d462c41402db8 --- /dev/null +++ b/system/stack/mmc/mmc_interface/mmc_interface.h @@ -0,0 +1,52 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MMC_MMC_INTERFACE_MMC_INTERFACE_H_ +#define MMC_MMC_INTERFACE_MMC_INTERFACE_H_ + +#include + +#include "mmc/proto/mmc_config.pb.h" + +namespace mmc { + +// An abstract interface representing either an encoder or a decoder. +class MmcInterface { + public: + virtual ~MmcInterface() = default; + + // Builds and configures the encoder/decoder instance. + // + // Returns: + // Input frame size accepted by the transcoder, if init succeeded. + // Negative errno on error, otherwise. + virtual int init(ConfigParam config) = 0; + + // Resets the encoder/decoder instance. + virtual void cleanup() = 0; + + // Transcodes data in |i_buf|, and stores the result in |o_buf|. + // + // Returns: + // Transcoded data length, if transcode succeeded. + // Negative errno on error, otherwise. + virtual int transcode(uint8_t* i_buf, int i_len, uint8_t* o_buf, + int o_len) = 0; +}; + +} // namespace mmc + +#endif // MMC_MMC_INTERFACE_MMC_INTERFACE_H_ diff --git a/system/stack/mmc/proto/BUILD.gn b/system/stack/mmc/proto/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..8245c2aa5da206a4cf4cdb054a0d76eec5e4d2f3 --- /dev/null +++ b/system/stack/mmc/proto/BUILD.gn @@ -0,0 +1,46 @@ +# +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import("//common-mk/proto_library.gni") + +proto_library("mmc_config_proto") { + proto_in_dir = "./" + proto_out_dir = "include/mmc/proto" + sources = [ + "${proto_in_dir}/mmc_config.proto", + ] + standalone=true + if (use.test) { + # Override optimize_for option in proto file. + gen_cpp_mode = "speed" + all_dependent_pkg_deps = [ "protobuf" ] + } +} + +proto_library("mmc_service_proto") { + proto_in_dir = "./" + proto_out_dir = "include/mmc/proto" + sources = [ + "${proto_in_dir}/mmc_service.proto", + ] + deps = [ ":mmc_config_proto" ] + standalone=true + if (use.test) { + # Override optimize_for option in proto file. + gen_cpp_mode = "speed" + all_dependent_pkg_deps = [ "protobuf" ] + } +} diff --git a/system/stack/mmc/proto/mmc_config.proto b/system/stack/mmc/proto/mmc_config.proto new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ead1b47248fcbe561d3ec79893fbd697f51a --- /dev/null +++ b/system/stack/mmc/proto/mmc_config.proto @@ -0,0 +1,110 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; + +package mmc; + +option optimize_for = LITE_RUNTIME; + +// union of Lc3 config and codec parameters +message Lc3Param { + // encoder/decoder config + int32 dt_us = 1; + int32 sr_hz = 2; + int32 sr_pcm_hz = 3; + + // encode/decode parameter + enum PcmFmt { + kLc3PcmFormatS16 = 0; + kLc3PcmFormatS24 = 1; + } + + PcmFmt fmt = 4; + int32 stride = 5; +} + +// corresponding to SBC_ENC_PARAMS +message SbcEncoderParam { + enum SamplingFreq { + kSbcSf16000 = 0; + kSbcSf32000 = 1; + kSbcSf44100 = 2; + kSbcSf48000 = 3; + } + + enum ChannelMode { + kSbcMono = 0; + kSbcDual = 1; + kSbcStereo = 2; + kSbcJointStereo = 3; + } + + enum AllocationMethod { + kSbcLoudNess = 0; + kSbcSnr = 1; + } + + // Default to be kSbcFormatGeneral for SBC if not assigned. + // Assigning to kSbcFormatMsbc for MSBC. + enum Format { + kSbcFormatGeneral = 0; + kSbcFormatMsbc = 1; + } + + // encoder config + int32 num_of_subbands = 1; + int32 num_of_channels = 2; + int32 num_of_blocks = 3; + int32 bit_pool = 4; + int32 bit_rate = 5; + SamplingFreq sampling_freq = 6; + ChannelMode channel_mode = 7; + AllocationMethod allocation_method = 8; + Format format = 9; +} + +message SbcDecoderParam { + // decoder config + int32 max_channels = 1; + int32 stride = 2; + bool enhanced = 3; +} + +message AacEncoderParam { + // encoder config + int32 sample_rate = 1; + int32 channel_count = 2; + int32 bit_rate = 3; + + // encode parameter + int32 bit_depth = 4; + int32 effective_frame_size = 5; +} + +// union of different codec parameters +message ConfigParam { + // This determines the codec type and whether it is an encoder or a decoder. + oneof codec_param { + // HFP LC3 encoder and decoder have same parameter type. + Lc3Param hfp_lc3_encoder_param = 1; + Lc3Param hfp_lc3_decoder_param = 2; + // HFP MSBC use SBC parameters + SbcEncoderParam hfp_msbc_encoder_param = 3; + SbcDecoderParam hfp_msbc_decoder_param = 4; + AacEncoderParam a2dp_aac_encoder_param = 5; + } +} diff --git a/system/stack/mmc/proto/mmc_service.proto b/system/stack/mmc/proto/mmc_service.proto new file mode 100644 index 0000000000000000000000000000000000000000..c7819b80834fde53336d63f8cc8ab695dcc5a062 --- /dev/null +++ b/system/stack/mmc/proto/mmc_service.proto @@ -0,0 +1,35 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; + +package mmc; + +import "mmc_config.proto"; + +option optimize_for = LITE_RUNTIME; + +message CodecInitRequest { + // Codec-specific parameters passed by client. + ConfigParam config = 1; +} + +message CodecInitResponse { + // Socket name generated by the daemon. + string socket_token = 1; + // Input frame size accepted by the codec server. + int32 input_frame_size = 2; +} diff --git a/system/stack/mmc/test/hfp_lc3_mmc_decoder_test.cc b/system/stack/mmc/test/hfp_lc3_mmc_decoder_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..580358602eb0182e7f8d96305631cc3c9e262144 --- /dev/null +++ b/system/stack/mmc/test/hfp_lc3_mmc_decoder_test.cc @@ -0,0 +1,197 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mmc/codec_server/hfp_lc3_mmc_decoder.h" + +#include +#include +#include + +#include +#include + +#include "mmc/codec_server/lc3_utils.h" +#include "mmc/proto/mmc_config.pb.h" +#include "mmc/test/mock/mock_embdrv_lc3.h" +#include "test/common/mock_functions.h" +#include "test/mock/mock_osi_allocator.h" + +namespace { + +using ::google::protobuf::TextFormat; +using ::testing::Contains; +using ::testing::Each; +using ::testing::Ne; +using ::testing::Test; + +constexpr char kLc3EncoderConfig[] = R"( + hfp_lc3_encoder_param: {} +)"; + +constexpr char kLc3DecoderConfig[] = R"( + hfp_lc3_decoder_param: {} +)"; + +const int kInputLen = mmc::HFP_LC3_PKT_FRAME_LEN; +const int kOutputLen = mmc::HFP_LC3_PCM_BYTES + 1; +const uint8_t kInputBuf[kInputLen] = {0}; +static uint8_t kOutputBuf[kOutputLen] = {0}; + +class HfpLc3DecoderTest : public Test { + public: + protected: + void SetUp() override { + reset_mock_function_count_map(); + decoder_ = std::make_unique(); + } + void TearDown() override { decoder_.release(); } + std::unique_ptr decoder_ = nullptr; +}; + +class HfpLc3DecoderWithInitTest : public HfpLc3DecoderTest { + public: + protected: + void SetUp() override { + test::mock::osi_allocator::osi_malloc.body = [&](size_t size) { + this->lc3_decoder_ = new struct lc3_decoder; + return (void*)this->lc3_decoder_; + }; + test::mock::embdrv_lc3::lc3_setup_decoder.body = + [this](int dt_us, int sr_hz, int sr_pcm_hz, void* mem) { + return this->lc3_decoder_; + }; + test::mock::osi_allocator::osi_free_and_reset.body = [&](void** p_ptr) { + delete this->lc3_decoder_; + lc3_decoder_ = nullptr; + *p_ptr = nullptr; + return; + }; + std::fill(kOutputBuf, kOutputBuf + kOutputLen, 1); + + HfpLc3DecoderTest::SetUp(); + mmc::ConfigParam lc3_decoder_config; + ASSERT_TRUE( + TextFormat::ParseFromString(kLc3DecoderConfig, &lc3_decoder_config)); + ASSERT_EQ(decoder_->init(lc3_decoder_config), mmc::HFP_LC3_PKT_FRAME_LEN); + } + void TearDown() override { + HfpLc3DecoderTest::TearDown(); + test::mock::embdrv_lc3::lc3_setup_decoder = {}; + test::mock::osi_allocator::osi_malloc = {}; + test::mock::osi_allocator::osi_free_and_reset = {}; + std::fill(kOutputBuf, kOutputBuf + kOutputLen, 0); + } + struct lc3_decoder* lc3_decoder_ = nullptr; +}; + +TEST_F(HfpLc3DecoderTest, InitWrongCodec) { + mmc::ConfigParam lc3_encoder_config; + ASSERT_TRUE( + TextFormat::ParseFromString(kLc3EncoderConfig, &lc3_encoder_config)); + + int ret = decoder_->init(lc3_encoder_config); + EXPECT_EQ(ret, -EINVAL); + EXPECT_EQ(get_func_call_count("lc3_setup_decoder"), 0); +} + +TEST_F(HfpLc3DecoderTest, InitWrongConfig) { + mmc::ConfigParam lc3_decoder_config; + ASSERT_TRUE( + TextFormat::ParseFromString(kLc3DecoderConfig, &lc3_decoder_config)); + + // lc3_setup_decoder failed due to wrong parameters (returned nullptr). + test::mock::embdrv_lc3::lc3_setup_decoder.body = + [](int dt_us, int sr_hz, int sr_pcm_hz, void* mem) { return nullptr; }; + + int ret = decoder_->init(lc3_decoder_config); + EXPECT_EQ(ret, -EINVAL); + EXPECT_EQ(get_func_call_count("lc3_setup_decoder"), 1); + + test::mock::embdrv_lc3::lc3_setup_decoder = {}; +} + +TEST_F(HfpLc3DecoderTest, InitSuccess) { + mmc::ConfigParam lc3_decoder_config; + ASSERT_TRUE( + TextFormat::ParseFromString(kLc3DecoderConfig, &lc3_decoder_config)); + + // lc3_setup_decoder returns decoder instance pointer. + struct lc3_decoder lc3_decoder; + test::mock::embdrv_lc3::lc3_setup_decoder.body = + [&lc3_decoder](int dt_us, int sr_hz, int sr_pcm_hz, void* mem) { + return &lc3_decoder; + }; + + int ret = decoder_->init(lc3_decoder_config); + EXPECT_EQ(ret, mmc::HFP_LC3_PKT_FRAME_LEN); + EXPECT_EQ(get_func_call_count("lc3_setup_decoder"), 1); + + test::mock::embdrv_lc3::lc3_setup_decoder = {}; +} + +TEST_F(HfpLc3DecoderWithInitTest, CleanUp) { + decoder_->cleanup(); + EXPECT_EQ(get_func_call_count("osi_free_and_reset"), 1); +} + +TEST_F(HfpLc3DecoderTest, TranscodeNullBuffer) { + // Null output buffer. + int ret = decoder_->transcode((uint8_t*)kInputBuf, kInputLen, nullptr, 0); + EXPECT_EQ(ret, -EINVAL); + EXPECT_EQ(get_func_call_count("lc3_decode"), 0); +} + +TEST_F(HfpLc3DecoderWithInitTest, TranscodeWrongParam) { + // lc3_decode failed (returned value neither zero nor one). + test::mock::embdrv_lc3::lc3_decode.return_value = -1; + + int ret = decoder_->transcode((uint8_t*)kInputBuf, kInputLen, kOutputBuf, + kOutputLen); + EXPECT_EQ(ret, mmc::HFP_LC3_PCM_BYTES + 1); + EXPECT_THAT(kOutputBuf, Each(0)); + EXPECT_EQ(get_func_call_count("lc3_decode"), 1); + + test::mock::embdrv_lc3::lc3_decode = {}; +} + +TEST_F(HfpLc3DecoderWithInitTest, TranscodePLC) { + // lc3_decode conducted PLC (return one). + test::mock::embdrv_lc3::lc3_decode.return_value = 1; + + int ret = decoder_->transcode((uint8_t*)kInputBuf, kInputLen, kOutputBuf, + kOutputLen); + EXPECT_EQ(ret, mmc::HFP_LC3_PCM_BYTES + 1); + EXPECT_EQ(kOutputBuf[0], 1); + EXPECT_EQ(get_func_call_count("lc3_decode"), 1); + + test::mock::embdrv_lc3::lc3_decode = {}; +} + +TEST_F(HfpLc3DecoderWithInitTest, TranscodeSuccess) { + // lc3_decode succeeded (return zero value). + test::mock::embdrv_lc3::lc3_decode.return_value = 0; + + int ret = decoder_->transcode((uint8_t*)kInputBuf, kInputLen, kOutputBuf, + kOutputLen); + EXPECT_EQ(ret, mmc::HFP_LC3_PCM_BYTES + 1); + EXPECT_EQ(kOutputBuf[0], 0); + EXPECT_THAT(kOutputBuf, Contains(Ne(0))); + EXPECT_EQ(get_func_call_count("lc3_decode"), 1); + + test::mock::embdrv_lc3::lc3_decode = {}; +} + +} // namespace diff --git a/system/stack/mmc/test/hfp_lc3_mmc_encoder_test.cc b/system/stack/mmc/test/hfp_lc3_mmc_encoder_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..8d462b1a463cc87a85a9eaba4c8822e48ead8171 --- /dev/null +++ b/system/stack/mmc/test/hfp_lc3_mmc_encoder_test.cc @@ -0,0 +1,188 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mmc/codec_server/hfp_lc3_mmc_encoder.h" + +#include +#include +#include + +#include +#include + +#include "mmc/codec_server/lc3_utils.h" +#include "mmc/proto/mmc_config.pb.h" +#include "mmc/test/mock/mock_embdrv_lc3.h" +#include "test/common/mock_functions.h" +#include "test/mock/mock_osi_allocator.h" + +namespace { + +using ::google::protobuf::TextFormat; +using ::testing::Contains; +using ::testing::Each; +using ::testing::Ne; +using ::testing::Test; + +constexpr char kLc3EncoderConfig[] = R"( + hfp_lc3_encoder_param: {} +)"; + +constexpr char kLc3DecoderConfig[] = R"( + hfp_lc3_decoder_param: {} +)"; + +const int kInputLen = mmc::HFP_LC3_PCM_BYTES; +const int kOutputLen = mmc::HFP_LC3_PKT_FRAME_LEN; +const uint8_t kInputBuf[kInputLen] = {0}; +static uint8_t kOutputBuf[kOutputLen] = {0}; + +class HfpLc3EncoderTest : public Test { + public: + protected: + void SetUp() override { + reset_mock_function_count_map(); + encoder_ = std::make_unique(); + } + void TearDown() override { encoder_.release(); } + std::unique_ptr encoder_ = nullptr; +}; + +class HfpLc3EncoderWithInitTest : public HfpLc3EncoderTest { + public: + protected: + void SetUp() override { + test::mock::osi_allocator::osi_malloc.body = [&](size_t size) { + this->lc3_encoder_ = new struct lc3_encoder; + return (void*)this->lc3_encoder_; + }; + test::mock::embdrv_lc3::lc3_setup_encoder.body = + [this](int dt_us, int sr_hz, int sr_pcm_hz, void* mem) { + return this->lc3_encoder_; + }; + test::mock::osi_allocator::osi_free_and_reset.body = [&](void** p_ptr) { + delete this->lc3_encoder_; + lc3_encoder_ = nullptr; + *p_ptr = nullptr; + return; + }; + std::fill(kOutputBuf, kOutputBuf + kOutputLen, 1); + + HfpLc3EncoderTest::SetUp(); + mmc::ConfigParam lc3_encoder_config; + ASSERT_TRUE( + TextFormat::ParseFromString(kLc3EncoderConfig, &lc3_encoder_config)); + ASSERT_EQ(encoder_->init(lc3_encoder_config), mmc::HFP_LC3_PCM_BYTES); + } + void TearDown() override { + HfpLc3EncoderTest::TearDown(); + test::mock::embdrv_lc3::lc3_setup_encoder = {}; + test::mock::osi_allocator::osi_malloc = {}; + test::mock::osi_allocator::osi_free_and_reset = {}; + std::fill(kOutputBuf, kOutputBuf + kOutputLen, 0); + } + struct lc3_encoder* lc3_encoder_ = nullptr; +}; + +TEST_F(HfpLc3EncoderTest, InitWrongCodec) { + mmc::ConfigParam lc3_decoder_config; + ASSERT_TRUE( + TextFormat::ParseFromString(kLc3DecoderConfig, &lc3_decoder_config)); + + int ret = encoder_->init(lc3_decoder_config); + EXPECT_EQ(ret, -EINVAL); + EXPECT_EQ(get_func_call_count("lc3_setup_encoder"), 0); +} + +TEST_F(HfpLc3EncoderTest, InitWrongConfig) { + mmc::ConfigParam lc3_encoder_config; + ASSERT_TRUE( + TextFormat::ParseFromString(kLc3EncoderConfig, &lc3_encoder_config)); + + // lc3_setup_encoder failed due to wrong parameters (returned nullptr). + test::mock::embdrv_lc3::lc3_setup_encoder.body = + [](int dt_us, int sr_hz, int sr_pcm_hz, void* mem) { return nullptr; }; + + int ret = encoder_->init(lc3_encoder_config); + EXPECT_EQ(ret, -EINVAL); + EXPECT_EQ(get_func_call_count("lc3_setup_encoder"), 1); + + test::mock::embdrv_lc3::lc3_setup_encoder = {}; +} + +TEST_F(HfpLc3EncoderTest, InitSuccess) { + mmc::ConfigParam lc3_encoder_config; + ASSERT_TRUE( + TextFormat::ParseFromString(kLc3EncoderConfig, &lc3_encoder_config)); + + // lc3_setup_encoder returns encoder instance pointer. + struct lc3_encoder lc3_encoder; + test::mock::embdrv_lc3::lc3_setup_encoder.body = + [&lc3_encoder](int dt_us, int sr_hz, int sr_pcm_hz, void* mem) { + return &lc3_encoder; + }; + + int ret = encoder_->init(lc3_encoder_config); + EXPECT_EQ(ret, mmc::HFP_LC3_PCM_BYTES); + EXPECT_EQ(get_func_call_count("lc3_setup_encoder"), 1); + + test::mock::embdrv_lc3::lc3_setup_encoder = {}; +} + +TEST_F(HfpLc3EncoderWithInitTest, CleanUp) { + encoder_->cleanup(); + EXPECT_EQ(get_func_call_count("osi_free_and_reset"), 1); +} + +TEST_F(HfpLc3EncoderTest, TranscodeNullBuffer) { + // Null input buffer. + int ret = encoder_->transcode(nullptr, 0, kOutputBuf, kOutputLen); + EXPECT_EQ(ret, -EINVAL); + EXPECT_EQ(get_func_call_count("lc3_encode"), 0); + + // Null output buffer. + ret = encoder_->transcode((uint8_t*)kInputBuf, kInputLen, nullptr, 0); + EXPECT_EQ(ret, -EINVAL); + EXPECT_EQ(get_func_call_count("lc3_encode"), 0); +} + +TEST_F(HfpLc3EncoderWithInitTest, TranscodeWrongParam) { + // lc3_encode failed (returned non-zero value). + test::mock::embdrv_lc3::lc3_encode.return_value = 1; + + int ret = encoder_->transcode((uint8_t*)kInputBuf, kInputLen, kOutputBuf, + kOutputLen); + EXPECT_EQ(ret, mmc::HFP_LC3_PKT_FRAME_LEN); + EXPECT_THAT(kOutputBuf, Each(0)); + EXPECT_EQ(get_func_call_count("lc3_encode"), 1); + + test::mock::embdrv_lc3::lc3_encode = {}; +} + +TEST_F(HfpLc3EncoderWithInitTest, TranscodeSuccess) { + // lc3_encode succeeded (return zero value). + test::mock::embdrv_lc3::lc3_encode.return_value = 0; + + int ret = encoder_->transcode((uint8_t*)kInputBuf, kInputLen, kOutputBuf, + kOutputLen); + EXPECT_EQ(ret, mmc::HFP_LC3_PKT_FRAME_LEN); + EXPECT_THAT(kOutputBuf, Contains(Ne(0))); + EXPECT_EQ(get_func_call_count("lc3_encode"), 1); + + test::mock::embdrv_lc3::lc3_encode = {}; +} + +} // namespace diff --git a/system/stack/mmc/test/mock/mock_embdrv_lc3.cc b/system/stack/mmc/test/mock/mock_embdrv_lc3.cc new file mode 100644 index 0000000000000000000000000000000000000000..ff7d5c60841eb22545578d33d7237dfca0e5bb7b --- /dev/null +++ b/system/stack/mmc/test/mock/mock_embdrv_lc3.cc @@ -0,0 +1,125 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Generated mock file from original source file + * Functions generated:10 + * + * mockcify.pl ver 0.6.1 + */ + +#include +#include +#include +#include + +// Mock include file to share data between tests and mock +#include "mmc/test/mock/mock_embdrv_lc3.h" + +// Original usings + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace embdrv_lc3 { + +// Function state capture and return values, if needed +struct lc3_decode lc3_decode; +struct lc3_decoder_size lc3_decoder_size; +struct lc3_delay_samples lc3_delay_samples; +struct lc3_encode lc3_encode; +struct lc3_encoder_size lc3_encoder_size; +struct lc3_frame_bytes lc3_frame_bytes; +struct lc3_frame_samples lc3_frame_samples; +struct lc3_resolve_bitrate lc3_resolve_bitrate; +struct lc3_setup_decoder lc3_setup_decoder; +struct lc3_setup_encoder lc3_setup_encoder; + +} // namespace embdrv_lc3 +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace embdrv_lc3 { + +int lc3_decode::return_value = 0; +unsigned lc3_decoder_size::return_value = 0; +int lc3_delay_samples::return_value = 0; +int lc3_encode::return_value = 0; +unsigned lc3_encoder_size::return_value = 0; +int lc3_frame_bytes::return_value = 0; +int lc3_frame_samples::return_value = 0; +int lc3_resolve_bitrate::return_value = 0; +struct lc3_decoder* lc3_setup_decoder::return_value = nullptr; +struct lc3_encoder* lc3_setup_encoder::return_value = nullptr; + +} // namespace embdrv_lc3 +} // namespace mock +} // namespace test + +// Mocked functions, if any +int lc3_decode(struct lc3_decoder* decoder, const void* in, int nbytes, + enum lc3_pcm_format fmt, void* pcm, int stride) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_decode(decoder, in, nbytes, fmt, pcm, + stride); +} +unsigned lc3_decoder_size(int dt_us, int sr_hz) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_decoder_size(dt_us, sr_hz); +} +int lc3_delay_samples(int dt_us, int sr_hz) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_delay_samples(dt_us, sr_hz); +} +int lc3_encode(struct lc3_encoder* encoder, enum lc3_pcm_format fmt, + const void* pcm, int stride, int nbytes, void* out) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_encode(encoder, fmt, pcm, stride, nbytes, + out); +} +unsigned lc3_encoder_size(int dt_us, int sr_hz) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_encoder_size(dt_us, sr_hz); +} +int lc3_frame_bytes(int dt_us, int bitrate) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_frame_bytes(dt_us, bitrate); +} +int lc3_frame_samples(int dt_us, int sr_hz) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_frame_samples(dt_us, sr_hz); +} +int lc3_resolve_bitrate(int dt_us, int nbytes) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_resolve_bitrate(dt_us, nbytes); +} +struct lc3_decoder* lc3_setup_decoder(int dt_us, int sr_hz, int sr_pcm_hz, + void* mem) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_setup_decoder(dt_us, sr_hz, sr_pcm_hz, + mem); +} +struct lc3_encoder* lc3_setup_encoder(int dt_us, int sr_hz, int sr_pcm_hz, + void* mem) { + inc_func_call_count(__func__); + return test::mock::embdrv_lc3::lc3_setup_encoder(dt_us, sr_hz, sr_pcm_hz, + mem); +} +// Mocked functions complete +// END mockcify generation diff --git a/system/stack/mmc/test/mock/mock_embdrv_lc3.h b/system/stack/mmc/test/mock/mock_embdrv_lc3.h new file mode 100644 index 0000000000000000000000000000000000000000..8e7bfcfe80f2cdb13b0092294fb88ee09705f022 --- /dev/null +++ b/system/stack/mmc/test/mock/mock_embdrv_lc3.h @@ -0,0 +1,176 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:10 + * + * mockcify.pl ver 0.6.1 + */ + +#include + +#include +#include +#include +#include + +#include "test/common/mock_functions.h" + +namespace test { +namespace mock { +namespace embdrv_lc3 { +// Shared state between mocked functions and tests +// Name: lc3_decode +// Params: struct lc3_decoder* decoder, const void* in, int nbytes, enum +// lc3_pcm_format fmt, void* pcm, int stride Return: int +struct lc3_decode { + static int return_value; + std::function + body{[](struct lc3_decoder* decoder, const void* in, int nbytes, + enum lc3_pcm_format fmt, void* pcm, + int stride) { return return_value; }}; + int operator()(struct lc3_decoder* decoder, const void* in, int nbytes, + enum lc3_pcm_format fmt, void* pcm, int stride) { + return body(decoder, in, nbytes, fmt, pcm, stride); + }; +}; +extern struct lc3_decode lc3_decode; + +// Name: lc3_decoder_size +// Params: int dt_us, int sr_hz +// Return: unsigned +struct lc3_decoder_size { + static unsigned return_value; + std::function body{ + [](int dt_us, int sr_hz) { return return_value; }}; + unsigned operator()(int dt_us, int sr_hz) { return body(dt_us, sr_hz); }; +}; +extern struct lc3_decoder_size lc3_decoder_size; + +// Name: lc3_delay_samples +// Params: int dt_us, int sr_hz +// Return: int +struct lc3_delay_samples { + static int return_value; + std::function body{ + [](int dt_us, int sr_hz) { return return_value; }}; + int operator()(int dt_us, int sr_hz) { return body(dt_us, sr_hz); }; +}; +extern struct lc3_delay_samples lc3_delay_samples; + +// Name: lc3_encode +// Params: struct lc3_encoder* encoder, enum lc3_pcm_format fmt, const void* +// pcm, int stride, int nbytes, void* out Return: int +struct lc3_encode { + static int return_value; + std::function + body{[](struct lc3_encoder* encoder, enum lc3_pcm_format fmt, + const void* pcm, int stride, int nbytes, + void* out) { return return_value; }}; + int operator()(struct lc3_encoder* encoder, enum lc3_pcm_format fmt, + const void* pcm, int stride, int nbytes, void* out) { + return body(encoder, fmt, pcm, stride, nbytes, out); + }; +}; +extern struct lc3_encode lc3_encode; + +// Name: lc3_encoder_size +// Params: int dt_us, int sr_hz +// Return: unsigned +struct lc3_encoder_size { + static unsigned return_value; + std::function body{ + [](int dt_us, int sr_hz) { return return_value; }}; + unsigned operator()(int dt_us, int sr_hz) { return body(dt_us, sr_hz); }; +}; +extern struct lc3_encoder_size lc3_encoder_size; + +// Name: lc3_frame_bytes +// Params: int dt_us, int bitrate +// Return: int +struct lc3_frame_bytes { + static int return_value; + std::function body{ + [](int dt_us, int bitrate) { return return_value; }}; + int operator()(int dt_us, int bitrate) { return body(dt_us, bitrate); }; +}; +extern struct lc3_frame_bytes lc3_frame_bytes; + +// Name: lc3_frame_samples +// Params: int dt_us, int sr_hz +// Return: int +struct lc3_frame_samples { + static int return_value; + std::function body{ + [](int dt_us, int sr_hz) { return return_value; }}; + int operator()(int dt_us, int sr_hz) { return body(dt_us, sr_hz); }; +}; +extern struct lc3_frame_samples lc3_frame_samples; + +// Name: lc3_resolve_bitrate +// Params: int dt_us, int nbytes +// Return: int +struct lc3_resolve_bitrate { + static int return_value; + std::function body{ + [](int dt_us, int nbytes) { return return_value; }}; + int operator()(int dt_us, int nbytes) { return body(dt_us, nbytes); }; +}; +extern struct lc3_resolve_bitrate lc3_resolve_bitrate; + +// Name: lc3_setup_decoder +// Params: int dt_us, int sr_hz, int sr_pcm_hz, void* mem +// Return: struct lc3_decoder* +struct lc3_setup_decoder { + static struct lc3_decoder* return_value; + std::function + body{[](int dt_us, int sr_hz, int sr_pcm_hz, void* mem) { + return return_value; + }}; + struct lc3_decoder* operator()(int dt_us, int sr_hz, int sr_pcm_hz, + void* mem) { + return body(dt_us, sr_hz, sr_pcm_hz, mem); + }; +}; +extern struct lc3_setup_decoder lc3_setup_decoder; + +// Name: lc3_setup_encoder +// Params: int dt_us, int sr_hz, int sr_pcm_hz, void* mem +// Return: struct lc3_encoder* +struct lc3_setup_encoder { + static struct lc3_encoder* return_value; + std::function + body{[](int dt_us, int sr_hz, int sr_pcm_hz, void* mem) { + return return_value; + }}; + struct lc3_encoder* operator()(int dt_us, int sr_hz, int sr_pcm_hz, + void* mem) { + return body(dt_us, sr_hz, sr_pcm_hz, mem); + }; +}; +extern struct lc3_setup_encoder lc3_setup_encoder; + +} // namespace embdrv_lc3 +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/build/secondary/third_party/tinyxml2/BUILD.gn b/system/stack/mmc/tmpfiles.d/mmc.conf similarity index 74% rename from system/build/secondary/third_party/tinyxml2/BUILD.gn rename to system/stack/mmc/tmpfiles.d/mmc.conf index aeb66a1ffc18bcf6323de63d665afa184b659f52..eb542a704b5c066e3093e3ae41e5aa0081e3406c 100644 --- a/system/build/secondary/third_party/tinyxml2/BUILD.gn +++ b/system/stack/mmc/tmpfiles.d/mmc.conf @@ -1,5 +1,5 @@ # -# Copyright 2015 Google, Inc. +# Copyright 2023 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,10 +14,7 @@ # limitations under the License. # -static_library("tinyxml2") { - sources = [ - "tinyxml2.cpp" - ] +# Setup the directory paths expected by MMC. - include_dirs = [ "." ] -} +# For common directories for mmc domain sockets. +d= /run/mmc/sockets 0770 mmc_service mmc_service diff --git a/system/stack/pan/pan_api.cc b/system/stack/pan/pan_api.cc index 378263cce38b0ea766c75924998cc97908f416f5..779ea7b3e7c7f37eb8e3c0b46129e1b83c5434c1 100644 --- a/system/stack/pan/pan_api.cc +++ b/system/stack/pan/pan_api.cc @@ -23,6 +23,8 @@ * *****************************************************************************/ +#define LOG_TAG "pan" + #include "stack/include/pan_api.h" #include @@ -32,17 +34,21 @@ #include #include "bta/sys/bta_sys.h" +#include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bnep_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_log_history.h" #include "stack/include/sdp_api.h" -#include "stack/include/sdpdefs.h" #include "stack/pan/pan_int.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + using bluetooth::Uuid; namespace { @@ -147,18 +153,18 @@ tPAN_RESULT PAN_SetRole(uint8_t role, std::string p_user_name, /* If the role is not a valid combination reject it */ if ((!(role & (PAN_ROLE_CLIENT | PAN_ROLE_NAP_SERVER))) && role != PAN_ROLE_INACTIVE) { - PAN_TRACE_ERROR("PAN role %d is invalid", role); + LOG_ERROR("PAN role %d is invalid", role); return PAN_FAILURE; } /* If the current active role is same as the role being set do nothing */ if (pan_cb.role == role) { - PAN_TRACE_EVENT("PAN role already was set to: %d", role); + LOG_VERBOSE("PAN role already was set to: %d", role); return PAN_SUCCESS; } /* Register all the roles with SDP */ - PAN_TRACE_API("PAN_SetRole() called with role 0x%x", role); + LOG_VERBOSE("PAN_SetRole() called with role 0x%x", role); if (role & PAN_ROLE_NAP_SERVER) { /* Check the service name */ if (p_nap_name.empty()) @@ -168,7 +174,8 @@ tPAN_RESULT PAN_SetRole(uint8_t role, std::string p_user_name, p_desc = PAN_NAP_DEFAULT_DESCRIPTION; if (pan_cb.pan_nap_sdp_handle != 0) - SDP_DeleteRecord(pan_cb.pan_nap_sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + pan_cb.pan_nap_sdp_handle); pan_cb.pan_nap_sdp_handle = pan_register_with_sdp(UUID_SERVCLASS_NAP, p_nap_name.c_str(), p_desc); @@ -179,7 +186,8 @@ tPAN_RESULT PAN_SetRole(uint8_t role, std::string p_user_name, */ else if (pan_cb.role & PAN_ROLE_NAP_SERVER) { if (pan_cb.pan_nap_sdp_handle != 0) { - SDP_DeleteRecord(pan_cb.pan_nap_sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + pan_cb.pan_nap_sdp_handle); pan_cb.pan_nap_sdp_handle = 0; bta_sys_remove_uuid(UUID_SERVCLASS_NAP); nap_service_name.clear(); @@ -193,7 +201,8 @@ tPAN_RESULT PAN_SetRole(uint8_t role, std::string p_user_name, /* Registering for PANU service with SDP */ p_desc = PAN_PANU_DEFAULT_DESCRIPTION; if (pan_cb.pan_user_sdp_handle != 0) - SDP_DeleteRecord(pan_cb.pan_user_sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + pan_cb.pan_user_sdp_handle); pan_cb.pan_user_sdp_handle = pan_register_with_sdp(UUID_SERVCLASS_PANU, p_user_name.c_str(), p_desc); @@ -204,7 +213,8 @@ tPAN_RESULT PAN_SetRole(uint8_t role, std::string p_user_name, */ else if (pan_cb.role & PAN_ROLE_CLIENT) { if (pan_cb.pan_user_sdp_handle != 0) { - SDP_DeleteRecord(pan_cb.pan_user_sdp_handle); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( + pan_cb.pan_user_sdp_handle); pan_cb.pan_user_sdp_handle = 0; bta_sys_remove_uuid(UUID_SERVCLASS_PANU); user_service_name.clear(); @@ -212,7 +222,7 @@ tPAN_RESULT PAN_SetRole(uint8_t role, std::string p_user_name, } pan_cb.role = role; - PAN_TRACE_EVENT("PAN role set to: %d", role); + LOG_VERBOSE("PAN role set to: %d", role); BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Role change", base::StringPrintf("role:0x%x", role)); @@ -254,15 +264,15 @@ tPAN_RESULT PAN_Connect(const RawAddress& rem_bda, tPAN_ROLE src_role, /* Check if PAN is active or not */ if (!(pan_cb.role & src_role)) { - PAN_TRACE_ERROR("PAN is not active for the role %d", src_role); + LOG_ERROR("PAN is not active for the role %d", src_role); return PAN_FAILURE; } /* Validate the parameters before proceeding */ if ((src_role != PAN_ROLE_CLIENT && src_role != PAN_ROLE_NAP_SERVER) || (dst_role != PAN_ROLE_CLIENT && dst_role != PAN_ROLE_NAP_SERVER)) { - PAN_TRACE_ERROR("Either source %d or destination role %d is invalid", - src_role, dst_role); + LOG_ERROR("Either source %d or destination role %d is invalid", src_role, + dst_role); return PAN_FAILURE; } @@ -278,7 +288,7 @@ tPAN_RESULT PAN_Connect(const RawAddress& rem_bda, tPAN_ROLE src_role, ** because if there is already a connection we cannot accept ** another connection in PANU role */ - PAN_TRACE_ERROR( + LOG_ERROR( "Cannot make PANU connections when there are more than one " "connection"); return PAN_INVALID_SRC_ROLE; @@ -295,7 +305,7 @@ tPAN_RESULT PAN_Connect(const RawAddress& rem_bda, tPAN_ROLE src_role, /* If destination is PANU role validate source role */ else if (dst_role == PAN_ROLE_CLIENT) { if (pan_cb.num_conns && pan_cb.active_role == PAN_ROLE_CLIENT && !pcb) { - PAN_TRACE_ERROR("Device already have a connection in PANU role"); + LOG_ERROR("Device already have a connection in PANU role"); return PAN_INVALID_SRC_ROLE; } @@ -305,16 +315,15 @@ tPAN_RESULT PAN_Connect(const RawAddress& rem_bda, tPAN_ROLE src_role, } /* The role combination is not valid */ else { - PAN_TRACE_ERROR( - "Source %d and Destination roles %d are not valid combination", - src_role, dst_role); + LOG_ERROR("Source %d and Destination roles %d are not valid combination", + src_role, dst_role); return PAN_FAILURE; } /* Allocate control block and initiate connection */ if (!pcb) pcb = pan_allocate_pcb(rem_bda, BNEP_INVALID_HANDLE); if (!pcb) { - PAN_TRACE_ERROR("PAN Connection failed because of no resources"); + LOG_ERROR("PAN Connection failed because of no resources"); return PAN_NO_RESOURCES; } @@ -342,7 +351,7 @@ tPAN_RESULT PAN_Connect(const RawAddress& rem_bda, tPAN_ROLE src_role, return (tPAN_RESULT)ret; } - PAN_TRACE_DEBUG("PAN_Connect() current active role set to %d", src_role); + LOG_VERBOSE("PAN_Connect() current active role set to %d", src_role); pan_cb.prv_active_role = pan_cb.active_role; pan_cb.active_role = src_role; *handle = pcb->handle; @@ -370,7 +379,7 @@ tPAN_RESULT PAN_Disconnect(uint16_t handle) { /* Check if the connection exists */ pcb = pan_get_pcb_by_handle(handle); if (!pcb) { - PAN_TRACE_ERROR("PAN connection not found for the handle %d", handle); + LOG_ERROR("PAN connection not found for the handle %d", handle); return PAN_FAILURE; } @@ -385,11 +394,11 @@ tPAN_RESULT PAN_Disconnect(uint16_t handle) { pan_release_pcb(pcb); if (result != BNEP_SUCCESS) { - PAN_TRACE_EVENT("Error in closing PAN connection"); + LOG_VERBOSE("Error in closing PAN connection"); return PAN_FAILURE; } - PAN_TRACE_EVENT("PAN connection closed"); + LOG_VERBOSE("PAN connection closed"); return PAN_SUCCESS; } @@ -420,7 +429,7 @@ tPAN_RESULT PAN_Write(uint16_t handle, const RawAddress& dst, const RawAddress& src, uint16_t protocol, uint8_t* p_data, uint16_t len, bool ext) { if (pan_cb.role == PAN_ROLE_INACTIVE || !pan_cb.num_conns) { - PAN_TRACE_ERROR("%s PAN is not active, data write failed.", __func__); + LOG_ERROR("%s PAN is not active, data write failed.", __func__); return PAN_FAILURE; } @@ -477,7 +486,7 @@ tPAN_RESULT PAN_WriteBuf(uint16_t handle, const RawAddress& dst, tBNEP_RESULT result; if (pan_cb.role == PAN_ROLE_INACTIVE || (!(pan_cb.num_conns))) { - PAN_TRACE_ERROR("PAN is not active Data write failed"); + LOG_ERROR("PAN is not active Data write failed"); osi_free(p_buf); return PAN_FAILURE; } @@ -504,7 +513,7 @@ tPAN_RESULT PAN_WriteBuf(uint16_t handle, const RawAddress& dst, } if (i == MAX_PAN_CONNS) { - PAN_TRACE_ERROR("PAN Don't have any user connections"); + LOG_ERROR("PAN Don't have any user connections"); osi_free(p_buf); return PAN_FAILURE; } @@ -512,30 +521,30 @@ tPAN_RESULT PAN_WriteBuf(uint16_t handle, const RawAddress& dst, result = BNEP_WriteBuf(pan_cb.pcb[i].handle, dst, p_buf, protocol, &src, ext); if (result == BNEP_IGNORE_CMD) { - PAN_TRACE_DEBUG("PAN ignored data write for PANU connection"); + LOG_VERBOSE("PAN ignored data write for PANU connection"); return (tPAN_RESULT)result; } else if (result != BNEP_SUCCESS) { - PAN_TRACE_ERROR("PAN failed to write data for the PANU connection"); + LOG_ERROR("PAN failed to write data for the PANU connection"); return (tPAN_RESULT)result; } pan_cb.pcb[i].write.octets += p_buf->len; pan_cb.pcb[i].write.packets++; - PAN_TRACE_DEBUG("PAN successfully wrote data for the PANU connection"); + LOG_VERBOSE("PAN successfully wrote data for the PANU connection"); return PAN_SUCCESS; } /* findout to which connection the data is meant for */ pcb = pan_get_pcb_by_handle(handle); if (!pcb) { - PAN_TRACE_ERROR("PAN Buf write for wrong handle"); + LOG_ERROR("PAN Buf write for wrong handle"); osi_free(p_buf); return PAN_FAILURE; } if (pcb->con_state != PAN_STATE_CONNECTED) { - PAN_TRACE_ERROR("PAN Buf write when conn is not active"); + LOG_ERROR("PAN Buf write when conn is not active"); pcb->write.drops++; osi_free(p_buf); return PAN_FAILURE; @@ -544,11 +553,11 @@ tPAN_RESULT PAN_WriteBuf(uint16_t handle, const RawAddress& dst, uint16_t len = p_buf->len; result = BNEP_WriteBuf(pcb->handle, dst, p_buf, protocol, &src, ext); if (result == BNEP_IGNORE_CMD) { - PAN_TRACE_DEBUG("PAN ignored data buf write to PANU"); + LOG_VERBOSE("PAN ignored data buf write to PANU"); pcb->write.errors++; return PAN_IGNORE_CMD; } else if (result != BNEP_SUCCESS) { - PAN_TRACE_ERROR("PAN failed to send data buf to the PANU"); + LOG_ERROR("PAN failed to send data buf to the PANU"); pcb->write.errors++; return (tPAN_RESULT)result; } @@ -556,7 +565,7 @@ tPAN_RESULT PAN_WriteBuf(uint16_t handle, const RawAddress& dst, pcb->write.octets += len; pcb->write.packets++; - PAN_TRACE_DEBUG("PAN successfully sent data buf to the PANU"); + LOG_VERBOSE("PAN successfully sent data buf to the PANU"); return PAN_SUCCESS; } @@ -585,18 +594,18 @@ tPAN_RESULT PAN_SetProtocolFilters(uint16_t handle, uint16_t num_filters, /* Check if the connection exists */ pcb = pan_get_pcb_by_handle(handle); if (!pcb) { - PAN_TRACE_ERROR("PAN connection not found for the handle %d", handle); + LOG_ERROR("PAN connection not found for the handle %d", handle); return PAN_FAILURE; } tBNEP_RESULT result = BNEP_SetProtocolFilters(pcb->handle, num_filters, p_start_array, p_end_array); if (result != BNEP_SUCCESS) { - PAN_TRACE_ERROR("PAN failed to set protocol filters for handle %d", handle); + LOG_ERROR("PAN failed to set protocol filters for handle %d", handle); return (tPAN_RESULT)result; } - PAN_TRACE_API("PAN successfully sent protocol filters for handle %d", handle); + LOG_VERBOSE("PAN successfully sent protocol filters for handle %d", handle); return PAN_SUCCESS; } @@ -624,42 +633,21 @@ tPAN_RESULT PAN_SetMulticastFilters(uint16_t handle, uint16_t num_mcast_filters, /* Check if the connection exists */ pcb = pan_get_pcb_by_handle(handle); if (!pcb) { - PAN_TRACE_ERROR("PAN connection not found for the handle %d", handle); + LOG_ERROR("PAN connection not found for the handle %d", handle); return PAN_FAILURE; } tBNEP_RESULT result = BNEP_SetMulticastFilters(pcb->handle, num_mcast_filters, p_start_array, p_end_array); if (result != BNEP_SUCCESS) { - PAN_TRACE_ERROR("PAN failed to set multicast filters for handle %d", - handle); + LOG_ERROR("PAN failed to set multicast filters for handle %d", handle); return (tPAN_RESULT)result; } - PAN_TRACE_API("PAN successfully sent multicast filters for handle %d", - handle); + LOG_VERBOSE("PAN successfully sent multicast filters for handle %d", handle); return PAN_SUCCESS; } -/******************************************************************************* - * - * Function PAN_SetTraceLevel - * - * Description This function sets the trace level for PAN. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t PAN_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) - pan_cb.trace_level = new_level; - else - pan_dump_status(); - - return (pan_cb.trace_level); -} - /******************************************************************************* * * Function PAN_Init @@ -673,12 +661,6 @@ uint8_t PAN_SetTraceLevel(uint8_t new_level) { ******************************************************************************/ void PAN_Init(void) { memset(&pan_cb, 0, sizeof(tPAN_CB)); - -#if defined(PAN_INITIAL_TRACE_LEVEL) - pan_cb.trace_level = PAN_INITIAL_TRACE_LEVEL; -#else - pan_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ -#endif } #define DUMPSYS_TAG "shim::legacy::pan" diff --git a/system/stack/pan/pan_int.h b/system/stack/pan/pan_int.h index 010de4ada1495055a53728d2761e8df27020efd8..bf0060d1bdde35c7481dabe11de2206bf401ee22 100644 --- a/system/stack/pan/pan_int.h +++ b/system/stack/pan/pan_int.h @@ -27,6 +27,7 @@ #include +#include "internal_include/bt_target.h" #include "stack/include/bt_hdr.h" #include "stack/include/pan_api.h" #include "types/bluetooth/uuid.h" @@ -99,7 +100,6 @@ typedef struct { uint32_t pan_gn_sdp_handle; uint32_t pan_nap_sdp_handle; uint8_t num_conns; - uint8_t trace_level; } tPAN_CB; /* Global PAN data diff --git a/system/stack/pan/pan_main.cc b/system/stack/pan/pan_main.cc index 789e88e943a65b770420fba03e7e1bc3c0cb4628..293c1e7d18239855ff1812a84789be64a4097c22 100644 --- a/system/stack/pan/pan_main.cc +++ b/system/stack/pan/pan_main.cc @@ -23,19 +23,19 @@ * ******************************************************************************/ +#define LOG_TAG "pan" + #include #include // memset #include -#include "main/shim/dumpsys.h" #include "osi/include/allocator.h" #include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bnep_api.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_log_history.h" -#include "stack/include/sdpdefs.h" +#include "stack/include/bt_uuid16.h" #include "stack/pan/pan_int.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -101,13 +101,13 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, */ if (!remote_uuid.Is16Bit()) { - PAN_TRACE_ERROR("PAN Connection failed because of wrong remote UUID "); + LOG_ERROR("PAN Connection failed because of wrong remote UUID "); BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID); return; } if (!local_uuid.Is16Bit()) { - PAN_TRACE_ERROR("PAN Connection failed because of wrong local UUID "); + LOG_ERROR("PAN Connection failed because of wrong local UUID "); BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID); return; } @@ -115,7 +115,7 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, uint16_t remote_uuid16 = remote_uuid.As16Bit(); uint16_t local_uuid16 = local_uuid.As16Bit(); - PAN_TRACE_EVENT( + LOG_VERBOSE( "%s - handle %d, current role %d, dst uuid 0x%x, src uuid 0x%x, role " "change %s", __func__, handle, pan_cb.role, local_uuid16, remote_uuid16, @@ -125,7 +125,7 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, if (remote_uuid16 != UUID_SERVCLASS_PANU && remote_uuid16 != UUID_SERVCLASS_NAP && remote_uuid16 != UUID_SERVCLASS_GN) { - PAN_TRACE_ERROR("Src UUID 0x%x is not valid", remote_uuid16); + LOG_ERROR("Src UUID 0x%x is not valid", remote_uuid16); BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID); return; } @@ -133,7 +133,7 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, /* Check if the destination UUID is a valid one */ if (local_uuid16 != UUID_SERVCLASS_PANU && local_uuid16 != UUID_SERVCLASS_NAP && local_uuid16 != UUID_SERVCLASS_GN) { - PAN_TRACE_ERROR("Dst UUID 0x%x is not valid", local_uuid16); + LOG_ERROR("Dst UUID 0x%x is not valid", local_uuid16); BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID); return; } @@ -145,7 +145,7 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, local_uuid16 == UUID_SERVCLASS_GN) || ((!(pan_cb.role & UUID_SERVCLASS_NAP)) && local_uuid16 == UUID_SERVCLASS_NAP)) { - PAN_TRACE_ERROR( + LOG_ERROR( "PAN Connection failed because of unsupported destination UUID 0x%x", local_uuid16); BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID); @@ -176,7 +176,7 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, is_valid_interaction = false; } if (!is_valid_interaction) { - PAN_TRACE_ERROR( + LOG_ERROR( "PAN Connection failed because of invalid PAN profile roles " "interaction: Remote UUID 0x%x Local UUID 0x%x", remote_uuid16, local_uuid16); @@ -200,7 +200,7 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, /* There are connections other than this one ** so we cann't accept PANU role. Reject */ - PAN_TRACE_ERROR( + LOG_ERROR( "Dst UUID should be either GN or NAP only because there are other " "connections"); BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID); @@ -209,8 +209,8 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, /* If it is already in connected state check for bridging status */ if (pcb->con_state == PAN_STATE_CONNECTED) { - PAN_TRACE_EVENT("PAN Role changing New Src 0x%x Dst 0x%x", remote_uuid16, - local_uuid16); + LOG_VERBOSE("PAN Role changing New Src 0x%x Dst 0x%x", remote_uuid16, + local_uuid16); pcb->prv_src_uuid = pcb->src_uuid; pcb->prv_dst_uuid = pcb->dst_uuid; @@ -235,22 +235,22 @@ void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda, */ if (pan_cb.num_conns && (local_uuid16 == UUID_SERVCLASS_PANU || pan_cb.active_role == PAN_ROLE_CLIENT)) { - PAN_TRACE_ERROR("PAN already have a connection and can't be user"); + LOG_ERROR("PAN already have a connection and can't be user"); BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID); return; } } /* This is a new connection */ - PAN_TRACE_DEBUG("New connection indication for handle %d", handle); + LOG_VERBOSE("New connection indication for handle %d", handle); pcb = pan_allocate_pcb(p_bda, handle); if (!pcb) { - PAN_TRACE_ERROR("PAN no control block for new connection"); + LOG_ERROR("PAN no control block for new connection"); BNEP_ConnectResp(handle, BNEP_CONN_FAILED); return; } - PAN_TRACE_EVENT("PAN connection destination UUID is 0x%x", local_uuid16); + LOG_VERBOSE("PAN connection destination UUID is 0x%x", local_uuid16); /* Set the latest active PAN role */ pan_cb.active_role = req_role; pcb->src_uuid = local_uuid16; @@ -287,11 +287,11 @@ void pan_connect_state_cb(uint16_t handle, tPAN_CONN* pcb; uint8_t peer_role; - PAN_TRACE_EVENT("pan_connect_state_cb - for handle %d, result %d", handle, - result); + LOG_VERBOSE("pan_connect_state_cb - for handle %d, result %d", handle, + result); pcb = pan_get_pcb_by_handle(handle); if (!pcb) { - PAN_TRACE_ERROR("PAN State change indication for wrong handle %d", handle); + LOG_ERROR("PAN State change indication for wrong handle %d", handle); return; } @@ -307,7 +307,7 @@ void pan_connect_state_cb(uint16_t handle, if (pcb->con_state != PAN_STATE_CONNECTED && (pcb->con_flags & PAN_FLAGS_CONN_COMPLETED)) { /* restore the original values */ - PAN_TRACE_EVENT("restoring the connection state to active"); + LOG_VERBOSE("restoring the connection state to active"); pcb->con_state = PAN_STATE_CONNECTED; pcb->con_flags &= (~PAN_FLAGS_CONN_COMPLETED); @@ -352,7 +352,7 @@ void pan_connect_state_cb(uint16_t handle, /* Create bridge if the destination role is NAP */ if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP) { - PAN_TRACE_EVENT("PAN requesting for bridge"); + LOG_VERBOSE("PAN requesting for bridge"); (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, true); } } @@ -389,14 +389,14 @@ void pan_data_buf_ind_cb(uint16_t handle, const RawAddress& src, /* Check if the connection is in right state */ pcb = pan_get_pcb_by_handle(handle); if (!pcb) { - PAN_TRACE_ERROR("PAN Data buffer indication for wrong handle %d", handle); + LOG_ERROR("PAN Data buffer indication for wrong handle %d", handle); osi_free(p_buf); return; } if (pcb->con_state != PAN_STATE_CONNECTED) { - PAN_TRACE_ERROR("PAN Data indication in wrong state %d for handle %d", - pcb->con_state, handle); + LOG_ERROR("PAN Data indication in wrong state %d for handle %d", + pcb->con_state, handle); pcb->read.drops++; osi_free(p_buf); return; @@ -408,7 +408,7 @@ void pan_data_buf_ind_cb(uint16_t handle, const RawAddress& src, pcb->read.octets += len; pcb->read.packets++; - PAN_TRACE_EVENT( + LOG_VERBOSE( "pan_data_buf_ind_cb - for handle %d, protocol 0x%x, length %d, ext %d", handle, protocol, len, ext); @@ -420,9 +420,8 @@ void pan_data_buf_ind_cb(uint16_t handle, const RawAddress& src, /* Check if it is broadcast or multicast packet */ if (pcb->src_uuid != UUID_SERVCLASS_PANU) { if (dst.address[0] & 0x01) { - PAN_TRACE_DEBUG( - "PAN received broadcast packet on handle %d, src uuid 0x%x", handle, - pcb->src_uuid); + LOG_VERBOSE("PAN received broadcast packet on handle %d, src uuid 0x%x", + handle, pcb->src_uuid); for (i = 0; i < MAX_PAN_CONNS; i++) { if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED && pan_cb.pcb[i].handle != handle && @@ -446,15 +445,15 @@ void pan_data_buf_ind_cb(uint16_t handle, const RawAddress& src, /* Check if it is for any other PAN connection */ dst_pcb = pan_get_pcb_by_addr(dst); if (dst_pcb) { - PAN_TRACE_EVENT( + LOG_VERBOSE( "%s - destination PANU found on handle %d and sending data, len: %d", __func__, dst_pcb->handle, len); result = BNEP_Write(dst_pcb->handle, dst, p_data, len, protocol, &src, ext); if (result != BNEP_SUCCESS && result != BNEP_IGNORE_CMD) - PAN_TRACE_ERROR("Failed to write data for PAN connection handle %d", - dst_pcb->handle); + LOG_ERROR("Failed to write data for PAN connection handle %d", + dst_pcb->handle); pcb->read.errors++; osi_free(p_buf); return; @@ -516,7 +515,7 @@ void pan_tx_data_flow_cb(uint16_t handle, tBNEP_RESULT result) { void pan_proto_filt_ind_cb(uint16_t handle, bool indication, tBNEP_RESULT result, uint16_t num_filters, uint8_t* p_filters) { - PAN_TRACE_EVENT( + LOG_VERBOSE( "pan_proto_filt_ind_cb - called for handle %d with ind %d, result %d, " "num %d", handle, indication, result, num_filters); @@ -550,7 +549,7 @@ void pan_proto_filt_ind_cb(uint16_t handle, bool indication, void pan_mcast_filt_ind_cb(uint16_t handle, bool indication, tBNEP_RESULT result, uint16_t num_filters, uint8_t* p_filters) { - PAN_TRACE_EVENT( + LOG_VERBOSE( "pan_mcast_filt_ind_cb - called for handle %d with ind %d, result %d, " "num %d", handle, indication, result, num_filters); diff --git a/system/stack/pan/pan_utils.cc b/system/stack/pan/pan_utils.cc index 7252ddfd7b4937bfa1c7f8282e6a8b789306d666..e33f1e38d9914fe7fb6786d898cd4cef73d9ef29 100644 --- a/system/stack/pan/pan_utils.cc +++ b/system/stack/pan/pan_utils.cc @@ -23,16 +23,23 @@ * *****************************************************************************/ +#define LOG_TAG "pan" + #include #include +#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" +#include "stack/include/sdpdefs.h" #include "stack/pan/pan_int.h" -#include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + static const uint8_t pan_proto_elem_data[] = { 0x35, 0x18, /* data element sequence of length 0x18 bytes */ 0x35, 0x06, /* data element sequence for L2CAP descriptor */ @@ -66,43 +73,49 @@ uint32_t pan_register_with_sdp(uint16_t uuid, const char* p_name, uint32_t proto_len = (uint32_t)pan_proto_elem_data[1]; /* Create a record */ - sdp_handle = SDP_CreateRecord(); + sdp_handle = get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); if (sdp_handle == 0) { - PAN_TRACE_ERROR("PAN_SetRole - could not create SDP record"); + LOG_ERROR("PAN_SetRole - could not create SDP record"); return 0; } /* Service Class ID List */ - SDP_AddServiceClassIdList(sdp_handle, 1, &uuid); + get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList(sdp_handle, 1, + &uuid); /* Add protocol element sequence from the constant string */ - SDP_AddAttribute(sdp_handle, ATTR_ID_PROTOCOL_DESC_LIST, - DATA_ELE_SEQ_DESC_TYPE, proto_len, - (uint8_t*)(pan_proto_elem_data + 2)); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_PROTOCOL_DESC_LIST, DATA_ELE_SEQ_DESC_TYPE, proto_len, + (uint8_t*)(pan_proto_elem_data + 2)); /* Language base */ - SDP_AddLanguageBaseAttrIDList(sdp_handle, LANG_ID_CODE_ENGLISH, - LANG_ID_CHAR_ENCODE_UTF8, LANGUAGE_BASE_ID); + get_legacy_stack_sdp_api()->handle.SDP_AddLanguageBaseAttrIDList( + sdp_handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8, + LANGUAGE_BASE_ID); /* Profile descriptor list */ - SDP_AddProfileDescriptorList(sdp_handle, uuid, PAN_PROFILE_VERSION); + get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList( + sdp_handle, uuid, PAN_PROFILE_VERSION); /* Service Name */ - SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, - (uint8_t)(strlen(p_name) + 1), (uint8_t*)p_name); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, + (uint8_t)(strlen(p_name) + 1), (uint8_t*)p_name); /* Service description */ - SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE, - (uint8_t)(strlen(p_desc) + 1), (uint8_t*)p_desc); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE, + (uint8_t)(strlen(p_desc) + 1), (uint8_t*)p_desc); /* Security description */ // Only NAP and PANU has service level security; GN has no security if (uuid == UUID_SERVCLASS_NAP || uuid == UUID_SERVCLASS_PANU) { UINT16_TO_BE_FIELD(&security, 0x0001); } - SDP_AddAttribute(sdp_handle, ATTR_ID_SECURITY_DESCRIPTION, UINT_DESC_TYPE, 2, - (uint8_t*)&security); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_SECURITY_DESCRIPTION, UINT_DESC_TYPE, 2, + (uint8_t*)&security); if (uuid == UUID_SERVCLASS_NAP) { uint16_t NetAccessType = 0x0005; /* Ethernet */ @@ -112,18 +125,19 @@ uint32_t pan_register_with_sdp(uint16_t uuid, const char* p_name, /* Net access type. */ p = array; UINT16_TO_BE_STREAM(p, NetAccessType); - SDP_AddAttribute(sdp_handle, ATTR_ID_NET_ACCESS_TYPE, UINT_DESC_TYPE, 2, - array); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_NET_ACCESS_TYPE, UINT_DESC_TYPE, 2, array); /* Net access rate. */ p = array; UINT32_TO_BE_STREAM(p, NetAccessRate); - SDP_AddAttribute(sdp_handle, ATTR_ID_MAX_NET_ACCESS_RATE, UINT_DESC_TYPE, 4, - array); + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( + sdp_handle, ATTR_ID_MAX_NET_ACCESS_RATE, UINT_DESC_TYPE, 4, array); } /* Make the service browsable */ - SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_list); + get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence( + sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_list); return sdp_handle; } @@ -265,8 +279,8 @@ void pan_dump_status(void) { uint16_t i; tPAN_CONN* p_pcb; - PAN_TRACE_DEBUG("PAN role %x, active role %d, num_conns %d", pan_cb.role, - pan_cb.active_role, pan_cb.num_conns); + LOG_VERBOSE("PAN role %x, active role %d, num_conns %d", pan_cb.role, + pan_cb.active_role, pan_cb.num_conns); for (i = 0, p_pcb = pan_cb.pcb; i < MAX_PAN_CONNS; i++, p_pcb++) { VLOG(1) << +i << " state:" << p_pcb->con_state diff --git a/system/stack/rfcomm/port_api.cc b/system/stack/rfcomm/port_api.cc index fa0119438e5eacf352bf02821098520c3fc5d16f..a481c18602b072b8435c9c0a3462ec102b7accef 100644 --- a/system/stack/rfcomm/port_api.cc +++ b/system/stack/rfcomm/port_api.cc @@ -30,12 +30,13 @@ #include +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/mutex.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" -#include "stack/include/sdpdefs.h" +#include "stack/include/bt_uuid16.h" #include "stack/rfcomm/rfc_int.h" #include "types/raw_address.h" @@ -109,7 +110,7 @@ int RFCOMM_CreateConnectionWithSecurity(uint16_t uuid, uint8_t scn, uint16_t sec_mask) { *p_handle = 0; - if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) { + if ((scn == 0) || (scn > RFCOMM_MAX_SCN)) { // Server Channel Number (SCN) should be in range [1, 30] LOG(ERROR) << __func__ << ": Invalid SCN, bd_addr=" << bd_addr << ", scn=" << static_cast(scn) @@ -286,17 +287,17 @@ int RFCOMM_ControlReqFromBTSOCK(uint8_t dlci, const RawAddress& bd_addr, int RFCOMM_RemoveConnection(uint16_t handle) { tPORT* p_port; - RFCOMM_TRACE_API("RFCOMM_RemoveConnection() handle:%d", handle); + LOG_VERBOSE("RFCOMM_RemoveConnection() handle:%d", handle); /* Check if handle is valid to avoid crashing */ if ((handle == 0) || (handle > MAX_RFC_PORTS)) { - RFCOMM_TRACE_ERROR("RFCOMM_RemoveConnection() BAD handle:%d", handle); + LOG_ERROR("RFCOMM_RemoveConnection() BAD handle:%d", handle); return (PORT_BAD_HANDLE); } p_port = &rfc_cb.port.port[handle - 1]; if (!p_port->in_use || (p_port->state == PORT_CONNECTION_STATE_CLOSED)) { - RFCOMM_TRACE_EVENT("RFCOMM_RemoveConnection() Not opened:%d", handle); + LOG_VERBOSE("RFCOMM_RemoveConnection() Not opened:%d", handle); return (PORT_SUCCESS); } @@ -371,7 +372,7 @@ int PORT_SetEventCallback(uint16_t port_handle, tPORT_CALLBACK* p_port_cb) { return (PORT_NOT_OPENED); } - RFCOMM_TRACE_API("PORT_SetEventCallback() handle:%d", port_handle); + LOG_VERBOSE("PORT_SetEventCallback() handle:%d", port_handle); p_port->p_callback = p_port_cb; @@ -417,8 +418,8 @@ int PORT_SetDataCOCallback(uint16_t port_handle, tPORT_DATA_CO_CALLBACK* p_port_cb) { tPORT* p_port; - RFCOMM_TRACE_API("PORT_SetDataCOCallback() handle:%d cb 0x%x", port_handle, - p_port_cb); + LOG_VERBOSE("PORT_SetDataCOCallback() handle:%d cb 0x%p", port_handle, + p_port_cb); /* Check if handle is valid to avoid crashing */ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) { @@ -449,8 +450,7 @@ int PORT_SetDataCOCallback(uint16_t port_handle, int PORT_SetEventMask(uint16_t port_handle, uint32_t mask) { tPORT* p_port; - RFCOMM_TRACE_API("PORT_SetEventMask() handle:%d mask:0x%x", port_handle, - mask); + LOG_VERBOSE("PORT_SetEventMask() handle:%d mask:0x%x", port_handle, mask); /* Check if handle is valid to avoid crashing */ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) { @@ -487,7 +487,7 @@ int PORT_CheckConnection(uint16_t handle, RawAddress* bd_addr, return (PORT_BAD_HANDLE); } tPORT* p_port = &rfc_cb.port.port[handle - 1]; - RFCOMM_TRACE_DEBUG( + LOG_VERBOSE( "%s: handle=%d, in_use=%d, port_state=%d, p_mcb=%p, peer_ready=%d, " "rfc_state=%d", __func__, handle, p_port->in_use, p_port->state, p_port->rfc.p_mcb, @@ -577,7 +577,7 @@ int PORT_SetState(uint16_t handle, tPORT_STATE* p_settings) { tPORT* p_port; uint8_t baud_rate; - RFCOMM_TRACE_API("PORT_SetState() handle:%d", handle); + LOG_VERBOSE("PORT_SetState() handle:%d", handle); /* Check if handle is valid to avoid crashing */ if ((handle == 0) || (handle > MAX_RFC_PORTS)) { @@ -594,8 +594,8 @@ int PORT_SetState(uint16_t handle, tPORT_STATE* p_settings) { return (PORT_LINE_ERR); } - RFCOMM_TRACE_API("PORT_SetState() handle:%d FC_TYPE:0x%x", handle, - p_settings->fc_type); + LOG_VERBOSE("PORT_SetState() handle:%d FC_TYPE:0x%x", handle, + p_settings->fc_type); baud_rate = p_port->user_port_pars.baud_rate; p_port->user_port_pars = *p_settings; @@ -622,7 +622,7 @@ int PORT_SetState(uint16_t handle, tPORT_STATE* p_settings) { int PORT_GetState(uint16_t handle, tPORT_STATE* p_settings) { tPORT* p_port; - RFCOMM_TRACE_API("PORT_GetState() handle:%d", handle); + LOG_VERBOSE("PORT_GetState() handle:%d", handle); /* Check if handle is valid to avoid crashing */ if ((handle == 0) || (handle > MAX_RFC_PORTS)) { @@ -662,7 +662,7 @@ int PORT_FlowControl_MaxCredit(uint16_t handle, bool enable) { bool old_fc; uint32_t events; - RFCOMM_TRACE_API("PORT_FlowControl() handle:%d enable: %d", handle, enable); + LOG_VERBOSE("PORT_FlowControl() handle:%d enable: %d", handle, enable); /* Check if handle is valid to avoid crashing */ if ((handle == 0) || (handle > MAX_RFC_PORTS)) { @@ -730,7 +730,7 @@ int PORT_ReadData(uint16_t handle, char* p_data, uint16_t max_len, BT_HDR* p_buf; uint16_t count; - RFCOMM_TRACE_API("PORT_ReadData() handle:%d max_len:%d", handle, max_len); + LOG_VERBOSE("PORT_ReadData() handle:%d max_len:%d", handle, max_len); /* Initialize this in case of an error */ *p_len = 0; @@ -802,11 +802,11 @@ int PORT_ReadData(uint16_t handle, char* p_data, uint16_t max_len, } if (*p_len == 1) { - RFCOMM_TRACE_EVENT("PORT_ReadData queue:%d returned:%d %x", - p_port->rx.queue_size, *p_len, (p_data[0])); + LOG_VERBOSE("PORT_ReadData queue:%d returned:%d %x", p_port->rx.queue_size, + *p_len, (p_data[0])); } else { - RFCOMM_TRACE_EVENT("PORT_ReadData queue:%d returned:%d", - p_port->rx.queue_size, *p_len); + LOG_VERBOSE("PORT_ReadData queue:%d returned:%d", p_port->rx.queue_size, + *p_len); } /* If rfcomm suspended traffic from the peer based on the rx_queue_size */ @@ -845,7 +845,7 @@ static int port_write(tPORT* p_port, BT_HDR* p_buf) { (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED))) { if ((p_port->tx.queue_size > PORT_TX_CRITICAL_WM) || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_CRITICAL_WM)) { - RFCOMM_TRACE_WARNING("PORT_Write: Queue size: %d", p_port->tx.queue_size); + LOG_WARN("PORT_Write: Queue size: %d", p_port->tx.queue_size); osi_free(p_buf); @@ -855,7 +855,7 @@ static int port_write(tPORT* p_port, BT_HDR* p_buf) { return (PORT_TX_FULL); } - RFCOMM_TRACE_EVENT( + LOG_VERBOSE( "PORT_Write : Data is enqued. flow disabled %d peer_ready %d state %d " "ctrl_state %x", p_port->tx.peer_fc, @@ -867,7 +867,7 @@ static int port_write(tPORT* p_port, BT_HDR* p_buf) { return (PORT_CMD_PENDING); } else { - RFCOMM_TRACE_EVENT("PORT_Write : Data is being sent"); + LOG_VERBOSE("PORT_Write : Data is being sent"); RFCOMM_DataReq(p_port->rfc.p_mcb, p_port->dlci, p_buf); return (PORT_SUCCESS); @@ -893,7 +893,7 @@ int PORT_WriteDataCO(uint16_t handle, int* p_len) { int rc = 0; uint16_t length; - RFCOMM_TRACE_API("PORT_WriteDataCO() handle:%d", handle); + LOG_VERBOSE("PORT_WriteDataCO() handle:%d", handle); *p_len = 0; /* Check if handle is valid to avoid crashing */ @@ -903,13 +903,12 @@ int PORT_WriteDataCO(uint16_t handle, int* p_len) { p_port = &rfc_cb.port.port[handle - 1]; if (!p_port->in_use || (p_port->state == PORT_CONNECTION_STATE_CLOSED)) { - RFCOMM_TRACE_WARNING("PORT_WriteDataByFd() no port state:%d", - p_port->state); + LOG_WARN("PORT_WriteDataByFd() no port state:%d", p_port->state); return (PORT_NOT_OPENED); } if (!p_port->peer_mtu) { - RFCOMM_TRACE_ERROR("PORT_WriteDataByFd() peer_mtu:%d", p_port->peer_mtu); + LOG_ERROR("PORT_WriteDataByFd() peer_mtu:%d", p_port->peer_mtu); return (PORT_UNKNOWN_ERROR); } int available = 0; @@ -917,7 +916,7 @@ int PORT_WriteDataCO(uint16_t handle, int* p_len) { if (!p_port->p_data_co_callback(handle, (uint8_t*)&available, sizeof(available), DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE)) { - RFCOMM_TRACE_ERROR( + LOG_ERROR( "p_data_co_callback DATA_CO_CALLBACK_TYPE_INCOMING_SIZE failed, " "available:%d", available); @@ -975,8 +974,8 @@ int PORT_WriteDataCO(uint16_t handle, int* p_len) { (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM)) { port_flow_control_user(p_port); event |= PORT_EV_FC; - RFCOMM_TRACE_EVENT( - "tx queue is full,tx.queue_size:%d,tx.queue.count:%d,available:%d", + LOG_VERBOSE( + "tx queue is full,tx.queue_size:%d,tx.queue.count:%zu,available:%d", p_port->tx.queue_size, fixed_queue_length(p_port->tx.queue), available); break; @@ -1004,7 +1003,7 @@ int PORT_WriteDataCO(uint16_t handle, int* p_len) { return (PORT_UNKNOWN_ERROR); } - RFCOMM_TRACE_EVENT("PORT_WriteData %d bytes", length); + LOG_VERBOSE("PORT_WriteData %d bytes", length); rc = port_write(p_port, p_buf); @@ -1051,7 +1050,7 @@ int PORT_WriteData(uint16_t handle, const char* p_data, uint16_t max_len, int rc = 0; uint16_t length; - RFCOMM_TRACE_API("PORT_WriteData() max_len:%d", max_len); + LOG_VERBOSE("PORT_WriteData() max_len:%d", max_len); *p_len = 0; @@ -1062,7 +1061,7 @@ int PORT_WriteData(uint16_t handle, const char* p_data, uint16_t max_len, p_port = &rfc_cb.port.port[handle - 1]; if (!p_port->in_use || (p_port->state == PORT_CONNECTION_STATE_CLOSED)) { - RFCOMM_TRACE_WARNING("PORT_WriteData() no port state:%d", p_port->state); + LOG_WARN("PORT_WriteData() no port state:%d", p_port->state); return (PORT_NOT_OPENED); } @@ -1071,7 +1070,7 @@ int PORT_WriteData(uint16_t handle, const char* p_data, uint16_t max_len, } if (!max_len || !p_port->peer_mtu) { - RFCOMM_TRACE_ERROR("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu); + LOG_ERROR("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu); return (PORT_UNKNOWN_ERROR); } @@ -1118,7 +1117,7 @@ int PORT_WriteData(uint16_t handle, const char* p_data, uint16_t max_len, memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, length); - RFCOMM_TRACE_EVENT("PORT_WriteData %d bytes", length); + LOG_VERBOSE("PORT_WriteData %d bytes", length); rc = port_write(p_port, p_buf); @@ -1158,31 +1157,9 @@ void RFCOMM_Init(void) { rfc_cb.rfc.last_mux = MAX_BD_CONNECTIONS; -#if defined(RFCOMM_INITIAL_TRACE_LEVEL) - rfc_cb.trace_level = RFCOMM_INITIAL_TRACE_LEVEL; -#else - rfc_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ -#endif - rfcomm_l2cap_if_init(); } -/******************************************************************************* - * - * Function PORT_SetTraceLevel - * - * Description Set the trace level for RFCOMM. If called with 0xFF, it - * simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t PORT_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) rfc_cb.trace_level = new_level; - - return (rfc_cb.trace_level); -} - /******************************************************************************* * * Function PORT_GetResultString diff --git a/system/stack/rfcomm/port_int.h b/system/stack/rfcomm/port_int.h index b0e9fb1c7bc8c66cfd631fd3e950548988f8bfc6..9b554ddd9814b2a1a2277b6ec8b514313ccd13ea 100644 --- a/system/stack/rfcomm/port_int.h +++ b/system/stack/rfcomm/port_int.h @@ -27,13 +27,13 @@ #include +#include "internal_include/bt_target.h" #include "osi/include/alarm.h" #include "osi/include/fixed_queue.h" #include "stack/include/l2c_api.h" #include "stack/include/port_api.h" #include "stack/include/rfcdefs.h" #include "types/raw_address.h" - /* * Flow control configuration values for the mux */ diff --git a/system/stack/rfcomm/port_rfc.cc b/system/stack/rfcomm/port_rfc.cc index 927bb1c56d27932103058dd06a21c09f1d5655b8..793c7b325514d3964913d1dcfe0d589a71ec47e0 100644 --- a/system/stack/rfcomm/port_rfc.cc +++ b/system/stack/rfcomm/port_rfc.cc @@ -23,6 +23,8 @@ * ******************************************************************************/ +#define LOG_TAG "rfcomm" + #include #include #include @@ -30,15 +32,16 @@ #include #include -#include "bt_target.h" -#include "bt_trace.h" #include "gd/hal/snoop_logger.h" -#include "main/shim/shim.h" +#include "internal_include/bt_target.h" +#include "internal_include/bt_trace.h" +#include "main/shim/entry.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/mutex.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" -#include "stack/include/sdpdefs.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/stack_metrics_logging.h" #include "stack/l2cap/l2c_int.h" #include "stack/rfcomm/port_int.h" @@ -58,16 +61,16 @@ void port_get_credits(tPORT* p_port, uint8_t k); * Description This function is called after security manager completes * required security checks. * - * Returns void + * Returns PORT_SUCCESS or PORT_[ERROR] * ******************************************************************************/ int port_open_continue(tPORT* p_port) { - RFCOMM_TRACE_EVENT("port_open_continue, p_port:%p", p_port); + LOG_VERBOSE("port_open_continue, p_port:%p", p_port); /* Check if multiplexer channel has already been established */ tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true); if (p_mcb == nullptr) { - RFCOMM_TRACE_WARNING("port_open_continue no mx channel"); + LOG_WARN("port_open_continue no mx channel"); port_release_port(p_port); return (PORT_NO_RESOURCES); } @@ -90,9 +93,8 @@ int port_open_continue(tPORT* p_port) { } else { // MX state machine ignores RFC_MX_EVENT_START_REQ in these states // When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports - RFCOMM_TRACE_DEBUG( - "port_open_continue: mx state(%d) mx channel is openning", - p_mcb->state); + LOG_VERBOSE("port_open_continue: mx state(%d) mx channel is opening", + p_mcb->state); } return (PORT_SUCCESS); } @@ -104,8 +106,6 @@ int port_open_continue(tPORT* p_port) { * Description This function is called in the BTU_TASK context to * send control information * - * Returns void - * ******************************************************************************/ void port_start_control(tPORT* p_port) { tRFC_MCB* p_mcb = p_port->rfc.p_mcb; @@ -122,8 +122,6 @@ void port_start_control(tPORT* p_port) { * Description This function is called in the BTU_TASK context to * send configuration information * - * Returns void - * ******************************************************************************/ void port_start_par_neg(tPORT* p_port) { tRFC_MCB* p_mcb = p_port->rfc.p_mcb; @@ -141,8 +139,6 @@ void port_start_par_neg(tPORT* p_port) { * Description This function is called in the BTU_TASK context to * release DLC * - * Returns void - * ******************************************************************************/ void port_start_close(tPORT* p_port) { tRFC_MCB* p_mcb = p_port->rfc.p_mcb; @@ -197,7 +193,7 @@ void port_start_close(tPORT* p_port) { void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result) { bool no_ports_up = true; - RFCOMM_TRACE_EVENT("%s: result %d", __func__, result); + LOG_VERBOSE("%s: result %d", __func__, result); tPORT* p_port = &rfc_cb.port.port[0]; for (int i = 0; i < MAX_RFC_PORTS; i++, p_port++) { @@ -205,10 +201,10 @@ void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result) { no_ports_up = false; if (result == RFCOMM_SUCCESS) { - RFCOMM_TRACE_EVENT("%s: dlci %d", __func__, p_port->dlci); + LOG_VERBOSE("%s: dlci %d", __func__, p_port->dlci); RFCOMM_ParameterNegotiationRequest(p_mcb, p_port->dlci, p_port->mtu); } else { - RFCOMM_TRACE_WARNING("%s: failed result:%d", __func__, result); + LOG_WARN("%s: failed result:%d", __func__, result); /* Warning: result is also set to 4 when l2cap connection fails due to l2cap connect cnf (no_resources) */ @@ -257,13 +253,13 @@ void PORT_StartInd(tRFC_MCB* p_mcb) { tPORT* p_port; int i; - RFCOMM_TRACE_EVENT("PORT_StartInd"); + LOG_VERBOSE("PORT_StartInd"); p_port = &rfc_cb.port.port[0]; for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) { if ((p_port->rfc.p_mcb == NULL) || (p_port->rfc.p_mcb == p_mcb)) { - RFCOMM_TRACE_DEBUG( - "PORT_StartInd, RFCOMM_StartRsp RFCOMM_SUCCESS: p_mcb:%p", p_mcb); + LOG_VERBOSE("PORT_StartInd, RFCOMM_StartRsp RFCOMM_SUCCESS: p_mcb:%p", + p_mcb); RFCOMM_StartRsp(p_mcb, RFCOMM_SUCCESS); return; } @@ -283,8 +279,8 @@ void PORT_StartInd(tRFC_MCB* p_mcb) { ******************************************************************************/ void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uint8_t k) { - RFCOMM_TRACE_EVENT("%s: bd_addr=%s, dlci=%d, mtu=%d", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_mcb->bd_addr), dlci, mtu); + LOG_VERBOSE("%s: bd_addr=%s, dlci=%d, mtu=%d", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_mcb->bd_addr), dlci, mtu); tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (!p_port) { /* This can be a first request for this port */ @@ -300,8 +296,8 @@ void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, rfc_check_mcb_active(p_mcb); return; } - RFCOMM_TRACE_EVENT("%s: port_handles[dlci:%d]:%d->%d", __func__, dlci, - p_mcb->port_handles[dlci], p_port->handle); + LOG_VERBOSE("%s: port_handles[dlci:%d]:%d->%d", __func__, dlci, + p_mcb->port_handles[dlci], p_port->handle); p_mcb->port_handles[dlci] = p_port->handle; } @@ -372,8 +368,7 @@ void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, ******************************************************************************/ void PORT_ParNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uint8_t k) { - RFCOMM_TRACE_EVENT("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu, - cl, k); + LOG_VERBOSE("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu, cl, k); tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (!p_port) { LOG(WARNING) << __func__ << ": port is null for " << p_mcb->bd_addr; @@ -387,8 +382,7 @@ void PORT_ParNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, /* This is illegal-- negotiation fails. */ if ((PORT_FC_DEFAULT == PORT_FC_TS710) && (cl == RFCOMM_PN_CONV_LAYER_CBFC_R)) { - RFCOMM_TRACE_WARNING("%s, negotiation fails, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, negotiation fails, index=%d", __func__, p_port->handle); rfc_send_disc(p_mcb, p_port->dlci); rfc_port_closed(p_port); return; @@ -426,17 +420,17 @@ void PORT_ParNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, * first message in the establishment procedure port_handle * has a handle to the port control block otherwise the control * block should be found based on the muliplexer channel and - * dlci. The block should be allocated allocated before - * meaning that application already made open. + * dlci. The block should be allocated before meaning + * that application already made open. * ******************************************************************************/ void PORT_DlcEstablishInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); - RFCOMM_TRACE_DEBUG( - "PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", p_mcb, dlci, - mtu, p_port); - VLOG(1) << __func__ << " p_mcb addr:" << p_mcb->bd_addr; + LOG_VERBOSE("PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", + p_mcb, dlci, mtu, p_port); + VLOG(1) << __func__ + << " p_mcb addr:" << ADDRESS_TO_LOGGABLE_STR(p_mcb->bd_addr); if (!p_port) { /* This can be a first request for this port */ @@ -478,15 +472,15 @@ void PORT_DlcEstablishInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) { * Description This function is called from the RFCOMM layer when peer * acknowledges establish procedure (SABME/UA). Send reply * to the user and set state to OPENED if result was - * successfull. + * successful. * ******************************************************************************/ void PORT_DlcEstablishCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint16_t result) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); - RFCOMM_TRACE_EVENT("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, - result); + LOG_VERBOSE("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, + result); if (!p_port) return; @@ -541,7 +535,7 @@ void PORT_PortNegInd(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars, uint16_t param_mask) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); - RFCOMM_TRACE_EVENT("PORT_PortNegInd"); + LOG_VERBOSE("PORT_PortNegInd"); if (!p_port) { /* This can be a first request for this port */ @@ -570,10 +564,10 @@ void PORT_PortNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, UNUSED_ATTR tPORT_STATE* p_pars, uint16_t result) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); - RFCOMM_TRACE_EVENT("PORT_PortNegCnf"); + LOG_VERBOSE("PORT_PortNegCnf"); if (!p_port) { - RFCOMM_TRACE_WARNING("PORT_PortNegCnf no port"); + LOG_WARN("PORT_PortNegCnf no port"); return; } /* Port negotiation failed. Drop the connection */ @@ -591,7 +585,7 @@ void PORT_PortNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT)) { RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl); } else { - RFCOMM_TRACE_WARNING("PORT_PortNegCnf Control Already sent"); + LOG_WARN("PORT_PortNegCnf Control Already sent"); } } @@ -608,7 +602,7 @@ void PORT_ControlInd(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) { uint32_t event; uint8_t old_signals; - RFCOMM_TRACE_EVENT("PORT_ControlInd"); + LOG_VERBOSE("PORT_ControlInd"); if (!p_port) return; @@ -639,12 +633,11 @@ void PORT_ControlInd(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) { */ if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->handle); - RFCOMM_TRACE_EVENT( - "PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d", - ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0), - ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0), - ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0), - ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0)); + LOG_VERBOSE("PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d", + ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0), + ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0), + ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0), + ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0)); } /******************************************************************************* @@ -660,7 +653,7 @@ void PORT_ControlCnf(tRFC_MCB* p_mcb, uint8_t dlci, tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); uint32_t event = 0; - RFCOMM_TRACE_EVENT("PORT_ControlCnf"); + LOG_VERBOSE("PORT_ControlCnf"); if (!p_port) return; @@ -692,7 +685,7 @@ void PORT_LineStatusInd(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t line_status) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); uint32_t event = 0; - RFCOMM_TRACE_EVENT("PORT_LineStatusInd"); + LOG_VERBOSE("PORT_LineStatusInd"); if (!p_port) return; @@ -738,7 +731,7 @@ void PORT_CloseInd(tRFC_MCB* p_mcb) { tPORT* p_port; int i; - RFCOMM_TRACE_EVENT("PORT_CloseInd"); + LOG_VERBOSE("PORT_CloseInd"); p_port = &rfc_cb.port.port[0]; for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) { @@ -754,17 +747,17 @@ void PORT_CloseInd(tRFC_MCB* p_mcb) { /******************************************************************************* * - * Function Port_TimeOutCloseMux + * Function PORT_TimeOutCloseMux * * Description This function is called when RFCOMM timesout on a command * as a result multiplexer connection is closed. * ******************************************************************************/ -void Port_TimeOutCloseMux(tRFC_MCB* p_mcb) { +void PORT_TimeOutCloseMux(tRFC_MCB* p_mcb) { tPORT* p_port; int i; - RFCOMM_TRACE_EVENT("Port_TimeOutCloseMux"); + LOG_VERBOSE("PORT_TimeOutCloseMux"); p_port = &rfc_cb.port.port[0]; for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) { @@ -792,9 +785,8 @@ void PORT_DataInd(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) { uint8_t* p; int i; - RFCOMM_TRACE_EVENT( - "PORT_DataInd with data length %d, p_mcb:%p,p_port:%p,dlci:%d", - p_buf->len, p_mcb, p_port, dlci); + LOG_VERBOSE("PORT_DataInd with data length %d, p_mcb:%p,p_port:%p,dlci:%d", + p_buf->len, p_mcb, p_port, dlci); if (!p_port) { osi_free(p_buf); return; @@ -824,7 +816,7 @@ void PORT_DataInd(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) { /* Check if rx queue exceeds the limit */ if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM) || (fixed_queue_length(p_port->rx.queue) + 1 > p_port->rx_buf_critical)) { - RFCOMM_TRACE_EVENT("PORT_DataInd. Buffer over run. Dropping the buffer"); + LOG_VERBOSE("PORT_DataInd. Buffer over run. Dropping the buffer"); osi_free(p_buf); RFCOMM_LineStatusReq(p_mcb, dlci, LINE_STATUS_OVERRUN); return; @@ -881,7 +873,7 @@ void PORT_FlowInd(tRFC_MCB* p_mcb, uint8_t dlci, bool enable_data) { uint32_t events = 0; int i; - RFCOMM_TRACE_EVENT("PORT_FlowInd fc:%d", enable_data); + LOG_VERBOSE("PORT_FlowInd fc:%d", enable_data); if (dlci == 0) { p_mcb->peer_ready = enable_data; @@ -945,8 +937,8 @@ uint32_t port_rfc_send_tx_data(tPORT* p_port) { mutex_global_unlock(); - RFCOMM_TRACE_DEBUG("Sending RFCOMM_DataReq tx.queue_size=%d", - p_port->tx.queue_size); + LOG_VERBOSE("Sending RFCOMM_DataReq tx.queue_size=%d", + p_port->tx.queue_size); RFCOMM_DataReq(p_port->rfc.p_mcb, p_port->dlci, p_buf); @@ -985,7 +977,7 @@ void port_rfc_closed(tPORT* p_port, uint8_t res) { if ((p_port->state == PORT_CONNECTION_STATE_OPENING) && (p_port->is_server)) { /* The server side was not informed that connection is up, ignore */ - RFCOMM_TRACE_WARNING("port_rfc_closed in OPENING state ignored"); + LOG_WARN("port_rfc_closed in OPENING state ignored"); rfc_port_timer_stop(p_port); p_port->rfc.state = RFC_STATE_CLOSED; diff --git a/system/stack/rfcomm/port_utils.cc b/system/stack/rfcomm/port_utils.cc index 827f1924876a7b4f1c9b72a17a7496d54586d42a..fb4097d9045e39a505309f76a2932e1d6e35f6be 100644 --- a/system/stack/rfcomm/port_utils.cc +++ b/system/stack/rfcomm/port_utils.cc @@ -22,12 +22,15 @@ * ******************************************************************************/ +#define LOG_TAG "rfcomm_port_utils" + #include #include #include -#include "bt_target.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/mutex.h" #include "stack/include/bt_hdr.h" @@ -81,7 +84,7 @@ tPORT* port_allocate_port(uint8_t dlci, const RawAddress& bd_addr) { p_port->dlci = dlci; p_port->bd_addr = bd_addr; rfc_cb.rfc.last_port_index = port_index; - RFCOMM_TRACE_DEBUG( + LOG_VERBOSE( "%s: rfc_cb.port.port[%d]:%p chosen, " "last_port_index:%d, bd_addr=%s", __func__, port_index, p_port, rfc_cb.rfc.last_port_index, @@ -167,16 +170,16 @@ void port_select_mtu(tPORT* p_port) { p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD; - RFCOMM_TRACE_DEBUG("%s: selected %d based on connection speed", - __func__, p_port->mtu); + LOG_VERBOSE("%s: selected %d based on connection speed", __func__, + p_port->mtu); } else { p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD; - RFCOMM_TRACE_DEBUG("%s: selected %d based on l2cap PDU size", __func__, - p_port->mtu); + LOG_VERBOSE("%s: selected %d based on l2cap PDU size", __func__, + p_port->mtu); } } } else { - RFCOMM_TRACE_DEBUG("%s: application selected %d", __func__, p_port->mtu); + LOG_VERBOSE("%s: application selected %d", __func__, p_port->mtu); } p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu); if (p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM) @@ -187,9 +190,9 @@ void port_select_mtu(tPORT* p_port) { p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu); if (p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM) p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM; - RFCOMM_TRACE_DEBUG( - "%s: credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d", __func__, - p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical); + LOG_VERBOSE("%s: credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d", + __func__, p_port->credit_rx_max, p_port->credit_rx_low, + p_port->rx_buf_critical); } /******************************************************************************* @@ -202,8 +205,8 @@ void port_select_mtu(tPORT* p_port) { * ******************************************************************************/ void port_release_port(tPORT* p_port) { - RFCOMM_TRACE_DEBUG("%s p_port: %p state: %d keep_handle: %d", __func__, - p_port, p_port->rfc.state, p_port->keep_port_handle); + LOG_VERBOSE("%s p_port: %p state: %d keep_handle: %d", __func__, p_port, + p_port->rfc.state, p_port->keep_port_handle); mutex_global_lock(); BT_HDR* p_buf; @@ -242,8 +245,7 @@ void port_release_port(tPORT* p_port) { mutex_global_unlock(); if (p_port->keep_port_handle) { - RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, - p_port->handle); + LOG_VERBOSE("%s Re-initialize handle: %d", __func__, p_port->handle); /* save event mask and callback */ uint32_t mask = p_port->ev_mask; @@ -265,7 +267,7 @@ void port_release_port(tPORT* p_port) { p_port->local_ctrl.modem_signal = p_port->default_signal_state; p_port->bd_addr = RawAddress::kAny; } else { - RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->handle); + LOG_VERBOSE("%s Clean-up handle: %d", __func__, p_port->handle); alarm_free(p_port->rfc.port_timer); memset(p_port, 0, sizeof(tPORT)); } @@ -284,12 +286,14 @@ tRFC_MCB* port_find_mcb(const RawAddress& bd_addr) { for (tRFC_MCB& mcb : rfc_cb.port.rfc_mcb) { if ((mcb.state != RFC_MX_STATE_IDLE) && (mcb.bd_addr == bd_addr)) { /* Multiplexer channel found do not change anything */ - VLOG(1) << __func__ << ": found bd_addr=" << bd_addr + VLOG(1) << __func__ + << ": found bd_addr=" << ADDRESS_TO_LOGGABLE_STR(bd_addr) << ", rfc_mcb=" << &mcb << ", lcid=" << loghex(mcb.lcid); return &mcb; } } - VLOG(1) << __func__ << ": not found, bd_addr:" << bd_addr; + VLOG(1) << __func__ + << ": not found, bd_addr:" << ADDRESS_TO_LOGGABLE_STR(bd_addr); return nullptr; } @@ -517,7 +521,7 @@ void port_flow_control_peer(tPORT* p_port, bool enable, uint16_t count) { else if (((p_port->rx.queue_size > PORT_RX_HIGH_WM) || (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM)) && !p_port->rx.peer_fc) { - RFCOMM_TRACE_EVENT("PORT_DataInd Data reached HW. Sending FC set."); + LOG_VERBOSE("PORT_DataInd Data reached HW. Sending FC set."); p_port->rx.peer_fc = true; RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false); diff --git a/system/stack/rfcomm/rfc_event.h b/system/stack/rfcomm/rfc_event.h index c950a4fcf2e9731fb6e91e4ef32f596edec7877c..47f4f4638ff231282095d809427bedcb99d2fbf8 100644 --- a/system/stack/rfcomm/rfc_event.h +++ b/system/stack/rfcomm/rfc_event.h @@ -18,6 +18,8 @@ #include +#include "macros.h" + /* * Events that can be received by multiplexer as well as port state machines */ @@ -79,10 +81,6 @@ enum tRFC_PORT_EVENT : uint16_t { RFC_PORT_EVENT_SEC_COMPLETE = 15, }; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - // Common events for both port and mux inline std::string rfcomm_event_text(const tRFC_EVENT& event) { switch (event) { @@ -138,5 +136,3 @@ inline std::string rfcomm_port_event_text(const tRFC_PORT_EVENT& event) { return std::string("UNKNOWN[") + std::to_string(event) + std::string("]"); } } - -#undef CASE_RETURN_TEXT diff --git a/system/stack/rfcomm/rfc_int.h b/system/stack/rfcomm/rfc_int.h index 8f348b4279174470e3736fcbd5db8a9ae32f1ba6..52fa23948dcb7efe290c4e06c455e5eb013a56a5 100644 --- a/system/stack/rfcomm/rfc_int.h +++ b/system/stack/rfcomm/rfc_int.h @@ -168,7 +168,6 @@ typedef struct { typedef struct { tRFCOMM_CB rfc; tPORT_CB port; - uint8_t trace_level; } tRFC_CB; extern tRFC_CB rfc_cb; @@ -275,7 +274,7 @@ void PORT_StartInd(tRFC_MCB* p_mcb); void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result); void PORT_CloseInd(tRFC_MCB* p_mcb); -void Port_TimeOutCloseMux(tRFC_MCB* p_mcb); +void PORT_TimeOutCloseMux(tRFC_MCB* p_mcb); void PORT_DlcEstablishInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu); void PORT_DlcEstablishCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, diff --git a/system/stack/rfcomm/rfc_l2cap_if.cc b/system/stack/rfcomm/rfc_l2cap_if.cc index d5a80d26a3b019eb702bbfb74b3e880f6ba5b8d2..9f9b0724484d622303cb85125cb777f46f7a3e49 100644 --- a/system/stack/rfcomm/rfc_l2cap_if.cc +++ b/system/stack/rfcomm/rfc_l2cap_if.cc @@ -27,13 +27,14 @@ #include #include -#include "bt_target.h" #include "common/time_util.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/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/l2c_api.h" #include "stack/rfcomm/port_int.h" #include "stack/rfcomm/rfc_int.h" @@ -100,7 +101,7 @@ void RFCOMM_ConnectInd(const RawAddress& bd_addr, uint16_t lcid, * continues as initiator */ /* if timeout, local device disconnects outgoing connection and continues * as acceptor */ - RFCOMM_TRACE_DEBUG( + LOG_VERBOSE( "RFCOMM_ConnectInd start timer for collision, initiator's " "LCID(0x%x), acceptor's LCID(0x%x)", p_mcb->lcid, p_mcb->pending_lcid); @@ -141,7 +142,7 @@ void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t result) { tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); if (!p_mcb) { - RFCOMM_TRACE_ERROR("RFCOMM_ConnectCnf LCID:0x%x", lcid); + LOG_ERROR("RFCOMM_ConnectCnf LCID:0x%x", lcid); return; } @@ -151,8 +152,8 @@ void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t result) { if (result != L2CAP_CONN_OK) { return; } else { - RFCOMM_TRACE_DEBUG("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", - p_mcb->pending_lcid); + LOG_VERBOSE("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", + p_mcb->pending_lcid); /* Peer gave up its connection request, make sure cleaning up L2CAP * channel */ @@ -186,7 +187,7 @@ void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); if (!p_mcb) { - RFCOMM_TRACE_ERROR("RFCOMM_ConfigInd LCID:0x%x", lcid); + LOG_ERROR("RFCOMM_ConfigInd LCID:0x%x", lcid); for (auto& [cid, mcb] : rfc_lcid_mcb) { if (mcb != nullptr && mcb->pending_lcid == lcid) { tL2CAP_CFG_INFO l2cap_cfg_info(*p_cfg); @@ -217,7 +218,7 @@ void RFCOMM_ConfigCnf(uint16_t lcid, UNUSED_ATTR uint16_t initiator, tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); if (!p_mcb) { - RFCOMM_TRACE_ERROR("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid); + LOG_ERROR("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid); return; } uintptr_t result_as_ptr = L2CAP_CFG_OK; @@ -274,8 +275,8 @@ void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) { } if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) { - RFCOMM_TRACE_DEBUG("%s: handle multiplexer event %d, p_mcb=%p", __func__, - event, p_mcb); + LOG_VERBOSE("%s: handle multiplexer event %d, p_mcb=%p", __func__, event, + p_mcb); /* Take special care of the Multiplexer Control Messages */ if (event == RFC_EVENT_UIH) { rfc_process_mx_message(p_mcb, p_buf); @@ -316,17 +317,17 @@ void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) { osi_free(p_buf); return; } - RFCOMM_TRACE_DEBUG("%s: port_handles[dlci=%d]:%d->%d, p_mcb=%p", __func__, - rfc_cb.rfc.rx_frame.dlci, - p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci], - p_port->handle); + LOG_VERBOSE("%s: port_handles[dlci=%d]:%d->%d, p_mcb=%p", __func__, + rfc_cb.rfc.rx_frame.dlci, + p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci], p_port->handle, + p_mcb); p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci] = p_port->handle; p_port->rfc.p_mcb = p_mcb; } if (event == RFC_EVENT_UIH) { - RFCOMM_TRACE_DEBUG("%s: Handling UIH event, buf_len=%u, credit=%u", - __func__, p_buf->len, rfc_cb.rfc.rx_frame.credit); + LOG_VERBOSE("%s: Handling UIH event, buf_len=%u, credit=%u", __func__, + p_buf->len, rfc_cb.rfc.rx_frame.credit); if (p_buf->len > 0) { rfc_port_sm_execute(p_port, static_cast(event), p_buf); } else { @@ -355,10 +356,10 @@ void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested) { tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); if (!p_mcb) { - RFCOMM_TRACE_ERROR("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid); + LOG_ERROR("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid); return; } else { - RFCOMM_TRACE_EVENT("RFCOMM_CongestionStatusInd LCID:0x%x", lcid); + LOG_VERBOSE("RFCOMM_CongestionStatusInd LCID:0x%x", lcid); } rfc_process_l2cap_congestion(p_mcb, is_congested); } diff --git a/system/stack/rfcomm/rfc_mx_fsm.cc b/system/stack/rfcomm/rfc_mx_fsm.cc index 4a54d4b7b4f8f06965e860b0a26addd9243d4d33..42916d4159410133966a58f3fe27ac39738ac305 100644 --- a/system/stack/rfcomm/rfc_mx_fsm.cc +++ b/system/stack/rfcomm/rfc_mx_fsm.cc @@ -23,20 +23,19 @@ * ******************************************************************************/ +#include + #include -#include "main/shim/dumpsys.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/l2c_api.h" #include "stack/rfcomm/port_int.h" #include "stack/rfcomm/rfc_int.h" -#include - #define L2CAP_SUCCESS 0 #define L2CAP_ERROR 1 @@ -171,11 +170,10 @@ void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) { return; default: - RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event); + LOG_ERROR("Mx error state %d event %d", p_mcb->state, event); return; } - RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event, - p_mcb->state); + LOG_VERBOSE("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); } /******************************************************************************* @@ -190,10 +188,10 @@ void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) { ******************************************************************************/ void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) { - RFCOMM_TRACE_EVENT("%s: evt %d", __func__, event); + LOG_VERBOSE("%s: evt %d", __func__, event); switch (event) { case RFC_MX_EVENT_START_REQ: - RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event); + LOG_ERROR("Mx error state %d event %d", p_mcb->state, event); return; /* There is some new timing so that Config Ind comes before security is @@ -227,7 +225,7 @@ void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, uint16_t i; uint8_t handle; - RFCOMM_TRACE_DEBUG( + LOG_VERBOSE( "RFCOMM MX retry as acceptor in collision case - evt:%d in " "state:%d", event, p_mcb->state); @@ -245,8 +243,8 @@ void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, p_mcb->port_handles[i] = 0; p_mcb->port_handles[i + 1] = handle; rfc_cb.port.port[handle - 1].dlci += 1; - RFCOMM_TRACE_DEBUG("RFCOMM MX - DLCI:%d -> %d", i, - rfc_cb.port.port[handle - 1].dlci); + LOG_VERBOSE("RFCOMM MX - DLCI:%d -> %d", i, + rfc_cb.port.port[handle - 1].dlci); } } @@ -259,8 +257,7 @@ void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_mcb->state); } - RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event, - p_mcb->state); + LOG_VERBOSE("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); } /******************************************************************************* @@ -275,12 +272,12 @@ void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, ******************************************************************************/ void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) { - RFCOMM_TRACE_EVENT("%s: event %d", __func__, event); + LOG_VERBOSE("%s: event %d", __func__, event); switch (event) { case RFC_MX_EVENT_START_REQ: case RFC_MX_EVENT_CONN_CNF: - RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event); + LOG_ERROR("Mx error state %d event %d", p_mcb->state, event); return; case RFC_MX_EVENT_CONF_IND: @@ -308,8 +305,7 @@ void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_mcb->state); } - RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event, - p_mcb->state); + LOG_VERBOSE("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); } /******************************************************************************* @@ -324,11 +320,11 @@ void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, ******************************************************************************/ void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, UNUSED_ATTR void* p_data) { - RFCOMM_TRACE_EVENT("%s: event %d", __func__, event); + LOG_VERBOSE("%s: event %d", __func__, event); switch (event) { case RFC_MX_EVENT_START_REQ: case RFC_MX_EVENT_CONN_CNF: - RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event); + LOG_ERROR("Mx error state %d event %d", p_mcb->state, event); return; /* workaround: we don't support reconfig */ @@ -372,8 +368,7 @@ void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_mcb->state); } - RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event, - p_mcb->state); + LOG_VERBOSE("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); } /******************************************************************************* @@ -388,7 +383,7 @@ void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, ******************************************************************************/ void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) { - RFCOMM_TRACE_EVENT("%s: event %d", __func__, event); + LOG_VERBOSE("%s: event %d", __func__, event); switch (event) { case RFC_MX_EVENT_DISC_IND: p_mcb->state = RFC_MX_STATE_IDLE; @@ -438,8 +433,7 @@ void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, default: LOG_WARN("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); } - RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event, - p_mcb->state); + LOG_VERBOSE("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); } /******************************************************************************* @@ -454,7 +448,7 @@ void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, ******************************************************************************/ void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, UNUSED_ATTR void* p_data) { - RFCOMM_TRACE_EVENT("%s: event %d", __func__, event); + LOG_VERBOSE("%s: event %d", __func__, event); switch (event) { case RFC_MX_EVENT_TIMEOUT: @@ -483,8 +477,7 @@ void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_mcb->state); } - RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event, - p_mcb->state); + LOG_VERBOSE("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); } /******************************************************************************* @@ -501,7 +494,7 @@ void rfc_mx_sm_state_disc_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) { BT_HDR* p_buf; - RFCOMM_TRACE_EVENT("%s: event %d", __func__, event); + LOG_VERBOSE("%s: event %d", __func__, event); switch (event) { case RFC_MX_EVENT_UA: case RFC_MX_EVENT_DM: @@ -563,8 +556,7 @@ void rfc_mx_sm_state_disc_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_mcb->state); } - RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event, - p_mcb->state); + LOG_VERBOSE("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); } void rfc_on_l2cap_error(uint16_t lcid, uint16_t result) { @@ -575,9 +567,8 @@ void rfc_on_l2cap_error(uint16_t lcid, uint16_t result) { /* if peer rejects our connect request but peer's connect request is pending */ if (p_mcb->pending_lcid) { - RFCOMM_TRACE_DEBUG( - "RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", - p_mcb->pending_lcid); + LOG_VERBOSE("RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", + p_mcb->pending_lcid); /* remove mcb from mapping table */ rfc_save_lcid_mcb(NULL, p_mcb->lcid); @@ -596,8 +587,8 @@ void rfc_on_l2cap_error(uint16_t lcid, uint16_t result) { p_mcb->port_handles[i] = 0; p_mcb->port_handles[i + 1] = handle; rfc_cb.port.port[handle - 1].dlci += 1; - RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", handle, - i, rfc_cb.port.port[handle - 1].dlci); + LOG_VERBOSE("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", handle, i, + rfc_cb.port.port[handle - 1].dlci); } } rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, nullptr); diff --git a/system/stack/rfcomm/rfc_port_fsm.cc b/system/stack/rfcomm/rfc_port_fsm.cc index 22baea89fcb82150ab4029364e157104777db943..55c1d00b3a360cde7488b3c6f30ab910e4d9f3f0 100644 --- a/system/stack/rfcomm/rfc_port_fsm.cc +++ b/system/stack/rfcomm/rfc_port_fsm.cc @@ -29,15 +29,14 @@ #include #include -#include "bt_target.h" #include "gd/hal/snoop_logger.h" -#include "main/shim/shim.h" +#include "main/shim/entry.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" -#include "stack/include/sdpdefs.h" +#include "stack/include/bt_uuid16.h" #include "stack/l2cap/l2c_int.h" #include "stack/rfcomm/port_int.h" #include "stack/rfcomm/rfc_int.h" @@ -81,7 +80,8 @@ static void rfc_set_port_state(tPORT_STATE* port_pars, MX_FRAME* p_frame); ******************************************************************************/ void rfc_port_sm_execute(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) { CHECK(p_port != nullptr) << __func__ << ": NULL port event " << event; - VLOG(1) << __func__ << ": BD_ADDR=" << p_port->bd_addr + VLOG(1) << __func__ + << ": BD_ADDR=" << ADDRESS_TO_LOGGABLE_STR(p_port->bd_addr) << ", PORT=" << std::to_string(p_port->handle) << ", STATE=" << std::to_string(p_port->rfc.state) << ", EVENT=" << event; @@ -159,8 +159,7 @@ void rfc_port_sm_state_closed(tPORT* p_port, tRFC_PORT_EVENT event, return; case RFC_PORT_EVENT_DM: - RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, RFC_EVENT_DM, index=%d", __func__, p_port->handle); rfc_port_closed(p_port); return; @@ -174,16 +173,15 @@ void rfc_port_sm_state_closed(tPORT* p_port, tRFC_PORT_EVENT event, return; case RFC_PORT_EVENT_TIMEOUT: - Port_TimeOutCloseMux(p_port->rfc.p_mcb); - RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state, - event); + PORT_TimeOutCloseMux(p_port->rfc.p_mcb); + LOG_ERROR("Port error state %d event %d", p_port->rfc.state, event); return; default: LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_port->rfc.state); } - RFCOMM_TRACE_WARNING("Port state closed Event ignored %d", event); + LOG_WARN("Port state closed Event ignored %d", event); return; } @@ -202,8 +200,7 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, switch (event) { case RFC_PORT_EVENT_OPEN: case RFC_PORT_EVENT_ESTABLISH_RSP: - RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state, - event); + LOG_ERROR("Port error state %d event %d", p_port->rfc.state, event); return; case RFC_PORT_EVENT_CLOSE: @@ -214,8 +211,7 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, return; case RFC_PORT_EVENT_CLEAR: - RFCOMM_TRACE_WARNING("%s, RFC_PORT_EVENT_CLEAR, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, RFC_PORT_EVENT_CLEAR, index=%d", __func__, p_port->handle); rfc_port_closed(p_port); return; @@ -256,8 +252,7 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, return; case RFC_PORT_EVENT_DM: - RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, RFC_EVENT_DM, index=%d", __func__, p_port->handle); p_port->rfc.p_mcb->is_disc_initiator = true; PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR); @@ -265,8 +260,7 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, return; case RFC_PORT_EVENT_DISC: - RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DISC, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, RFC_EVENT_DISC, index=%d", __func__, p_port->handle); rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci); PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR); @@ -291,7 +285,7 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_port->rfc.state); } - RFCOMM_TRACE_WARNING("Port state sabme_wait_ua Event ignored %d", event); + LOG_WARN("Port state sabme_wait_ua Event ignored %d", event); } /******************************************************************************* @@ -326,19 +320,17 @@ void rfc_port_sm_term_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, case RFC_PORT_EVENT_OPEN: case RFC_PORT_EVENT_CLOSE: - RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state, - event); + LOG_ERROR("Port error state %d event %d", p_port->rfc.state, event); return; case RFC_PORT_EVENT_CLEAR: - RFCOMM_TRACE_WARNING("%s, RFC_PORT_EVENT_CLEAR, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, RFC_PORT_EVENT_CLEAR, index=%d", __func__, p_port->handle); btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr); rfc_port_closed(p_port); return; case RFC_PORT_EVENT_DATA: - RFCOMM_TRACE_ERROR("Port error state Term Wait Sec event Data"); + LOG_ERROR("Port error state Term Wait Sec event Data"); osi_free(p_data); return; @@ -395,8 +387,7 @@ void rfc_port_sm_term_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_port->rfc.state); } - RFCOMM_TRACE_WARNING("Port state term_wait_sec_check Event ignored %d", - event); + LOG_WARN("Port state term_wait_sec_check Event ignored %d", event); } /******************************************************************************* @@ -415,9 +406,8 @@ void rfc_port_sm_orig_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, switch (event) { case RFC_PORT_EVENT_SEC_COMPLETE: if (*((uint8_t*)p_data) != BTM_SUCCESS) { - RFCOMM_TRACE_ERROR( - "%s, RFC_PORT_EVENT_SEC_COMPLETE, index=%d, result=%d", __func__, - event, p_port->handle, *((uint8_t*)p_data)); + LOG_ERROR("%s, RFC_PORT_EVENT_SEC_COMPLETE, index=%d, result=%d", + __func__, p_port->handle, *((uint8_t*)p_data)); p_port->rfc.p_mcb->is_disc_initiator = true; PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci, 0, RFCOMM_SECURITY_ERR); @@ -431,19 +421,17 @@ void rfc_port_sm_orig_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, case RFC_PORT_EVENT_OPEN: case RFC_PORT_EVENT_SABME: /* Peer should not use the same dlci */ - RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state, - event); + LOG_ERROR("Port error state %d event %d", p_port->rfc.state, event); return; case RFC_PORT_EVENT_CLOSE: - RFCOMM_TRACE_WARNING("%s, RFC_PORT_EVENT_CLOSE, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, RFC_PORT_EVENT_CLOSE, index=%d", __func__, p_port->handle); btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr); rfc_port_closed(p_port); return; case RFC_PORT_EVENT_DATA: - RFCOMM_TRACE_ERROR("Port error state Orig Wait Sec event Data"); + LOG_ERROR("Port error state Orig Wait Sec event Data"); osi_free(p_data); return; @@ -454,8 +442,7 @@ void rfc_port_sm_orig_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_port->rfc.state); } - RFCOMM_TRACE_WARNING("Port state orig_wait_sec_check Event ignored %d", - event); + LOG_WARN("Port state orig_wait_sec_check Event ignored %d", event); } /******************************************************************************* @@ -471,8 +458,7 @@ void rfc_port_sm_orig_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, void rfc_port_sm_opened(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) { switch (event) { case RFC_PORT_EVENT_OPEN: - RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state, - event); + LOG_ERROR("Port error state %d event %d", p_port->rfc.state, event); return; case RFC_PORT_EVENT_CLOSE: @@ -483,8 +469,7 @@ void rfc_port_sm_opened(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) { return; case RFC_PORT_EVENT_CLEAR: - RFCOMM_TRACE_WARNING("%s, RFC_PORT_EVENT_CLEAR, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, RFC_PORT_EVENT_CLEAR, index=%d", __func__, p_port->handle); rfc_port_closed(p_port); return; @@ -516,8 +501,7 @@ void rfc_port_sm_opened(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) { return; case RFC_PORT_EVENT_DM: - RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, - p_port->handle); + LOG_WARN("%s, RFC_EVENT_DM, index=%d", __func__, p_port->handle); PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci); rfc_port_closed(p_port); return; @@ -527,7 +511,7 @@ void rfc_port_sm_opened(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) { rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci); if (!fixed_queue_is_empty(p_port->rx.queue)) { /* give a chance to upper stack to close port properly */ - RFCOMM_TRACE_DEBUG("port queue is not empty"); + LOG_VERBOSE("port queue is not empty"); rfc_port_timer_start(p_port, RFC_DISC_TIMEOUT); } else PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci); @@ -538,15 +522,14 @@ void rfc_port_sm_opened(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) { return; case RFC_PORT_EVENT_TIMEOUT: - Port_TimeOutCloseMux(p_port->rfc.p_mcb); - RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state, - event); + PORT_TimeOutCloseMux(p_port->rfc.p_mcb); + LOG_ERROR("Port error state %d event %d", p_port->rfc.state, event); return; default: LOG_ERROR("Received unexpected event:%hu in state:%hhu", event, p_port->rfc.state); } - RFCOMM_TRACE_WARNING("Port state opened Event ignored %d", event); + LOG_WARN("Port state opened Event ignored %d", event); } /******************************************************************************* @@ -564,13 +547,11 @@ void rfc_port_sm_disc_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, switch (event) { case RFC_PORT_EVENT_OPEN: case RFC_PORT_EVENT_ESTABLISH_RSP: - RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state, - event); + LOG_ERROR("Port error state %d event %d", p_port->rfc.state, event); return; case RFC_PORT_EVENT_CLEAR: - RFCOMM_TRACE_WARNING("%s, RFC_PORT_EVENT_CLEAR, index=%d", __func__, - event, p_port->handle); + LOG_WARN("%s, RFC_PORT_EVENT_CLEAR, index=%d", __func__, p_port->handle); rfc_port_closed(p_port); return; @@ -583,8 +564,8 @@ void rfc_port_sm_disc_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, FALLTHROUGH_INTENDED; /* FALLTHROUGH */ case RFC_PORT_EVENT_DM: - RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM|RFC_EVENT_UA[%d], index=%d", - __func__, event, p_port->handle); + LOG_WARN("%s, RFC_EVENT_DM|RFC_EVENT_UA[%d], index=%d", __func__, event, + p_port->handle); rfc_port_closed(p_port); return; @@ -602,8 +583,7 @@ void rfc_port_sm_disc_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, return; case RFC_PORT_EVENT_TIMEOUT: - RFCOMM_TRACE_ERROR("%s, RFC_EVENT_TIMEOUT, index=%d", __func__, - p_port->handle); + LOG_ERROR("%s, RFC_EVENT_TIMEOUT, index=%d", __func__, p_port->handle); rfc_port_closed(p_port); return; default: @@ -611,7 +591,7 @@ void rfc_port_sm_disc_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, p_port->rfc.state); } - RFCOMM_TRACE_WARNING("Port state disc_wait_ua Event ignored %d", event); + LOG_WARN("Port state disc_wait_ua Event ignored %d", event); } /******************************************************************************* @@ -634,9 +614,9 @@ void rfc_port_uplink_data(tPORT* p_port, BT_HDR* p_buf) { * ******************************************************************************/ void rfc_process_pn(tRFC_MCB* p_mcb, bool is_command, MX_FRAME* p_frame) { - RFCOMM_TRACE_DEBUG("%s: is_initiator=%d, is_cmd=%d, state=%d, bd_addr=%s", - __func__, p_mcb->is_initiator, is_command, p_mcb->state, - ADDRESS_TO_LOGGABLE_CSTR(p_mcb->bd_addr)); + LOG_VERBOSE("%s: is_initiator=%d, is_cmd=%d, state=%d, bd_addr=%s", __func__, + p_mcb->is_initiator, is_command, p_mcb->state, + ADDRESS_TO_LOGGABLE_CSTR(p_mcb->bd_addr)); uint8_t dlci = p_frame->dlci; if (is_command) { diff --git a/system/stack/rfcomm/rfc_port_if.cc b/system/stack/rfcomm/rfc_port_if.cc index 5ef820ef60b9300f82a96b94bdb830dce019affc..f6eb46fb3a55cf08ebcc113ec6c3be19f72a4054 100644 --- a/system/stack/rfcomm/rfc_port_if.cc +++ b/system/stack/rfcomm/rfc_port_if.cc @@ -23,10 +23,13 @@ * *****************************************************************************/ +#define LOG_TAG "rfcomm" + #include #include -#include "bt_target.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" #include "stack/rfcomm/port_int.h" @@ -82,7 +85,7 @@ void RFCOMM_DlcEstablishReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (p_port == nullptr) { - RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci); + LOG_WARN("%s Unable to find DLCI port dlci:%d", __func__, dlci); return; } @@ -106,7 +109,7 @@ void RFCOMM_DlcEstablishRsp(tRFC_MCB* p_mcb, uint8_t dlci, tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (p_port == nullptr) { - RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci); + LOG_WARN("%s Unable to find DLCI port dlci:%d", __func__, dlci); return; } rfc_port_sm_execute(p_port, RFC_PORT_EVENT_ESTABLISH_RSP, &result); @@ -131,7 +134,7 @@ void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci, tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (p_port == nullptr) { - RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci); + LOG_WARN("%s Unable to find DLCI port dlci:%d", __func__, dlci); return; } @@ -200,7 +203,7 @@ void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci, tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (p_port == nullptr) { - RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci); + LOG_WARN("%s Unable to find DLCI port dlci:%d", __func__, dlci); return; } @@ -241,7 +244,7 @@ void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci, void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (p_port == nullptr) { - RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci); + LOG_WARN("%s Unable to find DLCI port dlci:%d", __func__, dlci); return; } @@ -269,7 +272,7 @@ void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) { void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool enable) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (p_port == nullptr) { - RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci); + LOG_WARN("%s Unable to find DLCI port dlci:%d", __func__, dlci); return; } @@ -296,7 +299,7 @@ void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool enable) { void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) { tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); if (p_port == nullptr) { - RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci); + LOG_WARN("%s Unable to find DLCI port dlci:%d", __func__, dlci); return; } diff --git a/system/stack/rfcomm/rfc_state.h b/system/stack/rfcomm/rfc_state.h index b725a3503a599dcf1e0007f495a274dd0dab952f..9d353e5882d924e6fdcc36f4291f87c130f14033 100644 --- a/system/stack/rfcomm/rfc_state.h +++ b/system/stack/rfcomm/rfc_state.h @@ -16,6 +16,10 @@ #pragma once +#include + +#include "macros.h" + /* * Define states and events for the RFC multiplexer state machine */ @@ -41,10 +45,6 @@ typedef enum : uint8_t { RFC_STATE_DISC_WAIT_UA = 5, } tRFC_PORT_STATE; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string rfcomm_mx_state_text(const tRFC_MX_STATE& state) { switch (state) { CASE_RETURN_TEXT(RFC_MX_STATE_IDLE); @@ -71,5 +71,3 @@ inline std::string rfcomm_port_state_text(const tRFC_PORT_STATE& state) { return std::string("UNKNOWN[") + std::to_string(state) + std::string("]"); } } - -#undef CASE_RETURN_TEXT diff --git a/system/stack/rfcomm/rfc_ts_frames.cc b/system/stack/rfcomm/rfc_ts_frames.cc index 93329eef06ad335b3f2170cf5a477e1e2c4a9bfe..8db32d68f925aa727c5017fdddaad5e36e2c71e5 100644 --- a/system/stack/rfcomm/rfc_ts_frames.cc +++ b/system/stack/rfcomm/rfc_ts_frames.cc @@ -22,12 +22,15 @@ * ******************************************************************************/ +#define LOG_TAG "rfcomm" + +#include #include #include -#include -#include "bt_target.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/l2c_api.h" @@ -35,8 +38,6 @@ #include "stack/rfcomm/port_int.h" #include "stack/rfcomm/rfc_int.h" -#include - /******************************************************************************* * * Function rfc_send_sabme @@ -517,13 +518,13 @@ tRFC_EVENT rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) { uint16_t len; if (p_buf->len < RFCOMM_CTRL_FRAME_LEN) { - RFCOMM_TRACE_ERROR("Bad Length1: %d", p_buf->len); + LOG_ERROR("Bad Length1: %d", p_buf->len); return (RFC_EVENT_BAD_FRAME); } RFCOMM_PARSE_CTRL_FIELD(ead, p_frame->cr, p_frame->dlci, p_data); if (!ead) { - RFCOMM_TRACE_ERROR("Bad Address(EA must be 1)"); + LOG_ERROR("Bad Address(EA must be 1)"); return (RFC_EVENT_BAD_FRAME); } RFCOMM_PARSE_TYPE_FIELD(p_frame->type, p_frame->pf, p_data); @@ -533,12 +534,12 @@ tRFC_EVENT rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) { if (eal == 0 && p_buf->len > RFCOMM_CTRL_FRAME_LEN) { len += (*(p_data)++ << RFCOMM_SHIFT_LENGTH2); } else if (eal == 0) { - RFCOMM_TRACE_ERROR("Bad Length when EAL = 0: %d", p_buf->len); + LOG_ERROR("Bad Length when EAL = 0: %d", p_buf->len); return RFC_EVENT_BAD_FRAME; } if (p_buf->len < (3 + !ead + !eal + 1)) { - RFCOMM_TRACE_ERROR("Bad Length: %d", p_buf->len); + LOG_ERROR("Bad Length: %d", p_buf->len); return RFC_EVENT_BAD_FRAME; } p_buf->len -= (3 + !ead + !eal + 1); /* Additional 1 for FCS */ @@ -548,7 +549,7 @@ tRFC_EVENT rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) { if ((p_mcb->flow == PORT_FC_CREDIT) && (p_frame->type == RFCOMM_UIH) && (p_frame->dlci != RFCOMM_MX_DLCI) && (p_frame->pf == 1)) { if (p_buf->len < sizeof(uint8_t)) { - RFCOMM_TRACE_ERROR("Bad Length in flow control: %d", p_buf->len); + LOG_ERROR("Bad Length in flow control: %d", p_buf->len); return RFC_EVENT_BAD_FRAME; } p_frame->credit = *p_data++; @@ -559,7 +560,7 @@ tRFC_EVENT rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) { } if (p_buf->len != len) { - RFCOMM_TRACE_ERROR("Bad Length2 %d %d", p_buf->len, len); + LOG_ERROR("Bad Length2 %d %d", p_buf->len, len); return (RFC_EVENT_BAD_FRAME); } @@ -574,7 +575,7 @@ tRFC_EVENT rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) { if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr) || !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci) || !rfc_check_fcs(RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) { - RFCOMM_TRACE_ERROR("Bad SABME"); + LOG_ERROR("Bad SABME"); return (RFC_EVENT_BAD_FRAME); } else return (RFC_EVENT_SABME); @@ -583,7 +584,7 @@ tRFC_EVENT rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) { if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr) || !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci) || !rfc_check_fcs(RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) { - RFCOMM_TRACE_ERROR("Bad UA"); + LOG_ERROR("Bad UA"); return (RFC_EVENT_BAD_FRAME); } else return (RFC_EVENT_UA); @@ -592,7 +593,7 @@ tRFC_EVENT rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) { if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr) || len || !RFCOMM_VALID_DLCI(p_frame->dlci) || !rfc_check_fcs(RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) { - RFCOMM_TRACE_ERROR("Bad DM"); + LOG_ERROR("Bad DM"); return (RFC_EVENT_BAD_FRAME); } else return (RFC_EVENT_DM); @@ -601,21 +602,21 @@ tRFC_EVENT rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) { if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr) || !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci) || !rfc_check_fcs(RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) { - RFCOMM_TRACE_ERROR("Bad DISC"); + LOG_ERROR("Bad DISC"); return (RFC_EVENT_BAD_FRAME); } else return (RFC_EVENT_DISC); case RFCOMM_UIH: if (!RFCOMM_VALID_DLCI(p_frame->dlci)) { - RFCOMM_TRACE_ERROR("Bad UIH - invalid DLCI"); + LOG_ERROR("Bad UIH - invalid DLCI"); return (RFC_EVENT_BAD_FRAME); } else if (!rfc_check_fcs(2, p_start, fcs)) { - RFCOMM_TRACE_ERROR("Bad UIH - FCS"); + LOG_ERROR("Bad UIH - FCS"); return (RFC_EVENT_BAD_FRAME); } else if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)) { /* we assume that this is ok to allow bad implementations to work */ - RFCOMM_TRACE_ERROR("Bad UIH - response"); + LOG_ERROR("Bad UIH - response"); return (RFC_EVENT_UIH); } else { return (RFC_EVENT_UIH); @@ -640,9 +641,8 @@ void rfc_process_mx_message(tRFC_MCB* p_mcb, BT_HDR* p_buf) { uint8_t ea, cr, mx_len; if (length < 2) { - RFCOMM_TRACE_ERROR( - "%s: Illegal MX Frame len when reading EA, C/R. len:%d < 2", __func__, - length); + LOG_ERROR("%s: Illegal MX Frame len when reading EA, C/R. len:%d < 2", + __func__, length); osi_free(p_buf); return; } @@ -669,8 +669,8 @@ void rfc_process_mx_message(tRFC_MCB* p_mcb, BT_HDR* p_buf) { if (!ea) { if (length < 1) { - RFCOMM_TRACE_ERROR("%s: Illegal MX Frame when EA = 0. len:%d < 1", - __func__, length); + LOG_ERROR("%s: Illegal MX Frame when EA = 0. len:%d < 1", __func__, + length); osi_free(p_buf); return; } @@ -685,8 +685,8 @@ void rfc_process_mx_message(tRFC_MCB* p_mcb, BT_HDR* p_buf) { return; } - RFCOMM_TRACE_DEBUG("%s: type=0x%02x, bd_addr=%s", __func__, p_rx_frame->type, - ADDRESS_TO_LOGGABLE_CSTR(p_mcb->bd_addr)); + LOG_VERBOSE("%s: type=0x%02x, bd_addr=%s", __func__, p_rx_frame->type, + ADDRESS_TO_LOGGABLE_CSTR(p_mcb->bd_addr)); switch (p_rx_frame->type) { case RFCOMM_MX_PN: if (length != RFCOMM_MX_PN_LEN) { @@ -752,7 +752,7 @@ void rfc_process_mx_message(tRFC_MCB* p_mcb, BT_HDR* p_buf) { case RFCOMM_MX_MSC: if (length != RFCOMM_MX_MSC_LEN_WITH_BREAK && length != RFCOMM_MX_MSC_LEN_NO_BREAK) { - RFCOMM_TRACE_ERROR("%s: Illegal MX MSC Frame len:%d", __func__, length); + LOG_ERROR("%s: Illegal MX MSC Frame len:%d", __func__, length); osi_free(p_buf); return; } @@ -762,7 +762,7 @@ void rfc_process_mx_message(tRFC_MCB* p_mcb, BT_HDR* p_buf) { if (!ea || !cr || !p_rx_frame->dlci || !RFCOMM_VALID_DLCI(p_rx_frame->dlci)) { - RFCOMM_TRACE_ERROR("Bad MSC frame"); + LOG_ERROR("Bad MSC frame"); break; } @@ -804,7 +804,7 @@ void rfc_process_mx_message(tRFC_MCB* p_mcb, BT_HDR* p_buf) { if (!ea || !cr || !p_rx_frame->dlci || !RFCOMM_VALID_DLCI(p_rx_frame->dlci)) { - RFCOMM_TRACE_ERROR("Bad RPN frame"); + LOG_ERROR("Bad RPN frame"); break; } @@ -845,7 +845,7 @@ void rfc_process_mx_message(tRFC_MCB* p_mcb, BT_HDR* p_buf) { if (!ea || !cr || !p_rx_frame->dlci || !RFCOMM_VALID_DLCI(p_rx_frame->dlci)) { - RFCOMM_TRACE_ERROR("Bad RPN frame"); + LOG_ERROR("Bad RPN frame"); break; } diff --git a/system/stack/rfcomm/rfc_utils.cc b/system/stack/rfcomm/rfc_utils.cc index b92963fb3d2ab720632e72a93d5e0d909ee912ae..1d86998bb489f360be0e83bbf471cbf675b73aee 100644 --- a/system/stack/rfcomm/rfc_utils.cc +++ b/system/stack/rfcomm/rfc_utils.cc @@ -22,10 +22,13 @@ * *****************************************************************************/ +#define LOG_TAG "rfcomm" + #include #include "bt_target.h" #include "osi/include/allocator.h" +#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" #include "stack/include/port_ext.h" @@ -131,11 +134,10 @@ tRFC_MCB* rfc_alloc_multiplexer_channel(const RawAddress& bd_addr, int i, j; tRFC_MCB* p_mcb = NULL; VLOG(1) << __func__ << ": bd_addr:" << ADDRESS_TO_LOGGABLE_STR(bd_addr); - RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d", - is_initiator); + LOG_VERBOSE("rfc_alloc_multiplexer_channel:is_initiator:%d", is_initiator); for (i = 0; i < MAX_BD_CONNECTIONS; i++) { - RFCOMM_TRACE_DEBUG( + LOG_VERBOSE( "rfc_alloc_multiplexer_channel rfc_cb.port.rfc_mcb[%d].state:%d", i, rfc_cb.port.rfc_mcb[i].state); VLOG(1) << "(rfc_cb.port.rfc_mcb[i].bd_addr:" @@ -147,7 +149,7 @@ tRFC_MCB* rfc_alloc_multiplexer_channel(const RawAddress& bd_addr, /* If there was an inactivity timer running stop it now */ if (rfc_cb.port.rfc_mcb[i].state == RFC_MX_STATE_CONNECTED) rfc_timer_stop(&rfc_cb.port.rfc_mcb[i]); - RFCOMM_TRACE_DEBUG( + LOG_VERBOSE( "rfc_alloc_multiplexer_channel:is_initiator:%d, found, state:%d, " "p_mcb:%p", is_initiator, rfc_cb.port.rfc_mcb[i].state, &rfc_cb.port.rfc_mcb[i]); @@ -166,7 +168,7 @@ tRFC_MCB* rfc_alloc_multiplexer_channel(const RawAddress& bd_addr, fixed_queue_free(p_mcb->cmd_q, NULL); memset(p_mcb, 0, sizeof(tRFC_MCB)); p_mcb->bd_addr = bd_addr; - RFCOMM_TRACE_DEBUG( + LOG_VERBOSE( "rfc_alloc_multiplexer_channel:is_initiator:%d, create new p_mcb:%p, " "index:%d", is_initiator, &rfc_cb.port.rfc_mcb[j], j); @@ -219,7 +221,7 @@ void rfc_release_multiplexer_channel(tRFC_MCB* p_mcb) { * ******************************************************************************/ void rfc_timer_start(tRFC_MCB* p_mcb, uint16_t timeout) { - RFCOMM_TRACE_EVENT("%s - timeout:%d seconds", __func__, timeout); + LOG_VERBOSE("%s - timeout:%d seconds", __func__, timeout); uint64_t interval_ms = timeout * 1000; alarm_set_on_mloop(p_mcb->mcb_timer, interval_ms, rfcomm_mcb_timer_timeout, @@ -234,7 +236,7 @@ void rfc_timer_start(tRFC_MCB* p_mcb, uint16_t timeout) { * ******************************************************************************/ void rfc_timer_stop(tRFC_MCB* p_mcb) { - RFCOMM_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); alarm_cancel(p_mcb->mcb_timer); } @@ -247,7 +249,7 @@ void rfc_timer_stop(tRFC_MCB* p_mcb) { * ******************************************************************************/ void rfc_port_timer_start(tPORT* p_port, uint16_t timeout) { - RFCOMM_TRACE_EVENT("%s - timeout:%d seconds", __func__, timeout); + LOG_VERBOSE("%s - timeout:%d seconds", __func__, timeout); uint64_t interval_ms = timeout * 1000; alarm_set_on_mloop(p_port->rfc.port_timer, interval_ms, @@ -262,7 +264,7 @@ void rfc_port_timer_start(tPORT* p_port, uint16_t timeout) { * ******************************************************************************/ void rfc_port_timer_stop(tPORT* p_port) { - RFCOMM_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("%s", __func__); alarm_cancel(p_port->rfc.port_timer); } @@ -375,7 +377,7 @@ void rfc_inc_credit(tPORT* p_port, uint8_t credit) { if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) { p_port->credit_tx += credit; - RFCOMM_TRACE_EVENT("rfc_inc_credit:%d", p_port->credit_tx); + LOG_VERBOSE("rfc_inc_credit:%d", p_port->credit_tx); if (p_port->tx.peer_fc) PORT_FlowInd(p_port->rfc.p_mcb, p_port->dlci, true); } @@ -414,7 +416,7 @@ void rfc_check_send_cmd(tRFC_MCB* p_mcb, BT_HDR* p_buf) { /* if passed a buffer queue it */ if (p_buf != NULL) { if (p_mcb->cmd_q == NULL) { - RFCOMM_TRACE_ERROR( + LOG_ERROR( "%s: empty queue: p_mcb = %p p_mcb->lcid = %u cached p_mcb = %p", __func__, p_mcb, p_mcb->lcid, rfc_find_lcid_mcb(p_mcb->lcid)); } diff --git a/system/stack/sdp/internal/sdp_api.h b/system/stack/sdp/internal/sdp_api.h new file mode 100644 index 0000000000000000000000000000000000000000..ba2276fb6edc4a5fee448c331606ca232789898f --- /dev/null +++ b/system/stack/sdp/internal/sdp_api.h @@ -0,0 +1,437 @@ +/****************************************************************************** + * + * Copyright 1999-2012 Broadcom Corporation + * + * 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 + +#include "stack/include/sdp_callback.h" +#include "stack/include/sdp_device_id.h" +#include "stack/sdp/sdp_discovery_db.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +/******************************************************************************* + * + * Function SDP_InitDiscoveryDb + * + * Description This function is called to initialize a discovery database. + * + * Returns true if successful, false if one or more parameters are bad + * + ******************************************************************************/ +bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len, + uint16_t num_uuid, const bluetooth::Uuid* p_uuid_list, + uint16_t num_attr, const uint16_t* p_attr_list); + +/******************************************************************************* + * + * Function SDP_CancelServiceSearch + * + * Description This function cancels an active query to an SDP server. + * + * Returns true if discovery cancelled, false if a matching activity is + * not found. + * + ******************************************************************************/ +bool SDP_CancelServiceSearch(const tSDP_DISCOVERY_DB* p_db); + +/******************************************************************************* + * + * Function SDP_ServiceSearchRequest + * + * Description This function queries an SDP server for information. + * + * Returns true if discovery started, false if failed. + * + ******************************************************************************/ +bool SDP_ServiceSearchRequest(const RawAddress& p_bd_addr, + tSDP_DISCOVERY_DB* p_db, tSDP_DISC_CMPL_CB* p_cb); + +/******************************************************************************* + * + * Function SDP_ServiceSearchAttributeRequest + * + * Description This function queries an SDP server for information. + * + * The difference between this API function and the function + * SDP_ServiceSearchRequest is that this one does a + * combined ServiceSearchAttributeRequest SDP function. + * + * Returns true if discovery started, false if failed. + * + ******************************************************************************/ +bool SDP_ServiceSearchAttributeRequest(const RawAddress& p_bd_addr, + tSDP_DISCOVERY_DB* p_db, + tSDP_DISC_CMPL_CB* p_cb); + +/******************************************************************************* + * + * Function SDP_ServiceSearchAttributeRequest2 + * + * Description This function queries an SDP server for information. + * + * The difference between this API function and the function + * SDP_ServiceSearchRequest is that this one does a + * combined ServiceSearchAttributeRequest SDP function with the + * user data piggyback + * + * Returns true if discovery started, false if failed. + * + ******************************************************************************/ +bool SDP_ServiceSearchAttributeRequest2(const RawAddress& p_bd_addr, + tSDP_DISCOVERY_DB* p_db, + tSDP_DISC_CMPL_CB2* p_cb, + const void* user_data); + +/* API of utilities to find data in the local discovery database */ + +/******************************************************************************* + * + * Function SDP_FindAttributeInRec + * + * Description This function searches an SDP discovery record for a + * specific attribute. + * + * Returns Pointer to matching attribute entry, or NULL + * + ******************************************************************************/ +tSDP_DISC_ATTR* SDP_FindAttributeInRec(const tSDP_DISC_REC* p_rec, + uint16_t attr_id); + +/******************************************************************************* + * + * Function SDP_FindServiceInDb + * + * Description This function queries an SDP database for a specific + * service. If the p_start_rec pointer is NULL, it looks from + * the beginning of the database, else it continues from the + * next record after p_start_rec. + * + * Returns Pointer to record containing service class, or NULL + * + ******************************************************************************/ +tSDP_DISC_REC* SDP_FindServiceInDb(const tSDP_DISCOVERY_DB* p_db, + uint16_t service_uuid, + tSDP_DISC_REC* p_start_rec); + +/******************************************************************************* + * + * Function SDP_FindServiceUUIDInDb + * + * Description This function queries an SDP database for a specific + * service. If the p_start_rec pointer is NULL, it looks from + * the beginning of the database, else it continues from the + * next record after p_start_rec. + * + * NOTE the only difference between this function and the previous + * function "SDP_FindServiceInDb()" is that this function takes + * a Uuid input. + * + * Returns Pointer to record containing service class, or NULL + * + ******************************************************************************/ +tSDP_DISC_REC* SDP_FindServiceUUIDInDb(const tSDP_DISCOVERY_DB* p_db, + const bluetooth::Uuid& uuid, + tSDP_DISC_REC* p_start_rec); + +/******************************************************************************* + * + * Function SDP_FindServiceUUIDInRec_128bit + * + * Description Read the 128-bit service UUID within a record, + * if there is any. + * + * Parameters: p_rec - pointer to a SDP record. + * p_uuid - output parameter to save the UUID found. + * + * Returns true if found, otherwise false. + * + ******************************************************************************/ +bool SDP_FindServiceUUIDInRec_128bit(const tSDP_DISC_REC* p_rec, + bluetooth::Uuid* p_uuid); + +/******************************************************************************* + * + * Function SDP_FindServiceUUIDInRec + * + * Description Read the service UUID within a record, + * if there is any. + * + * Parameters: p_rec - pointer to a SDP record. + * p_uuid - pointer to a UUID + * + * Returns true if found, otherwise false. + * + ******************************************************************************/ +bool SDP_FindServiceUUIDInRec(const tSDP_DISC_REC* p_rec, + bluetooth::Uuid* p_uuid); + +/******************************************************************************* + * + * Function SDP_FindServiceInDb_128bit + * + * Description Query an SDP database for a specific service. + * If the p_start_rec pointer is NULL, look from the beginning + * of the database, else continue from the next record after + * p_start_rec. + * + * Returns Pointer to record containing service class, or NULL + * + ******************************************************************************/ +tSDP_DISC_REC* SDP_FindServiceInDb_128bit(const tSDP_DISCOVERY_DB* p_db, + tSDP_DISC_REC* p_start_rec); + +/******************************************************************************* + * + * Function SDP_FindProtocolListElemInRec + * + * Description This function looks at a specific discovery record for a + * protocol list element. + * + * Returns true if found, false if not + * If found, the passed protocol list element is filled in. + * + ******************************************************************************/ +bool SDP_FindProtocolListElemInRec(const tSDP_DISC_REC* p_rec, + uint16_t layer_uuid, + tSDP_PROTOCOL_ELEM* p_elem); + +/******************************************************************************* + * + * Function SDP_FindProfileVersionInRec + * + * Description This function looks at a specific discovery record for the + * Profile list descriptor, and pulls out the version number. + * The version number consists of an 8-bit major version and + * an 8-bit minor version. + * + * Returns true if found, false if not + * If found, the major and minor version numbers that were + * passed in are filled in. + * + ******************************************************************************/ +bool SDP_FindProfileVersionInRec(const tSDP_DISC_REC* p_rec, + uint16_t profile_uuid, uint16_t* p_version); + +/* API into SDP for local service database updates */ + +/******************************************************************************* + * + * Function SDP_CreateRecord + * + * Description This function is called to create a record in the database. + * This would be through the SDP database maintenance API. The + * record is created empty, the application should then call + * "add_attribute" to add the record's attributes. + * + * Returns Record handle if OK, else 0. + * + ******************************************************************************/ +uint32_t SDP_CreateRecord(void); + +/******************************************************************************* + * + * Function SDP_DeleteRecord + * + * Description This function is called to add a record (or all records) + * from the database. This would be through the SDP database + * maintenance API. + * + * If a record handle of 0 is passed, all records are deleted. + * + * Returns true if succeeded, else false + * + ******************************************************************************/ +bool SDP_DeleteRecord(uint32_t handle); + +/******************************************************************************* + * + * Function SDP_AddAttribute + * + * Description This function is called to add an attribute to a record. + * This would be through the SDP database maintenance API. + * If the attribute already exists in the record, it is + * replaced with the new value. + * + * NOTE Attribute values must be passed as a Big Endian stream. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, + uint32_t attr_len, uint8_t* p_val); + +/******************************************************************************* + * + * Function SDP_AddSequence + * + * Description This function is called to add a sequence to a record. + * This would be through the SDP database maintenance API. + * If the sequence already exists in the record, it is replaced + * with the new sequence. + * + * NOTE Element values must be passed as a Big Endian stream. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem, + uint8_t type[], uint8_t len[], uint8_t* p_val[]); + +/******************************************************************************* + * + * Function SDP_AddUuidSequence + * + * Description This function is called to add a UUID sequence to a record. + * This would be through the SDP database maintenance API. + * If the sequence already exists in the record, it is replaced + * with the new sequence. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids, + uint16_t* p_uuids); + +/******************************************************************************* + * + * Function SDP_AddProtocolList + * + * Description This function is called to add a protocol descriptor list to + * a record. This would be through the SDP database + * maintenance API. If the protocol list already exists in the + * record, it is replaced with the new list. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem, + tSDP_PROTOCOL_ELEM* p_elem_list); + +/******************************************************************************* + * + * Function SDP_AddAdditionProtoLists + * + * Description This function is called to add a protocol descriptor list to + * a record. This would be through the SDP database maintenance + * API. If the protocol list already exists in the record, it + * is replaced with the new list. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool SDP_AddAdditionProtoLists(uint32_t handle, uint16_t num_elem, + tSDP_PROTO_LIST_ELEM* p_proto_list); + +/******************************************************************************* + * + * Function SDP_AddProfileDescriptorList + * + * Description This function is called to add a profile descriptor list to + * a record. This would be through the SDP database maintenance + * API. If the version already exists in the record, it is + * replaced with the new one. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid, + uint16_t version); + +/******************************************************************************* + * + * Function SDP_AddLanguageBaseAttrIDList + * + * Description This function is called to add a language base attr list to + * a record. This would be through the SDP database maintenance + * API. If the version already exists in the record, it is + * replaced with the new one. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool SDP_AddLanguageBaseAttrIDList(uint32_t handle, uint16_t lang, + uint16_t char_enc, uint16_t base_id); + +/******************************************************************************* + * + * Function SDP_AddServiceClassIdList + * + * Description This function is called to add a service list to a record. + * This would be through the SDP database maintenance API. + * If the service list already exists in the record, it is + * replaced with the new list. + * + * Returns true if added OK, else false + * + ******************************************************************************/ +bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services, + uint16_t* p_service_uuids); + +/* Device Identification APIs */ + +/******************************************************************************* + * + * Function SDP_SetLocalDiRecord + * + * Description This function adds a DI record to the local SDP database. + * + * Returns Returns SDP_SUCCESS if record added successfully, else error + * + ******************************************************************************/ +uint16_t SDP_SetLocalDiRecord(const tSDP_DI_RECORD* device_info, + uint32_t* p_handle); + +/******************************************************************************* + * + * Function SDP_DiDiscover + * + * Description This function queries a remote device for DI information. + * + * Returns SDP_SUCCESS if query started successfully, else error + * + ******************************************************************************/ +tSDP_STATUS SDP_DiDiscover(const RawAddress& remote_device, + tSDP_DISCOVERY_DB* p_db, uint32_t len, + tSDP_DISC_CMPL_CB* p_cb); + +/******************************************************************************* + * + * Function SDP_GetNumDiRecords + * + * Description Searches specified database for DI records + * + * Returns number of DI records found + * + ******************************************************************************/ +uint8_t SDP_GetNumDiRecords(const tSDP_DISCOVERY_DB* p_db); + +/******************************************************************************* + * + * Function SDP_GetDiRecord + * + * Description This function retrieves a remote device's DI record from + * the specified database. + * + * Returns SDP_SUCCESS if record retrieved, else error + * + ******************************************************************************/ +uint16_t SDP_GetDiRecord(uint8_t getRecordIndex, + tSDP_DI_GET_RECORD* device_info, + const tSDP_DISCOVERY_DB* p_db); diff --git a/system/stack/sdp/sdp_api.cc b/system/stack/sdp/sdp_api.cc index e2da778f5d80bb9b44b52f39ffc03e470a41e8ae..22d2d0430f85c30e9e8df5a77fc680c1e6bd0850 100644 --- a/system/stack/sdp/sdp_api.cc +++ b/system/stack/sdp/sdp_api.cc @@ -22,10 +22,7 @@ * ******************************************************************************/ -#ifndef LOG_TAG #define LOG_TAG "sdp_api" -#endif - #include "stack/include/sdp_api.h" @@ -36,7 +33,9 @@ #include "osi/include/log.h" #include "osi/include/osi.h" // PTR_TO_UINT #include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/sdp_api.h" +#include "stack/sdp/internal/sdp_api.h" #include "stack/sdp/sdpint.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -77,7 +76,7 @@ bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len, /* verify the parameters */ if (p_db == NULL || (sizeof(tSDP_DISCOVERY_DB) > len) || num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS) { - SDP_TRACE_ERROR( + LOG_ERROR( "SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, " "num_attr %d", PTR_TO_UINT(p_db), len, num_uuid, num_attr); @@ -395,14 +394,13 @@ tSDP_DISC_REC* SDP_FindServiceInDb(const tSDP_DISCOVERY_DB* p_db, p_sattr = p_sattr->p_next_attr) { if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) { - SDP_TRACE_DEBUG( + LOG_VERBOSE( "SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x", p_sattr->attr_value.v.u16, service_uuid); if (service_uuid == UUID_SERVCLASS_HDP_PROFILE) { if ((p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE) || (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK)) { - SDP_TRACE_DEBUG( - "SDP_FindServiceInDb found HDP source or sink\n"); + LOG_VERBOSE("SDP_FindServiceInDb found HDP source or sink\n"); return (p_rec); } } @@ -599,7 +597,7 @@ static bool sdp_fill_proto_elem(const tSDP_DISC_ATTR* p_attr, /* Now, see if the entry contains the layer we are interested in */ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) { - /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####", + /* LOG_VERBOSE ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####", p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) && @@ -1065,22 +1063,6 @@ uint16_t SDP_SetLocalDiRecord(const tSDP_DI_RECORD* p_device_info, return result; } -/******************************************************************************* - * - * Function SDP_SetTraceLevel - * - * Description This function sets the trace level for SDP. If called with - * a value of 0xFF, it simply reads the current trace level. - * - * Returns the new (current) trace level - * - ******************************************************************************/ -uint8_t SDP_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) sdp_cb.trace_level = new_level; - - return (sdp_cb.trace_level); -} - namespace { bluetooth::legacy::stack::sdp::tSdpApi api_ = { .service = @@ -1120,7 +1102,6 @@ bluetooth::legacy::stack::sdp::tSdpApi api_ = { .SDP_AddProfileDescriptorList = ::SDP_AddProfileDescriptorList, .SDP_AddLanguageBaseAttrIDList = ::SDP_AddLanguageBaseAttrIDList, .SDP_AddServiceClassIdList = ::SDP_AddServiceClassIdList, - .SDP_DeleteAttribute = ::SDP_DeleteAttribute, }, .device_id = { diff --git a/system/stack/sdp/sdp_db.cc b/system/stack/sdp/sdp_db.cc index f7caa8e4b79bb2135418f43e738d79b9ca78e008..a4326272dced308d150444b767283ef23418bad8 100644 --- a/system/stack/sdp/sdp_db.cc +++ b/system/stack/sdp/sdp_db.cc @@ -23,17 +23,20 @@ * ******************************************************************************/ +#define LOG_TAG "sdp" + #include #include #include "bt_target.h" #include "osi/include/allocator.h" +#include "osi/include/log.h" #include "stack/include/bt_types.h" -#include "stack/include/sdp_api.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/sdpdefs.h" +#include "stack/sdp/sdp_discovery_db.h" #include "stack/sdp/sdpint.h" -#include "types/bluetooth/uuid.h" /******************************************************************************/ /* L O C A L F U N C T I O N P R O T O T Y P E S */ @@ -42,6 +45,9 @@ static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, const uint8_t* p_his_uuid, uint16_t his_len, int nest_level); +bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, + uint32_t attr_len, uint8_t* p_val); + /******************************************************************************* * * Function sdp_db_service_search @@ -119,7 +125,7 @@ static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, type = *p++; p = sdpu_get_len_from_type(p, p_end, type, &len); if (p == NULL || (p + len) > p_end) { - SDP_TRACE_WARNING("%s: bad length", __func__); + LOG_WARN("%s: bad length", __func__); break; } type = type >> 3; @@ -269,7 +275,7 @@ uint32_t SDP_CreateRecord(void) { p_db->record[p_db->num_records].record_handle = handle; p_db->num_records++; - SDP_TRACE_DEBUG("SDP_CreateRecord ok, num_records:%d", p_db->num_records); + LOG_VERBOSE("SDP_CreateRecord ok, num_records:%d", p_db->num_records); /* Add the first attribute (the handle) automatically */ UINT32_TO_BE_FIELD(buf, handle); SDP_AddAttribute(handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE, 4, @@ -277,8 +283,8 @@ uint32_t SDP_CreateRecord(void) { return (p_db->record[p_db->num_records - 1].record_handle); } else - SDP_TRACE_ERROR("SDP_CreateRecord fail, exceed maximum records:%d", - SDP_MAX_RECORDS); + LOG_ERROR("SDP_CreateRecord fail, exceed maximum records:%d", + SDP_MAX_RECORDS); return (0); } @@ -322,8 +328,8 @@ bool SDP_DeleteRecord(uint32_t handle) { sdp_cb.server_db.num_records--; - SDP_TRACE_DEBUG("SDP_DeleteRecord ok, num_records:%d", - sdp_cb.server_db.num_records); + LOG_VERBOSE("SDP_DeleteRecord ok, num_records:%d", + sdp_cb.server_db.num_records); /* if we're deleting the primary DI record, clear the */ /* value in the control block */ if (sdp_cb.server_db.di_primary_handle == handle) { @@ -357,11 +363,13 @@ bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0]; if (p_val == nullptr) { - SDP_TRACE_WARNING("Trying to add attribute with p_val == nullptr, skipped"); + LOG_WARN("Trying to add attribute with p_val == nullptr, skipped"); return (false); } - if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) { + // TODO(305066880): invoke would_log when implemented to check + // if LOG_VERBOSE is displayed. + if (true) { if ((attr_type == UINT_DESC_TYPE) || (attr_type == TWO_COMP_INT_DESC_TYPE) || (attr_type == UUID_DESC_TYPE) || @@ -378,29 +386,29 @@ bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X", (uint8_t)(p_val[i])); } - SDP_TRACE_DEBUG( + LOG_VERBOSE( "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, " "*p_val:%s", handle, attr_id, attr_type, attr_len, p_val, num_array); } else if (attr_type == BOOLEAN_DESC_TYPE) { - SDP_TRACE_DEBUG( + LOG_VERBOSE( "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, " "*p_val:%d", handle, attr_id, attr_type, attr_len, p_val, *p_val); } else if ((attr_type == TEXT_STR_DESC_TYPE) || (attr_type == URL_DESC_TYPE)) { if (p_val[attr_len - 1] == '\0') { - SDP_TRACE_DEBUG( + LOG_VERBOSE( "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, " "*p_val:%s", handle, attr_id, attr_type, attr_len, p_val, (char*)p_val); } else { - SDP_TRACE_DEBUG( + LOG_VERBOSE( "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p", handle, attr_id, attr_type, attr_len, p_val); } } else { - SDP_TRACE_DEBUG( + LOG_VERBOSE( "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p", handle, attr_id, attr_type, attr_len, p_val); } @@ -412,8 +420,10 @@ bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, // error out early, no need to look up if (p_rec->free_pad_ptr >= SDP_MAX_PAD_LEN) { - SDP_TRACE_ERROR("the free pad for SDP record with handle %d is " - "full, skip adding the attribute", handle); + LOG_ERROR( + "the free pad for SDP record with handle %d is " + "full, skip adding the attribute", + handle); return (false); } @@ -471,7 +481,7 @@ bool SDP_AddAttributeToRecord(tSDP_RECORD* p_rec, uint16_t attr_id, if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN) { if (p_rec->free_pad_ptr >= SDP_MAX_PAD_LEN) { - SDP_TRACE_ERROR( + LOG_ERROR( "SDP_AddAttributeToRecord failed: free pad %d equals or exceeds max " "padding length %d", p_rec->free_pad_ptr, SDP_MAX_PAD_LEN); @@ -480,7 +490,7 @@ bool SDP_AddAttributeToRecord(tSDP_RECORD* p_rec, uint16_t attr_id, /* do truncate only for text string type descriptor */ if (attr_type == TEXT_STR_DESC_TYPE) { - SDP_TRACE_WARNING( + LOG_WARN( "SDP_AddAttributeToRecord: attr_len:%d too long. truncate to (%d)", attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr); @@ -497,7 +507,7 @@ bool SDP_AddAttributeToRecord(tSDP_RECORD* p_rec, uint16_t attr_id, p_rec->free_pad_ptr += attr_len; } else if (attr_len == 0 && p_attr->len != 0) { /* if truncate to 0 length, simply don't add */ - SDP_TRACE_ERROR( + LOG_ERROR( "SDP_AddAttributeToRecord fail, length exceed maximum: ID %d: " "attr_len:%d ", attr_id, attr_len); @@ -565,12 +575,12 @@ bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem, p = p_head; if (p_head == p_buff) { /* the first element exceed the max length */ - SDP_TRACE_ERROR("SDP_AddSequence - too long(attribute is not added)!!"); + LOG_ERROR("SDP_AddSequence - too long(attribute is not added)!!"); osi_free(p_buff); return false; } else - SDP_TRACE_ERROR("SDP_AddSequence - too long, add %d elements of %d", xx, - num_elem); + LOG_ERROR("SDP_AddSequence - too long, add %d elements of %d", xx, + num_elem); break; } } @@ -609,8 +619,8 @@ bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids, UINT16_TO_BE_STREAM(p, *p_uuids); if ((p - p_buff) > max_len) { - SDP_TRACE_WARNING("SDP_AddUuidSequence - too long, add %d uuids of %d", - xx, num_uuids); + LOG_WARN("SDP_AddUuidSequence - too long, add %d uuids of %d", xx, + num_uuids); break; } } @@ -842,31 +852,6 @@ bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services, return result; } -/******************************************************************************* - * - * Function SDP_DeleteAttribute - * - * Description This function is called to delete an attribute from a - * record. This would be through the SDP database maintenance - * API. - * - * Returns true if deleted OK, else false if not found - * - ******************************************************************************/ -bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id) { - tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0]; - - /* Find the record in the database */ - for (uint16_t record_index = 0; record_index < sdp_cb.server_db.num_records; record_index++, p_rec++) { - if (p_rec->record_handle == handle) { - SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle); - return SDP_DeleteAttributeFromRecord(p_rec, attr_id); - } - } - /* If here, not found */ - return (false); -} - /******************************************************************************* * * Function SDP_DeleteAttributeFromRecord diff --git a/system/stack/sdp/sdp_discovery.cc b/system/stack/sdp/sdp_discovery.cc index f025df856b97a4cf8418e9e901489ac72bb9d112..5238c06696e481a8fa1cc6583ed32a02d13fc12c 100644 --- a/system/stack/sdp/sdp_discovery.cc +++ b/system/stack/sdp/sdp_discovery.cc @@ -27,12 +27,12 @@ #include #include "bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" -#include "stack/include/sdp_api.h" #include "stack/include/sdpdefs.h" +#include "stack/sdp/sdp_discovery_db.h" #include "stack/sdp/sdpint.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -277,8 +277,7 @@ void sdp_disc_server_rsp(tCONN_CB* p_ccb, BT_HDR* p_msg) { } if (invalid_pdu) { - SDP_TRACE_WARNING("SDP - Unexp. PDU: %d in state: %d", rsp_pdu, - p_ccb->disc_state); + LOG_WARN("SDP - Unexp. PDU: %d in state: %d", rsp_pdu, p_ccb->disc_state); sdp_disconnect(p_ccb, SDP_GENERIC_ERROR); } } @@ -311,7 +310,7 @@ static void process_service_search_rsp(tCONN_CB* p_ccb, uint8_t* p_reply, orig = p_ccb->num_handles; p_ccb->num_handles += cur_handles; if (p_ccb->num_handles == 0 || p_ccb->num_handles < orig) { - SDP_TRACE_WARNING("SDP - Rcvd ServiceSearchRsp, no matches"); + LOG_WARN("SDP - Rcvd ServiceSearchRsp, no matches"); sdp_disconnect(p_ccb, SDP_NO_RECS_MATCH); return; } @@ -381,11 +380,11 @@ static bool sdp_copy_raw_data(tCONN_CB* p_ccb, bool offset) { uint8_t* old_p = p; p = sdpu_get_len_from_type(p, p_end, type, &list_len); if (p == NULL || (p + list_len) > p_end) { - SDP_TRACE_WARNING("%s: bad length", __func__); + LOG_WARN("%s: bad length", __func__); return false; } if ((int)cpy_len < (p - old_p)) { - SDP_TRACE_WARNING("%s: no bytes left for data", __func__); + LOG_WARN("%s: no bytes left for data", __func__); return false; } cpy_len -= (p - old_p); @@ -395,7 +394,7 @@ static bool sdp_copy_raw_data(tCONN_CB* p_ccb, bool offset) { } rem_len = SDP_MAX_LIST_BYTE_COUNT - (unsigned int)(p - &p_ccb->rsp_list[0]); if (cpy_len > rem_len) { - SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len); + LOG_WARN("rem_len :%d less than cpy_len:%d", rem_len, cpy_len); cpy_len = rem_len; } memcpy(&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len); @@ -457,9 +456,9 @@ static void process_service_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply, } cont_request_needed = true; } else { - SDP_TRACE_WARNING("process_service_attr_rsp"); + LOG_WARN("process_service_attr_rsp"); if (!sdp_copy_raw_data(p_ccb, false)) { - SDP_TRACE_ERROR("sdp_copy_raw_data failed"); + LOG_ERROR("sdp_copy_raw_data failed"); sdp_disconnect(p_ccb, SDP_ILLEGAL_PARAMETER); return; } @@ -727,19 +726,19 @@ static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end) { type = *p++; if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) { - SDP_TRACE_WARNING("SDP - Wrong type: 0x%02x in attr_rsp", type); + LOG_WARN("SDP - Wrong type: 0x%02x in attr_rsp", type); return (NULL); } p = sdpu_get_len_from_type(p, p_msg_end, type, &seq_len); if (p == NULL || (p + seq_len) > p_msg_end) { - SDP_TRACE_WARNING("SDP - Bad len in attr_rsp %d", seq_len); + LOG_WARN("SDP - Bad len in attr_rsp %d", seq_len); return (NULL); } /* Create a record */ p_rec = add_record(p_ccb->p_db, p_ccb->device_address); if (!p_rec) { - SDP_TRACE_WARNING("SDP - DB full add_record"); + LOG_WARN("SDP - DB full add_record"); return (NULL); } @@ -750,12 +749,11 @@ static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end) { type = *p++; p = sdpu_get_len_from_type(p, p_msg_end, type, &attr_len); if (p == NULL || (p + attr_len) > p_seq_end) { - SDP_TRACE_WARNING("%s: Bad len in attr_rsp %d", __func__, attr_len); + LOG_WARN("%s: Bad len in attr_rsp %d", __func__, attr_len); return (NULL); } if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2)) { - SDP_TRACE_WARNING("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type, - attr_len); + LOG_WARN("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type, attr_len); return (NULL); } BE_STREAM_TO_UINT16(attr_id, p); @@ -764,7 +762,7 @@ static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end) { p = add_attr(p, p_seq_end, p_ccb->p_db, p_rec, attr_id, NULL, 0); if (!p) { - SDP_TRACE_WARNING("SDP - DB full add_attr"); + LOG_WARN("SDP - DB full add_attr"); return (NULL); } } @@ -838,7 +836,7 @@ static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db, type = *p++; p = sdpu_get_len_from_type(p, p_end, type, &attr_len); if (p == NULL || (p + attr_len) > p_end) { - SDP_TRACE_WARNING("%s: bad length in attr_rsp", __func__); + LOG_WARN("%s: bad length in attr_rsp", __func__); return NULL; } attr_len &= SDP_DISC_ATTR_LEN_MASK; @@ -852,7 +850,7 @@ static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db, p_attr_end = p + attr_len; if (p_attr_end > p_end) { - SDP_TRACE_WARNING("%s: SDP - Attribute length beyond p_end", __func__); + LOG_WARN("%s: SDP - Attribute length beyond p_end", __func__); return NULL; } @@ -881,9 +879,9 @@ static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db, p_db->mem_free -= sizeof(tSDP_DISC_ATTR); total_len = 0; - /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */ + /* LOG_VERBOSE ("SDP - attr nest level:%d(list)", nest_level); */ if (nest_level >= MAX_NEST_LEVELS) { - SDP_TRACE_ERROR("SDP - attr nesting too deep"); + LOG_ERROR("SDP - attr nesting too deep"); return p_attr_end; } @@ -947,7 +945,7 @@ static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db, } break; default: - SDP_TRACE_WARNING("SDP - bad len in UUID attr: %d", attr_len); + LOG_WARN("SDP - bad len in UUID attr: %d", attr_len); return p_attr_end; } break; @@ -960,15 +958,15 @@ static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db, p_db->mem_free -= sizeof(tSDP_DISC_ATTR); total_len = 0; - /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d", nest_level); */ + /* LOG_VERBOSE ("SDP - attr nest level:%d", nest_level); */ if (nest_level >= MAX_NEST_LEVELS) { - SDP_TRACE_ERROR("SDP - attr nesting too deep"); + LOG_ERROR("SDP - attr nesting too deep"); return p_attr_end; } if (is_additional_list != 0 || attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS) nest_level |= SDP_ADDITIONAL_LIST_MASK; - /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */ + /* LOG_VERBOSE ("SDP - attr nest level:0x%x(finish)", nest_level); */ while (p < p_attr_end) { /* Now, add the list entry */ @@ -990,7 +988,7 @@ static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db, p_attr->attr_value.v.u8 = *p++; break; default: - SDP_TRACE_WARNING("SDP - bad len in boolean attr: %d", attr_len); + LOG_WARN("SDP - bad len in boolean attr: %d", attr_len); return p_attr_end; } break; @@ -1016,17 +1014,17 @@ static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db, } else { if (!p_parent_attr->attr_value.v.p_sub_attr) { p_parent_attr->attr_value.v.p_sub_attr = p_attr; - /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch:0x%x(id:%d)", + /* LOG_VERBOSE ("parent:0x%x(id:%d), ch:0x%x(id:%d)", p_parent_attr, p_parent_attr->attr_id, p_attr, p_attr->attr_id); */ } else { tSDP_DISC_ATTR* p_attr1 = p_parent_attr->attr_value.v.p_sub_attr; - /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch1:0x%x(id:%d)", + /* LOG_VERBOSE ("parent:0x%x(id:%d), ch1:0x%x(id:%d)", p_parent_attr, p_parent_attr->attr_id, p_attr1, p_attr1->attr_id); */ while (p_attr1->p_next_attr) p_attr1 = p_attr1->p_next_attr; p_attr1->p_next_attr = p_attr; - /* SDP_TRACE_DEBUG ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */ + /* LOG_VERBOSE ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */ } } diff --git a/system/stack/sdp/sdp_discovery_db.h b/system/stack/sdp/sdp_discovery_db.h new file mode 100644 index 0000000000000000000000000000000000000000..f67f026cc37524bed26ec01a55084c3080680728 --- /dev/null +++ b/system/stack/sdp/sdp_discovery_db.h @@ -0,0 +1,87 @@ +/****************************************************************************** + * + * Copyright 1999-2012 Broadcom Corporation + * + * 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 + +#include "bt_target.h" // SDP_MAX_PROTOCOL_PARAMS +#include "types/bluetooth/uuid.h" + +#pragma once + +/* Masks for attr_value field of tSDP_DISC_ATTR */ +#define SDP_DISC_ATTR_LEN_MASK 0x0FFF +#define SDP_DISC_ATTR_TYPE(len_type) ((len_type) >> 12) +#define SDP_DISC_ATTR_LEN(len_type) ((len_type)&SDP_DISC_ATTR_LEN_MASK) + +#define SDP_MAX_LIST_ELEMS 3 + +/* Define a structure to hold the discovered service information. */ +typedef struct { + union { + uint8_t u8; /* 8-bit integer */ + uint16_t u16; /* 16-bit integer */ + uint32_t u32; /* 32-bit integer */ + struct t_sdp_disc_attr* p_sub_attr; /* Addr of first sub-attr (list)*/ + uint8_t array[]; /* Variable length field */ + /* flexible array member */ + /* requiring backing store */ + /* from SDP DB */ + } v; + +} tSDP_DISC_ATVAL; + +typedef struct t_sdp_disc_attr { + struct t_sdp_disc_attr* p_next_attr; /* Addr of next linked attr */ + uint16_t attr_id; /* Attribute ID */ + uint16_t attr_len_type; /* Length and type fields */ + tSDP_DISC_ATVAL attr_value; /* Variable length entry data */ +} tSDP_DISC_ATTR; + +typedef struct t_sdp_disc_rec { + tSDP_DISC_ATTR* p_first_attr; /* First attribute of record */ + struct t_sdp_disc_rec* p_next_rec; /* Addr of next linked record */ + uint32_t time_read; /* The time the record was read */ + RawAddress remote_bd_addr; /* Remote BD address */ +} tSDP_DISC_REC; + +typedef struct { + uint32_t mem_size; /* Memory size of the DB */ + uint32_t mem_free; /* Memory still available */ + tSDP_DISC_REC* p_first_rec; /* Addr of first record in DB */ + uint16_t num_uuid_filters; /* Number of UUIds to filter */ + bluetooth::Uuid uuid_filters[SDP_MAX_UUID_FILTERS]; /* UUIDs to filter */ + uint16_t num_attr_filters; /* Number of attribute filters */ + uint16_t attr_filters[SDP_MAX_ATTR_FILTERS]; /* Attributes to filter */ + uint8_t* p_free_mem; /* Pointer to free memory */ + uint8_t* + raw_data; /* Received record from server. allocated/released by client */ + uint32_t raw_size; /* size of raw_data */ + uint32_t raw_used; /* length of raw_data used */ +} tSDP_DISCOVERY_DB; + +/* This structure is used to add protocol lists and find protocol elements */ +typedef struct { + uint16_t protocol_uuid; + uint16_t num_params; + uint16_t params[SDP_MAX_PROTOCOL_PARAMS]; +} tSDP_PROTOCOL_ELEM; + +typedef struct { + uint16_t num_elems; + tSDP_PROTOCOL_ELEM list_elem[SDP_MAX_LIST_ELEMS]; +} tSDP_PROTO_LIST_ELEM; diff --git a/system/stack/sdp/sdp_main.cc b/system/stack/sdp/sdp_main.cc index fea653f864fc0380885e66bb305cb81486e50697..829268f3c3de4b0c7c2caec8d7db7f5800c85d1a 100644 --- a/system/stack/sdp/sdp_main.cc +++ b/system/stack/sdp/sdp_main.cc @@ -22,17 +22,19 @@ * ******************************************************************************/ +#define LOG_TAG "sdp" + #include #include // memset #include "gd/common/init_flags.h" #include "osi/include/allocator.h" +#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/bt_hdr.h" -#include "stack/include/bt_types.h" -#include "stack/include/btm_api_types.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/btm_sec_api_types.h" #include "stack/include/l2c_api.h" -#include "stack/include/sdp_api.h" #include "stack/sdp/sdpint.h" #include "types/raw_address.h" @@ -80,8 +82,6 @@ void sdp_init(void) { sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16; sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS; - sdp_cb.trace_level = BT_TRACE_LEVEL_WARNING; - sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind; sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm; sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind; @@ -94,7 +94,7 @@ void sdp_init(void) { /* Now, register with L2CAP */ if (!L2CA_Register2(BT_PSM_SDP, sdp_cb.reg_info, true /* enable_snoop */, nullptr, SDP_MTU_SIZE, 0, BTM_SEC_NONE)) { - SDP_TRACE_ERROR("SDP Registration failed"); + LOG_ERROR("SDP Registration failed"); } } @@ -152,7 +152,7 @@ static void sdp_connect_cfm(uint16_t l2cap_cid, uint16_t result) { /* Find CCB based on CID */ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid); if (p_ccb == NULL) { - SDP_TRACE_WARNING("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid); + LOG_WARN("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid); return; } @@ -181,7 +181,7 @@ static void sdp_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) { /* Find CCB based on CID */ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid); if (p_ccb == NULL) { - SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); + LOG_WARN("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); return; } @@ -197,7 +197,7 @@ static void sdp_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) { p_ccb->rem_mtu_size = p_cfg->mtu; } - SDP_TRACE_EVENT("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid); + LOG_VERBOSE("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid); } /******************************************************************************* @@ -216,12 +216,12 @@ static void sdp_config_cfm(uint16_t l2cap_cid, uint16_t initiator, tCONN_CB* p_ccb; - SDP_TRACE_EVENT("SDP - Rcvd cfg cfm, CID: 0x%x", l2cap_cid); + LOG_VERBOSE("SDP - Rcvd cfg cfm, CID: 0x%x", l2cap_cid); /* Find CCB based on CID */ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid); if (p_ccb == NULL) { - SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); + LOG_WARN("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); return; } @@ -253,7 +253,7 @@ static void sdp_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) { /* Find CCB based on CID */ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid); if (p_ccb == NULL) { - SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid); + LOG_WARN("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid); return; } tCONN_CB& ccb = *p_ccb; @@ -263,12 +263,10 @@ static void sdp_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) { sdpu_callback(ccb, reason); if (ack_needed) { - SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc, process pend sdp ccb: 0x%x", - l2cap_cid); + LOG_WARN("SDP - Rcvd L2CAP disc, process pend sdp ccb: 0x%x", l2cap_cid); sdpu_process_pend_ccb_new_cid(ccb); } else { - SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc, clear pend sdp ccb: 0x%x", - l2cap_cid); + LOG_WARN("SDP - Rcvd L2CAP disc, clear pend sdp ccb: 0x%x", l2cap_cid); sdpu_clear_pend_ccb(ccb); } @@ -302,12 +300,11 @@ static void sdp_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) { else sdp_server_handle_client_req(p_ccb, p_msg); } else { - SDP_TRACE_WARNING( - "SDP - Ignored L2CAP data while in state: %d, CID: 0x%x", - p_ccb->con_state, l2cap_cid); + LOG_WARN("SDP - Ignored L2CAP data while in state: %d, CID: 0x%x", + p_ccb->con_state, l2cap_cid); } } else { - SDP_TRACE_WARNING("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid); + LOG_WARN("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid); } osi_free(p_msg); @@ -330,41 +327,38 @@ tCONN_CB* sdp_conn_originate(const RawAddress& p_bd_addr) { /* Allocate a new CCB. Return if none available. */ p_ccb = sdpu_allocate_ccb(); if (p_ccb == NULL) { - SDP_TRACE_WARNING("%s: no spare CCB for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr)); + LOG_WARN("%s: no spare CCB for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr)); return (NULL); } - SDP_TRACE_EVENT("%s: SDP - Originate started for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr)); + LOG_VERBOSE("%s: SDP - Originate started for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr)); + + /* Look for any active sdp connection on the remote device */ + cid = sdpu_get_active_ccb_cid(p_bd_addr); /* We are the originator of this connection */ p_ccb->con_flags |= SDP_FLAGS_IS_ORIG; - /* Save the BD Address and Channel ID. */ + /* Save the BD Address */ p_ccb->device_address = p_bd_addr; - /* Transition to the next appropriate state, waiting for connection confirm. - */ - p_ccb->con_state = SDP_STATE_CONN_SETUP; - - // Look for any active sdp connection on the remote device - cid = sdpu_get_active_ccb_cid(p_bd_addr); - + /* Transition to the next appropriate state, waiting for connection confirm */ if (!bluetooth::common::init_flags::sdp_serialization_is_enabled() || cid == 0) { p_ccb->con_state = SDP_STATE_CONN_SETUP; cid = L2CA_ConnectReq2(BT_PSM_SDP, p_bd_addr, BTM_SEC_NONE); } else { p_ccb->con_state = SDP_STATE_CONN_PEND; - SDP_TRACE_WARNING("SDP already active for peer %s. cid=%#0x", - ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr), cid); + LOG_WARN("SDP already active for peer %s. cid=%#0x", + ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr), cid); } /* Check if L2CAP started the connection process */ if (cid == 0) { - SDP_TRACE_WARNING("%s: SDP - Originate failed for peer %s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr)); + LOG_WARN("%s: SDP - Originate failed for peer %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr)); sdpu_release_ccb(*p_ccb); return (NULL); } @@ -383,7 +377,7 @@ tCONN_CB* sdp_conn_originate(const RawAddress& p_bd_addr) { ******************************************************************************/ void sdp_disconnect(tCONN_CB* p_ccb, tSDP_REASON reason) { tCONN_CB& ccb = *p_ccb; - SDP_TRACE_EVENT("SDP - disconnect CID: 0x%x", ccb.connection_id); + LOG_VERBOSE("SDP - disconnect CID: 0x%x", ccb.connection_id); /* Check if we have a connection ID */ if (ccb.connection_id != 0) { @@ -422,13 +416,12 @@ static void sdp_disconnect_cfm(uint16_t l2cap_cid, /* Find CCB based on CID */ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid); if (p_ccb == NULL) { - SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x", - l2cap_cid); + LOG_WARN("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid); return; } tCONN_CB& ccb = *p_ccb; - SDP_TRACE_EVENT("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid); + LOG_VERBOSE("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid); sdpu_callback(ccb, static_cast(ccb.disconnect_reason)); sdpu_process_pend_ccb_new_cid(ccb); @@ -448,8 +441,8 @@ static void sdp_disconnect_cfm(uint16_t l2cap_cid, void sdp_conn_timer_timeout(void* data) { tCONN_CB& ccb = *(tCONN_CB*)data; - SDP_TRACE_EVENT("SDP - CCB timeout in state: %d CID: 0x%x", ccb.con_state, - ccb.connection_id); + LOG_VERBOSE("SDP - CCB timeout in state: %d CID: 0x%x", ccb.con_state, + ccb.connection_id); L2CA_DisconnectReq(ccb.connection_id); diff --git a/system/stack/sdp/sdp_server.cc b/system/stack/sdp/sdp_server.cc index 4bba094b4af9f80c3f4453ddb5ed5f74a3a4f6da..3bbb8fc63566e0236ed84d84a6912dc79aa81b52 100644 --- a/system/stack/sdp/sdp_server.cc +++ b/system/stack/sdp/sdp_server.cc @@ -24,32 +24,25 @@ ******************************************************************************/ #define LOG_TAG "sdp_server" -#include -#include -#include #include // memcpy #include -// include before bta_hfp_api for pre-defined variable -#include "btif/include/btif_storage.h" - -// remaining includes -#include "bta/include/bta_hfp_api.h" -#include "btif/include/btif_config.h" #include "btif/include/btif_profile_storage.h" #include "btif/include/btif_storage.h" -#include "common/init_flags.h" #include "device/include/interop.h" #include "device/include/interop_config.h" +#include "gd/common/init_flags.h" +#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" #include "stack/btm/btm_dev.h" -#include "stack/include/avrc_api.h" -#include "stack/include/avrc_defs.h" +#include "stack/btm/btm_sco_hfp_hal.h" +#include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_api.h" -#include "stack/include/sdp_api.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/sdpdefs.h" #include "stack/sdp/sdpint.h" /* Maximum number of bytes to reserve out of SDP MTU for response data */ @@ -60,6 +53,7 @@ #define SDP_PROFILE_DESC_LENGTH 8 #define HFP_PROFILE_MINOR_VERSION_6 0x06 #define HFP_PROFILE_MINOR_VERSION_7 0x07 +#define HFP_PROFILE_MINOR_VERSION_9 0x09 #define PBAP_GOEP_L2CAP_PSM_LEN 0x06 #define PBAP_SUPP_FEA_LEN 0x08 @@ -171,15 +165,22 @@ bool sdp_dynamic_change_hfp_version(const tSDP_ATTRIBUTE* p_attr, bool is_allowlisted_1_7 = interop_match_addr_or_name(INTEROP_HFP_1_7_ALLOWLIST, &remote_address, &btif_storage_get_remote_device_property); + bool is_allowlisted_1_9 = + interop_match_addr_or_name(INTEROP_HFP_1_9_ALLOWLIST, &remote_address, + &btif_storage_get_remote_device_property); /* For PTS we should update AG's HFP version as 1.7 */ - if (!(is_allowlisted_1_7) && + if (!(is_allowlisted_1_7) && !(is_allowlisted_1_9) && !(osi_property_get_bool("vendor.bt.pts.certification", false))) { return false; } - p_attr->value_ptr[PROFILE_VERSION_POSITION] = HFP_PROFILE_MINOR_VERSION_7; - SDP_TRACE_INFO("%s SDP Change HFP Version = %d for %s", __func__, - p_attr->value_ptr[PROFILE_VERSION_POSITION], - ADDRESS_TO_LOGGABLE_CSTR(remote_address)); + if (hfp_hal_interface::get_swb_supported() && is_allowlisted_1_9) { + p_attr->value_ptr[PROFILE_VERSION_POSITION] = HFP_PROFILE_MINOR_VERSION_9; + } else { + p_attr->value_ptr[PROFILE_VERSION_POSITION] = HFP_PROFILE_MINOR_VERSION_7; + } + LOG_VERBOSE("%s SDP Change HFP Version = %d for %s", __func__, + p_attr->value_ptr[PROFILE_VERSION_POSITION], + ADDRESS_TO_LOGGABLE_CSTR(remote_address)); return true; } /****************************************************************************** @@ -194,7 +195,7 @@ bool sdp_dynamic_change_hfp_version(const tSDP_ATTRIBUTE* p_attr, void hfp_fallback(bool& is_hfp_fallback, const tSDP_ATTRIBUTE* p_attr) { /* Update HFP version back to 1.6 */ p_attr->value_ptr[PROFILE_VERSION_POSITION] = HFP_PROFILE_MINOR_VERSION_6; - SDP_TRACE_INFO("Restore HFP version to 1.6"); + LOG_VERBOSE("Restore HFP version to 1.6"); is_hfp_fallback = false; } @@ -263,7 +264,7 @@ void sdp_server_handle_client_req(tCONN_CB* p_ccb, BT_HDR* p_msg) { default: sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU); - SDP_TRACE_WARNING("SDP - server got unknown PDU: 0x%x", pdu_id); + LOG_WARN("SDP - server got unknown PDU: 0x%x", pdu_id); break; } } @@ -376,7 +377,7 @@ static void process_service_search(tCONN_CB* p_ccb, uint16_t trans_num, UINT16_TO_BE_STREAM(p_rsp, num_rsp_handles); UINT16_TO_BE_STREAM(p_rsp, cur_handles); - /* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, + /* LOG_VERBOSE("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, cont %d", num_rsp_handles, cur_handles, cont_offset, cont_offset + cur_handles-1, is_cont); */ @@ -471,7 +472,7 @@ static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, pbap_pse_dynamic_version_upgrade_is_enabled()) { p_rec = sdp_upgrade_pse_record(p_rec, p_ccb->device_address); } else { - SDP_TRACE_WARNING("PBAP PSE dynamic version upgrade is not enabled"); + LOG_WARN("PBAP PSE dynamic version upgrade is not enabled"); } /* Free and reallocate buffer */ @@ -537,8 +538,7 @@ static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, dynamic_avrcp_version_enhancement_is_enabled()) { avrc_sdp_version = sdpu_is_avrcp_profile_description_list( p_attr_profile_desc_list_id); - SDP_TRACE_ERROR("avrc_sdp_version in SDP records %x", - avrc_sdp_version); + LOG_ERROR("avrc_sdp_version in SDP records %x", avrc_sdp_version); sdpu_set_avrc_target_features(p_attr, &(p_ccb->device_address), avrc_sdp_version); } @@ -578,8 +578,8 @@ static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, attr_len) /* Not enough space for attr... so add partially */ { if (attr_len >= SDP_MAX_ATTR_LEN) { - SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", - max_list_len, attr_len); + LOG_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", + max_list_len, attr_len); sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL); return; } @@ -789,7 +789,7 @@ static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, pbap_pse_dynamic_version_upgrade_is_enabled()) { p_rec = sdp_upgrade_pse_record(p_rec, p_ccb->device_address); } else { - SDP_TRACE_WARNING("PBAP PSE dynamic version upgrade is not enabled"); + LOG_WARN("PBAP PSE dynamic version upgrade is not enabled"); } /* Allow space for attribute sequence type and length */ p_seq_start = p_rsp; @@ -832,8 +832,7 @@ static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, p_attr_profile_desc_list_id != nullptr) { avrc_sdp_version = sdpu_is_avrcp_profile_description_list( p_attr_profile_desc_list_id); - SDP_TRACE_ERROR("avrc_sdp_version in SDP records %x", - avrc_sdp_version); + LOG_ERROR("avrc_sdp_version in SDP records %x", avrc_sdp_version); sdpu_set_avrc_target_features(p_attr, &(p_ccb->device_address), avrc_sdp_version); } @@ -875,8 +874,8 @@ static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, attr_len) /* Not enough space for attr... so add partially */ { if (attr_len >= SDP_MAX_ATTR_LEN) { - SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", - max_list_len, attr_len); + LOG_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", + max_list_len, attr_len); sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL); return; } @@ -978,12 +977,12 @@ static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, sdp_pbap_pse_dynamic_attributes_len_update(p_ccb, &attr_seq_sav, &uid_seq); } else { - SDP_TRACE_WARNING("PBAP PSE dynamic version upgrade is not enabled"); + LOG_WARN("PBAP PSE dynamic version upgrade is not enabled"); p_ccb->pse_dynamic_attributes_len = 0; } - SDP_TRACE_DEBUG("p_ccb->list_len = %d pse_dynamic_attributes_len = %d", - p_ccb->list_len, p_ccb->pse_dynamic_attributes_len); + LOG_VERBOSE("p_ccb->list_len = %d pse_dynamic_attributes_len = %d", + p_ccb->list_len, p_ccb->pse_dynamic_attributes_len); /* Put in the sequence header (2 or 3 bytes) */ if (p_ccb->list_len > 255) { @@ -1029,7 +1028,7 @@ static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, p_ccb->cont_offset += len_to_send; - SDP_TRACE_DEBUG( + LOG_VERBOSE( "p_ccb->pse_dynamic_attributes_len %d, cont_offset = %d, p_ccb->list_len " "= %d", p_ccb->pse_dynamic_attributes_len, p_ccb->cont_offset, @@ -1072,7 +1071,7 @@ static bool is_device_in_allowlist_for_pbap(RawAddress remote_address, if (!check_for_1_2 && interop_match_addr_or_name(INTEROP_ADV_PBAP_VER_1_1, &remote_address, &btif_storage_get_remote_device_property)) { - SDP_TRACE_DEBUG("device is in allowlist for pbap version < 1.2 "); + LOG_VERBOSE("device is in allowlist for pbap version < 1.2 "); return true; } if (check_for_1_2) { @@ -1080,15 +1079,14 @@ static bool is_device_in_allowlist_for_pbap(RawAddress remote_address, if (interop_match_addr_or_name( INTEROP_ADV_PBAP_VER_1_2, &remote_address, &btif_storage_get_remote_device_property)) { - SDP_TRACE_DEBUG("device is in allowlist for pbap version 1.2 "); + LOG_VERBOSE("device is in allowlist for pbap version 1.2 "); return true; } } else { - char* p_name = BTM_SecReadDevName(remote_address); + const char* p_name = BTM_SecReadDevName(remote_address); if ((p_name != NULL) && interop_match_name(INTEROP_ADV_PBAP_VER_1_2, p_name)) { - SDP_TRACE_DEBUG( - "device is not paired & in allowlist for pbap version 1.2"); + LOG_VERBOSE("device is not paired & in allowlist for pbap version 1.2"); return true; } } @@ -1122,7 +1120,7 @@ static uint16_t sdp_pbap_pse_dynamic_attributes_len_update( is_device_in_allowlist_for_pbap(p_ccb->device_address, true); bool running_pts = osi_property_get_bool(SDP_ENABLE_PTS_PBAP, false); - SDP_TRACE_DEBUG( + LOG_VERBOSE( "remote BD Addr : %s is_pbap_102_supported = %d " "is_pbap_101_allowlisted = %d is_pbap_102_allowlisted = %d " "running_pts = %d", @@ -1145,13 +1143,13 @@ static uint16_t sdp_pbap_pse_dynamic_attributes_len_update( UUID_SERVCLASS_PBAP_PSE)) { // PBAP PSE Record p_rec = sdp_upgrade_pse_record(p_rec, p_ccb->device_address); - SDP_TRACE_DEBUG("response has PBAP PSE record for allowlist device"); + LOG_VERBOSE("response has PBAP PSE record for allowlist device"); int att_index; bool l2cap_psm_len_included = false, supp_attr_len_included = false; for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq->num_attr; xx++) { - SDP_TRACE_DEBUG( + LOG_VERBOSE( "xx = %d attr_seq->num_attr = %d, " "attr_seq->attr_entry[xx].start = %d , " "attr_seq->attr_entry[xx].end = %d", @@ -1166,7 +1164,7 @@ static uint16_t sdp_pbap_pse_dynamic_attributes_len_update( cur_attr.id <= attr_seq->attr_entry[xx].end) { l2cap_psm_len_included = true; p_ccb->pse_dynamic_attributes_len += PBAP_GOEP_L2CAP_PSM_LEN; - SDP_TRACE_ERROR( + LOG_ERROR( "ATTR_ID_GOEP_L2CAP_PSM requested," " need to change length by %d", p_ccb->pse_dynamic_attributes_len); @@ -1176,7 +1174,7 @@ static uint16_t sdp_pbap_pse_dynamic_attributes_len_update( cur_attr.id <= attr_seq->attr_entry[xx].end) { supp_attr_len_included = true; p_ccb->pse_dynamic_attributes_len += PBAP_SUPP_FEA_LEN; - SDP_TRACE_DEBUG( + LOG_VERBOSE( "ATTR_ID_PBAP_SUPPORTED_FEATURES requested," " need to change length by %d", p_ccb->pse_dynamic_attributes_len); @@ -1187,8 +1185,8 @@ static uint16_t sdp_pbap_pse_dynamic_attributes_len_update( break; } } - SDP_TRACE_DEBUG("pse_dynamic_attributes_len = %d", - p_ccb->pse_dynamic_attributes_len); + LOG_VERBOSE("pse_dynamic_attributes_len = %d", + p_ccb->pse_dynamic_attributes_len); return p_ccb->pse_dynamic_attributes_len; } @@ -1221,7 +1219,7 @@ static const tSDP_RECORD* sdp_upgrade_pse_record(const tSDP_RECORD* p_rec, is_device_in_allowlist_for_pbap(remote_address, true); bool running_pts = osi_property_get_bool(SDP_ENABLE_PTS_PBAP, false); - SDP_TRACE_DEBUG( + LOG_VERBOSE( "%s remote BD Addr : %s is_pbap_102_supported : %d " "is_pbap_101_allowlisted = %d is_pbap_102_allowlisted = %d " "running_pts = %d", @@ -1269,7 +1267,7 @@ static const tSDP_RECORD* sdp_upgrade_pse_record(const tSDP_RECORD* p_rec, UINT_DESC_TYPE, (uint32_t)2, temp); if (!status) { - SDP_TRACE_ERROR("FAILED"); + LOG_ERROR("FAILED"); return p_rec; } return &pbap_102_sdp_rec; @@ -1286,11 +1284,11 @@ void update_pce_entry_to_interop_database(RawAddress remote_addr) { if (!interop_match_addr_or_name(INTEROP_ADV_PBAP_VER_1_2, &remote_addr, &btif_storage_get_remote_device_property)) { interop_database_add_addr(INTEROP_ADV_PBAP_VER_1_2, &remote_addr, 3); - SDP_TRACE_DEBUG("device: %s is added into interop list", - ADDRESS_TO_LOGGABLE_CSTR(remote_addr)); + LOG_VERBOSE("device: %s is added into interop list", + ADDRESS_TO_LOGGABLE_CSTR(remote_addr)); } else { - SDP_TRACE_WARNING("device: %s is already found on interop list", - ADDRESS_TO_LOGGABLE_CSTR(remote_addr)); + LOG_WARN("device: %s is already found on interop list", + ADDRESS_TO_LOGGABLE_CSTR(remote_addr)); } } @@ -1308,7 +1306,7 @@ bool is_sdp_pbap_pce_disabled(RawAddress remote_address) { if (interop_match_addr_or_name(INTEROP_DISABLE_PCE_SDP_AFTER_PAIRING, &remote_address, &btif_storage_get_remote_device_property)) { - SDP_TRACE_DEBUG("device is denylisted for PCE SDP "); + LOG_VERBOSE("device is denylisted for PCE SDP "); return true; } else { return false; @@ -1330,7 +1328,7 @@ void sdp_save_local_pse_record_attributes(int32_t rfcomm_channel_number, int32_t profile_version, uint32_t supported_features, uint32_t supported_repositories) { - SDP_TRACE_WARNING( + LOG_WARN( "rfcomm_channel_number: 0x%x, l2cap_psm: 0x%x profile_version: 0x%x" "supported_features: 0x%x supported_repositories: 0x%x", rfcomm_channel_number, l2cap_psm, profile_version, supported_features, diff --git a/system/stack/sdp/sdp_utils.cc b/system/stack/sdp/sdp_utils.cc index cd4e8293d79543bb7b94b6c2ff1738b6776221ca..0f494cf93c67029ec690ea76e6658565da4a9687 100644 --- a/system/stack/sdp/sdp_utils.cc +++ b/system/stack/sdp/sdp_utils.cc @@ -39,14 +39,17 @@ #include "btif/include/stack_manager.h" #include "common/init_flags.h" #include "device/include/interop.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/properties.h" #include "stack/include/avrc_api.h" #include "stack/include/avrc_defs.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/include/btm_api_types.h" -#include "stack/include/sdp_api.h" +#include "stack/include/btm_sec_api_types.h" #include "stack/include/sdpdefs.h" #include "stack/include/stack_metrics_logging.h" #include "stack/sdp/sdpint.h" @@ -54,6 +57,16 @@ #include "types/raw_address.h" using bluetooth::Uuid; + +bool SDP_FindProtocolListElemInRec(const tSDP_DISC_REC* p_rec, + uint16_t layer_uuid, + tSDP_PROTOCOL_ELEM* p_elem); +tSDP_DISC_ATTR* SDP_FindAttributeInRec(const tSDP_DISC_REC* p_rec, + uint16_t attr_id); +uint16_t SDP_GetDiRecord(uint8_t getRecordIndex, + tSDP_DI_GET_RECORD* device_info, + const tSDP_DISCOVERY_DB* p_db); + static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}; @@ -408,9 +421,9 @@ tCONN_CB* sdpu_allocate_ccb(void) { ******************************************************************************/ void sdpu_callback(tCONN_CB& ccb, tSDP_REASON reason) { if (ccb.p_cb) { - (ccb.p_cb)(reason); + (ccb.p_cb)(ccb.device_address, reason); } else if (ccb.p_cb2) { - (ccb.p_cb2)(reason, ccb.user_data); + (ccb.p_cb2)(ccb.device_address, reason, ccb.user_data); } } @@ -432,7 +445,7 @@ void sdpu_release_ccb(tCONN_CB& ccb) { ccb.is_attr_search = false; /* Free the response buffer */ - if (ccb.rsp_list) SDP_TRACE_DEBUG("releasing SDP rsp_list"); + if (ccb.rsp_list) LOG_VERBOSE("releasing SDP rsp_list"); osi_free_and_reset((void**)&ccb.rsp_list); } @@ -708,8 +721,8 @@ void sdpu_build_n_send_error(tCONN_CB* p_ccb, uint16_t trans_num, uint16_t rsp_param_len; BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); - SDP_TRACE_WARNING("SDP - sdpu_build_n_send_error code: 0x%x CID: 0x%x", - error_code, p_ccb->connection_id); + LOG_WARN("SDP - sdpu_build_n_send_error code: 0x%x CID: 0x%x", error_code, + p_ccb->connection_id); /* Send the packet to L2CAP */ p_buf->offset = L2CAP_MIN_OFFSET; @@ -1059,7 +1072,7 @@ bool sdpu_compare_uuid_arrays(const uint8_t* p_uuid1, uint32_t len1, if (((len1 != 2) && (len1 != 4) && (len1 != 16)) || ((len2 != 2) && (len2 != 4) && (len2 != 16))) { - SDP_TRACE_ERROR("%s: invalid length", __func__); + LOG_ERROR("%s: invalid length", __func__); return false; } @@ -1128,8 +1141,28 @@ bool sdpu_compare_uuid_arrays(const uint8_t* p_uuid1, uint32_t len1, ******************************************************************************/ bool sdpu_compare_uuid_with_attr(const Uuid& uuid, tSDP_DISC_ATTR* p_attr) { int len = uuid.GetShortestRepresentationSize(); - if (len == 2) return uuid.As16Bit() == p_attr->attr_value.v.u16; - if (len == 4) return uuid.As32Bit() == p_attr->attr_value.v.u32; + if (len == 2) { + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == Uuid::kNumBytes16) { + return uuid.As16Bit() == p_attr->attr_value.v.u16; + } else { + LOG_ERROR("invalid length for discovery attribute"); + return (false); + } + } + if (len == 4) { + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == Uuid::kNumBytes32) { + return uuid.As32Bit() == p_attr->attr_value.v.u32; + } else { + LOG_ERROR("invalid length for discovery attribute"); + return (false); + } + } + + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) != Uuid::kNumBytes128) { + LOG_ERROR("invalid length for discovery attribute"); + return (false); + } + if (memcmp(uuid.To128BitBE().data(), (void*)p_attr->attr_value.v.array, Uuid::kNumBytes128) == 0) return (true); @@ -1323,7 +1356,7 @@ uint8_t* sdpu_build_partial_attrib_entry(uint8_t* p_out, uint16_t attr_len = sdpu_get_attrib_entry_len(p_attr); if (len > SDP_MAX_ATTR_LEN) { - SDP_TRACE_ERROR("%s len %d exceeds SDP_MAX_ATTR_LEN", __func__, len); + LOG_ERROR("%s len %d exceeds SDP_MAX_ATTR_LEN", __func__, len); len = SDP_MAX_ATTR_LEN; } diff --git a/system/stack/sdp/sdpint.h b/system/stack/sdp/sdpint.h index 6f657708ea04fd025953049042643184dcbf4717..e643ba12fa96f90ccc1685cc54a38b174a020374 100644 --- a/system/stack/sdp/sdpint.h +++ b/system/stack/sdp/sdpint.h @@ -30,9 +30,12 @@ #include #include "bt_target.h" +#include "macros.h" #include "osi/include/alarm.h" #include "stack/include/bt_hdr.h" #include "stack/include/l2c_api.h" +#include "stack/include/sdp_callback.h" +#include "stack/sdp/sdp_discovery_db.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -133,12 +136,6 @@ enum : uint8_t { }; typedef uint8_t tSDP_STATE; -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string sdp_state_text(const tSDP_STATE& state) { switch (state) { CASE_RETURN_TEXT(SDP_STATE_IDLE); @@ -168,8 +165,6 @@ inline std::string sdp_flags_text(const tSDP_FLAGS& flags) { } } -#undef CASE_RETURN_TEXT - enum : uint8_t { SDP_DISC_WAIT_CONN = 0, SDP_DISC_WAIT_HANDLES = 1, @@ -218,12 +213,6 @@ struct tCONN_CB { tCONN_CB(const tCONN_CB&) = delete; }; -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif - inline std::string sdp_disc_wait_text(const tSDP_DISC_WAIT& state) { switch (state) { CASE_RETURN_TEXT(SDP_DISC_WAIT_CONN); @@ -236,8 +225,6 @@ inline std::string sdp_disc_wait_text(const tSDP_DISC_WAIT& state) { } } -#undef CASE_RETURN_TEXT - /* The main SDP control block */ typedef struct { tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */ @@ -246,7 +233,6 @@ typedef struct { tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */ uint16_t max_attr_list_size; /* Max attribute list size to use */ uint16_t max_recs_per_search; /* Max records we want per seaarch */ - uint8_t trace_level; } tSDP_CB; /* Global SDP data */ diff --git a/system/stack/smp/crypto_toolbox.h b/system/stack/smp/crypto_toolbox.h deleted file mode 100644 index 96f84ee50251d76a745d0fb3961bd27b87bc365d..0000000000000000000000000000000000000000 --- a/system/stack/smp/crypto_toolbox.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 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 "stack/include/bt_types.h" - -/* Functions below implement cryptographic toolbox, as described in BT Spec - * Ver 5.0 | Vol 3, Part H CRYPTOGRAPHIC TOOLBOX. Please see the spec for - * description. - * - * Example of usage is avaliable in cryptographic_toolbox_test.cc */ - -Octet16 smp_calculate_f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z); -uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, const Octet16& x, - const Octet16& y); -void smp_calculate_f5(uint8_t* w, const Octet16& n1, const Octet16& n2, - uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk); -Octet16 smp_calculate_f6(const Octet16& w, const Octet16& n1, const Octet16& n2, - const Octet16& r, uint8_t* iocap, uint8_t* a1, - uint8_t* a2); -Octet16 smp_calculate_h6(const Octet16& w, std::array keyid); -Octet16 smp_calculate_h7(const Octet16& salt, const Octet16& w); -Octet16 smp_calculate_ltk_to_link_key(const Octet16& ltk, bool use_h7); -Octet16 smp_calculate_link_key_to_ltk(const Octet16& link_key, bool use_h7); diff --git a/system/stack/smp/p_256_curvepara.cc b/system/stack/smp/p_256_curvepara.cc index ebdf2661bed29a9083fdae106e5718050bf11265..ad63b434b6b767233ada9d23393c55403de34897 100644 --- a/system/stack/smp/p_256_curvepara.cc +++ b/system/stack/smp/p_256_curvepara.cc @@ -22,7 +22,8 @@ * ******************************************************************************/ -#include +#include + #include "p_256_ecc_pp.h" void p_256_init_curve() { diff --git a/system/stack/smp/p_256_ecc_pp.cc b/system/stack/smp/p_256_ecc_pp.cc index cef368a17c00cf0f8d3f441d922115c96822fcb8..ec8616f4124d8f82c5de712a79034f0c8c2d4574 100644 --- a/system/stack/smp/p_256_ecc_pp.cc +++ b/system/stack/smp/p_256_ecc_pp.cc @@ -23,9 +23,10 @@ * ******************************************************************************/ #include "p_256_ecc_pp.h" -#include -#include -#include + +#include +#include + #include "p_256_multprecision.h" elliptic_curve_t curve; diff --git a/system/stack/smp/p_256_multprecision.cc b/system/stack/smp/p_256_multprecision.cc index 0310829cb280ca98fdafa221c677cee628649e71..e0d63e549da616e2504630b2bcbab5dc0d7fb2f7 100644 --- a/system/stack/smp/p_256_multprecision.cc +++ b/system/stack/smp/p_256_multprecision.cc @@ -23,8 +23,7 @@ ******************************************************************************/ #include "p_256_multprecision.h" -#include -#include "bt_target.h" + #include "p_256_ecc_pp.h" void multiprecision_init(uint32_t* c) { diff --git a/system/stack/smp/smp_act.cc b/system/stack/smp/smp_act.cc index 5748169072a985685933b0aa083ce93e16739483..b9f13c03d8abbb24b30f6e465e5b278ac62a3d1e 100644 --- a/system/stack/smp/smp_act.cc +++ b/system/stack/smp/smp_act.cc @@ -18,33 +18,34 @@ #define LOG_TAG "smp_act" -#include +#include -#include "btif/include/btif_api.h" #include "btif/include/btif_common.h" #include "btif/include/core_callbacks.h" #include "btif/include/stack_manager.h" +#include "crypto_toolbox/crypto_toolbox.h" #include "device/include/interop.h" #include "internal_include/bt_target.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" +#include "os/log.h" +#include "p_256_ecc_pp.h" +#include "smp_int.h" +#include "stack/btm/btm_ble_sec.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" -#include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_api.h" #include "stack/include/btm_log_history.h" -#include "stack/include/l2c_api.h" #include "stack/include/smp_api_types.h" -#include "stack/smp/p_256_ecc_pp.h" -#include "stack/smp/smp_int.h" #include "types/raw_address.h" -extern tBTM_CB btm_cb; - namespace { constexpr char kBtmLogTag[] = "SMP"; } +static void smp_key_distribution_by_transport(tSMP_CB* p_cb, + tSMP_INT_DATA* p_data); + #define SMP_KEY_DIST_TYPE_MAX 4 const tSMP_ACT smp_distribute_act[] = { @@ -72,9 +73,9 @@ static bool pts_test_send_authentication_complete_failure(tSMP_CB* p_cb) { * Description This function updates the key mask for sending or receiving. ******************************************************************************/ static void smp_update_key_mask(tSMP_CB* p_cb, uint8_t key_type, bool recv) { - SMP_TRACE_DEBUG( - "%s before update role=%d recv=%d local_i_key = %02x, local_r_key = %02x", - __func__, p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key); + LOG_VERBOSE( + "before update role=%d recv=%d local_i_key=0x%02x, local_r_key=0x%02x", + p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key); if (((p_cb->le_secure_connections_mode_is_used) || (p_cb->smp_over_br)) && ((key_type == SMP_SEC_KEY_TYPE_ENC) || @@ -95,8 +96,8 @@ static void smp_update_key_mask(tSMP_CB* p_cb, uint8_t key_type, bool recv) { p_cb->local_i_key &= ~key_type; } - SMP_TRACE_DEBUG("updated local_i_key = %02x, local_r_key = %02x", - p_cb->local_i_key, p_cb->local_r_key); + LOG_VERBOSE("updated local_i_key=0x%02x, local_r_key=0x%02x", + p_cb->local_i_key, p_cb->local_r_key); } /******************************************************************************* @@ -117,7 +118,7 @@ void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE; cb_data.io_req.init_keys = p_cb->local_i_key; cb_data.io_req.resp_keys = p_cb->local_r_key; - LOG_DEBUG("Notify app io_cap = %hhu", cb_data.io_req.io_cap); + LOG_DEBUG("Notify app io_cap=%hhu", cb_data.io_req.io_cap); break; case SMP_NC_REQ_EVT: @@ -168,14 +169,14 @@ void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { } LOG_DEBUG( - "Remote request IO capabilities precondition auth_req: 0x%02x," - " io_cap: %d loc_oob_flag: %d loc_enc_size: %d, " - "local_i_key: 0x%02x, local_r_key: 0x%02x", + "Remote request IO capabilities precondition auth_req:0x%02x," + " io_cap:%d loc_oob_flag:%d loc_enc_size:%d, " + "local_i_key:0x%02x, local_r_key:0x%02x", p_cb->loc_auth_req, p_cb->local_io_capability, p_cb->loc_oob_flag, p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key); p_cb->secure_connections_only_mode_required = - (btm_cb.security_mode == BTM_SEC_MODE_SC) ? true : false; + (p_cb->init_security_mode == BTM_SEC_MODE_SC) ? true : false; /* just for PTS, force SC bit */ if (p_cb->secure_connections_only_mode_required) { p_cb->loc_auth_req |= SMP_SC_SUPPORT_BIT; @@ -197,7 +198,7 @@ void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { (const RawAddress*)&p_cb->pairing_bda))) { LOG_DEBUG( "Setting SC, H7 and LinkKey bits to false to support " - "legacy device with lmp version: %d", + "legacy device with lmp version:%d", remote_lmp_version); p_cb->loc_auth_req &= ~SMP_SC_SUPPORT_BIT; p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT; @@ -211,8 +212,8 @@ void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { } LOG_DEBUG( - "Remote request IO capabilities postcondition auth_req: 0x%02x," - " local_i_key: 0x%02x, local_r_key: 0x%02x", + "Remote request IO capabilities postcondition auth_req:0x%02x," + " local_i_key:0x%02x, local_r_key:0x%02x", p_cb->loc_auth_req, p_cb->local_i_key, p_cb->local_r_key); smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL); @@ -228,8 +229,8 @@ void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; LOG_DEBUG( - "for SMP over BR max_key_size: 0x%02x, local_i_key: 0x%02x, " - "local_r_key: 0x%02x, p_cb->loc_auth_req: 0x%02x", + "for SMP over BR max_key_size:0x%02x, local_i_key:0x%02x, " + "local_r_key:0x%02x, p_cb->loc_auth_req:0x%02x", p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key, p_cb->loc_auth_req); @@ -244,7 +245,7 @@ void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { break; default: - LOG_ERROR("Unexpected event: %hhu", p_cb->cb_evt); + LOG_ERROR("Unexpected event:%hhu", p_cb->cb_evt); } } } @@ -281,7 +282,7 @@ void smp_send_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { ******************************************************************************/ void smp_send_pair_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda); - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); /* erase all keys when central sends pairing req*/ if (p_dev_rec) btm_sec_clear_ble_keys(p_dev_rec); @@ -295,7 +296,7 @@ void smp_send_pair_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description actions related to sending pairing response ******************************************************************************/ void smp_send_pair_rsp(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p_cb->local_i_key &= p_cb->peer_i_key; p_cb->local_r_key &= p_cb->peer_r_key; @@ -313,25 +314,16 @@ void smp_send_pair_rsp(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description send confirmation to the peer ******************************************************************************/ void smp_send_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb); } -/******************************************************************************* - * Function smp_send_init - * Description process pairing initializer to peripheral device - ******************************************************************************/ -void smp_send_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); - smp_send_cmd(SMP_OPCODE_INIT, p_cb); -} - /******************************************************************************* * Function smp_send_rand * Description send pairing random to the peer ******************************************************************************/ void smp_send_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_send_cmd(SMP_OPCODE_RAND, p_cb); } @@ -340,7 +332,7 @@ void smp_send_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description send pairing public key command to the peer ******************************************************************************/ void smp_send_pair_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_send_cmd(SMP_OPCODE_PAIR_PUBLIC_KEY, p_cb); } @@ -349,7 +341,7 @@ void smp_send_pair_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description send commitment command to the peer ******************************************************************************/ void smp_send_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_send_cmd(SMP_OPCODE_PAIR_COMMITM, p_cb); } @@ -358,7 +350,7 @@ void smp_send_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description send DHKey Check command to the peer ******************************************************************************/ void smp_send_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_send_cmd(SMP_OPCODE_PAIR_DHKEY_CHECK, p_cb); } @@ -376,8 +368,7 @@ void smp_send_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description send encryption information command. ******************************************************************************/ void smp_send_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - - SMP_TRACE_DEBUG("%s: p_cb->loc_enc_size = %d", __func__, p_cb->loc_enc_size); + LOG_VERBOSE("p_cb->loc_enc_size=%d", p_cb->loc_enc_size); smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ENC, false); smp_send_cmd(SMP_OPCODE_ENCRYPT_INFO, p_cb); @@ -397,9 +388,6 @@ void smp_send_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, &le_key, true); - - SMP_TRACE_WARNING("%s", __func__); - smp_key_distribution(p_cb, NULL); } @@ -408,7 +396,7 @@ void smp_send_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description send ID information command. ******************************************************************************/ void smp_send_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ID, false); smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb); @@ -423,16 +411,16 @@ void smp_send_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { /** send CSRK command. */ void smp_send_csrk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_CSRK, false); if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb)) { tBTM_LE_KEY_VALUE key = { .lcsrk_key = { + .counter = 0, /* initialize the local counter */ .div = p_cb->div, .sec_level = p_cb->sec_level, - .counter = 0, /* initialize the local counter */ .csrk = p_cb->csrk, }, }; @@ -447,7 +435,7 @@ void smp_send_csrk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description send LTK reply ******************************************************************************/ void smp_send_ltk_reply(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); Octet16 stk; memcpy(stk.data(), p_data->key.p_data, stk.size()); @@ -460,26 +448,33 @@ void smp_send_ltk_reply(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description process security request. ******************************************************************************/ void smp_proc_sec_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { + if (smp_command_has_invalid_length(p_cb)) { + tSMP_INT_DATA smp_int_data; + smp_int_data.status = SMP_INVALID_PARAMETERS; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); + return; + } + tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ*)p_data->p_data; tBTM_BLE_SEC_REQ_ACT sec_req_act; - SMP_TRACE_DEBUG("%s: auth_req=0x%x", __func__, auth_req); + LOG_VERBOSE("auth_req=0x%x", auth_req); p_cb->cb_evt = SMP_EVT_NONE; btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act); - SMP_TRACE_DEBUG("%s: sec_req_act=0x%x", __func__, sec_req_act); + LOG_VERBOSE("sec_req_act=0x%x", sec_req_act); switch (sec_req_act) { case BTM_BLE_SEC_REQ_ACT_ENCRYPT: - SMP_TRACE_DEBUG("%s: BTM_BLE_SEC_REQ_ACT_ENCRYPT", __func__); + LOG_VERBOSE("BTM_BLE_SEC_REQ_ACT_ENCRYPT"); smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); break; case BTM_BLE_SEC_REQ_ACT_PAIR: p_cb->secure_connections_only_mode_required = - (btm_cb.security_mode == BTM_SEC_MODE_SC) ? true : false; + (p_cb->init_security_mode == BTM_SEC_MODE_SC) ? true : false; /* respond to non SC pairing request as failure in SC only mode */ if (p_cb->secure_connections_only_mode_required && @@ -511,7 +506,7 @@ void smp_proc_sec_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { ******************************************************************************/ void smp_proc_sec_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t res = p_data->status; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (res != SMP_SUCCESS) { smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data); } else /*otherwise, start pairing */ @@ -526,11 +521,11 @@ void smp_proc_sec_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description process pairing failure from peer device ******************************************************************************/ void smp_proc_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->rcvd_cmd_len < 2) { - SMP_TRACE_WARNING("%s: rcvd_cmd_len %d too short: must be at least 2", - __func__, p_cb->rcvd_cmd_len); + LOG_WARN("rcvd_cmd_len %d too short: must be at least 2", + p_cb->rcvd_cmd_len); p_cb->status = SMP_INVALID_PARAMETERS; } else { p_cb->status = p_data->status; @@ -548,8 +543,7 @@ void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda); - SMP_TRACE_DEBUG("%s: pairing_bda=%s", __func__, - ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); + LOG_VERBOSE("pairing_bda=%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); /* erase all keys if it is peripheral proc pairing req */ if (p_dev_rec && (p_cb->role == HCI_ROLE_PERIPHERAL)) @@ -607,10 +601,8 @@ void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { (!(p_cb->le_secure_connections_mode_is_used) || (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { - SMP_TRACE_ERROR( - "%s: pairing failed - peripheral requires secure connection only " - "mode", - __func__); + LOG_ERROR( + "pairing failed - peripheral requires secure connection only mode"); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_PAIR_AUTH_FAIL; smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); @@ -630,7 +622,7 @@ void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { if (p_cb->secure_connections_only_mode_required && (!(p_cb->le_secure_connections_mode_is_used) || (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { - SMP_TRACE_ERROR( + LOG_ERROR( "Central requires secure connection only mode " "but it can't be provided -> Central fails pairing"); tSMP_INT_DATA smp_int_data; @@ -649,7 +641,7 @@ void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { /** process pairing confirm from peer device */ void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("pairing_bda=%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -669,23 +661,6 @@ void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM; } -/** process pairing initializer from peer device */ -void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - uint8_t* p = p_data->p_data; - - SMP_TRACE_DEBUG("%s", __func__); - - if (smp_command_has_invalid_parameters(p_cb)) { - tSMP_INT_DATA smp_int_data; - smp_int_data.status = SMP_INVALID_PARAMETERS; - smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); - return; - } - - /* save the SRand for comparison */ - STREAM_TO_ARRAY(p_cb->rrand.data(), p, OCTET16_LEN); -} - /******************************************************************************* * Function smp_proc_rand * Description process pairing random (nonce) from peer device @@ -693,7 +668,7 @@ void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_proc_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("pairing_bda=%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -717,7 +692,7 @@ void smp_proc_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_process_pairing_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -734,7 +709,7 @@ void smp_process_pairing_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { memcpy(pt.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN); if (!memcmp(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, BT_OCTET32_LEN)) { - SMP_TRACE_WARNING("Remote and local public keys can't match"); + LOG_WARN("Remote and local public keys can't match"); tSMP_INT_DATA smp; smp.status = SMP_PAIR_AUTH_FAIL; smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp); @@ -760,7 +735,7 @@ void smp_process_pairing_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_process_pairing_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -783,7 +758,7 @@ void smp_process_pairing_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_process_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -806,7 +781,7 @@ void smp_process_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_process_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p_cb->status = p_data->status; if (smp_command_has_invalid_parameters(p_cb)) { @@ -833,9 +808,9 @@ void smp_br_process_pairing_command(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda); - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); /* rejecting BR pairing request over non-SC BR link */ - if (!p_dev_rec->new_encryption_key_is_p256 && + if (!p_dev_rec->sec_rec.new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_PERIPHERAL) { tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_XTRANS_DERIVE_NOT_ALLOW; @@ -877,15 +852,14 @@ void smp_br_process_pairing_command(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { p_cb->local_r_key = p_cb->peer_r_key; if (p_cb->role == HCI_ROLE_PERIPHERAL) { - p_dev_rec->new_encryption_key_is_p256 = false; + p_dev_rec->sec_rec.new_encryption_key_is_p256 = false; /* shortcut to skip Security Grant step */ p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; } else { /* Central receives pairing response */ - SMP_TRACE_DEBUG( - "%s central rcvs valid PAIRING RESPONSE." - " Supposed to move to key distribution phase. ", - __func__); + LOG_VERBOSE( + "central rcvs valid PAIRING RESPONSE." + " Supposed to move to key distribution phase."); } /* auth_req received via BR/EDR SM channel is set to 0, @@ -899,7 +873,7 @@ void smp_br_process_pairing_command(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description process security grant in case of pairing over BR/EDR transport. ******************************************************************************/ void smp_br_process_security_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_data->status != SMP_SUCCESS) { smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, p_data); } else { @@ -914,8 +888,8 @@ void smp_br_process_security_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * before starting the distribution/derivation ******************************************************************************/ void smp_br_check_authorization_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s rcvs i_keys=0x%x r_keys=0x%x (i-initiator r-responder)", - __func__, p_cb->local_i_key, p_cb->local_r_key); + LOG_VERBOSE("rcvs i_keys=0x%x r_keys=0x%x (i-initiator r-responder)", + p_cb->local_i_key, p_cb->local_r_key); /* In LE SC mode LK field is ignored when BR/EDR transport is used */ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; @@ -932,11 +906,9 @@ void smp_br_check_authorization_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { (p_cb->peer_auth_req & SMP_H7_SUPPORT_BIT)) { p_cb->key_derivation_h7_used = TRUE; } - SMP_TRACE_DEBUG("%s: use h7 = %d", __func__, p_cb->key_derivation_h7_used); - - SMP_TRACE_DEBUG( - "%s rcvs upgrades: i_keys=0x%x r_keys=0x%x (i-initiator r-responder)", - __func__, p_cb->local_i_key, p_cb->local_r_key); + LOG_VERBOSE("use h7=%d, i_keys=0x%x r_keys=0x%x (i-initiator r-responder)", + p_cb->key_derivation_h7_used, p_cb->local_i_key, + p_cb->local_r_key); if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) || (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/ @@ -959,8 +931,8 @@ void smp_br_check_authorization_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * used. ******************************************************************************/ void smp_br_select_next_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s role=%d (0-central) r_keys=0x%x i_keys=0x%x", __func__, - p_cb->role, p_cb->local_r_key, p_cb->local_i_key); + LOG_VERBOSE("role=%d (0-central) r_keys=0x%x i_keys=0x%x", p_cb->role, + p_cb->local_r_key, p_cb->local_i_key); if (p_cb->role == HCI_ROLE_PERIPHERAL || (!p_cb->local_r_key && p_cb->role == HCI_ROLE_CENTRAL)) { @@ -985,7 +957,7 @@ void smp_br_select_next_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_proc_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -1003,11 +975,11 @@ void smp_proc_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_proc_central_id(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->rcvd_cmd_len < 11) { // 1(Code) + 2(EDIV) + 8(Rand) - SMP_TRACE_ERROR("%s: Invalid command length: %d, should be at least 11", - __func__, p_cb->rcvd_cmd_len); + LOG_ERROR("Invalid command length:%d, should be at least 11", + p_cb->rcvd_cmd_len); return; } @@ -1035,7 +1007,7 @@ void smp_proc_central_id(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_proc_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -1052,7 +1024,7 @@ void smp_proc_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_proc_id_addr(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { const uint8_t* p = p_data->p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -1088,8 +1060,7 @@ void smp_proc_id_addr(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { /* process security information from peer device */ void smp_proc_srk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_command_has_invalid_parameters(p_cb)) { tSMP_INT_DATA smp_int_data; @@ -1126,7 +1097,7 @@ void smp_proc_srk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description process compare value ******************************************************************************/ void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (!memcmp(p_cb->rconfirm.data(), p_data->key.p_data, OCTET16_LEN)) { /* compare the max encryption key size, and save the smaller one for the * link */ @@ -1158,7 +1129,7 @@ void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_proc_sl_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t key_type = p_data->key.key_type; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (key_type == SMP_KEY_TYPE_TK) { smp_generate_srand_mrand_confirm(p_cb, NULL); } else if (key_type == SMP_KEY_TYPE_CFM) { @@ -1176,7 +1147,7 @@ void smp_proc_sl_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_start_enc(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { tBTM_STATUS cmd; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_data != NULL) { cmd = btm_ble_start_encrypt(p_cb->pairing_bda, true, (Octet16*)p_data->key.p_data); @@ -1196,7 +1167,7 @@ void smp_start_enc(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description processing for discard security request ******************************************************************************/ void smp_proc_discard(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) smp_reset_control_value(p_cb); } @@ -1208,12 +1179,56 @@ void smp_proc_discard(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_enc_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t enc_enable = p_data->status; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); tSMP_INT_DATA smp_int_data; smp_int_data.status = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL; smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); } +/******************************************************************************* + * Function smp_sirk_verify + * Description verify if device belongs to csis group. + ******************************************************************************/ +void smp_sirk_verify(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { + tBTM_STATUS callback_rc; + LOG_DEBUG("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); + + if (p_data->status != SMP_SUCCESS) { + LOG_DEBUG( + "Cancel device verification due to invalid status(%d) while bonding.", + p_data->status); + + tSMP_INT_DATA smp_int_data; + smp_int_data.status = SMP_SIRK_DEVICE_INVALID; + + BTM_LogHistory( + kBtmLogTag, p_cb->pairing_bda, "SIRK verification", + base::StringPrintf("Verification failed, smp_status:%s", + smp_status_text(smp_int_data.status).c_str())); + + smp_sm_event(p_cb, SMP_SIRK_DEVICE_VALID_EVT, &smp_int_data); + + return; + } + + if (p_cb->p_callback) { + p_cb->cb_evt = SMP_SIRK_VERIFICATION_REQ_EVT; + callback_rc = (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, nullptr); + + /* There is no member validator callback - device is by default valid */ + if (callback_rc == BTM_SUCCESS_NO_SECURITY) { + BTM_LogHistory(kBtmLogTag, p_cb->pairing_bda, "SIRK verification", + base::StringPrintf("Device validated due to no security")); + + tSMP_INT_DATA smp_int_data; + smp_int_data.status = SMP_SUCCESS; + smp_sm_event(p_cb, SMP_SIRK_DEVICE_VALID_EVT, &smp_int_data); + } + } else { + LOG_ERROR("There are no registrated callbacks for SMP"); + } +} + /******************************************************************************* * Function smp_check_auth_req * Description check authentication request @@ -1221,9 +1236,9 @@ void smp_enc_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_check_auth_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t enc_enable = p_data->status; - SMP_TRACE_DEBUG( - "%s rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x (i-initiator r-responder)", - __func__, enc_enable, p_cb->local_i_key, p_cb->local_r_key); + LOG_VERBOSE( + "rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x (i-initiator r-responder)", + enc_enable, p_cb->local_i_key, p_cb->local_r_key); if (enc_enable == 1) { if (p_cb->le_secure_connections_mode_is_used) { /* In LE SC mode LTK is used instead of STK and has to be always saved */ @@ -1248,9 +1263,9 @@ void smp_check_auth_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; } - SMP_TRACE_DEBUG( - "%s rcvs upgrades: i_keys=0x%x r_keys=0x%x (i-initiator r-responder)", - __func__, p_cb->local_i_key, p_cb->local_r_key); + LOG_VERBOSE( + "rcvs upgrades:i_keys=0x%x r_keys=0x%x (i-initiator r-responder)", + p_cb->local_i_key, p_cb->local_r_key); if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) || (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/ @@ -1285,12 +1300,12 @@ void smp_key_pick_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { : p_cb->local_i_key; uint8_t i = 0; - SMP_TRACE_DEBUG("%s key_to_dist=0x%x", __func__, key_to_dist); + LOG_VERBOSE("key_to_dist=0x%x", key_to_dist); while (i < SMP_KEY_DIST_TYPE_MAX) { - SMP_TRACE_DEBUG("key to send = %02x, i = %d", key_to_dist, i); + LOG_VERBOSE("key to send=0x%02x, i=%d", key_to_dist, i); if (key_to_dist & (1 << i)) { - SMP_TRACE_DEBUG("smp_distribute_act[%d]", i); + LOG_VERBOSE("smp_distribute_act[%d]", i); (*smp_distribute_act[i])(p_cb, p_data); break; } @@ -1302,8 +1317,8 @@ void smp_key_pick_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description start key distribution if required. ******************************************************************************/ void smp_key_distribution(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s role=%d (0-central) r_keys=0x%x i_keys=0x%x", __func__, - p_cb->role, p_cb->local_r_key, p_cb->local_i_key); + LOG_VERBOSE("role=%d (0-central) r_keys=0x%x i_keys=0x%x", p_cb->role, + p_cb->local_r_key, p_cb->local_i_key); if (p_cb->role == HCI_ROLE_PERIPHERAL || (!p_cb->local_r_key && p_cb->role == HCI_ROLE_CENTRAL)) { @@ -1315,12 +1330,11 @@ void smp_key_distribution(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { if (smp_get_state() == SMP_STATE_BOND_PENDING) { if (p_cb->derive_lk) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda); - if (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) && - (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)) { - SMP_TRACE_DEBUG( - "%s BR key is higher security than existing LE keys, don't " - "derive LK from LTK", - __func__); + if (!(p_dev_rec->sec_rec.sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) && + (p_dev_rec->sec_rec.sec_flags & BTM_SEC_LINK_KEY_AUTHED)) { + LOG_VERBOSE( + "BR key is higher security than existing LE keys, don't " + "derive LK from LTK"); } else { smp_derive_link_key_from_long_term_key(p_cb, NULL); } @@ -1336,7 +1350,7 @@ void smp_key_distribution(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * state should remain in SMP_STATE_BOND_PENDING. */ if (!alarm_is_scheduled(p_cb->delayed_auth_timer_ent)) { - SMP_TRACE_DEBUG("%s delaying auth complete.", __func__); + LOG_VERBOSE("delaying auth complete"); alarm_set_on_mloop(p_cb->delayed_auth_timer_ent, SMP_DELAYED_AUTH_TIMEOUT_MS, smp_delayed_auth_complete_timeout, NULL); @@ -1358,16 +1372,14 @@ void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { tSMP_EVENT int_evt = SMP_NOP_EVT; tSMP_INT_DATA smp_int_data; - SMP_TRACE_DEBUG("%s Association Model = %d", __func__, - p_cb->selected_association_model); + LOG_VERBOSE("Association Model=%d", p_cb->selected_association_model); switch (p_cb->selected_association_model) { case SMP_MODEL_ENCRYPTION_ONLY: /* TK = 0, go calculate Confirm */ if (p_cb->role == HCI_ROLE_CENTRAL && ((p_cb->peer_auth_req & SMP_AUTH_YN_BIT) != 0) && ((p_cb->loc_auth_req & SMP_AUTH_YN_BIT) == 0)) { - SMP_TRACE_ERROR( - "IO capability does not meet authentication requirement"); + LOG_ERROR("IO capability does not meet authentication requirement"); smp_int_data.status = SMP_PAIR_AUTH_FAIL; int_evt = SMP_AUTH_CMPL_EVT; } else { @@ -1375,14 +1387,14 @@ void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { (p_cb->local_io_capability == SMP_IO_CAP_IO || p_cb->local_io_capability == SMP_IO_CAP_KBDISP)) { /* display consent dialog if this device has a display */ - SMP_TRACE_DEBUG("ENCRYPTION_ONLY showing Consent Dialog"); + LOG_VERBOSE("ENCRYPTION_ONLY showing Consent Dialog"); p_cb->cb_evt = SMP_CONSENT_REQ_EVT; smp_set_state(SMP_STATE_WAIT_NONCE); smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, NULL); } else { p_cb->sec_level = SMP_SEC_UNAUTHENTICATE; - SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ", - p_cb->sec_level); + LOG_VERBOSE("p_cb->sec_level=%d (SMP_SEC_UNAUTHENTICATE) ", + p_cb->sec_level); tSMP_KEY key; key.key_type = SMP_KEY_TYPE_TK; @@ -1398,18 +1410,18 @@ void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { case SMP_MODEL_PASSKEY: p_cb->sec_level = SMP_SEC_AUTHENTICATED; - SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", - p_cb->sec_level); + LOG_VERBOSE("p_cb->sec_level=%d(SMP_SEC_AUTHENTICATED) ", + p_cb->sec_level); p_cb->cb_evt = SMP_PASSKEY_REQ_EVT; int_evt = SMP_TK_REQ_EVT; break; case SMP_MODEL_OOB: - SMP_TRACE_ERROR("Association Model = SMP_MODEL_OOB"); + LOG_ERROR("Association Model=SMP_MODEL_OOB"); p_cb->sec_level = SMP_SEC_AUTHENTICATED; - SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", - p_cb->sec_level); + LOG_VERBOSE("p_cb->sec_level=%d(SMP_SEC_AUTHENTICATED) ", + p_cb->sec_level); p_cb->cb_evt = SMP_OOB_REQ_EVT; int_evt = SMP_TK_REQ_EVT; @@ -1417,7 +1429,7 @@ void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { case SMP_MODEL_KEY_NOTIF: p_cb->sec_level = SMP_SEC_AUTHENTICATED; - SMP_TRACE_DEBUG("Need to generate Passkey"); + LOG_VERBOSE("Need to generate Passkey"); /* generate passkey and notify application */ smp_generate_passkey(p_cb, NULL); @@ -1432,20 +1444,19 @@ void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { break; case SMP_MODEL_OUT_OF_RANGE: - SMP_TRACE_ERROR("Association Model = SMP_MODEL_OUT_OF_RANGE (failed)"); + LOG_ERROR("Association Model=SMP_MODEL_OUT_OF_RANGE (failed)"); smp_int_data.status = SMP_UNKNOWN_IO_CAP; int_evt = SMP_AUTH_CMPL_EVT; break; default: - SMP_TRACE_ERROR( - "Association Model = %d (SOMETHING IS WRONG WITH THE CODE)", - p_cb->selected_association_model); + LOG_ERROR("Association Model=%d (SOMETHING IS WRONG WITH THE CODE)", + p_cb->selected_association_model); smp_int_data.status = SMP_UNKNOWN_IO_CAP; int_evt = SMP_AUTH_CMPL_EVT; } - SMP_TRACE_EVENT("sec_level=%d ", p_cb->sec_level); + LOG_VERBOSE("sec_level=%d ", p_cb->sec_level); if (int_evt) smp_sm_event(p_cb, int_evt, &smp_int_data); } @@ -1454,7 +1465,7 @@ void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description process IO response for a peripheral device. ******************************************************************************/ void smp_process_io_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { /* pairing started by local (peripheral) Security Request */ smp_set_state(SMP_STATE_SEC_REQ_PENDING); @@ -1467,7 +1478,7 @@ void smp_process_io_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { if (p_cb->secure_connections_only_mode_required && (!(p_cb->le_secure_connections_mode_is_used) || (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { - SMP_TRACE_ERROR( + LOG_ERROR( "Peripheral requires secure connection only mode " "but it can't be provided -> Peripheral fails pairing"); tSMP_INT_DATA smp_int_data; @@ -1537,7 +1548,7 @@ void smp_br_process_peripheral_keys_response(tSMP_CB* p_cb, * transport. ******************************************************************************/ void smp_br_send_pair_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p_cb->local_i_key &= p_cb->peer_i_key; p_cb->local_r_key &= p_cb->peer_r_key; @@ -1563,7 +1574,7 @@ void smp_pairing_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * callback and remove the connection if needed. ******************************************************************************/ void smp_pair_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p_cb->status = SMP_CONN_TOUT; smp_proc_pairing_cmpl(p_cb); } @@ -1575,7 +1586,7 @@ void smp_pair_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { ******************************************************************************/ void smp_idle_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { - SMP_TRACE_DEBUG("Pairing terminated at IDLE state."); + LOG_VERBOSE("Pairing terminated at IDLE state."); p_cb->status = SMP_FAIL; smp_proc_pairing_cmpl(p_cb); } @@ -1592,7 +1603,7 @@ void smp_idle_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * - invokes SC phase 1 process. ******************************************************************************/ void smp_both_have_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); /* invokes DHKey computation */ smp_compute_dhkey(p_cb); @@ -1611,16 +1622,15 @@ void smp_both_have_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * model. ******************************************************************************/ void smp_start_secure_connection_phase1(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) { p_cb->sec_level = SMP_SEC_UNAUTHENTICATE; - SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ", - p_cb->sec_level); + LOG_VERBOSE("p_cb->sec_level=%d (SMP_SEC_UNAUTHENTICATE) ", + p_cb->sec_level); } else { p_cb->sec_level = SMP_SEC_AUTHENTICATED; - SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", - p_cb->sec_level); + LOG_VERBOSE("p_cb->sec_level=%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level); } switch (p_cb->selected_association_model) { @@ -1636,7 +1646,7 @@ void smp_start_secure_connection_phase1(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { break; case SMP_MODEL_SEC_CONN_PASSKEY_DISP: /* passkey has to be provided to user */ - SMP_TRACE_DEBUG("Need to generate SC Passkey"); + LOG_VERBOSE("Need to generate SC Passkey"); smp_generate_passkey(p_cb, NULL); break; case SMP_MODEL_SEC_CONN_OOB: @@ -1644,8 +1654,8 @@ void smp_start_secure_connection_phase1(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { smp_process_secure_connection_oob_data(p_cb, NULL); break; default: - SMP_TRACE_ERROR("Association Model = %d is not used in LE SC", - p_cb->selected_association_model); + LOG_ERROR("Association Model=%d is not used in LE SC", + p_cb->selected_association_model); break; } } @@ -1657,7 +1667,7 @@ void smp_start_secure_connection_phase1(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Note It is supposed to be called in SC phase1. ******************************************************************************/ void smp_process_local_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); switch (p_cb->selected_association_model) { case SMP_MODEL_SEC_CONN_JUSTWORKS: @@ -1673,8 +1683,8 @@ void smp_process_local_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) { /* peripheral commitment is already received, send local nonce, wait * for remote nonce*/ - SMP_TRACE_DEBUG( - "central in assoc mode = %d " + LOG_VERBOSE( + "central in assoc mode=%d " "already rcvd peripheral commitment - race condition", p_cb->selected_association_model); p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM; @@ -1706,8 +1716,8 @@ void smp_process_local_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { smp_set_state(SMP_STATE_WAIT_NONCE); break; default: - SMP_TRACE_ERROR("Association Model = %d is not used in LE SC", - p_cb->selected_association_model); + LOG_ERROR("Association Model=%d is not used in LE SC", + p_cb->selected_association_model); break; } } @@ -1721,11 +1731,13 @@ void smp_process_local_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Note It is supposed to be called in SC phase1. ******************************************************************************/ void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s start ", __func__); + LOG_VERBOSE("addr:%s, selected_association_model:%d", + ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda), + p_cb->selected_association_model); // PTS Testing failure modes if (p_cb->cert_failure == SMP_CONFIRM_VALUE_ERR) { - SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure); + LOG_ERROR("failure case=%d", p_cb->cert_failure); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_CONFIRM_VALUE_ERR; p_cb->failure = SMP_CONFIRM_VALUE_ERR; @@ -1736,7 +1748,7 @@ void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { if ((p_cb->cert_failure == SMP_NUMERIC_COMPAR_FAIL) && (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) && (p_cb->role == HCI_ROLE_PERIPHERAL)) { - SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure); + LOG_ERROR("failure case=%d", p_cb->cert_failure); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_NUMERIC_COMPAR_FAIL; p_cb->failure = SMP_NUMERIC_COMPAR_FAIL; @@ -1766,7 +1778,7 @@ void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { (p_cb->local_io_capability == SMP_IO_CAP_IO || p_cb->local_io_capability == SMP_IO_CAP_KBDISP)) { /* display consent dialog */ - SMP_TRACE_DEBUG("JUST WORKS showing Consent Dialog"); + LOG_VERBOSE("JUST WORKS showing Consent Dialog"); p_cb->cb_evt = SMP_CONSENT_REQ_EVT; smp_set_state(SMP_STATE_WAIT_NONCE); smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, NULL); @@ -1812,12 +1824,10 @@ void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); break; default: - SMP_TRACE_ERROR("Association Model = %d is not used in LE SC", - p_cb->selected_association_model); + LOG_ERROR("Association Model=%d is not used in LE SC", + p_cb->selected_association_model); break; } - - SMP_TRACE_DEBUG("%s end ", __func__); } /******************************************************************************* @@ -1826,11 +1836,11 @@ void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * received from the peer DHKey check value. ******************************************************************************/ void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check.data(), OCTET16_LEN)) { - SMP_TRACE_WARNING("dhkey chcks do no match"); + LOG_WARN("dhkey chcks do no match"); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_DHKEY_CHK_FAIL; p_cb->failure = SMP_DHKEY_CHK_FAIL; @@ -1838,8 +1848,6 @@ void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { return; } - SMP_TRACE_EVENT("dhkey chcks match"); - /* compare the max encryption key size, and save the smaller one for the link */ if (p_cb->peer_enc_size < p_cb->loc_enc_size) @@ -1864,7 +1872,7 @@ void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { ******************************************************************************/ void smp_move_to_secure_connections_phase2(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); } @@ -1879,7 +1887,7 @@ void smp_move_to_secure_connections_phase2(tSMP_CB* p_cb, ******************************************************************************/ void smp_phase_2_dhkey_checks_are_present(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK) smp_sm_event(p_cb, SMP_SC_2_DHCK_CHKS_PRES_EVT, NULL); @@ -1894,7 +1902,7 @@ void smp_phase_2_dhkey_checks_are_present(tSMP_CB* p_cb, * ******************************************************************************/ void smp_wait_for_both_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if ((p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY) && (p_cb->flags & SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY)) { @@ -1914,7 +1922,7 @@ void smp_wait_for_both_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { void smp_start_passkey_verification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t* p = NULL; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = p_cb->local_random.data(); UINT32_TO_STREAM(p, p_data->passkey); @@ -1931,18 +1939,18 @@ void smp_start_passkey_verification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { ******************************************************************************/ void smp_process_secure_connection_oob_data(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); tSMP_SC_OOB_DATA* p_sc_oob_data = &p_cb->sc_oob_data; if (p_sc_oob_data->loc_oob_data.present) { p_cb->local_random = p_sc_oob_data->loc_oob_data.randomizer; } else { - SMP_TRACE_EVENT("%s: local OOB randomizer is absent", __func__); + LOG_VERBOSE("local OOB randomizer is absent"); p_cb->local_random = {0}; } if (!p_sc_oob_data->peer_oob_data.present) { - SMP_TRACE_EVENT("%s: peer OOB data is absent", __func__); + LOG_VERBOSE("peer OOB data is absent"); p_cb->peer_random = {0}; } else { p_cb->peer_random = p_sc_oob_data->peer_oob_data.randomizer; @@ -1959,9 +1967,8 @@ void smp_process_secure_connection_oob_data(tSMP_CB* p_cb, if (p_cb->peer_oob_flag != SMP_OOB_PRESENT) { /* the peer doesn't have local randomiser */ - SMP_TRACE_EVENT( - "%s: peer didn't receive local OOB data, set local randomizer to 0", - __func__); + LOG_VERBOSE( + "peer didn't receive local OOB data, set local randomizer to 0"); p_cb->local_random = {0}; } } @@ -1978,7 +1985,7 @@ void smp_process_secure_connection_oob_data(tSMP_CB* p_cb, * (to be saved in sc_oob_data.loc_oob_data.randomizer). ******************************************************************************/ void smp_set_local_oob_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); memcpy(p_cb->sc_oob_data.loc_oob_data.private_key_used, p_cb->private_key, BT_OCTET32_LEN); @@ -1993,7 +2000,7 @@ void smp_set_local_oob_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * for safekeeping. ******************************************************************************/ void smp_set_local_oob_random_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p_cb->sc_oob_data.loc_oob_data.randomizer = p_cb->rand; p_cb->sc_oob_data.loc_oob_data.commitment = @@ -2016,7 +2023,7 @@ void smp_set_local_oob_random_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { // connector will fail commitment check and dhkey exchange. smp_save_local_oob_data(p_cb); - smp_cb_cleanup(p_cb); + p_cb->reset(); } /******************************************************************************* @@ -2059,7 +2066,7 @@ void smp_link_encrypted(const RawAddress& bda, uint8_t encr_enable) { } void smp_cancel_start_encryption_attempt() { - SMP_TRACE_ERROR("%s: Encryption request cancelled", __func__); + LOG_ERROR("Encryption request cancelled"); smp_sm_event(&smp_cb, SMP_DISCARD_SEC_REQ_EVT, NULL); } @@ -2074,7 +2081,7 @@ void smp_cancel_start_encryption_attempt() { * ******************************************************************************/ bool smp_proc_ltk_request(const RawAddress& bda) { - SMP_TRACE_DEBUG("%s state = %d", __func__, smp_cb.state); + LOG_VERBOSE("addr:%s,state=%d", ADDRESS_TO_LOGGABLE_CSTR(bda), smp_cb.state); bool match = false; if (bda == smp_cb.pairing_bda) { @@ -2109,7 +2116,7 @@ bool smp_proc_ltk_request(const RawAddress& bda) { void smp_process_secure_connection_long_term_key(void) { tSMP_CB* p_cb = &smp_cb; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_save_secure_connections_long_term_key(p_cb); smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ENC, false); @@ -2128,7 +2135,7 @@ void smp_process_secure_connection_long_term_key(void) { * ******************************************************************************/ void smp_set_derive_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p_cb->derive_lk = true; smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_LK, false); smp_key_distribution(p_cb, NULL); @@ -2147,9 +2154,9 @@ void smp_derive_link_key_from_long_term_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (!smp_calculate_link_key_from_long_term_key(p_cb)) { - SMP_TRACE_ERROR("%s failed", __func__); + LOG_ERROR("calc link key failed"); tSMP_INT_DATA smp_int_data; smp_int_data.status = status; smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); @@ -2171,9 +2178,9 @@ void smp_derive_link_key_from_long_term_key(tSMP_CB* p_cb, void smp_br_process_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (!smp_calculate_long_term_key_from_link_key(p_cb)) { - SMP_TRACE_ERROR("%s: failed", __func__); + LOG_ERROR("calc LTK failed"); tSMP_INT_DATA smp_int_data; smp_int_data.status = status; smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data); @@ -2182,14 +2189,13 @@ void smp_br_process_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda); if (p_dev_rec) { - SMP_TRACE_DEBUG("%s: dev_type = %d ", __func__, p_dev_rec->device_type); + LOG_VERBOSE("dev_type=%d ", p_dev_rec->device_type); p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE; } else { - SMP_TRACE_ERROR("%s failed to find Security Record", __func__); + LOG_ERROR("failed to find Security Record"); } - SMP_TRACE_DEBUG("%s: LTK derivation from LK successfully completed", - __func__); + LOG_VERBOSE("LTK derivation from LK successfully completed"); smp_save_secure_connections_long_term_key(p_cb); smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ENC, false); smp_br_select_next_key(p_cb, NULL); @@ -2200,8 +2206,9 @@ void smp_br_process_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * Description depending on the transport used at the moment calls either * smp_key_distribution(...) or smp_br_key_distribution(...). ******************************************************************************/ -void smp_key_distribution_by_transport(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); +static void smp_key_distribution_by_transport(tSMP_CB* p_cb, + tSMP_INT_DATA* p_data) { + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->smp_over_br) { smp_br_select_next_key(p_cb, NULL); } else { @@ -2215,7 +2222,7 @@ void smp_key_distribution_by_transport(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * callback and remove the connection if needed. ******************************************************************************/ void smp_br_pairing_complete(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->total_tx_unacked == 0) { /* process the pairing complete */ diff --git a/system/stack/smp/smp_api.cc b/system/stack/smp/smp_api.cc index ace84db810737a575f1b075d92115391798b092b..606cc1f60429d98538cd234e9fab501628def76b 100644 --- a/system/stack/smp/smp_api.cc +++ b/system/stack/smp/smp_api.cc @@ -22,22 +22,18 @@ * applications that can run over an SMP. * ******************************************************************************/ +#define LOG_TAG "smp" + #include "smp_api.h" -#include #include -#include "bt_target.h" -#include "gd/os/log.h" -#include "gd/os/rand.h" #include "l2c_api.h" #include "l2cdefs.h" -#include "main/shim/shim.h" -#include "p_256_ecc_pp.h" +#include "os/log.h" #include "smp_int.h" -#include "stack/btm/btm_dev.h" #include "stack/include/bt_octets.h" -#include "stack_config.h" +#include "stack/include/btm_sec_api_types.h" #include "types/raw_address.h" /******************************************************************************* @@ -49,60 +45,7 @@ * Returns void * ******************************************************************************/ -void SMP_Init(void) { - if (bluetooth::shim::is_gd_shim_enabled()) { - LOG(INFO) << "Skipping legacy SMP_Init because GD is enabled"; - return; - } - - memset(&smp_cb, 0, sizeof(tSMP_CB)); - smp_cb.smp_rsp_timer_ent = alarm_new("smp.smp_rsp_timer_ent"); - smp_cb.delayed_auth_timer_ent = alarm_new("smp.delayed_auth_timer_ent"); - -#if defined(SMP_INITIAL_TRACE_LEVEL) - smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL; -#else - smp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ -#endif - SMP_TRACE_EVENT("%s", __func__); - - smp_l2cap_if_init(); - /* initialization of P-256 parameters */ - p_256_init_curve(); - - /* Initialize failure case for certification */ - smp_cb.cert_failure = static_cast( - stack_config_get_interface()->get_pts_smp_failure_case()); - if (smp_cb.cert_failure) - SMP_TRACE_ERROR("%s PTS FAILURE MODE IN EFFECT (CASE %d)", __func__, - smp_cb.cert_failure); -} - -/******************************************************************************* - * - * Function SMP_SetTraceLevel - * - * Description This function sets the trace level for SMP. If called with - * a value of 0xFF, it simply returns the current trace level. - * - * Input Parameters: - * level: The level to set the GATT tracing to: - * 0xff-returns the current setting. - * 0-turns off tracing. - * >= 1-Errors. - * >= 2-Warnings. - * >= 3-APIs. - * >= 4-Events. - * >= 5-Debug. - * - * Returns The new or current trace level - * - ******************************************************************************/ -uint8_t SMP_SetTraceLevel(uint8_t new_level) { - if (new_level != 0xFF) smp_cb.trace_level = new_level; - - return (smp_cb.trace_level); -} +void SMP_Init(uint8_t init_security_mode) { smp_cb.init(init_security_mode); } /******************************************************************************* * @@ -114,13 +57,10 @@ uint8_t SMP_SetTraceLevel(uint8_t new_level) { * ******************************************************************************/ bool SMP_Register(tSMP_CALLBACK* p_cback) { - LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled()) - << "Legacy SMP API should not be invoked when GD Security is used"; - - SMP_TRACE_EVENT("SMP_Register state=%d", smp_cb.state); + LOG_VERBOSE("state=%d", smp_cb.state); if (smp_cb.p_callback != NULL) { - SMP_TRACE_ERROR("SMP_Register: duplicate registration, overwrite it"); + LOG_ERROR("duplicate registration, overwrite it"); } smp_cb.p_callback = p_cback; @@ -140,13 +80,10 @@ bool SMP_Register(tSMP_CALLBACK* p_cback) { * ******************************************************************************/ tSMP_STATUS SMP_Pair(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) { - LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled()) - << "Legacy SMP API should not be invoked when GD Security is used"; tSMP_CB* p_cb = &smp_cb; - SMP_TRACE_EVENT("%s: state=%d br_state=%d flag=0x%x, bd_addr=%s", __func__, - p_cb->state, p_cb->br_state, p_cb->flags, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("state=%d br_state=%d flag=0x%x, bd_addr=%s", p_cb->state, + p_cb->br_state, p_cb->flags, ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); if (p_cb->state != SMP_STATE_IDLE || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD || p_cb->smp_over_br) { @@ -164,7 +101,7 @@ tSMP_STATUS SMP_Pair(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) { tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_PAIR_INTERNAL_ERR; p_cb->status = SMP_PAIR_INTERNAL_ERR; - SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __func__); + LOG_ERROR("L2C connect fixed channel failed."); smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); return SMP_PAIR_INTERNAL_ERR; } @@ -191,14 +128,10 @@ tSMP_STATUS SMP_Pair(const RawAddress& bd_addr) { * ******************************************************************************/ tSMP_STATUS SMP_BR_PairWith(const RawAddress& bd_addr) { - LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled()) - << "Legacy SMP API should not be invoked when GD Security is used"; - tSMP_CB* p_cb = &smp_cb; - SMP_TRACE_EVENT("%s: state=%d br_state=%d flag=0x%x, bd_addr=%s", __func__, - p_cb->state, p_cb->br_state, p_cb->flags, - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_VERBOSE("state=%d br_state=%d flag=0x%x, bd_addr=%s", p_cb->state, + p_cb->br_state, p_cb->flags, ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); if (p_cb->state != SMP_STATE_IDLE || p_cb->smp_over_br || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { @@ -212,7 +145,7 @@ tSMP_STATUS SMP_BR_PairWith(const RawAddress& bd_addr) { p_cb->pairing_bda = bd_addr; if (!L2CA_ConnectFixedChnl(L2CAP_SMP_BR_CID, bd_addr)) { - SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __func__); + LOG_ERROR("L2C connect fixed channel failed."); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_PAIR_INTERNAL_ERR; p_cb->status = SMP_PAIR_INTERNAL_ERR; @@ -235,16 +168,12 @@ tSMP_STATUS SMP_BR_PairWith(const RawAddress& bd_addr) { * ******************************************************************************/ bool SMP_PairCancel(const RawAddress& bd_addr) { - LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled()) - << "Legacy SMP API should not be invoked when GD Security is used"; - tSMP_CB* p_cb = &smp_cb; - SMP_TRACE_EVENT("SMP_CancelPair state=%d flag=0x%x ", p_cb->state, - p_cb->flags); + LOG_VERBOSE("state=%d flag=0x%x ", p_cb->state, p_cb->flags); if (p_cb->state != SMP_STATE_IDLE && p_cb->pairing_bda == bd_addr) { p_cb->is_pair_cancel = true; - SMP_TRACE_DEBUG("Cancel Pairing: set fail reason Unknown"); + LOG_VERBOSE("set fail reason Unknown"); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN; smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); @@ -268,10 +197,7 @@ bool SMP_PairCancel(const RawAddress& bd_addr) { * ******************************************************************************/ void SMP_SecurityGrant(const RawAddress& bd_addr, tSMP_STATUS res) { - LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled()) - << "Legacy SMP API should not be invoked when GD Security is used"; - - SMP_TRACE_EVENT("SMP_SecurityGrant "); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); // If just showing consent dialog, send response if (smp_cb.cb_evt == SMP_CONSENT_REQ_EVT) { @@ -280,8 +206,7 @@ void SMP_SecurityGrant(const RawAddress& bd_addr, tSMP_STATUS res) { if (res == SMP_SUCCESS) { smp_sm_event(&smp_cb, SMP_SC_NC_OK_EVT, NULL); } else { - SMP_TRACE_WARNING("%s() - Consent dialog fails for JUSTWORKS", - __func__); + LOG_WARN("Consent dialog fails for JUSTWORKS"); /* send pairing failure */ tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_NUMERIC_COMPAR_FAIL; @@ -300,8 +225,7 @@ void SMP_SecurityGrant(const RawAddress& bd_addr, tSMP_STATUS res) { smp_cb.tk = {0}; smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &smp_int_data); } else { - SMP_TRACE_WARNING("%s() - Consent dialog fails for ENCRYPTION_ONLY", - __func__); + LOG_WARN("Consent dialog fails for ENCRYPTION_ONLY"); /* send pairing failure */ tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_NUMERIC_COMPAR_FAIL; @@ -355,33 +279,23 @@ void SMP_SecurityGrant(const RawAddress& bd_addr, tSMP_STATUS res) { ******************************************************************************/ void SMP_PasskeyReply(const RawAddress& bd_addr, uint8_t res, uint32_t passkey) { - LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled()) - << "Legacy SMP API should not be invoked when GD Security is used"; - tSMP_CB* p_cb = &smp_cb; - SMP_TRACE_EVENT("SMP_PasskeyReply: Key: %d Result:%d", passkey, res); + LOG_VERBOSE("Key:%d Result:%d", passkey, res); /* If timeout already expired or has been canceled, ignore the reply */ if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT) { - SMP_TRACE_WARNING("SMP_PasskeyReply() - Wrong State: %d", p_cb->state); + LOG_WARN("Wrong State:%d", p_cb->state); return; } if (bd_addr != p_cb->pairing_bda) { - SMP_TRACE_ERROR("SMP_PasskeyReply() - Wrong BD Addr"); - return; - } - - if (btm_find_dev(bd_addr) == NULL) { - SMP_TRACE_ERROR("SMP_PasskeyReply() - no dev CB"); + LOG_ERROR("Wrong BD Addr"); return; } if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS) { - SMP_TRACE_WARNING( - "SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail", - passkey); + LOG_WARN("Wrong key len:%d or passkey entry fail", passkey); /* send pairing failure */ tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_PASSKEY_ENTRY_FAIL; @@ -412,31 +326,23 @@ void SMP_PasskeyReply(const RawAddress& bd_addr, uint8_t res, * ******************************************************************************/ void SMP_ConfirmReply(const RawAddress& bd_addr, uint8_t res) { - LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled()) - << "Legacy SMP API should not be invoked when GD Security is used"; - tSMP_CB* p_cb = &smp_cb; - SMP_TRACE_EVENT("%s: Result:%d", __func__, res); + LOG_VERBOSE("addr:%s, Result:%d", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), res); /* If timeout already expired or has been canceled, ignore the reply */ if (p_cb->cb_evt != SMP_NC_REQ_EVT) { - SMP_TRACE_WARNING("%s() - Wrong State: %d", __func__, p_cb->state); + LOG_WARN("Wrong State:%d", p_cb->state); return; } if (bd_addr != p_cb->pairing_bda) { - SMP_TRACE_ERROR("%s() - Wrong BD Addr", __func__); - return; - } - - if (btm_find_dev(bd_addr) == NULL) { - SMP_TRACE_ERROR("%s() - no dev CB", __func__); + LOG_ERROR("Wrong BD Addr"); return; } if (res != SMP_SUCCESS) { - SMP_TRACE_WARNING("%s() - Numeric Comparison fails", __func__); + LOG_WARN("Numeric Comparison fails"); /* send pairing failure */ tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_NUMERIC_COMPAR_FAIL; @@ -460,13 +366,10 @@ void SMP_ConfirmReply(const RawAddress& bd_addr, uint8_t res) { ******************************************************************************/ void SMP_OobDataReply(const RawAddress& bd_addr, tSMP_STATUS res, uint8_t len, uint8_t* p_data) { - LOG_ASSERT(!bluetooth::shim::is_gd_shim_enabled()) - << "Legacy SMP API should not be invoked when GD Security is used"; - tSMP_CB* p_cb = &smp_cb; tSMP_KEY key; - SMP_TRACE_EVENT("%s State: %d res:%d", __func__, smp_cb.state, res); + LOG_VERBOSE("State:%d res:%d", smp_cb.state, res); /* If timeout already expired or has been canceled, ignore the reply */ if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_OOB_REQ_EVT) @@ -505,17 +408,17 @@ void SMP_SecureConnectionOobDataReply(uint8_t* p_data) { tSMP_SC_OOB_DATA* p_oob = (tSMP_SC_OOB_DATA*)p_data; if (!p_oob) { - SMP_TRACE_ERROR("%s received no data", __func__); + LOG_ERROR("received no data"); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_OOB_FAIL; smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); return; } - SMP_TRACE_EVENT( - "%s req_oob_type: %d, loc_oob_data.present: %d, " - "peer_oob_data.present: %d", - __func__, p_cb->req_oob_type, p_oob->loc_oob_data.present, + LOG_VERBOSE( + "req_oob_type:%d, loc_oob_data.present:%d, " + "peer_oob_data.present:%d", + p_cb->req_oob_type, p_oob->loc_oob_data.present, p_oob->peer_oob_data.present); if (p_cb->state != SMP_STATE_WAIT_APP_RSP || @@ -541,7 +444,7 @@ void SMP_SecureConnectionOobDataReply(uint8_t* p_data) { data_missing = true; break; default: - SMP_TRACE_EVENT("Unexpected OOB data type requested. Fail OOB"); + LOG_VERBOSE("Unexpected OOB data type requested. Fail OOB"); data_missing = true; break; } @@ -583,3 +486,45 @@ bool SMP_CrLocScOobData() { * ******************************************************************************/ void SMP_ClearLocScOobData() { smp_clear_local_oob_data(); } + +/******************************************************************************* + * + * Function SMP_SirkConfirmDeviceReply + * + * Description This function is called after Security Manager submitted + * verification of device with CSIP. + * + * Parameters: bd_addr - Address of the device with which verification + * was requested + * res - comparison result SMP_SUCCESS if success + * + ******************************************************************************/ +void SMP_SirkConfirmDeviceReply(const RawAddress& bd_addr, uint8_t res) { + tSMP_CB* p_cb = &smp_cb; + + LOG_INFO("Result:%d", res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (p_cb->cb_evt != SMP_SIRK_VERIFICATION_REQ_EVT) { + LOG_WARN("Wrong State:%d", p_cb->state); + return; + } + + if (bd_addr != p_cb->pairing_bda) { + LOG_WARN("Wrong confirmation BD Addr: %s vs expected %s", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); + return; + } + + tSMP_INT_DATA smp_int_data; + if (res != SMP_SUCCESS) { + LOG_WARN("Verification fails"); + /* send pairing failure */ + smp_int_data.status = SMP_SIRK_DEVICE_INVALID; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); + } else { + smp_int_data.status = SMP_SUCCESS; + smp_sm_event(p_cb, SMP_SIRK_DEVICE_VALID_EVT, &smp_int_data); + } +} diff --git a/system/stack/smp/smp_br_main.cc b/system/stack/smp/smp_br_main.cc index d108539342c537d5a756a05217352f53d81778ab..24a84ab350e72d0b777f32d576ff0155e3773c06 100644 --- a/system/stack/smp/smp_br_main.cc +++ b/system/stack/smp/smp_br_main.cc @@ -16,11 +16,9 @@ * ******************************************************************************/ -#include "bt_target.h" +#define LOG_TAG "smp" -#include - -#include "osi/include/log.h" +#include "os/log.h" #include "smp_int.h" #include "types/hci_role.h" @@ -248,12 +246,12 @@ static const tSMP_BR_ENTRY_TBL smp_br_entry_table[] = { ******************************************************************************/ void smp_set_br_state(tSMP_BR_STATE br_state) { if (br_state < SMP_BR_STATE_MAX) { - SMP_TRACE_DEBUG("BR_State change: %s(%d) ==> %s(%d)", - smp_get_br_state_name(smp_cb.br_state), smp_cb.br_state, - smp_get_br_state_name(br_state), br_state); + LOG_VERBOSE("BR_State change:%s(%d)==>%s(%d)", + smp_get_br_state_name(smp_cb.br_state), smp_cb.br_state, + smp_get_br_state_name(br_state), br_state); smp_cb.br_state = br_state; } else { - SMP_TRACE_DEBUG("%s invalid br_state =%d", __func__, br_state); + LOG_VERBOSE("invalid br_state=%d", br_state); } } @@ -307,24 +305,23 @@ void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event, tSMP_BR_SM_TBL state_table; uint8_t action, entry; - SMP_TRACE_EVENT("main %s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (curr_state >= SMP_BR_STATE_MAX) { - SMP_TRACE_DEBUG("Invalid br_state: %d", curr_state); + LOG_VERBOSE("Invalid br_state: %d", curr_state); return; } if (p_cb->role > HCI_ROLE_PERIPHERAL) { - SMP_TRACE_ERROR("%s: invalid role %d", __func__, p_cb->role); + LOG_ERROR("invalid role %d", p_cb->role); return; } tSMP_BR_ENTRY_TBL entry_table = smp_br_entry_table[p_cb->role]; - SMP_TRACE_DEBUG( - "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]", - (p_cb->role == HCI_ROLE_PERIPHERAL) ? "Peripheral" : "Central", - smp_get_br_state_name(p_cb->br_state), p_cb->br_state, - smp_get_br_event_name(event), event); + LOG_VERBOSE("SMP Role:%s State:[%s(%d)], Event:[%s(%d)]", + (p_cb->role == HCI_ROLE_PERIPHERAL) ? "Peripheral" : "Central", + smp_get_br_state_name(p_cb->br_state), p_cb->br_state, + smp_get_br_event_name(event), event); /* look up the state table for the current state */ /* lookup entry / w event & curr_state */ @@ -339,9 +336,9 @@ void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event, state_table = smp_br_state_table[curr_state][p_cb->role]; } } else { - SMP_TRACE_DEBUG("Ignore event [%s (%d)] in state [%s (%d)]", - smp_get_br_event_name(event), event, - smp_get_br_state_name(curr_state), curr_state); + LOG_VERBOSE("Ignore event[%s(%d)] in state[%s(%d)]", + smp_get_br_event_name(event), event, + smp_get_br_state_name(curr_state), curr_state); return; } @@ -361,5 +358,5 @@ void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event, break; } } - SMP_TRACE_DEBUG("result state = %s", smp_get_br_state_name(p_cb->br_state)); + LOG_VERBOSE("result state=%s", smp_get_br_state_name(p_cb->br_state)); } diff --git a/system/stack/smp/smp_int.h b/system/stack/smp/smp_int.h index 1cf316ef305ced021dfdb11acb59a6fe7270b98b..7ddd471d9a4d13c51c19b3323bcf46efbd9b2af1 100644 --- a/system/stack/smp/smp_int.h +++ b/system/stack/smp/smp_int.h @@ -24,12 +24,13 @@ #ifndef SMP_INT_H #define SMP_INT_H -#include "btm_api.h" -#include "btm_ble_api.h" -#include "smp_api.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" +#include + +#include "macros.h" +#include "osi/include/alarm.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_octets.h" +#include "stack/include/smp_api_types.h" #include "types/raw_address.h" typedef enum : uint16_t { @@ -65,7 +66,49 @@ typedef enum : uint8_t { #define SMP_WAIT_FOR_RSP_TIMEOUT_MS (30 * 1000) #define SMP_DELAYED_AUTH_TIMEOUT_MS 500 -#define SMP_OPCODE_INIT 0x04 +/* SMP command code */ +typedef enum : uint8_t { + SMP_OPCODE_PAIRING_REQ = 0x01, + SMP_OPCODE_PAIRING_RSP = 0x02, + SMP_OPCODE_CONFIRM = 0x03, + SMP_OPCODE_RAND = 0x04, + SMP_OPCODE_PAIRING_FAILED = 0x05, + SMP_OPCODE_ENCRYPT_INFO = 0x06, + SMP_OPCODE_CENTRAL_ID = 0x07, + SMP_OPCODE_IDENTITY_INFO = 0x08, + SMP_OPCODE_ID_ADDR = 0x09, + SMP_OPCODE_SIGN_INFO = 0x0A, + SMP_OPCODE_SEC_REQ = 0x0B, + SMP_OPCODE_PAIR_PUBLIC_KEY = 0x0C, + SMP_OPCODE_PAIR_DHKEY_CHECK = 0x0D, + SMP_OPCODE_PAIR_KEYPR_NOTIF = 0x0E, + SMP_OPCODE_MAX = SMP_OPCODE_PAIR_KEYPR_NOTIF, + SMP_OPCODE_MIN = SMP_OPCODE_PAIRING_REQ, + // NOTE: For some reason this is outside the MAX/MIN values + SMP_OPCODE_PAIR_COMMITM = 0x0F, +} tSMP_OPCODE; + +inline std::string smp_opcode_text(const tSMP_OPCODE opcode) { + switch (opcode) { + CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_REQ); + CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_RSP); + CASE_RETURN_TEXT(SMP_OPCODE_CONFIRM); + CASE_RETURN_TEXT(SMP_OPCODE_RAND); + CASE_RETURN_TEXT(SMP_OPCODE_PAIRING_FAILED); + CASE_RETURN_TEXT(SMP_OPCODE_ENCRYPT_INFO); + CASE_RETURN_TEXT(SMP_OPCODE_CENTRAL_ID); + CASE_RETURN_TEXT(SMP_OPCODE_IDENTITY_INFO); + CASE_RETURN_TEXT(SMP_OPCODE_ID_ADDR); + CASE_RETURN_TEXT(SMP_OPCODE_SIGN_INFO); + CASE_RETURN_TEXT(SMP_OPCODE_SEC_REQ); + CASE_RETURN_TEXT(SMP_OPCODE_PAIR_PUBLIC_KEY); + CASE_RETURN_TEXT(SMP_OPCODE_PAIR_DHKEY_CHECK); + CASE_RETURN_TEXT(SMP_OPCODE_PAIR_KEYPR_NOTIF); + CASE_RETURN_TEXT(SMP_OPCODE_PAIR_COMMITM); + default: + return base::StringPrintf("UNKNOWN[%hhu]", opcode); + } +} /* SMP events */ typedef enum : uint8_t { @@ -147,7 +190,8 @@ typedef enum : uint8_t { SMP_SC_OOB_DATA_EVT = (SMP_SELF_DEF_EVT + 23), // 0x27 SMP_CR_LOC_SC_OOB_DATA_EVT = (SMP_SELF_DEF_EVT + 24), // 0x28 - SMP_MAX_EVT = SMP_CR_LOC_SC_OOB_DATA_EVT, // 0x28 + SMP_SIRK_DEVICE_VALID_EVT = (SMP_SELF_DEF_EVT + 25), // 0x29 + SMP_MAX_EVT = SMP_SIRK_DEVICE_VALID_EVT, // 0x29 } tSMP_EVENT; typedef tSMP_EVENT tSMP_BR_EVENT; @@ -232,10 +276,15 @@ typedef struct { } tSMP_REQ_Q_ENTRY; /* SMP control block */ -typedef struct { +class tSMP_CB { + public: + void init(uint8_t security_mode); + void reset(); + + public: + uint8_t init_security_mode{0}; tSMP_CALLBACK* p_callback; alarm_t* smp_rsp_timer_ent; - uint8_t trace_level; RawAddress pairing_bda; tSMP_STATE state; bool derive_lk; @@ -310,16 +359,13 @@ typedef struct { tSMP_STATUS cert_failure; /*failure case for certification */ alarm_t* delayed_auth_timer_ent; tBLE_BD_ADDR pairing_ble_bd_addr; -} tSMP_CB; +}; /* Server Action functions are of this type */ typedef void (*tSMP_ACT)(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); extern tSMP_CB smp_cb; -/* Functions provided by att_main.cc */ -void smp_init(void); - /* smp main */ bool smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, tSMP_INT_DATA* p_data); @@ -357,6 +403,7 @@ void smp_enc_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_proc_discard(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_pairing_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); +void smp_sirk_verify(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_check_auth_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); @@ -402,7 +449,6 @@ void smp_br_send_pair_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_br_check_authorization_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_br_select_next_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_br_process_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); -void smp_key_distribution_by_transport(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); void smp_br_pairing_complete(tSMP_CB* p_cb, tSMP_INT_DATA* p_data); /* smp_l2c */ @@ -413,7 +459,6 @@ void smp_data_ind(const RawAddress& bd_addr, BT_HDR* p_buf); void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing, const uint8_t* p_buf, size_t buf_len, bool is_over_br); bool smp_send_cmd(uint8_t cmd_code, tSMP_CB* p_cb); -void smp_cb_cleanup(tSMP_CB* p_cb); void smp_reset_control_value(tSMP_CB* p_cb); void smp_proc_pairing_cmpl(tSMP_CB* p_cb); void smp_convert_string_to_tk(Octet16* tk, uint32_t passkey); diff --git a/system/stack/smp/smp_keys.cc b/system/stack/smp/smp_keys.cc index 809366ce1c3edcb6cae4ac8c7e98e78275467e61..c03e100c079381374d1b8fc01c22e307a6febe22 100644 --- a/system/stack/smp/smp_keys.cc +++ b/system/stack/smp/smp_keys.cc @@ -21,28 +21,30 @@ * This file contains security manager protocol utility functions * ******************************************************************************/ +#define LOG_TAG "smp" + #include #include #include #include -#include "bt_target.h" -#include "btm_ble_api.h" -#include "btm_ble_int.h" +#include "crypto_toolbox/crypto_toolbox.h" #include "device/include/controller.h" +#include "os/log.h" #include "osi/include/osi.h" #include "p_256_ecc_pp.h" #include "smp_int.h" +#include "stack/btm/btm_ble_sec.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" #include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_ble_api.h" +#include "stack/include/btm_ble_sec_api.h" #include "types/raw_address.h" -extern tBTM_CB btm_cb; // TODO Remove - using base::Bind; using crypto_toolbox::aes_128; @@ -66,12 +68,14 @@ void smp_save_local_oob_data(tSMP_CB* p_cb) { void smp_clear_local_oob_data() { saved_local_oob_data = {}; } -static bool is_empty(tSMP_LOC_OOB_DATA* data) { +static bool is_oob_data_empty(tSMP_LOC_OOB_DATA* data) { tSMP_LOC_OOB_DATA empty_data = {}; return memcmp(data, &empty_data, sizeof(tSMP_LOC_OOB_DATA)) == 0; } -bool smp_has_local_oob_data() { return !is_empty(&saved_local_oob_data); } +bool smp_has_local_oob_data() { + return !is_oob_data_empty(&saved_local_oob_data); +} void smp_debug_print_nbyte_little_endian(uint8_t* p, const char* key_name, uint8_t len) {} @@ -92,7 +96,7 @@ void smp_proc_passkey(tSMP_CB* p_cb, BT_OCTET8 rand) { uint32_t passkey; /* 19655 test number; */ uint8_t* pp = rand; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); STREAM_TO_UINT32(passkey, pp); passkey &= ~SMP_PASSKEY_MASK; @@ -135,7 +139,7 @@ void smp_proc_passkey(tSMP_CB* p_cb, BT_OCTET8 rand) { * ******************************************************************************/ void smp_generate_passkey(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); /* generate MRand or SRand */ btsnd_hcic_ble_rand(Bind(&smp_proc_passkey, p_cb)); } @@ -154,10 +158,10 @@ void smp_generate_passkey(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { void smp_generate_stk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { Octet16 output; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->le_secure_connections_mode_is_used) { - SMP_TRACE_DEBUG("FOR LE SC LTK IS USED INSTEAD OF STK"); + LOG_VERBOSE("FOR LE SC LTK IS USED INSTEAD OF STK"); output = p_cb->ltk; } else { output = smp_calculate_legacy_short_term_key(p_cb); @@ -170,19 +174,19 @@ void smp_generate_stk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { * This function is called to calculate CSRK */ void smp_compute_csrk(uint16_t div, tSMP_CB* p_cb) { - uint8_t buffer[4]; /* for (r || DIV) r=1*/ + Octet16 buffer{}; /* for (r || DIV) r=1*/ uint16_t r = 1; - uint8_t* p = buffer; + uint8_t* p = buffer.data(); p_cb->div = div; - SMP_TRACE_DEBUG("%s: div=%x", __func__, p_cb->div); + LOG_VERBOSE("div=0x%x", p_cb->div); const Octet16& er = BTM_GetDeviceEncRoot(); /* CSRK = d1(ER, DIV, 1) */ UINT16_TO_STREAM(p, p_cb->div); UINT16_TO_STREAM(p, r); - p_cb->csrk = aes_128(er, buffer, 4); + p_cb->csrk = aes_128(er, buffer); smp_send_csrk_info(p_cb, NULL); } @@ -192,13 +196,13 @@ void smp_compute_csrk(uint16_t div, tSMP_CB* p_cb) { void smp_generate_csrk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { bool div_status; - SMP_TRACE_DEBUG("smp_generate_csrk"); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div); if (div_status) { smp_compute_csrk(p_cb->div, p_cb); } else { - SMP_TRACE_DEBUG("Generate DIV for CSRK"); + LOG_VERBOSE("Generate DIV for CSRK"); btsnd_hcic_ble_rand(Bind( [](tSMP_CB* p_cb, BT_OCTET8 rand) { uint16_t div; @@ -216,7 +220,7 @@ void smp_generate_csrk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { void smp_concatenate_local(tSMP_CB* p_cb, uint8_t** p_data, uint8_t op_code) { uint8_t* p = *p_data; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); UINT8_TO_STREAM(p, op_code); UINT8_TO_STREAM(p, p_cb->local_io_capability); UINT8_TO_STREAM(p, p_cb->loc_oob_flag); @@ -235,7 +239,7 @@ void smp_concatenate_local(tSMP_CB* p_cb, uint8_t** p_data, uint8_t op_code) { void smp_concatenate_peer(tSMP_CB* p_cb, uint8_t** p_data, uint8_t op_code) { uint8_t* p = *p_data; - SMP_TRACE_DEBUG("smp_concatenate_peer "); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); UINT8_TO_STREAM(p, op_code); UINT8_TO_STREAM(p, p_cb->peer_io_caps); UINT8_TO_STREAM(p, p_cb->peer_oob_flag); @@ -254,7 +258,9 @@ void smp_concatenate_peer(tSMP_CB* p_cb, uint8_t** p_data, uint8_t op_code) { */ Octet16 smp_gen_p1_4_confirm(tSMP_CB* p_cb, tBLE_ADDR_TYPE remote_bd_addr_type) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("pairing_addr:%s, rmt_addr_type:%s", + ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda), + AddressTypeText(remote_bd_addr_type).c_str()); Octet16 p1; uint8_t* p = p1.data(); if (p_cb->role == HCI_ROLE_CENTRAL) { @@ -288,7 +294,7 @@ Octet16 smp_gen_p1_4_confirm(tSMP_CB* p_cb, * p2 = ra || ia || padding */ Octet16 smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); Octet16 p2{0}; uint8_t* p = p2.data(); /* 32-bit Padding */ @@ -319,17 +325,18 @@ Octet16 smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda) { ******************************************************************************/ tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, const Octet16& rand, Octet16* output) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); RawAddress remote_bda; tBLE_ADDR_TYPE remote_bd_addr_type = BLE_ADDR_PUBLIC; /* get remote connection specific bluetooth address */ if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, - &remote_bd_addr_type)) { - SMP_TRACE_ERROR("%s: cannot obtain remote device address", __func__); + &remote_bd_addr_type, true)) { + LOG_ERROR("cannot obtain remote device address"); return SMP_PAIR_FAIL_UNKNOWN; } /* get local connection specific bluetooth address */ - BTM_ReadConnectionAddr(p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type); + BTM_ReadConnectionAddr(p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type, + true); /* generate p1 = pres || preq || rat' || iat' */ Octet16 p1 = smp_gen_p1_4_confirm(p_cb, remote_bd_addr_type); /* p1' = rand XOR p1 */ @@ -361,7 +368,7 @@ tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, const Octet16& rand, * ******************************************************************************/ static void smp_generate_confirm(tSMP_CB* p_cb) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_debug_print_nbyte_little_endian(p_cb->rand.data(), "local_rand", 16); Octet16 output; tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rand, &output); @@ -395,7 +402,7 @@ static void smp_generate_confirm(tSMP_CB* p_cb) { ******************************************************************************/ void smp_generate_srand_mrand_confirm(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); /* generate MRand or SRand */ btsnd_hcic_ble_rand(Bind( [](tSMP_CB* p_cb, BT_OCTET8 rand) { @@ -425,7 +432,7 @@ void smp_generate_srand_mrand_confirm(tSMP_CB* p_cb, * ******************************************************************************/ void smp_generate_compare(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("smp_generate_compare "); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_debug_print_nbyte_little_endian(p_cb->rrand, "peer rand", 16); Octet16 output; tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rrand, &output); @@ -450,7 +457,7 @@ void smp_generate_compare(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { static void smp_process_stk(tSMP_CB* p_cb, Octet16* p) { tSMP_KEY key; - SMP_TRACE_DEBUG("smp_process_stk "); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_mask_enc_key(p_cb->loc_enc_size, p); key.key_type = SMP_KEY_TYPE_STK; @@ -467,13 +474,12 @@ static void smp_process_ediv(tSMP_CB* p_cb, Octet16& p) { uint8_t* pp = p.data(); uint16_t y; - SMP_TRACE_DEBUG("smp_process_ediv "); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); STREAM_TO_UINT16(y, pp); /* EDIV = Y xor DIV */ p_cb->ediv = p_cb->div ^ y; /* send LTK ready */ - SMP_TRACE_ERROR("LTK ready"); key.key_type = SMP_KEY_TYPE_LTK; key.p_data = p.data(); @@ -486,12 +492,14 @@ static void smp_process_ediv(tSMP_CB* p_cb, Octet16& p) { * This function is to proceed generate Y = E(DHK, Rand) */ static void smp_generate_y(tSMP_CB* p_cb, BT_OCTET8 rand) { - SMP_TRACE_DEBUG("%s ", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); const Octet16& dhk = BTM_GetDeviceDHK(); memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN); - Octet16 output = aes_128(dhk, rand, BT_OCTET8_LEN); + Octet16 rand16{}; + memcpy(rand16.data(), rand, BT_OCTET8_LEN); + Octet16 output = aes_128(dhk, rand16); smp_process_ediv(p_cb, output); } @@ -501,11 +509,14 @@ static void smp_generate_y(tSMP_CB* p_cb, BT_OCTET8 rand) { static void smp_generate_ltk_cont(uint16_t div, tSMP_CB* p_cb) { p_cb->div = div; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); const Octet16& er = BTM_GetDeviceEncRoot(); /* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/ - Octet16 ltk = aes_128(er, (uint8_t*)&p_cb->div, sizeof(uint16_t)); + Octet16 div16{}; + div16.data()[0] = div & 0xff; + div16.data()[1] = div >> 8u; + Octet16 ltk = aes_128(er, div16); /* mask the LTK */ smp_mask_enc_key(p_cb->loc_enc_size, <k); p_cb->ltk = ltk; @@ -530,7 +541,7 @@ static void smp_generate_ltk_cont(uint16_t div, tSMP_CB* p_cb) { * ******************************************************************************/ void smp_generate_ltk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) { smp_br_process_link_key(p_cb, NULL); @@ -545,7 +556,7 @@ void smp_generate_ltk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { if (div_status) { smp_generate_ltk_cont(p_cb->div, p_cb); } else { - SMP_TRACE_DEBUG("%s: Generate DIV for LTK", __func__); + LOG_VERBOSE("Generate DIV for LTK"); /* generate MRand or SRand */ btsnd_hcic_ble_rand(Bind( @@ -560,9 +571,9 @@ void smp_generate_ltk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) { /* The function calculates legacy STK */ Octet16 smp_calculate_legacy_short_term_key(tSMP_CB* p_cb) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); - Octet16 text{0}; + Octet16 text{}; if (p_cb->role == HCI_ROLE_CENTRAL) { memcpy(text.data(), p_cb->rand.data(), BT_OCTET8_LEN); memcpy(text.data() + BT_OCTET8_LEN, p_cb->rrand.data(), BT_OCTET8_LEN); @@ -588,7 +599,7 @@ Octet16 smp_calculate_legacy_short_term_key(tSMP_CB* p_cb) { * ******************************************************************************/ void smp_create_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); // Only use the stored OOB data if we are in an oob association model if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) { @@ -597,7 +608,7 @@ void smp_create_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { // pairing will fail Not much we can do about it at this point, just have to // generate new data The data will be cleared after the advertiser times // out, so if the advertiser times out we want the pairing to fail anyway. - if (!is_empty(&saved_local_oob_data)) { + if (!is_oob_data_empty(&saved_local_oob_data)) { LOG_WARN("Found OOB data, loading keys"); for (int i = 0; i < BT_OCTET32_LEN; i++) { p_cb->private_key[i] = saved_local_oob_data.private_key_used[i]; @@ -653,7 +664,7 @@ void smp_create_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { * ******************************************************************************/ void smp_use_oob_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - LOG_INFO("req_oob_type: %d, role: %d", p_cb->req_oob_type, p_cb->role); + LOG_INFO("req_oob_type:%d, role:%d", p_cb->req_oob_type, p_cb->role); switch (p_cb->req_oob_type) { case SMP_OOB_BOTH: @@ -667,7 +678,7 @@ void smp_use_oob_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { // point, just have to generate new data The data will be cleared after // the advertiser times out, so if the advertiser times out we want the // pairing to fail anyway. - if (!is_empty(&saved_local_oob_data)) { + if (!is_oob_data_empty(&saved_local_oob_data)) { LOG_INFO("Found OOB data, loading keys"); for (int i = 0; i < BT_OCTET32_LEN; i++) { p_cb->private_key[i] = saved_local_oob_data.private_key_used[i]; @@ -709,7 +720,7 @@ void smp_process_private_key(tSMP_CB* p_cb) { Point public_key; BT_OCTET32 private_key; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN); ECC_PointMult(&public_key, &(curve_p256.G), (uint32_t*)private_key); @@ -742,7 +753,7 @@ void smp_compute_dhkey(tSMP_CB* p_cb) { Point peer_publ_key, new_publ_key; BT_OCTET32 private_key; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN); memcpy(peer_publ_key.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN); @@ -768,13 +779,13 @@ void smp_compute_dhkey(tSMP_CB* p_cb) { void smp_calculate_local_commitment(tSMP_CB* p_cb) { uint8_t random_input; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); switch (p_cb->selected_association_model) { case SMP_MODEL_SEC_CONN_JUSTWORKS: case SMP_MODEL_SEC_CONN_NUM_COMP: if (p_cb->role == HCI_ROLE_CENTRAL) - SMP_TRACE_WARNING( + LOG_WARN( "local commitment calc on central is not expected " "for Just Works/Numeric Comparison models"); p_cb->commitment = crypto_toolbox::f4( @@ -789,31 +800,29 @@ void smp_calculate_local_commitment(tSMP_CB* p_cb) { p_cb->rand, random_input); break; case SMP_MODEL_SEC_CONN_OOB: - SMP_TRACE_WARNING( + LOG_WARN( "local commitment calc is expected for OOB model BEFORE pairing"); p_cb->commitment = crypto_toolbox::f4( p_cb->loc_publ_key.x, p_cb->loc_publ_key.x, p_cb->local_random, 0); break; default: - SMP_TRACE_ERROR("Association Model = %d is not used in LE SC", - p_cb->selected_association_model); + LOG_ERROR("Association Model=%d is not used in LE SC", + p_cb->selected_association_model); return; } - - SMP_TRACE_EVENT("local commitment calculation is completed"); } /** The function calculates peer commmitment */ Octet16 smp_calculate_peer_commitment(tSMP_CB* p_cb) { uint8_t ri; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); Octet16 output{0}; switch (p_cb->selected_association_model) { case SMP_MODEL_SEC_CONN_JUSTWORKS: case SMP_MODEL_SEC_CONN_NUM_COMP: if (p_cb->role == HCI_ROLE_PERIPHERAL) - SMP_TRACE_WARNING( + LOG_WARN( "peer commitment calc on peripheral is not expected " "for Just Works/Numeric Comparison models"); output = crypto_toolbox::f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, @@ -830,12 +839,11 @@ Octet16 smp_calculate_peer_commitment(tSMP_CB* p_cb) { p_cb->peer_random, 0); break; default: - SMP_TRACE_ERROR("Association Model = %d is not used in LE SC", - p_cb->selected_association_model); + LOG_ERROR("Association Model=%d is not used in LE SC", + p_cb->selected_association_model); return output; } - SMP_TRACE_EVENT("peer commitment calculation is completed"); return output; } @@ -851,7 +859,7 @@ Octet16 smp_calculate_peer_commitment(tSMP_CB* p_cb) { ******************************************************************************/ void smp_calculate_numeric_comparison_display_number(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->role == HCI_ROLE_CENTRAL) { p_cb->number_to_display = crypto_toolbox::g2( @@ -865,17 +873,16 @@ void smp_calculate_numeric_comparison_display_number(tSMP_CB* p_cb, tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN; p_cb->failure = SMP_PAIR_FAIL_UNKNOWN; + LOG_VERBOSE("Number to display in numeric comparison=%d too large", + p_cb->number_to_display); smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); return; } - SMP_TRACE_EVENT("Number to display in numeric comparison = %d", - p_cb->number_to_display); p_cb->cb_evt = SMP_NC_REQ_EVT; tSMP_INT_DATA smp_int_data; smp_int_data.passkey = p_cb->number_to_display; smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, &smp_int_data); - return; } /******************************************************************************* @@ -895,7 +902,7 @@ void smp_calculate_numeric_comparison_display_number(tSMP_CB* p_cb, void smp_calculate_local_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t iocap[3], a[7], b[7]; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_calculate_f5_mackey_and_long_term_key(p_cb); @@ -905,8 +912,6 @@ void smp_calculate_local_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { smp_collect_peer_ble_address(b, p_cb); p_cb->dhkey_check = crypto_toolbox::f6(p_cb->mac_key, p_cb->rand, p_cb->rrand, p_cb->peer_random, iocap, a, b); - - SMP_TRACE_EVENT("local DHKey check calculation is completed"); } /******************************************************************************* @@ -922,7 +927,7 @@ void smp_calculate_peer_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { uint8_t iocap[3], a[7], b[7]; tSMP_KEY key; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); smp_collect_peer_io_capabilities(iocap, p_cb); @@ -930,8 +935,6 @@ void smp_calculate_peer_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { smp_collect_peer_ble_address(b, p_cb); Octet16 param_buf = crypto_toolbox::f6(p_cb->mac_key, p_cb->rrand, p_cb->rand, p_cb->local_random, iocap, b, a); - - SMP_TRACE_EVENT("peer DHKey check calculation is completed"); key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK; key.p_data = param_buf.data(); tSMP_INT_DATA smp_int_data; @@ -954,24 +957,24 @@ bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb) { RawAddress bda_for_lk; tBLE_ADDR_TYPE conn_addr_type; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->id_addr_rcvd && p_cb->id_addr_type == BLE_ADDR_PUBLIC) { - SMP_TRACE_DEBUG( + LOG_VERBOSE( "Use rcvd identity address as BD_ADDR of LK rcvd identity address"); bda_for_lk = p_cb->id_addr; } else if ((BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda_for_lk, - &conn_addr_type)) && + &conn_addr_type, true)) && conn_addr_type == BLE_ADDR_PUBLIC) { - SMP_TRACE_DEBUG("Use rcvd connection address as BD_ADDR of LK"); + LOG_VERBOSE("Use rcvd connection address as BD_ADDR of LK"); } else { - SMP_TRACE_WARNING("Don't have peer public address to associate with LK"); + LOG_WARN("Don't have peer public address to associate with LK"); return false; } p_dev_rec = btm_find_dev(p_cb->pairing_bda); if (p_dev_rec == NULL) { - SMP_TRACE_ERROR("%s failed to find Security Record", __func__); + LOG_ERROR("failed to find Security Record"); return false; } @@ -979,7 +982,7 @@ bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb) { crypto_toolbox::ltk_to_link_key(p_cb->ltk, p_cb->key_derivation_h7_used); uint8_t link_key_type; - if (btm_cb.security_mode == BTM_SEC_MODE_SC) { + if (p_cb->init_security_mode == BTM_SEC_MODE_SC) { /* Secure Connections Only Mode */ link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256; } else if (controller_get_interface()->supports_secure_connections()) { @@ -988,15 +991,15 @@ bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb) { link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256; else link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256; - } else if (btm_cb.security_mode == BTM_SEC_MODE_SP) { + } else if (p_cb->init_security_mode == BTM_SEC_MODE_SP) { /* BR/EDR transport is SSP capable */ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED) link_key_type = BTM_LKEY_TYPE_AUTH_COMB; else link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB; } else { - SMP_TRACE_ERROR("%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x", - __func__, btm_cb.security_mode, p_dev_rec->sm4); + LOG_ERROR("failed to update link_key. Sec Mode=%d, sm4=0x%02x", + p_cb->init_security_mode, p_dev_rec->sm4); return false; } @@ -1006,8 +1009,6 @@ bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb) { std::reverse_copy(link_key.begin(), link_key.end(), notif_link_key.begin()); btm_sec_link_key_notification(bda_for_lk, notif_link_key, link_key_type); - SMP_TRACE_EVENT("%s is completed", __func__); - return true; } @@ -1015,38 +1016,36 @@ bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb) { bool smp_calculate_long_term_key_from_link_key(tSMP_CB* p_cb) { tBTM_SEC_DEV_REC* p_dev_rec; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p_dev_rec = btm_find_dev(p_cb->pairing_bda); if (p_dev_rec == NULL) { - SMP_TRACE_ERROR("%s failed to find Security Record", __func__); + LOG_ERROR("ailed to find Security Record"); return false; } uint8_t br_link_key_type; br_link_key_type = BTM_SecGetDeviceLinkKeyType(p_cb->pairing_bda); if (br_link_key_type == BTM_LKEY_TYPE_IGNORE) { - SMP_TRACE_ERROR("%s failed to retrieve BR link type", __func__); + LOG_ERROR("failed to retrieve BR link type"); return false; } if ((br_link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256) && (br_link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) { - SMP_TRACE_ERROR("%s LE SC LTK can't be derived from LK %d", __func__, - br_link_key_type); + LOG_ERROR("LE SC LTK can't be derived from LK %d", br_link_key_type); return false; } Octet16 rev_link_key; - std::reverse_copy(p_dev_rec->link_key.begin(), p_dev_rec->link_key.end(), - rev_link_key.begin()); + std::reverse_copy(p_dev_rec->sec_rec.link_key.begin(), + p_dev_rec->sec_rec.link_key.end(), rev_link_key.begin()); p_cb->ltk = crypto_toolbox::link_key_to_ltk(rev_link_key, p_cb->key_derivation_h7_used); p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) ? SMP_SEC_AUTHENTICATED : SMP_SEC_UNAUTHENTICATE; - SMP_TRACE_EVENT("%s is completed", __func__); return true; } @@ -1054,14 +1053,14 @@ bool smp_calculate_long_term_key_from_link_key(tSMP_CB* p_cb) { * This function generates nonce. */ void smp_start_nonce_generation(tSMP_CB* p_cb) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("start generating nonce"); btsnd_hcic_ble_rand(Bind( [](tSMP_CB* p_cb, BT_OCTET8 rand) { memcpy(p_cb->rand.data(), rand, BT_OCTET8_LEN); btsnd_hcic_ble_rand(Bind( [](tSMP_CB* p_cb, BT_OCTET8 rand) { memcpy(p_cb->rand.data() + 8, rand, BT_OCTET8_LEN); - SMP_TRACE_DEBUG("%s round %d", __func__, p_cb->round); + LOG_VERBOSE("round %d, done", p_cb->round); /* notifies SM that it has new nonce. */ smp_sm_event(p_cb, SMP_HAVE_LOC_NONCE_EVT, NULL); }, diff --git a/system/stack/smp/smp_l2c.cc b/system/stack/smp/smp_l2c.cc index 5b1395d1812b57a50b4322fb13788d0ca061951a..1fccd76bcef30ff964b2128b374db75e327d6488 100644 --- a/system/stack/smp/smp_l2c.cc +++ b/system/stack/smp/smp_l2c.cc @@ -22,22 +22,17 @@ * ******************************************************************************/ -#define LOG_TAG "bluetooth" +#define LOG_TAG "smp" -#include -#include - -#include "bt_target.h" -#include "btm_ble_api.h" -#include "common/metrics.h" -#include "l2c_api.h" -#include "main/shim/dumpsys.h" +#include "internal_include/bt_target.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" // UNUSED_ATTR #include "smp_int.h" #include "stack/btm/btm_dev.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" +#include "stack/include/l2c_api.h" #include "types/raw_address.h" static void smp_connect_callback(uint16_t channel, const RawAddress& bd_addr, @@ -62,7 +57,7 @@ static void smp_br_data_received(uint16_t channel, const RawAddress& bd_addr, ******************************************************************************/ void smp_l2cap_if_init(void) { tL2CAP_FIXED_CHNL_REG fixed_reg; - SMP_TRACE_EVENT("SMDBG l2c %s", __func__); + LOG_VERBOSE("SMDBG l2c"); fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback; fixed_reg.pL2CA_FixedData_Cb = smp_data_received; @@ -96,29 +91,22 @@ static void smp_connect_callback(UNUSED_ATTR uint16_t channel, tSMP_CB* p_cb = &smp_cb; tSMP_INT_DATA int_data; + LOG_DEBUG("bd_addr:%s transport:%s, connected:%d", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + bt_transport_text(transport).c_str(), connected); + if (bd_addr.IsEmpty()) { - LOG_WARN("Received unexpected callback for empty address"); + LOG_WARN("empty address"); return; } if (transport == BT_TRANSPORT_BR_EDR) { - LOG_WARN("Received unexpected callback on classic channel peer:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); + LOG_WARN("unexpected transport"); return; } - if (connected) { - LOG_DEBUG("SMP Received connect callback bd_addr:%s transport:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); - } else { - LOG_DEBUG("SMP Received disconnect callback bd_addr:%s transport:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), bt_transport_text(transport).c_str()); - } - if (bd_addr == p_cb->pairing_bda) { - LOG_DEBUG("Received callback for device in pairing process:%s state:%s", - ADDRESS_TO_LOGGABLE_CSTR(bd_addr), - (connected) ? "connected" : "disconnected"); + LOG_DEBUG("in pairing process"); if (connected) { if (!p_cb->connect_initialized) { @@ -157,19 +145,19 @@ static void smp_data_received(uint16_t channel, const RawAddress& bd_addr, uint8_t cmd; if (p_buf->len < 1) { - SMP_TRACE_WARNING("%s: smp packet length %d too short: must be at least 1", - __func__, p_buf->len); + LOG_WARN("packet too short"); osi_free(p_buf); return; } STREAM_TO_UINT8(cmd, p); - SMP_TRACE_EVENT("%s: SMDBG l2c, cmd=0x%x", __func__, cmd); + LOG_VERBOSE("cmd=%s[0x%02x]", + smp_opcode_text(static_cast(cmd)).c_str(), cmd); /* sanity check */ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { - SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd); + LOG_WARN("invalid command"); osi_free(p_buf); return; } @@ -199,10 +187,8 @@ static void smp_data_received(uint16_t channel, const RawAddress& bd_addr, false /* is_over_br */); if (cmd == SMP_OPCODE_CONFIRM) { - SMP_TRACE_DEBUG( - "in %s cmd = 0x%02x, peer_auth_req = 0x%02x," - "loc_auth_req = 0x%02x", - __func__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req); + LOG_VERBOSE("peer_auth_req=0x%02x, loc_auth_req=0x%02x", + p_cb->peer_auth_req, p_cb->loc_auth_req); if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) { @@ -237,18 +223,14 @@ static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr, tSMP_CB* p_cb = &smp_cb; tSMP_INT_DATA int_data; - SMP_TRACE_EVENT("%s", __func__); - if (transport != BT_TRANSPORT_BR_EDR) { - SMP_TRACE_WARNING("%s is called on unexpected transport %d", __func__, - transport); + LOG_WARN("unexpected transport %s", bt_transport_text(transport).c_str()); return; } - VLOG(1) << __func__ << " for pairing BDA: " - << ADDRESS_TO_LOGGABLE_STR(bd_addr) - << ", pairing_bda:" << ADDRESS_TO_LOGGABLE_STR(p_cb->pairing_bda) - << " Event: " << ((connected) ? "connected" : "disconnected"); + LOG_INFO("BDA:%s pairing_bda:%s, connected:%d", + ADDRESS_TO_LOGGABLE_CSTR(bd_addr), + ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda), connected); if (bd_addr != p_cb->pairing_bda) return; @@ -257,8 +239,9 @@ static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr, * Classic transport shouldn't impact that. */ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda); - if (smp_get_state() == SMP_STATE_BOND_PENDING && - (p_dev_rec && p_dev_rec->is_link_key_known()) && + if ((smp_get_state() == SMP_STATE_BOND_PENDING || + smp_get_state() == SMP_STATE_IDLE) && + (p_dev_rec && p_dev_rec->sec_rec.is_link_key_known()) && alarm_is_scheduled(p_cb->delayed_auth_timer_ent)) { /* If we were to not return here, we would reset SMP control block, and * delayed_auth_timer_ent would never be executed. Even though we stored all @@ -281,7 +264,12 @@ static void smp_br_connect_callback(uint16_t channel, const RawAddress& bd_addr, } } else { /* Disconnected while doing security */ - smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data); + if (p_cb->smp_over_br) { + LOG_DEBUG("SMP over BR/EDR not supported, terminate the ongoing pairing"); + smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data); + } else { + LOG_DEBUG("SMP over BR/EDR not supported, continue the LE pairing"); + } } } @@ -300,20 +288,21 @@ static void smp_br_data_received(uint16_t channel, const RawAddress& bd_addr, tSMP_CB* p_cb = &smp_cb; uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset; uint8_t cmd; - SMP_TRACE_EVENT("SMDBG l2c %s", __func__); + LOG_VERBOSE("SMDBG l2c"); if (p_buf->len < 1) { - SMP_TRACE_WARNING("%s: smp packet length %d too short: must be at least 1", - __func__, p_buf->len); + LOG_WARN("packet too short"); osi_free(p_buf); return; } STREAM_TO_UINT8(cmd, p); + LOG_VERBOSE("cmd=%s[0x%02x]", + smp_opcode_text(static_cast(cmd)).c_str(), cmd); /* sanity check */ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { - SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd); + LOG_WARN("invalid command 0x%02x", cmd); osi_free(p_buf); return; } diff --git a/system/stack/smp/smp_main.cc b/system/stack/smp/smp_main.cc index ab30510e5bd1f8cf8d4795be0ac00b65f267d1d3..00310d75133eaf737f047de9ceef961556596538 100644 --- a/system/stack/smp/smp_main.cc +++ b/system/stack/smp/smp_main.cc @@ -16,14 +16,11 @@ * ******************************************************************************/ -#define LOG_TAG "bluetooth" +#define LOG_TAG "smp" -#include "bt_target.h" - -#include +#include "os/log.h" #include "smp_int.h" - -#include "osi/include/log.h" +#include "stack/include/btm_log_history.h" namespace { @@ -91,6 +88,7 @@ const char* const smp_event_name[] = {"PAIRING_REQ_EVT", "KEYPRESS_NOTIFICATION_EVT", "SEC_CONN_OOB_DATA_EVT", "CREATE_LOCAL_SEC_CONN_OOB_DATA_EVT", + "SIRK_DEVICE_VALID_EVT", "OUT_OF_RANGE_EVT"}; const char* smp_get_event_name(tSMP_EVENT event); @@ -137,6 +135,7 @@ enum { SMP_CHECK_AUTH_REQ, SMP_PAIR_TERMINATE, SMP_ENC_CMPL, + SMP_SIRK_VERIFY, SMP_PROC_DISCARD, SMP_CREATE_PRIVATE_KEY, SMP_USE_OOB_PRIVATE_KEY, @@ -201,6 +200,7 @@ static const tSMP_ACT smp_sm_action[] = { smp_check_auth_req, smp_pair_terminate, smp_enc_cmpl, + smp_sirk_verify, smp_proc_discard, smp_create_private_key, smp_use_oob_private_key, @@ -232,9 +232,10 @@ static const tSMP_ACT smp_sm_action[] = { /************ SMP Central FSM State/Event Indirection Table **************/ static const uint8_t smp_central_entry_map[][SMP_STATE_MAX] = { /* state name: */ - /* Idle, WaitApp Rsp, SecReq Pend, Pair ReqRsp, Wait Cfm, Confirm, Rand, - PublKey Exch, SCPhs1 Strt, Wait Cmtm, Wait Nonce, SCPhs2 Strt, Wait - DHKChk, DHKChk, Enc Pend, Bond Pend, CrLocSc OobData */ + /* Idle, WaitApp Rsp, SecReq Pend, Pair ReqRsp, Wait Cfm, + Confirm, Rand, PublKey Exch, SCPhs1 Strt, Wait Cmtm, Wait Nonce, + SCPhs2 Strt, Wait DHKChk, DHKChk, Enc Pend, Bond Pend, CrLocSc OobData + */ /* PAIR_REQ */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* PAIR_RSP */ @@ -283,7 +284,7 @@ static const uint8_t smp_central_entry_map[][SMP_STATE_MAX] = { {0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0}, /* AUTH_CMPL */ {4, 0x82, 0, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0}, + 0x82, 0x82, 7, 0}, /* ENC_REQ */ {0, 4, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0}, /* BOND_REQ */ @@ -318,6 +319,8 @@ static const uint8_t smp_central_entry_map[][SMP_STATE_MAX] = { {0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* CR_LOC_SC_OOB_DATA */ {5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* SIRK_VERIFY */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x82, 0}, }; static const uint8_t smp_all_table[][SMP_SM_NUM_COLS] = { @@ -512,6 +515,7 @@ static const uint8_t smp_central_enc_pending_table[][SMP_SM_NUM_COLS] = { {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, /* BOND_REQ */ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}}; + static const uint8_t smp_central_bond_pending_table[][SMP_SM_NUM_COLS] = { /* Event Action Next State */ /* ENC_INFO */ @@ -526,7 +530,10 @@ static const uint8_t smp_central_bond_pending_table[][SMP_SM_NUM_COLS] = { {SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, /* KEY_READY */ /* LTK ready */ - {SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}}; + {SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* AUTH_CMPL */ + {SMP_SIRK_VERIFY, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +}; static const uint8_t smp_central_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = { @@ -595,7 +602,7 @@ static const uint8_t smp_peripheral_entry_map[][SMP_STATE_MAX] = { /* ENC_REQ */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, /* BOND_REQ */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1}, /* DISCARD_SEC_REQ */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* PUBL_KEY_EXCH_REQ */ @@ -626,6 +633,8 @@ static const uint8_t smp_peripheral_entry_map[][SMP_STATE_MAX] = { {0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* CR_LOC_SC_OOB_DATA */ {3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* SIRK_VERIFY */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }; static const uint8_t smp_peripheral_idle_table[][SMP_SM_NUM_COLS] = { @@ -838,6 +847,7 @@ static const uint8_t smp_peripheral_enc_pending_table[][SMP_SM_NUM_COLS] = { {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, /* BOND_REQ */ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}}; + static const uint8_t smp_peripheral_bond_pending_table[][SMP_SM_NUM_COLS] = { /* Event Action Next State */ @@ -855,8 +865,9 @@ static const uint8_t smp_peripheral_bond_pending_table[][SMP_SM_NUM_COLS] = { /* CENTRAL_ID*/ {SMP_PROC_CENTRAL_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, /* ID_ADDR */ - {SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} - + {SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* AUTH_CMPL */ + {SMP_SIRK_VERIFY, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, }; static const uint8_t @@ -924,7 +935,8 @@ static const tSMP_SM_TBL smp_state_table[][2] = { /* SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA */ {smp_central_create_local_sec_conn_oob_data, - smp_peripheral_create_local_sec_conn_oob_data}}; + smp_peripheral_create_local_sec_conn_oob_data}, +}; typedef const uint8_t (*tSMP_ENTRY_TBL)[SMP_STATE_MAX]; static const tSMP_ENTRY_TBL smp_entry_table[] = {smp_central_entry_map, @@ -940,9 +952,9 @@ tSMP_CB smp_cb; ******************************************************************************/ void smp_set_state(tSMP_STATE state) { if (state < SMP_STATE_MAX) { - SMP_TRACE_DEBUG("State change: %s(%d) ==> %s(%d)", - smp_get_state_name(smp_cb.state), smp_cb.state, - smp_get_state_name(state), state); + LOG_VERBOSE("State change: %s(%d)==>%s(%d)", + smp_get_state_name(smp_cb.state), smp_cb.state, + smp_get_state_name(state), state); if (smp_cb.state != state) { BTM_LogHistory( kBtmLogTag, smp_cb.pairing_ble_bd_addr, "Security state changed", @@ -951,7 +963,7 @@ void smp_set_state(tSMP_STATE state) { } smp_cb.state = state; } else { - SMP_TRACE_DEBUG("smp_set_state invalid state =%d", state); + LOG_VERBOSE("invalid state=%d", state); } } @@ -984,22 +996,21 @@ bool smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, tSMP_INT_DATA* p_data) { uint8_t action, entry, i; if (p_cb->role >= 2) { - SMP_TRACE_DEBUG("Invalid role: %d", p_cb->role); + LOG_VERBOSE("Invalid role:%d", p_cb->role); return false; } tSMP_ENTRY_TBL entry_table = smp_entry_table[p_cb->role]; - SMP_TRACE_EVENT("main smp_sm_event"); if (curr_state >= SMP_STATE_MAX) { - SMP_TRACE_DEBUG("Invalid state: %d", curr_state); + LOG_VERBOSE("Invalid state:%d", curr_state); return false; } - SMP_TRACE_DEBUG("SMP Role: %s State: [%s (%d)], Event: [%s (%d)]", - (p_cb->role == 0x01) ? "Peripheral" : "Central", - smp_get_state_name(p_cb->state), p_cb->state, - smp_get_event_name(event), event); + LOG_VERBOSE("SMP Role:%s State:[%s(%d)], Event:[%s(%d)]", + (p_cb->role == 0x01) ? "Peripheral" : "Central", + smp_get_state_name(p_cb->state), p_cb->state, + smp_get_event_name(event), event); /* look up the state table for the current state */ /* lookup entry /w event & curr_state */ @@ -1013,14 +1024,13 @@ bool smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, tSMP_INT_DATA* p_data) { } else state_table = smp_state_table[curr_state][p_cb->role]; } else { - SMP_TRACE_DEBUG("Ignore event [%s (%d)] in state [%s (%d)]", - smp_get_event_name(event), event, - smp_get_state_name(curr_state), curr_state); + LOG_VERBOSE("Ignore event[%s(%d)] in state[%s(%d)]", + smp_get_event_name(event), event, + smp_get_state_name(curr_state), curr_state); return false; } /* Get possible next state from state table. */ - smp_set_state(state_table[entry - 1][SMP_SME_NEXT_STATE]); /* If action is not ignore, clear param, exec action and get next state. @@ -1036,7 +1046,7 @@ bool smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, tSMP_INT_DATA* p_data) { break; } } - SMP_TRACE_DEBUG("result state = %s", smp_get_state_name(p_cb->state)); + LOG_VERBOSE("result state=%s", smp_get_state_name(p_cb->state)); return true; } diff --git a/system/stack/smp/smp_utils.cc b/system/stack/smp/smp_utils.cc index 956066754b12812b62a4958ab60f7ca5c362b344..70471b3d577e09ad114d784c8228f8fbb59c17ab 100644 --- a/system/stack/smp/smp_utils.cc +++ b/system/stack/smp/smp_utils.cc @@ -21,27 +21,34 @@ * This file contains functions for the SMP L2CAP utility functions * ******************************************************************************/ -#include -#include -#include +#define LOG_TAG "smp" -#include "bt_target.h" -#include "btm_ble_api.h" +#include +#include + +#include "crypto_toolbox/crypto_toolbox.h" #include "device/include/controller.h" -#include "l2c_api.h" -#include "osi/include/log.h" +#include "internal_include/bt_target.h" +#include "internal_include/stack_config.h" +#include "os/log.h" +#include "osi/include/allocator.h" #include "osi/include/osi.h" +#include "p_256_ecc_pp.h" #include "smp_int.h" -#include "stack/btm/btm_ble_int.h" +#include "stack/btm/btm_ble_sec.h" +#include "stack/btm/btm_dev.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_octets.h" +#include "stack/include/bt_types.h" +#include "stack/include/btm_ble_api.h" +#include "stack/include/btm_ble_sec_api.h" #include "stack/include/btm_log_history.h" +#include "stack/include/l2c_api.h" +#include "stack/include/smp_status.h" #include "stack/include/stack_metrics_logging.h" #include "types/raw_address.h" -void btm_dev_consolidate_existing_connections(const RawAddress& bd_addr); - #define SMP_PAIRING_REQ_SIZE 7 #define SMP_CONFIRM_CMD_SIZE (OCTET16_LEN + 1) #define SMP_RAND_CMD_SIZE (OCTET16_LEN + 1) @@ -317,7 +324,7 @@ static tSMP_ASSO_MODEL smp_select_association_model_secure_connections( void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing, const uint8_t* p_buf, size_t buf_len, bool is_over_br) { if (buf_len < 1) { - LOG(WARNING) << __func__ << ": buffer is too small, size is " << buf_len; + LOG_WARN("buffer is too small"); return; } uint8_t raw_cmd; @@ -327,6 +334,9 @@ void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing, if (raw_cmd == SMP_OPCODE_PAIRING_FAILED && buf_len >= 1) { STREAM_TO_UINT8(failure_reason, p_buf); } + if (smp_cb.is_pair_cancel) { + failure_reason = SMP_USER_CANCELLED; // Tracking pairing cancellations + } uint16_t metric_cmd = is_over_br ? SMP_METRIC_COMMAND_BR_FLAG : SMP_METRIC_COMMAND_LE_FLAG; metric_cmd |= static_cast(raw_cmd); @@ -352,7 +362,8 @@ bool smp_send_msg_to_L2CAP(const RawAddress& rem_bda, BT_HDR* p_toL2CAP) { fixed_cid = L2CAP_SMP_BR_CID; } - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("rem_bda:%s, over_bredr:%d", ADDRESS_TO_LOGGABLE_CSTR(rem_bda), + smp_cb.smp_over_br); smp_log_metrics(rem_bda, true /* outgoing */, p_toL2CAP->data + p_toL2CAP->offset, p_toL2CAP->len, @@ -360,7 +371,7 @@ bool smp_send_msg_to_L2CAP(const RawAddress& rem_bda, BT_HDR* p_toL2CAP) { l2cap_ret = L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_toL2CAP); if (l2cap_ret == L2CAP_DW_FAILED) { - SMP_TRACE_ERROR("SMP failed to pass msg to L2CAP"); + LOG_ERROR("SMP failed to pass msg to L2CAP"); return false; } else { tSMP_CB* p_cb = &smp_cb; @@ -428,8 +439,7 @@ bool smp_send_cmd(uint8_t cmd_code, tSMP_CB* p_cb) { void smp_rsp_timeout(UNUSED_ATTR void* data) { tSMP_CB* p_cb = &smp_cb; - SMP_TRACE_EVENT("%s state:%d br_state:%d", __func__, p_cb->state, - p_cb->br_state); + LOG_VERBOSE("state:%d br_state:%d", p_cb->state, p_cb->br_state); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_RSP_TIMEOUT; @@ -456,7 +466,7 @@ void smp_delayed_auth_complete_timeout(UNUSED_ATTR void* data) { * the state is still in bond pending. */ if (smp_get_state() == SMP_STATE_BOND_PENDING) { - SMP_TRACE_EVENT("%s sending delayed auth complete.", __func__); + LOG_VERBOSE("sending delayed auth complete."); tSMP_INT_DATA smp_int_data; smp_int_data.status = SMP_SUCCESS; smp_sm_event(&smp_cb, SMP_AUTH_CMPL_EVT, &smp_int_data); @@ -475,7 +485,8 @@ BT_HDR* smp_build_pairing_cmd(uint8_t cmd_code, tSMP_CB* p_cb) { BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIRING_REQ_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("building cmd:%s", + smp_opcode_text(static_cast(cmd_code)).c_str()); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, cmd_code); @@ -506,7 +517,7 @@ static BT_HDR* smp_build_confirm_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_CONFIRM_CMD_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -531,7 +542,7 @@ static BT_HDR* smp_build_rand_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB* p_cb) { BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_RAND_CMD_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_RAND); @@ -556,7 +567,7 @@ static BT_HDR* smp_build_encrypt_info_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_ENC_INFO_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_ENCRYPT_INFO); @@ -581,7 +592,7 @@ static BT_HDR* smp_build_central_id_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_CENTRAL_ID_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_CENTRAL_ID); @@ -607,7 +618,7 @@ static BT_HDR* smp_build_identity_info_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; @@ -635,7 +646,7 @@ static BT_HDR* smp_build_id_addr_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_ID_ADDR); @@ -661,7 +672,7 @@ static BT_HDR* smp_build_signing_info_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_SIGN_INFO_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_SIGN_INFO); @@ -686,7 +697,7 @@ static BT_HDR* smp_build_pairing_fail(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_PAIRING_FAILED); @@ -710,7 +721,7 @@ static BT_HDR* smp_build_security_request(UNUSED_ATTR uint8_t cmd_code, uint8_t* p; BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + 2 + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_SEC_REQ); @@ -719,8 +730,8 @@ static BT_HDR* smp_build_security_request(UNUSED_ATTR uint8_t cmd_code, p_buf->offset = L2CAP_MIN_OFFSET; p_buf->len = SMP_SECURITY_REQUEST_SIZE; - SMP_TRACE_EVENT("opcode=%d auth_req=0x%x", SMP_OPCODE_SEC_REQ, - p_cb->loc_auth_req); + LOG_VERBOSE("opcode=%d auth_req=0x%x", SMP_OPCODE_SEC_REQ, + p_cb->loc_auth_req); return p_buf; } @@ -740,7 +751,7 @@ static BT_HDR* smp_build_pair_public_key_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_PUBL_KEY_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); memcpy(p_publ_key, p_cb->loc_publ_key.x, BT_OCTET32_LEN); memcpy(p_publ_key + BT_OCTET32_LEN, p_cb->loc_publ_key.y, BT_OCTET32_LEN); @@ -768,7 +779,7 @@ static BT_HDR* smp_build_pairing_commitment_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_COMMITM_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM); @@ -793,7 +804,7 @@ static BT_HDR* smp_build_pair_dhkey_check_cmd(UNUSED_ATTR uint8_t cmd_code, BT_HDR* p_buf = (BT_HDR*)osi_malloc( sizeof(BT_HDR) + SMP_PAIR_DHKEY_CHECK_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_DHKEY_CHECK); @@ -818,7 +829,7 @@ static BT_HDR* smp_build_pairing_keypress_notification_cmd( BT_HDR* p_buf = (BT_HDR*)osi_malloc( sizeof(BT_HDR) + SMP_PAIR_KEYPR_NOTIF_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_KEYPR_NOTIF); @@ -835,7 +846,7 @@ static BT_HDR* smp_build_pairing_keypress_notification_cmd( void smp_convert_string_to_tk(Octet16* tk, uint32_t passkey) { uint8_t* p = tk->data(); tSMP_KEY key; - SMP_TRACE_EVENT("smp_convert_string_to_tk"); + LOG_VERBOSE("smp_convert_string_to_tk"); UINT32_TO_STREAM(p, passkey); key.key_type = SMP_KEY_TYPE_TK; @@ -849,7 +860,7 @@ void smp_convert_string_to_tk(Octet16* tk, uint32_t passkey) { /** This function is called to mask off the encryption key based on the maximum * encryption key size. */ void smp_mask_enc_key(uint8_t loc_enc_size, Octet16* p_data) { - SMP_TRACE_EVENT("smp_mask_enc_key"); + LOG_VERBOSE("smp_mask_enc_key"); if (loc_enc_size < OCTET16_LEN) { for (; loc_enc_size < OCTET16_LEN; loc_enc_size++) (*p_data)[loc_enc_size] = 0; @@ -870,30 +881,52 @@ void smp_xor_128(Octet16* a, const Octet16& b) { } } +void tSMP_CB::init(uint8_t security_mode) { + *this = {}; + + init_security_mode = security_mode; + smp_cb.smp_rsp_timer_ent = alarm_new("smp.smp_rsp_timer_ent"); + smp_cb.delayed_auth_timer_ent = alarm_new("smp.delayed_auth_timer_ent"); + + LOG_VERBOSE("init_security_mode:%d", init_security_mode); + + smp_l2cap_if_init(); + /* initialization of P-256 parameters */ + p_256_init_curve(); + + /* Initialize failure case for certification */ + smp_cb.cert_failure = static_cast( + stack_config_get_interface()->get_pts_smp_failure_case()); + if (smp_cb.cert_failure) + LOG_ERROR("PTS FAILURE MODE IN EFFECT (CASE %d)", smp_cb.cert_failure); +} + /******************************************************************************* * - * Function smp_cb_cleanup + * Function reset * - * Description Clean up SMP control block + * Description reset SMP control block * * Returns void * ******************************************************************************/ -void smp_cb_cleanup(tSMP_CB* p_cb) { - tSMP_CALLBACK* p_callback = p_cb->p_callback; - uint8_t trace_level = p_cb->trace_level; - alarm_t* smp_rsp_timer_ent = p_cb->smp_rsp_timer_ent; - alarm_t* delayed_auth_timer_ent = p_cb->delayed_auth_timer_ent; +void tSMP_CB::reset() { + tSMP_CALLBACK* p_callback = this->p_callback; + uint8_t init_security_mode = this->init_security_mode; + alarm_t* smp_rsp_timer_ent = this->smp_rsp_timer_ent; + alarm_t* delayed_auth_timer_ent = this->delayed_auth_timer_ent; - SMP_TRACE_EVENT("smp_cb_cleanup"); + LOG_VERBOSE("resetting SMP_CB"); - alarm_cancel(p_cb->smp_rsp_timer_ent); - alarm_cancel(p_cb->delayed_auth_timer_ent); - memset(p_cb, 0, sizeof(tSMP_CB)); - p_cb->p_callback = p_callback; - p_cb->trace_level = trace_level; - p_cb->smp_rsp_timer_ent = smp_rsp_timer_ent; - p_cb->delayed_auth_timer_ent = delayed_auth_timer_ent; + alarm_cancel(this->smp_rsp_timer_ent); + alarm_cancel(this->delayed_auth_timer_ent); + + init(init_security_mode); + + this->p_callback = p_callback; + this->init_security_mode = init_security_mode; + this->smp_rsp_timer_ent = smp_rsp_timer_ent; + this->delayed_auth_timer_ent = delayed_auth_timer_ent; } /******************************************************************************* @@ -906,7 +939,7 @@ void smp_cb_cleanup(tSMP_CB* p_cb) { * ******************************************************************************/ void smp_remove_fixed_channel(tSMP_CB* p_cb) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->smp_over_br) L2CA_RemoveFixedChnl(L2CAP_SMP_BR_CID, p_cb->pairing_bda); @@ -926,7 +959,7 @@ void smp_remove_fixed_channel(tSMP_CB* p_cb) { * ******************************************************************************/ void smp_reset_control_value(tSMP_CB* p_cb) { - SMP_TRACE_EVENT("%s", __func__); + LOG_VERBOSE("reset smp_cb"); alarm_cancel(p_cb->smp_rsp_timer_ent); p_cb->flags = 0; @@ -939,7 +972,7 @@ void smp_reset_control_value(tSMP_CB* p_cb) { /* We can tell L2CAP to remove the fixed channel (if it has one) */ smp_remove_fixed_channel(p_cb); - smp_cb_cleanup(p_cb); + p_cb->reset(); } /******************************************************************************* @@ -1025,8 +1058,7 @@ bool smp_command_has_invalid_length(tSMP_CB* p_cb) { if ((cmd_code > (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */)) || (cmd_code < SMP_OPCODE_MIN)) { - SMP_TRACE_WARNING("%s: Received command with RESERVED code 0x%02x", - __func__, cmd_code); + LOG_WARN("Received command with RESERVED code 0x%02x", cmd_code); return true; } @@ -1054,20 +1086,17 @@ bool smp_command_has_invalid_parameters(tSMP_CB* p_cb) { if ((cmd_code > (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */)) || (cmd_code < SMP_OPCODE_MIN)) { - SMP_TRACE_WARNING("%s: Received command with RESERVED code 0x%02x", - __func__, cmd_code); + LOG_WARN("Received command with RESERVED code 0x%02x", cmd_code); return true; } if (!(*smp_cmd_len_is_valid[cmd_code])(p_cb)) { - SMP_TRACE_WARNING("%s: Command length not valid for cmd_code 0x%02x", - __func__, cmd_code); + LOG_WARN("Command length not valid for cmd_code 0x%02x", cmd_code); return true; } if (!(*smp_cmd_param_ranges_are_valid[cmd_code])(p_cb)) { - SMP_TRACE_WARNING("%s: Parameter ranges not valid code 0x%02x", __func__, - cmd_code); + LOG_WARN("Parameter ranges not valid code 0x%02x", cmd_code); return true; } @@ -1088,10 +1117,10 @@ bool smp_command_has_invalid_parameters(tSMP_CB* p_cb) { bool smp_command_has_valid_fixed_length(tSMP_CB* p_cb) { uint8_t cmd_code = p_cb->rcvd_cmd_code; - SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, cmd_code); + LOG_VERBOSE("cmd code 0x%02x", cmd_code); if (p_cb->rcvd_cmd_len != smp_cmd_size_per_spec[cmd_code]) { - SMP_TRACE_WARNING( + LOG_WARN( "Rcvd from the peer cmd 0x%02x with invalid length " "0x%02x (per spec the length is 0x%02x).", cmd_code, p_cb->rcvd_cmd_len, smp_cmd_size_per_spec[cmd_code]); @@ -1123,10 +1152,10 @@ bool smp_pairing_request_response_parameters_are_valid(tSMP_CB* p_cb) { p_cb->peer_auth_req & 0x03; // 0x03 is gen bond with appropriate mask uint8_t enc_size = p_cb->peer_enc_size; - SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, p_cb->rcvd_cmd_code); + LOG_VERBOSE("cmd code 0x%02x", p_cb->rcvd_cmd_code); if (io_caps >= BTM_IO_CAP_MAX) { - SMP_TRACE_WARNING( + LOG_WARN( "Rcvd from the peer cmd 0x%02x with IO Capability " "value (0x%02x) out of range).", p_cb->rcvd_cmd_code, io_caps); @@ -1134,7 +1163,7 @@ bool smp_pairing_request_response_parameters_are_valid(tSMP_CB* p_cb) { } if (!((oob_flag == SMP_OOB_NONE) || (oob_flag == SMP_OOB_PRESENT))) { - SMP_TRACE_WARNING( + LOG_WARN( "Rcvd from the peer cmd 0x%02x with OOB data flag value " "(0x%02x) out of range).", p_cb->rcvd_cmd_code, oob_flag); @@ -1142,7 +1171,7 @@ bool smp_pairing_request_response_parameters_are_valid(tSMP_CB* p_cb) { } if (!((bond_flag == SMP_AUTH_NO_BOND) || (bond_flag == SMP_AUTH_BOND))) { - SMP_TRACE_WARNING( + LOG_WARN( "Rcvd from the peer cmd 0x%02x with Bonding_Flags value (0x%02x) " "out of range).", p_cb->rcvd_cmd_code, bond_flag); @@ -1151,7 +1180,7 @@ bool smp_pairing_request_response_parameters_are_valid(tSMP_CB* p_cb) { if ((enc_size < SMP_ENCR_KEY_SIZE_MIN) || (enc_size > SMP_ENCR_KEY_SIZE_MAX)) { - SMP_TRACE_WARNING( + LOG_WARN( "Rcvd from the peer cmd 0x%02x with Maximum Encryption " "Key value (0x%02x) out of range).", p_cb->rcvd_cmd_code, enc_size); @@ -1173,10 +1202,10 @@ bool smp_pairing_request_response_parameters_are_valid(tSMP_CB* p_cb) { bool smp_pairing_keypress_notification_is_valid(tSMP_CB* p_cb) { tSMP_SC_KEY_TYPE keypress_notification = p_cb->peer_keypress_notification; - SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, p_cb->rcvd_cmd_code); + LOG_VERBOSE("cmd code 0x%02x", p_cb->rcvd_cmd_code); if (keypress_notification >= SMP_SC_KEY_OUT_OF_RANGE) { - SMP_TRACE_WARNING( + LOG_WARN( "Rcvd from the peer cmd 0x%02x with Pairing Keypress " "Notification value (0x%02x) out of range).", p_cb->rcvd_cmd_code, keypress_notification); @@ -1223,7 +1252,7 @@ void smp_reject_unexpected_pairing_command(const RawAddress& bd_addr) { BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET); - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("bd_addr:%s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr)); p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; UINT8_TO_STREAM(p, SMP_OPCODE_PAIRING_FAILED); @@ -1256,16 +1285,14 @@ tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB* p_cb) { tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; p_cb->le_secure_connections_mode_is_used = false; - SMP_TRACE_EVENT("%s", __func__); - SMP_TRACE_DEBUG("%s p_cb->peer_io_caps = %d p_cb->local_io_capability = %d", - __func__, p_cb->peer_io_caps, p_cb->local_io_capability); - SMP_TRACE_DEBUG("%s p_cb->peer_oob_flag = %d p_cb->loc_oob_flag = %d", - __func__, p_cb->peer_oob_flag, p_cb->loc_oob_flag); - SMP_TRACE_DEBUG("%s p_cb->peer_auth_req = 0x%02x p_cb->loc_auth_req = 0x%02x", - __func__, p_cb->peer_auth_req, p_cb->loc_auth_req); - SMP_TRACE_DEBUG( - "%s p_cb->secure_connections_only_mode_required = %s", __func__, - p_cb->secure_connections_only_mode_required ? "true" : "false"); + LOG_VERBOSE("p_cb->peer_io_caps = %d p_cb->local_io_capability = %d", + p_cb->peer_io_caps, p_cb->local_io_capability); + LOG_VERBOSE("p_cb->peer_oob_flag = %d p_cb->loc_oob_flag = %d", + p_cb->peer_oob_flag, p_cb->loc_oob_flag); + LOG_VERBOSE("p_cb->peer_auth_req = 0x%02x p_cb->loc_auth_req = 0x%02x", + p_cb->peer_auth_req, p_cb->loc_auth_req); + LOG_VERBOSE("p_cb->secure_connections_only_mode_required = %s", + p_cb->secure_connections_only_mode_required ? "true" : "false"); if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) { @@ -1277,9 +1304,9 @@ tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB* p_cb) { p_cb->key_derivation_h7_used = TRUE; } - SMP_TRACE_DEBUG("use_sc_process = %d, h7 use = %d", - p_cb->le_secure_connections_mode_is_used, - p_cb->key_derivation_h7_used); + LOG_VERBOSE("use_sc_process = %d, h7 use = %d", + p_cb->le_secure_connections_mode_is_used, + p_cb->key_derivation_h7_used); if (p_cb->le_secure_connections_mode_is_used) { model = smp_select_association_model_secure_connections(p_cb); @@ -1299,7 +1326,7 @@ tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB* p_cb) { tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB* p_cb) { tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); /* if OOB data is present on both devices, then use OOB association model */ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT) @@ -1336,7 +1363,7 @@ tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB* p_cb) { tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB* p_cb) { tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); /* if OOB data is present on at least one device, then use OOB association * model */ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT || @@ -1380,10 +1407,9 @@ uint8_t smp_calculate_random_input(uint8_t* random, uint8_t round) { uint8_t j = round % 8; uint8_t ri; - SMP_TRACE_DEBUG("random: 0x%02x, round: %d, i: %d, j: %d", random[i], round, - i, j); ri = ((random[i] >> j) & 1) | 0x80; - SMP_TRACE_DEBUG("%s ri=0x%02x", __func__, ri); + LOG_VERBOSE("random:0x%02x, round:%d, i:%d, j:%d, ri:0x%02x", random[i], + round, i, j, ri); return ri; } @@ -1397,7 +1423,7 @@ uint8_t smp_calculate_random_input(uint8_t* random, uint8_t round) { * ******************************************************************************/ void smp_collect_local_io_capabilities(uint8_t* iocap, tSMP_CB* p_cb) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); iocap[0] = p_cb->local_io_capability; iocap[1] = p_cb->loc_oob_flag; @@ -1414,7 +1440,7 @@ void smp_collect_local_io_capabilities(uint8_t* iocap, tSMP_CB* p_cb) { * ******************************************************************************/ void smp_collect_peer_io_capabilities(uint8_t* iocap, tSMP_CB* p_cb) { - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); iocap[0] = p_cb->peer_io_caps; iocap[1] = p_cb->peer_oob_flag; @@ -1436,9 +1462,9 @@ void smp_collect_local_ble_address(uint8_t* le_addr, tSMP_CB* p_cb) { RawAddress bda; uint8_t* p = le_addr; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); - BTM_ReadConnectionAddr(p_cb->pairing_bda, bda, &addr_type); + BTM_ReadConnectionAddr(p_cb->pairing_bda, bda, &addr_type, true); BDADDR_TO_STREAM(p, bda); UINT8_TO_STREAM(p, addr_type); } @@ -1458,11 +1484,10 @@ void smp_collect_peer_ble_address(uint8_t* le_addr, tSMP_CB* p_cb) { RawAddress bda; uint8_t* p = le_addr; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); - if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda, &addr_type)) { - SMP_TRACE_ERROR( - "can not collect peer le addr information for unknown device"); + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda, &addr_type, true)) { + LOG_ERROR("can not collect peer le addr information for unknown device"); return; } @@ -1482,19 +1507,17 @@ void smp_collect_peer_ble_address(uint8_t* le_addr, tSMP_CB* p_cb) { * ******************************************************************************/ bool smp_check_commitment(tSMP_CB* p_cb) { - - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); Octet16 expected = smp_calculate_peer_commitment(p_cb); print128(expected, (const uint8_t*)"calculated peer commitment"); print128(p_cb->remote_commitment, (const uint8_t*)"received peer commitment"); if (memcmp(p_cb->remote_commitment.data(), expected.data(), OCTET16_LEN)) { - SMP_TRACE_WARNING("%s: Commitment check fails", __func__); + LOG_WARN("Commitment check fails"); return false; } - SMP_TRACE_DEBUG("%s: Commitment check succeeds", __func__); return true; } @@ -1509,8 +1532,7 @@ bool smp_check_commitment(tSMP_CB* p_cb) { * ******************************************************************************/ void smp_save_secure_connections_long_term_key(tSMP_CB* p_cb) { - - SMP_TRACE_DEBUG("%s-Save LTK as local LTK key", __func__); + LOG_VERBOSE("Save LTK as local and peer key"); tBTM_LE_KEY_VALUE lle_key = { .lenc_key = { @@ -1522,14 +1544,13 @@ void smp_save_secure_connections_long_term_key(tSMP_CB* p_cb) { }; btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, &lle_key, true); - SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key", __func__); tBTM_LE_KEY_VALUE ple_key = { .penc_key = { .ltk = p_cb->ltk, + .ediv = 0, .sec_level = p_cb->sec_level, .key_size = p_cb->loc_enc_size, - .ediv = 0, }, }; memset(ple_key.penc_key.rand, 0, BT_OCTET8_LEN); @@ -1545,7 +1566,7 @@ void smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb) { Octet16 na; Octet16 nb; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->role == HCI_ROLE_CENTRAL) { smp_collect_local_ble_address(a, p_cb); @@ -1560,8 +1581,6 @@ void smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb) { } crypto_toolbox::f5(p_cb->dhkey, na, nb, a, b, &p_cb->mac_key, &p_cb->ltk); - - SMP_TRACE_EVENT("%s is completed", __func__); } /******************************************************************************* @@ -1577,7 +1596,7 @@ void smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb) { bool smp_request_oob_data(tSMP_CB* p_cb) { tSMP_OOB_DATA_TYPE req_oob_type = SMP_OOB_INVALID_TYPE; - SMP_TRACE_DEBUG("%s", __func__); + LOG_VERBOSE("addr:%s", ADDRESS_TO_LOGGABLE_CSTR(p_cb->pairing_bda)); if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT) { @@ -1590,7 +1609,7 @@ bool smp_request_oob_data(tSMP_CB* p_cb) { req_oob_type = SMP_OOB_PEER; } - SMP_TRACE_DEBUG("req_oob_type = %d", req_oob_type); + LOG_VERBOSE("req_oob_type=%d", req_oob_type); if (req_oob_type == SMP_OOB_INVALID_TYPE) return false; @@ -1607,10 +1626,11 @@ void print128(const Octet16& x, const uint8_t* key_name) { if (VLOG_IS_ON(2) && DLOG_IS_ON(INFO)) { uint8_t* p = (uint8_t*)x.data(); - DVLOG(2) << key_name << " (MSB ~ LSB) = "; + LOG_INFO("%s(MSB~LSB):", key_name); for (int i = 0; i < 4; i++) { - DVLOG(2) << +p[OCTET16_LEN - i * 4 - 1] << +p[OCTET16_LEN - i * 4 - 2] - << +p[OCTET16_LEN - i * 4 - 3] << +p[OCTET16_LEN - i * 4 - 4]; + LOG_INFO("%02x:%02x:%02x:%02x", p[OCTET16_LEN - i * 4 - 1], + p[OCTET16_LEN - i * 4 - 2], p[OCTET16_LEN - i * 4 - 3], + p[OCTET16_LEN - i * 4 - 4]); } } } diff --git a/system/stack/srvc/srvc_dis.cc b/system/stack/srvc/srvc_dis.cc index 3b75e8a6e416e5adc93a8a629cedabd4d6852cff..16a3d60c06cd03b842d4f1e2b04420bc01e51179 100644 --- a/system/stack/srvc/srvc_dis.cc +++ b/system/stack/srvc/srvc_dis.cc @@ -18,20 +18,20 @@ #define LOG_TAG "bt_srvc" -#include "bt_target.h" +#include + #include "gatt_api.h" -#include "gatt_int.h" +#include "hardware/bt_gatt_types.h" +#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" #include "osi/include/osi.h" #include "srvc_dis_int.h" #include "srvc_eng_int.h" #include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#include - using base::StringPrintf; #define DIS_MAX_NUM_INC_SVR 0 #define DIS_MAX_CHAR_NUM 9 @@ -260,10 +260,17 @@ bool dis_gatt_c_read_dis_req(uint16_t conn_id) { ******************************************************************************/ void dis_c_cmpl_cback(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data) { - uint16_t read_type = dis_attr_uuid[dis_cb.dis_read_uuid_idx]; + uint16_t read_type; uint8_t *pp = NULL, *p_str; uint16_t conn_id = p_clcb->conn_id; + if (dis_cb.dis_read_uuid_idx >= (sizeof(dis_attr_uuid)/sizeof(dis_attr_uuid[0]))) { + LOG(ERROR) << "invalid dis_cb.dis_read_uuid_idx"; + return; + } + + read_type = dis_attr_uuid[dis_cb.dis_read_uuid_idx]; + VLOG(1) << __func__ << StringPrintf("op_code: 0x%02x status: 0x%02x read_type: 0x%04x", op, status, read_type); @@ -428,7 +435,7 @@ tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR* p_info) { * * Description Read remote device DIS information. * - * Returns void + * Returns true on success, false otherwise * ******************************************************************************/ bool DIS_ReadDISInfo(const RawAddress& peer_bda, tDIS_READ_CBACK* p_cback, @@ -453,8 +460,10 @@ bool DIS_ReadDISInfo(const RawAddress& peer_bda, tDIS_READ_CBACK* p_cback, << StringPrintf(" cl_read_uuid: 0x%04x", dis_attr_uuid[dis_cb.dis_read_uuid_idx]); - GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id, - BT_TRANSPORT_LE); + if (!GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id, + BT_TRANSPORT_LE)) { + conn_id = GATT_INVALID_CONN_ID; + } /* need to enhance it as multiple service is needed */ srvc_eng_request_channel(peer_bda, SRVC_ID_DIS); diff --git a/system/stack/srvc/srvc_eng.cc b/system/stack/srvc/srvc_eng.cc index 73355e2839acff9a140485b5db89437caad996f4..6fe0463209aac3027e888ac42cc56911c3ead015 100644 --- a/system/stack/srvc/srvc_eng.cc +++ b/system/stack/srvc/srvc_eng.cc @@ -16,18 +16,17 @@ * ******************************************************************************/ -#include "bt_target.h" +#include + #include "gatt_api.h" -#include "gatt_int.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "srvc_dis_int.h" #include "srvc_eng_int.h" +#include "stack/include/bt_uuid16.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#include - using base::StringPrintf; static void srvc_eng_s_request_cback(uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type, tGATTS_DATA* p_data); diff --git a/system/stack/test/a2dp/a2dp_aac_unittest.cc b/system/stack/test/a2dp/a2dp_aac_unittest.cc index 47d8a10bfd9c642cec458ac8d29c91463181caeb..21c07006df9fea9c85715c1427865254422ec1c7 100644 --- a/system/stack/test/a2dp/a2dp_aac_unittest.cc +++ b/system/stack/test/a2dp/a2dp_aac_unittest.cc @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -32,15 +31,13 @@ #include "common/time_util.h" #include "os/log.h" #include "osi/include/allocator.h" -#include "osi/test/AllocationTestHarness.h" -#include "stack/include/bt_hdr.h" #include "stack/include/a2dp_aac_decoder.h" #include "stack/include/a2dp_aac_encoder.h" #include "stack/include/avdt_api.h" +#include "stack/include/bt_hdr.h" #include "test_util.h" #include "wav_reader.h" -void allocation_tracker_uninit(void); namespace { constexpr uint32_t kAacReadSize = 1024 * 2 * 2; constexpr uint32_t kA2dpTickUs = 23 * 1000; @@ -75,13 +72,10 @@ namespace testing { static BT_HDR* packet = nullptr; static WavReader wav_reader = WavReader(GetWavFilePath(kWavFile).c_str()); -class A2dpAacTest : public AllocationTestHarness { +class A2dpAacTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); common::InitFlags::SetAllForTesting(); - // Disable our allocation tracker to allow ASAN full range - allocation_tracker_uninit(); SetCodecConfig(); encoder_iface_ = const_cast( A2DP_GetEncoderInterfaceAac(kCodecInfoAacCapability)); @@ -103,7 +97,6 @@ class A2dpAacTest : public AllocationTestHarness { decoder_iface_->decoder_cleanup(); } A2DP_UnloadDecoderAac(); - AllocationTestHarness::TearDown(); } void SetCodecConfig() { @@ -177,9 +170,7 @@ TEST_F(A2dpAacTest, a2dp_source_read_underflow) { usleep(kA2dpTickUs); timestamp_us = bluetooth::common::time_gettimeofday_us(); encoder_iface_->send_frames(timestamp_us); - std::promise promise; - log_capture_->WaitUntilLogContains(&promise, - "a2dp_aac_encode_frames: underflow"); + log_capture_->WaitUntilLogContains("a2dp_aac_encode_frames: underflow"); } TEST_F(A2dpAacTest, a2dp_enqueue_cb_is_invoked) { @@ -189,7 +180,7 @@ TEST_F(A2dpAacTest, a2dp_enqueue_cb_is_invoked) { return len; }; auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool { - LOG_DEBUG("%s", kEnqueueCallbackIsInvoked); + LOG_INFO("%s", kEnqueueCallbackIsInvoked); osi_free(p_buf); return false; }; @@ -199,8 +190,7 @@ TEST_F(A2dpAacTest, a2dp_enqueue_cb_is_invoked) { usleep(kA2dpTickUs); timestamp_us = bluetooth::common::time_gettimeofday_us(); encoder_iface_->send_frames(timestamp_us); - std::promise promise; - log_capture_->WaitUntilLogContains(&promise, kEnqueueCallbackIsInvoked); + log_capture_->WaitUntilLogContains(kEnqueueCallbackIsInvoked); } TEST_F(A2dpAacTest, decoded_data_cb_not_invoked_when_empty_packet) { @@ -215,7 +205,7 @@ TEST_F(A2dpAacTest, decoded_data_cb_not_invoked_when_empty_packet) { TEST_F(A2dpAacTest, decoded_data_cb_invoked) { log_capture_ = std::make_unique(); auto data_cb = +[](uint8_t* p_buf, uint32_t len) { - LOG_DEBUG("%s", kDecodedDataCallbackIsInvoked); + LOG_INFO("%s", kDecodedDataCallbackIsInvoked); }; InitializeDecoder(data_cb); @@ -227,7 +217,7 @@ TEST_F(A2dpAacTest, decoded_data_cb_invoked) { }; auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool { packet = p_buf; - LOG_DEBUG("%s", kEnqueueCallbackIsInvoked); + LOG_INFO("%s", kEnqueueCallbackIsInvoked); return false; }; InitializeEncoder(true, read_cb, enqueue_cb); @@ -238,8 +228,7 @@ TEST_F(A2dpAacTest, decoded_data_cb_invoked) { timestamp_us = bluetooth::common::time_gettimeofday_us(); encoder_iface_->send_frames(timestamp_us); - std::promise promise; - log_capture_->WaitUntilLogContains(&promise, kEnqueueCallbackIsInvoked); + log_capture_->WaitUntilLogContains(kEnqueueCallbackIsInvoked); decoder_iface_->decode_packet(packet); osi_free(packet); ASSERT_TRUE(log_capture_->Find(kDecodedDataCallbackIsInvoked)); @@ -288,9 +277,7 @@ TEST_F(A2dpAacTest, effective_mtu_when_peer_does_not_support_3mbps) { TEST_F(A2dpAacTest, debug_codec_dump) { log_capture_ = std::make_unique(); a2dp_codecs_->debug_codec_dump(2); - std::promise promise; - log_capture_->WaitUntilLogContains(&promise, - "Current Codec: AAC"); + log_capture_->WaitUntilLogContains("Current Codec: AAC"); } TEST_F(A2dpAacTest, codec_info_string) { diff --git a/system/stack/test/a2dp/a2dp_opus_unittest.cc b/system/stack/test/a2dp/a2dp_opus_unittest.cc index 42cbc931fbe75c6094b0c2eb576192b123fa8ccf..8e13bef9c6434e7954b9c9b43cc81769c588d33b 100644 --- a/system/stack/test/a2dp/a2dp_opus_unittest.cc +++ b/system/stack/test/a2dp/a2dp_opus_unittest.cc @@ -14,8 +14,6 @@ * limitations under the License. */ -#include "stack/include/a2dp_vendor_opus.h" - #include #include #include @@ -32,13 +30,12 @@ #include "common/time_util.h" #include "os/log.h" #include "osi/include/allocator.h" -#include "osi/test/AllocationTestHarness.h" +#include "stack/include/a2dp_vendor_opus.h" #include "stack/include/a2dp_vendor_opus_constants.h" #include "stack/include/bt_hdr.h" #include "test_util.h" #include "wav_reader.h" -void allocation_tracker_uninit(void); namespace { constexpr uint32_t kA2dpTickUs = 23 * 1000; constexpr char kWavFile[] = "test/a2dp/raw_data/pcm1644s.wav"; @@ -69,13 +66,10 @@ static BT_HDR* packet = nullptr; static WavReader wav_reader = WavReader(GetWavFilePath(kWavFile).c_str()); static std::promise promise; -class A2dpOpusTest : public AllocationTestHarness { +class A2dpOpusTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); common::InitFlags::SetAllForTesting(); - // Disable our allocation tracker to allow ASAN full range - allocation_tracker_uninit(); SetCodecConfig(); encoder_iface_ = const_cast( A2DP_VendorGetEncoderInterfaceOpus(kCodecInfoOpusCapability)); @@ -95,7 +89,6 @@ class A2dpOpusTest : public AllocationTestHarness { if (decoder_iface_ != nullptr) { decoder_iface_->decoder_cleanup(); } - AllocationTestHarness::TearDown(); } void SetCodecConfig() { diff --git a/system/stack/test/a2dp/a2dp_sbc_unittest.cc b/system/stack/test/a2dp/a2dp_sbc_unittest.cc index 9225f7a2879546a01eedb7f11ea799b8013ca49f..24b03feb35d49eca684c0f13f2e861e1ac7871d7 100644 --- a/system/stack/test/a2dp/a2dp_sbc_unittest.cc +++ b/system/stack/test/a2dp/a2dp_sbc_unittest.cc @@ -33,15 +33,13 @@ #include "common/time_util.h" #include "os/log.h" #include "osi/include/allocator.h" -#include "osi/test/AllocationTestHarness.h" -#include "stack/include/bt_hdr.h" #include "stack/include/a2dp_sbc_decoder.h" #include "stack/include/a2dp_sbc_encoder.h" #include "stack/include/avdt_api.h" +#include "stack/include/bt_hdr.h" #include "test_util.h" #include "wav_reader.h" -void allocation_tracker_uninit(void); namespace { constexpr uint32_t kSbcReadSize = 512; constexpr uint32_t kA2dpTickUs = 23 * 1000; @@ -72,13 +70,10 @@ static BT_HDR* packet = nullptr; static WavReader wav_reader = WavReader(GetWavFilePath(kWavFile).c_str()); static std::promise promise; -class A2dpSbcTest : public AllocationTestHarness { +class A2dpSbcTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); common::InitFlags::SetAllForTesting(); - // Disable our allocation tracker to allow ASAN full range - allocation_tracker_uninit(); SetCodecConfig(); encoder_iface_ = const_cast( A2DP_GetEncoderInterfaceSbc(kCodecInfoSbcCapability)); @@ -100,7 +95,6 @@ class A2dpSbcTest : public AllocationTestHarness { decoder_iface_->decoder_cleanup(); } A2DP_UnloadDecoderSbc(); - AllocationTestHarness::TearDown(); } void SetCodecConfig() { @@ -293,9 +287,7 @@ TEST_F(A2dpSbcTest, effective_mtu_when_peer_does_not_support_3mbps) { TEST_F(A2dpSbcTest, debug_codec_dump) { log_capture_ = std::make_unique(); a2dp_codecs_->debug_codec_dump(2); - std::promise promise; - log_capture_->WaitUntilLogContains(&promise, - "Current Codec: SBC"); + log_capture_->WaitUntilLogContains("Current Codec: SBC"); } TEST_F(A2dpSbcTest, codec_info_string) { diff --git a/system/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc b/system/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc index 5d1a30385acb2358cb54c20294bc350e51ed67fa..44b90806738639c78e32341d17af53939066f851 100644 --- a/system/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc +++ b/system/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc @@ -23,11 +23,9 @@ #include #include "osi/include/allocator.h" -#include "osi/test/AllocationTestHarness.h" #include "stack/include/bt_hdr.h" #include "stack/include/ldacBT_bco_for_fluoride.h" -void allocation_tracker_uninit(void); namespace { uint8_t* Data(BT_HDR* packet) { return packet->data + packet->offset; } @@ -37,16 +35,8 @@ uint8_t* Data(BT_HDR* packet) { return packet->data + packet->offset; } /** * Test class to test selected functionality in stack/a2dp */ -class A2dpStackTest : public AllocationTestHarness { +class A2dpStackTest : public ::testing::Test { protected: - void SetUp() override { - AllocationTestHarness::SetUp(); - // Disable our allocation tracker to allow ASAN full range - allocation_tracker_uninit(); - } - - void TearDown() override { AllocationTestHarness::TearDown(); } - BT_HDR* AllocateL2capPacket(const std::vector data) const { auto packet = AllocatePacket(data.size()); std::copy(data.cbegin(), data.cend(), Data(packet)); diff --git a/system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc b/system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc index 7e27783815db7838d675bd64162411c88d1cc1ee..34c619891e34d2e43dc2ef81692a3fd439533d42 100644 --- a/system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc +++ b/system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc @@ -16,21 +16,19 @@ #include "stack/include/a2dp_vendor_ldac.h" -#include #include #include +#include "common/init_flags.h" #include "common/testing/log_capture.h" #include "common/time_util.h" #include "osi/include/allocator.h" -#include "osi/test/AllocationTestHarness.h" #include "stack/include/a2dp_vendor_ldac_constants.h" #include "stack/include/avdt_api.h" #include "stack/include/bt_hdr.h" #include "test_util.h" #include "wav_reader.h" -void allocation_tracker_uninit(void); namespace { constexpr uint32_t kA2dpTickUs = 23 * 1000; constexpr char kWavFile[] = "test/a2dp/raw_data/pcm1644s.wav"; @@ -55,13 +53,10 @@ namespace testing { // static BT_HDR* packet = nullptr; static WavReader wav_reader = WavReader(GetWavFilePath(kWavFile).c_str()); -class A2dpLdacTest : public AllocationTestHarness { +class A2dpLdacTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); common::InitFlags::SetAllForTesting(); - // Disable our allocation tracker to allow ASAN full range - allocation_tracker_uninit(); SetCodecConfig(); encoder_iface_ = const_cast( A2DP_VendorGetEncoderInterfaceLdac(kCodecInfoLdacCapability)); @@ -81,7 +76,6 @@ class A2dpLdacTest : public AllocationTestHarness { if (decoder_iface_ != nullptr) { decoder_iface_->decoder_cleanup(); } - AllocationTestHarness::TearDown(); } // NOTE: Make a super func for all codecs @@ -151,9 +145,7 @@ TEST_F(A2dpLdacTest, a2dp_source_read_underflow) { usleep(kA2dpTickUs); timestamp_us = bluetooth::common::time_gettimeofday_us(); encoder_iface_->send_frames(timestamp_us); - std::promise promise; - // log_capture_->WaitUntilLogContains(&promise, - // "a2dp_ldac_encode_frames: underflow"); + // log_capture_->WaitUntilLogContains("a2dp_ldac_encode_frames: underflow"); } } // namespace testing diff --git a/system/stack/test/ble_advertiser_test.cc b/system/stack/test/ble_advertiser_test.cc deleted file mode 100644 index a0ae0182ed5d62ec116a13a7af579d3a9b997084..0000000000000000000000000000000000000000 --- a/system/stack/test/ble_advertiser_test.cc +++ /dev/null @@ -1,1145 +0,0 @@ -/****************************************************************************** - * - * Copyright 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "stack/include/ble_advertiser.h" - -#include -#include - -#include - -#include "stack/btm/ble_advertiser_hci_interface.h" -#include "types/raw_address.h" - -using ::testing::Args; -using ::testing::Contains; -using ::testing::DoAll; -using ::testing::ElementsAreArray; -using ::testing::Exactly; -using ::testing::Field; -using ::testing::IsEmpty; -using ::testing::SaveArg; -using ::testing::SizeIs; -using ::testing::_; -using base::Bind; -using status_cb = BleAdvertiserHciInterface::status_cb; -using parameters_cb = BleAdvertiserHciInterface::parameters_cb; -using SetEnableData = BleAdvertiserHciInterface::SetEnableData; - -const int num_adv_instances = 16; - -/* Below are methods that must be implemented if we don't want to compile the - * whole stack. They will be removed, or changed into mocks one by one in the - * future, as the refactoring progresses */ -bool BTM_BleLocalPrivacyEnabled() { return true; } -void btm_acl_update_conn_addr(uint16_t conn_handle, const RawAddress& address) { -} -void btm_gen_resolvable_private_addr( - base::Callback cb) { - cb.Run(RawAddress::kEmpty); -} - -alarm_callback_t last_alarm_cb = nullptr; -void* last_alarm_data = nullptr; -void alarm_set_on_mloop(alarm_t* alarm, uint64_t interval_ms, - alarm_callback_t cb, void* data) { - last_alarm_cb = cb; - last_alarm_data = data; -} - -void alarm_cancel(alarm_t* alarm) {} -alarm_t* alarm_new_periodic(const char* name) { return nullptr; } -alarm_t* alarm_new(const char* name) { return nullptr; } -void alarm_free(alarm_t* alarm) {} - -uint64_t btm_get_next_private_addrress_interval_ms() { return 15 * 60 * 1000; } - -namespace { -void DoNothing(uint8_t) {} - -void DoNothing2(uint8_t, uint8_t) {} - -void TriggerRandomAddressUpdate() { - // Call to StartAdvertisingSet set the last_alarm_cb to random address timeout - // callback. Call it now in order to trigger address update - last_alarm_cb(last_alarm_data); -} - -constexpr uint8_t INTERMEDIATE = - 0x00; // Intermediate fragment of fragmented data -constexpr uint8_t FIRST = 0x01; // First fragment of fragmented data -constexpr uint8_t LAST = 0x02; // Last fragment of fragmented data -constexpr uint8_t COMPLETE = 0x03; // Complete extended advertising data - -class AdvertiserHciMock : public BleAdvertiserHciInterface { - public: - AdvertiserHciMock() = default; - AdvertiserHciMock(const AdvertiserHciMock&) = delete; - AdvertiserHciMock& operator=(const AdvertiserHciMock&) = delete; - - ~AdvertiserHciMock() override = default; - - MOCK_METHOD1(ReadInstanceCount, - void(base::Callback)); - MOCK_METHOD1(SetAdvertisingEventObserver, - void(AdvertisingEventObserver* observer)); - MOCK_METHOD6(SetAdvertisingData, - void(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t*, status_cb)); - MOCK_METHOD6(SetScanResponseData, - void(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t*, status_cb)); - MOCK_METHOD3(SetRandomAddress, void(uint8_t, const RawAddress&, status_cb)); - MOCK_METHOD3(Enable, void(uint8_t, std::vector, status_cb)); - MOCK_METHOD5(SetPeriodicAdvertisingParameters, - void(uint8_t, uint16_t, uint16_t, uint16_t, status_cb)); - MOCK_METHOD5(SetPeriodicAdvertisingData, - void(uint8_t, uint8_t, uint8_t, uint8_t*, status_cb)); - MOCK_METHOD((void), SetPeriodicAdvertisingEnable, - (bool, bool, uint8_t, status_cb), (override)); - MOCK_METHOD2(RemoveAdvertisingSet, void(uint8_t, status_cb)); - MOCK_METHOD1(ClearAdvertisingSets, void(status_cb)); - - MOCK_METHOD9(SetParameters1, - void(uint8_t, uint16_t, uint32_t, uint32_t, uint8_t, uint8_t, - const RawAddress&, uint8_t, const RawAddress&)); - MOCK_METHOD8(SetParameters2, void(uint8_t, int8_t, uint8_t, uint8_t, uint8_t, - uint8_t, uint8_t, parameters_cb)); - - void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min, - uint32_t adv_int_max, uint8_t channel_map, - uint8_t own_address_type, const RawAddress& own_address, - uint8_t peer_address_type, const RawAddress& peer_address, - uint8_t filter_policy, int8_t tx_power, - uint8_t primary_phy, uint8_t secondary_max_skip, - uint8_t secondary_phy, uint8_t advertising_sid, - uint8_t scan_request_notify_enable, - parameters_cb cmd_complete) override { - SetParameters1(handle, properties, adv_int_min, adv_int_max, channel_map, - own_address_type, own_address, peer_address_type, - peer_address); - SetParameters2(filter_policy, tx_power, primary_phy, secondary_max_skip, - secondary_phy, advertising_sid, scan_request_notify_enable, - cmd_complete); - }; - - bool QuirkAdvertiserZeroHandle() override { return false; } -}; - -} // namespace - -class BleAdvertisingManagerTest : public testing::Test { - protected: - int reg_inst_id = -1; - int reg_status = -1; - int set_params_status = -1; - int set_data_status = -1; - int enable_status = -1; - int start_advertising_status = -1; - int start_advertising_set_advertiser_id = -1; - int start_advertising_set_tx_power = -1; - int start_advertising_set_status = -1; - - std::unique_ptr hci_mock; - - void SetUp() override { - hci_mock.reset(new AdvertiserHciMock()); - - base::Callback inst_cnt_Cb; - EXPECT_CALL(*hci_mock, ReadInstanceCount(_)) - .Times(Exactly(1)) - .WillOnce(SaveArg<0>(&inst_cnt_Cb)); - - BleAdvertisingManager::Initialize(hci_mock.get()); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // we are a truly gracious fake controller, let the command succeed! - inst_cnt_Cb.Run(num_adv_instances); - } - - void TearDown() override { - BleAdvertisingManager::CleanUp(); - hci_mock.reset(); - } - - public: - void RegistrationCb(uint8_t inst_id, uint8_t status) { - reg_inst_id = inst_id; - reg_status = status; - } - - void SetParametersCb(uint8_t status, int8_t tx_power) { - set_params_status = status; - } - void SetDataCb(uint8_t status) { set_data_status = status; } - void EnableCb(uint8_t status) { enable_status = status; } - void StartAdvertisingCb(uint8_t status) { start_advertising_status = status; } - void StartAdvertisingSetCb(uint8_t advertiser_id, int8_t tx_power, - uint8_t status) { - start_advertising_set_advertiser_id = advertiser_id; - start_advertising_set_tx_power = tx_power; - start_advertising_set_status = status; - } - - void StartAdvertisingSetWithSpecificAddressType(int8_t own_address_type); -}; - -TEST_F(BleAdvertisingManagerTest, test_registration) { - for (int i = 0; i < num_adv_instances; i++) { - BleAdvertisingManager::Get()->RegisterAdvertiser(Bind( - &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - EXPECT_EQ(i, reg_inst_id); - } - - // This call should return an error - no more advertisers left. - BleAdvertisingManager::Get()->RegisterAdvertiser( - Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(ADVERTISE_FAILED_TOO_MANY_ADVERTISERS, reg_status); - // Don't bother checking inst_id, it doesn't matter - - status_cb remove_cb; - EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(_, _)) - .Times(1) - .WillOnce(SaveArg<1>(&remove_cb)); - BleAdvertisingManager::Get()->Unregister(5); - remove_cb.Run(0); - - // One advertiser was freed, so should be able to register one now - BleAdvertisingManager::Get()->RegisterAdvertiser( - Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - EXPECT_EQ(5, reg_inst_id); -} - -/* This test verifies that the following flow is working correctly: register, - * set parameters, set data, enable, ... (advertise) ..., unregister*/ -TEST_F(BleAdvertisingManagerTest, test_android_flow) { - BleAdvertisingManager::Get()->RegisterAdvertiser( - Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - int advertiser_id = reg_inst_id; - - parameters_cb set_params_cb; - tBTM_BLE_ADV_PARAMS params; - EXPECT_CALL(*hci_mock, SetParameters1(advertiser_id, _, _, _, _, _, _, _, _)) - .Times(1); - EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - BleAdvertisingManager::Get()->SetParameters( - advertiser_id, ¶ms, - Bind(&BleAdvertisingManagerTest::SetParametersCb, - base::Unretained(this))); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // we are a truly gracious fake controller, let the command succeed! - set_params_cb.Run(0, 0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status); - - status_cb set_data_cb; - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, std::vector(), - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - set_data_cb.Run(0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); - - status_cb enable_cb; - EXPECT_CALL(*hci_mock, - Enable(0x01 /* enable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - BleAdvertisingManager::Get()->Enable( - advertiser_id, true, - Bind(&BleAdvertisingManagerTest::EnableCb, base::Unretained(this)), 0, 0, - base::Callback()); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - enable_cb.Run(0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, enable_status); - - /* fake controller should be advertising */ - - EXPECT_CALL(*hci_mock, - Enable(0x00 /* disable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - status_cb remove_cb; - EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(_, _)) - .Times(1) - .WillOnce(SaveArg<1>(&remove_cb)); - BleAdvertisingManager::Get()->Unregister(advertiser_id); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - enable_cb.Run(0); - remove_cb.Run(0); -} - -/* This test verifies that when advertising data is set, tx power and flags will - * be properly filled. */ -TEST_F(BleAdvertisingManagerTest, test_adv_data_filling) { - BleAdvertisingManager::Get()->RegisterAdvertiser( - Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - int advertiser_id = reg_inst_id; - - parameters_cb set_params_cb; - tBTM_BLE_ADV_PARAMS params; - params.advertising_event_properties = - BleAdvertisingManager::advertising_prop_legacy_connectable; - params.tx_power = -15; - EXPECT_CALL(*hci_mock, SetParameters1(advertiser_id, _, _, _, _, _, _, _, _)) - .Times(1); - EXPECT_CALL(*hci_mock, SetParameters2(_, params.tx_power, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - BleAdvertisingManager::Get()->SetParameters( - advertiser_id, ¶ms, - Bind(&BleAdvertisingManagerTest::SetParametersCb, - base::Unretained(this))); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // let the set parameters command succeed! - set_params_cb.Run(0, 0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status); - - status_cb set_data_cb; - /* verify that flags will be added, and tx power filled, if call to SetData - * contained only tx power, and the advertisement is connectable */ - uint8_t expected_adv_data[] = { - 0x02 /* len */, 0x01 /* flags */, - 0x02 /* flags value */, 0x02 /* len */, - 0x0A /* tx_power */, static_cast(params.tx_power)}; - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, _, _, _, _, _)) - .With(Args<4, 3>(ElementsAreArray(expected_adv_data))) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, - std::vector({0x02 /* len */, 0x0A /* tx_power */, 0x00}), - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - set_data_cb.Run(0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); -} - -/* This test verifies that when advertising is non-connectable, flags will not - * be added. */ -TEST_F(BleAdvertisingManagerTest, test_adv_data_not_filling) { - BleAdvertisingManager::Get()->RegisterAdvertiser( - Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - int advertiser_id = reg_inst_id; - - parameters_cb set_params_cb; - tBTM_BLE_ADV_PARAMS params; - params.advertising_event_properties = - BleAdvertisingManager::advertising_prop_legacy_non_connectable; - params.tx_power = -15; - EXPECT_CALL(*hci_mock, SetParameters1(advertiser_id, _, _, _, _, _, _, _, _)) - .Times(1); - EXPECT_CALL(*hci_mock, - SetParameters2(_, (uint8_t)params.tx_power, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - BleAdvertisingManager::Get()->SetParameters( - advertiser_id, ¶ms, - Bind(&BleAdvertisingManagerTest::SetParametersCb, - base::Unretained(this))); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // let the set parameters command succeed! - set_params_cb.Run(0, -15); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status); - - status_cb set_data_cb; - /* verify that flags will not be added */ - uint8_t expected_adv_data[] = { - 0x02 /* len */, 0xFF /* manufacturer specific */, 0x01 /* data */}; - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, _, _, _, _, _)) - .With(Args<4, 3>(ElementsAreArray(expected_adv_data))) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, std::vector({0x02 /* len */, 0xFF, 0x01}), - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - set_data_cb.Run(0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); -} - -TEST_F(BleAdvertisingManagerTest, test_reenabling) { - BleAdvertisingManager::Get()->RegisterAdvertiser( - Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - EXPECT_EQ(0, reg_inst_id); - - uint8_t advertiser_id = reg_inst_id; - status_cb enable_cb; - EXPECT_CALL(*hci_mock, - Enable(0x01 /* enable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - BleAdvertisingManager::Get()->Enable(advertiser_id, true, Bind(DoNothing), 0, - 0, Bind(DoNothing)); - enable_cb.Run(0); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - EXPECT_CALL(*hci_mock, - Enable(0x01 /* enable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - BleAdvertisingManager::Get()->OnAdvertisingSetTerminated(advertiser_id, 0x00, - 0x01ed, 0x00); - enable_cb.Run(0); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); -} - -/* Make sure that instance is not reenabled if it's already disabled */ -TEST_F(BleAdvertisingManagerTest, test_reenabling_disabled_instance) { - uint8_t advertiser_id = 1; // any unregistered value - - EXPECT_CALL(*hci_mock, Enable(_, _, _)).Times(Exactly(0)); - BleAdvertisingManager::Get()->OnAdvertisingSetTerminated(advertiser_id, 0x00, - 0x05, 0x00); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); -} - -/* This test verifies that the only flow that is currently used on Android, is - * working correctly in happy case scenario. */ -void BleAdvertisingManagerTest::StartAdvertisingSetWithSpecificAddressType( - int8_t own_address_type) { - std::vector adv_data; - std::vector scan_resp; - tBTM_BLE_ADV_PARAMS params; - params.own_address_type = own_address_type; - tBLE_PERIODIC_ADV_PARAMS periodic_params; - periodic_params.enable = false; - std::vector periodic_data; - - parameters_cb set_params_cb; - status_cb set_address_cb; - status_cb set_data_cb; - status_cb set_scan_resp_data_cb; - status_cb enable_cb; - EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _, _, _, _)).Times(1); - EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - if (own_address_type != BLE_ADDR_PUBLIC) { - EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _)) - .Times(1) - .WillOnce(SaveArg<2>(&set_address_cb)); - } - EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, SetScanResponseData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_scan_resp_data_cb)); - EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, _, _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - - BleAdvertisingManager::Get()->StartAdvertisingSet( - Bind(&BleAdvertisingManagerTest::StartAdvertisingSetCb, - base::Unretained(this)), - ¶ms, adv_data, scan_resp, &periodic_params, periodic_data, - 0 /* duration */, 0 /* maxExtAdvEvents */, Bind(DoNothing2)); - - // we are a truly gracious fake controller, let the commands succeed! - int selected_tx_power = -15; - set_params_cb.Run(0, selected_tx_power); - if (own_address_type != BLE_ADDR_PUBLIC) { - set_address_cb.Run(0); - } - set_data_cb.Run(0); - set_scan_resp_data_cb.Run(0); - enable_cb.Run(0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, start_advertising_set_status); - EXPECT_EQ(selected_tx_power, start_advertising_set_tx_power); - int advertiser_id = start_advertising_set_advertiser_id; - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // ... advertising ... - - // Disable advertiser - status_cb disable_cb; - EXPECT_CALL(*hci_mock, - Enable(0x00 /* disable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&disable_cb)); - status_cb remove_cb; - EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(advertiser_id, _)) - .Times(1) - .WillOnce(SaveArg<1>(&remove_cb)); - BleAdvertisingManager::Get()->Unregister(advertiser_id); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - disable_cb.Run(0); - remove_cb.Run(0); -} - -TEST_F(BleAdvertisingManagerTest, - test_start_advertising_set_default_address_type) { - StartAdvertisingSetWithSpecificAddressType(BLE_ADDR_ANONYMOUS); -} - -TEST_F(BleAdvertisingManagerTest, - test_start_advertising_set_public_address_type) { - StartAdvertisingSetWithSpecificAddressType(BLE_ADDR_PUBLIC); -} - -TEST_F(BleAdvertisingManagerTest, - test_start_advertising_set_random_address_type) { - StartAdvertisingSetWithSpecificAddressType(BLE_ADDR_RANDOM); -} - -TEST_F(BleAdvertisingManagerTest, test_start_advertising_set_params_failed) { - BleAdvertisingManager::Get()->RegisterAdvertiser( - Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - int advertiser_id = reg_inst_id; - - std::vector adv_data; - std::vector scan_resp; - tBTM_BLE_ADV_PARAMS params; - - parameters_cb set_params_cb; - EXPECT_CALL(*hci_mock, SetParameters1(advertiser_id, _, _, _, _, _, _, _, _)) - .Times(1); - EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, _, _, _, _, _)) - .Times(Exactly(0)); - - BleAdvertisingManager::Get()->StartAdvertising( - advertiser_id, - Bind(&BleAdvertisingManagerTest::StartAdvertisingCb, - base::Unretained(this)), - ¶ms, adv_data, scan_resp, 0, base::Callback()); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // set params failed - set_params_cb.Run(0x01, 0); - - // Expect the whole flow to fail right away - EXPECT_EQ(BTM_BLE_MULTI_ADV_FAILURE, start_advertising_status); -} - -TEST_F(BleAdvertisingManagerTest, test_data_sender) { - // prepare test input vector - const int max_data_size = 1650; - std::vector data(max_data_size); - for (int i = 0; i < max_data_size; i++) data[i] = i; - - BleAdvertisingManager::Get()->RegisterAdvertiser( - Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - int advertiser_id = reg_inst_id; - - status_cb set_data_cb; - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, - SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _)) - .Times(5) - .WillRepeatedly(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 144, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, data, - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - for (int i = 0; i < 7; i++) { - set_data_cb.Run(0x00); - } - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - // Expect the whole flow to succeed - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); - - // ***************** Try again with different data size ********************* - data.resize(503); - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, - SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _)) - .Times(1) - .WillRepeatedly(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 1, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, data, - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - for (int i = 0; i < 3; i++) { - set_data_cb.Run(0x00); - } - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - // Expect the whole flow to succeed - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); - - // ***************** Try again with different data size ********************* - data.resize(502); - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 251, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, data, - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - for (int i = 0; i < 2; i++) { - set_data_cb.Run(0x00); - } - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - // Expect the whole flow to succeed - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); - - // ***************** Try again with different data size ********************* - data.resize(501); - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 250, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, data, - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - for (int i = 0; i < 2; i++) { - set_data_cb.Run(0x00); - } - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - // Expect the whole flow to succeed - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); - - // ***************** Try again with different data size ********************* - data.resize(251); - EXPECT_CALL(*hci_mock, - SetAdvertisingData(advertiser_id, COMPLETE, _, 251, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, data, - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - set_data_cb.Run(0x00); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - // Expect the whole flow to succeed - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); - - // ***************** Try again with different data size ********************* - data.resize(120); - EXPECT_CALL(*hci_mock, - SetAdvertisingData(advertiser_id, COMPLETE, _, 120, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, data, - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - set_data_cb.Run(0x00); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - // Expect the whole flow to succeed - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); - - // ***************** Try again with different data size ********************* - data.resize(0); - EXPECT_CALL(*hci_mock, - SetAdvertisingData(advertiser_id, COMPLETE, _, 0, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - BleAdvertisingManager::Get()->SetData( - advertiser_id, false, data, - Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); - set_data_cb.Run(0x00); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - // Expect the whole flow to succeed - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); -} - -/* This test makes sure that conectable advertisment with timeout will get it's - * address updated once the timeout passes and one tries to enable it again.*/ -TEST_F(BleAdvertisingManagerTest, - test_connectable_address_update_during_timeout) { - std::vector adv_data; - std::vector scan_resp; - tBTM_BLE_ADV_PARAMS params; - params.own_address_type = BLE_ADDR_ANONYMOUS; - params.advertising_event_properties = 0x1 /* connectable */; - tBLE_PERIODIC_ADV_PARAMS periodic_params; - periodic_params.enable = false; - std::vector periodic_data; - - uint8_t maxExtAdvEvents = 50; - - parameters_cb set_params_cb; - status_cb set_address_cb; - status_cb set_data_cb; - status_cb set_scan_resp_data_cb; - status_cb enable_cb; - EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _, _, _, _)).Times(1); - EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _)) - .Times(1) - .WillOnce(SaveArg<2>(&set_address_cb)); - EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, SetScanResponseData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_scan_resp_data_cb)); - EXPECT_CALL( - *hci_mock, - Enable( - 0x01 /* enable */, - AllOf(SizeIs(1), - Contains(Field(&SetEnableData::max_extended_advertising_events, - maxExtAdvEvents))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - - BleAdvertisingManager::Get()->StartAdvertisingSet( - Bind(&BleAdvertisingManagerTest::StartAdvertisingSetCb, - base::Unretained(this)), - ¶ms, adv_data, scan_resp, &periodic_params, periodic_data, - 0 /* duration */, maxExtAdvEvents, Bind(DoNothing2)); - - // we are a truly gracious fake controller, let the commands succeed! - int selected_tx_power = -15; - set_params_cb.Run(0, selected_tx_power); - set_address_cb.Run(0); - set_data_cb.Run(0); - set_scan_resp_data_cb.Run(0); - enable_cb.Run(0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, start_advertising_set_status); - EXPECT_EQ(selected_tx_power, start_advertising_set_tx_power); - int advertiser_id = start_advertising_set_advertiser_id; - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // ... advertising ... - - // No HCI calls should be triggered, becuase there is a timeout on a - // connectable advertisement. - TriggerRandomAddressUpdate(); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // Set terminated because we advertised maxExtAdvEvents times! - BleAdvertisingManager::Get()->OnAdvertisingSetTerminated( - 0x43 /*status */, advertiser_id, 0x00 /* conn_handle*/, maxExtAdvEvents); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // Try to Enable the advertiser. It should first update it's random address. - EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _)) - .Times(1) - .WillOnce(SaveArg<2>(&set_address_cb)); - EXPECT_CALL( - *hci_mock, - Enable( - 0x01 /* enable */, - AllOf(SizeIs(1), - Contains(Field(&SetEnableData::max_extended_advertising_events, - maxExtAdvEvents))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - BleAdvertisingManager::Get()->Enable( - advertiser_id, true, - Bind(&BleAdvertisingManagerTest::EnableCb, base::Unretained(this)), 0, - maxExtAdvEvents, Bind(DoNothing)); - set_address_cb.Run(0); - enable_cb.Run(0); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // Disable advertiser - status_cb disable_cb; - EXPECT_CALL(*hci_mock, - Enable(0x00 /* disable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&disable_cb)); - status_cb remove_cb; - EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(advertiser_id, _)) - .Times(1) - .WillOnce(SaveArg<1>(&remove_cb)); - BleAdvertisingManager::Get()->Unregister(advertiser_id); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - disable_cb.Run(0); - remove_cb.Run(0); -} - -/* This test makes sure that periodic advertising is stopped before - * unregistering the advertiser, if it was enabled. */ -TEST_F(BleAdvertisingManagerTest, test_periodic_adv_disable_on_unregister) { - std::vector adv_data; - std::vector scan_resp; - tBTM_BLE_ADV_PARAMS params; - params.own_address_type = BLE_ADDR_ANONYMOUS; - params.advertising_event_properties = 0x1 /* connectable */; - tBLE_PERIODIC_ADV_PARAMS periodic_params; - periodic_params.enable = true; // enable periodic advertising - std::vector periodic_data; - - parameters_cb set_params_cb; - status_cb set_address_cb; - status_cb set_data_cb; - status_cb set_scan_resp_data_cb; - status_cb enable_cb; - status_cb set_periodic_params_cb; - status_cb set_periodic_data_cb; - status_cb set_periodic_enable_cb; - EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _, _, _, _)).Times(1); - EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _)) - .Times(1) - .WillOnce(SaveArg<2>(&set_address_cb)); - EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, SetScanResponseData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_scan_resp_data_cb)); - EXPECT_CALL(*hci_mock, SetPeriodicAdvertisingParameters(_, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<4>(&set_periodic_params_cb)); - EXPECT_CALL(*hci_mock, SetPeriodicAdvertisingData(_, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<4>(&set_periodic_data_cb)); - EXPECT_CALL(*hci_mock, SetPeriodicAdvertisingEnable( - true /* enable */, false /* include_adi */, _, _)) - .Times(1) - .WillOnce(SaveArg<3>(&set_periodic_enable_cb)); - EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, _, _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - - BleAdvertisingManager::Get()->StartAdvertisingSet( - Bind(&BleAdvertisingManagerTest::StartAdvertisingSetCb, - base::Unretained(this)), - ¶ms, adv_data, scan_resp, &periodic_params, periodic_data, - 0 /* duration */, 0 /* maxExtAdvEvents */, Bind(DoNothing2)); - - // we are a truly gracious fake controller, let the commands succeed! - int selected_tx_power = -15; - set_params_cb.Run(0, selected_tx_power); - set_address_cb.Run(0); - set_data_cb.Run(0); - set_scan_resp_data_cb.Run(0); - set_periodic_params_cb.Run(0); - set_periodic_data_cb.Run(0); - set_periodic_enable_cb.Run(0); - enable_cb.Run(0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, start_advertising_set_status); - EXPECT_EQ(selected_tx_power, start_advertising_set_tx_power); - int advertiser_id = start_advertising_set_advertiser_id; - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // ... advertising ... - - // Unregister advertiser - should disable periodic advertising - status_cb disable_cb; - EXPECT_CALL(*hci_mock, - Enable(0x00 /* disable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&disable_cb)); - status_cb disable_periodic_cb; - EXPECT_CALL(*hci_mock, SetPeriodicAdvertisingEnable(false /* disable */, - false /* include_adi */, - advertiser_id, _)) - .Times(1) - .WillOnce(SaveArg<3>(&disable_periodic_cb)); - status_cb remove_cb; - EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(advertiser_id, _)) - .Times(1) - .WillOnce(SaveArg<1>(&remove_cb)); - BleAdvertisingManager::Get()->Unregister(advertiser_id); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - disable_cb.Run(0); - disable_periodic_cb.Run(0); - remove_cb.Run(0); -} - -TEST_F(BleAdvertisingManagerTest, test_suspend_resume) { - for (int i = 0; i < 10; i++) { - BleAdvertisingManager::Get()->RegisterAdvertiser(Bind( - &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); - EXPECT_EQ(i, reg_inst_id); - } - - std::array enabled = {{1, 3, 9}}; - - for (int advertiser_id : enabled) { - status_cb enable_cb; - EXPECT_CALL(*hci_mock, - Enable(0x01 /* enable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - BleAdvertisingManager::Get()->Enable( - advertiser_id, true, - Bind(&BleAdvertisingManagerTest::EnableCb, base::Unretained(this)), 0, - 0, base::Callback()); - enable_cb.Run(0); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - } - - // we have some advertisers registered, three advertising. - - // Call to Suspend() should disable all running advertisers - status_cb disable_cb; - EXPECT_CALL( - *hci_mock, - Enable(0x00 /* disable */, - AllOf(SizeIs(3), Contains(Field(&SetEnableData::handle, 1)), - Contains(Field(&SetEnableData::handle, 3)), - Contains(Field(&SetEnableData::handle, 9))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&disable_cb)); - - BleAdvertisingManager::Get()->Suspend(); - - disable_cb.Run(0); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // Call to Resume() should re-enable advertisers - status_cb enable_cb; - EXPECT_CALL( - *hci_mock, - Enable(0x01 /* enable */, - AllOf(SizeIs(3), Contains(Field(&SetEnableData::handle, 1)), - Contains(Field(&SetEnableData::handle, 3)), - Contains(Field(&SetEnableData::handle, 9))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - - BleAdvertisingManager::Get()->Resume(); - - enable_cb.Run(0); - - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); -} - -/* This test makes sure that conectable advertisment with timeout will get it's - * duration and maxExtAdvEvents updated, when it's terminated due to incoming - * connection.*/ -TEST_F(BleAdvertisingManagerTest, test_duration_update_during_timeout) { - std::vector adv_data; - std::vector scan_resp; - tBTM_BLE_ADV_PARAMS params; - params.own_address_type = BLE_ADDR_ANONYMOUS; - params.advertising_event_properties = 0x1 /* connectable */; - params.adv_int_min = params.adv_int_max = 0xA0 /* 100ms */; - tBLE_PERIODIC_ADV_PARAMS periodic_params; - periodic_params.enable = false; - std::vector periodic_data; - - uint8_t maxExtAdvEvents = 50; - uint16_t duration = 500 /* 5s */; - - parameters_cb set_params_cb; - status_cb set_address_cb; - status_cb set_data_cb; - status_cb set_scan_resp_data_cb; - status_cb enable_cb; - EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _, _, _, _)).Times(1); - EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _)) - .Times(1) - .WillOnce(SaveArg<2>(&set_address_cb)); - EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - EXPECT_CALL(*hci_mock, SetScanResponseData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_scan_resp_data_cb)); - EXPECT_CALL( - *hci_mock, - Enable(0x01 /* enable */, - AllOf(SizeIs(1), - Contains(AllOf( - Field(&SetEnableData::max_extended_advertising_events, - maxExtAdvEvents), - Field(&SetEnableData::duration, duration)))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&enable_cb)); - - BleAdvertisingManager::Get()->StartAdvertisingSet( - Bind(&BleAdvertisingManagerTest::StartAdvertisingSetCb, - base::Unretained(this)), - ¶ms, adv_data, scan_resp, &periodic_params, periodic_data, duration, - maxExtAdvEvents, Bind(DoNothing2)); - - // we are a truly gracious fake controller, let the commands succeed! - int selected_tx_power = -15; - set_params_cb.Run(0, selected_tx_power); - set_address_cb.Run(0); - set_data_cb.Run(0); - set_scan_resp_data_cb.Run(0); - enable_cb.Run(0); - EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, start_advertising_set_status); - EXPECT_EQ(selected_tx_power, start_advertising_set_tx_power); - int advertiser_id = start_advertising_set_advertiser_id; - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - // ... advertising ... - - sleep(1); - - std::vector setEnableData; - // Set terminated because we received connect request! Should trigger - // re-enabling of the set - EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, _, _)) - .Times(1) - .WillOnce(DoAll(SaveArg<1>(&setEnableData), SaveArg<2>(&enable_cb))); - - BleAdvertisingManager::Get()->OnAdvertisingSetTerminated( - 0x00 /* Advertising successfully ended with a connection being created */, - advertiser_id, 0x01fe /* conn_handle*/, 20 /* completed ExtAdvEvents */); - enable_cb.Run(0); - - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - uint16_t new_duration = setEnableData[0].duration; - uint8_t new_extAdvEvents = setEnableData[0].max_extended_advertising_events; - - // Sleep is not super-accurate, so assume the recomputed timeouts are around - // 4s +/- 100ms - EXPECT_NEAR((duration - new_duration), 100 /*4s */, 10); - EXPECT_NEAR((maxExtAdvEvents - new_extAdvEvents), 10, 1); - - // Disable advertiser - status_cb disable_cb; - EXPECT_CALL(*hci_mock, - Enable(0x00 /* disable */, - AllOf(SizeIs(1), Contains(Field(&SetEnableData::handle, - advertiser_id))), - _)) - .Times(1) - .WillOnce(SaveArg<2>(&disable_cb)); - status_cb remove_cb; - EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(advertiser_id, _)) - .Times(1) - .WillOnce(SaveArg<1>(&remove_cb)); - BleAdvertisingManager::Get()->Unregister(advertiser_id); - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); - - disable_cb.Run(0); - remove_cb.Run(0); -} - -/* This test verifies that stack cleanup, and shutdown happening while there is - * outstanding HCI command is not triggering the callback */ -TEST_F(BleAdvertisingManagerTest, test_cleanup_during_execution) { - std::vector adv_data; - std::vector scan_resp; - tBTM_BLE_ADV_PARAMS params; - params.own_address_type = BLE_ADDR_ANONYMOUS; - tBLE_PERIODIC_ADV_PARAMS periodic_params; - periodic_params.enable = false; - std::vector periodic_data; - - parameters_cb set_params_cb; - status_cb set_address_cb; - status_cb set_data_cb; - EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _, _, _, _)).Times(1); - EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<7>(&set_params_cb)); - EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _)) - .Times(1) - .WillOnce(SaveArg<2>(&set_address_cb)); - EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, _, _, _, _)) - .Times(1) - .WillOnce(SaveArg<5>(&set_data_cb)); - - BleAdvertisingManager::Get()->StartAdvertisingSet( - Bind(&BleAdvertisingManagerTest::StartAdvertisingSetCb, - base::Unretained(this)), - ¶ms, adv_data, scan_resp, &periodic_params, periodic_data, - 0 /* duration */, 0 /* maxExtAdvEvents */, Bind(DoNothing2)); - - // we are a truly gracious fake controller, let the commands succeed! - int selected_tx_power = -15; - set_params_cb.Run(0, selected_tx_power); - set_address_cb.Run(0); - - // Someone shut down the stack in the middle of flow, when the HCI Set - // Advertise Data was scheduled! - BleAdvertisingManager::Get()->CleanUp(); - - // The HCI call returns with status, and tries to execute the callback. This - // should just silently drop the call. If it got executed, we would get crash, - // because BleAdvertisingManager object was already deleted. - set_data_cb.Run(0); - - ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); -} - -void testRecomputeTimeout1(); -void testRecomputeTimeout2(); -void testRecomputeTimeout3(); - -TEST_F(BleAdvertisingManagerTest, test_recompute_timeout) { - testRecomputeTimeout1(); - testRecomputeTimeout2(); - testRecomputeTimeout3(); -} diff --git a/system/stack/test/btm/peer_packet_types_test.cc b/system/stack/test/btm/peer_packet_types_test.cc index 4b8485398e8777670c4d36e357b48879f46131cc..aeae23770c5d708047f95ba322b42c1ed36c98f7 100644 --- a/system/stack/test/btm/peer_packet_types_test.cc +++ b/system/stack/test/btm/peer_packet_types_test.cc @@ -16,12 +16,10 @@ * */ +#include "stack/acl/peer_packet_types.h" + #include #include -#include - -#include "stack/acl/peer_packet_types.h" -#include "stack/include/bt_types.h" namespace { diff --git a/system/stack/test/btm/sco_hci_test.cc b/system/stack/test/btm/sco_hci_test.cc index fd330ff1e532fe4503eece11b8fc44dabd0f781d..0dd96fa2c3aec09b904ec0d979b60bfd4d825a37 100644 --- a/system/stack/test/btm/sco_hci_test.cc +++ b/system/stack/test/btm/sco_hci_test.cc @@ -26,6 +26,8 @@ #include "btif/include/core_callbacks.h" #include "btif/include/stack_manager.h" #include "stack/btm/btm_sco.h" +#include "stack/include/hfp_lc3_decoder.h" +#include "stack/include/hfp_lc3_encoder.h" #include "stack/include/hfp_msbc_decoder.h" #include "stack/include/hfp_msbc_encoder.h" #include "test/common/mock_functions.h" @@ -43,15 +45,22 @@ using testing::Ge; using testing::Le; using testing::Test; -const uint8_t msbc_zero_packet[] = { +const std::vector msbc_zero_packet{ 0x01, 0x08, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00}; -struct CodecInterface : bluetooth::core::CodecInterface { - CodecInterface() : bluetooth::core::CodecInterface(){}; +const std::vector lc3_zero_packet{ + 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0xf9, 0x4a, 0x0d, 0x00, 0x00, 0x03}; + +struct MsbcCodecInterface : bluetooth::core::CodecInterface { + MsbcCodecInterface() : bluetooth::core::CodecInterface(){}; void initialize() override { hfp_msbc_decoder_init(); @@ -72,6 +81,28 @@ struct CodecInterface : bluetooth::core::CodecInterface { } }; +struct Lc3CodecInterface : bluetooth::core::CodecInterface { + Lc3CodecInterface() : bluetooth::core::CodecInterface(){}; + + void initialize() override { + hfp_lc3_decoder_init(); + hfp_lc3_encoder_init(); + } + + void cleanup() override { + hfp_lc3_decoder_cleanup(); + hfp_lc3_encoder_cleanup(); + } + + uint32_t encodePacket(int16_t* input, uint8_t* output) { + return hfp_lc3_encode_frames(input, output); + } + + bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) { + return hfp_lc3_decoder_decode_packet(i_buf, o_buf, out_len); + } +}; + class ScoHciTest : public Test { public: protected: @@ -81,8 +112,10 @@ class ScoHciTest : public Test { mock_uipc_read_ret = 0; mock_uipc_send_ret = true; - static auto codec = CodecInterface{}; - GetInterfaceToProfiles()->msbcCodec = &codec; + static auto msbc_codec = MsbcCodecInterface{}; + static auto lc3_codec = Lc3CodecInterface{}; + GetInterfaceToProfiles()->msbcCodec = &msbc_codec; + GetInterfaceToProfiles()->lc3Codec = &lc3_codec; } void TearDown() override {} }; @@ -99,6 +132,7 @@ class ScoHciWithOpenCleanTest : public ScoHciTest { }; class ScoHciWbsTest : public ScoHciTest {}; +class ScoHciSwbTest : public ScoHciTest {}; class ScoHciWbsWithInitCleanTest : public ScoHciTest { public: @@ -110,6 +144,16 @@ class ScoHciWbsWithInitCleanTest : public ScoHciTest { void TearDown() override { bluetooth::audio::sco::wbs::cleanup(); } }; +class ScoHciSwbWithInitCleanTest : public ScoHciTest { + public: + protected: + void SetUp() override { + ScoHciTest::SetUp(); + bluetooth::audio::sco::swb::init(60); + } + void TearDown() override { bluetooth::audio::sco::swb::cleanup(); } +}; + TEST_F(ScoHciTest, ScoOverHciOpenFail) { bluetooth::audio::sco::open(); ASSERT_EQ(get_func_call_count("UIPC_Init"), 1); @@ -188,31 +232,40 @@ TEST_F(ScoHciWbsTest, WbsInit) { bluetooth::audio::sco::wbs::cleanup(); } +TEST_F(ScoHciSwbTest, SwbInit) { + ASSERT_EQ(bluetooth::audio::sco::swb::init(60), size_t(60)); + ASSERT_EQ(bluetooth::audio::sco::swb::init(72), size_t(72)); + // Fallback to 60 if the packet size is not supported + ASSERT_EQ(bluetooth::audio::sco::swb::init(48), size_t(60)); + bluetooth::audio::sco::swb::cleanup(); +} + TEST_F(ScoHciWbsTest, WbsEnqueuePacketWithoutInit) { - uint8_t payload[60]; + std::vector payload{60, 0}; // Return 0 if buffer is uninitialized - ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload), - false), - size_t(0)); + ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), false); +} + +TEST_F(ScoHciSwbTest, SwbEnqueuePacketWithoutInit) { + std::vector payload{60, 0}; + // Return 0 if buffer is uninitialized + ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), false); } TEST_F(ScoHciWbsWithInitCleanTest, WbsEnqueuePacket) { - uint8_t payload[60]; - // Return 0 if payload is invalid - ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(nullptr, sizeof(payload), - false), - size_t(0)); - // Return 0 if packet size is consistent - ASSERT_EQ( - bluetooth::audio::sco::wbs::enqueue_packet(payload, size_t(72), false), - size_t(0)); - ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload), - false), - size_t(60)); + std::vector payload; + for (size_t i = 0; i < 60; i++) payload.push_back(0); + ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true); // Return 0 if buffer is full - ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload), - false), - size_t(0)); + ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), false); +} + +TEST_F(ScoHciSwbWithInitCleanTest, SwbEnqueuePacket) { + std::vector payload; + for (size_t i = 0; i < 60; i++) payload.push_back(0); + ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true); + // Return 0 if buffer is full + ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), false); } TEST_F(ScoHciWbsTest, WbsDecodeWithoutInit) { @@ -222,17 +275,23 @@ TEST_F(ScoHciWbsTest, WbsDecodeWithoutInit) { ASSERT_EQ(decoded, nullptr); } +TEST_F(ScoHciSwbTest, SwbDecodeWithoutInit) { + const uint8_t* decoded = nullptr; + // Return 0 if buffer is uninitialized + ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0)); + ASSERT_EQ(decoded, nullptr); +} + TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) { const uint8_t* decoded = nullptr; - uint8_t payload[60] = {0}; + std::vector payload; + for (size_t i = 0; i < 60; i++) payload.push_back(0); // No data to decode ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); // Fill in invalid packet, all zeros. - ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload), - false), - sizeof(payload)); + ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true); // Return all zero frames when there comes an invalid packet. // This is expected even with PLC as there is no history in the PLC buffer. @@ -244,9 +303,8 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) { } decoded = nullptr; - ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(msbc_zero_packet, - sizeof(payload), false), - sizeof(msbc_zero_packet)); + ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(msbc_zero_packet, false), + true); ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE)); ASSERT_NE(decoded, nullptr); @@ -260,12 +318,54 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) { ASSERT_EQ(decoded, nullptr); } +TEST_F(ScoHciSwbWithInitCleanTest, SwbDecode) { + const uint8_t* decoded = nullptr; + std::vector payload; + for (size_t i = 0; i < 60; i++) payload.push_back(0); + + // No data to decode + ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0)); + ASSERT_EQ(decoded, nullptr); + // Fill in invalid packet, all zeros. + ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true); + + // Return all zero frames when there comes an invalid packet. + // This is expected even with PLC as there is no history in the PLC buffer. + ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), + size_t(BTM_LC3_CODE_SIZE)); + ASSERT_NE(decoded, nullptr); + for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) { + ASSERT_EQ(decoded[i], 0); + } + + decoded = nullptr; + ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(lc3_zero_packet, false), + true); + ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), + size_t(BTM_LC3_CODE_SIZE)); + ASSERT_NE(decoded, nullptr); + for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) { + ASSERT_EQ(decoded[i], 0); + } + + decoded = nullptr; + // No remaining data to decode + ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0)); + ASSERT_EQ(decoded, nullptr); +} + TEST_F(ScoHciWbsTest, WbsEncodeWithoutInit) { int16_t data[120] = {0}; // Return 0 if buffer is uninitialized ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0)); } +TEST_F(ScoHciSwbTest, SwbEncodeWithoutInit) { + int16_t data[BTM_LC3_CODE_SIZE / 2] = {0}; + // Return 0 if buffer is uninitialized + ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), size_t(0)); +} + TEST_F(ScoHciWbsWithInitCleanTest, WbsEncode) { int16_t data[120] = {0}; @@ -282,6 +382,22 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsEncode) { ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0)); } +TEST_F(ScoHciSwbWithInitCleanTest, SwbEncode) { + int16_t data[BTM_LC3_CODE_SIZE / 2] = {0}; + + // Return 0 if data is invalid + ASSERT_EQ(bluetooth::audio::sco::swb::encode(nullptr, sizeof(data)), + size_t(0)); + // Return 0 if data length is insufficient + ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data) - 1), + size_t(0)); + ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), + sizeof(data)); + + // Return 0 if the packet buffer is full + ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), size_t(0)); +} + TEST_F(ScoHciWbsTest, WbsDequeuePacketWithoutInit) { const uint8_t* encoded = nullptr; // Return 0 if buffer is uninitialized @@ -289,6 +405,13 @@ TEST_F(ScoHciWbsTest, WbsDequeuePacketWithoutInit) { ASSERT_EQ(encoded, nullptr); } +TEST_F(ScoHciSwbTest, SwbDequeuePacketWithoutInit) { + const uint8_t* encoded = nullptr; + // Return 0 if buffer is uninitialized + ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(0)); + ASSERT_EQ(encoded, nullptr); +} + TEST_F(ScoHciWbsWithInitCleanTest, WbsDequeuePacket) { const uint8_t* encoded = nullptr; // Return 0 if output pointer is invalid @@ -300,6 +423,17 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsDequeuePacket) { ASSERT_EQ(encoded, nullptr); } +TEST_F(ScoHciSwbWithInitCleanTest, SwbDequeuePacket) { + const uint8_t* encoded = nullptr; + // Return 0 if output pointer is invalid + ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(nullptr), size_t(0)); + ASSERT_EQ(encoded, nullptr); + + // Return 0 if there is insufficient data to dequeue + ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(0)); + ASSERT_EQ(encoded, nullptr); +} + TEST_F(ScoHciWbsWithInitCleanTest, WbsEncodeDequeuePackets) { uint8_t h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; int16_t data[120] = {0}; @@ -317,14 +451,32 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsEncodeDequeuePackets) { } } +TEST_F(ScoHciSwbWithInitCleanTest, SwbEncodeDequeuePackets) { + uint8_t h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; + int16_t data[BTM_LC3_CODE_SIZE / 2] = {0}; + const uint8_t* encoded = nullptr; + + for (size_t i = 0; i < 5; i++) { + ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), + sizeof(data)); + ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60)); + ASSERT_NE(encoded, nullptr); + for (size_t j = 0; j < 60; j++) { + ASSERT_EQ(encoded[j], + j == 1 ? h2_header_frames_count[i % 4] : lc3_zero_packet[j]); + } + } +} + TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) { int16_t triangle[16] = {0, 100, 200, 300, 400, 300, 200, 100, 0, -100, -200, -300, -400, -300, -200, -100}; int16_t data[120]; int16_t expect_data[120]; + std::vector encoded_vec; + for (size_t i = 0; i < 60; i++) encoded_vec.push_back(0); const uint8_t* encoded = nullptr; const uint8_t* decoded = nullptr; - uint8_t invalid_pkt[60] = {0}; size_t lost_pkt_idx = 17; // Simulate a run without any packet loss @@ -339,8 +491,9 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) { ASSERT_NE(encoded, nullptr); // Simulate the reception of the packet - ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(encoded, 60, false), - size_t(60)); + std::copy(encoded, encoded + size_t(60), encoded_vec.data()); + ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(encoded_vec, false), + true); ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE)); ASSERT_NE(decoded, nullptr); @@ -351,6 +504,18 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) { // Start with the fresh WBS buffer bluetooth::audio::sco::wbs::cleanup(); bluetooth::audio::sco::wbs::init(60); + + // check PLC returns gracefully with invalid parameters + ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(nullptr, nullptr), + false); + + int num_decoded_frames; + double packet_loss_ratio; + // check PLC returns gracefully when there hasn't been decoded frames + ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames, + &packet_loss_ratio), + false); + int decode_count = 0; for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) { // Data is a 1000Hz triangle wave @@ -362,16 +527,16 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) { ASSERT_NE(encoded, nullptr); // Substitute to invalid packet to simulate packet loss. + std::copy(encoded, encoded + size_t(60), encoded_vec.data()); ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet( - i != lost_pkt_idx ? encoded : invalid_pkt, 60, false), - size_t(60)); + i != lost_pkt_idx ? encoded_vec : std::vector(60, 0), + false), + true); ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE)); decode_count++; ASSERT_NE(decoded, nullptr); } - int num_decoded_frames; - double packet_loss_ratio; ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames, &packet_loss_ratio), @@ -404,9 +569,10 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) { ASSERT_NE(encoded, nullptr); // Substitute to report packet corrupted to simulate packet loss. + std::copy(encoded, encoded + size_t(60), encoded_vec.data()); ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet( - encoded, 60, i == corrupted_pkt_idx), - size_t(60)); + encoded_vec, i == corrupted_pkt_idx), + true); ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE)); decode_count++; @@ -430,4 +596,113 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) { } } +// TODO(b/269970706): implement PLC validation with +// github.com/google/liblc3/issues/16 in mind. +TEST_F(ScoHciSwbWithInitCleanTest, SwbPlc) { + int16_t triangle[16] = {0, 100, 200, 300, 400, 300, 200, 100, + 0, -100, -200, -300, -400, -300, -200, -100}; + int16_t data[BTM_LC3_CODE_SIZE / 2]; + int16_t expect_data[BTM_LC3_CODE_SIZE / 2]; + std::vector encoded_vec; + for (size_t i = 0; i < 60; i++) encoded_vec.push_back(0); + const uint8_t* encoded = nullptr; + const uint8_t* decoded = nullptr; + size_t lost_pkt_idx = 17; + + // Simulate a run without any packet loss + for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) { + // Input data is a 1000Hz triangle wave + for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++) + data[j] = triangle[sample_idx % 16]; + // Build the packet + ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), + sizeof(data)); + ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60)); + ASSERT_NE(encoded, nullptr); + + // Simulate the reception of the packet + std::copy(encoded, encoded + size_t(60), encoded_vec.data()); + ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(encoded_vec, false), + true); + ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), + size_t(BTM_LC3_CODE_SIZE)); + ASSERT_NE(decoded, nullptr); + } + // Store the decoded data we expect to get + std::copy((const int16_t*)decoded, + (const int16_t*)(decoded + BTM_LC3_CODE_SIZE), expect_data); + // Start with the fresh SWB buffer + bluetooth::audio::sco::swb::cleanup(); + bluetooth::audio::sco::swb::init(60); + + // check PLC returns gracefully with invalid parameters + ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(nullptr, nullptr), + false); + + int num_decoded_frames; + double packet_loss_ratio; + // check PLC returns gracefully when there hasn't been decoded frames + ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames, + &packet_loss_ratio), + false); + + int decode_count = 0; + for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) { + // Data is a 1000Hz triangle wave + for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++) + data[j] = triangle[sample_idx % 16]; + ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), + sizeof(data)); + ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60)); + ASSERT_NE(encoded, nullptr); + + // Substitute to invalid packet to simulate packet loss. + std::copy(encoded, encoded + size_t(60), encoded_vec.data()); + ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet( + i != lost_pkt_idx ? encoded_vec : std::vector(60, 0), + false), + true); + ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), + size_t(BTM_LC3_CODE_SIZE)); + decode_count++; + ASSERT_NE(decoded, nullptr); + } + + ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames, + &packet_loss_ratio), + true); + ASSERT_EQ(num_decoded_frames, decode_count); + ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count); + + size_t corrupted_pkt_idx = lost_pkt_idx; + // Start with the fresh SWB buffer + decode_count = 0; + bluetooth::audio::sco::swb::cleanup(); + bluetooth::audio::sco::swb::init(60); + for (size_t i = 0, sample_idx = 0; i <= corrupted_pkt_idx; i++) { + // Data is a 1000Hz triangle wave + for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++) + data[j] = triangle[sample_idx % 16]; + ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), + sizeof(data)); + ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60)); + ASSERT_NE(encoded, nullptr); + + // Substitute to report packet corrupted to simulate packet loss. + std::copy(encoded, encoded + size_t(60), encoded_vec.data()); + ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet( + encoded_vec, i == corrupted_pkt_idx), + true); + ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), + size_t(BTM_LC3_CODE_SIZE)); + decode_count++; + ASSERT_NE(decoded, nullptr); + } + + ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames, + &packet_loss_ratio), + true); + ASSERT_EQ(num_decoded_frames, decode_count); + ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count); +} } // namespace diff --git a/system/stack/test/btm/sco_pkt_status_test.cc b/system/stack/test/btm/sco_pkt_status_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..73853e4c8e3d73048846b4700163c1e8f72d7a75 --- /dev/null +++ b/system/stack/test/btm/sco_pkt_status_test.cc @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stack/btm/sco_pkt_status.h" + +#include + +namespace { + +using testing::Test; + +class ScoPktStatusTest : public Test { + public: + protected: + void SetUp() override {} + void TearDown() override {} +}; + +TEST_F(ScoPktStatusTest, Update) { + tBTM_SCO_PKT_STATUS pkt_status; + pkt_status.init(); + pkt_status.update(true); + ASSERT_NE(pkt_status.begin_ts_raw_us(), (uint64_t)0); + ASSERT_EQ(pkt_status.end_ts_raw_us(), pkt_status.begin_ts_raw_us() + 7500); + ASSERT_EQ(pkt_status.data_to_hex_string(), "01"); + ASSERT_EQ(pkt_status.data_to_binary_string(), "1"); +} + +TEST_F(ScoPktStatusTest, data_to_string) { + bool pl[9] = {1, 0, 1, 1, 0, 1, 1, 1, 1}; + tBTM_SCO_PKT_STATUS pkt_status; + pkt_status.init(); + for (bool b : pl) pkt_status.update(b); + ASSERT_EQ(pkt_status.data_to_binary_string(), "101101111"); + ASSERT_EQ(pkt_status.data_to_hex_string(), "ed01"); +} + +TEST_F(ScoPktStatusTest, data_full) { + bool pl[BTM_PKT_STATUS_LEN * 8] = { + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 1, 1, 1, 1, 1, /* f8 */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 1, /* ff */ + 1, 1, 1, 1, 1, 1, 1, 0, /* 7f */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 00 */ + }; + tBTM_SCO_PKT_STATUS pkt_status; + pkt_status.init(); + for (bool b : pl) pkt_status.update(b); + ASSERT_EQ(pkt_status.data_to_binary_string(), + "111111110000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000" + "000000000111111111111111111111111111111111111111111111111111111111" + "111111111111111111111111111111111111111111111111111111111111111111" + "11111111111111111111111111111111111111111000000000"); + uint64_t begin_ts_raw_us = pkt_status.begin_ts_raw_us(); + ASSERT_EQ(pkt_status.data_to_hex_string(), + "ff0000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000f8ffffffffffffffffffffffffffffffffffffff7f00"); + pkt_status.update(true); + ASSERT_NE(begin_ts_raw_us, pkt_status.begin_ts_raw_us()); + ASSERT_EQ(pkt_status.end_ts_raw_us(), + pkt_status.begin_ts_raw_us() + + BTM_PKT_STATUS_WBS_FRAME_US * BTM_PKT_STATUS_LEN * 8); + ASSERT_EQ(pkt_status.data_to_binary_string(), + "11111110000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000" + "000000000111111111111111111111111111111111111111111111111111111111" + "111111111111111111111111111111111111111111111111111111111111111111" + "111111111111111111111111111111111111111110000000001"); + ASSERT_EQ(pkt_status.data_to_hex_string(), + "fe0000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000f9ffffffffffffffffffffffffffffffffffffff7e01"); +} + +} // namespace diff --git a/system/stack/test/btm/stack_btm_dm_inq_db_test.cc b/system/stack/test/btm/stack_btm_dm_inq_db_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..0954ca9208b0203adf6e7e258663cd5c23e08f8c --- /dev/null +++ b/system/stack/test/btm/stack_btm_dm_inq_db_test.cc @@ -0,0 +1,229 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "osi/include/log.h" +#include "stack/btm/btm_int_types.h" +#include "stack/btm/neighbor_inquiry.h" +#include "stack/include/inq_hci_link_interface.h" +#include "test/common/mock_functions.h" +#include "test/fake/fake_looper.h" +#include "test/fake/fake_osi.h" +#include "test/fake/fake_thread.h" +#include "test/mock/mock_osi_allocator.h" +#include "test/mock/mock_osi_thread.h" + +extern tBTM_CB btm_cb; +extern void btm_init_inq_result_flt(void); +extern void btm_clr_inq_result_flt(void); + +namespace { +constexpr size_t kNumberOfThreads = 8; +constexpr size_t kEntriesPerThread = + static_cast(BTM_INQ_DB_SIZE) / kNumberOfThreads; + +constexpr RawAddress* kClearAllEntries = nullptr; +} // namespace + +namespace bluetooth { +namespace legacy { +namespace testing { +void btm_clr_inq_db(const RawAddress* p_bda); +uint16_t btm_get_num_bd_entries(); +} // namespace testing +} // namespace legacy +} // namespace bluetooth + +class BtmDmInqDbWithMockTest : public testing::Test { + protected: + void SetUp() override { + reset_mock_function_count_map(); + fake_osi_ = std::make_unique(); + test::mock::osi_thread::thread_new.body = + [](const char* name) -> thread_t* { + thread_t* thread = new thread_t; + thread->name_ = std::string(name); + thread_start_arg_t start_arg; + start_arg.thread = thread; + pthread_create(&thread->pthread_, nullptr, run_message_loop, &start_arg); + // Wait for thread to start up with semaphore before continuing + start_arg.start_sem.wait(); + return thread; + }; + test::mock::osi_thread::thread_post.body = + [](thread_t* thread, thread_func func, void* context) -> bool { + if (!thread->is_running()) return false; + { + std::lock_guard lock(thread->work_queue_semaphore.mutex_); + thread->work_queue.push(std::make_pair(func, context)); + } + thread->work_queue_semaphore.notify(); + return true; + }; + test::mock::osi_thread::thread_free.body = [](thread_t* thread) { + thread->quiesce(); + pthread_join(thread->pthread_, nullptr); + thread->work_queue = {}; + delete thread; + }; + } + + void TearDown() override { + test::mock::osi_thread::thread_free = {}; + test::mock::osi_thread::thread_post = {}; + test::mock::osi_thread::thread_new = {}; + } + std::unique_ptr fake_osi_; +}; + +class BtmDmInqDbTest : public BtmDmInqDbWithMockTest { + protected: + void SetUp() override { + BtmDmInqDbWithMockTest::SetUp(); + bluetooth::legacy::testing::btm_clr_inq_db(kClearAllEntries); + btm_init_inq_result_flt(); + } + + void TearDown() override { + btm_clr_inq_result_flt(); + bluetooth::legacy::testing::btm_clr_inq_db(kClearAllEntries); + BtmDmInqDbWithMockTest::TearDown(); + } +}; + +class BtmDmInqDbThreadedTest : public BtmDmInqDbTest { + protected: + void SetUp() override { BtmDmInqDbTest::SetUp(); } + + void TearDown() override { BtmDmInqDbTest::TearDown(); } + + void setup_thread() { + for (size_t i = 0; i < kNumberOfThreads; i++) { + std::string name = base::StringPrintf("thread:%zu", i); + threads[i] = thread_new(name.c_str()); + } + } + + void teardown_thread() { + for (size_t i = 0; i < kNumberOfThreads; i++) { + thread_free(threads[i]); + } + } + + thread_t* threads[kNumberOfThreads]; +}; + +struct context_t { + std::deque inq_db_queue[kNumberOfThreads]; +}; + +struct entry_data_t { + int thread_id; + std::deque* inq_db_queue; +}; + +RawAddress RawAddressMaker(int thread_id, int subid) { + RawAddress bd_addr = {}; + // tODO Use const std::array array) + bd_addr.address[0] = 0x0a; + bd_addr.address[1] = 0x0b; + bd_addr.address[2] = 0x0c; + bd_addr.address[3] = 0x0d; + bd_addr.address[4] = (uint8_t)thread_id; + bd_addr.address[5] = (uint8_t)subid; + return bd_addr; +} + +void allocate_db_entry(void* context) { + entry_data_t* data = static_cast(context); + RawAddress p_bda = + RawAddressMaker(data->thread_id, (int)data->inq_db_queue->size()); + tINQ_DB_ENT* ent = btm_inq_db_new(p_bda); + data->inq_db_queue->push_back(ent); +} + +TEST_F(BtmDmInqDbThreadedTest, btm_inq_db_new) { + this->setup_thread(); + + context_t context = {}; + + for (size_t j = 0; j < kEntriesPerThread; j++) { + for (size_t i = 0; i < kNumberOfThreads; i++) { + data_t* data = static_cast(calloc(sizeof(data_t), 1)); + data->thread_id = i; + data->inq_db_queue = &context.inq_db_queue[i]; + ASSERT_TRUE( + thread_post(threads[i], allocate_db_entry, static_cast(data))); + } + } + + this->teardown_thread(); + + int failed = 0; + for (size_t i = 0; i < kNumberOfThreads; i++) { + ASSERT_EQ(kEntriesPerThread, context.inq_db_queue[i].size()); + for (const auto& it : context.inq_db_queue[i]) { + RawAddress exp = it->inq_info.results.remote_bd_addr; + exp.address[4] = i; + if (exp != it->inq_info.results.remote_bd_addr) { + EXPECT_EQ(exp, it->inq_info.results.remote_bd_addr); + failed++; + } + } + } + ASSERT_EQ(0, failed); +} + +struct address_data_t { + int thread_id; + int offset; +}; + +void check_address(void* context) { + address_data_t* data = static_cast(context); + RawAddress p_bda = RawAddressMaker(data->thread_id, data->offset); + // Make sure it's new + ASSERT_FALSE(btm_inq_find_bdaddr(p_bda)); +} + +TEST_F(BtmDmInqDbThreadedTest, btm_inq_find_bdaddr) { + this->setup_thread(); + context_t context = {}; + + for (size_t j = 0; j < kEntriesPerThread; j++) { + for (size_t i = 0; i < kNumberOfThreads; i++) { + address_data_t* data = + static_cast(calloc(sizeof(address_data_t), 1)); + data->thread_id = i; + data->offset = (int)j; + ASSERT_TRUE( + thread_post(threads[i], check_address, static_cast(data))); + } + } + + this->teardown_thread(); + + ASSERT_EQ((uint16_t)(kNumberOfThreads * kEntriesPerThread), + bluetooth::legacy::testing::btm_get_num_bd_entries()); +} diff --git a/system/stack/test/btm/stack_btm_power_mode_test.cc b/system/stack/test/btm/stack_btm_power_mode_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..52158b9b3f5babd27ecd3658b002d76ae5d2cea6 --- /dev/null +++ b/system/stack/test/btm/stack_btm_power_mode_test.cc @@ -0,0 +1,202 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0(the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include + +#include "btm_api_types.h" +#include "gd/common/init_flags.h" +#include "gd/os/log.h" +#include "stack/include/acl_api.h" +#include "stack/include/acl_hci_link_interface.h" +#include "stack/include/btm_api.h" +#include "stack/include/hci_error_code.h" +#include "test/common/mock_functions.h" +#include "types/raw_address.h" + +namespace { +const char* test_flags[] = { + "INIT_default_log_level_str=LOG_DEBUG", + nullptr, +}; + +const RawAddress kRawAddress = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); +const uint16_t kHciHandle = 123; + +} // namespace + +struct power_mode_callback { + const RawAddress bd_addr; + tBTM_PM_STATUS status; + uint16_t value; + tHCI_STATUS hci_status; +}; + +#include +std::deque power_mode_callback_queue; + +class StackBtmPowerMode : public testing::Test { + protected: + void SetUp() override { + power_mode_callback_queue.clear(); + reset_mock_function_count_map(); + bluetooth::common::InitFlags::Load(test_flags); + ASSERT_EQ(BTM_SUCCESS, + BTM_PmRegister(BTM_PM_REG_SET, &pm_id_, + [](const RawAddress& p_bda, tBTM_PM_STATUS status, + uint16_t value, tHCI_STATUS hci_status) { + power_mode_callback_queue.push_back( + power_mode_callback{ + .bd_addr = p_bda, + .status = status, + .value = value, + .hci_status = hci_status, + }); + })); + } + + void TearDown() override { + ASSERT_EQ(BTM_SUCCESS, + BTM_PmRegister(BTM_PM_DEREG, &pm_id_, + [](const RawAddress& p_bda, tBTM_PM_STATUS status, + uint16_t value, tHCI_STATUS hci_status) {})); + } + + uint8_t pm_id_{0}; +}; + +class StackBtmPowerModeConnected : public StackBtmPowerMode { + protected: + void SetUp() override { + StackBtmPowerMode::SetUp(); + BTM_PM_OnConnected(kHciHandle, kRawAddress); + } + + void TearDown() override { + BTM_PM_OnDisconnected(kHciHandle); + StackBtmPowerMode::TearDown(); + } +}; + +TEST_F(StackBtmPowerMode, BTM_SetPowerMode__Undefined) { + tBTM_PM_PWR_MD mode = {}; + ASSERT_EQ(BTM_UNKNOWN_ADDR, BTM_SetPowerMode(pm_id_, kRawAddress, &mode)); +} + +TEST_F(StackBtmPowerModeConnected, BTM_SetPowerMode__AlreadyActive) { + tBTM_PM_PWR_MD mode = {}; + ASSERT_EQ(BTM_SUCCESS, BTM_SetPowerMode(pm_id_, kRawAddress, &mode)); +} + +TEST_F(StackBtmPowerModeConnected, BTM_SetPowerMode__ActiveToSniff) { + tBTM_PM_PWR_MD mode = { + .mode = BTM_PM_MD_SNIFF, + }; + ASSERT_EQ("BTM_CMD_STARTED", + btm_status_text(BTM_SetPowerMode(pm_id_, kRawAddress, &mode))); + ASSERT_EQ(1, get_func_call_count("btsnd_hcic_sniff_mode")); + + // Respond with successful command status for mode command + btm_pm_proc_cmd_status(HCI_SUCCESS); + + // Check power mode state directly + { + tBTM_PM_MODE current_power_mode; + ASSERT_TRUE(BTM_ReadPowerMode(kRawAddress, ¤t_power_mode)); + ASSERT_EQ(BTM_PM_STS_PENDING, current_power_mode); + } + + // Check power mode state from callback + ASSERT_EQ(1U, power_mode_callback_queue.size()); + { + const auto cb = power_mode_callback_queue.front(); + power_mode_callback_queue.pop_front(); + + ASSERT_EQ(kRawAddress, cb.bd_addr); + ASSERT_EQ(BTM_PM_STS_PENDING, cb.status); + ASSERT_EQ(0, cb.value); + ASSERT_EQ(HCI_SUCCESS, cb.hci_status); + } + + // Respond with a successful mode change event + btm_pm_proc_mode_change(HCI_SUCCESS, kHciHandle, HCI_MODE_SNIFF, 0); + + { + tBTM_PM_MODE current_power_mode; + ASSERT_TRUE(BTM_ReadPowerMode(kRawAddress, ¤t_power_mode)); + ASSERT_EQ(BTM_PM_STS_SNIFF, current_power_mode); + } + + // Check power mode state from callback + ASSERT_EQ(1U, power_mode_callback_queue.size()); + { + const auto cb = power_mode_callback_queue.front(); + power_mode_callback_queue.pop_front(); + + ASSERT_EQ(kRawAddress, cb.bd_addr); + ASSERT_EQ(BTM_PM_STS_SNIFF, cb.status); + ASSERT_EQ(0, cb.value); + ASSERT_EQ(HCI_SUCCESS, cb.hci_status); + } +} + +TEST_F(StackBtmPowerModeConnected, BTM_SetPowerMode__ActiveToSniffTwice) { + tBTM_PM_PWR_MD mode = { + .mode = BTM_PM_MD_SNIFF, + }; + ASSERT_EQ("BTM_CMD_STARTED", + btm_status_text(BTM_SetPowerMode(pm_id_, kRawAddress, &mode))); + ASSERT_EQ(1, get_func_call_count("btsnd_hcic_sniff_mode")); + + // Respond with successful command status for mode command + btm_pm_proc_cmd_status(HCI_SUCCESS); + + // Check power mode state directly + { + tBTM_PM_MODE current_power_mode; + ASSERT_TRUE(BTM_ReadPowerMode(kRawAddress, ¤t_power_mode)); + ASSERT_EQ(BTM_PM_STS_PENDING, current_power_mode); + } + + // Check power mode state from callback + ASSERT_EQ(1U, power_mode_callback_queue.size()); + { + const auto cb = power_mode_callback_queue.front(); + power_mode_callback_queue.pop_front(); + + ASSERT_EQ(kRawAddress, cb.bd_addr); + ASSERT_EQ(BTM_PM_STS_PENDING, cb.status); + ASSERT_EQ(0, cb.value); + ASSERT_EQ(HCI_SUCCESS, cb.hci_status); + } + + // Send a second active to sniff command + ASSERT_EQ("BTM_CMD_STORED", + btm_status_text(BTM_SetPowerMode(pm_id_, kRawAddress, &mode))); + // No command should be issued + ASSERT_EQ(1, get_func_call_count("btsnd_hcic_sniff_mode")); + + // Check power mode state directly + { + tBTM_PM_MODE current_power_mode; + ASSERT_TRUE(BTM_ReadPowerMode(kRawAddress, ¤t_power_mode)); + // NOTE: The mixed enum values + ASSERT_EQ( + static_cast(BTM_PM_STS_PENDING | BTM_PM_STORED_MASK), + current_power_mode); + } +} diff --git a/system/stack/test/btm/stack_btm_regression_tests.cc b/system/stack/test/btm/stack_btm_regression_tests.cc index 93c3d6806be5d552e7d86d69e4a00f97ac0a41ff..ec111e941b6bcc874e35516b3564a0646cae794c 100644 --- a/system/stack/test/btm/stack_btm_regression_tests.cc +++ b/system/stack/test/btm/stack_btm_regression_tests.cc @@ -18,11 +18,11 @@ #include +#include "ble_hci_link_interface.h" #include "bt_hdr.h" #include "btm_ble_api_types.h" #include "hci_error_code.h" #include "osi/include/allocator.h" -#include "ble_hci_link_interface.h" namespace { @@ -35,17 +35,15 @@ class StackBTMRegressionTests : public ::testing::Test { // regression test for b/260078907 TEST_F(StackBTMRegressionTests, OOB_in_btm_ble_add_resolving_list_entry_complete) { - BT_HDR* pevent = (BT_HDR*)osi_calloc(sizeof(BT_HDR)); - btm_ble_add_resolving_list_entry_complete(pevent->data, 0); - osi_free(pevent); + BT_HDR event{}; + btm_ble_add_resolving_list_entry_complete(event.data, 0); } // regression test for b/255304475 TEST_F(StackBTMRegressionTests, OOB_in_btm_ble_clear_resolving_list_complete) { - BT_HDR* pevent = (BT_HDR*)osi_calloc(sizeof(BT_HDR)); - btm_ble_clear_resolving_list_complete(pevent->data, 0); - osi_free(pevent); + BT_HDR event{}; + btm_ble_clear_resolving_list_complete(event.data, 0); } } // namespace diff --git a/system/stack/test/btm/stack_btm_sec_test.cc b/system/stack/test/btm/stack_btm_sec_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..73631887f76aec84e2d64191d5028661ea283451 --- /dev/null +++ b/system/stack/test/btm/stack_btm_sec_test.cc @@ -0,0 +1,271 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +#include + +#include "gd/common/init_flags.h" +#include "hci/hci_layer_mock.h" +#include "internal_include/bt_target.h" +#include "stack/btm/btm_ble_sec.h" +#include "stack/btm/btm_dev.h" +#include "stack/btm/btm_sec.h" +#include "stack/btm/btm_sec_cb.h" +#include "stack/btm/security_device_record.h" +#include "test/common/mock_functions.h" +#include "test/mock/mock_main_shim_entry.h" +#include "types/raw_address.h" + +using testing::Return; +using testing::Test; + +namespace bluetooth { +namespace testing { +namespace legacy { + +void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec); + +} // namespace legacy +} // namespace testing +} // namespace bluetooth + +using bluetooth::testing::legacy::wipe_secrets_and_remove; + +constexpr size_t kBtmSecMaxDeviceRecords = + static_cast(BTM_SEC_MAX_DEVICE_RECORDS + 1); + +class StackBtmSecTest : public Test { + public: + protected: + void SetUp() override { reset_mock_function_count_map(); } + void TearDown() override {} +}; + +class StackBtmSecWithQueuesTest : public StackBtmSecTest { + public: + protected: + void SetUp() override { + StackBtmSecTest::SetUp(); + up_thread_ = new bluetooth::os::Thread( + "up_thread", bluetooth::os::Thread::Priority::NORMAL); + up_handler_ = new bluetooth::os::Handler(up_thread_); + down_thread_ = new bluetooth::os::Thread( + "down_thread", bluetooth::os::Thread::Priority::NORMAL); + down_handler_ = new bluetooth::os::Handler(down_thread_); + bluetooth::hci::testing::mock_hci_layer_ = &mock_hci_; + bluetooth::hci::testing::mock_gd_shim_handler_ = up_handler_; + } + void TearDown() override { + up_handler_->Clear(); + delete up_handler_; + delete up_thread_; + down_handler_->Clear(); + delete down_handler_; + delete down_thread_; + StackBtmSecTest::TearDown(); + } + bluetooth::common::BidiQueue + sco_queue_{10}; + bluetooth::hci::testing::MockHciLayer mock_hci_; + bluetooth::os::Thread* up_thread_; + bluetooth::os::Handler* up_handler_; + bluetooth::os::Thread* down_thread_; + bluetooth::os::Handler* down_handler_; +}; + +class StackBtmSecWithInitFreeTest : public StackBtmSecWithQueuesTest { + public: + protected: + void SetUp() override { + StackBtmSecWithQueuesTest::SetUp(); + ::btm_sec_cb.Init(BTM_SEC_MODE_SC); + } + void TearDown() override { + ::btm_sec_cb.Free(); + StackBtmSecWithQueuesTest::TearDown(); + } +}; + +TEST_F(StackBtmSecWithInitFreeTest, btm_sec_encrypt_change) { + bluetooth::common::InitFlags::SetAllForTesting(); + + RawAddress bd_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6}); + const uint16_t classic_handle = 0x1234; + const uint16_t ble_handle = 0x9876; + + // Check the collision conditionals + ::btm_sec_cb.collision_start_time = 0UL; + btm_sec_encrypt_change(classic_handle, HCI_ERR_LMP_ERR_TRANS_COLLISION, 0x01); + uint64_t collision_start_time = ::btm_sec_cb.collision_start_time; + ASSERT_NE(0UL, collision_start_time); + + ::btm_sec_cb.collision_start_time = 0UL; + btm_sec_encrypt_change(classic_handle, HCI_ERR_DIFF_TRANSACTION_COLLISION, + 0x01); + collision_start_time = ::btm_sec_cb.collision_start_time; + ASSERT_NE(0UL, collision_start_time); + + // No device + ::btm_sec_cb.collision_start_time = 0; + btm_sec_encrypt_change(classic_handle, HCI_SUCCESS, 0x01); + ASSERT_EQ(0UL, ::btm_sec_cb.collision_start_time); + + // Setup device + tBTM_SEC_DEV_REC* device_record = btm_sec_allocate_dev_rec(); + ASSERT_NE(nullptr, device_record); + ASSERT_EQ(BTM_SEC_IN_USE, device_record->sec_rec.sec_flags); + device_record->bd_addr = bd_addr; + device_record->hci_handle = classic_handle; + device_record->ble_hci_handle = ble_handle; + + // With classic device encryption enable + btm_sec_encrypt_change(classic_handle, HCI_SUCCESS, 0x01); + ASSERT_EQ(BTM_SEC_IN_USE | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED, + device_record->sec_rec.sec_flags); + + // With classic device encryption disable + btm_sec_encrypt_change(classic_handle, HCI_SUCCESS, 0x00); + ASSERT_EQ(BTM_SEC_IN_USE | BTM_SEC_AUTHENTICATED, + device_record->sec_rec.sec_flags); + device_record->sec_rec.sec_flags = BTM_SEC_IN_USE; + + // With le device encryption enable + btm_sec_encrypt_change(ble_handle, HCI_SUCCESS, 0x01); + ASSERT_EQ(BTM_SEC_IN_USE | BTM_SEC_LE_ENCRYPTED, + device_record->sec_rec.sec_flags); + + // With le device encryption disable + btm_sec_encrypt_change(ble_handle, HCI_SUCCESS, 0x00); + ASSERT_EQ(BTM_SEC_IN_USE, device_record->sec_rec.sec_flags); + device_record->sec_rec.sec_flags = BTM_SEC_IN_USE; + + wipe_secrets_and_remove(device_record); +} + +TEST_F(StackBtmSecWithInitFreeTest, BTM_SetEncryption) { + const RawAddress bd_addr = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); + const tBT_TRANSPORT transport{BT_TRANSPORT_LE}; + tBTM_SEC_CALLBACK* p_callback{nullptr}; + tBTM_BLE_SEC_ACT sec_act{BTM_BLE_SEC_ENCRYPT}; + + // No device + ASSERT_EQ(BTM_WRONG_MODE, BTM_SetEncryption(bd_addr, transport, p_callback, + nullptr, sec_act)); + + // With device + tBTM_SEC_DEV_REC* device_record = btm_sec_allocate_dev_rec(); + ASSERT_NE(nullptr, device_record); + device_record->bd_addr = bd_addr; + device_record->hci_handle = 0x1234; + + ASSERT_EQ(BTM_WRONG_MODE, BTM_SetEncryption(bd_addr, transport, p_callback, + nullptr, sec_act)); + + wipe_secrets_and_remove(device_record); +} + +TEST_F(StackBtmSecTest, btm_ble_sec_req_act_text) { + ASSERT_EQ("BTM_BLE_SEC_REQ_ACT_NONE", + btm_ble_sec_req_act_text(BTM_BLE_SEC_REQ_ACT_NONE)); + ASSERT_EQ("BTM_BLE_SEC_REQ_ACT_ENCRYPT", + btm_ble_sec_req_act_text(BTM_BLE_SEC_REQ_ACT_ENCRYPT)); + ASSERT_EQ("BTM_BLE_SEC_REQ_ACT_PAIR", + btm_ble_sec_req_act_text(BTM_BLE_SEC_REQ_ACT_PAIR)); + ASSERT_EQ("BTM_BLE_SEC_REQ_ACT_DISCARD", + btm_ble_sec_req_act_text(BTM_BLE_SEC_REQ_ACT_DISCARD)); +} + +TEST_F(StackBtmSecWithInitFreeTest, btm_sec_allocate_dev_rec__all) { + tBTM_SEC_DEV_REC* records[kBtmSecMaxDeviceRecords]; + + // Fill up the records + for (size_t i = 0; i < kBtmSecMaxDeviceRecords; i++) { + ASSERT_EQ(i, list_length(::btm_sec_cb.sec_dev_rec)); + records[i] = btm_sec_allocate_dev_rec(); + ASSERT_NE(nullptr, records[i]); + } + + // Second pass up the records + for (size_t i = 0; i < kBtmSecMaxDeviceRecords; i++) { + ASSERT_EQ(kBtmSecMaxDeviceRecords, list_length(::btm_sec_cb.sec_dev_rec)); + records[i] = btm_sec_allocate_dev_rec(); + ASSERT_NE(nullptr, records[i]); + } + + // NOTE: The memory allocated for each record is automatically + // allocated by the btm module and freed when the device record + // list is freed. + // Further, the memory for each record is reused when necessary. +} + +TEST_F(StackBtmSecTest, btm_oob_data_text) { + std::vector> datas = { + std::make_pair(BTM_OOB_NONE, "BTM_OOB_NONE"), + std::make_pair(BTM_OOB_PRESENT_192, "BTM_OOB_PRESENT_192"), + std::make_pair(BTM_OOB_PRESENT_256, "BTM_OOB_PRESENT_256"), + std::make_pair(BTM_OOB_PRESENT_192_AND_256, + "BTM_OOB_PRESENT_192_AND_256"), + std::make_pair(BTM_OOB_UNKNOWN, "BTM_OOB_UNKNOWN"), + }; + for (const auto& data : datas) { + ASSERT_STREQ(data.second.c_str(), btm_oob_data_text(data.first).c_str()); + } + auto unknown = base::StringPrintf("UNKNOWN[%hhu]", + std::numeric_limits::max()); + ASSERT_STREQ(unknown.c_str(), + btm_oob_data_text(static_cast( + std::numeric_limits::max())) + .c_str()); +} + +TEST_F(StackBtmSecTest, bond_type_text) { + std::vector> datas = { + std::make_pair(BOND_TYPE_UNKNOWN, "BOND_TYPE_UNKNOWN"), + std::make_pair(BOND_TYPE_PERSISTENT, "BOND_TYPE_PERSISTENT"), + std::make_pair(BOND_TYPE_TEMPORARY, "BOND_TYPE_TEMPORARY"), + }; + for (const auto& data : datas) { + ASSERT_STREQ(data.second.c_str(), bond_type_text(data.first).c_str()); + } + auto unknown = base::StringPrintf("UNKNOWN[%hhu]", + std::numeric_limits::max()); + ASSERT_STREQ(unknown.c_str(), + bond_type_text(static_cast( + std::numeric_limits::max())) + .c_str()); +} + +TEST_F(StackBtmSecWithInitFreeTest, wipe_secrets_and_remove) { + bluetooth::common::InitFlags::SetAllForTesting(); + + RawAddress bd_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6}); + const uint16_t classic_handle = 0x1234; + const uint16_t ble_handle = 0x9876; + + // Setup device + tBTM_SEC_DEV_REC* device_record = btm_sec_allocate_dev_rec(); + ASSERT_NE(nullptr, device_record); + ASSERT_EQ(BTM_SEC_IN_USE, device_record->sec_rec.sec_flags); + device_record->bd_addr = bd_addr; + device_record->hci_handle = classic_handle; + device_record->ble_hci_handle = ble_handle; + + wipe_secrets_and_remove(device_record); +} diff --git a/system/stack/test/btm/stack_btm_test.cc b/system/stack/test/btm/stack_btm_test.cc index c3579c4578397803762c02fdde64f91087c9d176..89db47e1d9533af3957debbe6543503c10b4e002 100644 --- a/system/stack/test/btm/stack_btm_test.cc +++ b/system/stack/test/btm/stack_btm_test.cc @@ -1,5 +1,4 @@ /* - * * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,45 +18,32 @@ #include #include -#include #include -#include #include -#include -#include "btif/include/btif_hh.h" -#include "common/init_flags.h" +#include "gd/common/init_flags.h" +#include "hci/hci_layer_mock.h" #include "hci/include/hci_layer.h" -#include "internal_include/stack_config.h" -#include "osi/include/allocator.h" -#include "osi/include/osi.h" +#include "internal_include/bt_target.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_int_types.h" #include "stack/btm/btm_sco.h" #include "stack/btm/btm_sec.h" -#include "stack/btm/security_device_record.h" +#include "stack/btm/btm_sec_cb.h" #include "stack/include/acl_api.h" #include "stack/include/acl_hci_link_interface.h" #include "stack/include/btm_client_interface.h" -#include "stack/include/hcidefs.h" -#include "stack/include/sec_hci_link_interface.h" #include "stack/l2cap/l2c_int.h" #include "test/common/mock_functions.h" -#include "test/mock/mock_device_iot_config.h" -#include "test/mock/mock_osi_list.h" -#include "test/mock/mock_stack_hcic_hcicmds.h" +#include "test/mock/mock_legacy_hci_interface.h" +#include "test/mock/mock_main_shim_entry.h" #include "types/raw_address.h" using testing::Each; using testing::Eq; -namespace mock = test::mock::stack_hcic_hcicmds; - extern tBTM_CB btm_cb; -uint8_t btif_trace_level = BT_TRACE_LEVEL_DEBUG; -uint8_t appl_trace_level = BT_TRACE_LEVEL_VERBOSE; -btif_hh_cb_t btif_hh_cb; tL2C_CB l2cb; const hci_t* hci_layer_get_interface() { return nullptr; } @@ -68,48 +54,74 @@ const std::string kBroadcastAudioConfigOptions( namespace { -using testing::_; -using testing::DoAll; -using testing::NotNull; -using testing::Pointee; using testing::Return; -using testing::SaveArg; -using testing::SaveArgPointee; -using testing::StrEq; -using testing::StrictMock; using testing::Test; -// NOTE: The production code allows N+1 device records. -constexpr size_t kBtmSecMaxDeviceRecords = - static_cast(BTM_SEC_MAX_DEVICE_RECORDS + 1); - -std::string Hex16(int n) { - std::ostringstream oss; - oss << "0x" << std::hex << std::setw(4) << std::setfill('0') << n; - return oss.str(); -} - class StackBtmTest : public Test { public: protected: - void SetUp() override { reset_mock_function_count_map(); } + void SetUp() override { + reset_mock_function_count_map(); + } void TearDown() override {} }; -class StackBtmWithInitFreeTest : public StackBtmTest { +class StackBtmWithQueuesTest : public StackBtmTest { public: protected: void SetUp() override { StackBtmTest::SetUp(); - btm_cb.Init(BTM_SEC_MODE_SC); + up_thread_ = new bluetooth::os::Thread( + "up_thread", bluetooth::os::Thread::Priority::NORMAL); + up_handler_ = new bluetooth::os::Handler(up_thread_); + down_thread_ = new bluetooth::os::Thread( + "down_thread", bluetooth::os::Thread::Priority::NORMAL); + down_handler_ = new bluetooth::os::Handler(down_thread_); + bluetooth::hci::testing::mock_hci_layer_ = &mock_hci_; + bluetooth::hci::testing::mock_gd_shim_handler_ = up_handler_; + bluetooth::legacy::hci::testing::SetMock(legacy_hci_mock_); } void TearDown() override { - btm_cb.Free(); + up_handler_->Clear(); + delete up_handler_; + delete up_thread_; + down_handler_->Clear(); + delete down_handler_; + delete down_thread_; StackBtmTest::TearDown(); } + bluetooth::common::BidiQueue + sco_queue_{10}; + bluetooth::hci::testing::MockHciLayer mock_hci_; + bluetooth::legacy::hci::testing::MockInterface legacy_hci_mock_; + bluetooth::os::Thread* up_thread_; + bluetooth::os::Handler* up_handler_; + bluetooth::os::Thread* down_thread_; + bluetooth::os::Handler* down_handler_; }; -TEST_F(StackBtmTest, GlobalLifecycle) { +class StackBtmWithInitFreeTest : public StackBtmWithQueuesTest { + public: + protected: + void SetUp() override { + StackBtmWithQueuesTest::SetUp(); + EXPECT_CALL(mock_hci_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); + + btm_cb.Init(); + btm_sec_cb.Init(BTM_SEC_MODE_SC); + } + void TearDown() override { + btm_sec_cb.Free(); + btm_cb.Free(); + StackBtmWithQueuesTest::TearDown(); + } +}; + +TEST_F(StackBtmWithQueuesTest, GlobalLifecycle) { + EXPECT_CALL(mock_hci_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); get_btm_client_interface().lifecycle.btm_free(); } @@ -119,19 +131,25 @@ TEST_F(StackBtmTest, DynamicLifecycle) { delete btm; } -TEST_F(StackBtmTest, InitFree) { - btm_cb.Init(0x1); +TEST_F(StackBtmWithQueuesTest, InitFree) { + EXPECT_CALL(mock_hci_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); + btm_cb.Init(); btm_cb.Free(); } -TEST_F(StackBtmTest, tSCO_CB) { +TEST_F(StackBtmWithQueuesTest, tSCO_CB) { + EXPECT_CALL(mock_hci_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); bluetooth::common::InitFlags::SetAllForTesting(); tSCO_CB* p_sco = &btm_cb.sco_cb; p_sco->Init(); p_sco->Free(); } -TEST_F(StackBtmTest, InformClientOnConnectionSuccess) { +TEST_F(StackBtmWithQueuesTest, InformClientOnConnectionSuccess) { + EXPECT_CALL(mock_hci_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); RawAddress bda({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); @@ -142,7 +160,9 @@ TEST_F(StackBtmTest, InformClientOnConnectionSuccess) { get_btm_client_interface().lifecycle.btm_free(); } -TEST_F(StackBtmTest, NoInformClientOnConnectionFail) { +TEST_F(StackBtmWithQueuesTest, NoInformClientOnConnectionFail) { + EXPECT_CALL(mock_hci_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); RawAddress bda({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); @@ -153,7 +173,9 @@ TEST_F(StackBtmTest, NoInformClientOnConnectionFail) { get_btm_client_interface().lifecycle.btm_free(); } -TEST_F(StackBtmTest, default_packet_type) { +TEST_F(StackBtmWithQueuesTest, default_packet_type) { + EXPECT_CALL(mock_hci_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); btm_cb.acl_cb_.SetDefaultPacketTypeMask(0x4321); @@ -162,62 +184,37 @@ TEST_F(StackBtmTest, default_packet_type) { get_btm_client_interface().lifecycle.btm_free(); } -TEST_F(StackBtmTest, change_packet_type) { - int cnt = 0; +TEST_F(StackBtmWithQueuesTest, change_packet_type) { + EXPECT_CALL(mock_hci_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); + uint16_t handle = 0x123; + btm_cb.acl_cb_.SetDefaultPacketTypeMask(0xffff); ASSERT_EQ(0xffff, btm_cb.acl_cb_.DefaultPacketTypes()); // Create connection RawAddress bda({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); - btm_acl_created(bda, 0x123, HCI_ROLE_CENTRAL, BT_TRANSPORT_BR_EDR); + btm_acl_created(bda, handle, HCI_ROLE_CENTRAL, BT_TRANSPORT_BR_EDR); uint64_t features = 0xffffffffffffffff; acl_process_supported_features(0x123, features); - uint16_t handle{0}; - uint16_t packet_types{0}; + EXPECT_CALL(legacy_hci_mock_, ChangeConnectionPacketType( + handle, 0x4400 | HCI_PKT_TYPES_MASK_DM1)); + EXPECT_CALL(legacy_hci_mock_, ChangeConnectionPacketType( + handle, (0xcc00 | HCI_PKT_TYPES_MASK_DM1 | + HCI_PKT_TYPES_MASK_DH1))); - mock::btsnd_hcic_change_conn_type.body = [&handle, &packet_types]( - uint16_t h, uint16_t p) { - handle = h; - packet_types = p; - }; btm_set_packet_types_from_address(bda, 0x55aa); - ASSERT_EQ(++cnt, get_func_call_count("btsnd_hcic_change_conn_type")); - ASSERT_EQ(0x123, handle); - ASSERT_EQ(Hex16(0x4400 | HCI_PKT_TYPES_MASK_DM1), Hex16(packet_types)); - btm_set_packet_types_from_address(bda, 0xffff); - ASSERT_EQ(++cnt, get_func_call_count("btsnd_hcic_change_conn_type")); - ASSERT_EQ(0x123, handle); - ASSERT_EQ(Hex16(0xcc00 | HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1), - Hex16(packet_types)); - + // Illegal mask, won't be sent. btm_set_packet_types_from_address(bda, 0x0); - ASSERT_EQ(0x123, handle); - ASSERT_EQ(Hex16(0xcc18), Hex16(packet_types)); - mock::btsnd_hcic_change_conn_type = {}; get_btm_client_interface().lifecycle.btm_free(); } -TEST(ScoTest, make_sco_packet) { - std::vector data = {10, 20, 30}; - uint16_t handle = 0xab; - BT_HDR* p = btm_sco_make_packet(data, handle); - ASSERT_EQ(p->event, BT_EVT_TO_LM_HCI_SCO); - ASSERT_EQ(p->len, 3 + data.size()); - ASSERT_EQ(p->data[0], 0xab); - ASSERT_EQ(p->data[1], 0); - ASSERT_EQ(p->data[2], 3); - ASSERT_EQ(p->data[3], 10); - ASSERT_EQ(p->data[4], 20); - ASSERT_EQ(p->data[5], 30); - osi_free(p); -} - TEST(BtmTest, BTM_EIR_MAX_SERVICES) { ASSERT_EQ(46, BTM_EIR_MAX_SERVICES); } } // namespace @@ -232,9 +229,8 @@ struct { tBTM_BD_NAME bd_name; } btm_test; -TEST(SecTest, btm_sec_rmt_name_request_complete) { +TEST_F(StackBtmWithInitFreeTest, btm_sec_rmt_name_request_complete) { bluetooth::common::InitFlags::SetAllForTesting(); - btm_cb.Init(0); ASSERT_TRUE(BTM_SecAddRmtNameNotifyCallback( [](const RawAddress& bd_addr, DEV_CLASS dc, tBTM_BD_NAME bd_name) { @@ -260,84 +256,6 @@ TEST(SecTest, btm_sec_rmt_name_request_complete) { ASSERT_STREQ((const char*)p_bd_name, (const char*)btm_test.bd_name); ASSERT_THAT(btm_test.dc, Each(Eq(0))); ASSERT_EQ(bd_addr, btm_test.bd_addr); - - btm_cb.Free(); -} - -TEST_F(StackBtmWithInitFreeTest, btm_sec_encrypt_change) { - bluetooth::common::InitFlags::SetAllForTesting(); - - RawAddress bd_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6}); - const uint16_t classic_handle = 0x1234; - const uint16_t ble_handle = 0x9876; - - // Check the collision conditionals - btm_cb.collision_start_time = 0UL; - btm_sec_encrypt_change(classic_handle, HCI_ERR_LMP_ERR_TRANS_COLLISION, 0x01); - uint64_t collision_start_time = btm_cb.collision_start_time; - ASSERT_NE(0UL, collision_start_time); - - btm_cb.collision_start_time = 0UL; - btm_sec_encrypt_change(classic_handle, HCI_ERR_DIFF_TRANSACTION_COLLISION, - 0x01); - collision_start_time = btm_cb.collision_start_time; - ASSERT_NE(0UL, collision_start_time); - - // No device - btm_cb.collision_start_time = 0; - btm_sec_encrypt_change(classic_handle, HCI_SUCCESS, 0x01); - ASSERT_EQ(0UL, btm_cb.collision_start_time); - - // Setup device - tBTM_SEC_DEV_REC* device_record = btm_sec_allocate_dev_rec(); - ASSERT_NE(nullptr, device_record); - ASSERT_EQ(BTM_SEC_IN_USE, device_record->sec_flags); - device_record->bd_addr = bd_addr; - device_record->hci_handle = classic_handle; - device_record->ble_hci_handle = ble_handle; - - // With classic device encryption enable - btm_sec_encrypt_change(classic_handle, HCI_SUCCESS, 0x01); - ASSERT_EQ(BTM_SEC_IN_USE | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED, - device_record->sec_flags); - - // With classic device encryption disable - btm_sec_encrypt_change(classic_handle, HCI_SUCCESS, 0x00); - ASSERT_EQ(BTM_SEC_IN_USE | BTM_SEC_AUTHENTICATED, device_record->sec_flags); - device_record->sec_flags = BTM_SEC_IN_USE; - - // With le device encryption enable - btm_sec_encrypt_change(ble_handle, HCI_SUCCESS, 0x01); - ASSERT_EQ(BTM_SEC_IN_USE | BTM_SEC_LE_ENCRYPTED, device_record->sec_flags); - - // With le device encryption disable - btm_sec_encrypt_change(ble_handle, HCI_SUCCESS, 0x00); - ASSERT_EQ(BTM_SEC_IN_USE, device_record->sec_flags); - device_record->sec_flags = BTM_SEC_IN_USE; - - wipe_secrets_and_remove(device_record); -} - -TEST_F(StackBtmWithInitFreeTest, BTM_SetEncryption) { - const RawAddress bd_addr = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); - const tBT_TRANSPORT transport{BT_TRANSPORT_LE}; - tBTM_SEC_CALLBACK* p_callback{nullptr}; - tBTM_BLE_SEC_ACT sec_act{BTM_BLE_SEC_ENCRYPT}; - - // No device - ASSERT_EQ(BTM_WRONG_MODE, BTM_SetEncryption(bd_addr, transport, p_callback, - nullptr, sec_act)); - - // With device - tBTM_SEC_DEV_REC* device_record = btm_sec_allocate_dev_rec(); - ASSERT_NE(nullptr, device_record); - device_record->bd_addr = bd_addr; - device_record->hci_handle = 0x1234; - - ASSERT_EQ(BTM_WRONG_MODE, BTM_SetEncryption(bd_addr, transport, p_callback, - nullptr, sec_act)); - - wipe_secrets_and_remove(device_record); } TEST_F(StackBtmTest, sco_state_text) { @@ -363,95 +281,22 @@ TEST_F(StackBtmTest, sco_state_text) { .c_str()); } -TEST_F(StackBtmTest, btm_ble_sec_req_act_text) { - ASSERT_EQ("BTM_BLE_SEC_REQ_ACT_NONE", - btm_ble_sec_req_act_text(BTM_BLE_SEC_REQ_ACT_NONE)); - ASSERT_EQ("BTM_BLE_SEC_REQ_ACT_ENCRYPT", - btm_ble_sec_req_act_text(BTM_BLE_SEC_REQ_ACT_ENCRYPT)); - ASSERT_EQ("BTM_BLE_SEC_REQ_ACT_PAIR", - btm_ble_sec_req_act_text(BTM_BLE_SEC_REQ_ACT_PAIR)); - ASSERT_EQ("BTM_BLE_SEC_REQ_ACT_DISCARD", - btm_ble_sec_req_act_text(BTM_BLE_SEC_REQ_ACT_DISCARD)); -} - -TEST_F(StackBtmWithInitFreeTest, btm_sec_allocate_dev_rec__all) { - tBTM_SEC_DEV_REC* records[kBtmSecMaxDeviceRecords]; - - // Fill up the records - for (size_t i = 0; i < kBtmSecMaxDeviceRecords; i++) { - ASSERT_EQ(i, list_length(btm_cb.sec_dev_rec)); - records[i] = btm_sec_allocate_dev_rec(); - ASSERT_NE(nullptr, records[i]); - } - - // Second pass up the records - for (size_t i = 0; i < kBtmSecMaxDeviceRecords; i++) { - ASSERT_EQ(kBtmSecMaxDeviceRecords, list_length(btm_cb.sec_dev_rec)); - records[i] = btm_sec_allocate_dev_rec(); - ASSERT_NE(nullptr, records[i]); - } - - // NOTE: The memory allocated for each record is automatically - // allocated by the btm module and freed when the device record - // list is freed. - // Further, the memory for each record is reused when necessary. -} - -TEST_F(StackBtmTest, btm_oob_data_text) { - std::vector> datas = { - std::make_pair(BTM_OOB_NONE, "BTM_OOB_NONE"), - std::make_pair(BTM_OOB_PRESENT_192, "BTM_OOB_PRESENT_192"), - std::make_pair(BTM_OOB_PRESENT_256, "BTM_OOB_PRESENT_256"), - std::make_pair(BTM_OOB_PRESENT_192_AND_256, - "BTM_OOB_PRESENT_192_AND_256"), - std::make_pair(BTM_OOB_UNKNOWN, "BTM_OOB_UNKNOWN"), +bool is_disconnect_reason_valid(const tHCI_REASON& reason); +TEST_F(StackBtmWithInitFreeTest, is_disconnect_reason_valid) { + std::set valid_reason_set{ + HCI_ERR_AUTH_FAILURE, + HCI_ERR_PEER_USER, + HCI_ERR_REMOTE_LOW_RESOURCE, + HCI_ERR_REMOTE_POWER_OFF, + HCI_ERR_UNSUPPORTED_REM_FEATURE, + HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED, + HCI_ERR_UNACCEPT_CONN_INTERVAL, }; - for (const auto& data : datas) { - ASSERT_STREQ(data.second.c_str(), btm_oob_data_text(data.first).c_str()); - } - auto unknown = base::StringPrintf("UNKNOWN[%hhu]", - std::numeric_limits::max()); - ASSERT_STREQ(unknown.c_str(), - btm_oob_data_text(static_cast( - std::numeric_limits::max())) - .c_str()); -} - -TEST_F(StackBtmTest, bond_type_text) { - std::vector> datas = - { - std::make_pair(tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN, - "tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN"), - std::make_pair(tBTM_SEC_DEV_REC::BOND_TYPE_PERSISTENT, - "tBTM_SEC_DEV_REC::BOND_TYPE_PERSISTENT"), - std::make_pair(tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY, - "tBTM_SEC_DEV_REC::BOND_TYPE_TEMPORARY"), - }; - for (const auto& data : datas) { - ASSERT_STREQ(data.second.c_str(), bond_type_text(data.first).c_str()); + for (unsigned u = 0; u < 256; u++) { + const tHCI_REASON reason = static_cast(u); + if (valid_reason_set.count(reason)) + ASSERT_TRUE(is_disconnect_reason_valid(reason)); + else + ASSERT_FALSE(is_disconnect_reason_valid(reason)); } - auto unknown = base::StringPrintf("UNKNOWN[%hhu]", - std::numeric_limits::max()); - ASSERT_STREQ(unknown.c_str(), - bond_type_text(static_cast( - std::numeric_limits::max())) - .c_str()); -} - -TEST_F(StackBtmWithInitFreeTest, wipe_secrets_and_remove) { - bluetooth::common::InitFlags::SetAllForTesting(); - - RawAddress bd_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6}); - const uint16_t classic_handle = 0x1234; - const uint16_t ble_handle = 0x9876; - - // Setup device - tBTM_SEC_DEV_REC* device_record = btm_sec_allocate_dev_rec(); - ASSERT_NE(nullptr, device_record); - ASSERT_EQ(BTM_SEC_IN_USE, device_record->sec_flags); - device_record->bd_addr = bd_addr; - device_record->hci_handle = classic_handle; - device_record->ble_hci_handle = ble_handle; - - wipe_secrets_and_remove(device_record); } diff --git a/system/stack/test/btm_iso_test.cc b/system/stack/test/btm_iso_test.cc index cdd9332226c4d9117a0da2bc8fb8b2d1c480223f..4f78638a243d8b02ad70f58b28a3ae27fa96db1b 100644 --- a/system/stack/test/btm_iso_test.cc +++ b/system/stack/test/btm_iso_test.cc @@ -20,12 +20,13 @@ #include "btm_iso_api.h" #include "hci/include/hci_layer.h" -#include "main/shim/shim.h" +#include "main/shim/hci_layer.h" #include "mock_controller.h" #include "mock_hcic_layer.h" #include "osi/include/allocator.h" #include "stack/btm/btm_dev.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_types.h" #include "stack/include/hci_error_code.h" #include "stack/include/hcidefs.h" @@ -40,9 +41,6 @@ using testing::SaveArg; using testing::StrictMock; using testing::Test; -// Iso Manager currently works on top of the legacy HCI layer -bool bluetooth::shim::is_gd_shim_enabled() { return false; } - // for function pointer testing purpose bool IsIsoActive = false; @@ -50,29 +48,46 @@ tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle) { return nullptr; } void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr, const std::string& msg, const std::string& extra) {} -namespace bte { -class BteInterface { +namespace bluetooth::shim { +class IsoInterface { public: - virtual void HciSend(BT_HDR* p_msg, uint16_t event) = 0; - virtual ~BteInterface() = default; + virtual void HciSend(BT_HDR* packet, uint16_t event) = 0; + virtual ~IsoInterface() = default; }; -class MockBteInterface : public BteInterface { +class MockIsoInterface : public IsoInterface { public: MOCK_METHOD((void), HciSend, (BT_HDR * p_msg, uint16_t event), (override)); }; -static MockBteInterface* bte_interface = nullptr; -static void SetMockBteInterface(MockBteInterface* interface) { - bte_interface = interface; +static MockIsoInterface* iso_interface = nullptr; +static void SetMockIsoInterface(MockIsoInterface* interface) { + iso_interface = interface; +} + +static void set_data_cb( + base::Callback /* send_data_cb */) { + FAIL() << __func__ << " should never be called"; } -} // namespace bte -void bte_main_hci_send(BT_HDR* p_msg, uint16_t event) { - bte::bte_interface->HciSend(p_msg, event); - osi_free(p_msg); +static void transmit_command(const BT_HDR* command, + command_complete_cb complete_callback, + command_status_cb status_cb, void* context) { + FAIL() << __func__ << " should never be called"; } +static void transmit_downward(uint16_t type, void* data) { + iso_interface->HciSend((BT_HDR*)data, type); + osi_free(data); +} + +static hci_t interface = {.set_data_cb = set_data_cb, + .transmit_command = transmit_command, + .transmit_downward = transmit_downward}; + +const hci_t* hci_layer_get_interface() { return &interface; } +} // namespace bluetooth::shim + namespace { class MockCigCallbacks : public bluetooth::hci::iso_manager::CigCallbacks { public: @@ -121,7 +136,7 @@ class MockBigCallbacks : public bluetooth::hci::iso_manager::BigCallbacks { class IsoManagerTest : public Test { protected: void SetUp() override { - bte::SetMockBteInterface(&bte_interface_); + bluetooth::shim::SetMockIsoInterface(&iso_interface_); hcic::SetMockHcicInterface(&hcic_interface_); controller::SetMockControllerInterface(&controller_interface_); @@ -145,7 +160,7 @@ class IsoManagerTest : public Test { big_callbacks_.reset(); cig_callbacks_.reset(); - bte::SetMockBteInterface(nullptr); + bluetooth::shim::SetMockIsoInterface(nullptr); hcic::SetMockHcicInterface(nullptr); controller::SetMockControllerInterface(nullptr); } @@ -319,7 +334,7 @@ class IsoManagerTest : public Test { volatile_test_big_params_evt_; IsoManager* manager_instance_; - bte::MockBteInterface bte_interface_; + bluetooth::shim::MockIsoInterface iso_interface_; hcic::MockHcicInterface hcic_interface_; controller::MockControllerInterface controller_interface_; @@ -330,8 +345,8 @@ class IsoManagerTest : public Test { const bluetooth::hci::iso_manager::cig_create_cmpl_evt IsoManagerTest::kDefaultCigParamsEvt = { - .cig_id = 128, .status = 0x00, + .cig_id = 128, .conn_handles = std::vector({0x0EFF, 0x00FF}), }; @@ -652,6 +667,41 @@ TEST_F(IsoManagerTest, CreateCigCallbackValid) { std::vector({0x0EFF, 0x00FF}).begin())); } +TEST_F(IsoManagerTest, CreateCigLateArrivingCallback) { + // Catch the callback + base::OnceCallback iso_cb; + ON_CALL(hcic_interface_, SetCigParams) + .WillByDefault([&](auto cig_id, auto, + base::OnceCallback cb) { + iso_cb = std::move(cb); + }); + + IsoManager::GetInstance()->CreateCig( + volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); + + // Stop the IsoManager before calling the callback + IsoManager::GetInstance()->Stop(); + + // Call the callback and expect no call + EXPECT_CALL(*cig_callbacks_, OnCigEvent(_, _)).Times(0); + ASSERT_FALSE(iso_cb.is_null()); + + uint8_t hci_mock_rsp_buffer[3 + sizeof(uint16_t) * + volatile_test_cig_create_cmpl_evt_ + .conn_handles.size()]; + uint8_t* p = hci_mock_rsp_buffer; + UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.status); + UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.cig_id); + UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.conn_handles.size()); + for (auto handle : volatile_test_cig_create_cmpl_evt_.conn_handles) { + UINT16_TO_STREAM(p, handle); + } + std::move(iso_cb).Run( + hci_mock_rsp_buffer, + 3 + sizeof(uint16_t) * + volatile_test_cig_create_cmpl_evt_.conn_handles.size()); +} + // Check if CIG reconfigure triggers HCI layer call TEST_F(IsoManagerTest, ReconfigureCigHciCall) { IsoManager::GetInstance()->CreateCig( @@ -765,6 +815,43 @@ TEST_F(IsoManagerTest, ReconfigureCigValid) { volatile_test_cig_create_cmpl_evt_.conn_handles.begin())); } +TEST_F(IsoManagerTest, ReconfigureCigLateArrivingCallback) { + IsoManager::GetInstance()->CreateCig( + volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); + + // Catch the callback + base::OnceCallback iso_cb; + ON_CALL(hcic_interface_, SetCigParams) + .WillByDefault([&](auto cig_id, auto, + base::OnceCallback cb) { + iso_cb = std::move(cb); + }); + IsoManager::GetInstance()->ReconfigureCig( + volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams2); + + // Stop the IsoManager before calling the callback + IsoManager::GetInstance()->Stop(); + + // Call the callback and expect no call + EXPECT_CALL(*cig_callbacks_, OnCigEvent(_, _)).Times(0); + ASSERT_FALSE(iso_cb.is_null()); + + uint8_t hci_mock_rsp_buffer[3 + sizeof(uint16_t) * + volatile_test_cig_create_cmpl_evt_ + .conn_handles.size()]; + uint8_t* p = hci_mock_rsp_buffer; + UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.status); + UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.cig_id); + UINT8_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.conn_handles.size()); + for (auto handle : volatile_test_cig_create_cmpl_evt_.conn_handles) { + UINT16_TO_STREAM(p, handle); + } + std::move(iso_cb).Run( + hci_mock_rsp_buffer, + 3 + sizeof(uint16_t) * + volatile_test_cig_create_cmpl_evt_.conn_handles.size()); +} + TEST_F(IsoManagerTest, RemoveCigHciCall) { IsoManager::GetInstance()->CreateCig( volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); @@ -941,7 +1028,7 @@ TEST_F(IsoManagerDeathTest, ConnectSameCisTwice) { ASSERT_EXIT( IsoManager::GetInstance()->IsoManager::GetInstance()->EstablishCis( params), - ::testing::KilledBySignal(SIGABRT), "Already connected or connecting"); + ::testing::KilledBySignal(SIGABRT), "already connected or connecting"); } TEST_F(IsoManagerDeathTest, EstablishCisInvalidResponsePacket) { @@ -1112,6 +1199,47 @@ TEST_F(IsoManagerTest, EstablishCisValid) { IsoManager::GetInstance()->EstablishCis(params); } +TEST_F(IsoManagerTest, EstablishCisLateArrivingCallback) { + IsoManager::GetInstance()->CreateCig( + volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); + + // Catch the callback + base::OnceCallback iso_cb; + EXT_CIS_CREATE_CFG cis_create_cfg; + uint8_t cis_num = 0; + ON_CALL(hcic_interface_, CreateCis) + .WillByDefault([&](uint8_t num_cis, const EXT_CIS_CREATE_CFG* cis_cfg, + base::OnceCallback cb) { + cis_create_cfg = *cis_cfg; + cis_num = num_cis; + iso_cb = std::move(cb); + }); + + // Establish all CISes before setting up their data paths + 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); + + // Stop the IsoManager before calling the callback + IsoManager::GetInstance()->Stop(); + + // Call the callback and expect no call + EXPECT_CALL( + *cig_callbacks_, + OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _)) + .Times(0); + ASSERT_FALSE(iso_cb.is_null()); + + // Command complete with error will trigger the callback without + // injecting any additional HCI events + std::vector buf(1); + uint8_t* p = buf.data(); + UINT8_TO_STREAM(p, 0x01); // status + std::move(iso_cb).Run(buf.data(), buf.size()); +} + TEST_F(IsoManagerTest, ReconnectCisValid) { IsoManager::GetInstance()->CreateCig( volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); @@ -1682,6 +1810,55 @@ TEST_F(IsoManagerTest, SetupIsoDataPathInvalidStatus) { } } +TEST_F(IsoManagerTest, SetupIsoDataPathLateArrivingCallback) { + IsoManager::GetInstance()->CreateCig( + volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); + IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, + kDefaultBigParams); + + // Establish all CISes before setting up their data paths + 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); + + bluetooth::hci::iso_manager::iso_data_path_params path_params = + kDefaultIsoDataPathParams; + + // Catch the callback + base::OnceCallback iso_cb; + ON_CALL(hcic_interface_, SetupIsoDataPath) + .WillByDefault( + [&iso_cb](uint16_t iso_handle, uint8_t /* data_path_dir */, + uint8_t /* data_path_id */, uint8_t /* codec_id_format */, + uint16_t /* codec_id_company */, + uint16_t /* codec_id_vendor */, + uint32_t /* controller_delay */, + std::vector /* codec_conf */, + base::OnceCallback cb) { + iso_cb = std::move(cb); + }); + // Setup and remove data paths for all CISes + path_params.data_path_dir = + bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput; + auto& handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0]; + IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params); + + // Stop the IsoManager before calling the callback + IsoManager::GetInstance()->Stop(); + + // Call the callback and expect no call + EXPECT_CALL(*cig_callbacks_, OnSetupIsoDataPath(_, handle, _)).Times(0); + ASSERT_FALSE(iso_cb.is_null()); + + std::vector buf(3); + uint8_t* p = buf.data(); + UINT8_TO_STREAM(p, HCI_SUCCESS); + UINT16_TO_STREAM(p, handle); + std::move(iso_cb).Run(buf.data(), buf.size()); +} + TEST_F(IsoManagerTest, RemoveIsoDataPathValid) { IsoManager::GetInstance()->CreateCig( volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); @@ -1831,6 +2008,56 @@ TEST_F(IsoManagerTest, RemoveIsoDataPathInvalidStatus) { iso_handle, kDefaultIsoDataPathParams.data_path_dir); } +TEST_F(IsoManagerTest, RemoveIsoDataPathLateArrivingCallback) { + IsoManager::GetInstance()->CreateCig( + volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); + IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, + kDefaultBigParams); + + // Establish all CISes before setting up their data paths + 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); + + bluetooth::hci::iso_manager::iso_data_path_params path_params = + kDefaultIsoDataPathParams; + + // Setup and remove data paths for all CISes + path_params.data_path_dir = + bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput; + auto& handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0]; + IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params); + + // Catch the callback + base::OnceCallback iso_cb; + ON_CALL(hcic_interface_, RemoveIsoDataPath) + .WillByDefault( + [&iso_cb](uint16_t iso_handle, uint8_t data_path_dir, + base::OnceCallback cb) { + iso_cb = std::move(cb); + }); + IsoManager::GetInstance()->RemoveIsoDataPath(handle, + path_params.data_path_dir); + + // Stop the IsoManager before calling the callback + IsoManager::GetInstance()->Stop(); + + // Call the callback and expect no call + EXPECT_CALL(*cig_callbacks_, + OnRemoveIsoDataPath(HCI_SUCCESS, handle, + volatile_test_cig_create_cmpl_evt_.cig_id)) + .Times(0); + ASSERT_FALSE(iso_cb.is_null()); + + std::vector buf(3); + uint8_t* p = buf.data(); + UINT8_TO_STREAM(p, HCI_SUCCESS); + UINT16_TO_STREAM(p, handle); + std::move(iso_cb).Run(buf.data(), buf.size()); +} + TEST_F(IsoManagerTest, SendIsoDataWithNoCigConnected) { std::vector data_vec(108, 0); IsoManager::GetInstance()->CreateCig( @@ -1839,7 +2066,7 @@ TEST_F(IsoManagerTest, SendIsoDataWithNoCigConnected) { auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0]; IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size()); - EXPECT_CALL(bte_interface_, HciSend).Times(0); + EXPECT_CALL(iso_interface_, HciSend).Times(0); } TEST_F(IsoManagerTest, SendIsoDataCigValid) { @@ -1862,7 +2089,7 @@ TEST_F(IsoManagerTest, SendIsoDataCigValid) { for (uint8_t num_pkts = 2; num_pkts != 0; num_pkts--) { constexpr uint8_t data_len = 108; - EXPECT_CALL(bte_interface_, HciSend) + EXPECT_CALL(iso_interface_, HciSend) .WillOnce([handle, data_len](BT_HDR* p_msg, uint16_t event) { uint8_t* p = p_msg->data; uint16_t msg_handle; @@ -1914,7 +2141,7 @@ TEST_F(IsoManagerTest, SendIsoDataBigValid) { for (uint8_t num_pkts = 2; num_pkts != 0; num_pkts--) { constexpr uint8_t data_len = 108; - EXPECT_CALL(bte_interface_, HciSend) + EXPECT_CALL(iso_interface_, HciSend) .WillOnce([handle, data_len](BT_HDR* p_msg, uint16_t event) { uint8_t* p = p_msg->data; uint16_t msg_handle; @@ -1979,7 +2206,7 @@ TEST_F(IsoManagerTest, SendIsoDataNoCredits) { * expect the redundant packets to be ignored and not propagated down to the * HCI. */ - EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); + EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); for (uint8_t i = 0; i < (2 * num_buffers); i++) { IsoManager::GetInstance()->SendIsoData( volatile_test_cig_create_cmpl_evt_.conn_handles[0], data_vec.data(), @@ -2004,7 +2231,7 @@ TEST_F(IsoManagerTest, SendIsoDataNoCredits) { * expect the redundant packets to be ignored and not propagated down to the * HCI. */ - EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers); + EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers); for (uint8_t i = 0; i < (2 * num_buffers); i++) { IsoManager::GetInstance()->SendIsoData( volatile_test_big_params_evt_.conn_handles[0], data_vec.data(), @@ -2034,7 +2261,7 @@ TEST_F(IsoManagerTest, SendIsoDataCreditsReturned) { * expect the redundant packets to be ignored and not propagated down to the * HCI. */ - EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); + EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); for (uint8_t i = 0; i < (2 * num_buffers); i++) { IsoManager::GetInstance()->SendIsoData( volatile_test_cig_create_cmpl_evt_.conn_handles[0], data_vec.data(), @@ -2050,7 +2277,7 @@ TEST_F(IsoManagerTest, SendIsoDataCreditsReturned) { IsoManager::GetInstance()->HandleNumComplDataPkts(mock_rsp, sizeof(mock_rsp)); // Expect some more events go down the HCI - EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); + EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); for (uint8_t i = 0; i < (2 * num_buffers); i++) { IsoManager::GetInstance()->SendIsoData( volatile_test_cig_create_cmpl_evt_.conn_handles[0], data_vec.data(), @@ -2074,7 +2301,7 @@ TEST_F(IsoManagerTest, SendIsoDataCreditsReturned) { * expect the redundant packets to be ignored and not propagated down to the * HCI. */ - EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); + EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); for (uint8_t i = 0; i < (2 * num_buffers); i++) { IsoManager::GetInstance()->SendIsoData( volatile_test_big_params_evt_.conn_handles[0], data_vec.data(), @@ -2089,7 +2316,7 @@ TEST_F(IsoManagerTest, SendIsoDataCreditsReturned) { IsoManager::GetInstance()->HandleNumComplDataPkts(mock_rsp, sizeof(mock_rsp)); // Expect some more events go down the HCI - EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); + EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); for (uint8_t i = 0; i < (2 * num_buffers); i++) { IsoManager::GetInstance()->SendIsoData( volatile_test_big_params_evt_.conn_handles[0], data_vec.data(), @@ -2117,7 +2344,7 @@ TEST_F(IsoManagerTest, SendIsoDataCreditsReturnedByDisconnection) { } /* Sending lot of ISO data to first ISO and getting all the credits */ - EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); + EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); for (uint8_t i = 0; i < num_buffers; i++) { IsoManager::GetInstance()->SendIsoData( volatile_test_cig_create_cmpl_evt_.conn_handles[0], data_vec.data(), @@ -2129,7 +2356,7 @@ TEST_F(IsoManagerTest, SendIsoDataCreditsReturnedByDisconnection) { volatile_test_cig_create_cmpl_evt_.conn_handles[0], 16); /* Try to send ISO data on the second ISO. Expect credits being available.*/ - EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); + EXPECT_CALL(iso_interface_, HciSend).Times(num_buffers).RetiresOnSaturation(); for (uint8_t i = 0; i < num_buffers; i++) { IsoManager::GetInstance()->SendIsoData( volatile_test_cig_create_cmpl_evt_.conn_handles[1], data_vec.data(), @@ -2150,7 +2377,7 @@ TEST_F(IsoManagerDeathTest, SendIsoDataWithNoDataPath) { } IsoManager::GetInstance()->EstablishCis(params); - EXPECT_CALL(bte_interface_, HciSend).Times(0); + EXPECT_CALL(iso_interface_, HciSend).Times(0); IsoManager::GetInstance()->SendIsoData( volatile_test_cig_create_cmpl_evt_.conn_handles[0], data_vec.data(), data_vec.size()); @@ -2159,7 +2386,7 @@ TEST_F(IsoManagerDeathTest, SendIsoDataWithNoDataPath) { IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams); - EXPECT_CALL(bte_interface_, HciSend).Times(0); + EXPECT_CALL(iso_interface_, HciSend).Times(0); IsoManager::GetInstance()->SendIsoData( volatile_test_big_params_evt_.conn_handles[0], data_vec.data(), data_vec.size()); @@ -2235,6 +2462,28 @@ TEST_F(IsoManagerTest, HandleDisconnectDisconnectedCig) { IsoManager::GetInstance()->HandleDisconnect(handle, 16); } +TEST_F(IsoManagerTest, HandleDisconnectLateArrivingCallback) { + IsoManager::GetInstance()->CreateCig( + volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); + + auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0]; + IsoManager::GetInstance()->EstablishCis({{{handle, 1}}}); + + EXPECT_CALL(*big_callbacks_, OnBigEvent).Times(0); + EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0); + EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0); + + // Expect disconnect event exactly once + EXPECT_CALL( + *cig_callbacks_, + OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDisconnected, _)) + .Times(0); + + // Expect no callback on late arriving event + IsoManager::GetInstance()->Stop(); + IsoManager::GetInstance()->HandleDisconnect(handle, 16); +} + TEST_F(IsoManagerTest, HandleIsoData) { IsoManager::GetInstance()->CreateCig( volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); @@ -2381,3 +2630,65 @@ TEST_F(IsoManagerTest, HandleIsoDataSameSeqNb) { IsoManager::GetInstance()->HandleIsoData(dummy_msg.data()); IsoManager::GetInstance()->HandleIsoData(dummy_msg.data()); } + +TEST_F(IsoManagerTest, ReadIsoLinkQualityLateArrivingCallback) { + IsoManager::GetInstance()->CreateCig( + volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); + + EXPECT_CALL( + *cig_callbacks_, + OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _)) + .Times(kDefaultCigParams.cis_cfgs.size()) + .WillRepeatedly([this](uint8_t type, void* data) { + bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt = + static_cast( + data); + + ASSERT_EQ(evt->status, HCI_SUCCESS); + ASSERT_TRUE( + std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(), + volatile_test_cig_create_cmpl_evt_.conn_handles.end(), + evt->cis_conn_hdl) != + volatile_test_cig_create_cmpl_evt_.conn_handles.end()); + }); + + // Establish all CISes + 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); + + // Catch the callback + base::OnceCallback iso_cb; + ON_CALL(hcic_interface_, ReadIsoLinkQuality) + .WillByDefault( + [&iso_cb](uint16_t iso_handle, + base::OnceCallback cb) { + iso_cb = std::move(cb); + }); + auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0]; + IsoManager::GetInstance()->ReadIsoLinkQuality(handle); + + // Stop the IsoManager before calling the callback + IsoManager::GetInstance()->Stop(); + + // Call the callback and expect no call + EXPECT_CALL(*cig_callbacks_, + OnIsoLinkQualityRead(handle, _, _, _, _, _, _, _, _)) + .Times(0); + ASSERT_FALSE(iso_cb.is_null()); + + std::vector buf(31); + uint8_t* p = buf.data(); + UINT8_TO_STREAM(p, HCI_SUCCESS); + UINT16_TO_STREAM(p, handle); + UINT32_TO_STREAM(p, 0); + UINT32_TO_STREAM(p, 0); + UINT32_TO_STREAM(p, 0); + UINT32_TO_STREAM(p, 0); + UINT32_TO_STREAM(p, 0); + UINT32_TO_STREAM(p, 0); + UINT32_TO_STREAM(p, 0); + std::move(iso_cb).Run(buf.data(), buf.size()); +} diff --git a/system/stack/test/common/mock_btif_storage.cc b/system/stack/test/common/mock_btif_storage.cc index b65d89ac2ff0d7c8a18dbec3057a171df6af4d3a..b2fc3c89b1e2149b527183e4db86c620d552b588 100644 --- a/system/stack/test/common/mock_btif_storage.cc +++ b/system/stack/test/common/mock_btif_storage.cc @@ -18,6 +18,8 @@ #include "mock_btif_storage.h" +#include "stack/include/btm_sec_api_types.h" + static bluetooth::manager::MockBtifStorageInterface* btif_storage_interface = nullptr; @@ -30,4 +32,4 @@ void btif_storage_load_bonded_eatt(void) { btif_storage_interface->LoadBondedEatt(); } -uint8_t btif_storage_get_local_io_caps() { return 0; } +tBTM_IO_CAP btif_storage_get_local_io_caps() { return BTM_IO_CAP_UNKNOWN; } diff --git a/system/stack/test/common/mock_btm_layer.cc b/system/stack/test/common/mock_btm_layer.cc index dc63bbf7d366c087a4f4e478941788f348e9a4ea..22a17a78c910437e4531cf083f3371b08f293eda 100644 --- a/system/stack/test/common/mock_btm_layer.cc +++ b/system/stack/test/common/mock_btm_layer.cc @@ -18,6 +18,7 @@ #include "mock_btm_layer.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/btm_client_interface.h" #include "stack/include/rfcdefs.h" #include "types/raw_address.h" @@ -53,9 +54,15 @@ uint16_t BTM_GetMaxPacketSize(const RawAddress& addr) { return RFCOMM_DEFAULT_MTU; } +bool BTM_IsAclConnectionUp(const RawAddress& remote_bda, + tBT_TRANSPORT transport) { + return true; +} + struct btm_client_interface_t btm_client_interface = { .peer = { + .BTM_IsAclConnectionUp = BTM_IsAclConnectionUp, .BTM_GetMaxPacketSize = BTM_GetMaxPacketSize, }, }; diff --git a/system/stack/test/common/mock_btm_layer.h b/system/stack/test/common/mock_btm_layer.h index ea9875b10d24c4742ab740a099e6e6ec02ca2258..741d55c130ccb200f8bc6a11ad9e5bf057d29e2c 100644 --- a/system/stack/test/common/mock_btm_layer.h +++ b/system/stack/test/common/mock_btm_layer.h @@ -20,6 +20,7 @@ #include #include "stack/include/btm_api_types.h" +#include "stack/include/btm_sec_api_types.h" #include "stack/include/btm_status.h" #include "types/raw_address.h" diff --git a/system/stack/test/common/mock_hcic_layer.cc b/system/stack/test/common/mock_hcic_layer.cc index e9f4d13a7a76d5200b818707214ecbe5785d2bba..33a57ce69a42b8e1f373324c921e4b21bafea729 100644 --- a/system/stack/test/common/mock_hcic_layer.cc +++ b/system/stack/test/common/mock_hcic_layer.cc @@ -104,11 +104,32 @@ void btsnd_hcic_term_big(uint8_t big_handle, uint8_t reason) { hcic_interface->TerminateBig(big_handle, reason); } -bluetooth::legacy::hci::Interface interface_ = { - .Disconnect = btsnd_hcic_disconnect, -}; +namespace bluetooth::legacy::hci { -const bluetooth::legacy::hci::Interface& -bluetooth::legacy::hci::GetInterface() { - return interface_; -} +class MockInterface : public Interface { + public: + virtual void StartInquiry(const LAP inq_lap, uint8_t duration, + uint8_t response_cnt) const override { + FAIL(); + } + virtual void InquiryCancel() const override { FAIL(); } + virtual void Disconnect(uint16_t handle, uint8_t reason) const override { + btsnd_hcic_disconnect(handle, reason); + } + virtual void ChangeConnectionPacketType( + uint16_t handle, uint16_t packet_types) const override { + FAIL(); + } + virtual void StartRoleSwitch(const RawAddress& bd_addr, + uint8_t role) const override { + FAIL(); + } + virtual void ConfigureDataPath( + hci_data_direction_t data_path_direction, uint8_t data_path_id, + std::vector vendor_config) const override { + FAIL(); + } +} interface_; + +const Interface& GetInterface() { return interface_; } +} // namespace bluetooth::legacy::hci diff --git a/system/stack/test/common/mock_main_shim.cc b/system/stack/test/common/mock_main_shim.cc index b74c6b011db702b99c32515f690cddc3cbd4194f..47e5c378c5472283dafe2752ae4bcd330773c616 100644 --- a/system/stack/test/common/mock_main_shim.cc +++ b/system/stack/test/common/mock_main_shim.cc @@ -32,22 +32,10 @@ #define UNUSED_ATTR #endif -bool bluetooth::shim::is_gd_l2cap_enabled() { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::is_gd_shim_enabled() { - inc_func_call_count(__func__); - return false; -} bool bluetooth::shim::is_gd_stack_started_up() { inc_func_call_count(__func__); return false; } -bool bluetooth::shim::is_gd_link_policy_enabled() { - inc_func_call_count(__func__); - return false; -} future_t* GeneralShutDown() { inc_func_call_count(__func__); return nullptr; diff --git a/system/stack/test/common/stack_test_packet_utils.cc b/system/stack/test/common/stack_test_packet_utils.cc index 7f89a61c8057667af68a5d00c50f8639dea30c32..e605813ebe4616d687e5d7cbc866bb974b4c3522 100644 --- a/system/stack/test/common/stack_test_packet_utils.cc +++ b/system/stack/test/common/stack_test_packet_utils.cc @@ -64,7 +64,7 @@ BT_HDR* AllocateWrappedIncomingL2capAclPacket(const uint8_t* acl_packet_bytes, packet->offset = 4 + L2CAP_PKT_OVERHEAD; packet->len = static_cast(buffer_length - 4 - L2CAP_PKT_OVERHEAD); packet->layer_specific = 0; - packet->event = MSG_HC_TO_STACK_HCI_ACL; + packet->event = 0x1100; // MSG_HC_TO_STACK_HCI_ACL; memcpy(packet->data, acl_packet_bytes, buffer_length); return packet; } diff --git a/system/stack/test/crypto_toolbox_test.cc b/system/stack/test/crypto_toolbox_test.cc deleted file mode 100644 index 3c7eb0b01718d98c1a034d2f55cfa785f37bee6d..0000000000000000000000000000000000000000 --- a/system/stack/test/crypto_toolbox_test.cc +++ /dev/null @@ -1,402 +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 "stack/crypto_toolbox/crypto_toolbox.h" - -#include -#include -#include -#include - -#include - -#include "stack/crypto_toolbox/aes.h" -#include "stack/include/bt_octets.h" - -using ::testing::ElementsAreArray; - -namespace crypto_toolbox { - -// BT Spec 5.0 | Vol 3, Part H D.1 -TEST(CryptoToolboxTest, bt_spec_test_d_1_test) { - uint8_t k[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; - - uint8_t m[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - uint8_t aes_cmac_k_m[] = {0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3, - 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f}; - - uint8_t output[16]; - aes_context ctx; - aes_set_key(k, sizeof(k), &ctx); - aes_encrypt(m, output, &ctx); /* outputs in byte 48 to byte 63 */ - - EXPECT_THAT(output, ElementsAreArray(aes_cmac_k_m, OCTET16_LEN)); - - // useful for debugging - // LOG(INFO) << "k " << base::HexEncode(k, OCTET16_LEN); - // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m)); - // LOG(INFO) << "output " << base::HexEncode(output, OCTET16_LEN); -} - -// BT Spec 5.0 | Vol 3, Part H D.1.1 -TEST(CryptoToolboxTest, bt_spec_example_d_1_1_test) { - Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; - - Octet16 aes_cmac_k_m{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, - 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(k), std::end(k)); - std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m)); - - Octet16 output = aes_cmac(k, nullptr /* empty message */, 0); - - EXPECT_EQ(output, aes_cmac_k_m); - - // useful for debugging - // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size()); - // LOG(INFO) << "aes_cmac(k,nullptr) " - // << base::HexEncode(output.data(), output.size()); -} - -// BT Spec 5.0 | Vol 3, Part H D.1.2 -TEST(CryptoToolboxTest, bt_spec_example_d_1_2_test) { - Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; - - Octet16 m = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, - 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a}; - - Octet16 aes_cmac_k_m{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, - 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(k), std::end(k)); - std::reverse(std::begin(m), std::end(m)); - std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m)); - - Octet16 output = aes_cmac(k, m); - - EXPECT_EQ(output, aes_cmac_k_m); - - // useful for debugging - // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size()); - // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m)); - // LOG(INFO) << "aes_cmac(k,m) " - // << base::HexEncode(output.data(), output.size()); -} - -// BT Spec 5.0 | Vol 3, Part H D.1.3 -TEST(CryptoToolboxTest, bt_spec_example_d_1_3_test) { - Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; - - uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, - 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, - 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, - 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11}; - - Octet16 aes_cmac_k_m{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, - 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(k), std::end(k)); - std::reverse(std::begin(m), std::end(m)); - std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m)); - - Octet16 output = aes_cmac(k, m, sizeof(m)); - EXPECT_EQ(output, aes_cmac_k_m); -} - -// BT Spec 5.0 | Vol 3, Part H D.1.4 -TEST(CryptoToolboxTest, bt_spec_example_d_1_4_test) { - Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; - - uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, - 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, - 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, - 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, - 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, - 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, - 0xe6, 0x6c, 0x37, 0x10}; - - Octet16 aes_cmac_k_m{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, - 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(k), std::end(k)); - std::reverse(std::begin(m), std::end(m)); - std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m)); - - Octet16 output = aes_cmac(k, m, sizeof(m)); - - EXPECT_EQ(output, aes_cmac_k_m); -} - -// BT Spec 5.0 | Vol 3, Part H D.2 -TEST(CryptoToolboxTest, bt_spec_example_d_2_test) { - std::vector u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c, - 0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9, - 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb, - 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6}; - std::vector v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a, - 0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a, - 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d, 0x7c, 0xfb, - 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd}; - Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, - 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab}; - uint8_t z = 0x00; - - Octet16 aes_cmac_k_m{0xf2, 0xc9, 0x16, 0xf1, 0x07, 0xa9, 0xbd, 0x1c, - 0xf1, 0xed, 0xa1, 0xbe, 0xa9, 0x74, 0x87, 0x2d}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(u), std::end(u)); - std::reverse(std::begin(v), std::end(v)); - std::reverse(std::begin(x), std::end(x)); - std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m)); - - Octet16 output = f4(u.data(), v.data(), x, z); - - EXPECT_EQ(output, aes_cmac_k_m); -} - -// BT Spec 5.0 | Vol 3, Part H D.3 -TEST(CryptoToolboxTest, bt_spec_example_d_3_test) { - std::array dhkey_w{ - 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, - 0xa6, 0x0a, 0x39, 0x7d, 0x9b, 0x99, 0x79, 0x6b, 0x13, 0xb4, 0xf8, - 0x66, 0xf1, 0x86, 0x8d, 0x34, 0xf3, 0x73, 0xbf, 0xa6, 0x98}; - Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, - 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab}; - Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, - 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf}; - std::array a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce}; - std::array a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1}; - - Octet16 expected_ltk{0x69, 0x86, 0x79, 0x11, 0x69, 0xd7, 0xcd, 0x23, - 0x98, 0x05, 0x22, 0xb5, 0x94, 0x75, 0x0a, 0x38}; - Octet16 expected_mac_key{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02, - 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(dhkey_w), std::end(dhkey_w)); - std::reverse(std::begin(n1), std::end(n1)); - std::reverse(std::begin(n2), std::end(n2)); - std::reverse(std::begin(a1), std::end(a1)); - std::reverse(std::begin(a2), std::end(a2)); - std::reverse(std::begin(expected_ltk), std::end(expected_ltk)); - std::reverse(std::begin(expected_mac_key), std::end(expected_mac_key)); - - Octet16 mac_key, ltk; - f5(dhkey_w.data(), n1, n2, a1.data(), a2.data(), &mac_key, <k); - - EXPECT_EQ(mac_key, expected_mac_key); - EXPECT_EQ(ltk, expected_ltk); -} - -// BT Spec 5.0 | Vol 3, Part H D.4 -TEST(CryptoToolboxTest, bt_spec_example_d_4_test) { - Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, - 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab}; - Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, - 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf}; - Octet16 r{0x12, 0xa3, 0x34, 0x3b, 0xb4, 0x53, 0xbb, 0x54, - 0x08, 0xda, 0x42, 0xd2, 0x0c, 0x2d, 0x0f, 0xc8}; - std::vector IOcap{0x01, 0x01, 0x02}; - std::vector a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce}; - std::vector a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1}; - - Octet16 MacKey{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02, - 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20}; - - Octet16 expected_aes_cmac{0xe3, 0xc4, 0x73, 0x98, 0x9c, 0xd0, 0xe8, 0xc5, - 0xd2, 0x6c, 0x0b, 0x09, 0xda, 0x95, 0x8f, 0x61}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(n1), std::end(n1)); - std::reverse(std::begin(n2), std::end(n2)); - std::reverse(std::begin(r), std::end(r)); - std::reverse(std::begin(IOcap), std::end(IOcap)); - std::reverse(std::begin(a1), std::end(a1)); - std::reverse(std::begin(a2), std::end(a2)); - std::reverse(std::begin(MacKey), std::end(MacKey)); - std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac)); - - Octet16 aes_cmac = f6(MacKey, n1, n2, r, IOcap.data(), a1.data(), a2.data()); - - EXPECT_EQ(aes_cmac, expected_aes_cmac); -} - -// BT Spec 5.0 | Vol 3, Part H D.5 -TEST(CryptoToolboxTest, bt_spec_example_d_5_test) { - std::array u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c, - 0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9, - 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb, - 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6}; - std::array v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a, - 0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a, - 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d, 0x7c, 0xfb, - 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd}; - - Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, - 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab}; - Octet16 y{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, - 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(u), std::end(u)); - std::reverse(std::begin(v), std::end(v)); - std::reverse(std::begin(x), std::end(x)); - std::reverse(std::begin(y), std::end(y)); - - uint32_t val = g2(u.data(), v.data(), x, y); - - /* the returned value is already mod 1000000, so do mod on the test result - * value too */ - EXPECT_EQ(val, 0x2f9ed5baU % 1000000); -} - -// BT Spec 5.0 | Vol 3, Part H D.6 -TEST(CryptoToolboxTest, bt_spec_example_d_6_test) { - Octet16 key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, - 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b}; - std::array keyID{0x6c, 0x65, 0x62, 0x72}; - Octet16 expected_aes_cmac{0x2d, 0x9a, 0xe1, 0x02, 0xe7, 0x6d, 0xc9, 0x1c, - 0xe8, 0xd3, 0xa9, 0xe2, 0x80, 0xb1, 0x63, 0x99}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(key), std::end(key)); - std::reverse(std::begin(keyID), std::end(keyID)); - std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac)); - - Octet16 aes_cmac = h6(key, keyID); - EXPECT_EQ(aes_cmac, expected_aes_cmac); -} - -// BT Spec 5.0 | Vol 3, Part H D.7 -TEST(CryptoToolboxTest, bt_spec_example_d_7_test) { - Octet16 IRK{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, - 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b}; - Octet16 prand{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x81, 0x94}; - Octet16 expected_aes_128{0x15, 0x9d, 0x5f, 0xb7, 0x2e, 0xbe, 0x23, 0x11, - 0xa4, 0x8c, 0x1b, 0xdc, 0xc4, 0x0d, 0xfb, 0xaa}; - std::array expected_ah{0x0d, 0xfb, 0xaa}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(IRK), std::end(IRK)); - std::reverse(std::begin(prand), std::end(prand)); - std::reverse(std::begin(expected_aes_128), std::end(expected_aes_128)); - std::reverse(std::begin(expected_ah), std::end(expected_ah)); - - Octet16 result = aes_128(IRK, prand.data(), 3); - EXPECT_EQ(expected_aes_128, result); - - // little/big endian 24 bits - EXPECT_EQ(result[0], expected_ah[0]); - EXPECT_EQ(result[1], expected_ah[1]); - EXPECT_EQ(result[2], expected_ah[2]); -} - -// BT Spec 5.0 | Vol 3, Part H D.8 -TEST(CryptoToolboxTest, bt_spec_example_d_8_test) { - Octet16 Key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, - 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b}; - Octet16 SALT{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31}; - Octet16 expected_aes_cmac{0xfb, 0x17, 0x35, 0x97, 0xc6, 0xa3, 0xc0, 0xec, - 0xd2, 0x99, 0x8c, 0x2a, 0x75, 0xa5, 0x70, 0x11}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(Key), std::end(Key)); - std::reverse(std::begin(SALT), std::end(SALT)); - std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac)); - - Octet16 aes_cmac = h7(SALT, Key); - EXPECT_EQ(expected_aes_cmac, aes_cmac); -} - -Octet16 smp_calculate_ltk_to_link_key(const Octet16& ltk, bool use_h7); - -// BT Spec 5.0 | Vol 3, Part H D.9 -TEST(CryptoToolboxTest, bt_spec_example_d_9_test) { - Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58, - 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64}; - Octet16 expected_link_key{0x28, 0x7a, 0xd3, 0x79, 0xdc, 0xa4, 0x02, 0x53, - 0x0a, 0x39, 0xf1, 0xf4, 0x30, 0x47, 0xb8, 0x35}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(LTK), std::end(LTK)); - std::reverse(std::begin(expected_link_key), std::end(expected_link_key)); - - Octet16 link_key = ltk_to_link_key(LTK, true); - EXPECT_EQ(expected_link_key, link_key); -} - -// BT Spec 5.0 | Vol 3, Part H D.10 -TEST(CryptoToolboxTest, bt_spec_example_d_10_test) { - Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58, - 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64}; - Octet16 expected_link_key{0xbc, 0x1c, 0xa4, 0xef, 0x63, 0x3f, 0xc1, 0xbd, - 0x0d, 0x82, 0x30, 0xaf, 0xee, 0x38, 0x8f, 0xb0}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(LTK), std::end(LTK)); - std::reverse(std::begin(expected_link_key), std::end(expected_link_key)); - - Octet16 link_key = ltk_to_link_key(LTK, false); - EXPECT_EQ(expected_link_key, link_key); -} - -// // BT Spec 5.0 | Vol 3, Part H D.11 -TEST(CryptoToolboxTest, bt_spec_example_d_11_test) { - Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00}; - Octet16 expected_ltk{0xe8, 0x5e, 0x09, 0xeb, 0x5e, 0xcc, 0xb3, 0xe2, - 0x69, 0x41, 0x8a, 0x13, 0x32, 0x11, 0xbc, 0x79}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(link_key), std::end(link_key)); - std::reverse(std::begin(expected_ltk), std::end(expected_ltk)); - - Octet16 ltk = link_key_to_ltk(link_key, true); - EXPECT_EQ(expected_ltk, ltk); -} - -// BT Spec 5.0 | Vol 3, Part H D.12 -TEST(CryptoToolboxTest, bt_spec_example_d_12_test) { - Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00}; - Octet16 expected_ltk{0xa8, 0x13, 0xfb, 0x72, 0xf1, 0xa3, 0xdf, 0xa1, - 0x8a, 0x2c, 0x9a, 0x43, 0xf1, 0x0d, 0x0a, 0x30}; - - // algorithm expect all input to be in little endian format, so reverse - std::reverse(std::begin(link_key), std::end(link_key)); - std::reverse(std::begin(expected_ltk), std::end(expected_ltk)); - - Octet16 ltk = link_key_to_ltk(link_key, false); - EXPECT_EQ(expected_ltk, ltk); -} - -} // namespace crypto_toolbox diff --git a/system/stack/test/eatt/eatt_test.cc b/system/stack/test/eatt/eatt_test.cc index 51187faecf64ab5608142dd27b0670c7a5750ea2..a0310b8e999479b4b338c7822b6084e97a69f11d 100644 --- a/system/stack/test/eatt/eatt_test.cc +++ b/system/stack/test/eatt/eatt_test.cc @@ -21,7 +21,6 @@ #include #include "bind_helpers.h" -#include "btm_api.h" #include "l2c_api.h" #include "mock_btif_storage.h" #include "mock_btm_api_layer.h" @@ -30,6 +29,7 @@ #include "mock_gatt_layer.h" #include "mock_l2cap_layer.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" #include "types/raw_address.h" using testing::_; diff --git a/system/stack/test/fuzzers/Android.bp b/system/stack/test/fuzzers/Android.bp index 47c68eb3466efb6fe1f34aff5cfbc7da951f8a19..720f0c0f2b2a94af2a84e63b98a573ab307322f3 100644 --- a/system/stack/test/fuzzers/Android.bp +++ b/system/stack/test/fuzzers/Android.bp @@ -9,9 +9,13 @@ package { cc_defaults { name: "libbt-stack_fuzz_defaults", - defaults: ["fluoride_defaults"], + defaults: [ + "fluoride_defaults", + "latest_android_hardware_bluetooth_audio_ndk_shared", + ], include_dirs: [ "packages/modules/Bluetooth/system/", + "packages/modules/Bluetooth/system/gd/", "packages/modules/Bluetooth/system/include/", "packages/modules/Bluetooth/system/internal_include/", "packages/modules/Bluetooth/system/stack/include", @@ -21,18 +25,21 @@ cc_defaults { static_libs: [ "libFraunhoferAAC", "libbluetooth-dumpsys", + "libbluetooth-types", "libbluetooth_core_rs", + "libbluetooth_crypto_toolbox", "libbluetooth_gd", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", + "libbt-btu-main-thread", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", "libbt-stack-core", + "libbt_shim_bridge", "libbtcore", "libbtdevice", "libbte", @@ -42,11 +49,11 @@ cc_defaults { "liblc3", "libopus", "libosi", + "libstatslog_bt", "libudrv-uipc", ], shared_libs: [ "android.hardware.bluetooth.a2dp@1.0", - "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", "android.hardware.bluetooth@1.0", @@ -63,6 +70,8 @@ cc_defaults { "libhidlbase", "liblog", "libprotobuf-cpp-lite", + "libstatssocket", "libutils", + "server_configurable_flags", ], } diff --git a/system/stack/test/fuzzers/a2dp/Android.bp b/system/stack/test/fuzzers/a2dp/Android.bp index 65b56b4895e1b80e3ad6ea866691faee2a4ffc0a..debbf061b0f70d0b789d35f327beada9f949fa16 100644 --- a/system/stack/test/fuzzers/a2dp/Android.bp +++ b/system/stack/test/fuzzers/a2dp/Android.bp @@ -14,4 +14,5 @@ cc_fuzz { srcs: [ "fuzz_a2dp.cc", ], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/stack/test/fuzzers/a2dp/a2dpFuzzFunctions.h b/system/stack/test/fuzzers/a2dp/a2dpFuzzFunctions.h index 24b96fcde411983b064e91a86f01ee113d8c7305..212456e2e49953c191c766fef26999f9b6e183ff 100644 --- a/system/stack/test/fuzzers/a2dp/a2dpFuzzFunctions.h +++ b/system/stack/test/fuzzers/a2dp/a2dpFuzzFunctions.h @@ -18,15 +18,17 @@ #define BT_STACK_FUZZ_A2DP_FUNCTIONS_H_ #include + #include -#include "a2dp_api.h" -#include "osi/include/allocator.h" -#include "raw_address.h" -#include "stack/a2dp/a2dp_int.h" +#include "a2dp_api.h" #include "fuzzers/a2dp/a2dpFuzzHelpers.h" #include "fuzzers/common/commonFuzzHelpers.h" #include "fuzzers/sdp/sdpFuzzFunctions.h" +#include "osi/include/allocator.h" +#include "raw_address.h" +#include "stack/a2dp/a2dp_int.h" +#include "stack/include/bt_uuid16.h" #define MAX_STR_LEN 4096 @@ -75,12 +77,6 @@ std::vector> a2dp_operations = { // A2DP_GetAvdtpVersion [](FuzzedDataProvider*) -> void { A2DP_GetAvdtpVersion(); }, - // A2DP_SetTraceLevel - [](FuzzedDataProvider* fdp) -> void { - // Expected val is [0-5], 0xff but other values are supported so fuzz all - A2DP_SetTraceLevel(fdp->ConsumeIntegral()); - }, - // A2DP_BitsSet [](FuzzedDataProvider* fdp) -> void { A2DP_BitsSet(fdp->ConsumeIntegral()); diff --git a/system/stack/test/fuzzers/a2dp/codec/Android.bp b/system/stack/test/fuzzers/a2dp/codec/Android.bp index 7c7825db3dab5cce052952a8abdc874c9fb2d7b2..8ae2c8590bec73c88919d1c669aafdbe56c65a6e 100644 --- a/system/stack/test/fuzzers/a2dp/codec/Android.bp +++ b/system/stack/test/fuzzers/a2dp/codec/Android.bp @@ -24,6 +24,7 @@ cc_fuzz { srcs: [ "fuzz_a2dp_codec.cc", ], + cflags: ["-Wno-unused-parameter"], } cc_fuzz { @@ -33,6 +34,7 @@ cc_fuzz { srcs: [ "fuzz_a2dp_codec_info.cc", ], + cflags: ["-Wno-unused-parameter"], } cc_fuzz { @@ -42,4 +44,5 @@ cc_fuzz { srcs: [ "fuzz_a2dp_codec_config.cc", ], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h b/system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h index 81887e0d6c06df0052fd79f012d47f82b29e29f5..28356deca2b0832efdf313cd23a5b7629817082e 100644 --- a/system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h +++ b/system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h @@ -132,8 +132,8 @@ std::shared_ptr getArbitraryBtHdr(FuzzedDataProvider* fdp) { } uint16_t hdr_size = bytes.size() + sizeof(BT_HDR); - std::shared_ptr bt_hdr( - reinterpret_cast(calloc(hdr_size, sizeof(uint8_t))), free); + std::shared_ptr bt_hdr(reinterpret_cast(calloc(1, hdr_size)), + free); bt_hdr->event = fdp->ConsumeIntegral(); bt_hdr->len = bytes.size(); diff --git a/system/stack/test/fuzzers/sdp/Android.bp b/system/stack/test/fuzzers/sdp/Android.bp index bc5aaa702b0eec8a8c191732f3e49c1da64a59e2..86a8c11fddcdc4c1a4222a9725f4f26d3938a1ca 100644 --- a/system/stack/test/fuzzers/sdp/Android.bp +++ b/system/stack/test/fuzzers/sdp/Android.bp @@ -14,4 +14,5 @@ cc_fuzz { srcs: [ "fuzz_sdp.cc", ], + cflags: ["-Wno-unused-parameter"], } diff --git a/system/stack/test/fuzzers/sdp/sdpFuzzFunctions.h b/system/stack/test/fuzzers/sdp/sdpFuzzFunctions.h index 10423f5f09b704dbf98ee2e2cb8e81dca1d9a037..908bb1eaa8894d74e809a326a914bc21783bb7fd 100644 --- a/system/stack/test/fuzzers/sdp/sdpFuzzFunctions.h +++ b/system/stack/test/fuzzers/sdp/sdpFuzzFunctions.h @@ -37,7 +37,7 @@ */ static const std::vector> sdp_operations = { - // SDP_InitDiscoveryDb + // ::SDP_InitDiscoveryDb [](FuzzedDataProvider* fdp) -> void { if (sdp_db_vect.size() >= MAX_NUM_DBS) { return; @@ -58,43 +58,47 @@ static const std::vector> std::shared_ptr p_db( reinterpret_cast(malloc(db_size)), free); if (p_db) { - bool success = SDP_InitDiscoveryDb( - p_db.get(), db_size, uuid_list.size(), uuid_list.data(), - attr_list.size(), - reinterpret_cast(attr_list.data())); + bool success = + get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + p_db.get(), db_size, uuid_list.size(), uuid_list.data(), + attr_list.size(), + reinterpret_cast(attr_list.data())); if (success) { sdp_db_vect.push_back(p_db); } } }, - // SDP_CancelServiceSearch + // ::SDP_CancelServiceSearch [](FuzzedDataProvider* fdp) -> void { - SDP_CancelServiceSearch( + get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch( getArbitraryVectorElement(fdp, sdp_db_vect, true).get()); }, - // SDP_ServiceSearchRequest + // ::SDP_ServiceSearchRequest [](FuzzedDataProvider* fdp) -> void { const RawAddress bd_addr = generateRawAddress(fdp); tSDP_DISCOVERY_DB* db = getArbitraryVectorElement(fdp, sdp_db_vect, false).get(); if (db) { - SDP_ServiceSearchRequest(bd_addr, db, &sdp_disc_cmpl_cb); + get_legacy_stack_sdp_api()->service.SDP_ServiceSearchRequest( + bd_addr, db, &sdp_disc_cmpl_cb); } }, - // SDP_ServiceSearchAttributeRequest + // ::SDP_ServiceSearchAttributeRequest [](FuzzedDataProvider* fdp) -> void { const RawAddress bd_addr = generateRawAddress(fdp); tSDP_DISCOVERY_DB* db = getArbitraryVectorElement(fdp, sdp_db_vect, false).get(); if (db) { - SDP_ServiceSearchAttributeRequest(bd_addr, db, &sdp_disc_cmpl_cb); + get_legacy_stack_sdp_api() + ->service.SDP_ServiceSearchAttributeRequest(bd_addr, db, + &sdp_disc_cmpl_cb); } }, - // SDP_ServiceSearchAttributeRequest2 + // ::SDP_ServiceSearchAttributeRequest2 [](FuzzedDataProvider* fdp) -> void { const RawAddress bd_addr = generateRawAddress(fdp); std::vector user_data = fdp->ConsumeBytes( @@ -103,105 +107,109 @@ static const std::vector> getArbitraryVectorElement(fdp, sdp_db_vect, false).get(); if (db) { - SDP_ServiceSearchAttributeRequest2(bd_addr, db, &sdp_disc_cmpl_cb2, - user_data.data()); + get_legacy_stack_sdp_api() + ->service.SDP_ServiceSearchAttributeRequest2( + bd_addr, db, &sdp_disc_cmpl_cb2, user_data.data()); } }, - // SDP_FindAttributeInRec + // ::SDP_FindAttributeInRec [](FuzzedDataProvider* fdp) -> void { tSDP_DISC_REC* p_rec = generateArbitrarySdpDiscRecord(fdp, false).get(); - SDP_FindAttributeInRec(p_rec, fdp->ConsumeIntegral()); + get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec( + p_rec, fdp->ConsumeIntegral()); }, - // SDP_FindServiceInDb + // ::SDP_FindServiceInDb [](FuzzedDataProvider* fdp) -> void { - SDP_FindServiceInDb( + get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( getArbitraryVectorElement(fdp, sdp_db_vect, true).get(), fdp->ConsumeIntegral(), generateArbitrarySdpDiscRecord(fdp, true).get()); }, - // SDP_FindServiceUUIDInDb + // ::SDP_FindServiceUUIDInDb [](FuzzedDataProvider* fdp) -> void { const bluetooth::Uuid uuid = generateArbitraryUuid(fdp); - SDP_FindServiceUUIDInDb( + get_legacy_stack_sdp_api()->db.SDP_FindServiceUUIDInDb( getArbitraryVectorElement(fdp, sdp_db_vect, true).get(), uuid, generateArbitrarySdpDiscRecord(fdp, true).get()); }, - // SDP_FindServiceUUIDInRec_128bit + // ::SDP_FindServiceUUIDInRec_128bit [](FuzzedDataProvider* fdp) -> void { bluetooth::Uuid uuid = generateArbitraryUuid(fdp); tSDP_DISC_REC* p_rec = generateArbitrarySdpDiscRecord(fdp, false).get(); - SDP_FindServiceUUIDInRec_128bit(p_rec, &uuid); + get_legacy_stack_sdp_api()->record.SDP_FindServiceUUIDInRec_128bit( + p_rec, &uuid); }, - // SDP_FindServiceInDb_128bit + // ::SDP_FindServiceInDb_128bit [](FuzzedDataProvider* fdp) -> void { - SDP_FindServiceInDb_128bit( + get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb_128bit( getArbitraryVectorElement(fdp, sdp_db_vect, true).get(), generateArbitrarySdpDiscRecord(fdp, true).get()); }, - // SDP_FindProtocolListElemInRec + // ::SDP_FindProtocolListElemInRec [](FuzzedDataProvider* fdp) -> void { tSDP_PROTOCOL_ELEM elem = generateArbitrarySdpProtocolElements(fdp); tSDP_DISC_REC* p_rec = generateArbitrarySdpDiscRecord(fdp, false).get(); - SDP_FindProtocolListElemInRec(p_rec, fdp->ConsumeIntegral(), - &elem); + get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec( + p_rec, fdp->ConsumeIntegral(), &elem); }, - // SDP_FindProfileVersionInRec + // ::SDP_FindProfileVersionInRec [](FuzzedDataProvider* fdp) -> void { uint16_t p_version; tSDP_DISC_REC* p_rec = generateArbitrarySdpDiscRecord(fdp, false).get(); - SDP_FindProfileVersionInRec(p_rec, fdp->ConsumeIntegral(), - &p_version); + get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec( + p_rec, fdp->ConsumeIntegral(), &p_version); }, - // SDP_CreateRecord + // ::SDP_CreateRecord [](FuzzedDataProvider* fdp) -> void { - uint32_t handle = SDP_CreateRecord(); + uint32_t handle = + get_legacy_stack_sdp_api()->handle.SDP_CreateRecord(); if (handle) { sdp_record_handles.push_back(handle); } }, - // SDP_DeleteRecord + // ::SDP_DeleteRecord [](FuzzedDataProvider* fdp) -> void { - SDP_DeleteRecord( + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord( getArbitraryVectorElement(fdp, sdp_record_handles, true)); }, - // SDP_AddAttribute + // ::SDP_AddAttribute [](FuzzedDataProvider* fdp) -> void { std::vector val = fdp->ConsumeBytes( fdp->ConsumeIntegralInRange(1, 1024)); if (val.size() > 0) { - SDP_AddAttribute( + get_legacy_stack_sdp_api()->handle.SDP_AddAttribute( getArbitraryVectorElement(fdp, sdp_record_handles, true), fdp->ConsumeIntegral(), fdp->ConsumeIntegral(), val.size(), val.data()); } }, - // SDP_AddSequence + // ::SDP_AddSequence [](FuzzedDataProvider* fdp) -> void { SDP_Sequence_Helper seq = generateArbitrarySdpElemSequence(fdp); - SDP_AddSequence( + get_legacy_stack_sdp_api()->handle.SDP_AddSequence( getArbitraryVectorElement(fdp, sdp_record_handles, true), fdp->ConsumeIntegral(), seq.num_elem, seq.type.get(), seq.len.get(), seq.p_val.get()); }, - // SDP_AddUuidSequence + // ::SDP_AddUuidSequence [](FuzzedDataProvider* fdp) -> void { uint16_t num_uuids = fdp->ConsumeIntegralInRange(1, 64); uint16_t* uuids = new uint16_t[num_uuids]; @@ -209,31 +217,31 @@ static const std::vector> uuids[i] = fdp->ConsumeIntegral(); } - SDP_AddUuidSequence( + get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence( getArbitraryVectorElement(fdp, sdp_record_handles, true), fdp->ConsumeIntegral(), num_uuids, uuids); delete[] uuids; }, - // SDP_AddProtocolList + // ::SDP_AddProtocolList [](FuzzedDataProvider* fdp) -> void { std::shared_ptr p_proto_list = generateArbitrarySdpProtocolElementList(fdp); if (p_proto_list) { - SDP_AddProtocolList( + get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList( getArbitraryVectorElement(fdp, sdp_record_handles, true), p_proto_list.get()->num_elems, p_proto_list.get()->list_elem); } }, - // SDP_AddAdditionProtoLists + // ::SDP_AddAdditionProtoLists [](FuzzedDataProvider* fdp) -> void { uint16_t arr_size; tSDP_PROTO_LIST_ELEM** p_proto_list = generateArbitrarySdpProtocolElementListArray(fdp, &arr_size); if (p_proto_list) { if (p_proto_list[0]) { - SDP_AddAdditionProtoLists( + get_legacy_stack_sdp_api()->handle.SDP_AddAdditionProtoLists( getArbitraryVectorElement(fdp, sdp_record_handles, true), arr_size, p_proto_list[0]); for (uint16_t i = 0; i < arr_size; i++) { @@ -244,24 +252,24 @@ static const std::vector> } }, - // SDP_AddProfileDescriptorList + // ::SDP_AddProfileDescriptorList [](FuzzedDataProvider* fdp) -> void { - SDP_AddProfileDescriptorList( + get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList( getArbitraryVectorElement(fdp, sdp_record_handles, true), fdp->ConsumeIntegral(), fdp->ConsumeIntegral()); }, - // SDP_AddLanguageBaseAttrIDList + // ::SDP_AddLanguageBaseAttrIDList [](FuzzedDataProvider* fdp) -> void { - SDP_AddLanguageBaseAttrIDList( + get_legacy_stack_sdp_api()->handle.SDP_AddLanguageBaseAttrIDList( getArbitraryVectorElement(fdp, sdp_record_handles, true), fdp->ConsumeIntegral(), fdp->ConsumeIntegral(), fdp->ConsumeIntegral()); }, - // SDP_AddServiceClassIdList + // ::SDP_AddServiceClassIdList [](FuzzedDataProvider* fdp) -> void { uint16_t num_services = fdp->ConsumeIntegralInRange(0, 64); uint16_t* service_uuids = new uint16_t[num_services]; @@ -269,28 +277,22 @@ static const std::vector> service_uuids[i] = fdp->ConsumeIntegral(); } - SDP_AddServiceClassIdList( + get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList( getArbitraryVectorElement(fdp, sdp_record_handles, true), num_services, service_uuids); delete[] service_uuids; }, - // SDP_DeleteAttribute - [](FuzzedDataProvider* fdp) -> void { - SDP_DeleteAttribute( - getArbitraryVectorElement(fdp, sdp_record_handles, true), - fdp->ConsumeIntegral()); - }, - - // SDP_SetLocalDiRecord + // ::SDP_SetLocalDiRecord [](FuzzedDataProvider* fdp) -> void { uint32_t handle; // Output var tSDP_DI_RECORD device_info = generateArbitrarySdpDiRecord(fdp); - SDP_SetLocalDiRecord(&device_info, &handle); + get_legacy_stack_sdp_api()->device_id.SDP_SetLocalDiRecord( + &device_info, &handle); }, - // SDP_DiDiscover + // ::SDP_DiDiscover [](FuzzedDataProvider* fdp) -> void { const RawAddress remote_device = generateRawAddress(fdp); @@ -300,36 +302,32 @@ static const std::vector> std::shared_ptr p_db( reinterpret_cast(malloc(db_size)), free); if (p_db) { - SDP_DiDiscover(remote_device, p_db.get(), db_size, - &sdp_disc_cmpl_cb); + get_legacy_stack_sdp_api()->device_id.SDP_DiDiscover( + remote_device, p_db.get(), db_size, &sdp_disc_cmpl_cb); } }, - // SDP_GetNumDiRecords + // ::SDP_GetNumDiRecords [](FuzzedDataProvider* fdp) -> void { - SDP_GetNumDiRecords( + get_legacy_stack_sdp_api()->device_id.SDP_GetNumDiRecords( getArbitraryVectorElement(fdp, sdp_db_vect, true).get()); }, - // SDP_GetDiRecord + // ::SDP_GetDiRecord [](FuzzedDataProvider* fdp) -> void { tSDP_DI_GET_RECORD device_info; // Output var - SDP_GetDiRecord( + get_legacy_stack_sdp_api()->device_id.SDP_GetDiRecord( fdp->ConsumeIntegral(), &device_info, getArbitraryVectorElement(fdp, sdp_db_vect, true).get()); }, - // SDP_SetTraceLevel - [](FuzzedDataProvider* fdp) -> void { - SDP_SetTraceLevel(fdp->ConsumeIntegral()); - }, - - // SDP_FindServiceUUIDInRec + // ::SDP_FindServiceUUIDInRec [](FuzzedDataProvider* fdp) -> void { tSDP_DISC_REC* p_rec = generateArbitrarySdpDiscRecord(fdp, false).get(); bluetooth::Uuid uuid; // Output var - SDP_FindServiceUUIDInRec(p_rec, &uuid); + get_legacy_stack_sdp_api()->record.SDP_FindServiceUUIDInRec(p_rec, + &uuid); }}; #endif // FUZZER_SDP_FUNCTIONS_H_ diff --git a/system/stack/test/fuzzers/sdp/sdpFuzzHelpers.h b/system/stack/test/fuzzers/sdp/sdpFuzzHelpers.h index fead81e98647d97d83d9814da8fa6fbbfbae30cf..f3d7d777c21230510ffb347baa4a266673d9c8a9 100644 --- a/system/stack/test/fuzzers/sdp/sdpFuzzHelpers.h +++ b/system/stack/test/fuzzers/sdp/sdpFuzzHelpers.h @@ -26,10 +26,13 @@ #include #include "fuzzers/common/commonFuzzHelpers.h" -#include "osi/include/alarm.h" +#include "stack/include/sdp_api.h" +#include "stack/include/sdpdefs.h" #include "stack/sdp/sdpint.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; + #define SDP_MAX_NUM_ELEMS 128 #define SDP_MAX_ELEM_LEN 1024 #define SDP_MAX_ATTRS 1024 @@ -76,14 +79,11 @@ void cleanupSdpFuzz() { sdp_protolist_elem_vect.clear(); // Delete all records - SDP_DeleteRecord(0); + get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(0); sdp_record_handles.clear(); // Delete Databases sdp_db_vect.clear(); - - // Set SDP Trace level back to default - SDP_SetTraceLevel(0); } std::vector generateArbitraryAttrList(FuzzedDataProvider* fdp) { @@ -274,7 +274,8 @@ SDP_Sequence_Helper generateArbitrarySdpElemSequence(FuzzedDataProvider* fdp) { } // Define our callback functions we'll be using within our functions -void sdp_disc_cmpl_cb(tSDP_STATUS result) {} -void sdp_disc_cmpl_cb2(tSDP_STATUS result, const void* user_data) {} +void sdp_disc_cmpl_cb(const RawAddress& bd_addr, tSDP_STATUS result) {} +void sdp_disc_cmpl_cb2(const RawAddress& bd_addr, tSDP_STATUS result, + const void* user_data) {} #endif // FUZZER_SDP_HELPERS_H_ diff --git a/system/stack/test/gatt/gatt_api_test.cc b/system/stack/test/gatt/gatt_api_test.cc index 7900b77c817a8f0566f894473fe32b7e8a6895be..770c08f58935aa799e44e1d93705a75217d6a9b3 100644 --- a/system/stack/test/gatt/gatt_api_test.cc +++ b/system/stack/test/gatt/gatt_api_test.cc @@ -20,26 +20,29 @@ #include #include "btm/btm_dev.h" +#include "btm/btm_sec_cb.h" #include "gatt/gatt_int.h" +#include "osi/include/allocator.h" -extern tBTM_CB btm_cb; +extern tBTM_SEC_CB btm_sec_cb; static const size_t QUEUE_SIZE_MAX = 10; static tBTM_SEC_DEV_REC* make_bonded_ble_device(const RawAddress& bda, const RawAddress& rra) { tBTM_SEC_DEV_REC* dev = btm_sec_allocate_dev_rec(); - dev->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN; + dev->sec_rec.sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN; dev->bd_addr = bda; dev->ble.pseudo_addr = rra; - dev->ble.key_type = BTM_LE_KEY_PID | BTM_LE_KEY_PENC | BTM_LE_KEY_LENC; + dev->sec_rec.ble_keys.key_type = + BTM_LE_KEY_PID | BTM_LE_KEY_PENC | BTM_LE_KEY_LENC; return dev; } static tBTM_SEC_DEV_REC* make_bonded_dual_device(const RawAddress& bda, const RawAddress& rra) { tBTM_SEC_DEV_REC* dev = make_bonded_ble_device(bda, rra); - dev->sec_flags |= BTM_SEC_LINK_KEY_KNOWN; + dev->sec_rec.sec_flags |= BTM_SEC_LINK_KEY_KNOWN; return dev; } @@ -52,12 +55,12 @@ class GattApiTest : public ::testing::Test { virtual ~GattApiTest() = default; void SetUp() override { - btm_cb.sec_dev_rec = list_new(osi_free); + btm_sec_cb.sec_dev_rec = list_new(osi_free); gatt_cb.srv_chg_clt_q = fixed_queue_new(QUEUE_SIZE_MAX); logging::SetMinLogLevel(-2); } - void TearDown() override { list_free(btm_cb.sec_dev_rec); } + void TearDown() override { list_free(btm_sec_cb.sec_dev_rec); } }; static const RawAddress SAMPLE_PUBLIC_BDA = { diff --git a/system/stack/test/gatt/gatt_sr_test.cc b/system/stack/test/gatt/gatt_sr_test.cc index 7614ce2208a85732a67b19d1d644c9f6cb3cfa44..2283b9e4c6da3cc87c82da07273d3090a7126269 100644 --- a/system/stack/test/gatt/gatt_sr_test.cc +++ b/system/stack/test/gatt/gatt_sr_test.cc @@ -20,9 +20,9 @@ #include -#include "osi/test/AllocationTestHarness.h" #include "stack/gatt/gatt_int.h" #include "stack/include/bt_hdr.h" +#include "stack/include/main_thread.h" #include "stack/test/common/mock_eatt.h" #undef LOG_TAG #include "stack/gatt/gatt_sr.cc" @@ -59,7 +59,8 @@ 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 direct_connect_remove(uint8_t app_id, const RawAddress& address, + bool connection_timeout) { return false; } bool is_background_connection(const RawAddress& address) { return false; } @@ -144,17 +145,13 @@ void gatt_sr_update_cl_status(tGATT_TCB& p_tcb, bool chg_aware) { /** * Test class to test selected functionality in stack/gatt/gatt_sr.cc */ -void allocation_tracker_uninit(void); namespace { uint16_t kHandle = 1; bt_gatt_db_attribute_type_t kGattCharacteristicType = BTGATT_DB_CHARACTERISTIC; } // namespace -class GattSrTest : public AllocationTestHarness { +class GattSrTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); - // Disable our allocation tracker to allow ASAN full range - allocation_tracker_uninit(); memset(&tcb_, 0, sizeof(tcb_)); memset(&el_, 0, sizeof(el_)); @@ -168,17 +165,14 @@ class GattSrTest : public AllocationTestHarness { test_state_ = TestMutables(); } - void TearDown() override { AllocationTestHarness::TearDown(); } - tGATT_TCB tcb_; tGATT_SRV_LIST_ELEM el_; }; /* Server Robust Caching Test */ -class GattSrRobustCachingTest : public AllocationTestHarness { +class GattSrRobustCachingTest : public ::testing::Test { protected: void SetUp() override { - AllocationTestHarness::SetUp(); memset(&tcb_, 0, sizeof(tcb_)); default_length_ = 2; @@ -187,8 +181,6 @@ class GattSrRobustCachingTest : public AllocationTestHarness { gatt_cb.handle_of_database_hash = 0x0010; } - void TearDown() override { AllocationTestHarness::TearDown(); } - tGATT_TCB tcb_; uint16_t default_length_; uint8_t default_data_[2]; diff --git a/system/stack/test/gatt/mock_gatt_utils_ref.cc b/system/stack/test/gatt/mock_gatt_utils_ref.cc index c3b8ae9701624f75762b6fab5ff4f9ce1d93d3f0..4c729389615ca4bc88c4e472d8eedbb4bc4d3a1e 100644 --- a/system/stack/test/gatt/mock_gatt_utils_ref.cc +++ b/system/stack/test/gatt/mock_gatt_utils_ref.cc @@ -25,7 +25,8 @@ 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 direct_connect_remove(uint8_t app_id, const RawAddress& address, + bool connection_timeout) { return false; } bool is_background_connection(const RawAddress& address) { return false; } @@ -72,24 +73,4 @@ void l2cble_set_fixed_channel_tx_data_length(const RawAddress& remote_bda, uint16_t fix_cid, uint16_t tx_mtu) {} void L2CA_SetLeFixedChannelTxDataLength(const RawAddress& remote_bda, - uint16_t fix_cid, - uint16_t tx_mtu) {} -/** stack/sdp/sdp_db.cc */ -bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, - uint32_t attr_len, uint8_t* p_val) { - return false; -} -bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem, - tSDP_PROTOCOL_ELEM* p_elem_list) { - return false; -} -bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services, - uint16_t* p_service_uuids) { - return false; -} -bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids, - uint16_t* p_uuids) { - return false; -} -uint32_t SDP_CreateRecord(void) { return 0; } - + uint16_t fix_cid, uint16_t tx_mtu) {} diff --git a/system/stack/test/gatt/stack_gatt_test.cc b/system/stack/test/gatt/stack_gatt_test.cc index fb000ef838cf6a0402051376e6148db3e2cbb15b..6d0e0b58f31f74db68369ce4ced914f063a44a9c 100644 --- a/system/stack/test/gatt/stack_gatt_test.cc +++ b/system/stack/test/gatt/stack_gatt_test.cc @@ -18,19 +18,33 @@ #include #include -#include #include #include -#include "common/message_loop_thread.h" #include "common/strings.h" #include "stack/gatt/gatt_int.h" #include "stack/include/gatt_api.h" -#include "test/common/mock_functions.h" +#include "stack/sdp/internal/sdp_api.h" +#include "test/mock/mock_stack_sdp_legacy_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -class StackGattTest : public ::testing::Test {}; +class StackGattTest : public ::testing::Test { + protected: + void SetUp() override { + test::mock::stack_sdp_legacy::api_.handle.SDP_CreateRecord = + ::SDP_CreateRecord; + test::mock::stack_sdp_legacy::api_.handle.SDP_AddServiceClassIdList = + ::SDP_AddServiceClassIdList; + test::mock::stack_sdp_legacy::api_.handle.SDP_AddAttribute = + ::SDP_AddAttribute; + test::mock::stack_sdp_legacy::api_.handle.SDP_AddProtocolList = + ::SDP_AddProtocolList; + test::mock::stack_sdp_legacy::api_.handle.SDP_AddUuidSequence = + ::SDP_AddUuidSequence; + } + void TearDown() override { test::mock::stack_sdp_legacy::api_.handle = {}; } +}; namespace { diff --git a/system/stack/test/gatt_connection_manager_test.cc b/system/stack/test/gatt_connection_manager_test.cc index 7c5b624e103938a01597b7c0bade0cdb2298686d..4d2efa10a054c10e1813e913423ce73f49da4664 100644 --- a/system/stack/test/gatt_connection_manager_test.cc +++ b/system/stack/test/gatt_connection_manager_test.cc @@ -78,7 +78,6 @@ void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr, namespace bluetooth { namespace shim { -bool is_gd_l2cap_enabled() { return false; } void set_target_announcements_filter(bool enable) {} } // namespace shim } // namespace bluetooth @@ -354,4 +353,41 @@ TEST_F(BleConnectionManager, test_re_add_background_connect_to_allow_list) { EXPECT_TRUE(background_connect_remove(CLIENT1, address1)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); } + +TEST_F(BleConnectionManager, + test_re_add_to_allow_list_after_timeout_with_multiple_clients) { + EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1); + alarm_callback_t alarm_callback = nullptr; + void* alarm_data = nullptr; + + /* Accept adding to allow list */ + ON_CALL(*localAcceptlistMock, AcceptlistAdd(address1)) + .WillByDefault(Return(true)); + + EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)).Times(1); + EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0); + + EXPECT_TRUE(background_connect_add(CLIENT1, address1)); + + Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); + + EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)) + .Times(1) + .WillOnce(DoAll(SaveArg<2>(&alarm_callback), SaveArg<3>(&alarm_data))); + // Start direct connect attempt... + EXPECT_TRUE(direct_connect_add(CLIENT2, address1)); + + Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); + + // simulate timeout seconds passed, alarm executing + EXPECT_CALL(*localAcceptlistMock, OnConnectionTimedOut(CLIENT2, address1)) + .Times(1); + EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0); + EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)).Times(1); + EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); + alarm_callback(alarm_data); + + Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); +} + } // namespace connection_manager diff --git a/system/stack/test/hci/stack_hci_test.cc b/system/stack/test/hci/stack_hci_test.cc index 7bfb5be4dbc3c056d021759a8fbb368cd9ecd972..944f373b59286d2f8a71bbb80d9c3a49f0f34541 100644 --- a/system/stack/test/hci/stack_hci_test.cc +++ b/system/stack/test/hci/stack_hci_test.cc @@ -25,9 +25,6 @@ #include "stack/include/hcidefs.h" #include "stack/include/l2cdefs.h" #include "test/common/mock_functions.h" -#include "test/mock/mock_hcic_hcicmds.h" - -namespace mock = test::mock::hcic_hcicmds; using testing::_; using testing::DoAll; diff --git a/system/stack/test/rfcomm/stack_rfcomm_test.cc b/system/stack/test/rfcomm/stack_rfcomm_test.cc index af8a30d8051d50cdad3bdab5c178b481cc4bba3c..c40400e3d641f49cc1373a2494fae0f17928cfc3 100644 --- a/system/stack/test/rfcomm/stack_rfcomm_test.cc +++ b/system/stack/test/rfcomm/stack_rfcomm_test.cc @@ -20,16 +20,15 @@ #include #include +#include "internal_include/bt_target.h" #include "mock_btm_layer.h" #include "mock_l2cap_layer.h" #include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_api.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/l2c_api.h" #include "stack/include/port_api.h" -#include "stack/rfcomm/rfc_int.h" +#include "stack/include/rfcdefs.h" #include "stack_rfcomm_test_utils.h" #include "stack_test_packet_utils.h" #include "types/raw_address.h" @@ -458,7 +457,6 @@ class StackRfcommTest : public Test { EXPECT_CALL(l2cap_interface_, Register(BT_PSM_RFCOMM, _, _, _)) .WillOnce(Return(BT_PSM_RFCOMM)); RFCOMM_Init(); - rfc_cb.trace_level = BT_TRACE_LEVEL_DEBUG; } void TearDown() override { diff --git a/system/stack/test/sdp/stack_sdp_test.cc b/system/stack/test/sdp/stack_sdp_test.cc index ef146e2465e3ec50ccffbf55e1c1b173a6bed835..957206a8b6e22d3a3fe94c1a2aa4c4a4d6630e40 100644 --- a/system/stack/test/sdp/stack_sdp_test.cc +++ b/system/stack/test/sdp/stack_sdp_test.cc @@ -20,7 +20,10 @@ #include -#include "stack/include/sdp_api.h" +#include "osi/include/allocator.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/sdpdefs.h" +#include "stack/sdp/internal/sdp_api.h" #include "stack/sdp/sdpint.h" #include "test/mock/mock_osi_allocator.h" #include "test/mock/mock_stack_l2cap_api.h" @@ -141,7 +144,7 @@ TEST_F(StackSdpMainTest, sdp_service_search_request_queuing) { ASSERT_EQ(p_ccb2->con_state, SDP_STATE_IDLE); } -void sdp_callback(tSDP_RESULT result) { +void sdp_callback(const RawAddress& bd_addr, tSDP_RESULT result) { if (result == SDP_SUCCESS) { ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr)); } @@ -227,3 +230,168 @@ TEST_F(StackSdpMainTest, sdp_flags_text) { std::numeric_limits::max())) .c_str()); } + +TEST_F(StackSdpMainTest, sdp_status_text) { + std::vector> status = { + std::make_pair(SDP_SUCCESS, "SDP_SUCCESS"), + std::make_pair(SDP_INVALID_VERSION, "SDP_INVALID_VERSION"), + std::make_pair(SDP_INVALID_SERV_REC_HDL, "SDP_INVALID_SERV_REC_HDL"), + std::make_pair(SDP_INVALID_REQ_SYNTAX, "SDP_INVALID_REQ_SYNTAX"), + std::make_pair(SDP_INVALID_PDU_SIZE, "SDP_INVALID_PDU_SIZE"), + std::make_pair(SDP_INVALID_CONT_STATE, "SDP_INVALID_CONT_STATE"), + std::make_pair(SDP_NO_RESOURCES, "SDP_NO_RESOURCES"), + std::make_pair(SDP_DI_REG_FAILED, "SDP_DI_REG_FAILED"), + std::make_pair(SDP_DI_DISC_FAILED, "SDP_DI_DISC_FAILED"), + std::make_pair(SDP_NO_DI_RECORD_FOUND, "SDP_NO_DI_RECORD_FOUND"), + std::make_pair(SDP_ERR_ATTR_NOT_PRESENT, "SDP_ERR_ATTR_NOT_PRESENT"), + std::make_pair(SDP_ILLEGAL_PARAMETER, "SDP_ILLEGAL_PARAMETER"), + std::make_pair(HID_SDP_NO_SERV_UUID, "HID_SDP_NO_SERV_UUID"), + std::make_pair(HID_SDP_MANDATORY_MISSING, "HID_SDP_MANDATORY_MISSING"), + std::make_pair(SDP_NO_RECS_MATCH, "SDP_NO_RECS_MATCH"), + std::make_pair(SDP_CONN_FAILED, "SDP_CONN_FAILED"), + std::make_pair(SDP_CFG_FAILED, "SDP_CFG_FAILED"), + std::make_pair(SDP_GENERIC_ERROR, "SDP_GENERIC_ERROR"), + std::make_pair(SDP_DB_FULL, "SDP_DB_FULL"), + std::make_pair(SDP_CANCEL, "SDP_CANCEL"), + }; + for (const auto& stat : status) { + ASSERT_STREQ(stat.second.c_str(), sdp_status_text(stat.first).c_str()); + } + auto unknown = + base::StringPrintf("UNKNOWN[%hu]", std::numeric_limits::max()); + ASSERT_STREQ(unknown.c_str(), + sdp_status_text(static_cast( + std::numeric_limits::max())) + .c_str()); +} + +static tSDP_DISCOVERY_DB db{}; +static tSDP_DISC_REC rec{}; +static tSDP_DISC_ATTR uuid_desc_attr{}; +static tSDP_DISC_ATTR client_exe_url_attr{}; +static tSDP_DISC_ATTR service_desc_attr{}; +static tSDP_DISC_ATTR doc_url_desc_attr{}; +static tSDP_DISC_ATTR spec_id_attr{}; +static tSDP_DISC_ATTR vendor_id_attr{}; +static tSDP_DISC_ATTR vendor_id_src_attr{}; +static tSDP_DISC_ATTR prod_id_attr{}; +static tSDP_DISC_ATTR prod_version_attr{}; +static tSDP_DISC_ATTR primary_rec_attr{}; + +class SDP_GetDiRecord_Tests : public ::testing::Test { +protected: + + void SetUp() override { + db.p_first_rec = &rec; + rec.p_first_attr = &uuid_desc_attr; + + uuid_desc_attr.attr_id = ATTR_ID_SERVICE_ID; + uuid_desc_attr.p_next_attr = &client_exe_url_attr; + + client_exe_url_attr.attr_id = ATTR_ID_CLIENT_EXE_URL; + client_exe_url_attr.p_next_attr = &service_desc_attr; + + service_desc_attr.attr_id = ATTR_ID_SERVICE_DESCRIPTION; + service_desc_attr.p_next_attr = &doc_url_desc_attr; + + doc_url_desc_attr.attr_id = ATTR_ID_DOCUMENTATION_URL; + doc_url_desc_attr.p_next_attr = &spec_id_attr; + + spec_id_attr.attr_id = ATTR_ID_SPECIFICATION_ID; + spec_id_attr.p_next_attr = &vendor_id_attr; + + vendor_id_attr.attr_id = ATTR_ID_VENDOR_ID; + vendor_id_attr.p_next_attr = &vendor_id_src_attr; + + vendor_id_src_attr.attr_id = ATTR_ID_VENDOR_ID_SOURCE; + vendor_id_src_attr.p_next_attr = &prod_id_attr; + + prod_id_attr.attr_id = ATTR_ID_PRODUCT_ID; + prod_id_attr.p_next_attr = &prod_version_attr; + + prod_version_attr.attr_id = ATTR_ID_PRODUCT_VERSION; + prod_version_attr.p_next_attr = &primary_rec_attr; + + primary_rec_attr.attr_id = ATTR_ID_PRIMARY_RECORD; + primary_rec_attr.p_next_attr = nullptr; + } + + void TearDown() override { + db = {}; + rec = {}; + uuid_desc_attr = {}; + client_exe_url_attr = {}; + service_desc_attr = {}; + doc_url_desc_attr = {}; + spec_id_attr = {}; + vendor_id_attr = {}; + vendor_id_src_attr = {}; + prod_id_attr = {}; + prod_version_attr = {}; + primary_rec_attr = {}; + } +}; + +// regression test for b/297831980 and others +TEST_F(SDP_GetDiRecord_Tests, SDP_GetDiRecord_Regression_test0) { + // tune the type/len and value of each attribute in + // each test + uuid_desc_attr.attr_len_type = (UUID_DESC_TYPE<<12) | 2; + uuid_desc_attr.attr_value.v.u16 = UUID_SERVCLASS_PNP_INFORMATION; + + // use a 2-byte string so that it can be + // saved in tSDP_DISC_ATVAL + const char *const text = "AB"; + int len = strlen(text); + client_exe_url_attr.attr_len_type = (URL_DESC_TYPE<<12) | len; + memcpy(client_exe_url_attr.attr_value.v.array, text, len); + + // make this attr not found by id + service_desc_attr.attr_id = ATTR_ID_SERVICE_DESCRIPTION + 1; + service_desc_attr.attr_len_type = (TEXT_STR_DESC_TYPE<<12) | len; + memcpy(service_desc_attr.attr_value.v.array, text, len); + + // make a wrong type + doc_url_desc_attr.attr_len_type =(TEXT_STR_DESC_TYPE<<12) | len; + memcpy(doc_url_desc_attr.attr_value.v.array, text, len); + + // setup unexpected sizes for the following attrs + spec_id_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1; + spec_id_attr.attr_value.v.u16 = 0x1111; + + vendor_id_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1; + vendor_id_attr.attr_value.v.u16 = 0x2222; + + vendor_id_src_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1; + vendor_id_src_attr.attr_value.v.u16 = 0x3333; + + prod_id_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1; + prod_id_attr.attr_value.v.u16 = 0x4444; + + prod_version_attr.attr_len_type = (UINT_DESC_TYPE << 12) | 1; + prod_version_attr.attr_value.v.u16 = 0x5555; + + // setup wrong size for primary_rec_attr + primary_rec_attr.attr_len_type = (BOOLEAN_DESC_TYPE << 12) | 0; + primary_rec_attr.attr_value.v.u8 = 0x66; + + tSDP_DI_GET_RECORD device_info{}; + + SDP_GetDiRecord(1, &device_info, &db); + + ASSERT_STREQ(text, device_info.rec.client_executable_url); + + // service description could not be found + ASSERT_EQ(strlen(device_info.rec.service_description), (size_t) 0); + + // with a wrong attr type, the attr value won't be accepted + ASSERT_EQ(strlen(device_info.rec.documentation_url), (size_t) 0); + + // none of the following values got setup + ASSERT_EQ(device_info.spec_id, 0); + ASSERT_EQ(device_info.rec.vendor, 0); + ASSERT_EQ(device_info.rec.vendor_id_source, 0); + ASSERT_EQ(device_info.rec.product, 0); + ASSERT_EQ(device_info.rec.version, 0); + ASSERT_FALSE(device_info.rec.primary_record); +} diff --git a/system/stack/test/sdp/stack_sdp_utils_test.cc b/system/stack/test/sdp/stack_sdp_utils_test.cc index 43f0d2dcb4b4f93deffd1225db6bb51999b12f11..1ca9d3901bb2b7d6991097ae1689d18683d1e960 100644 --- a/system/stack/test/sdp/stack_sdp_utils_test.cc +++ b/system/stack/test/sdp/stack_sdp_utils_test.cc @@ -18,7 +18,6 @@ #include -#include "bt_types.h" #include "btif/include/btif_storage.h" #include "btif/include/stack_manager.h" #include "common/init_flags.h" @@ -27,7 +26,8 @@ #include "profile/avrcp/avrcp_config.h" #include "stack/include/avrc_api.h" #include "stack/include/avrc_defs.h" -#include "stack/include/sdp_api.h" +#include "stack/include/bt_types.h" +#include "stack/include/bt_uuid16.h" #include "stack/sdp/sdpint.h" #include "test/mock/mock_btif_config.h" #include "test/mock/mock_osi_properties.h" @@ -46,9 +46,6 @@ using testing::DoAll; using testing::Return; using testing::SetArrayArgument; -// Global trace level referred in the code under test -uint8_t appl_trace_level = BT_TRACE_LEVEL_VERBOSE; - bool sdp_dynamic_change_hfp_version(const tSDP_ATTRIBUTE* p_attr, const RawAddress& remote_address); void hfp_fallback(bool& is_hfp_fallback, const tSDP_ATTRIBUTE* p_attr); @@ -589,6 +586,10 @@ TEST_F(StackSdpUtilsTest, check_HFP_version_change_fail) { InteropMatchAddrOrName(INTEROP_HFP_1_7_ALLOWLIST, &bdaddr, &btif_storage_get_remote_device_property)) .WillOnce(Return(false)); + EXPECT_CALL(*localIopMock, + InteropMatchAddrOrName(INTEROP_HFP_1_9_ALLOWLIST, &bdaddr, + &btif_storage_get_remote_device_property)) + .WillOnce(Return(false)); ASSERT_EQ(sdp_dynamic_change_hfp_version(&hfp_attr, bdaddr), false); } @@ -601,6 +602,10 @@ TEST_F(StackSdpUtilsTest, check_HFP_version_change_success) { InteropMatchAddrOrName(INTEROP_HFP_1_7_ALLOWLIST, &bdaddr, &btif_storage_get_remote_device_property)) .WillOnce(Return(true)); + EXPECT_CALL(*localIopMock, + InteropMatchAddrOrName(INTEROP_HFP_1_9_ALLOWLIST, &bdaddr, + &btif_storage_get_remote_device_property)) + .WillOnce(Return(true)); ASSERT_EQ(sdp_dynamic_change_hfp_version(&hfp_attr, bdaddr), true); } @@ -613,6 +618,10 @@ TEST_F(StackSdpUtilsTest, check_HFP_version_fallback_success) { InteropMatchAddrOrName(INTEROP_HFP_1_7_ALLOWLIST, &bdaddr, &btif_storage_get_remote_device_property)) .WillOnce(Return(true)); + EXPECT_CALL(*localIopMock, + InteropMatchAddrOrName(INTEROP_HFP_1_9_ALLOWLIST, &bdaddr, + &btif_storage_get_remote_device_property)) + .WillOnce(Return(true)); bool is_hfp_fallback = sdp_dynamic_change_hfp_version(&hfp_attr, bdaddr); ASSERT_EQ(hfp_attr.value_ptr[PROFILE_VERSION_POSITION], HFP_PROFILE_MINOR_VERSION_7); diff --git a/system/stack/test/stack_a2dp_test.cc b/system/stack/test/stack_a2dp_test.cc index 84744211185a76de4f6b8a89c5065f3a9baa2dac..c3550bf9608e9e1a6659cf2df5248d9d3920fc27 100644 --- a/system/stack/test/stack_a2dp_test.cc +++ b/system/stack/test/stack_a2dp_test.cc @@ -933,13 +933,6 @@ TEST_F(StackA2dpTest, test_a2dp_init_codec_config) { for (size_t i = 0; i < codec_info_sbc_capability[0] + 1; i++) { EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc_capability[i]); } -// Test for content protection -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - EXPECT_EQ(avdt_cfg.protect_info[0], AVDT_CP_LOSC); - EXPECT_EQ(avdt_cfg.protect_info[1], (AVDT_CP_SCMS_T_ID & 0xFF)); - EXPECT_EQ(avdt_cfg.protect_info[2], ((AVDT_CP_SCMS_T_ID >> 8) & 0xFF)); - EXPECT_EQ(avdt_cfg.num_protect, 1); -#endif // // Test for SBC Sink @@ -970,14 +963,6 @@ TEST_F(StackA2dpTest, test_a2dp_init_codec_config) { ASSERT_EQ(avdt_cfg.codec_info[i], codec_info_aac_capability[i]); } } - -// Test for content protection -#if (BTA_AV_CO_CP_SCMS_T == TRUE) - EXPECT_EQ(avdt_cfg.protect_info[0], AVDT_CP_LOSC); - EXPECT_EQ(avdt_cfg.protect_info[1], (AVDT_CP_SCMS_T_ID & 0xFF)); - EXPECT_EQ(avdt_cfg.protect_info[2], ((AVDT_CP_SCMS_T_ID >> 8) & 0xFF)); - EXPECT_EQ(avdt_cfg.num_protect, 1); -#endif } TEST_F(A2dpCodecConfigTest, createCodec) { diff --git a/system/stack/test/stack_acl_test.cc b/system/stack/test/stack_acl_test.cc index 6d12fb1429429fd47ae9696d0a22310aeaedecc2..19e8533e5a9ffc6f2ce75231576e9bcab73d7b2d 100644 --- a/system/stack/test/stack_acl_test.cc +++ b/system/stack/test/stack_acl_test.cc @@ -17,23 +17,18 @@ #include #include -#include #include "common/init_flags.h" -#include "osi/include/log.h" #include "stack/acl/acl.h" #include "stack/btm/btm_int_types.h" #include "stack/btm/security_device_record.h" #include "stack/include/acl_api.h" #include "stack/include/acl_hci_link_interface.h" -#include "stack/include/hci_error_code.h" +#include "stack/include/hcidefs.h" #include "test/common/mock_functions.h" -#include "test/mock/mock_main_shim_acl_api.h" -#include "types/ble_address_with_type.h" #include "types/hci_role.h" #include "types/raw_address.h" -uint8_t btif_trace_level = BT_TRACE_LEVEL_DEBUG; tBTM_CB btm_cb; namespace { @@ -53,12 +48,6 @@ std::set copy_of_connected_with_both_public_and_random_set(); } // namespace testing } // namespace bluetooth -void BTM_update_version_info(const RawAddress& bd_addr, - const remote_version_info& remote_version_info) {} - -void btm_sec_role_changed(tHCI_STATUS hci_status, const RawAddress& bd_addr, - tHCI_ROLE new_role) {} - class StackAclTest : public testing::Test { protected: void SetUp() override { diff --git a/system/stack/test/stack_avdtp_test.cc b/system/stack/test/stack_avdtp_test.cc index 34265fcc6402dca8e7618b033f648aeea6696409..0b3c1dc6936b6474cb177bb8d9a45b833e14bcbb 100644 --- a/system/stack/test/stack_avdtp_test.cc +++ b/system/stack/test/stack_avdtp_test.cc @@ -32,9 +32,6 @@ #define UNUSED_ATTR #endif -// Global trace level referred in the code under test -uint8_t appl_trace_level = BT_TRACE_LEVEL_VERBOSE; - class StackAvdtpTest : public ::testing::Test { protected: StackAvdtpTest() = default; diff --git a/system/stack/test/stack_avrcp_test.cc b/system/stack/test/stack_avrcp_test.cc index e731e98b765f2f1d0e5442287fa02446225ed297..c236eb90643a829d7343f862c1842e97daf3ff62 100644 --- a/system/stack/test/stack_avrcp_test.cc +++ b/system/stack/test/stack_avrcp_test.cc @@ -19,6 +19,7 @@ #include #include "stack/include/avrc_api.h" +#include "stack/include/bt_types.h" class StackAvrcpTest : public ::testing::Test { protected: diff --git a/system/stack/test/stack_btu_test.cc b/system/stack/test/stack_btu_test.cc index 57d653161ac68ae65b778c66e74b1752668d751d..80e9b26631e153b716d8a30a3c0099d3f2a6fc0a 100644 --- a/system/stack/test/stack_btu_test.cc +++ b/system/stack/test/stack_btu_test.cc @@ -20,15 +20,14 @@ #include #include -#include "stack/include/btu.h" +#include "stack/include/btu_hcif.h" #include "stack/include/hci_error_code.h" #include "stack/include/hcidefs.h" #include "test/common/mock_functions.h" /* Function for test provided by btu_hcif.cc */ void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status, - const uint8_t* p_cmd, - void* p_vsc_status_cback); + const uint8_t* p_cmd); class StackBtuTest : public ::testing::Test { protected: @@ -40,6 +39,6 @@ TEST_F(StackBtuTest, post_on_main) {} TEST_F(StackBtuTest, btm_sco_connection_failed_called) { uint8_t p_cmd[10]; // garbage data for testing bluetooth::legacy::testing::btu_hcif_hdl_command_status( - HCI_SETUP_ESCO_CONNECTION, HCI_ERR_UNSPECIFIED, p_cmd, nullptr); + HCI_SETUP_ESCO_CONNECTION, HCI_ERR_UNSPECIFIED, p_cmd); ASSERT_EQ(1, get_func_call_count("btm_sco_connection_failed")); } diff --git a/system/stack/test/stack_l2cap_test.cc b/system/stack/test/stack_l2cap_test.cc index 0bc6d90dfbe21fe6ee0466b3ceafd762bb11110f..91f58764a50399c62eb78879716ad7fc41b8dec3 100644 --- a/system/stack/test/stack_l2cap_test.cc +++ b/system/stack/test/stack_l2cap_test.cc @@ -18,12 +18,12 @@ #include "common/init_flags.h" #include "device/include/controller.h" -#include "internal_include/bt_trace.h" +#include "osi/include/allocator.h" #include "stack/btm/btm_int_types.h" +#include "stack/include/l2cap_controller_interface.h" #include "stack/include/l2cap_hci_link_interface.h" #include "stack/include/l2cdefs.h" #include "stack/l2cap/l2c_int.h" -#include "types/raw_address.h" tBTM_CB btm_cb; extern tL2C_CB l2cb; @@ -31,9 +31,6 @@ extern tL2C_CB l2cb; void l2c_link_send_to_lower_br_edr(tL2C_LCB* p_lcb, BT_HDR* p_buf); void l2c_link_send_to_lower_ble(tL2C_LCB* p_lcb, BT_HDR* p_buf); -// Global trace level referred in the code under test -uint8_t appl_trace_level = BT_TRACE_LEVEL_VERBOSE; - namespace { constexpr uint16_t kAclBufferCountClassic = 123; constexpr uint8_t kAclBufferCountBle = 45; diff --git a/system/stack/test/stack_smp_test.cc b/system/stack/test/stack_smp_test.cc index edd82321b28df65e5c66a83a8b3e9a35ca8073b2..8ab1594a5b693b7705a85b1dda139ff68439ddfb 100644 --- a/system/stack/test/stack_smp_test.cc +++ b/system/stack/test/stack_smp_test.cc @@ -21,17 +21,16 @@ #include -#include "bt_trace.h" +#include "crypto_toolbox/crypto_toolbox.h" #include "hci/include/packet_fragmenter.h" #include "internal_include/stack_config.h" #include "stack/btm/btm_int_types.h" #include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" -#include "stack/include/smp_api.h" +#include "stack/include/btm_ble_api.h" #include "stack/include/smp_status.h" #include "stack/smp/p_256_ecc_pp.h" #include "stack/smp/smp_int.h" -#include "test/common/mock_functions.h" #include "test/mock/mock_stack_acl.h" #include "types/hci_role.h" #include "types/raw_address.h" @@ -43,7 +42,6 @@ tBTM_CB btm_cb; const std::string kSmpOptions("mock smp options"); const std::string kBroadcastAudioConfigOptions( "mock broadcast audio config options"); -bool get_trace_config_enabled(void) { return false; } bool get_pts_avrcp_test(void) { return false; } bool get_pts_secure_only_mode(void) { return false; } bool get_pts_conn_updates_disabled(void) { return false; } @@ -71,7 +69,6 @@ config_t* get_all(void) { return nullptr; } const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; } stack_config_t mock_stack_config{ - .get_trace_config_enabled = get_trace_config_enabled, .get_pts_avrcp_test = get_pts_avrcp_test, .get_pts_secure_only_mode = get_pts_secure_only_mode, .get_pts_conn_updates_disabled = get_pts_conn_updates_disabled, @@ -88,9 +85,9 @@ stack_config_t mock_stack_config{ .get_pts_eatt_peripheral_collision_support = get_pts_eatt_peripheral_collision_support, .get_pts_use_eatt_for_all_services = get_pts_use_eatt_for_all_services, - .get_pts_l2cap_ecoc_upper_tester = get_pts_l2cap_ecoc_upper_tester, .get_pts_force_le_audio_multiple_contexts_metadata = get_pts_force_le_audio_multiple_contexts_metadata, + .get_pts_l2cap_ecoc_upper_tester = get_pts_l2cap_ecoc_upper_tester, .get_pts_l2cap_ecoc_min_key_size = get_pts_l2cap_ecoc_min_key_size, .get_pts_l2cap_ecoc_initial_chan_cnt = get_pts_l2cap_ecoc_initial_chan_cnt, .get_pts_l2cap_ecoc_connect_remaining = @@ -212,7 +209,7 @@ TEST_F(SmpCalculateConfirmTest, test_smp_gen_p2_4_confirm_as_central) { // Set local_bda to 0xA1A2A3A4A5A6 test::mock::stack_acl::BTM_ReadConnectionAddr.body = [](const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { local_conn_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6}); *p_addr_type = BLE_ADDR_RANDOM; }; @@ -220,7 +217,7 @@ TEST_F(SmpCalculateConfirmTest, test_smp_gen_p2_4_confirm_as_central) { // Set remote bda to 0xB1B2B3B4B5B6 test::mock::stack_acl::BTM_ReadRemoteConnectionAddr.body = [](const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { conn_addr = RawAddress({0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6}); *p_addr_type = BLE_ADDR_PUBLIC; return true; @@ -229,8 +226,9 @@ TEST_F(SmpCalculateConfirmTest, test_smp_gen_p2_4_confirm_as_central) { RawAddress remote_bda; tBLE_ADDR_TYPE remote_bd_addr_type = BLE_ADDR_PUBLIC; BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda, - &remote_bd_addr_type); - BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type); + &remote_bd_addr_type, true); + BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type, + true); Octet16 p2 = smp_gen_p2_4_confirm(&p_cb_, remote_bda); // Correct p2 is 0x00000000a1a2a3a4a5a6b1b2b3b4b5b6 const char expected_p2_str[] = "00000000a1a2a3a4a5a6b1b2b3b4b5b6"; @@ -247,7 +245,7 @@ TEST_F(SmpCalculateConfirmTest, test_aes_128_as_central) { // Set local_bda to 0xA1A2A3A4A5A6 test::mock::stack_acl::BTM_ReadConnectionAddr.body = [](const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { local_conn_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6}); *p_addr_type = BLE_ADDR_RANDOM; }; @@ -255,7 +253,7 @@ TEST_F(SmpCalculateConfirmTest, test_aes_128_as_central) { // Set remote bda to 0xB1B2B3B4B5B6 test::mock::stack_acl::BTM_ReadRemoteConnectionAddr.body = [](const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { conn_addr = RawAddress({0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6}); *p_addr_type = BLE_ADDR_PUBLIC; return true; @@ -264,8 +262,9 @@ TEST_F(SmpCalculateConfirmTest, test_aes_128_as_central) { RawAddress remote_bda; tBLE_ADDR_TYPE remote_bd_addr_type = BLE_ADDR_PUBLIC; BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda, - &remote_bd_addr_type); - BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type); + &remote_bd_addr_type, true); + BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type, + true); Octet16 p1 = smp_gen_p1_4_confirm(&p_cb_, remote_bd_addr_type); // Correct p1 is 0x05000800000302070710000001010001 const char expected_p1_str[] = "05000800000302070710000001010001"; @@ -278,7 +277,7 @@ TEST_F(SmpCalculateConfirmTest, test_aes_128_as_central) { char p1_xor_r_str[2 * OCTET16_LEN + 1]; dump_uint128_reverse(p1, p1_xor_r_str); ASSERT_THAT(p1_xor_r_str, StrEq(expected_p1_xor_r_str)); - Octet16 output = crypto_toolbox::aes_128(p_cb_.tk, p1.data(), OCTET16_LEN); + Octet16 output = crypto_toolbox::aes_128(p_cb_.tk, p1); const char expected_p1_prime_str[] = "02c7aa2a9857ac866ff91232df0e3c95"; char p1_prime_str[2 * OCTET16_LEN + 1]; dump_uint128_reverse(output, p1_prime_str); @@ -293,7 +292,7 @@ TEST_F(SmpCalculateConfirmTest, test_smp_calculate_comfirm_as_central) { // Set local_bda to 0xA1A2A3A4A5A6 test::mock::stack_acl::BTM_ReadConnectionAddr.body = [](const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { local_conn_addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6}); *p_addr_type = BLE_ADDR_RANDOM; }; @@ -301,7 +300,7 @@ TEST_F(SmpCalculateConfirmTest, test_smp_calculate_comfirm_as_central) { // Set remote bda to 0xB1B2B3B4B5B6 test::mock::stack_acl::BTM_ReadRemoteConnectionAddr.body = [](const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { conn_addr = RawAddress({0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6}); *p_addr_type = BLE_ADDR_PUBLIC; return true; diff --git a/system/test/Android.bp b/system/test/Android.bp index 817c8db20999afcbc64e47072f493a1da612651f..7c80d78002a7cc068c41a75c646d629e3baf1865 100644 --- a/system/test/Android.bp +++ b/system/test/Android.bp @@ -12,6 +12,11 @@ subdirs = [ "suite", ] +filegroup { + name: "TestMockAudioA2dp", + srcs: ["mock/mock_audio_a2dp*.cc"], +} + filegroup { name: "TestMockBtaAg", srcs: [ @@ -124,6 +129,13 @@ filegroup { ], } +filegroup { + name: "TestMockBtaScn", + srcs: [ + "mock/mock_bta_scn.cc", + ], +} + filegroup { name: "TestMockBtaSdp", srcs: [ @@ -177,13 +189,6 @@ filegroup { ], } -filegroup { - name: "TestMockCommon", - srcs: [ - "mock/mock_common_*.cc", - ], -} - filegroup { name: "TestMockStackA2dp", srcs: [ @@ -205,6 +210,34 @@ filegroup { ], } +filegroup { + name: "TestMockStackAvct", + srcs: [ + "mock/mock_stack_avct_*.cc", + ], +} + +filegroup { + name: "TestMockStackAvdt", + srcs: [ + "mock/mock_stack_avdt_*.cc", + ], +} + +filegroup { + name: "TestMockStackAvrc", + srcs: [ + "mock/mock_stack_avrc_*.cc", + ], +} + +filegroup { + name: "TestMockStackBnep", + srcs: [ + "mock/mock_stack_bnep_*.cc", + ], +} + filegroup { name: "TestMockStackL2cap", srcs: [ @@ -247,13 +280,6 @@ filegroup { ], } -filegroup { - name: "TestMockSystemLibfmq", - srcs: [ - "mock/mock_system_libfmq_*.cc", - ], -} - filegroup { name: "TestMockUdrv", srcs: [ @@ -261,13 +287,6 @@ filegroup { ], } -filegroup { - name: "TestMockAndroidHardware", - srcs: [ - "mock/mock_android_hardware_*.cc", - ], -} - filegroup { name: "TestMockDevice", srcs: [ @@ -315,23 +334,30 @@ filegroup { } filegroup { - name: "TestMockStackSdp", + name: "TestMockStackHid", srcs: [ - "mock/mock_stack_sdp*.cc", + "mock/mock_stack_hid*.cc", ], } filegroup { - name: "TestMockStackBtm", + name: "TestMockStackPan", srcs: [ - "mock/mock_stack_btm*.cc", + "mock/mock_stack_pan*.cc", ], } filegroup { - name: "TestStubLegacyTrace", + name: "TestMockStackSdp", + srcs: [ + "mock/mock_stack_sdp*.cc", + ], +} + +filegroup { + name: "TestMockStackBtm", srcs: [ - "stub/legacy_trace.cc", + "mock/mock_stack_btm*.cc", ], } @@ -412,13 +438,6 @@ filegroup { ], } -filegroup { - name: "TestMockStackCryptotoolbox", - srcs: [ - "mock/mock_stack_crypto_toolbox*.cc", - ], -} - filegroup { name: "TestMockBtu", srcs: [ @@ -426,13 +445,6 @@ filegroup { ], } -filegroup { - name: "TestMockUtils", - srcs: [ - "mock/mock_utils_*cc", - ], -} - filegroup { name: "TestCommonMockFunctions", srcs: [ @@ -450,10 +462,16 @@ filegroup { filegroup { name: "TestCommonMainHandler", srcs: [ + ":TestCommonSyncMainHandler", "common/main_handler.cc", ], } +filegroup { + name: "TestCommonSyncMainHandler", + srcs: ["common/sync_main_handler.cc"], +} + filegroup { name: "TestCommonInitFlags", srcs: [ @@ -475,13 +493,6 @@ filegroup { ], } -filegroup { - name: "TestCommonLogMsg", - srcs: [ - "common/log_msg.cc", - ], -} - filegroup { name: "TestMockBluetoothInterface", srcs: [ @@ -499,7 +510,7 @@ filegroup { filegroup { name: "TestMockLegacyHciInterface", srcs: [ - "mock/mock_legacy_hci_iterface.cc", + "mock/mock_legacy_hci_interface.cc", ], } @@ -525,6 +536,20 @@ filegroup { ], } +filegroup { + name: "TestFakeThread", + srcs: [ + "fake/fake_thread.cc", + ], +} + +filegroup { + name: "TestFakeLooper", + srcs: [ + "fake/fake_looper.cc", + ], +} + cc_defaults { name: "mts_defaults", target: { @@ -543,37 +568,3 @@ cc_defaults { }, }, } - -cc_test { - name: "net_test_common", - host_supported: true, - local_include_dirs: [ - "common", - ], - include_dirs: [ - "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - ], - srcs: [ - "common/log_msg.cc", - "common/log_msg_test.cc", - ], - shared_libs: [ - "libchrome", - ], - cflags: [ - "-Wall", - "-Werror", - "-Wextra", - // there are too many unused parameters in all the code. - "-Wno-unused-parameter", - // http://b/264549607 - "-Wno-deprecated-builtins", - ], - sanitize: { - address: true, - cfi: true, - misc_undefined: ["bounds"], - }, -} diff --git a/system/test/common/core_interface.cc b/system/test/common/core_interface.cc index f0b8235ec8b5ba95655e39fd36a0ae95efaffce3..c1998cc73bde04a2d6ccd034bfdc636f0c79cc36 100644 --- a/system/test/common/core_interface.cc +++ b/system/test/common/core_interface.cc @@ -36,6 +36,7 @@ static bluetooth::core::EventCallbacks eventCallbacks = { .invoke_le_address_associate_cb = invoke_le_address_associate_cb, .invoke_acl_state_changed_cb = invoke_acl_state_changed_cb, .invoke_thread_evt_cb = invoke_thread_evt_cb, + .invoke_le_test_mode_cb = invoke_le_test_mode_cb, .invoke_energy_info_cb = invoke_energy_info_cb, .invoke_link_quality_report_cb = invoke_link_quality_report_cb}; @@ -50,18 +51,34 @@ struct MockConfigInterface : public bluetooth::core::ConfigInterface { static auto mockConfigInterface = MockConfigInterface{}; // This interface lets us communicate with encoders used in profiles -struct MockCodecInterface : public bluetooth::core::CodecInterface { +struct MockMsbcCodecInterface : public bluetooth::core::CodecInterface { virtual void initialize(){}; virtual void cleanup() {} - virtual uint32_t encodePacket(int16_t* input, uint8_t* output) { return 0; }; - virtual bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, - size_t out_len) { + virtual uint32_t encodePacket(int16_t* /* input */, uint8_t* /* output */) { + return 0; + }; + virtual bool decodePacket(const uint8_t* /* i_buf */, int16_t* /* o_buf */, + size_t /* out_len */) { + return false; + }; +}; + +struct MockLc3CodecInterface : public bluetooth::core::CodecInterface { + virtual void initialize(){}; + virtual void cleanup() {} + + virtual uint32_t encodePacket(int16_t* /* input */, uint8_t* /* output */) { + return 0; + }; + virtual bool decodePacket(const uint8_t* /* i_buf */, int16_t* /* o_buf */, + size_t /* out_len */) { return false; }; }; -static auto mockCodecInterface = MockCodecInterface{}; +static auto mockMsbcCodecInterface = MockMsbcCodecInterface{}; +static auto mockLc3CodecInterface = MockLc3CodecInterface{}; struct bluetooth::core::HACK_ProfileInterface HACK_profileInterface = { // HID @@ -94,17 +111,18 @@ void CleanCoreInterface() { } MockCoreInterface::MockCoreInterface() - : bluetooth::core::CoreInterface{&eventCallbacks, &mockConfigInterface, - &mockCodecInterface, - &HACK_profileInterface} {}; + : bluetooth::core::CoreInterface{ + &eventCallbacks, &mockConfigInterface, &mockMsbcCodecInterface, + &mockLc3CodecInterface, &HACK_profileInterface} {}; void MockCoreInterface::onBluetoothEnabled(){}; -bt_status_t MockCoreInterface::toggleProfile(tBTA_SERVICE_ID service_id, - bool enable) { +bt_status_t MockCoreInterface::toggleProfile(tBTA_SERVICE_ID /* service_id */, + bool /* enable */) { return BT_STATUS_SUCCESS; }; -void MockCoreInterface::removeDeviceFromProfiles(const RawAddress& bd_addr){}; +void MockCoreInterface::removeDeviceFromProfiles( + const RawAddress& /* bd_addr */){}; -void MockCoreInterface::onLinkDown(const RawAddress& bd_addr){}; +void MockCoreInterface::onLinkDown(const RawAddress& /* bd_addr */){}; diff --git a/system/test/common/log_msg.cc b/system/test/common/log_msg.cc deleted file mode 100644 index 624a4371d21345578797176e776ff22063dd5219..0000000000000000000000000000000000000000 --- a/system/test/common/log_msg.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "test/common/log_msg.h" - -#include -#include -#include -#include - -namespace { -constexpr size_t kTestBufferLogSize = 512; -} // namespace - -size_t bluetooth::testing::common::get_common_log_msg_size() { - return kTestBufferLogSize; -} - -std::function bluetooth::testing::common::log_msg = - []([[maybe_unused]] uint32_t trace_set_mask, - [[maybe_unused]] const char* buffer) {}; - -extern "C" void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) { - char buffer[kTestBufferLogSize]; - - va_list ap; - va_start(ap, fmt_str); - vsnprintf(buffer, kTestBufferLogSize, fmt_str, ap); - va_end(ap); - - bluetooth::testing::common::log_msg(trace_set_mask, buffer); -} diff --git a/system/test/common/log_msg_test.cc b/system/test/common/log_msg_test.cc deleted file mode 100644 index 6ad53b8d663cf931c1819f55a07c175851a6fe3f..0000000000000000000000000000000000000000 --- a/system/test/common/log_msg_test.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "test/common/log_msg.h" - -#include - -#include -#include - -#include "internal_include/bt_trace.h" - -namespace { -uint32_t kDefaultTraceSetMask = 0x5a5a5a5a; -} - -class CommonLogMsgTest : public ::testing::Test { - protected: - void SetUp() override {} - void TearDown() override {} -}; - -class CommonLogMsgOutputTest : public CommonLogMsgTest { - protected: - void SetUp() override { - last_ = {}; - bluetooth::testing::common::log_msg = [this](uint32_t mask, - const char* data) { - if (mask) { - printf("This is printed :%s", data); - last_.mask = mask; - last_.data_len = strlen(data); - } - }; - } - void TearDown() override { bluetooth::testing::common::log_msg = {}; } - - const size_t max_buffer_size_ = - bluetooth::testing::common::get_common_log_msg_size(); - - struct { - uint32_t mask; - size_t data_len; - } last_; -}; - -TEST_F(CommonLogMsgTest, default_no_output) { - LogMsg(kDefaultTraceSetMask, "This is a test"); -} - -TEST_F(CommonLogMsgOutputTest, simple_with_output) { - LogMsg(kDefaultTraceSetMask, "This will be printed\n"); - ASSERT_EQ(kDefaultTraceSetMask, last_.mask); - ASSERT_EQ(strlen("This will be printed\n"), last_.data_len); -} - -TEST_F(CommonLogMsgOutputTest, simple_with_no_output) { - LogMsg(0U, "This will not be printed\n"); - ASSERT_EQ(0U, last_.mask); - ASSERT_EQ(0UL, last_.data_len); -} - -TEST_F(CommonLogMsgOutputTest, max_string) { - auto long_string = std::string(max_buffer_size_ - sizeof('\0'), 'x'); - LogMsg(kDefaultTraceSetMask, long_string.c_str()); - ASSERT_EQ(max_buffer_size_ - sizeof('\0'), last_.data_len); -} - -TEST_F(CommonLogMsgOutputTest, max_string_plus_string_terminator) { - auto long_string = std::string(max_buffer_size_, 'x'); - LogMsg(kDefaultTraceSetMask, long_string.c_str()); - ASSERT_EQ(max_buffer_size_ - sizeof('\0'), last_.data_len); -} - -TEST_F(CommonLogMsgOutputTest, too_large_string) { - auto long_string = std::string(4096UL, 'x'); - LogMsg(kDefaultTraceSetMask, long_string.c_str()); - ASSERT_EQ(max_buffer_size_ - sizeof('\0'), last_.data_len); -} diff --git a/system/test/common/main_handler.cc b/system/test/common/main_handler.cc index 8d935becff4ed29ed7e23ec3e3f3404c0dc7504e..af7cc06efacad78bceae245184dec86ab39bceba 100644 --- a/system/test/common/main_handler.cc +++ b/system/test/common/main_handler.cc @@ -32,7 +32,7 @@ using BtMainClosure = std::function; namespace { -MessageLoopThread main_thread("bt_test_main_thread", true); +MessageLoopThread main_thread("bt_test_main_thread"); void do_post_on_bt_main(BtMainClosure closure) { closure(); } } // namespace @@ -53,8 +53,8 @@ bt_status_t do_in_main_thread_delayed(const base::Location& from_here, } void post_on_bt_main(BtMainClosure closure) { - ASSERT(do_in_main_thread( - FROM_HERE, base::Bind(do_post_on_bt_main, std::move(closure))) == + ASSERT(do_in_main_thread(FROM_HERE, base::BindOnce(do_post_on_bt_main, + std::move(closure))) == BT_STATUS_SUCCESS); } @@ -68,31 +68,3 @@ void main_thread_shut_down() { main_thread.ShutDown(); } // osi_alarm bluetooth::common::MessageLoopThread* get_main_thread() { return &main_thread; } - -int sync_timeout_in_ms = 3000; - -void sync_main_handler() { - std::promise promise = std::promise(); - std::future future = promise.get_future(); - post_on_bt_main([&promise]() { promise.set_value(); }); - future.wait_for(std::chrono::milliseconds(sync_timeout_in_ms)); -}; - -bool is_on_main_thread() { - // Pthreads doesn't have the concept of a thread ID, so we have to reach down - // into the kernel. -#if defined(OS_MACOSX) - return main_thread.GetThreadId() == pthread_mach_thread_np(pthread_self()); -#elif defined(OS_LINUX) -#include /* For SYS_xxx definitions */ -#include - return main_thread.GetThreadId() == syscall(__NR_gettid); -#elif defined(__ANDROID__) -#include -#include - return main_thread.GetThreadId() == gettid(); -#else - LOG(ERROR) << __func__ << "Unable to determine if on main thread"; - return true; -#endif -} diff --git a/system/test/common/main_handler.h b/system/test/common/main_handler.h index 3aeeb663d59722b6a737351a98779722d5fac183..9719fa4a5c08e09a1f3bd080d2f5d1b442cc732b 100644 --- a/system/test/common/main_handler.h +++ b/system/test/common/main_handler.h @@ -37,4 +37,3 @@ void main_thread_shut_down(); extern int sync_timeout_in_ms; void sync_main_handler(); bluetooth::common::MessageLoopThread* get_main_thread(); -bool is_on_main_thread(); diff --git a/system/test/common/stack_config.cc b/system/test/common/stack_config.cc index bb783f9f64f361f50dd96f9624ff14c35039e922..b6cc2001036f655d0968a7bb5ef40a6789482d07 100644 --- a/system/test/common/stack_config.cc +++ b/system/test/common/stack_config.cc @@ -25,7 +25,6 @@ const std::string kSmpOptions("mock smp options"); const std::string kBroadcastAudioConfigOptions( "mock broadcast audio config options"); -bool get_trace_config_enabled(void) { return false; } bool get_pts_avrcp_test(void) { return false; } bool get_pts_secure_only_mode(void) { return false; } bool get_pts_conn_updates_disabled(void) { return false; } @@ -55,7 +54,6 @@ struct packet_fragmenter_t; const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; } stack_config_t mock_stack_config{ - .get_trace_config_enabled = get_trace_config_enabled, .get_pts_avrcp_test = get_pts_avrcp_test, .get_pts_secure_only_mode = get_pts_secure_only_mode, .get_pts_conn_updates_disabled = get_pts_conn_updates_disabled, @@ -72,9 +70,9 @@ stack_config_t mock_stack_config{ .get_pts_eatt_peripheral_collision_support = get_pts_eatt_peripheral_collision_support, .get_pts_use_eatt_for_all_services = get_pts_use_eatt_for_all_services, - .get_pts_l2cap_ecoc_upper_tester = get_pts_l2cap_ecoc_upper_tester, .get_pts_force_le_audio_multiple_contexts_metadata = get_pts_force_le_audio_multiple_contexts_metadata, + .get_pts_l2cap_ecoc_upper_tester = get_pts_l2cap_ecoc_upper_tester, .get_pts_l2cap_ecoc_min_key_size = get_pts_l2cap_ecoc_min_key_size, .get_pts_l2cap_ecoc_initial_chan_cnt = get_pts_l2cap_ecoc_initial_chan_cnt, .get_pts_l2cap_ecoc_connect_remaining = diff --git a/system/test/common/sync_main_handler.cc b/system/test/common/sync_main_handler.cc new file mode 100644 index 0000000000000000000000000000000000000000..a58bdcde398b13a4f5d45b7fd6f12b2e0193a2bb --- /dev/null +++ b/system/test/common/sync_main_handler.cc @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "stack/include/main_thread.h" + +constexpr int sync_timeout_in_ms = 3000; + +void sync_main_handler() { + std::promise promise = std::promise(); + std::future future = promise.get_future(); + post_on_bt_main([&promise]() { promise.set_value(); }); + future.wait_for(std::chrono::milliseconds(sync_timeout_in_ms)); +}; diff --git a/system/test/common/sync_main_handler.h b/system/test/common/sync_main_handler.h new file mode 100644 index 0000000000000000000000000000000000000000..31094c2693c4791be08afd6ed6a481b62bf1a294 --- /dev/null +++ b/system/test/common/sync_main_handler.h @@ -0,0 +1,30 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// Synchronize main handler for tests +// +// NOTE: This mechanism works ONLY when it is known that a single unit +// of execution under test does not spawn or otherwise extend entries +// into the main loop execution queue. +// +// If the execution under test reposts additional execution units to +// the main loop queue then this synchronization mechanism is unreliable +// and alternative methods must be used to properly sync within the +// multithreaded environment. + +void sync_main_handler(); diff --git a/system/test/fake/fake_looper.cc b/system/test/fake/fake_looper.cc new file mode 100644 index 0000000000000000000000000000000000000000..582fe124b11c5d10c5bfbf7ca2d8b2106f984ea8 --- /dev/null +++ b/system/test/fake/fake_looper.cc @@ -0,0 +1,111 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test/fake/fake_looper.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "osi/include/allocator.h" +#include "osi/include/log.h" +#include "test/fake/fake_thread.h" + +pid_t get_thread_id() { +#if defined(OS_MACOSX) + return pthread_mach_thread_np(pthread_self()); +#elif defined(OS_LINUX) +#include /* For SYS_xxx definitions */ +#include + return syscall(__NR_gettid); +#elif defined(__ANDROID__) +#include +#include + return gettid(); +#else + return 0; +#endif +} + +// message loop +void* run_message_loop(void* arg) { + ASSERT_LOG(arg != nullptr, "Must pass in a thread start argument"); + thread_t* thread = nullptr; + { + // Decouple thread portion from |start_arg| wrapper + thread_start_arg_t* start_arg = static_cast(arg); + thread = start_arg->thread; + thread->set_state(thread_t::State::RUNNING); + start_arg->start_sem.notify(); + } // Cannot touch any offsets from |start_arg| anymore + + // thread->tid_ = syscall(__NR_gettid); + thread->tid_ = get_thread_id(); + LOG_DEBUG("Thread message loop is operational name:%s tid:%u", + thread->name_.c_str(), thread->tid_); + + while (thread->is_running()) { + thread->work_queue_semaphore.wait(); + work_item work_item; + size_t num_work_items = 0UL; + { + std::lock_guard lock(thread->work_queue_semaphore.mutex_); + num_work_items = thread->work_queue.size(); + } + + while (num_work_items > 0) { + num_work_items--; + { + std::lock_guard lock(thread->work_queue_semaphore.mutex_); + work_item = thread->work_queue.front(); + thread->work_queue.pop(); + } + // Execute work item + work_item.first(work_item.second); + osi_free(work_item.second); + } + } + + // Flush the rest of the work items + work_item work_item; + size_t num_work_items = 0UL; + { + std::lock_guard lock(thread->work_queue_semaphore.mutex_); + num_work_items = thread->work_queue.size(); + } + while (num_work_items > 0) { + num_work_items--; + { + std::lock_guard lock(thread->work_queue_semaphore.mutex_); + work_item = thread->work_queue.front(); + thread->work_queue.pop(); + } + // Execute work item + work_item.first(work_item.second); + osi_free(work_item.second); + } + thread->set_state(thread_t::State::STOPPED); + + // Release the finish_semaphore for any waiters + thread->notify_finished(); + return NULL; +} diff --git a/system/test/fake/fake_looper.h b/system/test/fake/fake_looper.h new file mode 100644 index 0000000000000000000000000000000000000000..cc5e3285ed0fcda68aa73393729ac565bb858dfe --- /dev/null +++ b/system/test/fake/fake_looper.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +// message loop +void* run_message_loop(void* arg); diff --git a/system/test/fake/fake_thread.cc b/system/test/fake/fake_thread.cc new file mode 100644 index 0000000000000000000000000000000000000000..8a1436b05c6fb99bb976ace37859cc4f36a40f3d --- /dev/null +++ b/system/test/fake/fake_thread.cc @@ -0,0 +1,58 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test/fake/fake_thread.h" + +#include +#include +#include + +#include + +#include "include/check.h" + +struct quiesce_t { + thread_t* thread; +}; + +bool thread_t::is_running() const { + std::lock_guard lock(is_running_lock_); + return is_running_ == State::RUNNING; +} + +void thread_t::set_state(State state) { + std::lock_guard lock(is_running_lock_); + is_running_ = state; +} + +void thread_t::quiesce() { + quiesce_t* quiesce = static_cast(calloc(sizeof(quiesce_t), 1)); + CHECK(quiesce != nullptr); + quiesce->thread = this; + thread_post( + this, + [](void* context) { + quiesce_t* quiesce = static_cast(context); + quiesce->thread->set_state(thread_t::State::QUIESCE); + }, + static_cast(quiesce)); + + // Wait for thread to stop + thread_finish_semaphore.wait(); + // thread is queiesced so return +} + +void thread_t::notify_finished() { thread_finish_semaphore.notify(); } diff --git a/system/test/fake/fake_thread.h b/system/test/fake/fake_thread.h new file mode 100644 index 0000000000000000000000000000000000000000..dac08576b81163c692c1be6cb705fa426c9e64d0 --- /dev/null +++ b/system/test/fake/fake_thread.h @@ -0,0 +1,94 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "osi/include/thread.h" + +using thread_func = std::function; +using thread_data = void*; +using work_item = std::pair; + +class semaphore_t { + std::condition_variable condition_; + unsigned long count_ = 0; // Initialized as locked. + + public: + std::mutex mutex_; + void notify() { + std::lock_guard lock(mutex_); + ++count_; + condition_.notify_one(); + } + + void wait() { + std::unique_lock lock(mutex_); + while (!count_) // Handle spurious wake-ups. + condition_.wait(lock); + --count_; + } + + bool try_wait() { + std::lock_guard lock(mutex_); + if (count_) { + --count_; + return true; + } + return false; + } +}; + +struct thread_start_arg_t { + thread_t* thread; + int thread_id; + semaphore_t start_sem; +}; + +struct thread_t { + enum class State { + STOPPED, + RUNNING, + QUIESCE, + }; + + private: + State is_running_{State::STOPPED}; + mutable std::mutex is_running_lock_; + semaphore_t thread_finish_semaphore; + + public: + std::queue work_queue; + semaphore_t work_queue_semaphore; + + bool is_running() const; + void set_state(State state); + void quiesce(); + void notify_finished(); + + pthread_t pthread_; + pid_t tid_; + std::string name_; +}; diff --git a/system/test/headless/Android.bp b/system/test/headless/Android.bp index 135a22b738ae5777d9a5118bcc6b1d4e26fe7b04..ce9dcd47e5a8a065a840199e29d360a64ae37205 100644 --- a/system/test/headless/Android.bp +++ b/system/test/headless/Android.bp @@ -24,26 +24,11 @@ genrule { ], } -filegroup { - name: "TestHeadlessModules", - srcs: [ - "connect/connect.cc", - "discovery/discovery.cc", - "dumpsys/dumpsys.cc", - "nop/nop.cc", - "pairing/pairing.cc", - "read/name.cc", - "read/read.cc", - "scan/scan.cc", - "sdp/sdp.cc", - "sdp/sdp_db.cc", - ], -} - cc_binary { name: "bt_headless", defaults: [ "fluoride_defaults", + "latest_android_hardware_bluetooth_audio_ndk_shared", ], cflags: [ "-Wall", @@ -55,15 +40,24 @@ cc_binary { "HeadlessBuildTimestamp", ], srcs: [ - ":TestHeadlessModules", "bt_property.cc", + "connect/connect.cc", + "discovery/discovery.cc", + "dumpsys/dumpsys.cc", "get_options.cc", "handler.cc", "headless.cc", "log.cc", "main.cc", "messenger.cc", + "nop/nop.cc", + "pairing/pairing.cc", "property.cc", + "read/name.cc", + "read/read.cc", + "scan/scan.cc", + "sdp/sdp.cc", + "sdp/sdp_db.cc", "util.cc", ], include_dirs: [ @@ -71,9 +65,6 @@ cc_binary { "packages/modules/Bluetooth/system/gd", "packages/modules/Bluetooth/system/stack/include", ], - whole_static_libs: [ - "libbtcore", - ], static_libs: [ "android.hardware.bluetooth.a2dp@1.0", "android.system.suspend.control-V1-ndk", @@ -84,21 +75,24 @@ cc_binary { "libFraunhoferAAC", "libaudio-a2dp-hw-utils", "libbluetooth-dumpsys", + "libbluetooth-types", "libbluetooth_core_rs", + "libbluetooth_crypto_toolbox", "libbluetooth_gd", "libbluetooth_rust_interop", "libbt-audio-hal-interface", "libbt-bta", "libbt-bta-core", + "libbt-btu-main-thread", "libbt-common", "libbt-hci", - "libbt-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", "libbt-stack", "libbt-stack-core", "libbt_shim_bridge", "libbt_shim_ffi", + "libbtcore", "libbtdevice", "libbte", "libbtif", @@ -113,16 +107,17 @@ cc_binary { "libopus", "libosi", "libprotobuf-cpp-lite", + "libstatslog_bt", "libudrv-uipc", "libz", ], shared_libs: [ - "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", "android.hardware.bluetooth@1.0", "android.hardware.bluetooth@1.1", "android.system.suspend-V1-ndk", + "libPlatformProperties", "libaaudio", "libbase", "libbinder_ndk", @@ -132,11 +127,9 @@ cc_binary { "libhidlbase", "libjsoncpp", "liblog", // __android_log_print + "libstatssocket", "libutils", - "libPlatformProperties", + "server_configurable_flags", ], - ldflags: ["-rdynamic"], - sanitize: { - cfi: false, - }, + header_libs: ["libbluetooth_headers"], } diff --git a/system/test/headless/discovery/discovery.cc b/system/test/headless/discovery/discovery.cc index 761f4c40505c416a2aa4333cc67b72044926ae96..7faf81ca4871c529bd3ae88249816b5900a1a105 100644 --- a/system/test/headless/discovery/discovery.cc +++ b/system/test/headless/discovery/discovery.cc @@ -165,8 +165,6 @@ int start_discovery([[maybe_unused]] unsigned int num_loops, } // namespace -// extern uint8_t btu_trace_level; - int bluetooth::test::headless::Discovery::Run() { if (options_.loop_ < 1) { LOG_CONSOLE("This test requires at least a single loop"); diff --git a/system/test/headless/headless.cc b/system/test/headless/headless.cc index f2cc739beb650d8633ba52ea5474a7bd06e39d7b..6d1f476e2abc8c529e0a5aa66672517a76191d01 100644 --- a/system/test/headless/headless.cc +++ b/system/test/headless/headless.cc @@ -199,6 +199,17 @@ void thread_event([[maybe_unused]] bt_cb_thread_evt evt) { LOG_INFO("%s", __func__); } +void dut_mode_recv([[maybe_unused]] uint16_t opcode, + [[maybe_unused]] uint8_t* buf, + [[maybe_unused]] uint8_t len) { + LOG_INFO("%s", __func__); +} + +void le_test_mode([[maybe_unused]] bt_status_t status, + [[maybe_unused]] uint16_t num_packets) { + LOG_INFO("%s", __func__); +} + void energy_info([[maybe_unused]] bt_activity_energy_info* energy_info, [[maybe_unused]] bt_uid_traffic_t* uid_data) { LOG_INFO("%s", __func__); @@ -219,6 +230,8 @@ bt_callbacks_t bt_callbacks{ .le_address_associate_cb = le_address_associate, .acl_state_changed_cb = acl_state_changed, .thread_evt_cb = thread_event, + .dut_mode_recv_cb = dut_mode_recv, + .le_test_mode_cb = le_test_mode, .energy_info_cb = energy_info, .link_quality_report_cb = link_quality_report, .switch_buffer_size_cb = switch_buffer_size, @@ -227,13 +240,6 @@ bt_callbacks_t bt_callbacks{ // HAL HARDWARE CALLBACKS // OS CALLOUTS -bool set_wake_alarm_co([[maybe_unused]] uint64_t delay_millis, - [[maybe_unused]] bool should_wake, - [[maybe_unused]] alarm_cb cb, - [[maybe_unused]] void* data) { - LOG_INFO("%s", __func__); - return true; -} int acquire_wake_lock_co([[maybe_unused]] const char* lock_name) { LOG_INFO("%s", __func__); return 1; @@ -246,7 +252,6 @@ int release_wake_lock_co([[maybe_unused]] const char* lock_name) { bt_os_callouts_t bt_os_callouts{ .size = sizeof(bt_os_callouts_t), - .set_wake_alarm = set_wake_alarm_co, .acquire_wake_lock = acquire_wake_lock_co, .release_wake_lock = release_wake_lock_co, }; @@ -279,10 +284,6 @@ void HeadlessStack::SetUp() { while (bt_state_ != BT_STATE_ON) adapter_state_cv_.wait(lck); LOG_INFO("%s HeadlessStack stack is operational", __func__); - // Logging can only be enabled after the stack has started up to override - // the default logging levels built into the stack. - enable_logging(); - bluetooth::test::headless::start_messenger(); LOG_CONSOLE("%s Headless stack has started up successfully", kHeadlessIcon); @@ -291,7 +292,6 @@ void HeadlessStack::SetUp() { void HeadlessStack::TearDown() { bluetooth::test::headless::stop_messenger(); - log_logging(); LOG_INFO("Stack has disabled"); int status = bluetoothInterface.disable(); diff --git a/system/test/headless/log.cc b/system/test/headless/log.cc index 6c105f93d4449bb295902ed906eaf90899aa9c33..3bab572737515e7751a39202e3ae0633437a71ca 100644 --- a/system/test/headless/log.cc +++ b/system/test/headless/log.cc @@ -26,23 +26,7 @@ std::chrono::system_clock::time_point _prev = std::chrono::system_clock::now(); -extern uint8_t appl_trace_level; -extern uint8_t btu_trace_level; extern tBTM_CB btm_cb; bluetooth::common::TimestamperInMilliseconds timestamper_in_ms; long long GetTimestampMs() { return timestamper_in_ms.GetTimestamp(); } - -void enable_logging() { - btm_cb.trace_level = BT_TRACE_LEVEL_DEBUG; - btif_trace_level = BT_TRACE_LEVEL_DEBUG; - appl_trace_level = BT_TRACE_LEVEL_DEBUG; - btu_trace_level = BT_TRACE_LEVEL_DEBUG; -} - -void log_logging() { - LOG_INFO( - "btm_cb.trace_level:%hhu btif_trace_level:%hhu appl_trace_level:%hhu " - "btu_trace_level:%hhu", - btm_cb.trace_level, btif_trace_level, appl_trace_level, btu_trace_level); -} diff --git a/system/test/headless/log.h b/system/test/headless/log.h index 171107baca9256ddfe1d7efc6372d4bcffa8456e..303e220b44f4bbffe4a7ffbb26beb349adcf6344 100644 --- a/system/test/headless/log.h +++ b/system/test/headless/log.h @@ -28,8 +28,6 @@ #include "build_timestamp.h" // generated -void enable_logging(); -void log_logging(); long long GetTimestampMs(); // Internal to headless below diff --git a/system/test/headless/scan/scan.cc b/system/test/headless/scan/scan.cc index 6944a7c5326ad78e9f6cacd0b9570513c26bbbdb..0c9e14fcdc6446bb99a56d125c61285370aa4549 100644 --- a/system/test/headless/scan/scan.cc +++ b/system/test/headless/scan/scan.cc @@ -97,8 +97,6 @@ int start_scan([[maybe_unused]] unsigned int num_loops) { } // namespace -extern uint8_t btu_trace_level; - int bluetooth::test::headless::Scan::Run() { if (options_.loop_ < 1) { LOG_CONSOLE("This test requires at least a single loop"); @@ -106,9 +104,6 @@ int bluetooth::test::headless::Scan::Run() { return -1; } return RunOnHeadlessStack([this]() { - btif_trace_level = BT_TRACE_LEVEL_DEBUG; - appl_trace_level = BT_TRACE_LEVEL_DEBUG; - btu_trace_level = BT_TRACE_LEVEL_DEBUG; return start_scan(options_.loop_); }); } diff --git a/system/test/headless/sdp/sdp.cc b/system/test/headless/sdp/sdp.cc index 4779fb4d968ca507cd6d51736a4aa64fe8ddc5f0..6750f5a71539c128ce4ee552a21915619c29c986 100644 --- a/system/test/headless/sdp/sdp.cc +++ b/system/test/headless/sdp/sdp.cc @@ -22,6 +22,7 @@ #include "base/logging.h" // LOG() stdout and android log #include "osi/include/log.h" // android log only +#include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/sdp_api.h" #include "test/headless/get_options.h" #include "test/headless/headless.h" @@ -29,10 +30,12 @@ #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +using namespace bluetooth::legacy::stack::sdp; using namespace bluetooth::test::headless; -static void bta_jv_start_discovery_callback(tSDP_STATUS result, - const void* user_data) { +static void bta_jv_start_discovery_callback( + UNUSED_ATTR const RawAddress& bd_addr, tSDP_STATUS result, + const void* user_data) { auto promise = static_cast*>(const_cast(user_data)); promise->set_value(result); @@ -85,10 +88,10 @@ int sdp_query_uuid([[maybe_unused]] unsigned int num_loops, const RawAddress& raw_address, const bluetooth::Uuid& uuid) { SdpDb sdp_discovery_db(kMaxDiscoveryRecords); - if (!SDP_InitDiscoveryDb(sdp_discovery_db.RawPointer(), - sdp_discovery_db.Length(), - 1, // num_uuid, - &uuid, 0, nullptr)) { + if (!get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb( + sdp_discovery_db.RawPointer(), sdp_discovery_db.Length(), + 1, // num_uuid, + &uuid, 0, nullptr)) { fprintf(stdout, "%s Unable to initialize sdp discovery\n", __func__); return -1; } @@ -98,7 +101,7 @@ int sdp_query_uuid([[maybe_unused]] unsigned int num_loops, sdp_discovery_db.Print(stdout); - if (!SDP_ServiceSearchAttributeRequest2( + if (!get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest2( raw_address, sdp_discovery_db.RawPointer(), bta_jv_start_discovery_callback, (void*)&promise)) { fprintf(stdout, "%s Failed to start search attribute request\n", __func__); @@ -112,8 +115,8 @@ int sdp_query_uuid([[maybe_unused]] unsigned int num_loops, return result; } - tSDP_DISC_REC* rec = SDP_FindServiceInDb(sdp_discovery_db.RawPointer(), - uuid.As16Bit(), nullptr); + tSDP_DISC_REC* rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb( + sdp_discovery_db.RawPointer(), uuid.As16Bit(), nullptr); if (rec == nullptr) { fprintf(stdout, "discovery record is null from:%s uuid:%s\n", raw_address.ToString().c_str(), uuid.ToString().c_str()); diff --git a/system/test/mock/mock_a2dp_api.cc b/system/test/mock/mock_a2dp_api.cc index d01f59e53cf6d72ecc3f49154ce140c507163dc1..0c17cbef48156c418b3c915f966d5b647c09862c 100644 --- a/system/test/mock/mock_a2dp_api.cc +++ b/system/test/mock/mock_a2dp_api.cc @@ -19,24 +19,10 @@ * Functions generated:9 */ -#include - -#include -#include - #include "a2dp_api.h" -#include "a2dp_int.h" -#include "avdt_api.h" -#include "bt_target.h" -#include "osi/include/log.h" -#include "sdpdefs.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name, char* p_provider_name, uint16_t features, uint32_t sdp_handle) { @@ -57,10 +43,6 @@ uint8_t A2DP_BitsSet(uint64_t num) { inc_func_call_count(__func__); return 0; } -uint8_t A2DP_SetTraceLevel(uint8_t new_level) { - inc_func_call_count(__func__); - return 0; -} void A2DP_Init(void) { inc_func_call_count(__func__); } void a2dp_set_avdt_sdp_ver(uint16_t avdt_sdp_ver) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_a2dp_codec_config.cc b/system/test/mock/mock_a2dp_codec_config.cc index b718cca18668c27b644cab0611b6d050c38e3717..46ad311bd8960dc7c006045aafa05f7c7672eedc 100644 --- a/system/test/mock/mock_a2dp_codec_config.cc +++ b/system/test/mock/mock_a2dp_codec_config.cc @@ -20,25 +20,14 @@ */ #include -#include -#include #include -#include "a2dp_aac.h" #include "a2dp_codec_api.h" -#include "a2dp_sbc.h" -#include "a2dp_vendor.h" #include "bta/av/bta_av_int.h" -#include "osi/include/log.h" -#include "osi/include/properties.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - A2dpCodecConfig* A2dpCodecConfig::createCodec( btav_a2dp_codec_index_t codec_index, btav_a2dp_codec_priority_t codec_priority) { diff --git a/system/test/mock/mock_activity_attribution.cc b/system/test/mock/mock_activity_attribution.cc deleted file mode 100644 index 68797968d029a4c752443d45444817d89c4e1c7f..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_activity_attribution.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gd/module.h" - -#include "btif/include/btif_activity_attribution.h" -#include "main/shim/activity_attribution.h" -#include "main/shim/shim.h" - -ActivityAttributionInterface* -bluetooth::activity_attribution::get_activity_attribution_instance() { - return nullptr; -} - -ActivityAttributionInterface* -bluetooth::shim::get_activity_attribution_instance() { - return nullptr; -} - -const bluetooth::ModuleFactory - bluetooth::activity_attribution::ActivityAttribution::Factory = - bluetooth::ModuleFactory([]() { return nullptr; }); diff --git a/system/test/mock/mock_android_hardware_audio.cc b/system/test/mock/mock_android_hardware_audio.cc deleted file mode 100644 index 01910deee9b241b71c3686acf7a840892eabca43..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_android_hardware_audio.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include - -namespace android { -namespace hardware { -namespace bluetooth { - -namespace a2dp { -namespace V1_0 { -class BluetoothAudioHost : public IBluetoothAudioHost { - ::android::hardware::Return setHALInstrumentation() { return Void(); } - ::android::hardware::Return linkToDeath( - android::sp const&, uint64_t) { - return false; - } - ::android::hardware::Return ping() { return Void(); } - ::android::hardware::Return getDebugInfo( - std::__1::function) { - return Void(); - } - ::android::hardware::Return notifySyspropsChanged() { return Void(); } - ::android::hardware::Return unlinkToDeath( - android::sp const&) { - return false; - } -}; - -} // namespace V1_0 -} // namespace a2dp - -namespace audio { - -namespace V2_0 { - -class AudioConfiguration { - AudioConfiguration() {} -}; - -} // namespace V2_0 - -} // namespace audio -} // namespace bluetooth -} // namespace hardware -} // namespace android diff --git a/system/test/mock/mock_audio_a2dp_hw_utils.cc b/system/test/mock/mock_audio_a2dp_hw_utils.cc new file mode 100644 index 0000000000000000000000000000000000000000..527e8dee0f5f5ca680e6fba4ba63c79690fa349e --- /dev/null +++ b/system/test/mock/mock_audio_a2dp_hw_utils.cc @@ -0,0 +1,67 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Generated mock file from original source file + * Functions generated:2 + * + * mockcify.pl ver 0.6.1 + */ + +// Mock include file to share data between tests and mock +#include "test/mock/mock_audio_a2dp_hw_utils.h" + +#include "audio_a2dp_hw/include/audio_a2dp_hw.h" +#include "test/common/mock_functions.h" + +// Original usings + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace audio_a2dp_hw_utils { + +// Function state capture and return values, if needed +struct audio_a2dp_hw_dump_ctrl_event audio_a2dp_hw_dump_ctrl_event; +struct delay_reporting_enabled delay_reporting_enabled; + +} // namespace audio_a2dp_hw_utils +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace audio_a2dp_hw_utils { + +const char* audio_a2dp_hw_dump_ctrl_event::return_value = nullptr; +bool delay_reporting_enabled::return_value = false; + +} // namespace audio_a2dp_hw_utils +} // namespace mock +} // namespace test + +// Mocked functions, if any +const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event) { + inc_func_call_count(__func__); + return test::mock::audio_a2dp_hw_utils::audio_a2dp_hw_dump_ctrl_event(event); +} +bool delay_reporting_enabled() { + inc_func_call_count(__func__); + return test::mock::audio_a2dp_hw_utils::delay_reporting_enabled(); +} +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_audio_a2dp_hw_utils.h b/system/test/mock/mock_audio_a2dp_hw_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..3d4305989cdf6eba8c4cd464bfa00d8e26c4c4b9 --- /dev/null +++ b/system/test/mock/mock_audio_a2dp_hw_utils.h @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:2 + * + * mockcify.pl ver 0.6.1 + */ + +#include + +// Original included files, if any +#include "audio_a2dp_hw/include/audio_a2dp_hw.h" + +// Original usings + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace audio_a2dp_hw_utils { + +// Shared state between mocked functions and tests +// Name: audio_a2dp_hw_dump_ctrl_event +// Params: tA2DP_CTRL_CMD event +// Return: const char* +struct audio_a2dp_hw_dump_ctrl_event { + static const char* return_value; + std::function body{ + [](tA2DP_CTRL_CMD /* event */) { return return_value; }}; + const char* operator()(tA2DP_CTRL_CMD event) { return body(event); }; +}; +extern struct audio_a2dp_hw_dump_ctrl_event audio_a2dp_hw_dump_ctrl_event; + +// Name: delay_reporting_enabled +// Params: +// Return: bool +struct delay_reporting_enabled { + static bool return_value; + std::function body{[]() { return return_value; }}; + bool operator()() { return body(); }; +}; +extern struct delay_reporting_enabled delay_reporting_enabled; + +} // namespace audio_a2dp_hw_utils +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_bluetooth_interface.cc b/system/test/mock/mock_bluetooth_interface.cc index cd0f805fd5aa64ed1ae4d40879d02ed81f72dfb4..311afb619db6bd175e340edda30d474514e49917 100644 --- a/system/test/mock/mock_bluetooth_interface.cc +++ b/system/test/mock/mock_bluetooth_interface.cc @@ -17,7 +17,6 @@ #include #include "btif/include/stack_manager.h" -#include "device/include/interop.h" #include "hardware/bluetooth.h" #include "stack/include/bt_octets.h" #include "types/raw_address.h" @@ -50,6 +49,9 @@ void invoke_acl_state_changed_cb(bt_status_t status, RawAddress bd_addr, bt_conn_direction_t direction, uint16_t acl_handle) {} void invoke_thread_evt_cb(bt_cb_thread_evt event) {} + +void invoke_le_test_mode_cb(bt_status_t status, uint16_t count) {} + void invoke_energy_info_cb(bt_activity_energy_info energy_info, bt_uid_traffic_t* uid_data) {} void invoke_link_quality_report_cb(uint64_t timestamp, int report_id, int rssi, diff --git a/system/test/mock/mock_bta_ag_api.cc b/system/test/mock/mock_bta_ag_api.cc index 8b6a81ae0feaadb1ca6489650453bfa78adea0c2..01d50c31ed3bcdb817020732292ce81e874b1a51 100644 --- a/system/test/mock/mock_bta_ag_api.cc +++ b/system/test/mock/mock_bta_ag_api.cc @@ -23,26 +23,19 @@ #include #include -#include -#include #include #include -#include "bta/ag/bta_ag_int.h" #include "bta/include/bta_ag_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - tBTA_STATUS BTA_AgEnable(tBTA_AG_CBACK* p_cback) { inc_func_call_count(__func__); return BTA_SUCCESS; } void BTA_AgAudioClose(uint16_t handle) { inc_func_call_count(__func__); } -void BTA_AgAudioOpen(uint16_t handle, bool force_cvsd) { +void BTA_AgAudioOpen(uint16_t handle, tBTA_AG_PEER_CODEC disabled_codecs) { inc_func_call_count(__func__); } void BTA_AgClose(uint16_t handle) { inc_func_call_count(__func__); } @@ -68,3 +61,7 @@ void BTA_AgSetCodec(uint16_t handle, tBTA_AG_PEER_CODEC codec) { } void BTA_AgSetScoOffloadEnabled(bool value) { inc_func_call_count(__func__); } void BTA_AgSetScoAllowed(bool value) { inc_func_call_count(__func__); } +bool is_hfp_aptx_voice_enabled() { + inc_func_call_count(__func__); + return false; +}; \ No newline at end of file diff --git a/system/test/mock/mock_bta_ar.cc b/system/test/mock/mock_bta_ar.cc index 116685ed776ffb0b5e5982345f8f427a0d8ef7af..85cc99f978cb7060fd53db63404692fc974dc64d 100644 --- a/system/test/mock/mock_bta_ar.cc +++ b/system/test/mock/mock_bta_ar.cc @@ -20,20 +20,12 @@ */ #include -#include -#include -#include "bta/ar/bta_ar_int.h" #include "bta/sys/bta_sys.h" -#include "stack/include/avct_api.h" -#include "stack/include/avrc_api.h" +#include "stack/include/avdt_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, const RawAddress& bd_addr, uint8_t scb_index) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_bta_av_api.cc b/system/test/mock/mock_bta_av_api.cc index 44c5dbf2a37eba716c508e5860f1146a6624e87c..aaa6fe24b41dfc8714773501c37c075f0f585e16 100644 --- a/system/test/mock/mock_bta_av_api.cc +++ b/system/test/mock/mock_bta_av_api.cc @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,95 +13,179 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* * Generated mock file from original source file - * Functions generated:23 + * Functions generated:24 + * + * mockcify.pl ver 0.6.3 */ -#include -#include +// Mock include file to share data between tests and mock +#include "test/mock/mock_bta_av_api.h" + +#include -#include "bt_target.h" -#include "bta/av/bta_av_int.h" -#include "osi/include/allocator.h" -#include "osi/include/compat.h" -#include "osi/include/log.h" -#include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" -#include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +// Original usings -void BTA_AvEnable(tBTA_AV_FEAT features, tBTA_AV_CBACK* p_cback) { +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace bta_av_api { + +// Function state capture and return values, if needed +struct BTA_AvClose BTA_AvClose; +struct BTA_AvCloseRc BTA_AvCloseRc; +struct BTA_AvDeregister BTA_AvDeregister; +struct BTA_AvDisable BTA_AvDisable; +struct BTA_AvDisconnect BTA_AvDisconnect; +struct BTA_AvEnable BTA_AvEnable; +struct BTA_AvMetaCmd BTA_AvMetaCmd; +struct BTA_AvMetaRsp BTA_AvMetaRsp; +struct BTA_AvOffloadStart BTA_AvOffloadStart; +struct BTA_AvOffloadStartRsp BTA_AvOffloadStartRsp; +struct BTA_AvOpen BTA_AvOpen; +struct BTA_AvOpenRc BTA_AvOpenRc; +struct BTA_AvProtectReq BTA_AvProtectReq; +struct BTA_AvProtectRsp BTA_AvProtectRsp; +struct BTA_AvReconfig BTA_AvReconfig; +struct BTA_AvRegister BTA_AvRegister; +struct BTA_AvRemoteCmd BTA_AvRemoteCmd; +struct BTA_AvRemoteVendorUniqueCmd BTA_AvRemoteVendorUniqueCmd; +struct BTA_AvSetLatency BTA_AvSetLatency; +struct BTA_AvSetPeerSep BTA_AvSetPeerSep; +struct BTA_AvStart BTA_AvStart; +struct BTA_AvStop BTA_AvStop; +struct BTA_AvVendorCmd BTA_AvVendorCmd; +struct BTA_AvVendorRsp BTA_AvVendorRsp; + +} // namespace bta_av_api +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace bta_av_api {} // namespace bta_av_api +} // namespace mock +} // namespace test + +// Mocked functions, if any +void BTA_AvClose(tBTA_AV_HNDL handle) { + inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvClose(handle); +} +void BTA_AvCloseRc(uint8_t rc_handle) { + inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvCloseRc(rc_handle); +} +void BTA_AvDeregister(tBTA_AV_HNDL hndl) { + inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvDeregister(hndl); +} +void BTA_AvDisable(void) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvDisable(); } -void BTA_AvClose(tBTA_AV_HNDL handle) { inc_func_call_count(__func__); } -void BTA_AvCloseRc(uint8_t rc_handle) { inc_func_call_count(__func__); } -void BTA_AvDeregister(tBTA_AV_HNDL hndl) { inc_func_call_count(__func__); } -void BTA_AvDisable(void) { inc_func_call_count(__func__); } -void BTA_AvDisconnect(const RawAddress& bd_addr) { +void BTA_AvDisconnect(tBTA_AV_HNDL handle) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvDisconnect(handle); +} +void BTA_AvEnable(tBTA_AV_FEAT features, tBTA_AV_CBACK* p_cback) { + inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvEnable(features, p_cback); } void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code, BT_HDR* p_pkt) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvMetaCmd(rc_handle, label, cmd_code, p_pkt); } void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, BT_HDR* p_pkt) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvMetaRsp(rc_handle, label, rsp_code, p_pkt); +} +void BTA_AvOffloadStart(tBTA_AV_HNDL hndl) { + inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvOffloadStart(hndl); } -void BTA_AvOffloadStart(tBTA_AV_HNDL hndl) { inc_func_call_count(__func__); } void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvOffloadStartRsp(hndl, status); } void BTA_AvOpen(const RawAddress& bd_addr, tBTA_AV_HNDL handle, bool use_rc, uint16_t uuid) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvOpen(bd_addr, handle, use_rc, uuid); +} +void BTA_AvOpenRc(tBTA_AV_HNDL handle) { + inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvOpenRc(handle); } -void BTA_AvOpenRc(tBTA_AV_HNDL handle) { inc_func_call_count(__func__); } void BTA_AvProtectReq(tBTA_AV_HNDL hndl, uint8_t* p_data, uint16_t len) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvProtectReq(hndl, p_data, len); } void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, uint8_t error_code, uint8_t* p_data, uint16_t len) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvProtectRsp(hndl, error_code, p_data, len); } void BTA_AvReconfig(tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx, uint8_t* p_codec_info, uint8_t num_protect, const uint8_t* p_protect_info) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvReconfig( + hndl, suspend, sep_info_idx, p_codec_info, num_protect, p_protect_info); } void BTA_AvRegister(tBTA_AV_CHNL chnl, const char* p_service_name, uint8_t app_id, tBTA_AV_SINK_DATA_CBACK* p_sink_data_cback, uint16_t service_uuid) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvRegister(chnl, p_service_name, app_id, + p_sink_data_cback, service_uuid); } void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id, tBTA_AV_STATE key_state) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvRemoteCmd(rc_handle, label, rc_id, key_state); } void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_STATE key_state, uint8_t* p_msg, uint8_t buf_len) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvRemoteVendorUniqueCmd( + rc_handle, label, key_state, p_msg, buf_len); +} +void BTA_AvSetLatency(tBTA_AV_HNDL handle, bool is_low_latency) { + inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvSetLatency(handle, is_low_latency); +} +void BTA_AvSetPeerSep(const RawAddress& bdaddr, uint8_t sep) { + inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvSetPeerSep(bdaddr, sep); } void BTA_AvStart(tBTA_AV_HNDL handle, bool use_latency_mode) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvStart(handle, use_latency_mode); } void BTA_AvStop(tBTA_AV_HNDL handle, bool suspend) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvStop(handle, suspend); } void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code, uint8_t* p_data, uint16_t len) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvVendorCmd(rc_handle, label, cmd_code, p_data, + len); } void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, uint8_t* p_data, uint16_t len, uint32_t company_id) { inc_func_call_count(__func__); + test::mock::bta_av_api::BTA_AvVendorRsp(rc_handle, label, rsp_code, p_data, + len, company_id); } -void BTA_AvSetLatency(tBTA_AV_HNDL handle, bool is_low_latency) { - inc_func_call_count(__func__); -} +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_bta_av_api.h b/system/test/mock/mock_bta_av_api.h new file mode 100644 index 0000000000000000000000000000000000000000..80481c7c05eae4ea44c9d9e28d8afabb1ef28bac --- /dev/null +++ b/system/test/mock/mock_bta_av_api.h @@ -0,0 +1,367 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:24 + * + * mockcify.pl ver 0.6.3 + */ + +#include +#include + +// Original included files, if any +// NOTE: Since this is a mock file with mock definitions some number of +// include files may not be required. The include-what-you-use +// still applies, but crafting proper inclusion is out of scope +// for this effort. This compilation unit may compile as-is, or +// may need attention to prune from (or add to ) the inclusion set. +#include "bt_target.h" +#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" +#include "stack/include/bt_uuid16.h" +#include "types/raw_address.h" + +// Original usings + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace bta_av_api { + +// Shared state between mocked functions and tests +// Name: BTA_AvClose +// Params: tBTA_AV_HNDL handle +// Return: void +struct BTA_AvClose { + std::function body{ + [](tBTA_AV_HNDL /* handle */) {}}; + void operator()(tBTA_AV_HNDL handle) { body(handle); }; +}; +extern struct BTA_AvClose BTA_AvClose; + +// Name: BTA_AvCloseRc +// Params: uint8_t rc_handle +// Return: void +struct BTA_AvCloseRc { + std::function body{[](uint8_t /* rc_handle */) {}}; + void operator()(uint8_t rc_handle) { body(rc_handle); }; +}; +extern struct BTA_AvCloseRc BTA_AvCloseRc; + +// Name: BTA_AvDeregister +// Params: tBTA_AV_HNDL hndl +// Return: void +struct BTA_AvDeregister { + std::function body{[](tBTA_AV_HNDL /* hndl */) {}}; + void operator()(tBTA_AV_HNDL hndl) { body(hndl); }; +}; +extern struct BTA_AvDeregister BTA_AvDeregister; + +// Name: BTA_AvDisable +// Params: void +// Return: void +struct BTA_AvDisable { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct BTA_AvDisable BTA_AvDisable; + +// Name: BTA_AvDisconnect +// Params: tBTA_AV_HNDL handle +// Return: void +struct BTA_AvDisconnect { + std::function body{ + [](tBTA_AV_HNDL /* handle */) {}}; + void operator()(tBTA_AV_HNDL handle) { body(handle); }; +}; +extern struct BTA_AvDisconnect BTA_AvDisconnect; + +// Name: BTA_AvEnable +// Params: tBTA_AV_FEAT features, tBTA_AV_CBACK* p_cback +// Return: void +struct BTA_AvEnable { + std::function body{ + [](tBTA_AV_FEAT /* features */, tBTA_AV_CBACK* /* p_cback */) {}}; + void operator()(tBTA_AV_FEAT features, tBTA_AV_CBACK* p_cback) { + body(features, p_cback); + }; +}; +extern struct BTA_AvEnable BTA_AvEnable; + +// Name: BTA_AvMetaCmd +// Params: uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code, BT_HDR* p_pkt +// Return: void +struct BTA_AvMetaCmd { + std::function + body{[](uint8_t /* rc_handle */, uint8_t /* label */, + tBTA_AV_CMD /* cmd_code */, BT_HDR* /* p_pkt */) {}}; + void operator()(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code, + BT_HDR* p_pkt) { + body(rc_handle, label, cmd_code, p_pkt); + }; +}; +extern struct BTA_AvMetaCmd BTA_AvMetaCmd; + +// Name: BTA_AvMetaRsp +// Params: uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, BT_HDR* +// p_pkt Return: void +struct BTA_AvMetaRsp { + std::function + body{[](uint8_t /* rc_handle */, uint8_t /* label */, + tBTA_AV_CODE /* rsp_code */, BT_HDR* /* p_pkt */) {}}; + void operator()(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, + BT_HDR* p_pkt) { + body(rc_handle, label, rsp_code, p_pkt); + }; +}; +extern struct BTA_AvMetaRsp BTA_AvMetaRsp; + +// Name: BTA_AvOffloadStart +// Params: tBTA_AV_HNDL hndl +// Return: void +struct BTA_AvOffloadStart { + std::function body{[](tBTA_AV_HNDL /* hndl */) {}}; + void operator()(tBTA_AV_HNDL hndl) { body(hndl); }; +}; +extern struct BTA_AvOffloadStart BTA_AvOffloadStart; + +// Name: BTA_AvOffloadStartRsp +// Params: tBTA_AV_HNDL hndl, tBTA_AV_STATUS status +// Return: void +struct BTA_AvOffloadStartRsp { + std::function body{ + [](tBTA_AV_HNDL /* hndl */, tBTA_AV_STATUS /* status */) {}}; + void operator()(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status) { + body(hndl, status); + }; +}; +extern struct BTA_AvOffloadStartRsp BTA_AvOffloadStartRsp; + +// Name: BTA_AvOpen +// Params: const RawAddress& bd_addr, tBTA_AV_HNDL handle, bool use_rc, uint16_t +// uuid Return: void +struct BTA_AvOpen { + std::function + body{[](const RawAddress& /* bd_addr */, tBTA_AV_HNDL /* handle */, + bool /* use_rc */, uint16_t /* uuid */) {}}; + void operator()(const RawAddress& bd_addr, tBTA_AV_HNDL handle, bool use_rc, + uint16_t uuid) { + body(bd_addr, handle, use_rc, uuid); + }; +}; +extern struct BTA_AvOpen BTA_AvOpen; + +// Name: BTA_AvOpenRc +// Params: tBTA_AV_HNDL handle +// Return: void +struct BTA_AvOpenRc { + std::function body{ + [](tBTA_AV_HNDL /* handle */) {}}; + void operator()(tBTA_AV_HNDL handle) { body(handle); }; +}; +extern struct BTA_AvOpenRc BTA_AvOpenRc; + +// Name: BTA_AvProtectReq +// Params: tBTA_AV_HNDL hndl, uint8_t* p_data, uint16_t len +// Return: void +struct BTA_AvProtectReq { + std::function body{ + [](tBTA_AV_HNDL /* hndl */, uint8_t* /* p_data */, uint16_t /* len */) { + }}; + void operator()(tBTA_AV_HNDL hndl, uint8_t* p_data, uint16_t len) { + body(hndl, p_data, len); + }; +}; +extern struct BTA_AvProtectReq BTA_AvProtectReq; + +// Name: BTA_AvProtectRsp +// Params: tBTA_AV_HNDL hndl, uint8_t error_code, uint8_t* p_data, uint16_t len +// Return: void +struct BTA_AvProtectRsp { + std::function + body{[](tBTA_AV_HNDL /* hndl */, uint8_t /* error_code */, + uint8_t* /* p_data */, uint16_t /* len */) {}}; + void operator()(tBTA_AV_HNDL hndl, uint8_t error_code, uint8_t* p_data, + uint16_t len) { + body(hndl, error_code, p_data, len); + }; +}; +extern struct BTA_AvProtectRsp BTA_AvProtectRsp; + +// Name: BTA_AvReconfig +// Params: tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx, uint8_t* +// p_codec_info, uint8_t num_protect, const uint8_t* p_protect_info Return: void +struct BTA_AvReconfig { + std::function + body{[](tBTA_AV_HNDL /* hndl */, bool /* suspend */, + uint8_t /* sep_info_idx */, uint8_t* /* p_codec_info */, + uint8_t /* num_protect */, + const uint8_t* /* p_protect_info */) {}}; + void operator()(tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx, + uint8_t* p_codec_info, uint8_t num_protect, + const uint8_t* p_protect_info) { + body(hndl, suspend, sep_info_idx, p_codec_info, num_protect, + p_protect_info); + }; +}; +extern struct BTA_AvReconfig BTA_AvReconfig; + +// Name: BTA_AvRegister +// Params: tBTA_AV_CHNL chnl, const char* p_service_name, uint8_t app_id, +// tBTA_AV_SINK_DATA_CBACK* p_sink_data_cback, uint16_t service_uuid Return: +// void +struct BTA_AvRegister { + std::function + body{[](tBTA_AV_CHNL /* chnl */, const char* /* p_service_name */, + uint8_t /* app_id */, + tBTA_AV_SINK_DATA_CBACK* /* p_sink_data_cback */, + uint16_t /* service_uuid */) {}}; + void operator()(tBTA_AV_CHNL chnl, const char* p_service_name, uint8_t app_id, + tBTA_AV_SINK_DATA_CBACK* p_sink_data_cback, + uint16_t service_uuid) { + body(chnl, p_service_name, app_id, p_sink_data_cback, service_uuid); + }; +}; +extern struct BTA_AvRegister BTA_AvRegister; + +// Name: BTA_AvRemoteCmd +// Params: uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id, tBTA_AV_STATE +// key_state Return: void +struct BTA_AvRemoteCmd { + std::function + body{[](uint8_t /* rc_handle */, uint8_t /* label */, + tBTA_AV_RC /* rc_id */, tBTA_AV_STATE /* key_state */) {}}; + void operator()(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id, + tBTA_AV_STATE key_state) { + body(rc_handle, label, rc_id, key_state); + }; +}; +extern struct BTA_AvRemoteCmd BTA_AvRemoteCmd; + +// Name: BTA_AvRemoteVendorUniqueCmd +// Params: uint8_t rc_handle, uint8_t label, tBTA_AV_STATE key_state, uint8_t* +// p_msg, uint8_t buf_len Return: void +struct BTA_AvRemoteVendorUniqueCmd { + std::function + body{[](uint8_t /* rc_handle */, uint8_t /* label */, + tBTA_AV_STATE /* key_state */, uint8_t* /* p_msg */, + uint8_t /* buf_len */) {}}; + void operator()(uint8_t rc_handle, uint8_t label, tBTA_AV_STATE key_state, + uint8_t* p_msg, uint8_t buf_len) { + body(rc_handle, label, key_state, p_msg, buf_len); + }; +}; +extern struct BTA_AvRemoteVendorUniqueCmd BTA_AvRemoteVendorUniqueCmd; + +// Name: BTA_AvSetLatency +// Params: tBTA_AV_HNDL handle, bool is_low_latency +// Return: void +struct BTA_AvSetLatency { + std::function body{ + [](tBTA_AV_HNDL /* handle */, bool /* is_low_latency */) {}}; + void operator()(tBTA_AV_HNDL handle, bool is_low_latency) { + body(handle, is_low_latency); + }; +}; +extern struct BTA_AvSetLatency BTA_AvSetLatency; + +// Name: BTA_AvSetPeerSep +// Params: const RawAddress& bdaddr, uint8_t sep +// Return: void +struct BTA_AvSetPeerSep { + std::function body{ + [](const RawAddress& /* bdaddr */, uint8_t /* sep */) {}}; + void operator()(const RawAddress& bdaddr, uint8_t sep) { body(bdaddr, sep); }; +}; +extern struct BTA_AvSetPeerSep BTA_AvSetPeerSep; + +// Name: BTA_AvStart +// Params: tBTA_AV_HNDL handle, bool use_latency_mode +// Return: void +struct BTA_AvStart { + std::function body{ + [](tBTA_AV_HNDL /* handle */, bool /* use_latency_mode */) {}}; + void operator()(tBTA_AV_HNDL handle, bool use_latency_mode) { + body(handle, use_latency_mode); + }; +}; +extern struct BTA_AvStart BTA_AvStart; + +// Name: BTA_AvStop +// Params: tBTA_AV_HNDL handle, bool suspend +// Return: void +struct BTA_AvStop { + std::function body{ + [](tBTA_AV_HNDL /* handle */, bool /* suspend */) {}}; + void operator()(tBTA_AV_HNDL handle, bool suspend) { body(handle, suspend); }; +}; +extern struct BTA_AvStop BTA_AvStop; + +// Name: BTA_AvVendorCmd +// Params: uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code, uint8_t* +// p_data, uint16_t len Return: void +struct BTA_AvVendorCmd { + std::function + body{[](uint8_t /* rc_handle */, uint8_t /* label */, + tBTA_AV_CODE /* cmd_code */, uint8_t* /* p_data */, + uint16_t /* len */) {}}; + void operator()(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code, + uint8_t* p_data, uint16_t len) { + body(rc_handle, label, cmd_code, p_data, len); + }; +}; +extern struct BTA_AvVendorCmd BTA_AvVendorCmd; + +// Name: BTA_AvVendorRsp +// Params: uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, uint8_t* +// p_data, uint16_t len, uint32_t company_id Return: void +struct BTA_AvVendorRsp { + std::function + body{[](uint8_t /* rc_handle */, uint8_t /* label */, + tBTA_AV_CODE /* rsp_code */, uint8_t* /* p_data */, + uint16_t /* len */, uint32_t /* company_id */) {}}; + void operator()(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, + uint8_t* p_data, uint16_t len, uint32_t company_id) { + body(rc_handle, label, rsp_code, p_data, len, company_id); + }; +}; +extern struct BTA_AvVendorRsp BTA_AvVendorRsp; + +} // namespace bta_av_api +} // namespace mock +} // namespace test + +// END mockcify generation \ No newline at end of file diff --git a/system/test/mock/mock_bta_av_ci.cc b/system/test/mock/mock_bta_av_ci.cc index d70886b2eda2948f74ecb058583c003f459a6b19..32495fb79c4514d0242ae3d99f99939f5d546987 100644 --- a/system/test/mock/mock_bta_av_ci.cc +++ b/system/test/mock/mock_bta_av_ci.cc @@ -19,18 +19,9 @@ * Functions generated:2 */ -#include -#include - -#include "bta/av/bta_av_int.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" +#include "bta/include/bta_av_api.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void bta_av_ci_setconfig(tBTA_AV_HNDL bta_av_handle, uint8_t err_code, uint8_t category, uint8_t num_seid, uint8_t* p_seid, bool recfg_needed, uint8_t avdt_handle) { diff --git a/system/test/mock/mock_bta_av_main.cc b/system/test/mock/mock_bta_av_main.cc index c4d7ecc1dd2c780b2710a7c8cdc1cb9dc6b8ee02..980ed4f12d2a91d8f97a45aeb8461256a240f6b9 100644 --- a/system/test/mock/mock_bta_av_main.cc +++ b/system/test/mock/mock_bta_av_main.cc @@ -20,35 +20,17 @@ */ #include -#include -#include -#include "bt_target.h" #include "bta/av/bta_av_int.h" -#include "bta/include/bta_ar_api.h" -#include "bta/include/utl.h" -#include "btif/avrcp/avrcp_service.h" -#include "btif/include/btif_av_co.h" -#include "btif/include/btif_config.h" -#include "main/shim/dumpsys.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "osi/include/properties.h" -#include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" -#include "types/hci_role.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - bool bta_av_chk_start(tBTA_AV_SCB* p_scb) { inc_func_call_count(__func__); return false; } -bool bta_av_hdl_event(BT_HDR* p_msg) { +bool bta_av_hdl_event(const BT_HDR_RIGID* p_msg) { inc_func_call_count(__func__); return false; } @@ -79,8 +61,8 @@ tBTA_AV_SCB* bta_av_hndl_to_scb(uint16_t handle) { void bta_av_api_deregister(tBTA_AV_DATA* p_data) { inc_func_call_count(__func__); } -void bta_av_conn_cback(UNUSED_ATTR uint8_t handle, const RawAddress& bd_addr, - uint8_t event, tAVDT_CTRL* p_data, uint8_t scb_index) { +void bta_av_conn_cback(uint8_t handle, const RawAddress& bd_addr, uint8_t event, + tAVDT_CTRL* p_data, uint8_t scb_index) { inc_func_call_count(__func__); } void bta_av_dup_audio_buf(tBTA_AV_SCB* p_scb, BT_HDR* p_buf) { diff --git a/system/test/mock/mock_bta_csis.cc b/system/test/mock/mock_bta_csis.cc index af1a4ed1008706490b5dff6209fc8e41c0422573..6ec2761d88f0352f22fcbe4c6e20113bf38f95ee 100644 --- a/system/test/mock/mock_bta_csis.cc +++ b/system/test/mock/mock_bta_csis.cc @@ -18,17 +18,9 @@ #include #include -#include -#include - #include "bta/include/bta_csis_api.h" -#include "btif/include/btif_storage.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - using bluetooth::csis::CsisClient; using bluetooth::csis::CsisClientCallbacks; diff --git a/system/test/mock/mock_bta_dm_act.cc b/system/test/mock/mock_bta_dm_act.cc index 6daa80d5f0479f4984d9814196eab3e5bbcf7327..5ebe4f30195a205b63e6b443bf97bba6e84b81eb 100644 --- a/system/test/mock/mock_bta_dm_act.cc +++ b/system/test/mock/mock_bta_dm_act.cc @@ -21,13 +21,12 @@ * mockcify.pl ver 0.3.0 */ -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_bta_dm_act.h" + +#include + +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked internal structures, if any @@ -65,40 +64,20 @@ struct bta_dm_bond_cancel bta_dm_bond_cancel; struct bta_dm_check_if_only_hd_connected bta_dm_check_if_only_hd_connected; struct bta_dm_ci_rmt_oob_act bta_dm_ci_rmt_oob_act; struct bta_dm_close_acl bta_dm_close_acl; -struct bta_dm_close_gatt_conn bta_dm_close_gatt_conn; struct bta_dm_confirm bta_dm_confirm; -struct bta_dm_deinit_cb bta_dm_deinit_cb; struct bta_dm_disable bta_dm_disable; -struct bta_dm_disc_result bta_dm_disc_result; -struct bta_dm_disc_rmt_name bta_dm_disc_rmt_name; -struct bta_dm_discover bta_dm_discover; struct bta_dm_eir_update_cust_uuid bta_dm_eir_update_cust_uuid; struct bta_dm_eir_update_uuid bta_dm_eir_update_uuid; struct bta_dm_enable bta_dm_enable; struct bta_dm_encrypt_cback bta_dm_encrypt_cback; -struct bta_dm_execute_queued_request bta_dm_execute_queued_request; -struct bta_dm_free_sdp_db bta_dm_free_sdp_db; -struct bta_dm_init_cb bta_dm_init_cb; -struct bta_dm_inq_cmpl bta_dm_inq_cmpl; struct bta_dm_is_search_request_queued bta_dm_is_search_request_queued; struct bta_dm_pin_reply bta_dm_pin_reply; -struct bta_dm_proc_open_evt bta_dm_proc_open_evt; struct bta_dm_process_remove_device bta_dm_process_remove_device; -struct bta_dm_queue_disc bta_dm_queue_disc; -struct bta_dm_queue_search bta_dm_queue_search; struct bta_dm_remove_device bta_dm_remove_device; struct bta_dm_rm_cback bta_dm_rm_cback; -struct bta_dm_rmt_name bta_dm_rmt_name; struct bta_dm_sdp_result bta_dm_sdp_result; -struct bta_dm_search_cancel bta_dm_search_cancel; -struct bta_dm_search_cancel_notify bta_dm_search_cancel_notify; -struct bta_dm_search_clear_queue bta_dm_search_clear_queue; -struct bta_dm_search_cmpl bta_dm_search_cmpl; -struct bta_dm_search_result bta_dm_search_result; -struct bta_dm_search_start bta_dm_search_start; struct bta_dm_set_dev_name bta_dm_set_dev_name; struct bta_dm_set_encryption bta_dm_set_encryption; -struct btm_dm_start_gatt_discovery btm_dm_start_gatt_discovery; struct handle_remote_features_complete handle_remote_features_complete; } // namespace bta_dm_act @@ -236,34 +215,14 @@ void bta_dm_close_acl(const RawAddress& bd_addr, bool remove_dev, inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_close_acl(bd_addr, remove_dev, transport); } -void bta_dm_close_gatt_conn(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_close_gatt_conn(p_data); -} void bta_dm_confirm(const RawAddress& bd_addr, bool accept) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_confirm(bd_addr, accept); } -void bta_dm_deinit_cb(void) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_deinit_cb(); -} void bta_dm_disable() { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_disable(); } -void bta_dm_disc_result(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_disc_result(p_data); -} -void bta_dm_disc_rmt_name(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_disc_rmt_name(p_data); -} -void bta_dm_discover(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_discover(p_data); -} void bta_dm_eir_update_cust_uuid(const tBTA_CUSTOM_UUID& curr, bool adding) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_eir_update_cust_uuid(curr, adding); @@ -282,22 +241,6 @@ void bta_dm_encrypt_cback(const RawAddress* bd_addr, tBT_TRANSPORT transport, test::mock::bta_dm_act::bta_dm_encrypt_cback(bd_addr, transport, p_ref_data, result); } -void bta_dm_execute_queued_request() { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_execute_queued_request(); -} -void bta_dm_free_sdp_db() { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_free_sdp_db(); -} -void bta_dm_init_cb(void) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_init_cb(); -} -void bta_dm_inq_cmpl(uint8_t num) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_inq_cmpl(num); -} bool bta_dm_is_search_request_queued() { inc_func_call_count(__func__); return test::mock::bta_dm_act::bta_dm_is_search_request_queued(); @@ -306,22 +249,10 @@ void bta_dm_pin_reply(std::unique_ptr msg) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_pin_reply(std::move(msg)); } -void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_proc_open_evt(p_data); -} void bta_dm_process_remove_device(const RawAddress& bd_addr) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_process_remove_device(bd_addr); } -void bta_dm_queue_disc(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_queue_disc(p_data); -} -void bta_dm_queue_search(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_queue_search(p_data); -} void bta_dm_remove_device(const RawAddress& bd_addr) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_remove_device(bd_addr); @@ -331,38 +262,10 @@ void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id, uint8_t app_id, inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_rm_cback(status, id, app_id, peer_addr); } -void bta_dm_rmt_name(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_rmt_name(p_data); -} void bta_dm_sdp_result(tBTA_DM_MSG* p_data) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_sdp_result(p_data); } -void bta_dm_search_cancel() { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_search_cancel(); -} -void bta_dm_search_cancel_notify() { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_search_cancel_notify(); -} -void bta_dm_search_clear_queue() { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_search_clear_queue(); -} -void bta_dm_search_cmpl() { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_search_cmpl(); -} -void bta_dm_search_result(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_search_result(p_data); -} -void bta_dm_search_start(tBTA_DM_MSG* p_data) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::bta_dm_search_start(p_data); -} void bta_dm_set_dev_name(const std::vector& name) { inc_func_call_count(__func__); test::mock::bta_dm_act::bta_dm_set_dev_name(name); @@ -374,10 +277,6 @@ void bta_dm_set_encryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, test::mock::bta_dm_act::bta_dm_set_encryption(bd_addr, transport, p_callback, sec_act); } -void btm_dm_start_gatt_discovery(const RawAddress& bd_addr) { - inc_func_call_count(__func__); - test::mock::bta_dm_act::btm_dm_start_gatt_discovery(bd_addr); -} void handle_remote_features_complete(const RawAddress& bd_addr) { inc_func_call_count(__func__); test::mock::bta_dm_act::handle_remote_features_complete(bd_addr); diff --git a/system/test/mock/mock_bta_dm_act.h b/system/test/mock/mock_bta_dm_act.h index eb334992ab52c737454282758597eb483f666a48..1450c0bd5479f83ce7c5d3c5bc191ed9de0ad239 100644 --- a/system/test/mock/mock_bta_dm_act.h +++ b/system/test/mock/mock_bta_dm_act.h @@ -23,38 +23,12 @@ #include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include -#include "bta/dm/bta_dm_int.h" -#include "bta/gatt/bta_gattc_int.h" -#include "bta/include/bta_dm_ci.h" -#include "btif/include/btif_dm.h" -#include "btif/include/btif_storage.h" -#include "btif/include/stack_manager.h" -#include "gap_api.h" -#include "main/shim/acl_api.h" -#include "main/shim/btm_api.h" -#include "main/shim/dumpsys.h" -#include "main/shim/shim.h" -#include "osi/include/fixed_queue.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "stack/btm/btm_sec.h" -#include "stack/btm/neighbor_inquiry.h" -#include "stack/gatt/connection_manager.h" -#include "stack/include/acl_api.h" -#include "stack/include/btm_client_interface.h" +#include "bta/dm/bta_dm_disc_int.h" +#include "bta/dm/bta_dm_sec_int.h" #include "types/raw_address.h" // Mocked compile conditionals, if any @@ -431,15 +405,6 @@ struct bta_dm_close_acl { }; extern struct bta_dm_close_acl bta_dm_close_acl; -// Name: bta_dm_close_gatt_conn -// Params: tBTA_DM_MSG* p_data -// Return: void -struct bta_dm_close_gatt_conn { - std::function body{[](tBTA_DM_MSG* p_data) {}}; - void operator()(tBTA_DM_MSG* p_data) { body(p_data); }; -}; -extern struct bta_dm_close_gatt_conn bta_dm_close_gatt_conn; - // Name: bta_dm_confirm // Params: const RawAddress& bd_addr, bool accept // Return: void @@ -452,15 +417,6 @@ struct bta_dm_confirm { }; extern struct bta_dm_confirm bta_dm_confirm; -// Name: bta_dm_deinit_cb -// Params: void -// Return: void -struct bta_dm_deinit_cb { - std::function body{[](void) {}}; - void operator()(void) { body(); }; -}; -extern struct bta_dm_deinit_cb bta_dm_deinit_cb; - // Name: bta_dm_disable // Params: // Return: void @@ -470,33 +426,6 @@ struct bta_dm_disable { }; extern struct bta_dm_disable bta_dm_disable; -// Name: bta_dm_disc_result -// Params: tBTA_DM_MSG* p_data -// Return: void -struct bta_dm_disc_result { - std::function body{[](tBTA_DM_MSG* p_data) {}}; - void operator()(tBTA_DM_MSG* p_data) { body(p_data); }; -}; -extern struct bta_dm_disc_result bta_dm_disc_result; - -// Name: bta_dm_disc_rmt_name -// Params: tBTA_DM_MSG* p_data -// Return: void -struct bta_dm_disc_rmt_name { - std::function body{[](tBTA_DM_MSG* p_data) {}}; - void operator()(tBTA_DM_MSG* p_data) { body(p_data); }; -}; -extern struct bta_dm_disc_rmt_name bta_dm_disc_rmt_name; - -// Name: bta_dm_discover -// Params: tBTA_DM_MSG* p_data -// Return: void -struct bta_dm_discover { - std::function body{[](tBTA_DM_MSG* p_data) {}}; - void operator()(tBTA_DM_MSG* p_data) { body(p_data); }; -}; -extern struct bta_dm_discover bta_dm_discover; - // Name: bta_dm_eir_update_cust_uuid // Params: const tBTA_CUSTOM_UUID& curr, bool adding // Return: void @@ -544,42 +473,6 @@ struct bta_dm_encrypt_cback { }; extern struct bta_dm_encrypt_cback bta_dm_encrypt_cback; -// Name: bta_dm_execute_queued_request -// Params: -// Return: void -struct bta_dm_execute_queued_request { - std::function body{[]() {}}; - void operator()() { body(); }; -}; -extern struct bta_dm_execute_queued_request bta_dm_execute_queued_request; - -// Name: bta_dm_free_sdp_db -// Params: -// Return: void -struct bta_dm_free_sdp_db { - std::function body{[]() {}}; - void operator()() { body(); }; -}; -extern struct bta_dm_free_sdp_db bta_dm_free_sdp_db; - -// Name: bta_dm_init_cb -// Params: void -// Return: void -struct bta_dm_init_cb { - std::function body{[](void) {}}; - void operator()(void) { body(); }; -}; -extern struct bta_dm_init_cb bta_dm_init_cb; - -// Name: bta_dm_inq_cmpl -// Params: uint8_t num -// Return: void -struct bta_dm_inq_cmpl { - std::function body{[](uint8_t num) {}}; - void operator()(uint8_t num) { body(num); }; -}; -extern struct bta_dm_inq_cmpl bta_dm_inq_cmpl; - // Name: bta_dm_is_search_request_queued // Params: // Return: bool @@ -602,16 +495,6 @@ struct bta_dm_pin_reply { }; extern struct bta_dm_pin_reply bta_dm_pin_reply; -// Name: bta_dm_proc_open_evt -// Params: tBTA_GATTC_OPEN* p_data -// Return: void -struct bta_dm_proc_open_evt { - std::function body{ - [](tBTA_GATTC_OPEN* p_data) {}}; - void operator()(tBTA_GATTC_OPEN* p_data) { body(p_data); }; -}; -extern struct bta_dm_proc_open_evt bta_dm_proc_open_evt; - // Name: bta_dm_process_remove_device // Params: const RawAddress& bd_addr // Return: void @@ -622,24 +505,6 @@ struct bta_dm_process_remove_device { }; extern struct bta_dm_process_remove_device bta_dm_process_remove_device; -// Name: bta_dm_queue_disc -// Params: tBTA_DM_MSG* p_data -// Return: void -struct bta_dm_queue_disc { - std::function body{[](tBTA_DM_MSG* p_data) {}}; - void operator()(tBTA_DM_MSG* p_data) { body(p_data); }; -}; -extern struct bta_dm_queue_disc bta_dm_queue_disc; - -// Name: bta_dm_queue_search -// Params: tBTA_DM_MSG* p_data -// Return: void -struct bta_dm_queue_search { - std::function body{[](tBTA_DM_MSG* p_data) {}}; - void operator()(tBTA_DM_MSG* p_data) { body(p_data); }; -}; -extern struct bta_dm_queue_search bta_dm_queue_search; - // Name: bta_dm_remove_device // Params: const RawAddress& bd_addr // Return: void @@ -665,15 +530,6 @@ struct bta_dm_rm_cback { }; extern struct bta_dm_rm_cback bta_dm_rm_cback; -// Name: bta_dm_rmt_name -// Params: tBTA_DM_MSG* p_data -// Return: void -struct bta_dm_rmt_name { - std::function body{[](tBTA_DM_MSG* p_data) {}}; - void operator()(tBTA_DM_MSG* p_data) { body(p_data); }; -}; -extern struct bta_dm_rmt_name bta_dm_rmt_name; - // Name: bta_dm_sdp_result // Params: tBTA_DM_MSG* p_data // Return: void @@ -683,15 +539,6 @@ struct bta_dm_sdp_result { }; extern struct bta_dm_sdp_result bta_dm_sdp_result; -// Name: bta_dm_search_cancel -// Params: -// Return: void -struct bta_dm_search_cancel { - std::function body{[]() {}}; - void operator()() { body(); }; -}; -extern struct bta_dm_search_cancel bta_dm_search_cancel; - // Name: bta_dm_search_cancel_cmpl // Params: // Return: void @@ -710,24 +557,6 @@ struct bta_dm_search_cancel_notify { }; extern struct bta_dm_search_cancel_notify bta_dm_search_cancel_notify; -// Name: bta_dm_search_clear_queue -// Params: -// Return: void -struct bta_dm_search_clear_queue { - std::function body{[]() {}}; - void operator()() { body(); }; -}; -extern struct bta_dm_search_clear_queue bta_dm_search_clear_queue; - -// Name: bta_dm_search_cmpl -// Params: -// Return: void -struct bta_dm_search_cmpl { - std::function body{[]() {}}; - void operator()() { body(); }; -}; -extern struct bta_dm_search_cmpl bta_dm_search_cmpl; - // Name: bta_dm_search_result // Params: tBTA_DM_MSG* p_data // Return: void @@ -737,15 +566,6 @@ struct bta_dm_search_result { }; extern struct bta_dm_search_result bta_dm_search_result; -// Name: bta_dm_search_start -// Params: tBTA_DM_MSG* p_data -// Return: void -struct bta_dm_search_start { - std::function body{[](tBTA_DM_MSG* p_data) {}}; - void operator()(tBTA_DM_MSG* p_data) { body(p_data); }; -}; -extern struct bta_dm_search_start bta_dm_search_start; - // Name: bta_dm_set_dev_name // Params: const std::vector& name // Return: void @@ -772,16 +592,6 @@ struct bta_dm_set_encryption { }; extern struct bta_dm_set_encryption bta_dm_set_encryption; -// Name: btm_dm_start_gatt_discovery -// Params: const RawAddress& bd_addr -// Return: void -struct btm_dm_start_gatt_discovery { - std::function body{ - [](const RawAddress& bd_addr) {}}; - void operator()(const RawAddress& bd_addr) { body(bd_addr); }; -}; -extern struct btm_dm_start_gatt_discovery btm_dm_start_gatt_discovery; - // Name: handle_remote_features_complete // Params: const RawAddress& bd_addr // Return: void diff --git a/system/test/mock/mock_bta_dm_api.cc b/system/test/mock/mock_bta_dm_api.cc index 8b54c5896270cc0b0c236c6cc7eb6f3c3a033254..e9669fc54427ae421d7bd737b0711d323994bba3 100644 --- a/system/test/mock/mock_bta_dm_api.cc +++ b/system/test/mock/mock_bta_dm_api.cc @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,24 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* * Generated mock file from original source file - * Functions generated:34 + * Functions generated:47 * - * mockcify.pl ver 0.3.0 + * mockcify.pl ver 0.6.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_bta_dm_api.h" + #include -#include -#include -#include -#include "stack/include/bt_octets.h" +#include "test/common/mock_functions.h" -// Mock include file to share data between tests and mock -#include "test/mock/mock_bta_dm_api.h" -#include "types/raw_address.h" +// Original usings // Mocked internal structures, if any @@ -42,6 +39,7 @@ namespace bta_dm_api { struct BTA_DmAddBleDevice BTA_DmAddBleDevice; struct BTA_DmAddBleKey BTA_DmAddBleKey; struct BTA_DmAddDevice BTA_DmAddDevice; +struct BTA_DmAllowWakeByHid BTA_DmAllowWakeByHid; struct BTA_DmBleConfigLocalPrivacy BTA_DmBleConfigLocalPrivacy; struct BTA_DmBleConfirmReply BTA_DmBleConfirmReply; struct BTA_DmBleCsisObserve BTA_DmBleCsisObserve; @@ -49,24 +47,41 @@ struct BTA_DmBleGetEnergyInfo BTA_DmBleGetEnergyInfo; struct BTA_DmBleObserve BTA_DmBleObserve; struct BTA_DmBlePasskeyReply BTA_DmBlePasskeyReply; struct BTA_DmBleRequestMaxTxDataLength BTA_DmBleRequestMaxTxDataLength; +struct BTA_DmBleResetId BTA_DmBleResetId; struct BTA_DmBleScan BTA_DmBleScan; struct BTA_DmBleSecurityGrant BTA_DmBleSecurityGrant; +struct BTA_DmBleSubrateRequest BTA_DmBleSubrateRequest; struct BTA_DmBleUpdateConnectionParams BTA_DmBleUpdateConnectionParams; struct BTA_DmBond BTA_DmBond; struct BTA_DmBondCancel BTA_DmBondCancel; +struct BTA_DmCheckLeAudioCapable BTA_DmCheckLeAudioCapable; +struct BTA_DmClearEventFilter BTA_DmClearEventFilter; +struct BTA_DmClearEventMask BTA_DmClearEventMask; +struct BTA_DmClearFilterAcceptList BTA_DmClearFilterAcceptList; struct BTA_DmCloseACL BTA_DmCloseACL; struct BTA_DmConfirm BTA_DmConfirm; +struct BTA_DmDisconnectAllAcls BTA_DmDisconnectAllAcls; struct BTA_DmDiscover BTA_DmDiscover; struct BTA_DmGetConnectionState BTA_DmGetConnectionState; +struct BTA_DmLeRand BTA_DmLeRand; struct BTA_DmLocalOob BTA_DmLocalOob; struct BTA_DmPinReply BTA_DmPinReply; struct BTA_DmRemoveDevice BTA_DmRemoveDevice; +struct BTA_DmRestoreFilterAcceptList BTA_DmRestoreFilterAcceptList; struct BTA_DmSearch BTA_DmSearch; struct BTA_DmSearchCancel BTA_DmSearchCancel; struct BTA_DmSetBlePrefConnParams BTA_DmSetBlePrefConnParams; +struct BTA_DmSetDefaultEventMaskExcept BTA_DmSetDefaultEventMaskExcept; struct BTA_DmSetDeviceName BTA_DmSetDeviceName; struct BTA_DmSetEncryption BTA_DmSetEncryption; +struct BTA_DmSetEventFilterConnectionSetupAllDevices + BTA_DmSetEventFilterConnectionSetupAllDevices; +struct BTA_DmSetEventFilterInquiryResultAllDevices + BTA_DmSetEventFilterInquiryResultAllDevices; struct BTA_DmSetLocalDiRecord BTA_DmSetLocalDiRecord; +struct BTA_DmSirkConfirmDeviceReply BTA_DmSirkConfirmDeviceReply; +struct BTA_DmSirkSecCbRegister BTA_DmSirkSecCbRegister; +struct BTA_EnableTestMode BTA_EnableTestMode; struct BTA_GetEirService BTA_GetEirService; struct BTA_VendorInit BTA_VendorInit; struct BTA_dm_init BTA_dm_init; @@ -75,6 +90,20 @@ struct BTA_dm_init BTA_dm_init; } // namespace mock } // namespace test +// Mocked function return values, if any +namespace test { +namespace mock { +namespace bta_dm_api { + +bool BTA_DmCheckLeAudioCapable::return_value = false; +bool BTA_DmGetConnectionState::return_value = false; +tBTA_STATUS BTA_DmRemoveDevice::return_value = BTA_SUCCESS; +tBTA_STATUS BTA_DmSetLocalDiRecord::return_value = BTA_SUCCESS; + +} // namespace bta_dm_api +} // namespace mock +} // namespace test + // Mocked functions, if any void BTA_DmAddBleDevice(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, tBT_DEVICE_TYPE dev_type) { @@ -93,6 +122,13 @@ void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, test::mock::bta_dm_api::BTA_DmAddDevice(bd_addr, dev_class, link_key, key_type, pin_length); } +void BTA_DmAllowWakeByHid( + std::vector classic_hid_devices, + std::vector> le_hid_devices) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmAllowWakeByHid(classic_hid_devices, + le_hid_devices); +} void BTA_DmBleConfigLocalPrivacy(bool privacy_enable) { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_DmBleConfigLocalPrivacy(privacy_enable); @@ -123,15 +159,26 @@ void BTA_DmBleRequestMaxTxDataLength(const RawAddress& remote_device) { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_DmBleRequestMaxTxDataLength(remote_device); } -void BTA_DmBleScan(bool start, uint8_t duration, bool low_latency_scan) { +void BTA_DmBleResetId(void) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmBleResetId(); +} +void BTA_DmBleScan(bool start, uint8_t duration_sec, bool low_latency_scan) { inc_func_call_count(__func__); - test::mock::bta_dm_api::BTA_DmBleScan(start, duration, low_latency_scan); + test::mock::bta_dm_api::BTA_DmBleScan(start, duration_sec, low_latency_scan); } void BTA_DmBleSecurityGrant(const RawAddress& bd_addr, tBTA_DM_BLE_SEC_GRANT res) { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_DmBleSecurityGrant(bd_addr, res); } +void BTA_DmBleSubrateRequest(const RawAddress& bd_addr, uint16_t subrate_min, + uint16_t subrate_max, uint16_t max_latency, + uint16_t cont_num, uint16_t timeout) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmBleSubrateRequest( + bd_addr, subrate_min, subrate_max, max_latency, cont_num, timeout); +} void BTA_DmBleUpdateConnectionParams(const RawAddress& bd_addr, uint16_t min_int, uint16_t max_int, uint16_t latency, uint16_t timeout, @@ -150,6 +197,22 @@ void BTA_DmBondCancel(const RawAddress& bd_addr) { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_DmBondCancel(bd_addr); } +bool BTA_DmCheckLeAudioCapable(const RawAddress& address) { + inc_func_call_count(__func__); + return test::mock::bta_dm_api::BTA_DmCheckLeAudioCapable(address); +} +void BTA_DmClearEventFilter(void) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmClearEventFilter(); +} +void BTA_DmClearEventMask(void) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmClearEventMask(); +} +void BTA_DmClearFilterAcceptList(void) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmClearFilterAcceptList(); +} void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev, tBT_TRANSPORT transport) { inc_func_call_count(__func__); @@ -159,6 +222,10 @@ void BTA_DmConfirm(const RawAddress& bd_addr, bool accept) { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_DmConfirm(bd_addr, accept); } +void BTA_DmDisconnectAllAcls() { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmDisconnectAllAcls(); +} void BTA_DmDiscover(const RawAddress& bd_addr, tBTA_DM_SEARCH_CBACK* p_cback, tBT_TRANSPORT transport) { inc_func_call_count(__func__); @@ -168,6 +235,10 @@ bool BTA_DmGetConnectionState(const RawAddress& bd_addr) { inc_func_call_count(__func__); return test::mock::bta_dm_api::BTA_DmGetConnectionState(bd_addr); } +void BTA_DmLeRand(LeRandCallback cb) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmLeRand(std::move(cb)); +} void BTA_DmLocalOob(void) { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_DmLocalOob(); @@ -181,6 +252,11 @@ tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr) { inc_func_call_count(__func__); return test::mock::bta_dm_api::BTA_DmRemoveDevice(bd_addr); } +void BTA_DmRestoreFilterAcceptList( + std::vector> le_devices) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmRestoreFilterAcceptList(le_devices); +} void BTA_DmSearch(tBTA_DM_SEARCH_CBACK* p_cback) { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_DmSearch(p_cback); @@ -198,6 +274,10 @@ void BTA_DmSetBlePrefConnParams(const RawAddress& bd_addr, bd_addr, min_conn_int, max_conn_int, peripheral_latency, supervision_tout); } +void BTA_DmSetDefaultEventMaskExcept(uint64_t mask, uint64_t le_mask) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmSetDefaultEventMaskExcept(mask, le_mask); +} void BTA_DmSetDeviceName(const char* p_name) { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_DmSetDeviceName(p_name); @@ -209,12 +289,32 @@ void BTA_DmSetEncryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, test::mock::bta_dm_api::BTA_DmSetEncryption(bd_addr, transport, p_callback, sec_act); } +void BTA_DmSetEventFilterConnectionSetupAllDevices() { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmSetEventFilterConnectionSetupAllDevices(); +} +void BTA_DmSetEventFilterInquiryResultAllDevices() { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmSetEventFilterInquiryResultAllDevices(); +} tBTA_STATUS BTA_DmSetLocalDiRecord(tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { inc_func_call_count(__func__); return test::mock::bta_dm_api::BTA_DmSetLocalDiRecord(p_device_info, p_handle); } +void BTA_DmSirkConfirmDeviceReply(const RawAddress& bd_addr, bool accept) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmSirkConfirmDeviceReply(bd_addr, accept); +} +void BTA_DmSirkSecCbRegister(tBTA_DM_SEC_CBACK* p_cback) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_DmSirkSecCbRegister(p_cback); +} +void BTA_EnableTestMode(void) { + inc_func_call_count(__func__); + test::mock::bta_dm_api::BTA_EnableTestMode(); +} void BTA_GetEirService(const uint8_t* p_eir, size_t eir_len, tBTA_SERVICE_MASK* p_services) { inc_func_call_count(__func__); @@ -228,5 +328,5 @@ void BTA_dm_init() { inc_func_call_count(__func__); test::mock::bta_dm_api::BTA_dm_init(); } - +// Mocked functions complete // END mockcify generation diff --git a/system/test/mock/mock_bta_dm_api.h b/system/test/mock/mock_bta_dm_api.h index 1be9353e0253169ab0a19dea76bc102a4391de8e..d9acacdd6e0183f9930cd06c51d5776ef09086c5 100644 --- a/system/test/mock/mock_bta_dm_api.h +++ b/system/test/mock/mock_bta_dm_api.h @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,48 +13,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once /* * Generated mock file from original source file - * Functions generated:34 + * Functions generated:47 * - * mockcify.pl ver 0.3.0 + * mockcify.pl ver 0.6.1 */ #include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include -#include -#include #include -#include "bt_target.h" -#include "bta/dm/bta_dm_int.h" -#include "osi/include/allocator.h" -#include "stack/btm/btm_sec.h" +#include "bta/include/bta_api.h" +#include "bta/include/bta_sec_api.h" +#include "stack/include/bt_device_type.h" #include "stack/include/bt_octets.h" -#include "stack/include/btm_api.h" -#include "types/bluetooth/uuid.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" +// Original usings + // Mocked compile conditionals, if any namespace test { namespace mock { namespace bta_dm_api { +// Shared state between mocked functions and tests // Name: BTA_DmAddBleDevice // Params: const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, tBT_DEVICE_TYPE // dev_type Return: void @@ -103,6 +94,22 @@ struct BTA_DmAddDevice { }; extern struct BTA_DmAddDevice BTA_DmAddDevice; +// Name: BTA_DmAllowWakeByHid +// Params: std::vector classic_hid_devices, +// std::vector> le_hid_devices Return: void +struct BTA_DmAllowWakeByHid { + std::function classic_hid_devices, + std::vector> le_hid_devices)> + body{[](std::vector classic_hid_devices, + std::vector> le_hid_devices) {}}; + void operator()(std::vector classic_hid_devices, + std::vector> le_hid_devices) { + body(classic_hid_devices, le_hid_devices); + }; +}; +extern struct BTA_DmAllowWakeByHid BTA_DmAllowWakeByHid; + // Name: BTA_DmBleConfigLocalPrivacy // Params: bool privacy_enable // Return: void @@ -185,14 +192,23 @@ struct BTA_DmBleRequestMaxTxDataLength { }; extern struct BTA_DmBleRequestMaxTxDataLength BTA_DmBleRequestMaxTxDataLength; +// Name: BTA_DmBleResetId +// Params: void +// Return: void +struct BTA_DmBleResetId { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct BTA_DmBleResetId BTA_DmBleResetId; + // Name: BTA_DmBleScan -// Params: bool start, uint8_t duration, bool low_latency_scan +// Params: bool start, uint8_t duration_sec, bool low_latency_scan // Return: void struct BTA_DmBleScan { - std::function body{ - [](bool start, uint8_t duration, bool low_latency_scan) {}}; - void operator()(bool start, uint8_t duration, bool low_latency_scan) { - body(start, duration, low_latency_scan); + std::function + body{[](bool start, uint8_t duration_sec, bool low_latency_scan) {}}; + void operator()(bool start, uint8_t duration_sec, bool low_latency_scan) { + body(start, duration_sec, low_latency_scan); }; }; extern struct BTA_DmBleScan BTA_DmBleScan; @@ -209,6 +225,25 @@ struct BTA_DmBleSecurityGrant { }; extern struct BTA_DmBleSecurityGrant BTA_DmBleSecurityGrant; +// Name: BTA_DmBleSubrateRequest +// Params: const RawAddress& bd_addr, uint16_t subrate_min, uint16_t +// subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t timeout +// Return: void +struct BTA_DmBleSubrateRequest { + std::function + body{[](const RawAddress& bd_addr, uint16_t subrate_min, + uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, + uint16_t timeout) {}}; + void operator()(const RawAddress& bd_addr, uint16_t subrate_min, + uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, + uint16_t timeout) { + body(bd_addr, subrate_min, subrate_max, max_latency, cont_num, timeout); + }; +}; +extern struct BTA_DmBleSubrateRequest BTA_DmBleSubrateRequest; + // Name: BTA_DmBleUpdateConnectionParams // Params: const RawAddress& bd_addr, uint16_t min_int, uint16_t max_int, // uint16_t latency, uint16_t timeout, uint16_t min_ce_len, uint16_t max_ce_len @@ -253,6 +288,44 @@ struct BTA_DmBondCancel { }; extern struct BTA_DmBondCancel BTA_DmBondCancel; +// Name: BTA_DmCheckLeAudioCapable +// Params: const RawAddress& address +// Return: bool +struct BTA_DmCheckLeAudioCapable { + static bool return_value; + std::function body{ + [](const RawAddress& address) { return return_value; }}; + bool operator()(const RawAddress& address) { return body(address); }; +}; +extern struct BTA_DmCheckLeAudioCapable BTA_DmCheckLeAudioCapable; + +// Name: BTA_DmClearEventFilter +// Params: void +// Return: void +struct BTA_DmClearEventFilter { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct BTA_DmClearEventFilter BTA_DmClearEventFilter; + +// Name: BTA_DmClearEventMask +// Params: void +// Return: void +struct BTA_DmClearEventMask { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct BTA_DmClearEventMask BTA_DmClearEventMask; + +// Name: BTA_DmClearFilterAcceptList +// Params: void +// Return: void +struct BTA_DmClearFilterAcceptList { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct BTA_DmClearFilterAcceptList BTA_DmClearFilterAcceptList; + // Name: BTA_DmCloseACL // Params: const RawAddress& bd_addr, bool remove_dev, tBT_TRANSPORT transport // Return: void @@ -280,6 +353,15 @@ struct BTA_DmConfirm { }; extern struct BTA_DmConfirm BTA_DmConfirm; +// Name: BTA_DmDisconnectAllAcls +// Params: +// Return: void +struct BTA_DmDisconnectAllAcls { + std::function body{[]() {}}; + void operator()() { body(); }; +}; +extern struct BTA_DmDisconnectAllAcls BTA_DmDisconnectAllAcls; + // Name: BTA_DmDiscover // Params: const RawAddress& bd_addr, tBTA_DM_SEARCH_CBACK* p_cback, // tBT_TRANSPORT transport Return: void @@ -299,13 +381,22 @@ extern struct BTA_DmDiscover BTA_DmDiscover; // Params: const RawAddress& bd_addr // Return: bool struct BTA_DmGetConnectionState { - bool return_value{false}; + static bool return_value; std::function body{ - [this](const RawAddress& bd_addr) { return return_value; }}; + [](const RawAddress& bd_addr) { return return_value; }}; bool operator()(const RawAddress& bd_addr) { return body(bd_addr); }; }; extern struct BTA_DmGetConnectionState BTA_DmGetConnectionState; +// Name: BTA_DmLeRand +// Params: LeRandCallback cb +// Return: void +struct BTA_DmLeRand { + std::function body{[](LeRandCallback cb) {}}; + void operator()(LeRandCallback cb) { body(std::move(cb)); }; +}; +extern struct BTA_DmLeRand BTA_DmLeRand; + // Name: BTA_DmLocalOob // Params: void // Return: void @@ -334,13 +425,25 @@ extern struct BTA_DmPinReply BTA_DmPinReply; // Params: const RawAddress& bd_addr // Return: tBTA_STATUS struct BTA_DmRemoveDevice { - tBTA_STATUS return_value{0}; + static tBTA_STATUS return_value; std::function body{ - [this](const RawAddress& bd_addr) { return return_value; }}; + [](const RawAddress& bd_addr) { return return_value; }}; tBTA_STATUS operator()(const RawAddress& bd_addr) { return body(bd_addr); }; }; extern struct BTA_DmRemoveDevice BTA_DmRemoveDevice; +// Name: BTA_DmRestoreFilterAcceptList +// Params: std::vector> le_devices +// Return: void +struct BTA_DmRestoreFilterAcceptList { + std::function> le_devices)> + body{[](std::vector> le_devices) {}}; + void operator()(std::vector> le_devices) { + body(le_devices); + }; +}; +extern struct BTA_DmRestoreFilterAcceptList BTA_DmRestoreFilterAcceptList; + // Name: BTA_DmSearch // Params: tBTA_DM_SEARCH_CBACK* p_cback // Return: void @@ -380,8 +483,18 @@ struct BTA_DmSetBlePrefConnParams { }; extern struct BTA_DmSetBlePrefConnParams BTA_DmSetBlePrefConnParams; +// Name: BTA_DmSetDefaultEventMaskExcept +// Params: uint64_t mask, uint64_t le_mask +// Return: void +struct BTA_DmSetDefaultEventMaskExcept { + std::function body{ + [](uint64_t mask, uint64_t le_mask) {}}; + void operator()(uint64_t mask, uint64_t le_mask) { body(mask, le_mask); }; +}; +extern struct BTA_DmSetDefaultEventMaskExcept BTA_DmSetDefaultEventMaskExcept; + // Name: BTA_DmSetDeviceName -// Params: char* p_name +// Params: const char* p_name // Return: void struct BTA_DmSetDeviceName { std::function body{[](const char* p_name) {}}; @@ -405,13 +518,33 @@ struct BTA_DmSetEncryption { }; extern struct BTA_DmSetEncryption BTA_DmSetEncryption; +// Name: BTA_DmSetEventFilterConnectionSetupAllDevices +// Params: +// Return: void +struct BTA_DmSetEventFilterConnectionSetupAllDevices { + std::function body{[]() {}}; + void operator()() { body(); }; +}; +extern struct BTA_DmSetEventFilterConnectionSetupAllDevices + BTA_DmSetEventFilterConnectionSetupAllDevices; + +// Name: BTA_DmSetEventFilterInquiryResultAllDevices +// Params: +// Return: void +struct BTA_DmSetEventFilterInquiryResultAllDevices { + std::function body{[]() {}}; + void operator()() { body(); }; +}; +extern struct BTA_DmSetEventFilterInquiryResultAllDevices + BTA_DmSetEventFilterInquiryResultAllDevices; + // Name: BTA_DmSetLocalDiRecord // Params: tSDP_DI_RECORD* p_device_info, uint32_t* p_handle // Return: tBTA_STATUS struct BTA_DmSetLocalDiRecord { - tBTA_STATUS return_value{0}; + static tBTA_STATUS return_value; std::function - body{[this](tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { + body{[](tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { return return_value; }}; tBTA_STATUS operator()(tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { @@ -420,8 +553,39 @@ struct BTA_DmSetLocalDiRecord { }; extern struct BTA_DmSetLocalDiRecord BTA_DmSetLocalDiRecord; +// Name: BTA_DmSirkConfirmDeviceReply +// Params: const RawAddress& bd_addr, bool accept +// Return: void +struct BTA_DmSirkConfirmDeviceReply { + std::function body{ + [](const RawAddress& bd_addr, bool accept) {}}; + void operator()(const RawAddress& bd_addr, bool accept) { + body(bd_addr, accept); + }; +}; +extern struct BTA_DmSirkConfirmDeviceReply BTA_DmSirkConfirmDeviceReply; + +// Name: BTA_DmSirkSecCbRegister +// Params: tBTA_DM_SEC_CBACK* p_cback +// Return: void +struct BTA_DmSirkSecCbRegister { + std::function body{ + [](tBTA_DM_SEC_CBACK* p_cback) {}}; + void operator()(tBTA_DM_SEC_CBACK* p_cback) { body(p_cback); }; +}; +extern struct BTA_DmSirkSecCbRegister BTA_DmSirkSecCbRegister; + +// Name: BTA_EnableTestMode +// Params: void +// Return: void +struct BTA_EnableTestMode { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct BTA_EnableTestMode BTA_EnableTestMode; + // Name: BTA_GetEirService -// Params: uint8_t* p_eir, size_t eir_len, tBTA_SERVICE_MASK* p_services +// Params: const uint8_t* p_eir, size_t eir_len, tBTA_SERVICE_MASK* p_services // Return: void struct BTA_GetEirService { std::function -#include -#include -#include - // Mock include file to share data between tests and mock -#include "test/mock/mock_common_os_utils.h" +#include "test/mock/mock_bta_dm_main.h" + +#include "test/common/mock_functions.h" + +// Original usings // Mocked internal structures, if any namespace test { namespace mock { -namespace common_os_utils { +namespace bta_dm_main { // Function state capture and return values, if needed -struct is_bluetooth_uid is_bluetooth_uid; +struct DumpsysBtaDm DumpsysBtaDm; +struct bta_dm_search_sm_disable bta_dm_search_sm_disable; +struct bta_dm_search_sm_execute bta_dm_search_sm_execute; -} // namespace common_os_utils +} // namespace bta_dm_main } // namespace mock } // namespace test // Mocked function return values, if any namespace test { namespace mock { -namespace common_os_utils { +namespace bta_dm_main { -bool is_bluetooth_uid::return_value = false; +bool bta_dm_search_sm_execute::return_value = false; -} // namespace common_os_utils +} // namespace bta_dm_main } // namespace mock } // namespace test // Mocked functions, if any -bool is_bluetooth_uid() { +void DumpsysBtaDm(int fd) { + inc_func_call_count(__func__); + test::mock::bta_dm_main::DumpsysBtaDm(fd); +} +void bta_dm_search_sm_disable() { + inc_func_call_count(__func__); + test::mock::bta_dm_main::bta_dm_search_sm_disable(); +} +bool bta_dm_search_sm_execute(const BT_HDR_RIGID* p_msg) { inc_func_call_count(__func__); - return test::mock::common_os_utils::is_bluetooth_uid(); + return test::mock::bta_dm_main::bta_dm_search_sm_execute(p_msg); } // Mocked functions complete // END mockcify generation diff --git a/system/test/mock/mock_main_bte.h b/system/test/mock/mock_bta_dm_main.h similarity index 51% rename from system/test/mock/mock_main_bte.h rename to system/test/mock/mock_bta_dm_main.h index e58232156017fef8a19266c12dda52942598d017..350965b00c105e46f94be3d7ae8e368b12b8db7c 100644 --- a/system/test/mock/mock_main_bte.h +++ b/system/test/mock/mock_bta_dm_main.h @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,69 +13,66 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once /* * Generated mock file from original source file * Functions generated:3 * - * mockcify.pl ver 0.2 + * mockcify.pl ver 0.6.2 */ -#include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any // NOTE: Since this is a mock file with mock definitions some number of // include files may not be required. The include-what-you-use // still applies, but crafting proper inclusion is out of scope // for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include -#include +// may need attention to prune from (or add to ) the inclusion set. +#include -#include "btcore/include/module.h" -#include "btif/include/btif_config.h" -#include "hci/include/hci_layer.h" -#include "main/shim/hci_layer.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" -#include "stack_config.h" + +// Original usings // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif namespace test { namespace mock { -namespace main_bte { +namespace bta_dm_main { // Shared state between mocked functions and tests -// Name: bte_main_init -// Params: void -// Returns: void -struct bte_main_init { - std::function body{[](void) {}}; - void operator()(void) { body(); }; +// Name: DumpsysBtaDm +// Params: int fd +// Return: void +struct DumpsysBtaDm { + std::function body{[](int fd) {}}; + void operator()(int fd) { body(fd); }; }; -extern struct bte_main_init bte_main_init; -// Name: bte_main_hci_send -// Params: BT_HDR* p_msg, uint16_t event -// Returns: void -struct bte_main_hci_send { - std::function body{ - [](BT_HDR* p_msg, uint16_t event) {}}; - void operator()(BT_HDR* p_msg, uint16_t event) { body(p_msg, event); }; +extern struct DumpsysBtaDm DumpsysBtaDm; + +// Name: bta_dm_search_sm_disable +// Params: +// Return: void +struct bta_dm_search_sm_disable { + std::function body{[]() {}}; + void operator()() { body(); }; +}; +extern struct bta_dm_search_sm_disable bta_dm_search_sm_disable; + +// Name: bta_dm_search_sm_execute +// Params: const BT_HDR_RIGID* p_msg +// Return: bool +struct bta_dm_search_sm_execute { + static bool return_value; + std::function body{ + [](const BT_HDR_RIGID* p_msg) { return return_value; }}; + bool operator()(const BT_HDR_RIGID* p_msg) { return body(p_msg); }; }; -extern struct bte_main_hci_send bte_main_hci_send; +extern struct bta_dm_search_sm_execute bta_dm_search_sm_execute; -} // namespace main_bte +} // namespace bta_dm_main } // namespace mock } // namespace test diff --git a/system/test/mock/mock_bta_gattc_api.cc b/system/test/mock/mock_bta_gattc_api.cc index 7ad1d4755da210e64ae6a0103578d6d3df05078f..4e8265c818a340dd35068de80d7ac0822ce293a1 100644 --- a/system/test/mock/mock_bta_gattc_api.cc +++ b/system/test/mock/mock_bta_gattc_api.cc @@ -22,24 +22,14 @@ #include #include -#include -#include -#include -#include -#include -#include - -#include "bt_target.h" -#include "bta/gatt/bta_gattc_int.h" +#include "bta/gatt/database.h" +#include "bta/include/bta_gatt_api.h" +#include "stack/include/gatt_api.h" #include "test/common/mock_functions.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void BTA_GATTC_Disable(void) { inc_func_call_count(__func__); } const gatt::Characteristic* BTA_GATTC_GetCharacteristic(uint16_t conn_id, uint16_t handle) { @@ -138,8 +128,9 @@ void BTA_GATTC_ReadCharacteristic(uint16_t conn_id, uint16_t handle, GATT_READ_OP_CB callback, void* cb_data) { inc_func_call_count(__func__); } -void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI* p_read_multi, - tGATT_AUTH_REQ auth_req) { +void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI& handles, + bool variable_len, tGATT_AUTH_REQ auth_req, + GATT_READ_MULTI_OP_CB callback, void* cb_data) { inc_func_call_count(__func__); } void BTA_GATTC_ReadUsingCharUuid(uint16_t conn_id, const bluetooth::Uuid& uuid, @@ -171,3 +162,7 @@ void BTA_GATTC_WriteCharValue(uint16_t conn_id, uint16_t handle, GATT_WRITE_OP_CB callback, void* cb_data) { inc_func_call_count(__func__); } +void bta_gattc_continue_discovery_if_needed(const RawAddress& bd_addr, + uint16_t acl_handle) { + inc_func_call_count(__func__); +} diff --git a/system/test/mock/mock_bta_gatts_api.cc b/system/test/mock/mock_bta_gatts_api.cc index 450cb6f539998e30c1405bab7e79e5631552ede2..5610478a883fed74faad3ada682343889de12700 100644 --- a/system/test/mock/mock_bta_gatts_api.cc +++ b/system/test/mock/mock_bta_gatts_api.cc @@ -24,23 +24,14 @@ #include #include -#include -#include -#include #include -#include "bt_target.h" -#include "bta/gatt/bta_gatts_int.h" -#include "osi/include/allocator.h" +#include "bta/include/bta_gatt_api.h" #include "test/common/mock_functions.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void BTA_GATTS_Disable(void) { inc_func_call_count(__func__); } void BTA_GATTS_AppDeregister(tGATT_IF server_if) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_bta_groups.cc b/system/test/mock/mock_bta_groups.cc index 13a63bca8dc3869428e7b4476ec730392752fe5b..ff94864b9e7ed9a4fe7a4996804ccd53e36db89b 100644 --- a/system/test/mock/mock_bta_groups.cc +++ b/system/test/mock/mock_bta_groups.cc @@ -15,18 +15,11 @@ * limitations under the License. */ -#include -#include #include #include "bta/include/bta_groups.h" -#include "btif/include/btif_storage.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - using bluetooth::groups::DeviceGroups; void DeviceGroups::AddFromStorage(const RawAddress& addr, diff --git a/system/test/mock/mock_bta_has.cc b/system/test/mock/mock_bta_has.cc index 612fcc886a2e52ab0cce08a4e9fd1b6af3f177db..6d2f45d717bccd5212465f0c968cc5042e3787b7 100644 --- a/system/test/mock/mock_bta_has.cc +++ b/system/test/mock/mock_bta_has.cc @@ -17,17 +17,10 @@ #include #include -#include -#include - #include "bta/include/bta_has_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace le_audio { namespace has { diff --git a/system/test/mock/mock_bta_hd_api.cc b/system/test/mock/mock_bta_hd_api.cc index 8190e8ba630a08bb647699a7c078010d4b826db3..6efb79e82a6452cb0e9f3cfe629ea592ebeaa7a3 100644 --- a/system/test/mock/mock_bta_hd_api.cc +++ b/system/test/mock/mock_bta_hd_api.cc @@ -19,21 +19,10 @@ * Functions generated:12 */ -#include -#include - -#include "bt_target.h" -#include "bta/hd/bta_hd_int.h" -#include "osi/include/allocator.h" -#include "osi/include/compat.h" -#include "osi/include/log.h" +#include "bta/include/bta_hd_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void BTA_HdEnable(tBTA_HD_CBACK* p_cback) { inc_func_call_count(__func__); } void BTA_HdAddDevice(const RawAddress& addr) { inc_func_call_count(__func__); } void BTA_HdConnect(const RawAddress& addr) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_bta_hearing_aid.cc b/system/test/mock/mock_bta_hearing_aid.cc index 3e3e93ff7337f7232632ba26a0be86e04128ba74..edcbdf85304413f503b3d1e0219e08644cb9150c 100644 --- a/system/test/mock/mock_bta_hearing_aid.cc +++ b/system/test/mock/mock_bta_hearing_aid.cc @@ -24,37 +24,19 @@ #include #include -#include -#include -#include -#include "bta/include/bta_gatt_api.h" #include "bta/include/bta_gatt_queue.h" #include "bta/include/bta_hearing_aid_api.h" -#include "embdrv/g722/g722_enc_dec.h" -#include "osi/include/log.h" -#include "osi/include/properties.h" -#include "stack/btm/btm_sec.h" -#include "stack/include/acl_api.h" -#include "stack/include/acl_api_types.h" -#include "stack/include/gap_api.h" -#include "stack/include/l2c_api.h" #include "test/common/mock_functions.h" -#include "types/bluetooth/uuid.h" -#include "types/bt_transport.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - int HearingAid::GetDeviceCount() { inc_func_call_count(__func__); return 0; } void HearingAid::AddFromStorage(const HearingDevice& dev_info, - uint16_t is_acceptlisted) { + bool is_acceptlisted) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_bta_hf_client_api.cc b/system/test/mock/mock_bta_hf_client_api.cc index 6ccba1cd7e30524a64e9354b5ce5ad029718ef08..879ac6d210afe96c9e4dea9db70c2f431fa208ab 100644 --- a/system/test/mock/mock_bta_hf_client_api.cc +++ b/system/test/mock/mock_bta_hf_client_api.cc @@ -20,21 +20,12 @@ */ #include -#include -#include #include "bta/hf_client/bta_hf_client_int.h" #include "bta/include/bta_hf_client_api.h" -#include "bta/sys/bta_sys.h" -#include "osi/include/allocator.h" -#include "osi/include/compat.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK* p_cback, tBTA_HF_CLIENT_FEAT features, const char* p_service_name) { diff --git a/system/test/mock/mock_bta_hh_api.cc b/system/test/mock/mock_bta_hh_api.cc index 1889b45136804d4324bc69a1f9e715687b3c4d1a..70dd17a3165a411c6b5e094d7fe8204a53b600b6 100644 --- a/system/test/mock/mock_bta_hh_api.cc +++ b/system/test/mock/mock_bta_hh_api.cc @@ -20,22 +20,12 @@ */ #include -#include -#include -#include "bt_target.h" -#include "bta/hh/bta_hh_int.h" -#include "bta/sys/bta_sys.h" -#include "osi/include/allocator.h" -#include "osi/include/osi.h" +#include "bta/include/bta_hh_api.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void BTA_HhEnable(tBTA_HH_CBACK* p_cback, bool enable_hidp, bool enable_hogp) { inc_func_call_count(__func__); } @@ -58,7 +48,7 @@ void BTA_HhRemoveDev(uint8_t dev_handle) { inc_func_call_count(__func__); } void BTA_HhSendCtrl(uint8_t dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type) { inc_func_call_count(__func__); } -void BTA_HhSendData(uint8_t dev_handle, UNUSED_ATTR const RawAddress& dev_bda, +void BTA_HhSendData(uint8_t dev_handle, const RawAddress& dev_bda, BT_HDR* p_data) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_bta_hh_utils.cc b/system/test/mock/mock_bta_hh_utils.cc index 75755621bee5b8d33e0ece6924749f85efd72b9d..bb15bd8908f08c9b872df65c4ba82a4f2f3c90fc 100644 --- a/system/test/mock/mock_bta_hh_utils.cc +++ b/system/test/mock/mock_bta_hh_utils.cc @@ -20,14 +20,12 @@ * * mockcify.pl ver 0.3.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_bta_hh_utils.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_bta_hh_utils.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked internal structures, if any diff --git a/system/test/mock/mock_bta_hh_utils.h b/system/test/mock/mock_bta_hh_utils.h index 72920744875073f1b8fe7646183ecdca7af0f4ac..7ae214e99ab5cb7bd4cad5a000e8179ebd7404a8 100644 --- a/system/test/mock/mock_bta_hh_utils.h +++ b/system/test/mock/mock_bta_hh_utils.h @@ -23,26 +23,9 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include - -#include - -#include "bt_target.h" #include "bta/hh/bta_hh_int.h" -#include "btif/include/btif_storage.h" -#include "osi/include/osi.h" -#include "stack/include/acl_api.h" -#include "stack/include/btm_client_interface.h" -#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_bta_jv_api.cc b/system/test/mock/mock_bta_jv_api.cc index 1e80974120983dd5cfee8fffdf88622bbcd9e699..8d6b72fb5ae08eb4102760021f44d43bcaa9a076 100644 --- a/system/test/mock/mock_bta_jv_api.cc +++ b/system/test/mock/mock_bta_jv_api.cc @@ -24,22 +24,14 @@ #include #include -#include #include -#include -#include "bt_target.h" -#include "bta/jv/bta_jv_int.h" +#include "bta/include/bta_jv_api.h" #include "stack/include/bt_hdr.h" -#include "stack/include/gap_api.h" #include "test/common/mock_functions.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - tBTA_JV_STATUS BTA_JvCreateRecordByUser(uint32_t rfcomm_slot_id) { inc_func_call_count(__func__); return 0; diff --git a/system/test/mock/mock_bta_leaudio.cc b/system/test/mock/mock_bta_leaudio.cc index affd643435b77568464e0574b14bea2a8e88fcf4..743a10bc7e22405d26c225931c656243ddcdcc60 100644 --- a/system/test/mock/mock_bta_leaudio.cc +++ b/system/test/mock/mock_bta_leaudio.cc @@ -23,18 +23,12 @@ #include #include -#include #include -#include #include "bta/include/bta_le_audio_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - /* Empty class to satisfy compiler */ namespace bluetooth { namespace audio { @@ -80,10 +74,7 @@ bool LeAudioClient::GetAsesForStorage(const RawAddress& addr, return false; } -void LeAudioClient::Cleanup(base::Callback cleanupCb) { - std::move(cleanupCb).Run(); - inc_func_call_count(__func__); -} +void LeAudioClient::Cleanup(void) { inc_func_call_count(__func__); } LeAudioClient* LeAudioClient::Get(void) { inc_func_call_count(__func__); @@ -101,9 +92,3 @@ void LeAudioClient::Initialize( inc_func_call_count(__func__); } void LeAudioClient::DebugDump(int fd) { inc_func_call_count(__func__); } -void LeAudioClient::InitializeAudioSetConfigurationProvider() { - inc_func_call_count(__func__); -} -void LeAudioClient::CleanupAudioSetConfigurationProvider() { - inc_func_call_count(__func__); -} diff --git a/system/test/mock/mock_bta_leaudio_broadcaster.cc b/system/test/mock/mock_bta_leaudio_broadcaster.cc index 77dd25ece0b952aef8f12c6d1d5d6e405ef5a17f..2b84db285524be7ff2790cce7b915b6564b20562 100644 --- a/system/test/mock/mock_bta_leaudio_broadcaster.cc +++ b/system/test/mock/mock_bta_leaudio_broadcaster.cc @@ -18,16 +18,9 @@ #include #include -#include -#include - #include "bta/include/bta_le_audio_broadcaster_api.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void LeAudioBroadcaster::DebugDump(int) { inc_func_call_count(__func__); } void LeAudioBroadcaster::Initialize( bluetooth::le_audio::LeAudioBroadcasterCallbacks*, diff --git a/system/test/mock/mock_bta_pan_api.cc b/system/test/mock/mock_bta_pan_api.cc index fa86bbd1017c46844b532c6cfcb5625344b691b0..e7659023e84cfa94ced8c940a1c0f423d5adb7ff 100644 --- a/system/test/mock/mock_bta_pan_api.cc +++ b/system/test/mock/mock_bta_pan_api.cc @@ -20,17 +20,9 @@ */ #include -#include -#include -#include "bt_target.h" +#include "bta/include/bta_pan_api.h" #include "test/common/mock_functions.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -#include "bta/pan/bta_pan_int.h" #include "types/raw_address.h" void BTA_PanClose(uint16_t handle) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_bta_pan_ci.cc b/system/test/mock/mock_bta_pan_ci.cc index 977ea2641fc251b9dbd1a2738cb0fd28da90a3ef..98b1c3cea18d3477ad6116d9eaaf3786bb47035e 100644 --- a/system/test/mock/mock_bta_pan_ci.cc +++ b/system/test/mock/mock_bta_pan_ci.cc @@ -19,20 +19,10 @@ * Functions generated:8 */ -#include -#include - -#include "bt_target.h" -#include "bta/pan/bta_pan_int.h" -#include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - BT_HDR* bta_pan_ci_readbuf(uint16_t handle, RawAddress& src, RawAddress& dst, uint16_t* p_protocol, bool* p_ext, bool* p_forward) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_stack_btm_scn.cc b/system/test/mock/mock_bta_scn.cc similarity index 78% rename from system/test/mock/mock_stack_btm_scn.cc rename to system/test/mock/mock_bta_scn.cc index e9325b9322d02c0f0cc428fdbedfab507e3e9591..e376bdc49f2a4fc81e56440988d14ea153dd27f8 100644 --- a/system/test/mock/mock_stack_btm_scn.cc +++ b/system/test/mock/mock_bta_scn.cc @@ -20,26 +20,20 @@ */ #include -#include -#include -#include "stack/btm/btm_int_types.h" -#include "stack/include/rfcdefs.h" +#include "bta/include/bta_rfcomm_scn.h" +#include "bta/jv/bta_jv_int.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool BTM_FreeSCN(uint8_t scn) { +bool BTA_FreeSCN(uint8_t scn) { inc_func_call_count(__func__); return false; } -bool BTM_TryAllocateSCN(uint8_t scn) { +bool BTA_TryAllocateSCN(uint8_t scn) { inc_func_call_count(__func__); return false; } -uint8_t BTM_AllocateSCN(void) { +uint8_t BTA_AllocateSCN(void) { inc_func_call_count(__func__); return 0; } diff --git a/system/test/mock/mock_bta_sdp_api.cc b/system/test/mock/mock_bta_sdp_api.cc index 3a4db310ecd4de1a534d819be70bae22110f99cc..f506d7cb6870ae24857197c99e6f31c57c2fb08a 100644 --- a/system/test/mock/mock_bta_sdp_api.cc +++ b/system/test/mock/mock_bta_sdp_api.cc @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,43 +13,71 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* * Generated mock file from original source file - * Functions generated:4 + * Functions generated:5 + * + * mockcify.pl ver 0.6.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_bta_sdp_api.h" + +#include "test/common/mock_functions.h" -#include -#include +// Original usings -#include -#include +// Mocked internal structures, if any -#include "bt_target.h" -#include "bta/include/bta_sdp_api.h" -#include "bta/sdp/bta_sdp_int.h" -#include "test/common/mock_functions.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" +namespace test { +namespace mock { +namespace bta_sdp_api { + +// Function state capture and return values, if needed +struct BTA_SdpCreateRecordByUser BTA_SdpCreateRecordByUser; +struct BTA_SdpDumpsys BTA_SdpDumpsys; +struct BTA_SdpEnable BTA_SdpEnable; +struct BTA_SdpRemoveRecordByUser BTA_SdpRemoveRecordByUser; +struct BTA_SdpSearch BTA_SdpSearch; -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +} // namespace bta_sdp_api +} // namespace mock +} // namespace test +// Mocked function return values, if any +namespace test { +namespace mock { +namespace bta_sdp_api { + +tBTA_SDP_STATUS BTA_SdpCreateRecordByUser::return_value = BTA_SDP_SUCCESS; +tBTA_SDP_STATUS BTA_SdpEnable::return_value = BTA_SDP_SUCCESS; +tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser::return_value = BTA_SDP_SUCCESS; +tBTA_SDP_STATUS BTA_SdpSearch::return_value = BTA_SDP_SUCCESS; + +} // namespace bta_sdp_api +} // namespace mock +} // namespace test + +// Mocked functions, if any tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data) { inc_func_call_count(__func__); - return BTA_SDP_SUCCESS; + return test::mock::bta_sdp_api::BTA_SdpCreateRecordByUser(user_data); +} +void BTA_SdpDumpsys(int fd) { + inc_func_call_count(__func__); + test::mock::bta_sdp_api::BTA_SdpDumpsys(fd); } tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK* p_cback) { inc_func_call_count(__func__); - return BTA_SDP_SUCCESS; + return test::mock::bta_sdp_api::BTA_SdpEnable(p_cback); } tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void* user_data) { inc_func_call_count(__func__); - return BTA_SDP_SUCCESS; + return test::mock::bta_sdp_api::BTA_SdpRemoveRecordByUser(user_data); } tBTA_SDP_STATUS BTA_SdpSearch(const RawAddress& bd_addr, const bluetooth::Uuid& uuid) { inc_func_call_count(__func__); - return BTA_SDP_SUCCESS; + return test::mock::bta_sdp_api::BTA_SdpSearch(bd_addr, uuid); } +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_bta_sdp_api.h b/system/test/mock/mock_bta_sdp_api.h new file mode 100644 index 0000000000000000000000000000000000000000..24256a690ee0913b0b3a3e55fdaeb0545e3b0bbe --- /dev/null +++ b/system/test/mock/mock_bta_sdp_api.h @@ -0,0 +1,106 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:5 + * + * mockcify.pl ver 0.6.1 + */ + +#include + +// Original included files, if any +#include "bta/include/bta_sdp_api.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +// Original usings + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace bta_sdp_api { + +// Shared state between mocked functions and tests +// Name: BTA_SdpCreateRecordByUser +// Params: void* user_data +// Return: tBTA_SDP_STATUS +struct BTA_SdpCreateRecordByUser { + static tBTA_SDP_STATUS return_value; + std::function body{ + [](void* user_data) { return return_value; }}; + tBTA_SDP_STATUS operator()(void* user_data) { return body(user_data); }; +}; +extern struct BTA_SdpCreateRecordByUser BTA_SdpCreateRecordByUser; + +// Name: BTA_SdpDumpsys +// Params: int fd +// Return: void +struct BTA_SdpDumpsys { + std::function body{[](int fd) {}}; + void operator()(int fd) { body(fd); }; +}; +extern struct BTA_SdpDumpsys BTA_SdpDumpsys; + +// Name: BTA_SdpEnable +// Params: tBTA_SDP_DM_CBACK* p_cback +// Return: tBTA_SDP_STATUS +struct BTA_SdpEnable { + static tBTA_SDP_STATUS return_value; + std::function body{ + [](tBTA_SDP_DM_CBACK* p_cback) { return return_value; }}; + tBTA_SDP_STATUS operator()(tBTA_SDP_DM_CBACK* p_cback) { + return body(p_cback); + }; +}; +extern struct BTA_SdpEnable BTA_SdpEnable; + +// Name: BTA_SdpRemoveRecordByUser +// Params: void* user_data +// Return: tBTA_SDP_STATUS +struct BTA_SdpRemoveRecordByUser { + static tBTA_SDP_STATUS return_value; + std::function body{ + [](void* user_data) { return return_value; }}; + tBTA_SDP_STATUS operator()(void* user_data) { return body(user_data); }; +}; +extern struct BTA_SdpRemoveRecordByUser BTA_SdpRemoveRecordByUser; + +// Name: BTA_SdpSearch +// Params: const RawAddress& bd_addr, const bluetooth::Uuid& uuid +// Return: tBTA_SDP_STATUS +struct BTA_SdpSearch { + static tBTA_SDP_STATUS return_value; + std::function + body{[](const RawAddress& bd_addr, const bluetooth::Uuid& uuid) { + return return_value; + }}; + tBTA_SDP_STATUS operator()(const RawAddress& bd_addr, + const bluetooth::Uuid& uuid) { + return body(bd_addr, uuid); + }; +}; +extern struct BTA_SdpSearch BTA_SdpSearch; + +} // namespace bta_sdp_api +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_bta_sys_conn.cc b/system/test/mock/mock_bta_sys_conn.cc index c6b62f854b6ad38ba4cadf51190804574c489582..febd7ce9ba9bb24a8f461913f465cb4eda41b23c 100644 --- a/system/test/mock/mock_bta_sys_conn.cc +++ b/system/test/mock/mock_bta_sys_conn.cc @@ -20,50 +20,40 @@ */ #include -#include -#include -#include "bt_target.h" #include "bta/sys/bta_sys.h" -#include "bta/sys/bta_sys_int.h" -#include "main/shim/dumpsys.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "stack/include/btm_api.h" #include "test/common/mock_functions.h" #include "types/hci_role.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void bta_sys_app_close(uint8_t id, uint8_t app_id, +void bta_sys_app_close(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { inc_func_call_count(__func__); } -void bta_sys_app_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { +void bta_sys_app_open(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr) { inc_func_call_count(__func__); } -void bta_sys_busy(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { +void bta_sys_busy(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { inc_func_call_count(__func__); } -void bta_sys_chg_ssr_config(uint8_t id, uint8_t app_id, uint16_t max_latency, - uint16_t min_tout) { +void bta_sys_chg_ssr_config(tBTA_SYS_ID id, uint8_t app_id, + uint16_t max_latency, uint16_t min_tout) { inc_func_call_count(__func__); } -void bta_sys_collision_register(uint8_t bta_id, tBTA_SYS_CONN_CBACK* p_cback) { +void bta_sys_collision_register(tBTA_SYS_ID bta_id, + tBTA_SYS_CONN_CBACK* p_cback) { inc_func_call_count(__func__); } -void bta_sys_conn_close(uint8_t id, uint8_t app_id, +void bta_sys_conn_close(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { inc_func_call_count(__func__); } -void bta_sys_conn_open(uint8_t id, uint8_t app_id, +void bta_sys_conn_open(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { inc_func_call_count(__func__); } -void bta_sys_idle(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { +void bta_sys_idle(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { inc_func_call_count(__func__); } void bta_sys_notify_collision(const RawAddress& peer_addr) { @@ -82,21 +72,22 @@ void bta_sys_rm_register(tBTA_SYS_CONN_CBACK* p_cback) { void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK* p_cback) { inc_func_call_count(__func__); } -void bta_sys_sco_close(uint8_t id, uint8_t app_id, +void bta_sys_sco_close(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { inc_func_call_count(__func__); } -void bta_sys_sco_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr) { +void bta_sys_sco_open(tBTA_SYS_ID id, uint8_t app_id, + const RawAddress& peer_addr) { inc_func_call_count(__func__); } -void bta_sys_sco_register(tBTA_SYS_CONN_CBACK* p_cback) { +void bta_sys_sco_register(tBTA_SYS_CONN_SCO_CBACK* p_cback) { inc_func_call_count(__func__); } -void bta_sys_sco_unuse(uint8_t id, uint8_t app_id, +void bta_sys_sco_unuse(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { inc_func_call_count(__func__); } -void bta_sys_sco_use(UNUSED_ATTR uint8_t id, uint8_t app_id, +void bta_sys_sco_use(tBTA_SYS_ID id, uint8_t app_id, const RawAddress& peer_addr) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_bta_sys_main.cc b/system/test/mock/mock_bta_sys_main.cc index d1c3a7c00b348fb4d319d747c2daa482a1d8e255..56ae8ea8bb31bf51db480815f1187605c8006bae 100644 --- a/system/test/mock/mock_bta_sys_main.cc +++ b/system/test/mock/mock_bta_sys_main.cc @@ -21,14 +21,13 @@ * mockcify.pl ver 0.3.0 */ -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_bta_sys_main.h" +#include + +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_bta_sys_main.h b/system/test/mock/mock_bta_sys_main.h index f0d6afcce8d9f61418286162d648ded9b38e93a7..5ddf18b41d6eb3303d0d70326be59890704e97a9 100644 --- a/system/test/mock/mock_bta_sys_main.h +++ b/system/test/mock/mock_bta_sys_main.h @@ -23,30 +23,10 @@ #include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include - -#include -#include -#include - -#include "bt_target.h" #include "bta/sys/bta_sys.h" -#include "bta/sys/bta_sys_int.h" -#include "include/hardware/bluetooth.h" #include "osi/include/alarm.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_bta_sys_utl.cc b/system/test/mock/mock_bta_sys_utl.cc index bb456255bf8ecd2b96c6cd0296ca23668a864aba..a098d0770a4fbd6b199aea3b31a07b781bdc0103 100644 --- a/system/test/mock/mock_bta_sys_utl.cc +++ b/system/test/mock/mock_bta_sys_utl.cc @@ -20,18 +20,10 @@ */ #include -#include -#include -#include "bt_target.h" #include "bta/include/utl.h" -#include "stack/include/btm_api.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - bool utl_isdialchar(const char d) { inc_func_call_count(__func__); return false; diff --git a/system/test/mock/mock_bta_vc.cc b/system/test/mock/mock_bta_vc.cc index 27486877cc107948c01d0d8836091a02a9c8b894..4411d8e0e2d624013a89c120ee3f9ab6666e4f59 100644 --- a/system/test/mock/mock_bta_vc.cc +++ b/system/test/mock/mock_bta_vc.cc @@ -24,24 +24,12 @@ #include #include -#include -#include -#include - -#include "bind_helpers.h" -#include "bta/include/bta_gatt_api.h" #include "bta/include/bta_gatt_queue.h" #include "bta/include/bta_vc_api.h" -#include "btif/include/btif_storage.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void VolumeControl::AddFromStorage(const RawAddress& address, - bool auto_connect) { +void VolumeControl::AddFromStorage(const RawAddress& address) { inc_func_call_count(__func__); } void VolumeControl::CleanUp() { inc_func_call_count(__func__); } @@ -54,7 +42,7 @@ bool VolumeControl::IsVolumeControlRunning() { inc_func_call_count(__func__); return false; } -void VolumeControl::Initialize( - bluetooth::vc::VolumeControlCallbacks* callbacks) { +void VolumeControl::Initialize(bluetooth::vc::VolumeControlCallbacks* callbacks, + const base::Closure& initCb) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_bta_vc_device.cc b/system/test/mock/mock_bta_vc_device.cc index cddda754ba51fb9bdeefc694aa10dd79ac91ecce..f162d9452da4946f0c8db34d2aefd02b80aa1a82 100644 --- a/system/test/mock/mock_bta_vc_device.cc +++ b/system/test/mock/mock_bta_vc_device.cc @@ -19,8 +19,6 @@ * Functions generated:12 */ -#include -#include #include #include "bta/vc/devices.h" @@ -28,11 +26,10 @@ using namespace bluetooth::vc::internal; -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void VolumeControlDevice::EnableEncryption() { inc_func_call_count(__func__); } +bool VolumeControlDevice::EnableEncryption() { + inc_func_call_count(__func__); + return true; +} bool VolumeControlDevice::EnqueueInitialRequests( tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb, GATT_WRITE_OP_CB cccd_write_cb) { diff --git a/system/test/mock/mock_btcore_module.cc b/system/test/mock/mock_btcore_module.cc index 47211f8eee08e600865ed13a92ecce3711b3ed17..933602d1e7e724316bc2cc6a73838fb5d1fddb3b 100644 --- a/system/test/mock/mock_btcore_module.cc +++ b/system/test/mock/mock_btcore_module.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_btcore_module.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_btcore_module.h b/system/test/mock/mock_btcore_module.h index 96be2e2bf7fc5ade52b60868b56f75fc55647e2e..4111626e6d6be593c35cd4e0f5a14c479483051d 100644 --- a/system/test/mock/mock_btcore_module.h +++ b/system/test/mock/mock_btcore_module.h @@ -21,32 +21,10 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include - -#include -#include - #include "btcore/include/module.h" -#include "check.h" -#include "common/message_loop_thread.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_btif_av.cc b/system/test/mock/mock_btif_av.cc new file mode 100644 index 0000000000000000000000000000000000000000..cb939efb2414ca873ff36e60af9be368d467ec15 --- /dev/null +++ b/system/test/mock/mock_btif_av.cc @@ -0,0 +1,304 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Generated mock file from original source file + * Functions generated:43 + * + * mockcify.pl ver 0.6.0 + */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_btif_av.h" + +#include + +#include "test/common/mock_functions.h" + +// Original usings + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace btif_av { + +// Function state capture and return values, if needed +struct btif_av_acl_disconnected btif_av_acl_disconnected; +struct btif_av_clear_remote_suspend_flag btif_av_clear_remote_suspend_flag; +struct btif_av_find_by_handle btif_av_find_by_handle; +struct btif_av_get_audio_delay btif_av_get_audio_delay; +struct btif_av_get_peer_sep btif_av_get_peer_sep; +struct btif_av_get_sink_interface btif_av_get_sink_interface; +struct btif_av_get_src_interface btif_av_get_src_interface; +struct btif_av_is_a2dp_offload_enabled btif_av_is_a2dp_offload_enabled; +struct btif_av_is_a2dp_offload_running btif_av_is_a2dp_offload_running; +struct btif_av_is_connected btif_av_is_connected; +struct btif_av_is_connected_addr btif_av_is_connected_addr; +struct btif_av_is_peer_edr btif_av_is_peer_edr; +struct btif_av_is_peer_silenced btif_av_is_peer_silenced; +struct btif_av_is_sink_enabled btif_av_is_sink_enabled; +struct btif_av_is_source_enabled btif_av_is_source_enabled; +struct btif_av_peer_is_connected_sink btif_av_peer_is_connected_sink; +struct btif_av_peer_is_connected_source btif_av_peer_is_connected_source; +struct btif_av_peer_is_sink btif_av_peer_is_sink; +struct btif_av_peer_is_source btif_av_peer_is_source; +struct btif_av_peer_prefers_mandatory_codec + btif_av_peer_prefers_mandatory_codec; +struct btif_av_peer_supports_3mbps btif_av_peer_supports_3mbps; +struct btif_av_report_source_codec_state btif_av_report_source_codec_state; +struct btif_av_reset_audio_delay btif_av_reset_audio_delay; +struct btif_av_set_audio_delay btif_av_set_audio_delay; +struct btif_av_set_dynamic_audio_buffer_size + btif_av_set_dynamic_audio_buffer_size; +struct btif_av_set_low_latency btif_av_set_low_latency; +struct btif_av_sink_active_peer btif_av_sink_active_peer; +struct btif_av_sink_execute_service btif_av_sink_execute_service; +struct btif_av_source_active_peer btif_av_source_active_peer; +struct btif_av_source_execute_service btif_av_source_execute_service; +struct btif_av_src_disconnect_sink btif_av_src_disconnect_sink; +struct btif_av_src_sink_coexist_enabled btif_av_src_sink_coexist_enabled; +struct btif_av_stream_ready btif_av_stream_ready; +struct btif_av_stream_start btif_av_stream_start; +struct btif_av_stream_start_offload btif_av_stream_start_offload; +struct btif_av_stream_start_with_latency btif_av_stream_start_with_latency; +struct btif_av_stream_started_ready btif_av_stream_started_ready; +struct btif_av_stream_stop btif_av_stream_stop; +struct btif_av_stream_suspend btif_av_stream_suspend; +struct btif_debug_av_dump btif_debug_av_dump; +struct dump_av_sm_event_name dump_av_sm_event_name; +struct src_do_suspend_in_main_thread src_do_suspend_in_main_thread; + +} // namespace btif_av +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace btif_av { + +const RawAddress& btif_av_find_by_handle::return_value = RawAddress::kEmpty; +uint16_t btif_av_get_audio_delay::return_value = 0; +uint8_t btif_av_get_peer_sep::return_value = 0; +const btav_sink_interface_t* btif_av_get_sink_interface::return_value = nullptr; +const btav_source_interface_t* btif_av_get_src_interface::return_value = + nullptr; +bool btif_av_is_a2dp_offload_enabled::return_value = false; +bool btif_av_is_a2dp_offload_running::return_value = false; +bool btif_av_is_connected::return_value = false; +bool btif_av_is_connected_addr::return_value = false; +bool btif_av_is_peer_edr::return_value = false; +bool btif_av_is_peer_silenced::return_value = false; +bool btif_av_is_sink_enabled::return_value = false; +bool btif_av_is_source_enabled::return_value = false; +bool btif_av_peer_is_connected_sink::return_value = false; +bool btif_av_peer_is_connected_source::return_value = false; +bool btif_av_peer_is_sink::return_value = false; +bool btif_av_peer_is_source::return_value = false; +bool btif_av_peer_prefers_mandatory_codec::return_value = false; +bool btif_av_peer_supports_3mbps::return_value = false; +RawAddress btif_av_sink_active_peer::return_value; +bt_status_t btif_av_sink_execute_service::return_value = BT_STATUS_SUCCESS; +RawAddress btif_av_source_active_peer::return_value; +bt_status_t btif_av_source_execute_service::return_value = BT_STATUS_SUCCESS; +bool btif_av_src_sink_coexist_enabled::return_value = false; +bool btif_av_stream_ready::return_value = false; +bool btif_av_stream_started_ready::return_value = false; +const char* dump_av_sm_event_name::return_value = nullptr; + +} // namespace btif_av +} // namespace mock +} // namespace test + +// Mocked functions, if any +void btif_av_acl_disconnected(const RawAddress& peer_address) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_acl_disconnected(peer_address); +} +void btif_av_clear_remote_suspend_flag(void) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_clear_remote_suspend_flag(); +} +const RawAddress& btif_av_find_by_handle(tBTA_AV_HNDL bta_handle) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_find_by_handle(bta_handle); +} +uint16_t btif_av_get_audio_delay() { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_get_audio_delay(); +} +uint8_t btif_av_get_peer_sep(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_get_peer_sep(); +} +const btav_sink_interface_t* btif_av_get_sink_interface(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_get_sink_interface(); +} +const btav_source_interface_t* btif_av_get_src_interface(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_get_src_interface(); +} +bool btif_av_is_a2dp_offload_enabled() { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_is_a2dp_offload_enabled(); +} +bool btif_av_is_a2dp_offload_running() { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_is_a2dp_offload_running(); +} +bool btif_av_is_connected(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_is_connected(); +} +bool btif_av_is_connected_addr(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_is_connected_addr(peer_address); +} +bool btif_av_is_peer_edr(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_is_peer_edr(peer_address); +} +bool btif_av_is_peer_silenced(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_is_peer_silenced(peer_address); +} +bool btif_av_is_sink_enabled(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_is_sink_enabled(); +} +bool btif_av_is_source_enabled(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_is_source_enabled(); +} +bool btif_av_peer_is_connected_sink(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_peer_is_connected_sink(peer_address); +} +bool btif_av_peer_is_connected_source(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_peer_is_connected_source(peer_address); +} +bool btif_av_peer_is_sink(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_peer_is_sink(peer_address); +} +bool btif_av_peer_is_source(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_peer_is_source(peer_address); +} +bool btif_av_peer_prefers_mandatory_codec(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_peer_prefers_mandatory_codec( + peer_address); +} +bool btif_av_peer_supports_3mbps(const RawAddress& peer_address) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_peer_supports_3mbps(peer_address); +} +void btif_av_report_source_codec_state( + const RawAddress& peer_address, + const btav_a2dp_codec_config_t& codec_config, + const std::vector& codecs_local_capabilities, + const std::vector& + codecs_selectable_capabilities) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_report_source_codec_state( + peer_address, codec_config, codecs_local_capabilities, + codecs_selectable_capabilities); +} +void btif_av_reset_audio_delay(void) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_reset_audio_delay(); +} +void btif_av_set_audio_delay(const RawAddress& peer_address, uint16_t delay) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_set_audio_delay(peer_address, delay); +} +void btif_av_set_dynamic_audio_buffer_size(uint8_t dynamic_audio_buffer_size) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_set_dynamic_audio_buffer_size( + dynamic_audio_buffer_size); +} +void btif_av_set_low_latency(bool is_low_latency) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_set_low_latency(is_low_latency); +} +RawAddress btif_av_sink_active_peer(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_sink_active_peer(); +} +bt_status_t btif_av_sink_execute_service(bool enable) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_sink_execute_service(enable); +} +RawAddress btif_av_source_active_peer(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_source_active_peer(); +} +bt_status_t btif_av_source_execute_service(bool enable) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_source_execute_service(enable); +} +void btif_av_src_disconnect_sink(const RawAddress& peer_address) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_src_disconnect_sink(peer_address); +} +bool btif_av_src_sink_coexist_enabled(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_src_sink_coexist_enabled(); +} +bool btif_av_stream_ready(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_stream_ready(); +} +void btif_av_stream_start(void) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_stream_start(); +} +void btif_av_stream_start_offload(void) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_stream_start_offload(); +} +void btif_av_stream_start_with_latency(bool use_latency_mode) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_stream_start_with_latency(use_latency_mode); +} +bool btif_av_stream_started_ready(void) { + inc_func_call_count(__func__); + return test::mock::btif_av::btif_av_stream_started_ready(); +} +void btif_av_stream_stop(const RawAddress& peer_address) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_stream_stop(peer_address); +} +void btif_av_stream_suspend(void) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_av_stream_suspend(); +} +void btif_debug_av_dump(int fd) { + inc_func_call_count(__func__); + test::mock::btif_av::btif_debug_av_dump(fd); +} +const char* dump_av_sm_event_name(int event) { + inc_func_call_count(__func__); + return test::mock::btif_av::dump_av_sm_event_name(event); +} +void src_do_suspend_in_main_thread(btif_av_sm_event_t event) { + inc_func_call_count(__func__); + test::mock::btif_av::src_do_suspend_in_main_thread(event); +} +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_btif_av.h b/system/test/mock/mock_btif_av.h new file mode 100644 index 0000000000000000000000000000000000000000..ee2fa23a1f530856f0d741748145b3b3391eed36 --- /dev/null +++ b/system/test/mock/mock_btif_av.h @@ -0,0 +1,538 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:43 + * + * mockcify.pl ver 0.6.0 + */ + +#include +#include + +// Original included files, if any + +#include "bta/include/bta_av_api.h" +#include "include/hardware/bt_av.h" +#include "types/raw_address.h" + +// Original usings +typedef enum { + /* Reuse BTA_AV_XXX_EVT - No need to redefine them here */ + BTIF_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT, + BTIF_AV_DISCONNECT_REQ_EVT, + BTIF_AV_START_STREAM_REQ_EVT, + BTIF_AV_STOP_STREAM_REQ_EVT, + BTIF_AV_SUSPEND_STREAM_REQ_EVT, + BTIF_AV_SINK_CONFIG_REQ_EVT, + BTIF_AV_ACL_DISCONNECTED, + BTIF_AV_OFFLOAD_START_REQ_EVT, + BTIF_AV_AVRCP_OPEN_EVT, + BTIF_AV_AVRCP_CLOSE_EVT, + BTIF_AV_AVRCP_REMOTE_PLAY_EVT, + BTIF_AV_SET_LATENCY_REQ_EVT, +} btif_av_sm_event_t; + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace btif_av { + +// Shared state between mocked functions and tests +// Name: btif_av_acl_disconnected +// Params: const RawAddress& peer_address +// Return: void +struct btif_av_acl_disconnected { + std::function body{ + [](const RawAddress& peer_address) {}}; + void operator()(const RawAddress& peer_address) { body(peer_address); }; +}; +extern struct btif_av_acl_disconnected btif_av_acl_disconnected; + +// Name: btif_av_clear_remote_suspend_flag +// Params: void +// Return: void +struct btif_av_clear_remote_suspend_flag { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btif_av_clear_remote_suspend_flag + btif_av_clear_remote_suspend_flag; + +// Name: btif_av_find_by_handle +// Params: tBTA_AV_HNDL bta_handle +// Return: const RawAddress& +struct btif_av_find_by_handle { + static const RawAddress& return_value; + std::function body{ + [](tBTA_AV_HNDL bta_handle) { return return_value; }}; + const RawAddress& operator()(tBTA_AV_HNDL bta_handle) { + return body(bta_handle); + }; +}; +extern struct btif_av_find_by_handle btif_av_find_by_handle; + +// Name: btif_av_get_audio_delay +// Params: +// Return: uint16_t +struct btif_av_get_audio_delay { + static uint16_t return_value; + std::function body{[]() { return return_value; }}; + uint16_t operator()() { return body(); }; +}; +extern struct btif_av_get_audio_delay btif_av_get_audio_delay; + +// Name: btif_av_get_peer_sep +// Params: void +// Return: uint8_t +struct btif_av_get_peer_sep { + static uint8_t return_value; + std::function body{[](void) { return return_value; }}; + uint8_t operator()(void) { return body(); }; +}; +extern struct btif_av_get_peer_sep btif_av_get_peer_sep; + +// Name: btif_av_get_sink_interface +// Params: void +// Return: const btav_sink_interface_t* +struct btif_av_get_sink_interface { + static const btav_sink_interface_t* return_value; + std::function body{ + [](void) { return return_value; }}; + const btav_sink_interface_t* operator()(void) { return body(); }; +}; +extern struct btif_av_get_sink_interface btif_av_get_sink_interface; + +// Name: btif_av_get_src_interface +// Params: void +// Return: const btav_source_interface_t* +struct btif_av_get_src_interface { + static const btav_source_interface_t* return_value; + std::function body{ + [](void) { return return_value; }}; + const btav_source_interface_t* operator()(void) { return body(); }; +}; +extern struct btif_av_get_src_interface btif_av_get_src_interface; + +// Name: btif_av_is_a2dp_offload_enabled +// Params: +// Return: bool +struct btif_av_is_a2dp_offload_enabled { + static bool return_value; + std::function body{[]() { return return_value; }}; + bool operator()() { return body(); }; +}; +extern struct btif_av_is_a2dp_offload_enabled btif_av_is_a2dp_offload_enabled; + +// Name: btif_av_is_a2dp_offload_running +// Params: +// Return: bool +struct btif_av_is_a2dp_offload_running { + static bool return_value; + std::function body{[]() { return return_value; }}; + bool operator()() { return body(); }; +}; +extern struct btif_av_is_a2dp_offload_running btif_av_is_a2dp_offload_running; + +// Name: btif_av_is_connected +// Params: void +// Return: bool +struct btif_av_is_connected { + static bool return_value; + std::function body{[](void) { return return_value; }}; + bool operator()(void) { return body(); }; +}; +extern struct btif_av_is_connected btif_av_is_connected; + +// Name: btif_av_is_connected_addr +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_is_connected_addr { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_is_connected_addr btif_av_is_connected_addr; + +// Name: btif_av_is_peer_edr +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_is_peer_edr { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_is_peer_edr btif_av_is_peer_edr; + +// Name: btif_av_is_peer_silenced +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_is_peer_silenced { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_is_peer_silenced btif_av_is_peer_silenced; + +// Name: btif_av_is_sink_enabled +// Params: void +// Return: bool +struct btif_av_is_sink_enabled { + static bool return_value; + std::function body{[](void) { return return_value; }}; + bool operator()(void) { return body(); }; +}; +extern struct btif_av_is_sink_enabled btif_av_is_sink_enabled; + +// Name: btif_av_is_source_enabled +// Params: void +// Return: bool +struct btif_av_is_source_enabled { + static bool return_value; + std::function body{[](void) { return return_value; }}; + bool operator()(void) { return body(); }; +}; +extern struct btif_av_is_source_enabled btif_av_is_source_enabled; + +// Name: btif_av_peer_is_connected_sink +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_peer_is_connected_sink { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_peer_is_connected_sink btif_av_peer_is_connected_sink; + +// Name: btif_av_peer_is_connected_source +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_peer_is_connected_source { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_peer_is_connected_source btif_av_peer_is_connected_source; + +// Name: btif_av_peer_is_sink +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_peer_is_sink { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_peer_is_sink btif_av_peer_is_sink; + +// Name: btif_av_peer_is_source +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_peer_is_source { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_peer_is_source btif_av_peer_is_source; + +// Name: btif_av_peer_prefers_mandatory_codec +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_peer_prefers_mandatory_codec { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_peer_prefers_mandatory_codec + btif_av_peer_prefers_mandatory_codec; + +// Name: btif_av_peer_supports_3mbps +// Params: const RawAddress& peer_address +// Return: bool +struct btif_av_peer_supports_3mbps { + static bool return_value; + std::function body{ + [](const RawAddress& peer_address) { return return_value; }}; + bool operator()(const RawAddress& peer_address) { + return body(peer_address); + }; +}; +extern struct btif_av_peer_supports_3mbps btif_av_peer_supports_3mbps; + +// Name: btif_av_report_source_codec_state +// Params: const RawAddress& peer_address, const btav_a2dp_codec_config_t& +// codec_config, const std::vector& +// codecs_local_capabilities, const std::vector& +// codecs_selectable_capabilities Return: void +struct btif_av_report_source_codec_state { + std::function& codecs_local_capabilities, + const std::vector& + codecs_selectable_capabilities)> + body{[](const RawAddress& peer_address, + const btav_a2dp_codec_config_t& codec_config, + const std::vector& + codecs_local_capabilities, + const std::vector& + codecs_selectable_capabilities) {}}; + void operator()( + const RawAddress& peer_address, + const btav_a2dp_codec_config_t& codec_config, + const std::vector& codecs_local_capabilities, + const std::vector& + codecs_selectable_capabilities) { + body(peer_address, codec_config, codecs_local_capabilities, + codecs_selectable_capabilities); + }; +}; +extern struct btif_av_report_source_codec_state + btif_av_report_source_codec_state; + +// Name: btif_av_reset_audio_delay +// Params: void +// Return: void +struct btif_av_reset_audio_delay { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btif_av_reset_audio_delay btif_av_reset_audio_delay; + +// Name: btif_av_set_audio_delay +// Params: const RawAddress& peer_address, uint16_t delay +// Return: void +struct btif_av_set_audio_delay { + std::function body{ + [](const RawAddress& peer_address, uint16_t delay) {}}; + void operator()(const RawAddress& peer_address, uint16_t delay) { + body(peer_address, delay); + }; +}; +extern struct btif_av_set_audio_delay btif_av_set_audio_delay; + +// Name: btif_av_set_dynamic_audio_buffer_size +// Params: uint8_t dynamic_audio_buffer_size +// Return: void +struct btif_av_set_dynamic_audio_buffer_size { + std::function body{ + [](uint8_t dynamic_audio_buffer_size) {}}; + void operator()(uint8_t dynamic_audio_buffer_size) { + body(dynamic_audio_buffer_size); + }; +}; +extern struct btif_av_set_dynamic_audio_buffer_size + btif_av_set_dynamic_audio_buffer_size; + +// Name: btif_av_set_low_latency +// Params: bool is_low_latency +// Return: void +struct btif_av_set_low_latency { + std::function body{[](bool is_low_latency) {}}; + void operator()(bool is_low_latency) { body(is_low_latency); }; +}; +extern struct btif_av_set_low_latency btif_av_set_low_latency; + +// Name: btif_av_sink_active_peer +// Params: void +// Return: RawAddress +struct btif_av_sink_active_peer { + static RawAddress return_value; + std::function body{[](void) { return return_value; }}; + RawAddress operator()(void) { return body(); }; +}; +extern struct btif_av_sink_active_peer btif_av_sink_active_peer; + +// Name: btif_av_sink_execute_service +// Params: bool enable +// Return: bt_status_t +struct btif_av_sink_execute_service { + static bt_status_t return_value; + std::function body{ + [](bool enable) { return return_value; }}; + bt_status_t operator()(bool enable) { return body(enable); }; +}; +extern struct btif_av_sink_execute_service btif_av_sink_execute_service; + +// Name: btif_av_source_active_peer +// Params: void +// Return: RawAddress +struct btif_av_source_active_peer { + static RawAddress return_value; + std::function body{[](void) { return return_value; }}; + RawAddress operator()(void) { return body(); }; +}; +extern struct btif_av_source_active_peer btif_av_source_active_peer; + +// Name: btif_av_source_execute_service +// Params: bool enable +// Return: bt_status_t +struct btif_av_source_execute_service { + static bt_status_t return_value; + std::function body{ + [](bool enable) { return return_value; }}; + bt_status_t operator()(bool enable) { return body(enable); }; +}; +extern struct btif_av_source_execute_service btif_av_source_execute_service; + +// Name: btif_av_src_disconnect_sink +// Params: const RawAddress& peer_address +// Return: void +struct btif_av_src_disconnect_sink { + std::function body{ + [](const RawAddress& peer_address) {}}; + void operator()(const RawAddress& peer_address) { body(peer_address); }; +}; +extern struct btif_av_src_disconnect_sink btif_av_src_disconnect_sink; + +// Name: btif_av_src_sink_coexist_enabled +// Params: void +// Return: bool +struct btif_av_src_sink_coexist_enabled { + static bool return_value; + std::function body{[](void) { return return_value; }}; + bool operator()(void) { return body(); }; +}; +extern struct btif_av_src_sink_coexist_enabled btif_av_src_sink_coexist_enabled; + +// Name: btif_av_stream_ready +// Params: void +// Return: bool +struct btif_av_stream_ready { + static bool return_value; + std::function body{[](void) { return return_value; }}; + bool operator()(void) { return body(); }; +}; +extern struct btif_av_stream_ready btif_av_stream_ready; + +// Name: btif_av_stream_start +// Params: void +// Return: void +struct btif_av_stream_start { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btif_av_stream_start btif_av_stream_start; + +// Name: btif_av_stream_start_offload +// Params: void +// Return: void +struct btif_av_stream_start_offload { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btif_av_stream_start_offload btif_av_stream_start_offload; + +// Name: btif_av_stream_start_with_latency +// Params: bool use_latency_mode +// Return: void +struct btif_av_stream_start_with_latency { + std::function body{[](bool use_latency_mode) {}}; + void operator()(bool use_latency_mode) { body(use_latency_mode); }; +}; +extern struct btif_av_stream_start_with_latency + btif_av_stream_start_with_latency; + +// Name: btif_av_stream_started_ready +// Params: void +// Return: bool +struct btif_av_stream_started_ready { + static bool return_value; + std::function body{[](void) { return return_value; }}; + bool operator()(void) { return body(); }; +}; +extern struct btif_av_stream_started_ready btif_av_stream_started_ready; + +// Name: btif_av_stream_stop +// Params: const RawAddress& peer_address +// Return: void +struct btif_av_stream_stop { + std::function body{ + [](const RawAddress& peer_address) {}}; + void operator()(const RawAddress& peer_address) { body(peer_address); }; +}; +extern struct btif_av_stream_stop btif_av_stream_stop; + +// Name: btif_av_stream_suspend +// Params: void +// Return: void +struct btif_av_stream_suspend { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btif_av_stream_suspend btif_av_stream_suspend; + +// Name: btif_debug_av_dump +// Params: int fd +// Return: void +struct btif_debug_av_dump { + std::function body{[](int fd) {}}; + void operator()(int fd) { body(fd); }; +}; +extern struct btif_debug_av_dump btif_debug_av_dump; + +// Name: dump_av_sm_event_name +// Params: int event +// Return: const char* +struct dump_av_sm_event_name { + static const char* return_value; + std::function body{ + [](int event) { return return_value; }}; + const char* operator()(int event) { return body(event); }; +}; +extern struct dump_av_sm_event_name dump_av_sm_event_name; + +// Name: src_do_suspend_in_main_thread +// Params: btif_av_sm_event_t event +// Return: void +struct src_do_suspend_in_main_thread { + std::function body{ + [](btif_av_sm_event_t event) {}}; + void operator()(btif_av_sm_event_t event) { body(event); }; +}; +extern struct src_do_suspend_in_main_thread src_do_suspend_in_main_thread; + +} // namespace btif_av +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_btif_avrcp_service.cc b/system/test/mock/mock_btif_avrcp_service.cc index a3dbc213dcc3f3ff3ee407cc71d6248e694ab91d..bb1d1131fca3bd1b50c2c3cf4bad2337756a7509 100644 --- a/system/test/mock/mock_btif_avrcp_service.cc +++ b/system/test/mock/mock_btif_avrcp_service.cc @@ -20,13 +20,11 @@ * mockcify.pl ver 0.5.0 */ -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_btif_avrcp_service.h" + +#include "btif/avrcp/avrcp_service.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Original usings diff --git a/system/test/mock/mock_btif_avrcp_service.h b/system/test/mock/mock_btif_avrcp_service.h index f9e55eb11aea35e09c00bb23a36330ffdd1d5abd..3ba33f735c78d1caeed1e1b877fc250c799f1a31 100644 --- a/system/test/mock/mock_btif_avrcp_service.h +++ b/system/test/mock/mock_btif_avrcp_service.h @@ -22,23 +22,11 @@ * mockcify.pl ver 0.5.0 */ -#include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include -#include "btif/avrcp/avrcp_service.h" - // Original usings // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_btif_bluetooth.cc b/system/test/mock/mock_btif_bluetooth.cc index e9a6a8188ee418e8904800c4f5b9bd0fea72e847..f293d9d46d0854aac0f28f1e0391a896914c72c1 100644 --- a/system/test/mock/mock_btif_bluetooth.cc +++ b/system/test/mock/mock_btif_bluetooth.cc @@ -20,21 +20,15 @@ * * mockcify.pl ver 0.2.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_btif_bluetooth.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_btif_bluetooth.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -45,11 +39,14 @@ namespace btif_bluetooth { struct is_atv_device is_atv_device; struct is_common_criteria_mode is_common_criteria_mode; struct is_restricted_mode is_restricted_mode; +struct dut_mode_configure dut_mode_configure; +struct dut_mode_send dut_mode_send; struct get_common_criteria_config_compare_result get_common_criteria_config_compare_result; struct get_remote_device_properties get_remote_device_properties; struct get_remote_device_property get_remote_device_property; struct get_remote_services get_remote_services; +struct le_test_mode le_test_mode; struct set_remote_device_property set_remote_device_property; struct set_hal_cbacks set_hal_cbacks; @@ -70,6 +67,14 @@ bool is_restricted_mode() { inc_func_call_count(__func__); return test::mock::btif_bluetooth::is_restricted_mode(); } +int dut_mode_configure(uint8_t enable) { + inc_func_call_count(__func__); + return test::mock::btif_bluetooth::dut_mode_configure(enable); +} +int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) { + inc_func_call_count(__func__); + return test::mock::btif_bluetooth::dut_mode_send(opcode, buf, len); +} int get_common_criteria_config_compare_result() { inc_func_call_count(__func__); return test::mock::btif_bluetooth:: @@ -89,6 +94,10 @@ int get_remote_services(RawAddress* remote_addr) { inc_func_call_count(__func__); return test::mock::btif_bluetooth::get_remote_services(remote_addr); } +int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) { + inc_func_call_count(__func__); + return test::mock::btif_bluetooth::le_test_mode(opcode, buf, len); +} int set_remote_device_property(RawAddress* remote_addr, const bt_property_t* property) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_btif_bluetooth.h b/system/test/mock/mock_btif_bluetooth.h index a272a4ffa5d3b7f82900b7d24f7c6a90040b3bc7..4b9479d9e485a24c2731384a870f5cc1d208dfc7 100644 --- a/system/test/mock/mock_btif_bluetooth.h +++ b/system/test/mock/mock_btif_bluetooth.h @@ -23,25 +23,12 @@ #include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. #include "include/hardware/bluetooth.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace btif_bluetooth { @@ -71,6 +58,25 @@ struct is_restricted_mode { bool operator()() { return body(); }; }; extern struct is_restricted_mode is_restricted_mode; +// Name: dut_mode_configure +// Params: uint8_t enable +// Returns: int +struct dut_mode_configure { + std::function body{[](uint8_t enable) { return 0; }}; + int operator()(uint8_t enable) { return body(enable); }; +}; +extern struct dut_mode_configure dut_mode_configure; +// Name: dut_mode_send +// Params: uint16_t opcode, uint8_t* buf, uint8_t len +// Returns: int +struct dut_mode_send { + std::function body{ + [](uint16_t opcode, uint8_t* buf, uint8_t len) { return 0; }}; + int operator()(uint16_t opcode, uint8_t* buf, uint8_t len) { + return body(opcode, buf, len); + }; +}; +extern struct dut_mode_send dut_mode_send; // Name: get_common_criteria_config_compare_result // Params: // Returns: int @@ -109,6 +115,17 @@ struct get_remote_services { int operator()(RawAddress* remote_addr) { return body(remote_addr); }; }; extern struct get_remote_services get_remote_services; +// Name: le_test_mode +// Params: uint16_t opcode, uint8_t* buf, uint8_t len +// Returns: int +struct le_test_mode { + std::function body{ + [](uint16_t opcode, uint8_t* buf, uint8_t len) { return 0; }}; + int operator()(uint16_t opcode, uint8_t* buf, uint8_t len) { + return body(opcode, buf, len); + }; +}; +extern struct le_test_mode le_test_mode; // Name: set_remote_device_property // Params: RawAddress* remote_addr, const bt_property_t* property // Returns: int diff --git a/system/test/mock/mock_btif_bqr.cc b/system/test/mock/mock_btif_bqr.cc index ad68ff5dae72e4e6cf9a97f092ea3f7316e026ce..8e2ffb38ba0deb536efbe8c03fed4ba131aebb66 100644 --- a/system/test/mock/mock_btif_bqr.cc +++ b/system/test/mock/mock_btif_bqr.cc @@ -20,8 +20,6 @@ */ #include -#include -#include #include "test/common/mock_functions.h" diff --git a/system/test/mock/mock_btif_bta_pan_co_rx.cc b/system/test/mock/mock_btif_bta_pan_co_rx.cc index 6aa269dbe082e7c3cb0d3d693c5c7b627a3b6336..3a4874eac06f5a2b0e33e1625df25aa220ca7c6b 100644 --- a/system/test/mock/mock_btif_bta_pan_co_rx.cc +++ b/system/test/mock/mock_btif_bta_pan_co_rx.cc @@ -20,20 +20,14 @@ * * mockcify.pl ver 0.2.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_btif_bta_pan_co_rx.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_btif_bta_pan_co_rx.h" +#include "test/common/mock_functions.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -62,31 +56,25 @@ void bta_pan_co_close(uint16_t handle, uint8_t app_id) { inc_func_call_count(__func__); test::mock::btif_bta_pan_co_rx::bta_pan_co_close(handle, app_id); } -void bta_pan_co_mfilt_ind(UNUSED_ATTR uint16_t handle, - UNUSED_ATTR bool indication, - UNUSED_ATTR tBTA_PAN_STATUS result, - UNUSED_ATTR uint16_t len, - UNUSED_ATTR uint8_t* p_filters) { +void bta_pan_co_mfilt_ind(uint16_t handle, bool indication, + tBTA_PAN_STATUS result, uint16_t len, + uint8_t* p_filters) { inc_func_call_count(__func__); test::mock::btif_bta_pan_co_rx::bta_pan_co_mfilt_ind(handle, indication, result, len, p_filters); } -void bta_pan_co_pfilt_ind(UNUSED_ATTR uint16_t handle, - UNUSED_ATTR bool indication, - UNUSED_ATTR tBTA_PAN_STATUS result, - UNUSED_ATTR uint16_t len, - UNUSED_ATTR uint8_t* p_filters) { +void bta_pan_co_pfilt_ind(uint16_t handle, bool indication, + tBTA_PAN_STATUS result, uint16_t len, + uint8_t* p_filters) { inc_func_call_count(__func__); test::mock::btif_bta_pan_co_rx::bta_pan_co_pfilt_ind(handle, indication, result, len, p_filters); } -void bta_pan_co_rx_flow(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id, - UNUSED_ATTR bool enable) { +void bta_pan_co_rx_flow(uint16_t handle, uint8_t app_id, bool enable) { inc_func_call_count(__func__); test::mock::btif_bta_pan_co_rx::bta_pan_co_rx_flow(handle, app_id, enable); } -void bta_pan_co_rx_path(UNUSED_ATTR uint16_t handle, - UNUSED_ATTR uint8_t app_id) { +void bta_pan_co_rx_path(uint16_t handle, uint8_t app_id) { inc_func_call_count(__func__); test::mock::btif_bta_pan_co_rx::bta_pan_co_rx_path(handle, app_id); } diff --git a/system/test/mock/mock_btif_bta_pan_co_rx.h b/system/test/mock/mock_btif_bta_pan_co_rx.h index e56ac60b70c8b86fb2e9e7b2f5bba7442d7e76cb..9f5e90e45c09696e550e4bcdf8946c339a7ef4b7 100644 --- a/system/test/mock/mock_btif_bta_pan_co_rx.h +++ b/system/test/mock/mock_btif_bta_pan_co_rx.h @@ -23,29 +23,10 @@ #include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include -#include -#include -#include - #include "bta/include/bta_pan_api.h" -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace btif_bta_pan_co_rx { @@ -70,64 +51,53 @@ struct bta_pan_co_close { }; extern struct bta_pan_co_close bta_pan_co_close; // Name: bta_pan_co_mfilt_ind -// Params: UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool indication, UNUSED_ATTR -// tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len, UNUSED_ATTR uint8_t* +// Params: uint16_t handle, bool indication, +// tBTA_PAN_STATUS result, uint16_t len, uint8_t* // p_filters Returns: void struct bta_pan_co_mfilt_ind { - std::function - body{[](UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool indication, - UNUSED_ATTR tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len, - UNUSED_ATTR uint8_t* p_filters) { ; }}; - void operator()(UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool indication, - UNUSED_ATTR tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len, - UNUSED_ATTR uint8_t* p_filters) { + std::function + body{[](uint16_t handle, bool indication, tBTA_PAN_STATUS result, + uint16_t len, uint8_t* p_filters) { ; }}; + void operator()(uint16_t handle, bool indication, tBTA_PAN_STATUS result, + uint16_t len, uint8_t* p_filters) { body(handle, indication, result, len, p_filters); }; }; extern struct bta_pan_co_mfilt_ind bta_pan_co_mfilt_ind; // Name: bta_pan_co_pfilt_ind -// Params: UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool indication, UNUSED_ATTR -// tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len, UNUSED_ATTR uint8_t* +// Params: uint16_t handle, bool indication, +// tBTA_PAN_STATUS result, uint16_t len, uint8_t* // p_filters Returns: void struct bta_pan_co_pfilt_ind { - std::function - body{[](UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool indication, - UNUSED_ATTR tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len, - UNUSED_ATTR uint8_t* p_filters) { ; }}; - void operator()(UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool indication, - UNUSED_ATTR tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len, - UNUSED_ATTR uint8_t* p_filters) { + std::function + body{[](uint16_t handle, bool indication, tBTA_PAN_STATUS result, + uint16_t len, uint8_t* p_filters) { ; }}; + void operator()(uint16_t handle, bool indication, tBTA_PAN_STATUS result, + uint16_t len, uint8_t* p_filters) { body(handle, indication, result, len, p_filters); }; }; extern struct bta_pan_co_pfilt_ind bta_pan_co_pfilt_ind; // Name: bta_pan_co_rx_flow -// Params: UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id, UNUSED_ATTR +// Params: uint16_t handle, uint8_t app_id, // bool enable Returns: void struct bta_pan_co_rx_flow { - std::function - body{[](UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id, - UNUSED_ATTR bool enable) { ; }}; - void operator()(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id, - UNUSED_ATTR bool enable) { + std::function body{ + [](uint16_t handle, uint8_t app_id, bool enable) { ; }}; + void operator()(uint16_t handle, uint8_t app_id, bool enable) { body(handle, app_id, enable); }; }; extern struct bta_pan_co_rx_flow bta_pan_co_rx_flow; // Name: bta_pan_co_rx_path -// Params: UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id +// Params: uint16_t handle, uint8_t app_id // Returns: void struct bta_pan_co_rx_path { - std::function - body{[](UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id) { ; }}; - void operator()(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id) { - body(handle, app_id); - }; + std::function body{ + [](uint16_t handle, uint8_t app_id) { ; }}; + void operator()(uint16_t handle, uint8_t app_id) { body(handle, app_id); }; }; extern struct bta_pan_co_rx_path bta_pan_co_rx_path; // Name: bta_pan_co_tx_path diff --git a/system/test/mock/mock_btif_co_bta_av_co.cc b/system/test/mock/mock_btif_co_bta_av_co.cc index 15612db9867ffc6d4cfeb248a1dcc5c35705913a..1cbad4fc1342cc7f61a42df177a1bc5bfe5c7823 100644 --- a/system/test/mock/mock_btif_co_bta_av_co.cc +++ b/system/test/mock/mock_btif_co_bta_av_co.cc @@ -20,14 +20,13 @@ * mockcify.pl ver 0.5.0 */ -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_btif_co_bta_av_co.h" +#include + +#include "test/common/mock_functions.h" + // Original usings // Mocked internal structures, if any @@ -49,7 +48,6 @@ struct bta_av_co_audio_source_data_path bta_av_co_audio_source_data_path; struct bta_av_co_audio_start bta_av_co_audio_start; struct bta_av_co_audio_stop bta_av_co_audio_stop; struct bta_av_co_audio_update_mtu bta_av_co_audio_update_mtu; -struct bta_av_co_get_decoder_interface bta_av_co_get_decoder_interface; struct bta_av_co_get_encoder_effective_frame_size bta_av_co_get_encoder_effective_frame_size; struct bta_av_co_get_encoder_interface bta_av_co_get_encoder_interface; @@ -76,8 +74,6 @@ namespace btif_co_bta_av_co { tA2DP_STATUS bta_av_co_audio_getconfig::return_value = 0; bool bta_av_co_audio_init::return_value = false; BT_HDR* bta_av_co_audio_source_data_path::return_value = nullptr; -const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface::return_value = - nullptr; int bta_av_co_get_encoder_effective_frame_size::return_value = 0; const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface::return_value = nullptr; @@ -180,10 +176,6 @@ void bta_av_co_audio_update_mtu(tBTA_AV_HNDL bta_av_handle, test::mock::btif_co_bta_av_co::bta_av_co_audio_update_mtu(bta_av_handle, peer_address, mtu); } -const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) { - inc_func_call_count(__func__); - return test::mock::btif_co_bta_av_co::bta_av_co_get_decoder_interface(); -} int bta_av_co_get_encoder_effective_frame_size() { inc_func_call_count(__func__); return test::mock::btif_co_bta_av_co:: diff --git a/system/test/mock/mock_btif_co_bta_av_co.h b/system/test/mock/mock_btif_co_bta_av_co.h index 9f977ce53fcaae5a5cbad626122c3f7c08c913f7..82783bcafa41ab328e58b1fd664989488262e895 100644 --- a/system/test/mock/mock_btif_co_bta_av_co.h +++ b/system/test/mock/mock_btif_co_bta_av_co.h @@ -24,34 +24,16 @@ #include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include - -#include #include -#include "bt_target.h" #include "bta/include/bta_av_api.h" -#include "bta/include/bta_av_ci.h" -#include "btif/include/btif_a2dp_source.h" -#include "btif/include/btif_av.h" #include "include/hardware/bt_av.h" -#include "osi/include/osi.h" #include "stack/include/a2dp_codec_api.h" #include "stack/include/a2dp_error_codes.h" #include "stack/include/avdt_api.h" #include "stack/include/bt_hdr.h" -#include "types/bluetooth/uuid.h" #include "types/raw_address.h" // Original usings @@ -260,17 +242,6 @@ struct bta_av_co_audio_update_mtu { }; extern struct bta_av_co_audio_update_mtu bta_av_co_audio_update_mtu; -// Name: bta_av_co_get_decoder_interface -// Params: void -// Return: const tA2DP_DECODER_INTERFACE* -struct bta_av_co_get_decoder_interface { - static const tA2DP_DECODER_INTERFACE* return_value; - std::function body{ - [](void) { return return_value; }}; - const tA2DP_DECODER_INTERFACE* operator()(void) { return body(); }; -}; -extern struct bta_av_co_get_decoder_interface bta_av_co_get_decoder_interface; - // Name: bta_av_co_get_encoder_effective_frame_size // Params: // Return: int diff --git a/system/test/mock/mock_btif_co_bta_dm_co.cc b/system/test/mock/mock_btif_co_bta_dm_co.cc index e244296c5a55534e789bc3461d9de0a427e10cc9..63cbfc13899eb0ae0fa890fc1fc869d055443f0e 100644 --- a/system/test/mock/mock_btif_co_bta_dm_co.cc +++ b/system/test/mock/mock_btif_co_bta_dm_co.cc @@ -21,9 +21,9 @@ #include #include "bta/include/bta_api.h" +#include "bta/include/bta_sec_api.h" #include "bta/sys/bta_sys.h" #include "internal_include/bte_appl.h" -#include "osi/include/osi.h" // UNUSED_ATTR #include "stack/include/btm_api_types.h" tBTE_APPL_CFG bte_appl_cfg = { @@ -31,8 +31,7 @@ tBTE_APPL_CFG bte_appl_cfg = { BTM_IO_CAP_UNKNOWN, BTM_BLE_INITIATOR_KEY_SIZE, BTM_BLE_RESPONDER_KEY_SIZE, BTM_BLE_MAX_KEY_SIZE}; -bool bta_dm_co_get_compress_memory(UNUSED_ATTR tBTA_SYS_ID id, - UNUSED_ATTR uint8_t** memory_p, - UNUSED_ATTR uint32_t* memory_size) { +bool bta_dm_co_get_compress_memory(tBTA_SYS_ID id, uint8_t** memory_p, + uint32_t* memory_size) { return true; } diff --git a/system/test/mock/mock_btif_co_bta_hh_co.cc b/system/test/mock/mock_btif_co_bta_hh_co.cc index da9560d76dc206f1d1fd087d5281680503e546f5..35c20aeb394cf48c6fa6c3528c8343bc3dbced00 100644 --- a/system/test/mock/mock_btif_co_bta_hh_co.cc +++ b/system/test/mock/mock_btif_co_bta_hh_co.cc @@ -20,8 +20,6 @@ */ #include -#include -#include #include "bta/include/bta_hh_api.h" #include "bta/include/bta_hh_co.h" @@ -29,24 +27,20 @@ #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) { inc_func_call_count(__func__); return 0; } tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(const RawAddress& remote_bda, uint8_t* p_num_rpt, - UNUSED_ATTR uint8_t app_id) { + uint8_t app_id) { inc_func_call_count(__func__); return nullptr; } void bta_hh_co_close(btif_hh_device_t* p_dev) { inc_func_call_count(__func__); } void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len, tBTA_HH_PROTO_MODE mode, uint8_t sub_class, - uint8_t ctry_code, UNUSED_ATTR const RawAddress& peer_addr, + uint8_t ctry_code, const RawAddress& peer_addr, uint8_t app_id) { inc_func_call_count(__func__); } @@ -69,12 +63,11 @@ void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status) { inc_func_call_count(__func__); } void bta_hh_le_co_reset_rpt_cache(const RawAddress& remote_bda, - UNUSED_ATTR uint8_t app_id) { + uint8_t app_id) { inc_func_call_count(__func__); } void bta_hh_le_co_rpt_info(const RawAddress& remote_bda, - tBTA_HH_RPT_CACHE_ENTRY* p_entry, - UNUSED_ATTR uint8_t app_id) { + tBTA_HH_RPT_CACHE_ENTRY* p_entry, uint8_t app_id) { inc_func_call_count(__func__); } void uhid_set_non_blocking(int fd) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_btif_config.cc b/system/test/mock/mock_btif_config.cc index 3761b56124a36e113bbe2f413584e517d5314f3b..cac5101255364924f379e55840f51b708fdb47ef 100644 --- a/system/test/mock/mock_btif_config.cc +++ b/system/test/mock/mock_btif_config.cc @@ -21,27 +21,16 @@ * mockcify.pl ver 0.2 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_btif_config.h" + #include -#include -#include #include -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. - -// Mock include file to share data between tests and mock -#include "test/mock/mock_btif_config.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -49,6 +38,8 @@ namespace mock { namespace btif_config { // Function state capture and return values, if needed +struct btif_get_device_clockoffset btif_get_device_clockoffset; +struct btif_set_device_clockoffset btif_set_device_clockoffset; struct btif_config_exist btif_config_exist; struct btif_config_get_int btif_config_get_int; struct btif_config_set_int btif_config_set_int; @@ -61,6 +52,7 @@ struct btif_config_get_bin_length btif_config_get_bin_length; struct btif_config_set_bin btif_config_set_bin; struct btif_config_get_paired_devices btif_config_get_paired_devices; struct btif_config_remove btif_config_remove; +struct btif_config_remove_device btif_config_remove_device; struct btif_config_clear btif_config_clear; struct btif_debug_config_dump btif_debug_config_dump; @@ -69,6 +61,14 @@ struct btif_debug_config_dump btif_debug_config_dump; } // namespace test // Mocked functions, if any +bool btif_get_device_clockoffset(const RawAddress& bda, int* p_clock_offset) { + inc_func_call_count(__func__); + return test::mock::btif_config::btif_get_device_clockoffset(bda, p_clock_offset); +} +bool btif_set_device_clockoffset(const RawAddress& bda, int clock_offset) { + inc_func_call_count(__func__); + return test::mock::btif_config::btif_set_device_clockoffset(bda, clock_offset); +} bool btif_config_exist(const std::string& section, const std::string& key) { inc_func_call_count(__func__); return test::mock::btif_config::btif_config_exist(section, key); diff --git a/system/test/mock/mock_btif_config.h b/system/test/mock/mock_btif_config.h index f2f07f535abdcc3cecf94f3cd8315097fdaf30b4..153fd09e63ec258bb1729d3522b818ff9d6196bd 100644 --- a/system/test/mock/mock_btif_config.h +++ b/system/test/mock/mock_btif_config.h @@ -21,19 +21,12 @@ * mockcify.pl ver 0.2 */ -#include +#include #include - -#include "test/common/mock_functions.h" +#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "btif/include/btif_config.h" #include "types/raw_address.h" // Mocked compile conditionals, if any @@ -43,6 +36,26 @@ namespace mock { namespace btif_config { // Shared state between mocked functions and tests +// Name: btif_get_device_clockoffset +// Params: const RawAddress& bda, int* p_clock_offset +// Returns: bool +struct btif_get_device_clockoffset { + std::function body{ + [](const RawAddress& bda, int* p_clock_offset) { return false; }}; + bool operator()(const RawAddress& bda, int* p_clock_offset) { + return body(bda, p_clock_offset); + }; +}; +// Name: btif_set_device_clockoffset +// Params: const RawAddress& bda, int* p_clock_offset +// Returns: bool +struct btif_set_device_clockoffset { + std::function body{ + [](const RawAddress& bda, int clock_offset) { return false; }}; + bool operator()(const RawAddress& bda, int clock_offset) { + return body(bda, clock_offset); + }; +}; // Name: btif_config_exist // Params: const std::string& section, const std::string& key // Returns: bool @@ -201,6 +214,17 @@ struct btif_config_remove { }; }; extern struct btif_config_remove btif_config_remove; +// Name: btif_config_remove_device +// Params: const std::string& section +// Returns: void +struct btif_config_remove_device { + std::function body{ + [](const std::string& section) { return; }}; + void operator()(const std::string& section) { + return; + }; +}; +extern struct btif_config_remove_device btif_config_remove_device; // Name: btif_config_clear // Params: void // Returns: bool diff --git a/system/test/mock/mock_btif_core.cc b/system/test/mock/mock_btif_core.cc index 75544b45f0422f588ef376d5f11d5432f73d85b3..c031b2cef64717f3cd631ee1bd7f129b3f1dece1 100644 --- a/system/test/mock/mock_btif_core.cc +++ b/system/test/mock/mock_btif_core.cc @@ -22,7 +22,6 @@ #include #include -#include #include "bta/include/bta_api.h" #include "btif/include/btif_common.h" @@ -31,10 +30,10 @@ #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - +bool btif_is_dut_mode() { + inc_func_call_count(__func__); + return false; +} bool is_on_jni_thread() { inc_func_call_count(__func__); return false; @@ -72,10 +71,6 @@ bt_status_t do_in_jni_thread(const base::Location& from_here, do_in_jni_thread_task_queue.push(std::move(task)); return BT_STATUS_SUCCESS; } -btbase::AbstractMessageLoop* get_jni_message_loop() { - inc_func_call_count(__func__); - return nullptr; -} int btif_is_enabled(void) { inc_func_call_count(__func__); return 0; @@ -94,6 +89,10 @@ void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props, void btif_disable_service(tBTA_SERVICE_ID service_id) { inc_func_call_count(__func__); } +void btif_dut_mode_configure(uint8_t enable) { inc_func_call_count(__func__); } +void btif_dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) { + inc_func_call_count(__func__); +} void btif_enable_bluetooth_evt() { inc_func_call_count(__func__); } void btif_enable_service(tBTA_SERVICE_ID service_id) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_btif_debug_conn.cc b/system/test/mock/mock_btif_debug_conn.cc index e67f98fa516e5292145edb3f1b12cbefe1541964..1427ffd3d7d431c0ab4d5de64d6616eefb2429ad 100644 --- a/system/test/mock/mock_btif_debug_conn.cc +++ b/system/test/mock/mock_btif_debug_conn.cc @@ -19,18 +19,11 @@ * Functions generated:2 */ -#include -#include - #include "btif/include/btif_debug_conn.h" #include "stack/include/gatt_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void btif_debug_conn_dump(int fd) { inc_func_call_count(__func__); } void btif_debug_conn_state(const RawAddress& bda, const btif_debug_conn_state_t state, diff --git a/system/test/mock/mock_btif_dm.cc b/system/test/mock/mock_btif_dm.cc index 0559729e2ef108693cfbf3e6b181fa2fe2e0f817..9038ad0c47710ff309c45c11c0617a64c540865b 100644 --- a/system/test/mock/mock_btif_dm.cc +++ b/system/test/mock/mock_btif_dm.cc @@ -20,10 +20,9 @@ */ #include -#include -#include #include "bta/include/bta_api.h" +#include "bta/include/bta_sec_api.h" #include "include/hardware/bluetooth.h" #include "internal_include/bte_appl.h" #include "test/common/mock_functions.h" @@ -32,10 +31,6 @@ struct uid_set_t; -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - bool btif_dm_pairing_is_busy() { inc_func_call_count(__func__); return false; @@ -56,7 +51,7 @@ bool is_device_le_audio_capable(const RawAddress bd_addr) { inc_func_call_count(__func__); return false; } -uint16_t btif_dm_get_connection_state(const RawAddress* bd_addr) { +uint16_t btif_dm_get_connection_state(const RawAddress& bd_addr) { inc_func_call_count(__func__); return 0; } @@ -66,7 +61,13 @@ void BTIF_dm_on_hw_error() { inc_func_call_count(__func__); } void BTIF_dm_report_inquiry_status_change(uint8_t status) { inc_func_call_count(__func__); } -void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { +void btif_dm_sec_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) { + inc_func_call_count(__func__); +} +void btif_ble_receiver_test(uint8_t rx_freq) { inc_func_call_count(__func__); } +void btif_ble_test_end() { inc_func_call_count(__func__); } +void btif_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len, + uint8_t packet_payload) { inc_func_call_count(__func__); } void btif_debug_bond_event_dump(int fd) { inc_func_call_count(__func__); } @@ -117,9 +118,8 @@ void btif_dm_pin_reply(const RawAddress bd_addr, uint8_t accept, void btif_dm_proc_io_req(tBTM_AUTH_REQ* p_auth_req, bool is_orig) { inc_func_call_count(__func__); } -void btif_dm_proc_io_rsp(UNUSED_ATTR const RawAddress& bd_addr, - tBTM_IO_CAP io_cap, UNUSED_ATTR tBTM_OOB_DATA oob_data, - tBTM_AUTH_REQ auth_req) { +void btif_dm_proc_io_rsp(const RawAddress& bd_addr, tBTM_IO_CAP io_cap, + tBTM_OOB_DATA oob_data, tBTM_AUTH_REQ auth_req) { inc_func_call_count(__func__); } void btif_dm_read_energy_info() { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_btif_profile_queue.cc b/system/test/mock/mock_btif_profile_queue.cc index d21977b7ba0fd550ad50efc0fff2de5a67495885..3965449614165a64b118cc7b5a1b8637e8a9da19 100644 --- a/system/test/mock/mock_btif_profile_queue.cc +++ b/system/test/mock/mock_btif_profile_queue.cc @@ -20,14 +20,13 @@ * mockcify.pl ver 0.6.0 */ -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_btif_profile_queue.h" +#include + +#include "test/common/mock_functions.h" + // Original usings // Mocked internal structures, if any diff --git a/system/test/mock/mock_btif_profile_queue.h b/system/test/mock/mock_btif_profile_queue.h index 620a18073df4b19a0f3f05af64b83c85f3a54ecf..7576690908f024d61e473a12d04a83b8d514bdfb 100644 --- a/system/test/mock/mock_btif_profile_queue.h +++ b/system/test/mock/mock_btif_profile_queue.h @@ -24,29 +24,9 @@ #include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include -#include -#include - -#include - -#include "btif/include/btif_common.h" #include "btif/include/btif_profile_queue.h" -#include "btif/include/stack_manager.h" -#include "main/shim/dumpsys.h" #include "types/raw_address.h" // Original usings diff --git a/system/test/mock/mock_btif_sock_rfc.cc b/system/test/mock/mock_btif_sock_rfc.cc new file mode 100644 index 0000000000000000000000000000000000000000..b5cb79762557ade26089c86fb522fc7bbff9e65d --- /dev/null +++ b/system/test/mock/mock_btif_sock_rfc.cc @@ -0,0 +1,125 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Generated mock file from original source file + * Functions generated:10 + * + * mockcify.pl ver 0.6.2 + */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_btif_sock_rfc.h" + +#include + +#include "test/common/mock_functions.h" + +// Original usings +using bluetooth::Uuid; + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace btif_sock_rfc { + +// Function state capture and return values, if needed +struct bta_co_rfc_data_incoming bta_co_rfc_data_incoming; +struct bta_co_rfc_data_outgoing bta_co_rfc_data_outgoing; +struct bta_co_rfc_data_outgoing_size bta_co_rfc_data_outgoing_size; +struct btsock_rfc_cleanup btsock_rfc_cleanup; +struct btsock_rfc_connect btsock_rfc_connect; +struct btsock_rfc_control_req btsock_rfc_control_req; +struct btsock_rfc_disconnect btsock_rfc_disconnect; +struct btsock_rfc_init btsock_rfc_init; +struct btsock_rfc_listen btsock_rfc_listen; +struct btsock_rfc_signaled btsock_rfc_signaled; + +} // namespace btif_sock_rfc +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace btif_sock_rfc { + +int bta_co_rfc_data_incoming::return_value = 0; +int bta_co_rfc_data_outgoing::return_value = 0; +int bta_co_rfc_data_outgoing_size::return_value = 0; +bt_status_t btsock_rfc_connect::return_value = BT_STATUS_SUCCESS; +bt_status_t btsock_rfc_control_req::return_value = BT_STATUS_SUCCESS; +bt_status_t btsock_rfc_disconnect::return_value = BT_STATUS_SUCCESS; +bt_status_t btsock_rfc_init::return_value = BT_STATUS_SUCCESS; +bt_status_t btsock_rfc_listen::return_value = BT_STATUS_SUCCESS; + +} // namespace btif_sock_rfc +} // namespace mock +} // namespace test + +// Mocked functions, if any +int bta_co_rfc_data_incoming(uint32_t id, BT_HDR* p_buf) { + inc_func_call_count(__func__); + return test::mock::btif_sock_rfc::bta_co_rfc_data_incoming(id, p_buf); +} +int bta_co_rfc_data_outgoing(uint32_t id, uint8_t* buf, uint16_t size) { + inc_func_call_count(__func__); + return test::mock::btif_sock_rfc::bta_co_rfc_data_outgoing(id, buf, size); +} +int bta_co_rfc_data_outgoing_size(uint32_t id, int* size) { + inc_func_call_count(__func__); + return test::mock::btif_sock_rfc::bta_co_rfc_data_outgoing_size(id, size); +} +void btsock_rfc_cleanup(void) { + inc_func_call_count(__func__); + test::mock::btif_sock_rfc::btsock_rfc_cleanup(); +} +bt_status_t btsock_rfc_connect(const RawAddress* bd_addr, + const Uuid* service_uuid, int channel, + int* sock_fd, int flags, int app_uid) { + inc_func_call_count(__func__); + return test::mock::btif_sock_rfc::btsock_rfc_connect( + bd_addr, service_uuid, channel, sock_fd, flags, app_uid); +} +bt_status_t btsock_rfc_control_req(uint8_t dlci, const RawAddress& bd_addr, + uint8_t modem_signal, uint8_t break_signal, + uint8_t discard_buffers, + uint8_t break_signal_seq, bool fc) { + inc_func_call_count(__func__); + return test::mock::btif_sock_rfc::btsock_rfc_control_req( + dlci, bd_addr, modem_signal, break_signal, discard_buffers, + break_signal_seq, fc); +} +bt_status_t btsock_rfc_disconnect(const RawAddress* bd_addr) { + inc_func_call_count(__func__); + return test::mock::btif_sock_rfc::btsock_rfc_disconnect(bd_addr); +} +bt_status_t btsock_rfc_init(int poll_thread_handle, uid_set_t* set) { + inc_func_call_count(__func__); + return test::mock::btif_sock_rfc::btsock_rfc_init(poll_thread_handle, set); +} +bt_status_t btsock_rfc_listen(const char* service_name, + const Uuid* service_uuid, int channel, + int* sock_fd, int flags, int app_uid) { + inc_func_call_count(__func__); + return test::mock::btif_sock_rfc::btsock_rfc_listen( + service_name, service_uuid, channel, sock_fd, flags, app_uid); +} +void btsock_rfc_signaled(int fd, int flags, uint32_t id) { + inc_func_call_count(__func__); + test::mock::btif_sock_rfc::btsock_rfc_signaled(fd, flags, id); +} +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_btif_sock_rfc.h b/system/test/mock/mock_btif_sock_rfc.h new file mode 100644 index 0000000000000000000000000000000000000000..be8be5dd1fe4a83f1f5679d74b2ddbcb428f3acd --- /dev/null +++ b/system/test/mock/mock_btif_sock_rfc.h @@ -0,0 +1,184 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:10 + * + * mockcify.pl ver 0.6.2 + */ + +#include +#include +#include + +#include +#include + +#include "btif/include/btif_uid.h" +#include "stack/include/bt_hdr.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +// Original usings +using bluetooth::Uuid; + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace btif_sock_rfc { + +// Shared state between mocked functions and tests +// Name: bta_co_rfc_data_incoming +// Params: uint32_t id, BT_HDR* p_buf +// Return: int +struct bta_co_rfc_data_incoming { + static int return_value; + std::function body{ + [](uint32_t id, BT_HDR* p_buf) { return return_value; }}; + int operator()(uint32_t id, BT_HDR* p_buf) { return body(id, p_buf); }; +}; +extern struct bta_co_rfc_data_incoming bta_co_rfc_data_incoming; + +// Name: bta_co_rfc_data_outgoing +// Params: uint32_t id, uint8_t* buf, uint16_t size +// Return: int +struct bta_co_rfc_data_outgoing { + static int return_value; + std::function body{ + [](uint32_t id, uint8_t* buf, uint16_t size) { return return_value; }}; + int operator()(uint32_t id, uint8_t* buf, uint16_t size) { + return body(id, buf, size); + }; +}; +extern struct bta_co_rfc_data_outgoing bta_co_rfc_data_outgoing; + +// Name: bta_co_rfc_data_outgoing_size +// Params: uint32_t id, int* size +// Return: int +struct bta_co_rfc_data_outgoing_size { + static int return_value; + std::function body{ + [](uint32_t id, int* size) { return return_value; }}; + int operator()(uint32_t id, int* size) { return body(id, size); }; +}; +extern struct bta_co_rfc_data_outgoing_size bta_co_rfc_data_outgoing_size; + +// Name: btsock_rfc_cleanup +// Params: void +// Return: void +struct btsock_rfc_cleanup { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btsock_rfc_cleanup btsock_rfc_cleanup; + +// Name: btsock_rfc_connect +// Params: const RawAddress* bd_addr, const Uuid* service_uuid, int channel, +// int* sock_fd, int flags, int app_uid Return: bt_status_t +struct btsock_rfc_connect { + static bt_status_t return_value; + std::function + body{[](const RawAddress* bd_addr, const Uuid* service_uuid, int channel, + int* sock_fd, int flags, int app_uid) { return return_value; }}; + bt_status_t operator()(const RawAddress* bd_addr, const Uuid* service_uuid, + int channel, int* sock_fd, int flags, int app_uid) { + return body(bd_addr, service_uuid, channel, sock_fd, flags, app_uid); + }; +}; +extern struct btsock_rfc_connect btsock_rfc_connect; + +// Name: btsock_rfc_control_req +// Params: uint8_t dlci, const RawAddress& bd_addr, uint8_t modem_signal, +// uint8_t break_signal, uint8_t discard_buffers, uint8_t break_signal_seq, bool +// fc Return: bt_status_t +struct btsock_rfc_control_req { + static bt_status_t return_value; + std::function + body{[](uint8_t dlci, const RawAddress& bd_addr, uint8_t modem_signal, + uint8_t break_signal, uint8_t discard_buffers, + uint8_t break_signal_seq, bool fc) { return return_value; }}; + bt_status_t operator()(uint8_t dlci, const RawAddress& bd_addr, + uint8_t modem_signal, uint8_t break_signal, + uint8_t discard_buffers, uint8_t break_signal_seq, + bool fc) { + return body(dlci, bd_addr, modem_signal, break_signal, discard_buffers, + break_signal_seq, fc); + }; +}; +extern struct btsock_rfc_control_req btsock_rfc_control_req; + +// Name: btsock_rfc_disconnect +// Params: const RawAddress* bd_addr +// Return: bt_status_t +struct btsock_rfc_disconnect { + static bt_status_t return_value; + std::function body{ + [](const RawAddress* bd_addr) { return return_value; }}; + bt_status_t operator()(const RawAddress* bd_addr) { return body(bd_addr); }; +}; +extern struct btsock_rfc_disconnect btsock_rfc_disconnect; + +// Name: btsock_rfc_init +// Params: int poll_thread_handle, uid_set_t* set +// Return: bt_status_t +struct btsock_rfc_init { + static bt_status_t return_value; + std::function body{ + [](int poll_thread_handle, uid_set_t* set) { return return_value; }}; + bt_status_t operator()(int poll_thread_handle, uid_set_t* set) { + return body(poll_thread_handle, set); + }; +}; +extern struct btsock_rfc_init btsock_rfc_init; + +// Name: btsock_rfc_listen +// Params: const char* service_name, const Uuid* service_uuid, int channel, int* +// sock_fd, int flags, int app_uid Return: bt_status_t +struct btsock_rfc_listen { + static bt_status_t return_value; + std::function + body{[](const char* service_name, const Uuid* service_uuid, int channel, + int* sock_fd, int flags, int app_uid) { return return_value; }}; + bt_status_t operator()(const char* service_name, const Uuid* service_uuid, + int channel, int* sock_fd, int flags, int app_uid) { + return body(service_name, service_uuid, channel, sock_fd, flags, app_uid); + }; +}; +extern struct btsock_rfc_listen btsock_rfc_listen; + +// Name: btsock_rfc_signaled +// Params: int fd, int flags, uint32_t id +// Return: void +struct btsock_rfc_signaled { + std::function body{ + [](int fd, int flags, uint32_t id) {}}; + void operator()(int fd, int flags, uint32_t id) { body(fd, flags, id); }; +}; +extern struct btsock_rfc_signaled btsock_rfc_signaled; + +} // namespace btif_sock_rfc +} // namespace mock +} // namespace test + +// END mockcify generation \ No newline at end of file diff --git a/system/test/mock/mock_btif_storage.cc b/system/test/mock/mock_btif_storage.cc index bc029ece51a7d3f854692e24cfaef0f676c63be6..2d528672f1f82582d7cc607aad14c7c13065ef92 100644 --- a/system/test/mock/mock_btif_storage.cc +++ b/system/test/mock/mock_btif_storage.cc @@ -20,20 +20,16 @@ */ #include -#include #include #include "bta/include/bta_hearing_aid_api.h" #include "stack/include/bt_octets.h" +#include "stack/include/btm_sec_api_types.h" #include "test/common/mock_functions.h" #include "types/ble_address_with_type.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - Octet16 btif_storage_get_gatt_cl_db_hash(const RawAddress& bd_addr) { inc_func_call_count(__func__); Octet16 octet; @@ -184,13 +180,13 @@ uint8_t btif_storage_get_gatt_cl_supp_feat(const RawAddress& bd_addr) { inc_func_call_count(__func__); return 0; } -uint8_t btif_storage_get_local_io_caps() { +tBTM_IO_CAP btif_storage_get_local_io_caps() { inc_func_call_count(__func__); - return 0; + return BTM_IO_CAP_UNKNOWN; } -uint8_t btif_storage_get_local_io_caps_ble() { +tBTM_IO_CAP btif_storage_get_local_io_caps_ble() { inc_func_call_count(__func__); - return 0; + return BTM_IO_CAP_UNKNOWN; } void btif_storage_load_bonded_hearing_aids() { inc_func_call_count(__func__); } void btif_storage_remove_gatt_cl_db_hash(const RawAddress& bd_addr) { diff --git a/system/test/mock/mock_btif_util.cc b/system/test/mock/mock_btif_util.cc index ee54380b5229c96539d1238a937f84165750200d..4a469f955d63feb9b71e68769ff8a97e4d3ceead 100644 --- a/system/test/mock/mock_btif_util.cc +++ b/system/test/mock/mock_btif_util.cc @@ -19,14 +19,12 @@ * * mockcify.pl ver 0.6.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_btif_util.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_btif_util.h" +#include "test/common/mock_functions.h" // Original usings diff --git a/system/test/mock/mock_btif_util.h b/system/test/mock/mock_btif_util.h index 8aaeda5dca9408b7403e037c99dfca4f09f91162..473c924b3c7e014e217838281baaff1d4bf744bb 100644 --- a/system/test/mock/mock_btif_util.h +++ b/system/test/mock/mock_btif_util.h @@ -21,27 +21,15 @@ * * mockcify.pl ver 0.6.0 */ - #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include #include -#include -#include #include "include/hardware/bluetooth.h" #include "stack/include/bt_dev_class.h" -#include "test/common/mock_functions.h" -#include "test/mock/mock_btif_util.h" // Original usings diff --git a/system/test/mock/mock_btu_task.cc b/system/test/mock/mock_btu_task.cc index 1e737b46914b6e72632429cfcc2256e3ef5dea91..5c3cf08a8d9440505cc62cc5f5f5fae5de8f4e9d 100644 --- a/system/test/mock/mock_btu_task.cc +++ b/system/test/mock/mock_btu_task.cc @@ -19,31 +19,7 @@ * Functions generated:7 */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bta/sys/bta_sys.h" -#include "btcore/include/module.h" -#include "btif/include/btif_common.h" -#include "btm_iso_api.h" -#include "common/message_loop_thread.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "stack/include/acl_hci_link_interface.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void btu_hci_msg_process(BT_HDR* p_msg) { inc_func_call_count(__func__); } +void btu_hci_msg_process(BT_HDR* /* p_msg */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_common_address_obfuscator.cc b/system/test/mock/mock_common_address_obfuscator.cc index ca6f89c74c6aba627310124aaa74565849ee7915..0200877c8f415ca61b924b4735befdcf4573dbff 100644 --- a/system/test/mock/mock_common_address_obfuscator.cc +++ b/system/test/mock/mock_common_address_obfuscator.cc @@ -22,18 +22,12 @@ #include #include -#include -#include #include #include "common/address_obfuscator.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace bluetooth { namespace common { diff --git a/system/test/mock/mock_common_message_loop_thread.cc b/system/test/mock/mock_common_message_loop_thread.cc deleted file mode 100644 index b3127b13b1413569e023954f202d5e5110ec674d..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_common_message_loop_thread.cc +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "common/message_loop_thread.h" - -#include -#include -#include - -#include - -#include "gd/common/init_flags.h" -#include "osi/include/log.h" - -namespace bluetooth { - -namespace common { - -static constexpr int kRealTimeFifoSchedulingPriority = 1; - -MessageLoopThread::MessageLoopThread(const std::string& thread_name) - : MessageLoopThread(thread_name, false) {} - -MessageLoopThread::MessageLoopThread(const std::string& thread_name, - bool is_main) - : thread_name_(thread_name), - message_loop_(nullptr), - run_loop_(nullptr), - thread_(nullptr), - thread_id_(-1), - linux_tid_(-1), - weak_ptr_factory_(this), - shutting_down_(false), - is_main_(is_main) {} - -MessageLoopThread::~MessageLoopThread() { ShutDown(); } - -void MessageLoopThread::StartUp() { - std::promise start_up_promise; - std::future start_up_future = start_up_promise.get_future(); - { - std::lock_guard api_lock(api_mutex_); - if (thread_ != nullptr) { - LOG(WARNING) << __func__ << ": thread " << *this << " is already started"; - - return; - } - thread_ = new std::thread(&MessageLoopThread::RunThread, this, - std::move(start_up_promise)); - } - start_up_future.wait(); -} - -bool MessageLoopThread::DoInThread(const base::Location& from_here, - base::OnceClosure task) { - return DoInThreadDelayed(from_here, std::move(task), base::TimeDelta()); -} - -bool MessageLoopThread::DoInThreadDelayed(const base::Location& from_here, - base::OnceClosure task, - const base::TimeDelta& delay) { - std::lock_guard api_lock(api_mutex_); - if (message_loop_ == nullptr) { - LOG(ERROR) << __func__ << ": message loop is null for thread " << *this - << ", from " << from_here.ToString(); - return false; - } - if (!message_loop_->task_runner()->PostDelayedTask(from_here, std::move(task), - delay)) { - LOG(ERROR) << __func__ - << ": failed to post task to message loop for thread " << *this - << ", from " << from_here.ToString(); - return false; - } - return true; -} - -void MessageLoopThread::ShutDown() { - { - std::lock_guard api_lock(api_mutex_); - if (thread_ == nullptr) { - LOG(INFO) << __func__ << ": thread " << *this << " is already stopped"; - return; - } - if (message_loop_ == nullptr) { - LOG(INFO) << __func__ << ": message_loop_ is null. Already stopping"; - return; - } - if (shutting_down_) { - LOG(INFO) << __func__ << ": waiting for thread to join"; - return; - } - shutting_down_ = true; - CHECK_NE(thread_id_, base::PlatformThread::CurrentId()) - << __func__ << " should not be called on the thread itself. " - << "Otherwise, deadlock may happen."; - if (!message_loop_->task_runner()->PostTask( - FROM_HERE, run_loop_->QuitWhenIdleClosure())) { - LOG(FATAL) << __func__ - << ": failed to post task to message loop for thread " - << *this; - } - } - thread_->join(); - { - std::lock_guard api_lock(api_mutex_); - delete thread_; - thread_ = nullptr; - shutting_down_ = false; - } -} - -base::PlatformThreadId MessageLoopThread::GetThreadId() const { - std::lock_guard api_lock(api_mutex_); - return thread_id_; -} - -std::string MessageLoopThread::GetName() const { return thread_name_; } - -std::string MessageLoopThread::ToString() const { - std::lock_guard api_lock(api_mutex_); - return base::StringPrintf("%s(%d)", thread_name_.c_str(), thread_id_); -} - -bool MessageLoopThread::IsRunning() const { - std::lock_guard api_lock(api_mutex_); - return thread_id_ != -1; -} - -// Non API method, should not be protected by API mutex -void MessageLoopThread::RunThread(MessageLoopThread* thread, - std::promise start_up_promise) { - thread->Run(std::move(start_up_promise)); -} - -btbase::AbstractMessageLoop* MessageLoopThread::message_loop() const { - ASSERT_LOG(!is_main_, - "you are not allowed to get the main thread's message loop"); - - std::lock_guard api_lock(api_mutex_); - return message_loop_; -} - -bool MessageLoopThread::EnableRealTimeScheduling() { - std::lock_guard api_lock(api_mutex_); - - if (!IsRunning()) { - LOG(ERROR) << __func__ << ": thread " << *this << " is not running"; - return false; - } - - struct sched_param rt_params = {.sched_priority = - kRealTimeFifoSchedulingPriority}; - int rc = sched_setscheduler(linux_tid_, SCHED_FIFO, &rt_params); - if (rc != 0) { - LOG(ERROR) << __func__ << ": unable to set SCHED_FIFO priority " - << kRealTimeFifoSchedulingPriority << " for linux_tid " - << std::to_string(linux_tid_) << ", thread " << *this - << ", error: " << strerror(errno); - return false; - } - return true; -} - -base::WeakPtr MessageLoopThread::GetWeakPtr() { - std::lock_guard api_lock(api_mutex_); - return weak_ptr_factory_.GetWeakPtr(); -} - -void MessageLoopThread::Run(std::promise start_up_promise) { - { - std::lock_guard api_lock(api_mutex_); - LOG(INFO) << __func__ << ": message loop starting for thread " - << thread_name_; - base::PlatformThread::SetName(thread_name_); - message_loop_ = new btbase::AbstractMessageLoop(); - run_loop_ = new base::RunLoop(); - thread_id_ = base::PlatformThread::CurrentId(); - linux_tid_ = static_cast(syscall(SYS_gettid)); - start_up_promise.set_value(); - } - - // Blocking until ShutDown() is called - run_loop_->Run(); - - { - std::lock_guard api_lock(api_mutex_); - thread_id_ = -1; - linux_tid_ = -1; - delete message_loop_; - message_loop_ = nullptr; - delete run_loop_; - run_loop_ = nullptr; - LOG(INFO) << __func__ << ": message loop finished for thread " - << thread_name_; - } -} - -} // namespace common - -} // namespace bluetooth diff --git a/system/test/mock/mock_common_metric_id_allocator.cc b/system/test/mock/mock_common_metric_id_allocator.cc deleted file mode 100644 index f4caa5819a067abb32f1dd8d1129adad68c5dde0..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_common_metric_id_allocator.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:11 - */ - -#include - -#include -#include -#include -#include -#include - -#include "common/metric_id_allocator.h" -#include "test/common/mock_functions.h" -#include "types/raw_address.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -namespace { - -const size_t paired_device_cache_capacity{10}; -const std::string paired_device_cache_log_tag("Mock"); -} // namespace - -namespace bluetooth { -namespace common { - -const int MetricIdAllocator::kMinId = 0; - -MetricIdAllocator::MetricIdAllocator() - : paired_device_cache_(paired_device_cache_capacity, - paired_device_cache_log_tag), - temporary_device_cache_(paired_device_cache_capacity, - paired_device_cache_log_tag) { - next_id_ = 0; - initialized_ = true; -} - -class MockMetricIdAllocator : public MetricIdAllocator { - public: - MockMetricIdAllocator() {} -}; - -MockMetricIdAllocator metric_id_allocator; - -MetricIdAllocator& MetricIdAllocator::GetInstance() { - inc_func_call_count(__func__); - return metric_id_allocator; -} -MetricIdAllocator::~MetricIdAllocator() {} -bool MetricIdAllocator::Close() { - inc_func_call_count(__func__); - return false; -} -bool MetricIdAllocator::Init( - const std::unordered_map& paired_device_map, - Callback save_id_callback, Callback forget_device_callback) { - inc_func_call_count(__func__); - return false; -} -bool MetricIdAllocator::IsEmpty() const { - inc_func_call_count(__func__); - return false; -} -bool MetricIdAllocator::IsValidId(const int id) { - inc_func_call_count(__func__); - return false; -} -bool MetricIdAllocator::SaveDevice(const RawAddress& mac_address) { - inc_func_call_count(__func__); - return false; -} -int MetricIdAllocator::AllocateId(const RawAddress& mac_address) { - inc_func_call_count(__func__); - return 0; -} -void MetricIdAllocator::ForgetDevice(const RawAddress& mac_address) { - inc_func_call_count(__func__); -} -void MetricIdAllocator::ForgetDevicePostprocess(const RawAddress& mac_address, - const int id) { - inc_func_call_count(__func__); -} - -} // namespace common -} // namespace bluetooth diff --git a/system/test/mock/mock_common_metrics.cc b/system/test/mock/mock_common_metrics.cc deleted file mode 100644 index 3bd98b4a141cbf84b3db8277f56f42c753aca667..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_common_metrics.cc +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:36 - */ - -#include -#include - -#include "common/metrics.h" -#include "test/common/mock_functions.h" -#include "types/raw_address.h" - -#if 0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "address_obfuscator.h" -#include "bluetooth/metrics/bluetooth.pb.h" -#include "leaky_bonded_queue.h" -#include "metric_id_allocator.h" -#include "osi/include/osi.h" -#include "stack/include/btm_api_types.h" -#include "time_util.h" -#endif - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -namespace bluetooth { -namespace common { - -void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) { - inc_func_call_count(__func__); -} - -struct BluetoothMetricsLogger::impl { - int mock{123}; -}; - -BluetoothMetricsLogger::BluetoothMetricsLogger() {} -void BluetoothMetricsLogger::Build() { inc_func_call_count(__func__); } -void BluetoothMetricsLogger::CutoffSession() { inc_func_call_count(__func__); } -void BluetoothMetricsLogger::LogA2dpSession( - const A2dpSessionMetrics& a2dp_session_metrics) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo( - uint32_t device_class, device_type_t device_type) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::LogBluetoothSessionEnd( - disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::LogBluetoothSessionStart( - connection_tech_t connection_tech_type, uint64_t timestamp_ms) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::LogHeadsetProfileRfcConnection( - tBTA_SERVICE_ID service_id) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason, - uint64_t timestamp_ms, - uint32_t device_class, - device_type_t device_type) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::LogScanEvent(bool start, - const std::string& initator, - scan_tech_t type, uint32_t results, - uint64_t timestamp_ms) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type, - const std::string& requestor, - const std::string& name, - uint64_t timestamp_ms) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::Reset() { inc_func_call_count(__func__); } -void BluetoothMetricsLogger::ResetLog() { inc_func_call_count(__func__); } -void BluetoothMetricsLogger::ResetSession() { inc_func_call_count(__func__); } -void BluetoothMetricsLogger::WriteBase64(int fd) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::WriteBase64String(std::string* serialized) { - inc_func_call_count(__func__); -} -void BluetoothMetricsLogger::WriteString(std::string* serialized) { - inc_func_call_count(__func__); -} -void LogA2dpAudioOverrunEvent(const RawAddress& address, - uint64_t encoding_interval_millis, - int num_dropped_buffers, - int num_dropped_encoded_frames, - int num_dropped_encoded_bytes) { - inc_func_call_count(__func__); -} -void LogA2dpAudioUnderrunEvent(const RawAddress& address, - uint64_t encoding_interval_millis, - int num_missing_pcm_bytes) { - inc_func_call_count(__func__); -} -void LogA2dpPlaybackEvent(const RawAddress& address, int playback_state, - int audio_coding_mode) { - inc_func_call_count(__func__); -} -void LogBluetoothHalCrashReason(const RawAddress& address, uint32_t error_code, - uint32_t vendor_error_code) { - inc_func_call_count(__func__); -} -void LogClassicPairingEvent(const RawAddress& address, uint16_t handle, - uint32_t hci_cmd, uint16_t hci_event, - uint16_t cmd_status, uint16_t reason_code, - int64_t event_value) { - inc_func_call_count(__func__); -} -void LogHciTimeoutEvent(uint32_t hci_cmd) { inc_func_call_count(__func__); } -void LogLinkLayerConnectionEvent(const RawAddress* address, - uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, - uint16_t link_type, uint32_t hci_cmd, - uint16_t hci_event, uint16_t hci_ble_event, - uint16_t cmd_status, uint16_t reason_code) { - inc_func_call_count(__func__); -} -void LogManufacturerInfo(const RawAddress& address, - android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, - const std::string& manufacturer, - const std::string& model, - const std::string& hardware_version, - const std::string& software_version) { - inc_func_call_count(__func__); -} -void LogReadFailedContactCounterResult(const RawAddress& address, - uint16_t handle, uint32_t cmd_status, - int32_t failed_contact_counter) { - inc_func_call_count(__func__); -} -void LogReadRssiResult(const RawAddress& address, uint16_t handle, - uint32_t cmd_status, int8_t rssi) { - inc_func_call_count(__func__); -} -void LogReadTxPowerLevelResult(const RawAddress& address, uint16_t handle, - uint32_t cmd_status, - int32_t transmit_power_level) { - inc_func_call_count(__func__); -} -void LogRemoteVersionInfo(uint16_t handle, uint8_t status, uint8_t version, - uint16_t manufacturer_name, uint16_t subversion) { - inc_func_call_count(__func__); -} -void LogSdpAttribute(const RawAddress& address, uint16_t protocol_uuid, - uint16_t attribute_id, size_t attribute_size, - const char* attribute_value) { - inc_func_call_count(__func__); -} -void LogSmpPairingEvent(const RawAddress& address, uint8_t smp_cmd, - android::bluetooth::DirectionEnum direction, - uint8_t smp_fail_reason) { - inc_func_call_count(__func__); -} -void LogSocketConnectionState( - const RawAddress& address, int port, int type, - android::bluetooth::SocketConnectionstateEnum connection_state, - int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port, - android::bluetooth::SocketRoleEnum socket_role) { - inc_func_call_count(__func__); -} - -void LogLeAudioConnectionSessionReported( - int32_t group_size, int32_t group_metric_id, - int64_t connection_duration_nanos, - std::vector& device_connecting_offset_nanos, - std::vector& device_connected_offset_nanos, - std::vector& device_connection_duration_nanos, - std::vector& device_connection_status, - std::vector& device_disconnection_status, - std::vector& device_address, - std::vector& streaming_offset_nanos, - std::vector& streaming_duration_nanos, - std::vector& streaming_context_type) { - inc_func_call_count(__func__); -} - -void LogLeAudioBroadcastSessionReported(int64_t duration_nanos) { - inc_func_call_count(__func__); -} - -} // namespace common -} // namespace bluetooth diff --git a/system/test/mock/mock_common_os_utils.h b/system/test/mock/mock_common_os_utils.h index 704bf28c70973ac370fd4a1e72ebef56d7a482aa..ab78c85a76e2b17d2ca16e597460af53e85dc048 100644 --- a/system/test/mock/mock_common_os_utils.h +++ b/system/test/mock/mock_common_os_utils.h @@ -23,19 +23,9 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include #include diff --git a/system/test/mock/mock_common_repeating_timer.cc b/system/test/mock/mock_common_repeating_timer.cc deleted file mode 100644 index 7a8a1394227120c6b8cd3ea94fdaf717fb298483..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_common_repeating_timer.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:8 - */ - -#include -#include - -#include "common/message_loop_thread.h" -#include "common/repeating_timer.h" -#include "common/time_util.h" -#include "test/common/mock_functions.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -using namespace bluetooth::common; - -RepeatingTimer::~RepeatingTimer() { inc_func_call_count(__func__); } -bool RepeatingTimer::IsScheduled() const { - inc_func_call_count(__func__); - return false; -} -bool RepeatingTimer::SchedulePeriodic( - const base::WeakPtr& thread, - const base::Location& from_here, base::Closure task, - base::TimeDelta period) { - inc_func_call_count(__func__); - return false; -} -void RepeatingTimer::Cancel() { - inc_func_call_count(__func__); - expected_time_next_task_us_ = 0; -} -void RepeatingTimer::CancelAndWait() { inc_func_call_count(__func__); } -void RepeatingTimer::CancelClosure(std::promise promise) { - inc_func_call_count(__func__); -} -void RepeatingTimer::CancelHelper(std::promise promise) { - inc_func_call_count(__func__); -} -void RepeatingTimer::RunTask() { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_common_stop_watch_legacy.cc b/system/test/mock/mock_common_stop_watch_legacy.cc deleted file mode 100644 index 98e40a14d673c93869210539e44218de81ba4f0e..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_common_stop_watch_legacy.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:4 - */ - -#include - -#include -#include -#include -#include -#include - -#include "common/stop_watch_legacy.h" -#include "osi/include/log.h" -#include "test/common/mock_functions.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -namespace bluetooth { -namespace common { - -StopWatchLegacy::StopWatchLegacy(std::string text) - : text_(std::move(text)), - timestamp_(std::chrono::system_clock::now()), - start_timestamp_(std::chrono::high_resolution_clock::now()) { - inc_func_call_count(__func__); -} -StopWatchLegacy::~StopWatchLegacy() { inc_func_call_count(__func__); } -void StopWatchLegacy::DumpStopWatchLog() { inc_func_call_count(__func__); } -void StopWatchLegacy::RecordLog(StopWatchLog log) { - inc_func_call_count(__func__); -} - -} // namespace common -} // namespace bluetooth diff --git a/system/test/mock/mock_common_time_util.cc b/system/test/mock/mock_common_time_util.cc deleted file mode 100644 index 4f305d56f73c0261999a9947d966aabe96e039ea..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_common_time_util.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:3 - */ - -#include -#include - -#include -#include - -#include "common/time_util.h" -#include "test/common/mock_functions.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -namespace bluetooth { -namespace common { - -uint64_t time_get_os_boottime_ms() { - inc_func_call_count(__func__); - return 0; -} -uint64_t time_get_os_boottime_us() { - inc_func_call_count(__func__); - return 0; -} -uint64_t time_gettimeofday_us() { - inc_func_call_count(__func__); - return 0; -} -uint64_t time_get_os_monotonic_raw_us() { - inc_func_call_count(__func__); - return 0; -} - -} // namespace common -} // namespace bluetooth diff --git a/system/test/mock/mock_device_controller.cc b/system/test/mock/mock_device_controller.cc index b4f0d654847e502f0051e1eacc8d22725adf7340..da98d0e30ff002378d449f49b7c468a560b4f8a9 100644 --- a/system/test/mock/mock_device_controller.cc +++ b/system/test/mock/mock_device_controller.cc @@ -20,30 +20,18 @@ * * mockcify.pl ver 0.2 */ - -#include -#include +// Mock include file to share data between tests and mock +#include "test/mock/mock_device_controller.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "main/shim/controller.h" -#include "types/raw_address.h" - -// Mock include file to share data between tests and mock +#include "btcore/include/version.h" +#include "device/include/controller.h" #include "stack/include/btm_api_types.h" #include "stack/include/btm_status.h" #include "stack/include/hcidefs.h" -#include "test/mock/mock_device_controller.h" +#include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { namespace mock { @@ -93,6 +81,9 @@ bool ble_supported{false}; bool iso_supported{false}; bool simple_pairing_supported{false}; bool secure_connections_supported{false}; +bool supports_hold_mode{false}; +bool supports_sniff_mode{true}; +bool supports_park_mode{false}; bool get_is_ready(void) { return readable; } @@ -210,18 +201,6 @@ bool supports_role_switch(void) { return HCI_SWITCH_SUPPORTED(features_classic[0].as_array); } -bool supports_hold_mode(void) { - return HCI_HOLD_MODE_SUPPORTED(features_classic[0].as_array); -} - -bool supports_sniff_mode(void) { - return HCI_SNIFF_MODE_SUPPORTED(features_classic[0].as_array); -} - -bool supports_park_mode(void) { - return HCI_PARK_MODE_SUPPORTED(features_classic[0].as_array); -} - bool supports_non_flushable_pb(void) { return HCI_NON_FLUSHABLE_PB_SUPPORTED(features_classic[0].as_array); } @@ -405,7 +384,6 @@ tBTM_STATUS set_event_filter_inquiry_result_all_devices() { return BTM_SUCCESS; } -// clang-format off const controller_t interface = { get_is_ready, @@ -440,9 +418,9 @@ const controller_t interface = { supports_esco_3m_phy, supports_3_slot_esco_edr_packets, supports_role_switch, - supports_hold_mode, - supports_sniff_mode, - supports_park_mode, + []() { return supports_hold_mode; }, + []() { return supports_sniff_mode; }, + []() { return supports_park_mode; }, supports_non_flushable_pb, supports_sniff_subrating, supports_encryption_pause, @@ -503,7 +481,6 @@ const controller_t interface = { set_default_event_mask_except, set_event_filter_inquiry_result_all_devices, }; -// clang-format on } // namespace device_controller } // namespace mock diff --git a/system/test/mock/mock_device_controller.h b/system/test/mock/mock_device_controller.h index 3377ac3ea6d6340d9e203ed341e002f9166092a6..c3f39e13a009103515552743dbc9252e2c2ed340 100644 --- a/system/test/mock/mock_device_controller.h +++ b/system/test/mock/mock_device_controller.h @@ -21,25 +21,14 @@ * mockcify.pl ver 0.2 */ -#include -#include - -#include "test/common/mock_functions.h" +#include +#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. #include "btcore/include/device_features.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace device_controller { diff --git a/system/test/mock/mock_device_esco_parameters.cc b/system/test/mock/mock_device_esco_parameters.cc index 6e7f8931020e23f0eb4ffa829d0194dcaea6dd0d..c5441a9afa6d3caa077137307066ef4b304e3666 100644 --- a/system/test/mock/mock_device_esco_parameters.cc +++ b/system/test/mock/mock_device_esco_parameters.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_device_esco_parameters.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_device_esco_parameters.h b/system/test/mock/mock_device_esco_parameters.h index 6707dd82e32c0bcf294a40be753be886f3ff63fe..ecaefdb96df6f3243904a131cb557e29baf9a2fc 100644 --- a/system/test/mock/mock_device_esco_parameters.h +++ b/system/test/mock/mock_device_esco_parameters.h @@ -21,21 +21,10 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include "base/logging.h" -#include "check.h" #include "device/include/esco_parameters.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_device_interop.cc b/system/test/mock/mock_device_interop.cc index 375a45f6c95a0d077a92659e86d6dd7c01cb457d..5f108a58894bb91f1d773c24fa537905e9fa2682 100644 --- a/system/test/mock/mock_device_interop.cc +++ b/system/test/mock/mock_device_interop.cc @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,82 +13,300 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* * Generated mock file from original source file - * Functions generated:6 + * Functions generated:34 + * + * mockcify.pl ver 0.6.2 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_device_interop.h" -#include #include -#include -#include #include "device/include/interop.h" #include "test/common/mock_functions.h" -#include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +// Original usings -bool interop_match_addr(const interop_feature_t feature, - const RawAddress* addr) { +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace device_interop { + +// Function state capture and return values, if needed +struct interop_database_add interop_database_add; +struct interop_database_add_addr interop_database_add_addr; +struct interop_database_add_addr_lmp_version + interop_database_add_addr_lmp_version; +struct interop_database_add_addr_max_lat interop_database_add_addr_max_lat; +struct interop_database_add_manufacturer interop_database_add_manufacturer; +struct interop_database_add_name interop_database_add_name; +struct interop_database_add_version interop_database_add_version; +struct interop_database_add_vndr_prdt interop_database_add_vndr_prdt; +struct interop_database_clear interop_database_clear; +struct interop_database_match_addr interop_database_match_addr; +struct interop_database_match_addr_get_lmp_ver + interop_database_match_addr_get_lmp_ver; +struct interop_database_match_addr_get_max_lat + interop_database_match_addr_get_max_lat; +struct interop_database_match_manufacturer interop_database_match_manufacturer; +struct interop_database_match_name interop_database_match_name; +struct interop_database_match_version interop_database_match_version; +struct interop_database_match_vndr_prdt interop_database_match_vndr_prdt; +struct interop_database_remove_addr interop_database_remove_addr; +struct interop_database_remove_addr_lmp_version + interop_database_remove_addr_lmp_version; +struct interop_database_remove_addr_max_lat + interop_database_remove_addr_max_lat; +struct interop_database_remove_feature interop_database_remove_feature; +struct interop_database_remove_manufacturer + interop_database_remove_manufacturer; +struct interop_database_remove_name interop_database_remove_name; +struct interop_database_remove_version interop_database_remove_version; +struct interop_database_remove_vndr_prdt interop_database_remove_vndr_prdt; +struct interop_feature_name_to_feature_id interop_feature_name_to_feature_id; +struct interop_get_allowlisted_media_players_list + interop_get_allowlisted_media_players_list; +struct interop_match_addr interop_match_addr; +struct interop_match_addr_get_max_lat interop_match_addr_get_max_lat; +struct interop_match_addr_or_name interop_match_addr_or_name; +struct interop_match_manufacturer interop_match_manufacturer; +struct interop_match_name interop_match_name; +struct interop_match_vendor_product_ids interop_match_vendor_product_ids; +struct token_to_ul token_to_ul; + +} // namespace device_interop +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace device_interop { + +bool interop_database_match_addr::return_value = false; +bool interop_database_match_addr_get_lmp_ver::return_value = false; +bool interop_database_match_addr_get_max_lat::return_value = false; +bool interop_database_match_manufacturer::return_value = false; +bool interop_database_match_name::return_value = false; +bool interop_database_match_version::return_value = false; +bool interop_database_match_vndr_prdt::return_value = false; +bool interop_database_remove_addr::return_value = false; +bool interop_database_remove_addr_lmp_version::return_value = false; +bool interop_database_remove_addr_max_lat::return_value = false; +bool interop_database_remove_feature::return_value = false; +bool interop_database_remove_manufacturer::return_value = false; +bool interop_database_remove_name::return_value = false; +bool interop_database_remove_version::return_value = false; +bool interop_database_remove_vndr_prdt::return_value = false; +int interop_feature_name_to_feature_id::return_value = 0; +bool interop_get_allowlisted_media_players_list::return_value = false; +bool interop_match_addr::return_value = false; +bool interop_match_addr_get_max_lat::return_value = false; +bool interop_match_addr_or_name::return_value = false; +bool interop_match_manufacturer::return_value = false; +bool interop_match_name::return_value = false; +bool interop_match_vendor_product_ids::return_value = false; +bool token_to_ul::return_value = false; + +} // namespace device_interop +} // namespace mock +} // namespace test + +// Mocked functions, if any +void interop_database_add(const uint16_t feature, const RawAddress* addr, + size_t length) { inc_func_call_count(__func__); - return false; + test::mock::device_interop::interop_database_add(feature, addr, length); } -bool interop_match_name(const interop_feature_t feature, const char* name) { +void interop_database_add_addr(const uint16_t feature, const RawAddress* addr, + size_t length) { inc_func_call_count(__func__); - return false; + test::mock::device_interop::interop_database_add_addr(feature, addr, length); } -void interop_database_add(uint16_t feature, const RawAddress* addr, - size_t length) { +void interop_database_add_addr_lmp_version(const interop_feature_t feature, + const RawAddress* addr, + uint8_t lmp_ver, + uint16_t lmp_sub_ver) { inc_func_call_count(__func__); + test::mock::device_interop::interop_database_add_addr_lmp_version( + feature, addr, lmp_ver, lmp_sub_ver); } -void interop_database_clear() { inc_func_call_count(__func__); } - -bool interop_match_addr_or_name(const interop_feature_t feature, - const RawAddress* addr, - bt_status_t (*get_remote_device_property)( - const RawAddress*, bt_property_t*)) { +void interop_database_add_addr_max_lat(const interop_feature_t feature, + const RawAddress* addr, + uint16_t max_lat) { inc_func_call_count(__func__); - return false; + test::mock::device_interop::interop_database_add_addr_max_lat(feature, addr, + max_lat); } - -bool interop_match_manufacturer(const interop_feature_t feature, - uint16_t manufacturer) { +void interop_database_add_manufacturer(const interop_feature_t feature, + uint16_t manufacturer) { inc_func_call_count(__func__); - return false; + test::mock::device_interop::interop_database_add_manufacturer(feature, + manufacturer); } - -bool interop_match_vendor_product_ids(const interop_feature_t feature, - uint16_t vendor_id, uint16_t product_id) { +void interop_database_add_name(const uint16_t feature, const char* name) { inc_func_call_count(__func__); - return false; + test::mock::device_interop::interop_database_add_name(feature, name); +} +void interop_database_add_version(const interop_feature_t feature, + uint16_t version) { + inc_func_call_count(__func__); + test::mock::device_interop::interop_database_add_version(feature, version); +} +void interop_database_add_vndr_prdt(const interop_feature_t feature, + uint16_t vendor_id, uint16_t product_id) { + inc_func_call_count(__func__); + test::mock::device_interop::interop_database_add_vndr_prdt(feature, vendor_id, + product_id); +} +void interop_database_clear() { + inc_func_call_count(__func__); + test::mock::device_interop::interop_database_clear(); +} +bool interop_database_match_addr(const interop_feature_t feature, + const RawAddress* addr) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_match_addr(feature, addr); +} +bool interop_database_match_addr_get_lmp_ver(const interop_feature_t feature, + const RawAddress* addr, + uint8_t* lmp_ver, + uint16_t* lmp_sub_ver) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_match_addr_get_lmp_ver( + feature, addr, lmp_ver, lmp_sub_ver); +} +bool interop_database_match_addr_get_max_lat(const interop_feature_t feature, + const RawAddress* addr, + uint16_t* max_lat) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_match_addr_get_max_lat( + feature, addr, max_lat); +} +bool interop_database_match_manufacturer(const interop_feature_t feature, + uint16_t manufacturer) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_match_manufacturer( + feature, manufacturer); +} +bool interop_database_match_name(const interop_feature_t feature, + const char* name) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_match_name(feature, name); } - bool interop_database_match_version(const interop_feature_t feature, uint16_t version) { inc_func_call_count(__func__); - return false; + return test::mock::device_interop::interop_database_match_version(feature, + version); +} +bool interop_database_match_vndr_prdt(const interop_feature_t feature, + uint16_t vendor_id, uint16_t product_id) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_match_vndr_prdt( + feature, vendor_id, product_id); +} +bool interop_database_remove_addr(const interop_feature_t feature, + const RawAddress* addr) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_remove_addr(feature, + addr); +} +bool interop_database_remove_addr_lmp_version(const interop_feature_t feature, + const RawAddress* addr, + uint8_t lmp_ver, + uint16_t lmp_sub_ver) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_remove_addr_lmp_version( + feature, addr, lmp_ver, lmp_sub_ver); +} +bool interop_database_remove_addr_max_lat(const interop_feature_t feature, + const RawAddress* addr, + uint16_t max_lat) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_remove_addr_max_lat( + feature, addr, max_lat); +} +bool interop_database_remove_feature(const interop_feature_t feature) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_remove_feature(feature); +} +bool interop_database_remove_manufacturer(const interop_feature_t feature, + uint16_t manufacturer) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_remove_manufacturer( + feature, manufacturer); +} +bool interop_database_remove_name(const interop_feature_t feature, + const char* name) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_remove_name(feature, + name); +} +bool interop_database_remove_version(const interop_feature_t feature, + uint16_t version) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_remove_version(feature, + version); +} +bool interop_database_remove_vndr_prdt(const interop_feature_t feature, + uint16_t vendor_id, + uint16_t product_id) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_database_remove_vndr_prdt( + feature, vendor_id, product_id); +} +int interop_feature_name_to_feature_id(const char* feature_name) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_feature_name_to_feature_id( + feature_name); +} +bool interop_get_allowlisted_media_players_list(list_t* p_bl_devices) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_get_allowlisted_media_players_list( + p_bl_devices); +} +bool interop_match_addr(const interop_feature_t feature, + const RawAddress* addr) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_match_addr(feature, addr); } bool interop_match_addr_get_max_lat(const interop_feature_t feature, const RawAddress* addr, uint16_t* max_lat) { inc_func_call_count(__func__); - return false; + return test::mock::device_interop::interop_match_addr_get_max_lat( + feature, addr, max_lat); } - -bool interop_get_allowlisted_media_players_list(list_t* p_bl_devices) { +bool interop_match_addr_or_name(const interop_feature_t feature, + const RawAddress* addr, + bt_status_t (*get_remote_device_property)( + const RawAddress*, bt_property_t*)) { inc_func_call_count(__func__); - return false; + return test::mock::device_interop::interop_match_addr_or_name( + feature, addr, get_remote_device_property); } - -int interop_feature_name_to_feature_id(const char* feature_name) { +bool interop_match_manufacturer(const interop_feature_t feature, + uint16_t manufacturer) { inc_func_call_count(__func__); - return false; + return test::mock::device_interop::interop_match_manufacturer(feature, + manufacturer); } - -void interop_database_add_addr(const uint16_t feature, const RawAddress* addr, - size_t length) { +bool interop_match_name(const interop_feature_t feature, const char* name) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_match_name(feature, name); +} +bool interop_match_vendor_product_ids(const interop_feature_t feature, + uint16_t vendor_id, uint16_t product_id) { + inc_func_call_count(__func__); + return test::mock::device_interop::interop_match_vendor_product_ids( + feature, vendor_id, product_id); +} +bool token_to_ul(char* token, uint16_t* ul) { inc_func_call_count(__func__); + return test::mock::device_interop::token_to_ul(token, ul); } +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_device_interop.h b/system/test/mock/mock_device_interop.h new file mode 100644 index 0000000000000000000000000000000000000000..b0362a394814f8e836309cc67b0d5e4494b46f10 --- /dev/null +++ b/system/test/mock/mock_device_interop.h @@ -0,0 +1,536 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:34 + * + * mockcify.pl ver 0.6.2 + */ + +#include +#include + +// Original included files, if any + +#include "device/include/interop.h" +#include "osi/include/list.h" +#include "types/raw_address.h" + +// Original usings + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace device_interop { + +// Shared state between mocked functions and tests +// Name: interop_database_add +// Params: const uint16_t feature, const RawAddress* addr, size_t length +// Return: void +struct interop_database_add { + std::function + body{ + [](const uint16_t feature, const RawAddress* addr, size_t length) {}}; + void operator()(const uint16_t feature, const RawAddress* addr, + size_t length) { + body(feature, addr, length); + }; +}; +extern struct interop_database_add interop_database_add; + +// Name: interop_database_add_addr +// Params: const uint16_t feature, const RawAddress* addr, size_t length +// Return: void +struct interop_database_add_addr { + std::function + body{ + [](const uint16_t feature, const RawAddress* addr, size_t length) {}}; + void operator()(const uint16_t feature, const RawAddress* addr, + size_t length) { + body(feature, addr, length); + }; +}; +extern struct interop_database_add_addr interop_database_add_addr; + +// Name: interop_database_add_addr_lmp_version +// Params: const interop_feature_t feature, const RawAddress* addr, uint8_t +// lmp_ver, uint16_t lmp_sub_ver Return: void +struct interop_database_add_addr_lmp_version { + std::function + body{[](const interop_feature_t feature, const RawAddress* addr, + uint8_t lmp_ver, uint16_t lmp_sub_ver) {}}; + void operator()(const interop_feature_t feature, const RawAddress* addr, + uint8_t lmp_ver, uint16_t lmp_sub_ver) { + body(feature, addr, lmp_ver, lmp_sub_ver); + }; +}; +extern struct interop_database_add_addr_lmp_version + interop_database_add_addr_lmp_version; + +// Name: interop_database_add_addr_max_lat +// Params: const interop_feature_t feature, const RawAddress* addr, uint16_t +// max_lat Return: void +struct interop_database_add_addr_max_lat { + std::function + body{[](const interop_feature_t feature, const RawAddress* addr, + uint16_t max_lat) {}}; + void operator()(const interop_feature_t feature, const RawAddress* addr, + uint16_t max_lat) { + body(feature, addr, max_lat); + }; +}; +extern struct interop_database_add_addr_max_lat + interop_database_add_addr_max_lat; + +// Name: interop_database_add_manufacturer +// Params: const interop_feature_t feature, uint16_t manufacturer +// Return: void +struct interop_database_add_manufacturer { + std::function + body{[](const interop_feature_t feature, uint16_t manufacturer) {}}; + void operator()(const interop_feature_t feature, uint16_t manufacturer) { + body(feature, manufacturer); + }; +}; +extern struct interop_database_add_manufacturer + interop_database_add_manufacturer; + +// Name: interop_database_add_name +// Params: const uint16_t feature, const char* name +// Return: void +struct interop_database_add_name { + std::function body{ + [](const uint16_t feature, const char* name) {}}; + void operator()(const uint16_t feature, const char* name) { + body(feature, name); + }; +}; +extern struct interop_database_add_name interop_database_add_name; + +// Name: interop_database_add_version +// Params: const interop_feature_t feature, uint16_t version +// Return: void +struct interop_database_add_version { + std::function body{ + [](const interop_feature_t feature, uint16_t version) {}}; + void operator()(const interop_feature_t feature, uint16_t version) { + body(feature, version); + }; +}; +extern struct interop_database_add_version interop_database_add_version; + +// Name: interop_database_add_vndr_prdt +// Params: const interop_feature_t feature, uint16_t vendor_id, uint16_t +// product_id Return: void +struct interop_database_add_vndr_prdt { + std::function + body{[](const interop_feature_t feature, uint16_t vendor_id, + uint16_t product_id) {}}; + void operator()(const interop_feature_t feature, uint16_t vendor_id, + uint16_t product_id) { + body(feature, vendor_id, product_id); + }; +}; +extern struct interop_database_add_vndr_prdt interop_database_add_vndr_prdt; + +// Name: interop_database_clear +// Params: +// Return: void +struct interop_database_clear { + std::function body{[]() {}}; + void operator()() { body(); }; +}; +extern struct interop_database_clear interop_database_clear; + +// Name: interop_database_match_addr +// Params: const interop_feature_t feature, const RawAddress* addr +// Return: bool +struct interop_database_match_addr { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr) { + return body(feature, addr); + }; +}; +extern struct interop_database_match_addr interop_database_match_addr; + +// Name: interop_database_match_addr_get_lmp_ver +// Params: const interop_feature_t feature, const RawAddress* addr, uint8_t* +// lmp_ver, uint16_t* lmp_sub_ver Return: bool +struct interop_database_match_addr_get_lmp_ver { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr, + uint8_t* lmp_ver, + uint16_t* lmp_sub_ver) { return return_value; }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr, + uint8_t* lmp_ver, uint16_t* lmp_sub_ver) { + return body(feature, addr, lmp_ver, lmp_sub_ver); + }; +}; +extern struct interop_database_match_addr_get_lmp_ver + interop_database_match_addr_get_lmp_ver; + +// Name: interop_database_match_addr_get_max_lat +// Params: const interop_feature_t feature, const RawAddress* addr, uint16_t* +// max_lat Return: bool +struct interop_database_match_addr_get_max_lat { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr, + uint16_t* max_lat) { return return_value; }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr, + uint16_t* max_lat) { + return body(feature, addr, max_lat); + }; +}; +extern struct interop_database_match_addr_get_max_lat + interop_database_match_addr_get_max_lat; + +// Name: interop_database_match_manufacturer +// Params: const interop_feature_t feature, uint16_t manufacturer +// Return: bool +struct interop_database_match_manufacturer { + static bool return_value; + std::function + body{[](const interop_feature_t feature, uint16_t manufacturer) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, uint16_t manufacturer) { + return body(feature, manufacturer); + }; +}; +extern struct interop_database_match_manufacturer + interop_database_match_manufacturer; + +// Name: interop_database_match_name +// Params: const interop_feature_t feature, const char* name +// Return: bool +struct interop_database_match_name { + static bool return_value; + std::function body{ + [](const interop_feature_t feature, const char* name) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, const char* name) { + return body(feature, name); + }; +}; +extern struct interop_database_match_name interop_database_match_name; + +// Name: interop_database_match_version +// Params: const interop_feature_t feature, uint16_t version +// Return: bool +struct interop_database_match_version { + static bool return_value; + std::function body{ + [](const interop_feature_t feature, uint16_t version) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, uint16_t version) { + return body(feature, version); + }; +}; +extern struct interop_database_match_version interop_database_match_version; + +// Name: interop_database_match_vndr_prdt +// Params: const interop_feature_t feature, uint16_t vendor_id, uint16_t +// product_id Return: bool +struct interop_database_match_vndr_prdt { + static bool return_value; + std::function + body{[](const interop_feature_t feature, uint16_t vendor_id, + uint16_t product_id) { return return_value; }}; + bool operator()(const interop_feature_t feature, uint16_t vendor_id, + uint16_t product_id) { + return body(feature, vendor_id, product_id); + }; +}; +extern struct interop_database_match_vndr_prdt interop_database_match_vndr_prdt; + +// Name: interop_database_remove_addr +// Params: const interop_feature_t feature, const RawAddress* addr +// Return: bool +struct interop_database_remove_addr { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr) { + return body(feature, addr); + }; +}; +extern struct interop_database_remove_addr interop_database_remove_addr; + +// Name: interop_database_remove_addr_lmp_version +// Params: const interop_feature_t feature, const RawAddress* addr, uint8_t +// lmp_ver, uint16_t lmp_sub_ver Return: bool +struct interop_database_remove_addr_lmp_version { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr, + uint8_t lmp_ver, uint16_t lmp_sub_ver) { return return_value; }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr, + uint8_t lmp_ver, uint16_t lmp_sub_ver) { + return body(feature, addr, lmp_ver, lmp_sub_ver); + }; +}; +extern struct interop_database_remove_addr_lmp_version + interop_database_remove_addr_lmp_version; + +// Name: interop_database_remove_addr_max_lat +// Params: const interop_feature_t feature, const RawAddress* addr, uint16_t +// max_lat Return: bool +struct interop_database_remove_addr_max_lat { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr, + uint16_t max_lat) { return return_value; }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr, + uint16_t max_lat) { + return body(feature, addr, max_lat); + }; +}; +extern struct interop_database_remove_addr_max_lat + interop_database_remove_addr_max_lat; + +// Name: interop_database_remove_feature +// Params: const interop_feature_t feature +// Return: bool +struct interop_database_remove_feature { + static bool return_value; + std::function body{ + [](const interop_feature_t feature) { return return_value; }}; + bool operator()(const interop_feature_t feature) { return body(feature); }; +}; +extern struct interop_database_remove_feature interop_database_remove_feature; + +// Name: interop_database_remove_manufacturer +// Params: const interop_feature_t feature, uint16_t manufacturer +// Return: bool +struct interop_database_remove_manufacturer { + static bool return_value; + std::function + body{[](const interop_feature_t feature, uint16_t manufacturer) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, uint16_t manufacturer) { + return body(feature, manufacturer); + }; +}; +extern struct interop_database_remove_manufacturer + interop_database_remove_manufacturer; + +// Name: interop_database_remove_name +// Params: const interop_feature_t feature, const char* name +// Return: bool +struct interop_database_remove_name { + static bool return_value; + std::function body{ + [](const interop_feature_t feature, const char* name) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, const char* name) { + return body(feature, name); + }; +}; +extern struct interop_database_remove_name interop_database_remove_name; + +// Name: interop_database_remove_version +// Params: const interop_feature_t feature, uint16_t version +// Return: bool +struct interop_database_remove_version { + static bool return_value; + std::function body{ + [](const interop_feature_t feature, uint16_t version) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, uint16_t version) { + return body(feature, version); + }; +}; +extern struct interop_database_remove_version interop_database_remove_version; + +// Name: interop_database_remove_vndr_prdt +// Params: const interop_feature_t feature, uint16_t vendor_id, uint16_t +// product_id Return: bool +struct interop_database_remove_vndr_prdt { + static bool return_value; + std::function + body{[](const interop_feature_t feature, uint16_t vendor_id, + uint16_t product_id) { return return_value; }}; + bool operator()(const interop_feature_t feature, uint16_t vendor_id, + uint16_t product_id) { + return body(feature, vendor_id, product_id); + }; +}; +extern struct interop_database_remove_vndr_prdt + interop_database_remove_vndr_prdt; + +// Name: interop_feature_name_to_feature_id +// Params: const char* feature_name +// Return: int +struct interop_feature_name_to_feature_id { + static int return_value; + std::function body{ + [](const char* feature_name) { return return_value; }}; + int operator()(const char* feature_name) { return body(feature_name); }; +}; +extern struct interop_feature_name_to_feature_id + interop_feature_name_to_feature_id; + +// Name: interop_get_allowlisted_media_players_list +// Params: list_t* p_bl_devices +// Return: bool +struct interop_get_allowlisted_media_players_list { + static bool return_value; + std::function body{ + [](list_t* p_bl_devices) { return return_value; }}; + bool operator()(list_t* p_bl_devices) { return body(p_bl_devices); }; +}; +extern struct interop_get_allowlisted_media_players_list + interop_get_allowlisted_media_players_list; + +// Name: interop_match_addr +// Params: const interop_feature_t feature, const RawAddress* addr +// Return: bool +struct interop_match_addr { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr) { + return body(feature, addr); + }; +}; +extern struct interop_match_addr interop_match_addr; + +// Name: interop_match_addr_get_max_lat +// Params: const interop_feature_t feature, const RawAddress* addr, uint16_t* +// max_lat Return: bool +struct interop_match_addr_get_max_lat { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr, + uint16_t* max_lat) { return return_value; }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr, + uint16_t* max_lat) { + return body(feature, addr, max_lat); + }; +}; +extern struct interop_match_addr_get_max_lat interop_match_addr_get_max_lat; + +// Name: interop_match_addr_or_name +// Params: const interop_feature_t feature, const RawAddress* addr, bt_status_t +// (*get_remote_device_property Return: bool +struct interop_match_addr_or_name { + static bool return_value; + std::function + body{[](const interop_feature_t feature, const RawAddress* addr, + bt_status_t (*get_remote_device_property)( + const RawAddress*, bt_property_t*)) { return return_value; }}; + bool operator()(const interop_feature_t feature, const RawAddress* addr, + bt_status_t (*get_remote_device_property)(const RawAddress*, + bt_property_t*)) { + return body(feature, addr, get_remote_device_property); + }; +}; +extern struct interop_match_addr_or_name interop_match_addr_or_name; + +// Name: interop_match_manufacturer +// Params: const interop_feature_t feature, uint16_t manufacturer +// Return: bool +struct interop_match_manufacturer { + static bool return_value; + std::function + body{[](const interop_feature_t feature, uint16_t manufacturer) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, uint16_t manufacturer) { + return body(feature, manufacturer); + }; +}; +extern struct interop_match_manufacturer interop_match_manufacturer; + +// Name: interop_match_name +// Params: const interop_feature_t feature, const char* name +// Return: bool +struct interop_match_name { + static bool return_value; + std::function body{ + [](const interop_feature_t feature, const char* name) { + return return_value; + }}; + bool operator()(const interop_feature_t feature, const char* name) { + return body(feature, name); + }; +}; +extern struct interop_match_name interop_match_name; + +// Name: interop_match_vendor_product_ids +// Params: const interop_feature_t feature, uint16_t vendor_id, uint16_t +// product_id Return: bool +struct interop_match_vendor_product_ids { + static bool return_value; + std::function + body{[](const interop_feature_t feature, uint16_t vendor_id, + uint16_t product_id) { return return_value; }}; + bool operator()(const interop_feature_t feature, uint16_t vendor_id, + uint16_t product_id) { + return body(feature, vendor_id, product_id); + }; +}; +extern struct interop_match_vendor_product_ids interop_match_vendor_product_ids; + +// Name: token_to_ul +// Params: char* token, uint16_t* ul +// Return: bool +struct token_to_ul { + static bool return_value; + std::function body{ + [](char* token, uint16_t* ul) { return return_value; }}; + bool operator()(char* token, uint16_t* ul) { return body(token, ul); }; +}; +extern struct token_to_ul token_to_ul; + +} // namespace device_interop +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_device_iot_config.cc b/system/test/mock/mock_device_iot_config.cc index ffad039b979565417e9e5348410083e4f38bc86c..decabeecbbb1ed3b6bb35b7930be6abac53ebec2 100644 --- a/system/test/mock/mock_device_iot_config.cc +++ b/system/test/mock/mock_device_iot_config.cc @@ -13,15 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_device_iot_config.h" #include -#include -#include #include -// Mock include file to share data between tests and mock #include "test/common/mock_functions.h" -#include "test/mock/mock_device_iot_config.h" namespace test { namespace mock { diff --git a/system/test/mock/mock_device_iot_config.h b/system/test/mock/mock_device_iot_config.h index a3d9cd6deeb493118f25dc8355e1f3f27ad608fa..fd22398b5b0eeb5248528ac0eef26b6d26c87447 100644 --- a/system/test/mock/mock_device_iot_config.h +++ b/system/test/mock/mock_device_iot_config.h @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include +#include namespace test { namespace mock { diff --git a/system/test/mock/mock_frameworks_libaudio.cc b/system/test/mock/mock_frameworks_libaudio.cc index 62b3731e2aac0d9cbca5d1d63b6ba1fa31aa39fd..ac00199214fa4ebf934b4b83e8e9b05fa3e250d4 100644 --- a/system/test/mock/mock_frameworks_libaudio.cc +++ b/system/test/mock/mock_frameworks_libaudio.cc @@ -19,21 +19,15 @@ * Functions generated:60 */ -#include -#include - #include "test/common/mock_functions.h" -#undef __INTRODUCED_IN +#ifndef __INTRODUCED_IN #define __INTRODUCED_IN(x) +#endif // __INTRODUCED_IN #include #include -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - aaudio_allowed_capture_policy_t AAudioStream_getAllowedCapturePolicy( AAudioStream* stream) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_gd_os_logging_log_redaction.cc b/system/test/mock/mock_gd_os_logging_log_redaction.cc index 14dcaa0342a944fdcb55d728be14727793dbe02a..e3bbc410b0a74cd675ddbfc7bb2de88530ac8a5b 100644 --- a/system/test/mock/mock_gd_os_logging_log_redaction.cc +++ b/system/test/mock/mock_gd_os_logging_log_redaction.cc @@ -16,14 +16,11 @@ * ******************************************************************************/ -#include "common/init_flags.h" #include "os/logging/log_redaction.h" namespace bluetooth { namespace os { -using bluetooth::common::init_flags::redact_log_is_enabled; - bool should_log_be_redacted() { return false; } } // namespace os diff --git a/system/test/mock/mock_hcic_hcicmds.h b/system/test/mock/mock_hcic_hcicmds.h deleted file mode 100644 index efa39c9f5f13f835fcd8d8c320c89bfaf3d829f6..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_hcic_hcicmds.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:1 - * - * mockcify.pl ver 0.2 - */ - -#include -#include - -#include "test/common/mock_functions.h" - -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. - -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -namespace test { -namespace mock { -namespace hcic_hcicmds { - -struct btsnd_hcic_change_conn_type { - uint16_t handle; - uint16_t packet_types; -}; -extern struct btsnd_hcic_change_conn_type btsnd_hcic_change_conn_type; - -} // namespace hcic_hcicmds -} // namespace mock -} // namespace test - -// END mockcify generation diff --git a/system/test/mock/mock_le_audio_hal_verifier.cc b/system/test/mock/mock_le_audio_hal_verifier.cc index 0e985584e5a8964a7c67fea433212984496c42e6..d546e7dad40fd562e9aeda9753d973bf285a35e1 100644 --- a/system/test/mock/mock_le_audio_hal_verifier.cc +++ b/system/test/mock/mock_le_audio_hal_verifier.cc @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include #include "bta/include/bta_le_audio_api.h" #include "test/common/mock_functions.h" @@ -33,3 +31,8 @@ bool LeAudioHalVerifier::SupportsLeAudioBroadcast() { inc_func_call_count(__func__); return true; } + +bool LeAudioHalVerifier::SupportsStreamActiveApi() { + inc_func_call_count(__func__); + return true; +} diff --git a/system/test/mock/mock_legacy_hci_interface.cc b/system/test/mock/mock_legacy_hci_interface.cc new file mode 100644 index 0000000000000000000000000000000000000000..86cc5e36a68ff78f4c5596303b4ce3fe2f1f8ad2 --- /dev/null +++ b/system/test/mock/mock_legacy_hci_interface.cc @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test/mock/mock_legacy_hci_interface.h" + +#include + +#include "stack/include/hcimsgs.h" + +namespace bluetooth::legacy::hci { +namespace testing { +const MockInterface* interface_; +void SetMock(const MockInterface& mock) { interface_ = &mock; } +} // namespace testing +const Interface& GetInterface() { return *testing::interface_; } +} // namespace bluetooth::legacy::hci diff --git a/system/test/mock/mock_legacy_hci_interface.h b/system/test/mock/mock_legacy_hci_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..49d925b54ce86d6308bef642f7e16b12e2de8ba6 --- /dev/null +++ b/system/test/mock/mock_legacy_hci_interface.h @@ -0,0 +1,41 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "stack/include/hcimsgs.h" + +namespace bluetooth::legacy::hci::testing { +class MockInterface : public Interface { + public: + MOCK_METHOD(void, StartInquiry, + (const LAP inq_lap, uint8_t duration, uint8_t response_cnt), + (const)); + MOCK_METHOD(void, InquiryCancel, (), (const)); + MOCK_METHOD(void, Disconnect, (uint16_t handle, uint8_t reason), (const)); + MOCK_METHOD(void, ChangeConnectionPacketType, + (uint16_t handle, uint16_t packet_types), (const)); + MOCK_METHOD(void, StartRoleSwitch, (const RawAddress& bd_addr, uint8_t role), + (const)); + MOCK_METHOD(void, ConfigureDataPath, + (hci_data_direction_t data_path_direction, uint8_t data_path_id, + std::vector vendor_config), + (const)); +}; +void SetMock(const MockInterface& interface); +} // namespace bluetooth::legacy::hci::testing diff --git a/system/test/mock/mock_legacy_hci_iterface.cc b/system/test/mock/mock_legacy_hci_iterface.cc deleted file mode 100644 index a879f1bafaaf083e4e3ffa0d387d08b10c261157..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_legacy_hci_iterface.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include -#include - -#include "bt_target.h" -#include "btu.h" -#include "hcimsgs.h" -#include "stack/include/acl_hci_link_interface.h" -#include "stack/include/bt_octets.h" -#include "test/common/mock_functions.h" -#include "types/raw_address.h" - -namespace test { -namespace mock { -namespace hcic_hcicmds { - -struct btsnd_hcic_change_conn_type { - uint16_t handle{0}; - uint16_t packet_types{0}; -} btsnd_hcic_change_conn_type; - -} // namespace hcic_hcicmds -} // namespace mock -} // namespace test - -namespace mock = test::mock::hcic_hcicmds; - -namespace { -void btsnd_hcic_disconnect(uint16_t handle, uint8_t reason) { - inc_func_call_count(__func__); -} -void btsnd_hcic_switch_role(const RawAddress& bd_addr, uint8_t role) { - inc_func_call_count(__func__); -} -} // namespace - -bluetooth::legacy::hci::Interface interface_ = { - .Disconnect = btsnd_hcic_disconnect, - .StartRoleSwitch = btsnd_hcic_switch_role, - .ChangeConnectionPacketType = btsnd_hcic_change_conn_type, -}; - -const bluetooth::legacy::hci::Interface& -bluetooth::legacy::hci::GetInterface() { - return interface_; -} diff --git a/system/test/mock/mock_main_bte.cc b/system/test/mock/mock_main_bte.cc deleted file mode 100644 index 474531f2656178afee511cd0a7efd5f9815dbbcc..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_main_bte.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:3 - * - * mockcify.pl ver 0.2 - */ - -#include -#include -#include -#include - -// Mock include file to share data between tests and mock -#include "stack/include/bt_hdr.h" -#include "test/mock/mock_main_bte.h" - -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -// Mocked internal structures, if any - -namespace test { -namespace mock { -namespace main_bte { - -// Function state capture and return values, if needed -struct bte_main_init bte_main_init; -struct bte_main_hci_send bte_main_hci_send; - -} // namespace main_bte -} // namespace mock -} // namespace test - -// Mocked functions, if any -void bte_main_init(void) { - inc_func_call_count(__func__); - test::mock::main_bte::bte_main_init(); -} -void bte_main_hci_send(BT_HDR* p_msg, uint16_t event) { - inc_func_call_count(__func__); - test::mock::main_bte::bte_main_hci_send(p_msg, event); -} - -// END mockcify generation diff --git a/system/test/mock/mock_main_shim.cc b/system/test/mock/mock_main_shim.cc index a636338788551fe1bdd77b4e300fd36a829a2d69..8a7699d4165af26a09075d4b6bd6a468a29b8ce2 100644 --- a/system/test/mock/mock_main_shim.cc +++ b/system/test/mock/mock_main_shim.cc @@ -19,28 +19,11 @@ * Functions generated:14 */ -#include -#include - #define LOG_TAG "bt_shim" -#include "gd/common/init_flags.h" -#include "main/shim/entry.h" #include "main/shim/shim.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool bluetooth::shim::is_gd_l2cap_enabled() { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::is_gd_shim_enabled() { - inc_func_call_count(__func__); - return false; -} bool bluetooth::shim::is_classic_discovery_only_enabled() { inc_func_call_count(__func__); return false; @@ -54,10 +37,6 @@ bool bluetooth::shim::is_gd_stack_started_up() { inc_func_call_count(__func__); return test::mock::bluetooth_shim_is_gd_stack_started_up; } -bool bluetooth::shim::is_gd_link_policy_enabled() { - inc_func_call_count(__func__); - return false; -} future_t* GeneralShutDown() { inc_func_call_count(__func__); return nullptr; diff --git a/system/test/mock/mock_main_shim_BtifConfigInterface.cc b/system/test/mock/mock_main_shim_BtifConfigInterface.cc index f628b73541963f1cdb73542e3ebf906db2e7c07f..cdb4680debd1fd558a9f01daec8c0291cf07dde1 100644 --- a/system/test/mock/mock_main_shim_BtifConfigInterface.cc +++ b/system/test/mock/mock_main_shim_BtifConfigInterface.cc @@ -81,6 +81,7 @@ bool bluetooth::shim::BtifConfigInterface::RemoveProperty( const std::string& section, const std::string& key) { return false; } +void bluetooth::shim::BtifConfigInterface::RemoveSection(const std::string& section){}; std::vector bluetooth::shim::BtifConfigInterface::GetPersistentDevices() { return std::vector(); diff --git a/system/test/mock/mock_main_shim_acl.cc b/system/test/mock/mock_main_shim_acl.cc index af8b76c959bc9e0de4b3aa703f7988c7ceaa8359..4244b9446e739b259e5edba6d7502f5b4188dcf1 100644 --- a/system/test/mock/mock_main_shim_acl.cc +++ b/system/test/mock/mock_main_shim_acl.cc @@ -19,17 +19,7 @@ * Functions generated:7 */ -#include -#include -#include - #include "main/shim/acl_api.h" #include "test/common/mock_functions.h" -#include "types/ble_address_with_type.h" -#include "types/raw_address.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif void bluetooth::shim::ACL_Shutdown() { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_main_shim_acl_api.cc b/system/test/mock/mock_main_shim_acl_api.cc index edd4449a53ee2da9b30e7d11e106e50f41ddf14b..6107e430b37e0b37154bba2e9d5039dbe3842480 100644 --- a/system/test/mock/mock_main_shim_acl_api.cc +++ b/system/test/mock/mock_main_shim_acl_api.cc @@ -19,9 +19,7 @@ * Functions generated:5 */ -#include #include -#include #include #include "main/shim/acl_api.h" @@ -31,10 +29,6 @@ #include "types/ble_address_with_type.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void bluetooth::shim::ACL_CreateClassicConnection( const RawAddress& raw_address) { inc_func_call_count(__func__); @@ -65,9 +59,16 @@ void bluetooth::shim::ACL_Disconnect(uint16_t handle, bool is_classic, void bluetooth::shim::ACL_IgnoreAllLeConnections() { inc_func_call_count(__func__); } -void bluetooth::shim::ACL_ReadConnectionAddress(const RawAddress& pseudo_addr, +void bluetooth::shim::ACL_ReadConnectionAddress(uint16_t handle, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address) { + inc_func_call_count(__func__); +} +void bluetooth::shim::ACL_ReadPeerConnectionAddress(uint16_t handle, + RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address) { inc_func_call_count(__func__); } std::optional bluetooth::shim::ACL_GetAdvertisingSetConnectedTo( diff --git a/system/test/mock/mock_main_shim_acl_api.h b/system/test/mock/mock_main_shim_acl_api.h index 124a0e97e01508dd6b92e4dffed8c1da99063784..e43631777c471276a2e24f666340e6bbd9fcbf98 100644 --- a/system/test/mock/mock_main_shim_acl_api.h +++ b/system/test/mock/mock_main_shim_acl_api.h @@ -24,28 +24,13 @@ #include #include -#include +#include #include -#include "test/common/mock_functions.h" - // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include - -#include "gd/hci/acl_manager.h" -#include "main/shim/acl_api.h" -#include "main/shim/dumpsys.h" -#include "main/shim/helpers.h" -#include "main/shim/stack.h" -#include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_octets.h" +#include "stack/include/hci_error_code.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" @@ -208,20 +193,35 @@ struct ACL_IgnoreLeConnectionFrom { extern struct ACL_IgnoreLeConnectionFrom ACL_IgnoreLeConnectionFrom; // Name: ACL_ReadConnectionAddress -// Params: const RawAddress& pseudo_addr, RawAddress& conn_addr, tBLE_ADDR_TYPE* +// Params: uint16_t handle, RawAddress& conn_addr, tBLE_ADDR_TYPE*, bool // p_addr_type Return: void struct ACL_ReadConnectionAddress { - std::function - body{[](const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) {}}; - void operator()(const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - body(pseudo_addr, conn_addr, p_addr_type); + std::function + body{[](uint16_t handle, RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) {}}; + void operator()(uint16_t handle, RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { + body(handle, conn_addr, p_addr_type, ota_address); }; }; extern struct ACL_ReadConnectionAddress ACL_ReadConnectionAddress; +// Name: ACL_ReadPeerConnectionAddress +// Params: uint16_t handle, RawAddress& conn_addr, tBLE_ADDR_TYPE*, bool +// p_addr_type Return: void +struct ACL_ReadPeerConnectionAddress { + std::function + body{[](uint16_t handle, RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) {}}; + void operator()(uint16_t handle, RawAddress& conn_addr, + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { + body(handle, conn_addr, p_addr_type, ota_address); + }; +}; +extern struct ACL_ReadPeerConnectionAddress ACL_ReadPeerConnectionAddress; + // Name: ACL_GetAdvertisingSetConnectedTo // Params: const RawAddress& addr // Return: std::optional diff --git a/system/test/mock/mock_main_shim_activity_attribution.cc b/system/test/mock/mock_main_shim_activity_attribution.cc deleted file mode 100644 index 3b67f5aac96619182392993e4abbd30d17404d87..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_main_shim_activity_attribution.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:3 - */ - -#include -#include - -#include "btif/include/btif_common.h" -#include "main/shim/activity_attribution.h" -#include "main/shim/entry.h" -#include "test/common/mock_functions.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -ActivityAttributionInterface* -bluetooth::shim::get_activity_attribution_instance() { - inc_func_call_count(__func__); - return nullptr; -} -void bluetooth::shim::init_activity_attribution() { - inc_func_call_count(__func__); -} diff --git a/system/test/mock/mock_main_shim_btm_api.cc b/system/test/mock/mock_main_shim_btm_api.cc index 2cf7689927f5e3c8acbe0373b1f46b4cbb798836..94f1c599749f6c59190791af9d0971df7e6b336e 100644 --- a/system/test/mock/mock_main_shim_btm_api.cc +++ b/system/test/mock/mock_main_shim_btm_api.cc @@ -19,56 +19,20 @@ * Functions generated:85 */ -#include -#include -#include - #include #include +#include + #include "main/shim/btm_api.h" -#include "stack/include/bt_hdr.h" #include "stack/include/bt_octets.h" #include "stack/include/btm_ble_api_types.h" #include "test/common/mock_functions.h" -#include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - Octet16 octet16; -bool bluetooth::shim::BTM_BleDataSignature(const RawAddress& bd_addr, - uint8_t* p_text, uint16_t len, - BLE_SIGNATURE signature) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_BleLocalPrivacyEnabled(void) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_BleSecurityProcedureIsRunning( - const RawAddress& bd_addr) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_BleVerifySignature(const RawAddress& bd_addr, - uint8_t* p_orig, uint16_t len, - uint32_t counter, - uint8_t* p_comp) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_GetLeSecurityState(const RawAddress& bd_addr, - uint8_t* p_le_dev_sec_flags, - uint8_t* p_le_key_size) { - inc_func_call_count(__func__); - return false; -} bool bluetooth::shim::BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16) { inc_func_call_count(__func__); @@ -81,61 +45,11 @@ bool bluetooth::shim::BTM_ReadConnectedTransportAddress( } bool bluetooth::shim::BTM_ReadRemoteConnectionAddr( const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_SecAddDevice(const RawAddress& bd_addr, - DEV_CLASS dev_class, - const BD_NAME& bd_name, - uint8_t* features, LinkKey* link_key, - uint8_t key_type, uint8_t pin_length) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_SecAddRmtNameNotifyCallback( - tBTM_RMT_NAME_CALLBACK* p_callback) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_SecDeleteDevice(const RawAddress& bd_addr) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_SecDeleteRmtNameNotifyCallback( - tBTM_RMT_NAME_CALLBACK* p_callback) { - inc_func_call_count(__func__); - return false; -} -bool bluetooth::shim::BTM_SecRegister(const tBTM_APPL_INFO* bta_callbacks) { + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { inc_func_call_count(__func__); return false; } -bool bluetooth::shim::BTM_UseLeLink(const RawAddress& raw_address) { - inc_func_call_count(__func__); - return false; -} -char* bluetooth::shim::BTM_SecReadDevName(const RawAddress& address) { - inc_func_call_count(__func__); - return nullptr; -} -const Octet16& bluetooth::shim::BTM_GetDeviceEncRoot() { - inc_func_call_count(__func__); - return octet16; -} -const Octet16& bluetooth::shim::BTM_GetDeviceDHK() { - inc_func_call_count(__func__); - return octet16; -} -const Octet16& bluetooth::shim::BTM_GetDeviceIDRoot() { - inc_func_call_count(__func__); - return octet16; -} -tBTM_EIR_SEARCH_RESULT bluetooth::shim::BTM_HasInquiryEirService( - tBTM_INQ_RESULTS* p_results, uint16_t uuid16) { - inc_func_call_count(__func__); - return 0; -} + tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbFirst(void) { inc_func_call_count(__func__); return nullptr; @@ -176,17 +90,7 @@ tBTM_STATUS bluetooth::shim::BTM_ReadRemoteDeviceName( inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS bluetooth::shim::BTM_SecBond(const RawAddress& bd_addr, - tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, - tBT_DEVICE_TYPE device_type) { - inc_func_call_count(__func__); - return BTM_SUCCESS; -} -tBTM_STATUS bluetooth::shim::BTM_SecBondCancel(const RawAddress& bd_addr) { - inc_func_call_count(__func__); - return BTM_SUCCESS; -} + tBTM_STATUS bluetooth::shim::BTM_SetConnectability(uint16_t page_mode, uint16_t window, uint16_t interval) { @@ -203,14 +107,7 @@ tBTM_STATUS bluetooth::shim::BTM_SetDiscoverability(uint16_t discoverable_mode, inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS bluetooth::shim::BTM_SetEncryption(const RawAddress& bd_addr, - tBT_TRANSPORT transport, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data, - tBTM_BLE_SEC_ACT sec_act) { - inc_func_call_count(__func__); - return BTM_SUCCESS; -} + tBTM_STATUS bluetooth::shim::BTM_SetInquiryMode(uint8_t inquiry_mode) { inc_func_call_count(__func__); return BTM_SUCCESS; @@ -220,13 +117,7 @@ tBTM_STATUS bluetooth::shim::BTM_StartInquiry(tBTM_INQ_RESULTS_CB* p_results_cb, inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS bluetooth::shim::btm_sec_mx_access_request( - const RawAddress& bd_addr, bool is_originator, - uint16_t security_requirement, tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data) { - inc_func_call_count(__func__); - return BTM_SUCCESS; -} + uint16_t bluetooth::shim::BTM_GetHCIConnHandle(const RawAddress& remote_bda, tBT_TRANSPORT transport) { inc_func_call_count(__func__); @@ -236,10 +127,7 @@ uint16_t bluetooth::shim::BTM_IsInquiryActive(void) { inc_func_call_count(__func__); return 0; } -uint8_t bluetooth::shim::BTM_BleGetSupportedKeySize(const RawAddress& bd_addr) { - inc_func_call_count(__func__); - return 0; -} + uint8_t bluetooth::shim::BTM_BleMaxMultiAdvInstanceCount() { inc_func_call_count(__func__); return 0; @@ -253,36 +141,12 @@ void bluetooth::shim::BTM_BleAdvFilterParamSetup( tBTM_BLE_PF_PARAM_CB cb) { inc_func_call_count(__func__); } -void bluetooth::shim::BTM_BleEnableDisableFilterFeature( - uint8_t enable, tBTM_BLE_PF_STATUS_CBACK p_stat_cback) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_BleLoadLocalKeys(uint8_t key_type, - tBTM_BLE_LOCAL_KEYS* p_key) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_BleOobDataReply(const RawAddress& bd_addr, - uint8_t res, uint8_t len, - uint8_t* p_data) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_BleReadPhy( - const RawAddress& bd_addr, - base::Callback cb) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_BleSecureConnectionOobDataReply( - const RawAddress& bd_addr, uint8_t* p_c, uint8_t* p_r) { - inc_func_call_count(__func__); -} + void bluetooth::shim::BTM_BleSetConnScanParams(uint32_t scan_interval, uint32_t scan_window) { inc_func_call_count(__func__); } -void bluetooth::shim::BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, - uint8_t rx_phys, uint16_t phy_options) { - inc_func_call_count(__func__); -} + void bluetooth::shim::BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int, uint16_t max_conn_int, @@ -290,104 +154,23 @@ void bluetooth::shim::BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t supervision_tout) { inc_func_call_count(__func__); } -void bluetooth::shim::BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy) { - inc_func_call_count(__func__); -} + void bluetooth::shim::BTM_CancelInquiry(void) { inc_func_call_count(__func__); } -void bluetooth::shim::BTM_ConfirmReqReply(tBTM_STATUS res, - const RawAddress& bd_addr) { - inc_func_call_count(__func__); -} + void bluetooth::shim::BTM_EnableInterlacedInquiryScan() { inc_func_call_count(__func__); } void bluetooth::shim::BTM_EnableInterlacedPageScan() { inc_func_call_count(__func__); } -void bluetooth::shim::BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - tBLE_BD_ADDR addr, - tBTM_BLE_PF_CFG_CBACK cb) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_CFG_CBACK cb) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector name, - tBTM_BLE_PF_CFG_CBACK cb) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_LE_PF_manu_data( - tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, - uint16_t company_id, uint16_t company_id_mask, std::vector data, - std::vector data_mask, tBTM_BLE_PF_CFG_CBACK cb) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector commands, - tBTM_BLE_PF_CFG_CBACK cb) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_LE_PF_srvc_data_pattern( - tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector data, std::vector data_mask, - tBTM_BLE_PF_CFG_CBACK cb) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action, - tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_COND_TYPE filter_type, - const bluetooth::Uuid& uuid, - tBTM_BLE_PF_LOGIC_TYPE cond_logic, - const bluetooth::Uuid& uuid_mask, - tBTM_BLE_PF_CFG_CBACK cb) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_PINCodeReply(const RawAddress& bd_addr, - tBTM_STATUS res, uint8_t pin_len, - uint8_t* p_pin) { - inc_func_call_count(__func__); -} + void bluetooth::shim::BTM_ReadConnectionAddr(const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_ReadDevInfo(const RawAddress& remote_bda, - tBT_DEVICE_TYPE* p_dev_type, - tBLE_ADDR_TYPE* p_addr_type) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_RemoteOobDataReply(tBTM_STATUS res, - const RawAddress& bd_addr, - const Octet16& c, - const Octet16& r) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_SecAddBleDevice(const RawAddress& bd_addr, - tBT_DEVICE_TYPE dev_type, - tBLE_ADDR_TYPE addr_type) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_SecAddBleKey(const RawAddress& bd_addr, - tBTM_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_SecClearSecurityFlags(const RawAddress& bd_addr) { - inc_func_call_count(__func__); -} -void bluetooth::shim::BTM_SecurityGrant(const RawAddress& bd_addr, - uint8_t res) { + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address) { inc_func_call_count(__func__); } + void bluetooth::shim::SendRemoteNameRequest(const RawAddress& raw_address) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_main_shim_controller.cc b/system/test/mock/mock_main_shim_controller.cc index 9def4daa634cfa9431fedc439fcdc1a8f2b5fd19..9d4bffc60cfdc5e7ca1ae335462930f1df6a4b92 100644 --- a/system/test/mock/mock_main_shim_controller.cc +++ b/system/test/mock/mock_main_shim_controller.cc @@ -19,20 +19,19 @@ * Functions generated:9 */ -#include -#include - #include "device/include/controller.h" #include "main/shim/controller.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +namespace bluetooth { +namespace testing { +const controller_t* controller{nullptr}; +} +} // namespace bluetooth const controller_t* bluetooth::shim::controller_get_interface() { inc_func_call_count(__func__); - return nullptr; + return bluetooth::testing::controller; } void bluetooth::shim::controller_clear_event_mask() { diff --git a/system/btif/include/btif_activity_attribution.h b/system/test/mock/mock_main_shim_controller.h similarity index 75% rename from system/btif/include/btif_activity_attribution.h rename to system/test/mock/mock_main_shim_controller.h index 44b585575028a9c436d21f9200d9c3be4af26685..c15e47faaa924d84bc99f540443ed6a4b2acc983 100644 --- a/system/btif/include/btif_activity_attribution.h +++ b/system/test/mock/mock_main_shim_controller.h @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,12 +14,12 @@ * limitations under the License. */ -#include +#include "device/include/controller.h" namespace bluetooth { -namespace activity_attribution { +namespace testing { -ActivityAttributionInterface* get_activity_attribution_instance(); +extern const controller_t* controller; } } // namespace bluetooth diff --git a/system/test/mock/mock_main_shim_distance_measurement_manager.cc b/system/test/mock/mock_main_shim_distance_measurement_manager.cc index 3a578d8e8d8527373791c59e806d95921ceefd3b..67953f3014dc5710731b9dba9b7ca9af03f92771 100644 --- a/system/test/mock/mock_main_shim_distance_measurement_manager.cc +++ b/system/test/mock/mock_main_shim_distance_measurement_manager.cc @@ -19,19 +19,9 @@ * Functions generated:3 */ -#include -#include -#include - -#include "btif/include/btif_common.h" -#include "gd/common/init_flags.h" #include "main/shim/distance_measurement_manager.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - DistanceMeasurementInterface* bluetooth::shim::get_distance_measurement_instance() { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_main_shim_dumpsys.cc b/system/test/mock/mock_main_shim_dumpsys.cc index 1fab0c545cf50f130efd9fb7f37398755b0afe7b..0f3f773ef012773605d8c3f7d92c45efa45f8710 100644 --- a/system/test/mock/mock_main_shim_dumpsys.cc +++ b/system/test/mock/mock_main_shim_dumpsys.cc @@ -19,18 +19,9 @@ * Functions generated:4 */ -#include -#include - #include "main/shim/dumpsys.h" -#include "main/shim/entry.h" -#include "main/shim/shim.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void bluetooth::shim::RegisterDumpsysFunction(const void* token, DumpsysFunction func) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_main_shim_entry.cc b/system/test/mock/mock_main_shim_entry.cc index 4c49410f444ff5a2dc2a539430798c163541f32d..44438034cc60652ecc23cc2c2c2478db291439e4 100644 --- a/system/test/mock/mock_main_shim_entry.cc +++ b/system/test/mock/mock_main_shim_entry.cc @@ -18,18 +18,17 @@ #include "gd/hci/controller_mock.h" #include "gd/hci/distance_measurement_manager_mock.h" #include "gd/hci/hci_layer.h" +#include "gd/hci/hci_layer_mock.h" #include "gd/hci/le_advertising_manager_mock.h" #include "gd/hci/le_scanning_manager_mock.h" #include "gd/neighbor/connectability.h" #include "gd/neighbor/discoverability.h" #include "gd/neighbor/inquiry.h" -#include "gd/neighbor/inquiry_mock.h" #include "gd/neighbor/page.h" #include "gd/os/handler.h" #include "gd/security/security_module.h" #include "gd/storage/storage_module.h" #include "main/shim/entry.h" -#include "main/shim/stack.h" namespace bluetooth { namespace hci { @@ -37,6 +36,7 @@ namespace testing { MockAclManager* mock_acl_manager_{nullptr}; MockController* mock_controller_{nullptr}; +MockHciLayer* mock_hci_layer_{nullptr}; os::Handler* mock_gd_shim_handler_{nullptr}; MockLeAdvertisingManager* mock_le_advertising_manager_{nullptr}; MockLeScanningManager* mock_le_scanning_manager_{nullptr}; @@ -50,12 +50,9 @@ class Dumpsys; namespace shim { Dumpsys* GetDumpsys() { return nullptr; } -activity_attribution::ActivityAttribution* GetActivityAttribution() { - return nullptr; -} hci::AclManager* GetAclManager() { return hci::testing::mock_acl_manager_; } hci::Controller* GetController() { return hci::testing::mock_controller_; } -hci::HciLayer* GetHciLayer() { return nullptr; } +hci::HciLayer* GetHciLayer() { return hci::testing::mock_hci_layer_; } hci::LeAdvertisingManager* GetAdvertising() { return hci::testing::mock_le_advertising_manager_; } diff --git a/system/test/mock/mock_main_shim_entry.h b/system/test/mock/mock_main_shim_entry.h index 3a71fd6be4399f49dbae1522f80f7bb701dbaa6c..2285edea0de279cb292e062b935a58d721063aaf 100644 --- a/system/test/mock/mock_main_shim_entry.h +++ b/system/test/mock/mock_main_shim_entry.h @@ -16,6 +16,8 @@ #include "hci/acl_manager_mock.h" #include "hci/controller_mock.h" +#include "hci/distance_measurement_manager_mock.h" +#include "hci/hci_layer_mock.h" #include "hci/le_advertising_manager_mock.h" #include "hci/le_scanning_manager_mock.h" @@ -25,6 +27,8 @@ namespace testing { extern MockAclManager* mock_acl_manager_; extern MockController* mock_controller_; +extern MockHciLayer* mock_hci_layer_; +extern os::Handler* mock_gd_shim_handler_; extern MockLeAdvertisingManager* mock_le_advertising_manager_; extern MockLeScanningManager* mock_le_scanning_manager_; extern MockDistanceMeasurementManager* mock_distance_measurement_manager_; diff --git a/system/test/mock/mock_main_shim_hci_layer.cc b/system/test/mock/mock_main_shim_hci_layer.cc index 6b6b5bf7d89935a3fa6acc5da6199c86d373f87e..46031a613b805cb668ea37ff1719b00e88935406 100644 --- a/system/test/mock/mock_main_shim_hci_layer.cc +++ b/system/test/mock/mock_main_shim_hci_layer.cc @@ -21,16 +21,9 @@ * mockcify.pl ver 0.3.0 */ -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_main_shim_hci_layer.h" // Mocked internal structures, if any -const hci_t* bluetooth::shim::hci_layer_get_interface() { return nullptr; } - -// bool hci_is_root_inflammation_event_received() { return false; } +const hci_t* bluetooth::shim::hci_layer_get_interface() { return nullptr; } \ No newline at end of file diff --git a/system/test/mock/mock_main_shim_hci_layer.h b/system/test/mock/mock_main_shim_hci_layer.h index 21723da9d8c54f10669a7bcff3b0399ecedd15f8..69d6548099e0163e9903ae15ed5cb557fda0f200 100644 --- a/system/test/mock/mock_main_shim_hci_layer.h +++ b/system/test/mock/mock_main_shim_hci_layer.h @@ -23,17 +23,5 @@ * mockcify.pl ver 0.3.0 */ -#include -#include -#include -#include - -#include "test/common/mock_functions.h" - // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include "main/shim/hci_layer.h" diff --git a/system/test/mock/mock_main_shim_l2cap_api.cc b/system/test/mock/mock_main_shim_l2cap_api.cc index eaf8e3bf8d830ab749e6e1b51818e78c1775fa03..e0cfe37ee67af1697d1ecdf97b60740d8267ea3a 100644 --- a/system/test/mock/mock_main_shim_l2cap_api.cc +++ b/system/test/mock/mock_main_shim_l2cap_api.cc @@ -24,17 +24,13 @@ #include "test/mock/mock_main_shim_l2cap_api.h" #include -#include -#include -#include // Mock include file to share data between tests and mock -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +#include "main/shim/l2c_api.h" +#include "test/common/mock_functions.h" +// Mocked compile conditionals, if any // Mocked internal structures, if any namespace test { @@ -44,7 +40,6 @@ namespace main_shim_l2cap_api { // Function state capture and return values, if needed struct L2CA_ReadRemoteVersion L2CA_ReadRemoteVersion; struct L2CA_ReadRemoteFeatures L2CA_ReadRemoteFeatures; -struct L2CA_UseLegacySecurityModule L2CA_UseLegacySecurityModule; struct L2CA_Register L2CA_Register; struct L2CA_Deregister L2CA_Deregister; struct L2CA_ConnectReq L2CA_ConnectReq; @@ -105,10 +100,6 @@ uint8_t* bluetooth::shim::L2CA_ReadRemoteFeatures(const RawAddress& addr) { inc_func_call_count(__func__); return test::mock::main_shim_l2cap_api::L2CA_ReadRemoteFeatures(addr); } -void bluetooth::shim::L2CA_UseLegacySecurityModule() { - inc_func_call_count(__func__); - test::mock::main_shim_l2cap_api::L2CA_UseLegacySecurityModule(); -} uint16_t bluetooth::shim::L2CA_Register( uint16_t client_psm, const tL2CAP_APPL_INFO& callbacks, bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, diff --git a/system/test/mock/mock_main_shim_l2cap_api.h b/system/test/mock/mock_main_shim_l2cap_api.h index 5277c63832a77e3d57b016371184b0f93689c5d3..3905742bb92cd6d53cc38130f18432d9ade4cc35 100644 --- a/system/test/mock/mock_main_shim_l2cap_api.h +++ b/system/test/mock/mock_main_shim_l2cap_api.h @@ -23,44 +23,14 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include -#include -#include - -#include "bta/include/bta_dm_acl.h" -#include "gd/os/log.h" -#include "gd/os/queue.h" -#include "main/shim/acl_api.h" -#include "main/shim/entry.h" -#include "main/shim/helpers.h" -#include "main/shim/l2c_api.h" -#include "osi/include/allocator.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_sec.h" -#include "stack/include/acl_hci_link_interface.h" -#include "stack/include/ble_acl_interface.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_api.h" -#include "stack/include/gatt_api.h" -#include "stack/include/sco_hci_link_interface.h" -#include "test/common/mock_functions.h" +#include "stack/include/l2c_api.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace main_shim_l2cap_api { @@ -90,14 +60,6 @@ struct L2CA_ReadRemoteFeatures { uint8_t* operator()(const RawAddress& addr) { return body(addr); }; }; extern struct L2CA_ReadRemoteFeatures L2CA_ReadRemoteFeatures; -// Name: L2CA_UseLegacySecurityModule -// Params: -// Returns: void -struct L2CA_UseLegacySecurityModule { - std::function body{[]() {}}; - void operator()() { body(); }; -}; -extern struct L2CA_UseLegacySecurityModule L2CA_UseLegacySecurityModule; // Name: L2CA_Register // Params: uint16_t client_psm, const tL2CAP_APPL_INFO& callbacks, bool // enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t diff --git a/system/test/mock/mock_main_shim_le_advertising_manager.cc b/system/test/mock/mock_main_shim_le_advertising_manager.cc index 7c95a5aac5d3eb2b39870a93e1bf26f332bf9270..f8488dabfc832f102f34de0604943fa9c9421d39 100644 --- a/system/test/mock/mock_main_shim_le_advertising_manager.cc +++ b/system/test/mock/mock_main_shim_le_advertising_manager.cc @@ -19,21 +19,10 @@ * Functions generated:3 */ -#include -#include -#include - -#include "btif/include/btif_common.h" -#include "gd/common/init_flags.h" #include "include/hardware/ble_advertiser.h" #include "main/shim/le_advertising_manager.h" -#include "stack/include/ble_advertiser.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - BleAdvertiserInterface* bluetooth::shim::get_ble_advertiser_instance() { inc_func_call_count(__func__); return nullptr; diff --git a/system/test/mock/mock_main_shim_le_scanning_manager.cc b/system/test/mock/mock_main_shim_le_scanning_manager.cc index 73e68fec11f218a909a051de43dc36f953005029..58fd38e36856e538f902c4dc0ee9641c8bad92aa 100644 --- a/system/test/mock/mock_main_shim_le_scanning_manager.cc +++ b/system/test/mock/mock_main_shim_le_scanning_manager.cc @@ -19,17 +19,10 @@ * Functions generated:3 */ -#include -#include - #include "include/hardware/ble_scanner.h" #include "main/shim/le_scanning_manager.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - ::BleScannerInterface* bluetooth::shim::get_ble_scanner_instance() { inc_func_call_count(__func__); return nullptr; @@ -51,4 +44,4 @@ void bluetooth::shim::set_empty_filter(bool enable) { void bluetooth::shim::set_target_announcements_filter(bool enable) { inc_func_call_count(__func__); -} \ No newline at end of file +} diff --git a/system/test/mock/mock_main_shim_metric_id_api.cc b/system/test/mock/mock_main_shim_metric_id_api.cc index 35875c58e8f1839bc33fe06a566745535d4e2163..3c49f494ac046a2b598b3fa7b63165067b289737 100644 --- a/system/test/mock/mock_main_shim_metric_id_api.cc +++ b/system/test/mock/mock_main_shim_metric_id_api.cc @@ -19,19 +19,10 @@ * Functions generated:7 */ -#include -#include - -#include "gd/common/metric_id_manager.h" #include "main/shim/metric_id_api.h" -#include "main/shim/shim.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace bluetooth { namespace shim { diff --git a/system/test/mock/mock_main_shim_metrics_api.cc b/system/test/mock/mock_main_shim_metrics_api.cc index 4be7bd0e2902582ea747da3d749128e57c30264c..3c1615fd3321a515df579270715ac86289560309 100644 --- a/system/test/mock/mock_main_shim_metrics_api.cc +++ b/system/test/mock/mock_main_shim_metrics_api.cc @@ -20,30 +20,18 @@ * * mockcify.pl ver 0.2 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_main_shim_metrics_api.h" #include -#include -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "gd/hci/address.h" -#include "main/shim/helpers.h" +#include "main/shim/metrics_api.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" -// Mock include file to share data between tests and mock -#include "test/mock/mock_main_shim_metrics_api.h" - // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -56,6 +44,7 @@ struct LogMetricA2dpAudioUnderrunEvent LogMetricA2dpAudioUnderrunEvent; struct LogMetricA2dpAudioOverrunEvent LogMetricA2dpAudioOverrunEvent; struct LogMetricA2dpPlaybackEvent LogMetricA2dpPlaybackEvent; struct LogMetricHfpPacketLossStats LogMetricHfpPacketLossStats; +struct LogMetricMmcTranscodeRttStats LogMetricMmcTranscodeRttStats; struct LogMetricReadRssiResult LogMetricReadRssiResult; struct LogMetricReadFailedContactCounterResult LogMetricReadFailedContactCounterResult; @@ -106,10 +95,19 @@ void bluetooth::shim::LogMetricA2dpPlaybackEvent(const RawAddress& raw_address, } void bluetooth::shim::LogMetricHfpPacketLossStats(const RawAddress& raw_address, int num_decoded_frames, - double packet_loss_ratio) { + double packet_loss_ratio, + uint16_t codec_type) { inc_func_call_count(__func__); test::mock::main_shim_metrics_api::LogMetricHfpPacketLossStats( - raw_address, num_decoded_frames, packet_loss_ratio); + raw_address, num_decoded_frames, packet_loss_ratio, codec_type); +} +void bluetooth::shim::LogMetricMmcTranscodeRttStats(int maximum_rtt, + double mean_rtt, + int num_requests, + int codec_type) { + inc_func_call_count(__func__); + test::mock::main_shim_metrics_api::LogMetricMmcTranscodeRttStats( + maximum_rtt, mean_rtt, num_requests, codec_type); } void bluetooth::shim::LogMetricReadRssiResult(const RawAddress& raw_address, uint16_t handle, @@ -195,5 +193,4 @@ void bluetooth::shim::LogMetricBluetoothLEConnectionMetricEvent( inc_func_call_count(__func__); // test::mock::main_shim_metrics_api::LogMetricBluetoothLEConnectionMetricEvent(raw_address, origin_type, connection_type, transaction_state, argument_list); } - // END mockcify generation diff --git a/system/test/mock/mock_main_shim_metrics_api.h b/system/test/mock/mock_main_shim_metrics_api.h index c8b850ecedd62f47029b385aac76c7caeda71a58..acfe15a6a1b0388d6eaef6226a54a4233c42b7c1 100644 --- a/system/test/mock/mock_main_shim_metrics_api.h +++ b/system/test/mock/mock_main_shim_metrics_api.h @@ -23,30 +23,15 @@ #include #include -#include #include -#include "test/common/mock_functions.h" - // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "gd/hci/address.h" -#include "gd/os/metrics.h" -#include "main/shim/helpers.h" -#include "main/shim/metrics_api.h" -#include "types/raw_address.h" #include +#include "gd/os/metrics.h" +#include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace main_shim_metrics_api { @@ -131,18 +116,32 @@ struct LogMetricA2dpPlaybackEvent { extern struct LogMetricA2dpPlaybackEvent LogMetricA2dpPlaybackEvent; // Name: LogMetricHfpPacketLossStats // Params: const RawAddress& raw_address, int num_decoded_frames, double -// packet_loss_ratio Returns: void +// packet_loss_ratio, uint16_t codec_type Returns: void struct LogMetricHfpPacketLossStats { std::function + double packet_loss_ratio, uint16_t codec_type)> body{[](const RawAddress& raw_address, int num_decoded_frames, - double packet_loss_ratio) {}}; + double packet_loss_ratio, uint16_t codec_type) {}}; void operator()(const RawAddress& raw_address, int num_decoded_frames, - double packet_loss_ratio) { - body(raw_address, num_decoded_frames, packet_loss_ratio); + double packet_loss_ratio, uint16_t codec_type) { + body(raw_address, num_decoded_frames, packet_loss_ratio, codec_type); }; }; extern struct LogMetricHfpPacketLossStats LogMetricHfpPacketLossStats; +// Name: LogMetricMmcTranscodeRttStats +// Params: int maximum_rtt, double mean_rtt, int num_requests, int codec_type +// Return: void +struct LogMetricMmcTranscodeRttStats { + std::function + body{[](int maximum_rtt, double mean_rtt, int num_requests, + int codec_type) {}}; + void operator()(int maximum_rtt, double mean_rtt, int num_requests, + int codec_type) { + body(maximum_rtt, mean_rtt, num_requests, codec_type); + }; +}; +extern struct LogMetricMmcTranscodeRttStats LogMetricMmcTranscodeRttStats; // Name: LogMetricReadRssiResult // Params: const RawAddress& raw_address, uint16_t handle, uint32_t cmd_status, // int8_t rssi Returns: void diff --git a/system/test/mock/mock_osi_alarm.cc b/system/test/mock/mock_osi_alarm.cc index e9860a551b98da9a9d198354dc96fe03cc873fe2..b84a61ef651d68cf3a13a298e9c4f6c153757a89 100644 --- a/system/test/mock/mock_osi_alarm.cc +++ b/system/test/mock/mock_osi_alarm.cc @@ -20,14 +20,12 @@ * * mockcify.pl ver 0.3.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_osi_alarm.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_osi_alarm.h" +#include "test/common/mock_functions.h" // Mocked internal structures, if any diff --git a/system/test/mock/mock_osi_alarm.h b/system/test/mock/mock_osi_alarm.h index 7ffdbd3b11e2c6669622bbf3e61d69aac9248a22..339a5b1098f6082e3f3ce06eba7fe327f6db80d3 100644 --- a/system/test/mock/mock_osi_alarm.h +++ b/system/test/mock/mock_osi_alarm.h @@ -23,40 +23,11 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include - -#include "check.h" -#include "internal_include/bt_target.h" #include "osi/include/alarm.h" -#include "osi/include/allocator.h" -#include "osi/include/fixed_queue.h" -#include "osi/include/list.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "osi/include/thread.h" -#include "osi/include/wakelock.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_allocation_tracker.cc b/system/test/mock/mock_osi_allocation_tracker.cc deleted file mode 100644 index c79f9f8c890e2cea3b6a0cc95ee06ef6cbec353b..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_osi_allocation_tracker.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:8 - * - * mockcify.pl ver 0.3.0 - */ - -#include -#include -#include -#include - -// Mock include file to share data between tests and mock -#include "test/mock/mock_osi_allocation_tracker.h" - -// Mocked internal structures, if any - -namespace test { -namespace mock { -namespace osi_allocation_tracker { - -// Function state capture and return values, if needed -struct allocation_tracker_expect_no_allocations - allocation_tracker_expect_no_allocations; -struct allocation_tracker_init allocation_tracker_init; -struct allocation_tracker_notify_alloc allocation_tracker_notify_alloc; -struct allocation_tracker_notify_free allocation_tracker_notify_free; -struct allocation_tracker_reset allocation_tracker_reset; -struct allocation_tracker_resize_for_canary - allocation_tracker_resize_for_canary; -struct allocation_tracker_uninit allocation_tracker_uninit; -struct osi_allocator_debug_dump osi_allocator_debug_dump; - -} // namespace osi_allocation_tracker -} // namespace mock -} // namespace test - -// Mocked functions, if any -size_t allocation_tracker_expect_no_allocations(void) { - inc_func_call_count(__func__); - return test::mock::osi_allocation_tracker:: - allocation_tracker_expect_no_allocations(); -} -void allocation_tracker_init(void) { - inc_func_call_count(__func__); - test::mock::osi_allocation_tracker::allocation_tracker_init(); -} -void* allocation_tracker_notify_alloc(uint8_t allocator_id, void* ptr, - size_t requested_size) { - inc_func_call_count(__func__); - return test::mock::osi_allocation_tracker::allocation_tracker_notify_alloc( - allocator_id, ptr, requested_size); -} -void* allocation_tracker_notify_free(uint8_t allocator_id, void* ptr) { - inc_func_call_count(__func__); - return test::mock::osi_allocation_tracker::allocation_tracker_notify_free( - allocator_id, ptr); -} -void allocation_tracker_reset(void) { - inc_func_call_count(__func__); - test::mock::osi_allocation_tracker::allocation_tracker_reset(); -} -size_t allocation_tracker_resize_for_canary(size_t size) { - inc_func_call_count(__func__); - return test::mock::osi_allocation_tracker:: - allocation_tracker_resize_for_canary(size); -} -void allocation_tracker_uninit(void) { - inc_func_call_count(__func__); - test::mock::osi_allocation_tracker::allocation_tracker_uninit(); -} -void osi_allocator_debug_dump(int fd) { - inc_func_call_count(__func__); - test::mock::osi_allocation_tracker::osi_allocator_debug_dump(fd); -} -// Mocked functions complete -// END mockcify generation diff --git a/system/test/mock/mock_osi_allocation_tracker.h b/system/test/mock/mock_osi_allocation_tracker.h deleted file mode 100644 index 435f85aa5b5ef01e36602735c05b4beef3614d15..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_osi_allocation_tracker.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:8 - * - * mockcify.pl ver 0.3.0 - */ - -#include -#include -#include -#include - -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include - -#include -#include - -#include "check.h" -#include "osi/include/allocation_tracker.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "test/common/mock_functions.h" - -// Mocked compile conditionals, if any - -namespace test { -namespace mock { -namespace osi_allocation_tracker { - -// Shared state between mocked functions and tests -// Name: allocation_tracker_expect_no_allocations -// Params: void -// Return: size_t -struct allocation_tracker_expect_no_allocations { - size_t return_value{0}; - std::function body{[this](void) { return return_value; }}; - size_t operator()(void) { return body(); }; -}; -extern struct allocation_tracker_expect_no_allocations - allocation_tracker_expect_no_allocations; - -// Name: allocation_tracker_init -// Params: void -// Return: void -struct allocation_tracker_init { - std::function body{[](void) {}}; - void operator()(void) { body(); }; -}; -extern struct allocation_tracker_init allocation_tracker_init; - -// Name: allocation_tracker_notify_alloc -// Params: uint8_t allocator_id, void* ptr, size_t requested_size -// Return: void* -struct allocation_tracker_notify_alloc { - void* return_value{}; - std::function - body{[this](uint8_t allocator_id, void* ptr, size_t requested_size) { - return return_value; - }}; - void* operator()(uint8_t allocator_id, void* ptr, size_t requested_size) { - return body(allocator_id, ptr, requested_size); - }; -}; -extern struct allocation_tracker_notify_alloc allocation_tracker_notify_alloc; - -// Name: allocation_tracker_notify_free -// Params: uint8_t allocator_id, void* ptr -// Return: void* -struct allocation_tracker_notify_free { - void* return_value{}; - std::function body{ - [this](uint8_t allocator_id, void* ptr) { return return_value; }}; - void* operator()(uint8_t allocator_id, void* ptr) { - return body(allocator_id, ptr); - }; -}; -extern struct allocation_tracker_notify_free allocation_tracker_notify_free; - -// Name: allocation_tracker_reset -// Params: void -// Return: void -struct allocation_tracker_reset { - std::function body{[](void) {}}; - void operator()(void) { body(); }; -}; -extern struct allocation_tracker_reset allocation_tracker_reset; - -// Name: allocation_tracker_resize_for_canary -// Params: size_t size -// Return: size_t -struct allocation_tracker_resize_for_canary { - size_t return_value{0}; - std::function body{ - [this](size_t size) { return return_value; }}; - size_t operator()(size_t size) { return body(size); }; -}; -extern struct allocation_tracker_resize_for_canary - allocation_tracker_resize_for_canary; - -// Name: allocation_tracker_uninit -// Params: void -// Return: void -struct allocation_tracker_uninit { - std::function body{[](void) {}}; - void operator()(void) { body(); }; -}; -extern struct allocation_tracker_uninit allocation_tracker_uninit; - -// Name: osi_allocator_debug_dump -// Params: int fd -// Return: void -struct osi_allocator_debug_dump { - std::function body{[](int fd) {}}; - void operator()(int fd) { body(fd); }; -}; -extern struct osi_allocator_debug_dump osi_allocator_debug_dump; - -} // namespace osi_allocation_tracker -} // namespace mock -} // namespace test - -// END mockcify generation \ No newline at end of file diff --git a/system/test/mock/mock_osi_allocator.cc b/system/test/mock/mock_osi_allocator.cc index b240521070f2bb732679961450c3372b0375adda..224d51ed7c43face3c836bf9cacd3cc9da0c46d2 100644 --- a/system/test/mock/mock_osi_allocator.cc +++ b/system/test/mock/mock_osi_allocator.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_allocator.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_allocator.h b/system/test/mock/mock_osi_allocator.h index fd283cc3301925244f1bcdc28dd7f5b90feddb51..ee5459e6ebc3e3849309a5ff85b4d50a30f2a5dc 100644 --- a/system/test/mock/mock_osi_allocator.h +++ b/system/test/mock/mock_osi_allocator.h @@ -21,26 +21,13 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include #include #include -#include "check.h" -#include "osi/include/allocation_tracker.h" -#include "osi/include/allocator.h" -#include "test/common/mock_functions.h" - // Mocked compile conditionals, if any namespace test { @@ -114,4 +101,4 @@ extern struct osi_strndup osi_strndup; } // namespace mock } // namespace test -// END mockcify generation \ No newline at end of file +// END mockcify generation diff --git a/system/test/mock/mock_osi_config.cc b/system/test/mock/mock_osi_config.cc index 4576ff02c6662fe2d02caece5a3f0c4f3bd4f79f..e1fde83280ddd07a8e2316497f87028e5625732f 100644 --- a/system/test/mock/mock_osi_config.cc +++ b/system/test/mock/mock_osi_config.cc @@ -20,14 +20,13 @@ * * mockcify.pl ver 0.3.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_osi_config.h" #include -#include -#include #include -// Mock include file to share data between tests and mock -#include "test/mock/mock_osi_config.h" +#include "test/common/mock_functions.h" // Mocked internal structures, if any diff --git a/system/test/mock/mock_osi_config.h b/system/test/mock/mock_osi_config.h index 146d4e70ebe2b2fba3934776b829f87d48bc9c32..7344bbfcfbe9515613a352576889ec179bd31b18 100644 --- a/system/test/mock/mock_osi_config.h +++ b/system/test/mock/mock_osi_config.h @@ -23,34 +23,20 @@ #include #include -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include #include -#include -#include #include #include #include #include #include -#include #include #include -#include -#include - -#include "check.h" #include "osi/include/config.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_fixed_queue.cc b/system/test/mock/mock_osi_fixed_queue.cc index e9583a39d5ff8c43bcbe2a8aaa9221fedc143972..b4658f9e06d64b0ef49c4e0d1951d7c62e5b49cd 100644 --- a/system/test/mock/mock_osi_fixed_queue.cc +++ b/system/test/mock/mock_osi_fixed_queue.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_fixed_queue.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_fixed_queue.h b/system/test/mock/mock_osi_fixed_queue.h index b8458a9156515e8b4d393277bc62a86dd86bbb19..786ab27b2ea586042900284c6c66def2d4f4aa21 100644 --- a/system/test/mock/mock_osi_fixed_queue.h +++ b/system/test/mock/mock_osi_fixed_queue.h @@ -21,29 +21,15 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include #include -#include - -#include "check.h" -#include "osi/include/allocator.h" #include "osi/include/fixed_queue.h" #include "osi/include/list.h" -#include "osi/include/osi.h" #include "osi/include/reactor.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_future.cc b/system/test/mock/mock_osi_future.cc index febcfc748f12a5dfe650bb600f4406aa05ef51d2..4a6122a105ba17d092d2fc19dd6c46592f527933 100644 --- a/system/test/mock/mock_osi_future.cc +++ b/system/test/mock/mock_osi_future.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_future.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_future.h b/system/test/mock/mock_osi_future.h index 2a48bd157dd03b33c2f2b54adc990d947ea37217..0998b191949976353f416aadd2b615cdf0f34eab 100644 --- a/system/test/mock/mock_osi_future.h +++ b/system/test/mock/mock_osi_future.h @@ -21,25 +21,12 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include -#include "check.h" -#include "osi/include/allocator.h" #include "osi/include/future.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_list.cc b/system/test/mock/mock_osi_list.cc index 01a025f9547114ce6ffc51289a621065c3a27ee4..68315bc91c0d055a0c743d42d7785f418afd47b3 100644 --- a/system/test/mock/mock_osi_list.cc +++ b/system/test/mock/mock_osi_list.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_list.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_list.h b/system/test/mock/mock_osi_list.h index 09b9f36b49d639abf2a47548f4e558e262e1f8bb..494ef88f577a8cf6bb1c8d6be72ad1c2b38e2790 100644 --- a/system/test/mock/mock_osi_list.h +++ b/system/test/mock/mock_osi_list.h @@ -21,24 +21,13 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include -#include "check.h" #include "osi/include/allocator.h" #include "osi/include/list.h" -#include "osi/include/osi.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_mutex.cc b/system/test/mock/mock_osi_mutex.cc index 3116e098e96d68dd3df7fab52df1e7f50b5f5c3c..25fb8de3cf5792bb941b47c15b2e2d55bc5fa491 100644 --- a/system/test/mock/mock_osi_mutex.cc +++ b/system/test/mock/mock_osi_mutex.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_mutex.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_mutex.h b/system/test/mock/mock_osi_mutex.h index 8b0088741d6ad2f0f7e7e96e428dbca3b41fd3e7..be01b0646261b059d74c7696036d17e758f55ed1 100644 --- a/system/test/mock/mock_osi_mutex.h +++ b/system/test/mock/mock_osi_mutex.h @@ -23,21 +23,9 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include - -#include "osi/include/mutex.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_properties.cc b/system/test/mock/mock_osi_properties.cc index 8228b36a9c437b85adfde868fe615727916a953d..e5997ac2038576497ad4912b6c7e249968d6e45f 100644 --- a/system/test/mock/mock_osi_properties.cc +++ b/system/test/mock/mock_osi_properties.cc @@ -20,14 +20,13 @@ * * mockcify.pl ver 0.3.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_osi_properties.h" #include -#include -#include -#include +#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_osi_properties.h" +#include "test/common/mock_functions.h" // Mocked internal structures, if any diff --git a/system/test/mock/mock_osi_properties.h b/system/test/mock/mock_osi_properties.h index 3df8921080d2b46ff5223652f1eae8e87ba79ffd..3ef42786a82cba1095dc215610771373c026f46f 100644 --- a/system/test/mock/mock_osi_properties.h +++ b/system/test/mock/mock_osi_properties.h @@ -23,20 +23,9 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include -#include - -#include "osi/include/properties.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_ringbuffer.cc b/system/test/mock/mock_osi_ringbuffer.cc index 498810b62df7b36710baa33bb29a955f92d05d37..58c506e2461cc3340d533d2a969590458ba5171f 100644 --- a/system/test/mock/mock_osi_ringbuffer.cc +++ b/system/test/mock/mock_osi_ringbuffer.cc @@ -20,14 +20,12 @@ * * mockcify.pl ver 0.3.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_osi_ringbuffer.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_osi_ringbuffer.h" +#include "test/common/mock_functions.h" // Mocked internal structures, if any diff --git a/system/test/mock/mock_osi_ringbuffer.h b/system/test/mock/mock_osi_ringbuffer.h index 197f685178af30c533364f6fac66b883e67fc3bf..8128a2ee3ba8128cbd6f1485c66ac98edd83c0b3 100644 --- a/system/test/mock/mock_osi_ringbuffer.h +++ b/system/test/mock/mock_osi_ringbuffer.h @@ -23,22 +23,12 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include #include -#include "check.h" -#include "osi/include/allocator.h" #include "osi/include/ringbuffer.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_socket.cc b/system/test/mock/mock_osi_socket.cc index fd885934352f102d9ac65afb82c9a247f0afde94..353faf06bf121e31f64d0501c4bc04d46ef06ad7 100644 --- a/system/test/mock/mock_osi_socket.cc +++ b/system/test/mock/mock_osi_socket.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_socket.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_socket.h b/system/test/mock/mock_osi_socket.h index c6305649b1ec14f57ac420aee795cdb9f09b609e..f966e87d637fcb43bb59cce1da861074b9917c90 100644 --- a/system/test/mock/mock_osi_socket.h +++ b/system/test/mock/mock_osi_socket.h @@ -21,33 +21,11 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include -#include -#include -#include -#include -#include - -#include "check.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "osi/include/reactor.h" #include "osi/include/socket.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_stack_power_telemetry.cc b/system/test/mock/mock_osi_stack_power_telemetry.cc new file mode 100644 index 0000000000000000000000000000000000000000..c7d145b19b8ff47901be2017a4d5aead455e6caf --- /dev/null +++ b/system/test/mock/mock_osi_stack_power_telemetry.cc @@ -0,0 +1,140 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Generated mock file from original source file + * Functions generated:5 + * + * mockcify.pl ver 0.6.1 + */ + +#include + +#include "osi/include/stack_power_telemetry.h" +#include "test/common/mock_functions.h" + +// Mock include file to share data between tests and mock + +// Original usings + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace osi_stack_power_telemetry { + +::power_telemetry::PowerTelemetry fake_power_telemetry; + +} // namespace osi_stack_power_telemetry +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace osi_stack_power_telemetry {} // namespace osi_stack_power_telemetry +} // namespace mock +} // namespace test + +struct power_telemetry::PowerTelemetryImpl {}; + +power_telemetry::PowerTelemetry::PowerTelemetry() {} + +void power_telemetry::PowerTelemetry::RecordLogDataContainer() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogScanStarted() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogChannelConnected( + uint16_t psm, int32_t src_id, int32_t dst_id, const RawAddress& bd_addr) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogChannelDisconnected( + uint16_t psm, int32_t src_id, int32_t dst_id, const RawAddress& bd_addr) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogTxBytes(uint16_t psm, int32_t src_id, + int32_t dst_id, + const RawAddress& bd_addr, + int32_t num_bytes) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogRxBytes(uint16_t psm, int32_t src_id, + int32_t dst_id, + const RawAddress& bd_addr, + int32_t num_bytes) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::Dumpsys(int32_t fd) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogRxAclPktData(uint16_t len) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogTxAclPktData(uint16_t len) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogLinkDetails(uint16_t handle, + const RawAddress& bdaddr, + bool isConnected, + bool is_acl_link) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogAclTxPowerLevel(uint16_t handle, + uint8_t txPower) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogInqScanStarted() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogInqScanStopped() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogBleAdvStarted() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogBleAdvStopped() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogHciCmdDetail() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogHciEvtDetail() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogTxPower(void* res) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogTrafficData() { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogSniffStarted( + uint16_t handle, const RawAddress& bdaddr) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogSniffStopped( + uint16_t handle, const RawAddress& bdaddr) { + inc_func_call_count(__func__); +} +void power_telemetry::PowerTelemetry::LogBleScan(uint16_t num_resps) { + inc_func_call_count(__func__); +} +power_telemetry::PowerTelemetry& power_telemetry::GetInstance() { + return test::mock::osi_stack_power_telemetry::fake_power_telemetry; + // return fake_power_telemetry; +} +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_osi_thread.cc b/system/test/mock/mock_osi_thread.cc index a9a216b010a7645a81cb1fd1c6f1cdfe97ffbdcd..953a6c31c3c58547213780b7db29545b1b061f02 100644 --- a/system/test/mock/mock_osi_thread.cc +++ b/system/test/mock/mock_osi_thread.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_thread.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_thread.h b/system/test/mock/mock_osi_thread.h index 99d5c652e2bb7d476ddc424d2df44c9c8b0473b6..6ff2bbdd79ac20eb91aaaa6bf426308220496fe6 100644 --- a/system/test/mock/mock_osi_thread.h +++ b/system/test/mock/mock_osi_thread.h @@ -21,37 +21,12 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "check.h" -#include "osi/include/allocator.h" -#include "osi/include/compat.h" #include "osi/include/fixed_queue.h" -#include "osi/include/log.h" #include "osi/include/reactor.h" #include "osi/include/thread.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_thread_scheduler.cc b/system/test/mock/mock_osi_thread_scheduler.cc index 52aceff359201bd0e02c7b7ddc8a45ed873f61e2..77f0821e5d5ee224fd2590879124be966e2d94fb 100644 --- a/system/test/mock/mock_osi_thread_scheduler.cc +++ b/system/test/mock/mock_osi_thread_scheduler.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_thread_scheduler.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_thread_scheduler.h b/system/test/mock/mock_osi_thread_scheduler.h index c79e725d91811491738e14fcd8f8bb0332262b9c..d5fdd79afdbd1cbef5fc3e14c19c383116e3fc56 100644 --- a/system/test/mock/mock_osi_thread_scheduler.h +++ b/system/test/mock/mock_osi_thread_scheduler.h @@ -23,19 +23,9 @@ #include -#include #include -#include -#include - -#include "test/common/mock_functions.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_osi_wakelock.cc b/system/test/mock/mock_osi_wakelock.cc index 6a259767fa786b8151d797df76e8a447a1b17753..03cb33a2f4ba580a67254d5a451b84b0bc5a6d30 100644 --- a/system/test/mock/mock_osi_wakelock.cc +++ b/system/test/mock/mock_osi_wakelock.cc @@ -20,15 +20,11 @@ * * mockcify.pl ver 0.3.0 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_osi_wakelock.h" +#include "test/common/mock_functions.h" + // Mocked internal structures, if any namespace test { diff --git a/system/test/mock/mock_osi_wakelock.h b/system/test/mock/mock_osi_wakelock.h index 623c3093c2550af1fc48c45e232e7d66f9ceeb56..6e14e65aa0ca558fadf3df3b13b6b357e167a1af 100644 --- a/system/test/mock/mock_osi_wakelock.h +++ b/system/test/mock/mock_osi_wakelock.h @@ -21,42 +21,12 @@ * mockcify.pl ver 0.3.0 */ -#include #include -#include -#include -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include +#include "include/hardware/bluetooth.h" -#include "base/logging.h" -#include "check.h" -#include "common/metrics.h" -#include "osi/include/alarm.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "osi/include/thread.h" -#include "osi/include/wakelock.h" -#include "test/common/mock_functions.h" +// Original included files, if any +// #include "osi/include/wakelock.h" // Mocked compile conditionals, if any diff --git a/system/test/mock/mock_stack_a2dp_api.cc b/system/test/mock/mock_stack_a2dp_api.cc index becec92dedf4a716b0a58f7694b3ddcff2f55a5e..c9f1bec3cfe535f92d804efbab704e81827b7c65 100644 --- a/system/test/mock/mock_stack_a2dp_api.cc +++ b/system/test/mock/mock_stack_a2dp_api.cc @@ -19,33 +19,23 @@ * Functions generated:9 */ -#include - -#include -#include - #include "a2dp_api.h" -#include "avdt_api.h" -#include "bt_target.h" -#include "osi/include/log.h" -#include "sdpdefs.h" #include "stack/a2dp/a2dp_int.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name, - char* p_provider_name, uint16_t features, - uint32_t sdp_handle) { +tA2DP_STATUS A2DP_AddRecord(uint16_t /* service_uuid */, + char* /* p_service_name */, + char* /* p_provider_name */, + uint16_t /* features */, + uint32_t /* sdp_handle */) { inc_func_call_count(__func__); return A2DP_SUCCESS; } -tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, const RawAddress& bd_addr, - tA2DP_SDP_DB_PARAMS* p_db, - tA2DP_FIND_CBACK* p_cback) { +tA2DP_STATUS A2DP_FindService(uint16_t /* service_uuid */, + const RawAddress& /* bd_addr */, + tA2DP_SDP_DB_PARAMS* /* p_db */, + tA2DP_FIND_CBACK* /* p_cback */) { inc_func_call_count(__func__); return A2DP_SUCCESS; } @@ -53,15 +43,11 @@ uint16_t A2DP_GetAvdtpVersion() { inc_func_call_count(__func__); return 0; } -uint8_t A2DP_BitsSet(uint64_t num) { +uint8_t A2DP_BitsSet(uint64_t /* num */) { inc_func_call_count(__func__); return 1; } -uint8_t A2DP_SetTraceLevel(uint8_t new_level) { - inc_func_call_count(__func__); - return 0; -} void A2DP_Init(void) { inc_func_call_count(__func__); } -void a2dp_set_avdt_sdp_ver(uint16_t avdt_sdp_ver) { +void a2dp_set_avdt_sdp_ver(uint16_t /* avdt_sdp_ver */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_a2dp_codec_config.cc b/system/test/mock/mock_stack_a2dp_codec_config.cc index c1a0324095a45b10e5d3e216b58663150d662d8e..129da3a07d729777e2a3aa14e0059a02aae9f9f5 100644 --- a/system/test/mock/mock_stack_a2dp_codec_config.cc +++ b/system/test/mock/mock_stack_a2dp_codec_config.cc @@ -20,37 +20,27 @@ */ #include -#include -#include #include -#include "a2dp_aac.h" #include "a2dp_codec_api.h" -#include "a2dp_sbc.h" -#include "a2dp_vendor.h" #include "bta/av/bta_av_int.h" -#include "osi/include/log.h" -#include "osi/include/properties.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - A2dpCodecConfig* A2dpCodecConfig::createCodec( - btav_a2dp_codec_index_t codec_index, - btav_a2dp_codec_priority_t codec_priority) { + btav_a2dp_codec_index_t /* codec_index */, + btav_a2dp_codec_priority_t /* codec_priority */) { inc_func_call_count(__func__); return nullptr; } -A2dpCodecConfig* A2dpCodecs::findSinkCodecConfig(const uint8_t* p_codec_info) { +A2dpCodecConfig* A2dpCodecs::findSinkCodecConfig( + const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return nullptr; } A2dpCodecConfig* A2dpCodecs::findSourceCodecConfig( - const uint8_t* p_codec_info) { + const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return nullptr; } @@ -64,88 +54,91 @@ A2dpCodecConfig::A2dpCodecConfig(btav_a2dp_codec_index_t codec_index, } A2dpCodecConfig::~A2dpCodecConfig() { inc_func_call_count(__func__); } A2dpCodecs::A2dpCodecs( - const std::vector& codec_priorities) + const std::vector& /* codec_priorities */) : current_codec_config_(nullptr) { inc_func_call_count(__func__); } A2dpCodecs::~A2dpCodecs() { inc_func_call_count(__func__); } -bool A2DP_AdjustCodec(uint8_t* p_codec_info) { +bool A2DP_AdjustCodec(uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } -bool A2DP_BuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf, - uint16_t frames_per_packet) { +bool A2DP_BuildCodecHeader(const uint8_t* /* p_codec_info */, + BT_HDR* /* p_buf */, + uint16_t /* frames_per_packet */) { inc_func_call_count(__func__); return false; } -bool A2DP_CodecEquals(const uint8_t* p_codec_info_a, - const uint8_t* p_codec_info_b) { +bool A2DP_CodecEquals(const uint8_t* /* p_codec_info_a */, + const uint8_t* /* p_codec_info_b */) { inc_func_call_count(__func__); return false; } -bool A2DP_CodecTypeEquals(const uint8_t* p_codec_info_a, - const uint8_t* p_codec_info_b) { +bool A2DP_CodecTypeEquals(const uint8_t* /* p_codec_info_a */, + const uint8_t* /* p_codec_info_b */) { inc_func_call_count(__func__); return false; } -bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data, - uint32_t* p_timestamp) { +bool A2DP_GetPacketTimestamp(const uint8_t* /* p_codec_info */, + const uint8_t* /* p_data */, + uint32_t* /* p_timestamp */) { inc_func_call_count(__func__); return false; } -bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t codec_index, - AvdtpSepConfig* p_cfg) { +bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t /* codec_index */, + AvdtpSepConfig* /* p_cfg */) { inc_func_call_count(__func__); return false; } -int A2DP_GetEecoderEffectiveFrameSize(const uint8_t* p_codec_info) { +int A2DP_GetEecoderEffectiveFrameSize(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } -bool A2DP_IsPeerSinkCodecValid(const uint8_t* p_codec_info) { +bool A2DP_IsPeerSinkCodecValid(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } -bool A2DP_IsPeerSourceCodecSupported(const uint8_t* p_codec_info) { +bool A2DP_IsPeerSourceCodecSupported(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } -bool A2DP_IsPeerSourceCodecValid(const uint8_t* p_codec_info) { +bool A2DP_IsPeerSourceCodecValid(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } -bool A2DP_IsSinkCodecSupported(const uint8_t* p_codec_info) { +bool A2DP_IsSinkCodecSupported(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } -bool A2DP_IsSinkCodecValid(const uint8_t* p_codec_info) { +bool A2DP_IsSinkCodecValid(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } -bool A2DP_IsSourceCodecValid(const uint8_t* p_codec_info) { +bool A2DP_IsSourceCodecValid(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } -bool A2DP_UsesRtpHeader(bool content_protection_enabled, - const uint8_t* p_codec_info) { +bool A2DP_UsesRtpHeader(bool /* content_protection_enabled */, + const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } bool A2dpCodecConfig::codecConfigIsValid( - const btav_a2dp_codec_config_t& codec_config) { + const btav_a2dp_codec_config_t& /* codec_config */) { inc_func_call_count(__func__); return false; } -bool A2dpCodecConfig::copyOutOtaCodecConfig(uint8_t* p_codec_info) { +bool A2dpCodecConfig::copyOutOtaCodecConfig(uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return false; } -bool A2dpCodecConfig::getCodecSpecificConfig(tBT_A2DP_OFFLOAD* p_a2dp_offload) { +bool A2dpCodecConfig::getCodecSpecificConfig( + tBT_A2DP_OFFLOAD* /* p_a2dp_offload */) { inc_func_call_count(__func__); return false; } bool A2dpCodecConfig::isCodecConfigEmpty( - const btav_a2dp_codec_config_t& codec_config) { + const btav_a2dp_codec_config_t& /* codec_config */) { inc_func_call_count(__func__); return false; } @@ -154,19 +147,20 @@ bool A2dpCodecConfig::isValid() const { return false; } bool A2dpCodecConfig::setCodecUserConfig( - const btav_a2dp_codec_config_t& codec_user_config, - const btav_a2dp_codec_config_t& codec_audio_config, - const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, - const uint8_t* p_peer_codec_info, bool is_capability, - uint8_t* p_result_codec_config, bool* p_restart_input, - bool* p_restart_output, bool* p_config_updated) { + const btav_a2dp_codec_config_t& /* codec_user_config */, + const btav_a2dp_codec_config_t& /* codec_audio_config */, + const tA2DP_ENCODER_INIT_PEER_PARAMS* /* p_peer_params */, + const uint8_t* /* p_peer_codec_info */, bool /* is_capability */, + uint8_t* /* p_result_codec_config */, bool* /* p_restart_input */, + bool* /* p_restart_output */, bool* /* p_config_updated */) { inc_func_call_count(__func__); return false; } bool A2dpCodecs::getCodecConfigAndCapabilities( - btav_a2dp_codec_config_t* p_codec_config, - std::vector* p_codecs_local_capabilities, - std::vector* p_codecs_selectable_capabilities) { + btav_a2dp_codec_config_t* /* p_codec_config */, + std::vector* /* p_codecs_local_capabilities */, + std::vector< + btav_a2dp_codec_config_t>* /* p_codecs_selectable_capabilities */) { inc_func_call_count(__func__); return false; } @@ -174,55 +168,57 @@ bool A2dpCodecs::init() { inc_func_call_count(__func__); return false; } -bool A2dpCodecs::isSupportedCodec(btav_a2dp_codec_index_t codec_index) { +bool A2dpCodecs::isSupportedCodec(btav_a2dp_codec_index_t /* codec_index */) { inc_func_call_count(__func__); return false; } bool A2dpCodecs::setCodecAudioConfig( - const btav_a2dp_codec_config_t& codec_audio_config, - const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, - const uint8_t* p_peer_sink_capabilities, uint8_t* p_result_codec_config, - bool* p_restart_output, bool* p_config_updated) { + const btav_a2dp_codec_config_t& /* codec_audio_config */, + const tA2DP_ENCODER_INIT_PEER_PARAMS* /* p_peer_params */, + const uint8_t* /* p_peer_sink_capabilities */, + uint8_t* /* p_result_codec_config */, bool* /* p_restart_output */, + bool* /* p_config_updated */) { inc_func_call_count(__func__); return false; } -bool A2dpCodecs::setCodecConfig(const uint8_t* p_peer_codec_info, - bool is_capability, - uint8_t* p_result_codec_config, - bool select_current_codec) { +bool A2dpCodecs::setCodecConfig(const uint8_t* /* p_peer_codec_info */, + bool /* is_capability */, + uint8_t* /* p_result_codec_config */, + bool /* select_current_codec */) { inc_func_call_count(__func__); return false; } bool A2dpCodecs::setCodecOtaConfig( - const uint8_t* p_ota_codec_config, - const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, - uint8_t* p_result_codec_config, bool* p_restart_input, - bool* p_restart_output, bool* p_config_updated) { + const uint8_t* /* p_ota_codec_config */, + const tA2DP_ENCODER_INIT_PEER_PARAMS* /* p_peer_params */, + uint8_t* /* p_result_codec_config */, bool* /* p_restart_input */, + bool* /* p_restart_output */, bool* /* p_config_updated */) { inc_func_call_count(__func__); return false; } bool A2dpCodecs::setCodecUserConfig( - const btav_a2dp_codec_config_t& codec_user_config, - const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, - const uint8_t* p_peer_sink_capabilities, uint8_t* p_result_codec_config, - bool* p_restart_input, bool* p_restart_output, bool* p_config_updated) { + const btav_a2dp_codec_config_t& /* codec_user_config */, + const tA2DP_ENCODER_INIT_PEER_PARAMS* /* p_peer_params */, + const uint8_t* /* p_peer_sink_capabilities */, + uint8_t* /* p_result_codec_config */, bool* /* p_restart_input */, + bool* /* p_restart_output */, bool* /* p_config_updated */) { inc_func_call_count(__func__); return false; } bool A2dpCodecs::setPeerSinkCodecCapabilities( - const uint8_t* p_peer_codec_capabilities) { + const uint8_t* /* p_peer_codec_capabilities */) { inc_func_call_count(__func__); return false; } bool A2dpCodecs::setPeerSourceCodecCapabilities( - const uint8_t* p_peer_codec_capabilities) { + const uint8_t* /* p_peer_codec_capabilities */) { inc_func_call_count(__func__); return false; } -bool A2dpCodecs::setSinkCodecConfig(const uint8_t* p_peer_codec_info, - bool is_capability, - uint8_t* p_result_codec_config, - bool select_current_codec) { +bool A2dpCodecs::setSinkCodecConfig(const uint8_t* /* p_peer_codec_info */, + bool /* is_capability */, + uint8_t* /* p_result_codec_config */, + bool /* select_current_codec */) { inc_func_call_count(__func__); return false; } @@ -256,45 +252,46 @@ btav_a2dp_codec_config_t A2dpCodecConfig::getCodecUserConfig() { btav_a2dp_codec_config_t config; return config; } -btav_a2dp_codec_index_t A2DP_SinkCodecIndex(const uint8_t* p_codec_info) { +btav_a2dp_codec_index_t A2DP_SinkCodecIndex(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return BTAV_A2DP_CODEC_INDEX_MAX; } -btav_a2dp_codec_index_t A2DP_SourceCodecIndex(const uint8_t* p_codec_info) { +btav_a2dp_codec_index_t A2DP_SourceCodecIndex( + const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return BTAV_A2DP_CODEC_INDEX_MAX; } -const char* A2DP_CodecIndexStr(btav_a2dp_codec_index_t codec_index) { +const char* A2DP_CodecIndexStr(btav_a2dp_codec_index_t /* codec_index */) { inc_func_call_count(__func__); return nullptr; } -const char* A2DP_CodecName(const uint8_t* p_codec_info) { +const char* A2DP_CodecName(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return nullptr; } const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterface( - const uint8_t* p_codec_info) { + const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return nullptr; } const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface( - const uint8_t* p_codec_info) { + const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return nullptr; } -int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info) { +int A2DP_GetSinkTrackChannelType(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } -int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info) { +int A2DP_GetTrackBitsPerSample(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } -int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info) { +int A2DP_GetTrackChannelCount(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } -int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info) { +int A2DP_GetTrackSampleRate(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } @@ -302,35 +299,35 @@ int A2dpCodecConfig::getTrackBitRate() const { inc_func_call_count(__func__); return 0; } -std::string A2DP_CodecInfoString(const uint8_t* p_codec_info) { +std::string A2DP_CodecInfoString(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } std::string A2dpCodecConfig::codecBitsPerSample2Str( - btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample) { + btav_a2dp_codec_bits_per_sample_t /* codec_bits_per_sample */) { inc_func_call_count(__func__); return 0; } std::string A2dpCodecConfig::codecChannelMode2Str( - btav_a2dp_codec_channel_mode_t codec_channel_mode) { + btav_a2dp_codec_channel_mode_t /* codec_channel_mode */) { inc_func_call_count(__func__); return 0; } std::string A2dpCodecConfig::codecConfig2Str( - const btav_a2dp_codec_config_t& codec_config) { + const btav_a2dp_codec_config_t& /* codec_config */) { inc_func_call_count(__func__); return 0; } std::string A2dpCodecConfig::codecSampleRate2Str( - btav_a2dp_codec_sample_rate_t codec_sample_rate) { + btav_a2dp_codec_sample_rate_t /* codec_sample_rate */) { inc_func_call_count(__func__); return 0; } -tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info) { +tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } -uint8_t A2DP_GetMediaType(const uint8_t* p_codec_info) { +uint8_t A2DP_GetMediaType(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } @@ -338,21 +335,23 @@ uint8_t A2dpCodecConfig::getAudioBitsPerSample() { inc_func_call_count(__func__); return 0; } -void A2DP_InitDefaultCodec(uint8_t* p_codec_info) { +void A2DP_InitDefaultCodec(uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); } -void A2dpCodecConfig::debug_codec_dump(int fd) { +void A2dpCodecConfig::debug_codec_dump(int /* fd */) { inc_func_call_count(__func__); } -int A2DP_IotGetPeerSinkCodecType(const uint8_t* p_codec_info) { +int A2DP_IotGetPeerSinkCodecType(const uint8_t* /* p_codec_info */) { inc_func_call_count(__func__); return 0; } void A2dpCodecConfig::setCodecPriority( - btav_a2dp_codec_priority_t codec_priority) { + btav_a2dp_codec_priority_t /* codec_priority */) { inc_func_call_count(__func__); } void A2dpCodecConfig::setDefaultCodecPriority() { inc_func_call_count(__func__); } -void A2dpCodecs::debug_codec_dump(int fd) { inc_func_call_count(__func__); } +void A2dpCodecs::debug_codec_dump(int /* fd */) { + inc_func_call_count(__func__); +} diff --git a/system/test/mock/mock_stack_a2dp_sbc.cc b/system/test/mock/mock_stack_a2dp_sbc.cc index b05a946c086c3602b66760e0d7c5957fc4bb09df..680e2951ba3fb04f6c9177a787f6ab5775872790 100644 --- a/system/test/mock/mock_stack_a2dp_sbc.cc +++ b/system/test/mock/mock_stack_a2dp_sbc.cc @@ -19,14 +19,13 @@ * * mockcify.pl ver 0.5.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_a2dp_sbc.h" #include -#include -#include #include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_a2dp_sbc.h" +#include "test/common/mock_functions.h" // Original usings diff --git a/system/test/mock/mock_stack_a2dp_sbc.h b/system/test/mock/mock_stack_a2dp_sbc.h index ac470c6b4566f3aedf4114e09966cb2d8bc2a517..cee7fc2a8b5f8d4ac51d6530592b9cfe81b76cfd 100644 --- a/system/test/mock/mock_stack_a2dp_sbc.h +++ b/system/test/mock/mock_stack_a2dp_sbc.h @@ -24,26 +24,11 @@ #include #include -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include - -#include "a2dp_sbc.h" -#include "a2dp_sbc_decoder.h" -#include "a2dp_sbc_encoder.h" -#include "embdrv/sbc/encoder/include/sbc_encoder.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" +#include "stack/include/a2dp_codec_api.h" #include "stack/include/bt_hdr.h" -#include "test/common/mock_functions.h" // Original usings @@ -60,7 +45,7 @@ namespace stack_a2dp_sbc { struct A2DP_AdjustCodecSbc { static bool return_value; std::function body{ - [](uint8_t* p_codec_info) { return return_value; }}; + [](uint8_t* /* p_codec_info */) { return return_value; }}; bool operator()(uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_AdjustCodecSbc A2DP_AdjustCodecSbc; @@ -72,8 +57,8 @@ struct A2DP_BuildCodecHeaderSbc { static bool return_value; std::function - body{[](const uint8_t* p_codec_info, BT_HDR* p_buf, - uint16_t frames_per_packet) { return return_value; }}; + body{[](const uint8_t* /* p_codec_info */, BT_HDR* /* p_buf */, + uint16_t /* frames_per_packet */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info, BT_HDR* p_buf, uint16_t frames_per_packet) { return body(p_codec_info, p_buf, frames_per_packet); @@ -88,9 +73,8 @@ struct A2DP_CodecEqualsSbc { static bool return_value; std::function - body{[](const uint8_t* p_codec_info_a, const uint8_t* p_codec_info_b) { - return return_value; - }}; + body{[](const uint8_t* /* p_codec_info_a */, + const uint8_t* /* p_codec_info_b */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info_a, const uint8_t* p_codec_info_b) { return body(p_codec_info_a, p_codec_info_b); @@ -124,7 +108,7 @@ extern struct A2DP_CodecIndexStrSbcSink A2DP_CodecIndexStrSbcSink; struct A2DP_CodecInfoStringSbc { static std::string return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; std::string operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; @@ -137,7 +121,7 @@ extern struct A2DP_CodecInfoStringSbc A2DP_CodecInfoStringSbc; struct A2DP_CodecNameSbc { static const char* return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; const char* operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; @@ -151,9 +135,8 @@ struct A2DP_CodecTypeEqualsSbc { static bool return_value; std::function - body{[](const uint8_t* p_codec_info_a, const uint8_t* p_codec_info_b) { - return return_value; - }}; + body{[](const uint8_t* /* p_codec_info_a */, + const uint8_t* /* p_codec_info_b */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info_a, const uint8_t* p_codec_info_b) { return body(p_codec_info_a, p_codec_info_b); @@ -167,7 +150,7 @@ extern struct A2DP_CodecTypeEqualsSbc A2DP_CodecTypeEqualsSbc; struct A2DP_GetAllocationMethodCodeSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetAllocationMethodCodeSbc A2DP_GetAllocationMethodCodeSbc; @@ -188,7 +171,7 @@ extern struct A2DP_GetBitrateSbc A2DP_GetBitrateSbc; struct A2DP_GetChannelModeCodeSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetChannelModeCodeSbc A2DP_GetChannelModeCodeSbc; @@ -199,7 +182,7 @@ extern struct A2DP_GetChannelModeCodeSbc A2DP_GetChannelModeCodeSbc; struct A2DP_GetDecoderInterfaceSbc { static const tA2DP_DECODER_INTERFACE* return_value; std::function - body{[](const uint8_t* p_codec_info) { return return_value; }}; + body{[](const uint8_t* /* p_codec_info */) { return return_value; }}; const tA2DP_DECODER_INTERFACE* operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; @@ -212,7 +195,7 @@ extern struct A2DP_GetDecoderInterfaceSbc A2DP_GetDecoderInterfaceSbc; struct A2DP_GetEncoderInterfaceSbc { static const tA2DP_ENCODER_INTERFACE* return_value; std::function - body{[](const uint8_t* p_codec_info) { return return_value; }}; + body{[](const uint8_t* /* p_codec_info */) { return return_value; }}; const tA2DP_ENCODER_INTERFACE* operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; @@ -225,7 +208,7 @@ extern struct A2DP_GetEncoderInterfaceSbc A2DP_GetEncoderInterfaceSbc; struct A2DP_GetMaxBitpoolSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetMaxBitpoolSbc A2DP_GetMaxBitpoolSbc; @@ -236,7 +219,7 @@ extern struct A2DP_GetMaxBitpoolSbc A2DP_GetMaxBitpoolSbc; struct A2DP_GetMinBitpoolSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetMinBitpoolSbc A2DP_GetMinBitpoolSbc; @@ -247,7 +230,7 @@ extern struct A2DP_GetMinBitpoolSbc A2DP_GetMinBitpoolSbc; struct A2DP_GetNumberOfBlocksSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetNumberOfBlocksSbc A2DP_GetNumberOfBlocksSbc; @@ -258,7 +241,7 @@ extern struct A2DP_GetNumberOfBlocksSbc A2DP_GetNumberOfBlocksSbc; struct A2DP_GetNumberOfSubbandsSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetNumberOfSubbandsSbc A2DP_GetNumberOfSubbandsSbc; @@ -270,8 +253,8 @@ struct A2DP_GetPacketTimestampSbc { static bool return_value; std::function - body{[](const uint8_t* p_codec_info, const uint8_t* p_data, - uint32_t* p_timestamp) { return return_value; }}; + body{[](const uint8_t* /* p_codec_info */, const uint8_t* /* p_data */, + uint32_t* /* p_timestamp */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info, const uint8_t* p_data, uint32_t* p_timestamp) { return body(p_codec_info, p_data, p_timestamp); @@ -285,7 +268,7 @@ extern struct A2DP_GetPacketTimestampSbc A2DP_GetPacketTimestampSbc; struct A2DP_GetSamplingFrequencyCodeSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetSamplingFrequencyCodeSbc A2DP_GetSamplingFrequencyCodeSbc; @@ -296,7 +279,7 @@ extern struct A2DP_GetSamplingFrequencyCodeSbc A2DP_GetSamplingFrequencyCodeSbc; struct A2DP_GetSinkTrackChannelTypeSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetSinkTrackChannelTypeSbc A2DP_GetSinkTrackChannelTypeSbc; @@ -307,7 +290,7 @@ extern struct A2DP_GetSinkTrackChannelTypeSbc A2DP_GetSinkTrackChannelTypeSbc; struct A2DP_GetTrackBitsPerSampleSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetTrackBitsPerSampleSbc A2DP_GetTrackBitsPerSampleSbc; @@ -318,7 +301,7 @@ extern struct A2DP_GetTrackBitsPerSampleSbc A2DP_GetTrackBitsPerSampleSbc; struct A2DP_GetTrackChannelCountSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetTrackChannelCountSbc A2DP_GetTrackChannelCountSbc; @@ -329,7 +312,7 @@ extern struct A2DP_GetTrackChannelCountSbc A2DP_GetTrackChannelCountSbc; struct A2DP_GetTrackSampleRateSbc { static int return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; int operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_GetTrackSampleRateSbc A2DP_GetTrackSampleRateSbc; @@ -340,7 +323,7 @@ extern struct A2DP_GetTrackSampleRateSbc A2DP_GetTrackSampleRateSbc; struct A2DP_InitCodecConfigSbc { static bool return_value; std::function body{ - [](AvdtpSepConfig* p_cfg) { return return_value; }}; + [](AvdtpSepConfig* /* p_cfg */) { return return_value; }}; bool operator()(AvdtpSepConfig* p_cfg) { return body(p_cfg); }; }; extern struct A2DP_InitCodecConfigSbc A2DP_InitCodecConfigSbc; @@ -351,7 +334,7 @@ extern struct A2DP_InitCodecConfigSbc A2DP_InitCodecConfigSbc; struct A2DP_InitCodecConfigSbcSink { static bool return_value; std::function body{ - [](AvdtpSepConfig* p_cfg) { return return_value; }}; + [](AvdtpSepConfig* /* p_cfg */) { return return_value; }}; bool operator()(AvdtpSepConfig* p_cfg) { return body(p_cfg); }; }; extern struct A2DP_InitCodecConfigSbcSink A2DP_InitCodecConfigSbcSink; @@ -360,7 +343,8 @@ extern struct A2DP_InitCodecConfigSbcSink A2DP_InitCodecConfigSbcSink; // Params: uint8_t* p_codec_info // Return: void struct A2DP_InitDefaultCodecSbc { - std::function body{[](uint8_t* p_codec_info) {}}; + std::function body{ + [](uint8_t* /* p_codec_info */) {}}; void operator()(uint8_t* p_codec_info) { body(p_codec_info); }; }; extern struct A2DP_InitDefaultCodecSbc A2DP_InitDefaultCodecSbc; @@ -371,7 +355,7 @@ extern struct A2DP_InitDefaultCodecSbc A2DP_InitDefaultCodecSbc; struct A2DP_IsPeerSinkCodecValidSbc { static bool return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_IsPeerSinkCodecValidSbc A2DP_IsPeerSinkCodecValidSbc; @@ -382,7 +366,7 @@ extern struct A2DP_IsPeerSinkCodecValidSbc A2DP_IsPeerSinkCodecValidSbc; struct A2DP_IsPeerSourceCodecSupportedSbc { static bool return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_IsPeerSourceCodecSupportedSbc @@ -394,7 +378,7 @@ extern struct A2DP_IsPeerSourceCodecSupportedSbc struct A2DP_IsPeerSourceCodecValidSbc { static bool return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_IsPeerSourceCodecValidSbc A2DP_IsPeerSourceCodecValidSbc; @@ -405,7 +389,7 @@ extern struct A2DP_IsPeerSourceCodecValidSbc A2DP_IsPeerSourceCodecValidSbc; struct A2DP_IsSinkCodecSupportedSbc { static bool return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_IsSinkCodecSupportedSbc A2DP_IsSinkCodecSupportedSbc; @@ -416,7 +400,7 @@ extern struct A2DP_IsSinkCodecSupportedSbc A2DP_IsSinkCodecSupportedSbc; struct A2DP_IsSinkCodecValidSbc { static bool return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_IsSinkCodecValidSbc A2DP_IsSinkCodecValidSbc; @@ -427,7 +411,7 @@ extern struct A2DP_IsSinkCodecValidSbc A2DP_IsSinkCodecValidSbc; struct A2DP_IsSourceCodecValidSbc { static bool return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; bool operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; }; extern struct A2DP_IsSourceCodecValidSbc A2DP_IsSourceCodecValidSbc; @@ -438,7 +422,7 @@ extern struct A2DP_IsSourceCodecValidSbc A2DP_IsSourceCodecValidSbc; struct A2DP_SinkCodecIndexSbc { static btav_a2dp_codec_index_t return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; btav_a2dp_codec_index_t operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; @@ -451,7 +435,7 @@ extern struct A2DP_SinkCodecIndexSbc A2DP_SinkCodecIndexSbc; struct A2DP_SourceCodecIndexSbc { static btav_a2dp_codec_index_t return_value; std::function body{ - [](const uint8_t* p_codec_info) { return return_value; }}; + [](const uint8_t* /* p_codec_info */) { return return_value; }}; btav_a2dp_codec_index_t operator()(const uint8_t* p_codec_info) { return body(p_codec_info); }; diff --git a/system/test/mock/mock_stack_acl.cc b/system/test/mock/mock_stack_acl.cc index 971123ebf85ce55741ccbf8cc19b52ca7f1a218b..5ca96ee704f3c082f5240c46ce8603c1b9c8e327 100644 --- a/system/test/mock/mock_stack_acl.cc +++ b/system/test/mock/mock_stack_acl.cc @@ -20,23 +20,19 @@ * * mockcify.pl ver 0.2.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_acl.h" #include -#include -#include #include -// Mock include file to share data between tests and mock +#include "stack/include/acl_client_callbacks.h" #include "stack/include/bt_hdr.h" -#include "test/mock/mock_stack_acl.h" +#include "test/common/mock_functions.h" #include "types/class_of_device.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -53,6 +49,7 @@ struct BTM_IsAclConnectionUpFromHandle BTM_IsAclConnectionUpFromHandle; struct BTM_IsBleConnection BTM_IsBleConnection; struct BTM_IsPhy2mSupported BTM_IsPhy2mSupported; struct BTM_ReadRemoteConnectionAddr BTM_ReadRemoteConnectionAddr; +struct BTM_IsRemoteVersionReceived BTM_IsRemoteVersionReceived; struct BTM_ReadRemoteVersion BTM_ReadRemoteVersion; struct BTM_is_sniff_allowed_for BTM_is_sniff_allowed_for; struct acl_create_le_connection acl_create_le_connection; @@ -74,10 +71,7 @@ struct acl_peer_supports_ble_connection_subrating_host struct acl_refresh_remote_address acl_refresh_remote_address; struct acl_set_peer_le_features_from_handle acl_set_peer_le_features_from_handle; -struct sco_peer_supports_esco_2m_phy sco_peer_supports_esco_2m_phy; -struct sco_peer_supports_esco_3m_phy sco_peer_supports_esco_3m_phy; struct acl_create_classic_connection acl_create_classic_connection; -struct IsEprAvailable IsEprAvailable; struct acl_get_connection_from_address acl_get_connection_from_address; struct btm_acl_for_bda btm_acl_for_bda; struct acl_get_connection_from_handle acl_get_connection_from_handle; @@ -96,7 +90,6 @@ struct BTM_GetMaxPacketSize BTM_GetMaxPacketSize; struct BTM_GetNumAclLinks BTM_GetNumAclLinks; struct acl_get_supported_packet_types acl_get_supported_packet_types; struct BTM_GetPeerSCA BTM_GetPeerSCA; -struct BTM_SetTraceLevel BTM_SetTraceLevel; struct acl_link_role_from_handle acl_link_role_from_handle; struct btm_handle_to_acl_index btm_handle_to_acl_index; struct BTM_ReadRemoteFeatures BTM_ReadRemoteFeatures; @@ -112,36 +105,26 @@ struct BTM_default_block_role_switch BTM_default_block_role_switch; struct BTM_default_unblock_role_switch BTM_default_unblock_role_switch; struct BTM_unblock_role_switch_for BTM_unblock_role_switch_for; struct BTM_unblock_sniff_mode_for BTM_unblock_sniff_mode_for; -struct HACK_acl_check_sm4 HACK_acl_check_sm4; -struct acl_accept_connection_request acl_accept_connection_request; struct acl_disconnect_after_role_switch acl_disconnect_after_role_switch; struct acl_disconnect_from_handle acl_disconnect_from_handle; -struct acl_link_segments_xmitted acl_link_segments_xmitted; struct acl_packets_completed acl_packets_completed; struct acl_process_extended_features acl_process_extended_features; struct acl_process_supported_features acl_process_supported_features; struct acl_rcv_acl_data acl_rcv_acl_data; -struct acl_reject_connection_request acl_reject_connection_request; struct acl_send_data_packet_ble acl_send_data_packet_ble; struct acl_set_disconnect_reason acl_set_disconnect_reason; struct acl_write_automatic_flush_timeout acl_write_automatic_flush_timeout; struct btm_acl_connected btm_acl_connected; -struct btm_acl_connection_request btm_acl_connection_request; struct btm_acl_created btm_acl_created; struct btm_acl_device_down btm_acl_device_down; struct btm_acl_disconnected btm_acl_disconnected; struct btm_acl_iso_disconnected btm_acl_iso_disconnected; struct btm_acl_encrypt_change btm_acl_encrypt_change; struct btm_acl_notif_conn_collision btm_acl_notif_conn_collision; -struct btm_acl_paging btm_acl_paging; struct btm_acl_process_sca_cmpl_pkt btm_acl_process_sca_cmpl_pkt; struct btm_acl_removed btm_acl_removed; -struct btm_acl_reset_paging btm_acl_reset_paging; -struct btm_acl_resubmit_page btm_acl_resubmit_page; struct btm_acl_role_changed btm_acl_role_changed; -struct btm_acl_set_paging btm_acl_set_paging; struct btm_acl_update_conn_addr btm_acl_update_conn_addr; -struct btm_configure_data_path btm_configure_data_path; struct btm_acl_update_inquiry_status btm_acl_update_inquiry_status; struct btm_ble_refresh_local_resolvable_private_addr btm_ble_refresh_local_resolvable_private_addr; @@ -163,7 +146,6 @@ struct btm_read_remote_ext_features_complete struct btm_read_remote_ext_features_complete_raw btm_read_remote_ext_features_complete_raw; struct btm_read_remote_ext_features_failed btm_read_remote_ext_features_failed; -struct btm_read_remote_features_complete btm_read_remote_features_complete; struct btm_read_remote_version_complete btm_read_remote_version_complete; struct btm_read_rssi_complete btm_read_rssi_complete; struct btm_read_rssi_timeout btm_read_rssi_timeout; @@ -218,10 +200,15 @@ bool BTM_IsPhy2mSupported(const RawAddress& remote_bda, } bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, + bool ota_address) { inc_func_call_count(__func__); return test::mock::stack_acl::BTM_ReadRemoteConnectionAddr( - pseudo_addr, conn_addr, p_addr_type); + pseudo_addr, conn_addr, p_addr_type, ota_address); +} +bool BTM_IsRemoteVersionReceived(const RawAddress& addr) { + inc_func_call_count(__func__); + return test::mock::stack_acl::BTM_IsRemoteVersionReceived(addr); } bool BTM_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version, uint16_t* manufacturer, uint16_t* lmp_sub_version) { @@ -289,7 +276,7 @@ bool acl_peer_supports_ble_connection_subrating_host( bool acl_refresh_remote_address(const RawAddress& identity_address, tBLE_ADDR_TYPE identity_address_type, const RawAddress& bda, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type, + tBLE_RAND_ADDR_TYPE rra_type, const RawAddress& rpa) { inc_func_call_count(__func__); return test::mock::stack_acl::acl_refresh_remote_address( @@ -301,14 +288,6 @@ bool acl_set_peer_le_features_from_handle(uint16_t hci_handle, return test::mock::stack_acl::acl_set_peer_le_features_from_handle(hci_handle, p); } -bool sco_peer_supports_esco_2m_phy(const RawAddress& remote_bda) { - inc_func_call_count(__func__); - return test::mock::stack_acl::sco_peer_supports_esco_2m_phy(remote_bda); -} -bool sco_peer_supports_esco_3m_phy(const RawAddress& remote_bda) { - inc_func_call_count(__func__); - return test::mock::stack_acl::sco_peer_supports_esco_3m_phy(remote_bda); -} void acl_send_data_packet_br_edr(const RawAddress& bd_addr, BT_HDR* p_buf) { inc_func_call_count(__func__); test::mock::stack_acl::acl_send_data_packet_br_edr(bd_addr, p_buf); @@ -320,10 +299,6 @@ void acl_create_classic_connection(const RawAddress& bd_addr, return test::mock::stack_acl::acl_create_classic_connection( bd_addr, there_are_high_priority_channels, is_bonding); } -bool IsEprAvailable(const tACL_CONN& p_acl) { - inc_func_call_count(__func__); - return test::mock::stack_acl::IsEprAvailable(p_acl); -} tACL_CONN* acl_get_connection_from_address(const RawAddress& bd_addr, tBT_TRANSPORT transport) { inc_func_call_count(__func__); @@ -403,10 +378,6 @@ uint8_t BTM_GetPeerSCA(const RawAddress& remote_bda, tBT_TRANSPORT transport) { inc_func_call_count(__func__); return test::mock::stack_acl::BTM_GetPeerSCA(remote_bda, transport); } -uint8_t BTM_SetTraceLevel(uint8_t new_level) { - inc_func_call_count(__func__); - return test::mock::stack_acl::BTM_SetTraceLevel(new_level); -} uint8_t acl_link_role_from_handle(uint16_t handle) { inc_func_call_count(__func__); return test::mock::stack_acl::acl_link_role_from_handle(handle); @@ -429,10 +400,10 @@ void ACL_UnregisterClient(struct acl_client_callback_s* callbacks) { } void BTM_ReadConnectionAddr(const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { inc_func_call_count(__func__); test::mock::stack_acl::BTM_ReadConnectionAddr(remote_bda, local_conn_addr, - p_addr_type); + p_addr_type, ota_address); } void BTM_RequestPeerSCA(const RawAddress& remote_bda, tBT_TRANSPORT transport) { inc_func_call_count(__func__); @@ -466,14 +437,6 @@ void BTM_unblock_sniff_mode_for(const RawAddress& peer_addr) { inc_func_call_count(__func__); test::mock::stack_acl::BTM_unblock_sniff_mode_for(peer_addr); } -void HACK_acl_check_sm4(tBTM_SEC_DEV_REC& record) { - inc_func_call_count(__func__); - test::mock::stack_acl::HACK_acl_check_sm4(record); -} -void acl_accept_connection_request(const RawAddress& bd_addr, uint8_t role) { - inc_func_call_count(__func__); - test::mock::stack_acl::acl_accept_connection_request(bd_addr, role); -} void acl_disconnect_after_role_switch(uint16_t conn_handle, tHCI_STATUS reason, std::string comment) { inc_func_call_count(__func__); @@ -485,10 +448,6 @@ void acl_disconnect_from_handle(uint16_t handle, tHCI_STATUS reason, inc_func_call_count(__func__); test::mock::stack_acl::acl_disconnect_from_handle(handle, reason, comment); } -void acl_link_segments_xmitted(BT_HDR* p_msg) { - inc_func_call_count(__func__); - test::mock::stack_acl::acl_link_segments_xmitted(p_msg); -} void acl_packets_completed(uint16_t handle, uint16_t credits) { inc_func_call_count(__func__); test::mock::stack_acl::acl_packets_completed(handle, credits); @@ -507,10 +466,6 @@ void acl_rcv_acl_data(BT_HDR* p_msg) { inc_func_call_count(__func__); test::mock::stack_acl::acl_rcv_acl_data(p_msg); } -void acl_reject_connection_request(const RawAddress& bd_addr, uint8_t reason) { - inc_func_call_count(__func__); - test::mock::stack_acl::acl_reject_connection_request(bd_addr, reason); -} void acl_send_data_packet_ble(const RawAddress& bd_addr, BT_HDR* p_buf) { inc_func_call_count(__func__); test::mock::stack_acl::acl_send_data_packet_ble(bd_addr, p_buf); @@ -530,10 +485,6 @@ void btm_acl_connected(const RawAddress& bda, uint16_t handle, inc_func_call_count(__func__); test::mock::stack_acl::btm_acl_connected(bda, handle, status, enc_mode); } -void btm_acl_connection_request(const RawAddress& bda, uint8_t* dc) { - inc_func_call_count(__func__); - test::mock::stack_acl::btm_acl_connection_request(bda, dc); -} void btm_acl_created(const RawAddress& bda, uint16_t hci_handle, tHCI_ROLE link_role, tBT_TRANSPORT transport) { inc_func_call_count(__func__); @@ -561,10 +512,6 @@ void btm_acl_notif_conn_collision(const RawAddress& bda) { inc_func_call_count(__func__); test::mock::stack_acl::btm_acl_notif_conn_collision(bda); } -void btm_acl_paging(BT_HDR* p, const RawAddress& bda) { - inc_func_call_count(__func__); - test::mock::stack_acl::btm_acl_paging(p, bda); -} void btm_acl_process_sca_cmpl_pkt(uint8_t len, uint8_t* data) { inc_func_call_count(__func__); test::mock::stack_acl::btm_acl_process_sca_cmpl_pkt(len, data); @@ -573,33 +520,15 @@ void btm_acl_removed(uint16_t handle) { inc_func_call_count(__func__); test::mock::stack_acl::btm_acl_removed(handle); } -void btm_acl_reset_paging(void) { - inc_func_call_count(__func__); - test::mock::stack_acl::btm_acl_reset_paging(); -} -void btm_acl_resubmit_page(void) { - inc_func_call_count(__func__); - test::mock::stack_acl::btm_acl_resubmit_page(); -} void btm_acl_role_changed(tHCI_STATUS hci_status, const RawAddress& bd_addr, tHCI_ROLE new_role) { inc_func_call_count(__func__); test::mock::stack_acl::btm_acl_role_changed(hci_status, bd_addr, new_role); } -void btm_acl_set_paging(bool value) { - inc_func_call_count(__func__); - test::mock::stack_acl::btm_acl_set_paging(value); -} void btm_acl_update_conn_addr(uint16_t handle, const RawAddress& address) { inc_func_call_count(__func__); test::mock::stack_acl::btm_acl_update_conn_addr(handle, address); } -void btm_configure_data_path(uint8_t direction, uint8_t path_id, - std::vector vendor_config) { - inc_func_call_count(__func__); - test::mock::stack_acl::btm_configure_data_path(direction, path_id, - vendor_config); -} void btm_acl_update_inquiry_status(uint8_t status) { inc_func_call_count(__func__); test::mock::stack_acl::btm_acl_update_inquiry_status(status); @@ -641,7 +570,7 @@ void btm_read_failed_contact_counter_complete(uint8_t* p) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_failed_contact_counter_complete(p); } -void btm_read_failed_contact_counter_timeout(UNUSED_ATTR void* data) { +void btm_read_failed_contact_counter_timeout(void* data) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_failed_contact_counter_timeout(data); } @@ -649,7 +578,7 @@ void btm_read_link_quality_complete(uint8_t* p, uint16_t evt_len) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_link_quality_complete(p, evt_len); } -void btm_read_link_quality_timeout(UNUSED_ATTR void* data) { +void btm_read_link_quality_timeout(void* data) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_link_quality_timeout(data); } @@ -672,10 +601,6 @@ void btm_read_remote_ext_features_failed(uint8_t status, uint16_t handle) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_remote_ext_features_failed(status, handle); } -void btm_read_remote_features_complete(uint16_t handle, uint8_t* features) { - inc_func_call_count(__func__); - test::mock::stack_acl::btm_read_remote_features_complete(handle, features); -} void btm_read_remote_version_complete(tHCI_STATUS status, uint16_t handle, uint8_t lmp_version, uint16_t manufacturer, @@ -688,7 +613,7 @@ void btm_read_rssi_complete(uint8_t* p, uint16_t evt_len) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_rssi_complete(p, evt_len); } -void btm_read_rssi_timeout(UNUSED_ATTR void* data) { +void btm_read_rssi_timeout(void* data) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_rssi_timeout(data); } @@ -696,7 +621,7 @@ void btm_read_tx_power_complete(uint8_t* p, uint16_t evt_len, bool is_ble) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_tx_power_complete(p, evt_len, is_ble); } -void btm_read_tx_power_timeout(UNUSED_ATTR void* data) { +void btm_read_tx_power_timeout(void* data) { inc_func_call_count(__func__); test::mock::stack_acl::btm_read_tx_power_timeout(data); } @@ -740,3 +665,6 @@ void BTM_unblock_role_switch_and_sniff_mode_for(const RawAddress& peer_addr) { } // END mockcify generation + +void BTM_block_role_switch_and_sniff_mode_for( + const RawAddress& /* peer_addr */) {} diff --git a/system/test/mock/mock_stack_acl.h b/system/test/mock/mock_stack_acl.h index 98b1e0ef7afc68fa899a7f23a243ece3a7fdac60..62ae3cdd751eb896e6de918c18947580f10abc0f 100644 --- a/system/test/mock/mock_stack_acl.h +++ b/system/test/mock/mock_stack_acl.h @@ -23,31 +23,18 @@ #include #include -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include - #include "device/include/controller.h" #include "stack/acl/acl.h" #include "stack/btm/security_device_record.h" +#include "stack/include/acl_client_callbacks.h" #include "stack/include/bt_hdr.h" -#include "stack/include/btm_client_interface.h" -#include "test/common/mock_functions.h" #include "types/class_of_device.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_acl { @@ -58,7 +45,7 @@ namespace stack_acl { // Returns: bool struct ACL_SupportTransparentSynchronousData { std::function body{ - [](const RawAddress& bd_addr) { return false; }}; + [](const RawAddress& /* bd_addr */) { return false; }}; bool operator()(const RawAddress& bd_addr) { return body(bd_addr); }; }; extern struct ACL_SupportTransparentSynchronousData @@ -68,7 +55,7 @@ extern struct ACL_SupportTransparentSynchronousData // Returns: bool struct BTM_BLE_IS_RESOLVE_BDA { std::function body{ - [](const RawAddress& x) { return false; }}; + [](const RawAddress& /* x */) { return false; }}; bool operator()(const RawAddress& x) { return body(x); }; }; extern struct BTM_BLE_IS_RESOLVE_BDA BTM_BLE_IS_RESOLVE_BDA; @@ -77,9 +64,8 @@ extern struct BTM_BLE_IS_RESOLVE_BDA BTM_BLE_IS_RESOLVE_BDA; // Returns: bool struct BTM_IsAclConnectionUp { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport) { - return false; - }}; + body{[](const RawAddress& /* remote_bda */, + tBT_TRANSPORT /* transport */) { return false; }}; bool operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport) { return body(remote_bda, transport); }; @@ -90,9 +76,8 @@ extern struct BTM_IsAclConnectionUp BTM_IsAclConnectionUp; // Returns: bool struct BTM_IsAclConnectionUpAndHandleValid { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport) { - return false; - }}; + body{[](const RawAddress& /* remote_bda */, + tBT_TRANSPORT /* transport */) { return false; }}; bool operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport) { return body(remote_bda, transport); }; @@ -104,7 +89,7 @@ extern struct BTM_IsAclConnectionUpAndHandleValid // Returns: bool struct BTM_IsAclConnectionUpFromHandle { std::function body{ - [](uint16_t hci_handle) { return false; }}; + [](uint16_t /* hci_handle */) { return false; }}; bool operator()(uint16_t hci_handle) { return body(hci_handle); }; }; extern struct BTM_IsAclConnectionUpFromHandle BTM_IsAclConnectionUpFromHandle; @@ -113,7 +98,7 @@ extern struct BTM_IsAclConnectionUpFromHandle BTM_IsAclConnectionUpFromHandle; // Returns: bool struct BTM_IsBleConnection { std::function body{ - [](uint16_t hci_handle) { return false; }}; + [](uint16_t /* hci_handle */) { return false; }}; bool operator()(uint16_t hci_handle) { return body(hci_handle); }; }; extern struct BTM_IsBleConnection BTM_IsBleConnection; @@ -122,29 +107,37 @@ extern struct BTM_IsBleConnection BTM_IsBleConnection; // Returns: bool struct BTM_IsPhy2mSupported { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport) { - return false; - }}; + body{[](const RawAddress& /* remote_bda */, + tBT_TRANSPORT /* transport */) { return false; }}; bool operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport) { return body(remote_bda, transport); }; }; extern struct BTM_IsPhy2mSupported BTM_IsPhy2mSupported; // Name: BTM_ReadRemoteConnectionAddr -// Params: const RawAddress& pseudo_addr, RawAddress& conn_addr, -// tBLE_ADDR_TYPE* p_addr_type -// Returns: bool +// Params: const RawAddress& pseudo_addr, RawAddress& conn_addr, bool +// ota_address tBLE_ADDR_TYPE* p_addr_type Returns: bool struct BTM_ReadRemoteConnectionAddr { std::function - body{[](const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { return false; }}; + tBLE_ADDR_TYPE* p_addr_type, bool ota_address)> + body{[](const RawAddress& /* pseudo_addr */, RawAddress& /* conn_addr */, + tBLE_ADDR_TYPE* /* p_addr_type */, + bool /* ota_address */) { return false; }}; bool operator()(const RawAddress& pseudo_addr, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - return body(pseudo_addr, conn_addr, p_addr_type); + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { + return body(pseudo_addr, conn_addr, p_addr_type, ota_address); }; }; extern struct BTM_ReadRemoteConnectionAddr BTM_ReadRemoteConnectionAddr; +// Name: BTM_IsRemoteVersionReceived +// Params: const RawAddress& addr +// Returns: bool +struct BTM_IsRemoteVersionReceived { + std::function body{ + [](const RawAddress& /* addr */) { return false; }}; + bool operator()(const RawAddress& addr) { return body(addr); }; +}; +extern struct BTM_IsRemoteVersionReceived BTM_IsRemoteVersionReceived; // Name: BTM_ReadRemoteVersion // Params: const RawAddress& addr, uint8_t* lmp_version, uint16_t* // manufacturer, uint16_t* lmp_sub_version @@ -152,9 +145,9 @@ extern struct BTM_ReadRemoteConnectionAddr BTM_ReadRemoteConnectionAddr; struct BTM_ReadRemoteVersion { std::function - body{[](const RawAddress& addr, uint8_t* lmp_version, - uint16_t* manufacturer, - uint16_t* lmp_sub_version) { return false; }}; + body{[](const RawAddress& /* addr */, uint8_t* /* lmp_version */, + uint16_t* /* manufacturer */, + uint16_t* /* lmp_sub_version */) { return false; }}; bool operator()(const RawAddress& addr, uint8_t* lmp_version, uint16_t* manufacturer, uint16_t* lmp_sub_version) { return body(addr, lmp_version, manufacturer, lmp_sub_version); @@ -166,7 +159,7 @@ extern struct BTM_ReadRemoteVersion BTM_ReadRemoteVersion; // Returns: bool struct BTM_is_sniff_allowed_for { std::function body{ - [](const RawAddress& peer_addr) { return false; }}; + [](const RawAddress& /* peer_addr */) { return false; }}; bool operator()(const RawAddress& peer_addr) { return body(peer_addr); }; }; extern struct BTM_is_sniff_allowed_for BTM_is_sniff_allowed_for; @@ -175,7 +168,7 @@ extern struct BTM_is_sniff_allowed_for BTM_is_sniff_allowed_for; // Returns: void struct acl_send_data_packet_br_edr { std::function body{ - [](const RawAddress& bd_addr, BT_HDR* p_buf) {}}; + [](const RawAddress& /* bd_addr */, BT_HDR* /* p_buf */) {}}; void operator()(const RawAddress& bd_addr, BT_HDR* p_buf) { return body(bd_addr, p_buf); }; @@ -186,7 +179,7 @@ extern struct acl_send_data_packet_br_edr acl_send_data_packet_br_edr; // Returns: bool struct acl_create_le_connection { std::function body{ - [](const RawAddress& bd_addr) { return false; }}; + [](const RawAddress& /* bd_addr */) { return false; }}; bool operator()(const RawAddress& bd_addr) { return body(bd_addr); }; }; extern struct acl_create_le_connection acl_create_le_connection; @@ -196,9 +189,8 @@ extern struct acl_create_le_connection acl_create_le_connection; struct acl_create_le_connection_with_id { std::function - body{[](uint8_t id, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) { - return false; - }}; + body{[](uint8_t /* id */, const RawAddress& /* bd_addr */, + tBLE_ADDR_TYPE /* addr_type */) { return false; }}; bool operator()(uint8_t id, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) { return body(id, bd_addr, addr_type); @@ -218,7 +210,9 @@ extern struct acl_is_role_switch_allowed acl_is_role_switch_allowed; // Returns: bool struct acl_is_switch_role_idle { std::function body{ - [](const RawAddress& bd_addr, tBT_TRANSPORT transport) { return false; }}; + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { + return false; + }}; bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { return body(bd_addr, transport); }; @@ -229,7 +223,7 @@ extern struct acl_is_switch_role_idle acl_is_switch_role_idle; // Returns: bool struct acl_peer_supports_ble_2m_phy { std::function body{ - [](uint16_t hci_handle) { return false; }}; + [](uint16_t /* hci_handle */) { return false; }}; bool operator()(uint16_t hci_handle) { return body(hci_handle); }; }; extern struct acl_peer_supports_ble_2m_phy acl_peer_supports_ble_2m_phy; @@ -238,7 +232,7 @@ extern struct acl_peer_supports_ble_2m_phy acl_peer_supports_ble_2m_phy; // Returns: bool struct acl_peer_supports_ble_coded_phy { std::function body{ - [](uint16_t hci_handle) { return false; }}; + [](uint16_t /* hci_handle */) { return false; }}; bool operator()(uint16_t hci_handle) { return body(hci_handle); }; }; extern struct acl_peer_supports_ble_coded_phy acl_peer_supports_ble_coded_phy; @@ -247,7 +241,7 @@ extern struct acl_peer_supports_ble_coded_phy acl_peer_supports_ble_coded_phy; // Returns: bool struct acl_peer_supports_ble_connection_parameters_request { std::function body{ - [](const RawAddress& remote_bda) { return false; }}; + [](const RawAddress& /* remote_bda */) { return false; }}; bool operator()(const RawAddress& remote_bda) { return body(remote_bda); }; }; extern struct acl_peer_supports_ble_connection_parameters_request @@ -257,7 +251,7 @@ extern struct acl_peer_supports_ble_connection_parameters_request // Returns: bool struct acl_peer_supports_ble_packet_extension { std::function body{ - [](uint16_t hci_handle) { return false; }}; + [](uint16_t /* hci_handle */) { return false; }}; bool operator()(uint16_t hci_handle) { return body(hci_handle); }; }; extern struct acl_peer_supports_ble_packet_extension @@ -267,7 +261,7 @@ extern struct acl_peer_supports_ble_packet_extension // Returns: bool struct acl_peer_supports_sniff_subrating { std::function body{ - [](const RawAddress& remote_bda) { return false; }}; + [](const RawAddress& /* remote_bda */) { return false; }}; bool operator()(const RawAddress& remote_bda) { return body(remote_bda); }; }; extern struct acl_peer_supports_sniff_subrating @@ -277,7 +271,7 @@ extern struct acl_peer_supports_sniff_subrating // Returns: bool struct acl_peer_supports_ble_connection_subrating { std::function body{ - [](const RawAddress& remote_bda) { return false; }}; + [](const RawAddress& /* remote_bda */) { return false; }}; bool operator()(const RawAddress& remote_bda) { return body(remote_bda); }; }; extern struct acl_peer_supports_ble_connection_subrating @@ -287,7 +281,7 @@ extern struct acl_peer_supports_ble_connection_subrating // Returns: bool struct acl_peer_supports_ble_connection_subrating_host { std::function body{ - [](const RawAddress& remote_bda) { return false; }}; + [](const RawAddress& /* remote_bda */) { return false; }}; bool operator()(const RawAddress& remote_bda) { return body(remote_bda); }; }; extern struct acl_peer_supports_ble_connection_subrating_host @@ -297,17 +291,17 @@ extern struct acl_peer_supports_ble_connection_subrating_host // identity_address_type, const RawAddress& bda, tBLE_ADDR_TYPE rra_type, // const RawAddress& rpa Returns: bool struct acl_refresh_remote_address { - std::function - body{[](const RawAddress& identity_address, - tBLE_ADDR_TYPE identity_address_type, const RawAddress& bda, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type, - const RawAddress& rpa) { return false; }}; + std::function + body{[](const RawAddress& /* identity_address */, + tBLE_ADDR_TYPE /* identity_address_type */, + const RawAddress& /* bda */, tBLE_RAND_ADDR_TYPE /* rra_type */, + const RawAddress& /* rpa */) { return false; }}; bool operator()(const RawAddress& identity_address, tBLE_ADDR_TYPE identity_address_type, const RawAddress& bda, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type, const RawAddress& rpa) { + tBLE_RAND_ADDR_TYPE rra_type, const RawAddress& rpa) { return body(identity_address, identity_address_type, bda, rra_type, rpa); }; }; @@ -317,31 +311,13 @@ extern struct acl_refresh_remote_address acl_refresh_remote_address; // Returns: bool struct acl_set_peer_le_features_from_handle { std::function body{ - [](uint16_t hci_handle, const uint8_t* p) { return false; }}; + [](uint16_t /* hci_handle */, const uint8_t* /* p */) { return false; }}; bool operator()(uint16_t hci_handle, const uint8_t* p) { return body(hci_handle, p); }; }; extern struct acl_set_peer_le_features_from_handle acl_set_peer_le_features_from_handle; -// Name: sco_peer_supports_esco_2m_phy -// Params: const RawAddress& remote_bda -// Returns: bool -struct sco_peer_supports_esco_2m_phy { - std::function body{ - [](const RawAddress& remote_bda) { return false; }}; - bool operator()(const RawAddress& remote_bda) { return body(remote_bda); }; -}; -extern struct sco_peer_supports_esco_2m_phy sco_peer_supports_esco_2m_phy; -// Name: sco_peer_supports_esco_3m_phy -// Params: const RawAddress& remote_bda -// Returns: bool -struct sco_peer_supports_esco_3m_phy { - std::function body{ - [](const RawAddress& remote_bda) { return false; }}; - bool operator()(const RawAddress& remote_bda) { return body(remote_bda); }; -}; -extern struct sco_peer_supports_esco_3m_phy sco_peer_supports_esco_3m_phy; // Name: acl_create_classic_connection // Params: const RawAddress& bd_addr, bool there_are_high_priority_channels, // bool is_bonding Returns: constexpr uint16_t kDefaultPacketTypes = @@ -351,29 +327,21 @@ extern struct sco_peer_supports_esco_3m_phy sco_peer_supports_esco_3m_phy; struct acl_create_classic_connection { std::function - body{[](const RawAddress& bd_addr, bool there_are_high_priority_channels, - bool is_bonding) { return 0; }}; + body{[](const RawAddress& /* bd_addr */, + bool /* there_are_high_priority_channels */, + bool /* is_bonding */) { return 0; }}; void operator()(const RawAddress& bd_addr, bool there_are_high_priority_channels, bool is_bonding) { return body(bd_addr, there_are_high_priority_channels, is_bonding); }; }; extern struct acl_create_classic_connection acl_create_classic_connection; -// Name: IsEprAvailable -// Params: const tACL_CONN& p_acl -// Returns: inline bool -struct IsEprAvailable { - std::function body{ - [](const tACL_CONN& p_acl) { return 0; }}; - inline bool operator()(const tACL_CONN& p_acl) { return body(p_acl); }; -}; -extern struct IsEprAvailable IsEprAvailable; // Name: acl_get_connection_from_address // Params: const RawAddress& bd_addr, tBT_TRANSPORT transport // Returns: tACL_CONN* struct acl_get_connection_from_address { std::function - body{[](const RawAddress& bd_addr, tBT_TRANSPORT transport) { + body{[](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { return nullptr; }}; tACL_CONN* operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { @@ -386,7 +354,7 @@ extern struct acl_get_connection_from_address acl_get_connection_from_address; // Returns: tACL_CONN* struct btm_acl_for_bda { std::function - body{[](const RawAddress& bd_addr, tBT_TRANSPORT transport) { + body{[](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { return nullptr; }}; tACL_CONN* operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { @@ -399,7 +367,7 @@ extern struct btm_acl_for_bda btm_acl_for_bda; // Returns: tACL_CONN* struct acl_get_connection_from_handle { std::function body{ - [](uint16_t handle) { return nullptr; }}; + [](uint16_t /* handle */) { return nullptr; }}; tACL_CONN* operator()(uint16_t handle) { return body(handle); }; }; extern struct acl_get_connection_from_handle acl_get_connection_from_handle; @@ -408,7 +376,9 @@ extern struct acl_get_connection_from_handle acl_get_connection_from_handle; // Returns: tBTM_STATUS struct BTM_GetLinkSuperTout { std::function - body{[](const RawAddress& remote_bda, uint16_t* p_timeout) { return 0; }}; + body{[](const RawAddress& /* remote_bda */, uint16_t* /* p_timeout */) { + return 0; + }}; tBTM_STATUS operator()(const RawAddress& remote_bda, uint16_t* p_timeout) { return body(remote_bda, p_timeout); }; @@ -420,7 +390,7 @@ extern struct BTM_GetLinkSuperTout BTM_GetLinkSuperTout; struct BTM_GetRole { std::function - body{[](const RawAddress& remote_bd_addr, tHCI_ROLE* p_role) { + body{[](const RawAddress& /* remote_bd_addr */, tHCI_ROLE* /* p_role */) { return 0; }}; tBTM_STATUS operator()(const RawAddress& remote_bd_addr, tHCI_ROLE* p_role) { @@ -433,7 +403,9 @@ extern struct BTM_GetRole BTM_GetRole; // Returns: tBTM_STATUS struct BTM_ReadFailedContactCounter { std::function - body{[](const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) { return 0; }}; + body{[](const RawAddress& /* remote_bda */, tBTM_CMPL_CB* /* p_cb */) { + return 0; + }}; tBTM_STATUS operator()(const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) { return body(remote_bda, p_cb); }; @@ -444,7 +416,9 @@ extern struct BTM_ReadFailedContactCounter BTM_ReadFailedContactCounter; // Returns: tBTM_STATUS struct BTM_ReadRSSI { std::function - body{[](const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) { return 0; }}; + body{[](const RawAddress& /* remote_bda */, tBTM_CMPL_CB* /* p_cb */) { + return 0; + }}; tBTM_STATUS operator()(const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) { return body(remote_bda, p_cb); }; @@ -456,8 +430,8 @@ extern struct BTM_ReadRSSI BTM_ReadRSSI; struct BTM_ReadTxPower { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport, - tBTM_CMPL_CB* p_cb) { return BT_TRANSPORT_BR_EDR; }}; + body{[](const RawAddress& /* remote_bda */, tBT_TRANSPORT /* transport */, + tBTM_CMPL_CB* /* p_cb */) { return BT_TRANSPORT_BR_EDR; }}; tBTM_STATUS operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport, tBTM_CMPL_CB* p_cb) { return body(remote_bda, transport, p_cb); @@ -469,7 +443,9 @@ extern struct BTM_ReadTxPower BTM_ReadTxPower; // Returns: tBTM_STATUS struct BTM_SetLinkSuperTout { std::function - body{[](const RawAddress& remote_bda, uint16_t timeout) { return 0; }}; + body{[](const RawAddress& /* remote_bda */, uint16_t /* timeout */) { + return 0; + }}; tBTM_STATUS operator()(const RawAddress& remote_bda, uint16_t timeout) { return body(remote_bda, timeout); }; @@ -480,7 +456,7 @@ extern struct BTM_SetLinkSuperTout BTM_SetLinkSuperTout; // Returns: tBTM_STATUS struct BTM_SwitchRoleToCentral { std::function body{ - [](const RawAddress& remote_bd_addr) { return 0; }}; + [](const RawAddress& /* remote_bd_addr */) { return 0; }}; tBTM_STATUS operator()(const RawAddress& remote_bd_addr) { return body(remote_bd_addr); }; @@ -491,7 +467,7 @@ extern struct BTM_SwitchRoleToCentral BTM_SwitchRoleToCentral; // Returns: tBTM_STATUS struct btm_remove_acl { std::function - body{[](const RawAddress& bd_addr, tBT_TRANSPORT transport) { + body{[](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { return BT_TRANSPORT_BR_EDR; }}; tBTM_STATUS operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { @@ -520,9 +496,8 @@ extern struct btm_is_acl_locally_initiated btm_is_acl_locally_initiated; // Returns: uint16_t struct BTM_GetHCIConnHandle { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport) { - return BT_TRANSPORT_BR_EDR; - }}; + body{[](const RawAddress& /* remote_bda */, + tBT_TRANSPORT /* transport */) { return BT_TRANSPORT_BR_EDR; }}; uint16_t operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport) { return body(remote_bda, transport); }; @@ -533,7 +508,7 @@ extern struct BTM_GetHCIConnHandle BTM_GetHCIConnHandle; // Returns: uint16_t struct BTM_GetMaxPacketSize { std::function body{ - [](const RawAddress& addr) { return 0; }}; + [](const RawAddress& /* addr */) { return 0; }}; uint16_t operator()(const RawAddress& addr) { return body(addr); }; }; extern struct BTM_GetMaxPacketSize BTM_GetMaxPacketSize; @@ -558,29 +533,19 @@ extern struct acl_get_supported_packet_types acl_get_supported_packet_types; // Returns: uint8_t struct BTM_GetPeerSCA { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport) { - return BT_TRANSPORT_BR_EDR; - }}; + body{[](const RawAddress& /* remote_bda */, + tBT_TRANSPORT /* transport */) { return BT_TRANSPORT_BR_EDR; }}; uint8_t operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport) { return body(remote_bda, transport); }; }; extern struct BTM_GetPeerSCA BTM_GetPeerSCA; -// Name: BTM_SetTraceLevel -// Params: uint8_t new_level -// Returns: uint8_t -struct BTM_SetTraceLevel { - std::function body{ - [](uint8_t new_level) { return 0; }}; - uint8_t operator()(uint8_t new_level) { return body(new_level); }; -}; -extern struct BTM_SetTraceLevel BTM_SetTraceLevel; // Name: acl_link_role_from_handle // Params: uint16_t handle // Returns: uint8_t struct acl_link_role_from_handle { std::function body{ - [](uint16_t handle) { return 0; }}; + [](uint16_t /* handle */) { return 0; }}; uint8_t operator()(uint16_t handle) { return body(handle); }; }; extern struct acl_link_role_from_handle acl_link_role_from_handle; @@ -589,7 +554,7 @@ extern struct acl_link_role_from_handle acl_link_role_from_handle; // Returns: uint8_t struct btm_handle_to_acl_index { std::function body{ - [](uint16_t hci_handle) { return 0; }}; + [](uint16_t /* hci_handle */) { return 0; }}; uint8_t operator()(uint16_t hci_handle) { return body(hci_handle); }; }; extern struct btm_handle_to_acl_index btm_handle_to_acl_index; @@ -598,7 +563,7 @@ extern struct btm_handle_to_acl_index btm_handle_to_acl_index; // Returns: uint8_t* struct BTM_ReadRemoteFeatures { std::function body{ - [](const RawAddress& addr) { return nullptr; }}; + [](const RawAddress& /* addr */) { return nullptr; }}; uint8_t* operator()(const RawAddress& addr) { return body(addr); }; }; extern struct BTM_ReadRemoteFeatures BTM_ReadRemoteFeatures; @@ -607,7 +572,7 @@ extern struct BTM_ReadRemoteFeatures BTM_ReadRemoteFeatures; // Returns: void struct ACL_RegisterClient { std::function body{ - [](struct acl_client_callback_s* callbacks) { ; }}; + [](struct acl_client_callback_s* /* callbacks */) { ; }}; void operator()(struct acl_client_callback_s* callbacks) { body(callbacks); }; }; extern struct ACL_RegisterClient ACL_RegisterClient; @@ -616,21 +581,22 @@ extern struct ACL_RegisterClient ACL_RegisterClient; // Returns: void struct ACL_UnregisterClient { std::function body{ - [](struct acl_client_callback_s* callbacks) { ; }}; + [](struct acl_client_callback_s* /* callbacks */) { ; }}; void operator()(struct acl_client_callback_s* callbacks) { body(callbacks); }; }; extern struct ACL_UnregisterClient ACL_UnregisterClient; // Name: BTM_ReadConnectionAddr -// Params: const RawAddress& remote_bda, RawAddress& local_conn_addr, -// tBLE_ADDR_TYPE* p_addr_type Returns: void +// Params: const RawAddress& remote_bda, RawAddress& local_conn_addr, bool +// ota_address tBLE_ADDR_TYPE* p_addr_type Returns: void struct BTM_ReadConnectionAddr { std::function - body{[](const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { ; }}; + tBLE_ADDR_TYPE* p_addr_type, bool ota_address)> + body{[](const RawAddress& /* remote_bda */, + RawAddress& /* local_conn_addr */, + tBLE_ADDR_TYPE* /* p_addr_type */, bool /* ota_address */) { ; }}; void operator()(const RawAddress& remote_bda, RawAddress& local_conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { - body(remote_bda, local_conn_addr, p_addr_type); + tBLE_ADDR_TYPE* p_addr_type, bool ota_address) { + body(remote_bda, local_conn_addr, p_addr_type, ota_address); }; }; extern struct BTM_ReadConnectionAddr BTM_ReadConnectionAddr; @@ -639,7 +605,8 @@ extern struct BTM_ReadConnectionAddr BTM_ReadConnectionAddr; // Returns: void struct BTM_RequestPeerSCA { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport) { ; }}; + body{[](const RawAddress& /* remote_bda */, + tBT_TRANSPORT /* transport */) { ; }}; void operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport) { body(remote_bda, transport); }; @@ -650,7 +617,7 @@ extern struct BTM_RequestPeerSCA BTM_RequestPeerSCA; // Returns: void struct BTM_acl_after_controller_started { std::function body{ - [](const controller_t* controller) { ; }}; + [](const controller_t* /* controller */) { ; }}; void operator()(const controller_t* controller) { body(controller); }; }; extern struct BTM_acl_after_controller_started BTM_acl_after_controller_started; @@ -659,7 +626,7 @@ extern struct BTM_acl_after_controller_started BTM_acl_after_controller_started; // Returns: void struct BTM_block_role_switch_for { std::function body{ - [](const RawAddress& peer_addr) { ; }}; + [](const RawAddress& /* peer_addr */) { ; }}; void operator()(const RawAddress& peer_addr) { body(peer_addr); }; }; extern struct BTM_block_role_switch_for BTM_block_role_switch_for; @@ -668,7 +635,7 @@ extern struct BTM_block_role_switch_for BTM_block_role_switch_for; // Returns: void struct BTM_block_sniff_mode_for { std::function body{ - [](const RawAddress& peer_addr) { ; }}; + [](const RawAddress& /* peer_addr */) { ; }}; void operator()(const RawAddress& peer_addr) { body(peer_addr); }; }; extern struct BTM_block_sniff_mode_for BTM_block_sniff_mode_for; @@ -693,7 +660,7 @@ extern struct BTM_default_unblock_role_switch BTM_default_unblock_role_switch; // Returns: void struct BTM_unblock_role_switch_for { std::function body{ - [](const RawAddress& peer_addr) { ; }}; + [](const RawAddress& /* peer_addr */) { ; }}; void operator()(const RawAddress& peer_addr) { body(peer_addr); }; }; extern struct BTM_unblock_role_switch_for BTM_unblock_role_switch_for; @@ -702,39 +669,18 @@ extern struct BTM_unblock_role_switch_for BTM_unblock_role_switch_for; // Returns: void struct BTM_unblock_sniff_mode_for { std::function body{ - [](const RawAddress& peer_addr) { ; }}; + [](const RawAddress& /* peer_addr */) { ; }}; void operator()(const RawAddress& peer_addr) { body(peer_addr); }; }; extern struct BTM_unblock_sniff_mode_for BTM_unblock_sniff_mode_for; -// Name: HACK_acl_check_sm4 -// Params: tBTM_SEC_DEV_REC& record -// Returns: void -struct HACK_acl_check_sm4 { - std::function body{ - [](tBTM_SEC_DEV_REC& record) { ; }}; - void operator()(tBTM_SEC_DEV_REC& record) { body(record); }; -}; -extern struct HACK_acl_check_sm4 HACK_acl_check_sm4; -// Name: acl_accept_connection_request -// Params: const RawAddress& bd_addr, uint8_t role -// Returns: void -struct acl_accept_connection_request { - std::function body{ - [](const RawAddress& bd_addr, uint8_t role) { ; }}; - void operator()(const RawAddress& bd_addr, uint8_t role) { - body(bd_addr, role); - }; -}; -extern struct acl_accept_connection_request acl_accept_connection_request; // Name: acl_disconnect_after_role_switch // Params: uint16_t conn_handle, tHCI_STATUS reason // Returns: void struct acl_disconnect_after_role_switch { std::function - body{[](uint16_t conn_handle, tHCI_STATUS reason, std::string comment) { - ; - }}; + body{[](uint16_t /* conn_handle */, tHCI_STATUS /* reason */, + std::string /* comment */) { ; }}; void operator()(uint16_t conn_handle, tHCI_STATUS reason, std::string comment) { body(conn_handle, reason, comment); @@ -746,26 +692,19 @@ extern struct acl_disconnect_after_role_switch acl_disconnect_after_role_switch; // Returns: void struct acl_disconnect_from_handle { std::function - body{[](uint16_t handle, tHCI_STATUS reason, std::string comment) { ; }}; + body{[](uint16_t /* handle */, tHCI_STATUS /* reason */, + std::string /* comment */) { ; }}; void operator()(uint16_t handle, tHCI_STATUS reason, std::string comment) { body(handle, reason, comment); }; }; extern struct acl_disconnect_from_handle acl_disconnect_from_handle; -// Name: acl_link_segments_xmitted -// Params: BT_HDR* p_msg -// Returns: void -struct acl_link_segments_xmitted { - std::function body{[](BT_HDR* p_msg) { ; }}; - void operator()(BT_HDR* p_msg) { body(p_msg); }; -}; -extern struct acl_link_segments_xmitted acl_link_segments_xmitted; // Name: acl_packets_completed // Params: uint16_t handle, uint16_t credits // Returns: void struct acl_packets_completed { std::function body{ - [](uint16_t handle, uint16_t credits) { ; }}; + [](uint16_t /* handle */, uint16_t /* credits */) { ; }}; void operator()(uint16_t handle, uint16_t credits) { body(handle, credits); }; }; extern struct acl_packets_completed acl_packets_completed; @@ -775,8 +714,8 @@ extern struct acl_packets_completed acl_packets_completed; struct acl_process_extended_features { std::function - body{[](uint16_t handle, uint8_t current_page_number, - uint8_t max_page_number, uint64_t features) { ; }}; + body{[](uint16_t /* handle */, uint8_t /* current_page_number */, + uint8_t /* max_page_number */, uint64_t /* features */) { ; }}; void operator()(uint16_t handle, uint8_t current_page_number, uint8_t max_page_number, uint64_t features) { body(handle, current_page_number, max_page_number, features); @@ -788,7 +727,7 @@ extern struct acl_process_extended_features acl_process_extended_features; // Returns: void struct acl_process_supported_features { std::function body{ - [](uint16_t handle, uint64_t features) { ; }}; + [](uint16_t /* handle */, uint64_t /* features */) { ; }}; void operator()(uint16_t handle, uint64_t features) { body(handle, features); }; @@ -798,27 +737,16 @@ extern struct acl_process_supported_features acl_process_supported_features; // Params: BT_HDR* p_msg // Returns: void struct acl_rcv_acl_data { - std::function body{[](BT_HDR* p_msg) { ; }}; + std::function body{[](BT_HDR* /* p_msg */) { ; }}; void operator()(BT_HDR* p_msg) { body(p_msg); }; }; extern struct acl_rcv_acl_data acl_rcv_acl_data; -// Name: acl_reject_connection_request -// Params: const RawAddress& bd_addr, uint8_t reason -// Returns: void -struct acl_reject_connection_request { - std::function body{ - [](const RawAddress& bd_addr, uint8_t reason) { ; }}; - void operator()(const RawAddress& bd_addr, uint8_t reason) { - body(bd_addr, reason); - }; -}; -extern struct acl_reject_connection_request acl_reject_connection_request; // Name: acl_send_data_packet_ble // Params: const RawAddress& bd_addr, BT_HDR* p_buf // Returns: void struct acl_send_data_packet_ble { std::function body{ - [](const RawAddress& bd_addr, BT_HDR* p_buf) { ; }}; + [](const RawAddress& /* bd_addr */, BT_HDR* /* p_buf */) { ; }}; void operator()(const RawAddress& bd_addr, BT_HDR* p_buf) { body(bd_addr, p_buf); }; @@ -829,7 +757,7 @@ extern struct acl_send_data_packet_ble acl_send_data_packet_ble; // Returns: void struct acl_set_disconnect_reason { std::function body{ - [](tHCI_STATUS acl_disc_reason) { ; }}; + [](tHCI_STATUS /* acl_disc_reason */) { ; }}; void operator()(tHCI_STATUS acl_disc_reason) { body(acl_disc_reason); }; }; extern struct acl_set_disconnect_reason acl_set_disconnect_reason; @@ -839,8 +767,8 @@ extern struct acl_set_disconnect_reason acl_set_disconnect_reason; struct acl_write_automatic_flush_timeout { std::function - body{ - [](const RawAddress& bd_addr, uint16_t flush_timeout_in_ticks) { ; }}; + body{[](const RawAddress& /* bd_addr */, + uint16_t /* flush_timeout_in_ticks */) { ; }}; void operator()(const RawAddress& bd_addr, uint16_t flush_timeout_in_ticks) { body(bd_addr, flush_timeout_in_ticks); }; @@ -853,8 +781,8 @@ extern struct acl_write_automatic_flush_timeout struct btm_acl_connected { std::function - body{[](const RawAddress& bda, uint16_t handle, tHCI_STATUS status, - uint8_t enc_mode) { ; }}; + body{[](const RawAddress& /* bda */, uint16_t /* handle */, + tHCI_STATUS /* status */, uint8_t /* enc_mode */) { ; }}; void operator()(const RawAddress& bda, uint16_t handle, tHCI_STATUS status, uint8_t enc_mode) { body(bda, handle, status, enc_mode); @@ -867,31 +795,22 @@ extern struct btm_acl_connected btm_acl_connected; struct btm_connection_request { std::function - body{[](const RawAddress& bda, - const bluetooth::types::ClassOfDevice& cod) { ; }}; + body{[](const RawAddress& /* bda */, + const bluetooth::types::ClassOfDevice& /* cod */) { ; }}; void operator()(const RawAddress& bda, const bluetooth::types::ClassOfDevice& cod) { body(bda, cod); }; }; -extern struct btm_acl_connection_request btm_acl_connection_request; -// Name: btm_acl_connection_request -// Params: const RawAddress& bda, uint8_t* dc -// Returns: void -struct btm_acl_connection_request { - std::function body{ - [](const RawAddress& bda, uint8_t* dc) { ; }}; - void operator()(const RawAddress& bda, uint8_t* dc) { body(bda, dc); }; -}; -extern struct btm_acl_connection_request btm_acl_connection_request; +extern struct btm_connection_request btm_connection_request; // Name: btm_acl_created // Params: const RawAddress& bda, uint16_t hci_handle, tHCI_ROLE link_role, // tBT_TRANSPORT transport Returns: void struct btm_acl_created { std::function - body{[](const RawAddress& bda, uint16_t hci_handle, tHCI_ROLE link_role, - tBT_TRANSPORT transport) { ; }}; + body{[](const RawAddress& /* bda */, uint16_t /* hci_handle */, + tHCI_ROLE /* link_role */, tBT_TRANSPORT /* transport */) { ; }}; void operator()(const RawAddress& bda, uint16_t hci_handle, tHCI_ROLE link_role, tBT_TRANSPORT transport) { body(bda, hci_handle, link_role, transport); @@ -911,7 +830,8 @@ extern struct btm_acl_device_down btm_acl_device_down; // Returns: void struct btm_acl_disconnected { std::function - body{[](tHCI_STATUS status, uint16_t handle, tHCI_REASON reason) { ; }}; + body{[](tHCI_STATUS /* status */, uint16_t /* handle */, + tHCI_REASON /* reason */) { ; }}; void operator()(tHCI_STATUS status, uint16_t handle, tHCI_REASON reason) { body(status, handle, reason); }; @@ -922,7 +842,7 @@ extern struct btm_acl_disconnected btm_acl_disconnected; // Returns: void struct btm_acl_iso_disconnected { std::function body{ - [](uint16_t handle, tHCI_REASON reason) { ; }}; + [](uint16_t /* handle */, tHCI_REASON /* reason */) { ; }}; void operator()(uint16_t handle, tHCI_REASON reason) { body(handle, reason); }; @@ -933,7 +853,8 @@ extern struct btm_acl_iso_disconnected btm_acl_iso_disconnected; // Returns: void struct btm_acl_encrypt_change { std::function - body{[](uint16_t handle, uint8_t status, uint8_t encr_enable) { ; }}; + body{[](uint16_t /* handle */, uint8_t /* status */, + uint8_t /* encr_enable */) { ; }}; void operator()(uint16_t handle, uint8_t status, uint8_t encr_enable) { body(handle, status, encr_enable); }; @@ -944,25 +865,16 @@ extern struct btm_acl_encrypt_change btm_acl_encrypt_change; // Returns: void struct btm_acl_notif_conn_collision { std::function body{ - [](const RawAddress& bda) { ; }}; + [](const RawAddress& /* bda */) { ; }}; void operator()(const RawAddress& bda) { body(bda); }; }; extern struct btm_acl_notif_conn_collision btm_acl_notif_conn_collision; -// Name: btm_acl_paging -// Params: BT_HDR* p, const RawAddress& bda -// Returns: void -struct btm_acl_paging { - std::function body{ - [](BT_HDR* p, const RawAddress& bda) { ; }}; - void operator()(BT_HDR* p, const RawAddress& bda) { body(p, bda); }; -}; -extern struct btm_acl_paging btm_acl_paging; // Name: btm_acl_process_sca_cmpl_pkt // Params: uint8_t len, uint8_t* data // Returns: void struct btm_acl_process_sca_cmpl_pkt { std::function body{ - [](uint8_t len, uint8_t* data) { ; }}; + [](uint8_t /* len */, uint8_t* /* data */) { ; }}; void operator()(uint8_t len, uint8_t* data) { body(len, data); }; }; extern struct btm_acl_process_sca_cmpl_pkt btm_acl_process_sca_cmpl_pkt; @@ -970,78 +882,40 @@ extern struct btm_acl_process_sca_cmpl_pkt btm_acl_process_sca_cmpl_pkt; // Params: uint16_t handle // Returns: void struct btm_acl_removed { - std::function body{[](uint16_t handle) { ; }}; + std::function body{[](uint16_t /* handle */) { ; }}; void operator()(uint16_t handle) { body(handle); }; }; extern struct btm_acl_removed btm_acl_removed; -// Name: btm_acl_reset_paging -// Params: void -// Returns: void -struct btm_acl_reset_paging { - std::function body{[](void) { ; }}; - void operator()(void) { body(); }; -}; -extern struct btm_acl_reset_paging btm_acl_reset_paging; -// Name: btm_acl_resubmit_page -// Params: void -// Returns: void -struct btm_acl_resubmit_page { - std::function body{[](void) { ; }}; - void operator()(void) { body(); }; -}; -extern struct btm_acl_resubmit_page btm_acl_resubmit_page; // Name: btm_acl_role_changed // Params: tHCI_STATUS hci_status, const RawAddress& bd_addr, tHCI_ROLE // new_role Returns: void struct btm_acl_role_changed { std::function - body{[](tHCI_STATUS hci_status, const RawAddress& bd_addr, - tHCI_ROLE new_role) { ; }}; + body{[](tHCI_STATUS /* hci_status */, const RawAddress& /* bd_addr */, + tHCI_ROLE /* new_role */) { ; }}; void operator()(tHCI_STATUS hci_status, const RawAddress& bd_addr, tHCI_ROLE new_role) { body(hci_status, bd_addr, new_role); }; }; extern struct btm_acl_role_changed btm_acl_role_changed; -// Name: btm_acl_set_paging -// Params: bool value -// Returns: void -struct btm_acl_set_paging { - std::function body{[](bool value) { ; }}; - void operator()(bool value) { body(value); }; -}; -extern struct btm_acl_set_paging btm_acl_set_paging; // Name: btm_acl_update_conn_addr // Params: uint16_t handle, const RawAddress& address // Returns: void struct btm_acl_update_conn_addr { std::function body{ - [](uint16_t handle, const RawAddress& address) { ; }}; + [](uint16_t /* handle */, const RawAddress& /* address */) { ; }}; void operator()(uint16_t handle, const RawAddress& address) { body(handle, address); }; }; extern struct btm_acl_update_conn_addr btm_acl_update_conn_addr; -// Name: btm_configure_data_path -// Params: uint8_t direction, uint8_t path_id, std::vector -// vendor_config Returns: void -struct btm_configure_data_path { - std::function vendor_config)> - body{[](uint8_t direction, uint8_t path_id, - std::vector vendor_config) { ; }}; - void operator()(uint8_t direction, uint8_t path_id, - std::vector vendor_config) { - body(direction, path_id, vendor_config); - }; -}; -extern struct btm_configure_data_path btm_configure_data_path; // Name: btm_acl_update_inquiry_status // Params: uint8_t status // Returns: void struct btm_acl_update_inquiry_status { - std::function body{[](uint8_t status) { ; }}; + std::function body{[](uint8_t /* status */) { ; }}; void operator()(uint8_t status) { body(status); }; }; extern struct btm_acl_update_inquiry_status btm_acl_update_inquiry_status; @@ -1051,8 +925,8 @@ extern struct btm_acl_update_inquiry_status btm_acl_update_inquiry_status; struct btm_ble_refresh_local_resolvable_private_addr { std::function - body{ - [](const RawAddress& pseudo_addr, const RawAddress& local_rpa) { ; }}; + body{[](const RawAddress& /* pseudo_addr */, + const RawAddress& /* local_rpa */) { ; }}; void operator()(const RawAddress& pseudo_addr, const RawAddress& local_rpa) { body(pseudo_addr, local_rpa); }; @@ -1063,7 +937,8 @@ extern struct btm_ble_refresh_local_resolvable_private_addr // Params: uint16_t hci_handle // Returns: void struct btm_cont_rswitch_from_handle { - std::function body{[](uint16_t hci_handle) { ; }}; + std::function body{ + [](uint16_t /* hci_handle */) { ; }}; void operator()(uint16_t hci_handle) { body(hci_handle); }; }; extern struct btm_cont_rswitch_from_handle btm_cont_rswitch_from_handle; @@ -1072,7 +947,7 @@ extern struct btm_cont_rswitch_from_handle btm_cont_rswitch_from_handle; // Returns: void struct btm_establish_continue_from_address { std::function body{ - [](const RawAddress& bda, tBT_TRANSPORT transport) { ; }}; + [](const RawAddress& /* bda */, tBT_TRANSPORT /* transport */) { ; }}; void operator()(const RawAddress& bda, tBT_TRANSPORT transport) { body(bda, transport); }; @@ -1084,7 +959,7 @@ extern struct btm_establish_continue_from_address // Returns: void struct btm_process_remote_ext_features { std::function body{ - [](tACL_CONN* p_acl_cb, uint8_t max_page_number) { ; }}; + [](tACL_CONN* /* p_acl_cb */, uint8_t /* max_page_number */) { ; }}; void operator()(tACL_CONN* p_acl_cb, uint8_t max_page_number) { body(p_acl_cb, max_page_number); }; @@ -1096,8 +971,9 @@ extern struct btm_process_remote_ext_features btm_process_remote_ext_features; struct btm_process_remote_version_complete { std::function - body{[](uint8_t status, uint16_t handle, uint8_t lmp_version, - uint16_t manufacturer, uint16_t lmp_subversion) { ; }}; + body{[](uint8_t /* status */, uint16_t /* handle */, + uint8_t /* lmp_version */, uint16_t /* manufacturer */, + uint16_t /* lmp_subversion */) { ; }}; void operator()(uint8_t status, uint16_t handle, uint8_t lmp_version, uint16_t manufacturer, uint16_t lmp_subversion) { body(status, handle, lmp_version, manufacturer, lmp_subversion); @@ -1109,7 +985,7 @@ extern struct btm_process_remote_version_complete // Params: uint8_t* p // Returns: void struct btm_read_automatic_flush_timeout_complete { - std::function body{[](uint8_t* p) { ; }}; + std::function body{[](uint8_t* /* p */) { ; }}; void operator()(uint8_t* p) { body(p); }; }; extern struct btm_read_automatic_flush_timeout_complete @@ -1118,18 +994,17 @@ extern struct btm_read_automatic_flush_timeout_complete // Params: uint8_t* p // Returns: void struct btm_read_failed_contact_counter_complete { - std::function body{[](uint8_t* p) { ; }}; + std::function body{[](uint8_t* /* p */) { ; }}; void operator()(uint8_t* p) { body(p); }; }; extern struct btm_read_failed_contact_counter_complete btm_read_failed_contact_counter_complete; // Name: btm_read_failed_contact_counter_timeout -// Params: UNUSED_ATTR void* data +// Params: void* data // Returns: void struct btm_read_failed_contact_counter_timeout { - std::function body{ - [](UNUSED_ATTR void* data) { ; }}; - void operator()(UNUSED_ATTR void* data) { body(data); }; + std::function body{[](void* /* data */) { ; }}; + void operator()(void* data) { body(data); }; }; extern struct btm_read_failed_contact_counter_timeout btm_read_failed_contact_counter_timeout; @@ -1137,17 +1012,17 @@ extern struct btm_read_failed_contact_counter_timeout // Params: uint8_t* p // Returns: void struct btm_read_link_quality_complete { - std::function body{[](uint8_t* p, uint16_t evt_len) { ; }}; + std::function body{ + [](uint8_t* /* p */, uint16_t /* evt_len */) { ; }}; void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); }; }; extern struct btm_read_link_quality_complete btm_read_link_quality_complete; // Name: btm_read_link_quality_timeout -// Params: UNUSED_ATTR void* data +// Params: void* data // Returns: void struct btm_read_link_quality_timeout { - std::function body{ - [](UNUSED_ATTR void* data) { ; }}; - void operator()(UNUSED_ATTR void* data) { body(data); }; + std::function body{[](void* /* data */) { ; }}; + void operator()(void* data) { body(data); }; }; extern struct btm_read_link_quality_timeout btm_read_link_quality_timeout; // Name: btm_read_remote_ext_features @@ -1155,7 +1030,7 @@ extern struct btm_read_link_quality_timeout btm_read_link_quality_timeout; // Returns: void struct btm_read_remote_ext_features { std::function body{ - [](uint16_t handle, uint8_t page_number) { ; }}; + [](uint16_t /* handle */, uint8_t /* page_number */) { ; }}; void operator()(uint16_t handle, uint8_t page_number) { body(handle, page_number); }; @@ -1167,8 +1042,8 @@ extern struct btm_read_remote_ext_features btm_read_remote_ext_features; struct btm_read_remote_ext_features_complete { std::function - body{[](uint16_t handle, uint8_t page_num, uint8_t max_page, - uint8_t* features) { ; }}; + body{[](uint16_t /* handle */, uint8_t /* page_num */, + uint8_t /* max_page */, uint8_t* /* features */) { ; }}; void operator()(uint16_t handle, uint8_t page_num, uint8_t max_page, uint8_t* features) { body(handle, page_num, max_page, features); @@ -1181,7 +1056,7 @@ extern struct btm_read_remote_ext_features_complete // Returns: void struct btm_read_remote_ext_features_complete_raw { std::function body{ - [](uint8_t* p, uint8_t evt_len) { ; }}; + [](uint8_t* /* p */, uint8_t /* evt_len */) { ; }}; void operator()(uint8_t* p, uint8_t evt_len) { body(p, evt_len); }; }; extern struct btm_read_remote_ext_features_complete_raw @@ -1191,31 +1066,20 @@ extern struct btm_read_remote_ext_features_complete_raw // Returns: void struct btm_read_remote_ext_features_failed { std::function body{ - [](uint8_t status, uint16_t handle) { ; }}; + [](uint8_t /* status */, uint16_t /* handle */) { ; }}; void operator()(uint8_t status, uint16_t handle) { body(status, handle); }; }; extern struct btm_read_remote_ext_features_failed btm_read_remote_ext_features_failed; -// Name: btm_read_remote_features_complete -// Params: uint16_t handle, uint8_t* features -// Returns: void -struct btm_read_remote_features_complete { - std::function body{ - [](uint16_t handle, uint8_t* features) { ; }}; - void operator()(uint16_t handle, uint8_t* features) { - body(handle, features); - }; -}; -extern struct btm_read_remote_features_complete - btm_read_remote_features_complete; // Name: btm_read_remote_version_complete // Params: tHCI_STATUS status, uint16_t handle, uint8_t lmp_version, uint16_t // manufacturer, uint16_t lmp_subversion Returns: void struct btm_read_remote_version_complete { std::function - body{[](tHCI_STATUS status, uint16_t handle, uint8_t lmp_version, - uint16_t manufacturer, uint16_t lmp_subversion) { ; }}; + body{[](tHCI_STATUS /* status */, uint16_t /* handle */, + uint8_t /* lmp_version */, uint16_t /* manufacturer */, + uint16_t /* lmp_subversion */) { ; }}; void operator()(tHCI_STATUS status, uint16_t handle, uint8_t lmp_version, uint16_t manufacturer, uint16_t lmp_subversion) { body(status, handle, lmp_version, manufacturer, lmp_subversion); @@ -1227,17 +1091,16 @@ extern struct btm_read_remote_version_complete btm_read_remote_version_complete; // Returns: void struct btm_read_rssi_complete { std::function body{ - [](uint8_t* pm, uint16_t evt_len) { ; }}; + [](uint8_t* /* pm */, uint16_t /* evt_len */) { ; }}; void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); }; }; extern struct btm_read_rssi_complete btm_read_rssi_complete; // Name: btm_read_rssi_timeout -// Params: UNUSED_ATTR void* data +// Params: void* data // Returns: void struct btm_read_rssi_timeout { - std::function body{ - [](UNUSED_ATTR void* data) { ; }}; - void operator()(UNUSED_ATTR void* data) { body(data); }; + std::function body{[](void* /* data */) { ; }}; + void operator()(void* data) { body(data); }; }; extern struct btm_read_rssi_timeout btm_read_rssi_timeout; // Name: btm_read_tx_power_complete @@ -1245,19 +1108,18 @@ extern struct btm_read_rssi_timeout btm_read_rssi_timeout; // Returns: void struct btm_read_tx_power_complete { std::function body{ - [](uint8_t* p, uint16_t evt_len, bool is_ble) { ; }}; + [](uint8_t* /* p */, uint16_t /* evt_len */, bool /* is_ble */) { ; }}; void operator()(uint8_t* p, uint16_t evt_len, bool is_ble) { body(p, evt_len, is_ble); }; }; extern struct btm_read_tx_power_complete btm_read_tx_power_complete; // Name: btm_read_tx_power_timeout -// Params: UNUSED_ATTR void* data +// Params: void* data // Returns: void struct btm_read_tx_power_timeout { - std::function body{ - [](UNUSED_ATTR void* data) { ; }}; - void operator()(UNUSED_ATTR void* data) { body(data); }; + std::function body{[](void* /* data */) { ; }}; + void operator()(void* data) { body(data); }; }; extern struct btm_read_tx_power_timeout btm_read_tx_power_timeout; // Name: btm_rejectlist_role_change_device @@ -1265,7 +1127,7 @@ extern struct btm_read_tx_power_timeout btm_read_tx_power_timeout; // Returns: void struct btm_rejectlist_role_change_device { std::function body{ - [](const RawAddress& bd_addr, uint8_t hci_status) { ; }}; + [](const RawAddress& /* bd_addr */, uint8_t /* hci_status */) { ; }}; void operator()(const RawAddress& bd_addr, uint8_t hci_status) { body(bd_addr, hci_status); }; @@ -1277,7 +1139,7 @@ extern struct btm_rejectlist_role_change_device // Returns: void struct btm_set_link_policy { std::function body{ - [](tACL_CONN* conn, tLINK_POLICY policy) { ; }}; + [](tACL_CONN* /* conn */, tLINK_POLICY /* policy */) { ; }}; void operator()(tACL_CONN* conn, tLINK_POLICY policy) { body(conn, policy); }; }; extern struct btm_set_link_policy btm_set_link_policy; @@ -1286,7 +1148,7 @@ extern struct btm_set_link_policy btm_set_link_policy; // Returns: void struct btm_set_packet_types_from_address { std::function body{ - [](const RawAddress& bd_addr, uint16_t pkt_types) { ; }}; + [](const RawAddress& /* bd_addr */, uint16_t /* pkt_types */) { ; }}; void operator()(const RawAddress& bd_addr, uint16_t pkt_types) { body(bd_addr, pkt_types); }; @@ -1298,7 +1160,7 @@ extern struct btm_set_packet_types_from_address // Returns: void struct hci_btm_set_link_supervision_timeout { std::function body{ - [](tACL_CONN& link, uint16_t timeout) { ; }}; + [](tACL_CONN& /* link */, uint16_t /* timeout */) { ; }}; void operator()(tACL_CONN& link, uint16_t timeout) { body(link, timeout); }; }; extern struct hci_btm_set_link_supervision_timeout @@ -1309,8 +1171,8 @@ extern struct hci_btm_set_link_supervision_timeout struct on_acl_br_edr_connected { std::function - body{[](const RawAddress& bda, uint16_t handle, uint8_t enc_mode, - bool locally_initiated) { ; }}; + body{[](const RawAddress& /* bda */, uint16_t /* handle */, + uint8_t /* enc_mode */, bool /* locally_initiated */) { ; }}; void operator()(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, bool locally_initiated) { body(bda, handle, enc_mode, locally_initiated); @@ -1323,8 +1185,8 @@ extern struct on_acl_br_edr_connected on_acl_br_edr_connected; struct on_acl_br_edr_failed { std::function - body{[](const RawAddress& bda, tHCI_STATUS status, - bool locally_initiated) { ; }}; + body{[](const RawAddress& /* bda */, tHCI_STATUS /* status */, + bool /* locally_initiated */) { ; }}; void operator()(const RawAddress& bda, tHCI_STATUS status, bool locally_initiated) { body(bda, status, locally_initiated); @@ -1335,7 +1197,7 @@ extern struct on_acl_br_edr_failed on_acl_br_edr_failed; // Manually added struct BTM_unblock_role_switch_and_sniff_mode_for { std::function body{ - [](const RawAddress& peer_addr) {}}; + [](const RawAddress& /* peer_addr */) {}}; void operator()(const RawAddress& peer_addr) { body(peer_addr); }; }; extern struct BTM_unblock_role_switch_and_sniff_mode_for diff --git a/system/test/mock/mock_stack_acl_ble.cc b/system/test/mock/mock_stack_acl_ble.cc index 7e7a8818f71f7d38f49d29daef86e8bdd470f944..2d0711b04b999c2252684be3d54d6fb78144dd31 100644 --- a/system/test/mock/mock_stack_acl_ble.cc +++ b/system/test/mock/mock_stack_acl_ble.cc @@ -20,58 +20,52 @@ */ #include -#include -#include -#include "osi/include/log.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_dev.h" -#include "stack/btm/btm_sec.h" -#include "stack/gatt/connection_manager.h" -#include "stack/include/acl_api.h" -#include "stack/include/l2cap_hci_link_interface.h" +#include "stack/include/hci_error_code.h" #include "test/common/mock_functions.h" #include "types/ble_address_with_type.h" #include "types/hci_role.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void acl_ble_connection_fail(const tBLE_BD_ADDR& address_with_type, - uint16_t handle, bool enhanced, - tHCI_STATUS status) { +void acl_ble_connection_fail(const tBLE_BD_ADDR& /* address_with_type */, + uint16_t /* handle */, bool /* enhanced */, + tHCI_STATUS /* status */) { inc_func_call_count(__func__); } void acl_ble_enhanced_connection_complete( - const tBLE_BD_ADDR& address_with_type, uint16_t handle, tHCI_ROLE role, - bool match, uint16_t conn_interval, uint16_t conn_latency, - uint16_t conn_timeout, const RawAddress& local_rpa, - const RawAddress& peer_rpa, uint8_t peer_addr_type, - bool can_read_discoverable_characteristics) { + const tBLE_BD_ADDR& /* address_with_type */, uint16_t /* handle */, + tHCI_ROLE /* role */, bool /* match */, uint16_t /* conn_interval */, + uint16_t /* conn_latency */, uint16_t /* conn_timeout */, + const RawAddress& /* local_rpa */, const RawAddress& /* peer_rpa */, + uint8_t /* peer_addr_type */, + bool /* can_read_discoverable_characteristics */) { inc_func_call_count(__func__); } void acl_ble_enhanced_connection_complete_from_shim( - const tBLE_BD_ADDR& address_with_type, uint16_t handle, tHCI_ROLE role, - uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout, - const RawAddress& local_rpa, const RawAddress& peer_rpa, - tBLE_ADDR_TYPE peer_addr_type, bool can_read_discoverable_characteristics) { + const tBLE_BD_ADDR& /* address_with_type */, uint16_t /* handle */, + tHCI_ROLE /* role */, uint16_t /* conn_interval */, + uint16_t /* conn_latency */, uint16_t /* conn_timeout */, + const RawAddress& /* local_rpa */, const RawAddress& /* peer_rpa */, + tBLE_ADDR_TYPE /* peer_addr_type */, + bool /* can_read_discoverable_characteristics */) { inc_func_call_count(__func__); } -void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval, - uint16_t latency, uint16_t timeout, - tHCI_STATUS status); -void acl_ble_update_event_received(tHCI_STATUS status, uint16_t handle, - uint16_t interval, uint16_t latency, - uint16_t timeout) { +void gatt_notify_conn_update(const RawAddress& /* remote */, + uint16_t /* interval */, uint16_t /* latency */, + uint16_t /* timeout */, tHCI_STATUS /* status */); +void acl_ble_update_event_received(tHCI_STATUS /* status */, + uint16_t /* handle */, + uint16_t /* interval */, + uint16_t /* latency */, + uint16_t /* timeout */) { inc_func_call_count(__func__); } -void acl_ble_data_length_change_event(uint16_t handle, uint16_t max_tx_octets, - uint16_t max_tx_time, - uint16_t max_rx_octets, - uint16_t max_rx_time) { +void acl_ble_data_length_change_event(uint16_t /* handle */, + uint16_t /* max_tx_octets */, + uint16_t /* max_tx_time */, + uint16_t /* max_rx_octets */, + uint16_t /* max_rx_time */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_acl_btm_ble_connection_establishment.cc b/system/test/mock/mock_stack_acl_btm_ble_connection_establishment.cc index c303724d25315e0ec8f76781ba7820b0812803e7..1320c49336ec015ad92fa64eb8f6ddc542ce04b3 100644 --- a/system/test/mock/mock_stack_acl_btm_ble_connection_establishment.cc +++ b/system/test/mock/mock_stack_acl_btm_ble_connection_establishment.cc @@ -20,27 +20,17 @@ * * mockcify.pl ver 0.2 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_acl_btm_ble_connection_establishment.h" #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_acl_btm_ble_connection_establishment.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -49,8 +39,6 @@ namespace stack_acl_btm_ble_connection_establishment { // Function state capture and return values, if needed struct btm_ble_create_ll_conn_complete btm_ble_create_ll_conn_complete; -struct maybe_resolve_address maybe_resolve_address; -struct btm_ble_conn_complete btm_ble_conn_complete; } // namespace stack_acl_btm_ble_connection_establishment } // namespace mock @@ -61,15 +49,5 @@ void btm_ble_create_ll_conn_complete(tHCI_STATUS status) { test::mock::stack_acl_btm_ble_connection_establishment:: btm_ble_create_ll_conn_complete(status); } -bool maybe_resolve_address(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { - inc_func_call_count(__func__); - return test::mock::stack_acl_btm_ble_connection_establishment:: - maybe_resolve_address(bda, bda_type); -} -void btm_ble_conn_complete(uint8_t* p, uint16_t evt_len, bool enhanced) { - inc_func_call_count(__func__); - test::mock::stack_acl_btm_ble_connection_establishment::btm_ble_conn_complete( - p, evt_len, enhanced); -} // END mockcify generation diff --git a/system/test/mock/mock_stack_acl_btm_ble_connection_establishment.h b/system/test/mock/mock_stack_acl_btm_ble_connection_establishment.h index c65d020d4846e198d416ee32af6030332aa5e756..20bb590cac1607fd7e24a50851fcbff885996cb4 100644 --- a/system/test/mock/mock_stack_acl_btm_ble_connection_establishment.h +++ b/system/test/mock/mock_stack_acl_btm_ble_connection_establishment.h @@ -22,26 +22,14 @@ */ #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. #include "stack/include/hci_error_code.h" -#include "test/common/mock_functions.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_acl_btm_ble_connection_establishment { @@ -51,32 +39,10 @@ namespace stack_acl_btm_ble_connection_establishment { // Params: tHCI_STATUS status // Returns: void struct btm_ble_create_ll_conn_complete { - std::function body{[](tHCI_STATUS status) {}}; + std::function body{[](tHCI_STATUS /* status */) {}}; void operator()(tHCI_STATUS status) { body(status); }; }; extern struct btm_ble_create_ll_conn_complete btm_ble_create_ll_conn_complete; -// Name: maybe_resolve_address -// Params: RawAddress* bda, tBLE_ADDR_TYPE* bda_type -// Returns: bool -struct maybe_resolve_address { - std::function body{ - [](RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { return false; }}; - bool operator()(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { - return body(bda, bda_type); - }; -}; -extern struct maybe_resolve_address maybe_resolve_address; -// Name: btm_ble_conn_complete -// Params: uint8_t* p, uint16_t evt_len, bool enhanced -// Returns: void -struct btm_ble_conn_complete { - std::function body{ - [](uint8_t* p, uint16_t evt_len, bool enhanced) {}}; - void operator()(uint8_t* p, uint16_t evt_len, bool enhanced) { - body(p, evt_len, enhanced); - }; -}; -extern struct btm_ble_conn_complete btm_ble_conn_complete; } // namespace stack_acl_btm_ble_connection_establishment } // namespace mock diff --git a/system/test/mock/mock_stack_acl_btm_pm.cc b/system/test/mock/mock_stack_acl_btm_pm.cc index cd4fb992a65cfc59fce2be2cb75fe699ab0de1c9..99f83442b1d4075d3b3f62c856e7480119b0da64 100644 --- a/system/test/mock/mock_stack_acl_btm_pm.cc +++ b/system/test/mock/mock_stack_acl_btm_pm.cc @@ -22,31 +22,18 @@ #include #include -#include -#include -#include -#include "bt_target.h" -#include "device/include/controller.h" -#include "main/shim/dumpsys.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" -#include "stack/btm/btm_int_types.h" -#include "stack/include/btm_api.h" -#include "stack/include/btm_api_types.h" +#include "stack/btm/power_mode.h" #include "stack/include/btm_status.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool BTM_ReadPowerMode(const RawAddress& remote_bda, tBTM_PM_MODE* p_mode) { +bool BTM_ReadPowerMode(const RawAddress& /* remote_bda */, + tBTM_PM_MODE* /* p_mode */) { inc_func_call_count(__func__); return false; } -bool BTM_SetLinkPolicyActiveMode(const RawAddress& remote_bda) { +bool BTM_SetLinkPolicyActiveMode(const RawAddress& /* remote_bda */) { inc_func_call_count(__func__); return false; } @@ -54,48 +41,56 @@ tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void) { inc_func_call_count(__func__); return BTM_CONTRL_UNKNOWN; } -tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id, - tBTM_PM_STATUS_CBACK* p_cb) { +tBTM_STATUS BTM_PmRegister(uint8_t /* mask */, uint8_t* /* p_pm_id */, + tBTM_PM_STATUS_CBACK* /* p_cb */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda, - const tBTM_PM_PWR_MD* p_mode) { +tBTM_STATUS BTM_SetPowerMode(uint8_t /* pm_id */, + const RawAddress& /* remote_bda */, + const tBTM_PM_PWR_MD* /* p_mode */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_SetSsrParams(const RawAddress& remote_bda, uint16_t max_lat, - uint16_t min_rmt_to, uint16_t min_loc_to) { +tBTM_STATUS BTM_SetSsrParams(const RawAddress& /* remote_bda */, + uint16_t /* max_lat */, uint16_t /* min_rmt_to */, + uint16_t /* min_loc_to */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -void BTM_PM_OnConnected(uint16_t handle, const RawAddress& remote_bda) { +void BTM_PM_OnConnected(uint16_t /* handle */, + const RawAddress& /* remote_bda */) { + inc_func_call_count(__func__); +} +void BTM_PM_OnDisconnected(uint16_t /* handle */) { inc_func_call_count(__func__); } -void BTM_PM_OnDisconnected(uint16_t handle) { inc_func_call_count(__func__); } -void btm_pm_on_mode_change(tHCI_STATUS status, uint16_t handle, - tHCI_MODE current_mode, uint16_t interval) { +void btm_pm_on_mode_change(tHCI_STATUS /* status */, uint16_t /* handle */, + tHCI_MODE /* current_mode */, + uint16_t /* interval */) { inc_func_call_count(__func__); } -void btm_pm_on_sniff_subrating(tHCI_STATUS status, uint16_t handle, - uint16_t maximum_transmit_latency, - uint16_t maximum_receive_latency, - uint16_t minimum_remote_timeout, - uint16_t minimum_local_timeout) { +void btm_pm_on_sniff_subrating(tHCI_STATUS /* status */, uint16_t /* handle */, + uint16_t /* maximum_transmit_latency */, + uint16_t /* maximum_receive_latency */, + uint16_t /* minimum_remote_timeout */, + uint16_t /* minimum_local_timeout */) { inc_func_call_count(__func__); } -void btm_pm_proc_cmd_status(tHCI_STATUS status) { +void btm_pm_proc_cmd_status(tHCI_STATUS /* status */) { inc_func_call_count(__func__); } -void btm_pm_proc_mode_change(tHCI_STATUS hci_status, uint16_t hci_handle, - tHCI_MODE hci_mode, uint16_t interval) { +void btm_pm_proc_mode_change(tHCI_STATUS /* hci_status */, + uint16_t /* hci_handle */, + tHCI_MODE /* hci_mode */, + uint16_t /* interval */) { inc_func_call_count(__func__); } -void btm_pm_proc_ssr_evt(uint8_t* p, UNUSED_ATTR uint16_t evt_len) { +void btm_pm_proc_ssr_evt(uint8_t* /* p */, uint16_t /* evt_len */) { inc_func_call_count(__func__); } void btm_pm_reset(void) { inc_func_call_count(__func__); } -void process_ssr_event(tHCI_STATUS status, uint16_t handle, - UNUSED_ATTR uint16_t max_tx_lat, uint16_t max_rx_lat) { +void process_ssr_event(tHCI_STATUS /* status */, uint16_t /* handle */, + uint16_t /* max_tx_lat */, uint16_t /* max_rx_lat */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_arbiter_acl_arbiter.cc b/system/test/mock/mock_stack_arbiter_acl_arbiter.cc index 60ee86f1c6eeb0231a2b6bb7c9e8930b3cab0337..c0086b5f053b510055449f689c384ab58da78ba2 100644 --- a/system/test/mock/mock_stack_arbiter_acl_arbiter.cc +++ b/system/test/mock/mock_stack_arbiter_acl_arbiter.cc @@ -22,20 +22,21 @@ namespace arbiter { class MockAclArbiter : public AclArbiter { public: - virtual void OnLeConnect(uint8_t tcb_idx, uint16_t advertiser_id) override {} + virtual void OnLeConnect(uint8_t /* tcb_idx */, + uint16_t /* advertiser_id */) override {} - virtual void OnLeDisconnect(uint8_t tcb_idx) override {} + virtual void OnLeDisconnect(uint8_t /* tcb_idx */) override {} - virtual InterceptAction InterceptAttPacket(uint8_t tcb_idx, - const BT_HDR* packet) override { + virtual InterceptAction InterceptAttPacket( + uint8_t /* tcb_idx */, const BT_HDR* /* packet */) override { return InterceptAction::FORWARD; } - virtual void OnOutgoingMtuReq(uint8_t tcb_idx) override {} + virtual void OnOutgoingMtuReq(uint8_t /* tcb_idx */) override {} - virtual void OnIncomingMtuResp(uint8_t tcb_idx, size_t mtu) {} + virtual void OnIncomingMtuResp(uint8_t /* tcb_idx */, size_t /* mtu */) {} - virtual void OnIncomingMtuReq(uint8_t tcb_idx, size_t mtu) {} + virtual void OnIncomingMtuReq(uint8_t /* tcb_idx */, size_t /* mtu */) {} static MockAclArbiter& Get() { static auto singleton = MockAclArbiter(); @@ -49,4 +50,4 @@ AclArbiter& GetArbiter() { } // namespace arbiter } // namespace shim -} // namespace bluetooth \ No newline at end of file +} // namespace bluetooth diff --git a/system/test/mock/mock_stack_avct_api.cc b/system/test/mock/mock_stack_avct_api.cc index e2cc1c71422997c5742592f2224d13e5c1dff6bc..659f417d5c8f29245561b6ab24101c984693698c 100644 --- a/system/test/mock/mock_stack_avct_api.cc +++ b/system/test/mock/mock_stack_avct_api.cc @@ -19,60 +19,40 @@ * Functions generated:9 */ -#include - -#include -#include - #include "avct_api.h" -#include "bt_target.h" -#include "bta/include/bta_api.h" -#include "btm_api.h" -#include "l2c_api.h" -#include "l2cdefs.h" -#include "osi/include/osi.h" -#include "stack/avct/avct_int.h" -#include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role) { +uint16_t AVCT_CreateBrowse(uint8_t /* handle */, uint8_t /* role */) { inc_func_call_count(__func__); return 0; } -uint16_t AVCT_CreateConn(uint8_t* p_handle, tAVCT_CC* p_cc, - const RawAddress& peer_addr) { +uint16_t AVCT_CreateConn(uint8_t* /* p_handle */, tAVCT_CC* /* p_cc */, + const RawAddress& /* peer_addr */) { inc_func_call_count(__func__); return 0; } -uint16_t AVCT_GetBrowseMtu(uint8_t handle) { +uint16_t AVCT_GetBrowseMtu(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } -uint16_t AVCT_GetPeerMtu(uint8_t handle) { +uint16_t AVCT_GetPeerMtu(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } -uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR* p_msg) { +uint16_t AVCT_MsgReq(uint8_t /* handle */, uint8_t /* label */, + uint8_t /* cr */, BT_HDR* /* p_msg */) { inc_func_call_count(__func__); return 0; } -uint16_t AVCT_RemoveBrowse(uint8_t handle) { +uint16_t AVCT_RemoveBrowse(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } -uint16_t AVCT_RemoveConn(uint8_t handle) { +uint16_t AVCT_RemoveConn(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } void AVCT_Deregister(void) { inc_func_call_count(__func__); } void AVCT_Register() { inc_func_call_count(__func__); } -uint8_t AVCT_SetTraceLevel(uint8_t new_level) { - inc_func_call_count(__func__); - return 0; -} diff --git a/system/test/mock/mock_stack_avdt_api.cc b/system/test/mock/mock_stack_avdt_api.cc index 1ec3562d1ac4bb7dad7a4ba74f9b60cc14de2808..af64bb7a812a94da3dc8c5a4d4dc3d82113aa2b2 100644 --- a/system/test/mock/mock_stack_avdt_api.cc +++ b/system/test/mock/mock_stack_avdt_api.cc @@ -19,129 +19,116 @@ * Functions generated:26 */ -#include - -#include -#include - -#include "avdt_api.h" -#include "avdtc_api.h" -#include "bt_target.h" -#include "bta/include/bta_api.h" -#include "btm_api.h" -#include "l2c_api.h" -#include "main/shim/dumpsys.h" -#include "osi/include/log.h" #include "stack/avdt/avdt_int.h" -#include "stack/btm/btm_sec.h" -#include "stack/include/a2dp_codec_api.h" +#include "stack/include/avdt_api.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -uint16_t AVDT_CloseReq(uint8_t handle) { - inc_func_call_count(__func__); - return 0; -} -uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code, - uint8_t category) { +uint16_t AVDT_CloseReq(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_ConnectReq(const RawAddress& bd_addr, uint8_t channel_index, - tAVDT_CTRL_CBACK* p_cback) { +uint16_t AVDT_ConfigRsp(uint8_t /* handle */, uint8_t /* label */, + uint8_t /* error_code */, uint8_t /* category */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_CreateStream(uint8_t peer_id, uint8_t* p_handle, - const AvdtpStreamConfig& avdtp_stream_config) { +uint16_t AVDT_ConnectReq(const RawAddress& /* bd_addr */, + uint8_t /* channel_index */, + tAVDT_CTRL_CBACK* /* p_cback */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay) { +uint16_t AVDT_CreateStream(uint8_t /* peer_id */, uint8_t* /* p_handle */, + const AvdtpStreamConfig& /* avdtp_stream_config */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_DisconnectReq(const RawAddress& bd_addr, - tAVDT_CTRL_CBACK* p_cback) { +uint16_t AVDT_DelayReport(uint8_t /* handle */, uint8_t /* seid */, + uint16_t /* delay */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_DiscoverReq(const RawAddress& bd_addr, uint8_t channel_index, - tAVDT_SEP_INFO* p_sep_info, uint8_t max_seps, - tAVDT_CTRL_CBACK* p_cback) { +uint16_t AVDT_DisconnectReq(const RawAddress& /* bd_addr */, + tAVDT_CTRL_CBACK* /* p_cback */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_GetCapReq(const RawAddress& bd_addr, uint8_t channel_index, - uint8_t seid, AvdtpSepConfig* p_cfg, - tAVDT_CTRL_CBACK* p_cback, bool get_all_cap) { +uint16_t AVDT_DiscoverReq(const RawAddress& /* bd_addr */, + uint8_t /* channel_index */, + tAVDT_SEP_INFO* /* p_sep_info */, + uint8_t /* max_seps */, + tAVDT_CTRL_CBACK* /* p_cback */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_GetL2CapChannel(uint8_t handle) { +uint16_t AVDT_GetCapReq(const RawAddress& /* bd_addr */, + uint8_t /* channel_index */, uint8_t /* seid */, + AvdtpSepConfig* /* p_cfg */, + tAVDT_CTRL_CBACK* /* p_cback */, + bool /* get_all_cap */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_OpenReq(uint8_t handle, const RawAddress& bd_addr, - uint8_t channel_index, uint8_t seid, - AvdtpSepConfig* p_cfg) { +uint16_t AVDT_GetL2CapChannel(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_ReconfigReq(uint8_t handle, AvdtpSepConfig* p_cfg) { +uint16_t AVDT_OpenReq(uint8_t /* handle */, const RawAddress& /* bd_addr */, + uint8_t /* channel_index */, uint8_t /* seid */, + AvdtpSepConfig* /* p_cfg */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_RemoveStream(uint8_t handle) { +uint16_t AVDT_ReconfigReq(uint8_t /* handle */, AvdtpSepConfig* /* p_cfg */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len) { +uint16_t AVDT_RemoveStream(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code, - uint8_t* p_data, uint16_t len) { +uint16_t AVDT_SecurityReq(uint8_t /* handle */, uint8_t* /* p_data */, + uint16_t /* len */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles) { +uint16_t AVDT_SecurityRsp(uint8_t /* handle */, uint8_t /* label */, + uint8_t /* error_code */, uint8_t* /* p_data */, + uint16_t /* len */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles) { +uint16_t AVDT_StartReq(uint8_t* /* p_handles */, uint8_t /* num_handles */) { inc_func_call_count(__func__); return 0; } -uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp, - uint8_t m_pt, tAVDT_DATA_OPT_MASK opt) { +uint16_t AVDT_SuspendReq(uint8_t* /* p_handles */, uint8_t /* num_handles */) { inc_func_call_count(__func__); return 0; } -uint8_t AVDT_SetTraceLevel(uint8_t new_level) { +uint16_t AVDT_WriteReqOpt(uint8_t /* handle */, BT_HDR* /* p_pkt */, + uint32_t /* time_stamp */, uint8_t /* m_pt */, + tAVDT_DATA_OPT_MASK /* opt */) { inc_func_call_count(__func__); return 0; } -void AVDT_AbortReq(uint8_t handle) { inc_func_call_count(__func__); } +void AVDT_AbortReq(uint8_t /* handle */) { inc_func_call_count(__func__); } void AVDT_Deregister(void) { inc_func_call_count(__func__); } -void AVDT_Register(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback) { +void AVDT_Register(AvdtpRcb* /* p_reg */, tAVDT_CTRL_CBACK* /* p_cback */) { inc_func_call_count(__func__); } -void avdt_ccb_idle_ccb_timer_timeout(void* data) { +void avdt_ccb_idle_ccb_timer_timeout(void* /* data */) { inc_func_call_count(__func__); } -void avdt_ccb_ret_ccb_timer_timeout(void* data) { +void avdt_ccb_ret_ccb_timer_timeout(void* /* data */) { inc_func_call_count(__func__); } -void avdt_ccb_rsp_ccb_timer_timeout(void* data) { +void avdt_ccb_rsp_ccb_timer_timeout(void* /* data */) { inc_func_call_count(__func__); } -void avdt_scb_transport_channel_timer_timeout(void* data) { +void avdt_scb_transport_channel_timer_timeout(void* /* data */) { inc_func_call_count(__func__); } -void stack_debug_avdtp_api_dump(int fd) { inc_func_call_count(__func__); } +void stack_debug_avdtp_api_dump(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 d7fb4513966dd1a5add26128cb539076bf5c0bd3..94834bd1aeb59c1318600a6c321db75f483cd828 100644 --- a/system/test/mock/mock_stack_avrc_api.cc +++ b/system/test/mock/mock_stack_avrc_api.cc @@ -20,34 +20,22 @@ */ #include -#include -#include -#include - -#include "osi/include/fixed_queue.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "osi/include/properties.h" #include "stack/avrc/avrc_int.h" #include "stack/include/avrc_api.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - bool avrcp_absolute_volume_is_enabled() { inc_func_call_count(__func__); return true; } -uint16_t AVRC_Close(uint8_t handle) { +uint16_t AVRC_Close(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } -uint16_t AVRC_CloseBrowse(uint8_t handle) { +uint16_t AVRC_CloseBrowse(uint8_t /* handle */) { inc_func_call_count(__func__); return 0; } @@ -59,36 +47,46 @@ uint16_t AVRC_GetProfileVersion() { inc_func_call_count(__func__); return 0; } -uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, - BT_HDR* p_pkt) { +uint16_t AVRC_MsgReq(uint8_t /* handle */, uint8_t /* label */, + uint8_t /* ctype */, BT_HDR* /* p_pkt */, + bool /* is_new_avrcp */) { inc_func_call_count(__func__); return 0; } -uint16_t AVRC_Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb, - const RawAddress& peer_addr) { +uint16_t AVRC_Open(uint8_t* /* p_handle */, tAVRC_CONN_CB* /* p_ccb */, + const RawAddress& /* peer_addr */) { 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 */, uint8_t /* conn_role */) { inc_func_call_count(__func__); return 0; } -void AVRC_SaveControllerVersion(const RawAddress& bdaddr, uint16_t version) { +void AVRC_SaveControllerVersion(const RawAddress& /* bdaddr */, + uint16_t /* version */) { + inc_func_call_count(__func__); +} + +void AVRC_UpdateCcb(RawAddress* /* addr */, uint32_t /* company_id */) { inc_func_call_count(__func__); } -uint16_t AVRC_PassCmd(uint8_t handle, uint8_t label, tAVRC_MSG_PASS* p_msg) { + +uint16_t AVRC_PassCmd(uint8_t /* handle */, uint8_t /* label */, + tAVRC_MSG_PASS* /* p_msg */) { inc_func_call_count(__func__); return 0; } -uint16_t AVRC_PassRsp(uint8_t handle, uint8_t label, tAVRC_MSG_PASS* p_msg) { +uint16_t AVRC_PassRsp(uint8_t /* handle */, uint8_t /* label */, + tAVRC_MSG_PASS* /* p_msg */) { inc_func_call_count(__func__); 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) { +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) { +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_apt.cc b/system/test/mock/mock_stack_avrc_apt.cc index fc72f4c9d92750d1b9d2877e9d64fcf428f1569c..23ed7b6365b723687816abff0c2d87fcecb19b85 100644 --- a/system/test/mock/mock_stack_avrc_apt.cc +++ b/system/test/mock/mock_stack_avrc_apt.cc @@ -19,14 +19,12 @@ * * mockcify.pl ver 0.5.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_avrc_apt.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_avrc_apt.h" +#include "test/common/mock_functions.h" // Original usings diff --git a/system/test/mock/mock_stack_avrc_apt.h b/system/test/mock/mock_stack_avrc_apt.h index 96e39de3705a69edddb3d3c3941c45a340eacf2a..fd16afbe6078b84c2003656586c1af575c91be02 100644 --- a/system/test/mock/mock_stack_avrc_apt.h +++ b/system/test/mock/mock_stack_avrc_apt.h @@ -24,23 +24,9 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include - -#include "avrc_api.h" -#include "osi/include/allocator.h" -#include "stack/avrc/avrc_int.h" -#include "stack/include/bt_hdr.h" -#include "test/common/mock_functions.h" +#include "stack/include/avrc_defs.h" // Original usings @@ -57,7 +43,9 @@ namespace stack_avrc_apt { struct AVRC_SubCmd { static uint16_t return_value; std::function body{ - [](uint8_t handle, uint8_t label, uint8_t page) { return return_value; }}; + [](uint8_t /* handle */, uint8_t /* label */, uint8_t /* page */) { + return return_value; + }}; uint16_t operator()(uint8_t handle, uint8_t label, uint8_t page) { return body(handle, label, page); }; @@ -70,7 +58,7 @@ extern struct AVRC_SubCmd AVRC_SubCmd; struct AVRC_UnitCmd { static uint16_t return_value; std::function body{ - [](uint8_t handle, uint8_t label) { return return_value; }}; + [](uint8_t /* handle */, uint8_t /* label */) { return return_value; }}; uint16_t operator()(uint8_t handle, uint8_t label) { return body(handle, label); }; @@ -84,9 +72,8 @@ struct AVRC_VendorCmd { static uint16_t return_value; std::function - body{[](uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR* p_msg) { - return return_value; - }}; + body{[](uint8_t /* handle */, uint8_t /* label */, + tAVRC_MSG_VENDOR* /* p_msg */) { return return_value; }}; uint16_t operator()(uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR* p_msg) { return body(handle, label, p_msg); }; @@ -100,9 +87,8 @@ struct AVRC_VendorRsp { static uint16_t return_value; std::function - body{[](uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR* p_msg) { - return return_value; - }}; + body{[](uint8_t /* handle */, uint8_t /* label */, + tAVRC_MSG_VENDOR* /* p_msg */) { return return_value; }}; uint16_t operator()(uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR* p_msg) { return body(handle, label, p_msg); }; diff --git a/system/test/mock/mock_stack_avrc_bld_ct.cc b/system/test/mock/mock_stack_avrc_bld_ct.cc index d083bf15ebe47e37118910851ba0e628cd0c5af7..3bf300a75cffb31f87df3d4b3e2f5f73f1bf6906 100644 --- a/system/test/mock/mock_stack_avrc_bld_ct.cc +++ b/system/test/mock/mock_stack_avrc_bld_ct.cc @@ -19,22 +19,12 @@ * Functions generated:2 */ -#include - -#include -#include - #include "avrc_api.h" #include "avrc_defs.h" -#include "stack/avrc/avrc_int.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { +tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* /* p_cmd */, BT_HDR** /* pp_pkt */) { inc_func_call_count(__func__); return 0; } diff --git a/system/test/mock/mock_stack_avrc_bld_tg.cc b/system/test/mock/mock_stack_avrc_bld_tg.cc index 72d07391ca75777ba86048caaaa7b3514e790c7d..c65e0fdcd1b23a2de127ddd855cbbad5f118c66e 100644 --- a/system/test/mock/mock_stack_avrc_bld_tg.cc +++ b/system/test/mock/mock_stack_avrc_bld_tg.cc @@ -20,28 +20,19 @@ */ #include -#include - -#include -#include #include "avrc_api.h" #include "avrc_defs.h" -#include "osi/include/osi.h" -#include "stack/avrc/avrc_int.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp, - BT_HDR** pp_pkt) { +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) { +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 5c28c81a6910f71a683a3614d52df272376068c6..81dbd91aaca8f0845f1b1a8d1da4dfc309e9a5ed 100644 --- a/system/test/mock/mock_stack_avrc_pars.ct.cc +++ b/system/test/mock/mock_stack_avrc_pars.ct.cc @@ -19,35 +19,26 @@ * Functions generated:4 */ -#include - -#include -#include - #include "avrc_api.h" #include "avrc_defs.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "stack/avrc/avrc_int.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result, - uint8_t* p_buf, uint16_t* buf_len) { +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__); return 0; } -tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result, - UNUSED_ATTR uint8_t* p_buf, - UNUSED_ATTR uint16_t buf_len) { +tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* /* p_msg */, + tAVRC_RESPONSE* /* p_result */, + uint8_t* /* p_buf */, uint16_t /* buf_len */) { 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) { +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_avrc_pars_tg.cc b/system/test/mock/mock_stack_avrc_pars_tg.cc index 9ce8f058952548b4de26e3217ba84dd655b798ff..73509063df515daa4c7000b3790e0263ba8c2014 100644 --- a/system/test/mock/mock_stack_avrc_pars_tg.cc +++ b/system/test/mock/mock_stack_avrc_pars_tg.cc @@ -19,27 +19,18 @@ * Functions generated:4 */ -#include - -#include -#include - #include "avrc_api.h" #include "avrc_defs.h" -#include "osi/include/log.h" -#include "stack/avrc/avrc_int.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) { +tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* /* p_msg */, + tAVRC_COMMAND* /* p_result */) { inc_func_call_count(__func__); return 0; } -tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result, - uint8_t* p_buf, uint16_t buf_len) { +tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* /* p_msg */, + tAVRC_COMMAND* /* p_result */, uint8_t* /* p_buf */, + uint16_t /* buf_len */) { inc_func_call_count(__func__); return 0; } diff --git a/system/test/mock/mock_stack_avrc_sdp.cc b/system/test/mock/mock_stack_avrc_sdp.cc index d09ab2e3346969608927745bf721433ea858e5c8..90b88012461fb9c18408fe3887a8c2bf695a4b92 100644 --- a/system/test/mock/mock_stack_avrc_sdp.cc +++ b/system/test/mock/mock_stack_avrc_sdp.cc @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,45 +13,77 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* * Generated mock file from original source file - * Functions generated:7 + * Functions generated:5 + * + * mockcify.pl ver 0.6.3 */ -#include +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_avrc_sdp.h" -#include -#include +#include -#include "stack/avrc/avrc_int.h" -#include "stack/include/avrc_api.h" #include "test/common/mock_functions.h" -#include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +// Original usings +using bluetooth::Uuid; +using namespace bluetooth::legacy::stack::sdp; + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace stack_avrc_sdp { + +// Function state capture and return values, if needed +struct AVRC_AddRecord AVRC_AddRecord; +struct AVRC_FindService AVRC_FindService; +struct AVRC_Init AVRC_Init; +struct AVRC_RemoveRecord AVRC_RemoveRecord; + +} // namespace stack_avrc_sdp +} // namespace mock +} // namespace test +// Mocked function return values, if any +namespace test { +namespace mock { +namespace stack_avrc_sdp { + +uint16_t AVRC_AddRecord::return_value = 0; +uint16_t AVRC_FindService::return_value = 0; +uint16_t AVRC_RemoveRecord::return_value = 0; + +} // namespace stack_avrc_sdp +} // namespace mock +} // namespace test + +// Mocked functions, if any uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, const char* p_provider_name, uint16_t categories, uint32_t sdp_handle, bool browse_supported, uint16_t profile_version, uint16_t cover_art_psm) { inc_func_call_count(__func__); - return 0; + return test::mock::stack_avrc_sdp::AVRC_AddRecord( + service_uuid, p_service_name, p_provider_name, categories, sdp_handle, + browse_supported, profile_version, cover_art_psm); } uint16_t AVRC_FindService(uint16_t service_uuid, const RawAddress& bd_addr, tAVRC_SDP_DB_PARAMS* p_db, const tAVRC_FIND_CBACK& find_cback) { inc_func_call_count(__func__); - return 0; + return test::mock::stack_avrc_sdp::AVRC_FindService(service_uuid, bd_addr, + p_db, find_cback); } -uint16_t AVRC_RemoveRecord(uint32_t sdp_handle) { +void AVRC_Init(void) { inc_func_call_count(__func__); - return 0; + test::mock::stack_avrc_sdp::AVRC_Init(); } -uint8_t AVRC_SetTraceLevel(uint8_t new_level) { +uint16_t AVRC_RemoveRecord(uint32_t sdp_handle) { inc_func_call_count(__func__); - return 0; + return test::mock::stack_avrc_sdp::AVRC_RemoveRecord(sdp_handle); } -void AVRC_Init(void) { inc_func_call_count(__func__); } +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_stack_avrc_sdp.h b/system/test/mock/mock_stack_avrc_sdp.h new file mode 100644 index 0000000000000000000000000000000000000000..8d165038b98c70926ad6c05b6b899e209926d539 --- /dev/null +++ b/system/test/mock/mock_stack_avrc_sdp.h @@ -0,0 +1,122 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:5 + * + * mockcify.pl ver 0.6.3 + */ + +#include +#include + +// Original included files, if any +// NOTE: Since this is a mock file with mock definitions some number of +// include files may not be required. The include-what-you-use +// still applies, but crafting proper inclusion is out of scope +// for this effort. This compilation unit may compile as-is, or +// may need attention to prune from (or add to ) the inclusion set. + +#include "stack/include/avrc_api.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +// Original usings +using bluetooth::Uuid; +using namespace bluetooth::legacy::stack::sdp; + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace stack_avrc_sdp { + +// Shared state between mocked functions and tests +// Name: AVRC_AddRecord +// Params: uint16_t service_uuid, const char* p_service_name, const char* +// p_provider_name, uint16_t categories, uint32_t sdp_handle, bool +// browse_supported, uint16_t profile_version, uint16_t cover_art_psm Return: +// uint16_t +struct AVRC_AddRecord { + static uint16_t return_value; + std::function + body{[](uint16_t /* service_uuid */, const char* /* p_service_name */, + const char* /* p_provider_name */, uint16_t /* categories */, + uint32_t /* sdp_handle */, bool /* browse_supported */, + uint16_t /* profile_version */, + uint16_t /* cover_art_psm */) { return return_value; }}; + uint16_t operator()(uint16_t service_uuid, const char* p_service_name, + const char* p_provider_name, uint16_t categories, + uint32_t sdp_handle, bool browse_supported, + uint16_t profile_version, uint16_t cover_art_psm) { + return body(service_uuid, p_service_name, p_provider_name, categories, + sdp_handle, browse_supported, profile_version, cover_art_psm); + }; +}; +extern struct AVRC_AddRecord AVRC_AddRecord; + +// Name: AVRC_FindService +// Params: uint16_t service_uuid, const RawAddress& bd_addr, +// tAVRC_SDP_DB_PARAMS* p_db, const tAVRC_FIND_CBACK& find_cback Return: +// uint16_t +struct AVRC_FindService { + static uint16_t return_value; + std::function + body{[](uint16_t /* service_uuid */, const RawAddress& /* bd_addr */, + tAVRC_SDP_DB_PARAMS* /* p_db */, + const tAVRC_FIND_CBACK& /* find_cback */) { + return return_value; + }}; + uint16_t operator()(uint16_t service_uuid, const RawAddress& bd_addr, + tAVRC_SDP_DB_PARAMS* p_db, + const tAVRC_FIND_CBACK& find_cback) { + return body(service_uuid, bd_addr, p_db, find_cback); + }; +}; +extern struct AVRC_FindService AVRC_FindService; + +// Name: AVRC_Init +// Params: void +// Return: void +struct AVRC_Init { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct AVRC_Init AVRC_Init; + +// Name: AVRC_RemoveRecord +// Params: uint32_t sdp_handle +// Return: uint16_t +struct AVRC_RemoveRecord { + static uint16_t return_value; + std::function body{ + [](uint32_t /* sdp_handle */) { return return_value; }}; + uint16_t operator()(uint32_t sdp_handle) { return body(sdp_handle); }; +}; +extern struct AVRC_RemoveRecord AVRC_RemoveRecord; + +} // namespace stack_avrc_sdp +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_stack_avrc_utils.cc b/system/test/mock/mock_stack_avrc_utils.cc index 4acd75a8d9754b77b528e4d10b5b33ca5ebd5f32..00e6000e4073d65288620f723769c91a2657d7a5 100644 --- a/system/test/mock/mock_stack_avrc_utils.cc +++ b/system/test/mock/mock_stack_avrc_utils.cc @@ -19,14 +19,12 @@ * * mockcify.pl ver 0.5.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_avrc_utils.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_avrc_utils.h" +#include "test/common/mock_functions.h" // Original usings diff --git a/system/test/mock/mock_stack_avrc_utils.h b/system/test/mock/mock_stack_avrc_utils.h index d45bd0c8e739a0c205b9f0461b0138dce9818082..0a51e71bcdd8c051047863471c09159bdb959d6f 100644 --- a/system/test/mock/mock_stack_avrc_utils.h +++ b/system/test/mock/mock_stack_avrc_utils.h @@ -24,20 +24,9 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include - -#include "avrc_api.h" -#include "stack/avrc/avrc_int.h" -#include "test/common/mock_functions.h" +#include "stack/include/avrc_defs.h" // Original usings @@ -54,7 +43,9 @@ namespace stack_avrc_utils { struct AVRC_IsValidAvcType { static bool return_value; std::function body{ - [](uint8_t pdu_id, uint8_t avc_type) { return return_value; }}; + [](uint8_t /* pdu_id */, uint8_t /* avc_type */) { + return return_value; + }}; bool operator()(uint8_t pdu_id, uint8_t avc_type) { return body(pdu_id, avc_type); }; @@ -67,7 +58,7 @@ extern struct AVRC_IsValidAvcType AVRC_IsValidAvcType; struct AVRC_IsValidPlayerAttr { static bool return_value; std::function body{ - [](uint8_t attr) { return return_value; }}; + [](uint8_t /* attr */) { return return_value; }}; bool operator()(uint8_t attr) { return body(attr); }; }; extern struct AVRC_IsValidPlayerAttr AVRC_IsValidPlayerAttr; @@ -78,7 +69,7 @@ extern struct AVRC_IsValidPlayerAttr AVRC_IsValidPlayerAttr; struct avrc_is_valid_opcode { static bool return_value; std::function body{ - [](uint8_t opcode) { return return_value; }}; + [](uint8_t /* opcode */) { return return_value; }}; bool operator()(uint8_t opcode) { return body(opcode); }; }; extern struct avrc_is_valid_opcode avrc_is_valid_opcode; @@ -89,7 +80,7 @@ extern struct avrc_is_valid_opcode avrc_is_valid_opcode; struct avrc_is_valid_player_attrib_value { static bool return_value; std::function body{ - [](uint8_t attrib, uint8_t value) { return return_value; }}; + [](uint8_t /* attrib */, uint8_t /* value */) { return return_value; }}; bool operator()(uint8_t attrib, uint8_t value) { return body(attrib, value); }; @@ -103,7 +94,7 @@ extern struct avrc_is_valid_player_attrib_value struct avrc_opcode_from_pdu { static uint8_t return_value; std::function body{ - [](uint8_t pdu) { return return_value; }}; + [](uint8_t /* pdu */) { return return_value; }}; uint8_t operator()(uint8_t pdu) { return body(pdu); }; }; extern struct avrc_opcode_from_pdu avrc_opcode_from_pdu; @@ -114,7 +105,7 @@ extern struct avrc_opcode_from_pdu avrc_opcode_from_pdu; struct avrc_pars_pass_thru { static tAVRC_STS return_value; std::function - body{[](tAVRC_MSG_PASS* p_msg, uint16_t* p_vendor_unique_id) { + body{[](tAVRC_MSG_PASS* /* p_msg */, uint16_t* /* p_vendor_unique_id */) { return return_value; }}; tAVRC_STS operator()(tAVRC_MSG_PASS* p_msg, uint16_t* p_vendor_unique_id) { diff --git a/system/test/mock/mock_stack_bnep_api.cc b/system/test/mock/mock_stack_bnep_api.cc index 8a0a82f5dd048e76507a832312771cd2ef3a3fed..041e67a3d94ebe6900758c493f0b64ab09d075ea 100644 --- a/system/test/mock/mock_stack_bnep_api.cc +++ b/system/test/mock/mock_stack_bnep_api.cc @@ -19,69 +19,61 @@ * Functions generated:11 */ -#include - -#include -#include - -#include "bta/include/bta_api.h" -#include "stack/bnep/bnep_int.h" -#include "stack/btm/btm_sec.h" #include "stack/include/bnep_api.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - using namespace bluetooth; -tBNEP_RESULT BNEP_Connect(const RawAddress& p_rem_bda, const Uuid& src_uuid, - const Uuid& dst_uuid, uint16_t* p_handle, - uint32_t mx_chan_id) { - inc_func_call_count(__func__); - return 0; -} -tBNEP_RESULT BNEP_ConnectResp(uint16_t handle, tBNEP_RESULT resp) { +tBNEP_RESULT BNEP_Connect(const RawAddress& /* p_rem_bda */, + const Uuid& /* src_uuid */, + const Uuid& /* dst_uuid */, uint16_t* /* p_handle */, + uint32_t /* mx_chan_id */) { inc_func_call_count(__func__); return 0; } -tBNEP_RESULT BNEP_Disconnect(uint16_t handle) { +tBNEP_RESULT BNEP_ConnectResp(uint16_t /* handle */, tBNEP_RESULT /* resp */) { inc_func_call_count(__func__); return 0; } -tBNEP_RESULT BNEP_Register(tBNEP_REGISTER* p_reg_info) { +tBNEP_RESULT BNEP_Disconnect(uint16_t /* handle */) { inc_func_call_count(__func__); return 0; } -tBNEP_RESULT BNEP_SetMulticastFilters(uint16_t handle, uint16_t num_filters, - uint8_t* p_start_array, - uint8_t* p_end_array) { +tBNEP_RESULT BNEP_Register(tBNEP_REGISTER* /* p_reg_info */) { inc_func_call_count(__func__); return 0; } -tBNEP_RESULT BNEP_SetProtocolFilters(uint16_t handle, uint16_t num_filters, - uint16_t* p_start_array, - uint16_t* p_end_array) { +tBNEP_RESULT BNEP_SetMulticastFilters(uint16_t /* handle */, + uint16_t /* num_filters */, + uint8_t* /* p_start_array */, + uint8_t* /* p_end_array */) { inc_func_call_count(__func__); return 0; } -tBNEP_RESULT BNEP_Write(uint16_t handle, const RawAddress& p_dest_addr, - uint8_t* p_data, uint16_t len, uint16_t protocol, - const RawAddress* p_src_addr, bool fw_ext_present) { +tBNEP_RESULT BNEP_SetProtocolFilters(uint16_t /* handle */, + uint16_t /* num_filters */, + uint16_t* /* p_start_array */, + uint16_t* /* p_end_array */) { inc_func_call_count(__func__); return 0; } -tBNEP_RESULT BNEP_WriteBuf(uint16_t handle, const RawAddress& p_dest_addr, - BT_HDR* p_buf, uint16_t protocol, - const RawAddress* p_src_addr, bool fw_ext_present) { +tBNEP_RESULT BNEP_Write(uint16_t /* handle */, + const RawAddress& /* p_dest_addr */, + uint8_t* /* p_data */, uint16_t /* len */, + uint16_t /* protocol */, + const RawAddress* /* p_src_addr */, + bool /* fw_ext_present */) { inc_func_call_count(__func__); return 0; } -uint8_t BNEP_SetTraceLevel(uint8_t new_level) { +tBNEP_RESULT BNEP_WriteBuf(uint16_t /* handle */, + const RawAddress& /* p_dest_addr */, + BT_HDR* /* p_buf */, uint16_t /* protocol */, + const RawAddress* /* p_src_addr */, + bool /* fw_ext_present */) { inc_func_call_count(__func__); return 0; } diff --git a/system/test/mock/mock_stack_btm.cc b/system/test/mock/mock_stack_btm.cc deleted file mode 100644 index 475a45780c79422c803931b1e638477b1442f1d2..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_stack_btm.cc +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - */ - -#include "stack/include/btm_api.h" -#include "stack/include/btm_ble_api_types.h" -#include "stack/include/btm_client_interface.h" -#include "types/raw_address.h" - -namespace { - -uint8_t hci_feature_bytes_per_page[HCI_FEATURE_BYTES_PER_PAGE] = {}; - -} - -void BTM_BleReadControllerFeatures(void (*cb)(tHCI_ERROR_CODE)) {} -tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback) { - return BTM_SUCCESS; -} - -struct btm_client_interface_t btm_client_interface = { - .lifecycle = { - .BTM_GetHCIConnHandle = [](const RawAddress& remote_bda, - tBT_TRANSPORT transport) -> uint16_t { - return 0; - }, - .BTM_PmRegister = [](uint8_t mask, uint8_t* p_pm_id, - tBTM_PM_STATUS_CBACK* p_cb) -> tBTM_STATUS { - return BTM_SUCCESS; - }, - .BTM_VendorSpecificCommand = BTM_VendorSpecificCommand, - .ACL_RegisterClient = [](struct acl_client_callback_s* callbacks) {}, - .ACL_UnregisterClient = [](struct acl_client_callback_s* callbacks) {}, - .btm_init = []() {}, - .btm_free = []() {}, - .btm_ble_init = []() {}, - .btm_ble_free = []() {}, - .BTM_reset_complete = []() {}, - }, - .eir = { - .BTM_GetEirSupportedServices = - [](uint32_t* p_eir_uuid, uint8_t** p, uint8_t max_num_uuid16, - uint8_t* p_num_uuid16) -> uint8_t { return 0; }, - .BTM_GetEirUuidList = [](const uint8_t* p_eir, size_t eir_len, - uint8_t uuid_size, uint8_t* p_num_uuid, - uint8_t* p_uuid_list, - uint8_t max_num_uuid) -> uint8_t { return 0; }, - .BTM_AddEirService = [](uint32_t* p_eir_uuid, uint16_t uuid16) {}, - .BTM_RemoveEirService = [](uint32_t* p_eir_uuid, uint16_t uuid16) {}, - .BTM_WriteEIR = [](BT_HDR* p_buff) -> tBTM_STATUS { - return BTM_SUCCESS; - }, - }, - .link_policy = { - .BTM_GetRole = [](const RawAddress& remote_bd_addr, tHCI_ROLE* p_role) - -> tBTM_STATUS { return BTM_SUCCESS; }, - .BTM_SetPowerMode = [](uint8_t pm_id, const RawAddress& remote_bda, - const tBTM_PM_PWR_MD* p_mode) -> tBTM_STATUS { - return BTM_SUCCESS; - }, - .BTM_SetSsrParams = - [](RawAddress const& bd_addr, uint16_t max_lat, uint16_t min_rmt_to, - uint16_t min_loc_to) -> tBTM_STATUS { return BTM_SUCCESS; }, - .BTM_SwitchRoleToCentral = [](const RawAddress& remote_bd_addr) - -> tBTM_STATUS { return BTM_SUCCESS; }, - .BTM_WritePageTimeout = BTM_WritePageTimeout, - .BTM_block_role_switch_for = [](const RawAddress& peer_addr) {}, - .BTM_unblock_role_switch_for = [](const RawAddress& peer_addr) {}, - .BTM_block_sniff_mode_for = [](const RawAddress& peer_addr) {}, - .BTM_unblock_sniff_mode_for = [](const RawAddress& peer_addr) {}, - .BTM_default_unblock_role_switch = []() {}, - }, - .link_controller = { - .BTM_GetLinkSuperTout = [](const RawAddress& remote_bda, - uint16_t* p_timeout) -> tBTM_STATUS { - return BTM_SUCCESS; - }, - .BTM_ReadRSSI = [](const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) - -> tBTM_STATUS { return BTM_SUCCESS; }, - }, - .neighbor = - { - .BTM_CancelInquiry = BTM_CancelInquiry, - .BTM_ClearInqDb = BTM_ClearInqDb, - .BTM_InqDbNext = BTM_InqDbNext, - .BTM_SetConnectability = BTM_SetConnectability, - .BTM_SetDiscoverability = BTM_SetDiscoverability, - .BTM_StartInquiry = BTM_StartInquiry, - .BTM_IsInquiryActive = BTM_IsInquiryActive, - .BTM_SetInquiryMode = BTM_SetInquiryMode, - .BTM_EnableInterlacedInquiryScan = BTM_EnableInterlacedInquiryScan, - .BTM_EnableInterlacedPageScan = BTM_EnableInterlacedPageScan, - }, - .peer = { - .features = - { - .SupportTransparentSynchronousData = - [](const RawAddress& bd_addr) -> bool { return false; }, - }, - .BTM_CancelRemoteDeviceName = BTM_CancelRemoteDeviceName, - .BTM_IsAclConnectionUp = [](const RawAddress& remote_bda, - tBT_TRANSPORT transport) -> bool { - return false; - }, - .BTM_ReadConnectedTransportAddress = - [](RawAddress* remote_bda, tBT_TRANSPORT transport) -> bool { - return false; - }, - .BTM_ReadDevInfo = [](const RawAddress& remote_bda, - tBT_DEVICE_TYPE* p_dev_type, - tBLE_ADDR_TYPE* p_addr_type) {}, - .BTM_ReadRemoteDeviceName = BTM_ReadRemoteDeviceName, - .BTM_ReadRemoteFeatures = [](const RawAddress& addr) -> uint8_t* { - return hci_feature_bytes_per_page; - }, - .BTM_GetMaxPacketSize = [](const RawAddress& bd_addr) -> uint16_t { - return 0; - }, - .BTM_ReadRemoteVersion = - [](const RawAddress& addr, uint8_t* lmp_version, - uint16_t* manufacturer, - uint16_t* lmp_sub_version) -> bool { return false; }, - }, - .scn = - { - .BTM_AllocateSCN = BTM_AllocateSCN, - .BTM_TryAllocateSCN = BTM_TryAllocateSCN, - .BTM_FreeSCN = BTM_FreeSCN, - }, - .security = { - .BTM_ConfirmReqReply = [](tBTM_STATUS res, - const RawAddress& bd_addr) {}, - .BTM_PINCodeReply = [](const RawAddress& bd_addr, tBTM_STATUS res, - uint8_t pin_len, uint8_t* p_pin) {}, - .BTM_RemoteOobDataReply = [](tBTM_STATUS res, const RawAddress& bd_addr, - const Octet16& c, const Octet16& r) {}, - .BTM_SecAddBleDevice = [](const RawAddress& bd_addr, - tBT_DEVICE_TYPE dev_type, - tBLE_ADDR_TYPE addr_type) {}, - .BTM_SecAddBleKey = [](const RawAddress& bd_addr, - tBTM_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type) {}, - .BTM_SecAddDevice = BTM_SecAddDevice, - .BTM_SecAddRmtNameNotifyCallback = - [](tBTM_RMT_NAME_CALLBACK* p_callback) -> bool { return false; }, - .BTM_SecBond = [](const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type, - uint8_t pin_len, uint8_t* p_pin) -> tBTM_STATUS { - return BTM_SUCCESS; - }, - .BTM_SecBondCancel = [](const RawAddress& bd_addr) -> tBTM_STATUS { - return BTM_SUCCESS; - }, - .BTM_SecClearSecurityFlags = BTM_SecClearSecurityFlags, - .BTM_SecClrService = [](uint8_t service_id) -> uint8_t { return 0; }, - .BTM_SecClrServiceByPsm = [](uint16_t psm) -> uint8_t { return 0; }, - .BTM_SecDeleteDevice = BTM_SecDeleteDevice, - .BTM_SecDeleteRmtNameNotifyCallback = - [](tBTM_RMT_NAME_CALLBACK* p_callback) -> bool { return false; }, - .BTM_SecReadDevName = [](const RawAddress& bd_addr) -> char* { - return nullptr; - }, - .BTM_SecRegister = [](const tBTM_APPL_INFO* p_cb_info) -> bool { - return false; - }, - .BTM_SetEncryption = - [](const RawAddress& bd_addr, tBT_TRANSPORT transport, - tBTM_SEC_CALLBACK* p_callback, void* p_ref_data, - tBTM_BLE_SEC_ACT sec_act) -> tBTM_STATUS { return BTM_SUCCESS; }, - .BTM_IsEncrypted = [](const RawAddress& bd_addr, - tBT_TRANSPORT transport) -> bool { - return false; - }, - .BTM_SecIsSecurityPending = [](const RawAddress& bd_addr) -> bool { - return false; - }, - .BTM_IsLinkKeyKnown = [](const RawAddress& bd_addr, - tBT_TRANSPORT transport) -> bool { - return false; - }, - }, - .ble = { - .BTM_BleConfirmReply = [](const RawAddress& bd_addr, uint8_t res) {}, - .BTM_BleGetEnergyInfo = [](tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback) - -> tBTM_STATUS { return BTM_SUCCESS; }, - .BTM_BleLoadLocalKeys = [](uint8_t key_type, - tBTM_BLE_LOCAL_KEYS* p_key) {}, - .BTM_BleObserve = - [](bool start, uint8_t duration, tBTM_INQ_RESULTS_CB* p_results_cb, - tBTM_CMPL_CB* p_cmpl_cb, - bool low_latency_scan) -> tBTM_STATUS { return BTM_SUCCESS; }, - .BTM_BlePasskeyReply = [](const RawAddress& bd_addr, uint8_t res, - uint32_t passkey) {}, - .BTM_BleReadControllerFeatures = - [](tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) {}, - .BTM_BleSetPhy = [](const RawAddress& bd_addr, uint8_t tx_phys, - uint8_t rx_phys, uint16_t phy_options) {}, - .BTM_BleSetPrefConnParams = - [](const RawAddress& bd_addr, uint16_t min_conn_int, - uint16_t max_conn_int, uint16_t peripheral_latency, - uint16_t supervision_tout) {}, - .BTM_SetBleDataLength = [](const RawAddress& bd_addr, - uint16_t tx_pdu_length) -> tBTM_STATUS { - return BTM_SUCCESS; - }, - .BTM_UseLeLink = [](const RawAddress& bd_addr) -> bool { - return false; - }}, - .sco = - { - .BTM_CreateSco = BTM_CreateSco, - .BTM_EScoConnRsp = BTM_EScoConnRsp, - .BTM_GetNumScoLinks = BTM_GetNumScoLinks, - .BTM_RegForEScoEvts = BTM_RegForEScoEvts, - .BTM_RemoveSco = BTM_RemoveSco, - .BTM_SetEScoMode = BTM_SetEScoMode, - .BTM_WriteVoiceSettings = BTM_WriteVoiceSettings, - }, - .local = - { - .BTM_ReadLocalDeviceNameFromController = - BTM_ReadLocalDeviceNameFromController, - .BTM_SetDeviceClass = BTM_SetDeviceClass, - .BTM_SetLocalDeviceName = BTM_SetLocalDeviceName, - .BTM_IsDeviceUp = BTM_IsDeviceUp, - .BTM_ReadDeviceClass = BTM_ReadDeviceClass, - }, - .db = - { - .BTM_InqDbRead = BTM_InqDbRead, - .BTM_InqDbFirst = BTM_InqDbFirst, - .BTM_InqDbNext = BTM_InqDbNext, - .BTM_ClearInqDb = BTM_ClearInqDb, - }, -}; - -struct btm_client_interface_t& get_btm_client_interface() { - return btm_client_interface; -} diff --git a/system/test/mock/mock_stack_btm_ble.cc b/system/test/mock/mock_stack_btm_ble.cc index 869552d66f0ffbcf5b55419c270d54328707a3d1..ca3b7f7d468d251fad0cebf1c50bfa877d4b2e1d 100644 --- a/system/test/mock/mock_stack_btm_ble.cc +++ b/system/test/mock/mock_stack_btm_ble.cc @@ -19,14 +19,15 @@ * * mockcify.pl ver 0.5.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_ble.h" #include -#include -#include -#include +#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_btm_ble.h" +#include "stack/include/btm_api_types.h" +#include "stack/include/btm_status.h" +#include "test/common/mock_functions.h" // Original usings @@ -43,9 +44,12 @@ struct BTM_BleLoadLocalKeys BTM_BleLoadLocalKeys; struct BTM_BleOobDataReply BTM_BleOobDataReply; struct BTM_BlePasskeyReply BTM_BlePasskeyReply; struct BTM_BleReadPhy BTM_BleReadPhy; +struct BTM_BleReceiverTest BTM_BleReceiverTest; struct BTM_BleSecureConnectionOobDataReply BTM_BleSecureConnectionOobDataReply; struct BTM_BleSetPhy BTM_BleSetPhy; struct BTM_BleSetPrefConnParams BTM_BleSetPrefConnParams; +struct BTM_BleTestEnd BTM_BleTestEnd; +struct BTM_BleTransmitterTest BTM_BleTransmitterTest; struct BTM_BleVerifySignature BTM_BleVerifySignature; struct BTM_GetDeviceDHK BTM_GetDeviceDHK; struct BTM_GetDeviceEncRoot BTM_GetDeviceEncRoot; @@ -58,18 +62,13 @@ struct BTM_SecAddBleKey BTM_SecAddBleKey; struct BTM_SecurityGrant BTM_SecurityGrant; struct BTM_SetBleDataLength BTM_SetBleDataLength; struct BTM_UseLeLink BTM_UseLeLink; -struct btm_ble_br_keys_req btm_ble_br_keys_req; struct btm_ble_connected btm_ble_connected; -struct btm_ble_determine_security_act btm_ble_determine_security_act; struct btm_ble_get_acl_remote_addr btm_ble_get_acl_remote_addr; struct btm_ble_get_enc_key_type btm_ble_get_enc_key_type; -struct btm_ble_increment_sign_ctr btm_ble_increment_sign_ctr; -struct btm_ble_io_capabilities_req btm_ble_io_capabilities_req; struct btm_ble_link_encrypted btm_ble_link_encrypted; struct btm_ble_link_sec_check btm_ble_link_sec_check; struct btm_ble_ltk_request btm_ble_ltk_request; struct btm_ble_ltk_request_reply btm_ble_ltk_request_reply; -struct btm_ble_rand_enc_complete btm_ble_rand_enc_complete; struct btm_ble_read_sec_key_size btm_ble_read_sec_key_size; struct btm_ble_reset_id btm_ble_reset_id; struct btm_ble_set_encryption btm_ble_set_encryption; @@ -112,16 +111,12 @@ const Octet16 BTM_GetDeviceIDRoot::return_value{ bool BTM_ReadConnectedTransportAddress::return_value = false; tBTM_STATUS BTM_SetBleDataLength::return_value = 0; bool BTM_UseLeLink::return_value = false; -uint8_t btm_ble_br_keys_req::return_value = 0; -tBTM_SEC_ACTION btm_ble_determine_security_act::return_value = 0; bool btm_ble_get_acl_remote_addr::return_value = false; bool btm_ble_get_enc_key_type::return_value = false; -uint8_t btm_ble_io_capabilities_req::return_value = 0; uint8_t btm_ble_read_sec_key_size::return_value = 0; tBTM_STATUS btm_ble_set_encryption::return_value = 0; tBTM_STATUS btm_ble_start_encrypt::return_value = 0; -tL2CAP_LE_RESULT_CODE btm_ble_start_sec_check::return_value = - L2CAP_LE_RESULT_CONN_OK; +tBTM_STATUS btm_ble_start_sec_check::return_value = BTM_SUCCESS; bool btm_get_local_div::return_value = false; tBTM_STATUS btm_proc_smp_cback::return_value = 0; @@ -160,6 +155,10 @@ void BTM_BleReadPhy( inc_func_call_count(__func__); test::mock::stack_btm_ble::BTM_BleReadPhy(bd_addr, cb); } +void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback) { + inc_func_call_count(__func__); + test::mock::stack_btm_ble::BTM_BleReceiverTest(rx_freq, p_cmd_cmpl_cback); +} void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr, uint8_t* p_c, uint8_t* p_r) { inc_func_call_count(__func__); @@ -181,6 +180,17 @@ void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int, bd_addr, min_conn_int, max_conn_int, peripheral_latency, supervision_tout); } +void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) { + inc_func_call_count(__func__); + test::mock::stack_btm_ble::BTM_BleTestEnd(p_cmd_cmpl_cback); +} +void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len, + uint8_t packet_payload, + tBTM_CMPL_CB* p_cmd_cmpl_cback) { + inc_func_call_count(__func__); + test::mock::stack_btm_ble::BTM_BleTransmitterTest( + tx_freq, test_data_len, packet_payload, p_cmd_cmpl_cback); +} bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig, uint16_t len, uint32_t counter, uint8_t* p_comp) { inc_func_call_count(__func__); @@ -239,11 +249,6 @@ bool BTM_UseLeLink(const RawAddress& bd_addr) { inc_func_call_count(__func__); return test::mock::stack_btm_ble::BTM_UseLeLink(bd_addr); } -uint8_t btm_ble_br_keys_req(tBTM_SEC_DEV_REC* p_dev_rec, - tBTM_LE_IO_REQ* p_data) { - inc_func_call_count(__func__); - return test::mock::stack_btm_ble::btm_ble_br_keys_req(p_dev_rec, p_data); -} void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, uint8_t role, tBLE_ADDR_TYPE addr_type, bool addr_matched, @@ -253,13 +258,6 @@ void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, bda, handle, enc_mode, role, addr_type, addr_matched, can_read_discoverable_characteristics); } -tBTM_SEC_ACTION btm_ble_determine_security_act(bool is_originator, - const RawAddress& bdaddr, - uint16_t security_required) { - inc_func_call_count(__func__); - return test::mock::stack_btm_ble::btm_ble_determine_security_act( - is_originator, bdaddr, security_required); -} bool btm_ble_get_acl_remote_addr(uint16_t hci_handle, RawAddress& conn_addr, tBLE_ADDR_TYPE* p_addr_type) { inc_func_call_count(__func__); @@ -271,16 +269,6 @@ bool btm_ble_get_enc_key_type(const RawAddress& bd_addr, uint8_t* p_key_types) { return test::mock::stack_btm_ble::btm_ble_get_enc_key_type(bd_addr, p_key_types); } -void btm_ble_increment_sign_ctr(const RawAddress& bd_addr, bool is_local) { - inc_func_call_count(__func__); - test::mock::stack_btm_ble::btm_ble_increment_sign_ctr(bd_addr, is_local); -} -uint8_t btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC* p_dev_rec, - tBTM_LE_IO_REQ* p_data) { - inc_func_call_count(__func__); - return test::mock::stack_btm_ble::btm_ble_io_capabilities_req(p_dev_rec, - p_data); -} void btm_ble_link_encrypted(const RawAddress& bd_addr, uint8_t encr_enable) { inc_func_call_count(__func__); test::mock::stack_btm_ble::btm_ble_link_encrypted(bd_addr, encr_enable); @@ -292,7 +280,7 @@ void btm_ble_link_sec_check(const RawAddress& bd_addr, test::mock::stack_btm_ble::btm_ble_link_sec_check(bd_addr, auth_req, p_sec_req_act); } -void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv) { +void btm_ble_ltk_request(uint16_t handle, BT_OCTET8 rand, uint16_t ediv) { inc_func_call_count(__func__); test::mock::stack_btm_ble::btm_ble_ltk_request(handle, rand, ediv); } @@ -301,12 +289,6 @@ void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk, inc_func_call_count(__func__); test::mock::stack_btm_ble::btm_ble_ltk_request_reply(bda, use_stk, stk); } -void btm_ble_rand_enc_complete(uint8_t* p,uint16_t evt_len, uint16_t op_code, - tBTM_RAND_ENC_CB* p_enc_cplt_cback) { - inc_func_call_count(__func__); - test::mock::stack_btm_ble::btm_ble_rand_enc_complete(p, evt_len, op_code, - p_enc_cplt_cback); -} uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr) { inc_func_call_count(__func__); return test::mock::stack_btm_ble::btm_ble_read_sec_key_size(bd_addr); @@ -345,10 +327,10 @@ tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk, inc_func_call_count(__func__); return test::mock::stack_btm_ble::btm_ble_start_encrypt(bda, use_stk, p_stk); } -tL2CAP_LE_RESULT_CODE btm_ble_start_sec_check(const RawAddress& bd_addr, - uint16_t psm, bool is_originator, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data) { +tBTM_STATUS btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm, + bool is_originator, + tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data) { inc_func_call_count(__func__); return test::mock::stack_btm_ble::btm_ble_start_sec_check( bd_addr, psm, is_originator, p_callback, p_ref_data); @@ -389,3 +371,7 @@ void read_phy_cb( } // Mocked functions complete // END mockcify generation + +std::optional BTM_BleGetPeerLTK(const RawAddress /* address */) { + return std::nullopt; +} diff --git a/system/test/mock/mock_stack_btm_ble.h b/system/test/mock/mock_stack_btm_ble.h index e86eaf47bf0f64e631418bc04d8f5affee3864bc..e31a5b7508a0b15ac9168e5f6062bcd11014960a 100644 --- a/system/test/mock/mock_stack_btm_ble.h +++ b/system/test/mock/mock_stack_btm_ble.h @@ -24,41 +24,23 @@ #include #include -#include -#include +#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include - -#include - -#include "device/include/controller.h" -#include "main/shim/btm_api.h" -#include "main/shim/l2c_api.h" -#include "main/shim/shim.h" -#include "osi/include/allocator.h" -#include "osi/include/properties.h" -#include "stack/btm/btm_dev.h" -#include "stack/btm/btm_int_types.h" -#include "stack/btm/security_device_record.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" -#include "stack/include/acl_api.h" +#include "stack/btm/btm_ble_sec.h" +#include "stack/include/bt_device_type.h" #include "stack/include/bt_octets.h" -#include "stack/include/bt_types.h" -#include "stack/include/btm_api.h" -#include "stack/include/btu.h" -#include "stack/include/gatt_api.h" -#include "stack/include/l2cap_security_interface.h" +#include "stack/include/btm_api_types.h" +#include "stack/include/btm_ble_api_types.h" +#include "stack/include/btm_ble_sec_api_types.h" +#include "stack/include/btm_sec_api_types.h" +#include "stack/include/btm_status.h" #include "stack/include/l2cdefs.h" -#include "stack/include/smp_api.h" -#include "test/common/mock_functions.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" +typedef uint8_t tBTM_SEC_ACTION; + // Original usings // Mocked compile conditionals, if any @@ -72,8 +54,8 @@ namespace stack_btm_ble { // Params: const RawAddress& bd_addr, uint8_t res // Return: void struct BTM_BleConfirmReply { - std::function body{ - [](const RawAddress& bd_addr, uint8_t res) {}}; + std::function body{ + [](const RawAddress& /* bd_addr */, uint8_t /* res */) {}}; void operator()(const RawAddress& bd_addr, uint8_t res) { body(bd_addr, res); }; @@ -87,8 +69,9 @@ struct BTM_BleDataSignature { static bool return_value; std::function - body{[](const RawAddress& bd_addr, uint8_t* p_text, uint16_t len, - BLE_SIGNATURE signature) { return return_value; }}; + body{[](const RawAddress& /* bd_addr */, uint8_t* /* p_text */, + uint16_t /* len */, + BLE_SIGNATURE /* signature */) { return return_value; }}; bool operator()(const RawAddress& bd_addr, uint8_t* p_text, uint16_t len, BLE_SIGNATURE signature) { return body(bd_addr, p_text, len, signature); @@ -101,7 +84,7 @@ extern struct BTM_BleDataSignature BTM_BleDataSignature; // Return: void struct BTM_BleLoadLocalKeys { std::function body{ - [](uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) {}}; + [](uint8_t /* key_type */, tBTM_BLE_LOCAL_KEYS* /* p_key */) {}}; void operator()(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) { body(key_type, p_key); }; @@ -114,8 +97,8 @@ extern struct BTM_BleLoadLocalKeys BTM_BleLoadLocalKeys; struct BTM_BleOobDataReply { std::function - body{[](const RawAddress& bd_addr, uint8_t res, uint8_t len, - uint8_t* p_data) {}}; + body{[](const RawAddress& /* bd_addr */, uint8_t /* res */, + uint8_t /* len */, uint8_t* /* p_data */) {}}; void operator()(const RawAddress& bd_addr, uint8_t res, uint8_t len, uint8_t* p_data) { body(bd_addr, res, len, p_data); @@ -128,7 +111,8 @@ extern struct BTM_BleOobDataReply BTM_BleOobDataReply; // Return: void struct BTM_BlePasskeyReply { std::function - body{[](const RawAddress& bd_addr, uint8_t res, uint32_t passkey) {}}; + body{[](const RawAddress& /* bd_addr */, uint8_t /* res */, + uint32_t /* passkey */) {}}; void operator()(const RawAddress& bd_addr, uint8_t res, uint32_t passkey) { body(bd_addr, res, passkey); }; @@ -143,10 +127,10 @@ struct BTM_BleReadPhy { const RawAddress& bd_addr, base::Callback callback)> - body{[](const RawAddress& bd_addr, + body{[](const RawAddress& /* bd_addr */, base::Callback - callback) {}}; + /* callback */) {}}; void operator()( const RawAddress& bd_addr, base::Callback @@ -156,12 +140,25 @@ struct BTM_BleReadPhy { }; extern struct BTM_BleReadPhy BTM_BleReadPhy; +// Name: BTM_BleReceiverTest +// Params: uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback +// Return: void +struct BTM_BleReceiverTest { + std::function body{ + [](uint8_t /* rx_freq */, tBTM_CMPL_CB* /* p_cmd_cmpl_cback */) {}}; + void operator()(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback) { + body(rx_freq, p_cmd_cmpl_cback); + }; +}; +extern struct BTM_BleReceiverTest BTM_BleReceiverTest; + // Name: BTM_BleSecureConnectionOobDataReply // Params: const RawAddress& bd_addr, uint8_t* p_c, uint8_t* p_r // Return: void struct BTM_BleSecureConnectionOobDataReply { std::function - body{[](const RawAddress& bd_addr, uint8_t* p_c, uint8_t* p_r) {}}; + body{[](const RawAddress& /* bd_addr */, uint8_t* /* p_c */, + uint8_t* /* p_r */) {}}; void operator()(const RawAddress& bd_addr, uint8_t* p_c, uint8_t* p_r) { body(bd_addr, p_c, p_r); }; @@ -175,8 +172,8 @@ extern struct BTM_BleSecureConnectionOobDataReply struct BTM_BleSetPhy { std::function - body{[](const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys, - uint16_t phy_options) {}}; + body{[](const RawAddress& /* bd_addr */, uint8_t /* tx_phys */, + uint8_t /* rx_phys */, uint16_t /* phy_options */) {}}; void operator()(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys, uint16_t phy_options) { body(bd_addr, tx_phys, rx_phys, phy_options); @@ -192,9 +189,9 @@ struct BTM_BleSetPrefConnParams { std::function - body{[](const RawAddress& bd_addr, uint16_t min_conn_int, - uint16_t max_conn_int, uint16_t peripheral_latency, - uint16_t supervision_tout) {}}; + body{[](const RawAddress& /* bd_addr */, uint16_t /* min_conn_int */, + uint16_t /* max_conn_int */, uint16_t /* peripheral_latency */, + uint16_t /* supervision_tout */) {}}; void operator()(const RawAddress& bd_addr, uint16_t min_conn_int, uint16_t max_conn_int, uint16_t peripheral_latency, uint16_t supervision_tout) { @@ -204,6 +201,32 @@ struct BTM_BleSetPrefConnParams { }; extern struct BTM_BleSetPrefConnParams BTM_BleSetPrefConnParams; +// Name: BTM_BleTestEnd +// Params: tBTM_CMPL_CB* p_cmd_cmpl_cback +// Return: void +struct BTM_BleTestEnd { + std::function body{ + [](tBTM_CMPL_CB* /* p_cmd_cmpl_cback */) {}}; + void operator()(tBTM_CMPL_CB* p_cmd_cmpl_cback) { body(p_cmd_cmpl_cback); }; +}; +extern struct BTM_BleTestEnd BTM_BleTestEnd; + +// Name: BTM_BleTransmitterTest +// Params: uint8_t tx_freq, uint8_t test_data_len, uint8_t packet_payload, +// tBTM_CMPL_CB* p_cmd_cmpl_cback Return: void +struct BTM_BleTransmitterTest { + std::function + body{[](uint8_t /* tx_freq */, uint8_t /* test_data_len */, + uint8_t /* packet_payload */, + tBTM_CMPL_CB* /* p_cmd_cmpl_cback */) {}}; + void operator()(uint8_t tx_freq, uint8_t test_data_len, + uint8_t packet_payload, tBTM_CMPL_CB* p_cmd_cmpl_cback) { + body(tx_freq, test_data_len, packet_payload, p_cmd_cmpl_cback); + }; +}; +extern struct BTM_BleTransmitterTest BTM_BleTransmitterTest; + // Name: BTM_BleVerifySignature // Params: const RawAddress& bd_addr, uint8_t* p_orig, uint16_t len, uint32_t // counter, uint8_t* p_comp Return: bool @@ -211,8 +234,9 @@ struct BTM_BleVerifySignature { static bool return_value; std::function - body{[](const RawAddress& bd_addr, uint8_t* p_orig, uint16_t len, - uint32_t counter, uint8_t* p_comp) { return return_value; }}; + body{[](const RawAddress& /* bd_addr */, uint8_t* /* p_orig */, + uint16_t /* len */, uint32_t /* counter */, + uint8_t* /* p_comp */) { return return_value; }}; bool operator()(const RawAddress& bd_addr, uint8_t* p_orig, uint16_t len, uint32_t counter, uint8_t* p_comp) { return body(bd_addr, p_orig, len, counter, p_comp); @@ -262,7 +286,7 @@ extern struct BTM_GetDeviceIDRoot BTM_GetDeviceIDRoot; struct BTM_ReadConnectedTransportAddress { static bool return_value; std::function body{ - [](RawAddress* remote_bda, tBT_TRANSPORT transport) { + [](RawAddress* /* remote_bda */, tBT_TRANSPORT /* transport */) { return return_value; }}; bool operator()(RawAddress* remote_bda, tBT_TRANSPORT transport) { @@ -278,8 +302,9 @@ extern struct BTM_ReadConnectedTransportAddress struct BTM_ReadDevInfo { std::function - body{[](const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, - tBLE_ADDR_TYPE* p_addr_type) {}}; + body{[](const RawAddress& /* remote_bda */, + tBT_DEVICE_TYPE* /* p_dev_type */, + tBLE_ADDR_TYPE* /* p_addr_type */) {}}; void operator()(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type, tBLE_ADDR_TYPE* p_addr_type) { body(remote_bda, p_dev_type, p_addr_type); @@ -293,8 +318,8 @@ extern struct BTM_ReadDevInfo BTM_ReadDevInfo; struct BTM_SecAddBleDevice { std::function - body{[](const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, - tBLE_ADDR_TYPE addr_type) {}}; + body{[](const RawAddress& /* bd_addr */, tBT_DEVICE_TYPE /* dev_type */, + tBLE_ADDR_TYPE /* addr_type */) {}}; void operator()(const RawAddress& bd_addr, tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type) { body(bd_addr, dev_type, addr_type); @@ -308,7 +333,9 @@ extern struct BTM_SecAddBleDevice BTM_SecAddBleDevice; struct BTM_GetRemoteDeviceName { static bool return_value; std::function body{ - [](const RawAddress& bd_addr, BD_NAME bd_name) { return return_value; }}; + [](const RawAddress& /* bd_addr */, BD_NAME /* bd_name */) { + return return_value; + }}; bool operator()(const RawAddress& bd_addr, BD_NAME bd_name) { return body(bd_addr, bd_name); }; @@ -321,8 +348,9 @@ extern struct BTM_GetRemoteDeviceName BTM_GetRemoteDeviceName; struct BTM_SecAddBleKey { std::function - body{[](const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key, - tBTM_LE_KEY_TYPE key_type) {}}; + body{[](const RawAddress& /* bd_addr */, + tBTM_LE_KEY_VALUE* /* p_le_key */, + tBTM_LE_KEY_TYPE /* key_type */) {}}; void operator()(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key, tBTM_LE_KEY_TYPE key_type) { body(bd_addr, p_le_key, key_type); @@ -335,7 +363,7 @@ extern struct BTM_SecAddBleKey BTM_SecAddBleKey; // Return: void struct BTM_SecurityGrant { std::function body{ - [](const RawAddress& bd_addr, uint8_t res) {}}; + [](const RawAddress& /* bd_addr */, uint8_t /* res */) {}}; void operator()(const RawAddress& bd_addr, uint8_t res) { body(bd_addr, res); }; @@ -348,7 +376,7 @@ extern struct BTM_SecurityGrant BTM_SecurityGrant; struct BTM_SetBleDataLength { static tBTM_STATUS return_value; std::function - body{[](const RawAddress& bd_addr, uint16_t tx_pdu_length) { + body{[](const RawAddress& /* bd_addr */, uint16_t /* tx_pdu_length */) { return return_value; }}; tBTM_STATUS operator()(const RawAddress& bd_addr, uint16_t tx_pdu_length) { @@ -363,26 +391,11 @@ extern struct BTM_SetBleDataLength BTM_SetBleDataLength; struct BTM_UseLeLink { static bool return_value; std::function body{ - [](const RawAddress& bd_addr) { return return_value; }}; + [](const RawAddress& /* bd_addr */) { return return_value; }}; bool operator()(const RawAddress& bd_addr) { return body(bd_addr); }; }; extern struct BTM_UseLeLink BTM_UseLeLink; -// Name: btm_ble_br_keys_req -// Params: tBTM_SEC_DEV_REC* p_dev_rec, tBTM_LE_IO_REQ* p_data -// Return: uint8_t -struct btm_ble_br_keys_req { - static uint8_t return_value; - std::function - body{[](tBTM_SEC_DEV_REC* p_dev_rec, tBTM_LE_IO_REQ* p_data) { - return return_value; - }}; - uint8_t operator()(tBTM_SEC_DEV_REC* p_dev_rec, tBTM_LE_IO_REQ* p_data) { - return body(p_dev_rec, p_data); - }; -}; -extern struct btm_ble_br_keys_req btm_ble_br_keys_req; - // Name: btm_ble_connected // Params: const RawAddress& bda, uint16_t handle, uint8_t enc_mode, uint8_t // role, tBLE_ADDR_TYPE addr_type, bool addr_matched Return: void @@ -390,9 +403,10 @@ struct btm_ble_connected { std::function - body{[](const RawAddress& bda, uint16_t handle, uint8_t enc_mode, - uint8_t role, tBLE_ADDR_TYPE addr_type, bool addr_matched, - bool can_read_discoverable_characteristics) {}}; + body{[](const RawAddress& /* bda */, uint16_t /* handle */, + uint8_t /* enc_mode */, uint8_t /* role */, + tBLE_ADDR_TYPE /* addr_type */, bool /* addr_matched */, + bool /* can_read_discoverable_characteristics */) {}}; void operator()(const RawAddress& bda, uint16_t handle, uint8_t enc_mode, uint8_t role, tBLE_ADDR_TYPE addr_type, bool addr_matched, bool can_read_discoverable_characteristics) { @@ -402,22 +416,6 @@ struct btm_ble_connected { }; extern struct btm_ble_connected btm_ble_connected; -// Name: btm_ble_determine_security_act -// Params: bool is_originator, const RawAddress& bdaddr, uint16_t -// security_required Return: tBTM_SEC_ACTION -struct btm_ble_determine_security_act { - static tBTM_SEC_ACTION return_value; - std::function - body{[](bool is_originator, const RawAddress& bdaddr, - uint16_t security_required) { return return_value; }}; - tBTM_SEC_ACTION operator()(bool is_originator, const RawAddress& bdaddr, - uint16_t security_required) { - return body(is_originator, bdaddr, security_required); - }; -}; -extern struct btm_ble_determine_security_act btm_ble_determine_security_act; - // Name: btm_ble_get_acl_remote_addr // Params: uint16_t hci_handle, RawAddress& conn_addr, tBLE_ADDR_TYPE* // p_addr_type Return: bool @@ -425,8 +423,8 @@ struct btm_ble_get_acl_remote_addr { static bool return_value; std::function - body{[](uint16_t hci_handle, RawAddress& conn_addr, - tBLE_ADDR_TYPE* p_addr_type) { return return_value; }}; + body{[](uint16_t /* hci_handle */, RawAddress& /* conn_addr */, + tBLE_ADDR_TYPE* /* p_addr_type */) { return return_value; }}; bool operator()(uint16_t hci_handle, RawAddress& conn_addr, tBLE_ADDR_TYPE* p_addr_type) { return body(hci_handle, conn_addr, p_addr_type); @@ -440,7 +438,7 @@ extern struct btm_ble_get_acl_remote_addr btm_ble_get_acl_remote_addr; struct btm_ble_get_enc_key_type { static bool return_value; std::function body{ - [](const RawAddress& bd_addr, uint8_t* p_key_types) { + [](const RawAddress& /* bd_addr */, uint8_t* /* p_key_types */) { return return_value; }}; bool operator()(const RawAddress& bd_addr, uint8_t* p_key_types) { @@ -449,39 +447,12 @@ struct btm_ble_get_enc_key_type { }; extern struct btm_ble_get_enc_key_type btm_ble_get_enc_key_type; -// Name: btm_ble_increment_sign_ctr -// Params: const RawAddress& bd_addr, bool is_local -// Return: void -struct btm_ble_increment_sign_ctr { - std::function body{ - [](const RawAddress& bd_addr, bool is_local) {}}; - void operator()(const RawAddress& bd_addr, bool is_local) { - body(bd_addr, is_local); - }; -}; -extern struct btm_ble_increment_sign_ctr btm_ble_increment_sign_ctr; - -// Name: btm_ble_io_capabilities_req -// Params: tBTM_SEC_DEV_REC* p_dev_rec, tBTM_LE_IO_REQ* p_data -// Return: uint8_t -struct btm_ble_io_capabilities_req { - static uint8_t return_value; - std::function - body{[](tBTM_SEC_DEV_REC* p_dev_rec, tBTM_LE_IO_REQ* p_data) { - return return_value; - }}; - uint8_t operator()(tBTM_SEC_DEV_REC* p_dev_rec, tBTM_LE_IO_REQ* p_data) { - return body(p_dev_rec, p_data); - }; -}; -extern struct btm_ble_io_capabilities_req btm_ble_io_capabilities_req; - // Name: btm_ble_link_encrypted // Params: const RawAddress& bd_addr, uint8_t encr_enable // Return: void struct btm_ble_link_encrypted { std::function body{ - [](const RawAddress& bd_addr, uint8_t encr_enable) {}}; + [](const RawAddress& /* bd_addr */, uint8_t /* encr_enable */) {}}; void operator()(const RawAddress& bd_addr, uint8_t encr_enable) { body(bd_addr, encr_enable); }; @@ -494,8 +465,8 @@ extern struct btm_ble_link_encrypted btm_ble_link_encrypted; struct btm_ble_link_sec_check { std::function - body{[](const RawAddress& bd_addr, tBTM_LE_AUTH_REQ auth_req, - tBTM_BLE_SEC_REQ_ACT* p_sec_req_act) {}}; + body{[](const RawAddress& /* bd_addr */, tBTM_LE_AUTH_REQ /* auth_req */, + tBTM_BLE_SEC_REQ_ACT* /* p_sec_req_act */) {}}; void operator()(const RawAddress& bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT* p_sec_req_act) { body(bd_addr, auth_req, p_sec_req_act); @@ -507,9 +478,9 @@ extern struct btm_ble_link_sec_check btm_ble_link_sec_check; // Params: uint16_t handle, uint8_t rand[8], uint16_t ediv // Return: void struct btm_ble_ltk_request { - std::function body{ - [](uint16_t handle, uint8_t* rand, uint16_t ediv) {}}; - void operator()(uint16_t handle, uint8_t* rand, uint16_t ediv) { + std::function body{ + [](uint16_t /* handle */, BT_OCTET8 /* rand */, uint16_t /* ediv */) {}}; + void operator()(uint16_t handle, BT_OCTET8 rand, uint16_t ediv) { body(handle, rand, ediv); }; }; @@ -520,35 +491,21 @@ extern struct btm_ble_ltk_request btm_ble_ltk_request; // Return: void struct btm_ble_ltk_request_reply { std::function - body{[](const RawAddress& bda, bool use_stk, const Octet16& stk) {}}; + body{[](const RawAddress& /* bda */, bool /* use_stk */, + const Octet16& /* stk */) {}}; void operator()(const RawAddress& bda, bool use_stk, const Octet16& stk) { body(bda, use_stk, stk); }; }; extern struct btm_ble_ltk_request_reply btm_ble_ltk_request_reply; -// Name: btm_ble_rand_enc_complete -// Params: uint8_t* p, uint16_t op_code, tBTM_RAND_ENC_CB* p_enc_cplt_cback -// Return: void -struct btm_ble_rand_enc_complete { - std::function - body{[](uint8_t* p, uint16_t evt_len, uint16_t op_code, - tBTM_RAND_ENC_CB* p_enc_cplt_cback) {}}; - void operator()(uint8_t* p, uint16_t evt_len, uint16_t op_code, - tBTM_RAND_ENC_CB* p_enc_cplt_cback) { - body(p, evt_len, op_code, p_enc_cplt_cback); - }; -}; -extern struct btm_ble_rand_enc_complete btm_ble_rand_enc_complete; - // Name: btm_ble_read_sec_key_size // Params: const RawAddress& bd_addr // Return: uint8_t struct btm_ble_read_sec_key_size { static uint8_t return_value; std::function body{ - [](const RawAddress& bd_addr) { return return_value; }}; + [](const RawAddress& /* bd_addr */) { return return_value; }}; uint8_t operator()(const RawAddress& bd_addr) { return body(bd_addr); }; }; extern struct btm_ble_read_sec_key_size btm_ble_read_sec_key_size; @@ -569,8 +526,8 @@ struct btm_ble_set_encryption { static tBTM_STATUS return_value; std::function - body{[](const RawAddress& bd_addr, tBTM_BLE_SEC_ACT sec_act, - uint8_t link_role) { return return_value; }}; + body{[](const RawAddress& /* bd_addr */, tBTM_BLE_SEC_ACT /* sec_act */, + uint8_t /* link_role */) { return return_value; }}; tBTM_STATUS operator()(const RawAddress& bd_addr, tBTM_BLE_SEC_ACT sec_act, uint8_t link_role) { return body(bd_addr, sec_act, link_role); @@ -582,7 +539,7 @@ extern struct btm_ble_set_encryption btm_ble_set_encryption; // Params: bool keep_rfu // Return: void struct btm_ble_set_keep_rfu_in_auth_req { - std::function body{[](bool keep_rfu) {}}; + std::function body{[](bool /* keep_rfu */) {}}; void operator()(bool keep_rfu) { body(keep_rfu); }; }; extern struct btm_ble_set_keep_rfu_in_auth_req btm_ble_set_keep_rfu_in_auth_req; @@ -591,7 +548,7 @@ extern struct btm_ble_set_keep_rfu_in_auth_req btm_ble_set_keep_rfu_in_auth_req; // Params: bool disable_disc // Return: void struct btm_ble_set_no_disc_if_pair_fail { - std::function body{[](bool disable_disc) {}}; + std::function body{[](bool /* disable_disc */) {}}; void operator()(bool disable_disc) { body(disable_disc); }; }; extern struct btm_ble_set_no_disc_if_pair_fail btm_ble_set_no_disc_if_pair_fail; @@ -601,7 +558,7 @@ extern struct btm_ble_set_no_disc_if_pair_fail btm_ble_set_no_disc_if_pair_fail; // Return: void struct btm_ble_set_test_local_sign_cntr_value { std::function body{ - [](bool enable, uint32_t test_local_sign_cntr) {}}; + [](bool /* enable */, uint32_t /* test_local_sign_cntr */) {}}; void operator()(bool enable, uint32_t test_local_sign_cntr) { body(enable, test_local_sign_cntr); }; @@ -614,7 +571,7 @@ extern struct btm_ble_set_test_local_sign_cntr_value // Return: void struct btm_ble_set_test_mac_value { std::function body{ - [](bool enable, uint8_t* p_test_mac_val) {}}; + [](bool /* enable */, uint8_t* /* p_test_mac_val */) {}}; void operator()(bool enable, uint8_t* p_test_mac_val) { body(enable, p_test_mac_val); }; @@ -628,9 +585,8 @@ struct btm_ble_start_encrypt { static tBTM_STATUS return_value; std::function - body{[](const RawAddress& bda, bool use_stk, Octet16* p_stk) { - return return_value; - }}; + body{[](const RawAddress& /* bda */, bool /* use_stk */, + Octet16* /* p_stk */) { return return_value; }}; tBTM_STATUS operator()(const RawAddress& bda, bool use_stk, Octet16* p_stk) { return body(bda, use_stk, p_stk); }; @@ -641,17 +597,16 @@ extern struct btm_ble_start_encrypt btm_ble_start_encrypt; // Params: const RawAddress& bd_addr, uint16_t psm, bool is_originator, // tBTM_SEC_CALLBACK* p_callback, void* p_ref_data Return: tL2CAP_LE_RESULT_CODE struct btm_ble_start_sec_check { - static tL2CAP_LE_RESULT_CODE return_value; - std::function - body{[](const RawAddress& bd_addr, uint16_t psm, bool is_originator, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data) { return return_value; }}; - tL2CAP_LE_RESULT_CODE operator()(const RawAddress& bd_addr, uint16_t psm, - bool is_originator, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data) { + static tBTM_STATUS return_value; + std::function + body{[](const RawAddress& /* bd_addr */, uint16_t /* psm */, + bool /* is_originator */, tBTM_SEC_CALLBACK* /* p_callback */, + void* /* p_ref_data */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress& bd_addr, uint16_t psm, + bool is_originator, tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data) { return body(bd_addr, psm, is_originator, p_callback, p_ref_data); }; }; @@ -661,7 +616,7 @@ extern struct btm_ble_start_sec_check btm_ble_start_sec_check; // Params: uint8_t* p // Return: void struct btm_ble_test_command_complete { - std::function body{[](uint8_t* p) {}}; + std::function body{[](uint8_t* /* p */) {}}; void operator()(uint8_t* p) { body(p); }; }; extern struct btm_ble_test_command_complete btm_ble_test_command_complete; @@ -671,7 +626,7 @@ extern struct btm_ble_test_command_complete btm_ble_test_command_complete; // Return: void struct btm_ble_update_sec_key_size { std::function body{ - [](const RawAddress& bd_addr, uint8_t enc_key_size) {}}; + [](const RawAddress& /* bd_addr */, uint8_t /* enc_key_size */) {}}; void operator()(const RawAddress& bd_addr, uint8_t enc_key_size) { body(bd_addr, enc_key_size); }; @@ -684,7 +639,9 @@ extern struct btm_ble_update_sec_key_size btm_ble_update_sec_key_size; struct btm_get_local_div { static bool return_value; std::function body{ - [](const RawAddress& bd_addr, uint16_t* p_div) { return return_value; }}; + [](const RawAddress& /* bd_addr */, uint16_t* /* p_div */) { + return return_value; + }}; bool operator()(const RawAddress& bd_addr, uint16_t* p_div) { return body(bd_addr, p_div); }; @@ -698,8 +655,8 @@ struct btm_proc_smp_cback { static tBTM_STATUS return_value; std::function - body{[](tSMP_EVT event, const RawAddress& bd_addr, - const tSMP_EVT_DATA* p_data) { return return_value; }}; + body{[](tSMP_EVT /* event */, const RawAddress& /* bd_addr */, + const tSMP_EVT_DATA* /* p_data */) { return return_value; }}; tBTM_STATUS operator()(tSMP_EVT event, const RawAddress& bd_addr, const tSMP_EVT_DATA* p_data) { return body(event, bd_addr, p_data); @@ -713,8 +670,9 @@ extern struct btm_proc_smp_cback btm_proc_smp_cback; struct btm_sec_save_le_key { std::function - body{[](const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type, - tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) {}}; + body{[](const RawAddress& /* bd_addr */, tBTM_LE_KEY_TYPE /* key_type */, + tBTM_LE_KEY_VALUE* /* p_keys */, + bool /* pass_to_application */) {}}; void operator()(const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) { body(bd_addr, key_type, p_keys, pass_to_application); @@ -727,7 +685,7 @@ extern struct btm_sec_save_le_key btm_sec_save_le_key; // Return: void struct doNothing { std::function body{ - [](uint8_t* data, uint16_t len) {}}; + [](uint8_t* /* data */, uint16_t /* len */) {}}; void operator()(uint8_t* data, uint16_t len) { body(data, len); }; }; extern struct doNothing doNothing; @@ -742,8 +700,8 @@ struct read_phy_cb { uint8_t* data, uint16_t len)> body{[](base::Callback - callback, - uint8_t* data, uint16_t len) {}}; + /* callback */, + uint8_t* /* data */, uint16_t /* len */) {}}; void operator()( base::Callback callback, @@ -757,4 +715,9 @@ extern struct read_phy_cb read_phy_cb; } // namespace mock } // namespace test +std::optional BTM_BleGetIdentityAddress( + const RawAddress /* address */) { + return std::nullopt; +} + // END mockcify generation diff --git a/system/test/mock/mock_stack_btm_ble_addr.cc b/system/test/mock/mock_stack_btm_ble_addr.cc index ae5067d9dbec2c8dc00a202337e01dd6d631dd59..2f736ab410e0be5e9333cc9c68e632103cc2dc10 100644 --- a/system/test/mock/mock_stack_btm_ble_addr.cc +++ b/system/test/mock/mock_stack_btm_ble_addr.cc @@ -20,27 +20,16 @@ * * mockcify.pl ver 0.2 */ - -#include -#include +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_ble_addr.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_btm_ble_addr.h" +#include "test/common/mock_functions.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -50,8 +39,6 @@ namespace stack_btm_ble_addr { // Function state capture and return values, if needed struct btm_gen_resolve_paddr_low btm_gen_resolve_paddr_low; struct btm_gen_resolvable_private_addr btm_gen_resolvable_private_addr; -struct btm_get_next_private_addrress_interval_ms - btm_get_next_private_addrress_interval_ms; struct btm_ble_init_pseudo_addr btm_ble_init_pseudo_addr; struct btm_ble_addr_resolvable btm_ble_addr_resolvable; struct btm_ble_resolve_random_addr btm_ble_resolve_random_addr; @@ -76,11 +63,6 @@ void btm_gen_resolvable_private_addr( inc_func_call_count(__func__); test::mock::stack_btm_ble_addr::btm_gen_resolvable_private_addr(cb); } -uint64_t btm_get_next_private_addrress_interval_ms() { - inc_func_call_count(__func__); - return test::mock::stack_btm_ble_addr:: - btm_get_next_private_addrress_interval_ms(); -} bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr) { inc_func_call_count(__func__); @@ -120,7 +102,7 @@ bool btm_random_pseudo_to_identity_addr(RawAddress* random_pseudo, } void btm_ble_refresh_peer_resolvable_private_addr( const RawAddress& pseudo_bda, const RawAddress& rpa, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type) { + tBLE_RAND_ADDR_TYPE rra_type) { inc_func_call_count(__func__); test::mock::stack_btm_ble_addr::btm_ble_refresh_peer_resolvable_private_addr( pseudo_bda, rpa, rra_type); diff --git a/system/test/mock/mock_stack_btm_ble_addr.h b/system/test/mock/mock_stack_btm_ble_addr.h index cfd8fae8e45c24ac11c636d8b264c5531c2e5632..dace61b37ea689c05c0fdc71552eb3a0895d5d1e 100644 --- a/system/test/mock/mock_stack_btm_ble_addr.h +++ b/system/test/mock/mock_stack_btm_ble_addr.h @@ -21,30 +21,15 @@ * mockcify.pl ver 0.2 */ -#include // RepeatingCallback - #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -// #include "stack/btm/security_device_record.h" -#include "test/common/mock_functions.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_btm_ble_addr { @@ -55,7 +40,7 @@ namespace stack_btm_ble_addr { // Returns: void struct btm_gen_resolve_paddr_low { std::function body{ - [](const RawAddress& address) {}}; + [](const RawAddress& /* address */) {}}; void operator()(const RawAddress& address) { body(address); }; }; extern struct btm_gen_resolve_paddr_low btm_gen_resolve_paddr_low; @@ -64,28 +49,19 @@ extern struct btm_gen_resolve_paddr_low btm_gen_resolve_paddr_low; // Returns: void struct btm_gen_resolvable_private_addr { std::function cb)> body{ - [](base::Callback cb) {}}; + [](base::Callback /* cb */) {}}; void operator()(base::Callback cb) { body(cb); }; }; extern struct btm_gen_resolvable_private_addr btm_gen_resolvable_private_addr; -// Name: btm_get_next_private_addrress_interval_ms -// Params: -// Returns: uint64_t -struct btm_get_next_private_addrress_interval_ms { - std::function body{[]() { return 0; }}; - uint64_t operator()() { return body(); }; -}; -extern struct btm_get_next_private_addrress_interval_ms - btm_get_next_private_addrress_interval_ms; + // Name: btm_ble_init_pseudo_addr // Params: tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr // Returns: bool struct btm_ble_init_pseudo_addr { std::function - body{[](tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr) { - return false; - }}; + body{[](tBTM_SEC_DEV_REC* /* p_dev_rec */, + const RawAddress& /* new_pseudo_addr */) { return false; }}; bool operator()(tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr) { return body(p_dev_rec, new_pseudo_addr); @@ -97,7 +73,9 @@ extern struct btm_ble_init_pseudo_addr btm_ble_init_pseudo_addr; // Returns: bool struct btm_ble_addr_resolvable { std::function body{ - [](const RawAddress& rpa, tBTM_SEC_DEV_REC* p_dev_rec) { return false; }}; + [](const RawAddress& /* rpa */, tBTM_SEC_DEV_REC* /* p_dev_rec */) { + return false; + }}; bool operator()(const RawAddress& rpa, tBTM_SEC_DEV_REC* p_dev_rec) { return body(rpa, p_dev_rec); }; @@ -108,7 +86,7 @@ extern struct btm_ble_addr_resolvable btm_ble_addr_resolvable; // Returns: tBTM_SEC_DEV_REC* struct btm_ble_resolve_random_addr { std::function body{ - [](const RawAddress& random_bda) { return nullptr; }}; + [](const RawAddress& /* random_bda */) { return nullptr; }}; tBTM_SEC_DEV_REC* operator()(const RawAddress& random_bda) { return body(random_bda); }; @@ -120,9 +98,8 @@ extern struct btm_ble_resolve_random_addr btm_ble_resolve_random_addr; struct btm_identity_addr_to_random_pseudo { std::function - body{[](RawAddress* bd_addr, tBLE_ADDR_TYPE* p_addr_type, bool refresh) { - return false; - }}; + body{[](RawAddress* /* bd_addr */, tBLE_ADDR_TYPE* /* p_addr_type */, + bool /* refresh */) { return false; }}; bool operator()(RawAddress* bd_addr, tBLE_ADDR_TYPE* p_addr_type, bool refresh) { return body(bd_addr, p_addr_type, refresh); @@ -135,7 +112,9 @@ extern struct btm_identity_addr_to_random_pseudo // Returns: bool struct btm_identity_addr_to_random_pseudo_from_address_with_type { std::function body{ - [](tBLE_BD_ADDR* address_with_type, bool refresh) { return false; }}; + [](tBLE_BD_ADDR* /* address_with_type */, bool /* refresh */) { + return false; + }}; bool operator()(tBLE_BD_ADDR* address_with_type, bool refresh) { return body(address_with_type, refresh); }; @@ -148,9 +127,8 @@ extern struct btm_identity_addr_to_random_pseudo_from_address_with_type struct btm_random_pseudo_to_identity_addr { std::function - body{[](RawAddress* random_pseudo, tBLE_ADDR_TYPE* p_identity_addr_type) { - return false; - }}; + body{[](RawAddress* /* random_pseudo */, + tBLE_ADDR_TYPE* /* p_identity_addr_type */) { return false; }}; bool operator()(RawAddress* random_pseudo, tBLE_ADDR_TYPE* p_identity_addr_type) { return body(random_pseudo, p_identity_addr_type); @@ -160,14 +138,14 @@ extern struct btm_random_pseudo_to_identity_addr btm_random_pseudo_to_identity_addr; // Name: btm_ble_refresh_peer_resolvable_private_addr // Params: const RawAddress& pseudo_bda, const RawAddress& rpa, -// tBTM_SEC_BLE::tADDRESS_TYPE rra_type Returns: void +// tBLE_RAND_ADDR_TYPE rra_type Returns: void struct btm_ble_refresh_peer_resolvable_private_addr { std::function - body{[](const RawAddress& pseudo_bda, const RawAddress& rpa, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type) {}}; + tBLE_RAND_ADDR_TYPE rra_type)> + body{[](const RawAddress& /* pseudo_bda */, const RawAddress& /* rpa */, + tBLE_RAND_ADDR_TYPE /* rra_type */) {}}; void operator()(const RawAddress& pseudo_bda, const RawAddress& rpa, - tBTM_SEC_BLE::tADDRESS_TYPE rra_type) { + tBLE_RAND_ADDR_TYPE rra_type) { body(pseudo_bda, rpa, rra_type); }; }; diff --git a/system/test/mock/mock_stack_btm_ble_adv_filter.cc b/system/test/mock/mock_stack_btm_ble_adv_filter.cc index 396992592eaf514a73fec182704cd2e2cd45c3c4..95d56bf6ae216756bc2c81fe45501f7f8966799c 100644 --- a/system/test/mock/mock_stack_btm_ble_adv_filter.cc +++ b/system/test/mock/mock_stack_btm_ble_adv_filter.cc @@ -20,43 +20,17 @@ */ #include -#include -#include -#include -#include -#include +#include -#include "bind_helpers.h" -#include "bt_target.h" #include "btm_ble_api.h" -#include "btu.h" -#include "device/include/controller.h" #include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_int_types.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void BTM_BleAdvFilterParamSetup( - tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, - std::unique_ptr p_filt_params, - tBTM_BLE_PF_PARAM_CB cb) { - inc_func_call_count(__func__); -} -void BTM_BleEnableDisableFilterFeature(uint8_t enable, - tBTM_BLE_PF_STATUS_CBACK p_stat_cback) { - inc_func_call_count(__func__); -} -void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index, - tBTM_BLE_PF_CFG_CBACK cb) { - inc_func_call_count(__func__); -} -void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index, - std::vector commands, - tBTM_BLE_PF_CFG_CBACK cb) { + tBTM_BLE_SCAN_COND_OP /* action */, tBTM_BLE_PF_FILT_INDEX /* filt_index */, + std::unique_ptr /* p_filt_params */, + tBTM_BLE_PF_PARAM_CB /* cb */) { inc_func_call_count(__func__); } void btm_ble_adv_filter_init(void) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_btm_ble_advertiser_hci_interface.cc b/system/test/mock/mock_stack_btm_ble_advertiser_hci_interface.cc deleted file mode 100644 index a4a3d5dba191af8c9f40514df4c3bbcb6a51b2ed..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_stack_btm_ble_advertiser_hci_interface.cc +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:5 - * - * mockcify.pl ver 0.2 - */ - -#include -#include -#include -#include - -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. - -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_btm_ble_advertiser_hci_interface.h" - -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -// Mocked internal structures, if any - -namespace test { -namespace mock { -namespace stack_btm_ble_advertiser_hci_interface { - -// Function state capture and return values, if needed -struct btm_le_on_advertising_set_terminated - btm_le_on_advertising_set_terminated; -struct btm_ble_advertiser_notify_terminated_legacy - btm_ble_advertiser_notify_terminated_legacy; - -} // namespace stack_btm_ble_advertiser_hci_interface -} // namespace mock -} // namespace test - -// Mocked functions, if any -void btm_le_on_advertising_set_terminated(uint8_t* p, uint16_t length) { - inc_func_call_count(__func__); - test::mock::stack_btm_ble_advertiser_hci_interface:: - btm_le_on_advertising_set_terminated(p, length); -} -void btm_ble_advertiser_notify_terminated_legacy(uint8_t status, - uint16_t connection_handle) { - inc_func_call_count(__func__); - test::mock::stack_btm_ble_advertiser_hci_interface:: - btm_ble_advertiser_notify_terminated_legacy(status, connection_handle); -} - -// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_ble_advertiser_hci_interface.h b/system/test/mock/mock_stack_btm_ble_advertiser_hci_interface.h deleted file mode 100644 index 890add1a09d0b5ff518fe6fb11a60cc1e2bcff94..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_stack_btm_ble_advertiser_hci_interface.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:5 - * - * mockcify.pl ver 0.2 - */ - -#include -#include -#include -#include - -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "stack/btm/ble_advertiser_hci_interface.h" -#include "test/common/mock_functions.h" - -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -namespace test { -namespace mock { -namespace stack_btm_ble_advertiser_hci_interface { - -// Shared state between mocked functions and tests -// Name: btm_le_on_advertising_set_terminated -// Params: uint8_t* p, uint16_t length -// Returns: void -struct btm_le_on_advertising_set_terminated { - std::function body{ - [](uint8_t* p, uint16_t length) {}}; - void operator()(uint8_t* p, uint16_t length) { body(p, length); }; -}; -extern struct btm_le_on_advertising_set_terminated - btm_le_on_advertising_set_terminated; -// Name: btm_ble_advertiser_notify_terminated_legacy -// Params: uint8_t status, uint16_t connection_handle -// Returns: void -struct btm_ble_advertiser_notify_terminated_legacy { - std::function body{ - [](uint8_t status, uint16_t connection_handle) {}}; - void operator()(uint8_t status, uint16_t connection_handle) { - body(status, connection_handle); - }; -}; -extern struct btm_ble_advertiser_notify_terminated_legacy - btm_ble_advertiser_notify_terminated_legacy; - -} // namespace stack_btm_ble_advertiser_hci_interface -} // namespace mock -} // namespace test - -// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_ble_batchscan.cc b/system/test/mock/mock_stack_btm_ble_batchscan.cc index af185b64bdfa0d9bd281dddd3b383f708601d1eb..8365f97bec5288b0b2239e3ae5a4704cdaadde16 100644 --- a/system/test/mock/mock_stack_btm_ble_batchscan.cc +++ b/system/test/mock/mock_stack_btm_ble_batchscan.cc @@ -21,48 +21,35 @@ #include #include -#include -#include -#include -#include -#include - -#include "bt_target.h" #include "btm_ble_api.h" -#include "btu.h" -#include "device/include/controller.h" -#include "stack/btm/btm_int_types.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void BTM_BleDisableBatchScan(base::Callback cb) { +void BTM_BleDisableBatchScan(base::Callback /* cb */) { inc_func_call_count(__func__); } -void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode, - uint32_t scan_interval, uint32_t scan_window, - tBLE_ADDR_TYPE addr_type, - tBTM_BLE_DISCARD_RULE discard_rule, - base::Callback cb) { +void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE /* scan_mode */, + uint32_t /* scan_interval */, + uint32_t /* scan_window */, + tBLE_ADDR_TYPE /* addr_type */, + tBTM_BLE_DISCARD_RULE /* discard_rule */, + base::Callback /* cb */) { inc_func_call_count(__func__); } -void BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, - tBTM_BLE_SCAN_REP_CBACK cb) { +void BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE /* scan_mode */, + tBTM_BLE_SCAN_REP_CBACK /* cb */) { inc_func_call_count(__func__); } -void BTM_BleSetStorageConfig(uint8_t batch_scan_full_max, - uint8_t batch_scan_trunc_max, - uint8_t batch_scan_notify_threshold, - base::Callback cb, - tBTM_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback, - tBTM_BLE_REF_VALUE ref_value) { +void BTM_BleSetStorageConfig(uint8_t /* batch_scan_full_max */, + uint8_t /* batch_scan_trunc_max */, + uint8_t /* batch_scan_notify_threshold */, + base::Callback /* cb */, + tBTM_BLE_SCAN_THRESHOLD_CBACK* /* p_thres_cback */, + tBTM_BLE_REF_VALUE /* ref_value */) { inc_func_call_count(__func__); } -void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback, - tBTM_BLE_REF_VALUE ref_value) { +void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* /* p_track_cback */, + tBTM_BLE_REF_VALUE /* ref_value */) { inc_func_call_count(__func__); } void btm_ble_batchscan_init(void) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_btm_ble_bgconn.cc b/system/test/mock/mock_stack_btm_ble_bgconn.cc index 13a42b60a9abf61d0395905f996eb5ec2d650729..d3561a4f9adcf0b6449939b488e685de5b8c547d 100644 --- a/system/test/mock/mock_stack_btm_ble_bgconn.cc +++ b/system/test/mock/mock_stack_btm_ble_bgconn.cc @@ -20,21 +20,13 @@ * * mockcify.pl ver 0.2 */ - -#include -#include -#include -#include - // Mock include file to share data between tests and mock #include "test/mock/mock_stack_btm_ble_bgconn.h" + +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any struct BackgroundConnection {}; struct BgConnHash {}; @@ -44,11 +36,9 @@ namespace mock { namespace stack_btm_ble_bgconn { // Function state capture and return values, if needed -struct convert_to_address_with_type convert_to_address_with_type; struct btm_update_scanner_filter_policy btm_update_scanner_filter_policy; struct btm_ble_suspend_bg_conn btm_ble_suspend_bg_conn; struct btm_ble_resume_bg_conn btm_ble_resume_bg_conn; -struct BTM_BackgroundConnectAddressKnown BTM_BackgroundConnectAddressKnown; struct BTM_SetLeConnectionModeToFast BTM_SetLeConnectionModeToFast; struct BTM_SetLeConnectionModeToSlow BTM_SetLeConnectionModeToSlow; struct BTM_AcceptlistAdd BTM_AcceptlistAdd; @@ -60,13 +50,6 @@ struct BTM_AcceptlistClear BTM_AcceptlistClear; } // namespace mock } // namespace test -// Mocked functions, if any -const tBLE_BD_ADDR convert_to_address_with_type( - const RawAddress& bd_addr, const tBTM_SEC_DEV_REC* p_dev_rec) { - inc_func_call_count(__func__); - return test::mock::stack_btm_ble_bgconn::convert_to_address_with_type( - bd_addr, p_dev_rec); -} void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) { inc_func_call_count(__func__); test::mock::stack_btm_ble_bgconn::btm_update_scanner_filter_policy( @@ -80,11 +63,6 @@ bool btm_ble_resume_bg_conn(void) { inc_func_call_count(__func__); return test::mock::stack_btm_ble_bgconn::btm_ble_resume_bg_conn(); } -bool BTM_BackgroundConnectAddressKnown(const RawAddress& address) { - inc_func_call_count(__func__); - return test::mock::stack_btm_ble_bgconn::BTM_BackgroundConnectAddressKnown( - address); -} bool BTM_SetLeConnectionModeToFast() { inc_func_call_count(__func__); return test::mock::stack_btm_ble_bgconn::BTM_SetLeConnectionModeToFast(); diff --git a/system/test/mock/mock_stack_btm_ble_bgconn.h b/system/test/mock/mock_stack_btm_ble_bgconn.h index e3971c1f610e762157582cadc9ab0875e42a966f..66c488bbbc97f57bf3f64e7644e583835613c66a 100644 --- a/system/test/mock/mock_stack_btm_ble_bgconn.h +++ b/system/test/mock/mock_stack_btm_ble_bgconn.h @@ -21,62 +21,25 @@ * mockcify.pl ver 0.2 */ -#include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. #include -#include -#include - -#include "device/include/controller.h" -#include "main/shim/acl_api.h" -#include "main/shim/shim.h" -#include "stack/btm/btm_dev.h" -#include "stack/btm/btm_int_types.h" -#include "stack/btm/security_device_record.h" -#include "test/common/mock_functions.h" +#include "stack/include/btm_ble_api_types.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_btm_ble_bgconn { -// Shared state between mocked functions and tests -// Name: convert_to_address_with_type -// Params: const RawAddress& bd_addr, const tBTM_SEC_DEV_REC* p_dev_rec -// Returns: const tBLE_BD_ADDR -struct convert_to_address_with_type { - tBLE_BD_ADDR ble_bd_addr; - std::function - body{[this](const RawAddress& bd_addr, - const tBTM_SEC_DEV_REC* p_dev_rec) { return ble_bd_addr; }}; - const tBLE_BD_ADDR operator()(const RawAddress& bd_addr, - const tBTM_SEC_DEV_REC* p_dev_rec) { - return body(bd_addr, p_dev_rec); - }; -}; -extern struct convert_to_address_with_type convert_to_address_with_type; // Name: btm_update_scanner_filter_policy // Params: tBTM_BLE_SFP scan_policy // Returns: void struct btm_update_scanner_filter_policy { std::function body{ - [](tBTM_BLE_SFP scan_policy) {}}; + [](tBTM_BLE_SFP /* scan_policy */) {}}; void operator()(tBTM_BLE_SFP scan_policy) { body(scan_policy); }; }; extern struct btm_update_scanner_filter_policy btm_update_scanner_filter_policy; @@ -96,16 +59,7 @@ struct btm_ble_resume_bg_conn { bool operator()(void) { return body(); }; }; extern struct btm_ble_resume_bg_conn btm_ble_resume_bg_conn; -// Name: BTM_BackgroundConnectAddressKnown -// Params: const RawAddress& address -// Returns: bool -struct BTM_BackgroundConnectAddressKnown { - std::function body{ - [](const RawAddress& address) { return false; }}; - bool operator()(const RawAddress& address) { return body(address); }; -}; -extern struct BTM_BackgroundConnectAddressKnown - BTM_BackgroundConnectAddressKnown; + // Name: BTM_SetLeConnectionModeToFast // Params: // Returns: bool @@ -127,7 +81,7 @@ extern struct BTM_SetLeConnectionModeToSlow BTM_SetLeConnectionModeToSlow; // Returns: bool struct BTM_AcceptlistAdd { std::function body{ - [](const RawAddress& address) { return false; }}; + [](const RawAddress& /* address */) { return false; }}; bool operator()(const RawAddress& address) { return body(address); }; }; extern struct BTM_AcceptlistAdd BTM_AcceptlistAdd; @@ -136,7 +90,9 @@ extern struct BTM_AcceptlistAdd BTM_AcceptlistAdd; // Returns: bool struct BTM_AcceptlistAddDirect { std::function body{ - [](const RawAddress& address, bool is_direct) { return false; }}; + [](const RawAddress& /* address */, bool /* is_direct */) { + return false; + }}; bool operator()(const RawAddress& address, bool is_direct) { return body(address, is_direct); }; @@ -147,7 +103,7 @@ extern struct BTM_AcceptlistAddDirect BTM_AcceptlistAddDirect; // Returns: void struct BTM_AcceptlistRemove { std::function body{ - [](const RawAddress& address) {}}; + [](const RawAddress& /* address */) {}}; void operator()(const RawAddress& address) { body(address); }; }; extern struct BTM_AcceptlistRemove BTM_AcceptlistRemove; diff --git a/system/test/mock/mock_stack_btm_ble_gap.cc b/system/test/mock/mock_stack_btm_ble_gap.cc index 79cd29edb9316fb4dbc270182e9a1972068a9f91..23c22b4e4223c92b74d8a8bac2d21b00fa0354de 100644 --- a/system/test/mock/mock_stack_btm_ble_gap.cc +++ b/system/test/mock/mock_stack_btm_ble_gap.cc @@ -23,37 +23,17 @@ #include #include -#include -#include -#include -#include #include -#include "common/time_util.h" -#include "device/include/controller.h" -#include "main/shim/acl_api.h" -#include "main/shim/btm_api.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" #include "stack/btm/btm_ble_int.h" #include "stack/btm/btm_ble_int_types.h" #include "stack/btm/btm_dev.h" -#include "stack/btm/btm_int_types.h" -#include "stack/gatt/gatt_int.h" -#include "stack/include/acl_api.h" -#include "stack/include/advertise_data_parser.h" #include "stack/include/btm_api_types.h" -#include "stack/include/gap_api.h" #include "stack/include/hci_error_code.h" -#include "stack/include/inq_hci_link_interface.h" #include "test/common/mock_functions.h" #include "types/ble_address_with_type.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - using StartSyncCb = base::Callback; using SyncTransferCb = base::Callback; -bool BTM_BleConfigPrivacy(bool privacy_mode) { +bool ble_vnd_is_included() { + inc_func_call_count(__func__); + return false; +} +bool BTM_BleConfigPrivacy(bool /* privacy_mode */) { inc_func_call_count(__func__); return false; } @@ -72,50 +56,51 @@ bool BTM_BleLocalPrivacyEnabled(void) { inc_func_call_count(__func__); return false; } -bool btm_ble_cancel_remote_name(const RawAddress& remote_bda) { +bool btm_ble_cancel_remote_name(const RawAddress& /* remote_bda */) { inc_func_call_count(__func__); return false; } -bool btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) { +bool btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK /* request_state_mask */) { inc_func_call_count(__func__); return false; } -bool btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) { +bool btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK /* request_state_mask */) { inc_func_call_count(__func__); return false; } -bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask) { +bool btm_ble_topology_check(tBTM_BLE_STATE_MASK /* request_state_mask */) { inc_func_call_count(__func__); return false; } -tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration, - tBTM_INQ_RESULTS_CB* p_results_cb, - tBTM_CMPL_CB* p_cmpl_cb, bool low_latency_scan) { +tBTM_STATUS BTM_BleObserve(bool /* start */, uint8_t /* duration */, + tBTM_INQ_RESULTS_CB* /* p_results_cb */, + tBTM_CMPL_CB* /* p_cmpl_cb */, + bool /* low_latency_scan */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -void BTM_BleOpportunisticObserve(bool enable, - tBTM_INQ_RESULTS_CB* p_results_cb) { +void BTM_BleOpportunisticObserve(bool /* enable */, + tBTM_INQ_RESULTS_CB* /* p_results_cb */) { inc_func_call_count(__func__); } -void BTM_BleTargetAnnouncementObserve(bool enable, - tBTM_INQ_RESULTS_CB* p_results_cb) { +void BTM_BleTargetAnnouncementObserve(bool /* enable */, + tBTM_INQ_RESULTS_CB* /* p_results_cb */) { inc_func_call_count(__func__); } -tBTM_STATUS btm_ble_read_remote_name(const RawAddress& remote_bda, - tBTM_CMPL_CB* p_cb) { +tBTM_STATUS btm_ble_read_remote_name(const RawAddress& /* remote_bda */, + tBTM_CMPL_CB* /* p_cb */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode) { +tBTM_STATUS btm_ble_set_connectability(uint16_t /* combined_mode */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode) { +tBTM_STATUS btm_ble_set_discoverability(uint16_t /* combined_mode */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS btm_ble_start_inquiry(uint8_t duration) { +tBTM_STATUS btm_ble_start_inquiry(uint8_t /* duration */) { inc_func_call_count(__func__); return BTM_SUCCESS; } @@ -132,122 +117,144 @@ uint8_t BTM_BleMaxMultiAdvInstanceCount(void) { return 0; } void BTM_BleGetDynamicAudioBuffer( - tBTM_BT_DYNAMIC_AUDIO_BUFFER_CB p_dynamic_audio_buffer_cb[]) { + tBTM_BT_DYNAMIC_AUDIO_BUFFER_CB /* p_dynamic_audio_buffer_cb*/[]) { inc_func_call_count(__func__); } -void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb) { +void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB* /* p_cmn_vsc_cb */) { inc_func_call_count(__func__); } -void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window, - tBLE_SCAN_MODE scan_mode, - base::Callback cb) { +void BTM_BleSetScanParams(uint32_t /* scan_interval */, + uint32_t /* scan_window */, + tBLE_SCAN_MODE /* scan_mode */, + base::Callback /* cb */) { inc_func_call_count(__func__); } -void btm_ble_decrement_link_topology_mask(uint8_t link_role) { +void btm_ble_decrement_link_topology_mask(uint8_t /* link_role */) { inc_func_call_count(__func__); } void btm_ble_dir_adv_tout(void) { inc_func_call_count(__func__); } void btm_ble_free() { inc_func_call_count(__func__); } -void btm_ble_increment_link_topology_mask(uint8_t link_role) { +void btm_ble_increment_link_topology_mask(uint8_t /* link_role */) { inc_func_call_count(__func__); } void btm_ble_init(void) { inc_func_call_count(__func__); } -bool btm_ble_get_appearance_as_cod(std::vector const& data, - DEV_CLASS dev_class) { +bool btm_ble_get_appearance_as_cod(std::vector const& /* data */, + DEV_CLASS /* dev_class */) { inc_func_call_count(__func__); return false; } -void btm_ble_process_adv_addr(RawAddress& bda, tBLE_ADDR_TYPE* addr_type) { +void btm_ble_process_adv_addr(RawAddress& /* bda */, + tBLE_ADDR_TYPE* /* addr_type */) { inc_func_call_count(__func__); } -void btm_ble_process_adv_pkt(uint8_t data_len, const uint8_t* data) { +void btm_ble_process_adv_pkt(uint8_t /* data_len */, + const uint8_t* /* data */) { inc_func_call_count(__func__); } -void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type, - const RawAddress& bda, uint8_t primary_phy, - uint8_t secondary_phy, - uint8_t advertising_sid, int8_t tx_power, - int8_t rssi, uint16_t periodic_adv_int, - uint8_t data_len, const uint8_t* data, - const RawAddress& original_bda) { +void btm_ble_process_adv_pkt_cont( + uint16_t /* evt_type */, tBLE_ADDR_TYPE /* addr_type */, + const RawAddress& /* bda */, uint8_t /* primary_phy */, + uint8_t /* secondary_phy */, uint8_t /* advertising_sid */, + int8_t /* tx_power */, int8_t /* rssi */, uint16_t /* periodic_adv_int */, + uint8_t /* data_len */, const uint8_t* /* data */, + const RawAddress& /* original_bda */) { inc_func_call_count(__func__); } void btm_ble_process_adv_pkt_cont_for_inquiry( - uint16_t evt_type, tBLE_ADDR_TYPE addr_type, const RawAddress& bda, - uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, - int8_t tx_power, int8_t rssi, uint16_t periodic_adv_int, - std::vector advertising_data) { + uint16_t /* evt_type */, tBLE_ADDR_TYPE /* addr_type */, + const RawAddress& /* bda */, uint8_t /* primary_phy */, + uint8_t /* secondary_phy */, uint8_t /* advertising_sid */, + int8_t /* tx_power */, int8_t /* rssi */, uint16_t /* periodic_adv_int */, + std::vector /* advertising_data */) { inc_func_call_count(__func__); } -void btm_ble_process_ext_adv_pkt(uint8_t data_len, const uint8_t* data) { +void btm_ble_process_ext_adv_pkt(uint8_t /* data_len */, + const uint8_t* /* data */) { inc_func_call_count(__func__); } -void btm_ble_process_phy_update_pkt(uint8_t len, uint8_t* data) { +void btm_ble_process_phy_update_pkt(uint8_t /* len */, uint8_t* /* data */) { inc_func_call_count(__func__); } -void btm_ble_read_remote_features_complete(uint8_t* p, uint8_t length) { +void btm_ble_read_remote_features_complete(uint8_t* /* p */, + uint8_t /* length */) { inc_func_call_count(__func__); } -void btm_ble_read_remote_name_cmpl(bool status, const RawAddress& bda, - uint16_t length, char* p_name) { +void btm_ble_read_remote_name_cmpl(bool /* status */, + const RawAddress& /* bda */, + uint16_t /* length */, char* /* p_name */) { inc_func_call_count(__func__); } -void btm_ble_set_adv_flag(uint16_t connect_mode, uint16_t disc_mode) { +void btm_ble_set_adv_flag(uint16_t /* connect_mode */, + uint16_t /* disc_mode */) { inc_func_call_count(__func__); } void btm_ble_stop_inquiry(void) { inc_func_call_count(__func__); } -void btm_ble_update_dmt_flag_bits(uint8_t* adv_flag_value, - const uint16_t connect_mode, - const uint16_t disc_mode) { +void btm_ble_update_dmt_flag_bits(uint8_t* /* adv_flag_value */, + const uint16_t /* connect_mode */, + const uint16_t /* disc_mode */) { + inc_func_call_count(__func__); +} +void btm_ble_update_inq_result( + tINQ_DB_ENT* /* p_i */, uint8_t /* addr_type */, + const RawAddress& /* bda */, uint16_t /* evt_type */, + uint8_t /* primary_phy */, uint8_t /* secondary_phy */, + uint8_t /* advertising_sid */, int8_t /* tx_power */, int8_t /* rssi */, + uint16_t /* periodic_adv_int */, std::vector const& /* data */) { inc_func_call_count(__func__); } -void btm_ble_update_inq_result(tINQ_DB_ENT* p_i, uint8_t addr_type, - const RawAddress& bda, uint16_t evt_type, - uint8_t primary_phy, uint8_t secondary_phy, - uint8_t advertising_sid, int8_t tx_power, - int8_t rssi, uint16_t periodic_adv_int, - std::vector const& data) { +void btm_ble_update_mode_operation(uint8_t /* link_role */, + const RawAddress* /* bd_addr */, + tHCI_STATUS /* status */) { inc_func_call_count(__func__); } -void btm_ble_update_mode_operation(uint8_t link_role, const RawAddress* bd_addr, - tHCI_STATUS status) { +void btm_ble_write_adv_enable_complete(uint8_t* /* p */, + uint16_t /* evt_len */) { inc_func_call_count(__func__); } -void btm_ble_write_adv_enable_complete(uint8_t* p, uint16_t evt_len) { +void btm_send_hci_set_scan_params(uint8_t /* scan_type */, + uint16_t /* scan_int */, + uint16_t /* scan_win */, + tBLE_ADDR_TYPE /* addr_type_own */, + uint8_t /* scan_filter_policy */) { inc_func_call_count(__func__); } -void btm_send_hci_set_scan_params(uint8_t scan_type, uint16_t scan_int, - uint16_t scan_win, - tBLE_ADDR_TYPE addr_type_own, - uint8_t scan_filter_policy) { +void BTM_BleStartPeriodicSync(uint8_t /* adv_sid */, RawAddress /* address */, + uint16_t /* skip */, uint16_t /* timeout */, + StartSyncCb /* syncCb */, + SyncReportCb /* reportCb */, + SyncLostCb /* lostCb */) { inc_func_call_count(__func__); } -void BTM_BleStartPeriodicSync(uint8_t adv_sid, RawAddress address, - uint16_t skip, uint16_t timeout, - StartSyncCb syncCb, SyncReportCb reportCb, - SyncLostCb lostCb) { +void BTM_BleStopPeriodicSync(uint16_t /* handle */) { inc_func_call_count(__func__); } -void BTM_BleStopPeriodicSync(uint16_t handle) { inc_func_call_count(__func__); } -void BTM_BleCancelPeriodicSync(uint8_t adv_sid, RawAddress address) { +void BTM_BleCancelPeriodicSync(uint8_t /* adv_sid */, + RawAddress /* address */) { inc_func_call_count(__func__); } -void BTM_BlePeriodicSyncTransfer(RawAddress addr, uint16_t service_data, - uint16_t sync_handle, SyncTransferCb cb) { +void BTM_BlePeriodicSyncTransfer(RawAddress /* addr */, + uint16_t /* service_data */, + uint16_t /* sync_handle */, + SyncTransferCb /* cb */) { inc_func_call_count(__func__); } -void BTM_BlePeriodicSyncSetInfo(RawAddress addr, uint16_t service_data, - uint8_t adv_handle, SyncTransferCb cb) { +void BTM_BlePeriodicSyncSetInfo(RawAddress /* addr */, + uint16_t /* service_data */, + uint8_t /* adv_handle */, + SyncTransferCb /* cb */) { inc_func_call_count(__func__); } -void BTM_BlePeriodicSyncTxParameters(RawAddress addr, uint8_t mode, - uint16_t skip, uint16_t timeout, - StartSyncCb syncCb) { +void BTM_BlePeriodicSyncTxParameters(RawAddress /* addr */, uint8_t /* mode */, + uint16_t /* skip */, + uint16_t /* timeout */, + StartSyncCb /* syncCb */) { inc_func_call_count(__func__); } -void btm_ble_periodic_adv_sync_tx_rcvd(uint8_t* p, uint16_t param_len) { +void btm_ble_periodic_adv_sync_tx_rcvd(const uint8_t* /* p */, + uint16_t /* param_len */) { inc_func_call_count(__func__); } -void btm_ble_biginfo_adv_report_rcvd(uint8_t* p, uint16_t param_len) { +void btm_ble_biginfo_adv_report_rcvd(const uint8_t* /* p */, + uint16_t /* param_len */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_btm_ble_multi_adv.cc b/system/test/mock/mock_stack_btm_ble_multi_adv.cc deleted file mode 100644 index be052905c62a0cc63fc375886224a9e0e31141dd..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_stack_btm_ble_multi_adv.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:11 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "bind_helpers.h" -#include "ble_advertiser.h" -#include "bt_target.h" -#include "device/include/controller.h" -#include "osi/include/alarm.h" -#include "stack/btm/ble_advertiser_hci_interface.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_int_types.h" -#include "test/common/mock_functions.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void BleAdvertisingManager::CleanUp() { inc_func_call_count(__func__); } -void btm_ble_adv_init() { inc_func_call_count(__func__); } -base::WeakPtr BleAdvertisingManager::Get() { - inc_func_call_count(__func__); - return nullptr; -} -bool BleAdvertisingManager::IsInitialized() { - inc_func_call_count(__func__); - return false; -} -void test_timeout_cb(uint8_t status) { inc_func_call_count(__func__); } -void BleAdvertisingManager::Initialize(BleAdvertiserHciInterface* interface) { - inc_func_call_count(__func__); -} -void btm_ble_multi_adv_cleanup(void) { inc_func_call_count(__func__); } -void testRecomputeTimeout1() { inc_func_call_count(__func__); } -void testRecomputeTimeout2() { inc_func_call_count(__func__); } -void testRecomputeTimeout3() { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_btm_ble_privacy.cc b/system/test/mock/mock_stack_btm_ble_privacy.cc index ed15409df80f9dec00bcd7b72f5fd2932ee34de8..4ad71a12ab6b07ccd74383ed1ea19669f64ce950 100644 --- a/system/test/mock/mock_stack_btm_ble_privacy.cc +++ b/system/test/mock/mock_stack_btm_ble_privacy.cc @@ -20,25 +20,14 @@ * * mockcify.pl ver 0.2 */ - -#include -#include +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_ble_privacy.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_btm_ble_privacy.h" +#include "test/common/mock_functions.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -102,7 +91,7 @@ bool btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) { return test::mock::stack_btm_ble_privacy::btm_ble_read_resolving_list_entry( p_dev_rec); } -void btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC& p_dev_rec) { +void btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC& /* p_dev_rec */) { inc_func_call_count(__func__); } void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec) { diff --git a/system/test/mock/mock_stack_btm_ble_privacy.h b/system/test/mock/mock_stack_btm_ble_privacy.h index 396c75b5a213564f3d7cbaa37383d752bba0abe9..c632c62e0f7079e7cfa330d5d7bebfc3cd3a0995 100644 --- a/system/test/mock/mock_stack_btm_ble_privacy.h +++ b/system/test/mock/mock_stack_btm_ble_privacy.h @@ -23,23 +23,11 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. #include "stack/btm/security_device_record.h" -#include "test/common/mock_functions.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_btm_ble_privacy { @@ -50,7 +38,7 @@ namespace stack_btm_ble_privacy { // Returns: void struct btm_ble_clear_resolving_list_complete { std::function body{ - [](uint8_t* p, uint16_t evt_len) {}}; + [](uint8_t* /* p */, uint16_t /* evt_len */) {}}; void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); }; }; extern struct btm_ble_clear_resolving_list_complete @@ -60,7 +48,7 @@ extern struct btm_ble_clear_resolving_list_complete // Returns: void struct btm_ble_add_resolving_list_entry_complete { std::function body{ - [](uint8_t* p, uint16_t evt_len) {}}; + [](uint8_t* /* p */, uint16_t /* evt_len */) {}}; void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); }; }; extern struct btm_ble_add_resolving_list_entry_complete @@ -70,7 +58,7 @@ extern struct btm_ble_add_resolving_list_entry_complete // Returns: void struct btm_ble_remove_resolving_list_entry_complete { std::function body{ - [](uint8_t* p, uint16_t evt_len) {}}; + [](uint8_t* /* p */, uint16_t /* evt_len */) {}}; void operator()(uint8_t* p, uint16_t evt_len) { body(p, evt_len); }; }; extern struct btm_ble_remove_resolving_list_entry_complete @@ -80,7 +68,7 @@ extern struct btm_ble_remove_resolving_list_entry_complete // Returns: void struct btm_ble_read_resolving_list_entry_complete { std::function body{ - [](const uint8_t* p, uint16_t evt_len) {}}; + [](const uint8_t* /* p */, uint16_t /* evt_len */) {}}; void operator()(const uint8_t* p, uint16_t evt_len) { body(p, evt_len); }; }; extern struct btm_ble_read_resolving_list_entry_complete @@ -90,7 +78,7 @@ extern struct btm_ble_read_resolving_list_entry_complete // Returns: tBTM_STATUS struct btm_ble_remove_resolving_list_entry { std::function body{ - [](tBTM_SEC_DEV_REC* p_dev_rec) { return 0; }}; + [](tBTM_SEC_DEV_REC* /* p_dev_rec */) { return 0; }}; tBTM_STATUS operator()(tBTM_SEC_DEV_REC* p_dev_rec) { return body(p_dev_rec); }; @@ -110,7 +98,7 @@ extern struct btm_ble_clear_resolving_list btm_ble_clear_resolving_list; // Returns: bool struct btm_ble_read_resolving_list_entry { std::function body{ - [](tBTM_SEC_DEV_REC* p_dev_rec) { return false; }}; + [](tBTM_SEC_DEV_REC* /* p_dev_rec */) { return false; }}; bool operator()(tBTM_SEC_DEV_REC* p_dev_rec) { return body(p_dev_rec); }; }; extern struct btm_ble_read_resolving_list_entry @@ -120,7 +108,7 @@ extern struct btm_ble_read_resolving_list_entry // Returns: void struct btm_ble_resolving_list_load_dev { std::function body{ - [](const tBTM_SEC_DEV_REC& p_dev_rec) {}}; + [](const tBTM_SEC_DEV_REC& /* p_dev_rec */) {}}; void operator()(const tBTM_SEC_DEV_REC& p_dev_rec) { body(p_dev_rec); }; }; extern struct btm_ble_resolving_list_load_dev btm_ble_resolving_list_load_dev; @@ -129,7 +117,7 @@ extern struct btm_ble_resolving_list_load_dev btm_ble_resolving_list_load_dev; // Returns: void struct btm_ble_resolving_list_remove_dev { std::function body{ - [](tBTM_SEC_DEV_REC* p_dev_rec) {}}; + [](tBTM_SEC_DEV_REC* /* p_dev_rec */) {}}; void operator()(tBTM_SEC_DEV_REC* p_dev_rec) { body(p_dev_rec); }; }; extern struct btm_ble_resolving_list_remove_dev @@ -138,7 +126,7 @@ extern struct btm_ble_resolving_list_remove_dev // Params: uint8_t rl_mask // Returns: void struct btm_ble_enable_resolving_list_for_platform { - std::function body{[](uint8_t rl_mask) {}}; + std::function body{[](uint8_t /* rl_mask */) {}}; void operator()(uint8_t rl_mask) { body(rl_mask); }; }; extern struct btm_ble_enable_resolving_list_for_platform @@ -148,7 +136,7 @@ extern struct btm_ble_enable_resolving_list_for_platform // Returns: void struct btm_ble_resolving_list_init { std::function body{ - [](uint8_t max_irk_list_sz) {}}; + [](uint8_t /* max_irk_list_sz */) {}}; void operator()(uint8_t max_irk_list_sz) { body(max_irk_list_sz); }; }; extern struct btm_ble_resolving_list_init btm_ble_resolving_list_init; diff --git a/system/test/mock/mock_stack_btm_ble_scanner.cc b/system/test/mock/mock_stack_btm_ble_scanner.cc index ef34f700a06a20b4312651227adcd51db8ec280a..63951f555ef414cd1a49de4ade9be7b8a6efa1f9 100644 --- a/system/test/mock/mock_stack_btm_ble_scanner.cc +++ b/system/test/mock/mock_stack_btm_ble_scanner.cc @@ -20,27 +20,12 @@ #include #include #include -#include -#include -#include -#include -#include - -#include "bind_helpers.h" #include "ble_scanner.h" -#include "bt_target.h" -#include "device/include/controller.h" -#include "osi/include/alarm.h" #include "stack/btm/ble_scanner_hci_interface.h" #include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_int_types.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void BleScanningManager::CleanUp() { inc_func_call_count(__func__); } void btm_ble_scanner_init() { inc_func_call_count(__func__); } base::WeakPtr BleScanningManager::Get() { @@ -51,7 +36,7 @@ bool BleScanningManager::IsInitialized() { inc_func_call_count(__func__); return false; } -void BleScanningManager::Initialize(BleScannerHciInterface* interface) { +void BleScanningManager::Initialize(BleScannerHciInterface* /* interface */) { inc_func_call_count(__func__); } void btm_ble_scanner_cleanup(void) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_btm_ble_scanner_hci_interface.cc b/system/test/mock/mock_stack_btm_ble_scanner_hci_interface.cc deleted file mode 100644 index 802faccfba0274d6ba9d4aa4055cefc066450f31..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_stack_btm_ble_scanner_hci_interface.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:6 - * - * mockcify.pl ver 0.2 - */ - -#include -#include -#include -#include - -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_btm_ble_scanner_hci_interface.h" - -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -// Mocked internal structures, if any - -namespace test { -namespace mock { -namespace stack_btm_ble_scanner_hci_interface { - -// Function state capture and return values, if needed -struct btm_ble_process_periodic_adv_sync_est_evt - btm_ble_process_periodic_adv_sync_est_evt; -struct btm_ble_process_periodic_adv_pkt btm_ble_process_periodic_adv_pkt; -struct btm_ble_process_periodic_adv_sync_lost_evt - btm_ble_process_periodic_adv_sync_lost_evt; - -} // namespace stack_btm_ble_scanner_hci_interface -} // namespace mock -} // namespace test - -// Mocked functions, if any -void btm_ble_process_periodic_adv_sync_est_evt(uint8_t data_len, - const uint8_t* data) { - inc_func_call_count(__func__); - test::mock::stack_btm_ble_scanner_hci_interface:: - btm_ble_process_periodic_adv_sync_est_evt(data_len, data); -} -void btm_ble_process_periodic_adv_pkt(uint8_t data_len, const uint8_t* data) { - inc_func_call_count(__func__); - test::mock::stack_btm_ble_scanner_hci_interface:: - btm_ble_process_periodic_adv_pkt(data_len, data); -} -void btm_ble_process_periodic_adv_sync_lost_evt(uint8_t data_len, - uint8_t* data) { - inc_func_call_count(__func__); - test::mock::stack_btm_ble_scanner_hci_interface:: - btm_ble_process_periodic_adv_sync_lost_evt(data_len, data); -} - -// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_ble_scanner_hci_interface.h b/system/test/mock/mock_stack_btm_ble_scanner_hci_interface.h deleted file mode 100644 index f0d0232edac7b0dee83acb86242eda95d7ddbbc5..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_stack_btm_ble_scanner_hci_interface.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:6 - * - * mockcify.pl ver 0.2 - */ - -#include -#include -#include -#include - -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "stack/btm/ble_scanner_hci_interface.h" -#include "test/common/mock_functions.h" - -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -namespace test { -namespace mock { -namespace stack_btm_ble_scanner_hci_interface { - -// Name: btm_ble_process_periodic_adv_sync_est_evt -// Params: uint8_t data_len, uint8_t* data -// Returns: void -struct btm_ble_process_periodic_adv_sync_est_evt { - std::function body{ - [](uint8_t data_len, const uint8_t* data) {}}; - void operator()(uint8_t data_len, const uint8_t* data) { - body(data_len, data); - }; -}; -extern struct btm_ble_process_periodic_adv_sync_est_evt - btm_ble_process_periodic_adv_sync_est_evt; -// Name: btm_ble_process_periodic_adv_pkt -// Params: uint8_t data_len, uint8_t* data -// Returns: void -struct btm_ble_process_periodic_adv_pkt { - std::function body{ - [](uint8_t data_len, const uint8_t* data) {}}; - void operator()(uint8_t data_len, const uint8_t* data) { - body(data_len, data); - }; -}; -extern struct btm_ble_process_periodic_adv_pkt btm_ble_process_periodic_adv_pkt; -// Name: btm_ble_process_periodic_adv_sync_lost_evt -// Params: uint8_t data_len, uint8_t* data -// Returns: void -struct btm_ble_process_periodic_adv_sync_lost_evt { - std::function body{ - [](uint8_t data_len, uint8_t* data) {}}; - void operator()(uint8_t data_len, uint8_t* data) { body(data_len, data); }; -}; -extern struct btm_ble_process_periodic_adv_sync_lost_evt - btm_ble_process_periodic_adv_sync_lost_evt; - -} // namespace stack_btm_ble_scanner_hci_interface -} // namespace mock -} // namespace test - -// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_dev.cc b/system/test/mock/mock_stack_btm_dev.cc index e0fc1e35de37893edd92dba7a22e3a72ca9842c6..5c4958dbfd125be29205de7a613063704de0c58d 100644 --- a/system/test/mock/mock_stack_btm_dev.cc +++ b/system/test/mock/mock_stack_btm_dev.cc @@ -24,65 +24,48 @@ #include #include #include -#include -#include #include #include "btm_api.h" -#include "device/include/controller.h" -#include "l2c_api.h" -#include "main/shim/btm_api.h" -#include "main/shim/shim.h" #include "stack/btm/btm_dev.h" -#include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_btm_dev { struct btm_find_dev btm_find_dev; +struct BTM_Sec_AddressKnown BTM_Sec_AddressKnown; +struct maybe_resolve_address maybe_resolve_address; } } // namespace mock } // namespace test -bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, - const BD_NAME& bd_name, uint8_t* features, - LinkKey* p_link_key, uint8_t key_type, - uint8_t pin_length) { - inc_func_call_count(__func__); - return false; -} -bool BTM_SecDeleteDevice(const RawAddress& bd_addr) { +bool BTM_SecAddDevice(const RawAddress& /* bd_addr */, + DEV_CLASS /* dev_class */, const BD_NAME& /* bd_name */, + uint8_t* /* features */, LinkKey* /* p_link_key */, + uint8_t /* key_type */, uint8_t /* pin_length */) { inc_func_call_count(__func__); return false; } -bool btm_dev_support_role_switch(const RawAddress& bd_addr) { +bool BTM_SecDeleteDevice(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return false; } -bool btm_set_bond_type_dev(const RawAddress& bd_addr, - tBTM_SEC_DEV_REC::tBTM_BOND_TYPE bond_type) { +bool btm_dev_support_role_switch(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return false; } -bool is_address_equal(void* data, void* context) { +bool btm_set_bond_type_dev(const RawAddress& /* bd_addr */, + tBTM_BOND_TYPE /* bond_type */) { inc_func_call_count(__func__); return false; } -bool is_handle_equal(void* data, void* context) { - inc_func_call_count(__func__); - return false; -} -char* BTM_SecReadDevName(const RawAddress& bd_addr) { +const char* BTM_SecReadDevName(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return nullptr; } @@ -90,15 +73,15 @@ tBTM_SEC_DEV_REC* btm_find_dev(const RawAddress& bd_addr) { inc_func_call_count(__func__); return test::mock::stack_btm_dev::btm_find_dev.body(bd_addr); } -tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle) { +tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t /* handle */) { inc_func_call_count(__func__); return nullptr; } -tBTM_SEC_DEV_REC* btm_find_or_alloc_dev(const RawAddress& bd_addr) { +tBTM_SEC_DEV_REC* btm_find_or_alloc_dev(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return nullptr; } -tBTM_SEC_DEV_REC* btm_sec_alloc_dev(const RawAddress& bd_addr) { +tBTM_SEC_DEV_REC* btm_sec_alloc_dev(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return nullptr; } @@ -106,25 +89,23 @@ tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void) { inc_func_call_count(__func__); return nullptr; } -tBTM_SEC_DEV_REC::tBTM_BOND_TYPE btm_get_bond_type_dev( - const RawAddress& bd_addr) { +tBTM_BOND_TYPE btm_get_bond_type_dev(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); - return tBTM_SEC_DEV_REC::BOND_TYPE_UNKNOWN; + return BOND_TYPE_UNKNOWN; } -void BTM_SecClearSecurityFlags(const RawAddress& bd_addr) { +void BTM_SecClearSecurityFlags(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); } -void btm_consolidate_dev(tBTM_SEC_DEV_REC* p_target_rec) { +void btm_consolidate_dev(tBTM_SEC_DEV_REC* /* p_target_rec */) { inc_func_call_count(__func__); } -void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec) { +void btm_dev_consolidate_existing_connections(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); } -void btm_dev_consolidate_existing_connections(const RawAddress& bd_addr) { +void BTM_SecDump(const std::string& /* label */) { inc_func_call_count(__func__); } -void BTM_SecDump(const std::string& label) { inc_func_call_count(__func__); } -void BTM_SecDumpDev(const RawAddress& bd_addr) { +void BTM_SecDumpDev(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); } std::vector btm_get_sec_dev_rec() { @@ -132,6 +113,19 @@ std::vector btm_get_sec_dev_rec() { return {}; } -void BTM_SetConsolidationCallback(BTM_CONSOLIDATION_CB* cb) { +void BTM_SetConsolidationCallback(BTM_CONSOLIDATION_CB* /* cb */) { inc_func_call_count(__func__); } + +bool BTM_Sec_AddressKnown(const RawAddress& address) { + inc_func_call_count(__func__); + return test::mock::stack_btm_dev::BTM_Sec_AddressKnown(address); +} + +bool maybe_resolve_address(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { + inc_func_call_count(__func__); + return test::mock::stack_btm_dev::maybe_resolve_address(bda, bda_type); +} +const tBLE_BD_ADDR BTM_Sec_GetAddressWithType(const RawAddress& /* bd_addr */) { + return {}; +} diff --git a/system/test/mock/mock_stack_btm_dev.h b/system/test/mock/mock_stack_btm_dev.h index 3267b44f513c590bbf9f5e20d73350d59e5dd9ea..7fd76bbd11b28e3e868cd19059aadedb92eb634f 100644 --- a/system/test/mock/mock_stack_btm_dev.h +++ b/system/test/mock/mock_stack_btm_dev.h @@ -14,14 +14,7 @@ * limitations under the License. */ -#include -#include - #include "stack/btm/btm_dev.h" -#include "stack/include/btm_api_types.h" -#include "stack/include/btm_status.h" -#include "test/common/mock_functions.h" -#include "types/bt_transport.h" #include "types/raw_address.h" namespace test { @@ -38,6 +31,27 @@ struct btm_find_dev { }; extern struct btm_find_dev btm_find_dev; +struct BTM_Sec_AddressKnown { + std::function body{ + [](const RawAddress& /* address */) { return false; }}; + bool operator()(const RawAddress& address) { return body(address); }; +}; +extern struct BTM_Sec_AddressKnown BTM_Sec_AddressKnown; + +// Name: maybe_resolve_address +// Params: RawAddress* bda, tBLE_ADDR_TYPE* bda_type +// Returns: bool +struct maybe_resolve_address { + std::function body{ + [](RawAddress* /* bda */, tBLE_ADDR_TYPE* /* bda_type */) { + return false; + }}; + bool operator()(RawAddress* bda, tBLE_ADDR_TYPE* bda_type) { + return body(bda, bda_type); + }; +}; +extern struct maybe_resolve_address maybe_resolve_address; + } // namespace stack_btm_dev } // namespace mock } // namespace test diff --git a/system/test/mock/mock_stack_btm_devctl.cc b/system/test/mock/mock_stack_btm_devctl.cc index b7a5e32a03281c549b3a8be32d98873b1139bb9b..fb0581f487f6f954a1ddbf697a9892c924071c6d 100644 --- a/system/test/mock/mock_stack_btm_devctl.cc +++ b/system/test/mock/mock_stack_btm_devctl.cc @@ -23,33 +23,12 @@ #include #include #include -#include -#include -#include - -#include "bta/dm/bta_dm_int.h" -#include "bta/sys/bta_sys.h" -#include "btcore/include/module.h" -#include "btif/include/btif_bqr.h" -#include "common/message_loop_thread.h" -#include "device/include/controller.h" -#include "hci/include/hci_layer.h" -#include "main/shim/btm_api.h" -#include "main/shim/controller.h" -#include "main/shim/shim.h" -#include "osi/include/osi.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/gatt/connection_manager.h" -#include "stack/include/acl_api.h" -#include "stack/include/l2cap_controller_interface.h" +#include "stack/include/btm_api_types.h" +#include "stack/include/btm_status.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_btm_devctl { @@ -66,33 +45,39 @@ bool BTM_IsDeviceUp(void) { } tBTM_STATUS BTM_BT_Quality_Report_VSE_Register( - bool is_register, tBTM_BT_QUALITY_REPORT_RECEIVER* p_bqr_report_receiver) { + bool /* is_register */, + tBTM_BT_QUALITY_REPORT_RECEIVER* /* p_bqr_report_receiver */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* bd_addr, - tBTM_CMPL_CB* p_cb) { +tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* /* bd_addr */, + tBTM_CMPL_CB* /* p_cb */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_ReadLocalDeviceName(const char** p_name) { +tBTM_STATUS BTM_EnableTestMode(void) { + inc_func_call_count(__func__); + return BTM_SUCCESS; +} +tBTM_STATUS BTM_ReadLocalDeviceName(const char** /* p_name */) { inc_func_call_count(__func__); return BTM_SUCCESS; } tBTM_STATUS BTM_ReadLocalDeviceNameFromController( - tBTM_CMPL_CB* p_rln_cmpl_cback) { + tBTM_CMPL_CB* /* p_rln_cmpl_cback */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* p_cb, bool is_register) { +tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* /* p_cb */, + bool /* is_register */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_SetDeviceClass(DEV_CLASS dev_class) { +tBTM_STATUS BTM_SetDeviceClass(DEV_CLASS /* dev_class */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_SetLocalDeviceName(const char* p_name) { +tBTM_STATUS BTM_SetLocalDeviceName(const char* /* p_name */) { inc_func_call_count(__func__); return BTM_SUCCESS; } @@ -100,29 +85,33 @@ uint8_t* BTM_ReadDeviceClass(void) { inc_func_call_count(__func__); return nullptr; } -void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len, - uint8_t* p_param_buf, tBTM_VSC_CMPL_CB* p_cb) { +void BTM_VendorSpecificCommand(uint16_t /* opcode */, uint8_t /* param_len */, + uint8_t* /* p_param_buf */, + tBTM_VSC_CMPL_CB* /* p_cb */) { + inc_func_call_count(__func__); +} +void BTM_WritePageTimeout(uint16_t /* timeout */) { inc_func_call_count(__func__); } -void BTM_WritePageTimeout(uint16_t timeout) { inc_func_call_count(__func__); } -void BTM_WriteVoiceSettings(uint16_t settings) { +void BTM_WriteVoiceSettings(uint16_t /* settings */) { inc_func_call_count(__func__); } void BTM_db_reset(void) { inc_func_call_count(__func__); } void BTM_reset_complete() { inc_func_call_count(__func__); } -void btm_delete_stored_link_key_complete(uint8_t* p, - UNUSED_ATTR uint16_t evt_len) { +void btm_delete_stored_link_key_complete(uint8_t* /* p */, + uint16_t /* evt_len */) { inc_func_call_count(__func__); } void btm_dev_free() { inc_func_call_count(__func__); } void btm_dev_init() { inc_func_call_count(__func__); } -void btm_read_local_name_complete(uint8_t* p, UNUSED_ATTR uint16_t evt_len) { +void btm_read_local_name_complete(uint8_t* /* p */, uint16_t /* evt_len */) { inc_func_call_count(__func__); } -void btm_vendor_specific_evt(const uint8_t* p, uint8_t evt_len) { +void btm_vendor_specific_evt(const uint8_t* /* p */, uint8_t /* evt_len */) { inc_func_call_count(__func__); } -void btm_vsc_complete(uint8_t* p, uint16_t opcode, uint16_t evt_len, - tBTM_VSC_CMPL_CB* p_vsc_cplt_cback) { +void btm_vsc_complete(uint8_t* /* p */, uint16_t /* opcode */, + uint16_t /* evt_len */, + tBTM_VSC_CMPL_CB* /* p_vsc_cplt_cback */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_btm_devctl.h b/system/test/mock/mock_stack_btm_devctl.h index 433d47152b887f06926bd86ab319465fc1d4e8c5..142b7171b6cd0ed3abeb306d3b94a235033abe44 100644 --- a/system/test/mock/mock_stack_btm_devctl.h +++ b/system/test/mock/mock_stack_btm_devctl.h @@ -14,16 +14,7 @@ * limitations under the License. */ -#include -#include - -#include "stack/btm/btm_dev.h" -#include "stack/include/btm_api_types.h" -#include "stack/include/btm_status.h" -#include "test/common/mock_functions.h" -#include "types/bt_transport.h" -#include "types/raw_address.h" - +#include namespace test { namespace mock { namespace stack_btm_devctl { diff --git a/system/test/mock/mock_stack_btm_hfp_lc3_decoder.cc b/system/test/mock/mock_stack_btm_hfp_lc3_decoder.cc new file mode 100644 index 0000000000000000000000000000000000000000..22824453505000ff040b805f5a08417c9a7df1c1 --- /dev/null +++ b/system/test/mock/mock_stack_btm_hfp_lc3_decoder.cc @@ -0,0 +1,76 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Generated mock file from original source file + * Functions generated:3 + * + * mockcify.pl ver 0.5.0 + */ + +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_hfp_lc3_decoder.h" + +#include + +#include "hfp_lc3_decoder.h" +#include "test/common/mock_functions.h" + +// Original usings + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace stack_btm_hfp_lc3_decoder { + +// Function state capture and return values, if needed +struct hfp_lc3_decoder_cleanup hfp_lc3_decoder_cleanup; +struct hfp_lc3_decoder_decode_packet hfp_lc3_decoder_decode_packet; +struct hfp_lc3_decoder_init hfp_lc3_decoder_init; + +} // namespace stack_btm_hfp_lc3_decoder +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace stack_btm_hfp_lc3_decoder { + +bool hfp_lc3_decoder_decode_packet::return_value = false; +bool hfp_lc3_decoder_init::return_value = false; + +} // namespace stack_btm_hfp_lc3_decoder +} // namespace mock +} // namespace test + +// Mocked functions, if any +void hfp_lc3_decoder_cleanup(void) { + inc_func_call_count(__func__); + test::mock::stack_btm_hfp_lc3_decoder::hfp_lc3_decoder_cleanup(); +} +bool hfp_lc3_decoder_decode_packet(const uint8_t* i_buf, int16_t* o_buf, + size_t out_len) { + inc_func_call_count(__func__); + return test::mock::stack_btm_hfp_lc3_decoder::hfp_lc3_decoder_decode_packet( + i_buf, o_buf, out_len); +} +bool hfp_lc3_decoder_init() { + inc_func_call_count(__func__); + return test::mock::stack_btm_hfp_lc3_decoder::hfp_lc3_decoder_init(); +} +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_hfp_lc3_decoder.h b/system/test/mock/mock_stack_btm_hfp_lc3_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..96a8adf3caebfe9fa8387f44ddf8841ffafd18b7 --- /dev/null +++ b/system/test/mock/mock_stack_btm_hfp_lc3_decoder.h @@ -0,0 +1,78 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:3 + * + * mockcify.pl ver 0.5.0 + */ + +#include +#include + +// Original included files, if any +#include + +// Original usings + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace stack_btm_hfp_lc3_decoder { + +// Shared state between mocked functions and tests +// Name: hfp_lc3_decoder_cleanup +// Params: void +// Return: void +struct hfp_lc3_decoder_cleanup { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct hfp_lc3_decoder_cleanup hfp_lc3_decoder_cleanup; + +// Name: hfp_lc3_decoder_decode_packet +// Params: const uint8_t* i_buf, int16_t* o_buf, size_t out_len +// Return: bool +struct hfp_lc3_decoder_decode_packet { + static bool return_value; + std::function + body{[](const uint8_t* /* i_buf */, int16_t* /* o_buf */, + size_t /* out_len */) { return return_value; }}; + bool operator()(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) { + return body(i_buf, o_buf, out_len); + }; +}; +extern struct hfp_lc3_decoder_decode_packet hfp_lc3_decoder_decode_packet; + +// Name: hfp_lc3_decoder_init +// Params: +// Return: bool +struct hfp_lc3_decoder_init { + static bool return_value; + std::function body{[]() { return return_value; }}; + bool operator()() { return body(); }; +}; +extern struct hfp_lc3_decoder_init hfp_lc3_decoder_init; + +} // namespace stack_btm_hfp_lc3_decoder +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_hfp_lc3_encoder.cc b/system/test/mock/mock_stack_btm_hfp_lc3_encoder.cc new file mode 100644 index 0000000000000000000000000000000000000000..c074b4e2de6b4bf12fad1c246e3a8164b58a319d --- /dev/null +++ b/system/test/mock/mock_stack_btm_hfp_lc3_encoder.cc @@ -0,0 +1,75 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Generated mock file from original source file + * Functions generated:3 + * + * mockcify.pl ver 0.5.1 + */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_hfp_lc3_encoder.h" + +#include + +#ifndef __clang_analyzer__ + +#include "test/common/mock_functions.h" + +// Original usings + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace stack_btm_hfp_lc3_encoder { + +// Function state capture and return values, if needed +struct hfp_lc3_encode_frames hfp_lc3_encode_frames; +struct hfp_lc3_encoder_cleanup hfp_lc3_encoder_cleanup; +struct hfp_lc3_encoder_init hfp_lc3_encoder_init; + +} // namespace stack_btm_hfp_lc3_encoder +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace stack_btm_hfp_lc3_encoder { + +uint32_t hfp_lc3_encode_frames::return_value = 0; + +} // namespace stack_btm_hfp_lc3_encoder +} // namespace mock +} // namespace test + +// Mocked functions, if any +uint32_t hfp_lc3_encode_frames(int16_t* input, uint8_t* output) { + inc_func_call_count(__func__); + return test::mock::stack_btm_hfp_lc3_encoder::hfp_lc3_encode_frames(input, + output); +} +void hfp_lc3_encoder_cleanup(void) { + inc_func_call_count(__func__); + test::mock::stack_btm_hfp_lc3_encoder::hfp_lc3_encoder_cleanup(); +} +void hfp_lc3_encoder_init(void) { + inc_func_call_count(__func__); + test::mock::stack_btm_hfp_lc3_encoder::hfp_lc3_encoder_init(); +} +// Mocked functions complete +#endif // __clang_analyzer__ +// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_hfp_lc3_encoder.h b/system/test/mock/mock_stack_btm_hfp_lc3_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..e20383e8ea5ae5c969abcf2e3c1401d1c946329c --- /dev/null +++ b/system/test/mock/mock_stack_btm_hfp_lc3_encoder.h @@ -0,0 +1,74 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:3 + * + * mockcify.pl ver 0.5.1 + */ + +#include +#include + +// Original included files, if any + +// Original usings + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace stack_btm_hfp_lc3_encoder { + +// Shared state between mocked functions and tests +// Name: hfp_lc3_encode_frames +// Params: int16_t* input, uint8_t* output +// Return: uint32_t +struct hfp_lc3_encode_frames { + static uint32_t return_value; + std::function body{ + [](int16_t* /* input */, uint8_t* /* output */) { return return_value; }}; + uint32_t operator()(int16_t* input, uint8_t* output) { + return body(input, output); + }; +}; +extern struct hfp_lc3_encode_frames hfp_lc3_encode_frames; + +// Name: hfp_lc3_encoder_cleanup +// Params: void +// Return: void +struct hfp_lc3_encoder_cleanup { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct hfp_lc3_encoder_cleanup hfp_lc3_encoder_cleanup; + +// Name: hfp_lc3_encoder_init +// Params: void +// Return: void +struct hfp_lc3_encoder_init { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct hfp_lc3_encoder_init hfp_lc3_encoder_init; + +} // namespace stack_btm_hfp_lc3_encoder +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_hfp_msbc_decoder.cc b/system/test/mock/mock_stack_btm_hfp_msbc_decoder.cc index 25a0975b6b15523a5e7265f68d89775829581ed2..7d5520e91c3f0179d1614a32cda68f19700ebe9e 100644 --- a/system/test/mock/mock_stack_btm_hfp_msbc_decoder.cc +++ b/system/test/mock/mock_stack_btm_hfp_msbc_decoder.cc @@ -19,14 +19,12 @@ * * mockcify.pl ver 0.5.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_hfp_msbc_decoder.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_btm_hfp_msbc_decoder.h" +#include "test/common/mock_functions.h" // Original usings diff --git a/system/test/mock/mock_stack_btm_hfp_msbc_decoder.h b/system/test/mock/mock_stack_btm_hfp_msbc_decoder.h index 36c0414c46b562950e190aceb144c6119cb6746c..c9ecdf24fbf134e1c84e081b376a15d4bf4839d2 100644 --- a/system/test/mock/mock_stack_btm_hfp_msbc_decoder.h +++ b/system/test/mock/mock_stack_btm_hfp_msbc_decoder.h @@ -24,25 +24,12 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include #include -#include "embdrv/sbc/decoder/include/oi_codec_sbc.h" -#include "embdrv/sbc/decoder/include/oi_status.h" -#include "hfp_msbc_decoder.h" -#include "osi/include/log.h" -#include "test/common/mock_functions.h" - // Original usings // Mocked compile conditionals, if any @@ -67,9 +54,8 @@ extern struct hfp_msbc_decoder_cleanup hfp_msbc_decoder_cleanup; struct hfp_msbc_decoder_decode_packet { static bool return_value; std::function - body{[](const uint8_t* i_buf, int16_t* o_buf, size_t out_len) { - return return_value; - }}; + body{[](const uint8_t* /* i_buf */, int16_t* /* o_buf */, + size_t /* out_len */) { return return_value; }}; bool operator()(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) { return body(i_buf, o_buf, out_len); }; @@ -90,4 +76,4 @@ extern struct hfp_msbc_decoder_init hfp_msbc_decoder_init; } // namespace mock } // namespace test -// END mockcify generation \ No newline at end of file +// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_hfp_msbc_encoder.cc b/system/test/mock/mock_stack_btm_hfp_msbc_encoder.cc index 4d6079127899c9145bc4ea26dc77a06663806712..6fab1ce130ee5eafe01976726aa436a1352d20b9 100644 --- a/system/test/mock/mock_stack_btm_hfp_msbc_encoder.cc +++ b/system/test/mock/mock_stack_btm_hfp_msbc_encoder.cc @@ -20,14 +20,14 @@ * mockcify.pl ver 0.5.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_hfp_msbc_encoder.h" + #include -#include -#include -#include #ifndef __clang_analyzer__ -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_btm_hfp_msbc_encoder.h" + +#include "test/common/mock_functions.h" // Original usings diff --git a/system/test/mock/mock_stack_btm_hfp_msbc_encoder.h b/system/test/mock/mock_stack_btm_hfp_msbc_encoder.h index adb21dbba91e0d4c2084c71e1dbb94b4ccfb778a..6412cdaec623b75da194eded08699fd1a85f2bd2 100644 --- a/system/test/mock/mock_stack_btm_hfp_msbc_encoder.h +++ b/system/test/mock/mock_stack_btm_hfp_msbc_encoder.h @@ -24,21 +24,8 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include - -#include "embdrv/sbc/encoder/include/sbc_encoder.h" -#include "hfp_msbc_encoder.h" -#include "osi/include/log.h" -#include "test/common/mock_functions.h" // Original usings @@ -55,7 +42,7 @@ namespace stack_btm_hfp_msbc_encoder { struct hfp_msbc_encode_frames { static uint32_t return_value; std::function body{ - [](int16_t* input, uint8_t* output) { return return_value; }}; + [](int16_t* /* input */, uint8_t* /* output */) { return return_value; }}; uint32_t operator()(int16_t* input, uint8_t* output) { return body(input, output); }; @@ -84,4 +71,4 @@ extern struct hfp_msbc_encoder_init hfp_msbc_encoder_init; } // namespace mock } // namespace test -// END mockcify generation \ No newline at end of file +// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_inq.cc b/system/test/mock/mock_stack_btm_inq.cc index f782f59fd8c4f215695c1b33bb9c4dfa62af8cf0..8ff677f2abd0a5e4e9c5b6e0e3f59faf9a3d216b 100644 --- a/system/test/mock/mock_stack_btm_inq.cc +++ b/system/test/mock/mock_stack_btm_inq.cc @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,170 +13,276 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* * Generated mock file from original source file - * Functions generated:44 + * Functions generated:43 + * + * mockcify.pl ver 0.6.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_inq.h" -#include -#include -#include -#include - -#include -#include +#include -#include "advertise_data_parser.h" -#include "btm_api.h" -#include "common/time_util.h" -#include "device/include/controller.h" -#include "main/shim/btm_api.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_int_types.h" -#include "stack/include/acl_api.h" -#include "stack/include/bt_hdr.h" -#include "stack/include/btm_ble_api.h" -#include "stack/include/inq_hci_link_interface.h" #include "test/common/mock_functions.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +// Original usings -void SendRemoteNameRequest(const RawAddress& raw_address) { +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace stack_btm_inq { + +// Function state capture and return values, if needed +struct BTM_AddEirService BTM_AddEirService; +struct BTM_CancelInquiry BTM_CancelInquiry; +struct BTM_CancelRemoteDeviceName BTM_CancelRemoteDeviceName; +struct BTM_ClearInqDb BTM_ClearInqDb; +struct BTM_EnableInterlacedInquiryScan BTM_EnableInterlacedInquiryScan; +struct BTM_EnableInterlacedPageScan BTM_EnableInterlacedPageScan; +struct BTM_GetEirSupportedServices BTM_GetEirSupportedServices; +struct BTM_GetEirUuidList BTM_GetEirUuidList; +struct BTM_HasEirService BTM_HasEirService; +struct BTM_InqDbFirst BTM_InqDbFirst; +struct BTM_InqDbNext BTM_InqDbNext; +struct BTM_InqDbRead BTM_InqDbRead; +struct BTM_IsInquiryActive BTM_IsInquiryActive; +struct BTM_ReadRemoteDeviceName BTM_ReadRemoteDeviceName; +struct BTM_RemoveEirService BTM_RemoveEirService; +struct BTM_SetConnectability BTM_SetConnectability; +struct BTM_SetDiscoverability BTM_SetDiscoverability; +struct BTM_SetInquiryMode BTM_SetInquiryMode; +struct BTM_StartInquiry BTM_StartInquiry; +struct BTM_WriteEIR BTM_WriteEIR; +struct SendRemoteNameRequest SendRemoteNameRequest; +struct btm_clear_all_pending_le_entry btm_clear_all_pending_le_entry; +struct btm_clr_inq_db btm_clr_inq_db; +struct btm_clr_inq_result_flt btm_clr_inq_result_flt; +struct btm_inq_clear_ssp btm_inq_clear_ssp; +struct btm_inq_db_find btm_inq_db_find; +struct btm_inq_db_free btm_inq_db_free; +struct btm_inq_db_init btm_inq_db_init; +struct btm_inq_db_new btm_inq_db_new; +struct btm_inq_db_reset btm_inq_db_reset; +struct btm_inq_find_bdaddr btm_inq_find_bdaddr; +struct btm_inq_remote_name_timer_timeout btm_inq_remote_name_timer_timeout; +struct btm_inq_rmt_name_failed_cancelled btm_inq_rmt_name_failed_cancelled; +struct btm_inq_stop_on_ssp btm_inq_stop_on_ssp; +struct btm_process_cancel_complete btm_process_cancel_complete; +struct btm_process_inq_complete btm_process_inq_complete; +struct btm_process_inq_results btm_process_inq_results; +struct btm_process_remote_name btm_process_remote_name; +struct btm_set_eir_uuid btm_set_eir_uuid; +struct btm_sort_inq_result btm_sort_inq_result; + +} // namespace stack_btm_inq +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace stack_btm_inq { + +tBTM_STATUS BTM_CancelRemoteDeviceName::return_value = 0; +tBTM_STATUS BTM_ClearInqDb::return_value = 0; +uint8_t BTM_GetEirSupportedServices::return_value = 0; +uint8_t BTM_GetEirUuidList::return_value = 0; +bool BTM_HasEirService::return_value = false; +tBTM_INQ_INFO* BTM_InqDbFirst::return_value = nullptr; +tBTM_INQ_INFO* BTM_InqDbNext::return_value = nullptr; +tBTM_INQ_INFO* BTM_InqDbRead::return_value = nullptr; +uint16_t BTM_IsInquiryActive::return_value = 0; +tBTM_STATUS BTM_ReadRemoteDeviceName::return_value = 0; +tBTM_STATUS BTM_SetConnectability::return_value = 0; +tBTM_STATUS BTM_SetDiscoverability::return_value = 0; +tBTM_STATUS BTM_SetInquiryMode::return_value = 0; +tBTM_STATUS BTM_StartInquiry::return_value = 0; +tBTM_STATUS BTM_WriteEIR::return_value = 0; +tINQ_DB_ENT* btm_inq_db_find::return_value = nullptr; +tINQ_DB_ENT* btm_inq_db_new::return_value = nullptr; +bool btm_inq_find_bdaddr::return_value = false; + +} // namespace stack_btm_inq +} // namespace mock +} // namespace test + +// Mocked functions, if any +void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) { inc_func_call_count(__func__); + test::mock::stack_btm_inq::BTM_AddEirService(p_eir_uuid, uuid16); } -bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16) { +void BTM_CancelInquiry(void) { inc_func_call_count(__func__); - return false; + test::mock::stack_btm_inq::BTM_CancelInquiry(); } -bool btm_inq_find_bdaddr(const RawAddress& p_bda) { +tBTM_STATUS BTM_CancelRemoteDeviceName(void) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_inq::BTM_CancelRemoteDeviceName(); } -tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS* p_results, - uint16_t uuid16) { +tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda) { + inc_func_call_count(__func__); + return test::mock::stack_btm_inq::BTM_ClearInqDb(p_bda); +} +void BTM_EnableInterlacedInquiryScan() { + inc_func_call_count(__func__); + test::mock::stack_btm_inq::BTM_EnableInterlacedInquiryScan(); +} +void BTM_EnableInterlacedPageScan() { + inc_func_call_count(__func__); + test::mock::stack_btm_inq::BTM_EnableInterlacedPageScan(); +} +uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p, + uint8_t max_num_uuid16, + uint8_t* p_num_uuid16) { + inc_func_call_count(__func__); + return test::mock::stack_btm_inq::BTM_GetEirSupportedServices( + p_eir_uuid, p, max_num_uuid16, p_num_uuid16); +} +uint8_t BTM_GetEirUuidList(const uint8_t* p_eir, size_t eir_len, + uint8_t uuid_size, uint8_t* p_num_uuid, + uint8_t* p_uuid_list, uint8_t max_num_uuid) { + inc_func_call_count(__func__); + return test::mock::stack_btm_inq::BTM_GetEirUuidList( + p_eir, eir_len, uuid_size, p_num_uuid, p_uuid_list, max_num_uuid); +} +bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16) { inc_func_call_count(__func__); - return 0; + return test::mock::stack_btm_inq::BTM_HasEirService(p_eir_uuid, uuid16); } tBTM_INQ_INFO* BTM_InqDbFirst(void) { inc_func_call_count(__func__); - return nullptr; + return test::mock::stack_btm_inq::BTM_InqDbFirst(); } tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur) { inc_func_call_count(__func__); - return nullptr; + return test::mock::stack_btm_inq::BTM_InqDbNext(p_cur); } tBTM_INQ_INFO* BTM_InqDbRead(const RawAddress& p_bda) { inc_func_call_count(__func__); - return nullptr; + return test::mock::stack_btm_inq::BTM_InqDbRead(p_bda); } -tBTM_STATUS BTM_CancelRemoteDeviceName(void) { - inc_func_call_count(__func__); - return BTM_SUCCESS; -} -tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda) { +uint16_t BTM_IsInquiryActive(void) { inc_func_call_count(__func__); - return BTM_SUCCESS; + return test::mock::stack_btm_inq::BTM_IsInquiryActive(); } + tBTM_STATUS BTM_ReadRemoteDeviceName(const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb, tBT_TRANSPORT transport) { inc_func_call_count(__func__); - return BTM_SUCCESS; + return test::mock::stack_btm_inq::BTM_ReadRemoteDeviceName(remote_bda, p_cb, + transport); +} +void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16) { + inc_func_call_count(__func__); + test::mock::stack_btm_inq::BTM_RemoveEirService(p_eir_uuid, uuid16); } tBTM_STATUS BTM_SetConnectability(uint16_t page_mode) { inc_func_call_count(__func__); - return BTM_SUCCESS; + return test::mock::stack_btm_inq::BTM_SetConnectability(page_mode); } tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode) { inc_func_call_count(__func__); - return BTM_SUCCESS; + return test::mock::stack_btm_inq::BTM_SetDiscoverability(inq_mode); } tBTM_STATUS BTM_SetInquiryMode(uint8_t mode) { inc_func_call_count(__func__); - return BTM_SUCCESS; + return test::mock::stack_btm_inq::BTM_SetInquiryMode(mode); } tBTM_STATUS BTM_StartInquiry(tBTM_INQ_RESULTS_CB* p_results_cb, tBTM_CMPL_CB* p_cmpl_cb) { inc_func_call_count(__func__); - return BTM_SUCCESS; + return test::mock::stack_btm_inq::BTM_StartInquiry(p_results_cb, p_cmpl_cb); +} +tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff) { + inc_func_call_count(__func__); + return test::mock::stack_btm_inq::BTM_WriteEIR(p_buff); +} +void SendRemoteNameRequest(const RawAddress& raw_address) { + inc_func_call_count(__func__); + test::mock::stack_btm_inq::SendRemoteNameRequest(raw_address); +} +void btm_clear_all_pending_le_entry(void) { + inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_clear_all_pending_le_entry(); +} +void btm_clr_inq_db(const RawAddress* p_bda) { + inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_clr_inq_db(p_bda); } -tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda, uint8_t origin, - uint64_t timeout_ms, tBTM_CMPL_CB* p_cb) { +void btm_clr_inq_result_flt(void) { inc_func_call_count(__func__); - return BTM_SUCCESS; + test::mock::stack_btm_inq::btm_clr_inq_result_flt(); +} +void btm_inq_clear_ssp(void) { + inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_inq_clear_ssp(); } tINQ_DB_ENT* btm_inq_db_find(const RawAddress& p_bda) { inc_func_call_count(__func__); - return nullptr; + return test::mock::stack_btm_inq::btm_inq_db_find(p_bda); } -tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda) { +void btm_inq_db_free(void) { inc_func_call_count(__func__); - return nullptr; + test::mock::stack_btm_inq::btm_inq_db_free(); } -uint16_t BTM_IsInquiryActive(void) { +void btm_inq_db_init(void) { inc_func_call_count(__func__); - return 0; + test::mock::stack_btm_inq::btm_inq_db_init(); } -uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p, - uint8_t max_num_uuid16, - uint8_t* p_num_uuid16) { +tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda, bool is_ble) { inc_func_call_count(__func__); - return 0; + return test::mock::stack_btm_inq::btm_inq_db_new(p_bda, is_ble); } -uint8_t BTM_GetEirUuidList(const uint8_t* p_eir, size_t eir_len, - uint8_t uuid_size, uint8_t* p_num_uuid, - uint8_t* p_uuid_list, uint8_t max_num_uuid) { +void btm_inq_db_reset(void) { inc_func_call_count(__func__); - return 0; + test::mock::stack_btm_inq::btm_inq_db_reset(); } -void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) { +bool btm_inq_find_bdaddr(const RawAddress& p_bda) { + inc_func_call_count(__func__); + return test::mock::stack_btm_inq::btm_inq_find_bdaddr(p_bda); +} +void btm_inq_remote_name_timer_timeout(void* data) { + inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_inq_remote_name_timer_timeout(data); +} +void btm_inq_rmt_name_failed_cancelled(void) { inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_inq_rmt_name_failed_cancelled(); } -void BTM_CancelInquiry(void) { inc_func_call_count(__func__); } -void BTM_EnableInterlacedInquiryScan() { inc_func_call_count(__func__); } -void BTM_EnableInterlacedPageScan() { inc_func_call_count(__func__); } -void btm_clr_inq_db(const RawAddress* p_bda) { inc_func_call_count(__func__); } -void btm_clr_inq_result_flt(void) { inc_func_call_count(__func__); } -void btm_inq_clear_ssp(void) { inc_func_call_count(__func__); } -void btm_inq_db_free(void) { inc_func_call_count(__func__); } -void btm_inq_db_init(void) { inc_func_call_count(__func__); } -void btm_inq_db_reset(void) { inc_func_call_count(__func__); } -void btm_inq_remote_name_timer_timeout(UNUSED_ATTR void* data) { +void btm_inq_stop_on_ssp(void) { inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_inq_stop_on_ssp(); } -void btm_inq_rmt_name_failed_cancelled(void) { inc_func_call_count(__func__); } -void btm_inq_stop_on_ssp(void) { inc_func_call_count(__func__); } void btm_process_cancel_complete(tHCI_STATUS status, uint8_t mode) { inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_process_cancel_complete(status, mode); } void btm_process_inq_complete(tHCI_STATUS status, uint8_t mode) { inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_process_inq_complete(status, mode); } void btm_process_inq_results(const uint8_t* p, uint8_t hci_evt_len, uint8_t inq_res_mode) { inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_process_inq_results(p, hci_evt_len, + inq_res_mode); } void btm_process_remote_name(const RawAddress* bda, const BD_NAME bdn, uint16_t evt_len, tHCI_STATUS hci_status) { inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_process_remote_name(bda, bdn, evt_len, + hci_status); } void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) { inc_func_call_count(__func__); + test::mock::stack_btm_inq::btm_set_eir_uuid(p_eir, p_results); } -void btm_sort_inq_result(void) { inc_func_call_count(__func__); } -bool BTM_IsRemoteNameKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) { +void btm_sort_inq_result(void) { inc_func_call_count(__func__); - return false; + test::mock::stack_btm_inq::btm_sort_inq_result(); } -void btm_clear_all_pending_le_entry(void) { inc_func_call_count(__func__); } - // Mocked functions complete // END mockcify generation diff --git a/system/test/mock/mock_stack_btm_inq.h b/system/test/mock/mock_stack_btm_inq.h new file mode 100644 index 0000000000000000000000000000000000000000..c9f2411eaaaf5f77df2ce53e8d21c024db80a231 --- /dev/null +++ b/system/test/mock/mock_stack_btm_inq.h @@ -0,0 +1,505 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +/* + * Generated mock file from original source file + * Functions generated:43 + * + * mockcify.pl ver 0.6.0 + */ + +#include +#include + +// Original included files, if any +#include +#include +#include +#include +#include + +#include "stack/btm/neighbor_inquiry.h" +#include "stack/include/bt_hdr.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" + +// Original usings +using bluetooth::Uuid; + +// Mocked compile conditionals, if any + +namespace test { +namespace mock { +namespace stack_btm_inq { + +// Shared state between mocked functions and tests +// Name: BTM_AddEirService +// Params: uint32_t* p_eir_uuid, uint16_t uuid16 +// Return: void +struct BTM_AddEirService { + std::function body{ + [](uint32_t* /* p_eir_uuid */, uint16_t /* uuid16 */) {}}; + void operator()(uint32_t* p_eir_uuid, uint16_t uuid16) { + body(p_eir_uuid, uuid16); + }; +}; +extern struct BTM_AddEirService BTM_AddEirService; + +// Name: BTM_CancelInquiry +// Params: void +// Return: void +struct BTM_CancelInquiry { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct BTM_CancelInquiry BTM_CancelInquiry; + +// Name: BTM_CancelRemoteDeviceName +// Params: void +// Return: tBTM_STATUS +struct BTM_CancelRemoteDeviceName { + static tBTM_STATUS return_value; + std::function body{[](void) { return return_value; }}; + tBTM_STATUS operator()(void) { return body(); }; +}; +extern struct BTM_CancelRemoteDeviceName BTM_CancelRemoteDeviceName; + +// Name: BTM_ClearInqDb +// Params: const RawAddress* p_bda +// Return: tBTM_STATUS +struct BTM_ClearInqDb { + static tBTM_STATUS return_value; + std::function body{ + [](const RawAddress* /* p_bda */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress* p_bda) { return body(p_bda); }; +}; +extern struct BTM_ClearInqDb BTM_ClearInqDb; + +// Name: BTM_EnableInterlacedInquiryScan +// Params: +// Return: void +struct BTM_EnableInterlacedInquiryScan { + std::function body{[]() {}}; + void operator()() { body(); }; +}; +extern struct BTM_EnableInterlacedInquiryScan BTM_EnableInterlacedInquiryScan; + +// Name: BTM_EnableInterlacedPageScan +// Params: +// Return: void +struct BTM_EnableInterlacedPageScan { + std::function body{[]() {}}; + void operator()() { body(); }; +}; +extern struct BTM_EnableInterlacedPageScan BTM_EnableInterlacedPageScan; + +// Name: BTM_GetEirSupportedServices +// Params: uint32_t* p_eir_uuid, uint8_t** p, uint8_t max_num_uuid16, uint8_t* +// p_num_uuid16 Return: uint8_t +struct BTM_GetEirSupportedServices { + static uint8_t return_value; + std::function + body{[](uint32_t* /* p_eir_uuid */, uint8_t** /* p */, + uint8_t /* max_num_uuid16 */, + uint8_t* /* p_num_uuid16 */) { return return_value; }}; + uint8_t operator()(uint32_t* p_eir_uuid, uint8_t** p, uint8_t max_num_uuid16, + uint8_t* p_num_uuid16) { + return body(p_eir_uuid, p, max_num_uuid16, p_num_uuid16); + }; +}; +extern struct BTM_GetEirSupportedServices BTM_GetEirSupportedServices; + +// Name: BTM_GetEirUuidList +// Params: const uint8_t* p_eir, size_t eir_len, uint8_t uuid_size, uint8_t* +// p_num_uuid, uint8_t* p_uuid_list, uint8_t max_num_uuid Return: uint8_t +struct BTM_GetEirUuidList { + static uint8_t return_value; + std::function + body{[](const uint8_t* /* p_eir */, size_t /* eir_len */, + uint8_t /* uuid_size */, uint8_t* /* p_num_uuid */, + uint8_t* /* p_uuid_list */, + uint8_t /* max_num_uuid */) { return return_value; }}; + uint8_t operator()(const uint8_t* p_eir, size_t eir_len, uint8_t uuid_size, + uint8_t* p_num_uuid, uint8_t* p_uuid_list, + uint8_t max_num_uuid) { + return body(p_eir, eir_len, uuid_size, p_num_uuid, p_uuid_list, + max_num_uuid); + }; +}; +extern struct BTM_GetEirUuidList BTM_GetEirUuidList; + +// Name: BTM_HasEirService +// Params: const uint32_t* p_eir_uuid, uint16_t uuid16 +// Return: bool +struct BTM_HasEirService { + static bool return_value; + std::function body{ + [](const uint32_t* /* p_eir_uuid */, uint16_t /* uuid16 */) { + return return_value; + }}; + bool operator()(const uint32_t* p_eir_uuid, uint16_t uuid16) { + return body(p_eir_uuid, uuid16); + }; +}; +extern struct BTM_HasEirService BTM_HasEirService; + +// Name: BTM_InqDbFirst +// Params: void +// Return: tBTM_INQ_INFO* +struct BTM_InqDbFirst { + static tBTM_INQ_INFO* return_value; + std::function body{[](void) { return return_value; }}; + tBTM_INQ_INFO* operator()(void) { return body(); }; +}; +extern struct BTM_InqDbFirst BTM_InqDbFirst; + +// Name: BTM_InqDbNext +// Params: tBTM_INQ_INFO* p_cur +// Return: tBTM_INQ_INFO* +struct BTM_InqDbNext { + static tBTM_INQ_INFO* return_value; + std::function body{ + [](tBTM_INQ_INFO* /* p_cur */) { return return_value; }}; + tBTM_INQ_INFO* operator()(tBTM_INQ_INFO* p_cur) { return body(p_cur); }; +}; +extern struct BTM_InqDbNext BTM_InqDbNext; + +// Name: BTM_InqDbRead +// Params: const RawAddress& p_bda +// Return: tBTM_INQ_INFO* +struct BTM_InqDbRead { + static tBTM_INQ_INFO* return_value; + std::function body{ + [](const RawAddress& /* p_bda */) { return return_value; }}; + tBTM_INQ_INFO* operator()(const RawAddress& p_bda) { return body(p_bda); }; +}; +extern struct BTM_InqDbRead BTM_InqDbRead; + +// Name: BTM_IsInquiryActive +// Params: void +// Return: uint16_t +struct BTM_IsInquiryActive { + static uint16_t return_value; + std::function body{[](void) { return return_value; }}; + uint16_t operator()(void) { return body(); }; +}; +extern struct BTM_IsInquiryActive BTM_IsInquiryActive; + +// Name: BTM_ReadRemoteDeviceName +// Params: const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb, tBT_TRANSPORT +// transport Return: tBTM_STATUS +struct BTM_ReadRemoteDeviceName { + static tBTM_STATUS return_value; + std::function + body{[](const RawAddress& /* remote_bda */, tBTM_NAME_CMPL_CB* /* p_cb */, + tBT_TRANSPORT /* transport */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb, + tBT_TRANSPORT transport) { + return body(remote_bda, p_cb, transport); + }; +}; +extern struct BTM_ReadRemoteDeviceName BTM_ReadRemoteDeviceName; + +// Name: BTM_RemoveEirService +// Params: uint32_t* p_eir_uuid, uint16_t uuid16 +// Return: void +struct BTM_RemoveEirService { + std::function body{ + [](uint32_t* /* p_eir_uuid */, uint16_t /* uuid16 */) {}}; + void operator()(uint32_t* p_eir_uuid, uint16_t uuid16) { + body(p_eir_uuid, uuid16); + }; +}; +extern struct BTM_RemoveEirService BTM_RemoveEirService; + +// Name: BTM_SetConnectability +// Params: uint16_t page_mode +// Return: tBTM_STATUS +struct BTM_SetConnectability { + static tBTM_STATUS return_value; + std::function body{ + [](uint16_t /* page_mode */) { return return_value; }}; + tBTM_STATUS operator()(uint16_t page_mode) { return body(page_mode); }; +}; +extern struct BTM_SetConnectability BTM_SetConnectability; + +// Name: BTM_SetDiscoverability +// Params: uint16_t inq_mode +// Return: tBTM_STATUS +struct BTM_SetDiscoverability { + static tBTM_STATUS return_value; + std::function body{ + [](uint16_t /* inq_mode */) { return return_value; }}; + tBTM_STATUS operator()(uint16_t inq_mode) { return body(inq_mode); }; +}; +extern struct BTM_SetDiscoverability BTM_SetDiscoverability; + +// Name: BTM_SetInquiryMode +// Params: uint8_t mode +// Return: tBTM_STATUS +struct BTM_SetInquiryMode { + static tBTM_STATUS return_value; + std::function body{ + [](uint8_t /* mode */) { return return_value; }}; + tBTM_STATUS operator()(uint8_t mode) { return body(mode); }; +}; +extern struct BTM_SetInquiryMode BTM_SetInquiryMode; + +// Name: BTM_StartInquiry +// Params: tBTM_INQ_RESULTS_CB* p_results_cb, tBTM_CMPL_CB* p_cmpl_cb +// Return: tBTM_STATUS +struct BTM_StartInquiry { + static tBTM_STATUS return_value; + std::function + body{[](tBTM_INQ_RESULTS_CB* /* p_results_cb */, + tBTM_CMPL_CB* /* p_cmpl_cb */) { return return_value; }}; + tBTM_STATUS operator()(tBTM_INQ_RESULTS_CB* p_results_cb, + tBTM_CMPL_CB* p_cmpl_cb) { + return body(p_results_cb, p_cmpl_cb); + }; +}; +extern struct BTM_StartInquiry BTM_StartInquiry; + +// Name: BTM_WriteEIR +// Params: BT_HDR* p_buff +// Return: tBTM_STATUS +struct BTM_WriteEIR { + static tBTM_STATUS return_value; + std::function body{ + [](BT_HDR* /* p_buff */) { return return_value; }}; + tBTM_STATUS operator()(BT_HDR* p_buff) { return body(p_buff); }; +}; +extern struct BTM_WriteEIR BTM_WriteEIR; + +// Name: SendRemoteNameRequest +// Params: const RawAddress& raw_address +// Return: void +struct SendRemoteNameRequest { + std::function body{ + [](const RawAddress& /* raw_address */) {}}; + void operator()(const RawAddress& raw_address) { body(raw_address); }; +}; +extern struct SendRemoteNameRequest SendRemoteNameRequest; + +// Name: btm_clear_all_pending_le_entry +// Params: void +// Return: void +struct btm_clear_all_pending_le_entry { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_clear_all_pending_le_entry btm_clear_all_pending_le_entry; + +// Name: btm_clr_inq_db +// Params: const RawAddress* p_bda +// Return: void +struct btm_clr_inq_db { + std::function body{ + [](const RawAddress* /* p_bda */) {}}; + void operator()(const RawAddress* p_bda) { body(p_bda); }; +}; +extern struct btm_clr_inq_db btm_clr_inq_db; + +// Name: btm_clr_inq_result_flt +// Params: void +// Return: void +struct btm_clr_inq_result_flt { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_clr_inq_result_flt btm_clr_inq_result_flt; + +// Name: btm_inq_clear_ssp +// Params: void +// Return: void +struct btm_inq_clear_ssp { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_inq_clear_ssp btm_inq_clear_ssp; + +// Name: btm_inq_db_find +// Params: const RawAddress& p_bda +// Return: tINQ_DB_ENT* +struct btm_inq_db_find { + static tINQ_DB_ENT* return_value; + std::function body{ + [](const RawAddress& /* p_bda */) { return return_value; }}; + tINQ_DB_ENT* operator()(const RawAddress& p_bda) { return body(p_bda); }; +}; +extern struct btm_inq_db_find btm_inq_db_find; + +// Name: btm_inq_db_free +// Params: void +// Return: void +struct btm_inq_db_free { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_inq_db_free btm_inq_db_free; + +// Name: btm_inq_db_init +// Params: void +// Return: void +struct btm_inq_db_init { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_inq_db_init btm_inq_db_init; + +// Name: btm_inq_db_new +// Params: const RawAddress& p_bda +// Return: tINQ_DB_ENT* +struct btm_inq_db_new { + static tINQ_DB_ENT* return_value; + std::function body{ + [](const RawAddress& /* p_bda */, bool /* is_ble */) { + return return_value; + }}; + tINQ_DB_ENT* operator()(const RawAddress& p_bda, bool is_ble) { return body(p_bda, is_ble); }; +}; +extern struct btm_inq_db_new btm_inq_db_new; + +// Name: btm_inq_db_reset +// Params: void +// Return: void +struct btm_inq_db_reset { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_inq_db_reset btm_inq_db_reset; + +// Name: btm_inq_find_bdaddr +// Params: const RawAddress& p_bda +// Return: bool +struct btm_inq_find_bdaddr { + static bool return_value; + std::function body{ + [](const RawAddress& /* p_bda */) { return return_value; }}; + bool operator()(const RawAddress& p_bda) { return body(p_bda); }; +}; +extern struct btm_inq_find_bdaddr btm_inq_find_bdaddr; + +// Name: btm_inq_remote_name_timer_timeout +// Params: void* data +// Return: void +struct btm_inq_remote_name_timer_timeout { + std::function body{[](void* /* data */) {}}; + void operator()(void* data) { body(data); }; +}; +extern struct btm_inq_remote_name_timer_timeout + btm_inq_remote_name_timer_timeout; + +// Name: btm_inq_rmt_name_failed_cancelled +// Params: void +// Return: void +struct btm_inq_rmt_name_failed_cancelled { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_inq_rmt_name_failed_cancelled + btm_inq_rmt_name_failed_cancelled; + +// Name: btm_inq_stop_on_ssp +// Params: void +// Return: void +struct btm_inq_stop_on_ssp { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_inq_stop_on_ssp btm_inq_stop_on_ssp; + +// Name: btm_process_cancel_complete +// Params: tHCI_STATUS status, uint8_t mode +// Return: void +struct btm_process_cancel_complete { + std::function body{ + [](tHCI_STATUS /* status */, uint8_t /* mode */) {}}; + void operator()(tHCI_STATUS status, uint8_t mode) { body(status, mode); }; +}; +extern struct btm_process_cancel_complete btm_process_cancel_complete; + +// Name: btm_process_inq_complete +// Params: tHCI_STATUS status, uint8_t mode +// Return: void +struct btm_process_inq_complete { + std::function body{ + [](tHCI_STATUS /* status */, uint8_t /* mode */) {}}; + void operator()(tHCI_STATUS status, uint8_t mode) { body(status, mode); }; +}; +extern struct btm_process_inq_complete btm_process_inq_complete; + +// Name: btm_process_inq_results +// Params: const uint8_t* p, uint8_t hci_evt_len, uint8_t inq_res_mode +// Return: void +struct btm_process_inq_results { + std::function + body{[](const uint8_t* /* p */, uint8_t /* hci_evt_len */, + uint8_t /* inq_res_mode */) {}}; + void operator()(const uint8_t* p, uint8_t hci_evt_len, uint8_t inq_res_mode) { + body(p, hci_evt_len, inq_res_mode); + }; +}; +extern struct btm_process_inq_results btm_process_inq_results; + +// Name: btm_process_remote_name +// Params: const RawAddress* bda, const BD_NAME bdn, uint16_t evt_len, +// tHCI_STATUS hci_status Return: void +struct btm_process_remote_name { + std::function + body{[](const RawAddress* /* bda */, const BD_NAME /* bdn */, + uint16_t /* evt_len */, tHCI_STATUS /* hci_status */) {}}; + void operator()(const RawAddress* bda, const BD_NAME bdn, uint16_t evt_len, + tHCI_STATUS hci_status) { + body(bda, bdn, evt_len, hci_status); + }; +}; +extern struct btm_process_remote_name btm_process_remote_name; + +// Name: btm_set_eir_uuid +// Params: const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results +// Return: void +struct btm_set_eir_uuid { + std::function body{ + [](const uint8_t* /* p_eir */, tBTM_INQ_RESULTS* /* p_results */) {}}; + void operator()(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) { + body(p_eir, p_results); + }; +}; +extern struct btm_set_eir_uuid btm_set_eir_uuid; + +// Name: btm_sort_inq_result +// Params: void +// Return: void +struct btm_sort_inq_result { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_sort_inq_result btm_sort_inq_result; + +} // namespace stack_btm_inq +} // namespace mock +} // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_interface.cc b/system/test/mock/mock_stack_btm_interface.cc new file mode 100644 index 0000000000000000000000000000000000000000..323d891bda2bada33341629ef5fe1ddb2c340435 --- /dev/null +++ b/system/test/mock/mock_stack_btm_interface.cc @@ -0,0 +1,288 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Generated mock file from original source file + */ + +#include "stack/include/btm_api.h" +#include "stack/include/btm_ble_api_types.h" +#include "stack/include/btm_ble_sec_api_types.h" +#include "stack/include/btm_client_interface.h" +#include "stack/include/btm_sec_api.h" +#include "stack/include/btm_sec_api_types.h" +#include "types/raw_address.h" + +// Test accessible feature page +uint8_t hci_feature_bytes_per_page[HCI_FEATURE_BYTES_PER_PAGE] = {}; + +namespace { + +struct btm_client_interface_t default_btm_client_interface = { + .lifecycle = { + .BTM_PmRegister = [](uint8_t /* mask */, uint8_t* /* p_pm_id */, + tBTM_PM_STATUS_CBACK* /* p_cb */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_GetHCIConnHandle = [](const RawAddress& /* remote_bda */, + tBT_TRANSPORT /* transport */) -> uint16_t { + return 0; + }, + .BTM_VendorSpecificCommand = BTM_VendorSpecificCommand, + .ACL_RegisterClient = + [](struct acl_client_callback_s* /* callbacks */) {}, + .ACL_UnregisterClient = + [](struct acl_client_callback_s* /* callbacks */) {}, + .btm_init = []() {}, + .btm_free = []() {}, + .btm_ble_init = []() {}, + .btm_ble_free = []() {}, + .BTM_reset_complete = []() {}, + }, + .peer = { + .features = + { + .SupportTransparentSynchronousData = + [](const RawAddress& /* bd_addr */) -> bool { + return false; + }, + }, + .BTM_IsAclConnectionUp = [](const RawAddress& /* remote_bda */, + tBT_TRANSPORT /* transport */) -> bool { + return false; + }, + .BTM_ReadConnectedTransportAddress = + [](RawAddress* /* remote_bda */, + tBT_TRANSPORT /* transport */) -> bool { return false; }, + .BTM_CancelRemoteDeviceName = BTM_CancelRemoteDeviceName, + .BTM_ReadRemoteDeviceName = BTM_ReadRemoteDeviceName, + .BTM_ReadRemoteFeatures = [](const RawAddress& /* addr */) -> uint8_t* { + return hci_feature_bytes_per_page; + }, + .BTM_ReadDevInfo = [](const RawAddress& /* remote_bda */, + tBT_DEVICE_TYPE* /* p_dev_type */, + tBLE_ADDR_TYPE* /* p_addr_type */) {}, + .BTM_GetMaxPacketSize = + [](const RawAddress& /* bd_addr */) -> uint16_t { return 0; }, + .BTM_ReadRemoteVersion = + [](const RawAddress& /* addr */, uint8_t* /* lmp_version */, + uint16_t* /* manufacturer */, + uint16_t* /* lmp_sub_version */) -> bool { return false; }, + }, + .link_policy = { + .BTM_GetRole = [](const RawAddress& /* remote_bd_addr */, + tHCI_ROLE* /* p_role */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_SetPowerMode = + [](uint8_t /* pm_id */, const RawAddress& /* remote_bda */, + const tBTM_PM_PWR_MD* /* p_mode */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_SetSsrParams = [](RawAddress const& /* bd_addr */, + uint16_t /* max_lat */, + uint16_t /* min_rmt_to */, + uint16_t /* min_loc_to */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_SwitchRoleToCentral = [](const RawAddress& /* remote_bd_addr */) + -> tBTM_STATUS { return BTM_SUCCESS; }, + .BTM_block_role_switch_for = [](const RawAddress& /* peer_addr */) {}, + .BTM_block_sniff_mode_for = [](const RawAddress& /* peer_addr */) {}, + .BTM_default_unblock_role_switch = []() {}, + .BTM_unblock_role_switch_for = [](const RawAddress& /* peer_addr */) {}, + .BTM_unblock_sniff_mode_for = [](const RawAddress& /* peer_addr */) {}, + .BTM_WritePageTimeout = BTM_WritePageTimeout, + }, + .link_controller = { + .BTM_GetLinkSuperTout = [](const RawAddress& /* remote_bda */, + uint16_t* /* p_timeout */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_ReadRSSI = [](const RawAddress& /* remote_bda */, + tBTM_CMPL_CB* /* p_cb */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + }, + .security = { + .BTM_Sec_Init = []() {}, + .BTM_Sec_Free = []() {}, + .BTM_SecAddDevice = BTM_SecAddDevice, + .BTM_SecAddRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK* /* p_callback */) -> bool { + return false; + }, + .BTM_SecDeleteDevice = BTM_SecDeleteDevice, + .BTM_SecRegister = [](const tBTM_APPL_INFO* /* p_cb_info */) -> bool { + return false; + }, + .BTM_SecReadDevName = [](const RawAddress& /* bd_addr */) + -> const char* { return nullptr; }, + .BTM_SecBond = [](const RawAddress& /* bd_addr */, + tBLE_ADDR_TYPE /* addr_type */, + tBT_TRANSPORT /* transport */, + tBT_DEVICE_TYPE /* device_type */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_SecBondCancel = [](const RawAddress& /* bd_addr */) + -> tBTM_STATUS { return BTM_SUCCESS; }, + .BTM_SecAddBleKey = [](const RawAddress& /* bd_addr */, + tBTM_LE_KEY_VALUE* /* p_le_key */, + tBTM_LE_KEY_TYPE /* key_type */) {}, + .BTM_SecAddBleDevice = [](const RawAddress& /* bd_addr */, + tBT_DEVICE_TYPE /* dev_type */, + tBLE_ADDR_TYPE /* addr_type */) {}, + .BTM_SecClearSecurityFlags = BTM_SecClearSecurityFlags, + .BTM_SecClrService = [](uint8_t /* service_id */) -> uint8_t { + return 0; + }, + .BTM_SecClrServiceByPsm = [](uint16_t /* psm */) -> uint8_t { + return 0; + }, + .BTM_RemoteOobDataReply = + [](tBTM_STATUS /* res */, const RawAddress& /* bd_addr */, + const Octet16& /* c */, const Octet16& /* r */) {}, + .BTM_PINCodeReply = [](const RawAddress& /* bd_addr */, + tBTM_STATUS /* res */, uint8_t /* pin_len */, + uint8_t* /* p_pin */) {}, + .BTM_ConfirmReqReply = [](tBTM_STATUS /* res */, + const RawAddress& /* bd_addr */) {}, + .BTM_SecDeleteRmtNameNotifyCallback = + [](tBTM_RMT_NAME_CALLBACK* /* p_callback */) -> bool { + return false; + }, + .BTM_SetEncryption = + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */, + tBTM_SEC_CALLBACK* /* p_callback */, void* /* p_ref_data */, + tBTM_BLE_SEC_ACT /* sec_act */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_IsEncrypted = [](const RawAddress& /* bd_addr */, + tBT_TRANSPORT /* transport */) -> bool { + return false; + }, + .BTM_SecIsSecurityPending = + [](const RawAddress& /* bd_addr */) -> bool { return false; }, + .BTM_IsLinkKeyKnown = [](const RawAddress& /* bd_addr */, + tBT_TRANSPORT /* transport */) -> bool { + return false; + }, + .BTM_BleSirkConfirmDeviceReply = [](const RawAddress& /* bd_addr */, + uint8_t /* res */) {}, + .BTM_GetSecurityMode = []() -> uint8_t { return 0; }, + }, + .ble = { + .BTM_BleGetEnergyInfo = + [](tBTM_BLE_ENERGY_INFO_CBACK* /* p_ener_cback */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_BleObserve = [](bool /* start */, uint8_t /* duration */, + tBTM_INQ_RESULTS_CB* /* p_results_cb */, + tBTM_CMPL_CB* /* p_cmpl_cb */, + bool /* low_latency_scan */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_SetBleDataLength = [](const RawAddress& /* bd_addr */, + uint16_t /* tx_pdu_length */) + -> tBTM_STATUS { return BTM_SUCCESS; }, + .BTM_BleConfirmReply = [](const RawAddress& /* bd_addr */, + uint8_t /* res */) {}, + .BTM_BleLoadLocalKeys = [](uint8_t /* key_type */, + tBTM_BLE_LOCAL_KEYS* /* p_key */) {}, + .BTM_BlePasskeyReply = [](const RawAddress& /* bd_addr */, + uint8_t /* res */, uint32_t /* passkey */) {}, + .BTM_BleReadControllerFeatures = + [](tBTM_BLE_CTRL_FEATURES_CBACK* /* p_vsc_cback */) {}, + .BTM_BleSetConnScanParams = [](uint32_t /* scan_interval */, + uint32_t /* scan_window */) {}, + .BTM_BleSetPhy = [](const RawAddress& /* bd_addr */, + uint8_t /* tx_phys */, uint8_t /* rx_phys */, + uint16_t /* phy_options */) {}, + .BTM_BleSetPrefConnParams = + [](const RawAddress& /* bd_addr */, uint16_t /* min_conn_int */, + uint16_t /* max_conn_int */, uint16_t /* peripheral_latency */, + uint16_t /* supervision_tout */) {}, + .BTM_UseLeLink = [](const RawAddress& /* bd_addr */) -> bool { + return false; + }, + }, + .sco = + { + .BTM_CreateSco = BTM_CreateSco, + .BTM_RegForEScoEvts = BTM_RegForEScoEvts, + .BTM_RemoveSco = BTM_RemoveSco, + .BTM_WriteVoiceSettings = BTM_WriteVoiceSettings, + .BTM_EScoConnRsp = BTM_EScoConnRsp, + .BTM_GetNumScoLinks = BTM_GetNumScoLinks, + .BTM_SetEScoMode = BTM_SetEScoMode, + }, + .local = + { + .BTM_ReadLocalDeviceNameFromController = + BTM_ReadLocalDeviceNameFromController, + .BTM_SetLocalDeviceName = BTM_SetLocalDeviceName, + .BTM_SetDeviceClass = BTM_SetDeviceClass, + .BTM_IsDeviceUp = BTM_IsDeviceUp, + .BTM_ReadDeviceClass = BTM_ReadDeviceClass, + }, + .eir = { + .BTM_WriteEIR = [](BT_HDR* /* p_buff */) -> tBTM_STATUS { + return BTM_SUCCESS; + }, + .BTM_GetEirSupportedServices = + [](uint32_t* /* p_eir_uuid */, uint8_t** /* p */, + uint8_t /* max_num_uuid16 */, + uint8_t* /* p_num_uuid16 */) -> uint8_t { return 0; }, + .BTM_GetEirUuidList = + [](const uint8_t* /* p_eir */, size_t /* eir_len */, + uint8_t /* uuid_size */, uint8_t* /* p_num_uuid */, + uint8_t* /* p_uuid_list */, + uint8_t /* max_num_uuid */) -> uint8_t { return 0; }, + .BTM_AddEirService = [](uint32_t* /* p_eir_uuid */, + uint16_t /* uuid16 */) {}, + .BTM_RemoveEirService = [](uint32_t* /* p_eir_uuid */, + uint16_t /* uuid16 */) {}, + }, + .db = + { + .BTM_InqDbRead = BTM_InqDbRead, + .BTM_InqDbFirst = BTM_InqDbFirst, + .BTM_InqDbNext = BTM_InqDbNext, + .BTM_ClearInqDb = BTM_ClearInqDb, + }, +}; + +} // namespace + +void BTM_BleReadControllerFeatures(void (*)(tHCI_ERROR_CODE)) {} +tBTM_STATUS BTM_BleGetEnergyInfo( + tBTM_BLE_ENERGY_INFO_CBACK* /* p_ener_cback */) { + return BTM_SUCCESS; +} + +// Initialize the working btm client interface to the default +struct btm_client_interface_t mock_btm_client_interface = + default_btm_client_interface; + +// Reset the working btm client interface to the default +void reset_mock_btm_client_interface() { + mock_btm_client_interface = default_btm_client_interface; +} + +// Serve the working btm client interface +struct btm_client_interface_t& get_btm_client_interface() { + return mock_btm_client_interface; +} diff --git a/system/test/mock/mock_stack_btm_interface.h b/system/test/mock/mock_stack_btm_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..b27d4ba53863b25036490ea0fa555390226ca08e --- /dev/null +++ b/system/test/mock/mock_stack_btm_interface.h @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "stack/include/btm_client_interface.h" + +void reset_mock_btm_client_interface(); + +extern struct btm_client_interface_t mock_btm_client_interface; diff --git a/system/test/mock/mock_stack_btm_iso.cc b/system/test/mock/mock_stack_btm_iso.cc index 962ddf4028f16cb10abc8b28dfe63d22e3cd6f2e..1112ec3fc606f873ebde58bdebd6d715f5779d8e 100644 --- a/system/test/mock/mock_stack_btm_iso.cc +++ b/system/test/mock/mock_stack_btm_iso.cc @@ -1,4 +1,3 @@ -#include #include "stack/include/btm_iso_api.h" @@ -12,38 +11,45 @@ struct IsoManager::impl {}; IsoManager::IsoManager() {} IsoManager::~IsoManager() {} -void IsoManager::RegisterCigCallbacks(CigCallbacks* callbacks) const {} -void IsoManager::RegisterBigCallbacks(BigCallbacks* callbacks) const {} -void IsoManager::RegisterOnIsoTrafficActiveCallback( - void callbacks(bool)) const {} -void IsoManager::CreateCig(uint8_t cig_id, - struct iso_manager::cig_create_params cig_params) {} +void IsoManager::RegisterCigCallbacks(CigCallbacks* /* callbacks */) const {} +void IsoManager::RegisterBigCallbacks(BigCallbacks* /* callbacks */) const {} +void IsoManager::RegisterOnIsoTrafficActiveCallback(void (*)(bool)) const {} +void IsoManager::CreateCig( + uint8_t /* cig_id */, + struct iso_manager::cig_create_params /* cig_params */) {} void IsoManager::ReconfigureCig( - uint8_t cig_id, struct iso_manager::cig_create_params cig_params) {} -void IsoManager::RemoveCig(uint8_t cig_id, bool force) {} + uint8_t /* cig_id */, + struct iso_manager::cig_create_params /* cig_params */) {} +void IsoManager::RemoveCig(uint8_t /* cig_id */, bool /* force */) {} void IsoManager::EstablishCis( - struct iso_manager::cis_establish_params conn_params) {} -void IsoManager::DisconnectCis(uint16_t cis_handle, uint8_t reason) {} + struct iso_manager::cis_establish_params /* conn_params */) {} +void IsoManager::DisconnectCis(uint16_t /* cis_handle */, + uint8_t /* reason */) {} void IsoManager::SetupIsoDataPath( - uint16_t iso_handle, struct iso_manager::iso_data_path_params path_params) { + uint16_t /* iso_handle */, + struct iso_manager::iso_data_path_params /* path_params */) {} +void IsoManager::RemoveIsoDataPath(uint16_t /* iso_handle */, + uint8_t /* data_path_dir */) {} +void IsoManager::ReadIsoLinkQuality(uint16_t /* iso_handle */) {} +void IsoManager::SendIsoData(uint16_t /* iso_handle */, + const uint8_t* /* data */, + uint16_t /* data_len */) {} +void IsoManager::CreateBig( + uint8_t /* big_id */, + struct iso_manager::big_create_params /* big_params */) {} +void IsoManager::TerminateBig(uint8_t /* big_id */, uint8_t /* reason */) {} +void IsoManager::HandleIsoData(void* /* p_msg */) {} +void IsoManager::HandleDisconnect(uint16_t /* handle */, uint8_t /* reason */) { } -void IsoManager::RemoveIsoDataPath(uint16_t iso_handle, uint8_t data_path_dir) { -} -void IsoManager::ReadIsoLinkQuality(uint16_t iso_handle) {} -void IsoManager::SendIsoData(uint16_t iso_handle, const uint8_t* data, - uint16_t data_len) {} -void IsoManager::CreateBig(uint8_t big_id, - struct iso_manager::big_create_params big_params) {} -void IsoManager::TerminateBig(uint8_t big_id, uint8_t reason) {} -void IsoManager::HandleIsoData(void* p_msg) {} -void IsoManager::HandleDisconnect(uint16_t handle, uint8_t reason) {} -void IsoManager::HandleNumComplDataPkts(uint8_t* p, uint8_t evt_len) {} -void IsoManager::HandleGdNumComplDataPkts(uint16_t handle, uint16_t credits) {} -void IsoManager::HandleHciEvent(uint8_t sub_code, uint8_t* params, - uint16_t length) {} +void IsoManager::HandleNumComplDataPkts(uint8_t* /* p */, + uint8_t /* evt_len */) {} +void IsoManager::HandleGdNumComplDataPkts(uint16_t /* handle */, + uint16_t /* credits */) {} +void IsoManager::HandleHciEvent(uint8_t /* sub_code */, uint8_t* /* params */, + uint16_t /* length */) {} void IsoManager::Start() {} void IsoManager::Stop() {} -void IsoManager::Dump(int fd) {} +void IsoManager::Dump(int /* fd */) {} } // namespace hci } // namespace bluetooth diff --git a/system/test/mock/mock_stack_btm_main.cc b/system/test/mock/mock_stack_btm_main.cc index 67f72ac196eb08f976a5d978d900967766b92053..31d2dae958fe1f536c4488f65e4a4c89e6affc72 100644 --- a/system/test/mock/mock_stack_btm_main.cc +++ b/system/test/mock/mock_stack_btm_main.cc @@ -19,36 +19,32 @@ * Functions generated:7 */ -#include -#include #include -#include "bt_target.h" -#include "main/shim/dumpsys.h" -#include "stack/btm/btm_int_types.h" -#include "stack/include/btm_client_interface.h" -#include "stack_config.h" #include "test/common/mock_functions.h" +#include "types/ble_address_with_type.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr, - const std::string& msg) { +void BTM_LogHistory(const std::string& /* tag */, + const RawAddress& /* bd_addr */, + const std::string& /* msg */) { inc_func_call_count(__func__); } -void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr, - const std::string& msg, const std::string& extra) { +void BTM_LogHistory(const std::string& /* tag */, + const RawAddress& /* bd_addr */, + const std::string& /* msg */, + const std::string& /* extra */) { inc_func_call_count(__func__); } -void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& ble_bd_addr, - const std::string& msg) { +void BTM_LogHistory(const std::string& /* tag */, + const tBLE_BD_ADDR& /* ble_bd_addr */, + const std::string& /* msg */) { inc_func_call_count(__func__); } -void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& ble_bd_addr, - const std::string& msg, const std::string& extra) { +void BTM_LogHistory(const std::string& /* tag */, + const tBLE_BD_ADDR& /* ble_bd_addr */, + const std::string& /* msg */, + const std::string& /* extra */) { inc_func_call_count(__func__); } void btm_free(void) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_btm_sco.cc b/system/test/mock/mock_stack_btm_sco.cc index 5396a9db73d61bc746aa9735193fa1461b61a0d2..d7ad6d37d1bbda0c3825a3661e74e0ab1e772ce9 100644 --- a/system/test/mock/mock_stack_btm_sco.cc +++ b/system/test/mock/mock_stack_btm_sco.cc @@ -20,10 +20,9 @@ */ #include -#include -#include #include "device/include/esco_parameters.h" +#include "stack/btm/btm_sco.h" #include "stack/include/bt_hdr.h" #include "stack/include/btm_api_types.h" #include "stack/include/btm_status.h" @@ -32,42 +31,40 @@ #include "types/class_of_device.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool BTM_IsScoActiveByBdaddr(const RawAddress& remote_bda) { +bool BTM_IsScoActiveByBdaddr(const RawAddress& /* remote_bda */) { inc_func_call_count(__func__); return false; } -bool btm_is_sco_active(uint16_t handle) { +bool btm_is_sco_active(uint16_t /* handle */) { inc_func_call_count(__func__); return false; } -bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason) { +bool btm_sco_removed(uint16_t /* hci_handle */, tHCI_REASON /* reason */) { inc_func_call_count(__func__); return false; } -const RawAddress* BTM_ReadScoBdAddr(uint16_t sco_inx) { +const RawAddress* BTM_ReadScoBdAddr(uint16_t /* sco_inx */) { inc_func_call_count(__func__); return nullptr; } -tBTM_STATUS BTM_CreateSco(const RawAddress* remote_bda, bool is_orig, - uint16_t pkt_types, uint16_t* p_sco_inx, - tBTM_SCO_CB* p_conn_cb, tBTM_SCO_CB* p_disc_cb) { +tBTM_STATUS BTM_CreateSco(const RawAddress* /* remote_bda */, + bool /* is_orig */, uint16_t /* pkt_types */, + uint16_t* /* p_sco_inx */, + tBTM_SCO_CB* /* p_conn_cb */, + tBTM_SCO_CB* /* p_disc_cb */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx, - tBTM_ESCO_CBACK* p_esco_cback) { +tBTM_STATUS BTM_RegForEScoEvts(uint16_t /* sco_inx */, + tBTM_ESCO_CBACK* /* p_esco_cback */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) { +tBTM_STATUS BTM_RemoveSco(uint16_t /* sco_inx */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms) { +tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* /* p_parms */) { inc_func_call_count(__func__); return BTM_SUCCESS; } @@ -75,45 +72,68 @@ uint8_t BTM_GetNumScoLinks(void) { inc_func_call_count(__func__); return 0; } -void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status, - enh_esco_params_t* p_parms) { +tBTM_SCO_DEBUG_DUMP BTM_GetScoDebugDump(void) { + inc_func_call_count(__func__); + return {}; +} +void BTM_EScoConnRsp(uint16_t /* sco_inx */, uint8_t /* hci_status */, + enh_esco_params_t* /* p_parms */) { inc_func_call_count(__func__); } -void BTM_RemoveSco(const RawAddress& bda) { inc_func_call_count(__func__); } -void btm_route_sco_data(BT_HDR* p_msg) { inc_func_call_count(__func__); } -void btm_sco_acl_removed(const RawAddress* bda) { +void BTM_RemoveSco(const RawAddress& /* bda */) { inc_func_call_count(__func__); } -void btm_sco_chk_pend_rolechange(uint16_t hci_handle) { +void btm_sco_acl_removed(const RawAddress* /* bda */) { inc_func_call_count(__func__); } -void btm_sco_chk_pend_unpark(tHCI_STATUS hci_status, uint16_t hci_handle) { +void btm_sco_chk_pend_rolechange(uint16_t /* hci_handle */) { inc_func_call_count(__func__); } -void btm_sco_conn_req(const RawAddress& bda, const DEV_CLASS& dev_class, - uint8_t link_type) { +void btm_sco_chk_pend_unpark(tHCI_STATUS /* hci_status */, + uint16_t /* hci_handle */) { inc_func_call_count(__func__); } -void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, - tBTM_ESCO_DATA* p_esco_data) { +void btm_sco_conn_req(const RawAddress& /* bda */, + const DEV_CLASS& /* dev_class */, + uint8_t /* link_type */) { inc_func_call_count(__func__); } -void btm_sco_connection_failed(tHCI_STATUS hci_status, const RawAddress& bda, - uint16_t hci_handle, - tBTM_ESCO_DATA* p_esco_data) { +void btm_sco_connected(const RawAddress& /* bda */, uint16_t /* hci_handle */, + tBTM_ESCO_DATA* /* p_esco_data */) { inc_func_call_count(__func__); } -void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle) { +void btm_sco_connection_failed(tHCI_STATUS /* hci_status */, + const RawAddress& /* bda */, + uint16_t /* hci_handle */, + tBTM_ESCO_DATA* /* p_esco_data */) { + inc_func_call_count(__func__); +} +void btm_sco_disc_chk_pend_for_modechange(uint16_t /* hci_handle */) { inc_func_call_count(__func__); } void btm_sco_on_esco_connect_request( - const RawAddress& bda, const bluetooth::types::ClassOfDevice& cod) { + const RawAddress& /* bda */, + const bluetooth::types::ClassOfDevice& /* cod */) { inc_func_call_count(__func__); } void btm_sco_on_sco_connect_request( - const RawAddress& bda, const bluetooth::types::ClassOfDevice& cod) { + const RawAddress& /* bda */, + const bluetooth::types::ClassOfDevice& /* cod */) { + inc_func_call_count(__func__); +} +void btm_sco_on_disconnected(uint16_t /* hci_handle */, + tHCI_REASON /* reason */) { + inc_func_call_count(__func__); +} +bool btm_peer_supports_esco_2m_phy(RawAddress /* bd_addr */) { + inc_func_call_count(__func__); + return true; +} +bool btm_peer_supports_esco_3m_phy(RawAddress /* bd_addr */) { inc_func_call_count(__func__); + return true; } -void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) { +bool btm_peer_supports_esco_ev3(RawAddress /* bd_addr */) { inc_func_call_count(__func__); + return true; } diff --git a/system/test/mock/mock_stack_btm_sco_hfp_hal.cc b/system/test/mock/mock_stack_btm_sco_hfp_hal.cc index 2e52fe2d53eb4c25279d0ad1ab248635f2db7b1c..96d18afe24a738b0131889bd4aac74c522f2c9fb 100644 --- a/system/test/mock/mock_stack_btm_sco_hfp_hal.cc +++ b/system/test/mock/mock_stack_btm_sco_hfp_hal.cc @@ -19,15 +19,13 @@ * * mockcify.pl ver 0.5.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_btm_sco_hfp_hal.h" #ifndef __clang_analyzer__ #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_btm_sco_hfp_hal.h" +#include "test/common/mock_functions.h" // Original usings @@ -112,7 +110,7 @@ void notify_sco_connection_change(RawAddress device, bool is_connected, test::mock::stack_btm_sco_hfp_hal::notify_sco_connection_change( device, is_connected, codec); } -void set_codec_datapath(esco_coding_format_t coding_format) { +void set_codec_datapath(int coding_format) { inc_func_call_count(__func__); test::mock::stack_btm_sco_hfp_hal::set_codec_datapath(coding_format); } diff --git a/system/test/mock/mock_stack_btm_sco_hfp_hal.h b/system/test/mock/mock_stack_btm_sco_hfp_hal.h index 8b0e02d2c0f24e6ff18a23285de203ad6211f2a5..fdabd2b150240e8dc69d50341c657659ef3d8955 100644 --- a/system/test/mock/mock_stack_btm_sco_hfp_hal.h +++ b/system/test/mock/mock_stack_btm_sco_hfp_hal.h @@ -24,20 +24,11 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include - -#include "btm_sco_hfp_hal.h" + #include "device/include/esco_parameters.h" -#include "test/common/mock_functions.h" +#include "stack/btm/btm_sco_hfp_hal.h" // Original usings @@ -54,7 +45,7 @@ namespace stack_btm_sco_hfp_hal { struct enable_offload { static bool return_value; std::function body{ - [](bool enable) { return return_value; }}; + [](bool /* enable */) { return return_value; }}; bool operator()(bool enable) { return body(enable); }; }; extern struct enable_offload enable_offload; @@ -65,7 +56,7 @@ extern struct enable_offload enable_offload; struct get_codec_capabilities { static hfp_hal_interface::bt_codecs return_value; std::function body{ - [](uint64_t codecs) { return return_value; }}; + [](uint64_t /* codecs */) { return return_value; }}; hfp_hal_interface::bt_codecs operator()(uint64_t codecs) { return body(codecs); }; @@ -97,7 +88,8 @@ extern struct get_offload_supported get_offload_supported; // Return: int struct get_packet_size { static int return_value; - std::function body{[](int codec) { return return_value; }}; + std::function body{ + [](int /* codec */) { return return_value; }}; int operator()(int codec) { return body(codec); }; }; extern struct get_packet_size get_packet_size; @@ -136,7 +128,7 @@ extern struct init init; // Return: void struct notify_sco_connection_change { std::function body{ - [](RawAddress device, bool is_connected, int codec) {}}; + [](RawAddress /* device */, bool /* is_connected */, int /* codec */) {}}; void operator()(RawAddress device, bool is_connected, int codec) { body(device, is_connected, codec); }; @@ -147,9 +139,8 @@ extern struct notify_sco_connection_change notify_sco_connection_change; // Params: esco_coding_format_t coding_format // Return: void struct set_codec_datapath { - std::function body{ - [](esco_coding_format_t coding_format) {}}; - void operator()(esco_coding_format_t coding_format) { body(coding_format); }; + std::function body{[](int /* coding_format */) {}}; + void operator()(int coding_format) { body(coding_format); }; }; extern struct set_codec_datapath set_codec_datapath; @@ -158,7 +149,7 @@ extern struct set_codec_datapath set_codec_datapath; // Return: void struct update_esco_parameters { std::function body{ - [](enh_esco_params_t* p_parms) {}}; + [](enh_esco_params_t* /* p_parms */) {}}; void operator()(enh_esco_params_t* p_parms) { body(p_parms); }; }; extern struct update_esco_parameters update_esco_parameters; diff --git a/system/test/mock/mock_stack_btm_sec.cc b/system/test/mock/mock_stack_btm_sec.cc index d24156e9a0d46bea4e9775cb11cae230dc48d22d..7bea4563242273f77b820185eba9e6bf7ef35364 100644 --- a/system/test/mock/mock_stack_btm_sec.cc +++ b/system/test/mock/mock_stack_btm_sec.cc @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,305 +13,461 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* * Generated mock file from original source file * Functions generated:66 + * + * mockcify.pl ver 0.6.0 */ - +// Mock include file to share data between tests and mock #include "test/mock/mock_stack_btm_sec.h" -#include -#include -#include -#include - -#include +#include #include -#include "btif/include/btif_storage.h" -#include "common/metrics.h" -#include "common/time_util.h" -#include "device/include/controller.h" -#include "l2c_api.h" -#include "main/shim/btm_api.h" -#include "main/shim/dumpsys.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" -#include "stack/btm/btm_dev.h" -#include "stack/btm/btm_sec.h" -#include "stack/include/acl_api.h" -#include "stack/include/acl_hci_link_interface.h" +#include "stack/include/btm_sec_api_types.h" #include "stack/include/btm_status.h" -#include "stack/include/l2cap_security_interface.h" -#include "stack/smp/smp_int.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +// Original usings + +// Mocked internal structures, if any + +namespace test { +namespace mock { +namespace stack_btm_sec { + +// Function state capture and return values, if needed +struct BTM_BothEndsSupportSecureConnections + BTM_BothEndsSupportSecureConnections; +struct BTM_CanReadDiscoverableCharacteristics + BTM_CanReadDiscoverableCharacteristics; +struct BTM_ConfirmReqReply BTM_ConfirmReqReply; +struct BTM_GetClockOffset BTM_GetClockOffset; +struct BTM_GetPeerDeviceTypeFromFeatures BTM_GetPeerDeviceTypeFromFeatures; +struct BTM_IsAuthenticated BTM_IsAuthenticated; +struct BTM_IsEncrypted BTM_IsEncrypted; +struct BTM_IsLinkKeyAuthed BTM_IsLinkKeyAuthed; +struct BTM_IsLinkKeyKnown BTM_IsLinkKeyKnown; +struct BTM_PINCodeReply BTM_PINCodeReply; +struct BTM_PasskeyReqReply BTM_PasskeyReqReply; +struct BTM_PeerSupportsSecureConnections BTM_PeerSupportsSecureConnections; +struct BTM_ReadLocalOobData BTM_ReadLocalOobData; +struct BTM_RemoteOobDataReply BTM_RemoteOobDataReply; +struct BTM_SecAddRmtNameNotifyCallback BTM_SecAddRmtNameNotifyCallback; +struct BTM_SecBond BTM_SecBond; +struct BTM_SecBondCancel BTM_SecBondCancel; +struct BTM_SecClrService BTM_SecClrService; +struct BTM_SecClrServiceByPsm BTM_SecClrServiceByPsm; +struct BTM_SecDeleteRmtNameNotifyCallback BTM_SecDeleteRmtNameNotifyCallback; +struct BTM_SecGetDeviceLinkKeyType BTM_SecGetDeviceLinkKeyType; +struct BTM_SecIsSecurityPending BTM_SecIsSecurityPending; +struct BTM_SecRegister BTM_SecRegister; +struct BTM_SetEncryption BTM_SetEncryption; +struct BTM_SetPinType BTM_SetPinType; +struct BTM_SetSecurityLevel BTM_SetSecurityLevel; +struct BTM_update_version_info BTM_update_version_info; +struct NotifyBondingCanceled NotifyBondingCanceled; +struct btm_create_conn_cancel_complete btm_create_conn_cancel_complete; +struct btm_get_dev_class btm_get_dev_class; +struct btm_io_capabilities_req btm_io_capabilities_req; +struct btm_io_capabilities_rsp btm_io_capabilities_rsp; +struct btm_proc_sp_req_evt btm_proc_sp_req_evt; +struct btm_read_local_oob_complete btm_read_local_oob_complete; +struct btm_rem_oob_req btm_rem_oob_req; +struct btm_sec_abort_access_req btm_sec_abort_access_req; +struct btm_sec_auth_complete btm_sec_auth_complete; +struct btm_sec_bond_by_transport btm_sec_bond_by_transport; +struct btm_sec_check_pending_reqs btm_sec_check_pending_reqs; +struct btm_sec_clear_ble_keys btm_sec_clear_ble_keys; +struct btm_sec_conn_req btm_sec_conn_req; +struct btm_sec_connected btm_sec_connected; +struct btm_sec_cr_loc_oob_data_cback_event btm_sec_cr_loc_oob_data_cback_event; +struct btm_sec_dev_rec_cback_event btm_sec_dev_rec_cback_event; +struct btm_sec_dev_reset btm_sec_dev_reset; +struct btm_sec_disconnect btm_sec_disconnect; +struct btm_sec_disconnected btm_sec_disconnected; +struct btm_sec_encrypt_change btm_sec_encrypt_change; +struct btm_sec_is_a_bonded_dev btm_sec_is_a_bonded_dev; +struct btm_sec_l2cap_access_req btm_sec_l2cap_access_req; +struct btm_sec_l2cap_access_req_by_requirement + btm_sec_l2cap_access_req_by_requirement; +struct btm_sec_link_key_notification btm_sec_link_key_notification; +struct btm_sec_encryption_key_refresh_complete + btm_sec_encryption_key_refresh_complete; +struct btm_sec_link_key_request btm_sec_link_key_request; +struct btm_sec_mx_access_request btm_sec_mx_access_request; +struct btm_sec_pin_code_request btm_sec_pin_code_request; +struct btm_sec_rmt_host_support_feat_evt btm_sec_rmt_host_support_feat_evt; +struct btm_sec_rmt_name_request_complete btm_sec_rmt_name_request_complete; +struct btm_sec_role_changed btm_sec_role_changed; +struct btm_sec_set_peer_sec_caps btm_sec_set_peer_sec_caps; +struct btm_sec_update_clock_offset btm_sec_update_clock_offset; +struct btm_simple_pair_complete btm_simple_pair_complete; + +struct BTM_IsRemoteNameKnown BTM_IsRemoteNameKnown; +} // namespace stack_btm_sec +} // namespace mock +} // namespace test + +// Mocked function return values, if any +namespace test { +namespace mock { +namespace stack_btm_sec { + +bool BTM_BothEndsSupportSecureConnections::return_value = false; +bool BTM_CanReadDiscoverableCharacteristics::return_value = false; +uint16_t BTM_GetClockOffset::return_value = 0; +tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures::return_value = 0; +bool BTM_IsAuthenticated::return_value = false; +bool BTM_IsEncrypted::return_value = false; +bool BTM_IsLinkKeyAuthed::return_value = false; +bool BTM_IsLinkKeyKnown::return_value = false; +bool BTM_PeerSupportsSecureConnections::return_value = false; +bool BTM_SecAddRmtNameNotifyCallback::return_value = false; +tBTM_STATUS BTM_SecBond::return_value = 0; +tBTM_STATUS BTM_SecBondCancel::return_value = 0; +uint8_t BTM_SecClrService::return_value = 0; +uint8_t BTM_SecClrServiceByPsm::return_value = 0; +bool BTM_SecDeleteRmtNameNotifyCallback::return_value = false; +tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType::return_value = 0; +bool BTM_SecIsSecurityPending::return_value = false; +bool BTM_SecRegister::return_value = false; +tBTM_STATUS BTM_SetEncryption::return_value = 0; +bool BTM_SetSecurityLevel::return_value = false; +const uint8_t* btm_get_dev_class::return_value = nullptr; +tBTM_STATUS btm_sec_bond_by_transport::return_value = 0; +tBTM_STATUS btm_sec_disconnect::return_value = 0; +bool btm_sec_is_a_bonded_dev::return_value = false; +tBTM_STATUS btm_sec_l2cap_access_req::return_value = 0; +tBTM_STATUS btm_sec_l2cap_access_req_by_requirement::return_value = 0; +tBTM_STATUS btm_sec_mx_access_request::return_value = 0; + +bool BTM_IsRemoteNameKnown::return_value = false; + +} // namespace stack_btm_sec +} // namespace mock +} // namespace test + +// Mocked functions, if any bool BTM_BothEndsSupportSecureConnections(const RawAddress& bd_addr) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_BothEndsSupportSecureConnections( + bd_addr); } -bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr, - uint8_t* p_sec_flags, - tBT_TRANSPORT transport) { +bool BTM_CanReadDiscoverableCharacteristics(const RawAddress& bd_addr) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_CanReadDiscoverableCharacteristics( + bd_addr); } -bool BTM_IsAuthenticated(const RawAddress& bd_addr, tBT_TRANSPORT transport) { +void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr) { inc_func_call_count(__func__); - return false; + test::mock::stack_btm_sec::BTM_ConfirmReqReply(res, bd_addr); } -bool BTM_CanReadDiscoverableCharacteristics(const RawAddress& bd_addr) { +uint16_t BTM_GetClockOffset(const RawAddress& remote_bda) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_GetClockOffset(remote_bda); } -bool BTM_IsEncrypted(const RawAddress& bd_addr, tBT_TRANSPORT transport) { +tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(const RawAddress& bd_addr) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_GetPeerDeviceTypeFromFeatures(bd_addr); } -bool BTM_IsLinkKeyAuthed(const RawAddress& bd_addr, tBT_TRANSPORT transport) { +bool BTM_IsAuthenticated(const RawAddress& bd_addr, tBT_TRANSPORT transport) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_IsAuthenticated(bd_addr, transport); } -bool BTM_IsLinkKeyKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) { +bool BTM_IsEncrypted(const RawAddress& bd_addr, tBT_TRANSPORT transport) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_IsEncrypted(bd_addr, transport); } -bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr) { +bool BTM_IsLinkKeyAuthed(const RawAddress& bd_addr, tBT_TRANSPORT transport) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_IsLinkKeyAuthed(bd_addr, transport); } -tBT_DEVICE_TYPE BTM_GetPeerDeviceTypeFromFeatures(const RawAddress& bd_addr) { +bool BTM_IsLinkKeyKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) { inc_func_call_count(__func__); - return BT_DEVICE_TYPE_BREDR; + return test::mock::stack_btm_sec::BTM_IsLinkKeyKnown(bd_addr, transport); } -bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) { +void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, + uint8_t pin_len, uint8_t* p_pin) { inc_func_call_count(__func__); - return false; + test::mock::stack_btm_sec::BTM_PINCodeReply(bd_addr, res, pin_len, p_pin); } -bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) { +void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr, + uint32_t passkey) { inc_func_call_count(__func__); - return false; + test::mock::stack_btm_sec::BTM_PasskeyReqReply(res, bd_addr, passkey); } -bool BTM_SecIsSecurityPending(const RawAddress& bd_addr) { +bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_PeerSupportsSecureConnections(bd_addr); } -bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) { +void BTM_ReadLocalOobData(void) { inc_func_call_count(__func__); - return false; + test::mock::stack_btm_sec::BTM_ReadLocalOobData(); } -bool BTM_SetSecurityLevel(bool is_originator, const char* p_name, - uint8_t service_id, uint16_t sec_level, uint16_t psm, - uint32_t mx_proto_id, uint32_t mx_chan_id) { +void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr, + const Octet16& c, const Octet16& r) { inc_func_call_count(__func__); - return false; + test::mock::stack_btm_sec::BTM_RemoteOobDataReply(res, bd_addr, c, r); } -bool btm_sec_is_a_bonded_dev(const RawAddress& bda) { +bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_SecAddRmtNameNotifyCallback(p_callback); } -bool is_sec_state_equal(void* data, void* context) { +tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_SecBond(bd_addr, addr_type, transport, + device_type); } -bool is_state_getting_name(void* data, void* context) { +tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr) { inc_func_call_count(__func__); - return false; + return test::mock::stack_btm_sec::BTM_SecBondCancel(bd_addr); } -const uint8_t* btm_get_dev_class(const RawAddress& bda) { +uint8_t BTM_SecClrService(uint8_t service_id) { inc_func_call_count(__func__); - return nullptr; + return test::mock::stack_btm_sec::BTM_SecClrService(service_id); } -tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr) { +uint8_t BTM_SecClrServiceByPsm(uint16_t psm) { inc_func_call_count(__func__); - return 0; + return test::mock::stack_btm_sec::BTM_SecClrServiceByPsm(psm); } -tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state) { +bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) { inc_func_call_count(__func__); - return nullptr; + return test::mock::stack_btm_sec::BTM_SecDeleteRmtNameNotifyCallback( + p_callback); } -tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm) { +tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr) { inc_func_call_count(__func__); - return nullptr; + return test::mock::stack_btm_sec::BTM_SecGetDeviceLinkKeyType(bd_addr); } -tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type, - uint8_t pin_len, uint8_t* p_pin) { +bool BTM_SecIsSecurityPending(const RawAddress& bd_addr) { inc_func_call_count(__func__); - return BTM_SUCCESS; + return test::mock::stack_btm_sec::BTM_SecIsSecurityPending(bd_addr); } -tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr) { +bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) { inc_func_call_count(__func__); - return BTM_SUCCESS; -} -namespace test { -namespace mock { -namespace stack_btm_sec { - -struct BTM_SetEncryption BTM_SetEncryption; - + return test::mock::stack_btm_sec::BTM_SecRegister(p_cb_info); } -} // namespace mock -} // namespace test - tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr, tBT_TRANSPORT transport, tBTM_SEC_CALLBACK* p_callback, void* p_ref_data, tBTM_BLE_SEC_ACT sec_act) { inc_func_call_count(__func__); - if (test::mock::stack_btm_sec::BTM_SetEncryption.body) { - return test::mock::stack_btm_sec::BTM_SetEncryption.body( - bd_addr, transport, p_callback, p_ref_data, sec_act); - } - return BTM_SUCCESS; + return test::mock::stack_btm_sec::BTM_SetEncryption( + bd_addr, transport, p_callback, p_ref_data, sec_act); } -tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, - tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, uint8_t pin_len, - uint8_t* p_pin) { +void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len) { inc_func_call_count(__func__); - return BTM_SUCCESS; + test::mock::stack_btm_sec::BTM_SetPinType(pin_type, pin_code, pin_code_len); } -tBTM_STATUS btm_sec_disconnect(uint16_t handle, tHCI_STATUS reason, - std::string comment) { +bool BTM_SetSecurityLevel(bool is_originator, const char* p_name, + uint8_t service_id, uint16_t sec_level, uint16_t psm, + uint32_t mx_proto_id, uint32_t mx_chan_id) { inc_func_call_count(__func__); - return BTM_SUCCESS; + return test::mock::stack_btm_sec::BTM_SetSecurityLevel( + is_originator, p_name, service_id, sec_level, psm, mx_proto_id, + mx_chan_id); } -tBTM_STATUS btm_sec_l2cap_access_req(const RawAddress& bd_addr, uint16_t psm, - bool is_originator, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data) { +void BTM_update_version_info(const RawAddress& bd_addr, + const remote_version_info& remote_version_info) { inc_func_call_count(__func__); - return BTM_SUCCESS; + test::mock::stack_btm_sec::BTM_update_version_info(bd_addr, + remote_version_info); } -tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( - const RawAddress& bd_addr, uint16_t security_required, bool is_originator, - tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) { +void NotifyBondingCanceled(tBTM_STATUS btm_status) { inc_func_call_count(__func__); - return BTM_SUCCESS; + test::mock::stack_btm_sec::NotifyBondingCanceled(btm_status); } -tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, - bool is_originator, - uint16_t security_required, - tBTM_SEC_CALLBACK* p_callback, - void* p_ref_data) { +void btm_create_conn_cancel_complete(uint8_t status, const RawAddress bd_addr) { inc_func_call_count(__func__); - return BTM_SUCCESS; + test::mock::stack_btm_sec::btm_create_conn_cancel_complete(status, bd_addr); } -uint16_t BTM_GetClockOffset(const RawAddress& remote_bda) { +const uint8_t* btm_get_dev_class(const RawAddress& bda) { inc_func_call_count(__func__); - return 0; + return test::mock::stack_btm_sec::btm_get_dev_class(bda); } -uint8_t BTM_SecClrService(uint8_t service_id) { +void btm_io_capabilities_req(RawAddress p) { inc_func_call_count(__func__); - return 0; + test::mock::stack_btm_sec::btm_io_capabilities_req(p); } -uint8_t BTM_SecClrServiceByPsm(uint16_t psm) { +void btm_io_capabilities_rsp(const tBTM_SP_IO_RSP evt_data) { inc_func_call_count(__func__); - return 0; + test::mock::stack_btm_sec::btm_io_capabilities_rsp(evt_data); } -void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr) { +void btm_proc_sp_req_evt(tBTM_SP_EVT event, const RawAddress bd_addr, + uint32_t value) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_proc_sp_req_evt(event, bd_addr, value); } -void BTM_PINCodeReply(const RawAddress& bd_addr, tBTM_STATUS res, - uint8_t pin_len, uint8_t* p_pin) { +void btm_read_local_oob_complete(const tBTM_SP_LOC_OOB evt_data) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_read_local_oob_complete(evt_data); } -void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr, - uint32_t passkey) { +void btm_rem_oob_req(const RawAddress bd_addr) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_rem_oob_req(bd_addr); } -void BTM_ReadLocalOobData(void) { inc_func_call_count(__func__); } -void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr, - const Octet16& c, const Octet16& r) { +void btm_sec_abort_access_req(const RawAddress& bd_addr) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_abort_access_req(bd_addr); } -void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len) { +void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_auth_complete(handle, status); } -void NotifyBondingCanceled(tBTM_STATUS btm_status) { +tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr, + tBLE_ADDR_TYPE addr_type, + tBT_TRANSPORT transport) { inc_func_call_count(__func__); + return test::mock::stack_btm_sec::btm_sec_bond_by_transport( + bd_addr, addr_type, transport); } -void btm_create_conn_cancel_complete(const uint8_t* p, uint16_t evt_len) { +void btm_sec_check_pending_reqs(void) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_check_pending_reqs(); } -void btm_io_capabilities_req(const RawAddress& p) { +void btm_sec_clear_ble_keys(tBTM_SEC_DEV_REC* p_dev_rec) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_clear_ble_keys(p_dev_rec); } -void btm_io_capabilities_rsp(const uint8_t* p) { +void btm_sec_conn_req(const RawAddress& bda, const DEV_CLASS dc) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_conn_req(bda, dc); } -void btm_proc_sp_req_evt(tBTM_SP_EVT event, const uint8_t* p) { +void btm_sec_connected(const RawAddress& bda, uint16_t handle, + tHCI_STATUS status, uint8_t enc_mode, + tHCI_ROLE assigned_role) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_connected(bda, handle, status, enc_mode, + assigned_role); } -void btm_read_local_oob_complete(uint8_t* p, uint16_t evt_len) { +void btm_sec_cr_loc_oob_data_cback_event(const RawAddress& address, + tSMP_LOC_OOB_DATA loc_oob_data) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_cr_loc_oob_data_cback_event(address, + loc_oob_data); } -void btm_rem_oob_req(const uint8_t* p) { inc_func_call_count(__func__); } -void btm_sec_abort_access_req(const RawAddress& bd_addr) { +void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec, + tBTM_STATUS btm_status, bool is_le_transport) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_dev_rec_cback_event(p_dev_rec, btm_status, + is_le_transport); } -void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { +void btm_sec_dev_reset(void) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_dev_reset(); } -void btm_sec_check_pending_reqs(void) { inc_func_call_count(__func__); } -void btm_sec_clear_ble_keys(tBTM_SEC_DEV_REC* p_dev_rec) { +tBTM_STATUS btm_sec_disconnect(uint16_t handle, tHCI_STATUS reason, + std::string comment) { inc_func_call_count(__func__); + return test::mock::stack_btm_sec::btm_sec_disconnect(handle, reason, comment); } -void btm_sec_conn_req(const RawAddress& bda, uint8_t* dc) { +void btm_sec_disconnected(uint16_t handle, tHCI_REASON reason, + std::string comment) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_disconnected(handle, reason, comment); } -void btm_sec_connected(const RawAddress& bda, uint16_t handle, - tHCI_STATUS status, uint8_t enc_mode, - tHCI_ROLE assigned_role) { +void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, + uint8_t encr_enable) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_encrypt_change(handle, status, + encr_enable); } -void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec, - tBTM_STATUS btm_status, bool is_le_transport) { +bool btm_sec_is_a_bonded_dev(const RawAddress& bda) { inc_func_call_count(__func__); + return test::mock::stack_btm_sec::btm_sec_is_a_bonded_dev(bda); } -void btm_sec_dev_reset(void) { inc_func_call_count(__func__); } -void btm_sec_disconnected(uint16_t handle, tHCI_REASON reason, - std::string comment) { +tBTM_STATUS btm_sec_l2cap_access_req(const RawAddress& bd_addr, uint16_t psm, + bool is_originator, + tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data) { inc_func_call_count(__func__); + return test::mock::stack_btm_sec::btm_sec_l2cap_access_req( + bd_addr, psm, is_originator, p_callback, p_ref_data); } -void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, - uint8_t encr_enable) { +tBTM_STATUS btm_sec_l2cap_access_req_by_requirement( + const RawAddress& bd_addr, uint16_t security_required, bool is_originator, + tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) { inc_func_call_count(__func__); + return test::mock::stack_btm_sec::btm_sec_l2cap_access_req_by_requirement( + bd_addr, security_required, is_originator, p_callback, p_ref_data); } void btm_sec_link_key_notification(const RawAddress& p_bda, const Octet16& link_key, uint8_t key_type) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_link_key_notification(p_bda, link_key, + key_type); } -void btm_sec_link_key_request(const uint8_t* p_event) { +void btm_sec_encryption_key_refresh_complete(uint16_t handle, + tHCI_STATUS status) { + inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_encryption_key_refresh_complete(handle, + status); +} +void btm_sec_link_key_request(const RawAddress bda) { + inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_link_key_request(bda); +} +tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, + bool is_originator, + uint16_t security_required, + tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data) { inc_func_call_count(__func__); + return test::mock::stack_btm_sec::btm_sec_mx_access_request( + bd_addr, is_originator, security_required, p_callback, p_ref_data); } -void btm_sec_pin_code_request(const uint8_t* p_event) { +void btm_sec_pin_code_request(const RawAddress bda) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_pin_code_request(bda); } -void btm_sec_rmt_host_support_feat_evt(const uint8_t* p) { +void btm_sec_rmt_host_support_feat_evt(const RawAddress bd_addr, + uint8_t features_0) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_rmt_host_support_feat_evt(bd_addr, + features_0); } void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, const uint8_t* p_bd_name, tHCI_STATUS status) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_rmt_name_request_complete( + p_bd_addr, p_bd_name, status); +} +void btm_sec_role_changed(tHCI_STATUS hci_status, const RawAddress& bd_addr, + tHCI_ROLE new_role) { + inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_role_changed(hci_status, bd_addr, + new_role); } void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported, bool sc_supported, bool hci_role_switch_supported, bool br_edr_supported, bool le_supported) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_set_peer_sec_caps( + hci_handle, ssp_supported, sc_supported, hci_role_switch_supported, + br_edr_supported, le_supported); } void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_sec_update_clock_offset(handle, clock_offset); } -void btm_simple_pair_complete(const uint8_t* p) { +void btm_simple_pair_complete(const RawAddress bd_addr, uint8_t status) { inc_func_call_count(__func__); + test::mock::stack_btm_sec::btm_simple_pair_complete(bd_addr, status); +} +bool BTM_IsRemoteNameKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + inc_func_call_count(__func__); + return test::mock::stack_btm_sec::BTM_IsRemoteNameKnown(bd_addr, transport); +} +bool BTM_BleIsLinkKeyKnown(const RawAddress /* address */) { + inc_func_call_count(__func__); + return false; } +// Mocked functions complete +// END mockcify generation diff --git a/system/test/mock/mock_stack_btm_sec.h b/system/test/mock/mock_stack_btm_sec.h index da4922a8b8856c6c6bf3694cf6f075ab48979c90..824c7b2047a2307769a8a874b14367e9b7ec05e7 100644 --- a/system/test/mock/mock_stack_btm_sec.h +++ b/system/test/mock/mock_stack_btm_sec.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Android Open Source Project + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,26 +13,354 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#include +/* + * Generated mock file from original source file + * Functions generated:66 + * + * mockcify.pl ver 0.6.0 + */ + +#include +#include #include -#include "stack/include/btm_api_types.h" +// Original included files, if any +#include "bt_dev_class.h" +#include "stack/btm/security_device_record.h" +#include "stack/include/bt_device_type.h" #include "stack/include/btm_status.h" -#include "test/common/mock_functions.h" +#include "stack/include/hci_error_code.h" +#include "stack/include/security_client_callbacks.h" #include "types/bt_transport.h" +#include "types/hci_role.h" #include "types/raw_address.h" +// Original usings + +// Mocked compile conditionals, if any + namespace test { namespace mock { namespace stack_btm_sec { -// Function state capture and return values, if needed +// Shared state between mocked functions and tests +// Name: BTM_BothEndsSupportSecureConnections +// Params: const RawAddress& bd_addr +// Return: bool +struct BTM_BothEndsSupportSecureConnections { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */) { return return_value; }}; + bool operator()(const RawAddress& bd_addr) { return body(bd_addr); }; +}; +extern struct BTM_BothEndsSupportSecureConnections + BTM_BothEndsSupportSecureConnections; + +// Name: BTM_CanReadDiscoverableCharacteristics +// Params: const RawAddress& bd_addr +// Return: bool +struct BTM_CanReadDiscoverableCharacteristics { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */) { return return_value; }}; + bool operator()(const RawAddress& bd_addr) { return body(bd_addr); }; +}; +extern struct BTM_CanReadDiscoverableCharacteristics + BTM_CanReadDiscoverableCharacteristics; + +// Name: BTM_ConfirmReqReply +// Params: tBTM_STATUS res, const RawAddress& bd_addr +// Return: void +struct BTM_ConfirmReqReply { + std::function body{ + [](tBTM_STATUS /* res */, const RawAddress& /* bd_addr */) {}}; + void operator()(tBTM_STATUS res, const RawAddress& bd_addr) { + body(res, bd_addr); + }; +}; +extern struct BTM_ConfirmReqReply BTM_ConfirmReqReply; + +// Name: BTM_GetClockOffset +// Params: const RawAddress& remote_bda +// Return: uint16_t +struct BTM_GetClockOffset { + static uint16_t return_value; + std::function body{ + [](const RawAddress& /* remote_bda */) { return return_value; }}; + uint16_t operator()(const RawAddress& remote_bda) { + return body(remote_bda); + }; +}; +extern struct BTM_GetClockOffset BTM_GetClockOffset; + +// Name: BTM_GetPeerDeviceTypeFromFeatures +// Params: const RawAddress& bd_addr +// Return: tBT_DEVICE_TYPE +struct BTM_GetPeerDeviceTypeFromFeatures { + static tBT_DEVICE_TYPE return_value; + std::function body{ + [](const RawAddress& /* bd_addr */) { return return_value; }}; + tBT_DEVICE_TYPE operator()(const RawAddress& bd_addr) { + return body(bd_addr); + }; +}; +extern struct BTM_GetPeerDeviceTypeFromFeatures + BTM_GetPeerDeviceTypeFromFeatures; + +// Name: BTM_IsAuthenticated +// Params: const RawAddress& bd_addr, tBT_TRANSPORT transport +// Return: bool +struct BTM_IsAuthenticated { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { + return return_value; + }}; + bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + return body(bd_addr, transport); + }; +}; +extern struct BTM_IsAuthenticated BTM_IsAuthenticated; + +// Name: BTM_IsEncrypted +// Params: const RawAddress& bd_addr, tBT_TRANSPORT transport +// Return: bool +struct BTM_IsEncrypted { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { + return return_value; + }}; + bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + return body(bd_addr, transport); + }; +}; +extern struct BTM_IsEncrypted BTM_IsEncrypted; + +// Name: BTM_IsLinkKeyAuthed +// Params: const RawAddress& bd_addr, tBT_TRANSPORT transport +// Return: bool +struct BTM_IsLinkKeyAuthed { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { + return return_value; + }}; + bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + return body(bd_addr, transport); + }; +}; +extern struct BTM_IsLinkKeyAuthed BTM_IsLinkKeyAuthed; + +// Name: BTM_IsLinkKeyKnown +// Params: const RawAddress& bd_addr, tBT_TRANSPORT transport +// Return: bool +struct BTM_IsLinkKeyKnown { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { + return return_value; + }}; + bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + return body(bd_addr, transport); + }; +}; +extern struct BTM_IsLinkKeyKnown BTM_IsLinkKeyKnown; + +// Name: BTM_PINCodeReply +// Params: const RawAddress& bd_addr, tBTM_STATUS res, uint8_t pin_len, uint8_t* +// p_pin Return: void +struct BTM_PINCodeReply { + std::function + body{[](const RawAddress& /* bd_addr */, tBTM_STATUS /* res */, + uint8_t /* pin_len */, uint8_t* /* p_pin */) {}}; + void operator()(const RawAddress& bd_addr, tBTM_STATUS res, uint8_t pin_len, + uint8_t* p_pin) { + body(bd_addr, res, pin_len, p_pin); + }; +}; +extern struct BTM_PINCodeReply BTM_PINCodeReply; + +// Name: BTM_PasskeyReqReply +// Params: tBTM_STATUS res, const RawAddress& bd_addr, uint32_t passkey +// Return: void +struct BTM_PasskeyReqReply { + std::function + body{[](tBTM_STATUS /* res */, const RawAddress& /* bd_addr */, + uint32_t /* passkey */) {}}; + void operator()(tBTM_STATUS res, const RawAddress& bd_addr, + uint32_t passkey) { + body(res, bd_addr, passkey); + }; +}; +extern struct BTM_PasskeyReqReply BTM_PasskeyReqReply; + +// Name: BTM_PeerSupportsSecureConnections +// Params: const RawAddress& bd_addr +// Return: bool +struct BTM_PeerSupportsSecureConnections { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */) { return return_value; }}; + bool operator()(const RawAddress& bd_addr) { return body(bd_addr); }; +}; +extern struct BTM_PeerSupportsSecureConnections + BTM_PeerSupportsSecureConnections; + +// Name: BTM_ReadLocalOobData +// Params: void +// Return: void +struct BTM_ReadLocalOobData { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct BTM_ReadLocalOobData BTM_ReadLocalOobData; + +// Name: BTM_RemoteOobDataReply +// Params: tBTM_STATUS res, const RawAddress& bd_addr, const Octet16& c, const +// Octet16& r Return: void +struct BTM_RemoteOobDataReply { + std::function + body{[](tBTM_STATUS /* res */, const RawAddress& /* bd_addr */, + const Octet16& /* c */, const Octet16& /* r */) {}}; + void operator()(tBTM_STATUS res, const RawAddress& bd_addr, const Octet16& c, + const Octet16& r) { + body(res, bd_addr, c, r); + }; +}; +extern struct BTM_RemoteOobDataReply BTM_RemoteOobDataReply; + +// Name: BTM_SecAddRmtNameNotifyCallback +// Params: tBTM_RMT_NAME_CALLBACK* p_callback +// Return: bool +struct BTM_SecAddRmtNameNotifyCallback { + static bool return_value; + std::function body{ + [](tBTM_RMT_NAME_CALLBACK* /* p_callback */) { return return_value; }}; + bool operator()(tBTM_RMT_NAME_CALLBACK* p_callback) { + return body(p_callback); + }; +}; +extern struct BTM_SecAddRmtNameNotifyCallback BTM_SecAddRmtNameNotifyCallback; + +// Name: BTM_SecBond +// Params: const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, tBT_TRANSPORT +// transport, tBT_DEVICE_TYPE device_type, uint8_t pin_len, uint8_t* p_pin +// Return: tBTM_STATUS +struct BTM_SecBond { + static tBTM_STATUS return_value; + std::function + body{[](const RawAddress& /* bd_addr */, tBLE_ADDR_TYPE /* addr_type */, + tBT_TRANSPORT /* transport */, + tBT_DEVICE_TYPE /* device_type */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) { + return body(bd_addr, addr_type, transport, device_type); + }; +}; +extern struct BTM_SecBond BTM_SecBond; + +// Name: BTM_SecBondCancel +// Params: const RawAddress& bd_addr +// Return: tBTM_STATUS +struct BTM_SecBondCancel { + static tBTM_STATUS return_value; + std::function body{ + [](const RawAddress& /* bd_addr */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress& bd_addr) { return body(bd_addr); }; +}; +extern struct BTM_SecBondCancel BTM_SecBondCancel; + +// Name: BTM_SecClrService +// Params: uint8_t service_id +// Return: uint8_t +struct BTM_SecClrService { + static uint8_t return_value; + std::function body{ + [](uint8_t /* service_id */) { return return_value; }}; + uint8_t operator()(uint8_t service_id) { return body(service_id); }; +}; +extern struct BTM_SecClrService BTM_SecClrService; + +// Name: BTM_SecClrServiceByPsm +// Params: uint16_t psm +// Return: uint8_t +struct BTM_SecClrServiceByPsm { + static uint8_t return_value; + std::function body{ + [](uint16_t /* psm */) { return return_value; }}; + uint8_t operator()(uint16_t psm) { return body(psm); }; +}; +extern struct BTM_SecClrServiceByPsm BTM_SecClrServiceByPsm; + +// Name: BTM_SecDeleteRmtNameNotifyCallback +// Params: tBTM_RMT_NAME_CALLBACK* p_callback +// Return: bool +struct BTM_SecDeleteRmtNameNotifyCallback { + static bool return_value; + std::function body{ + [](tBTM_RMT_NAME_CALLBACK* /* p_callback */) { return return_value; }}; + bool operator()(tBTM_RMT_NAME_CALLBACK* p_callback) { + return body(p_callback); + }; +}; +extern struct BTM_SecDeleteRmtNameNotifyCallback + BTM_SecDeleteRmtNameNotifyCallback; + +// Name: BTM_SecGetDeviceLinkKeyType +// Params: const RawAddress& bd_addr +// Return: tBTM_LINK_KEY_TYPE +struct BTM_SecGetDeviceLinkKeyType { + static tBTM_LINK_KEY_TYPE return_value; + std::function body{ + [](const RawAddress& /* bd_addr */) { return return_value; }}; + tBTM_LINK_KEY_TYPE operator()(const RawAddress& bd_addr) { + return body(bd_addr); + }; +}; +extern struct BTM_SecGetDeviceLinkKeyType BTM_SecGetDeviceLinkKeyType; + +// Name: BTM_SecIsSecurityPending +// Params: const RawAddress& bd_addr +// Return: bool +struct BTM_SecIsSecurityPending { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */) { return return_value; }}; + bool operator()(const RawAddress& bd_addr) { return body(bd_addr); }; +}; +extern struct BTM_SecIsSecurityPending BTM_SecIsSecurityPending; + +// Name: BTM_SecRegister +// Params: const tBTM_APPL_INFO* p_cb_info +// Return: bool +struct BTM_SecRegister { + static bool return_value; + std::function body{ + [](const tBTM_APPL_INFO* /* p_cb_info */) { return return_value; }}; + bool operator()(const tBTM_APPL_INFO* p_cb_info) { return body(p_cb_info); }; +}; +extern struct BTM_SecRegister BTM_SecRegister; + +// Name: BTM_SetEncryption +// Params: const RawAddress& bd_addr, tBT_TRANSPORT transport, +// tBTM_SEC_CALLBACK* p_callback, void* p_ref_data, tBTM_BLE_SEC_ACT sec_act +// Return: tBTM_STATUS struct BTM_SetEncryption { + static tBTM_STATUS return_value; std::function - body{}; + body{[](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */, + tBTM_SEC_CALLBACK* /* p_callback */, void* /* p_ref_data */, + tBTM_BLE_SEC_ACT /* sec_act */) { return return_value; }}; tBTM_STATUS operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport, tBTM_SEC_CALLBACK* p_callback, void* p_ref_data, tBTM_BLE_SEC_ACT sec_act) { @@ -41,6 +369,533 @@ struct BTM_SetEncryption { }; extern struct BTM_SetEncryption BTM_SetEncryption; +// Name: BTM_SetPinType +// Params: uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len +// Return: void +struct BTM_SetPinType { + std::function + body{[](uint8_t /* pin_type */, PIN_CODE /* pin_code */, + uint8_t /* pin_code_len */) {}}; + void operator()(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len) { + body(pin_type, pin_code, pin_code_len); + }; +}; +extern struct BTM_SetPinType BTM_SetPinType; + +// Name: BTM_SetSecurityLevel +// Params: bool is_originator, const char* p_name, uint8_t service_id, uint16_t +// sec_level, uint16_t psm, uint32_t mx_proto_id, uint32_t mx_chan_id Return: +// bool +struct BTM_SetSecurityLevel { + static bool return_value; + std::function + body{[](bool /* is_originator */, const char* /* p_name */, + uint8_t /* service_id */, uint16_t /* sec_level */, + uint16_t /* psm */, uint32_t /* mx_proto_id */, + uint32_t /* mx_chan_id */) { return return_value; }}; + bool operator()(bool is_originator, const char* p_name, uint8_t service_id, + uint16_t sec_level, uint16_t psm, uint32_t mx_proto_id, + uint32_t mx_chan_id) { + return body(is_originator, p_name, service_id, sec_level, psm, mx_proto_id, + mx_chan_id); + }; +}; +extern struct BTM_SetSecurityLevel BTM_SetSecurityLevel; + +// Name: BTM_update_version_info +// Params: const RawAddress& bd_addr, const remote_version_info& +// remote_version_info Return: void +struct BTM_update_version_info { + std::function + body{[](const RawAddress& /* bd_addr */, + const remote_version_info& /* remote_version_info */) {}}; + void operator()(const RawAddress& bd_addr, + const remote_version_info& remote_version_info) { + body(bd_addr, remote_version_info); + }; +}; +extern struct BTM_update_version_info BTM_update_version_info; + +// Name: NotifyBondingCanceled +// Params: tBTM_STATUS btm_status +// Return: void +struct NotifyBondingCanceled { + std::function body{ + [](tBTM_STATUS /* btm_status */) {}}; + void operator()(tBTM_STATUS btm_status) { body(btm_status); }; +}; +extern struct NotifyBondingCanceled NotifyBondingCanceled; + +// Name: btm_create_conn_cancel_complete +// Params: uint8_t status, RawAddress bd_addr +// Return: void +struct btm_create_conn_cancel_complete { + std::function body{ + [](uint8_t /* status */, const RawAddress /* bd_addr */) {}}; + void operator()(uint8_t status, const RawAddress bd_addr) { + body(status, bd_addr); + }; +}; +extern struct btm_create_conn_cancel_complete btm_create_conn_cancel_complete; + +// Name: btm_get_dev_class +// Params: const RawAddress& bda +// Return: const uint8_t* +struct btm_get_dev_class { + static const uint8_t* return_value; + std::function body{ + [](const RawAddress& /* bda */) { return return_value; }}; + const uint8_t* operator()(const RawAddress& bda) { return body(bda); }; +}; +extern struct btm_get_dev_class btm_get_dev_class; + +// Name: btm_io_capabilities_req +// Params: RawAddress p +// Return: void +struct btm_io_capabilities_req { + std::function body{[](RawAddress /* p */) {}}; + void operator()(RawAddress p) { body(p); }; +}; +extern struct btm_io_capabilities_req btm_io_capabilities_req; + +// Name: btm_io_capabilities_rsp +// Params: tBTM_SP_IO_RSP evt_data +// Return: void +struct btm_io_capabilities_rsp { + std::function body{ + [](const tBTM_SP_IO_RSP /* evt_data */) {}}; + void operator()(const tBTM_SP_IO_RSP evt_data) { body(evt_data); }; +}; +extern struct btm_io_capabilities_rsp btm_io_capabilities_rsp; + +// Name: btm_proc_sp_req_evt +// Params: tBTM_SP_EVT event, const uint8_t* p +// Return: void +struct btm_proc_sp_req_evt { + std::function + body{[](tBTM_SP_EVT /* event */, const RawAddress /* bda */, + uint32_t /* value */) {}}; + void operator()(tBTM_SP_EVT event, const RawAddress bda, uint32_t value) { + body(event, bda, value); + }; +}; +extern struct btm_proc_sp_req_evt btm_proc_sp_req_evt; + +// Name: btm_read_local_oob_complete +// Params: +// tBTM_SP_LOC_OOB evt_data; +// uint8_t status; +// Return: void +struct btm_read_local_oob_complete { + std::function body{ + [](const tBTM_SP_LOC_OOB /* evt_data */) {}}; + void operator()(const tBTM_SP_LOC_OOB evt_data) { body(evt_data); }; +}; +extern struct btm_read_local_oob_complete btm_read_local_oob_complete; + +// Name: btm_rem_oob_req +// Params: RawAddress bda +// Return: void +struct btm_rem_oob_req { + std::function body{ + [](const RawAddress /* bda */) {}}; + void operator()(const RawAddress bda) { body(bda); }; +}; +extern struct btm_rem_oob_req btm_rem_oob_req; + +// Name: btm_sec_abort_access_req +// Params: const RawAddress& bd_addr +// Return: void +struct btm_sec_abort_access_req { + std::function body{ + [](const RawAddress& /* bd_addr */) {}}; + void operator()(const RawAddress& bd_addr) { body(bd_addr); }; +}; +extern struct btm_sec_abort_access_req btm_sec_abort_access_req; + +// Name: btm_sec_auth_complete +// Params: uint16_t handle, tHCI_STATUS status +// Return: void +struct btm_sec_auth_complete { + std::function body{ + [](uint16_t /* handle */, tHCI_STATUS /* status */) {}}; + void operator()(uint16_t handle, tHCI_STATUS status) { + body(handle, status); + }; +}; +extern struct btm_sec_auth_complete btm_sec_auth_complete; + +// Name: btm_sec_bond_by_transport +// Params: const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, tBT_TRANSPORT +// transport, uint8_t pin_len, uint8_t* p_pin Return: tBTM_STATUS +struct btm_sec_bond_by_transport { + static tBTM_STATUS return_value; + std::function + body{[](const RawAddress& /* bd_addr */, tBLE_ADDR_TYPE /* addr_type */, + tBT_TRANSPORT /* transport */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_TRANSPORT transport) { + return body(bd_addr, addr_type, transport); + }; +}; +extern struct btm_sec_bond_by_transport btm_sec_bond_by_transport; + +// Name: btm_sec_check_pending_reqs +// Params: void +// Return: void +struct btm_sec_check_pending_reqs { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_sec_check_pending_reqs btm_sec_check_pending_reqs; + +// Name: btm_sec_clear_ble_keys +// Params: tBTM_SEC_DEV_REC* p_dev_rec +// Return: void +struct btm_sec_clear_ble_keys { + std::function body{ + [](tBTM_SEC_DEV_REC* /* p_dev_rec */) {}}; + void operator()(tBTM_SEC_DEV_REC* p_dev_rec) { body(p_dev_rec); }; +}; +extern struct btm_sec_clear_ble_keys btm_sec_clear_ble_keys; + +// Name: btm_sec_conn_req +// Params: const RawAddress& bda, const DEV_CLASS dc +// Return: void +struct btm_sec_conn_req { + std::function body{ + [](const RawAddress& /* bda */, const DEV_CLASS /* dc */) {}}; + void operator()(const RawAddress& bda, const DEV_CLASS dc) { body(bda, dc); }; +}; +extern struct btm_sec_conn_req btm_sec_conn_req; + +// Name: btm_sec_connected +// Params: const RawAddress& bda, uint16_t handle, tHCI_STATUS status, uint8_t +// enc_mode, tHCI_ROLE assigned_role Return: void +struct btm_sec_connected { + std::function + body{[](const RawAddress& /* bda */, uint16_t /* handle */, + tHCI_STATUS /* status */, uint8_t /* enc_mode */, + tHCI_ROLE /* assigned_role */) {}}; + void operator()(const RawAddress& bda, uint16_t handle, tHCI_STATUS status, + uint8_t enc_mode, tHCI_ROLE assigned_role) { + body(bda, handle, status, enc_mode, assigned_role); + }; +}; +extern struct btm_sec_connected btm_sec_connected; + +// Name: btm_sec_cr_loc_oob_data_cback_event +// Params: const RawAddress& address, tSMP_LOC_OOB_DATA loc_oob_data +// Return: void +struct btm_sec_cr_loc_oob_data_cback_event { + std::function + body{[](const RawAddress& /* address */, + tSMP_LOC_OOB_DATA /* loc_oob_data */) {}}; + void operator()(const RawAddress& address, tSMP_LOC_OOB_DATA loc_oob_data) { + body(address, loc_oob_data); + }; +}; +extern struct btm_sec_cr_loc_oob_data_cback_event + btm_sec_cr_loc_oob_data_cback_event; + +// Name: btm_sec_dev_rec_cback_event +// Params: tBTM_SEC_DEV_REC* p_dev_rec, tBTM_STATUS btm_status, bool +// is_le_transport Return: void +struct btm_sec_dev_rec_cback_event { + std::function + body{[](tBTM_SEC_DEV_REC* /* p_dev_rec */, tBTM_STATUS /* btm_status */, + bool /* is_le_transport */) {}}; + void operator()(tBTM_SEC_DEV_REC* p_dev_rec, tBTM_STATUS btm_status, + bool is_le_transport) { + body(p_dev_rec, btm_status, is_le_transport); + }; +}; +extern struct btm_sec_dev_rec_cback_event btm_sec_dev_rec_cback_event; + +// Name: btm_sec_dev_reset +// Params: void +// Return: void +struct btm_sec_dev_reset { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btm_sec_dev_reset btm_sec_dev_reset; + +// Name: btm_sec_disconnect +// Params: uint16_t handle, tHCI_STATUS reason, std::string comment +// Return: tBTM_STATUS +struct btm_sec_disconnect { + static tBTM_STATUS return_value; + std::function + body{[](uint16_t /* handle */, tHCI_STATUS /* reason */, + std::string /* comment */) { return return_value; }}; + tBTM_STATUS operator()(uint16_t handle, tHCI_STATUS reason, + std::string comment) { + return body(handle, reason, comment); + }; +}; +extern struct btm_sec_disconnect btm_sec_disconnect; + +// Name: btm_sec_disconnected +// Params: uint16_t handle, tHCI_REASON reason, std::string comment +// Return: void +struct btm_sec_disconnected { + std::function + body{[](uint16_t /* handle */, tHCI_REASON /* reason */, + std::string /* comment */) {}}; + void operator()(uint16_t handle, tHCI_REASON reason, std::string comment) { + body(handle, reason, comment); + }; +}; +extern struct btm_sec_disconnected btm_sec_disconnected; + +// Name: btm_sec_encrypt_change +// Params: uint16_t handle, tHCI_STATUS status, uint8_t encr_enable +// Return: void +struct btm_sec_encrypt_change { + std::function + body{[](uint16_t /* handle */, tHCI_STATUS /* status */, + uint8_t /* encr_enable */) {}}; + void operator()(uint16_t handle, tHCI_STATUS status, uint8_t encr_enable) { + body(handle, status, encr_enable); + }; +}; +extern struct btm_sec_encrypt_change btm_sec_encrypt_change; + +// Name: btm_sec_is_a_bonded_dev +// Params: const RawAddress& bda +// Return: bool +struct btm_sec_is_a_bonded_dev { + static bool return_value; + std::function body{ + [](const RawAddress& /* bda */) { return return_value; }}; + bool operator()(const RawAddress& bda) { return body(bda); }; +}; +extern struct btm_sec_is_a_bonded_dev btm_sec_is_a_bonded_dev; + +// Name: btm_sec_l2cap_access_req +// Params: const RawAddress& bd_addr, uint16_t psm, bool is_originator, +// tBTM_SEC_CALLBACK* p_callback, void* p_ref_data Return: tBTM_STATUS +struct btm_sec_l2cap_access_req { + static tBTM_STATUS return_value; + std::function + body{[](const RawAddress& /* bd_addr */, uint16_t /* psm */, + bool /* is_originator */, tBTM_SEC_CALLBACK* /* p_callback */, + void* /* p_ref_data */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress& bd_addr, uint16_t psm, + bool is_originator, tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data) { + return body(bd_addr, psm, is_originator, p_callback, p_ref_data); + }; +}; +extern struct btm_sec_l2cap_access_req btm_sec_l2cap_access_req; + +// Name: btm_sec_l2cap_access_req_by_requirement +// Params: const RawAddress& bd_addr, uint16_t security_required, bool +// is_originator, tBTM_SEC_CALLBACK* p_callback, void* p_ref_data Return: +// tBTM_STATUS +struct btm_sec_l2cap_access_req_by_requirement { + static tBTM_STATUS return_value; + std::function + body{[](const RawAddress& /* bd_addr */, uint16_t /* security_required */, + bool /* is_originator */, tBTM_SEC_CALLBACK* /* p_callback */, + void* /* p_ref_data */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress& bd_addr, uint16_t security_required, + bool is_originator, tBTM_SEC_CALLBACK* p_callback, + void* p_ref_data) { + return body(bd_addr, security_required, is_originator, p_callback, + p_ref_data); + }; +}; +extern struct btm_sec_l2cap_access_req_by_requirement + btm_sec_l2cap_access_req_by_requirement; + +// Name: btm_sec_link_key_notification +// Params: const RawAddress& p_bda, const Octet16& link_key, uint8_t key_type +// Return: void +struct btm_sec_link_key_notification { + std::function + body{[](const RawAddress& /* p_bda */, const Octet16& /* link_key */, + uint8_t /* key_type */) {}}; + void operator()(const RawAddress& p_bda, const Octet16& link_key, + uint8_t key_type) { + body(p_bda, link_key, key_type); + }; +}; +extern struct btm_sec_link_key_notification btm_sec_link_key_notification; + +// Name: btm_sec_encryption_key_refresh_complete +// Params: uint16_t handle, tHCI_STATUS status +// Return: void +struct btm_sec_encryption_key_refresh_complete { + std::function body{ + [](uint16_t /* handle */, tHCI_STATUS /* status */) -> void {}}; + void operator()(uint16_t handle, tHCI_STATUS status) { + body(handle, status); + }; +}; +extern struct btm_sec_encryption_key_refresh_complete + btm_sec_encryption_key_refresh_complete; + +// Name: btm_sec_link_key_request +// Params: const uint8_t* p_event +// Return: void +struct btm_sec_link_key_request { + std::function body{ + [](const RawAddress /* bda */) {}}; + void operator()(const RawAddress bda) { body(bda); }; +}; +extern struct btm_sec_link_key_request btm_sec_link_key_request; + +// Name: btm_sec_mx_access_request +// Params: const RawAddress& bd_addr, bool is_originator, uint16_t +// security_required, tBTM_SEC_CALLBACK* p_callback, void* p_ref_data Return: +// tBTM_STATUS +struct btm_sec_mx_access_request { + static tBTM_STATUS return_value; + std::function + body{[](const RawAddress& /* bd_addr */, bool /* is_originator */, + uint16_t /* security_required */, + tBTM_SEC_CALLBACK* /* p_callback */, + void* /* p_ref_data */) { return return_value; }}; + tBTM_STATUS operator()(const RawAddress& bd_addr, bool is_originator, + uint16_t security_required, + tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) { + return body(bd_addr, is_originator, security_required, p_callback, + p_ref_data); + }; +}; +extern struct btm_sec_mx_access_request btm_sec_mx_access_request; + +// Name: btm_sec_pin_code_request +// Params: const uint8_t* p_event +// Return: void +struct btm_sec_pin_code_request { + std::function body{ + [](const RawAddress /* bda */) {}}; + void operator()(const RawAddress bda) { body(bda); }; +}; +extern struct btm_sec_pin_code_request btm_sec_pin_code_request; + +// Name: btm_sec_rmt_host_support_feat_evt +// Params: const uint8_t* p +// Return: void +struct btm_sec_rmt_host_support_feat_evt { + std::function body{ + [](const RawAddress /* bd_addr */, uint8_t /* features_0 */) {}}; + void operator()(const RawAddress bd_addr, uint8_t features_0) { + body(bd_addr, features_0); + }; +}; +extern struct btm_sec_rmt_host_support_feat_evt + btm_sec_rmt_host_support_feat_evt; + +// Name: btm_sec_rmt_name_request_complete +// Params: const RawAddress* p_bd_addr, const uint8_t* p_bd_name, tHCI_STATUS +// status Return: void +struct btm_sec_rmt_name_request_complete { + std::function + body{[](const RawAddress* /* p_bd_addr */, const uint8_t* /* p_bd_name */, + tHCI_STATUS /* status */) {}}; + void operator()(const RawAddress* p_bd_addr, const uint8_t* p_bd_name, + tHCI_STATUS status) { + body(p_bd_addr, p_bd_name, status); + }; +}; +extern struct btm_sec_rmt_name_request_complete + btm_sec_rmt_name_request_complete; + +// Name: btm_sec_role_changed +// Params: tHCI_STATUS hci_status, const RawAddress& bd_addr, tHCI_ROLE new_role +// Return: void +struct btm_sec_role_changed { + std::function + body{[](tHCI_STATUS /* hci_status */, const RawAddress& /* bd_addr */, + tHCI_ROLE /* new_role */) {}}; + void operator()(tHCI_STATUS hci_status, const RawAddress& bd_addr, + tHCI_ROLE new_role) { + body(hci_status, bd_addr, new_role); + }; +}; +extern struct btm_sec_role_changed btm_sec_role_changed; + +// Name: btm_sec_set_peer_sec_caps +// Params: uint16_t hci_handle, bool ssp_supported, bool sc_supported, bool +// hci_role_switch_supported, bool br_edr_supported, bool le_supported Return: +// void +struct btm_sec_set_peer_sec_caps { + std::function + body{[](uint16_t /* hci_handle */, bool /* ssp_supported */, + bool /* sc_supported */, bool /* hci_role_switch_supported */, + bool /* br_edr_supported */, bool /* le_supported */) {}}; + void operator()(uint16_t hci_handle, bool ssp_supported, bool sc_supported, + bool hci_role_switch_supported, bool br_edr_supported, + bool le_supported) { + body(hci_handle, ssp_supported, sc_supported, hci_role_switch_supported, + br_edr_supported, le_supported); + }; +}; +extern struct btm_sec_set_peer_sec_caps btm_sec_set_peer_sec_caps; + +// Name: btm_sec_update_clock_offset +// Params: uint16_t handle, uint16_t clock_offset +// Return: void +struct btm_sec_update_clock_offset { + std::function body{ + [](uint16_t /* handle */, uint16_t /* clock_offset */) {}}; + void operator()(uint16_t handle, uint16_t clock_offset) { + body(handle, clock_offset); + }; +}; +extern struct btm_sec_update_clock_offset btm_sec_update_clock_offset; + +// Name: btm_simple_pair_complete +// Params: RawAddress bd_addr, uint8_t status +// Return: void +struct btm_simple_pair_complete { + std::function body{ + [](const RawAddress /* bd_addr */, uint8_t /* status */) {}}; + void operator()(const RawAddress bd_addr, uint8_t status) { + body(bd_addr, status); + }; +}; +extern struct btm_simple_pair_complete btm_simple_pair_complete; + +// Name: BTM_IsRemoteNameKnown +// Params: const RawAddress& bd_addr, tBT_TRANSPORT transport +// Return: bool +struct BTM_IsRemoteNameKnown { + static bool return_value; + std::function body{ + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { + return return_value; + }}; + bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { + return body(bd_addr, transport); + }; +}; +extern struct BTM_IsRemoteNameKnown BTM_IsRemoteNameKnown; + } // namespace stack_btm_sec } // namespace mock } // namespace test + +// END mockcify generation diff --git a/system/test/mock/mock_stack_btu_hcif.cc b/system/test/mock/mock_stack_btu_hcif.cc index 40d0bf4a9f84c02bf4ece87a0ff382eed7a55c91..ba9967917c8a314cf398a89a19c79e30baebc9fa 100644 --- a/system/test/mock/mock_stack_btu_hcif.cc +++ b/system/test/mock/mock_stack_btu_hcif.cc @@ -20,8 +20,6 @@ */ #include -#include -#include #define LOG_TAG "bt_btu_hcif" #include @@ -29,12 +27,9 @@ #include #include "stack/include/bt_hdr.h" +#include "stack/include/btu_hcif.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - using hci_cmd_cb = base::OnceCallback; @@ -43,13 +38,10 @@ struct cmd_with_cb_data { base::Location posted_from; }; -void btu_hcif_log_event_metrics(uint8_t evt_code, uint8_t* p_event) { - inc_func_call_count(__func__); -} -void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_msg) { +void btu_hcif_process_event(uint8_t controller_id, BT_HDR* p_msg) { inc_func_call_count(__func__); } -void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, const BT_HDR* p_buf) { +void btu_hcif_send_cmd(uint8_t controller_id, const BT_HDR* p_buf) { inc_func_call_count(__func__); } void btu_hcif_send_cmd_with_cb(const base::Location& posted_from, diff --git a/system/test/mock/mock_stack_crypto_toolbox.cc b/system/test/mock/mock_stack_crypto_toolbox.cc deleted file mode 100644 index ccdd43d629fa89a609a57e55edd6e0ad8858f3b3..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_stack_crypto_toolbox.cc +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:8 - * - * mockcify.pl ver 0.2 - */ - -#include -#include -#include -#include - -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_crypto_toolbox.h" - -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -// Mocked internal structures, if any - -namespace test { -namespace mock { -namespace stack_crypto_toolbox { - -// Function state capture and return values, if needed -struct h6 h6; -struct h7 h7; -struct f4 f4; -struct f5 f5; -struct f6 f6; -struct g2 g2; -struct ltk_to_link_key ltk_to_link_key; -struct link_key_to_ltk link_key_to_ltk; - -} // namespace stack_crypto_toolbox -} // namespace mock -} // namespace test - -// Mocked functions, if any -Octet16 h6(const Octet16& w, std::array keyid) { - inc_func_call_count(__func__); - return test::mock::stack_crypto_toolbox::h6(w, keyid); -} -Octet16 h7(const Octet16& salt, const Octet16& w) { - inc_func_call_count(__func__); - return test::mock::stack_crypto_toolbox::h7(salt, w); -} -Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z) { - inc_func_call_count(__func__); - return test::mock::stack_crypto_toolbox::f4(u, v, x, z); -} -void f5(const uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, - uint8_t* a2, Octet16* mac_key, Octet16* ltk) { - inc_func_call_count(__func__); - test::mock::stack_crypto_toolbox::f5(w, n1, n2, a1, a2, mac_key, ltk); -} -Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2, - const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2) { - inc_func_call_count(__func__); - return test::mock::stack_crypto_toolbox::f6(w, n1, n2, r, iocap, a1, a2); -} -uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x, - const Octet16& y) { - inc_func_call_count(__func__); - return test::mock::stack_crypto_toolbox::g2(u, v, x, y); -} -Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7) { - inc_func_call_count(__func__); - return test::mock::stack_crypto_toolbox::ltk_to_link_key(ltk, use_h7); -} -Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7) { - inc_func_call_count(__func__); - return test::mock::stack_crypto_toolbox::link_key_to_ltk(link_key, use_h7); -} - -// END mockcify generation diff --git a/system/test/mock/mock_stack_crypto_toolbox.h b/system/test/mock/mock_stack_crypto_toolbox.h deleted file mode 100644 index f8375e5a69fd6e5662273c7508e3f257a51d253c..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_stack_crypto_toolbox.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:8 - * - * mockcify.pl ver 0.2 - */ - -#include -#include -#include -#include - -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include -#include - -#include - -#include "stack/crypto_toolbox/aes.h" -#include "stack/crypto_toolbox/crypto_toolbox.h" -#include "test/common/mock_functions.h" - -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -namespace test { -namespace mock { -namespace stack_crypto_toolbox { - -// Shared state between mocked functions and tests -// Name: h6 -// Params: const Octet16& w, std::array keyid -// Returns: Octet16 -struct h6 { - Octet16 octet16; - std::function keyid)> body{ - [this](const Octet16& w, std::array keyid) { - return octet16; - }}; - Octet16 operator()(const Octet16& w, std::array keyid) { - return body(w, keyid); - }; -}; -extern struct h6 h6; -// Name: h7 -// Params: const Octet16& salt, const Octet16& w -// Returns: Octet16 -struct h7 { - Octet16 octet16; - std::function body{ - [this](const Octet16& salt, const Octet16& w) { return octet16; }}; - Octet16 operator()(const Octet16& salt, const Octet16& w) { - return body(salt, w); - }; -}; -extern struct h7 h7; -// Name: f4 -// Params: const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z -// Returns: Octet16 -struct f4 { - Octet16 octet16; - std::function - body{[this](const uint8_t* u, const uint8_t* v, const Octet16& x, - uint8_t z) { return octet16; }}; - Octet16 operator()(const uint8_t* u, const uint8_t* v, const Octet16& x, - uint8_t z) { - return body(u, v, x, z); - }; -}; -extern struct f4 f4; -// Name: f5 -// Params: const uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, -// uint8_t* a2, Octet16* mac_key, Octet16* ltk Returns: void -struct f5 { - std::function - body{[](const uint8_t* w, const Octet16& n1, const Octet16& n2, - uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk) {}}; - void operator()(const uint8_t* w, const Octet16& n1, const Octet16& n2, - uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk) { - body(w, n1, n2, a1, a2, mac_key, ltk); - }; -}; -extern struct f5 f5; -// Name: f6 -// Params: const Octet16& w, const Octet16& n1, const Octet16& n2, const -// Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2 Returns: Octet16 -struct f6 { - Octet16 octet16; - std::function - body{[this](const Octet16& w, const Octet16& n1, const Octet16& n2, - const Octet16& r, uint8_t* iocap, uint8_t* a1, - uint8_t* a2) { return octet16; }}; - Octet16 operator()(const Octet16& w, const Octet16& n1, const Octet16& n2, - const Octet16& r, uint8_t* iocap, uint8_t* a1, - uint8_t* a2) { - return body(w, n1, n2, r, iocap, a1, a2); - }; -}; -extern struct f6 f6; -// Name: g2 -// Params: const uint8_t* u, const uint8_t* v, const Octet16& x, const Octet16& -// y Returns: uint32_t -struct g2 { - std::function - body{[](const uint8_t* u, const uint8_t* v, const Octet16& x, - const Octet16& y) { return 0; }}; - uint32_t operator()(const uint8_t* u, const uint8_t* v, const Octet16& x, - const Octet16& y) { - return body(u, v, x, y); - }; -}; -extern struct g2 g2; -// Name: ltk_to_link_key -// Params: const Octet16& ltk, bool use_h7 -// Returns: Octet16 -struct ltk_to_link_key { - Octet16 octet16; - std::function body{ - [this](const Octet16& ltk, bool use_h7) { return octet16; }}; - Octet16 operator()(const Octet16& ltk, bool use_h7) { - return body(ltk, use_h7); - }; -}; -extern struct ltk_to_link_key ltk_to_link_key; -// Name: link_key_to_ltk -// Params: const Octet16& link_key, bool use_h7 -// Returns: Octet16 -struct link_key_to_ltk { - Octet16 octet16; - std::function body{ - [this](const Octet16& link_key, bool use_h7) { return octet16; }}; - Octet16 operator()(const Octet16& link_key, bool use_h7) { - return body(link_key, use_h7); - }; -}; -extern struct link_key_to_ltk link_key_to_ltk; - -} // namespace stack_crypto_toolbox -} // namespace mock -} // namespace test - -// END mockcify generation diff --git a/system/test/mock/mock_stack_gap_ble.cc b/system/test/mock/mock_stack_gap_ble.cc index 505d8bab69dc291f4a23bfd1eb88e949df0252a5..09ef941ffdd1312b238ed0cc4f8cb8f92d33d9c6 100644 --- a/system/test/mock/mock_stack_gap_ble.cc +++ b/system/test/mock/mock_stack_gap_ble.cc @@ -20,31 +20,26 @@ */ #include -#include -#include #include "stack/include/gap_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool GAP_BleCancelReadPeerDevName(const RawAddress& peer_bda) { +bool GAP_BleCancelReadPeerDevName(const RawAddress& /* peer_bda */) { inc_func_call_count(__func__); return false; } -bool GAP_BleReadPeerDevName(const RawAddress& peer_bda, - tGAP_BLE_CMPL_CBACK* p_cback) { +bool GAP_BleReadPeerDevName(const RawAddress& /* peer_bda */, + tGAP_BLE_CMPL_CBACK* /* p_cback */) { inc_func_call_count(__func__); return false; } -bool GAP_BleReadPeerPrefConnParams(const RawAddress& peer_bda) { +bool GAP_BleReadPeerPrefConnParams(const RawAddress& /* peer_bda */) { inc_func_call_count(__func__); return false; } -void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE* p_value) { +void GAP_BleAttrDBUpdate(uint16_t /* attr_uuid */, + tGAP_BLE_ATTR_VALUE* /* p_value */) { inc_func_call_count(__func__); } void gap_attr_db_init(void) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_gap_conn.cc b/system/test/mock/mock_stack_gap_conn.cc index f798d5158845940216ca148ba2c51d3b3850a7b4..2fe6d339c98ad0973c26915bba9b1d79ec0776a0 100644 --- a/system/test/mock/mock_stack_gap_conn.cc +++ b/system/test/mock/mock_stack_gap_conn.cc @@ -20,65 +20,53 @@ */ #include -#include -#include -#include - -#include "bt_target.h" -#include "device/include/controller.h" #include "gap_api.h" #include "l2c_api.h" -#include "l2cdefs.h" -#include "osi/include/fixed_queue.h" -#include "osi/include/mutex.h" -#include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -const RawAddress* GAP_ConnGetRemoteAddr(uint16_t gap_handle) { +const RawAddress* GAP_ConnGetRemoteAddr(uint16_t /* gap_handle */) { inc_func_call_count(__func__); return nullptr; } -int GAP_GetRxQueueCnt(uint16_t handle, uint32_t* p_rx_queue_count) { +int GAP_GetRxQueueCnt(uint16_t /* handle */, uint32_t* /* p_rx_queue_count */) { inc_func_call_count(__func__); return 0; } -uint16_t GAP_ConnClose(uint16_t gap_handle) { +uint16_t GAP_ConnClose(uint16_t /* gap_handle */) { inc_func_call_count(__func__); return 0; } -uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle) { +uint16_t GAP_ConnGetL2CAPCid(uint16_t /* gap_handle */) { inc_func_call_count(__func__); return 0; } -uint16_t GAP_ConnGetRemMtuSize(uint16_t gap_handle) { +uint16_t GAP_ConnGetRemMtuSize(uint16_t /* gap_handle */) { inc_func_call_count(__func__); return 0; } -uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id, - bool is_server, const RawAddress* p_rem_bda, uint16_t psm, - uint16_t le_mps, tL2CAP_CFG_INFO* p_cfg, - tL2CAP_ERTM_INFO* ertm_info, uint16_t security, - tGAP_CONN_CALLBACK* p_cb, tBT_TRANSPORT transport) { +uint16_t GAP_ConnOpen(const char* /* p_serv_name */, uint8_t /* service_id */, + bool /* is_server */, const RawAddress* /* p_rem_bda */, + uint16_t /* psm */, uint16_t /* le_mps */, + tL2CAP_CFG_INFO* /* p_cfg */, + tL2CAP_ERTM_INFO* /* ertm_info */, + uint16_t /* security */, tGAP_CONN_CALLBACK* /* p_cb */, + tBT_TRANSPORT /* transport */) { inc_func_call_count(__func__); return 0; } -uint16_t GAP_ConnReadData(uint16_t gap_handle, uint8_t* p_data, - uint16_t max_len, uint16_t* p_len) { +uint16_t GAP_ConnReadData(uint16_t /* gap_handle */, uint8_t* /* p_data */, + uint16_t /* max_len */, uint16_t* /* p_len */) { inc_func_call_count(__func__); return 0; } -uint16_t GAP_ConnWriteData(uint16_t gap_handle, BT_HDR* msg) { +uint16_t GAP_ConnWriteData(uint16_t /* gap_handle */, BT_HDR* /* msg */) { inc_func_call_count(__func__); return 0; } void GAP_Init(void) { inc_func_call_count(__func__); } -void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent) { +void gap_tx_complete_ind(uint16_t /* l2cap_cid */, uint16_t /* sdu_sent */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_gatt.cc b/system/test/mock/mock_stack_gatt.cc index ce1e15bb9ddaea60230fc5809fcf187151c7ce7e..efee8f44f6e2b65a120e175c40658bbf07bee253 100644 --- a/system/test/mock/mock_stack_gatt.cc +++ b/system/test/mock/mock_stack_gatt.cc @@ -20,31 +20,24 @@ */ #include -#include -#include #include "stack/gatt/gatt_int.h" #include "stack/include/gatt_api.h" #include "test/common/mock_functions.h" #include "types/bluetooth/uuid.h" -#include "types/bt_transport.h" -#include "types/raw_address.h" using namespace bluetooth; tGATT_HDL_LIST_ELEM elem; // gatt_add_an_item_to_list -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t s_handle) { +tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t /* s_handle */) { inc_func_call_count(__func__); return elem; } -tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type, - uint16_t start_handle, uint16_t end_handle, - const Uuid& uuid) { +tGATT_STATUS GATTC_Discover(uint16_t /* conn_id */, + tGATT_DISC_TYPE /* disc_type */, + uint16_t /* start_handle */, + uint16_t /* end_handle */, const Uuid& /* uuid */) { inc_func_call_count(__func__); return GATT_SUCCESS; } diff --git a/system/test/mock/mock_stack_gatt_api.cc b/system/test/mock/mock_stack_gatt_api.cc index 902b8376e52abb23bb8fe75b6f695111ceba345b..da4b93afea40ac6c49eb41123ccc5e4279f596b9 100644 --- a/system/test/mock/mock_stack_gatt_api.cc +++ b/system/test/mock/mock_stack_gatt_api.cc @@ -19,14 +19,13 @@ * * mockcify.pl ver 0.5.0 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_gatt_api.h" #include -#include -#include #include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_gatt_api.h" +#include "test/common/mock_functions.h" // Original usings using bluetooth::Uuid; diff --git a/system/test/mock/mock_stack_gatt_api.h b/system/test/mock/mock_stack_gatt_api.h index e6f51f2941b990547746a6f70b4197c358f09e11..51db2c887394f72f3b1f88c2e70e9d8018bcc918 100644 --- a/system/test/mock/mock_stack_gatt_api.h +++ b/system/test/mock/mock_stack_gatt_api.h @@ -24,32 +24,16 @@ #include #include -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. #include #include #include #include -#include "bt_target.h" -#include "device/include/controller.h" -#include "l2c_api.h" -#include "main/shim/dumpsys.h" -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "stack/gatt/connection_manager.h" -#include "stack/gatt/gatt_int.h" -#include "stack/include/bt_hdr.h" #include "stack/include/gatt_api.h" -#include "test/common/mock_functions.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -70,7 +54,7 @@ namespace stack_gatt_api { struct GATTC_GetAndRemoveListOfConnIdsWaitingForMtuRequest { static std::list return_value; std::function(const RawAddress& remote_bda)> body{ - [](const RawAddress& remote_bda) { return return_value; }}; + [](const RawAddress& /* remote_bda */) { return return_value; }}; std::list operator()(const RawAddress& remote_bda) { return body(remote_bda); }; @@ -88,9 +72,9 @@ struct GATTC_TryMtuRequest { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport, - uint16_t conn_id, - uint16_t* current_mtu) { return return_value; }}; + body{[](const RawAddress& /* remote_bda */, tBT_TRANSPORT /* transport */, + uint16_t /* conn_id */, + uint16_t* /* current_mtu */) { return return_value; }}; tGATTC_TryMtuRequestResult operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport, uint16_t conn_id, @@ -108,8 +92,8 @@ extern struct GATTC_TryMtuRequest GATTC_TryMtuRequest; struct GATTC_UpdateUserAttMtuIfNeeded { std::function - body{[](const RawAddress& remote_bda, tBT_TRANSPORT transport, - uint16_t user_mtu) {}}; + body{[](const RawAddress& /* remote_bda */, tBT_TRANSPORT /* transport */, + uint16_t /* user_mtu */) {}}; void operator()(const RawAddress& remote_bda, tBT_TRANSPORT transport, uint16_t user_mtu) { body(remote_bda, transport, user_mtu); @@ -124,7 +108,7 @@ extern struct GATTC_UpdateUserAttMtuIfNeeded GATTC_UpdateUserAttMtuIfNeeded; struct GATTC_ConfigureMTU { static tGATT_STATUS return_value; std::function body{ - [](uint16_t conn_id, uint16_t mtu) { return return_value; }}; + [](uint16_t /* conn_id */, uint16_t /* mtu */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id, uint16_t mtu) { return body(conn_id, mtu); }; @@ -138,9 +122,9 @@ struct GATTC_Discover { static tGATT_STATUS return_value; std::function - body{[](uint16_t conn_id, tGATT_DISC_TYPE disc_type, - uint16_t start_handle, - uint16_t end_handle) { return return_value; }}; + body{[](uint16_t /* conn_id */, tGATT_DISC_TYPE /* disc_type */, + uint16_t /* start_handle */, + uint16_t /* end_handle */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id, tGATT_DISC_TYPE disc_type, uint16_t start_handle, uint16_t end_handle) { return body(conn_id, disc_type, start_handle, end_handle); @@ -154,7 +138,9 @@ extern struct GATTC_Discover GATTC_Discover; struct GATTC_ExecuteWrite { static tGATT_STATUS return_value; std::function body{ - [](uint16_t conn_id, bool is_execute) { return return_value; }}; + [](uint16_t /* conn_id */, bool /* is_execute */) { + return return_value; + }}; tGATT_STATUS operator()(uint16_t conn_id, bool is_execute) { return body(conn_id, is_execute); }; @@ -168,8 +154,8 @@ struct GATTC_Read { static tGATT_STATUS return_value; std::function - body{[](uint16_t conn_id, tGATT_READ_TYPE type, - tGATT_READ_PARAM* p_read) { return return_value; }}; + body{[](uint16_t /* conn_id */, tGATT_READ_TYPE /* type */, + tGATT_READ_PARAM* /* p_read */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM* p_read) { return body(conn_id, type, p_read); @@ -183,7 +169,7 @@ extern struct GATTC_Read GATTC_Read; struct GATTC_SendHandleValueConfirm { static tGATT_STATUS return_value; std::function body{ - [](uint16_t conn_id, uint16_t cid) { return return_value; }}; + [](uint16_t /* conn_id */, uint16_t /* cid */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id, uint16_t cid) { return body(conn_id, cid); }; @@ -197,9 +183,8 @@ struct GATTC_Write { static tGATT_STATUS return_value; std::function - body{[](uint16_t conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE* p_write) { - return return_value; - }}; + body{[](uint16_t /* conn_id */, tGATT_WRITE_TYPE /* type */, + tGATT_VALUE* /* p_write */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE* p_write) { return body(conn_id, type, p_write); @@ -214,9 +199,8 @@ struct GATTS_AddService { static tGATT_STATUS return_value; std::function - body{[](tGATT_IF gatt_if, btgatt_db_element_t* service, int count) { - return return_value; - }}; + body{[](tGATT_IF /* gatt_if */, btgatt_db_element_t* /* service */, + int /* count */) { return return_value; }}; tGATT_STATUS operator()(tGATT_IF gatt_if, btgatt_db_element_t* service, int count) { return body(gatt_if, service, count); @@ -230,9 +214,8 @@ extern struct GATTS_AddService GATTS_AddService; struct GATTS_DeleteService { static bool return_value; std::function - body{[](tGATT_IF gatt_if, Uuid* p_svc_uuid, uint16_t svc_inst) { - return return_value; - }}; + body{[](tGATT_IF /* gatt_if */, Uuid* /* p_svc_uuid */, + uint16_t /* svc_inst */) { return return_value; }}; bool operator()(tGATT_IF gatt_if, Uuid* p_svc_uuid, uint16_t svc_inst) { return body(gatt_if, p_svc_uuid, svc_inst); }; @@ -246,8 +229,9 @@ struct GATTS_HandleValueIndication { static tGATT_STATUS return_value; std::function - body{[](uint16_t conn_id, uint16_t attr_handle, uint16_t val_len, - uint8_t* p_val) { return return_value; }}; + body{[](uint16_t /* conn_id */, uint16_t /* attr_handle */, + uint16_t /* val_len */, + uint8_t* /* p_val */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id, uint16_t attr_handle, uint16_t val_len, uint8_t* p_val) { return body(conn_id, attr_handle, val_len, p_val); @@ -262,8 +246,9 @@ struct GATTS_HandleValueNotification { static tGATT_STATUS return_value; std::function - body{[](uint16_t conn_id, uint16_t attr_handle, uint16_t val_len, - uint8_t* p_val) { return return_value; }}; + body{[](uint16_t /* conn_id */, uint16_t /* attr_handle */, + uint16_t /* val_len */, + uint8_t* /* p_val */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id, uint16_t attr_handle, uint16_t val_len, uint8_t* p_val) { return body(conn_id, attr_handle, val_len, p_val); @@ -277,7 +262,7 @@ extern struct GATTS_HandleValueNotification GATTS_HandleValueNotification; struct GATTS_NVRegister { static bool return_value; std::function body{ - [](tGATT_APPL_INFO* p_cb_info) { return return_value; }}; + [](tGATT_APPL_INFO* /* p_cb_info */) { return return_value; }}; bool operator()(tGATT_APPL_INFO* p_cb_info) { return body(p_cb_info); }; }; extern struct GATTS_NVRegister GATTS_NVRegister; @@ -289,8 +274,9 @@ struct GATTS_SendRsp { static tGATT_STATUS return_value; std::function - body{[](uint16_t conn_id, uint32_t trans_id, tGATT_STATUS status, - tGATTS_RSP* p_msg) { return return_value; }}; + body{[](uint16_t /* conn_id */, uint32_t /* trans_id */, + tGATT_STATUS /* status */, + tGATTS_RSP* /* p_msg */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id, uint32_t trans_id, tGATT_STATUS status, tGATTS_RSP* p_msg) { return body(conn_id, trans_id, status, p_msg); @@ -303,7 +289,7 @@ extern struct GATTS_SendRsp GATTS_SendRsp; // Return: void struct GATTS_StopService { std::function body{ - [](uint16_t service_handle) {}}; + [](uint16_t /* service_handle */) {}}; void operator()(uint16_t service_handle) { body(service_handle); }; }; extern struct GATTS_StopService GATTS_StopService; @@ -315,9 +301,8 @@ struct GATT_CancelConnect { static bool return_value; std::function - body{[](tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct) { - return return_value; - }}; + body{[](tGATT_IF /* gatt_if */, const RawAddress& /* bd_addr */, + bool /* is_direct */) { return return_value; }}; bool operator()(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct) { return body(gatt_if, bd_addr, is_direct); }; @@ -334,10 +319,10 @@ struct GATT_Connect { tBLE_ADDR_TYPE addr_type, bool is_direct, tBT_TRANSPORT transport, bool opportunistic, uint8_t initiating_phys)> - body{[](tGATT_IF gatt_if, const RawAddress& bd_addr, - tBLE_ADDR_TYPE addr_type, bool is_direct, tBT_TRANSPORT transport, - bool opportunistic, - uint8_t initiating_phys) { return return_value; }}; + body{[](tGATT_IF /* gatt_if */, const RawAddress& /* bd_addr */, + tBLE_ADDR_TYPE /* addr_type */, bool /* is_direct */, + tBT_TRANSPORT /* transport */, bool /* opportunistic */, + uint8_t /* initiating_phys */) { return return_value; }}; bool operator()(tGATT_IF gatt_if, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, bool is_direct, tBT_TRANSPORT transport, bool opportunistic, @@ -352,7 +337,7 @@ extern struct GATT_Connect GATT_Connect; // Params: tGATT_IF gatt_if // Return: void struct GATT_Deregister { - std::function body{[](tGATT_IF gatt_if) {}}; + std::function body{[](tGATT_IF /* gatt_if */) {}}; void operator()(tGATT_IF gatt_if) { body(gatt_if); }; }; extern struct GATT_Deregister GATT_Deregister; @@ -363,7 +348,7 @@ extern struct GATT_Deregister GATT_Deregister; struct GATT_Disconnect { static tGATT_STATUS return_value; std::function body{ - [](uint16_t conn_id) { return return_value; }}; + [](uint16_t /* conn_id */) { return return_value; }}; tGATT_STATUS operator()(uint16_t conn_id) { return body(conn_id); }; }; extern struct GATT_Disconnect GATT_Disconnect; @@ -375,8 +360,9 @@ struct GATT_GetConnIdIfConnected { static bool return_value; std::function - body{[](tGATT_IF gatt_if, const RawAddress& bd_addr, uint16_t* p_conn_id, - tBT_TRANSPORT transport) { return return_value; }}; + body{[](tGATT_IF /* gatt_if */, const RawAddress& /* bd_addr */, + uint16_t* /* p_conn_id */, + tBT_TRANSPORT /* transport */) { return return_value; }}; bool operator()(tGATT_IF gatt_if, const RawAddress& bd_addr, uint16_t* p_conn_id, tBT_TRANSPORT transport) { return body(gatt_if, bd_addr, p_conn_id, transport); @@ -391,8 +377,9 @@ struct GATT_GetConnectionInfor { static bool return_value; std::function - body{[](uint16_t conn_id, tGATT_IF* p_gatt_if, RawAddress& bd_addr, - tBT_TRANSPORT* p_transport) { return return_value; }}; + body{[](uint16_t /* conn_id */, tGATT_IF* /* p_gatt_if */, + RawAddress& /* bd_addr */, + tBT_TRANSPORT* /* p_transport */) { return return_value; }}; bool operator()(uint16_t conn_id, tGATT_IF* p_gatt_if, RawAddress& bd_addr, tBT_TRANSPORT* p_transport) { return body(conn_id, p_gatt_if, bd_addr, p_transport); @@ -407,9 +394,9 @@ struct GATT_Register { static tGATT_IF return_value; std::function - body{[](const Uuid& app_uuid128, const std::string& name, - tGATT_CBACK* p_cb_info, - bool eatt_support) { return return_value; }}; + body{[](const Uuid& /* app_uuid128 */, const std::string& /* name */, + tGATT_CBACK* /* p_cb_info */, + bool /* eatt_support */) { return return_value; }}; tGATT_IF operator()(const Uuid& app_uuid128, const std::string& name, tGATT_CBACK* p_cb_info, bool eatt_support) { return body(app_uuid128, name, p_cb_info, eatt_support); @@ -423,8 +410,8 @@ extern struct GATT_Register GATT_Register; struct GATT_SetIdleTimeout { std::function - body{[](const RawAddress& bd_addr, uint16_t idle_tout, - tBT_TRANSPORT transport, bool is_active) {}}; + body{[](const RawAddress& /* bd_addr */, uint16_t /* idle_tout */, + tBT_TRANSPORT /* transport */, bool /* is_active */) {}}; void operator()(const RawAddress& bd_addr, uint16_t idle_tout, tBT_TRANSPORT transport, bool is_active) { body(bd_addr, idle_tout, transport, is_active); @@ -436,7 +423,7 @@ extern struct GATT_SetIdleTimeout GATT_SetIdleTimeout; // Params: tGATT_IF gatt_if // Return: void struct GATT_StartIf { - std::function body{[](tGATT_IF gatt_if) {}}; + std::function body{[](tGATT_IF /* gatt_if */) {}}; void operator()(tGATT_IF gatt_if) { body(gatt_if); }; }; extern struct GATT_StartIf GATT_StartIf; @@ -460,8 +447,8 @@ struct is_active_service { static bool return_value; std::function - body{[](const Uuid& app_uuid128, Uuid* p_svc_uuid, - uint16_t start_handle) { return return_value; }}; + body{[](const Uuid& /* app_uuid128 */, Uuid* /* p_svc_uuid */, + uint16_t /* start_handle */) { return return_value; }}; bool operator()(const Uuid& app_uuid128, Uuid* p_svc_uuid, uint16_t start_handle) { return body(app_uuid128, p_svc_uuid, start_handle); diff --git a/system/test/mock/mock_stack_gatt_attr.cc b/system/test/mock/mock_stack_gatt_attr.cc index 4af0961e0bffc0ed0585f0a9f24b88c5357f9104..ae74c2cf01681d95bcec6e29d9a9b30c6188bdb2 100644 --- a/system/test/mock/mock_stack_gatt_attr.cc +++ b/system/test/mock/mock_stack_gatt_attr.cc @@ -22,62 +22,68 @@ #include #include -#include -#include #include "stack/gatt/gatt_int.h" #include "test/common/mock_functions.h" #include "types/bt_transport.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -uint16_t gatt_profile_find_conn_id_by_bd_addr(const RawAddress& remote_bda) { +uint16_t gatt_profile_find_conn_id_by_bd_addr( + const RawAddress& /* remote_bda */) { inc_func_call_count(__func__); return 0; } bool gatt_profile_get_eatt_support( - const RawAddress& remote_bda, - base::OnceCallback cb) { + const RawAddress& /* remote_bda */, + base::OnceCallback /* cb */) { inc_func_call_count(__func__); return false; } -bool gatt_sr_is_cl_change_aware(tGATT_TCB& tcb) { +bool gatt_sr_is_cl_change_aware(tGATT_TCB& /* tcb */) { inc_func_call_count(__func__); return false; } -tGATT_PROFILE_CLCB* gatt_profile_clcb_alloc(uint16_t conn_id, - const RawAddress& bda, - tBT_TRANSPORT tranport) { +tGATT_PROFILE_CLCB* gatt_profile_clcb_alloc(uint16_t /* conn_id */, + const RawAddress& /* bda */, + tBT_TRANSPORT /* tranport */) { inc_func_call_count(__func__); return nullptr; } -tGATT_STATUS proc_read_req(uint16_t conn_id, tGATTS_REQ_TYPE, - tGATT_READ_REQ* p_data, tGATTS_RSP* p_rsp) { +tGATT_STATUS proc_read_req(uint16_t /* conn_id */, tGATTS_REQ_TYPE, + tGATT_READ_REQ* /* p_data */, + tGATTS_RSP* /* p_rsp */) { inc_func_call_count(__func__); return GATT_SUCCESS; } -tGATT_STATUS proc_write_req(uint16_t conn_id, tGATTS_REQ_TYPE, - tGATT_WRITE_REQ* p_data) { +tGATT_STATUS proc_write_req(uint16_t /* conn_id */, tGATTS_REQ_TYPE, + tGATT_WRITE_REQ* /* p_data */) { inc_func_call_count(__func__); return GATT_SUCCESS; } -tGATT_STATUS read_attr_value(uint16_t conn_id, uint16_t handle, - tGATT_VALUE* p_value, bool is_long) { +tGATT_STATUS read_attr_value(uint16_t /* conn_id */, uint16_t /* handle */, + tGATT_VALUE* /* p_value */, bool /* is_long */) { inc_func_call_count(__func__); return GATT_SUCCESS; } -void GATT_ConfigServiceChangeCCC(const RawAddress& remote_bda, bool enable, - tBT_TRANSPORT transport) { +void GATT_ConfigServiceChangeCCC(const RawAddress& /* remote_bda */, + bool /* enable */, + tBT_TRANSPORT /* transport */) { inc_func_call_count(__func__); } -void gatt_profile_clcb_dealloc(tGATT_PROFILE_CLCB* p_clcb) { +void gatt_profile_clcb_dealloc(tGATT_PROFILE_CLCB* /* p_clcb */) { inc_func_call_count(__func__); } void gatt_profile_db_init(void) { inc_func_call_count(__func__); } -void gatt_sr_init_cl_status(tGATT_TCB& tcb) { inc_func_call_count(__func__); } -void gatt_sr_update_cl_status(tGATT_TCB& tcb, bool chg_aware) { +void gatt_sr_init_cl_status(tGATT_TCB& /* tcb */) { + inc_func_call_count(__func__); +} +void gatt_sr_update_cl_status(tGATT_TCB& /* tcb */, bool /* chg_aware */) { inc_func_call_count(__func__); } +bool gatt_cl_read_sirk_req( + const RawAddress& /* peer_bda */, + base::OnceCallback + /* cb */) { + return false; +} diff --git a/system/test/mock/mock_stack_gatt_auth.cc b/system/test/mock/mock_stack_gatt_auth.cc index 303c8864620567ec64b08525ab6c36293828bde5..f9b7bc077151e316def24098001678da3260bb0c 100644 --- a/system/test/mock/mock_stack_gatt_auth.cc +++ b/system/test/mock/mock_stack_gatt_auth.cc @@ -20,40 +20,35 @@ */ #include -#include -#include #include "stack/gatt/gatt_int.h" #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool gatt_security_check_start(tGATT_CLCB* p_clcb) { +bool gatt_security_check_start(tGATT_CLCB* /* p_clcb */) { inc_func_call_count(__func__); return false; } -tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB* p_clcb) { +tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB* /* p_clcb */) { inc_func_call_count(__func__); return GATT_SEC_NONE; } -tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB* p_tcb) { +tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB* /* p_tcb */) { inc_func_call_count(__func__); return GATT_SEC_NONE; } -tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB& tcb) { +tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB& /* tcb */) { inc_func_call_count(__func__); return GATT_SUCCESS; } -void gatt_notify_enc_cmpl(const RawAddress& bd_addr) { +void gatt_notify_enc_cmpl(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); } -void gatt_set_sec_act(tGATT_TCB* p_tcb, tGATT_SEC_ACTION sec_act) { +void gatt_set_sec_act(tGATT_TCB* /* p_tcb */, tGATT_SEC_ACTION /* sec_act */) { inc_func_call_count(__func__); } -void gatt_verify_signature(tGATT_TCB& tcb, uint16_t cid, BT_HDR* p_buf) { +void gatt_verify_signature(tGATT_TCB& /* tcb */, uint16_t /* cid */, + BT_HDR* /* p_buf */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_gatt_connection_manager.cc b/system/test/mock/mock_stack_gatt_connection_manager.cc index 2a1a846f84819e110a5ab603c60444f5fefde5f5..ed54a2d51787b7ffa5af466ead803345800284a2 100644 --- a/system/test/mock/mock_stack_gatt_connection_manager.cc +++ b/system/test/mock/mock_stack_gatt_connection_manager.cc @@ -19,78 +19,65 @@ * Functions generated:16 */ -#include -#include -#include -#include - -#include -#include #include -#include -#include "main/shim/shim.h" -#include "osi/include/alarm.h" -#include "osi/include/log.h" #include "stack/btm/btm_ble_bgconn.h" #include "stack/gatt/connection_manager.h" -#include "stack/include/l2c_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" using namespace connection_manager; -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool connection_manager::background_connect_add(uint8_t app_id, - const RawAddress& address) { +bool connection_manager::background_connect_add( + uint8_t /* app_id */, const RawAddress& /* address */) { inc_func_call_count(__func__); return false; } -bool connection_manager::background_connect_remove(uint8_t app_id, - const RawAddress& address) { +bool connection_manager::background_connect_remove( + uint8_t /* app_id */, const RawAddress& /* address */) { inc_func_call_count(__func__); return false; } -bool connection_manager::direct_connect_add(uint8_t app_id, - const RawAddress& address) { +bool connection_manager::direct_connect_add(uint8_t /* app_id */, + const RawAddress& /* address */) { inc_func_call_count(__func__); return false; } -bool connection_manager::direct_connect_remove(uint8_t app_id, - const RawAddress& address) { +bool connection_manager::direct_connect_remove(uint8_t /* app_id */, + const RawAddress& /* address */, + bool /* connection_timeout */) { inc_func_call_count(__func__); return false; } -bool connection_manager::remove_unconditional(const RawAddress& address) { +bool connection_manager::remove_unconditional(const RawAddress& /* address */) { inc_func_call_count(__func__); return false; } std::set connection_manager::get_apps_connecting_to( - const RawAddress& address) { + const RawAddress& /* address */) { inc_func_call_count(__func__); return std::set(); } -void connection_manager::dump(int fd) { inc_func_call_count(__func__); } -void connection_manager::on_app_deregistered(uint8_t app_id) { +void connection_manager::dump(int /* fd */) { inc_func_call_count(__func__); } +void connection_manager::on_app_deregistered(uint8_t /* app_id */) { inc_func_call_count(__func__); } -void connection_manager::on_connection_complete(const RawAddress& address) { +void connection_manager::on_connection_complete( + const RawAddress& /* address */) { inc_func_call_count(__func__); } void connection_manager::on_connection_timed_out_from_shim( - const RawAddress& address) { + const RawAddress& /* address */) { inc_func_call_count(__func__); } -void connection_manager::reset(bool after_reset) { +void connection_manager::reset(bool /* after_reset */) { inc_func_call_count(__func__); } -bool connection_manager::is_background_connection(const RawAddress& address) { +bool connection_manager::is_background_connection( + const RawAddress& /* address */) { inc_func_call_count(__func__); return false; } diff --git a/system/test/mock/mock_stack_gatt_main.cc b/system/test/mock/mock_stack_gatt_main.cc index 9052e1be74733b14eafc9a0591c118bfe3d08df2..5a6bf35641745f5b58f4522964aaccdb130d944b 100644 --- a/system/test/mock/mock_stack_gatt_main.cc +++ b/system/test/mock/mock_stack_gatt_main.cc @@ -19,100 +19,92 @@ * Functions generated:23 */ -#include -#include - -#include "bt_target.h" #include "l2c_api.h" -#include "osi/include/osi.h" -#include "stack/btm/btm_ble_int.h" -#include "stack/btm/btm_dev.h" -#include "stack/btm/btm_sec.h" #include "stack/gatt/gatt_int.h" #include "stack/include/bt_hdr.h" -#include "stack/include/l2cap_acl_interface.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - void gatt_init(void) { inc_func_call_count(__func__); } -bool gatt_act_connect(tGATT_REG* p_reg, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, int8_t initiating_phys) { +bool gatt_act_connect(tGATT_REG* /* p_reg */, const RawAddress& /* bd_addr */, + tBLE_ADDR_TYPE /* addr_type */, + tBT_TRANSPORT /* transport */, + int8_t /* initiating_phys */) { inc_func_call_count(__func__); return false; } -bool gatt_connect(const RawAddress& rem_bda, tGATT_TCB* p_tcb, tBLE_ADDR_TYPE addr_type, - tBT_TRANSPORT transport, uint8_t initiating_phys, - tGATT_IF gatt_if) { +bool gatt_connect(const RawAddress& /* rem_bda */, tGATT_TCB* /* p_tcb */, + tBLE_ADDR_TYPE /* addr_type */, tBT_TRANSPORT /* transport */, + uint8_t /* initiating_phys */, tGATT_IF /* gatt_if */) { inc_func_call_count(__func__); return false; } -bool gatt_disconnect(tGATT_TCB* p_tcb) { +bool gatt_disconnect(tGATT_TCB* /* p_tcb */) { inc_func_call_count(__func__); return false; } -bool gatt_update_app_hold_link_status(tGATT_IF gatt_if, tGATT_TCB* p_tcb, - bool is_add) { +bool gatt_update_app_hold_link_status(tGATT_IF /* gatt_if */, + tGATT_TCB* /* p_tcb */, + bool /* is_add */) { inc_func_call_count(__func__); return false; } -tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* p_tcb) { +tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* /* p_tcb */) { inc_func_call_count(__func__); return GATT_CH_CLOSE; } -void gatt_add_a_bonded_dev_for_srv_chg(const RawAddress& bda) { - inc_func_call_count(__func__); -} -void gatt_chk_srv_chg(tGATTS_SRV_CHG* p_srv_chg_clt) { +void gatt_add_a_bonded_dev_for_srv_chg(const RawAddress& /* bda */) { inc_func_call_count(__func__); } -void gatt_data_process(tGATT_TCB& tcb, uint16_t cid, BT_HDR* p_buf) { +void gatt_chk_srv_chg(tGATTS_SRV_CHG* /* p_srv_chg_clt */) { inc_func_call_count(__func__); } -void gatt_consolidate(const RawAddress& identity_addr, const RawAddress& rpa) { +void gatt_data_process(tGATT_TCB& /* tcb */, uint16_t /* cid */, + BT_HDR* /* p_buf */) { inc_func_call_count(__func__); } -void gatt_find_in_device_record(const RawAddress& bd_addr, - tBLE_BD_ADDR* address_with_type) { +void gatt_consolidate(const RawAddress& /* identity_addr */, + const RawAddress& /* rpa */) { inc_func_call_count(__func__); } void gatt_free(void) { inc_func_call_count(__func__); } void gatt_init_srv_chg(void) { inc_func_call_count(__func__); } -void gatt_l2cif_config_cfm_cback(uint16_t lcid, uint16_t initiator, - tL2CAP_CFG_INFO* p_cfg) { +void gatt_l2cif_config_cfm_cback(uint16_t /* lcid */, uint16_t /* initiator */, + tL2CAP_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); } -void gatt_l2cif_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { +void gatt_l2cif_config_ind_cback(uint16_t /* lcid */, + tL2CAP_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); } -void gatt_l2cif_disconnect_ind_cback(uint16_t lcid, bool ack_needed) { +void gatt_l2cif_disconnect_ind_cback(uint16_t /* lcid */, + bool /* ack_needed */) { inc_func_call_count(__func__); } -void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval, - uint16_t latency, uint16_t timeout, - tHCI_STATUS status) { +void gatt_notify_conn_update(const RawAddress& /* remote */, + uint16_t /* interval */, uint16_t /* latency */, + uint16_t /* timeout */, tHCI_STATUS /* status */) { inc_func_call_count(__func__); } -void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle, - uint8_t tx_phy, uint8_t rx_phy) { +void gatt_notify_phy_updated(tHCI_STATUS /* status */, uint16_t /* handle */, + uint8_t /* tx_phy */, uint8_t /* rx_phy */) { inc_func_call_count(__func__); } -void gatt_notify_subrate_change(uint16_t handle, uint16_t subrate_factor, - uint16_t latency, uint16_t cont_num, - uint16_t timeout, uint8_t status) { +void gatt_notify_subrate_change(uint16_t /* handle */, + uint16_t /* subrate_factor */, + uint16_t /* latency */, uint16_t /* cont_num */, + uint16_t /* timeout */, uint8_t /* status */) { inc_func_call_count(__func__); } void gatt_proc_srv_chg(void) { inc_func_call_count(__func__); } -void gatt_send_srv_chg_ind(const RawAddress& peer_bda) { +void gatt_send_srv_chg_ind(const RawAddress& /* peer_bda */) { inc_func_call_count(__func__); } -void gatt_set_ch_state(tGATT_TCB* p_tcb, tGATT_CH_STATE ch_state) { +void gatt_set_ch_state(tGATT_TCB* /* p_tcb */, tGATT_CH_STATE /* ch_state */) { inc_func_call_count(__func__); } -void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb, - bool is_add, bool check_acl_link) { +void gatt_update_app_use_link_flag(tGATT_IF /* gatt_if */, + tGATT_TCB* /* p_tcb */, bool /* is_add */, + bool /* check_acl_link */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_hcic_hciblecmds.cc b/system/test/mock/mock_stack_hcic_hciblecmds.cc index 37add1216dffd387d7e31f752f76c00d8710e1f5..8d7097f27bcb9d17303acc763ed082de797d244a 100644 --- a/system/test/mock/mock_stack_hcic_hciblecmds.cc +++ b/system/test/mock/mock_stack_hcic_hciblecmds.cc @@ -19,14 +19,12 @@ * * mockcify.pl ver 0.3.2 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_hcic_hciblecmds.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_hcic_hciblecmds.h" +#include "test/common/mock_functions.h" // Mocked internal structures, if any @@ -39,17 +37,11 @@ struct btsnd_hci_ble_add_device_to_periodic_advertiser_list btsnd_hci_ble_add_device_to_periodic_advertiser_list; struct btsnd_hci_ble_clear_periodic_advertiser_list btsnd_hci_ble_clear_periodic_advertiser_list; -struct btsnd_hci_ble_read_periodic_advertiser_list_size - btsnd_hci_ble_read_periodic_advertiser_list_size; struct btsnd_hci_ble_remove_device_from_periodic_advertiser_list btsnd_hci_ble_remove_device_from_periodic_advertiser_list; struct btsnd_hcic_accept_cis_req btsnd_hcic_accept_cis_req; -struct btsnd_hcic_big_term_sync btsnd_hcic_big_term_sync; -struct btsnd_hcic_ble_create_conn_cancel btsnd_hcic_ble_create_conn_cancel; -struct btsnd_hcic_ble_create_ll_conn btsnd_hcic_ble_create_ll_conn; struct btsnd_hcic_ble_enh_rx_test btsnd_hcic_ble_enh_rx_test; struct btsnd_hcic_ble_enh_tx_test btsnd_hcic_ble_enh_tx_test; -struct btsnd_hcic_ble_ext_create_conn btsnd_hcic_ble_ext_create_conn; struct btsnd_hcic_ble_ltk_req_neg_reply btsnd_hcic_ble_ltk_req_neg_reply; struct btsnd_hcic_ble_ltk_req_reply btsnd_hcic_ble_ltk_req_reply; struct btsnd_hcic_ble_periodic_advertising_create_sync @@ -68,15 +60,10 @@ struct btsnd_hcic_ble_rc_param_req_neg_reply struct btsnd_hcic_ble_rc_param_req_reply btsnd_hcic_ble_rc_param_req_reply; struct btsnd_hcic_ble_read_adv_chnl_tx_power btsnd_hcic_ble_read_adv_chnl_tx_power; -struct btsnd_hcic_ble_read_chnl_map btsnd_hcic_ble_read_chnl_map; -struct btsnd_hcic_ble_read_host_supported btsnd_hcic_ble_read_host_supported; struct btsnd_hcic_ble_read_remote_feat btsnd_hcic_ble_read_remote_feat; -struct btsnd_hcic_ble_read_resolvable_addr_local - btsnd_hcic_ble_read_resolvable_addr_local; struct btsnd_hcic_ble_read_resolvable_addr_peer btsnd_hcic_ble_read_resolvable_addr_peer; -struct btsnd_hcic_ble_set_addr_resolution_enable - btsnd_hcic_ble_set_addr_resolution_enable; +struct btsnd_hcic_ble_receiver_test btsnd_hcic_ble_receiver_test; struct btsnd_hcic_ble_set_adv_data btsnd_hcic_ble_set_adv_data; struct btsnd_hcic_ble_set_adv_enable btsnd_hcic_ble_set_adv_enable; struct btsnd_hcic_ble_set_data_length btsnd_hcic_ble_set_data_length; @@ -86,8 +73,6 @@ struct btsnd_hcic_ble_set_extended_scan_enable btsnd_hcic_ble_set_extended_scan_enable; struct btsnd_hcic_ble_set_extended_scan_params btsnd_hcic_ble_set_extended_scan_params; -struct btsnd_hcic_ble_set_host_chnl_class btsnd_hcic_ble_set_host_chnl_class; -struct btsnd_hcic_ble_set_local_used_feat btsnd_hcic_ble_set_local_used_feat; struct btsnd_hcic_ble_set_periodic_advertising_receive_enable btsnd_hcic_ble_set_periodic_advertising_receive_enable; struct btsnd_hcic_ble_set_periodic_advertising_sync_transfer_params @@ -95,17 +80,16 @@ struct btsnd_hcic_ble_set_periodic_advertising_sync_transfer_params struct btsnd_hcic_ble_set_privacy_mode btsnd_hcic_ble_set_privacy_mode; struct btsnd_hcic_ble_set_rand_priv_addr_timeout btsnd_hcic_ble_set_rand_priv_addr_timeout; -struct btsnd_hcic_ble_set_random_addr btsnd_hcic_ble_set_random_addr; struct btsnd_hcic_ble_set_scan_enable btsnd_hcic_ble_set_scan_enable; struct btsnd_hcic_ble_set_scan_params btsnd_hcic_ble_set_scan_params; -struct btsnd_hcic_ble_set_scan_rsp_data btsnd_hcic_ble_set_scan_rsp_data; struct btsnd_hcic_ble_start_enc btsnd_hcic_ble_start_enc; +struct btsnd_hcic_ble_test_end btsnd_hcic_ble_test_end; +struct btsnd_hcic_ble_transmitter_test btsnd_hcic_ble_transmitter_test; struct btsnd_hcic_ble_upd_ll_conn_params btsnd_hcic_ble_upd_ll_conn_params; struct btsnd_hcic_ble_write_adv_params btsnd_hcic_ble_write_adv_params; struct btsnd_hcic_create_big btsnd_hcic_create_big; struct btsnd_hcic_create_cis btsnd_hcic_create_cis; struct btsnd_hcic_read_iso_link_quality btsnd_hcic_read_iso_link_quality; -struct btsnd_hcic_read_iso_tx_sync btsnd_hcic_read_iso_tx_sync; struct btsnd_hcic_rej_cis_req btsnd_hcic_rej_cis_req; struct btsnd_hcic_remove_cig btsnd_hcic_remove_cig; struct btsnd_hcic_remove_iso_data_path btsnd_hcic_remove_iso_data_path; @@ -140,12 +124,6 @@ void btsnd_hci_ble_clear_periodic_advertiser_list( test::mock::stack_hcic_hciblecmds:: btsnd_hci_ble_clear_periodic_advertiser_list(std::move(cb)); } -void btsnd_hci_ble_read_periodic_advertiser_list_size( - base::OnceCallback cb) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds:: - btsnd_hci_ble_read_periodic_advertiser_list_size(std::move(cb)); -} void btsnd_hci_ble_remove_device_from_periodic_advertiser_list( uint8_t adv_addr_type, const RawAddress& adv_addr, uint8_t adv_sid, base::OnceCallback cb) { @@ -158,30 +136,6 @@ void btsnd_hcic_accept_cis_req(uint16_t conn_handle) { inc_func_call_count(__func__); test::mock::stack_hcic_hciblecmds::btsnd_hcic_accept_cis_req(conn_handle); } -void btsnd_hcic_big_term_sync(uint8_t big_handle, - base::OnceCallback cb) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_big_term_sync(big_handle, - std::move(cb)); -} -void btsnd_hcic_ble_create_conn_cancel(void) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_create_conn_cancel(); -} -void btsnd_hcic_ble_create_ll_conn(uint16_t scan_int, uint16_t scan_win, - uint8_t init_filter_policy, - tBLE_ADDR_TYPE addr_type_peer, - const RawAddress& bda_peer, - tBLE_ADDR_TYPE addr_type_own, - uint16_t conn_int_min, uint16_t conn_int_max, - uint16_t conn_latency, uint16_t conn_timeout, - uint16_t min_ce_len, uint16_t max_ce_len) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_create_ll_conn( - scan_int, scan_win, init_filter_policy, addr_type_peer, bda_peer, - addr_type_own, conn_int_min, conn_int_max, conn_latency, conn_timeout, - min_ce_len, max_ce_len); -} void btsnd_hcic_ble_enh_rx_test(uint8_t rx_chan, uint8_t phy, uint8_t mod_index) { inc_func_call_count(__func__); @@ -194,17 +148,6 @@ void btsnd_hcic_ble_enh_tx_test(uint8_t tx_chan, uint8_t data_len, test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_enh_tx_test( tx_chan, data_len, payload, phy); } -void btsnd_hcic_ble_ext_create_conn(uint8_t init_filter_policy, - tBLE_ADDR_TYPE addr_type_own, - tBLE_ADDR_TYPE addr_type_peer, - const RawAddress& bda_peer, - uint8_t initiating_phys, - EXT_CONN_PHY_CFG* phy_cfg) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_ext_create_conn( - init_filter_policy, addr_type_own, addr_type_peer, bda_peer, - initiating_phys, phy_cfg); -} void btsnd_hcic_ble_ltk_req_neg_reply(uint16_t handle) { inc_func_call_count(__func__); test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_ltk_req_neg_reply(handle); @@ -276,34 +219,19 @@ void btsnd_hcic_ble_read_adv_chnl_tx_power(void) { inc_func_call_count(__func__); test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_read_adv_chnl_tx_power(); } -void btsnd_hcic_ble_read_chnl_map(uint16_t handle) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_read_chnl_map(handle); -} -void btsnd_hcic_ble_read_host_supported(void) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_read_host_supported(); -} void btsnd_hcic_ble_read_remote_feat(uint16_t handle) { inc_func_call_count(__func__); test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_read_remote_feat(handle); } -void btsnd_hcic_ble_read_resolvable_addr_local(uint8_t addr_type_peer, - const RawAddress& bda_peer) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_read_resolvable_addr_local( - addr_type_peer, bda_peer); -} void btsnd_hcic_ble_read_resolvable_addr_peer(uint8_t addr_type_peer, const RawAddress& bda_peer) { inc_func_call_count(__func__); test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_read_resolvable_addr_peer( addr_type_peer, bda_peer); } -void btsnd_hcic_ble_set_addr_resolution_enable(uint8_t addr_resolution_enable) { +void btsnd_hcic_ble_receiver_test(uint8_t rx_freq) { inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_addr_resolution_enable( - addr_resolution_enable); + test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_receiver_test(rx_freq); } void btsnd_hcic_ble_set_adv_data(uint8_t data_len, uint8_t* p_data) { inc_func_call_count(__func__); @@ -344,17 +272,6 @@ void btsnd_hcic_ble_set_extended_scan_params(uint8_t own_address_type, test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_extended_scan_params( own_address_type, scanning_filter_policy, scanning_phys, phy_cfg); } -void btsnd_hcic_ble_set_host_chnl_class( - uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE]) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_host_chnl_class( - chnl_map); -} -void btsnd_hcic_ble_set_local_used_feat(uint8_t feat_set[8]) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_local_used_feat( - feat_set); -} void btsnd_hcic_ble_set_periodic_advertising_receive_enable( uint16_t sync_handle, bool enable, base::OnceCallback cb) { @@ -383,10 +300,6 @@ void btsnd_hcic_ble_set_rand_priv_addr_timeout(uint16_t rpa_timout) { test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_rand_priv_addr_timeout( rpa_timout); } -void btsnd_hcic_ble_set_random_addr(const RawAddress& random_bda) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_random_addr(random_bda); -} void btsnd_hcic_ble_set_scan_enable(uint8_t scan_enable, uint8_t duplicate) { inc_func_call_count(__func__); test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_scan_enable(scan_enable, @@ -399,11 +312,6 @@ void btsnd_hcic_ble_set_scan_params(uint8_t scan_type, uint16_t scan_int, test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_scan_params( scan_type, scan_int, scan_win, addr_type_own, scan_filter_policy); } -void btsnd_hcic_ble_set_scan_rsp_data(uint8_t data_len, uint8_t* p_scan_rsp) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_set_scan_rsp_data( - data_len, p_scan_rsp); -} void btsnd_hcic_ble_start_enc(uint16_t handle, uint8_t rand[HCIC_BLE_RAND_DI_SIZE], uint16_t ediv, const Octet16& ltk) { @@ -411,6 +319,16 @@ void btsnd_hcic_ble_start_enc(uint16_t handle, test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_start_enc(handle, rand, ediv, ltk); } +void btsnd_hcic_ble_test_end(void) { + inc_func_call_count(__func__); + test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_test_end(); +} +void btsnd_hcic_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len, + uint8_t payload) { + inc_func_call_count(__func__); + test::mock::stack_hcic_hciblecmds::btsnd_hcic_ble_transmitter_test( + tx_freq, test_data_len, payload); +} void btsnd_hcic_ble_upd_ll_conn_params(uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency, @@ -457,12 +375,6 @@ void btsnd_hcic_read_iso_link_quality( test::mock::stack_hcic_hciblecmds::btsnd_hcic_read_iso_link_quality( iso_handle, std::move(cb)); } -void btsnd_hcic_read_iso_tx_sync( - uint16_t iso_handle, base::OnceCallback cb) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hciblecmds::btsnd_hcic_read_iso_tx_sync(iso_handle, - std::move(cb)); -} void btsnd_hcic_rej_cis_req(uint16_t conn_handle, uint8_t reason, base::OnceCallback cb) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_stack_hcic_hciblecmds.h b/system/test/mock/mock_stack_hcic_hciblecmds.h index 0f374b37452ec800bb4a7e3e0992bb34188e8ece..5d9b5766b452f5750efa9bcee9be0efaa3643699 100644 --- a/system/test/mock/mock_stack_hcic_hciblecmds.h +++ b/system/test/mock/mock_stack_hcic_hciblecmds.h @@ -24,29 +24,12 @@ #include #include -#include -#include +#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include - -#include - -#include "bt_target.h" -#include "btu.h" -#include "hcidefs.h" +#include "base/callback.h" #include "hcimsgs.h" -#include "osi/include/allocator.h" -#include "stack/include/bt_hdr.h" #include "stack/include/bt_octets.h" -#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any @@ -87,19 +70,6 @@ struct btsnd_hci_ble_clear_periodic_advertiser_list { extern struct btsnd_hci_ble_clear_periodic_advertiser_list btsnd_hci_ble_clear_periodic_advertiser_list; -// Name: btsnd_hci_ble_read_periodic_advertiser_list_size -// Params: base::OnceCallback)> body{ - [](base::OnceCallback cb) {}}; - void operator()(base::OnceCallback cb) { - body(std::move(cb)); - }; -}; -extern struct btsnd_hci_ble_read_periodic_advertiser_list_size - btsnd_hci_ble_read_periodic_advertiser_list_size; - // Name: btsnd_hci_ble_remove_device_from_periodic_advertiser_list // Params: uint8_t adv_addr_type, const RawAddress& adv_addr, uint8_t adv_sid, // base::OnceCallback)> - body{[](uint8_t big_handle, - base::OnceCallback) {}}; - void operator()(uint8_t big_handle, - base::OnceCallback cb) { - body(big_handle, std::move(cb)); - }; -}; -extern struct btsnd_hcic_big_term_sync btsnd_hcic_big_term_sync; - // Name: btsnd_hcic_ble_add_device_resolving_list // Params: uint8_t addr_type_peer, const RawAddress& bda_peer, const Octet16& // irk_peer, const Octet16& irk_local Return: void @@ -167,48 +123,6 @@ struct btsnd_hcic_ble_clear_resolving_list { extern struct btsnd_hcic_ble_clear_resolving_list btsnd_hcic_ble_clear_resolving_list; -// Name: btsnd_hcic_ble_create_conn_cancel -// Params: void -// Return: void -struct btsnd_hcic_ble_create_conn_cancel { - std::function body{[](void) {}}; - void operator()(void) { body(); }; -}; -extern struct btsnd_hcic_ble_create_conn_cancel - btsnd_hcic_ble_create_conn_cancel; - -// Name: btsnd_hcic_ble_create_ll_conn -// Params: uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy, -// tBLE_ADDR_TYPE addr_type_peer, const RawAddress& bda_peer, tBLE_ADDR_TYPE -// addr_type_own, uint16_t conn_int_min, uint16_t conn_int_max, uint16_t -// conn_latency, uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len -// Return: void -struct btsnd_hcic_ble_create_ll_conn { - std::function - body{[](uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy, - tBLE_ADDR_TYPE addr_type_peer, const RawAddress& bda_peer, - tBLE_ADDR_TYPE addr_type_own, uint16_t conn_int_min, - uint16_t conn_int_max, uint16_t conn_latency, - uint16_t conn_timeout, uint16_t min_ce_len, - uint16_t max_ce_len) {}}; - void operator()(uint16_t scan_int, uint16_t scan_win, - uint8_t init_filter_policy, tBLE_ADDR_TYPE addr_type_peer, - const RawAddress& bda_peer, tBLE_ADDR_TYPE addr_type_own, - uint16_t conn_int_min, uint16_t conn_int_max, - uint16_t conn_latency, uint16_t conn_timeout, - uint16_t min_ce_len, uint16_t max_ce_len) { - body(scan_int, scan_win, init_filter_policy, addr_type_peer, bda_peer, - addr_type_own, conn_int_min, conn_int_max, conn_latency, conn_timeout, - min_ce_len, max_ce_len); - }; -}; -extern struct btsnd_hcic_ble_create_ll_conn btsnd_hcic_ble_create_ll_conn; - // Name: btsnd_hcic_ble_enh_rx_test // Params: uint8_t rx_chan, uint8_t phy, uint8_t mod_index // Return: void @@ -236,26 +150,6 @@ struct btsnd_hcic_ble_enh_tx_test { }; extern struct btsnd_hcic_ble_enh_tx_test btsnd_hcic_ble_enh_tx_test; -// Name: btsnd_hcic_ble_ext_create_conn -// Params: uint8_t init_filter_policy, tBLE_ADDR_TYPE addr_type_own, -// tBLE_ADDR_TYPE addr_type_peer, const RawAddress& bda_peer, uint8_t -// initiating_phys, EXT_CONN_PHY_CFG* phy_cfg Return: void -struct btsnd_hcic_ble_ext_create_conn { - std::function - body{[](uint8_t init_filter_policy, tBLE_ADDR_TYPE addr_type_own, - tBLE_ADDR_TYPE addr_type_peer, const RawAddress& bda_peer, - uint8_t initiating_phys, EXT_CONN_PHY_CFG* phy_cfg) {}}; - void operator()(uint8_t init_filter_policy, tBLE_ADDR_TYPE addr_type_own, - tBLE_ADDR_TYPE addr_type_peer, const RawAddress& bda_peer, - uint8_t initiating_phys, EXT_CONN_PHY_CFG* phy_cfg) { - body(init_filter_policy, addr_type_own, addr_type_peer, bda_peer, - initiating_phys, phy_cfg); - }; -}; -extern struct btsnd_hcic_ble_ext_create_conn btsnd_hcic_ble_ext_create_conn; - // Name: btsnd_hcic_ble_ltk_req_neg_reply // Params: uint16_t handle // Return: void @@ -411,25 +305,6 @@ struct btsnd_hcic_ble_read_adv_chnl_tx_power { extern struct btsnd_hcic_ble_read_adv_chnl_tx_power btsnd_hcic_ble_read_adv_chnl_tx_power; -// Name: btsnd_hcic_ble_read_chnl_map -// Params: uint16_t handle -// Return: void -struct btsnd_hcic_ble_read_chnl_map { - std::function body{[](uint16_t handle) {}}; - void operator()(uint16_t handle) { body(handle); }; -}; -extern struct btsnd_hcic_ble_read_chnl_map btsnd_hcic_ble_read_chnl_map; - -// Name: btsnd_hcic_ble_read_host_supported -// Params: void -// Return: void -struct btsnd_hcic_ble_read_host_supported { - std::function body{[](void) {}}; - void operator()(void) { body(); }; -}; -extern struct btsnd_hcic_ble_read_host_supported - btsnd_hcic_ble_read_host_supported; - // Name: btsnd_hcic_ble_read_remote_feat // Params: uint16_t handle // Return: void @@ -439,19 +314,6 @@ struct btsnd_hcic_ble_read_remote_feat { }; extern struct btsnd_hcic_ble_read_remote_feat btsnd_hcic_ble_read_remote_feat; -// Name: btsnd_hcic_ble_read_resolvable_addr_local -// Params: uint8_t addr_type_peer, const RawAddress& bda_peer -// Return: void -struct btsnd_hcic_ble_read_resolvable_addr_local { - std::function body{ - [](uint8_t addr_type_peer, const RawAddress& bda_peer) {}}; - void operator()(uint8_t addr_type_peer, const RawAddress& bda_peer) { - body(addr_type_peer, bda_peer); - }; -}; -extern struct btsnd_hcic_ble_read_resolvable_addr_local - btsnd_hcic_ble_read_resolvable_addr_local; - // Name: btsnd_hcic_ble_read_resolvable_addr_peer // Params: uint8_t addr_type_peer, const RawAddress& bda_peer // Return: void @@ -464,6 +326,16 @@ struct btsnd_hcic_ble_read_resolvable_addr_peer { }; extern struct btsnd_hcic_ble_read_resolvable_addr_peer btsnd_hcic_ble_read_resolvable_addr_peer; + +// Name: btsnd_hcic_ble_receiver_test +// Params: uint8_t rx_freq +// Return: void +struct btsnd_hcic_ble_receiver_test { + std::function body{[](uint8_t rx_freq) {}}; + void operator()(uint8_t rx_freq) { body(rx_freq); }; +}; +extern struct btsnd_hcic_ble_receiver_test btsnd_hcic_ble_receiver_test; + // Name: btsnd_hcic_ble_rm_device_resolving_list // Params: uint8_t addr_type_peer, const RawAddress& bda_peer // Return: void @@ -477,19 +349,6 @@ struct btsnd_hcic_ble_rm_device_resolving_list { extern struct btsnd_hcic_ble_rm_device_resolving_list btsnd_hcic_ble_rm_device_resolving_list; -// Name: btsnd_hcic_ble_set_addr_resolution_enable -// Params: uint8_t addr_resolution_enable -// Return: void -struct btsnd_hcic_ble_set_addr_resolution_enable { - std::function body{ - [](uint8_t addr_resolution_enable) {}}; - void operator()(uint8_t addr_resolution_enable) { - body(addr_resolution_enable); - }; -}; -extern struct btsnd_hcic_ble_set_addr_resolution_enable - btsnd_hcic_ble_set_addr_resolution_enable; - // Name: btsnd_hcic_ble_set_adv_data // Params: uint8_t data_len, uint8_t* p_data // Return: void @@ -576,27 +435,6 @@ struct btsnd_hcic_ble_set_extended_scan_params { extern struct btsnd_hcic_ble_set_extended_scan_params btsnd_hcic_ble_set_extended_scan_params; -// Name: btsnd_hcic_ble_set_host_chnl_class -// Params: uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE] -// Return: void -struct btsnd_hcic_ble_set_host_chnl_class { - std::function body{ - [](uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE]) {}}; - void operator()(uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE]) { body(chnl_map); }; -}; -extern struct btsnd_hcic_ble_set_host_chnl_class - btsnd_hcic_ble_set_host_chnl_class; - -// Name: btsnd_hcic_ble_set_local_used_feat -// Params: uint8_t feat_set[8] -// Return: void -struct btsnd_hcic_ble_set_local_used_feat { - std::function body{[](uint8_t feat_set[8]) {}}; - void operator()(uint8_t feat_set[]) { body(feat_set); }; -}; -extern struct btsnd_hcic_ble_set_local_used_feat - btsnd_hcic_ble_set_local_used_feat; - // Name: btsnd_hcic_ble_set_periodic_advertising_receive_enable // Params: uint16_t sync_handle, bool enable, base::OnceCallback body{ - [](const RawAddress& random_bda) {}}; - void operator()(const RawAddress& random_bda) { body(random_bda); }; -}; -extern struct btsnd_hcic_ble_set_random_addr btsnd_hcic_ble_set_random_addr; - // Name: btsnd_hcic_ble_set_scan_enable // Params: uint8_t scan_enable, uint8_t duplicate // Return: void @@ -694,18 +522,6 @@ struct btsnd_hcic_ble_set_scan_params { }; extern struct btsnd_hcic_ble_set_scan_params btsnd_hcic_ble_set_scan_params; -// Name: btsnd_hcic_ble_set_scan_rsp_data -// Params: uint8_t data_len, uint8_t* p_scan_rsp -// Return: void -struct btsnd_hcic_ble_set_scan_rsp_data { - std::function body{ - [](uint8_t data_len, uint8_t* p_scan_rsp) {}}; - void operator()(uint8_t data_len, uint8_t* p_scan_rsp) { - body(data_len, p_scan_rsp); - }; -}; -extern struct btsnd_hcic_ble_set_scan_rsp_data btsnd_hcic_ble_set_scan_rsp_data; - // Name: btsnd_hcic_ble_start_enc // Params: uint16_t handle, uint8_t rand[HCIC_BLE_RAND_DI_SIZE], uint16_t ediv, // const Octet16& ltk Return: void @@ -721,6 +537,27 @@ struct btsnd_hcic_ble_start_enc { }; extern struct btsnd_hcic_ble_start_enc btsnd_hcic_ble_start_enc; +// Name: btsnd_hcic_ble_test_end +// Params: void +// Return: void +struct btsnd_hcic_ble_test_end { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btsnd_hcic_ble_test_end btsnd_hcic_ble_test_end; + +// Name: btsnd_hcic_ble_transmitter_test +// Params: uint8_t tx_freq, uint8_t test_data_len, uint8_t payload +// Return: void +struct btsnd_hcic_ble_transmitter_test { + std::function + body{[](uint8_t tx_freq, uint8_t test_data_len, uint8_t payload) {}}; + void operator()(uint8_t tx_freq, uint8_t test_data_len, uint8_t payload) { + body(tx_freq, test_data_len, payload); + }; +}; +extern struct btsnd_hcic_ble_transmitter_test btsnd_hcic_ble_transmitter_test; + // Name: btsnd_hcic_ble_upd_ll_conn_params // Params: uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max, // uint16_t conn_latency, uint16_t conn_timeout, uint16_t min_ce_len, uint16_t @@ -822,20 +659,6 @@ struct btsnd_hcic_read_iso_link_quality { }; extern struct btsnd_hcic_read_iso_link_quality btsnd_hcic_read_iso_link_quality; -// Name: btsnd_hcic_read_iso_tx_sync -// Params: uint16_t iso_handle, base::OnceCallback)> - body{[](uint16_t iso_handle, - base::OnceCallback cb) {}}; - void operator()(uint16_t iso_handle, - base::OnceCallback cb) { - body(iso_handle, std::move(cb)); - }; -}; -extern struct btsnd_hcic_read_iso_tx_sync btsnd_hcic_read_iso_tx_sync; - // Name: btsnd_hcic_rej_cis_req // Params: uint16_t conn_handle, uint8_t reason, // base::OnceCallback -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_hcic_hcicmds.h" +#include "test/common/mock_functions.h" // Mocked internal structures, if any @@ -40,10 +38,10 @@ struct btsnd_hcic_accept_conn btsnd_hcic_accept_conn; struct btsnd_hcic_accept_esco_conn btsnd_hcic_accept_esco_conn; struct btsnd_hcic_add_SCO_conn btsnd_hcic_add_SCO_conn; struct btsnd_hcic_auth_request btsnd_hcic_auth_request; -struct btsnd_hcic_change_conn_type btsnd_hcic_change_conn_type; struct btsnd_hcic_change_name btsnd_hcic_change_name; struct btsnd_hcic_create_conn_cancel btsnd_hcic_create_conn_cancel; struct btsnd_hcic_delete_stored_key btsnd_hcic_delete_stored_key; +struct btsnd_hcic_enable_test_mode btsnd_hcic_enable_test_mode; struct btsnd_hcic_enhanced_accept_synchronous_connection btsnd_hcic_enhanced_accept_synchronous_connection; struct btsnd_hcic_enhanced_flush btsnd_hcic_enhanced_flush; @@ -76,6 +74,7 @@ struct btsnd_hcic_rmt_name_req btsnd_hcic_rmt_name_req; struct btsnd_hcic_rmt_name_req_cancel btsnd_hcic_rmt_name_req_cancel; struct btsnd_hcic_rmt_ver_req btsnd_hcic_rmt_ver_req; struct btsnd_hcic_set_conn_encrypt btsnd_hcic_set_conn_encrypt; +struct btsnd_hcic_set_event_filter btsnd_hcic_set_event_filter; struct btsnd_hcic_setup_esco_conn btsnd_hcic_setup_esco_conn; struct btsnd_hcic_sniff_mode btsnd_hcic_sniff_mode; struct btsnd_hcic_sniff_sub_rate btsnd_hcic_sniff_sub_rate; @@ -101,7 +100,6 @@ struct btsnd_hcic_write_pin_type btsnd_hcic_write_pin_type; struct btsnd_hcic_write_policy_set btsnd_hcic_write_policy_set; struct btsnd_hcic_write_scan_enable btsnd_hcic_write_scan_enable; struct btsnd_hcic_write_voice_settings btsnd_hcic_write_voice_settings; -struct btsnd_hcic_configure_data_path btsnd_hcic_configure_data_path; } // namespace stack_hcic_hcicmds } // namespace mock @@ -131,11 +129,6 @@ void btsnd_hcic_auth_request(uint16_t handle) { inc_func_call_count(__func__); test::mock::stack_hcic_hcicmds::btsnd_hcic_auth_request(handle); } -void btsnd_hcic_change_conn_type(uint16_t handle, uint16_t packet_types) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hcicmds::btsnd_hcic_change_conn_type(handle, - packet_types); -} void btsnd_hcic_change_name(BD_NAME name) { inc_func_call_count(__func__); test::mock::stack_hcic_hcicmds::btsnd_hcic_change_name(name); @@ -150,6 +143,10 @@ void btsnd_hcic_delete_stored_key(const RawAddress& bd_addr, test::mock::stack_hcic_hcicmds::btsnd_hcic_delete_stored_key(bd_addr, delete_all_flag); } +void btsnd_hcic_enable_test_mode(void) { + inc_func_call_count(__func__); + test::mock::stack_hcic_hcicmds::btsnd_hcic_enable_test_mode(); +} void btsnd_hcic_enhanced_accept_synchronous_connection( const RawAddress& bd_addr, enh_esco_params_t* p_params) { inc_func_call_count(__func__); @@ -289,6 +286,12 @@ void btsnd_hcic_set_conn_encrypt(uint16_t handle, bool enable) { inc_func_call_count(__func__); test::mock::stack_hcic_hcicmds::btsnd_hcic_set_conn_encrypt(handle, enable); } +void btsnd_hcic_set_event_filter(uint8_t filt_type, uint8_t filt_cond_type, + uint8_t* filt_cond, uint8_t filt_cond_len) { + inc_func_call_count(__func__); + test::mock::stack_hcic_hcicmds::btsnd_hcic_set_event_filter( + filt_type, filt_cond_type, filt_cond, filt_cond_len); +} void btsnd_hcic_setup_esco_conn(uint16_t handle, uint32_t transmit_bandwidth, uint32_t receive_bandwidth, uint16_t max_latency, uint16_t voice, @@ -324,11 +327,11 @@ void btsnd_hcic_user_passkey_reply(const RawAddress& bd_addr, uint32_t value) { inc_func_call_count(__func__); test::mock::stack_hcic_hcicmds::btsnd_hcic_user_passkey_reply(bd_addr, value); } -void btsnd_hcic_vendor_spec_cmd(void* buffer, uint16_t opcode, uint8_t len, - uint8_t* p_data, void* p_cmd_cplt_cback) { +void btsnd_hcic_vendor_spec_cmd(uint16_t opcode, uint8_t len, uint8_t* p_data, + tBTM_VSC_CMPL_CB* p_cmd_cplt_cback) { inc_func_call_count(__func__); test::mock::stack_hcic_hcicmds::btsnd_hcic_vendor_spec_cmd( - buffer, opcode, len, p_data, p_cmd_cplt_cback); + opcode, len, p_data, p_cmd_cplt_cback); } void btsnd_hcic_write_auth_enable(uint8_t flag) { inc_func_call_count(__func__); @@ -404,13 +407,5 @@ void btsnd_hcic_write_voice_settings(uint16_t flags) { inc_func_call_count(__func__); test::mock::stack_hcic_hcicmds::btsnd_hcic_write_voice_settings(flags); } - -void btsnd_hcic_configure_data_path(uint8_t data_path_direction, - uint8_t data_path_id, - std::vector vendor_config) { - inc_func_call_count(__func__); - test::mock::stack_hcic_hcicmds::btsnd_hcic_configure_data_path( - data_path_direction, data_path_id, vendor_config); -} // Mocked functions complete // END mockcify generation diff --git a/system/test/mock/mock_stack_hcic_hcicmds.h b/system/test/mock/mock_stack_hcic_hcicmds.h index 81bbfeba3dd66928f6ee3002cc4fa40c56e69ac1..b0d5d3ef78fc13b910c2854286fcd13aa867f57a 100644 --- a/system/test/mock/mock_stack_hcic_hcicmds.h +++ b/system/test/mock/mock_stack_hcic_hcicmds.h @@ -25,29 +25,12 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune from (or add to ) the inclusion set. -#include -#include -#include - -#include "bt_target.h" -#include "btu.h" +#include "base/callback.h" #include "device/include/esco_parameters.h" -#include "hcidefs.h" #include "hcimsgs.h" -#include "osi/include/allocator.h" -#include "stack/include/acl_hci_link_interface.h" -#include "stack/include/bt_hdr.h" #include "stack/include/bt_octets.h" -#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any @@ -110,18 +93,6 @@ struct btsnd_hcic_auth_request { }; extern struct btsnd_hcic_auth_request btsnd_hcic_auth_request; -// Name: btsnd_hcic_change_conn_type -// Params: uint16_t handle, uint16_t packet_types -// Return: void -struct btsnd_hcic_change_conn_type { - std::function body{ - [](uint16_t handle, uint16_t packet_types) {}}; - void operator()(uint16_t handle, uint16_t packet_types) { - body(handle, packet_types); - }; -}; -extern struct btsnd_hcic_change_conn_type btsnd_hcic_change_conn_type; - // Name: btsnd_hcic_change_name // Params: BD_NAME name // Return: void @@ -153,6 +124,15 @@ struct btsnd_hcic_delete_stored_key { }; extern struct btsnd_hcic_delete_stored_key btsnd_hcic_delete_stored_key; +// Name: btsnd_hcic_enable_test_mode +// Params: void +// Return: void +struct btsnd_hcic_enable_test_mode { + std::function body{[](void) {}}; + void operator()(void) { body(); }; +}; +extern struct btsnd_hcic_enable_test_mode btsnd_hcic_enable_test_mode; + // Name: btsnd_hcic_enhanced_accept_synchronous_connection // Params: const RawAddress& bd_addr, enh_esco_params_t* p_params // Return: void @@ -487,6 +467,21 @@ struct btsnd_hcic_set_conn_encrypt { }; extern struct btsnd_hcic_set_conn_encrypt btsnd_hcic_set_conn_encrypt; +// Name: btsnd_hcic_set_event_filter +// Params: uint8_t filt_type, uint8_t filt_cond_type, uint8_t* filt_cond, +// uint8_t filt_cond_len Return: void +struct btsnd_hcic_set_event_filter { + std::function + body{[](uint8_t filt_type, uint8_t filt_cond_type, uint8_t* filt_cond, + uint8_t filt_cond_len) {}}; + void operator()(uint8_t filt_type, uint8_t filt_cond_type, uint8_t* filt_cond, + uint8_t filt_cond_len) { + body(filt_type, filt_cond_type, filt_cond, filt_cond_len); + }; +}; +extern struct btsnd_hcic_set_event_filter btsnd_hcic_set_event_filter; + // Name: btsnd_hcic_setup_esco_conn // Params: uint16_t handle, uint32_t transmit_bandwidth, uint32_t // receive_bandwidth, uint16_t max_latency, uint16_t voice, uint8_t @@ -579,16 +574,16 @@ struct btsnd_hcic_user_passkey_reply { extern struct btsnd_hcic_user_passkey_reply btsnd_hcic_user_passkey_reply; // Name: btsnd_hcic_vendor_spec_cmd -// Params: void* buffer, uint16_t opcode, uint8_t len, uint8_t* p_data, void* +// Params: uint16_t opcode, uint8_t len, uint8_t* p_data, void* // p_cmd_cplt_cback Return: void struct btsnd_hcic_vendor_spec_cmd { - std::function - body{[](void* buffer, uint16_t opcode, uint8_t len, uint8_t* p_data, - void* p_cmd_cplt_cback) {}}; - void operator()(void* buffer, uint16_t opcode, uint8_t len, uint8_t* p_data, - void* p_cmd_cplt_cback) { - body(buffer, opcode, len, p_data, p_cmd_cplt_cback); + std::function + body{[](uint16_t opcode, uint8_t len, uint8_t* p_data, + tBTM_VSC_CMPL_CB* p_cmd_cplt_cback) {}}; + void operator()(uint16_t opcode, uint8_t len, uint8_t* p_data, + tBTM_VSC_CMPL_CB* p_cmd_cplt_cback) { + body(opcode, len, p_data, p_cmd_cplt_cback); }; }; extern struct btsnd_hcic_vendor_spec_cmd btsnd_hcic_vendor_spec_cmd; @@ -762,21 +757,6 @@ struct btsnd_hcic_write_voice_settings { }; extern struct btsnd_hcic_write_voice_settings btsnd_hcic_write_voice_settings; -// Name: btsnd_hcic_configure_data_path -// Params: uint8_t data_path_direction, uint8_t data_path_id, -// std::vector vendor_config Return: void -struct btsnd_hcic_configure_data_path { - std::function vendor_config)> - body{[](uint8_t data_path_direction, uint8_t data_path_id, - std::vector vendor_config) {}}; - void operator()(uint8_t data_path_direction, uint8_t data_path_id, - std::vector vendor_config) { - body(data_path_direction, data_path_id, vendor_config); - }; -}; -extern struct btsnd_hcic_configure_data_path btsnd_hcic_configure_data_path; - } // namespace stack_hcic_hcicmds } // namespace mock } // namespace test diff --git a/system/test/mock/mock_stack_hidd_api.cc b/system/test/mock/mock_stack_hidd_api.cc index cade8b96d982662458d1e931c83bec5de749b88e..581f952902b58a4268fa53a48994e60073d6daa3 100644 --- a/system/test/mock/mock_stack_hidd_api.cc +++ b/system/test/mock/mock_stack_hidd_api.cc @@ -21,26 +21,16 @@ #include #include -#include -#include -#include - -#include "btm_api.h" -#include "hidd_api.h" -#include "hiddefs.h" -#include "stack/btm/btm_sec.h" -#include "stack/hid/hidd_int.h" +#include "stack/include/hidd_api.h" +#include "stack/include/hiddefs.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, - char* p_provider, uint16_t subclass, - uint16_t desc_len, uint8_t* p_desc_data) { +tHID_STATUS HID_DevAddRecord(uint32_t /* handle */, char* /* p_name */, + char* /* p_description */, char* /* p_provider */, + uint16_t /* subclass */, uint16_t /* desc_len */, + uint8_t* /* p_desc_data */) { inc_func_call_count(__func__); return HID_SUCCESS; } @@ -56,46 +46,51 @@ tHID_STATUS HID_DevDisconnect(void) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevGetDevice(RawAddress* addr) { +tHID_STATUS HID_DevGetDevice(RawAddress* /* addr */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevPlugDevice(const RawAddress& addr) { +tHID_STATUS HID_DevPlugDevice(const RawAddress& /* addr */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) { +tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* /* host_cback */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevReportError(uint8_t error) { +tHID_STATUS HID_DevReportError(uint8_t /* error */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id, - uint16_t len, uint8_t* p_data) { +tHID_STATUS HID_DevSendReport(uint8_t /* channel */, uint8_t /* type */, + uint8_t /* id */, uint16_t /* len */, + uint8_t* /* p_data */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevSetIncomingPolicy(bool allow) { +tHID_STATUS HID_DevSetIncomingPolicy(bool /* allow */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate, - uint32_t token_bucket_size, - uint32_t peak_bandwidth, uint32_t latency, - uint32_t delay_variation) { +tHID_STATUS HID_DevSetIncomingQos(uint8_t /* service_type */, + uint32_t /* token_rate */, + uint32_t /* token_bucket_size */, + uint32_t /* peak_bandwidth */, + uint32_t /* latency */, + uint32_t /* delay_variation */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate, - uint32_t token_bucket_size, - uint32_t peak_bandwidth, uint32_t latency, - uint32_t delay_variation) { +tHID_STATUS HID_DevSetOutgoingQos(uint8_t /* service_type */, + uint32_t /* token_rate */, + uint32_t /* token_bucket_size */, + uint32_t /* peak_bandwidth */, + uint32_t /* latency */, + uint32_t /* delay_variation */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_DevUnplugDevice(const RawAddress& addr) { +tHID_STATUS HID_DevUnplugDevice(const RawAddress& /* addr */) { inc_func_call_count(__func__); return HID_SUCCESS; } @@ -103,8 +98,4 @@ tHID_STATUS HID_DevVirtualCableUnplug(void) { inc_func_call_count(__func__); return HID_SUCCESS; } -uint8_t HID_DevSetTraceLevel(uint8_t new_level) { - inc_func_call_count(__func__); - return 0; -} void HID_DevInit(void) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_hidh.cc b/system/test/mock/mock_stack_hidh.cc index 9cee97f5d30c64ca242cd9c710cf88f39c814242..b3a1144a96627dc6f4856968c2d51929941f13b1 100644 --- a/system/test/mock/mock_stack_hidh.cc +++ b/system/test/mock/mock_stack_hidh.cc @@ -20,26 +20,19 @@ */ #include -#include -#include #include "stack/include/bt_hdr.h" #include "stack/include/hiddefs.h" #include "stack/include/hidh_api.h" -#include "stack/include/sdp_api.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tHID_STATUS HID_HostAddDev(const RawAddress& addr, uint16_t attr_mask, - uint8_t* handle) { +tHID_STATUS HID_HostAddDev(const RawAddress& /* addr */, + uint16_t /* attr_mask */, uint8_t* /* handle */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_HostCloseDev(uint8_t dev_handle) { +tHID_STATUS HID_HostCloseDev(uint8_t /* dev_handle */) { inc_func_call_count(__func__); return HID_SUCCESS; } @@ -47,35 +40,37 @@ tHID_STATUS HID_HostDeregister(void) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr, - tSDP_DISCOVERY_DB* p_db, uint32_t db_len, - tHID_HOST_SDP_CALLBACK* sdp_cback) { +tHID_STATUS HID_HostGetSDPRecord(const RawAddress& /* addr */, + tSDP_DISCOVERY_DB* /* p_db */, + uint32_t /* db_len */, + tHID_HOST_SDP_CALLBACK* /* sdp_cback */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_HostOpenDev(uint8_t dev_handle) { +bool HID_HostSDPDisable(const RawAddress& /* addr */) { inc_func_call_count(__func__); - return HID_SUCCESS; + return false; } -tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* dev_cback) { +tHID_STATUS HID_HostOpenDev(uint8_t /* dev_handle */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_HostRemoveDev(uint8_t dev_handle) { +tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* /* dev_cback */) { inc_func_call_count(__func__); return HID_SUCCESS; } -tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param, - uint16_t data, uint8_t report_id, BT_HDR* pbuf) { +tHID_STATUS HID_HostRemoveDev(uint8_t /* dev_handle */) { inc_func_call_count(__func__); return HID_SUCCESS; } -uint8_t HID_HostSetTraceLevel(uint8_t new_level) { +tHID_STATUS HID_HostWriteDev(uint8_t /* dev_handle */, uint8_t /* t_type */, + uint8_t /* param */, uint16_t /* data */, + uint8_t /* report_id */, BT_HDR* /* pbuf */) { inc_func_call_count(__func__); return HID_SUCCESS; } void HID_HostInit(void) { inc_func_call_count(__func__); } -void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len, - char* str) { +void hidh_get_str_attr(tSDP_DISC_REC* /* p_rec */, uint16_t /* attr_id */, + uint16_t /* max_len */, char* /* str */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_l2cap_api.cc b/system/test/mock/mock_stack_l2cap_api.cc index d4e31ff436df5e292e1a7bd7faf9d4e11f5d402a..63133f5e633f58e5dc1dd40d5c3bec96a3294c69 100644 --- a/system/test/mock/mock_stack_l2cap_api.cc +++ b/system/test/mock/mock_stack_l2cap_api.cc @@ -20,23 +20,13 @@ * * mockcify.pl ver 0.2 */ - -#include -#include +#include "test/mock/mock_stack_l2cap_api.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "test/mock/mock_stack_l2cap_api.h" -// Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif +#include "test/common/mock_functions.h" +// Mocked compile conditionals, if any // Mocked internal structures, if any namespace test { @@ -63,7 +53,6 @@ struct L2CA_DisconnectReq L2CA_DisconnectReq; struct L2CA_DisconnectLECocReq L2CA_DisconnectLECocReq; struct L2CA_GetRemoteCid L2CA_GetRemoteCid; struct L2CA_SetIdleTimeoutByBdAddr L2CA_SetIdleTimeoutByBdAddr; -struct L2CA_SetTraceLevel L2CA_SetTraceLevel; struct L2CA_UseLatencyMode L2CA_UseLatencyMode; struct L2CA_SetAclPriority L2CA_SetAclPriority; struct L2CA_SetAclLatency L2CA_SetAclLatency; @@ -194,10 +183,6 @@ bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout, return test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr( bd_addr, timeout, transport); } -uint8_t L2CA_SetTraceLevel(uint8_t new_level) { - inc_func_call_count(__func__); - return test::mock::stack_l2cap_api::L2CA_SetTraceLevel(new_level); -} bool L2CA_UseLatencyMode(const RawAddress& bd_addr, bool use_latency_mode) { inc_func_call_count(__func__); return test::mock::stack_l2cap_api::L2CA_UseLatencyMode(bd_addr, diff --git a/system/test/mock/mock_stack_l2cap_api.h b/system/test/mock/mock_stack_l2cap_api.h index 79fe84d8b7f87448c92ade1dd6fe556c81712c1c..06cb73dfaa2a769f6e425d56ae750bfe332ccc54 100644 --- a/system/test/mock/mock_stack_l2cap_api.h +++ b/system/test/mock/mock_stack_l2cap_api.h @@ -22,38 +22,19 @@ */ #include -#include -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. #include #include #include -#include -#include "device/include/controller.h" -#include "main/shim/l2c_api.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" -#include "stack/btm/btm_sec.h" #include "stack/include/bt_hdr.h" #include "stack/include/l2c_api.h" -#include "stack/l2cap/l2c_int.h" -#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_l2cap_api { @@ -64,7 +45,7 @@ namespace stack_l2cap_api { // Returns: tBT_TRANSPORT struct l2c_get_transport_from_fixed_cid { std::function body{ - [](uint16_t fixed_cid) { return 0; }}; + [](uint16_t /* fixed_cid */) { return 0; }}; 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; @@ -77,9 +58,10 @@ struct L2CA_Register2 { bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t required_remote_mtu, uint16_t sec_level)> - body{[](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, - bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, - uint16_t required_remote_mtu, uint16_t sec_level) { return 0; }}; + body{[](uint16_t /* psm */, const tL2CAP_APPL_INFO& /* p_cb_info */, + bool /* enable_snoop */, tL2CAP_ERTM_INFO* /* p_ertm_info */, + uint16_t /* my_mtu */, uint16_t /* required_remote_mtu */, + uint16_t /* sec_level */) { return 0; }}; uint16_t operator()(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, @@ -98,9 +80,10 @@ struct L2CA_Register { bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t required_remote_mtu, uint16_t sec_level)> - body{[](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, - bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, - uint16_t required_remote_mtu, uint16_t sec_level) { return 0; }}; + body{[](uint16_t /* psm */, const tL2CAP_APPL_INFO& /* p_cb_info */, + bool /* enable_snoop */, tL2CAP_ERTM_INFO* /* p_ertm_info */, + uint16_t /* my_mtu */, uint16_t /* required_remote_mtu */, + uint16_t /* sec_level */) { return 0; }}; uint16_t operator()(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, @@ -114,7 +97,7 @@ extern struct L2CA_Register L2CA_Register; // Params: uint16_t psm // Returns: void struct L2CA_Deregister { - std::function body{[](uint16_t psm) {}}; + std::function body{[](uint16_t /* psm */) {}}; void operator()(uint16_t psm) { body(psm); }; }; extern struct L2CA_Deregister L2CA_Deregister; @@ -130,7 +113,7 @@ extern struct L2CA_AllocateLePSM L2CA_AllocateLePSM; // Params: uint16_t psm // Returns: void struct L2CA_FreeLePSM { - std::function body{[](uint16_t psm) {}}; + std::function body{[](uint16_t /* psm */) {}}; void operator()(uint16_t psm) { body(psm); }; }; extern struct L2CA_FreeLePSM L2CA_FreeLePSM; @@ -140,9 +123,8 @@ extern struct L2CA_FreeLePSM L2CA_FreeLePSM; struct L2CA_ConnectReq2 { std::function - body{[](uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level) { - return 0; - }}; + body{[](uint16_t /* psm */, const RawAddress& /* p_bd_addr */, + uint16_t /* sec_level */) { return 0; }}; uint16_t operator()(uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level) { return body(psm, p_bd_addr, sec_level); @@ -154,7 +136,7 @@ extern struct L2CA_ConnectReq2 L2CA_ConnectReq2; // Returns: uint16_t struct L2CA_ConnectReq { std::function body{ - [](uint16_t psm, const RawAddress& p_bd_addr) { return 0; }}; + [](uint16_t /* psm */, const RawAddress& /* p_bd_addr */) { return 0; }}; uint16_t operator()(uint16_t psm, const RawAddress& p_bd_addr) { return body(psm, p_bd_addr); }; @@ -166,8 +148,9 @@ extern struct L2CA_ConnectReq L2CA_ConnectReq; struct L2CA_RegisterLECoc { std::function - body{[](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, - uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) { return 0; }}; + body{[](uint16_t /* psm */, const tL2CAP_APPL_INFO& /* p_cb_info */, + uint16_t /* sec_level */, + tL2CAP_LE_CFG_INFO /* cfg */) { return 0; }}; uint16_t operator()(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) { return body(psm, p_cb_info, sec_level, cfg); @@ -178,7 +161,7 @@ extern struct L2CA_RegisterLECoc L2CA_RegisterLECoc; // Params: uint16_t psm // Returns: void struct L2CA_DeregisterLECoc { - std::function body{[](uint16_t psm) {}}; + std::function body{[](uint16_t /* psm */) {}}; void operator()(uint16_t psm) { body(psm); }; }; extern struct L2CA_DeregisterLECoc L2CA_DeregisterLECoc; @@ -188,8 +171,9 @@ extern struct L2CA_DeregisterLECoc L2CA_DeregisterLECoc; struct L2CA_ConnectLECocReq { std::function - body{[](uint16_t psm, const RawAddress& p_bd_addr, - tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) { return 0; }}; + body{[](uint16_t /* psm */, const RawAddress& /* p_bd_addr */, + tL2CAP_LE_CFG_INFO* /* p_cfg */, + uint16_t /* sec_level */) { return 0; }}; uint16_t operator()(uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg, uint16_t sec_level) { return body(psm, p_bd_addr, p_cfg, sec_level); @@ -201,7 +185,9 @@ extern struct L2CA_ConnectLECocReq L2CA_ConnectLECocReq; // Returns: bool struct L2CA_GetPeerLECocConfig { std::function body{ - [](uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) { return false; }}; + [](uint16_t /* lcid */, tL2CAP_LE_CFG_INFO* /* peer_cfg */) { + return false; + }}; bool operator()(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) { return body(lcid, peer_cfg); }; @@ -214,9 +200,10 @@ struct L2CA_ConnectCreditBasedRsp { std::function& accepted_lcids, uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg)> - body{[](const RawAddress& p_bd_addr, uint8_t id, - std::vector& accepted_lcids, uint16_t result, - tL2CAP_LE_CFG_INFO* p_cfg) { return false; }}; + body{[](const RawAddress& /* p_bd_addr */, uint8_t /* id */, + std::vector& /* accepted_lcids */, + uint16_t /* result */, + tL2CAP_LE_CFG_INFO* /* p_cfg */) { return false; }}; bool operator()(const RawAddress& p_bd_addr, uint8_t id, std::vector& accepted_lcids, uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg) { @@ -231,8 +218,8 @@ struct L2CA_ConnectCreditBasedReq { std::vector cids; std::function(uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg)> - body{[this](uint16_t psm, const RawAddress& p_bd_addr, - tL2CAP_LE_CFG_INFO* p_cfg) { return cids; }}; + body{[this](uint16_t /* psm */, const RawAddress& /* p_bd_addr */, + tL2CAP_LE_CFG_INFO* /* p_cfg */) { return cids; }}; std::vector operator()(uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg) { return body(psm, p_bd_addr, p_cfg); @@ -245,8 +232,8 @@ extern struct L2CA_ConnectCreditBasedReq L2CA_ConnectCreditBasedReq; struct L2CA_ReconfigCreditBasedConnsReq { std::function& lcids, tL2CAP_LE_CFG_INFO* p_cfg)> - body{[](const RawAddress& bda, std::vector& lcids, - tL2CAP_LE_CFG_INFO* p_cfg) { return false; }}; + body{[](const RawAddress& /* bda */, std::vector& /* lcids */, + tL2CAP_LE_CFG_INFO* /* p_cfg */) { return false; }}; bool operator()(const RawAddress& bda, std::vector& lcids, tL2CAP_LE_CFG_INFO* p_cfg) { return body(bda, lcids, p_cfg); @@ -257,7 +244,8 @@ extern struct L2CA_ReconfigCreditBasedConnsReq L2CA_ReconfigCreditBasedConnsReq; // Params: uint16_t cid // Returns: bool struct L2CA_DisconnectReq { - std::function body{[](uint16_t cid) { return false; }}; + std::function body{ + [](uint16_t /* cid */) { return false; }}; bool operator()(uint16_t cid) { return body(cid); }; }; extern struct L2CA_DisconnectReq L2CA_DisconnectReq; @@ -265,7 +253,8 @@ extern struct L2CA_DisconnectReq L2CA_DisconnectReq; // Params: uint16_t cid // Returns: bool struct L2CA_DisconnectLECocReq { - std::function body{[](uint16_t cid) { return false; }}; + std::function body{ + [](uint16_t /* cid */) { return false; }}; bool operator()(uint16_t cid) { return body(cid); }; }; extern struct L2CA_DisconnectLECocReq L2CA_DisconnectLECocReq; @@ -274,7 +263,7 @@ extern struct L2CA_DisconnectLECocReq L2CA_DisconnectLECocReq; // Returns: bool struct L2CA_GetRemoteCid { std::function body{ - [](uint16_t lcid, uint16_t* rcid) { return false; }}; + [](uint16_t /* lcid */, uint16_t* /* rcid */) { return false; }}; bool operator()(uint16_t lcid, uint16_t* rcid) { return body(lcid, rcid); }; }; extern struct L2CA_GetRemoteCid L2CA_GetRemoteCid; @@ -284,29 +273,22 @@ extern struct L2CA_GetRemoteCid L2CA_GetRemoteCid; struct L2CA_SetIdleTimeoutByBdAddr { std::function - body{[](const RawAddress& bd_addr, uint16_t timeout, - tBT_TRANSPORT transport) { return false; }}; + body{[](const RawAddress& /* bd_addr */, uint16_t /* timeout */, + tBT_TRANSPORT /* transport */) { return false; }}; bool operator()(const RawAddress& bd_addr, uint16_t timeout, tBT_TRANSPORT transport) { return body(bd_addr, timeout, transport); }; }; extern struct L2CA_SetIdleTimeoutByBdAddr L2CA_SetIdleTimeoutByBdAddr; -// Name: L2CA_SetTraceLevel -// Params: uint8_t new_level -// Returns: uint8_t -struct L2CA_SetTraceLevel { - std::function body{ - [](uint8_t new_level) { return 0; }}; - uint8_t operator()(uint8_t new_level) { return body(new_level); }; -}; -extern struct L2CA_SetTraceLevel L2CA_SetTraceLevel; // Name: L2CA_UseLatencyMode // Params: const RawAddress& bd_addr, bool use_latency_mode // Returns: bool struct L2CA_UseLatencyMode { std::function body{ - [](const RawAddress& bd_addr, bool use_latency_mode) { return false; }}; + [](const RawAddress& /* bd_addr */, bool /* use_latency_mode */) { + return false; + }}; bool operator()(const RawAddress& bd_addr, bool use_latency_mode) { return body(bd_addr, use_latency_mode); }; @@ -317,7 +299,7 @@ extern struct L2CA_UseLatencyMode L2CA_UseLatencyMode; // Returns: bool struct L2CA_SetAclPriority { std::function body{ - [](const RawAddress& bd_addr, tL2CAP_PRIORITY priority) { + [](const RawAddress& /* bd_addr */, tL2CAP_PRIORITY /* priority */) { return false; }}; bool operator()(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) { @@ -330,7 +312,9 @@ extern struct L2CA_SetAclPriority L2CA_SetAclPriority; // Returns: bool struct L2CA_SetAclLatency { std::function body{ - [](const RawAddress& bd_addr, tL2CAP_LATENCY latency) { return false; }}; + [](const RawAddress& /* bd_addr */, tL2CAP_LATENCY /* latency */) { + return false; + }}; bool operator()(const RawAddress& bd_addr, tL2CAP_LATENCY latency) { return body(bd_addr, latency); }; @@ -341,7 +325,9 @@ extern struct L2CA_SetAclLatency L2CA_SetAclLatency; // Returns: bool struct L2CA_SetTxPriority { std::function body{ - [](uint16_t cid, tL2CAP_CHNL_PRIORITY priority) { return false; }}; + [](uint16_t /* cid */, tL2CAP_CHNL_PRIORITY /* priority */) { + return false; + }}; bool operator()(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) { return body(cid, priority); }; @@ -353,8 +339,8 @@ extern struct L2CA_SetTxPriority L2CA_SetTxPriority; struct L2CA_GetPeerFeatures { std::function - body{[](const RawAddress& bd_addr, uint32_t* p_ext_feat, - uint8_t* p_chnl_mask) { return false; }}; + body{[](const RawAddress& /* bd_addr */, uint32_t* /* p_ext_feat */, + uint8_t* /* p_chnl_mask */) { return false; }}; bool operator()(const RawAddress& bd_addr, uint32_t* p_ext_feat, uint8_t* p_chnl_mask) { return body(bd_addr, p_ext_feat, p_chnl_mask); @@ -366,7 +352,9 @@ extern struct L2CA_GetPeerFeatures L2CA_GetPeerFeatures; // Returns: bool struct L2CA_RegisterFixedChannel { std::function body{ - [](uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg) { return false; }}; + [](uint16_t /* fixed_cid */, tL2CAP_FIXED_CHNL_REG* /* p_freg */) { + return false; + }}; bool operator()(uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg) { return body(fixed_cid, p_freg); }; @@ -377,7 +365,9 @@ extern struct L2CA_RegisterFixedChannel L2CA_RegisterFixedChannel; // Returns: bool struct L2CA_ConnectFixedChnl { std::function body{ - [](uint16_t fixed_cid, const RawAddress& rem_bda) { return false; }}; + [](uint16_t /* fixed_cid */, const RawAddress& /* rem_bda */) { + return false; + }}; bool operator()(uint16_t fixed_cid, const RawAddress& rem_bda) { return body(fixed_cid, rem_bda); }; @@ -389,9 +379,8 @@ extern struct L2CA_ConnectFixedChnl L2CA_ConnectFixedChnl; struct L2CA_SendFixedChnlData { std::function - body{[](uint16_t fixed_cid, const RawAddress& rem_bda, BT_HDR* p_buf) { - return 0; - }}; + body{[](uint16_t /* fixed_cid */, const RawAddress& /* rem_bda */, + BT_HDR* /* p_buf */) { return 0; }}; uint16_t operator()(uint16_t fixed_cid, const RawAddress& rem_bda, BT_HDR* p_buf) { return body(fixed_cid, rem_bda, p_buf); @@ -403,7 +392,9 @@ extern struct L2CA_SendFixedChnlData L2CA_SendFixedChnlData; // Returns: bool struct L2CA_RemoveFixedChnl { std::function body{ - [](uint16_t fixed_cid, const RawAddress& rem_bda) { return false; }}; + [](uint16_t /* fixed_cid */, const RawAddress& /* rem_bda */) { + return false; + }}; bool operator()(uint16_t fixed_cid, const RawAddress& rem_bda) { return body(fixed_cid, rem_bda); }; @@ -414,7 +405,9 @@ extern struct L2CA_RemoveFixedChnl L2CA_RemoveFixedChnl; // Returns: bool struct L2CA_SetLeGattTimeout { std::function body{ - [](const RawAddress& rem_bda, uint16_t idle_tout) { return false; }}; + [](const RawAddress& /* rem_bda */, uint16_t /* idle_tout */) { + return false; + }}; bool operator()(const RawAddress& rem_bda, uint16_t idle_tout) { return body(rem_bda, idle_tout); }; @@ -425,7 +418,7 @@ extern struct L2CA_SetLeGattTimeout L2CA_SetLeGattTimeout; // Returns: bool struct L2CA_MarkLeLinkAsActive { std::function body{ - [](const RawAddress& rem_bda) { return false; }}; + [](const RawAddress& /* rem_bda */) { return false; }}; bool operator()(const RawAddress& rem_bda) { return body(rem_bda); }; }; extern struct L2CA_MarkLeLinkAsActive L2CA_MarkLeLinkAsActive; @@ -434,7 +427,7 @@ extern struct L2CA_MarkLeLinkAsActive L2CA_MarkLeLinkAsActive; // Returns: uint8_t struct L2CA_DataWrite { std::function body{ - [](uint16_t cid, BT_HDR* p_data) { return 0; }}; + [](uint16_t /* cid */, BT_HDR* /* p_data */) { return 0; }}; uint8_t operator()(uint16_t cid, BT_HDR* p_data) { return body(cid, p_data); }; @@ -445,7 +438,7 @@ extern struct L2CA_DataWrite L2CA_DataWrite; // Returns: uint8_t struct L2CA_LECocDataWrite { std::function body{ - [](uint16_t cid, BT_HDR* p_data) { return 0; }}; + [](uint16_t /* cid */, BT_HDR* /* p_data */) { return 0; }}; uint8_t operator()(uint16_t cid, BT_HDR* p_data) { return body(cid, p_data); }; @@ -456,7 +449,7 @@ extern struct L2CA_LECocDataWrite L2CA_LECocDataWrite; // Returns: bool struct L2CA_SetChnlFlushability { std::function body{ - [](uint16_t cid, bool is_flushable) { return false; }}; + [](uint16_t /* cid */, bool /* is_flushable */) { return false; }}; bool operator()(uint16_t cid, bool is_flushable) { return body(cid, is_flushable); }; @@ -467,7 +460,7 @@ extern struct L2CA_SetChnlFlushability L2CA_SetChnlFlushability; // Returns: uint16_t struct L2CA_FlushChannel { std::function body{ - [](uint16_t lcid, uint16_t num_to_flush) { return 0; }}; + [](uint16_t /* lcid */, uint16_t /* num_to_flush */) { return 0; }}; uint16_t operator()(uint16_t lcid, uint16_t num_to_flush) { return body(lcid, num_to_flush); }; @@ -478,7 +471,9 @@ extern struct L2CA_FlushChannel L2CA_FlushChannel; // Returns: bool struct L2CA_IsLinkEstablished { std::function body{ - [](const RawAddress& bd_addr, tBT_TRANSPORT transport) { return false; }}; + [](const RawAddress& /* bd_addr */, tBT_TRANSPORT /* transport */) { + return false; + }}; bool operator()(const RawAddress& bd_addr, tBT_TRANSPORT transport) { return body(bd_addr, transport); }; @@ -489,7 +484,7 @@ extern struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished; // Returns: void struct L2CA_SetMediaStreamChannel { std::function body{ - [](uint16_t local_media_cid, bool status) {}}; + [](uint16_t /* local_media_cid */, bool /* status */) {}}; void operator()(uint16_t local_media_cid, bool status) { body(local_media_cid, status); }; @@ -500,9 +495,8 @@ extern struct L2CA_SetMediaStreamChannel L2CA_SetMediaStreamChannel; // Returns: bool struct L2CA_isMediaChannel { std::function - body{[](uint16_t handle, uint16_t channel_id, bool is_local_cid) { - return false; - }}; + body{[](uint16_t /* handle */, uint16_t /* channel_id */, + bool /* is_local_cid */) { return false; }}; bool operator()(uint16_t handle, uint16_t channel_id, bool is_local_cid) { return body(handle, channel_id, is_local_cid); }; diff --git a/system/test/mock/mock_stack_l2cap_ble.cc b/system/test/mock/mock_stack_l2cap_ble.cc index e1ec0a18e7e7b90f13654cc79fe723d1ebfa3d33..8c0c6cfd280a98d1cc73c9cf0943cd10b16d10c5 100644 --- a/system/test/mock/mock_stack_l2cap_ble.cc +++ b/system/test/mock/mock_stack_l2cap_ble.cc @@ -20,26 +20,15 @@ * * mockcify.pl ver 0.2 */ - -#include -#include +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_l2cap_ble.h" // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_l2cap_ble.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -53,8 +42,6 @@ struct L2CA_ConsolidateParams L2CA_ConsolidateParams; struct L2CA_GetBleConnRole L2CA_GetBleConnRole; struct l2cble_notify_le_connection l2cble_notify_le_connection; struct l2cble_conn_comp l2cble_conn_comp; -struct l2cble_conn_comp_from_address_with_type - l2cble_conn_comp_from_address_with_type; struct l2cble_process_conn_update_evt l2cble_process_conn_update_evt; struct l2cble_process_sig_cmd l2cble_process_sig_cmd; struct l2cble_create_conn l2cble_create_conn; @@ -112,14 +99,6 @@ bool l2cble_conn_comp(uint16_t handle, uint8_t role, const RawAddress& bda, return test::mock::stack_l2cap_ble::l2cble_conn_comp( handle, role, bda, type, conn_interval, conn_latency, conn_timeout); } -bool l2cble_conn_comp_from_address_with_type( - uint16_t handle, uint8_t role, const tBLE_BD_ADDR& address_with_type, - uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout) { - inc_func_call_count(__func__); - return test::mock::stack_l2cap_ble::l2cble_conn_comp_from_address_with_type( - handle, role, address_with_type, conn_interval, conn_latency, - conn_timeout); -} void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status, uint16_t interval, uint16_t latency, uint16_t timeout) { @@ -186,7 +165,7 @@ void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport, } tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm, bool is_originator, - tL2CAP_SEC_CBACK* p_callback, + tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) { inc_func_call_count(__func__); return test::mock::stack_l2cap_ble::l2ble_sec_access_req( diff --git a/system/test/mock/mock_stack_l2cap_ble.h b/system/test/mock/mock_stack_l2cap_ble.h index 35bf34b67a3debb2784dc08b28782d64f65d8dc4..5c21a06efc8d36994a36e884200ea544007b0d85 100644 --- a/system/test/mock/mock_stack_l2cap_ble.h +++ b/system/test/mock/mock_stack_l2cap_ble.h @@ -23,27 +23,14 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "stack/include/l2c_api.h" #include "stack/l2cap/l2c_int.h" -#include "test/common/mock_functions.h" #include "types/ble_address_with_type.h" #include "types/hci_role.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_l2cap_ble { @@ -57,9 +44,10 @@ struct L2CA_UpdateBleConnParams { std::function - body{[](const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int, - uint16_t latency, uint16_t timeout, uint16_t min_ce_len, - uint16_t max_ce_len) { return false; }}; + body{[](const RawAddress& /* rem_bda */, uint16_t /* min_int */, + uint16_t /* max_int */, uint16_t /* latency */, + uint16_t /* timeout */, uint16_t /* min_ce_len */, + uint16_t /* max_ce_len */) { return false; }}; bool operator()(const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int, uint16_t latency, uint16_t timeout, uint16_t min_ce_len, uint16_t max_ce_len) { @@ -73,7 +61,7 @@ extern struct L2CA_UpdateBleConnParams L2CA_UpdateBleConnParams; // Returns: bool struct L2CA_EnableUpdateBleConnParams { std::function body{ - [](const RawAddress& rem_bda, bool enable) { return false; }}; + [](const RawAddress& /* rem_bda */, bool /* enable */) { return false; }}; bool operator()(const RawAddress& rem_bda, bool enable) { return body(rem_bda, enable); }; @@ -84,9 +72,8 @@ extern struct L2CA_EnableUpdateBleConnParams L2CA_EnableUpdateBleConnParams; // Returns: bool struct L2CA_ConsolidateParams { std::function - body{[](const RawAddress& identity_addr, const RawAddress& rpa) { - return false; - }}; + body{[](const RawAddress& /* identity_addr */, + const RawAddress& /* rpa */) { return false; }}; void operator()(const RawAddress& identity_addr, const RawAddress& rpa) { body(identity_addr, rpa); }; @@ -97,7 +84,7 @@ extern struct L2CA_ConsolidateParams L2CA_ConsolidateParams; // Returns: hci_role_t struct L2CA_GetBleConnRole { std::function body{ - [](const RawAddress& bd_addr) { return HCI_ROLE_CENTRAL; }}; + [](const RawAddress& /* bd_addr */) { return HCI_ROLE_CENTRAL; }}; hci_role_t operator()(const RawAddress& bd_addr) { return body(bd_addr); }; }; extern struct L2CA_GetBleConnRole L2CA_GetBleConnRole; @@ -105,7 +92,8 @@ extern struct L2CA_GetBleConnRole L2CA_GetBleConnRole; // Params: const RawAddress& bda // Returns: void struct l2cble_notify_le_connection { - std::function body{[](const RawAddress& bda) {}}; + std::function body{ + [](const RawAddress& /* bda */) {}}; void operator()(const RawAddress& bda) { body(bda); }; }; extern struct l2cble_notify_le_connection l2cble_notify_le_connection; @@ -117,9 +105,10 @@ struct l2cble_conn_comp { std::function - body{[](uint16_t handle, uint8_t role, const RawAddress& bda, - tBLE_ADDR_TYPE type, uint16_t conn_interval, - uint16_t conn_latency, uint16_t conn_timeout) { return false; }}; + body{[](uint16_t /* handle */, uint8_t /* role */, + const RawAddress& /* bda */, tBLE_ADDR_TYPE /* type */, + uint16_t /* conn_interval */, uint16_t /* conn_latency */, + uint16_t /* conn_timeout */) { return false; }}; bool operator()(uint16_t handle, uint8_t role, const RawAddress& bda, tBLE_ADDR_TYPE type, uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout) { @@ -128,34 +117,15 @@ struct l2cble_conn_comp { }; }; extern struct l2cble_conn_comp l2cble_conn_comp; -// Name: l2cble_conn_comp_from_address_with_type -// Params: uint16_t handle, uint8_t role, const tBLE_BD_ADDR& -// address_with_type, uint16_t conn_interval, uint16_t conn_latency, uint16_t -// conn_timeout Returns: bool -struct l2cble_conn_comp_from_address_with_type { - std::function - body{[](uint16_t handle, uint8_t role, - const tBLE_BD_ADDR& address_with_type, uint16_t conn_interval, - uint16_t conn_latency, uint16_t conn_timeout) { return false; }}; - bool operator()(uint16_t handle, uint8_t role, - const tBLE_BD_ADDR& address_with_type, uint16_t conn_interval, - uint16_t conn_latency, uint16_t conn_timeout) { - return body(handle, role, address_with_type, conn_interval, conn_latency, - conn_timeout); - }; -}; -extern struct l2cble_conn_comp_from_address_with_type - l2cble_conn_comp_from_address_with_type; // Name: l2cble_process_conn_update_evt // Params: uint16_t handle, uint8_t status, uint16_t interval, uint16_t latency, // uint16_t timeout Returns: void struct l2cble_process_conn_update_evt { std::function - body{[](uint16_t handle, uint8_t status, uint16_t interval, - uint16_t latency, uint16_t timeout) {}}; + body{[](uint16_t /* handle */, uint8_t /* status */, + uint16_t /* interval */, uint16_t /* latency */, + uint16_t /* timeout */) {}}; void operator()(uint16_t handle, uint8_t status, uint16_t interval, uint16_t latency, uint16_t timeout) { body(handle, status, interval, latency, timeout); @@ -167,7 +137,7 @@ extern struct l2cble_process_conn_update_evt l2cble_process_conn_update_evt; // Returns: void struct l2cble_process_sig_cmd { std::function body{ - [](tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {}}; + [](tL2C_LCB* /* p_lcb */, uint8_t* /* p */, uint16_t /* pkt_len */) {}}; void operator()(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) { body(p_lcb, p, pkt_len); }; @@ -178,7 +148,7 @@ extern struct l2cble_process_sig_cmd l2cble_process_sig_cmd; // Returns: bool struct l2cble_create_conn { std::function body{ - [](tL2C_LCB* p_lcb) { return false; }}; + [](tL2C_LCB* /* p_lcb */) { return false; }}; bool operator()(tL2C_LCB* p_lcb) { return body(p_lcb); }; }; extern struct l2cble_create_conn l2cble_create_conn; @@ -187,7 +157,7 @@ extern struct l2cble_create_conn l2cble_create_conn; // Returns: void struct l2c_link_processs_ble_num_bufs { std::function body{ - [](uint16_t num_lm_ble_bufs) {}}; + [](uint16_t /* num_lm_ble_bufs */) {}}; void operator()(uint16_t num_lm_ble_bufs) { body(num_lm_ble_bufs); }; }; extern struct l2c_link_processs_ble_num_bufs l2c_link_processs_ble_num_bufs; @@ -205,8 +175,9 @@ extern struct l2c_ble_link_adjust_allocation l2c_ble_link_adjust_allocation; struct l2cble_process_rc_param_request_evt { std::function - body{[](uint16_t handle, uint16_t int_min, uint16_t int_max, - uint16_t latency, uint16_t timeout) {}}; + body{[](uint16_t /* handle */, uint16_t /* int_min */, + uint16_t /* int_max */, uint16_t /* latency */, + uint16_t /* timeout */) {}}; void operator()(uint16_t handle, uint16_t int_min, uint16_t int_max, uint16_t latency, uint16_t timeout) { body(handle, int_min, int_max, latency, timeout); @@ -218,7 +189,7 @@ extern struct l2cble_process_rc_param_request_evt // Params: tL2C_LCB* p_lcb // Returns: void struct l2cble_update_data_length { - std::function body{[](tL2C_LCB* p_lcb) {}}; + std::function body{[](tL2C_LCB* /* p_lcb */) {}}; void operator()(tL2C_LCB* p_lcb) { body(p_lcb); }; }; extern struct l2cble_update_data_length l2cble_update_data_length; @@ -228,7 +199,8 @@ extern struct l2cble_update_data_length l2cble_update_data_length; struct l2cble_process_data_length_change_event { std::function - body{[](uint16_t handle, uint16_t tx_data_len, uint16_t rx_data_len) {}}; + body{[](uint16_t /* handle */, uint16_t /* tx_data_len */, + uint16_t /* rx_data_len */) {}}; void operator()(uint16_t handle, uint16_t tx_data_len, uint16_t rx_data_len) { body(handle, tx_data_len, rx_data_len); }; @@ -239,7 +211,7 @@ extern struct l2cble_process_data_length_change_event // Params: tL2C_CCB* p_ccb // Returns: void struct l2cble_credit_based_conn_req { - std::function body{[](tL2C_CCB* p_ccb) {}}; + std::function body{[](tL2C_CCB* /* p_ccb */) {}}; void operator()(tL2C_CCB* p_ccb) { body(p_ccb); }; }; extern struct l2cble_credit_based_conn_req l2cble_credit_based_conn_req; @@ -248,7 +220,7 @@ extern struct l2cble_credit_based_conn_req l2cble_credit_based_conn_req; // Returns: void struct l2cble_credit_based_conn_res { std::function body{ - [](tL2C_CCB* p_ccb, uint16_t result) {}}; + [](tL2C_CCB* /* p_ccb */, uint16_t /* result */) {}}; void operator()(tL2C_CCB* p_ccb, uint16_t result) { body(p_ccb, result); }; }; extern struct l2cble_credit_based_conn_res l2cble_credit_based_conn_res; @@ -257,7 +229,7 @@ extern struct l2cble_credit_based_conn_res l2cble_credit_based_conn_res; // Returns: void struct l2cble_send_flow_control_credit { std::function body{ - [](tL2C_CCB* p_ccb, uint16_t credit_value) {}}; + [](tL2C_CCB* /* p_ccb */, uint16_t /* credit_value */) {}}; void operator()(tL2C_CCB* p_ccb, uint16_t credit_value) { body(p_ccb, credit_value); }; @@ -267,7 +239,7 @@ extern struct l2cble_send_flow_control_credit l2cble_send_flow_control_credit; // Params: tL2C_CCB* p_ccb // Returns: void struct l2cble_send_peer_disc_req { - std::function body{[](tL2C_CCB* p_ccb) {}}; + std::function body{[](tL2C_CCB* /* p_ccb */) {}}; void operator()(tL2C_CCB* p_ccb) { body(p_ccb); }; }; extern struct l2cble_send_peer_disc_req l2cble_send_peer_disc_req; @@ -277,8 +249,8 @@ extern struct l2cble_send_peer_disc_req l2cble_send_peer_disc_req; struct l2cble_sec_comp { std::function - body{[](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); @@ -291,13 +263,13 @@ extern struct l2cble_sec_comp l2cble_sec_comp; struct l2ble_sec_access_req { std::function - body{[](const RawAddress& bd_addr, uint16_t psm, bool is_originator, - tL2CAP_SEC_CBACK* p_callback, - void* p_ref_data) { return L2CAP_LE_RESULT_CONN_OK; }}; + tBTM_SEC_CALLBACK* p_callback, void* p_ref_data)> + body{[](const RawAddress& /* bd_addr */, uint16_t /* psm */, + bool /* is_originator */, tBTM_SEC_CALLBACK* /* p_callback */, + void* /* p_ref_data */) { return L2CAP_LE_RESULT_CONN_OK; }}; tL2CAP_LE_RESULT_CODE operator()(const RawAddress& bd_addr, uint16_t psm, bool is_originator, - tL2CAP_SEC_CBACK* p_callback, + tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) { return body(bd_addr, psm, is_originator, p_callback, p_ref_data); }; @@ -309,8 +281,8 @@ extern struct l2ble_sec_access_req l2ble_sec_access_req; struct L2CA_AdjustConnectionIntervals { std::function - body{[](uint16_t* min_interval, uint16_t* max_interval, - uint16_t floor_interval) {}}; + body{[](uint16_t* /* min_interval */, uint16_t* /* max_interval */, + uint16_t /* floor_interval */) {}}; void operator()(uint16_t* min_interval, uint16_t* max_interval, uint16_t floor_interval) { body(min_interval, max_interval, floor_interval); @@ -321,7 +293,8 @@ extern struct L2CA_AdjustConnectionIntervals L2CA_AdjustConnectionIntervals; // Params: const RawAddress& bda // Returns: void struct l2cble_use_preferred_conn_params { - std::function body{[](const RawAddress& bda) {}}; + std::function body{ + [](const RawAddress& /* bda */) {}}; void operator()(const RawAddress& bda) { body(bda); }; }; extern struct l2cble_use_preferred_conn_params l2cble_use_preferred_conn_params; @@ -332,9 +305,10 @@ struct L2CA_SubrateRequest { std::function - body{[](const RawAddress& rem_bda, uint16_t subrate_min, - uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, - uint16_t timeout) { return false; }}; + body{[](const RawAddress& /* rem_bda */, uint16_t /* subrate_min */, + uint16_t /* subrate_max */, uint16_t /* max_latency */, + uint16_t /* cont_num */, + uint16_t /* timeout */) { return false; }}; bool operator()(const RawAddress& rem_bda, uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t timeout) { @@ -350,9 +324,9 @@ struct l2cble_process_subrate_change_evt { std::function - body{[](uint16_t handle, uint8_t status, uint16_t subrate_factor, - uint16_t peripheral_latency, uint16_t cont_num, - uint16_t timeout) {}}; + body{[](uint16_t /* handle */, uint8_t /* status */, + uint16_t /* subrate_factor */, uint16_t /* peripheral_latency */, + uint16_t /* cont_num */, uint16_t /* timeout */) {}}; void operator()(uint16_t handle, uint8_t status, uint16_t subrate_factor, uint16_t peripheral_latency, uint16_t cont_num, uint16_t timeout) { diff --git a/system/test/mock/mock_stack_l2cap_link.cc b/system/test/mock/mock_stack_l2cap_link.cc index 97e498098abee5c0444d9a0f35fcb5ad7b274b11..ca03b26b82f3ce9d2346bcd850d5f11452ddf742 100644 --- a/system/test/mock/mock_stack_l2cap_link.cc +++ b/system/test/mock/mock_stack_l2cap_link.cc @@ -18,11 +18,6 @@ * Generated mock file from original source file */ -#include -#include - -#define UNUSED_ATTR - #include #include "stack/include/bt_hdr.h" @@ -30,64 +25,62 @@ #include "test/common/mock_functions.h" #include "types/raw_address.h" -BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb) { +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) { +bool l2c_link_hci_disc_comp(uint16_t /* handle */, tHCI_REASON /* reason */) { inc_func_call_count(__func__); return false; } -tBTM_STATUS l2cu_ConnectAclForSecurity(const RawAddress& bd_addr) { +tBTM_STATUS l2cu_ConnectAclForSecurity(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return BTM_SUCCESS; } -tL2C_CCB* l2cu_get_next_channel_in_rr(tL2C_LCB* p_lcb) { +tL2C_CCB* l2cu_get_next_channel_in_rr(tL2C_LCB* /* p_lcb */) { inc_func_call_count(__func__); return nullptr; } -void l2c_OnHciModeChangeSendPendingPackets(RawAddress remote) { +void l2c_OnHciModeChangeSendPendingPackets(RawAddress /* remote */) { inc_func_call_count(__func__); } -void l2c_info_resp_timer_timeout(void* data) { inc_func_call_count(__func__); } -void l2c_link_adjust_allocation(void) { inc_func_call_count(__func__); } -void l2c_link_adjust_chnl_allocation(void) { inc_func_call_count(__func__); } -void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, uint16_t local_cid, - BT_HDR* p_buf) { +void l2c_info_resp_timer_timeout(void* /* data */) { inc_func_call_count(__func__); } -void l2c_link_hci_conn_comp(tHCI_STATUS status, uint16_t handle, - const RawAddress& p_bda) { +void l2c_link_adjust_allocation(void) { inc_func_call_count(__func__); } +void l2c_link_adjust_chnl_allocation(void) { inc_func_call_count(__func__); } +void l2c_link_check_send_pkts(tL2C_LCB* /* p_lcb */, uint16_t /* local_cid */, + BT_HDR* /* p_buf */) { inc_func_call_count(__func__); } -void l2c_link_hci_conn_req(const RawAddress& bd_addr) { +void l2c_link_hci_conn_comp(tHCI_STATUS /* status */, uint16_t /* handle */, + const RawAddress& /* p_bda */) { inc_func_call_count(__func__); } -void l2c_link_init(const uint16_t acl_buffer_count_classic) { +void l2c_link_init(const uint16_t /* acl_buffer_count_classic */) { inc_func_call_count(__func__); } -void l2c_link_role_changed(const RawAddress* bd_addr, uint8_t new_role, - uint8_t hci_status) { +void l2c_link_role_changed(const RawAddress* /* bd_addr */, + uint8_t /* new_role */, uint8_t /* hci_status */) { inc_func_call_count(__func__); } -void l2c_link_sec_comp(const RawAddress* p_bda, - UNUSED_ATTR tBT_TRANSPORT transport, void* p_ref_data, - uint8_t status) { +void l2c_link_sec_comp(const RawAddress* /* p_bda */, + tBT_TRANSPORT /* transport */, void* /* p_ref_data */, + uint8_t /* status */) { inc_func_call_count(__func__); } -void l2c_link_sec_comp2(const RawAddress& p_bda, - UNUSED_ATTR tBT_TRANSPORT transport, void* p_ref_data, - uint8_t status) { + +void l2c_link_segments_xmitted(BT_HDR* /* p_msg */) { 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) { +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__); } -void l2c_pin_code_request(const RawAddress& bd_addr) { +void l2c_pin_code_request(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); } -void l2cble_update_sec_act(const RawAddress& bd_addr, uint16_t sec_act) { +void l2cble_update_sec_act(const RawAddress& /* bd_addr */, + uint16_t /* sec_act */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_l2cap_main.cc b/system/test/mock/mock_stack_l2cap_main.cc index 18ded1832356eb06cf7a130875cf751700f5a5a4..9ff48db9fec4a51fc769cb0aa4d832e488c7f34c 100644 --- a/system/test/mock/mock_stack_l2cap_main.cc +++ b/system/test/mock/mock_stack_l2cap_main.cc @@ -19,35 +19,24 @@ * Functions generated:9 */ -#include - -#include -#include - -#include "bt_target.h" #include "l2c_api.h" -#include "l2cdefs.h" -#include "main/shim/shim.h" -#include "osi/include/log.h" -#include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "stack/l2cap/l2c_int.h" #include "test/common/mock_functions.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flags) { +uint8_t l2c_data_write(uint16_t /* cid */, BT_HDR* /* p_data */, + uint16_t /* flags */) { inc_func_call_count(__func__); return 0; } -void l2c_ccb_timer_timeout(void* data) { inc_func_call_count(__func__); } -void l2c_fcrb_ack_timer_timeout(void* data) { inc_func_call_count(__func__); } +void l2c_ccb_timer_timeout(void* /* data */) { inc_func_call_count(__func__); } +void l2c_fcrb_ack_timer_timeout(void* /* data */) { + inc_func_call_count(__func__); +} void l2c_free(void) { inc_func_call_count(__func__); } void l2c_init(void) { inc_func_call_count(__func__); } -void l2c_lcb_timer_timeout(void* data) { inc_func_call_count(__func__); } -void l2c_rcv_acl_data(BT_HDR* p_msg) { inc_func_call_count(__func__); } -void l2c_receive_hold_timer_timeout(UNUSED_ATTR void* data) { +void l2c_lcb_timer_timeout(void* /* data */) { inc_func_call_count(__func__); } +void l2c_rcv_acl_data(BT_HDR* /* p_msg */) { inc_func_call_count(__func__); } +void l2c_receive_hold_timer_timeout(void* /* data */) { 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 f1166f29474aad370c7ddc6686b66d6b259ba373..5cb8637fd8e0451f1c39b09767ed6d4435a70e56 100644 --- a/system/test/mock/mock_stack_l2cap_utils.cc +++ b/system/test/mock/mock_stack_l2cap_utils.cc @@ -20,40 +20,36 @@ */ #include -#include -#include #include "stack/include/bt_hdr.h" #include "stack/l2cap/l2c_int.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -BT_HDR* l2cu_build_header(tL2C_LCB* p_lcb, uint16_t len, uint8_t cmd, - uint8_t signal_id) { +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) { +bool l2c_is_cmd_rejected(uint8_t /* cmd_code */, uint8_t /* signal_id */, + tL2C_LCB* /* p_lcb */) { inc_func_call_count(__func__); return false; } -bool l2cu_create_conn_le(tL2C_LCB* p_lcb) { +bool l2cu_create_conn_le(tL2C_LCB* /* p_lcb */) { inc_func_call_count(__func__); return false; } -bool l2cu_create_conn_le(tL2C_LCB* p_lcb, uint8_t initiating_phys) { +bool l2cu_create_conn_le(tL2C_LCB* /* p_lcb */, uint8_t /* initiating_phys */) { inc_func_call_count(__func__); return false; } -bool l2cu_initialize_fixed_ccb(tL2C_LCB* p_lcb, uint16_t fixed_cid) { +bool l2cu_initialize_fixed_ccb(tL2C_LCB* /* p_lcb */, + uint16_t /* fixed_cid */) { inc_func_call_count(__func__); return false; } -bool l2cu_is_ccb_active(tL2C_CCB* p_ccb) { +bool l2cu_is_ccb_active(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); return false; } @@ -61,58 +57,63 @@ bool l2cu_lcb_disconnecting(void) { inc_func_call_count(__func__); return false; } -bool l2cu_set_acl_priority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority, - bool reset_after_rs) { +bool l2cu_set_acl_priority(const RawAddress& /* bd_addr */, + tL2CAP_PRIORITY /* priority */, + bool /* reset_after_rs */) { inc_func_call_count(__func__); return false; } -bool l2cu_start_post_bond_timer(uint16_t handle) { +bool l2cu_start_post_bond_timer(uint16_t /* handle */) { inc_func_call_count(__func__); return false; } -tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid) { +tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* /* p_lcb */, uint16_t /* cid */, + bool /* is_eatt */) { inc_func_call_count(__func__); return nullptr; } -tL2C_CCB* l2cu_find_ccb_by_cid(tL2C_LCB* p_lcb, uint16_t local_cid) { +tL2C_CCB* l2cu_find_ccb_by_cid(tL2C_LCB* /* p_lcb */, + uint16_t /* local_cid */) { inc_func_call_count(__func__); return nullptr; } -tL2C_CCB* l2cu_find_ccb_by_remote_cid(tL2C_LCB* p_lcb, uint16_t remote_cid) { +tL2C_CCB* l2cu_find_ccb_by_remote_cid(tL2C_LCB* /* p_lcb */, + uint16_t /* remote_cid */) { inc_func_call_count(__func__); return nullptr; } -tL2C_LCB* l2cu_allocate_lcb(const RawAddress& p_bd_addr, bool is_bonding, - tBT_TRANSPORT transport) { +tL2C_LCB* l2cu_allocate_lcb(const RawAddress& /* p_bd_addr */, + bool /* is_bonding */, + tBT_TRANSPORT /* transport */) { inc_func_call_count(__func__); return nullptr; } -tL2C_LCB* l2cu_find_lcb_by_bd_addr(const RawAddress& p_bd_addr, - tBT_TRANSPORT transport) { +tL2C_LCB* l2cu_find_lcb_by_bd_addr(const RawAddress& /* p_bd_addr */, + tBT_TRANSPORT /* transport */) { inc_func_call_count(__func__); return nullptr; } -tL2C_LCB* l2cu_find_lcb_by_handle(uint16_t handle) { +tL2C_LCB* l2cu_find_lcb_by_handle(uint16_t /* handle */) { inc_func_call_count(__func__); return nullptr; } -tL2C_LCB* l2cu_find_lcb_by_state(tL2C_LINK_STATE state) { +tL2C_LCB* l2cu_find_lcb_by_state(tL2C_LINK_STATE /* state */) { inc_func_call_count(__func__); return nullptr; } -tL2C_RCB* l2cu_allocate_ble_rcb(uint16_t psm) { +tL2C_RCB* l2cu_allocate_ble_rcb(uint16_t /* psm */) { inc_func_call_count(__func__); return nullptr; } -tL2C_RCB* l2cu_allocate_rcb(uint16_t psm) { +tL2C_RCB* l2cu_allocate_rcb(uint16_t /* psm */) { inc_func_call_count(__func__); return nullptr; } -tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm) { +tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t /* psm */) { inc_func_call_count(__func__); return nullptr; } -tL2C_RCB* l2cu_find_rcb_by_psm(uint16_t psm) { +tL2C_RCB* l2cu_find_rcb_by_psm(uint16_t /* psm */) { inc_func_call_count(__func__); return nullptr; } @@ -120,151 +121,176 @@ 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) { +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) { +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__); } -void l2cu_check_channel_congestion(tL2C_CCB* p_ccb) { +void l2cu_check_channel_congestion(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } -void l2cu_create_conn_after_switch(tL2C_LCB* p_lcb) { +void l2cu_create_conn_after_switch(tL2C_LCB* /* p_lcb */) { inc_func_call_count(__func__); } -void l2cu_create_conn_br_edr(tL2C_LCB* p_lcb) { inc_func_call_count(__func__); } -void l2cu_dequeue_ccb(tL2C_CCB* p_ccb) { inc_func_call_count(__func__); } +void l2cu_create_conn_br_edr(tL2C_LCB* /* p_lcb */) { + inc_func_call_count(__func__); +} +void l2cu_dequeue_ccb(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } void l2cu_device_reset(void) { inc_func_call_count(__func__); } -void l2cu_disconnect_chnl(tL2C_CCB* p_ccb) { inc_func_call_count(__func__); } -void l2cu_enqueue_ccb(tL2C_CCB* p_ccb) { inc_func_call_count(__func__); } -void l2cu_no_dynamic_ccbs(tL2C_LCB* p_lcb) { inc_func_call_count(__func__); } -void l2cu_process_fixed_chnl_resp(tL2C_LCB* p_lcb) { +void l2cu_disconnect_chnl(tL2C_CCB* /* p_ccb */) { + inc_func_call_count(__func__); +} +void l2cu_enqueue_ccb(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } +void l2cu_no_dynamic_ccbs(tL2C_LCB* /* p_lcb */) { + inc_func_call_count(__func__); +} +void l2cu_process_fixed_chnl_resp(tL2C_LCB* /* p_lcb */) { + inc_func_call_count(__func__); +} +void l2cu_process_fixed_disc_cback(tL2C_LCB* /* p_lcb */) { + inc_func_call_count(__func__); +} +void l2cu_process_our_cfg_req(tL2C_CCB* /* p_ccb */, + tL2CAP_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); } -void l2cu_process_fixed_disc_cback(tL2C_LCB* p_lcb) { +void l2cu_process_our_cfg_rsp(tL2C_CCB* /* p_ccb */, + tL2CAP_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); } -void l2cu_process_our_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { +void l2cu_process_peer_cfg_rsp(tL2C_CCB* /* p_ccb */, + tL2CAP_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); } -void l2cu_process_our_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { +void l2cu_reject_ble_coc_connection(tL2C_LCB* /* p_lcb */, uint8_t /* rem_id */, + uint16_t /* result */) { inc_func_call_count(__func__); } -void l2cu_process_peer_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { +void l2cu_reject_ble_connection(tL2C_CCB* /* p_ccb */, uint8_t /* rem_id */, + uint16_t /* result */) { inc_func_call_count(__func__); } -void l2cu_reject_ble_coc_connection(tL2C_LCB* p_lcb, uint8_t rem_id, - uint16_t result) { +void l2cu_reject_connection(tL2C_LCB* /* p_lcb */, uint16_t /* remote_cid */, + uint8_t /* rem_id */, uint16_t /* result */) { inc_func_call_count(__func__); } -void l2cu_reject_ble_connection(tL2C_CCB* p_ccb, uint8_t rem_id, - uint16_t result) { +void l2cu_reject_credit_based_conn_req(tL2C_LCB* /* p_lcb */, + uint8_t /* rem_id */, + uint8_t /* num_of_channels */, + uint16_t /* result */) { inc_func_call_count(__func__); } -void l2cu_reject_connection(tL2C_LCB* p_lcb, uint16_t remote_cid, - uint8_t rem_id, uint16_t result) { +void l2cu_release_ble_rcb(tL2C_RCB* /* p_rcb */) { inc_func_call_count(__func__); } -void l2cu_reject_credit_based_conn_req(tL2C_LCB* p_lcb, uint8_t rem_id, - uint8_t num_of_channels, - uint16_t result) { +void l2cu_release_ccb(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } +void l2cu_release_lcb(tL2C_LCB* /* p_lcb */) { inc_func_call_count(__func__); } +void l2cu_release_rcb(tL2C_RCB* /* p_rcb */) { inc_func_call_count(__func__); } +void l2cu_resubmit_pending_sec_req(const RawAddress* /* p_bda */) { inc_func_call_count(__func__); } -void l2cu_release_ble_rcb(tL2C_RCB* p_rcb) { inc_func_call_count(__func__); } -void l2cu_release_ccb(tL2C_CCB* p_ccb) { inc_func_call_count(__func__); } -void l2cu_release_lcb(tL2C_LCB* p_lcb) { inc_func_call_count(__func__); } -void l2cu_release_rcb(tL2C_RCB* p_rcb) { inc_func_call_count(__func__); } -void l2cu_resubmit_pending_sec_req(const RawAddress* p_bda) { +void l2cu_send_ble_reconfig_rsp(tL2C_LCB* /* p_lcb */, uint8_t /* rem_id */, + uint16_t /* result */) { inc_func_call_count(__func__); } -void l2cu_send_ble_reconfig_rsp(tL2C_LCB* p_lcb, uint8_t rem_id, - uint16_t result) { +void l2cu_send_credit_based_reconfig_req(tL2C_CCB* /* p_ccb */, + tL2CAP_LE_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); } -void l2cu_send_credit_based_reconfig_req(tL2C_CCB* p_ccb, - tL2CAP_LE_CFG_INFO* p_cfg) { +void l2cu_send_peer_ble_credit_based_conn_req(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } -void l2cu_send_peer_ble_credit_based_conn_req(tL2C_CCB* p_ccb) { +void l2cu_send_peer_ble_credit_based_conn_res(tL2C_CCB* /* p_ccb */, + uint16_t /* result */) { inc_func_call_count(__func__); } -void l2cu_send_peer_ble_credit_based_conn_res(tL2C_CCB* p_ccb, - uint16_t result) { +void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } -void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB* p_ccb) { +void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB* /* p_ccb */, + uint16_t /* credit_value */) { inc_func_call_count(__func__); } -void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB* p_ccb, - uint16_t credit_value) { +void l2cu_send_peer_ble_par_req(tL2C_LCB* /* p_lcb */, uint16_t /* min_int */, + uint16_t /* max_int */, uint16_t /* latency */, + uint16_t /* timeout */) { inc_func_call_count(__func__); } -void l2cu_send_peer_ble_par_req(tL2C_LCB* p_lcb, uint16_t min_int, - uint16_t max_int, uint16_t latency, - uint16_t timeout) { +void l2cu_send_peer_ble_par_rsp(tL2C_LCB* /* p_lcb */, uint16_t /* reason */, + uint8_t /* rem_id */) { inc_func_call_count(__func__); } -void l2cu_send_peer_ble_par_rsp(tL2C_LCB* p_lcb, uint16_t reason, - uint8_t rem_id) { +void l2cu_send_peer_cmd_reject(tL2C_LCB* /* p_lcb */, uint16_t /* reason */, + uint8_t /* rem_id */, uint16_t /* p1 */, + uint16_t /* p2 */) { inc_func_call_count(__func__); } -void l2cu_send_peer_cmd_reject(tL2C_LCB* p_lcb, uint16_t reason, uint8_t rem_id, - uint16_t p1, uint16_t p2) { +void l2cu_send_peer_config_rej(tL2C_CCB* /* p_ccb */, uint8_t* /* p_data */, + uint16_t /* data_len */, + uint16_t /* rej_len */) { inc_func_call_count(__func__); } -void l2cu_send_peer_config_rej(tL2C_CCB* p_ccb, uint8_t* p_data, - uint16_t data_len, uint16_t rej_len) { +void l2cu_send_peer_config_req(tL2C_CCB* /* p_ccb */, + tL2CAP_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); } -void l2cu_send_peer_config_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { +void l2cu_send_peer_config_rsp(tL2C_CCB* /* p_ccb */, + tL2CAP_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); } -void l2cu_send_peer_config_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { +void l2cu_send_peer_connect_req(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } -void l2cu_send_peer_connect_req(tL2C_CCB* p_ccb) { +void l2cu_send_peer_connect_rsp(tL2C_CCB* /* p_ccb */, uint16_t /* result */, + uint16_t /* status */) { inc_func_call_count(__func__); } -void l2cu_send_peer_connect_rsp(tL2C_CCB* p_ccb, uint16_t result, - uint16_t status) { +void l2cu_send_peer_credit_based_conn_req(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } -void l2cu_send_peer_credit_based_conn_req(tL2C_CCB* p_ccb) { +void l2cu_send_peer_credit_based_conn_res( + tL2C_CCB* /* p_ccb */, std::vector& /* accepted_cids */, + uint16_t /* result */) { inc_func_call_count(__func__); } -void l2cu_send_peer_credit_based_conn_res(tL2C_CCB* p_ccb, - std::vector& accepted_cids, - uint16_t result) { +void l2cu_send_peer_disc_req(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } -void l2cu_send_peer_disc_req(tL2C_CCB* p_ccb) { inc_func_call_count(__func__); } -void l2cu_send_peer_disc_rsp(tL2C_LCB* p_lcb, uint8_t remote_id, - uint16_t local_cid, uint16_t remote_cid) { +void l2cu_send_peer_disc_rsp(tL2C_LCB* /* p_lcb */, uint8_t /* remote_id */, + uint16_t /* local_cid */, + uint16_t /* remote_cid */) { inc_func_call_count(__func__); } -void l2cu_send_peer_echo_rsp(tL2C_LCB* p_lcb, uint8_t signal_id, - uint8_t* p_data, uint16_t data_len) { +void l2cu_send_peer_echo_rsp(tL2C_LCB* /* p_lcb */, uint8_t /* signal_id */, + uint8_t* /* p_data */, uint16_t /* data_len */) { inc_func_call_count(__func__); } -void l2cu_send_peer_info_req(tL2C_LCB* p_lcb, uint16_t info_type) { +void l2cu_send_peer_info_req(tL2C_LCB* /* p_lcb */, uint16_t /* info_type */) { inc_func_call_count(__func__); } -void l2cu_send_peer_info_rsp(tL2C_LCB* p_lcb, uint8_t remote_id, - uint16_t info_type) { +void l2cu_send_peer_info_rsp(tL2C_LCB* /* p_lcb */, uint8_t /* remote_id */, + uint16_t /* info_type */) { inc_func_call_count(__func__); } -void l2cu_set_acl_hci_header(BT_HDR* p_buf, tL2C_CCB* p_ccb) { +void l2cu_set_acl_hci_header(BT_HDR* /* p_buf */, tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } -void l2cu_set_lcb_handle(struct t_l2c_linkcb& p_lcb, uint16_t handle) { +void l2cu_set_lcb_handle(struct t_l2c_linkcb& /* p_lcb */, + uint16_t /* handle */) { inc_func_call_count(__func__); } -void l2cu_set_non_flushable_pbf(bool is_supported) { +void l2cu_set_non_flushable_pbf(bool /* is_supported */) { inc_func_call_count(__func__); } -void l2cu_update_lcb_4_bonding(const RawAddress& p_bd_addr, bool is_bonding) { +void l2cu_update_lcb_4_bonding(const RawAddress& /* p_bd_addr */, + bool /* is_bonding */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_metrics_logging.cc b/system/test/mock/mock_stack_metrics_logging.cc index 3a5e2d1277355b74a317d81527287eca16d8de88..ed2225c4ecc5f9b72617eda10bdccb075f2dff2d 100644 --- a/system/test/mock/mock_stack_metrics_logging.cc +++ b/system/test/mock/mock_stack_metrics_logging.cc @@ -20,29 +20,19 @@ * * mockcify.pl ver 0.2 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_metrics_logging.h" -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. #include #include +#include "test/common/mock_functions.h" #include "types/raw_address.h" -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_metrics_logging.h" - // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -57,6 +47,7 @@ struct log_sdp_attribute log_sdp_attribute; struct log_manufacturer_info log_manufacturer_info; struct log_counter_metrics log_counter_metrics; struct log_hfp_audio_packet_loss_stats log_hfp_audio_packet_loss_stats; +struct log_mmc_transcode_rtt_stats log_mmc_transcode_rtt_stats; } // namespace stack_metrics_logging } // namespace mock @@ -130,9 +121,17 @@ void log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum key, void log_hfp_audio_packet_loss_stats(const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio) { + double packet_loss_ratio, + uint16_t codec_type) { inc_func_call_count(__func__); test::mock::stack_metrics_logging::log_hfp_audio_packet_loss_stats( - address, num_decoded_frames, packet_loss_ratio); + address, num_decoded_frames, packet_loss_ratio, codec_type); +} + +void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, + int num_requests, int codec_type) { + inc_func_call_count(__func__); + test::mock::stack_metrics_logging::log_mmc_transcode_rtt_stats( + maximum_rtt, mean_rtt, num_requests, codec_type); } // END mockcify generation diff --git a/system/test/mock/mock_stack_metrics_logging.h b/system/test/mock/mock_stack_metrics_logging.h index ad6802920b3ddbfed4761f2082b83ed4b9205a84..fd34980a107af2304264e2da4ffc244e24f68091 100644 --- a/system/test/mock/mock_stack_metrics_logging.h +++ b/system/test/mock/mock_stack_metrics_logging.h @@ -21,24 +21,15 @@ * mockcify.pl ver 0.2 */ -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. #include #include -#include "test/common/mock_functions.h" +#include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif namespace test { namespace mock { @@ -193,15 +184,28 @@ extern struct log_counter_metrics log_counter_metrics; // Name: log_hfp_audio_packet_loss_stats struct log_hfp_audio_packet_loss_stats { std::function + double packet_loss_ratio, uint16_t codec_type)> body{[](const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio) {}}; + double packet_loss_ratio, uint16_t codec_type) {}}; void operator()(const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio) { - body(address, num_decoded_frames, packet_loss_ratio); + double packet_loss_ratio, uint16_t codec_type) { + body(address, num_decoded_frames, packet_loss_ratio, codec_type); }; }; extern struct log_hfp_audio_packet_loss_stats log_hfp_audio_packet_loss_stats; + +// Name: log_mmc_transcode_rtt_stats +struct log_mmc_transcode_rtt_stats { + std::function + body{[](int maximum_rtt, double mean_rtt, int num_requests, + int codec_type) {}}; + void operator()(int maximum_rtt, double mean_rtt, int num_requests, + int codec_type) { + body(maximum_rtt, mean_rtt, num_requests, codec_type); + }; +}; +extern struct log_mmc_transcode_rtt_stats log_mmc_transcode_rtt_stats; } // namespace stack_metrics_logging } // namespace mock } // namespace test diff --git a/system/test/mock/mock_stack_pan_api.cc b/system/test/mock/mock_stack_pan_api.cc index 88f291f56f9d83ed102c76179b33be1c8bc6fabc..4722d94ddb90871fd09aac52b8a2d0f805780829 100644 --- a/system/test/mock/mock_stack_pan_api.cc +++ b/system/test/mock/mock_stack_pan_api.cc @@ -20,20 +20,15 @@ * * mockcify.pl ver 0.2.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_pan_api.h" #include -#include -#include #include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_pan_api.h" +#include "test/common/mock_functions.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -48,7 +43,6 @@ struct PAN_SetProtocolFilters PAN_SetProtocolFilters; struct PAN_SetRole PAN_SetRole; struct PAN_Write PAN_Write; struct PAN_WriteBuf PAN_WriteBuf; -struct PAN_SetTraceLevel PAN_SetTraceLevel; struct PAN_Deregister PAN_Deregister; struct PAN_Dumpsys PAN_Dumpsys; struct PAN_Init PAN_Init; @@ -102,10 +96,6 @@ tPAN_RESULT PAN_WriteBuf(uint16_t handle, const RawAddress& dst, return test::mock::stack_pan_api::PAN_WriteBuf(handle, dst, src, protocol, p_buf, ext); } -uint8_t PAN_SetTraceLevel(uint8_t new_level) { - inc_func_call_count(__func__); - return test::mock::stack_pan_api::PAN_SetTraceLevel(new_level); -} void PAN_Deregister(void) { inc_func_call_count(__func__); test::mock::stack_pan_api::PAN_Deregister(); diff --git a/system/test/mock/mock_stack_pan_api.h b/system/test/mock/mock_stack_pan_api.h index 14a371c23c714be437cff7e250459a4b3233fb6d..b4ede2b3729ba6a5e9bd3a28c4eba271582b8640 100644 --- a/system/test/mock/mock_stack_pan_api.h +++ b/system/test/mock/mock_stack_pan_api.h @@ -23,30 +23,13 @@ #include #include -#include #include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include -#include - -#include -#include - #include "stack/include/pan_api.h" -#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_pan_api { @@ -58,8 +41,9 @@ namespace stack_pan_api { struct PAN_Connect { std::function - body{[](const RawAddress& rem_bda, tPAN_ROLE src_role, tPAN_ROLE dst_role, - uint16_t* handle) { return PAN_SUCCESS; }}; + body{[](const RawAddress& /* rem_bda */, tPAN_ROLE /* src_role */, + tPAN_ROLE /* dst_role */, + uint16_t* /* handle */) { return PAN_SUCCESS; }}; tPAN_RESULT operator()(const RawAddress& rem_bda, tPAN_ROLE src_role, tPAN_ROLE dst_role, uint16_t* handle) { return body(rem_bda, src_role, dst_role, handle); @@ -71,7 +55,7 @@ extern struct PAN_Connect PAN_Connect; // Returns: tPAN_RESULT struct PAN_Disconnect { std::function body{ - [](uint16_t handle) { return PAN_SUCCESS; }}; + [](uint16_t /* handle */) { return PAN_SUCCESS; }}; tPAN_RESULT operator()(uint16_t handle) { return body(handle); }; }; extern struct PAN_Disconnect PAN_Disconnect; @@ -81,9 +65,9 @@ extern struct PAN_Disconnect PAN_Disconnect; struct PAN_SetMulticastFilters { std::function - body{[](uint16_t handle, uint16_t num_mcast_filters, - uint8_t* p_start_array, - uint8_t* p_end_array) { return PAN_SUCCESS; }}; + body{[](uint16_t /* handle */, uint16_t /* num_mcast_filters */, + uint8_t* /* p_start_array */, + uint8_t* /* p_end_array */) { return PAN_SUCCESS; }}; tPAN_RESULT operator()(uint16_t handle, uint16_t num_mcast_filters, uint8_t* p_start_array, uint8_t* p_end_array) { return body(handle, num_mcast_filters, p_start_array, p_end_array); @@ -96,8 +80,9 @@ extern struct PAN_SetMulticastFilters PAN_SetMulticastFilters; struct PAN_SetProtocolFilters { std::function - body{[](uint16_t handle, uint16_t num_filters, uint16_t* p_start_array, - uint16_t* p_end_array) { return PAN_SUCCESS; }}; + body{[](uint16_t /* handle */, uint16_t /* num_filters */, + uint16_t* /* p_start_array */, + uint16_t* /* p_end_array */) { return PAN_SUCCESS; }}; tPAN_RESULT operator()(uint16_t handle, uint16_t num_filters, uint16_t* p_start_array, uint16_t* p_end_array) { return body(handle, num_filters, p_start_array, p_end_array); @@ -110,9 +95,8 @@ extern struct PAN_SetProtocolFilters PAN_SetProtocolFilters; struct PAN_SetRole { std::function - body{[](uint8_t role, std::string p_user_name, std::string p_nap_name) { - return PAN_SUCCESS; - }}; + body{[](uint8_t /* role */, std::string /* p_user_name */, + std::string /* p_nap_name */) { return PAN_SUCCESS; }}; tPAN_RESULT operator()(uint8_t role, std::string p_user_name, std::string p_nap_name) { return body(role, p_user_name, p_nap_name); @@ -127,9 +111,10 @@ struct PAN_Write { std::function - body{[](uint16_t handle, const RawAddress& dst, const RawAddress& src, - uint16_t protocol, uint8_t* p_data, uint16_t len, - bool ext) { return PAN_SUCCESS; }}; + body{[](uint16_t /* handle */, const RawAddress& /* dst */, + const RawAddress& /* src */, uint16_t /* protocol */, + uint8_t* /* p_data */, uint16_t /* len */, + bool /* ext */) { return PAN_SUCCESS; }}; tPAN_RESULT operator()(uint16_t handle, const RawAddress& dst, const RawAddress& src, uint16_t protocol, uint8_t* p_data, uint16_t len, bool ext) { @@ -144,9 +129,9 @@ struct PAN_WriteBuf { std::function - body{[](uint16_t handle, const RawAddress& dst, const RawAddress& src, - uint16_t protocol, BT_HDR* p_buf, - bool ext) { return PAN_SUCCESS; }}; + body{[](uint16_t /* handle */, const RawAddress& /* dst */, + const RawAddress& /* src */, uint16_t /* protocol */, + BT_HDR* /* p_buf */, bool /* ext */) { return PAN_SUCCESS; }}; tPAN_RESULT operator()(uint16_t handle, const RawAddress& dst, const RawAddress& src, uint16_t protocol, BT_HDR* p_buf, bool ext) { @@ -154,15 +139,6 @@ struct PAN_WriteBuf { }; }; extern struct PAN_WriteBuf PAN_WriteBuf; -// Name: PAN_SetTraceLevel -// Params: uint8_t new_level -// Returns: uint8_t -struct PAN_SetTraceLevel { - std::function body{ - [](uint8_t new_level) { return 0; }}; - uint8_t operator()(uint8_t new_level) { return body(new_level); }; -}; -extern struct PAN_SetTraceLevel PAN_SetTraceLevel; // Name: PAN_Deregister // Params: void // Returns: void @@ -175,7 +151,7 @@ extern struct PAN_Deregister PAN_Deregister; // Params: int fd // Returns: void struct PAN_Dumpsys { - std::function body{[](int fd) { ; }}; + std::function body{[](int /* fd */) { ; }}; void operator()(int fd) { body(fd); }; }; extern struct PAN_Dumpsys PAN_Dumpsys; @@ -192,7 +168,7 @@ extern struct PAN_Init PAN_Init; // Returns: void struct PAN_Register { std::function body{ - [](tPAN_REGISTER* p_register) { ; }}; + [](tPAN_REGISTER* /* p_register */) { ; }}; void operator()(tPAN_REGISTER* p_register) { body(p_register); }; }; extern struct PAN_Register PAN_Register; diff --git a/system/test/mock/mock_stack_rfcomm_port_api.cc b/system/test/mock/mock_stack_rfcomm_port_api.cc index 067fbc016a5b9a50aa23b9c99aab03fae1df0206..d8d025cebf1e0befcff77048ef8a8592b6b8c409 100644 --- a/system/test/mock/mock_stack_rfcomm_port_api.cc +++ b/system/test/mock/mock_stack_rfcomm_port_api.cc @@ -20,112 +20,96 @@ */ #include -#include -#include -#include - -#include "l2c_api.h" -#include "osi/include/log.h" -#include "osi/include/mutex.h" #include "port_api.h" -#include "rfcdefs.h" -#include "sdp_api.h" -#include "stack/include/btm_api_types.h" -#include "stack/rfcomm/port_int.h" -#include "stack/rfcomm/rfc_int.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool PORT_IsOpening(RawAddress* bd_addr) { +bool PORT_IsOpening(RawAddress* /* bd_addr */) { inc_func_call_count(__func__); return false; } -const char* PORT_GetResultString(const uint8_t result_code) { +const char* PORT_GetResultString(const uint8_t /* result_code */) { inc_func_call_count(__func__); return nullptr; } -int PORT_CheckConnection(uint16_t handle, RawAddress* bd_addr, - uint16_t* p_lcid) { - inc_func_call_count(__func__); - return 0; -} -int PORT_ClearKeepHandleFlag(uint16_t port_handle) { +int PORT_CheckConnection(uint16_t /* handle */, RawAddress* /* bd_addr */, + uint16_t* /* p_lcid */) { inc_func_call_count(__func__); return 0; } -int PORT_FlowControl_MaxCredit(uint16_t handle, bool enable) { +int PORT_ClearKeepHandleFlag(uint16_t /* port_handle */) { inc_func_call_count(__func__); return 0; } -int PORT_GetState(uint16_t handle, tPORT_STATE* p_settings) { +int PORT_FlowControl_MaxCredit(uint16_t /* handle */, bool /* enable */) { inc_func_call_count(__func__); return 0; } -int PORT_ReadData(uint16_t handle, char* p_data, uint16_t max_len, - uint16_t* p_len) { +int PORT_GetState(uint16_t /* handle */, tPORT_STATE* /* p_settings */) { inc_func_call_count(__func__); return 0; } -int PORT_SetDataCOCallback(uint16_t port_handle, - tPORT_DATA_CO_CALLBACK* p_port_cb) { +int PORT_ReadData(uint16_t /* handle */, char* /* p_data */, + uint16_t /* max_len */, uint16_t* /* p_len */) { inc_func_call_count(__func__); return 0; } -int PORT_SetEventCallback(uint16_t port_handle, tPORT_CALLBACK* p_port_cb) { +int PORT_SetDataCOCallback(uint16_t /* port_handle */, + tPORT_DATA_CO_CALLBACK* /* p_port_cb */) { inc_func_call_count(__func__); return 0; } -int PORT_SetEventMask(uint16_t port_handle, uint32_t mask) { +int PORT_SetEventCallback(uint16_t /* port_handle */, + tPORT_CALLBACK* /* p_port_cb */) { inc_func_call_count(__func__); return 0; } -int PORT_SetState(uint16_t handle, tPORT_STATE* p_settings) { +int PORT_SetEventMask(uint16_t /* port_handle */, uint32_t /* mask */) { inc_func_call_count(__func__); return 0; } -int PORT_WriteData(uint16_t handle, const char* p_data, uint16_t max_len, - uint16_t* p_len) { +int PORT_SetState(uint16_t /* handle */, tPORT_STATE* /* p_settings */) { inc_func_call_count(__func__); return 0; } -int PORT_WriteDataCO(uint16_t handle, int* p_len) { +int PORT_WriteData(uint16_t /* handle */, const char* /* p_data */, + uint16_t /* max_len */, uint16_t* /* p_len */) { inc_func_call_count(__func__); return 0; } -int RFCOMM_CreateConnectionWithSecurity(uint16_t uuid, uint8_t scn, - bool is_server, uint16_t mtu, - const RawAddress& bd_addr, - uint16_t* p_handle, - tPORT_CALLBACK* p_mgmt_cb, - uint16_t sec_mask) { +int PORT_WriteDataCO(uint16_t /* handle */, int* /* p_len */) { inc_func_call_count(__func__); return 0; } -int RFCOMM_ControlReqFromBTSOCK(uint8_t dlci, const RawAddress& bd_addr, - uint8_t modem_signal, uint8_t break_signal, - uint8_t discard_buffers, - uint8_t break_signal_seq, bool fc) { +int RFCOMM_CreateConnectionWithSecurity(uint16_t /* uuid */, uint8_t /* scn */, + bool /* is_server */, + uint16_t /* mtu */, + const RawAddress& /* bd_addr */, + uint16_t* /* p_handle */, + tPORT_CALLBACK* /* p_mgmt_cb */, + uint16_t /* sec_mask */) { inc_func_call_count(__func__); return 0; } -int RFCOMM_RemoveConnection(uint16_t handle) { +int RFCOMM_ControlReqFromBTSOCK(uint8_t /* dlci */, + const RawAddress& /* bd_addr */, + uint8_t /* modem_signal */, + uint8_t /* break_signal */, + uint8_t /* discard_buffers */, + uint8_t /* break_signal_seq */, bool /* fc */) { inc_func_call_count(__func__); return 0; } -int RFCOMM_RemoveServer(uint16_t handle) { +int RFCOMM_RemoveConnection(uint16_t /* handle */) { inc_func_call_count(__func__); return 0; } -uint8_t PORT_SetTraceLevel(uint8_t new_level) { +int RFCOMM_RemoveServer(uint16_t /* handle */) { inc_func_call_count(__func__); return 0; } -int PORT_GetSecurityMask(uint16_t handle, uint16_t* sec_mask) { +int PORT_GetSecurityMask(uint16_t /* handle */, uint16_t* /* sec_mask */) { inc_func_call_count(__func__); return 0; } diff --git a/system/test/mock/mock_stack_sdp_api.cc b/system/test/mock/mock_stack_sdp_api.cc index 7a81a5a3f81712f1bf02bcd0db84c089705c488f..28b56bf6f14859ec737ba71eca2a8936179e85f4 100644 --- a/system/test/mock/mock_stack_sdp_api.cc +++ b/system/test/mock/mock_stack_sdp_api.cc @@ -20,22 +20,16 @@ * * mockcify.pl ver 0.2.1 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_sdp_api.h" #include -#include -#include -#include -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_sdp_api.h" +#include "test/common/mock_functions.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -60,7 +54,6 @@ struct SDP_DiDiscover SDP_DiDiscover; struct SDP_GetDiRecord SDP_GetDiRecord; struct SDP_SetLocalDiRecord SDP_SetLocalDiRecord; struct SDP_GetNumDiRecords SDP_GetNumDiRecords; -struct SDP_SetTraceLevel SDP_SetTraceLevel; } // namespace stack_sdp_api } // namespace mock @@ -173,9 +166,4 @@ uint8_t SDP_GetNumDiRecords(const tSDP_DISCOVERY_DB* p_db) { inc_func_call_count(__func__); return test::mock::stack_sdp_api::SDP_GetNumDiRecords(p_db); } -uint8_t SDP_SetTraceLevel(uint8_t new_level) { - inc_func_call_count(__func__); - return test::mock::stack_sdp_api::SDP_SetTraceLevel(new_level); -} - // END mockcify generation diff --git a/system/test/mock/mock_stack_sdp_api.h b/system/test/mock/mock_stack_sdp_api.h index 9499fbb2a5e24fe1597430365d4271f252b7b6d9..758f48d98708149a6dc2f2ac3f63a90603af538c 100644 --- a/system/test/mock/mock_stack_sdp_api.h +++ b/system/test/mock/mock_stack_sdp_api.h @@ -23,30 +23,14 @@ #include #include -#include -#include -// Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include - -#include "bt_target.h" -#include "osi/include/osi.h" -#include "stack/include/sdp_api.h" -#include "stack/sdp/sdpint.h" -#include "test/common/mock_functions.h" +#include "stack/include/sdp_callback.h" +#include "stack/include/sdp_device_id.h" +#include "stack/sdp/sdp_discovery_db.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_sdp_api { @@ -57,7 +41,7 @@ namespace stack_sdp_api { // Returns: bool struct SDP_CancelServiceSearch { std::function body{ - [](const tSDP_DISCOVERY_DB* p_db) { return false; }}; + [](const tSDP_DISCOVERY_DB* /* p_db */) { return false; }}; bool operator()(const tSDP_DISCOVERY_DB* p_db) { return body(p_db); }; }; extern struct SDP_CancelServiceSearch SDP_CancelServiceSearch; @@ -67,8 +51,8 @@ extern struct SDP_CancelServiceSearch SDP_CancelServiceSearch; struct SDP_FindProfileVersionInRec { std::function - body{[](const tSDP_DISC_REC* p_rec, uint16_t profile_uuid, - uint16_t* p_version) { return false; }}; + body{[](const tSDP_DISC_REC* /* p_rec */, uint16_t /* profile_uuid */, + uint16_t* /* p_version */) { return false; }}; bool operator()(const tSDP_DISC_REC* p_rec, uint16_t profile_uuid, uint16_t* p_version) { return body(p_rec, profile_uuid, p_version); @@ -81,8 +65,8 @@ extern struct SDP_FindProfileVersionInRec SDP_FindProfileVersionInRec; struct SDP_FindProtocolListElemInRec { std::function - body{[](const tSDP_DISC_REC* p_rec, uint16_t layer_uuid, - tSDP_PROTOCOL_ELEM* p_elem) { return false; }}; + body{[](const tSDP_DISC_REC* /* p_rec */, uint16_t /* layer_uuid */, + tSDP_PROTOCOL_ELEM* /* p_elem */) { return false; }}; bool operator()(const tSDP_DISC_REC* p_rec, uint16_t layer_uuid, tSDP_PROTOCOL_ELEM* p_elem) { return body(p_rec, layer_uuid, p_elem); @@ -94,7 +78,7 @@ extern struct SDP_FindProtocolListElemInRec SDP_FindProtocolListElemInRec; // Returns: bool struct SDP_FindServiceUUIDInRec { std::function body{ - [](const tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) { + [](const tSDP_DISC_REC* /* p_rec */, bluetooth::Uuid* /* p_uuid */) { return false; }}; bool operator()(const tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) { @@ -107,7 +91,7 @@ extern struct SDP_FindServiceUUIDInRec SDP_FindServiceUUIDInRec; // Returns: bool struct SDP_FindServiceUUIDInRec_128bit { std::function body{ - [](const tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) { + [](const tSDP_DISC_REC* /* p_rec */, bluetooth::Uuid* /* p_uuid */) { return false; }}; bool operator()(const tSDP_DISC_REC* p_rec, bluetooth::Uuid* p_uuid) { @@ -123,9 +107,10 @@ struct SDP_InitDiscoveryDb { std::function - body{[](tSDP_DISCOVERY_DB* p_db, uint32_t len, uint16_t num_uuid, - const bluetooth::Uuid* p_uuid_list, uint16_t num_attr, - const uint16_t* p_attr_list) { return false; }}; + body{[](tSDP_DISCOVERY_DB* /* p_db */, uint32_t /* len */, + uint16_t /* num_uuid */, const bluetooth::Uuid* /* p_uuid_list */, + uint16_t /* num_attr */, + const uint16_t* /* p_attr_list */) { return false; }}; bool operator()(tSDP_DISCOVERY_DB* p_db, uint32_t len, uint16_t num_uuid, const bluetooth::Uuid* p_uuid_list, uint16_t num_attr, const uint16_t* p_attr_list) { @@ -139,8 +124,8 @@ extern struct SDP_InitDiscoveryDb SDP_InitDiscoveryDb; struct SDP_ServiceSearchAttributeRequest { std::function - body{[](const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db, - tSDP_DISC_CMPL_CB* p_cb) { return false; }}; + body{[](const RawAddress& /* p_bd_addr */, tSDP_DISCOVERY_DB* /* p_db */, + tSDP_DISC_CMPL_CB* /* p_cb */) { return false; }}; bool operator()(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db, tSDP_DISC_CMPL_CB* p_cb) { return body(p_bd_addr, p_db, p_cb); @@ -154,9 +139,9 @@ extern struct SDP_ServiceSearchAttributeRequest struct SDP_ServiceSearchAttributeRequest2 { std::function - body{[](const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db, - tSDP_DISC_CMPL_CB2* p_cb2, - const void* user_data) { return false; }}; + body{[](const RawAddress& /* p_bd_addr */, tSDP_DISCOVERY_DB* /* p_db */, + tSDP_DISC_CMPL_CB2* /* p_cb2 */, + const void* /* user_data */) { return false; }}; bool operator()(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db, tSDP_DISC_CMPL_CB2* p_cb2, const void* user_data) { return body(p_bd_addr, p_db, p_cb2, user_data); @@ -170,8 +155,8 @@ extern struct SDP_ServiceSearchAttributeRequest2 struct SDP_ServiceSearchRequest { std::function - body{[](const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db, - tSDP_DISC_CMPL_CB* p_cb) { return false; }}; + body{[](const RawAddress& /* p_bd_addr */, tSDP_DISCOVERY_DB* /* p_db */, + tSDP_DISC_CMPL_CB* /* p_cb */) { return false; }}; bool operator()(const RawAddress& p_bd_addr, tSDP_DISCOVERY_DB* p_db, tSDP_DISC_CMPL_CB* p_cb) { return body(p_bd_addr, p_db, p_cb); @@ -183,8 +168,9 @@ extern struct SDP_ServiceSearchRequest SDP_ServiceSearchRequest; // Returns: tSDP_DISC_ATTR* struct SDP_FindAttributeInRec { std::function - body{ - [](const tSDP_DISC_REC* p_rec, uint16_t attr_id) { return nullptr; }}; + body{[](const tSDP_DISC_REC* /* p_rec */, uint16_t /* attr_id */) { + return nullptr; + }}; tSDP_DISC_ATTR* operator()(const tSDP_DISC_REC* p_rec, uint16_t attr_id) { return body(p_rec, attr_id); }; @@ -197,8 +183,8 @@ struct SDP_FindServiceInDb { std::function - body{[](const tSDP_DISCOVERY_DB* p_db, uint16_t service_uuid, - tSDP_DISC_REC* p_start_rec) { return nullptr; }}; + body{[](const tSDP_DISCOVERY_DB* /* p_db */, uint16_t /* service_uuid */, + tSDP_DISC_REC* /* p_start_rec */) { return nullptr; }}; tSDP_DISC_REC* operator()(const tSDP_DISCOVERY_DB* p_db, uint16_t service_uuid, tSDP_DISC_REC* p_start_rec) { return body(p_db, service_uuid, p_start_rec); @@ -211,9 +197,8 @@ extern struct SDP_FindServiceInDb SDP_FindServiceInDb; struct SDP_FindServiceInDb_128bit { std::function - body{[](const tSDP_DISCOVERY_DB* p_db, tSDP_DISC_REC* p_start_rec) { - return nullptr; - }}; + body{[](const tSDP_DISCOVERY_DB* /* p_db */, + tSDP_DISC_REC* /* p_start_rec */) { return nullptr; }}; tSDP_DISC_REC* operator()(const tSDP_DISCOVERY_DB* p_db, tSDP_DISC_REC* p_start_rec) { return body(p_db, p_start_rec); @@ -227,8 +212,9 @@ struct SDP_FindServiceUUIDInDb { std::function - body{[](const tSDP_DISCOVERY_DB* p_db, const bluetooth::Uuid& uuid, - tSDP_DISC_REC* p_start_rec) { return nullptr; }}; + body{[](const tSDP_DISCOVERY_DB* /* p_db */, + const bluetooth::Uuid& /* uuid */, + tSDP_DISC_REC* /* p_start_rec */) { return nullptr; }}; tSDP_DISC_REC* operator()(const tSDP_DISCOVERY_DB* p_db, const bluetooth::Uuid& uuid, tSDP_DISC_REC* p_start_rec) { @@ -243,8 +229,9 @@ struct SDP_DiDiscover { std::function - body{[](const RawAddress& remote_device, tSDP_DISCOVERY_DB* p_db, - uint32_t len, tSDP_DISC_CMPL_CB* p_cb) { return SDP_SUCCESS; }}; + body{[](const RawAddress& /* remote_device */, + tSDP_DISCOVERY_DB* /* p_db */, uint32_t /* len */, + tSDP_DISC_CMPL_CB* /* p_cb */) { return SDP_SUCCESS; }}; tSDP_STATUS operator()(const RawAddress& remote_device, tSDP_DISCOVERY_DB* p_db, uint32_t len, tSDP_DISC_CMPL_CB* p_cb) { @@ -259,8 +246,9 @@ struct SDP_GetDiRecord { std::function - body{[](uint8_t get_record_index, tSDP_DI_GET_RECORD* p_device_info, - const tSDP_DISCOVERY_DB* p_db) { return 0; }}; + body{[](uint8_t /* get_record_index */, + tSDP_DI_GET_RECORD* /* p_device_info */, + const tSDP_DISCOVERY_DB* /* p_db */) { return 0; }}; uint16_t operator()(uint8_t get_record_index, tSDP_DI_GET_RECORD* p_device_info, const tSDP_DISCOVERY_DB* p_db) { @@ -274,9 +262,8 @@ extern struct SDP_GetDiRecord SDP_GetDiRecord; struct SDP_SetLocalDiRecord { std::function - body{[](const tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { - return 0; - }}; + body{[](const tSDP_DI_RECORD* /* p_device_info */, + uint32_t* /* p_handle */) { return 0; }}; uint16_t operator()(const tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { return body(p_device_info, p_handle); }; @@ -287,19 +274,10 @@ extern struct SDP_SetLocalDiRecord SDP_SetLocalDiRecord; // Returns: uint8_t struct SDP_GetNumDiRecords { std::function body{ - [](const tSDP_DISCOVERY_DB* p_db) { return 0; }}; + [](const tSDP_DISCOVERY_DB* /* p_db */) { return 0; }}; uint8_t operator()(const tSDP_DISCOVERY_DB* p_db) { return body(p_db); }; }; extern struct SDP_GetNumDiRecords SDP_GetNumDiRecords; -// Name: SDP_SetTraceLevel -// Params: uint8_t new_level -// Returns: uint8_t -struct SDP_SetTraceLevel { - std::function body{ - [](uint8_t new_level) { return 0; }}; - uint8_t operator()(uint8_t new_level) { return body(new_level); }; -}; -extern struct SDP_SetTraceLevel SDP_SetTraceLevel; } // namespace stack_sdp_api } // namespace mock diff --git a/system/test/mock/mock_stack_sdp_db.cc b/system/test/mock/mock_stack_sdp_db.cc index 5d8be3aae3d163fcc1f83430a84cad193a271671..f009c982f5a63423a3f8428fdf726b06c44fac5b 100644 --- a/system/test/mock/mock_stack_sdp_db.cc +++ b/system/test/mock/mock_stack_sdp_db.cc @@ -20,80 +20,71 @@ */ #include -#include -#include -#include - -#include "bt_target.h" -#include "stack/include/sdp_api.h" #include "stack/sdp/sdpint.h" #include "test/common/mock_functions.h" -#include "types/bluetooth/uuid.h" - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif -bool SDP_AddAdditionProtoLists(uint32_t handle, uint16_t num_elem, - tSDP_PROTO_LIST_ELEM* p_proto_list) { - inc_func_call_count(__func__); - return false; -} -bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, - uint32_t attr_len, uint8_t* p_val) { +bool SDP_AddAdditionProtoLists(uint32_t /* handle */, uint16_t /* num_elem */, + tSDP_PROTO_LIST_ELEM* /* p_proto_list */) { inc_func_call_count(__func__); return false; } -bool SDP_AddLanguageBaseAttrIDList(uint32_t handle, uint16_t lang, - uint16_t char_enc, uint16_t base_id) { +bool SDP_AddAttribute(uint32_t /* handle */, uint16_t /* attr_id */, + uint8_t /* attr_type */, uint32_t /* attr_len */, + uint8_t* /* p_val */) { inc_func_call_count(__func__); return false; } -bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid, - uint16_t version) { +bool SDP_AddLanguageBaseAttrIDList(uint32_t /* handle */, uint16_t /* lang */, + uint16_t /* char_enc */, + uint16_t /* base_id */) { inc_func_call_count(__func__); return false; } -bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem, - tSDP_PROTOCOL_ELEM* p_elem_list) { +bool SDP_AddProfileDescriptorList(uint32_t /* handle */, + uint16_t /* profile_uuid */, + uint16_t /* version */) { inc_func_call_count(__func__); return false; } -bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem, - uint8_t type[], uint8_t len[], uint8_t* p_val[]) { +bool SDP_AddProtocolList(uint32_t /* handle */, uint16_t /* num_elem */, + tSDP_PROTOCOL_ELEM* /* p_elem_list */) { inc_func_call_count(__func__); return false; } -bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services, - uint16_t* p_service_uuids) { +bool SDP_AddSequence(uint32_t /* handle */, uint16_t /* attr_id */, + uint16_t /* num_elem */, uint8_t /* type */[], + uint8_t /* len */[], uint8_t* /* p_val */[]) { inc_func_call_count(__func__); return false; } -bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids, - uint16_t* p_uuids) { +bool SDP_AddServiceClassIdList(uint32_t /* handle */, + uint16_t /* num_services */, + uint16_t* /* p_service_uuids */) { inc_func_call_count(__func__); return false; } -bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id) { +bool SDP_AddUuidSequence(uint32_t /* handle */, uint16_t /* attr_id */, + uint16_t /* num_uuids */, uint16_t* /* p_uuids */) { inc_func_call_count(__func__); return false; } -bool SDP_DeleteRecord(uint32_t handle) { +bool SDP_DeleteRecord(uint32_t /* handle */) { inc_func_call_count(__func__); return false; } -tSDP_ATTRIBUTE* sdp_db_find_attr_in_rec(tSDP_RECORD* p_rec, uint16_t start_attr, - uint16_t end_attr) { +tSDP_ATTRIBUTE* sdp_db_find_attr_in_rec(tSDP_RECORD* /* p_rec */, + uint16_t /* start_attr */, + uint16_t /* end_attr */) { inc_func_call_count(__func__); return nullptr; } -tSDP_RECORD* sdp_db_find_record(uint32_t handle) { +tSDP_RECORD* sdp_db_find_record(uint32_t /* handle */) { inc_func_call_count(__func__); return nullptr; } -const tSDP_RECORD* sdp_db_service_search(const tSDP_RECORD* p_rec, - tSDP_UUID_SEQ* p_seq) { +const tSDP_RECORD* sdp_db_service_search(const tSDP_RECORD* /* p_rec */, + tSDP_UUID_SEQ* /* p_seq */) { inc_func_call_count(__func__); return nullptr; } diff --git a/system/test/mock/mock_stack_sdp_legacy_api.cc b/system/test/mock/mock_stack_sdp_legacy_api.cc index f339a266bb64866448c6636c6afbea7c7954cd7b..e0ce88f5918e535586965934070e329d727de656 100644 --- a/system/test/mock/mock_stack_sdp_legacy_api.cc +++ b/system/test/mock/mock_stack_sdp_legacy_api.cc @@ -1,4 +1,18 @@ - +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include @@ -48,7 +62,6 @@ bluetooth::legacy::stack::sdp::tSdpApi api_ = { .SDP_AddProfileDescriptorList = nullptr, .SDP_AddLanguageBaseAttrIDList = nullptr, .SDP_AddServiceClassIdList = nullptr, - .SDP_DeleteAttribute = nullptr, }, .device_id = { diff --git a/system/test/mock/mock_stack_sdp_legacy_api.h b/system/test/mock/mock_stack_sdp_legacy_api.h new file mode 100644 index 0000000000000000000000000000000000000000..93d9077e33c920e9eba5911c21cdcc09a657631d --- /dev/null +++ b/system/test/mock/mock_stack_sdp_legacy_api.h @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "stack/include/sdp_api.h" + +namespace test { +namespace mock { +namespace stack_sdp_legacy { + +extern bluetooth::legacy::stack::sdp::tSdpApi api_; + +} // namespace stack_sdp_legacy +} // namespace mock +} // namespace test diff --git a/system/test/mock/mock_stack_sdp_main.cc b/system/test/mock/mock_stack_sdp_main.cc index c99ad36ecbb67db6b1b0ed5fdc0d84f13090f4b2..53976691d0bf9ac920508a5cc52fa875f7fcbfc8 100644 --- a/system/test/mock/mock_stack_sdp_main.cc +++ b/system/test/mock/mock_stack_sdp_main.cc @@ -19,31 +19,16 @@ * Functions generated:5 */ -#include - -#include -#include - -#include "bt_target.h" -#include "l2c_api.h" -#include "l2cdefs.h" -#include "osi/include/osi.h" -#include "sdp_api.h" -#include "stack/btm/btm_sec.h" #include "stack/sdp/sdpint.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -tCONN_CB* sdp_conn_originate(const RawAddress& p_bd_addr) { +tCONN_CB* sdp_conn_originate(const RawAddress& /* p_bd_addr */) { inc_func_call_count(__func__); return nullptr; } -void sdp_conn_timer_timeout(void* data) { inc_func_call_count(__func__); } -void sdp_disconnect(tCONN_CB* p_ccb, uint16_t reason) { +void sdp_conn_timer_timeout(void* /* data */) { inc_func_call_count(__func__); } +void sdp_disconnect(tCONN_CB* /* p_ccb */, uint16_t /* reason */) { inc_func_call_count(__func__); } void sdp_free(void) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_sdp_server.cc b/system/test/mock/mock_stack_sdp_server.cc index 0e603bf24a31a198e0def27ba148b4a707033457..240b921078b31a70d57b8a14a43956357f4737cd 100644 --- a/system/test/mock/mock_stack_sdp_server.cc +++ b/system/test/mock/mock_stack_sdp_server.cc @@ -17,22 +17,17 @@ #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -void update_pce_entry_to_interop_database(RawAddress remote_addr) { +void update_pce_entry_to_interop_database(RawAddress /* remote_addr */) { inc_func_call_count(__func__); } -bool is_sdp_pbap_pce_disabled(RawAddress remote_address) { +bool is_sdp_pbap_pce_disabled(RawAddress /* remote_address */) { inc_func_call_count(__func__); return false; } -void sdp_save_local_pse_record_attributes(int32_t rfcomm_channel_number, - int32_t l2cap_psm, - int32_t profile_version, - uint32_t supported_features, - uint32_t supported_repositories) { +void sdp_save_local_pse_record_attributes( + int32_t /* rfcomm_channel_number */, int32_t /* l2cap_psm */, + int32_t /* profile_version */, uint32_t /* supported_features */, + uint32_t /* supported_repositories */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_smp_act.cc b/system/test/mock/mock_stack_smp_act.cc index 06badb8f5349daecb86358fb75d6e4bf83611165..44496922d56431026b525b1e56780159bd5a3c2d 100644 --- a/system/test/mock/mock_stack_smp_act.cc +++ b/system/test/mock/mock_stack_smp_act.cc @@ -20,28 +20,16 @@ * * mockcify.pl ver 0.2 */ +// Mock include file to share data between tests and mock +#include "test/mock/mock_stack_smp_act.h" #include -#include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. - -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_smp_act.h" +#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - // Mocked internal structures, if any namespace test { @@ -54,7 +42,6 @@ struct smp_send_pair_fail smp_send_pair_fail; struct smp_send_pair_req smp_send_pair_req; struct smp_send_pair_rsp smp_send_pair_rsp; struct smp_send_confirm smp_send_confirm; -struct smp_send_init smp_send_init; struct smp_send_rand smp_send_rand; struct smp_send_pair_public_key smp_send_pair_public_key; struct smp_send_commitment smp_send_commitment; @@ -69,7 +56,6 @@ struct smp_proc_sec_grant smp_proc_sec_grant; struct smp_proc_pair_fail smp_proc_pair_fail; struct smp_proc_pair_cmd smp_proc_pair_cmd; struct smp_proc_confirm smp_proc_confirm; -struct smp_proc_init smp_proc_init; struct smp_proc_rand smp_proc_rand; struct smp_process_pairing_public_key smp_process_pairing_public_key; struct smp_process_pairing_commitment smp_process_pairing_commitment; @@ -124,7 +110,6 @@ struct smp_set_derive_link_key smp_set_derive_link_key; struct smp_derive_link_key_from_long_term_key smp_derive_link_key_from_long_term_key; struct smp_br_process_link_key smp_br_process_link_key; -struct smp_key_distribution_by_transport smp_key_distribution_by_transport; struct smp_br_pairing_complete smp_br_pairing_complete; } // namespace stack_smp_act @@ -152,10 +137,6 @@ void smp_send_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { inc_func_call_count(__func__); test::mock::stack_smp_act::smp_send_confirm(p_cb, p_data); } -void smp_send_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - inc_func_call_count(__func__); - test::mock::stack_smp_act::smp_send_init(p_cb, p_data); -} void smp_send_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { inc_func_call_count(__func__); test::mock::stack_smp_act::smp_send_rand(p_cb, p_data); @@ -212,10 +193,6 @@ void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { inc_func_call_count(__func__); test::mock::stack_smp_act::smp_proc_confirm(p_cb, p_data); } -void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - inc_func_call_count(__func__); - test::mock::stack_smp_act::smp_proc_init(p_cb, p_data); -} void smp_proc_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { inc_func_call_count(__func__); test::mock::stack_smp_act::smp_proc_rand(p_cb, p_data); @@ -417,10 +394,6 @@ void smp_br_process_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { inc_func_call_count(__func__); test::mock::stack_smp_act::smp_br_process_link_key(p_cb, p_data); } -void smp_key_distribution_by_transport(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { - inc_func_call_count(__func__); - test::mock::stack_smp_act::smp_key_distribution_by_transport(p_cb, p_data); -} void smp_br_pairing_complete(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { inc_func_call_count(__func__); test::mock::stack_smp_act::smp_br_pairing_complete(p_cb, p_data); diff --git a/system/test/mock/mock_stack_smp_act.h b/system/test/mock/mock_stack_smp_act.h index 5754f3bed9d6ddc372c4d508599a96e503913562..24766de35b7495361aa86acd50e42c315eb98e6a 100644 --- a/system/test/mock/mock_stack_smp_act.h +++ b/system/test/mock/mock_stack_smp_act.h @@ -23,25 +23,12 @@ #include #include -#include -#include // Original included files, if any -// NOTE: Since this is a mock file with mock definitions some number of -// include files may not be required. The include-what-you-use -// still applies, but crafting proper inclusion is out of scope -// for this effort. This compilation unit may compile as-is, or -// may need attention to prune the inclusion set. -#include "btif/include/btif_api.h" #include "stack/smp/smp_int.h" -#include "test/common/mock_functions.h" #include "types/raw_address.h" // Mocked compile conditionals, if any -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - namespace test { namespace mock { namespace stack_smp_act { @@ -52,7 +39,7 @@ namespace stack_smp_act { // Returns: void struct smp_send_app_cback { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_app_cback smp_send_app_cback; @@ -61,7 +48,7 @@ extern struct smp_send_app_cback smp_send_app_cback; // Returns: void struct smp_send_pair_fail { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_pair_fail smp_send_pair_fail; @@ -70,7 +57,7 @@ extern struct smp_send_pair_fail smp_send_pair_fail; // Returns: void struct smp_send_pair_req { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_pair_req smp_send_pair_req; @@ -79,7 +66,7 @@ extern struct smp_send_pair_req smp_send_pair_req; // Returns: void struct smp_send_pair_rsp { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_pair_rsp smp_send_pair_rsp; @@ -88,25 +75,16 @@ extern struct smp_send_pair_rsp smp_send_pair_rsp; // Returns: void struct smp_send_confirm { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_confirm smp_send_confirm; -// Name: smp_send_init -// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data -// Returns: void -struct smp_send_init { - std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; - void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; -}; -extern struct smp_send_init smp_send_init; // Name: smp_send_rand // Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data // Returns: void struct smp_send_rand { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_rand smp_send_rand; @@ -115,7 +93,7 @@ extern struct smp_send_rand smp_send_rand; // Returns: void struct smp_send_pair_public_key { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_pair_public_key smp_send_pair_public_key; @@ -124,7 +102,7 @@ extern struct smp_send_pair_public_key smp_send_pair_public_key; // Returns: void struct smp_send_commitment { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_commitment smp_send_commitment; @@ -133,7 +111,7 @@ extern struct smp_send_commitment smp_send_commitment; // Returns: void struct smp_send_dhkey_check { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_dhkey_check smp_send_dhkey_check; @@ -142,7 +120,7 @@ extern struct smp_send_dhkey_check smp_send_dhkey_check; // Returns: void struct smp_send_keypress_notification { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_keypress_notification smp_send_keypress_notification; @@ -151,7 +129,7 @@ extern struct smp_send_keypress_notification smp_send_keypress_notification; // Returns: void struct smp_send_enc_info { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_enc_info smp_send_enc_info; @@ -160,7 +138,7 @@ extern struct smp_send_enc_info smp_send_enc_info; // Returns: void struct smp_send_id_info { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_id_info smp_send_id_info; @@ -169,7 +147,7 @@ extern struct smp_send_id_info smp_send_id_info; // Returns: void struct smp_send_csrk_info { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_csrk_info smp_send_csrk_info; @@ -178,7 +156,7 @@ extern struct smp_send_csrk_info smp_send_csrk_info; // Returns: void struct smp_send_ltk_reply { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_send_ltk_reply smp_send_ltk_reply; @@ -187,7 +165,7 @@ extern struct smp_send_ltk_reply smp_send_ltk_reply; // Returns: void struct smp_proc_sec_req { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_sec_req smp_proc_sec_req; @@ -196,7 +174,7 @@ extern struct smp_proc_sec_req smp_proc_sec_req; // Returns: void struct smp_proc_sec_grant { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_sec_grant smp_proc_sec_grant; @@ -205,7 +183,7 @@ extern struct smp_proc_sec_grant smp_proc_sec_grant; // Returns: void struct smp_proc_pair_fail { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_pair_fail smp_proc_pair_fail; @@ -214,7 +192,7 @@ extern struct smp_proc_pair_fail smp_proc_pair_fail; // Returns: void struct smp_proc_pair_cmd { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_pair_cmd smp_proc_pair_cmd; @@ -223,25 +201,17 @@ extern struct smp_proc_pair_cmd smp_proc_pair_cmd; // Returns: void struct smp_proc_confirm { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_confirm smp_proc_confirm; -// Name: smp_proc_init -// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data -// Returns: void -struct smp_proc_init { - std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; - void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; -}; -extern struct smp_proc_init smp_proc_init; + // Name: smp_proc_rand // Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data // Returns: void struct smp_proc_rand { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_rand smp_proc_rand; @@ -250,7 +220,7 @@ extern struct smp_proc_rand smp_proc_rand; // Returns: void struct smp_process_pairing_public_key { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_process_pairing_public_key smp_process_pairing_public_key; @@ -259,7 +229,7 @@ extern struct smp_process_pairing_public_key smp_process_pairing_public_key; // Returns: void struct smp_process_pairing_commitment { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_process_pairing_commitment smp_process_pairing_commitment; @@ -268,7 +238,7 @@ extern struct smp_process_pairing_commitment smp_process_pairing_commitment; // Returns: void struct smp_process_dhkey_check { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_process_dhkey_check smp_process_dhkey_check; @@ -277,7 +247,7 @@ extern struct smp_process_dhkey_check smp_process_dhkey_check; // Returns: void struct smp_process_keypress_notification { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_process_keypress_notification @@ -287,7 +257,7 @@ extern struct smp_process_keypress_notification // Returns: void struct smp_br_process_pairing_command { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_br_process_pairing_command smp_br_process_pairing_command; @@ -296,7 +266,7 @@ extern struct smp_br_process_pairing_command smp_br_process_pairing_command; // Returns: void struct smp_br_process_security_grant { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_br_process_security_grant smp_br_process_security_grant; @@ -305,7 +275,7 @@ extern struct smp_br_process_security_grant smp_br_process_security_grant; // Returns: void struct smp_br_check_authorization_request { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_br_check_authorization_request @@ -315,7 +285,7 @@ extern struct smp_br_check_authorization_request // Returns: void struct smp_br_select_next_key { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_br_select_next_key smp_br_select_next_key; @@ -324,7 +294,7 @@ extern struct smp_br_select_next_key smp_br_select_next_key; // Returns: void struct smp_proc_enc_info { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_enc_info smp_proc_enc_info; @@ -333,7 +303,7 @@ extern struct smp_proc_enc_info smp_proc_enc_info; // Returns: void struct smp_proc_central_id { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_central_id smp_proc_central_id; @@ -342,7 +312,7 @@ extern struct smp_proc_central_id smp_proc_central_id; // Returns: void struct smp_proc_id_info { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_id_info smp_proc_id_info; @@ -351,7 +321,7 @@ extern struct smp_proc_id_info smp_proc_id_info; // Returns: void struct smp_proc_id_addr { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_id_addr smp_proc_id_addr; @@ -360,7 +330,7 @@ extern struct smp_proc_id_addr smp_proc_id_addr; // Returns: void struct smp_proc_srk_info { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_srk_info smp_proc_srk_info; @@ -369,7 +339,7 @@ extern struct smp_proc_srk_info smp_proc_srk_info; // Returns: void struct smp_proc_compare { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_compare smp_proc_compare; @@ -378,7 +348,7 @@ extern struct smp_proc_compare smp_proc_compare; // Returns: void struct smp_proc_sl_key { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_sl_key smp_proc_sl_key; @@ -387,7 +357,7 @@ extern struct smp_proc_sl_key smp_proc_sl_key; // Returns: void struct smp_start_enc { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_start_enc smp_start_enc; @@ -396,7 +366,7 @@ extern struct smp_start_enc smp_start_enc; // Returns: void struct smp_proc_discard { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_proc_discard smp_proc_discard; @@ -405,7 +375,7 @@ extern struct smp_proc_discard smp_proc_discard; // Returns: void struct smp_enc_cmpl { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_enc_cmpl smp_enc_cmpl; @@ -414,7 +384,7 @@ extern struct smp_enc_cmpl smp_enc_cmpl; // Returns: void struct smp_check_auth_req { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_check_auth_req smp_check_auth_req; @@ -423,7 +393,7 @@ extern struct smp_check_auth_req smp_check_auth_req; // Returns: void struct smp_key_pick_key { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_key_pick_key smp_key_pick_key; @@ -432,7 +402,7 @@ extern struct smp_key_pick_key smp_key_pick_key; // Returns: void struct smp_key_distribution { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_key_distribution smp_key_distribution; @@ -441,7 +411,7 @@ extern struct smp_key_distribution smp_key_distribution; // Returns: void struct smp_decide_association_model { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_decide_association_model smp_decide_association_model; @@ -450,7 +420,7 @@ extern struct smp_decide_association_model smp_decide_association_model; // Returns: void struct smp_process_io_response { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_process_io_response smp_process_io_response; @@ -459,7 +429,7 @@ extern struct smp_process_io_response smp_process_io_response; // Returns: void struct smp_br_process_peripheral_keys_response { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_br_process_peripheral_keys_response @@ -469,7 +439,7 @@ extern struct smp_br_process_peripheral_keys_response // Returns: void struct smp_br_send_pair_response { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_br_send_pair_response smp_br_send_pair_response; @@ -478,7 +448,7 @@ extern struct smp_br_send_pair_response smp_br_send_pair_response; // Returns: void struct smp_pairing_cmpl { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_pairing_cmpl smp_pairing_cmpl; @@ -487,7 +457,7 @@ extern struct smp_pairing_cmpl smp_pairing_cmpl; // Returns: void struct smp_pair_terminate { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_pair_terminate smp_pair_terminate; @@ -496,7 +466,7 @@ extern struct smp_pair_terminate smp_pair_terminate; // Returns: void struct smp_idle_terminate { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_idle_terminate smp_idle_terminate; @@ -505,7 +475,7 @@ extern struct smp_idle_terminate smp_idle_terminate; // Returns: void struct smp_both_have_public_keys { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_both_have_public_keys smp_both_have_public_keys; @@ -514,7 +484,7 @@ extern struct smp_both_have_public_keys smp_both_have_public_keys; // Returns: void struct smp_start_secure_connection_phase1 { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_start_secure_connection_phase1 @@ -524,7 +494,7 @@ extern struct smp_start_secure_connection_phase1 // Returns: void struct smp_process_local_nonce { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_process_local_nonce smp_process_local_nonce; @@ -533,7 +503,7 @@ extern struct smp_process_local_nonce smp_process_local_nonce; // Returns: void struct smp_process_peer_nonce { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_process_peer_nonce smp_process_peer_nonce; @@ -542,7 +512,7 @@ extern struct smp_process_peer_nonce smp_process_peer_nonce; // Returns: void struct smp_match_dhkey_checks { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_match_dhkey_checks smp_match_dhkey_checks; @@ -551,7 +521,7 @@ extern struct smp_match_dhkey_checks smp_match_dhkey_checks; // Returns: void struct smp_move_to_secure_connections_phase2 { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_move_to_secure_connections_phase2 @@ -561,7 +531,7 @@ extern struct smp_move_to_secure_connections_phase2 // Returns: void struct smp_phase_2_dhkey_checks_are_present { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_phase_2_dhkey_checks_are_present @@ -571,7 +541,7 @@ extern struct smp_phase_2_dhkey_checks_are_present // Returns: void struct smp_wait_for_both_public_keys { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_wait_for_both_public_keys smp_wait_for_both_public_keys; @@ -580,7 +550,7 @@ extern struct smp_wait_for_both_public_keys smp_wait_for_both_public_keys; // Returns: void struct smp_start_passkey_verification { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_start_passkey_verification smp_start_passkey_verification; @@ -589,7 +559,7 @@ extern struct smp_start_passkey_verification smp_start_passkey_verification; // Returns: void struct smp_process_secure_connection_oob_data { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_process_secure_connection_oob_data @@ -599,7 +569,7 @@ extern struct smp_process_secure_connection_oob_data // Returns: void struct smp_set_local_oob_keys { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_set_local_oob_keys smp_set_local_oob_keys; @@ -608,7 +578,7 @@ extern struct smp_set_local_oob_keys smp_set_local_oob_keys; // Returns: void struct smp_set_local_oob_random_commitment { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_set_local_oob_random_commitment @@ -618,7 +588,7 @@ extern struct smp_set_local_oob_random_commitment // Returns: void struct smp_link_encrypted { std::function body{ - [](const RawAddress& bda, uint8_t encr_enable) {}}; + [](const RawAddress& /* bda */, uint8_t /* encr_enable */) {}}; void operator()(const RawAddress& bda, uint8_t encr_enable) { body(bda, encr_enable); }; @@ -638,7 +608,7 @@ extern struct smp_cancel_start_encryption_attempt // Returns: bool struct smp_proc_ltk_request { std::function body{ - [](const RawAddress& bda) { return false; }}; + [](const RawAddress& /* bda */) { return false; }}; bool operator()(const RawAddress& bda) { return body(bda); }; }; extern struct smp_proc_ltk_request smp_proc_ltk_request; @@ -656,7 +626,7 @@ extern struct smp_process_secure_connection_long_term_key // Returns: void struct smp_set_derive_link_key { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_set_derive_link_key smp_set_derive_link_key; @@ -665,7 +635,7 @@ extern struct smp_set_derive_link_key smp_set_derive_link_key; // Returns: void struct smp_derive_link_key_from_long_term_key { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_derive_link_key_from_long_term_key @@ -675,26 +645,16 @@ extern struct smp_derive_link_key_from_long_term_key // Returns: void struct smp_br_process_link_key { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_br_process_link_key smp_br_process_link_key; -// Name: smp_key_distribution_by_transport -// Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data -// Returns: void -struct smp_key_distribution_by_transport { - std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; - void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; -}; -extern struct smp_key_distribution_by_transport - smp_key_distribution_by_transport; // Name: smp_br_pairing_complete // Params: tSMP_CB* p_cb, tSMP_INT_DATA* p_data // Returns: void struct smp_br_pairing_complete { std::function body{ - [](tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {}}; + [](tSMP_CB* /* p_cb */, tSMP_INT_DATA* /* p_data */) {}}; void operator()(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { body(p_cb, p_data); }; }; extern struct smp_br_pairing_complete smp_br_pairing_complete; diff --git a/system/test/mock/mock_stack_smp_api.cc b/system/test/mock/mock_stack_smp_api.cc index 62b04f834aa64f3a5223a0e521442adf20eb6576..faeef318d8548c400c99c1b99aaf63843fb2159c 100644 --- a/system/test/mock/mock_stack_smp_api.cc +++ b/system/test/mock/mock_stack_smp_api.cc @@ -19,66 +19,50 @@ * Functions generated:11 */ -#include - -#include -#include - -#include "bt_target.h" -#include "main/shim/shim.h" #include "stack/btm/btm_dev.h" -#include "stack/include/l2c_api.h" -#include "stack/include/l2cdefs.h" #include "stack/include/smp_api.h" -#include "stack/smp/smp_int.h" -#include "stack_config.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool SMP_PairCancel(const RawAddress& bd_addr) { +bool SMP_PairCancel(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return false; } -bool SMP_Register(tSMP_CALLBACK* p_cback) { +bool SMP_Register(tSMP_CALLBACK* /* p_cback */) { inc_func_call_count(__func__); return false; } -tSMP_STATUS SMP_BR_PairWith(const RawAddress& bd_addr) { +tSMP_STATUS SMP_BR_PairWith(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return SMP_SUCCESS; } -tSMP_STATUS SMP_Pair(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) { +tSMP_STATUS SMP_Pair(const RawAddress& /* bd_addr */, + tBLE_ADDR_TYPE /* addr_type */) { inc_func_call_count(__func__); return SMP_SUCCESS; } -tSMP_STATUS SMP_Pair(const RawAddress& bd_addr) { +tSMP_STATUS SMP_Pair(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return SMP_SUCCESS; } -uint8_t SMP_SetTraceLevel(uint8_t new_level) { +void SMP_ConfirmReply(const RawAddress& /* bd_addr */, uint8_t /* res */) { inc_func_call_count(__func__); - return 0; } -void SMP_ConfirmReply(const RawAddress& bd_addr, uint8_t res) { +void SMP_Init(uint8_t /* init_security_mode */) { inc_func_call_count(__func__); } -void SMP_Init(void) { inc_func_call_count(__func__); } -void SMP_OobDataReply(const RawAddress& bd_addr, tSMP_STATUS res, uint8_t len, - uint8_t* p_data) { +void SMP_OobDataReply(const RawAddress& /* bd_addr */, tSMP_STATUS /* res */, + uint8_t /* len */, uint8_t* /* p_data */) { inc_func_call_count(__func__); } -void SMP_PasskeyReply(const RawAddress& bd_addr, uint8_t res, - uint32_t passkey) { +void SMP_PasskeyReply(const RawAddress& /* bd_addr */, uint8_t /* res */, + uint32_t /* passkey */) { inc_func_call_count(__func__); } -void SMP_SecureConnectionOobDataReply(uint8_t* p_data) { +void SMP_SecureConnectionOobDataReply(uint8_t* /* p_data */) { inc_func_call_count(__func__); } -void SMP_SecurityGrant(const RawAddress& bd_addr, tSMP_STATUS res) { +void SMP_SecurityGrant(const RawAddress& /* bd_addr */, tSMP_STATUS /* res */) { inc_func_call_count(__func__); } @@ -88,3 +72,8 @@ bool SMP_CrLocScOobData() { } void SMP_ClearLocScOobData() { inc_func_call_count(__func__); } + +void SMP_SirkConfirmDeviceReply(const RawAddress& /* bd_addr */, + uint8_t /* res */) { + 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 276d874b493fbd6ec0df75f5bfca744c6d094ff2..1b18c98cf8035f16bd6075887a66f9eee7ec0509 100644 --- a/system/test/mock/mock_stack_srvc_dis.cc +++ b/system/test/mock/mock_stack_srvc_dis.cc @@ -20,51 +20,48 @@ */ #include -#include -#include #include "stack/include/srvc_api.h" #include "stack/srvc/srvc_eng_int.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -bool DIS_ReadDISInfo(const RawAddress& peer_bda, tDIS_READ_CBACK* p_cback, - tDIS_ATTR_MASK mask) { +bool DIS_ReadDISInfo(const RawAddress& /* peer_bda */, + tDIS_READ_CBACK* /* p_cback */, + tDIS_ATTR_MASK /* mask */) { inc_func_call_count(__func__); return false; } -bool dis_gatt_c_read_dis_req(uint16_t conn_id) { +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) { +bool dis_valid_handle_range(uint16_t /* handle */) { inc_func_call_count(__func__); return false; } -tDIS_STATUS DIS_SrInit(tDIS_ATTR_MASK dis_attr_mask) { +tDIS_STATUS DIS_SrInit(tDIS_ATTR_MASK /* dis_attr_mask */) { inc_func_call_count(__func__); return 0; } -tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR* p_info) { +tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT /* dis_attr_bit */, + tDIS_ATTR* /* p_info */) { inc_func_call_count(__func__); return 0; } -uint8_t dis_read_attr_value(UNUSED_ATTR uint8_t clcb_idx, uint16_t handle, - tGATT_VALUE* p_value, bool is_long, - tGATT_STATUS* p_status) { +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(UNUSED_ATTR tGATT_WRITE_REQ* p_data, - tGATT_STATUS* p_status) { +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) { +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/mock/mock_system_libfmq_eventflag.cc b/system/test/mock/mock_system_libfmq_eventflag.cc deleted file mode 100644 index 611ef7009e27b958a19ef221abe0f1299c22aa2c..0000000000000000000000000000000000000000 --- a/system/test/mock/mock_system_libfmq_eventflag.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generated mock file from original source file - * Functions generated:11 - */ - -#include - -#include -#include - -#include "test/common/mock_functions.h" - -using namespace android; -using namespace android::hardware; - -namespace android { -namespace hardware { -namespace details { - -void logError(const std::string& message) {} -void check(bool exp, const char* message) {} - -} // namespace details -} // namespace hardware -} // namespace android - -#if 0 -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - -EventFlag::EventFlag(std::atomic* fwAddr, status_t* status) { - inc_func_call_count(__func__); -} -EventFlag::~EventFlag() { inc_func_call_count(__func__); } -status_t EventFlag::createEventFlag(std::atomic* fwAddr, - EventFlag** flag) { - inc_func_call_count(__func__); - return 0; -} -status_t EventFlag::deleteEventFlag(EventFlag** evFlag) { - inc_func_call_count(__func__); - return 0; -} -status_t EventFlag::unmapEventFlagWord(std::atomic* efWordPtr, - bool* efWordNeedsUnmapping) { - inc_func_call_count(__func__); - return 0; -} -status_t EventFlag::wait(uint32_t bitmask, uint32_t* efState, - int64_t timeoutNanoSeconds, bool retry) { - inc_func_call_count(__func__); - return 0; -} -status_t EventFlag::waitHelper(uint32_t bitmask, uint32_t* efState, - int64_t timeoutNanoSeconds) { - inc_func_call_count(__func__); - return 0; -} -status_t EventFlag::wake(uint32_t bitmask) { - inc_func_call_count(__func__); - return 0; -} -void EventFlag::addNanosecondsToCurrentTime(int64_t nanoSeconds, - struct timespec* waitTime) { - inc_func_call_count(__func__); -} diff --git a/system/test/mock/mock_udrv_ulinux_uipc.cc b/system/test/mock/mock_udrv_ulinux_uipc.cc index 84530e889fa7fb6fe1eccdbf40b27059ab03036a..3dcc091e9c8acf67bb6c1d7ef9cc17b97d371fed 100644 --- a/system/test/mock/mock_udrv_ulinux_uipc.cc +++ b/system/test/mock/mock_udrv_ulinux_uipc.cc @@ -20,16 +20,10 @@ */ #include -#include -#include #include "test/common/mock_functions.h" #include "udrv/include/uipc.h" -#ifndef UNUSED_ATTR -#define UNUSED_ATTR -#endif - std::unique_ptr mock_uipc_init_ret; uint32_t mock_uipc_read_ret; bool mock_uipc_send_ret; @@ -39,9 +33,8 @@ bool UIPC_Open(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback, inc_func_call_count(__func__); return false; } -bool UIPC_Send(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, - UNUSED_ATTR uint16_t msg_evt, const uint8_t* p_buf, - uint16_t msglen) { +bool UIPC_Send(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint16_t msg_evt, + const uint8_t* p_buf, uint16_t msglen) { inc_func_call_count(__func__); return mock_uipc_send_ret; } diff --git a/system/test/run_benchmarks.sh b/system/test/run_benchmarks.sh deleted file mode 100755 index 3ca1d0999b1eb4a5c9bc11416c1a4fdae4b3fb82..0000000000000000000000000000000000000000 --- a/system/test/run_benchmarks.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/sh -# A utility script that runs benchmark on Android device -# -# Note: Only one Android device can be connected when running this script -# -# Example usage: -# $ cd packages/modules/Bluetooth/system -# $ ./test/run_benchmarks.sh bluetooth_benchmark_example - -known_benchmarks=( - bluetooth_benchmark_thread_performance - bluetooth_benchmark_timer_performance -) - -usage() { - binary="$(basename "$0")" - echo "Usage: ${binary} --help" - echo " ${binary} [-i ] [-s ] [--all] [[.] ...] [-- ...]" - echo - echo "Unknown long arguments are passed to the benchmark." - echo - echo "Known benchmark names:" - - for name in "${known_benchmarks[@]}" - do - echo " ${name}" - done -} - -iterations=1 -device= -benchmarks=() -benchmark_args=() -while [ $# -gt 0 ] -do - case "$1" in - -h|--help) - usage - exit 0 - ;; - -i) - shift - if [ $# -eq 0 ]; then - echo "error: number of iterations expected" 1>&2 - usage - exit 2 - fi - iterations=$(( $1 )) - shift - ;; - -s) - shift - if [ $# -eq 0 ]; then - echo "error: no device specified" 1>&2 - usage - exit 2 - fi - device="$1" - shift - ;; - --all) - benchmarks+=( "${known_benchmarks[@]}" ) - shift - ;; - --*) - benchmark_args+=( "$1" ) - shift - ;; - *) - benchmarks+=( "$1" ) - shift - ;; - esac -done - -if [ "${#benchmarks[@]}" -eq 0 ]; then - benchmarks+=( "${known_benchmarks[@]}" ) -fi - -adb=( "adb" ) -if [ -n "${device}" ]; then - adb+=( "-s" "${device}" ) -fi - -source ${ANDROID_BUILD_TOP}/build/envsetup.sh -target_arch=$(gettargetarch) - -failed_benchmarks=() -for spec in "${benchmarks[@]}" -do - name="${spec%%.*}" - if [[ $target_arch == *"64"* ]]; then - binary="/data/benchmarktest64/${name}/${name}" - else - binary="/data/benchmarktest/${name}/${name}" - fi - - push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" ) - benchmark_command=( "${adb[@]}" shell "${binary}" ) - if [ "${name}" != "${spec}" ]; then - filter="${spec#*.}" - benchmark_command+=( "--benchmark_filter=${filter}" ) - fi - benchmark_command+=( "${benchmark_args[@]}" ) - - echo "--- ${name} ---" - echo "pushing..." - "${push_command[@]}" - echo "running..." - failed_count=0 - for i in $(seq 1 ${iterations}) - do - "${benchmark_command[@]}" || failed_count=$(( $failed_count + 1 )) - done - - if [ $failed_count != 0 ]; then - failed_benchmarks+=( "${name} ${failed_count}/${iterations}" ) - fi -done - -if [ "${#failed_benchmarks[@]}" -ne 0 ]; then - for failed_benchmark in "${failed_benchmarks[@]}" - do - echo "!!! FAILED TEST: ${failed_benchmark} !!!" - done - exit 1 -fi - -exit 0 diff --git a/system/test/run_host_unit_tests.py b/system/test/run_host_unit_tests.py deleted file mode 100755 index 5f70325faebba62c482c03b4d6de11dd4e0bfa6a..0000000000000000000000000000000000000000 --- a/system/test/run_host_unit_tests.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2017, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import sys -import subprocess -import os -import argparse - -# Registered host based unit tests -# Must have 'host_supported: true' -HOST_TESTS = [ - 'bluetooth_test_common', - 'bluetoothtbd_test', - 'net_test_avrcp', - 'net_test_btcore', - 'net_test_types', - 'net_test_btm_iso', - 'net_test_btpackets', -] - -SOONG_UI_BASH = 'build/soong/soong_ui.bash' - - -def str2bool(argument, default=False): - """ Convert a string to a booleen value. """ - argument = str(argument) - if argument.lower() in ['0', 'f', 'false', 'off', 'no', 'n']: - return False - elif argument.lower() in ['1', 't', 'true', 'on', 'yes', 'y']: - return True - return default - - -def check_dir_exists(dir, dirname): - if not os.path.isdir(dir): - print "Couldn't find %s (%s)!" % (dirname, dir) - sys.exit(0) - - -def get_output_from_command(cmd): - try: - return subprocess.check_output(cmd).strip() - except subprocess.CalledProcessError as e: - print 'Failed to call {cmd}, return code {code}'.format(cmd=cmd, code=e.returncode) - print e - return None - - -def get_android_root_or_die(): - value = os.environ.get('ANDROID_BUILD_TOP') - if not value: - # Try to find build/soong/soong_ui.bash upwards until root directory - current_path = os.path.abspath(os.getcwd()) - while current_path and os.path.isdir(current_path): - soong_ui_bash_path = os.path.join(current_path, SOONG_UI_BASH) - if os.path.isfile(soong_ui_bash_path): - # Use value returned from Soong UI instead in case definition to TOP - # changes in the future - value = get_output_from_command((soong_ui_bash_path, '--dumpvar-mode', '--abs', 'TOP')) - break - parent_path = os.path.abspath(os.path.join(current_path, os.pardir)) - if parent_path == current_path: - current_path = None - else: - current_path = parent_path - if not value: - print 'Cannot determine ANDROID_BUILD_TOP' - sys.exit(1) - check_dir_exists(value, '$ANDROID_BUILD_TOP') - return value - - -def get_android_host_out_or_die(): - value = os.environ.get('ANDROID_HOST_OUT') - if not value: - ANDROID_BUILD_TOP = get_android_root_or_die() - value = get_output_from_command((os.path.join(ANDROID_BUILD_TOP, SOONG_UI_BASH), '--dumpvar-mode', '--abs', - 'HOST_OUT')) - if not value: - print 'Cannot determine ANDROID_HOST_OUT' - sys.exit(1) - check_dir_exists(value, '$ANDROID_HOST_OUT') - return value - - -def get_android_dist_dir_or_die(): - # Check if $DIST_DIR is predefined as environment variable - value = os.environ.get('DIST_DIR') - if not value: - # If not use the default path - ANDROID_BUILD_TOP = get_android_root_or_die() - value = os.path.join(os.path.join(ANDROID_BUILD_TOP, 'out'), 'dist') - if not os.path.isdir(value): - if os.path.exists(value): - print '%s is not a directory!' % (value) - sys.exit(1) - os.makedirs(value) - return value - - -def get_native_test_root_or_die(): - android_host_out = get_android_host_out_or_die() - test_root = os.path.join(android_host_out, 'nativetest64') - if not os.path.isdir(test_root): - test_root = os.path.join(android_host_out, 'nativetest') - if not os.path.isdir(test_root): - print 'Neither nativetest64 nor nativetest directory exist,' \ - ' please compile first' - sys.exit(1) - return test_root - - -def get_test_cmd_or_die(test_root, test_name, enable_xml, test_filter): - test_path = os.path.join(os.path.join(test_root, test_name), test_name) - if not os.path.isfile(test_path): - print 'Cannot find: ' + test_path - sys.exit(1) - cmd = [test_path] - if enable_xml: - dist_dir = get_android_dist_dir_or_die() - log_output_path = os.path.join(dist_dir, 'gtest/{0}_test_details.xml'.format(test_name)) - cmd.append('--gtest_output=xml:{0}'.format(log_output_path)) - if test_filter: - cmd.append('--gtest_filter=%s' % test_filter) - return cmd - - -# path is relative to Android build top -def build_target(target, num_tasks): - ANDROID_BUILD_TOP = get_android_root_or_die() - build_cmd = [SOONG_UI_BASH, '--make-mode'] - if num_tasks > 1: - build_cmd.append('-j' + str(num_tasks)) - build_cmd.append(target) - p = subprocess.Popen(build_cmd, cwd=ANDROID_BUILD_TOP, env=os.environ.copy()) - return_code = p.wait() - if return_code != 0: - print 'BUILD FAILED, return code: {0}'.format(str(return_code)) - sys.exit(1) - return - - -def main(): - """ run_host_unit_tests.py - Run registered host based unit tests - """ - parser = argparse.ArgumentParser(description='Run host based unit tests.') - parser.add_argument( - '--enable_xml', - type=str2bool, - dest='enable_xml', - nargs='?', - const=True, - default=False, - help='Whether to output structured XML log output in out/dist/gtest directory') - parser.add_argument( - '-j', - type=int, - nargs='?', - dest='num_tasks', - const=-1, - default=-1, - help='Number of tasks to run at the same time') - parser.add_argument( - 'rest', nargs=argparse.REMAINDER, help='-- args, other gtest arguments for each individual test') - args = parser.parse_args() - - build_target('MODULES-IN-system-bt', args.num_tasks) - TEST_ROOT = get_native_test_root_or_die() - test_results = [] - for test in HOST_TESTS: - test_cmd = get_test_cmd_or_die(TEST_ROOT, test, args.enable_xml, args.rest) - if subprocess.call(test_cmd) != 0: - test_results.append(False) - else: - test_results.append(True) - if not all(test_results): - failures = [i for i, x in enumerate(test_results) if not x] - for index in failures: - print 'TEST FAILLED: ' + HOST_TESTS[index] - sys.exit(0) - print 'TEST PASSED ' + str(len(test_results)) + ' tests were run' - - dist_dir = get_android_dist_dir_or_die() - log_output_path = os.path.join(dist_dir, 'gtest/coverage') - cmd_path = os.path.join(get_android_root_or_die(), 'packages/modules/Bluetooth/system/test') - print cmd_path - cmd = [ - os.path.join(cmd_path, 'gen_coverage.py'), - '--skip-html', - '--json-file', - '-o', - log_output_path, - ] - subprocess.call(cmd) - - sys.exit(0) - - -if __name__ == '__main__': - main() diff --git a/system/test/run_unit_tests.sh b/system/test/run_unit_tests.sh deleted file mode 100755 index 361fbdcd8e1aa6eeb57c18b717ba2622e420aacd..0000000000000000000000000000000000000000 --- a/system/test/run_unit_tests.sh +++ /dev/null @@ -1,162 +0,0 @@ -#!/bin/sh - -known_tests=( - audio_bluetooth_hw_test - bluetooth-test-audio-hal-interface - bluetooth_test_common - bluetoothtbd_test - net_test_audio_a2dp_hw - net_test_avrcp - net_test_bluetooth - net_test_btcore - net_test_bta - net_test_bta_security - net_test_btif - net_test_btif_profile_queue - net_test_btif_avrcp_audio_track - net_test_btif_config_cache - net_test_device - net_test_device_iot_config - net_test_eatt - net_test_hci - net_test_stack - net_test_stack_multi_adv - net_test_stack_ad_parser - net_test_stack_smp - net_test_types - net_test_osi - net_test_performance - net_test_stack_rfcomm - net_test_gatt_conn_multiplexing -) - -known_remote_tests=( - net_test_rfcomm_suite -) - - -usage() { - binary="$(basename "$0")" - echo "Usage: ${binary} --help" - echo " ${binary} [-i ] [-s ] [--all] [[.] ...] [-- ...]" - echo - echo "Unknown long arguments are passed to the test." - echo - echo "Known test names:" - - for name in "${known_tests[@]}" - do - echo " ${name}" - done - - echo - echo "Known tests that need a remote device:" - for name in "${known_remote_tests[@]}" - do - echo " ${name}" - done -} - -iterations=1 -device= -tests=() -test_args=() -while [ $# -gt 0 ] -do - case "$1" in - -h|--help) - usage - exit 0 - ;; - -i) - shift - if [ $# -eq 0 ]; then - echo "error: number of iterations expected" 1>&2 - usage - exit 2 - fi - iterations=$(( $1 )) - shift - ;; - -s) - shift - if [ $# -eq 0 ]; then - echo "error: no device specified" 1>&2 - usage - exit 2 - fi - device="$1" - shift - ;; - --all) - tests+=( "${known_tests[@]}" ) - shift - ;; - --*) - test_args+=( "$1" ) - shift - ;; - *) - tests+=( "$1" ) - shift - ;; - esac -done - -if [ "${#tests[@]}" -eq 0 ]; then - tests+=( "${known_tests[@]}" ) -fi - -adb=( "adb" ) -if [ -n "${device}" ]; then - adb+=( "-s" "${device}" ) -fi - -source ${ANDROID_BUILD_TOP}/build/envsetup.sh -target_arch=$(gettargetarch) - -failed_tests=() -for spec in "${tests[@]}" -do - name="${spec%%.*}" - if [[ $target_arch == *"64"* ]]; then - binary="/data/nativetest64/${name}/${name}" - if [ -e "${ANDROID_PRODUCT_OUT}${binary}64" ]; then - binary="/data/nativetest64/${name}/${name}64" - fi - else - binary="/data/nativetest/${name}/${name}" - fi - - push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" ) - test_command=( "${adb[@]}" shell "${binary}" ) - if [ "${name}" != "${spec}" ]; then - filter="${spec#*.}" - test_command+=( "--gtest_filter=${filter}" ) - fi - test_command+=( "${test_args[@]}" ) - - echo "--- ${name} ---" - echo "pushing..." - "${push_command[@]}" - echo "running..." - failed_count=0 - for i in $(seq 1 ${iterations}) - do - "${test_command[@]}" || failed_count=$(( $failed_count + 1 )) - done - - if [ $failed_count != 0 ]; then - failed_tests+=( "${name} ${failed_count}/${iterations}" ) - fi -done - -if [ "${#failed_tests[@]}" -ne 0 ]; then - for failed_test in "${failed_tests[@]}" - do - echo "!!! FAILED TEST: ${failed_test} !!!" - done - exit 1 -fi - -exit 0 diff --git a/system/test/stub/legacy_trace.cc b/system/test/stub/legacy_trace.cc deleted file mode 100644 index e3351ee21084e282bdc1e2e7894a1e302f8a4f70..0000000000000000000000000000000000000000 --- a/system/test/stub/legacy_trace.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -// tLEGACY_TRACE_LEVEL -uint8_t btu_trace_level = 6; -uint8_t appl_trace_level = 6; -uint8_t btif_trace_level = 6; - -uint8_t A2DP_SetTraceLevel(uint8_t new_level) { return 0; } -uint8_t AVCT_SetTraceLevel(uint8_t new_level) { return 0; } -uint8_t AVDT_SetTraceLevel(uint8_t new_level) { return 0; } -uint8_t AVRC_SetTraceLevel(uint8_t new_level) { return 0; } -uint8_t BNEP_SetTraceLevel(uint8_t new_level) { return 0; } -uint8_t BTM_SetTraceLevel(uint8_t new_level) { return 0; } -uint8_t PAN_SetTraceLevel(uint8_t new_level) { return 0; } -uint8_t PORT_SetTraceLevel(uint8_t new_level) { return 0; } -uint8_t SMP_SetTraceLevel(uint8_t new_level) { return 0; } diff --git a/system/test/stub/osi.cc b/system/test/stub/osi.cc index 6c6be0a5d49867c32dd69f343e0cc8848a3f1805..6643ad7b5c98843f8b9e6bfc6aa681f7884adbcd 100644 --- a/system/test/stub/osi.cc +++ b/system/test/stub/osi.cc @@ -28,8 +28,6 @@ #include "osi/include/alarm.h" #include "osi/include/allocator.h" -#include "osi/include/array.h" -#include "osi/include/buffer.h" #include "osi/include/config.h" #include "osi/include/fixed_queue.h" #include "osi/include/future.h" @@ -161,50 +159,6 @@ void section_t::Set(std::string key, std::string value) { inc_func_call_count(__func__); } -bool array_append_ptr(array_t* array, void* data) { - inc_func_call_count(__func__); - return false; -} -bool array_append_value(array_t* array, uint32_t value) { - inc_func_call_count(__func__); - return false; -} -size_t array_length(const array_t* array) { - inc_func_call_count(__func__); - return 0; -} -void array_free(array_t* array) { inc_func_call_count(__func__); } -void* array_at(const array_t* array, size_t index) { - inc_func_call_count(__func__); - return nullptr; -} -void* array_ptr(const array_t* array) { - inc_func_call_count(__func__); - return nullptr; -} - -size_t allocation_tracker_expect_no_allocations(void) { - inc_func_call_count(__func__); - return 0; -} -size_t allocation_tracker_resize_for_canary(size_t size) { - inc_func_call_count(__func__); - return 0; -} -void allocation_tracker_reset(void) { inc_func_call_count(__func__); } -void allocation_tracker_uninit(void) { inc_func_call_count(__func__); } -void osi_allocator_debug_dump(int fd) { inc_func_call_count(__func__); } -void* allocation_tracker_notify_alloc(uint8_t allocator_id, void* ptr, - size_t requested_size) { - inc_func_call_count(__func__); - return nullptr; -} -void* allocation_tracker_notify_free(UNUSED_ATTR uint8_t allocator_id, - void* ptr) { - inc_func_call_count(__func__); - return nullptr; -} - bool reactor_change_registration(reactor_object_t* object, void (*read_ready)(void* context), void (*write_ready)(void* context)) { @@ -425,24 +379,6 @@ int osi_rand(void) { return 0; } -buffer_t* buffer_new_ref(const buffer_t* buf) { - inc_func_call_count(__func__); - return nullptr; -} -buffer_t* buffer_new_slice(const buffer_t* buf, size_t slice_size) { - inc_func_call_count(__func__); - return nullptr; -} -size_t buffer_length(const buffer_t* buf) { - inc_func_call_count(__func__); - return 0; -} -void buffer_free(buffer_t* buffer) { inc_func_call_count(__func__); } -void* buffer_ptr(const buffer_t* buf) { - inc_func_call_count(__func__); - return nullptr; -} - bool socket_listen(const socket_t* socket, port_t port) { inc_func_call_count(__func__); return false; diff --git a/system/test/suite/Android.bp b/system/test/suite/Android.bp index ff838d602c63a3b63cc90ba68944132dd0e04342..1234a49397cc3dc0edac0543fa5e5386357aa198 100644 --- a/system/test/suite/Android.bp +++ b/system/test/suite/Android.bp @@ -32,18 +32,13 @@ cc_defaults { "packages/modules/Bluetooth/system/stack/include", "packages/modules/Bluetooth/system/stack/l2cap", "packages/modules/Bluetooth/system/udrv/include", - "packages/modules/Bluetooth/system/vnd/include", "system/libfmq/include", "system/libhwbinder/include", ], srcs: [ ":BtaDmSources", ":TestCommonMockFunctions", - ":TestMockAndroidHardware", - ":TestMockCommon", - ":TestMockFrameworks", ":TestMockHci", - ":TestMockSystemLibfmq", ":TestMockUdrv", "adapter/bluetooth_test.cc", ], @@ -51,15 +46,17 @@ cc_defaults { "android.hardware.bluetooth.audio@2.0", "android.hardware.bluetooth.audio@2.1", "android.system.suspend-V1-ndk", + "libPlatformProperties", + "libaaudio", "libbinder", "libbinder_ndk", "libcrypto", "libcutils", + "libfmq", "libhidlbase", "liblog", "libstatssocket", "libutils", - "libPlatformProperties", ], static_libs: [ "android.hardware.bluetooth.a2dp@1.0", @@ -89,7 +86,7 @@ cc_defaults { "libbtif", "libbtif-core", "libc++fs", - "libcom.android.sysprop.bluetooth", + "libcom.android.sysprop.bluetooth.wrapped", "libflatbuffers-cpp", "libg722codec", "libgmock", @@ -106,9 +103,11 @@ cc_defaults { cc_test { name: "net_test_bluetooth", - test_suites: ["device-tests"], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", + "latest_android_hardware_audio_common_ndk_static", + "latest_android_hardware_bluetooth_audio_ndk_static", + "latest_android_media_audio_common_types_ndk_static", "mts_defaults", "net_test_defaults", ], @@ -118,14 +117,28 @@ cc_test { "gatt/gatt_unittest.cc", ], static_libs: [ - "android.hardware.audio.common-V2-ndk", - "android.hardware.bluetooth.audio-V3-ndk", - "android.hardware.bluetooth@1.0", - "android.hardware.bluetooth@1.1", - "android.hardware.common-V2-ndk", - "android.hardware.common.fmq-V1-ndk", - "android.media.audio.common.types-V2-ndk", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbt-btu-main-thread", + "libbt-platform-protos-lite", + "libbt_shim_bridge", "libchrome", "libevent", + "libprotobuf-cpp-lite", + ], + shared_libs: [ + "server_configurable_flags", ], + target: { + android: { + static_libs: [ + "android.hardware.bluetooth@1.0", + "android.hardware.bluetooth@1.1", + "android.hardware.common-V2-ndk", + "android.hardware.common.fmq-V1-ndk", + ], + }, + host: {}, + }, + cflags: ["-Wno-unused-parameter"], } diff --git a/system/test/suite/adapter/adapter_unittest.cc b/system/test/suite/adapter/adapter_unittest.cc index fe30df33529b8786e99712d4db5e7d7c68d4f9cd..dc8771da3c054b93adabd0e71b98e4b251982aa0 100644 --- a/system/test/suite/adapter/adapter_unittest.cc +++ b/system/test/suite/adapter/adapter_unittest.cc @@ -18,7 +18,6 @@ #include "adapter/bluetooth_test.h" #include "btcore/include/property.h" -#include "stack/include/bt_types.h" #include "types/bt_transport.h" #include "types/raw_address.h" diff --git a/system/test/tool/README.md b/system/test/tool/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a8abb5cce7efc453300509d43702c5c6d3f71da0 --- /dev/null +++ b/system/test/tool/README.md @@ -0,0 +1,27 @@ + + +*** mock-C-ify + +Any legacy code that is incapable of mocking may be a candidate for the +use of the mockCify tool to mock code in order to provide symbolic endpoints during the linkage +phase with additonal run time configurability to provide crafted testing solution. + + +** To use + + < + +mockcify_tool: mockcify.pl +namespace: A brief single token namespace conventionally used from the path and filename +source_code: The C code being mocked. + +``` +e.g. +mockcify.pl btif_sock_rfc < btif/src/btif_sock_rfc.cc +``` + +NOTE: This tool is does not handle Cpp code well and is recommended to use gmock for those solutions. + +Other Cpp language syntax, such as move semantics and lambdas also do not parse well and may need hand +crafting for those last few pieces. + diff --git a/system/test/tool/mockcify.pl b/system/test/tool/mockcify.pl index 90649044442b476d6eec29c00a85a2e0303d64f9..dd974c0aaeb6f6146a026bbe84e29cf966c52a1d 100755 --- a/system/test/tool/mockcify.pl +++ b/system/test/tool/mockcify.pl @@ -18,6 +18,14 @@ use File::Basename; ## mockcify version ## +## 0.7.0 Comment out unused mock variables +## +## 0.6.3 Streamline inclusion for headers and source +## +## 0.6.2 Add tBTA_STATUS default value, Cpp type failure log +## +## 0.6.1 Add tBTA_SDP_STATUS default value +## ## 0.6.0 Replace `extern` with `include` for mock_function_count_map ## ## 0.5.0 Add compilation check @@ -36,11 +44,15 @@ use File::Basename; ## ## 0.2.0 First version ## -my $VERSION = "0.6.0"; +my $VERSION = "0.7.0"; +use diagnostics; use strict; use warnings; +use lib "$ENV{ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/test/tool"; +require 'mockcify_util.pl'; + my $YEAR = "2023"; my $TOKEN = "MOCKCIFY_TOKEN"; my $MOCKCIFY_BRACKET_GROUP = "MOCKCIFY_BRACKET_GROUP"; @@ -267,9 +279,9 @@ sub print_source { my $FH = shift @_; print_copyright($FH); print_generated_note($FH); - print_mock_decl_src($FH); print_mock_header_include($FH); + print_mock_decl_src($FH); print_usings($FH); print_internal_structs($FH); print_source_namespace_structs($FH); @@ -303,6 +315,10 @@ sub get_function_param_names { my $param_name = $function_param_names{$name}[$_]; my $param_type = $function_param_types{$name}[$_]; + if (!defined($param_type)) { + printf(STDERR "Unable to find param type def for $name\n"); + next; + } if ($param_type =~ /unique_ptr/) { ## Wrap name in a move operation push(@param_names, "std::move($param_name)"); @@ -361,6 +377,7 @@ sub parse_function_into_components { ## Skip when void keyword used for no parameters if ($params ne "void") { + ## TODO Replace all comma types within angle brackets before split foreach (split ',', $params) { s/^\s+//; if (/\(/) { @@ -561,6 +578,10 @@ sub get_default_return_value_from_type { return "nullptr"; } elsif(/btav_a2dp_codec_index_t/) { return "BTAV_A2DP_CODEC_INDEX_SOURCE_MIN"; + } elsif(/tBTA_SDP_STATUS/) { + return "BTA_SDP_SUCCESS"; + } elsif(/tBTA_STATUS/) { + return "BTA_SUCCESS"; } else { ## Decay to int type return "0"; @@ -680,6 +701,7 @@ namespace $namespace { EOF foreach my $name (sort @function_names) { my $input_params = $function_params{$name}; + my $vars_commented_out_input_params = comment_out_input_vars($input_params); my $return_type = $function_return_types{$name}; my @param_names = $function_param_names{$name}; assert($return_type ne ''); @@ -699,7 +721,7 @@ EOF print $FH "$return_definition\n"; } print $FH < body{[]($input_params){$return_statement}}; + std::function<$return_type($input_params)> body{[]($vars_commented_out_input_params){$return_statement}}; $return_type operator()($input_params) { ${return_keyword} body($function_param_names);}; }; extern struct $name $name; @@ -777,10 +799,6 @@ sub print_mock_decl_hdr { print $FH < #include -#include -#include - -#include "test/common/mock_functions.h" EOF } @@ -789,9 +807,8 @@ sub print_mock_decl_src { my $FH = shift @_; print $FH < -#include -#include -#include + +#include "test/common/mock_functions.h" EOF } diff --git a/system/test/tool/mockcify_test.pl b/system/test/tool/mockcify_test.pl index 617c8a3d3c0da9944116bbc45d9eda843cd6cd5f..0922cfe87b56a7d9720e7cc746a3484fee40a54f 100755 --- a/system/test/tool/mockcify_test.pl +++ b/system/test/tool/mockcify_test.pl @@ -14,22 +14,26 @@ ## See the License for the specific language governing permissions and ## limitations under the License. -my $MOCKCIFY="./test/tool/mockcify.pl"; +package Mockcify; -my @tests=( - "osi/src/allocator.cc", - "osi/src/list.cc", - "osi/src/mutex.cc", -); +use diagnostics; +use strict; +use warnings; -print; -foreach (@tests) { - print(STDOUT "\33[2K\r$_\r"); - my $cmd = "$MOCKCIFY TEST < $_"; - my $rc = system("$cmd > /dev/null 2&>1"); - if ($rc != 0) { - print(STDERR "\nFAILED \'$_\' cmd:\'$cmd\'\n"); - exit 1; - } -} -print(STDERR "\33[2K\rPASSED\n"); +use lib "$ENV{ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/test/tool"; +require 'mockcify_util.pl'; + +printf("MOCKCIFY unit test\n"); + +"void" eq comment_out_input_vars("void") + || die("FAIL file:", __FILE__, " line:", __LINE__, "\n"); +"one /* two */" eq comment_out_input_vars("one two") + || die("FAIL file:", __FILE__, " line:", __LINE__, "\n"); +"one /* two */, three /* four */, five /* six */" eq comment_out_input_vars("one two, three four, five six") + || die("FAIL file:", __FILE__, " line:", __LINE__, "\n"); +"std::string /* s */, tSOME_STRUCT /* struct */" eq comment_out_input_vars("std::string s , tSOME_STRUCT struct") + || die("FAIL file:", __FILE__, " line:", __LINE__, "\n"); +"const std::string& /* s */, tSOME_STRUCT /* struct */" eq comment_out_input_vars(" const std::string& s , tSOME_STRUCT struct") + || die("FAIL file:", __FILE__, " line:", __LINE__, "\n"); + +printf("SUCCESS\n"); diff --git a/system/test/tool/mockcify_util.pl b/system/test/tool/mockcify_util.pl new file mode 100644 index 0000000000000000000000000000000000000000..ec7a9c17f1a3dcd6635b2424ea9bcec67862e025 --- /dev/null +++ b/system/test/tool/mockcify_util.pl @@ -0,0 +1,47 @@ +## +## Copyright 2023 The Android Open Source Project +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. + +use diagnostics; +use strict; +use warnings; + +## +## Take a string of parameters in and return the parameter name commented out +## +## e.g. +## int a, char b, std::string c => int /* a */, char /* b */, std::string /* c */ +## +sub comment_out_input_vars { + my $input_param_string = shift @_; + my @return_param_string; + my @params = split /,/, $input_param_string; + foreach (@params) { + ## Trim leading and trailing space + s/^\s+|\s+$//g; + ## Reduce multiple internal spaces to single space + s/\s\+/ /g; + my @w = split /\s+/, $_; + my $s; + if ($#w != 0) { + chomp($w[$#w]); + $w[$#w] = "/* $w[$#w] */"; + } + $s .= join " ", @w; + push(@return_param_string, $s); + } + return join(', ', @return_param_string); +} + +1; diff --git a/system/tools/Android.mk.disabled b/system/tools/Android.mk.disabled deleted file mode 100644 index 5053e7d64389d3eaa35c6e807277fff9f83898f6..0000000000000000000000000000000000000000 --- a/system/tools/Android.mk.disabled +++ /dev/null @@ -1 +0,0 @@ -include $(call all-subdir-makefiles) diff --git a/system/tools/bdtool/Android.mk.disabled b/system/tools/bdtool/Android.mk.disabled deleted file mode 100644 index 76b8dceb1a2836a68f5abcb67e5e7e38d9aa7169..0000000000000000000000000000000000000000 --- a/system/tools/bdtool/Android.mk.disabled +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2014 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. -# - -LOCAL_PATH := $(call my-dir) - -# Bluetooth tools for target -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := net_bdtool - -LOCAL_SRC_FILES := \ - adapter.c \ - bdtool.c \ - ../../test/suite/support/callbacks.c \ - ../../test/suite/support/gatt.c \ - ../../test/suite/support/hal.c \ - ../../test/suite/support/pan.c - -LOCAL_STATIC_LIBRARIES := \ - libbtcore \ - libosi - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/../../test/suite \ - $(LOCAL_PATH)/../.. - -LOCAL_SHARED_LIBRARIES := \ - libhardware liblog - -LOCAL_CFLAGS += $(bluetooth_CFLAGS) -LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS) -LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS) - -include $(BUILD_EXECUTABLE) diff --git a/system/tools/bdtool/adapter.c b/system/tools/bdtool/adapter.c deleted file mode 100644 index 3b964a0f78328939553b2ea8fe6df65cf7249594..0000000000000000000000000000000000000000 --- a/system/tools/bdtool/adapter.c +++ /dev/null @@ -1,276 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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. - * - ******************************************************************************/ - -#include "support/adapter.h" - -#include "base.h" -#include "btcore/include/property.h" -#include "support/callbacks.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" - -static bt_state_t state; -static int property_count = 0; -static bt_property_t* properties = NULL; -static bt_discovery_state_t discovery_state; -static bt_acl_state_t acl_state; -static bt_bond_state_t bond_state; - -static void parse_properties(int num_properties, bt_property_t* property); - -// Returns the current adapter state. -bt_state_t adapter_get_state() { return state; } - -// Returns the number of adapter properties. -int adapter_get_property_count() { return property_count; } - -// Returns the specified property. -bt_property_t* adapter_get_property(bt_property_type_t type) { - for (int i = 0; i < property_count; ++i) { - if (properties[i].type == type) { - return &properties[i]; - } - } - - return NULL; -} - -// Returns the device discovery state. -bt_discovery_state_t adapter_get_discovery_state() { return discovery_state; } - -// Returns the device acl state. -bt_acl_state_t adapter_get_acl_state() { return acl_state; } - -// Returns the device bond state. -bt_bond_state_t adapter_get_bond_state() { return bond_state; } - -// callback -void acl_state_changed(bt_status_t status, RawAddress* remote_bd_addr, - bt_acl_state_t state) { - acl_state = state; - CALLBACK_RET(); -} - -// callback -void adapter_properties(bt_status_t status, int num_properties, - bt_property_t* new_properties) { - property_free_array(properties, property_count); - properties = property_copy_array(new_properties, num_properties); - property_count = num_properties; - - CALLBACK_RET(); -} - -// callback -void adapter_state_changed(bt_state_t new_state) { - state = new_state; - CALLBACK_RET(); -} - -// callback -void bond_state_changed(bt_status_t status, RawAddress* bdaddr, - bt_bond_state_t state) { - char buf[18]; - bond_state = state; - - const char* state_name = "Bond state unknown"; - switch (bond_state) { - case BT_BOND_STATE_NONE: - state_name = "Bond state none"; - break; - - case BT_BOND_STATE_BONDING: - state_name = "Bond state bonding"; - break; - - case BT_BOND_STATE_BONDED: - state_name = "Bond state bonded"; - break; - - // default none - } - fprintf(stdout, "Bond state changed callback addr:%s state:%s\n", - bdaddr_to_string(bdaddr, buf, sizeof(buf)), state_name); - - CALLBACK_RET(); -} - -// callback -void device_found(int num_properties, bt_property_t* property) { - fprintf(stdout, "Device found num_properties:%d\n", num_properties); - parse_properties(num_properties, property); - - CALLBACK_RET(); -} - -// callback -void discovery_state_changed(bt_discovery_state_t state) { - const char* state_name = "Unknown"; - discovery_state = state; - - switch (discovery_state) { - case BT_DISCOVERY_STOPPED: - state_name = "Discovery stopped"; - break; - - case BT_DISCOVERY_STARTED: - state_name = "Discovery started"; - break; - - // default omitted - } - fprintf(stdout, "Discover state %s\n", state_name); - - CALLBACK_RET(); -} - -// callback -void remote_device_properties(bt_status_t status, RawAddress* bdaddr, - int num_properties, bt_property_t* properties) { - char buf[18]; - fprintf(stdout, "Device found bdaddr:%s num_properties:%d\n", - bdaddr_to_string(bdaddr, buf, sizeof(buf)), num_properties); - - parse_properties(num_properties, properties); - - CALLBACK_RET(); -} - -// callback -void ssp_request(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod, - bt_ssp_variant_t pairing_variant, uint32_t pass_key) { - char* pairing_variant_name = "Unknown"; - - switch (pairing_variant) { - case BT_SSP_VARIANT_PASSKEY_CONFIRMATION: - pairing_variant_name = "Passkey confirmation"; - break; - case BT_SSP_VARIANT_PASSKEY_ENTRY: - pairing_variant_name = "Passkey entry"; - break; - - case BT_SSP_VARIANT_CONSENT: - pairing_variant_name = "Passkey consent"; - break; - - case BT_SSP_VARIANT_PASSKEY_NOTIFICATION: - pairing_variant_name = "Passkey notification"; - break; - } - - fprintf(stdout, - "Got ssp request device_class:%u passkey:%x pairing_variant:%s\n", - cod, pass_key, pairing_variant_name); - char buf[18]; - fprintf(stdout, "Device found:%s %s\n", - bdaddr_to_string(remote_bd_addr, buf, sizeof(buf)), bd_name->name); - - fprintf(stdout, "auto-accepting bond\n"); - bool accept = true; - int rc = bt_interface->ssp_reply(remote_bd_addr, pairing_variant, - (uint8_t)accept, pass_key); - CALLBACK_RET(); -} - -// callback -void thread_evt(bt_cb_thread_evt evt) { CALLBACK_RET(); } - -static void parse_properties(int num_properties, bt_property_t* property) { - while (num_properties-- > 0) { - switch (property->type) { - case BT_PROPERTY_BDNAME: { - const bt_bdname_t* name = property_as_name(property); - if (name) fprintf(stdout, " name:%s\n", name->name); - } break; - - case BT_PROPERTY_BDADDR: { - char buf[18]; - const RawAddress* addr = property_as_addr(property); - if (addr) - fprintf(stdout, " addr:%s\n", - bdaddr_to_string(addr, buf, sizeof(buf))); - } break; - - case BT_PROPERTY_UUIDS: { - size_t num_uuid; - const Uuid* uuid = property_as_uuids(property, &num_uuid); - if (uuid) { - for (size_t i = 0; i < num_uuid; i++) { - fprintf(stdout, " uuid:%zd: ", i); - for (size_t j = 0; j < sizeof(uuid); j++) { - fprintf(stdout, "%02x", uuid->uu[j]); - } - fprintf(stdout, "\n"); - } - } - } break; - - case BT_PROPERTY_TYPE_OF_DEVICE: { - bt_device_type_t device_type = property_as_device_type(property); - if (device_type) { - const struct { - const char* device_type; - } device_type_lookup[] = { - {"Unknown"}, - {"Classic Only"}, - {"BLE Only"}, - {"Both Classic and BLE"}, - }; - int idx = (int)device_type; - if (idx > BT_DEVICE_DEVTYPE_DUAL) idx = 0; - fprintf(stdout, " device_type:%s\n", - device_type_lookup[idx].device_type); - } - } break; - - case BT_PROPERTY_CLASS_OF_DEVICE: { - const bt_device_class_t* dc = property_as_device_class(property); - int dc_int = device_class_to_int(dc); - fprintf(stdout, " device_class:0x%x\n", dc_int); - } break; - - case BT_PROPERTY_REMOTE_RSSI: { - int8_t rssi = property_as_rssi(property); - fprintf(stdout, " rssi:%d\n", rssi); - } break; - - case BT_PROPERTY_REMOTE_FRIENDLY_NAME: { - const bt_bdname_t* name = property_as_name(property); - if (name) fprintf(stdout, " remote_name:%s\n", name->name); - } break; - - case BT_PROPERTY_SERVICE_RECORD: - case BT_PROPERTY_ADAPTER_SCAN_MODE: - case BT_PROPERTY_ADAPTER_BONDED_DEVICES: - case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT: - case BT_PROPERTY_REMOTE_VERSION_INFO: - case BT_PROPERTY_LOCAL_LE_FEATURES: - case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP: - default: { - fprintf(stderr, "Unhandled property type:%d len:%d\n", property->type, - property->len); - uint8_t* p = (uint8_t*)property->val; - for (int i = 0; i < property->len; ++i, p++) { - fprintf(stderr, " %02x", *p); - } - if (property->len != 0) fprintf(stderr, "\n"); - } - } - property++; - } -} diff --git a/system/tools/bdtool/bdtool.c b/system/tools/bdtool/bdtool.c deleted file mode 100644 index 07970a7744fe526cf9e764bb01e11568168fcabb..0000000000000000000000000000000000000000 --- a/system/tools/bdtool/bdtool.c +++ /dev/null @@ -1,362 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 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. - * - ******************************************************************************/ - -#include -#include -#include -#include - -#include "btcore/include/property.h" -#include "osi/include/osi.h" -#include "test/suite/support/callbacks.h" -#include "test/suite/support/hal.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" - -static const Uuid HFP_UUID = - Uuid::From128BitBE({{0x00, 0x00, 0x11, 0x1E, 0x00, 0x00, 0x10, 0x00, 0x80, - 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}}); -static const Uuid HFP_AG_UUID = - Uuid::From128BitBE({{0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10, 0x00, 0x80, - 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}}); - -const bt_interface_t* bt_interface; - -RawAddress bt_remote_bdaddr; - -static int f_verbose; -static bool discover = false; -static bool discoverable = false; -static bool bond = false; -static bool up = false; -static bool get_name = false; -static bool set_name = false; -static bool sco_listen = false; -static bool sco_connect = false; - -static int timeout_in_sec = 30; -static char* bd_name; - -static struct option long_options[] = { - {"bdaddr", required_argument, 0, 0}, {"discover", no_argument, 0, 0}, - {"discoverable", no_argument, 0, 0}, {"time", required_argument, 0, 0}, - {"bond", no_argument, 0, 0}, {"up", no_argument, 0, 0}, - {"verbose", no_argument, 0, 0}, {"get_name", no_argument, 0, 0}, - {"set_name", required_argument, 0, 0}, {"sco_listen", no_argument, 0, 0}, - {"sco_connect", no_argument, 0, 0}, {0, 0, 0, 0}}; - -static void usage(const char* name); -static bool parse_args(int argc, char** argv); -static void sig_handler(int signo); - -bt_property_t* adapter_get_property(bt_property_type_t type); - -int main(int argc, char** argv) { - if (!parse_args(argc, argv)) { - usage(argv[0]); - } - - if (bond && discoverable) { - fprintf(stderr, "Can only select either bond or discoverable, not both\n"); - usage(argv[0]); - } - - if (sco_listen && sco_connect) { - fprintf(stderr, - "Can only select either sco_listen or sco_connect, not both\n"); - usage(argv[0]); - } - - if (!bond && !discover && !discoverable && !up && !get_name && !set_name && - !sco_listen && !sco_connect) { - fprintf(stderr, "Must specify one command\n"); - usage(argv[0]); - } - - if (signal(SIGINT, sig_handler) == SIG_ERR) { - fprintf(stderr, "Will be unable to catch signals\n"); - } - - fprintf(stdout, "Bringing up bluetooth adapter\n"); - if (!hal_open(callbacks_get_adapter_struct())) { - fprintf(stderr, "Unable to open Bluetooth HAL.\n"); - return 1; - } - - if (discover) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - fprintf(stdout, "Starting to start discovery\n"); - CALL_AND_WAIT(bt_interface->start_discovery(), discovery_state_changed); - fprintf(stdout, "Started discovery for %d seconds\n", timeout_in_sec); - - sleep(timeout_in_sec); - - fprintf(stdout, "Starting to cancel discovery\n"); - CALL_AND_WAIT(bt_interface->cancel_discovery(), discovery_state_changed); - fprintf(stdout, "Cancelled discovery after %d seconds\n", timeout_in_sec); - } - - if (discoverable) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - bt_property_t* property = - property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); - - int rc = bt_interface->set_adapter_property(property); - fprintf(stdout, "Set rc:%d device as discoverable for %d seconds\n", rc, - timeout_in_sec); - - sleep(timeout_in_sec); - - property_free(property); - } - - if (bond) { - if (bdaddr_is_empty(&bt_remote_bdaddr)) { - fprintf(stderr, - "Must specify a remote device address [ " - "--bdaddr=xx:yy:zz:aa:bb:cc ]\n"); - exit(1); - } - - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - int rc = bt_interface->create_bond( - &bt_remote_bdaddr, 0 /* UNKNOWN; Currently not documented :( */); - fprintf(stdout, "Started bonding:%d for %d seconds\n", rc, timeout_in_sec); - - sleep(timeout_in_sec); - } - - if (up) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - fprintf(stdout, "Waiting for %d seconds\n", timeout_in_sec); - sleep(timeout_in_sec); - } - - if (get_name) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - int error; - CALL_AND_WAIT( - error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), - adapter_properties); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to get adapter property\n"); - exit(1); - } - bt_property_t* property = adapter_get_property(BT_PROPERTY_BDNAME); - const bt_bdname_t* name = property_as_name(property); - if (name) - printf("Queried bluetooth device name:%s\n", name->name); - else - printf("No name\n"); - } - - if (set_name) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - bt_property_t* property = property_new_name(bd_name); - printf("Setting bluetooth device name to:%s\n", bd_name); - int error; - CALL_AND_WAIT(error = bt_interface->set_adapter_property(property), - adapter_properties); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to set adapter property\n"); - exit(1); - } - CALL_AND_WAIT( - error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), - adapter_properties); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to get adapter property\n"); - exit(1); - } - property_free(property); - sleep(timeout_in_sec); - } - - const int app_uid = 0; - - if (sco_listen) { - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - bt_property_t* property = - property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); - CALL_AND_WAIT(bt_interface->set_adapter_property(property), - adapter_properties); - property_free(property); - - const btsock_interface_t* sock = - bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID); - - int rfcomm_fd = INVALID_FD; - int error = - sock->listen(BTSOCK_RFCOMM, "meow", (const uint8_t*)&HFP_AG_UUID, 0, - &rfcomm_fd, 0, app_uid); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to listen for incoming RFCOMM socket: %d\n", - error); - exit(1); - } - - int sock_fd = INVALID_FD; - error = sock->listen(BTSOCK_SCO, NULL, NULL, 5, &sock_fd, 0, app_uid); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to listen for incoming SCO sockets: %d\n", error); - exit(1); - } - fprintf(stdout, "Waiting for incoming SCO connections...\n"); - sleep(timeout_in_sec); - } - - if (sco_connect) { - if (bdaddr_is_empty(&bt_remote_bdaddr)) { - fprintf(stderr, - "Must specify a remote device address [ " - "--bdaddr=xx:yy:zz:aa:bb:cc ]\n"); - exit(1); - } - - CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); - fprintf(stdout, "BT adapter is up\n"); - - const btsock_interface_t* sock = - bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID); - - int rfcomm_fd = INVALID_FD; - int error = - sock->connect(&bt_remote_bdaddr, BTSOCK_RFCOMM, - (const uint8_t*)&HFP_AG_UUID, 0, &rfcomm_fd, 0, app_uid); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to connect to RFCOMM socket: %d.\n", error); - exit(1); - } - - WAIT(acl_state_changed); - - fprintf(stdout, "Establishing SCO connection...\n"); - - int sock_fd = INVALID_FD; - error = sock->connect(&bt_remote_bdaddr, BTSOCK_SCO, NULL, 5, &sock_fd, 0, - app_uid); - if (error != BT_STATUS_SUCCESS) { - fprintf(stderr, "Unable to connect to SCO socket: %d.\n", error); - exit(1); - } - sleep(timeout_in_sec); - } - - CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed); - fprintf(stdout, "BT adapter is down\n"); -} - -static void sig_handler(int signo) { - if (signo == SIGINT) { - fprintf(stderr, "Received SIGINT\n"); - CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed); - fprintf(stderr, "BT adapter is down\n"); - exit(1); - } -} - -static void usage(const char* name) { - fprintf(stderr, - "Usage: %s " - "[--bond|--discover|--discoverable|--up|--sco_listen|--sco_connect] " - "[--bdaddr=] [--time=] --verbose\n", - name); - fprintf(stderr, " bond: Discover actively advertising devices\n"); - fprintf(stderr, " discover: Discover actively advertising devices\n"); - fprintf(stderr, - " discoverable: Set into a connectable and discoverable mode\n"); - fprintf(stderr, " up: Only bring up stack\n"); - fprintf(stderr, " sco_listen: Listen for incoming SCO connections\n"); - fprintf(stderr, - " sco_connect: Establish a SCO connection with another device\n"); - fprintf(stderr, " time: Time to hold in the specified mode\n"); - exit(1); -} - -static bool parse_args(int argc, char** argv) { - while (1) { - int option_index = 0; - int c = getopt_long_only(argc, argv, "", long_options, &option_index); - if (c != 0) break; - - switch (c) { - case 0: - if (option_index == 0) { - if (!string_to_bdaddr(optarg, &bt_remote_bdaddr)) { - return false; - } - } - if (option_index == 1) { - discover = true; - } - if (option_index == 2) { - discoverable = true; - } - if (option_index == 3) { - timeout_in_sec = atoi(optarg); - } - if (option_index == 4) { - bond = true; - } - if (option_index == 5) { - up = true; - } - if (option_index == 6) { - f_verbose++; - } - if (option_index == 7) { - get_name = true; - } - if (option_index == 8) { - bd_name = (char*)optarg; - set_name = true; - } - if (option_index == 9) { - sco_listen = true; - } - if (option_index == 10) { - sco_connect = true; - } - break; - - default: - fprintf(stderr, "?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) { - fprintf(stderr, "non-option ARGV-elements: "); - while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); - fprintf(stderr, "\n"); - return false; - } - return true; -} diff --git a/system/tools/hci/main.c b/system/tools/hci/main.c deleted file mode 100644 index 093af6bb3a4771a0ad3d29e29a8500eb707dc8b1..0000000000000000000000000000000000000000 --- a/system/tools/hci/main.c +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "osi/include/osi.h" - -typedef int (*handler_t)(int argc, char** argv); - -typedef enum { - HCI_PACKET_COMMAND = 1, - HCI_PACKET_ACL_DATA = 2, - HCI_PACKET_SCO_DATA = 3, - HCI_PACKET_EVENT = 4, - HCI_PACKET_ISO = 5, -} hci_packet_t; - -typedef struct { - const char* name; - const char* help; - handler_t handler; -} command_t; - -static int help(int argc, char** argv); -static int set_discoverable(int argc, char** argv); -static int set_name(int argc, char** argv); -static int set_pcm_loopback(int argc, char** argv); -static int set_sco_route(int argc, char** argv); - -static bool write_hci_command(hci_packet_t type, const void* packet, - size_t length); -static const command_t* find_command(const char* name); -static void usage(const char* name); - -static const command_t commands[] = { - {"help", " - shows help text for .", help}, - {"setDiscoverable", - "(true|false) - whether the controller should be discoverable.", - set_discoverable}, - {"setName", " - sets the device's Bluetooth name to .", - set_name}, - {"setPcmLoopback", - "(true|false) - enables or disables PCM loopback on the controller.", - set_pcm_loopback}, - {"setScoRoute", - "(pcm|i2s|uart) - sets the SCO packet route to one of the specified " - "buses.", - set_sco_route}, -}; - -static int help(int argc, char** argv) { - if (!argc) { - printf("No help command specified.\n"); - return 1; - } - - const command_t* command = find_command(argv[0]); - if (!command) { - printf("No command named '%s'.\n", argv[0]); - return 2; - } - - printf("%s %s\n", argv[0], command->help); - return 0; -} - -static int set_discoverable(int argc, char** argv) { - if (argc != 1) { - printf("Discoverable mode not specified.\n"); - return 1; - } - - if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { - printf("Invalid discoverable mode '%s'.\n", argv[0]); - return 2; - } - - uint8_t packet[] = {0x1A, 0x0C, 0x01, 0x00}; - if (argv[0][0] == 't') packet[ARRAY_SIZE(packet) - 1] = 0x03; - - return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); -} - -static int set_name(int argc, char** argv) { - if (argc != 1) { - printf("Device name not specified.\n"); - return 1; - } - - size_t len = strlen(argv[0]); - if (len > 247) { - printf("Device name cannot exceed 247 bytes.\n"); - return 2; - } - - uint8_t packet[251] = {0x13, 0x0C, 248}; - memcpy(&packet[3], argv[0], len + 1); - - if (!write_hci_command(HCI_PACKET_COMMAND, packet, sizeof(packet))) return 1; - - memset(&packet[0], 0, sizeof(packet)); - packet[0] = 0x52; - packet[1] = 0x0C; - packet[2] = 0xF1; // HCI command packet length. - packet[3] = 0x01; // FEC required. - packet[4] = len + 1; - packet[5] = 0x09; // Device name field tag. - memcpy(&packet[6], argv[0], len); - return !write_hci_command(HCI_PACKET_COMMAND, packet, 0xF4); -} - -static int set_pcm_loopback(int argc, char** argv) { - if (argc != 1) { - printf("PCM loopback mode not specified.\n"); - return 1; - } - - if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { - printf("Invalid PCM mode '%s'.\n", argv[0]); - return 2; - } - - uint8_t packet[] = {0x24, 0xFC, 0x01, 0x00}; - if (argv[0][0] == 't') packet[ARRAY_SIZE(packet) - 1] = 0x01; - - return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); -} - -static int set_sco_route(int argc, char** argv) { - if (argc != 1) { - printf("SCO route parameter must be specified.\n"); - return 1; - } - - uint8_t route = 0xFF; - if (!strcmp(argv[0], "pcm")) - route = 0; - else if (!strcmp(argv[0], "i2s")) - route = 3; - else if (!strcmp(argv[0], "uart")) - route = 1; - - if (route == 0xFF) { - printf("Invalid SCO route specified: %s\n", argv[0]); - return 2; - } - - uint8_t packet[] = {0x1C, 0xFC, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00}; - packet[3] = route; - - return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); -} - -int main(int argc, char** argv) { - if (argc < 2) { - usage(argv[0]); - return -1; - } - - const command_t* command = find_command(argv[1]); - if (!command) { - printf("Unrecognized command '%s'.\n", argv[1]); - return -2; - } - - if (!command->handler) { - printf("Unhandled command '%s'.\n", argv[1]); - return -3; - } - - return command->handler(argc - 2, &argv[2]); -} - -static bool write_hci_command(hci_packet_t type, const void* packet, - size_t length) { - int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock == INVALID_FD) goto error; - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(0x7F000001); - addr.sin_port = htons(8873); - int ret; - OSI_NO_INTR(ret = connect(sock, (const struct sockaddr*)&addr, sizeof(addr))); - if (ret == -1) goto error; - - if (send(sock, &type, 1, 0) != 1) goto error; - - if (send(sock, &length, 2, 0) != 2) goto error; - - if (send(sock, packet, length, 0) != (ssize_t)length) goto error; - - close(sock); - return true; - -error:; - close(sock); - return false; -} - -static const command_t* find_command(const char* name) { - for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) - if (!strcmp(commands[i].name, name)) return &commands[i]; - return NULL; -} - -static void usage(const char* name) { - printf("Usage: %s [options]\n", name); - printf("Commands:\n"); - for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) - printf(" %s\n", commands[i].name); - printf("For detailed help on a command, run '%s help '.\n", name); -} diff --git a/system/tools/scripts/change_types.sh b/system/tools/scripts/change_types.sh deleted file mode 100755 index 4467b89677391d2b1243c465e088770ac84c6efa..0000000000000000000000000000000000000000 --- a/system/tools/scripts/change_types.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -# This script will recursively search all |FILES| from the current -# directory and replace all |TYPES| according to the list below. - -# NOTE 1: -# If this script is run from .../packages/modules/Bluetooth/system (as it's intended to be), -# please edit stack/include/bt_types.h next and remove the typedef's -# near the top and restore the definitions of TRUE and FALSE. These -# are still used in the vnd_* files and device specific repositories. - -# NOTE 2: -# The list of files to be modified also includes "*.patch", which means -# this script can be used to help cherry-picking changes from older -# branches. Follow this workflow outline: -# 1. git format-patch [-1] -# 2. Run change_type script on patch[es] -# 3. git apply / git am - - -# Regular expression matching the file name -FILES="\.h$|\.c$|\.cpp$|\.cc$|\.patch$" - -# Search/replace terms, separated by ":" -TYPES=( - "UINT8 :uint8_t " - "UINT16 :uint16_t " - "UINT32 :uint32_t " - "UINT64 :uint64_t " - "INT8 :int8_t " - "INT16 :int16_t " - "INT32 :int32_t " - "INT64 :int64_t " - "UINT8:uint8_t" - "UINT16:uint16_t" - "UINT32:uint32_t" - "UINT64:uint64_t" - "INT8:int8_t" - "INT16:int16_t" - "INT32:int32_t" - "INT64:int64_t" - "BOOLEAN:bool " - "TRUE:true" - "FALSE:false" - "__FUNCTION__:__func__" -) - -function process_file -{ - echo -n "Processing file $1 " - - for tt in "${TYPES[@]}" ; - do - before=${tt%%:*} - after=${tt#*:} - - echo -n "." - sed -i -e "s/\b${before}/${after}/g; s/${after}_/${before}_/g;" "$1" - done - echo -} - -function process_files -{ - until [ -z "$1" ] - do - process_file "$1" - shift - done -} - - -# Let's do this ... -process_files `find ./ | grep -E "${FILES}"` - -# All done ... -echo -echo "All done." - -# Try to be helpful ... -PWD=`pwd` -if [[ "${PWD}" == */packages/modules/Bluetooth/system ]] -then - echo "Please edit ${PWD}/stack/include/bt_types.h next." -fi diff --git a/system/types/Android.bp b/system/types/Android.bp index c9d52b2c245772d071d179a623e0107fe8835b93..e556f8e5f25be0a0be519800610b160dae4c56cb 100644 --- a/system/types/Android.bp +++ b/system/types/Android.bp @@ -14,8 +14,6 @@ cc_library_headers { export_include_dirs: ["./"], vendor_available: true, host_supported: true, - // TODO(b/153609531): remove when no longer needed. - native_bridge_supported: true, apex_available: [ "//apex_available:platform", "com.android.btservices", @@ -34,7 +32,7 @@ cc_library_headers { cc_library_static { name: "libbluetooth-types", vendor_available: true, - defaults: ["fluoride_types_defaults"], + defaults: ["fluoride_defaults"], cflags: [ /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/ "-fvisibility=default", @@ -58,10 +56,13 @@ cc_library_static { cc_test { name: "net_test_types", - static_libs: ["libchrome"], - test_suites: ["device-tests"], + static_libs: [ + "libbluetooth-types", + "libchrome", + "libosi", // strlcpy + ], + test_suites: ["general-tests"], defaults: [ - "bluetooth_gtest_x86_asan_workaround", "fluoride_defaults", "mts_defaults", ], @@ -72,7 +73,9 @@ cc_test { srcs: [ "test/ble_address_with_type_unittest.cc", "test/bluetooth/uuid_unittest.cc", + "test/bt_name_test.cc", "test/class_of_device_unittest.cc", "test/raw_address_unittest.cc", ], + shared_libs: ["liblog"], } diff --git a/system/types/bt_transport.h b/system/types/bt_transport.h index 98b313679da7adcf7b560392440e7c4c682e53c4..4bf4b7d6b44beaa2da3a141ebf6d69c4b2fd9911 100644 --- a/system/types/bt_transport.h +++ b/system/types/bt_transport.h @@ -20,15 +20,13 @@ #include +#include "macros.h" + #define BT_TRANSPORT_AUTO 0 #define BT_TRANSPORT_BR_EDR 1 #define BT_TRANSPORT_LE 2 typedef uint8_t tBT_TRANSPORT; -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code - inline std::string bt_transport_text(const tBT_TRANSPORT& transport) { switch (transport) { CASE_RETURN_TEXT(BT_TRANSPORT_AUTO); @@ -38,4 +36,3 @@ inline std::string bt_transport_text(const tBT_TRANSPORT& transport) { return base::StringPrintf("UNKNOWN[%hhu]", transport); } } -#undef CASE_RETURN_TEXT diff --git a/system/types/class_of_device.h b/system/types/class_of_device.h index b0fffc88532721f78f6d0a363d748eef1c67cfd3..7a2ec0301b853bf0ee3a2b1e625db37d8aa5344f 100644 --- a/system/types/class_of_device.h +++ b/system/types/class_of_device.h @@ -18,6 +18,7 @@ #pragma once +#include #include #include diff --git a/system/types/raw_address.h b/system/types/raw_address.h index d623b9f1ab500360710d5b5893b1fae8d8d94885..3a9b9c18c48d149c68e857761c29980024ea0781 100644 --- a/system/types/raw_address.h +++ b/system/types/raw_address.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include #include @@ -106,9 +107,3 @@ inline void STREAM_TO_BDADDR(RawAddress& a, const uint8_t*& p) { uint8_t* pbda = (uint8_t*)(a.address) + BD_ADDR_LEN - 1; for (int ijk = 0; ijk < BD_ADDR_LEN; ijk++) *pbda-- = *(p)++; } - -// DEPRECATED -inline void STREAM_TO_BDADDR(RawAddress& a, uint8_t*& p) { - uint8_t* pbda = (uint8_t*)(a.address) + BD_ADDR_LEN - 1; - for (int ijk = 0; ijk < BD_ADDR_LEN; ijk++) *pbda-- = *(p)++; -} diff --git a/system/osi/test/AlarmTestHarness.h b/system/types/remote_version_type.h similarity index 52% rename from system/osi/test/AlarmTestHarness.h rename to system/types/remote_version_type.h index 38be959d3516cf96e2281d9066cd34a8d82d76a9..f64aad8c18cf370fcc6d827a77aea23722455cd1 100644 --- a/system/osi/test/AlarmTestHarness.h +++ b/system/types/remote_version_type.h @@ -1,6 +1,6 @@ -/****************************************************************************** +/* * - * Copyright 2014 Google, Inc. + * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. * - ******************************************************************************/ + */ #pragma once -#include "AllocationTestHarness.h" +#include -extern int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS; +#include +#include -class AlarmTestHarness : public AllocationTestHarness { - protected: - virtual void SetUp(); - virtual void TearDown(); - - public: - // Returns true if a wake lock is held. - bool WakeLockHeld(); +struct tREMOTE_VERSION_INFO { + uint8_t lmp_version{0}; + uint16_t lmp_subversion{0}; + uint16_t manufacturer{0}; + bool valid{false}; + std::string ToString() const { + return (valid) ? base::StringPrintf("%02hhu-%05hu-%05hu", lmp_version, + lmp_subversion, manufacturer) + : std::string("UNKNOWN"); + } }; + +using remote_version_info = tREMOTE_VERSION_INFO; \ No newline at end of file diff --git a/system/types/test/bt_name_test.cc b/system/types/test/bt_name_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..eb22003b4552e4b80f6fa16b2bb15d72c3ff2b1b --- /dev/null +++ b/system/types/test/bt_name_test.cc @@ -0,0 +1,93 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stack/include/bt_name.h" + +#include + +TEST(BtNameTest, new_name) { + BD_NAME bd_name1 = {}; + bd_name_from_char_pointer(bd_name1, "ATestName"); + + BD_NAME bd_name2 = {}; + bd_name_from_char_pointer(bd_name2, "ATestName"); + + BD_NAME bd_name3 = {}; + bd_name_from_char_pointer(bd_name3, "ADifferentTestName"); + + ASSERT_TRUE(bd_name_is_equal(bd_name1, bd_name2)); + ASSERT_FALSE(bd_name_is_equal(bd_name1, bd_name3)); +} + +TEST(BtNameTest, new_name_nullptr) { + BD_NAME bd_name1 = {0}; + bd_name_from_char_pointer(bd_name1, nullptr); + ASSERT_TRUE(bd_name_is_empty(bd_name1)); + + BD_NAME bd_name2 = {}; + bd_name_from_char_pointer(bd_name2, "ARealTestName"); + bd_name_from_char_pointer(bd_name2, nullptr); + ASSERT_FALSE(bd_name_is_empty(bd_name2)); +} + +TEST(BtNameTest, clear) { + BD_NAME bd_name = {}; + bd_name_from_char_pointer(bd_name, "ATestName"); + + bd_name_clear(bd_name); + ASSERT_TRUE(bd_name_is_empty(bd_name)); +} + +TEST(BtNameTest, copy_name) { + BD_NAME bd_name1 = {}; + bd_name_from_char_pointer(bd_name1, "OldName"); + + BD_NAME bd_name2 = {}; + bd_name_from_char_pointer(bd_name2, "ATestName"); + + const size_t len = bd_name_copy(bd_name1, bd_name2); + + ASSERT_EQ(strlen(reinterpret_cast(bd_name2)), len); + ASSERT_TRUE(bd_name_is_equal(bd_name1, bd_name2)); +} + +TEST(BtNameTest, copy_name_max_chars) { + BD_NAME bd_name1 = {}; + std::string s(kBdNameLength, 'a'); + s.replace(kBdNameLength - 1, 1, std::string("b")); + bd_name_from_char_pointer(bd_name1, s.data()); + ASSERT_EQ('\0', bd_name1[kBdNameLength]); + + BD_NAME bd_name2 = {}; + + const size_t len = bd_name_copy(bd_name2, bd_name1); + ASSERT_EQ('\0', bd_name2[kBdNameLength]); + ASSERT_EQ('b', bd_name2[kBdNameLength - 1]); + + ASSERT_EQ(strlen(reinterpret_cast(bd_name1)), len); + ASSERT_EQ(kBdNameLength, len); + ASSERT_TRUE(bd_name_is_equal(bd_name1, bd_name2)); +} + +TEST(BtNameTest, too_many_characters) { + std::string s(kBdNameLength + 1, 'a'); + BD_NAME bd_name1 = {}; + bd_name_from_char_pointer(bd_name1, s.data()); + ASSERT_EQ('\0', bd_name1[kBdNameLength]); + + ASSERT_EQ(kBdNameLength + 1, s.length()); + ASSERT_EQ(kBdNameLength, strlen(reinterpret_cast(bd_name1))); +} diff --git a/system/udrv/Android.bp b/system/udrv/Android.bp index 8b0534f8f3ea65bee7290491e25505b2b3a5588a..2f89f4729659b288fc026979c7aa0e52803173db 100644 --- a/system/udrv/Android.bp +++ b/system/udrv/Android.bp @@ -28,4 +28,6 @@ cc_library_static { "com.android.btservices", ], min_sdk_version: "Tiramisu", + header_libs: ["libbluetooth_headers"], + static_libs: ["libbt_shim_bridge"], } diff --git a/system/udrv/ulinux/uipc.cc b/system/udrv/ulinux/uipc.cc index d52f9364322b111550796fc906531b874182d4c4..3a5edb4bd08fce82e4ec6b69049f41a38f8994d2 100644 --- a/system/udrv/ulinux/uipc.cc +++ b/system/udrv/ulinux/uipc.cc @@ -24,10 +24,8 @@ * *****************************************************************************/ -#include #include #include -#include #include #include #include @@ -38,17 +36,18 @@ #include #include #include + +#include #include -#include // Define before including log.h #define LOG_TAG "uipc" #include "audio_a2dp_hw/include/audio_a2dp_hw.h" -#include "osi/include/log.h" +#include "os/log.h" #include "osi/include/osi.h" #include "osi/include/socket_utils/sockets.h" -#include "uipc.h" +#include "udrv/include/uipc.h" /***************************************************************************** * Constants & Macros diff --git a/system/vendor_libs/linux/interface/Android.bp b/system/vendor_libs/linux/interface/Android.bp index 49f65dec1098e3c36b83f9d8eb0af12e56a0d5d5..a47a57dbd8d88249ab26a1112d852860de9abbcb 100644 --- a/system/vendor_libs/linux/interface/Android.bp +++ b/system/vendor_libs/linux/interface/Android.bp @@ -24,7 +24,7 @@ package { cc_binary { name: "android.hardware.bluetooth@1.1-service.btlinux", - defaults: ["fluoride_common_options"], + defaults: ["bluetooth_cflags"], proprietary: true, relative_install_path: "hw", srcs: [ @@ -46,15 +46,12 @@ cc_binary { static_libs: [ "async_fd_watcher", ], - conlyflags: [ - "-std=c99", - ], init_rc: ["android.hardware.bluetooth@1.1-service.btlinux.rc"], } cc_library_static { name: "async_fd_watcher", - defaults: ["fluoride_common_options"], + defaults: ["bluetooth_cflags"], proprietary: true, srcs: [ "async_fd_watcher.cc", diff --git a/system/vendor_libs/linux/interface/bluetooth_hci.cc b/system/vendor_libs/linux/interface/bluetooth_hci.cc index 7f4814ff6133d240dbedc11e27bffb79387dbf4f..a437b6cbeabe79fb2f3df2704b8f5a66c110a2a4 100644 --- a/system/vendor_libs/linux/interface/bluetooth_hci.cc +++ b/system/vendor_libs/linux/interface/bluetooth_hci.cc @@ -15,18 +15,17 @@ // #define LOG_TAG "android.hardware.bluetooth@1.1-btlinux" -#include +#include "bluetooth_hci.h" + #include #include #include #include #include - #include - #include -#include "bluetooth_hci.h" +#include #define BTPROTO_HCI 1 diff --git a/system/vnd/ble/vendor_hcidefs.h b/system/vnd/ble/vendor_hcidefs.h deleted file mode 100644 index b6782afab693ca11d692d5434d8412e555097da0..0000000000000000000000000000000000000000 --- a/system/vnd/ble/vendor_hcidefs.h +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************************************************** - * - * Copyright 2003-2014 Broadcom Corporation - * - * 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. - * - ******************************************************************************/ - -/***************************************************************************** - * - * Name vendor_hcidefs.h - * - * Function This file contains Broadcom Specific Host Controller Interface - * definitions. - * - *****************************************************************************/ - -#ifndef VENDOR_HCIDEFS_H -#define VENDOR_HCIDEFS_H - -/***************************************************************************** - * Private address resolution VSC - *****************************************************************************/ - -/* VSC */ -#define HCI_VENDOR_BLE_RPA_VSC (0x0155 | HCI_GRP_VENDOR_SPECIFIC) - -/* Sub codes */ -#define HCI_VENDOR_BLE_RPA_ENABLE 0x01 -#define HCI_VENDOR_BLE_RPA_ADD_IRK 0x02 -#define HCI_VENDOR_BLE_RPA_REMOVE_IRK 0x03 -#define HCI_VENDOR_BLE_RPA_CLEAR_IRK 0x04 -#define HCI_VENDOR_BLE_RPA_READ_IRK 0x05 - -/***************************************************************************** - * Advertising data payload filter VSC - *****************************************************************************/ - -/* VSC */ -#define HCI_VENDOR_BLE_PCF_VSC (0x0157 | HCI_GRP_VENDOR_SPECIFIC) - -#endif diff --git a/system/vnd/include/vendor_api.h b/system/vnd/include/vendor_api.h deleted file mode 100644 index be10778c1bd15575b20826cf51944ff59ed5d4a6..0000000000000000000000000000000000000000 --- a/system/vnd/include/vendor_api.h +++ /dev/null @@ -1,22 +0,0 @@ -/**************************************************************************** - * - * Name: vendor_api.h - * - * Description: Vendor specific BTE API function external definitions. - * - * Copyright (c) 2009-2011, BROADCOM Inc., All Rights Reserved. - * Broadcom Bluetooth Core. Proprietary and confidential. - * - *****************************************************************************/ -#ifndef VENDOR_API_H -#define VENDOR_API_H - -#include "btm_api.h" - -/**************************************************************************** - * Resolvable private address offload VSC specific definitions - *****************************************************************************/ - -enum { BTM_BLE_PRIVACY_ENABLE, BTM_BLE_PRIVACY_DISABLE }; - -#endif diff --git a/tools/OWNERS b/tools/OWNERS index e950f0b0db2a29896595c85d33ac07e707fcd326..1979131142218e88d0931086e6af898a398e8843 100644 --- a/tools/OWNERS +++ b/tools/OWNERS @@ -1,11 +1,8 @@ # Reviewers for /tools cmanton@google.com -cncn@google.com jpawlowski@google.com +licorne@google.com mylesgw@google.com -optedoblivion@google.com -qasimj@google.com -rahulsabnis@google.com sattiraju@google.com siyuanh@google.com diff --git a/tools/bt-api-plumber/bt-api-plumber-9000.sh b/tools/bt-api-plumber/bt-api-plumber-9000.sh deleted file mode 100755 index f1b56b1a2c35a52550ad0883ec3a40674aff6975..0000000000000000000000000000000000000000 --- a/tools/bt-api-plumber/bt-api-plumber-9000.sh +++ /dev/null @@ -1,559 +0,0 @@ -#!/bin/bash - -YELLOW="\033[1;33m" -NOCOLOR="\033[0m" -BLUE="\033[1;34m" -RED="\033[1;91m" - -# TODO(optedoblivion): Check for 'git' and 'clang' binary - -function check_environment { - if [[ -z "${ANDROID_BUILD_TOP}" ]] || [[ -z "${ANDROID_HOST_OUT}" ]] ; then - echo -e "${RED}ANDROID_BUILD_TOP${NOCOLOR} or ${RED}ANDROID_HOST_OUT${NOCOLOR} is not set for host run" - echo -e "Navigate to android root and run:" - echo -e "${YELLOW}" - echo -e ". build/envsetup.sh" - echo -e "lunch " - echo -e "${NOCOLOR}" - echo - exit 1 - fi -} - -QUOTES=( - "It's a-me, Martino!" - "Hello!" - "Wahoo!" - "Oh yeah!" - "Martino time!" - "Lucky!" - "Hui hew! Just what I needed!" - "Spin! Hammer! Fire! Jump!" - "Yiiiiiipeee!" - "Yeah, ha ha ha!" - "Waha!" - "Let's-a go!" - "Here we go!" - "Yes! I'm the winner!" - "Luigi!" - "Way to go!" - "Here I go!" - "Mama Mia!" -) - -VERBOSE=false - -# Controller -CONTROLLER=false -CONTROLLER_FILES=( - "system/gd/hci/controller.h" - "system/gd/hci/controller.cc" - "system/gd/hci/controller.cc" - "system/gd/hci/controller_mock.h" - "system/gd/hci/controller_test.cc" -) -CONTROLLER_FIND_PATTERNS=( - " LeRand(LeRandCallback cb);" - "Controller::impl::le_rand_cb, cb));" - "impl::le_rand, cb);" - " (LeRandCallback cb));" - " le_rand_set.get_future().wait();" -) -CONTROLLER_CODE_TEMPLATES=( - " virtual void :CamelApiName:();" - " }\\\n\\\n void :snake_api_name:() {\\\n \\\\\/\\\\\/TODO(WHOAMI): Implement HCI Call" - "}\\\n\\\nvoid Controller:::CamelApiName:() {\\\n CallOn(impl_.get(), \\\\\&impl:::snake_api_name:);" - " MOCK_METHOD(void, :CamelApiName:, ());" - "}\\\n\\\nTEST_F(ControllerTest, :CamelApiName:Test) {\\\n controller->:CamelApiName:();" -) -CONTROLLER_REPLACEMENT_PATTERNS=( - "FIRST\n\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" -) - -# Controller shim -CONTROLLER_SHIM=false -CONTROLLER_SHIM_FILES=( - "system/device/include/controller.h" - "system/main/shim/controller.cc" - "system/main/shim/controller.cc" - "system/test/mock/mock_device_controller.cc" - "system/test/mock/mock_device_controller.cc" -) -CONTROLLER_SHIM_FIND_PATTERNS=( - " (\*le_rand)(LeRandCallback);" - " bluetooth::shim::GetController()->LeRand(cb);" - " controller_le_rand," - " le_rand(LeRandCallback cb) { return BTM_SUCCESS; }" - " le_rand," -) -CONTROLLER_SHIM_CODE_TEMPLATES=( - " uint8_t (*:snake_api_name:)(void);" - " return BTM_SUCCESS;\\\n}\\\n\\\nstatic uint8_t controller_:snake_api_name:() {\\\n bluetooth::shim::GetController()->:CamelApiName:();" - " .:snake_api_name: = controller_:snake_api_name:" - "tBTM_STATUS :snake_api_name:() { return BTM_SUCCESS; }" - " :snake_api_name:," -) -CONTROLLER_SHIM_REPLACEMENT_PATTERNS=( - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" -) - -## Files length must match templates and replacement pattern lengths! -# BTM -BTM_SHIM=false -BTM_SHIM_FILES=( - "system/main/shim/btm_api.h" - "system/main/shim/btm_api.cc" - "system/test/mock/mock_main_shim_btm_api.cc" -) -BTM_SHIM_FIND_PATTERNS=( - "TM_STATUS BTM_LeRand(LeRandCallback);" - "ontroller_get_interface()->le_rand(cb);" - " bluetooth::shim::BTM_LeRand(LeRandCallback cb) {" -) -BTM_SHIM_CODE_TEMPLATES=( - "\\\\\/*******************************************************************************\\\n *\\\n * Function BTM_:CamelApiName:\\\n *\\\n * Description :API_DESCRIPTION:\\\n *\\\n * Parameters\\\n *\\\n *******************************************************************************\\\\\/\\\ntBTM_STATUS BTM_:CamelApiName:(void);" - " return BTM_SUCCESS;\\\n}\\\n\\\ntBTM_STATUS bluetooth::shim::BTM_:CamelApiName:() {\\\n \\\\\/\\\\\/PLUMB: controller_get_interface()->:snake_api_name:();" - " inc_func_call_count(__func__);\\\n return BTM_SUCCESS;\\\n}\\\n\\\ntBTM_STATUS bluetooth::shim::BTM_:CamelApiName:() {" -) -BTM_SHIM_REPLACEMENT_PATTERNS=( - "FIRST\n\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" -) - -# BTA -BTA=false -BTA_FILES=( - # External BTA API - "system/bta/include/bta_api.h" - "system/bta/dm/bta_dm_api.cc" - # internal BTA API - "system/bta/dm/bta_dm_int.h" - "system/bta/dm/bta_dm_act.cc" -) -BTA_FIND_PATTERNS=( - "extern void BTA_DmLeRand(LeRandCallback cb);" - "do_in_main_thread(FROM_HERE, base::Bind(bta_dm_le_rand, cb));" - "extern void bta_dm_le_rand(LeRandCallback cb);" - "ooth::shim::BTM_LeRand(cb);" -) -BTA_CODE_TEMPLATES=( - "\\\\\/*******************************************************************************\\\n *\\\n * Function BTA_Dm:CamelApiName:\\\n *\\\n * Description :API_DESCRIPTION:\\\n *\\\n * Parameters\\\n *\\\n *******************************************************************************\\\\\/\\\nextern void BTA_Dm:CamelApiName:();" - "}\\\n\\\nvoid BTA_Dm:CamelApiName:() {\\\n APPL_TRACE_API(\"BTA_Dm:CamelApiName:\");\\\n do_in_main_thread(FROM_HERE, base::Bind(bta_dm_:snake_api_name:));" - "extern void bta_dm_:snake_api_name:();" - "}\\\n\\\n\\\\\/*******************************************************************************\\\n *\\\n * Function BTA_Dm:CamelApiName:\\\n *\\\n * Description :API_DESCRIPTION:\\\n *\\\n * Parameters\\\n *\\\n *******************************************************************************\\\\\/\\\nvoid bta_dm_:snake_api_name:() {\\\n \\\\\/\\\\\/PLUMB: bluetooth::shim::BTM_:CamelApiName:();" -) -BTA_REPLACEMENT_PATTERNS=( - "FIRST\n\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" -) - -# BTIF -BTIF=false -BTIF_FILES=( - # BTIF DM Layer - "system/btif/include/btif_dm.h" - "system/btif/src/btif_dm.cc" - # BTIF Layer - "system/include/hardware/bluetooth.h" - "system/btif/src/bluetooth.cc" - "system/btif/src/bluetooth.cc" - "system/service/hal/fake_bluetooth_interface.cc" - # Yes double it for two replacements - "system/test/mock/mock_bluetooth_interface.cc" - "system/test/mock/mock_bluetooth_interface.cc" -) -BTIF_FIND_PATTERNS=( - # BTIF DM Layer - "oid btif_dm_le_rand(LeRandCallback callback);" - "_dm_le_rand(callback);" - # BTIF Layer - "} bt_interface_t;" - " void dump(" - " le_rand," - " le_rand " - "EXPORT_SYMBOL" - " le_rand," -) -BTIF_CODE_TEMPLATES=( - # BTIF DM Layer - " void btif_dm_:snake_api_name:();" - "}\\\n\\\nvoid btif_dm_:snake_api_name:() {\\\n \\\\\/\\\\\/PLUMB: BTA_Dm:CamelApiName:();" - # BTIF Layer - " \\\n\\\\\/**\\\n *\\\n * :API_DESCRIPTION:\\\n *\\\n *\\\\\/\\\nint (*:snake_api_name:)();" - " int :snake_api_name:() {\\\n if(!interface_ready()) return BT_STATUS_NOT_READY;\\\n do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_:snake_api_name:));\\\n return BT_STATUS_SUCCESS;\\\n}\\\n\\\nstatic" - "\ \ \ \ :snake_api_name:," - "*\\\\\/\\\n\ \ \ \ nullptr, \\\\\/* :snake_api_name: " - "static int :snake_api_name:() { return 0; }\\\n\\\nE" - "\ \ \ \ :snake_api_name:," -) -BTIF_REPLACEMENT_PATTERNS=( - # BTIF DM Layer - "FIRST\nSECOND" - "FIRST\nSECOND" - # BTIF Layer - "SECOND\nFIRST" - "SECONDFIRST" - "FIRST\nSECOND" - "FIRSTSECOND" - "SECONDFIRST" - "FIRST\nSECOND" -) - -# Topshim -TOPSHIM=false -TOPSHIM_FILES=( - # Topshim API - "system/gd/rust/topshim/src/btif.rs" - "system/gd/rust/topshim/facade/src/adapter_service.rs" - # Topshim Test API - "system/blueberry/facade/topshim/facade.proto" - "system/blueberry/tests/gd/rust/topshim/facade/automation_helper.py" -) -TOPSHIM_FIND_PATTERNS=( - # Topshim API - " le_rand)" - ".le_rand();" - # Topshim Test API - " LeRand(google.protobuf.Empty) returns (google.protobuf.Empty) {}" - " self.adapter_stub.LeRand(empty_proto.Empty())" -) -TOPSHIM_CODE_TEMPLATES=( - # Topshim API - " }\\\n\\\n pub fn :snake_api_name:(\\\\\&self) -> i32 {\\\n ccall!(self, :snake_api_name:)" - " ctx.spawn(async move {\\\n sink.success(Empty::default()).await.unwrap();\\\n })\\\n }\\\n\\\n fn :snake_api_name:(\\\\\&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink) {\\\n self.btif_intf.lock().unwrap().:snake_api_name:();" - # Topshim Test API - " rpc :CamelApiName:(google.protobuf.Empty) returns (google.protobuf.Empty) {}" - " async def :snake_api_name:(self):\\\n await self.adapter_stub.:CamelApiName:(empty_proto.Empty())" -) -TOPSHIM_REPLACEMENT_PATTERNS=( - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\nSECOND" - "FIRST\n\nSECOND" -) - -function help_menu { - echo - echo -e "${YELLOW}Help menu${NOCOLOR}" - echo -e "===================================" - echo -e "${BLUE} --controller${NOCOLOR}" - echo -e " Adds plumbing for the GD Controller Layer for the API." - echo -e " This includes test file changes required to build." - echo -e "${BLUE} --controller-shim${NOCOLOR}" - echo -e " Adds plumbing for the GD Controller Shim Layer for the API." - echo -e " This includes test file changes required to build." - echo -e " Will autoplumb to ONLY the GD controller if --controller flag is set. (as opposed to legacy controller btu_hcif)" - echo -e "${BLUE} --btm${NOCOLOR}" - echo -e " Adds plumbing for the BTM Shim Layer for the given API." - echo -e " Will autoplumb to ONLY the controller shim if --controller-shim flag is set. vs directly to legacy btu_hcif" - echo -e "${BLUE} --bta${NOCOLOR}" - echo -e " Adds plumbing for the BTA Layer for the given API." - echo -e " Will autoplumb to BTM if --btm set." - echo -e "${BLUE} --btif${NOCOLOR}" - echo -e " Adds plumbing for the BTIF Layer for the API." - echo -e " This currently includes JNI as it is a requirement for Android to build." - echo -e " Will autoplumb to BTA if --bta set." - echo -e "${BLUE} --topshim${NOCOLOR}" - echo -e " Adds plumbing for the topshim to BTIF Layer for the API." - echo -e " This will also include testing APIs callable from python tests." - echo -e " Will autoplumb to BTIF if --btif set." - echo -e "${BLUE} --verbose${NOCOLOR}" - echo -e " Prints verbose logging." - echo - echo -e "Usage: $0 [--controller|--controller-shim|--btm|--bta|--btif|--topshim] [CamelCaseApiName] [snake_case_api_name] (description)" - echo -e " ${YELLOW}e.g." - echo -e " $0 --controller --btm ClearEventMask clear_event_mask \"Clear out the event mask\"" - echo -e " $0 --controller --btm --bta --btif --topshim ClearEventMaskclear_event_mask \"Clear out the event mask\" ${NOCOLOR}" - echo -} - -## Start parsing arguments here -POSITIONAL=() -function parse_options { - while [[ $# -gt 0 ]] - do - key="$1" - case $key in - --verbose) - VERBOSE=true - shift - ;; - --help) - help_menu - shift - exit 0 - ;; - --controller) - CONTROLLER=true - shift - ;; - --controller-shim) - CONTROLLER_SHIM=true - shift - ;; - --btm) - # Actually we skip BTM here and just use the BTM Shim - BTM_SHIM=true - shift - ;; - --bta) - BTA=true - shift - ;; - --btif) - BTIF=true - shift - ;; - --topshim) - TOPSHIM=true - shift - ;; - --*) - echo "$0: unrecognized argument: '$1'" - echo "Try '$0 --help' for more information" - exit 1 - shift - ;; - *) - POSITIONAL+=("${1}") - shift - ;; - esac - done - set -- "${POSITIONAL[@]}" -} - -function show_mario { - MSG="$(mario_message)I'm plumbing the '${1}'" - echo - echo -e "${RED} ⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ "â € - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⡾⣻⣿⣿⣿⣿⣯â£â ›â »â¢·â£¦â£€â €â €â €â €â €â €â € " - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⠟â¢â£¾â Ÿâ ‹â£â£€â£¤â¡‰â »â£·â¡€â €â ™â¢¿â£·â£„⠀⠀⠀⠀⠀ "â € - echo -e "${NOCOLOR}⠀⠀⠀⠀⠀⠀⠀⢀⡀${RED}⠀⠀⠀⠀⠀⠀⣰⣿â â €â €â¢¸â£¿â €â ¼â¢‹â£‰â£ˆâ¡³â¢€â£¿â ƒâ €â €â €â ™â£¿â£¦â¡€â €â €â € "â € - echo -e "${NOCOLOR}⠀⠀⠀⠀⠀⠀⢰⡿⠿⣷⡀⠀${RED}⠀⠀⣼⣿⠃⠀⠀⣀⣤⡿⠟⠛⠋⠉⠉⠙⢛⣻⠶⣦⣄⡀⠀⠘⣿⣷⡀⠀⠀ "â € - echo -e "${NOCOLOR}⢠⣾⠟⠳⣦⣄⢸⡇⠀⠈⣷⡀${RED}⠀⣼⣿â¡â¢€â£¤â¡¾${NOCOLOR}⢋⣵⠿⠻⢿⠋⠉⠉⢻⠟⠛⠻⣦â£${RED}⠻⣷⣄⠸⣿⣿${NOCOLOR}⠀⠀ ( ${MSG} )"â € - echo -e "⠘⣧⠀⠀⠀⠙⢿⣿⠀⠀⢸⣷${RED}⠀⣿⣿⣧⣾â£${NOCOLOR}⡴⠛⢡⠖⢛⣲⣅⠀⠀⣴⣋⡉⠳⡄⠈⠳${RED}⢬⣿⣿⣿⡿${NOCOLOR}⠀⠀ O"â € - echo -e "⠀⠘⠷⣤⣀⣀⣀⣽⡶⠛⠛⠛⢷⣿⣿⣿⣿â£â €â €â¡â¢°â¡¿â¢¿â£¿â €â €â£¿â »â£¿â €â¡·â €â£ â£¾â£¿â¡¿â ›â ·â£¦â € o"â € - echo -e "⠀⠀⢀⣾⠟⠉⠙⣿⣤⣄⠀⢀⣾⠉⠀⢹⣿⣿⣷⠀⠹⡘⣷⠾⠛⠋⠉⠛⠻⢿⡴⢃⣄⣻⣿⣿⣷⠀⠀⢹⡇ ."â € - echo -e "⠀⠀⢸⡇⠈⠉⠛⢦⣿â¡â €â¢¸â£§â €â ˆâ »â£¿â¡¿â¢£â£¾â£¦â£½â ƒâ €â €â €â €â €â €â €â£·â£¾â£¿â¡‡â ‰â¢¿â¡‡â €â¢€â£¼â ‡ "â € - echo -e "⠀⠀⠘⣷⡠⣄⣀⣼⠇⠀⠀⠀⠻⣷⣤⣀⣸⡇⠀⠹⣿⣿⣦⣀⠀⠀⠀⠀⢀⣴⣿⣿⡟⠀⠀⢸⣷⣾⡿⠃⠀ "â € - echo -e "⠀⠀⠀⠈⠻⢦â£â£€â£€â£€â¡„⠀⣰⣿⡿⠿⢿⣇⠀⠀⠉⠛⠻⣿⣿⡷⠾⣿⣿⡿⠉â â €â €â¢€â£¾â ‹â â €â €â € " - echo -e "⠀⠀⠀⠀⠀⠀⠈⠉⠉⠙⠿⢿⣿⣇⠀⠀⠈⢿⣧⣄⠀⠀⠀⢹⣷⣶⣶⣾⣿⡇⠀⠀⣀⣴⡿⣧⣄⡀⠀⠀⠀ "â € - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣷⡀⠀⠀⠙⢿⣿⣶⣤⡀⠻⢤⣀⡤⠞⢀⣴⣿⣿⠟⢷⡀⠙⠻⣦⣄⠀ "â € - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣦⠀⢠⡟â â ™â¢»â£¿â ·â ¶â£¶â ¶â ¾â ›â ™â£¿â ‡â €â €â¢»â¡„⠀⠀⠙⢷⡀ " - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⡀⣿â â£¤â£¤â¡„⢻⡶⠶⠛⠛⠛⠛⠛⣿⢠⣾⣷⣆⢻⡀⠀⠀⠈⣷ " - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⢸⣿⣿⣿⡈⢿⡀⠀⠀⠀⠀⠀⡿⢸⣿⣿⣿⢸⡇⠀⠀⠀⡟ " - echo -e "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠈⠉⠉⠉â â ˆâ â €â €â €â €â ˆâ â ˆâ ‰â ‰â ‰â €â â €â €â ˆâ  " - echo -} - -function mario_done { - echo -e "${YELLOW}Done.${NOCOLOR}" -} - -function mario_message { - I=$((0 + $RANDOM % ${#QUOTES[@]})) - echo -en "${BLUE}${QUOTES[$I]}! ${BLUE}${2}${YELLOW}${1} ${NOCOLOR}" -} - -# TODO: Pass in which patterns and templates to use -function plumbit { - layer="$1" - shift - camel_api_name="$1" - shift - snake_api_name="$1" - shift - api_description="$1" - shift - files_array=($@) - - WORKING_CODE_TEMPLATES=() - WORKING_PATTERNS=() - AUTOPLUMB=false - if [ "$layer" == "controller" ]; then - WORKING_PATTERNS=("${CONTROLLER_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${CONTROLLER_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${CONTROLLER_REPLACEMENT_PATTERNS[@]}") - elif [ "$layer" == "controller_shim" ]; then - WORKING_PATTERNS=("${CONTROLLER_SHIM_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${CONTROLLER_SHIM_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${CONTROLLER_SHIM_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$CONTROLLER - elif [ "$layer" == "btm_shim" ]; then - WORKING_PATTERNS=("${BTM_SHIM_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${BTM_SHIM_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${BTM_SHIM_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$CONTROLLER_SHIM - elif [ "$layer" == "bta" ]; then - WORKING_PATTERNS=("${BTA_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${BTA_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${BTA_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$BTM_SHIM - elif [ "$layer" == "btif" ]; then - WORKING_PATTERNS=("${BTIF_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${BTIF_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${BTIF_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$BTA - elif [ "$layer" == "topshim" ]; then - WORKING_PATTERNS=("${TOPSHIM_FIND_PATTERNS[@]}") - WORKING_CODE_TEMPLATES=("${TOPSHIM_CODE_TEMPLATES[@]}") - WORKING_REPLACEMENTS=("${TOPSHIM_REPLACEMENT_PATTERNS[@]}") - AUTOPLUMB=$BTIF - fi - - for index in ${!files_array[@]}; do - CODE=$(echo "${WORKING_CODE_TEMPLATES[$index]}" | sed "s/:CamelApiName:/$camel_api_name/g" | sed "s/:snake_api_name:/$snake_api_name/g" | sed "s/WHOAMI/$(whoami)/g" | sed "s/:API_DESCRIPTION:/${api_description}/g") - if [ "$AUTOPLUMB" == true ]; then - CODE=$(echo "${CODE}" | sed "s/PLUMB:/ Autoplumbed\\\\\\\n /g") - fi - PATTERN="${WORKING_PATTERNS[$index]}" - REPLACEMENT=$(echo ${WORKING_REPLACEMENTS[$index]} | sed s/FIRST/"\\${PATTERN}"/g | sed s/SECOND/"${CODE}"/g) - if [ "$VERBOSE" == true ]; then - echo sed -i "s/\\${PATTERN}/\\${REPLACEMENT}/g" "${files_array[$index]}" - fi - sed -i "s/\\${PATTERN}/\\${REPLACEMENT}/g" "${files_array[$index]}" - done -} - -CL_COUNT=0 - -function commitit { - mario_message "${1}" "Committing the code..." - git commit -qam "${2} ${1} API" - mario_done - let CL_COUNT=$CL_COUNT+1 -} - -function clangit { - FORMATTER="${ANDROID_BUILD_TOP}/tools/repohooks/tools/clang-format.py" - FIX="--fix" - CLANG_FORMAT="--clang-format ${ANDROID_BUILD_TOP}/prebuilts/clang/host/linux-x86/clang-stable/bin/clang-format" - GIT_CLANG_FORMAT="--git-clang-format ${ANDROID_BUILD_TOP}/prebuilts/clang/host/linux-x86/clang-stable/bin/git-clang-format" - COMMIT="--commit" - STYLE="--style file" - EXTENSIONS="--extensions c,h,cc,cpp,hpp" - HASH="$1" - CMD="${FORMATTER} ${FIX} ${CLANG_FORMAT} ${GIT_CLANG_FORMAT} ${COMMIT} ${HASH} ${STYLE} ${EXTENSIONS}" - $(${CMD}) -} - -function rustfmtit { - echo "rusty rust" -# FORMATTER="${ANDROID_BUILD_TOP}/prebuilts/rust/linux-x86/stable/rustfmt" -# CONFIG="'--config-path=rustfmt.toml'" -# FILE="" -# CMD="${FORMATTER} ${CONFIG} ${FILE}" -# $(${CMD}) -} - - -function formatit { - mario_message "${1}" "Formatting the code..." - hash="$(git log -n 1 --pretty=oneline | awk '{ print $1 }')" - clangit $hash - rustfmtit $hash - git commit -a --amend --no-edit - mario_done -} - -function controller { - if [ "$CONTROLLER" == false ]; then - return - fi - mario_message "Controller" "Plumbing the '${1}' API..." - plumbit "controller" "${1}" "${2}" "${3}" "${CONTROLLER_FILES[@]}" - mario_done - commitit "Controller" "${3}" - formatit "Controller" -} - -function controller_shim { - if [ "$CONTROLLER_SHIM" == false ]; then - return - fi - mario_message "Controller shim" "Plumbing the '${1}' API..." - plumbit "controller_shim" "${1}" "${2}" "${3}" "${CONTROLLER_SHIM_FILES[@]}" - mario_done - commitit "Controller shim" "${3}" - formatit "Controller shim" -} - -function btm_shim { - if [ "$BTM_SHIM" == false ]; then - return - fi - mario_message "BTM" "Plumbing the '${1}' API..." - plumbit "btm_shim" "${1}" "${2}" "${3}" "${BTM_SHIM_FILES[@]}" - mario_done - commitit "BTM" "${3}" - formatit "BTM" -} - -function bta { - if [ "$BTA" == false ]; then - return - fi - mario_message "BTA" "Plumbing the '${1}' API..." - plumbit "bta" "${1}" "${2}" "${3}" "${BTA_FILES[@]}" - mario_done - commitit "BTA" "${3}" - formatit "BTA" -} - -function btif { - if [ "$BTIF" == false ]; then - return - fi - mario_message "BTIF" "Plumbing the '${1}' API..." - plumbit "btif" "${1}" "${2}" "${3}" "${BTIF_FILES[@]}" - mario_done - commitit "BTIF" "${3}" - formatit "BTIF" -} - -function topshim { - if [ "$TOPSHIM" == false ]; then - return - fi - mario_message "Topshim" "Plumbing the '${1}' API..." - plumbit "topshim" "${1}" "${2}" "${3}" "${TOPSHIM_FILES[@]}" - mario_done - commitit "Topshim" "${3}" - formatit "Topshim" -} - -function main { - check_environment - parse_options $@ - if [ "${#POSITIONAL[@]}" -lt 3 ]; then - echo -e "${RED}Error: Invalid argument count for API Names!${NOCOLOR}" - help_menu - exit 1 - fi - camel_api_name="${POSITIONAL[0]}" - snake_api_name="${POSITIONAL[1]}" - api_description="${POSITIONAL[@]:2}" - show_mario "${camel_api_name} API that ${api_description}!" - controller "${camel_api_name}" "${snake_api_name}" "${api_description}" - controller_shim "${camel_api_name}" "${snake_api_name}" "${api_description}" - btm_shim "${camel_api_name}" "${snake_api_name}" "${api_description}" - bta "${camel_api_name}" "${snake_api_name}" "${api_description}" - btif "${camel_api_name}" "${snake_api_name}" "${api_description}" - topshim "${camel_api_name}" "${snake_api_name}" "${api_description}" - git rebase -i HEAD~${CL_COUNT} -x 'git commit --amend' -} - -main $@ -#/usr/local/google/home/optedoblivion/workspace/AOSP/prebuilts/rust/linux-x86/stable/rustfmt '--config-path=rustfmt.toml' system/gd/rust/topshim/facade/src/adapter_service.rs diff --git a/tools/pdl/Android.bp b/tools/pdl/Android.bp deleted file mode 100644 index 3deba58a145ed198d415c9c122401d4f60cc3668..0000000000000000000000000000000000000000 --- a/tools/pdl/Android.bp +++ /dev/null @@ -1,552 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "system_bt_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["system_bt_license"], -} - -rust_defaults { - name: "pdl_defaults", - // LINT.IfChange - rustlibs: [ - "libargh", - "libcodespan_reporting", - "libheck", - "libpest", - "libproc_macro2", - "libquote", - "libserde", - "libserde_json", - "libsyn", - "libtempfile", - ], - proc_macros: [ - "libpest_derive", - ], - // LINT.ThenChange(Cargo.toml) -} - -rust_binary_host { - name: "pdl", - defaults: ["pdl_defaults"], - srcs: ["src/main.rs"], - visibility: [ - "//external/uwb/src", - "//packages/modules/Bluetooth:__subpackages__", - ], -} - -filegroup { - name: "pdl_generated_files", - srcs: [ - "tests/generated/enum_declaration_big_endian.rs", - "tests/generated/enum_declaration_little_endian.rs", - "tests/generated/packet_decl_8bit_enum_array_big_endian.rs", - "tests/generated/packet_decl_8bit_enum_array_little_endian.rs", - "tests/generated/packet_decl_8bit_enum_big_endian.rs", - "tests/generated/packet_decl_8bit_enum_little_endian.rs", - "tests/generated/packet_decl_8bit_scalar_array_big_endian.rs", - "tests/generated/packet_decl_8bit_scalar_array_little_endian.rs", - "tests/generated/packet_decl_8bit_scalar_big_endian.rs", - "tests/generated/packet_decl_8bit_scalar_little_endian.rs", - "tests/generated/packet_decl_24bit_enum_array_big_endian.rs", - "tests/generated/packet_decl_24bit_enum_array_little_endian.rs", - "tests/generated/packet_decl_24bit_enum_big_endian.rs", - "tests/generated/packet_decl_24bit_enum_little_endian.rs", - "tests/generated/packet_decl_24bit_scalar_array_big_endian.rs", - "tests/generated/packet_decl_24bit_scalar_array_little_endian.rs", - "tests/generated/packet_decl_24bit_scalar_big_endian.rs", - "tests/generated/packet_decl_24bit_scalar_little_endian.rs", - "tests/generated/packet_decl_64bit_enum_array_big_endian.rs", - "tests/generated/packet_decl_64bit_enum_array_little_endian.rs", - "tests/generated/packet_decl_64bit_enum_big_endian.rs", - "tests/generated/packet_decl_64bit_enum_little_endian.rs", - "tests/generated/packet_decl_64bit_scalar_array_big_endian.rs", - "tests/generated/packet_decl_64bit_scalar_array_little_endian.rs", - "tests/generated/packet_decl_64bit_scalar_big_endian.rs", - "tests/generated/packet_decl_64bit_scalar_little_endian.rs", - "tests/generated/packet_decl_array_dynamic_count_big_endian.rs", - "tests/generated/packet_decl_array_dynamic_count_little_endian.rs", - "tests/generated/packet_decl_array_dynamic_size_big_endian.rs", - "tests/generated/packet_decl_array_dynamic_size_little_endian.rs", - "tests/generated/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs", - "tests/generated/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs", - "tests/generated/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs", - "tests/generated/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs", - "tests/generated/packet_decl_child_packets_big_endian.rs", - "tests/generated/packet_decl_child_packets_little_endian.rs", - "tests/generated/packet_decl_complex_scalars_big_endian.rs", - "tests/generated/packet_decl_complex_scalars_little_endian.rs", - "tests/generated/packet_decl_empty_big_endian.rs", - "tests/generated/packet_decl_empty_little_endian.rs", - "tests/generated/packet_decl_fixed_enum_field_big_endian.rs", - "tests/generated/packet_decl_fixed_enum_field_little_endian.rs", - "tests/generated/packet_decl_fixed_scalar_field_big_endian.rs", - "tests/generated/packet_decl_fixed_scalar_field_little_endian.rs", - "tests/generated/packet_decl_grand_children_big_endian.rs", - "tests/generated/packet_decl_grand_children_little_endian.rs", - "tests/generated/packet_decl_mask_scalar_value_big_endian.rs", - "tests/generated/packet_decl_mask_scalar_value_little_endian.rs", - "tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs", - "tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs", - "tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs", - "tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs", - "tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs", - "tests/generated/packet_decl_payload_field_unknown_size_terminal_little_endian.rs", - "tests/generated/packet_decl_payload_field_variable_size_big_endian.rs", - "tests/generated/packet_decl_payload_field_variable_size_little_endian.rs", - "tests/generated/packet_decl_reserved_field_big_endian.rs", - "tests/generated/packet_decl_reserved_field_little_endian.rs", - "tests/generated/packet_decl_simple_scalars_big_endian.rs", - "tests/generated/packet_decl_simple_scalars_little_endian.rs", - "tests/generated/preamble.rs", - "tests/generated/struct_decl_complex_scalars_big_endian.rs", - "tests/generated/struct_decl_complex_scalars_little_endian.rs", - ], -} - -rust_test_host { - name: "pdl_tests", - defaults: ["pdl_defaults"], - srcs: ["src/main.rs"], - proc_macros: [ - "libpaste", - ], - test_suites: ["general-tests"], - enabled: false, // rustfmt is only available on x86. - arch: { - x86_64: { - enabled: true, - }, - }, - data: [ - ":rustfmt", - ":rustfmt.toml", - ":pdl_generated_files", - ], -} - -genrule { - name: "pdl_generated_files_compile_rs", - cmd: "$(location tests/generated_files_compile.sh) $(in) > $(out)", - srcs: [":pdl_generated_files"], - out: ["generated_files_compile.rs"], - tool_files: ["tests/generated_files_compile.sh"], -} - -rust_test_host { - name: "pdl_generated_files_compile", - srcs: [":pdl_generated_files_compile_rs"], - test_suites: ["general-tests"], - clippy_lints: "none", - lints: "none", - defaults: ["pdl_backend_defaults"], -} - -genrule_defaults { - name: "pdl_rust_generator_defaults", - cmd: "set -o pipefail;" + - " $(location :pdl) --output-format rust $(in) |" + - " $(location :rustfmt) > $(out)", - tools: [ - ":pdl", - ":rustfmt", - ], - defaults_visibility: [ - "//external/uwb/src", - "//packages/modules/Bluetooth:__subpackages__", - ], -} - -// The generators support more features for LE packets than for BE -// packets. We use a single input written for LE packets and remove -// the parts that don't work for BE packets. We do this by removing -// everything between -// -// // Start: little_endian_only -// -// and -// -// // End: little_endian_only -// -// from the LE packet input. -genrule_defaults { - name: "pdl_be_test_file_defaults", - cmd: "sed -e 's/little_endian_packets/big_endian_packets/' " + - " -e '/Start: little_endian_only/,/End: little_endian_only/d' " + - " < $(in) > $(out)", -} - -genrule { - name: "pdl_be_rust_test_file", - defaults: ["pdl_be_test_file_defaults"], - srcs: ["tests/canonical/le_rust_test_file.pdl"], - out: ["be_rust_test_file.pdl"], -} - -genrule { - name: "pdl_be_test_file", - defaults: ["pdl_be_test_file_defaults"], - srcs: ["tests/canonical/le_test_file.pdl"], - out: ["be_test_file.pdl"], -} - -// Generate the Rust parser+serializer backends. -genrule { - name: "pdl_le_backend", - defaults: ["pdl_rust_generator_defaults"], - srcs: ["tests/canonical/le_rust_test_file.pdl"], - out: ["le_backend.rs"], -} - -genrule { - name: "pdl_be_backend", - defaults: ["pdl_rust_generator_defaults"], - srcs: [":pdl_be_rust_test_file"], - out: ["be_backend.rs"], -} - -rust_defaults { - name: "pdl_backend_defaults", - features: ["serde"], - rustlibs: [ - "libbytes", - "libnum_traits", - "libserde", - "libtempfile", - "libthiserror", - ], - proc_macros: [ - "libnum_derive", - "libserde_derive", - ], -} - -rust_library_host { - name: "libpdl_le_backend", - crate_name: "pdl_le_backend", - srcs: [":pdl_le_backend"], - defaults: ["pdl_backend_defaults"], - clippy_lints: "none", - lints: "none", -} - -rust_library_host { - name: "libpdl_be_backend", - crate_name: "pdl_be_backend", - srcs: [":pdl_be_backend"], - defaults: ["pdl_backend_defaults"], - clippy_lints: "none", - lints: "none", -} - -rust_binary_host { - name: "pdl_generate_tests", - srcs: ["src/bin/generate-canonical-tests.rs"], - rustlibs: [ - "libproc_macro2", - "libquote", - "libserde", - "libserde_json", - "libsyn", - "libtempfile", - ], -} - -genrule_defaults { - name: "pdl_rust_generator_src_defaults", - tools: [ - ":pdl_generate_tests", - ":rustfmt", - ], -} - -genrule { - name: "pdl_rust_generator_tests_le_src", - cmd: "set -o pipefail;" + - " $(location :pdl_generate_tests) $(in) pdl_le_backend |" + - " $(location :rustfmt) > $(out)", - srcs: ["tests/canonical/le_test_vectors.json"], - out: ["le_canonical.rs"], - defaults: ["pdl_rust_generator_src_defaults"], -} - -genrule { - name: "pdl_rust_generator_tests_be_src", - cmd: "set -o pipefail;" + - " $(location :pdl_generate_tests) $(in) pdl_be_backend |" + - " $(location :rustfmt) > $(out)", - srcs: ["tests/canonical/be_test_vectors.json"], - out: ["be_canonical.rs"], - defaults: ["pdl_rust_generator_src_defaults"], -} - -rust_test_host { - name: "pdl_rust_generator_tests_le", - srcs: [":pdl_rust_generator_tests_le_src"], - test_suites: ["general-tests"], - rustlibs: [ - "libnum_traits", - "libpdl_le_backend", - "libserde_json", - ], - clippy_lints: "none", - lints: "none", -} - -rust_test_host { - name: "pdl_rust_generator_tests_be", - srcs: [":pdl_rust_generator_tests_be_src"], - test_suites: ["general-tests"], - rustlibs: [ - "libnum_traits", - "libpdl_be_backend", - "libserde_json", - ], - clippy_lints: "none", - lints: "none", -} - -// Defaults for PDL python backend generation. -genrule_defaults { - name: "pdl_python_generator_defaults", - tools: [ - ":pdl", - ":pdl_python_generator", - ], -} - -// Defaults for PDL python backend generation. -genrule_defaults { - name: "pdl_cxx_generator_defaults", - tools: [ - ":pdl", - ":pdl_cxx_generator", - ], -} - -// Generate the python parser+serializer backend for the -// little endian test file located at tests/canonical/le_test_file.pdl. -genrule { - name: "pdl_python_generator_le_test_gen", - defaults: ["pdl_python_generator_defaults"], - cmd: "set -o pipefail;" + - " $(location :pdl) $(in) |" + - " $(location :pdl_python_generator)" + - " --output $(out) --custom-type-location tests.custom_types", - tool_files: [ - "tests/custom_types.py", - ], - srcs: [ - "tests/canonical/le_test_file.pdl", - ], - out: [ - "le_pdl_test.py", - ], -} - -// Generate the python parser+serializer backend for a big endian test -// file derived from tests/canonical/le_test_file.pdl. -genrule { - name: "pdl_python_generator_be_test_gen", - defaults: ["pdl_python_generator_defaults"], - cmd: "set -o pipefail;" + - " $(location :pdl) $(in) |" + - " $(location :pdl_python_generator)" + - " --output $(out) --custom-type-location tests.custom_types", - tool_files: [ - "tests/custom_types.py", - ], - srcs: [ - ":pdl_be_test_file", - ], - out: [ - "be_pdl_test.py", - ], -} - -// Test the generated python parser+serializer against -// pre-generated binary inputs. -python_test_host { - name: "pdl_python_generator_test", - main: "tests/python_generator_test.py", - srcs: [ - ":pdl_python_generator_be_test_gen", - ":pdl_python_generator_le_test_gen", - "tests/custom_types.py", - "tests/python_generator_test.py", - ], - data: [ - "tests/canonical/be_test_vectors.json", - "tests/canonical/le_test_vectors.json", - ], - libs: [ - "typing_extensions", - ], - test_options: { - unit_test: true, - }, - version: { - py3: { - embedded_launcher: true, - }, - }, -} - -// Defaults for the rust_noalloc backend -genrule_defaults { - name: "pdl_rust_noalloc_generator_defaults", - cmd: "set -o pipefail;" + - " $(location :pdl) --output-format rust_no_alloc $(in) |" + - " $(location :rustfmt) > $(out)", - tools: [ - ":pdl", - ":rustfmt", - ], -} - -// Generate the rust_noalloc backend srcs against the little-endian test vectors -genrule { - name: "pdl_rust_noalloc_le_test_backend_srcs", - defaults: ["pdl_rust_noalloc_generator_defaults"], - srcs: ["tests/canonical/le_rust_noalloc_test_file.pdl"], - out: ["_packets.rs"], -} - -// Generate the rust_noalloc test harness srcs for the supplied test vectors -genrule { - name: "pdl_rust_noalloc_le_test_gen_harness", - cmd: "set -o pipefail;" + - " $(location :pdl) $(in) --output-format rust_no_alloc_test" + - " > $(out)", - srcs: ["tests/canonical/le_rust_noalloc_test_file.pdl"], - out: ["test_rust_noalloc_parser.rs"], - tools: [":pdl"], -} - -// The test target for rust_noalloc -rust_test_host { - name: "pdl_rust_noalloc_le_test", - srcs: [ - ":pdl_rust_noalloc_le_test_gen_harness", - - ":pdl_rust_noalloc_le_test_backend_srcs", - ], - test_suites: ["general-tests"], -} - -// Generate the C++ parser+serializer backend for the -// little endian test file located at tests/canonical/le_test_file.pdl. -genrule { - name: "pdl_cxx_canonical_le_src_gen", - defaults: ["pdl_cxx_generator_defaults"], - cmd: "set -o pipefail;" + - " $(location :pdl) $(in) |" + - " $(location :pdl_cxx_generator)" + - " --namespace le_test" + - " --output $(out)", - srcs: [ - "tests/canonical/le_test_file.pdl", - ], - out: [ - "canonical_le_test_file.h", - ], -} - -// Generate the C++ parser+serializer backend tests for the -// little endian test file located at tests/canonical/le_test_file.pdl. -genrule { - name: "pdl_cxx_canonical_le_test_gen", - cmd: "set -o pipefail;" + - " inputs=( $(in) ) &&" + - " $(location :pdl) $${inputs[0]} |" + - " $(location :pdl_cxx_unittest_generator)" + - " --output $(out)" + - " --test-vectors $${inputs[1]}" + - " --include-header $$(basename $${inputs[2]})" + - " --using-namespace le_test" + - " --namespace le_test" + - " --parser-test-suite LeParserTest" + - " --serializer-test-suite LeSerializerTest", - tools: [ - ":pdl", - ":pdl_cxx_unittest_generator", - ], - srcs: [ - "tests/canonical/le_test_file.pdl", - "tests/canonical/le_test_vectors.json", - ":pdl_cxx_canonical_le_src_gen", - ], - out: [ - "canonical_le_test.cc", - ], -} - -// Generate the C++ parser+serializer backend for the -// big endian test file. -genrule { - name: "pdl_cxx_canonical_be_src_gen", - defaults: ["pdl_cxx_generator_defaults"], - cmd: "set -o pipefail;" + - " $(location :pdl) $(in) |" + - " $(location :pdl_cxx_generator)" + - " --namespace be_test" + - " --output $(out)", - srcs: [ - ":pdl_be_test_file", - ], - out: [ - "canonical_be_test_file.h", - ], -} - -// Generate the C++ parser+serializer backend tests for the -// big endian test file. -genrule { - name: "pdl_cxx_canonical_be_test_gen", - cmd: "set -o pipefail;" + - " inputs=( $(in) ) &&" + - " $(location :pdl) $${inputs[0]} |" + - " $(location :pdl_cxx_unittest_generator)" + - " --output $(out)" + - " --test-vectors $${inputs[1]}" + - " --include-header $$(basename $${inputs[2]})" + - " --using-namespace be_test" + - " --namespace be_test" + - " --parser-test-suite BeParserTest" + - " --serializer-test-suite BeSerializerTest", - tools: [ - ":pdl", - ":pdl_cxx_unittest_generator", - ], - srcs: [ - ":pdl_be_test_file", - "tests/canonical/be_test_vectors.json", - ":pdl_cxx_canonical_be_src_gen", - ], - out: [ - "canonical_be_test.cc", - ], -} - -// Test the generated C++ parser+serializer against -// pre-generated binary inputs. -cc_test_host { - name: "pdl_cxx_generator_test", - local_include_dirs: [ - "scripts", - ], - generated_headers: [ - "pdl_cxx_canonical_le_src_gen", - "pdl_cxx_canonical_be_src_gen", - ], - generated_sources: [ - "pdl_cxx_canonical_le_test_gen", - "pdl_cxx_canonical_be_test_gen", - ], - static_libs: [ - "libgtest", - ], -} diff --git a/tools/pdl/CONTRIBUTING.md b/tools/pdl/CONTRIBUTING.md deleted file mode 100644 index b16bd944285bc0e5c8f354249f8b61017c8783ff..0000000000000000000000000000000000000000 --- a/tools/pdl/CONTRIBUTING.md +++ /dev/null @@ -1,33 +0,0 @@ -# How to contribute - -We'd love to accept your patches and contributions to this project. - -## Before you begin - -### Sign our Contributor License Agreement - -Contributions to this project must be accompanied by a -[Contributor License Agreement](https://cla.developers.google.com/about) (CLA). -You (or your employer) retain the copyright to your contribution; this simply -gives us permission to use and redistribute your contributions as part of the -project. - -If you or your current employer have already signed the Google CLA (even if it -was for a different project), you probably don't need to do it again. - -Visit to see your current agreements or to -sign a new one. - -### Review our community guidelines - -This project follows -[Google's Open Source Community Guidelines](https://opensource.google/conduct/). - -## Contribution process - -### Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. Consult -[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more -information on using pull requests. diff --git a/tools/pdl/Cargo.toml b/tools/pdl/Cargo.toml deleted file mode 100644 index d8da5ff25563cca99eebbec2b0534d01fd4e20aa..0000000000000000000000000000000000000000 --- a/tools/pdl/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "pdl" -version = "0.1.0" -edition = "2021" -default-run = "pdl" - -[workspace] - -[features] -default = ["serde"] - -[dependencies] -codespan-reporting = "0.11.1" -heck = "0.4.0" -pest = "2.5.5" -pest_derive = "2.5.5" -proc-macro2 = "1.0.46" -quote = "1.0.21" -serde_json = "1.0.86" -argh = "0.1.7" -syn = "1.0.102" - -[dependencies.serde] -version = "1.0.145" -features = ["default", "derive", "serde_derive", "std", "rc"] -optional = true - -[dev-dependencies] -tempfile = "3.3.0" -bytes = { version = "1.2.1", features = ["serde"] } -num-derive = "0.3.3" -num-traits = "0.2.15" -thiserror = "1.0.37" -paste = "1.0.6" diff --git a/tools/pdl/LICENSE b/tools/pdl/LICENSE deleted file mode 100644 index d645695673349e3947e8e5ae42332d0ac3164cd7..0000000000000000000000000000000000000000 --- a/tools/pdl/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/tools/pdl/OWNERS b/tools/pdl/OWNERS deleted file mode 100644 index 02d2aab7b2f0eec695b537eaefff0bb38d386a96..0000000000000000000000000000000000000000 --- a/tools/pdl/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -# Reviewers for /tools/pdl - -henrichataing@google.com -licorne@google.com -mgeisler@google.com -mylesgw@google.com diff --git a/tools/pdl/README.md b/tools/pdl/README.md deleted file mode 100644 index c6eb85d4518e3ec606e9f2cfbe596ef8d650ed61..0000000000000000000000000000000000000000 --- a/tools/pdl/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Packet Description Language (PDL) - -PDL is a domain specific language for writing the definition of binary protocol -packets. Parsing and validating packets from raw bytes is tedious and error -prone in any language. PDL generates memory safe and tailored backends for -mulitple target languages: - - - Rust - - C++ - - Python - -## How to use PDL - -1. Write the protocol definition -1. `cargo run my-protocol.pdl --output-format rust > my-protocol.rs` - -Language specific instructions are provided in another section. - -## Supported Features - -[Full reference documentation](#doc/reference.md) -- Scalar values -- Enumerators -- Arrays -- Nested packets -- Conditional packet derivation -- Custom field definitions - -## Similar projects - -* [Kaitai](https://kaitai.io) -* [EMBOSS](https://github.com/kimrutherford/EMBOSS) -* [P4](https://p4.org/p4-spec/docs/P4-16-v1.0.0-spec.html) diff --git a/tools/pdl/doc/reference.md b/tools/pdl/doc/reference.md deleted file mode 100644 index 2529c294194a066006f11c6c79604999cb56b269..0000000000000000000000000000000000000000 --- a/tools/pdl/doc/reference.md +++ /dev/null @@ -1,682 +0,0 @@ -# Packet Description Language - -[TOC] - -## Notation - -| Notation | Example | Meaning | -|:-------------:|:----------------------------:|:----------------------------------------------------:| -| __ANY__ | __ANY__ | Any character | -| CAPITAL | IDENTIFIER, INT | A token production | -| snake_case | declaration, constraint | A syntactical production | -| `string` | `enum`, `=` | The exact character(s) | -| \x | \n, \r, \t, \0 | The character represented by this escape | -| x? | `,`? | An optional item | -| x* | ALPHANUM* | 0 or more of x | -| x+ | HEXDIGIT+ | 1 or more of x | -| x \| y | ALPHA \| DIGIT, `0x` \| `0X` | Either x or y | -| [x-y] | [`a`-`z`] | Any of the characters in the range from x to y | -| !x | !\n | Negative Predicate (lookahead), do not consume input | -| () | (`,` enum_tag) | Groups items | - - -[WHITESPACE](#Whitespace) and [COMMENT](#Comment) are implicitly inserted between every item -and repetitions in syntactical rules (snake_case). - -``` -file: endianess declaration* -``` -behaves like: -``` -file: (WHITESPACE | COMMENT)* endianess (WHITESPACE | COMMENT)* (declaration | WHITESPACE | COMMENT)* -``` - -## File - -> file:\ ->    endianess [declaration](#declarations)* -> -> endianess:\ ->    `little_endian_packets` | `big_endian_packets` - -The structure of a `.pdl`file is: -1. A declaration of the protocol endianess: `little_endian_packets` or `big_endian_packets`. Followed by -2. Declarations describing the structure of the protocol. - -``` -// The protocol is little endian -little_endian_packets - -// Brew a coffee -packet Brew { - pot: 8, // Output Pot: 8bit, 0-255 - additions: CoffeeAddition[2] // Coffee Additions: array of 2 CoffeeAddition -} -``` - -The endianess affects how fields of fractional byte sizes (hence named -bit-fields) are parsed or serialized. Such fields are grouped together to the -next byte boundary, least significant bit first, and then byte-swapped to the -required endianess before being written to memory, or after being read from -memory. - -``` -packet Coffee { - a: 1, - b: 15, - c: 3, - d: 5, -} - -// The first two field are laid out as a single -// integer of 16-bits -// MSB LSB -// 16 8 0 -// +---------------------------------------+ -// | b14 .. .. b0 |a| -// +---------------------------------------+ -// -// The file endianness is applied to this integer -// to obtain the byte layout of the packet fields. -// -// Little endian layout -// MSB LSB -// 7 6 5 4 3 2 1 0 -// +---------------------------------------+ -// 0 | b[6:0] | a | -// +---------------------------------------+ -// 1 | b[14:7] | -// +---------------------------------------+ -// 2 | d | c | -// +---------------------------------------+ -// -// Big endian layout -// MSB LSB -// 7 6 5 4 3 2 1 0 -// +---------------------------------------+ -// 0 | b[14:7] | -// +---------------------------------------+ -// 1 | b[6:0] | a | -// +---------------------------------------+ -// 2 | d | c | -// +---------------------------------------+ -``` - -Fields which qualify as bit-fields are: -- [Scalar](#fields-scalar) fields -- [Size](#fields-size) fields -- [Count](#fields-count) fields -- [Fixed](#fields-fixed) fields -- [Reserved](#fields-reserved) fields -- [Typedef](#fields-typedef) fields, when the field type is an - [Enum](#enum) - -Fields that do not qualify as bit-fields _must_ start and end on a byte boundary. - -## Identifiers - -- Identifiers can denote a field; an enumeration tag; or a declared type. - -- Field identifiers declared in a [packet](#packet) (resp. [struct](#struct)) belong to the _scope_ that extends - to the packet (resp. struct), and all derived packets (resp. structs). - -- Field identifiers declared in a [group](#group) belong to the _scope_ that - extends to the packets declaring a [group field](#group_field) for this group. - -- Two fields may not be declared with the same identifier in any packet scope. - -- Two types may not be declared width the same identifier. - -## Declarations - -> declaration: {#declaration}\ ->    [enum_declaration](#enum) |\ ->    [packet_declaration](#packet) |\ ->    [struct_declaration](#struct) |\ ->    [group_declaration](#group) |\ ->    [checksum_declaration](#checksum) |\ ->    [custom_field_declaration](#custom-field) |\ ->    [test_declaration](#test) - -A *declaration* defines a type inside a `.pdl` file. A declaration can reference -another declaration appearing later in the file. - -A declaration is either: -- an [Enum](#enum) declaration -- a [Packet](#packet) declaration -- a [Struct](#struct) declaration -- a [Group](#group) declaration -- a [Checksum](#checksum) declaration -- a [Custom Field](#custom-field) declaration -- a [Test](#test) declaration - -### Enum - -> enum_declaration:\ ->    `enum` [IDENTIFIER](#identifier) `:` [INTEGER](#integer) `{`\ ->      enum_tag_list\ ->    `}` -> -> enum_tag_list:\ ->    enum_tag (`,` enum_tag)* `,`? -> -> enum_tag:\ ->    enum_range | enum_value -> -> enum_range:\ ->    [IDENTIFIER](#identifier) `=` [INTEGER](#integer) `..` [INTEGER](#integer)) (`{`\ ->      enum_value_list\ ->    `}`)? -> -> enum_value_list:\ ->    enum_value (`,` enum_value)* `,`? -> -> enum_value:\ ->    [IDENTIFIER](#identifier) `=` [INTEGER](#integer) - -An *enumeration* or for short *enum*, is a declaration of a set of named [integer](#integer) constants -or named [integer](#integer) ranges. [integer](#integer) ranges are inclusive in both ends. -[integer](#integer) value within a range *must* be unique. [integer](#integer) ranges -*must not* overlap. - -The [integer](#integer) following the name specifies the bit size of the values. - -``` -enum CoffeeAddition: 5 { - Empty = 0, - - NonAlcoholic = 1..9 { - Cream = 1, - Vanilla = 2, - Chocolate = 3, - }, - - Alcoholic = 10..19 { - Whisky = 10, - Rum = 11, - Kahlua = 12, - Aquavit = 13, - }, - - Custom = 20..29, -} -``` - -### Packet - -> packet_declaration:\ ->    `packet` [IDENTIFIER](#identifier)\ ->      (`:` [IDENTIFIER](#identifier)\ ->        (`(` [constraint_list](#constraints) `)`)?\ ->      )?\ ->    `{`\ ->      [field_list](#fields)?\ ->    `}` - -A *packet* is a declaration of a sequence of [fields](#fields). While packets -can contain bit-fields, the size of the whole packet must be a multiple of 8 -bits. - -A *packet* can optionally inherit from another *packet* declaration. In this case the packet -inherits the parent's fields and the child's fields replace the -[*\_payload\_*](#fields-payload) or [*\_body\_*](#fields-body) field of the parent. - -When inheriting, you can use constraints to set values on parent fields. -See [constraints](#constraints) for more details. - -``` -packet Error { - code: 32, - _payload_ -} - -packet ImATeapot: Error(code = 418) { - brand_id: 8 -} -``` - -### Struct - -> struct_declaration:\ ->    `struct` [IDENTIFIER](#identifier)\ ->      (`:` [IDENTIFIER](#identifier)\ ->        (`(` [constraint_list](#constraints) `)`)?\ ->      )?\ ->    `{`\ ->      [field_list](#fields)?\ ->    `}` - -A *struct* follows the same rules as a [*packet*](#packet) with the following differences: -- It inherits from a *struct* declaration instead of *packet* declaration. -- A [typedef](#fields-typedef) field can reference a *struct*. - -### Group - -> group_declaration:\ ->    `group` [IDENTIFIER](#identifier) `{`\ ->      [field_list](#fields)\ ->    `}` - -A *group* is a sequence of [fields](#fields) that expand in a -[packet](#packet) or [struct](#struct) when used. - -See also the [Group field](#fields-group). - -``` -group Paged { - offset: 8, - limit: 8 -} - -packet AskBrewHistory { - pot: 8, // Coffee Pot - Paged -} -``` -behaves like: -``` -packet AskBrewHistory { - pot: 8, // Coffee Pot - offset: 8, - limit: 8 -} -``` - -### Checksum - -> checksum_declaration:\ ->    `checksum` [IDENTIFIER](#identifier) `:` [INTEGER](#integer) [STRING](#string) - -A *checksum* is a native type (not implemented in PDL). See your generator documentation -for more information on how to use it. - -The [integer](#integer) following the name specify the bit size of the checksum value. -The [string](#string) following the size is a value defined by the generator implementation. - -``` -checksum CRC16: 16 "crc16" -``` - -### Custom Field - -> custom_field_declaration:\ ->    `custom_field` [IDENTIFIER](#identifier) (`:` [INTEGER](#integer))? [STRING](#string) - -A *custom field* is a native type (not implemented in PDL). See your generator documentation for more -information on how to use it. - -If present, the [integer](#integer) following the name specify the bit size of the value. -The [string](#string) following the size is a value defined by the generator implementation. - -``` -custom_field URL "url" -``` - -### Test - -> test_declaration:\ ->    `test` [IDENTIFIER](#identifier) `{`\ ->      test_case_list\ ->    `}` -> -> test_case_list:\ ->    test_case (`,` test_case)* `,`? -> -> test_case:\ ->    [STRING](#string) - -A *test* declares a set of valid octet representations of a packet identified by its name. -The generator implementation defines how to use the test data. - -A test passes if the packet parser accepts the input; if you want to test -the values returned for each field, you may specify a derived packet with field values enforced using -constraints. - -``` -packet Brew { - pot: 8, - addition: CoffeeAddition -} - -test Brew { - "\x00\x00", - "\x00\x04" -} - -// Fully Constrained Packet -packet IrishCoffeeBrew: Brew(pot = 0, additions_list = Whisky) {} - -test IrishCoffeeBrew { - "\x00\x04" -} -``` - -## Constraints - -> constraint:\ ->    [IDENTIFIER](#identifier) `=` [IDENTIFIER](#identifier) | [INTEGER](#integer) -> -> constraint_list:\ ->    constraint (`,` constraint)* `,`? - -A *constraint* defines the value of a parent field. -The value can either be an [enum](#enum) tag or an [integer](#integer). - -``` -group Additionable { - addition: CoffeAddition -} - -packet IrishCoffeeBrew { - pot: 8, - Additionable { - addition = Whisky - } -} - -packet Pot0IrishCoffeeBrew: IrishCoffeeBrew(pot = 0) {} -``` - -## Fields - -> field_list:\ ->    field (`,` field)* `,`? -> -> field:\ ->    [checksum_field](#fields-checksum) |\ ->    [padding_field](#fields-padding) |\ ->    [size_field](#fields-size) |\ ->    [count_field](#fields-count) |\ ->    [payload_field](#fields-payload) |\ ->    [body_field](#fields-body) |\ ->    [fixed_field](#fields-fixed) |\ ->    [reserved_field](#fields-reserved) |\ ->    [array_field](#fields-array) |\ ->    [scalar_field](#fields-scalar) |\ ->    [typedef_field](#fields-typedef) |\ ->    [group_field](#fields-group) - -A field is either: -- a [Scalar](#fields-scalar) field -- a [Typedef](#fields-typedef) field -- a [Group](#fields-group) field -- an [Array](#fields-array) field -- a [Size](#fields-size) field -- a [Count](#fields-count) field -- a [Payload](#fields-payload) field -- a [Body](#fields-body) field -- a [Fixed](#fields-fixed) field -- a [Checksum](#fields-checksum) field -- a [Padding](#fields-padding) field -- a [Reserved](#fields-reserved) field - -### Scalar {#fields-scalar} - -> scalar_field:\ ->    [IDENTIFIER](#identifier) `:` [INTEGER](#integer) - -A *scalar* field defines a numeric value with a bit size. - -``` -struct Coffee { - temperature: 8 -} -``` - -### Typedef {#fields-typedef} - -> typedef_field:\ ->    [IDENTIFIER](#identifier) `:` [IDENTIFIER](#identifier) - -A *typedef* field defines a field taking as value either an [enum](#enum), [struct](#struct), -[checksum](#checksum) or a [custom_field](#custom-field). - -``` -packet LastTimeModification { - coffee: Coffee, - addition: CoffeeAddition -} -``` - -### Array {#fields-array} - -> array_field:\ ->    [IDENTIFIER](#identifier) `:` [INTEGER](#integer) | [IDENTIFIER](#identifier) `[`\ ->      [SIZE_MODIFIER](#size-modifier) | [INTEGER](#integer)\ ->    `]` - -An *array* field defines a sequence of `N` elements of type `T`. - -`N` can be: -- An [integer](#integer) value. -- A [size modifier](#size-modifier). -- Unspecified: In this case the array is dynamically sized using a -[*\_size\_*](#fields-size) or a [*\_count\_*](#fields-count). - -`T` can be: -- An [integer](#integer) denoting the bit size of one element. -- An [identifier](#identifier) referencing an [enum](#enum), a [struct](#struct) -or a [custom field](#custom-field) type. - -The size of `T` must always be a multiple of 8 bits, that is, the array elements -must start at byte boundaries. - -``` -packet Brew { - pots: 8[2], - additions: CoffeeAddition[2], - extra_additions: CoffeeAddition[], -} -``` - -### Group {#fields-group} - -> group_field:\ ->    [IDENTIFIER](#identifier) (`{` [constraint_list](#constraints) `}`)? - -A *group* field inlines all the fields defined in the referenced group. - -If a [constraint list](#constraints) constrains a [scalar](#fields-scalar) field -or [typedef](#fields-typedef) field with an [enum](#enum) type, the field will -become a [fixed](#fields-fixed) field. -The [fixed](#fields-fixed) field inherits the type or size of the original field and the -value from the constraint list. - -See [Group Declaration](#group) for more information. - -### Size {#fields-size} - -> size_field:\ ->    `_size_` `(` [IDENTIFIER](#identifier) | `_payload_` | `_body_` `)` `:` [INTEGER](#integer) - -A *\_size\_* field is a [scalar](#fields-scalar) field with as value the size in octet of the designated -[array](#fields-array), [*\_payload\_*](#fields-payload) or [*\_body\_*](#fields-body). - -``` -packet Parent { - _size_(_payload_): 2, - _payload_ -} - -packet Brew { - pot: 8, - _size_(additions): 8, - additions: CoffeeAddition[] -} -``` - -### Count {#fields-count} - -> count_field:\ ->    `_count_` `(` [IDENTIFIER](#identifier) `)` `:` [INTEGER](#integer) - -A *\_count\_* field is a [*scalar*](#fields-scalar) field with as value the number of elements of the designated -[array](#fields-array). - -``` -packet Brew { - pot: 8, - _count_(additions): 8, - additions: CoffeeAddition[] -} -``` - -### Payload {#fields-payload} - -> payload_field:\ ->    `_payload_` (`:` `[` [SIZE_MODIFIER](#size-modifier) `]` )? - -A *\_payload\_* field is a dynamically sized array of octets. - -It declares where to parse the definition of a child [packet](#packet) or [struct](#struct). - -A [*\_size\_*](#fields-size) or a [*\_count\_*](#fields-count) field referencing -the payload induce its size. - -If used, a [size modifier](#size-modifier) can alter the octet size. - -### Body {#fields-body} - -> body_field:\ ->    `_body_` - -A *\_body\_* field is like a [*\_payload\_*](#fields-payload) field with the following differences: -- The body field is private to the packet definition, it's accessible only when inheriting. -- The body does not accept a size modifier. - -### Fixed {#fields-fixed} - -> fixed_field:\ ->    `_fixed_` `=` \ ->      ( [INTEGER](#integer) `:` [INTEGER](#integer) ) |\ ->      ( [IDENTIFIER](#identifier) `:` [IDENTIFIER](#identifier) ) - -A *\_fixed\_* field defines a constant with a known bit size. -The constant can be either: -- An [integer](#integer) value -- An [enum](#enum) tag - -``` -packet Teapot { - _fixed_ = 42: 8, - _fixed_ = Empty: CoffeeAddition -} -``` - -### Checksum {#fields-checksum} - -> checksum_field:\ ->    `_checksum_start_` `(` [IDENTIFIER](#identifier) `)` - -A *\_checksum_start\_* field is a zero sized field that acts as a marker for the beginning of -the fields covered by a checksum. - -The *\_checksum_start\_* references a [typedef](#fields-typedef) field -with a [checksum](#checksum) type that stores the checksum value and selects the algorithm -for the checksum. - -``` -checksum CRC16: 16 "crc16" - -packet CRCedBrew { - crc: CRC16, - _checksum_start_(crc), - pot: 8, -} -``` - -### Padding {#fields-padding} - -> padding_field:\ ->    `_padding_` `[` [INTEGER](#integer) `]` - -A *\_padding\_* field immediately following an array field pads the array field with `0`s to the -specified number of **octets**. - -``` -packet PaddedCoffee { - additions: CoffeeAddition[], - _padding_[100] -} -``` - -### Reserved {#fields-reserved} - -> reserved_field:\ ->    `_reserved_` `:` [INTEGER](#integer) - -A *\_reserved\_* field adds reserved bits. - -``` -packet DeloreanCoffee { - _reserved_: 2014 -} -``` - -## Tokens - -### Integer - -> INTEGER:\ ->    HEXVALUE | INTVALUE -> -> HEXVALUE:\ ->    `0x` | `0X` HEXDIGIT+ -> -> INTVALUE:\ ->    DIGIT+ -> -> HEXDIGIT:\ ->    DIGIT | [`a`-`f`] | [`A`-`F`] -> -> DIGIT:\ ->    [`0`-`9`] - -A integer is a number in base 10 (decimal) or in base 16 (hexadecimal) with -the prefix `0x` - -### String - -> STRING:\ ->    `"` (!`"` __ANY__)* `"` - -A string is sequence of character. It can be multi-line. - -### Identifier - -> IDENTIFIER: \ ->    ALPHA (ALPHANUM | `_`)* -> -> ALPHA:\ ->    [`a`-`z`] | [`A`-`Z`] -> -> ALPHANUM:\ ->    ALPHA | DIGIT - -An identifier is a sequence of alphanumeric or `_` characters -starting with a letter. - -### Size Modifier - -> SIZE_MODIFIER:\ ->    `+` INTVALUE - -A size modifier alters the octet size of the field it is attached to. -For example, `+ 2` defines that the size is 2 octet bigger than the -actual field size. - -### Comment - -> COMMENT:\ ->    BLOCK_COMMENT | LINE_COMMENT -> -> BLOCK_COMMENT:\ ->    `/*` (!`*/` ANY) `*/` -> -> LINE_COMMENT:\ ->    `//` (!\n ANY) `//` - -### Whitespace - -> WHITESPACE:\ ->    ` ` | `\t` | `\n` diff --git a/tools/pdl/scripts/Android.bp b/tools/pdl/scripts/Android.bp deleted file mode 100644 index 8035e1d465f3ea0efd30d6b3057c84173cb146db..0000000000000000000000000000000000000000 --- a/tools/pdl/scripts/Android.bp +++ /dev/null @@ -1,44 +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"], -} - -// Python generator. -python_binary_host { - name: "pdl_python_generator", - main: "generate_python_backend.py", - srcs: [ - "generate_python_backend.py", - "pdl/ast.py", - "pdl/core.py", - "pdl/utils.py", - ], -} - -// C++ generator. -python_binary_host { - name: "pdl_cxx_generator", - main: "generate_cxx_backend.py", - srcs: [ - "generate_cxx_backend.py", - "pdl/ast.py", - "pdl/core.py", - "pdl/utils.py", - ], -} - -// C++ test generator. -python_binary_host { - name: "pdl_cxx_unittest_generator", - main: "generate_cxx_backend_tests.py", - srcs: [ - "generate_cxx_backend_tests.py", - "pdl/ast.py", - "pdl/core.py", - "pdl/utils.py", - ], -} diff --git a/tools/pdl/scripts/generate_cxx_backend.py b/tools/pdl/scripts/generate_cxx_backend.py deleted file mode 100755 index a728d13411f02fa70c737132cab9653685cdfd81..0000000000000000000000000000000000000000 --- a/tools/pdl/scripts/generate_cxx_backend.py +++ /dev/null @@ -1,1392 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2023 Google LLC -# -# 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 -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -from dataclasses import dataclass, field -import json -from pathlib import Path -import sys -from textwrap import dedent -from typing import List, Tuple, Union, Optional - -from pdl import ast, core -from pdl.utils import indent, to_pascal_case - - -def mask(width: int) -> str: - return hex((1 << width) - 1) - - -def deref(var: Optional[str], id: str) -> str: - return f'{var}.{id}' if var else id - - -def get_cxx_scalar_type(width: int) -> str: - """Return the cxx scalar type to be used to back a PDL type.""" - for n in [8, 16, 32, 64]: - if width <= n: - return f'uint{n}_t' - # PDL type does not fit on non-extended scalar types. - assert False - - -@dataclass -class FieldParser: - byteorder: str - offset: int = 0 - shift: int = 0 - extract_arrays: bool = field(default=False) - chunk: List[Tuple[int, int, ast.Field]] = field(default_factory=lambda: []) - chunk_nr: int = 0 - unchecked_code: List[str] = field(default_factory=lambda: []) - code: List[str] = field(default_factory=lambda: []) - - def unchecked_append_(self, line: str): - """Append unchecked field parsing code. - The function check_size_ must be called to generate a size guard - after parsing is completed.""" - self.unchecked_code.append(line) - - def append_(self, line: str): - """Append field parsing code. - There must be no unchecked code left before this function is called.""" - assert len(self.unchecked_code) == 0 - self.code.append(line) - - def check_size_(self, size: str): - """Generate a check of the current span size.""" - self.append_(f"if (span.size() < {size}) {{") - self.append_(" return false;") - self.append_("}") - - def check_code_(self): - """Generate a size check for pending field parsing.""" - if len(self.unchecked_code) > 0: - assert len(self.chunk) == 0 - unchecked_code = self.unchecked_code - self.unchecked_code = [] - self.check_size_(str(self.offset)) - self.code.extend(unchecked_code) - self.offset = 0 - - def parse_bit_field_(self, field: ast.Field): - """Parse the selected field as a bit field. - The field is added to the current chunk. When a byte boundary - is reached all saved fields are extracted together.""" - - # Add to current chunk. - width = core.get_field_size(field) - self.chunk.append((self.shift, width, field)) - self.shift += width - - # Wait for more fields if not on a byte boundary. - if (self.shift % 8) != 0: - return - - # Parse the backing integer using the configured endianness, - # extract field values. - size = int(self.shift / 8) - backing_type = get_cxx_scalar_type(self.shift) - - # Special case when no field is actually used from - # the chunk. - should_skip_value = all(isinstance(field, ast.ReservedField) for (_, _, field) in self.chunk) - if should_skip_value: - self.unchecked_append_(f"span.skip({size}); // skip reserved fields") - self.offset += size - self.shift = 0 - self.chunk = [] - return - - if len(self.chunk) > 1: - value = f"chunk{self.chunk_nr}" - self.unchecked_append_(f"{backing_type} {value} = span.read_{self.byteorder}<{backing_type}, {size}>();") - self.chunk_nr += 1 - else: - value = f"span.read_{self.byteorder}<{backing_type}, {size}>()" - - for shift, width, field in self.chunk: - v = (value if len(self.chunk) == 1 and shift == 0 else f"({value} >> {shift}) & {mask(width)}") - - if isinstance(field, ast.ScalarField): - self.unchecked_append_(f"{field.id}_ = {v};") - elif isinstance(field, ast.FixedField) and field.enum_id: - self.unchecked_append_(f"if ({field.enum_id}({v}) != {field.enum_id}::{field.tag_id}) {{") - self.unchecked_append_(" return false;") - self.unchecked_append_("}") - elif isinstance(field, ast.FixedField): - self.unchecked_append_(f"if (({v}) != {hex(field.value)}) {{") - self.unchecked_append_(" return false;") - self.unchecked_append_("}") - elif isinstance(field, ast.TypedefField): - self.unchecked_append_(f"{field.id}_ = {field.type_id}({v});") - elif isinstance(field, ast.SizeField): - self.unchecked_append_(f"{field.field_id}_size = {v};") - elif isinstance(field, ast.CountField): - self.unchecked_append_(f"{field.field_id}_count = {v};") - elif isinstance(field, ast.ReservedField): - pass - else: - raise Exception(f'Unsupported bit field type {field.kind}') - - # Reset state. - self.offset += size - self.shift = 0 - self.chunk = [] - - def parse_typedef_field_(self, field: ast.TypedefField): - """Parse a typedef field, to the exclusion of Enum fields.""" - if self.shift != 0: - raise Exception('Typedef field does not start on an octet boundary') - - self.check_code_() - self.append_( - dedent("""\ - if (!{field_type}::Parse(span, &{field_id}_)) {{ - return false; - }}""".format(field_type=field.type.id, field_id=field.id))) - - def parse_array_field_lite_(self, field: ast.ArrayField): - """Parse the selected array field. - This function does not attempt to parse all elements but just to - identify the span of the array.""" - array_size = core.get_array_field_size(field) - element_width = core.get_array_element_size(field) - padded_size = field.padded_size - - if element_width: - element_width = int(element_width / 8) - - if isinstance(array_size, int): - size = None - count = array_size - elif isinstance(array_size, ast.SizeField): - size = f'{field.id}_size' - count = None - elif isinstance(array_size, ast.CountField): - size = None - count = f'{field.id}_count' - else: - size = None - count = None - - # Shift the span to reset the offset to 0. - self.check_code_() - - # Apply the size modifier. - if field.size_modifier and size: - self.append_(f"{size} = {size} - {field.size_modifier};") - - # Compute the array size if the count and element width are known. - if count is not None and element_width is not None: - size = f"{count} * {element_width}" - - # Parse from the padded array if padding is present. - if padded_size: - self.check_size_(padded_size) - self.append_("{") - self.append_( - f"pdl::packet::slice remaining_span = span.subrange({padded_size}, span.size() - {padded_size});") - self.append_(f"span = span.subrange(0, {padded_size});") - - # The array size is known in bytes. - if size is not None: - self.check_size_(size) - self.append_(f"{field.id}_ = span.subrange(0, {size});") - self.append_(f"span.skip({size});") - - # The array count is known. The element width is dynamic. - # Parse each element iteratively and derive the array span. - elif count is not None: - self.append_("{") - self.append_("pdl::packet::slice temp_span = span;") - self.append_(f"for (size_t n = 0; n < {count}; n++) {{") - self.append_(f" {field.type_id} element;") - self.append_(f" if (!{field.type_id}::Parse(temp_span, &element)) {{") - self.append_(" return false;") - self.append_(" }") - self.append_("}") - self.append_(f"{field.id}_ = span.subrange(0, span.size() - temp_span.size());") - self.append_(f"span.skip({field.id}_.size());") - self.append_("}") - - # The array size is not known, assume the array takes the - # full remaining space. TODO support having fixed sized fields - # following the array. - else: - self.append_(f"{field.id}_ = span;") - self.append_("span.clear();") - - if padded_size: - self.append_(f"span = remaining_span;") - self.append_("}") - - def parse_array_field_full_(self, field: ast.ArrayField): - """Parse the selected array field. - This function does not attempt to parse all elements but just to - identify the span of the array.""" - array_size = core.get_array_field_size(field) - element_width = core.get_array_element_size(field) - element_type = field.type_id or get_cxx_scalar_type(field.width) - padded_size = field.padded_size - - if element_width: - element_width = int(element_width / 8) - - if isinstance(array_size, int): - size = None - count = array_size - elif isinstance(array_size, ast.SizeField): - size = f'{field.id}_size' - count = None - elif isinstance(array_size, ast.CountField): - size = None - count = f'{field.id}_count' - else: - size = None - count = None - - # Shift the span to reset the offset to 0. - self.check_code_() - - # Apply the size modifier. - if field.size_modifier and size: - self.append_(f"{size} = {size} - {field.size_modifier};") - - # Compute the array size if the count and element width are known. - if count is not None and element_width is not None: - size = f"{count} * {element_width}" - - # Parse from the padded array if padding is present. - if padded_size: - self.check_size_(padded_size) - self.append_("{") - self.append_( - f"pdl::packet::slice remaining_span = span.subrange({padded_size}, span.size() - {padded_size});") - self.append_(f"span = span.subrange(0, {padded_size});") - - # The array size is known in bytes. - if size is not None: - self.check_size_(size) - self.append_("{") - self.append_(f"pdl::packet::slice temp_span = span.subrange(0, {size});") - self.append_(f"span.skip({size});") - self.append_(f"while (temp_span.size() > 0) {{") - if field.width: - element_size = int(field.width / 8) - self.append_(f" if (temp_span.size() < {element_size}) {{") - self.append_(f" return false;") - self.append_(" }") - self.append_( - f" {field.id}_.push_back(temp_span.read_{self.byteorder}<{element_type}, {element_size}>());") - elif isinstance(field.type, ast.EnumDeclaration): - backing_type = get_cxx_scalar_type(field.type.width) - element_size = int(field.type.width / 8) - self.append_(f" if (temp_span.size() < {element_size}) {{") - self.append_(f" return false;") - self.append_(" }") - self.append_( - f" {field.id}_.push_back({element_type}(temp_span.read_{self.byteorder}<{backing_type}, {element_size}>()));" - ) - else: - self.append_(f" {element_type} element;") - self.append_(f" if (!{element_type}::Parse(temp_span, &element)) {{") - self.append_(f" return false;") - self.append_(" }") - self.append_(f" {field.id}_.emplace_back(std::move(element));") - self.append_("}") - self.append_("}") - - # The array count is known. The element width is dynamic. - # Parse each element iteratively and derive the array span. - elif count is not None: - self.append_(f"for (size_t n = 0; n < {count}; n++) {{") - self.append_(f" {element_type} element;") - self.append_(f" if (!{field.type_id}::Parse(span, &element)) {{") - self.append_(" return false;") - self.append_(" }") - self.append_(f" {field.id}_.emplace_back(std::move(element));") - self.append_("}") - - # The array size is not known, assume the array takes the - # full remaining space. TODO support having fixed sized fields - # following the array. - elif field.width: - element_size = int(field.width / 8) - self.append_(f"while (span.size() > 0) {{") - self.append_(f" if (span.size() < {element_size}) {{") - self.append_(f" return false;") - self.append_(" }") - self.append_(f" {field.id}_.push_back(span.read_{self.byteorder}<{element_type}, {element_size}>());") - self.append_("}") - elif isinstance(field.type, ast.EnumDeclaration): - element_size = int(field.type.width / 8) - backing_type = get_cxx_scalar_type(field.type.width) - self.append_(f"while (span.size() > 0) {{") - self.append_(f" if (span.size() < {element_size}) {{") - self.append_(f" return false;") - self.append_(" }") - self.append_( - f" {field.id}_.push_back({element_type}(span.read_{self.byteorder}<{backing_type}, {element_size}>()));" - ) - self.append_("}") - else: - self.append_(f"while (span.size() > 0) {{") - self.append_(f" {element_type} element;") - self.append_(f" if (!{element_type}::Parse(span, &element)) {{") - self.append_(f" return false;") - self.append_(" }") - self.append_(f" {field.id}_.emplace_back(std::move(element));") - self.append_("}") - - if padded_size: - self.append_(f"span = remaining_span;") - self.append_("}") - - def parse_payload_field_lite_(self, field: Union[ast.BodyField, ast.PayloadField]): - """Parse body and payload fields.""" - if self.shift != 0: - raise Exception('Payload field does not start on an octet boundary') - - payload_size = core.get_payload_field_size(field) - offset_from_end = core.get_field_offset_from_end(field) - self.check_code_() - - if payload_size and getattr(field, 'size_modifier', None): - self.append_(f"{field.id}_size -= {field.size_modifier};") - - # The payload or body has a known size. - # Consume the payload and update the span in case - # fields are placed after the payload. - if payload_size: - self.check_size_(f"{field.id}_size") - self.append_(f"payload_ = span.subrange(0, {field.id}_size);") - self.append_(f"span.skip({field.id}_size);") - # The payload or body is the last field of a packet, - # consume the remaining span. - elif offset_from_end == 0: - self.append_(f"payload_ = span;") - self.append_(f"span.clear();") - # The payload or body is followed by fields of static size. - # Consume the span that is not reserved for the following fields. - elif offset_from_end: - if (offset_from_end % 8) != 0: - raise Exception('Payload field offset from end of packet is not a multiple of 8') - offset_from_end = int(offset_from_end / 8) - self.check_size_(f'{offset_from_end}') - self.append_(f"payload_ = span.subrange(0, span.size() - {offset_from_end});") - self.append_(f"span.skip(payload_.size());") - - def parse_payload_field_full_(self, field: Union[ast.BodyField, ast.PayloadField]): - """Parse body and payload fields.""" - if self.shift != 0: - raise Exception('Payload field does not start on an octet boundary') - - payload_size = core.get_payload_field_size(field) - offset_from_end = core.get_field_offset_from_end(field) - self.check_code_() - - if payload_size and getattr(field, 'size_modifier', None): - self.append_(f"{field.id}_size -= {field.size_modifier};") - - # The payload or body has a known size. - # Consume the payload and update the span in case - # fields are placed after the payload. - if payload_size: - self.check_size_(f"{field.id}_size") - self.append_(f"for (size_t n = 0; n < {field.id}_size; n++) {{") - self.append_(f" payload_.push_back(span.read_{self.byteorder}();") - self.append_("}") - # The payload or body is the last field of a packet, - # consume the remaining span. - elif offset_from_end == 0: - self.append_("while (span.size() > 0) {") - self.append_(f" payload_.push_back(span.read_{self.byteorder}();") - self.append_("}") - # The payload or body is followed by fields of static size. - # Consume the span that is not reserved for the following fields. - elif offset_from_end is not None: - if (offset_from_end % 8) != 0: - raise Exception('Payload field offset from end of packet is not a multiple of 8') - offset_from_end = int(offset_from_end / 8) - self.check_size_(f'{offset_from_end}') - self.append_(f"while (span.size() > {offset_from_end}) {{") - self.append_(f" payload_.push_back(span.read_{self.byteorder}();") - self.append_("}") - - def parse(self, field: ast.Field): - # Field has bit granularity. - # Append the field to the current chunk, - # check if a byte boundary was reached. - if core.is_bit_field(field): - self.parse_bit_field_(field) - - # Padding fields. - elif isinstance(field, ast.PaddingField): - pass - - # Array fields. - elif isinstance(field, ast.ArrayField) and self.extract_arrays: - self.parse_array_field_full_(field) - - elif isinstance(field, ast.ArrayField) and not self.extract_arrays: - self.parse_array_field_lite_(field) - - # Other typedef fields. - elif isinstance(field, ast.TypedefField): - self.parse_typedef_field_(field) - - # Payload and body fields. - elif isinstance(field, (ast.PayloadField, ast.BodyField)) and self.extract_arrays: - self.parse_payload_field_full_(field) - - elif isinstance(field, (ast.PayloadField, ast.BodyField)) and not self.extract_arrays: - self.parse_payload_field_lite_(field) - - else: - raise Exception(f'Unsupported field type {field.kind}') - - def done(self): - self.check_code_() - - -@dataclass -class FieldSerializer: - byteorder: str - shift: int = 0 - value: List[Tuple[str, int]] = field(default_factory=lambda: []) - code: List[str] = field(default_factory=lambda: []) - indent: int = 0 - - def indent_(self): - self.indent += 1 - - def unindent_(self): - self.indent -= 1 - - def append_(self, line: str): - """Append field serializing code.""" - lines = line.split('\n') - self.code.extend([' ' * self.indent + line for line in lines]) - - def get_payload_field_size(self, var: Optional[str], payload: ast.PayloadField, decl: ast.Declaration) -> str: - """Compute the size of the selected payload field, with the information - of the builder for the selected declaration. The payload field can be - the payload of any of the parent declarations, or the current declaration.""" - - if payload.parent.id == decl.id: - return deref(var, 'payload_.size()') - - # Get the child packet declaration that will match the current - # declaration further down. - child = decl - while child.parent_id != payload.parent.id: - child = child.parent - - # The payload is the result of serializing the children fields. - constant_width = 0 - variable_width = [] - for f in child.fields: - field_size = core.get_field_size(f) - if field_size is not None: - constant_width += field_size - elif isinstance(f, (ast.PayloadField, ast.BodyField)): - variable_width.append(self.get_payload_field_size(var, f, decl)) - elif isinstance(f, ast.TypedefField): - variable_width.append(f"{f.id}_.GetSize()") - elif isinstance(f, ast.ArrayField): - variable_width.append(f"Get{to_pascal_case(f.id)}Size()") - else: - raise Exception("Unsupported field type") - - constant_width = int(constant_width / 8) - if constant_width and not variable_width: - return str(constant_width) - - temp_var = f'{payload.parent.id.lower()}_payload_size' - self.append_(f"size_t {temp_var} = {constant_width};") - for dyn in variable_width: - self.append_(f"{temp_var} += {dyn};") - return temp_var - - def serialize_array_element_(self, field: ast.ArrayField, var: str): - """Serialize a single array field element.""" - if field.width: - backing_type = get_cxx_scalar_type(field.width) - element_size = int(field.width / 8) - self.append_( - f"pdl::packet::Builder::write_{self.byteorder}<{backing_type}, {element_size}>(output, {var});") - elif isinstance(field.type, ast.EnumDeclaration): - backing_type = get_cxx_scalar_type(field.type.width) - element_size = int(field.type.width / 8) - self.append_(f"pdl::packet::Builder::write_{self.byteorder}<{backing_type}, {element_size}>(" + - f"output, static_cast<{backing_type}>({var}));") - else: - self.append_(f"{var}.Serialize(output);") - - def serialize_array_field_(self, field: ast.ArrayField, var: str): - """Serialize the selected array field.""" - if field.padded_size: - self.append_(f"size_t {field.id}_end = output.size() + {field.padded_size};") - - if field.width == 8: - self.append_(f"output.insert(output.end(), {var}.begin(), {var}.end());") - else: - self.append_(f"for (size_t n = 0; n < {var}.size(); n++) {{") - self.indent_() - self.serialize_array_element_(field, f'{var}[n]') - self.unindent_() - self.append_("}") - - if field.padded_size: - self.append_(f"while (output.size() < {field.id}_end) {{") - self.append_(" output.push_back(0);") - self.append_("}") - - def serialize_bit_field_(self, field: ast.Field, parent_var: Optional[str], var: Optional[str], - decl: ast.Declaration): - """Serialize the selected field as a bit field. - The field is added to the current chunk. When a byte boundary - is reached all saved fields are serialized together.""" - - # Add to current chunk. - width = core.get_field_size(field) - shift = self.shift - - if isinstance(field, ast.ScalarField): - self.value.append((f"{var} & {mask(field.width)}", shift)) - elif isinstance(field, ast.FixedField) and field.enum_id: - self.value.append((f"{field.enum_id}::{field.tag_id}", shift)) - elif isinstance(field, ast.FixedField): - self.value.append((f"{field.value}", shift)) - elif isinstance(field, ast.TypedefField): - self.value.append((f"{var}", shift)) - - elif isinstance(field, ast.SizeField): - max_size = (1 << field.width) - 1 - value_field = core.get_packet_field(field.parent, field.field_id) - size_modifier = '' - - if getattr(value_field, 'size_modifier', None): - size_modifier = f' + {value_field.size_modifier}' - - if isinstance(value_field, (ast.PayloadField, ast.BodyField)): - array_size = self.get_payload_field_size(var, field, decl) + size_modifier - - elif isinstance(value_field, ast.ArrayField): - accessor_name = to_pascal_case(field.field_id) - array_size = deref(var, f'Get{accessor_name}Size()') + size_modifier - - self.value.append((f"{array_size}", shift)) - - elif isinstance(field, ast.CountField): - max_count = (1 << field.width) - 1 - self.value.append((f"{field.field_id}_.size()", shift)) - - elif isinstance(field, ast.ReservedField): - pass - else: - raise Exception(f'Unsupported bit field type {field.kind}') - - # Check if a byte boundary is reached. - self.shift += width - if (self.shift % 8) == 0: - self.pack_bit_fields_() - - def pack_bit_fields_(self): - """Pack serialized bit fields.""" - - # Should have an integral number of bytes now. - assert (self.shift % 8) == 0 - - # Generate the backing integer, and serialize it - # using the configured endiannes, - size = int(self.shift / 8) - backing_type = get_cxx_scalar_type(self.shift) - value = [f"(static_cast<{backing_type}>({v[0]}) << {v[1]})" for v in self.value] - - if len(value) == 0: - self.append_(f"pdl::packet::Builder::write_{self.byteorder}<{backing_type}, {size}>(output, 0);") - elif len(value) == 1: - self.append_(f"pdl::packet::Builder::write_{self.byteorder}<{backing_type}, {size}>(output, {value[0]});") - else: - self.append_( - f"pdl::packet::Builder::write_{self.byteorder}<{backing_type}, {size}>(output, {' | '.join(value)});") - - # Reset state. - self.shift = 0 - self.value = [] - - def serialize_typedef_field_(self, field: ast.TypedefField, var: str): - """Serialize a typedef field, to the exclusion of Enum fields.""" - - if self.shift != 0: - raise Exception('Typedef field does not start on an octet boundary') - if (isinstance(field.type, ast.StructDeclaration) and field.type.parent_id is not None): - raise Exception('Derived struct used in typedef field') - - self.append_(f"{var}.Serialize(output);") - - def serialize_payload_field_(self, field: Union[ast.BodyField, ast.PayloadField], var: str): - """Serialize body and payload fields.""" - - if self.shift != 0: - raise Exception('Payload field does not start on an octet boundary') - - self.append_(f"output.insert(output.end(), {var}.begin(), {var}.end());") - - def serialize(self, field: ast.Field, decl: ast.Declaration, var: Optional[str] = None): - field_var = deref(var, f'{field.id}_') if hasattr(field, 'id') else None - - # Field has bit granularity. - # Append the field to the current chunk, - # check if a byte boundary was reached. - if core.is_bit_field(field): - self.serialize_bit_field_(field, var, field_var, decl) - - # Padding fields. - elif isinstance(field, ast.PaddingField): - pass - - # Array fields. - elif isinstance(field, ast.ArrayField): - self.serialize_array_field_(field, field_var) - - # Other typedef fields. - elif isinstance(field, ast.TypedefField): - self.serialize_typedef_field_(field, field_var) - - # Payload and body fields. - elif isinstance(field, (ast.PayloadField, ast.BodyField)): - self.serialize_payload_field_(field, deref(var, 'payload_')) - - else: - raise Exception(f'Unimplemented field type {field.kind}') - - -def generate_enum_declaration(decl: ast.EnumDeclaration) -> str: - """Generate the implementation of an enum type.""" - - enum_name = decl.id - enum_type = get_cxx_scalar_type(decl.width) - tag_decls = [] - for t in decl.tags: - tag_decls.append(f"{t.id} = {hex(t.value)},") - - return dedent("""\ - - enum class {enum_name} : {enum_type} {{ - {tag_decls} - }}; - """).format(enum_name=enum_name, enum_type=enum_type, tag_decls=indent(tag_decls, 1)) - - -def generate_enum_to_text(decl: ast.EnumDeclaration) -> str: - """Generate the helper function that will convert an enum tag to string.""" - - enum_name = decl.id - tag_cases = [] - for t in decl.tags: - tag_cases.append(f"case {enum_name}::{t.id}: return \"{t.id}\";") - - return dedent("""\ - - inline std::string {enum_name}Text({enum_name} tag) {{ - switch (tag) {{ - {tag_cases} - default: - return std::string("Unknown {enum_name}: " + - std::to_string(static_cast(tag))); - }} - }} - """).format(enum_name=enum_name, tag_cases=indent(tag_cases, 2)) - - -def generate_packet_field_members(decl: ast.Declaration, view: bool) -> List[str]: - """Return the declaration of fields that are backed in the view - class declaration. - - Backed fields include all named fields that do not have a constrained - value in the selected declaration and its parents. - - :param decl: target declaration - :param view: if true the payload and array fields are generated as slices""" - - fields = core.get_unconstrained_parent_fields(decl) + decl.fields - members = [] - for field in fields: - if isinstance(field, (ast.PayloadField, ast.BodyField)) and view: - members.append("pdl::packet::slice payload_;") - elif isinstance(field, (ast.PayloadField, ast.BodyField)): - members.append("std::vector payload_;") - elif isinstance(field, ast.ArrayField) and view: - members.append(f"pdl::packet::slice {field.id}_;") - elif isinstance(field, ast.ArrayField): - element_type = field.type_id or get_cxx_scalar_type(field.width) - members.append(f"std::vector<{element_type}> {field.id}_;") - elif isinstance(field, ast.ScalarField): - members.append(f"{get_cxx_scalar_type(field.width)} {field.id}_{{0}};") - elif isinstance(field, ast.TypedefField) and isinstance(field.type, ast.EnumDeclaration): - members.append(f"{field.type_id} {field.id}_{{{field.type_id}::{field.type.tags[0].id}}};") - elif isinstance(field, ast.TypedefField): - members.append(f"{field.type_id} {field.id}_;") - - return members - - -def generate_packet_field_serializers(packet: ast.Declaration) -> List[str]: - """Generate the code to serialize the fields of a packet builder or struct.""" - serializer = FieldSerializer(byteorder=packet.file.byteorder_short) - constraints = core.get_parent_constraints(packet) - constraints = dict([(c.id, c) for c in constraints]) - for field in core.get_packet_fields(packet): - field_id = getattr(field, 'id', None) - constraint = constraints.get(field_id, None) - fixed_field = None - if constraint and constraint.tag_id: - fixed_field = ast.FixedField(enum_id=field.type_id, - tag_id=constraint.tag_id, - loc=field.loc, - kind='fixed_field') - fixed_field.parent = field.parent - elif constraint: - fixed_field = ast.FixedField(width=field.width, value=constraint.value, loc=field.loc, kind='fixed_field') - fixed_field.parent = field.parent - serializer.serialize(fixed_field or field, packet) - return serializer.code - - -def generate_scalar_array_field_accessor(field: ast.ArrayField) -> str: - """Parse the selected scalar array field.""" - element_size = int(field.width / 8) - backing_type = get_cxx_scalar_type(field.width) - byteorder = field.parent.file.byteorder_short - return dedent("""\ - pdl::packet::slice span = {field_id}_; - std::vector<{backing_type}> elements; - while (span.size() >= {element_size}) {{ - elements.push_back(span.read_{byteorder}<{backing_type}, {element_size}>()); - }} - return elements;""").format(field_id=field.id, - backing_type=backing_type, - element_size=element_size, - byteorder=byteorder) - - -def generate_enum_array_field_accessor(field: ast.ArrayField) -> str: - """Parse the selected enum array field.""" - element_size = int(field.type.width / 8) - backing_type = get_cxx_scalar_type(field.type.width) - byteorder = field.parent.file.byteorder_short - return dedent("""\ - pdl::packet::slice span = {field_id}_; - std::vector<{enum_type}> elements; - while (span.size() >= {element_size}) {{ - elements.push_back({enum_type}(span.read_{byteorder}<{backing_type}, {element_size}>())); - }} - return elements;""").format(field_id=field.id, - enum_type=field.type_id, - backing_type=backing_type, - element_size=element_size, - byteorder=byteorder) - - -def generate_typedef_array_field_accessor(field: ast.ArrayField) -> str: - """Parse the selected typedef array field.""" - return dedent("""\ - pdl::packet::slice span = {field_id}_; - std::vector<{struct_type}> elements; - for (;;) {{ - {struct_type} element; - if (!{struct_type}::Parse(span, &element)) {{ - break; - }} - elements.emplace_back(std::move(element)); - }} - return elements;""").format(field_id=field.id, struct_type=field.type_id) - - -def generate_array_field_accessor(field: ast.ArrayField): - """Parse the selected array field.""" - - if field.width is not None: - return generate_scalar_array_field_accessor(field) - elif isinstance(field.type, ast.EnumDeclaration): - return generate_enum_array_field_accessor(field) - else: - return generate_typedef_array_field_accessor(field) - - -def generate_array_field_size_getters(decl: ast.Declaration) -> str: - """Generate size getters for array fields. Produces the serialized - size of the array in bytes.""" - - getters = [] - fields = core.get_unconstrained_parent_fields(decl) + decl.fields - for field in fields: - if not isinstance(field, ast.ArrayField): - continue - - element_width = field.width or core.get_declaration_size(field.type) - size = None - - if element_width and field.size: - size = int(element_width * field.size / 8) - elif element_width: - size = f"{field.id}_.size() * {int(element_width / 8)}" - - if size: - getters.append( - dedent("""\ - size_t Get{accessor_name}Size() const {{ - return {size}; - }} - """).format(accessor_name=to_pascal_case(field.id), size=size)) - else: - getters.append( - dedent("""\ - size_t Get{accessor_name}Size() const {{ - size_t array_size = 0; - for (size_t n = 0; n < {field_id}_.size(); n++) {{ - array_size += {field_id}_[n].GetSize(); - }} - return array_size; - }} - """).format(accessor_name=to_pascal_case(field.id), field_id=field.id)) - - return '\n'.join(getters) - - -def generate_packet_size_getter(decl: ast.Declaration) -> List[str]: - """Generate a size getter the current packet. Produces the serialized - size of the packet in bytes.""" - - constant_width = 0 - variable_width = [] - for f in core.get_packet_fields(decl): - field_size = core.get_field_size(f) - if field_size is not None: - constant_width += field_size - elif isinstance(f, (ast.PayloadField, ast.BodyField)): - variable_width.append("payload_.size()") - elif isinstance(f, ast.TypedefField): - variable_width.append(f"{f.id}_.GetSize()") - elif isinstance(f, ast.ArrayField): - variable_width.append(f"Get{to_pascal_case(f.id)}Size()") - else: - raise Exception("Unsupported field type") - - constant_width = int(constant_width / 8) - if not variable_width: - return [f"return {constant_width};"] - elif len(variable_width) == 1 and constant_width: - return [f"return {variable_width[0]} + {constant_width};"] - elif len(variable_width) == 1: - return [f"return {variable_width[0]};"] - elif len(variable_width) > 1 and constant_width: - return ([f"return {constant_width} + ("] + " +\n ".join(variable_width).split("\n") + [");"]) - elif len(variable_width) > 1: - return (["return ("] + " +\n ".join(variable_width).split("\n") + [");"]) - else: - assert False - - -def generate_packet_view_field_accessors(packet: ast.PacketDeclaration) -> List[str]: - """Return the declaration of accessors for the named packet fields.""" - - accessors = [] - - # Add accessors for the backed fields. - fields = core.get_unconstrained_parent_fields(packet) + packet.fields - for field in fields: - if isinstance(field, (ast.PayloadField, ast.BodyField)): - accessors.append( - dedent("""\ - std::vector GetPayload() const { - ASSERT(valid_); - return payload_.bytes(); - } - - """)) - elif isinstance(field, ast.ArrayField): - element_type = field.type_id or get_cxx_scalar_type(field.width) - accessor_name = to_pascal_case(field.id) - accessors.append( - dedent("""\ - std::vector<{element_type}> Get{accessor_name}() const {{ - ASSERT(valid_); - {accessor} - }} - - """).format(element_type=element_type, - accessor_name=accessor_name, - accessor=indent(generate_array_field_accessor(field), 1))) - elif isinstance(field, ast.ScalarField): - field_type = get_cxx_scalar_type(field.width) - accessor_name = to_pascal_case(field.id) - accessors.append( - dedent("""\ - {field_type} Get{accessor_name}() const {{ - ASSERT(valid_); - return {member_name}_; - }} - - """).format(field_type=field_type, accessor_name=accessor_name, member_name=field.id)) - elif isinstance(field, ast.TypedefField): - field_qualifier = "" if isinstance(field.type, ast.EnumDeclaration) else " const&" - accessor_name = to_pascal_case(field.id) - accessors.append( - dedent("""\ - {field_type}{field_qualifier} Get{accessor_name}() const {{ - ASSERT(valid_); - return {member_name}_; - }} - - """).format(field_type=field.type_id, - field_qualifier=field_qualifier, - accessor_name=accessor_name, - member_name=field.id)) - - # Add accessors for constrained parent fields. - # The accessors return a constant value in this case. - for c in core.get_parent_constraints(packet): - field = core.get_packet_field(packet, c.id) - if isinstance(field, ast.ScalarField): - field_type = get_cxx_scalar_type(field.width) - accessor_name = to_pascal_case(field.id) - accessors.append( - dedent("""\ - {field_type} Get{accessor_name}() const {{ - return {value}; - }} - - """).format(field_type=field_type, accessor_name=accessor_name, value=c.value)) - else: - accessor_name = to_pascal_case(field.id) - accessors.append( - dedent("""\ - {field_type} Get{accessor_name}() const {{ - return {field_type}::{tag_id}; - }} - - """).format(field_type=field.type_id, accessor_name=accessor_name, tag_id=c.tag_id)) - - return "".join(accessors) - - -def generate_packet_stringifier(packet: ast.PacketDeclaration) -> str: - """Generate the packet printer. TODO """ - return dedent("""\ - std::string ToString() const { - return ""; - } - """) - - -def generate_packet_view_field_parsers(packet: ast.PacketDeclaration) -> str: - """Generate the packet parser. The validator will extract - the fields it can in a pre-parsing phase. """ - - code = [] - - # Generate code to check the validity of the parent, - # and import parent fields that do not have a fixed value in the - # current packet. - if packet.parent: - code.append( - dedent("""\ - // Check validity of parent packet. - if (!parent.IsValid()) { - return false; - } - """)) - parent_fields = core.get_unconstrained_parent_fields(packet) - if parent_fields: - code.append("// Copy parent field values.") - for f in parent_fields: - code.append(f"{f.id}_ = parent.{f.id}_;") - code.append("") - span = "parent.payload_" - else: - span = "parent" - - # Validate parent constraints. - for c in packet.constraints: - if c.tag_id: - enum_type = core.get_packet_field(packet.parent, c.id).type_id - code.append( - dedent("""\ - if (parent.{field_id}_ != {enum_type}::{tag_id}) {{ - return false; - }} - """).format(field_id=c.id, enum_type=enum_type, tag_id=c.tag_id)) - else: - code.append( - dedent("""\ - if (parent.{field_id}_ != {value}) {{ - return false; - }} - """).format(field_id=c.id, value=c.value)) - - # Parse fields linearly. - if packet.fields: - code.append("// Parse packet field values.") - code.append(f"pdl::packet::slice span = {span};") - for f in packet.fields: - if isinstance(f, ast.SizeField): - code.append(f"{get_cxx_scalar_type(f.width)} {f.field_id}_size;") - elif isinstance(f, (ast.SizeField, ast.CountField)): - code.append(f"{get_cxx_scalar_type(f.width)} {f.field_id}_count;") - parser = FieldParser(extract_arrays=False, byteorder=packet.file.byteorder_short) - for f in packet.fields: - parser.parse(f) - parser.done() - code.extend(parser.code) - - code.append("return true;") - return '\n'.join(code) - - -def generate_packet_view_friend_classes(packet: ast.PacketDeclaration) -> str: - """Generate the list of friend declarations for a packet. - These are the direct children of the class.""" - - return [f"friend class {decl.id}View;" for (_, decl) in core.get_derived_packets(packet, traverse=False)] - - -def generate_packet_view(packet: ast.PacketDeclaration) -> str: - """Generate the implementation of the View class for a - packet declaration.""" - - parent_class = f"{packet.parent.id}View" if packet.parent else "pdl::packet::slice" - field_members = generate_packet_field_members(packet, view=True) - field_accessors = generate_packet_view_field_accessors(packet) - field_parsers = generate_packet_view_field_parsers(packet) - friend_classes = generate_packet_view_friend_classes(packet) - stringifier = generate_packet_stringifier(packet) - - return dedent("""\ - - class {packet_name}View {{ - public: - static {packet_name}View Create({parent_class} const& parent) {{ - return {packet_name}View(parent); - }} - - {field_accessors} - {stringifier} - - bool IsValid() const {{ - return valid_; - }} - - protected: - explicit {packet_name}View({parent_class} const& parent) {{ - valid_ = Parse(parent); - }} - - bool Parse({parent_class} const& parent) {{ - {field_parsers} - }} - - bool valid_{{false}}; - {field_members} - - {friend_classes} - }}; - """).format(packet_name=packet.id, - parent_class=parent_class, - field_accessors=indent(field_accessors, 1), - field_members=indent(field_members, 1), - field_parsers=indent(field_parsers, 2), - friend_classes=indent(friend_classes, 1), - stringifier=indent(stringifier, 1)) - - -def generate_packet_constructor(struct: ast.StructDeclaration, constructor_name: str) -> str: - """Generate the implementation of the constructor for a - struct declaration.""" - - constructor_params = [] - constructor_initializers = [] - fields = core.get_unconstrained_parent_fields(struct) + struct.fields - - for field in fields: - if isinstance(field, (ast.PayloadField, ast.BodyField)): - constructor_params.append("std::vector payload") - constructor_initializers.append("payload_(std::move(payload))") - elif isinstance(field, ast.ArrayField): - element_type = field.type_id or get_cxx_scalar_type(field.width) - constructor_params.append(f"std::vector<{element_type}> {field.id}") - constructor_initializers.append(f"{field.id}_(std::move({field.id}))") - elif isinstance(field, ast.ScalarField): - backing_type = get_cxx_scalar_type(field.width) - constructor_params.append(f"{backing_type} {field.id}") - constructor_initializers.append(f"{field.id}_({field.id})") - elif (isinstance(field, ast.TypedefField) and isinstance(field.type, ast.EnumDeclaration)): - constructor_params.append(f"{field.type_id} {field.id}") - constructor_initializers.append(f"{field.id}_({field.id})") - elif isinstance(field, ast.TypedefField): - constructor_params.append(f"{field.type_id} {field.id}") - constructor_initializers.append(f"{field.id}_(std::move({field.id}))") - - if not constructor_params: - return "" - - explicit = 'explicit ' if len(constructor_params) == 1 else '' - constructor_params = ', '.join(constructor_params) - constructor_initializers = ', '.join(constructor_initializers) - - return dedent("""\ - {explicit}{constructor_name}({constructor_params}) - : {constructor_initializers} {{}}""").format(explicit=explicit, - constructor_name=constructor_name, - constructor_params=constructor_params, - constructor_initializers=constructor_initializers) - - -def generate_packet_builder(packet: ast.PacketDeclaration) -> str: - """Generate the implementation of the Builder class for a - packet declaration.""" - - class_name = f'{packet.id}Builder' - builder_constructor = generate_packet_constructor(packet, constructor_name=class_name) - field_members = generate_packet_field_members(packet, view=False) - field_serializers = generate_packet_field_serializers(packet) - size_getter = generate_packet_size_getter(packet) - array_field_size_getters = generate_array_field_size_getters(packet) - - return dedent("""\ - - class {class_name} : public pdl::packet::Builder {{ - public: - ~{class_name}() override = default; - {class_name}() = default; - {class_name}({class_name} const&) = default; - {class_name}({class_name}&&) = default; - {class_name}& operator=({class_name} const&) = default; - {builder_constructor} - - void Serialize(std::vector& output) const override {{ - {field_serializers} - }} - - size_t GetSize() const override {{ - {size_getter} - }} - - {array_field_size_getters} - {field_members} - }}; - """).format(class_name=f'{packet.id}Builder', - builder_constructor=builder_constructor, - field_members=indent(field_members, 1), - field_serializers=indent(field_serializers, 2), - size_getter=indent(size_getter, 1), - array_field_size_getters=indent(array_field_size_getters, 1)) - - -def generate_struct_field_parsers(struct: ast.StructDeclaration) -> str: - """Generate the struct parser. The validator will extract - the fields it can in a pre-parsing phase. """ - - code = [] - parsed_fields = [] - post_processing = [] - - for field in struct.fields: - if isinstance(field, (ast.PayloadField, ast.BodyField)): - code.append("std::vector payload_;") - parsed_fields.append("std::move(payload_)") - elif isinstance(field, ast.ArrayField): - element_type = field.type_id or get_cxx_scalar_type(field.width) - code.append(f"std::vector<{element_type}> {field.id}_;") - parsed_fields.append(f"std::move({field.id}_)") - elif isinstance(field, ast.ScalarField): - backing_type = get_cxx_scalar_type(field.width) - code.append(f"{backing_type} {field.id}_;") - parsed_fields.append(f"{field.id}_") - elif (isinstance(field, ast.TypedefField) and isinstance(field.type, ast.EnumDeclaration)): - code.append(f"{field.type_id} {field.id}_;") - parsed_fields.append(f"{field.id}_") - elif isinstance(field, ast.TypedefField): - code.append(f"{field.type_id} {field.id}_;") - parsed_fields.append(f"std::move({field.id}_)") - elif isinstance(field, ast.SizeField): - code.append(f"{get_cxx_scalar_type(field.width)} {field.field_id}_size;") - elif isinstance(field, ast.CountField): - code.append(f"{get_cxx_scalar_type(field.width)} {field.field_id}_count;") - - parser = FieldParser(extract_arrays=True, byteorder=struct.file.byteorder_short) - for f in struct.fields: - parser.parse(f) - parser.done() - code.extend(parser.code) - - parsed_fields = ', '.join(parsed_fields) - code.append(f"*output = {struct.id}({parsed_fields});") - code.append("return true;") - return '\n'.join(code) - - -def generate_struct_declaration(struct: ast.StructDeclaration) -> str: - """Generate the implementation of the class for a - struct declaration.""" - - if struct.parent: - raise Exception("Struct declaration with parents are not supported") - - struct_constructor = generate_packet_constructor(struct, constructor_name=struct.id) - field_members = generate_packet_field_members(struct, view=False) - field_parsers = generate_struct_field_parsers(struct) - field_serializers = generate_packet_field_serializers(struct) - size_getter = generate_packet_size_getter(struct) - array_field_size_getters = generate_array_field_size_getters(struct) - stringifier = generate_packet_stringifier(struct) - - return dedent("""\ - - class {struct_name} : public pdl::packet::Builder {{ - public: - ~{struct_name}() override = default; - {struct_name}() = default; - {struct_name}({struct_name} const&) = default; - {struct_name}({struct_name}&&) = default; - {struct_name}& operator=({struct_name} const&) = default; - {struct_constructor} - - static bool Parse(pdl::packet::slice& span, {struct_name}* output) {{ - {field_parsers} - }} - - void Serialize(std::vector& output) const override {{ - {field_serializers} - }} - - size_t GetSize() const override {{ - {size_getter} - }} - - {array_field_size_getters} - {stringifier} - {field_members} - }}; - """).format(struct_name=struct.id, - struct_constructor=struct_constructor, - field_members=indent(field_members, 1), - field_parsers=indent(field_parsers, 2), - field_serializers=indent(field_serializers, 2), - stringifier=indent(stringifier, 1), - size_getter=indent(size_getter, 1), - array_field_size_getters=indent(array_field_size_getters, 1)) - - -def run(input: argparse.FileType, output: argparse.FileType, namespace: Optional[str], include_header: List[str], - using_namespace: List[str]): - - file = ast.File.from_json(json.load(input)) - core.desugar(file) - - include_header = '\n'.join([f'#include <{header}>' for header in include_header]) - using_namespace = '\n'.join([f'using namespace {namespace};' for namespace in using_namespace]) - open_namespace = f"namespace {namespace} {{" if namespace else "" - close_namespace = f"}} // {namespace}" if namespace else "" - - # Disable unsupported features in the canonical test suite. - skipped_decls = [ - 'Packet_Custom_Field_ConstantSize', - 'Packet_Custom_Field_VariableSize', - 'Packet_Checksum_Field_FromStart', - 'Packet_Checksum_Field_FromEnd', - 'Struct_Custom_Field_ConstantSize', - 'Struct_Custom_Field_VariableSize', - 'Struct_Checksum_Field_FromStart', - 'Struct_Checksum_Field_FromEnd', - 'Struct_Custom_Field_ConstantSize_', - 'Struct_Custom_Field_VariableSize_', - 'Struct_Checksum_Field_FromStart_', - 'Struct_Checksum_Field_FromEnd_', - 'PartialParent5', - 'PartialChild5_A', - 'PartialChild5_B', - 'PartialParent12', - 'PartialChild12_A', - 'PartialChild12_B', - ] - - output.write( - dedent("""\ - // File generated from {input_name}, with the command: - // {input_command} - // /!\\ Do not edit by hand - - #pragma once - - #include - #include - #include - #include - - #include - - {include_header} - {using_namespace} - - #ifndef ASSERT - #include - #define ASSERT assert - #endif // !ASSERT - - {open_namespace} - """).format(input_name=input.name, - input_command=' '.join(sys.argv), - include_header=include_header, - using_namespace=using_namespace, - open_namespace=open_namespace)) - - for d in file.declarations: - if d.id in skipped_decls: - continue - - if isinstance(d, ast.EnumDeclaration): - output.write(generate_enum_declaration(d)) - output.write(generate_enum_to_text(d)) - elif isinstance(d, ast.PacketDeclaration): - output.write(generate_packet_view(d)) - output.write(generate_packet_builder(d)) - elif isinstance(d, ast.StructDeclaration): - output.write(generate_struct_declaration(d)) - - output.write(f"{close_namespace}\n") - - -def main() -> int: - """Generate cxx PDL backend.""" - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('--input', type=argparse.FileType('r'), default=sys.stdin, help='Input PDL-JSON source') - parser.add_argument('--output', type=argparse.FileType('w'), default=sys.stdout, help='Output C++ file') - parser.add_argument('--namespace', type=str, help='Generated module namespace') - parser.add_argument('--include-header', type=str, default=[], action='append', help='Added include directives') - parser.add_argument('--using-namespace', - type=str, - default=[], - action='append', - help='Added using namespace statements') - return run(**vars(parser.parse_args())) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tools/pdl/scripts/generate_cxx_backend_tests.py b/tools/pdl/scripts/generate_cxx_backend_tests.py deleted file mode 100755 index 1f90600ac5b96230bdd0199abb0eaf9b3fca38ee..0000000000000000000000000000000000000000 --- a/tools/pdl/scripts/generate_cxx_backend_tests.py +++ /dev/null @@ -1,319 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2023 Google LLC -# -# 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 -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -from dataclasses import dataclass, field -import json -from pathlib import Path -import sys -from textwrap import dedent -from typing import List, Tuple, Union, Optional - -from pdl import ast, core -from pdl.utils import indent, to_pascal_case - - -def get_cxx_scalar_type(width: int) -> str: - """Return the cxx scalar type to be used to back a PDL type.""" - for n in [8, 16, 32, 64]: - if width <= n: - return f'uint{n}_t' - # PDL type does not fit on non-extended scalar types. - assert False - - -def generate_packet_parser_test(parser_test_suite: str, packet: ast.PacketDeclaration, tests: List[object]) -> str: - """Generate the implementation of unit tests for the selected packet.""" - - def parse_packet(packet: ast.PacketDeclaration) -> str: - parent = parse_packet(packet.parent) if packet.parent else "input" - return f"{packet.id}View::Create({parent})" - - def input_bytes(input: str) -> List[str]: - input = bytes.fromhex(input) - input_bytes = [] - for i in range(0, len(input), 16): - input_bytes.append(' '.join(f'0x{b:x},' for b in input[i:i + 16])) - return input_bytes - - def get_field(decl: ast.Declaration, var: str, id: str) -> str: - if isinstance(decl, ast.StructDeclaration): - return f"{var}.{id}_" - else: - return f"{var}.Get{to_pascal_case(id)}()" - - def check_members(decl: ast.Declaration, var: str, expected: object) -> List[str]: - checks = [] - for (id, value) in expected.items(): - field = core.get_packet_field(decl, id) - sanitized_var = var.replace('[', '_').replace(']', '') - field_var = f'{sanitized_var}_{id}' - - if isinstance(field, ast.ScalarField): - checks.append(f"ASSERT_EQ({get_field(decl, var, id)}, {value});") - - elif (isinstance(field, ast.TypedefField) and - isinstance(field.type, (ast.EnumDeclaration, ast.CustomFieldDeclaration, ast.ChecksumDeclaration))): - checks.append(f"ASSERT_EQ({get_field(decl, var, id)}, {field.type_id}({value}));") - - elif isinstance(field, ast.TypedefField): - checks.append(f"{field.type_id} const& {field_var} = {get_field(decl, var, id)};") - checks.extend(check_members(field.type, field_var, value)) - - elif isinstance(field, (ast.PayloadField, ast.BodyField)): - checks.append(f"std::vector expected_{field_var} {{") - for i in range(0, len(value), 16): - checks.append(' ' + ' '.join([f"0x{v:x}," for v in value[i:i + 16]])) - checks.append("};") - checks.append(f"ASSERT_EQ({get_field(decl, var, id)}, expected_{field_var});") - - elif isinstance(field, ast.ArrayField) and field.width: - checks.append(f"std::vector<{get_cxx_scalar_type(field.width)}> expected_{field_var} {{") - step = int(16 * 8 / field.width) - for i in range(0, len(value), step): - checks.append(' ' + ' '.join([f"0x{v:x}," for v in value[i:i + step]])) - checks.append("};") - checks.append(f"ASSERT_EQ({get_field(decl, var, id)}, expected_{field_var});") - - elif (isinstance(field, ast.ArrayField) and isinstance(field.type, ast.EnumDeclaration)): - checks.append(f"std::vector<{field.type_id}> expected_{field_var} {{") - for v in value: - checks.append(f" {field.type_id}({v}),") - checks.append("};") - checks.append(f"ASSERT_EQ({get_field(decl, var, id)}, expected_{field_var});") - - elif isinstance(field, ast.ArrayField): - checks.append(f"std::vector<{field.type_id}> {field_var} = {get_field(decl, var, id)};") - checks.append(f"ASSERT_EQ({field_var}.size(), {len(value)});") - for (n, value) in enumerate(value): - checks.extend(check_members(field.type, f"{field_var}[{n}]", value)) - - else: - pass - - return checks - - generated_tests = [] - for (test_nr, test) in enumerate(tests): - child_packet_id = test.get('packet', packet.id) - child_packet = packet.file.packet_scope[child_packet_id] - - generated_tests.append( - dedent("""\ - - TEST_F({parser_test_suite}, {packet_id}_Case{test_nr}) {{ - pdl::packet::slice input(std::shared_ptr>(new std::vector {{ - {input_bytes} - }})); - {child_packet_id}View packet = {parse_packet}; - ASSERT_TRUE(packet.IsValid()); - {checks} - }} - """).format(parser_test_suite=parser_test_suite, - packet_id=packet.id, - child_packet_id=child_packet_id, - test_nr=test_nr, - input_bytes=indent(input_bytes(test['packed']), 2), - parse_packet=parse_packet(child_packet), - checks=indent(check_members(packet, 'packet', test['unpacked']), 1))) - - return ''.join(generated_tests) - - -def generate_packet_serializer_test(serializer_test_suite: str, packet: ast.PacketDeclaration, - tests: List[object]) -> str: - """Generate the implementation of unit tests for the selected packet.""" - - def build_packet(decl: ast.Declaration, var: str, initializer: object) -> (str, List[str]): - fields = core.get_unconstrained_parent_fields(decl) + decl.fields - declarations = [] - parameters = [] - for field in fields: - sanitized_var = var.replace('[', '_').replace(']', '') - field_id = getattr(field, 'id', None) - field_var = f'{sanitized_var}_{field_id}' - value = initializer['payload'] if isinstance(field, (ast.PayloadField, - ast.BodyField)) else initializer.get(field_id, None) - - if isinstance(field, ast.ScalarField): - parameters.append(f"{value}") - - elif isinstance(field, ast.TypedefField) and isinstance(field.type, ast.EnumDeclaration): - parameters.append(f"{field.type_id}({value})") - - elif isinstance(field, ast.TypedefField): - (element, intermediate_declarations) = build_packet(field.type, field_var, value) - declarations.extend(intermediate_declarations) - parameters.append(element) - - elif isinstance(field, (ast.PayloadField, ast.BodyField)): - declarations.append(f"std::vector {field_var} {{") - for i in range(0, len(value), 16): - declarations.append(' ' + ' '.join([f"0x{v:x}," for v in value[i:i + 16]])) - declarations.append("};") - parameters.append(f"std::move({field_var})") - - elif isinstance(field, ast.ArrayField) and field.width: - declarations.append(f"std::vector<{get_cxx_scalar_type(field.width)}> {field_var} {{") - step = int(16 * 8 / field.width) - for i in range(0, len(value), step): - declarations.append(' ' + ' '.join([f"0x{v:x}," for v in value[i:i + step]])) - declarations.append("};") - parameters.append(f"std::move({field_var})") - - elif isinstance(field, ast.ArrayField) and isinstance(field.type, ast.EnumDeclaration): - declarations.append(f"std::vector<{field.type_id}> {field_var} {{") - for v in value: - declarations.append(f" {field.type_id}({v}),") - declarations.append("};") - parameters.append(f"std::move({field_var})") - - elif isinstance(field, ast.ArrayField): - elements = [] - for (n, value) in enumerate(value): - (element, intermediate_declarations) = build_packet(field.type, f'{field_var}_{n}', value) - elements.append(element) - declarations.extend(intermediate_declarations) - declarations.append(f"std::vector<{field.type_id}> {field_var} {{") - for element in elements: - declarations.append(f" {element},") - declarations.append("};") - parameters.append(f"std::move({field_var})") - - else: - pass - - constructor_name = f'{decl.id}Builder' if isinstance(decl, ast.PacketDeclaration) else decl.id - return (f"{constructor_name}({', '.join(parameters)})", declarations) - - def output_bytes(output: str) -> List[str]: - output = bytes.fromhex(output) - output_bytes = [] - for i in range(0, len(output), 16): - output_bytes.append(' '.join(f'0x{b:x},' for b in output[i:i + 16])) - return output_bytes - - generated_tests = [] - for (test_nr, test) in enumerate(tests): - child_packet_id = test.get('packet', packet.id) - child_packet = packet.file.packet_scope[child_packet_id] - - (built_packet, intermediate_declarations) = build_packet(child_packet, 'packet', test['unpacked']) - generated_tests.append( - dedent("""\ - - TEST_F({serializer_test_suite}, {packet_id}_Case{test_nr}) {{ - std::vector expected_output {{ - {output_bytes} - }}; - {intermediate_declarations} - {child_packet_id}Builder packet = {built_packet}; - ASSERT_EQ(packet.pdl::packet::Builder::Serialize(), expected_output); - }} - """).format(serializer_test_suite=serializer_test_suite, - packet_id=packet.id, - child_packet_id=child_packet_id, - test_nr=test_nr, - output_bytes=indent(output_bytes(test['packed']), 2), - built_packet=built_packet, - intermediate_declarations=indent(intermediate_declarations, 1))) - - return ''.join(generated_tests) - - -def run(input: argparse.FileType, output: argparse.FileType, test_vectors: argparse.FileType, include_header: List[str], - using_namespace: List[str], namespace: str, parser_test_suite: str, serializer_test_suite: str): - - file = ast.File.from_json(json.load(input)) - tests = json.load(test_vectors) - core.desugar(file) - - include_header = '\n'.join([f'#include <{header}>' for header in include_header]) - using_namespace = '\n'.join([f'using namespace {namespace};' for namespace in using_namespace]) - - skipped_tests = [ - 'Packet_Checksum_Field_FromStart', - 'Packet_Checksum_Field_FromEnd', - 'Struct_Checksum_Field_FromStart', - 'Struct_Checksum_Field_FromEnd', - 'PartialParent5', - 'PartialParent12', - ] - - output.write( - dedent("""\ - // File generated from {input_name} and {test_vectors_name}, with the command: - // {input_command} - // /!\\ Do not edit by hand - - #include - #include - #include - #include - - {include_header} - {using_namespace} - - namespace {namespace} {{ - - class {parser_test_suite} : public testing::Test {{}}; - class {serializer_test_suite} : public testing::Test {{}}; - """).format(parser_test_suite=parser_test_suite, - serializer_test_suite=serializer_test_suite, - input_name=input.name, - input_command=' '.join(sys.argv), - test_vectors_name=test_vectors.name, - include_header=include_header, - using_namespace=using_namespace, - namespace=namespace)) - - for decl in file.declarations: - if decl.id in skipped_tests: - continue - - if isinstance(decl, ast.PacketDeclaration): - matching_tests = [test['tests'] for test in tests if test['packet'] == decl.id] - matching_tests = [test for test_list in matching_tests for test in test_list] - if matching_tests: - output.write(generate_packet_parser_test(parser_test_suite, decl, matching_tests)) - output.write(generate_packet_serializer_test(serializer_test_suite, decl, matching_tests)) - - output.write(f"}} // namespace {namespace}\n") - - -def main() -> int: - """Generate cxx PDL backend.""" - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('--input', type=argparse.FileType('r'), default=sys.stdin, help='Input PDL-JSON source') - parser.add_argument('--output', type=argparse.FileType('w'), default=sys.stdout, help='Output C++ file') - parser.add_argument('--test-vectors', type=argparse.FileType('r'), required=True, help='Input PDL test file') - parser.add_argument('--namespace', type=str, default='pdl', help='Namespace of the generated file') - parser.add_argument('--parser-test-suite', type=str, default='ParserTest', help='Name of the parser test suite') - parser.add_argument('--serializer-test-suite', - type=str, - default='SerializerTest', - help='Name of the serializer test suite') - parser.add_argument('--include-header', type=str, default=[], action='append', help='Added include directives') - parser.add_argument('--using-namespace', - type=str, - default=[], - action='append', - help='Added using namespace statements') - return run(**vars(parser.parse_args())) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tools/pdl/scripts/generate_python_backend.py b/tools/pdl/scripts/generate_python_backend.py deleted file mode 100755 index 3a1a82bb886bb9c726b376b907448d7e22c3e9fb..0000000000000000000000000000000000000000 --- a/tools/pdl/scripts/generate_python_backend.py +++ /dev/null @@ -1,1059 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2023 Google LLC -# -# 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 -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -from dataclasses import dataclass, field -import json -from pathlib import Path -import sys -from textwrap import dedent -from typing import List, Tuple, Union, Optional - -from pdl import ast, core -from pdl.utils import indent - - -def mask(width: int) -> str: - return hex((1 << width) - 1) - - -def generate_prelude() -> str: - return dedent("""\ - from dataclasses import dataclass, field, fields - from typing import Optional, List, Tuple - import enum - import inspect - import math - - @dataclass - class Packet: - payload: Optional[bytes] = field(repr=False, default_factory=bytes, compare=False) - - @classmethod - def parse_all(cls, span: bytes) -> 'Packet': - packet, remain = getattr(cls, 'parse')(span) - if len(remain) > 0: - raise Exception('Unexpected parsing remainder') - return packet - - @property - def size(self) -> int: - pass - - def show(self, prefix: str = ''): - print(f'{self.__class__.__name__}') - - def print_val(p: str, pp: str, name: str, align: int, typ, val): - if name == 'payload': - pass - - # Scalar fields. - elif typ is int: - print(f'{p}{name:{align}} = {val} (0x{val:x})') - - # Byte fields. - elif typ is bytes: - print(f'{p}{name:{align}} = [', end='') - line = '' - n_pp = '' - for (idx, b) in enumerate(val): - if idx > 0 and idx % 8 == 0: - print(f'{n_pp}{line}') - line = '' - n_pp = pp + (' ' * (align + 4)) - line += f' {b:02x}' - print(f'{n_pp}{line} ]') - - # Enum fields. - elif inspect.isclass(typ) and issubclass(typ, enum.IntEnum): - print(f'{p}{name:{align}} = {typ.__name__}::{val.name} (0x{val:x})') - - # Struct fields. - elif inspect.isclass(typ) and issubclass(typ, globals().get('Packet')): - print(f'{p}{name:{align}} = ', end='') - val.show(prefix=pp) - - # Array fields. - elif getattr(typ, '__origin__', None) == list: - print(f'{p}{name:{align}}') - last = len(val) - 1 - align = 5 - for (idx, elt) in enumerate(val): - n_p = pp + ('├── ' if idx != last else '└── ') - n_pp = pp + ('│ ' if idx != last else ' ') - print_val(n_p, n_pp, f'[{idx}]', align, typ.__args__[0], val[idx]) - - # Custom fields. - elif inspect.isclass(typ): - print(f'{p}{name:{align}} = {repr(val)}') - - else: - print(f'{p}{name:{align}} = ##{typ}##') - - last = len(fields(self)) - 1 - align = max(len(f.name) for f in fields(self) if f.name != 'payload') - - for (idx, f) in enumerate(fields(self)): - p = prefix + ('├── ' if idx != last else '└── ') - pp = prefix + ('│ ' if idx != last else ' ') - val = getattr(self, f.name) - - print_val(p, pp, f.name, align, f.type, val) - """) - - -@dataclass -class FieldParser: - byteorder: str - offset: int = 0 - shift: int = 0 - chunk: List[Tuple[int, int, ast.Field]] = field(default_factory=lambda: []) - unchecked_code: List[str] = field(default_factory=lambda: []) - code: List[str] = field(default_factory=lambda: []) - - def unchecked_append_(self, line: str): - """Append unchecked field parsing code. - The function check_size_ must be called to generate a size guard - after parsing is completed.""" - self.unchecked_code.append(line) - - def append_(self, line: str): - """Append field parsing code. - There must be no unchecked code left before this function is called.""" - assert len(self.unchecked_code) == 0 - self.code.append(line) - - def check_size_(self, size: str): - """Generate a check of the current span size.""" - self.append_(f"if len(span) < {size}:") - self.append_(f" raise Exception('Invalid packet size')") - - def check_code_(self): - """Generate a size check for pending field parsing.""" - if len(self.unchecked_code) > 0: - assert len(self.chunk) == 0 - unchecked_code = self.unchecked_code - self.unchecked_code = [] - self.check_size_(str(self.offset)) - self.code.extend(unchecked_code) - - def consume_span_(self, keep: int = 0) -> str: - """Skip consumed span bytes.""" - if self.offset > 0: - self.check_code_() - self.append_(f'span = span[{self.offset - keep}:]') - self.offset = 0 - - def parse_array_element_dynamic_(self, field: ast.ArrayField, span: str): - """Parse a single array field element of variable size.""" - if isinstance(field.type, ast.StructDeclaration): - self.append_(f" element, {span} = {field.type_id}.parse({span})") - self.append_(f" {field.id}.append(element)") - else: - raise Exception(f'Unexpected array element type {field.type_id} {field.width}') - - def parse_array_element_static_(self, field: ast.ArrayField, span: str): - """Parse a single array field element of constant size.""" - if field.width is not None: - element = f"int.from_bytes({span}, byteorder='{self.byteorder}')" - self.append_(f" {field.id}.append({element})") - elif isinstance(field.type, ast.EnumDeclaration): - element = f"int.from_bytes({span}, byteorder='{self.byteorder}')" - element = f"{field.type_id}({element})" - self.append_(f" {field.id}.append({element})") - else: - element = f"{field.type_id}.parse_all({span})" - self.append_(f" {field.id}.append({element})") - - def parse_byte_array_field_(self, field: ast.ArrayField): - """Parse the selected u8 array field.""" - array_size = core.get_array_field_size(field) - padded_size = field.padded_size - - # Shift the span to reset the offset to 0. - self.consume_span_() - - # Derive the array size. - if isinstance(array_size, int): - size = array_size - elif isinstance(array_size, ast.SizeField): - size = f'{field.id}_size - {field.size_modifier}' if field.size_modifier else f'{field.id}_size' - elif isinstance(array_size, ast.CountField): - size = f'{field.id}_count' - else: - size = None - - # Parse from the padded array if padding is present. - if padded_size and size is not None: - self.check_size_(padded_size) - self.append_(f"if {size} > {padded_size}:") - self.append_(" raise Exception('Array size is larger than the padding size')") - self.append_(f"fields['{field.id}'] = list(span[:{size}])") - self.append_(f"span = span[{padded_size}:]") - - elif size is not None: - self.check_size_(size) - self.append_(f"fields['{field.id}'] = list(span[:{size}])") - self.append_(f"span = span[{size}:]") - - else: - self.append_(f"fields['{field.id}'] = list(span)") - self.append_(f"span = bytes()") - - def parse_array_field_(self, field: ast.ArrayField): - """Parse the selected array field.""" - array_size = core.get_array_field_size(field) - element_width = core.get_array_element_size(field) - padded_size = field.padded_size - - if element_width: - if element_width % 8 != 0: - raise Exception('Array element size is not a multiple of 8') - element_width = int(element_width / 8) - - if isinstance(array_size, int): - size = None - count = array_size - elif isinstance(array_size, ast.SizeField): - size = f'{field.id}_size' - count = None - elif isinstance(array_size, ast.CountField): - size = None - count = f'{field.id}_count' - else: - size = None - count = None - - # Shift the span to reset the offset to 0. - self.consume_span_() - - # Apply the size modifier. - if field.size_modifier and size: - self.append_(f"{size} = {size} - {field.size_modifier}") - - # Parse from the padded array if padding is present. - if padded_size: - self.check_size_(padded_size) - self.append_(f"remaining_span = span[{padded_size}:]") - self.append_(f"span = span[:{padded_size}]") - - # The element width is not known, but the array full octet size - # is known by size field. Parse elements item by item as a vector. - if element_width is None and size is not None: - self.check_size_(size) - self.append_(f"array_span = span[:{size}]") - self.append_(f"{field.id} = []") - self.append_("while len(array_span) > 0:") - self.parse_array_element_dynamic_(field, 'array_span') - self.append_(f"fields['{field.id}'] = {field.id}") - self.append_(f"span = span[{size}:]") - - # The element width is not known, but the array element count - # is known statically or by count field. - # Parse elements item by item as a vector. - elif element_width is None and count is not None: - self.append_(f"{field.id} = []") - self.append_(f"for n in range({count}):") - self.parse_array_element_dynamic_(field, 'span') - self.append_(f"fields['{field.id}'] = {field.id}") - - # Neither the count not size is known, - # parse elements until the end of the span. - elif element_width is None: - self.append_(f"{field.id} = []") - self.append_("while len(span) > 0:") - self.parse_array_element_dynamic_(field, 'span') - self.append_(f"fields['{field.id}'] = {field.id}") - - # The element width is known, and the array element count is known - # statically, or by count field. - elif count is not None: - array_size = (f'{count}' if element_width == 1 else f'{count} * {element_width}') - self.check_size_(array_size) - self.append_(f"{field.id} = []") - self.append_(f"for n in range({count}):") - span = ('span[n:n + 1]' if element_width == 1 else f'span[n * {element_width}:(n + 1) * {element_width}]') - self.parse_array_element_static_(field, span) - self.append_(f"fields['{field.id}'] = {field.id}") - self.append_(f"span = span[{array_size}:]") - - # The element width is known, and the array full size is known - # by size field, or unknown (in which case it is the remaining span - # length). - else: - if size is not None: - self.check_size_(size) - array_size = size or 'len(span)' - if element_width != 1: - self.append_(f"if {array_size} % {element_width} != 0:") - self.append_(" raise Exception('Array size is not a multiple of the element size')") - self.append_(f"{field.id}_count = int({array_size} / {element_width})") - array_count = f'{field.id}_count' - else: - array_count = array_size - self.append_(f"{field.id} = []") - self.append_(f"for n in range({array_count}):") - span = ('span[n:n + 1]' if element_width == 1 else f'span[n * {element_width}:(n + 1) * {element_width}]') - self.parse_array_element_static_(field, span) - self.append_(f"fields['{field.id}'] = {field.id}") - if size is not None: - self.append_(f"span = span[{size}:]") - else: - self.append_(f"span = bytes()") - - # Drop the padding - if padded_size: - self.append_(f"span = remaining_span") - - def parse_bit_field_(self, field: ast.Field): - """Parse the selected field as a bit field. - The field is added to the current chunk. When a byte boundary - is reached all saved fields are extracted together.""" - - # Add to current chunk. - width = core.get_field_size(field) - self.chunk.append((self.shift, width, field)) - self.shift += width - - # Wait for more fields if not on a byte boundary. - if (self.shift % 8) != 0: - return - - # Parse the backing integer using the configured endiannes, - # extract field values. - size = int(self.shift / 8) - end_offset = self.offset + size - - if size == 1: - value = f"span[{self.offset}]" - else: - span = f"span[{self.offset}:{end_offset}]" - self.unchecked_append_(f"value_ = int.from_bytes({span}, byteorder='{self.byteorder}')") - value = "value_" - - for shift, width, field in self.chunk: - v = (value if len(self.chunk) == 1 and shift == 0 else f"({value} >> {shift}) & {mask(width)}") - - if isinstance(field, ast.ScalarField): - self.unchecked_append_(f"fields['{field.id}'] = {v}") - elif isinstance(field, ast.FixedField) and field.enum_id: - self.unchecked_append_(f"if {v} != {field.enum_id}.{field.tag_id}:") - self.unchecked_append_(f" raise Exception('Unexpected fixed field value')") - elif isinstance(field, ast.FixedField): - self.unchecked_append_(f"if {v} != {hex(field.value)}:") - self.unchecked_append_(f" raise Exception('Unexpected fixed field value')") - elif isinstance(field, ast.TypedefField): - self.unchecked_append_(f"fields['{field.id}'] = {field.type_id}({v})") - elif isinstance(field, ast.SizeField): - self.unchecked_append_(f"{field.field_id}_size = {v}") - elif isinstance(field, ast.CountField): - self.unchecked_append_(f"{field.field_id}_count = {v}") - elif isinstance(field, ast.ReservedField): - pass - else: - raise Exception(f'Unsupported bit field type {field.kind}') - - # Reset state. - self.offset = end_offset - self.shift = 0 - self.chunk = [] - - def parse_typedef_field_(self, field: ast.TypedefField): - """Parse a typedef field, to the exclusion of Enum fields.""" - - if self.shift != 0: - raise Exception('Typedef field does not start on an octet boundary') - if (isinstance(field.type, ast.StructDeclaration) and field.type.parent_id is not None): - raise Exception('Derived struct used in typedef field') - - width = core.get_declaration_size(field.type) - if width is None: - self.consume_span_() - self.append_(f"{field.id}, span = {field.type_id}.parse(span)") - self.append_(f"fields['{field.id}'] = {field.id}") - else: - if width % 8 != 0: - raise Exception('Typedef field type size is not a multiple of 8') - width = int(width / 8) - end_offset = self.offset + width - # Checksum value field is generated alongside checksum start. - # Deal with this field as padding. - if not isinstance(field.type, ast.ChecksumDeclaration): - span = f'span[{self.offset}:{end_offset}]' - self.unchecked_append_(f"fields['{field.id}'] = {field.type_id}.parse_all({span})") - self.offset = end_offset - - def parse_payload_field_(self, field: Union[ast.BodyField, ast.PayloadField]): - """Parse body and payload fields.""" - - payload_size = core.get_payload_field_size(field) - offset_from_end = core.get_field_offset_from_end(field) - - # If the payload is not byte aligned, do parse the bit fields - # that can be extracted, but do not consume the input bytes as - # they will also be included in the payload span. - if self.shift != 0: - if payload_size: - raise Exception("Unexpected payload size for non byte aligned payload") - - rounded_size = int((self.shift + 7) / 8) - padding_bits = 8 * rounded_size - self.shift - self.parse_bit_field_(core.make_reserved_field(padding_bits)) - self.consume_span_(rounded_size) - else: - self.consume_span_() - - # The payload or body has a known size. - # Consume the payload and update the span in case - # fields are placed after the payload. - if payload_size: - if getattr(field, 'size_modifier', None): - self.append_(f"{field.id}_size -= {field.size_modifier}") - self.check_size_(f'{field.id}_size') - self.append_(f"payload = span[:{field.id}_size]") - self.append_(f"span = span[{field.id}_size:]") - # The payload or body is the last field of a packet, - # consume the remaining span. - elif offset_from_end == 0: - self.append_(f"payload = span") - self.append_(f"span = bytes([])") - # The payload or body is followed by fields of static size. - # Consume the span that is not reserved for the following fields. - elif offset_from_end is not None: - if (offset_from_end % 8) != 0: - raise Exception('Payload field offset from end of packet is not a multiple of 8') - offset_from_end = int(offset_from_end / 8) - self.check_size_(f'{offset_from_end}') - self.append_(f"payload = span[:-{offset_from_end}]") - self.append_(f"span = span[-{offset_from_end}:]") - self.append_(f"fields['payload'] = payload") - - def parse_checksum_field_(self, field: ast.ChecksumField): - """Generate a checksum check.""" - - # The checksum value field can be read starting from the current - # offset if the fields in between are of fixed size, or from the end - # of the span otherwise. - self.consume_span_() - value_field = core.get_packet_field(field.parent, field.field_id) - offset_from_start = 0 - offset_from_end = 0 - start_index = field.parent.fields.index(field) - value_index = field.parent.fields.index(value_field) - value_size = int(core.get_field_size(value_field) / 8) - - for f in field.parent.fields[start_index + 1:value_index]: - size = core.get_field_size(f) - if size is None: - offset_from_start = None - break - else: - offset_from_start += size - - trailing_fields = field.parent.fields[value_index:] - trailing_fields.reverse() - for f in trailing_fields: - size = core.get_field_size(f) - if size is None: - offset_from_end = None - break - else: - offset_from_end += size - - if offset_from_start is not None: - if offset_from_start % 8 != 0: - raise Exception('Checksum value field is not aligned to an octet boundary') - offset_from_start = int(offset_from_start / 8) - checksum_span = f'span[:{offset_from_start}]' - if value_size > 1: - start = offset_from_start - end = offset_from_start + value_size - value = f"int.from_bytes(span[{start}:{end}], byteorder='{self.byteorder}')" - else: - value = f'span[{offset_from_start}]' - self.check_size_(offset_from_start + value_size) - - elif offset_from_end is not None: - sign = '' - if offset_from_end % 8 != 0: - raise Exception('Checksum value field is not aligned to an octet boundary') - offset_from_end = int(offset_from_end / 8) - checksum_span = f'span[:-{offset_from_end}]' - if value_size > 1: - start = offset_from_end - end = offset_from_end - value_size - value = f"int.from_bytes(span[-{start}:-{end}], byteorder='{self.byteorder}')" - else: - value = f'span[-{offset_from_end}]' - self.check_size_(offset_from_end) - - else: - raise Exception('Checksum value field cannot be read at constant offset') - - self.append_(f"{value_field.id} = {value}") - self.append_(f"fields['{value_field.id}'] = {value_field.id}") - self.append_(f"computed_{value_field.id} = {value_field.type.function}({checksum_span})") - self.append_(f"if computed_{value_field.id} != {value_field.id}:") - self.append_(" raise Exception(f'Invalid checksum computation:" + - f" {{computed_{value_field.id}}} != {{{value_field.id}}}')") - - def parse(self, field: ast.Field): - # Field has bit granularity. - # Append the field to the current chunk, - # check if a byte boundary was reached. - if core.is_bit_field(field): - self.parse_bit_field_(field) - - # Padding fields. - elif isinstance(field, ast.PaddingField): - pass - - # Array fields. - elif isinstance(field, ast.ArrayField) and field.width == 8: - self.parse_byte_array_field_(field) - - elif isinstance(field, ast.ArrayField): - self.parse_array_field_(field) - - # Other typedef fields. - elif isinstance(field, ast.TypedefField): - self.parse_typedef_field_(field) - - # Payload and body fields. - elif isinstance(field, (ast.PayloadField, ast.BodyField)): - self.parse_payload_field_(field) - - # Checksum fields. - elif isinstance(field, ast.ChecksumField): - self.parse_checksum_field_(field) - - else: - raise Exception(f'Unimplemented field type {field.kind}') - - def done(self): - self.consume_span_() - - -@dataclass -class FieldSerializer: - byteorder: str - shift: int = 0 - value: List[str] = field(default_factory=lambda: []) - code: List[str] = field(default_factory=lambda: []) - indent: int = 0 - - def indent_(self): - self.indent += 1 - - def unindent_(self): - self.indent -= 1 - - def append_(self, line: str): - """Append field serializing code.""" - lines = line.split('\n') - self.code.extend([' ' * self.indent + line for line in lines]) - - def extend_(self, value: str, length: int): - """Append data to the span being constructed.""" - if length == 1: - self.append_(f"_span.append({value})") - else: - self.append_(f"_span.extend(int.to_bytes({value}, length={length}, byteorder='{self.byteorder}'))") - - def serialize_array_element_(self, field: ast.ArrayField): - """Serialize a single array field element.""" - if field.width is not None: - length = int(field.width / 8) - self.extend_('_elt', length) - elif isinstance(field.type, ast.EnumDeclaration): - length = int(field.type.width / 8) - self.extend_('_elt', length) - else: - self.append_("_span.extend(_elt.serialize())") - - def serialize_array_field_(self, field: ast.ArrayField): - """Serialize the selected array field.""" - if field.padded_size: - self.append_(f"_{field.id}_start = len(_span)") - - if field.width == 8: - self.append_(f"_span.extend(self.{field.id})") - else: - self.append_(f"for _elt in self.{field.id}:") - self.indent_() - self.serialize_array_element_(field) - self.unindent_() - - if field.padded_size: - self.append_(f"_span.extend([0] * ({field.padded_size} - len(_span) + _{field.id}_start))") - - def serialize_bit_field_(self, field: ast.Field): - """Serialize the selected field as a bit field. - The field is added to the current chunk. When a byte boundary - is reached all saved fields are serialized together.""" - - # Add to current chunk. - width = core.get_field_size(field) - shift = self.shift - - if isinstance(field, str): - self.value.append(f"({field} << {shift})") - elif isinstance(field, ast.ScalarField): - max_value = (1 << field.width) - 1 - self.append_(f"if self.{field.id} > {max_value}:") - self.append_(f" print(f\"Invalid value for field {field.parent.id}::{field.id}:" + - f" {{self.{field.id}}} > {max_value}; the value will be truncated\")") - self.append_(f" self.{field.id} &= {max_value}") - self.value.append(f"(self.{field.id} << {shift})") - elif isinstance(field, ast.FixedField) and field.enum_id: - self.value.append(f"({field.enum_id}.{field.tag_id} << {shift})") - elif isinstance(field, ast.FixedField): - self.value.append(f"({field.value} << {shift})") - elif isinstance(field, ast.TypedefField): - self.value.append(f"(self.{field.id} << {shift})") - - elif isinstance(field, ast.SizeField): - max_size = (1 << field.width) - 1 - value_field = core.get_packet_field(field.parent, field.field_id) - size_modifier = '' - - if getattr(value_field, 'size_modifier', None): - size_modifier = f' + {value_field.size_modifier}' - - if isinstance(value_field, (ast.PayloadField, ast.BodyField)): - self.append_(f"_payload_size = len(payload or self.payload or []){size_modifier}") - self.append_(f"if _payload_size > {max_size}:") - self.append_(f" print(f\"Invalid length for payload field:" + - f" {{_payload_size}} > {max_size}; the packet cannot be generated\")") - self.append_(f" raise Exception(\"Invalid payload length\")") - array_size = "_payload_size" - elif isinstance(value_field, ast.ArrayField) and value_field.width: - array_size = f"(len(self.{value_field.id}) * {int(value_field.width / 8)}{size_modifier})" - elif isinstance(value_field, ast.ArrayField) and isinstance(value_field.type, ast.EnumDeclaration): - array_size = f"(len(self.{value_field.id}) * {int(value_field.type.width / 8)}{size_modifier})" - elif isinstance(value_field, ast.ArrayField): - self.append_( - f"_{value_field.id}_size = sum([elt.size for elt in self.{value_field.id}]){size_modifier}") - array_size = f"_{value_field.id}_size" - else: - raise Exception("Unsupported field type") - self.value.append(f"({array_size} << {shift})") - - elif isinstance(field, ast.CountField): - max_count = (1 << field.width) - 1 - self.append_(f"if len(self.{field.field_id}) > {max_count}:") - self.append_(f" print(f\"Invalid length for field {field.parent.id}::{field.field_id}:" + - f" {{len(self.{field.field_id})}} > {max_count}; the array will be truncated\")") - self.append_(f" del self.{field.field_id}[{max_count}:]") - self.value.append(f"(len(self.{field.field_id}) << {shift})") - elif isinstance(field, ast.ReservedField): - pass - else: - raise Exception(f'Unsupported bit field type {field.kind}') - - # Check if a byte boundary is reached. - self.shift += width - if (self.shift % 8) == 0: - self.pack_bit_fields_() - - def pack_bit_fields_(self): - """Pack serialized bit fields.""" - - # Should have an integral number of bytes now. - assert (self.shift % 8) == 0 - - # Generate the backing integer, and serialize it - # using the configured endiannes, - size = int(self.shift / 8) - - if len(self.value) == 0: - self.append_(f"_span.extend([0] * {size})") - elif len(self.value) == 1: - self.extend_(self.value[0], size) - else: - self.append_(f"_value = (") - self.append_(" " + " |\n ".join(self.value)) - self.append_(")") - self.extend_('_value', size) - - # Reset state. - self.shift = 0 - self.value = [] - - def serialize_typedef_field_(self, field: ast.TypedefField): - """Serialize a typedef field, to the exclusion of Enum fields.""" - - if self.shift != 0: - raise Exception('Typedef field does not start on an octet boundary') - if (isinstance(field.type, ast.StructDeclaration) and field.type.parent_id is not None): - raise Exception('Derived struct used in typedef field') - - if isinstance(field.type, ast.ChecksumDeclaration): - size = int(field.type.width / 8) - self.append_(f"_checksum = {field.type.function}(_span[_checksum_start:])") - self.extend_('_checksum', size) - else: - self.append_(f"_span.extend(self.{field.id}.serialize())") - - def serialize_payload_field_(self, field: Union[ast.BodyField, ast.PayloadField]): - """Serialize body and payload fields.""" - - if self.shift != 0 and self.byteorder == 'big': - raise Exception('Payload field does not start on an octet boundary') - - if self.shift == 0: - self.append_(f"_span.extend(payload or self.payload or [])") - else: - # Supported case of packet inheritance; - # the incomplete fields are serialized into - # the payload, rather than separately. - # First extract the padding bits from the payload, - # then recombine them with the bit fields to be serialized. - rounded_size = int((self.shift + 7) / 8) - padding_bits = 8 * rounded_size - self.shift - self.append_(f"_payload = payload or self.payload or bytes()") - self.append_(f"if len(_payload) < {rounded_size}:") - self.append_(f" raise Exception(f\"Invalid length for payload field:" + - f" {{len(_payload)}} < {rounded_size}\")") - self.append_( - f"_padding = int.from_bytes(_payload[:{rounded_size}], byteorder='{self.byteorder}') >> {self.shift}") - self.value.append(f"(_padding << {self.shift})") - self.shift += padding_bits - self.pack_bit_fields_() - self.append_(f"_span.extend(_payload[{rounded_size}:])") - - def serialize_checksum_field_(self, field: ast.ChecksumField): - """Generate a checksum check.""" - - self.append_("_checksum_start = len(_span)") - - def serialize(self, field: ast.Field): - # Field has bit granularity. - # Append the field to the current chunk, - # check if a byte boundary was reached. - if core.is_bit_field(field): - self.serialize_bit_field_(field) - - # Padding fields. - elif isinstance(field, ast.PaddingField): - pass - - # Array fields. - elif isinstance(field, ast.ArrayField): - self.serialize_array_field_(field) - - # Other typedef fields. - elif isinstance(field, ast.TypedefField): - self.serialize_typedef_field_(field) - - # Payload and body fields. - elif isinstance(field, (ast.PayloadField, ast.BodyField)): - self.serialize_payload_field_(field) - - # Checksum fields. - elif isinstance(field, ast.ChecksumField): - self.serialize_checksum_field_(field) - - else: - raise Exception(f'Unimplemented field type {field.kind}') - - -def generate_toplevel_packet_serializer(packet: ast.Declaration) -> List[str]: - """Generate the serialize() function for a toplevel Packet or Struct - declaration.""" - - serializer = FieldSerializer(byteorder=packet.file.byteorder) - for f in packet.fields: - serializer.serialize(f) - return ['_span = bytearray()'] + serializer.code + ['return bytes(_span)'] - - -def generate_derived_packet_serializer(packet: ast.Declaration) -> List[str]: - """Generate the serialize() function for a derived Packet or Struct - declaration.""" - - packet_shift = core.get_packet_shift(packet) - if packet_shift and packet.file.byteorder == 'big': - raise Exception(f"Big-endian packet {packet.id} has an unsupported body shift") - - serializer = FieldSerializer(byteorder=packet.file.byteorder, shift=packet_shift) - for f in packet.fields: - serializer.serialize(f) - return ['_span = bytearray()' - ] + serializer.code + [f'return {packet.parent.id}.serialize(self, payload = bytes(_span))'] - - -def generate_packet_parser(packet: ast.Declaration) -> List[str]: - """Generate the parse() function for a toplevel Packet or Struct - declaration.""" - - packet_shift = core.get_packet_shift(packet) - if packet_shift and packet.file.byteorder == 'big': - raise Exception(f"Big-endian packet {packet.id} has an unsupported body shift") - - # Convert the packet constraints to a boolean expression. - validation = [] - if packet.constraints: - cond = [] - for c in packet.constraints: - if c.value is not None: - cond.append(f"fields['{c.id}'] != {hex(c.value)}") - else: - field = core.get_packet_field(packet, c.id) - cond.append(f"fields['{c.id}'] != {field.type_id}.{c.tag_id}") - - validation = [f"if {' or '.join(cond)}:", " raise Exception(\"Invalid constraint field values\")"] - - # Parse fields iteratively. - parser = FieldParser(byteorder=packet.file.byteorder, shift=packet_shift) - for f in packet.fields: - parser.parse(f) - parser.done() - - # Specialize to child packets. - children = core.get_derived_packets(packet) - decl = [] if packet.parent_id else ['fields = {\'payload\': None}'] - specialization = [] - - if len(children) != 0: - # Try parsing every child packet successively until one is - # successfully parsed. Return a parsing error if none is valid. - # Return parent packet if no child packet matches. - # TODO: order child packets by decreasing size in case no constraint - # is given for specialization. - for _, child in children: - specialization.append("try:") - specialization.append(f" return {child.id}.parse(fields.copy(), payload)") - specialization.append("except Exception as exn:") - specialization.append(" pass") - - return decl + validation + parser.code + specialization + [f"return {packet.id}(**fields), span"] - - -def generate_packet_size_getter(packet: ast.Declaration) -> List[str]: - constant_width = 0 - variable_width = [] - for f in packet.fields: - field_size = core.get_field_size(f) - if field_size is not None: - constant_width += field_size - elif isinstance(f, (ast.PayloadField, ast.BodyField)): - variable_width.append("len(self.payload)") - elif isinstance(f, ast.TypedefField): - variable_width.append(f"self.{f.id}.size") - elif isinstance(f, ast.ArrayField) and isinstance(f.type, (ast.StructDeclaration, ast.CustomFieldDeclaration)): - variable_width.append(f"sum([elt.size for elt in self.{f.id}])") - elif isinstance(f, ast.ArrayField) and isinstance(f.type, ast.EnumDeclaration): - variable_width.append(f"len(self.{f.id}) * {f.type.width}") - elif isinstance(f, ast.ArrayField): - variable_width.append(f"len(self.{f.id}) * {int(f.width / 8)}") - else: - raise Exception("Unsupported field type") - - constant_width = int(constant_width / 8) - if len(variable_width) == 0: - return [f"return {constant_width}"] - elif len(variable_width) == 1 and constant_width: - return [f"return {variable_width[0]} + {constant_width}"] - elif len(variable_width) == 1: - return [f"return {variable_width[0]}"] - elif len(variable_width) > 1 and constant_width: - return ([f"return {constant_width} + ("] + " +\n ".join(variable_width).split("\n") + [")"]) - elif len(variable_width) > 1: - return (["return ("] + " +\n ".join(variable_width).split("\n") + [")"]) - else: - assert False - - -def generate_packet_post_init(decl: ast.Declaration) -> List[str]: - """Generate __post_init__ function to set constraint field values.""" - - # Gather all constraints from parent packets. - constraints = [] - current = decl - while current.parent_id: - constraints.extend(current.constraints) - current = current.parent - - if constraints: - code = [] - for c in constraints: - if c.value is not None: - code.append(f"self.{c.id} = {c.value}") - else: - field = core.get_packet_field(decl, c.id) - code.append(f"self.{c.id} = {field.type_id}.{c.tag_id}") - return code - - else: - return ["pass"] - - -def generate_enum_declaration(decl: ast.EnumDeclaration) -> str: - """Generate the implementation of an enum type.""" - - enum_name = decl.id - tag_decls = [] - for t in decl.tags: - tag_decls.append(f"{t.id} = {hex(t.value)}") - - return dedent("""\ - - class {enum_name}(enum.IntEnum): - {tag_decls} - """).format(enum_name=enum_name, tag_decls=indent(tag_decls, 1)) - - -def generate_packet_declaration(packet: ast.Declaration) -> str: - """Generate the implementation a toplevel Packet or Struct - declaration.""" - - packet_name = packet.id - field_decls = [] - for f in packet.fields: - if isinstance(f, ast.ScalarField): - field_decls.append(f"{f.id}: int = field(kw_only=True, default=0)") - elif isinstance(f, ast.TypedefField): - if isinstance(f.type, ast.EnumDeclaration): - field_decls.append( - f"{f.id}: {f.type_id} = field(kw_only=True, default={f.type_id}.{f.type.tags[0].id})") - elif isinstance(f.type, ast.ChecksumDeclaration): - field_decls.append(f"{f.id}: int = field(kw_only=True, default=0)") - elif isinstance(f.type, (ast.StructDeclaration, ast.CustomFieldDeclaration)): - field_decls.append(f"{f.id}: {f.type_id} = field(kw_only=True, default_factory={f.type_id})") - else: - raise Exception("Unsupported typedef field type") - elif isinstance(f, ast.ArrayField) and f.width == 8: - field_decls.append(f"{f.id}: bytearray = field(kw_only=True, default_factory=bytearray)") - elif isinstance(f, ast.ArrayField) and f.width: - field_decls.append(f"{f.id}: List[int] = field(kw_only=True, default_factory=list)") - elif isinstance(f, ast.ArrayField) and f.type_id: - field_decls.append(f"{f.id}: List[{f.type_id}] = field(kw_only=True, default_factory=list)") - - if packet.parent_id: - parent_name = packet.parent_id - parent_fields = 'fields: dict, ' - serializer = generate_derived_packet_serializer(packet) - else: - parent_name = 'Packet' - parent_fields = '' - serializer = generate_toplevel_packet_serializer(packet) - - parser = generate_packet_parser(packet) - size = generate_packet_size_getter(packet) - post_init = generate_packet_post_init(packet) - - return dedent("""\ - - @dataclass - class {packet_name}({parent_name}): - {field_decls} - - def __post_init__(self): - {post_init} - - @staticmethod - def parse({parent_fields}span: bytes) -> Tuple['{packet_name}', bytes]: - {parser} - - def serialize(self, payload: bytes = None) -> bytes: - {serializer} - - @property - def size(self) -> int: - {size} - """).format(packet_name=packet_name, - parent_name=parent_name, - parent_fields=parent_fields, - field_decls=indent(field_decls, 1), - post_init=indent(post_init, 2), - parser=indent(parser, 2), - serializer=indent(serializer, 2), - size=indent(size, 2)) - - -def generate_custom_field_declaration_check(decl: ast.CustomFieldDeclaration) -> str: - """Generate the code to validate a user custom field implementation. - - This code is to be executed when the generated module is loaded to ensure - the user gets an immediate and clear error message when the provided - custom types do not fit the expected template. - """ - return dedent("""\ - - if (not callable(getattr({custom_field_name}, 'parse', None)) or - not callable(getattr({custom_field_name}, 'parse_all', None))): - raise Exception('The custom field type {custom_field_name} does not implement the parse method') - """).format(custom_field_name=decl.id) - - -def generate_checksum_declaration_check(decl: ast.ChecksumDeclaration) -> str: - """Generate the code to validate a user checksum field implementation. - - This code is to be executed when the generated module is loaded to ensure - the user gets an immediate and clear error message when the provided - checksum functions do not fit the expected template. - """ - return dedent("""\ - - if not callable({checksum_name}): - raise Exception('{checksum_name} is not callable') - """).format(checksum_name=decl.id) - - -def run(input: argparse.FileType, output: argparse.FileType, custom_type_location: Optional[str]): - file = ast.File.from_json(json.load(input)) - core.desugar(file) - - custom_types = [] - custom_type_checks = "" - for d in file.declarations: - if isinstance(d, ast.CustomFieldDeclaration): - custom_types.append(d.id) - custom_type_checks += generate_custom_field_declaration_check(d) - elif isinstance(d, ast.ChecksumDeclaration): - custom_types.append(d.id) - custom_type_checks += generate_checksum_declaration_check(d) - - output.write(f"# File generated from {input.name}, with the command:\n") - output.write(f"# {' '.join(sys.argv)}\n") - output.write("# /!\\ Do not edit by hand.\n") - if custom_types and custom_type_location: - output.write(f"\nfrom {custom_type_location} import {', '.join(custom_types)}\n") - output.write(generate_prelude()) - output.write(custom_type_checks) - - for d in file.declarations: - if isinstance(d, ast.EnumDeclaration): - output.write(generate_enum_declaration(d)) - elif isinstance(d, (ast.PacketDeclaration, ast.StructDeclaration)): - output.write(generate_packet_declaration(d)) - - -def main() -> int: - """Generate python PDL backend.""" - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('--input', type=argparse.FileType('r'), default=sys.stdin, help='Input PDL-JSON source') - parser.add_argument('--output', type=argparse.FileType('w'), default=sys.stdout, help='Output Python file') - parser.add_argument('--custom-type-location', - type=str, - required=False, - help='Module of declaration of custom types') - return run(**vars(parser.parse_args())) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tools/pdl/scripts/packet_runtime.h b/tools/pdl/scripts/packet_runtime.h deleted file mode 100644 index c9e1420ea910b38fa627b550c173b90396d64dc3..0000000000000000000000000000000000000000 --- a/tools/pdl/scripts/packet_runtime.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#ifndef ASSERT -#include -#define ASSERT assert -#endif // !ASSERT - -namespace pdl::packet { - -/// Representation of a raw packet slice. -/// The slice contains a shared pointer to the source packet bytes, and points -/// to a subrange within this byte buffer. -class slice { - public: - slice() = default; - slice(slice const&) = default; - slice(std::shared_ptr> packet) - : packet_(std::move(packet)), offset_(0), size_(packet_->size()) {} - - slice(std::shared_ptr> packet, size_t offset, - size_t size) - : packet_(std::move(packet)), offset_(offset), size_(size) {} - - /// Return a new slice that contains the selected subrange within the - /// current slice. The range ['offset', 'offset' + 'slice') must be - /// contained within the bonuds of the current slice. - slice subrange(size_t offset, size_t size) const { - ASSERT((offset + size) <= size_); - return slice(packet_, offset_ + offset, size); - } - - /// Read a scalar value encoded in little-endian. - /// The bytes that are read from calling this function are consumed. - /// This function can be used to iterativaly extract values from a packet - /// slice. - template - T read_le() { - static_assert(N <= sizeof(T)); - ASSERT(N <= size_); - T value = 0; - for (size_t n = 0; n < N; n++) { - value |= (T)at(n) << (8 * n); - } - skip(N); - return value; - } - - /// Read a scalar value encoded in big-endian. - /// The bytes that are read from calling this function are consumed. - /// This function can be used to iterativaly extract values from a packet - /// slice. - template - T read_be() { - static_assert(N <= sizeof(T)); - ASSERT(N <= size_); - T value = 0; - for (size_t n = 0; n < N; n++) { - value = (value << 8) | (T)at(n); - } - skip(N); - return value; - } - - /// Return the value of the byte at the given offset. - /// `offset` must be within the bounds of the slice. - uint8_t at(size_t offset) const { - ASSERT(offset <= size_); - return packet_->at(offset_ + offset); - } - - /// Skip `size` bytes at the front of the slice. - /// `size` must be lower than or equal to the slice size. - void skip(size_t size) { - ASSERT(size <= size_); - offset_ += size; - size_ -= size; - } - - /// Empty the slice. - void clear() { size_ = 0; } - - /// Return the size of the slice in bytes. - size_t size() const { return size_; } - - /// Return the contents of the slice as a byte vector. - std::vector bytes() const { - return std::vector(packet_->cbegin() + offset_, - packet_->cbegin() + offset_ + size_); - } - - private: - std::shared_ptr> packet_; - size_t offset_{0}; - size_t size_{0}; -}; - -/// Interface class for generated packet builders. -class Builder { - public: - virtual ~Builder() = default; - - /// Method implemented by generated packet builders. - /// The packet fields are concatenated to the output vector. - virtual void Serialize(std::vector&) const {} - - /// Method implemented by generated packet builders. - /// Returns the size of the serialized packet in bytes. - virtual size_t GetSize() const { return 0; } - - /// Write a scalar value encoded in little-endian. - template - static void write_le(std::vector& output, T value) { - static_assert(N <= sizeof(T)); - for (size_t n = 0; n < N; n++) { - output.push_back(value >> (8 * n)); - } - } - - /// Write a scalar value encoded in big-endian. - template - static void write_be(std::vector& output, T value) { - static_assert(N <= sizeof(T)); - for (size_t n = 0; n < N; n++) { - output.push_back(value >> (8 * (N - 1 - n))); - } - } - - /// Helper method to serialize the packet to a byte vector. - std::vector Serialize() const { - std::vector output; - Serialize(output); - return output; - } -}; - -} // namespace pdl::packet diff --git a/tools/pdl/scripts/pdl/ast.py b/tools/pdl/scripts/pdl/ast.py deleted file mode 100644 index 4f884e5eb99f81a6aa5976bac10691b2327fe3e0..0000000000000000000000000000000000000000 --- a/tools/pdl/scripts/pdl/ast.py +++ /dev/null @@ -1,281 +0,0 @@ -# Copyright 2023 Google LLC -# -# 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 -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from dataclasses import dataclass, field -from typing import Optional, List, Dict, Tuple - -constructors_ = dict() - - -def node(kind: str): - - def decorator(cls): - cls = dataclass(cls) - constructors_[kind] = cls - return cls - - return decorator - - -@dataclass -class SourceLocation: - offset: int - line: int - column: int - - -@dataclass -class SourceRange: - file: int - start: SourceLocation - end: SourceLocation - - -@dataclass -class Node: - kind: str - loc: SourceLocation - - -@node('tag') -class Tag(Node): - id: str - value: Optional[int] = field(default=None) - range: Optional[Tuple[int, int]] = field(default=None) - tags: Optional[List['Tag']] = field(default=None) - - -@node('constraint') -class Constraint(Node): - id: str - value: Optional[int] - tag_id: Optional[str] - - -@dataclass -class Field(Node): - parent: Node = field(init=False) - - -@node('checksum_field') -class ChecksumField(Field): - field_id: str - - -@node('padding_field') -class PaddingField(Field): - size: int - - -@node('size_field') -class SizeField(Field): - field_id: str - width: int - - -@node('count_field') -class CountField(Field): - field_id: str - width: int - - -@node('body_field') -class BodyField(Field): - id: str = field(init=False, default='_body_') - - -@node('payload_field') -class PayloadField(Field): - size_modifier: Optional[str] - id: str = field(init=False, default='_payload_') - - -@node('fixed_field') -class FixedField(Field): - width: Optional[int] = None - value: Optional[int] = None - enum_id: Optional[str] = None - tag_id: Optional[str] = None - - @property - def type(self) -> Optional['Declaration']: - return self.parent.file.typedef_scope[self.enum_id] if self.enum_id else None - - -@node('reserved_field') -class ReservedField(Field): - width: int - - -@node('array_field') -class ArrayField(Field): - id: str - width: Optional[int] - type_id: Optional[str] - size_modifier: Optional[str] - size: Optional[int] - padded_size: Optional[int] = field(init=False, default=None) - - @property - def type(self) -> Optional['Declaration']: - return self.parent.file.typedef_scope[self.type_id] if self.type_id else None - - -@node('scalar_field') -class ScalarField(Field): - id: str - width: int - - -@node('typedef_field') -class TypedefField(Field): - id: str - type_id: str - - @property - def type(self) -> 'Declaration': - return self.parent.file.typedef_scope[self.type_id] - - -@node('group_field') -class GroupField(Field): - group_id: str - constraints: List[Constraint] - - -@dataclass -class Declaration(Node): - file: 'File' = field(init=False) - - def __post_init__(self): - if hasattr(self, 'fields'): - for f in self.fields: - f.parent = self - - -@node('endianness_declaration') -class EndiannessDeclaration(Node): - value: str - - -@node('checksum_declaration') -class ChecksumDeclaration(Declaration): - id: str - function: str - width: int - - -@node('custom_field_declaration') -class CustomFieldDeclaration(Declaration): - id: str - function: str - width: Optional[int] - - -@node('enum_declaration') -class EnumDeclaration(Declaration): - id: str - tags: List[Tag] - width: int - - -@node('packet_declaration') -class PacketDeclaration(Declaration): - id: str - parent_id: Optional[str] - constraints: List[Constraint] - fields: List[Field] - - @property - def parent(self) -> Optional['PacketDeclaration']: - return self.file.packet_scope[self.parent_id] if self.parent_id else None - - -@node('struct_declaration') -class StructDeclaration(Declaration): - id: str - parent_id: Optional[str] - constraints: List[Constraint] - fields: List[Field] - - @property - def parent(self) -> Optional['StructDeclaration']: - return self.file.typedef_scope[self.parent_id] if self.parent_id else None - - -@node('group_declaration') -class GroupDeclaration(Declaration): - id: str - fields: List[Field] - - -@dataclass -class File: - endianness: EndiannessDeclaration - declarations: List[Declaration] - packet_scope: Dict[str, Declaration] = field(init=False) - typedef_scope: Dict[str, Declaration] = field(init=False) - group_scope: Dict[str, Declaration] = field(init=False) - - def __post_init__(self): - self.packet_scope = dict() - self.typedef_scope = dict() - self.group_scope = dict() - - # Construct the toplevel declaration scopes. - for d in self.declarations: - d.file = self - if isinstance(d, PacketDeclaration): - self.packet_scope[d.id] = d - elif isinstance(d, GroupDeclaration): - self.group_scope[d.id] = d - else: - self.typedef_scope[d.id] = d - - @staticmethod - def from_json(obj: object) -> 'File': - """Import a File exported as JSON object by the PDL parser.""" - endianness = convert_(obj['endianness']) - declarations = convert_(obj['declarations']) - return File(endianness, declarations) - - @property - def byteorder(self) -> str: - return 'little' if self.endianness.value == 'little_endian' else 'big' - - @property - def byteorder_short(self, short: bool = False) -> str: - return 'le' if self.endianness.value == 'little_endian' else 'be' - - -def convert_(obj: object) -> object: - if obj is None: - return None - if isinstance(obj, (int, str)): - return obj - if isinstance(obj, list): - return [convert_(elt) for elt in obj] - if isinstance(obj, object): - if 'start' in obj.keys() and 'end' in obj.keys(): - return (objs.start, obj.end) - kind = obj['kind'] - loc = obj['loc'] - loc = SourceRange(loc['file'], SourceLocation(**loc['start']), SourceLocation(**loc['end'])) - constructor = constructors_.get(kind) - members = {'loc': loc, 'kind': kind} - for name, value in obj.items(): - if name != 'kind' and name != 'loc': - members[name] = convert_(value) - return constructor(**members) - raise Exception('Unhandled json object type') diff --git a/tools/pdl/scripts/pdl/core.py b/tools/pdl/scripts/pdl/core.py deleted file mode 100644 index f55bb3018aa9d0ec35ddc440651fa22ad5a3b584..0000000000000000000000000000000000000000 --- a/tools/pdl/scripts/pdl/core.py +++ /dev/null @@ -1,334 +0,0 @@ -# Copyright 2023 Google LLC -# -# 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 -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Optional, List, Dict, Union, Tuple, Set -from .ast import * - - -def desugar_field_(field: Field, previous: Field, constraints: Dict[str, Constraint]) -> List[Field]: - """Inline group and constrained fields. - Constrained fields are transformed into fixed fields. - Group fields are inlined and recursively desugared.""" - - if isinstance(field, ScalarField) and field.id in constraints: - value = constraints[field.id].value - fixed = FixedField(kind='fixed_field', loc=field.loc, width=field.width, value=value) - fixed.parent = field.parent - return [fixed] - - elif isinstance(field, PaddingField): - previous.padded_size = field.size - field.padded_field = previous - return [field] - - elif isinstance(field, TypedefField) and field.id in constraints: - tag_id = constraints[field.id].tag_id - fixed = FixedField(kind='fixed_field', loc=field.loc, enum_id=field.type_id, tag_id=tag_id) - fixed.parent = field.parent - return [fixed] - - elif isinstance(field, GroupField): - group = field.parent.file.group_scope[field.group_id] - constraints = dict([(c.id, c) for c in field.constraints]) - fields = [] - for f in group.fields: - fields.extend(desugar_field_(f, previous, constraints)) - previous = f - return fields - - else: - return [field] - - -def desugar(file: File): - """Inline group fields. - Constrained fields are transformed into fixed fields. - Group declarations are removed from the file object. - **The original file object is modified inline.**""" - - declarations = [] - for d in file.declarations: - if isinstance(d, GroupDeclaration): - continue - - if isinstance(d, (PacketDeclaration, StructDeclaration)): - fields = [] - for f in d.fields: - fields.extend(desugar_field_(f, fields[-1] if len(fields) > 0 else None, {})) - d.fields = fields - - declarations.append(d) - - file.declarations = declarations - file.group_scope = {} - - -def make_reserved_field(width: int) -> ReservedField: - """Create a reserved field of specified width.""" - return ReservedField(kind='reserved_field', loc=None, width=width) - - -def get_packet_field(packet: Union[PacketDeclaration, StructDeclaration], id: str) -> Optional[Field]: - """Return the field with selected identifier declared in the provided - packet or its ancestors.""" - id = '_payload_' if id == 'payload' else id - for f in packet.fields: - if getattr(f, 'id', None) == id: - return f - if isinstance(packet, PacketDeclaration) and packet.parent_id: - parent = packet.file.packet_scope[packet.parent_id] - return get_packet_field(parent, id) - elif isinstance(packet, StructDeclaration) and packet.parent_id: - parent = packet.file.typedef_scope[packet.parent_id] - return get_packet_field(parent, id) - else: - return None - - -def get_packet_fields(decl: Union[PacketDeclaration, StructDeclaration]) -> List[Field]: - """Return the list of fields declared in the selected packet and its parents. - Payload fields are removed from the parent declarations.""" - - fields = [] - if decl.parent: - fields = [f for f in get_packet_fields(decl.parent) if not isinstance(f, (PayloadField, BodyField))] - return fields + decl.fields - - -def get_packet_shift(packet: Union[PacketDeclaration, StructDeclaration]) -> int: - """Return the bit shift of the payload or body field in the parent packet. - - When using packet derivation on bit fields, the body may be shifted. - The shift is handled statically in the implementation of child packets, - and the incomplete field is included in the body. - ``` - packet Basic { - type: 1, - _body_ - } - ``` - """ - - # Traverse empty parents. - parent = packet.parent - while parent and len(parent.fields) == 1: - parent = parent.parent - - if not parent: - return 0 - - shift = 0 - for f in packet.parent.fields: - if isinstance(f, (BodyField, PayloadField)): - return 0 if (shift % 8) == 0 else shift - else: - # Fields that do not have a constant size are assumed to start - # on a byte boundary, and measure an integral number of bytes. - # Start the count over. - size = get_field_size(f) - shift = 0 if size is None else shift + size - - # No payload or body in parent packet. - # Not raising an error, the generation will fail somewhere else. - return 0 - - -def get_packet_ancestor( - decl: Union[PacketDeclaration, StructDeclaration]) -> Union[PacketDeclaration, StructDeclaration]: - """Return the root ancestor of the selected packet or struct.""" - if decl.parent_id is None: - return decl - else: - return get_packet_ancestor(decl.file.packet_scope[decl.parent_id]) - - -def get_derived_packets( - decl: Union[PacketDeclaration, StructDeclaration], - traverse: bool = True, -) -> List[Tuple[List[Constraint], Union[PacketDeclaration, StructDeclaration]]]: - """Return the list of packets or structs that immediately derive from the - selected packet or struct, coupled with the field constraints. - Packet aliases (containing no field declarations other than a payload) - are traversed.""" - - children = [] - for d in decl.file.declarations: - if type(d) is type(decl) and d.parent_id == decl.id: - if (len(d.fields) == 1 and isinstance(d.fields[0], (PayloadField, BodyField))) and traverse: - children.extend([(d.constraints + sub_constraints, sub_child) - for (sub_constraints, sub_child) in get_derived_packets(d)]) - else: - children.append((d.constraints, d)) - return children - - -def get_field_size(field: Field, skip_payload: bool = False) -> Optional[int]: - """Determine the size of a field in bits, if possible. - If the field is dynamically sized (e.g. unsized array or payload field), - None is returned instead. If skip_payload is set, payload and body fields - are counted as having size 0 rather than a variable size.""" - - if isinstance(field, (ScalarField, SizeField, CountField, ReservedField)): - return field.width - - elif isinstance(field, FixedField): - return field.width or field.type.width - - elif isinstance(field, PaddingField): - # Padding field width is added to the padded field size. - return 0 - - elif isinstance(field, ArrayField) and field.padded_size is not None: - return field.padded_size * 8 - - elif isinstance(field, ArrayField) and field.size is not None: - element_width = field.width or get_declaration_size(field.type) - return element_width * field.size if element_width is not None else None - - elif isinstance(field, TypedefField): - return get_declaration_size(field.type) - - elif isinstance(field, ChecksumField): - return 0 - - elif isinstance(field, (PayloadField, BodyField)) and skip_payload: - return 0 - - else: - return None - - -def get_declaration_size(decl: Declaration, skip_payload: bool = False) -> Optional[int]: - """Determine the size of a declaration type in bits, if possible. - If the type is dynamically sized (e.g. contains an array or payload), - None is returned instead. If skip_payload is set, payload and body fields - are counted as having size 0 rather than a variable size.""" - - if isinstance(decl, (EnumDeclaration, CustomFieldDeclaration, ChecksumDeclaration)): - return decl.width - - elif isinstance(decl, (PacketDeclaration, StructDeclaration)): - parent = decl.parent - packet_size = get_declaration_size(parent, skip_payload=True) if parent else 0 - if packet_size is None: - return None - for f in decl.fields: - field_size = get_field_size(f, skip_payload=skip_payload) - if field_size is None: - return None - packet_size += field_size - return packet_size - - else: - return None - - -def get_array_field_size(field: ArrayField) -> Union[None, int, Field]: - """Return the array static size, size field, or count field. - If the array is unsized None is returned instead.""" - - if field.size is not None: - return field.size - for f in field.parent.fields: - if isinstance(f, (SizeField, CountField)) and f.field_id == field.id: - return f - return None - - -def get_payload_field_size(field: Union[PayloadField, BodyField]) -> Optional[Field]: - """Return the payload or body size field. - If the payload is unsized None is returned instead.""" - - for f in field.parent.fields: - if isinstance(f, SizeField) and f.field_id == field.id: - return f - return None - - -def get_array_element_size(field: ArrayField) -> Optional[int]: - """Return the array element size, if possible. - If the element size is not known at compile time, - None is returned instead.""" - - return field.width or get_declaration_size(field.type) - - -def get_field_offset_from_start(field: Field) -> Optional[int]: - """Return the field bit offset from the start of the parent packet, if it - can be statically computed. If the offset is variable None is returned - instead.""" - offset = 0 - field_index = field.parent.fields.index(field) - for f in field.parent.fields[:field_index]: - size = get_field_size(f) - if size is None: - return None - - offset += size - return offset - - -def get_field_offset_from_end(field: Field) -> Optional[int]: - """Return the field bit offset from the end of the parent packet, if it - can be statically computed. If the offset is variable None is returned - instead. The selected field size is not counted towards the offset.""" - offset = 0 - field_index = field.parent.fields.index(field) - for f in field.parent.fields[field_index + 1:]: - size = get_field_size(f) - if size is None: - return None - offset += size - return offset - - -def get_unconstrained_parent_fields(decl: Union[PacketDeclaration, StructDeclaration]) -> List[Field]: - """Return the list of fields from the parent declarations that have an identifier - but that do not have a value fixed by any of the parent constraints. - The fields are returned in order of declaration.""" - - def constraint_ids(constraints: List[Constraint]) -> Set[str]: - return set([c.id for c in constraints]) - - def aux(decl: Optional[Declaration], constraints: Set[str]) -> List[Field]: - if decl is None: - return [] - fields = aux(decl.parent, constraints.union(constraint_ids(decl.constraints))) - for f in decl.fields: - if (isinstance(f, (ScalarField, ArrayField, TypedefField)) and not f.id in constraints): - fields.append(f) - return fields - - return aux(decl.parent, constraint_ids(decl.constraints)) - - -def get_parent_constraints(decl: Union[PacketDeclaration, StructDeclaration]) -> List[Constraint]: - """Return the list of constraints from the current and parent declarations.""" - parent_constraints = get_parent_constraints(decl.parent) if decl.parent else [] - return parent_constraints + decl.constraints - - -def is_bit_field(field: Field) -> bool: - """Identify fields that can have bit granularity. - These include: ScalarField, FixedField, TypedefField with enum type, - SizeField, and CountField.""" - - if isinstance(field, (ScalarField, SizeField, CountField, FixedField, ReservedField)): - return True - - elif isinstance(field, TypedefField) and isinstance(field.type, EnumDeclaration): - return True - - else: - return False diff --git a/tools/pdl/scripts/pdl/utils.py b/tools/pdl/scripts/pdl/utils.py deleted file mode 100644 index 24e91ca9fb18549beecb359f7043ce082f9d0b4b..0000000000000000000000000000000000000000 --- a/tools/pdl/scripts/pdl/utils.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2023 Google LLC -# -# 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 -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import List, Tuple, Union, Optional - - -def indent(code: Union[str, List[str]], depth: int) -> str: - """Indent a code block to the selected depth. - - Accepts as parameter a list of lines or a code block. Handles - line breaks in the lines as well. - The first line is intentionally not indented so that - the caller may use it as: - - ''' - def generated(): - {codeblock} - ''' - """ - code = [code] if isinstance(code, str) else code - lines = [line for block in code for line in block.split('\n')] - sep = '\n' + (' ' * (depth * 4)) - return sep.join(lines) - - -def to_pascal_case(text: str) -> str: - """Convert UPPER_SNAKE_CASE strings to PascalCase.""" - return text.replace('_', ' ').title().replace(' ', '') diff --git a/tools/pdl/src/analyzer.rs b/tools/pdl/src/analyzer.rs deleted file mode 100644 index e9e8d2561bb5a2ba2e11869052db32a6385837fa..0000000000000000000000000000000000000000 --- a/tools/pdl/src/analyzer.rs +++ /dev/null @@ -1,2591 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use codespan_reporting::diagnostic::Diagnostic; -use codespan_reporting::files; -use codespan_reporting::term; -use codespan_reporting::term::termcolor; -use std::collections::HashMap; - -use crate::ast::*; -use crate::parser::ast as parser_ast; -use crate::utils; - -pub mod ast { - use serde::Serialize; - - /// Field and declaration size information. - #[derive(Debug, Clone, Copy)] - #[allow(unused)] - pub enum Size { - /// Constant size in bits. - Static(usize), - /// Size indicated at packet parsing by a size or count field. - /// The parameter is the static part of the size. - Dynamic, - /// The size cannot be determined statically or at runtime. - /// The packet assumes the largest possible size. - Unknown, - } - - // TODO: use derive(Default) when UWB is using Rust 1.62.0. - #[allow(clippy::derivable_impls)] - impl Default for Size { - fn default() -> Size { - Size::Unknown - } - } - - #[derive(Debug, Serialize, Default, Clone, PartialEq)] - pub struct Annotation; - - #[derive(Default, Debug, Clone)] - pub struct FieldAnnotation { - // Size of field. - pub size: Size, - } - - #[derive(Default, Debug, Clone)] - pub struct DeclAnnotation { - // Size computed excluding the payload. - pub size: Size, - // Payload size, or Static(0) if the declaration does not - // have a payload. - pub payload_size: Size, - } - - impl std::ops::Add for Size { - type Output = Size; - fn add(self, rhs: Size) -> Self::Output { - match (self, rhs) { - (Size::Unknown, _) | (_, Size::Unknown) => Size::Unknown, - (Size::Dynamic, _) | (_, Size::Dynamic) => Size::Dynamic, - (Size::Static(lhs), Size::Static(rhs)) => Size::Static(lhs + rhs), - } - } - } - - impl std::ops::Mul for Size { - type Output = Size; - fn mul(self, rhs: Size) -> Self::Output { - match (self, rhs) { - (Size::Unknown, _) | (_, Size::Unknown) => Size::Unknown, - (Size::Dynamic, _) | (_, Size::Dynamic) => Size::Dynamic, - (Size::Static(lhs), Size::Static(rhs)) => Size::Static(lhs * rhs), - } - } - } - - impl std::ops::Mul for Size { - type Output = Size; - fn mul(self, rhs: usize) -> Self::Output { - match self { - Size::Unknown => Size::Unknown, - Size::Dynamic => Size::Dynamic, - Size::Static(lhs) => Size::Static(lhs * rhs), - } - } - } - - impl crate::ast::Annotation for Annotation { - type FieldAnnotation = FieldAnnotation; - type DeclAnnotation = DeclAnnotation; - } - - #[allow(unused)] - pub type Field = crate::ast::Field; - #[allow(unused)] - pub type Decl = crate::ast::Decl; - #[allow(unused)] - pub type File = crate::ast::File; -} - -/// List of unique errors reported as analyzer diagnostics. -#[repr(u16)] -pub enum ErrorCode { - DuplicateDeclIdentifier = 1, - RecursiveDecl = 2, - UndeclaredGroupIdentifier = 3, - InvalidGroupIdentifier = 4, - UndeclaredTypeIdentifier = 5, - InvalidTypeIdentifier = 6, - UndeclaredParentIdentifier = 7, - InvalidParentIdentifier = 8, - UndeclaredTestIdentifier = 9, - InvalidTestIdentifier = 10, - DuplicateFieldIdentifier = 11, - DuplicateTagIdentifier = 12, - DuplicateTagValue = 13, - InvalidTagValue = 14, - UndeclaredConstraintIdentifier = 15, - InvalidConstraintIdentifier = 16, - E17 = 17, - ConstraintValueOutOfRange = 18, - E19 = 19, - E20 = 20, - E21 = 21, - DuplicateConstraintIdentifier = 22, - DuplicateSizeField = 23, - UndeclaredSizeIdentifier = 24, - InvalidSizeIdentifier = 25, - DuplicateCountField = 26, - UndeclaredCountIdentifier = 27, - InvalidCountIdentifier = 28, - DuplicateElementSizeField = 29, - UndeclaredElementSizeIdentifier = 30, - InvalidElementSizeIdentifier = 31, - FixedValueOutOfRange = 32, - E33 = 33, - E34 = 34, - E35 = 35, - DuplicatePayloadField = 36, - MissingPayloadField = 37, - RedundantArraySize = 38, - InvalidPaddingField = 39, - InvalidTagRange = 40, - DuplicateTagRange = 41, - E42 = 42, - E43 = 43, -} - -impl From for String { - fn from(code: ErrorCode) -> Self { - format!("E{}", code as u16) - } -} - -/// Aggregate analyzer diagnostics. -#[derive(Debug, Default)] -pub struct Diagnostics { - pub diagnostics: Vec>, -} - -/// Gather information about the full AST. -#[derive(Debug, Default)] -pub struct Scope<'d, A: Annotation> { - /// Collection of Group, Packet, Enum, Struct, Checksum, and CustomField - /// declarations. - pub typedef: HashMap>, -} - -impl Diagnostics { - fn is_empty(&self) -> bool { - self.diagnostics.is_empty() - } - - fn push(&mut self, diagnostic: Diagnostic) { - self.diagnostics.push(diagnostic) - } - - fn err_or(self, value: T) -> Result { - if self.is_empty() { - Ok(value) - } else { - Err(self) - } - } - - pub fn emit( - &self, - sources: &SourceDatabase, - writer: &mut dyn termcolor::WriteColor, - ) -> Result<(), files::Error> { - let config = term::Config::default(); - for d in self.diagnostics.iter() { - term::emit(writer, &config, sources, d)?; - } - Ok(()) - } -} - -impl<'d, A: Annotation + Default> Scope<'d, A> { - pub fn new(file: &'d crate::ast::File) -> Result, Diagnostics> { - // Gather top-level declarations. - let mut scope: Scope = Default::default(); - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - if let Some(id) = decl.id() { - if let Some(prev) = scope.typedef.insert(id.to_string(), decl) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateDeclIdentifier) - .with_message(format!( - "redeclaration of {} identifier `{}`", - decl.kind(), - id - )) - .with_labels(vec![ - decl.loc.primary(), - prev.loc - .secondary() - .with_message(format!("`{}` is first declared here", id)), - ]), - ) - } - } - } - - // Return failure if any diagnostic is raised. - if diagnostics.is_empty() { - Ok(scope) - } else { - Err(diagnostics) - } - } - - /// Return the parent declaration of the selected declaration, - /// if it has one. - pub fn get_parent(&self, decl: &crate::ast::Decl) -> Option<&'d crate::ast::Decl> { - decl.parent_id().and_then(|parent_id| self.typedef.get(parent_id).cloned()) - } - - /// Iterate over the parent declarations of the selected declaration. - pub fn iter_parents<'s>( - &'s self, - decl: &'d crate::ast::Decl, - ) -> impl Iterator> + 's { - std::iter::successors(self.get_parent(decl), |decl| self.get_parent(decl)) - } - - /// Iterate over the declaration and its parent's fields. - pub fn iter_fields<'s>( - &'s self, - decl: &'d crate::ast::Decl, - ) -> impl Iterator> + 's { - std::iter::successors(Some(decl), |decl| self.get_parent(decl)).flat_map(Decl::fields) - } - - /// Return the type declaration for the selected field, if applicable. - #[allow(dead_code)] - pub fn get_declaration( - &self, - field: &'d crate::ast::Field, - ) -> Option<&'d crate::ast::Decl> { - match &field.desc { - FieldDesc::Checksum { .. } - | FieldDesc::Padding { .. } - | FieldDesc::Size { .. } - | FieldDesc::Count { .. } - | FieldDesc::ElementSize { .. } - | FieldDesc::Body - | FieldDesc::Payload { .. } - | FieldDesc::FixedScalar { .. } - | FieldDesc::Reserved { .. } - | FieldDesc::Group { .. } - | FieldDesc::Scalar { .. } - | FieldDesc::Array { type_id: None, .. } => None, - FieldDesc::FixedEnum { enum_id: type_id, .. } - | FieldDesc::Array { type_id: Some(type_id), .. } - | FieldDesc::Typedef { type_id, .. } => self.typedef.get(type_id).cloned(), - } - } -} - -/// Return the bit-width of a scalar value. -fn bit_width(value: usize) -> usize { - usize::BITS as usize - value.leading_zeros() as usize -} - -/// Return the maximum value for a scalar value. -fn scalar_max(width: usize) -> usize { - if width >= usize::BITS as usize { - usize::MAX - } else { - (1 << width) - 1 - } -} - -/// Check declaration identifiers. -/// Raises error diagnostics for the following cases: -/// - undeclared parent identifier -/// - invalid parent identifier -/// - undeclared group identifier -/// - invalid group identifier -/// - undeclared typedef identifier -/// - invalid typedef identifier -/// - undeclared test identifier -/// - invalid test identifier -/// - recursive declaration -fn check_decl_identifiers( - file: &parser_ast::File, - scope: &Scope, -) -> Result<(), Diagnostics> { - enum Mark { - Temporary, - Permanent, - } - #[derive(Default)] - struct Context<'d> { - visited: HashMap<&'d str, Mark>, - } - - fn bfs<'d>( - decl: &'d parser_ast::Decl, - context: &mut Context<'d>, - scope: &Scope<'d, parser_ast::Annotation>, - diagnostics: &mut Diagnostics, - ) { - let decl_id = decl.id().unwrap(); - match context.visited.get(decl_id) { - Some(Mark::Permanent) => return, - Some(Mark::Temporary) => { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::RecursiveDecl) - .with_message(format!( - "recursive declaration of {} `{}`", - decl.kind(), - decl_id - )) - .with_labels(vec![decl.loc.primary()]), - ); - return; - } - _ => (), - } - - // Start visiting current declaration. - context.visited.insert(decl_id, Mark::Temporary); - - // Iterate over Struct and Group fields. - for field in decl.fields() { - match &field.desc { - // Validate that the group field has a valid identifier. - // If the type is a group recurse the group definition. - FieldDesc::Group { group_id, .. } => match scope.typedef.get(group_id) { - None => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::UndeclaredGroupIdentifier) - .with_message(format!("undeclared group identifier `{}`", group_id)) - .with_labels(vec![field.loc.primary()]) - .with_notes(vec!["hint: expected group identifier".to_owned()]), - ), - Some(group_decl @ Decl { desc: DeclDesc::Group { .. }, .. }) => { - bfs(group_decl, context, scope, diagnostics) - } - Some(_) => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidGroupIdentifier) - .with_message(format!("invalid group identifier `{}`", group_id)) - .with_labels(vec![field.loc.primary()]) - .with_notes(vec!["hint: expected group identifier".to_owned()]), - ), - }, - // Validate that the typedef field has a valid identifier. - // If the type is a struct recurse the struct definition. - // Append the field to the packet re-definition. - FieldDesc::Typedef { type_id, .. } - | FieldDesc::Array { type_id: Some(type_id), .. } => { - match scope.typedef.get(type_id) { - None => diagnostics.push( - Diagnostic::error().with_code(ErrorCode::UndeclaredTypeIdentifier) - .with_message(format!( - "undeclared {} identifier `{}`", - field.kind(), - type_id - )) - .with_labels(vec![field.loc.primary()]) - .with_notes(vec!["hint: expected enum, struct, custom_field, or checksum identifier".to_owned()]), - ), - Some(Decl { desc: DeclDesc::Packet { .. }, .. }) => diagnostics.push( - Diagnostic::error().with_code(ErrorCode::InvalidTypeIdentifier) - .with_message(format!( - "invalid {} identifier `{}`", - field.kind(), - type_id - )) - .with_labels(vec![field.loc.primary()]) - .with_notes(vec!["hint: expected enum, struct, custom_field, or checksum identifier".to_owned()]), - ), - Some(typedef_decl) => - // Not recursing on array type since it is allowed to - // have recursive structures, e.g. nested TLV types. - if matches!(&field.desc, FieldDesc::Typedef { .. }) || - matches!(&field.desc, FieldDesc::Array { size: Some(_), .. }) { - bfs(typedef_decl, context, scope, diagnostics) - } - } - } - // Ignore other fields. - _ => (), - } - } - - // Iterate over parent declaration. - if let Some(parent_id) = decl.parent_id() { - let parent_decl = scope.typedef.get(parent_id); - match (&decl.desc, parent_decl) { - (DeclDesc::Packet { .. }, None) | (DeclDesc::Struct { .. }, None) => diagnostics - .push( - Diagnostic::error() - .with_code(ErrorCode::UndeclaredParentIdentifier) - .with_message(format!("undeclared parent identifier `{}`", parent_id)) - .with_labels(vec![decl.loc.primary()]) - .with_notes(vec![format!("hint: expected {} identifier", decl.kind())]), - ), - ( - DeclDesc::Packet { .. }, - Some(parent_decl @ Decl { desc: DeclDesc::Packet { .. }, .. }), - ) - | ( - DeclDesc::Struct { .. }, - Some(parent_decl @ Decl { desc: DeclDesc::Struct { .. }, .. }), - ) => bfs(parent_decl, context, scope, diagnostics), - (_, Some(_)) => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidParentIdentifier) - .with_message(format!("invalid parent identifier `{}`", parent_id)) - .with_labels(vec![decl.loc.primary()]) - .with_notes(vec![format!("hint: expected {} identifier", decl.kind())]), - ), - _ => unreachable!(), - } - } - - // Done visiting current declaration. - context.visited.insert(decl_id, Mark::Permanent); - } - - // Start bfs. - let mut diagnostics = Default::default(); - let mut context = Default::default(); - for decl in &file.declarations { - match &decl.desc { - DeclDesc::Checksum { .. } | DeclDesc::CustomField { .. } | DeclDesc::Enum { .. } => (), - DeclDesc::Packet { .. } | DeclDesc::Struct { .. } | DeclDesc::Group { .. } => { - bfs(decl, &mut context, scope, &mut diagnostics) - } - DeclDesc::Test { type_id, .. } => match scope.typedef.get(type_id) { - None => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::UndeclaredTestIdentifier) - .with_message(format!("undeclared test identifier `{}`", type_id)) - .with_labels(vec![decl.loc.primary()]) - .with_notes(vec!["hint: expected packet identifier".to_owned()]), - ), - Some(Decl { desc: DeclDesc::Packet { .. }, .. }) => (), - Some(_) => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidTestIdentifier) - .with_message(format!("invalid test identifier `{}`", type_id)) - .with_labels(vec![decl.loc.primary()]) - .with_notes(vec!["hint: expected packet identifier".to_owned()]), - ), - }, - } - } - - diagnostics.err_or(()) -} - -/// Check field identifiers. -/// Raises error diagnostics for the following cases: -/// - duplicate field identifier -fn check_field_identifiers(file: &parser_ast::File) -> Result<(), Diagnostics> { - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - let mut local_scope = HashMap::new(); - for field in decl.fields() { - if let Some(id) = field.id() { - if let Some(prev) = local_scope.insert(id.to_string(), field) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateFieldIdentifier) - .with_message(format!( - "redeclaration of {} field identifier `{}`", - field.kind(), - id - )) - .with_labels(vec![ - field.loc.primary(), - prev.loc - .secondary() - .with_message(format!("`{}` is first declared here", id)), - ]), - ) - } - } - } - } - - diagnostics.err_or(()) -} - -/// Check enum declarations. -/// Raises error diagnostics for the following cases: -/// - duplicate tag identifier -/// - duplicate tag value -fn check_enum_declarations(file: &parser_ast::File) -> Result<(), Diagnostics> { - // Return the inclusive range with bounds correctly ordered. - // The analyzer will raise an error if the bounds are incorrectly ordered, but this - // will enable additional checks. - fn ordered_range(range: &std::ops::RangeInclusive) -> std::ops::RangeInclusive { - *std::cmp::min(range.start(), range.end())..=*std::cmp::max(range.start(), range.end()) - } - - fn check_tag_value<'a>( - tag: &'a TagValue, - range: std::ops::RangeInclusive, - reserved_ranges: impl Iterator, - tags_by_id: &mut HashMap<&'a str, SourceRange>, - tags_by_value: &mut HashMap, - diagnostics: &mut Diagnostics, - ) { - if let Some(prev) = tags_by_id.insert(&tag.id, tag.loc) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateTagIdentifier) - .with_message(format!("duplicate tag identifier `{}`", tag.id)) - .with_labels(vec![ - tag.loc.primary(), - prev.secondary() - .with_message(format!("`{}` is first declared here", tag.id)), - ]), - ) - } - if let Some(prev) = tags_by_value.insert(tag.value, tag.loc) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateTagValue) - .with_message(format!("duplicate tag value `{}`", tag.value)) - .with_labels(vec![ - tag.loc.primary(), - prev.secondary() - .with_message(format!("`{}` is first declared here", tag.value)), - ]), - ) - } - if !range.contains(&tag.value) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidTagValue) - .with_message(format!( - "tag value `{}` is outside the range of valid values `{}..{}`", - tag.value, - range.start(), - range.end() - )) - .with_labels(vec![tag.loc.primary()]), - ) - } - for reserved_range in reserved_ranges { - if ordered_range(&reserved_range.range).contains(&tag.value) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E43) - .with_message(format!( - "tag value `{}` is declared inside the reserved range `{} = {}..{}`", - tag.value, - reserved_range.id, - reserved_range.range.start(), - reserved_range.range.end() - )) - .with_labels(vec![tag.loc.primary()]), - ) - } - } - } - - fn check_tag_range<'a>( - tag: &'a TagRange, - range: std::ops::RangeInclusive, - tags_by_id: &mut HashMap<&'a str, SourceRange>, - tags_by_value: &mut HashMap, - diagnostics: &mut Diagnostics, - ) { - if let Some(prev) = tags_by_id.insert(&tag.id, tag.loc) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateTagIdentifier) - .with_message(format!("duplicate tag identifier `{}`", tag.id)) - .with_labels(vec![ - tag.loc.primary(), - prev.secondary() - .with_message(format!("`{}` is first declared here", tag.id)), - ]), - ) - } - if !range.contains(tag.range.start()) || !range.contains(tag.range.end()) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidTagRange) - .with_message(format!( - "tag range `{}..{}` has bounds outside the range of valid values `{}..{}`", - tag.range.start(), - tag.range.end(), - range.start(), - range.end(), - )) - .with_labels(vec![tag.loc.primary()]), - ) - } - if tag.range.start() >= tag.range.end() { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidTagRange) - .with_message(format!( - "tag start value `{}` is greater than or equal to the end value `{}`", - tag.range.start(), - tag.range.end() - )) - .with_labels(vec![tag.loc.primary()]), - ) - } - - let range = ordered_range(&tag.range); - for tag in tag.tags.iter() { - check_tag_value(tag, range.clone(), [].iter(), tags_by_id, tags_by_value, diagnostics) - } - } - - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - if let DeclDesc::Enum { tags, width, .. } = &decl.desc { - let mut tags_by_id = HashMap::new(); - let mut tags_by_value = HashMap::new(); - let mut tags_by_range = tags - .iter() - .filter_map(|tag| match tag { - Tag::Range(tag) => Some(tag), - _ => None, - }) - .collect::>(); - - for tag in tags { - match tag { - Tag::Value(value) => check_tag_value( - value, - 0..=scalar_max(*width), - tags_by_range.iter().copied(), - &mut tags_by_id, - &mut tags_by_value, - &mut diagnostics, - ), - Tag::Range(range) => check_tag_range( - range, - 0..=scalar_max(*width), - &mut tags_by_id, - &mut tags_by_value, - &mut diagnostics, - ), - } - } - - // Order tag ranges by increasing bounds in order to check for intersecting ranges. - tags_by_range.sort_by(|lhs, rhs| { - ordered_range(&lhs.range).into_inner().cmp(&ordered_range(&rhs.range).into_inner()) - }); - - // Iterate to check for overlap between tag ranges. - // Not all potential errors are reported, but the check will report - // at least one error if the values are incorrect. - for tag in tags_by_range.windows(2) { - let left_tag = tag[0]; - let right_tag = tag[1]; - let left = ordered_range(&left_tag.range); - let right = ordered_range(&right_tag.range); - if !(left.end() < right.start() || right.end() < left.start()) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateTagRange) - .with_message(format!( - "overlapping tag range `{}..{}`", - right.start(), - right.end() - )) - .with_labels(vec![ - right_tag.loc.primary(), - left_tag.loc.secondary().with_message(format!( - "`{}..{}` is first declared here", - left.start(), - left.end() - )), - ]), - ) - } - } - } - } - - diagnostics.err_or(()) -} - -/// Check constraints. -/// Raises error diagnostics for the following cases: -/// - undeclared constraint identifier -/// - invalid constraint identifier -/// - invalid constraint scalar value (bad type) -/// - invalid constraint scalar value (overflow) -/// - invalid constraint enum value (bad type) -/// - invalid constraint enum value (undeclared tag) -/// - duplicate constraint -fn check_constraints( - file: &parser_ast::File, - scope: &Scope, -) -> Result<(), Diagnostics> { - fn check_constraint( - constraint: &Constraint, - decl: &parser_ast::Decl, - scope: &Scope, - diagnostics: &mut Diagnostics, - ) { - match scope.iter_fields(decl).find(|field| field.id() == Some(&constraint.id)) { - None => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::UndeclaredConstraintIdentifier) - .with_message(format!("undeclared constraint identifier `{}`", constraint.id)) - .with_labels(vec![constraint.loc.primary()]) - .with_notes(vec!["hint: expected scalar or typedef identifier".to_owned()]), - ), - Some(field @ Field { desc: FieldDesc::Array { .. }, .. }) => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidConstraintIdentifier) - .with_message(format!("invalid constraint identifier `{}`", constraint.id)) - .with_labels(vec![ - constraint.loc.primary(), - field.loc.secondary().with_message(format!( - "`{}` is declared here as array field", - constraint.id - )), - ]) - .with_notes(vec!["hint: expected scalar or typedef identifier".to_owned()]), - ), - Some(field @ Field { desc: FieldDesc::Scalar { width, .. }, .. }) => { - match constraint.value { - None => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E17) - .with_message(format!( - "invalid constraint value `{}`", - constraint.tag_id.as_ref().unwrap() - )) - .with_labels(vec![ - constraint.loc.primary(), - field.loc.secondary().with_message(format!( - "`{}` is declared here as scalar field", - constraint.id - )), - ]) - .with_notes(vec!["hint: expected scalar value".to_owned()]), - ), - Some(value) if bit_width(value) > *width => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::ConstraintValueOutOfRange) - .with_message(format!( - "constraint value `{}` is larger than maximum value", - value - )) - .with_labels(vec![constraint.loc.primary(), field.loc.secondary()]), - ), - _ => (), - } - } - Some(field @ Field { desc: FieldDesc::Typedef { type_id, .. }, .. }) => { - match scope.typedef.get(type_id) { - None => (), - Some(Decl { desc: DeclDesc::Enum { tags, .. }, .. }) => { - match &constraint.tag_id { - None => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E19) - .with_message(format!( - "invalid constraint value `{}`", - constraint.value.unwrap() - )) - .with_labels(vec![ - constraint.loc.primary(), - field.loc.secondary().with_message(format!( - "`{}` is declared here as typedef field", - constraint.id - )), - ]) - .with_notes(vec!["hint: expected enum value".to_owned()]), - ), - Some(tag_id) => match tags.iter().find(|tag| tag.id() == tag_id) { - None => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E20) - .with_message(format!("undeclared enum tag `{}`", tag_id)) - .with_labels(vec![ - constraint.loc.primary(), - field.loc.secondary().with_message(format!( - "`{}` is declared here", - constraint.id - )), - ]), - ), - Some(Tag::Range { .. }) => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E42) - .with_message(format!( - "enum tag `{}` defines a range", - tag_id - )) - .with_labels(vec![ - constraint.loc.primary(), - field.loc.secondary().with_message(format!( - "`{}` is declared here", - constraint.id - )), - ]) - .with_notes(vec![ - "hint: expected enum tag with value".to_owned() - ]), - ), - Some(_) => (), - }, - } - } - Some(decl) => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E21) - .with_message(format!( - "invalid constraint identifier `{}`", - constraint.value.unwrap() - )) - .with_labels(vec![ - constraint.loc.primary(), - field.loc.secondary().with_message(format!( - "`{}` is declared here as {} typedef field", - constraint.id, - decl.kind() - )), - ]) - .with_notes(vec!["hint: expected enum value".to_owned()]), - ), - } - } - Some(_) => unreachable!(), - } - } - - fn check_constraints<'d>( - constraints: &'d [Constraint], - parent_decl: &parser_ast::Decl, - scope: &Scope, - mut constraints_by_id: HashMap, - diagnostics: &mut Diagnostics, - ) { - for constraint in constraints { - check_constraint(constraint, parent_decl, scope, diagnostics); - if let Some(prev) = constraints_by_id.insert(constraint.id.to_string(), constraint) { - // Constraint appears twice in current set. - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateConstraintIdentifier) - .with_message(format!( - "duplicate constraint identifier `{}`", - constraint.id - )) - .with_labels(vec![ - constraint.loc.primary(), - prev.loc - .secondary() - .with_message(format!("`{}` is first constrained here", prev.id)), - ]), - ) - } - } - } - - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - // Check constraints for packet inheritance. - match &decl.desc { - DeclDesc::Packet { constraints, parent_id: Some(parent_id), .. } - | DeclDesc::Struct { constraints, parent_id: Some(parent_id), .. } => { - let parent_decl = scope.typedef.get(parent_id).unwrap(); - check_constraints( - constraints, - parent_decl, - scope, - // Include constraints declared in parent declarations - // for duplicate check. - scope.iter_parents(decl).fold(HashMap::new(), |acc, decl| { - decl.constraints().fold(acc, |mut acc, constraint| { - let _ = acc.insert(constraint.id.to_string(), constraint); - acc - }) - }), - &mut diagnostics, - ) - } - _ => (), - } - - // Check constraints for group inlining. - for field in decl.fields() { - if let FieldDesc::Group { group_id, constraints } = &field.desc { - let group_decl = scope.typedef.get(group_id).unwrap(); - check_constraints(constraints, group_decl, scope, HashMap::new(), &mut diagnostics) - } - } - } - - diagnostics.err_or(()) -} - -/// Check size fields. -/// Raises error diagnostics for the following cases: -/// - undeclared size identifier -/// - invalid size identifier -/// - duplicate size field -/// - undeclared count identifier -/// - invalid count identifier -/// - duplicate count field -/// - undeclared elementsize identifier -/// - invalid elementsize identifier -/// - duplicate elementsize field -fn check_size_fields(file: &parser_ast::File) -> Result<(), Diagnostics> { - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - let mut size_for_id = HashMap::new(); - let mut element_size_for_id = HashMap::new(); - for field in decl.fields() { - // Check for duplicate size, count, or element size fields. - if let Some((reverse_map, field_id, err)) = match &field.desc { - FieldDesc::Size { field_id, .. } => { - Some((&mut size_for_id, field_id, ErrorCode::DuplicateSizeField)) - } - FieldDesc::Count { field_id, .. } => { - Some((&mut size_for_id, field_id, ErrorCode::DuplicateCountField)) - } - FieldDesc::ElementSize { field_id, .. } => { - Some((&mut element_size_for_id, field_id, ErrorCode::DuplicateElementSizeField)) - } - _ => None, - } { - if let Some(prev) = reverse_map.insert(field_id, field) { - diagnostics.push( - Diagnostic::error() - .with_code(err) - .with_message(format!("duplicate {} field", field.kind())) - .with_labels(vec![ - field.loc.primary(), - prev.loc.secondary().with_message(format!( - "{} is first declared here", - prev.kind() - )), - ]), - ) - } - } - - // Check for invalid size, count, or element size field identifiers. - match &field.desc { - FieldDesc::Size { field_id, .. } => { - match decl.fields().find(|field| match &field.desc { - FieldDesc::Payload { .. } => field_id == "_payload_", - FieldDesc::Body { .. } => field_id == "_body_", - _ => field.id() == Some(field_id), - }) { - None => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::UndeclaredSizeIdentifier) - .with_message(format!( - "undeclared {} identifier `{}`", - field.kind(), - field_id - )) - .with_labels(vec![field.loc.primary()]) - .with_notes(vec![ - "hint: expected payload, body, or array identifier".to_owned(), - ]), - ), - Some(Field { desc: FieldDesc::Body { .. }, .. }) - | Some(Field { desc: FieldDesc::Payload { .. }, .. }) - | Some(Field { desc: FieldDesc::Array { .. }, .. }) => (), - Some(Field { loc, .. }) => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidSizeIdentifier) - .with_message(format!( - "invalid {} identifier `{}`", - field.kind(), - field_id - )) - .with_labels(vec![field.loc.primary(), loc.secondary()]) - .with_notes(vec![ - "hint: expected payload, body, or array identifier".to_owned(), - ]), - ), - } - } - - FieldDesc::Count { field_id, .. } | FieldDesc::ElementSize { field_id, .. } => { - let (undeclared_err, invalid_err) = - if matches!(&field.desc, FieldDesc::Count { .. }) { - ( - ErrorCode::UndeclaredCountIdentifier, - ErrorCode::InvalidCountIdentifier, - ) - } else { - ( - ErrorCode::UndeclaredElementSizeIdentifier, - ErrorCode::InvalidElementSizeIdentifier, - ) - }; - match decl.fields().find(|field| field.id() == Some(field_id)) { - None => diagnostics.push( - Diagnostic::error() - .with_code(undeclared_err) - .with_message(format!( - "undeclared {} identifier `{}`", - field.kind(), - field_id - )) - .with_labels(vec![field.loc.primary()]) - .with_notes(vec!["hint: expected array identifier".to_owned()]), - ), - Some(Field { desc: FieldDesc::Array { .. }, .. }) => (), - Some(Field { loc, .. }) => diagnostics.push( - Diagnostic::error() - .with_code(invalid_err) - .with_message(format!( - "invalid {} identifier `{}`", - field.kind(), - field_id - )) - .with_labels(vec![field.loc.primary(), loc.secondary()]) - .with_notes(vec!["hint: expected array identifier".to_owned()]), - ), - } - } - _ => (), - } - } - } - - diagnostics.err_or(()) -} - -/// Check fixed fields. -/// Raises error diagnostics for the following cases: -/// - invalid scalar value -/// - undeclared enum identifier -/// - invalid enum identifier -/// - undeclared tag identifier -fn check_fixed_fields( - file: &parser_ast::File, - scope: &Scope, -) -> Result<(), Diagnostics> { - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - for field in decl.fields() { - match &field.desc { - FieldDesc::FixedScalar { value, width } if bit_width(*value) > *width => { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::FixedValueOutOfRange) - .with_message(format!( - "fixed value `{}` is larger than maximum value", - value - )) - .with_labels(vec![field.loc.primary()]), - ) - } - FieldDesc::FixedEnum { tag_id, enum_id } => match scope.typedef.get(enum_id) { - None => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E33) - .with_message(format!("undeclared type identifier `{}`", enum_id)) - .with_labels(vec![field.loc.primary()]) - .with_notes(vec!["hint: expected enum identifier".to_owned()]), - ), - Some(enum_decl @ Decl { desc: DeclDesc::Enum { tags, .. }, .. }) => { - if !tags.iter().any(|tag| tag.id() == tag_id) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E34) - .with_message(format!("undeclared tag identifier `{}`", tag_id)) - .with_labels(vec![ - field.loc.primary(), - enum_decl.loc.secondary(), - ]), - ) - } - } - Some(decl) => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::E35) - .with_message(format!("invalid type identifier `{}`", enum_id)) - .with_labels(vec![ - field.loc.primary(), - decl.loc - .secondary() - .with_message(format!("`{}` is declared here", enum_id)), - ]) - .with_notes(vec!["hint: expected enum identifier".to_owned()]), - ), - }, - _ => (), - } - } - } - - diagnostics.err_or(()) -} - -/// Check payload fields. -/// Raises error diagnostics for the following cases: -/// - duplicate payload field -/// - duplicate payload field size -/// - duplicate body field -/// - duplicate body field size -/// - missing payload field -fn check_payload_fields(file: &parser_ast::File) -> Result<(), Diagnostics> { - // Check whether the declaration requires a payload field. - // The payload is required if any child packets declares fields. - fn requires_payload(file: &parser_ast::File, decl: &parser_ast::Decl) -> bool { - file.iter_children(decl).any(|child| child.fields().next().is_some()) - } - - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - let mut payload: Option<&parser_ast::Field> = None; - for field in decl.fields() { - match &field.desc { - FieldDesc::Payload { .. } | FieldDesc::Body { .. } => { - if let Some(prev) = payload { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicatePayloadField) - .with_message(format!("duplicate {} field", field.kind())) - .with_labels(vec![ - field.loc.primary(), - prev.loc.secondary().with_message(format!( - "{} is first declared here", - prev.kind() - )), - ]), - ) - } else { - payload = Some(field); - } - } - _ => (), - } - } - - if payload.is_none() && requires_payload(file, decl) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::MissingPayloadField) - .with_message("missing payload field".to_owned()) - .with_labels(vec![decl.loc.primary()]) - .with_notes(vec![format!( - "hint: one child packet is extending `{}`", - decl.id().unwrap() - )]), - ) - } - } - - diagnostics.err_or(()) -} - -/// Check array fields. -/// Raises error diagnostics for the following cases: -/// - redundant array field size -fn check_array_fields(file: &parser_ast::File) -> Result<(), Diagnostics> { - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - for field in decl.fields() { - if let FieldDesc::Array { id, size: Some(size), .. } = &field.desc { - if let Some(size_field) = decl.fields().find(|field| match &field.desc { - FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => { - field_id == id - } - _ => false, - }) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::RedundantArraySize) - .with_message(format!("redundant array {} field", size_field.kind())) - .with_labels(vec![ - size_field.loc.primary(), - field - .loc - .secondary() - .with_message(format!("`{}` has constant size {}", id, size)), - ]), - ) - } - } - } - } - - diagnostics.err_or(()) -} - -/// Check padding fields. -/// Raises error diagnostics for the following cases: -/// - padding field not following an array field -fn check_padding_fields(file: &parser_ast::File) -> Result<(), Diagnostics> { - let mut diagnostics: Diagnostics = Default::default(); - for decl in &file.declarations { - let mut previous_is_array = false; - for field in decl.fields() { - match &field.desc { - FieldDesc::Padding { .. } if !previous_is_array => diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::InvalidPaddingField) - .with_message("padding field does not follow an array field".to_owned()) - .with_labels(vec![field.loc.primary()]), - ), - FieldDesc::Array { .. } => previous_is_array = true, - _ => previous_is_array = false, - } - } - } - - diagnostics.err_or(()) -} - -/// Check checksum fields. -/// Raises error diagnostics for the following cases: -/// - checksum field precedes checksum start -/// - undeclared checksum field -/// - invalid checksum field -fn check_checksum_fields( - _file: &parser_ast::File, - _scope: &Scope, -) -> Result<(), Diagnostics> { - // TODO - Ok(()) -} - -/// Check correct definition of packet sizes. -/// Annotate fields and declarations with the size in bits. -fn compute_field_sizes(file: &parser_ast::File) -> ast::File { - fn annotate_decl( - decl: &parser_ast::Decl, - scope: &HashMap, - ) -> ast::Decl { - // Annotate the declaration fields. - let mut decl = decl.annotate(Default::default(), |fields| { - fields.iter().map(|field| annotate_field(decl, field, scope)).collect() - }); - - // Compute the declaration annotation. - decl.annot = match &decl.desc { - DeclDesc::Packet { fields, .. } - | DeclDesc::Struct { fields, .. } - | DeclDesc::Group { fields, .. } => { - let mut size = decl - .parent_id() - .and_then(|parent_id| scope.get(parent_id)) - .map(|annot| annot.size) - .unwrap_or(ast::Size::Static(0)); - let mut payload_size = ast::Size::Static(0); - for field in fields { - match &field.desc { - FieldDesc::Payload { .. } | FieldDesc::Body { .. } => { - payload_size = field.annot.size - } - _ => size = size + field.annot.size, - } - } - ast::DeclAnnotation { size, payload_size } - } - DeclDesc::Enum { width, .. } - | DeclDesc::Checksum { width, .. } - | DeclDesc::CustomField { width: Some(width), .. } => { - ast::DeclAnnotation { size: ast::Size::Static(*width), ..decl.annot } - } - DeclDesc::CustomField { width: None, .. } => { - ast::DeclAnnotation { size: ast::Size::Dynamic, ..decl.annot } - } - DeclDesc::Test { .. } => { - ast::DeclAnnotation { size: ast::Size::Static(0), ..decl.annot } - } - }; - decl - } - - fn annotate_field( - decl: &parser_ast::Decl, - field: &parser_ast::Field, - scope: &HashMap, - ) -> ast::Field { - field.annotate(match &field.desc { - FieldDesc::Checksum { .. } | FieldDesc::Padding { .. } => { - ast::FieldAnnotation { size: ast::Size::Static(0) } - } - FieldDesc::Size { width, .. } - | FieldDesc::Count { width, .. } - | FieldDesc::ElementSize { width, .. } - | FieldDesc::FixedScalar { width, .. } - | FieldDesc::Reserved { width } - | FieldDesc::Scalar { width, .. } => { - ast::FieldAnnotation { size: ast::Size::Static(*width) } - } - FieldDesc::Body | FieldDesc::Payload { .. } => { - let has_payload_size = decl.fields().any(|field| match &field.desc { - FieldDesc::Size { field_id, .. } => { - field_id == "_body_" || field_id == "_payload_" - } - _ => false, - }); - ast::FieldAnnotation { - size: if has_payload_size { ast::Size::Dynamic } else { ast::Size::Unknown }, - } - } - FieldDesc::Typedef { type_id, .. } - | FieldDesc::FixedEnum { enum_id: type_id, .. } - | FieldDesc::Group { group_id: type_id, .. } => { - let type_annot = scope.get(type_id).unwrap(); - ast::FieldAnnotation { size: type_annot.size + type_annot.payload_size } - } - FieldDesc::Array { width: Some(width), size: Some(size), .. } => { - ast::FieldAnnotation { size: ast::Size::Static(*size * *width) } - } - FieldDesc::Array { width: None, size: Some(size), type_id: Some(type_id), .. } => { - let type_annot = scope.get(type_id).unwrap(); - ast::FieldAnnotation { size: (type_annot.size + type_annot.payload_size) * *size } - } - FieldDesc::Array { id, size: None, .. } => { - // The element does not matter when the size of the array is - // not static. The array size depends on there being a count - // or size field or not. - let has_array_size = decl.fields().any(|field| match &field.desc { - FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => { - field_id == id - } - _ => false, - }); - ast::FieldAnnotation { - size: if has_array_size { ast::Size::Dynamic } else { ast::Size::Unknown }, - } - } - FieldDesc::Array { .. } => unreachable!(), - }) - } - - // Construct a scope mapping typedef identifiers to decl annotations. - let mut scope = HashMap::new(); - - // Annotate declarations. - let mut declarations = Vec::new(); - for decl in file.declarations.iter() { - let decl = annotate_decl(decl, &scope); - if let Some(id) = decl.id() { - scope.insert(id.to_string(), decl.annot.clone()); - } - declarations.push(decl); - } - - File { - version: file.version.clone(), - file: file.file, - comments: file.comments.clone(), - endianness: file.endianness, - declarations, - } -} - -/// Inline group fields and remove group declarations. -fn inline_groups(file: &mut ast::File) -> Result<(), Diagnostics> { - fn inline_fields<'a>( - fields: impl Iterator, - groups: &HashMap, - constraints: &HashMap, - ) -> Vec { - fields - .flat_map(|field| match &field.desc { - FieldDesc::Group { group_id, constraints: group_constraints } => { - let mut constraints = constraints.clone(); - constraints.extend( - group_constraints - .iter() - .map(|constraint| (constraint.id.clone(), constraint.clone())), - ); - inline_fields(groups.get(group_id).unwrap().fields(), groups, &constraints) - } - FieldDesc::Scalar { id, width } if constraints.contains_key(id) => { - vec![ast::Field { - desc: FieldDesc::FixedScalar { - width: *width, - value: constraints.get(id).unwrap().value.unwrap(), - }, - loc: field.loc, - annot: field.annot.clone(), - }] - } - FieldDesc::Typedef { id, type_id, .. } if constraints.contains_key(id) => { - vec![ast::Field { - desc: FieldDesc::FixedEnum { - enum_id: type_id.clone(), - tag_id: constraints - .get(id) - .and_then(|constraint| constraint.tag_id.clone()) - .unwrap(), - }, - loc: field.loc, - annot: field.annot.clone(), - }] - } - _ => vec![field.clone()], - }) - .collect() - } - - let groups = utils::drain_filter(&mut file.declarations, |decl| { - matches!(&decl.desc, DeclDesc::Group { .. }) - }) - .into_iter() - .map(|decl| (decl.id().unwrap().to_owned(), decl)) - .collect::>(); - - for decl in file.declarations.iter_mut() { - match &mut decl.desc { - DeclDesc::Packet { fields, .. } | DeclDesc::Struct { fields, .. } => { - *fields = inline_fields(fields.iter(), &groups, &HashMap::new()) - } - _ => (), - } - } - - Ok(()) -} - -/// Analyzer entry point, produces a new AST with annotations resulting -/// from the analysis. -pub fn analyze(file: &parser_ast::File) -> Result { - let scope = Scope::new(file)?; - check_decl_identifiers(file, &scope)?; - check_field_identifiers(file)?; - check_enum_declarations(file)?; - check_constraints(file, &scope)?; - check_size_fields(file)?; - check_fixed_fields(file, &scope)?; - check_payload_fields(file)?; - check_array_fields(file)?; - check_padding_fields(file)?; - check_checksum_fields(file, &scope)?; - let mut file = compute_field_sizes(file); - inline_groups(&mut file)?; - Ok(file) -} - -#[cfg(test)] -mod test { - use crate::analyzer; - use crate::ast::*; - use crate::parser::parse_inline; - use codespan_reporting::term::termcolor; - - macro_rules! raises { - ($code:ident, $text:literal) => {{ - let mut db = SourceDatabase::new(); - let file = parse_inline(&mut db, "stdin".to_owned(), $text.to_owned()) - .expect("parsing failure"); - let result = analyzer::analyze(&file); - assert!(matches!(result, Err(_))); - let diagnostics = result.err().unwrap(); - let mut buffer = termcolor::Buffer::no_color(); - let _ = diagnostics.emit(&db, &mut buffer); - println!("{}", std::str::from_utf8(buffer.as_slice()).unwrap()); - assert_eq!(diagnostics.diagnostics.len(), 1); - assert_eq!(diagnostics.diagnostics[0].code, Some(analyzer::ErrorCode::$code.into())); - }}; - } - - macro_rules! valid { - ($text:literal) => {{ - let mut db = SourceDatabase::new(); - let file = parse_inline(&mut db, "stdin".to_owned(), $text.to_owned()) - .expect("parsing failure"); - assert!(analyzer::analyze(&file).is_ok()); - }}; - } - - #[test] - fn test_e1() { - raises!( - DuplicateDeclIdentifier, - r#" - little_endian_packets - struct A { } - packet A { } - "# - ); - - raises!( - DuplicateDeclIdentifier, - r#" - little_endian_packets - struct A { } - enum A : 8 { X = 0, Y = 1 } - "# - ); - } - - #[test] - fn test_e2() { - raises!( - RecursiveDecl, - r#" - little_endian_packets - packet A : A { } - "# - ); - - raises!( - RecursiveDecl, - r#" - little_endian_packets - packet A : B { } - packet B : A { } - "# - ); - - raises!( - RecursiveDecl, - r#" - little_endian_packets - struct B { x : B } - "# - ); - - raises!( - RecursiveDecl, - r#" - little_endian_packets - struct B { x : B[8] } - "# - ); - - raises!( - RecursiveDecl, - r#" - little_endian_packets - group C { C { x = 1 } } - "# - ); - } - - #[test] - fn test_e3() { - raises!( - UndeclaredGroupIdentifier, - r#" - little_endian_packets - packet A { C { x = 1 } } - "# - ); - } - - #[test] - fn test_e4() { - raises!( - InvalidGroupIdentifier, - r#" - little_endian_packets - struct C { x : 8 } - packet A { C { x = 1 } } - "# - ); - } - - #[test] - fn test_e5() { - raises!( - UndeclaredTypeIdentifier, - r#" - little_endian_packets - packet A { x : B } - "# - ); - - raises!( - UndeclaredTypeIdentifier, - r#" - little_endian_packets - packet A { x : B[] } - "# - ); - } - - #[test] - fn test_e6() { - raises!( - InvalidTypeIdentifier, - r#" - little_endian_packets - packet A { x : 8 } - packet B { x : A } - "# - ); - - raises!( - InvalidTypeIdentifier, - r#" - little_endian_packets - packet A { x : 8 } - packet B { x : A[] } - "# - ); - } - - #[test] - fn test_e7() { - raises!( - UndeclaredParentIdentifier, - r#" - little_endian_packets - packet A : B { } - "# - ); - - raises!( - UndeclaredParentIdentifier, - r#" - little_endian_packets - struct A : B { } - "# - ); - } - - #[test] - fn test_e8() { - raises!( - InvalidParentIdentifier, - r#" - little_endian_packets - struct A { } - packet B : A { } - "# - ); - - raises!( - InvalidParentIdentifier, - r#" - little_endian_packets - packet A { } - struct B : A { } - "# - ); - - raises!( - InvalidParentIdentifier, - r#" - little_endian_packets - group A { x : 1 } - struct B : A { } - "# - ); - } - - #[ignore] - #[test] - fn test_e9() { - raises!( - UndeclaredTestIdentifier, - r#" - little_endian_packets - test A { "aaa" } - "# - ); - } - - #[ignore] - #[test] - fn test_e10() { - raises!( - InvalidTestIdentifier, - r#" - little_endian_packets - struct A { } - test A { "aaa" } - "# - ); - - raises!( - InvalidTestIdentifier, - r#" - little_endian_packets - group A { x : 8 } - test A { "aaa" } - "# - ); - } - - #[test] - fn test_e11() { - raises!( - DuplicateFieldIdentifier, - r#" - little_endian_packets - enum A : 8 { X = 0 } - struct B { - x : 8, - x : A - } - "# - ); - - raises!( - DuplicateFieldIdentifier, - r#" - little_endian_packets - enum A : 8 { X = 0 } - packet B { - x : 8, - x : A[] - } - "# - ); - } - - #[test] - fn test_e12() { - raises!( - DuplicateTagIdentifier, - r#" - little_endian_packets - enum A : 8 { - X = 0, - X = 1, - } - "# - ); - - raises!( - DuplicateTagIdentifier, - r#" - little_endian_packets - enum A : 8 { - X = 0, - A = 1..10 { - X = 1, - } - } - "# - ); - - raises!( - DuplicateTagIdentifier, - r#" - little_endian_packets - enum A : 8 { - X = 0, - X = 1..10, - } - "# - ); - } - - #[test] - fn test_e13() { - raises!( - DuplicateTagValue, - r#" - little_endian_packets - enum A : 8 { - X = 0, - Y = 0, - } - "# - ); - - raises!( - DuplicateTagValue, - r#" - little_endian_packets - enum A : 8 { - A = 1..10 { - X = 1, - Y = 1, - } - } - "# - ); - } - - #[test] - fn test_e14() { - raises!( - InvalidTagValue, - r#" - little_endian_packets - enum A : 8 { - X = 256, - } - "# - ); - - raises!( - InvalidTagValue, - r#" - little_endian_packets - enum A : 8 { - A = 0, - X = 10..20 { - B = 1, - }, - } - "# - ); - } - - #[test] - fn test_e15() { - raises!( - UndeclaredConstraintIdentifier, - r#" - little_endian_packets - packet A { } - packet B : A (x = 1) { } - "# - ); - - raises!( - UndeclaredConstraintIdentifier, - r#" - little_endian_packets - group A { x : 8 } - packet B { - A { y = 1 } - } - "# - ); - } - - #[test] - fn test_e16() { - raises!( - InvalidConstraintIdentifier, - r#" - little_endian_packets - packet A { x : 8[] } - packet B : A (x = 1) { } - "# - ); - - raises!( - InvalidConstraintIdentifier, - r#" - little_endian_packets - group A { x : 8[] } - packet B { - A { x = 1 } - } - "# - ); - } - - #[test] - fn test_e17() { - raises!( - E17, - r#" - little_endian_packets - packet A { x : 8 } - packet B : A (x = X) { } - "# - ); - - raises!( - E17, - r#" - little_endian_packets - group A { x : 8 } - packet B { - A { x = X } - } - "# - ); - } - - #[test] - fn test_e18() { - raises!( - ConstraintValueOutOfRange, - r#" - little_endian_packets - packet A { x : 8 } - packet B : A (x = 256) { } - "# - ); - - raises!( - ConstraintValueOutOfRange, - r#" - little_endian_packets - group A { x : 8 } - packet B { - A { x = 256 } - } - "# - ); - } - - #[test] - fn test_e19() { - raises!( - E19, - r#" - little_endian_packets - enum C : 8 { X = 0 } - packet A { x : C } - packet B : A (x = 0) { } - "# - ); - - raises!( - E19, - r#" - little_endian_packets - enum C : 8 { X = 0 } - group A { x : C } - packet B { - A { x = 0 } - } - "# - ); - } - - #[test] - fn test_e20() { - raises!( - E20, - r#" - little_endian_packets - enum C : 8 { X = 0 } - packet A { x : C } - packet B : A (x = Y) { } - "# - ); - - raises!( - E20, - r#" - little_endian_packets - enum C : 8 { X = 0 } - group A { x : C } - packet B { - A { x = Y } - } - "# - ); - } - - #[test] - fn test_e21() { - raises!( - E21, - r#" - little_endian_packets - struct C { } - packet A { x : C } - packet B : A (x = 0) { } - "# - ); - - raises!( - E21, - r#" - little_endian_packets - struct C { } - group A { x : C } - packet B { - A { x = 0 } - } - "# - ); - } - - #[test] - fn test_e22() { - raises!( - DuplicateConstraintIdentifier, - r#" - little_endian_packets - packet A { x: 8 } - packet B : A (x = 0, x = 1) { } - "# - ); - - raises!( - DuplicateConstraintIdentifier, - r#" - little_endian_packets - packet A { x: 8 } - packet B : A (x = 0) { } - packet C : B (x = 1) { } - "# - ); - - raises!( - DuplicateConstraintIdentifier, - r#" - little_endian_packets - group A { x : 8 } - packet B { - A { x = 0, x = 1 } - } - "# - ); - } - - #[test] - fn test_e23() { - raises!( - DuplicateSizeField, - r#" - little_endian_packets - struct A { - _size_ (_payload_) : 8, - _size_ (_payload_) : 8, - _payload_, - } - "# - ); - - raises!( - DuplicateSizeField, - r#" - little_endian_packets - struct A { - _count_ (x) : 8, - _size_ (x) : 8, - x: 8[], - } - "# - ); - } - - #[test] - fn test_e24() { - raises!( - UndeclaredSizeIdentifier, - r#" - little_endian_packets - struct A { - _size_ (x) : 8, - } - "# - ); - - raises!( - UndeclaredSizeIdentifier, - r#" - little_endian_packets - struct A { - _size_ (_payload_) : 8, - } - "# - ); - } - - #[test] - fn test_e25() { - raises!( - InvalidSizeIdentifier, - r#" - little_endian_packets - enum B : 8 { X = 0 } - struct A { - _size_ (x) : 8, - x : B, - } - "# - ); - } - - #[test] - fn test_e26() { - raises!( - DuplicateCountField, - r#" - little_endian_packets - struct A { - _size_ (x) : 8, - _count_ (x) : 8, - x: 8[], - } - "# - ); - } - - #[test] - fn test_e27() { - raises!( - UndeclaredCountIdentifier, - r#" - little_endian_packets - struct A { - _count_ (x) : 8, - } - "# - ); - } - - #[test] - fn test_e28() { - raises!( - InvalidCountIdentifier, - r#" - little_endian_packets - enum B : 8 { X = 0 } - struct A { - _count_ (x) : 8, - x : B, - } - "# - ); - } - - #[test] - fn test_e29() { - raises!( - DuplicateElementSizeField, - r#" - little_endian_packets - struct A { - _elementsize_ (x) : 8, - _elementsize_ (x) : 8, - x: 8[], - } - "# - ); - } - - #[test] - fn test_e30() { - raises!( - UndeclaredElementSizeIdentifier, - r#" - little_endian_packets - struct A { - _elementsize_ (x) : 8, - } - "# - ); - } - - #[test] - fn test_e31() { - raises!( - InvalidElementSizeIdentifier, - r#" - little_endian_packets - enum B : 8 { X = 0 } - struct A { - _elementsize_ (x) : 8, - x : B, - } - "# - ); - } - - #[test] - fn test_e32() { - raises!( - FixedValueOutOfRange, - r#" - little_endian_packets - struct A { - _fixed_ = 256 : 8, - } - "# - ); - } - - #[test] - fn test_e33() { - raises!( - E33, - r#" - little_endian_packets - struct A { - _fixed_ = X : B, - } - "# - ); - } - - #[test] - fn test_e34() { - raises!( - E34, - r#" - little_endian_packets - enum B : 8 { X = 0 } - struct A { - _fixed_ = Y : B, - } - "# - ); - } - - #[test] - fn test_e35() { - raises!( - E35, - r#" - little_endian_packets - struct B { } - struct A { - _fixed_ = X : B, - } - "# - ); - } - - #[test] - fn test_e36() { - raises!( - DuplicatePayloadField, - r#" - little_endian_packets - packet A { - _payload_, - _body_, - } - "# - ); - - raises!( - DuplicatePayloadField, - r#" - little_endian_packets - packet A { - _body_, - _payload_, - } - "# - ); - } - - #[test] - fn test_e37() { - raises!( - MissingPayloadField, - r#" - little_endian_packets - packet A { x : 8 } - packet B : A { y : 8 } - "# - ); - - raises!( - MissingPayloadField, - r#" - little_endian_packets - packet A { x : 8 } - packet B : A (x = 0) { } - packet C : B { y : 8 } - "# - ); - } - - #[test] - fn test_e38() { - raises!( - RedundantArraySize, - r#" - little_endian_packets - packet A { - _size_ (x) : 8, - x : 8[8] - } - "# - ); - - raises!( - RedundantArraySize, - r#" - little_endian_packets - packet A { - _count_ (x) : 8, - x : 8[8] - } - "# - ); - } - - #[test] - fn test_e39() { - raises!( - InvalidPaddingField, - r#" - little_endian_packets - packet A { - _padding_ [16], - x : 8[] - } - "# - ); - - raises!( - InvalidPaddingField, - r#" - little_endian_packets - enum A : 8 { X = 0 } - packet B { - x : A, - _padding_ [16] - } - "# - ); - - valid!( - r#" - little_endian_packets - packet A { - x : 8[], - _padding_ [16] - } - "# - ); - } - - #[test] - fn test_e40() { - raises!( - InvalidTagRange, - r#" - little_endian_packets - enum A : 8 { - X = 4..2, - } - "# - ); - - raises!( - InvalidTagRange, - r#" - little_endian_packets - enum A : 8 { - X = 2..2, - } - "# - ); - - raises!( - InvalidTagRange, - r#" - little_endian_packets - enum A : 8 { - X = 258..259, - } - "# - ); - } - - #[test] - fn test_e41() { - raises!( - DuplicateTagRange, - r#" - little_endian_packets - enum A : 8 { - X = 0..15, - Y = 8..31, - } - "# - ); - - raises!( - DuplicateTagRange, - r#" - little_endian_packets - enum A : 8 { - X = 8..31, - Y = 0..15, - } - "# - ); - - raises!( - DuplicateTagRange, - r#" - little_endian_packets - enum A : 8 { - X = 1..9, - Y = 9..11, - } - "# - ); - } - - #[test] - fn test_e42() { - raises!( - E42, - r#" - little_endian_packets - enum C : 8 { X = 0..15 } - packet A { x : C } - packet B : A (x = X) { } - "# - ); - - raises!( - E42, - r#" - little_endian_packets - enum C : 8 { X = 0..15 } - group A { x : C } - packet B { - A { x = X } - } - "# - ); - } - - #[test] - fn test_e43() { - raises!( - E43, - r#" - little_endian_packets - enum A : 8 { - A = 0, - B = 1, - X = 1..15, - } - "# - ); - } - - #[test] - fn test_enum_declaration() { - valid!( - r#" - little_endian_packets - enum A : 7 { - X = 0, - Y = 1, - Z = 127, - } - "# - ); - - valid!( - r#" - little_endian_packets - enum A : 7 { - A = 50..100 { - X = 50, - Y = 100, - }, - Z = 101, - } - "# - ); - - valid!( - r#" - little_endian_packets - enum A : 7 { - A = 50..100, - X = 101, - } - "# - ); - } - - fn desugar(text: &str) -> analyzer::ast::File { - let mut db = SourceDatabase::new(); - let file = - parse_inline(&mut db, "stdin".to_owned(), text.to_owned()).expect("parsing failure"); - analyzer::analyze(&file).expect("analyzer failure") - } - - #[test] - fn test_inline_groups() { - assert_eq!( - desugar( - r#" - little_endian_packets - enum E : 8 { X=0, Y=1 } - group G { - a: 8, - b: E, - } - packet A { - G { } - } - "# - ), - desugar( - r#" - little_endian_packets - enum E : 8 { X=0, Y=1 } - packet A { - a: 8, - b: E, - } - "# - ) - ); - - assert_eq!( - desugar( - r#" - little_endian_packets - enum E : 8 { X=0, Y=1 } - group G { - a: 8, - b: E, - } - packet A { - G { a=1, b=X } - } - "# - ), - desugar( - r#" - little_endian_packets - enum E : 8 { X=0, Y=1 } - packet A { - _fixed_ = 1: 8, - _fixed_ = X: E, - } - "# - ) - ); - - assert_eq!( - desugar( - r#" - little_endian_packets - enum E : 8 { X=0, Y=1 } - group G1 { - a: 8, - } - group G2 { - G1 { a=1 }, - b: E, - } - packet A { - G2 { b=X } - } - "# - ), - desugar( - r#" - little_endian_packets - enum E : 8 { X=0, Y=1 } - packet A { - _fixed_ = 1: 8, - _fixed_ = X: E, - } - "# - ) - ); - } -} diff --git a/tools/pdl/src/ast.rs b/tools/pdl/src/ast.rs deleted file mode 100644 index da46c1338304b709b212bef864f18620021c231b..0000000000000000000000000000000000000000 --- a/tools/pdl/src/ast.rs +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use codespan_reporting::diagnostic; -use codespan_reporting::files; -use serde::Serialize; -use std::fmt; -use std::ops; - -/// File identfiier. -/// References a source file in the source database. -pub type FileId = usize; - -/// Source database. -/// Stores the source file contents for reference. -pub type SourceDatabase = files::SimpleFiles; - -#[derive(Debug, Default, Copy, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)] -pub struct SourceLocation { - /// Byte offset into the file (counted from zero). - pub offset: usize, - /// Line number (counted from zero). - pub line: usize, - /// Column number (counted from zero) - pub column: usize, -} - -#[derive(Default, Copy, Clone, PartialEq, Eq, Serialize)] -pub struct SourceRange { - pub file: FileId, - pub start: SourceLocation, - pub end: SourceLocation, -} - -pub trait Annotation: fmt::Debug + Serialize { - type FieldAnnotation: Default + fmt::Debug + Clone; - type DeclAnnotation: Default + fmt::Debug; -} - -#[derive(Debug, Serialize, Clone)] -#[serde(tag = "kind", rename = "comment")] -pub struct Comment { - pub loc: SourceRange, - pub text: String, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)] -#[serde(rename_all = "snake_case")] -pub enum EndiannessValue { - LittleEndian, - BigEndian, -} - -#[derive(Debug, Copy, Clone, Serialize)] -#[serde(tag = "kind", rename = "endianness_declaration")] -pub struct Endianness { - pub loc: SourceRange, - pub value: EndiannessValue, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(tag = "kind", rename = "tag")] -pub struct TagValue { - pub id: String, - pub loc: SourceRange, - pub value: usize, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(tag = "kind", rename = "tag")] -pub struct TagRange { - pub id: String, - pub loc: SourceRange, - pub range: std::ops::RangeInclusive, - pub tags: Vec, -} - -#[derive(Debug, Serialize, Clone, PartialEq, Eq)] -#[serde(untagged)] -pub enum Tag { - Value(TagValue), - Range(TagRange), -} - -#[derive(Debug, Serialize, Clone)] -#[serde(tag = "kind", rename = "constraint")] -pub struct Constraint { - pub id: String, - pub loc: SourceRange, - pub value: Option, - pub tag_id: Option, -} - -#[derive(Debug, Serialize, Clone, PartialEq, Eq)] -#[serde(tag = "kind")] -pub enum FieldDesc { - #[serde(rename = "checksum_field")] - Checksum { field_id: String }, - #[serde(rename = "padding_field")] - Padding { size: usize }, - #[serde(rename = "size_field")] - Size { field_id: String, width: usize }, - #[serde(rename = "count_field")] - Count { field_id: String, width: usize }, - #[serde(rename = "elementsize_field")] - ElementSize { field_id: String, width: usize }, - #[serde(rename = "body_field")] - Body, - #[serde(rename = "payload_field")] - Payload { size_modifier: Option }, - #[serde(rename = "fixed_field")] - FixedScalar { width: usize, value: usize }, - #[serde(rename = "fixed_field")] - FixedEnum { enum_id: String, tag_id: String }, - #[serde(rename = "reserved_field")] - Reserved { width: usize }, - #[serde(rename = "array_field")] - Array { - id: String, - width: Option, - type_id: Option, - size_modifier: Option, - size: Option, - }, - #[serde(rename = "scalar_field")] - Scalar { id: String, width: usize }, - #[serde(rename = "typedef_field")] - Typedef { id: String, type_id: String }, - #[serde(rename = "group_field")] - Group { group_id: String, constraints: Vec }, -} - -#[derive(Debug, Serialize, Clone)] -pub struct Field { - pub loc: SourceRange, - #[serde(skip_serializing)] - pub annot: A::FieldAnnotation, - #[serde(flatten)] - pub desc: FieldDesc, -} - -#[derive(Debug, Serialize, Clone)] -#[serde(tag = "kind", rename = "test_case")] -pub struct TestCase { - pub loc: SourceRange, - pub input: String, -} - -#[derive(Debug, Serialize, PartialEq, Eq)] -#[serde(tag = "kind")] -pub enum DeclDesc { - #[serde(rename = "checksum_declaration")] - Checksum { id: String, function: String, width: usize }, - #[serde(rename = "custom_field_declaration")] - CustomField { id: String, width: Option, function: String }, - #[serde(rename = "enum_declaration")] - Enum { id: String, tags: Vec, width: usize }, - #[serde(rename = "packet_declaration")] - Packet { - id: String, - constraints: Vec, - fields: Vec>, - parent_id: Option, - }, - #[serde(rename = "struct_declaration")] - Struct { - id: String, - constraints: Vec, - fields: Vec>, - parent_id: Option, - }, - #[serde(rename = "group_declaration")] - Group { id: String, fields: Vec> }, - #[serde(rename = "test_declaration")] - Test { type_id: String, test_cases: Vec }, -} - -#[derive(Debug, Serialize)] -pub struct Decl { - pub loc: SourceRange, - #[serde(skip_serializing)] - pub annot: A::DeclAnnotation, - #[serde(flatten)] - pub desc: DeclDesc, -} - -#[derive(Debug, Serialize)] -pub struct File { - pub version: String, - pub file: FileId, - pub comments: Vec, - pub endianness: Endianness, - pub declarations: Vec>, -} - -impl SourceLocation { - /// Construct a new source location. - /// - /// The `line_starts` indicates the byte offsets where new lines - /// start in the file. The first element should thus be `0` since - /// every file has at least one line starting at offset `0`. - pub fn new(offset: usize, line_starts: &[usize]) -> SourceLocation { - let mut loc = SourceLocation { offset, line: 0, column: offset }; - for (line, start) in line_starts.iter().enumerate() { - if *start > offset { - break; - } - loc = SourceLocation { offset, line, column: offset - start }; - } - loc - } -} - -impl SourceRange { - pub fn primary(&self) -> diagnostic::Label { - diagnostic::Label::primary(self.file, self.start.offset..self.end.offset) - } - pub fn secondary(&self) -> diagnostic::Label { - diagnostic::Label::secondary(self.file, self.start.offset..self.end.offset) - } -} - -impl fmt::Display for SourceRange { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.start.line == self.end.line { - write!(f, "{}:{}-{}", self.start.line, self.start.column, self.end.column) - } else { - write!( - f, - "{}:{}-{}:{}", - self.start.line, self.start.column, self.end.line, self.end.column - ) - } - } -} - -impl fmt::Debug for SourceRange { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceRange").finish_non_exhaustive() - } -} - -impl ops::Add for SourceRange { - type Output = SourceRange; - - fn add(self, rhs: SourceRange) -> SourceRange { - assert!(self.file == rhs.file); - SourceRange { - file: self.file, - start: self.start.min(rhs.start), - end: self.end.max(rhs.end), - } - } -} - -impl Eq for Endianness {} -impl PartialEq for Endianness { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out loc. - self.value == other.value - } -} - -impl Eq for TagValue {} -impl PartialEq for TagValue { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out loc. - self.id == other.id && self.value == other.value - } -} - -impl Eq for TagRange {} -impl PartialEq for TagRange { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out loc. - self.id == other.id && self.range == other.range && self.tags == other.tags - } -} - -impl Tag { - pub fn id(&self) -> &str { - match self { - Tag::Value(TagValue { id, .. }) | Tag::Range(TagRange { id, .. }) => id, - } - } - - pub fn loc(&self) -> &SourceRange { - match self { - Tag::Value(TagValue { loc, .. }) | Tag::Range(TagRange { loc, .. }) => loc, - } - } - - pub fn value(&self) -> Option { - match self { - Tag::Value(TagValue { value, .. }) => Some(*value), - Tag::Range(_) => None, - } - } -} - -impl Eq for Constraint {} -impl PartialEq for Constraint { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out loc. - self.id == other.id && self.value == other.value && self.tag_id == other.tag_id - } -} - -impl Eq for TestCase {} -impl PartialEq for TestCase { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out loc. - self.input == other.input - } -} - -impl Eq for File {} -impl PartialEq for File { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out comments and PDL - // version information. - self.endianness == other.endianness && self.declarations == other.declarations - } -} - -impl File { - pub fn new(file: FileId) -> File { - File { - version: "1,0".to_owned(), - comments: vec![], - // The endianness is mandatory, so this default value will - // be updated while parsing. - endianness: Endianness { - loc: SourceRange::default(), - value: EndiannessValue::LittleEndian, - }, - declarations: vec![], - file, - } - } - - /// Iterate over the children of the selected declaration. - /// /!\ This method is unsafe to use if the file contains cyclic - /// declarations, use with caution. - pub fn iter_children<'d>(&'d self, decl: &'d Decl) -> impl Iterator> { - self.declarations.iter().filter(|other_decl| other_decl.parent_id() == decl.id()) - } -} - -impl Eq for Decl {} -impl PartialEq for Decl { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out loc and annot. - self.desc == other.desc - } -} - -impl Decl { - pub fn new(loc: SourceRange, desc: DeclDesc) -> Decl { - Decl { loc, annot: Default::default(), desc } - } - - pub fn annotate( - &self, - annot: B::DeclAnnotation, - annotate_fields: F, - ) -> Decl - where - F: FnOnce(&[Field]) -> Vec>, - { - let desc = match &self.desc { - DeclDesc::Checksum { id, function, width } => { - DeclDesc::Checksum { id: id.clone(), function: function.clone(), width: *width } - } - DeclDesc::CustomField { id, width, function } => { - DeclDesc::CustomField { id: id.clone(), width: *width, function: function.clone() } - } - DeclDesc::Enum { id, tags, width } => { - DeclDesc::Enum { id: id.clone(), tags: tags.clone(), width: *width } - } - - DeclDesc::Test { type_id, test_cases } => { - DeclDesc::Test { type_id: type_id.clone(), test_cases: test_cases.clone() } - } - DeclDesc::Packet { id, constraints, parent_id, fields } => DeclDesc::Packet { - id: id.clone(), - constraints: constraints.clone(), - parent_id: parent_id.clone(), - fields: annotate_fields(fields), - }, - DeclDesc::Struct { id, constraints, parent_id, fields } => DeclDesc::Struct { - id: id.clone(), - constraints: constraints.clone(), - parent_id: parent_id.clone(), - fields: annotate_fields(fields), - }, - DeclDesc::Group { id, fields } => { - DeclDesc::Group { id: id.clone(), fields: annotate_fields(fields) } - } - }; - Decl { loc: self.loc, desc, annot } - } - - pub fn id(&self) -> Option<&str> { - match &self.desc { - DeclDesc::Test { .. } => None, - DeclDesc::Checksum { id, .. } - | DeclDesc::CustomField { id, .. } - | DeclDesc::Enum { id, .. } - | DeclDesc::Packet { id, .. } - | DeclDesc::Struct { id, .. } - | DeclDesc::Group { id, .. } => Some(id), - } - } - - pub fn parent_id(&self) -> Option<&str> { - match &self.desc { - DeclDesc::Packet { parent_id, .. } | DeclDesc::Struct { parent_id, .. } => { - parent_id.as_deref() - } - _ => None, - } - } - - pub fn constraints(&self) -> std::slice::Iter<'_, Constraint> { - match &self.desc { - DeclDesc::Packet { constraints, .. } | DeclDesc::Struct { constraints, .. } => { - constraints.iter() - } - _ => [].iter(), - } - } - - pub fn fields(&self) -> std::slice::Iter<'_, Field> { - match &self.desc { - DeclDesc::Packet { fields, .. } - | DeclDesc::Struct { fields, .. } - | DeclDesc::Group { fields, .. } => fields.iter(), - _ => [].iter(), - } - } - - pub fn kind(&self) -> &str { - match &self.desc { - DeclDesc::Checksum { .. } => "checksum", - DeclDesc::CustomField { .. } => "custom field", - DeclDesc::Enum { .. } => "enum", - DeclDesc::Packet { .. } => "packet", - DeclDesc::Struct { .. } => "struct", - DeclDesc::Group { .. } => "group", - DeclDesc::Test { .. } => "test", - } - } -} - -impl Eq for Field {} -impl PartialEq for Field { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out loc and annot. - self.desc == other.desc - } -} - -impl Field { - pub fn annotate(&self, annot: B::FieldAnnotation) -> Field { - Field { loc: self.loc, annot, desc: self.desc.clone() } - } - - pub fn id(&self) -> Option<&str> { - match &self.desc { - FieldDesc::Checksum { .. } - | FieldDesc::Padding { .. } - | FieldDesc::Size { .. } - | FieldDesc::Count { .. } - | FieldDesc::ElementSize { .. } - | FieldDesc::Body - | FieldDesc::Payload { .. } - | FieldDesc::FixedScalar { .. } - | FieldDesc::FixedEnum { .. } - | FieldDesc::Reserved { .. } - | FieldDesc::Group { .. } => None, - FieldDesc::Array { id, .. } - | FieldDesc::Scalar { id, .. } - | FieldDesc::Typedef { id, .. } => Some(id), - } - } - - pub fn kind(&self) -> &str { - match &self.desc { - FieldDesc::Checksum { .. } => "payload", - FieldDesc::Padding { .. } => "padding", - FieldDesc::Size { .. } => "size", - FieldDesc::Count { .. } => "count", - FieldDesc::ElementSize { .. } => "elementsize", - FieldDesc::Body { .. } => "body", - FieldDesc::Payload { .. } => "payload", - FieldDesc::FixedScalar { .. } | FieldDesc::FixedEnum { .. } => "fixed", - FieldDesc::Reserved { .. } => "reserved", - FieldDesc::Group { .. } => "group", - FieldDesc::Array { .. } => "array", - FieldDesc::Scalar { .. } => "scalar", - FieldDesc::Typedef { .. } => "typedef", - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn source_location_new() { - let line_starts = &[0, 20, 80, 120, 150]; - assert_eq!( - SourceLocation::new(0, line_starts), - SourceLocation { offset: 0, line: 0, column: 0 } - ); - assert_eq!( - SourceLocation::new(10, line_starts), - SourceLocation { offset: 10, line: 0, column: 10 } - ); - assert_eq!( - SourceLocation::new(50, line_starts), - SourceLocation { offset: 50, line: 1, column: 30 } - ); - assert_eq!( - SourceLocation::new(100, line_starts), - SourceLocation { offset: 100, line: 2, column: 20 } - ); - assert_eq!( - SourceLocation::new(1000, line_starts), - SourceLocation { offset: 1000, line: 4, column: 850 } - ); - } - - #[test] - fn source_location_new_no_crash_with_empty_line_starts() { - let loc = SourceLocation::new(100, &[]); - assert_eq!(loc, SourceLocation { offset: 100, line: 0, column: 100 }); - } -} diff --git a/tools/pdl/src/backends/intermediate.rs b/tools/pdl/src/backends/intermediate.rs deleted file mode 100644 index e0d1041170b92083834c07be754fefaab016735b..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/intermediate.rs +++ /dev/null @@ -1,537 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use std::collections::{hash_map::Entry, HashMap}; - -use crate::ast; -use crate::parser; - -pub struct Schema<'a> { - pub packets_and_structs: HashMap<&'a str, PacketOrStruct<'a>>, - pub enums: HashMap<&'a str, Enum<'a>>, -} - -pub struct PacketOrStruct<'a> { - pub computed_offsets: HashMap, ComputedOffset<'a>>, - pub computed_values: HashMap, ComputedValue<'a>>, - /// whether the parse of this packet needs to know its length, - /// or if the packet can determine its own length - pub length: PacketOrStructLength, -} - -pub enum PacketOrStructLength { - Static(usize), - Dynamic, - NeedsExternal, -} - -pub struct Enum<'a> { - pub tags: &'a [ast::Tag], - pub width: usize, -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum ComputedValueId<'a> { - // needed for array fields + varlength structs - note that this is in OCTETS, not BITS - // this always works since array entries are either structs (which are byte-aligned) or integer-octet-width scalars - FieldSize(&'a str), - - // needed for arrays with fixed element size (otherwise codegen will loop!) - FieldElementSize(&'a str), // note that this is in OCTETS, not BITS - FieldCount(&'a str), - - Custom(u16), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum ComputedOffsetId<'a> { - // these quantities are known by the runtime - HeaderStart, - - // if the packet needs its length, this will be supplied. otherwise it will be computed - PacketEnd, - - // these quantities will be computed and stored in computed_values - FieldOffset(&'a str), // needed for all fields, measured in BITS - FieldEndOffset(&'a str), // needed only for Payload + Body fields, as well as variable-size structs (not arrays), measured in BITS - Custom(u16), - TrailerStart, -} - -pub enum ComputedValue<'a> { - Constant(usize), - CountStructsUpToSize { - base_id: ComputedOffsetId<'a>, - size: ComputedValueId<'a>, - struct_type: &'a str, - }, - SizeOfNStructs { - base_id: ComputedOffsetId<'a>, - n: ComputedValueId<'a>, - struct_type: &'a str, - }, - Product(ComputedValueId<'a>, ComputedValueId<'a>), - Divide(ComputedValueId<'a>, ComputedValueId<'a>), - Difference(ComputedOffsetId<'a>, ComputedOffsetId<'a>), - ValueAt { - offset: ComputedOffsetId<'a>, - width: usize, - }, -} - -#[derive(Copy, Clone)] -pub enum ComputedOffset<'a> { - ConstantPlusOffsetInBits(ComputedOffsetId<'a>, i64), - SumWithOctets(ComputedOffsetId<'a>, ComputedValueId<'a>), - Alias(ComputedOffsetId<'a>), -} - -pub fn generate(file: &parser::ast::File) -> Result { - let mut schema = Schema { packets_and_structs: HashMap::new(), enums: HashMap::new() }; - match file.endianness.value { - ast::EndiannessValue::LittleEndian => {} - _ => unimplemented!("Only little_endian endianness supported"), - }; - - for decl in &file.declarations { - process_decl(&mut schema, decl); - } - - Ok(schema) -} - -fn process_decl<'a>(schema: &mut Schema<'a>, decl: &'a parser::ast::Decl) { - match &decl.desc { - ast::DeclDesc::Enum { id, tags, width, .. } => process_enum(schema, id, tags, *width), - ast::DeclDesc::Packet { id, fields, .. } | ast::DeclDesc::Struct { id, fields, .. } => { - process_packet_or_struct(schema, id, fields) - } - ast::DeclDesc::Group { .. } => todo!(), - _ => unimplemented!("type {decl:?} not supported"), - } -} - -fn process_enum<'a>(schema: &mut Schema<'a>, id: &'a str, tags: &'a [ast::Tag], width: usize) { - schema.enums.insert(id, Enum { tags, width }); - schema.packets_and_structs.insert( - id, - PacketOrStruct { - computed_offsets: HashMap::new(), - computed_values: HashMap::new(), - length: PacketOrStructLength::Static(width), - }, - ); -} - -fn process_packet_or_struct<'a>( - schema: &mut Schema<'a>, - id: &'a str, - fields: &'a [parser::ast::Field], -) { - schema.packets_and_structs.insert(id, compute_getters(schema, fields)); -} - -fn compute_getters<'a>( - schema: &Schema<'a>, - fields: &'a [parser::ast::Field], -) -> PacketOrStruct<'a> { - let mut prev_pos_id = None; - let mut curr_pos_id = ComputedOffsetId::HeaderStart; - let mut computed_values = HashMap::new(); - let mut computed_offsets = HashMap::new(); - - let mut cnt = 0; - - let one_id = ComputedValueId::Custom(cnt); - let one_val = ComputedValue::Constant(1); - cnt += 1; - computed_values.insert(one_id, one_val); - - let mut needs_length = false; - - for field in fields { - // populate this only if we are an array with a knowable size - let mut next_prev_pos_id = None; - - let next_pos = match &field.desc { - ast::FieldDesc::Reserved { width } => { - ComputedOffset::ConstantPlusOffsetInBits(curr_pos_id, *width as i64) - } - ast::FieldDesc::Scalar { id, width } => { - computed_offsets - .insert(ComputedOffsetId::FieldOffset(id), ComputedOffset::Alias(curr_pos_id)); - ComputedOffset::ConstantPlusOffsetInBits(curr_pos_id, *width as i64) - } - ast::FieldDesc::FixedScalar { width, .. } => { - let offset = *width; - ComputedOffset::ConstantPlusOffsetInBits(curr_pos_id, offset as i64) - } - ast::FieldDesc::FixedEnum { enum_id, .. } => { - let offset = schema.enums[enum_id.as_str()].width; - ComputedOffset::ConstantPlusOffsetInBits(curr_pos_id, offset as i64) - } - ast::FieldDesc::Size { field_id, width } => { - computed_values.insert( - ComputedValueId::FieldSize(field_id), - ComputedValue::ValueAt { offset: curr_pos_id, width: *width }, - ); - ComputedOffset::ConstantPlusOffsetInBits(curr_pos_id, *width as i64) - } - ast::FieldDesc::Count { field_id, width } => { - computed_values.insert( - ComputedValueId::FieldCount(field_id.as_str()), - ComputedValue::ValueAt { offset: curr_pos_id, width: *width }, - ); - ComputedOffset::ConstantPlusOffsetInBits(curr_pos_id, *width as i64) - } - ast::FieldDesc::ElementSize { field_id, width } => { - computed_values.insert( - ComputedValueId::FieldElementSize(field_id), - ComputedValue::ValueAt { offset: curr_pos_id, width: *width }, - ); - ComputedOffset::ConstantPlusOffsetInBits(curr_pos_id, *width as i64) - } - ast::FieldDesc::Group { .. } => { - unimplemented!("this should be removed by the linter...") - } - ast::FieldDesc::Checksum { .. } => unimplemented!("checksum not supported"), - ast::FieldDesc::Body => { - computed_offsets.insert( - ComputedOffsetId::FieldOffset("_body_"), - ComputedOffset::Alias(curr_pos_id), - ); - let computed_size_id = ComputedValueId::FieldSize("_body_"); - let end_offset = if computed_values.contains_key(&computed_size_id) { - ComputedOffset::SumWithOctets(curr_pos_id, computed_size_id) - } else { - if needs_length { - panic!("only one variable-length field can exist") - } - needs_length = true; - ComputedOffset::Alias(ComputedOffsetId::TrailerStart) - }; - computed_offsets.insert(ComputedOffsetId::FieldEndOffset("_body_"), end_offset); - end_offset - } - ast::FieldDesc::Payload { size_modifier } => { - if size_modifier.is_some() { - unimplemented!("size modifiers not supported") - } - computed_offsets.insert( - ComputedOffsetId::FieldOffset("_payload_"), - ComputedOffset::Alias(curr_pos_id), - ); - let computed_size_id = ComputedValueId::FieldSize("_payload_"); - let end_offset = if computed_values.contains_key(&computed_size_id) { - ComputedOffset::SumWithOctets(curr_pos_id, computed_size_id) - } else { - if needs_length { - panic!("only one variable-length field can exist") - } - needs_length = true; - ComputedOffset::Alias(ComputedOffsetId::TrailerStart) - }; - computed_offsets.insert(ComputedOffsetId::FieldEndOffset("_payload_"), end_offset); - end_offset - } - ast::FieldDesc::Array { - id, - width, - type_id, - size_modifier, - size: statically_known_count, - } => { - if size_modifier.is_some() { - unimplemented!("size modifiers not supported") - } - - computed_offsets - .insert(ComputedOffsetId::FieldOffset(id), ComputedOffset::Alias(curr_pos_id)); - - // there are a few parameters to consider when parsing arrays - // 1: the count of elements - // 2: the total byte size (possibly by subtracting out the len of the trailer) - // 3: whether the structs know their own lengths - // parsing is possible if we know (1 OR 2) AND 3 - - if let Some(count) = statically_known_count { - computed_values - .insert(ComputedValueId::FieldCount(id), ComputedValue::Constant(*count)); - } - - let statically_known_width_in_bits = if let Some(type_id) = type_id { - if let PacketOrStructLength::Static(len) = - schema.packets_and_structs[type_id.as_str()].length - { - Some(len) - } else { - None - } - } else if let Some(width) = width { - Some(*width) - } else { - unreachable!() - }; - - // whether the count is known *prior* to parsing the field - let is_count_known = computed_values.contains_key(&ComputedValueId::FieldCount(id)); - // whether the total field size is explicitly specified - let is_total_size_known = - computed_values.contains_key(&ComputedValueId::FieldSize(id)); - - let element_size = if let Some(type_id) = type_id { - match schema.packets_and_structs[type_id.as_str()].length { - PacketOrStructLength::Static(width) => { - assert!(width % 8 == 0); - Some(width / 8) - } - PacketOrStructLength::Dynamic => None, - PacketOrStructLength::NeedsExternal => None, - } - } else if let Some(width) = width { - assert!(width % 8 == 0); - Some(width / 8) - } else { - unreachable!() - }; - if let Some(element_size) = element_size { - computed_values.insert( - ComputedValueId::FieldElementSize(id), - ComputedValue::Constant(element_size), - ); - } - - // whether we can know the length of each element in the array by greedy parsing, - let structs_know_length = if let Some(type_id) = type_id { - match schema.packets_and_structs[type_id.as_str()].length { - PacketOrStructLength::Static(_) => true, - PacketOrStructLength::Dynamic => true, - PacketOrStructLength::NeedsExternal => { - computed_values.contains_key(&ComputedValueId::FieldElementSize(id)) - } - } - } else { - width.is_some() - }; - - if !structs_know_length { - panic!("structs need to know their own length, if they live in an array") - } - - let mut out = None; - if let Some(count) = statically_known_count { - if let Some(width) = statically_known_width_in_bits { - // the fast path, if the count and width are statically known, is to just immediately multiply - // otherwise this becomes a dynamic computation - assert!(width % 8 == 0); - computed_values.insert( - ComputedValueId::FieldSize(id), - ComputedValue::Constant(count * width / 8), - ); - out = Some(ComputedOffset::ConstantPlusOffsetInBits( - curr_pos_id, - (count * width) as i64, - )); - } - } - - // note: this introduces a forward dependency with the total_size_id - // however, the FieldSize(id) only depends on the FieldElementSize(id) if FieldCount() == true - // thus, there will never be an infinite loop, since the FieldElementSize(id) only depends on the - // FieldSize() if the FieldCount() is not unknown - if !is_count_known { - // the count is not known statically, or from earlier in the packet - // thus, we must compute it from the total size of the field, known either explicitly or implicitly via the trailer - // the fast path is to do a divide, but otherwise we need to loop over the TLVs - computed_values.insert( - ComputedValueId::FieldCount(id), - if computed_values.contains_key(&ComputedValueId::FieldElementSize(id)) { - ComputedValue::Divide( - ComputedValueId::FieldSize(id), - ComputedValueId::FieldElementSize(id), - ) - } else { - ComputedValue::CountStructsUpToSize { - base_id: curr_pos_id, - size: ComputedValueId::FieldSize(id), - struct_type: type_id.as_ref().unwrap(), - } - }, - ); - } - - if let Some(out) = out { - // we are paddable if the total size is known - next_prev_pos_id = Some(curr_pos_id); - out - } else if is_total_size_known { - // we are paddable if the total size is known - next_prev_pos_id = Some(curr_pos_id); - ComputedOffset::SumWithOctets(curr_pos_id, ComputedValueId::FieldSize(id)) - } else if is_count_known { - // we are paddable if the total count is known, since structs know their lengths - next_prev_pos_id = Some(curr_pos_id); - - computed_values.insert( - ComputedValueId::FieldSize(id), - if computed_values.contains_key(&ComputedValueId::FieldElementSize(id)) { - ComputedValue::Product( - ComputedValueId::FieldCount(id), - ComputedValueId::FieldElementSize(id), - ) - } else { - ComputedValue::SizeOfNStructs { - base_id: curr_pos_id, - n: ComputedValueId::FieldCount(id), - struct_type: type_id.as_ref().unwrap(), - } - }, - ); - ComputedOffset::SumWithOctets(curr_pos_id, ComputedValueId::FieldSize(id)) - } else { - // we can try to infer the total size if we are still in the header - // however, we are not paddable in this case - next_prev_pos_id = None; - - if needs_length { - panic!("either the total size, or the count of elements in an array, must be known") - } - // now we are in the trailer - computed_values.insert( - ComputedValueId::FieldSize(id), - ComputedValue::Difference(ComputedOffsetId::TrailerStart, curr_pos_id), - ); - needs_length = true; - ComputedOffset::Alias(ComputedOffsetId::TrailerStart) - } - } - ast::FieldDesc::Padding { size } => { - if let Some(prev_pos_id) = prev_pos_id { - ComputedOffset::ConstantPlusOffsetInBits(prev_pos_id, *size as i64) - } else { - panic!("padding must follow array field with known total size") - } - } - ast::FieldDesc::Typedef { id, type_id } => { - computed_offsets - .insert(ComputedOffsetId::FieldOffset(id), ComputedOffset::Alias(curr_pos_id)); - - match schema.packets_and_structs[type_id.as_str()].length { - PacketOrStructLength::Static(len) => { - ComputedOffset::ConstantPlusOffsetInBits(curr_pos_id, len as i64) - } - PacketOrStructLength::Dynamic => { - computed_values.insert( - ComputedValueId::FieldSize(id), - ComputedValue::SizeOfNStructs { - base_id: curr_pos_id, - n: one_id, - struct_type: type_id, - }, - ); - ComputedOffset::SumWithOctets(curr_pos_id, ComputedValueId::FieldSize(id)) - } - PacketOrStructLength::NeedsExternal => { - let end_offset = if let Entry::Vacant(entry) = - computed_values.entry(ComputedValueId::FieldSize(id)) - { - // its size is presently unknown - if needs_length { - panic!( - "cannot have multiple variable-length fields in a single packet/struct" - ) - } - // we are now in the trailer - entry.insert(ComputedValue::Difference( - ComputedOffsetId::TrailerStart, - curr_pos_id, - )); - needs_length = true; - ComputedOffset::Alias(ComputedOffsetId::TrailerStart) - } else { - ComputedOffset::SumWithOctets( - curr_pos_id, - ComputedValueId::FieldSize(id), - ) - }; - computed_offsets.insert(ComputedOffsetId::FieldEndOffset(id), end_offset); - end_offset - } - } - - // it is possible to size a struct in this variant of PDL, even though the linter doesn't allow it - } - }; - - prev_pos_id = next_prev_pos_id; - curr_pos_id = ComputedOffsetId::Custom(cnt); - cnt += 1; - computed_offsets.insert(curr_pos_id, next_pos); - } - - // TODO(aryarahul): simplify compute graph to improve trailer resolution? - - // we are now at the end of the packet - let length = if needs_length { - // if we needed the length, use the PacketEnd and length to reconstruct the TrailerStart - let trailer_length = - compute_length_to_goal(&computed_offsets, curr_pos_id, ComputedOffsetId::TrailerStart) - .expect("trailers should have deterministic length"); - computed_offsets.insert( - ComputedOffsetId::TrailerStart, - ComputedOffset::ConstantPlusOffsetInBits(ComputedOffsetId::PacketEnd, -trailer_length), - ); - PacketOrStructLength::NeedsExternal - } else { - // otherwise, try to reconstruct the full length, if possible - let full_length = - compute_length_to_goal(&computed_offsets, curr_pos_id, ComputedOffsetId::HeaderStart); - if let Some(full_length) = full_length { - computed_offsets.insert( - ComputedOffsetId::PacketEnd, - ComputedOffset::ConstantPlusOffsetInBits( - ComputedOffsetId::HeaderStart, - full_length, - ), - ); - PacketOrStructLength::Static(full_length as usize) - } else { - computed_offsets - .insert(ComputedOffsetId::PacketEnd, ComputedOffset::Alias(curr_pos_id)); - PacketOrStructLength::Dynamic - } - }; - - PacketOrStruct { computed_values, computed_offsets, length } -} - -fn compute_length_to_goal( - computed_offsets: &HashMap, - start: ComputedOffsetId, - goal: ComputedOffsetId, -) -> Option { - let mut out = 0; - let mut pos = start; - while pos != goal { - match computed_offsets.get(&pos).ok_or_else(|| format!("key {pos:?} not found")).unwrap() { - ComputedOffset::ConstantPlusOffsetInBits(base_id, offset) => { - out += offset; - pos = *base_id; - } - ComputedOffset::Alias(alias) => pos = *alias, - ComputedOffset::SumWithOctets { .. } => return None, - } - } - Some(out) -} diff --git a/tools/pdl/src/backends/rust.rs b/tools/pdl/src/backends/rust.rs deleted file mode 100644 index e14efbd7d3ce7c51d14fad00d843b8879535a117..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust.rs +++ /dev/null @@ -1,1434 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -//! Rust compiler backend. - -use crate::{ast, lint}; -use quote::{format_ident, quote}; -use std::collections::BTreeSet; -use std::path::Path; -use syn::LitInt; - -use crate::analyzer::ast as analyzer_ast; - -mod parser; -mod preamble; -mod serializer; -mod types; - -use parser::FieldParser; -use serializer::FieldSerializer; - -#[cfg(not(tm_mainline_prod))] -pub use heck::ToUpperCamelCase; - -#[cfg(tm_mainline_prod)] -pub trait ToUpperCamelCase { - fn to_upper_camel_case(&self) -> String; -} - -#[cfg(tm_mainline_prod)] -impl ToUpperCamelCase for str { - fn to_upper_camel_case(&self) -> String { - use heck::CamelCase; - let camel_case = self.to_camel_case(); - if camel_case.is_empty() { - camel_case - } else { - // PDL identifiers are a-zA-z0-9, so we're dealing with - // simple ASCII text. - format!("{}{}", &camel_case[..1].to_ascii_uppercase(), &camel_case[1..]) - } - } -} - -/// Generate a block of code. -/// -/// Like `quote!`, but the code block will be followed by an empty -/// line of code. This makes the generated code more readable. -#[macro_export] -macro_rules! quote_block { - ($($tt:tt)*) => { - format!("{}\n\n", ::quote::quote!($($tt)*)) - } -} - -/// Generate a bit-mask which masks out `n` least significant bits. -/// -/// Literal integers in Rust default to the `i32` type. For this -/// reason, if `n` is larger than 31, a suffix is added to the -/// `LitInt` returned. This should either be `u64` or `usize` -/// depending on where the result is used. -pub fn mask_bits(n: usize, suffix: &str) -> syn::LitInt { - let suffix = if n > 31 { format!("_{suffix}") } else { String::new() }; - // Format the hex digits as 0x1111_2222_3333_usize. - let hex_digits = format!("{:x}", (1u64 << n) - 1) - .as_bytes() - .rchunks(4) - .rev() - .map(|chunk| std::str::from_utf8(chunk).unwrap()) - .collect::>() - .join("_"); - syn::parse_str::(&format!("0x{hex_digits}{suffix}")).unwrap() -} - -fn generate_packet_size_getter<'a>( - scope: &lint::Scope<'a>, - fields: impl Iterator, - is_packet: bool, -) -> (usize, proc_macro2::TokenStream) { - let mut constant_width = 0; - let mut dynamic_widths = Vec::new(); - - for field in fields { - if let Some(width) = scope.get_field_width(field, false) { - constant_width += width; - continue; - } - - let decl = scope.get_field_declaration(field); - dynamic_widths.push(match &field.desc { - ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. } => { - if is_packet { - quote! { - self.child.get_total_size() - } - } else { - quote! { - self.payload.len() - } - } - } - ast::FieldDesc::Typedef { id, .. } => { - let id = format_ident!("{id}"); - quote!(self.#id.get_size()) - } - ast::FieldDesc::Array { id, width, .. } => { - let id = format_ident!("{id}"); - match &decl { - Some(analyzer_ast::Decl { - desc: ast::DeclDesc::Struct { .. } | ast::DeclDesc::CustomField { .. }, - .. - }) => { - quote! { - self.#id.iter().map(|elem| elem.get_size()).sum::() - } - } - Some(analyzer_ast::Decl { desc: ast::DeclDesc::Enum { .. }, .. }) => { - let width = syn::Index::from( - scope.get_decl_width(decl.unwrap(), false).unwrap() / 8, - ); - let mul_width = (width.index > 1).then(|| quote!(* #width)); - quote! { - self.#id.len() #mul_width - } - } - _ => { - let width = syn::Index::from(width.unwrap() / 8); - let mul_width = (width.index > 1).then(|| quote!(* #width)); - quote! { - self.#id.len() #mul_width - } - } - } - } - _ => panic!("Unsupported field type: {field:?}"), - }); - } - - if constant_width > 0 { - let width = syn::Index::from(constant_width / 8); - dynamic_widths.insert(0, quote!(#width)); - } - if dynamic_widths.is_empty() { - dynamic_widths.push(quote!(0)) - } - - ( - constant_width, - quote! { - #(#dynamic_widths)+* - }, - ) -} - -fn top_level_packet<'a>(scope: &lint::Scope<'a>, packet_name: &'a str) -> &'a analyzer_ast::Decl { - let mut decl = scope.typedef[packet_name]; - while let ast::DeclDesc::Packet { parent_id: Some(parent_id), .. } - | ast::DeclDesc::Struct { parent_id: Some(parent_id), .. } = &decl.desc - { - decl = scope.typedef[parent_id]; - } - decl -} - -/// Find all constrained fields in children of `id`. -fn find_constrained_fields<'a>( - scope: &'a lint::Scope<'a>, - id: &'a str, -) -> Vec<&'a analyzer_ast::Field> { - let mut fields = Vec::new(); - let mut field_names = BTreeSet::new(); - let mut children = scope.iter_children(id).collect::>(); - - while let Some(child) = children.pop() { - if let ast::DeclDesc::Packet { id, constraints, .. } - | ast::DeclDesc::Struct { id, constraints, .. } = &child.desc - { - let packet_scope = &scope.scopes[&scope.typedef[id]]; - for constraint in constraints { - if field_names.insert(&constraint.id) { - fields.push(packet_scope.all_fields[&constraint.id]); - } - } - children.extend(scope.iter_children(id).collect::>()); - } - } - - fields -} - -/// Find parent fields which are constrained in child packets. -/// -/// These fields are the fields which need to be passed in when -/// parsing a `id` packet since their values are needed for one or -/// more child packets. -fn find_constrained_parent_fields<'a>( - scope: &'a lint::Scope<'a>, - id: &'a str, -) -> impl Iterator { - let packet_scope = &scope.scopes[&scope.typedef[id]]; - find_constrained_fields(scope, id).into_iter().filter(|field| { - let id = field.id().unwrap(); - packet_scope.all_fields.contains_key(id) && packet_scope.get_packet_field(id).is_none() - }) -} - -/// Generate the declaration and implementation for a data struct. -/// -/// This struct will hold the data for a packet or a struct. It knows -/// how to parse and serialize its own fields. -fn generate_data_struct( - scope: &lint::Scope<'_>, - endianness: ast::EndiannessValue, - id: &str, -) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { - let decl = scope.typedef[id]; - let packet_scope = &scope.scopes[&decl]; - let is_packet = matches!(&decl.desc, ast::DeclDesc::Packet { .. }); - - let span = format_ident!("bytes"); - let serializer_span = format_ident!("buffer"); - let mut field_parser = FieldParser::new(scope, endianness, id, &span); - let mut field_serializer = FieldSerializer::new(scope, endianness, id, &serializer_span); - for field in packet_scope.iter_fields() { - field_parser.add(field); - field_serializer.add(field); - } - field_parser.done(); - - let (parse_arg_names, parse_arg_types) = if is_packet { - let fields = find_constrained_parent_fields(scope, id).collect::>(); - let names = fields.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::>(); - let types = fields.iter().map(|f| types::rust_type(f)).collect::>(); - (names, types) - } else { - (Vec::new(), Vec::new()) // No extra arguments to parse in structs. - }; - - let (constant_width, packet_size) = - generate_packet_size_getter(scope, packet_scope.iter_fields(), is_packet); - let conforms = if constant_width == 0 { - quote! { true } - } else { - let constant_width = syn::Index::from(constant_width / 8); - quote! { #span.len() >= #constant_width } - }; - - let visibility = if is_packet { quote!() } else { quote!(pub) }; - let has_payload = packet_scope.get_payload_field().is_some(); - let has_children = scope.iter_children(id).next().is_some(); - - let struct_name = if is_packet { format_ident!("{id}Data") } else { format_ident!("{id}") }; - let fields_with_ids = - packet_scope.iter_fields().filter(|f| f.id().is_some()).collect::>(); - let mut field_names = - fields_with_ids.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::>(); - let mut field_types = fields_with_ids.iter().map(|f| types::rust_type(f)).collect::>(); - if has_children || has_payload { - if is_packet { - field_names.push(format_ident!("child")); - let field_type = format_ident!("{id}DataChild"); - field_types.push(quote!(#field_type)); - } else { - field_names.push(format_ident!("payload")); - field_types.push(quote!(Vec)); - } - } - - let data_struct_decl = quote! { - #[derive(Debug, Clone, PartialEq, Eq)] - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - pub struct #struct_name { - #(#visibility #field_names: #field_types,)* - } - }; - - let data_struct_impl = quote! { - impl #struct_name { - fn conforms(#span: &[u8]) -> bool { - #conforms - } - - #visibility fn parse( - #span: &[u8] #(, #parse_arg_names: #parse_arg_types)* - ) -> Result { - let mut cell = Cell::new(#span); - let packet = Self::parse_inner(&mut cell #(, #parse_arg_names)*)?; - // TODO(mgeisler): communicate back to user if !cell.get().is_empty()? - Ok(packet) - } - - fn parse_inner( - mut #span: &mut Cell<&[u8]> #(, #parse_arg_names: #parse_arg_types)* - ) -> Result { - #field_parser - Ok(Self { - #(#field_names,)* - }) - } - - fn write_to(&self, buffer: &mut BytesMut) { - #field_serializer - } - - fn get_total_size(&self) -> usize { - self.get_size() - } - - fn get_size(&self) -> usize { - #packet_size - } - } - }; - - (data_struct_decl, data_struct_impl) -} - -/// Find all parents from `id`. -/// -/// This includes the `Decl` for `id` itself. -fn find_parents<'a>(scope: &lint::Scope<'a>, id: &str) -> Vec<&'a analyzer_ast::Decl> { - let mut decl = scope.typedef[id]; - let mut parents = vec![decl]; - while let ast::DeclDesc::Packet { parent_id: Some(parent_id), .. } - | ast::DeclDesc::Struct { parent_id: Some(parent_id), .. } = &decl.desc - { - decl = scope.typedef[parent_id]; - parents.push(decl); - } - parents.reverse(); - parents -} - -/// Turn the constraint into a value (such as `10` or -/// `SomeEnum::Foo`). -pub fn constraint_to_value( - packet_scope: &lint::PacketScope<'_>, - constraint: &ast::Constraint, -) -> proc_macro2::TokenStream { - match constraint { - ast::Constraint { value: Some(value), .. } => { - let value = proc_macro2::Literal::usize_unsuffixed(*value); - quote!(#value) - } - // TODO(mgeisler): include type_id in `ast::Constraint` and - // drop the packet_scope argument. - ast::Constraint { tag_id: Some(tag_id), .. } => { - let type_id = match &packet_scope.all_fields[&constraint.id].desc { - ast::FieldDesc::Typedef { type_id, .. } => format_ident!("{type_id}"), - _ => unreachable!("Invalid constraint: {constraint:?}"), - }; - let tag_id = format_ident!("{}", tag_id.to_upper_camel_case()); - quote!(#type_id::#tag_id) - } - _ => unreachable!("Invalid constraint: {constraint:?}"), - } -} - -/// Generate code for a `ast::Decl::Packet`. -fn generate_packet_decl( - scope: &lint::Scope<'_>, - endianness: ast::EndiannessValue, - id: &str, -) -> proc_macro2::TokenStream { - let packet_scope = &scope.scopes[&scope.typedef[id]]; - - let top_level = top_level_packet(scope, id); - let top_level_id = top_level.id().unwrap(); - let top_level_packet = format_ident!("{top_level_id}"); - let top_level_data = format_ident!("{top_level_id}Data"); - let top_level_id_lower = format_ident!("{}", top_level_id.to_lowercase()); - - // TODO(mgeisler): use the convert_case crate to convert between - // `FooBar` and `foo_bar` in the code below. - let span = format_ident!("bytes"); - let id_lower = format_ident!("{}", id.to_lowercase()); - let id_packet = format_ident!("{id}"); - let id_child = format_ident!("{id}Child"); - let id_data_child = format_ident!("{id}DataChild"); - let id_builder = format_ident!("{id}Builder"); - - let parents = find_parents(scope, id); - let parent_ids = parents.iter().map(|p| p.id().unwrap()).collect::>(); - let parent_shifted_ids = parent_ids.iter().skip(1).map(|id| format_ident!("{id}")); - let parent_lower_ids = - parent_ids.iter().map(|id| format_ident!("{}", id.to_lowercase())).collect::>(); - let parent_shifted_lower_ids = parent_lower_ids.iter().skip(1).collect::>(); - let parent_packet = parent_ids.iter().map(|id| format_ident!("{id}")); - let parent_data = parent_ids.iter().map(|id| format_ident!("{id}Data")); - let parent_data_child = parent_ids.iter().map(|id| format_ident!("{id}DataChild")); - - let all_fields = { - let mut fields = packet_scope.all_fields.values().collect::>(); - fields.sort_by_key(|f| f.id()); - fields - }; - let all_field_names = - all_fields.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::>(); - let all_field_types = all_fields.iter().map(|f| types::rust_type(f)).collect::>(); - let all_field_borrows = - all_fields.iter().map(|f| types::rust_borrow(f, scope)).collect::>(); - let all_field_getter_names = all_field_names.iter().map(|id| format_ident!("get_{id}")); - let all_field_self_field = all_fields.iter().map(|f| { - for (parent, parent_id) in parents.iter().zip(parent_lower_ids.iter()) { - if scope.scopes[parent].iter_fields().any(|ff| ff.id() == f.id()) { - return quote!(self.#parent_id); - } - } - unreachable!("Could not find {f:?} in parent chain"); - }); - - let unconstrained_fields = all_fields - .iter() - .filter(|f| !packet_scope.all_constraints.contains_key(f.id().unwrap())) - .collect::>(); - let unconstrained_field_names = unconstrained_fields - .iter() - .map(|f| format_ident!("{}", f.id().unwrap())) - .collect::>(); - let unconstrained_field_types = unconstrained_fields.iter().map(|f| types::rust_type(f)); - - let rev_parents = parents.iter().rev().collect::>(); - let builder_assignments = rev_parents.iter().enumerate().map(|(idx, parent)| { - let parent_id = parent.id().unwrap(); - let parent_id_lower = format_ident!("{}", parent_id.to_lowercase()); - let parent_data = format_ident!("{parent_id}Data"); - let parent_data_child = format_ident!("{parent_id}DataChild"); - let parent_packet_scope = &scope.scopes[&scope.typedef[parent_id]]; - - let named_fields = { - let mut names = - parent_packet_scope.iter_fields().filter_map(ast::Field::id).collect::>(); - names.sort_unstable(); - names - }; - - let mut field = named_fields.iter().map(|id| format_ident!("{id}")).collect::>(); - let mut value = named_fields - .iter() - .map(|&id| match packet_scope.all_constraints.get(id) { - Some(constraint) => constraint_to_value(packet_scope, constraint), - None => { - let id = format_ident!("{id}"); - quote!(self.#id) - } - }) - .collect::>(); - - if parent_packet_scope.get_payload_field().is_some() { - field.push(format_ident!("child")); - if idx == 0 { - // Top-most parent, the child is simply created from - // our payload. - value.push(quote! { - match self.payload { - None => #parent_data_child::None, - Some(bytes) => #parent_data_child::Payload(bytes), - } - }); - } else { - // Child is created from the previous parent. - let prev_parent_id = rev_parents[idx - 1].id().unwrap(); - let prev_parent_id_lower = format_ident!("{}", prev_parent_id.to_lowercase()); - let prev_parent_id = format_ident!("{prev_parent_id}"); - value.push(quote! { - #parent_data_child::#prev_parent_id(#prev_parent_id_lower) - }); - } - } - - quote! { - let #parent_id_lower = Arc::new(#parent_data { - #(#field: #value,)* - }); - } - }); - - let children = scope.iter_children(id).collect::>(); - let has_payload = packet_scope.get_payload_field().is_some(); - let has_children_or_payload = !children.is_empty() || has_payload; - let child = - children.iter().map(|child| format_ident!("{}", child.id().unwrap())).collect::>(); - let child_data = child.iter().map(|child| format_ident!("{child}Data")).collect::>(); - let get_payload = (children.is_empty() && has_payload).then(|| { - quote! { - pub fn get_payload(&self) -> &[u8] { - match &self.#id_lower.child { - #id_data_child::Payload(bytes) => &bytes, - #id_data_child::None => &[], - } - } - } - }); - let child_declaration = has_children_or_payload.then(|| { - quote! { - #[derive(Debug, Clone, PartialEq, Eq)] - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - pub enum #id_data_child { - #(#child(Arc<#child_data>),)* - Payload(Bytes), - None, - } - - impl #id_data_child { - fn get_total_size(&self) -> usize { - match self { - #(#id_data_child::#child(value) => value.get_total_size(),)* - #id_data_child::Payload(bytes) => bytes.len(), - #id_data_child::None => 0, - } - } - } - - #[derive(Debug, Clone, PartialEq, Eq)] - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - pub enum #id_child { - #(#child(#child),)* - Payload(Bytes), - None, - } - } - }); - let specialize = has_children_or_payload.then(|| { - quote! { - pub fn specialize(&self) -> #id_child { - match &self.#id_lower.child { - #( - #id_data_child::#child(_) => - #id_child::#child(#child::new(self.#top_level_id_lower.clone()).unwrap()), - )* - #id_data_child::Payload(payload) => #id_child::Payload(payload.clone()), - #id_data_child::None => #id_child::None, - } - } - } - }); - - let builder_payload_field = has_children_or_payload.then(|| { - quote! { - pub payload: Option - } - }); - - let ancestor_packets = - parent_ids[..parent_ids.len() - 1].iter().map(|id| format_ident!("{id}")); - let impl_from_and_try_from = (top_level_id != id).then(|| { - quote! { - #( - impl From<#id_packet> for #ancestor_packets { - fn from(packet: #id_packet) -> #ancestor_packets { - #ancestor_packets::new(packet.#top_level_id_lower).unwrap() - } - } - )* - - impl TryFrom<#top_level_packet> for #id_packet { - type Error = Error; - fn try_from(packet: #top_level_packet) -> Result<#id_packet> { - #id_packet::new(packet.#top_level_id_lower) - } - } - } - }); - - let (data_struct_decl, data_struct_impl) = generate_data_struct(scope, endianness, id); - - quote! { - #child_declaration - - #data_struct_decl - - #[derive(Debug, Clone, PartialEq, Eq)] - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - pub struct #id_packet { - #( - #[cfg_attr(feature = "serde", serde(flatten))] - #parent_lower_ids: Arc<#parent_data>, - )* - } - - #[derive(Debug)] - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - pub struct #id_builder { - #(pub #unconstrained_field_names: #unconstrained_field_types,)* - #builder_payload_field - } - - #data_struct_impl - - impl Packet for #id_packet { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.#top_level_id_lower.get_size()); - self.#top_level_id_lower.write_to(&mut buffer); - buffer.freeze() - } - - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } - } - - impl From<#id_packet> for Bytes { - fn from(packet: #id_packet) -> Self { - packet.to_bytes() - } - } - - impl From<#id_packet> for Vec { - fn from(packet: #id_packet) -> Self { - packet.to_vec() - } - } - - #impl_from_and_try_from - - impl #id_packet { - pub fn parse(#span: &[u8]) -> Result { - let mut cell = Cell::new(#span); - let packet = Self::parse_inner(&mut cell)?; - // TODO(mgeisler): communicate back to user if !cell.get().is_empty()? - Ok(packet) - } - - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = #top_level_data::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - - #specialize - - fn new(#top_level_id_lower: Arc<#top_level_data>) -> Result { - #( - let #parent_shifted_lower_ids = match &#parent_lower_ids.child { - #parent_data_child::#parent_shifted_ids(value) => value.clone(), - _ => return Err(Error::InvalidChildError { - expected: stringify!(#parent_data_child::#parent_shifted_ids), - actual: format!("{:?}", &#parent_lower_ids.child), - }), - }; - )* - Ok(Self { #(#parent_lower_ids),* }) - } - - #(pub fn #all_field_getter_names(&self) -> #all_field_borrows #all_field_types { - #all_field_borrows #all_field_self_field.as_ref().#all_field_names - })* - - #get_payload - - fn write_to(&self, buffer: &mut BytesMut) { - self.#id_lower.write_to(buffer) - } - - pub fn get_size(&self) -> usize { - self.#top_level_id_lower.get_size() - } - } - - impl #id_builder { - pub fn build(self) -> #id_packet { - #(#builder_assignments;)* - #id_packet::new(#top_level_id_lower).unwrap() - } - } - - #( - impl From<#id_builder> for #parent_packet { - fn from(builder: #id_builder) -> #parent_packet { - builder.build().into() - } - } - )* - } -} - -/// Generate code for a `ast::Decl::Struct`. -fn generate_struct_decl( - scope: &lint::Scope<'_>, - endianness: ast::EndiannessValue, - id: &str, -) -> proc_macro2::TokenStream { - let (struct_decl, struct_impl) = generate_data_struct(scope, endianness, id); - quote! { - #struct_decl - #struct_impl - } -} - -/// Generate an enum declaration. -/// -/// # Arguments -/// * `id` - Enum identifier. -/// * `tags` - List of enum tags. -/// * `width` - Width of the backing type of the enum, in bits. -/// * `open` - Whether to generate an open or closed enum. Open enums have -/// an additional Unknown case for unmatched valued. Complete -/// enums (where the full range of values is covered) are -/// automatically closed. -fn generate_enum_decl( - id: &str, - tags: &[ast::Tag], - width: usize, - open: bool, -) -> proc_macro2::TokenStream { - // Determine if the enum is complete, i.e. all values in the backing - // integer range have a matching tag in the original declaration. - fn enum_is_complete(tags: &[ast::Tag], max: usize) -> bool { - let mut ranges = tags - .iter() - .map(|tag| match tag { - ast::Tag::Value(tag) => (tag.value, tag.value), - ast::Tag::Range(tag) => tag.range.clone().into_inner(), - }) - .collect::>(); - ranges.sort_unstable(); - ranges.first().unwrap().0 == 0 - && ranges.last().unwrap().1 == max - && ranges.windows(2).all(|window| { - if let [left, right] = window { - left.1 == right.0 - 1 - } else { - false - } - }) - } - - // Determine if the enum is primitive, i.e. does not contain any - // tag range. - fn enum_is_primitive(tags: &[ast::Tag]) -> bool { - tags.iter().all(|tag| matches!(tag, ast::Tag::Value(_))) - } - - // Return the maximum value for the scalar type. - fn scalar_max(width: usize) -> usize { - if width >= usize::BITS as usize { - usize::MAX - } else { - (1 << width) - 1 - } - } - - // Format an enum tag identifier to rust upper caml case. - fn format_tag_ident(id: &str) -> proc_macro2::TokenStream { - let id = format_ident!("{}", id.to_upper_camel_case()); - quote! { #id } - } - - // Format a constant value as hexadecimal constant. - fn format_value(value: usize) -> LitInt { - syn::parse_str::(&format!("{:#x}", value)).unwrap() - } - - // Backing type for the enum. - let backing_type = types::Integer::new(width); - let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width)); - let range_max = scalar_max(width); - let is_complete = enum_is_complete(tags, scalar_max(width)); - let is_primitive = enum_is_primitive(tags); - let name = format_ident!("{id}"); - - // Generate the variant cases for the enum declaration. - // Tags declared in ranges are flattened in the same declaration. - let use_variant_values = is_primitive && (is_complete || !open); - let repr_u64 = use_variant_values.then(|| quote! { #[repr(u64)] }); - let mut variants = vec![]; - for tag in tags.iter() { - match tag { - ast::Tag::Value(tag) if use_variant_values => { - let id = format_tag_ident(&tag.id); - let value = format_value(tag.value); - variants.push(quote! { #id = #value }) - } - ast::Tag::Value(tag) => variants.push(format_tag_ident(&tag.id)), - ast::Tag::Range(tag) => { - variants.extend(tag.tags.iter().map(|tag| format_tag_ident(&tag.id))); - let id = format_tag_ident(&tag.id); - variants.push(quote! { #id(Private<#backing_type>) }) - } - } - } - - // Generate the cases for parsing the enum value from an integer. - let mut from_cases = vec![]; - for tag in tags.iter() { - match tag { - ast::Tag::Value(tag) => { - let id = format_tag_ident(&tag.id); - let value = format_value(tag.value); - from_cases.push(quote! { #value => Ok(#name::#id) }) - } - ast::Tag::Range(tag) => { - from_cases.extend(tag.tags.iter().map(|tag| { - let id = format_tag_ident(&tag.id); - let value = format_value(tag.value); - quote! { #value => Ok(#name::#id) } - })); - let id = format_tag_ident(&tag.id); - let start = format_value(*tag.range.start()); - let end = format_value(*tag.range.end()); - from_cases.push(quote! { #start ..= #end => Ok(#name::#id(Private(value))) }) - } - } - } - - // Generate the cases for serializing the enum value to an integer. - let mut into_cases = vec![]; - for tag in tags.iter() { - match tag { - ast::Tag::Value(tag) => { - let id = format_tag_ident(&tag.id); - let value = format_value(tag.value); - into_cases.push(quote! { #name::#id => #value }) - } - ast::Tag::Range(tag) => { - into_cases.extend(tag.tags.iter().map(|tag| { - let id = format_tag_ident(&tag.id); - let value = format_value(tag.value); - quote! { #name::#id => #value } - })); - let id = format_tag_ident(&tag.id); - into_cases.push(quote! { #name::#id(Private(value)) => *value }) - } - } - } - - // Generate a default case if the enum is open and incomplete. - if !is_complete && open { - variants.push(quote! { Unknown(Private<#backing_type>) }); - from_cases.push(quote! { 0..#range_max => Ok(#name::Unknown(Private(value))) }); - into_cases.push(quote! { #name::Unknown(Private(value)) => *value }); - } - - // Generate an error case if the enum size is lower than the backing - // type size, or if the enum is closed or incomplete. - if backing_type.width != width || (!is_complete && !open) { - from_cases.push(quote! { _ => Err(value) }); - } - - // Derive other Into and Into implementations from the explicit - // implementation, where the type is larger than the backing type. - let derived_signed_into_types = [8, 16, 32, 64] - .into_iter() - .filter(|w| *w > width) - .map(|w| syn::parse_str::(&format!("i{}", w)).unwrap()); - let derived_unsigned_into_types = [8, 16, 32, 64] - .into_iter() - .filter(|w| *w >= width && *w != backing_type.width) - .map(|w| syn::parse_str::(&format!("u{}", w)).unwrap()); - let derived_into_types = derived_signed_into_types.chain(derived_unsigned_into_types); - - quote! { - #repr_u64 - #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - #[cfg_attr(feature = "serde", serde(try_from = #backing_type_str, into = #backing_type_str))] - pub enum #name { - #(#variants,)* - } - - impl TryFrom<#backing_type> for #name { - type Error = #backing_type; - fn try_from(value: #backing_type) -> std::result::Result { - match value { - #(#from_cases,)* - } - } - } - - impl From<&#name> for #backing_type { - fn from(value: &#name) -> Self { - match value { - #(#into_cases,)* - } - } - } - - impl From<#name> for #backing_type { - fn from(value: #name) -> Self { - (&value).into() - } - } - - #(impl From<#name> for #derived_into_types { - fn from(value: #name) -> Self { - #backing_type::from(value) as Self - } - })* - } -} - -fn generate_decl( - scope: &lint::Scope<'_>, - file: &analyzer_ast::File, - decl: &analyzer_ast::Decl, -) -> String { - match &decl.desc { - ast::DeclDesc::Packet { id, .. } => { - generate_packet_decl(scope, file.endianness.value, id).to_string() - } - ast::DeclDesc::Struct { id, parent_id: None, .. } => { - // TODO(mgeisler): handle structs with parents. We could - // generate code for them, but the code is not useful - // since it would require the caller to unpack everything - // manually. We either need to change the API, or - // implement the recursive (de)serialization. - generate_struct_decl(scope, file.endianness.value, id).to_string() - } - ast::DeclDesc::Enum { id, tags, width } => { - generate_enum_decl(id, tags, *width, false).to_string() - } - _ => todo!("unsupported Decl::{:?}", decl), - } -} - -/// Generate Rust code from an AST. -/// -/// The code is not formatted, pipe it through `rustfmt` to get -/// readable source code. -pub fn generate(sources: &ast::SourceDatabase, file: &analyzer_ast::File) -> String { - let mut code = String::new(); - - let source = sources.get(file.file).expect("could not read source"); - code.push_str(&preamble::generate(Path::new(source.name()))); - - let scope = lint::Scope::new(file); - for decl in &file.declarations { - code.push_str(&generate_decl(&scope, file, decl)); - code.push_str("\n\n"); - } - - code -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::analyzer; - use crate::ast; - use crate::parser::parse_inline; - use crate::test_utils::{assert_snapshot_eq, rustfmt}; - use paste::paste; - - /// Parse a string fragment as a PDL file. - /// - /// # Panics - /// - /// Panics on parse errors. - pub fn parse_str(text: &str) -> analyzer_ast::File { - let mut db = ast::SourceDatabase::new(); - let file = - parse_inline(&mut db, String::from("stdin"), String::from(text)).expect("parse error"); - analyzer::analyze(&file).expect("analyzer error") - } - - #[track_caller] - fn assert_iter_eq( - left: impl IntoIterator, - right: impl IntoIterator, - ) { - assert_eq!(left.into_iter().collect::>(), right.into_iter().collect::>()); - } - - #[test] - fn test_find_constrained_parent_fields() { - let code = " - little_endian_packets - packet Parent { - a: 8, - b: 8, - c: 8, - _payload_, - } - packet Child: Parent(a = 10) { - x: 8, - _payload_, - } - packet GrandChild: Child(b = 20) { - y: 8, - _payload_, - } - packet GrandGrandChild: GrandChild(c = 30) { - z: 8, - } - "; - let file = parse_str(code); - let scope = lint::Scope::new(&file); - let find_fields = - |id| find_constrained_parent_fields(&scope, id).map(|field| field.id().unwrap()); - assert_iter_eq(find_fields("Parent"), vec![]); - assert_iter_eq(find_fields("Child"), vec!["b", "c"]); - assert_iter_eq(find_fields("GrandChild"), vec!["c"]); - assert_iter_eq(find_fields("GrandGrandChild"), vec![]); - } - - /// Create a unit test for the given PDL `code`. - /// - /// The unit test will compare the generated Rust code for all - /// declarations with previously saved snapshots. The snapshots - /// are read from `"tests/generated/{name}_{endianness}_{id}.rs"` - /// where `is` taken from the declaration. - /// - /// When adding new tests or modifying existing ones, use - /// `UPDATE_SNAPSHOTS=1 cargo test` to automatically populate the - /// snapshots with the expected output. - /// - /// The `code` cannot have an endianness declaration, instead you - /// must supply either `little_endian` or `big_endian` as - /// `endianness`. - macro_rules! make_pdl_test { - ($name:ident, $code:expr, $endianness:ident) => { - paste! { - #[test] - fn [< test_ $name _ $endianness >]() { - let name = stringify!($name); - let endianness = stringify!($endianness); - let code = format!("{endianness}_packets\n{}", $code); - let mut db = ast::SourceDatabase::new(); - let file = parse_inline(&mut db, String::from("test"), code).unwrap(); - let file = analyzer::analyze(&file).unwrap(); - let actual_code = generate(&db, &file); - assert_snapshot_eq( - &format!("tests/generated/{name}_{endianness}.rs"), - &rustfmt(&actual_code), - ); - } - } - }; - } - - /// Create little- and bit-endian tests for the given PDL `code`. - /// - /// The `code` cannot have an endianness declaration: we will - /// automatically generate unit tests for both - /// "little_endian_packets" and "big_endian_packets". - macro_rules! test_pdl { - ($name:ident, $code:expr $(,)?) => { - make_pdl_test!($name, $code, little_endian); - make_pdl_test!($name, $code, big_endian); - }; - } - - test_pdl!(packet_decl_empty, "packet Foo {}"); - - test_pdl!(packet_decl_8bit_scalar, " packet Foo { x: 8 }"); - test_pdl!(packet_decl_24bit_scalar, "packet Foo { x: 24 }"); - test_pdl!(packet_decl_64bit_scalar, "packet Foo { x: 64 }"); - - test_pdl!( - enum_declaration, - r#" - // Should generate unknown case. - enum IncompleteTruncated : 3 { - A = 0, - B = 1, - } - - // Should generate unknown case. - enum IncompleteTruncatedWithRange : 3 { - A = 0, - B = 1..6 { - X = 1, - Y = 2, - } - } - - // Should generate unreachable case. - enum CompleteTruncated : 3 { - A = 0, - B = 1, - C = 2, - D = 3, - E = 4, - F = 5, - G = 6, - H = 7, - } - - // Should generate unreachable case. - enum CompleteTruncatedWithRange : 3 { - A = 0, - B = 1..7 { - X = 1, - Y = 2, - } - } - - // Should generate no unknown or unreachable case. - enum CompleteWithRange : 8 { - A = 0, - B = 1, - C = 2..255, - } - "# - ); - - test_pdl!( - packet_decl_simple_scalars, - r#" - packet Foo { - x: 8, - y: 16, - z: 24, - } - "# - ); - - test_pdl!( - packet_decl_complex_scalars, - r#" - packet Foo { - a: 3, - b: 8, - c: 5, - d: 24, - e: 12, - f: 4, - } - "#, - ); - - // Test that we correctly mask a byte-sized value in the middle of - // a chunk. - test_pdl!( - packet_decl_mask_scalar_value, - r#" - packet Foo { - a: 2, - b: 24, - c: 6, - } - "#, - ); - - test_pdl!( - struct_decl_complex_scalars, - r#" - struct Foo { - a: 3, - b: 8, - c: 5, - d: 24, - e: 12, - f: 4, - } - "#, - ); - - test_pdl!(packet_decl_8bit_enum, " enum Foo : 8 { A = 1, B = 2 } packet Bar { x: Foo }"); - test_pdl!(packet_decl_24bit_enum, "enum Foo : 24 { A = 1, B = 2 } packet Bar { x: Foo }"); - test_pdl!(packet_decl_64bit_enum, "enum Foo : 64 { A = 1, B = 2 } packet Bar { x: Foo }"); - - test_pdl!( - packet_decl_mixed_scalars_enums, - " - enum Enum7 : 7 { - A = 1, - B = 2, - } - - enum Enum9 : 9 { - A = 1, - B = 2, - } - - packet Foo { - x: Enum7, - y: 5, - z: Enum9, - w: 3, - } - " - ); - - test_pdl!(packet_decl_8bit_scalar_array, " packet Foo { x: 8[3] }"); - test_pdl!(packet_decl_24bit_scalar_array, "packet Foo { x: 24[5] }"); - test_pdl!(packet_decl_64bit_scalar_array, "packet Foo { x: 64[7] }"); - - test_pdl!( - packet_decl_8bit_enum_array, - "enum Foo : 8 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[3] }" - ); - test_pdl!( - packet_decl_24bit_enum_array, - "enum Foo : 24 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[5] }" - ); - test_pdl!( - packet_decl_64bit_enum_array, - "enum Foo : 64 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[7] }" - ); - - test_pdl!( - packet_decl_array_dynamic_count, - " - packet Foo { - _count_(x): 5, - padding: 3, - x: 24[] - } - " - ); - - test_pdl!( - packet_decl_array_dynamic_size, - " - packet Foo { - _size_(x): 5, - padding: 3, - x: 24[] - } - " - ); - - test_pdl!( - packet_decl_array_unknown_element_width_dynamic_size, - " - struct Foo { - _count_(a): 40, - a: 16[], - } - - packet Bar { - _size_(x): 40, - x: Foo[], - } - " - ); - - test_pdl!( - packet_decl_array_unknown_element_width_dynamic_count, - " - struct Foo { - _count_(a): 40, - a: 16[], - } - - packet Bar { - _count_(x): 40, - x: Foo[], - } - " - ); - - test_pdl!( - packet_decl_reserved_field, - " - packet Foo { - _reserved_: 40, - } - " - ); - - test_pdl!( - packet_decl_fixed_scalar_field, - " - packet Foo { - _fixed_ = 7 : 7, - b: 57, - } - " - ); - - test_pdl!( - packet_decl_fixed_enum_field, - " - enum Enum7 : 7 { - A = 1, - B = 2, - } - - packet Foo { - _fixed_ = A : Enum7, - b: 57, - } - " - ); - - test_pdl!( - packet_decl_payload_field_variable_size, - " - packet Foo { - a: 8, - _size_(_payload_): 8, - _payload_, - b: 16, - } - " - ); - - test_pdl!( - packet_decl_payload_field_unknown_size, - " - packet Foo { - a: 24, - _payload_, - } - " - ); - - test_pdl!( - packet_decl_payload_field_unknown_size_terminal, - " - packet Foo { - _payload_, - a: 24, - } - " - ); - - test_pdl!( - packet_decl_child_packets, - " - enum Enum16 : 16 { - A = 1, - B = 2, - } - - packet Foo { - a: 8, - b: Enum16, - _size_(_payload_): 8, - _payload_ - } - - packet Bar : Foo (a = 100) { - x: 8, - } - - packet Baz : Foo (b = B) { - y: 16, - } - " - ); - - test_pdl!( - packet_decl_grand_children, - " - enum Enum16 : 16 { - A = 1, - B = 2, - } - - packet Parent { - foo: Enum16, - bar: Enum16, - baz: Enum16, - _size_(_payload_): 8, - _payload_ - } - - packet Child : Parent (foo = A) { - quux: Enum16, - _payload_, - } - - packet GrandChild : Child (bar = A, quux = A) { - _body_, - } - - packet GrandGrandChild : GrandChild (baz = A) { - _body_, - } - " - ); - - // TODO(mgeisler): enable this test when we have an approach to - // struct fields with parents. - // - // test_pdl!( - // struct_decl_child_structs, - // " - // enum Enum16 : 16 { - // A = 1, - // B = 2, - // } - // - // struct Foo { - // a: 8, - // b: Enum16, - // _size_(_payload_): 8, - // _payload_ - // } - // - // struct Bar : Foo (a = 100) { - // x: 8, - // } - // - // struct Baz : Foo (b = B) { - // y: 16, - // } - // " - // ); - // - // test_pdl!( - // struct_decl_grand_children, - // " - // enum Enum16 : 16 { - // A = 1, - // B = 2, - // } - // - // struct Parent { - // foo: Enum16, - // bar: Enum16, - // baz: Enum16, - // _size_(_payload_): 8, - // _payload_ - // } - // - // struct Child : Parent (foo = A) { - // quux: Enum16, - // _payload_, - // } - // - // struct GrandChild : Child (bar = A, quux = A) { - // _body_, - // } - // - // struct GrandGrandChild : GrandChild (baz = A) { - // _body_, - // } - // " - // ); -} diff --git a/tools/pdl/src/backends/rust/parser.rs b/tools/pdl/src/backends/rust/parser.rs deleted file mode 100644 index 71984f877bbc825b896e4127b0c3d2dffa15c1f8..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust/parser.rs +++ /dev/null @@ -1,744 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use crate::analyzer::ast as analyzer_ast; -use crate::backends::rust::{ - constraint_to_value, find_constrained_parent_fields, mask_bits, types, ToUpperCamelCase, -}; -use crate::{ast, lint}; -use quote::{format_ident, quote}; -use std::collections::{BTreeSet, HashMap}; - -fn size_field_ident(id: &str) -> proc_macro2::Ident { - format_ident!("{}_size", id.trim_matches('_')) -} - -/// A single bit-field. -struct BitField<'a> { - shift: usize, // The shift to apply to this field. - field: &'a analyzer_ast::Field, -} - -pub struct FieldParser<'a> { - scope: &'a lint::Scope<'a>, - endianness: ast::EndiannessValue, - packet_name: &'a str, - span: &'a proc_macro2::Ident, - chunk: Vec>, - code: Vec, - shift: usize, - offset: usize, -} - -impl<'a> FieldParser<'a> { - pub fn new( - scope: &'a lint::Scope<'a>, - endianness: ast::EndiannessValue, - packet_name: &'a str, - span: &'a proc_macro2::Ident, - ) -> FieldParser<'a> { - FieldParser { - scope, - endianness, - packet_name, - span, - chunk: Vec::new(), - code: Vec::new(), - shift: 0, - offset: 0, - } - } - - pub fn add(&mut self, field: &'a analyzer_ast::Field) { - match &field.desc { - _ if self.scope.is_bitfield(field) => self.add_bit_field(field), - ast::FieldDesc::Padding { .. } => todo!("Padding fields are not supported"), - ast::FieldDesc::Array { id, width, type_id, size, .. } => self.add_array_field( - id, - *width, - type_id.as_deref(), - *size, - self.scope.get_field_declaration(field), - ), - ast::FieldDesc::Typedef { id, type_id } => self.add_typedef_field(id, type_id), - ast::FieldDesc::Payload { size_modifier, .. } => { - self.add_payload_field(size_modifier.as_deref()) - } - ast::FieldDesc::Body { .. } => self.add_payload_field(None), - _ => todo!("{field:?}"), - } - } - - fn add_bit_field(&mut self, field: &'a analyzer_ast::Field) { - self.chunk.push(BitField { shift: self.shift, field }); - self.shift += self.scope.get_field_width(field, false).unwrap(); - if self.shift % 8 != 0 { - return; - } - - let size = self.shift / 8; - let end_offset = self.offset + size; - - let wanted = proc_macro2::Literal::usize_unsuffixed(size); - self.check_size("e!(#wanted)); - - let chunk_type = types::Integer::new(self.shift); - // TODO(mgeisler): generate Rust variable names which cannot - // conflict with PDL field names. An option would be to start - // Rust variable names with `_`, but that has a special - // semantic in Rust. - let chunk_name = format_ident!("chunk"); - - let get = types::get_uint(self.endianness, self.shift, self.span); - if self.chunk.len() > 1 { - // Multiple values: we read into a local variable. - self.code.push(quote! { - let #chunk_name = #get; - }); - } - - let single_value = self.chunk.len() == 1; // && self.chunk[0].offset == 0; - for BitField { shift, field } in self.chunk.drain(..) { - let mut v = if single_value { - // Single value: read directly. - quote! { #get } - } else { - // Multiple values: read from `chunk_name`. - quote! { #chunk_name } - }; - - if shift > 0 { - let shift = proc_macro2::Literal::usize_unsuffixed(shift); - v = quote! { (#v >> #shift) } - } - - let width = self.scope.get_field_width(field, false).unwrap(); - let value_type = types::Integer::new(width); - if !single_value && width < value_type.width { - // Mask value if we grabbed more than `width` and if - // `as #value_type` doesn't already do the masking. - let mask = mask_bits(width, "u64"); - v = quote! { (#v & #mask) }; - } - - if value_type.width < chunk_type.width { - v = quote! { #v as #value_type }; - } - - self.code.push(match &field.desc { - ast::FieldDesc::Scalar { id, .. } => { - let id = format_ident!("{id}"); - quote! { - let #id = #v; - } - } - ast::FieldDesc::FixedEnum { enum_id, tag_id, .. } => { - let enum_id = format_ident!("{enum_id}"); - let tag_id = format_ident!("{}", tag_id.to_upper_camel_case()); - quote! { - if #v != #value_type::from(#enum_id::#tag_id) { - return Err(Error::InvalidFixedValue { - expected: #value_type::from(#enum_id::#tag_id) as u64, - actual: #v as u64, - }); - } - } - } - ast::FieldDesc::FixedScalar { value, .. } => { - let value = proc_macro2::Literal::usize_unsuffixed(*value); - quote! { - if #v != #value { - return Err(Error::InvalidFixedValue { - expected: #value, - actual: #v as u64, - }); - } - } - } - ast::FieldDesc::Typedef { id, type_id } => { - let field_name = id; - let type_name = type_id; - let packet_name = &self.packet_name; - let id = format_ident!("{id}"); - let type_id = format_ident!("{type_id}"); - quote! { - let #id = #type_id::try_from(#v).map_err(|_| Error::InvalidEnumValueError { - obj: #packet_name.to_string(), - field: #field_name.to_string(), - value: #v as u64, - type_: #type_name.to_string(), - })?; - } - } - ast::FieldDesc::Reserved { .. } => { - if single_value { - let span = self.span; - let size = proc_macro2::Literal::usize_unsuffixed(size); - quote! { - #span.get_mut().advance(#size); - } - } else { - // Otherwise we don't need anything: we will - // have advanced past the reserved field when - // reading the chunk above. - quote! {} - } - } - ast::FieldDesc::Size { field_id, .. } => { - let id = size_field_ident(field_id); - quote! { - let #id = #v as usize; - } - } - ast::FieldDesc::Count { field_id, .. } => { - let id = format_ident!("{field_id}_count"); - quote! { - let #id = #v as usize; - } - } - _ => todo!(), - }); - } - - self.offset = end_offset; - self.shift = 0; - } - - fn packet_scope(&self) -> Option<&lint::PacketScope> { - self.scope.scopes.get(self.scope.typedef.get(self.packet_name)?) - } - - fn find_count_field(&self, id: &str) -> Option { - match self.packet_scope()?.get_array_size_field(id)?.desc { - ast::FieldDesc::Count { .. } => Some(format_ident!("{id}_count")), - _ => None, - } - } - - fn find_size_field(&self, id: &str) -> Option { - match self.packet_scope()?.get_array_size_field(id)?.desc { - ast::FieldDesc::Size { .. } => Some(size_field_ident(id)), - _ => None, - } - } - - fn payload_field_offset_from_end(&self) -> Option { - let packet_scope = self.packet_scope().unwrap(); - let mut fields = packet_scope.iter_fields(); - fields.find(|f| { - matches!(f.desc, ast::FieldDesc::Body { .. } | ast::FieldDesc::Payload { .. }) - })?; - - let mut offset = 0; - for field in fields { - if let Some(width) = self.scope.get_field_width(field, false) { - offset += width; - } else { - return None; - } - } - - Some(offset) - } - - fn check_size(&mut self, wanted: &proc_macro2::TokenStream) { - let packet_name = &self.packet_name; - let span = self.span; - self.code.push(quote! { - if #span.get().remaining() < #wanted { - return Err(Error::InvalidLengthError { - obj: #packet_name.to_string(), - wanted: #wanted, - got: #span.get().remaining(), - }); - } - }); - } - - fn add_array_field( - &mut self, - id: &str, - // `width`: the width in bits of the array elements (if Some). - width: Option, - // `type_id`: the enum type of the array elements (if Some). - // Mutually exclusive with `width`. - type_id: Option<&str>, - // `size`: the size of the array in number of elements (if - // known). If None, the array is a Vec with a dynamic size. - size: Option, - decl: Option<&analyzer_ast::Decl>, - ) { - enum ElementWidth { - Static(usize), // Static size in bytes. - Unknown, - } - let element_width = match width.or_else(|| self.scope.get_decl_width(decl?, false)) { - Some(w) => { - assert_eq!(w % 8, 0, "Array element size ({w}) is not a multiple of 8"); - ElementWidth::Static(w / 8) - } - None => ElementWidth::Unknown, - }; - - // The "shape" of the array, i.e., the number of elements - // given via a static count, a count field, a size field, or - // unknown. - enum ArrayShape { - Static(usize), // Static count - CountField(proc_macro2::Ident), // Count based on count field - SizeField(proc_macro2::Ident), // Count based on size and field - Unknown, // Variable count based on remaining bytes - } - let array_shape = if let Some(count) = size { - ArrayShape::Static(count) - } else if let Some(count_field) = self.find_count_field(id) { - ArrayShape::CountField(count_field) - } else if let Some(size_field) = self.find_size_field(id) { - ArrayShape::SizeField(size_field) - } else { - ArrayShape::Unknown - }; - - // TODO size modifier - - // TODO padded_size - - let id = format_ident!("{id}"); - let span = self.span; - - let parse_element = self.parse_array_element(self.span, width, type_id, decl); - match (element_width, &array_shape) { - (ElementWidth::Unknown, ArrayShape::SizeField(size_field)) => { - // The element width is not known, but the array full - // octet size is known by size field. Parse elements - // item by item as a vector. - self.check_size("e!(#size_field)); - let parse_element = - self.parse_array_element(&format_ident!("head"), width, type_id, decl); - self.code.push(quote! { - let (head, tail) = #span.get().split_at(#size_field); - let mut head = &mut Cell::new(head); - #span.replace(tail); - let mut #id = Vec::new(); - while !head.get().is_empty() { - #id.push(#parse_element?); - } - }); - } - (ElementWidth::Unknown, ArrayShape::Static(count)) => { - // The element width is not known, but the array - // element count is known statically. Parse elements - // item by item as an array. - let count = syn::Index::from(*count); - self.code.push(quote! { - // TODO(mgeisler): use - // https://doc.rust-lang.org/std/array/fn.try_from_fn.html - // when stabilized. - let #id = (0..#count) - .map(|_| #parse_element) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - }); - } - (ElementWidth::Unknown, ArrayShape::CountField(count_field)) => { - // The element width is not known, but the array - // element count is known by the count field. Parse - // elements item by item as a vector. - self.code.push(quote! { - let #id = (0..#count_field) - .map(|_| #parse_element) - .collect::>>()?; - }); - } - (ElementWidth::Unknown, ArrayShape::Unknown) => { - // Neither the count not size is known, parse elements - // until the end of the span. - self.code.push(quote! { - let mut #id = Vec::new(); - while !#span.get().is_empty() { - #id.push(#parse_element?); - } - }); - } - (ElementWidth::Static(element_width), ArrayShape::Static(count)) => { - // The element width is known, and the array element - // count is known statically. - let count = syn::Index::from(*count); - // This creates a nicely formatted size. - let array_size = if element_width == 1 { - quote!(#count) - } else { - let element_width = syn::Index::from(element_width); - quote!(#count * #element_width) - }; - self.check_size(&array_size); - self.code.push(quote! { - // TODO(mgeisler): use - // https://doc.rust-lang.org/std/array/fn.try_from_fn.html - // when stabilized. - let #id = (0..#count) - .map(|_| #parse_element) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - }); - } - (ElementWidth::Static(_), ArrayShape::CountField(count_field)) => { - // The element width is known, and the array element - // count is known dynamically by the count field. - self.check_size("e!(#count_field)); - self.code.push(quote! { - let #id = (0..#count_field) - .map(|_| #parse_element) - .collect::>>()?; - }); - } - (ElementWidth::Static(element_width), ArrayShape::SizeField(_)) - | (ElementWidth::Static(element_width), ArrayShape::Unknown) => { - // The element width is known, and the array full size - // is known by size field, or unknown (in which case - // it is the remaining span length). - let array_size = if let ArrayShape::SizeField(size_field) = &array_shape { - self.check_size("e!(#size_field)); - quote!(#size_field) - } else { - quote!(#span.get().remaining()) - }; - let count_field = format_ident!("{id}_count"); - let array_count = if element_width != 1 { - let element_width = syn::Index::from(element_width); - self.code.push(quote! { - if #array_size % #element_width != 0 { - return Err(Error::InvalidArraySize { - array: #array_size, - element: #element_width, - }); - } - let #count_field = #array_size / #element_width; - }); - quote!(#count_field) - } else { - array_size - }; - - self.code.push(quote! { - let mut #id = Vec::with_capacity(#array_count); - for _ in 0..#array_count { - #id.push(#parse_element?); - } - }); - } - } - } - - /// Parse typedef fields. - /// - /// This is only for non-enum fields: enums are parsed via - /// add_bit_field. - fn add_typedef_field(&mut self, id: &str, type_id: &str) { - assert_eq!(self.shift, 0, "Typedef field does not start on an octet boundary"); - - let decl = self.scope.typedef[type_id]; - if let ast::DeclDesc::Struct { parent_id: Some(_), .. } = &decl.desc { - panic!("Derived struct used in typedef field"); - } - - let span = self.span; - let id = format_ident!("{id}"); - let type_id = format_ident!("{type_id}"); - - match self.scope.get_decl_width(decl, true) { - None => self.code.push(quote! { - let #id = #type_id::parse_inner(&mut #span)?; - }), - Some(width) => { - assert_eq!(width % 8, 0, "Typedef field type size is not a multiple of 8"); - let width = syn::Index::from(width / 8); - self.code.push(if let ast::DeclDesc::Checksum { .. } = &decl.desc { - // TODO: handle checksum fields. - quote! { - #span.get_mut().advance(#width); - } - } else { - quote! { - let (head, tail) = #span.get().split_at(#width); - #span.replace(tail); - let #id = #type_id::parse(head)?; - } - }); - } - } - } - - /// Parse body and payload fields. - fn add_payload_field(&mut self, size_modifier: Option<&str>) { - let span = self.span; - let packet_scope = self.packet_scope().unwrap(); - let payload_size_field = packet_scope.get_payload_size_field(); - let offset_from_end = self.payload_field_offset_from_end(); - - if size_modifier.is_some() { - todo!( - "Unsupported size modifier for {packet}: {size_modifier:?}", - packet = self.packet_name - ); - } - - if self.shift != 0 { - if payload_size_field.is_some() { - panic!("Unexpected payload size for non byte aligned payload"); - } - - //let rounded_size = self.shift / 8 + if self.shift % 8 == 0 { 0 } else { 1 }; - //let padding_bits = 8 * rounded_size - self.shift; - //let reserved_field = - // ast::Field::Reserved { loc: ast::SourceRange::default(), width: padding_bits }; - //TODO: self.add_bit_field(&reserved_field); -- - // reserved_field does not live long enough. - - // TODO: consume span of rounded size - } else { - // TODO: consume span - } - - if let Some(ast::FieldDesc::Size { field_id, .. }) = &payload_size_field.map(|f| &f.desc) { - // The payload or body has a known size. Consume the - // payload and update the span in case fields are placed - // after the payload. - let size_field = size_field_ident(field_id); - self.check_size("e!(#size_field )); - self.code.push(quote! { - let payload = &#span.get()[..#size_field]; - #span.get_mut().advance(#size_field); - }); - } else if offset_from_end == Some(0) { - // The payload or body is the last field of a packet, - // consume the remaining span. - self.code.push(quote! { - let payload = #span.get(); - #span.get_mut().advance(payload.len()); - }); - } else if let Some(offset_from_end) = offset_from_end { - // The payload or body is followed by fields of static - // size. Consume the span that is not reserved for the - // following fields. - assert_eq!( - offset_from_end % 8, - 0, - "Payload field offset from end of packet is not a multiple of 8" - ); - let offset_from_end = syn::Index::from(offset_from_end / 8); - self.check_size("e!(#offset_from_end)); - self.code.push(quote! { - let payload = &#span.get()[..#span.get().len() - #offset_from_end]; - #span.get_mut().advance(payload.len()); - }); - } - - let decl = self.scope.typedef[self.packet_name]; - if let ast::DeclDesc::Struct { .. } = &decl.desc { - self.code.push(quote! { - let payload = Vec::from(payload); - }); - } - } - - /// Parse a single array field element from `span`. - fn parse_array_element( - &self, - span: &proc_macro2::Ident, - width: Option, - type_id: Option<&str>, - decl: Option<&analyzer_ast::Decl>, - ) -> proc_macro2::TokenStream { - if let Some(width) = width { - let get_uint = types::get_uint(self.endianness, width, span); - return quote! { - Ok::<_, Error>(#get_uint) - }; - } - - if let Some(ast::DeclDesc::Enum { id, width, .. }) = decl.map(|decl| &decl.desc) { - let get_uint = types::get_uint(self.endianness, *width, span); - let type_id = format_ident!("{id}"); - let packet_name = &self.packet_name; - return quote! { - #type_id::try_from(#get_uint).map_err(|_| Error::InvalidEnumValueError { - obj: #packet_name.to_string(), - field: String::new(), // TODO(mgeisler): fill out or remove - value: 0, - type_: #id.to_string(), - }) - }; - } - - let type_id = format_ident!("{}", type_id.unwrap()); - quote! { - #type_id::parse_inner(#span) - } - } - - pub fn done(&mut self) { - let decl = self.scope.typedef[self.packet_name]; - if let ast::DeclDesc::Struct { .. } = &decl.desc { - return; // Structs don't parse the child structs recursively. - } - - let packet_scope = &self.scope.scopes[&decl]; - let children = self.scope.iter_children(self.packet_name).collect::>(); - if children.is_empty() && packet_scope.get_payload_field().is_none() { - return; - } - - let child_ids = children - .iter() - .map(|child| format_ident!("{}", child.id().unwrap())) - .collect::>(); - let child_ids_data = child_ids.iter().map(|ident| format_ident!("{ident}Data")); - - // Set of field names (sorted by name). - let mut constrained_fields = BTreeSet::new(); - // Maps (child name, field name) -> value. - let mut constraint_values = HashMap::new(); - - for child in children.iter() { - match &child.desc { - ast::DeclDesc::Packet { id, constraints, .. } - | ast::DeclDesc::Struct { id, constraints, .. } => { - for constraint in constraints.iter() { - constrained_fields.insert(&constraint.id); - constraint_values.insert( - (id.as_str(), &constraint.id), - constraint_to_value(packet_scope, constraint), - ); - } - } - _ => unreachable!("Invalid child: {child:?}"), - } - } - - let wildcard = quote!(_); - let match_values = children.iter().map(|child| { - let child_id = child.id().unwrap(); - let values = constrained_fields.iter().map(|field_name| { - constraint_values.get(&(child_id, field_name)).unwrap_or(&wildcard) - }); - quote! { - (#(#values),*) - } - }); - let constrained_field_idents = - constrained_fields.iter().map(|field| format_ident!("{field}")); - let child_parse_args = children.iter().map(|child| { - let fields = find_constrained_parent_fields(self.scope, child.id().unwrap()) - .map(|field| format_ident!("{}", field.id().unwrap())); - quote!(#(, #fields)*) - }); - let packet_data_child = format_ident!("{}DataChild", self.packet_name); - self.code.push(quote! { - let child = match (#(#constrained_field_idents),*) { - #(#match_values if #child_ids_data::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = #child_ids_data::parse_inner(&mut cell #child_parse_args)?; - // TODO(mgeisler): communicate back to user if !cell.get().is_empty()? - #packet_data_child::#child_ids(Arc::new(child_data)) - }),* - _ if !payload.is_empty() => { - #packet_data_child::Payload(Bytes::copy_from_slice(payload)) - } - _ => #packet_data_child::None, - }; - }); - } -} - -impl quote::ToTokens for FieldParser<'_> { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let code = &self.code; - tokens.extend(quote! { - #(#code)* - }); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::analyzer; - use crate::ast; - use crate::parser::parse_inline; - - /// Parse a string fragment as a PDL file. - /// - /// # Panics - /// - /// Panics on parse errors. - pub fn parse_str(text: &str) -> analyzer_ast::File { - let mut db = ast::SourceDatabase::new(); - let file = - parse_inline(&mut db, String::from("stdin"), String::from(text)).expect("parse error"); - analyzer::analyze(&file).expect("analyzer error") - } - - #[test] - fn test_find_fields_static() { - let code = " - little_endian_packets - packet P { - a: 24[3], - } - "; - let file = parse_str(code); - let scope = lint::Scope::new(&file); - let span = format_ident!("bytes"); - let parser = FieldParser::new(&scope, file.endianness.value, "P", &span); - assert_eq!(parser.find_size_field("a"), None); - assert_eq!(parser.find_count_field("a"), None); - } - - #[test] - fn test_find_fields_dynamic_count() { - let code = " - little_endian_packets - packet P { - _count_(b): 24, - b: 16[], - } - "; - let file = parse_str(code); - let scope = lint::Scope::new(&file); - let span = format_ident!("bytes"); - let parser = FieldParser::new(&scope, file.endianness.value, "P", &span); - assert_eq!(parser.find_size_field("b"), None); - assert_eq!(parser.find_count_field("b"), Some(format_ident!("b_count"))); - } - - #[test] - fn test_find_fields_dynamic_size() { - let code = " - little_endian_packets - packet P { - _size_(c): 8, - c: 24[], - } - "; - let file = parse_str(code); - let scope = lint::Scope::new(&file); - let span = format_ident!("bytes"); - let parser = FieldParser::new(&scope, file.endianness.value, "P", &span); - assert_eq!(parser.find_size_field("c"), Some(format_ident!("c_size"))); - assert_eq!(parser.find_count_field("c"), None); - } -} diff --git a/tools/pdl/src/backends/rust/preamble.rs b/tools/pdl/src/backends/rust/preamble.rs deleted file mode 100644 index 9b23ede5527846cecc3bb72afe7d0d6270ea4105..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust/preamble.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use std::path::Path; - -use crate::quote_block; - -/// Generate the file preamble. -pub fn generate(path: &Path) -> String { - let mut code = String::new(); - let filename = path.file_name().unwrap().to_str().expect("non UTF-8 filename"); - // TODO(mgeisler): Make the generated code free from warnings. - // - // The code either needs - // - // clippy_lints: "none", - // lints: "none", - // - // in the Android.bp file, or we need to add - // - // #![allow(warnings, missing_docs)] - // - // to the generated code. We cannot add the module-level attribute - // here because of how the generated code is used with include! in - // lmp/src/packets.rs. - code.push_str(&format!("// @generated rust packets from {filename}\n\n")); - - code.push_str("e_block! { - use bytes::{Buf, BufMut, Bytes, BytesMut}; - use std::convert::{TryFrom, TryInto}; - use std::cell::Cell; - use std::fmt; - use std::sync::Arc; - use thiserror::Error; - }); - - code.push_str("e_block! { - type Result = std::result::Result; - }); - - code.push_str("e_block! { - /// Private prevents users from creating arbitrary scalar values - /// in situations where the value needs to be validated. - /// Users can freely deref the value, but only the backend - /// may create it. - #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] - pub struct Private(T); - - impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - }); - - code.push_str("e_block! { - #[derive(Debug, Error)] - pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, - } - }); - - code.push_str("e_block! { - pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; - } - }); - - code -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_utils::{assert_snapshot_eq, rustfmt}; - - #[test] - fn test_generate_preamble() { - let actual_code = generate(Path::new("some/path/foo.pdl")); - assert_snapshot_eq("tests/generated/preamble.rs", &rustfmt(&actual_code)); - } -} diff --git a/tools/pdl/src/backends/rust/serializer.rs b/tools/pdl/src/backends/rust/serializer.rs deleted file mode 100644 index 7ef3bf29351833da3b064e7f703ce51be389ab92..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust/serializer.rs +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use crate::analyzer::ast as analyzer_ast; -use crate::backends::rust::{mask_bits, types, ToUpperCamelCase}; -use crate::{ast, lint}; -use quote::{format_ident, quote}; - -/// A single bit-field value. -struct BitField { - value: proc_macro2::TokenStream, // An expression which produces a value. - field_type: types::Integer, // The type of the value. - shift: usize, // A bit-shift to apply to `value`. -} - -pub struct FieldSerializer<'a> { - scope: &'a lint::Scope<'a>, - endianness: ast::EndiannessValue, - packet_name: &'a str, - span: &'a proc_macro2::Ident, - chunk: Vec, - code: Vec, - shift: usize, -} - -impl<'a> FieldSerializer<'a> { - pub fn new( - scope: &'a lint::Scope<'a>, - endianness: ast::EndiannessValue, - packet_name: &'a str, - span: &'a proc_macro2::Ident, - ) -> FieldSerializer<'a> { - FieldSerializer { - scope, - endianness, - packet_name, - span, - chunk: Vec::new(), - code: Vec::new(), - shift: 0, - } - } - - pub fn add(&mut self, field: &analyzer_ast::Field) { - match &field.desc { - _ if self.scope.is_bitfield(field) => self.add_bit_field(field), - ast::FieldDesc::Array { id, width, .. } => { - self.add_array_field(id, *width, self.scope.get_field_declaration(field)) - } - ast::FieldDesc::Typedef { id, type_id } => { - self.add_typedef_field(id, type_id); - } - ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. } => { - self.add_payload_field() - } - _ => todo!("Cannot yet serialize {field:?}"), - } - } - - fn add_bit_field(&mut self, field: &analyzer_ast::Field) { - let width = self.scope.get_field_width(field, false).unwrap(); - let shift = self.shift; - - match &field.desc { - ast::FieldDesc::Scalar { id, width } => { - let field_name = format_ident!("{id}"); - let field_type = types::Integer::new(*width); - if field_type.width > *width { - let packet_name = &self.packet_name; - let max_value = mask_bits(*width, "u64"); - self.code.push(quote! { - if self.#field_name > #max_value { - panic!( - "Invalid value for {}::{}: {} > {}", - #packet_name, #id, self.#field_name, #max_value - ); - } - }); - } - self.chunk.push(BitField { value: quote!(self.#field_name), field_type, shift }); - } - ast::FieldDesc::FixedEnum { enum_id, tag_id, .. } => { - let field_type = types::Integer::new(width); - let enum_id = format_ident!("{enum_id}"); - let tag_id = format_ident!("{}", tag_id.to_upper_camel_case()); - self.chunk.push(BitField { - value: quote!(#field_type::from(#enum_id::#tag_id)), - field_type, - shift, - }); - } - ast::FieldDesc::FixedScalar { value, .. } => { - let field_type = types::Integer::new(width); - let value = proc_macro2::Literal::usize_unsuffixed(*value); - self.chunk.push(BitField { value: quote!(#value), field_type, shift }); - } - ast::FieldDesc::Typedef { id, .. } => { - let field_name = format_ident!("{id}"); - let field_type = types::Integer::new(width); - self.chunk.push(BitField { - value: quote!(#field_type::from(self.#field_name)), - field_type, - shift, - }); - } - ast::FieldDesc::Reserved { .. } => { - // Nothing to do here. - } - ast::FieldDesc::Size { field_id, width, .. } => { - let packet_name = &self.packet_name; - let max_value = mask_bits(*width, "usize"); - - let decl = self.scope.typedef.get(self.packet_name).unwrap(); - let scope = self.scope.scopes.get(decl).unwrap(); - let value_field = scope.get_packet_field(field_id).unwrap(); - - let field_name = format_ident!("{field_id}"); - let field_type = types::Integer::new(*width); - // TODO: size modifier - - let value_field_decl = self.scope.get_field_declaration(value_field); - - let field_size_name = format_ident!("{field_id}_size"); - let array_size = match (&value_field.desc, value_field_decl.map(|decl| &decl.desc)) - { - (ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. }, _) => { - if let ast::DeclDesc::Packet { .. } = &decl.desc { - quote! { self.child.get_total_size() } - } else { - quote! { self.payload.len() } - } - } - (ast::FieldDesc::Array { width: Some(width), .. }, _) - | (ast::FieldDesc::Array { .. }, Some(ast::DeclDesc::Enum { width, .. })) => { - let byte_width = syn::Index::from(width / 8); - if byte_width.index == 1 { - quote! { self.#field_name.len() } - } else { - quote! { (self.#field_name.len() * #byte_width) } - } - } - (ast::FieldDesc::Array { .. }, _) => { - self.code.push(quote! { - let #field_size_name = self.#field_name - .iter() - .map(|elem| elem.get_size()) - .sum::(); - }); - quote! { #field_size_name } - } - _ => panic!("Unexpected size field: {field:?}"), - }; - - self.code.push(quote! { - if #array_size > #max_value { - panic!( - "Invalid length for {}::{}: {} > {}", - #packet_name, #field_id, #array_size, #max_value - ); - } - }); - - self.chunk.push(BitField { - value: quote!(#array_size as #field_type), - field_type, - shift, - }); - } - ast::FieldDesc::Count { field_id, width, .. } => { - let field_name = format_ident!("{field_id}"); - let field_type = types::Integer::new(*width); - if field_type.width > *width { - let packet_name = &self.packet_name; - let max_value = mask_bits(*width, "usize"); - self.code.push(quote! { - if self.#field_name.len() > #max_value { - panic!( - "Invalid length for {}::{}: {} > {}", - #packet_name, #field_id, self.#field_name.len(), #max_value - ); - } - }); - } - self.chunk.push(BitField { - value: quote!(self.#field_name.len() as #field_type), - field_type, - shift, - }); - } - _ => todo!("{field:?}"), - } - - self.shift += width; - if self.shift % 8 == 0 { - self.pack_bit_fields() - } - } - - fn pack_bit_fields(&mut self) { - assert_eq!(self.shift % 8, 0); - let chunk_type = types::Integer::new(self.shift); - let values = self - .chunk - .drain(..) - .map(|BitField { mut value, field_type, shift }| { - if field_type.width != chunk_type.width { - // We will be combining values with `|`, so we - // need to cast them first. - value = quote! { (#value as #chunk_type) }; - } - if shift > 0 { - let op = quote!(<<); - let shift = proc_macro2::Literal::usize_unsuffixed(shift); - value = quote! { (#value #op #shift) }; - } - value - }) - .collect::>(); - - match values.as_slice() { - [] => { - let span = format_ident!("{}", self.span); - let count = syn::Index::from(self.shift / 8); - self.code.push(quote! { - #span.put_bytes(0, #count); - }); - } - [value] => { - let put = types::put_uint(self.endianness, value, self.shift, self.span); - self.code.push(quote! { - #put; - }); - } - _ => { - let put = types::put_uint(self.endianness, "e!(value), self.shift, self.span); - self.code.push(quote! { - let value = #(#values)|*; - #put; - }); - } - } - - self.shift = 0; - } - - fn add_array_field( - &mut self, - id: &str, - width: Option, - decl: Option<&analyzer_ast::Decl>, - ) { - // TODO: padding - - let serialize = match width { - Some(width) => { - let value = quote!(*elem); - types::put_uint(self.endianness, &value, width, self.span) - } - None => { - if let Some(ast::DeclDesc::Enum { width, .. }) = decl.map(|decl| &decl.desc) { - let element_type = types::Integer::new(*width); - types::put_uint( - self.endianness, - "e!(#element_type::from(elem)), - *width, - self.span, - ) - } else { - let span = format_ident!("{}", self.span); - quote! { - elem.write_to(#span) - } - } - } - }; - - let id = format_ident!("{id}"); - self.code.push(quote! { - for elem in &self.#id { - #serialize; - } - }); - } - - fn add_typedef_field(&mut self, id: &str, type_id: &str) { - assert_eq!(self.shift, 0, "Typedef field does not start on an octet boundary"); - let decl = self.scope.typedef[type_id]; - if let ast::DeclDesc::Struct { parent_id: Some(_), .. } = &decl.desc { - panic!("Derived struct used in typedef field"); - } - - let id = format_ident!("{id}"); - let span = format_ident!("{}", self.span); - self.code.push(quote! { - self.#id.write_to(#span); - }); - } - - fn add_payload_field(&mut self) { - if self.shift != 0 && self.endianness == ast::EndiannessValue::BigEndian { - panic!("Payload field does not start on an octet boundary"); - } - - let decl = self.scope.typedef[self.packet_name]; - let is_packet = matches!(&decl.desc, ast::DeclDesc::Packet { .. }); - - let child_ids = self - .scope - .iter_children(self.packet_name) - .map(|child| format_ident!("{}", child.id().unwrap())) - .collect::>(); - - let span = format_ident!("{}", self.span); - if self.shift == 0 { - if is_packet { - let packet_data_child = format_ident!("{}DataChild", self.packet_name); - self.code.push(quote! { - match &self.child { - #(#packet_data_child::#child_ids(child) => child.write_to(#span),)* - #packet_data_child::Payload(payload) => #span.put_slice(payload), - #packet_data_child::None => {}, - } - }) - } else { - self.code.push(quote! { - #span.put_slice(&self.payload); - }); - } - } else { - todo!("Shifted payloads"); - } - } -} - -impl quote::ToTokens for FieldSerializer<'_> { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let code = &self.code; - tokens.extend(quote! { - #(#code)* - }); - } -} diff --git a/tools/pdl/src/backends/rust/types.rs b/tools/pdl/src/backends/rust/types.rs deleted file mode 100644 index bd73c0d6c3fbcef3965395e8d2845dd692391d43..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust/types.rs +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -//! Utility functions for dealing with Rust integer types. - -use crate::analyzer::ast as analyzer_ast; -use crate::{ast, lint}; -use quote::{format_ident, quote}; - -/// A Rust integer type such as `u8`. -#[derive(Copy, Clone)] -pub struct Integer { - pub width: usize, -} - -impl Integer { - /// Get the Rust integer type for the given bit width. - /// - /// This will round up the size to the nearest Rust integer size. - /// PDL supports integers up to 64 bit, so it is an error to call - /// this with a width larger than 64. - pub fn new(width: usize) -> Integer { - for integer_width in [8, 16, 32, 64] { - if width <= integer_width { - return Integer { width: integer_width }; - } - } - panic!("Cannot construct Integer with width: {width}") - } -} - -impl quote::ToTokens for Integer { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let t: syn::Type = syn::parse_str(&format!("u{}", self.width)) - .expect("Could not parse integer, unsupported width?"); - t.to_tokens(tokens); - } -} - -pub fn rust_type(field: &analyzer_ast::Field) -> proc_macro2::TokenStream { - match &field.desc { - ast::FieldDesc::Scalar { width, .. } => { - let field_type = Integer::new(*width); - quote!(#field_type) - } - ast::FieldDesc::Typedef { type_id, .. } => { - let field_type = format_ident!("{type_id}"); - quote!(#field_type) - } - ast::FieldDesc::Array { width: Some(width), size: Some(size), .. } => { - let field_type = Integer::new(*width); - let size = proc_macro2::Literal::usize_unsuffixed(*size); - quote!([#field_type; #size]) - } - ast::FieldDesc::Array { width: Some(width), size: None, .. } => { - let field_type = Integer::new(*width); - quote!(Vec<#field_type>) - } - ast::FieldDesc::Array { type_id: Some(type_id), size: Some(size), .. } => { - let field_type = format_ident!("{type_id}"); - let size = proc_macro2::Literal::usize_unsuffixed(*size); - quote!([#field_type; #size]) - } - ast::FieldDesc::Array { type_id: Some(type_id), size: None, .. } => { - let field_type = format_ident!("{type_id}"); - quote!(Vec<#field_type>) - } - //ast::Field::Size { .. } | ast::Field::Count { .. } => quote!(), - _ => todo!("{field:?}"), - } -} - -pub fn rust_borrow( - field: &analyzer_ast::Field, - scope: &lint::Scope<'_>, -) -> proc_macro2::TokenStream { - match &field.desc { - ast::FieldDesc::Scalar { .. } => quote!(), - ast::FieldDesc::Typedef { type_id, .. } => match &scope.typedef[type_id].desc { - ast::DeclDesc::Enum { .. } => quote!(), - ast::DeclDesc::Struct { .. } => quote!(&), - desc => unreachable!("unexpected declaration: {desc:?}"), - }, - ast::FieldDesc::Array { .. } => quote!(&), - _ => todo!(), - } -} - -/// Suffix for `Buf::get_*` and `BufMut::put_*` methods when reading a -/// value with the given `width`. -fn endianness_suffix(endianness: ast::EndiannessValue, width: usize) -> &'static str { - if width > 8 && endianness == ast::EndiannessValue::LittleEndian { - "_le" - } else { - "" - } -} - -/// Parse an unsigned integer with the given `width`. -/// -/// The generated code requires that `span` is a mutable `bytes::Buf` -/// value. -pub fn get_uint( - endianness: ast::EndiannessValue, - width: usize, - span: &proc_macro2::Ident, -) -> proc_macro2::TokenStream { - let suffix = endianness_suffix(endianness, width); - let value_type = Integer::new(width); - if value_type.width == width { - let get_u = format_ident!("get_u{}{}", value_type.width, suffix); - quote! { - #span.get_mut().#get_u() - } - } else { - let get_uint = format_ident!("get_uint{}", suffix); - let value_nbytes = proc_macro2::Literal::usize_unsuffixed(width / 8); - let cast = (value_type.width < 64).then(|| quote!(as #value_type)); - quote! { - #span.get_mut().#get_uint(#value_nbytes) #cast - } - } -} - -/// Write an unsigned integer `value` to `span`. -/// -/// The generated code requires that `span` is a mutable -/// `bytes::BufMut` value. -pub fn put_uint( - endianness: ast::EndiannessValue, - value: &proc_macro2::TokenStream, - width: usize, - span: &proc_macro2::Ident, -) -> proc_macro2::TokenStream { - let suffix = endianness_suffix(endianness, width); - let value_type = Integer::new(width); - if value_type.width == width { - let put_u = format_ident!("put_u{}{}", width, suffix); - quote! { - #span.#put_u(#value) - } - } else { - let put_uint = format_ident!("put_uint{}", suffix); - let value_nbytes = proc_macro2::Literal::usize_unsuffixed(width / 8); - let cast = (value_type.width < 64).then(|| quote!(as u64)); - quote! { - #span.#put_uint(#value #cast, #value_nbytes) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_integer_new() { - assert_eq!(Integer::new(0).width, 8); - assert_eq!(Integer::new(8).width, 8); - assert_eq!(Integer::new(9).width, 16); - assert_eq!(Integer::new(64).width, 64); - } - - #[test] - #[should_panic] - fn test_integer_new_panics_on_large_width() { - Integer::new(65); - } -} diff --git a/tools/pdl/src/backends/rust_no_allocation/computed_values.rs b/tools/pdl/src/backends/rust_no_allocation/computed_values.rs deleted file mode 100644 index 37ef6550f4a87d6f899f379a19a2ce974afdf96d..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust_no_allocation/computed_values.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use proc_macro2::{Ident, TokenStream}; -use quote::{format_ident, quote}; - -use crate::backends::intermediate::{ - ComputedOffset, ComputedOffsetId, ComputedValue, ComputedValueId, -}; - -/// This trait is implemented on computed quantities (offsets and values) that can be retrieved via a function call -pub trait Declarable { - fn get_name(&self) -> String; - - fn get_ident(&self) -> Ident { - format_ident!("try_get_{}", self.get_name()) - } - - fn call_fn(&self) -> TokenStream { - let fn_name = self.get_ident(); - quote! { self.#fn_name()? } - } - - fn declare_fn(&self, body: TokenStream) -> TokenStream { - let fn_name = self.get_ident(); - quote! { - #[inline] - fn #fn_name(&self) -> Result { - #body - } - } - } -} - -impl Declarable for ComputedValueId<'_> { - fn get_name(&self) -> String { - match self { - ComputedValueId::FieldSize(field) => format!("{field}_size"), - ComputedValueId::FieldElementSize(field) => format!("{field}_element_size"), - ComputedValueId::FieldCount(field) => format!("{field}_count"), - ComputedValueId::Custom(i) => format!("custom_value_{i}"), - } - } -} - -impl Declarable for ComputedOffsetId<'_> { - fn get_name(&self) -> String { - match self { - ComputedOffsetId::HeaderStart => "header_start_offset".to_string(), - ComputedOffsetId::PacketEnd => "packet_end_offset".to_string(), - ComputedOffsetId::FieldOffset(field) => format!("{field}_offset"), - ComputedOffsetId::FieldEndOffset(field) => format!("{field}_end_offset"), - ComputedOffsetId::Custom(i) => format!("custom_offset_{i}"), - ComputedOffsetId::TrailerStart => "trailer_start_offset".to_string(), - } - } -} - -/// This trait is implemented on computed expressions that are computed on-demand (i.e. not via a function call) -pub trait Computable { - fn compute(&self) -> TokenStream; -} - -impl Computable for ComputedValue<'_> { - fn compute(&self) -> TokenStream { - match self { - ComputedValue::Constant(k) => quote! { Ok(#k) }, - ComputedValue::CountStructsUpToSize { base_id, size, struct_type } => { - let base_offset = base_id.call_fn(); - let size = size.call_fn(); - let struct_type = format_ident!("{struct_type}View"); - quote! { - let mut cnt = 0; - let mut view = self.buf.offset(#base_offset)?; - let mut remaining_size = #size; - while remaining_size > 0 { - let next_struct_size = #struct_type::try_parse(view)?.try_get_size()?; - if next_struct_size > remaining_size { - return Err(ParseError::OutOfBoundsAccess); - } - remaining_size -= next_struct_size; - view = view.offset(next_struct_size * 8)?; - cnt += 1; - } - Ok(cnt) - } - } - ComputedValue::SizeOfNStructs { base_id, n, struct_type } => { - let base_offset = base_id.call_fn(); - let n = n.call_fn(); - let struct_type = format_ident!("{struct_type}View"); - quote! { - let mut view = self.buf.offset(#base_offset)?; - let mut size = 0; - for _ in 0..#n { - let next_struct_size = #struct_type::try_parse(view)?.try_get_size()?; - size += next_struct_size; - view = view.offset(next_struct_size * 8)?; - } - Ok(size) - } - } - ComputedValue::Product(x, y) => { - let x = x.call_fn(); - let y = y.call_fn(); - quote! { #x.checked_mul(#y).ok_or(ParseError::ArithmeticOverflow) } - } - ComputedValue::Divide(x, y) => { - let x = x.call_fn(); - let y = y.call_fn(); - quote! { - if #y == 0 || #x % #y != 0 { - return Err(ParseError::DivisionFailure) - } - Ok(#x / #y) - } - } - ComputedValue::Difference(x, y) => { - let x = x.call_fn(); - let y = y.call_fn(); - quote! { - let bit_difference = #x.checked_sub(#y).ok_or(ParseError::ArithmeticOverflow)?; - if bit_difference % 8 != 0 { - return Err(ParseError::DivisionFailure); - } - Ok(bit_difference / 8) - } - } - ComputedValue::ValueAt { offset, width } => { - let offset = offset.call_fn(); - quote! { self.buf.offset(#offset)?.slice(#width)?.try_parse() } - } - } - } -} - -impl Computable for ComputedOffset<'_> { - fn compute(&self) -> TokenStream { - match self { - ComputedOffset::ConstantPlusOffsetInBits(base_id, offset) => { - let base_id = base_id.call_fn(); - quote! { #base_id.checked_add_signed(#offset as isize).ok_or(ParseError::ArithmeticOverflow) } - } - ComputedOffset::SumWithOctets(x, y) => { - let x = x.call_fn(); - let y = y.call_fn(); - quote! { - #x.checked_add(#y.checked_mul(8).ok_or(ParseError::ArithmeticOverflow)?) - .ok_or(ParseError::ArithmeticOverflow) - } - } - ComputedOffset::Alias(alias) => { - let alias = alias.call_fn(); - quote! { Ok(#alias) } - } - } - } -} diff --git a/tools/pdl/src/backends/rust_no_allocation/enums.rs b/tools/pdl/src/backends/rust_no_allocation/enums.rs deleted file mode 100644 index 663566a8489e5e1b6d3e1b2ec65c445239c4d8bf..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust_no_allocation/enums.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use proc_macro2::{Literal, TokenStream}; -use quote::{format_ident, quote}; - -use crate::ast; - -use super::utils::get_integer_type; - -pub fn generate_enum(id: &str, tags: &[ast::Tag], width: usize) -> TokenStream { - let id_ident = format_ident!("{id}"); - let tag_ids = tags.iter().map(|tag| format_ident!("{}", tag.id())).collect::>(); - let tag_values = tags - .iter() - .map(|tag| Literal::u64_unsuffixed(tag.value().unwrap() as u64)) - .collect::>(); - let backing_ident = get_integer_type(width); - - quote! { - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - pub enum #id_ident { - #(#tag_ids),* - } - - impl #id_ident { - pub fn new(value: #backing_ident) -> Result { - match value { - #(#tag_values => Ok(Self::#tag_ids)),*, - _ => Err(ParseError::InvalidEnumValue), - } - } - - pub fn value(&self) -> #backing_ident { - match self { - #(Self::#tag_ids => #tag_values),*, - } - } - - fn try_parse(buf: BitSlice) -> Result { - let value = buf.slice(#width)?.try_parse()?; - match value { - #(#tag_values => Ok(Self::#tag_ids)),*, - _ => Err(ParseError::InvalidEnumValue), - } - } - } - - impl Serializable for #id_ident { - fn serialize(&self, writer: &mut impl BitWriter) -> Result<(), SerializeError> { - writer.write_bits(#width, || Ok(self.value())); - Ok(()) - } - } - - impl From<#id_ident> for #backing_ident { - fn from(x: #id_ident) -> #backing_ident { - x.value() - } - } - - impl TryFrom<#backing_ident> for #id_ident { - type Error = ParseError; - - fn try_from(value: #backing_ident) -> Result { - Self::new(value) - } - } - } -} diff --git a/tools/pdl/src/backends/rust_no_allocation/mod.rs b/tools/pdl/src/backends/rust_no_allocation/mod.rs deleted file mode 100644 index 858526f529ab2c9d86a2ed24dab37f0b77105167..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust_no_allocation/mod.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -//! Rust no-allocation backend -//! -//! The motivation for this backend is to be a more "idiomatic" backend than -//! the existing backend. Specifically, it should -//! 1. Use lifetimes, not reference counting -//! 2. Avoid expensive memory copies unless needed -//! 3. Use the intermediate Schema rather than doing all the logic from scratch -//! -//! One notable consequence is that we avoid .specialize(), as it has "magic" behavior -//! not defined in the spec. Instead we mimic the C++ approach of calling tryParse() and -//! getting a Result<> back. - -mod computed_values; -mod enums; -mod packet_parser; -mod packet_serializer; -pub mod test; -mod utils; - -use std::collections::HashMap; - -use proc_macro2::TokenStream; -use quote::quote; - -use crate::ast; -use crate::parser; - -use self::{ - enums::generate_enum, packet_parser::generate_packet, - packet_serializer::generate_packet_serializer, -}; - -use super::intermediate::Schema; - -pub fn generate(file: &parser::ast::File, schema: &Schema) -> Result { - match file.endianness.value { - ast::EndiannessValue::LittleEndian => {} - _ => unimplemented!("Only little_endian endianness supported"), - }; - - let mut out = String::new(); - - out.push_str(include_str!("preamble.rs")); - - let mut children = HashMap::<&str, Vec<&str>>::new(); - for decl in &file.declarations { - match &decl.desc { - ast::DeclDesc::Packet { id, parent_id: Some(parent_id), .. } - | ast::DeclDesc::Struct { id, parent_id: Some(parent_id), .. } => { - children.entry(parent_id.as_str()).or_default().push(id.as_str()); - } - _ => {} - } - } - - let declarations = file - .declarations - .iter() - .map(|decl| generate_decl(decl, schema, &children)) - .collect::>()?; - - out.push_str( - "e! { - #declarations - } - .to_string(), - ); - - Ok(out) -} - -fn generate_decl( - decl: &parser::ast::Decl, - schema: &Schema, - children: &HashMap<&str, Vec<&str>>, -) -> Result { - match &decl.desc { - ast::DeclDesc::Enum { id, tags, width, .. } => Ok(generate_enum(id, tags, *width)), - ast::DeclDesc::Packet { id, fields, parent_id, .. } - | ast::DeclDesc::Struct { id, fields, parent_id, .. } => { - let parser = generate_packet( - id, - fields, - parent_id.as_deref(), - schema, - &schema.packets_and_structs[id.as_str()], - )?; - let serializer = generate_packet_serializer( - id, - parent_id.as_deref(), - fields, - schema, - &schema.packets_and_structs[id.as_str()], - children, - ); - Ok(quote! { - #parser - #serializer - }) - } - _ => unimplemented!("Unsupported decl type"), - } -} diff --git a/tools/pdl/src/backends/rust_no_allocation/packet_parser.rs b/tools/pdl/src/backends/rust_no_allocation/packet_parser.rs deleted file mode 100644 index 44342fb80fcd05ac87a44589c7afcd21c7bb310a..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust_no_allocation/packet_parser.rs +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use std::iter::empty; - -use proc_macro2::TokenStream; -use quote::{format_ident, quote}; - -use crate::ast; -use crate::parser; - -use crate::backends::intermediate::{ - ComputedOffsetId, ComputedValueId, PacketOrStruct, PacketOrStructLength, Schema, -}; - -use super::computed_values::{Computable, Declarable}; -use super::utils::get_integer_type; - -pub fn generate_packet( - id: &str, - fields: &[parser::ast::Field], - parent_id: Option<&str>, - schema: &Schema, - curr_schema: &PacketOrStruct, -) -> Result { - let id_ident = format_ident!("{id}View"); - - let needs_external = matches!(curr_schema.length, PacketOrStructLength::NeedsExternal); - - let length_getter = if needs_external { - ComputedOffsetId::PacketEnd.declare_fn(quote! { Ok(self.buf.get_size_in_bits()) }) - } else { - quote! {} - }; - - let computed_getters = empty() - .chain( - curr_schema.computed_offsets.iter().map(|(decl, defn)| decl.declare_fn(defn.compute())), - ) - .chain( - curr_schema.computed_values.iter().map(|(decl, defn)| decl.declare_fn(defn.compute())), - ); - - let field_getters = fields.iter().map(|field| { - match &field.desc { - ast::FieldDesc::Padding { .. } - | ast::FieldDesc::Reserved { .. } - | ast::FieldDesc::FixedScalar { .. } - | ast::FieldDesc::FixedEnum { .. } - | ast::FieldDesc::ElementSize { .. } - | ast::FieldDesc::Count { .. } - | ast::FieldDesc::Size { .. } => { - // no-op, no getter generated for this type - quote! {} - } - ast::FieldDesc::Group { .. } => unreachable!(), - ast::FieldDesc::Checksum { .. } => { - unimplemented!("checksums not yet supported with this backend") - } - ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body => { - let name = if matches!(field.desc, ast::FieldDesc::Payload { .. }) { "_payload_"} else { "_body_"}; - let payload_start_offset = ComputedOffsetId::FieldOffset(name).call_fn(); - let payload_end_offset = ComputedOffsetId::FieldEndOffset(name).call_fn(); - quote! { - fn try_get_payload(&self) -> Result, ParseError> { - let payload_start_offset = #payload_start_offset; - let payload_end_offset = #payload_end_offset; - self.buf.offset(payload_start_offset)?.slice(payload_end_offset - payload_start_offset) - } - - fn try_get_raw_payload(&self) -> Result> + '_, ParseError> { - let view = self.try_get_payload()?; - let count = (view.get_size_in_bits() + 7) / 8; - Ok((0..count).map(move |i| Ok(view.offset(i*8)?.slice(8.min(view.get_size_in_bits() - i*8))?.try_parse()?))) - } - - pub fn get_raw_payload(&self) -> impl Iterator + '_ { - self.try_get_raw_payload().unwrap().map(|x| x.unwrap()) - } - } - } - ast::FieldDesc::Array { id, width, type_id, .. } => { - let (elem_type, return_type) = if let Some(width) = width { - let ident = get_integer_type(*width); - (ident.clone(), quote!{ #ident }) - } else if let Some(type_id) = type_id { - if schema.enums.contains_key(type_id.as_str()) { - let ident = format_ident!("{}", type_id); - (ident.clone(), quote! { #ident }) - } else { - let ident = format_ident!("{}View", type_id); - (ident.clone(), quote! { #ident<'a> }) - } - } else { - unreachable!() - }; - - let try_getter_name = format_ident!("try_get_{id}_iter"); - let getter_name = format_ident!("get_{id}_iter"); - - let start_offset = ComputedOffsetId::FieldOffset(id).call_fn(); - let count = ComputedValueId::FieldCount(id).call_fn(); - - let element_size_known = curr_schema - .computed_values - .contains_key(&ComputedValueId::FieldElementSize(id)); - - let body = if element_size_known { - let element_size = ComputedValueId::FieldElementSize(id).call_fn(); - let parsed_curr_view = if width.is_some() { - quote! { curr_view.try_parse() } - } else { - quote! { #elem_type::try_parse(curr_view.into()) } - }; - quote! { - let view = self.buf.offset(#start_offset)?; - let count = #count; - let element_size = #element_size; - Ok((0..count).map(move |i| { - let curr_view = view.offset(element_size.checked_mul(i * 8).ok_or(ParseError::ArithmeticOverflow)?)? - .slice(element_size.checked_mul(8).ok_or(ParseError::ArithmeticOverflow)?)?; - #parsed_curr_view - })) - } - } else { - quote! { - let mut view = self.buf.offset(#start_offset)?; - let count = #count; - Ok((0..count).map(move |i| { - let parsed = #elem_type::try_parse(view.into())?; - view = view.offset(parsed.try_get_size()? * 8)?; - Ok(parsed) - })) - } - }; - - quote! { - fn #try_getter_name(&self) -> Result> + 'a, ParseError> { - #body - } - - #[inline] - pub fn #getter_name(&self) -> impl Iterator + 'a { - self.#try_getter_name().unwrap().map(|x| x.unwrap()) - } - } - } - ast::FieldDesc::Scalar { id, width } => { - let try_getter_name = format_ident!("try_get_{id}"); - let getter_name = format_ident!("get_{id}"); - let offset = ComputedOffsetId::FieldOffset(id).call_fn(); - let scalar_type = get_integer_type(*width); - quote! { - fn #try_getter_name(&self) -> Result<#scalar_type, ParseError> { - self.buf.offset(#offset)?.slice(#width)?.try_parse() - } - - #[inline] - pub fn #getter_name(&self) -> #scalar_type { - self.#try_getter_name().unwrap() - } - } - } - ast::FieldDesc::Typedef { id, type_id } => { - let try_getter_name = format_ident!("try_get_{id}"); - let getter_name = format_ident!("get_{id}"); - - let (type_ident, return_type) = if schema.enums.contains_key(type_id.as_str()) { - let ident = format_ident!("{type_id}"); - (ident.clone(), quote! { #ident }) - } else { - let ident = format_ident!("{}View", type_id); - (ident.clone(), quote! { #ident<'a> }) - }; - let offset = ComputedOffsetId::FieldOffset(id).call_fn(); - let end_offset_known = curr_schema - .computed_offsets - .contains_key(&ComputedOffsetId::FieldEndOffset(id)); - let sliced_view = if end_offset_known { - let end_offset = ComputedOffsetId::FieldEndOffset(id).call_fn(); - quote! { self.buf.offset(#offset)?.slice(#end_offset.checked_sub(#offset).ok_or(ParseError::ArithmeticOverflow)?)? } - } else { - quote! { self.buf.offset(#offset)? } - }; - - quote! { - fn #try_getter_name(&self) -> Result<#return_type, ParseError> { - #type_ident::try_parse(#sliced_view.into()) - } - - #[inline] - pub fn #getter_name(&self) -> #return_type { - self.#try_getter_name().unwrap() - } - } - } - } - }); - - let backing_buffer = if needs_external { - quote! { SizedBitSlice<'a> } - } else { - quote! { BitSlice<'a> } - }; - - let parent_ident = match parent_id { - Some(parent) => format_ident!("{parent}View"), - None => match curr_schema.length { - PacketOrStructLength::Static(_) => format_ident!("BitSlice"), - PacketOrStructLength::Dynamic => format_ident!("BitSlice"), - PacketOrStructLength::NeedsExternal => format_ident!("SizedBitSlice"), - }, - }; - - let buffer_extractor = if parent_id.is_some() { - quote! { parent.try_get_payload().unwrap().into() } - } else { - quote! { parent } - }; - - let field_validators = fields.iter().map(|field| match &field.desc { - ast::FieldDesc::Checksum { .. } => unimplemented!(), - ast::FieldDesc::Group { .. } => unreachable!(), - ast::FieldDesc::Padding { .. } - | ast::FieldDesc::Size { .. } - | ast::FieldDesc::Count { .. } - | ast::FieldDesc::ElementSize { .. } - | ast::FieldDesc::Body - | ast::FieldDesc::FixedScalar { .. } - | ast::FieldDesc::FixedEnum { .. } - | ast::FieldDesc::Reserved { .. } => { - quote! {} - } - ast::FieldDesc::Payload { .. } => { - quote! { - self.try_get_payload()?; - self.try_get_raw_payload()?; - } - } - ast::FieldDesc::Array { id, .. } => { - let iter_ident = format_ident!("try_get_{id}_iter"); - quote! { - for elem in self.#iter_ident()? { - elem?; - } - } - } - ast::FieldDesc::Scalar { id, .. } | ast::FieldDesc::Typedef { id, .. } => { - let getter_ident = format_ident!("try_get_{id}"); - quote! { self.#getter_ident()?; } - } - }); - - let packet_end_offset = ComputedOffsetId::PacketEnd.call_fn(); - - let owned_id_ident = format_ident!("Owned{id_ident}"); - let builder_ident = format_ident!("{id}Builder"); - - Ok(quote! { - #[derive(Clone, Copy, Debug)] - pub struct #id_ident<'a> { - buf: #backing_buffer, - } - - impl<'a> #id_ident<'a> { - #length_getter - - #(#computed_getters)* - - #(#field_getters)* - - #[inline] - fn try_get_header_start_offset(&self) -> Result { - Ok(0) - } - - #[inline] - fn try_get_size(&self) -> Result { - let size = #packet_end_offset; - if size % 8 != 0 { - return Err(ParseError::MisalignedPayload); - } - Ok(size / 8) - } - - fn validate(&self) -> Result<(), ParseError> { - #(#field_validators)* - Ok(()) - } - } - - impl<'a> Packet<'a> for #id_ident<'a> { - type Parent = #parent_ident<'a>; - type Owned = #owned_id_ident; - type Builder = #builder_ident; - - fn try_parse_from_buffer(buf: impl Into>) -> Result { - let out = Self { buf: buf.into().into() }; - out.validate()?; - Ok(out) - } - - fn try_parse(parent: #parent_ident<'a>) -> Result { - let out = Self { buf: #buffer_extractor }; - out.validate()?; - Ok(out) - } - - fn to_owned_packet(&self) -> #owned_id_ident { - #owned_id_ident { - buf: self.buf.backing.to_owned().into(), - start_bit_offset: self.buf.start_bit_offset, - end_bit_offset: self.buf.end_bit_offset, - } - } - } - - #[derive(Debug)] - pub struct #owned_id_ident { - buf: Box<[u8]>, - start_bit_offset: usize, - end_bit_offset: usize, - } - - impl OwnedPacket for #owned_id_ident { - fn try_parse(buf: Box<[u8]>) -> Result { - #id_ident::try_parse_from_buffer(&buf[..])?; - let end_bit_offset = buf.len() * 8; - Ok(Self { buf, start_bit_offset: 0, end_bit_offset }) - } - } - - impl #owned_id_ident { - pub fn view<'a>(&'a self) -> #id_ident<'a> { - #id_ident { - buf: SizedBitSlice(BitSlice { - backing: &self.buf[..], - start_bit_offset: self.start_bit_offset, - end_bit_offset: self.end_bit_offset, - }) - .into(), - } - } - } - - impl<'a> From<&'a #owned_id_ident> for #id_ident<'a> { - fn from(x: &'a #owned_id_ident) -> Self { - x.view() - } - } - }) -} diff --git a/tools/pdl/src/backends/rust_no_allocation/packet_serializer.rs b/tools/pdl/src/backends/rust_no_allocation/packet_serializer.rs deleted file mode 100644 index 9ecae381d3b1adf764c1d753a05a535f93da5854..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust_no_allocation/packet_serializer.rs +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use std::collections::HashMap; - -use proc_macro2::TokenStream; -use quote::{format_ident, quote}; - -use crate::{ - ast, - backends::{ - intermediate::{ComputedValue, ComputedValueId, PacketOrStruct, Schema}, - rust_no_allocation::utils::get_integer_type, - }, - parser, -}; - -fn standardize_child(id: &str) -> &str { - match id { - "_body_" | "_payload_" => "_child_", - _ => id, - } -} - -pub fn generate_packet_serializer( - id: &str, - parent_id: Option<&str>, - fields: &[parser::ast::Field], - schema: &Schema, - curr_schema: &PacketOrStruct, - children: &HashMap<&str, Vec<&str>>, -) -> TokenStream { - let id_ident = format_ident!("{id}Builder"); - - let builder_fields = fields - .iter() - .filter_map(|field| { - match &field.desc { - ast::FieldDesc::Padding { .. } - | ast::FieldDesc::Reserved { .. } - | ast::FieldDesc::FixedScalar { .. } - | ast::FieldDesc::FixedEnum { .. } - | ast::FieldDesc::ElementSize { .. } - | ast::FieldDesc::Count { .. } - | ast::FieldDesc::Size { .. } => { - // no-op, no getter generated for this type - None - } - ast::FieldDesc::Group { .. } => unreachable!(), - ast::FieldDesc::Checksum { .. } => { - unimplemented!("checksums not yet supported with this backend") - } - ast::FieldDesc::Body | ast::FieldDesc::Payload { .. } => { - let type_ident = format_ident!("{id}Child"); - Some(("_child_", quote! { #type_ident })) - } - ast::FieldDesc::Array { id, width, type_id, .. } => { - let element_type = if let Some(width) = width { - get_integer_type(*width) - } else if let Some(type_id) = type_id { - if schema.enums.contains_key(type_id.as_str()) { - format_ident!("{type_id}") - } else { - format_ident!("{type_id}Builder") - } - } else { - unreachable!(); - }; - Some((id.as_str(), quote! { Box<[#element_type]> })) - } - ast::FieldDesc::Scalar { id, width } => { - let id_type = get_integer_type(*width); - Some((id.as_str(), quote! { #id_type })) - } - ast::FieldDesc::Typedef { id, type_id } => { - let type_ident = if schema.enums.contains_key(type_id.as_str()) { - format_ident!("{type_id}") - } else { - format_ident!("{type_id}Builder") - }; - Some((id.as_str(), quote! { #type_ident })) - } - } - }) - .map(|(id, typ)| { - let id_ident = format_ident!("{id}"); - quote! { pub #id_ident: #typ } - }); - - let mut has_child = false; - - let serializer = fields.iter().map(|field| { - match &field.desc { - ast::FieldDesc::Checksum { .. } | ast::FieldDesc::Group { .. } => unimplemented!(), - ast::FieldDesc::Padding { size, .. } => { - quote! { - if (most_recent_array_size_in_bits > #size * 8) { - return Err(SerializeError::NegativePadding); - } - writer.write_bits((#size * 8 - most_recent_array_size_in_bits) as usize, || Ok(0u64))?; - } - }, - ast::FieldDesc::Size { field_id, width } => { - let field_id = standardize_child(field_id); - let field_ident = format_ident!("{field_id}"); - - // if the element-size is fixed, we can directly multiply - if let Some(ComputedValue::Constant(element_width)) = curr_schema.computed_values.get(&ComputedValueId::FieldElementSize(field_id)) { - return quote! { - writer.write_bits( - #width, - || u64::try_from(self.#field_ident.len() * #element_width).or(Err(SerializeError::IntegerConversionFailure)) - )?; - } - } - - // if the field is "countable", loop over it to sum up the size - if curr_schema.computed_values.contains_key(&ComputedValueId::FieldCount(field_id)) { - return quote! { - writer.write_bits(#width, || { - let size_in_bits = self.#field_ident.iter().map(|elem| elem.size_in_bits()).fold(Ok(0), |total, next| { - let total: u64 = total?; - let next = u64::try_from(next?).or(Err(SerializeError::IntegerConversionFailure))?; - total.checked_add(next).ok_or(SerializeError::IntegerConversionFailure) - })?; - if size_in_bits % 8 != 0 { - return Err(SerializeError::AlignmentError); - } - Ok(size_in_bits / 8) - })?; - } - } - - // otherwise, try to get the size directly - quote! { - writer.write_bits(#width, || { - let size_in_bits: u64 = self.#field_ident.size_in_bits()?.try_into().or(Err(SerializeError::IntegerConversionFailure))?; - if size_in_bits % 8 != 0 { - return Err(SerializeError::AlignmentError); - } - Ok(size_in_bits / 8) - })?; - } - } - ast::FieldDesc::Count { field_id, width } => { - let field_ident = format_ident!("{field_id}"); - quote! { writer.write_bits(#width, || u64::try_from(self.#field_ident.len()).or(Err(SerializeError::IntegerConversionFailure)))?; } - } - ast::FieldDesc::ElementSize { field_id, width } => { - // TODO(aryarahul) - add validation for elementsize against all the other elements - let field_ident = format_ident!("{field_id}"); - quote! { - let get_element_size = || Ok(if let Some(field) = self.#field_ident.get(0) { - let size_in_bits = field.size_in_bits()?; - if size_in_bits % 8 == 0 { - (size_in_bits / 8) as u64 - } else { - return Err(SerializeError::AlignmentError); - } - } else { - 0 - }); - writer.write_bits(#width, || get_element_size() )?; - } - } - ast::FieldDesc::Reserved { width, .. } => { - quote!{ writer.write_bits(#width, || Ok(0u64))?; } - } - ast::FieldDesc::Scalar { width, id } => { - let field_ident = format_ident!("{id}"); - quote! { writer.write_bits(#width, || Ok(self.#field_ident))?; } - } - ast::FieldDesc::FixedScalar { width, value } => { - let width = quote! { #width }; - let value = { - let value = *value as u64; - quote! { #value } - }; - quote!{ writer.write_bits(#width, || Ok(#value))?; } - } - ast::FieldDesc::FixedEnum { enum_id, tag_id } => { - let width = { - let width = schema.enums[enum_id.as_str()].width; - quote! { #width } - }; - let value = { - let enum_ident = format_ident!("{}", enum_id); - let tag_ident = format_ident!("{tag_id}"); - quote! { #enum_ident::#tag_ident.value() } - }; - quote!{ writer.write_bits(#width, || Ok(#value))?; } - } - ast::FieldDesc::Body | ast::FieldDesc::Payload { .. } => { - has_child = true; - quote! { self._child_.serialize(writer)?; } - } - ast::FieldDesc::Array { width, id, .. } => { - let id_ident = format_ident!("{id}"); - if let Some(width) = width { - quote! { - for elem in self.#id_ident.iter() { - writer.write_bits(#width, || Ok(*elem))?; - } - let most_recent_array_size_in_bits = #width * self.#id_ident.len(); - } - } else { - quote! { - let mut most_recent_array_size_in_bits = 0; - for elem in self.#id_ident.iter() { - most_recent_array_size_in_bits += elem.size_in_bits()?; - elem.serialize(writer)?; - } - } - } - } - ast::FieldDesc::Typedef { id, .. } => { - let id_ident = format_ident!("{id}"); - quote! { self.#id_ident.serialize(writer)?; } - } - } - }).collect::>(); - - let variant_names = children.get(id).into_iter().flatten().collect::>(); - - let variants = variant_names.iter().map(|name| { - let name_ident = format_ident!("{name}"); - let variant_ident = format_ident!("{name}Builder"); - quote! { #name_ident(#variant_ident) } - }); - - let variant_serializers = variant_names.iter().map(|name| { - let name_ident = format_ident!("{name}"); - quote! { - Self::#name_ident(x) => { - x.serialize(writer)?; - } - } - }); - - let children_enum = if has_child { - let enum_ident = format_ident!("{id}Child"); - quote! { - #[derive(Debug, Clone, PartialEq, Eq)] - pub enum #enum_ident { - RawData(Box<[u8]>), - #(#variants),* - } - - impl Serializable for #enum_ident { - fn serialize(&self, writer: &mut impl BitWriter) -> Result<(), SerializeError> { - match self { - Self::RawData(data) => { - for byte in data.iter() { - writer.write_bits(8, || Ok(*byte as u64))?; - } - }, - #(#variant_serializers),* - } - Ok(()) - } - } - } - } else { - quote! {} - }; - - let parent_type_converter = if let Some(parent_id) = parent_id { - let parent_enum_ident = format_ident!("{parent_id}Child"); - let variant_ident = format_ident!("{id}"); - Some(quote! { - impl From<#id_ident> for #parent_enum_ident { - fn from(x: #id_ident) -> Self { - Self::#variant_ident(x) - } - } - }) - } else { - None - }; - - let owned_packet_ident = format_ident!("Owned{id}View"); - - quote! { - #[derive(Debug, Clone, PartialEq, Eq)] - pub struct #id_ident { - #(#builder_fields),* - } - - impl Builder for #id_ident { - type OwnedPacket = #owned_packet_ident; - } - - impl Serializable for #id_ident { - fn serialize(&self, writer: &mut impl BitWriter) -> Result<(), SerializeError> { - #(#serializer)* - Ok(()) - } - } - - #parent_type_converter - - #children_enum - } -} diff --git a/tools/pdl/src/backends/rust_no_allocation/preamble.rs b/tools/pdl/src/backends/rust_no_allocation/preamble.rs deleted file mode 100644 index 30f8486b2003573cd22e30f30123535b67c23885..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust_no_allocation/preamble.rs +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use std::convert::TryFrom; -use std::convert::TryInto; -use std::ops::Deref; - -#[derive(Debug)] -pub enum ParseError { - InvalidEnumValue, - DivisionFailure, - ArithmeticOverflow, - OutOfBoundsAccess, - MisalignedPayload, -} - -#[derive(Clone, Copy, Debug)] -pub struct BitSlice<'a> { - // note: the offsets are ENTIRELY UNRELATED to the size of this struct, - // so indexing needs to be checked to avoid panics - backing: &'a [u8], - - // invariant: end_bit_offset >= start_bit_offset, so subtraction will NEVER wrap - start_bit_offset: usize, - end_bit_offset: usize, -} - -#[derive(Clone, Copy, Debug)] -pub struct SizedBitSlice<'a>(BitSlice<'a>); - -impl<'a> BitSlice<'a> { - pub fn offset(&self, offset: usize) -> Result, ParseError> { - if self.end_bit_offset - self.start_bit_offset < offset { - return Err(ParseError::OutOfBoundsAccess); - } - Ok(Self { - backing: self.backing, - start_bit_offset: self - .start_bit_offset - .checked_add(offset) - .ok_or(ParseError::ArithmeticOverflow)?, - end_bit_offset: self.end_bit_offset, - }) - } - - pub fn slice(&self, len: usize) -> Result, ParseError> { - if self.end_bit_offset - self.start_bit_offset < len { - return Err(ParseError::OutOfBoundsAccess); - } - Ok(SizedBitSlice(Self { - backing: self.backing, - start_bit_offset: self.start_bit_offset, - end_bit_offset: self - .start_bit_offset - .checked_add(len) - .ok_or(ParseError::ArithmeticOverflow)?, - })) - } - - fn byte_at(&self, index: usize) -> Result { - self.backing.get(index).ok_or(ParseError::OutOfBoundsAccess).copied() - } -} - -impl<'a> Deref for SizedBitSlice<'a> { - type Target = BitSlice<'a>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<'a> From> for BitSlice<'a> { - fn from(x: SizedBitSlice<'a>) -> Self { - *x - } -} - -impl<'a, 'b> From<&'b [u8]> for SizedBitSlice<'a> -where - 'b: 'a, -{ - fn from(backing: &'a [u8]) -> Self { - Self(BitSlice { backing, start_bit_offset: 0, end_bit_offset: backing.len() * 8 }) - } -} - -impl<'a> SizedBitSlice<'a> { - pub fn try_parse>(&self) -> Result { - if self.end_bit_offset < self.start_bit_offset { - return Err(ParseError::OutOfBoundsAccess); - } - let size_in_bits = self.end_bit_offset - self.start_bit_offset; - - // fields that fit into a u64 don't need to be byte-aligned - if size_in_bits <= 64 { - let mut accumulator = 0u64; - - // where we are in our accumulation - let mut curr_byte_index = self.start_bit_offset / 8; - let mut curr_bit_offset = self.start_bit_offset % 8; - let mut remaining_bits = size_in_bits; - - while remaining_bits > 0 { - // how many bits to take from the current byte? - // check if this is the last byte - if curr_bit_offset + remaining_bits <= 8 { - let tmp = ((self.byte_at(curr_byte_index)? >> curr_bit_offset) as u64) - & ((1u64 << remaining_bits) - 1); - accumulator += tmp << (size_in_bits - remaining_bits); - break; - } else { - // this is not the last byte, so we have 8 - curr_bit_offset bits to - // consume in this byte - let bits_to_consume = 8 - curr_bit_offset; - let tmp = (self.byte_at(curr_byte_index)? >> curr_bit_offset) as u64; - accumulator += tmp << (size_in_bits - remaining_bits); - curr_bit_offset = 0; - curr_byte_index += 1; - remaining_bits -= bits_to_consume as usize; - } - } - T::try_from(accumulator).map_err(|_| ParseError::ArithmeticOverflow) - } else { - return Err(ParseError::MisalignedPayload); - } - } - - pub fn get_size_in_bits(&self) -> usize { - self.end_bit_offset - self.start_bit_offset - } -} - -pub trait Packet<'a> -where - Self: Sized, -{ - type Parent; - type Owned; - type Builder; - fn try_parse_from_buffer(buf: impl Into>) -> Result; - fn try_parse(parent: Self::Parent) -> Result; - fn to_owned_packet(&self) -> Self::Owned; -} - -pub trait OwnedPacket -where - Self: Sized, -{ - // Enable GAT when 1.65 is available in AOSP - // type View<'a> where Self : 'a; - fn try_parse(buf: Box<[u8]>) -> Result; - // fn view<'a>(&'a self) -> Self::View<'a>; -} - -pub trait Builder: Serializable { - type OwnedPacket: OwnedPacket; -} - -#[derive(Debug)] -pub enum SerializeError { - NegativePadding, - IntegerConversionFailure, - ValueTooLarge, - AlignmentError, -} - -pub trait BitWriter { - fn write_bits>( - &mut self, - num_bits: usize, - gen_contents: impl FnOnce() -> Result, - ) -> Result<(), SerializeError>; -} - -pub trait Serializable { - fn serialize(&self, writer: &mut impl BitWriter) -> Result<(), SerializeError>; - - fn size_in_bits(&self) -> Result { - let mut sizer = Sizer::new(); - self.serialize(&mut sizer)?; - Ok(sizer.size()) - } - - fn write(&self, vec: &mut Vec) -> Result<(), SerializeError> { - let mut serializer = Serializer::new(vec); - self.serialize(&mut serializer)?; - serializer.flush(); - Ok(()) - } - - fn to_vec(&self) -> Result, SerializeError> { - let mut out = vec![]; - self.write(&mut out)?; - Ok(out) - } -} - -struct Sizer { - size: usize, -} - -impl Sizer { - fn new() -> Self { - Self { size: 0 } - } - - fn size(self) -> usize { - self.size - } -} - -impl BitWriter for Sizer { - fn write_bits>( - &mut self, - num_bits: usize, - gen_contents: impl FnOnce() -> Result, - ) -> Result<(), SerializeError> { - self.size += num_bits; - Ok(()) - } -} - -struct Serializer<'a> { - buf: &'a mut Vec, - curr_byte: u8, - curr_bit_offset: u8, -} - -impl<'a> Serializer<'a> { - fn new(buf: &'a mut Vec) -> Self { - Self { buf, curr_byte: 0, curr_bit_offset: 0 } - } - - fn flush(self) { - if self.curr_bit_offset > 0 { - // partial byte remaining - self.buf.push(self.curr_byte << (8 - self.curr_bit_offset)); - } - } -} - -impl<'a> BitWriter for Serializer<'a> { - fn write_bits>( - &mut self, - num_bits: usize, - gen_contents: impl FnOnce() -> Result, - ) -> Result<(), SerializeError> { - let val = gen_contents()?.into(); - - if num_bits < 64 && val >= 1 << num_bits { - return Err(SerializeError::ValueTooLarge); - } - - let mut remaining_val = val; - let mut remaining_bits = num_bits; - while remaining_bits > 0 { - let remaining_bits_in_curr_byte = (8 - self.curr_bit_offset) as usize; - if remaining_bits < remaining_bits_in_curr_byte { - // we cannot finish the last byte - self.curr_byte += (remaining_val as u8) << self.curr_bit_offset; - self.curr_bit_offset += remaining_bits as u8; - break; - } else { - // finish up our current byte and move on - let val_for_this_byte = - (remaining_val & ((1 << remaining_bits_in_curr_byte) - 1)) as u8; - let curr_byte = self.curr_byte + (val_for_this_byte << self.curr_bit_offset); - self.buf.push(curr_byte); - - // clear pending byte - self.curr_bit_offset = 0; - self.curr_byte = 0; - - // update what's remaining - remaining_val >>= remaining_bits_in_curr_byte; - remaining_bits -= remaining_bits_in_curr_byte; - } - } - - Ok(()) - } -} diff --git a/tools/pdl/src/backends/rust_no_allocation/test.rs b/tools/pdl/src/backends/rust_no_allocation/test.rs deleted file mode 100644 index 18aa82be6ec300a76d80ed7d919f64f97e46c2de..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust_no_allocation/test.rs +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use std::collections::HashMap; - -use proc_macro2::TokenStream; -use quote::{format_ident, quote}; -use serde::Deserialize; - -use crate::{ast, parser::parse_inline, quote_block}; - -#[derive(Deserialize)] -struct PacketTest { - packet: String, - tests: Box<[PacketTestCase]>, -} - -#[derive(Deserialize)] -struct PacketTestCase { - packed: String, - unpacked: UnpackedTestFields, - packet: Option, -} - -#[derive(Deserialize)] -struct UnpackedTestFields(HashMap); - -// fields can be scalars, lists, or structs -#[derive(Deserialize)] -#[serde(untagged)] -enum Field { - Number(usize), - Struct(UnpackedTestFields), - List(Box<[ListEntry]>), -} - -// lists can either contain scalars or structs -#[derive(Deserialize)] -#[serde(untagged)] -enum ListEntry { - Number(usize), - Struct(UnpackedTestFields), -} - -fn generate_matchers( - base: TokenStream, - value: &UnpackedTestFields, - filter_fields: &dyn Fn(&str) -> Result, - curr_type: &str, - type_lookup: &HashMap<&str, HashMap<&str, Option<&str>>>, -) -> Result { - let mut out = vec![]; - - for (field_name, field_value) in value.0.iter() { - if !filter_fields(field_name)? { - continue; - } - let getter_ident = format_ident!("get_{field_name}"); - match field_value { - Field::Number(num) => { - let num = *num as u64; - if let Some(field_type) = type_lookup[curr_type][field_name.as_str()] { - let field_ident = format_ident!("{field_type}"); - out.push(quote! { assert_eq!(#base.#getter_ident(), #field_ident::new(#num as _).unwrap()); }); - } else { - out.push(quote! { assert_eq!(u64::from(#base.#getter_ident()), #num); }); - } - } - Field::List(lst) => { - if field_name == "payload" { - let reference = lst - .iter() - .map(|val| match val { - ListEntry::Number(val) => *val as u8, - _ => unreachable!(), - }) - .collect::>(); - out.push(quote! { - assert_eq!(#base.get_raw_payload().collect::>(), vec![#(#reference),*]); - }) - } else { - let get_iter_ident = format_ident!("get_{field_name}_iter"); - let vec_ident = format_ident!("{field_name}_vec"); - out.push( - quote! { let #vec_ident = #base.#get_iter_ident().collect::>(); }, - ); - - for (i, val) in lst.iter().enumerate() { - let list_elem = quote! { #vec_ident[#i] }; - out.push(match val { - ListEntry::Number(num) => { - if let Some(field_type) = type_lookup[curr_type][field_name.as_str()] { - let field_ident = format_ident!("{field_type}"); - quote! { assert_eq!(#list_elem, #field_ident::new(#num as _).unwrap()); } - } else { - quote! { assert_eq!(u64::from(#list_elem), #num as u64); } - } - } - ListEntry::Struct(fields) => { - generate_matchers(list_elem, fields, &|_| Ok(true), type_lookup[curr_type][field_name.as_str()].unwrap(), type_lookup)? - } - }) - } - } - } - Field::Struct(fields) => { - out.push(generate_matchers( - quote! { #base.#getter_ident() }, - fields, - &|_| Ok(true), - type_lookup[curr_type][field_name.as_str()].unwrap(), - type_lookup, - )?); - } - } - } - Ok(quote! { { #(#out)* } }) -} - -fn generate_builder( - curr_type: &str, - child_type: Option<&str>, - type_lookup: &HashMap<&str, HashMap<&str, Option<&str>>>, - value: &UnpackedTestFields, -) -> TokenStream { - let builder_ident = format_ident!("{curr_type}Builder"); - let child_ident = format_ident!("{curr_type}Child"); - - let curr_fields = &type_lookup[curr_type]; - - let fields = value.0.iter().filter_map(|(field_name, field_value)| { - let curr_field_info = curr_fields.get(field_name.as_str()); - - if let Some(curr_field_info) = curr_field_info { - let field_name_ident = if field_name == "payload" { - format_ident!("_child_") - } else { - format_ident!("{field_name}") - }; - let val = match field_value { - Field::Number(val) => { - if let Some(field) = curr_field_info { - let field_ident = format_ident!("{field}"); - quote! { #field_ident::new(#val as _).unwrap() } - } else { - quote! { (#val as u64).try_into().unwrap() } - } - } - Field::Struct(fields) => { - generate_builder(curr_field_info.unwrap(), None, type_lookup, fields) - } - Field::List(lst) => { - let elems = lst.iter().map(|entry| match entry { - ListEntry::Number(val) => { - if let Some(field) = curr_field_info { - let field_ident = format_ident!("{field}"); - quote! { #field_ident::new(#val as _).unwrap() } - } else { - quote! { (#val as u64).try_into().unwrap() } - } - } - ListEntry::Struct(fields) => { - generate_builder(curr_field_info.unwrap(), None, type_lookup, fields) - } - }); - quote! { vec![#(#elems),*].into_boxed_slice() } - } - }; - - Some(if field_name == "payload" { - quote! { #field_name_ident: #child_ident::RawData(#val) } - } else { - quote! { #field_name_ident: #val } - }) - } else { - None - } - }); - - let child_field = if let Some(child_type) = child_type { - let child_builder = generate_builder(child_type, None, type_lookup, value); - Some(quote! { - _child_: #child_builder.into(), - }) - } else { - None - }; - - quote! { - #builder_ident { - #child_field - #(#fields),* - } - } -} - -pub fn generate_test_file() -> Result { - let mut out = String::new(); - - out.push_str(include_str!("test_preamble.rs")); - - let file = include_str!("../../../tests/canonical/le_test_vectors.json"); - let test_vectors: Box<[_]> = - serde_json::from_str(file).map_err(|_| "could not parse test vectors")?; - - let pdl = include_str!("../../../tests/canonical/le_rust_noalloc_test_file.pdl"); - let ast = parse_inline(&mut ast::SourceDatabase::new(), "test.pdl".to_owned(), pdl.to_owned()) - .expect("could not parse reference PDL"); - let packet_lookup = - ast.declarations - .iter() - .filter_map(|decl| match &decl.desc { - ast::DeclDesc::Packet { id, fields, .. } - | ast::DeclDesc::Struct { id, fields, .. } => Some(( - id.as_str(), - fields - .iter() - .filter_map(|field| match &field.desc { - ast::FieldDesc::Body { .. } | ast::FieldDesc::Payload { .. } => { - Some(("payload", None)) - } - ast::FieldDesc::Array { id, type_id, .. } => match type_id { - Some(type_id) => Some((id.as_str(), Some(type_id.as_str()))), - None => Some((id.as_str(), None)), - }, - ast::FieldDesc::Typedef { id, type_id, .. } => { - Some((id.as_str(), Some(type_id.as_str()))) - } - ast::FieldDesc::Scalar { id, .. } => Some((id.as_str(), None)), - _ => None, - }) - .collect::>(), - )), - _ => None, - }) - .collect::>(); - - for PacketTest { packet, tests } in test_vectors.iter() { - if !pdl.contains(packet) { - // huge brain hack to skip unsupported test vectors - continue; - } - - for (i, PacketTestCase { packed, unpacked, packet: sub_packet }) in tests.iter().enumerate() - { - if let Some(sub_packet) = sub_packet { - if !pdl.contains(sub_packet) { - // huge brain hack to skip unsupported test vectors - continue; - } - } - - let test_name_ident = format_ident!("test_{packet}_{i}"); - let packet_ident = format_ident!("{packet}_instance"); - let packet_view = format_ident!("{packet}View"); - - let mut leaf_packet = packet; - - let specialization = if let Some(sub_packet) = sub_packet { - let sub_packet_ident = format_ident!("{}_instance", sub_packet); - let sub_packet_view_ident = format_ident!("{}View", sub_packet); - - leaf_packet = sub_packet; - quote! { let #sub_packet_ident = #sub_packet_view_ident::try_parse(#packet_ident).unwrap(); } - } else { - quote! {} - }; - - let leaf_packet_ident = format_ident!("{leaf_packet}_instance"); - - let packet_matchers = generate_matchers( - quote! { #packet_ident }, - unpacked, - &|field| { - Ok(packet_lookup - .get(packet.as_str()) - .ok_or(format!("could not find packet {packet}"))? - .contains_key(field)) - }, - packet, - &packet_lookup, - )?; - - let sub_packet_matchers = generate_matchers( - quote! { #leaf_packet_ident }, - unpacked, - &|field| { - Ok(packet_lookup - .get(leaf_packet.as_str()) - .ok_or(format!("could not find packet {packet}"))? - .contains_key(field)) - }, - sub_packet.as_ref().unwrap_or(packet), - &packet_lookup, - )?; - - out.push_str("e_block! { - #[test] - fn #test_name_ident() { - let base = hex_str_to_byte_vector(#packed); - let #packet_ident = #packet_view::try_parse(SizedBitSlice::from(&base[..]).into()).unwrap(); - - #specialization - - #packet_matchers - #sub_packet_matchers - } - }); - - let builder = generate_builder(packet, sub_packet.as_deref(), &packet_lookup, unpacked); - - let test_name_ident = format_ident!("test_{packet}_builder_{i}"); - out.push_str("e_block! { - #[test] - fn #test_name_ident() { - let packed = hex_str_to_byte_vector(#packed); - let serialized = #builder.to_vec().unwrap(); - assert_eq!(packed, serialized); - } - }); - } - } - - Ok(out) -} diff --git a/tools/pdl/src/backends/rust_no_allocation/test_preamble.rs b/tools/pdl/src/backends/rust_no_allocation/test_preamble.rs deleted file mode 100644 index f7c1200062e3f753018eddc37a5bb4117dcf09bc..0000000000000000000000000000000000000000 --- a/tools/pdl/src/backends/rust_no_allocation/test_preamble.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -#![allow(non_snake_case)] -#![allow(non_camel_case_types)] -#![allow(warnings, missing_docs)] -#![allow(clippy::all)] -// this is now stable -#![feature(mixed_integer_ops)] - -include!(concat!(env!("OUT_DIR"), "/_packets.rs")); - -fn hex_to_word(hex: u8) -> u8 { - if b'0' <= hex && hex <= b'9' { - hex - b'0' - } else if b'A' <= hex && hex <= b'F' { - hex - b'A' + 0xa - } else { - hex - b'a' + 0xa - } -} - -fn hex_str_to_byte_vector(hex: &str) -> Vec { - hex.as_bytes() - .chunks_exact(2) - .map(|chunk| hex_to_word(chunk[1]) + (hex_to_word(chunk[0]) << 4)) - .collect() -} diff --git a/tools/pdl/src/bin/generate-canonical-tests.rs b/tools/pdl/src/bin/generate-canonical-tests.rs deleted file mode 100644 index 070cd3c994aa822bfa1604783095ae6cb462cc22..0000000000000000000000000000000000000000 --- a/tools/pdl/src/bin/generate-canonical-tests.rs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -//! Generate Rust unit tests for canonical test vectors. - -use quote::{format_ident, quote}; -use serde::{Deserialize, Serialize}; -use serde_json::Value; - -#[derive(Debug, Deserialize)] -struct Packet { - #[serde(rename = "packet")] - name: String, - tests: Vec, -} - -#[derive(Debug, Deserialize)] -struct TestVector { - packed: String, - unpacked: Value, - packet: Option, -} - -/// Convert a string of hexadecimal characters into a Rust vector of -/// bytes. -/// -/// The string `"80038302"` becomes `vec![0x80, 0x03, 0x83, 0x02]`. -fn hexadecimal_to_vec(hex: &str) -> proc_macro2::TokenStream { - assert!(hex.len() % 2 == 0, "Expects an even number of hex digits"); - let bytes = hex.as_bytes().chunks_exact(2).map(|chunk| { - let number = format!("0x{}", std::str::from_utf8(chunk).unwrap()); - syn::parse_str::(&number).unwrap() - }); - - quote! { - vec![#(#bytes),*] - } -} - -/// Convert `value` to a JSON string literal. -/// -/// The string literal is a raw literal to avoid escaping -/// double-quotes. -fn to_json(value: &T) -> syn::LitStr { - let json = serde_json::to_string(value).unwrap(); - assert!(!json.contains("\"#"), "Please increase number of # for {json:?}"); - syn::parse_str::(&format!("r#\" {json} \"#")).unwrap() -} - -fn generate_unit_tests(input: &str, packet_names: &[&str], module_name: &str) { - eprintln!("Reading test vectors from {input}, will use {} packets", packet_names.len()); - - let data = std::fs::read_to_string(input) - .unwrap_or_else(|err| panic!("Could not read {input}: {err}")); - let packets: Vec = serde_json::from_str(&data).expect("Could not parse JSON"); - - let module = format_ident!("{}", module_name); - let mut tests = Vec::new(); - for packet in &packets { - for (i, test_vector) in packet.tests.iter().enumerate() { - let test_packet = test_vector.packet.as_deref().unwrap_or(packet.name.as_str()); - if !packet_names.contains(&test_packet) { - eprintln!("Skipping packet {}", test_packet); - continue; - } - eprintln!("Generating tests for packet {}", test_packet); - - let parse_test_name = format_ident!( - "test_parse_{}_vector_{}_0x{}", - test_packet, - i + 1, - &test_vector.packed - ); - let serialize_test_name = format_ident!( - "test_serialize_{}_vector_{}_0x{}", - test_packet, - i + 1, - &test_vector.packed - ); - let packed = hexadecimal_to_vec(&test_vector.packed); - let packet_name = format_ident!("{}", test_packet); - let builder_name = format_ident!("{}Builder", test_packet); - - let object = test_vector.unpacked.as_object().unwrap_or_else(|| { - panic!("Expected test vector object, found: {}", test_vector.unpacked) - }); - let assertions = object.iter().map(|(key, value)| { - let getter = format_ident!("get_{key}"); - let expected = format_ident!("expected_{key}"); - let json = to_json(&value); - quote! { - let #expected: serde_json::Value = serde_json::from_str(#json) - .expect("Could not create expected value from canonical JSON data"); - assert_eq!(json!(actual.#getter()), #expected); - } - }); - - let json = to_json(&object); - tests.push(quote! { - #[test] - fn #parse_test_name() { - let packed = #packed; - let actual = #module::#packet_name::parse(&packed).unwrap(); - #(#assertions)* - } - - #[test] - fn #serialize_test_name() { - let builder: #module::#builder_name = serde_json::from_str(#json) - .expect("Could not create builder from canonical JSON data"); - let packet = builder.build(); - let packed: Vec = #packed; - assert_eq!(packet.to_vec(), packed); - } - }); - } - } - - // TODO(mgeisler): make the generated code clean from warnings. - println!("#![allow(warnings, missing_docs)]"); - println!(); - println!( - "{}", - "e! { - use #module::Packet; - use serde_json::json; - - #(#tests)* - } - ); -} - -fn main() { - let input_path = std::env::args().nth(1).expect("Need path to JSON file with test vectors"); - let module_name = std::env::args().nth(2).expect("Need name for the generated module"); - // TODO(mgeisler): remove the `packet_names` argument when we - // support all canonical packets. - generate_unit_tests( - &input_path, - &[ - "EnumChild_A", - "EnumChild_B", - "Packet_Array_Field_ByteElement_ConstantSize", - "Packet_Array_Field_ByteElement_UnknownSize", - "Packet_Array_Field_ByteElement_VariableCount", - "Packet_Array_Field_ByteElement_VariableSize", - "Packet_Array_Field_EnumElement", - "Packet_Array_Field_EnumElement_ConstantSize", - "Packet_Array_Field_EnumElement_UnknownSize", - "Packet_Array_Field_EnumElement_VariableCount", - "Packet_Array_Field_EnumElement_VariableCount", - "Packet_Array_Field_ScalarElement", - "Packet_Array_Field_ScalarElement_ConstantSize", - "Packet_Array_Field_ScalarElement_UnknownSize", - "Packet_Array_Field_ScalarElement_VariableCount", - "Packet_Array_Field_ScalarElement_VariableSize", - "Packet_Array_Field_SizedElement_ConstantSize", - "Packet_Array_Field_SizedElement_UnknownSize", - "Packet_Array_Field_SizedElement_VariableCount", - "Packet_Array_Field_SizedElement_VariableSize", - "Packet_Array_Field_UnsizedElement_ConstantSize", - "Packet_Array_Field_UnsizedElement_UnknownSize", - "Packet_Array_Field_UnsizedElement_VariableCount", - "Packet_Array_Field_UnsizedElement_VariableSize", - "Packet_Body_Field_UnknownSize", - "Packet_Body_Field_UnknownSize_Terminal", - "Packet_Body_Field_VariableSize", - "Packet_Count_Field", - "Packet_Enum8_Field", - "Packet_Enum_Field", - "Packet_FixedEnum_Field", - "Packet_FixedScalar_Field", - "Packet_Payload_Field_UnknownSize", - "Packet_Payload_Field_UnknownSize_Terminal", - "Packet_Payload_Field_VariableSize", - "Packet_Reserved_Field", - "Packet_Scalar_Field", - "Packet_Size_Field", - "Packet_Struct_Field", - "ScalarChild_A", - "ScalarChild_B", - "Struct_Count_Field", - "Struct_Array_Field_ByteElement_ConstantSize", - "Struct_Array_Field_ByteElement_UnknownSize", - "Struct_Array_Field_ByteElement_UnknownSize", - "Struct_Array_Field_ByteElement_VariableCount", - "Struct_Array_Field_ByteElement_VariableCount", - "Struct_Array_Field_ByteElement_VariableSize", - "Struct_Array_Field_ByteElement_VariableSize", - "Struct_Array_Field_EnumElement_ConstantSize", - "Struct_Array_Field_EnumElement_UnknownSize", - "Struct_Array_Field_EnumElement_UnknownSize", - "Struct_Array_Field_EnumElement_VariableCount", - "Struct_Array_Field_EnumElement_VariableCount", - "Struct_Array_Field_EnumElement_VariableSize", - "Struct_Array_Field_EnumElement_VariableSize", - "Struct_Array_Field_ScalarElement_ConstantSize", - "Struct_Array_Field_ScalarElement_UnknownSize", - "Struct_Array_Field_ScalarElement_UnknownSize", - "Struct_Array_Field_ScalarElement_VariableCount", - "Struct_Array_Field_ScalarElement_VariableCount", - "Struct_Array_Field_ScalarElement_VariableSize", - "Struct_Array_Field_ScalarElement_VariableSize", - "Struct_Array_Field_SizedElement_ConstantSize", - "Struct_Array_Field_SizedElement_UnknownSize", - "Struct_Array_Field_SizedElement_UnknownSize", - "Struct_Array_Field_SizedElement_VariableCount", - "Struct_Array_Field_SizedElement_VariableCount", - "Struct_Array_Field_SizedElement_VariableSize", - "Struct_Array_Field_SizedElement_VariableSize", - "Struct_Array_Field_UnsizedElement_ConstantSize", - "Struct_Array_Field_UnsizedElement_UnknownSize", - "Struct_Array_Field_UnsizedElement_UnknownSize", - "Struct_Array_Field_UnsizedElement_VariableCount", - "Struct_Array_Field_UnsizedElement_VariableCount", - "Struct_Array_Field_UnsizedElement_VariableSize", - "Struct_Array_Field_UnsizedElement_VariableSize", - "Struct_Enum_Field", - "Struct_FixedEnum_Field", - "Struct_FixedScalar_Field", - "Struct_Size_Field", - "Struct_Struct_Field", - ], - &module_name, - ); -} diff --git a/tools/pdl/src/lint.rs b/tools/pdl/src/lint.rs deleted file mode 100644 index 27457ac078a7cbc58b66e4226b94a80c85887a18..0000000000000000000000000000000000000000 --- a/tools/pdl/src/lint.rs +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use std::collections::HashMap; - -use crate::analyzer::ast as analyzer_ast; -use crate::ast::*; - -/// Gather information about the full AST. -#[derive(Debug)] -pub struct Scope<'d> { - // Original file. - file: &'d analyzer_ast::File, - - // Collection of Group, Packet, Enum, Struct, Checksum, and CustomField declarations. - pub typedef: HashMap, - - // Collection of Packet, Struct, and Group scope declarations. - pub scopes: HashMap<&'d analyzer_ast::Decl, PacketScope<'d>>, -} - -/// Gather information about a Packet, Struct, or Group declaration. -#[derive(Debug)] -pub struct PacketScope<'d> { - // Original decl. - decl: &'d analyzer_ast::Decl, - - // Local and inherited field declarations. Only named fields are preserved. - // Saved here for reference for parent constraint resolving. - pub all_fields: HashMap, - - // Local and inherited constraint declarations. - // Saved here for constraint conflict checks. - pub all_constraints: HashMap, -} - -impl<'d> std::hash::Hash for &'d analyzer_ast::Decl { - fn hash(&self, state: &mut H) { - std::ptr::hash(*self, state); - } -} - -impl<'d> PacketScope<'d> { - /// Add parent fields and constraints to the scope. - /// Only named fields are imported. - fn inherit( - &mut self, - parent: &PacketScope<'d>, - constraints: impl Iterator, - ) { - // Check constraints. - assert!(self.all_constraints.is_empty()); - self.all_constraints = parent.all_constraints.clone(); - for constraint in constraints { - let id = constraint.id.clone(); - self.all_constraints.insert(id, constraint); - } - - // Save parent fields. - self.all_fields = parent.all_fields.clone(); - } - - /// Iterate over the packet's fields. - pub fn iter_fields(&self) -> impl Iterator { - self.decl.fields() - } - - /// Lookup a field by name. This will also find the special - /// `_payload_` and `_body_` fields. - pub fn get_packet_field(&self, id: &str) -> Option<&analyzer_ast::Field> { - self.decl.fields().find(|field| match &field.desc { - FieldDesc::Payload { .. } => id == "_payload_", - FieldDesc::Body { .. } => id == "_body_", - _ => field.id() == Some(id), - }) - } - - /// Find the payload or body field, if any. - pub fn get_payload_field(&self) -> Option<&analyzer_ast::Field> { - self.decl - .fields() - .find(|field| matches!(&field.desc, FieldDesc::Payload { .. } | FieldDesc::Body { .. })) - } - - /// Lookup the size field for an array field. - pub fn get_array_size_field(&self, id: &str) -> Option<&analyzer_ast::Field> { - self.decl.fields().find(|field| match &field.desc { - FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => field_id == id, - _ => false, - }) - } - - /// Find the size field corresponding to the payload or body - /// field of this packet. - pub fn get_payload_size_field(&self) -> Option<&analyzer_ast::Field> { - self.decl.fields().find(|field| match &field.desc { - FieldDesc::Size { field_id, .. } => field_id == "_payload_" || field_id == "_body_", - _ => false, - }) - } - - /// Cleanup scope after processing all fields. - fn finalize(&mut self) { - // Check field shadowing. - for f in self.decl.fields() { - if let Some(id) = f.id() { - self.all_fields.insert(id.to_string(), f); - } - } - } -} - -impl<'d> Scope<'d> { - pub fn new(file: &analyzer_ast::File) -> Scope<'_> { - let mut scope = Scope { file, typedef: HashMap::new(), scopes: HashMap::new() }; - - // Gather top-level declarations. - // Validate the top-level scopes (Group, Packet, Typedef). - // - // TODO: switch to try_insert when stable - for decl in &file.declarations { - if let Some(id) = decl.id() { - scope.typedef.insert(id.to_string(), decl); - } - } - - scope.finalize(); - scope - } - - // Sort Packet, Struct, and Group declarations by reverse topological - // order. - fn finalize(&mut self) -> Vec<&'d analyzer_ast::Decl> { - // Auxiliary function implementing BFS on Packet tree. - enum Mark { - Temporary, - Permanent, - } - struct Context<'d> { - list: Vec<&'d analyzer_ast::Decl>, - visited: HashMap<&'d analyzer_ast::Decl, Mark>, - scopes: HashMap<&'d analyzer_ast::Decl, PacketScope<'d>>, - } - - fn bfs<'s, 'd>( - decl: &'d analyzer_ast::Decl, - context: &'s mut Context<'d>, - scope: &Scope<'d>, - ) -> Option<&'s PacketScope<'d>> { - match context.visited.get(&decl) { - Some(Mark::Permanent) => return context.scopes.get(&decl), - Some(Mark::Temporary) => { - return None; - } - _ => (), - } - - let (parent_id, fields) = match &decl.desc { - DeclDesc::Packet { parent_id, fields, .. } - | DeclDesc::Struct { parent_id, fields, .. } => (parent_id.as_ref(), fields), - DeclDesc::Group { fields, .. } => (None, fields), - _ => return None, - }; - - context.visited.insert(decl, Mark::Temporary); - let mut lscope = - PacketScope { decl, all_fields: HashMap::new(), all_constraints: HashMap::new() }; - - // Iterate over Struct and Group fields. - for f in fields { - match &f.desc { - FieldDesc::Group { .. } => unreachable!(), - FieldDesc::Typedef { type_id, .. } => match scope.typedef.get(type_id) { - Some(struct_decl @ Decl { desc: DeclDesc::Struct { .. }, .. }) => { - bfs(struct_decl, context, scope); - } - None | Some(_) => (), - }, - _ => (), - } - } - - // Iterate over parent declaration. - let parent = parent_id.and_then(|id| scope.typedef.get(id)); - if let Some(parent_decl) = parent { - if let Some(rscope) = bfs(parent_decl, context, scope) { - // Import the parent fields and constraints into the current scope. - lscope.inherit(rscope, decl.constraints()) - } - } - - lscope.finalize(); - context.list.push(decl); - context.visited.insert(decl, Mark::Permanent); - context.scopes.insert(decl, lscope); - context.scopes.get(&decl) - } - - let mut context = - Context::<'d> { list: vec![], visited: HashMap::new(), scopes: HashMap::new() }; - - for decl in self.typedef.values() { - bfs(decl, &mut context, self); - } - - self.scopes = context.scopes; - context.list - } - - pub fn iter_children<'a>( - &'a self, - id: &'a str, - ) -> impl Iterator + 'a { - self.file.iter_children(self.typedef.get(id).unwrap()) - } - - /// Return the declaration of the typedef type backing the - /// selected field. - pub fn get_field_declaration( - &self, - field: &analyzer_ast::Field, - ) -> Option<&'d analyzer_ast::Decl> { - match &field.desc { - FieldDesc::FixedEnum { enum_id, .. } => self.typedef.get(enum_id).copied(), - FieldDesc::Array { type_id: Some(type_id), .. } => self.typedef.get(type_id).copied(), - FieldDesc::Typedef { type_id, .. } => self.typedef.get(type_id.as_str()).copied(), - _ => None, - } - } - - /// Test if the selected field is a bitfield. - pub fn is_bitfield(&self, field: &analyzer_ast::Field) -> bool { - match &field.desc { - FieldDesc::Size { .. } - | FieldDesc::Count { .. } - | FieldDesc::ElementSize { .. } - | FieldDesc::FixedScalar { .. } - | FieldDesc::FixedEnum { .. } - | FieldDesc::Reserved { .. } - | FieldDesc::Scalar { .. } => true, - FieldDesc::Typedef { type_id, .. } => { - let field = self.typedef.get(type_id.as_str()); - matches!(field, Some(Decl { desc: DeclDesc::Enum { .. }, .. })) - } - _ => false, - } - } - - /// Determine the size of a field in bits, if possible. - /// - /// If the field is dynamically sized (e.g. unsized array or - /// payload field), `None` is returned. If `skip_payload` is set, - /// payload and body fields are counted as having size `0` rather - /// than a variable size. - pub fn get_field_width( - &self, - field: &analyzer_ast::Field, - skip_payload: bool, - ) -> Option { - match &field.desc { - FieldDesc::Scalar { width, .. } - | FieldDesc::Size { width, .. } - | FieldDesc::Count { width, .. } - | FieldDesc::ElementSize { width, .. } - | FieldDesc::Reserved { width, .. } - | FieldDesc::FixedScalar { width, .. } => Some(*width), - FieldDesc::Padding { .. } => todo!(), - FieldDesc::Array { size: Some(size), width, .. } => { - let element_width = width - .or_else(|| self.get_decl_width(self.get_field_declaration(field)?, false))?; - Some(element_width * size) - } - FieldDesc::FixedEnum { .. } | FieldDesc::Typedef { .. } => { - self.get_decl_width(self.get_field_declaration(field)?, false) - } - FieldDesc::Checksum { .. } => Some(0), - FieldDesc::Payload { .. } | FieldDesc::Body { .. } if skip_payload => Some(0), - _ => None, - } - } - - /// Determine the size of a declaration type in bits, if possible. - /// - /// If the type is dynamically sized (e.g. contains an array or - /// payload), `None` is returned. If `skip_payload` is set, - /// payload and body fields are counted as having size `0` rather - /// than a variable size. - pub fn get_decl_width(&self, decl: &analyzer_ast::Decl, skip_payload: bool) -> Option { - match &decl.desc { - DeclDesc::Enum { width, .. } | DeclDesc::Checksum { width, .. } => Some(*width), - DeclDesc::CustomField { width, .. } => *width, - DeclDesc::Packet { fields, parent_id, .. } - | DeclDesc::Struct { fields, parent_id, .. } => { - let mut packet_size = match parent_id { - None => 0, - Some(id) => self.get_decl_width(self.typedef.get(id.as_str())?, true)?, - }; - for field in fields.iter() { - packet_size += self.get_field_width(field, skip_payload)?; - } - Some(packet_size) - } - DeclDesc::Group { .. } | DeclDesc::Test { .. } => None, - } - } -} diff --git a/tools/pdl/src/main.rs b/tools/pdl/src/main.rs deleted file mode 100644 index 979f10254623cedd8cf0ab6f6943edb59efbc7d4..0000000000000000000000000000000000000000 --- a/tools/pdl/src/main.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -//! PDL parser and analyzer. - -use argh::FromArgs; -use codespan_reporting::term::{self, termcolor}; - -mod analyzer; -mod ast; -mod backends; -mod lint; -mod parser; -#[cfg(test)] -mod test_utils; -mod utils; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum OutputFormat { - JSON, - Rust, - RustNoAlloc, - RustNoAllocTest, -} - -impl std::str::FromStr for OutputFormat { - type Err = String; - - fn from_str(input: &str) -> Result { - match input.to_lowercase().as_str() { - "json" => Ok(Self::JSON), - "rust" => Ok(Self::Rust), - "rust_no_alloc" => Ok(Self::RustNoAlloc), - "rust_no_alloc_test" => Ok(Self::RustNoAllocTest), - _ => Err(format!("could not parse {:?}, valid option are 'json', 'rust', 'rust_no_alloc', and 'rust_no_alloc_test'.", input)), - } - } -} - -#[derive(FromArgs, Debug)] -/// PDL analyzer and generator. -struct Opt { - #[argh(switch)] - /// print tool version and exit. - version: bool, - - #[argh(option, default = "OutputFormat::JSON")] - /// generate output in this format ("json", "rust", "rust_no_alloc", "rust_no_alloc_test"). The output - /// will be printed on stdout in both cases. - output_format: OutputFormat, - - #[argh(positional)] - /// input file. - input_file: String, -} - -fn main() -> Result<(), String> { - let opt: Opt = argh::from_env(); - - if opt.version { - println!("Packet Description Language parser version 1.0"); - return Ok(()); - } - - let mut sources = ast::SourceDatabase::new(); - match parser::parse_file(&mut sources, opt.input_file) { - Ok(file) => { - let analyzed_file = match analyzer::analyze(&file) { - Ok(file) => file, - Err(diagnostics) => { - diagnostics - .emit( - &sources, - &mut termcolor::StandardStream::stderr(termcolor::ColorChoice::Always) - .lock(), - ) - .expect("Could not print analyzer diagnostics"); - return Err(String::from("Analysis failed")); - } - }; - - match opt.output_format { - OutputFormat::JSON => { - println!("{}", backends::json::generate(&file).unwrap()) - } - OutputFormat::Rust => { - println!("{}", backends::rust::generate(&sources, &analyzed_file)) - } - OutputFormat::RustNoAlloc => { - let schema = backends::intermediate::generate(&file).unwrap(); - println!("{}", backends::rust_no_allocation::generate(&file, &schema).unwrap()) - } - OutputFormat::RustNoAllocTest => { - println!( - "{}", - backends::rust_no_allocation::test::generate_test_file().unwrap() - ) - } - } - Ok(()) - } - - Err(err) => { - let writer = termcolor::StandardStream::stderr(termcolor::ColorChoice::Always); - let config = term::Config::default(); - term::emit(&mut writer.lock(), &config, &sources, &err).expect("Could not print error"); - Err(String::from("Error while parsing input")) - } - } -} diff --git a/tools/pdl/src/parser.rs b/tools/pdl/src/parser.rs deleted file mode 100644 index 6d19648f0ba6b236708eb788f19afcb6875d7891..0000000000000000000000000000000000000000 --- a/tools/pdl/src/parser.rs +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -use codespan_reporting::diagnostic::Diagnostic; -use codespan_reporting::files; -use pest::iterators::{Pair, Pairs}; -use pest::{Parser, Token}; -use std::iter::{Filter, Peekable}; - -pub mod ast { - use serde::Serialize; - - #[derive(Debug, Serialize, Default, PartialEq, Eq)] - pub struct Annotation; - - impl crate::ast::Annotation for Annotation { - type FieldAnnotation = (); - type DeclAnnotation = (); - } - - pub type Field = crate::ast::Field; - pub type Decl = crate::ast::Decl; - pub type File = crate::ast::File; -} - -// Generate the PDL parser. -// TODO: use #[grammar = "pdl.pest"] -// currently not possible because CARGO_MANIFEST_DIR is not set -// in soong environment. -#[derive(pest_derive::Parser)] -#[grammar_inline = r#" -WHITESPACE = _{ " " | "\n" } -COMMENT = { block_comment | line_comment } - -block_comment = { "/*" ~ (!"*/" ~ ANY)* ~ "*/" } -line_comment = { "//" ~ (!"\n" ~ ANY)* } - -alpha = { 'a'..'z' | 'A'..'Z' } -digit = { '0'..'9' } -hexdigit = { digit | 'a'..'f' | 'A'..'F' } -alphanum = { alpha | digit | "_" } - -identifier = @{ alpha ~ alphanum* } -payload_identifier = @{ "_payload_" } -body_identifier = @{ "_body_" } -intvalue = @{ digit+ } -hexvalue = @{ ("0x"|"0X") ~ hexdigit+ } -integer = @{ hexvalue | intvalue } -string = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" } -size_modifier = @{ "+" ~ intvalue } - -endianness_declaration = { "little_endian_packets" | "big_endian_packets" } - -enum_value = { identifier ~ "=" ~ integer } -enum_value_list = { enum_value ~ ("," ~ enum_value)* ~ ","? } -enum_range = { - identifier ~ "=" ~ integer ~ ".." ~ integer ~ ("{" ~ - enum_value_list ~ - "}")? -} -enum_tag = { enum_range | enum_value } -enum_tag_list = { enum_tag ~ ("," ~ enum_tag)* ~ ","? } -enum_declaration = { - "enum" ~ identifier ~ ":" ~ integer ~ "{" ~ - enum_tag_list ~ - "}" -} - -constraint = { identifier ~ "=" ~ (identifier|integer) } -constraint_list = { constraint ~ ("," ~ constraint)* } - -checksum_field = { "_checksum_start_" ~ "(" ~ identifier ~ ")" } -padding_field = { "_padding_" ~ "[" ~ integer ~ "]" } -size_field = { "_size_" ~ "(" ~ (identifier|payload_identifier|body_identifier) ~ ")" ~ ":" ~ integer } -count_field = { "_count_" ~ "(" ~ identifier ~ ")" ~ ":" ~ integer } -elementsize_field = { "_elementsize_" ~ "(" ~ identifier ~ ")" ~ ":" ~ integer } -body_field = @{ "_body_" } -payload_field = { "_payload_" ~ (":" ~ "[" ~ size_modifier ~ "]")? } -fixed_field = { "_fixed_" ~ "=" ~ ( - (integer ~ ":" ~ integer) | - (identifier ~ ":" ~ identifier) -)} -reserved_field = { "_reserved_" ~ ":" ~ integer } -array_field = { identifier ~ ":" ~ (integer|identifier) ~ - "[" ~ (size_modifier|integer)? ~ "]" -} -scalar_field = { identifier ~ ":" ~ integer } -typedef_field = { identifier ~ ":" ~ identifier } -group_field = { identifier ~ ("{" ~ constraint_list? ~ "}")? } - -field = _{ - checksum_field | - padding_field | - size_field | - count_field | - elementsize_field | - body_field | - payload_field | - fixed_field | - reserved_field | - array_field | - scalar_field | - typedef_field | - group_field -} -field_list = { field ~ ("," ~ field)* ~ ","? } - -packet_declaration = { - "packet" ~ identifier ~ - (":" ~ identifier)? ~ - ("(" ~ constraint_list ~ ")")? ~ - "{" ~ - field_list? ~ - "}" -} - -struct_declaration = { - "struct" ~ identifier ~ - (":" ~ identifier)? ~ - ("(" ~ constraint_list ~ ")")? ~ - "{" ~ - field_list? ~ - "}" -} - -group_declaration = { - "group" ~ identifier ~ "{" ~ field_list ~ "}" -} - -checksum_declaration = { - "checksum" ~ identifier ~ ":" ~ integer ~ string -} - -custom_field_declaration = { - "custom_field" ~ identifier ~ (":" ~ integer)? ~ string -} - -test_case = { string } -test_case_list = _{ test_case ~ ("," ~ test_case)* ~ ","? } -test_declaration = { - "test" ~ identifier ~ "{" ~ - test_case_list ~ - "}" -} - -declaration = _{ - enum_declaration | - packet_declaration | - struct_declaration | - group_declaration | - checksum_declaration | - custom_field_declaration | - test_declaration -} - -file = { - SOI ~ - endianness_declaration ~ - declaration* ~ - EOI -} -"#] -pub struct PDLParser; - -type Node<'i> = Pair<'i, Rule>; -type NodeIterator<'i> = Peekable, fn(&Node<'i>) -> bool>>; -type Context<'a> = (crate::ast::FileId, &'a Vec); - -trait Helpers<'i> { - fn children(self) -> NodeIterator<'i>; - fn as_loc(&self, context: &Context) -> crate::ast::SourceRange; - fn as_string(&self) -> String; - fn as_usize(&self) -> Result; -} - -impl<'i> Helpers<'i> for Node<'i> { - fn children(self) -> NodeIterator<'i> { - self.into_inner().filter((|n| n.as_rule() != Rule::COMMENT) as fn(&Self) -> bool).peekable() - } - - fn as_loc(&self, context: &Context) -> crate::ast::SourceRange { - let span = self.as_span(); - crate::ast::SourceRange { - file: context.0, - start: crate::ast::SourceLocation::new(span.start_pos().pos(), context.1), - end: crate::ast::SourceLocation::new(span.end_pos().pos(), context.1), - } - } - - fn as_string(&self) -> String { - self.as_str().to_owned() - } - - fn as_usize(&self) -> Result { - let text = self.as_str(); - if let Some(num) = text.strip_prefix("0x") { - usize::from_str_radix(num, 16) - .map_err(|_| format!("cannot convert '{}' to usize", self.as_str())) - } else { - #[allow(clippy::from_str_radix_10)] - usize::from_str_radix(text, 10) - .map_err(|_| format!("cannot convert '{}' to usize", self.as_str())) - } - } -} - -fn err_unexpected_rule(expected: Rule, found: Rule) -> Result { - Err(format!("expected rule {:?}, got {:?}", expected, found)) -} - -fn err_missing_rule(expected: Rule) -> Result { - Err(format!("expected rule {:?}, got nothing", expected)) -} - -fn expect<'i>(iter: &mut impl Iterator>, rule: Rule) -> Result, String> { - match iter.next() { - Some(node) if node.as_rule() == rule => Ok(node), - Some(node) => err_unexpected_rule(rule, node.as_rule()), - None => err_missing_rule(rule), - } -} - -fn maybe<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Option> { - iter.next_if(|n| n.as_rule() == rule) -} - -fn parse_identifier(iter: &mut NodeIterator<'_>) -> Result { - expect(iter, Rule::identifier).map(|n| n.as_string()) -} - -fn parse_integer(iter: &mut NodeIterator<'_>) -> Result { - expect(iter, Rule::integer).and_then(|n| n.as_usize()) -} - -fn parse_identifier_opt(iter: &mut NodeIterator<'_>) -> Result, String> { - Ok(maybe(iter, Rule::identifier).map(|n| n.as_string())) -} - -fn parse_integer_opt(iter: &mut NodeIterator<'_>) -> Result, String> { - maybe(iter, Rule::integer).map(|n| n.as_usize()).transpose() -} - -fn parse_identifier_or_integer( - iter: &mut NodeIterator<'_>, -) -> Result<(Option, Option), String> { - match iter.next() { - Some(n) if n.as_rule() == Rule::identifier => Ok((Some(n.as_string()), None)), - Some(n) if n.as_rule() == Rule::integer => Ok((None, Some(n.as_usize()?))), - Some(n) => Err(format!( - "expected rule {:?} or {:?}, got {:?}", - Rule::identifier, - Rule::integer, - n.as_rule() - )), - None => { - Err(format!("expected rule {:?} or {:?}, got nothing", Rule::identifier, Rule::integer)) - } - } -} - -fn parse_string<'i>(iter: &mut impl Iterator>) -> Result { - expect(iter, Rule::string) - .map(|n| n.as_str()) - .and_then(|s| s.strip_prefix('"').ok_or_else(|| "expected \" prefix".to_owned())) - .and_then(|s| s.strip_suffix('"').ok_or_else(|| "expected \" suffix".to_owned())) - .map(|s| s.to_owned()) -} - -fn parse_size_modifier_opt(iter: &mut NodeIterator<'_>) -> Option { - maybe(iter, Rule::size_modifier).map(|n| n.as_string()) -} - -fn parse_endianness(node: Node<'_>, context: &Context) -> Result { - if node.as_rule() != Rule::endianness_declaration { - err_unexpected_rule(Rule::endianness_declaration, node.as_rule()) - } else { - Ok(crate::ast::Endianness { - loc: node.as_loc(context), - value: match node.as_str() { - "little_endian_packets" => crate::ast::EndiannessValue::LittleEndian, - "big_endian_packets" => crate::ast::EndiannessValue::BigEndian, - _ => unreachable!(), - }, - }) - } -} - -fn parse_constraint(node: Node<'_>, context: &Context) -> Result { - if node.as_rule() != Rule::constraint { - err_unexpected_rule(Rule::constraint, node.as_rule()) - } else { - let loc = node.as_loc(context); - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let (tag_id, value) = parse_identifier_or_integer(&mut children)?; - Ok(crate::ast::Constraint { id, loc, value, tag_id }) - } -} - -fn parse_constraint_list_opt( - iter: &mut NodeIterator<'_>, - context: &Context, -) -> Result, String> { - maybe(iter, Rule::constraint_list) - .map_or(Ok(vec![]), |n| n.children().map(|n| parse_constraint(n, context)).collect()) -} - -fn parse_enum_value(node: Node<'_>, context: &Context) -> Result { - if node.as_rule() != Rule::enum_value { - err_unexpected_rule(Rule::enum_value, node.as_rule()) - } else { - let loc = node.as_loc(context); - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let value = parse_integer(&mut children)?; - Ok(crate::ast::TagValue { id, loc, value }) - } -} - -fn parse_enum_value_list_opt( - iter: &mut NodeIterator<'_>, - context: &Context, -) -> Result, String> { - maybe(iter, Rule::enum_value_list) - .map_or(Ok(vec![]), |n| n.children().map(|n| parse_enum_value(n, context)).collect()) -} - -fn parse_enum_range(node: Node<'_>, context: &Context) -> Result { - if node.as_rule() != Rule::enum_range { - err_unexpected_rule(Rule::enum_range, node.as_rule()) - } else { - let loc = node.as_loc(context); - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let start = parse_integer(&mut children)?; - let end = parse_integer(&mut children)?; - let tags = parse_enum_value_list_opt(&mut children, context)?; - Ok(crate::ast::TagRange { id, loc, range: start..=end, tags }) - } -} - -fn parse_enum_tag(node: Node<'_>, context: &Context) -> Result { - if node.as_rule() != Rule::enum_tag { - err_unexpected_rule(Rule::enum_tag, node.as_rule()) - } else { - match node.children().next() { - Some(node) if node.as_rule() == Rule::enum_value => { - Ok(crate::ast::Tag::Value(parse_enum_value(node, context)?)) - } - Some(node) if node.as_rule() == Rule::enum_range => { - Ok(crate::ast::Tag::Range(parse_enum_range(node, context)?)) - } - Some(node) => Err(format!( - "expected rule {:?} or {:?}, got {:?}", - Rule::enum_value, - Rule::enum_range, - node.as_rule() - )), - None => Err(format!( - "expected rule {:?} or {:?}, got nothing", - Rule::enum_value, - Rule::enum_range - )), - } - } -} - -fn parse_enum_tag_list( - iter: &mut NodeIterator<'_>, - context: &Context, -) -> Result, String> { - expect(iter, Rule::enum_tag_list) - .and_then(|n| n.children().map(|n| parse_enum_tag(n, context)).collect()) -} - -fn parse_field(node: Node<'_>, context: &Context) -> Result { - let loc = node.as_loc(context); - let rule = node.as_rule(); - let mut children = node.children(); - Ok(crate::ast::Field { - loc, - annot: Default::default(), - desc: match rule { - Rule::checksum_field => { - let field_id = parse_identifier(&mut children)?; - crate::ast::FieldDesc::Checksum { field_id } - } - Rule::padding_field => { - let size = parse_integer(&mut children)?; - crate::ast::FieldDesc::Padding { size } - } - Rule::size_field => { - let field_id = match children.next() { - Some(n) if n.as_rule() == Rule::identifier => n.as_string(), - Some(n) if n.as_rule() == Rule::payload_identifier => n.as_string(), - Some(n) if n.as_rule() == Rule::body_identifier => n.as_string(), - Some(n) => err_unexpected_rule(Rule::identifier, n.as_rule())?, - None => err_missing_rule(Rule::identifier)?, - }; - let width = parse_integer(&mut children)?; - crate::ast::FieldDesc::Size { field_id, width } - } - Rule::count_field => { - let field_id = parse_identifier(&mut children)?; - let width = parse_integer(&mut children)?; - crate::ast::FieldDesc::Count { field_id, width } - } - Rule::elementsize_field => { - let field_id = parse_identifier(&mut children)?; - let width = parse_integer(&mut children)?; - crate::ast::FieldDesc::ElementSize { field_id, width } - } - Rule::body_field => crate::ast::FieldDesc::Body, - Rule::payload_field => { - let size_modifier = parse_size_modifier_opt(&mut children); - crate::ast::FieldDesc::Payload { size_modifier } - } - Rule::fixed_field => match children.next() { - Some(n) if n.as_rule() == Rule::integer => { - let value = n.as_usize()?; - let width = parse_integer(&mut children)?; - crate::ast::FieldDesc::FixedScalar { width, value } - } - Some(n) if n.as_rule() == Rule::identifier => { - let tag_id = n.as_string(); - let enum_id = parse_identifier(&mut children)?; - crate::ast::FieldDesc::FixedEnum { enum_id, tag_id } - } - _ => unreachable!(), - }, - Rule::reserved_field => { - let width = parse_integer(&mut children)?; - crate::ast::FieldDesc::Reserved { width } - } - Rule::array_field => { - let id = parse_identifier(&mut children)?; - let (type_id, width) = parse_identifier_or_integer(&mut children)?; - let (size, size_modifier) = match children.next() { - Some(n) if n.as_rule() == Rule::integer => (Some(n.as_usize()?), None), - Some(n) if n.as_rule() == Rule::size_modifier => (None, Some(n.as_string())), - Some(n) => { - return Err(format!( - "expected rule {:?} or {:?}, got {:?}", - Rule::integer, - Rule::size_modifier, - n.as_rule() - )) - } - None => (None, None), - }; - crate::ast::FieldDesc::Array { id, type_id, width, size, size_modifier } - } - Rule::scalar_field => { - let id = parse_identifier(&mut children)?; - let width = parse_integer(&mut children)?; - crate::ast::FieldDesc::Scalar { id, width } - } - Rule::typedef_field => { - let id = parse_identifier(&mut children)?; - let type_id = parse_identifier(&mut children)?; - crate::ast::FieldDesc::Typedef { id, type_id } - } - Rule::group_field => { - let group_id = parse_identifier(&mut children)?; - let constraints = parse_constraint_list_opt(&mut children, context)?; - crate::ast::FieldDesc::Group { group_id, constraints } - } - _ => return Err(format!("expected rule *_field, got {:?}", rule)), - }, - }) -} - -fn parse_field_list(iter: &mut NodeIterator, context: &Context) -> Result, String> { - expect(iter, Rule::field_list) - .and_then(|n| n.children().map(|n| parse_field(n, context)).collect()) -} - -fn parse_field_list_opt( - iter: &mut NodeIterator, - context: &Context, -) -> Result, String> { - maybe(iter, Rule::field_list) - .map_or(Ok(vec![]), |n| n.children().map(|n| parse_field(n, context)).collect()) -} - -fn parse_toplevel(root: Node<'_>, context: &Context) -> Result { - let mut toplevel_comments = vec![]; - let mut file = crate::ast::File::new(context.0); - - let mut comment_start = vec![]; - for token in root.clone().tokens() { - match token { - Token::Start { rule: Rule::COMMENT, pos } => comment_start.push(pos), - Token::End { rule: Rule::COMMENT, pos } => { - let start_pos = comment_start.pop().unwrap(); - file.comments.push(crate::ast::Comment { - loc: crate::ast::SourceRange { - file: context.0, - start: crate::ast::SourceLocation::new(start_pos.pos(), context.1), - end: crate::ast::SourceLocation::new(pos.pos(), context.1), - }, - text: start_pos.span(&pos).as_str().to_owned(), - }) - } - _ => (), - } - } - - for node in root.children() { - let loc = node.as_loc(context); - let rule = node.as_rule(); - match rule { - Rule::endianness_declaration => file.endianness = parse_endianness(node, context)?, - Rule::checksum_declaration => { - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let width = parse_integer(&mut children)?; - let function = parse_string(&mut children)?; - file.declarations.push(crate::ast::Decl::new( - loc, - crate::ast::DeclDesc::Checksum { id, function, width }, - )) - } - Rule::custom_field_declaration => { - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let width = parse_integer_opt(&mut children)?; - let function = parse_string(&mut children)?; - file.declarations.push(crate::ast::Decl::new( - loc, - crate::ast::DeclDesc::CustomField { id, function, width }, - )) - } - Rule::enum_declaration => { - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let width = parse_integer(&mut children)?; - let tags = parse_enum_tag_list(&mut children, context)?; - file.declarations.push(crate::ast::Decl::new( - loc, - crate::ast::DeclDesc::Enum { id, width, tags }, - )) - } - Rule::packet_declaration => { - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let parent_id = parse_identifier_opt(&mut children)?; - let constraints = parse_constraint_list_opt(&mut children, context)?; - let fields = parse_field_list_opt(&mut children, context)?; - file.declarations.push(crate::ast::Decl::new( - loc, - crate::ast::DeclDesc::Packet { id, parent_id, constraints, fields }, - )) - } - Rule::struct_declaration => { - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let parent_id = parse_identifier_opt(&mut children)?; - let constraints = parse_constraint_list_opt(&mut children, context)?; - let fields = parse_field_list_opt(&mut children, context)?; - file.declarations.push(crate::ast::Decl::new( - loc, - crate::ast::DeclDesc::Struct { id, parent_id, constraints, fields }, - )) - } - Rule::group_declaration => { - let mut children = node.children(); - let id = parse_identifier(&mut children)?; - let fields = parse_field_list(&mut children, context)?; - file.declarations - .push(crate::ast::Decl::new(loc, crate::ast::DeclDesc::Group { id, fields })) - } - Rule::test_declaration => {} - Rule::EOI => (), - _ => unreachable!(), - } - } - file.comments.append(&mut toplevel_comments); - Ok(file) -} - -/// Parse PDL source code from a string. -/// -/// The file is added to the compilation database under the provided -/// name. -pub fn parse_inline( - sources: &mut crate::ast::SourceDatabase, - name: String, - source: String, -) -> Result> { - let root = PDLParser::parse(Rule::file, &source) - .map_err(|e| { - Diagnostic::error() - .with_message(format!("failed to parse input file '{}': {}", &name, e)) - })? - .next() - .unwrap(); - let line_starts: Vec<_> = files::line_starts(&source).collect(); - let file = sources.add(name, source.clone()); - parse_toplevel(root, &(file, &line_starts)).map_err(|e| Diagnostic::error().with_message(e)) -} - -/// Parse a new source file. -/// -/// The source file is fully read and added to the compilation -/// database. Returns the constructed AST, or a descriptive error -/// message in case of syntax error. -pub fn parse_file( - sources: &mut crate::ast::SourceDatabase, - name: String, -) -> Result> { - let source = std::fs::read_to_string(&name).map_err(|e| { - Diagnostic::error().with_message(format!("failed to read input file '{}': {}", &name, e)) - })?; - parse_inline(sources, name, source) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn endianness_is_set() { - // The file starts out with a placeholder little-endian value. - // This tests that we update it while parsing. - let mut db = crate::ast::SourceDatabase::new(); - let file = - parse_inline(&mut db, String::from("stdin"), String::from(" big_endian_packets ")) - .unwrap(); - assert_eq!(file.endianness.value, crate::ast::EndiannessValue::BigEndian); - assert_ne!(file.endianness.loc, crate::ast::SourceRange::default()); - } - - #[test] - fn test_parse_string_bare() { - let mut pairs = PDLParser::parse(Rule::string, r#""test""#).unwrap(); - - assert_eq!(parse_string(&mut pairs).as_deref(), Ok("test")); - assert_eq!(pairs.next(), None, "pairs is empty"); - } - - #[test] - fn test_parse_string_space() { - let mut pairs = PDLParser::parse(Rule::string, r#""test with space""#).unwrap(); - - assert_eq!(parse_string(&mut pairs).as_deref(), Ok("test with space")); - assert_eq!(pairs.next(), None, "pairs is empty"); - } - - #[test] - #[should_panic] /* This is not supported */ - fn test_parse_string_escape() { - let mut pairs = PDLParser::parse(Rule::string, r#""\"test\"""#).unwrap(); - - assert_eq!(parse_string(&mut pairs).as_deref(), Ok(r#""test""#)); - assert_eq!(pairs.next(), None, "pairs is empty"); - } -} diff --git a/tools/pdl/src/pdl.pest b/tools/pdl/src/pdl.pest deleted file mode 100644 index 06563d61b05a6e348f83acf921688eeab472ed4f..0000000000000000000000000000000000000000 --- a/tools/pdl/src/pdl.pest +++ /dev/null @@ -1,125 +0,0 @@ -WHITESPACE = _{ " " | "\n" } -COMMENT = { block_comment | line_comment } - -block_comment = { "/*" ~ (!"*/" ~ ANY)* ~ "*/" } -line_comment = { "//" ~ (!"\n" ~ ANY)* } - -alpha = { 'a'..'z' | 'A'..'Z' } -digit = { '0'..'9' } -hexdigit = { digit | 'a'..'f' | 'A'..'F' } -alphanum = { alpha | digit | "_" } - -identifier = @{ alpha ~ alphanum* } -payload_identifier = @{ "_payload_" } -body_identifier = @{ "_body_" } -intvalue = @{ digit+ } -hexvalue = @{ ("0x"|"0X") ~ hexdigit+ } -integer = @{ hexvalue | intvalue } -string = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" } -size_modifier = @{ - ("+"|"-"|"*"|"/") ~ (digit|"+"|"-"|"*"|"/")+ -} - -endianness_declaration = { "little_endian_packets" | "big_endian_packets" } - -enum_tag = { identifier ~ "=" ~ integer } -enum_tag_list = { enum_tag ~ ("," ~ enum_tag)* ~ ","? } -enum_declaration = { - "enum" ~ identifier ~ ":" ~ integer ~ "{" ~ - enum_tag_list ~ - "}" -} - -constraint = { identifier ~ "=" ~ (identifier|integer) } -constraint_list = { constraint ~ ("," ~ constraint)* } - -checksum_field = { "_checksum_start_" ~ "(" ~ identifier ~ ")" } -padding_field = { "_padding_" ~ "[" ~ integer ~ "]" } -size_field = { "_size_" ~ "(" ~ (identifier|payload_identifier|body_identifier) ~ ")" ~ ":" ~ integer } -count_field = { "_count_" ~ "(" ~ identifier ~ ")" ~ ":" ~ integer } -elementsize_field = { "_elementsize_" ~ "(" ~ identifier ~ ")" ~ ":" ~ integer } -body_field = @{ "_body_" } -payload_field = { "_payload_" ~ (":" ~ "[" ~ size_modifier ~ "]")? } -fixed_field = { "_fixed_" ~ "=" ~ ( - (integer ~ ":" ~ integer) | - (identifier ~ ":" ~ identifier) -)} -reserved_field = { "_reserved_" ~ ":" ~ integer } -array_field = { identifier ~ ":" ~ (integer|identifier) ~ - "[" ~ (size_modifier|integer)? ~ "]" -} -scalar_field = { identifier ~ ":" ~ integer } -typedef_field = { identifier ~ ":" ~ identifier } -group_field = { identifier ~ ("{" ~ constraint_list ~ "}")? } - -field = _{ - checksum_field | - padding_field | - size_field | - count_field | - elementsize_field | - body_field | - payload_field | - fixed_field | - reserved_field | - array_field | - scalar_field | - typedef_field | - group_field -} -field_list = { field ~ ("," ~ field)* ~ ","? } - -packet_declaration = { - "packet" ~ identifier ~ - (":" ~ identifier)? ~ - ("(" ~ constraint_list ~ ")")? ~ - "{" ~ - field_list? ~ - "}" -} - -struct_declaration = { - "struct" ~ identifier ~ - (":" ~ identifier)? ~ - ("(" ~ constraint_list ~ ")")? ~ - "{" ~ - field_list? ~ - "}" -} - -group_declaration = { - "group" ~ identifier ~ "{" ~ field_list ~ "}" -} - -checksum_declaration = { - "checksum" ~ identifier ~ ":" ~ integer ~ string -} - -custom_field_declaration = { - "custom_field" ~ identifier ~ (":" ~ integer)? ~ string -} - -test_case = { string } -test_case_list = _{ test_case ~ ("," ~ test_case)* ~ ","? } -test_declaration = { - "test" ~ identifier ~ "{" ~ - test_case_list ~ - "}" -} - -declaration = _{ - enum_declaration | - packet_declaration | - struct_declaration | - group_declaration | - checksum_declaration | - custom_field_declaration | - test_declaration -} - -file = { - SOI ~ - endianness_declaration ~ - declaration* ~ - EOI -} diff --git a/tools/pdl/src/test_utils.rs b/tools/pdl/src/test_utils.rs deleted file mode 100644 index 7e618f647ebe12579ee129c2c7c95bab3f890313..0000000000000000000000000000000000000000 --- a/tools/pdl/src/test_utils.rs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -//! Various utility functions used in tests. - -// This file is included directly into integration tests in the -// `tests/` directory. These tests are compiled without access to the -// rest of the `pdl` crate. To make this work, avoid `use crate::` -// statements below. - -use std::fs; -use std::io::Write; -use std::path::Path; -use std::process::{Command, Stdio}; -use tempfile::NamedTempFile; - -/// Search for a binary in `$PATH` or as a sibling to the current -/// executable (typically the test binary). -pub fn find_binary(name: &str) -> Result { - let mut current_exe = std::env::current_exe().unwrap(); - current_exe.pop(); - let paths = std::env::var_os("PATH").unwrap(); - for mut path in std::iter::once(current_exe.clone()).chain(std::env::split_paths(&paths)) { - path.push(name); - if path.exists() { - return Ok(path); - } - } - - Err(format!( - "could not find '{}' in the directory of the binary ({}) or in $PATH ({})", - name, - current_exe.to_string_lossy(), - paths.to_string_lossy(), - )) -} - -/// Run `input` through `rustfmt`. -/// -/// # Panics -/// -/// Panics if `rustfmt` cannot be found in the same directory as the -/// test executable or if it returns a non-zero exit code. -pub fn rustfmt(input: &str) -> String { - let rustfmt_path = find_binary("rustfmt").expect("cannot find rustfmt"); - let mut rustfmt = Command::new(&rustfmt_path) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .unwrap_or_else(|_| panic!("failed to start {:?}", &rustfmt_path)); - - let mut stdin = rustfmt.stdin.take().unwrap(); - // Owned copy which we can move into the writing thread. - let input = String::from(input); - std::thread::spawn(move || { - stdin.write_all(input.as_bytes()).expect("could not write to stdin"); - }); - - let output = rustfmt.wait_with_output().expect("error executing rustfmt"); - assert!(output.status.success(), "rustfmt failed: {}", output.status); - String::from_utf8(output.stdout).expect("rustfmt output was not UTF-8") -} - -/// Find the unified diff between two strings using `diff`. -/// -/// # Panics -/// -/// Panics if `diff` cannot be found on `$PATH` or if it returns an -/// error. -pub fn diff(left_label: &str, left: &str, right_label: &str, right: &str) -> String { - let mut temp_left = NamedTempFile::new().unwrap(); - temp_left.write_all(left.as_bytes()).unwrap(); - let mut temp_right = NamedTempFile::new().unwrap(); - temp_right.write_all(right.as_bytes()).unwrap(); - - // We expect `diff` to be available on PATH. - let output = Command::new("diff") - .arg("--unified") - .arg("--color=always") - .arg("--label") - .arg(left_label) - .arg("--label") - .arg(right_label) - .arg(temp_left.path()) - .arg(temp_right.path()) - .output() - .expect("failed to run diff"); - let diff_trouble_exit_code = 2; // from diff(1) - assert_ne!( - output.status.code().unwrap(), - diff_trouble_exit_code, - "diff failed: {}", - output.status - ); - String::from_utf8(output.stdout).expect("diff output was not UTF-8") -} - -/// Compare two strings and output a diff if they are not equal. -#[track_caller] -pub fn assert_eq_with_diff(left_label: &str, left: &str, right_label: &str, right: &str) { - assert!( - left == right, - "texts did not match, diff:\n{}\n", - diff(left_label, left, right_label, right) - ); -} - -/// Check that `haystack` contains `needle`. -/// -/// Panic with a nice message if not. -#[track_caller] -pub fn assert_contains(haystack: &str, needle: &str) { - assert!(haystack.contains(needle), "Could not find {:?} in {:?}", needle, haystack); -} - -/// Compare a string with a snapshot file. -/// -/// The `snapshot_path` is relative to the current working directory -/// of the test binary. This depends on how you execute the tests: -/// -/// * When using `atest`: The current working directory is a random -/// temporary directory. You need to ensure that the snapshot file -/// is installed into this directory. You do this by adding the -/// snapshot to the `data` attribute of your test rule -/// -/// * When using Cargo: The current working directory is set to -/// `CARGO_MANIFEST_DIR`, which is where the `Cargo.toml` file is -/// found. -/// -/// If you run the test with Cargo and the `UPDATE_SNAPSHOTS` -/// environment variable is set, then the `actual_content` will be -/// written to `snapshot_path`. Otherwise the content is compared and -/// a panic is triggered if they differ. -#[track_caller] -pub fn assert_snapshot_eq>(snapshot_path: P, actual_content: &str) { - let update_snapshots = std::env::var("UPDATE_SNAPSHOTS").is_ok(); - let snapshot = snapshot_path.as_ref(); - let snapshot_content = match fs::read(snapshot) { - Ok(content) => content, - Err(_) if update_snapshots => Vec::new(), - Err(err) => panic!("Could not read snapshot from {}: {}", snapshot.display(), err), - }; - let snapshot_content = String::from_utf8(snapshot_content).expect("Snapshot was not UTF-8"); - - // Normal comparison if UPDATE_SNAPSHOTS is unset. - if !update_snapshots { - return assert_eq_with_diff( - snapshot.to_str().unwrap(), - &snapshot_content, - "actual", - actual_content, - ); - } - - // Bail out if we are not using Cargo. - if std::env::var("CARGO_MANIFEST_DIR").is_err() { - panic!("Please unset UPDATE_SNAPSHOTS if you are not using Cargo"); - } - - if actual_content != snapshot_content { - eprintln!( - "Updating snapshot {}: {} -> {} bytes", - snapshot.display(), - snapshot_content.len(), - actual_content.len() - ); - fs::write(&snapshot_path, actual_content).unwrap_or_else(|err| { - panic!("Could not write snapshot to {}: {}", snapshot.display(), err) - }); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_diff_labels_with_special_chars() { - // Check that special characters in labels are passed - // correctly to diff. - let patch = diff("left 'file'", "foo\nbar\n", "right ~file!", "foo\nnew line\nbar\n"); - assert_contains(&patch, "left 'file'"); - assert_contains(&patch, "right ~file!"); - } - - #[test] - #[should_panic] - fn test_assert_eq_with_diff_on_diff() { - // We use identical labels to check that we haven't - // accidentally mixed up the labels with the file content. - assert_eq_with_diff("", "foo\nbar\n", "", "foo\nnew line\nbar\n"); - } - - #[test] - fn test_assert_eq_with_diff_on_eq() { - // No panic when there is no diff. - assert_eq_with_diff("left", "foo\nbar\n", "right", "foo\nbar\n"); - } -} diff --git a/tools/pdl/src/utils.rs b/tools/pdl/src/utils.rs deleted file mode 100644 index 0e642502664004b0d6a66e7cdf0a0168c4f0ff0e..0000000000000000000000000000000000000000 --- a/tools/pdl/src/utils.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2023 Google LLC -// -// 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 -// -// https://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. - -/// Placeholder implementation of Vec::drain_filter. -/// The feature drain_filter is currently unstable. -pub fn drain_filter(input: &mut Vec, predicate: F) -> Vec -where - F: Fn(&T) -> bool, -{ - // Pass 1: compute the total number of removed elements. - let mut total_left_count = 0; - for element in input.iter() { - total_left_count += !predicate(element) as usize; - } - // Pass 2: compute the final position of each element in the input - // array in order to position left elements first and drained elements - // last, preserving the order. - let mut rank = Vec::with_capacity(input.len()); - let mut left_count = 0; - let mut removed_count = 0; - for element in input.iter() { - if predicate(element) { - rank.push(total_left_count + removed_count); - removed_count += 1; - } else { - rank.push(left_count); - left_count += 1; - } - } - // Pass 3: swap the elements to their final position. - let mut n = 0; - while n < input.len() { - let rank_n = rank[n]; - if n != rank_n { - input.swap(n, rank_n); - rank.swap(n, rank_n); - } else { - n += 1; - } - } - // Finally: split off the removed elements off the input vector. - input.split_off(total_left_count) -} - -#[cfg(test)] -mod test { - use crate::utils::drain_filter; - - #[test] - fn test_drain_filter() { - let mut input = vec![1, 4, 2, 5, 3, 6, 7]; - let drained = drain_filter(&mut input, |element| *element > 3); - assert_eq!(input, vec![1, 2, 3]); - assert_eq!(drained, vec![4, 5, 6, 7]); - } -} diff --git a/tools/pdl/tests/canonical/be_test_vectors.json b/tools/pdl/tests/canonical/be_test_vectors.json deleted file mode 100644 index e03357ed71292b31ae1434157d0ec8d5293f5a8c..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/canonical/be_test_vectors.json +++ /dev/null @@ -1,4271 +0,0 @@ -[ - { - "packet": "Packet_Scalar_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "c": 0 - } - }, - { - "packed": "ffffffffffffff80", - "unpacked": { - "a": 0, - "c": 144115188075855871 - } - }, - { - "packed": "0081018202830380", - "unpacked": { - "a": 0, - "c": 283686952306183 - } - }, - { - "packed": "000000000000007f", - "unpacked": { - "a": 127, - "c": 0 - } - }, - { - "packed": "ffffffffffffffff", - "unpacked": { - "a": 127, - "c": 144115188075855871 - } - }, - { - "packed": "00810182028303ff", - "unpacked": { - "a": 127, - "c": 283686952306183 - } - }, - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "c": 0 - } - }, - { - "packed": "ffffffffffffff80", - "unpacked": { - "a": 0, - "c": 144115188075855871 - } - }, - { - "packed": "0081018202830380", - "unpacked": { - "a": 0, - "c": 283686952306183 - } - } - ] - }, - { - "packet": "Packet_Enum_Field", - "tests": [ - { - "packed": "0000000000000001", - "unpacked": { - "a": 1, - "c": 0 - } - }, - { - "packed": "ffffffffffffff81", - "unpacked": { - "a": 1, - "c": 144115188075855871 - } - }, - { - "packed": "08090a0b0c0d0e81", - "unpacked": { - "a": 1, - "c": 4523477106694685 - } - }, - { - "packed": "0000000000000002", - "unpacked": { - "a": 2, - "c": 0 - } - }, - { - "packed": "ffffffffffffff82", - "unpacked": { - "a": 2, - "c": 144115188075855871 - } - }, - { - "packed": "08090a0b0c0d0e82", - "unpacked": { - "a": 2, - "c": 4523477106694685 - } - } - ] - }, - { - "packet": "Packet_Reserved_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "c": 0 - } - }, - { - "packed": "fffffffffffffe00", - "unpacked": { - "a": 0, - "c": 36028797018963967 - } - }, - { - "packed": "1011121314152c00", - "unpacked": { - "a": 0, - "c": 2261184477268630 - } - }, - { - "packed": "000000000000007f", - "unpacked": { - "a": 127, - "c": 0 - } - }, - { - "packed": "fffffffffffffe7f", - "unpacked": { - "a": 127, - "c": 36028797018963967 - } - }, - { - "packed": "1011121314152c7f", - "unpacked": { - "a": 127, - "c": 2261184477268630 - } - }, - { - "packed": "0000000000000007", - "unpacked": { - "a": 7, - "c": 0 - } - }, - { - "packed": "fffffffffffffe07", - "unpacked": { - "a": 7, - "c": 36028797018963967 - } - }, - { - "packed": "1011121314152c07", - "unpacked": { - "a": 7, - "c": 2261184477268630 - } - } - ] - }, - { - "packet": "Packet_Size_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "b": [] - } - }, - { - "packed": "00000000000000071f102122232425", - "unpacked": { - "a": 0, - "b": [ - 31, - 16, - 33, - 34, - 35, - 36, - 37 - ] - } - }, - { - "packed": "fffffffffffffff8", - "unpacked": { - "a": 2305843009213693951, - "b": [] - } - }, - { - "packed": "ffffffffffffffff1f102122232425", - "unpacked": { - "a": 2305843009213693951, - "b": [ - 31, - 16, - 33, - 34, - 35, - 36, - 37 - ] - } - }, - { - "packed": "0b8c0c8d0d8e0ef0", - "unpacked": { - "a": 104006728889254366, - "b": [] - } - }, - { - "packed": "0b8c0c8d0d8e0ef71f102122232425", - "unpacked": { - "a": 104006728889254366, - "b": [ - 31, - 16, - 33, - 34, - 35, - 36, - 37 - ] - } - } - ] - }, - { - "packet": "Packet_Count_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "b": [] - } - }, - { - "packed": "00000000000000072c2f2e31303332", - "unpacked": { - "a": 0, - "b": [ - 44, - 47, - 46, - 49, - 48, - 51, - 50 - ] - } - }, - { - "packed": "fffffffffffffff8", - "unpacked": { - "a": 2305843009213693951, - "b": [] - } - }, - { - "packed": "ffffffffffffffff2c2f2e31303332", - "unpacked": { - "a": 2305843009213693951, - "b": [ - 44, - 47, - 46, - 49, - 48, - 51, - 50 - ] - } - }, - { - "packed": "2262728292a2b2c8", - "unpacked": { - "a": 309708581267330649, - "b": [] - } - }, - { - "packed": "2262728292a2b2cf2c2f2e31303332", - "unpacked": { - "a": 309708581267330649, - "b": [ - 44, - 47, - 46, - 49, - 48, - 51, - 50 - ] - } - } - ] - }, - { - "packet": "Packet_FixedScalar_Field", - "tests": [ - { - "packed": "0000000000000007", - "unpacked": { - "b": 0 - } - }, - { - "packed": "ffffffffffffff87", - "unpacked": { - "b": 144115188075855871 - } - }, - { - "packed": "346a6c6e70727587", - "unpacked": { - "b": 29507425461658859 - } - } - ] - }, - { - "packet": "Packet_FixedEnum_Field", - "tests": [ - { - "packed": "0000000000000001", - "unpacked": { - "b": 0 - } - }, - { - "packed": "ffffffffffffff81", - "unpacked": { - "b": 144115188075855871 - } - }, - { - "packed": "38f0f4f8fd010501", - "unpacked": { - "b": 32055067271627274 - } - } - ] - }, - { - "packet": "Packet_Payload_Field_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "payload": [] - } - }, - { - "packed": "0743444546474049", - "unpacked": { - "payload": [ - 67, - 68, - 69, - 70, - 71, - 64, - 73 - ] - } - } - ] - }, - { - "packet": "Packet_Payload_Field_SizeModifier", - "tests": [ - { - "packed": "02", - "unpacked": { - "payload": [] - } - }, - { - "packed": "074a4b4c4d4e", - "unpacked": { - "payload": [ - 74, - 75, - 76, - 77, - 78 - ] - } - } - ] - }, - { - "packet": "Packet_Payload_Field_UnknownSize", - "tests": [ - { - "packed": "0000", - "unpacked": { - "payload": [], - "a": 0 - } - }, - { - "packed": "ffff", - "unpacked": { - "payload": [], - "a": 65535 - } - }, - { - "packed": "52a5", - "unpacked": { - "payload": [], - "a": 21157 - } - }, - { - "packed": "4f485152530000", - "unpacked": { - "payload": [ - 79, - 72, - 81, - 82, - 83 - ], - "a": 0 - } - }, - { - "packed": "4f48515253ffff", - "unpacked": { - "payload": [ - 79, - 72, - 81, - 82, - 83 - ], - "a": 65535 - } - }, - { - "packed": "4f4851525352a5", - "unpacked": { - "payload": [ - 79, - 72, - 81, - 82, - 83 - ], - "a": 21157 - } - } - ] - }, - { - "packet": "Packet_Payload_Field_UnknownSize_Terminal", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": 0, - "payload": [] - } - }, - { - "packed": "000050595a5b5c", - "unpacked": { - "a": 0, - "payload": [ - 80, - 89, - 90, - 91, - 92 - ] - } - }, - { - "packed": "ffff", - "unpacked": { - "a": 65535, - "payload": [] - } - }, - { - "packed": "ffff50595a5b5c", - "unpacked": { - "a": 65535, - "payload": [ - 80, - 89, - 90, - 91, - 92 - ] - } - }, - { - "packed": "52b7", - "unpacked": { - "a": 21175, - "payload": [] - } - }, - { - "packed": "52b750595a5b5c", - "unpacked": { - "a": 21175, - "payload": [ - 80, - 89, - 90, - 91, - 92 - ] - } - } - ] - }, - { - "packet": "Packet_Body_Field_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "payload": [] - } - }, - { - "packed": "075d5e5f58616263", - "unpacked": { - "payload": [ - 93, - 94, - 95, - 88, - 97, - 98, - 99 - ] - } - } - ] - }, - { - "packet": "Packet_Body_Field_UnknownSize", - "tests": [ - { - "packed": "0000", - "unpacked": { - "payload": [], - "a": 0 - } - }, - { - "packed": "ffff", - "unpacked": { - "payload": [], - "a": 65535 - } - }, - { - "packed": "6b4a", - "unpacked": { - "payload": [], - "a": 27466 - } - }, - { - "packed": "64656667600000", - "unpacked": { - "payload": [ - 100, - 101, - 102, - 103, - 96 - ], - "a": 0 - } - }, - { - "packed": "6465666760ffff", - "unpacked": { - "payload": [ - 100, - 101, - 102, - 103, - 96 - ], - "a": 65535 - } - }, - { - "packed": "64656667606b4a", - "unpacked": { - "payload": [ - 100, - 101, - 102, - 103, - 96 - ], - "a": 27466 - } - } - ] - }, - { - "packet": "Packet_Body_Field_UnknownSize_Terminal", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": 0, - "payload": [] - } - }, - { - "packed": "00006d6e6f6871", - "unpacked": { - "a": 0, - "payload": [ - 109, - 110, - 111, - 104, - 113 - ] - } - }, - { - "packed": "ffff", - "unpacked": { - "a": 65535, - "payload": [] - } - }, - { - "packed": "ffff6d6e6f6871", - "unpacked": { - "a": 65535, - "payload": [ - 109, - 110, - 111, - 104, - 113 - ] - } - }, - { - "packed": "6b5c", - "unpacked": { - "a": 27484, - "payload": [] - } - }, - { - "packed": "6b5c6d6e6f6871", - "unpacked": { - "a": 27484, - "payload": [ - 109, - 110, - 111, - 104, - 113 - ] - } - } - ] - }, - { - "packet": "Packet_ScalarGroup_Field", - "tests": [ - { - "packed": "002a", - "unpacked": {} - } - ] - }, - { - "packet": "Packet_EnumGroup_Field", - "tests": [ - { - "packed": "aabb", - "unpacked": {} - } - ] - }, - { - "packet": "Packet_Checksum_Field_FromStart", - "tests": [ - { - "packed": "0000000000", - "unpacked": { - "a": 0, - "b": 0, - "crc": 0 - } - }, - { - "packed": "0000fffffe", - "unpacked": { - "a": 0, - "b": 65535, - "crc": 254 - } - }, - { - "packed": "000073a518", - "unpacked": { - "a": 0, - "b": 29605, - "crc": 24 - } - }, - { - "packed": "ffff0000fe", - "unpacked": { - "a": 65535, - "b": 0, - "crc": 254 - } - }, - { - "packed": "fffffffffc", - "unpacked": { - "a": 65535, - "b": 65535, - "crc": 252 - } - }, - { - "packed": "ffff73a516", - "unpacked": { - "a": 65535, - "b": 29605, - "crc": 22 - } - }, - { - "packed": "7393000006", - "unpacked": { - "a": 29587, - "b": 0, - "crc": 6 - } - }, - { - "packed": "7393ffff04", - "unpacked": { - "a": 29587, - "b": 65535, - "crc": 4 - } - }, - { - "packed": "739373a51e", - "unpacked": { - "a": 29587, - "b": 29605, - "crc": 30 - } - } - ] - }, - { - "packet": "Packet_Checksum_Field_FromEnd", - "tests": [ - { - "packed": "0000000000", - "unpacked": { - "payload": [], - "crc": 0, - "a": 0, - "b": 0 - } - }, - { - "packed": "000000ffff", - "unpacked": { - "payload": [], - "crc": 0, - "a": 0, - "b": 65535 - } - }, - { - "packed": "0000007bee", - "unpacked": { - "payload": [], - "crc": 0, - "a": 0, - "b": 31726 - } - }, - { - "packed": "00ffff0000", - "unpacked": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 0 - } - }, - { - "packed": "00ffffffff", - "unpacked": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 65535 - } - }, - { - "packed": "00ffff7bee", - "unpacked": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 31726 - } - }, - { - "packed": "007bdc0000", - "unpacked": { - "payload": [], - "crc": 0, - "a": 31708, - "b": 0 - } - }, - { - "packed": "007bdcffff", - "unpacked": { - "payload": [], - "crc": 0, - "a": 31708, - "b": 65535 - } - }, - { - "packed": "007bdc7bee", - "unpacked": { - "payload": [], - "crc": 0, - "a": 31708, - "b": 31726 - } - }, - { - "packed": "767770797a5000000000", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 0, - "b": 0 - } - }, - { - "packed": "767770797a500000ffff", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 0, - "b": 65535 - } - }, - { - "packed": "767770797a5000007bee", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 0, - "b": 31726 - } - }, - { - "packed": "767770797a50ffff0000", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 65535, - "b": 0 - } - }, - { - "packed": "767770797a50ffffffff", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 65535, - "b": 65535 - } - }, - { - "packed": "767770797a50ffff7bee", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 65535, - "b": 31726 - } - }, - { - "packed": "767770797a507bdc0000", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 31708, - "b": 0 - } - }, - { - "packed": "767770797a507bdcffff", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 31708, - "b": 65535 - } - }, - { - "packed": "767770797a507bdc7bee", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 31708, - "b": 31726 - } - } - ] - }, - { - "packet": "Packet_Struct_Field", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": { - "a": 0 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "0003788182", - "unpacked": { - "a": { - "a": 0 - }, - "b": { - "array": [ - 120, - 129, - 130 - ] - } - } - }, - { - "packed": "ff00", - "unpacked": { - "a": { - "a": 255 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "ff03788182", - "unpacked": { - "a": { - "a": 255 - }, - "b": { - "array": [ - 120, - 129, - 130 - ] - } - } - }, - { - "packed": "7f00", - "unpacked": { - "a": { - "a": 127 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "7f03788182", - "unpacked": { - "a": { - "a": 127 - }, - "b": { - "array": [ - 120, - 129, - 130 - ] - } - } - } - ] - }, - { - "packet": "Packet_Array_Field_ByteElement_ConstantSize", - "tests": [ - { - "packed": "83848586", - "unpacked": { - "array": [ - 131, - 132, - 133, - 134 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ByteElement_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "array": [] - } - }, - { - "packed": "0f8780898a8b8c8d8e8f889192939495", - "unpacked": { - "array": [ - 135, - 128, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 136, - 145, - 146, - 147, - 148, - 149 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ByteElement_VariableCount", - "tests": [ - { - "packed": "00", - "unpacked": { - "array": [] - } - }, - { - "packed": "0f969790999a9b9c9d9e9f98a1a2a3a4", - "unpacked": { - "array": [ - 150, - 151, - 144, - 153, - 154, - 155, - 156, - 157, - 158, - 159, - 152, - 161, - 162, - 163, - 164 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ByteElement_UnknownSize", - "tests": [ - { - "packed": "", - "unpacked": { - "array": [] - } - }, - { - "packed": "a5a6a7", - "unpacked": { - "array": [ - 165, - 166, - 167 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ScalarElement_ConstantSize", - "tests": [ - { - "packed": "a541ad53ad65ad77", - "unpacked": { - "array": [ - 42305, - 44371, - 44389, - 44407 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ScalarElement_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "array": [] - } - }, - { - "packed": "0ead81b593b5a5b5b7b5c1bdd3bde5", - "unpacked": { - "array": [ - 44417, - 46483, - 46501, - 46519, - 46529, - 48595, - 48613 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ScalarElement_VariableCount", - "tests": [ - { - "packed": "00", - "unpacked": { - "array": [] - } - }, - { - "packed": "0fbdf7be01c613c625c637c641ce53ce65ce77ce81d693d6a5d6b7d6c1ded3", - "unpacked": { - "array": [ - 48631, - 48641, - 50707, - 50725, - 50743, - 50753, - 52819, - 52837, - 52855, - 52865, - 54931, - 54949, - 54967, - 54977, - 57043 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ScalarElement_UnknownSize", - "tests": [ - { - "packed": "", - "unpacked": { - "array": [] - } - }, - { - "packed": "dee5def7df01", - "unpacked": { - "array": [ - 57061, - 57079, - 57089 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_EnumElement_ConstantSize", - "tests": [ - { - "packed": "aabbccddaabbccdd", - "unpacked": { - "array": [ - 43707, - 52445, - 43707, - 52445 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_EnumElement_VariableSize", - "tests": [ - { - "packed": "0eaabbccddaabbccddaabbccddaabb", - "unpacked": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707 - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_EnumElement_VariableCount", - "tests": [ - { - "packed": "0faabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabb", - "unpacked": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707 - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_EnumElement_UnknownSize", - "tests": [ - { - "packed": "aabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccdd", - "unpacked": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445 - ] - } - }, - { - "packed": "", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_ConstantSize", - "tests": [ - { - "packed": "00ffe200", - "unpacked": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 226 - }, - { - "a": 0 - } - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_VariableSize", - "tests": [ - { - "packed": "0f00ffe400ffe500ffe600ffe700ffe0", - "unpacked": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 228 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 229 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 230 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 231 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 224 - } - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_VariableCount", - "tests": [ - { - "packed": "0f00ffea00ffeb00ffec00ffed00ffee", - "unpacked": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 234 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 235 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 236 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 237 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 238 - } - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_UnknownSize", - "tests": [ - { - "packed": "00ffe800fff100fff200fff300fff400fff500fff600fff700fff000fff900ff", - "unpacked": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 232 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 241 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 242 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 243 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 244 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 245 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 246 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 247 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 240 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 249 - }, - { - "a": 0 - }, - { - "a": 255 - } - ] - } - }, - { - "packed": "", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_ConstantSize", - "tests": [ - { - "packed": "0003fbfcfd0003fef801", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 251, - 252, - 253 - ] - }, - { - "array": [] - }, - { - "array": [ - 254, - 248, - 1 - ] - } - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_VariableSize", - "tests": [ - { - "packed": "0f0003050607000300090a00030b0c0d", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 5, - 6, - 7 - ] - }, - { - "array": [] - }, - { - "array": [ - 0, - 9, - 10 - ] - }, - { - "array": [] - }, - { - "array": [ - 11, - 12, - 13 - ] - } - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_VariableCount", - "tests": [ - { - "packed": "0f00031112130003141516000317101900031a1b1c00031d1e1f0003182122000323242500", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 17, - 18, - 19 - ] - }, - { - "array": [] - }, - { - "array": [ - 20, - 21, - 22 - ] - }, - { - "array": [] - }, - { - "array": [ - 23, - 16, - 25 - ] - }, - { - "array": [] - }, - { - "array": [ - 26, - 27, - 28 - ] - }, - { - "array": [] - }, - { - "array": [ - 29, - 30, - 31 - ] - }, - { - "array": [] - }, - { - "array": [ - 24, - 33, - 34 - ] - }, - { - "array": [] - }, - { - "array": [ - 35, - 36, - 37 - ] - }, - { - "array": [] - } - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_UnknownSize", - "tests": [ - { - "packed": "0003292a2b00032c2d2e00032f283100033233340003353637000330393a00033b3c3d00033e3f3800034142430003444546000347404900034a4b4c00034d4e4f000348515200035354550003565750", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 41, - 42, - 43 - ] - }, - { - "array": [] - }, - { - "array": [ - 44, - 45, - 46 - ] - }, - { - "array": [] - }, - { - "array": [ - 47, - 40, - 49 - ] - }, - { - "array": [] - }, - { - "array": [ - 50, - 51, - 52 - ] - }, - { - "array": [] - }, - { - "array": [ - 53, - 54, - 55 - ] - }, - { - "array": [] - }, - { - "array": [ - 48, - 57, - 58 - ] - }, - { - "array": [] - }, - { - "array": [ - 59, - 60, - 61 - ] - }, - { - "array": [] - }, - { - "array": [ - 62, - 63, - 56 - ] - }, - { - "array": [] - }, - { - "array": [ - 65, - 66, - 67 - ] - }, - { - "array": [] - }, - { - "array": [ - 68, - 69, - 70 - ] - }, - { - "array": [] - }, - { - "array": [ - 71, - 64, - 73 - ] - }, - { - "array": [] - }, - { - "array": [ - 74, - 75, - 76 - ] - }, - { - "array": [] - }, - { - "array": [ - 77, - 78, - 79 - ] - }, - { - "array": [] - }, - { - "array": [ - 72, - 81, - 82 - ] - }, - { - "array": [] - }, - { - "array": [ - 83, - 84, - 85 - ] - }, - { - "array": [] - }, - { - "array": [ - 86, - 87, - 80 - ] - } - ] - } - }, - { - "packed": "", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_SizeModifier", - "tests": [ - { - "packed": "0d00035c5d5e00035f586100", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 92, - 93, - 94 - ] - }, - { - "array": [] - }, - { - "array": [ - 95, - 88, - 97 - ] - }, - { - "array": [] - } - ] - } - }, - { - "packed": "02", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_VariableSize_Padded", - "tests": [ - { - "packed": "0000000000000000000000000000000000", - "unpacked": { - "array": [] - } - }, - { - "packed": "0e632e63386b4a6b5c6b6e6b78738a0000", - "unpacked": { - "array": [ - 25390, - 25400, - 27466, - 27484, - 27502, - 27512, - 29578 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_VariableCount_Padded", - "tests": [ - { - "packed": "07000373747500037677700003797a7b00", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 115, - 116, - 117 - ] - }, - { - "array": [] - }, - { - "array": [ - 118, - 119, - 112 - ] - }, - { - "array": [] - }, - { - "array": [ - 121, - 122, - 123 - ] - }, - { - "array": [] - } - ] - } - }, - { - "packed": "0000000000000000000000000000000000", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "ScalarParent", - "tests": [ - { - "packed": "000100", - "unpacked": { - "a": 0, - "b": 0 - }, - "packet": "ScalarChild_A" - }, - { - "packed": "0001ff", - "unpacked": { - "a": 0, - "b": 255 - }, - "packet": "ScalarChild_A" - }, - { - "packed": "00017f", - "unpacked": { - "a": 0, - "b": 127 - }, - "packet": "ScalarChild_A" - }, - { - "packed": "01020000", - "unpacked": { - "a": 1, - "c": 0 - }, - "packet": "ScalarChild_B" - }, - { - "packed": "0102ffff", - "unpacked": { - "a": 1, - "c": 65535 - }, - "packet": "ScalarChild_B" - }, - { - "packed": "01027c01", - "unpacked": { - "a": 1, - "c": 31745 - }, - "packet": "ScalarChild_B" - }, - { - "packed": "020100", - "unpacked": { - "a": 2, - "b": 0 - }, - "packet": "AliasedChild_A" - }, - { - "packed": "0201ff", - "unpacked": { - "a": 2, - "b": 255 - }, - "packet": "AliasedChild_A" - }, - { - "packed": "020185", - "unpacked": { - "a": 2, - "b": 133 - }, - "packet": "AliasedChild_A" - }, - { - "packed": "03020000", - "unpacked": { - "a": 3, - "c": 0 - }, - "packet": "AliasedChild_B" - }, - { - "packed": "0302ffff", - "unpacked": { - "a": 3, - "c": 65535 - }, - "packet": "AliasedChild_B" - }, - { - "packed": "03028437", - "unpacked": { - "a": 3, - "c": 33847 - }, - "packet": "AliasedChild_B" - } - ] - }, - { - "packet": "EnumParent", - "tests": [ - { - "packed": "aabb0100", - "unpacked": { - "a": 43707, - "b": 0 - }, - "packet": "EnumChild_A" - }, - { - "packed": "aabb01ff", - "unpacked": { - "a": 43707, - "b": 255 - }, - "packet": "EnumChild_A" - }, - { - "packed": "aabb0182", - "unpacked": { - "a": 43707, - "b": 130 - }, - "packet": "EnumChild_A" - }, - { - "packed": "ccdd020000", - "unpacked": { - "a": 52445, - "c": 0 - }, - "packet": "EnumChild_B" - }, - { - "packed": "ccdd02ffff", - "unpacked": { - "a": 52445, - "c": 65535 - }, - "packet": "EnumChild_B" - }, - { - "packed": "ccdd02841c", - "unpacked": { - "a": 52445, - "c": 33820 - }, - "packet": "EnumChild_B" - } - ] - }, - { - "packet": "Struct_Enum_Field", - "tests": [ - { - "packed": "0000000000000001", - "unpacked": { - "s": { - "a": 1, - "c": 0 - } - } - }, - { - "packed": "ffffffffffffff81", - "unpacked": { - "s": { - "a": 1, - "c": 144115188075855871 - } - } - }, - { - "packed": "84444c545c646f01", - "unpacked": { - "s": { - "a": 1, - "c": 74459583098702046 - } - } - }, - { - "packed": "0000000000000002", - "unpacked": { - "s": { - "a": 2, - "c": 0 - } - } - }, - { - "packed": "ffffffffffffff82", - "unpacked": { - "s": { - "a": 2, - "c": 144115188075855871 - } - } - }, - { - "packed": "84444c545c646f02", - "unpacked": { - "s": { - "a": 2, - "c": 74459583098702046 - } - } - } - ] - }, - { - "packet": "Struct_Reserved_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "s": { - "a": 0, - "c": 0 - } - } - }, - { - "packed": "fffffffffffffe00", - "unpacked": { - "s": { - "a": 0, - "c": 36028797018963967 - } - } - }, - { - "packed": "8c848c949ca4ac00", - "unpacked": { - "s": { - "a": 0, - "c": 19776118031536726 - } - } - }, - { - "packed": "000000000000007f", - "unpacked": { - "s": { - "a": 127, - "c": 0 - } - } - }, - { - "packed": "fffffffffffffe7f", - "unpacked": { - "s": { - "a": 127, - "c": 36028797018963967 - } - } - }, - { - "packed": "8c848c949ca4ac7f", - "unpacked": { - "s": { - "a": 127, - "c": 19776118031536726 - } - } - }, - { - "packed": "0000000000000047", - "unpacked": { - "s": { - "a": 71, - "c": 0 - } - } - }, - { - "packed": "fffffffffffffe47", - "unpacked": { - "s": { - "a": 71, - "c": 36028797018963967 - } - } - }, - { - "packed": "8c848c949ca4ac47", - "unpacked": { - "s": { - "a": 71, - "c": 19776118031536726 - } - } - } - ] - }, - { - "packet": "Struct_Size_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "s": { - "a": 0, - "b": [] - } - } - }, - { - "packed": "00000000000000079e9fa0a1a2a3a4", - "unpacked": { - "s": { - "a": 0, - "b": [ - 158, - 159, - 160, - 161, - 162, - 163, - 164 - ] - } - } - }, - { - "packed": "fffffffffffffff8", - "unpacked": { - "s": { - "a": 2305843009213693951, - "b": [] - } - } - }, - { - "packed": "ffffffffffffffff9e9fa0a1a2a3a4", - "unpacked": { - "s": { - "a": 2305843009213693951, - "b": [ - 158, - 159, - 160, - 161, - 162, - 163, - 164 - ] - } - } - }, - { - "packed": "965e62666a6e70e8", - "unpacked": { - "s": { - "a": 1354400743188975133, - "b": [] - } - } - }, - { - "packed": "965e62666a6e70ef9e9fa0a1a2a3a4", - "unpacked": { - "s": { - "a": 1354400743188975133, - "b": [ - 158, - 159, - 160, - 161, - 162, - 163, - 164 - ] - } - } - } - ] - }, - { - "packet": "Struct_Count_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "s": { - "a": 0, - "b": [] - } - } - }, - { - "packed": "0000000000000007adaeafa0b1b2b3", - "unpacked": { - "s": { - "a": 0, - "b": [ - 173, - 174, - 175, - 160, - 177, - 178, - 179 - ] - } - } - }, - { - "packed": "fffffffffffffff8", - "unpacked": { - "s": { - "a": 2305843009213693951, - "b": [] - } - } - }, - { - "packed": "ffffffffffffffffadaeafa0b1b2b3", - "unpacked": { - "s": { - "a": 2305843009213693951, - "b": [ - 173, - 174, - 175, - 160, - 177, - 178, - 179 - ] - } - } - }, - { - "packed": "d2d353d454d555e0", - "unpacked": { - "s": { - "a": 1898947267434031804, - "b": [] - } - } - }, - { - "packed": "d2d353d454d555e7adaeafa0b1b2b3", - "unpacked": { - "s": { - "a": 1898947267434031804, - "b": [ - 173, - 174, - 175, - 160, - 177, - 178, - 179 - ] - } - } - } - ] - }, - { - "packet": "Struct_FixedScalar_Field", - "tests": [ - { - "packed": "0000000000000007", - "unpacked": { - "s": { - "b": 0 - } - } - }, - { - "packed": "ffffffffffffff87", - "unpacked": { - "s": { - "b": 144115188075855871 - } - } - }, - { - "packed": "bb4b5b6b7b8b9d07", - "unpacked": { - "s": { - "b": 105437353324517178 - } - } - } - ] - }, - { - "packet": "Struct_FixedEnum_Field", - "tests": [ - { - "packed": "0000000000000001", - "unpacked": { - "s": { - "b": 0 - } - } - }, - { - "packed": "ffffffffffffff81", - "unpacked": { - "s": { - "b": 144115188075855871 - } - } - }, - { - "packed": "b77797b7d7f80081", - "unpacked": { - "s": { - "b": 103282828492402689 - } - } - } - ] - }, - { - "packet": "Struct_ScalarGroup_Field", - "tests": [ - { - "packed": "002a", - "unpacked": { - "s": {} - } - } - ] - }, - { - "packet": "Struct_EnumGroup_Field", - "tests": [ - { - "packed": "aabb", - "unpacked": { - "s": {} - } - } - ] - }, - { - "packet": "Struct_Checksum_Field_FromStart", - "tests": [ - { - "packed": "0000000000", - "unpacked": { - "s": { - "a": 0, - "b": 0, - "crc": 0 - } - } - }, - { - "packed": "0000fffffe", - "unpacked": { - "s": { - "a": 0, - "b": 65535, - "crc": 254 - } - } - }, - { - "packed": "0000f105f6", - "unpacked": { - "s": { - "a": 0, - "b": 61701, - "crc": 246 - } - } - }, - { - "packed": "ffff0000fe", - "unpacked": { - "s": { - "a": 65535, - "b": 0, - "crc": 254 - } - } - }, - { - "packed": "fffffffffc", - "unpacked": { - "s": { - "a": 65535, - "b": 65535, - "crc": 252 - } - } - }, - { - "packed": "fffff105f4", - "unpacked": { - "s": { - "a": 65535, - "b": 61701, - "crc": 244 - } - } - }, - { - "packed": "f083000073", - "unpacked": { - "s": { - "a": 61571, - "b": 0, - "crc": 115 - } - } - }, - { - "packed": "f083ffff71", - "unpacked": { - "s": { - "a": 61571, - "b": 65535, - "crc": 113 - } - } - }, - { - "packed": "f083f10569", - "unpacked": { - "s": { - "a": 61571, - "b": 61701, - "crc": 105 - } - } - } - ] - }, - { - "packet": "Struct_Checksum_Field_FromEnd", - "tests": [ - { - "packed": "0000000000", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 0, - "b": 0 - } - } - }, - { - "packed": "000000ffff", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 0, - "b": 65535 - } - } - }, - { - "packed": "000000f34e", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 0, - "b": 62286 - } - } - }, - { - "packed": "00ffff0000", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 0 - } - } - }, - { - "packed": "00ffffffff", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 65535 - } - } - }, - { - "packed": "00fffff34e", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 62286 - } - } - }, - { - "packed": "00f2cc0000", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 62156, - "b": 0 - } - } - }, - { - "packed": "00f2ccffff", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 62156, - "b": 65535 - } - } - }, - { - "packed": "00f2ccf34e", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 62156, - "b": 62286 - } - } - }, - { - "packed": "c6c7c8c9cae800000000", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 0, - "b": 0 - } - } - }, - { - "packed": "c6c7c8c9cae80000ffff", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 0, - "b": 65535 - } - } - }, - { - "packed": "c6c7c8c9cae80000f34e", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 0, - "b": 62286 - } - } - }, - { - "packed": "c6c7c8c9cae8ffff0000", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 65535, - "b": 0 - } - } - }, - { - "packed": "c6c7c8c9cae8ffffffff", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 65535, - "b": 65535 - } - } - }, - { - "packed": "c6c7c8c9cae8fffff34e", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 65535, - "b": 62286 - } - } - }, - { - "packed": "c6c7c8c9cae8f2cc0000", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 62156, - "b": 0 - } - } - }, - { - "packed": "c6c7c8c9cae8f2ccffff", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 62156, - "b": 65535 - } - } - }, - { - "packed": "c6c7c8c9cae8f2ccf34e", - "unpacked": { - "s": { - "payload": [ - 198, - 199, - 200, - 201, - 202 - ], - "crc": 232, - "a": 62156, - "b": 62286 - } - } - } - ] - }, - { - "packet": "Struct_Struct_Field", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": { - "a": 0 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "0003d0d1d2", - "unpacked": { - "a": { - "a": 0 - }, - "b": { - "array": [ - 208, - 209, - 210 - ] - } - } - }, - { - "packed": "ff00", - "unpacked": { - "a": { - "a": 255 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "ff03d0d1d2", - "unpacked": { - "a": { - "a": 255 - }, - "b": { - "array": [ - 208, - 209, - 210 - ] - } - } - }, - { - "packed": "cf00", - "unpacked": { - "a": { - "a": 207 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "cf03d0d1d2", - "unpacked": { - "a": { - "a": 207 - }, - "b": { - "array": [ - 208, - 209, - 210 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ByteElement_ConstantSize", - "tests": [ - { - "packed": "d3d4d5d6", - "unpacked": { - "s": { - "array": [ - 211, - 212, - 213, - 214 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ByteElement_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0fd7d8d9dadbdcdddedfe0e1e2e3e4e5", - "unpacked": { - "s": { - "array": [ - 215, - 216, - 217, - 218, - 219, - 220, - 221, - 222, - 223, - 224, - 225, - 226, - 227, - 228, - 229 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ByteElement_VariableCount", - "tests": [ - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0fe6e7e8e9eaebecedeeeff0f1f2f3f4", - "unpacked": { - "s": { - "array": [ - 230, - 231, - 232, - 233, - 234, - 235, - 236, - 237, - 238, - 239, - 240, - 241, - 242, - 243, - 244 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ByteElement_UnknownSize", - "tests": [ - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "f5f6f7", - "unpacked": { - "s": { - "array": [ - 245, - 246, - 247 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ScalarElement_ConstantSize", - "tests": [ - { - "packed": "fe39febbff3dff80", - "unpacked": { - "s": { - "array": [ - 65081, - 65211, - 65341, - 65408 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ScalarElement_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0e004200c4014601c8024a02cc034e", - "unpacked": { - "s": { - "array": [ - 66, - 196, - 326, - 456, - 586, - 716, - 846 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ScalarElement_VariableCount", - "tests": [ - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0f03d0045204d4055605d8065a06dc075e07e0086208e4096609e80a6a0aec", - "unpacked": { - "s": { - "array": [ - 976, - 1106, - 1236, - 1366, - 1496, - 1626, - 1756, - 1886, - 2016, - 2146, - 2276, - 2406, - 2536, - 2666, - 2796 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ScalarElement_UnknownSize", - "tests": [ - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0b6e0bf00c72", - "unpacked": { - "s": { - "array": [ - 2926, - 3056, - 3186 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_EnumElement_ConstantSize", - "tests": [ - { - "packed": "aabbccddaabbccdd", - "unpacked": { - "s": { - "array": [ - 43707, - 52445, - 43707, - 52445 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_EnumElement_VariableSize", - "tests": [ - { - "packed": "0eaabbccddaabbccddaabbccddaabb", - "unpacked": { - "s": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707 - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_EnumElement_VariableCount", - "tests": [ - { - "packed": "0faabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabb", - "unpacked": { - "s": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707 - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_EnumElement_UnknownSize", - "tests": [ - { - "packed": "aabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccdd", - "unpacked": { - "s": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445 - ] - } - } - }, - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_ConstantSize", - "tests": [ - { - "packed": "00ff3300", - "unpacked": { - "s": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 51 - }, - { - "a": 0 - } - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_VariableSize", - "tests": [ - { - "packed": "0f00ff3500ff3600ff3700ff3800ff39", - "unpacked": { - "s": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 53 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 54 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 55 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 56 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 57 - } - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_VariableCount", - "tests": [ - { - "packed": "0f00ff3b00ff3c00ff3d00ff3e00ff3f", - "unpacked": { - "s": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 59 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 60 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 61 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 62 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 63 - } - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_UnknownSize", - "tests": [ - { - "packed": "00ff4100ff4200ff4300ff4400ff4500ff4600ff4700ff4800ff4900ff4a00ff", - "unpacked": { - "s": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 65 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 66 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 67 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 68 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 69 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 70 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 71 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 72 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 73 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 74 - }, - { - "a": 0 - }, - { - "a": 255 - } - ] - } - } - }, - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_ConstantSize", - "tests": [ - { - "packed": "00034c4d4e00034f5051", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 76, - 77, - 78 - ] - }, - { - "array": [] - }, - { - "array": [ - 79, - 80, - 81 - ] - } - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_VariableSize", - "tests": [ - { - "packed": "0f0003555657000358595a00035b5c5d", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 85, - 86, - 87 - ] - }, - { - "array": [] - }, - { - "array": [ - 88, - 89, - 90 - ] - }, - { - "array": [] - }, - { - "array": [ - 91, - 92, - 93 - ] - } - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_VariableCount", - "tests": [ - { - "packed": "0f00036162630003646566000367686900036a6b6c00036d6e6f0003707172000373747500", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 97, - 98, - 99 - ] - }, - { - "array": [] - }, - { - "array": [ - 100, - 101, - 102 - ] - }, - { - "array": [] - }, - { - "array": [ - 103, - 104, - 105 - ] - }, - { - "array": [] - }, - { - "array": [ - 106, - 107, - 108 - ] - }, - { - "array": [] - }, - { - "array": [ - 109, - 110, - 111 - ] - }, - { - "array": [] - }, - { - "array": [ - 112, - 113, - 114 - ] - }, - { - "array": [] - }, - { - "array": [ - 115, - 116, - 117 - ] - }, - { - "array": [] - } - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_UnknownSize", - "tests": [ - { - "packed": "0003797a7b00037c7d7e00037f408100038283840003858687000388898a00038b8c8d00038e8f9000039192930003949596000397989900039a9b9c00039d9e9f0003a0a1a20003a3a4a50003a6a7a8", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 121, - 122, - 123 - ] - }, - { - "array": [] - }, - { - "array": [ - 124, - 125, - 126 - ] - }, - { - "array": [] - }, - { - "array": [ - 127, - 64, - 129 - ] - }, - { - "array": [] - }, - { - "array": [ - 130, - 131, - 132 - ] - }, - { - "array": [] - }, - { - "array": [ - 133, - 134, - 135 - ] - }, - { - "array": [] - }, - { - "array": [ - 136, - 137, - 138 - ] - }, - { - "array": [] - }, - { - "array": [ - 139, - 140, - 141 - ] - }, - { - "array": [] - }, - { - "array": [ - 142, - 143, - 144 - ] - }, - { - "array": [] - }, - { - "array": [ - 145, - 146, - 147 - ] - }, - { - "array": [] - }, - { - "array": [ - 148, - 149, - 150 - ] - }, - { - "array": [] - }, - { - "array": [ - 151, - 152, - 153 - ] - }, - { - "array": [] - }, - { - "array": [ - 154, - 155, - 156 - ] - }, - { - "array": [] - }, - { - "array": [ - 157, - 158, - 159 - ] - }, - { - "array": [] - }, - { - "array": [ - 160, - 161, - 162 - ] - }, - { - "array": [] - }, - { - "array": [ - 163, - 164, - 165 - ] - }, - { - "array": [] - }, - { - "array": [ - 166, - 167, - 168 - ] - } - ] - } - } - }, - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_SizeModifier", - "tests": [ - { - "packed": "0d0003acadae0003afb0b100", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 172, - 173, - 174 - ] - }, - { - "array": [] - }, - { - "array": [ - 175, - 176, - 177 - ] - }, - { - "array": [] - } - ] - } - } - }, - { - "packed": "02", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_VariableSize_Padded", - "tests": [ - { - "packed": "0000000000000000000000000000000000", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0ead76adf8ae7aaefcaf7eafc0f0420000", - "unpacked": { - "s": { - "array": [ - 44406, - 44536, - 44666, - 44796, - 44926, - 44992, - 61506 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_VariableCount_Padded", - "tests": [ - { - "packed": "070003c3c4c50003c6c7c80003c9cacb00", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 195, - 196, - 197 - ] - }, - { - "array": [] - }, - { - "array": [ - 198, - 199, - 200 - ] - }, - { - "array": [] - }, - { - "array": [ - 201, - 202, - 203 - ] - }, - { - "array": [] - } - ] - } - } - }, - { - "packed": "0000000000000000000000000000000000", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - } -] \ No newline at end of file diff --git a/tools/pdl/tests/canonical/le_rust_noalloc_test_file.pdl b/tools/pdl/tests/canonical/le_rust_noalloc_test_file.pdl deleted file mode 100644 index 7137fae32bb1b6e0afc951ffebd31fab055f712c..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/canonical/le_rust_noalloc_test_file.pdl +++ /dev/null @@ -1,610 +0,0 @@ -little_endian_packets - - -enum Enum7 : 7 { - A = 1, - B = 2, -} - -enum Enum16 : 16 { - A = 0xaabb, - B = 0xccdd, -} - -struct SizedStruct { - a: 8, -} - -struct UnsizedStruct { - _size_(array): 2, - _reserved_: 6, - array: 8[], -} - -packet ScalarParent { - a: 8, - _size_(_payload_): 8, - _payload_ -} - -packet EnumParent { - a: Enum16, - _size_(_payload_): 8, - _payload_ -} - -packet EmptyParent : ScalarParent { - _payload_ -} - -packet PartialParent5 { - a: 5, - _payload_ -} - -packet PartialParent12 { - a: 12, - _payload_ -} - -// Packet bit fields - -// The parser must be able to handle bit fields with scalar values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Scalar_Field { - a: 7, - c: 57, -} - -// The parser must be able to handle bit fields with enum values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Enum_Field { - a: Enum7, - c: 57, -} - -// The parser must be able to handle bit fields with reserved fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Reserved_Field { - a: 7, - _reserved_: 2, - c: 55, -} - -// The parser must be able to handle bit fields with size fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Size_Field { - _size_(b): 3, - a: 61, - b: 8[], -} - -// The parser must be able to handle bit fields with count fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Count_Field { - _count_(b): 3, - a: 61, - b: 8[], -} - -// The parser must be able to handle bit fields with fixed scalar values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_FixedScalar_Field { - _fixed_ = 7 : 7, - b: 57, -} - -// The parser must be able to handle bit fields with fixed enum values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_FixedEnum_Field { - _fixed_ = A : Enum7, - b: 57, -} - -// Packet payload fields - -// The parser must be able to handle sized payload fields without -// size modifier. -packet Packet_Payload_Field_VariableSize { - _size_(_payload_): 3, - _reserved_: 5, - _payload_ -} - -// The parser must be able to handle payload fields of unkonwn size followed -// by fields of statically known size. The remaining span is integrated -// in the packet. -packet Packet_Payload_Field_UnknownSize { - _payload_, - a: 16, -} - -// The parser must be able to handle payload fields of unkonwn size. -// The remaining span is integrated in the packet. -packet Packet_Payload_Field_UnknownSize_Terminal { - a: 16, - _payload_, -} - -// Packet body fields - -// The parser must be able to handle sized body fields without -// size modifier when the packet has no children. -packet Packet_Body_Field_VariableSize { - _size_(_body_): 3, - _reserved_: 5, - _body_ -} - -// The parser must be able to handle body fields of unkonwn size followed -// by fields of statically known size. The remaining span is integrated -// in the packet. -packet Packet_Body_Field_UnknownSize { - _body_, - a: 16, -} - -// The parser must be able to handle body fields of unkonwn size. -// The remaining span is integrated in the packet. -packet Packet_Body_Field_UnknownSize_Terminal { - a: 16, - _payload_, -} - -// Packet typedef fields - -// The parser must be able to handle struct fields. -// The size guard is generated by the Struct parser. -packet Packet_Struct_Field { - a: SizedStruct, - b: UnsizedStruct, -} - -// Array field configurations. -// Add constructs for all configurations of type, size, and padding: -// -// - type: u8, u16, enum, struct with static size, struct with dynamic size -// - size: constant, with size field, with count field, unspecified -// -// The type u8 is tested separately since it is likely to be handled -// idiomatically by the specific language generators. - -packet Packet_Array_Field_ByteElement_ConstantSize { - array: 8[4], -} - -packet Packet_Array_Field_ByteElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: 8[], -} - -packet Packet_Array_Field_ByteElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: 8[], -} - -packet Packet_Array_Field_ByteElement_UnknownSize { - array: 8[], -} - -packet Packet_Array_Field_ScalarElement_ConstantSize { - array: 16[4], -} - -packet Packet_Array_Field_ScalarElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: 16[], -} - -packet Packet_Array_Field_ScalarElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: 16[], -} - -packet Packet_Array_Field_ScalarElement_UnknownSize { - array: 16[], -} - -packet Packet_Array_Field_EnumElement_ConstantSize { - array: Enum16[4], -} - -packet Packet_Array_Field_EnumElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: Enum16[], -} - -packet Packet_Array_Field_EnumElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: Enum16[], -} - -packet Packet_Array_Field_EnumElement_UnknownSize { - array: Enum16[], -} - -packet Packet_Array_Field_SizedElement_ConstantSize { - array: SizedStruct[4], -} - -packet Packet_Array_Field_SizedElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} - -packet Packet_Array_Field_SizedElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} - -packet Packet_Array_Field_SizedElement_UnknownSize { - array: SizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_ConstantSize { - array: UnsizedStruct[4], -} - -packet Packet_Array_Field_UnsizedElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_UnknownSize { - array: UnsizedStruct[], -} - -// The parser must be able to handle arrays with padded size. -packet Packet_Array_Field_SizedElement_VariableSize_Padded { - _size_(array) : 4, - _reserved_: 4, - array: 16[], - _padding_ [16], -} - -// The parser must be able to handle arrays with padded size. -packet Packet_Array_Field_UnsizedElement_VariableCount_Padded { - _count_(array) : 8, - array: UnsizedStruct[], - _padding_ [16], -} - -// Packet inheritance - -// The parser must handle specialization into -// any child packet of a parent packet with scalar constraints. -packet ScalarChild_A : ScalarParent (a = 0) { - b: 8, -} - -// The parser must handle specialization into -// any child packet of a parent packet with scalar constraints. -packet ScalarChild_B : ScalarParent (a = 1) { - c: 16, -} - -// The parser must handle specialization into -// any child packet of a parent packet with enum constraints. -packet EnumChild_A : EnumParent (a = A) { - b: 8, -} - -// The parser must handle specialization into -// any child packet of a parent packet with enum constraints. -packet EnumChild_B : EnumParent (a = B) { - c: 16, -} - -// The parser must handle inheritance of packets with payloads starting -// on a shifted byte boundary, as long as the first fields of the child -// complete the bit fields. -packet PartialChild5_A : PartialParent5 (a = 0) { - b: 11, -} - -// The parser must handle inheritance of packets with payloads starting -// on a shifted byte boundary, as long as the first fields of the child -// complete the bit fields. -packet PartialChild5_B : PartialParent5 (a = 1) { - c: 27, -} - -// The parser must handle inheritance of packets with payloads starting -// on a shifted byte boundary, as long as the first fields of the child -// complete the bit fields. -packet PartialChild12_A : PartialParent12 (a = 2) { - d: 4, -} - -// The parser must handle inheritance of packets with payloads starting -// on a shifted byte boundary, as long as the first fields of the child -// complete the bit fields. -packet PartialChild12_B : PartialParent12 (a = 3) { - e: 20, -} - -// Struct bit fields - -// The parser must be able to handle bit fields with scalar values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Scalar_Field { - a: 7, - c: 57, -} - -// The parser must be able to handle bit fields with enum values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Enum_Field_ { - a: Enum7, - c: 57, -} -packet Struct_Enum_Field { - s: Struct_Enum_Field_, -} - -// The parser must be able to handle bit fields with reserved fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Reserved_Field_ { - a: 7, - _reserved_: 2, - c: 55, -} -packet Struct_Reserved_Field { - s: Struct_Reserved_Field_, -} - -// The parser must be able to handle bit fields with size fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Size_Field_ { - _size_(b): 3, - a: 61, - b: 8[], -} -packet Struct_Size_Field { - s: Struct_Size_Field_, -} - -// The parser must be able to handle bit fields with count fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Count_Field_ { - _count_(b): 3, - a: 61, - b: 8[], -} -packet Struct_Count_Field { - s: Struct_Count_Field_, -} - -// The parser must be able to handle bit fields with fixed scalar values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_FixedScalar_Field_ { - _fixed_ = 7 : 7, - b: 57, -} -packet Struct_FixedScalar_Field { - s: Struct_FixedScalar_Field_, -} - -// The parser must be able to handle bit fields with fixed enum values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_FixedEnum_Field_ { - _fixed_ = A : Enum7, - b: 57, -} -packet Struct_FixedEnum_Field { - s: Struct_FixedEnum_Field_, -} - -// Struct typedef fields - -// The parser must be able to handle struct fields. -// The size guard is generated by the Struct parser. -packet Struct_Struct_Field { - a: SizedStruct, - b: UnsizedStruct, -} - -// Array field configurations. -// Add constructs for all configurations of type, size, and padding: -// -// - type: u8, u16, enum, struct with static size, struct with dynamic size -// - size: constant, with size field, with count field, unspecified -// -// The type u8 is tested separately since it is likely to be handled -// idiomatically by the specific language generators. - -struct Struct_Array_Field_ByteElement_ConstantSize_ { - array: 8[4], -} -packet Struct_Array_Field_ByteElement_ConstantSize { - s: Struct_Array_Field_ByteElement_ConstantSize_, -} - -struct Struct_Array_Field_ByteElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: 8[], -} -packet Struct_Array_Field_ByteElement_VariableSize { - s: Struct_Array_Field_ByteElement_VariableSize_, -} - -struct Struct_Array_Field_ByteElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: 8[], -} -packet Struct_Array_Field_ByteElement_VariableCount { - s: Struct_Array_Field_ByteElement_VariableCount_, -} - -struct Struct_Array_Field_ByteElement_UnknownSize_ { - array: 8[], -} -packet Struct_Array_Field_ByteElement_UnknownSize { - s: Struct_Array_Field_ByteElement_UnknownSize_, -} - -struct Struct_Array_Field_ScalarElement_ConstantSize_ { - array: 16[4], -} -packet Struct_Array_Field_ScalarElement_ConstantSize { - s: Struct_Array_Field_ScalarElement_ConstantSize_, -} - -struct Struct_Array_Field_ScalarElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: 16[], -} -packet Struct_Array_Field_ScalarElement_VariableSize { - s: Struct_Array_Field_ScalarElement_VariableSize_, -} - -struct Struct_Array_Field_ScalarElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: 16[], -} -packet Struct_Array_Field_ScalarElement_VariableCount { - s: Struct_Array_Field_ScalarElement_VariableCount_, -} - -struct Struct_Array_Field_ScalarElement_UnknownSize_ { - array: 16[], -} -packet Struct_Array_Field_ScalarElement_UnknownSize { - s: Struct_Array_Field_ScalarElement_UnknownSize_, -} - -struct Struct_Array_Field_EnumElement_ConstantSize_ { - array: Enum16[4], -} -packet Struct_Array_Field_EnumElement_ConstantSize { - s: Struct_Array_Field_EnumElement_ConstantSize_, -} - -struct Struct_Array_Field_EnumElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_VariableSize { - s: Struct_Array_Field_EnumElement_VariableSize_, -} - -struct Struct_Array_Field_EnumElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_VariableCount { - s: Struct_Array_Field_EnumElement_VariableCount_, -} - -struct Struct_Array_Field_EnumElement_UnknownSize_ { - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_UnknownSize { - s: Struct_Array_Field_EnumElement_UnknownSize_, -} - -struct Struct_Array_Field_SizedElement_ConstantSize_ { - array: SizedStruct[4], -} -packet Struct_Array_Field_SizedElement_ConstantSize { - s: Struct_Array_Field_SizedElement_ConstantSize_, -} - -struct Struct_Array_Field_SizedElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_VariableSize { - s: Struct_Array_Field_SizedElement_VariableSize_, -} - -struct Struct_Array_Field_SizedElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_VariableCount { - s: Struct_Array_Field_SizedElement_VariableCount_, -} - -struct Struct_Array_Field_SizedElement_UnknownSize_ { - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_UnknownSize { - s: Struct_Array_Field_SizedElement_UnknownSize_, -} - -struct Struct_Array_Field_UnsizedElement_ConstantSize_ { - array: UnsizedStruct[4], -} -packet Struct_Array_Field_UnsizedElement_ConstantSize { - s: Struct_Array_Field_UnsizedElement_ConstantSize_, -} - -struct Struct_Array_Field_UnsizedElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_VariableSize { - s: Struct_Array_Field_UnsizedElement_VariableSize_, -} - -struct Struct_Array_Field_UnsizedElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_VariableCount { - s: Struct_Array_Field_UnsizedElement_VariableCount_, -} - -struct Struct_Array_Field_UnsizedElement_UnknownSize_ { - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_UnknownSize { - s: Struct_Array_Field_UnsizedElement_UnknownSize_, -} - -// The parser must be able to handle arrays with padded size. -struct Struct_Array_Field_SizedElement_VariableSize_Padded_ { - _size_(array) : 4, - _reserved_: 4, - array: 16[], - _padding_ [16], -} -packet Struct_Array_Field_SizedElement_VariableSize_Padded { - s: Struct_Array_Field_SizedElement_VariableSize_Padded_, -} - -// The parser must be able to handle arrays with padded size. -struct Struct_Array_Field_UnsizedElement_VariableCount_Padded_ { - _count_(array) : 8, - array: UnsizedStruct[], - _padding_ [16], -} -packet Struct_Array_Field_UnsizedElement_VariableCount_Padded { - s: Struct_Array_Field_UnsizedElement_VariableCount_Padded_, -} diff --git a/tools/pdl/tests/canonical/le_rust_test_file.pdl b/tools/pdl/tests/canonical/le_rust_test_file.pdl deleted file mode 100644 index d1450de564bead7aaedcb5e87b657dd3007db9a2..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/canonical/le_rust_test_file.pdl +++ /dev/null @@ -1,538 +0,0 @@ -little_endian_packets - -// Preliminary definitions - -enum MaxDiscriminantEnum : 64 { - Max = 0xffffffffffffffff, -} - -enum Enum7 : 7 { - A = 1, - B = 2, -} - -enum Enum16 : 16 { - A = 0xaabb, - B = 0xccdd, -} - -struct SizedStruct { - a: 8, -} - -struct UnsizedStruct { - _size_(array): 2, - _reserved_: 6, - array: 8[], -} - -packet ScalarParent { - a: 8, - _size_(_payload_): 8, - _payload_ -} - -packet EnumParent { - a: Enum16, - _size_(_payload_): 8, - _payload_ -} - -// Packet bit fields - -// The parser must be able to handle bit fields with scalar values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Scalar_Field { - a: 7, - c: 57, -} - -// The parser must be able to handle bit fields with enum values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Enum_Field { - a: Enum7, - c: 57, -} - -// The parser must be able to handle bit fields with reserved fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Reserved_Field { - a: 7, - _reserved_: 2, - c: 55, -} - -// The parser must be able to handle bit fields with size fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Size_Field { - _size_(b): 3, - a: 61, - b: 8[], -} - -// The parser must be able to handle bit fields with count fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Count_Field { - _count_(b): 3, - a: 61, - b: 8[], -} - -// The parser must be able to handle bit fields with fixed scalar values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_FixedScalar_Field { - _fixed_ = 7 : 7, - b: 57, -} - -// The parser must be able to handle bit fields with fixed enum values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_FixedEnum_Field { - _fixed_ = A : Enum7, - b: 57, -} - -// Packet payload fields - -// The parser must be able to handle sized payload fields without -// size modifier. -packet Packet_Payload_Field_VariableSize { - _size_(_payload_): 3, - _reserved_: 5, - _payload_ -} - -// The parser must be able to handle payload fields of unkonwn size followed -// by fields of statically known size. The remaining span is integrated -// in the packet. -packet Packet_Payload_Field_UnknownSize { - _payload_, - a: 16, -} - -// The parser must be able to handle payload fields of unkonwn size. -// The remaining span is integrated in the packet. -packet Packet_Payload_Field_UnknownSize_Terminal { - a: 16, - _payload_, -} - -// Packet body fields - -// The parser must be able to handle sized body fields without -// size modifier when the packet has no children. -packet Packet_Body_Field_VariableSize { - _size_(_body_): 3, - _reserved_: 5, - _body_ -} - -// The parser must be able to handle body fields of unkonwn size followed -// by fields of statically known size. The remaining span is integrated -// in the packet. -packet Packet_Body_Field_UnknownSize { - _body_, - a: 16, -} - -// The parser must be able to handle body fields of unkonwn size. -// The remaining span is integrated in the packet. -packet Packet_Body_Field_UnknownSize_Terminal { - a: 16, - _body_, -} - -// Packet typedef fields - -// The parser must be able to handle struct fields. -// The size guard is generated by the Struct parser. -packet Packet_Struct_Field { - a: SizedStruct, - b: UnsizedStruct, -} - - -// Array field configurations. -// Add constructs for all configurations of type, size, and padding: -// -// - type: u8, u16, enum, struct with static size, struct with dynamic size -// - size: constant, with size field, with count field, unspecified -// -// The type u8 is tested separately since it is likely to be handled -// idiomatically by the specific language generators. -packet Packet_Array_Field_ByteElement_ConstantSize { - array: 8[4], -} - -packet Packet_Array_Field_ByteElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: 8[], -} - -packet Packet_Array_Field_ByteElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: 8[], -} - -packet Packet_Array_Field_ByteElement_UnknownSize { - array: 8[], -} - -packet Packet_Array_Field_ScalarElement_ConstantSize { - array: 16[4], -} - -packet Packet_Array_Field_ScalarElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: 16[], -} - -packet Packet_Array_Field_ScalarElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: 16[], -} - -packet Packet_Array_Field_ScalarElement_UnknownSize { - array: 16[], -} - -packet Packet_Array_Field_EnumElement_ConstantSize { - array: Enum16[4], -} - -packet Packet_Array_Field_EnumElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: Enum16[], -} - -packet Packet_Array_Field_EnumElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: Enum16[], -} - -packet Packet_Array_Field_EnumElement_UnknownSize { - array: Enum16[], -} - -packet Packet_Array_Field_SizedElement_ConstantSize { - array: SizedStruct[4], -} - -packet Packet_Array_Field_SizedElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} - -packet Packet_Array_Field_SizedElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} - -packet Packet_Array_Field_SizedElement_UnknownSize { - array: SizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_ConstantSize { - array: UnsizedStruct[4], -} - -packet Packet_Array_Field_UnsizedElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_UnknownSize { - array: UnsizedStruct[], -} - -// Packet inheritance - -// The parser must handle specialization into -// any child packet of a parent packet with scalar constraints. -packet ScalarChild_A : ScalarParent (a = 0) { - b: 8, -} - -// The parser must handle specialization into -// any child packet of a parent packet with scalar constraints. -packet ScalarChild_B : ScalarParent (a = 1) { - c: 16, -} - -// The parser must handle specialization into -// any child packet of a parent packet with enum constraints. -packet EnumChild_A : EnumParent (a = A) { - b: 8, -} - -// The parser must handle specialization into -// any child packet of a parent packet with enum constraints. -packet EnumChild_B : EnumParent (a = B) { - c: 16, -} - -// Struct bit fields - -// The parser must be able to handle bit fields with scalar values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Scalar_Field { - a: 7, - c: 57, -} - -// The parser must be able to handle bit fields with enum values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Enum_Field_ { - a: Enum7, - c: 57, -} -packet Struct_Enum_Field { - s: Struct_Enum_Field_, -} - -// The parser must be able to handle bit fields with reserved fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Reserved_Field_ { - a: 7, - _reserved_: 2, - c: 55, -} -packet Struct_Reserved_Field { - s: Struct_Reserved_Field_, -} - -// The parser must be able to handle bit fields with size fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Size_Field_ { - _size_(b): 3, - a: 61, - b: 8[], -} -packet Struct_Size_Field { - s: Struct_Size_Field_, -} - -// The parser must be able to handle bit fields with count fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Count_Field_ { - _count_(b): 3, - a: 61, - b: 8[], -} -packet Struct_Count_Field { - s: Struct_Count_Field_, -} -// The parser must be able to handle bit fields with fixed scalar values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_FixedScalar_Field_ { - _fixed_ = 7 : 7, - b: 57, -} -packet Struct_FixedScalar_Field { - s: Struct_FixedScalar_Field_, -} - -// The parser must be able to handle bit fields with fixed enum values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_FixedEnum_Field_ { - _fixed_ = A : Enum7, - b: 57, -} -packet Struct_FixedEnum_Field { - s: Struct_FixedEnum_Field_, -} - -// Struct typedef fields - -// The parser must be able to handle struct fields. -// The size guard is generated by the Struct parser. -packet Struct_Struct_Field { - a: SizedStruct, - b: UnsizedStruct, -} - -// Array field configurations. -// Add constructs for all configurations of type, size, and padding: -// -// - type: u8, u16, enum, struct with static size, struct with dynamic size -// - size: constant, with size field, with count field, unspecified -// -// The type u8 is tested separately since it is likely to be handled -// idiomatically by the specific language generators. - -struct Struct_Array_Field_ByteElement_ConstantSize_ { - array: 8[4], -} -packet Struct_Array_Field_ByteElement_ConstantSize { - s: Struct_Array_Field_ByteElement_ConstantSize_, -} - - -struct Struct_Array_Field_ByteElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: 8[], -} -packet Struct_Array_Field_ByteElement_VariableSize { - s: Struct_Array_Field_ByteElement_VariableSize_, -} - -struct Struct_Array_Field_ByteElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: 8[], -} -packet Struct_Array_Field_ByteElement_VariableCount { - s: Struct_Array_Field_ByteElement_VariableCount_, -} - -struct Struct_Array_Field_ByteElement_UnknownSize_ { - array: 8[], -} -packet Struct_Array_Field_ByteElement_UnknownSize { - s: Struct_Array_Field_ByteElement_UnknownSize_, -} - -struct Struct_Array_Field_ScalarElement_ConstantSize_ { - array: 16[4], -} -packet Struct_Array_Field_ScalarElement_ConstantSize { - s: Struct_Array_Field_ScalarElement_ConstantSize_, -} - -struct Struct_Array_Field_ScalarElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: 16[], -} -packet Struct_Array_Field_ScalarElement_VariableSize { - s: Struct_Array_Field_ScalarElement_VariableSize_, -} - -struct Struct_Array_Field_ScalarElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: 16[], -} -packet Struct_Array_Field_ScalarElement_VariableCount { - s: Struct_Array_Field_ScalarElement_VariableCount_, -} - -struct Struct_Array_Field_ScalarElement_UnknownSize_ { - array: 16[], -} -packet Struct_Array_Field_ScalarElement_UnknownSize { - s: Struct_Array_Field_ScalarElement_UnknownSize_, -} - -struct Struct_Array_Field_EnumElement_ConstantSize_ { - array: Enum16[4], -} -packet Struct_Array_Field_EnumElement_ConstantSize { - s: Struct_Array_Field_EnumElement_ConstantSize_, -} - -struct Struct_Array_Field_EnumElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_VariableSize { - s: Struct_Array_Field_EnumElement_VariableSize_, -} - -struct Struct_Array_Field_EnumElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_VariableCount { - s: Struct_Array_Field_EnumElement_VariableCount_, -} - -struct Struct_Array_Field_EnumElement_UnknownSize_ { - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_UnknownSize { - s: Struct_Array_Field_EnumElement_UnknownSize_, -} - -struct Struct_Array_Field_SizedElement_ConstantSize_ { - array: SizedStruct[4], -} -packet Struct_Array_Field_SizedElement_ConstantSize { - s: Struct_Array_Field_SizedElement_ConstantSize_, -} - -struct Struct_Array_Field_SizedElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_VariableSize { - s: Struct_Array_Field_SizedElement_VariableSize_, -} - -struct Struct_Array_Field_SizedElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_VariableCount { - s: Struct_Array_Field_SizedElement_VariableCount_, -} - -struct Struct_Array_Field_SizedElement_UnknownSize_ { - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_UnknownSize { - s: Struct_Array_Field_SizedElement_UnknownSize_, -} - -struct Struct_Array_Field_UnsizedElement_ConstantSize_ { - array: UnsizedStruct[4], -} -packet Struct_Array_Field_UnsizedElement_ConstantSize { - s: Struct_Array_Field_UnsizedElement_ConstantSize_, -} - -struct Struct_Array_Field_UnsizedElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_VariableSize { - s: Struct_Array_Field_UnsizedElement_VariableSize_, -} - -struct Struct_Array_Field_UnsizedElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_VariableCount { - s: Struct_Array_Field_UnsizedElement_VariableCount_, -} - -struct Struct_Array_Field_UnsizedElement_UnknownSize_ { - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_UnknownSize { - s: Struct_Array_Field_UnsizedElement_UnknownSize_, -} - diff --git a/tools/pdl/tests/canonical/le_test_file.pdl b/tools/pdl/tests/canonical/le_test_file.pdl deleted file mode 100644 index 6bc140c46edd09c14fde498009fbaa699c18f034..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/canonical/le_test_file.pdl +++ /dev/null @@ -1,780 +0,0 @@ -little_endian_packets - -// Preliminary definitions - -custom_field SizedCustomField : 8 "SizedCustomField" -custom_field UnsizedCustomField "UnsizedCustomField" -checksum Checksum : 8 "Checksum" - -enum Enum7 : 7 { - A = 1, - B = 2, -} - -enum Enum16 : 16 { - A = 0xaabb, - B = 0xccdd, -} - -struct SizedStruct { - a: 8, -} - -struct UnsizedStruct { - _size_(array): 2, - _reserved_: 6, - array: 8[], -} - -group ScalarGroup { - a: 16 -} - -group EnumGroup { - a: Enum16 -} - -packet ScalarParent { - a: 8, - _size_(_payload_): 8, - _payload_ -} - -packet EnumParent { - a: Enum16, - _size_(_payload_): 8, - _payload_ -} - -packet EmptyParent : ScalarParent { - _payload_ -} - -// Start: little_endian_only -packet PartialParent5 { - a: 5, - _payload_ -} - -packet PartialParent12 { - a: 12, - _payload_ -} -// End: little_endian_only - -// Packet bit fields - -// The parser must be able to handle bit fields with scalar values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Scalar_Field { - a: 7, - c: 57, -} - -// The parser must be able to handle bit fields with enum values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Enum_Field { - a: Enum7, - c: 57, -} - -// The parser must be able to handle bit fields with reserved fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Reserved_Field { - a: 7, - _reserved_: 2, - c: 55, -} - -// The parser must be able to handle bit fields with size fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Size_Field { - _size_(b): 3, - a: 61, - b: 8[], -} - -// The parser must be able to handle bit fields with count fields -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_Count_Field { - _count_(b): 3, - a: 61, - b: 8[], -} - -// The parser must be able to handle bit fields with fixed scalar values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_FixedScalar_Field { - _fixed_ = 7 : 7, - b: 57, -} - -// The parser must be able to handle bit fields with fixed enum values -// up to 64 bits wide. The parser should generate a static size guard. -packet Packet_FixedEnum_Field { - _fixed_ = A : Enum7, - b: 57, -} - -// Packet payload fields - -// The parser must be able to handle sized payload fields without -// size modifier. -packet Packet_Payload_Field_VariableSize { - _size_(_payload_): 3, - _reserved_: 5, - _payload_ -} - -// The parser must be able to handle sized payload fields with -// size modifier. -packet Packet_Payload_Field_SizeModifier { - _size_(_payload_): 3, - _reserved_: 5, - _payload_ : [+2], -} - -// The parser must be able to handle payload fields of unkonwn size followed -// by fields of statically known size. The remaining span is integrated -// in the packet. -packet Packet_Payload_Field_UnknownSize { - _payload_, - a: 16, -} - -// The parser must be able to handle payload fields of unkonwn size. -// The remaining span is integrated in the packet. -packet Packet_Payload_Field_UnknownSize_Terminal { - a: 16, - _payload_, -} - -// Packet body fields - -// The parser must be able to handle sized body fields without -// size modifier when the packet has no children. -packet Packet_Body_Field_VariableSize { - _size_(_body_): 3, - _reserved_: 5, - _body_ -} - -// The parser must be able to handle body fields of unkonwn size followed -// by fields of statically known size. The remaining span is integrated -// in the packet. -packet Packet_Body_Field_UnknownSize { - _body_, - a: 16, -} - -// The parser must be able to handle body fields of unkonwn size. -// The remaining span is integrated in the packet. -packet Packet_Body_Field_UnknownSize_Terminal { - a: 16, - _body_, -} - -// Packet group fields - -packet Packet_ScalarGroup_Field { - ScalarGroup { a = 42 }, -} - -packet Packet_EnumGroup_Field { - EnumGroup { a = A }, -} - -// Packet checksum fields - -// The parser must be able to handle checksum fields if the checksum value -// field is positioned at constant offset from the checksum start. -// The parser should generate a checksum guard for the buffer covered by the -// checksum. -packet Packet_Checksum_Field_FromStart { - _checksum_start_(crc), - a: 16, - b: 16, - crc: Checksum, -} - -// The parser must be able to handle checksum fields if the checksum value -// field is positioned at constant offset from the end of the packet. -// The parser should generate a checksum guard for the buffer covered by the -// checksum. -packet Packet_Checksum_Field_FromEnd { - _checksum_start_(crc), - _payload_, - crc: Checksum, - a: 16, - b: 16, -} - -// Packet typedef fields - -// The parser must be able to handle struct fields. -// The size guard is generated by the Struct parser. -packet Packet_Struct_Field { - a: SizedStruct, - b: UnsizedStruct, -} - -// The parser must be able to handle custom fields of constant size. -// The parser should generate a static size guard. -packet Packet_Custom_Field_ConstantSize { - a: SizedCustomField, -} - -// The parser must be able to handle custom fields of undefined size. -// No size guard possible. -packet Packet_Custom_Field_VariableSize { - a: UnsizedCustomField, -} - -// Array field configurations. -// Add constructs for all configurations of type, size, and padding: -// -// - type: u8, u16, enum, struct with static size, struct with dynamic size -// - size: constant, with size field, with count field, unspecified -// -// The type u8 is tested separately since it is likely to be handled -// idiomatically by the specific language generators. - -packet Packet_Array_Field_ByteElement_ConstantSize { - array: 8[4], -} - -packet Packet_Array_Field_ByteElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: 8[], -} - -packet Packet_Array_Field_ByteElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: 8[], -} - -packet Packet_Array_Field_ByteElement_UnknownSize { - array: 8[], -} - -packet Packet_Array_Field_ScalarElement_ConstantSize { - array: 16[4], -} - -packet Packet_Array_Field_ScalarElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: 16[], -} - -packet Packet_Array_Field_ScalarElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: 16[], -} - -packet Packet_Array_Field_ScalarElement_UnknownSize { - array: 16[], -} - -packet Packet_Array_Field_EnumElement_ConstantSize { - array: Enum16[4], -} - -packet Packet_Array_Field_EnumElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: Enum16[], -} - -packet Packet_Array_Field_EnumElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: Enum16[], -} - -packet Packet_Array_Field_EnumElement_UnknownSize { - array: Enum16[], -} - -packet Packet_Array_Field_SizedElement_ConstantSize { - array: SizedStruct[4], -} - -packet Packet_Array_Field_SizedElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} - -packet Packet_Array_Field_SizedElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} - -packet Packet_Array_Field_SizedElement_UnknownSize { - array: SizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_ConstantSize { - array: UnsizedStruct[4], -} - -packet Packet_Array_Field_UnsizedElement_VariableSize { - _size_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_VariableCount { - _count_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} - -packet Packet_Array_Field_UnsizedElement_UnknownSize { - array: UnsizedStruct[], -} - -// The parser must support complex size modifiers on arrays whose size is -// specified by a size field. -packet Packet_Array_Field_UnsizedElement_SizeModifier { - _size_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[+2], -} - -// The parser must be able to handle arrays with padded size. -packet Packet_Array_Field_SizedElement_VariableSize_Padded { - _size_(array) : 4, - _reserved_: 4, - array: 16[], - _padding_ [16], -} - -// The parser must be able to handle arrays with padded size. -packet Packet_Array_Field_UnsizedElement_VariableCount_Padded { - _count_(array) : 8, - array: UnsizedStruct[], - _padding_ [16], -} - -// Packet inheritance - -// The parser must handle specialization into -// any child packet of a parent packet with scalar constraints. -packet ScalarChild_A : ScalarParent (a = 0) { - b: 8, -} - -// The parser must handle specialization into -// any child packet of a parent packet with scalar constraints. -packet ScalarChild_B : ScalarParent (a = 1) { - c: 16, -} - -// The parser must handle specialization into -// any child packet of a parent packet with enum constraints. -packet EnumChild_A : EnumParent (a = A) { - b: 8, -} - -// The parser must handle specialization into -// any child packet of a parent packet with enum constraints. -packet EnumChild_B : EnumParent (a = B) { - c: 16, -} - -// The parser must handle aliasing of packets -// through inheritance with no constraints -packet AliasedChild_A : EmptyParent (a = 2) { - b: 8, -} - -// The parser must handle aliasing of packets -// through inheritance with no constraints -packet AliasedChild_B : EmptyParent (a = 3) { - c: 16, -} - -// Start: little_endian_only - -// The parser must handle inheritance of packets with payloads starting -// on a shifted byte boundary, as long as the first fields of the child -// complete the bit fields. -packet PartialChild5_A : PartialParent5 (a = 0) { - b: 11, -} - -// The parser must handle inheritance of packets with payloads starting -// on a shifted byte boundary, as long as the first fields of the child -// complete the bit fields. -packet PartialChild5_B : PartialParent5 (a = 1) { - c: 27, -} - -// The parser must handle inheritance of packets with payloads starting -// on a shifted byte boundary, as long as the first fields of the child -// complete the bit fields. -packet PartialChild12_A : PartialParent12 (a = 2) { - d: 4, -} - -// The parser must handle inheritance of packets with payloads starting -// on a shifted byte boundary, as long as the first fields of the child -// complete the bit fields. -packet PartialChild12_B : PartialParent12 (a = 3) { - e: 20, -} - -// End: little_endian_only - -// Struct bit fields - -// The parser must be able to handle bit fields with scalar values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Scalar_Field { - a: 7, - c: 57, -} - -// The parser must be able to handle bit fields with enum values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Enum_Field_ { - a: Enum7, - c: 57, -} -packet Struct_Enum_Field { - s: Struct_Enum_Field_, -} - -// The parser must be able to handle bit fields with reserved fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Reserved_Field_ { - a: 7, - _reserved_: 2, - c: 55, -} -packet Struct_Reserved_Field { - s: Struct_Reserved_Field_, -} - -// The parser must be able to handle bit fields with size fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Size_Field_ { - _size_(b): 3, - a: 61, - b: 8[], -} -packet Struct_Size_Field { - s: Struct_Size_Field_, -} - -// The parser must be able to handle bit fields with count fields -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_Count_Field_ { - _count_(b): 3, - a: 61, - b: 8[], -} -packet Struct_Count_Field { - s: Struct_Count_Field_, -} - -// The parser must be able to handle bit fields with fixed scalar values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_FixedScalar_Field_ { - _fixed_ = 7 : 7, - b: 57, -} -packet Struct_FixedScalar_Field { - s: Struct_FixedScalar_Field_, -} - -// The parser must be able to handle bit fields with fixed enum values -// up to 64 bits wide. The parser should generate a static size guard. -struct Struct_FixedEnum_Field_ { - _fixed_ = A : Enum7, - b: 57, -} -packet Struct_FixedEnum_Field { - s: Struct_FixedEnum_Field_, -} - -// Struct group fields - -struct Struct_ScalarGroup_Field_ { - ScalarGroup { a = 42 }, -} -packet Struct_ScalarGroup_Field { - s: Struct_ScalarGroup_Field_, -} - -struct Struct_EnumGroup_Field_ { - EnumGroup { a = A }, -} -packet Struct_EnumGroup_Field { - s: Struct_EnumGroup_Field_, -} - -// Struct checksum fields - -// The parser must be able to handle checksum fields if the checksum value -// field is positioned at constant offset from the checksum start. -// The parser should generate a checksum guard for the buffer covered by the -// checksum. -struct Struct_Checksum_Field_FromStart_ { - _checksum_start_(crc), - a: 16, - b: 16, - crc: Checksum, -} -packet Struct_Checksum_Field_FromStart { - s: Struct_Checksum_Field_FromStart_, -} - -// The parser must be able to handle checksum fields if the checksum value -// field is positioned at constant offset from the end of the packet. -// The parser should generate a checksum guard for the buffer covered by the -// checksum. -struct Struct_Checksum_Field_FromEnd_ { - _checksum_start_(crc), - _payload_, - crc: Checksum, - a: 16, - b: 16, -} -packet Struct_Checksum_Field_FromEnd { - s: Struct_Checksum_Field_FromEnd_, -} - -// Struct typedef fields - -// The parser must be able to handle struct fields. -// The size guard is generated by the Struct parser. -packet Struct_Struct_Field { - a: SizedStruct, - b: UnsizedStruct, -} - -// The parser must be able to handle custom fields of constant size. -// The parser should generate a static size guard. -struct Struct_Custom_Field_ConstantSize_ { - a: SizedCustomField, -} -packet Struct_Custom_Field_ConstantSize { - s: Struct_Custom_Field_ConstantSize_, -} - -// The parser must be able to handle custom fields of undefined size. -// No size guard possible. -struct Struct_Custom_Field_VariableSize_ { - a: UnsizedCustomField, -} -packet Struct_Custom_Field_VariableSize { - s: Struct_Custom_Field_VariableSize_, -} - -// Array field configurations. -// Add constructs for all configurations of type, size, and padding: -// -// - type: u8, u16, enum, struct with static size, struct with dynamic size -// - size: constant, with size field, with count field, unspecified -// -// The type u8 is tested separately since it is likely to be handled -// idiomatically by the specific language generators. - -struct Struct_Array_Field_ByteElement_ConstantSize_ { - array: 8[4], -} -packet Struct_Array_Field_ByteElement_ConstantSize { - s: Struct_Array_Field_ByteElement_ConstantSize_, -} - -struct Struct_Array_Field_ByteElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: 8[], -} -packet Struct_Array_Field_ByteElement_VariableSize { - s: Struct_Array_Field_ByteElement_VariableSize_, -} - -struct Struct_Array_Field_ByteElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: 8[], -} -packet Struct_Array_Field_ByteElement_VariableCount { - s: Struct_Array_Field_ByteElement_VariableCount_, -} - -struct Struct_Array_Field_ByteElement_UnknownSize_ { - array: 8[], -} -packet Struct_Array_Field_ByteElement_UnknownSize { - s: Struct_Array_Field_ByteElement_UnknownSize_, -} - -struct Struct_Array_Field_ScalarElement_ConstantSize_ { - array: 16[4], -} -packet Struct_Array_Field_ScalarElement_ConstantSize { - s: Struct_Array_Field_ScalarElement_ConstantSize_, -} - -struct Struct_Array_Field_ScalarElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: 16[], -} -packet Struct_Array_Field_ScalarElement_VariableSize { - s: Struct_Array_Field_ScalarElement_VariableSize_, -} - -struct Struct_Array_Field_ScalarElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: 16[], -} -packet Struct_Array_Field_ScalarElement_VariableCount { - s: Struct_Array_Field_ScalarElement_VariableCount_, -} - -struct Struct_Array_Field_ScalarElement_UnknownSize_ { - array: 16[], -} -packet Struct_Array_Field_ScalarElement_UnknownSize { - s: Struct_Array_Field_ScalarElement_UnknownSize_, -} - -struct Struct_Array_Field_EnumElement_ConstantSize_ { - array: Enum16[4], -} -packet Struct_Array_Field_EnumElement_ConstantSize { - s: Struct_Array_Field_EnumElement_ConstantSize_, -} - -struct Struct_Array_Field_EnumElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_VariableSize { - s: Struct_Array_Field_EnumElement_VariableSize_, -} - -struct Struct_Array_Field_EnumElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_VariableCount { - s: Struct_Array_Field_EnumElement_VariableCount_, -} - -struct Struct_Array_Field_EnumElement_UnknownSize_ { - array: Enum16[], -} -packet Struct_Array_Field_EnumElement_UnknownSize { - s: Struct_Array_Field_EnumElement_UnknownSize_, -} - -struct Struct_Array_Field_SizedElement_ConstantSize_ { - array: SizedStruct[4], -} -packet Struct_Array_Field_SizedElement_ConstantSize { - s: Struct_Array_Field_SizedElement_ConstantSize_, -} - -struct Struct_Array_Field_SizedElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_VariableSize { - s: Struct_Array_Field_SizedElement_VariableSize_, -} - -struct Struct_Array_Field_SizedElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_VariableCount { - s: Struct_Array_Field_SizedElement_VariableCount_, -} - -struct Struct_Array_Field_SizedElement_UnknownSize_ { - array: SizedStruct[], -} -packet Struct_Array_Field_SizedElement_UnknownSize { - s: Struct_Array_Field_SizedElement_UnknownSize_, -} - -struct Struct_Array_Field_UnsizedElement_ConstantSize_ { - array: UnsizedStruct[4], -} -packet Struct_Array_Field_UnsizedElement_ConstantSize { - s: Struct_Array_Field_UnsizedElement_ConstantSize_, -} - -struct Struct_Array_Field_UnsizedElement_VariableSize_ { - _size_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_VariableSize { - s: Struct_Array_Field_UnsizedElement_VariableSize_, -} - -struct Struct_Array_Field_UnsizedElement_VariableCount_ { - _count_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_VariableCount { - s: Struct_Array_Field_UnsizedElement_VariableCount_, -} - -struct Struct_Array_Field_UnsizedElement_UnknownSize_ { - array: UnsizedStruct[], -} -packet Struct_Array_Field_UnsizedElement_UnknownSize { - s: Struct_Array_Field_UnsizedElement_UnknownSize_, -} - -// The parser must support complex size modifiers on arrays whose size is -// specified by a size field. -struct Struct_Array_Field_UnsizedElement_SizeModifier_ { - _size_(array) : 4, - _reserved_: 4, - array: UnsizedStruct[+2], -} -packet Struct_Array_Field_UnsizedElement_SizeModifier { - s: Struct_Array_Field_UnsizedElement_SizeModifier_, -} - -// The parser must be able to handle arrays with padded size. -struct Struct_Array_Field_SizedElement_VariableSize_Padded_ { - _size_(array) : 4, - _reserved_: 4, - array: 16[], - _padding_ [16], -} -packet Struct_Array_Field_SizedElement_VariableSize_Padded { - s: Struct_Array_Field_SizedElement_VariableSize_Padded_, -} - -// The parser must be able to handle arrays with padded size. -struct Struct_Array_Field_UnsizedElement_VariableCount_Padded_ { - _count_(array) : 8, - array: UnsizedStruct[], - _padding_ [16], -} -packet Struct_Array_Field_UnsizedElement_VariableCount_Padded { - s: Struct_Array_Field_UnsizedElement_VariableCount_Padded_, -} diff --git a/tools/pdl/tests/canonical/le_test_vectors.json b/tools/pdl/tests/canonical/le_test_vectors.json deleted file mode 100644 index 243952c697883b387549fcfc4f744fc214d4c572..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/canonical/le_test_vectors.json +++ /dev/null @@ -1,4377 +0,0 @@ -[ - { - "packet": "Packet_Scalar_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "c": 0 - } - }, - { - "packed": "80ffffffffffffff", - "unpacked": { - "a": 0, - "c": 144115188075855871 - } - }, - { - "packed": "8003830282018100", - "unpacked": { - "a": 0, - "c": 283686952306183 - } - }, - { - "packed": "7f00000000000000", - "unpacked": { - "a": 127, - "c": 0 - } - }, - { - "packed": "ffffffffffffffff", - "unpacked": { - "a": 127, - "c": 144115188075855871 - } - }, - { - "packed": "ff03830282018100", - "unpacked": { - "a": 127, - "c": 283686952306183 - } - }, - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "c": 0 - } - }, - { - "packed": "80ffffffffffffff", - "unpacked": { - "a": 0, - "c": 144115188075855871 - } - }, - { - "packed": "8003830282018100", - "unpacked": { - "a": 0, - "c": 283686952306183 - } - } - ] - }, - { - "packet": "Packet_Enum_Field", - "tests": [ - { - "packed": "0100000000000000", - "unpacked": { - "a": 1, - "c": 0 - } - }, - { - "packed": "81ffffffffffffff", - "unpacked": { - "a": 1, - "c": 144115188075855871 - } - }, - { - "packed": "810e0d0c0b0a0908", - "unpacked": { - "a": 1, - "c": 4523477106694685 - } - }, - { - "packed": "0200000000000000", - "unpacked": { - "a": 2, - "c": 0 - } - }, - { - "packed": "82ffffffffffffff", - "unpacked": { - "a": 2, - "c": 144115188075855871 - } - }, - { - "packed": "820e0d0c0b0a0908", - "unpacked": { - "a": 2, - "c": 4523477106694685 - } - } - ] - }, - { - "packet": "Packet_Reserved_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "c": 0 - } - }, - { - "packed": "00feffffffffffff", - "unpacked": { - "a": 0, - "c": 36028797018963967 - } - }, - { - "packed": "002c151413121110", - "unpacked": { - "a": 0, - "c": 2261184477268630 - } - }, - { - "packed": "7f00000000000000", - "unpacked": { - "a": 127, - "c": 0 - } - }, - { - "packed": "7ffeffffffffffff", - "unpacked": { - "a": 127, - "c": 36028797018963967 - } - }, - { - "packed": "7f2c151413121110", - "unpacked": { - "a": 127, - "c": 2261184477268630 - } - }, - { - "packed": "0700000000000000", - "unpacked": { - "a": 7, - "c": 0 - } - }, - { - "packed": "07feffffffffffff", - "unpacked": { - "a": 7, - "c": 36028797018963967 - } - }, - { - "packed": "072c151413121110", - "unpacked": { - "a": 7, - "c": 2261184477268630 - } - } - ] - }, - { - "packet": "Packet_Size_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "b": [] - } - }, - { - "packed": "07000000000000001f102122232425", - "unpacked": { - "a": 0, - "b": [ - 31, - 16, - 33, - 34, - 35, - 36, - 37 - ] - } - }, - { - "packed": "f8ffffffffffffff", - "unpacked": { - "a": 2305843009213693951, - "b": [] - } - }, - { - "packed": "ffffffffffffffff1f102122232425", - "unpacked": { - "a": 2305843009213693951, - "b": [ - 31, - 16, - 33, - 34, - 35, - 36, - 37 - ] - } - }, - { - "packed": "f00e8e0d8d0c8c0b", - "unpacked": { - "a": 104006728889254366, - "b": [] - } - }, - { - "packed": "f70e8e0d8d0c8c0b1f102122232425", - "unpacked": { - "a": 104006728889254366, - "b": [ - 31, - 16, - 33, - 34, - 35, - 36, - 37 - ] - } - } - ] - }, - { - "packet": "Packet_Count_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "a": 0, - "b": [] - } - }, - { - "packed": "07000000000000002c2f2e31303332", - "unpacked": { - "a": 0, - "b": [ - 44, - 47, - 46, - 49, - 48, - 51, - 50 - ] - } - }, - { - "packed": "f8ffffffffffffff", - "unpacked": { - "a": 2305843009213693951, - "b": [] - } - }, - { - "packed": "ffffffffffffffff2c2f2e31303332", - "unpacked": { - "a": 2305843009213693951, - "b": [ - 44, - 47, - 46, - 49, - 48, - 51, - 50 - ] - } - }, - { - "packed": "c8b2a29282726222", - "unpacked": { - "a": 309708581267330649, - "b": [] - } - }, - { - "packed": "cfb2a292827262222c2f2e31303332", - "unpacked": { - "a": 309708581267330649, - "b": [ - 44, - 47, - 46, - 49, - 48, - 51, - 50 - ] - } - } - ] - }, - { - "packet": "Packet_FixedScalar_Field", - "tests": [ - { - "packed": "0700000000000000", - "unpacked": { - "b": 0 - } - }, - { - "packed": "87ffffffffffffff", - "unpacked": { - "b": 144115188075855871 - } - }, - { - "packed": "877572706e6c6a34", - "unpacked": { - "b": 29507425461658859 - } - } - ] - }, - { - "packet": "Packet_FixedEnum_Field", - "tests": [ - { - "packed": "0100000000000000", - "unpacked": { - "b": 0 - } - }, - { - "packed": "81ffffffffffffff", - "unpacked": { - "b": 144115188075855871 - } - }, - { - "packed": "010501fdf8f4f038", - "unpacked": { - "b": 32055067271627274 - } - } - ] - }, - { - "packet": "Packet_Payload_Field_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "payload": [] - } - }, - { - "packed": "0743444546474049", - "unpacked": { - "payload": [ - 67, - 68, - 69, - 70, - 71, - 64, - 73 - ] - } - } - ] - }, - { - "packet": "Packet_Payload_Field_SizeModifier", - "tests": [ - { - "packed": "02", - "unpacked": { - "payload": [] - } - }, - { - "packed": "074a4b4c4d4e", - "unpacked": { - "payload": [ - 74, - 75, - 76, - 77, - 78 - ] - } - } - ] - }, - { - "packet": "Packet_Payload_Field_UnknownSize", - "tests": [ - { - "packed": "0000", - "unpacked": { - "payload": [], - "a": 0 - } - }, - { - "packed": "ffff", - "unpacked": { - "payload": [], - "a": 65535 - } - }, - { - "packed": "a552", - "unpacked": { - "payload": [], - "a": 21157 - } - }, - { - "packed": "4f485152530000", - "unpacked": { - "payload": [ - 79, - 72, - 81, - 82, - 83 - ], - "a": 0 - } - }, - { - "packed": "4f48515253ffff", - "unpacked": { - "payload": [ - 79, - 72, - 81, - 82, - 83 - ], - "a": 65535 - } - }, - { - "packed": "4f48515253a552", - "unpacked": { - "payload": [ - 79, - 72, - 81, - 82, - 83 - ], - "a": 21157 - } - } - ] - }, - { - "packet": "Packet_Payload_Field_UnknownSize_Terminal", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": 0, - "payload": [] - } - }, - { - "packed": "000050595a5b5c", - "unpacked": { - "a": 0, - "payload": [ - 80, - 89, - 90, - 91, - 92 - ] - } - }, - { - "packed": "ffff", - "unpacked": { - "a": 65535, - "payload": [] - } - }, - { - "packed": "ffff50595a5b5c", - "unpacked": { - "a": 65535, - "payload": [ - 80, - 89, - 90, - 91, - 92 - ] - } - }, - { - "packed": "b752", - "unpacked": { - "a": 21175, - "payload": [] - } - }, - { - "packed": "b75250595a5b5c", - "unpacked": { - "a": 21175, - "payload": [ - 80, - 89, - 90, - 91, - 92 - ] - } - } - ] - }, - { - "packet": "Packet_Body_Field_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "payload": [] - } - }, - { - "packed": "075d5e5f58616263", - "unpacked": { - "payload": [ - 93, - 94, - 95, - 88, - 97, - 98, - 99 - ] - } - } - ] - }, - { - "packet": "Packet_Body_Field_UnknownSize", - "tests": [ - { - "packed": "0000", - "unpacked": { - "payload": [], - "a": 0 - } - }, - { - "packed": "ffff", - "unpacked": { - "payload": [], - "a": 65535 - } - }, - { - "packed": "4a6b", - "unpacked": { - "payload": [], - "a": 27466 - } - }, - { - "packed": "64656667600000", - "unpacked": { - "payload": [ - 100, - 101, - 102, - 103, - 96 - ], - "a": 0 - } - }, - { - "packed": "6465666760ffff", - "unpacked": { - "payload": [ - 100, - 101, - 102, - 103, - 96 - ], - "a": 65535 - } - }, - { - "packed": "64656667604a6b", - "unpacked": { - "payload": [ - 100, - 101, - 102, - 103, - 96 - ], - "a": 27466 - } - } - ] - }, - { - "packet": "Packet_Body_Field_UnknownSize_Terminal", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": 0, - "payload": [] - } - }, - { - "packed": "00006d6e6f6871", - "unpacked": { - "a": 0, - "payload": [ - 109, - 110, - 111, - 104, - 113 - ] - } - }, - { - "packed": "ffff", - "unpacked": { - "a": 65535, - "payload": [] - } - }, - { - "packed": "ffff6d6e6f6871", - "unpacked": { - "a": 65535, - "payload": [ - 109, - 110, - 111, - 104, - 113 - ] - } - }, - { - "packed": "5c6b", - "unpacked": { - "a": 27484, - "payload": [] - } - }, - { - "packed": "5c6b6d6e6f6871", - "unpacked": { - "a": 27484, - "payload": [ - 109, - 110, - 111, - 104, - 113 - ] - } - } - ] - }, - { - "packet": "Packet_ScalarGroup_Field", - "tests": [ - { - "packed": "2a00", - "unpacked": {} - } - ] - }, - { - "packet": "Packet_EnumGroup_Field", - "tests": [ - { - "packed": "bbaa", - "unpacked": {} - } - ] - }, - { - "packet": "Packet_Checksum_Field_FromStart", - "tests": [ - { - "packed": "0000000000", - "unpacked": { - "a": 0, - "b": 0, - "crc": 0 - } - }, - { - "packed": "0000fffffe", - "unpacked": { - "a": 0, - "b": 65535, - "crc": 254 - } - }, - { - "packed": "0000a57318", - "unpacked": { - "a": 0, - "b": 29605, - "crc": 24 - } - }, - { - "packed": "ffff0000fe", - "unpacked": { - "a": 65535, - "b": 0, - "crc": 254 - } - }, - { - "packed": "fffffffffc", - "unpacked": { - "a": 65535, - "b": 65535, - "crc": 252 - } - }, - { - "packed": "ffffa57316", - "unpacked": { - "a": 65535, - "b": 29605, - "crc": 22 - } - }, - { - "packed": "9373000006", - "unpacked": { - "a": 29587, - "b": 0, - "crc": 6 - } - }, - { - "packed": "9373ffff04", - "unpacked": { - "a": 29587, - "b": 65535, - "crc": 4 - } - }, - { - "packed": "9373a5731e", - "unpacked": { - "a": 29587, - "b": 29605, - "crc": 30 - } - } - ] - }, - { - "packet": "Packet_Checksum_Field_FromEnd", - "tests": [ - { - "packed": "0000000000", - "unpacked": { - "payload": [], - "crc": 0, - "a": 0, - "b": 0 - } - }, - { - "packed": "000000ffff", - "unpacked": { - "payload": [], - "crc": 0, - "a": 0, - "b": 65535 - } - }, - { - "packed": "000000ee7b", - "unpacked": { - "payload": [], - "crc": 0, - "a": 0, - "b": 31726 - } - }, - { - "packed": "00ffff0000", - "unpacked": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 0 - } - }, - { - "packed": "00ffffffff", - "unpacked": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 65535 - } - }, - { - "packed": "00ffffee7b", - "unpacked": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 31726 - } - }, - { - "packed": "00dc7b0000", - "unpacked": { - "payload": [], - "crc": 0, - "a": 31708, - "b": 0 - } - }, - { - "packed": "00dc7bffff", - "unpacked": { - "payload": [], - "crc": 0, - "a": 31708, - "b": 65535 - } - }, - { - "packed": "00dc7bee7b", - "unpacked": { - "payload": [], - "crc": 0, - "a": 31708, - "b": 31726 - } - }, - { - "packed": "767770797a5000000000", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 0, - "b": 0 - } - }, - { - "packed": "767770797a500000ffff", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 0, - "b": 65535 - } - }, - { - "packed": "767770797a500000ee7b", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 0, - "b": 31726 - } - }, - { - "packed": "767770797a50ffff0000", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 65535, - "b": 0 - } - }, - { - "packed": "767770797a50ffffffff", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 65535, - "b": 65535 - } - }, - { - "packed": "767770797a50ffffee7b", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 65535, - "b": 31726 - } - }, - { - "packed": "767770797a50dc7b0000", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 31708, - "b": 0 - } - }, - { - "packed": "767770797a50dc7bffff", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 31708, - "b": 65535 - } - }, - { - "packed": "767770797a50dc7bee7b", - "unpacked": { - "payload": [ - 118, - 119, - 112, - 121, - 122 - ], - "crc": 80, - "a": 31708, - "b": 31726 - } - } - ] - }, - { - "packet": "Packet_Struct_Field", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": { - "a": 0 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "0003788182", - "unpacked": { - "a": { - "a": 0 - }, - "b": { - "array": [ - 120, - 129, - 130 - ] - } - } - }, - { - "packed": "ff00", - "unpacked": { - "a": { - "a": 255 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "ff03788182", - "unpacked": { - "a": { - "a": 255 - }, - "b": { - "array": [ - 120, - 129, - 130 - ] - } - } - }, - { - "packed": "7f00", - "unpacked": { - "a": { - "a": 127 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "7f03788182", - "unpacked": { - "a": { - "a": 127 - }, - "b": { - "array": [ - 120, - 129, - 130 - ] - } - } - } - ] - }, - { - "packet": "Packet_Array_Field_ByteElement_ConstantSize", - "tests": [ - { - "packed": "83848586", - "unpacked": { - "array": [ - 131, - 132, - 133, - 134 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ByteElement_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "array": [] - } - }, - { - "packed": "0f8780898a8b8c8d8e8f889192939495", - "unpacked": { - "array": [ - 135, - 128, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 136, - 145, - 146, - 147, - 148, - 149 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ByteElement_VariableCount", - "tests": [ - { - "packed": "00", - "unpacked": { - "array": [] - } - }, - { - "packed": "0f969790999a9b9c9d9e9f98a1a2a3a4", - "unpacked": { - "array": [ - 150, - 151, - 144, - 153, - 154, - 155, - 156, - 157, - 158, - 159, - 152, - 161, - 162, - 163, - 164 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ByteElement_UnknownSize", - "tests": [ - { - "packed": "", - "unpacked": { - "array": [] - } - }, - { - "packed": "a5a6a7", - "unpacked": { - "array": [ - 165, - 166, - 167 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ScalarElement_ConstantSize", - "tests": [ - { - "packed": "41a553ad65ad77ad", - "unpacked": { - "array": [ - 42305, - 44371, - 44389, - 44407 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ScalarElement_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "array": [] - } - }, - { - "packed": "0e81ad93b5a5b5b7b5c1b5d3bde5bd", - "unpacked": { - "array": [ - 44417, - 46483, - 46501, - 46519, - 46529, - 48595, - 48613 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ScalarElement_VariableCount", - "tests": [ - { - "packed": "00", - "unpacked": { - "array": [] - } - }, - { - "packed": "0ff7bd01be13c625c637c641c653ce65ce77ce81ce93d6a5d6b7d6c1d6d3de", - "unpacked": { - "array": [ - 48631, - 48641, - 50707, - 50725, - 50743, - 50753, - 52819, - 52837, - 52855, - 52865, - 54931, - 54949, - 54967, - 54977, - 57043 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_ScalarElement_UnknownSize", - "tests": [ - { - "packed": "", - "unpacked": { - "array": [] - } - }, - { - "packed": "e5def7de01df", - "unpacked": { - "array": [ - 57061, - 57079, - 57089 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_EnumElement_ConstantSize", - "tests": [ - { - "packed": "bbaaddccbbaaddcc", - "unpacked": { - "array": [ - 43707, - 52445, - 43707, - 52445 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_EnumElement_VariableSize", - "tests": [ - { - "packed": "0ebbaaddccbbaaddccbbaaddccbbaa", - "unpacked": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707 - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_EnumElement_VariableCount", - "tests": [ - { - "packed": "0fbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaa", - "unpacked": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707 - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_EnumElement_UnknownSize", - "tests": [ - { - "packed": "bbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddcc", - "unpacked": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445 - ] - } - }, - { - "packed": "", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_ConstantSize", - "tests": [ - { - "packed": "00ffe200", - "unpacked": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 226 - }, - { - "a": 0 - } - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_VariableSize", - "tests": [ - { - "packed": "0f00ffe400ffe500ffe600ffe700ffe0", - "unpacked": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 228 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 229 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 230 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 231 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 224 - } - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_VariableCount", - "tests": [ - { - "packed": "0f00ffea00ffeb00ffec00ffed00ffee", - "unpacked": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 234 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 235 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 236 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 237 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 238 - } - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_UnknownSize", - "tests": [ - { - "packed": "00ffe800fff100fff200fff300fff400fff500fff600fff700fff000fff900ff", - "unpacked": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 232 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 241 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 242 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 243 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 244 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 245 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 246 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 247 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 240 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 249 - }, - { - "a": 0 - }, - { - "a": 255 - } - ] - } - }, - { - "packed": "", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_ConstantSize", - "tests": [ - { - "packed": "0003fbfcfd0003fef801", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 251, - 252, - 253 - ] - }, - { - "array": [] - }, - { - "array": [ - 254, - 248, - 1 - ] - } - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_VariableSize", - "tests": [ - { - "packed": "0f0003050607000300090a00030b0c0d", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 5, - 6, - 7 - ] - }, - { - "array": [] - }, - { - "array": [ - 0, - 9, - 10 - ] - }, - { - "array": [] - }, - { - "array": [ - 11, - 12, - 13 - ] - } - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_VariableCount", - "tests": [ - { - "packed": "0f00031112130003141516000317101900031a1b1c00031d1e1f0003182122000323242500", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 17, - 18, - 19 - ] - }, - { - "array": [] - }, - { - "array": [ - 20, - 21, - 22 - ] - }, - { - "array": [] - }, - { - "array": [ - 23, - 16, - 25 - ] - }, - { - "array": [] - }, - { - "array": [ - 26, - 27, - 28 - ] - }, - { - "array": [] - }, - { - "array": [ - 29, - 30, - 31 - ] - }, - { - "array": [] - }, - { - "array": [ - 24, - 33, - 34 - ] - }, - { - "array": [] - }, - { - "array": [ - 35, - 36, - 37 - ] - }, - { - "array": [] - } - ] - } - }, - { - "packed": "00", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_UnknownSize", - "tests": [ - { - "packed": "0003292a2b00032c2d2e00032f283100033233340003353637000330393a00033b3c3d00033e3f3800034142430003444546000347404900034a4b4c00034d4e4f000348515200035354550003565750", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 41, - 42, - 43 - ] - }, - { - "array": [] - }, - { - "array": [ - 44, - 45, - 46 - ] - }, - { - "array": [] - }, - { - "array": [ - 47, - 40, - 49 - ] - }, - { - "array": [] - }, - { - "array": [ - 50, - 51, - 52 - ] - }, - { - "array": [] - }, - { - "array": [ - 53, - 54, - 55 - ] - }, - { - "array": [] - }, - { - "array": [ - 48, - 57, - 58 - ] - }, - { - "array": [] - }, - { - "array": [ - 59, - 60, - 61 - ] - }, - { - "array": [] - }, - { - "array": [ - 62, - 63, - 56 - ] - }, - { - "array": [] - }, - { - "array": [ - 65, - 66, - 67 - ] - }, - { - "array": [] - }, - { - "array": [ - 68, - 69, - 70 - ] - }, - { - "array": [] - }, - { - "array": [ - 71, - 64, - 73 - ] - }, - { - "array": [] - }, - { - "array": [ - 74, - 75, - 76 - ] - }, - { - "array": [] - }, - { - "array": [ - 77, - 78, - 79 - ] - }, - { - "array": [] - }, - { - "array": [ - 72, - 81, - 82 - ] - }, - { - "array": [] - }, - { - "array": [ - 83, - 84, - 85 - ] - }, - { - "array": [] - }, - { - "array": [ - 86, - 87, - 80 - ] - } - ] - } - }, - { - "packed": "", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_SizeModifier", - "tests": [ - { - "packed": "0d00035c5d5e00035f586100", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 92, - 93, - 94 - ] - }, - { - "array": [] - }, - { - "array": [ - 95, - 88, - 97 - ] - }, - { - "array": [] - } - ] - } - }, - { - "packed": "02", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "Packet_Array_Field_SizedElement_VariableSize_Padded", - "tests": [ - { - "packed": "0000000000000000000000000000000000", - "unpacked": { - "array": [] - } - }, - { - "packed": "0e2e6338634a6b5c6b6e6b786b8a730000", - "unpacked": { - "array": [ - 25390, - 25400, - 27466, - 27484, - 27502, - 27512, - 29578 - ] - } - } - ] - }, - { - "packet": "Packet_Array_Field_UnsizedElement_VariableCount_Padded", - "tests": [ - { - "packed": "07000373747500037677700003797a7b00", - "unpacked": { - "array": [ - { - "array": [] - }, - { - "array": [ - 115, - 116, - 117 - ] - }, - { - "array": [] - }, - { - "array": [ - 118, - 119, - 112 - ] - }, - { - "array": [] - }, - { - "array": [ - 121, - 122, - 123 - ] - }, - { - "array": [] - } - ] - } - }, - { - "packed": "0000000000000000000000000000000000", - "unpacked": { - "array": [] - } - } - ] - }, - { - "packet": "ScalarParent", - "tests": [ - { - "packed": "000100", - "unpacked": { - "a": 0, - "b": 0 - }, - "packet": "ScalarChild_A" - }, - { - "packed": "0001ff", - "unpacked": { - "a": 0, - "b": 255 - }, - "packet": "ScalarChild_A" - }, - { - "packed": "00017f", - "unpacked": { - "a": 0, - "b": 127 - }, - "packet": "ScalarChild_A" - }, - { - "packed": "01020000", - "unpacked": { - "a": 1, - "c": 0 - }, - "packet": "ScalarChild_B" - }, - { - "packed": "0102ffff", - "unpacked": { - "a": 1, - "c": 65535 - }, - "packet": "ScalarChild_B" - }, - { - "packed": "0102017c", - "unpacked": { - "a": 1, - "c": 31745 - }, - "packet": "ScalarChild_B" - }, - { - "packed": "020100", - "unpacked": { - "a": 2, - "b": 0 - }, - "packet": "AliasedChild_A" - }, - { - "packed": "0201ff", - "unpacked": { - "a": 2, - "b": 255 - }, - "packet": "AliasedChild_A" - }, - { - "packed": "020185", - "unpacked": { - "a": 2, - "b": 133 - }, - "packet": "AliasedChild_A" - }, - { - "packed": "03020000", - "unpacked": { - "a": 3, - "c": 0 - }, - "packet": "AliasedChild_B" - }, - { - "packed": "0302ffff", - "unpacked": { - "a": 3, - "c": 65535 - }, - "packet": "AliasedChild_B" - }, - { - "packed": "03023784", - "unpacked": { - "a": 3, - "c": 33847 - }, - "packet": "AliasedChild_B" - } - ] - }, - { - "packet": "EnumParent", - "tests": [ - { - "packed": "bbaa0100", - "unpacked": { - "a": 43707, - "b": 0 - }, - "packet": "EnumChild_A" - }, - { - "packed": "bbaa01ff", - "unpacked": { - "a": 43707, - "b": 255 - }, - "packet": "EnumChild_A" - }, - { - "packed": "bbaa0182", - "unpacked": { - "a": 43707, - "b": 130 - }, - "packet": "EnumChild_A" - }, - { - "packed": "ddcc020000", - "unpacked": { - "a": 52445, - "c": 0 - }, - "packet": "EnumChild_B" - }, - { - "packed": "ddcc02ffff", - "unpacked": { - "a": 52445, - "c": 65535 - }, - "packet": "EnumChild_B" - }, - { - "packed": "ddcc021c84", - "unpacked": { - "a": 52445, - "c": 33820 - }, - "packet": "EnumChild_B" - } - ] - }, - { - "packet": "PartialParent5", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": 0, - "b": 0 - }, - "packet": "PartialChild5_A" - }, - { - "packed": "e0ff", - "unpacked": { - "a": 0, - "b": 2047 - }, - "packet": "PartialChild5_A" - }, - { - "packed": "0081", - "unpacked": { - "a": 0, - "b": 1032 - }, - "packet": "PartialChild5_A" - }, - { - "packed": "01000000", - "unpacked": { - "a": 1, - "c": 0 - }, - "packet": "PartialChild5_B" - }, - { - "packed": "e1ffffff", - "unpacked": { - "a": 1, - "c": 134217727 - }, - "packet": "PartialChild5_B" - }, - { - "packed": "c1a262a2", - "unpacked": { - "a": 1, - "c": 85136662 - }, - "packet": "PartialChild5_B" - } - ] - }, - { - "packet": "PartialParent12", - "tests": [ - { - "packed": "0200", - "unpacked": { - "a": 2, - "d": 0 - }, - "packet": "PartialChild12_A" - }, - { - "packed": "02f0", - "unpacked": { - "a": 2, - "d": 15 - }, - "packet": "PartialChild12_A" - }, - { - "packed": "0260", - "unpacked": { - "a": 2, - "d": 6 - }, - "packet": "PartialChild12_A" - }, - { - "packed": "03000000", - "unpacked": { - "a": 3, - "e": 0 - }, - "packet": "PartialChild12_B" - }, - { - "packed": "03f0ffff", - "unpacked": { - "a": 3, - "e": 1048575 - }, - "packet": "PartialChild12_B" - }, - { - "packed": "03d0b191", - "unpacked": { - "a": 3, - "e": 596765 - }, - "packet": "PartialChild12_B" - } - ] - }, - { - "packet": "Struct_Enum_Field", - "tests": [ - { - "packed": "0100000000000000", - "unpacked": { - "s": { - "a": 1, - "c": 0 - } - } - }, - { - "packed": "81ffffffffffffff", - "unpacked": { - "s": { - "a": 1, - "c": 144115188075855871 - } - } - }, - { - "packed": "012b29272523218f", - "unpacked": { - "s": { - "a": 1, - "c": 80574713001038422 - } - } - }, - { - "packed": "0200000000000000", - "unpacked": { - "s": { - "a": 2, - "c": 0 - } - } - }, - { - "packed": "82ffffffffffffff", - "unpacked": { - "s": { - "a": 2, - "c": 144115188075855871 - } - } - }, - { - "packed": "022b29272523218f", - "unpacked": { - "s": { - "a": 2, - "c": 80574713001038422 - } - } - } - ] - }, - { - "packet": "Struct_Reserved_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "s": { - "a": 0, - "c": 0 - } - } - }, - { - "packed": "00feffffffffffff", - "unpacked": { - "s": { - "a": 0, - "c": 36028797018963967 - } - } - }, - { - "packed": "003a393735333197", - "unpacked": { - "s": { - "a": 0, - "c": 21278408744606877 - } - } - }, - { - "packed": "7f00000000000000", - "unpacked": { - "s": { - "a": 127, - "c": 0 - } - } - }, - { - "packed": "7ffeffffffffffff", - "unpacked": { - "s": { - "a": 127, - "c": 36028797018963967 - } - } - }, - { - "packed": "7f3a393735333197", - "unpacked": { - "s": { - "a": 127, - "c": 21278408744606877 - } - } - }, - { - "packed": "4b00000000000000", - "unpacked": { - "s": { - "a": 75, - "c": 0 - } - } - }, - { - "packed": "4bfeffffffffffff", - "unpacked": { - "s": { - "a": 75, - "c": 36028797018963967 - } - } - }, - { - "packed": "4b3a393735333197", - "unpacked": { - "s": { - "a": 75, - "c": 21278408744606877 - } - } - } - ] - }, - { - "packet": "Struct_Size_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "s": { - "a": 0, - "b": [] - } - } - }, - { - "packed": "0700000000000000a6a7a8a9aaabac", - "unpacked": { - "s": { - "a": 0, - "b": [ - 166, - 167, - 168, - 169, - 170, - 171, - 172 - ] - } - } - }, - { - "packed": "f8ffffffffffffff", - "unpacked": { - "s": { - "a": 2305843009213693951, - "b": [] - } - } - }, - { - "packed": "ffffffffffffffffa6a7a8a9aaabac", - "unpacked": { - "s": { - "a": 2305843009213693951, - "b": [ - 166, - 167, - 168, - 169, - 170, - 171, - 172 - ] - } - } - }, - { - "packed": "28a4a3a2a1a09f9e", - "unpacked": { - "s": { - "a": 1428753874421052549, - "b": [] - } - } - }, - { - "packed": "2fa4a3a2a1a09f9ea6a7a8a9aaabac", - "unpacked": { - "s": { - "a": 1428753874421052549, - "b": [ - 166, - 167, - 168, - 169, - 170, - 171, - 172 - ] - } - } - } - ] - }, - { - "packet": "Struct_Count_Field", - "tests": [ - { - "packed": "0000000000000000", - "unpacked": { - "s": { - "a": 0, - "b": [] - } - } - }, - { - "packed": "0700000000000000b5b6b7b4b9babb", - "unpacked": { - "s": { - "a": 0, - "b": [ - 181, - 182, - 183, - 180, - 185, - 186, - 187 - ] - } - } - }, - { - "packed": "f8ffffffffffffff", - "unpacked": { - "s": { - "a": 2305843009213693951, - "b": [] - } - } - }, - { - "packed": "ffffffffffffffffb5b6b7b4b9babb", - "unpacked": { - "s": { - "a": 2305843009213693951, - "b": [ - 181, - 182, - 183, - 180, - 185, - 186, - 187 - ] - } - } - }, - { - "packed": "60563616f6d5b5b5", - "unpacked": { - "s": { - "a": 1636700843070114508, - "b": [] - } - } - }, - { - "packed": "67563616f6d5b5b5b5b6b7b4b9babb", - "unpacked": { - "s": { - "a": 1636700843070114508, - "b": [ - 181, - 182, - 183, - 180, - 185, - 186, - 187 - ] - } - } - } - ] - }, - { - "packet": "Struct_FixedScalar_Field", - "tests": [ - { - "packed": "0700000000000000", - "unpacked": { - "s": { - "b": 0 - } - } - }, - { - "packed": "87ffffffffffffff", - "unpacked": { - "s": { - "b": 144115188075855871 - } - } - }, - { - "packed": "070503fffaf6f2ba", - "unpacked": { - "s": { - "b": 105242976510150154 - } - } - } - ] - }, - { - "packet": "Struct_FixedEnum_Field", - "tests": [ - { - "packed": "0100000000000000", - "unpacked": { - "s": { - "b": 0 - } - } - }, - { - "packed": "81ffffffffffffff", - "unpacked": { - "s": { - "b": 144115188075855871 - } - } - }, - { - "packed": "81443e362e261ec6", - "unpacked": { - "s": { - "b": 111530389443214473 - } - } - } - ] - }, - { - "packet": "Struct_ScalarGroup_Field", - "tests": [ - { - "packed": "2a00", - "unpacked": { - "s": {} - } - } - ] - }, - { - "packet": "Struct_EnumGroup_Field", - "tests": [ - { - "packed": "bbaa", - "unpacked": { - "s": {} - } - } - ] - }, - { - "packet": "Struct_Checksum_Field_FromStart", - "tests": [ - { - "packed": "0000000000", - "unpacked": { - "s": { - "a": 0, - "b": 0, - "crc": 0 - } - } - }, - { - "packed": "0000fffffe", - "unpacked": { - "s": { - "a": 0, - "b": 65535, - "crc": 254 - } - } - }, - { - "packed": "0000cdcc99", - "unpacked": { - "s": { - "a": 0, - "b": 52429, - "crc": 153 - } - } - }, - { - "packed": "ffff0000fe", - "unpacked": { - "s": { - "a": 65535, - "b": 0, - "crc": 254 - } - } - }, - { - "packed": "fffffffffc", - "unpacked": { - "s": { - "a": 65535, - "b": 65535, - "crc": 252 - } - } - }, - { - "packed": "ffffcdcc97", - "unpacked": { - "s": { - "a": 65535, - "b": 52429, - "crc": 151 - } - } - }, - { - "packed": "abcc000077", - "unpacked": { - "s": { - "a": 52395, - "b": 0, - "crc": 119 - } - } - }, - { - "packed": "abccffff75", - "unpacked": { - "s": { - "a": 52395, - "b": 65535, - "crc": 117 - } - } - }, - { - "packed": "abcccdcc10", - "unpacked": { - "s": { - "a": 52395, - "b": 52429, - "crc": 16 - } - } - } - ] - }, - { - "packet": "Struct_Checksum_Field_FromEnd", - "tests": [ - { - "packed": "0000000000", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 0, - "b": 0 - } - } - }, - { - "packed": "000000ffff", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 0, - "b": 65535 - } - } - }, - { - "packed": "00000056dd", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 0, - "b": 56662 - } - } - }, - { - "packed": "00ffff0000", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 0 - } - } - }, - { - "packed": "00ffffffff", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 65535 - } - } - }, - { - "packed": "00ffff56dd", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 65535, - "b": 56662 - } - } - }, - { - "packed": "0034dd0000", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 56628, - "b": 0 - } - } - }, - { - "packed": "0034ddffff", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 56628, - "b": 65535 - } - } - }, - { - "packed": "0034dd56dd", - "unpacked": { - "s": { - "payload": [], - "crc": 0, - "a": 56628, - "b": 56662 - } - } - }, - { - "packed": "cecfc0d1d20000000000", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 0, - "b": 0 - } - } - }, - { - "packed": "cecfc0d1d2000000ffff", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 0, - "b": 65535 - } - } - }, - { - "packed": "cecfc0d1d200000056dd", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 0, - "b": 56662 - } - } - }, - { - "packed": "cecfc0d1d200ffff0000", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 65535, - "b": 0 - } - } - }, - { - "packed": "cecfc0d1d200ffffffff", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 65535, - "b": 65535 - } - } - }, - { - "packed": "cecfc0d1d200ffff56dd", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 65535, - "b": 56662 - } - } - }, - { - "packed": "cecfc0d1d20034dd0000", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 56628, - "b": 0 - } - } - }, - { - "packed": "cecfc0d1d20034ddffff", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 56628, - "b": 65535 - } - } - }, - { - "packed": "cecfc0d1d20034dd56dd", - "unpacked": { - "s": { - "payload": [ - 206, - 207, - 192, - 209, - 210 - ], - "crc": 0, - "a": 56628, - "b": 56662 - } - } - } - ] - }, - { - "packet": "Struct_Struct_Field", - "tests": [ - { - "packed": "0000", - "unpacked": { - "a": { - "a": 0 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "0003d8d9da", - "unpacked": { - "a": { - "a": 0 - }, - "b": { - "array": [ - 216, - 217, - 218 - ] - } - } - }, - { - "packed": "ff00", - "unpacked": { - "a": { - "a": 255 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "ff03d8d9da", - "unpacked": { - "a": { - "a": 255 - }, - "b": { - "array": [ - 216, - 217, - 218 - ] - } - } - }, - { - "packed": "d700", - "unpacked": { - "a": { - "a": 215 - }, - "b": { - "array": [] - } - } - }, - { - "packed": "d703d8d9da", - "unpacked": { - "a": { - "a": 215 - }, - "b": { - "array": [ - 216, - 217, - 218 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ByteElement_ConstantSize", - "tests": [ - { - "packed": "dbdcddde", - "unpacked": { - "s": { - "array": [ - 219, - 220, - 221, - 222 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ByteElement_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0fdfd0e1e2e3e4e5e6e7e8e9eaebeced", - "unpacked": { - "s": { - "array": [ - 223, - 208, - 225, - 226, - 227, - 228, - 229, - 230, - 231, - 232, - 233, - 234, - 235, - 236, - 237 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ByteElement_VariableCount", - "tests": [ - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0feeefe0f1f2f3f4f5f6f7f8f9fafbfc", - "unpacked": { - "s": { - "array": [ - 238, - 239, - 224, - 241, - 242, - 243, - 244, - 245, - 246, - 247, - 248, - 249, - 250, - 251, - 252 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ByteElement_UnknownSize", - "tests": [ - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "fdfef0", - "unpacked": { - "s": { - "array": [ - 253, - 254, - 240 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ScalarElement_ConstantSize", - "tests": [ - { - "packed": "1200340056007800", - "unpacked": { - "s": { - "array": [ - 18, - 52, - 86, - 120 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ScalarElement_VariableSize", - "tests": [ - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0e9a00bc00de00f000121134115611", - "unpacked": { - "s": { - "array": [ - 154, - 188, - 222, - 240, - 4370, - 4404, - 4438 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ScalarElement_VariableCount", - "tests": [ - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0f78119a11bc11de11f01112223422562278229a22bc22de22f02212333433", - "unpacked": { - "s": { - "array": [ - 4472, - 4506, - 4540, - 4574, - 4592, - 8722, - 8756, - 8790, - 8824, - 8858, - 8892, - 8926, - 8944, - 13074, - 13108 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_ScalarElement_UnknownSize", - "tests": [ - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "563378339a33", - "unpacked": { - "s": { - "array": [ - 13142, - 13176, - 13210 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_EnumElement_ConstantSize", - "tests": [ - { - "packed": "bbaaddccbbaaddcc", - "unpacked": { - "s": { - "array": [ - 43707, - 52445, - 43707, - 52445 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_EnumElement_VariableSize", - "tests": [ - { - "packed": "0ebbaaddccbbaaddccbbaaddccbbaa", - "unpacked": { - "s": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707 - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_EnumElement_VariableCount", - "tests": [ - { - "packed": "0fbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaa", - "unpacked": { - "s": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707 - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_EnumElement_UnknownSize", - "tests": [ - { - "packed": "bbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddccbbaaddcc", - "unpacked": { - "s": { - "array": [ - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445, - 43707, - 52445 - ] - } - } - }, - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_ConstantSize", - "tests": [ - { - "packed": "00ff3b00", - "unpacked": { - "s": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 59 - }, - { - "a": 0 - } - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_VariableSize", - "tests": [ - { - "packed": "0f00ff3d00ff3e00ff3f00ff3000ff41", - "unpacked": { - "s": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 61 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 62 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 63 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 48 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 65 - } - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_VariableCount", - "tests": [ - { - "packed": "0f00ff4300ff4400ff4500ff4600ff47", - "unpacked": { - "s": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 67 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 68 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 69 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 70 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 71 - } - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_UnknownSize", - "tests": [ - { - "packed": "00ff4900ff4a00ff4b00ff4c00ff4d00ff4e00ff4f00ff4000ff5100ff5200ff", - "unpacked": { - "s": { - "array": [ - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 73 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 74 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 75 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 76 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 77 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 78 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 79 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 64 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 81 - }, - { - "a": 0 - }, - { - "a": 255 - }, - { - "a": 82 - }, - { - "a": 0 - }, - { - "a": 255 - } - ] - } - } - }, - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_ConstantSize", - "tests": [ - { - "packed": "00035455560003575859", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 84, - 85, - 86 - ] - }, - { - "array": [] - }, - { - "array": [ - 87, - 88, - 89 - ] - } - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_VariableSize", - "tests": [ - { - "packed": "0f00035d5e5f00035061620003636465", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 93, - 94, - 95 - ] - }, - { - "array": [] - }, - { - "array": [ - 80, - 97, - 98 - ] - }, - { - "array": [] - }, - { - "array": [ - 99, - 100, - 101 - ] - } - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_VariableCount", - "tests": [ - { - "packed": "0f0003696a6b00036c6d6e00036f607100037273740003757677000378797a00037b7c7d00", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 105, - 106, - 107 - ] - }, - { - "array": [] - }, - { - "array": [ - 108, - 109, - 110 - ] - }, - { - "array": [] - }, - { - "array": [ - 111, - 96, - 113 - ] - }, - { - "array": [] - }, - { - "array": [ - 114, - 115, - 116 - ] - }, - { - "array": [] - }, - { - "array": [ - 117, - 118, - 119 - ] - }, - { - "array": [] - }, - { - "array": [ - 120, - 121, - 122 - ] - }, - { - "array": [] - }, - { - "array": [ - 123, - 124, - 125 - ] - }, - { - "array": [] - } - ] - } - } - }, - { - "packed": "00", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_UnknownSize", - "tests": [ - { - "packed": "00038182830003848586000387888900038a8b8c00038d8e8f0003809192000393949500039697980003999a9b00039c9d9e00039f90a10003a2a3a40003a5a6a70003a8a9aa0003abacad0003aeafa0", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 129, - 130, - 131 - ] - }, - { - "array": [] - }, - { - "array": [ - 132, - 133, - 134 - ] - }, - { - "array": [] - }, - { - "array": [ - 135, - 136, - 137 - ] - }, - { - "array": [] - }, - { - "array": [ - 138, - 139, - 140 - ] - }, - { - "array": [] - }, - { - "array": [ - 141, - 142, - 143 - ] - }, - { - "array": [] - }, - { - "array": [ - 128, - 145, - 146 - ] - }, - { - "array": [] - }, - { - "array": [ - 147, - 148, - 149 - ] - }, - { - "array": [] - }, - { - "array": [ - 150, - 151, - 152 - ] - }, - { - "array": [] - }, - { - "array": [ - 153, - 154, - 155 - ] - }, - { - "array": [] - }, - { - "array": [ - 156, - 157, - 158 - ] - }, - { - "array": [] - }, - { - "array": [ - 159, - 144, - 161 - ] - }, - { - "array": [] - }, - { - "array": [ - 162, - 163, - 164 - ] - }, - { - "array": [] - }, - { - "array": [ - 165, - 166, - 167 - ] - }, - { - "array": [] - }, - { - "array": [ - 168, - 169, - 170 - ] - }, - { - "array": [] - }, - { - "array": [ - 171, - 172, - 173 - ] - }, - { - "array": [] - }, - { - "array": [ - 174, - 175, - 160 - ] - } - ] - } - } - }, - { - "packed": "", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_SizeModifier", - "tests": [ - { - "packed": "0d0003b4b5b60003b7b8b900", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 180, - 181, - 182 - ] - }, - { - "array": [] - }, - { - "array": [ - 183, - 184, - 185 - ] - }, - { - "array": [] - } - ] - } - } - }, - { - "packed": "02", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_SizedElement_VariableSize_Padded", - "tests": [ - { - "packed": "0000000000000000000000000000000000", - "unpacked": { - "s": { - "array": [] - } - } - }, - { - "packed": "0edebbf0bb12cc34cc56cc78cc9acc0000", - "unpacked": { - "s": { - "array": [ - 48094, - 48112, - 52242, - 52276, - 52310, - 52344, - 52378 - ] - } - } - } - ] - }, - { - "packet": "Struct_Array_Field_UnsizedElement_VariableCount_Padded", - "tests": [ - { - "packed": "070003cbcccd0003cecfc00003d1d2d300", - "unpacked": { - "s": { - "array": [ - { - "array": [] - }, - { - "array": [ - 203, - 204, - 205 - ] - }, - { - "array": [] - }, - { - "array": [ - 206, - 207, - 192 - ] - }, - { - "array": [] - }, - { - "array": [ - 209, - 210, - 211 - ] - }, - { - "array": [] - } - ] - } - } - }, - { - "packed": "0000000000000000000000000000000000", - "unpacked": { - "s": { - "array": [] - } - } - } - ] - } -] \ No newline at end of file diff --git a/tools/pdl/tests/custom_types.py b/tools/pdl/tests/custom_types.py deleted file mode 100644 index cac9896244710a85785b62549296b08bce571ca1..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/custom_types.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2023 Google LLC -# -# 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 -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from dataclasses import dataclass -from typing import Tuple - - -@dataclass -class SizedCustomField: - - def __init__(self, value: int = 0): - self.value = value - - def parse(span: bytes) -> Tuple['SizedCustomField', bytes]: - return (SizedCustomField(span[0]), span[1:]) - - def parse_all(span: bytes) -> 'SizedCustomField': - assert (len(span) == 1) - return SizedCustomField(span[0]) - - @property - def size(self) -> int: - return 1 - - -@dataclass -class UnsizedCustomField: - - def __init__(self, value: int = 0): - self.value = value - - def parse(span: bytes) -> Tuple['UnsizedCustomField', bytes]: - return (UnsizedCustomField(span[0]), span[1:]) - - def parse_all(span: bytes) -> 'UnsizedCustomField': - assert (len(span) == 1) - return UnsizedCustomField(span[0]) - - @property - def size(self) -> int: - return 1 - - -def Checksum(span: bytes) -> int: - return sum(span) % 256 diff --git a/tools/pdl/tests/examples/array-field.pdl b/tools/pdl/tests/examples/array-field.pdl deleted file mode 100644 index 070a6cc53243bfddfa1ffe5daebfd3e5230dff43..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/array-field.pdl +++ /dev/null @@ -1,39 +0,0 @@ -little_endian_packets - -custom_field custom: 1 "custom" -checksum checksum: 1 "checksum" - -enum Enum : 1 { - tag = 0, -} - -struct Struct { - a: 1, -} - -packet Packet { - a: 1, -} - -group Group { - a: 1, -} - -packet InvalidKind { - array_0: Group[], - array_1: Packet[], - array_2: checksum[], -} - -packet UndeclaredType { - array: Unknown[], -} - -packet Correct { - array_0: custom[], - array_1: Enum[], - array_2: Struct[], - array_3: 1[], - array_4: 1[42], - array_5: 1[+2], -} diff --git a/tools/pdl/tests/examples/checksum-field.pdl b/tools/pdl/tests/examples/checksum-field.pdl deleted file mode 100644 index 0e1a98b266565f3b7f0cab09b9a56dd39e997684..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/checksum-field.pdl +++ /dev/null @@ -1,22 +0,0 @@ -little_endian_packets - -checksum crc16: 16 "crc16" - -packet Undefined { - _checksum_start_ (crc16), -} - -packet InvalidType { - crc16: 16, - _checksum_start_ (crc16), -} - -packet InvalidOrder { - _checksum_start_ (crc16), - crc16: crc16, -} - -packet Correct { - crc16: crc16, - _checksum_start_ (crc16), -} diff --git a/tools/pdl/tests/examples/count-field.pdl b/tools/pdl/tests/examples/count-field.pdl deleted file mode 100644 index a88cccdec8c3056987e4a4f55a00521bd7baaf04..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/count-field.pdl +++ /dev/null @@ -1,25 +0,0 @@ -little_endian_packets - -packet Undefined { - _count_ (array): 8, -} - -packet InvalidType { - _count_ (array): 8, - array: 16, -} - -packet InvalidOrder { - array: 16[], - _count_ (array): 8, -} - -packet InvalidSize { - _count_ (array): 8, - array: 16[32], -} - -packet Correct { - _count_ (array): 8, - array: 16[], -} diff --git a/tools/pdl/tests/examples/decl-scope.pdl b/tools/pdl/tests/examples/decl-scope.pdl deleted file mode 100644 index c1391ab3f2bb2f363dc66fafa466a2bc640a1f9e..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/decl-scope.pdl +++ /dev/null @@ -1,26 +0,0 @@ - -// Clashes with custom_field, struct, enum -checksum decl_name: 16 "crc16" - -// Clashes with checksum, struct, enum -custom_field decl_name: 1 "custom" - -// Clashes with checksum, custom_field, struct -enum decl_name : 1 { - A = 1, -} - -// Clashes with checksum, custom_field, enum -struct decl_name { - a: 1, -} - -// OK -group decl_name { - a: 1, -} - -// OK -packet decl_name { - a: 1, -} diff --git a/tools/pdl/tests/examples/example.pdl b/tools/pdl/tests/examples/example.pdl deleted file mode 100644 index b34d1400dbfb67fa028a1be35d2aaa6b2e1f4d59..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/example.pdl +++ /dev/null @@ -1,78 +0,0 @@ -// line comment -/* block comment */ - -little_endian_packets - -/* stuff */ -enum FourBits : 4 { - ONE = 1, - TWO = 2, - THREE = 3, - FIVE = 5, - TEN = 10, - LAZY_ME = 15, -} - -/* other stuff */ -enum FourBits : 4 { - ONE = 1, - TWO = 2, - THREE = 3, - FIVE = 5, - TEN = 10, - LAZY_ME = 15 -} - -packet Test { - /* Checksum */ - _checksum_start_ (crc16), - /* Padding */ - _padding_ [1], - /* Size */ - _size_ (_payload_) : 1, - _size_ (_body_) : 1, - _size_ (id) : 1, - /* Body */ - _body_, - /* Payload */ - _payload_, - _payload_ : [+1], - /* Fixed */ - _fixed_ = 1:1, - _fixed_ = id:id, - /* Reserved */ - _reserved_ : 1, - /* Array */ - id: 1[+1], - id: id[+1], - id: 1[1], - id: id[1], - id: 1[], - id: id[], - /* Scalar */ - id: 1, - /* Typedef */ - id : id, - /* Group */ - id { a=1, b=2 }, - id, -} - -packet TestChild : Test { -} - -packet TestChild (a=1, b=2) { -} - -packet TestChild : Test (a=1, b=2) { -} - -checksum id: 1 "id" - -custom_field id : 1 "id" -custom_field id "id" - -test Test { - "1111", - "2222", -} diff --git a/tools/pdl/tests/examples/fixed-field.pdl b/tools/pdl/tests/examples/fixed-field.pdl deleted file mode 100644 index e69fc7e37fa86d3faef8ae018b714465e615d37c..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/fixed-field.pdl +++ /dev/null @@ -1,22 +0,0 @@ -little_endian_packets - -enum Enum : 1 { - tag = 0, -} - -packet InvalidValue { - _fixed_ = 1: 256, -} - -packet UndeclaredEnum { - _fixed_ = tag : InvalidEnum, -} - -packet UndeclaredTag { - _fixed_ = invalid_tag : Enum, -} - -packet Correct { - _fixed_ = 1: 256, - _fixed_ = tag: Enum, -} diff --git a/tools/pdl/tests/examples/group-constraint.pdl b/tools/pdl/tests/examples/group-constraint.pdl deleted file mode 100644 index 34ee2ab7ef90328d400c513a74f8cec1739340a3..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/group-constraint.pdl +++ /dev/null @@ -1,39 +0,0 @@ -little_endian_packets - -custom_field custom_field: 1 "custom" -checksum checksum: 1 "checksum" - -enum Enum : 1 { - tag = 0, -} - -group Group { - a: 4, - b: Enum, - c: custom_field, - d: checksum, -} - -struct Undeclared { - Group { e=1 }, -} - -struct Redeclared { - Group { a=1, a=2 }, -} - -struct TypeMismatch { - Group { a=tag, b=1, c=1, d=1 }, -} - -struct InvalidLiteral { - Group { a=42 }, -} - -struct UndeclaredTag { - Group { b=undeclared_tag }, -} - -struct Correct { - Group { a=1, b=tag }, -} diff --git a/tools/pdl/tests/examples/packet.pdl b/tools/pdl/tests/examples/packet.pdl deleted file mode 100644 index 9b9ca201d65c4210ab442ba9cf82ce4dae574968..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/packet.pdl +++ /dev/null @@ -1,52 +0,0 @@ -little_endian_packets - -custom_field custom: 1 "custom" -checksum checksum: 1 "checksum" - -enum Enum : 1 { - tag = 0, -} - -packet Packet { - a: 4, - b: Enum, - c: custom, - d: checksum, -} - -struct Struct { - a: 4, -} - -packet RecursivePacket_0 : RecursivePacket_1 { -} - -packet RecursivePacket_1 : RecursivePacket_0 { -} - -packet InvalidParent : Struct { -} - -packet UndeclaredParent : FooBar { -} - -packet UnnecessaryConstraints (a=1) { -} - -packet Undeclared : Packet (c=1) { -} - -packet Redeclared : Packet (a=1, a=2) { -} - -packet TypeMismatch : Packet (a=tag, b=1, c=1, d=1) { -} - -packet InvalidLiteral : Packet (a=42) { -} - -packet UndeclaredTag : Packet (b=undeclared_tag) { -} - -packet Correct : Packet (a=1, b=tag) { -} diff --git a/tools/pdl/tests/examples/recurse.pdl b/tools/pdl/tests/examples/recurse.pdl deleted file mode 100644 index ad3a2009815497f740e01b4a4a5366f0368d9b0b..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/recurse.pdl +++ /dev/null @@ -1,38 +0,0 @@ - -struct Struct_0: Struct_1 { -} - -struct Struct_1: Struct_0 { -} - - -struct Packet_0: Packet_1 { -} - -struct Packet_1: Packet_0 { -} - - -group Group_0 { - Group_1 -} - -struct Struct_2 { - Group_0 -} - -group Group_1 { - a: Struct_2 -} - - -struct Struct_3: Struct_4 { -} - -struct Struct_4 { - Group_2 -} - -group Group_2 { - a: Struct_3 -} diff --git a/tools/pdl/tests/examples/size-field.pdl b/tools/pdl/tests/examples/size-field.pdl deleted file mode 100644 index dfa9ad7f5b428f2968ab8df2e51a660d6492b44d..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/size-field.pdl +++ /dev/null @@ -1,58 +0,0 @@ -little_endian_packets - -packet Undefined { - _size_ (array): 8, -} - -packet UndefinedPayloadWithBody { - _size_ (_payload_): 8, - _body_, -} - -packet UndefinedPayload { - _size_ (_payload_): 8, -} - -packet UndefinedBodyWithPayload { - _size_ (_body_): 8, - _payload_, -} - -packet UndefinedBody { - _size_ (_body_): 8, -} - -packet InvalidType { - _size_ (array): 8, - array: 16, -} - -packet InvalidArrayOrder { - array: 16[], - _size_ (array): 8, -} - -packet InvalidPayloadOrder { - _payload_, - _size_ (_payload_): 8, -} - -packet InvalidBodyOrder { - _body_, - _size_ (_body_): 8, -} - -packet CorrectArray { - _size_ (array): 8, - array: 16[], -} - -packet CorrectPayload { - _size_ (_payload_): 8, - _payload_, -} - -packet CorrectBody { - _size_ (_body_): 8, - _body_, -} diff --git a/tools/pdl/tests/examples/struct.pdl b/tools/pdl/tests/examples/struct.pdl deleted file mode 100644 index d8ed439a2e11b330ec534efc36ea80dcb4c798d4..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/struct.pdl +++ /dev/null @@ -1,52 +0,0 @@ -little_endian_packets - -custom_field custom: 1 "custom" -checksum checksum: 1 "checksum" - -enum Enum : 1 { - tag = 0, -} - -struct Struct { - a: 4, - b: Enum, - c: custom, - d: checksum, -} - -packet Packet { - a: 4, -} - -struct RecursiveStruct_0 : RecursiveStruct_1 { -} - -struct RecursiveStruct_1 : RecursiveStruct_0 { -} - -struct InvalidParent : Packet { -} - -struct UndeclaredParent : FooBar { -} - -struct UnnecessaryConstraints (a=1) { -} - -struct Undeclared : Struct (c=1) { -} - -struct Redeclared : Struct (a=1, a=2) { -} - -struct TypeMismatch : Struct (a=tag, b=1, c=1, d=1) { -} - -struct InvalidLiteral : Struct (a=42) { -} - -struct UndeclaredTag : Struct (b=undeclared_tag) { -} - -struct Correct : Struct (a=1, b=tag) { -} diff --git a/tools/pdl/tests/examples/typedef-field.pdl b/tools/pdl/tests/examples/typedef-field.pdl deleted file mode 100644 index 2e5667655831070cefc631d62887c87f09c2d11f..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/examples/typedef-field.pdl +++ /dev/null @@ -1,36 +0,0 @@ -little_endian_packets - -custom_field custom: 1 "custom" -checksum checksum: 1 "checksum" - -enum Enum : 1 { - tag = 0, -} - -struct Struct { - a: 1, -} - -packet Packet { - a: 1, -} - -group Group { - a: 1, -} - -packet InvalidKind { - typedef_0: Group, - typedef_1: Packet, -} - -packet UndeclaredType { - typedef: Unknown, -} - -packet Correct { - typedef_0: custom, - typedef_1: checksum, - typedef_2: Enum, - typedef_3: Struct, -} diff --git a/tools/pdl/tests/generated/enum_declaration_big_endian.rs b/tools/pdl/tests/generated/enum_declaration_big_endian.rs deleted file mode 100644 index f598c3408c0eb6de92f1dcd1c10a8120bd3d7745..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/enum_declaration_big_endian.rs +++ /dev/null @@ -1,407 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum IncompleteTruncated { - A = 0x0, - B = 0x1, -} -impl TryFrom for IncompleteTruncated { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(IncompleteTruncated::A), - 0x1 => Ok(IncompleteTruncated::B), - _ => Err(value), - } - } -} -impl From<&IncompleteTruncated> for u8 { - fn from(value: &IncompleteTruncated) -> Self { - match value { - IncompleteTruncated::A => 0x0, - IncompleteTruncated::B => 0x1, - } - } -} -impl From for u8 { - fn from(value: IncompleteTruncated) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum IncompleteTruncatedWithRange { - A, - X, - Y, - B(Private), -} -impl TryFrom for IncompleteTruncatedWithRange { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(IncompleteTruncatedWithRange::A), - 0x1 => Ok(IncompleteTruncatedWithRange::X), - 0x2 => Ok(IncompleteTruncatedWithRange::Y), - 0x1..=0x6 => Ok(IncompleteTruncatedWithRange::B(Private(value))), - _ => Err(value), - } - } -} -impl From<&IncompleteTruncatedWithRange> for u8 { - fn from(value: &IncompleteTruncatedWithRange) -> Self { - match value { - IncompleteTruncatedWithRange::A => 0x0, - IncompleteTruncatedWithRange::X => 0x1, - IncompleteTruncatedWithRange::Y => 0x2, - IncompleteTruncatedWithRange::B(Private(value)) => *value, - } - } -} -impl From for u8 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum CompleteTruncated { - A = 0x0, - B = 0x1, - C = 0x2, - D = 0x3, - E = 0x4, - F = 0x5, - G = 0x6, - H = 0x7, -} -impl TryFrom for CompleteTruncated { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(CompleteTruncated::A), - 0x1 => Ok(CompleteTruncated::B), - 0x2 => Ok(CompleteTruncated::C), - 0x3 => Ok(CompleteTruncated::D), - 0x4 => Ok(CompleteTruncated::E), - 0x5 => Ok(CompleteTruncated::F), - 0x6 => Ok(CompleteTruncated::G), - 0x7 => Ok(CompleteTruncated::H), - _ => Err(value), - } - } -} -impl From<&CompleteTruncated> for u8 { - fn from(value: &CompleteTruncated) -> Self { - match value { - CompleteTruncated::A => 0x0, - CompleteTruncated::B => 0x1, - CompleteTruncated::C => 0x2, - CompleteTruncated::D => 0x3, - CompleteTruncated::E => 0x4, - CompleteTruncated::F => 0x5, - CompleteTruncated::G => 0x6, - CompleteTruncated::H => 0x7, - } - } -} -impl From for u8 { - fn from(value: CompleteTruncated) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum CompleteTruncatedWithRange { - A, - X, - Y, - B(Private), -} -impl TryFrom for CompleteTruncatedWithRange { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(CompleteTruncatedWithRange::A), - 0x1 => Ok(CompleteTruncatedWithRange::X), - 0x2 => Ok(CompleteTruncatedWithRange::Y), - 0x1..=0x7 => Ok(CompleteTruncatedWithRange::B(Private(value))), - _ => Err(value), - } - } -} -impl From<&CompleteTruncatedWithRange> for u8 { - fn from(value: &CompleteTruncatedWithRange) -> Self { - match value { - CompleteTruncatedWithRange::A => 0x0, - CompleteTruncatedWithRange::X => 0x1, - CompleteTruncatedWithRange::Y => 0x2, - CompleteTruncatedWithRange::B(Private(value)) => *value, - } - } -} -impl From for u8 { - fn from(value: CompleteTruncatedWithRange) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum CompleteWithRange { - A, - B, - C(Private), -} -impl TryFrom for CompleteWithRange { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(CompleteWithRange::A), - 0x1 => Ok(CompleteWithRange::B), - 0x2..=0xff => Ok(CompleteWithRange::C(Private(value))), - } - } -} -impl From<&CompleteWithRange> for u8 { - fn from(value: &CompleteWithRange) -> Self { - match value { - CompleteWithRange::A => 0x0, - CompleteWithRange::B => 0x1, - CompleteWithRange::C(Private(value)) => *value, - } - } -} -impl From for u8 { - fn from(value: CompleteWithRange) -> Self { - (&value).into() - } -} -impl From for i16 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} diff --git a/tools/pdl/tests/generated/enum_declaration_little_endian.rs b/tools/pdl/tests/generated/enum_declaration_little_endian.rs deleted file mode 100644 index f598c3408c0eb6de92f1dcd1c10a8120bd3d7745..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/enum_declaration_little_endian.rs +++ /dev/null @@ -1,407 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum IncompleteTruncated { - A = 0x0, - B = 0x1, -} -impl TryFrom for IncompleteTruncated { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(IncompleteTruncated::A), - 0x1 => Ok(IncompleteTruncated::B), - _ => Err(value), - } - } -} -impl From<&IncompleteTruncated> for u8 { - fn from(value: &IncompleteTruncated) -> Self { - match value { - IncompleteTruncated::A => 0x0, - IncompleteTruncated::B => 0x1, - } - } -} -impl From for u8 { - fn from(value: IncompleteTruncated) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: IncompleteTruncated) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum IncompleteTruncatedWithRange { - A, - X, - Y, - B(Private), -} -impl TryFrom for IncompleteTruncatedWithRange { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(IncompleteTruncatedWithRange::A), - 0x1 => Ok(IncompleteTruncatedWithRange::X), - 0x2 => Ok(IncompleteTruncatedWithRange::Y), - 0x1..=0x6 => Ok(IncompleteTruncatedWithRange::B(Private(value))), - _ => Err(value), - } - } -} -impl From<&IncompleteTruncatedWithRange> for u8 { - fn from(value: &IncompleteTruncatedWithRange) -> Self { - match value { - IncompleteTruncatedWithRange::A => 0x0, - IncompleteTruncatedWithRange::X => 0x1, - IncompleteTruncatedWithRange::Y => 0x2, - IncompleteTruncatedWithRange::B(Private(value)) => *value, - } - } -} -impl From for u8 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: IncompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum CompleteTruncated { - A = 0x0, - B = 0x1, - C = 0x2, - D = 0x3, - E = 0x4, - F = 0x5, - G = 0x6, - H = 0x7, -} -impl TryFrom for CompleteTruncated { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(CompleteTruncated::A), - 0x1 => Ok(CompleteTruncated::B), - 0x2 => Ok(CompleteTruncated::C), - 0x3 => Ok(CompleteTruncated::D), - 0x4 => Ok(CompleteTruncated::E), - 0x5 => Ok(CompleteTruncated::F), - 0x6 => Ok(CompleteTruncated::G), - 0x7 => Ok(CompleteTruncated::H), - _ => Err(value), - } - } -} -impl From<&CompleteTruncated> for u8 { - fn from(value: &CompleteTruncated) -> Self { - match value { - CompleteTruncated::A => 0x0, - CompleteTruncated::B => 0x1, - CompleteTruncated::C => 0x2, - CompleteTruncated::D => 0x3, - CompleteTruncated::E => 0x4, - CompleteTruncated::F => 0x5, - CompleteTruncated::G => 0x6, - CompleteTruncated::H => 0x7, - } - } -} -impl From for u8 { - fn from(value: CompleteTruncated) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: CompleteTruncated) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum CompleteTruncatedWithRange { - A, - X, - Y, - B(Private), -} -impl TryFrom for CompleteTruncatedWithRange { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(CompleteTruncatedWithRange::A), - 0x1 => Ok(CompleteTruncatedWithRange::X), - 0x2 => Ok(CompleteTruncatedWithRange::Y), - 0x1..=0x7 => Ok(CompleteTruncatedWithRange::B(Private(value))), - _ => Err(value), - } - } -} -impl From<&CompleteTruncatedWithRange> for u8 { - fn from(value: &CompleteTruncatedWithRange) -> Self { - match value { - CompleteTruncatedWithRange::A => 0x0, - CompleteTruncatedWithRange::X => 0x1, - CompleteTruncatedWithRange::Y => 0x2, - CompleteTruncatedWithRange::B(Private(value)) => *value, - } - } -} -impl From for u8 { - fn from(value: CompleteTruncatedWithRange) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: CompleteTruncatedWithRange) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum CompleteWithRange { - A, - B, - C(Private), -} -impl TryFrom for CompleteWithRange { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x0 => Ok(CompleteWithRange::A), - 0x1 => Ok(CompleteWithRange::B), - 0x2..=0xff => Ok(CompleteWithRange::C(Private(value))), - } - } -} -impl From<&CompleteWithRange> for u8 { - fn from(value: &CompleteWithRange) -> Self { - match value { - CompleteWithRange::A => 0x0, - CompleteWithRange::B => 0x1, - CompleteWithRange::C(Private(value)) => *value, - } - } -} -impl From for u8 { - fn from(value: CompleteWithRange) -> Self { - (&value).into() - } -} -impl From for i16 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: CompleteWithRange) -> Self { - u8::from(value) as Self - } -} diff --git a/tools/pdl/tests/generated/packet_decl_24bit_enum_array_big_endian.rs b/tools/pdl/tests/generated/packet_decl_24bit_enum_array_big_endian.rs deleted file mode 100644 index 77b7af35271e5e633f69405fb08603145503d124..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_24bit_enum_array_big_endian.rs +++ /dev/null @@ -1,211 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))] -pub enum Foo { - FooBar = 0x1, - Baz = 0x2, -} -impl TryFrom for Foo { - type Error = u32; - fn try_from(value: u32) -> std::result::Result { - match value { - 0x1 => Ok(Foo::FooBar), - 0x2 => Ok(Foo::Baz), - _ => Err(value), - } - } -} -impl From<&Foo> for u32 { - fn from(value: &Foo) -> Self { - match value { - Foo::FooBar => 0x1, - Foo::Baz => 0x2, - } - } -} -impl From for u32 { - fn from(value: Foo) -> Self { - (&value).into() - } -} -impl From for i32 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} -impl From for i64 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: [Foo; 5], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: [Foo; 5], -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 15 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 * 3 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 5 * 3, - got: bytes.get().remaining(), - }); - } - let x = (0..5) - .map(|_| { - Foo::try_from(bytes.get_mut().get_uint(3) as u32).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: String::new(), - value: 0, - type_: "Foo".to_string(), - } - }) - }) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_uint(u32::from(elem) as u64, 3); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 15 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &[Foo; 5] { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_24bit_enum_array_little_endian.rs b/tools/pdl/tests/generated/packet_decl_24bit_enum_array_little_endian.rs deleted file mode 100644 index 74498b4a5ebe2a84abc14a05310370df494f72fb..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_24bit_enum_array_little_endian.rs +++ /dev/null @@ -1,211 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))] -pub enum Foo { - FooBar = 0x1, - Baz = 0x2, -} -impl TryFrom for Foo { - type Error = u32; - fn try_from(value: u32) -> std::result::Result { - match value { - 0x1 => Ok(Foo::FooBar), - 0x2 => Ok(Foo::Baz), - _ => Err(value), - } - } -} -impl From<&Foo> for u32 { - fn from(value: &Foo) -> Self { - match value { - Foo::FooBar => 0x1, - Foo::Baz => 0x2, - } - } -} -impl From for u32 { - fn from(value: Foo) -> Self { - (&value).into() - } -} -impl From for i32 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} -impl From for i64 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: [Foo; 5], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: [Foo; 5], -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 15 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 * 3 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 5 * 3, - got: bytes.get().remaining(), - }); - } - let x = (0..5) - .map(|_| { - Foo::try_from(bytes.get_mut().get_uint_le(3) as u32).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: String::new(), - value: 0, - type_: "Foo".to_string(), - } - }) - }) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_uint_le(u32::from(elem) as u64, 3); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 15 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &[Foo; 5] { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_24bit_enum_big_endian.rs b/tools/pdl/tests/generated/packet_decl_24bit_enum_big_endian.rs deleted file mode 100644 index 1a7ae4c6bc9b82498096e03797cb3b653df669b2..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_24bit_enum_big_endian.rs +++ /dev/null @@ -1,203 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))] -pub enum Foo { - A = 0x1, - B = 0x2, -} -impl TryFrom for Foo { - type Error = u32; - fn try_from(value: u32) -> std::result::Result { - match value { - 0x1 => Ok(Foo::A), - 0x2 => Ok(Foo::B), - _ => Err(value), - } - } -} -impl From<&Foo> for u32 { - fn from(value: &Foo) -> Self { - match value { - Foo::A => 0x1, - Foo::B => 0x2, - } - } -} -impl From for u32 { - fn from(value: Foo) -> Self { - (&value).into() - } -} -impl From for i32 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} -impl From for i64 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Foo, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Foo, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let x = Foo::try_from(bytes.get_mut().get_uint(3) as u32).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: "x".to_string(), - value: bytes.get_mut().get_uint(3) as u32 as u64, - type_: "Foo".to_string(), - } - })?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_uint(u32::from(self.x) as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> Foo { - self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_24bit_enum_little_endian.rs b/tools/pdl/tests/generated/packet_decl_24bit_enum_little_endian.rs deleted file mode 100644 index 1edc62686cf8c82884a5d22a909e7b8188bd6b44..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_24bit_enum_little_endian.rs +++ /dev/null @@ -1,203 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))] -pub enum Foo { - A = 0x1, - B = 0x2, -} -impl TryFrom for Foo { - type Error = u32; - fn try_from(value: u32) -> std::result::Result { - match value { - 0x1 => Ok(Foo::A), - 0x2 => Ok(Foo::B), - _ => Err(value), - } - } -} -impl From<&Foo> for u32 { - fn from(value: &Foo) -> Self { - match value { - Foo::A => 0x1, - Foo::B => 0x2, - } - } -} -impl From for u32 { - fn from(value: Foo) -> Self { - (&value).into() - } -} -impl From for i32 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} -impl From for i64 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - u32::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Foo, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Foo, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let x = Foo::try_from(bytes.get_mut().get_uint_le(3) as u32).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: "x".to_string(), - value: bytes.get_mut().get_uint_le(3) as u32 as u64, - type_: "Foo".to_string(), - } - })?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_uint_le(u32::from(self.x) as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> Foo { - self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_24bit_scalar_array_big_endian.rs b/tools/pdl/tests/generated/packet_decl_24bit_scalar_array_big_endian.rs deleted file mode 100644 index 2289d06265d9b1f698d2143359ff22ca91d3af95..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_24bit_scalar_array_big_endian.rs +++ /dev/null @@ -1,155 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: [u32; 5], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: [u32; 5], -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 15 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 * 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 5 * 3, - got: bytes.get().remaining(), - }); - } - let x = (0..5) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_uint(3) as u32)) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_uint(*elem as u64, 3); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 15 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> &[u32; 5] { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_24bit_scalar_array_little_endian.rs b/tools/pdl/tests/generated/packet_decl_24bit_scalar_array_little_endian.rs deleted file mode 100644 index 8cf1ec587f1f5b8f5a09a8f439a96a85343f2b42..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_24bit_scalar_array_little_endian.rs +++ /dev/null @@ -1,155 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: [u32; 5], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: [u32; 5], -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 15 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 * 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 5 * 3, - got: bytes.get().remaining(), - }); - } - let x = (0..5) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_uint_le(3) as u32)) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_uint_le(*elem as u64, 3); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 15 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> &[u32; 5] { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_24bit_scalar_big_endian.rs b/tools/pdl/tests/generated/packet_decl_24bit_scalar_big_endian.rs deleted file mode 100644 index 4782eabd3c23e7bd70b033b8c0a2991a853c9173..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_24bit_scalar_big_endian.rs +++ /dev/null @@ -1,152 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: u32, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: u32, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_uint(3) as u32; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.x > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "x", self.x, 0xff_ffff); - } - buffer.put_uint(self.x as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> u32 { - self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_24bit_scalar_little_endian.rs b/tools/pdl/tests/generated/packet_decl_24bit_scalar_little_endian.rs deleted file mode 100644 index a0f1c58e0d85cea1eb6e8bc077ea6f2f0142e26a..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_24bit_scalar_little_endian.rs +++ /dev/null @@ -1,152 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: u32, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: u32, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_uint_le(3) as u32; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.x > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "x", self.x, 0xff_ffff); - } - buffer.put_uint_le(self.x as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> u32 { - self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_64bit_enum_array_big_endian.rs b/tools/pdl/tests/generated/packet_decl_64bit_enum_array_big_endian.rs deleted file mode 100644 index c7ebf8b779551950e1b9ec1a8cf16488eefbc438..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_64bit_enum_array_big_endian.rs +++ /dev/null @@ -1,194 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u64", into = "u64"))] -pub enum Foo { - FooBar = 0x1, - Baz = 0x2, -} -impl TryFrom for Foo { - type Error = u64; - fn try_from(value: u64) -> std::result::Result { - match value { - 0x1 => Ok(Foo::FooBar), - 0x2 => Ok(Foo::Baz), - _ => Err(value), - } - } -} -impl From<&Foo> for u64 { - fn from(value: &Foo) -> Self { - match value { - Foo::FooBar => 0x1, - Foo::Baz => 0x2, - } - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - (&value).into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: [Foo; 7], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: [Foo; 7], -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 56 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 7 * 8 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 7 * 8, - got: bytes.get().remaining(), - }); - } - let x = (0..7) - .map(|_| { - Foo::try_from(bytes.get_mut().get_u64()).map_err(|_| Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: String::new(), - value: 0, - type_: "Foo".to_string(), - }) - }) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_u64(u64::from(elem)); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 56 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &[Foo; 7] { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_64bit_enum_array_little_endian.rs b/tools/pdl/tests/generated/packet_decl_64bit_enum_array_little_endian.rs deleted file mode 100644 index d8d0d72110fd8c0bad94fa5432b9d46d0c15af79..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_64bit_enum_array_little_endian.rs +++ /dev/null @@ -1,196 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u64", into = "u64"))] -pub enum Foo { - FooBar = 0x1, - Baz = 0x2, -} -impl TryFrom for Foo { - type Error = u64; - fn try_from(value: u64) -> std::result::Result { - match value { - 0x1 => Ok(Foo::FooBar), - 0x2 => Ok(Foo::Baz), - _ => Err(value), - } - } -} -impl From<&Foo> for u64 { - fn from(value: &Foo) -> Self { - match value { - Foo::FooBar => 0x1, - Foo::Baz => 0x2, - } - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - (&value).into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: [Foo; 7], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: [Foo; 7], -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 56 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 7 * 8 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 7 * 8, - got: bytes.get().remaining(), - }); - } - let x = (0..7) - .map(|_| { - Foo::try_from(bytes.get_mut().get_u64_le()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: String::new(), - value: 0, - type_: "Foo".to_string(), - } - }) - }) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_u64_le(u64::from(elem)); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 56 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &[Foo; 7] { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_64bit_enum_big_endian.rs b/tools/pdl/tests/generated/packet_decl_64bit_enum_big_endian.rs deleted file mode 100644 index 0dd9553ae73f205f59d5fcab7294757cdf63a128..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_64bit_enum_big_endian.rs +++ /dev/null @@ -1,187 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u64", into = "u64"))] -pub enum Foo { - A = 0x1, - B = 0x2, -} -impl TryFrom for Foo { - type Error = u64; - fn try_from(value: u64) -> std::result::Result { - match value { - 0x1 => Ok(Foo::A), - 0x2 => Ok(Foo::B), - _ => Err(value), - } - } -} -impl From<&Foo> for u64 { - fn from(value: &Foo) -> Self { - match value { - Foo::A => 0x1, - Foo::B => 0x2, - } - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - (&value).into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Foo, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Foo, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 8 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 8 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 8, - got: bytes.get().remaining(), - }); - } - let x = - Foo::try_from(bytes.get_mut().get_u64()).map_err(|_| Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: "x".to_string(), - value: bytes.get_mut().get_u64() as u64, - type_: "Foo".to_string(), - })?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u64(u64::from(self.x)); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 8 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> Foo { - self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_64bit_enum_little_endian.rs b/tools/pdl/tests/generated/packet_decl_64bit_enum_little_endian.rs deleted file mode 100644 index b9182cc28886011ee26eb165e6c076a3faf2cf4f..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_64bit_enum_little_endian.rs +++ /dev/null @@ -1,188 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u64", into = "u64"))] -pub enum Foo { - A = 0x1, - B = 0x2, -} -impl TryFrom for Foo { - type Error = u64; - fn try_from(value: u64) -> std::result::Result { - match value { - 0x1 => Ok(Foo::A), - 0x2 => Ok(Foo::B), - _ => Err(value), - } - } -} -impl From<&Foo> for u64 { - fn from(value: &Foo) -> Self { - match value { - Foo::A => 0x1, - Foo::B => 0x2, - } - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - (&value).into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Foo, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Foo, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 8 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 8 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 8, - got: bytes.get().remaining(), - }); - } - let x = Foo::try_from(bytes.get_mut().get_u64_le()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: "x".to_string(), - value: bytes.get_mut().get_u64_le() as u64, - type_: "Foo".to_string(), - } - })?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u64_le(u64::from(self.x)); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 8 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> Foo { - self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_64bit_scalar_array_big_endian.rs b/tools/pdl/tests/generated/packet_decl_64bit_scalar_array_big_endian.rs deleted file mode 100644 index b62eb41fa729b8710f905270d819674124b107f3..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_64bit_scalar_array_big_endian.rs +++ /dev/null @@ -1,155 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: [u64; 7], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: [u64; 7], -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 56 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 7 * 8 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 7 * 8, - got: bytes.get().remaining(), - }); - } - let x = (0..7) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_u64())) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_u64(*elem); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 56 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> &[u64; 7] { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_64bit_scalar_array_little_endian.rs b/tools/pdl/tests/generated/packet_decl_64bit_scalar_array_little_endian.rs deleted file mode 100644 index 0aee553e95d2a35abb4d85376fc49c26e6595eb8..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_64bit_scalar_array_little_endian.rs +++ /dev/null @@ -1,155 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: [u64; 7], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: [u64; 7], -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 56 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 7 * 8 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 7 * 8, - got: bytes.get().remaining(), - }); - } - let x = (0..7) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_u64_le())) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_u64_le(*elem); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 56 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> &[u64; 7] { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_64bit_scalar_big_endian.rs b/tools/pdl/tests/generated/packet_decl_64bit_scalar_big_endian.rs deleted file mode 100644 index bf640019c1f428fc89791ee179446ec28cb5b3cc..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_64bit_scalar_big_endian.rs +++ /dev/null @@ -1,149 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: u64, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: u64, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 8 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 8 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 8, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_u64(); - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u64(self.x); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 8 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> u64 { - self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_64bit_scalar_little_endian.rs b/tools/pdl/tests/generated/packet_decl_64bit_scalar_little_endian.rs deleted file mode 100644 index 63d838a41feaee800f6e3466588b678ff66dc31c..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_64bit_scalar_little_endian.rs +++ /dev/null @@ -1,149 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: u64, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: u64, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 8 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 8 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 8, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_u64_le(); - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u64_le(self.x); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 8 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> u64 { - self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_8bit_enum_array_big_endian.rs b/tools/pdl/tests/generated/packet_decl_8bit_enum_array_big_endian.rs deleted file mode 100644 index bf243090fbe30aba96e2840c02d2fd3175495289..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_8bit_enum_array_big_endian.rs +++ /dev/null @@ -1,224 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum Foo { - FooBar = 0x1, - Baz = 0x2, -} -impl TryFrom for Foo { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x1 => Ok(Foo::FooBar), - 0x2 => Ok(Foo::Baz), - _ => Err(value), - } - } -} -impl From<&Foo> for u8 { - fn from(value: &Foo) -> Self { - match value { - Foo::FooBar => 0x1, - Foo::Baz => 0x2, - } - } -} -impl From for u8 { - fn from(value: Foo) -> Self { - (&value).into() - } -} -impl From for i16 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: [Foo; 3], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: [Foo; 3], -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let x = (0..3) - .map(|_| { - Foo::try_from(bytes.get_mut().get_u8()).map_err(|_| Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: String::new(), - value: 0, - type_: "Foo".to_string(), - }) - }) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_u8(u8::from(elem)); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &[Foo; 3] { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_8bit_enum_array_little_endian.rs b/tools/pdl/tests/generated/packet_decl_8bit_enum_array_little_endian.rs deleted file mode 100644 index bf243090fbe30aba96e2840c02d2fd3175495289..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_8bit_enum_array_little_endian.rs +++ /dev/null @@ -1,224 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum Foo { - FooBar = 0x1, - Baz = 0x2, -} -impl TryFrom for Foo { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x1 => Ok(Foo::FooBar), - 0x2 => Ok(Foo::Baz), - _ => Err(value), - } - } -} -impl From<&Foo> for u8 { - fn from(value: &Foo) -> Self { - match value { - Foo::FooBar => 0x1, - Foo::Baz => 0x2, - } - } -} -impl From for u8 { - fn from(value: Foo) -> Self { - (&value).into() - } -} -impl From for i16 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: [Foo; 3], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: [Foo; 3], -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let x = (0..3) - .map(|_| { - Foo::try_from(bytes.get_mut().get_u8()).map_err(|_| Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: String::new(), - value: 0, - type_: "Foo".to_string(), - }) - }) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_u8(u8::from(elem)); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &[Foo; 3] { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_8bit_enum_big_endian.rs b/tools/pdl/tests/generated/packet_decl_8bit_enum_big_endian.rs deleted file mode 100644 index 60976c9607f6c1a02d67667f6a4d3a74c84e2fcd..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_8bit_enum_big_endian.rs +++ /dev/null @@ -1,217 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum Foo { - A = 0x1, - B = 0x2, -} -impl TryFrom for Foo { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x1 => Ok(Foo::A), - 0x2 => Ok(Foo::B), - _ => Err(value), - } - } -} -impl From<&Foo> for u8 { - fn from(value: &Foo) -> Self { - match value { - Foo::A => 0x1, - Foo::B => 0x2, - } - } -} -impl From for u8 { - fn from(value: Foo) -> Self { - (&value).into() - } -} -impl From for i16 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Foo, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Foo, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let x = - Foo::try_from(bytes.get_mut().get_u8()).map_err(|_| Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: "x".to_string(), - value: bytes.get_mut().get_u8() as u64, - type_: "Foo".to_string(), - })?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(u8::from(self.x)); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> Foo { - self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_8bit_enum_little_endian.rs b/tools/pdl/tests/generated/packet_decl_8bit_enum_little_endian.rs deleted file mode 100644 index 60976c9607f6c1a02d67667f6a4d3a74c84e2fcd..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_8bit_enum_little_endian.rs +++ /dev/null @@ -1,217 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum Foo { - A = 0x1, - B = 0x2, -} -impl TryFrom for Foo { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x1 => Ok(Foo::A), - 0x2 => Ok(Foo::B), - _ => Err(value), - } - } -} -impl From<&Foo> for u8 { - fn from(value: &Foo) -> Self { - match value { - Foo::A => 0x1, - Foo::B => 0x2, - } - } -} -impl From for u8 { - fn from(value: Foo) -> Self { - (&value).into() - } -} -impl From for i16 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: Foo) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Foo, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Foo, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let x = - Foo::try_from(bytes.get_mut().get_u8()).map_err(|_| Error::InvalidEnumValueError { - obj: "Bar".to_string(), - field: "x".to_string(), - value: bytes.get_mut().get_u8() as u64, - type_: "Foo".to_string(), - })?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(u8::from(self.x)); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> Foo { - self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_8bit_scalar_array_big_endian.rs b/tools/pdl/tests/generated/packet_decl_8bit_scalar_array_big_endian.rs deleted file mode 100644 index 8a0c287cc12e11c16100bd0a1df40e6b5a4e16b7..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_8bit_scalar_array_big_endian.rs +++ /dev/null @@ -1,155 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: [u8; 3], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: [u8; 3], -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let x = (0..3) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_u8())) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_u8(*elem); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> &[u8; 3] { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_8bit_scalar_array_little_endian.rs b/tools/pdl/tests/generated/packet_decl_8bit_scalar_array_little_endian.rs deleted file mode 100644 index 8a0c287cc12e11c16100bd0a1df40e6b5a4e16b7..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_8bit_scalar_array_little_endian.rs +++ /dev/null @@ -1,155 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: [u8; 3], -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: [u8; 3], -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let x = (0..3) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_u8())) - .collect::>>()? - .try_into() - .map_err(|_| Error::InvalidPacketError)?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - for elem in &self.x { - buffer.put_u8(*elem); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> &[u8; 3] { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_8bit_scalar_big_endian.rs b/tools/pdl/tests/generated/packet_decl_8bit_scalar_big_endian.rs deleted file mode 100644 index 103eeb32ddf81d9f7923e5844fad7fd65a219040..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_8bit_scalar_big_endian.rs +++ /dev/null @@ -1,149 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: u8, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_u8(); - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.x); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> u8 { - self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_8bit_scalar_little_endian.rs b/tools/pdl/tests/generated/packet_decl_8bit_scalar_little_endian.rs deleted file mode 100644 index 103eeb32ddf81d9f7923e5844fad7fd65a219040..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_8bit_scalar_little_endian.rs +++ /dev/null @@ -1,149 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: u8, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_u8(); - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.x); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> u8 { - self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_array_dynamic_count_big_endian.rs b/tools/pdl/tests/generated/packet_decl_array_dynamic_count_big_endian.rs deleted file mode 100644 index 412285fb8888292a2d6b41f79a29cf18f069c3fd..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_array_dynamic_count_big_endian.rs +++ /dev/null @@ -1,176 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - padding: u8, - x: Vec, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub padding: u8, - pub x: Vec, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u8(); - let x_count = (chunk & 0x1f) as usize; - let padding = ((chunk >> 5) & 0x7); - if bytes.get().remaining() < x_count { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: x_count, - got: bytes.get().remaining(), - }); - } - let x = (0..x_count) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_uint(3) as u32)) - .collect::>>()?; - Ok(Self { padding, x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.x.len() > 0x1f { - panic!("Invalid length for {}::{}: {} > {}", "Foo", "x", self.x.len(), 0x1f); - } - if self.padding > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "padding", self.padding, 0x7); - } - let value = self.x.len() as u8 | (self.padding << 5); - buffer.put_u8(value); - for elem in &self.x { - buffer.put_uint(*elem as u64, 3); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 + self.x.len() * 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_padding(&self) -> u8 { - self.foo.as_ref().padding - } - pub fn get_x(&self) -> &Vec { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { padding: self.padding, x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_array_dynamic_count_little_endian.rs b/tools/pdl/tests/generated/packet_decl_array_dynamic_count_little_endian.rs deleted file mode 100644 index 40999524292aa0c14702402ba26accbc3fa2a25c..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_array_dynamic_count_little_endian.rs +++ /dev/null @@ -1,176 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - padding: u8, - x: Vec, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub padding: u8, - pub x: Vec, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u8(); - let x_count = (chunk & 0x1f) as usize; - let padding = ((chunk >> 5) & 0x7); - if bytes.get().remaining() < x_count { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: x_count, - got: bytes.get().remaining(), - }); - } - let x = (0..x_count) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_uint_le(3) as u32)) - .collect::>>()?; - Ok(Self { padding, x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.x.len() > 0x1f { - panic!("Invalid length for {}::{}: {} > {}", "Foo", "x", self.x.len(), 0x1f); - } - if self.padding > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "padding", self.padding, 0x7); - } - let value = self.x.len() as u8 | (self.padding << 5); - buffer.put_u8(value); - for elem in &self.x { - buffer.put_uint_le(*elem as u64, 3); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 + self.x.len() * 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_padding(&self) -> u8 { - self.foo.as_ref().padding - } - pub fn get_x(&self) -> &Vec { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { padding: self.padding, x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_array_dynamic_size_big_endian.rs b/tools/pdl/tests/generated/packet_decl_array_dynamic_size_big_endian.rs deleted file mode 100644 index 7148196e291f9d0f5efe33821585e3faf2d92812..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_array_dynamic_size_big_endian.rs +++ /dev/null @@ -1,181 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - padding: u8, - x: Vec, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub padding: u8, - pub x: Vec, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u8(); - let x_size = (chunk & 0x1f) as usize; - let padding = ((chunk >> 5) & 0x7); - if bytes.get().remaining() < x_size { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: x_size, - got: bytes.get().remaining(), - }); - } - if x_size % 3 != 0 { - return Err(Error::InvalidArraySize { array: x_size, element: 3 }); - } - let x_count = x_size / 3; - let mut x = Vec::with_capacity(x_count); - for _ in 0..x_count { - x.push(Ok::<_, Error>(bytes.get_mut().get_uint(3) as u32)?); - } - Ok(Self { padding, x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if (self.x.len() * 3) > 0x1f { - panic!("Invalid length for {}::{}: {} > {}", "Foo", "x", (self.x.len() * 3), 0x1f); - } - if self.padding > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "padding", self.padding, 0x7); - } - let value = (self.x.len() * 3) as u8 | (self.padding << 5); - buffer.put_u8(value); - for elem in &self.x { - buffer.put_uint(*elem as u64, 3); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 + self.x.len() * 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_padding(&self) -> u8 { - self.foo.as_ref().padding - } - pub fn get_x(&self) -> &Vec { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { padding: self.padding, x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_array_dynamic_size_little_endian.rs b/tools/pdl/tests/generated/packet_decl_array_dynamic_size_little_endian.rs deleted file mode 100644 index 6645cf2f411ec4a979007294693d3a6c28f96c98..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_array_dynamic_size_little_endian.rs +++ /dev/null @@ -1,181 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - padding: u8, - x: Vec, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub padding: u8, - pub x: Vec, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u8(); - let x_size = (chunk & 0x1f) as usize; - let padding = ((chunk >> 5) & 0x7); - if bytes.get().remaining() < x_size { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: x_size, - got: bytes.get().remaining(), - }); - } - if x_size % 3 != 0 { - return Err(Error::InvalidArraySize { array: x_size, element: 3 }); - } - let x_count = x_size / 3; - let mut x = Vec::with_capacity(x_count); - for _ in 0..x_count { - x.push(Ok::<_, Error>(bytes.get_mut().get_uint_le(3) as u32)?); - } - Ok(Self { padding, x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if (self.x.len() * 3) > 0x1f { - panic!("Invalid length for {}::{}: {} > {}", "Foo", "x", (self.x.len() * 3), 0x1f); - } - if self.padding > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "padding", self.padding, 0x7); - } - let value = (self.x.len() * 3) as u8 | (self.padding << 5); - buffer.put_u8(value); - for elem in &self.x { - buffer.put_uint_le(*elem as u64, 3); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 + self.x.len() * 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_padding(&self) -> u8 { - self.foo.as_ref().padding - } - pub fn get_x(&self) -> &Vec { - &self.foo.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { padding: self.padding, x: self.x }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs b/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs deleted file mode 100644 index 0d533b5a1a63116f5a813a24f695444a712bbf8f..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs +++ /dev/null @@ -1,220 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - pub a: Vec, -} -impl Foo { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - let a_count = bytes.get_mut().get_uint(5) as usize; - if bytes.get().remaining() < a_count { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: a_count, - got: bytes.get().remaining(), - }); - } - let a = (0..a_count) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16())) - .collect::>>()?; - Ok(Self { a }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a.len() > 0xff_ffff_ffff_usize { - panic!( - "Invalid length for {}::{}: {} > {}", - "Foo", - "a", - self.a.len(), - 0xff_ffff_ffff_usize - ); - } - buffer.put_uint(self.a.len() as u64, 5); - for elem in &self.a { - buffer.put_u16(*elem); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 + self.a.len() * 2 - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Vec, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Vec, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - let x_count = bytes.get_mut().get_uint(5) as usize; - let x = (0..x_count).map(|_| Foo::parse_inner(bytes)).collect::>>()?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.x.len() > 0xff_ffff_ffff_usize { - panic!( - "Invalid length for {}::{}: {} > {}", - "Bar", - "x", - self.x.len(), - 0xff_ffff_ffff_usize - ); - } - buffer.put_uint(self.x.len() as u64, 5); - for elem in &self.x { - elem.write_to(buffer); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 + self.x.iter().map(|elem| elem.get_size()).sum::() - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &Vec { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs b/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs deleted file mode 100644 index 8a33453edff0d20162db12aca9fd799cdfb91e07..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs +++ /dev/null @@ -1,220 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - pub a: Vec, -} -impl Foo { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - let a_count = bytes.get_mut().get_uint_le(5) as usize; - if bytes.get().remaining() < a_count { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: a_count, - got: bytes.get().remaining(), - }); - } - let a = (0..a_count) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16_le())) - .collect::>>()?; - Ok(Self { a }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a.len() > 0xff_ffff_ffff_usize { - panic!( - "Invalid length for {}::{}: {} > {}", - "Foo", - "a", - self.a.len(), - 0xff_ffff_ffff_usize - ); - } - buffer.put_uint_le(self.a.len() as u64, 5); - for elem in &self.a { - buffer.put_u16_le(*elem); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 + self.a.len() * 2 - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Vec, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Vec, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - let x_count = bytes.get_mut().get_uint_le(5) as usize; - let x = (0..x_count).map(|_| Foo::parse_inner(bytes)).collect::>>()?; - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.x.len() > 0xff_ffff_ffff_usize { - panic!( - "Invalid length for {}::{}: {} > {}", - "Bar", - "x", - self.x.len(), - 0xff_ffff_ffff_usize - ); - } - buffer.put_uint_le(self.x.len() as u64, 5); - for elem in &self.x { - elem.write_to(buffer); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 + self.x.iter().map(|elem| elem.get_size()).sum::() - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &Vec { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs b/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs deleted file mode 100644 index b85578ff14f2403d9e276bf1b106e0aed47bfb57..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs +++ /dev/null @@ -1,228 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - pub a: Vec, -} -impl Foo { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - let a_count = bytes.get_mut().get_uint(5) as usize; - if bytes.get().remaining() < a_count { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: a_count, - got: bytes.get().remaining(), - }); - } - let a = (0..a_count) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16())) - .collect::>>()?; - Ok(Self { a }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a.len() > 0xff_ffff_ffff_usize { - panic!( - "Invalid length for {}::{}: {} > {}", - "Foo", - "a", - self.a.len(), - 0xff_ffff_ffff_usize - ); - } - buffer.put_uint(self.a.len() as u64, 5); - for elem in &self.a { - buffer.put_u16(*elem); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 + self.a.len() * 2 - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Vec, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Vec, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - let x_size = bytes.get_mut().get_uint(5) as usize; - if bytes.get().remaining() < x_size { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: x_size, - got: bytes.get().remaining(), - }); - } - let (head, tail) = bytes.get().split_at(x_size); - let mut head = &mut Cell::new(head); - bytes.replace(tail); - let mut x = Vec::new(); - while !head.get().is_empty() { - x.push(Foo::parse_inner(head)?); - } - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - let x_size = self.x.iter().map(|elem| elem.get_size()).sum::(); - if x_size > 0xff_ffff_ffff_usize { - panic!("Invalid length for {}::{}: {} > {}", "Bar", "x", x_size, 0xff_ffff_ffff_usize); - } - buffer.put_uint(x_size as u64, 5); - for elem in &self.x { - elem.write_to(buffer); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 + self.x.iter().map(|elem| elem.get_size()).sum::() - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &Vec { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs b/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs deleted file mode 100644 index dff0ab107d8970290d969c97e6d6a23fb41c7ef2..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs +++ /dev/null @@ -1,228 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - pub a: Vec, -} -impl Foo { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - let a_count = bytes.get_mut().get_uint_le(5) as usize; - if bytes.get().remaining() < a_count { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: a_count, - got: bytes.get().remaining(), - }); - } - let a = (0..a_count) - .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16_le())) - .collect::>>()?; - Ok(Self { a }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a.len() > 0xff_ffff_ffff_usize { - panic!( - "Invalid length for {}::{}: {} > {}", - "Foo", - "a", - self.a.len(), - 0xff_ffff_ffff_usize - ); - } - buffer.put_uint_le(self.a.len() as u64, 5); - for elem in &self.a { - buffer.put_u16_le(*elem); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 + self.a.len() * 2 - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: Vec, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub x: Vec, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - let x_size = bytes.get_mut().get_uint_le(5) as usize; - if bytes.get().remaining() < x_size { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: x_size, - got: bytes.get().remaining(), - }); - } - let (head, tail) = bytes.get().split_at(x_size); - let mut head = &mut Cell::new(head); - bytes.replace(tail); - let mut x = Vec::new(); - while !head.get().is_empty() { - x.push(Foo::parse_inner(head)?); - } - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - let x_size = self.x.iter().map(|elem| elem.get_size()).sum::(); - if x_size > 0xff_ffff_ffff_usize { - panic!("Invalid length for {}::{}: {} > {}", "Bar", "x", x_size, 0xff_ffff_ffff_usize); - } - buffer.put_uint_le(x_size as u64, 5); - for elem in &self.x { - elem.write_to(buffer); - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 + self.x.iter().map(|elem| elem.get_size()).sum::() - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.bar.get_size()); - self.bar.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = BarData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(bar: Arc) -> Result { - Ok(Self { bar }) - } - pub fn get_x(&self) -> &Vec { - &self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.bar.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - Bar::new(bar).unwrap() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_child_packets_big_endian.rs b/tools/pdl/tests/generated/packet_decl_child_packets_big_endian.rs deleted file mode 100644 index 3940cc0f3fbadf1d989f43e43ec1b500fe2bcff6..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_child_packets_big_endian.rs +++ /dev/null @@ -1,584 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))] -pub enum Enum16 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum16 { - type Error = u16; - fn try_from(value: u16) -> std::result::Result { - match value { - 0x1 => Ok(Enum16::A), - 0x2 => Ok(Enum16::B), - _ => Err(value), - } - } -} -impl From<&Enum16> for u16 { - fn from(value: &Enum16) -> Self { - match value { - Enum16::A => 0x1, - Enum16::B => 0x2, - } - } -} -impl From for u16 { - fn from(value: Enum16) -> Self { - (&value).into() - } -} -impl From for i32 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooDataChild { - Bar(Arc), - Baz(Arc), - Payload(Bytes), - None, -} -impl FooDataChild { - fn get_total_size(&self) -> usize { - match self { - FooDataChild::Bar(value) => value.get_total_size(), - FooDataChild::Baz(value) => value.get_total_size(), - FooDataChild::Payload(bytes) => bytes.len(), - FooDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooChild { - Bar(Bar), - Baz(Baz), - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u8, - b: Enum16, - child: FooDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u8, - pub b: Enum16, - pub payload: Option, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 4 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let a = bytes.get_mut().get_u8(); - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let b = Enum16::try_from(bytes.get_mut().get_u16()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Foo".to_string(), - field: "b".to_string(), - value: bytes.get_mut().get_u16() as u64, - type_: "Enum16".to_string(), - } - })?; - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let payload_size = bytes.get_mut().get_u8() as usize; - if bytes.get().remaining() < payload_size { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: payload_size, - got: bytes.get().remaining(), - }); - } - let payload = &bytes.get()[..payload_size]; - bytes.get_mut().advance(payload_size); - let child = match (a, b) { - (100, _) if BarData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = BarData::parse_inner(&mut cell)?; - FooDataChild::Bar(Arc::new(child_data)) - } - (_, Enum16::B) if BazData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = BazData::parse_inner(&mut cell)?; - FooDataChild::Baz(Arc::new(child_data)) - } - _ if !payload.is_empty() => FooDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => FooDataChild::None, - }; - Ok(Self { a, b, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.a); - buffer.put_u16(u16::from(self.b)); - if self.child.get_total_size() > 0xff { - panic!( - "Invalid length for {}::{}: {} > {}", - "Foo", - "_payload_", - self.child.get_total_size(), - 0xff - ); - } - buffer.put_u8(self.child.get_total_size() as u8); - match &self.child { - FooDataChild::Bar(child) => child.write_to(buffer), - FooDataChild::Baz(child) => child.write_to(buffer), - FooDataChild::Payload(payload) => buffer.put_slice(payload), - FooDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 4 + self.child.get_total_size() - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> FooChild { - match &self.foo.child { - FooDataChild::Bar(_) => FooChild::Bar(Bar::new(self.foo.clone()).unwrap()), - FooDataChild::Baz(_) => FooChild::Baz(Baz::new(self.foo.clone()).unwrap()), - FooDataChild::Payload(payload) => FooChild::Payload(payload.clone()), - FooDataChild::None => FooChild::None, - } - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> Enum16 { - self.foo.as_ref().b - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { - a: self.a, - b: self.b, - child: match self.payload { - None => FooDataChild::None, - Some(bytes) => FooDataChild::Payload(bytes), - }, - }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub b: Enum16, - pub x: u8, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_u8(); - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.x); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl From for Foo { - fn from(packet: Bar) -> Foo { - Foo::new(packet.foo).unwrap() - } -} -impl TryFrom for Bar { - type Error = Error; - fn try_from(packet: Foo) -> Result { - Bar::new(packet.foo) - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - let bar = match &foo.child { - FooDataChild::Bar(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(FooDataChild::Bar), - actual: format!("{:?}", &foo.child), - }) - } - }; - Ok(Self { foo, bar }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> Enum16 { - self.foo.as_ref().b - } - pub fn get_x(&self) -> u8 { - self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - let foo = Arc::new(FooData { a: 100, b: self.b, child: FooDataChild::Bar(bar) }); - Bar::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: BarBuilder) -> Foo { - builder.build().into() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BazData { - y: u16, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Baz { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - baz: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BazBuilder { - pub a: u8, - pub y: u16, -} -impl BazData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 2 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Baz".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let y = bytes.get_mut().get_u16(); - Ok(Self { y }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u16(self.y); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 2 - } -} -impl Packet for Baz { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Baz) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Baz) -> Self { - packet.to_vec() - } -} -impl From for Foo { - fn from(packet: Baz) -> Foo { - Foo::new(packet.foo).unwrap() - } -} -impl TryFrom for Baz { - type Error = Error; - fn try_from(packet: Foo) -> Result { - Baz::new(packet.foo) - } -} -impl Baz { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - let baz = match &foo.child { - FooDataChild::Baz(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(FooDataChild::Baz), - actual: format!("{:?}", &foo.child), - }) - } - }; - Ok(Self { foo, baz }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> Enum16 { - self.foo.as_ref().b - } - pub fn get_y(&self) -> u16 { - self.baz.as_ref().y - } - fn write_to(&self, buffer: &mut BytesMut) { - self.baz.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl BazBuilder { - pub fn build(self) -> Baz { - let baz = Arc::new(BazData { y: self.y }); - let foo = Arc::new(FooData { a: self.a, b: Enum16::B, child: FooDataChild::Baz(baz) }); - Baz::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: BazBuilder) -> Foo { - builder.build().into() - } -} -impl From for Baz { - fn from(builder: BazBuilder) -> Baz { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_child_packets_little_endian.rs b/tools/pdl/tests/generated/packet_decl_child_packets_little_endian.rs deleted file mode 100644 index ca17b244db9a5fb533ab61df7ad74f6f32596c5a..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_child_packets_little_endian.rs +++ /dev/null @@ -1,584 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))] -pub enum Enum16 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum16 { - type Error = u16; - fn try_from(value: u16) -> std::result::Result { - match value { - 0x1 => Ok(Enum16::A), - 0x2 => Ok(Enum16::B), - _ => Err(value), - } - } -} -impl From<&Enum16> for u16 { - fn from(value: &Enum16) -> Self { - match value { - Enum16::A => 0x1, - Enum16::B => 0x2, - } - } -} -impl From for u16 { - fn from(value: Enum16) -> Self { - (&value).into() - } -} -impl From for i32 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooDataChild { - Bar(Arc), - Baz(Arc), - Payload(Bytes), - None, -} -impl FooDataChild { - fn get_total_size(&self) -> usize { - match self { - FooDataChild::Bar(value) => value.get_total_size(), - FooDataChild::Baz(value) => value.get_total_size(), - FooDataChild::Payload(bytes) => bytes.len(), - FooDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooChild { - Bar(Bar), - Baz(Baz), - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u8, - b: Enum16, - child: FooDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u8, - pub b: Enum16, - pub payload: Option, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 4 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let a = bytes.get_mut().get_u8(); - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let b = Enum16::try_from(bytes.get_mut().get_u16_le()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Foo".to_string(), - field: "b".to_string(), - value: bytes.get_mut().get_u16_le() as u64, - type_: "Enum16".to_string(), - } - })?; - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let payload_size = bytes.get_mut().get_u8() as usize; - if bytes.get().remaining() < payload_size { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: payload_size, - got: bytes.get().remaining(), - }); - } - let payload = &bytes.get()[..payload_size]; - bytes.get_mut().advance(payload_size); - let child = match (a, b) { - (100, _) if BarData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = BarData::parse_inner(&mut cell)?; - FooDataChild::Bar(Arc::new(child_data)) - } - (_, Enum16::B) if BazData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = BazData::parse_inner(&mut cell)?; - FooDataChild::Baz(Arc::new(child_data)) - } - _ if !payload.is_empty() => FooDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => FooDataChild::None, - }; - Ok(Self { a, b, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.a); - buffer.put_u16_le(u16::from(self.b)); - if self.child.get_total_size() > 0xff { - panic!( - "Invalid length for {}::{}: {} > {}", - "Foo", - "_payload_", - self.child.get_total_size(), - 0xff - ); - } - buffer.put_u8(self.child.get_total_size() as u8); - match &self.child { - FooDataChild::Bar(child) => child.write_to(buffer), - FooDataChild::Baz(child) => child.write_to(buffer), - FooDataChild::Payload(payload) => buffer.put_slice(payload), - FooDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 4 + self.child.get_total_size() - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> FooChild { - match &self.foo.child { - FooDataChild::Bar(_) => FooChild::Bar(Bar::new(self.foo.clone()).unwrap()), - FooDataChild::Baz(_) => FooChild::Baz(Baz::new(self.foo.clone()).unwrap()), - FooDataChild::Payload(payload) => FooChild::Payload(payload.clone()), - FooDataChild::None => FooChild::None, - } - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> Enum16 { - self.foo.as_ref().b - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { - a: self.a, - b: self.b, - child: match self.payload { - None => FooDataChild::None, - Some(bytes) => FooDataChild::Payload(bytes), - }, - }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarData { - x: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Bar { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - bar: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BarBuilder { - pub b: Enum16, - pub x: u8, -} -impl BarData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Bar".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_u8(); - Ok(Self { x }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.x); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 - } -} -impl Packet for Bar { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Bar) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Bar) -> Self { - packet.to_vec() - } -} -impl From for Foo { - fn from(packet: Bar) -> Foo { - Foo::new(packet.foo).unwrap() - } -} -impl TryFrom for Bar { - type Error = Error; - fn try_from(packet: Foo) -> Result { - Bar::new(packet.foo) - } -} -impl Bar { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - let bar = match &foo.child { - FooDataChild::Bar(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(FooDataChild::Bar), - actual: format!("{:?}", &foo.child), - }) - } - }; - Ok(Self { foo, bar }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> Enum16 { - self.foo.as_ref().b - } - pub fn get_x(&self) -> u8 { - self.bar.as_ref().x - } - fn write_to(&self, buffer: &mut BytesMut) { - self.bar.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl BarBuilder { - pub fn build(self) -> Bar { - let bar = Arc::new(BarData { x: self.x }); - let foo = Arc::new(FooData { a: 100, b: self.b, child: FooDataChild::Bar(bar) }); - Bar::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: BarBuilder) -> Foo { - builder.build().into() - } -} -impl From for Bar { - fn from(builder: BarBuilder) -> Bar { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BazData { - y: u16, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Baz { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - baz: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BazBuilder { - pub a: u8, - pub y: u16, -} -impl BazData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 2 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Baz".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let y = bytes.get_mut().get_u16_le(); - Ok(Self { y }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u16_le(self.y); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 2 - } -} -impl Packet for Baz { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Baz) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Baz) -> Self { - packet.to_vec() - } -} -impl From for Foo { - fn from(packet: Baz) -> Foo { - Foo::new(packet.foo).unwrap() - } -} -impl TryFrom for Baz { - type Error = Error; - fn try_from(packet: Foo) -> Result { - Baz::new(packet.foo) - } -} -impl Baz { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - let baz = match &foo.child { - FooDataChild::Baz(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(FooDataChild::Baz), - actual: format!("{:?}", &foo.child), - }) - } - }; - Ok(Self { foo, baz }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> Enum16 { - self.foo.as_ref().b - } - pub fn get_y(&self) -> u16 { - self.baz.as_ref().y - } - fn write_to(&self, buffer: &mut BytesMut) { - self.baz.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl BazBuilder { - pub fn build(self) -> Baz { - let baz = Arc::new(BazData { y: self.y }); - let foo = Arc::new(FooData { a: self.a, b: Enum16::B, child: FooDataChild::Baz(baz) }); - Baz::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: BazBuilder) -> Foo { - builder.build().into() - } -} -impl From for Baz { - fn from(builder: BazBuilder) -> Baz { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_complex_scalars_big_endian.rs b/tools/pdl/tests/generated/packet_decl_complex_scalars_big_endian.rs deleted file mode 100644 index 7eeb9b7df6e2135d16cbe2690c563ea2217e875c..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_complex_scalars_big_endian.rs +++ /dev/null @@ -1,215 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u8, - b: u8, - c: u8, - d: u32, - e: u16, - f: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u8, - pub b: u8, - pub c: u8, - pub d: u32, - pub e: u16, - pub f: u8, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 7 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u16(); - let a = (chunk & 0x7) as u8; - let b = (chunk >> 3) as u8; - let c = ((chunk >> 11) & 0x1f) as u8; - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let d = bytes.get_mut().get_uint(3) as u32; - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u16(); - let e = (chunk & 0xfff); - let f = ((chunk >> 12) & 0xf) as u8; - Ok(Self { a, b, c, d, e, f }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x7); - } - if self.c > 0x1f { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x1f); - } - let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11); - buffer.put_u16(value); - if self.d > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "d", self.d, 0xff_ffff); - } - buffer.put_uint(self.d as u64, 3); - if self.e > 0xfff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "e", self.e, 0xfff); - } - if self.f > 0xf { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "f", self.f, 0xf); - } - let value = self.e | ((self.f as u16) << 12); - buffer.put_u16(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 7 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> u8 { - self.foo.as_ref().b - } - pub fn get_c(&self) -> u8 { - self.foo.as_ref().c - } - pub fn get_d(&self) -> u32 { - self.foo.as_ref().d - } - pub fn get_e(&self) -> u16 { - self.foo.as_ref().e - } - pub fn get_f(&self) -> u8 { - self.foo.as_ref().f - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = - Arc::new(FooData { a: self.a, b: self.b, c: self.c, d: self.d, e: self.e, f: self.f }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_complex_scalars_little_endian.rs b/tools/pdl/tests/generated/packet_decl_complex_scalars_little_endian.rs deleted file mode 100644 index dd684e60a1860c5d020f2c4e1edd14ef730ac913..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_complex_scalars_little_endian.rs +++ /dev/null @@ -1,215 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u8, - b: u8, - c: u8, - d: u32, - e: u16, - f: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u8, - pub b: u8, - pub c: u8, - pub d: u32, - pub e: u16, - pub f: u8, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 7 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u16_le(); - let a = (chunk & 0x7) as u8; - let b = (chunk >> 3) as u8; - let c = ((chunk >> 11) & 0x1f) as u8; - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let d = bytes.get_mut().get_uint_le(3) as u32; - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u16_le(); - let e = (chunk & 0xfff); - let f = ((chunk >> 12) & 0xf) as u8; - Ok(Self { a, b, c, d, e, f }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x7); - } - if self.c > 0x1f { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x1f); - } - let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11); - buffer.put_u16_le(value); - if self.d > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "d", self.d, 0xff_ffff); - } - buffer.put_uint_le(self.d as u64, 3); - if self.e > 0xfff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "e", self.e, 0xfff); - } - if self.f > 0xf { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "f", self.f, 0xf); - } - let value = self.e | ((self.f as u16) << 12); - buffer.put_u16_le(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 7 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> u8 { - self.foo.as_ref().b - } - pub fn get_c(&self) -> u8 { - self.foo.as_ref().c - } - pub fn get_d(&self) -> u32 { - self.foo.as_ref().d - } - pub fn get_e(&self) -> u16 { - self.foo.as_ref().e - } - pub fn get_f(&self) -> u8 { - self.foo.as_ref().f - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = - Arc::new(FooData { a: self.a, b: self.b, c: self.c, d: self.d, e: self.e, f: self.f }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_empty_big_endian.rs b/tools/pdl/tests/generated/packet_decl_empty_big_endian.rs deleted file mode 100644 index cecac9589becc58466ab2b6423bf9f7467f0558a..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_empty_big_endian.rs +++ /dev/null @@ -1,132 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData {} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder {} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - true - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - Ok(Self {}) - } - fn write_to(&self, buffer: &mut BytesMut) {} - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 0 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData {}); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_empty_little_endian.rs b/tools/pdl/tests/generated/packet_decl_empty_little_endian.rs deleted file mode 100644 index cecac9589becc58466ab2b6423bf9f7467f0558a..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_empty_little_endian.rs +++ /dev/null @@ -1,132 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData {} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder {} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - true - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - Ok(Self {}) - } - fn write_to(&self, buffer: &mut BytesMut) {} - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 0 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData {}); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_fixed_enum_field_big_endian.rs b/tools/pdl/tests/generated/packet_decl_fixed_enum_field_big_endian.rs deleted file mode 100644 index 5736028b3dab2411d5d920c2e3d68636931028fd..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_fixed_enum_field_big_endian.rs +++ /dev/null @@ -1,230 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum Enum7 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum7 { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x1 => Ok(Enum7::A), - 0x2 => Ok(Enum7::B), - _ => Err(value), - } - } -} -impl From<&Enum7> for u8 { - fn from(value: &Enum7) -> Self { - match value { - Enum7::A => 0x1, - Enum7::B => 0x2, - } - } -} -impl From for u8 { - fn from(value: Enum7) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - b: u64, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub b: u64, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 8 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 8 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 8, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u64(); - if (chunk & 0x7f) as u8 != u8::from(Enum7::A) { - return Err(Error::InvalidFixedValue { - expected: u8::from(Enum7::A) as u64, - actual: (chunk & 0x7f) as u8 as u64, - }); - } - let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64); - Ok(Self { b }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.b > 0x1ff_ffff_ffff_ffff_u64 { - panic!( - "Invalid value for {}::{}: {} > {}", - "Foo", "b", self.b, 0x1ff_ffff_ffff_ffff_u64 - ); - } - let value = (u8::from(Enum7::A) as u64) | (self.b << 7); - buffer.put_u64(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 8 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_b(&self) -> u64 { - self.foo.as_ref().b - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { b: self.b }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_fixed_enum_field_little_endian.rs b/tools/pdl/tests/generated/packet_decl_fixed_enum_field_little_endian.rs deleted file mode 100644 index ec39ae01990e21223ba5e5f31c9070789efe029f..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_fixed_enum_field_little_endian.rs +++ /dev/null @@ -1,230 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum Enum7 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum7 { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x1 => Ok(Enum7::A), - 0x2 => Ok(Enum7::B), - _ => Err(value), - } - } -} -impl From<&Enum7> for u8 { - fn from(value: &Enum7) -> Self { - match value { - Enum7::A => 0x1, - Enum7::B => 0x2, - } - } -} -impl From for u8 { - fn from(value: Enum7) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - b: u64, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub b: u64, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 8 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 8 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 8, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u64_le(); - if (chunk & 0x7f) as u8 != u8::from(Enum7::A) { - return Err(Error::InvalidFixedValue { - expected: u8::from(Enum7::A) as u64, - actual: (chunk & 0x7f) as u8 as u64, - }); - } - let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64); - Ok(Self { b }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.b > 0x1ff_ffff_ffff_ffff_u64 { - panic!( - "Invalid value for {}::{}: {} > {}", - "Foo", "b", self.b, 0x1ff_ffff_ffff_ffff_u64 - ); - } - let value = (u8::from(Enum7::A) as u64) | (self.b << 7); - buffer.put_u64_le(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 8 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_b(&self) -> u64 { - self.foo.as_ref().b - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { b: self.b }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs b/tools/pdl/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs deleted file mode 100644 index 8623d8b4b2542c2ca5a7df1593e2b5a08c37401b..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs +++ /dev/null @@ -1,163 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - b: u64, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub b: u64, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 8 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 8 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 8, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u64(); - if (chunk & 0x7f) as u8 != 7 { - return Err(Error::InvalidFixedValue { - expected: 7, - actual: (chunk & 0x7f) as u8 as u64, - }); - } - let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64); - Ok(Self { b }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.b > 0x1ff_ffff_ffff_ffff_u64 { - panic!( - "Invalid value for {}::{}: {} > {}", - "Foo", "b", self.b, 0x1ff_ffff_ffff_ffff_u64 - ); - } - let value = (7 as u64) | (self.b << 7); - buffer.put_u64(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 8 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_b(&self) -> u64 { - self.foo.as_ref().b - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { b: self.b }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs b/tools/pdl/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs deleted file mode 100644 index 42d4a8f3ffed4904afe0cd39f0931204c53b66d6..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs +++ /dev/null @@ -1,163 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - b: u64, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub b: u64, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 8 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 8 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 8, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u64_le(); - if (chunk & 0x7f) as u8 != 7 { - return Err(Error::InvalidFixedValue { - expected: 7, - actual: (chunk & 0x7f) as u8 as u64, - }); - } - let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64); - Ok(Self { b }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.b > 0x1ff_ffff_ffff_ffff_u64 { - panic!( - "Invalid value for {}::{}: {} > {}", - "Foo", "b", self.b, 0x1ff_ffff_ffff_ffff_u64 - ); - } - let value = (7 as u64) | (self.b << 7); - buffer.put_u64_le(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 8 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_b(&self) -> u64 { - self.foo.as_ref().b - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { b: self.b }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_grand_children_big_endian.rs b/tools/pdl/tests/generated/packet_decl_grand_children_big_endian.rs deleted file mode 100644 index 96bca77d887c98641a3d7311cd734f53859b2ad4..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_grand_children_big_endian.rs +++ /dev/null @@ -1,986 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))] -pub enum Enum16 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum16 { - type Error = u16; - fn try_from(value: u16) -> std::result::Result { - match value { - 0x1 => Ok(Enum16::A), - 0x2 => Ok(Enum16::B), - _ => Err(value), - } - } -} -impl From<&Enum16> for u16 { - fn from(value: &Enum16) -> Self { - match value { - Enum16::A => 0x1, - Enum16::B => 0x2, - } - } -} -impl From for u16 { - fn from(value: Enum16) -> Self { - (&value).into() - } -} -impl From for i32 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ParentDataChild { - Child(Arc), - Payload(Bytes), - None, -} -impl ParentDataChild { - fn get_total_size(&self) -> usize { - match self { - ParentDataChild::Child(value) => value.get_total_size(), - ParentDataChild::Payload(bytes) => bytes.len(), - ParentDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ParentChild { - Child(Child), - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ParentData { - foo: Enum16, - bar: Enum16, - baz: Enum16, - child: ParentDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Parent { - #[cfg_attr(feature = "serde", serde(flatten))] - parent: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ParentBuilder { - pub bar: Enum16, - pub baz: Enum16, - pub foo: Enum16, - pub payload: Option, -} -impl ParentData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 7 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let foo = Enum16::try_from(bytes.get_mut().get_u16()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Parent".to_string(), - field: "foo".to_string(), - value: bytes.get_mut().get_u16() as u64, - type_: "Enum16".to_string(), - } - })?; - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let bar = Enum16::try_from(bytes.get_mut().get_u16()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Parent".to_string(), - field: "bar".to_string(), - value: bytes.get_mut().get_u16() as u64, - type_: "Enum16".to_string(), - } - })?; - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let baz = Enum16::try_from(bytes.get_mut().get_u16()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Parent".to_string(), - field: "baz".to_string(), - value: bytes.get_mut().get_u16() as u64, - type_: "Enum16".to_string(), - } - })?; - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let payload_size = bytes.get_mut().get_u8() as usize; - if bytes.get().remaining() < payload_size { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: payload_size, - got: bytes.get().remaining(), - }); - } - let payload = &bytes.get()[..payload_size]; - bytes.get_mut().advance(payload_size); - let child = match (foo) { - (Enum16::A) if ChildData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = ChildData::parse_inner(&mut cell, bar, baz)?; - ParentDataChild::Child(Arc::new(child_data)) - } - _ if !payload.is_empty() => ParentDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => ParentDataChild::None, - }; - Ok(Self { foo, bar, baz, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u16(u16::from(self.foo)); - buffer.put_u16(u16::from(self.bar)); - buffer.put_u16(u16::from(self.baz)); - if self.child.get_total_size() > 0xff { - panic!( - "Invalid length for {}::{}: {} > {}", - "Parent", - "_payload_", - self.child.get_total_size(), - 0xff - ); - } - buffer.put_u8(self.child.get_total_size() as u8); - match &self.child { - ParentDataChild::Child(child) => child.write_to(buffer), - ParentDataChild::Payload(payload) => buffer.put_slice(payload), - ParentDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 7 + self.child.get_total_size() - } -} -impl Packet for Parent { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.parent.get_size()); - self.parent.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Parent) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Parent) -> Self { - packet.to_vec() - } -} -impl Parent { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = ParentData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> ParentChild { - match &self.parent.child { - ParentDataChild::Child(_) => { - ParentChild::Child(Child::new(self.parent.clone()).unwrap()) - } - ParentDataChild::Payload(payload) => ParentChild::Payload(payload.clone()), - ParentDataChild::None => ParentChild::None, - } - } - fn new(parent: Arc) -> Result { - Ok(Self { parent }) - } - pub fn get_bar(&self) -> Enum16 { - self.parent.as_ref().bar - } - pub fn get_baz(&self) -> Enum16 { - self.parent.as_ref().baz - } - pub fn get_foo(&self) -> Enum16 { - self.parent.as_ref().foo - } - fn write_to(&self, buffer: &mut BytesMut) { - self.parent.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.parent.get_size() - } -} -impl ParentBuilder { - pub fn build(self) -> Parent { - let parent = Arc::new(ParentData { - bar: self.bar, - baz: self.baz, - foo: self.foo, - child: match self.payload { - None => ParentDataChild::None, - Some(bytes) => ParentDataChild::Payload(bytes), - }, - }); - Parent::new(parent).unwrap() - } -} -impl From for Parent { - fn from(builder: ParentBuilder) -> Parent { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ChildDataChild { - GrandChild(Arc), - Payload(Bytes), - None, -} -impl ChildDataChild { - fn get_total_size(&self) -> usize { - match self { - ChildDataChild::GrandChild(value) => value.get_total_size(), - ChildDataChild::Payload(bytes) => bytes.len(), - ChildDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ChildChild { - GrandChild(GrandChild), - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ChildData { - quux: Enum16, - child: ChildDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Child { - #[cfg_attr(feature = "serde", serde(flatten))] - parent: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - child: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ChildBuilder { - pub bar: Enum16, - pub baz: Enum16, - pub quux: Enum16, - pub payload: Option, -} -impl ChildData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 2 - } - fn parse(bytes: &[u8], bar: Enum16, baz: Enum16) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell, bar, baz)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>, bar: Enum16, baz: Enum16) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Child".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let quux = Enum16::try_from(bytes.get_mut().get_u16()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Child".to_string(), - field: "quux".to_string(), - value: bytes.get_mut().get_u16() as u64, - type_: "Enum16".to_string(), - } - })?; - let payload = bytes.get(); - bytes.get_mut().advance(payload.len()); - let child = match (bar, quux) { - (Enum16::A, Enum16::A) if GrandChildData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = GrandChildData::parse_inner(&mut cell, baz)?; - ChildDataChild::GrandChild(Arc::new(child_data)) - } - _ if !payload.is_empty() => ChildDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => ChildDataChild::None, - }; - Ok(Self { quux, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u16(u16::from(self.quux)); - match &self.child { - ChildDataChild::GrandChild(child) => child.write_to(buffer), - ChildDataChild::Payload(payload) => buffer.put_slice(payload), - ChildDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 2 + self.child.get_total_size() - } -} -impl Packet for Child { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.parent.get_size()); - self.parent.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Child) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Child) -> Self { - packet.to_vec() - } -} -impl From for Parent { - fn from(packet: Child) -> Parent { - Parent::new(packet.parent).unwrap() - } -} -impl TryFrom for Child { - type Error = Error; - fn try_from(packet: Parent) -> Result { - Child::new(packet.parent) - } -} -impl Child { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = ParentData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> ChildChild { - match &self.child.child { - ChildDataChild::GrandChild(_) => { - ChildChild::GrandChild(GrandChild::new(self.parent.clone()).unwrap()) - } - ChildDataChild::Payload(payload) => ChildChild::Payload(payload.clone()), - ChildDataChild::None => ChildChild::None, - } - } - fn new(parent: Arc) -> Result { - let child = match &parent.child { - ParentDataChild::Child(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ParentDataChild::Child), - actual: format!("{:?}", &parent.child), - }) - } - }; - Ok(Self { parent, child }) - } - pub fn get_bar(&self) -> Enum16 { - self.parent.as_ref().bar - } - pub fn get_baz(&self) -> Enum16 { - self.parent.as_ref().baz - } - pub fn get_foo(&self) -> Enum16 { - self.parent.as_ref().foo - } - pub fn get_quux(&self) -> Enum16 { - self.child.as_ref().quux - } - fn write_to(&self, buffer: &mut BytesMut) { - self.child.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.parent.get_size() - } -} -impl ChildBuilder { - pub fn build(self) -> Child { - let child = Arc::new(ChildData { - quux: self.quux, - child: match self.payload { - None => ChildDataChild::None, - Some(bytes) => ChildDataChild::Payload(bytes), - }, - }); - let parent = Arc::new(ParentData { - bar: self.bar, - baz: self.baz, - foo: Enum16::A, - child: ParentDataChild::Child(child), - }); - Child::new(parent).unwrap() - } -} -impl From for Parent { - fn from(builder: ChildBuilder) -> Parent { - builder.build().into() - } -} -impl From for Child { - fn from(builder: ChildBuilder) -> Child { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum GrandChildDataChild { - GrandGrandChild(Arc), - Payload(Bytes), - None, -} -impl GrandChildDataChild { - fn get_total_size(&self) -> usize { - match self { - GrandChildDataChild::GrandGrandChild(value) => value.get_total_size(), - GrandChildDataChild::Payload(bytes) => bytes.len(), - GrandChildDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum GrandChildChild { - GrandGrandChild(GrandGrandChild), - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandChildData { - child: GrandChildDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandChild { - #[cfg_attr(feature = "serde", serde(flatten))] - parent: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - child: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - grandchild: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandChildBuilder { - pub baz: Enum16, - pub payload: Option, -} -impl GrandChildData { - fn conforms(bytes: &[u8]) -> bool { - true - } - fn parse(bytes: &[u8], baz: Enum16) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell, baz)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>, baz: Enum16) -> Result { - let payload = bytes.get(); - bytes.get_mut().advance(payload.len()); - let child = match (baz) { - (Enum16::A) if GrandGrandChildData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = GrandGrandChildData::parse_inner(&mut cell)?; - GrandChildDataChild::GrandGrandChild(Arc::new(child_data)) - } - _ if !payload.is_empty() => { - GrandChildDataChild::Payload(Bytes::copy_from_slice(payload)) - } - _ => GrandChildDataChild::None, - }; - Ok(Self { child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - match &self.child { - GrandChildDataChild::GrandGrandChild(child) => child.write_to(buffer), - GrandChildDataChild::Payload(payload) => buffer.put_slice(payload), - GrandChildDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - self.child.get_total_size() - } -} -impl Packet for GrandChild { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.parent.get_size()); - self.parent.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: GrandChild) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: GrandChild) -> Self { - packet.to_vec() - } -} -impl From for Parent { - fn from(packet: GrandChild) -> Parent { - Parent::new(packet.parent).unwrap() - } -} -impl From for Child { - fn from(packet: GrandChild) -> Child { - Child::new(packet.parent).unwrap() - } -} -impl TryFrom for GrandChild { - type Error = Error; - fn try_from(packet: Parent) -> Result { - GrandChild::new(packet.parent) - } -} -impl GrandChild { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = ParentData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> GrandChildChild { - match &self.grandchild.child { - GrandChildDataChild::GrandGrandChild(_) => { - GrandChildChild::GrandGrandChild(GrandGrandChild::new(self.parent.clone()).unwrap()) - } - GrandChildDataChild::Payload(payload) => GrandChildChild::Payload(payload.clone()), - GrandChildDataChild::None => GrandChildChild::None, - } - } - fn new(parent: Arc) -> Result { - let child = match &parent.child { - ParentDataChild::Child(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ParentDataChild::Child), - actual: format!("{:?}", &parent.child), - }) - } - }; - let grandchild = match &child.child { - ChildDataChild::GrandChild(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ChildDataChild::GrandChild), - actual: format!("{:?}", &child.child), - }) - } - }; - Ok(Self { parent, child, grandchild }) - } - pub fn get_bar(&self) -> Enum16 { - self.parent.as_ref().bar - } - pub fn get_baz(&self) -> Enum16 { - self.parent.as_ref().baz - } - pub fn get_foo(&self) -> Enum16 { - self.parent.as_ref().foo - } - pub fn get_quux(&self) -> Enum16 { - self.child.as_ref().quux - } - fn write_to(&self, buffer: &mut BytesMut) { - self.grandchild.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.parent.get_size() - } -} -impl GrandChildBuilder { - pub fn build(self) -> GrandChild { - let grandchild = Arc::new(GrandChildData { - child: match self.payload { - None => GrandChildDataChild::None, - Some(bytes) => GrandChildDataChild::Payload(bytes), - }, - }); - let child = - Arc::new(ChildData { quux: Enum16::A, child: ChildDataChild::GrandChild(grandchild) }); - let parent = Arc::new(ParentData { - bar: Enum16::A, - baz: self.baz, - foo: Enum16::A, - child: ParentDataChild::Child(child), - }); - GrandChild::new(parent).unwrap() - } -} -impl From for Parent { - fn from(builder: GrandChildBuilder) -> Parent { - builder.build().into() - } -} -impl From for Child { - fn from(builder: GrandChildBuilder) -> Child { - builder.build().into() - } -} -impl From for GrandChild { - fn from(builder: GrandChildBuilder) -> GrandChild { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum GrandGrandChildDataChild { - Payload(Bytes), - None, -} -impl GrandGrandChildDataChild { - fn get_total_size(&self) -> usize { - match self { - GrandGrandChildDataChild::Payload(bytes) => bytes.len(), - GrandGrandChildDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum GrandGrandChildChild { - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandGrandChildData { - child: GrandGrandChildDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandGrandChild { - #[cfg_attr(feature = "serde", serde(flatten))] - parent: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - child: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - grandchild: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - grandgrandchild: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandGrandChildBuilder { - pub payload: Option, -} -impl GrandGrandChildData { - fn conforms(bytes: &[u8]) -> bool { - true - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let payload = bytes.get(); - bytes.get_mut().advance(payload.len()); - let child = match () { - _ if !payload.is_empty() => { - GrandGrandChildDataChild::Payload(Bytes::copy_from_slice(payload)) - } - _ => GrandGrandChildDataChild::None, - }; - Ok(Self { child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - match &self.child { - GrandGrandChildDataChild::Payload(payload) => buffer.put_slice(payload), - GrandGrandChildDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - self.child.get_total_size() - } -} -impl Packet for GrandGrandChild { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.parent.get_size()); - self.parent.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: GrandGrandChild) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: GrandGrandChild) -> Self { - packet.to_vec() - } -} -impl From for Parent { - fn from(packet: GrandGrandChild) -> Parent { - Parent::new(packet.parent).unwrap() - } -} -impl From for Child { - fn from(packet: GrandGrandChild) -> Child { - Child::new(packet.parent).unwrap() - } -} -impl From for GrandChild { - fn from(packet: GrandGrandChild) -> GrandChild { - GrandChild::new(packet.parent).unwrap() - } -} -impl TryFrom for GrandGrandChild { - type Error = Error; - fn try_from(packet: Parent) -> Result { - GrandGrandChild::new(packet.parent) - } -} -impl GrandGrandChild { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = ParentData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> GrandGrandChildChild { - match &self.grandgrandchild.child { - GrandGrandChildDataChild::Payload(payload) => { - GrandGrandChildChild::Payload(payload.clone()) - } - GrandGrandChildDataChild::None => GrandGrandChildChild::None, - } - } - fn new(parent: Arc) -> Result { - let child = match &parent.child { - ParentDataChild::Child(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ParentDataChild::Child), - actual: format!("{:?}", &parent.child), - }) - } - }; - let grandchild = match &child.child { - ChildDataChild::GrandChild(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ChildDataChild::GrandChild), - actual: format!("{:?}", &child.child), - }) - } - }; - let grandgrandchild = match &grandchild.child { - GrandChildDataChild::GrandGrandChild(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(GrandChildDataChild::GrandGrandChild), - actual: format!("{:?}", &grandchild.child), - }) - } - }; - Ok(Self { parent, child, grandchild, grandgrandchild }) - } - pub fn get_bar(&self) -> Enum16 { - self.parent.as_ref().bar - } - pub fn get_baz(&self) -> Enum16 { - self.parent.as_ref().baz - } - pub fn get_foo(&self) -> Enum16 { - self.parent.as_ref().foo - } - pub fn get_quux(&self) -> Enum16 { - self.child.as_ref().quux - } - pub fn get_payload(&self) -> &[u8] { - match &self.grandgrandchild.child { - GrandGrandChildDataChild::Payload(bytes) => &bytes, - GrandGrandChildDataChild::None => &[], - } - } - fn write_to(&self, buffer: &mut BytesMut) { - self.grandgrandchild.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.parent.get_size() - } -} -impl GrandGrandChildBuilder { - pub fn build(self) -> GrandGrandChild { - let grandgrandchild = Arc::new(GrandGrandChildData { - child: match self.payload { - None => GrandGrandChildDataChild::None, - Some(bytes) => GrandGrandChildDataChild::Payload(bytes), - }, - }); - let grandchild = Arc::new(GrandChildData { - child: GrandChildDataChild::GrandGrandChild(grandgrandchild), - }); - let child = - Arc::new(ChildData { quux: Enum16::A, child: ChildDataChild::GrandChild(grandchild) }); - let parent = Arc::new(ParentData { - bar: Enum16::A, - baz: Enum16::A, - foo: Enum16::A, - child: ParentDataChild::Child(child), - }); - GrandGrandChild::new(parent).unwrap() - } -} -impl From for Parent { - fn from(builder: GrandGrandChildBuilder) -> Parent { - builder.build().into() - } -} -impl From for Child { - fn from(builder: GrandGrandChildBuilder) -> Child { - builder.build().into() - } -} -impl From for GrandChild { - fn from(builder: GrandGrandChildBuilder) -> GrandChild { - builder.build().into() - } -} -impl From for GrandGrandChild { - fn from(builder: GrandGrandChildBuilder) -> GrandGrandChild { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_grand_children_little_endian.rs b/tools/pdl/tests/generated/packet_decl_grand_children_little_endian.rs deleted file mode 100644 index 16af6fcfbabba3a4bb6a198833c18deb41071fb2..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_grand_children_little_endian.rs +++ /dev/null @@ -1,986 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))] -pub enum Enum16 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum16 { - type Error = u16; - fn try_from(value: u16) -> std::result::Result { - match value { - 0x1 => Ok(Enum16::A), - 0x2 => Ok(Enum16::B), - _ => Err(value), - } - } -} -impl From<&Enum16> for u16 { - fn from(value: &Enum16) -> Self { - match value { - Enum16::A => 0x1, - Enum16::B => 0x2, - } - } -} -impl From for u16 { - fn from(value: Enum16) -> Self { - (&value).into() - } -} -impl From for i32 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum16) -> Self { - u16::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ParentDataChild { - Child(Arc), - Payload(Bytes), - None, -} -impl ParentDataChild { - fn get_total_size(&self) -> usize { - match self { - ParentDataChild::Child(value) => value.get_total_size(), - ParentDataChild::Payload(bytes) => bytes.len(), - ParentDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ParentChild { - Child(Child), - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ParentData { - foo: Enum16, - bar: Enum16, - baz: Enum16, - child: ParentDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Parent { - #[cfg_attr(feature = "serde", serde(flatten))] - parent: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ParentBuilder { - pub bar: Enum16, - pub baz: Enum16, - pub foo: Enum16, - pub payload: Option, -} -impl ParentData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 7 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let foo = Enum16::try_from(bytes.get_mut().get_u16_le()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Parent".to_string(), - field: "foo".to_string(), - value: bytes.get_mut().get_u16_le() as u64, - type_: "Enum16".to_string(), - } - })?; - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let bar = Enum16::try_from(bytes.get_mut().get_u16_le()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Parent".to_string(), - field: "bar".to_string(), - value: bytes.get_mut().get_u16_le() as u64, - type_: "Enum16".to_string(), - } - })?; - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let baz = Enum16::try_from(bytes.get_mut().get_u16_le()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Parent".to_string(), - field: "baz".to_string(), - value: bytes.get_mut().get_u16_le() as u64, - type_: "Enum16".to_string(), - } - })?; - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let payload_size = bytes.get_mut().get_u8() as usize; - if bytes.get().remaining() < payload_size { - return Err(Error::InvalidLengthError { - obj: "Parent".to_string(), - wanted: payload_size, - got: bytes.get().remaining(), - }); - } - let payload = &bytes.get()[..payload_size]; - bytes.get_mut().advance(payload_size); - let child = match (foo) { - (Enum16::A) if ChildData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = ChildData::parse_inner(&mut cell, bar, baz)?; - ParentDataChild::Child(Arc::new(child_data)) - } - _ if !payload.is_empty() => ParentDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => ParentDataChild::None, - }; - Ok(Self { foo, bar, baz, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u16_le(u16::from(self.foo)); - buffer.put_u16_le(u16::from(self.bar)); - buffer.put_u16_le(u16::from(self.baz)); - if self.child.get_total_size() > 0xff { - panic!( - "Invalid length for {}::{}: {} > {}", - "Parent", - "_payload_", - self.child.get_total_size(), - 0xff - ); - } - buffer.put_u8(self.child.get_total_size() as u8); - match &self.child { - ParentDataChild::Child(child) => child.write_to(buffer), - ParentDataChild::Payload(payload) => buffer.put_slice(payload), - ParentDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 7 + self.child.get_total_size() - } -} -impl Packet for Parent { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.parent.get_size()); - self.parent.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Parent) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Parent) -> Self { - packet.to_vec() - } -} -impl Parent { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = ParentData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> ParentChild { - match &self.parent.child { - ParentDataChild::Child(_) => { - ParentChild::Child(Child::new(self.parent.clone()).unwrap()) - } - ParentDataChild::Payload(payload) => ParentChild::Payload(payload.clone()), - ParentDataChild::None => ParentChild::None, - } - } - fn new(parent: Arc) -> Result { - Ok(Self { parent }) - } - pub fn get_bar(&self) -> Enum16 { - self.parent.as_ref().bar - } - pub fn get_baz(&self) -> Enum16 { - self.parent.as_ref().baz - } - pub fn get_foo(&self) -> Enum16 { - self.parent.as_ref().foo - } - fn write_to(&self, buffer: &mut BytesMut) { - self.parent.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.parent.get_size() - } -} -impl ParentBuilder { - pub fn build(self) -> Parent { - let parent = Arc::new(ParentData { - bar: self.bar, - baz: self.baz, - foo: self.foo, - child: match self.payload { - None => ParentDataChild::None, - Some(bytes) => ParentDataChild::Payload(bytes), - }, - }); - Parent::new(parent).unwrap() - } -} -impl From for Parent { - fn from(builder: ParentBuilder) -> Parent { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ChildDataChild { - GrandChild(Arc), - Payload(Bytes), - None, -} -impl ChildDataChild { - fn get_total_size(&self) -> usize { - match self { - ChildDataChild::GrandChild(value) => value.get_total_size(), - ChildDataChild::Payload(bytes) => bytes.len(), - ChildDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ChildChild { - GrandChild(GrandChild), - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ChildData { - quux: Enum16, - child: ChildDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Child { - #[cfg_attr(feature = "serde", serde(flatten))] - parent: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - child: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ChildBuilder { - pub bar: Enum16, - pub baz: Enum16, - pub quux: Enum16, - pub payload: Option, -} -impl ChildData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 2 - } - fn parse(bytes: &[u8], bar: Enum16, baz: Enum16) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell, bar, baz)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>, bar: Enum16, baz: Enum16) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Child".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let quux = Enum16::try_from(bytes.get_mut().get_u16_le()).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Child".to_string(), - field: "quux".to_string(), - value: bytes.get_mut().get_u16_le() as u64, - type_: "Enum16".to_string(), - } - })?; - let payload = bytes.get(); - bytes.get_mut().advance(payload.len()); - let child = match (bar, quux) { - (Enum16::A, Enum16::A) if GrandChildData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = GrandChildData::parse_inner(&mut cell, baz)?; - ChildDataChild::GrandChild(Arc::new(child_data)) - } - _ if !payload.is_empty() => ChildDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => ChildDataChild::None, - }; - Ok(Self { quux, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u16_le(u16::from(self.quux)); - match &self.child { - ChildDataChild::GrandChild(child) => child.write_to(buffer), - ChildDataChild::Payload(payload) => buffer.put_slice(payload), - ChildDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 2 + self.child.get_total_size() - } -} -impl Packet for Child { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.parent.get_size()); - self.parent.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Child) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Child) -> Self { - packet.to_vec() - } -} -impl From for Parent { - fn from(packet: Child) -> Parent { - Parent::new(packet.parent).unwrap() - } -} -impl TryFrom for Child { - type Error = Error; - fn try_from(packet: Parent) -> Result { - Child::new(packet.parent) - } -} -impl Child { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = ParentData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> ChildChild { - match &self.child.child { - ChildDataChild::GrandChild(_) => { - ChildChild::GrandChild(GrandChild::new(self.parent.clone()).unwrap()) - } - ChildDataChild::Payload(payload) => ChildChild::Payload(payload.clone()), - ChildDataChild::None => ChildChild::None, - } - } - fn new(parent: Arc) -> Result { - let child = match &parent.child { - ParentDataChild::Child(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ParentDataChild::Child), - actual: format!("{:?}", &parent.child), - }) - } - }; - Ok(Self { parent, child }) - } - pub fn get_bar(&self) -> Enum16 { - self.parent.as_ref().bar - } - pub fn get_baz(&self) -> Enum16 { - self.parent.as_ref().baz - } - pub fn get_foo(&self) -> Enum16 { - self.parent.as_ref().foo - } - pub fn get_quux(&self) -> Enum16 { - self.child.as_ref().quux - } - fn write_to(&self, buffer: &mut BytesMut) { - self.child.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.parent.get_size() - } -} -impl ChildBuilder { - pub fn build(self) -> Child { - let child = Arc::new(ChildData { - quux: self.quux, - child: match self.payload { - None => ChildDataChild::None, - Some(bytes) => ChildDataChild::Payload(bytes), - }, - }); - let parent = Arc::new(ParentData { - bar: self.bar, - baz: self.baz, - foo: Enum16::A, - child: ParentDataChild::Child(child), - }); - Child::new(parent).unwrap() - } -} -impl From for Parent { - fn from(builder: ChildBuilder) -> Parent { - builder.build().into() - } -} -impl From for Child { - fn from(builder: ChildBuilder) -> Child { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum GrandChildDataChild { - GrandGrandChild(Arc), - Payload(Bytes), - None, -} -impl GrandChildDataChild { - fn get_total_size(&self) -> usize { - match self { - GrandChildDataChild::GrandGrandChild(value) => value.get_total_size(), - GrandChildDataChild::Payload(bytes) => bytes.len(), - GrandChildDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum GrandChildChild { - GrandGrandChild(GrandGrandChild), - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandChildData { - child: GrandChildDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandChild { - #[cfg_attr(feature = "serde", serde(flatten))] - parent: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - child: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - grandchild: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandChildBuilder { - pub baz: Enum16, - pub payload: Option, -} -impl GrandChildData { - fn conforms(bytes: &[u8]) -> bool { - true - } - fn parse(bytes: &[u8], baz: Enum16) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell, baz)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>, baz: Enum16) -> Result { - let payload = bytes.get(); - bytes.get_mut().advance(payload.len()); - let child = match (baz) { - (Enum16::A) if GrandGrandChildData::conforms(&payload) => { - let mut cell = Cell::new(payload); - let child_data = GrandGrandChildData::parse_inner(&mut cell)?; - GrandChildDataChild::GrandGrandChild(Arc::new(child_data)) - } - _ if !payload.is_empty() => { - GrandChildDataChild::Payload(Bytes::copy_from_slice(payload)) - } - _ => GrandChildDataChild::None, - }; - Ok(Self { child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - match &self.child { - GrandChildDataChild::GrandGrandChild(child) => child.write_to(buffer), - GrandChildDataChild::Payload(payload) => buffer.put_slice(payload), - GrandChildDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - self.child.get_total_size() - } -} -impl Packet for GrandChild { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.parent.get_size()); - self.parent.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: GrandChild) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: GrandChild) -> Self { - packet.to_vec() - } -} -impl From for Parent { - fn from(packet: GrandChild) -> Parent { - Parent::new(packet.parent).unwrap() - } -} -impl From for Child { - fn from(packet: GrandChild) -> Child { - Child::new(packet.parent).unwrap() - } -} -impl TryFrom for GrandChild { - type Error = Error; - fn try_from(packet: Parent) -> Result { - GrandChild::new(packet.parent) - } -} -impl GrandChild { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = ParentData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> GrandChildChild { - match &self.grandchild.child { - GrandChildDataChild::GrandGrandChild(_) => { - GrandChildChild::GrandGrandChild(GrandGrandChild::new(self.parent.clone()).unwrap()) - } - GrandChildDataChild::Payload(payload) => GrandChildChild::Payload(payload.clone()), - GrandChildDataChild::None => GrandChildChild::None, - } - } - fn new(parent: Arc) -> Result { - let child = match &parent.child { - ParentDataChild::Child(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ParentDataChild::Child), - actual: format!("{:?}", &parent.child), - }) - } - }; - let grandchild = match &child.child { - ChildDataChild::GrandChild(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ChildDataChild::GrandChild), - actual: format!("{:?}", &child.child), - }) - } - }; - Ok(Self { parent, child, grandchild }) - } - pub fn get_bar(&self) -> Enum16 { - self.parent.as_ref().bar - } - pub fn get_baz(&self) -> Enum16 { - self.parent.as_ref().baz - } - pub fn get_foo(&self) -> Enum16 { - self.parent.as_ref().foo - } - pub fn get_quux(&self) -> Enum16 { - self.child.as_ref().quux - } - fn write_to(&self, buffer: &mut BytesMut) { - self.grandchild.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.parent.get_size() - } -} -impl GrandChildBuilder { - pub fn build(self) -> GrandChild { - let grandchild = Arc::new(GrandChildData { - child: match self.payload { - None => GrandChildDataChild::None, - Some(bytes) => GrandChildDataChild::Payload(bytes), - }, - }); - let child = - Arc::new(ChildData { quux: Enum16::A, child: ChildDataChild::GrandChild(grandchild) }); - let parent = Arc::new(ParentData { - bar: Enum16::A, - baz: self.baz, - foo: Enum16::A, - child: ParentDataChild::Child(child), - }); - GrandChild::new(parent).unwrap() - } -} -impl From for Parent { - fn from(builder: GrandChildBuilder) -> Parent { - builder.build().into() - } -} -impl From for Child { - fn from(builder: GrandChildBuilder) -> Child { - builder.build().into() - } -} -impl From for GrandChild { - fn from(builder: GrandChildBuilder) -> GrandChild { - builder.build().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum GrandGrandChildDataChild { - Payload(Bytes), - None, -} -impl GrandGrandChildDataChild { - fn get_total_size(&self) -> usize { - match self { - GrandGrandChildDataChild::Payload(bytes) => bytes.len(), - GrandGrandChildDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum GrandGrandChildChild { - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandGrandChildData { - child: GrandGrandChildDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandGrandChild { - #[cfg_attr(feature = "serde", serde(flatten))] - parent: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - child: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - grandchild: Arc, - #[cfg_attr(feature = "serde", serde(flatten))] - grandgrandchild: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct GrandGrandChildBuilder { - pub payload: Option, -} -impl GrandGrandChildData { - fn conforms(bytes: &[u8]) -> bool { - true - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let payload = bytes.get(); - bytes.get_mut().advance(payload.len()); - let child = match () { - _ if !payload.is_empty() => { - GrandGrandChildDataChild::Payload(Bytes::copy_from_slice(payload)) - } - _ => GrandGrandChildDataChild::None, - }; - Ok(Self { child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - match &self.child { - GrandGrandChildDataChild::Payload(payload) => buffer.put_slice(payload), - GrandGrandChildDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - self.child.get_total_size() - } -} -impl Packet for GrandGrandChild { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.parent.get_size()); - self.parent.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: GrandGrandChild) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: GrandGrandChild) -> Self { - packet.to_vec() - } -} -impl From for Parent { - fn from(packet: GrandGrandChild) -> Parent { - Parent::new(packet.parent).unwrap() - } -} -impl From for Child { - fn from(packet: GrandGrandChild) -> Child { - Child::new(packet.parent).unwrap() - } -} -impl From for GrandChild { - fn from(packet: GrandGrandChild) -> GrandChild { - GrandChild::new(packet.parent).unwrap() - } -} -impl TryFrom for GrandGrandChild { - type Error = Error; - fn try_from(packet: Parent) -> Result { - GrandGrandChild::new(packet.parent) - } -} -impl GrandGrandChild { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = ParentData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> GrandGrandChildChild { - match &self.grandgrandchild.child { - GrandGrandChildDataChild::Payload(payload) => { - GrandGrandChildChild::Payload(payload.clone()) - } - GrandGrandChildDataChild::None => GrandGrandChildChild::None, - } - } - fn new(parent: Arc) -> Result { - let child = match &parent.child { - ParentDataChild::Child(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ParentDataChild::Child), - actual: format!("{:?}", &parent.child), - }) - } - }; - let grandchild = match &child.child { - ChildDataChild::GrandChild(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(ChildDataChild::GrandChild), - actual: format!("{:?}", &child.child), - }) - } - }; - let grandgrandchild = match &grandchild.child { - GrandChildDataChild::GrandGrandChild(value) => value.clone(), - _ => { - return Err(Error::InvalidChildError { - expected: stringify!(GrandChildDataChild::GrandGrandChild), - actual: format!("{:?}", &grandchild.child), - }) - } - }; - Ok(Self { parent, child, grandchild, grandgrandchild }) - } - pub fn get_bar(&self) -> Enum16 { - self.parent.as_ref().bar - } - pub fn get_baz(&self) -> Enum16 { - self.parent.as_ref().baz - } - pub fn get_foo(&self) -> Enum16 { - self.parent.as_ref().foo - } - pub fn get_quux(&self) -> Enum16 { - self.child.as_ref().quux - } - pub fn get_payload(&self) -> &[u8] { - match &self.grandgrandchild.child { - GrandGrandChildDataChild::Payload(bytes) => &bytes, - GrandGrandChildDataChild::None => &[], - } - } - fn write_to(&self, buffer: &mut BytesMut) { - self.grandgrandchild.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.parent.get_size() - } -} -impl GrandGrandChildBuilder { - pub fn build(self) -> GrandGrandChild { - let grandgrandchild = Arc::new(GrandGrandChildData { - child: match self.payload { - None => GrandGrandChildDataChild::None, - Some(bytes) => GrandGrandChildDataChild::Payload(bytes), - }, - }); - let grandchild = Arc::new(GrandChildData { - child: GrandChildDataChild::GrandGrandChild(grandgrandchild), - }); - let child = - Arc::new(ChildData { quux: Enum16::A, child: ChildDataChild::GrandChild(grandchild) }); - let parent = Arc::new(ParentData { - bar: Enum16::A, - baz: Enum16::A, - foo: Enum16::A, - child: ParentDataChild::Child(child), - }); - GrandGrandChild::new(parent).unwrap() - } -} -impl From for Parent { - fn from(builder: GrandGrandChildBuilder) -> Parent { - builder.build().into() - } -} -impl From for Child { - fn from(builder: GrandGrandChildBuilder) -> Child { - builder.build().into() - } -} -impl From for GrandChild { - fn from(builder: GrandGrandChildBuilder) -> GrandChild { - builder.build().into() - } -} -impl From for GrandGrandChild { - fn from(builder: GrandGrandChildBuilder) -> GrandGrandChild { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_mask_scalar_value_big_endian.rs b/tools/pdl/tests/generated/packet_decl_mask_scalar_value_big_endian.rs deleted file mode 100644 index 6879967e728e962c27e90b050df3b5c923787c7e..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_mask_scalar_value_big_endian.rs +++ /dev/null @@ -1,172 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u8, - b: u32, - c: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u8, - pub b: u32, - pub c: u8, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 4 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 4 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 4, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u32(); - let a = (chunk & 0x3) as u8; - let b = ((chunk >> 2) & 0xff_ffff); - let c = ((chunk >> 26) & 0x3f) as u8; - Ok(Self { a, b, c }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a > 0x3 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x3); - } - if self.b > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "b", self.b, 0xff_ffff); - } - if self.c > 0x3f { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x3f); - } - let value = (self.a as u32) | (self.b << 2) | ((self.c as u32) << 26); - buffer.put_u32(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 4 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> u32 { - self.foo.as_ref().b - } - pub fn get_c(&self) -> u8 { - self.foo.as_ref().c - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { a: self.a, b: self.b, c: self.c }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_mask_scalar_value_little_endian.rs b/tools/pdl/tests/generated/packet_decl_mask_scalar_value_little_endian.rs deleted file mode 100644 index b4c5b3c35796afad0e17cac21c15f3d9d210a6e6..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_mask_scalar_value_little_endian.rs +++ /dev/null @@ -1,172 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u8, - b: u32, - c: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u8, - pub b: u32, - pub c: u8, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 4 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 4 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 4, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u32_le(); - let a = (chunk & 0x3) as u8; - let b = ((chunk >> 2) & 0xff_ffff); - let c = ((chunk >> 26) & 0x3f) as u8; - Ok(Self { a, b, c }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a > 0x3 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x3); - } - if self.b > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "b", self.b, 0xff_ffff); - } - if self.c > 0x3f { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x3f); - } - let value = (self.a as u32) | (self.b << 2) | ((self.c as u32) << 26); - buffer.put_u32_le(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 4 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> u32 { - self.foo.as_ref().b - } - pub fn get_c(&self) -> u8 { - self.foo.as_ref().c - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { a: self.a, b: self.b, c: self.c }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs b/tools/pdl/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs deleted file mode 100644 index 49982a0a4a4c4a22ccc26beeec0f820d9ea738f4..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs +++ /dev/null @@ -1,315 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum Enum7 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum7 { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x1 => Ok(Enum7::A), - 0x2 => Ok(Enum7::B), - _ => Err(value), - } - } -} -impl From<&Enum7> for u8 { - fn from(value: &Enum7) -> Self { - match value { - Enum7::A => 0x1, - Enum7::B => 0x2, - } - } -} -impl From for u8 { - fn from(value: Enum7) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))] -pub enum Enum9 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum9 { - type Error = u16; - fn try_from(value: u16) -> std::result::Result { - match value { - 0x1 => Ok(Enum9::A), - 0x2 => Ok(Enum9::B), - _ => Err(value), - } - } -} -impl From<&Enum9> for u16 { - fn from(value: &Enum9) -> Self { - match value { - Enum9::A => 0x1, - Enum9::B => 0x2, - } - } -} -impl From for u16 { - fn from(value: Enum9) -> Self { - (&value).into() - } -} -impl From for i16 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} -impl From for i32 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: Enum7, - y: u8, - z: Enum9, - w: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub w: u8, - pub x: Enum7, - pub y: u8, - pub z: Enum9, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_uint(3) as u32; - let x = - Enum7::try_from((chunk & 0x7f) as u8).map_err(|_| Error::InvalidEnumValueError { - obj: "Foo".to_string(), - field: "x".to_string(), - value: (chunk & 0x7f) as u8 as u64, - type_: "Enum7".to_string(), - })?; - let y = ((chunk >> 7) & 0x1f) as u8; - let z = Enum9::try_from(((chunk >> 12) & 0x1ff) as u16).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Foo".to_string(), - field: "z".to_string(), - value: ((chunk >> 12) & 0x1ff) as u16 as u64, - type_: "Enum9".to_string(), - } - })?; - let w = ((chunk >> 21) & 0x7) as u8; - Ok(Self { x, y, z, w }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.y > 0x1f { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "y", self.y, 0x1f); - } - if self.w > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "w", self.w, 0x7); - } - let value = (u8::from(self.x) as u32) - | ((self.y as u32) << 7) - | ((u16::from(self.z) as u32) << 12) - | ((self.w as u32) << 21); - buffer.put_uint(value as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_w(&self) -> u8 { - self.foo.as_ref().w - } - pub fn get_x(&self) -> Enum7 { - self.foo.as_ref().x - } - pub fn get_y(&self) -> u8 { - self.foo.as_ref().y - } - pub fn get_z(&self) -> Enum9 { - self.foo.as_ref().z - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { w: self.w, x: self.x, y: self.y, z: self.z }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs b/tools/pdl/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs deleted file mode 100644 index 0ca860b80763ca5d10ea2bd2b0a855269f5f3ffa..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs +++ /dev/null @@ -1,315 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))] -pub enum Enum7 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum7 { - type Error = u8; - fn try_from(value: u8) -> std::result::Result { - match value { - 0x1 => Ok(Enum7::A), - 0x2 => Ok(Enum7::B), - _ => Err(value), - } - } -} -impl From<&Enum7> for u8 { - fn from(value: &Enum7) -> Self { - match value { - Enum7::A => 0x1, - Enum7::B => 0x2, - } - } -} -impl From for u8 { - fn from(value: Enum7) -> Self { - (&value).into() - } -} -impl From for i8 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i16 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i32 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u16 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum7) -> Self { - u8::from(value) as Self - } -} - -#[repr(u64)] -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))] -pub enum Enum9 { - A = 0x1, - B = 0x2, -} -impl TryFrom for Enum9 { - type Error = u16; - fn try_from(value: u16) -> std::result::Result { - match value { - 0x1 => Ok(Enum9::A), - 0x2 => Ok(Enum9::B), - _ => Err(value), - } - } -} -impl From<&Enum9> for u16 { - fn from(value: &Enum9) -> Self { - match value { - Enum9::A => 0x1, - Enum9::B => 0x2, - } - } -} -impl From for u16 { - fn from(value: Enum9) -> Self { - (&value).into() - } -} -impl From for i16 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} -impl From for i32 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} -impl From for i64 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} -impl From for u32 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} -impl From for u64 { - fn from(value: Enum9) -> Self { - u16::from(value) as Self - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: Enum7, - y: u8, - z: Enum9, - w: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub w: u8, - pub x: Enum7, - pub y: u8, - pub z: Enum9, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_uint_le(3) as u32; - let x = - Enum7::try_from((chunk & 0x7f) as u8).map_err(|_| Error::InvalidEnumValueError { - obj: "Foo".to_string(), - field: "x".to_string(), - value: (chunk & 0x7f) as u8 as u64, - type_: "Enum7".to_string(), - })?; - let y = ((chunk >> 7) & 0x1f) as u8; - let z = Enum9::try_from(((chunk >> 12) & 0x1ff) as u16).map_err(|_| { - Error::InvalidEnumValueError { - obj: "Foo".to_string(), - field: "z".to_string(), - value: ((chunk >> 12) & 0x1ff) as u16 as u64, - type_: "Enum9".to_string(), - } - })?; - let w = ((chunk >> 21) & 0x7) as u8; - Ok(Self { x, y, z, w }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.y > 0x1f { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "y", self.y, 0x1f); - } - if self.w > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "w", self.w, 0x7); - } - let value = (u8::from(self.x) as u32) - | ((self.y as u32) << 7) - | ((u16::from(self.z) as u32) << 12) - | ((self.w as u32) << 21); - buffer.put_uint_le(value as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_w(&self) -> u8 { - self.foo.as_ref().w - } - pub fn get_x(&self) -> Enum7 { - self.foo.as_ref().x - } - pub fn get_y(&self) -> u8 { - self.foo.as_ref().y - } - pub fn get_z(&self) -> Enum9 { - self.foo.as_ref().z - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { w: self.w, x: self.x, y: self.y, z: self.z }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs b/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs deleted file mode 100644 index 40f779a75a2056e1efc1688f1faaf10da4acc464..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs +++ /dev/null @@ -1,202 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooDataChild { - Payload(Bytes), - None, -} -impl FooDataChild { - fn get_total_size(&self) -> usize { - match self { - FooDataChild::Payload(bytes) => bytes.len(), - FooDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooChild { - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u32, - child: FooDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u32, - pub payload: Option, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let a = bytes.get_mut().get_uint(3) as u32; - let payload = bytes.get(); - bytes.get_mut().advance(payload.len()); - let child = match () { - _ if !payload.is_empty() => FooDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => FooDataChild::None, - }; - Ok(Self { a, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0xff_ffff); - } - buffer.put_uint(self.a as u64, 3); - match &self.child { - FooDataChild::Payload(payload) => buffer.put_slice(payload), - FooDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 + self.child.get_total_size() - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> FooChild { - match &self.foo.child { - FooDataChild::Payload(payload) => FooChild::Payload(payload.clone()), - FooDataChild::None => FooChild::None, - } - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u32 { - self.foo.as_ref().a - } - pub fn get_payload(&self) -> &[u8] { - match &self.foo.child { - FooDataChild::Payload(bytes) => &bytes, - FooDataChild::None => &[], - } - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { - a: self.a, - child: match self.payload { - None => FooDataChild::None, - Some(bytes) => FooDataChild::Payload(bytes), - }, - }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs b/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs deleted file mode 100644 index 36bcca6553a472dc99798b87e60504811a9369c5..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs +++ /dev/null @@ -1,202 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooDataChild { - Payload(Bytes), - None, -} -impl FooDataChild { - fn get_total_size(&self) -> usize { - match self { - FooDataChild::Payload(bytes) => bytes.len(), - FooDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooChild { - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u32, - child: FooDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u32, - pub payload: Option, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let a = bytes.get_mut().get_uint_le(3) as u32; - let payload = bytes.get(); - bytes.get_mut().advance(payload.len()); - let child = match () { - _ if !payload.is_empty() => FooDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => FooDataChild::None, - }; - Ok(Self { a, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0xff_ffff); - } - buffer.put_uint_le(self.a as u64, 3); - match &self.child { - FooDataChild::Payload(payload) => buffer.put_slice(payload), - FooDataChild::None => {} - } - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 + self.child.get_total_size() - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> FooChild { - match &self.foo.child { - FooDataChild::Payload(payload) => FooChild::Payload(payload.clone()), - FooDataChild::None => FooChild::None, - } - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u32 { - self.foo.as_ref().a - } - pub fn get_payload(&self) -> &[u8] { - match &self.foo.child { - FooDataChild::Payload(bytes) => &bytes, - FooDataChild::None => &[], - } - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { - a: self.a, - child: match self.payload { - None => FooDataChild::None, - Some(bytes) => FooDataChild::Payload(bytes), - }, - }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs b/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs deleted file mode 100644 index fcfbb99ba8d9d7a4d3ddc435001164735342f0db..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs +++ /dev/null @@ -1,209 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooDataChild { - Payload(Bytes), - None, -} -impl FooDataChild { - fn get_total_size(&self) -> usize { - match self { - FooDataChild::Payload(bytes) => bytes.len(), - FooDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooChild { - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u32, - child: FooDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u32, - pub payload: Option, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let payload = &bytes.get()[..bytes.get().len() - 3]; - bytes.get_mut().advance(payload.len()); - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let a = bytes.get_mut().get_uint(3) as u32; - let child = match () { - _ if !payload.is_empty() => FooDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => FooDataChild::None, - }; - Ok(Self { a, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - match &self.child { - FooDataChild::Payload(payload) => buffer.put_slice(payload), - FooDataChild::None => {} - } - if self.a > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0xff_ffff); - } - buffer.put_uint(self.a as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 + self.child.get_total_size() - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> FooChild { - match &self.foo.child { - FooDataChild::Payload(payload) => FooChild::Payload(payload.clone()), - FooDataChild::None => FooChild::None, - } - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u32 { - self.foo.as_ref().a - } - pub fn get_payload(&self) -> &[u8] { - match &self.foo.child { - FooDataChild::Payload(bytes) => &bytes, - FooDataChild::None => &[], - } - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { - a: self.a, - child: match self.payload { - None => FooDataChild::None, - Some(bytes) => FooDataChild::Payload(bytes), - }, - }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_terminal_little_endian.rs b/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_terminal_little_endian.rs deleted file mode 100644 index 277eddd0a1bb63421d7bbf5c0b92a8bd1ad4602e..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_payload_field_unknown_size_terminal_little_endian.rs +++ /dev/null @@ -1,209 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooDataChild { - Payload(Bytes), - None, -} -impl FooDataChild { - fn get_total_size(&self) -> usize { - match self { - FooDataChild::Payload(bytes) => bytes.len(), - FooDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooChild { - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u32, - child: FooDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u32, - pub payload: Option, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 3 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let payload = &bytes.get()[..bytes.get().len() - 3]; - bytes.get_mut().advance(payload.len()); - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let a = bytes.get_mut().get_uint_le(3) as u32; - let child = match () { - _ if !payload.is_empty() => FooDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => FooDataChild::None, - }; - Ok(Self { a, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - match &self.child { - FooDataChild::Payload(payload) => buffer.put_slice(payload), - FooDataChild::None => {} - } - if self.a > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0xff_ffff); - } - buffer.put_uint_le(self.a as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 3 + self.child.get_total_size() - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> FooChild { - match &self.foo.child { - FooDataChild::Payload(payload) => FooChild::Payload(payload.clone()), - FooDataChild::None => FooChild::None, - } - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u32 { - self.foo.as_ref().a - } - pub fn get_payload(&self) -> &[u8] { - match &self.foo.child { - FooDataChild::Payload(bytes) => &bytes, - FooDataChild::None => &[], - } - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { - a: self.a, - child: match self.payload { - None => FooDataChild::None, - Some(bytes) => FooDataChild::Payload(bytes), - }, - }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_payload_field_variable_size_big_endian.rs b/tools/pdl/tests/generated/packet_decl_payload_field_variable_size_big_endian.rs deleted file mode 100644 index 3b57129bf79967db25a2c2922a4a2df18ed5d3ad..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_payload_field_variable_size_big_endian.rs +++ /dev/null @@ -1,239 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooDataChild { - Payload(Bytes), - None, -} -impl FooDataChild { - fn get_total_size(&self) -> usize { - match self { - FooDataChild::Payload(bytes) => bytes.len(), - FooDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooChild { - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u8, - b: u16, - child: FooDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u8, - pub b: u16, - pub payload: Option, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 4 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let a = bytes.get_mut().get_u8(); - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let payload_size = bytes.get_mut().get_u8() as usize; - if bytes.get().remaining() < payload_size { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: payload_size, - got: bytes.get().remaining(), - }); - } - let payload = &bytes.get()[..payload_size]; - bytes.get_mut().advance(payload_size); - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let b = bytes.get_mut().get_u16(); - let child = match () { - _ if !payload.is_empty() => FooDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => FooDataChild::None, - }; - Ok(Self { a, b, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.a); - if self.child.get_total_size() > 0xff { - panic!( - "Invalid length for {}::{}: {} > {}", - "Foo", - "_payload_", - self.child.get_total_size(), - 0xff - ); - } - buffer.put_u8(self.child.get_total_size() as u8); - match &self.child { - FooDataChild::Payload(payload) => buffer.put_slice(payload), - FooDataChild::None => {} - } - buffer.put_u16(self.b); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 4 + self.child.get_total_size() - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> FooChild { - match &self.foo.child { - FooDataChild::Payload(payload) => FooChild::Payload(payload.clone()), - FooDataChild::None => FooChild::None, - } - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> u16 { - self.foo.as_ref().b - } - pub fn get_payload(&self) -> &[u8] { - match &self.foo.child { - FooDataChild::Payload(bytes) => &bytes, - FooDataChild::None => &[], - } - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { - a: self.a, - b: self.b, - child: match self.payload { - None => FooDataChild::None, - Some(bytes) => FooDataChild::Payload(bytes), - }, - }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_payload_field_variable_size_little_endian.rs b/tools/pdl/tests/generated/packet_decl_payload_field_variable_size_little_endian.rs deleted file mode 100644 index d7ae81fec5acc06c242bcec642ee5612c0a7c29a..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_payload_field_variable_size_little_endian.rs +++ /dev/null @@ -1,239 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooDataChild { - Payload(Bytes), - None, -} -impl FooDataChild { - fn get_total_size(&self) -> usize { - match self { - FooDataChild::Payload(bytes) => bytes.len(), - FooDataChild::None => 0, - } - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FooChild { - Payload(Bytes), - None, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - a: u8, - b: u16, - child: FooDataChild, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub a: u8, - pub b: u16, - pub payload: Option, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 4 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let a = bytes.get_mut().get_u8(); - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let payload_size = bytes.get_mut().get_u8() as usize; - if bytes.get().remaining() < payload_size { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: payload_size, - got: bytes.get().remaining(), - }); - } - let payload = &bytes.get()[..payload_size]; - bytes.get_mut().advance(payload_size); - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let b = bytes.get_mut().get_u16_le(); - let child = match () { - _ if !payload.is_empty() => FooDataChild::Payload(Bytes::copy_from_slice(payload)), - _ => FooDataChild::None, - }; - Ok(Self { a, b, child }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.a); - if self.child.get_total_size() > 0xff { - panic!( - "Invalid length for {}::{}: {} > {}", - "Foo", - "_payload_", - self.child.get_total_size(), - 0xff - ); - } - buffer.put_u8(self.child.get_total_size() as u8); - match &self.child { - FooDataChild::Payload(payload) => buffer.put_slice(payload), - FooDataChild::None => {} - } - buffer.put_u16_le(self.b); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 4 + self.child.get_total_size() - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - pub fn specialize(&self) -> FooChild { - match &self.foo.child { - FooDataChild::Payload(payload) => FooChild::Payload(payload.clone()), - FooDataChild::None => FooChild::None, - } - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_a(&self) -> u8 { - self.foo.as_ref().a - } - pub fn get_b(&self) -> u16 { - self.foo.as_ref().b - } - pub fn get_payload(&self) -> &[u8] { - match &self.foo.child { - FooDataChild::Payload(bytes) => &bytes, - FooDataChild::None => &[], - } - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { - a: self.a, - b: self.b, - child: match self.payload { - None => FooDataChild::None, - Some(bytes) => FooDataChild::Payload(bytes), - }, - }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_reserved_field_big_endian.rs b/tools/pdl/tests/generated/packet_decl_reserved_field_big_endian.rs deleted file mode 100644 index 6cfe597634cb265edbcd18aa96cbbca138bd8449..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_reserved_field_big_endian.rs +++ /dev/null @@ -1,142 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData {} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder {} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - bytes.get_mut().advance(5); - Ok(Self {}) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_bytes(0, 5); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData {}); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_reserved_field_little_endian.rs b/tools/pdl/tests/generated/packet_decl_reserved_field_little_endian.rs deleted file mode 100644 index 6cfe597634cb265edbcd18aa96cbbca138bd8449..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_reserved_field_little_endian.rs +++ /dev/null @@ -1,142 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData {} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder {} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 5 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 5 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 5, - got: bytes.get().remaining(), - }); - } - bytes.get_mut().advance(5); - Ok(Self {}) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_bytes(0, 5); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 5 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData {}); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_simple_scalars_big_endian.rs b/tools/pdl/tests/generated/packet_decl_simple_scalars_big_endian.rs deleted file mode 100644 index 244ed08e671c02175975a863517467c2861d3b1c..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_simple_scalars_big_endian.rs +++ /dev/null @@ -1,180 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: u8, - y: u16, - z: u32, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: u8, - pub y: u16, - pub z: u32, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 6 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_u8(); - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let y = bytes.get_mut().get_u16(); - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let z = bytes.get_mut().get_uint(3) as u32; - Ok(Self { x, y, z }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.x); - buffer.put_u16(self.y); - if self.z > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "z", self.z, 0xff_ffff); - } - buffer.put_uint(self.z as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 6 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> u8 { - self.foo.as_ref().x - } - pub fn get_y(&self) -> u16 { - self.foo.as_ref().y - } - pub fn get_z(&self) -> u32 { - self.foo.as_ref().z - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x, y: self.y, z: self.z }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/packet_decl_simple_scalars_little_endian.rs b/tools/pdl/tests/generated/packet_decl_simple_scalars_little_endian.rs deleted file mode 100644 index 775d7a091295d92cbc6d50da4439180a368785ba..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/packet_decl_simple_scalars_little_endian.rs +++ /dev/null @@ -1,180 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooData { - x: u8, - y: u16, - z: u32, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - #[cfg_attr(feature = "serde", serde(flatten))] - foo: Arc, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FooBuilder { - pub x: u8, - pub y: u16, - pub z: u32, -} -impl FooData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 6 - } - fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let x = bytes.get_mut().get_u8(); - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let y = bytes.get_mut().get_u16_le(); - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let z = bytes.get_mut().get_uint_le(3) as u32; - Ok(Self { x, y, z }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.x); - buffer.put_u16_le(self.y); - if self.z > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "z", self.z, 0xff_ffff); - } - buffer.put_uint_le(self.z as u64, 3); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 6 - } -} -impl Packet for Foo { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.foo.get_size()); - self.foo.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec { - self.to_bytes().to_vec() - } -} -impl From for Bytes { - fn from(packet: Foo) -> Self { - packet.to_bytes() - } -} -impl From for Vec { - fn from(packet: Foo) -> Self { - packet.to_vec() - } -} -impl Foo { - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - let data = FooData::parse_inner(&mut bytes)?; - Self::new(Arc::new(data)) - } - fn new(foo: Arc) -> Result { - Ok(Self { foo }) - } - pub fn get_x(&self) -> u8 { - self.foo.as_ref().x - } - pub fn get_y(&self) -> u16 { - self.foo.as_ref().y - } - pub fn get_z(&self) -> u32 { - self.foo.as_ref().z - } - fn write_to(&self, buffer: &mut BytesMut) { - self.foo.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.foo.get_size() - } -} -impl FooBuilder { - pub fn build(self) -> Foo { - let foo = Arc::new(FooData { x: self.x, y: self.y, z: self.z }); - Foo::new(foo).unwrap() - } -} -impl From for Foo { - fn from(builder: FooBuilder) -> Foo { - builder.build().into() - } -} diff --git a/tools/pdl/tests/generated/preamble.rs b/tools/pdl/tests/generated/preamble.rs deleted file mode 100644 index c7d0fad1b92fee5bedb0002a9d20188a6e5b375a..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/preamble.rs +++ /dev/null @@ -1,48 +0,0 @@ -// @generated rust packets from foo.pdl - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} diff --git a/tools/pdl/tests/generated/struct_decl_complex_scalars_big_endian.rs b/tools/pdl/tests/generated/struct_decl_complex_scalars_big_endian.rs deleted file mode 100644 index 35cbe95eb3b50550dd946c864e29b78513b01fb0..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/struct_decl_complex_scalars_big_endian.rs +++ /dev/null @@ -1,129 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - pub a: u8, - pub b: u8, - pub c: u8, - pub d: u32, - pub e: u16, - pub f: u8, -} -impl Foo { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 7 - } - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u16(); - let a = (chunk & 0x7) as u8; - let b = (chunk >> 3) as u8; - let c = ((chunk >> 11) & 0x1f) as u8; - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let d = bytes.get_mut().get_uint(3) as u32; - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u16(); - let e = (chunk & 0xfff); - let f = ((chunk >> 12) & 0xf) as u8; - Ok(Self { a, b, c, d, e, f }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x7); - } - if self.c > 0x1f { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x1f); - } - let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11); - buffer.put_u16(value); - if self.d > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "d", self.d, 0xff_ffff); - } - buffer.put_uint(self.d as u64, 3); - if self.e > 0xfff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "e", self.e, 0xfff); - } - if self.f > 0xf { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "f", self.f, 0xf); - } - let value = self.e | ((self.f as u16) << 12); - buffer.put_u16(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 7 - } -} diff --git a/tools/pdl/tests/generated/struct_decl_complex_scalars_little_endian.rs b/tools/pdl/tests/generated/struct_decl_complex_scalars_little_endian.rs deleted file mode 100644 index d227b3846fdd46b6b8a6afcdc7cfd9aa2f7aa121..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated/struct_decl_complex_scalars_little_endian.rs +++ /dev/null @@ -1,129 +0,0 @@ -// @generated rust packets from test - -use bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::cell::Cell; -use std::convert::{TryFrom, TryInto}; -use std::fmt; -use std::sync::Arc; -use thiserror::Error; - -type Result = std::result::Result; - -#[doc = r" Private prevents users from creating arbitrary scalar values"] -#[doc = r" in situations where the value needs to be validated."] -#[doc = r" Users can freely deref the value, but only the backend"] -#[doc = r" may create it."] -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Private(T); -impl std::ops::Deref for Private { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} - -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Foo { - pub a: u8, - pub b: u8, - pub c: u8, - pub d: u32, - pub e: u16, - pub f: u8, -} -impl Foo { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 7 - } - pub fn parse(bytes: &[u8]) -> Result { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result { - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u16_le(); - let a = (chunk & 0x7) as u8; - let b = (chunk >> 3) as u8; - let c = ((chunk >> 11) & 0x1f) as u8; - if bytes.get().remaining() < 3 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 3, - got: bytes.get().remaining(), - }); - } - let d = bytes.get_mut().get_uint_le(3) as u32; - if bytes.get().remaining() < 2 { - return Err(Error::InvalidLengthError { - obj: "Foo".to_string(), - wanted: 2, - got: bytes.get().remaining(), - }); - } - let chunk = bytes.get_mut().get_u16_le(); - let e = (chunk & 0xfff); - let f = ((chunk >> 12) & 0xf) as u8; - Ok(Self { a, b, c, d, e, f }) - } - fn write_to(&self, buffer: &mut BytesMut) { - if self.a > 0x7 { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x7); - } - if self.c > 0x1f { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x1f); - } - let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11); - buffer.put_u16_le(value); - if self.d > 0xff_ffff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "d", self.d, 0xff_ffff); - } - buffer.put_uint_le(self.d as u64, 3); - if self.e > 0xfff { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "e", self.e, 0xfff); - } - if self.f > 0xf { - panic!("Invalid value for {}::{}: {} > {}", "Foo", "f", self.f, 0xf); - } - let value = self.e | ((self.f as u16) << 12); - buffer.put_u16_le(value); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 7 - } -} diff --git a/tools/pdl/tests/generated_files_compile.sh b/tools/pdl/tests/generated_files_compile.sh deleted file mode 100755 index 583abac8337dabdff0cfc7341c757ad84d6b5a48..0000000000000000000000000000000000000000 --- a/tools/pdl/tests/generated_files_compile.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2023 Google LLC -# -# 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 -# -# https://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. - -# Run this script with a number of Rust files as input. It will combine them to -# a single file which you can compile to check the validity of the inputs. -# -# For a Cargo based workflow, you can run -# -# ./generated_files_compile.sh generated/*.rs > generated_files.rs -# -# followed by cargo test. - -for input_path in "$@"; do - echo "mod $(basename -s .rs "$input_path") {" - cat "$input_path" - echo "}" -done - -cat < "${pdl_OUTPUT_ABSOLUTE}" COMMENT "Generating rust module from ${pdl_INPUT}" VERBATIM - DEPENDS pdl ${pdl_INPUT_ABSOLUTE}) - endif() -endfunction() - -# ~~~ -# ! foobar : Compile .pdl files to C++/Rust! -# -# This function allows you to compile a set of .pdl files -# to rust or C++. It will generate a set of headers and -# sources. -# -# :GENERATED: The set of sources that are generated. -# Add these sources to the library you are building -# :SRC: The set of .pdl files to be compiled. -# :INCLUDES: Include directory used when generating sources. -# :LANG: Optional parameter indicating which language to use, -# either rust or c++, defaults to c++ -# :NAMESPACE: Root name space to use for the generated c++ classes. -# :OUTPUT_DIR: Optional paramater of the directory where the generated -# sources will be placed, defaults to CMAKE_CURRENT_BINARY_DIR/gens -# :SOURCE_DIR: Root directory where sources can be found, -# defaults to CMAKE_CURRENT_SOURCE_DIR -# ~~~ -function(android_bluetooth_packet_gen) - # Parse arguments - set(options) - set(oneValueArgs OUTPUT_DIR GENERATED SOURCE_DIR INCLUDES NAMESPACE LANG) - set(multiValueArgs SRC) - cmake_parse_arguments(packet_gen "${options}" "${oneValueArgs}" - "${multiValueArgs}" ${ARGN}) - - if(NOT packet_gen_OUTPUT_DIR) - set(packet_gen_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/packet_gen) - endif() - - if(packet_gen_NAMESPACE) - set(packet_gen_NAMESPACE "--root_namespace=${packet_gen_NAMESPACE}") - endif() - - if(NOT packet_gen_SOURCE_DIR) - set(packet_gen_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + DEPENDS pdlc ${pdl_INPUT_ABSOLUTE}) endif() - if(NOT packet_gen_SRC) - message( - FATAL_ERROR - "Error: android_packet_gen_compile() called without any .yy files") - return() - endif() - - set(SUFFIX_GEN "h") - - if(packet_gen_LANG STREQUAL "rust") - set(SUFFIX_GEN "rs") - set(packet_gen_LANG "--rust") - endif() + if(pdl_LANG STREQUAL "c++") + if(NOT pdl_NAMESPACE) + message(FATAL_ERROR "Error: namespace not specified") + endif() - # Configure packet_gen - android_compile_for_host( - bluetooth_packetgen ${ANDROID_QEMU2_TOP_DIR}/android/bluetooth/packet_gen - bluetooth_packetgen_EXECUTABLE) + foreach(namespace ${pdl_USING}) + list(APPEND pdl_FLAGS --using-namespace) + list(APPEND pdl_FLAGS ${namespace}) + endforeach() + foreach(header ${pdl_INCLUDE}) + list(APPEND pdl_FLAGS --include-header) + list(APPEND pdl_FLAGS ${header}) + endforeach() - set(BLUE_GEN "") - file(MAKE_DIRECTORY ${packet_gen_OUTPUT_DIR}) + add_custom_command( + OUTPUT "${pdl_OUTPUT_ABSOLUTE}.json" + COMMAND + ${pdlc_EXECUTABLE} + --output-format json + "${pdl_INPUT_ABSOLUTE}" + > "${pdl_OUTPUT_ABSOLUTE}.json" + COMMENT "Analyzing ${pdl_INPUT}" + VERBATIM + DEPENDS pdlc ${pdl_INPUT_ABSOLUTE}) - foreach(FIL ${packet_gen_SRC}) - get_filename_component( - ABS_FIL ${packet_gen_SOURCE_DIR}/${packet_gen_INCLUDES}/${FIL} ABSOLUTE) - get_filename_component(FIL_WE ${FIL} NAME_WE) - get_filename_component(FIL_DIR ${FIL} DIRECTORY) - set(FIL_GEN "${packet_gen_OUTPUT_DIR}/${FIL_DIR}/${FIL_WE}.${SUFFIX_GEN}") add_custom_command( - OUTPUT "${FIL_GEN}" - COMMAND - ${bluetooth_packetgen_EXECUTABLE} ${packet_gen_NAMESPACE} - "--include=${packet_gen_INCLUDES}" "--out=${packet_gen_OUTPUT_DIR}" - ${packet_gen_INCLUDES}/${FIL} ${packet_gen_LANG} - COMMENT "Creating bluetooth packet headers from ${ABS_FIL}" - WORKING_DIRECTORY ${packet_gen_SOURCE_DIR} - VERBATIM - DEPENDS ${bluetooth_packetgen_EXECUTABLE} ${ABS_FIL}) - list(APPEND BLUE_GEN ${FIL_GEN}) - set_source_files_properties(${FIL_GEN} PROPERTIES GENERATED TRUE) - endforeach() - - # Make the library available - if(packet_gen_GENERATED) - set(${packet_gen_GENERATED} "${BLUE_GEN}" PARENT_SCOPE) + OUTPUT "${pdl_OUTPUT_ABSOLUTE}" + COMMAND + ${PDL_ROOT}/scripts/generate_cxx_backend.py + --input "${pdl_OUTPUT_ABSOLUTE}.json" + --output "${pdl_OUTPUT_ABSOLUTE}" + --namespace ${pdl_NAMESPACE} + ${pdl_FLAGS} + COMMENT "Generating c++ header from ${pdl_INPUT}" + VERBATIM + DEPENDS pdlc ${pdl_OUTPUT_ABSOLUTE}.json) endif() -endfunction() -android_bluetooth_packet_gen( - GENERATED BluetoothGeneratedPackets_h INCLUDES tools/rootcanal/packets - SRC hci/hci_packets.pdl SOURCE_DIR ${BT_ROOT}/..) + add_custom_target("pdl_gen-${pdl_NAME}" DEPENDS ${pdl_OUTPUT_ABSOLUTE}) +endfunction() -android_bluetooth_packet_gen( - GENERATED RootCanalGeneratedPackets_h INCLUDES tools/rootcanal NAMESPACE model - SRC packets/link_layer_packets.pdl SOURCE_DIR ${BT_ROOT}/..) +pdl_gen( + NAME BluetoothGeneratedPackets_h + INPUT ${ROOTCANAL_ROOT}/packets/hci_packets.pdl + OUTPUT packets/hci_packets.h + LANG c++ + NAMESPACE "bluetooth::hci" + INCLUDE "hci/address.h") + +pdl_gen( + NAME RootCanalGeneratedPackets_h + INPUT ${ROOTCANAL_ROOT}/packets/link_layer_packets.pdl + OUTPUT packets/link_layer_packets.h + LANG c++ + NAMESPACE model::packets + INCLUDE "hci/address.h" + USING "bluetooth::hci") + +pdl_gen( + NAME RootCanalGeneratedPackets_rs + INPUT ${ROOTCANAL_ROOT}/packets/link_layer_packets.pdl + OUTPUT link_layer_packets.rs + LANG rust) android_add_library( TARGET libscriptedbeaconpayload-protos-lite LICENSE Apache-2.0 @@ -188,14 +157,14 @@ android_add_library( protobuf_generate_with_plugin( TARGET librootcanal_config - PROTOS ${ROOTCANAL_ROOT}/config.proto + PROTOS ${ROOTCANAL_ROOT}/proto/rootcanal/configuration.proto APPEND_PATH PROTOPATH -I${AOSP_ROOT}/external/protobuf/src - PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/config) + PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/proto/rootcanal) target_include_directories( librootcanal_config - PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/config ${AOSP_ROOT}/external/protobuf/src) + PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/proto ${AOSP_ROOT}/external/protobuf/src) target_link_libraries(librootcanal_config PRIVATE protobuf::libprotobuf) @@ -205,32 +174,19 @@ target_include_directories(libbt-rootcanal.headers INTERFACE ${ROOTCANAL_ROOT}) target_link_libraries(libbt-rootcanal.headers INTERFACE android-emu-base-headers) android_license(TARGET "libbt-rootcanal.headers" LIBNAME None SPDX Apache-2.0 - LICENSE Apache-2.0 LOCAL "${BT_ROOT}/../NOTICE") + LICENSE Apache-2.0 LOCAL "${BT_ROOT}/NOTICE") android_add_library( - TARGET BluetoothPacketSources + TARGET librootcanal_log LICENSE Apache-2.0 - SOURCE_DIR ${BT_ROOT}/gd/packet - SRC bit_inserter.cc - byte_inserter.cc - byte_observer.cc - fragmenting_inserter.cc - iterator.cc - packet_view.cc - raw_builder.cc - view.cc - DEPS android-emu-base android-emu-base-headers) + SOURCE_DIR ${ROOTCANAL_ROOT} + SRC lib/log.cc + ${AOSP_ROOT}/external/fmtlib/src/format.cc) target_include_directories( - BluetoothPacketSources PUBLIC - ${ROOTCANAL_ROOT}/emulator - ${ROOTCANAL_ROOT}/emulator/include + librootcanal_log PUBLIC ${ROOTCANAL_ROOT}/include - ${BT_ROOT}/gd - ${BT_ROOT}) - -target_compile_options(BluetoothPacketSources - PUBLIC -Wno-inconsistent-missing-override) + ${AOSP_ROOT}/external/fmtlib/include) android_add_library( TARGET libbt-rootcanal @@ -238,19 +194,18 @@ android_add_library( SOURCE_DIR ${ROOTCANAL_ROOT} SRC ${BluetoothGeneratedPackets_h} ${RootCanalGeneratedPackets_h} - emulator/src/log.cc lib/crypto/crypto.cc lib/hci/address.cc - lib/hci/class_of_device.cc lib/hci/pcap_filter.cc + lib/log.cc model/controller/acl_connection.cc model/controller/acl_connection_handler.cc model/controller/controller_properties.cc model/controller/dual_mode_controller.cc - model/controller/isochronous_connection_handler.cc model/controller/le_advertiser.cc model/controller/link_layer_controller.cc model/controller/sco_connection.cc + model/controller/vendor_commands/le_apcf.cc model/devices/beacon.cc model/devices/beacon_swarm.cc model/devices/device.cc @@ -260,7 +215,6 @@ android_add_library( model/devices/sniffer.cc model/hci/h4_data_channel_packetizer.cc model/hci/h4_parser.cc - model/hci/hci_protocol.cc model/hci/hci_sniffer.cc model/hci/hci_socket_transport.cc model/setup/device_boutique.cc @@ -278,20 +232,20 @@ android_add_library( DEPS android-emu-base android-emu-base-headers android-emu-base-logging - BluetoothPacketSources crypto librootcanal_config libscriptedbeaconpayload-protos-lite) +target_link_libraries( + libbt-rootcanal + PUBLIC librootcanal_log) + target_include_directories( libbt-rootcanal - PUBLIC ${ROOTCANAL_ROOT}/emulator - ${ROOTCANAL_ROOT}/emulator/include - ${ROOTCANAL_ROOT}/include + PUBLIC ${ROOTCANAL_ROOT}/include ${ROOTCANAL_ROOT} - ${BT_ROOT}/gd - ${BT_ROOT} - ${CMAKE_CURRENT_BINARY_DIR}/packet_gen + ${PDL_ROOT}/scripts + ${CMAKE_CURRENT_BINARY_DIR}/pdl_gen ${CMAKE_CURRENT_BINARY_DIR}/config) target_compile_options(libbt-rootcanal diff --git a/tools/rootcanal/config.proto b/tools/rootcanal/config.proto deleted file mode 100644 index 11a447dc8b1bfafc85c222b283d703e929219597..0000000000000000000000000000000000000000 --- a/tools/rootcanal/config.proto +++ /dev/null @@ -1,54 +0,0 @@ -syntax = "proto2"; - -package rootcanal.configuration; -option optimize_for = CODE_SIZE; - -enum ControllerPreset { - // Version 5.3, all features enabled, all quirks disabled. - DEFAULT = 0; -} - -message ControllerFeatures { - optional bool le_extended_advertising = 1; - optional bool le_periodic_advertising = 2; - optional bool ll_privacy = 3; - optional bool le_2m_phy = 4; - optional bool le_coded_phy = 5; -} - -message ControllerQuirks { - // Randomly send ACL payloads before the Connection Complete event - // is sent to the Host stack. - optional bool send_acl_data_before_connection_complete = 1; - // Configure a default value for the LE random address. - optional bool has_default_random_address = 2; - // Send the Role Change event before the Connection Complete event - // in the case where a role switch is initiated at connection establishment. - optional bool send_role_change_before_connection_complete = 3; - // Send an Hardware Error event if any command is called before HCI Reset. - optional bool hardware_error_before_reset = 4; -} - -message Controller { - // Configure the controller preset. Presets come with a pre-selection - // of features and quirks, but these can be overridden with the next fields. - optional ControllerPreset preset = 1; - // Configure support for controller features. - optional ControllerFeatures features = 2; - // Enable controller quirks. - // Quirks are behaviors observed in real controllers that are not valid - // according to the specification. - optional ControllerQuirks quirks = 3; -} - -message TcpServer { - // Configure the TCP port on which the controller with this defined - // configuration will be served. - required int32 tcp_port = 1; - // Controller configuration for this port. - optional Controller configuration = 2; -} - -message Configuration { - repeated TcpServer tcp_server = 1; -} diff --git a/tools/rootcanal/desktop/root_canal_main.cc b/tools/rootcanal/desktop/root_canal_main.cc index 8d7ebac70cbaead7b7c138217abac164c8a9b56f..20be4b90809a1522cd6752c930bcc0d61a0af1a7 100644 --- a/tools/rootcanal/desktop/root_canal_main.cc +++ b/tools/rootcanal/desktop/root_canal_main.cc @@ -33,16 +33,18 @@ #include "net/posix/posix_async_socket_server.h" #include "test_environment.h" -using ::android::bluetooth::root_canal::TestEnvironment; using ::android::net::PosixAsyncSocketConnector; using ::android::net::PosixAsyncSocketServer; using rootcanal::AsyncManager; +using rootcanal::TestEnvironment; +using namespace rootcanal; DEFINE_string(controller_properties_file, "", "deprecated"); DEFINE_string(configuration, "", "controller configuration (see config.proto)"); DEFINE_string(configuration_file, "", "controller configuration file path (see config.proto)"); DEFINE_string(default_commands_file, "", "deprecated"); +DEFINE_bool(enable_log_color, false, "enable log colors"); DEFINE_bool(enable_hci_sniffer, false, "enable hci sniffer"); DEFINE_bool(enable_baseband_sniffer, false, "enable baseband sniffer"); DEFINE_bool(enable_pcap_filter, false, "enable PCAP filter"); @@ -67,20 +69,20 @@ bool crash_callback(const void* crash_context, size_t crash_context_size, crash_context); tid = ctx->tid; int signal_number = ctx->siginfo.si_signo; - LOG_ERROR("Process crashed, signal: %s[%d], tid: %d", - strsignal(signal_number), signal_number, ctx->tid); + ERROR("Process crashed, signal: {}[{}], tid: {}", strsignal(signal_number), + signal_number, ctx->tid); } else { - LOG_ERROR("Process crashed, signal: unknown, tid: unknown"); + ERROR("Process crashed, signal: unknown, tid: unknown"); } unwindstack::AndroidLocalUnwinder unwinder; unwindstack::AndroidUnwinderData data; if (!unwinder.Unwind(tid, data)) { - LOG_ERROR("Unwind failed"); + ERROR("Unwind failed"); return false; } - LOG_ERROR("Backtrace:"); + ERROR("Backtrace:"); for (const auto& frame : data.frames) { - LOG_ERROR("%s", unwinder.FormatFrame(frame).c_str()); + ERROR("{}", unwinder.FormatFrame(frame)); } return true; } @@ -93,27 +95,27 @@ int main(int argc, char** argv) { eh.set_crash_handler(crash_callback); gflags::ParseCommandLineFlags(&argc, &argv, true); - android::base::InitLogging(argv); + rootcanal::log::SetLogColorEnable(FLAGS_enable_log_color); - LOG_INFO("main"); + INFO("starting rootcanal"); if (FLAGS_test_port > UINT16_MAX) { - LOG_ERROR("test_port out of range: %" PRIu32, FLAGS_test_port); + ERROR("test_port out of range: {}", FLAGS_test_port); return -1; } if (FLAGS_hci_port > UINT16_MAX) { - LOG_ERROR("hci_port out of range: %" PRIu32, FLAGS_hci_port); + ERROR("hci_port out of range: {}", FLAGS_hci_port); return -1; } if (FLAGS_link_port > UINT16_MAX) { - LOG_ERROR("link_port out of range: %" PRIu32, FLAGS_link_port); + ERROR("link_port out of range: {}", FLAGS_link_port); return -1; } if (FLAGS_link_ble_port > UINT16_MAX) { - LOG_ERROR("link_ble_port out of range: %" PRIu32, FLAGS_link_ble_port); + ERROR("link_ble_port out of range: {}", FLAGS_link_ble_port); return -1; } diff --git a/tools/rootcanal/desktop/test_environment.cc b/tools/rootcanal/desktop/test_environment.cc index fd3320d8c619b80888b7fd100d8398e65431ae47..59e093bcd7e1d56e0bbb7c3806ce62ddfb32696d 100644 --- a/tools/rootcanal/desktop/test_environment.cc +++ b/tools/rootcanal/desktop/test_environment.cc @@ -14,26 +14,38 @@ // limitations under the License. // -#include "test_environment.h" +#include "desktop/test_environment.h" #include -#include // for exists -#include // for remove_extent_t -#include // for move -#include // for vector - -#include "log.h" // for LOG_INFO, LOG_ERROR, LOG_WARN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hci/pcap_filter.h" +#include "log.h" +#include "model/controller/controller_properties.h" #include "model/devices/baseband_sniffer.h" -#include "model/devices/link_layer_socket_device.h" // for LinkLayerSocketDevice -#include "model/hci/hci_sniffer.h" // for HciSniffer -#include "model/hci/hci_socket_transport.h" // for HciSocketTransport -#include "net/async_data_channel.h" // for AsyncDataChannel -#include "net/async_data_channel_connector.h" // for AsyncDataChannelConnector - -namespace android { -namespace bluetooth { -namespace root_canal { +#include "model/devices/device.h" +#include "model/devices/hci_device.h" +#include "model/devices/link_layer_socket_device.h" +#include "model/hci/hci_sniffer.h" +#include "model/hci/hci_socket_transport.h" +#include "model/setup/async_manager.h" +#include "model/setup/test_channel_transport.h" +#include "net/async_data_channel.h" +#include "net/async_data_channel_connector.h" +#include "phy.h" +#include "rootcanal/configuration.pb.h" + +namespace rootcanal { using rootcanal::AsyncTaskId; using rootcanal::BaseBandSniffer; @@ -59,7 +71,7 @@ TestEnvironment::TestEnvironment( link_socket_server_ = open_server(&async_manager_, link_port); link_ble_socket_server_ = open_server(&async_manager_, link_ble_port); connector_ = open_connector(&async_manager_); - test_model_.SetReuseDeviceIds(!disable_address_reuse); + test_model_.SetReuseDeviceAddresses(!disable_address_reuse); // Get a user ID for tasks scheduled within the test environment. socket_user_id_ = async_manager_.GetNextUserId(); @@ -90,7 +102,7 @@ void TestEnvironment::SetUpHciServer( std::function(AsyncManager*, int)> open_server, int tcp_port, rootcanal::ControllerProperties properties) { - LOG_INFO("Opening an HCI with port %d", tcp_port); + INFO("Opening an HCI with port {}", tcp_port); std::shared_ptr server = open_server(&async_manager_, tcp_port); @@ -135,7 +147,7 @@ void TestEnvironment::SetUpHciServer( } void TestEnvironment::initialize(std::promise barrier) { - LOG_INFO("Initialized barrier"); + INFO("Initialized barrier"); barrier_ = std::move(barrier); @@ -169,11 +181,11 @@ void TestEnvironment::initialize(std::promise barrier) { Phy::Type::BR_EDR); } - LOG_INFO("%s: Finished", __func__); + INFO("{}: Finished", __func__); } void TestEnvironment::close() { - LOG_INFO("%s", __func__); + INFO("{}", __func__); test_model_.Reset(); } @@ -214,10 +226,10 @@ void TestEnvironment::SetUpTestChannel() { bool transport_configured = test_channel_transport_.SetUp( test_socket_server_, [this](std::shared_ptr conn_fd, AsyncDataChannelServer* server) { - LOG_INFO("Test channel connection accepted."); + INFO("Test channel connection accepted."); server->StartListening(); if (test_channel_open_) { - LOG_WARN("Only one connection at a time is supported"); + WARNING("Only one connection at a time is supported"); rootcanal::TestChannelTransport::SendResponse( conn_fd, "The connection is broken"); return false; @@ -245,13 +257,11 @@ void TestEnvironment::SetUpTestChannel() { test_channel_.StartTimer({}); if (!transport_configured) { - LOG_ERROR("Test channel SetUp failed."); + ERROR("Test channel SetUp failed."); return; } - LOG_INFO("Test channel SetUp() successful"); + INFO("Test channel SetUp() successful"); } -} // namespace root_canal -} // namespace bluetooth -} // namespace android +} // namespace rootcanal diff --git a/tools/rootcanal/desktop/test_environment.h b/tools/rootcanal/desktop/test_environment.h index 2658aaf4e2b922b690e912d7d93a8b92b2b8afb6..5947d075714a06224fc0ce367da1db21a84d4058 100644 --- a/tools/rootcanal/desktop/test_environment.h +++ b/tools/rootcanal/desktop/test_environment.h @@ -16,26 +16,26 @@ #pragma once -#include // for milliseconds -#include // for __base, function -#include // for promise -#include // for shared_ptr, make_... -#include // for string - -#include "model/setup/async_manager.h" // for AsyncTaskId, Asyn... -#include "model/setup/test_channel_transport.h" // for TestChannelTransport -#include "model/setup/test_command_handler.h" // for TestCommandHandler -#include "model/setup/test_model.h" // for TestModel -#include "net/async_data_channel_server.h" // for AsyncDataChannelS... - -namespace android { -namespace net { +#include +#include +#include +#include +#include +#include + +#include "model/controller/controller_properties.h" +#include "model/setup/async_manager.h" +#include "model/setup/test_channel_transport.h" +#include "model/setup/test_command_handler.h" +#include "model/setup/test_model.h" +#include "net/async_data_channel_server.h" + +namespace android::net { class AsyncDataChannel; class AsyncDataChannelConnector; -} // namespace net +} // namespace android::net -namespace bluetooth { -namespace root_canal { +namespace rootcanal { using android::net::AsyncDataChannel; using android::net::AsyncDataChannelConnector; @@ -115,6 +115,5 @@ class TestEnvironment { rootcanal::TestCommandHandler test_channel_{test_model_}; }; -} // namespace root_canal -} // namespace bluetooth -} // namespace android + +} // namespace rootcanal diff --git a/tools/rootcanal/emulator/include/log.h b/tools/rootcanal/emulator/include/log.h deleted file mode 100644 index d262ecd0f1547783f54ba9def26f8c33f3cf5e6f..0000000000000000000000000000000000000000 --- a/tools/rootcanal/emulator/include/log.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once -#include // for abort -#include // for shared_ptr -#include // for ostream -#include // for string_view - -#include "aemu/base/logging/LogSeverity.h" // for EMULATOR_LOG_INFO, EMULATOR_... - -#ifdef ANDROID_EMULATOR_BUILD -#include "android/utils/debug.h" // for __emu_log_print, VERBOSE_CHECK -#else -#include "aemu/base/logging/CLog.h" -#endif - -extern "C" void __blue_write_to_file(LogSeverity prio, - const char* file, - int line, - const char* fmt, - ...); - -namespace android::bluetooth { -// Gets a log stream that can be used to write logging information. -// The id can be used to uniquely identify the stream. If the id has -// already been used it will be prefixed by %d_ and a number. -std::shared_ptr getLogstream(std::string_view id); -} // namespace android::bluetooth - -// Note that we log both to a file as well as the emulator log system. -#ifdef ANDROID_EMULATOR_BUILD -#define LOGWRAPPER(level, fmt, args...) \ - do { \ - if (VERBOSE_CHECK(bluetooth)) { \ - __blue_write_to_file(level, __FILE__, __LINE__, fmt "", ##args); \ - __emu_log_print(level, __FILE__, __LINE__, fmt "", ##args); \ - } \ - } while (false) -#else -#define LOGWRAPPER(level, fmt, args...) \ - do { \ - __blue_write_to_file(level, __FILE__, __LINE__, fmt "", ##args); \ - __emu_log_print(level, __FILE__, __LINE__, fmt "", ##args); \ - } while (false) -#endif - -#define LOG_VERBOSE(fmt, args...) LOGWRAPPER(EMULATOR_LOG_VERBOSE, fmt, ##args); -#define LOG_DEBUG(fmt, args...) LOGWRAPPER(EMULATOR_LOG_DEBUG, fmt, ##args); -#define LOG_INFO(...) LOGWRAPPER(EMULATOR_LOG_INFO, __VA_ARGS__) -#define LOG_WARN(...) LOGWRAPPER(EMULATOR_LOG_WARNING, __VA_ARGS__) -#define LOG_ERROR(...) LOGWRAPPER(EMULATOR_LOG_ERROR, __VA_ARGS__) - -#ifndef LOG_ALWAYS_FATAL -#define LOG_ALWAYS_FATAL(...) \ - do { \ - __emu_log_print(EMULATOR_LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__); \ - std::abort(); \ - } while (false) -#endif - -#define ASSERT(condition) \ - do { \ - if (!(condition)) { \ - LOG_ALWAYS_FATAL("assertion '" #condition "' failed"); \ - } \ - } while (false) - -#define ASSERT_LOG(condition, fmt, args...) \ - do { \ - if (!(condition)) { \ - LOG_ALWAYS_FATAL("assertion '" #condition "' failed - " fmt, \ - ##args); \ - } \ - } while (false) - -#ifndef CASE_RETURN_TEXT -#define CASE_RETURN_TEXT(code) \ - case code: \ - return #code -#endif diff --git a/tools/rootcanal/emulator/src/log.cc b/tools/rootcanal/emulator/src/log.cc deleted file mode 100644 index 31f29326204b169e2c743c4a43903d60647e6243..0000000000000000000000000000000000000000 --- a/tools/rootcanal/emulator/src/log.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use connection 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 -#include -#include -#include -#include - -#include "aemu/base/files/PathUtils.h" -#include "aemu/base/logging/CLog.h" -#include "aemu/base/logging/LogFormatter.h" -#include "aemu/base/logging/LogSeverity.h" -#include "android/base/system/System.h" -#include "android/utils/path.h" - -static constexpr std::string_view BLUETOOTH_LOG{"bluetooth"}; -using android::base::System; -using android::base::VerboseLogFormatter; - -namespace android::bluetooth { -std::shared_ptr getLogstream(std::string_view id) { - auto basedir = android::base::pj( - {System::get()->getTempDir(), BLUETOOTH_LOG.data(), - std::to_string(System::get()->getCurrentProcessId())}); - - if (path_mkdir_if_needed(basedir.c_str(), 0700) != 0) { - dfatal("Unable to create bluetooth logging directory: %s", - basedir.c_str()); - } - std::string filename = android::base::pj(basedir, id.data()); - for (int i = 0; System::get()->pathExists(filename); i++) { - filename = android::base::pj(basedir, - std::to_string(i) + "_" + std::string(id)); - } - dinfo("Creating bluetooth log: %s", filename.c_str()); - - return std::make_shared(filename, std::ios::binary); -} -} // namespace android::bluetooth - -extern "C" void __blue_write_to_file(LogSeverity prio, - const char* file, - int line, - const char* fmt, - ...) { - static VerboseLogFormatter formatter; - static std::shared_ptr logStream = - android::bluetooth::getLogstream("rootcanal.log"); - va_list args; - va_start(args, fmt); - std::string msg = formatter.format({file, line, prio}, fmt, args); - va_end(args); - - if (!msg.empty()) { - if (msg.back() == '\n') { - *logStream << msg; - } else { - *logStream << msg << std::endl; - } - } -} diff --git a/system/test/rootcanal/Android.bp b/tools/rootcanal/hal/Android.bp similarity index 75% rename from system/test/rootcanal/Android.bp rename to tools/rootcanal/hal/Android.bp index 99caf40608fb5e29ea1aec1899b12bcce63fb52f..f211b70b9cc22988d1c2bb0f192d7267babdcf9b 100644 --- a/system/test/rootcanal/Android.bp +++ b/tools/rootcanal/hal/Android.bp @@ -24,10 +24,7 @@ package { cc_binary { name: "android.hardware.bluetooth@1.1-service.sim", - defaults: [ - "gd_defaults", - "libchrome_support_defaults", - ], + defaults: ["rootcanal_defaults"], proprietary: true, relative_install_path: "hw", srcs: [ @@ -37,7 +34,6 @@ cc_binary { visibility: [ "//platform_testing/libraries/sts-common-util/host-side/rootcanal", ], - header_libs: ["libbluetooth_headers"], shared_libs: [ "android.hardware.bluetooth@1.0", "android.hardware.bluetooth@1.1", @@ -45,7 +41,6 @@ cc_binary { "libcrypto", "libcutils", "libhidlbase", - "libjsoncpp", "liblog", "libprotobuf-cpp-full", "libutils", @@ -53,9 +48,6 @@ cc_binary { cflags: [ "-fvisibility=hidden", ], - generated_headers: [ - "libbt_init_flags_bridge_header", - ], whole_static_libs: [ "libbt-rootcanal", ], @@ -64,20 +56,12 @@ cc_binary { "android.hardware.bluetooth-hci", "libscriptedbeaconpayload-protos-lite", ], - include_dirs: [ - "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/internal_include", - "packages/modules/Bluetooth/system/stack/include", - ], init_rc: ["android.hardware.bluetooth@1.1-service.sim.rc"], } cc_library_shared { name: "android.hardware.bluetooth@1.1-impl-sim", - defaults: [ - "gd_defaults", - "libchrome_support_defaults", - ], + defaults: ["rootcanal_defaults"], proprietary: true, relative_install_path: "hw", srcs: [ @@ -86,7 +70,6 @@ cc_library_shared { visibility: [ "//platform_testing/libraries/sts-common-util/host-side/rootcanal", ], - header_libs: ["libbluetooth_headers"], shared_libs: [ "android.hardware.bluetooth@1.0", "android.hardware.bluetooth@1.1", @@ -94,14 +77,10 @@ cc_library_shared { "libcrypto", "libcutils", "libhidlbase", - "libjsoncpp", "liblog", "libprotobuf-cpp-full", "libutils", ], - generated_headers: [ - "libbt_init_flags_bridge_header", - ], whole_static_libs: [ "libbt-rootcanal", ], @@ -110,9 +89,4 @@ cc_library_shared { "android.hardware.bluetooth-hci", "libscriptedbeaconpayload-protos-lite", ], - include_dirs: [ - "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/internal_include", - "packages/modules/Bluetooth/system/stack/include", - ], } diff --git a/system/test/rootcanal/android.hardware.bluetooth@1.1-service.sim.rc b/tools/rootcanal/hal/android.hardware.bluetooth@1.1-service.sim.rc similarity index 100% rename from system/test/rootcanal/android.hardware.bluetooth@1.1-service.sim.rc rename to tools/rootcanal/hal/android.hardware.bluetooth@1.1-service.sim.rc diff --git a/system/test/rootcanal/bluetooth_hci.cc b/tools/rootcanal/hal/bluetooth_hci.cc similarity index 99% rename from system/test/rootcanal/bluetooth_hci.cc rename to tools/rootcanal/hal/bluetooth_hci.cc index bab7be11395584c38b0a4d05e3f9f1a8c9e80086..d63b870843b3a9418e9f51452e457cd1a42bb7cf 100644 --- a/system/test/rootcanal/bluetooth_hci.cc +++ b/tools/rootcanal/hal/bluetooth_hci.cc @@ -69,7 +69,7 @@ class BluetoothDeathRecipient : public hidl_death_recipient { void setHasDied(bool has_died) { has_died_ = has_died; } private: - bool has_died_; + bool has_died_{false}; }; BluetoothHci::BluetoothHci() diff --git a/system/test/rootcanal/bluetooth_hci.h b/tools/rootcanal/hal/bluetooth_hci.h similarity index 100% rename from system/test/rootcanal/bluetooth_hci.h rename to tools/rootcanal/hal/bluetooth_hci.h diff --git a/system/test/rootcanal/service.cc b/tools/rootcanal/hal/service.cc similarity index 100% rename from system/test/rootcanal/service.cc rename to tools/rootcanal/hal/service.cc diff --git a/tools/rootcanal/include/hci/address.h b/tools/rootcanal/include/hci/address.h index 5c20295ea9d091c3d5f84a97ac61ecc4bc6f6524..74f93907229ed6e09f8d8ac26c7b40983585d189 100644 --- a/tools/rootcanal/include/hci/address.h +++ b/tools/rootcanal/include/hci/address.h @@ -1,36 +1,37 @@ -/****************************************************************************** +/* + * Copyright 2022 The Android Open Source Project * - * Copyright 2022 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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 * - * 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. - * - ******************************************************************************/ + * 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 +#include + #include +#include #include +#include #include #include #include #include +#include -#include "packet/custom_field_fixed_size_interface.h" +namespace bluetooth::hci { -namespace bluetooth { -namespace hci { - -class Address final : public packet::CustomFieldFixedSizeInterface
    { +class Address final : public pdl::packet::Builder { public: static constexpr size_t kLength = 6; @@ -45,10 +46,6 @@ class Address final : public packet::CustomFieldFixedSizeInterface
    { Address(const uint8_t (&address)[kLength]); Address(std::initializer_list l); - // CustomFieldFixedSizeInterface methods - inline uint8_t* data() override { return address.data(); } - inline const uint8_t* data() const override { return address.data(); } - // storage::Serializable methods std::string ToString() const; static std::optional
    FromString(const std::string& from); @@ -61,6 +58,17 @@ class Address final : public packet::CustomFieldFixedSizeInterface
    { bool operator!=(const Address& rhs) const { return !(*this == rhs); } bool IsEmpty() const { return *this == kEmpty; } + uint8_t* data() { return address.data(); } + uint8_t const* data() const { return address.data(); } + + // Packet parser interface. + static bool Parse(pdl::packet::slice& input, Address* output); + + // Packet builder interface. + size_t GetSize() const override { return kLength; } + void Serialize(std::vector& output) const override { + output.insert(output.end(), address.begin(), address.end()); + } // Converts |string| to Address and places it in |to|. If |from| does // not represent a Bluetooth address, |to| is not modified and this function @@ -82,8 +90,7 @@ inline std::ostream& operator<<(std::ostream& os, const Address& a) { return os; } -} // namespace hci -} // namespace bluetooth +} // namespace bluetooth::hci namespace std { template <> @@ -98,3 +105,43 @@ struct hash { } }; } // namespace std + +template <> +struct fmt::formatter { + // Presentation format: 'x' - lowercase, 'X' - uppercase. + char presentation = 'x'; + + // Parses format specifications of the form ['x' | 'X']. + constexpr auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { + // Parse the presentation format and store it in the formatter: + auto it = ctx.begin(); + auto end = ctx.end(); + if (it != end && (*it == 'x' || *it == 'X')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + ctx.on_error("invalid format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + // Formats the address a using the parsed format specification (presentation) + // stored in this formatter. + auto format(const bluetooth::hci::Address& a, format_context& ctx) const + -> format_context::iterator { + return presentation == 'x' + ? fmt::format_to(ctx.out(), + "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + a.address[5], a.address[4], a.address[3], + a.address[2], a.address[1], a.address[0]) + : fmt::format_to(ctx.out(), + "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + a.address[5], a.address[4], a.address[3], + a.address[2], a.address[1], a.address[0]); + } +}; diff --git a/tools/rootcanal/include/hci/address_with_type.h b/tools/rootcanal/include/hci/address_with_type.h index b58d40a77dba4f903253d1efb569b633bd2afde6..01968b8c251492a70db444f414903dfe188f88e1 100644 --- a/tools/rootcanal/include/hci/address_with_type.h +++ b/tools/rootcanal/include/hci/address_with_type.h @@ -1,33 +1,37 @@ -/****************************************************************************** +/* + * Copyright 2018 The Android Open Source Project * - * Copyright 2022 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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 * - * 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. - * - ******************************************************************************/ + * 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 + +#include +#include +#include +#include +#include #include #include #include #include "crypto/crypto.h" #include "hci/address.h" -#include "hci/hci_packets.h" +#include "packets/hci_packets.h" -namespace bluetooth { -namespace hci { +namespace bluetooth::hci { class AddressWithType final { public: @@ -120,8 +124,7 @@ inline std::ostream& operator<<(std::ostream& os, const AddressWithType& a) { return os; } -} // namespace hci -} // namespace bluetooth +} // namespace bluetooth::hci namespace std { template <> @@ -136,3 +139,38 @@ struct hash { } }; } // namespace std + +template <> +struct fmt::formatter { + // Presentation format: 'x' - lowercase, 'X' - uppercase. + char presentation = 'x'; + + // Parses format specifications of the form ['x' | 'X']. + constexpr auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { + // Parse the presentation format and store it in the formatter: + auto it = ctx.begin(); + auto end = ctx.end(); + if (it != end && (*it == 'x' || *it == 'X')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + ctx.on_error("invalid format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + // Formats the address a using the parsed format specification (presentation) + // stored in this formatter. + auto format(const bluetooth::hci::AddressWithType& a, + format_context& ctx) const -> format_context::iterator { + auto out = presentation == 'x' + ? fmt::format_to(ctx.out(), "{:x}", a.GetAddress()) + : fmt::format_to(ctx.out(), "{:X}", a.GetAddress()); + return fmt::format_to(out, "[{}]", AddressTypeText(a.GetAddressType())); + } +}; diff --git a/tools/rootcanal/include/hci/pcap_filter.h b/tools/rootcanal/include/hci/pcap_filter.h index beac219cb636346111df1d81efe85f76fd15d3d4..1731ce866d311a5c7024b1c40fd8507011a2c5ee 100644 --- a/tools/rootcanal/include/hci/pcap_filter.h +++ b/tools/rootcanal/include/hci/pcap_filter.h @@ -1,26 +1,28 @@ -/****************************************************************************** +/* + * Copyright 2022 The Android Open Source Project * - * Copyright 2022 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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 * - * 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. - * - ******************************************************************************/ + * 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 +#include +#include +#include +#include +#include -#include +#include "packets/hci_packets.h" namespace rootcanal { @@ -50,7 +52,6 @@ class PcapFilter final { std::vector FilterHciCommand(std::vector const& packet); std::vector FilterHciEvent(std::vector const& packet); - private: // Specific filters for HCI commands. std::vector FilterWriteLocalName( bluetooth::hci::CommandView& command); @@ -66,10 +67,6 @@ class PcapFilter final { bluetooth::hci::CommandView& command); std::vector FilterLeSetPeriodicAdvertisingData( bluetooth::hci::CommandView& command); - std::vector FilterLeMultiAdvtSetData( - bluetooth::hci::LeMultiAdvtView& command); - std::vector FilterLeMultiAdvtSetScanResp( - bluetooth::hci::LeMultiAdvtView& command); // Specific filters for HCI events. std::vector FilterReadLocalNameComplete( @@ -87,9 +84,8 @@ class PcapFilter final { // Specific filter for any Gap data array. // The Gap data entries are modified in place. - void FilterGapData(std::vector& gap_data); - void FilterLengthAndData( - std::vector& gap_data); + void FilterGapData(uint8_t* gap_data, size_t gap_data_len); + void FilterGapData(std::vector& gap_data); // Helpers to replace local names. std::array ChangeDeviceName( @@ -97,6 +93,7 @@ class PcapFilter final { std::vector ChangeDeviceName( std::vector const& device_name); + private: // Map device names to anonymous replacements. std::vector, std::vector>> device_name_map{}; diff --git a/tools/rootcanal/include/log.h b/tools/rootcanal/include/log.h index f301a327491518a1975b5eb2df8dcd138e023147..130800ae9ace1b3d75fbf89222166ba4b0cce299 100644 --- a/tools/rootcanal/include/log.h +++ b/tools/rootcanal/include/log.h @@ -16,15 +16,71 @@ #pragma once -#include -#include - -// FIXME: remove those shims -#define LOG_DEBUG(...) LOG(DEBUG) << fmt::sprintf(__VA_ARGS__) -#define LOG_INFO(...) LOG(INFO) << fmt::sprintf(__VA_ARGS__) -#define LOG_WARN(...) LOG(WARNING) << fmt::sprintf(__VA_ARGS__) -#define LOG_ERROR(...) LOG(ERROR) << fmt::sprintf(__VA_ARGS__) -#define LOG_ALWAYS_FATAL(...) LOG(FATAL) << fmt::sprintf(__VA_ARGS__) - -#define ASSERT(cond) CHECK(cond) -#define ASSERT_LOG(cond, ...) CHECK(cond) << fmt::sprintf(__VA_ARGS__) +#include +#include +#include + +#include + +namespace rootcanal::log { + +enum Verbosity { + kDebug, + kInfo, + kWarning, + kError, + kFatal, +}; + +void SetLogColorEnable(bool); + +void VLog(Verbosity verb, char const* file, int line, + std::optional instance, char const* format, + fmt::format_args args); + +template +static void Log(Verbosity verb, char const* file, int line, int instance, + char const* format, const Args&... args) { + VLog(verb, file, line, instance, format, fmt::make_format_args(args...)); +} + +template +static void Log(Verbosity verb, char const* file, int line, char const* format, + const Args&... args) { + VLog(verb, file, line, {}, format, fmt::make_format_args(args...)); +} + +#define DEBUG(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kDebug, __FILE__, __LINE__, \ + __VA_ARGS__) + +#define INFO(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kInfo, __FILE__, __LINE__, \ + __VA_ARGS__) + +#define WARNING(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kWarning, __FILE__, __LINE__, \ + __VA_ARGS__) + +#define ERROR(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kError, __FILE__, __LINE__, \ + __VA_ARGS__) + +#define FATAL(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kFatal, __FILE__, __LINE__, \ + __VA_ARGS__) + +#define ASSERT(x) \ + __builtin_expect((x) != 0, true) || \ + (rootcanal::log::Log(rootcanal::log::Verbosity::kFatal, __FILE__, \ + __LINE__, "Check failed: {}", #x), \ + false) + +#define ASSERT_LOG(x, ...) \ + __builtin_expect((x) != 0, true) || \ + (rootcanal::log::Log(rootcanal::log::Verbosity::kFatal, __FILE__, \ + __LINE__, "Check failed: {}, {}", #x, \ + fmt::sprintf(__VA_ARGS__)), \ + false) + +} // namespace rootcanal::log diff --git a/tools/rootcanal/include/os/log.h b/tools/rootcanal/include/os/log.h index 2fbb07098117ff00c98fd2e398debb1a52595b49..a1e46ddeceba925c07ad8aba91a0f914d13bc2ca 100644 --- a/tools/rootcanal/include/os/log.h +++ b/tools/rootcanal/include/os/log.h @@ -18,3 +18,16 @@ // FIXME: Change hci_packets.h to not depend on os/log.h // and remove this. #include "include/log.h" + +#define LOG_INFO(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kInfo, __FILE__, __LINE__, \ + "{}", fmt::sprintf(__VA_ARGS__)) +#define LOG_WARN(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kWarning, __FILE__, __LINE__, \ + "{}", fmt::sprintf(__VA_ARGS__)) +#define LOG_ERROR(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kError, __FILE__, __LINE__, \ + "{}", fmt::sprintf(__VA_ARGS__)) +#define LOG_ALWAYS_FATAL(...) \ + rootcanal::log::Log(rootcanal::log::Verbosity::kFatal, __FILE__, __LINE__, \ + "{}", fmt::sprintf(__VA_ARGS__)) diff --git a/tools/rootcanal/include/phy.h b/tools/rootcanal/include/phy.h index 1fa82743ab777fcd90ecf93bf1a20c26ba9c640d..1e82c1515a2bd2cb3266aa9dafe659f3e6b4a360 100644 --- a/tools/rootcanal/include/phy.h +++ b/tools/rootcanal/include/phy.h @@ -25,4 +25,5 @@ class Phy { BR_EDR, }; }; + } // namespace rootcanal diff --git a/tools/rootcanal/lib/crypto/crypto.cc b/tools/rootcanal/lib/crypto/crypto.cc index 0477f6b8028ba8eddfc524a053beff5624eacf46..560416dbec984646752025c69211540978eeca91 100644 --- a/tools/rootcanal/lib/crypto/crypto.cc +++ b/tools/rootcanal/lib/crypto/crypto.cc @@ -1,10 +1,24 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "crypto/crypto.h" #include #include -#include namespace rootcanal::crypto { diff --git a/tools/rootcanal/lib/hci/address.cc b/tools/rootcanal/lib/hci/address.cc index 0bb5bc5e3f7877a7ee2d20f5331e591977df0f55..3f9103c80f8fdf9474f0b06de82c022fdf1e17d1 100644 --- a/tools/rootcanal/lib/hci/address.cc +++ b/tools/rootcanal/lib/hci/address.cc @@ -1,31 +1,38 @@ -/****************************************************************************** +/* + * Copyright 2018 The Android Open Source Project * - * Copyright 2022 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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 * - * 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. - * - ******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "hci/address.h" +#include + #include +#include #include #include +#include +#include #include +#include +#include +#include #include +#include +#include -namespace bluetooth { -namespace hci { +namespace bluetooth::hci { const Address Address::kAny{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; const Address Address::kEmpty{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -43,6 +50,20 @@ Address::Address(std::initializer_list l) { std::copy(l.begin(), std::min(l.begin() + kLength, l.end()), data()); } +bool Address::Parse(pdl::packet::slice& input, Address* output) { + if (input.size() < kLength) { + return false; + } + + std::array address{ + input.read_le(), input.read_le(), + input.read_le(), input.read_le(), + input.read_le(), input.read_le(), + }; + *output = Address(address); + return true; +} + std::string Address::ToString() const { std::stringstream ss; for (auto it = address.rbegin(); it != address.rend(); it++) { @@ -107,11 +128,10 @@ bool Address::FromString(const std::string& from, Address& to) { size_t Address::FromOctets(const uint8_t* from) { std::copy(from, from + kLength, data()); return kLength; -}; +} bool Address::IsValidAddress(const std::string& address) { return Address::FromString(address).has_value(); } -} // namespace hci -} // namespace bluetooth +} // namespace bluetooth::hci diff --git a/tools/rootcanal/lib/hci/pcap_filter.cc b/tools/rootcanal/lib/hci/pcap_filter.cc index bab0d9df551e9328b9928630aa1e568c9db56e9a..4a05da0fdddb1d74410b9887b790d5f271fa0066 100644 --- a/tools/rootcanal/lib/hci/pcap_filter.cc +++ b/tools/rootcanal/lib/hci/pcap_filter.cc @@ -1,36 +1,46 @@ -/****************************************************************************** +/* + * Copyright 2022 The Android Open Source Project * - * Copyright 2022 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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 * - * 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 -#include -#include + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hci/pcap_filter.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "packets/hci_packets.h" using namespace bluetooth::hci; -using namespace bluetooth::packet; namespace rootcanal { -static PacketView create_packet_view( +static pdl::packet::slice create_packet_view( std::vector const& packet) { // Wrap the reference to the packet in a shared_ptr with created // a no-op deleter. The packet view will be short lived so there is no // risk of the reference leaking. - return PacketView(std::shared_ptr const>( + return pdl::packet::slice(std::shared_ptr const>( &packet, [](std::vector const* /* ptr */) {})); } @@ -76,19 +86,6 @@ std::vector PcapFilter::FilterHciCommand( return FilterLeSetExtendedScanResponseData(command); case OpCode::LE_SET_PERIODIC_ADVERTISING_DATA: return FilterLeSetPeriodicAdvertisingData(command); - case OpCode::LE_MULTI_ADVT: { - auto le_multi_advt_command = LeMultiAdvtView::Create(command); - ASSERT(le_multi_advt_command.IsValid()); - switch (le_multi_advt_command.GetSubCmd()) { - case SubOcf::SET_DATA: - return FilterLeMultiAdvtSetData(le_multi_advt_command); - case SubOcf::SET_SCAN_RESP: - return FilterLeMultiAdvtSetScanResp(le_multi_advt_command); - default: - break; - } - break; - } default: break; } @@ -142,8 +139,7 @@ static std::vector FilterHciAcl(std::vector const& packet) { payload.resize(acl.GetPayload().size()); ASSERT(acl.IsValid()); return AclBuilder::Create(acl.GetHandle(), acl.GetPacketBoundaryFlag(), - acl.GetBroadcastFlag(), - std::make_unique(payload)) + acl.GetBroadcastFlag(), std::move(payload)) ->SerializeToBytes(); } @@ -162,47 +158,55 @@ static std::vector FilterHciIso(std::vector const& packet) { payload.resize(iso.GetPayload().size()); ASSERT(iso.IsValid()); return IsoBuilder::Create(iso.GetConnectionHandle(), iso.GetPbFlag(), - iso.GetTsFlag(), - std::make_unique(payload)) + iso.GetTsFlag(), std::move(payload)) ->SerializeToBytes(); } // Replace device names in GAP entries. -void PcapFilter::FilterGapData(std::vector& gap_data) { - for (GapData& entry : gap_data) { - switch (entry.data_type_) { - case GapDataType::COMPLETE_LOCAL_NAME: - case GapDataType::SHORTENED_LOCAL_NAME: - entry.data_ = ChangeDeviceName(entry.data_); - break; - default: - break; +// TODO: extended advertising reports can be chunked across multiple +// events, and a single GAP data entry can be segmented in two. +// The filter should account for that and keep a state for partial +// GAP entries. +void PcapFilter::FilterGapData(uint8_t* gap_data, size_t gap_data_len) { + size_t offset = 0; + while ((offset + 2) <= gap_data_len) { + size_t length = gap_data[offset]; + GapDataType data_type = static_cast(gap_data[offset + 1]); + + // Truncated entry. + if ((offset + length + 1) > gap_data_len) { + break; } - } -} -void PcapFilter::FilterLengthAndData( - std::vector& gap_data) { - for (LengthAndData& entry : gap_data) { - if (entry.data_.empty()) { + // Empty entry. + if (length == 0) { + offset += 1; continue; } - switch (GapDataType(entry.data_[0])) { + + // Apply the filter to entries that contain user data. + switch (data_type) { case GapDataType::COMPLETE_LOCAL_NAME: case GapDataType::SHORTENED_LOCAL_NAME: { - std::vector device_name(entry.data_.begin() + 1, - entry.data_.end()); - device_name = ChangeDeviceName(device_name); - entry.data_.insert(device_name.begin(), device_name.end(), - entry.data_.begin() + 1); + auto start_pos = gap_data + offset + 1; + auto end_pos = gap_data + offset + length; + std::vector new_name = + ChangeDeviceName(std::vector{start_pos, end_pos}); + std::copy(new_name.begin(), new_name.end(), start_pos); break; } default: break; } + + offset += length + 1; } } +void PcapFilter::FilterGapData(std::vector& gap_data) { + FilterGapData(gap_data.data(), gap_data.size()); +} + // Replace the local device name. std::vector PcapFilter::FilterWriteLocalName(CommandView& command) { auto parameters = WriteLocalNameView::Create(command); @@ -219,9 +223,10 @@ std::vector PcapFilter::FilterWriteExtendedInquiryResponse( auto parameters = WriteExtendedInquiryResponseView::Create(command); ASSERT(parameters.IsValid()); - std::vector extended_inquiry_response = + std::array extended_inquiry_response = parameters.GetExtendedInquiryResponse(); - FilterGapData(extended_inquiry_response); + FilterGapData(extended_inquiry_response.data(), + extended_inquiry_response.size()); return WriteExtendedInquiryResponseBuilder::Create( parameters.GetFecRequired(), extended_inquiry_response) ->SerializeToBytes(); @@ -233,7 +238,7 @@ std::vector PcapFilter::FilterLeSetAdvertisingData( auto parameters = LeSetAdvertisingDataView::Create(command); ASSERT(parameters.IsValid()); - std::vector advertising_data = parameters.GetAdvertisingData(); + std::vector advertising_data = parameters.GetAdvertisingData(); FilterGapData(advertising_data); return LeSetAdvertisingDataBuilder::Create(advertising_data) ->SerializeToBytes(); @@ -245,7 +250,7 @@ std::vector PcapFilter::FilterLeSetScanResponseData( auto parameters = LeSetScanResponseDataView::Create(command); ASSERT(parameters.IsValid()); - std::vector advertising_data = parameters.GetAdvertisingData(); + std::vector advertising_data = parameters.GetAdvertisingData(); FilterGapData(advertising_data); return LeSetScanResponseDataBuilder::Create(advertising_data) ->SerializeToBytes(); @@ -257,7 +262,7 @@ std::vector PcapFilter::FilterLeSetExtendedAdvertisingData( auto parameters = LeSetExtendedAdvertisingDataView::Create(command); ASSERT(parameters.IsValid()); - std::vector advertising_data = parameters.GetAdvertisingData(); + std::vector advertising_data = parameters.GetAdvertisingData(); FilterGapData(advertising_data); return LeSetExtendedAdvertisingDataBuilder::Create( parameters.GetAdvertisingHandle(), parameters.GetOperation(), @@ -272,7 +277,7 @@ std::vector PcapFilter::FilterLeSetExtendedScanResponseData( auto parameters = LeSetExtendedScanResponseDataView::Create(command); ASSERT(parameters.IsValid()); - std::vector advertising_data = parameters.GetScanResponseData(); + std::vector advertising_data = parameters.GetScanResponseData(); FilterGapData(advertising_data); return LeSetExtendedScanResponseDataBuilder::Create( parameters.GetAdvertisingHandle(), parameters.GetOperation(), @@ -287,7 +292,7 @@ std::vector PcapFilter::FilterLeSetPeriodicAdvertisingData( auto parameters = LeSetPeriodicAdvertisingDataView::Create(command); ASSERT(parameters.IsValid()); - std::vector advertising_data = parameters.GetAdvertisingData(); + std::vector advertising_data = parameters.GetAdvertisingData(); FilterGapData(advertising_data); return LeSetPeriodicAdvertisingDataBuilder::Create( parameters.GetAdvertisingHandle(), parameters.GetOperation(), @@ -295,32 +300,6 @@ std::vector PcapFilter::FilterLeSetPeriodicAdvertisingData( ->SerializeToBytes(); } -// Replace the device names in the GAP entries of the advertising data. -std::vector PcapFilter::FilterLeMultiAdvtSetData( - bluetooth::hci::LeMultiAdvtView& command) { - auto parameters = LeMultiAdvtSetDataView::Create(command); - ASSERT(parameters.IsValid()); - - std::vector advertising_data = parameters.GetAdvertisingData(); - FilterGapData(advertising_data); - return LeMultiAdvtSetDataBuilder::Create(advertising_data, - parameters.GetAdvertisingInstance()) - ->SerializeToBytes(); -} - -// Replace the device names in the GAP entries of the scan response data. -std::vector PcapFilter::FilterLeMultiAdvtSetScanResp( - bluetooth::hci::LeMultiAdvtView& command) { - auto parameters = LeMultiAdvtSetScanRespView::Create(command); - ASSERT(parameters.IsValid()); - - std::vector advertising_data = parameters.GetAdvertisingData(); - FilterGapData(advertising_data); - return LeMultiAdvtSetScanRespBuilder::Create( - advertising_data, parameters.GetAdvertisingInstance()) - ->SerializeToBytes(); -} - // Replace the local device name in the read local name complete event. std::vector PcapFilter::FilterReadLocalNameComplete( bluetooth::hci::CommandCompleteView& command_complete) { @@ -345,10 +324,11 @@ std::vector PcapFilter::FilterReadExtendedInquiryResponseComplete( ReadExtendedInquiryResponseCompleteView::Create(command_complete); ASSERT(parameters.IsValid()); - std::vector extended_inquiry_response = + std::array extended_inquiry_response = parameters.GetExtendedInquiryResponse(); if (parameters.GetStatus() == ErrorCode::SUCCESS) { - FilterGapData(extended_inquiry_response); + FilterGapData(extended_inquiry_response.data(), + extended_inquiry_response.size()); } return ReadExtendedInquiryResponseCompleteBuilder::Create( @@ -379,10 +359,10 @@ std::vector PcapFilter::FilterExtendedInquiryResult( auto parameters = ExtendedInquiryResultView::Create(event); ASSERT(parameters.IsValid()); - std::vector extended_inquiry_response = + std::array extended_inquiry_response = parameters.GetExtendedInquiryResponse(); - FilterGapData(extended_inquiry_response); - + FilterGapData(extended_inquiry_response.data(), + extended_inquiry_response.size()); return ExtendedInquiryResultBuilder::Create( parameters.GetAddress(), parameters.GetPageScanRepetitionMode(), parameters.GetClassOfDevice(), parameters.GetClockOffset(), @@ -398,7 +378,7 @@ std::vector PcapFilter::FilterLeAdvertisingReport( std::vector responses = parameters.GetResponses(); for (auto& response : responses) { - FilterLengthAndData(response.advertising_data_); + FilterGapData(response.advertising_data_); } return LeAdvertisingReportBuilder::Create(responses)->SerializeToBytes(); @@ -414,7 +394,7 @@ std::vector PcapFilter::FilterLeExtendedAdvertisingReport( std::vector responses = parameters.GetResponses(); for (auto& response : responses) { - FilterLengthAndData(response.advertising_data_); + FilterGapData(response.advertising_data_); } return LeExtendedAdvertisingReportBuilder::Create(responses) diff --git a/tools/rootcanal/lib/log.cc b/tools/rootcanal/lib/log.cc new file mode 100644 index 0000000000000000000000000000000000000000..9c78b16a3fc43cbbe3f3e6060cf7bf50a86f184c --- /dev/null +++ b/tools/rootcanal/lib/log.cc @@ -0,0 +1,106 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "log.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace rootcanal::log { + +// Enable flag for log styling. +static bool enable_log_color = true; + +void SetLogColorEnable(bool enable) { enable_log_color = enable; } + +static std::array verbosity_tag = {'D', 'I', 'W', 'E', 'F'}; + +static std::array text_style = { + fmt::fg(fmt::color::dim_gray), + fmt::fg(fmt::color::floral_white), + fmt::emphasis::bold | fmt::fg(fmt::color::yellow), + fmt::emphasis::bold | fmt::fg(fmt::color::orange_red), + fmt::emphasis::bold | fmt::fg(fmt::color::red), +}; + +static std::array text_color = { + fmt::color::cadet_blue, fmt::color::aquamarine, + fmt::color::indian_red, fmt::color::blue_violet, + fmt::color::chartreuse, fmt::color::medium_sea_green, + fmt::color::deep_pink, fmt::color::medium_orchid, + fmt::color::green_yellow, fmt::color::dark_orange, + fmt::color::golden_rod, fmt::color::medium_slate_blue, + fmt::color::coral, fmt::color::lemon_chiffon, + fmt::color::wheat, fmt::color::turquoise, +}; + +void VLog(Verbosity verb, char const* file, int line, + std::optional instance, char const* format, + fmt::format_args args) { + // Generate the time label. + auto now = std::chrono::system_clock::now(); + auto now_ms = std::chrono::time_point_cast(now); + auto now_t = std::chrono::system_clock::to_time_t(now); + char time_str[19]; // "mm-dd_HH:MM:SS.mmm\0" is 19 byte long + auto n = std::strftime(time_str, sizeof(time_str), "%m-%d %H:%M:%S", + std::localtime(&now_t)); + snprintf(time_str + n, sizeof(time_str) - n, ".%03u", + static_cast(now_ms.time_since_epoch().count() % 1000)); + + // Generate the file label. + char delimiter = '/'; + char const* file_name = ::strrchr(file, delimiter); + file_name = file_name == nullptr ? file : file_name + 1; + char file_str[40]; // file:line limited to 40 characters + snprintf(file_str, sizeof(file_str), "%.35s:%d", file_name, line); + + fmt::print("root-canal {} {} {:<35.35} ", verbosity_tag[verb], time_str, + file_str); + + if (instance.has_value() && enable_log_color) { + fmt::color instance_color = text_color[*instance % text_color.size()]; + fmt::print(fmt::bg(instance_color) | fmt::fg(fmt::color::black), " {:>2} ", + *instance); + fmt::print(" "); + } else if (instance.has_value()) { + fmt::print(" {:>2} ", *instance); + } else { + fmt::print(" "); + } + + if (enable_log_color) { + fmt::text_style style = text_style[verb]; + fmt::vprint(stdout, style, format, args); + } else { + fmt::vprint(stdout, format, args); + } + + fmt::print("\n"); + + if (verb == Verbosity::kFatal) { + std::abort(); + } +} + +} // namespace rootcanal::log diff --git a/tools/rootcanal/model/controller/acl_connection.cc b/tools/rootcanal/model/controller/acl_connection.cc index 2c47ad191dc760d3365d577a3af8b94e3f2f55de..33e4c36713d30f5072e26d0187f2215925a1c4fd 100644 --- a/tools/rootcanal/model/controller/acl_connection.cc +++ b/tools/rootcanal/model/controller/acl_connection.cc @@ -14,7 +14,13 @@ * limitations under the License. */ -#include "acl_connection.h" +#include "model/controller/acl_connection.h" + +#include +#include + +#include "packets/hci_packets.h" +#include "phy.h" namespace rootcanal { AclConnection::AclConnection(AddressWithType address, @@ -27,21 +33,17 @@ AclConnection::AclConnection(AddressWithType address, type_(phy_type), role_(role), last_packet_timestamp_(std::chrono::steady_clock::now()), - timeout_(std::chrono::seconds(1)) {} - -void AclConnection::Encrypt() { encrypted_ = true; }; + timeout_(std::chrono::seconds(3)) {} -bool AclConnection::IsEncrypted() const { return encrypted_; }; +void AclConnection::Encrypt() { encrypted_ = true; } -uint16_t AclConnection::GetLinkPolicySettings() const { - return link_policy_settings_; -}; +bool AclConnection::IsEncrypted() const { return encrypted_; } void AclConnection::SetLinkPolicySettings(uint16_t settings) { link_policy_settings_ = settings; } -bluetooth::hci::Role AclConnection::GetRole() const { return role_; }; +bluetooth::hci::Role AclConnection::GetRole() const { return role_; } void AclConnection::SetRole(bluetooth::hci::Role role) { role_ = role; } diff --git a/tools/rootcanal/model/controller/acl_connection.h b/tools/rootcanal/model/controller/acl_connection.h index 74bc9a700ab2ceeab58000999944ecad5222a6aa..86ba9513e44da5d4cae3c2d7bde097437b957e9b 100644 --- a/tools/rootcanal/model/controller/acl_connection.h +++ b/tools/rootcanal/model/controller/acl_connection.h @@ -20,12 +20,19 @@ #include #include "hci/address_with_type.h" +#include "packets/hci_packets.h" #include "phy.h" namespace rootcanal { using ::bluetooth::hci::AddressWithType; +enum AclConnectionState { + kActiveMode, + kHoldMode, + kSniffMode, +}; + // Model the connection of a device to the controller. class AclConnection { public: @@ -44,8 +51,15 @@ class AclConnection { void Encrypt(); bool IsEncrypted() const; - uint16_t GetLinkPolicySettings() const; void SetLinkPolicySettings(uint16_t settings); + uint16_t GetLinkPolicySettings() const { return link_policy_settings_; } + bool IsRoleSwitchEnabled() const { + return (link_policy_settings_ & 0x1) != 0; + } + bool IsHoldModeEnabled() const { return (link_policy_settings_ & 0x2) != 0; } + bool IsSniffModeEnabled() const { return (link_policy_settings_ & 0x4) != 0; } + + AclConnectionState GetMode() const { return state_; } bluetooth::hci::Role GetRole() const; void SetRole(bluetooth::hci::Role role); @@ -81,6 +95,7 @@ class AclConnection { // State variables bool encrypted_{false}; uint16_t link_policy_settings_{0}; + AclConnectionState state_{kActiveMode}; bluetooth::hci::Role role_{bluetooth::hci::Role::CENTRAL}; std::chrono::steady_clock::time_point last_packet_timestamp_; std::chrono::steady_clock::duration timeout_; diff --git a/tools/rootcanal/model/controller/acl_connection_handler.cc b/tools/rootcanal/model/controller/acl_connection_handler.cc index d310450b10ec26383bafe86d1bffd73aa81ee279..656c495b844cff9cea3b20b3549c41d24024e097 100644 --- a/tools/rootcanal/model/controller/acl_connection_handler.cc +++ b/tools/rootcanal/model/controller/acl_connection_handler.cc @@ -14,12 +14,22 @@ * limitations under the License. */ -#include "acl_connection_handler.h" +#include "model/controller/acl_connection_handler.h" -#include +#include +#include +#include +#include +#include +#include #include "hci/address.h" +#include "hci/address_with_type.h" #include "log.h" +#include "model/controller/acl_connection.h" +#include "model/controller/sco_connection.h" +#include "packets/hci_packets.h" +#include "phy.h" namespace rootcanal { @@ -46,8 +56,11 @@ bool AclConnectionHandler::HasScoHandle(uint16_t handle) const { } uint16_t AclConnectionHandler::GetUnusedHandle() { + // Keep a reserved range of handles for CIS connections implemented + // in the rust module. while (HasHandle(last_handle_) || HasScoHandle(last_handle_) || - isochronous_connection_handler_.HasHandle(last_handle_)) { + (last_handle_ >= kCisHandleRangeStart && + last_handle_ < kCisHandleRangeEnd)) { last_handle_ = (last_handle_ + 1) % kReservedHandle; } uint16_t unused_handle = last_handle_; @@ -58,7 +71,7 @@ uint16_t AclConnectionHandler::GetUnusedHandle() { bool AclConnectionHandler::CreatePendingConnection(Address addr, bool authenticate_on_connect, bool allow_role_switch) { - if (classic_connection_pending_) { + if (classic_connection_pending_ || GetAclConnectionHandle(addr).has_value()) { return false; } classic_connection_pending_ = true; @@ -93,18 +106,17 @@ bool AclConnectionHandler::CreatePendingLeConnection( auto connection = std::get(pair); if (connection.GetAddress() == peer || connection.GetResolvedAddress() == resolved_peer) { - LOG_INFO("%s: %s is already connected", __func__, - peer.ToString().c_str()); + INFO("{}: {} is already connected", __func__, peer); if (connection.GetResolvedAddress() == resolved_peer) { - LOG_INFO("%s: allowing a second connection with %s", __func__, - resolved_peer.ToString().c_str()); + INFO("{}: allowing a second connection with {}", __func__, + resolved_peer); } else { return false; } } } if (le_connection_pending_) { - LOG_INFO("%s: connection already pending", __func__); + INFO("{}: connection already pending", __func__); return false; } le_connection_pending_ = true; @@ -130,9 +142,9 @@ bool AclConnectionHandler::CancelPendingLeConnection(AddressWithType addr) { return true; } -uint16_t AclConnectionHandler::CreateConnection(Address addr, - Address own_addr) { - if (CancelPendingConnection(addr)) { +uint16_t AclConnectionHandler::CreateConnection(Address addr, Address own_addr, + bool pending) { + if (!pending || CancelPendingConnection(addr)) { uint16_t handle = GetUnusedHandle(); acl_connections_.emplace( handle, @@ -197,6 +209,17 @@ uint16_t AclConnectionHandler::GetHandleOnlyAddress( return kReservedHandle; } +std::optional AclConnectionHandler::GetAclConnectionHandle( + bluetooth::hci::Address bd_addr) const { + for (auto const& [handle, connection] : acl_connections_) { + if (connection.GetAddress().GetAddress() == bd_addr && + connection.GetPhyType() == Phy::Type::BR_EDR) { + return handle; + } + } + return {}; +} + AclConnection& AclConnectionHandler::GetAclConnection(uint16_t handle) { ASSERT_LOG(HasHandle(handle), "Unknown handle %d", handle); return acl_connections_.at(handle); @@ -262,7 +285,7 @@ Phy::Type AclConnectionHandler::GetPhyType(uint16_t handle) const { uint16_t AclConnectionHandler::GetAclLinkPolicySettings(uint16_t handle) const { return acl_connections_.at(handle).GetLinkPolicySettings(); -}; +} void AclConnectionHandler::SetAclLinkPolicySettings(uint16_t handle, uint16_t settings) { @@ -271,220 +294,13 @@ void AclConnectionHandler::SetAclLinkPolicySettings(uint16_t handle, bluetooth::hci::Role AclConnectionHandler::GetAclRole(uint16_t handle) const { return acl_connections_.at(handle).GetRole(); -}; +} void AclConnectionHandler::SetAclRole(uint16_t handle, bluetooth::hci::Role role) { acl_connections_.at(handle).SetRole(role); } -std::unique_ptr -AclConnectionHandler::SetCigParameters( - uint8_t id, uint32_t sdu_interval_m_to_s, uint32_t sdu_interval_s_to_m, - bluetooth::hci::ClockAccuracy /* accuracy */, - bluetooth::hci::Packing packing, bluetooth::hci::Enable framing, - uint16_t max_transport_latency_m_to_s, - uint16_t max_transport_latency_s_to_m, - std::vector& streams) { - std::vector handles; - GroupParameters group_parameters{ - .id = id, - .sdu_interval_m_to_s = sdu_interval_m_to_s, - .sdu_interval_s_to_m = sdu_interval_s_to_m, - .interleaved = packing == bluetooth::hci::Packing::INTERLEAVED, - .framed = framing == bluetooth::hci::Enable::ENABLED, - .max_transport_latency_m_to_s = max_transport_latency_m_to_s, - .max_transport_latency_s_to_m = max_transport_latency_s_to_m}; - std::vector stream_parameters; - for (size_t i = 0; i < streams.size(); i++) { - auto handle = GetUnusedHandle(); - StreamParameters a{.group_id = group_parameters.id, - .stream_id = streams[i].cis_id_, - .max_sdu_m_to_s = streams[i].max_sdu_m_to_s_, - .max_sdu_s_to_m = streams[i].max_sdu_s_to_m_, - .rtn_m_to_s = streams[i].rtn_m_to_s_, - .rtn_s_to_m = streams[i].rtn_s_to_m_, - .handle = handle}; - handles.push_back(handle); - stream_parameters.push_back(std::move(a)); - } - - return isochronous_connection_handler_.SetCigParameters( - group_parameters, stream_parameters, std::move(handles)); -} - -void AclConnectionHandler::CreatePendingCis( - bluetooth::hci::CreateCisConfig config) { - CisHandles handles; - handles.cis_handle_ = config.cis_connection_handle_; - handles.acl_handle_ = config.acl_connection_handle_; - handles.remote_cis_handle_ = kReservedHandle; - pending_streams_.emplace_back(std::move(handles)); -} - -bool AclConnectionHandler::ConnectCis(uint16_t handle) { - size_t position; - CisHandles connection; - for (position = 0; position < pending_streams_.size(); position++) { - if (handle == pending_streams_[position].cis_handle_) { - LOG_INFO("Found handle 0x%04hx", handle); - connection = pending_streams_[position]; - pending_streams_.erase(pending_streams_.begin() + position); - connected_streams_.push_back(connection); - ASSERT(connection.cis_handle_ != kReservedHandle); - ASSERT(connection.acl_handle_ != kReservedHandle); - ASSERT(connection.remote_cis_handle_ != kReservedHandle); - return true; - } - } - - LOG_INFO("No pending CIS connection with handle 0x%04hx", handle); - return false; -} - -void AclConnectionHandler::SetRemoteCisHandle(uint16_t handle, - uint16_t remote_handle) { - for (size_t position = 0; position < pending_streams_.size(); position++) { - if (handle == pending_streams_[position].cis_handle_) { - LOG_INFO("Added remote handle 0x%04hx to handle 0x%04hx", remote_handle, - pending_streams_[position].cis_handle_); - pending_streams_[position].remote_cis_handle_ = remote_handle; - return; - } - } - LOG_INFO("Couldn't find CIS connection with handle 0x%04hx", handle); -} - -bool AclConnectionHandler::RejectCis(uint16_t handle) { - size_t position; - for (position = 0; position < pending_streams_.size(); position++) { - if (handle == pending_streams_[position].cis_handle_) { - pending_streams_.erase(pending_streams_.begin() + position); - break; - } - } - if (position == pending_streams_.size()) { - LOG_INFO("No pending connection with handle 0x%hx", handle); - return false; - } - return true; -} - -uint16_t AclConnectionHandler::GetPendingAclHandle(uint16_t cis_handle) const { - size_t position; - uint16_t handle = 0xffff; - for (position = 0; position < pending_streams_.size(); position++) { - if (cis_handle == pending_streams_[position].cis_handle_) { - handle = pending_streams_[position].acl_handle_; - break; - } - } - if (position == pending_streams_.size()) { - LOG_INFO("No pending connection with handle 0x%hx", cis_handle); - } - return handle; -} - -bool AclConnectionHandler::DisconnectCis(uint16_t cis_handle) { - size_t position; - for (position = 0; position < connected_streams_.size(); position++) { - if (cis_handle == connected_streams_[position].cis_handle_) { - connected_streams_.erase(connected_streams_.begin() + position); - break; - } - } - if (position == connected_streams_.size()) { - LOG_INFO("No connected stream 0x%hx", cis_handle); - return false; - } - return true; -} - -bluetooth::hci::ErrorCode AclConnectionHandler::RemoveCig(uint8_t cig_id) { - for (const auto& stream : connected_streams_) { - if (isochronous_connection_handler_.GetGroupId(stream.cis_handle_) == - cig_id) { - return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED; - } - } - for (const auto& stream : pending_streams_) { - if (isochronous_connection_handler_.GetGroupId(stream.cis_handle_) == - cig_id) { - return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED; - } - } - auto status = isochronous_connection_handler_.RemoveCig(cig_id); - if (status == bluetooth::hci::ErrorCode::SUCCESS) { - // Clean up? - } - return status; -} - -bool AclConnectionHandler::HasPendingCisConnection(uint16_t handle) const { - for (const auto& config : pending_streams_) { - if (config.cis_handle_ == handle) { - return true; - } - } - return false; -} - -bool AclConnectionHandler::HasPendingCis() const { - return !pending_streams_.empty(); -} - -bool AclConnectionHandler::HasConnectedCis(uint16_t handle) const { - for (const auto& cs : connected_streams_) { - if (handle == cs.cis_handle_) { - return true; - } - } - return false; -} - -bool AclConnectionHandler::HasCisHandle(uint16_t handle) const { - for (const auto& cs : pending_streams_) { - if (handle == cs.cis_handle_) { - return true; - } - } - for (const auto& cs : connected_streams_) { - if (handle == cs.cis_handle_) { - return true; - } - } - return isochronous_connection_handler_.HasHandle(handle); -} - -uint16_t AclConnectionHandler::GetAclHandleForCisHandle( - uint16_t cis_handle) const { - for (const auto& cs : connected_streams_) { - if (cis_handle == cs.cis_handle_) { - return cs.acl_handle_; - } - } - return kReservedHandle; -} - -uint16_t AclConnectionHandler::GetRemoteCisHandleForCisHandle( - uint16_t cis_handle) const { - for (const auto& cs : connected_streams_) { - if (cis_handle == cs.cis_handle_) { - return cs.remote_cis_handle_; - } - } - return kReservedHandle; -} - -GroupParameters AclConnectionHandler::GetGroupParameters(uint8_t id) const { - return isochronous_connection_handler_.GetGroupParameters(id); -} - -StreamParameters AclConnectionHandler::GetStreamParameters( - uint16_t handle) const { - return isochronous_connection_handler_.GetStreamParameters(handle); -} - void AclConnectionHandler::CreateScoConnection( bluetooth::hci::Address addr, ScoConnectionParameters const& parameters, ScoState state, ScoDatapath datapath, bool legacy) { @@ -599,7 +415,7 @@ ScoLinkParameters AclConnectionHandler::GetScoLinkParameters( } std::vector AclConnectionHandler::GetAclHandles() const { - std::vector keys; + std::vector keys(acl_connections_.size()); for (const auto& pair : acl_connections_) { keys.push_back(pair.first); diff --git a/tools/rootcanal/model/controller/acl_connection_handler.h b/tools/rootcanal/model/controller/acl_connection_handler.h index c9bf92aaec86ec48ffbd55aad117bda8e459a15c..146cc475fd98e72c6ca987f7ccd8bb9a74e7e45e 100644 --- a/tools/rootcanal/model/controller/acl_connection_handler.h +++ b/tools/rootcanal/model/controller/acl_connection_handler.h @@ -18,18 +18,22 @@ #include #include -#include +#include +#include #include +#include -#include "acl_connection.h" #include "hci/address.h" #include "hci/address_with_type.h" -#include "isochronous_connection_handler.h" +#include "model/controller/acl_connection.h" +#include "model/controller/sco_connection.h" +#include "packets/hci_packets.h" #include "phy.h" -#include "sco_connection.h" namespace rootcanal { static constexpr uint16_t kReservedHandle = 0xF00; +static constexpr uint16_t kCisHandleRangeStart = 0xE00; +static constexpr uint16_t kCisHandleRangeEnd = 0xEFE; class AclConnectionHandler { public: @@ -74,8 +78,11 @@ class AclConnectionHandler { bool HasPendingLeConnection(bluetooth::hci::AddressWithType addr) const; bool CancelPendingLeConnection(bluetooth::hci::AddressWithType addr); + // \p pending is true if the connection is expected to be + // in pending state. uint16_t CreateConnection(bluetooth::hci::Address addr, - bluetooth::hci::Address own_addr); + bluetooth::hci::Address own_addr, + bool pending = true); uint16_t CreateLeConnection(bluetooth::hci::AddressWithType addr, bluetooth::hci::AddressWithType own_addr, bluetooth::hci::Role role); @@ -83,6 +90,11 @@ class AclConnectionHandler { bool HasHandle(uint16_t handle) const; bool HasScoHandle(uint16_t handle) const; + // Return the connection handle for a classic ACL connection only. + // \p bd_addr is the peer address. + std::optional GetAclConnectionHandle( + bluetooth::hci::Address bd_addr) const; + uint16_t GetHandle(bluetooth::hci::AddressWithType addr) const; uint16_t GetHandleOnlyAddress(bluetooth::hci::Address addr) const; bluetooth::hci::AddressWithType GetAddress(uint16_t handle) const; @@ -109,44 +121,6 @@ class AclConnectionHandler { bluetooth::hci::Role GetAclRole(uint16_t handle) const; void SetAclRole(uint16_t handle, bluetooth::hci::Role role); - std::unique_ptr - SetCigParameters(uint8_t id, uint32_t sdu_interval_m_to_s, - uint32_t sdu_interval_s_to_m, - bluetooth::hci::ClockAccuracy accuracy, - bluetooth::hci::Packing packing, - bluetooth::hci::Enable framing, - uint16_t max_transport_latency_m_to_s, - uint16_t max_transport_latency_s_to_m, - std::vector& streams); - - void CreatePendingCis(bluetooth::hci::CreateCisConfig config); - - bool ConnectCis(uint16_t handle); - - void SetRemoteCisHandle(uint16_t handle, uint16_t remote_handle); - - uint16_t GetPendingAclHandle(uint16_t cis_handle) const; - - bool RejectCis(uint16_t handle); - - bool DisconnectCis(uint16_t handle); - - bluetooth::hci::ErrorCode RemoveCig(uint8_t cig_id); - - bool HasPendingCis() const; - - bool HasPendingCisConnection(uint16_t handle) const; - - bool HasCisHandle(uint16_t handle) const; - - bool HasConnectedCis(uint16_t handle) const; - - uint16_t GetAclHandleForCisHandle(uint16_t cis_handle) const; - uint16_t GetRemoteCisHandleForCisHandle(uint16_t cis_handle) const; - - StreamParameters GetStreamParameters(uint16_t handle) const; - GroupParameters GetGroupParameters(uint8_t id) const; - std::vector GetAclHandles() const; void ResetLinkTimer(uint16_t handle); @@ -180,14 +154,6 @@ class AclConnectionHandler { uint16_t GetUnusedHandle(); uint16_t last_handle_{kReservedHandle - 2}; - IsochronousConnectionHandler isochronous_connection_handler_; - struct CisHandles { - uint16_t acl_handle_ = kReservedHandle; - uint16_t cis_handle_ = kReservedHandle; - uint16_t remote_cis_handle_ = kReservedHandle; - }; - std::vector connected_streams_; - std::vector pending_streams_; }; } // namespace rootcanal diff --git a/tools/rootcanal/model/controller/connected_isochronous_group.h b/tools/rootcanal/model/controller/connected_isochronous_group.h deleted file mode 100644 index b64d0fdc8a33403a6645b2830228664a16269214..0000000000000000000000000000000000000000 --- a/tools/rootcanal/model/controller/connected_isochronous_group.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "hci/hci_packets.h" -#include "model/controller/connected_isochronous_stream.h" - -namespace rootcanal { - -class GroupParameters { - public: - uint8_t id; - uint32_t sdu_interval_m_to_s; - uint32_t sdu_interval_s_to_m; - bool interleaved; - bool framed; - uint16_t max_transport_latency_m_to_s; - uint16_t max_transport_latency_s_to_m; -}; - -class ConnectedIsochronousGroup { - public: - ConnectedIsochronousGroup(GroupParameters parameters, - std::vector streams) - : parameters_(parameters), streams_(std::move(streams)) {} - - virtual ~ConnectedIsochronousGroup() = default; - - bool HasConnectedStream() const { - return std::any_of( - streams_.begin(), streams_.end(), - [&](const ConnectedIsochronousStream& s) { return s.IsConnected(); }); - } - - bool StreamIsConnected(uint16_t handle) const { - return streams_.at(handle).IsConnected(); - } - - bool HasStreams() const { return !streams_.empty(); } - - GroupParameters GetParameters() const { return parameters_; } - - StreamParameters GetStreamParameters(uint16_t handle) const { - for (const auto& stream : streams_) { - if (stream.GetHandle() == handle) { - return stream.GetConfig(); - } - } - return StreamParameters{}; - } - - private: - GroupParameters parameters_; - std::vector streams_; -}; - -} // namespace rootcanal diff --git a/tools/rootcanal/model/controller/connected_isochronous_stream.h b/tools/rootcanal/model/controller/connected_isochronous_stream.h deleted file mode 100644 index f599fc6e023d7662e5488e1865e4ab311bc4a1cb..0000000000000000000000000000000000000000 --- a/tools/rootcanal/model/controller/connected_isochronous_stream.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include "hci/hci_packets.h" - -namespace rootcanal { - -class StreamParameters { - public: - uint8_t group_id; - uint8_t stream_id; - uint16_t max_sdu_m_to_s; - uint16_t max_sdu_s_to_m; - uint8_t rtn_m_to_s; - uint8_t rtn_s_to_m; - uint16_t handle; -}; - -class ConnectedIsochronousStream { - public: - ConnectedIsochronousStream(StreamParameters& stream_param) - : config_(stream_param) {} - - virtual ~ConnectedIsochronousStream() = default; - - bool IsConnected() const { return is_connected_; } - StreamParameters GetConfig() const { return config_; } - - uint16_t GetHandle() const { return config_.handle; } - void Connect() { is_connected_ = true; } - - void Disconnect() { is_connected_ = false; } - - private: - bool is_connected_{false}; - StreamParameters config_; -}; -} // namespace rootcanal diff --git a/tools/rootcanal/model/controller/controller_properties.cc b/tools/rootcanal/model/controller/controller_properties.cc index cd230b714742a2a2a0094f858fe83ee1b8b5bf03..49198879d2dbe88e8164da5dd7534aca77f23a9b 100644 --- a/tools/rootcanal/model/controller/controller_properties.cc +++ b/tools/rootcanal/model/controller/controller_properties.cc @@ -1,5 +1,6 @@ /* * Copyright 2015 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 @@ -13,16 +14,16 @@ * limitations under the License. */ -#include "controller_properties.h" - -#include -#include +#include "model/controller/controller_properties.h" -#include -#include -#include +#include +#include +#include +#include #include "log.h" +#include "packets/hci_packets.h" +#include "rootcanal/configuration.pb.h" namespace rootcanal { using namespace bluetooth::hci; @@ -108,13 +109,13 @@ static constexpr uint64_t LlFeatures() { LLFeaturesBits::LE_PING, LLFeaturesBits::LL_PRIVACY, LLFeaturesBits::EXTENDED_SCANNER_FILTER_POLICIES, - LLFeaturesBits::LE_2M_PHY, LLFeaturesBits::LE_CODED_PHY, + LLFeaturesBits::LE_2M_PHY, + LLFeaturesBits::LE_CODED_PHY, LLFeaturesBits::LE_EXTENDED_ADVERTISING, LLFeaturesBits::LE_PERIODIC_ADVERTISING, - // TODO: breaks AVD boot tests with LE audio - // LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_CENTRAL, - // LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL, + LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_CENTRAL, + LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL, }; uint64_t value = 0; @@ -377,20 +378,17 @@ static std::array SupportedCommands() { // OpCodeIndex::LE_MODIFY_SLEEP_CLOCK_ACCURACY, OpCodeIndex::LE_READ_BUFFER_SIZE_V2, // OpCodeIndex::LE_READ_ISO_TX_SYNC, - // OpCodeIndex::LE_SET_CIG_PARAMETERS, - // OpCodeIndex::LE_SET_CIG_PARAMETERS_TEST, - // OpCodeIndex::LE_CREATE_CIS, - // OpCodeIndex::LE_REMOVE_CIG, - // OpCodeIndex::LE_ACCEPT_CIS_REQUEST, - // OpCodeIndex::LE_REJECT_CIS_REQUEST, + OpCodeIndex::LE_SET_CIG_PARAMETERS, + OpCodeIndex::LE_SET_CIG_PARAMETERS_TEST, OpCodeIndex::LE_CREATE_CIS, + OpCodeIndex::LE_REMOVE_CIG, OpCodeIndex::LE_ACCEPT_CIS_REQUEST, + OpCodeIndex::LE_REJECT_CIS_REQUEST, // OpCodeIndex::LE_CREATE_BIG, // OpCodeIndex::LE_CREATE_BIG_TEST, // OpCodeIndex::LE_TERMINATE_BIG, // OpCodeIndex::LE_BIG_CREATE_SYNC, // OpCodeIndex::LE_BIG_TERMINATE_SYNC, - // OpCodeIndex::LE_REQUEST_PEER_SCA, - // OpCodeIndex::LE_SETUP_ISO_DATA_PATH, - // OpCodeIndex::LE_REMOVE_ISO_DATA_PATH, + OpCodeIndex::LE_REQUEST_PEER_SCA, OpCodeIndex::LE_SETUP_ISO_DATA_PATH, + OpCodeIndex::LE_REMOVE_ISO_DATA_PATH, // OpCodeIndex::LE_ISO_TRANSMIT_TEST, // OpCodeIndex::LE_ISO_RECEIVE_TEST, // OpCodeIndex::LE_ISO_READ_TEST_COUNTERS, @@ -479,21 +477,23 @@ bool ControllerProperties::CheckSupportedFeatures() const { lmp_page_0_reserved_bits = UINT64_C(0x7884000401000100); lmp_page_2_reserved_bits = UINT64_C(0xfffffffffffff080); break; - }; + } if ((lmp_page_0_reserved_bits & lmp_features[0]) != 0) { - LOG_INFO("The page 0 feature bits 0x%016" PRIx64 - " are reserved in the specification %s", - lmp_page_0_reserved_bits & lmp_features[0], - LmpVersionText(lmp_version).c_str()); + INFO( + "The page 0 feature bits 0x{:016x}" + " are reserved in the specification {}", + lmp_page_0_reserved_bits & lmp_features[0], + LmpVersionText(lmp_version)); return false; } if ((lmp_page_2_reserved_bits & lmp_features[2]) != 0) { - LOG_INFO("The page 2 feature bits 0x%016" PRIx64 - " are reserved in the specification %s", - lmp_page_2_reserved_bits & lmp_features[2], - LmpVersionText(lmp_version).c_str()); + INFO( + "The page 2 feature bits 0x{:016x}" + " are reserved in the specification {}", + lmp_page_2_reserved_bits & lmp_features[2], + LmpVersionText(lmp_version)); return false; } @@ -511,14 +511,14 @@ bool ControllerProperties::CheckSupportedFeatures() const { !SupportsLMPFeature( LMPFeaturesPage0Bits::SECURE_SIMPLE_PAIRING_CONTROLLER) || !SupportsLMPFeature(LMPFeaturesPage0Bits::ENCAPSULATED_PDU)) { - LOG_INFO("Table 3.5 validation failed"); + INFO("Table 3.5 validation failed"); return false; } // The features listed in Table 3.6 are forbidden in this version of the // specification and these feature bits shall not be set. if (SupportsLMPFeature(LMPFeaturesPage0Bits::BR_EDR_NOT_SUPPORTED)) { - LOG_INFO("Table 3.6 validation failed"); + INFO("Table 3.6 validation failed"); return false; } @@ -526,7 +526,7 @@ bool ControllerProperties::CheckSupportedFeatures() const { // supported or none of the features named in that row shall be supported. if (SupportsLMPFeature(LMPFeaturesPage0Bits::SNIFF_MODE) != SupportsLMPFeature(LMPFeaturesPage0Bits::SNIFF_SUBRATING)) { - LOG_INFO("Table 3.7 validation failed"); + INFO("Table 3.7 validation failed"); return false; } @@ -534,7 +534,7 @@ bool ControllerProperties::CheckSupportedFeatures() const { // supported. if (SupportsLMPFeature(LMPFeaturesPage0Bits::BROADCAST_ENCRYPTION) && SupportsLMPFeature(LMPFeaturesPage2Bits::COARSE_CLOCK_ADJUSTMENT)) { - LOG_INFO("Table 3.8 validation failed"); + INFO("Table 3.8 validation failed"); return false; } @@ -542,76 +542,72 @@ bool ControllerProperties::CheckSupportedFeatures() const { // supported then the feature named in the second column shall be supported. if (SupportsLMPFeature(LMPFeaturesPage0Bits::ROLE_SWITCH) && !SupportsLMPFeature(LMPFeaturesPage0Bits::SLOT_OFFSET)) { - LOG_INFO("Table 3.9 validation failed; expected Slot Offset"); + INFO("Table 3.9 validation failed; expected Slot Offset"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::HV2_PACKETS) && !SupportsLMPFeature(LMPFeaturesPage0Bits::SCO_LINK)) { - LOG_INFO("Table 3.9 validation failed; expected Sco Link"); + INFO("Table 3.9 validation failed; expected Sco Link"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::HV3_PACKETS) && !SupportsLMPFeature(LMPFeaturesPage0Bits::SCO_LINK)) { - LOG_INFO("Table 3.9 validation failed; expected Sco Link"); + INFO("Table 3.9 validation failed; expected Sco Link"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::M_LAW_LOG_SYNCHRONOUS_DATA) && !SupportsLMPFeature(LMPFeaturesPage0Bits::SCO_LINK) && !SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_SCO_LINK)) { - LOG_INFO( - "Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); + INFO("Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::A_LAW_LOG_SYNCHRONOUS_DATA) && !SupportsLMPFeature(LMPFeaturesPage0Bits::SCO_LINK) && !SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_SCO_LINK)) { - LOG_INFO( - "Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); + INFO("Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::CVSD_SYNCHRONOUS_DATA) && !SupportsLMPFeature(LMPFeaturesPage0Bits::SCO_LINK) && !SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_SCO_LINK)) { - LOG_INFO( - "Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); + INFO("Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::TRANSPARENT_SYNCHRONOUS_DATA) && !SupportsLMPFeature(LMPFeaturesPage0Bits::SCO_LINK) && !SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_SCO_LINK)) { - LOG_INFO( - "Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); + INFO("Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); return false; } if (SupportsLMPFeature( LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ACL_3_MB_S_MODE) && !SupportsLMPFeature( LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ACL_2_MB_S_MODE)) { - LOG_INFO( + INFO( "Table 3.9 validation failed; expected Enhanced Data Rate ACL 2Mb/s " "mode"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::EV4_PACKETS) && !SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_SCO_LINK)) { - LOG_INFO("Table 3.9 validation failed; expected Extended Sco Link"); + INFO("Table 3.9 validation failed; expected Extended Sco Link"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::EV5_PACKETS) && !SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_SCO_LINK)) { - LOG_INFO("Table 3.9 validation failed; expected Extended Sco Link"); + INFO("Table 3.9 validation failed; expected Extended Sco Link"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::AFH_CLASSIFICATION_PERIPHERAL) && !SupportsLMPFeature(LMPFeaturesPage0Bits::AFH_CAPABLE_PERIPHERAL)) { - LOG_INFO("Table 3.9 validation failed; expected AFH Capable Peripheral"); + INFO("Table 3.9 validation failed; expected AFH Capable Peripheral"); return false; } if (SupportsLMPFeature( LMPFeaturesPage0Bits::LMP_3_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS) && !SupportsLMPFeature( LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ACL_2_MB_S_MODE)) { - LOG_INFO( + INFO( "Table 3.9 validation failed; expected Enhanced Data Rate ACL 2Mb/s " "mode"); return false; @@ -620,27 +616,27 @@ bool ControllerProperties::CheckSupportedFeatures() const { LMPFeaturesPage0Bits::LMP_5_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS) && !SupportsLMPFeature( LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ACL_2_MB_S_MODE)) { - LOG_INFO( + INFO( "Table 3.9 validation failed; expected Enhanced Data Rate ACL 2Mb/s " "mode"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::AFH_CLASSIFICATION_CENTRAL) && !SupportsLMPFeature(LMPFeaturesPage0Bits::AFH_CAPABLE_CENTRAL)) { - LOG_INFO("Table 3.9 validation failed; expected AFH Capable Central"); + INFO("Table 3.9 validation failed; expected AFH Capable Central"); return false; } if (SupportsLMPFeature( LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ESCO_2_MB_S_MODE) && !SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_SCO_LINK)) { - LOG_INFO("Table 3.9 validation failed; expected Extended Sco Link"); + INFO("Table 3.9 validation failed; expected Extended Sco Link"); return false; } if (SupportsLMPFeature( LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ESCO_3_MB_S_MODE) && !SupportsLMPFeature( LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ESCO_2_MB_S_MODE)) { - LOG_INFO( + INFO( "Table 3.9 validation failed; expected Enhanced Data Rate eSCO 2Mb/s " "mode"); return false; @@ -649,33 +645,32 @@ bool ControllerProperties::CheckSupportedFeatures() const { LMPFeaturesPage0Bits::LMP_3_SLOT_ENHANCED_DATA_RATE_ESCO_PACKETS) && !SupportsLMPFeature( LMPFeaturesPage0Bits::ENHANCED_DATA_RATE_ESCO_2_MB_S_MODE)) { - LOG_INFO( + INFO( "Table 3.9 validation failed; expected Enhanced Data Rate eSCO 2Mb/s " "mode"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_INQUIRY_RESPONSE) && !SupportsLMPFeature(LMPFeaturesPage0Bits::RSSI_WITH_INQUIRY_RESULTS)) { - LOG_INFO("Table 3.9 validation failed; expected RSSI with Inquiry Results"); + INFO("Table 3.9 validation failed; expected RSSI with Inquiry Results"); return false; } if (SupportsLMPFeature( LMPFeaturesPage0Bits::SIMULTANEOUS_LE_AND_BR_CONTROLLER) && !SupportsLMPFeature(LMPFeaturesPage0Bits::LE_SUPPORTED_CONTROLLER)) { - LOG_INFO("Table 3.9 validation failed; expected LE Supported (Controller)"); + INFO("Table 3.9 validation failed; expected LE Supported (Controller)"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::ERRONEOUS_DATA_REPORTING) && !SupportsLMPFeature(LMPFeaturesPage0Bits::SCO_LINK) && !SupportsLMPFeature(LMPFeaturesPage0Bits::EXTENDED_SCO_LINK)) { - LOG_INFO( - "Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); + INFO("Table 3.9 validation failed; expected Sco Link or Extended Sco Link"); return false; } if (SupportsLMPFeature(LMPFeaturesPage0Bits::ENHANCED_POWER_CONTROL) && (!SupportsLMPFeature(LMPFeaturesPage0Bits::POWER_CONTROL_REQUESTS) || !SupportsLMPFeature(LMPFeaturesPage0Bits::POWER_CONTROL))) { - LOG_INFO( + INFO( "Table 3.9 validation failed; expected Power Control Request and Power " "Control"); return false; @@ -684,20 +679,20 @@ bool ControllerProperties::CheckSupportedFeatures() const { LMPFeaturesPage2Bits:: CONNECTIONLESS_PERIPHERAL_BROADCAST_TRANSMITTER_OPERATION) && !SupportsLMPFeature(LMPFeaturesPage2Bits::SYNCHRONIZATION_TRAIN)) { - LOG_INFO("Table 3.9 validation failed; expected Synchronization Train"); + INFO("Table 3.9 validation failed; expected Synchronization Train"); return false; } if (SupportsLMPFeature( LMPFeaturesPage2Bits:: CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVER_OPERATION) && !SupportsLMPFeature(LMPFeaturesPage2Bits::SYNCHRONIZATION_SCAN)) { - LOG_INFO("Table 3.9 validation failed; expected Synchronization Scan"); + INFO("Table 3.9 validation failed; expected Synchronization Scan"); return false; } if (SupportsLMPFeature(LMPFeaturesPage2Bits::GENERALIZED_INTERLACED_SCAN) && !SupportsLMPFeature(LMPFeaturesPage0Bits::INTERLACED_INQUIRY_SCAN) && !SupportsLMPFeature(LMPFeaturesPage0Bits::INTERLACED_PAGE_SCAN)) { - LOG_INFO( + INFO( "Table 3.9 validation failed; expected Interlaced Inquiry Scan or " "Interlaced Page Scan"); return false; @@ -707,7 +702,7 @@ bool ControllerProperties::CheckSupportedFeatures() const { !SupportsLMPFeature(LMPFeaturesPage0Bits::AFH_CAPABLE_CENTRAL) || !SupportsLMPFeature(LMPFeaturesPage2Bits::SYNCHRONIZATION_TRAIN) || !SupportsLMPFeature(LMPFeaturesPage2Bits::SYNCHRONIZATION_SCAN))) { - LOG_INFO( + INFO( "Table 3.9 validation failed; expected AFH Capable Central/Peripheral " "and Synchronization Train/Scan"); return false; @@ -716,7 +711,7 @@ bool ControllerProperties::CheckSupportedFeatures() const { LMPFeaturesPage2Bits::SECURE_CONNECTIONS_CONTROLLER_SUPPORT) && (!SupportsLMPFeature(LMPFeaturesPage0Bits::PAUSE_ENCRYPTION) || !SupportsLMPFeature(LMPFeaturesPage2Bits::PING))) { - LOG_INFO("Table 3.9 validation failed; expected Pause Encryption and Ping"); + INFO("Table 3.9 validation failed; expected Pause Encryption and Ping"); return false; } @@ -963,7 +958,8 @@ bool ControllerProperties::CheckSupportedCommands() const { auto c36 = mandatory; // C37: Mandatory if the LE Controller can change its sleep clock accuracy, // otherwise excluded. - auto c37 = excluded; + auto c37 = mandatory_or_excluded( + SupportsLLFeature(LLFeaturesBits::SLEEP_CLOCK_ACCURACY_UPDATES)); // C38: Mandatory if LE Feature (Connected Isochronous Stream - Central) or // LE Feature (Connected Isochronous Stream - Peripheral) is supported, // otherwise excluded. @@ -1105,7 +1101,7 @@ bool ControllerProperties::CheckSupportedCommands() const { // // C96: Optional if the LE Controller supports Connection State, // otherwise excluded. - auto c96 = mandatory; + auto c96 = optional; // C97: Mandatory if Advertising State is supported, otherwise excluded. auto c97 = mandatory; // C98: Mandatory if Scanning State is supported, otherwise excluded. @@ -1370,8 +1366,8 @@ bool ControllerProperties::CheckSupportedCommands() const { SupportsCommand(bluetooth::hci::OpCodeIndex::op_code); \ if (!check_command_requirement(br_supported, br_requirement, le_supported, \ le_requirement, command_supported)) { \ - LOG_INFO(#op_code " command validation failed (" #br_requirement \ - "," #le_requirement ")"); \ + INFO(#op_code " command validation failed (" #br_requirement \ + "," #le_requirement ")"); \ } \ } @@ -1735,14 +1731,14 @@ ControllerProperties::ControllerProperties() lmp_features({Page0LmpFeatures(), 0, Page2LmpFeatures()}), le_features(LlFeatures()) { if (!CheckSupportedFeatures()) { - LOG_INFO( + INFO( "Warning: initial LMP and/or LE are not consistent. Please make sure" " that the features are correct w.r.t. the rules described" " in Vol 2, Part C 3.5 Feature requirements"); } if (!CheckSupportedCommands()) { - LOG_INFO( + INFO( "Warning: initial supported commands are not consistent. Please make" " sure that the supported commands are correct w.r.t. the rules" " described in Vol 4, Part E § 3 Overview of commands and events"); @@ -1797,6 +1793,20 @@ static std::vector ll_privacy_commands_ = { OpCodeIndex::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT, }; +// Commands enabled by the LL Connected Isochronous Stream feature bit. +// Central and Peripheral support bits are enabled together. +static std::vector ll_connected_isochronous_stream_commands_ = { + OpCodeIndex::LE_SET_CIG_PARAMETERS, + OpCodeIndex::LE_SET_CIG_PARAMETERS_TEST, + OpCodeIndex::LE_CREATE_CIS, + OpCodeIndex::LE_REMOVE_CIG, + OpCodeIndex::LE_ACCEPT_CIS_REQUEST, + OpCodeIndex::LE_REJECT_CIS_REQUEST, + OpCodeIndex::LE_SETUP_ISO_DATA_PATH, + OpCodeIndex::LE_REMOVE_ISO_DATA_PATH, + OpCodeIndex::LE_REQUEST_PEER_SCA, +}; + static void SetLLFeatureBit(uint64_t& le_features, LLFeaturesBits bit, bool set) { if (set) { @@ -1821,7 +1831,8 @@ static void SetSupportedCommandBits(std::array& supported_commands, ControllerProperties::ControllerProperties( rootcanal::configuration::Controller const& config) - : supported_commands(std::move(SupportedCommands())), + : strict(!config.has_strict() || config.strict()), + supported_commands(std::move(SupportedCommands())), lmp_features({Page0LmpFeatures(), 0, Page2LmpFeatures()}), le_features(LlFeatures()) { using namespace rootcanal::configuration; @@ -1831,6 +1842,69 @@ ControllerProperties::ControllerProperties( switch (config.preset()) { case ControllerPreset::DEFAULT: break; + + case ControllerPreset::LAIRD_BL654: + // Configuration extracted with the helper script controller_info.py + br_supported = false; + le_supported = true; + hci_version = bluetooth::hci::HciVersion::V_5_4; + hci_subversion = 0x5ad2; + lmp_version = bluetooth::hci::LmpVersion::V_5_4; + lmp_subversion = 0x5ad2; + company_identifier = 0x7e8; + supported_commands = std::array{ + 0x20, 0x00, 0x80, 0x00, 0x00, 0xc0, 0x00, 0x0c, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x28, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0xf7, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x30, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xe0, 0xf7, 0xff, 0xff, + 0xff, 0xc1, 0xe3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + lmp_features = std::array { 0x6000000000, 0x0, 0x0 }; + le_features = 0x19beff017fff; + le_acl_data_packet_length = 512; + total_num_le_acl_data_packets = 4; + iso_data_packet_length = 512; + total_num_iso_data_packets = 5; + le_filter_accept_list_size = 4; + le_resolving_list_size = 4; + le_supported_states = 0x3ffffffffff; + le_max_advertising_data_length = 256; + le_num_supported_advertising_sets = 4; + le_periodic_advertiser_list_size = 4; + break; + + case ControllerPreset::CSR_RCK_PTS_DONGLE: + // Configuration extracted with the helper script controller_info.py + supports_csr_vendor_command = true; + br_supported = true; + le_supported = true; + hci_version = bluetooth::hci::HciVersion::V_4_2; + hci_subversion = 0x30e8; + lmp_version = bluetooth::hci::LmpVersion::V_4_2; + lmp_subversion = 0x30e8; + company_identifier = 0xa; + supported_commands = std::array { + 0xff, 0xff, 0xff, 0x03, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf3, 0x0f, 0xe8, 0xfe, 0x3f, 0xf7, 0x83, 0xff, 0x1c, 0x00, + 0x04, 0x00, 0x61, 0xf7, 0xff, 0xff, 0x7f, 0x00, 0xc0, 0xff, 0xff, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + lmp_features = std::array { 0x875b1fd87e8fffff, 0x0, 0x30f }; + acl_data_packet_length = 310; + total_num_acl_data_packets = 10; + sco_data_packet_length = 64; + total_num_sco_data_packets = 8; + num_supported_iac = 2; + le_features = 0x1f; + le_acl_data_packet_length = 0; + total_num_le_acl_data_packets = 0; + le_filter_accept_list_size = 25; + le_supported_states = 0x3ffffffffff; + break; + default: break; } @@ -1867,6 +1941,17 @@ ControllerProperties::ControllerProperties( SetLLFeatureBit(le_features, LLFeaturesBits::LE_CODED_PHY, features.le_coded_phy()); } + if (features.has_le_connected_isochronous_stream()) { + SetLLFeatureBit(le_features, + LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_CENTRAL, + features.le_connected_isochronous_stream()); + SetLLFeatureBit(le_features, + LLFeaturesBits::CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL, + features.le_connected_isochronous_stream()); + SetSupportedCommandBits(supported_commands, + ll_connected_isochronous_stream_commands_, + features.le_connected_isochronous_stream()); + } } // Apply selected quirks. @@ -1880,18 +1965,28 @@ ControllerProperties::ControllerProperties( config.quirks().hardware_error_before_reset(); } // TODO(b/270606199): support send_acl_data_before_connection_complete - // TODO(b/274476773): support send_role_change_before_connection_complete + } + + // Apply selected vendor features. + if (config.has_vendor()) { + if (config.vendor().has_csr()) { + supports_csr_vendor_command = config.vendor().csr(); + } + if (config.vendor().has_android()) { + supports_le_get_vendor_capabilities_command = config.vendor().android(); + supports_le_apcf_vendor_command = config.vendor().android(); + } } if (!CheckSupportedFeatures()) { - LOG_INFO( + INFO( "Warning: LMP and/or LE features are not consistent. Please make sure" " that the features are correct w.r.t. the rules described" " in Vol 2, Part C 3.5 Feature requirements"); } if (!CheckSupportedCommands()) { - LOG_INFO( + INFO( "Warning: supported commands are not consistent. Please make" " sure that the supported commands are correct w.r.t. the rules" " described in Vol 4, Part E § 3 Overview of commands and events"); diff --git a/tools/rootcanal/model/controller/controller_properties.h b/tools/rootcanal/model/controller/controller_properties.h index 9164b635bab1b455507b4ba913dc929053deaf98..0a153f105d0b17c2376bbb198163db12b569dd6e 100644 --- a/tools/rootcanal/model/controller/controller_properties.h +++ b/tools/rootcanal/model/controller/controller_properties.h @@ -18,13 +18,10 @@ #include #include -#include -#include #include -#include "config.pb.h" -#include "hci/address.h" -#include "hci/hci_packets.h" +#include "packets/hci_packets.h" +#include "rootcanal/configuration.pb.h" namespace rootcanal { using bluetooth::hci::HciVersion; @@ -67,6 +64,8 @@ struct ControllerProperties { ControllerProperties(ControllerProperties&&) = default; ~ControllerProperties() = default; + ControllerProperties& operator=(ControllerProperties const&) = default; + // Perform a bitwise and operation on the supported commands mask; // the default bit setting is either loaded from the configuration // file or all 1s. @@ -83,6 +82,9 @@ struct ControllerProperties { // Enabled quirks. ControllerQuirks quirks{}; + // Strict mode. + bool strict{true}; + // Local Version Information (Vol 4, Part E § 7.4.1). HciVersion hci_version{HciVersion::V_5_3}; LmpVersion lmp_version{LmpVersion::V_5_3}; @@ -99,6 +101,8 @@ struct ControllerProperties { // Vendor Supported Commands. bool supports_le_get_vendor_capabilities_command{true}; + bool supports_csr_vendor_command{true}; + bool supports_le_apcf_vendor_command{true}; // Local Supported Features (Vol 4, Part E § 7.4.3) and // Local Extended Features (Vol 4, Part E § 7.4.3). @@ -151,9 +155,17 @@ struct ControllerProperties { // LE Periodic Advertiser List Size (Vol 4, Part E § 7.8.73). uint8_t le_periodic_advertiser_list_size{8}; - // Vendor Information. - // Provide parameters returned by vendor specific commands. - std::vector le_vendor_capabilities{}; + // Android Vendor Capabilities. + // https://source.android.com/docs/core/connect/bluetooth/hci_requirements#vendor-specific-capabilities + uint8_t le_apcf_filter_list_size{16}; + uint8_t le_apcf_num_of_tracked_advertisers{16}; + uint8_t le_apcf_broadcaster_address_filter_list_size{16}; + uint8_t le_apcf_service_uuid_filter_list_size{16}; + uint8_t le_apcf_service_solicitation_uuid_filter_list_size{16}; + uint8_t le_apcf_local_name_filter_list_size{16}; + uint8_t le_apcf_manufacturer_data_filter_list_size{16}; + uint8_t le_apcf_service_data_filter_list_size{16}; + uint8_t le_apcf_ad_type_filter_list_size{16}; bool SupportsLMPFeature(bluetooth::hci::LMPFeaturesPage0Bits bit) const { return (lmp_features[0] & static_cast(bit)) != 0; diff --git a/tools/rootcanal/model/controller/dual_mode_controller.cc b/tools/rootcanal/model/controller/dual_mode_controller.cc index b6efbd4510dee9af0d3d2ccc15bf28d0f97d2df1..c7bee2c2dcd37d5fb2b0d0fe66ffb43b9b0438e1 100644 --- a/tools/rootcanal/model/controller/dual_mode_controller.cc +++ b/tools/rootcanal/model/controller/dual_mode_controller.cc @@ -14,25 +14,48 @@ * limitations under the License. */ -#include "dual_mode_controller.h" +#include "model/controller/dual_mode_controller.h" + +#include #include +#include +#include #include -#include +#include +#include +#include +#include #include "crypto/crypto.h" +#include "hci/address_with_type.h" #include "log.h" -#include "packet/raw_builder.h" +#include "model/controller/acl_connection_handler.h" +#include "model/controller/controller_properties.h" +#include "model/controller/sco_connection.h" +#include "model/controller/vendor_commands/csr.h" +#include "model/devices/device.h" +#include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" +#include "phy.h" using bluetooth::hci::ErrorCode; using bluetooth::hci::LoopbackMode; using bluetooth::hci::OpCode; -using std::vector; namespace rootcanal { constexpr uint16_t kNumCommandPackets = 0x01; constexpr uint16_t kLeMaximumDataLength = 64; constexpr uint16_t kLeMaximumDataTime = 0x148; +constexpr uint8_t kTransmitPowerLevel = -20; + +constexpr bool kLeApcfTransportDiscoveryDataFilterSupported = true; +constexpr bool kLeApcfAdTypeFilterSupported = true; + +void DualModeController::SetProperties(ControllerProperties properties) { + WARNING(id_, "updating the device properties!"); + properties_ = std::move(properties); +} // Device methods. std::string DualModeController::GetTypeString() const { @@ -56,12 +79,12 @@ void DualModeController::SendCommandCompleteUnknownOpCodeEvent( bluetooth::hci::OpCode op_code) const { send_event_(bluetooth::hci::CommandCompleteBuilder::Create( kNumCommandPackets, op_code, - std::make_unique(std::vector{ - static_cast(ErrorCode::UNKNOWN_HCI_COMMAND)}))); + std::vector{ + static_cast(ErrorCode::UNKNOWN_HCI_COMMAND)})); } DualModeController::DualModeController(ControllerProperties properties) - : properties_(std::move(properties)) { + : properties_(std::move(properties)), random_generator_(id_) { Address public_address{}; ASSERT(Address::FromString("3C:5A:B4:04:05:06", public_address)); SetAddress(public_address); @@ -74,32 +97,26 @@ DualModeController::DualModeController(ControllerProperties properties) } void DualModeController::ForwardToLm(CommandView command) { + DEBUG(id_, "<< [LM] {}", bluetooth::hci::OpCodeText(command.GetOpCode())); link_layer_controller_.ForwardToLm(command); } -void DualModeController::SniffSubrating(CommandView command) { - auto command_view = bluetooth::hci::SniffSubratingView::Create(command); - ASSERT(command_view.IsValid()); - - send_event_(bluetooth::hci::SniffSubratingCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, - command_view.GetConnectionHandle())); +void DualModeController::ForwardToLl(CommandView command) { + DEBUG(id_, "<< [LL] {}", bluetooth::hci::OpCodeText(command.GetOpCode())); + link_layer_controller_.ForwardToLl(command); } void DualModeController::HandleAcl( std::shared_ptr> packet) { - bluetooth::hci::PacketView raw_packet(packet); - auto acl_packet = bluetooth::hci::AclView::Create(raw_packet); + auto acl_packet = bluetooth::hci::AclView::Create(pdl::packet::slice(packet)); ASSERT(acl_packet.IsValid()); if (loopback_mode_ == LoopbackMode::ENABLE_LOCAL) { uint16_t handle = acl_packet.GetHandle(); - std::vector payload{acl_packet.GetPayload().begin(), - acl_packet.GetPayload().end()}; + std::vector payload(acl_packet.GetPayload()); send_acl_(bluetooth::hci::AclBuilder::Create( handle, acl_packet.GetPacketBoundaryFlag(), - acl_packet.GetBroadcastFlag(), - std::make_unique(payload))); + acl_packet.GetBroadcastFlag(), std::move(payload))); std::vector completed_packets; bluetooth::hci::CompletedPackets cp; @@ -116,8 +133,7 @@ void DualModeController::HandleAcl( void DualModeController::HandleSco( std::shared_ptr> packet) { - bluetooth::hci::PacketView raw_packet(packet); - auto sco_packet = bluetooth::hci::ScoView::Create(raw_packet); + auto sco_packet = bluetooth::hci::ScoView::Create(pdl::packet::slice(packet)); ASSERT(sco_packet.IsValid()); if (loopback_mode_ == LoopbackMode::ENABLE_LOCAL) { uint16_t handle = sco_packet.GetHandle(); @@ -142,16 +158,15 @@ void DualModeController::HandleSco( void DualModeController::HandleIso( std::shared_ptr> packet) { - bluetooth::hci::PacketView raw_packet(packet); - auto iso = bluetooth::hci::IsoView::Create(raw_packet); + auto iso = bluetooth::hci::IsoView::Create(pdl::packet::slice(packet)); ASSERT(iso.IsValid()); link_layer_controller_.HandleIso(iso); } void DualModeController::HandleCommand( std::shared_ptr> packet) { - auto command_packet = bluetooth::hci::CommandView::Create( - bluetooth::hci::PacketView(packet)); + auto command_packet = + bluetooth::hci::CommandView::Create(pdl::packet::slice(packet)); ASSERT(command_packet.IsValid()); OpCode op_code = command_packet.GetOpCode(); @@ -183,19 +198,17 @@ void DualModeController::HandleCommand( op_code != OpCode::READ_BUFFER_SIZE && op_code != OpCode::READ_LOOPBACK_MODE && op_code != OpCode::WRITE_LOOPBACK_MODE) { - std::unique_ptr raw_builder_ptr = - std::make_unique(255); - raw_builder_ptr->AddOctets(*packet); send_event_(bluetooth::hci::LoopbackCommandBuilder::Create( - std::move(raw_builder_ptr))); + std::vector(packet->begin(), packet->end()))); } // Quirk to reset the host stack when a command is received before the Hci // Reset command. else if (properties_.quirks.hardware_error_before_reset && - !controller_reset_ && - op_code != OpCode::RESET) { - LOG_WARN("Received command %s before HCI Reset; sending the Hardware" - " Error event", OpCodeText(op_code).c_str()); + !controller_reset_ && op_code != OpCode::RESET) { + WARNING(id_, + "Received command {} before HCI Reset; sending the Hardware" + " Error event", + OpCodeText(op_code)); send_event_(bluetooth::hci::HardwareErrorBuilder::Create(0x42)); } // Command is both supported and implemented. @@ -205,22 +218,22 @@ void DualModeController::HandleCommand( } // Command is supported but not implemented: // the command needs to be implemented to fix this. - else if (is_supported_command) { - LOG_ALWAYS_FATAL( - "Unimplemented command %s;\n" - "This message will be displayed if the command is set as supported\n" - "in the command mask but no implementation was provided.\n" - "This warning will be fixed by implementing the command in " - "DualModeController", - OpCodeText(op_code).c_str()); + else if (is_supported_command && properties_.strict) { + FATAL(id_, + "Unimplemented command {};\n" + "This message will be displayed if the command is set as supported\n" + "in the command mask but no implementation was provided.\n" + "This warning will be fixed by implementing the command in " + "DualModeController", + OpCodeText(op_code)); } // The command is not supported. // Respond with the status code Unknown Command. else { SendCommandCompleteUnknownOpCodeEvent(op_code); uint16_t raw_op_code = static_cast(op_code); - LOG_INFO("Unknown command, opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", - raw_op_code, (raw_op_code & 0xFC00) >> 10, raw_op_code & 0x03FF); + INFO(id_, "Unknown command, opcode: 0x{:04x}, OGF: 0x{:02x}, OCF: 0x{:03x}", + raw_op_code, (raw_op_code & 0xFC00) >> 10, raw_op_code & 0x03FF); } } @@ -230,10 +243,8 @@ void DualModeController::RegisterEventChannel( send_event_ = [send_event](std::shared_ptr event) { auto bytes = std::make_shared>(); - bluetooth::packet::BitInserter bit_inserter(*bytes); - bytes->reserve(event->size()); - event->Serialize(bit_inserter); - send_event(std::move(bytes)); + event->Serialize(*bytes); + send_event(bytes); }; link_layer_controller_.RegisterEventChannel(send_event_); } @@ -243,10 +254,8 @@ void DualModeController::RegisterAclChannel( send_acl) { send_acl_ = [send_acl](std::shared_ptr acl_data) { auto bytes = std::make_shared>(); - bluetooth::packet::BitInserter bit_inserter(*bytes); - bytes->reserve(acl_data->size()); - acl_data->Serialize(bit_inserter); - send_acl(std::move(bytes)); + acl_data->Serialize(*bytes); + send_acl(bytes); }; link_layer_controller_.RegisterAclChannel(send_acl_); } @@ -256,10 +265,8 @@ void DualModeController::RegisterScoChannel( send_sco) { send_sco_ = [send_sco](std::shared_ptr sco_data) { auto bytes = std::make_shared>(); - bluetooth::packet::BitInserter bit_inserter(*bytes); - bytes->reserve(sco_data->size()); - sco_data->Serialize(bit_inserter); - send_sco(std::move(bytes)); + sco_data->Serialize(*bytes); + send_sco(bytes); }; link_layer_controller_.RegisterScoChannel(send_sco_); } @@ -269,10 +276,8 @@ void DualModeController::RegisterIsoChannel( send_iso) { send_iso_ = [send_iso](std::shared_ptr iso_data) { auto bytes = std::make_shared>(); - bluetooth::packet::BitInserter bit_inserter(*bytes); - bytes->reserve(iso_data->size()); - iso_data->Serialize(bit_inserter); - send_iso(std::move(bytes)); + iso_data->Serialize(*bytes); + send_iso(bytes); }; link_layer_controller_.RegisterIsoChannel(send_iso_); } @@ -280,12 +285,13 @@ void DualModeController::RegisterIsoChannel( void DualModeController::Reset(CommandView command) { auto command_view = bluetooth::hci::ResetView::Create(command); ASSERT(command_view.IsValid()); - link_layer_controller_.Reset(); - if (loopback_mode_ == LoopbackMode::ENABLE_LOCAL) { - loopback_mode_ = LoopbackMode::NO_LOOPBACK; - } + DEBUG(id_, "<< Reset"); + + link_layer_controller_.Reset(); + loopback_mode_ = LoopbackMode::NO_LOOPBACK; controller_reset_ = true; + send_event_(bluetooth::hci::ResetCompleteBuilder::Create(kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -294,6 +300,8 @@ void DualModeController::ReadBufferSize(CommandView command) { auto command_view = bluetooth::hci::ReadBufferSizeView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Buffer Size"); + send_event_(bluetooth::hci::ReadBufferSizeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, properties_.acl_data_packet_length, properties_.sco_data_packet_length, @@ -301,6 +309,41 @@ void DualModeController::ReadBufferSize(CommandView command) { properties_.total_num_sco_data_packets)); } +void DualModeController::ReadFailedContactCounter(CommandView command) { + auto command_view = + bluetooth::hci::ReadFailedContactCounterView::Create(command); + ASSERT(command_view.IsValid()); + + uint16_t connection_handle = command_view.GetConnectionHandle(); + uint16_t failed_contact_counter = 0; + ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) + ? ErrorCode::SUCCESS + : ErrorCode::UNKNOWN_CONNECTION; + + DEBUG(id_, "<< Read Failed Contact Counter"); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); + + send_event_(bluetooth::hci::ReadFailedContactCounterCompleteBuilder::Create( + kNumCommandPackets, status, connection_handle, failed_contact_counter)); +} + +void DualModeController::ResetFailedContactCounter(CommandView command) { + auto command_view = + bluetooth::hci::ReadFailedContactCounterView::Create(command); + ASSERT(command_view.IsValid()); + uint16_t connection_handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< Reset Failed Contact Counter"); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); + + ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) + ? ErrorCode::SUCCESS + : ErrorCode::UNKNOWN_CONNECTION; + + send_event_(bluetooth::hci::ResetFailedContactCounterCompleteBuilder::Create( + kNumCommandPackets, status, connection_handle)); +} + void DualModeController::ReadRssi(CommandView command) { auto command_view = bluetooth::hci::ReadRssiView::Create(command); ASSERT(command_view.IsValid()); @@ -308,6 +351,9 @@ void DualModeController::ReadRssi(CommandView command) { uint16_t connection_handle = command_view.GetConnectionHandle(); int8_t rssi = 0; + DEBUG(id_, "<< Read RSSI"); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); + ErrorCode status = link_layer_controller_.ReadRssi(connection_handle, &rssi); send_event_(bluetooth::hci::ReadRssiCompleteBuilder::Create( kNumCommandPackets, status, connection_handle, rssi)); @@ -318,6 +364,9 @@ void DualModeController::ReadEncryptionKeySize(CommandView command) { bluetooth::hci::ReadEncryptionKeySizeView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Encryption Key Size"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + send_event_(bluetooth::hci::ReadEncryptionKeySizeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, command_view.GetConnectionHandle(), @@ -327,6 +376,9 @@ void DualModeController::ReadEncryptionKeySize(CommandView command) { void DualModeController::HostBufferSize(CommandView command) { auto command_view = bluetooth::hci::HostBufferSizeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Host Buffer Size"); + send_event_(bluetooth::hci::HostBufferSizeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -336,6 +388,8 @@ void DualModeController::ReadLocalVersionInformation(CommandView command) { bluetooth::hci::ReadLocalVersionInformationView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Local Version Information"); + bluetooth::hci::LocalVersionInformation local_version_information; local_version_information.hci_version_ = properties_.hci_version; local_version_information.lmp_version_ = properties_.lmp_version; @@ -353,8 +407,11 @@ void DualModeController::ReadRemoteVersionInformation(CommandView command) { bluetooth::hci::ReadRemoteVersionInformationView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Remote Version Information"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto status = link_layer_controller_.SendCommandToRemoteByHandle( - OpCode::READ_REMOTE_VERSION_INFORMATION, command.GetPayload(), + OpCode::READ_REMOTE_VERSION_INFORMATION, command.bytes(), command_view.GetConnectionHandle()); send_event_(bluetooth::hci::ReadRemoteVersionInformationStatusBuilder::Create( @@ -364,6 +421,9 @@ void DualModeController::ReadRemoteVersionInformation(CommandView command) { void DualModeController::ReadBdAddr(CommandView command) { auto command_view = bluetooth::hci::ReadBdAddrView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read BD_ADDR"); + send_event_(bluetooth::hci::ReadBdAddrCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, GetAddress())); } @@ -372,6 +432,9 @@ void DualModeController::ReadLocalSupportedCommands(CommandView command) { auto command_view = bluetooth::hci::ReadLocalSupportedCommandsView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Local Supported Commands"); + send_event_(bluetooth::hci::ReadLocalSupportedCommandsCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, properties_.supported_commands)); } @@ -381,6 +444,8 @@ void DualModeController::ReadLocalSupportedFeatures(CommandView command) { bluetooth::hci::ReadLocalSupportedFeaturesView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Local Supported Features"); + send_event_(bluetooth::hci::ReadLocalSupportedFeaturesCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, link_layer_controller_.GetLmpFeatures())); @@ -390,6 +455,9 @@ void DualModeController::ReadLocalSupportedCodecsV1(CommandView command) { auto command_view = bluetooth::hci::ReadLocalSupportedCodecsV1View::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Local Supported Codecs V1"); + send_event_(bluetooth::hci::ReadLocalSupportedCodecsV1CompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, properties_.supported_standard_codecs, @@ -402,6 +470,9 @@ void DualModeController::ReadLocalExtendedFeatures(CommandView command) { ASSERT(command_view.IsValid()); uint8_t page_number = command_view.GetPageNumber(); + DEBUG(id_, "<< Read Local Extended Features"); + DEBUG(id_, " page_number={}", page_number); + send_event_(bluetooth::hci::ReadLocalExtendedFeaturesCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, page_number, link_layer_controller_.GetMaxLmpFeaturesPageNumber(), @@ -413,8 +484,12 @@ void DualModeController::ReadRemoteExtendedFeatures(CommandView command) { bluetooth::hci::ReadRemoteExtendedFeaturesView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Remote Extended Features"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + DEBUG(id_, " page_number={}", command_view.GetPageNumber()); + auto status = link_layer_controller_.SendCommandToRemoteByHandle( - OpCode::READ_REMOTE_EXTENDED_FEATURES, command_view.GetPayload(), + OpCode::READ_REMOTE_EXTENDED_FEATURES, command_view.bytes(), command_view.GetConnectionHandle()); send_event_(bluetooth::hci::ReadRemoteExtendedFeaturesStatusBuilder::Create( @@ -425,6 +500,10 @@ void DualModeController::SwitchRole(CommandView command) { auto command_view = bluetooth::hci::SwitchRoleView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Switch Role"); + DEBUG(id_, " bd_addr={}", command_view.GetBdAddr()); + DEBUG(id_, " role={}", bluetooth::hci::RoleText(command_view.GetRole())); + auto status = link_layer_controller_.SwitchRole(command_view.GetBdAddr(), command_view.GetRole()); @@ -437,8 +516,11 @@ void DualModeController::ReadRemoteSupportedFeatures(CommandView command) { bluetooth::hci::ReadRemoteSupportedFeaturesView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Remote Supported Features"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto status = link_layer_controller_.SendCommandToRemoteByHandle( - OpCode::READ_REMOTE_SUPPORTED_FEATURES, command_view.GetPayload(), + OpCode::READ_REMOTE_SUPPORTED_FEATURES, command_view.bytes(), command_view.GetConnectionHandle()); send_event_(bluetooth::hci::ReadRemoteSupportedFeaturesStatusBuilder::Create( @@ -449,10 +531,13 @@ void DualModeController::ReadClockOffset(CommandView command) { auto command_view = bluetooth::hci::ReadClockOffsetView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Clock Offset"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + uint16_t handle = command_view.GetConnectionHandle(); auto status = link_layer_controller_.SendCommandToRemoteByHandle( - OpCode::READ_CLOCK_OFFSET, command_view.GetPayload(), handle); + OpCode::READ_CLOCK_OFFSET, command_view.bytes(), handle); send_event_(bluetooth::hci::ReadClockOffsetStatusBuilder::Create( status, kNumCommandPackets)); @@ -464,6 +549,10 @@ void DualModeController::AddScoConnection(CommandView command) { auto command_view = bluetooth::hci::AddScoConnectionView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Add SCO Connection"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); + auto status = link_layer_controller_.AddScoConnection( command_view.GetConnectionHandle(), command_view.GetPacketType(), ScoDatapath::NORMAL); @@ -477,6 +566,10 @@ void DualModeController::SetupSynchronousConnection(CommandView command) { bluetooth::hci::SetupSynchronousConnectionView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Setup Synchronous Connection"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); + auto status = link_layer_controller_.SetupSynchronousConnection( command_view.GetConnectionHandle(), command_view.GetTransmitBandwidth(), command_view.GetReceiveBandwidth(), command_view.GetMaxLatency(), @@ -493,6 +586,10 @@ void DualModeController::AcceptSynchronousConnection(CommandView command) { bluetooth::hci::AcceptSynchronousConnectionView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Accept Synchronous Connection"); + DEBUG(id_, " bd_addr={}", command_view.GetBdAddr()); + DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); + auto status = link_layer_controller_.AcceptSynchronousConnection( command_view.GetBdAddr(), command_view.GetTransmitBandwidth(), command_view.GetReceiveBandwidth(), command_view.GetMaxLatency(), @@ -511,6 +608,10 @@ void DualModeController::EnhancedSetupSynchronousConnection( auto status = ErrorCode::SUCCESS; ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Enhanced Setup Synchronous Connection"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); + // The Host shall set the Transmit_Coding_Format and Receive_Coding_Formats // to be equal. auto transmit_coding_format = command_view.GetTransmitCodingFormat(); @@ -520,12 +621,10 @@ void DualModeController::EnhancedSetupSynchronousConnection( transmit_coding_format.company_id_ != receive_coding_format.company_id_ || transmit_coding_format.vendor_specific_codec_id_ != receive_coding_format.vendor_specific_codec_id_) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " - "(%s)" - " and Receive_Coding_Format (%s) as they are not equal", - transmit_coding_format.ToString().c_str(), - receive_coding_format.ToString().c_str()); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " + "({}) and Receive_Coding_Format ({}) as they are not equal", + transmit_coding_format.ToString(), receive_coding_format.ToString()); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -535,9 +634,10 @@ void DualModeController::EnhancedSetupSynchronousConnection( auto output_bandwidth = command_view.GetOutputBandwidth(); if (input_bandwidth != output_bandwidth && input_bandwidth != 0 && output_bandwidth != 0) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Input_Bandwidth (%u)" - " and Output_Bandwidth (%u) as they are not equal and different from 0", + INFO( + id_, + "EnhancedSetupSynchronousConnection: rejected Input_Bandwidth ({})" + " and Output_Bandwidth ({}) as they are not equal and different from 0", input_bandwidth, output_bandwidth); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -551,11 +651,10 @@ void DualModeController::EnhancedSetupSynchronousConnection( input_coding_format.company_id_ != output_coding_format.company_id_ || input_coding_format.vendor_specific_codec_id_ != output_coding_format.vendor_specific_codec_id_) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Input_Coding_Format (%s)" - " and Output_Coding_Format (%s) as they are not equal", - input_coding_format.ToString().c_str(), - output_coding_format.ToString().c_str()); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Input_Coding_Format ({})" + " and Output_Coding_Format ({}) as they are not equal", + input_coding_format.ToString(), output_coding_format.ToString()); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -564,12 +663,12 @@ void DualModeController::EnhancedSetupSynchronousConnection( ScoDatapath datapath = ScoDatapath::NORMAL; if (command_view.GetInputDataPath() != bluetooth::hci::ScoDataPath::HCI || command_view.GetOutputDataPath() != bluetooth::hci::ScoDataPath::HCI) { - LOG_WARN( - "EnhancedSetupSynchronousConnection: Input_Data_Path (%u)" - " and/or Output_Data_Path (%u) are not over HCI, so data will be " - "spoofed", - static_cast(command_view.GetInputDataPath()), - static_cast(command_view.GetOutputDataPath())); + WARNING(id_, + "EnhancedSetupSynchronousConnection: Input_Data_Path ({})" + " and/or Output_Data_Path ({}) are not over HCI, so data will be " + "spoofed", + static_cast(command_view.GetInputDataPath()), + static_cast(command_view.GetOutputDataPath())); datapath = ScoDatapath::SPOOFED; } @@ -584,25 +683,24 @@ void DualModeController::EnhancedSetupSynchronousConnection( input_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && transmit_bandwidth != input_bandwidth) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Transmit_Bandwidth (%u)" - " and Input_Bandwidth (%u) as they are not equal", - transmit_bandwidth, input_bandwidth); - LOG_INFO( - "EnhancedSetupSynchronousConnection: the Transmit_Bandwidth and " - "Input_Bandwidth shall be equal when both Transmit_Coding_Format " - "and Input_Coding_Format are 'transparent'"); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Transmit_Bandwidth ({})" + " and Input_Bandwidth ({}) as they are not equal", + transmit_bandwidth, input_bandwidth); + INFO(id_, + "EnhancedSetupSynchronousConnection: the Transmit_Bandwidth and " + "Input_Bandwidth shall be equal when both Transmit_Coding_Format " + "and Input_Coding_Format are 'transparent'"); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } if ((transmit_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT) != (input_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT)) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " - "(%s) and Input_Coding_Format (%s) as they are incompatible", - transmit_coding_format.ToString().c_str(), - input_coding_format.ToString().c_str()); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " + "({}) and Input_Coding_Format ({}) as they are incompatible", + transmit_coding_format.ToString(), input_coding_format.ToString()); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -615,25 +713,24 @@ void DualModeController::EnhancedSetupSynchronousConnection( output_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && receive_bandwidth != output_bandwidth) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Receive_Bandwidth (%u)" - " and Output_Bandwidth (%u) as they are not equal", - receive_bandwidth, output_bandwidth); - LOG_INFO( - "EnhancedSetupSynchronousConnection: the Receive_Bandwidth and " - "Output_Bandwidth shall be equal when both Receive_Coding_Format " - "and Output_Coding_Format are 'transparent'"); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Receive_Bandwidth ({})" + " and Output_Bandwidth ({}) as they are not equal", + receive_bandwidth, output_bandwidth); + INFO(id_, + "EnhancedSetupSynchronousConnection: the Receive_Bandwidth and " + "Output_Bandwidth shall be equal when both Receive_Coding_Format " + "and Output_Coding_Format are 'transparent'"); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } if ((receive_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT) != (output_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT)) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Receive_Coding_Format " - "(%s) and Output_Coding_Format (%s) as they are incompatible", - receive_coding_format.ToString().c_str(), - output_coding_format.ToString().c_str()); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Receive_Coding_Format " + "({}) and Output_Coding_Format ({}) as they are incompatible", + receive_coding_format.ToString(), output_coding_format.ToString()); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -658,6 +755,10 @@ void DualModeController::EnhancedAcceptSynchronousConnection( auto status = ErrorCode::SUCCESS; ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Enhanced Accept Synchronous Connection"); + DEBUG(id_, " bd_addr={}", command_view.GetBdAddr()); + DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); + // The Host shall set the Transmit_Coding_Format and Receive_Coding_Formats // to be equal. auto transmit_coding_format = command_view.GetTransmitCodingFormat(); @@ -667,12 +768,11 @@ void DualModeController::EnhancedAcceptSynchronousConnection( transmit_coding_format.company_id_ != receive_coding_format.company_id_ || transmit_coding_format.vendor_specific_codec_id_ != receive_coding_format.vendor_specific_codec_id_) { - LOG_INFO( - "EnhancedAcceptSynchronousConnection: rejected Transmit_Coding_Format " - "(%s)" - " and Receive_Coding_Format (%s) as they are not equal", - transmit_coding_format.ToString().c_str(), - receive_coding_format.ToString().c_str()); + INFO(id_, + "EnhancedAcceptSynchronousConnection: rejected Transmit_Coding_Format " + "({})" + " and Receive_Coding_Format ({}) as they are not equal", + transmit_coding_format.ToString(), receive_coding_format.ToString()); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -682,9 +782,10 @@ void DualModeController::EnhancedAcceptSynchronousConnection( auto output_bandwidth = command_view.GetOutputBandwidth(); if (input_bandwidth != output_bandwidth && input_bandwidth != 0 && output_bandwidth != 0) { - LOG_INFO( - "EnhancedAcceptSynchronousConnection: rejected Input_Bandwidth (%u)" - " and Output_Bandwidth (%u) as they are not equal and different from 0", + INFO( + id_, + "EnhancedAcceptSynchronousConnection: rejected Input_Bandwidth ({})" + " and Output_Bandwidth ({}) as they are not equal and different from 0", input_bandwidth, output_bandwidth); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -698,11 +799,11 @@ void DualModeController::EnhancedAcceptSynchronousConnection( input_coding_format.company_id_ != output_coding_format.company_id_ || input_coding_format.vendor_specific_codec_id_ != output_coding_format.vendor_specific_codec_id_) { - LOG_INFO( - "EnhancedAcceptSynchronousConnection: rejected Input_Coding_Format (%s)" - " and Output_Coding_Format (%s) as they are not equal", - input_coding_format.ToString().c_str(), - output_coding_format.ToString().c_str()); + INFO( + id_, + "EnhancedAcceptSynchronousConnection: rejected Input_Coding_Format ({})" + " and Output_Coding_Format ({}) as they are not equal", + input_coding_format.ToString(), output_coding_format.ToString()); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -710,12 +811,12 @@ void DualModeController::EnhancedAcceptSynchronousConnection( // default HCI transport. if (command_view.GetInputDataPath() != bluetooth::hci::ScoDataPath::HCI || command_view.GetOutputDataPath() != bluetooth::hci::ScoDataPath::HCI) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: Input_Data_Path (%u)" - " and/or Output_Data_Path (%u) are not over HCI, so data will be " - "spoofed", - static_cast(command_view.GetInputDataPath()), - static_cast(command_view.GetOutputDataPath())); + INFO(id_, + "EnhancedSetupSynchronousConnection: Input_Data_Path ({})" + " and/or Output_Data_Path ({}) are not over HCI, so data will be " + "spoofed", + static_cast(command_view.GetInputDataPath()), + static_cast(command_view.GetOutputDataPath())); } // Either both the Transmit_Coding_Format and Input_Coding_Format shall be @@ -729,25 +830,24 @@ void DualModeController::EnhancedAcceptSynchronousConnection( input_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && transmit_bandwidth != input_bandwidth) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Transmit_Bandwidth (%u)" - " and Input_Bandwidth (%u) as they are not equal", - transmit_bandwidth, input_bandwidth); - LOG_INFO( - "EnhancedSetupSynchronousConnection: the Transmit_Bandwidth and " - "Input_Bandwidth shall be equal when both Transmit_Coding_Format " - "and Input_Coding_Format are 'transparent'"); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Transmit_Bandwidth ({})" + " and Input_Bandwidth ({}) as they are not equal", + transmit_bandwidth, input_bandwidth); + INFO(id_, + "EnhancedSetupSynchronousConnection: the Transmit_Bandwidth and " + "Input_Bandwidth shall be equal when both Transmit_Coding_Format " + "and Input_Coding_Format are 'transparent'"); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } if ((transmit_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT) != (input_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT)) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " - "(%s) and Input_Coding_Format (%s) as they are incompatible", - transmit_coding_format.ToString().c_str(), - input_coding_format.ToString().c_str()); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " + "({}) and Input_Coding_Format ({}) as they are incompatible", + transmit_coding_format.ToString(), input_coding_format.ToString()); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -760,25 +860,24 @@ void DualModeController::EnhancedAcceptSynchronousConnection( output_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && receive_bandwidth != output_bandwidth) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Receive_Bandwidth (%u)" - " and Output_Bandwidth (%u) as they are not equal", - receive_bandwidth, output_bandwidth); - LOG_INFO( - "EnhancedSetupSynchronousConnection: the Receive_Bandwidth and " - "Output_Bandwidth shall be equal when both Receive_Coding_Format " - "and Output_Coding_Format are 'transparent'"); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Receive_Bandwidth ({})" + " and Output_Bandwidth ({}) as they are not equal", + receive_bandwidth, output_bandwidth); + INFO(id_, + "EnhancedSetupSynchronousConnection: the Receive_Bandwidth and " + "Output_Bandwidth shall be equal when both Receive_Coding_Format " + "and Output_Coding_Format are 'transparent'"); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } if ((receive_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT) != (output_coding_format.coding_format_ == bluetooth::hci::ScoCodingFormatValues::TRANSPARENT)) { - LOG_INFO( - "EnhancedSetupSynchronousConnection: rejected Receive_Coding_Format " - "(%s) and Output_Coding_Format (%s) as they are incompatible", - receive_coding_format.ToString().c_str(), - output_coding_format.ToString().c_str()); + INFO(id_, + "EnhancedSetupSynchronousConnection: rejected Receive_Coding_Format " + "({}) and Output_Coding_Format ({}) as they are incompatible", + receive_coding_format.ToString(), output_coding_format.ToString()); status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -800,6 +899,11 @@ void DualModeController::RejectSynchronousConnection(CommandView command) { bluetooth::hci::RejectSynchronousConnectionView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Reject Synchronous Connection"); + DEBUG(id_, " bd_addr={}", command_view.GetBdAddr()); + DEBUG(id_, " reason={}", + bluetooth::hci::RejectConnectionReasonText(command_view.GetReason())); + auto status = link_layer_controller_.RejectSynchronousConnection( command_view.GetBdAddr(), (uint16_t)command_view.GetReason()); @@ -814,6 +918,8 @@ void DualModeController::ReadInquiryResponseTransmitPowerLevel( command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Inquiry Response Transmit Power Level"); + uint8_t tx_power = 20; // maximum send_event_( bluetooth::hci::ReadInquiryResponseTransmitPowerLevelCompleteBuilder:: @@ -824,6 +930,9 @@ void DualModeController::EnhancedFlush(CommandView command) { auto command_view = bluetooth::hci::EnhancedFlushView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Enhanced Flush"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto handle = command_view.GetConnectionHandle(); send_event_(bluetooth::hci::EnhancedFlushStatusBuilder::Create( ErrorCode::SUCCESS, kNumCommandPackets)); @@ -840,6 +949,10 @@ void DualModeController::EnhancedFlush(CommandView command) { void DualModeController::SetEventMaskPage2(CommandView command) { auto command_view = bluetooth::hci::SetEventMaskPage2View::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Set Event Mask Page 2"); + DEBUG(id_, " event_mask_page_2=0x{:x}", command_view.GetEventMaskPage2()); + link_layer_controller_.SetEventMaskPage2(command_view.GetEventMaskPage2()); send_event_(bluetooth::hci::SetEventMaskPage2CompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); @@ -847,12 +960,18 @@ void DualModeController::SetEventMaskPage2(CommandView command) { void DualModeController::ReadLocalOobData(CommandView command) { auto command_view = bluetooth::hci::ReadLocalOobDataView::Create(command); + + DEBUG(id_, "<< Read Local Oob Data"); + link_layer_controller_.ReadLocalOobData(); } void DualModeController::ReadLocalOobExtendedData(CommandView command) { auto command_view = bluetooth::hci::ReadLocalOobExtendedDataView::Create(command); + + DEBUG(id_, "<< Read Local Oob Extended Data"); + link_layer_controller_.ReadLocalOobExtendedData(); } @@ -861,6 +980,10 @@ void DualModeController::WriteSimplePairingMode(CommandView command) { bluetooth::hci::WriteSimplePairingModeView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Write Simple Pairing Mode"); + DEBUG(id_, " simple_pairing_mode={}", + command_view.GetSimplePairingMode() == bluetooth::hci::Enable::ENABLED); + auto enabled = command_view.GetSimplePairingMode() == bluetooth::hci::Enable::ENABLED; link_layer_controller_.SetSecureSimplePairingSupport(enabled); @@ -873,6 +996,10 @@ void DualModeController::ChangeConnectionPacketType(CommandView command) { bluetooth::hci::ChangeConnectionPacketTypeView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Change Connection Packet Type"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + DEBUG(id_, " packet_type=0x{:x}", command_view.GetPacketType()); + uint16_t handle = command_view.GetConnectionHandle(); uint16_t packet_type = static_cast(command_view.GetPacketType()); @@ -885,6 +1012,11 @@ void DualModeController::ChangeConnectionPacketType(CommandView command) { void DualModeController::WriteLeHostSupport(CommandView command) { auto command_view = bluetooth::hci::WriteLeHostSupportView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write LE Host Support"); + DEBUG(id_, " le_supported_host={}", + command_view.GetLeSupportedHost() == bluetooth::hci::Enable::ENABLED); + auto le_support = command_view.GetLeSupportedHost() == bluetooth::hci::Enable::ENABLED; link_layer_controller_.SetLeHostSupport(le_support); @@ -897,6 +1029,12 @@ void DualModeController::WriteSecureConnectionsHostSupport( auto command_view = bluetooth::hci::WriteSecureConnectionsHostSupportView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Secure Connections Host Support"); + DEBUG(id_, " secure_connections_host_support={}", + command_view.GetSecureConnectionsHostSupport() == + bluetooth::hci::Enable::ENABLED); + link_layer_controller_.SetSecureConnectionsSupport( command_view.GetSecureConnectionsHostSupport() == bluetooth::hci::Enable::ENABLED); @@ -908,6 +1046,10 @@ void DualModeController::WriteSecureConnectionsHostSupport( void DualModeController::SetEventMask(CommandView command) { auto command_view = bluetooth::hci::SetEventMaskView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Set Event Mask"); + DEBUG(id_, " event_mask=0x{:x}", command_view.GetEventMask()); + link_layer_controller_.SetEventMask(command_view.GetEventMask()); send_event_(bluetooth::hci::SetEventMaskCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); @@ -916,6 +1058,9 @@ void DualModeController::SetEventMask(CommandView command) { void DualModeController::ReadInquiryMode(CommandView command) { auto command_view = bluetooth::hci::ReadInquiryModeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Inquiry Mode"); + bluetooth::hci::InquiryMode inquiry_mode = bluetooth::hci::InquiryMode::STANDARD; send_event_(bluetooth::hci::ReadInquiryModeCompleteBuilder::Create( @@ -925,6 +1070,11 @@ void DualModeController::ReadInquiryMode(CommandView command) { void DualModeController::WriteInquiryMode(CommandView command) { auto command_view = bluetooth::hci::WriteInquiryModeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Inquiry Mode"); + DEBUG(id_, " inquiry_mode={}", + bluetooth::hci::InquiryModeText(command_view.GetInquiryMode())); + link_layer_controller_.SetInquiryMode( static_cast(command_view.GetInquiryMode())); send_event_(bluetooth::hci::WriteInquiryModeCompleteBuilder::Create( @@ -934,6 +1084,9 @@ void DualModeController::WriteInquiryMode(CommandView command) { void DualModeController::ReadPageScanType(CommandView command) { auto command_view = bluetooth::hci::ReadPageScanTypeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Page Scan Type"); + bluetooth::hci::PageScanType page_scan_type = bluetooth::hci::PageScanType::STANDARD; send_event_(bluetooth::hci::ReadPageScanTypeCompleteBuilder::Create( @@ -943,6 +1096,11 @@ void DualModeController::ReadPageScanType(CommandView command) { void DualModeController::WritePageScanType(CommandView command) { auto command_view = bluetooth::hci::WritePageScanTypeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Page Scan Type"); + DEBUG(id_, " page_scan_type={}", + bluetooth::hci::PageScanTypeText(command_view.GetPageScanType())); + send_event_(bluetooth::hci::WritePageScanTypeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -950,6 +1108,9 @@ void DualModeController::WritePageScanType(CommandView command) { void DualModeController::ReadInquiryScanType(CommandView command) { auto command_view = bluetooth::hci::ReadInquiryScanTypeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Inquiry Scan Type"); + bluetooth::hci::InquiryScanType inquiry_scan_type = bluetooth::hci::InquiryScanType::STANDARD; send_event_(bluetooth::hci::ReadInquiryScanTypeCompleteBuilder::Create( @@ -959,6 +1120,11 @@ void DualModeController::ReadInquiryScanType(CommandView command) { void DualModeController::WriteInquiryScanType(CommandView command) { auto command_view = bluetooth::hci::WriteInquiryScanTypeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Inquiry Scan Type"); + DEBUG(id_, " inquiry_scan_type={}", + bluetooth::hci::InquiryScanTypeText(command_view.GetInquiryScanType())); + send_event_(bluetooth::hci::WriteInquiryScanTypeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -967,8 +1133,11 @@ void DualModeController::ChangeConnectionLinkKey(CommandView command) { auto command_view = bluetooth::hci::ChangeConnectionLinkKeyView::Create(command); ASSERT(command_view.IsValid()); - uint16_t handle = command_view.GetConnectionHandle(); + DEBUG(id_, "<< Change Connection Link Key"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + + uint16_t handle = command_view.GetConnectionHandle(); auto status = link_layer_controller_.ChangeConnectionLinkKey(handle); send_event_(bluetooth::hci::ChangeConnectionLinkKeyStatusBuilder::Create( @@ -978,8 +1147,11 @@ void DualModeController::ChangeConnectionLinkKey(CommandView command) { void DualModeController::CentralLinkKey(CommandView command) { auto command_view = bluetooth::hci::CentralLinkKeyView::Create(command); ASSERT(command_view.IsValid()); - uint8_t key_flag = static_cast(command_view.GetKeyFlag()); + DEBUG(id_, "<< Central Link Key"); + DEBUG(id_, " key_flag={}", command_view.GetKeyFlag()); + + uint8_t key_flag = static_cast(command_view.GetKeyFlag()); auto status = link_layer_controller_.CentralLinkKey(key_flag); send_event_(bluetooth::hci::CentralLinkKeyStatusBuilder::Create( @@ -990,6 +1162,11 @@ void DualModeController::WriteAuthenticationEnable(CommandView command) { auto command_view = bluetooth::hci::WriteAuthenticationEnableView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Authentication Enable"); + DEBUG(id_, " authentication_enable={}", + command_view.GetAuthenticationEnable()); + link_layer_controller_.SetAuthenticationEnable( command_view.GetAuthenticationEnable()); send_event_(bluetooth::hci::WriteAuthenticationEnableCompleteBuilder::Create( @@ -1000,15 +1177,33 @@ void DualModeController::ReadAuthenticationEnable(CommandView command) { auto command_view = bluetooth::hci::ReadAuthenticationEnableView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Authentication Enable"); + send_event_(bluetooth::hci::ReadAuthenticationEnableCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, static_cast( link_layer_controller_.GetAuthenticationEnable()))); } +void DualModeController::ReadClassOfDevice(CommandView command) { + auto command_view = bluetooth::hci::ReadClassOfDeviceView::Create(command); + ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Class of Device"); + + send_event_(bluetooth::hci::ReadClassOfDeviceCompleteBuilder::Create( + kNumCommandPackets, ErrorCode::SUCCESS, + link_layer_controller_.GetClassOfDevice())); +} + void DualModeController::WriteClassOfDevice(CommandView command) { auto command_view = bluetooth::hci::WriteClassOfDeviceView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Class of Device"); + DEBUG(id_, " class_of_device=0x{:x}", command_view.GetClassOfDevice()); + link_layer_controller_.SetClassOfDevice(command_view.GetClassOfDevice()); send_event_(bluetooth::hci::WriteClassOfDeviceCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); @@ -1017,6 +1212,9 @@ void DualModeController::WriteClassOfDevice(CommandView command) { void DualModeController::ReadPageTimeout(CommandView command) { auto command_view = bluetooth::hci::ReadPageTimeoutView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Page Timeout"); + uint16_t page_timeout = link_layer_controller_.GetPageTimeout(); send_event_(bluetooth::hci::ReadPageTimeoutCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, page_timeout)); @@ -1025,6 +1223,10 @@ void DualModeController::ReadPageTimeout(CommandView command) { void DualModeController::WritePageTimeout(CommandView command) { auto command_view = bluetooth::hci::WritePageTimeoutView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Page Timeout"); + DEBUG(id_, " page_timeout={}", command_view.GetPageTimeout()); + link_layer_controller_.SetPageTimeout(command_view.GetPageTimeout()); send_event_(bluetooth::hci::WritePageTimeoutCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); @@ -1037,6 +1239,9 @@ void DualModeController::HoldMode(CommandView command) { uint16_t hold_mode_max_interval = command_view.GetHoldModeMaxInterval(); uint16_t hold_mode_min_interval = command_view.GetHoldModeMinInterval(); + DEBUG(id_, "<< Hold Mode"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto status = link_layer_controller_.HoldMode(handle, hold_mode_max_interval, hold_mode_min_interval); @@ -1053,6 +1258,9 @@ void DualModeController::SniffMode(CommandView command) { uint16_t sniff_attempt = command_view.GetSniffAttempt(); uint16_t sniff_timeout = command_view.GetSniffTimeout(); + DEBUG(id_, "<< Sniff Mode"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto status = link_layer_controller_.SniffMode(handle, sniff_max_interval, sniff_min_interval, sniff_attempt, sniff_timeout); @@ -1065,6 +1273,9 @@ void DualModeController::ExitSniffMode(CommandView command) { auto command_view = bluetooth::hci::ExitSniffModeView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Exit Sniff Mode"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto status = link_layer_controller_.ExitSniffMode(command_view.GetConnectionHandle()); @@ -1082,6 +1293,9 @@ void DualModeController::QosSetup(CommandView command) { uint32_t latency = command_view.GetLatency(); uint32_t delay_variation = command_view.GetDelayVariation(); + DEBUG(id_, "<< Qos Setup"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto status = link_layer_controller_.QosSetup(handle, service_type, token_rate, peak_bandwidth, latency, delay_variation); @@ -1095,6 +1309,9 @@ void DualModeController::RoleDiscovery(CommandView command) { ASSERT(command_view.IsValid()); uint16_t handle = command_view.GetConnectionHandle(); + DEBUG(id_, "<< Role Discovery"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + auto role = bluetooth::hci::Role::CENTRAL; auto status = link_layer_controller_.RoleDiscovery(handle, &role); @@ -1106,6 +1323,9 @@ void DualModeController::ReadDefaultLinkPolicySettings(CommandView command) { auto command_view = bluetooth::hci::ReadDefaultLinkPolicySettingsView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Default Link Policy Settings"); + uint16_t settings = link_layer_controller_.ReadDefaultLinkPolicySettings(); send_event_( bluetooth::hci::ReadDefaultLinkPolicySettingsCompleteBuilder::Create( @@ -1116,6 +1336,11 @@ void DualModeController::WriteDefaultLinkPolicySettings(CommandView command) { auto command_view = bluetooth::hci::WriteDefaultLinkPolicySettingsView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Default Link Policy Settings"); + DEBUG(id_, " default_link_policy_settings=0x{:x}", + command_view.GetDefaultLinkPolicySettings()); + ErrorCode status = link_layer_controller_.WriteDefaultLinkPolicySettings( command_view.GetDefaultLinkPolicySettings()); send_event_( @@ -1123,6 +1348,18 @@ void DualModeController::WriteDefaultLinkPolicySettings(CommandView command) { kNumCommandPackets, status)); } +void DualModeController::SniffSubrating(CommandView command) { + auto command_view = bluetooth::hci::SniffSubratingView::Create(command); + ASSERT(command_view.IsValid()); + uint16_t connection_handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< Sniff Subrating"); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); + + send_event_(bluetooth::hci::SniffSubratingCompleteBuilder::Create( + kNumCommandPackets, ErrorCode::SUCCESS, connection_handle)); +} + void DualModeController::FlowSpecification(CommandView command) { auto command_view = bluetooth::hci::FlowSpecificationView::Create(command); ASSERT(command_view.IsValid()); @@ -1135,6 +1372,9 @@ void DualModeController::FlowSpecification(CommandView command) { uint32_t peak_bandwidth = command_view.GetPeakBandwidth(); uint32_t access_latency = command_view.GetAccessLatency(); + DEBUG(id_, "<< Flow Specification"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + auto status = link_layer_controller_.FlowSpecification( handle, flow_direction, service_type, token_rate, token_bucket_size, peak_bandwidth, access_latency); @@ -1147,10 +1387,12 @@ void DualModeController::ReadLinkPolicySettings(CommandView command) { auto command_view = bluetooth::hci::ReadLinkPolicySettingsView::Create(command); ASSERT(command_view.IsValid()); - uint16_t handle = command_view.GetConnectionHandle(); - uint16_t settings; + DEBUG(id_, "<< Read Link Policy Settings"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + + uint16_t settings = 0; auto status = link_layer_controller_.ReadLinkPolicySettings(handle, &settings); @@ -1162,10 +1404,13 @@ void DualModeController::WriteLinkPolicySettings(CommandView command) { auto command_view = bluetooth::hci::WriteLinkPolicySettingsView::Create(command); ASSERT(command_view.IsValid()); - uint16_t handle = command_view.GetConnectionHandle(); uint16_t settings = command_view.GetLinkPolicySettings(); + DEBUG(id_, "<< Write Link Policy Settings"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + DEBUG(id_, " link_policy_settings=0x{:x}", settings); + auto status = link_layer_controller_.WriteLinkPolicySettings(handle, settings); @@ -1177,10 +1422,13 @@ void DualModeController::WriteLinkSupervisionTimeout(CommandView command) { auto command_view = bluetooth::hci::WriteLinkSupervisionTimeoutView::Create(command); ASSERT(command_view.IsValid()); - uint16_t handle = command_view.GetConnectionHandle(); uint16_t timeout = command_view.GetLinkSupervisionTimeout(); + DEBUG(id_, "<< Write Link Supervision Timeout"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + DEBUG(id_, " link_supervision_timeout={}", timeout); + auto status = link_layer_controller_.WriteLinkSupervisionTimeout(handle, timeout); send_event_( @@ -1191,6 +1439,9 @@ void DualModeController::WriteLinkSupervisionTimeout(CommandView command) { void DualModeController::ReadLocalName(CommandView command) { auto command_view = bluetooth::hci::ReadLocalNameView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Local Name"); + send_event_(bluetooth::hci::ReadLocalNameCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, link_layer_controller_.GetLocalName())); @@ -1199,6 +1450,9 @@ void DualModeController::ReadLocalName(CommandView command) { void DualModeController::WriteLocalName(CommandView command) { auto command_view = bluetooth::hci::WriteLocalNameView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Local Name"); + link_layer_controller_.SetLocalName(command_view.GetLocalName()); send_event_(bluetooth::hci::WriteLocalNameCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); @@ -1208,8 +1462,11 @@ void DualModeController::WriteExtendedInquiryResponse(CommandView command) { auto command_view = bluetooth::hci::WriteExtendedInquiryResponseView::Create(command); ASSERT(command_view.IsValid()); - link_layer_controller_.SetExtendedInquiryResponse(std::vector( - command_view.GetPayload().begin() + 1, command_view.GetPayload().end())); + + DEBUG(id_, "<< Write Extended Inquiry Response"); + + link_layer_controller_.SetExtendedInquiryResponse( + command_view.GetExtendedInquiryResponse()); send_event_( bluetooth::hci::WriteExtendedInquiryResponseCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); @@ -1219,6 +1476,10 @@ void DualModeController::RefreshEncryptionKey(CommandView command) { auto command_view = bluetooth::hci::RefreshEncryptionKeyView::Create(command); ASSERT(command_view.IsValid()); uint16_t handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< Refresh Encryption Key"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + send_event_(bluetooth::hci::RefreshEncryptionKeyStatusBuilder::Create( ErrorCode::SUCCESS, kNumCommandPackets)); // TODO: Support this in the link layer @@ -1226,10 +1487,24 @@ void DualModeController::RefreshEncryptionKey(CommandView command) { ErrorCode::SUCCESS, handle)); } +void DualModeController::ReadVoiceSetting(CommandView command) { + auto command_view = bluetooth::hci::ReadVoiceSettingView::Create(command); + ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Voice Setting"); + + send_event_(bluetooth::hci::ReadVoiceSettingCompleteBuilder::Create( + kNumCommandPackets, ErrorCode::SUCCESS, + link_layer_controller_.GetVoiceSetting())); +} + void DualModeController::WriteVoiceSetting(CommandView command) { auto command_view = bluetooth::hci::WriteVoiceSettingView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Write Voice Setting"); + DEBUG(id_, " voice_setting=0x{:x}", command_view.GetVoiceSetting()); + link_layer_controller_.SetVoiceSetting(command_view.GetVoiceSetting()); send_event_(bluetooth::hci::WriteVoiceSettingCompleteBuilder::Create( @@ -1240,6 +1515,9 @@ void DualModeController::ReadNumberOfSupportedIac(CommandView command) { auto command_view = bluetooth::hci::ReadNumberOfSupportedIacView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Number of Supported Iac"); + send_event_(bluetooth::hci::ReadNumberOfSupportedIacCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, properties_.num_supported_iac)); } @@ -1247,6 +1525,9 @@ void DualModeController::ReadNumberOfSupportedIac(CommandView command) { void DualModeController::ReadCurrentIacLap(CommandView command) { auto command_view = bluetooth::hci::ReadCurrentIacLapView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Current Iac Lap"); + send_event_(bluetooth::hci::ReadCurrentIacLapCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, link_layer_controller_.ReadCurrentIacLap())); @@ -1255,6 +1536,9 @@ void DualModeController::ReadCurrentIacLap(CommandView command) { void DualModeController::WriteCurrentIacLap(CommandView command) { auto command_view = bluetooth::hci::WriteCurrentIacLapView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Current Iac Lap"); + link_layer_controller_.WriteCurrentIacLap(command_view.GetLapsToWrite()); send_event_(bluetooth::hci::WriteCurrentIacLapCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); @@ -1263,6 +1547,9 @@ void DualModeController::WriteCurrentIacLap(CommandView command) { void DualModeController::ReadPageScanActivity(CommandView command) { auto command_view = bluetooth::hci::ReadPageScanActivityView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Page Scan Activity"); + uint16_t interval = 0x1000; uint16_t window = 0x0012; send_event_(bluetooth::hci::ReadPageScanActivityCompleteBuilder::Create( @@ -1273,6 +1560,9 @@ void DualModeController::WritePageScanActivity(CommandView command) { auto command_view = bluetooth::hci::WritePageScanActivityView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Page Scan Activity"); + send_event_(bluetooth::hci::WritePageScanActivityCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1281,6 +1571,9 @@ void DualModeController::ReadInquiryScanActivity(CommandView command) { auto command_view = bluetooth::hci::ReadInquiryScanActivityView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Inquiry Scan Activity"); + uint16_t interval = 0x1000; uint16_t window = 0x0012; send_event_(bluetooth::hci::ReadInquiryScanActivityCompleteBuilder::Create( @@ -1291,6 +1584,9 @@ void DualModeController::WriteInquiryScanActivity(CommandView command) { auto command_view = bluetooth::hci::WriteInquiryScanActivityView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Inquiry Scan Activity"); + send_event_(bluetooth::hci::WriteInquiryScanActivityCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1299,6 +1595,8 @@ void DualModeController::ReadScanEnable(CommandView command) { auto command_view = bluetooth::hci::ReadScanEnableView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Scan Enable"); + bool inquiry_scan = link_layer_controller_.GetInquiryScanEnable(); bool page_scan = link_layer_controller_.GetPageScanEnable(); @@ -1316,7 +1614,6 @@ void DualModeController::ReadScanEnable(CommandView command) { void DualModeController::WriteScanEnable(CommandView command) { auto command_view = bluetooth::hci::WriteScanEnableView::Create(command); ASSERT(command_view.IsValid()); - bluetooth::hci::ScanEnable scan_enable = command_view.GetScanEnable(); bool inquiry_scan = scan_enable == bluetooth::hci::ScanEnable::INQUIRY_AND_PAGE_SCAN || @@ -1325,8 +1622,8 @@ void DualModeController::WriteScanEnable(CommandView command) { scan_enable == bluetooth::hci::ScanEnable::INQUIRY_AND_PAGE_SCAN || scan_enable == bluetooth::hci::ScanEnable::PAGE_SCAN_ONLY; - LOG_INFO("%s | WriteScanEnable %s", GetAddress().ToString().c_str(), - bluetooth::hci::ScanEnableText(scan_enable).c_str()); + DEBUG(id_, "<< Write Scan Enable"); + DEBUG(id_, " scan_enable={}", bluetooth::hci::ScanEnableText(scan_enable)); link_layer_controller_.SetInquiryScanEnable(inquiry_scan); link_layer_controller_.SetPageScanEnable(page_scan); @@ -1334,10 +1631,46 @@ void DualModeController::WriteScanEnable(CommandView command) { kNumCommandPackets, ErrorCode::SUCCESS)); } +void DualModeController::ReadTransmitPowerLevel(CommandView command) { + auto command_view = bluetooth::hci::ReadTransmitPowerLevelView::Create(command); + ASSERT(command_view.IsValid()); + uint16_t connection_handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< Read Transmit Power Level"); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); + + ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) + ? ErrorCode::SUCCESS + : ErrorCode::UNKNOWN_CONNECTION; + + send_event_(bluetooth::hci::ReadTransmitPowerLevelCompleteBuilder::Create( + kNumCommandPackets, status, connection_handle, kTransmitPowerLevel)); +} + +void DualModeController::ReadEnhancedTransmitPowerLevel(CommandView command) { + auto command_view = bluetooth::hci::ReadEnhancedTransmitPowerLevelView::Create(command); + ASSERT(command_view.IsValid()); + uint16_t connection_handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< Read Enhanced Transmit Power Level"); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); + + ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) + ? ErrorCode::SUCCESS + : ErrorCode::UNKNOWN_CONNECTION; + + send_event_(bluetooth::hci::ReadEnhancedTransmitPowerLevelCompleteBuilder::Create( + kNumCommandPackets, status, connection_handle, kTransmitPowerLevel, + kTransmitPowerLevel, kTransmitPowerLevel)); +} + void DualModeController::ReadSynchronousFlowControlEnable(CommandView command) { auto command_view = bluetooth::hci::ReadSynchronousFlowControlEnableView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Synchronous Flow Control Enable"); + auto enabled = bluetooth::hci::Enable::DISABLED; if (link_layer_controller_.GetScoFlowControlEnable()) { enabled = bluetooth::hci::Enable::ENABLED; @@ -1353,6 +1686,10 @@ void DualModeController::WriteSynchronousFlowControlEnable( bluetooth::hci::WriteSynchronousFlowControlEnableView::Create(command); ASSERT(command_view.IsValid()); auto enabled = command_view.GetEnable() == bluetooth::hci::Enable::ENABLED; + + DEBUG(id_, "<< Write Synchronous Flow Control Enable"); + DEBUG(id_, " enable={}", enabled); + link_layer_controller_.SetScoFlowControlEnable(enabled); send_event_( bluetooth::hci::WriteSynchronousFlowControlEnableCompleteBuilder::Create( @@ -1362,6 +1699,15 @@ void DualModeController::WriteSynchronousFlowControlEnable( void DualModeController::SetEventFilter(CommandView command) { auto command_view = bluetooth::hci::SetEventFilterView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Set Event Filter"); + DEBUG(id_, " filter_type={}", + bluetooth::hci::FilterTypeText(command_view.GetFilterType())); + + if (command_view.GetFilterType() != bluetooth::hci::FilterType::CLEAR_ALL_FILTERS) { + FATAL("unsupported event filter type"); + } + send_event_(bluetooth::hci::SetEventFilterCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } @@ -1371,6 +1717,11 @@ void DualModeController::Inquiry(CommandView command) { ASSERT(command_view.IsValid()); auto max_responses = command_view.GetNumResponses(); auto length = command_view.GetInquiryLength(); + + DEBUG(id_, "<< Inquiry"); + DEBUG(id_, " num_responses={}", max_responses); + DEBUG(id_, " inquiry_length={}", length); + if (max_responses > 0xff || length < 1 || length > 0x30) { send_event_(bluetooth::hci::InquiryStatusBuilder::Create( ErrorCode::INVALID_HCI_COMMAND_PARAMETERS, kNumCommandPackets)); @@ -1387,6 +1738,9 @@ void DualModeController::Inquiry(CommandView command) { void DualModeController::InquiryCancel(CommandView command) { auto command_view = bluetooth::hci::InquiryCancelView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Inquiry Cancel"); + link_layer_controller_.InquiryCancel(); send_event_(bluetooth::hci::InquiryCancelCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); @@ -1396,12 +1750,17 @@ void DualModeController::AcceptConnectionRequest(CommandView command) { auto command_view = bluetooth::hci::AcceptConnectionRequestView::Create(command); ASSERT(command_view.IsValid()); - Address addr = command_view.GetBdAddr(); + Address bd_addr = command_view.GetBdAddr(); bool try_role_switch = command_view.GetRole() == bluetooth::hci::AcceptConnectionRequestRole::BECOME_CENTRAL; + + DEBUG(id_, "<< Accept Connection Request"); + DEBUG(id_, " bd_addr={}", bd_addr); + DEBUG(id_, " try_role_switch={}", try_role_switch); + auto status = - link_layer_controller_.AcceptConnectionRequest(addr, try_role_switch); + link_layer_controller_.AcceptConnectionRequest(bd_addr, try_role_switch); send_event_(bluetooth::hci::AcceptConnectionRequestStatusBuilder::Create( status, kNumCommandPackets)); } @@ -1410,9 +1769,16 @@ void DualModeController::RejectConnectionRequest(CommandView command) { auto command_view = bluetooth::hci::RejectConnectionRequestView::Create(command); ASSERT(command_view.IsValid()); - Address addr = command_view.GetBdAddr(); - uint8_t reason = static_cast(command_view.GetReason()); - auto status = link_layer_controller_.RejectConnectionRequest(addr, reason); + Address bd_addr = command_view.GetBdAddr(); + auto reason = command_view.GetReason(); + + DEBUG(id_, "<< Reject Connection Request"); + DEBUG(id_, " bd_addr={}", bd_addr); + DEBUG(id_, " reason={}", + bluetooth::hci::RejectConnectionReasonText(reason)); + + auto status = link_layer_controller_.RejectConnectionRequest( + bd_addr, static_cast(reason)); send_event_(bluetooth::hci::RejectConnectionRequestStatusBuilder::Create( status, kNumCommandPackets)); } @@ -1421,6 +1787,8 @@ void DualModeController::DeleteStoredLinkKey(CommandView command) { auto command_view = bluetooth::hci::DeleteStoredLinkKeyView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Delete Stored Link Key"); + send_event_(bluetooth::hci::DeleteStoredLinkKeyCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, 0)); } @@ -1428,12 +1796,13 @@ void DualModeController::DeleteStoredLinkKey(CommandView command) { void DualModeController::RemoteNameRequest(CommandView command) { auto command_view = bluetooth::hci::RemoteNameRequestView::Create(command); ASSERT(command_view.IsValid()); + Address bd_addr = command_view.GetBdAddr(); - Address remote_addr = command_view.GetBdAddr(); + DEBUG(id_, "<< Remote Name Request"); + DEBUG(id_, " bd_addr={}", bd_addr); auto status = link_layer_controller_.SendCommandToRemoteByAddress( - OpCode::REMOTE_NAME_REQUEST, command_view.GetPayload(), GetAddress(), - remote_addr); + OpCode::REMOTE_NAME_REQUEST, command_view.bytes(), GetAddress(), bd_addr); send_event_(bluetooth::hci::RemoteNameRequestStatusBuilder::Create( status, kNumCommandPackets)); @@ -1442,18 +1811,59 @@ void DualModeController::RemoteNameRequest(CommandView command) { void DualModeController::LeSetEventMask(CommandView command) { auto command_view = bluetooth::hci::LeSetEventMaskView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Event Mask"); + DEBUG(id_, " le_event_mask=0x{:x}", command_view.GetLeEventMask()); + link_layer_controller_.SetLeEventMask(command_view.GetLeEventMask()); send_event_(bluetooth::hci::LeSetEventMaskCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS)); } +void DualModeController::LeRequestPeerSca(CommandView command) { + auto command_view = bluetooth::hci::LeRequestPeerScaView::Create(command); + ASSERT(command_view.IsValid()); + uint16_t connection_handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< LE Request Peer SCA"); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); + + // If the Host sends this command and the peer device does not support the + // Sleep Clock Accuracy Updates feature, the Controller shall return the error + // code Unsupported Feature or Parameter Value (0x11) in the HCI_LE_- + // Request_Peer_SCA_Complete event. + // TODO + + // If the Host issues this command when the Controller is aware (e.g., through + // a previous feature exchange) that the peer device's Link Layer does not + // support the Sleep Clock Accuracy Updates feature, the Controller shall + // return the error code Unsupported Remote Feature (0x1A). + // TODO + + if (link_layer_controller_.HasAclConnection(connection_handle)) { + send_event_(bluetooth::hci::LeRequestPeerScaStatusBuilder::Create( + ErrorCode::SUCCESS, kNumCommandPackets)); + send_event_(bluetooth::hci::LeRequestPeerScaCompleteBuilder::Create( + ErrorCode::SUCCESS, connection_handle, + bluetooth::hci::ClockAccuracy::PPM_500)); + } else { + send_event_(bluetooth::hci::LeRequestPeerScaStatusBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, kNumCommandPackets)); + } +} + void DualModeController::LeSetHostFeature(CommandView command) { auto command_view = bluetooth::hci::LeSetHostFeatureView::Create(command); ASSERT(command_view.IsValid()); + uint8_t bit_number = static_cast(command_view.GetBitNumber()); + uint8_t bit_value = static_cast(command_view.GetBitValue()); - ErrorCode status = link_layer_controller_.LeSetHostFeature( - static_cast(command_view.GetBitNumber()), - static_cast(command_view.GetBitValue())); + DEBUG(id_, "<< LE Set Host Feature"); + DEBUG(id_, " bit_number={}", bit_number); + DEBUG(id_, " bit_value={}", bit_value); + + ErrorCode status = + link_layer_controller_.LeSetHostFeature(bit_number, bit_value); send_event_(bluetooth::hci::LeSetHostFeatureCompleteBuilder::Create( kNumCommandPackets, status)); } @@ -1462,6 +1872,8 @@ void DualModeController::LeReadBufferSizeV1(CommandView command) { auto command_view = bluetooth::hci::LeReadBufferSizeV1View::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< LE Read Buffer Size V1"); + bluetooth::hci::LeBufferSize le_buffer_size; le_buffer_size.le_data_packet_length_ = properties_.le_acl_data_packet_length; le_buffer_size.total_num_le_packets_ = @@ -1475,6 +1887,8 @@ void DualModeController::LeReadBufferSizeV2(CommandView command) { auto command_view = bluetooth::hci::LeReadBufferSizeV2View::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< LE Read Buffer Size V2"); + bluetooth::hci::LeBufferSize le_buffer_size; le_buffer_size.le_data_packet_length_ = properties_.le_acl_data_packet_length; le_buffer_size.total_num_le_packets_ = @@ -1492,6 +1906,12 @@ void DualModeController::LeSetAddressResolutionEnable(CommandView command) { auto command_view = bluetooth::hci::LeSetAddressResolutionEnableView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Address Resolution Enable"); + DEBUG(id_, " address_resolution_enable={}", + command_view.GetAddressResolutionEnable() == + bluetooth::hci::Enable::ENABLED); + ErrorCode status = link_layer_controller_.LeSetAddressResolutionEnable( command_view.GetAddressResolutionEnable() == bluetooth::hci::Enable::ENABLED); @@ -1505,6 +1925,9 @@ void DualModeController::LeSetResolvablePrivateAddressTimeout( auto command_view = bluetooth::hci::LeSetResolvablePrivateAddressTimeoutView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Resolvable Private Address Timeout"); + ErrorCode status = link_layer_controller_.LeSetResolvablePrivateAddressTimeout( command_view.GetRpaTimeout()); @@ -1517,18 +1940,22 @@ void DualModeController::LeReadLocalSupportedFeatures(CommandView command) { auto command_view = bluetooth::hci::LeReadLocalSupportedFeaturesView::Create(command); ASSERT(command_view.IsValid()); - LOG_INFO("%s | LeReadLocalSupportedFeatures (%016llx)", - GetAddress().ToString().c_str(), - static_cast(properties_.le_features)); + DEBUG(id_, "<< LE Read Local Supported Features"); + + uint64_t le_features = link_layer_controller_.GetLeSupportedFeatures(); send_event_( bluetooth::hci::LeReadLocalSupportedFeaturesCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, properties_.le_features)); + kNumCommandPackets, ErrorCode::SUCCESS, le_features)); } void DualModeController::LeSetRandomAddress(CommandView command) { auto command_view = bluetooth::hci::LeSetRandomAddressView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Random Address"); + DEBUG(id_, " random_address={}", command_view.GetRandomAddress()); + ErrorCode status = link_layer_controller_.LeSetRandomAddress( command_view.GetRandomAddress()); send_event_(bluetooth::hci::LeSetRandomAddressCompleteBuilder::Create( @@ -1539,6 +1966,9 @@ void DualModeController::LeSetAdvertisingParameters(CommandView command) { auto command_view = bluetooth::hci::LeSetAdvertisingParametersView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Advertising Parameters"); + ErrorCode status = link_layer_controller_.LeSetAdvertisingParameters( command_view.GetAdvertisingIntervalMin(), command_view.GetAdvertisingIntervalMax(), @@ -1556,6 +1986,9 @@ void DualModeController::LeReadAdvertisingPhysicalChannelTxPower( bluetooth::hci::LeReadAdvertisingPhysicalChannelTxPowerView::Create( command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Physical Channel Tx Power"); + send_event_( bluetooth::hci::LeReadAdvertisingPhysicalChannelTxPowerCompleteBuilder:: Create(kNumCommandPackets, ErrorCode::SUCCESS, @@ -1563,9 +1996,11 @@ void DualModeController::LeReadAdvertisingPhysicalChannelTxPower( } void DualModeController::LeSetAdvertisingData(CommandView command) { - auto command_view = - bluetooth::hci::LeSetAdvertisingDataRawView::Create(command); + auto command_view = bluetooth::hci::LeSetAdvertisingDataView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Advertising Data"); + ErrorCode status = link_layer_controller_.LeSetAdvertisingData( command_view.GetAdvertisingData()); send_event_(bluetooth::hci::LeSetAdvertisingDataCompleteBuilder::Create( @@ -1574,8 +2009,11 @@ void DualModeController::LeSetAdvertisingData(CommandView command) { void DualModeController::LeSetScanResponseData(CommandView command) { auto command_view = - bluetooth::hci::LeSetScanResponseDataRawView::Create(command); + bluetooth::hci::LeSetScanResponseDataView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Scan Response Data"); + ErrorCode status = link_layer_controller_.LeSetScanResponseData( command_view.GetAdvertisingData()); send_event_(bluetooth::hci::LeSetScanResponseDataCompleteBuilder::Create( @@ -1587,9 +2025,9 @@ void DualModeController::LeSetAdvertisingEnable(CommandView command) { bluetooth::hci::LeSetAdvertisingEnableView::Create(command); ASSERT(command_view.IsValid()); - LOG_INFO( - "%s | LeSetAdvertisingEnable (%d)", GetAddress().ToString().c_str(), - command_view.GetAdvertisingEnable() == bluetooth::hci::Enable::ENABLED); + DEBUG(id_, "<< LE Set Advertising Enable"); + DEBUG(id_, " advertising_enable={}", + command_view.GetAdvertisingEnable() == bluetooth::hci::Enable::ENABLED); ErrorCode status = link_layer_controller_.LeSetAdvertisingEnable( command_view.GetAdvertisingEnable() == bluetooth::hci::Enable::ENABLED); @@ -1601,6 +2039,8 @@ void DualModeController::LeSetScanParameters(CommandView command) { auto command_view = bluetooth::hci::LeSetScanParametersView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< LE Set Scan Parameters"); + ErrorCode status = link_layer_controller_.LeSetScanParameters( command_view.GetLeScanType(), command_view.GetLeScanInterval(), command_view.GetLeScanWindow(), command_view.GetOwnAddressType(), @@ -1613,8 +2053,9 @@ void DualModeController::LeSetScanEnable(CommandView command) { auto command_view = bluetooth::hci::LeSetScanEnableView::Create(command); ASSERT(command_view.IsValid()); - LOG_INFO("%s | LeSetScanEnable (%d)", GetAddress().ToString().c_str(), - command_view.GetLeScanEnable() == bluetooth::hci::Enable::ENABLED); + DEBUG(id_, "<< LE Set Scan Enable"); + DEBUG(id_, " scan_enable={}", + command_view.GetLeScanEnable() == bluetooth::hci::Enable::ENABLED); ErrorCode status = link_layer_controller_.LeSetScanEnable( command_view.GetLeScanEnable() == bluetooth::hci::Enable::ENABLED, @@ -1626,6 +2067,17 @@ void DualModeController::LeSetScanEnable(CommandView command) { void DualModeController::LeCreateConnection(CommandView command) { auto command_view = bluetooth::hci::LeCreateConnectionView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Create Connection"); + DEBUG(id_, " peer_address={}", command_view.GetPeerAddress()); + DEBUG(id_, " peer_address_type={}", + bluetooth::hci::AddressTypeText(command_view.GetPeerAddressType())); + DEBUG(id_, " own_address_type={}", + bluetooth::hci::OwnAddressTypeText(command_view.GetOwnAddressType())); + DEBUG(id_, " initiator_filter_policy={}", + bluetooth::hci::InitiatorFilterPolicyText( + command_view.GetInitiatorFilterPolicy())); + ErrorCode status = link_layer_controller_.LeCreateConnection( command_view.GetLeScanInterval(), command_view.GetLeScanWindow(), command_view.GetInitiatorFilterPolicy(), @@ -1633,10 +2085,10 @@ void DualModeController::LeCreateConnection(CommandView command) { command_view.GetPeerAddress(), command_view.GetPeerAddressType(), }, - command_view.GetOwnAddressType(), command_view.GetConnIntervalMin(), - command_view.GetConnIntervalMax(), command_view.GetConnLatency(), - command_view.GetSupervisionTimeout(), command_view.GetMinimumCeLength(), - command_view.GetMaximumCeLength()); + command_view.GetOwnAddressType(), command_view.GetConnectionIntervalMin(), + command_view.GetConnectionIntervalMax(), command_view.GetMaxLatency(), + command_view.GetSupervisionTimeout(), command_view.GetMinCeLength(), + command_view.GetMaxCeLength()); send_event_(bluetooth::hci::LeCreateConnectionStatusBuilder::Create( status, kNumCommandPackets)); } @@ -1645,6 +2097,9 @@ void DualModeController::LeCreateConnectionCancel(CommandView command) { auto command_view = bluetooth::hci::LeCreateConnectionCancelView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Create Connection Cancel"); + ErrorCode status = link_layer_controller_.LeCreateConnectionCancel(); send_event_(bluetooth::hci::LeCreateConnectionCancelCompleteBuilder::Create( kNumCommandPackets, status)); @@ -1653,9 +2108,14 @@ void DualModeController::LeCreateConnectionCancel(CommandView command) { void DualModeController::LeConnectionUpdate(CommandView command) { auto command_view = bluetooth::hci::LeConnectionUpdateView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Connection Update"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + ErrorCode status = link_layer_controller_.LeConnectionUpdate( - command_view.GetConnectionHandle(), command_view.GetConnIntervalMin(), - command_view.GetConnIntervalMax(), command_view.GetConnLatency(), + command_view.GetConnectionHandle(), + command_view.GetConnectionIntervalMin(), + command_view.GetConnectionIntervalMax(), command_view.GetMaxLatency(), command_view.GetSupervisionTimeout()); send_event_(bluetooth::hci::LeConnectionUpdateStatusBuilder::Create( @@ -1665,8 +2125,7 @@ void DualModeController::LeConnectionUpdate(CommandView command) { void DualModeController::CreateConnection(CommandView command) { auto command_view = bluetooth::hci::CreateConnectionView::Create(command); ASSERT(command_view.IsValid()); - - Address address = command_view.GetBdAddr(); + Address bd_addr = command_view.GetBdAddr(); uint16_t packet_type = command_view.GetPacketType(); uint8_t page_scan_mode = static_cast(command_view.GetPageScanRepetitionMode()); @@ -1677,8 +2136,14 @@ void DualModeController::CreateConnection(CommandView command) { uint8_t allow_role_switch = static_cast(command_view.GetAllowRoleSwitch()); + DEBUG(id_, "<< Create Connection"); + DEBUG(id_, " bd_addr={}", bd_addr); + DEBUG(id_, " allow_role_switch={}", + command_view.GetAllowRoleSwitch() == + bluetooth::hci::CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH); + auto status = link_layer_controller_.CreateConnection( - address, packet_type, page_scan_mode, clock_offset, allow_role_switch); + bd_addr, packet_type, page_scan_mode, clock_offset, allow_role_switch); send_event_(bluetooth::hci::CreateConnectionStatusBuilder::Create( status, kNumCommandPackets)); @@ -1688,9 +2153,11 @@ void DualModeController::CreateConnectionCancel(CommandView command) { auto command_view = bluetooth::hci::CreateConnectionCancelView::Create(command); ASSERT(command_view.IsValid()); - Address address = command_view.GetBdAddr(); + DEBUG(id_, "<< Create Connection Cancel"); + DEBUG(id_, " bd_addr={}", address); + auto status = link_layer_controller_.CreateConnectionCancel(address); send_event_(bluetooth::hci::CreateConnectionCancelCompleteBuilder::Create( @@ -1700,20 +2167,30 @@ void DualModeController::CreateConnectionCancel(CommandView command) { void DualModeController::Disconnect(CommandView command) { auto command_view = bluetooth::hci::DisconnectView::Create(command); ASSERT(command_view.IsValid()); + uint16_t connection_handle = command_view.GetConnectionHandle(); - uint16_t handle = command_view.GetConnectionHandle(); + DEBUG(id_, "<< Disconnect"); + DEBUG(id_, " connection_handle=0x{:x}", connection_handle); - auto status = link_layer_controller_.Disconnect( - handle, ErrorCode(command_view.GetReason())); + if (connection_handle >= kCisHandleRangeStart && + connection_handle < kCisHandleRangeEnd) { + link_layer_controller_.ForwardToLl(command); + } else { + auto status = link_layer_controller_.Disconnect( + connection_handle, ErrorCode(command_view.GetReason())); - send_event_(bluetooth::hci::DisconnectStatusBuilder::Create( - status, kNumCommandPackets)); + send_event_(bluetooth::hci::DisconnectStatusBuilder::Create( + status, kNumCommandPackets)); + } } void DualModeController::LeReadFilterAcceptListSize(CommandView command) { auto command_view = bluetooth::hci::LeReadFilterAcceptListSizeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Filter Accept List Size"); + send_event_(bluetooth::hci::LeReadFilterAcceptListSizeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, properties_.le_filter_accept_list_size)); @@ -1723,6 +2200,9 @@ void DualModeController::LeClearFilterAcceptList(CommandView command) { auto command_view = bluetooth::hci::LeClearFilterAcceptListView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Clear Filter Accept List"); + ErrorCode status = link_layer_controller_.LeClearFilterAcceptList(); send_event_(bluetooth::hci::LeClearFilterAcceptListCompleteBuilder::Create( kNumCommandPackets, status)); @@ -1732,6 +2212,13 @@ void DualModeController::LeAddDeviceToFilterAcceptList(CommandView command) { auto command_view = bluetooth::hci::LeAddDeviceToFilterAcceptListView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Add Device To Filter Accept List"); + DEBUG(id_, " address={}", command_view.GetAddress()); + DEBUG(id_, " address_type={}", + bluetooth::hci::FilterAcceptListAddressTypeText( + command_view.GetAddressType())); + ErrorCode status = link_layer_controller_.LeAddDeviceToFilterAcceptList( command_view.GetAddressType(), command_view.GetAddress()); send_event_( @@ -1744,6 +2231,13 @@ void DualModeController::LeRemoveDeviceFromFilterAcceptList( auto command_view = bluetooth::hci::LeRemoveDeviceFromFilterAcceptListView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Remove Device From Filter Accept List"); + DEBUG(id_, " address={}", command_view.GetAddress()); + DEBUG(id_, " address_type={}", + bluetooth::hci::FilterAcceptListAddressTypeText( + command_view.GetAddressType())); + ErrorCode status = link_layer_controller_.LeRemoveDeviceFromFilterAcceptList( command_view.GetAddressType(), command_view.GetAddress()); send_event_( @@ -1754,6 +2248,9 @@ void DualModeController::LeRemoveDeviceFromFilterAcceptList( void DualModeController::LeClearResolvingList(CommandView command) { auto command_view = bluetooth::hci::LeClearResolvingListView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Clear Resolving List"); + ErrorCode status = link_layer_controller_.LeClearResolvingList(); send_event_(bluetooth::hci::LeClearResolvingListCompleteBuilder::Create( kNumCommandPackets, status)); @@ -1763,6 +2260,9 @@ void DualModeController::LeReadResolvingListSize(CommandView command) { auto command_view = bluetooth::hci::LeReadResolvingListSizeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Resolving List Size"); + send_event_(bluetooth::hci::LeReadResolvingListSizeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, properties_.le_resolving_list_size)); @@ -1772,6 +2272,14 @@ void DualModeController::LeReadPeerResolvableAddress(CommandView command) { auto command_view = bluetooth::hci::LeReadPeerResolvableAddressView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Peer Resolvable Address"); + DEBUG(id_, " peer_identity_address={}", + command_view.GetPeerIdentityAddress()); + DEBUG(id_, " peer_identity_address_type={}", + bluetooth::hci::PeerAddressTypeText( + command_view.GetPeerIdentityAddressType())); + Address peer_resolvable_address; ErrorCode status = link_layer_controller_.LeReadPeerResolvableAddress( command_view.GetPeerIdentityAddressType(), @@ -1785,6 +2293,14 @@ void DualModeController::LeReadLocalResolvableAddress(CommandView command) { auto command_view = bluetooth::hci::LeReadLocalResolvableAddressView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Local Resolvable Address"); + DEBUG(id_, " peer_identity_address={}", + command_view.GetPeerIdentityAddress()); + DEBUG(id_, " peer_identity_address_type={}", + bluetooth::hci::PeerAddressTypeText( + command_view.GetPeerIdentityAddressType())); + Address local_resolvable_address; ErrorCode status = link_layer_controller_.LeReadLocalResolvableAddress( command_view.GetPeerIdentityAddressType(), @@ -1798,6 +2314,9 @@ void DualModeController::LeReadMaximumDataLength(CommandView command) { auto command_view = bluetooth::hci::LeReadMaximumDataLengthView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Maximum Data Length"); + bluetooth::hci::LeMaximumDataLength data_length; data_length.supported_max_rx_octets_ = kLeMaximumDataLength; data_length.supported_max_rx_time_ = kLeMaximumDataTime; @@ -1811,6 +2330,10 @@ void DualModeController::LeReadPhy(CommandView command) { auto command_view = bluetooth::hci::LeReadPhyView::Create(command); ASSERT(command_view.IsValid()); uint16_t connection_handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< LE Read Phy"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + bluetooth::hci::PhyType tx_phy{}; bluetooth::hci::PhyType rx_phy{}; ErrorCode status = @@ -1822,6 +2345,9 @@ void DualModeController::LeReadPhy(CommandView command) { void DualModeController::LeSetDefaultPhy(CommandView command) { auto command_view = bluetooth::hci::LeSetDefaultPhyView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Default Phy"); + ErrorCode status = link_layer_controller_.LeSetDefaultPhy( command_view.GetAllPhysNoTransmitPreference(), command_view.GetAllPhysNoReceivePreference(), command_view.GetTxPhys(), @@ -1833,6 +2359,10 @@ void DualModeController::LeSetDefaultPhy(CommandView command) { void DualModeController::LeSetPhy(CommandView command) { auto command_view = bluetooth::hci::LeSetPhyView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Phy"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + ErrorCode status = link_layer_controller_.LeSetPhy( command_view.GetConnectionHandle(), command_view.GetAllPhysNoTransmitPreference(), @@ -1846,6 +2376,9 @@ void DualModeController::LeReadSuggestedDefaultDataLength(CommandView command) { auto command_view = bluetooth::hci::LeReadSuggestedDefaultDataLengthView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Suggested Default Data Length"); + send_event_( bluetooth::hci::LeReadSuggestedDefaultDataLengthCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, @@ -1859,6 +2392,8 @@ void DualModeController::LeWriteSuggestedDefaultDataLength( bluetooth::hci::LeWriteSuggestedDefaultDataLengthView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< LE Write Suggested Default Data Length"); + uint16_t max_tx_octets = command_view.GetTxOctets(); uint16_t max_tx_time = command_view.GetTxTime(); ErrorCode status = ErrorCode::SUCCESS; @@ -1879,6 +2414,14 @@ void DualModeController::LeAddDeviceToResolvingList(CommandView command) { auto command_view = bluetooth::hci::LeAddDeviceToResolvingListView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Add Device to Resolving List"); + DEBUG(id_, " peer_identity_address={}", + command_view.GetPeerIdentityAddress()); + DEBUG(id_, " peer_identity_address_type={}", + bluetooth::hci::PeerAddressTypeText( + command_view.GetPeerIdentityAddressType())); + ErrorCode status = link_layer_controller_.LeAddDeviceToResolvingList( command_view.GetPeerIdentityAddressType(), command_view.GetPeerIdentityAddress(), command_view.GetPeerIrk(), @@ -1891,6 +2434,14 @@ void DualModeController::LeRemoveDeviceFromResolvingList(CommandView command) { auto command_view = bluetooth::hci::LeRemoveDeviceFromResolvingListView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Remove Device from Resolving List"); + DEBUG(id_, " peer_identity_address={}", + command_view.GetPeerIdentityAddress()); + DEBUG(id_, " peer_identity_address_type={}", + bluetooth::hci::PeerAddressTypeText( + command_view.GetPeerIdentityAddressType())); + ErrorCode status = link_layer_controller_.LeRemoveDeviceFromResolvingList( command_view.GetPeerIdentityAddressType(), command_view.GetPeerIdentityAddress()); @@ -1904,6 +2455,10 @@ void DualModeController::LeSetPeriodicAdvertisingParameters( auto command_view = bluetooth::hci::LeSetPeriodicAdvertisingParametersView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Periodic Advertising Parameters"); + DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); + ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingParameters( command_view.GetAdvertisingHandle(), command_view.GetPeriodicAdvertisingIntervalMin(), @@ -1916,8 +2471,12 @@ void DualModeController::LeSetPeriodicAdvertisingParameters( void DualModeController::LeSetPeriodicAdvertisingData(CommandView command) { auto command_view = - bluetooth::hci::LeSetPeriodicAdvertisingDataRawView::Create(command); + bluetooth::hci::LeSetPeriodicAdvertisingDataView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Periodic Advertising Data"); + DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); + ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingData( command_view.GetAdvertisingHandle(), command_view.GetOperation(), command_view.GetAdvertisingData()); @@ -1930,6 +2489,11 @@ void DualModeController::LeSetPeriodicAdvertisingEnable(CommandView command) { auto command_view = bluetooth::hci::LeSetPeriodicAdvertisingEnableView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Periodic Advertising Enable"); + DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); + DEBUG(id_, " enable={}", command_view.GetEnable() != 0); + ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingEnable( command_view.GetEnable(), command_view.GetIncludeAdi(), command_view.GetAdvertisingHandle()); @@ -1942,6 +2506,13 @@ void DualModeController::LePeriodicAdvertisingCreateSync(CommandView command) { auto command_view = bluetooth::hci::LePeriodicAdvertisingCreateSyncView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Periodic Advertising Create Sync"); + DEBUG(id_, " advertiser_address={}", command_view.GetAdvertiserAddress()); + DEBUG(id_, " advertiser_address_type={}", + bluetooth::hci::AdvertiserAddressTypeText( + command_view.GetAdvertiserAddressType())); + ErrorCode status = link_layer_controller_.LePeriodicAdvertisingCreateSync( command_view.GetOptions(), command_view.GetAdvertisingSid(), command_view.GetAdvertiserAddressType(), @@ -1958,6 +2529,9 @@ void DualModeController::LePeriodicAdvertisingCreateSyncCancel( bluetooth::hci::LePeriodicAdvertisingCreateSyncCancelView::Create( command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Periodic Advertising Create Sync Cancel"); + ErrorCode status = link_layer_controller_.LePeriodicAdvertisingCreateSyncCancel(); send_event_( @@ -1970,6 +2544,10 @@ void DualModeController::LePeriodicAdvertisingTerminateSync( auto command_view = bluetooth::hci::LePeriodicAdvertisingTerminateSyncView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Periodic Advertising Terminate Sync"); + DEBUG(id_, " sync_handle=0x{:x}", command_view.GetSyncHandle()); + ErrorCode status = link_layer_controller_.LePeriodicAdvertisingTerminateSync( command_view.GetSyncHandle()); send_event_( @@ -1982,6 +2560,13 @@ void DualModeController::LeAddDeviceToPeriodicAdvertiserList( auto command_view = bluetooth::hci::LeAddDeviceToPeriodicAdvertiserListView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Add Device to Periodic Advertiser List"); + DEBUG(id_, " advertiser_address={}", command_view.GetAdvertiserAddress()); + DEBUG(id_, " advertiser_address_type={}", + bluetooth::hci::AdvertiserAddressTypeText( + command_view.GetAdvertiserAddressType())); + ErrorCode status = link_layer_controller_.LeAddDeviceToPeriodicAdvertiserList( command_view.GetAdvertiserAddressType(), command_view.GetAdvertiserAddress(), command_view.GetAdvertisingSid()); @@ -1996,6 +2581,13 @@ void DualModeController::LeRemoveDeviceFromPeriodicAdvertiserList( bluetooth::hci::LeRemoveDeviceFromPeriodicAdvertiserListView::Create( command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Remove Device from Periodic Advertiser List"); + DEBUG(id_, " advertiser_address={}", command_view.GetAdvertiserAddress()); + DEBUG(id_, " advertiser_address_type={}", + bluetooth::hci::AdvertiserAddressTypeText( + command_view.GetAdvertiserAddressType())); + ErrorCode status = link_layer_controller_.LeRemoveDeviceFromPeriodicAdvertiserList( command_view.GetAdvertiserAddressType(), @@ -2010,6 +2602,9 @@ void DualModeController::LeClearPeriodicAdvertiserList(CommandView command) { auto command_view = bluetooth::hci::LeClearPeriodicAdvertiserListView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Clear Periodic Advertiser List"); + ErrorCode status = link_layer_controller_.LeClearPeriodicAdvertiserList(); send_event_( bluetooth::hci::LeClearPeriodicAdvertiserListCompleteBuilder::Create( @@ -2020,6 +2615,9 @@ void DualModeController::LeReadPeriodicAdvertiserListSize(CommandView command) { auto command_view = bluetooth::hci::LeReadPeriodicAdvertiserListSizeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Periodic Advertiser List Size"); + send_event_( bluetooth::hci::LeReadPeriodicAdvertiserListSizeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, @@ -2030,9 +2628,12 @@ void DualModeController::LeSetExtendedScanParameters(CommandView command) { auto command_view = bluetooth::hci::LeSetExtendedScanParametersView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Extended Scan Parameters"); + ErrorCode status = link_layer_controller_.LeSetExtendedScanParameters( command_view.GetOwnAddressType(), command_view.GetScanningFilterPolicy(), - command_view.GetScanningPhys(), command_view.GetParameters()); + command_view.GetScanningPhys(), command_view.GetScanningPhyParameters()); send_event_( bluetooth::hci::LeSetExtendedScanParametersCompleteBuilder::Create( kNumCommandPackets, status)); @@ -2042,6 +2643,11 @@ void DualModeController::LeSetExtendedScanEnable(CommandView command) { auto command_view = bluetooth::hci::LeSetExtendedScanEnableView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Extended Scan Enable"); + DEBUG(id_, " enable={}", + command_view.GetEnable() == bluetooth::hci::Enable::ENABLED); + ErrorCode status = link_layer_controller_.LeSetExtendedScanEnable( command_view.GetEnable() == bluetooth::hci::Enable::ENABLED, command_view.GetFilterDuplicates(), command_view.GetDuration(), @@ -2054,13 +2660,34 @@ void DualModeController::LeExtendedCreateConnection(CommandView command) { auto command_view = bluetooth::hci::LeExtendedCreateConnectionView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Extended Create Connection"); + DEBUG(id_, " peer_address={}", command_view.GetPeerAddress()); + DEBUG(id_, " peer_address_type={}", + bluetooth::hci::PeerAddressTypeText(command_view.GetPeerAddressType())); + DEBUG(id_, " initiator_filter_policy={}", + bluetooth::hci::InitiatorFilterPolicyText( + command_view.GetInitiatorFilterPolicy())); + + AddressType peer_address_type; + switch (command_view.GetPeerAddressType()) { + case PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS: + default: + peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS; + break; + case PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS: + peer_address_type = AddressType::RANDOM_DEVICE_ADDRESS; + break; + } + ErrorCode status = link_layer_controller_.LeExtendedCreateConnection( command_view.GetInitiatorFilterPolicy(), command_view.GetOwnAddressType(), AddressWithType{ command_view.GetPeerAddress(), - command_view.GetPeerAddressType(), + peer_address_type, }, - command_view.GetInitiatingPhys(), command_view.GetPhyScanParameters()); + command_view.GetInitiatingPhys(), + command_view.GetInitiatingPhyParameters()); send_event_(bluetooth::hci::LeExtendedCreateConnectionStatusBuilder::Create( status, kNumCommandPackets)); } @@ -2068,6 +2695,16 @@ void DualModeController::LeExtendedCreateConnection(CommandView command) { void DualModeController::LeSetPrivacyMode(CommandView command) { auto command_view = bluetooth::hci::LeSetPrivacyModeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Privacy Mode"); + DEBUG(id_, " peer_identity_address={}", + command_view.GetPeerIdentityAddress()); + DEBUG(id_, " peer_identity_address_type={}", + bluetooth::hci::PeerAddressTypeText( + command_view.GetPeerIdentityAddressType())); + DEBUG(id_, " privacy_mode={}", + bluetooth::hci::PrivacyModeText(command_view.GetPrivacyMode())); + ErrorCode status = link_layer_controller_.LeSetPrivacyMode( command_view.GetPeerIdentityAddressType(), command_view.GetPeerIdentityAddress(), command_view.GetPrivacyMode()); @@ -2075,132 +2712,16 @@ void DualModeController::LeSetPrivacyMode(CommandView command) { kNumCommandPackets, status)); } -void DualModeController::LeReadIsoTxSync(CommandView command) { - auto command_view = bluetooth::hci::LeReadIsoTxSyncView::Create(command); - ASSERT(command_view.IsValid()); - link_layer_controller_.LeReadIsoTxSync(command_view.GetConnectionHandle()); -} - -void DualModeController::LeSetCigParameters(CommandView command) { - auto command_view = bluetooth::hci::LeSetCigParametersView::Create(command); - ASSERT(command_view.IsValid()); - link_layer_controller_.LeSetCigParameters( - command_view.GetCigId(), command_view.GetSduIntervalMToS(), - command_view.GetSduIntervalSToM(), - command_view.GetPeripheralsClockAccuracy(), command_view.GetPacking(), - command_view.GetFraming(), command_view.GetMaxTransportLatencyMToS(), - command_view.GetMaxTransportLatencySToM(), command_view.GetCisConfig()); -} - -void DualModeController::LeCreateCis(CommandView command) { - auto command_view = bluetooth::hci::LeCreateCisView::Create(command); - ASSERT(command_view.IsValid()); - ErrorCode status = - link_layer_controller_.LeCreateCis(command_view.GetCisConfig()); - send_event_(bluetooth::hci::LeCreateCisStatusBuilder::Create( - status, kNumCommandPackets)); -} - -void DualModeController::LeRemoveCig(CommandView command) { - auto command_view = bluetooth::hci::LeRemoveCigView::Create(command); - ASSERT(command_view.IsValid()); - uint8_t cig = command_view.GetCigId(); - ErrorCode status = link_layer_controller_.LeRemoveCig(cig); - send_event_(bluetooth::hci::LeRemoveCigCompleteBuilder::Create( - kNumCommandPackets, status, cig)); -} - -void DualModeController::LeAcceptCisRequest(CommandView command) { - auto command_view = bluetooth::hci::LeAcceptCisRequestView::Create(command); - ASSERT(command_view.IsValid()); - ErrorCode status = link_layer_controller_.LeAcceptCisRequest( - command_view.GetConnectionHandle()); - send_event_(bluetooth::hci::LeAcceptCisRequestStatusBuilder::Create( - status, kNumCommandPackets)); -} - -void DualModeController::LeRejectCisRequest(CommandView command) { - auto command_view = bluetooth::hci::LeRejectCisRequestView::Create(command); - ASSERT(command_view.IsValid()); - link_layer_controller_.LeRejectCisRequest(command_view.GetConnectionHandle(), - command_view.GetReason()); -} - -void DualModeController::LeCreateBig(CommandView command) { - auto command_view = bluetooth::hci::LeCreateBigView::Create(command); - ASSERT(command_view.IsValid()); - ErrorCode status = link_layer_controller_.LeCreateBig( - command_view.GetBigHandle(), command_view.GetAdvertisingHandle(), - command_view.GetNumBis(), command_view.GetSduInterval(), - command_view.GetMaxSdu(), command_view.GetMaxTransportLatency(), - command_view.GetRtn(), command_view.GetPhy(), command_view.GetPacking(), - command_view.GetFraming(), command_view.GetEncryption(), - command_view.GetBroadcastCode()); - send_event_(bluetooth::hci::LeCreateBigStatusBuilder::Create( - status, kNumCommandPackets)); -} - -void DualModeController::LeTerminateBig(CommandView command) { - auto command_view = bluetooth::hci::LeTerminateBigView::Create(command); - ASSERT(command_view.IsValid()); - ErrorCode status = link_layer_controller_.LeTerminateBig( - command_view.GetBigHandle(), command_view.GetReason()); - send_event_(bluetooth::hci::LeTerminateBigStatusBuilder::Create( - status, kNumCommandPackets)); -} - -void DualModeController::LeBigCreateSync(CommandView command) { - auto command_view = bluetooth::hci::LeBigCreateSyncView::Create(command); - ASSERT(command_view.IsValid()); - ErrorCode status = link_layer_controller_.LeBigCreateSync( - command_view.GetBigHandle(), command_view.GetSyncHandle(), - command_view.GetEncryption(), command_view.GetBroadcastCode(), - command_view.GetMse(), command_view.GetBigSyncTimeout(), - command_view.GetBis()); - send_event_(bluetooth::hci::LeBigCreateSyncStatusBuilder::Create( - status, kNumCommandPackets)); -} - -void DualModeController::LeBigTerminateSync(CommandView command) { - auto command_view = bluetooth::hci::LeBigTerminateSyncView::Create(command); - ASSERT(command_view.IsValid()); - link_layer_controller_.LeBigTerminateSync(command_view.GetBigHandle()); -} - -void DualModeController::LeRequestPeerSca(CommandView command) { - auto command_view = bluetooth::hci::LeRequestPeerScaView::Create(command); - ASSERT(command_view.IsValid()); - ErrorCode status = link_layer_controller_.LeRequestPeerSca( - command_view.GetConnectionHandle()); - send_event_(bluetooth::hci::LeRequestPeerScaStatusBuilder::Create( - status, kNumCommandPackets)); -} - -void DualModeController::LeSetupIsoDataPath(CommandView command) { - auto command_view = bluetooth::hci::LeSetupIsoDataPathView::Create(command); - ASSERT(command_view.IsValid()); - link_layer_controller_.LeSetupIsoDataPath( - command_view.GetConnectionHandle(), command_view.GetDataPathDirection(), - command_view.GetDataPathId(), command_view.GetCodecId(), - command_view.GetControllerDelay(), command_view.GetCodecConfiguration()); -} - -void DualModeController::LeRemoveIsoDataPath(CommandView command) { - auto command_view = bluetooth::hci::LeRemoveIsoDataPathView::Create(command); - ASSERT(command_view.IsValid()); - link_layer_controller_.LeRemoveIsoDataPath( - command_view.GetConnectionHandle(), - command_view.GetRemoveDataPathDirection()); -} - void DualModeController::LeReadRemoteFeatures(CommandView command) { auto command_view = bluetooth::hci::LeReadRemoteFeaturesView::Create(command); ASSERT(command_view.IsValid()); - uint16_t handle = command_view.GetConnectionHandle(); + DEBUG(id_, "<< LE Read Remote Features"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + auto status = link_layer_controller_.SendCommandToRemoteByHandle( - OpCode::LE_READ_REMOTE_FEATURES, command_view.GetPayload(), handle); + OpCode::LE_READ_REMOTE_FEATURES, command_view.bytes(), handle); send_event_(bluetooth::hci::LeReadRemoteFeaturesStatusBuilder::Create( status, kNumCommandPackets)); @@ -2210,6 +2731,8 @@ void DualModeController::LeEncrypt(CommandView command) { auto command_view = bluetooth::hci::LeEncryptView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< LE Encrypt"); + auto encrypted_data = rootcanal::crypto::aes_128( command_view.GetKey(), command_view.GetPlaintextData()); @@ -2217,23 +2740,23 @@ void DualModeController::LeEncrypt(CommandView command) { kNumCommandPackets, ErrorCode::SUCCESS, encrypted_data)); } -static std::random_device rd{}; -static std::mt19937_64 s_mt{rd()}; - void DualModeController::LeRand(CommandView command) { auto command_view = bluetooth::hci::LeRandView::Create(command); ASSERT(command_view.IsValid()); - uint64_t random_val = s_mt(); + DEBUG(id_, "<< LE Rand"); send_event_(bluetooth::hci::LeRandCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, random_val)); + kNumCommandPackets, ErrorCode::SUCCESS, random_generator_())); } void DualModeController::LeReadSupportedStates(CommandView command) { auto command_view = bluetooth::hci::LeReadSupportedStatesView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Supported States"); + send_event_(bluetooth::hci::LeReadSupportedStatesCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, properties_.le_supported_states)); } @@ -2244,6 +2767,10 @@ void DualModeController::LeRemoteConnectionParameterRequestReply( bluetooth::hci::LeRemoteConnectionParameterRequestReplyView::Create( command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Remote Connection Parameters Request Reply"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto status = link_layer_controller_.LeRemoteConnectionParameterRequestReply( command_view.GetConnectionHandle(), command_view.GetIntervalMin(), command_view.GetIntervalMax(), command_view.GetTimeout(), @@ -2260,6 +2787,10 @@ void DualModeController::LeRemoteConnectionParameterRequestNegativeReply( auto command_view = bluetooth::hci:: LeRemoteConnectionParameterRequestNegativeReplyView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Remote Connection Parameters Request Negative Reply"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + auto status = link_layer_controller_.LeRemoteConnectionParameterRequestNegativeReply( command_view.GetConnectionHandle(), command_view.GetReason()); @@ -2271,8 +2802,8 @@ void DualModeController::LeRemoteConnectionParameterRequestNegativeReply( } void DualModeController::LeGetVendorCapabilities(CommandView command) { - auto command_view = bluetooth::hci::LeGetVendorCapabilitiesView::Create( - bluetooth::hci::VendorCommandView::Create(command)); + auto command_view = + bluetooth::hci::LeGetVendorCapabilitiesView::Create(command); ASSERT(command_view.IsValid()); if (!properties_.supports_le_get_vendor_capabilities_command) { @@ -2280,45 +2811,342 @@ void DualModeController::LeGetVendorCapabilities(CommandView command) { return; } - // Ensure a minimal size for vendor capabilities. - vector vendor_capabilities = properties_.le_vendor_capabilities; - if (vendor_capabilities.size() < 8) { - vendor_capabilities.resize(8); + DEBUG(id_, "<< LE Get Vendor Capabilities"); + + bluetooth::hci::VendorCapabilities_V_0_98 vendor_capabilities; + vendor_capabilities.total_scan_results_storage_ = 0; + vendor_capabilities.max_irk_list_sz_ = 16; + vendor_capabilities.filtering_support_ = + properties_.supports_le_apcf_vendor_command; + vendor_capabilities.max_filter_ = properties_.le_apcf_filter_list_size; + vendor_capabilities.activity_energy_info_support_ = 0; + vendor_capabilities.total_num_of_advt_tracked_ = + properties_.le_apcf_num_of_tracked_advertisers; + vendor_capabilities.extended_scan_support_ = 0; + vendor_capabilities.debug_logging_supported_ = 0; + vendor_capabilities.a2dp_source_offload_capability_mask_ = 0; + vendor_capabilities.bluetooth_quality_report_support_ = 0; + + send_event_(bluetooth::hci::LeGetVendorCapabilitiesCompleteBuilder::Create( + kNumCommandPackets, ErrorCode::SUCCESS, + vendor_capabilities.SerializeToBytes())); +} + +void DualModeController::LeBatchScan(CommandView command) { + auto command_view = bluetooth::hci::LeBatchScanView::Create(command); + ASSERT(command_view.IsValid()); + SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_BATCH_SCAN); +} + +void DualModeController::LeApcf(CommandView command) { + auto command_view = bluetooth::hci::LeApcfView::Create(command); + ASSERT(command_view.IsValid()); + + if (!properties_.supports_le_apcf_vendor_command) { + SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_APCF); + return; } - std::unique_ptr raw_builder_ptr = - std::make_unique(); - raw_builder_ptr->AddOctets1(static_cast(ErrorCode::SUCCESS)); - raw_builder_ptr->AddOctets(vendor_capabilities); + switch (command_view.GetApcfOpcode()) { + case bluetooth::hci::ApcfOpcode::ENABLE: { + auto subcommand_view = + bluetooth::hci::LeApcfEnableView::Create(command_view); + ASSERT(subcommand_view.IsValid()); - send_event_(bluetooth::hci::CommandCompleteBuilder::Create( - kNumCommandPackets, OpCode::LE_GET_VENDOR_CAPABILITIES, - std::move(raw_builder_ptr))); + DEBUG(id_, "<< LE APCF Enable"); + DEBUG(id_, " enable={}", subcommand_view.GetApcfEnable()); + + ErrorCode status = link_layer_controller_.LeApcfEnable( + subcommand_view.GetApcfEnable() == bluetooth::hci::Enable::ENABLED); + send_event_(bluetooth::hci::LeApcfEnableCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfEnable())); + break; + } + case bluetooth::hci::ApcfOpcode::SET_FILTERING_PARAMETERS: { + auto subcommand_view = + bluetooth::hci::LeApcfSetFilteringParametersView::Create( + command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Set Filtering Parameters"); + DEBUG(id_, " action={}", subcommand_view.GetApcfAction()); + + ErrorCode status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + uint8_t apcf_available_spaces = 0; + + switch (subcommand_view.GetApcfAction()) { + case bluetooth::hci::ApcfAction::ADD: { + auto subsubcommand_view = + bluetooth::hci::LeApcfAddFilteringParametersView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfAddFilteringParameters( + subsubcommand_view.GetApcfFilterIndex(), + subsubcommand_view.GetApcfFeatureSelection(), + subsubcommand_view.GetApcfListLogicType(), + subsubcommand_view.GetApcfFilterLogicType(), + subsubcommand_view.GetRssiHighThresh(), + subsubcommand_view.GetDeliveryMode(), + subsubcommand_view.GetOnfoundTimeout(), + subsubcommand_view.GetOnfoundTimeoutCnt(), + subsubcommand_view.GetRssiLowThresh(), + subsubcommand_view.GetOnlostTimeout(), + subsubcommand_view.GetNumOfTrackingEntries(), + &apcf_available_spaces); + break; + } + case bluetooth::hci::ApcfAction::DELETE: { + auto subsubcommand_view = + bluetooth::hci::LeApcfDeleteFilteringParametersView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfDeleteFilteringParameters( + subsubcommand_view.GetApcfFilterIndex(), &apcf_available_spaces); + break; + } + case bluetooth::hci::ApcfAction::CLEAR: { + auto subsubcommand_view = + bluetooth::hci::LeApcfClearFilteringParametersView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfClearFilteringParameters( + &apcf_available_spaces); + break; + } + default: + INFO(id_, "unknown apcf action {}", subcommand_view.GetApcfAction()); + break; + } + + send_event_( + bluetooth::hci::LeApcfSetFilteringParametersCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::BROADCASTER_ADDRESS: { + auto subcommand_view = + bluetooth::hci::LeApcfBroadcasterAddressView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Broadcaster Address"); + DEBUG(id_, " action={}", subcommand_view.GetApcfAction()); + + ErrorCode status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + uint8_t apcf_available_spaces = 0; + + switch (subcommand_view.GetApcfAction()) { + case bluetooth::hci::ApcfAction::ADD: { + auto subsubcommand_view = + bluetooth::hci::LeApcfAddBroadcasterAddressView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfBroadcasterAddress( + bluetooth::hci::ApcfAction::ADD, + subsubcommand_view.GetApcfFilterIndex(), + subsubcommand_view.GetApcfBroadcasterAddress(), + subsubcommand_view.GetApcfApplicationAddressType(), + &apcf_available_spaces); + break; + } + case bluetooth::hci::ApcfAction::DELETE: { + auto subsubcommand_view = + bluetooth::hci::LeApcfDeleteBroadcasterAddressView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfBroadcasterAddress( + bluetooth::hci::ApcfAction::DELETE, + subsubcommand_view.GetApcfFilterIndex(), + subsubcommand_view.GetApcfBroadcasterAddress(), + subsubcommand_view.GetApcfApplicationAddressType(), + &apcf_available_spaces); + break; + } + case bluetooth::hci::ApcfAction::CLEAR: { + auto subsubcommand_view = + bluetooth::hci::LeApcfClearBroadcasterAddressView::Create( + subcommand_view); + ASSERT(subsubcommand_view.IsValid()); + status = link_layer_controller_.LeApcfBroadcasterAddress( + bluetooth::hci::ApcfAction::CLEAR, + subsubcommand_view.GetApcfFilterIndex(), Address(), + bluetooth::hci::ApcfApplicationAddressType::NOT_APPLICABLE, + &apcf_available_spaces); + break; + } + default: + INFO(id_, "unknown apcf action {}", subcommand_view.GetApcfAction()); + break; + } + + send_event_( + bluetooth::hci::LeApcfBroadcasterAddressCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::SERVICE_UUID: { + auto subcommand_view = + bluetooth::hci::LeApcfServiceUuidView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Service UUID"); + DEBUG(id_, " action={}", subcommand_view.GetApcfAction()); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfServiceUuid( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetAcpfUuidData(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfServiceUuidCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::SERVICE_SOLICITATION_UUID: { + auto subcommand_view = + bluetooth::hci::LeApcfServiceSolicitationUuidView::Create( + command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Service Solicitation UUID"); + DEBUG(id_, " action={}", subcommand_view.GetApcfAction()); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfServiceSolicitationUuid( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetAcpfUuidData(), &apcf_available_spaces); + send_event_( + bluetooth::hci::LeApcfServiceSolicitationUuidCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::LOCAL_NAME: { + auto subcommand_view = + bluetooth::hci::LeApcfLocalNameView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Local Name"); + DEBUG(id_, " action={}", subcommand_view.GetApcfAction()); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfLocalName( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetApcfLocalName(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfLocalNameCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::MANUFACTURER_DATA: { + auto subcommand_view = + bluetooth::hci::LeApcfManufacturerDataView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Manufacturer Data"); + DEBUG(id_, " action={}", subcommand_view.GetApcfAction()); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfManufacturerData( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetApcfManufacturerData(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfManufacturerDataCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::SERVICE_DATA: { + auto subcommand_view = + bluetooth::hci::LeApcfServiceDataView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Service Data"); + DEBUG(id_, " action={}", subcommand_view.GetApcfAction()); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfServiceData( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetApcfServiceData(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfServiceDataCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::AD_TYPE_FILTER: { + auto subcommand_view = + bluetooth::hci::LeApcfAdTypeFilterView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF AD Type Filter"); + DEBUG(id_, " action={}", subcommand_view.GetApcfAction()); + + uint8_t apcf_available_spaces = 0; + ErrorCode status = link_layer_controller_.LeApcfAdTypeFilter( + subcommand_view.GetApcfAction(), subcommand_view.GetApcfFilterIndex(), + subcommand_view.GetApcfAdType(), subcommand_view.GetApcfAdData(), + subcommand_view.GetApcfAdDataMask(), &apcf_available_spaces); + send_event_(bluetooth::hci::LeApcfAdTypeFilterCompleteBuilder::Create( + kNumCommandPackets, status, subcommand_view.GetApcfAction(), + apcf_available_spaces)); + break; + } + case bluetooth::hci::ApcfOpcode::READ_EXTENDED_FEATURES: { + auto subcommand_view = + bluetooth::hci::LeApcfReadExtendedFeaturesView::Create(command_view); + ASSERT(subcommand_view.IsValid()); + + DEBUG(id_, "<< LE APCF Read Extended Features"); + + send_event_( + bluetooth::hci::LeApcfReadExtendedFeaturesCompleteBuilder::Create( + kNumCommandPackets, ErrorCode::SUCCESS, + kLeApcfTransportDiscoveryDataFilterSupported, + kLeApcfAdTypeFilterSupported)); + break; + } + default: + FATAL(id_, "unknown APCF opcode {}", command_view.GetApcfOpcode()); + } } -void DualModeController::LeMultiAdv(CommandView command) { - auto command_view = bluetooth::hci::LeMultiAdvtView::Create(command); +void DualModeController::LeGetControllerActivityEnergyInfo( + CommandView command) { + auto command_view = + bluetooth::hci::LeGetControllerActivityEnergyInfoView::Create(command); ASSERT(command_view.IsValid()); - SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_MULTI_ADVT); + SendCommandCompleteUnknownOpCodeEvent( + OpCode::LE_GET_CONTROLLER_ACTIVITY_ENERGY_INFO); } -void DualModeController::LeAdvertisingFilter(CommandView command) { - auto command_view = bluetooth::hci::LeAdvFilterView::Create(command); +void DualModeController::LeExSetScanParameters(CommandView command) { + auto command_view = + bluetooth::hci::LeExSetScanParametersView::Create(command); ASSERT(command_view.IsValid()); - SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_ADV_FILTER); + SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_EX_SET_SCAN_PARAMETERS); } -void DualModeController::LeEnergyInfo(CommandView command) { - auto command_view = bluetooth::hci::LeEnergyInfoView::Create( - bluetooth::hci::VendorCommandView::Create(command)); +void DualModeController::GetControllerDebugInfo(CommandView command) { + auto command_view = + bluetooth::hci::GetControllerDebugInfoView::Create(command); ASSERT(command_view.IsValid()); - SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_ENERGY_INFO); + + DEBUG(id_, "<< Get Controller Debug Info"); + + send_event_(bluetooth::hci::GetControllerDebugInfoCompleteBuilder::Create( + kNumCommandPackets, ErrorCode::SUCCESS)); } // CSR vendor command. // Implement the command specific to the CSR controller // used specifically by the PTS tool to pass certification tests. void DualModeController::CsrVendorCommand(CommandView command) { + if (!properties_.supports_csr_vendor_command) { + SendCommandCompleteUnknownOpCodeEvent(OpCode(CSR_VENDOR)); + return; + } + + DEBUG(id_, "<< CSR"); + // The byte order is little endian. // The command parameters are formatted as // @@ -2334,23 +3162,22 @@ void DualModeController::CsrVendorCommand(CommandView command) { // // BlueZ has a reference implementation of the CSR vendor command. - std::vector parameters(command.GetPayload().begin(), - command.GetPayload().end()); + std::vector parameters(command.GetPayload()); uint16_t type = 0; uint16_t length = 0; uint16_t varid = 0; if (parameters.empty()) { - LOG_INFO("Empty CSR vendor command"); + INFO(id_, "Empty CSR vendor command"); goto complete; } if (parameters[0] != 0xc2 || parameters.size() < 11) { - LOG_INFO( - "Unsupported CSR vendor command with code %02x " - "and parameter length %zu", - static_cast(parameters[0]), parameters.size()); + INFO(id_, + "Unsupported CSR vendor command with code {:02x} " + "and parameter length {}", + static_cast(parameters[0]), parameters.size()); goto complete; } @@ -2361,8 +3188,8 @@ void DualModeController::CsrVendorCommand(CommandView command) { if (parameters.size() < (11 + length) || (varid == CsrVarid::CSR_VARID_PS && length < 6)) { - LOG_INFO("Invalid CSR vendor command parameter length %zu, expected %u", - parameters.size(), 11 + length); + INFO(id_, "Invalid CSR vendor command parameter length {}, expected {}", + parameters.size(), 11 + length); goto complete; } @@ -2375,16 +3202,16 @@ void DualModeController::CsrVendorCommand(CommandView command) { length = 2 * length; if (parameters.size() < (17 + length)) { - LOG_INFO("Invalid CSR vendor command parameter length %zu, expected %u", - parameters.size(), 17 + length); + INFO(id_, "Invalid CSR vendor command parameter length {}, expected {}", + parameters.size(), 17 + length); goto complete; } std::vector value(parameters.begin() + 17, parameters.begin() + 17 + length); - LOG_INFO("CSR vendor command type=%04x length=%04x pskey=%04x", type, - length, pskey); + INFO(id_, "CSR vendor command type={:04x} length={:04x} pskey={:04x}", type, + length, pskey); if (type == 0) { CsrReadPskey(static_cast(pskey), value); @@ -2398,8 +3225,8 @@ void DualModeController::CsrVendorCommand(CommandView command) { std::vector value(parameters.begin() + 11, parameters.begin() + 11 + length); - LOG_INFO("CSR vendor command type=%04x length=%04x varid=%04x", type, - length, varid); + INFO(id_, "CSR vendor command type={:04x} length={:04x} varid={:04x}", type, + length, varid); if (type == 0) { CsrReadVarid(static_cast(varid), value); @@ -2414,13 +3241,11 @@ complete: parameters[1] = 0x1; parameters[2] = 0x0; send_event_(bluetooth::hci::EventBuilder::Create( - bluetooth::hci::EventCode::VENDOR_SPECIFIC, - std::make_unique(std::move(parameters)))); + bluetooth::hci::EventCode::VENDOR_SPECIFIC, std::move(parameters))); } -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) void DualModeController::CsrReadVarid(CsrVarid varid, - std::vector& value) { + std::vector& value) const { switch (varid) { case CsrVarid::CSR_VARID_BUILDID: // Return the extact Build ID returned by the official PTS dongle. @@ -2430,20 +3255,18 @@ void DualModeController::CsrReadVarid(CsrVarid varid, break; default: - LOG_INFO("Unsupported read of CSR varid 0x%04x", varid); + INFO(id_, "Unsupported read of CSR varid 0x{:04x}", varid); break; } } -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -void DualModeController::CsrWriteVarid(CsrVarid varid, - std::vector const& value) { - LOG_INFO("Unsupported write of CSR varid 0x%04x", varid); +void DualModeController::CsrWriteVarid( + CsrVarid varid, std::vector const& /*value*/) const { + INFO(id_, "Unsupported write of CSR varid 0x{:04x}", varid); } -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) void DualModeController::CsrReadPskey(CsrPskey pskey, - std::vector& value) { + std::vector& value) const { switch (pskey) { case CsrPskey::CSR_PSKEY_ENC_KEY_LMIN: ASSERT(!value.empty()); @@ -2463,7 +3286,7 @@ void DualModeController::CsrReadPskey(CsrPskey pskey, break; default: - LOG_INFO("Unsupported read of CSR pskey 0x%04x", pskey); + INFO(id_, "Unsupported read of CSR pskey 0x{:04x}", pskey); break; } } @@ -2473,7 +3296,7 @@ void DualModeController::CsrWritePskey(CsrPskey pskey, switch (pskey) { case CsrPskey::CSR_PSKEY_LOCAL_SUPPORTED_FEATURES: ASSERT(value.size() >= 8); - LOG_INFO("CSR Vendor updating the Local Supported Features"); + INFO(id_, "CSR Vendor updating the Local Supported Features"); properties_.lmp_features[0] = ((uint64_t)value[0] << 0) | ((uint64_t)value[1] << 8) | ((uint64_t)value[2] << 16) | ((uint64_t)value[3] << 24) | @@ -2482,7 +3305,7 @@ void DualModeController::CsrWritePskey(CsrPskey pskey, break; default: - LOG_INFO("Unsupported write of CSR pskey 0x%04x", pskey); + INFO(id_, "Unsupported write of CSR pskey 0x{:04x}", pskey); break; } } @@ -2491,6 +3314,11 @@ void DualModeController::LeSetAdvertisingSetRandomAddress(CommandView command) { auto command_view = bluetooth::hci::LeSetAdvertisingSetRandomAddressView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Advertising Set Random Address"); + DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); + DEBUG(id_, " random_address={}", command_view.GetRandomAddress()); + ErrorCode status = link_layer_controller_.LeSetAdvertisingSetRandomAddress( command_view.GetAdvertisingHandle(), command_view.GetRandomAddress()); send_event_( @@ -2503,6 +3331,10 @@ void DualModeController::LeSetExtendedAdvertisingParameters( auto command_view = bluetooth::hci::LeSetExtendedAdvertisingParametersView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Extended Advertising Parameters"); + DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); + ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingParameters( command_view.GetAdvertisingHandle(), command_view.GetAdvertisingEventProperties(), @@ -2528,13 +3360,13 @@ void DualModeController::LeSetExtendedAdvertisingData(CommandView command) { auto command_view = bluetooth::hci::LeSetExtendedAdvertisingDataView::Create(command); ASSERT(command_view.IsValid()); - auto raw_command_view = - bluetooth::hci::LeSetExtendedAdvertisingDataRawView::Create(command); - ASSERT(raw_command_view.IsValid()); + + DEBUG(id_, "<< LE Set Extended Advertising Data"); + DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); + ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingData( command_view.GetAdvertisingHandle(), command_view.GetOperation(), - command_view.GetFragmentPreference(), - raw_command_view.GetAdvertisingData()); + command_view.GetFragmentPreference(), command_view.GetAdvertisingData()); send_event_( bluetooth::hci::LeSetExtendedAdvertisingDataCompleteBuilder::Create( kNumCommandPackets, status)); @@ -2544,13 +3376,13 @@ void DualModeController::LeSetExtendedScanResponseData(CommandView command) { auto command_view = bluetooth::hci::LeSetExtendedScanResponseDataView::Create(command); ASSERT(command_view.IsValid()); - auto raw_command_view = - bluetooth::hci::LeSetExtendedScanResponseDataRawView::Create(command); - ASSERT(raw_command_view.IsValid()); + + DEBUG(id_, "<< LE Set Extended Scan Response Data"); + DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); + ErrorCode status = link_layer_controller_.LeSetExtendedScanResponseData( command_view.GetAdvertisingHandle(), command_view.GetOperation(), - command_view.GetFragmentPreference(), - raw_command_view.GetScanResponseData()); + command_view.GetFragmentPreference(), command_view.GetScanResponseData()); send_event_( bluetooth::hci::LeSetExtendedScanResponseDataCompleteBuilder::Create( kNumCommandPackets, status)); @@ -2560,6 +3392,14 @@ void DualModeController::LeSetExtendedAdvertisingEnable(CommandView command) { auto command_view = bluetooth::hci::LeSetExtendedAdvertisingEnableView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Set Extended Advertising Enable"); + DEBUG(id_, " enable={}", + command_view.GetEnable() == bluetooth::hci::Enable::ENABLED); + for (auto const& set : command_view.GetEnabledSets()) { + DEBUG(id_, " advertising_handle={}", set.advertising_handle_); + } + ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingEnable( command_view.GetEnable() == bluetooth::hci::Enable::ENABLED, command_view.GetEnabledSets()); @@ -2573,6 +3413,9 @@ void DualModeController::LeReadMaximumAdvertisingDataLength( auto command_view = bluetooth::hci::LeReadMaximumAdvertisingDataLengthView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Maximum Advertising Data Length"); + send_event_( bluetooth::hci::LeReadMaximumAdvertisingDataLengthCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, @@ -2585,6 +3428,9 @@ void DualModeController::LeReadNumberOfSupportedAdvertisingSets( bluetooth::hci::LeReadNumberOfSupportedAdvertisingSetsView::Create( command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Read Number of Supported Advertising Sets"); + send_event_( bluetooth::hci::LeReadNumberOfSupportedAdvertisingSetsCompleteBuilder:: Create(kNumCommandPackets, ErrorCode::SUCCESS, @@ -2595,6 +3441,10 @@ void DualModeController::LeRemoveAdvertisingSet(CommandView command) { auto command_view = bluetooth::hci::LeRemoveAdvertisingSetView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Remove Advertising Set"); + DEBUG(id_, " advertising_handle={}", command_view.GetAdvertisingHandle()); + auto status = link_layer_controller_.LeRemoveAdvertisingSet( command_view.GetAdvertisingHandle()); send_event_(bluetooth::hci::LeRemoveAdvertisingSetCompleteBuilder::Create( @@ -2605,21 +3455,21 @@ void DualModeController::LeClearAdvertisingSets(CommandView command) { auto command_view = bluetooth::hci::LeClearAdvertisingSetsView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< LE Clear Advertising Sets"); + auto status = link_layer_controller_.LeClearAdvertisingSets(); send_event_(bluetooth::hci::LeClearAdvertisingSetsCompleteBuilder::Create( kNumCommandPackets, status)); } -void DualModeController::LeExtendedScanParams(CommandView command) { - auto command_view = bluetooth::hci::LeExtendedScanParamsView::Create(command); - ASSERT(command_view.IsValid()); - SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_EXTENDED_SCAN_PARAMS); -} - void DualModeController::LeStartEncryption(CommandView command) { auto command_view = bluetooth::hci::LeStartEncryptionView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< LE Start Encryption"); + DEBUG(id_, " connection_handle=0x{:x}", command_view.GetConnectionHandle()); + ErrorCode status = link_layer_controller_.LeEnableEncryption( command_view.GetConnectionHandle(), command_view.GetRand(), command_view.GetEdiv(), command_view.GetLtk()); @@ -2632,8 +3482,11 @@ void DualModeController::LeLongTermKeyRequestReply(CommandView command) { auto command_view = bluetooth::hci::LeLongTermKeyRequestReplyView::Create(command); ASSERT(command_view.IsValid()); - uint16_t handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< LE Long Term Key Request Reply"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + ErrorCode status = link_layer_controller_.LeLongTermKeyRequestReply( handle, command_view.GetLongTermKey()); @@ -2646,8 +3499,11 @@ void DualModeController::LeLongTermKeyRequestNegativeReply( auto command_view = bluetooth::hci::LeLongTermKeyRequestNegativeReplyView::Create(command); ASSERT(command_view.IsValid()); - uint16_t handle = command_view.GetConnectionHandle(); + + DEBUG(id_, "<< LE Long Term Key Request Negative Reply"); + DEBUG(id_, " connection_handle=0x{:x}", handle); + ErrorCode status = link_layer_controller_.LeLongTermKeyRequestNegativeReply(handle); @@ -2656,29 +3512,13 @@ void DualModeController::LeLongTermKeyRequestNegativeReply( kNumCommandPackets, status, handle)); } -void DualModeController::ReadClassOfDevice(CommandView command) { - auto command_view = bluetooth::hci::ReadClassOfDeviceView::Create(command); - ASSERT(command_view.IsValid()); - - send_event_(bluetooth::hci::ReadClassOfDeviceCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, - link_layer_controller_.GetClassOfDevice())); -} - -void DualModeController::ReadVoiceSetting(CommandView command) { - auto command_view = bluetooth::hci::ReadVoiceSettingView::Create(command); - ASSERT(command_view.IsValid()); - - send_event_(bluetooth::hci::ReadVoiceSettingCompleteBuilder::Create( - kNumCommandPackets, ErrorCode::SUCCESS, - link_layer_controller_.GetVoiceSetting())); -} - void DualModeController::ReadConnectionAcceptTimeout(CommandView command) { auto command_view = bluetooth::hci::ReadConnectionAcceptTimeoutView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Read Connection Accept Timeout"); + send_event_( bluetooth::hci::ReadConnectionAcceptTimeoutCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, @@ -2690,6 +3530,8 @@ void DualModeController::WriteConnectionAcceptTimeout(CommandView command) { bluetooth::hci::WriteConnectionAcceptTimeoutView::Create(command); ASSERT(command_view.IsValid()); + DEBUG(id_, "<< Write Connection Accept Timeout"); + link_layer_controller_.SetConnectionAcceptTimeout( command_view.GetConnAcceptTimeout()); @@ -2701,6 +3543,9 @@ void DualModeController::WriteConnectionAcceptTimeout(CommandView command) { void DualModeController::ReadLoopbackMode(CommandView command) { auto command_view = bluetooth::hci::ReadLoopbackModeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Read Loopback Mode"); + send_event_(bluetooth::hci::ReadLoopbackModeCompleteBuilder::Create( kNumCommandPackets, ErrorCode::SUCCESS, loopback_mode_)); } @@ -2708,6 +3553,10 @@ void DualModeController::ReadLoopbackMode(CommandView command) { void DualModeController::WriteLoopbackMode(CommandView command) { auto command_view = bluetooth::hci::WriteLoopbackModeView::Create(command); ASSERT(command_view.IsValid()); + + DEBUG(id_, "<< Write Loopback Mode"); + DEBUG(id_, " loopback_mode={}", command_view.GetLoopbackMode()); + loopback_mode_ = command_view.GetLoopbackMode(); // ACL channel uint16_t acl_handle = 0x123; @@ -3374,8 +4223,8 @@ const std::unordered_map //&DualModeController::ReadHoldModeActivity}, //{OpCode::WRITE_HOLD_MODE_ACTIVITY, //&DualModeController::WriteHoldModeActivity}, - //{OpCode::READ_TRANSMIT_POWER_LEVEL, - //&DualModeController::ReadTransmitPowerLevel}, + {OpCode::READ_TRANSMIT_POWER_LEVEL, + &DualModeController::ReadTransmitPowerLevel}, {OpCode::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE, &DualModeController::ReadSynchronousFlowControlEnable}, {OpCode::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE, @@ -3434,8 +4283,8 @@ const std::unordered_map //&DualModeController::ReadFlowControlMode}, //{OpCode::WRITE_FLOW_CONTROL_MODE, //&DualModeController::WriteFlowControlMode}, - //{OpCode::READ_ENHANCED_TRANSMIT_POWER_LEVEL, - //&DualModeController::ReadEnhancedTransmitPowerLevel}, + {OpCode::READ_ENHANCED_TRANSMIT_POWER_LEVEL, + &DualModeController::ReadEnhancedTransmitPowerLevel}, //{OpCode::READ_LE_HOST_SUPPORT, //&DualModeController::ReadLeHostSupport}, {OpCode::WRITE_LE_HOST_SUPPORT, @@ -3510,10 +4359,10 @@ const std::unordered_map //&DualModeController::ReadLocalSupportedControllerDelay}, // STATUS_PARAMETERS - //{OpCode::READ_FAILED_CONTACT_COUNTER, - //&DualModeController::ReadFailedContactCounter}, - //{OpCode::RESET_FAILED_CONTACT_COUNTER, - //&DualModeController::ResetFailedContactCounter}, + {OpCode::READ_FAILED_CONTACT_COUNTER, + &DualModeController::ReadFailedContactCounter}, + {OpCode::RESET_FAILED_CONTACT_COUNTER, + &DualModeController::ResetFailedContactCounter}, //{OpCode::READ_LINK_QUALITY, &DualModeController::ReadLinkQuality}, {OpCode::READ_RSSI, &DualModeController::ReadRssi}, //{OpCode::READ_AFH_CHANNEL_MAP, @@ -3710,28 +4559,22 @@ const std::unordered_map //&DualModeController::LeModifySleepClockAccuracy}, {OpCode::LE_READ_BUFFER_SIZE_V2, &DualModeController::LeReadBufferSizeV2}, - {OpCode::LE_READ_ISO_TX_SYNC, &DualModeController::LeReadIsoTxSync}, - {OpCode::LE_SET_CIG_PARAMETERS, - &DualModeController::LeSetCigParameters}, - //{OpCode::LE_SET_CIG_PARAMETERS_TEST, - //&DualModeController::LeSetCigParametersTest}, - {OpCode::LE_CREATE_CIS, &DualModeController::LeCreateCis}, - {OpCode::LE_REMOVE_CIG, &DualModeController::LeRemoveCig}, - {OpCode::LE_ACCEPT_CIS_REQUEST, - &DualModeController::LeAcceptCisRequest}, - {OpCode::LE_REJECT_CIS_REQUEST, - &DualModeController::LeRejectCisRequest}, - {OpCode::LE_CREATE_BIG, &DualModeController::LeCreateBig}, + //{OpCode::LE_READ_ISO_TX_SYNC, &DualModeController::LeReadIsoTxSync}, + {OpCode::LE_SET_CIG_PARAMETERS, &DualModeController::ForwardToLl}, + {OpCode::LE_SET_CIG_PARAMETERS_TEST, &DualModeController::ForwardToLl}, + {OpCode::LE_CREATE_CIS, &DualModeController::ForwardToLl}, + {OpCode::LE_REMOVE_CIG, &DualModeController::ForwardToLl}, + {OpCode::LE_ACCEPT_CIS_REQUEST, &DualModeController::ForwardToLl}, + {OpCode::LE_REJECT_CIS_REQUEST, &DualModeController::ForwardToLl}, + //{OpCode::LE_CREATE_BIG, &DualModeController::LeCreateBig}, //{OpCode::LE_CREATE_BIG_TEST, &DualModeController::LeCreateBigTest}, - {OpCode::LE_TERMINATE_BIG, &DualModeController::LeTerminateBig}, - {OpCode::LE_BIG_CREATE_SYNC, &DualModeController::LeBigCreateSync}, - {OpCode::LE_BIG_TERMINATE_SYNC, - &DualModeController::LeBigTerminateSync}, + //{OpCode::LE_TERMINATE_BIG, &DualModeController::LeTerminateBig}, + //{OpCode::LE_BIG_CREATE_SYNC, &DualModeController::LeBigCreateSync}, + //{OpCode::LE_BIG_TERMINATE_SYNC, + //&DualModeController::LeBigTerminateSync}, {OpCode::LE_REQUEST_PEER_SCA, &DualModeController::LeRequestPeerSca}, - {OpCode::LE_SETUP_ISO_DATA_PATH, - &DualModeController::LeSetupIsoDataPath}, - {OpCode::LE_REMOVE_ISO_DATA_PATH, - &DualModeController::LeRemoveIsoDataPath}, + {OpCode::LE_SETUP_ISO_DATA_PATH, &DualModeController::ForwardToLl}, + {OpCode::LE_REMOVE_ISO_DATA_PATH, &DualModeController::ForwardToLl}, //{OpCode::LE_ISO_TRANSMIT_TEST, //&DualModeController::LeIsoTransmitTest}, //{OpCode::LE_ISO_RECEIVE_TEST, &DualModeController::LeIsoReceiveTest}, @@ -3761,12 +4604,15 @@ const std::unordered_map // VENDOR {OpCode(CSR_VENDOR), &DualModeController::CsrVendorCommand}, - {OpCode::LE_MULTI_ADVT, &DualModeController::LeMultiAdv}, - {OpCode::LE_ADV_FILTER, &DualModeController::LeAdvertisingFilter}, - {OpCode::LE_EXTENDED_SCAN_PARAMS, - &DualModeController::LeExtendedScanParams}, - {OpCode::LE_ENERGY_INFO, &DualModeController::LeEnergyInfo}, {OpCode::LE_GET_VENDOR_CAPABILITIES, - &DualModeController::LeGetVendorCapabilities}}; + &DualModeController::LeGetVendorCapabilities}, + {OpCode::LE_BATCH_SCAN, &DualModeController::LeBatchScan}, + {OpCode::LE_APCF, &DualModeController::LeApcf}, + {OpCode::LE_GET_CONTROLLER_ACTIVITY_ENERGY_INFO, + &DualModeController::LeGetControllerActivityEnergyInfo}, + {OpCode::LE_EX_SET_SCAN_PARAMETERS, + &DualModeController::LeExSetScanParameters}, + {OpCode::GET_CONTROLLER_DEBUG_INFO, + &DualModeController::GetControllerDebugInfo}}; } // namespace rootcanal diff --git a/tools/rootcanal/model/controller/dual_mode_controller.h b/tools/rootcanal/model/controller/dual_mode_controller.h index 181348c9927844a67740cba17bc46ec7d0a2de8e..3f56acc7893c2a8fefba2d654f9940b732be0ea6 100644 --- a/tools/rootcanal/model/controller/dual_mode_controller.h +++ b/tools/rootcanal/model/controller/dual_mode_controller.h @@ -19,17 +19,21 @@ #include #include +#include #include +#include #include #include #include -#include "controller_properties.h" #include "hci/address.h" -#include "hci/hci_packets.h" -#include "link_layer_controller.h" +#include "model/controller/controller_properties.h" +#include "model/controller/link_layer_controller.h" #include "model/controller/vendor_commands/csr.h" #include "model/devices/device.h" +#include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { @@ -56,6 +60,9 @@ class DualModeController : public Device { DualModeController& operator=(const DualModeController&) = delete; + // Overwrite the configuration. + void SetProperties(ControllerProperties properties); + // Device methods. std::string GetTypeString() const override; @@ -130,9 +137,6 @@ class DualModeController : public Device { // 7.1.19 void RemoteNameRequest(CommandView command); - // 7.2.8 - void SwitchRole(CommandView command); - // 7.1.21 void ReadRemoteSupportedFeatures(CommandView command); @@ -178,6 +182,9 @@ class DualModeController : public Device { // 7.2.7 void RoleDiscovery(CommandView command); + // 7.2.8 + void SwitchRole(CommandView command); + // 7.2.9 void ReadLinkPolicySettings(CommandView command); @@ -217,46 +224,43 @@ class DualModeController : public Device { // 7.3.12 void ReadLocalName(CommandView command); - // 7.3.15 - void ReadPageTimeout(CommandView command); + // 7.3.13 - 7.3.14 + void ReadConnectionAcceptTimeout(CommandView command); + void WriteConnectionAcceptTimeout(CommandView command); - // 7.3.16 + // 7.3.15 - 7.3.16 + void ReadPageTimeout(CommandView command); void WritePageTimeout(CommandView command); - // 7.3.17 + // 7.3.17 - 7.3.18 void ReadScanEnable(CommandView command); - - // 7.3.18 void WriteScanEnable(CommandView command); - // 7.3.19 + // 7.3.19 - 7.3.20 void ReadPageScanActivity(CommandView command); - - // 7.3.20 void WritePageScanActivity(CommandView command); - // 7.3.21 + // 7.3.21 - 7.3.22 void ReadInquiryScanActivity(CommandView command); - - // 7.3.22 void WriteInquiryScanActivity(CommandView command); - // 7.3.23 + // 7.3.23 - 7.3.24 void ReadAuthenticationEnable(CommandView command); - - // 7.3.24 void WriteAuthenticationEnable(CommandView command); - // 7.3.26 + // 7.3.25 - 7.3.26 + void ReadClassOfDevice(CommandView command); void WriteClassOfDevice(CommandView command); - // 7.3.28 + // 7.3.27 - 7.3.28 + void ReadVoiceSetting(CommandView command); void WriteVoiceSetting(CommandView command); - // 7.3.36 - void ReadSynchronousFlowControlEnable(CommandView command); + // 7.3.35 + void ReadTransmitPowerLevel(CommandView command); - // 7.3.37 + // 7.3.36 - 7.3.37 + void ReadSynchronousFlowControlEnable(CommandView command); void WriteSynchronousFlowControlEnable(CommandView command); // 7.3.39 @@ -268,10 +272,8 @@ class DualModeController : public Device { // 7.3.43 void ReadNumberOfSupportedIac(CommandView command); - // 7.3.44 + // 7.3.44 - 7.3.45 void ReadCurrentIacLap(CommandView command); - - // 7.3.45 void WriteCurrentIacLap(CommandView command); // 7.3.47 @@ -313,6 +315,9 @@ class DualModeController : public Device { // 7.3.69 void SetEventMaskPage2(CommandView command); + // 7.3.74 + void ReadEnhancedTransmitPowerLevel(CommandView command); + // 7.3.79 void WriteLeHostSupport(CommandView command); @@ -349,6 +354,10 @@ class DualModeController : public Device { // Status Parameters Commands // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.5 + // 7.5.1 - 7.5.2 + void ReadFailedContactCounter(CommandView command); + void ResetFailedContactCounter(CommandView command); + // 7.5.4 void ReadRssi(CommandView command); @@ -370,7 +379,7 @@ class DualModeController : public Device { // 7.8.1 void LeSetEventMask(CommandView command); - // 7.8.2 and 7.8.93 + // 7.8.2 - 7.8.93 void LeReadBufferSizeV1(CommandView command); void LeReadBufferSizeV2(CommandView command); @@ -380,43 +389,25 @@ class DualModeController : public Device { // 7.8.4 void LeSetRandomAddress(CommandView command); - // 7.8.5 + // 7.8.5 - 7.8.9 void LeSetAdvertisingParameters(CommandView command); - - // 7.8.6 void LeReadAdvertisingPhysicalChannelTxPower(CommandView command); - - // 7.8.7 void LeSetAdvertisingData(CommandView command); - - // 7.8.8 void LeSetScanResponseData(CommandView command); - - // 7.8.9 void LeSetAdvertisingEnable(CommandView command); - // 7.8.10 + // 7.8.10 - 7.8.11 void LeSetScanParameters(CommandView command); - - // 7.8.11 void LeSetScanEnable(CommandView command); - // 7.8.12 + // 7.8.12 - 7.8.13 void LeCreateConnection(CommandView command); - - // 7.8.13 void LeCreateConnectionCancel(CommandView command); - // 7.8.14 + // 7.8.14 - 7.8.17 void LeReadFilterAcceptListSize(CommandView command); - - // 7.8.15 void LeClearFilterAcceptList(CommandView command); - - // 7.8.16 void LeAddDeviceToFilterAcceptList(CommandView command); - - // 7.8.17 void LeRemoveDeviceFromFilterAcceptList(CommandView command); // 7.8.18 @@ -434,25 +425,19 @@ class DualModeController : public Device { // 7.8.24 void LeStartEncryption(CommandView command); - // 7.8.25 + // 7.8.25 - 7.8.26 void LeLongTermKeyRequestReply(CommandView command); - - // 7.8.26 void LeLongTermKeyRequestNegativeReply(CommandView command); // 7.8.27 void LeReadSupportedStates(CommandView command); - // 7.8.31 + // 7.8.31 - 7.8.32 void LeRemoteConnectionParameterRequestReply(CommandView command); - - // 7.8.32 void LeRemoteConnectionParameterRequestNegativeReply(CommandView command); - // 7.8.34 + // 7.8.34 - 7.8.35 void LeReadSuggestedDefaultDataLength(CommandView command); - - // 7.8.35 void LeWriteSuggestedDefaultDataLength(CommandView command); // 7.8.38 - 7.8.41 @@ -465,44 +450,27 @@ class DualModeController : public Device { void LeReadPeerResolvableAddress(CommandView command); void LeReadLocalResolvableAddress(CommandView command); - // 7.8.44 + // 7.8.44 - 7.8.45 void LeSetAddressResolutionEnable(CommandView command); - - // 7.8.45 void LeSetResolvablePrivateAddressTimeout(CommandView command); // 7.8.46 void LeReadMaximumDataLength(CommandView command); + // 7.8.47 - 7.8.49 void LeReadPhy(CommandView command); void LeSetDefaultPhy(CommandView command); void LeSetPhy(CommandView command); - // 7.8.52 + // 7.8.52 - 7.8.60 void LeSetAdvertisingSetRandomAddress(CommandView command); - - // 7.8.53 void LeSetExtendedAdvertisingParameters(CommandView command); - - // 7.8.54 void LeSetExtendedAdvertisingData(CommandView command); - - // 7.8.55 void LeSetExtendedScanResponseData(CommandView command); - - // 7.8.56 void LeSetExtendedAdvertisingEnable(CommandView command); - - // 7.8.57 void LeReadMaximumAdvertisingDataLength(CommandView command); - - // 7.8.58 void LeReadNumberOfSupportedAdvertisingSets(CommandView command); - - // 7.8.59 void LeRemoveAdvertisingSet(CommandView command); - - // 7.8.60 void LeClearAdvertisingSets(CommandView command); // 7.8.61 - 7.8.63 @@ -521,10 +489,8 @@ class DualModeController : public Device { void LeClearPeriodicAdvertiserList(CommandView command); void LeReadPeriodicAdvertiserListSize(CommandView command); - // 7.8.64 + // 7.8.64 - 7.8.65 void LeSetExtendedScanParameters(CommandView command); - - // 7.8.65 void LeSetExtendedScanEnable(CommandView command); // 7.8.66 @@ -533,56 +499,39 @@ class DualModeController : public Device { // 7.8.77 void LeSetPrivacyMode(CommandView command); - // 7.8.96 - 7.8.110 - void LeReadIsoTxSync(CommandView command); - void LeSetCigParameters(CommandView command); - void LeCreateCis(CommandView command); - void LeRemoveCig(CommandView command); - void LeAcceptCisRequest(CommandView command); - void LeRejectCisRequest(CommandView command); - void LeCreateBig(CommandView command); - void LeTerminateBig(CommandView command); - void LeBigCreateSync(CommandView command); - void LeBigTerminateSync(CommandView command); + // 7.8.108 void LeRequestPeerSca(CommandView command); - void LeSetupIsoDataPath(CommandView command); - void LeRemoveIsoDataPath(CommandView command); // 7.8.115 void LeSetHostFeature(CommandView command); - // Required commands for handshaking with hci driver - void ReadClassOfDevice(CommandView command); - void ReadVoiceSetting(CommandView command); - void ReadConnectionAcceptTimeout(CommandView command); - void WriteConnectionAcceptTimeout(CommandView command); - // Vendor-specific Commands - void LeGetVendorCapabilities(CommandView command); - void LeEnergyInfo(CommandView command); - void LeMultiAdv(CommandView command); - void LeAdvertisingFilter(CommandView command); - void LeExtendedScanParams(CommandView command); + void LeBatchScan(CommandView command); + void LeApcf(CommandView command); + void LeGetControllerActivityEnergyInfo(CommandView command); + void LeExSetScanParameters(CommandView command); + void GetControllerDebugInfo(CommandView command); // CSR vendor command. // Implement the command specific to the CSR controller // used specifically by the PTS tool to pass certification tests. void CsrVendorCommand(CommandView command); - void CsrReadVarid(CsrVarid varid, std::vector& value); - void CsrWriteVarid(CsrVarid varid, std::vector const& value); - void CsrReadPskey(CsrPskey pskey, std::vector& value); + void CsrReadVarid(CsrVarid varid, std::vector& value) const; + void CsrWriteVarid(CsrVarid varid, std::vector const& value) const; + void CsrReadPskey(CsrPskey pskey, std::vector& value) const; void CsrWritePskey(CsrPskey pskey, std::vector const& value); // Command pass-through. void ForwardToLm(CommandView command); + void ForwardToLl(CommandView command); protected: // Controller configuration. ControllerProperties properties_; // Link Layer state. - LinkLayerController link_layer_controller_{address_, properties_}; + LinkLayerController link_layer_controller_{address_, properties_, id_}; private: // Send a HCI_Command_Complete event for the specified op_code with @@ -602,6 +551,9 @@ class DualModeController : public Device { // with RootCanal. bluetooth::hci::LoopbackMode loopback_mode_{LoopbackMode::NO_LOOPBACK}; + // Random value generator, always seeded with 0 to be deterministic. + std::mt19937_64 random_generator_{}; + // Flag set to true after the HCI Reset command has been received // the first time. bool controller_reset_{false}; diff --git a/tools/rootcanal/model/controller/ffi.cc b/tools/rootcanal/model/controller/ffi.cc index 81162ed9dddbd989a29544d1fea9b1f831036049..d01ff16653954ec28a85a8c98bccd26a97e8d1f2 100644 --- a/tools/rootcanal/model/controller/ffi.cc +++ b/tools/rootcanal/model/controller/ffi.cc @@ -14,13 +14,13 @@ * limitations under the License. */ -#include "ffi.h" +#include "model/controller/ffi.h" #include #include -#include "dual_mode_controller.h" +#include "model/controller/dual_mode_controller.h" using namespace rootcanal; using bluetooth::hci::Address; @@ -117,9 +117,7 @@ __attribute__((visibility("default"))) void ffi_controller_receive_ll( std::shared_ptr> bytes = std::make_shared>(data, data + data_len); model::packets::LinkLayerPacketView packet = - model::packets::LinkLayerPacketView::Create( - bluetooth::packet::PacketView( - bytes)); + model::packets::LinkLayerPacketView::Create(pdl::packet::slice(bytes)); if (!packet.IsValid()) { std::cerr << "Dropping malformed LL packet" << std::endl; return; diff --git a/tools/rootcanal/model/controller/isochronous_connection_handler.cc b/tools/rootcanal/model/controller/isochronous_connection_handler.cc deleted file mode 100644 index 8b41f7bb548d1a633fdc099432ba6570d92c341a..0000000000000000000000000000000000000000 --- a/tools/rootcanal/model/controller/isochronous_connection_handler.cc +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "model/controller/isochronous_connection_handler.h" - -#include "hci/address.h" -#include "log.h" - -namespace rootcanal { - -using bluetooth::hci::ErrorCode; - -std::unique_ptr -IsochronousConnectionHandler::SetCigParameters( - GroupParameters group_parameters, std::vector& streams, - std::vector handles) { - if (groups_.count(group_parameters.id) != 0) { - if (groups_.at(group_parameters.id).HasStreams()) { - return bluetooth::hci::LeSetCigParametersCompleteBuilder::Create( - 1, ErrorCode::COMMAND_DISALLOWED, group_parameters.id, {}); - } - groups_.erase(group_parameters.id); - } - - // TODO: Limit groups and return ErrorCode::MEMORY_CAPACITY_EXCEEDED - // TODO: Limit connections return ErrorCode::CONNECTION_LIMIT_EXCEEDED - - std::vector created_streams; - for (size_t i = 0; i < streams.size(); i++) { - streams[i].handle = handles[i]; - streams[i].group_id = group_parameters.id; - created_streams.emplace_back(streams[i]); - cis_to_group_.emplace(handles[i], group_parameters.id); - } - - groups_.emplace(std::piecewise_construct, - std::forward_as_tuple(group_parameters.id), - std::forward_as_tuple(group_parameters, created_streams)); - - return bluetooth::hci::LeSetCigParametersCompleteBuilder::Create( - 1, ErrorCode::SUCCESS, group_parameters.id, handles); -} - -bluetooth::hci::ErrorCode IsochronousConnectionHandler::RemoveCig( - uint8_t cig_id) { - if (groups_.count(cig_id) != 0) { - return ErrorCode::UNKNOWN_CONNECTION; - } - if (groups_.at(cig_id).HasConnectedStream()) { - return ErrorCode::COMMAND_DISALLOWED; - } - groups_.erase(cig_id); - auto copy = cis_to_group_; - cis_to_group_.clear(); - for (auto pair : cis_to_group_) { - if (pair.second != cig_id) { - cis_to_group_.emplace(pair.first, pair.second); - } - } - return ErrorCode::SUCCESS; -} - -bool IsochronousConnectionHandler::HasHandle(uint16_t handle) const { - return cis_to_group_.count(handle) != 0; -} - -uint8_t IsochronousConnectionHandler::GetGroupId(uint16_t handle) const { - return cis_to_group_.at(handle); -} - -StreamParameters IsochronousConnectionHandler::GetStreamParameters( - uint16_t handle) const { - return groups_.at(cis_to_group_.at(handle)).GetStreamParameters(handle); -} - -GroupParameters IsochronousConnectionHandler::GetGroupParameters( - uint8_t id) const { - return groups_.at(id).GetParameters(); -} - -bool IsochronousConnectionHandler::GetStreamIsConnected(uint16_t handle) const { - return groups_.at(cis_to_group_.at(handle)).StreamIsConnected(handle); -} - -} // namespace rootcanal diff --git a/tools/rootcanal/model/controller/isochronous_connection_handler.h b/tools/rootcanal/model/controller/isochronous_connection_handler.h deleted file mode 100644 index fa368d02ef6682223acfaa305800701757e658f3..0000000000000000000000000000000000000000 --- a/tools/rootcanal/model/controller/isochronous_connection_handler.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "hci/hci_packets.h" -#include "model/controller/connected_isochronous_group.h" -#include "model/controller/connected_isochronous_stream.h" - -namespace rootcanal { - -class IsochronousConnectionHandler { - public: - IsochronousConnectionHandler() = default; - virtual ~IsochronousConnectionHandler() = default; - - std::unique_ptr - SetCigParameters(GroupParameters parameters, - std::vector& streams, - std::vector handles); - - bluetooth::hci::ErrorCode RemoveCig(uint8_t cig_id); - - bool HasHandle(uint16_t handle) const; - - uint8_t GetGroupId(uint16_t handle) const; - - StreamParameters GetStreamParameters(uint16_t handle) const; - GroupParameters GetGroupParameters(uint8_t id) const; - - bool GetStreamIsConnected(uint16_t handle) const; - - std::vector GetCigHandles(uint8_t id) const; - - private: - std::map groups_; - std::map cis_to_group_; -}; - -} // namespace rootcanal diff --git a/tools/rootcanal/model/controller/le_advertiser.cc b/tools/rootcanal/model/controller/le_advertiser.cc index 518ad10937ada74630a00935a9e7171f903bc32d..865ceeb6b9734da449d189b8535913c16488fef2 100644 --- a/tools/rootcanal/model/controller/le_advertiser.cc +++ b/tools/rootcanal/model/controller/le_advertiser.cc @@ -14,10 +14,21 @@ * limitations under the License. */ -#include "le_advertiser.h" +#include "model/controller/le_advertiser.h" -#include "link_layer_controller.h" +#include +#include +#include +#include +#include +#include +#include + +#include "hci/address_with_type.h" #include "log.h" +#include "model/controller/link_layer_controller.h" +#include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" using namespace bluetooth::hci; using namespace std::literals; @@ -57,9 +68,9 @@ ErrorCode LinkLayerController::LeSetAdvertisingParameters( // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { - LOG_INFO( - "legacy advertising command rejected because extended advertising" - " is being used"); + INFO(id_, + "legacy advertising command rejected because extended advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -78,17 +89,17 @@ ErrorCode LinkLayerController::LeSetAdvertisingParameters( // The Host shall not issue this command when advertising is enabled in the // Controller; if it is the Command Disallowed error code shall be used. if (legacy_advertiser_.advertising_enable) { - LOG_INFO("legacy advertising is enabled"); + INFO(id_, "legacy advertising is enabled"); return ErrorCode::COMMAND_DISALLOWED; } // At least one channel bit shall be set in the // Advertising_Channel_Map parameter. if (advertising_channel_map == 0) { - LOG_INFO( - "advertising_channel_map (0x%04x) does not enable any" - " advertising channel", - advertising_channel_map); + INFO(id_, + "advertising_channel_map (0x{:04x}) does not enable any" + " advertising channel", + advertising_channel_map); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -99,21 +110,21 @@ ErrorCode LinkLayerController::LeSetAdvertisingParameters( // error code. if (advertising_interval_min < 0x0020 || advertising_interval_min > 0x4000 || advertising_interval_max < 0x0020 || advertising_interval_max > 0x4000) { - LOG_INFO( - "advertising_interval_min (0x%04x) and/or" - " advertising_interval_max (0x%04x) are outside the range" - " of supported values (0x0020 - 0x4000)", - advertising_interval_min, advertising_interval_max); + INFO(id_, + "advertising_interval_min (0x{:04x}) and/or" + " advertising_interval_max (0x{:04x}) are outside the range" + " of supported values (0x0020 - 0x4000)", + advertising_interval_min, advertising_interval_max); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // The Advertising_Interval_Min shall be less than or equal to the // Advertising_Interval_Max. if (advertising_interval_min > advertising_interval_max) { - LOG_INFO( - "advertising_interval_min (0x%04x) is larger than" - " advertising_interval_max (0x%04x)", - advertising_interval_min, advertising_interval_max); + INFO(id_, + "advertising_interval_min (0x{:04x}) is larger than" + " advertising_interval_max (0x{:04x})", + advertising_interval_min, advertising_interval_max); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -136,9 +147,9 @@ ErrorCode LinkLayerController::LeSetAdvertisingData( // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { - LOG_INFO( - "legacy advertising command rejected because extended advertising" - " is being used"); + INFO(id_, + "legacy advertising command rejected because extended advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -152,9 +163,9 @@ ErrorCode LinkLayerController::LeSetScanResponseData( // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { - LOG_INFO( - "legacy advertising command rejected because extended advertising" - " is being used"); + INFO(id_, + "legacy advertising command rejected because extended advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -167,9 +178,9 @@ ErrorCode LinkLayerController::LeSetAdvertisingEnable(bool advertising_enable) { // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { - LOG_INFO( - "legacy advertising command rejected because extended advertising" - " is being used"); + INFO(id_, + "legacy advertising command rejected because extended advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -201,9 +212,9 @@ ErrorCode LinkLayerController::LeSetAdvertisingEnable(bool advertising_enable) { // command, the Controller shall return the error code // Invalid HCI Command Parameters (0x12). if (random_address.GetAddress() == Address::kEmpty) { - LOG_INFO( - "own_address_type is Random_Device_Address but the Random_Address" - " has not been initialized"); + INFO(id_, + "own_address_type is Random_Device_Address but the Random_Address" + " has not been initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } legacy_advertiser_.advertising_address = random_address; @@ -224,10 +235,10 @@ ErrorCode LinkLayerController::LeSetAdvertisingEnable(bool advertising_enable) { if (resolvable_address) { legacy_advertiser_.advertising_address = resolvable_address.value(); } else if (random_address.GetAddress() == Address::kEmpty) { - LOG_INFO( - "own_address_type is Resolvable_Or_Random_Address but the" - " Resolving_List does not contain a matching entry and the" - " Random_Address is not initialized"); + INFO(id_, + "own_address_type is Resolvable_Or_Random_Address but the" + " Resolving_List does not contain a matching entry and the" + " Random_Address is not initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } else { legacy_advertiser_.advertising_address = random_address; @@ -285,8 +296,8 @@ ErrorCode LinkLayerController::LeSetAdvertisingSetRandomAddress( // Unknown Advertising Identifier (0x42). // TODO(c++20) unordered_map<>::contains if (extended_advertisers_.count(advertising_handle) == 0) { - LOG_INFO("no advertising set defined with handle %02x", - static_cast(advertising_handle)); + INFO(id_, "no advertising set defined with handle {:02x}", + static_cast(advertising_handle)); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -297,7 +308,7 @@ ErrorCode LinkLayerController::LeSetAdvertisingSetRandomAddress( // enabled, the Controller shall return the error code // Command Disallowed (0x0C). if (advertiser.advertising_enable) { - LOG_INFO("advertising is enabled for the specified advertising set"); + INFO(id_, "advertising is enabled for the specified advertising set"); return ErrorCode::COMMAND_DISALLOWED; } @@ -320,9 +331,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { - LOG_INFO( - "extended advertising command rejected because legacy advertising" - " is being used"); + INFO(id_, + "extended advertising command rejected because legacy advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -350,10 +361,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( if (extended_advertisers_.count(advertising_handle) == 0) { if (extended_advertisers_.size() >= properties_.le_num_supported_advertising_sets) { - LOG_INFO( - "no advertising set defined with handle %02x and" - " cannot allocate any more advertisers", - static_cast(advertising_handle)); + INFO(id_, + "no advertising set defined with handle {:02x} and" + " cannot allocate any more advertisers", + static_cast(advertising_handle)); return ErrorCode::MEMORY_CAPACITY_EXCEEDED; } } else { @@ -364,7 +375,7 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( // specified advertising set, the Controller shall return the error code // Command Disallowed (0x0C). if (advertiser.advertising_enable) { - LOG_INFO("advertising is enabled for the specified advertising set"); + INFO(id_, "advertising is enabled for the specified advertising set"); return ErrorCode::COMMAND_DISALLOWED; } @@ -385,10 +396,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( (raw_advertising_event_properties & ~0x10) != static_cast( LegacyAdvertisingEventProperties::ADV_NONCONN_IND)) { - LOG_INFO( - "advertising_event_properties (0x%02x) is legacy but does not" - " match valid legacy advertising event types", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties (0x{:02x}) is legacy but does not" + " match valid legacy advertising event types", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -401,20 +412,20 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( // contains some, the Controller shall return the error code // Invalid HCI Command Parameters (0x12). if (!can_have_advertising_data && !advertiser.advertising_data.empty()) { - LOG_INFO( - "advertising_event_properties (0x%02x) specifies an event type" - " that does not support avertising data but the set contains some", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties (0x{:02x}) specifies an event type" + " that does not support avertising data but the set contains some", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } // Note: not explicitly specified in the specification but makes sense // in the context of the other checks. if (!scannable_advertising && !advertiser.scan_response_data.empty()) { - LOG_INFO( - "advertising_event_properties (0x%02x) specifies an event type" - " that does not support scan response data but the set contains some", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties (0x{:02x}) specifies an event type" + " that does not support scan response data but the set contains some", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -425,11 +436,11 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( (advertiser.advertising_data.size() > max_legacy_advertising_pdu_size || advertiser.scan_response_data.size() > max_legacy_advertising_pdu_size)) { - LOG_INFO( - "advertising_event_properties (0x%02x) is legacy and the" - " advertising data or scan response data exceeds the capacity" - " of legacy PDUs", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties (0x{:02x}) is legacy and the" + " advertising data or scan response data exceeds the capacity" + " of legacy PDUs", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -437,10 +448,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( // The advertisement shall not be both connectable and scannable. if (extended_advertising && connectable_advertising && scannable_advertising) { - LOG_INFO( - "advertising_event_properties (0x%02x) is extended and may not" - " be connectable and scannable at the same time", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties (0x{:02x}) is extended and may not" + " be connectable and scannable at the same time", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -448,10 +459,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( // advertising interval) shall not be used (bit 3 = 0). if (extended_advertising && connectable_advertising && directed_advertising && high_duty_cycle_advertising) { - LOG_INFO( - "advertising_event_properties (0x%02x) is extended and may not" - " be high-duty cycle directed connectable", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties (0x{:02x}) is extended and may not" + " be high-duty cycle directed connectable", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -462,41 +473,41 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( // Parameter Value (0x11). if (primary_advertising_interval_min < 0x20 || primary_advertising_interval_max < 0x20) { - LOG_INFO( - "primary_advertising_interval_min (0x%04x) and/or" - " primary_advertising_interval_max (0x%04x) are outside the range" - " of supported values (0x0020 - 0xffff)", - primary_advertising_interval_min, primary_advertising_interval_max); + INFO(id_, + "primary_advertising_interval_min (0x{:04x}) and/or" + " primary_advertising_interval_max (0x{:04x}) are outside the range" + " of supported values (0x0020 - 0xffff)", + primary_advertising_interval_min, primary_advertising_interval_max); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // The Primary_Advertising_Interval_Min parameter shall be less than or equal // to the Primary_Advertising_Interval_Max parameter. if (primary_advertising_interval_min > primary_advertising_interval_max) { - LOG_INFO( - "primary_advertising_interval_min (0x%04x) is larger than" - " primary_advertising_interval_max (0x%04x)", - primary_advertising_interval_min, primary_advertising_interval_max); + INFO(id_, + "primary_advertising_interval_min (0x{:04x}) is larger than" + " primary_advertising_interval_max (0x{:04x})", + primary_advertising_interval_min, primary_advertising_interval_max); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } // At least one channel bit shall be set in the // Primary_Advertising_Channel_Map parameter. if (primary_advertising_channel_map == 0) { - LOG_INFO( - "primary_advertising_channel_map does not enable any" - " advertising channel"); + INFO(id_, + "primary_advertising_channel_map does not enable any" + " advertising channel"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } // If legacy advertising PDUs are being used, the // Primary_Advertising_PHY shall indicate the LE 1M PHY. if (legacy_advertising && primary_advertising_phy != PrimaryPhyType::LE_1M) { - LOG_INFO( - "advertising_event_properties (0x%04x) is legacy but" - " primary_advertising_phy (%02x) is not LE 1M", - raw_advertising_event_properties, - static_cast(primary_advertising_phy)); + INFO(id_, + "advertising_event_properties (0x{:04x}) is legacy but" + " primary_advertising_phy ({:02x}) is not LE 1M", + raw_advertising_event_properties, + static_cast(primary_advertising_phy)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -506,10 +517,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( // return the error code Command Disallowed (0x0C). if (advertiser.constant_tone_extensions && secondary_advertising_phy == SecondaryPhyType::LE_CODED) { - LOG_INFO( - "constant tone extensions are enabled but" - " secondary_advertising_phy (%02x) does not support them", - static_cast(secondary_advertising_phy)); + INFO(id_, + "constant tone extensions are enabled but" + " secondary_advertising_phy ({:02x}) does not support them", + static_cast(secondary_advertising_phy)); return ErrorCode::COMMAND_DISALLOWED; } @@ -520,11 +531,11 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( if (advertiser.periodic_advertising_enable && (connectable_advertising || scannable_advertising || legacy_advertising || anonymous_advertising)) { - LOG_INFO( - "periodic advertising is enabled for the specified advertising set" - " and advertising_event_properties (0x%02x) is either" - " connectable, scannable, legacy, or anonymous", - raw_advertising_event_properties); + INFO(id_, + "periodic advertising is enabled for the specified advertising set" + " and advertising_event_properties (0x{:02x}) is either" + " connectable, scannable, legacy, or anonymous", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -535,7 +546,7 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( #if 0 if (advertiser.periodic_advertising_enable) { // TODO - LOG_INFO( + INFO(id_, "periodic advertising is enabled for the specified advertising set" " and the secondary PHY does not match the periodic" " advertising PHY"); @@ -554,9 +565,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingParameters( (advertiser.advertising_data.size() > max_extended_advertising_pdu_size || advertiser.scan_response_data.size() > max_extended_advertising_pdu_size)) { - LOG_INFO( - "the advertising data contained in the set is larger than the" - " available PDU capacity"); + INFO(id_, + "the advertising data contained in the set is larger than the" + " available PDU capacity"); return ErrorCode::PACKET_TOO_LONG; } @@ -589,9 +600,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { - LOG_INFO( - "extended advertising command rejected because legacy advertising" - " is being used"); + INFO(id_, + "extended advertising command rejected because legacy advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -603,8 +614,8 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( // Unknown Advertising Identifier (0x42). // TODO(c++20) unordered_map<>::contains if (extended_advertisers_.count(advertising_handle) == 0) { - LOG_INFO("no advertising set defined with handle %02x", - static_cast(advertising_handle)); + INFO(id_, "no advertising set defined with handle {:02x}", + static_cast(advertising_handle)); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -624,10 +635,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( // advertising data, the Controller shall return the error code // Invalid HCI Command Parameters (0x12). if (!can_have_advertising_data) { - LOG_INFO( - "advertising_event_properties (%02x) does not support" - " advertising data", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties ({:02x}) does not support" + " advertising data", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -638,11 +649,11 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( if (advertising_event_properties.legacy_ && (operation != Operation::COMPLETE_ADVERTISEMENT || advertising_data.size() > max_legacy_advertising_pdu_size)) { - LOG_INFO( - "advertising_event_properties (%02x) is legacy and" - " and an incomplete operation was used or the advertising data" - " is larger than 31", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties ({:02x}) is legacy and" + " and an incomplete operation was used or the advertising data" + " is larger than 31", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -656,11 +667,11 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( if (operation == Operation::UNCHANGED_DATA && (!advertiser.advertising_enable || advertiser.advertising_data.empty() || advertising_event_properties.legacy_ || !advertising_data.empty())) { - LOG_INFO( - "Unchanged_Data operation is used but advertising is disabled;" - " or the advertising set contains no data;" - " or the advertising set uses legacy PDUs;" - " or the advertising data is not empty"); + INFO(id_, + "Unchanged_Data operation is used but advertising is disabled;" + " or the advertising set contains no data;" + " or the advertising set uses legacy PDUs;" + " or the advertising data is not empty"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -669,10 +680,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( // Command Parameters (0x12). if (operation != Operation::COMPLETE_ADVERTISEMENT && operation != Operation::UNCHANGED_DATA && advertising_data.empty()) { - LOG_INFO( - "operation (%02x) is not Complete_Advertisement or Unchanged_Data" - " but the advertising data is empty", - static_cast(operation)); + INFO(id_, + "operation ({:02x}) is not Complete_Advertisement or Unchanged_Data" + " but the advertising data is empty", + static_cast(operation)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -682,10 +693,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( if (advertiser.advertising_enable && operation != Operation::COMPLETE_ADVERTISEMENT && operation != Operation::UNCHANGED_DATA) { - LOG_INFO( - "operation (%02x) is used but advertising is enabled for the" - " specified advertising set", - static_cast(operation)); + INFO(id_, + "operation ({:02x}) is used but advertising is enabled for the" + " specified advertising set", + static_cast(operation)); return ErrorCode::COMMAND_DISALLOWED; } @@ -718,7 +729,7 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( break; default: - LOG_INFO("unknown operation (%x)", static_cast(operation)); + INFO(id_, "unknown operation ({})", static_cast(operation)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -730,11 +741,11 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( // Capacity Exceeded (0x07). if (advertiser.advertising_data.size() > properties_.le_max_advertising_data_length) { - LOG_INFO( - "the combined length %zu of the advertising data exceeds the" - " advertising set capacity %d", - advertiser.advertising_data.size(), - properties_.le_max_advertising_data_length); + INFO(id_, + "the combined length {} of the advertising data exceeds the" + " advertising set capacity {}", + advertiser.advertising_data.size(), + properties_.le_max_advertising_data_length); advertiser.advertising_data.clear(); advertiser.partial_advertising_data = false; return ErrorCode::MEMORY_CAPACITY_EXCEEDED; @@ -752,9 +763,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingData( advertising_event_properties); if (advertiser.advertising_enable && advertiser.advertising_data.size() > max_advertising_data_length) { - LOG_INFO( - "the advertising data contained in the set is larger than the" - " available PDU capacity"); + INFO(id_, + "the advertising data contained in the set is larger than the" + " available PDU capacity"); advertiser.advertising_data.clear(); advertiser.partial_advertising_data = false; return ErrorCode::PACKET_TOO_LONG; @@ -771,9 +782,9 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { - LOG_INFO( - "extended advertising command rejected because legacy advertising" - " is being used"); + INFO(id_, + "extended advertising command rejected because legacy advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -785,8 +796,8 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( // Unknown Advertising Identifier (0x42). // TODO(c++20) unordered_map<>::contains if (extended_advertisers_.count(advertising_handle) == 0) { - LOG_INFO("no advertising set defined with handle %02x", - static_cast(advertising_handle)); + INFO(id_, "no advertising set defined with handle {:02x}", + static_cast(advertising_handle)); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -801,10 +812,10 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( // command other than to discard existing data, the Controller shall // return the error code Invalid HCI Command Parameters (0x12). if (!advertising_event_properties.scannable_ && !scan_response_data.empty()) { - LOG_INFO( - "advertising_event_properties (%02x) is not scannable" - " but the scan response data is not empty", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties ({:02x}) is not scannable" + " but the scan response data is not empty", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -816,11 +827,11 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( advertising_event_properties.legacy_ && (operation != Operation::COMPLETE_ADVERTISEMENT || scan_response_data.size() > max_legacy_advertising_pdu_size)) { - LOG_INFO( - "advertising_event_properties (%02x) is scannable legacy" - " and an incomplete operation was used or the scan response data" - " is larger than 31", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties ({:02x}) is scannable legacy" + " and an incomplete operation was used or the scan response data" + " is larger than 31", + raw_advertising_event_properties); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -829,10 +840,10 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( // Invalid HCI Command Parameters (0x12). if (operation != Operation::COMPLETE_ADVERTISEMENT && scan_response_data.empty()) { - LOG_INFO( - "operation (%02x) is not Complete_Advertisement but the" - " scan response data is empty", - static_cast(operation)); + INFO(id_, + "operation ({:02x}) is not Complete_Advertisement but the" + " scan response data is empty", + static_cast(operation)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -841,10 +852,10 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( // return the error code Command Disallowed (0x0C). if (advertiser.advertising_enable && operation != Operation::COMPLETE_ADVERTISEMENT) { - LOG_INFO( - "operation (%02x) is used but advertising is enabled for the" - " specified advertising set", - static_cast(operation)); + INFO(id_, + "operation ({:02x}) is used but advertising is enabled for the" + " specified advertising set", + static_cast(operation)); return ErrorCode::COMMAND_DISALLOWED; } @@ -855,11 +866,11 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( if (advertiser.advertising_enable && advertising_event_properties.scannable_ && !advertising_event_properties.legacy_ && scan_response_data.empty()) { - LOG_INFO( - "advertising_event_properties (%02x) is scannable extended," - " advertising is enabled for the specified advertising set" - " and the scan response data is empty", - raw_advertising_event_properties); + INFO(id_, + "advertising_event_properties ({:02x}) is scannable extended," + " advertising is enabled for the specified advertising set" + " and the scan response data is empty", + raw_advertising_event_properties); return ErrorCode::COMMAND_DISALLOWED; } @@ -889,13 +900,13 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( break; case Operation::UNCHANGED_DATA: - LOG_INFO( - "the operation Unchanged_Data is only allowed" - " for Advertising_Data"); + INFO(id_, + "the operation Unchanged_Data is only allowed" + " for Advertising_Data"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; default: - LOG_INFO("unknown operation (%x)", static_cast(operation)); + INFO(id_, "unknown operation ({})", static_cast(operation)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -907,9 +918,9 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( // Memory Capacity Exceeded (0x07). if (advertiser.scan_response_data.size() > properties_.le_max_advertising_data_length) { - LOG_INFO( - "the combined length of the scan response data exceeds the" - " advertising set capacity"); + INFO(id_, + "the combined length of the scan response data exceeds the" + " advertising set capacity"); advertiser.scan_response_data.clear(); advertiser.partial_scan_response_data = false; return ErrorCode::MEMORY_CAPACITY_EXCEEDED; @@ -925,9 +936,9 @@ ErrorCode LinkLayerController::LeSetExtendedScanResponseData( // the S=8 coding shall be assumed. if (advertiser.scan_response_data.size() > max_extended_advertising_pdu_size) { - LOG_INFO( - "the scan response data contained in the set is larger than the" - " available PDU capacity"); + INFO(id_, + "the scan response data contained in the set is larger than the" + " available PDU capacity"); advertiser.scan_response_data.clear(); advertiser.partial_scan_response_data = false; return ErrorCode::PACKET_TOO_LONG; @@ -942,9 +953,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { - LOG_INFO( - "extended advertising command rejected because legacy advertising" - " is being used"); + INFO(id_, + "extended advertising command rejected because legacy advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -955,8 +966,8 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // Advertising_Handle[i] arrayed parameter, then the Controller shall return // the error code Invalid HCI Command Parameters (0x12). if (used_advertising_handles[set.advertising_handle_]) { - LOG_INFO("advertising handle %02x is added more than once", - set.advertising_handle_); + INFO(id_, "advertising handle {:02x} is added more than once", + set.advertising_handle_); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -965,8 +976,8 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // Unknown Advertising Identifier (0x42). if (extended_advertisers_.find(set.advertising_handle_) == extended_advertisers_.end()) { - LOG_INFO("advertising handle %02x is not defined", - set.advertising_handle_); + INFO(id_, "advertising handle {:02x} is not defined", + set.advertising_handle_); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -985,7 +996,7 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // If Num_Sets is set to 0x00, the Controller shall return the error code // Invalid HCI Command Parameters (0x12). if (sets.empty()) { - LOG_INFO("enable is true but no advertising set is selected"); + INFO(id_, "enable is true but no advertising set is selected"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1020,9 +1031,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( if (connectable_advertising && directed_advertising && high_duty_cycle_advertising && (set.duration_ == 0 || duration > adv_direct_ind_high_timeout)) { - LOG_INFO( - "extended advertising is high duty cycle connectable directed" - " but the duration is either 0 or larger than 1.28 seconds"); + INFO(id_, + "extended advertising is high duty cycle connectable directed" + " but the duration is either 0 or larger than 1.28 seconds"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1031,9 +1042,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // Command Disallowed (0x0C). if (advertiser.partial_advertising_data || advertiser.partial_scan_response_data) { - LOG_INFO( - "advertising set contains partial advertising" - " or scan response data"); + INFO(id_, + "advertising set contains partial advertising" + " or scan response data"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1042,9 +1053,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // error code Command Disallowed (0x0C). if (extended_advertising && scannable_advertising && advertiser.scan_response_data.empty()) { - LOG_INFO( - "advertising set uses scannable extended advertising PDUs" - " but no scan response data is provided"); + INFO(id_, + "advertising set uses scannable extended advertising PDUs" + " but no scan response data is provided"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1056,9 +1067,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( advertiser.advertising_data.size() > ExtendedAdvertiser::GetMaxAdvertisingDataLength( advertising_event_properties)) { - LOG_INFO( - "advertising set uses connectable extended advertising PDUs" - " but the advertising data does not fit in AUX_ADV_IND PDUs"); + INFO(id_, + "advertising set uses connectable extended advertising PDUs" + " but the advertising data does not fit in AUX_ADV_IND PDUs"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1072,9 +1083,9 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( max_extended_advertising_pdu_size || advertiser.scan_response_data.size() > max_extended_advertising_pdu_size)) { - LOG_INFO( - "advertising set uses extended advertising PDUs" - " but the advertising data does not fit in advertising PDUs"); + INFO(id_, + "advertising set uses extended advertising PDUs" + " but the advertising data does not fit in advertising PDUs"); return ErrorCode::PACKET_TOO_LONG; } @@ -1103,7 +1114,8 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( // command, the Controller shall return the error code // Invalid HCI Command Parameters (0x12). if (random_address.GetAddress() == Address::kEmpty) { - LOG_INFO( + INFO( + id_, "own_address_type is Random_Device_Address but the Random_Address" " has not been initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; @@ -1126,10 +1138,10 @@ ErrorCode LinkLayerController::LeSetExtendedAdvertisingEnable( if (resolvable_address) { advertiser.advertising_address = resolvable_address.value(); } else if (random_address.GetAddress() == Address::kEmpty) { - LOG_INFO( - "own_address_type is Resolvable_Or_Random_Address but the" - " Resolving_List does not contain a matching entry and the" - " Random_Address is not initialized"); + INFO(id_, + "own_address_type is Resolvable_Or_Random_Address but the" + " Resolving_List does not contain a matching entry and the" + " Random_Address is not initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } else { advertiser.advertising_address = random_address; @@ -1166,8 +1178,8 @@ ErrorCode LinkLayerController::LeRemoveAdvertisingSet( // Unknown Advertising Identifier (0x42). auto advertiser = extended_advertisers_.find(advertising_handle); if (advertiser == extended_advertisers_.end()) { - LOG_INFO("no advertising set defined with handle %02x", - static_cast(advertising_handle)); + INFO(id_, "no advertising set defined with handle {:02x}", + static_cast(advertising_handle)); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -1175,8 +1187,8 @@ ErrorCode LinkLayerController::LeRemoveAdvertisingSet( // enabled, then the Controller shall return the error code // Command Disallowed (0x0C). if (advertiser->second.advertising_enable) { - LOG_INFO("the advertising set defined with handle %02x is enabled", - static_cast(advertising_handle)); + INFO(id_, "the advertising set defined with handle {:02x} is enabled", + static_cast(advertising_handle)); return ErrorCode::COMMAND_DISALLOWED; } @@ -1190,8 +1202,8 @@ ErrorCode LinkLayerController::LeClearAdvertisingSets() { // then the Controller shall return the error code Command Disallowed (0x0C). for (auto& advertiser : extended_advertisers_) { if (advertiser.second.advertising_enable) { - LOG_INFO("the advertising set with handle %02x is enabled", - static_cast(advertiser.second.advertising_enable)); + INFO(id_, "the advertising set with handle {:02x} is enabled", + static_cast(advertiser.second.advertising_enable)); return ErrorCode::COMMAND_DISALLOWED; } } @@ -1309,8 +1321,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingParameters( // the error code Unknown Advertising Identifier (0x42). // TODO(c++20) unordered_map<>::contains if (extended_advertisers_.count(advertising_handle) == 0) { - LOG_INFO("no advertising set defined with handle %02x", - static_cast(advertising_handle)); + INFO(id_, "no advertising set defined with handle {:02x}", + static_cast(advertising_handle)); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -1321,9 +1333,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingParameters( if (periodic_advertising_interval_min < 0x6 || periodic_advertising_interval_max < 0x6 || periodic_advertising_interval_max < periodic_advertising_interval_min) { - LOG_INFO("invalid periodic advertising interval range %04x - %04x", - periodic_advertising_interval_min, - periodic_advertising_interval_max); + INFO(id_, "invalid periodic advertising interval range {:04x} - {:04x}", + periodic_advertising_interval_min, periodic_advertising_interval_max); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1334,10 +1345,10 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingParameters( advertiser.advertising_event_properties.scannable_ || advertiser.advertising_event_properties.legacy_ || advertiser.advertising_event_properties.anonymous_) { - LOG_INFO( - "the periodic advertising set %02x specifies scannable," - " connectable, legacy or anonymous advertising", - static_cast(advertising_handle)); + INFO(id_, + "the periodic advertising set {:02x} specifies scannable," + " connectable, legacy or anonymous advertising", + static_cast(advertising_handle)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1345,8 +1356,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingParameters( // the specified advertising set, the Controller shall return the error code // Command Disallowed (0x0C). if (advertiser.periodic_advertising_enable) { - LOG_INFO("periodic advertising is enabled for the set %02x", - static_cast(advertising_handle)); + INFO(id_, "periodic advertising is enabled for the set {:02x}", + static_cast(advertising_handle)); return ErrorCode::COMMAND_DISALLOWED; } @@ -1365,10 +1376,10 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingParameters( if (advertiser.periodic_advertising_data.size() > ExtendedAdvertiser::GetMaxPeriodicAdvertisingDataLength( slots(periodic_advertising_interval_max))) { - LOG_INFO( - "the length of the periodic advertising data exceeds the maximum" - " that the controller can transmit within the maximum periodic" - " advertising interval"); + INFO(id_, + "the length of the periodic advertising data exceeds the maximum" + " that the controller can transmit within the maximum periodic" + " advertising interval"); return ErrorCode::PACKET_TOO_LONG; } @@ -1386,8 +1397,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( // Unknown Advertising Identifier (0x42). // TODO(c++20) unordered_map<>::contains if (extended_advertisers_.count(advertising_handle) == 0) { - LOG_INFO("no advertising set defined with handle %02x", - static_cast(advertising_handle)); + INFO(id_, "no advertising set defined with handle {:02x}", + static_cast(advertising_handle)); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -1396,8 +1407,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( // If the advertising set has not been configured for periodic advertising, // then the Controller shall return the error code Command Disallowed (0x0C). if (advertiser.periodic_advertising_interval.count() == 0) { - LOG_INFO("periodic advertising is not configured for the set %02x", - static_cast(advertising_handle)); + INFO(id_, "periodic advertising is not configured for the set {:02x}", + static_cast(advertising_handle)); return ErrorCode::COMMAND_DISALLOWED; } @@ -1407,9 +1418,9 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( if (advertiser.periodic_advertising_enable && operation != Operation::COMPLETE_ADVERTISEMENT && operation != Operation::UNCHANGED_DATA) { - LOG_INFO( - "periodic advertising is enabled and the operation is not" - " Complete_Advertisement or Unchanged_Data"); + INFO(id_, + "periodic advertising is enabled and the operation is not" + " Complete_Advertisement or Unchanged_Data"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1419,9 +1430,9 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( if (advertising_data.empty() && operation != Operation::COMPLETE_ADVERTISEMENT && operation != Operation::UNCHANGED_DATA) { - LOG_INFO( - "periodic advertising data is empty is enabled and the operation" - " is not Complete_Advertisement or Unchanged_Data"); + INFO(id_, + "periodic advertising data is empty is enabled and the operation" + " is not Complete_Advertisement or Unchanged_Data"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1435,7 +1446,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( (!advertiser.periodic_advertising_enable || advertiser.periodic_advertising_data.empty() || !advertising_data.empty())) { - LOG_INFO( + INFO( + id_, "Unchanged_Data operation is used but periodic advertising is disabled;" " or the periodic advertising set contains no data;" " or the advertising data is not empty"); @@ -1471,7 +1483,7 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( break; default: - LOG_INFO("unknown operation (%x)", static_cast(operation)); + INFO(id_, "unknown operation ({})", static_cast(operation)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1481,9 +1493,9 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( // shall return the error code Memory Capacity Exceeded (0x07). if (advertiser.periodic_advertising_data.size() > properties_.le_max_advertising_data_length) { - LOG_INFO( - "the length of the combined periodic advertising data exceeds" - " the maximum advertising data length"); + INFO(id_, + "the length of the combined periodic advertising data exceeds" + " the maximum advertising data length"); advertiser.periodic_advertising_data.clear(); advertiser.partial_periodic_advertising_data = false; return ErrorCode::MEMORY_CAPACITY_EXCEEDED; @@ -1496,10 +1508,10 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingData( if (advertiser.periodic_advertising_data.size() > ExtendedAdvertiser::GetMaxPeriodicAdvertisingDataLength( advertiser.periodic_advertising_interval)) { - LOG_INFO( - "the length of the combined periodic advertising data exceeds" - " the maximum that the controller can transmit within the current" - " periodic advertising interval"); + INFO(id_, + "the length of the combined periodic advertising data exceeds" + " the maximum that the controller can transmit within the current" + " periodic advertising interval"); advertiser.periodic_advertising_data.clear(); advertiser.partial_periodic_advertising_data = false; return ErrorCode::PACKET_TOO_LONG; @@ -1516,8 +1528,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingEnable( // Advertising Identifier (0x42). // TODO(c++20) unordered_map<>::contains if (extended_advertisers_.count(advertising_handle) == 0) { - LOG_INFO("no advertising set defined with handle %02x", - static_cast(advertising_handle)); + INFO(id_, "no advertising set defined with handle {:02x}", + static_cast(advertising_handle)); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -1532,7 +1544,7 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingEnable( // advertising set contains partial periodic advertising data, the Controller // shall return the error code Command Disallowed (0x0C). if (advertiser.partial_periodic_advertising_data) { - LOG_INFO("the advertising set contains partial periodic advertising data"); + INFO(id_, "the advertising set contains partial periodic advertising data"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1541,8 +1553,8 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingEnable( // the Controller shall either use vendor-specified parameters or return the // error code Command Disallowed (0x0C). if (advertiser.periodic_advertising_interval.count() == 0) { - LOG_INFO("periodic advertising is not configured for the set %02x", - static_cast(advertising_handle)); + INFO(id_, "periodic advertising is not configured for the set {:02x}", + static_cast(advertising_handle)); return ErrorCode::COMMAND_DISALLOWED; } @@ -1553,10 +1565,10 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingEnable( if (advertiser.periodic_advertising_data.size() > ExtendedAdvertiser::GetMaxPeriodicAdvertisingDataLength( advertiser.periodic_advertising_interval)) { - LOG_INFO( - "the length of the combined periodic advertising data exceeds" - " the maximum that the controller can transmit within the current" - " periodic advertising interval"); + INFO(id_, + "the length of the combined periodic advertising data exceeds" + " the maximum that the controller can transmit within the current" + " periodic advertising interval"); return ErrorCode::PACKET_TOO_LONG; } @@ -1568,10 +1580,10 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingEnable( advertiser.advertising_event_properties.scannable_ || advertiser.advertising_event_properties.legacy_ || advertiser.advertising_event_properties.anonymous_) { - LOG_INFO( - "the periodic advertising set %02x specifies scannable," - " connectable, legacy or anonymous advertising", - static_cast(advertising_handle)); + INFO(id_, + "the periodic advertising set {:02x} specifies scannable," + " connectable, legacy or anonymous advertising", + static_cast(advertising_handle)); return ErrorCode::COMMAND_DISALLOWED; } @@ -1581,10 +1593,10 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingEnable( // Parameter Value (0x11). if (include_adi && !properties_.SupportsLLFeature( LLFeaturesBits::PERIODIC_ADVERTISING_ADI_SUPPORT)) { - LOG_INFO( - "include ADI is true but the controller does not support the" - " Periodic Advertising ADI Supported feature", - static_cast(advertising_handle)); + INFO(id_, + "include ADI is true but the controller does not support the" + " Periodic Advertising ADI Supported feature", + static_cast(advertising_handle)); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -1593,7 +1605,7 @@ ErrorCode LinkLayerController::LeSetPeriodicAdvertisingEnable( } uint16_t ExtendedAdvertiser::GetMaxPeriodicAdvertisingDataLength( - slots periodic_advertising_interval) { + slots /*periodic_advertising_interval*/) { // TODO: evaluate the maximum length of the advertising PDU that can // be physically sent in the advertising interval. return max_extended_advertising_pdu_size; @@ -1618,7 +1630,7 @@ void LinkLayerController::LeAdvertising() { // HCI_LE_Connection_Complete or HCI_LE_Enhanced_Connection_Complete // event shall be generated with the Status code set to // Advertising Timeout (0x3C). - LOG_INFO("Directed Advertising Timeout"); + INFO(id_, "Directed Advertising Timeout"); legacy_advertiser_.Disable(); // TODO: The PTS tool expects an LE_Connection_Complete event in this @@ -1698,7 +1710,7 @@ void LinkLayerController::LeAdvertising() { // set to the error code Advertising Timeout (0x3C) may be generated // instead of or in addition to the HCI_LE_Advertising_Set_Terminated // event. - LOG_INFO("Extended Advertising Timeout"); + INFO(id_, "Extended Advertising Timeout"); advertiser.Disable(); bool high_duty_cycle_connectable_directed_advertising = @@ -1744,7 +1756,7 @@ void LinkLayerController::LeAdvertising() { // other than 0x00, an HCI_LE_Advertising_Set_Terminated event shall be // generated when the maximum number of extended advertising events has // been transmitted by the Controller. - LOG_INFO("Max Extended Advertising count reached"); + INFO(id_, "Max Extended Advertising count reached"); advertiser.Disable(); if (IsLeEventUnmasked(SubeventCode::ADVERTISING_SET_TERMINATED)) { @@ -1783,7 +1795,8 @@ void LinkLayerController::LeAdvertising() { type = model::packets::LegacyAdvertisingType::ADV_NONCONN_IND; break; default: - LOG_ALWAYS_FATAL( + FATAL( + id_, "unexpected raw advertising event properties;" " please check the extended advertising parameter validation"); break; diff --git a/tools/rootcanal/model/controller/le_advertiser.h b/tools/rootcanal/model/controller/le_advertiser.h index 19af1125d44e2a500c59eac3fb5869bd00882724..cef651642b18765a0dff1f059846a24e4c2b74ee 100644 --- a/tools/rootcanal/model/controller/le_advertiser.h +++ b/tools/rootcanal/model/controller/le_advertiser.h @@ -18,13 +18,13 @@ #include #include -#include #include #include +#include +#include "hci/address.h" #include "hci/address_with_type.h" -#include "hci/hci_packets.h" -#include "packets/link_layer_packets.h" +#include "packets/hci_packets.h" namespace rootcanal { diff --git a/tools/rootcanal/model/controller/link_layer_controller.cc b/tools/rootcanal/model/controller/link_layer_controller.cc index 00eb1b0c4220e8de102bdc207d66ad77bda59655..1ef188ba9aa98084288eda40100027469050f109 100644 --- a/tools/rootcanal/model/controller/link_layer_controller.cc +++ b/tools/rootcanal/model/controller/link_layer_controller.cc @@ -14,37 +14,52 @@ * limitations under the License. */ -#include "link_layer_controller.h" +#include "model/controller/link_layer_controller.h" + +#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "crypto/crypto.h" +#include "hci/address.h" +#include "hci/address_with_type.h" #include "log.h" -#include "packet/raw_builder.h" +#include "model/controller/acl_connection.h" +#include "model/controller/acl_connection_handler.h" +#include "model/controller/controller_properties.h" +#include "model/controller/le_advertiser.h" +#include "model/controller/sco_connection.h" +#include "packets/hci_packets.h" +#include "packets/link_layer_packets.h" +#include "phy.h" +#include "rust/include/rootcanal_rs.h" using namespace std::chrono; using bluetooth::hci::Address; using bluetooth::hci::AddressType; using bluetooth::hci::AddressWithType; -using bluetooth::hci::DirectAdvertisingAddressType; -using bluetooth::hci::EventCode; using bluetooth::hci::LLFeaturesBits; using bluetooth::hci::SubeventCode; using namespace model::packets; -using model::packets::PacketType; using namespace std::literals; using TaskId = rootcanal::LinkLayerController::TaskId; -// Temporay define, to be replaced when verbose log level is implemented. -#define LOG_VERB(...) LOG_INFO(__VA_ARGS__) - namespace rootcanal { constexpr milliseconds kNoDelayMs(0); +constexpr milliseconds kPageInterval(1000); const Address& LinkLayerController::GetAddress() const { return address_; } @@ -258,7 +273,7 @@ ErrorCode LinkLayerController::ReadRssi(uint16_t connection_handle, // Not documented: If the connection handle is not found, the Controller // shall return the error code Unknown Connection Identifier (0x02). if (!connections_.HasHandle(connection_handle)) { - LOG_INFO("unknown connection identifier"); + INFO(id_, "unknown connection identifier"); return ErrorCode::UNKNOWN_CONNECTION; } @@ -277,17 +292,15 @@ ErrorCode LinkLayerController::LeSetRandomAddress(Address random_address) { // the Controller shall return the error code Command Disallowed (0x0C). if (legacy_advertiser_.IsEnabled() || scanner_.IsEnabled() || initiator_.IsEnabled()) { - LOG_INFO("advertising, scanning or initiating are currently active"); + INFO(id_, "advertising, scanning or initiating are currently active"); return ErrorCode::COMMAND_DISALLOWED; } if (random_address == Address::kEmpty) { - LOG_INFO("the random address may not be set to 00:00:00:00:00:00"); + INFO(id_, "the random address may not be set to 00:00:00:00:00:00"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } - LOG_INFO("device random address configured to %s", - random_address.ToString().c_str()); random_address_ = random_address; return ErrorCode::SUCCESS; } @@ -297,10 +310,10 @@ ErrorCode LinkLayerController::LeSetResolvablePrivateAddressTimeout( uint16_t rpa_timeout) { // Note: no documented status code for this case. if (rpa_timeout < 0x1 || rpa_timeout > 0x0e10) { - LOG_INFO( - "rpa_timeout (0x%04x) is outside the range of supported values " - " 0x1 - 0x0e10", - rpa_timeout); + INFO(id_, + "rpa_timeout (0x{:04x}) is outside the range of supported values " + " 0x1 - 0x0e10", + rpa_timeout); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -315,7 +328,7 @@ ErrorCode LinkLayerController::LeReadPhy(uint16_t connection_handle, // Note: no documented status code for this case. if (!connections_.HasHandle(connection_handle) || connections_.GetPhyType(connection_handle) != Phy::Type::LOW_ENERGY) { - LOG_INFO("unknown or invalid connection handle"); + INFO(id_, "unknown or invalid connection handle"); return ErrorCode::UNKNOWN_CONNECTION; } @@ -339,7 +352,7 @@ ErrorCode LinkLayerController::LeSetDefaultPhy( tx_phys = supported_phys; } if (tx_phys == 0) { - LOG_INFO("TX_Phys does not configure any bit"); + INFO(id_, "TX_Phys does not configure any bit"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -350,7 +363,7 @@ ErrorCode LinkLayerController::LeSetDefaultPhy( rx_phys = supported_phys; } if (rx_phys == 0) { - LOG_INFO("RX_Phys does not configure any bit"); + INFO(id_, "RX_Phys does not configure any bit"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -359,11 +372,11 @@ ErrorCode LinkLayerController::LeSetDefaultPhy( // future use, the Controller shall return the error code Unsupported Feature // or Parameter Value (0x11). if ((tx_phys & ~supported_phys) != 0) { - LOG_INFO("TX_PhyS (%x) configures unsupported or reserved bits", tx_phys); + INFO(id_, "TX_PhyS {:x} configures unsupported or reserved bits", tx_phys); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } if ((rx_phys & ~supported_phys) != 0) { - LOG_INFO("RX_PhyS (%x) configures unsupported or reserved bits", rx_phys); + INFO(id_, "RX_PhyS {:x} configures unsupported or reserved bits", rx_phys); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -382,7 +395,7 @@ ErrorCode LinkLayerController::LeSetPhy( // Note: no documented status code for this case. if (!connections_.HasHandle(connection_handle) || connections_.GetPhyType(connection_handle) != Phy::Type::LOW_ENERGY) { - LOG_INFO("unknown or invalid connection handle"); + INFO(id_, "unknown or invalid connection handle"); return ErrorCode::UNKNOWN_CONNECTION; } @@ -393,7 +406,7 @@ ErrorCode LinkLayerController::LeSetPhy( tx_phys = supported_phys; } if (tx_phys == 0) { - LOG_INFO("TX_Phys does not configure any bit"); + INFO(id_, "TX_Phys does not configure any bit"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -404,7 +417,7 @@ ErrorCode LinkLayerController::LeSetPhy( rx_phys = supported_phys; } if (rx_phys == 0) { - LOG_INFO("RX_Phys does not configure any bit"); + INFO(id_, "RX_Phys does not configure any bit"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -413,11 +426,13 @@ ErrorCode LinkLayerController::LeSetPhy( // future use, the Controller shall return the error code Unsupported Feature // or Parameter Value (0x11). if ((tx_phys & ~supported_phys) != 0) { - LOG_INFO("TX_PhyS (%x) configures unsupported or reserved bits", tx_phys); + INFO(id_, "TX_PhyS ({:x}) configures unsupported or reserved bits", + tx_phys); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } if ((rx_phys & ~supported_phys) != 0) { - LOG_INFO("RX_PhyS (%x) configures unsupported or reserved bits", rx_phys); + INFO(id_, "RX_PhyS ({:x}) configures unsupported or reserved bits", + rx_phys); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -460,6 +475,13 @@ void LinkLayerController::IncomingLlPhyReq( ASSERT(phy_req.IsValid()); uint16_t connection_handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); + + if (connection_handle == kReservedHandle) { + INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), + incoming.GetSourceAddress()); + return; + } + AclConnection& connection = connections_.GetAclConnection(connection_handle); if (connection.GetRole() == bluetooth::hci::Role::PERIPHERAL) { @@ -515,6 +537,13 @@ void LinkLayerController::IncomingLlPhyRsp( ASSERT(phy_rsp.IsValid()); uint16_t connection_handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); + + if (connection_handle == kReservedHandle) { + INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), + incoming.GetSourceAddress()); + return; + } + AclConnection& connection = connections_.GetAclConnection(connection_handle); ASSERT(connection.GetRole() == bluetooth::hci::Role::CENTRAL); @@ -559,6 +588,13 @@ void LinkLayerController::IncomingLlPhyUpdateInd( ASSERT(phy_update_ind.IsValid()); uint16_t connection_handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); + + if (connection_handle == kReservedHandle) { + INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), + incoming.GetSourceAddress()); + return; + } + AclConnection& connection = connections_.GetAclConnection(connection_handle); ASSERT(connection.GetRole() == bluetooth::hci::Role::PERIPHERAL); @@ -644,16 +680,16 @@ ErrorCode LinkLayerController::LeAddDeviceToResolvingList( // • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or // HCI_LE_Periodic_Advertising_Create_Sync command is pending. if (le_resolving_list_enabled_ && ResolvingListBusy()) { - LOG_INFO( - "device is currently advertising, scanning, or establishing an" - " LE connection"); + INFO(id_, + "device is currently advertising, scanning, or establishing an" + " LE connection"); return ErrorCode::COMMAND_DISALLOWED; } // When a Controller cannot add a device to the list because there is no space // available, it shall return the error code Memory Capacity Exceeded (0x07). if (le_resolving_list_.size() >= properties_.le_resolving_list_size) { - LOG_INFO("resolving list is full"); + INFO(id_, "resolving list is full"); return ErrorCode::MEMORY_CAPACITY_EXCEEDED; } @@ -664,8 +700,8 @@ ErrorCode LinkLayerController::LeAddDeviceToResolvingList( for (auto const& entry : le_resolving_list_) { if ((entry.peer_identity_address_type == peer_identity_address_type && entry.peer_identity_address == peer_identity_address) || - entry.peer_irk == peer_irk) { - LOG_INFO("device is already present in the resolving list"); + (entry.peer_irk == peer_irk && !irk_is_zero(peer_irk))) { + INFO(id_, "device is already present in the resolving list"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } } @@ -690,9 +726,9 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromResolvingList( // • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or // HCI_LE_Periodic_Advertising_Create_Sync command is pending. if (le_resolving_list_enabled_ && ResolvingListBusy()) { - LOG_INFO( - "device is currently advertising, scanning, or establishing an" - " LE connection"); + INFO(id_, + "device is currently advertising, scanning, or establishing an" + " LE connection"); return ErrorCode::COMMAND_DISALLOWED; } @@ -708,7 +744,7 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromResolvingList( // When a Controller cannot remove a device from the resolving list because // it is not found, it shall return the error code // Unknown Connection Identifier (0x02). - LOG_INFO("peer address not found in the resolving list"); + INFO(id_, "peer address not found in the resolving list"); return ErrorCode::UNKNOWN_CONNECTION; } @@ -721,9 +757,9 @@ ErrorCode LinkLayerController::LeClearResolvingList() { // • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or // HCI_LE_Periodic_Advertising_Create_Sync command is pending. if (le_resolving_list_enabled_ && ResolvingListBusy()) { - LOG_INFO( - "device is currently advertising, scanning," - " or establishing an LE connection"); + INFO(id_, + "device is currently advertising, scanning," + " or establishing an LE connection"); return ErrorCode::COMMAND_DISALLOWED; } @@ -748,11 +784,10 @@ ErrorCode LinkLayerController::LeReadPeerResolvableAddress( // the Peer Identity Address, or if the Peer Identity Address cannot be found // in the resolving list, it shall return the error code // Unknown Connection Identifier (0x02). - LOG_INFO( - "peer identity address %s[%s] not found in the resolving list," - " or peer resolvable address unavailable", - peer_identity_address.ToString().c_str(), - PeerAddressTypeText(peer_identity_address_type).c_str()); + INFO(id_, + "peer identity address {}[{}] not found in the resolving list," + " or peer resolvable address unavailable", + peer_identity_address, PeerAddressTypeText(peer_identity_address_type)); return ErrorCode::UNKNOWN_CONNECTION; } @@ -773,11 +808,10 @@ ErrorCode LinkLayerController::LeReadLocalResolvableAddress( // the Peer Identity Address, or if the Peer Identity Address cannot be found // in the resolving list, it shall return the error code // Unknown Connection Identifier (0x02). - LOG_INFO( - "peer identity address %s[%s] not found in the resolving list," - " or peer resolvable address unavailable", - peer_identity_address.ToString().c_str(), - PeerAddressTypeText(peer_identity_address_type).c_str()); + INFO(id_, + "peer identity address {}[{}] not found in the resolving list," + " or peer resolvable address unavailable", + peer_identity_address, PeerAddressTypeText(peer_identity_address_type)); return ErrorCode::UNKNOWN_CONNECTION; } @@ -789,9 +823,9 @@ ErrorCode LinkLayerController::LeSetAddressResolutionEnable(bool enable) { // • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or // HCI_LE_Periodic_Advertising_Create_Sync command is pending. if (ResolvingListBusy()) { - LOG_INFO( - "device is currently advertising, scanning," - " or establishing an LE connection"); + INFO(id_, + "device is currently advertising, scanning," + " or establishing an LE connection"); return ErrorCode::COMMAND_DISALLOWED; } @@ -810,9 +844,9 @@ ErrorCode LinkLayerController::LeSetPrivacyMode( // • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or // HCI_LE_Periodic_Advertising_Create_Sync command is pending. if (le_resolving_list_enabled_ && ResolvingListBusy()) { - LOG_INFO( - "device is currently advertising, scanning," - " or establishing an LE connection"); + INFO(id_, + "device is currently advertising, scanning," + " or establishing an LE connection"); return ErrorCode::COMMAND_DISALLOWED; } @@ -826,7 +860,7 @@ ErrorCode LinkLayerController::LeSetPrivacyMode( // If the device is not on the resolving list, the Controller shall return // the error code Unknown Connection Identifier (0x02). - LOG_INFO("peer address not found in the resolving list"); + INFO(id_, "peer address not found in the resolving list"); return ErrorCode::UNKNOWN_CONNECTION; } @@ -845,9 +879,9 @@ ErrorCode LinkLayerController::LeClearFilterAcceptList() { // HCI_LE_Create_Connection or HCI_LE_Extended_Create_Connection // command is pending. if (FilterAcceptListBusy()) { - LOG_INFO( - "device is currently advertising, scanning," - " or establishing an LE connection using the filter accept list"); + INFO(id_, + "device is currently advertising, scanning," + " or establishing an LE connection using the filter accept list"); return ErrorCode::COMMAND_DISALLOWED; } @@ -867,9 +901,9 @@ ErrorCode LinkLayerController::LeAddDeviceToFilterAcceptList( // HCI_LE_Create_Connection or HCI_LE_Extended_Create_Connection // command is pending. if (FilterAcceptListBusy()) { - LOG_INFO( - "device is currently advertising, scanning," - " or establishing an LE connection using the filter accept list"); + INFO(id_, + "device is currently advertising, scanning," + " or establishing an LE connection using the filter accept list"); return ErrorCode::COMMAND_DISALLOWED; } @@ -877,7 +911,7 @@ ErrorCode LinkLayerController::LeAddDeviceToFilterAcceptList( // because there is no space available, it shall return the error code // Memory Capacity Exceeded (0x07). if (le_filter_accept_list_.size() >= properties_.le_filter_accept_list_size) { - LOG_INFO("filter accept list is full"); + INFO(id_, "filter accept list is full"); return ErrorCode::MEMORY_CAPACITY_EXCEEDED; } @@ -899,9 +933,9 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromFilterAcceptList( // HCI_LE_Create_Connection or HCI_LE_Extended_Create_Connection // command is pending. if (FilterAcceptListBusy()) { - LOG_INFO( - "device is currently advertising, scanning," - " or establishing an LE connection using the filter accept list"); + INFO(id_, + "device is currently advertising, scanning," + " or establishing an LE connection using the filter accept list"); return ErrorCode::COMMAND_DISALLOWED; } @@ -917,7 +951,7 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromFilterAcceptList( } // Note: this case is not documented. - LOG_INFO("address not found in the filter accept list"); + INFO(id_, "address not found in the filter accept list"); return ErrorCode::SUCCESS; } @@ -934,8 +968,8 @@ ErrorCode LinkLayerController::LeAddDeviceToPeriodicAdvertiserList( // Create_Sync command is pending, the Controller shall return the error code // Command Disallowed (0x0C). if (synchronizing_.has_value()) { - LOG_INFO( - "LE Periodic Advertising Create Sync command is currently pending"); + INFO(id_, + "LE Periodic Advertising Create Sync command is currently pending"); return ErrorCode::COMMAND_DISALLOWED; } @@ -944,7 +978,7 @@ ErrorCode LinkLayerController::LeAddDeviceToPeriodicAdvertiserList( // Capacity Exceeded (0x07). if (le_periodic_advertiser_list_.size() >= properties_.le_periodic_advertiser_list_size) { - LOG_INFO("periodic advertiser list is full"); + INFO(id_, "periodic advertiser list is full"); return ErrorCode::MEMORY_CAPACITY_EXCEEDED; } @@ -954,7 +988,7 @@ ErrorCode LinkLayerController::LeAddDeviceToPeriodicAdvertiserList( if (entry.advertiser_address_type == advertiser_address_type && entry.advertiser_address == advertiser_address && entry.advertising_sid == advertising_sid) { - LOG_INFO("entry is already found in the periodic advertiser list"); + INFO(id_, "entry is already found in the periodic advertiser list"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } } @@ -973,8 +1007,8 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromPeriodicAdvertiserList( // command is pending, the Controller shall return the error code Command // Disallowed (0x0C). if (synchronizing_.has_value()) { - LOG_INFO( - "LE Periodic Advertising Create Sync command is currently pending"); + INFO(id_, + "LE Periodic Advertising Create Sync command is currently pending"); return ErrorCode::COMMAND_DISALLOWED; } @@ -991,7 +1025,7 @@ ErrorCode LinkLayerController::LeRemoveDeviceFromPeriodicAdvertiserList( // When a Controller cannot remove an entry from the Periodic Advertiser list // because it is not found, the Controller shall return the error code Unknown // Advertising Identifier (0x42). - LOG_INFO("entry not found in the periodic advertiser list"); + INFO(id_, "entry not found in the periodic advertiser list"); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -1001,8 +1035,8 @@ ErrorCode LinkLayerController::LeClearPeriodicAdvertiserList() { // command is pending, the Controller shall return the error code Command // Disallowed (0x0C). if (synchronizing_.has_value()) { - LOG_INFO( - "LE Periodic Advertising Create Sync command is currently pending"); + INFO(id_, + "LE Periodic Advertising Create Sync command is currently pending"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1024,8 +1058,8 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSync( // Create_Sync command is pending, the Controller shall return the error code // Command Disallowed (0x0C). if (synchronizing_.has_value()) { - LOG_INFO( - "LE Periodic Advertising Create Sync command is currently pending"); + INFO(id_, + "LE Periodic Advertising Create Sync command is currently pending"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1033,8 +1067,8 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSync( // to 1, the Controller shall return the error code Command Disallowed (0x0C). uint8_t sync_cte_type_mask = 0x1f; if ((sync_cte_type & sync_cte_type_mask) == sync_cte_type_mask) { - LOG_INFO( - "Sync_CTE_Type is configured to ignore all types of advertisement"); + INFO(id_, + "Sync_CTE_Type is configured to ignore all types of advertisement"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1051,13 +1085,12 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSync( sync.advertising_sid == advertising_sid; } if (!options.use_periodic_advertiser_list_ && has_synchronized_train) { - LOG_INFO( - "the controller is already synchronized on the periodic advertising" - " train from %s[%s] - SID=0x%x", - advertiser_address.ToString().c_str(), - bluetooth::hci::AdvertiserAddressTypeText(advertiser_address_type) - .c_str(), - advertising_sid); + INFO(id_, + "the controller is already synchronized on the periodic advertising" + " train from {}[{}] - SID=0x{:x}", + advertiser_address, + bluetooth::hci::AdvertiserAddressTypeText(advertiser_address_type), + advertising_sid); return ErrorCode::CONNECTION_ALREADY_EXISTS; } @@ -1073,10 +1106,10 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSync( if (!options.disable_reporting_ && options.enable_duplicate_filtering_ && !properties_.SupportsLLFeature( LLFeaturesBits::PERIODIC_ADVERTISING_ADI_SUPPORT)) { - LOG_INFO( - "reporting and duplicate filtering are enabled in the options," - " but the controller does not support the Periodic Advertising ADI" - " Support feature"); + INFO(id_, + "reporting and duplicate filtering are enabled in the options," + " but the controller does not support the Periodic Advertising ADI" + " Support feature"); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -1088,9 +1121,9 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSync( !properties_.SupportsCommand( bluetooth::hci::OpCodeIndex:: LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE)) { - LOG_INFO( - "reporting is disabled in the options, but the controller does not" - " support the HCI_LE_Set_Periodic_Advertising_Receive_Enable command"); + INFO(id_, + "reporting is disabled in the options, but the controller does not" + " support the HCI_LE_Set_Periodic_Advertising_Receive_Enable command"); return ErrorCode::CONNECTION_FAILED_ESTABLISHMENT; } @@ -1111,7 +1144,7 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingCreateSyncCancel() { // Create_Sync command is pending, the Controller shall return the error code // Command Disallowed (0x0C). if (!synchronizing_.has_value()) { - LOG_INFO("no LE Periodic Advertising Create Sync command is pending"); + INFO(id_, "no LE Periodic Advertising Create Sync command is pending"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1142,7 +1175,7 @@ ErrorCode LinkLayerController::LePeriodicAdvertisingTerminateSync( // parameter does not exist, then the Controller shall return the error // code Unknown Advertising Identifier (0x42). if (synchronized_.count(sync_handle) == 0) { - LOG_INFO("the Sync_Handle 0x%x does not exist", sync_handle); + INFO(id_, "the Sync_Handle 0x{:x} does not exist", sync_handle); return ErrorCode::UNKNOWN_ADVERTISING_IDENTIFIER; } @@ -1162,16 +1195,16 @@ ErrorCode LinkLayerController::LeSetScanParameters( // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { - LOG_INFO( - "legacy advertising command rejected because extended advertising" - " is being used"); + INFO(id_, + "legacy advertising command rejected because extended advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } // The Host shall not issue this command when scanning is enabled in the // Controller; if it is the Command Disallowed error code shall be used. if (scanner_.IsEnabled()) { - LOG_INFO("scanning is currently enabled"); + INFO(id_, "scanning is currently enabled"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1180,19 +1213,20 @@ ErrorCode LinkLayerController::LeSetScanParameters( // error code based on similar advertising command. if (scan_interval < 0x4 || scan_interval > 0x4000 || scan_window < 0x4 || scan_window > 0x4000) { - LOG_INFO( - "le_scan_interval (0x%04x) and/or" - " le_scan_window (0x%04x) are outside the range" - " of supported values (0x0004 - 0x4000)", - scan_interval, scan_window); + INFO(id_, + "le_scan_interval (0x{:04x}) and/or" + " le_scan_window (0x{:04x}) are outside the range" + " of supported values (0x0004 - 0x4000)", + scan_interval, scan_window); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // The LE_Scan_Window parameter shall always be set to a value smaller // or equal to the value set for the LE_Scan_Interval parameter. if (scan_window > scan_interval) { - LOG_INFO("le_scan_window (0x%04x) is larger than le_scan_interval (0x%04x)", - scan_window, scan_interval); + INFO(id_, + "le_scan_window (0x{:04x}) is larger than le_scan_interval (0x{:04x})", + scan_window, scan_interval); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1212,14 +1246,15 @@ ErrorCode LinkLayerController::LeSetScanEnable(bool enable, // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { - LOG_INFO( - "legacy advertising command rejected because extended advertising" - " is being used"); + INFO(id_, + "legacy advertising command rejected because extended advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } if (!enable) { scanner_.scan_enable = false; + scanner_.pending_scan_request = {}; scanner_.history.clear(); return ErrorCode::SUCCESS; } @@ -1237,10 +1272,10 @@ ErrorCode LinkLayerController::LeSetScanEnable(bool enable, scanner_.own_address_type == bluetooth::hci::OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) && random_address_ == Address::kEmpty) { - LOG_INFO( - "own_address_type is Random_Device_Address or" - " Resolvable_or_Random_Address but the Random_Address" - " has not been initialized"); + INFO(id_, + "own_address_type is Random_Device_Address or" + " Resolvable_or_Random_Address but the Random_Address" + " has not been initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1248,6 +1283,7 @@ ErrorCode LinkLayerController::LeSetScanEnable(bool enable, scanner_.history.clear(); scanner_.timeout = {}; scanner_.periodical_timeout = {}; + scanner_.pending_scan_request = {}; scanner_.filter_duplicates = filter_duplicates ? bluetooth::hci::FilterDuplicates::ENABLED : bluetooth::hci::FilterDuplicates::DISABLED; @@ -1263,22 +1299,23 @@ ErrorCode LinkLayerController::LeSetExtendedScanParameters( bluetooth::hci::OwnAddressType own_address_type, bluetooth::hci::LeScanningFilterPolicy scanning_filter_policy, uint8_t scanning_phys, - std::vector scanning_phy_parameters) { + std::vector + scanning_phy_parameters) { uint8_t supported_phys = properties_.LeSupportedPhys(); // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { - LOG_INFO( - "extended advertising command rejected because legacy advertising" - " is being used"); + INFO(id_, + "extended advertising command rejected because legacy advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } // If the Host issues this command when scanning is enabled in the Controller, // the Controller shall return the error code Command Disallowed (0x0C). if (scanner_.IsEnabled()) { - LOG_INFO("scanning is currently enabled"); + INFO(id_, "scanning is currently enabled"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1286,20 +1323,20 @@ ErrorCode LinkLayerController::LeSetExtendedScanParameters( // including a bit that is reserved for future use, it should return the // error code Unsupported Feature or Parameter Value (0x11). if ((scanning_phys & ~supported_phys) != 0) { - LOG_INFO( - "scanning_phys (%02x) enables PHYs that are not supported by" - " the controller", - scanning_phys); + INFO(id_, + "scanning_phys ({:02x}) enables PHYs that are not supported by" + " the controller", + scanning_phys); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // TODO(c++20) std::popcount if (__builtin_popcount(scanning_phys) != int(scanning_phy_parameters.size())) { - LOG_INFO( - "scanning_phy_parameters (%zu)" - " does not match scanning_phys (%02x)", - scanning_phy_parameters.size(), scanning_phys); + INFO(id_, + "scanning_phy_parameters ({})" + " does not match scanning_phys ({:02x})", + scanning_phy_parameters.size(), scanning_phys); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1307,7 +1344,7 @@ ErrorCode LinkLayerController::LeSetExtendedScanParameters( // but assuming Unsupported Feature or Parameter Value (0x11) // error code based on HCI Extended LE Create Connecton command. if (scanning_phys == 0) { - LOG_INFO("scanning_phys is empty"); + INFO(id_, "scanning_phys is empty"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1316,18 +1353,19 @@ ErrorCode LinkLayerController::LeSetExtendedScanParameters( // the Controller shall return the error code // Invalid HCI Command Parameters (0x12). if (parameter.le_scan_interval_ < 0x4 || parameter.le_scan_window_ < 0x4) { - LOG_INFO( - "le_scan_interval (0x%04x) and/or" - " le_scan_window (0x%04x) are outside the range" - " of supported values (0x0004 - 0xffff)", - parameter.le_scan_interval_, parameter.le_scan_window_); + INFO(id_, + "le_scan_interval (0x{:04x}) and/or" + " le_scan_window (0x{:04x}) are outside the range" + " of supported values (0x0004 - 0xffff)", + parameter.le_scan_interval_, parameter.le_scan_window_); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } if (parameter.le_scan_window_ > parameter.le_scan_interval_) { - LOG_INFO( - "le_scan_window (0x%04x) is larger than le_scan_interval (0x%04x)", - parameter.le_scan_window_, parameter.le_scan_interval_); + INFO(id_, + "le_scan_window (0x{:04x}) is larger than le_scan_interval " + "(0x{:04x})", + parameter.le_scan_window_, parameter.le_scan_interval_); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } } @@ -1368,14 +1406,15 @@ ErrorCode LinkLayerController::LeSetExtendedScanEnable( // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { - LOG_INFO( - "extended advertising command rejected because legacy advertising" - " is being used"); + INFO(id_, + "extended advertising command rejected because legacy advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } if (!enable) { scanner_.scan_enable = false; + scanner_.pending_scan_request = {}; scanner_.history.clear(); return ErrorCode::SUCCESS; } @@ -1391,9 +1430,9 @@ ErrorCode LinkLayerController::LeSetExtendedScanEnable( if (filter_duplicates == bluetooth::hci::FilterDuplicates::RESET_EACH_PERIOD && (period == 0 || duration == 0)) { - LOG_INFO( - "filter_duplicates is Reset_Each_Period but either" - " the period or duration is 0"); + INFO(id_, + "filter_duplicates is Reset_Each_Period but either" + " the period or duration is 0"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1404,7 +1443,7 @@ ErrorCode LinkLayerController::LeSetExtendedScanEnable( // greater than or equal to the Period, the Controller shall return the // error code Invalid HCI Command Parameters (0x12). if (period != 0 && duration != 0 && duration_ms >= period_ms) { - LOG_INFO("the period is greater than or equal to the duration"); + INFO(id_, "the period is greater than or equal to the duration"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1421,10 +1460,10 @@ ErrorCode LinkLayerController::LeSetExtendedScanEnable( scanner_.own_address_type == bluetooth::hci::OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) && random_address_ == Address::kEmpty) { - LOG_INFO( - "own_address_type is Random_Device_Address or" - " Resolvable_or_Random_Address but the Random_Address" - " has not been initialized"); + INFO(id_, + "own_address_type is Random_Device_Address or" + " Resolvable_or_Random_Address but the Random_Address" + " has not been initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1432,6 +1471,7 @@ ErrorCode LinkLayerController::LeSetExtendedScanEnable( scanner_.history.clear(); scanner_.timeout = {}; scanner_.periodical_timeout = {}; + scanner_.pending_scan_request = {}; scanner_.filter_duplicates = filter_duplicates; scanner_.duration = duration_ms; scanner_.period = period_ms; @@ -1466,9 +1506,9 @@ ErrorCode LinkLayerController::LeCreateConnection( // Legacy advertising commands are disallowed when extended advertising // commands were used since the last reset. if (!SelectLegacyAdvertising()) { - LOG_INFO( - "legacy advertising command rejected because extended advertising" - " is being used"); + INFO(id_, + "legacy advertising command rejected because extended advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1476,7 +1516,7 @@ ErrorCode LinkLayerController::LeCreateConnection( // command is pending in the Controller, the Controller shall return the // error code Command Disallowed (0x0C). if (initiator_.IsEnabled()) { - LOG_INFO("initiator is currently enabled"); + INFO(id_, "initiator is currently enabled"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1485,19 +1525,19 @@ ErrorCode LinkLayerController::LeCreateConnection( // error code based on similar advertising command. if (scan_interval < 0x4 || scan_interval > 0x4000 || scan_window < 0x4 || scan_window > 0x4000) { - LOG_INFO( - "scan_interval (0x%04x) and/or " - "scan_window (0x%04x) are outside the range" - " of supported values (0x4 - 0x4000)", - scan_interval, scan_window); + INFO(id_, + "scan_interval (0x{:04x}) and/or " + "scan_window (0x{:04x}) are outside the range" + " of supported values (0x4 - 0x4000)", + scan_interval, scan_window); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // The LE_Scan_Window parameter shall be set to a value smaller or equal to // the value set for the LE_Scan_Interval parameter. if (scan_interval < scan_window) { - LOG_INFO("scan_window (0x%04x) is larger than scan_interval (0x%04x)", - scan_window, scan_interval); + INFO(id_, "scan_window (0x{:04x}) is larger than scan_interval (0x{:04x})", + scan_window, scan_interval); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1506,21 +1546,21 @@ ErrorCode LinkLayerController::LeCreateConnection( // error code based on similar advertising command. if (connection_interval_min < 0x6 || connection_interval_min > 0x0c80 || connection_interval_max < 0x6 || connection_interval_max > 0x0c80) { - LOG_INFO( - "connection_interval_min (0x%04x) and/or " - "connection_interval_max (0x%04x) are outside the range" - " of supported values (0x6 - 0x0c80)", - connection_interval_min, connection_interval_max); + INFO(id_, + "connection_interval_min (0x{:04x}) and/or " + "connection_interval_max (0x{:04x}) are outside the range" + " of supported values (0x6 - 0x0c80)", + connection_interval_min, connection_interval_max); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // The Connection_Interval_Min parameter shall not be greater than the // Connection_Interval_Max parameter. if (connection_interval_max < connection_interval_min) { - LOG_INFO( - "connection_interval_min (0x%04x) is larger than" - " connection_interval_max (0x%04x)", - connection_interval_min, connection_interval_max); + INFO(id_, + "connection_interval_min (0x{:04x}) is larger than" + " connection_interval_max (0x{:04x})", + connection_interval_min, connection_interval_max); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1528,10 +1568,10 @@ ErrorCode LinkLayerController::LeCreateConnection( // values but assuming Unsupported Feature or Parameter Value (0x11) // error code based on similar advertising command. if (max_latency > 0x01f3) { - LOG_INFO( - "max_latency (0x%04x) is outside the range" - " of supported values (0x0 - 0x01f3)", - max_latency); + INFO(id_, + "max_latency (0x{:04x}) is outside the range" + " of supported values (0x0 - 0x01f3)", + max_latency); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -1539,10 +1579,10 @@ ErrorCode LinkLayerController::LeCreateConnection( // values but assuming Unsupported Feature or Parameter Value (0x11) // error code based on similar advertising command. if (supervision_timeout < 0xa || supervision_timeout > 0x0c80) { - LOG_INFO( - "supervision_timeout (0x%04x) is outside the range" - " of supported values (0xa - 0x0c80)", - supervision_timeout); + INFO(id_, + "supervision_timeout (0x{:04x}) is outside the range" + " of supported values (0xa - 0x0c80)", + supervision_timeout); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -1552,11 +1592,11 @@ ErrorCode LinkLayerController::LeCreateConnection( milliseconds min_supervision_timeout = duration_cast( (1 + max_latency) * slots(2 * connection_interval_max) * 2); if (supervision_timeout * 10ms < min_supervision_timeout) { - LOG_INFO( - "supervision_timeout (%d ms) is smaller that the minimal supervision " - "timeout allowed by connection_interval_max and max_latency (%u ms)", - supervision_timeout * 10, - static_cast(min_supervision_timeout / 1ms)); + INFO(id_, + "supervision_timeout ({} ms) is smaller that the minimal supervision " + "timeout allowed by connection_interval_max and max_latency ({} ms)", + supervision_timeout * 10, + static_cast(min_supervision_timeout / 1ms)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1569,9 +1609,9 @@ ErrorCode LinkLayerController::LeCreateConnection( // error code Invalid HCI Command Parameters (0x12). if (own_address_type == OwnAddressType::RANDOM_DEVICE_ADDRESS && random_address_ == Address::kEmpty) { - LOG_INFO( - "own_address_type is Random_Device_Address but the Random_Address" - " has not been initialized"); + INFO(id_, + "own_address_type is Random_Device_Address but the Random_Address" + " has not been initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1585,10 +1625,10 @@ ErrorCode LinkLayerController::LeCreateConnection( initiator_filter_policy == InitiatorFilterPolicy::USE_PEER_ADDRESS && !GenerateResolvablePrivateAddress(peer_address, IrkSelection::Local) && random_address_ == Address::kEmpty) { - LOG_INFO( - "own_address_type is Resolvable_Or_Random_Address but the" - " Resolving_List does not contain a matching entry and the" - " Random_Address is not initialized"); + INFO(id_, + "own_address_type is Resolvable_Or_Random_Address but the" + " Resolving_List does not contain a matching entry and the" + " Random_Address is not initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1617,7 +1657,7 @@ ErrorCode LinkLayerController::LeCreateConnectionCancel() { // command is pending, then the Controller shall return the error code // Command Disallowed (0x0C). if (!initiator_.IsEnabled()) { - LOG_INFO("initiator is currently disabled"); + INFO(id_, "initiator is currently disabled"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1655,14 +1695,14 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( bluetooth::hci::InitiatorFilterPolicy initiator_filter_policy, bluetooth::hci::OwnAddressType own_address_type, AddressWithType peer_address, uint8_t initiating_phys, - std::vector + std::vector initiating_phy_parameters) { // Extended advertising commands are disallowed when legacy advertising // commands were used since the last reset. if (!SelectExtendedAdvertising()) { - LOG_INFO( - "extended advertising command rejected because legacy advertising" - " is being used"); + INFO(id_, + "extended advertising command rejected because legacy advertising" + " is being used"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1670,7 +1710,7 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // HCI_LE_Extended_Create_Connection command is pending in the Controller, // the Controller shall return the error code Command Disallowed (0x0C). if (initiator_.IsEnabled()) { - LOG_INFO("initiator is currently enabled"); + INFO(id_, "initiator is currently enabled"); return ErrorCode::COMMAND_DISALLOWED; } @@ -1678,20 +1718,20 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // including a bit that is reserved for future use, the latter should return // the error code Unsupported Feature or Parameter Value (0x11). if ((initiating_phys & 0xf8) != 0) { - LOG_INFO( - "initiating_phys (%02x) enables PHYs that are not supported by" - " the controller", - initiating_phys); + INFO(id_, + "initiating_phys ({:02x}) enables PHYs that are not supported by" + " the controller", + initiating_phys); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // TODO(c++20) std::popcount if (__builtin_popcount(initiating_phys) != int(initiating_phy_parameters.size())) { - LOG_INFO( - "initiating_phy_parameters (%zu)" - " does not match initiating_phys (%02x)", - initiating_phy_parameters.size(), initiating_phys); + INFO(id_, + "initiating_phy_parameters ({})" + " does not match initiating_phys ({:02x})", + initiating_phy_parameters.size(), initiating_phys); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1700,7 +1740,7 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // Controller shall return the error code // Invalid HCI Command Parameters (0x12). if (initiating_phys == 0) { - LOG_INFO("initiating_phys is empty"); + INFO(id_, "initiating_phys is empty"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1710,55 +1750,59 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // error code based on similar advertising command. if (parameter.scan_interval_ < 0x4 || parameter.scan_interval_ > 0x4000 || parameter.scan_window_ < 0x4 || parameter.scan_window_ > 0x4000) { - LOG_INFO( - "scan_interval (0x%04x) and/or " - "scan_window (0x%04x) are outside the range" - " of supported values (0x4 - 0x4000)", - parameter.scan_interval_, parameter.scan_window_); + INFO(id_, + "scan_interval (0x{:04x}) and/or " + "scan_window (0x{:04x}) are outside the range" + " of supported values (0x4 - 0x4000)", + parameter.scan_interval_, parameter.scan_window_); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // The LE_Scan_Window parameter shall be set to a value smaller or equal to // the value set for the LE_Scan_Interval parameter. if (parameter.scan_interval_ < parameter.scan_window_) { - LOG_INFO("scan_window (0x%04x) is larger than scan_interval (0x%04x)", - parameter.scan_window_, parameter.scan_interval_); + INFO(id_, + "scan_window (0x{:04x}) is larger than scan_interval (0x{:04x})", + parameter.scan_window_, parameter.scan_interval_); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } // Note: no explicit error code stated for invalid connection interval // values but assuming Unsupported Feature or Parameter Value (0x11) // error code based on similar advertising command. - if (parameter.conn_interval_min_ < 0x6 || - parameter.conn_interval_min_ > 0x0c80 || - parameter.conn_interval_max_ < 0x6 || - parameter.conn_interval_max_ > 0x0c80) { - LOG_INFO( - "connection_interval_min (0x%04x) and/or " - "connection_interval_max (0x%04x) are outside the range" - " of supported values (0x6 - 0x0c80)", - parameter.conn_interval_min_, parameter.conn_interval_max_); + if (parameter.connection_interval_min_ < 0x6 || + parameter.connection_interval_min_ > 0x0c80 || + parameter.connection_interval_max_ < 0x6 || + parameter.connection_interval_max_ > 0x0c80) { + INFO(id_, + "connection_interval_min (0x{:04x}) and/or " + "connection_interval_max (0x{:04x}) are outside the range" + " of supported values (0x6 - 0x0c80)", + parameter.connection_interval_min_, + parameter.connection_interval_max_); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } // The Connection_Interval_Min parameter shall not be greater than the // Connection_Interval_Max parameter. - if (parameter.conn_interval_max_ < parameter.conn_interval_min_) { - LOG_INFO( - "connection_interval_min (0x%04x) is larger than" - " connection_interval_max (0x%04x)", - parameter.conn_interval_min_, parameter.conn_interval_max_); + if (parameter.connection_interval_max_ < + parameter.connection_interval_min_) { + INFO(id_, + "connection_interval_min (0x{:04x}) is larger than" + " connection_interval_max (0x{:04x})", + parameter.connection_interval_min_, + parameter.connection_interval_max_); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } // Note: no explicit error code stated for invalid max_latency // values but assuming Unsupported Feature or Parameter Value (0x11) // error code based on similar advertising command. - if (parameter.conn_latency_ > 0x01f3) { - LOG_INFO( - "max_latency (0x%04x) is outside the range" - " of supported values (0x0 - 0x01f3)", - parameter.conn_latency_); + if (parameter.max_latency_ > 0x01f3) { + INFO(id_, + "max_latency (0x{:04x}) is outside the range" + " of supported values (0x0 - 0x01f3)", + parameter.max_latency_); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -1767,10 +1811,10 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // error code based on similar advertising command. if (parameter.supervision_timeout_ < 0xa || parameter.supervision_timeout_ > 0x0c80) { - LOG_INFO( - "supervision_timeout (0x%04x) is outside the range" - " of supported values (0xa - 0x0c80)", - parameter.supervision_timeout_); + INFO(id_, + "supervision_timeout (0x{:04x}) is outside the range" + " of supported values (0xa - 0x0c80)", + parameter.supervision_timeout_); return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } @@ -1778,12 +1822,13 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // (1 + Max_Latency) * Connection_Interval_Max * 2, where // Connection_Interval_Max is given in milliseconds. milliseconds min_supervision_timeout = duration_cast( - (1 + parameter.conn_latency_) * - slots(2 * parameter.conn_interval_max_) * 2); + (1 + parameter.max_latency_) * + slots(2 * parameter.connection_interval_max_) * 2); if (parameter.supervision_timeout_ * 10ms < min_supervision_timeout) { - LOG_INFO( - "supervision_timeout (%d ms) is smaller that the minimal supervision " - "timeout allowed by connection_interval_max and max_latency (%u ms)", + INFO( + id_, + "supervision_timeout ({} ms) is smaller that the minimal supervision " + "timeout allowed by connection_interval_max and max_latency ({} ms)", parameter.supervision_timeout_ * 10, static_cast(min_supervision_timeout / 1ms)); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; @@ -1799,9 +1844,9 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( // error code Invalid HCI Command Parameters (0x12). if (own_address_type == OwnAddressType::RANDOM_DEVICE_ADDRESS && random_address_ == Address::kEmpty) { - LOG_INFO( - "own_address_type is Random_Device_Address but the Random_Address" - " has not been initialized"); + INFO(id_, + "own_address_type is Random_Device_Address but the Random_Address" + " has not been initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1815,10 +1860,10 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( initiator_filter_policy == InitiatorFilterPolicy::USE_PEER_ADDRESS && !GenerateResolvablePrivateAddress(peer_address, IrkSelection::Local) && random_address_ == Address::kEmpty) { - LOG_INFO( - "own_address_type is Resolvable_Or_Random_Address but the" - " Resolving_List does not contain a matching entry and the" - " Random_Address is not initialized"); + INFO(id_, + "own_address_type is Resolvable_Or_Random_Address but the" + " Resolving_List does not contain a matching entry and the" + " Random_Address is not initialized"); return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } @@ -1839,10 +1884,10 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( .scan_interval = initiating_phy_parameters[offset].scan_interval_, .scan_window = initiating_phy_parameters[offset].scan_window_, .connection_interval_min = - initiating_phy_parameters[offset].conn_interval_min_, + initiating_phy_parameters[offset].connection_interval_min_, .connection_interval_max = - initiating_phy_parameters[offset].conn_interval_max_, - .max_latency = initiating_phy_parameters[offset].conn_latency_, + initiating_phy_parameters[offset].connection_interval_max_, + .max_latency = initiating_phy_parameters[offset].max_latency_, .supervision_timeout = initiating_phy_parameters[offset].supervision_timeout_, .min_ce_length = initiating_phy_parameters[offset].min_ce_length_, @@ -1857,10 +1902,10 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( .scan_interval = initiating_phy_parameters[offset].scan_interval_, .scan_window = initiating_phy_parameters[offset].scan_window_, .connection_interval_min = - initiating_phy_parameters[offset].conn_interval_min_, + initiating_phy_parameters[offset].connection_interval_min_, .connection_interval_max = - initiating_phy_parameters[offset].conn_interval_max_, - .max_latency = initiating_phy_parameters[offset].conn_latency_, + initiating_phy_parameters[offset].connection_interval_max_, + .max_latency = initiating_phy_parameters[offset].max_latency_, .supervision_timeout = initiating_phy_parameters[offset].supervision_timeout_, .min_ce_length = initiating_phy_parameters[offset].min_ce_length_, @@ -1875,10 +1920,10 @@ ErrorCode LinkLayerController::LeExtendedCreateConnection( .scan_interval = initiating_phy_parameters[offset].scan_interval_, .scan_window = initiating_phy_parameters[offset].scan_window_, .connection_interval_min = - initiating_phy_parameters[offset].conn_interval_min_, + initiating_phy_parameters[offset].connection_interval_min_, .connection_interval_max = - initiating_phy_parameters[offset].conn_interval_max_, - .max_latency = initiating_phy_parameters[offset].conn_latency_, + initiating_phy_parameters[offset].connection_interval_max_, + .max_latency = initiating_phy_parameters[offset].max_latency_, .supervision_timeout = initiating_phy_parameters[offset].supervision_timeout_, .min_ce_length = initiating_phy_parameters[offset].min_ce_length_, @@ -1938,6 +1983,11 @@ void LinkLayerController::SetLocalName(std::vector const& local_name) { std::copy(local_name.begin(), local_name.end(), local_name_.begin()); } +void LinkLayerController::SetExtendedInquiryResponse( + std::array const& extended_inquiry_response) { + extended_inquiry_response_ = extended_inquiry_response; +} + void LinkLayerController::SetExtendedInquiryResponse( std::vector const& extended_inquiry_response) { ASSERT(extended_inquiry_response.size() <= extended_inquiry_response_.size()); @@ -1947,17 +1997,19 @@ void LinkLayerController::SetExtendedInquiryResponse( } LinkLayerController::LinkLayerController(const Address& address, - const ControllerProperties& properties) - : address_(address), + const ControllerProperties& properties, + uint32_t id) + : id_(id), + address_(address), properties_(properties), - lm_(nullptr, link_manager_destroy) { - + lm_(nullptr, link_manager_destroy), + ll_(nullptr, link_layer_destroy) { if (properties_.quirks.has_default_random_address) { - LOG_WARN("Configuring a default random address for this controller"); + WARNING(id_, "Configuring a default random address for this controller"); random_address_ = Address { 0xba, 0xdb, 0xad, 0xba, 0xdb, 0xad }; } - ops_ = { + controller_ops_ = { .user_pointer = this, .get_handle = [](void* user, const uint8_t(*address)[6]) { @@ -1979,22 +2031,31 @@ LinkLayerController::LinkLayerController(const Address& address, reinterpret_cast(result)); }, - .extended_features = + .get_extended_features = [](void* user, uint8_t features_page) { auto controller = static_cast(user); return controller->GetLmpFeatures(features_page); }, + .get_le_features = + [](void* user) { + auto controller = static_cast(user); + return controller->GetLeSupportedFeatures(); + }, + + .get_le_event_mask = + [](void* user) { + auto controller = static_cast(user); + return controller->le_event_mask_; + }, + .send_hci_event = [](void* user, const uint8_t* data, uintptr_t len) { auto controller = static_cast(user); auto event_code = static_cast(data[0]); - auto payload = std::make_unique( - std::vector(data + 2, data + len)); - controller->send_event_(bluetooth::hci::EventBuilder::Create( - event_code, std::move(payload))); + event_code, std::vector(data + 2, data + len))); }, .send_lmp_packet = @@ -2002,17 +2063,38 @@ LinkLayerController::LinkLayerController(const Address& address, uintptr_t len) { auto controller = static_cast(user); - auto payload = std::make_unique( - std::vector(data, data + len)); - Address source = controller->GetAddress(); Address dest(*to); controller->SendLinkLayerPacket(model::packets::LmpBuilder::Create( - source, dest, std::move(payload))); + source, dest, std::vector(data, data + len))); + }, + + .send_llcp_packet = + [](void* user, uint16_t acl_connection_handle, const uint8_t* data, + uintptr_t len) { + auto controller = static_cast(user); + + if (!controller->connections_.HasHandle(acl_connection_handle)) { + ERROR( + "Dropping LLCP packet sent for unknown connection handle " + "0x{:x}", + acl_connection_handle); + return; + } + + AclConnection const& connection = + controller->connections_.GetAclConnection( + acl_connection_handle); + Address source = connection.GetOwnAddress().GetAddress(); + Address destination = connection.GetAddress().GetAddress(); + + controller->SendLinkLayerPacket(model::packets::LlcpBuilder::Create( + source, destination, std::vector(data, data + len))); }}; - lm_.reset(link_manager_create(ops_)); + lm_.reset(link_manager_create(controller_ops_)); + ll_.reset(link_layer_create(controller_ops_)); } LinkLayerController::~LinkLayerController() {} @@ -2045,8 +2127,8 @@ ErrorCode LinkLayerController::SendLeCommandToRemoteByAddress( own_address, peer_address)); break; default: - LOG_INFO("Dropping unhandled command 0x%04x", - static_cast(opcode)); + INFO(id_, "Dropping unhandled command 0x{:04x}", + static_cast(opcode)); return ErrorCode::UNKNOWN_HCI_COMMAND; } @@ -2054,8 +2136,8 @@ ErrorCode LinkLayerController::SendLeCommandToRemoteByAddress( } ErrorCode LinkLayerController::SendCommandToRemoteByAddress( - OpCode opcode, bluetooth::packet::PacketView args, - const Address& own_address, const Address& peer_address) { + OpCode opcode, pdl::packet::slice args, const Address& own_address, + const Address& peer_address) { switch (opcode) { case (OpCode::REMOTE_NAME_REQUEST): // LMP features get requested with remote name requests. @@ -2070,8 +2152,8 @@ ErrorCode LinkLayerController::SendCommandToRemoteByAddress( own_address, peer_address)); break; case (OpCode::READ_REMOTE_EXTENDED_FEATURES): { - uint8_t page_number = - (args.begin() + 2).extract(); // skip the handle + pdl::packet::slice page_number_slice = args.subrange(5, 1); + uint8_t page_number = page_number_slice.read_le(); SendLinkLayerPacket( model::packets::ReadRemoteExtendedFeaturesBuilder::Create( own_address, peer_address, page_number)); @@ -2086,8 +2168,8 @@ ErrorCode LinkLayerController::SendCommandToRemoteByAddress( own_address, peer_address)); break; default: - LOG_INFO("Dropping unhandled command 0x%04x", - static_cast(opcode)); + INFO(id_, "Dropping unhandled command 0x{:04x}", + static_cast(opcode)); return ErrorCode::UNKNOWN_HCI_COMMAND; } @@ -2095,7 +2177,7 @@ ErrorCode LinkLayerController::SendCommandToRemoteByAddress( } ErrorCode LinkLayerController::SendCommandToRemoteByHandle( - OpCode opcode, bluetooth::packet::PacketView args, uint16_t handle) { + OpCode opcode, pdl::packet::slice args, uint16_t handle) { if (!connections_.HasHandle(handle)) { return ErrorCode::UNKNOWN_CONNECTION; } @@ -2161,8 +2243,7 @@ ErrorCode LinkLayerController::SendScoToRemote( std::vector sco_data_bytes(sco_data.begin(), sco_data.end()); SendLinkLayerPacket(model::packets::ScoBuilder::Create( - source, destination, - std::make_unique(sco_data_bytes))); + source, destination, std::move(sco_data_bytes))); return ErrorCode::SUCCESS; } @@ -2213,10 +2294,9 @@ void LinkLayerController::IncomingPacket( // Drop packets not addressed to me if (!address_matches) { - LOG_INFO("%s | Dropping packet not addressed to me %s->%s (type 0x%x)", - address_.ToString().c_str(), source_address.ToString().c_str(), - destination_address.ToString().c_str(), - static_cast(incoming.GetType())); + INFO(id_, "{} | Dropping packet not addressed to me {}->{} (type 0x{:x})", + address_, source_address, destination_address, + static_cast(incoming.GetType())); return; } @@ -2227,12 +2307,18 @@ void LinkLayerController::IncomingPacket( case model::packets::PacketType::SCO: IncomingScoPacket(incoming); break; + case model::packets::PacketType::LE_CONNECTED_ISOCHRONOUS_PDU: + IncomingLeConnectedIsochronousPdu(incoming); + break; case model::packets::PacketType::DISCONNECT: IncomingDisconnectPacket(incoming); break; case model::packets::PacketType::LMP: IncomingLmpPacket(incoming); break; + case model::packets::PacketType::LLCP: + IncomingLlcpPacket(incoming); + break; case model::packets::PacketType::INQUIRY: if (inquiry_scan_enable_) { IncomingInquiryPacket(incoming, rssi); @@ -2241,15 +2327,6 @@ void LinkLayerController::IncomingPacket( case model::packets::PacketType::INQUIRY_RESPONSE: IncomingInquiryResponsePacket(incoming); break; - case PacketType::ISO: - IncomingIsoPacket(incoming); - break; - case PacketType::ISO_CONNECTION_REQUEST: - IncomingIsoConnectionRequestPacket(incoming); - break; - case PacketType::ISO_CONNECTION_RESPONSE: - IncomingIsoConnectionResponsePacket(incoming); - break; case model::packets::PacketType::LE_LEGACY_ADVERTISING_PDU: IncomingLeLegacyAdvertisingPdu(incoming, rssi); return; @@ -2367,8 +2444,8 @@ void LinkLayerController::IncomingPacket( IncomingLlPhyUpdateInd(incoming); break; default: - LOG_WARN("Dropping unhandled packet of type %s", - model::packets::PacketTypeText(incoming.GetType()).c_str()); + WARNING(id_, "Dropping unhandled packet of type {}", + model::packets::PacketTypeText(incoming.GetType())); } } @@ -2388,14 +2465,13 @@ void LinkLayerController::IncomingAclPacket( bluetooth::hci::PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; } - LOG_INFO("Acl Packet [%zu] %s -> %s", acl_data.size(), - incoming.GetSourceAddress().ToString().c_str(), - incoming.GetDestinationAddress().ToString().c_str()); + INFO(id_, "Acl Packet [{}] {} -> {}", acl_data.size(), + incoming.GetSourceAddress(), incoming.GetDestinationAddress()); uint16_t connection_handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); if (connection_handle == kReservedHandle) { - LOG_INFO("Dropping packet since connection does not exist"); + INFO(id_, "Dropping packet since connection does not exist"); return; } @@ -2414,7 +2490,7 @@ void LinkLayerController::IncomingAclPacket( auto acl_packet = bluetooth::hci::AclBuilder::Create( connection_handle, packet_boundary_flag, broadcast_flag, - std::make_unique(std::move(fragment))); + std::move(fragment)); send_acl_(std::move(acl_packet)); @@ -2429,7 +2505,7 @@ void LinkLayerController::IncomingScoPacket( Address source = incoming.GetSourceAddress(); uint16_t sco_handle = connections_.GetScoHandle(source); if (!connections_.HasScoHandle(sco_handle)) { - LOG_INFO("Spurious SCO packet from %s", source.ToString().c_str()); + INFO(id_, "Spurious SCO packet from {}", source); return; } @@ -2438,9 +2514,8 @@ void LinkLayerController::IncomingScoPacket( auto sco_data = sco.GetPayload(); std::vector sco_data_bytes(sco_data.begin(), sco_data.end()); - LOG_INFO("Sco Packet [%d] %s -> %s", static_cast(sco_data_bytes.size()), - incoming.GetSourceAddress().ToString().c_str(), - incoming.GetDestinationAddress().ToString().c_str()); + INFO(id_, "Sco Packet [{}] {} -> {}", static_cast(sco_data_bytes.size()), + incoming.GetSourceAddress(), incoming.GetDestinationAddress()); send_sco_(bluetooth::hci::ScoBuilder::Create( sco_handle, bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED, @@ -2504,8 +2579,7 @@ void LinkLayerController::IncomingReadRemoteSupportedFeaturesResponse( Address source = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandleOnlyAddress(source); if (handle == kReservedHandle) { - LOG_INFO("Discarding response from a disconnected device %s", - source.ToString().c_str()); + INFO(id_, "Discarding response from a disconnected device {}", source); return; } if (IsEventUnmasked(EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE)) { @@ -2539,8 +2613,7 @@ void LinkLayerController::IncomingReadRemoteExtendedFeaturesResponse( Address source = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandleOnlyAddress(source); if (handle == kReservedHandle) { - LOG_INFO("Discarding response from a disconnected device %s", - source.ToString().c_str()); + INFO(id_, "Discarding response from a disconnected device {}", source); return; } if (IsEventUnmasked(EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE)) { @@ -2569,8 +2642,7 @@ void LinkLayerController::IncomingReadRemoteVersionResponse( Address source = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandleOnlyAddress(source); if (handle == kReservedHandle) { - LOG_INFO("Discarding response from a disconnected device %s", - source.ToString().c_str()); + INFO(id_, "Discarding response from a disconnected device {}", source); return; } if (IsEventUnmasked(EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE)) { @@ -2595,8 +2667,7 @@ void LinkLayerController::IncomingReadClockOffsetResponse( Address source = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandleOnlyAddress(source); if (handle == kReservedHandle) { - LOG_INFO("Discarding response from a disconnected device %s", - source.ToString().c_str()); + INFO(id_, "Discarding response from a disconnected device {}", source); return; } if (IsEventUnmasked(EventCode::READ_CLOCK_OFFSET_COMPLETE)) { @@ -2607,28 +2678,29 @@ void LinkLayerController::IncomingReadClockOffsetResponse( void LinkLayerController::IncomingDisconnectPacket( model::packets::LinkLayerPacketView incoming) { - LOG_INFO("Disconnect Packet"); + INFO(id_, "Disconnect Packet"); auto disconnect = model::packets::DisconnectView::Create(incoming); ASSERT(disconnect.IsValid()); Address peer = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandleOnlyAddress(peer); if (handle == kReservedHandle) { - LOG_INFO("Discarding disconnect from a disconnected device %s", - peer.ToString().c_str()); + INFO(id_, "Discarding disconnect from a disconnected device {}", peer); return; } auto is_br_edr = connections_.GetPhyType(handle) == Phy::Type::BR_EDR; ASSERT_LOG( connections_.Disconnect( handle, [this](TaskId task_id) { CancelScheduledTask(task_id); }), - "GetHandle() returned invalid handle %hx", handle); + "GetHandle() returned invalid handle 0x{:x}", handle); uint8_t reason = disconnect.GetReason(); SendDisconnectionCompleteEvent(handle, ErrorCode(reason)); if (is_br_edr) { ASSERT(link_manager_remove_link( lm_.get(), reinterpret_cast(peer.data()))); + } else { + ASSERT(link_layer_remove_link(ll_.get(), handle)); } } @@ -2667,11 +2739,10 @@ void LinkLayerController::IncomingInquiryPacket( static_cast(GetPageScanRepetitionMode()), class_of_device_, GetClockOffset(), rssi, extended_inquiry_response_)); - } break; default: - LOG_WARN("Unhandled Incoming Inquiry of type %d", - static_cast(inquiry.GetType())); + WARNING(id_, "Unhandled Incoming Inquiry of type {}", + static_cast(inquiry.GetType())); return; } // TODO: Send an Inquiry Response Notification Event 7.7.74 @@ -2735,234 +2806,18 @@ void LinkLayerController::IncomingInquiryResponsePacket( basic_inquiry_response); ASSERT(inquiry_response.IsValid()); - send_event_(bluetooth::hci::ExtendedInquiryResultRawBuilder::Create( + send_event_(bluetooth::hci::ExtendedInquiryResultBuilder::Create( inquiry_response.GetSourceAddress(), static_cast( inquiry_response.GetPageScanRepetitionMode()), inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), inquiry_response.GetRssi(), - extended_inquiry_response_)); + inquiry_response.GetExtendedInquiryResponse())); } break; - default: - LOG_WARN("Unhandled Incoming Inquiry Response of type %d", - static_cast(basic_inquiry_response.GetInquiryType())); - } -} - -void LinkLayerController::IncomingIsoPacket(LinkLayerPacketView incoming) { - auto iso = IsoDataPacketView::Create(incoming); - ASSERT(iso.IsValid()); - - uint16_t cis_handle = iso.GetHandle(); - if (!connections_.HasCisHandle(cis_handle)) { - LOG_INFO("Dropping ISO packet to unknown handle 0x%hx", cis_handle); - return; - } - if (!connections_.HasConnectedCis(cis_handle)) { - LOG_INFO("Dropping ISO packet to a disconnected handle 0x%hx", cis_handle); - return; - } - - auto sc = iso.GetSc(); - switch (sc) { - case StartContinuation::START: { - auto iso_start = IsoStartView::Create(iso); - ASSERT(iso_start.IsValid()); - if (iso.GetCmplt() == Complete::COMPLETE) { - send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( - cis_handle, bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU, - 0 /* seq num */, bluetooth::hci::IsoPacketStatusFlag::VALID, - std::make_unique( - std::vector(iso_start.GetPayload().begin(), - iso_start.GetPayload().end())))); - } else { - send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( - cis_handle, bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT, - 0 /* seq num */, bluetooth::hci::IsoPacketStatusFlag::VALID, - std::make_unique( - std::vector(iso_start.GetPayload().begin(), - iso_start.GetPayload().end())))); - } - } break; - case StartContinuation::CONTINUATION: { - auto continuation = IsoContinuationView::Create(iso); - ASSERT(continuation.IsValid()); - if (iso.GetCmplt() == Complete::COMPLETE) { - send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( - cis_handle, bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT, - 0 /* seq num */, bluetooth::hci::IsoPacketStatusFlag::VALID, - std::make_unique( - std::vector(continuation.GetPayload().begin(), - continuation.GetPayload().end())))); - } else { - send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( - cis_handle, - bluetooth::hci::IsoPacketBoundaryFlag::CONTINUATION_FRAGMENT, - 0 /* seq num */, bluetooth::hci::IsoPacketStatusFlag::VALID, - std::make_unique( - std::vector(continuation.GetPayload().begin(), - continuation.GetPayload().end())))); - } - } break; - } -} - -void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) { - auto cis_handle = iso.GetConnectionHandle(); - if (!connections_.HasCisHandle(cis_handle)) { - LOG_INFO("Dropping ISO packet to unknown handle 0x%hx", cis_handle); - return; - } - if (!connections_.HasConnectedCis(cis_handle)) { - LOG_INFO("Dropping ISO packet to disconnected handle 0x%hx", cis_handle); - return; - } - - auto acl_handle = connections_.GetAclHandleForCisHandle(cis_handle); - uint16_t remote_handle = - connections_.GetRemoteCisHandleForCisHandle(cis_handle); - model::packets::StartContinuation start_flag = - model::packets::StartContinuation::START; - model::packets::Complete complete_flag = model::packets::Complete::COMPLETE; - switch (iso.GetPbFlag()) { - case bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU: - start_flag = model::packets::StartContinuation::START; - complete_flag = model::packets::Complete::COMPLETE; - break; - case bluetooth::hci::IsoPacketBoundaryFlag::CONTINUATION_FRAGMENT: - start_flag = model::packets::StartContinuation::CONTINUATION; - complete_flag = model::packets::Complete::INCOMPLETE; - break; - case bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT: - start_flag = model::packets::StartContinuation::START; - complete_flag = model::packets::Complete::INCOMPLETE; - break; - case bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT: - start_flag = model::packets::StartContinuation::CONTINUATION; - complete_flag = model::packets::Complete::INCOMPLETE; - break; - } - if (start_flag == model::packets::StartContinuation::START) { - if (iso.GetTsFlag() == bluetooth::hci::TimeStampFlag::PRESENT) { - auto timestamped = bluetooth::hci::IsoWithTimestampView::Create(iso); - ASSERT(timestamped.IsValid()); - uint32_t timestamp = timestamped.GetTimeStamp(); - std::vector payload; - for (const auto it : timestamped.GetPayload()) { - payload.push_back(it); - } - - SendLeLinkLayerPacket(model::packets::IsoStartBuilder::Create( - connections_.GetOwnAddress(acl_handle).GetAddress(), - connections_.GetAddress(acl_handle).GetAddress(), remote_handle, - complete_flag, timestamp, - std::make_unique(std::move(payload)))); - } else { - auto pkt = bluetooth::hci::IsoWithoutTimestampView::Create(iso); - ASSERT(pkt.IsValid()); - - auto payload = - std::make_unique(std::vector( - pkt.GetPayload().begin(), pkt.GetPayload().end())); - - SendLeLinkLayerPacket(model::packets::IsoStartBuilder::Create( - connections_.GetOwnAddress(acl_handle).GetAddress(), - connections_.GetAddress(acl_handle).GetAddress(), remote_handle, - complete_flag, 0, std::move(payload))); - } - } else { - auto pkt = bluetooth::hci::IsoWithoutTimestampView::Create(iso); - ASSERT(pkt.IsValid()); - auto payload = std::make_unique( - std::vector(pkt.GetPayload().begin(), pkt.GetPayload().end())); - SendLeLinkLayerPacket(model::packets::IsoContinuationBuilder::Create( - connections_.GetOwnAddress(acl_handle).GetAddress(), - connections_.GetAddress(acl_handle).GetAddress(), remote_handle, - complete_flag, std::move(payload))); - } -} - -void LinkLayerController::IncomingIsoConnectionRequestPacket( - LinkLayerPacketView incoming) { - auto req = IsoConnectionRequestView::Create(incoming); - ASSERT(req.IsValid()); - std::vector stream_configs; - bluetooth::hci::CisParametersConfig stream_config; - - stream_config.max_sdu_m_to_s_ = req.GetMaxSduMToS(); - stream_config.max_sdu_s_to_m_ = req.GetMaxSduSToM(); - - stream_configs.push_back(stream_config); - - uint8_t group_id = req.GetCigId(); - /* CIG should be created by the local host before use */ - bluetooth::hci::CreateCisConfig config; - config.cis_connection_handle_ = req.GetRequesterCisHandle(); - - config.acl_connection_handle_ = - connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); - connections_.CreatePendingCis(config); - connections_.SetRemoteCisHandle(config.cis_connection_handle_, - req.GetRequesterCisHandle()); - if (IsEventUnmasked(EventCode::LE_META_EVENT)) { - send_event_(bluetooth::hci::LeCisRequestBuilder::Create( - config.acl_connection_handle_, config.cis_connection_handle_, group_id, - req.GetId())); - } -} - -void LinkLayerController::IncomingIsoConnectionResponsePacket( - LinkLayerPacketView incoming) { - auto response = IsoConnectionResponseView::Create(incoming); - ASSERT(response.IsValid()); - - bluetooth::hci::CreateCisConfig config; - config.acl_connection_handle_ = response.GetRequesterAclHandle(); - config.cis_connection_handle_ = response.GetRequesterCisHandle(); - if (!connections_.HasPendingCisConnection(config.cis_connection_handle_)) { - LOG_INFO("Ignoring connection response with unknown CIS handle 0x%04hx", - config.cis_connection_handle_); - return; - } - ErrorCode status = static_cast(response.GetStatus()); - if (status != ErrorCode::SUCCESS) { - if (IsEventUnmasked(EventCode::LE_META_EVENT)) { - send_event_(bluetooth::hci::LeCisEstablishedBuilder::Create( - status, config.cis_connection_handle_, 0, 0, 0, 0, - bluetooth::hci::SecondaryPhyType::NO_PACKETS, - bluetooth::hci::SecondaryPhyType::NO_PACKETS, 0, 0, 0, 0, 0, 0, 0, - 0)); - } - return; - } - connections_.SetRemoteCisHandle(config.cis_connection_handle_, - response.GetResponderCisHandle()); - connections_.ConnectCis(config.cis_connection_handle_); - auto stream_parameters = - connections_.GetStreamParameters(config.cis_connection_handle_); - auto group_parameters = - connections_.GetGroupParameters(stream_parameters.group_id); - // TODO: Which of these are important enough to fake? - uint32_t cig_sync_delay = 0x100; - uint32_t cis_sync_delay = 0x200; - uint32_t latency_m_to_s = group_parameters.max_transport_latency_m_to_s; - uint32_t latency_s_to_m = group_parameters.max_transport_latency_s_to_m; - uint8_t nse = 1; - uint8_t bn_m_to_s = 0; - uint8_t bn_s_to_m = 0; - uint8_t ft_m_to_s = 0; - uint8_t ft_s_to_m = 0; - uint8_t max_pdu_m_to_s = 0x40; - uint8_t max_pdu_s_to_m = 0x40; - uint16_t iso_interval = 0x100; - if (IsEventUnmasked(EventCode::LE_META_EVENT)) { - send_event_(bluetooth::hci::LeCisEstablishedBuilder::Create( - status, config.cis_connection_handle_, cig_sync_delay, cis_sync_delay, - latency_m_to_s, latency_s_to_m, - bluetooth::hci::SecondaryPhyType::NO_PACKETS, - bluetooth::hci::SecondaryPhyType::NO_PACKETS, nse, bn_m_to_s, bn_s_to_m, - ft_m_to_s, ft_s_to_m, max_pdu_m_to_s, max_pdu_s_to_m, iso_interval)); + default: + WARNING(id_, "Unhandled Incoming Inquiry Response of type {}", + static_cast(basic_inquiry_response.GetInquiryType())); } } @@ -2996,10 +2851,14 @@ Address LinkLayerController::generate_rpa( rpa.address[0] = p[0]; rpa.address[1] = p[1]; rpa.address[2] = p[2]; - LOG_INFO("RPA %s", rpa.ToString().c_str()); + INFO("RPA {}", rpa); return rpa; } +bool LinkLayerController::irk_is_zero(std::array irk) { + return std::all_of(irk.begin(), irk.end(), [](uint8_t b) { return b == 0; }); +} + // Handle legacy advertising PDUs while in the Scanning state. void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( model::packets::LeLegacyAdvertisingPduView& pdu, uint8_t rssi) { @@ -3045,11 +2904,8 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( ResolvePrivateAddress(target_address, IrkSelection::Peer); if (resolved_advertising_address != advertising_address) { - LOG_VERB("Resolved the advertising address %s(%hhx) to %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - resolved_advertising_address.ToString().c_str(), - resolved_advertising_address.GetAddressType()); + DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address, + resolved_advertising_address); } // Vol 6, Part B § 4.3.3 Scanner filter policy @@ -3061,11 +2917,10 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( case bluetooth::hci::LeScanningFilterPolicy:: FILTER_ACCEPT_LIST_AND_INITIATORS_IDENTITY: if (!LeFilterAcceptListContainsDevice(resolved_advertising_address)) { - LOG_VERB( - "Legacy advertising ignored by scanner because the advertising " - "address %s(%hhx) is not in the filter accept list", - resolved_advertising_address.ToString().c_str(), - resolved_advertising_address.GetAddressType()); + DEBUG(id_, + "Legacy advertising ignored by scanner because the advertising " + "address {} is not in the filter accept list", + resolved_advertising_address); return; } break; @@ -3091,12 +2946,11 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( case bluetooth::hci::LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY: if (!IsLocalPublicOrRandomAddress(target_address) && !(target_address.IsRpa() && resolved_target_address)) { - LOG_VERB( - "Legacy advertising ignored by scanner because the directed " - "address %s(%hhx) does not match the current device or cannot be " - "resolved", - target_address.ToString().c_str(), - target_address.GetAddressType()); + DEBUG(id_, + "Legacy advertising ignored by scanner because the directed " + "address {} does not match the current device or cannot be " + "resolved", + target_address); return; } break; @@ -3109,12 +2963,11 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( FILTER_ACCEPT_LIST_AND_INITIATORS_IDENTITY: if (!IsLocalPublicOrRandomAddress(target_address) && !target_address.IsRpa()) { - LOG_VERB( - "Legacy advertising ignored by scanner because the directed " - "address %s(%hhx) does not match the current device or is not a " - "resovable private address", - target_address.ToString().c_str(), - target_address.GetAddressType()); + DEBUG(id_, + "Legacy advertising ignored by scanner because the directed " + "address {} does not match the current device or is not a " + "resovable private address", + target_address); return; } should_send_directed_advertising_report = @@ -3126,10 +2979,10 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( bool should_send_advertising_report = true; if (scanner_.filter_duplicates != bluetooth::hci::FilterDuplicates::DISABLED) { - if (scanner_.IsPacketInHistory(pdu)) { + if (scanner_.IsPacketInHistory(pdu.bytes())) { should_send_advertising_report = false; } else { - scanner_.AddPacketToHistory(pdu); + scanner_.AddPacketToHistory(pdu.bytes()); } } @@ -3157,7 +3010,7 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( if (LegacyAdvertising() && should_send_advertising_report && !should_send_directed_advertising_report && IsLeEventUnmasked(SubeventCode::ADVERTISING_REPORT)) { - bluetooth::hci::LeAdvertisingResponseRaw response; + bluetooth::hci::LeAdvertisingResponse response; response.address_type_ = resolved_advertising_address.GetAddressType(); response.address_ = resolved_advertising_address.GetAddress(); response.advertising_data_ = advertising_data; @@ -3181,14 +3034,13 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( break; } - send_event_( - bluetooth::hci::LeAdvertisingReportRawBuilder::Create({response})); + send_event_(bluetooth::hci::LeAdvertisingReportBuilder::Create({response})); } // Extended scanning. if (ExtendedAdvertising() && should_send_advertising_report && IsLeEventUnmasked(SubeventCode::EXTENDED_ADVERTISING_REPORT)) { - bluetooth::hci::LeExtendedAdvertisingResponseRaw response; + bluetooth::hci::LeExtendedAdvertisingResponse response; response.connectable_ = connectable_advertising; response.scannable_ = scannable_advertising; response.directed_ = directed_advertising; @@ -3217,8 +3069,8 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( } response.advertising_data_ = advertising_data; - send_event_(bluetooth::hci::LeExtendedAdvertisingReportRawBuilder::Create( - {response})); + send_event_( + bluetooth::hci::LeExtendedAdvertisingReportBuilder::Create({response})); } // Did the user enable Active scanning ? @@ -3232,29 +3084,25 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( // Note: only send SCAN requests in response to scannable advertising // events (ADV_IND, ADV_SCAN_IND). if (!scannable_advertising) { - LOG_VERB( - "Not sending LE Scan request to advertising address %s(%hhx) because " - "it is not scannable", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + DEBUG(id_, + "Not sending LE Scan request to advertising address {} because " + "it is not scannable", + advertising_address); } else if (!active_scanning) { - LOG_VERB( - "Not sending LE Scan request to advertising address %s(%hhx) because " - "the scanner is passive", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + DEBUG(id_, + "Not sending LE Scan request to advertising address {} because " + "the scanner is passive", + advertising_address); } else if (scanner_.pending_scan_request) { - LOG_VERB( - "Not sending LE Scan request to advertising address %s(%hhx) because " - "an LE Scan request is already pending", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + DEBUG(id_, + "Not sending LE Scan request to advertising address {} because " + "an LE Scan request is already pending", + advertising_address); } else if (!should_send_advertising_report) { - LOG_VERB( - "Not sending LE Scan request to advertising address %s(%hhx) because " - "the advertising message was filtered", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + DEBUG(id_, + "Not sending LE Scan request to advertising address {} because " + "the advertising message was filtered", + advertising_address); } else { // TODO: apply privacy mode in resolving list. // Scan requests with public or random device addresses must be ignored @@ -3299,12 +3147,10 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu( scanner_.connectable_scan_response = connectable_advertising; scanner_.pending_scan_request = advertising_address; - LOG_INFO( - "Sending LE Scan request to advertising address %s(%hhx) with scanning " - "address %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - scanning_address.ToString().c_str(), scanning_address.GetAddressType()); + INFO(id_, + "Sending LE Scan request to advertising address {} with scanning " + "address {}", + advertising_address, scanning_address); // The advertiser’s device address (AdvA field) in the scan request PDU // shall be the same as the advertiser’s device address (AdvA field) @@ -3335,15 +3181,15 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( // Note: only send CONNECT requests in response to connectable advertising // events (ADV_IND, ADV_DIRECT_IND). if (!connectable_advertising) { - LOG_VERB( - "Legacy advertising ignored by initiator because it is not " - "connectable"); + DEBUG(id_, + "Legacy advertising ignored by initiator because it is not " + "connectable"); return; } if (initiator_.pending_connect_request) { - LOG_VERB( - "Legacy advertising ignored because an LE Connect request is already " - "pending"); + DEBUG(id_, + "Legacy advertising ignored because an LE Connect request is already " + "pending"); return; } @@ -3367,20 +3213,19 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( switch (initiator_.initiator_filter_policy) { case bluetooth::hci::InitiatorFilterPolicy::USE_PEER_ADDRESS: if (resolved_advertising_address != initiator_.peer_address) { - LOG_VERB( - "Legacy advertising ignored by initiator because the " - "advertising address %s does not match the peer address %s", - resolved_advertising_address.ToString().c_str(), - initiator_.peer_address.ToString().c_str()); + DEBUG(id_, + "Legacy advertising ignored by initiator because the " + "advertising address {} does not match the peer address {}", + resolved_advertising_address, initiator_.peer_address); return; } break; case bluetooth::hci::InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST: if (!LeFilterAcceptListContainsDevice(resolved_advertising_address)) { - LOG_VERB( - "Legacy advertising ignored by initiator because the " - "advertising address %s is not in the filter accept list", - resolved_advertising_address.ToString().c_str()); + DEBUG(id_, + "Legacy advertising ignored by initiator because the " + "advertising address {} is not in the filter accept list", + resolved_advertising_address); return; } break; @@ -3396,10 +3241,10 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( // field). if (directed_advertising) { if (!IsLocalPublicOrRandomAddress(resolved_target_address)) { - LOG_VERB( - "Directed legacy advertising ignored by initiator because the " - "target address %s does not match the current device addresses", - resolved_advertising_address.ToString().c_str()); + DEBUG(id_, + "Directed legacy advertising ignored by initiator because the " + "target address {} does not match the current device addresses", + resolved_advertising_address); return; } if (resolved_target_address == target_address && @@ -3407,11 +3252,11 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS || initiator_.own_address_type == OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS)) { - LOG_VERB( - "Directed legacy advertising ignored by initiator because the " - "target address %s is static or public and the initiator is " - "configured to use resolvable addresses", - resolved_advertising_address.ToString().c_str()); + DEBUG(id_, + "Directed legacy advertising ignored by initiator because the " + "target address {} is static or public and the initiator is " + "configured to use resolvable addresses", + resolved_advertising_address); return; } } @@ -3456,15 +3301,15 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu( ? resolved_advertising_address : AddressWithType{}, initiating_address)) { - LOG_WARN("CreatePendingLeConnection failed for connection to %s", - advertising_address.ToString().c_str()); + WARNING(id_, "CreatePendingLeConnection failed for connection to {}", + advertising_address); } initiator_.pending_connect_request = advertising_address; + initiator_.initiating_address = initiating_address.GetAddress(); - LOG_INFO("Sending LE Connect request to %s with initiating address %s", - resolved_advertising_address.ToString().c_str(), - initiating_address.ToString().c_str()); + INFO(id_, "Sending LE Connect request to {} with initiating address {}", + resolved_advertising_address, initiating_address); // The advertiser’s device address (AdvA field) in the initiating PDU // shall be the same as the advertiser’s device address (AdvA field) @@ -3499,7 +3344,7 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( return; } if (!ExtendedAdvertising()) { - LOG_VERB("Extended advertising ignored because the scanner is legacy"); + DEBUG(id_, "Extended advertising ignored because the scanner is legacy"); return; } @@ -3532,11 +3377,9 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( ResolvePrivateAddress(target_address, IrkSelection::Peer); if (resolved_advertising_address != advertising_address) { - LOG_VERB("Resolved the advertising address %s(%hhx) to %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - resolved_advertising_address.ToString().c_str(), - resolved_advertising_address.GetAddressType()); + DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address, + advertising_address.GetAddressType(), resolved_advertising_address, + resolved_advertising_address.GetAddressType()); } // Vol 6, Part B § 4.3.3 Scanner filter policy @@ -3548,11 +3391,10 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( case bluetooth::hci::LeScanningFilterPolicy:: FILTER_ACCEPT_LIST_AND_INITIATORS_IDENTITY: if (!LeFilterAcceptListContainsDevice(resolved_advertising_address)) { - LOG_VERB( - "Extended advertising ignored by scanner because the advertising " - "address %s(%hhx) is not in the filter accept list", - resolved_advertising_address.ToString().c_str(), - resolved_advertising_address.GetAddressType()); + DEBUG(id_, + "Extended advertising ignored by scanner because the advertising " + "address {} is not in the filter accept list", + resolved_advertising_address); return; } break; @@ -3569,12 +3411,11 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( case bluetooth::hci::LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY: if (!IsLocalPublicOrRandomAddress(target_address) && !(target_address.IsRpa() && resolved_target_address)) { - LOG_VERB( - "Extended advertising ignored by scanner because the directed " - "address %s(%hhx) does not match the current device or cannot be " - "resolved", - target_address.ToString().c_str(), - target_address.GetAddressType()); + DEBUG(id_, + "Extended advertising ignored by scanner because the directed " + "address {} does not match the current device or cannot be " + "resolved", + target_address); return; } break; @@ -3587,12 +3428,11 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( FILTER_ACCEPT_LIST_AND_INITIATORS_IDENTITY: if (!IsLocalPublicOrRandomAddress(target_address) && !target_address.IsRpa()) { - LOG_VERB( - "Extended advertising ignored by scanner because the directed " - "address %s(%hhx) does not match the current device or is not a " - "resovable private address", - target_address.ToString().c_str(), - target_address.GetAddressType()); + DEBUG(id_, + "Extended advertising ignored by scanner because the directed " + "address {} does not match the current device or is not a " + "resovable private address", + target_address); return; } break; @@ -3602,16 +3442,16 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( bool should_send_advertising_report = true; if (scanner_.filter_duplicates != bluetooth::hci::FilterDuplicates::DISABLED) { - if (scanner_.IsPacketInHistory(pdu)) { + if (scanner_.IsPacketInHistory(pdu.bytes())) { should_send_advertising_report = false; } else { - scanner_.AddPacketToHistory(pdu); + scanner_.AddPacketToHistory(pdu.bytes()); } } if (should_send_advertising_report && IsLeEventUnmasked(SubeventCode::EXTENDED_ADVERTISING_REPORT)) { - bluetooth::hci::LeExtendedAdvertisingResponseRaw response; + bluetooth::hci::LeExtendedAdvertisingResponse response; response.connectable_ = connectable_advertising; response.scannable_ = scannable_advertising; response.directed_ = directed_advertising; @@ -3656,7 +3496,7 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( std::vector(advertising_data.begin() + offset, advertising_data.begin() + offset + fragment_size); offset += fragment_size; - send_event_(bluetooth::hci::LeExtendedAdvertisingReportRawBuilder::Create( + send_event_(bluetooth::hci::LeExtendedAdvertisingReportBuilder::Create( {response})); } while (offset < advertising_data.size()); } @@ -3672,29 +3512,25 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( // Note: only send SCAN requests in response to scannable advertising // events (ADV_IND, ADV_SCAN_IND). if (!scannable_advertising) { - LOG_VERB( - "Not sending LE Scan request to advertising address %s(%hhx) because " - "it is not scannable", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + DEBUG(id_, + "Not sending LE Scan request to advertising address {} because " + "it is not scannable", + advertising_address); } else if (!active_scanning) { - LOG_VERB( - "Not sending LE Scan request to advertising address %s(%hhx) because " - "the scanner is passive", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + DEBUG(id_, + "Not sending LE Scan request to advertising address {} because " + "the scanner is passive", + advertising_address); } else if (scanner_.pending_scan_request) { - LOG_VERB( - "Not sending LE Scan request to advertising address %s(%hhx) because " - "an LE Scan request is already pending", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + DEBUG(id_, + "Not sending LE Scan request to advertising address {} because " + "an LE Scan request is already pending", + advertising_address); } else if (!should_send_advertising_report) { - LOG_VERB( - "Not sending LE Scan request to advertising address %s(%hhx) because " - "the advertising message was filtered", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + DEBUG(id_, + "Not sending LE Scan request to advertising address {} because " + "the advertising message was filtered", + advertising_address); } else { // TODO: apply privacy mode in resolving list. // Scan requests with public or random device addresses must be ignored @@ -3740,12 +3576,10 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu( scanner_.connectable_scan_response = connectable_advertising; scanner_.pending_scan_request = advertising_address; - LOG_INFO( - "Sending LE Scan request to advertising address %s(%hhx) with scanning " - "address %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - scanning_address.ToString().c_str(), scanning_address.GetAddressType()); + INFO(id_, + "Sending LE Scan request to advertising address {} with scanning " + "address {}", + advertising_address, scanning_address); // The advertiser’s device address (AdvA field) in the scan request PDU // shall be the same as the advertiser’s device address (AdvA field) @@ -3765,7 +3599,7 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( return; } if (!ExtendedAdvertising()) { - LOG_VERB("Extended advertising ignored because the initiator is legacy"); + DEBUG(id_, "Extended advertising ignored because the initiator is legacy"); return; } @@ -3773,13 +3607,14 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( // Note: only send CONNECT requests in response to connectable advertising // events (ADV_IND, ADV_DIRECT_IND). if (!pdu.GetConnectable()) { - LOG_VERB( - "Extended advertising ignored by initiator because it is not " - "connectable"); + DEBUG(id_, + "Extended advertising ignored by initiator because it is not " + "connectable"); return; } if (initiator_.pending_connect_request) { - LOG_VERB( + DEBUG( + id_, "Extended advertising ignored because an LE Connect request is already " "pending"); return; @@ -3805,20 +3640,19 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( switch (initiator_.initiator_filter_policy) { case bluetooth::hci::InitiatorFilterPolicy::USE_PEER_ADDRESS: if (resolved_advertising_address != initiator_.peer_address) { - LOG_VERB( - "Extended advertising ignored by initiator because the " - "advertising address %s does not match the peer address %s", - resolved_advertising_address.ToString().c_str(), - initiator_.peer_address.ToString().c_str()); + DEBUG(id_, + "Extended advertising ignored by initiator because the " + "advertising address {} does not match the peer address {}", + resolved_advertising_address, initiator_.peer_address); return; } break; case bluetooth::hci::InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST: if (!LeFilterAcceptListContainsDevice(resolved_advertising_address)) { - LOG_VERB( - "Extended advertising ignored by initiator because the " - "advertising address %s is not in the filter accept list", - resolved_advertising_address.ToString().c_str()); + DEBUG(id_, + "Extended advertising ignored by initiator because the " + "advertising address {} is not in the filter accept list", + resolved_advertising_address); return; } break; @@ -3834,10 +3668,10 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( // field). if (pdu.GetDirected()) { if (!IsLocalPublicOrRandomAddress(resolved_target_address)) { - LOG_VERB( - "Directed extended advertising ignored by initiator because the " - "target address %s does not match the current device addresses", - resolved_advertising_address.ToString().c_str()); + DEBUG(id_, + "Directed extended advertising ignored by initiator because the " + "target address {} does not match the current device addresses", + resolved_advertising_address); return; } if (resolved_target_address == target_address && @@ -3845,11 +3679,11 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS || initiator_.own_address_type == OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS)) { - LOG_VERB( - "Directed extended advertising ignored by initiator because the " - "target address %s is static or public and the initiator is " - "configured to use resolvable addresses", - resolved_advertising_address.ToString().c_str()); + DEBUG(id_, + "Directed extended advertising ignored by initiator because the " + "target address {} is static or public and the initiator is " + "configured to use resolvable addresses", + resolved_advertising_address); return; } } @@ -3894,15 +3728,15 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu( ? resolved_advertising_address : AddressWithType{}, initiating_address)) { - LOG_WARN("CreatePendingLeConnection failed for connection to %s", - advertising_address.ToString().c_str()); + WARNING(id_, "CreatePendingLeConnection failed for connection to {}", + advertising_address); } initiator_.pending_connect_request = advertising_address; + initiator_.initiating_address = initiating_address.GetAddress(); - LOG_INFO("Sending LE Connect request to %s with initiating address %s", - resolved_advertising_address.ToString().c_str(), - initiating_address.ToString().c_str()); + INFO(id_, "Sending LE Connect request to {} with initiating address {}", + resolved_advertising_address, initiating_address); // The advertiser’s device address (AdvA field) in the initiating PDU // shall be the same as the advertiser’s device address (AdvA field) @@ -3941,7 +3775,7 @@ void LinkLayerController::IncomingLePeriodicAdvertisingPdu( return; } if (!ExtendedAdvertising()) { - LOG_VERB("Extended advertising ignored because the scanner is legacy"); + DEBUG(id_, "Extended advertising ignored because the scanner is legacy"); return; } @@ -3995,11 +3829,10 @@ void LinkLayerController::IncomingLePeriodicAdvertisingPdu( // If the periodic advertising event matches the synchronizing state, // create the synchronized train and report to the Host. if (matches_synchronizing) { - LOG_INFO("Established Sync with advertiser %s[%s] - SID 0x%x", - advertiser_address.ToString().c_str(), - bluetooth::hci::AdvertiserAddressTypeText(advertiser_address_type) - .c_str(), - advertising_sid); + INFO(id_, "Established Sync with advertiser {}[{}] - SID 0x{:x}", + advertiser_address, + bluetooth::hci::AdvertiserAddressTypeText(advertiser_address_type), + advertising_sid); // Use the first unused Sync_Handle. // Note: sync handles are allocated from a different number space // compared to connection handles. @@ -4091,16 +3924,15 @@ void LinkLayerController::IncomingScoConnectionRequest( auto request = model::packets::ScoConnectionRequestView::Create(incoming); ASSERT(request.IsValid()); - LOG_INFO("Received eSCO connection request from %s", - address.ToString().c_str()); + INFO(id_, "Received eSCO connection request from {}", address); // Automatically reject if connection request was already sent // from the current device. if (connections_.HasPendingScoConnection(address)) { - LOG_INFO( - "Rejecting eSCO connection request from %s, " - "an eSCO connection already exist with this device", - address.ToString().c_str()); + INFO(id_, + "Rejecting eSCO connection request from {}, " + "an eSCO connection already exist with this device", + address); SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( GetAddress(), address, @@ -4137,9 +3969,8 @@ void LinkLayerController::IncomingScoConnectionResponse( auto status = ErrorCode(response.GetStatus()); bool is_legacy = connections_.IsLegacyScoConnection(address); - LOG_INFO("Received eSCO connection response with status 0x%02x from %s", - static_cast(status), - incoming.GetSourceAddress().ToString().c_str()); + INFO(id_, "Received eSCO connection response with status 0x{:02x} from {}", + static_cast(status), incoming.GetSourceAddress()); if (status == ErrorCode::SUCCESS) { bool extended = response.GetExtended(); @@ -4198,11 +4029,10 @@ void LinkLayerController::IncomingScoDisconnect( auto reason = request.GetReason(); uint16_t handle = connections_.GetScoHandle(address); - LOG_INFO( - "Received eSCO disconnection request with" - " reason 0x%02x from %s", - static_cast(reason), - incoming.GetSourceAddress().ToString().c_str()); + INFO(id_, + "Received eSCO disconnection request with" + " reason 0x{:02x} from {}", + static_cast(reason), incoming.GetSourceAddress()); if (handle != kReservedHandle) { connections_.Disconnect( @@ -4224,6 +4054,161 @@ void LinkLayerController::IncomingLmpPacket( packet.size())); } +void LinkLayerController::IncomingLlcpPacket( + model::packets::LinkLayerPacketView incoming) { + Address address = incoming.GetSourceAddress(); + auto request = model::packets::LlcpView::Create(incoming); + ASSERT(request.IsValid()); + auto payload = request.GetPayload(); + auto packet = std::vector(payload.begin(), payload.end()); + uint16_t acl_connection_handle = connections_.GetHandleOnlyAddress(address); + + if (acl_connection_handle == kReservedHandle) { + INFO(id_, "Dropping LLCP packet since connection does not exist"); + return; + } + + ASSERT(link_layer_ingest_llcp(ll_.get(), acl_connection_handle, packet.data(), + packet.size())); +} + +void LinkLayerController::IncomingLeConnectedIsochronousPdu( + LinkLayerPacketView incoming) { + auto pdu = model::packets::LeConnectedIsochronousPduView::Create(incoming); + ASSERT(pdu.IsValid()); + auto data = pdu.GetData(); + auto packet = std::vector(data.begin(), data.end()); + uint8_t cig_id = pdu.GetCigId(); + uint8_t cis_id = pdu.GetCisId(); + uint16_t cis_connection_handle = 0; + uint16_t iso_sdu_length = packet.size(); + + if (!link_layer_get_cis_connection_handle(ll_.get(), cig_id, cis_id, + &cis_connection_handle)) { + INFO(id_, + "Dropping CIS pdu received on disconnected CIS cig_id={}, cis_id={}", + cig_id, cis_id); + return; + } + + // Fragment the ISO SDU if larger than the maximum payload size (4095). + constexpr size_t kMaxPayloadSize = 4095 - 4; // remove sequence_number and + // iso_sdu_length + size_t remaining_size = packet.size(); + size_t offset = 0; + auto packet_boundary_flag = + remaining_size <= kMaxPayloadSize + ? bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU + : bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT; + + do { + size_t fragment_size = std::min(kMaxPayloadSize, remaining_size); + std::vector fragment(packet.data() + offset, + packet.data() + offset + fragment_size); + + send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( + cis_connection_handle, packet_boundary_flag, pdu.GetSequenceNumber(), + iso_sdu_length, bluetooth::hci::IsoPacketStatusFlag::VALID, + std::move(fragment))); + + remaining_size -= fragment_size; + offset += fragment_size; + packet_boundary_flag = + remaining_size <= kMaxPayloadSize + ? bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT + : bluetooth::hci::IsoPacketBoundaryFlag::CONTINUATION_FRAGMENT; + } while (remaining_size > 0); +} + +void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) { + uint16_t cis_connection_handle = iso.GetConnectionHandle(); + auto pb_flag = iso.GetPbFlag(); + auto ts_flag = iso.GetTsFlag(); + auto iso_data_load = iso.GetPayload(); + + // In the Host to Controller direction, ISO_Data_Load_Length + // shall be less than or equal to the size of the buffer supported by the + // Controller (which is returned using the ISO_Data_Packet_Length return + // parameter of the LE Read Buffer Size command). + if (iso_data_load.size() > properties_.iso_data_packet_length) { + FATAL(id_, + "Received ISO HCI packet with ISO_Data_Load_Length ({}) larger than" + " the controller buffer size ISO_Data_Packet_Length ({})", + iso_data_load.size(), properties_.iso_data_packet_length); + } + + // The TS_Flag bit shall only be set if the PB_Flag field equals 0b00 or 0b10. + if (ts_flag == bluetooth::hci::TimeStampFlag::PRESENT && + (pb_flag == + bluetooth::hci::IsoPacketBoundaryFlag::CONTINUATION_FRAGMENT || + pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT)) { + FATAL(id_, + "Received ISO HCI packet with TS_Flag set, but no ISO Header is " + "expected"); + } + + uint8_t cig_id = 0; + uint8_t cis_id = 0; + uint16_t acl_connection_handle = kReservedHandle; + uint16_t packet_sequence_number = 0; + uint16_t max_sdu_length = 0; + + if (!link_layer_get_cis_information(ll_.get(), cis_connection_handle, + &acl_connection_handle, &cig_id, &cis_id, + &max_sdu_length)) { + INFO(id_, "Ignoring CIS pdu received on disconnected CIS handle={}", + cis_connection_handle); + return; + } + + if (pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT || + pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU) { + iso_sdu_.clear(); + } + + switch (ts_flag) { + case bluetooth::hci::TimeStampFlag::PRESENT: { + auto iso_with_timestamp = + bluetooth::hci::IsoWithTimestampView::Create(iso); + ASSERT(iso_with_timestamp.IsValid()); + auto iso_payload = iso_with_timestamp.GetPayload(); + iso_sdu_.insert(iso_sdu_.end(), iso_payload.begin(), iso_payload.end()); + packet_sequence_number = iso_with_timestamp.GetPacketSequenceNumber(); + break; + } + default: + case bluetooth::hci::TimeStampFlag::NOT_PRESENT: { + auto iso_without_timestamp = + bluetooth::hci::IsoWithoutTimestampView::Create(iso); + ASSERT(iso_without_timestamp.IsValid()); + auto iso_payload = iso_without_timestamp.GetPayload(); + iso_sdu_.insert(iso_sdu_.end(), iso_payload.begin(), iso_payload.end()); + packet_sequence_number = iso_without_timestamp.GetPacketSequenceNumber(); + break; + } + } + + if (pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT || + pb_flag == bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU) { + // Validate that the Host stack is not sending ISO SDUs that are larger + // that what was configured for the CIS. + if (iso_sdu_.size() > max_sdu_length) { + WARNING( + id_, + "attempted to send an SDU of length {} that exceeds the configure " + "Max_SDU_Length ({})", + iso_sdu_.size(), max_sdu_length); + return; + } + + SendLeLinkLayerPacket( + model::packets::LeConnectedIsochronousPduBuilder::Create( + address_, + connections_.GetAddress(acl_connection_handle).GetAddress(), cig_id, + cis_id, packet_sequence_number, std::move(iso_sdu_))); + } +} + uint16_t LinkLayerController::HandleLeConnection( AddressWithType address, AddressWithType own_address, bluetooth::hci::Role role, uint16_t connection_interval, @@ -4235,8 +4220,7 @@ uint16_t LinkLayerController::HandleLeConnection( uint16_t handle = connections_.CreateLeConnection(address, own_address, role); if (handle == kReservedHandle) { - LOG_WARN("No pending connection for connection from %s", - address.ToString().c_str()); + WARNING(id_, "No pending connection for connection from {}", address); return kReservedHandle; } @@ -4255,9 +4239,8 @@ uint16_t LinkLayerController::HandleLeConnection( AddressType::RANDOM_DEVICE_ADDRESS) { peer_address_type = AddressType::RANDOM_IDENTITY_ADDRESS; } else { - LOG_WARN("Unhandled resolved address type %s -> %s", - address.ToString().c_str(), - peer_resolved_address.ToString().c_str()); + WARNING(id_, "Unhandled resolved address type {} -> {}", address, + peer_resolved_address); } connection_address = peer_resolved_address.GetAddress(); } @@ -4279,6 +4262,12 @@ uint16_t LinkLayerController::HandleLeConnection( supervision_timeout, static_cast(0x00))); } + // Update the link layer with the new link. + ASSERT(link_layer_add_link( + ll_.get(), handle, + reinterpret_cast(address.GetAddress().data()), + static_cast(role))); + // Note: the HCI_LE_Connection_Complete event is immediately followed by // an HCI_LE_Channel_Selection_Algorithm event if the connection is created // using the LE_Extended_Create_Connection command (see Section 7.7.8.66). @@ -4303,9 +4292,9 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest( return false; } if (!legacy_advertiser_.IsConnectable()) { - LOG_VERB( - "LE Connect request ignored by legacy advertiser because it is not " - "connectable"); + DEBUG(id_, + "LE Connect request ignored by legacy advertiser because it is not " + "connectable"); return false; } @@ -4320,13 +4309,10 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest( }; if (legacy_advertiser_.GetAdvertisingAddress() != advertising_address) { - LOG_VERB( - "LE Connect request ignored by legacy advertiser because the " - "advertising address %s(%hhx) does not match %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - legacy_advertiser_.GetAdvertisingAddress().ToString().c_str(), - legacy_advertiser_.GetAdvertisingAddress().GetAddressType()); + DEBUG(id_, + "LE Connect request ignored by legacy advertiser because the " + "advertising address {} does not match {}", + advertising_address, legacy_advertiser_.GetAdvertisingAddress()); return false; } @@ -4340,25 +4326,18 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest( .value_or(initiating_address); if (resolved_initiating_address != initiating_address) { - LOG_VERB("Resolved the initiating address %s(%hhx) to %s(%hhx)", - initiating_address.ToString().c_str(), - initiating_address.GetAddressType(), - resolved_initiating_address.ToString().c_str(), - resolved_initiating_address.GetAddressType()); + DEBUG(id_, "Resolved the initiating address {} to {}", initiating_address, + resolved_initiating_address); } // When the Link Layer is [...] connectable directed advertising events the // advertising filter policy shall be ignored. if (legacy_advertiser_.IsDirected()) { if (legacy_advertiser_.GetTargetAddress() != resolved_initiating_address) { - LOG_VERB( - "LE Connect request ignored by legacy advertiser because the " - "initiating address %s(%hhx) does not match the target address " - "%s(%hhx)", - resolved_initiating_address.ToString().c_str(), - resolved_initiating_address.GetAddressType(), - legacy_advertiser_.GetTargetAddress().ToString().c_str(), - legacy_advertiser_.GetTargetAddress().GetAddressType()); + DEBUG(id_, + "LE Connect request ignored by legacy advertiser because the " + "initiating address {} does not match the target address {}", + resolved_initiating_address, legacy_advertiser_.GetTargetAddress()); return false; } } else { @@ -4371,22 +4350,20 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest( case bluetooth::hci::AdvertisingFilterPolicy::LISTED_CONNECT: case bluetooth::hci::AdvertisingFilterPolicy::LISTED_SCAN_AND_CONNECT: if (!LeFilterAcceptListContainsDevice(resolved_initiating_address)) { - LOG_VERB( - "LE Connect request ignored by legacy advertiser because the " - "initiating address %s(%hhx) is not in the filter accept list", - resolved_initiating_address.ToString().c_str(), - resolved_initiating_address.GetAddressType()); + DEBUG(id_, + "LE Connect request ignored by legacy advertiser because the " + "initiating address {} is not in the filter accept list", + resolved_initiating_address); return false; } break; } } - LOG_INFO( - "Accepting LE Connect request to legacy advertiser from initiating " - "address %s(%hhx)", - resolved_initiating_address.ToString().c_str(), - resolved_initiating_address.GetAddressType()); + INFO(id_, + "Accepting LE Connect request to legacy advertiser from initiating " + "address {}", + resolved_initiating_address); if (!connections_.CreatePendingLeConnection( initiating_address, @@ -4394,10 +4371,8 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest( ? resolved_initiating_address : AddressWithType{}, advertising_address)) { - LOG_WARN( - "CreatePendingLeConnection failed for connection from %s (type %hhx)", - initiating_address.GetAddress().ToString().c_str(), - initiating_address.GetAddressType()); + WARNING(id_, "CreatePendingLeConnection failed for connection from {}", + initiating_address.GetAddress()); return false; } @@ -4427,10 +4402,10 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest( return false; } if (!advertiser.IsConnectable()) { - LOG_VERB( - "LE Connect request ignored by extended advertiser %d because it is " - "not connectable", - advertiser.advertising_handle); + DEBUG(id_, + "LE Connect request ignored by extended advertiser {} because it is " + "not connectable", + advertiser.advertising_handle); return false; } @@ -4445,13 +4420,11 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest( }; if (advertiser.GetAdvertisingAddress() != advertising_address) { - LOG_VERB( - "LE Connect request ignored by extended advertiser %d because the " - "advertising address %s(%hhx) does not match %s(%hhx)", - advertiser.advertising_handle, advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - advertiser.GetAdvertisingAddress().ToString().c_str(), - advertiser.GetAdvertisingAddress().GetAddressType()); + DEBUG(id_, + "LE Connect request ignored by extended advertiser {} because the " + "advertising address {} does not match {}", + advertiser.advertising_handle, advertising_address, + advertiser.GetAdvertisingAddress()); return false; } @@ -4465,26 +4438,19 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest( .value_or(initiating_address); if (resolved_initiating_address != initiating_address) { - LOG_VERB("Resolved the initiating address %s(%hhx) to %s(%hhx)", - initiating_address.ToString().c_str(), - initiating_address.GetAddressType(), - resolved_initiating_address.ToString().c_str(), - resolved_initiating_address.GetAddressType()); + DEBUG(id_, "Resolved the initiating address {} to {}", initiating_address, + resolved_initiating_address); } // When the Link Layer is [...] connectable directed advertising events the // advertising filter policy shall be ignored. if (advertiser.IsDirected()) { if (advertiser.GetTargetAddress() != resolved_initiating_address) { - LOG_VERB( - "LE Connect request ignored by extended advertiser %d because the " - "initiating address %s(%hhx) does not match the target address " - "%s(%hhx)", - advertiser.advertising_handle, - resolved_initiating_address.ToString().c_str(), - resolved_initiating_address.GetAddressType(), - advertiser.GetTargetAddress().ToString().c_str(), - advertiser.GetTargetAddress().GetAddressType()); + DEBUG(id_, + "LE Connect request ignored by extended advertiser {} because the " + "initiating address {} does not match the target address {}", + advertiser.advertising_handle, resolved_initiating_address, + advertiser.GetTargetAddress()); return false; } } else { @@ -4497,25 +4463,20 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest( case bluetooth::hci::AdvertisingFilterPolicy::LISTED_CONNECT: case bluetooth::hci::AdvertisingFilterPolicy::LISTED_SCAN_AND_CONNECT: if (!LeFilterAcceptListContainsDevice(resolved_initiating_address)) { - LOG_VERB( - "LE Connect request ignored by extended advertiser %d because " - "the initiating address %s(%hhx) is not in the filter accept " - "list", - advertiser.advertising_handle, - resolved_initiating_address.ToString().c_str(), - resolved_initiating_address.GetAddressType()); + DEBUG(id_, + "LE Connect request ignored by extended advertiser {} because " + "the initiating address {} is not in the filter accept list", + advertiser.advertising_handle, resolved_initiating_address); return false; } break; } } - LOG_INFO( - "Accepting LE Connect request to extended advertiser %d from initiating " - "address %s(%hhx)", - advertiser.advertising_handle, - resolved_initiating_address.ToString().c_str(), - resolved_initiating_address.GetAddressType()); + INFO(id_, + "Accepting LE Connect request to extended advertiser {} from initiating " + "address {}", + advertiser.advertising_handle, resolved_initiating_address); if (!connections_.CreatePendingLeConnection( initiating_address, @@ -4523,10 +4484,8 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest( ? resolved_initiating_address : AddressWithType{}, advertising_address)) { - LOG_WARN( - "CreatePendingLeConnection failed for connection from %s (type %hhx)", - initiating_address.GetAddress().ToString().c_str(), - initiating_address.GetAddressType()); + WARNING(id_, "CreatePendingLeConnection failed for connection from {}", + initiating_address.GetAddress()); return false; } @@ -4587,10 +4546,8 @@ void LinkLayerController::IncomingLeConnectCompletePacket( incoming.GetSourceAddress(), static_cast( complete.GetAdvertisingAddressType())}; - LOG_INFO( - "Received LE Connect complete response with advertising address %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType()); + INFO(id_, "Received LE Connect complete response with advertising address {}", + advertising_address); HandleLeConnection(advertising_address, AddressWithType(incoming.GetDestinationAddress(), @@ -4613,9 +4570,8 @@ void LinkLayerController::IncomingLeConnectionParameterRequest( Address peer = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandleOnlyAddress(peer); if (handle == kReservedHandle) { - LOG_INFO("@%s: Unknown connection @%s", - incoming.GetDestinationAddress().ToString().c_str(), - peer.ToString().c_str()); + INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), + peer); return; } @@ -4644,9 +4600,8 @@ void LinkLayerController::IncomingLeConnectionParameterUpdate( Address peer = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandleOnlyAddress(peer); if (handle == kReservedHandle) { - LOG_INFO("@%s: Unknown connection @%s", - incoming.GetDestinationAddress().ToString().c_str(), - peer.ToString().c_str()); + INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), + peer); return; } if (IsLeEventUnmasked(SubeventCode::CONNECTION_UPDATE_COMPLETE)) { @@ -4658,14 +4613,13 @@ void LinkLayerController::IncomingLeConnectionParameterUpdate( void LinkLayerController::IncomingLeEncryptConnection( model::packets::LinkLayerPacketView incoming) { - LOG_INFO("IncomingLeEncryptConnection"); + INFO(id_, "IncomingLeEncryptConnection"); Address peer = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandleOnlyAddress(peer); if (handle == kReservedHandle) { - LOG_INFO("@%s: Unknown connection @%s", - incoming.GetDestinationAddress().ToString().c_str(), - peer.ToString().c_str()); + INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), + peer); return; } auto le_encrypt = model::packets::LeEncryptConnectionView::Create(incoming); @@ -4681,14 +4635,13 @@ void LinkLayerController::IncomingLeEncryptConnection( void LinkLayerController::IncomingLeEncryptConnectionResponse( model::packets::LinkLayerPacketView incoming) { - LOG_INFO("IncomingLeEncryptConnectionResponse"); + INFO(id_, "IncomingLeEncryptConnectionResponse"); // TODO: Check keys uint16_t handle = connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); if (handle == kReservedHandle) { - LOG_INFO("@%s: Unknown connection @%s", - incoming.GetDestinationAddress().ToString().c_str(), - incoming.GetSourceAddress().ToString().c_str()); + INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), + incoming.GetSourceAddress()); return; } ErrorCode status = ErrorCode::SUCCESS; @@ -4728,9 +4681,8 @@ void LinkLayerController::IncomingLeReadRemoteFeatures( connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); ErrorCode status = ErrorCode::SUCCESS; if (handle == kReservedHandle) { - LOG_WARN("@%s: Unknown connection @%s", - incoming.GetDestinationAddress().ToString().c_str(), - incoming.GetSourceAddress().ToString().c_str()); + WARNING(id_, "@{}: Unknown connection @{}", + incoming.GetDestinationAddress(), incoming.GetSourceAddress()); } SendLeLinkLayerPacket( model::packets::LeReadRemoteFeaturesResponseBuilder::Create( @@ -4747,9 +4699,8 @@ void LinkLayerController::IncomingLeReadRemoteFeaturesResponse( model::packets::LeReadRemoteFeaturesResponseView::Create(incoming); ASSERT(response.IsValid()); if (handle == kReservedHandle) { - LOG_INFO("@%s: Unknown connection @%s", - incoming.GetDestinationAddress().ToString().c_str(), - incoming.GetSourceAddress().ToString().c_str()); + INFO(id_, "@{}: Unknown connection @{}", incoming.GetDestinationAddress(), + incoming.GetSourceAddress()); status = ErrorCode::UNKNOWN_CONNECTION; } else { status = static_cast(response.GetStatus()); @@ -4769,20 +4720,18 @@ void LinkLayerController::ProcessIncomingLegacyScanRequest( return; } if (!legacy_advertiser_.IsScannable()) { - LOG_VERB( - "LE Scan request ignored by legacy advertiser because it is not " - "scannable"); + DEBUG(id_, + "LE Scan request ignored by legacy advertiser because it is not " + "scannable"); return; } if (advertising_address != legacy_advertiser_.advertising_address) { - LOG_VERB( + DEBUG( + id_, "LE Scan request ignored by legacy advertiser because the advertising " - "address %s(%hhx) does not match %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - legacy_advertiser_.GetAdvertisingAddress().ToString().c_str(), - legacy_advertiser_.GetAdvertisingAddress().GetAddressType()); + "address {} does not match {}", + advertising_address, legacy_advertiser_.GetAdvertisingAddress()); return; } @@ -4795,21 +4744,20 @@ void LinkLayerController::ProcessIncomingLegacyScanRequest( case bluetooth::hci::AdvertisingFilterPolicy::LISTED_SCAN: case bluetooth::hci::AdvertisingFilterPolicy::LISTED_SCAN_AND_CONNECT: if (!LeFilterAcceptListContainsDevice(resolved_scanning_address)) { - LOG_VERB( + DEBUG( + id_, "LE Scan request ignored by legacy advertiser because the scanning " - "address %s(%hhx) is not in the filter accept list", - resolved_scanning_address.ToString().c_str(), - resolved_scanning_address.GetAddressType()); + "address {} is not in the filter accept list", + resolved_scanning_address); return; } break; } - LOG_INFO( - "Accepting LE Scan request to legacy advertiser from scanning address " - "%s(%hhx)", - resolved_scanning_address.ToString().c_str(), - resolved_scanning_address.GetAddressType()); + INFO(id_, + "Accepting LE Scan request to legacy advertiser from scanning address " + "{}", + resolved_scanning_address); // Generate the SCAN_RSP packet. // Note: If the advertiser processes the scan request, the advertiser’s @@ -4835,21 +4783,19 @@ void LinkLayerController::ProcessIncomingExtendedScanRequest( return; } if (!advertiser.IsScannable()) { - LOG_VERB( - "LE Scan request ignored by extended advertiser %d because it is not " - "scannable", - advertiser.advertising_handle); + DEBUG(id_, + "LE Scan request ignored by extended advertiser {} because it is not " + "scannable", + advertiser.advertising_handle); return; } if (advertising_address != advertiser.advertising_address) { - LOG_VERB( - "LE Scan request ignored by extended advertiser %d because the " - "advertising address %s(%hhx) does not match %s(%hhx)", - advertiser.advertising_handle, advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - advertiser.GetAdvertisingAddress().ToString().c_str(), - advertiser.GetAdvertisingAddress().GetAddressType()); + DEBUG(id_, + "LE Scan request ignored by extended advertiser {} because the " + "advertising address {} does not match {}", + advertiser.advertising_handle, advertising_address, + advertiser.GetAdvertisingAddress()); return; } @@ -4862,12 +4808,10 @@ void LinkLayerController::ProcessIncomingExtendedScanRequest( case bluetooth::hci::AdvertisingFilterPolicy::LISTED_SCAN: case bluetooth::hci::AdvertisingFilterPolicy::LISTED_SCAN_AND_CONNECT: if (!LeFilterAcceptListContainsDevice(resolved_scanning_address)) { - LOG_VERB( - "LE Scan request ignored by extended advertiser %d because the " - "scanning address %s(%hhx) is not in the filter accept list", - advertiser.advertising_handle, - resolved_scanning_address.ToString().c_str(), - resolved_scanning_address.GetAddressType()); + DEBUG(id_, + "LE Scan request ignored by extended advertiser {} because the " + "scanning address {} is not in the filter accept list", + advertiser.advertising_handle, resolved_scanning_address); return; } break; @@ -4877,23 +4821,18 @@ void LinkLayerController::ProcessIncomingExtendedScanRequest( // scannable directed event types. if (advertiser.IsDirected() && advertiser.target_address != resolved_scanning_address) { - LOG_VERB( - "LE Scan request ignored by extended advertiser %d because the " - "scanning address %s(%hhx) does not match the target address %s(%hhx)", - advertiser.advertising_handle, - resolved_scanning_address.ToString().c_str(), - resolved_scanning_address.GetAddressType(), - advertiser.GetTargetAddress().ToString().c_str(), - advertiser.GetTargetAddress().GetAddressType()); + DEBUG(id_, + "LE Scan request ignored by extended advertiser {} because the " + "scanning address {} does not match the target address {}", + advertiser.advertising_handle, resolved_scanning_address, + advertiser.GetTargetAddress()); return; } - LOG_INFO( - "Accepting LE Scan request to extended advertiser %d from scanning " - "address %s(%hhx)", - advertiser.advertising_handle, - resolved_scanning_address.ToString().c_str(), - resolved_scanning_address.GetAddressType()); + INFO(id_, + "Accepting LE Scan request to extended advertiser {} from scanning " + "address {}", + advertiser.advertising_handle, resolved_scanning_address); // Generate the SCAN_RSP packet. // Note: If the advertiser processes the scan request, the advertiser’s @@ -4934,11 +4873,8 @@ void LinkLayerController::IncomingLeScanPacket( .value_or(scanning_address); if (resolved_scanning_address != scanning_address) { - LOG_VERB("Resolved the scanning address %s(%hhx) to %s(%hhx)", - scanning_address.ToString().c_str(), - scanning_address.GetAddressType(), - resolved_scanning_address.ToString().c_str(), - resolved_scanning_address.GetAddressType()); + DEBUG(id_, "Resolved the scanning address {} to {}", scanning_address, + resolved_scanning_address); } ProcessIncomingLegacyScanRequest(scanning_address, resolved_scanning_address, @@ -4960,9 +4896,9 @@ void LinkLayerController::IncomingLeScanResponsePacket( } if (!scanner_.pending_scan_request) { - LOG_VERB( - "LE Scan response ignored by scanner because no request is currently " - "pending"); + DEBUG(id_, + "LE Scan response ignored by scanner because no request is currently " + "pending"); return; } @@ -4975,13 +4911,10 @@ void LinkLayerController::IncomingLeScanResponsePacket( // advertiser’s device address (AdvA field) in the scan request PDU to which // it is responding. if (advertising_address != scanner_.pending_scan_request) { - LOG_VERB( - "LE Scan response ignored by scanner because the advertising address " - "%s(%hhx) does not match the pending request %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - scanner_.pending_scan_request.value().ToString().c_str(), - scanner_.pending_scan_request.value().GetAddressType()); + DEBUG(id_, + "LE Scan response ignored by scanner because the advertising address " + "{} does not match the pending request {}", + advertising_address, scanner_.pending_scan_request.value()); return; } @@ -4990,44 +4923,39 @@ void LinkLayerController::IncomingLeScanResponsePacket( .value_or(advertising_address); if (advertising_address != resolved_advertising_address) { - LOG_VERB("Resolved the advertising address %s(%hhx) to %s(%hhx)", - advertising_address.ToString().c_str(), - advertising_address.GetAddressType(), - resolved_advertising_address.ToString().c_str(), - resolved_advertising_address.GetAddressType()); + DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address, + resolved_advertising_address); } - LOG_INFO("Accepting LE Scan response from advertising address %s(%hhx)", - resolved_advertising_address.ToString().c_str(), - resolved_advertising_address.GetAddressType()); + INFO(id_, "Accepting LE Scan response from advertising address {}", + resolved_advertising_address); scanner_.pending_scan_request = {}; bool should_send_advertising_report = true; if (scanner_.filter_duplicates != bluetooth::hci::FilterDuplicates::DISABLED) { - if (scanner_.IsPacketInHistory(incoming)) { + if (scanner_.IsPacketInHistory(incoming.bytes())) { should_send_advertising_report = false; } else { - scanner_.AddPacketToHistory(incoming); + scanner_.AddPacketToHistory(incoming.bytes()); } } if (LegacyAdvertising() && should_send_advertising_report && IsLeEventUnmasked(SubeventCode::ADVERTISING_REPORT)) { - bluetooth::hci::LeAdvertisingResponseRaw response; + bluetooth::hci::LeAdvertisingResponse response; response.event_type_ = bluetooth::hci::AdvertisingEventType::SCAN_RESPONSE; response.address_ = resolved_advertising_address.GetAddress(); response.address_type_ = resolved_advertising_address.GetAddressType(); response.advertising_data_ = scan_response.GetScanResponseData(); response.rssi_ = rssi; - send_event_( - bluetooth::hci::LeAdvertisingReportRawBuilder::Create({response})); + send_event_(bluetooth::hci::LeAdvertisingReportBuilder::Create({response})); } if (ExtendedAdvertising() && should_send_advertising_report && IsLeEventUnmasked(SubeventCode::EXTENDED_ADVERTISING_REPORT)) { - bluetooth::hci::LeExtendedAdvertisingResponseRaw response; + bluetooth::hci::LeExtendedAdvertisingResponse response; response.address_ = resolved_advertising_address.GetAddress(); response.address_type_ = static_cast( @@ -5041,8 +4969,8 @@ void LinkLayerController::IncomingLeScanResponsePacket( response.tx_power_ = 0x7F; response.advertising_data_ = scan_response.GetScanResponseData(); response.rssi_ = rssi; - send_event_(bluetooth::hci::LeExtendedAdvertisingReportRawBuilder::Create( - {response})); + send_event_( + bluetooth::hci::LeExtendedAdvertisingReportBuilder::Create({response})); } } @@ -5064,8 +4992,9 @@ void LinkLayerController::LeScanning() { now >= scanner_.timeout.value()) { // At the end of a single scan (Duration non-zero but Period zero), // an HCI_LE_Scan_Timeout event shall be generated. - LOG_INFO("Extended Scan Timeout"); + INFO(id_, "Extended Scan Timeout"); scanner_.scan_enable = false; + scanner_.pending_scan_request = {}; scanner_.history.clear(); if (IsLeEventUnmasked(SubeventCode::SCAN_TIMEOUT)) { send_event_(bluetooth::hci::LeScanTimeoutBuilder::Create()); @@ -5094,8 +5023,8 @@ void LinkLayerController::LeSynchronization() { std::vector removed_sync_handles; for (auto& [_, sync] : synchronized_) { if (sync.timeout > std::chrono::steady_clock::now()) { - LOG_INFO("Periodic advertising sync with handle 0x%x lost", - sync.sync_handle); + INFO(id_, "Periodic advertising sync with handle 0x{:x} lost", + sync.sync_handle); removed_sync_handles.push_back(sync.sync_handle); } if (IsLeEventUnmasked(SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST)) { @@ -5111,87 +5040,120 @@ void LinkLayerController::LeSynchronization() { void LinkLayerController::IncomingPagePacket( model::packets::LinkLayerPacketView incoming) { + auto bd_addr = incoming.GetSourceAddress(); auto page = model::packets::PageView::Create(incoming); ASSERT(page.IsValid()); - LOG_INFO("from %s", incoming.GetSourceAddress().ToString().c_str()); + + // [HCI] 7.3.3 Set Event Filter command + // If the Auto_Accept_Flag is off and the Host has masked the + // HCI_Connection_Request event, the Controller shall reject the + // connection attempt. + if (!IsEventUnmasked(EventCode::CONNECTION_REQUEST)) { + INFO(id_, + "rejecting connection request from {} because the HCI_Connection_Request" + " event is masked by the Host", bd_addr); + SendLinkLayerPacket( + model::packets::PageRejectBuilder::Create( + GetAddress(), bd_addr, static_cast(ErrorCode::CONNECTION_TIMEOUT))); + return; + } + + // Cannot establish two BR-EDR connections with the same peer. + if (connections_.GetAclConnectionHandle(bd_addr).has_value()) { + return; + } bool allow_role_switch = page.GetAllowRoleSwitch(); if (!connections_.CreatePendingConnection( - incoming.GetSourceAddress(), - authentication_enable_ == AuthenticationEnable::REQUIRED, + bd_addr, authentication_enable_ == AuthenticationEnable::REQUIRED, allow_role_switch)) { - // Send a response to indicate that we're busy, or drop the packet? - LOG_WARN("Failed to create a pending connection for %s", - incoming.GetSourceAddress().ToString().c_str()); + // Will be triggered when multiple hosts are paging simultaneously; + // only one connection will be accepted. + WARNING(id_, "Failed to create a pending connection for {}", bd_addr); + return; } - bluetooth::hci::Address source_address{}; - bluetooth::hci::Address::FromString(page.GetSourceAddress().ToString(), - source_address); - - if (IsEventUnmasked(EventCode::CONNECTION_REQUEST)) { - send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( - source_address, page.GetClassOfDevice(), - bluetooth::hci::ConnectionRequestLinkType::ACL)); - } + send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( + bd_addr, page.GetClassOfDevice(), + bluetooth::hci::ConnectionRequestLinkType::ACL)); } void LinkLayerController::IncomingPageRejectPacket( model::packets::LinkLayerPacketView incoming) { - LOG_INFO("%s", incoming.GetSourceAddress().ToString().c_str()); + auto bd_addr = incoming.GetSourceAddress(); auto reject = model::packets::PageRejectView::Create(incoming); ASSERT(reject.IsValid()); - LOG_INFO("Sending CreateConnectionComplete"); + + if (!page_.has_value() || page_->bd_addr != bd_addr) { + INFO(id_, + "ignoring Page Reject packet received when not in Page state," + " or paging to a different address"); + return; + } + + INFO(id_, "Received Page Reject packet from {}", bd_addr); + page_ = {}; + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - static_cast(reject.GetReason()), 0x0eff, - incoming.GetSourceAddress(), bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); + static_cast(reject.GetReason()), 0, bd_addr, + bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED)); } } void LinkLayerController::IncomingPageResponsePacket( model::packets::LinkLayerPacketView incoming) { - Address peer = incoming.GetSourceAddress(); - LOG_INFO("%s", peer.ToString().c_str()); - uint16_t handle = - connections_.CreateConnection(peer, incoming.GetDestinationAddress()); - if (handle == kReservedHandle) { - LOG_WARN("No free handles"); + auto bd_addr = incoming.GetSourceAddress(); + auto response = model::packets::PageResponseView::Create(incoming); + ASSERT(response.IsValid()); + + if (!page_.has_value() || page_->bd_addr != bd_addr) { + INFO(id_, + "ignoring Page Response packet received when not in Page state," + " or paging to a different address"); return; } - CancelScheduledTask(page_timeout_task_id_); - ASSERT(link_manager_add_link( - lm_.get(), reinterpret_cast(peer.data()))); - CheckExpiringConnection(handle); + INFO(id_, "Received Page Response packet from {}", bd_addr); - auto addr = incoming.GetSourceAddress(); - auto response = model::packets::PageResponseView::Create(incoming); - ASSERT(response.IsValid()); - /* Role change event before connection complete is a quirk commonly exists in - * Android-capatable Bluetooth controllers. - * On the initiator side, only connection in peripheral role should be - * accompanied with a role change event */ - // TODO(b/274476773): Add a config option for this quirk - if (connections_.IsRoleSwitchAllowedForPendingConnection() && - response.GetTryRoleSwitch()) { - auto role = bluetooth::hci::Role::PERIPHERAL; - connections_.SetAclRole(handle, role); - if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { - send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, - addr, role)); - } + uint16_t connection_handle = + connections_.CreateConnection(bd_addr, GetAddress(), false); + ASSERT(connection_handle != kReservedHandle); + + bluetooth::hci::Role role = + page_->allow_role_switch && response.GetTryRoleSwitch() + ? bluetooth::hci::Role::PERIPHERAL + : bluetooth::hci::Role::CENTRAL; + + AclConnection& connection = connections_.GetAclConnection(connection_handle); + CheckExpiringConnection(connection_handle); + connection.SetLinkPolicySettings(default_link_policy_settings_); + connection.SetRole(role); + page_ = {}; + + ASSERT(link_manager_add_link( + lm_.get(), reinterpret_cast(bd_addr.data()))); + + // Role change event before connection complete generates an HCI Role Change + // event on the initiator side if accepted; the event is sent before the + // HCI Connection Complete event. + if (role == bluetooth::hci::Role::PERIPHERAL && + IsEventUnmasked(EventCode::ROLE_CHANGE)) { + send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, + bd_addr, role)); } + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode::SUCCESS, handle, addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); + ErrorCode::SUCCESS, connection_handle, bd_addr, + bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED)); } } void LinkLayerController::Tick() { RunPendingTasks(); + Paging(); + if (inquiry_timer_task_id_ != kInvalidTaskId) { Inquiry(); } @@ -5202,8 +5164,8 @@ void LinkLayerController::Tick() { void LinkLayerController::Close() { for (auto handle : connections_.GetAclHandles()) { - Disconnect(handle, ErrorCode::CONNECTION_TIMEOUT, - ErrorCode::CONNECTION_TIMEOUT); + Disconnect(handle, ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF, + ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF); } } @@ -5239,10 +5201,15 @@ void LinkLayerController::RegisterRemoteChannel( } void LinkLayerController::ForwardToLm(bluetooth::hci::CommandView command) { - auto packet = std::vector(command.begin(), command.end()); + auto packet = command.bytes().bytes(); ASSERT(link_manager_ingest_hci(lm_.get(), packet.data(), packet.size())); } +void LinkLayerController::ForwardToLl(bluetooth::hci::CommandView command) { + auto packet = command.bytes().bytes(); + ASSERT(link_layer_ingest_hci(ll_.get(), packet.data(), packet.size())); +} + std::vector const& LinkLayerController::ReadCurrentIacLap() const { return current_iac_lap_list_; @@ -5262,10 +5229,9 @@ void LinkLayerController::WriteCurrentIacLap( ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr, bool try_role_switch) { if (connections_.HasPendingConnection(bd_addr)) { - LOG_INFO("Accepting connection request from %s", - bd_addr.ToString().c_str()); + INFO(id_, "Accepting connection request from {}", bd_addr); ScheduleTask(kNoDelayMs, [this, bd_addr, try_role_switch]() { - LOG_INFO("Accepted connection from %s", bd_addr.ToString().c_str()); + INFO(id_, "Accepted connection from {}", bd_addr); MakePeripheralConnection(bd_addr, try_role_switch); }); @@ -5301,62 +5267,80 @@ ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr, link_parameters.extended)); // Schedule HCI Connection Complete event. - ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr]() { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode(status), sco_handle, bd_addr, bluetooth::hci::LinkType::SCO, - bluetooth::hci::Enable::DISABLED)); - }); + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { + ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr]() { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode(status), sco_handle, bd_addr, + bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED)); + }); + } return ErrorCode::SUCCESS; } - LOG_INFO("No pending connection for %s", bd_addr.ToString().c_str()); + INFO(id_, "No pending connection for {}", bd_addr); return ErrorCode::UNKNOWN_CONNECTION; } -void LinkLayerController::MakePeripheralConnection(const Address& addr, +void LinkLayerController::MakePeripheralConnection(const Address& bd_addr, bool try_role_switch) { - LOG_INFO("Sending page response to %s", addr.ToString().c_str()); - SendLinkLayerPacket(model::packets::PageResponseBuilder::Create( - GetAddress(), addr, try_role_switch)); - - uint16_t handle = connections_.CreateConnection(addr, GetAddress()); - if (handle == kReservedHandle) { - LOG_INFO("CreateConnection failed"); + uint16_t connection_handle = + connections_.CreateConnection(bd_addr, GetAddress()); + if (connection_handle == kReservedHandle) { + INFO(id_, "CreateConnection failed"); return; } - ASSERT(link_manager_add_link( - lm_.get(), reinterpret_cast(addr.data()))); - - CheckExpiringConnection(handle); - /* Role change event before connection complete is a quirk commonly exists in - * Android-capatable Bluetooth controllers. - * On the responder side, any connection should be accompanied with a role - * change event */ - // TODO(b/274476773): Add a config option for this quirk - auto role = + bluetooth::hci::Role role = try_role_switch && connections_.IsRoleSwitchAllowedForPendingConnection() ? bluetooth::hci::Role::CENTRAL : bluetooth::hci::Role::PERIPHERAL; - connections_.SetAclRole(handle, role); - if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { + + AclConnection& connection = connections_.GetAclConnection(connection_handle); + CheckExpiringConnection(connection_handle); + connection.SetLinkPolicySettings(default_link_policy_settings_); + connection.SetRole(role); + + ASSERT(link_manager_add_link( + lm_.get(), reinterpret_cast(bd_addr.data()))); + + // Role change event before connection complete generates an HCI Role Change + // event on the acceptor side if accepted; the event is sent before the + // HCI Connection Complete event. + if (role == bluetooth::hci::Role::CENTRAL && + IsEventUnmasked(EventCode::ROLE_CHANGE)) { + INFO(id_, "Role at connection setup accepted"); send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, - addr, role)); + bd_addr, role)); } - LOG_INFO("CreateConnection returned handle 0x%x", handle); if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode::SUCCESS, handle, addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); + ErrorCode::SUCCESS, connection_handle, bd_addr, + bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED)); } + + // If the current Host was initiating a connection to the same bd_addr, + // send a connection complete event for the pending Create Connection + // command and cancel the paging. + if (page_.has_value() && page_->bd_addr == bd_addr) { + // TODO: the core specification is very unclear as to what behavior + // is expected when two connections are established simultaneously. + // This implementation considers that a unique HCI Connection Complete + // event is expected for both the HCI Create Connection and HCI Accept + // Connection Request commands. + page_ = {}; + } + + INFO(id_, "Sending page response to {}", bd_addr.ToString()); + SendLinkLayerPacket(model::packets::PageResponseBuilder::Create( + GetAddress(), bd_addr, try_role_switch)); } ErrorCode LinkLayerController::RejectConnectionRequest(const Address& addr, uint8_t reason) { if (!connections_.HasPendingConnection(addr)) { - LOG_INFO("No pending connection for %s", addr.ToString().c_str()); + INFO(id_, "No pending connection for {}", addr); return ErrorCode::UNKNOWN_CONNECTION; } @@ -5369,8 +5353,7 @@ ErrorCode LinkLayerController::RejectConnectionRequest(const Address& addr, void LinkLayerController::RejectPeripheralConnection(const Address& addr, uint8_t reason) { - LOG_INFO("Sending page reject to %s (reason 0x%02hhx)", - addr.ToString().c_str(), reason); + INFO(id_, "Sending page reject to {} (reason 0x{:02x})", addr, reason); SendLinkLayerPacket( model::packets::PageRejectBuilder::Create(GetAddress(), addr, reason)); @@ -5381,36 +5364,61 @@ void LinkLayerController::RejectPeripheralConnection(const Address& addr, } } -ErrorCode LinkLayerController::CreateConnection(const Address& addr, +ErrorCode LinkLayerController::CreateConnection(const Address& bd_addr, uint16_t /* packet_type */, uint8_t /* page_scan_mode */, uint16_t /* clock_offset */, uint8_t allow_role_switch) { - if (!connections_.CreatePendingConnection( - addr, authentication_enable_ == AuthenticationEnable::REQUIRED, - allow_role_switch)) { - return ErrorCode::CONTROLLER_BUSY; + // RootCanal only accepts one pending outgoing connection at any time. + if (page_.has_value()) { + INFO(id_, "Create Connection command is already pending"); + return ErrorCode::COMMAND_DISALLOWED; } - page_timeout_task_id_ = ScheduleTask( - duration_cast(page_timeout_ * microseconds(625)), - [this, addr] { - send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( - ErrorCode::PAGE_TIMEOUT, 0xeff, addr, bluetooth::hci::LinkType::ACL, - bluetooth::hci::Enable::DISABLED)); - }); + // Reject the command if a connection or pending connection already exists + // for the selected peer address. + if (connections_.HasPendingConnection(bd_addr) || + connections_.GetAclConnectionHandle(bd_addr).has_value()) { + INFO(id_, "Connection with {} already exists", bd_addr.ToString()); + return ErrorCode::CONNECTION_ALREADY_EXISTS; + } - SendLinkLayerPacket(model::packets::PageBuilder::Create( - GetAddress(), addr, class_of_device_, allow_role_switch)); + auto now = std::chrono::steady_clock::now(); + page_ = Page{ + .bd_addr = bd_addr, + .allow_role_switch = allow_role_switch, + .next_page_event = now + kPageInterval, + .page_timeout = now + slots(page_timeout_), + }; return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::CreateConnectionCancel(const Address& addr) { - if (!connections_.CancelPendingConnection(addr)) { +ErrorCode LinkLayerController::CreateConnectionCancel(const Address& bd_addr) { + // If the HCI_Create_Connection_Cancel command is sent to the Controller + // without a preceding HCI_Create_Connection command to the same device, + // the BR/EDR Controller shall return an HCI_Command_Complete event with + // the error code Unknown Connection Identifier (0x02) + if (!page_.has_value() || page_->bd_addr != bd_addr) { + INFO(id_, "no pending connection to {}", bd_addr.ToString()); return ErrorCode::UNKNOWN_CONNECTION; } - CancelScheduledTask(page_timeout_task_id_); + + // The HCI_Connection_Complete event for the corresponding HCI_Create_- + // Connection command shall always be sent. The HCI_Connection_Complete + // event shall be sent after the HCI_Command_Complete event for the + // HCI_Create_Connection_Cancel command. If the cancellation was successful, + // the HCI_Connection_Complete event will be generated with the error code + // Unknown Connection Identifier (0x02). + if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) { + ScheduleTask(kNoDelayMs, [this, bd_addr]() { + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, 0, bd_addr, + bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED)); + }); + } + + page_ = {}; return ErrorCode::SUCCESS; } @@ -5429,8 +5437,7 @@ ErrorCode LinkLayerController::Disconnect(uint16_t handle, ErrorCode controller_reason) { if (connections_.HasScoHandle(handle)) { const Address remote = connections_.GetScoAddress(handle); - LOG_INFO("Disconnecting eSCO connection with %s", - remote.ToString().c_str()); + INFO(id_, "Disconnecting eSCO connection with {}", remote); SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create( GetAddress(), remote, static_cast(host_reason))); @@ -5449,7 +5456,7 @@ ErrorCode LinkLayerController::Disconnect(uint16_t handle, auto is_br_edr = connections_.GetPhyType(handle) == Phy::Type::BR_EDR; if (is_br_edr) { - LOG_INFO("Disconnecting ACL connection with %s", remote.ToString().c_str()); + INFO(id_, "Disconnecting ACL connection with {}", remote); uint16_t sco_handle = connections_.GetScoHandle(remote.GetAddress()); if (sco_handle != kReservedHandle) { @@ -5465,7 +5472,7 @@ ErrorCode LinkLayerController::Disconnect(uint16_t handle, SendLinkLayerPacket(model::packets::DisconnectBuilder::Create( GetAddress(), remote.GetAddress(), static_cast(host_reason))); } else { - LOG_INFO("Disconnecting LE connection with %s", remote.ToString().c_str()); + INFO(id_, "Disconnecting LE connection with {}", remote); SendLeLinkLayerPacket(model::packets::DisconnectBuilder::Create( connections_.GetOwnAddress(handle).GetAddress(), remote.GetAddress(), @@ -5479,6 +5486,8 @@ ErrorCode LinkLayerController::Disconnect(uint16_t handle, ASSERT(link_manager_remove_link( lm_.get(), reinterpret_cast(remote.GetAddress().data()))); + } else { + ASSERT(link_layer_remove_link(ll_.get(), handle)); } return ErrorCode::SUCCESS; } @@ -5579,67 +5588,124 @@ ErrorCode LinkLayerController::RoleDiscovery(uint16_t handle, if (!connections_.HasHandle(handle)) { return ErrorCode::UNKNOWN_CONNECTION; } + *role = connections_.GetAclRole(handle); return ErrorCode::SUCCESS; } -ErrorCode LinkLayerController::SwitchRole(Address addr, +ErrorCode LinkLayerController::SwitchRole(Address bd_addr, bluetooth::hci::Role role) { - auto handle = connections_.GetHandleOnlyAddress(addr); - if (handle == rootcanal::kReservedHandle) { + // The BD_ADDR command parameter indicates for which connection + // the role switch is to be performed and shall specify a BR/EDR Controller + // for which a connection already exists. + uint16_t connection_handle = connections_.GetHandleOnlyAddress(bd_addr); + if (connection_handle == kReservedHandle) { + INFO(id_, "unknown connection address {}", bd_addr); return ErrorCode::UNKNOWN_CONNECTION; } - // TODO(b/274248798): Reject role switch if disabled in link policy - SendLinkLayerPacket(model::packets::RoleSwitchRequestBuilder::Create( - GetAddress(), addr, static_cast(role))); + + AclConnection& connection = connections_.GetAclConnection(connection_handle); + + // If there is an (e)SCO connection between the local device and the device + // identified by the BD_ADDR parameter, an attempt to perform a role switch + // shall be rejected by the local device. + if (connections_.GetScoHandle(bd_addr) != kReservedHandle) { + INFO(id_, + "role switch rejected because an Sco link is opened with" + " the target device"); + return ErrorCode::COMMAND_DISALLOWED; + } + + // If the connection between the local device and the device identified by the + // BD_ADDR parameter is placed in Sniff mode, an attempt to perform a role + // switch shall be rejected by the local device. + if (connection.GetMode() == AclConnectionState::kSniffMode) { + INFO(id_, + "role switch rejected because the acl connection is in sniff mode"); + return ErrorCode::COMMAND_DISALLOWED; + } + + if (role != connection.GetRole()) { + SendLinkLayerPacket(model::packets::RoleSwitchRequestBuilder::Create( + GetAddress(), bd_addr)); + } else if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { + // Note: the status is Success only if the role change procedure was + // actually performed, otherwise the status is >0. + ScheduleTask(kNoDelayMs, [this, bd_addr, role]() { + send_event_(bluetooth::hci::RoleChangeBuilder::Create( + ErrorCode::ROLE_SWITCH_FAILED, bd_addr, role)); + }); + } + return ErrorCode::SUCCESS; } void LinkLayerController::IncomingRoleSwitchRequest( model::packets::LinkLayerPacketView incoming) { - auto addr = incoming.GetSourceAddress(); - auto handle = connections_.GetHandleOnlyAddress(addr); - auto request = model::packets::RoleSwitchRequestView::Create(incoming); - ASSERT(request.IsValid()); + auto bd_addr = incoming.GetSourceAddress(); + auto connection_handle = connections_.GetHandleOnlyAddress(bd_addr); + auto switch_req = model::packets::RoleSwitchRequestView::Create(incoming); + ASSERT(switch_req.IsValid()); - // TODO(b/274248798): Reject role switch if disabled in link policy - Role remote_role = static_cast(request.GetInitiatorNewRole()); - Role local_role = - remote_role == Role::CENTRAL ? Role::PERIPHERAL : Role::CENTRAL; - connections_.SetAclRole(handle, local_role); - if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { - ScheduleTask(kNoDelayMs, [this, addr, local_role]() { - send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS, - addr, local_role)); - }); + if (connection_handle == kReservedHandle) { + INFO(id_, "ignoring Switch Request received on unknown connection"); + return; } - ScheduleTask(kNoDelayMs, [this, addr, remote_role]() { + + AclConnection& connection = connections_.GetAclConnection(connection_handle); + + if (!connection.IsRoleSwitchEnabled()) { + INFO(id_, "role switch disabled by local link policy settings"); SendLinkLayerPacket(model::packets::RoleSwitchResponseBuilder::Create( - GetAddress(), addr, static_cast(ErrorCode::SUCCESS), - static_cast(remote_role))); - }); + GetAddress(), bd_addr, + static_cast(ErrorCode::ROLE_CHANGE_NOT_ALLOWED))); + } else { + INFO(id_, "role switch request accepted by local device"); + SendLinkLayerPacket(model::packets::RoleSwitchResponseBuilder::Create( + GetAddress(), bd_addr, static_cast(ErrorCode::SUCCESS))); + + bluetooth::hci::Role new_role = + connection.GetRole() == bluetooth::hci::Role::CENTRAL + ? bluetooth::hci::Role::PERIPHERAL + : bluetooth::hci::Role::CENTRAL; + + connection.SetRole(new_role); + + if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { + ScheduleTask(kNoDelayMs, [this, bd_addr, new_role]() { + send_event_(bluetooth::hci::RoleChangeBuilder::Create( + ErrorCode::SUCCESS, bd_addr, new_role)); + }); + } + } } void LinkLayerController::IncomingRoleSwitchResponse( model::packets::LinkLayerPacketView incoming) { - auto addr = incoming.GetSourceAddress(); - auto handle = connections_.GetHandleOnlyAddress(addr); - auto response = model::packets::RoleSwitchResponseView::Create(incoming); - ASSERT(response.IsValid()); + auto bd_addr = incoming.GetSourceAddress(); + auto connection_handle = connections_.GetHandleOnlyAddress(bd_addr); + auto switch_rsp = model::packets::RoleSwitchResponseView::Create(incoming); + ASSERT(switch_rsp.IsValid()); - // TODO(b/274248798): Reject role switch if disabled in link policy - ErrorCode status = ErrorCode::SUCCESS; - Role role = static_cast(response.GetInitiatorNewRole()); - if (response.GetStatus() == static_cast(ErrorCode::SUCCESS)) { - connections_.SetAclRole(handle, role); - } else { - status = static_cast(response.GetStatus()); + if (connection_handle == kReservedHandle) { + INFO(id_, "ignoring Switch Response received on unknown connection"); + return; } + AclConnection& connection = connections_.GetAclConnection(connection_handle); + ErrorCode status = ErrorCode(switch_rsp.GetStatus()); + bluetooth::hci::Role new_role = + status != ErrorCode::SUCCESS ? connection.GetRole() + : connection.GetRole() == bluetooth::hci::Role::CENTRAL + ? bluetooth::hci::Role::PERIPHERAL + : bluetooth::hci::Role::CENTRAL; + + connection.SetRole(new_role); + if (IsEventUnmasked(EventCode::ROLE_CHANGE)) { - ScheduleTask(kNoDelayMs, [this, status, addr, role]() { + ScheduleTask(kNoDelayMs, [this, status, bd_addr, new_role]() { send_event_( - bluetooth::hci::RoleChangeBuilder::Create(status, addr, role)); + bluetooth::hci::RoleChangeBuilder::Create(status, bd_addr, new_role)); }); } } @@ -5649,6 +5715,7 @@ ErrorCode LinkLayerController::ReadLinkPolicySettings(uint16_t handle, if (!connections_.HasHandle(handle)) { return ErrorCode::UNKNOWN_CONNECTION; } + *settings = connections_.GetAclLinkPolicySettings(handle); return ErrorCode::SUCCESS; } @@ -5670,6 +5737,7 @@ ErrorCode LinkLayerController::WriteDefaultLinkPolicySettings( if (settings > 7 /* Sniff + Hold + Role switch */) { return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; } + default_link_policy_settings_ = settings; return ErrorCode::SUCCESS; } @@ -5851,165 +5919,10 @@ bool LinkLayerController::HasAclConnection() { return !connections_.GetAclHandles().empty(); } -void LinkLayerController::LeReadIsoTxSync(uint16_t /* handle */) {} - -void LinkLayerController::LeSetCigParameters( - uint8_t cig_id, uint32_t sdu_interval_m_to_s, uint32_t sdu_interval_s_to_m, - bluetooth::hci::ClockAccuracy clock_accuracy, - bluetooth::hci::Packing packing, bluetooth::hci::Enable framing, - uint16_t max_transport_latency_m_to_s, - uint16_t max_transport_latency_s_to_m, - std::vector cis_config) { - if (IsEventUnmasked(EventCode::LE_META_EVENT)) { - send_event_(connections_.SetCigParameters( - cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, clock_accuracy, - packing, framing, max_transport_latency_m_to_s, - max_transport_latency_s_to_m, cis_config)); - } -} - -ErrorCode LinkLayerController::LeCreateCis( - std::vector cis_config) { - if (connections_.HasPendingCis()) { - return ErrorCode::COMMAND_DISALLOWED; - } - for (auto& config : cis_config) { - if (!connections_.HasHandle(config.acl_connection_handle_)) { - LOG_INFO("Unknown ACL handle %04x", config.acl_connection_handle_); - return ErrorCode::UNKNOWN_CONNECTION; - } - if (!connections_.HasCisHandle(config.cis_connection_handle_)) { - LOG_INFO("Unknown CIS handle %04x", config.cis_connection_handle_); - return ErrorCode::UNKNOWN_CONNECTION; - } - } - for (auto& config : cis_config) { - connections_.CreatePendingCis(config); - auto own_address = - connections_.GetOwnAddress(config.acl_connection_handle_); - auto peer_address = connections_.GetAddress(config.acl_connection_handle_); - StreamParameters stream_parameters = - connections_.GetStreamParameters(config.cis_connection_handle_); - GroupParameters group_parameters = - connections_.GetGroupParameters(stream_parameters.group_id); - - SendLeLinkLayerPacket(model::packets::IsoConnectionRequestBuilder::Create( - own_address.GetAddress(), peer_address.GetAddress(), - stream_parameters.group_id, group_parameters.sdu_interval_m_to_s, - group_parameters.sdu_interval_s_to_m, group_parameters.interleaved, - group_parameters.framed, group_parameters.max_transport_latency_m_to_s, - group_parameters.max_transport_latency_s_to_m, - stream_parameters.stream_id, stream_parameters.max_sdu_m_to_s, - stream_parameters.max_sdu_s_to_m, config.cis_connection_handle_, - config.acl_connection_handle_)); - } - return ErrorCode::SUCCESS; +bool LinkLayerController::HasAclConnection(uint16_t connection_handle) { + return connections_.HasHandle(connection_handle); } -ErrorCode LinkLayerController::LeRemoveCig(uint8_t cig_id) { - return connections_.RemoveCig(cig_id); -} - -ErrorCode LinkLayerController::LeAcceptCisRequest(uint16_t cis_handle) { - if (!connections_.HasPendingCisConnection(cis_handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - auto acl_handle = connections_.GetPendingAclHandle(cis_handle); - - connections_.ConnectCis(cis_handle); - - SendLeLinkLayerPacket(model::packets::IsoConnectionResponseBuilder::Create( - connections_.GetOwnAddress(acl_handle).GetAddress(), - connections_.GetAddress(acl_handle).GetAddress(), - static_cast(ErrorCode::SUCCESS), cis_handle, acl_handle, - connections_.GetRemoteCisHandleForCisHandle(cis_handle))); - - // Both sides have to send LeCisEstablished event - - uint32_t cig_sync_delay = 0x100; - uint32_t cis_sync_delay = 0x200; - uint32_t latency_m_to_s = 0x200; - uint32_t latency_s_to_m = 0x200; - uint8_t nse = 1; - uint8_t bn_m_to_s = 0; - uint8_t bn_s_to_m = 0; - uint8_t ft_m_to_s = 0; - uint8_t ft_s_to_m = 0; - uint8_t max_pdu_m_to_s = 0x40; - uint8_t max_pdu_s_to_m = 0x40; - uint16_t iso_interval = 0x100; - if (IsEventUnmasked(EventCode::LE_META_EVENT)) { - send_event_(bluetooth::hci::LeCisEstablishedBuilder::Create( - ErrorCode::SUCCESS, cis_handle, cig_sync_delay, cis_sync_delay, - latency_m_to_s, latency_s_to_m, - bluetooth::hci::SecondaryPhyType::NO_PACKETS, - bluetooth::hci::SecondaryPhyType::NO_PACKETS, nse, bn_m_to_s, bn_s_to_m, - ft_m_to_s, ft_s_to_m, max_pdu_m_to_s, max_pdu_s_to_m, iso_interval)); - } - return ErrorCode::SUCCESS; -} - -ErrorCode LinkLayerController::LeRejectCisRequest(uint16_t cis_handle, - ErrorCode reason) { - if (!connections_.HasPendingCisConnection(cis_handle)) { - return ErrorCode::UNKNOWN_CONNECTION; - } - auto acl_handle = connections_.GetPendingAclHandle(cis_handle); - - SendLeLinkLayerPacket(model::packets::IsoConnectionResponseBuilder::Create( - connections_.GetOwnAddress(acl_handle).GetAddress(), - connections_.GetAddress(acl_handle).GetAddress(), - static_cast(reason), cis_handle, acl_handle, kReservedHandle)); - connections_.RejectCis(cis_handle); - return ErrorCode::SUCCESS; -} - -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -ErrorCode LinkLayerController::LeCreateBig( - uint8_t /* big_handle */, uint8_t /* advertising_handle */, - uint8_t /* num_bis */, uint32_t /* sdu_interval */, uint16_t /* max_sdu */, - uint16_t /* max_transport_latency */, uint8_t /* rtn */, - bluetooth::hci::SecondaryPhyType /* phy */, - bluetooth::hci::Packing /* packing */, bluetooth::hci::Enable /* framing */, - bluetooth::hci::Enable /* encryption */, - std::array /* broadcast_code */) { - return ErrorCode::SUCCESS; -} - -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -ErrorCode LinkLayerController::LeTerminateBig(uint8_t /* big_handle */, - ErrorCode /* reason */) { - return ErrorCode::SUCCESS; -} - -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -ErrorCode LinkLayerController::LeBigCreateSync( - uint8_t /* big_handle */, uint16_t /* sync_handle */, - bluetooth::hci::Enable /* encryption */, - std::array /* broadcast_code */, uint8_t /* mse */, - uint16_t /* big_sync_timeout */, std::vector /* bis */) { - return ErrorCode::SUCCESS; -} - -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -void LinkLayerController::LeBigTerminateSync(uint8_t /* big_handle */) {} - -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -ErrorCode LinkLayerController::LeRequestPeerSca(uint16_t /* request_handle */) { - return ErrorCode::SUCCESS; -} - -void LinkLayerController::LeSetupIsoDataPath( - uint16_t /* connection_handle */, - bluetooth::hci::DataPathDirection /* data_path_direction */, - uint8_t /* data_path_id */, uint64_t /* codec_id */, - uint32_t /* controller_Delay */, - std::vector /* codec_configuration */) {} - -void LinkLayerController::LeRemoveIsoDataPath( - uint16_t /* connection_handle */, - bluetooth::hci::RemoveDataPathDirection /* remove_data_path_direction */) {} - void LinkLayerController::HandleLeEnableEncryption( uint16_t handle, std::array rand, uint16_t ediv, std::array ltk) { @@ -6027,7 +5940,7 @@ ErrorCode LinkLayerController::LeEnableEncryption( uint16_t handle, std::array rand, uint16_t ediv, std::array ltk) { if (!connections_.HasHandle(handle)) { - LOG_INFO("Unknown handle %04x", handle); + INFO(id_, "Unknown handle 0x{:04x}", handle); return ErrorCode::UNKNOWN_CONNECTION; } @@ -6040,7 +5953,7 @@ ErrorCode LinkLayerController::LeEnableEncryption( ErrorCode LinkLayerController::LeLongTermKeyRequestReply( uint16_t handle, std::array ltk) { if (!connections_.HasHandle(handle)) { - LOG_INFO("Unknown handle %04x", handle); + INFO(id_, "Unknown handle {:04x}", handle); return ErrorCode::UNKNOWN_CONNECTION; } @@ -6069,7 +5982,7 @@ ErrorCode LinkLayerController::LeLongTermKeyRequestReply( ErrorCode LinkLayerController::LeLongTermKeyRequestNegativeReply( uint16_t handle) { if (!connections_.HasHandle(handle)) { - LOG_INFO("Unknown handle %04x", handle); + INFO(id_, "Unknown handle {:04x}", handle); return ErrorCode::UNKNOWN_CONNECTION; } @@ -6104,7 +6017,7 @@ void LinkLayerController::Reset() { sco_flow_control_enable_ = false; local_name_.fill(0); extended_inquiry_response_.fill(0); - class_of_device_ = ClassOfDevice({0, 0, 0}); + class_of_device_ = 0; min_encryption_key_size_ = 16; event_mask_ = 0x00001fffffffffff; event_mask_page_2_ = 0x0; @@ -6140,17 +6053,43 @@ void LinkLayerController::Reset() { current_iac_lap_list_.clear(); current_iac_lap_list_.emplace_back(general_iac); + page_ = {}; + if (inquiry_timer_task_id_ != kInvalidTaskId) { CancelScheduledTask(inquiry_timer_task_id_); inquiry_timer_task_id_ = kInvalidTaskId; } - if (page_timeout_task_id_ != kInvalidTaskId) { - CancelScheduledTask(page_timeout_task_id_); - page_timeout_task_id_ = kInvalidTaskId; + lm_.reset(link_manager_create(controller_ops_)); + ll_.reset(link_layer_create(controller_ops_)); +} + +/// Drive the logic for the Page controller substate. +void LinkLayerController::Paging() { + auto now = std::chrono::steady_clock::now(); + + if (page_.has_value() && now >= page_->page_timeout) { + INFO("page timeout triggered for connection with {}", + page_->bd_addr.ToString()); + + send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( + ErrorCode::PAGE_TIMEOUT, 0, page_->bd_addr, + bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED)); + + page_ = {}; + return; } - lm_.reset(link_manager_create(ops_)); + // Send a Page packet to the peer when a paging interval has passed. + // Paging is suppressed while a pending connection with the same peer is + // being established (i.e. two hosts initiated a connection simultaneously). + if (page_.has_value() && now >= page_->next_page_event && + !connections_.HasPendingConnection(page_->bd_addr)) { + SendLinkLayerPacket(model::packets::PageBuilder::Create( + GetAddress(), page_->bd_addr, class_of_device_, + page_->allow_role_switch)); + page_->next_page_event = now + kPageInterval; + } } void LinkLayerController::StartInquiry(milliseconds timeout) { @@ -6220,7 +6159,7 @@ ErrorCode LinkLayerController::AddScoConnection(uint16_t connection_handle, return ErrorCode::COMMAND_DISALLOWED; } - LOG_INFO("Creating SCO connection with %s", bd_addr.ToString().c_str()); + INFO(id_, "Creating SCO connection with {}", bd_addr); // Save connection parameters. ScoConnectionParameters connection_parameters = { @@ -6269,7 +6208,7 @@ ErrorCode LinkLayerController::SetupSynchronousConnection( return ErrorCode::COMMAND_DISALLOWED; } - LOG_INFO("Creating eSCO connection with %s", bd_addr.ToString().c_str()); + INFO(id_, "Creating eSCO connection with {}", bd_addr); // Save connection parameters. ScoConnectionParameters connection_parameters = { @@ -6290,11 +6229,10 @@ ErrorCode LinkLayerController::AcceptSynchronousConnection( Address bd_addr, uint32_t transmit_bandwidth, uint32_t receive_bandwidth, uint16_t max_latency, uint16_t voice_setting, uint8_t retransmission_effort, uint16_t packet_types) { - LOG_INFO("Accepting eSCO connection request from %s", - bd_addr.ToString().c_str()); + INFO(id_, "Accepting eSCO connection request from {}", bd_addr); if (!connections_.HasPendingScoConnection(bd_addr)) { - LOG_INFO("No pending eSCO connection for %s", bd_addr.ToString().c_str()); + INFO(id_, "No pending eSCO connection for {}", bd_addr); return ErrorCode::COMMAND_DISALLOWED; } @@ -6343,8 +6281,7 @@ ErrorCode LinkLayerController::AcceptSynchronousConnection( ErrorCode LinkLayerController::RejectSynchronousConnection(Address bd_addr, uint16_t reason) { - LOG_INFO("Rejecting eSCO connection request from %s", - bd_addr.ToString().c_str()); + INFO(id_, "Rejecting eSCO connection request from {}", bd_addr); if (reason == (uint8_t)ErrorCode::SUCCESS) { reason = (uint8_t)ErrorCode::REMOTE_USER_TERMINATED_CONNECTION; @@ -6409,16 +6346,13 @@ TaskId LinkLayerController::StartScoStream(Address address) { connections_.GetScoHandle(address), PacketStatusFlag::CORRECTLY_RECEIVED, {0, 0, 0, 0, 0}); - auto bytes = std::make_shared>(); - bluetooth::packet::BitInserter bit_inserter(*bytes); - sco_builder->Serialize(bit_inserter); - auto raw_view = - bluetooth::hci::PacketView(bytes); - auto sco_view = bluetooth::hci::ScoView::Create(raw_view); + auto sco_bytes = sco_builder->SerializeToBytes(); + auto sco_view = bluetooth::hci::ScoView::Create(pdl::packet::slice( + std::make_shared>(std::move(sco_bytes)))); ASSERT(sco_view.IsValid()); return SchedulePeriodicTask(0ms, 20ms, [this, address, sco_view]() { - LOG_INFO("SCO sending..."); + INFO(id_, "SCO sending..."); SendScoToRemote(sco_view); }); } diff --git a/tools/rootcanal/model/controller/link_layer_controller.h b/tools/rootcanal/model/controller/link_layer_controller.h index f7300747ee72dc931c71881661c97c544dff5768..ce50d91f1f409d3e3c320375139d98518ef35d7e 100644 --- a/tools/rootcanal/model/controller/link_layer_controller.h +++ b/tools/rootcanal/model/controller/link_layer_controller.h @@ -16,36 +16,43 @@ #pragma once +#include + #include +#include #include -#include +#include +#include +#include +#include +#include #include +#include +#include #include #include "hci/address.h" -#include "hci/hci_packets.h" -#include "include/phy.h" +#include "hci/address_with_type.h" #include "model/controller/acl_connection_handler.h" #include "model/controller/controller_properties.h" #include "model/controller/le_advertiser.h" +#include "model/controller/sco_connection.h" +#include "model/controller/vendor_commands/le_apcf.h" +#include "packets/hci_packets.h" #include "packets/link_layer_packets.h" - -extern "C" { -struct LinkManager; -} - -#include "lmp.h" +#include "phy.h" +#include "rust/include/rootcanal_rs.h" namespace rootcanal { using ::bluetooth::hci::Address; using ::bluetooth::hci::AddressType; using ::bluetooth::hci::AuthenticationEnable; -using ::bluetooth::hci::ClassOfDevice; using ::bluetooth::hci::ErrorCode; using ::bluetooth::hci::FilterAcceptListAddressType; using ::bluetooth::hci::OpCode; using ::bluetooth::hci::PageScanRepetitionMode; +using rootcanal::apcf::ApcfScanner; // Create an address with type Public Device Address or Random Device Address. AddressWithType PeerDeviceAddress(Address address, @@ -62,26 +69,33 @@ class LinkLayerController { static constexpr size_t kLocalNameSize = 248; static constexpr size_t kExtendedInquiryResponseSize = 240; + // Unique instance identifier. + const uint32_t id_; + // Generate a resolvable private address using the specified IRK. static Address generate_rpa( std::array irk); + // Return true if the input IRK is all 0s. + static bool irk_is_zero(std::array irk); + LinkLayerController(const Address& address, - const ControllerProperties& properties); + const ControllerProperties& properties, uint32_t id = 0); ~LinkLayerController(); - ErrorCode SendCommandToRemoteByAddress( - OpCode opcode, bluetooth::packet::PacketView args, - const Address& own_address, const Address& peer_address); + ErrorCode SendCommandToRemoteByAddress(OpCode opcode, pdl::packet::slice args, + const Address& own_address, + const Address& peer_address); ErrorCode SendLeCommandToRemoteByAddress(OpCode opcode, const Address& own_address, const Address& peer_address); - ErrorCode SendCommandToRemoteByHandle( - OpCode opcode, bluetooth::packet::PacketView args, uint16_t handle); + ErrorCode SendCommandToRemoteByHandle(OpCode opcode, pdl::packet::slice args, + uint16_t handle); ErrorCode SendScoToRemote(bluetooth::hci::ScoView sco_packet); ErrorCode SendAclToRemote(bluetooth::hci::AclView acl_packet); void ForwardToLm(bluetooth::hci::CommandView command); + void ForwardToLl(bluetooth::hci::CommandView command); std::vector const& ReadCurrentIacLap() const; void WriteCurrentIacLap(std::vector iac_lap); @@ -90,12 +104,13 @@ class LinkLayerController { void MakePeripheralConnection(const Address& addr, bool try_role_switch); ErrorCode RejectConnectionRequest(const Address& addr, uint8_t reason); void RejectPeripheralConnection(const Address& addr, uint8_t reason); - ErrorCode CreateConnection(const Address& addr, uint16_t packet_type, + + // HCI command Create Connection (Vol 4, Part E § 7.1.5). + ErrorCode CreateConnection(const Address& bd_addr, uint16_t packet_type, uint8_t page_scan_mode, uint16_t clock_offset, uint8_t allow_role_switch); - ErrorCode CreateConnectionCancel(const Address& addr); - // Disconnect a link. + // HCI command Disconnect (Vol 4, Part E § 7.1.6). // \p host_reason is taken from the Disconnect command, and sent over // to the remote as disconnect error. \p controller_reason is the code // used in the DisconnectionComplete event. @@ -103,6 +118,9 @@ class LinkLayerController { ErrorCode controller_reason = ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST); + // HCI command Create Connection Cancel (Vol 4, Part E § 7.1.7). + ErrorCode CreateConnectionCancel(const Address& bd_addr); + // Internal task scheduler. // This scheduler is driven by the tick function only, // hence the precision of the scheduler is within a tick period. @@ -166,6 +184,7 @@ class LinkLayerController { void Reset(); + void Paging(); void LeAdvertising(); void LeScanning(); void LeSynchronization(); @@ -232,45 +251,6 @@ class LinkLayerController { } } - void LeReadIsoTxSync(uint16_t handle); - void LeSetCigParameters( - uint8_t cig_id, uint32_t sdu_interval_m_to_s, - uint32_t sdu_interval_s_to_m, - bluetooth::hci::ClockAccuracy clock_accuracy, - bluetooth::hci::Packing packing, bluetooth::hci::Enable framing, - uint16_t max_transport_latency_m_to_s, - uint16_t max_transport_latency_s_to_m, - std::vector cis_config); - bluetooth::hci::ErrorCode LeCreateCis( - std::vector cis_config); - bluetooth::hci::ErrorCode LeRemoveCig(uint8_t cig_id); - bluetooth::hci::ErrorCode LeAcceptCisRequest(uint16_t handle); - bluetooth::hci::ErrorCode LeRejectCisRequest( - uint16_t handle, bluetooth::hci::ErrorCode reason); - bluetooth::hci::ErrorCode LeCreateBig( - uint8_t big_handle, uint8_t advertising_handle, uint8_t num_bis, - uint32_t sdu_interval, uint16_t max_sdu, uint16_t max_transport_latency, - uint8_t rtn, bluetooth::hci::SecondaryPhyType phy, - bluetooth::hci::Packing packing, bluetooth::hci::Enable framing, - bluetooth::hci::Enable encryption, - std::array broadcast_code); - bluetooth::hci::ErrorCode LeTerminateBig(uint8_t big_handle, - bluetooth::hci::ErrorCode reason); - bluetooth::hci::ErrorCode LeBigCreateSync( - uint8_t big_handle, uint16_t sync_handle, - bluetooth::hci::Enable encryption, std::array broadcast_code, - uint8_t mse, uint16_t big_syunc_timeout, std::vector bis); - void LeBigTerminateSync(uint8_t big_handle); - bluetooth::hci::ErrorCode LeRequestPeerSca(uint16_t request_handle); - void LeSetupIsoDataPath(uint16_t connection_handle, - bluetooth::hci::DataPathDirection data_path_direction, - uint8_t data_path_id, uint64_t codec_id, - uint32_t controller_Delay, - std::vector codec_configuration); - void LeRemoveIsoDataPath( - uint16_t connection_handle, - bluetooth::hci::RemoveDataPathDirection remove_data_path_direction); - void HandleLeEnableEncryption(uint16_t handle, std::array rand, uint16_t ediv, std::array ltk); @@ -345,7 +325,10 @@ class LinkLayerController { uint8_t retransmission_effort, uint16_t packet_types); ErrorCode RejectSynchronousConnection(Address bd_addr, uint16_t reason); + // Returns true if any ACL connection exists. bool HasAclConnection(); + // Returns true if the specified ACL connection handle is valid. + bool HasAclConnection(uint16_t connection_handle); void HandleIso(bluetooth::hci::IsoView iso); @@ -513,7 +496,8 @@ class LinkLayerController { bluetooth::hci::OwnAddressType own_address_type, bluetooth::hci::LeScanningFilterPolicy scanning_filter_policy, uint8_t scanning_phys, - std::vector scanning_phy_parameters); + std::vector + scanning_phy_parameters); // HCI command LE_Set_Extended_Scan_Enable (Vol 4, Part E § 7.8.65). ErrorCode LeSetExtendedScanEnable( @@ -542,7 +526,7 @@ class LinkLayerController { bluetooth::hci::InitiatorFilterPolicy initiator_filter_policy, bluetooth::hci::OwnAddressType own_address_type, AddressWithType peer_address, uint8_t initiating_phys, - std::vector + std::vector initiating_phy_parameters); // Periodic Advertising @@ -597,6 +581,59 @@ class LinkLayerController { // HCI LE Clear Periodic Advertiser List command (Vol 4, Part E § 7.8.72). ErrorCode LeClearPeriodicAdvertiserList(); + // LE APCF + + ErrorCode LeApcfEnable(bool apcf_enable); + + ErrorCode LeApcfAddFilteringParameters( + uint8_t apcf_filter_index, uint16_t apcf_feature_selection, + uint16_t apcf_list_logic_type, uint8_t apcf_filter_logic_type, + uint8_t rssi_high_thresh, bluetooth::hci::DeliveryMode delivery_mode, + uint16_t onfound_timeout, uint8_t onfound_timeout_cnt, + uint8_t rssi_low_thresh, uint16_t onlost_timeout, + uint16_t num_of_tracking_entries, uint8_t* apcf_available_spaces); + + ErrorCode LeApcfDeleteFilteringParameters(uint8_t apcf_filter_index, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfClearFilteringParameters(uint8_t* apcf_available_spaces); + + ErrorCode LeApcfBroadcasterAddress( + bluetooth::hci::ApcfAction apcf_action, uint8_t apcf_filter_index, + bluetooth::hci::Address apcf_broadcaster_address, + bluetooth::hci::ApcfApplicationAddressType apcf_application_address_type, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfServiceUuid(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector acpf_uuid_data, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfServiceSolicitationUuid( + bluetooth::hci::ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector acpf_uuid_data, uint8_t* apcf_available_spaces); + + ErrorCode LeApcfLocalName(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector apcf_local_name, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfManufacturerData(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector apcf_manufacturer_data, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfServiceData(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, + std::vector apcf_service_data, + uint8_t* apcf_available_spaces); + + ErrorCode LeApcfAdTypeFilter(bluetooth::hci::ApcfAction apcf_action, + uint8_t apcf_filter_index, uint8_t ad_type, + std::vector apcf_ad_data, + std::vector apcf_ad_data_mask, + uint8_t* apcf_available_spaces); + protected: void SendLinkLayerPacket( std::unique_ptr packet, @@ -617,10 +654,8 @@ class LinkLayerController { void IncomingInquiryResponsePacket( model::packets::LinkLayerPacketView incoming); void IncomingLmpPacket(model::packets::LinkLayerPacketView incoming); - void IncomingIsoPacket(model::packets::LinkLayerPacketView incoming); - void IncomingIsoConnectionRequestPacket( - model::packets::LinkLayerPacketView incoming); - void IncomingIsoConnectionResponsePacket( + void IncomingLlcpPacket(model::packets::LinkLayerPacketView incoming); + void IncomingLeConnectedIsochronousPdu( model::packets::LinkLayerPacketView incoming); void ScanIncomingLeLegacyAdvertisingPdu( @@ -753,7 +788,7 @@ class LinkLayerController { } uint16_t GetVoiceSetting() const { return voice_setting_; } - const ClassOfDevice& GetClassOfDevice() const { return class_of_device_; } + uint32_t GetClassOfDevice() const { return class_of_device_; } uint8_t GetMaxLmpFeaturesPageNumber() { return properties_.lmp_features.size() - 1; @@ -766,17 +801,14 @@ class LinkLayerController { void SetLocalName(std::vector const& local_name); void SetLocalName(std::array const& local_name); + + void SetExtendedInquiryResponse( + std::array const& extended_inquiry_response); void SetExtendedInquiryResponse( std::vector const& extended_inquiry_response); - void SetClassOfDevice(ClassOfDevice class_of_device) { - class_of_device_ = class_of_device; - } - void SetClassOfDevice(uint32_t class_of_device) { - class_of_device_.cod[0] = class_of_device & UINT8_MAX; - class_of_device_.cod[1] = (class_of_device >> 8) & UINT8_MAX; - class_of_device_.cod[2] = (class_of_device >> 16) & UINT8_MAX; + class_of_device_ = class_of_device; } void SetAuthenticationEnable(AuthenticationEnable enable) { @@ -905,7 +937,7 @@ class LinkLayerController { extended_inquiry_response_{}; // Class of Device (Vol 4, Part E § 6.26). - ClassOfDevice class_of_device_{{0, 0, 0}}; + uint32_t class_of_device_{0}; // Other configuration parameters. @@ -1036,20 +1068,17 @@ class LinkLayerController { std::optional periodical_timeout; // Packet History - std::vector history; + std::vector history; bool IsEnabled() const { return scan_enable; } - bool IsPacketInHistory(model::packets::LinkLayerPacketView packet) const { + bool IsPacketInHistory(pdl::packet::slice const& packet) const { return std::any_of( history.begin(), history.end(), - [packet](model::packets::LinkLayerPacketView const& a) { - return a.size() == packet.size() && - std::equal(a.begin(), a.end(), packet.begin()); - }); + [packet](pdl::packet::slice const& a) { return a == packet; }); } - void AddPacketToHistory(model::packets::LinkLayerPacketView packet) { + void AddPacketToHistory(pdl::packet::slice packet) { history.push_back(packet); } }; @@ -1060,6 +1089,9 @@ class LinkLayerController { // Only one type of advertising may be used during a controller session. Scanner scanner_{}; + // APCF scanning state for Android vendor support. + ApcfScanner apcf_scanner_{}; + struct Initiator { bool connect_enable; bluetooth::hci::InitiatorFilterPolicy initiator_filter_policy; @@ -1119,11 +1151,26 @@ class LinkLayerController { std::optional synchronizing_{}; std::unordered_map synchronized_{}; - // Classic state + // Buffer to contain the ISO SDU sent from the host stack over HCI. + // The SDU is forwarded to the peer only when complete. + std::vector iso_sdu_{}; + + // Rust state. std::unique_ptr lm_; - struct LinkManagerOps ops_; + std::unique_ptr ll_; + struct ControllerOps controller_ops_; + + // Classic state. + struct Page { + Address bd_addr; + uint8_t allow_role_switch; + std::chrono::steady_clock::time_point next_page_event{}; + std::chrono::steady_clock::time_point page_timeout{}; + }; - TaskId page_timeout_task_id_ = kInvalidTaskId; + // Page substate. + // RootCanal will allow only one page request running at the same time. + std::optional page_; std::chrono::steady_clock::time_point last_inquiry_; model::packets::InquiryType inquiry_mode_{ diff --git a/tools/rootcanal/model/controller/sco_connection.cc b/tools/rootcanal/model/controller/sco_connection.cc index 45961a190ff8fdd2f704090eb83321f7bb7bf037..e0fb08702f5d3a366ad64dee7a1e7d37f51bc1a4 100644 --- a/tools/rootcanal/model/controller/sco_connection.cc +++ b/tools/rootcanal/model/controller/sco_connection.cc @@ -14,13 +14,17 @@ * limitations under the License. */ -#include "sco_connection.h" - -#include -#include +#include "model/controller/sco_connection.h" +#include +#include +#include +#include #include +#include "log.h" +#include "packets/hci_packets.h" + using namespace rootcanal; using namespace bluetooth::hci; @@ -86,7 +90,7 @@ std::optional ScoConnectionParameters::GetLinkParameters() } // Ignore empty bandwidths for now. if (transmit_bandwidth == 0 || receive_bandwidth == 0) { - LOG_WARN("eSCO transmissions with null bandwidths are not supported"); + WARNING("eSCO transmissions with null bandwidths are not supported"); return {}; } @@ -108,8 +112,8 @@ std::optional ScoConnectionParameters::GetLinkParameters() continue; } - LOG_INFO("Testing combination %u/%u : %u/%u", tx.length, tx.slots, - rx.length, rx.slots); + INFO("Testing combination {}/{} : {}/{}", tx.length, tx.slots, rx.length, + rx.slots); unsigned rx_max_interval = (1600 * rx.length) / receive_bandwidth; @@ -119,7 +123,7 @@ std::optional ScoConnectionParameters::GetLinkParameters() transmission_interval -= transmission_interval % 2; transmission_interval = std::min(transmission_interval, 254U); - LOG_INFO("Transmission interval: %u slots", transmission_interval); + INFO("Transmission interval: {} slots", transmission_interval); // Compute retransmission window. unsigned retransmission_window = @@ -134,7 +138,7 @@ std::optional ScoConnectionParameters::GetLinkParameters() ? 2 * (rx.slots + tx.slots) : 0; - LOG_INFO("Retransmission window: %u slots", retransmission_window); + INFO("Retransmission window: {} slots", retransmission_window); // Compute transmission window and validate latency. unsigned transmission_window = @@ -149,7 +153,7 @@ std::optional ScoConnectionParameters::GetLinkParameters() // Compute and validate latency. unsigned latency = (transmission_window * 1250) / 2; - LOG_INFO("Latency: %u us (max %u us)", latency, max_latency * 1000U); + INFO("Latency: {} us (max {} us)", latency, max_latency * 1000U); if (latency > (1000 * max_latency)) { // Oops @@ -162,7 +166,7 @@ std::optional ScoConnectionParameters::GetLinkParameters() (double)transmission_window / (double)transmission_interval; if (bandwidth_usage <= best_bandwidth_usage) { - LOG_INFO("Valid combination!"); + INFO("Valid combination!"); uint16_t tx_packet_length = (transmit_bandwidth * transmission_interval + 1600 - 1) / 1600; @@ -194,7 +198,7 @@ std::optional ScoConnectionParameters::GetLinkParameters() (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_POWER || retransmission_effort == (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_LINK_QUALITY) { - LOG_WARN("SCO Retransmission effort must be None or Don't care"); + WARNING("SCO Retransmission effort must be None or Don't care"); return {}; } @@ -212,7 +216,7 @@ std::optional ScoConnectionParameters::GetLinkParameters() transmission_interval = 2; packet_length = 10; } else { - LOG_WARN("No SCO packet type enabled"); + WARNING("No SCO packet type enabled"); return {}; } @@ -231,25 +235,23 @@ bool ScoConnection::NegotiateLinkParameters( ScoConnectionParameters const& peer) { if (peer.transmit_bandwidth != 0xffff && peer.transmit_bandwidth != parameters_.receive_bandwidth) { - LOG_WARN("Transmit bandwidth requirements cannot be met"); + WARNING("Transmit bandwidth requirements cannot be met"); return false; } if (state_ == SCO_STATE_SENT_ESCO_CONNECTION_REQUEST && peer.receive_bandwidth != 0xffff && peer.receive_bandwidth != parameters_.transmit_bandwidth) { - LOG_WARN("Receive bandwidth requirements cannot be met"); + WARNING("Receive bandwidth requirements cannot be met"); return false; } // mask out the air coding format bits before comparison, as per 5.3 Vol // 4E 6.12 if ((peer.voice_setting & ~0x3) != (parameters_.voice_setting & ~0x3)) { - LOG_WARN("Voice setting requirements cannot be met"); - LOG_WARN("Remote voice setting: 0x%04x", - static_cast(parameters_.voice_setting)); - LOG_WARN("Local voice setting: 0x%04x", - static_cast(peer.voice_setting)); + WARNING("Voice setting requirements cannot be met"); + WARNING("Remote voice setting: 0x{:04x}", parameters_.voice_setting); + WARNING("Local voice setting: 0x{:04x}", peer.voice_setting); return false; } @@ -257,11 +259,9 @@ bool ScoConnection::NegotiateLinkParameters( packet_type |= (peer.packet_type | parameters_.packet_type) & 0x3c0; if (packet_type == 0x3c0) { - LOG_WARN("Packet type requirements cannot be met"); - LOG_WARN("Remote packet type: 0x%04x", - static_cast(parameters_.packet_type)); - LOG_WARN("Local packet type: 0x%04x", - static_cast(peer.packet_type)); + WARNING("Packet type requirements cannot be met"); + WARNING("Remote packet type: 0x{:04x}", parameters_.packet_type); + WARNING("Local packet type: 0x{:04x}", peer.packet_type); return false; } @@ -285,11 +285,11 @@ bool ScoConnection::NegotiateLinkParameters( (uint8_t)RetransmissionEffort::NO_RETRANSMISSION || parameters_.retransmission_effort == (uint8_t)RetransmissionEffort::NO_RETRANSMISSION) { - LOG_WARN("Retransmission effort requirements cannot be met"); - LOG_WARN("Remote retransmission effort: 0x%02x", - static_cast(parameters_.retransmission_effort)); - LOG_WARN("Local retransmission effort: 0x%04x", - static_cast(peer.retransmission_effort)); + WARNING("Retransmission effort requirements cannot be met"); + WARNING("Remote retransmission effort: 0x{:02x}", + parameters_.retransmission_effort); + WARNING("Local retransmission effort: 0x{:02x}", + peer.retransmission_effort); return false; } else { retransmission_effort = (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_POWER; @@ -306,19 +306,16 @@ bool ScoConnection::NegotiateLinkParameters( auto link_parameters = negotiated_parameters.GetLinkParameters(); if (link_parameters.has_value()) { link_parameters_ = link_parameters.value(); - LOG_INFO("Negotiated link parameters for SCO connection:"); - LOG_INFO(" Transmission interval: %u slots", - static_cast(link_parameters_.transmission_interval)); - LOG_INFO(" Retransmission window: %u slots", - static_cast(link_parameters_.retransmission_window)); - LOG_INFO(" RX packet length: %u bytes", - static_cast(link_parameters_.rx_packet_length)); - LOG_INFO(" TX packet length: %u bytes", - static_cast(link_parameters_.tx_packet_length)); - LOG_INFO(" Air mode: %u", - static_cast(link_parameters_.air_mode)); + INFO("Negotiated link parameters for SCO connection:"); + INFO(" Transmission interval: {} slots", + link_parameters_.transmission_interval); + INFO(" Retransmission window: {} slots", + link_parameters_.retransmission_window); + INFO(" RX packet length: {} bytes", link_parameters_.rx_packet_length); + INFO(" TX packet length: {} bytes", link_parameters_.tx_packet_length); + INFO(" Air mode: {}", link_parameters_.air_mode); } else { - LOG_WARN("Failed to derive link parameters"); + WARNING("Failed to derive link parameters"); } return link_parameters.has_value(); } diff --git a/tools/rootcanal/model/controller/vendor_commands/le_apcf.cc b/tools/rootcanal/model/controller/vendor_commands/le_apcf.cc new file mode 100644 index 0000000000000000000000000000000000000000..a28fcd73d0cfdcc47a5740509785814ea5193ce7 --- /dev/null +++ b/tools/rootcanal/model/controller/vendor_commands/le_apcf.cc @@ -0,0 +1,395 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License") { + + } + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "log.h" +#include "model/controller/link_layer_controller.h" +#include "packets/hci_packets.h" + +#pragma GCC diagnostic ignored "-Wunused-parameter" + +namespace rootcanal::apcf { + +bool ApcfScanner::HasFilterIndex(uint8_t apcf_filter_index) const { + return std::any_of(std::begin(filters), std::end(filters), [&](auto it) { + return it.filter_index == apcf_filter_index; + }); +} + +void ApcfScanner::ClearFilterIndex(uint8_t apcf_filter_index) { + broadcaster_address_filters.erase( + std::remove_if( + std::begin(broadcaster_address_filters), + std::end(broadcaster_address_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(broadcaster_address_filters)); + service_uuid_filters.erase( + std::remove_if( + std::begin(service_uuid_filters), std::end(service_uuid_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(service_uuid_filters)); + service_solicitation_uuid_filters.erase( + std::remove_if( + std::begin(service_solicitation_uuid_filters), + std::end(service_solicitation_uuid_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(service_solicitation_uuid_filters)); + local_name_filters.erase( + std::remove_if( + std::begin(local_name_filters), std::end(local_name_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(local_name_filters)); + manufacturer_data_filters.erase( + std::remove_if( + std::begin(manufacturer_data_filters), + std::end(manufacturer_data_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(manufacturer_data_filters)); + service_data_filters.erase( + std::remove_if( + std::begin(service_data_filters), std::end(service_data_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(service_data_filters)); + ad_type_filters.erase( + std::remove_if( + std::begin(ad_type_filters), std::end(ad_type_filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(ad_type_filters)); +} + +void ApcfScanner::Clear() { + filters.clear(); + broadcaster_address_filters.clear(); + service_uuid_filters.clear(); + service_solicitation_uuid_filters.clear(); + local_name_filters.clear(); + manufacturer_data_filters.clear(); + service_data_filters.clear(); + ad_type_filters.clear(); +} + +template +ErrorCode ApcfScanner::UpdateFilterList(std::vector& filter_list, + size_t max_filter_list_size, + bluetooth::hci::ApcfAction action, + T filter) { + if (!HasFilterIndex(filter.filter_index)) { + return ErrorCode::UNKNOWN_CONNECTION; + } + + switch (action) { + case ApcfAction::ADD: { + if (filter_list.size() == max_filter_list_size) { + return ErrorCode::MEMORY_CAPACITY_EXCEEDED; + } + + filter_list.emplace_back(std::move(filter)); + return ErrorCode::SUCCESS; + } + case ApcfAction::DELETE: { + // Delete will delete the specified data in the specified filter. + filter_list.erase( + std::remove_if(std::begin(filter_list), std::end(filter_list), + [&](auto it) { return it == filter; }), + std::end(filter_list)); + return ErrorCode::SUCCESS; + } + case ApcfAction::CLEAR: { + // Clear will clear all data in the specified filter. + filter_list.erase( + std::remove_if( + std::begin(filter_list), std::end(filter_list), + [&](auto it) { return it.filter_index == filter.filter_index; }), + std::end(filter_list)); + return ErrorCode::SUCCESS; + } + default: + break; + } + + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; +} + +bool operator==(BroadcasterAddressFilter const& lhs, + BroadcasterAddressFilter const& rhs) { + return lhs.filter_index == rhs.filter_index && + lhs.broadcaster_address == rhs.broadcaster_address && + lhs.application_address_type == rhs.application_address_type; +} + +bool operator==(GapDataFilter const& lhs, GapDataFilter const& rhs) { + return lhs.filter_index == rhs.filter_index && lhs.gap_data == rhs.gap_data && + lhs.gap_data_mask == rhs.gap_data_mask; +} + +bool operator==(AdTypeFilter const& lhs, AdTypeFilter const& rhs) { + return lhs.filter_index == rhs.filter_index && lhs.ad_type == rhs.ad_type && + lhs.ad_data == rhs.ad_data && lhs.ad_data_mask == rhs.ad_data_mask; +} + +} // namespace rootcanal::apcf + +namespace rootcanal { + +using bluetooth::hci::ApcfAction; + +ErrorCode LinkLayerController::LeApcfEnable(bool apcf_enable) { + apcf_scanner_.enable = apcf_enable; + return ErrorCode::SUCCESS; +} + +ErrorCode LinkLayerController::LeApcfAddFilteringParameters( + uint8_t apcf_filter_index, uint16_t apcf_feature_selection, + uint16_t apcf_list_logic_type, uint8_t apcf_filter_logic_type, + uint8_t rssi_high_thresh, bluetooth::hci::DeliveryMode delivery_mode, + uint16_t onfound_timeout, uint8_t onfound_timeout_cnt, + uint8_t rssi_low_thresh, uint16_t onlost_timeout, + uint16_t num_of_tracking_entries, uint8_t* apcf_available_spaces) { + *apcf_available_spaces = + properties_.le_apcf_filter_list_size - apcf_scanner_.filters.size(); + + if (apcf_scanner_.HasFilterIndex(apcf_filter_index)) { + INFO(id_, "apcf filter index {} already configured", apcf_filter_index); + return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; + } + + if (*apcf_available_spaces == 0) { + INFO(id_, "reached max number of apcf filters"); + return ErrorCode::MEMORY_CAPACITY_EXCEEDED; + } + + apcf_scanner_.filters.push_back(rootcanal::apcf::Filter{ + .filter_index = apcf_filter_index, + .feature_selection = apcf_feature_selection, + .list_logic_type = apcf_list_logic_type, + .filter_logic_type = apcf_filter_logic_type, + .rssi_high_thresh = rssi_high_thresh, + .delivery_mode = delivery_mode, + .onfound_timeout = onfound_timeout, + .onfound_timeout_cnt = onfound_timeout_cnt, + .rssi_low_thresh = rssi_low_thresh, + .onlost_timeout = onlost_timeout, + .num_of_tracking_entries = num_of_tracking_entries, + }); + + *apcf_available_spaces -= 1; + return ErrorCode::SUCCESS; +} + +ErrorCode LinkLayerController::LeApcfDeleteFilteringParameters( + uint8_t apcf_filter_index, uint8_t* apcf_available_spaces) { + *apcf_available_spaces = + properties_.le_apcf_filter_list_size - apcf_scanner_.filters.size(); + + if (!apcf_scanner_.HasFilterIndex(apcf_filter_index)) { + INFO(id_, "apcf filter index {} is not configured", apcf_filter_index); + return ErrorCode::UNKNOWN_CONNECTION; + } + + apcf_scanner_.filters.erase( + std::remove_if( + std::begin(apcf_scanner_.filters), + std::end(apcf_scanner_.filters), + [&](auto it) { return it.filter_index == apcf_filter_index; }), + std::end(apcf_scanner_.filters)); + + apcf_scanner_.ClearFilterIndex(apcf_filter_index); + *apcf_available_spaces += 1; + return ErrorCode::SUCCESS; +} + +ErrorCode LinkLayerController::LeApcfClearFilteringParameters( + uint8_t* apcf_available_spaces) { + apcf_scanner_.Clear(); + *apcf_available_spaces = properties_.le_apcf_filter_list_size; + return ErrorCode::SUCCESS; +} + +ErrorCode LinkLayerController::LeApcfBroadcasterAddress( + ApcfAction apcf_action, uint8_t apcf_filter_index, + bluetooth::hci::Address apcf_broadcaster_address, + bluetooth::hci::ApcfApplicationAddressType apcf_application_address_type, + uint8_t* apcf_available_spaces) { + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.broadcaster_address_filters, + properties_.le_apcf_broadcaster_address_filter_list_size, apcf_action, + rootcanal::apcf::BroadcasterAddressFilter{ + .filter_index = apcf_filter_index, + .broadcaster_address = apcf_broadcaster_address, + .application_address_type = apcf_application_address_type, + }); + + *apcf_available_spaces = + properties_.le_apcf_broadcaster_address_filter_list_size - + apcf_scanner_.broadcaster_address_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::LeApcfServiceUuid( + ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_uuid_data, uint8_t* apcf_available_spaces) { + size_t uuid_data_size = apcf_uuid_data.size() / 2; + std::vector uuid_data(std::begin(apcf_uuid_data), + std::begin(apcf_uuid_data) + uuid_data_size); + std::vector uuid_data_mask( + std::begin(apcf_uuid_data) + uuid_data_size, std::end(apcf_uuid_data)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.service_uuid_filters, + properties_.le_apcf_service_uuid_filter_list_size, apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = uuid_data, + .gap_data_mask = uuid_data_mask, + }); + + *apcf_available_spaces = properties_.le_apcf_service_uuid_filter_list_size - + apcf_scanner_.service_uuid_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::LeApcfServiceSolicitationUuid( + ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_uuid_data, uint8_t* apcf_available_spaces) { + size_t uuid_data_size = apcf_uuid_data.size() / 2; + std::vector uuid_data(std::begin(apcf_uuid_data), + std::begin(apcf_uuid_data) + uuid_data_size); + std::vector uuid_data_mask( + std::begin(apcf_uuid_data) + uuid_data_size, std::end(apcf_uuid_data)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.service_solicitation_uuid_filters, + properties_.le_apcf_service_solicitation_uuid_filter_list_size, + apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = uuid_data, + .gap_data_mask = uuid_data_mask, + }); + + *apcf_available_spaces = + properties_.le_apcf_service_solicitation_uuid_filter_list_size - + apcf_scanner_.service_solicitation_uuid_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::LeApcfLocalName( + ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_local_name, uint8_t* apcf_available_spaces) { + size_t local_name_size = apcf_local_name.size() / 2; + std::vector local_name( + std::begin(apcf_local_name), + std::begin(apcf_local_name) + local_name_size); + std::vector local_name_mask( + std::begin(apcf_local_name) + local_name_size, std::end(apcf_local_name)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.local_name_filters, + properties_.le_apcf_local_name_filter_list_size, apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = local_name, + .gap_data_mask = local_name_mask, + }); + + *apcf_available_spaces = properties_.le_apcf_local_name_filter_list_size - + apcf_scanner_.local_name_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::LeApcfManufacturerData( + ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_manufacturer_data, + uint8_t* apcf_available_spaces) { + size_t manufacturer_data_size = apcf_manufacturer_data.size() / 2; + std::vector manufacturer_data( + std::begin(apcf_manufacturer_data), + std::begin(apcf_manufacturer_data) + manufacturer_data_size); + std::vector manufacturer_data_mask( + std::begin(apcf_manufacturer_data) + manufacturer_data_size, + std::end(apcf_manufacturer_data)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.manufacturer_data_filters, + properties_.le_apcf_manufacturer_data_filter_list_size, apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = manufacturer_data, + .gap_data_mask = manufacturer_data_mask, + }); + + *apcf_available_spaces = + properties_.le_apcf_manufacturer_data_filter_list_size - + apcf_scanner_.manufacturer_data_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::LeApcfServiceData( + ApcfAction apcf_action, uint8_t apcf_filter_index, + std::vector apcf_service_data, uint8_t* apcf_available_spaces) { + size_t service_data_size = apcf_service_data.size() / 2; + std::vector service_data( + std::begin(apcf_service_data), + std::begin(apcf_service_data) + service_data_size); + std::vector service_data_mask( + std::begin(apcf_service_data) + service_data_size, + std::end(apcf_service_data)); + + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.service_data_filters, + properties_.le_apcf_service_data_filter_list_size, apcf_action, + rootcanal::apcf::GapDataFilter{ + .filter_index = apcf_filter_index, + .gap_data = service_data, + .gap_data_mask = service_data_mask, + }); + + *apcf_available_spaces = properties_.le_apcf_service_data_filter_list_size - + apcf_scanner_.service_data_filters.size(); + + return status; +} + +ErrorCode LinkLayerController::LeApcfAdTypeFilter( + ApcfAction apcf_action, uint8_t apcf_filter_index, uint8_t apcf_ad_type, + std::vector apcf_ad_data, std::vector apcf_ad_data_mask, + uint8_t* apcf_available_spaces) { + ErrorCode status = apcf_scanner_.UpdateFilterList( + apcf_scanner_.ad_type_filters, + properties_.le_apcf_ad_type_filter_list_size, apcf_action, + rootcanal::apcf::AdTypeFilter{ + .filter_index = apcf_filter_index, + .ad_type = apcf_ad_type, + .ad_data = std::move(apcf_ad_data), + .ad_data_mask = std::move(apcf_ad_data_mask), + }); + + *apcf_available_spaces = properties_.le_apcf_ad_type_filter_list_size - + apcf_scanner_.ad_type_filters.size(); + + return status; +} + +} // namespace rootcanal diff --git a/tools/rootcanal/model/controller/vendor_commands/le_apcf.h b/tools/rootcanal/model/controller/vendor_commands/le_apcf.h new file mode 100644 index 0000000000000000000000000000000000000000..5c6cce40c03539ddea4632b4e180a92a69d99635 --- /dev/null +++ b/tools/rootcanal/model/controller/vendor_commands/le_apcf.h @@ -0,0 +1,94 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace rootcanal::apcf { + +/// Records the filtering parameters for the specified filter_index. +/// The associated advertising filters are added to their respective tables. +struct Filter { + uint8_t filter_index; + uint16_t feature_selection; + uint16_t list_logic_type; + uint8_t filter_logic_type; + uint8_t rssi_high_thresh; + bluetooth::hci::DeliveryMode delivery_mode; + uint16_t onfound_timeout; + uint8_t onfound_timeout_cnt; + uint8_t rssi_low_thresh; + uint16_t onlost_timeout; + uint16_t num_of_tracking_entries; +}; + +/// Filter for matching the advertiser address. +struct BroadcasterAddressFilter { + uint8_t filter_index; + bluetooth::hci::Address broadcaster_address; + bluetooth::hci::ApcfApplicationAddressType application_address_type; +}; + +/// Generic filter for GAP data information. +/// Used for matching Service UUID, Service Solicitation UUID, +/// Local Name, Manufacturer Data, Service Data. +struct GapDataFilter { + uint8_t filter_index; + std::vector gap_data; + std::vector gap_data_mask; +}; + +/// Filter for matching the AD type. +struct AdTypeFilter { + uint8_t filter_index; + uint8_t ad_type; + std::vector ad_data; + std::vector ad_data_mask; +}; + +/// State of the APCF scanner. +struct ApcfScanner { + bool enable{false}; + std::vector filters{}; + std::vector broadcaster_address_filters{}; + std::vector service_uuid_filters{}; + std::vector service_solicitation_uuid_filters{}; + std::vector local_name_filters{}; + std::vector manufacturer_data_filters{}; + std::vector service_data_filters{}; + std::vector ad_type_filters{}; + + // Return if the APCF filter index is defined in the + // list of filters. + bool HasFilterIndex(uint8_t apcf_filter_index) const; + + // Remove the entries associated with the APCF filter index + // from all tables. + void ClearFilterIndex(uint8_t apcf_filter_index); + + // Remove all entries in all tables. + void Clear(); + + // Apply the requested modification to the selected + // filter list. + template + ErrorCode UpdateFilterList(std::vector& filter_list, + size_t max_filter_list_size, + bluetooth::hci::ApcfAction action, T filter); +}; + +} // namespace rootcanal::apcf diff --git a/tools/rootcanal/model/devices/baseband_sniffer.cc b/tools/rootcanal/model/devices/baseband_sniffer.cc index 50b1b345d8f7b31417c2e06fbe160195dc58effe..fd3f01887b57e26a965526a1732efc90f0ee4b64 100644 --- a/tools/rootcanal/model/devices/baseband_sniffer.cc +++ b/tools/rootcanal/model/devices/baseband_sniffer.cc @@ -14,13 +14,19 @@ * limitations under the License. */ -#include "baseband_sniffer.h" +#include "model/devices/baseband_sniffer.h" + +#include +#include +#include +#include +#include +#include #include "log.h" -#include "packet/raw_builder.h" +#include "packets/link_layer_packets.h" #include "pcap.h" - -using std::vector; +#include "phy.h" namespace rootcanal { @@ -38,11 +44,7 @@ BaseBandSniffer::BaseBandSniffer(const std::string& filename) { void BaseBandSniffer::AppendRecord( std::unique_ptr packet) { - auto bytes = std::vector(); - bytes.reserve(packet->size()); - bluetooth::packet::BitInserter i(bytes); - packet->Serialize(i); - + std::vector bytes = packet->SerializeToBytes(); pcap::WriteRecordHeader(output_, bytes.size()); output_.write((char*)bytes.data(), bytes.size()); output_.flush(); @@ -143,7 +145,7 @@ void BaseBandSniffer::ReceiveLinkLayerPacket( 0, // eir 0, // sr 0, // sp - uap, nap, page_view.GetClassOfDevice().ToUint32(), + uap, nap, page_view.GetClassOfDevice(), 1, // lt_addr 0, // clk 0, // page_scan_mode @@ -152,9 +154,7 @@ void BaseBandSniffer::ReceiveLinkLayerPacket( } else if (packet_type == model::packets::PacketType::LMP) { auto lmp_view = model::packets::LmpView::Create(packet); ASSERT(lmp_view.IsValid()); - auto lmp_bytes = std::vector(lmp_view.GetPayload().begin(), - lmp_view.GetPayload().end()); - + auto lmp_bytes = lmp_view.GetPayload(); uint8_t bt_packet_type = 0b0011; // DM1 AppendRecord(bredr_bb::DM1AclPacketBuilder::Create( @@ -165,7 +165,7 @@ void BaseBandSniffer::ReceiveLinkLayerPacket( flags, 0x3, // llid 1, // flow - std::make_unique(lmp_bytes), + std::move(lmp_bytes), 0 // crc )); } diff --git a/tools/rootcanal/model/devices/baseband_sniffer.h b/tools/rootcanal/model/devices/baseband_sniffer.h index 496d15312ac2c8bed927145e285700fbcc485b0c..96c2b7e84e04bc0d129629dbad427b897dc80463 100644 --- a/tools/rootcanal/model/devices/baseband_sniffer.h +++ b/tools/rootcanal/model/devices/baseband_sniffer.h @@ -18,15 +18,18 @@ #include #include +#include +#include -#include "device.h" +#include "hci/address.h" +#include "model/devices/device.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { namespace bredr_bb { -namespace { class BaseBandPacketBuilder; -} } // namespace bredr_bb using ::bluetooth::hci::Address; diff --git a/tools/rootcanal/model/devices/beacon.cc b/tools/rootcanal/model/devices/beacon.cc index cb87104611bf18a41da9744ec423e93cf35a3a54..d61d44bbb7775b3efeb8153b1a63f76b8294506f 100644 --- a/tools/rootcanal/model/devices/beacon.cc +++ b/tools/rootcanal/model/devices/beacon.cc @@ -14,9 +14,18 @@ * limitations under the License. */ -#include "beacon.h" +#include "model/devices/beacon.h" +#include +#include +#include +#include +#include + +#include "hci/address.h" #include "model/setup/device_boutique.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { using namespace model::packets; diff --git a/tools/rootcanal/model/devices/beacon.h b/tools/rootcanal/model/devices/beacon.h index e83bdfdcd44f86fdb2ac79ba97b8b64ab915472e..6b33197dd7da9d338a065f3b463f3620e841e127 100644 --- a/tools/rootcanal/model/devices/beacon.h +++ b/tools/rootcanal/model/devices/beacon.h @@ -16,11 +16,16 @@ #pragma once +#include #include #include +#include +#include #include -#include "device.h" +#include "model/devices/device.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { diff --git a/tools/rootcanal/model/devices/beacon_swarm.cc b/tools/rootcanal/model/devices/beacon_swarm.cc index 45827dc8985a7f5bb59ead6885e550619b93657c..af4b7555c3b5a42f0de5c7ecfbf8e1fade532b83 100644 --- a/tools/rootcanal/model/devices/beacon_swarm.cc +++ b/tools/rootcanal/model/devices/beacon_swarm.cc @@ -14,11 +14,16 @@ * limitations under the License. */ -#include "beacon_swarm.h" +#include "model/devices/beacon_swarm.h" -#include "model/setup/device_boutique.h" +#include +#include +#include +#include -using std::vector; +#include "model/devices/beacon.h" +#include "model/setup/device_boutique.h" +#include "packets/link_layer_packets.h" namespace rootcanal { using namespace model::packets; @@ -27,7 +32,7 @@ using namespace std::chrono_literals; bool BeaconSwarm::registered_ = DeviceBoutique::Register("beacon_swarm", &BeaconSwarm::Create); -BeaconSwarm::BeaconSwarm(const vector& args) : Beacon(args) { +BeaconSwarm::BeaconSwarm(const std::vector& args) : Beacon(args) { advertising_interval_ = 1280ms; advertising_type_ = LegacyAdvertisingType::ADV_NONCONN_IND; advertising_data_ = { diff --git a/tools/rootcanal/model/devices/beacon_swarm.h b/tools/rootcanal/model/devices/beacon_swarm.h index d7bc6c1f3f550af9b11aebc8858d1e965280ad51..69f6dd44bcdafb2c3b47c37c8d93b1e85dc343aa 100644 --- a/tools/rootcanal/model/devices/beacon_swarm.h +++ b/tools/rootcanal/model/devices/beacon_swarm.h @@ -16,10 +16,12 @@ #pragma once -#include +#include +#include #include -#include "beacon.h" +#include "model/devices/beacon.h" +#include "model/devices/device.h" namespace rootcanal { diff --git a/tools/rootcanal/model/devices/device.cc b/tools/rootcanal/model/devices/device.cc index bfe86b056adcc0b64e7cd08202f4af685415f2a7..9fadf9e3df0e98ff82e49059f464d373c440a8ba 100644 --- a/tools/rootcanal/model/devices/device.cc +++ b/tools/rootcanal/model/devices/device.cc @@ -14,12 +14,29 @@ * limitations under the License. */ -#include "device.h" +#include "model/devices/device.h" +#include +#include +#include +#include #include +#include "log.h" +#include "packets/link_layer_packets.h" +#include "phy.h" + namespace rootcanal { +static uint32_t next_instance_id() { + static uint32_t instance_counter = 0; + return instance_counter++; +} + +Device::Device() : id_(next_instance_id()) { + ASSERT(Address::FromString("BB:BB:BB:BB:BB:AD", address_)); +} + std::string Device::ToString() const { return GetTypeString() + "@" + address_.ToString(); } diff --git a/tools/rootcanal/model/devices/device.h b/tools/rootcanal/model/devices/device.h index 56fd8941745627e62f466d0175afa3ac704b17c8..3d5f258a29550be3f097ff0dba7dc146375f6eba 100644 --- a/tools/rootcanal/model/devices/device.h +++ b/tools/rootcanal/model/devices/device.h @@ -16,9 +16,9 @@ #pragma once -#include #include -#include +#include +#include #include #include @@ -34,7 +34,10 @@ using ::bluetooth::hci::Address; // - Provide Get*() and Set*() functions for device attributes. class Device { public: - Device() { ASSERT(Address::FromString("BB:BB:BB:BB:BB:AD", address_)); } + // Unique device identifier. + const uint32_t id_; + + Device(); virtual ~Device() = default; // Return a string representation of the type of device. @@ -53,8 +56,8 @@ class Device { virtual void Close(); virtual void ReceiveLinkLayerPacket( - model::packets::LinkLayerPacketView packet, Phy::Type type, - int8_t rssi){}; + model::packets::LinkLayerPacketView /*packet*/, Phy::Type /*type*/, + int8_t /*rssi*/) {} void SendLinkLayerPacket( std::shared_ptr packet, diff --git a/tools/rootcanal/model/devices/hci_device.cc b/tools/rootcanal/model/devices/hci_device.cc index 97740821baa52877bcf5c6253f783b827968ff1a..9f0b30b5f31c9b5bed7bd55a6f14e94f00fcf3e8 100644 --- a/tools/rootcanal/model/devices/hci_device.cc +++ b/tools/rootcanal/model/devices/hci_device.cc @@ -14,9 +14,17 @@ * limitations under the License. */ -#include "hci_device.h" +#include "model/devices/hci_device.h" + +#include +#include +#include #include "log.h" +#include "model/controller/controller_properties.h" +#include "model/controller/dual_mode_controller.h" +#include "model/hci/hci_transport.h" +#include "packets/link_layer_packets.h" namespace rootcanal { @@ -54,33 +62,41 @@ HciDevice::HciDevice(std::shared_ptr transport, })); RegisterEventChannel([this](std::shared_ptr> packet) { - transport_->SendEvent(*packet); + transport_->Send(PacketType::EVENT, *packet); }); RegisterAclChannel([this](std::shared_ptr> packet) { - transport_->SendAcl(*packet); + transport_->Send(PacketType::ACL, *packet); }); RegisterScoChannel([this](std::shared_ptr> packet) { - transport_->SendSco(*packet); + transport_->Send(PacketType::SCO, *packet); }); RegisterIsoChannel([this](std::shared_ptr> packet) { - transport_->SendIso(*packet); + transport_->Send(PacketType::ISO, *packet); }); transport_->RegisterCallbacks( - [this](const std::shared_ptr> command) { - HandleCommand(command); - }, - [this](const std::shared_ptr> acl) { - HandleAcl(acl); - }, - [this](const std::shared_ptr> sco) { - HandleSco(sco); - }, - [this](const std::shared_ptr> iso) { - HandleIso(iso); + [this](PacketType packet_type, + const std::shared_ptr> packet) { + switch (packet_type) { + case PacketType::COMMAND: + HandleCommand(packet); + break; + case PacketType::ACL: + HandleAcl(packet); + break; + case PacketType::SCO: + HandleSco(packet); + break; + case PacketType::ISO: + HandleIso(packet); + break; + default: + ASSERT(false); + break; + } }, [this]() { - LOG_INFO("HCI transport closed"); + INFO(id_, "HCI transport closed"); Close(); }); } diff --git a/tools/rootcanal/model/devices/hci_device.h b/tools/rootcanal/model/devices/hci_device.h index 65dacd0d44c2e781795a4d815d9001a0f7e640bd..38be7fb7bb1e57157c1ca673299e1e29ac52c2bb 100644 --- a/tools/rootcanal/model/devices/hci_device.h +++ b/tools/rootcanal/model/devices/hci_device.h @@ -16,11 +16,12 @@ #pragma once -#include // for shared_ptr, make_... -#include // for string +#include +#include -#include "model/controller/dual_mode_controller.h" // for DualModeController -#include "model/hci/hci_transport.h" // for HciTransport +#include "model/controller/controller_properties.h" +#include "model/controller/dual_mode_controller.h" +#include "model/hci/hci_transport.h" namespace rootcanal { diff --git a/tools/rootcanal/model/devices/link_layer_socket_device.cc b/tools/rootcanal/model/devices/link_layer_socket_device.cc index 4f2074a3fa65cc47840ceb21caa69ab31be90283..e61badf070bba797a89810b55c2045532e7ad7fe 100644 --- a/tools/rootcanal/model/devices/link_layer_socket_device.cc +++ b/tools/rootcanal/model/devices/link_layer_socket_device.cc @@ -14,17 +14,21 @@ * limitations under the License. */ -#include "link_layer_socket_device.h" +#include "model/devices/link_layer_socket_device.h" -#include // for remove_extent_t +#include -#include "log.h" // for ASSERT, LOG_INFO, LOG_ERROR, LOG_WARN -#include "packet/bit_inserter.h" // for BitInserter -#include "packet/iterator.h" // for Iterator -#include "packet/packet_view.h" // for PacketView, kLittleEndian -#include "packet/raw_builder.h" // for RawBuilder -#include "packet/view.h" // for View -#include "phy.h" // for Phy, Phy::Type +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "model/devices/device.h" +#include "packets/link_layer_packets.h" +#include "phy.h" using std::vector; @@ -43,11 +47,10 @@ void LinkLayerSocketDevice::Tick() { if (bytes_received <= 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // Nothing available yet. - // LOG_DEBUG("Nothing available yet..."); + // DEBUG("Nothing available yet..."); return; } - LOG_INFO("Closing socket, received: %zd, %s", bytes_received, - strerror(errno)); + INFO("Closing socket, received: {}, {}", bytes_received, strerror(errno)); Close(); return; } @@ -56,9 +59,8 @@ void LinkLayerSocketDevice::Tick() { offset_ += bytes_received; return; } - bluetooth::packet::PacketView size( - {bluetooth::packet::View(size_bytes_, 0, kSizeBytes)}); - bytes_left_ = size.begin().extract(); + pdl::packet::slice size(std::move(size_bytes_)); + bytes_left_ = size.read_le(); received_ = std::make_shared>(bytes_left_); offset_ = 0; receiving_size_ = false; @@ -68,11 +70,10 @@ void LinkLayerSocketDevice::Tick() { if (bytes_received <= 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // Nothing available yet. - // LOG_DEBUG("Nothing available yet..."); + // DEBUG("Nothing available yet..."); return; } - LOG_INFO("Closing socket, received: %zd, %s", bytes_received, - strerror(errno)); + INFO("Closing socket, received: {}, {}", bytes_received, strerror(errno)); Close(); return; } @@ -97,15 +98,12 @@ void LinkLayerSocketDevice::Close() { void LinkLayerSocketDevice::ReceiveLinkLayerPacket( model::packets::LinkLayerPacketView packet, Phy::Type /*type*/, int8_t /*rssi*/) { - auto size_packet = bluetooth::packet::RawBuilder(); - size_packet.AddOctets4(packet.size()); + std::vector packet_bytes = packet.bytes().bytes(); std::vector size_bytes; - bluetooth::packet::BitInserter bit_inserter(size_bytes); - size_packet.Serialize(bit_inserter); + pdl::packet::Builder::write_le(size_bytes, packet_bytes.size()); if (socket_->Send(size_bytes.data(), size_bytes.size()) == kSizeBytes) { - std::vector payload_bytes{packet.begin(), packet.end()}; - socket_->Send(payload_bytes.data(), payload_bytes.size()); + socket_->Send(packet_bytes.data(), packet_bytes.size()); } } diff --git a/tools/rootcanal/model/devices/link_layer_socket_device.h b/tools/rootcanal/model/devices/link_layer_socket_device.h index b0adb157f89c1ac91a0f5f07670370fc9726a248..b91263a479cd209a39f6c8f9b70443ba55736ab1 100644 --- a/tools/rootcanal/model/devices/link_layer_socket_device.h +++ b/tools/rootcanal/model/devices/link_layer_socket_device.h @@ -16,17 +16,16 @@ #pragma once -#include // for size_t +#include +#include +#include +#include +#include -#include // for uint8_t, uint32_t -#include // for shared_ptr, make_shared -#include // for string -#include // for vector - -#include "device.h" // for Device -#include "include/phy.h" // for Phy, Phy::Type -#include "net/async_data_channel.h" // for AsyncDataChannel -#include "packets/link_layer_packets.h" // for LinkLayerPacketView +#include "model/devices/device.h" +#include "net/async_data_channel.h" +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { diff --git a/tools/rootcanal/model/devices/scripted_beacon.cc b/tools/rootcanal/model/devices/scripted_beacon.cc index 1139944d85619d2539bf18c0446dc8d4e410fd76..7215066d68d5817e5ced76b192662ac370221aa8 100644 --- a/tools/rootcanal/model/devices/scripted_beacon.cc +++ b/tools/rootcanal/model/devices/scripted_beacon.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "scripted_beacon.h" +#include "model/devices/scripted_beacon.h" #include @@ -78,14 +78,14 @@ ScriptedBeacon::ScriptedBeacon(const vector& args) : Beacon(args) { scan_response_data_ = { 0x05 /* Length */, 0x08 /* TYPE_NAME_SHORT */, 'g', 'b', 'e', 'a'}; - LOG_INFO("Scripted_beacon registered %s", registered_ ? "true" : "false"); + INFO("Scripted_beacon registered {}", registered_); if (args.size() >= 4) { config_file_ = args[2]; events_file_ = args[3]; set_state(PlaybackEvent::INITIALIZED); } else { - LOG_ERROR( + ERROR( "Initialization failed, need playback and playback events file " "arguments"); } @@ -97,7 +97,7 @@ bool has_time_elapsed(steady_clock::time_point time_point) { static void populate_event(PlaybackEvent* event, PlaybackEvent::PlaybackEventType type) { - LOG_INFO("Adding event: %d", type); + INFO("Adding event: {}", type); event->set_type(type); event->set_secs_since_epoch(system_clock::now().time_since_epoch().count()); } @@ -111,7 +111,7 @@ void ScriptedBeacon::set_state(PlaybackEvent::PlaybackEventType state) { events_ostream_.open(events_file_, std::ios::out | std::ios::binary | std::ios::trunc); if (!events_ostream_.is_open()) { - LOG_INFO("Events file not opened yet, for event: %d", state); + INFO("Events file not opened yet, for event: {}", state); return; } } @@ -153,13 +153,12 @@ void ScriptedBeacon::Tick() { } std::fstream input(config_file_, std::ios::in | std::ios::binary); if (!ble_ad_list_.ParseFromIstream(&input)) { - LOG_ERROR("Cannot parse playback file %s", config_file_.c_str()); + ERROR("Cannot parse playback file {}", config_file_); set_state(PlaybackEvent::FILE_PARSING_FAILED); return; } set_state(PlaybackEvent::PLAYBACK_STARTED); - LOG_INFO("Starting Ble advertisement playback from file: %s", - config_file_.c_str()); + INFO("Starting Ble advertisement playback from file: {}", config_file_); next_ad_.ad_time = steady_clock::now(); get_next_advertisement(); input.close(); @@ -179,10 +178,10 @@ void ScriptedBeacon::Tick() { if (events_ostream_.is_open()) { events_ostream_.close(); } - LOG_INFO( - "Completed Ble advertisement playback from file: %s with %d " + INFO( + "Completed Ble advertisement playback from file: {} with {} " "packets", - config_file_.c_str(), packet_num_); + config_file_, packet_num_); break; } } diff --git a/tools/rootcanal/model/devices/scripted_beacon.h b/tools/rootcanal/model/devices/scripted_beacon.h index 8bb7b32c152df14c527e3960ede322001ba34520..4d62ac6527373d6bb6951150e7633f446524a8bc 100644 --- a/tools/rootcanal/model/devices/scripted_beacon.h +++ b/tools/rootcanal/model/devices/scripted_beacon.h @@ -20,7 +20,7 @@ #include #include -#include "beacon.h" +#include "model/devices/beacon.h" #include "model/devices/scripted_beacon_ble_payload.pb.h" using android::bluetooth::rootcanal::model::devices::ScriptedBeaconBleAdProto:: diff --git a/tools/rootcanal/model/devices/scripted_beacon_ble_payload.proto b/tools/rootcanal/model/devices/scripted_beacon_ble_payload.proto index 6f66288d5846dd1dbba157d0547cda90e7047055..6f3f792349c7728bbdad34535ab5ae999d4be27e 100644 --- a/tools/rootcanal/model/devices/scripted_beacon_ble_payload.proto +++ b/tools/rootcanal/model/devices/scripted_beacon_ble_payload.proto @@ -1,3 +1,17 @@ +// Copyright 2023 Google LLC +// +// 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 +// +// https://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 = "proto2"; package android.bluetooth.rootcanal.model.devices.ScriptedBeaconBleAdProto; diff --git a/tools/rootcanal/model/devices/sniffer.cc b/tools/rootcanal/model/devices/sniffer.cc index 6adddfab26179592422dcf5fec7a8558bd43104b..793b078b52fd663a6a035378c6f17f80d68d17c7 100644 --- a/tools/rootcanal/model/devices/sniffer.cc +++ b/tools/rootcanal/model/devices/sniffer.cc @@ -14,19 +14,24 @@ * limitations under the License. */ -#include "sniffer.h" +#include "model/devices/sniffer.h" +#include +#include +#include + +#include "hci/address.h" #include "log.h" #include "model/setup/device_boutique.h" - -using std::vector; +#include "packets/link_layer_packets.h" +#include "phy.h" namespace rootcanal { bool Sniffer::registered_ = DeviceBoutique::Register("sniffer", &Sniffer::Create); -Sniffer::Sniffer(const vector& args) { +Sniffer::Sniffer(const std::vector& args) { if (args.size() >= 2) { Address::FromString(args[1], address_); } @@ -44,10 +49,9 @@ void Sniffer::ReceiveLinkLayerPacket(model::packets::LinkLayerPacketView packet, return; } - LOG_INFO("%s %s -> %s (Type %s)", - (match_source ? (match_dest ? "<->" : "<--") : "-->"), - source.ToString().c_str(), dest.ToString().c_str(), - model::packets::PacketTypeText(packet_type).c_str()); + INFO("{} {} -> {} (Type {})", + (match_source ? (match_dest ? "<->" : "<--") : "-->"), source, dest, + model::packets::PacketTypeText(packet_type)); } } // namespace rootcanal diff --git a/tools/rootcanal/model/devices/sniffer.h b/tools/rootcanal/model/devices/sniffer.h index 5ee49ff2e4c4159468a01bd3349b194832fa1c0f..60bee3e9c29041630f17adda92bc6f7d61f74460 100644 --- a/tools/rootcanal/model/devices/sniffer.h +++ b/tools/rootcanal/model/devices/sniffer.h @@ -25,8 +25,6 @@ namespace rootcanal { -using ::bluetooth::hci::Address; - class Sniffer : public Device { public: Sniffer(const std::vector& args); diff --git a/tools/rootcanal/model/hci/h4_data_channel_packetizer.cc b/tools/rootcanal/model/hci/h4_data_channel_packetizer.cc index b1a4efcf5d3d051ffd1e8cd5618da34bd5ab8bcb..e8f2114ecd25257b279ec1d644f1087d1f865f65 100644 --- a/tools/rootcanal/model/hci/h4_data_channel_packetizer.cc +++ b/tools/rootcanal/model/hci/h4_data_channel_packetizer.cc @@ -26,9 +26,8 @@ #include // for move #include // for vector -#include "log.h" // for LOG_ERROR, LOG_ALWAYS_FATAL +#include "log.h" #include "model/hci/h4_parser.h" // for H4Parser, ClientDisconnectCa... -#include "model/hci/hci_protocol.h" // for PacketReadCallback, AsyncDataChannel #include "net/async_data_channel.h" // for AsyncDataChannel namespace rootcanal { @@ -46,20 +45,19 @@ size_t H4DataChannelPacketizer::Send(uint8_t type, const uint8_t* data, size_t length) { ssize_t ret = uart_socket_->Send(&type, sizeof(type)); if (ret == -1) { - LOG_ERROR("Error writing to UART (%s)", strerror(errno)); + ERROR("Error writing to UART ({})", strerror(errno)); } size_t to_be_written = ret; ret = uart_socket_->Send(data, length); if (ret == -1) { - LOG_ERROR("Error writing to UART (%s)", strerror(errno)); + ERROR("Error writing to UART ({})", strerror(errno)); } to_be_written += ret; if (to_be_written != length + sizeof(type)) { - LOG_ERROR("%d / %d bytes written - something went wrong...", - static_cast(to_be_written), - static_cast(length + sizeof(type))); + ERROR("{} / {} bytes written - something went wrong...", to_be_written, + length + sizeof(type)); } return to_be_written; } @@ -76,7 +74,7 @@ void H4DataChannelPacketizer::OnDataReady( ssize_t bytes_read = socket->Recv(buffer.data(), bytes_to_read); if (bytes_read == 0) { - LOG_INFO("remote disconnected!"); + INFO("remote disconnected!"); disconnected_ = true; disconnect_cb_(); return; @@ -92,8 +90,7 @@ void H4DataChannelPacketizer::OnDataReady( disconnect_cb_(); return; } - LOG_ALWAYS_FATAL("Read error in %u: %s", h4_parser_.CurrentState(), - strerror(errno)); + FATAL("Read error in {}: {}", h4_parser_.CurrentState(), strerror(errno)); } h4_parser_.Consume(buffer.data(), bytes_read); } diff --git a/tools/rootcanal/model/hci/h4_data_channel_packetizer.h b/tools/rootcanal/model/hci/h4_data_channel_packetizer.h index 819f037b1f1c2c97ca74bebf9b0bf9d6733d8852..272373c26eb2065189dc32d5fc3af7b514c36eb8 100644 --- a/tools/rootcanal/model/hci/h4_data_channel_packetizer.h +++ b/tools/rootcanal/model/hci/h4_data_channel_packetizer.h @@ -21,8 +21,7 @@ #include // for shared_ptr -#include "h4_parser.h" // for ClientDisconnectCallback, H4Parser -#include "hci_protocol.h" // for PacketReadCallback, AsyncDataChannel, HciProtocol +#include "h4_parser.h" // for ClientDisconnectCallback, H4Parser #include "net/async_data_channel.h" // for AsyncDataChannel namespace rootcanal { @@ -31,7 +30,7 @@ using android::net::AsyncDataChannel; // A socket based H4DataChannelPacketizer. Call OnDataReady whenever // data can be read from the socket. -class H4DataChannelPacketizer : public HciProtocol { +class H4DataChannelPacketizer { public: H4DataChannelPacketizer(std::shared_ptr socket, PacketReadCallback command_cb, @@ -40,7 +39,7 @@ class H4DataChannelPacketizer : public HciProtocol { PacketReadCallback iso_cb, ClientDisconnectCallback disconnect_cb); - size_t Send(uint8_t type, const uint8_t* data, size_t length) override; + size_t Send(uint8_t type, const uint8_t* data, size_t length); void OnDataReady(std::shared_ptr socket); diff --git a/tools/rootcanal/model/hci/h4_packetizer.cc b/tools/rootcanal/model/hci/h4_packetizer.cc deleted file mode 100644 index 9564669079b28f8aa5e27fac29f35ae00051233c..0000000000000000000000000000000000000000 --- a/tools/rootcanal/model/hci/h4_packetizer.cc +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright 2017 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "h4_packetizer.h" - -#include -#include -#include -#include - -#include - -#include "log.h" - -namespace rootcanal { - -H4Packetizer::H4Packetizer(int fd, PacketReadCallback command_cb, - PacketReadCallback event_cb, - PacketReadCallback acl_cb, PacketReadCallback sco_cb, - PacketReadCallback iso_cb, - ClientDisconnectCallback disconnect_cb) - : uart_fd_(fd), - h4_parser_(command_cb, event_cb, acl_cb, sco_cb, iso_cb), - disconnect_cb_(std::move(disconnect_cb)) {} - -size_t H4Packetizer::Send(uint8_t type, const uint8_t* data, size_t length) { - struct iovec iov[] = {{&type, sizeof(type)}, - {const_cast(data), length}}; - ssize_t ret = 0; - do { - ret = writev(uart_fd_, iov, sizeof(iov) / sizeof(iov[0])); - } while (-1 == ret && (EINTR == errno || EAGAIN == errno)); - - if (ret == -1) { - LOG_ERROR("Error writing to UART (%s)", strerror(errno)); - } else if (ret < static_cast(length + 1)) { - LOG_ERROR("%d / %d bytes written - something went wrong...", - static_cast(ret), static_cast(length + 1)); - } - return ret; -} - -void H4Packetizer::OnDataReady(int fd) { - if (disconnected_) { - return; - } - ssize_t bytes_to_read = h4_parser_.BytesRequested(); - std::vector buffer(bytes_to_read); - - ssize_t bytes_read; - do { - bytes_read = read(fd, buffer.data(), bytes_to_read); - } while (bytes_read == -1 && errno == EINTR); - - if (bytes_read == 0) { - LOG_INFO("remote disconnected!"); - disconnected_ = true; - disconnect_cb_(); - return; - } - if (bytes_read < 0) { - if (errno == EAGAIN) { - // No data, try again later. - return; - } - if (errno == ECONNRESET) { - // They probably rejected our packet - disconnected_ = true; - disconnect_cb_(); - return; - } - - LOG_ALWAYS_FATAL("Read error in %d: %s", h4_parser_.CurrentState(), - strerror(errno)); - } - h4_parser_.Consume(buffer.data(), bytes_read); -} - -} // namespace rootcanal diff --git a/tools/rootcanal/model/hci/h4_packetizer.h b/tools/rootcanal/model/hci/h4_packetizer.h deleted file mode 100644 index 9c65a666c29cf91e91a6add1fbe73f4765f4e956..0000000000000000000000000000000000000000 --- a/tools/rootcanal/model/hci/h4_packetizer.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright 2017 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#pragma once - -#include -#include - -#include "h4_parser.h" -#include "hci_protocol.h" - -namespace rootcanal { - -// A socket based H4Packetizer. Call OnDataReady whenever -// data can be read from file descriptor fd. -// -// This is only supported on unix. -class H4Packetizer : public HciProtocol { - public: - H4Packetizer(int fd, PacketReadCallback command_cb, - PacketReadCallback event_cb, PacketReadCallback acl_cb, - PacketReadCallback sco_cb, PacketReadCallback iso_cb, - ClientDisconnectCallback disconnect_cb); - - size_t Send(uint8_t type, const uint8_t* data, size_t length) override; - - void OnDataReady(int fd); - - private: - int uart_fd_; - H4Parser h4_parser_; - - ClientDisconnectCallback disconnect_cb_; - bool disconnected_{false}; -}; - -} // namespace rootcanal diff --git a/tools/rootcanal/model/hci/h4_parser.cc b/tools/rootcanal/model/hci/h4_parser.cc index 1aabcbb6d605b0e0d3d2620e1085d25af0e3b9e0..c263cd7389aacd8ab81516d5cda3af4fcecd5346 100644 --- a/tools/rootcanal/model/hci/h4_parser.cc +++ b/tools/rootcanal/model/hci/h4_parser.cc @@ -1,5 +1,5 @@ // -// Copyright 20 The Android Open Source Project +// Copyright 2021 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,8 +23,7 @@ #include // for move #include // for vector -#include "log.h" // for LOG_ALWAYS_FATAL, LOG_INFO -#include "model/hci/hci_protocol.h" // for PacketReadCallback +#include "log.h" namespace rootcanal { @@ -86,8 +85,7 @@ void H4Parser::OnPacketReady() { iso_cb_(packet_); break; default: - LOG_ALWAYS_FATAL("Unimplemented packet type %d", - static_cast(hci_packet_type_)); + FATAL("Unimplemented packet type {}", hci_packet_type_); } // Get ready for the next type byte. hci_packet_type_ = PacketType::UNKNOWN; @@ -107,13 +105,12 @@ size_t H4Parser::BytesRequested() { bool H4Parser::Consume(const uint8_t* buffer, int32_t bytes_read) { size_t bytes_to_read = BytesRequested(); if (bytes_read <= 0) { - LOG_INFO("remote disconnected, or unhandled error?"); + INFO("remote disconnected, or unhandled error?"); return false; } if ((uint32_t)bytes_read > BytesRequested()) { - LOG_ALWAYS_FATAL("More bytes read (%u) than expected (%u)!", - static_cast(bytes_read), - static_cast(bytes_to_read)); + FATAL("More bytes read ({}) than expected ({})!", bytes_read, + bytes_to_read); } static const size_t preamble_size[static_cast(PacketType::ISO) + 1] = @@ -137,8 +134,7 @@ bool H4Parser::Consume(const uint8_t* buffer, int32_t bytes_read) { // The parser can end up in a bad state when the host is restarted. const std::array reset_command{0x01, 0x03, 0x0c, 0x00}; size_t offset = packet_.size(); - LOG_WARN("Received byte in recovery state : 0x%x", - static_cast(*buffer)); + WARNING("Received byte in recovery state : 0x{:x}", *buffer); packet_.push_back(*buffer); // Last byte does not match expected byte in the sequence. @@ -153,7 +149,7 @@ bool H4Parser::Consume(const uint8_t* buffer, int32_t bytes_read) { // Received full reset command. if (packet_.size() == reset_command.size()) { - LOG_INFO("Received HCI Reset command, exiting recovery state"); + INFO("Received HCI Reset command, exiting recovery state"); // Pop the Idc from the received packet. packet_.erase(packet_.begin()); bytes_wanted_ = 0; @@ -177,11 +173,10 @@ bool H4Parser::Consume(const uint8_t* buffer, int32_t bytes_read) { hci_packet_type_ != PacketType::EVENT && hci_packet_type_ != PacketType::ISO) { if (!enable_recovery_state_) { - LOG_ALWAYS_FATAL("Received invalid packet type 0x%x", - static_cast(packet_type_)); + FATAL("Received invalid packet type 0x{:x}", packet_type_); } - LOG_ERROR("Received invalid packet type 0x%x, entering recovery state", - static_cast(packet_type_)); + ERROR("Received invalid packet type 0x{:x}, entering recovery state", + packet_type_); state_ = HCI_RECOVERY; hci_packet_type_ = PacketType::COMMAND; bytes_wanted_ = 1; diff --git a/tools/rootcanal/model/hci/h4_parser.h b/tools/rootcanal/model/hci/h4_parser.h index 01f13b73c17bcee7b8577a13872a362a7a996639..e7a63636fa8561fbb7dce67378c04026a1d4ec65 100644 --- a/tools/rootcanal/model/hci/h4_parser.h +++ b/tools/rootcanal/model/hci/h4_parser.h @@ -23,11 +23,11 @@ #include // for operator<<, ostream #include // for vector -#include "model/hci/h4.h" // for PacketType -#include "model/hci/hci_protocol.h" // for PacketReadCallback +#include "model/hci/h4.h" // for PacketType namespace rootcanal { +using PacketReadCallback = std::function&)>; using HciPacketReadyCallback = std::function; using ClientDisconnectCallback = std::function; diff --git a/tools/rootcanal/model/hci/hci_protocol.cc b/tools/rootcanal/model/hci/hci_protocol.cc deleted file mode 100644 index ea0ce454136e954eeb8e299e5dbbaf2f9bc5f953..0000000000000000000000000000000000000000 --- a/tools/rootcanal/model/hci/hci_protocol.cc +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright 2017 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "hci_protocol.h" - -#include -#include -#include -#include - -#include "log.h" - -namespace rootcanal { - -size_t HciProtocol::WriteSafely(AsyncDataChannel* socket, const uint8_t* data, - size_t length) { - size_t transmitted_length = 0; - while (length > 0) { - ssize_t ret = socket->Send(data + transmitted_length, length); - - if (ret == -1) { - if (errno == EAGAIN) { - continue; - } - LOG_ERROR("%s error writing to UART (%s)", __func__, strerror(errno)); - break; - } - if (ret == 0) { - // Nothing written :( - LOG_ERROR("%s zero bytes written - something went wrong...", __func__); - break; - } - - transmitted_length += ret; - length -= ret; - } - - return transmitted_length; -} - -} // namespace rootcanal diff --git a/tools/rootcanal/model/hci/hci_protocol.h b/tools/rootcanal/model/hci/hci_protocol.h deleted file mode 100644 index b13f82069b7d56b071bea2ba6086fe1db25a1b6d..0000000000000000000000000000000000000000 --- a/tools/rootcanal/model/hci/hci_protocol.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright 2017 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#pragma once - -#include -#include - -#include "net/async_data_channel.h" - -namespace rootcanal { - -using PacketReadCallback = std::function&)>; -using android::net::AsyncDataChannel; - -// Implementation of HCI protocol bits common to different transports -class HciProtocol { - public: - HciProtocol() = default; - virtual ~HciProtocol(){}; - - // Protocol-specific implementation of sending packets. - virtual size_t Send(uint8_t type, const uint8_t* data, size_t length) = 0; - - protected: - static size_t WriteSafely(AsyncDataChannel* socket, const uint8_t* data, - size_t length); -}; - -} // namespace rootcanal diff --git a/tools/rootcanal/model/hci/hci_sniffer.cc b/tools/rootcanal/model/hci/hci_sniffer.cc index f0dbc139f0525f851c9143fcf3379a18ca6a9048..ea3e2cbeac3b0afb1db153cd9f7851f3d1e77d90 100644 --- a/tools/rootcanal/model/hci/hci_sniffer.cc +++ b/tools/rootcanal/model/hci/hci_sniffer.cc @@ -73,32 +73,14 @@ void HciSniffer::AppendRecord(PacketDirection packet_direction, output_->flush(); } -void HciSniffer::RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, +void HciSniffer::RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) { transport_->RegisterCallbacks( - [this, - command_callback](const std::shared_ptr> command) { - AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::COMMAND, - *command); - command_callback(command); - }, - [this, acl_callback](const std::shared_ptr> acl) { - AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::ACL, - *acl); - acl_callback(acl); - }, - [this, sco_callback](const std::shared_ptr> sco) { - AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::SCO, - *sco); - sco_callback(sco); - }, - [this, iso_callback](const std::shared_ptr> iso) { - AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::ISO, - *iso); - iso_callback(iso); + [this, packet_callback]( + PacketType packet_type, + const std::shared_ptr> packet) { + AppendRecord(PacketDirection::HOST_TO_CONTROLLER, packet_type, *packet); + packet_callback(packet_type, packet); }, close_callback); } @@ -112,23 +94,10 @@ void HciSniffer::Close() { } } -void HciSniffer::SendEvent(const std::vector& packet) { - AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::EVENT, packet); - transport_->SendEvent(packet); -} - -void HciSniffer::SendAcl(const std::vector& packet) { - AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::ACL, packet); - transport_->SendAcl(packet); -} - -void HciSniffer::SendSco(const std::vector& packet) { - AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::SCO, packet); - transport_->SendSco(packet); +void HciSniffer::Send(PacketType packet_type, + const std::vector& packet) { + AppendRecord(PacketDirection::CONTROLLER_TO_HOST, packet_type, packet); + transport_->Send(packet_type, packet); } -void HciSniffer::SendIso(const std::vector& packet) { - AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::ISO, packet); - transport_->SendIso(packet); -} } // namespace rootcanal diff --git a/tools/rootcanal/model/hci/hci_sniffer.h b/tools/rootcanal/model/hci/hci_sniffer.h index da7d9fe83393c9615c80f7d1b5c772ddd7f2ce1f..5ad47fbe7b364108c37e04ffdaded7368716cf43 100644 --- a/tools/rootcanal/model/hci/hci_sniffer.h +++ b/tools/rootcanal/model/hci/hci_sniffer.h @@ -44,7 +44,7 @@ class HciSniffer : public HciTransport { static std::shared_ptr Create( std::shared_ptr transport, std::shared_ptr outputStream = nullptr, - std::shared_ptr filter = nullptr) { + std::shared_ptr /*filter*/ = nullptr) { return std::make_shared(transport, outputStream); } @@ -52,22 +52,13 @@ class HciSniffer : public HciTransport { void SetOutputStream(std::shared_ptr outputStream); void SetPcapFilter(std::shared_ptr filter); - void SendEvent(const std::vector& packet) override; + void Send(PacketType packet_type, + const std::vector& packet) override; - void SendAcl(const std::vector& packet) override; - - void SendSco(const std::vector& packet) override; - - void SendIso(const std::vector& packet) override; - - void RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, + void RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) override; void Tick() override; - void Close() override; private: diff --git a/tools/rootcanal/model/hci/hci_socket_transport.cc b/tools/rootcanal/model/hci/hci_socket_transport.cc index 6a84e753e0e56751f4371dbd527fd1f627d37f36..82632e466ddb0c74085cd4c49c22085493e197e9 100644 --- a/tools/rootcanal/model/hci/hci_socket_transport.cc +++ b/tools/rootcanal/model/hci/hci_socket_transport.cc @@ -16,76 +16,56 @@ #include "hci_socket_transport.h" -#include "log.h" // for LOG_INFO, LOG_ALWAYS_FATAL +#include "log.h" namespace rootcanal { HciSocketTransport::HciSocketTransport(std::shared_ptr socket) : socket_(socket) {} -void HciSocketTransport::RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, +void HciSocketTransport::RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) { // TODO: Avoid the copy here by using new buffer in H4DataChannel h4_ = H4DataChannelPacketizer( socket_, - [command_callback](const std::vector& raw_command) { + [packet_callback](const std::vector& raw_command) { std::shared_ptr> packet_copy = std::make_shared>(raw_command); - command_callback(packet_copy); + packet_callback(PacketType::COMMAND, packet_copy); }, [](const std::vector&) { - LOG_ALWAYS_FATAL("Unexpected Event in HciSocketTransport!"); + FATAL("Unexpected Event in HciSocketTransport!"); }, - [acl_callback](const std::vector& raw_acl) { + [packet_callback](const std::vector& raw_acl) { std::shared_ptr> packet_copy = std::make_shared>(raw_acl); - acl_callback(packet_copy); + packet_callback(PacketType::ACL, packet_copy); }, - [sco_callback](const std::vector& raw_sco) { + [packet_callback](const std::vector& raw_sco) { std::shared_ptr> packet_copy = std::make_shared>(raw_sco); - sco_callback(packet_copy); + packet_callback(PacketType::SCO, packet_copy); }, - [iso_callback](const std::vector& raw_iso) { + [packet_callback](const std::vector& raw_iso) { std::shared_ptr> packet_copy = std::make_shared>(raw_iso); - iso_callback(packet_copy); + packet_callback(PacketType::ISO, packet_copy); }, close_callback); } void HciSocketTransport::Tick() { h4_.OnDataReady(socket_); } -void HciSocketTransport::SendHci(PacketType packet_type, - const std::vector& packet) { +void HciSocketTransport::Send(PacketType packet_type, + const std::vector& packet) { if (!socket_ || !socket_->Connected()) { - LOG_INFO("Closed socket. Dropping packet of type %d", - static_cast(packet_type)); + INFO("Closed socket. Dropping packet of type {}", packet_type); return; } uint8_t type = static_cast(packet_type); h4_.Send(type, packet.data(), packet.size()); } -void HciSocketTransport::SendEvent(const std::vector& packet) { - SendHci(PacketType::EVENT, packet); -} - -void HciSocketTransport::SendAcl(const std::vector& packet) { - SendHci(PacketType::ACL, packet); -} - -void HciSocketTransport::SendSco(const std::vector& packet) { - SendHci(PacketType::SCO, packet); -} - -void HciSocketTransport::SendIso(const std::vector& packet) { - SendHci(PacketType::ISO, packet); -} - void HciSocketTransport::Close() { socket_->Close(); } } // namespace rootcanal diff --git a/tools/rootcanal/model/hci/hci_socket_transport.h b/tools/rootcanal/model/hci/hci_socket_transport.h index 6bd2d8e7e57891c910cae1daa9a6f984fa654d29..e6e4a356acdf48f6c5a8ded2acaaeb5f8bfa333c 100644 --- a/tools/rootcanal/model/hci/hci_socket_transport.h +++ b/tools/rootcanal/model/hci/hci_socket_transport.h @@ -36,27 +36,16 @@ class HciSocketTransport : public HciTransport { return std::make_shared(socket); } - void SendEvent(const std::vector& packet) override; + void Send(PacketType packet_type, + const std::vector& packet) override; - void SendAcl(const std::vector& packet) override; - - void SendSco(const std::vector& packet) override; - - void SendIso(const std::vector& packet) override; - - void RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, + void RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) override; void Tick() override; - void Close() override; private: - void SendHci(PacketType packet_type, const std::vector& packet); - std::shared_ptr socket_; H4DataChannelPacketizer h4_{socket_, [](const std::vector&) {}, diff --git a/tools/rootcanal/model/hci/hci_transport.h b/tools/rootcanal/model/hci/hci_transport.h index e682801255eb32ddaff5a203766f1494d710c5ab..5aa10f160c0c4dbf269d409330bdda487b119792 100644 --- a/tools/rootcanal/model/hci/hci_transport.h +++ b/tools/rootcanal/model/hci/hci_transport.h @@ -20,32 +20,28 @@ #include #include +#include "model/hci/h4.h" + namespace rootcanal { -using PacketCallback = - std::function>)>; +using PacketCallback = std::function>)>; using CloseCallback = std::function; class HciTransport { public: virtual ~HciTransport() = default; - virtual void SendEvent(const std::vector& packet) = 0; - - virtual void SendAcl(const std::vector& packet) = 0; - - virtual void SendSco(const std::vector& packet) = 0; + /// Send the input HCI packet with the selected H4 packet type. + /// The packet data contains the H4 header but not the IDC byte. + virtual void Send(PacketType packet_type, + std::vector const& packet) = 0; - virtual void SendIso(const std::vector& packet) = 0; - - virtual void RegisterCallbacks(PacketCallback command_callback, - PacketCallback acl_callback, - PacketCallback sco_callback, - PacketCallback iso_callback, + /// Register the handler for received HCI packets. + virtual void RegisterCallbacks(PacketCallback packet_callback, CloseCallback close_callback) = 0; virtual void Tick() = 0; - virtual void Close() = 0; }; diff --git a/tools/rootcanal/model/setup/async_manager.cc b/tools/rootcanal/model/setup/async_manager.cc index dd9b1a4687604ac65fec580f7401d6a9cfb6a173..2bbdfba6d2c2997e9d620791db6c0213151782a3 100644 --- a/tools/rootcanal/model/setup/async_manager.cc +++ b/tools/rootcanal/model/setup/async_manager.cc @@ -105,7 +105,7 @@ class AsyncManager::AsyncFdWatcher { // start the thread if not started yet int started = tryStartThread(); if (started != 0) { - LOG_ERROR("%s: Unable to start thread", __func__); + ERROR("{}: Unable to start thread", __func__); return started; } @@ -136,8 +136,8 @@ class AsyncManager::AsyncFdWatcher { if (std::this_thread::get_id() != thread_.get_id()) { thread_.join(); } else { - LOG_WARN("%s: Starting thread stop from inside the reading thread itself", - __func__); + WARNING("{}: Starting thread stop from inside the reading thread itself", + __func__); } { @@ -158,8 +158,8 @@ class AsyncManager::AsyncFdWatcher { // set up the communication channel int pipe_fds[2]; if (pipe2(pipe_fds, O_NONBLOCK)) { - LOG_ERROR( - "%s:Unable to establish a communication channel to the reading " + ERROR( + "{}: Unable to establish a communication channel to the reading " "thread", __func__); return -1; @@ -169,7 +169,7 @@ class AsyncManager::AsyncFdWatcher { thread_ = std::thread([this]() { ThreadRoutine(); }); if (!thread_.joinable()) { - LOG_ERROR("%s: Unable to start reading thread", __func__); + ERROR("{}: Unable to start reading thread", __func__); return -1; } return 0; @@ -178,7 +178,7 @@ class AsyncManager::AsyncFdWatcher { int notifyThread() const { char buffer = '0'; if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) { - LOG_ERROR("%s: Unable to send message to reading thread", __func__); + ERROR("{}: Unable to send message to reading thread", __func__); return -1; } return 0; @@ -236,9 +236,9 @@ class AsyncManager::AsyncFdWatcher { // wait until there is data available to read on some FD int retval = select(nfds + 1, &read_fds, NULL, NULL, NULL); if (retval <= 0) { // there was some error or a timeout - LOG_ERROR( - "%s: There was an error while waiting for data on the file " - "descriptors: %s", + ERROR( + "{}: There was an error while waiting for data on the file " + "descriptors: {}", __func__, strerror(errno)); continue; } @@ -329,8 +329,8 @@ class AsyncManager::AsyncTaskManager { if (std::this_thread::get_id() != thread_.get_id()) { thread_.join(); } else { - LOG_WARN("%s: Starting thread stop from inside the task thread itself", - __func__); + WARNING("{}: Starting thread stop from inside the task thread itself", + __func__); } return 0; } @@ -425,7 +425,7 @@ class AsyncManager::AsyncTaskManager { // start thread if necessary int started = tryStartThread(); if (started != 0) { - LOG_ERROR("%s: Unable to start thread", __func__); + ERROR("{}: Unable to start thread", __func__); return kInvalidTaskId; } // notify the thread so that it knows of the new task @@ -449,7 +449,7 @@ class AsyncManager::AsyncTaskManager { running_ = true; thread_ = std::thread([this]() { ThreadRoutine(); }); if (!thread_.joinable()) { - LOG_ERROR("%s: Unable to start task thread", __func__); + ERROR("{}: Unable to start task thread", __func__); return -1; } return 0; diff --git a/tools/rootcanal/model/setup/async_manager.h b/tools/rootcanal/model/setup/async_manager.h index bc1f7fd0f556d35f945fbf1ae2dfc2c65b2d7be3..d1861d2f6dbf7926eb40cae9a690c05cad447f27 100644 --- a/tools/rootcanal/model/setup/async_manager.h +++ b/tools/rootcanal/model/setup/async_manager.h @@ -1,3 +1,19 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #ifndef TEST_VENDOR_LIB_ASYNC_MANAGER_H_ #define TEST_VENDOR_LIB_ASYNC_MANAGER_H_ diff --git a/tools/rootcanal/model/setup/device_boutique.cc b/tools/rootcanal/model/setup/device_boutique.cc index 0b5a830355705504c88e73c575a3b161df529feb..ad04cbe28f6664e615cf3571efe87fe64beaf63d 100644 --- a/tools/rootcanal/model/setup/device_boutique.cc +++ b/tools/rootcanal/model/setup/device_boutique.cc @@ -36,7 +36,7 @@ bool DeviceBoutique::Register( const std::string& device_type, const std::function(const vector&)> method) { - LOG_INFO("Registering %s", device_type.c_str()); + INFO("Registering {}", device_type); GetMap()[device_type] = method; return true; } @@ -48,7 +48,7 @@ std::shared_ptr DeviceBoutique::Create( auto device = GetMap().find(args[0]); if (device == GetMap().end()) { - LOG_WARN("No constructor registered for %s", args[0].c_str()); + WARNING("No constructor registered for {}", args[0]); return std::shared_ptr(nullptr); } diff --git a/tools/rootcanal/model/setup/phy_device.cc b/tools/rootcanal/model/setup/phy_device.cc index 1d5bf3ae4069f7b03aa6d130f1eabece44819c6d..59f3d52b435b4f6f0cfa46ae6332087f3c6f3794 100644 --- a/tools/rootcanal/model/setup/phy_device.cc +++ b/tools/rootcanal/model/setup/phy_device.cc @@ -16,13 +16,14 @@ #include "phy_device.h" +#include + #include "phy_layer.h" namespace rootcanal { -PhyDevice::PhyDevice(Identifier id, std::string type, - std::shared_ptr device) - : id(id), type(std::move(type)), device_(std::move(device)) { +PhyDevice::PhyDevice(std::string type, std::shared_ptr device) + : id(device->id_), type(std::move(type)), device_(std::move(device)) { using namespace std::placeholders; ASSERT(device_ != nullptr); device_->RegisterLinkLayerChannel( @@ -35,6 +36,14 @@ void PhyDevice::Unregister(PhyLayer* phy) { phy_layers_.erase(phy); } void PhyDevice::Tick() { device_->Tick(); } +bluetooth::hci::Address PhyDevice::GetAddress() const { + return device_->GetAddress(); +} + +std::shared_ptr PhyDevice::GetDevice() const { + return device_; +} + void PhyDevice::SetAddress(bluetooth::hci::Address address) { device_->SetAddress(std::move(address)); } @@ -45,12 +54,11 @@ void PhyDevice::Receive(std::vector const& packet, Phy::Type type, std::make_shared>(packet); model::packets::LinkLayerPacketView packet_view = model::packets::LinkLayerPacketView::Create( - bluetooth::packet::PacketView( - packet_copy)); + pdl::packet::slice(packet_copy)); if (packet_view.IsValid()) { device_->ReceiveLinkLayerPacket(std::move(packet_view), type, rssi); } else { - LOG_WARN("received invalid LL packet"); + WARNING("received invalid LL packet"); } } diff --git a/tools/rootcanal/model/setup/phy_device.h b/tools/rootcanal/model/setup/phy_device.h index 60a5edb98b9f460018a0ba4bb85ba58ca111d485..af45dbedd4595636bebcf67293a802ce5aa9d89c 100644 --- a/tools/rootcanal/model/setup/phy_device.h +++ b/tools/rootcanal/model/setup/phy_device.h @@ -31,7 +31,7 @@ class PhyDevice { public: using Identifier = uint32_t; - PhyDevice(Identifier id, std::string type, std::shared_ptr device); + PhyDevice(std::string type, std::shared_ptr device); PhyDevice(PhyDevice &&) = delete; ~PhyDevice() = default; @@ -43,6 +43,8 @@ class PhyDevice { void Send(std::vector const& packet, Phy::Type type, int8_t tx_power); + bluetooth::hci::Address GetAddress() const; + std::shared_ptr GetDevice() const; void SetAddress(bluetooth::hci::Address address); std::string ToString(); diff --git a/tools/rootcanal/model/setup/phy_layer.cc b/tools/rootcanal/model/setup/phy_layer.cc index 1c669120bd5c2e431235f07a551cd3f0098a35f3..301979c85f8bacb4ad8bba50df9f0aefc44e2bbf 100644 --- a/tools/rootcanal/model/setup/phy_layer.cc +++ b/tools/rootcanal/model/setup/phy_layer.cc @@ -44,9 +44,9 @@ void PhyLayer::UnregisterAll() { phy_devices_.clear(); } -int8_t PhyLayer::ComputeRssi(PhyDevice::Identifier sender_id, - PhyDevice::Identifier receiver_id, - int8_t tx_power) { +int8_t PhyLayer::ComputeRssi(PhyDevice::Identifier /*sender_id*/, + PhyDevice::Identifier /*receiver_id*/, + int8_t /*tx_power*/) { // Perform no RSSI computation by default. // Clients overriding this function should use the TX power and // positional information to derive correct device-to-device RSSI. diff --git a/tools/rootcanal/model/setup/test_channel_transport.cc b/tools/rootcanal/model/setup/test_channel_transport.cc index a4635e3f831f5420ae237afc375c4035f9e5da93..6b04326be66d0a556d6c13d33a38544d8f7f4db6 100644 --- a/tools/rootcanal/model/setup/test_channel_transport.cc +++ b/tools/rootcanal/model/setup/test_channel_transport.cc @@ -23,7 +23,7 @@ #include // for strerror #include // for remove_extent_t -#include "log.h" // for LOG_INFO, ASSERT_LOG, LOG_WARN +#include "log.h" #include "net/async_data_channel.h" // for AsyncDataChannel using std::vector; @@ -48,21 +48,21 @@ void TestChannelTransport::OnCommandReady(AsyncDataChannel* socket, uint8_t command_name_size = 0; ssize_t bytes_read = socket->Recv(&command_name_size, 1); if (bytes_read != 1) { - LOG_INFO("Unexpected (command_name_size) bytes_read: %zd != %d, %s", - bytes_read, 1, strerror(errno)); + INFO("Unexpected (command_name_size) bytes_read: {} != {}, {}", bytes_read, + 1, strerror(errno)); socket->Close(); } vector command_name_raw; command_name_raw.resize(command_name_size); bytes_read = socket->Recv(command_name_raw.data(), command_name_size); if (bytes_read != command_name_size) { - LOG_INFO("Unexpected (command_name) bytes_read: %zd != %d, %s", bytes_read, - command_name_size, strerror(errno)); + INFO("Unexpected (command_name) bytes_read: {} != {}, {}", bytes_read, + command_name_size, strerror(errno)); } std::string command_name(command_name_raw.begin(), command_name_raw.end()); if (command_name == "CLOSE_TEST_CHANNEL" || command_name.empty()) { - LOG_INFO("Test channel closed"); + INFO("Test channel closed"); unwatch(); socket->Close(); return; @@ -71,23 +71,23 @@ void TestChannelTransport::OnCommandReady(AsyncDataChannel* socket, uint8_t num_args = 0; bytes_read = socket->Recv(&num_args, 1); if (bytes_read != 1) { - LOG_INFO("Unexpected (num_args) bytes_read: %zd != %d, %s", bytes_read, 1, - strerror(errno)); + INFO("Unexpected (num_args) bytes_read: {} != {}, {}", bytes_read, 1, + strerror(errno)); } vector args; for (uint8_t i = 0; i < num_args; ++i) { uint8_t arg_size = 0; bytes_read = socket->Recv(&arg_size, 1); if (bytes_read != 1) { - LOG_INFO("Unexpected (arg_size) bytes_read: %zd != %d, %s", bytes_read, 1, - strerror(errno)); + INFO("Unexpected (arg_size) bytes_read: {} != {}, {}", bytes_read, 1, + strerror(errno)); } vector arg; arg.resize(arg_size); bytes_read = socket->Recv(arg.data(), arg_size); if (bytes_read != arg_size) { - LOG_INFO("Unexpected (arg) bytes_read: %zd != %d, %s", bytes_read, - arg_size, strerror(errno)); + INFO("Unexpected (arg) bytes_read: {} != {}, {}", bytes_read, arg_size, + strerror(errno)); } args.push_back(std::string(arg.begin(), arg.end())); } @@ -108,7 +108,7 @@ void TestChannelTransport::SendResponse( static_cast((size >> 24) & 0xff)}; ssize_t written = socket->Send(size_buf, 4); if (written == -1 && errno == EBADF) { - LOG_WARN("Unable to send a response. EBADF"); + WARNING("Unable to send a response. EBADF"); return; } ASSERT_LOG(written == 4, "What happened? written = %zd errno = %d", written, diff --git a/tools/rootcanal/model/setup/test_command_handler.cc b/tools/rootcanal/model/setup/test_command_handler.cc index b0eaa5fdb8de6afe983b62f26d0ab9ec56380e25..45b947c09b1420e99f25b3d2bc3a57c8e38f824e 100644 --- a/tools/rootcanal/model/setup/test_command_handler.cc +++ b/tools/rootcanal/model/setup/test_command_handler.cc @@ -25,11 +25,16 @@ #include "device_boutique.h" #include "log.h" #include "phy.h" +#include "rootcanal/configuration.pb.h" using std::vector; namespace rootcanal { +static size_t ParseIntParam(std::string const& in) { + return static_cast(std::strtoul(in.c_str(), nullptr, 0)); +} + TestCommandHandler::TestCommandHandler(TestModel& test_model) : model_(test_model) { #define SET_HANDLER(command_name, method) \ @@ -45,6 +50,7 @@ TestCommandHandler::TestCommandHandler(TestModel& test_model) SET_HANDLER("del_device_from_phy", RemoveDeviceFromPhy); SET_HANDLER("list", List); SET_HANDLER("set_device_address", SetDeviceAddress); + SET_HANDLER("set_device_configuration", SetDeviceConfiguration); SET_HANDLER("set_timer_period", SetTimerPeriod); SET_HANDLER("start_timer", StartTimer); SET_HANDLER("stop_timer", StopTimer); @@ -106,11 +112,11 @@ void TestCommandHandler::AddDevice(const vector& args) { if (new_dev == NULL) { response_string_ = "TestCommandHandler 'add' " + args[0] + " failed!"; send_response_(response_string_); - LOG_WARN("%s", response_string_.c_str()); + WARNING("{}", response_string_); return; } - LOG_INFO("Add %s", new_dev->ToString().c_str()); + INFO("Add {}", new_dev->ToString()); size_t dev_index = model_.AddDevice(new_dev); response_string_ = std::to_string(dev_index) + std::string(":") + new_dev->ToString(); @@ -125,7 +131,7 @@ void TestCommandHandler::AddRemote(const vector& args) { return; } - size_t port = std::stoi(args[1]); + size_t port = ParseIntParam(args[1]); Phy::Type phy_type = Phy::Type::BR_EDR; if ("LOW_ENERGY" == args[2]) { phy_type = Phy::Type::LOW_ENERGY; @@ -146,7 +152,7 @@ void TestCommandHandler::AddRemote(const vector& args) { } void TestCommandHandler::RemoveDevice(const vector& args) { - size_t dev_index = std::stoi(args[0]); + size_t dev_index = ParseIntParam(args[0]); model_.RemoveDevice(dev_index); response_string_ = "TestCommandHandler 'del' called with device at index " + @@ -171,7 +177,7 @@ void TestCommandHandler::AddPhy(const vector& args) { } void TestCommandHandler::RemovePhy(const vector& args) { - size_t phy_index = std::stoi(args[0]); + size_t phy_index = ParseIntParam(args[0]); model_.RemovePhy(phy_index); response_string_ = "TestCommandHandler 'del_phy' called with phy at index " + @@ -186,8 +192,8 @@ void TestCommandHandler::AddDeviceToPhy(const vector& args) { send_response_(response_string_); return; } - size_t dev_index = std::stoi(args[0]); - size_t phy_index = std::stoi(args[1]); + size_t dev_index = ParseIntParam(args[0]); + size_t phy_index = ParseIntParam(args[1]); model_.AddDeviceToPhy(dev_index, phy_index); response_string_ = "TestCommandHandler 'add_device_to_phy' called with device " + @@ -202,8 +208,8 @@ void TestCommandHandler::RemoveDeviceFromPhy(const vector& args) { send_response_(response_string_); return; } - size_t dev_index = std::stoi(args[0]); - size_t phy_index = std::stoi(args[1]); + size_t dev_index = ParseIntParam(args[0]); + size_t phy_index = ParseIntParam(args[1]); model_.RemoveDeviceFromPhy(dev_index, phy_index); response_string_ = "TestCommandHandler 'del_device_from_phy' called with device " + @@ -213,7 +219,7 @@ void TestCommandHandler::RemoveDeviceFromPhy(const vector& args) { void TestCommandHandler::List(const vector& args) { if (!args.empty()) { - LOG_INFO("Unused args: arg[0] = %s", args[0].c_str()); + INFO("Unused args: arg[0] = {}", args[0]); return; } send_response_(model_.List()); @@ -226,7 +232,7 @@ void TestCommandHandler::SetDeviceAddress(const vector& args) { send_response_(response_string_); return; } - size_t device_id = std::stoi(args[0]); + size_t device_id = ParseIntParam(args[0]); Address device_address{}; Address::FromString(args[1], device_address); model_.SetDeviceAddress(device_id, device_address); @@ -236,11 +242,44 @@ void TestCommandHandler::SetDeviceAddress(const vector& args) { send_response_(response_string_); } +void TestCommandHandler::SetDeviceConfiguration(const vector& args) { + if (args.size() != 2) { + response_string_ = + "TestCommandHandler 'set_device_configuration' takes two arguments"; + send_response_(response_string_); + return; + } + size_t device_id = ParseIntParam(args[0]); + rootcanal::configuration::ControllerPreset preset = + rootcanal::configuration::ControllerPreset::DEFAULT; + + if (args[1] == "default") { + preset = rootcanal::configuration::ControllerPreset::DEFAULT; + } else if (args[1] == "laird_bl654") { + preset = rootcanal::configuration::ControllerPreset::LAIRD_BL654; + } else if (args[1] == "csr_rck_pts_dongle") { + preset = rootcanal::configuration::ControllerPreset::CSR_RCK_PTS_DONGLE; + } else { + response_string_ = + "TestCommandHandler 'set_device_configuration' invalid configuration preset"; + send_response_(response_string_); + return; + } + + rootcanal::configuration::Controller configuration; + configuration.set_preset(preset); + model_.SetDeviceConfiguration(device_id, configuration); + response_string_ = "set_device_configuration " + args[0]; + response_string_ += " "; + response_string_ += args[1]; + send_response_(response_string_); +} + void TestCommandHandler::SetTimerPeriod(const vector& args) { if (args.size() != 1) { - LOG_INFO("SetTimerPeriod takes 1 argument"); + INFO("SetTimerPeriod takes 1 argument"); } - size_t period = std::stoi(args[0]); + size_t period = ParseIntParam(args[0]); if (period != 0) { response_string_ = "set timer period to "; response_string_ += args[0]; @@ -254,7 +293,7 @@ void TestCommandHandler::SetTimerPeriod(const vector& args) { void TestCommandHandler::StartTimer(const vector& args) { if (!args.empty()) { - LOG_INFO("Unused args: arg[0] = %s", args[0].c_str()); + INFO("Unused args: arg[0] = {}", args[0]); } model_.StartTimer(); response_string_ = "timer started"; @@ -263,7 +302,7 @@ void TestCommandHandler::StartTimer(const vector& args) { void TestCommandHandler::StopTimer(const vector& args) { if (!args.empty()) { - LOG_INFO("Unused args: arg[0] = %s", args[0].c_str()); + INFO("Unused args: arg[0] = {}", args[0]); } model_.StopTimer(); response_string_ = "timer stopped"; @@ -272,7 +311,7 @@ void TestCommandHandler::StopTimer(const vector& args) { void TestCommandHandler::Reset(const std::vector& args) { if (!args.empty()) { - LOG_INFO("Unused args: arg[0] = %s", args[0].c_str()); + INFO("Unused args: arg[0] = {}", args[0]); } model_.Reset(); response_string_ = "model reset"; diff --git a/tools/rootcanal/model/setup/test_command_handler.h b/tools/rootcanal/model/setup/test_command_handler.h index 75b7ba3bdd014493fc690d44ef0f548a7af21d90..4f41c3222adfea636fe04db0498a01e04ad6591a 100644 --- a/tools/rootcanal/model/setup/test_command_handler.h +++ b/tools/rootcanal/model/setup/test_command_handler.h @@ -72,6 +72,9 @@ class TestCommandHandler { // Change the device's MAC address void SetDeviceAddress(const std::vector& args); + // Change the device's configuration + void SetDeviceConfiguration(const std::vector& args); + // Timer management functions void SetTimerPeriod(const std::vector& args); diff --git a/tools/rootcanal/model/setup/test_model.cc b/tools/rootcanal/model/setup/test_model.cc index bca03afada55bbe15e8bc234fb9be1428e578f65..060b4cfb83245c056f5cc1652d39769007b460a8 100644 --- a/tools/rootcanal/model/setup/test_model.cc +++ b/tools/rootcanal/model/setup/test_model.cc @@ -24,9 +24,10 @@ #include #include // for remove_extent_t #include // for move +#include #include "include/phy.h" // for Phy, Phy::Type -#include "log.h" // for LOG_WARN, LOG_INFO +#include "log.h" #include "phy_layer.h" namespace rootcanal { @@ -73,14 +74,14 @@ void TestModel::SetTimerPeriod(std::chrono::milliseconds new_period) { } void TestModel::StartTimer() { - LOG_INFO("StartTimer()"); + INFO("StartTimer()"); timer_tick_task_ = schedule_periodic_task_(model_user_id_, std::chrono::milliseconds(0), timer_period_, [this]() { TestModel::Tick(); }); } void TestModel::StopTimer() { - LOG_INFO("StopTimer()"); + INFO("StopTimer()"); cancel_task_(timer_tick_task_); timer_tick_task_ = kInvalidTaskId; } @@ -91,34 +92,42 @@ std::unique_ptr TestModel::CreatePhyLayer(PhyLayer::Identifier id, } std::shared_ptr TestModel::CreatePhyDevice( - PhyDevice::Identifier id, std::string type, - std::shared_ptr device) { - return std::make_shared(id, std::move(type), std::move(device)); + std::string type, std::shared_ptr device) { + return std::make_shared(std::move(type), std::move(device)); } -// Add a device to the test model. -PhyDevice::Identifier TestModel::AddDevice(std::shared_ptr device) { - std::optional device_id{}; - if (reuse_device_ids_) { - // Find the first unused identifier. - // The identifier is used to generate the bluetooth address, - // and reusing the first unused identifier lets a re-connecting - // get the same identifier and address. - for (PhyDevice::Identifier id = 0; id < next_device_id_; id++) { - if (phy_devices_.count(id) == 0) { - device_id = id; +Address TestModel::GenerateBluetoothAddress(uint32_t device_id) const { + Address address({ + static_cast(device_id), + bluetooth_address_prefix_[4], + bluetooth_address_prefix_[3], + bluetooth_address_prefix_[2], + bluetooth_address_prefix_[1], + bluetooth_address_prefix_[0], + }); + + if (reuse_device_addresses_) { + // Find the first unused address. + for (uint16_t b0 = 0; b0 <= 0xff; b0++) { + address.address[0] = b0; + bool used = std::any_of(phy_devices_.begin(), phy_devices_.end(), + [address](auto& device) { + return device.second->GetAddress() == address; + }); + if (!used) { break; } } } - if (!device_id.has_value()) { - device_id = next_device_id_++; - } + return address; +} +// Add a device to the test model. +PhyDevice::Identifier TestModel::AddDevice(std::shared_ptr device) { std::string device_type = device->GetTypeString(); std::shared_ptr phy_device = - CreatePhyDevice(device_id.value(), device_type, std::move(device)); + CreatePhyDevice(device_type, std::move(device)); phy_devices_[phy_device->id] = phy_device; return phy_device->id; } @@ -166,8 +175,8 @@ void TestModel::RemoveDeviceFromPhy(PhyDevice::Identifier device_id, void TestModel::AddLinkLayerConnection(std::shared_ptr device, Phy::Type type) { - LOG_INFO("Adding a new link layer connection of type: %s", - type == Phy::Type::BR_EDR ? "BR_EDR" : "LOW_ENERGY"); + INFO(device->id_, "Adding a new link layer connection of type: {}", + type == Phy::Type::BR_EDR ? "BR_EDR" : "LOW_ENERGY"); PhyDevice::Identifier device_id = AddDevice(device); @@ -195,26 +204,18 @@ void TestModel::AddRemote(const std::string& server, int port, Phy::Type type) { } PhyDevice::Identifier TestModel::AddHciConnection( - std::shared_ptr device) { - PhyDevice::Identifier device_id = - AddDevice(std::static_pointer_cast(device)); - auto bluetooth_address = Address{{ - uint8_t(device_id), - bluetooth_address_prefix_[4], - bluetooth_address_prefix_[3], - bluetooth_address_prefix_[2], - bluetooth_address_prefix_[1], - bluetooth_address_prefix_[0], - }}; - device->SetAddress(bluetooth_address); + std::shared_ptr device, std::optional
    address) { + // clients can specify BD_ADDR or have it set based on device_id. + device->SetAddress(address.value_or(GenerateBluetoothAddress(device->id_))); + AddDevice(std::static_pointer_cast(device)); - LOG_INFO("Initialized device with address %s", - bluetooth_address.ToString().c_str()); + INFO(device->id_, "Initialized device with address {}", device->GetAddress()); for (auto& [_, phy_layer] : phy_layers_) { - phy_layer->Register(phy_devices_[device_id]); + phy_layer->Register(phy_devices_[device->id_]); } + PhyDevice::Identifier device_id = device->id_; AsyncUserId user_id = get_user_id_(); device->RegisterCloseCallback([this, device_id, user_id] { schedule_task_(user_id, std::chrono::milliseconds(0), @@ -222,7 +223,7 @@ PhyDevice::Identifier TestModel::AddHciConnection( OnConnectionClosed(device_id, user_id); }); }); - return device_id; + return device->id_; } void TestModel::OnConnectionClosed(PhyDevice::Identifier device_id, @@ -240,6 +241,19 @@ void TestModel::SetDeviceAddress(PhyDevice::Identifier device_id, } } +void TestModel::SetDeviceConfiguration(PhyDevice::Identifier device_id, + rootcanal::configuration::Controller const& configuration) { + if (phy_devices_.find(device_id) != phy_devices_.end()) { + if (phy_devices_[device_id]->GetDevice()->GetTypeString() == "hci_device") { + std::shared_ptr device = std::static_pointer_cast( + phy_devices_[device_id]->GetDevice()); + device->SetProperties(ControllerProperties(configuration)); + } else { + ERROR(device_id, "failed to update the configuration, device is not a controller device"); + } + } +} + const std::string& TestModel::List() { list_string_.clear(); list_string_ += " Devices: \r\n"; @@ -268,12 +282,11 @@ void TestModel::Tick() { void TestModel::Reset() { StopTimer(); schedule_task_(model_user_id_, std::chrono::milliseconds(0), [this]() { - LOG_INFO("Running Reset task"); + INFO("Running Reset task"); for (auto& [_, phy_layer] : phy_layers_) { phy_layer->UnregisterAll(); } phy_devices_.clear(); - next_device_id_ = 0; }); } diff --git a/tools/rootcanal/model/setup/test_model.h b/tools/rootcanal/model/setup/test_model.h index 7ef94c58194d8f21712272a111a422bb8e5d5f2f..b9871a6c6200a38eb95b6a75495d920530484553 100644 --- a/tools/rootcanal/model/setup/test_model.h +++ b/tools/rootcanal/model/setup/test_model.h @@ -23,12 +23,14 @@ #include // for shared_ptr #include // for string #include // for vector +#include #include "hci/address.h" // for Address #include "model/devices/hci_device.h" // for HciDevice #include "model/setup/async_manager.h" // for AsyncUserId, AsyncTaskId #include "phy.h" // for Phy, Phy::Type #include "phy_layer.h" +#include "rootcanal/configuration.pb.h" namespace rootcanal { class Device; @@ -56,8 +58,8 @@ class TestModel { TestModel(TestModel& model) = delete; TestModel& operator=(const TestModel& model) = delete; - void SetReuseDeviceIds(bool reuse_device_ids) { - reuse_device_ids_ = reuse_device_ids; + void SetReuseDeviceAddresses(bool reuse_device_addresses) { + reuse_device_addresses_ = reuse_device_addresses; } // Allow derived classes to use custom phy layer. @@ -66,8 +68,7 @@ class TestModel { // Allow derived classes to use custom phy devices. virtual std::shared_ptr CreatePhyDevice( - PhyDevice::Identifier id, std::string type, - std::shared_ptr device); + std::string type, std::shared_ptr device); // Test model commands @@ -85,8 +86,8 @@ class TestModel { // Handle incoming remote connections void AddLinkLayerConnection(std::shared_ptr dev, Phy::Type phy_type); // Add an HCI device, return its index - PhyDevice::Identifier AddHciConnection(std::shared_ptr dev); - + PhyDevice::Identifier AddHciConnection(std::shared_ptr dev, + std::optional
    address = {}); // Handle closed remote connections (both hci & link layer) void OnConnectionClosed(PhyDevice::Identifier device_id, AsyncUserId user_id); @@ -97,6 +98,9 @@ class TestModel { void SetDeviceAddress(PhyDevice::Identifier device_id, Address device_address); + void SetDeviceConfiguration(PhyDevice::Identifier device_id, + rootcanal::configuration::Controller const& configuration); + // Let devices know about the passage of time void Tick(); void StartTimer(); @@ -110,13 +114,14 @@ class TestModel { void Reset(); private: + Address GenerateBluetoothAddress(uint32_t device_id) const; + std::map> phy_layers_; std::map> phy_devices_; std::string list_string_; // Generator for device identifiers. - PhyDevice::Identifier next_device_id_{0}; - bool reuse_device_ids_{true}; + bool reuse_device_addresses_{true}; // Prefix used to generate public device addresses for hosts // connecting over TCP. diff --git a/tools/rootcanal/net/posix/posix_async_socket.cc b/tools/rootcanal/net/posix/posix_async_socket.cc index 0fe8f65c8f6d9b7ffef863e45f825520cd5c578c..d6c982e70a1a06fea69de996e8dfdb5c6612b65e 100644 --- a/tools/rootcanal/net/posix/posix_async_socket.cc +++ b/tools/rootcanal/net/posix/posix_async_socket.cc @@ -21,7 +21,7 @@ #include // for __base -#include "log.h" // for LOG_INFO +#include "log.h" #include "model/setup/async_manager.h" // for AsyncManager #ifdef _WIN32 @@ -29,10 +29,10 @@ #endif /* set for very verbose debugging */ -#ifndef DEBUG +#ifdef NDEBUG #define DD(...) (void)0 #else -#define DD(...) LOG_INFO(__VA_ARGS__) +#define DD(...) INFO(__VA_ARGS__) #endif namespace android { @@ -76,9 +76,9 @@ ssize_t PosixAsyncSocket::Recv(uint8_t* buffer, uint64_t bufferSize) { REPEAT_UNTIL_NO_INTR(res = read(fd_, buffer, bufferSize)); if (res < 0) { - DD("Recv < 0: %s (%d)", strerror(errno), fd_); + DD("Recv < 0: {} ({})", strerror(errno), fd_); } - DD("%zd bytes (%d)", res, fd_); + DD("{} bytes ({})", res, fd_); return res; }; @@ -97,7 +97,7 @@ ssize_t PosixAsyncSocket::Send(const uint8_t* buffer, uint64_t bufferSize) { REPEAT_UNTIL_NO_INTR(res = send(fd_, buffer, bufferSize, sendFlags)); - DD("%zd bytes (%d)", res, fd_); + DD("{} bytes ({})", res, fd_); return res; } @@ -107,7 +107,7 @@ bool PosixAsyncSocket::Connected() { } char buf; if (recv(fd_, &buf, 1, MSG_PEEK | MSG_DONTWAIT) != 1) { - DD("Recv not 1, could be connected: %s (%d)", strerror(errno), fd_); + DD("Recv not 1, could be connected: {} ({})", strerror(errno), fd_); return errno == EAGAIN || errno == EWOULDBLOCK; } @@ -133,9 +133,9 @@ void PosixAsyncSocket::Close() { error_code = ::close(fd_); if (error_code == -1) { - LOG_INFO("Failed to close: %s (%d)", strerror(errno), fd_); + INFO("Failed to close: {} ({})", strerror(errno), fd_); } - LOG_INFO("(%d)", fd_); + INFO("({})", fd_); fd_ = -1; } diff --git a/tools/rootcanal/net/posix/posix_async_socket_connector.cc b/tools/rootcanal/net/posix/posix_async_socket_connector.cc index dbb58b7874a83defa8412e88b0860917dc060b4c..ed02bc130d94816eed5670473234ab9fe3561393 100644 --- a/tools/rootcanal/net/posix/posix_async_socket_connector.cc +++ b/tools/rootcanal/net/posix/posix_async_socket_connector.cc @@ -24,7 +24,7 @@ #include // for remove_extent_t -#include "log.h" // for LOG_INFO +#include "log.h" #include "net/posix/posix_async_socket.h" // for PosixAsyncSocket namespace android { @@ -37,22 +37,20 @@ std::shared_ptr PosixAsyncSocketConnector::ConnectToRemoteServer( const std::string& server, int port, const std::chrono::milliseconds timeout) { - LOG_INFO("Connecting to %s:%d in %d ms", server.c_str(), port, - (int)timeout.count()); + INFO("Connecting to {}:{} in {} ms", server, port, timeout.count()); int socket_fd = socket(AF_INET, SOCK_STREAM, 0); std::shared_ptr pas = std::make_shared(socket_fd, am_); if (socket_fd < 1) { - LOG_INFO("socket() call failed: %s", strerror(errno)); + INFO("socket() call failed: {}", strerror(errno)); return pas; } struct hostent* host; host = gethostbyname(server.c_str()); if (host == NULL) { - LOG_INFO("gethostbyname() failed for %s: %s", server.c_str(), - strerror(errno)); + INFO("gethostbyname() failed for {}: {}", server, strerror(errno)); pas->Close(); return pas; } @@ -68,8 +66,8 @@ PosixAsyncSocketConnector::ConnectToRemoteServer( if (result != 0 && errno != EWOULDBLOCK && errno != EAGAIN && errno != EINPROGRESS) { - LOG_INFO("Failed to connect to %s:%d, error: %s", server.c_str(), port, - strerror(errno)); + INFO("Failed to connect to {}:{}, error: {}", server, port, + strerror(errno)); pas->Close(); return pas; } @@ -87,8 +85,8 @@ PosixAsyncSocketConnector::ConnectToRemoteServer( REPEAT_UNTIL_NO_INTR(numFdsReady = ::poll(fds, 1, timeout.count())); if (numFdsReady <= 0) { - LOG_INFO("Failed to connect to %s:%d, error: %s", server.c_str(), port, - strerror(errno)); + INFO("Failed to connect to {}:{}, error: {}", server, port, + strerror(errno)); pas->Close(); return pas; } @@ -99,8 +97,8 @@ PosixAsyncSocketConnector::ConnectToRemoteServer( socklen_t sslen = sizeof(ss); if (getpeername(socket_fd, (struct sockaddr*)&ss, &sslen) < 0) { - LOG_INFO("Failed to connect to %s:%d, error: %s", server.c_str(), port, - strerror(errno)); + INFO("Failed to connect to {}:{}, error: {}", server, port, + strerror(errno)); pas->Close(); return pas; } @@ -112,13 +110,12 @@ PosixAsyncSocketConnector::ConnectToRemoteServer( err) { // Either getsockopt failed or there was an error associated // with the socket. The connection did not succeed. - LOG_INFO("Failed to connect to %s:%d, error: %s", server.c_str(), port, - strerror(err)); + INFO("Failed to connect to {}:{}, error: {}", server, port, strerror(err)); pas->Close(); return pas; } - LOG_INFO("Connected to %s:%d (%d)", server.c_str(), port, socket_fd); + INFO("Connected to {}:{} ({})", server, port, socket_fd); return pas; } diff --git a/tools/rootcanal/net/posix/posix_async_socket_server.cc b/tools/rootcanal/net/posix/posix_async_socket_server.cc index 1b54dc48c41b4a93447676ee52119cfb7b3f71c7..185f17dd2de47efc4957e774c8477c995cd3f6ae 100644 --- a/tools/rootcanal/net/posix/posix_async_socket_server.cc +++ b/tools/rootcanal/net/posix/posix_async_socket_server.cc @@ -23,7 +23,7 @@ #include // for __base, function #include // for remove_extent_t -#include "log.h" // for LOG_INFO, LOG_ERROR +#include "log.h" #include "net/posix/posix_async_socket.h" // for PosixAsyncSocket, AsyncMan... namespace android { @@ -41,14 +41,14 @@ PosixAsyncSocketServer::PosixAsyncSocketServer(int port, AsyncManager* am) } while (listen_fd == -1 && errno == EAGAIN); if (listen_fd < 0) { - LOG_INFO("Error creating socket for test channel."); + INFO("Error creating socket for test channel."); return; } int enable = 1; if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) { - LOG_ERROR("setsockopt(SO_REUSEADDR) failed: %s", strerror(errno)); + ERROR("setsockopt(SO_REUSEADDR) failed: {}", strerror(errno)); } listen_address.sin_family = AF_INET; @@ -57,14 +57,14 @@ PosixAsyncSocketServer::PosixAsyncSocketServer(int port, AsyncManager* am) if (bind(listen_fd, reinterpret_cast(&listen_address), sockaddr_in_size) < 0) { - LOG_INFO("Error binding test channel listener socket to port: %d, %s", port, - strerror(errno)); + INFO("Error binding test channel listener socket to port: {}, {}", port, + strerror(errno)); close(listen_fd); return; } if (listen(listen_fd, 1) < 0) { - LOG_INFO("Error listening for test channel: %s", strerror(errno)); + INFO("Error listening for test channel: {}", strerror(errno)); close(listen_fd); return; } @@ -72,11 +72,11 @@ PosixAsyncSocketServer::PosixAsyncSocketServer(int port, AsyncManager* am) struct sockaddr_in sin; socklen_t slen = sizeof(sin); if (getsockname(listen_fd, (struct sockaddr*)&sin, &slen) == -1) { - LOG_INFO("Error retrieving actual port: %s", strerror(errno)); + INFO("Error retrieving actual port: {}", strerror(errno)); } else { port_ = ntohs(sin.sin_port); } - LOG_INFO("Listening on: %d (%d)", port_, listen_fd); + INFO("Listening on: {} ({})", port_, listen_fd); server_socket_ = std::make_shared(listen_fd, am_); } @@ -105,12 +105,12 @@ void PosixAsyncSocketServer::AcceptSocket() { REPEAT_UNTIL_NO_INTR(accept_fd = accept(server_socket_->fd(), NULL, NULL)); if (accept_fd < 0) { - LOG_INFO("Error accepting test channel connection errno=%d (%s).", errno, - strerror(errno)); + INFO("Error accepting test channel connection errno={} ({}).", errno, + strerror(errno)); return; } - LOG_INFO("accept_fd = %d.", accept_fd); + INFO("accept_fd = {}.", accept_fd); StopListening(); callback_(std::make_shared(accept_fd, am_), this); } diff --git a/tools/rootcanal/packets/hci/hci_packets.pdl b/tools/rootcanal/packets/hci_packets.pdl similarity index 91% rename from tools/rootcanal/packets/hci/hci_packets.pdl rename to tools/rootcanal/packets/hci_packets.pdl index 2eb4e5ea5a99fd9b3ac80c4efa89d15c014152af..a2610f9c7a73c8c59c0d87ba7cf33c746e294cd6 100644 --- a/tools/rootcanal/packets/hci/hci_packets.pdl +++ b/tools/rootcanal/packets/hci_packets.pdl @@ -1,73 +1,12 @@ little_endian_packets custom_field Address : 48 "hci/" -custom_field ClassOfDevice : 24 "hci/" enum Enable : 8 { DISABLED = 0x00, ENABLED = 0x01, } -// https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile -enum GapDataType : 8 { - INVALID = 0x00, - FLAGS = 0x01, - INCOMPLETE_LIST_16_BIT_UUIDS = 0x02, - COMPLETE_LIST_16_BIT_UUIDS = 0x03, - INCOMPLETE_LIST_32_BIT_UUIDS = 0x04, - COMPLETE_LIST_32_BIT_UUIDS = 0x05, - INCOMPLETE_LIST_128_BIT_UUIDS = 0x06, - COMPLETE_LIST_128_BIT_UUIDS = 0x07, - SHORTENED_LOCAL_NAME = 0x08, - COMPLETE_LOCAL_NAME = 0x09, - TX_POWER_LEVEL = 0x0A, - CLASS_OF_DEVICE = 0x0D, - SIMPLE_PAIRING_HASH_C = 0x0E, - SIMPLE_PAIRING_RANDOMIZER_R = 0x0F, - DEVICE_ID = 0x10, - SECURITY_MANAGER_OOB_FLAGS = 0x11, - SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, - LIST_16BIT_SERVICE_SOLICITATION_UUIDS = 0x14, - LIST_128BIT_SERVICE_SOLICITATION_UUIDS = 0x15, - SERVICE_DATA_16_BIT_UUIDS = 0x16, - PUBLIC_TARGET_ADDRESS = 0x17, - RANDOM_TARGET_ADDRESS = 0x18, - APPEARANCE = 0x19, - ADVERTISING_INTERVAL = 0x1A, - LE_BLUETOOTH_DEVICE_ADDRESS = 0x1B, - LE_ROLE = 0x1C, - SIMPLE_PAIRING_HASH_C_256 = 0x1D, - SIMPLE_PAIRING_RANDOMIZER_R_256 = 0x1E, - LIST_32BIT_SERVICE_SOLICITATION_UUIDS = 0x1F, - SERVICE_DATA_32_BIT_UUIDS = 0x20, - SERVICE_DATA_128_BIT_UUIDS = 0x21, - LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE = 0x22, - LE_SECURE_CONNECTIONS_RANDOM_VALUE = 0x23, - URI = 0x24, - INDOOR_POSITIONING = 0x25, - TRANSPORT_DISCOVERY_DATA = 0x26, - LE_SUPPORTED_FEATURES = 0x27, - CHANNEL_MAP_UPDATE_INDICATION = 0x28, - MESH_PB_ADV = 0x29, - MESH_MESSAGE = 0x2A, - MESH_BEACON = 0x2B, - BIG_INFO = 0x2C, - BROADCAST_CODE = 0x2D, - THREE_D_INFORMATION_DATA = 0x3D, - MANUFACTURER_SPECIFIC_DATA = 0xFF, -} - -struct LengthAndData { - _size_(data) : 8, - data: 8[], -} - -struct GapData { - _size_(data) : 8, // Including one byte for data_type - data_type : GapDataType, - data : 8[+1], -} - // HCI ACL Packets enum PacketBoundaryFlag : 2 { @@ -432,14 +371,11 @@ enum OpCode : 16 { // MSFT_OPCODE_xxxx below is needed for the tests. MSFT_OPCODE_INTEL = 0xFC1E, LE_GET_VENDOR_CAPABILITIES = 0xFD53, - LE_MULTI_ADVT = 0xFD54, LE_BATCH_SCAN = 0xFD56, - LE_ADV_FILTER = 0xFD57, - LE_ENERGY_INFO = 0xFD59, - LE_EXTENDED_SCAN_PARAMS = 0xFD5A, - CONTROLLER_DEBUG_INFO = 0xFD5B, - CONTROLLER_A2DP_OPCODE = 0xFD5D, - CONTROLLER_BQR = 0xFD5E, + LE_APCF = 0xFD57, + LE_GET_CONTROLLER_ACTIVITY_ENERGY_INFO = 0xFD59, + LE_EX_SET_SCAN_PARAMETERS = 0xFD5A, + GET_CONTROLLER_DEBUG_INFO = 0xFD5B, // MSFT_OPCODE_xxxx below are needed for the tests. MSFT_OPCODE_MEDIATEK = 0xFD30, MSFT_OPCODE_QUALCOMM = 0xFD70, @@ -716,7 +652,7 @@ enum OpCodeIndex : 16 { LE_READ_BUFFER_SIZE_V2 = 415, LE_READ_ISO_TX_SYNC = 416, LE_SET_CIG_PARAMETERS = 417, - LE_SET_CIG_PARAMETERS_TEST = 418, + LE_SET_CIG_PARAMETERS_TEST = 420, LE_CREATE_CIS = 421, LE_REMOVE_CIG = 422, LE_ACCEPT_CIS_REQUEST = 423, @@ -758,10 +694,6 @@ packet Command { _payload_, } -// Packets for interfaces - -packet VendorCommand : Command { _payload_, } - // HCI Event Packets enum EventCode : 8 { @@ -820,14 +752,7 @@ enum EventCode : 8 { VENDOR_SPECIFIC = 0xFF, } -packet Event { - event_code : EventCode, - _size_(_payload_) : 8, - _payload_, -} - -// LE Events - +// LE events enum SubeventCode : 8 { CONNECTION_COMPLETE = 0x01, ADVERTISING_REPORT = 0x02, @@ -868,11 +793,17 @@ enum SubeventCode : 8 { // Vendor specific events enum VseSubeventCode : 8 { - BLE_THRESHOLD = 0x54, - BLE_STCHANGE = 0x55, - BLE_TRACKING = 0x56, - DEBUG_INFO = 0x57, - BQR_EVENT = 0x58, + STORAGE_THRESHOLD_BREACH = 0x54, + LE_MULTI_ADVERTISING_STATE_CHANGE = 0x55, + LE_ADVERTISEMENT_TRACKING = 0x56, + CONTROLLER_DEBUG_INFO = 0x57, + BLUETOOTH_QUALITY_REPORT = 0x58, +} + +packet Event { + event_code : EventCode, + _size_(_payload_) : 8, + _payload_, } // Common definitions for commands and events @@ -947,6 +878,11 @@ packet CommandStatus : Event (event_code = COMMAND_STATUS) { _payload_, } +packet VendorSpecificEvent : Event (event_code = VENDOR_SPECIFIC) { + subevent_code : VseSubeventCode, + _payload_, +} + // Credits packet NoCommandComplete : CommandComplete (command_op_code = NONE) { } @@ -1805,8 +1741,8 @@ packet SetEventFilterInquiryResultAllDevices : SetEventFilterInquiryResult (filt } packet SetEventFilterInquiryResultClassOfDevice : SetEventFilterInquiryResult (filter_condition_type = CLASS_OF_DEVICE) { - class_of_device : ClassOfDevice, - class_of_device_mask : ClassOfDevice, + class_of_device : 24, + class_of_device_mask : 24, } packet SetEventFilterInquiryResultAddress : SetEventFilterInquiryResult (filter_condition_type = ADDRESS) { @@ -1829,8 +1765,8 @@ packet SetEventFilterConnectionSetupAllDevices : SetEventFilterConnectionSetup ( } packet SetEventFilterConnectionSetupClassOfDevice : SetEventFilterConnectionSetup (filter_condition_type = CLASS_OF_DEVICE) { - class_of_device : ClassOfDevice, - class_of_device_mask : ClassOfDevice, + class_of_device : 24, + class_of_device_mask : 24, auto_accept_flag : AutoAcceptFlag, } @@ -2082,11 +2018,11 @@ packet ReadClassOfDevice : Command (op_code = READ_CLASS_OF_DEVICE) { packet ReadClassOfDeviceComplete : CommandComplete (command_op_code = READ_CLASS_OF_DEVICE) { status : ErrorCode, - class_of_device : ClassOfDevice, + class_of_device : 24, } packet WriteClassOfDevice : Command (op_code = WRITE_CLASS_OF_DEVICE) { - class_of_device : ClassOfDevice, + class_of_device : 24, } packet WriteClassOfDeviceComplete : CommandComplete (command_op_code = WRITE_CLASS_OF_DEVICE) { @@ -2183,7 +2119,6 @@ packet ReadTransmitPowerLevel : Command (op_code = READ_TRANSMIT_POWER_LEVEL) { connection_handle : 12, _reserved_ : 4, transmit_power_level_type : TransmitPowerLevelType, - } packet ReadTransmitPowerLevelComplete : CommandComplete (command_op_code = READ_TRANSMIT_POWER_LEVEL) { @@ -2426,13 +2361,12 @@ packet ReadExtendedInquiryResponse : Command (op_code = READ_EXTENDED_INQUIRY_RE packet ReadExtendedInquiryResponseComplete : CommandComplete (command_op_code = READ_EXTENDED_INQUIRY_RESPONSE) { status : ErrorCode, fec_required : FecRequired, - extended_inquiry_response : GapData[], + extended_inquiry_response : 8[240], } packet WriteExtendedInquiryResponse : Command (op_code = WRITE_EXTENDED_INQUIRY_RESPONSE) { fec_required : FecRequired, - extended_inquiry_response : GapData[], - _padding_[240], // Zero padding GapData[] to be 240 octets + extended_inquiry_response : 8[240], } packet WriteExtendedInquiryResponseComplete : CommandComplete (command_op_code = WRITE_EXTENDED_INQUIRY_RESPONSE) { @@ -2522,6 +2456,21 @@ packet SetEventMaskPage2Complete : CommandComplete (command_op_code = SET_EVENT_ status: ErrorCode, } +packet ReadEnhancedTransmitPowerLevel : Command (op_code = READ_ENHANCED_TRANSMIT_POWER_LEVEL) { + connection_handle : 12, + _reserved_ : 4, + transmit_power_level_type : TransmitPowerLevelType, +} + +packet ReadEnhancedTransmitPowerLevelComplete : CommandComplete (command_op_code = READ_ENHANCED_TRANSMIT_POWER_LEVEL) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + tx_power_level_gfsk : 8, + tx_power_level_dqpsk : 8, + tx_power_level_8dpsk : 8, +} + packet ReadLeHostSupport : Command (op_code = READ_LE_HOST_SUPPORT) { } @@ -2638,6 +2587,7 @@ enum HciVersion : 8 { V_5_1 = 0x0a, V_5_2 = 0x0b, V_5_3 = 0x0c, + V_5_4 = 0x0d, } enum LmpVersion : 8 { @@ -2654,6 +2604,7 @@ enum LmpVersion : 8 { V_5_1 = 0x0a, V_5_2 = 0x0b, V_5_3 = 0x0c, + V_5_4 = 0x0d, } struct LocalVersionInformation { @@ -3245,12 +3196,6 @@ packet LeReadAdvertisingPhysicalChannelTxPowerComplete : CommandComplete (comman } packet LeSetAdvertisingData : Command (op_code = LE_SET_ADVERTISING_DATA) { - _size_(advertising_data) : 8, - advertising_data : GapData[], - _padding_[31], // Zero padding to 31 bytes of advertising_data -} - -packet LeSetAdvertisingDataRaw : Command (op_code = LE_SET_ADVERTISING_DATA) { _size_(advertising_data) : 8, advertising_data : 8[], _padding_[31], // Zero padding to 31 bytes of advertising_data @@ -3261,12 +3206,6 @@ packet LeSetAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_ } packet LeSetScanResponseData : Command (op_code = LE_SET_SCAN_RESPONSE_DATA) { - _size_(advertising_data) : 8, - advertising_data : GapData[], - _padding_[31], // Zero padding to 31 bytes of advertising_data -} - -packet LeSetScanResponseDataRaw : Command (op_code = LE_SET_SCAN_RESPONSE_DATA) { _size_(advertising_data) : 8, advertising_data : 8[], _padding_[31], // Zero padding to 31 bytes of advertising_data @@ -3337,12 +3276,12 @@ packet LeCreateConnection : Command (op_code = LE_CREATE_CONNECTION) { peer_address_type : AddressType, peer_address : Address, own_address_type : OwnAddressType, - conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_latency : 16, // 0x0006-0x01F3 + connection_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) + connection_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) + max_latency : 16, // 0x0006-0x01F3 supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s) - minimum_ce_length : 16, // 0.625ms - maximum_ce_length : 16, // 0.625ms + min_ce_length : 16, // 0.625ms + max_ce_length : 16, // 0.625ms } packet LeCreateConnectionStatus : CommandStatus (command_op_code = LE_CREATE_CONNECTION) { @@ -3405,12 +3344,12 @@ packet LeRemoveDeviceFromFilterAcceptListComplete : CommandComplete (command_op_ packet LeConnectionUpdate : Command (op_code = LE_CONNECTION_UPDATE) { connection_handle : 12, _reserved_ : 4, - conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_latency : 16, // 0x0006-0x01F3 + connection_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) + connection_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) + max_latency : 16, // 0x0006-0x01F3 supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s) - minimum_ce_length : 16, // 0.625ms - maximum_ce_length : 16, // 0.625ms + min_ce_length : 16, // 0.625ms + max_ce_length : 16, // 0.625ms } packet LeConnectionUpdateStatus : CommandStatus (command_op_code = LE_CONNECTION_UPDATE) { @@ -3897,23 +3836,13 @@ packet LeSetExtendedAdvertisingData : Command (op_code = LE_SET_EXTENDED_ADVERTI fragment_preference : FragmentPreference, _reserved_ : 7, _size_(advertising_data) : 8, - advertising_data : GapData[], + advertising_data : 8[], } test LeSetExtendedAdvertisingData { "\x37\x20\x12\x00\x03\x01\x0e\x02\x01\x02\x0a\x09\x50\x69\x78\x65\x6c\x20\x33\x20\x58", } -packet LeSetExtendedAdvertisingDataRaw : Command (op_code = LE_SET_EXTENDED_ADVERTISING_DATA) { - advertising_handle : 8, - operation : Operation, - _reserved_ : 5, - fragment_preference : FragmentPreference, - _reserved_ : 7, - _size_(advertising_data) : 8, - advertising_data : 8[], -} - packet LeSetExtendedAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_ADVERTISING_DATA) { status : ErrorCode, } @@ -3923,16 +3852,6 @@ test LeSetExtendedAdvertisingDataComplete { } packet LeSetExtendedScanResponseData : Command (op_code = LE_SET_EXTENDED_SCAN_RESPONSE_DATA) { - advertising_handle : 8, - operation : Operation, - _reserved_ : 5, - fragment_preference : FragmentPreference, - _reserved_ : 7, - _size_(scan_response_data) : 8, - scan_response_data : GapData[], -} - -packet LeSetExtendedScanResponseDataRaw : Command (op_code = LE_SET_EXTENDED_SCAN_RESPONSE_DATA) { advertising_handle : 8, operation : Operation, _reserved_ : 5, @@ -4044,14 +3963,6 @@ packet LeSetPeriodicAdvertisingParametersComplete : CommandComplete (command_op_ } packet LeSetPeriodicAdvertisingData : Command (op_code = LE_SET_PERIODIC_ADVERTISING_DATA) { - advertising_handle : 8, - operation : Operation, - _reserved_ : 5, - _size_(advertising_data) : 8, - advertising_data : GapData[], -} - -packet LeSetPeriodicAdvertisingDataRaw : Command (op_code = LE_SET_PERIODIC_ADVERTISING_DATA) { advertising_handle : 8, operation : Operation, _reserved_ : 5, @@ -4074,7 +3985,7 @@ packet LeSetPeriodicAdvertisingEnableComplete : CommandComplete (command_op_code status : ErrorCode, } -struct PhyScanParameters { +struct ScanningPhyParameters { le_scan_type : LeScanType, le_scan_interval : 16, // 0x0004-0xFFFF Default 0x10 (10ms) le_scan_window : 16, // 0x004-0xFFFF Default 0x10 (10ms) @@ -4084,7 +3995,7 @@ packet LeSetExtendedScanParameters : Command (op_code = LE_SET_EXTENDED_SCAN_PAR own_address_type : OwnAddressType, scanning_filter_policy : LeScanningFilterPolicy, scanning_phys : 8, - parameters : PhyScanParameters[], + scanning_phy_parameters : ScanningPhyParameters[], } test LeSetExtendedScanParameters { @@ -4126,12 +4037,12 @@ test LeSetExtendedScanEnableComplete { "\x0e\x04\x01\x42\x20\x00", } -struct LeCreateConnPhyScanParameters { +struct InitiatingPhyParameters { scan_interval : 16, // 0x0004-0xFFFF scan_window : 16, // < = LeScanInterval - conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) - conn_latency : 16, // 0x0006-0x01F3 + connection_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s) + connection_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s) + max_latency : 16, // 0x0006-0x01F3 supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s) min_ce_length : 16, // 0.625ms max_ce_length : 16, // 0.625ms @@ -4140,10 +4051,10 @@ struct LeCreateConnPhyScanParameters { packet LeExtendedCreateConnection : Command (op_code = LE_EXTENDED_CREATE_CONNECTION) { initiator_filter_policy : InitiatorFilterPolicy, own_address_type : OwnAddressType, - peer_address_type : AddressType, + peer_address_type : PeerAddressType, peer_address : Address, initiating_phys : 8, - phy_scan_parameters : LeCreateConnPhyScanParameters[], + initiating_phy_parameters : InitiatingPhyParameters[], } test LeExtendedCreateConnection { @@ -4405,17 +4316,17 @@ packet LeReadIsoTxSyncComplete : CommandComplete (command_op_code = LE_READ_ISO_ struct CisParametersConfig { cis_id : 8, - max_sdu_m_to_s : 12, + max_sdu_c_to_p : 12, _reserved_ : 4, - max_sdu_s_to_m : 12, + max_sdu_p_to_c : 12, _reserved_ : 4, - phy_m_to_s : 3, + phy_c_to_p : 3, _reserved_ : 5, - phy_s_to_m : 3, + phy_p_to_c : 3, _reserved_ : 5, - rtn_m_to_s : 4, + rtn_c_to_p : 4, _reserved_ : 4, - rtn_s_to_m : 4, + rtn_p_to_c : 4, _reserved_ : 4, } @@ -4437,13 +4348,13 @@ enum ClockAccuracy : 8 { packet LeSetCigParameters : Command (op_code = LE_SET_CIG_PARAMETERS) { cig_id : 8, - sdu_interval_m_to_s : 24, - sdu_interval_s_to_m : 24, - peripherals_clock_accuracy : ClockAccuracy, + sdu_interval_c_to_p : 24, + sdu_interval_p_to_c : 24, + worst_case_sca: ClockAccuracy, packing : Packing, framing : Enable, - max_transport_latency_m_to_s : 16, - max_transport_latency_s_to_m : 16, + max_transport_latency_c_to_p : 16, + max_transport_latency_p_to_c : 16, _count_(cis_config) : 8, cis_config : CisParametersConfig[], } @@ -4458,24 +4369,24 @@ packet LeSetCigParametersComplete : CommandComplete (command_op_code = LE_SET_CI struct LeCisParametersTestConfig { cis_id : 8, nse : 8, - max_sdu_m_to_s : 16, - max_sdu_s_to_m : 16, - max_pdu_m_to_s : 16, - max_pdu_s_to_m : 16, - phy_m_to_s : 8, - phy_s_to_m : 8, - bn_m_to_s : 8, - bn_s_to_m : 8, + max_sdu_c_to_p : 16, + max_sdu_p_to_c : 16, + max_pdu_c_to_p : 16, + max_pdu_p_to_c : 16, + phy_c_to_p : 8, + phy_p_to_c : 8, + bn_c_to_p : 8, + bn_p_to_c : 8, } packet LeSetCigParametersTest : Command (op_code = LE_SET_CIG_PARAMETERS_TEST) { cig_id : 8, - sdu_interval_m_to_s : 24, - sdu_interval_s_to_m : 24, - ft_m_to_s : 8, - ft_s_to_m : 8, + sdu_interval_c_to_p : 24, + sdu_interval_p_to_c : 24, + ft_c_to_p : 8, + ft_p_to_c : 8, iso_interval : 16, - peripherals_clock_accuracy : ClockAccuracy, + worst_case_sca: ClockAccuracy, packing : Packing, framing : Enable, _count_(cis_config) : 8, @@ -4489,7 +4400,7 @@ packet LeSetCigParametersTestComplete : CommandComplete (command_op_code = LE_SE connection_handle : 16[], } -struct CreateCisConfig { +struct LeCreateCisConfig { cis_connection_handle : 12, _reserved_ : 4, acl_connection_handle : 12, @@ -4498,7 +4409,7 @@ struct CreateCisConfig { packet LeCreateCis : Command (op_code = LE_CREATE_CIS) { _count_(cis_config) : 8, - cis_config : CreateCisConfig[], + cis_config : LeCreateCisConfig[], } packet LeCreateCisStatus : CommandStatus (command_op_code = LE_CREATE_CIS) { @@ -4776,1596 +4687,1426 @@ packet LeSubrateRequest : Command (op_code = LE_SUBRATE_REQUEST) { packet LeSubrateRequestStatus : CommandStatus (command_op_code = LE_SUBRATE_REQUEST) { } - // VENDOR_SPECIFIC -packet LeGetVendorCapabilities : VendorCommand (op_code = LE_GET_VENDOR_CAPABILITIES) { -} +// HCI Event Packets -test LeGetVendorCapabilities { - "\x53\xfd\x00", +packet InquiryComplete : Event (event_code = INQUIRY_COMPLETE) { + status : ErrorCode, } -struct BaseVendorCapabilities { - max_advt_instances: 8, - offloaded_resolution_of_private_address : 8, - total_scan_results_storage: 16, - max_irk_list_sz: 8, - filtering_support: 8, - max_filter: 8, - activity_energy_info_support: 8, +struct InquiryResponse { + bd_addr : Address, + page_scan_repetition_mode : PageScanRepetitionMode, + _reserved_ : 8, + _reserved_ : 8, + class_of_device : 24, + clock_offset : 15, + _reserved_ : 1, } -packet LeGetVendorCapabilitiesComplete : CommandComplete (command_op_code = LE_GET_VENDOR_CAPABILITIES) { - status : ErrorCode, - base_vendor_capabilities : BaseVendorCapabilities, - _payload_, +packet InquiryResult : Event (event_code = INQUIRY_RESULT) { + _count_(responses) : 8, + responses : InquiryResponse[], } -packet LeGetVendorCapabilitiesComplete095 : LeGetVendorCapabilitiesComplete { - version_supported: 16, - total_num_of_advt_tracked: 16, - extended_scan_support: 8, - debug_logging_supported: 8, - _payload_, +enum LinkType : 8 { + SCO = 0x00, + ACL = 0x01, } -packet LeGetVendorCapabilitiesComplete096 : LeGetVendorCapabilitiesComplete095 { - le_address_generation_offloading_support: 8, - _payload_, +packet ConnectionComplete : Event (event_code = CONNECTION_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + bd_addr : Address, + link_type : LinkType, + encryption_enabled : Enable, } -packet LeGetVendorCapabilitiesComplete098 : LeGetVendorCapabilitiesComplete096 { - a2dp_source_offload_capability_mask: 32, - bluetooth_quality_report_support: 8 +enum ConnectionRequestLinkType : 8 { + UNKNOWN = 0xFF, + SCO = 0x00, + ACL = 0x01, + ESCO = 0x02, } -enum SubOcf : 8 { - SET_PARAM = 0x01, - SET_DATA = 0x02, - SET_SCAN_RESP = 0x03, - SET_RANDOM_ADDR = 0x04, - SET_ENABLE = 0x05, +packet ConnectionRequest : Event (event_code = CONNECTION_REQUEST) { + bd_addr : Address, + class_of_device : 24, + link_type : ConnectionRequestLinkType, } -packet LeMultiAdvt : Command (op_code = LE_MULTI_ADVT) { - sub_cmd : SubOcf, - _body_, +packet DisconnectionComplete : Event (event_code = DISCONNECTION_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + reason : ErrorCode, } -packet LeMultiAdvtComplete : CommandComplete (command_op_code = LE_MULTI_ADVT) { +packet AuthenticationComplete : Event (event_code = AUTHENTICATION_COMPLETE) { status : ErrorCode, - sub_cmd : SubOcf, + connection_handle : 12, + _reserved_ : 4, } -packet LeMultiAdvtParam : LeMultiAdvt (sub_cmd = SET_PARAM) { - interval_min : 16, - interval_max : 16, - advertising_type : AdvertisingType, - own_address_type : OwnAddressType, - own_address : Address, - peer_address_type : PeerAddressType, - peer_address : Address, - channel_map : 8, - filter_policy : AdvertisingFilterPolicy, - _reserved_ : 6, - instance : 8, - tx_power : 8, +packet RemoteNameRequestComplete : Event (event_code = REMOTE_NAME_REQUEST_COMPLETE) { + status : ErrorCode, + bd_addr : Address, + remote_name : 8[248], // UTF-8 encoded user-friendly descriptive name } -packet LeMultiAdvtParamComplete : LeMultiAdvtComplete (sub_cmd = SET_PARAM) { +enum EncryptionEnabled : 8 { + OFF = 0x00, + ON = 0x01, // E0 for BR/EDR and AES-CCM for LE + BR_EDR_AES_CCM = 0x02, } -packet LeMultiAdvtSetData : LeMultiAdvt (sub_cmd = SET_DATA) { - _size_(advertising_data) : 8, - advertising_data : GapData[], - _padding_[31], // Zero padding to 31 bytes of advertising_data - advertising_instance : 8, +packet EncryptionChange : Event (event_code = ENCRYPTION_CHANGE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + encryption_enabled : EncryptionEnabled, } -packet LeMultiAdvtSetDataComplete : LeMultiAdvtComplete (sub_cmd = SET_DATA) { +packet ChangeConnectionLinkKeyComplete : Event (event_code = CHANGE_CONNECTION_LINK_KEY_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, } -packet LeMultiAdvtSetScanResp : LeMultiAdvt (sub_cmd = SET_SCAN_RESP) { - _size_(advertising_data) : 8, - advertising_data : GapData[], - _padding_[31], // Zero padding to 31 bytes of advertising_data - advertising_instance : 8, +packet CentralLinkKeyComplete : Event (event_code = CENTRAL_LINK_KEY_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + key_flag : KeyFlag, } -packet LeMultiAdvtSetScanRespComplete : LeMultiAdvtComplete (sub_cmd = SET_SCAN_RESP) { +packet ReadRemoteSupportedFeaturesComplete : Event (event_code = READ_REMOTE_SUPPORTED_FEATURES_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + lmp_features : 64, } -packet LeMultiAdvtSetRandomAddr : LeMultiAdvt (sub_cmd = SET_RANDOM_ADDR) { - random_address : Address, - advertising_instance : 8, +packet ReadRemoteVersionInformationComplete : Event (event_code = READ_REMOTE_VERSION_INFORMATION_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + version : 8, + manufacturer_name : 16, + sub_version : 16, } -packet LeMultiAdvtSetRandomAddrComplete : LeMultiAdvtComplete (sub_cmd = SET_RANDOM_ADDR) { +packet QosSetupComplete : Event (event_code = QOS_SETUP_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + _reserved_ : 8, + service_type : ServiceType, + token_rate : 32, // Octets/s + peak_bandwidth : 32, // Octets/s + latency : 32, // Octets/s + delay_variation : 32, // microseconds } -packet LeMultiAdvtSetEnable : LeMultiAdvt (sub_cmd = SET_ENABLE) { - advertising_enable : Enable, // Default DISABLED - advertising_instance : 8, +// Command Complete and Command Status Events are implemented above Commands. + +packet HardwareError : Event (event_code = HARDWARE_ERROR) { + hardware_code : 8, } -packet LeMultiAdvtSetEnableComplete : LeMultiAdvtComplete (sub_cmd = SET_ENABLE) { +packet FlushOccurred : Event (event_code = FLUSH_OCCURRED) { + connection_handle : 12, + _reserved_ : 4, } -enum BatchScanOpcode : 8 { - ENABLE = 0x01, - SET_STORAGE_PARAMETERS = 0x02, - SET_SCAN_PARAMETERS = 0x03, - READ_RESULT_PARAMETERS = 0x04, +packet RoleChange : Event (event_code = ROLE_CHANGE) { + status : ErrorCode, + bd_addr : Address, + new_role : Role, } -// https://source.android.com/devices/bluetooth/hci_requirements#batching-of-scan-results -packet LeBatchScan : Command (op_code = LE_BATCH_SCAN) { - batch_scan_opcode : BatchScanOpcode, - _body_, +packet NumberOfCompletedPackets : Event (event_code = NUMBER_OF_COMPLETED_PACKETS) { + _count_(completed_packets) : 8, + completed_packets : CompletedPackets[], } -packet LeBatchScanComplete : CommandComplete (command_op_code = LE_BATCH_SCAN) { +enum Mode : 8 { + ACTIVE = 0x00, + HOLD = 0x01, + SNIFF = 0x02, +} + +packet ModeChange : Event (event_code = MODE_CHANGE) { status : ErrorCode, - batch_scan_opcode : BatchScanOpcode, - _body_, + connection_handle : 12, + _reserved_ : 4, + current_mode : Mode, + interval : 16, // 0x002 - 0xFFFE (1.25ms - 40.9s) } -packet LeBatchScanEnable : LeBatchScan (batch_scan_opcode = ENABLE) { - enable : Enable, +struct ZeroKeyAndAddress { + address : Address, + _fixed_ = 0 : 64, + _fixed_ = 0 : 64, } -packet LeBatchScanEnableComplete : LeBatchScanComplete (batch_scan_opcode = ENABLE) { +packet ReturnLinkKeys : Event (event_code = RETURN_LINK_KEYS) { + _count_(keys) : 8, + keys : ZeroKeyAndAddress[], } -packet LeBatchScanSetStorageParameters : LeBatchScan (batch_scan_opcode = SET_STORAGE_PARAMETERS) { - batch_scan_full_max_percentage : 8, - batch_scan_truncated_max_percentage : 8, - batch_scan_notify_threshold_percentage : 8, +packet PinCodeRequest : Event (event_code = PIN_CODE_REQUEST) { + bd_addr : Address, } -packet LeBatchScanSetStorageParametersComplete : LeBatchScanComplete (batch_scan_opcode = SET_STORAGE_PARAMETERS) { +packet LinkKeyRequest : Event (event_code = LINK_KEY_REQUEST) { + bd_addr : Address, } -enum BatchScanDiscardRule : 8 { - OLDEST = 0x00, - WEAKEST_RSSI = 0x01, +enum KeyType : 8 { + COMBINATION = 0x00, + DEBUG_COMBINATION = 0x03, + UNAUTHENTICATED_P192 = 0x04, + AUTHENTICATED_P192 = 0x05, + CHANGED = 0x06, + UNAUTHENTICATED_P256 = 0x07, + AUTHENTICATED_P256 = 0x08, } -packet LeBatchScanSetScanParameters : LeBatchScan (batch_scan_opcode = SET_SCAN_PARAMETERS) { - truncated_mode_enabled : 1, - full_mode_enabled : 1, - _reserved_ : 6, - duty_cycle_scan_window_slots : 32, - duty_cycle_scan_interval_slots : 32, - own_address_type : PeerAddressType, - batch_scan_discard_rule : BatchScanDiscardRule, +packet LinkKeyNotification : Event (event_code = LINK_KEY_NOTIFICATION) { + bd_addr : Address, + link_key : 8[16], + key_type : KeyType, } -packet LeBatchScanSetScanParametersComplete : LeBatchScanComplete (batch_scan_opcode = SET_SCAN_PARAMETERS) { +packet LoopbackCommand : Event (event_code = LOOPBACK_COMMAND) { + _payload_, // Command packet, truncated if it was longer than 252 bytes } -enum BatchScanDataRead : 8 { - TRUNCATED_MODE_DATA = 0x01, - FULL_MODE_DATA = 0x02, +packet DataBufferOverflow : Event (event_code = DATA_BUFFER_OVERFLOW) { + link_type : LinkType, } -packet LeBatchScanReadResultParameters : LeBatchScan (batch_scan_opcode = READ_RESULT_PARAMETERS) { - batch_scan_data_read : BatchScanDataRead, +packet MaxSlotsChange : Event (event_code = MAX_SLOTS_CHANGE) { + connection_handle : 12, + _reserved_ : 4, + lmp_max_slots : 8, } -packet LeBatchScanReadResultParametersCompleteRaw : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) { - batch_scan_data_read : BatchScanDataRead, - num_of_records : 8, - raw_data : 8[], +packet ReadClockOffsetComplete : Event (event_code = READ_CLOCK_OFFSET_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + clock_offset : 15, + _reserved_ : 1, } -packet LeBatchScanReadResultParametersComplete : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) { - batch_scan_data_read : BatchScanDataRead, - _body_, +packet ConnectionPacketTypeChanged : Event (event_code = CONNECTION_PACKET_TYPE_CHANGED) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + packet_type : 16, } -struct TruncatedResult { +packet QosViolation : Event (event_code = QOS_VIOLATION) { + connection_handle : 12, + _reserved_ : 4, +} + +packet PageScanRepetitionModeChange : Event (event_code = PAGE_SCAN_REPETITION_MODE_CHANGE) { bd_addr : Address, - address_type : AddressType, - tx_power : 8, - rssi : 8, - timestamp : 16, + page_scan_repetition_mode : PageScanRepetitionMode, } -packet LeBatchScanReadTruncatedResultParametersComplete : LeBatchScanReadResultParametersComplete (batch_scan_data_read = TRUNCATED_MODE_DATA) { - _count_(results) : 8, - results : TruncatedResult[], +packet FlowSpecificationComplete : Event (event_code = FLOW_SPECIFICATION_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + _reserved_ : 8, + flow_direction : FlowDirection, + service_type : ServiceType, + token_rate : 32, // Octets/s + token_bucket_size : 32, + peak_bandwidth : 32, // Octets/s + access_latency : 32, // Octets/s } -struct FullResult { - bd_addr : Address, - address_type : AddressType, - tx_power : 8, +struct InquiryResponseWithRssi { + address : Address, + page_scan_repetition_mode : PageScanRepetitionMode, + _reserved_ : 8, + class_of_device : 24, + clock_offset : 15, + _reserved_ : 1, rssi : 8, - timestamp : 16, - _size_(adv_packet) : 8, - adv_packet : 8[], - _size_(scan_response) : 8, - scan_response : 8[], } -packet LeBatchScanReadFullResultParametersComplete : LeBatchScanReadResultParametersComplete (batch_scan_data_read = FULL_MODE_DATA) { - _count_(results) : 8, - results : FullResult[], +packet InquiryResultWithRssi : Event (event_code = INQUIRY_RESULT_WITH_RSSI) { + _count_(responses) : 8, + responses : InquiryResponseWithRssi[], } -enum ApcfOpcode : 8 { - ENABLE = 0x00, - SET_FILTERING_PARAMETERS = 0x01, - BROADCASTER_ADDRESS = 0x02, - SERVICE_UUID = 0x03, - SERVICE_SOLICITATION_UUID = 0x04, - LOCAL_NAME = 0x05, - MANUFACTURER_DATA = 0x06, - SERVICE_DATA = 0x07, - TRANSPORT_DISCOVERY_DATA = 0x08, - AD_TYPE = 0x09, - READ_EXTENDED_FEATURES = 0xFF, +packet ReadRemoteExtendedFeaturesComplete : Event (event_code = READ_REMOTE_EXTENDED_FEATURES_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + page_number : 8, + maximum_page_number : 8, + extended_lmp_features : 64, } -// https://source.android.com/devices/bluetooth/hci_requirements#advertising-packet-content-filter -packet LeAdvFilter : Command (op_code = LE_ADV_FILTER) { - apcf_opcode : ApcfOpcode, - _body_, +enum ScoLinkType : 8 { + SCO = 0x00, + ESCO = 0x02, +} + +enum ScoAirMode : 8 { + ULAW_LOG = 0x00, + ALAW_LOG = 0x01, + CVSD = 0x02, + TRANSPARENT = 0x03, } -packet LeAdvFilterComplete : CommandComplete (command_op_code = LE_ADV_FILTER) { +packet SynchronousConnectionComplete : Event (event_code = SYNCHRONOUS_CONNECTION_COMPLETE) { status : ErrorCode, - apcf_opcode : ApcfOpcode, - _body_, + connection_handle : 12, + _reserved_ : 4, + bd_addr : Address, + link_type : ScoLinkType, + // Time between two consecutive eSCO instants measured in slots. + // eSCO only, Shall be zero for SCO links. + transmission_interval_slots : 8, + // The size of the retransmission window measured in slots. + // eSCO only. Shall be zero for SCO links. + retransmission_window_slots : 8, + // Length in bytes of the eSCO payload in the receive direction. + // eSCO only. Shall be zero for SCO links. + rx_packet_length : 16, + // Length in bytes of the eSCO payload in the transmit direction. + // eSCO only. Shall be zero for SCO links. + tx_packet_length : 16, + air_mode : ScoAirMode, } -packet LeAdvFilterEnable : LeAdvFilter (apcf_opcode = ENABLE) { - apcf_enable : Enable, +test SynchronousConnectionComplete { + "\x2c\x11\x00\x03\x00\x1d\xdf\xed\x2b\x1a\xf8\x02\x0c\x04\x3c\x00\x3c\x00\x03", } -packet LeAdvFilterEnableComplete : LeAdvFilterComplete (apcf_opcode = ENABLE) { - apcf_enable : Enable, +packet SynchronousConnectionChanged : Event (event_code = SYNCHRONOUS_CONNECTION_CHANGED) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + // Time between two consecutive eSCO instants measured in slots. + // eSCO only, Shall be zero for SCO links. + transmission_interval_slots : 8, + // Time between two consecutive SCO/eSCO instants measured in slots. + retransmission_window_slots : 8, + // Length in bytes of the SCO/eSCO payload in the receive direction. + rx_packet_length : 16, + // Length in bytes of the SCO/eSCO payload in the transmit direction. + tx_packet_length : 16, } -enum ApcfAction : 8 { - ADD = 0x00, - DELETE = 0x01, - CLEAR = 0x02, +packet SniffSubratingEvent : Event (event_code = SNIFF_SUBRATING) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + maximum_transmit_latency : 16, // 0x000 - 0xFFFE (0s - 40.9s) + maximum_receive_latency : 16, // 0x000 - 0xFFFE (0s - 40.9s) + minimum_remote_timeout : 16, // 0x000 - 0xFFFE (0s - 40.9s) + minimum_local_timeout : 16, // 0x000 - 0xFFFE (0s - 40.9s) } -enum DeliveryMode : 8 { - IMMEDIATE = 0x00, - ONFOUND = 0x01, - BATCHED = 0x02, +packet ExtendedInquiryResult : Event (event_code = EXTENDED_INQUIRY_RESULT) { + _fixed_ = 0x01 : 8, + address : Address, + page_scan_repetition_mode : PageScanRepetitionMode, + _reserved_ : 8, + class_of_device : 24, + clock_offset : 15, + _reserved_ : 1, + rssi : 8, + // Extended inquiry Result is always 255 bytes long; + // the gap data is padded with zeros as necessary. + // Refer to BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 3, Part C Section 8 on page 1340 + extended_inquiry_response : 8[240], } -// Bit masks for the selected features -enum ApcfFilterType : 8 { - BROADCASTER_ADDRESS = 0x00, - SERVICE_DATA_CHANGE = 0x01, - SERVICE_UUID = 0x02, - SERVICE_SOLICITATION_UUID = 0x03, - LOCAL_NAME = 0x04, - MANUFACTURER_DATA = 0x05, - SERVICE_DATA = 0x06, - TRANSPORT_DISCOVERY_DATA = 0x07, - AD_TYPE = 0x08, +packet EncryptionKeyRefreshComplete : Event (event_code = ENCRYPTION_KEY_REFRESH_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, } -packet LeAdvFilterSetFilteringParameters : LeAdvFilter (apcf_opcode = SET_FILTERING_PARAMETERS) { - apcf_action : ApcfAction, - _body_, +packet IoCapabilityRequest : Event (event_code = IO_CAPABILITY_REQUEST) { + bd_addr : Address, } -packet LeAdvFilterAddFilteringParameters : LeAdvFilterSetFilteringParameters (apcf_action = ADD) { - apcf_filter_index : 8, - apcf_feature_selection : 16, - apcf_list_logic_type : 16, - apcf_filter_logic_type : 8, - rssi_high_thresh : 8, - delivery_mode : DeliveryMode, - onfound_timeout : 16, - onfound_timeout_cnt : 8, - rssi_low_thresh : 8, - onlost_timeout : 16, - num_of_tracking_entries : 16, -} - -packet LeAdvFilterDeleteFilteringParameters : LeAdvFilterSetFilteringParameters (apcf_action = DELETE) { - apcf_filter_index : 8, +packet IoCapabilityResponse : Event (event_code = IO_CAPABILITY_RESPONSE) { + bd_addr : Address, + io_capability : IoCapability, + oob_data_present : OobDataPresent, + authentication_requirements : AuthenticationRequirements, } -packet LeAdvFilterClearFilteringParameters : LeAdvFilterSetFilteringParameters (apcf_action = CLEAR) { +packet UserConfirmationRequest : Event (event_code = USER_CONFIRMATION_REQUEST) { + bd_addr : Address, + numeric_value : 20, // 0x00000-0xF423F (000000 - 999999) + _reserved_ : 12, } -packet LeAdvFilterSetFilteringParametersComplete : LeAdvFilterComplete (apcf_opcode = SET_FILTERING_PARAMETERS) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +packet UserPasskeyRequest : Event (event_code = USER_PASSKEY_REQUEST) { + bd_addr : Address, } -enum ApcfApplicationAddressType : 8 { - PUBLIC = 0x00, - RANDOM = 0x01, - NOT_APPLICABLE = 0x02, +packet RemoteOobDataRequest : Event (event_code = REMOTE_OOB_DATA_REQUEST) { + bd_addr : Address, } -packet LeAdvFilterBroadcasterAddress : LeAdvFilter (apcf_opcode = BROADCASTER_ADDRESS) { - apcf_action : ApcfAction, - apcf_filter_index : 8, - apcf_broadcaster_address : Address, - apcf_application_address_type : ApcfApplicationAddressType, +packet SimplePairingComplete : Event (event_code = SIMPLE_PAIRING_COMPLETE) { + status : ErrorCode, + bd_addr : Address, } -packet LeAdvFilterClearBroadcasterAddress : LeAdvFilter (apcf_opcode = BROADCASTER_ADDRESS) { - _fixed_ = 0x02 : 8, - apcf_filter_index : 8, +packet LinkSupervisionTimeoutChanged : Event (event_code = LINK_SUPERVISION_TIMEOUT_CHANGED) { + connection_handle : 12, + _reserved_ : 4, + link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s) } -packet LeAdvFilterBroadcasterAddressComplete : LeAdvFilterComplete (apcf_opcode = BROADCASTER_ADDRESS) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +enum FlushablePacketType : 8 { + AUTOMATICALLY_FLUSHABLE_ONLY = 0, } - -packet LeAdvFilterServiceUuid : LeAdvFilter (apcf_opcode = SERVICE_UUID) { - apcf_action : ApcfAction, - apcf_filter_index : 8, - acpf_uuid_data : 8[], +packet EnhancedFlush : Command (op_code = ENHANCED_FLUSH) { + connection_handle : 12, + _reserved_ : 4, + packet_type : FlushablePacketType, } -packet LeAdvFilterServiceUuidComplete : LeAdvFilterComplete (apcf_opcode = SERVICE_UUID) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +test EnhancedFlush { + "\x5f\x0c\x03\x02\x00\x00", } -packet LeAdvFilterSolicitationUuid : LeAdvFilter (apcf_opcode = SERVICE_SOLICITATION_UUID) { - apcf_action : ApcfAction, - apcf_filter_index : 8, - acpf_uuid_data : 8[], +packet EnhancedFlushStatus : CommandStatus (command_op_code = ENHANCED_FLUSH) { } -packet LeAdvFilterSolicitationUuidComplete : LeAdvFilterComplete (apcf_opcode = SERVICE_SOLICITATION_UUID) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +packet EnhancedFlushComplete : Event (event_code = ENHANCED_FLUSH_COMPLETE) { + connection_handle : 12, + _reserved_ : 4, } -packet LeAdvFilterLocalName : LeAdvFilter (apcf_opcode = LOCAL_NAME) { - apcf_action : ApcfAction, - apcf_filter_index : 8, - apcf_local_name : 8[], +test EnhancedFlushComplete { + "\x39\x02\x02\x00", } -packet LeAdvFilterLocalNameComplete : LeAdvFilterComplete (apcf_opcode = LOCAL_NAME) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +packet UserPasskeyNotification : Event (event_code = USER_PASSKEY_NOTIFICATION) { + bd_addr : Address, + passkey : 20, // 0x00000-0xF423F (000000 - 999999) + _reserved_ : 12, } -packet LeAdvFilterManufacturerData : LeAdvFilter (apcf_opcode = MANUFACTURER_DATA) { - apcf_action : ApcfAction, - apcf_filter_index : 8, - apcf_manufacturer_data : 8[], +packet KeypressNotification : Event (event_code = KEYPRESS_NOTIFICATION) { + bd_addr : Address, + notification_type : KeypressNotificationType, } -packet LeAdvFilterManufacturerDataComplete : LeAdvFilterComplete (apcf_opcode = MANUFACTURER_DATA) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +packet RemoteHostSupportedFeaturesNotification : Event (event_code = REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION) { + bd_addr : Address, + host_supported_features : 64, } -packet LeAdvFilterServiceData : LeAdvFilter (apcf_opcode = SERVICE_DATA) { - apcf_action : ApcfAction, - apcf_filter_index : 8, - apcf_service_data : 8[], +packet LeMetaEvent : Event (event_code = LE_META_EVENT) { + subevent_code : SubeventCode, + _body_, } -packet LeAdvFilterServiceDataComplete : LeAdvFilterComplete (apcf_opcode = SERVICE_DATA) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +packet NumberOfCompletedDataBlocks : Event (event_code = NUMBER_OF_COMPLETED_DATA_BLOCKS) { + total_num_data_blocks : 16, + _payload_, // placeholder (unimplemented) } -packet LeAdvFilterTransportDiscoveryData : LeAdvFilter (apcf_opcode = TRANSPORT_DISCOVERY_DATA) { - apcf_action : ApcfAction, - apcf_filter_index : 8, - apcf_transport_discovery_data : 8[], +// LE Events +packet LeConnectionComplete : LeMetaEvent (subevent_code = CONNECTION_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + role : Role, + peer_address_type : AddressType, + peer_address : Address, + connection_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) + peripheral_latency : 16, + supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) + central_clock_accuracy : ClockAccuracy, } -packet LeAdvFilterTransportDiscoveryDataComplete : LeAdvFilterComplete (apcf_opcode = TRANSPORT_DISCOVERY_DATA) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +enum AdvertisingEventType : 8 { + ADV_IND = 0x00, + ADV_DIRECT_IND = 0x01, + ADV_SCAN_IND = 0x02, + ADV_NONCONN_IND = 0x03, + SCAN_RESPONSE = 0x04, } -packet LeAdvFilterADType : LeAdvFilter (apcf_opcode = AD_TYPE) { - apcf_action : ApcfAction, - apcf_filter_index : 8, - apcf_ad_type_data : 8[], +struct LeAdvertisingResponse { + event_type : AdvertisingEventType, + address_type : AddressType, + address : Address, + _size_(advertising_data) : 8, + advertising_data : 8[], + rssi : 8, } -packet LeAdvFilterADTypeComplete : LeAdvFilterComplete (apcf_opcode = AD_TYPE) { - apcf_action : ApcfAction, - apcf_available_spaces : 8, +packet LeAdvertisingReport : LeMetaEvent (subevent_code = ADVERTISING_REPORT) { + _count_(responses) : 8, + responses : LeAdvertisingResponse[], } -packet LeAdvFilterReadExtendedFeatures : LeAdvFilter (apcf_opcode = READ_EXTENDED_FEATURES) { +packet LeConnectionUpdateComplete : LeMetaEvent (subevent_code = CONNECTION_UPDATE_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + connection_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) + peripheral_latency : 16, // Number of connection events + supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) } -test LeAdvFilterReadExtendedFeatures { - "\x57\xfd\x01\xff", +packet LeReadRemoteFeaturesComplete : LeMetaEvent (subevent_code = READ_REMOTE_FEATURES_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + le_features : 64, } -packet LeAdvFilterReadExtendedFeaturesComplete : LeAdvFilterComplete (apcf_opcode = READ_EXTENDED_FEATURES) { - transport_discovery_data_filter : 1, - ad_type_filter : 1, - _reserved_ : 14, +packet LeLongTermKeyRequest : LeMetaEvent (subevent_code = LONG_TERM_KEY_REQUEST) { + connection_handle : 12, + _reserved_ : 4, + random_number : 8[8], + encrypted_diversifier : 16, } -test LeAdvFilterReadExtendedFeaturesComplete { - "\x0e\x07\x01\x57\xfd\x00\xff\x03\x00", +packet LeRemoteConnectionParameterRequest : LeMetaEvent (subevent_code = REMOTE_CONNECTION_PARAMETER_REQUEST) { + connection_handle : 12, + _reserved_ : 4, + interval_min : 16, // 0x006 - 0x0C80 (7.5ms - 4s) + interval_max : 16, // 0x006 - 0x0C80 (7.5ms - 4s) + latency : 16, // Number of connection events (0x0000 to 0x01f3 (499) + timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) } -packet LeEnergyInfo : VendorCommand (op_code = LE_ENERGY_INFO) { +packet LeDataLengthChange : LeMetaEvent (subevent_code = DATA_LENGTH_CHANGE) { + connection_handle : 12, + _reserved_ : 4, + max_tx_octets : 16, // 0x001B - 0x00FB + max_tx_time : 16, // 0x0148 - 0x4290 + max_rx_octets : 16, // 0x001B - 0x00FB + max_rx_time : 16, // 0x0148 - 0x4290 } -packet LeEnergyInfoComplete : CommandComplete (command_op_code = LE_ENERGY_INFO) { +packet ReadLocalP256PublicKeyComplete : LeMetaEvent (subevent_code = READ_LOCAL_P256_PUBLIC_KEY_COMPLETE) { status : ErrorCode, - total_tx_time_ms : 32, - total_rx_time_ms : 32, - total_idle_time_ms : 32, - total_energy_used_ma_v_ms : 32, + local_p_256_public_key : 8[64], } -packet LeExtendedScanParams : Command (op_code = LE_EXTENDED_SCAN_PARAMS) { - le_scan_type : LeScanType, - le_scan_interval : 32, // 0x0004-0x4000 Default 0x10 (10ms) - le_scan_window : 32, // Default 0x10 (10ms) - own_address_type : OwnAddressType, - scanning_filter_policy : LeScanningFilterPolicy, +packet GenerateDhKeyComplete : LeMetaEvent (subevent_code = GENERATE_DHKEY_COMPLETE) { + status : ErrorCode, + dh_key : 8[32], } -packet LeExtendedScanParamsComplete : CommandComplete (command_op_code = LE_EXTENDED_SCAN_PARAMS) { +packet LeEnhancedConnectionComplete : LeMetaEvent (subevent_code = ENHANCED_CONNECTION_COMPLETE) { status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + role : Role, + peer_address_type : AddressType, + peer_address : Address, + local_resolvable_private_address : Address, + peer_resolvable_private_address : Address, + connection_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) + peripheral_latency : 16, + supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) + central_clock_accuracy : ClockAccuracy, } -packet ControllerDebugInfo : VendorCommand (op_code = CONTROLLER_DEBUG_INFO) { +enum DirectAdvertisingAddressType : 8 { + PUBLIC_DEVICE_ADDRESS = 0x00, + RANDOM_DEVICE_ADDRESS = 0x01, + PUBLIC_IDENTITY_ADDRESS = 0x02, + RANDOM_IDENTITY_ADDRESS = 0x03, + CONTROLLER_UNABLE_TO_RESOLVE = 0xFE, + NO_ADDRESS_PROVIDED = 0xFF, } -packet ControllerDebugInfoComplete : CommandComplete (command_op_code = CONTROLLER_DEBUG_INFO) { - status : ErrorCode, +enum DirectAdvertisingEventType : 8 { + ADV_DIRECT_IND = 0x01, } -packet ControllerA2DPOpcode : VendorCommand (op_code = CONTROLLER_A2DP_OPCODE) { - _payload_, // placeholder (unimplemented) +enum DirectAddressType : 8 { + RANDOM_DEVICE_ADDRESS = 0x01, } -packet ControllerA2DPOpcodeComplete : CommandComplete (command_op_code = CONTROLLER_A2DP_OPCODE) { - _payload_, // placeholder (unimplemented) +struct LeDirectedAdvertisingResponse { + event_type : DirectAdvertisingEventType, + address_type : DirectAdvertisingAddressType, + address : Address, + direct_address_type : DirectAddressType, + direct_address : Address, + rssi : 8, } -enum BqrReportAction : 8 { - ADD = 0x00, - DELETE = 0x01, - CLEAR = 0x02, +packet LeDirectedAdvertisingReport : LeMetaEvent (subevent_code = DIRECTED_ADVERTISING_REPORT) { + _count_(responses) : 8, + responses : LeDirectedAdvertisingResponse[], } -packet ControllerBqr : VendorCommand(op_code = CONTROLLER_BQR) { - bqr_report_action : BqrReportAction, - bqr_quality_event_mask : 32, - bqr_minimum_report_interval : 16, +packet LePhyUpdateComplete : LeMetaEvent (subevent_code = PHY_UPDATE_COMPLETE) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + tx_phy : PhyType, + rx_phy : PhyType, } -test ControllerBqr { - "\x5e\xfd\x07\x00\x1f\x00\x07\x00\x88\x13", +enum DataStatus : 2 { + COMPLETE = 0x0, + CONTINUING = 0x1, + TRUNCATED = 0x2, + RESERVED = 0x3, } -packet ControllerBqrComplete : CommandComplete (command_op_code = CONTROLLER_BQR) { - status : ErrorCode, - current_quality_event_mask : 32 +struct LeExtendedAdvertisingResponse { + connectable : 1, + scannable : 1, + directed : 1, + scan_response : 1, + legacy : 1, + data_status : DataStatus, + _reserved_ : 9, + address_type : DirectAdvertisingAddressType, + address : Address, + primary_phy : PrimaryPhyType, + secondary_phy : SecondaryPhyType, + advertising_sid : 8, // SID subfield in the ADI field + tx_power : 8, + rssi : 8, // -127 to +20 (0x7F means not available) + periodic_advertising_interval : 16, // 0x006 to 0xFFFF (7.5 ms to 82s) + direct_address_type : DirectAdvertisingAddressType, + direct_address : Address, + _size_(advertising_data) : 8, + advertising_data: 8[], } -test ControllerBqrComplete { - "\x0e\x08\x01\x5e\xfd\x00\x1f\x00\x07\x00", +packet LeExtendedAdvertisingReport : LeMetaEvent (subevent_code = EXTENDED_ADVERTISING_REPORT) { + _count_(responses) : 8, + responses : LeExtendedAdvertisingResponse[], } -// HCI Event Packets - -packet InquiryComplete : Event (event_code = INQUIRY_COMPLETE) { +packet LePeriodicAdvertisingSyncEstablished : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_ESTABLISHED) { status : ErrorCode, + sync_handle : 12, + _reserved_ : 4, + advertising_sid : 8, + advertiser_address_type : AddressType, + advertiser_address : Address, + advertiser_phy : SecondaryPhyType, + periodic_advertising_interval : 16, + advertiser_clock_accuracy : ClockAccuracy, } -struct InquiryResponse { - bd_addr : Address, - page_scan_repetition_mode : PageScanRepetitionMode, - _reserved_ : 8, - _reserved_ : 8, - class_of_device : ClassOfDevice, - clock_offset : 15, - _reserved_ : 1, +packet LePeriodicAdvertisingReport : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_REPORT) { + sync_handle : 12, + _reserved_ : 4, + tx_power : 8, + rssi : 8, + cte_type : CteType, + data_status : DataStatus, + _reserved_: 6, + _size_(data) : 8, + data : 8[], } -packet InquiryResult : Event (event_code = INQUIRY_RESULT) { - _count_(responses) : 8, - responses : InquiryResponse[], +packet LePeriodicAdvertisingSyncLost : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_LOST) { + sync_handle : 12, + _reserved_ : 4, } -enum LinkType : 8 { - SCO = 0x00, - ACL = 0x01, +packet LeScanTimeout : LeMetaEvent (subevent_code = SCAN_TIMEOUT) { } -packet ConnectionComplete : Event (event_code = CONNECTION_COMPLETE) { +packet LeAdvertisingSetTerminated : LeMetaEvent (subevent_code = ADVERTISING_SET_TERMINATED) { status : ErrorCode, + advertising_handle : 8, connection_handle : 12, _reserved_ : 4, - bd_addr : Address, - link_type : LinkType, - encryption_enabled : Enable, + num_completed_extended_advertising_events : 8, } -enum ConnectionRequestLinkType : 8 { - UNKNOWN = 0xFF, - SCO = 0x00, - ACL = 0x01, - ESCO = 0x02, +packet LeScanRequestReceived : LeMetaEvent (subevent_code = SCAN_REQUEST_RECEIVED) { + advertising_handle : 8, + scanner_address_type : AddressType, + scanner_address : Address, } -packet ConnectionRequest : Event (event_code = CONNECTION_REQUEST) { - bd_addr : Address, - class_of_device : ClassOfDevice, - link_type : ConnectionRequestLinkType, +enum ChannelSelectionAlgorithm : 8 { + ALGORITHM_1 = 0, + ALGORITHM_2 = 1, } -packet DisconnectionComplete : Event (event_code = DISCONNECTION_COMPLETE) { - status : ErrorCode, +packet LeChannelSelectionAlgorithm : LeMetaEvent (subevent_code = CHANNEL_SELECTION_ALGORITHM) { connection_handle : 12, _reserved_ : 4, - reason : ErrorCode, + channel_selection_algorithm : ChannelSelectionAlgorithm, } -packet AuthenticationComplete : Event (event_code = AUTHENTICATION_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, +packet LeConnectionlessIqReport : LeMetaEvent (subevent_code = CONNECTIONLESS_IQ_REPORT) { + _payload_, // placeholder (unimplemented) } -packet RemoteNameRequestComplete : Event (event_code = REMOTE_NAME_REQUEST_COMPLETE) { - status : ErrorCode, - bd_addr : Address, - remote_name : 8[248], // UTF-8 encoded user-friendly descriptive name +packet LeConnectionIqReport : LeMetaEvent (subevent_code = CONNECTION_IQ_REPORT) { + _payload_, // placeholder (unimplemented) } -enum EncryptionEnabled : 8 { - OFF = 0x00, - ON = 0x01, // E0 for BR/EDR and AES-CCM for LE - BR_EDR_AES_CCM = 0x02, +packet LeCteRequestFailed : LeMetaEvent (subevent_code = CTE_REQUEST_FAILED) { + _payload_, // placeholder (unimplemented) } -packet EncryptionChange : Event (event_code = ENCRYPTION_CHANGE) { +packet LePeriodicAdvertisingSyncTransferReceived : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED) { status : ErrorCode, connection_handle : 12, _reserved_ : 4, - encryption_enabled : EncryptionEnabled, + service_data : 16, + sync_handle : 12, + _reserved_ : 4, + advertising_sid : 4, + _reserved_ : 4, + advertiser_address_type : AddressType, + advertiser_address : Address, + advertiser_phy : SecondaryPhyType, + periodic_advertising_interval : 16, + advertiser_clock_accuracy : ClockAccuracy, } -packet ChangeConnectionLinkKeyComplete : Event (event_code = CHANGE_CONNECTION_LINK_KEY_COMPLETE) { +packet LeCisEstablished : LeMetaEvent (subevent_code = CIS_ESTABLISHED) { status : ErrorCode, connection_handle : 12, _reserved_ : 4, + cig_sync_delay : 24, + cis_sync_delay : 24, + transport_latency_c_to_p : 24, + transport_latency_p_to_c : 24, + phy_c_to_p : SecondaryPhyType, + phy_p_to_c : SecondaryPhyType, + nse : 8, + bn_c_to_p : 4, + _reserved_ : 4, + bn_p_to_c : 4, + _reserved_ : 4, + ft_c_to_p : 8, + ft_p_to_c : 8, + max_pdu_c_to_p : 8, + _reserved_ : 8, + max_pdu_p_to_c : 8, + _reserved_ : 8, + iso_interval : 16, } -packet CentralLinkKeyComplete : Event (event_code = CENTRAL_LINK_KEY_COMPLETE) { - status : ErrorCode, - connection_handle : 12, +packet LeCisRequest : LeMetaEvent (subevent_code = CIS_REQUEST) { + acl_connection_handle : 12, _reserved_ : 4, - key_flag : KeyFlag, + cis_connection_handle : 12, + _reserved_ : 4, + cig_id : 8, + cis_id : 8, } -packet ReadRemoteSupportedFeaturesComplete : Event (event_code = READ_REMOTE_SUPPORTED_FEATURES_COMPLETE) { +packet LeCreateBigComplete : LeMetaEvent (subevent_code = CREATE_BIG_COMPLETE) { status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - lmp_features : 64, + big_handle : 8, + big_sync_delay : 24, + transport_latency_big: 24, + phy : SecondaryPhyType, + nse : 8, + bn : 8, + pto : 8, + irc : 8, + max_pdu : 16, + iso_interval : 16, + _size_(connection_handle) : 8, + connection_handle : 16[], } -packet ReadRemoteVersionInformationComplete : Event (event_code = READ_REMOTE_VERSION_INFORMATION_COMPLETE) { +packet LeTerminateBigComplete : LeMetaEvent (subevent_code = TERMINATE_BIG_COMPLETE) { + big_handle : 8, + reason : ErrorCode, +} + +packet LeBigSyncEstablished : LeMetaEvent (subevent_code = BIG_SYNC_ESTABLISHED) { status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - version : 8, - manufacturer_name : 16, - sub_version : 16, + big_handle : 8, + transport_latency_big : 24, + nse : 8, + bn : 8, + pto : 8, + irc : 8, + max_pdu : 16, + iso_interval : 16, + _size_(connection_handle) : 8, + connection_handle : 16[], } -packet QosSetupComplete : Event (event_code = QOS_SETUP_COMPLETE) { +packet LeBigSyncLost : LeMetaEvent (subevent_code = BIG_SYNC_LOST) { + big_handle : 8, + reason : ErrorCode, +} + +packet LeRequestPeerScaComplete : LeMetaEvent (subevent_code = REQUEST_PEER_SCA_COMPLETE) { status : ErrorCode, connection_handle : 12, _reserved_ : 4, - _reserved_ : 8, - service_type : ServiceType, - token_rate : 32, // Octets/s - peak_bandwidth : 32, // Octets/s - latency : 32, // Octets/s - delay_variation : 32, // microseconds + peer_clock_accuracy : ClockAccuracy, } -// Command Complete and Command Status Events are implemented above Commands. - -packet HardwareError : Event (event_code = HARDWARE_ERROR) { - hardware_code : 8, +enum PathLossZone : 8 { + LOW = 0, + MID = 1, + HIGH = 2, } -packet FlushOccurred : Event (event_code = FLUSH_OCCURRED) { +packet LePathLossThreshold : LeMetaEvent (subevent_code = PATH_LOSS_THRESHOLD) { connection_handle : 12, _reserved_ : 4, + current_path_loss : 8, + zone_entered : PathLossZone, } -packet RoleChange : Event (event_code = ROLE_CHANGE) { - status : ErrorCode, - bd_addr : Address, - new_role : Role, +enum ReportingReason : 8 { + LOCAL_TRANSMIT_POWER_CHANGED = 0x00, + REMOTE_TRANSMIT_POWER_CHANGED = 0x01, + READ_COMMAND_COMPLETE = 0x02, } -packet NumberOfCompletedPackets : Event (event_code = NUMBER_OF_COMPLETED_PACKETS) { - _count_(completed_packets) : 8, - completed_packets : CompletedPackets[], +packet LeTransmitPowerReporting : LeMetaEvent (subevent_code = TRANSMIT_POWER_REPORTING) { + status : ErrorCode, + connection_handle : 12, + _reserved_ : 4, + reason : ReportingReason, + phy : 8, + transmit_power_level : 8, + transmit_power_level_flag : 8, + delta : 8, } -enum Mode : 8 { - ACTIVE = 0x00, - HOLD = 0x01, - SNIFF = 0x02, +packet LeBigInfoAdvertisingReport : LeMetaEvent (subevent_code = BIG_INFO_ADVERTISING_REPORT) { + sync_handle : 12, + _reserved_ : 4, + num_bis : 8, + nse : 8, + iso_interval : 16, + bn : 8, + pto : 8, + irc : 8, + max_pdu : 16, + sdu_interval : 24, + max_sdu : 16, + phy : SecondaryPhyType, + framing : Enable, + encryption : Enable, } -packet ModeChange : Event (event_code = MODE_CHANGE) { +packet LeSubrateChange : LeMetaEvent (subevent_code = LE_SUBRATE_CHANGE) { status : ErrorCode, connection_handle : 12, _reserved_ : 4, - current_mode : Mode, - interval : 16, // 0x002 - 0xFFFE (1.25ms - 40.9s) + subrate_factor : 9, + _reserved_ : 7, + peripheral_latency : 9, + _reserved_ : 7, + continuation_number : 9, + _reserved_ : 7, + supervision_timeout: 12, + _reserved_ : 4, } -struct ZeroKeyAndAddress { - address : Address, - _fixed_ = 0 : 64, - _fixed_ = 0 : 64, +enum IsoPacketBoundaryFlag : 2 { + FIRST_FRAGMENT = 0, + CONTINUATION_FRAGMENT = 1, + COMPLETE_SDU = 2, + LAST_FRAGMENT = 3, } -packet ReturnLinkKeys : Event (event_code = RETURN_LINK_KEYS) { - _count_(keys) : 8, - keys : ZeroKeyAndAddress[], +enum TimeStampFlag : 1 { + NOT_PRESENT = 0, + PRESENT = 1, } -packet PinCodeRequest : Event (event_code = PIN_CODE_REQUEST) { - bd_addr : Address, +packet Iso { + connection_handle : 12, + pb_flag : IsoPacketBoundaryFlag, + ts_flag : TimeStampFlag, + _reserved_ : 1, + _size_(_payload_) : 14, + _reserved_ : 2, + _payload_, } -packet LinkKeyRequest : Event (event_code = LINK_KEY_REQUEST) { - bd_addr : Address, +enum IsoPacketStatusFlag : 2 { + VALID = 0, + POSSIBLY_INVALID = 1, + LOST_DATA = 2, } -enum KeyType : 8 { - COMBINATION = 0x00, - DEBUG_COMBINATION = 0x03, - UNAUTHENTICATED_P192 = 0x04, - AUTHENTICATED_P192 = 0x05, - CHANGED = 0x06, - UNAUTHENTICATED_P256 = 0x07, - AUTHENTICATED_P256 = 0x08, +packet IsoWithTimestamp : Iso (ts_flag = PRESENT) { + time_stamp : 32, + packet_sequence_number : 16, + iso_sdu_length : 12, + _reserved_ : 2, + packet_status_flag : IsoPacketStatusFlag, + _payload_, } -packet LinkKeyNotification : Event (event_code = LINK_KEY_NOTIFICATION) { - bd_addr : Address, - link_key : 8[16], - key_type : KeyType, +packet IsoWithoutTimestamp : Iso (ts_flag = NOT_PRESENT) { + packet_sequence_number : 16, + iso_sdu_length : 12, + _reserved_ : 2, + packet_status_flag : IsoPacketStatusFlag, + _payload_, } -packet LoopbackCommand : Event (event_code = LOOPBACK_COMMAND) { - _payload_, // Command packet, truncated if it was longer than 252 bytes +// https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile +enum GapDataType : 8 { + INVALID = 0x00, + FLAGS = 0x01, + INCOMPLETE_LIST_16_BIT_UUIDS = 0x02, + COMPLETE_LIST_16_BIT_UUIDS = 0x03, + INCOMPLETE_LIST_32_BIT_UUIDS = 0x04, + COMPLETE_LIST_32_BIT_UUIDS = 0x05, + INCOMPLETE_LIST_128_BIT_UUIDS = 0x06, + COMPLETE_LIST_128_BIT_UUIDS = 0x07, + SHORTENED_LOCAL_NAME = 0x08, + COMPLETE_LOCAL_NAME = 0x09, + TX_POWER_LEVEL = 0x0A, + CLASS_OF_DEVICE = 0x0D, + SIMPLE_PAIRING_HASH_C = 0x0E, + SIMPLE_PAIRING_RANDOMIZER_R = 0x0F, + DEVICE_ID = 0x10, + SECURITY_MANAGER_OOB_FLAGS = 0x11, + SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, + LIST_16BIT_SERVICE_SOLICITATION_UUIDS = 0x14, + LIST_128BIT_SERVICE_SOLICITATION_UUIDS = 0x15, + SERVICE_DATA_16_BIT_UUIDS = 0x16, + PUBLIC_TARGET_ADDRESS = 0x17, + RANDOM_TARGET_ADDRESS = 0x18, + APPEARANCE = 0x19, + ADVERTISING_INTERVAL = 0x1A, + LE_BLUETOOTH_DEVICE_ADDRESS = 0x1B, + LE_ROLE = 0x1C, + SIMPLE_PAIRING_HASH_C_256 = 0x1D, + SIMPLE_PAIRING_RANDOMIZER_R_256 = 0x1E, + LIST_32BIT_SERVICE_SOLICITATION_UUIDS = 0x1F, + SERVICE_DATA_32_BIT_UUIDS = 0x20, + SERVICE_DATA_128_BIT_UUIDS = 0x21, + LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE = 0x22, + LE_SECURE_CONNECTIONS_RANDOM_VALUE = 0x23, + URI = 0x24, + INDOOR_POSITIONING = 0x25, + TRANSPORT_DISCOVERY_DATA = 0x26, + LE_SUPPORTED_FEATURES = 0x27, + CHANNEL_MAP_UPDATE_INDICATION = 0x28, + MESH_PB_ADV = 0x29, + MESH_MESSAGE = 0x2A, + MESH_BEACON = 0x2B, + BIG_INFO = 0x2C, + BROADCAST_CODE = 0x2D, + THREE_D_INFORMATION_DATA = 0x3D, + MANUFACTURER_SPECIFIC_DATA = 0xFF, } -packet DataBufferOverflow : Event (event_code = DATA_BUFFER_OVERFLOW) { - link_type : LinkType, -} +// ----------------------------------------------------------------------------- +// LE Get Vendor Capabilities Command +// https://source.android.com/docs/core/connect/bluetooth/hci_requirements#vendor-specific-capabilities +// ----------------------------------------------------------------------------- -packet MaxSlotsChange : Event (event_code = MAX_SLOTS_CHANGE) { - connection_handle : 12, - _reserved_ : 4, - lmp_max_slots : 8, +packet LeGetVendorCapabilities : Command (op_code = LE_GET_VENDOR_CAPABILITIES) { } -packet ReadClockOffsetComplete : Event (event_code = READ_CLOCK_OFFSET_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - clock_offset : 15, - _reserved_ : 1, +test LeGetVendorCapabilities { + "\x53\xfd\x00", } -packet ConnectionPacketTypeChanged : Event (event_code = CONNECTION_PACKET_TYPE_CHANGED) { +packet LeGetVendorCapabilitiesComplete : CommandComplete (command_op_code = LE_GET_VENDOR_CAPABILITIES) { status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - packet_type : 16, -} - -packet QosViolation : Event (event_code = QOS_VIOLATION) { - connection_handle : 12, - _reserved_ : 4, + vendor_capabilities : 8[], } -packet PageScanRepetitionModeChange : Event (event_code = PAGE_SCAN_REPETITION_MODE_CHANGE) { - bd_addr : Address, - page_scan_repetition_mode : PageScanRepetitionMode, +struct VendorCapabilities_V_0_96 { + max_advt_instances: 8, + offloaded_resolution_of_private_address: 8, + total_scan_results_storage: 16, + max_irk_list_sz: 8, + filtering_support: 8, + max_filter: 8, + activity_energy_info_support: 8, + _fixed_ = 0x6000 : 16, // v0.96 + total_num_of_advt_tracked: 16, + extended_scan_support: 8, + debug_logging_supported: 8, + le_address_generation_offloading_support: 8, } -packet FlowSpecificationComplete : Event (event_code = FLOW_SPECIFICATION_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, +struct VendorCapabilities_V_0_98 { _reserved_ : 8, - flow_direction : FlowDirection, - service_type : ServiceType, - token_rate : 32, // Octets/s - token_bucket_size : 32, - peak_bandwidth : 32, // Octets/s - access_latency : 32, // Octets/s -} - -struct InquiryResponseWithRssi { - address : Address, - page_scan_repetition_mode : PageScanRepetitionMode, _reserved_ : 8, - class_of_device : ClassOfDevice, - clock_offset : 15, - _reserved_ : 1, - rssi : 8, -} - -packet InquiryResultWithRssi : Event (event_code = INQUIRY_RESULT_WITH_RSSI) { - _count_(responses) : 8, - responses : InquiryResponseWithRssi[], -} - -packet ReadRemoteExtendedFeaturesComplete : Event (event_code = READ_REMOTE_EXTENDED_FEATURES_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - page_number : 8, - maximum_page_number : 8, - extended_lmp_features : 64, -} - -enum ScoLinkType : 8 { - SCO = 0x00, - ESCO = 0x02, -} - -enum ScoAirMode : 8 { - ULAW_LOG = 0x00, - ALAW_LOG = 0x01, - CVSD = 0x02, - TRANSPARENT = 0x03, -} - -packet SynchronousConnectionComplete : Event (event_code = SYNCHRONOUS_CONNECTION_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - bd_addr : Address, - link_type : ScoLinkType, - // Time between two consecutive eSCO instants measured in slots. - // eSCO only, Shall be zero for SCO links. - transmission_interval_slots : 8, - // The size of the retransmission window measured in slots. - // eSCO only. Shall be zero for SCO links. - retransmission_window_slots : 8, - // Length in bytes of the eSCO payload in the receive direction. - // eSCO only. Shall be zero for SCO links. - rx_packet_length : 16, - // Length in bytes of the eSCO payload in the transmit direction. - // eSCO only. Shall be zero for SCO links. - tx_packet_length : 16, - air_mode : ScoAirMode, -} - -test SynchronousConnectionComplete { - "\x2c\x11\x00\x03\x00\x1d\xdf\xed\x2b\x1a\xf8\x02\x0c\x04\x3c\x00\x3c\x00\x03", -} - -packet SynchronousConnectionChanged : Event (event_code = SYNCHRONOUS_CONNECTION_CHANGED) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - // Time between two consecutive eSCO instants measured in slots. - // eSCO only, Shall be zero for SCO links. - transmission_interval_slots : 8, - // Time between two consecutive SCO/eSCO instants measured in slots. - retransmission_window_slots : 8, - // Length in bytes of the SCO/eSCO payload in the receive direction. - rx_packet_length : 16, - // Length in bytes of the SCO/eSCO payload in the transmit direction. - tx_packet_length : 16, -} - -packet SniffSubratingEvent : Event (event_code = SNIFF_SUBRATING) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - maximum_transmit_latency : 16, // 0x000 - 0xFFFE (0s - 40.9s) - maximum_receive_latency : 16, // 0x000 - 0xFFFE (0s - 40.9s) - minimum_remote_timeout : 16, // 0x000 - 0xFFFE (0s - 40.9s) - minimum_local_timeout : 16, // 0x000 - 0xFFFE (0s - 40.9s) -} - -packet ExtendedInquiryResult : Event (event_code = EXTENDED_INQUIRY_RESULT) { - _fixed_ = 0x01 : 8, - address : Address, - page_scan_repetition_mode : PageScanRepetitionMode, + total_scan_results_storage: 16, + max_irk_list_sz: 8, + filtering_support: 8, + max_filter: 8, + activity_energy_info_support: 8, + _fixed_ = 0x6200 : 16, // v0.98 + total_num_of_advt_tracked: 16, + extended_scan_support: 8, + debug_logging_supported: 8, _reserved_ : 8, - class_of_device : ClassOfDevice, - clock_offset : 15, - _reserved_ : 1, - rssi : 8, - extended_inquiry_response : GapData[], - // Extended inquiry Result is always 255 bytes long - // padded GapData with zeroes as necessary - // Refer to BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 3, Part C Section 8 on page 1340 - _padding_[240], + a2dp_source_offload_capability_mask: 32, + bluetooth_quality_report_support: 8, } -packet ExtendedInquiryResultRaw : Event (event_code = EXTENDED_INQUIRY_RESULT) { - _fixed_ = 0x01 : 8, - address : Address, - page_scan_repetition_mode : PageScanRepetitionMode, +struct VendorCapabilities_V_1_03 { _reserved_ : 8, - class_of_device : ClassOfDevice, - clock_offset : 15, - _reserved_ : 1, - rssi : 8, - // Extended inquiry Result is always 255 bytes long - // padded GapData with zeroes as necessary - // Refer to BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 3, Part C Section 8 on page 1340 - extended_inquiry_response : 8[240], -} - - -packet EncryptionKeyRefreshComplete : Event (event_code = ENCRYPTION_KEY_REFRESH_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, -} - -packet IoCapabilityRequest : Event (event_code = IO_CAPABILITY_REQUEST) { - bd_addr : Address, -} - -packet IoCapabilityResponse : Event (event_code = IO_CAPABILITY_RESPONSE) { - bd_addr : Address, - io_capability : IoCapability, - oob_data_present : OobDataPresent, - authentication_requirements : AuthenticationRequirements, -} - -packet UserConfirmationRequest : Event (event_code = USER_CONFIRMATION_REQUEST) { - bd_addr : Address, - numeric_value : 20, // 0x00000-0xF423F (000000 - 999999) - _reserved_ : 12, -} - -packet UserPasskeyRequest : Event (event_code = USER_PASSKEY_REQUEST) { - bd_addr : Address, -} - -packet RemoteOobDataRequest : Event (event_code = REMOTE_OOB_DATA_REQUEST) { - bd_addr : Address, -} - -packet SimplePairingComplete : Event (event_code = SIMPLE_PAIRING_COMPLETE) { - status : ErrorCode, - bd_addr : Address, -} - -packet LinkSupervisionTimeoutChanged : Event (event_code = LINK_SUPERVISION_TIMEOUT_CHANGED) { - connection_handle : 12, - _reserved_ : 4, - link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s) -} - -enum FlushablePacketType : 8 { - AUTOMATICALLY_FLUSHABLE_ONLY = 0, -} - -packet EnhancedFlush : Command (op_code = ENHANCED_FLUSH) { - connection_handle : 12, - _reserved_ : 4, - packet_type : FlushablePacketType, -} - -test EnhancedFlush { - "\x5f\x0c\x03\x02\x00\x00", -} - -packet EnhancedFlushStatus : CommandStatus (command_op_code = ENHANCED_FLUSH) { -} - -packet EnhancedFlushComplete : Event (event_code = ENHANCED_FLUSH_COMPLETE) { - connection_handle : 12, - _reserved_ : 4, -} - -test EnhancedFlushComplete { - "\x39\x02\x02\x00", -} - -packet UserPasskeyNotification : Event (event_code = USER_PASSKEY_NOTIFICATION) { - bd_addr : Address, - passkey : 20, // 0x00000-0xF423F (000000 - 999999) - _reserved_ : 12, -} - -packet KeypressNotification : Event (event_code = KEYPRESS_NOTIFICATION) { - bd_addr : Address, - notification_type : KeypressNotificationType, -} - -packet RemoteHostSupportedFeaturesNotification : Event (event_code = REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION) { - bd_addr : Address, - host_supported_features : 64, -} - -packet LeMetaEvent : Event (event_code = LE_META_EVENT) { - subevent_code : SubeventCode, - _body_, -} - -packet NumberOfCompletedDataBlocks : Event (event_code = NUMBER_OF_COMPLETED_DATA_BLOCKS) { - total_num_data_blocks : 16, - _payload_, // placeholder (unimplemented) -} - -// LE Events -packet LeConnectionComplete : LeMetaEvent (subevent_code = CONNECTION_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - role : Role, - peer_address_type : AddressType, - peer_address : Address, - conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) - conn_latency : 16, // Number of connection events - supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) - central_clock_accuracy : ClockAccuracy, -} - -enum AdvertisingEventType : 8 { - ADV_IND = 0x00, - ADV_DIRECT_IND = 0x01, - ADV_SCAN_IND = 0x02, - ADV_NONCONN_IND = 0x03, - SCAN_RESPONSE = 0x04, -} - -struct LeAdvertisingResponse { - event_type : AdvertisingEventType, - address_type : AddressType, - address : Address, - _size_(advertising_data) : 8, - advertising_data : LengthAndData[], - rssi : 8, -} - -packet LeAdvertisingReport : LeMetaEvent (subevent_code = ADVERTISING_REPORT) { - _count_(responses) : 8, - responses : LeAdvertisingResponse[], + _reserved_ : 8, + total_scan_results_storage: 16, + max_irk_list_sz: 8, + filtering_support: 8, + max_filter: 8, + activity_energy_info_support: 8, + _fixed_ = 0x0301 : 16, // v1.03 + total_num_of_advt_tracked: 16, + extended_scan_support: 8, + debug_logging_supported: 8, + _reserved_ : 8, + a2dp_source_offload_capability_mask: 32, + bluetooth_quality_report_support: 8, + dynamic_audio_buffer_support: 32, } -struct LeAdvertisingResponseRaw { - event_type : AdvertisingEventType, - address_type : AddressType, - address : Address, - _size_(advertising_data) : 8, - advertising_data : 8[], - rssi : 8, -} +// ----------------------------------------------------------------------------- +// LE Batch Scan Command +// https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le_batch_scan_command +// https://source.android.com/docs/core/connect/bluetooth/hci_requirements#storage-threshold-breach-subevent +// ----------------------------------------------------------------------------- -packet LeAdvertisingReportRaw : LeMetaEvent (subevent_code = ADVERTISING_REPORT) { - _count_(responses) : 8, - responses : LeAdvertisingResponseRaw[], +enum BatchScanOpcode : 8 { + ENABLE = 0x01, + SET_STORAGE_PARAMETERS = 0x02, + SET_SCAN_PARAMETERS = 0x03, + READ_RESULT_PARAMETERS = 0x04, } -packet LeConnectionUpdateComplete : LeMetaEvent (subevent_code = CONNECTION_UPDATE_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) - conn_latency : 16, // Number of connection events - supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) +packet LeBatchScan : Command (op_code = LE_BATCH_SCAN) { + batch_scan_opcode : BatchScanOpcode, + _body_, } -packet LeReadRemoteFeaturesComplete : LeMetaEvent (subevent_code = READ_REMOTE_FEATURES_COMPLETE) { +packet LeBatchScanComplete : CommandComplete (command_op_code = LE_BATCH_SCAN) { status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - le_features : 64, + batch_scan_opcode : BatchScanOpcode, + _body_, } -packet LeLongTermKeyRequest : LeMetaEvent (subevent_code = LONG_TERM_KEY_REQUEST) { - connection_handle : 12, - _reserved_ : 4, - random_number : 8[8], - encrypted_diversifier : 16, +packet LeBatchScanEnable : LeBatchScan (batch_scan_opcode = ENABLE) { + enable : Enable, } -packet LeRemoteConnectionParameterRequest : LeMetaEvent (subevent_code = REMOTE_CONNECTION_PARAMETER_REQUEST) { - connection_handle : 12, - _reserved_ : 4, - interval_min : 16, // 0x006 - 0x0C80 (7.5ms - 4s) - interval_max : 16, // 0x006 - 0x0C80 (7.5ms - 4s) - latency : 16, // Number of connection events (0x0000 to 0x01f3 (499) - timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) +packet LeBatchScanEnableComplete : LeBatchScanComplete (batch_scan_opcode = ENABLE) { } -packet LeDataLengthChange : LeMetaEvent (subevent_code = DATA_LENGTH_CHANGE) { - connection_handle : 12, - _reserved_ : 4, - max_tx_octets : 16, // 0x001B - 0x00FB - max_tx_time : 16, // 0x0148 - 0x4290 - max_rx_octets : 16, // 0x001B - 0x00FB - max_rx_time : 16, // 0x0148 - 0x4290 +packet LeBatchScanSetStorageParameters : LeBatchScan (batch_scan_opcode = SET_STORAGE_PARAMETERS) { + batch_scan_full_max_percentage : 8, + batch_scan_truncated_max_percentage : 8, + batch_scan_notify_threshold_percentage : 8, } -packet ReadLocalP256PublicKeyComplete : LeMetaEvent (subevent_code = READ_LOCAL_P256_PUBLIC_KEY_COMPLETE) { - status : ErrorCode, - local_p_256_public_key : 8[64], +packet LeBatchScanSetStorageParametersComplete : LeBatchScanComplete (batch_scan_opcode = SET_STORAGE_PARAMETERS) { } -packet GenerateDhKeyComplete : LeMetaEvent (subevent_code = GENERATE_DHKEY_COMPLETE) { - status : ErrorCode, - dh_key : 8[32], +enum BatchScanDiscardRule : 8 { + OLDEST = 0x00, + WEAKEST_RSSI = 0x01, } -packet LeEnhancedConnectionComplete : LeMetaEvent (subevent_code = ENHANCED_CONNECTION_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - role : Role, - peer_address_type : AddressType, - peer_address : Address, - local_resolvable_private_address : Address, - peer_resolvable_private_address : Address, - conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms) - conn_latency : 16, // Number of connection events - supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s) - central_clock_accuracy : ClockAccuracy, +packet LeBatchScanSetScanParameters : LeBatchScan (batch_scan_opcode = SET_SCAN_PARAMETERS) { + truncated_mode_enabled : 1, + full_mode_enabled : 1, + _reserved_ : 6, + duty_cycle_scan_window_slots : 32, + duty_cycle_scan_interval_slots : 32, + own_address_type : PeerAddressType, + batch_scan_discard_rule : BatchScanDiscardRule, } -enum DirectAdvertisingAddressType : 8 { - PUBLIC_DEVICE_ADDRESS = 0x00, - RANDOM_DEVICE_ADDRESS = 0x01, - PUBLIC_IDENTITY_ADDRESS = 0x02, - RANDOM_IDENTITY_ADDRESS = 0x03, - CONTROLLER_UNABLE_TO_RESOLVE = 0xFE, - NO_ADDRESS_PROVIDED = 0xFF, +packet LeBatchScanSetScanParametersComplete : LeBatchScanComplete (batch_scan_opcode = SET_SCAN_PARAMETERS) { } -enum DirectAdvertisingEventType : 8 { - ADV_DIRECT_IND = 0x01, +enum BatchScanDataRead : 8 { + TRUNCATED_MODE_DATA = 0x01, + FULL_MODE_DATA = 0x02, } -enum DirectAddressType : 8 { - RANDOM_DEVICE_ADDRESS = 0x01, +packet LeBatchScanReadResultParameters : LeBatchScan (batch_scan_opcode = READ_RESULT_PARAMETERS) { + batch_scan_data_read : BatchScanDataRead, } -struct LeDirectedAdvertisingResponse { - event_type : DirectAdvertisingEventType, - address_type : DirectAdvertisingAddressType, - address : Address, - direct_address_type : DirectAddressType, - direct_address : Address, - rssi : 8, +packet LeBatchScanReadResultParametersCompleteRaw : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) { + batch_scan_data_read : BatchScanDataRead, + num_of_records : 8, + raw_data : 8[], } -packet LeDirectedAdvertisingReport : LeMetaEvent (subevent_code = DIRECTED_ADVERTISING_REPORT) { - _count_(responses) : 8, - responses : LeDirectedAdvertisingResponse[], +packet LeBatchScanReadResultParametersComplete : LeBatchScanComplete (batch_scan_opcode = READ_RESULT_PARAMETERS) { + batch_scan_data_read : BatchScanDataRead, + _body_, } -packet LePhyUpdateComplete : LeMetaEvent (subevent_code = PHY_UPDATE_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - tx_phy : PhyType, - rx_phy : PhyType, +struct TruncatedResult { + bd_addr : Address, + address_type : AddressType, + tx_power : 8, + rssi : 8, + timestamp : 16, } -enum DataStatus : 2 { - COMPLETE = 0x0, - CONTINUING = 0x1, - TRUNCATED = 0x2, - RESERVED = 0x3, +packet LeBatchScanReadTruncatedResultParametersComplete : LeBatchScanReadResultParametersComplete (batch_scan_data_read = TRUNCATED_MODE_DATA) { + _count_(results) : 8, + results : TruncatedResult[], } -struct LeExtendedAdvertisingResponse { - connectable : 1, - scannable : 1, - directed : 1, - scan_response : 1, - legacy : 1, - data_status : DataStatus, - _reserved_ : 9, - address_type : DirectAdvertisingAddressType, - address : Address, - primary_phy : PrimaryPhyType, - secondary_phy : SecondaryPhyType, - advertising_sid : 8, // SID subfield in the ADI field +struct FullResult { + bd_addr : Address, + address_type : AddressType, tx_power : 8, - rssi : 8, // -127 to +20 (0x7F means not available) - periodic_advertising_interval : 16, // 0x006 to 0xFFFF (7.5 ms to 82s) - direct_address_type : DirectAdvertisingAddressType, - direct_address : Address, - _size_(advertising_data) : 8, - advertising_data: LengthAndData[], + rssi : 8, + timestamp : 16, + _size_(adv_packet) : 8, + adv_packet : 8[], + _size_(scan_response) : 8, + scan_response : 8[], } -struct LeExtendedAdvertisingResponseRaw { - connectable : 1, - scannable : 1, - directed : 1, - scan_response : 1, - legacy : 1, - data_status : DataStatus, - _reserved_ : 9, - address_type : DirectAdvertisingAddressType, - address : Address, - primary_phy : PrimaryPhyType, - secondary_phy : SecondaryPhyType, - advertising_sid : 8, // SID subfield in the ADI field - tx_power : 8, - rssi : 8, // -127 to +20 (0x7F means not available) - periodic_advertising_interval : 16, // 0x006 to 0xFFFF (7.5 ms to 82s) - direct_address_type : DirectAdvertisingAddressType, - direct_address : Address, - _size_(advertising_data) : 8, - advertising_data: 8[], +packet LeBatchScanReadFullResultParametersComplete : LeBatchScanReadResultParametersComplete (batch_scan_data_read = FULL_MODE_DATA) { + _count_(results) : 8, + results : FullResult[], } -packet LeExtendedAdvertisingReportRaw : LeMetaEvent (subevent_code = EXTENDED_ADVERTISING_REPORT) { - _count_(responses) : 8, - responses : LeExtendedAdvertisingResponseRaw[], +packet StorageThresholdBreachEvent : VendorSpecificEvent (subevent_code = STORAGE_THRESHOLD_BREACH) { } -packet LeExtendedAdvertisingReport : LeMetaEvent (subevent_code = EXTENDED_ADVERTISING_REPORT) { - _count_(responses) : 8, - responses : LeExtendedAdvertisingResponse[], +// ----------------------------------------------------------------------------- +// Advertising Packet Content Filter (APCF) Command. +// https://source.android.com/docs/core/connect/bluetooth/hci_requirements#advertising-packet-content-filter +// https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le-advertisement-tracking-sub-event +// ----------------------------------------------------------------------------- + +enum ApcfOpcode : 8 { + ENABLE = 0x00, + SET_FILTERING_PARAMETERS = 0x01, + BROADCASTER_ADDRESS = 0x02, + SERVICE_UUID = 0x03, + SERVICE_SOLICITATION_UUID = 0x04, + LOCAL_NAME = 0x05, + MANUFACTURER_DATA = 0x06, + SERVICE_DATA = 0x07, + TRANSPORT_DISCOVERY_SERVICE = 0x08, + AD_TYPE_FILTER = 0x09, + READ_EXTENDED_FEATURES = 0xFF, } -packet LePeriodicAdvertisingSyncEstablished : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_ESTABLISHED) { - status : ErrorCode, - sync_handle : 12, - _reserved_ : 4, - advertising_sid : 8, - advertiser_address_type : AddressType, - advertiser_address : Address, - advertiser_phy : SecondaryPhyType, - periodic_advertising_interval : 16, - advertiser_clock_accuracy : ClockAccuracy, +packet LeApcf : Command (op_code = LE_APCF) { + apcf_opcode : ApcfOpcode, + _payload_, } -packet LePeriodicAdvertisingReport : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_REPORT) { - sync_handle : 12, - _reserved_ : 4, - tx_power : 8, - rssi : 8, - cte_type : CteType, - data_status : DataStatus, - _reserved_: 6, - _size_(data) : 8, - data : 8[], +packet LeApcfComplete : CommandComplete (command_op_code = LE_APCF) { + status : ErrorCode, + apcf_opcode : ApcfOpcode, + _payload_ } -packet LePeriodicAdvertisingSyncLost : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_LOST) { - sync_handle : 12, - _reserved_ : 4, +packet LeApcfEnable : LeApcf (apcf_opcode = ENABLE) { + apcf_enable : Enable, } -packet LeScanTimeout : LeMetaEvent (subevent_code = SCAN_TIMEOUT) { +packet LeApcfEnableComplete : LeApcfComplete (apcf_opcode = ENABLE) { + apcf_enable : Enable, } -packet LeAdvertisingSetTerminated : LeMetaEvent (subevent_code = ADVERTISING_SET_TERMINATED) { - status : ErrorCode, - advertising_handle : 8, - connection_handle : 12, - _reserved_ : 4, - num_completed_extended_advertising_events : 8, +enum ApcfAction : 8 { + ADD = 0x00, + DELETE = 0x01, + CLEAR = 0x02, } -packet LeScanRequestReceived : LeMetaEvent (subevent_code = SCAN_REQUEST_RECEIVED) { - advertising_handle : 8, - scanner_address_type : AddressType, - scanner_address : Address, +enum DeliveryMode : 8 { + IMMEDIATE = 0x00, + ONFOUND = 0x01, + BATCHED = 0x02, } -enum ChannelSelectionAlgorithm : 8 { - ALGORITHM_1 = 0, - ALGORITHM_2 = 1, +// Bit mask for the APCF Feature Selection field. +enum ApcfFeatureSelection : 8 { + BROADCASTER_ADDRESS = 0x00, + SERVICE_DATA_CHANGE = 0x01, + SERVICE_UUID = 0x02, + SERVICE_SOLICITATION_UUID = 0x03, + LOCAL_NAME = 0x04, + MANUFACTURER_DATA = 0x05, + SERVICE_DATA = 0x06, + TRANSPORT_DISCOVERY_DATA = 0x07, + AD_TYPE = 0x08, } -packet LeChannelSelectionAlgorithm : LeMetaEvent (subevent_code = CHANNEL_SELECTION_ALGORITHM) { - connection_handle : 12, - _reserved_ : 4, - channel_selection_algorithm : ChannelSelectionAlgorithm, +packet LeApcfSetFilteringParameters : LeApcf (apcf_opcode = SET_FILTERING_PARAMETERS) { + apcf_action : ApcfAction, + _payload_, } -packet LeConnectionlessIqReport : LeMetaEvent (subevent_code = CONNECTIONLESS_IQ_REPORT) { - _payload_, // placeholder (unimplemented) +packet LeApcfAddFilteringParameters : LeApcfSetFilteringParameters (apcf_action = ADD) { + apcf_filter_index : 8, + apcf_feature_selection : 16, + apcf_list_logic_type : 16, + apcf_filter_logic_type : 8, + rssi_high_thresh : 8, + delivery_mode : DeliveryMode, + onfound_timeout : 16, + onfound_timeout_cnt : 8, + rssi_low_thresh : 8, + onlost_timeout : 16, + num_of_tracking_entries : 16, } -packet LeConnectionIqReport : LeMetaEvent (subevent_code = CONNECTION_IQ_REPORT) { - _payload_, // placeholder (unimplemented) +packet LeApcfDeleteFilteringParameters : LeApcfSetFilteringParameters (apcf_action = DELETE) { + apcf_filter_index : 8, } -packet LeCteRequestFailed : LeMetaEvent (subevent_code = CTE_REQUEST_FAILED) { - _payload_, // placeholder (unimplemented) +packet LeApcfClearFilteringParameters : LeApcfSetFilteringParameters (apcf_action = CLEAR) { } -packet LePeriodicAdvertisingSyncTransferReceived : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - service_data : 16, - sync_handle : 12, - _reserved_ : 4, - advertising_sid : 4, - _reserved_ : 4, - advertiser_address_type : AddressType, - advertiser_address : Address, - advertiser_phy : SecondaryPhyType, - periodic_advertising_interval : 16, - advertiser_clock_accuracy : ClockAccuracy, +packet LeApcfSetFilteringParametersComplete : LeApcfComplete (apcf_opcode = SET_FILTERING_PARAMETERS) { + apcf_action : ApcfAction, + apcf_available_spaces : 8, } -packet LeCisEstablished : LeMetaEvent (subevent_code = CIS_ESTABLISHED) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - cig_sync_delay : 24, - cis_sync_delay : 24, - transport_latency_m_to_s : 24, - transport_latency_s_to_m : 24, - phy_m_to_s : SecondaryPhyType, - phy_s_to_m : SecondaryPhyType, - nse : 8, - bn_m_to_s : 4, - _reserved_ : 4, - bn_s_to_m : 4, - _reserved_ : 4, - ft_m_to_s : 8, - ft_s_to_m : 8, - max_pdu_m_to_s : 8, - _reserved_ : 8, - max_pdu_s_to_m : 8, - _reserved_ : 8, - iso_interval : 16, +enum ApcfApplicationAddressType : 8 { + PUBLIC = 0x00, + RANDOM = 0x01, + NOT_APPLICABLE = 0x02, } -packet LeCisRequest : LeMetaEvent (subevent_code = CIS_REQUEST) { - acl_connection_handle : 12, - _reserved_ : 4, - cis_connection_handle : 12, - _reserved_ : 4, - cig_id : 8, - cis_id : 8, +packet LeApcfBroadcasterAddress : LeApcf (apcf_opcode = BROADCASTER_ADDRESS) { + apcf_action : ApcfAction, + _payload_, } -packet LeCreateBigComplete : LeMetaEvent (subevent_code = CREATE_BIG_COMPLETE) { - status : ErrorCode, - big_handle : 8, - big_sync_delay : 24, - transport_latency_big: 24, - phy : SecondaryPhyType, - nse : 8, - bn : 8, - pto : 8, - irc : 8, - max_pdu : 16, - iso_interval : 16, - _size_(connection_handle) : 8, - connection_handle : 16[], +packet LeApcfAddBroadcasterAddress : LeApcfBroadcasterAddress (apcf_action = ADD) { + apcf_filter_index : 8, + apcf_broadcaster_address : Address, + apcf_application_address_type : ApcfApplicationAddressType, } -packet LeTerminateBigComplete : LeMetaEvent (subevent_code = TERMINATE_BIG_COMPLETE) { - big_handle : 8, - reason : ErrorCode, +packet LeApcfDeleteBroadcasterAddress : LeApcfBroadcasterAddress (apcf_action = DELETE) { + apcf_filter_index : 8, + apcf_broadcaster_address : Address, + apcf_application_address_type : ApcfApplicationAddressType, } -packet LeBigSyncEstablished : LeMetaEvent (subevent_code = BIG_SYNC_ESTABLISHED) { - status : ErrorCode, - big_handle : 8, - transport_latency_big : 24, - nse : 8, - bn : 8, - pto : 8, - irc : 8, - max_pdu : 16, - iso_interval : 16, - _size_(connection_handle) : 8, - connection_handle : 16[], +packet LeApcfClearBroadcasterAddress : LeApcfBroadcasterAddress (apcf_action = CLEAR) { + apcf_filter_index : 8, } -packet LeBigSyncLost : LeMetaEvent (subevent_code = BIG_SYNC_LOST) { - big_handle : 8, - reason : ErrorCode, +packet LeApcfBroadcasterAddressComplete : LeApcfComplete (apcf_opcode = BROADCASTER_ADDRESS) { + apcf_action : ApcfAction, + apcf_available_spaces : 8, } -packet LeRequestPeerScaComplete : LeMetaEvent (subevent_code = REQUEST_PEER_SCA_COMPLETE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - peer_clock_accuracy : ClockAccuracy, +packet LeApcfServiceUuid : LeApcf (apcf_opcode = SERVICE_UUID) { + apcf_action : ApcfAction, + apcf_filter_index : 8, + acpf_uuid_data : 8[], } -enum PathLossZone : 8 { - LOW = 0, - MID = 1, - HIGH = 2, +packet LeApcfServiceUuidComplete : LeApcfComplete (apcf_opcode = SERVICE_UUID) { + apcf_action : ApcfAction, + apcf_available_spaces : 8, } -packet LePathLossThreshold : LeMetaEvent (subevent_code = PATH_LOSS_THRESHOLD) { - connection_handle : 12, - _reserved_ : 4, - current_path_loss : 8, - zone_entered : PathLossZone, +packet LeApcfServiceSolicitationUuid : LeApcf (apcf_opcode = SERVICE_SOLICITATION_UUID) { + apcf_action : ApcfAction, + apcf_filter_index : 8, + acpf_uuid_data : 8[], } -enum ReportingReason : 8 { - LOCAL_TRANSMIT_POWER_CHANGED = 0x00, - REMOTE_TRANSMIT_POWER_CHANGED = 0x01, - READ_COMMAND_COMPLETE = 0x02, +packet LeApcfServiceSolicitationUuidComplete : LeApcfComplete (apcf_opcode = SERVICE_SOLICITATION_UUID) { + apcf_action : ApcfAction, + apcf_available_spaces : 8, } -packet LeTransmitPowerReporting : LeMetaEvent (subevent_code = TRANSMIT_POWER_REPORTING) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - reason : ReportingReason, - phy : 8, - transmit_power_level : 8, - transmit_power_level_flag : 8, - delta : 8, +packet LeApcfLocalName : LeApcf (apcf_opcode = LOCAL_NAME) { + apcf_action : ApcfAction, + apcf_filter_index : 8, + apcf_local_name : 8[], } -packet LeBigInfoAdvertisingReport : LeMetaEvent (subevent_code = BIG_INFO_ADVERTISING_REPORT) { - sync_handle : 12, - _reserved_ : 4, - num_bis : 8, - nse : 8, - iso_interval : 16, - bn : 8, - pto : 8, - irc : 8, - max_pdu : 16, - sdu_interval : 24, - max_sdu : 16, - phy : SecondaryPhyType, - framing : Enable, - encryption : Enable, +packet LeApcfLocalNameComplete : LeApcfComplete (apcf_opcode = LOCAL_NAME) { + apcf_action : ApcfAction, + apcf_available_spaces : 8, } -packet LeSubrateChange : LeMetaEvent (subevent_code = LE_SUBRATE_CHANGE) { - status : ErrorCode, - connection_handle : 12, - _reserved_ : 4, - subrate_factor : 9, - _reserved_ : 7, - peripheral_latency : 9, - _reserved_ : 7, - continuation_number : 9, - _reserved_ : 7, - supervision_timeout: 12, - _reserved_ : 4, +packet LeApcfManufacturerData : LeApcf (apcf_opcode = MANUFACTURER_DATA) { + apcf_action : ApcfAction, + apcf_filter_index : 8, + apcf_manufacturer_data : 8[], } -// Vendor specific events - -packet VendorSpecificEvent : Event (event_code = VENDOR_SPECIFIC) { - subevent_code : VseSubeventCode, - _payload_, +packet LeApcfManufacturerDataComplete : LeApcfComplete (apcf_opcode = MANUFACTURER_DATA) { + apcf_action : ApcfAction, + apcf_available_spaces : 8, } -packet StorageThresholdBreachEvent : VendorSpecificEvent (subevent_code = BLE_THRESHOLD) { +packet LeApcfServiceData : LeApcf (apcf_opcode = SERVICE_DATA) { + apcf_action : ApcfAction, + apcf_filter_index : 8, + apcf_service_data : 8[], } -enum AdvtInfoPresent : 8 { - ADVT_INFO_PRESENT = 0x00, - NO_ADVT_INFO_PRESENT = 0x01, +packet LeApcfServiceDataComplete : LeApcfComplete (apcf_opcode = SERVICE_DATA) { + apcf_action : ApcfAction, + apcf_available_spaces : 8, } -packet LEAdvertisementTrackingEvent : VendorSpecificEvent (subevent_code = BLE_TRACKING) { +packet LeApcfAdTypeFilter : LeApcf (apcf_opcode = AD_TYPE_FILTER) { + apcf_action : ApcfAction, apcf_filter_index : 8, - advertiser_state : 8, - advt_info_present : AdvtInfoPresent, - advertiser_address : Address, - advertiser_address_type : 8, - _body_, + apcf_ad_type : 8, + _size_(apcf_ad_data) : 8, + apcf_ad_data : 8[], + apcf_ad_data_mask : 8[], } -enum VseStateChangeReason : 8 { - CONNECTION_RECEIVED = 0x00, +packet LeApcfAdTypeFilterComplete : LeApcfComplete (apcf_opcode = AD_TYPE_FILTER) { + apcf_action : ApcfAction, + apcf_available_spaces : 8, } -packet LEAdvertiseStateChangeEvent : VendorSpecificEvent (subevent_code = BLE_STCHANGE) { - advertising_instance : 8, - state_change_reason : VseStateChangeReason, - connection_handle : 12, - _reserved_ : 4, +packet LeApcfReadExtendedFeatures : LeApcf (apcf_opcode = READ_EXTENDED_FEATURES) { } -packet LEAdvertisementTrackingWithInfoEvent : LEAdvertisementTrackingEvent { - tx_power : 8, - rssi : 8, - timestamp : 16, - _size_(adv_packet) : 8, - adv_packet : 8[], - _size_(scan_response) : 8, - scan_response : 8[], +test LeApcfReadExtendedFeatures { + "\x57\xfd\x01\xff", } -enum QualityReportId : 8 { - MONITOR_MODE = 0x01, - APPROACH_LSTO = 0x02, - A2DP_AUDIO_CHOPPY = 0x03, - SCO_VOICE_CHOPPY = 0x04, - ROOT_INFLAMMATION = 0x05, - LMP_LL_MESSAGE_TRACE = 0x11, - BT_SCHEDULING_TRACE = 0x12, - CONTROLLER_DBG_INFO = 0x13, +packet LeApcfReadExtendedFeaturesComplete : LeApcfComplete (apcf_opcode = READ_EXTENDED_FEATURES) { + transport_discovery_data_filter : 1, + ad_type_filter : 1, + _reserved_ : 14, } -packet BqrEvent : VendorSpecificEvent (subevent_code = BQR_EVENT) { - quality_report_id : QualityReportId, - _payload_, +test LeApcfReadExtendedFeaturesComplete { + "\x0e\x07\x01\x57\xfd\x00\xff\x03\x00", } -enum BqrPacketType : 8 { - TYPE_ID = 0x01, - TYPE_NULL = 0x02, - TYPE_POLL = 0x03, - TYPE_FHS = 0x04, - TYPE_HV1 = 0x05, - TYPE_HV2 = 0x06, - TYPE_HV3 = 0x07, - TYPE_DV = 0x08, - TYPE_EV3 = 0x09, - TYPE_EV4 = 0x0A, - TYPE_EV5 = 0x0B, - TYPE_2EV3 = 0x0C, - TYPE_2EV5 = 0x0D, - TYPE_3EV3 = 0x0E, - TYPE_3EV5 = 0x0F, - TYPE_DM1 = 0x10, - TYPE_DH1 = 0x11, - TYPE_DM3 = 0x12, - TYPE_DH3 = 0x13, - TYPE_DM5 = 0x14, - TYPE_DH5 = 0x15, - TYPE_AUX1 = 0x16, - TYPE_2DH1 = 0x17, - TYPE_2DH3 = 0x18, - TYPE_2DH5 = 0x19, - TYPE_3DH1 = 0x1A, - TYPE_3DH3 = 0x1B, - TYPE_3DH5 = 0x1C, -} - -packet BqrLinkQualityEvent : BqrEvent { - packet_type : BqrPacketType, - connection_handle : 12, - _reserved_ : 4, - connection_role : Role, - tx_power_level : 8, - rssi : 8, - snr : 8, - unused_afh_channel_count : 8, - afh_select_unideal_channel_count : 8, - lsto : 16, - connection_piconet_clock : 32, - retransmission_count : 32, - no_rx_count : 32, - nak_count : 32, - last_tx_ack_timestamp : 32, - flow_off_count : 32, - last_flow_on_timestamp : 32, - buffer_overflow_bytes : 32, - buffer_underflow_bytes : 32, - _payload_, +enum AdvertiserState : 8 { + ADVERTISER_FOUND = 0x0, + ADVERTISER_LOST = 0x1, } -packet BqrMonitorModeEvent : BqrLinkQualityEvent (quality_report_id = MONITOR_MODE) { - _payload_, // vendor specific parameter +enum AdvtInfoPresent : 8 { + ADVT_INFO_PRESENT = 0x0, + ADVT_INFO_NOT_PRESENT = 0x1, } -packet BqrApproachLstoEvent : BqrLinkQualityEvent (quality_report_id = APPROACH_LSTO) { - _payload_, // vendor specific parameter +struct AdvtInfo { + tx_power : 8, + rssi : 8, + timestamp : 16, + _size_(adv_packet) : 8, + adv_packet : 8[], + _size_(scan_data_resp) : 8, + scan_data_resp : 8[], } -packet BqrA2dpAudioChoppyEvent : BqrLinkQualityEvent (quality_report_id = A2DP_AUDIO_CHOPPY) { - _payload_, // vendor specific parameter +packet LeAdvertisementTrackingEvent : VendorSpecificEvent (subevent_code = LE_ADVERTISEMENT_TRACKING) { + apcf_filter_index : 8, + advertiser_state : AdvertiserState, + advt_info_present : AdvtInfoPresent, + advertiser_address : Address, + advertiser_address_type : PeerAddressType, + advt_info : AdvtInfo[], } -packet BqrScoVoiceChoppyEvent : BqrLinkQualityEvent (quality_report_id = SCO_VOICE_CHOPPY) { - _payload_, // vendor specific parameter -} +// ----------------------------------------------------------------------------- +// LE Get Controller Activity Energy Info Command +// https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le_get_controller_activity_energy_info +// ----------------------------------------------------------------------------- -packet BqrRootInflammationEvent : BqrEvent (quality_report_id = ROOT_INFLAMMATION) { - error_code : 8, - vendor_specific_error_code : 8, - _payload_, // vendor specific parameter +packet LeGetControllerActivityEnergyInfo : Command (op_code = LE_GET_CONTROLLER_ACTIVITY_ENERGY_INFO) { } -packet BqrLogDumpEvent : BqrEvent { - connection_handle : 12, - _reserved_ : 4, - _payload_, +packet LeGetControllerActivityEnergyInfoComplete : CommandComplete (command_op_code = LE_GET_CONTROLLER_ACTIVITY_ENERGY_INFO) { + status : ErrorCode, + total_tx_time_ms : 32, + total_rx_time_ms : 32, + total_idle_time_ms : 32, + total_energy_used : 32, } -packet BqrLmpLlMessageTraceEvent : BqrLogDumpEvent (quality_report_id = LMP_LL_MESSAGE_TRACE) { - _payload_, // vendor specific parameter -} +// ----------------------------------------------------------------------------- +// LE Extended Set Scan Parameters Command +// https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le-extended-set-scan-parameters-command +// ----------------------------------------------------------------------------- -packet BqrBtSchedulingTraceEvent : BqrLogDumpEvent (quality_report_id = BT_SCHEDULING_TRACE) { - _payload_, // vendor specific parameter +enum LeExScanType : 8 { + PASSIVE = 0x0, + ACTIVE = 0x1, } -packet BqrControllerDbgInfoEvent : BqrLogDumpEvent (quality_report_id = CONTROLLER_DBG_INFO) { - _payload_, // vendor specific parameter +enum LeExScanFilterPolicy : 8 { + ACCEPT_ALL = 0x0, + FILTER_ACCEPT_LIST_ONLY = 0x01, } -// Isochronous Adaptation Layer - -enum IsoPacketBoundaryFlag : 2 { - FIRST_FRAGMENT = 0, - CONTINUATION_FRAGMENT = 1, - COMPLETE_SDU = 2, - LAST_FRAGMENT = 3, +packet LeExSetScanParameters : Command (op_code = LE_EX_SET_SCAN_PARAMETERS) { + le_ex_scan_type : LeExScanType, + le_ex_scan_interval : 32, + le_ex_scan_window : 32, + own_address_type : OwnAddressType, + le_ex_scan_filter_policy : LeExScanFilterPolicy, } -enum TimeStampFlag : 1 { - NOT_PRESENT = 0, - PRESENT = 1, +packet LeExSetScanParametersComplete : CommandComplete (command_op_code = LE_EX_SET_SCAN_PARAMETERS) { + status : ErrorCode, } -packet Iso { - connection_handle : 12, - pb_flag : IsoPacketBoundaryFlag, - ts_flag : TimeStampFlag, - _reserved_ : 1, - _size_(_payload_) : 14, - _reserved_ : 2, - _payload_, -} +// ----------------------------------------------------------------------------- +// Get Controller Debug Info Command +// https://source.android.com/docs/core/connect/bluetooth/hci_requirements#get-controller-debug-info-command +// ----------------------------------------------------------------------------- -enum IsoPacketStatusFlag : 2 { - VALID = 0, - POSSIBLY_INVALID = 1, - LOST_DATA = 2, +packet GetControllerDebugInfo : Command (op_code = GET_CONTROLLER_DEBUG_INFO) { } -packet IsoWithTimestamp : Iso (ts_flag = PRESENT) { - time_stamp : 32, - packet_sequence_number : 16, - _size_(_payload_) : 12, // iso_sdu_length - _reserved_ : 2, - packet_status_flag : IsoPacketStatusFlag, - _payload_, +packet GetControllerDebugInfoComplete : CommandComplete (command_op_code = GET_CONTROLLER_DEBUG_INFO) { + status : ErrorCode, } -packet IsoWithoutTimestamp : Iso (ts_flag = NOT_PRESENT) { - packet_sequence_number : 16, - _size_(_payload_) : 12, // iso_sdu_length - _reserved_ : 2, - packet_status_flag : IsoPacketStatusFlag, - _payload_, +packet ControllerDebugInfoEvent : VendorSpecificEvent (subevent_code = CONTROLLER_DEBUG_INFO) { + debug_block_byte_offset_start : 16, + last_block : 8, + _size_(debug_data) : 16, + debug_data : 8[], } -// MSFT packets -// Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events +// ----------------------------------------------------------------------------- +// Microsoft Commands +// https://learn.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events +// ----------------------------------------------------------------------------- enum MsftSubcommandOpcode : 8 { MSFT_READ_SUPPORTED_FEATURES = 0x00, @@ -6377,7 +6118,7 @@ enum MsftSubcommandOpcode : 8 { MSFT_READ_ABSOLUTE_RSSI = 0x06, } -// MSFT Commands don't have a constant opcode, so leave `op_code` undefined. +// MSFT Commands do not have a constant opcode, so leave `op_code` undefined. packet MsftCommand : Command { subcommand_opcode: MsftSubcommandOpcode, _payload_, diff --git a/tools/rootcanal/packets/link_layer_packets.pdl b/tools/rootcanal/packets/link_layer_packets.pdl index 3a92e39f08907c88b40da2252dcbb50a9183941f..d2fcbfca4fa4f9de54dd720cad51e66c59311852 100644 --- a/tools/rootcanal/packets/link_layer_packets.pdl +++ b/tools/rootcanal/packets/link_layer_packets.pdl @@ -1,12 +1,16 @@ little_endian_packets custom_field Address : 48 "hci/" -custom_field ClassOfDevice : 24 "hci/" enum PacketType : 8 { UNKNOWN = 0x00, ACL = 0x01, - DISCONNECT = 0x02, + SCO = 0x02, + + LE_CONNECTED_ISOCHRONOUS_PDU = 0x03, + LE_BROADCAST_ISOCHRONOUS_PDU = 0x04, + + DISCONNECT = 0x05, INQUIRY = 0x06, INQUIRY_RESPONSE = 0x07, LE_LEGACY_ADVERTISING_PDU = 0x0B, @@ -31,12 +35,8 @@ enum PacketType : 8 { READ_REMOTE_VERSION_INFORMATION_RESPONSE = 0x1C, REMOTE_NAME_REQUEST = 0x1D, REMOTE_NAME_REQUEST_RESPONSE = 0x1E, - SCO = 0x1F, LE_ENCRYPT_CONNECTION = 0x20, LE_ENCRYPT_CONNECTION_RESPONSE = 0x21, - ISO = 0x22, - ISO_CONNECTION_REQUEST = 0x23, - ISO_CONNECTION_RESPONSE = 0x24, LE_READ_REMOTE_FEATURES = 0x2C, LE_READ_REMOTE_FEATURES_RESPONSE = 0x2D, LE_CONNECTION_PARAMETER_REQUEST = 0x2E, @@ -47,6 +47,7 @@ enum PacketType : 8 { SCO_DISCONNECT = 0x32, LMP = 0x34, + LLCP = 0x41, PING_REQUEST = 0x35, PING_RESPONSE = 0x36, @@ -71,6 +72,20 @@ packet Acl : LinkLayerPacket (type = ACL) { data: 8[], } +packet Sco : LinkLayerPacket (type = SCO) { + _payload_, +} + +packet LeConnectedIsochronousPdu : LinkLayerPacket (type = LE_CONNECTED_ISOCHRONOUS_PDU) { + cig_id: 8, + cis_id: 8, + sequence_number: 16, + data: 8[], +} + +packet LeBroadcastIsochronousPdu : LinkLayerPacket (type = LE_BROADCAST_ISOCHRONOUS_PDU) { +} + packet Disconnect : LinkLayerPacket (type = DISCONNECT) { reason : 8, } @@ -94,7 +109,7 @@ packet Inquiry : LinkLayerPacket (type = INQUIRY) { packet BasicInquiryResponse : LinkLayerPacket(type = INQUIRY_RESPONSE) { inquiry_type : InquiryType, page_scan_repetition_mode : 8, - class_of_device : ClassOfDevice, + class_of_device : 24, clock_offset : 15, _reserved_ : 1, _body_, @@ -197,7 +212,7 @@ packet LeScanResponse : LinkLayerPacket (type = LE_SCAN_RESPONSE) { } packet Page : LinkLayerPacket (type = PAGE) { - class_of_device : ClassOfDevice, + class_of_device : 24, allow_role_switch : 8, } @@ -257,10 +272,6 @@ packet RemoteNameRequestResponse : LinkLayerPacket (type = REMOTE_NAME_REQUEST_R name : 8[248], } -packet Sco : LinkLayerPacket (type = SCO) { - _payload_, -} - packet LeEncryptConnection : LinkLayerPacket (type = LE_ENCRYPT_CONNECTION) { rand : 8[8], ediv : 16, @@ -273,67 +284,6 @@ packet LeEncryptConnectionResponse : LinkLayerPacket (type = LE_ENCRYPT_CONNECTI ltk : 8[16], } -enum StartContinuation : 1 { - START = 0, - CONTINUATION = 1, -} - -enum Complete : 1 { - INCOMPLETE = 0, - COMPLETE = 1, -} - -packet IsoDataPacket : LinkLayerPacket (type = ISO) { - handle : 12, - _reserved_ : 4, - sc : StartContinuation, - cmplt : Complete, - _reserved_ : 6, - _size_(_payload_) : 16, - _payload_, -} - -packet IsoStart : IsoDataPacket (sc = START) { - time_offset : 24, - _payload_, -} - -packet IsoContinuation : IsoDataPacket (sc = CONTINUATION) { - _payload_, -} - -packet IsoConnectionRequest : LinkLayerPacket (type = ISO_CONNECTION_REQUEST) { - // Group - cig_id : 8, - sdu_interval_m_to_s : 32, - sdu_interval_s_to_m : 32, - interleaved : 1, - framed : 1, - _reserved_ : 6, - latency_m_to_s : 16, - latency_s_to_m : 16, - // Stream parameters - id : 8, - max_sdu_m_to_s_ : 16, - max_sdu_s_to_m_ : 16, - // For the response - requester_cis_handle : 12, - _reserved_ : 4, - requester_acl_handle : 12, - _reserved_ : 4, -} - -packet IsoConnectionResponse : LinkLayerPacket (type = ISO_CONNECTION_RESPONSE){ - status : 8, // ErrorCode (SUCCESS == connected) - requester_cis_handle : 12, - _reserved_ : 4, - requester_acl_handle : 12, - _reserved_ : 4, - // For the link layer - responder_cis_handle : 12, - _reserved_ : 4, -} - enum PasskeyNotificationType : 8 { ENTRY_STARTED = 0x00, DIGIT_ENTERED = 0x01, @@ -372,7 +322,7 @@ packet ScoConnectionRequest : LinkLayerPacket (type = SCO_CONNECTION_REQUEST) { _reserved_ : 6, retransmission_effort : 8, packet_type : 16, - class_of_device : ClassOfDevice, + class_of_device : 24, } packet ScoConnectionResponse : LinkLayerPacket (type = SCO_CONNECTION_RESPONSE) { @@ -394,6 +344,10 @@ packet Lmp : LinkLayerPacket (type = LMP) { _payload_, } +packet Llcp : LinkLayerPacket (type = LLCP) { + _payload_, +} + packet PingRequest : LinkLayerPacket (type = PING_REQUEST) { } @@ -401,12 +355,10 @@ packet PingResponse : LinkLayerPacket (type = PING_RESPONSE) { } packet RoleSwitchRequest : LinkLayerPacket (type = ROLE_SWITCH_REQUEST) { - initiator_new_role: 8, } packet RoleSwitchResponse : LinkLayerPacket (type = ROLE_SWITCH_RESPONSE) { status: 8, - initiator_new_role: 8, } packet LlPhyReq : LinkLayerPacket (type = LL_PHY_REQ) { diff --git a/tools/rootcanal/proto/Android.bp b/tools/rootcanal/proto/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..ebe45e9a2c5099f25aa42e9df526484a983f479c --- /dev/null +++ b/tools/rootcanal/proto/Android.bp @@ -0,0 +1,25 @@ +filegroup { + name: "rootcanal-protos", + srcs: [ + "rootcanal/configuration.proto", + ], +} + +// This library contains the generated headers for the +// RootCanal configuration file / parameter. +cc_library_static { + name: "librootcanal_config", + host_supported: true, + vendor_available: true, + proto: { + export_proto_headers: true, + canonical_path_from_root: false, + include_dirs: [ + "packages/modules/Bluetooth/tools/rootcanal/proto", + ], + }, + shared_libs: [ + "libprotobuf-cpp-full", + ], + srcs: [":rootcanal-protos"], +} diff --git a/tools/rootcanal/proto/rootcanal/configuration.proto b/tools/rootcanal/proto/rootcanal/configuration.proto new file mode 100644 index 0000000000000000000000000000000000000000..0b6db15c897792275be066b248ad5ebaa276ea6a --- /dev/null +++ b/tools/rootcanal/proto/rootcanal/configuration.proto @@ -0,0 +1,88 @@ +// Copyright 2023 Google LLC +// +// 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 +// +// https://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 = "proto2"; + +package rootcanal.configuration; +option optimize_for = CODE_SIZE; + +enum ControllerPreset { + // Version 5.3, all features enabled, all quirks disabled. + DEFAULT = 0; + // Official PTS dongle, Laird BL654. + LAIRD_BL654 = 1; + // Official PTS dongle, CSR rck. + CSR_RCK_PTS_DONGLE = 2; +} + +message ControllerFeatures { + optional bool le_extended_advertising = 1; + optional bool le_periodic_advertising = 2; + optional bool ll_privacy = 3; + optional bool le_2m_phy = 4; + optional bool le_coded_phy = 5; + // Enable the support for both LL Connected Isochronous Stream Central + // and LL Connected Isochronous Stream Peripheral. + optional bool le_connected_isochronous_stream = 6; +} + +message ControllerQuirks { + // Randomly send ACL payloads before the Connection Complete event + // is sent to the Host stack. + optional bool send_acl_data_before_connection_complete = 1; + // Configure a default value for the LE random address. + optional bool has_default_random_address = 2; + // Send an Hardware Error event if any command is called before HCI Reset. + optional bool hardware_error_before_reset = 3; +} + +message VendorFeatures { + // Enable the support for the CSR vendor command. + optional bool csr = 1; + // Enable the support for Android vendor commands. + // Note: not all required vendor commands are necessarily implemented + // in RootCanal, unimplemented commands will return a Command Status or + // Command Complete HCI event with the status Unsupported Opcode. + optional bool android = 2; +} + +message Controller { + // Configure the controller preset. Presets come with a pre-selection + // of features and quirks, but these can be overridden with the next fields. + optional ControllerPreset preset = 1; + // Configure support for controller features. + optional ControllerFeatures features = 2; + // Enable controller quirks. + // Quirks are behaviors observed in real controllers that are not valid + // according to the specification. + optional ControllerQuirks quirks = 3; + // Enable strict mode (defaults to enabled). + // Activate assertion checks in RootCanal for missing RootCanal features + // or Host stack misbehavior. + optional bool strict = 4; + // Configure support for vendor features. + optional VendorFeatures vendor = 5; +} + +message TcpServer { + // Configure the TCP port on which the controller with this defined + // configuration will be served. + required int32 tcp_port = 1; + // Controller configuration for this port. + optional Controller configuration = 2; +} + +message Configuration { + repeated TcpServer tcp_server = 1; +} diff --git a/tools/rootcanal/py/bluetooth.py b/tools/rootcanal/py/bluetooth.py index 0244333722777919f3113fb671d016b36a2d65e0..d216bbe5495e25e3b859eae2c41f05452cd91c91 100644 --- a/tools/rootcanal/py/bluetooth.py +++ b/tools/rootcanal/py/bluetooth.py @@ -1,3 +1,17 @@ +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from dataclasses import dataclass, field from typing import Tuple @@ -51,16 +65,19 @@ class Address: @dataclass class ClassOfDevice: + class_of_device: int = 0 def parse(span: bytes) -> Tuple['Address', bytes]: - assert False + assert len(span) >= 3 + return (ClassOfDevice(int.from_bytes(span[:3], byteorder='little')), span[3:]) def parse_all(span: bytes) -> 'Address': - assert False + assert len(span) == 3 + return ClassOfDevice(int.from_bytes(span, byteorder='little')) def serialize(self) -> bytes: - assert False + return int.to_bytes(self.class_of_device, length=3, byteorder='little') @property def size(self) -> int: - assert False + return 3 diff --git a/tools/rootcanal/py/controller.py b/tools/rootcanal/py/controller.py index f0a43d77dcb5019c62be9d692d660d3db041216f..b4bbecaac0b77ac22f01d11a400329617f73631a 100644 --- a/tools/rootcanal/py/controller.py +++ b/tools/rootcanal/py/controller.py @@ -1,8 +1,23 @@ +# Copyright 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import asyncio import collections import enum import hci_packets as hci import link_layer_packets as ll +import llcp_packets as llcp import py.bluetooth import sys import typing @@ -81,9 +96,11 @@ class Controller: self.address = address self.evt_queue = collections.deque() self.acl_queue = collections.deque() + self.iso_queue = collections.deque() self.ll_queue = collections.deque() self.evt_queue_event = asyncio.Event() self.acl_queue_event = asyncio.Event() + self.iso_queue_event = asyncio.Event() self.ll_queue_event = asyncio.Event() def __del__(self): @@ -98,8 +115,12 @@ class Controller: print(f"<-- received HCI ACL packet data={len(packet)}[..]") self.acl_queue.append(packet) self.acl_queue_event.set() + elif idc == Idc.Iso: + print(f"<-- received HCI ISO packet data={len(packet)}[..]") + self.iso_queue.append(packet) + self.iso_queue_event.set() else: - print(f"ignoring HCI packet typ={typ}") + print(f"ignoring HCI packet typ={idc}") def receive_ll_(self, packet: bytes, phy: int, tx_power: int): print(f"<-- received LL pdu data={len(packet)}[..]") @@ -111,12 +132,31 @@ class Controller: data = cmd.serialize() rootcanal.ffi_controller_receive_hci(c_void_p(self.instance), c_int(Idc.Cmd), c_char_p(data), c_int(len(data))) + def send_iso(self, iso: hci.Iso): + print(f"--> sending HCI iso pdu data={len(iso.payload)}[..]") + data = iso.serialize() + rootcanal.ffi_controller_receive_hci(c_void_p(self.instance), c_int(Idc.Iso), c_char_p(data), c_int(len(data))) + def send_ll(self, pdu: ll.LinkLayerPacket, phy: Phy = Phy.LowEnergy, rssi: int = -90): print(f"--> sending LL pdu {pdu.__class__.__name__}") data = pdu.serialize() rootcanal.ffi_controller_receive_ll(c_void_p(self.instance), c_char_p(data), c_int(len(data)), c_int(phy), c_int(rssi)) + def send_llcp(self, + source_address: hci.Address, + destination_address: hci.Address, + pdu: llcp.LlcpPacket, + phy: Phy = Phy.LowEnergy, + rssi: int = -90): + print(f"--> sending LLCP pdu {pdu.__class__.__name__}") + ll_pdu = ll.Llcp(source_address=source_address, + destination_address=destination_address, + payload=pdu.serialize()) + data = ll_pdu.serialize() + rootcanal.ffi_controller_receive_ll(c_void_p(self.instance), c_char_p(data), c_int(len(data)), c_int(phy), + c_int(rssi)) + async def start(self): async def timer(): @@ -138,6 +178,13 @@ class Controller: evt.show() raise Exception("evt queue not empty at stop()") + if self.iso_queue: + print("iso queue not empty at stop():") + for packet in self.iso_queue: + iso = hci.Iso.parse_all(packet) + iso.show() + raise Exception("ll queue not empty at stop()") + if self.ll_queue: for (packet, _) in self.ll_queue: pdu = ll.LinkLayerPacket.parse_all(packet) @@ -150,6 +197,12 @@ class Controller: self.evt_queue_event.clear() return self.evt_queue.popleft() + async def receive_iso(self): + while not self.iso_queue: + await self.iso_queue_event.wait() + self.iso_queue_event.clear() + return self.iso_queue.popleft() + async def expect_evt(self, expected_evt: hci.Event): packet = await self.receive_evt() evt = hci.Event.parse_all(packet) @@ -238,6 +291,18 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase): assert evt.num_hci_command_packets == 1 return evt + async def expect_iso(self, expected_iso: hci.Iso, timeout: int = 3): + packet = await asyncio.wait_for(self.controller.receive_iso(), timeout=timeout) + iso = hci.Iso.parse_all(packet) + + if iso != expected_iso: + print("received unexpected iso packet") + print("expected packet:") + expected_iso.show() + print("received packet:") + iso.show() + self.assertTrue(False) + async def expect_ll(self, expected_pdus: typing.Union[list, typing.Union[ll.LinkLayerPacket, type]], timeout: int = 3) -> ll.LinkLayerPacket: @@ -265,5 +330,152 @@ class ControllerTest(unittest.IsolatedAsyncioTestCase): self.assertTrue(False) + async def expect_llcp(self, + source_address: hci.Address, + destination_address: hci.Address, + expected_pdu: llcp.LlcpPacket, + timeout: int = 3) -> llcp.LlcpPacket: + packet = await asyncio.wait_for(self.controller.receive_ll(), timeout=timeout) + pdu = ll.LinkLayerPacket.parse_all(packet) + + if (pdu.type != ll.PacketType.LLCP or pdu.source_address != source_address or + pdu.destination_address != destination_address): + print("received unexpected pdu:") + pdu.show() + print(f"expected pdu: {source_address} -> {destination_address}") + expected_pdu.show() + self.assertTrue(False) + + pdu = llcp.LlcpPacket.parse_all(pdu.payload) + if pdu != expected_pdu: + print("received unexpected pdu:") + pdu.show() + print("expected pdu:") + expected_pdu.show() + self.assertTrue(False) + + return pdu + + async def enable_connected_isochronous_stream_host_support(self): + """Enable Connected Isochronous Stream Host Support in the LE Feature mask.""" + self.controller.send_cmd( + hci.LeSetHostFeature(bit_number=hci.LeHostFeatureBits.CONNECTED_ISO_STREAM_HOST_SUPPORT, + bit_value=hci.Enable.ENABLED)) + + await self.expect_evt(hci.LeSetHostFeatureComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + async def establish_le_connection_central(self, peer_address: hci.Address) -> int: + """Establish a connection with the selected peer as Central. + Returns the ACL connection handle for the opened link.""" + self.controller.send_cmd( + hci.LeExtendedCreateConnection(initiator_filter_policy=hci.InitiatorFilterPolicy.USE_PEER_ADDRESS, + own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS, + peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, + peer_address=peer_address, + initiating_phys=0x1, + initiating_phy_parameters=[ + hci.InitiatingPhyParameters( + scan_interval=0x200, + scan_window=0x100, + connection_interval_min=0x200, + connection_interval_max=0x200, + max_latency=0x6, + supervision_timeout=0xc80, + min_ce_length=0, + max_ce_length=0, + ) + ])) + + await self.expect_evt(hci.LeExtendedCreateConnectionStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + self.controller.send_ll(ll.LeLegacyAdvertisingPdu(source_address=peer_address, + advertising_address_type=ll.AddressType.PUBLIC, + advertising_type=ll.LegacyAdvertisingType.ADV_IND, + advertising_data=[]), + rssi=-16) + + await self.expect_ll( + ll.LeConnect(source_address=self.controller.address, + destination_address=peer_address, + initiating_address_type=ll.AddressType.PUBLIC, + advertising_address_type=ll.AddressType.PUBLIC, + conn_interval=0x200, + conn_peripheral_latency=0x6, + conn_supervision_timeout=0xc80)) + + self.controller.send_ll( + ll.LeConnectComplete(source_address=peer_address, + destination_address=self.controller.address, + initiating_address_type=ll.AddressType.PUBLIC, + advertising_address_type=ll.AddressType.PUBLIC, + conn_interval=0x200, + conn_peripheral_latency=0x6, + conn_supervision_timeout=0xc80)) + + connection_complete = await self.expect_evt( + hci.LeEnhancedConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=self.Any, + role=hci.Role.CENTRAL, + peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, + peer_address=peer_address, + connection_interval=0x200, + peripheral_latency=0x6, + supervision_timeout=0xc80, + central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + + acl_connection_handle = connection_complete.connection_handle + await self.expect_evt( + hci.LeChannelSelectionAlgorithm(connection_handle=acl_connection_handle, + channel_selection_algorithm=hci.ChannelSelectionAlgorithm.ALGORITHM_1)) + + return acl_connection_handle + + async def establish_le_connection_peripheral(self, peer_address: hci.Address) -> int: + """Establish a connection with the selected peer as Peripheral. + Returns the ACL connection handle for the opened link.""" + self.controller.send_cmd( + hci.LeSetAdvertisingParameters(advertising_interval_min=0x200, + advertising_interval_max=0x200, + advertising_type=hci.AdvertisingType.ADV_IND, + own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS, + advertising_channel_map=0x7, + advertising_filter_policy=hci.AdvertisingFilterPolicy.ALL_DEVICES)) + + await self.expect_evt( + hci.LeSetAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + self.controller.send_cmd(hci.LeSetAdvertisingEnable(advertising_enable=True)) + + await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + self.controller.send_ll(ll.LeConnect(source_address=peer_address, + destination_address=self.controller.address, + initiating_address_type=ll.AddressType.PUBLIC, + advertising_address_type=ll.AddressType.PUBLIC, + conn_interval=0x200, + conn_peripheral_latency=0x200, + conn_supervision_timeout=0x200), + rssi=-16) + + await self.expect_ll( + ll.LeConnectComplete(source_address=self.controller.address, + destination_address=peer_address, + conn_interval=0x200, + conn_peripheral_latency=0x200, + conn_supervision_timeout=0x200)) + + connection_complete = await self.expect_evt( + hci.LeEnhancedConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=self.Any, + role=hci.Role.PERIPHERAL, + peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, + peer_address=peer_address, + connection_interval=0x200, + peripheral_latency=0x200, + supervision_timeout=0x200, + central_clock_accuracy=hci.ClockAccuracy.PPM_500)) + + return connection_complete.connection_handle + def tearDown(self): self.controller.stop() diff --git a/tools/rootcanal/rust/Android.bp b/tools/rootcanal/rust/Android.bp index 0a156033e8e23f63068dbecbd0a6b52ea37cb601..8b634500682f682d41bdb95d201295b61d501304 100644 --- a/tools/rootcanal/rust/Android.bp +++ b/tools/rootcanal/rust/Android.bp @@ -14,8 +14,10 @@ rust_ffi { crate_name: "rootcanal_rs", srcs: [ "src/lib.rs", - ":rootcanal_lmp_packets_rust_gen", + ":rootcanal_hci_packets_rust_gen", + ":rootcanal_llcp_packets_rust_gen", + ":rootcanal_lmp_packets_rust_gen", ], edition: "2018", proc_macros: ["libnum_derive"], @@ -24,6 +26,7 @@ rust_ffi { "libnum_bigint", "libnum_integer", "libnum_traits", + "libpdl_runtime", "libpin_utils", "librand", "libthiserror", @@ -38,13 +41,22 @@ genrule { out: ["lmp_packets.rs"], } +genrule { + name: "rootcanal_llcp_packets_rust_gen", + defaults: ["pdl_rust_generator_defaults"], + srcs: ["llcp_packets.pdl"], + out: ["llcp_packets.rs"], +} + rust_test_host { name: "rootcanal_rs_test", crate_name: "rootcanal_rs", srcs: [ "src/lib.rs", - ":rootcanal_lmp_packets_rust_gen", + ":rootcanal_hci_packets_rust_gen", + ":rootcanal_llcp_packets_rust_gen", + ":rootcanal_lmp_packets_rust_gen", ], auto_gen_config: true, edition: "2018", @@ -53,11 +65,11 @@ rust_test_host { "libpaste", ], rustlibs: [ - "libbt_packets", "libbytes", "libnum_bigint", "libnum_integer", "libnum_traits", + "libpdl_runtime", "libpin_utils", "librand", "libthiserror", diff --git a/tools/rootcanal/rust/CMakeLists.txt b/tools/rootcanal/rust/CMakeLists.txt index e3b478194bcb8c18cbd303ca8ae77c5f44fed7aa..2e7c7cbaa918e450c23989f93e7ce44310697e91 100644 --- a/tools/rootcanal/rust/CMakeLists.txt +++ b/tools/rootcanal/rust/CMakeLists.txt @@ -1,9 +1,10 @@ message(STATUS "Enabling bluetooth LMP module.") -# TODO(b/279494407): migrate hci packets to new generator -android_bluetooth_packet_gen( - GENERATED hci_packets_rs INCLUDES packets SRC hci/hci_packets.pdl - SOURCE_DIR ${ROOTCANAL_ROOT} LANG rust) +pdl_gen( + NAME hci_packets_rs + INPUT ${ROOTCANAL_ROOT}/packets/hci_packets.pdl + OUTPUT hci_packets.rs + LANG rust) pdl_gen( NAME lmp_packets_rs @@ -11,17 +12,25 @@ pdl_gen( OUTPUT lmp_packets.rs LANG rust) +pdl_gen( + NAME llcp_packets_rs + INPUT ${ROOTCANAL_ROOT}/rust/llcp_packets.pdl + OUTPUT llcp_packets.rs + LANG rust) + # This will automatically register all the tests as well. corrosion_import_crate(MANIFEST_PATH ${ROOTCANAL_ROOT}/rust/Cargo.toml FLAGS --offline --verbose --verbose) corrosion_set_env_vars(rootcanal-rs LMP_PACKETS_PREBUILT=${lmp_packets_rs} + LLCP_PACKETS_PREBUILT=${llcp_packets_rs} HCI_PACKETS_PREBUILT=${hci_packets_rs} CARGO_HOME=${Rust_CARGO_HOME}) android_license(TARGET rootcanal-rs LIBNAME None SPDX None LICENSE None LOCAL None) add_custom_target(lmp_rust_packets DEPENDS ${lmp_packets_rs} + ${llcp_packets_rs} ${hci_packets_rs}) # Make sure we have the rust packets generated before we build them. diff --git a/tools/rootcanal/rust/Cargo.toml b/tools/rootcanal/rust/Cargo.toml index 84dbd5e8c7631fa965a5a6b77a7da95386c7099b..15105748b8767b330b4b05f664c5c14596bb5a76 100644 --- a/tools/rootcanal/rust/Cargo.toml +++ b/tools/rootcanal/rust/Cargo.toml @@ -26,6 +26,7 @@ num-derive = "0.3.3" num-integer = "0.1.45" num-traits = "0.2.14" paste = "1.0.4" +pdl-runtime = "0.2.2" pin-utils = "0.1.0" rand = "0.8.3" thiserror = "1.0.23" diff --git a/tools/rootcanal/rust/build.rs b/tools/rootcanal/rust/build.rs index 086639681a6c2887fa73b37e5d14de307751a001..793e1f93e15d79fe8421590cd8c561616a81ac0c 100644 --- a/tools/rootcanal/rust/build.rs +++ b/tools/rootcanal/rust/build.rs @@ -1,4 +1,3 @@ -// // Copyright 2022 Google, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,8 +13,9 @@ // limitations under the License. use std::env; +use std::fs::File; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; fn main() { install_generated_module( @@ -23,10 +23,15 @@ fn main() { "LMP_PACKETS_PREBUILT", &PathBuf::from("lmp_packets.pdl").canonicalize().unwrap(), ); + install_generated_module( + "llcp_packets.rs", + "LLCP_PACKETS_PREBUILT", + &PathBuf::from("llcp_packets.pdl").canonicalize().unwrap(), + ); install_generated_module( "hci_packets.rs", "HCI_PACKETS_PREBUILT", - &PathBuf::from("../packets/hci/hci_packets.pdl").canonicalize().unwrap(), + &PathBuf::from("../packets/hci_packets.pdl").canonicalize().unwrap(), ); } @@ -48,35 +53,33 @@ fn install_generated_module(module_name: &str, prebuilt_var: &str, pdl_name: &Pa } } -fn generate_module(pdl_name: &PathBuf) { +fn generate_module(in_file: &PathBuf) { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let out_file = + File::create(out_dir.join(in_file.file_name().unwrap()).with_extension("rs")).unwrap(); - // Find the packetgen tool. Expecting it at CARGO_HOME/bin - let packetgen = match env::var("CARGO_HOME") { - Ok(dir) => PathBuf::from(dir).join("bin").join("bluetooth_packetgen"), - Err(_) => PathBuf::from("bluetooth_packetgen"), + // Find the pdl tool. Expecting it at CARGO_HOME/bin + let pdl = match env::var("CARGO_HOME") { + Ok(dir) => PathBuf::from(dir).join("bin").join("pdlc"), + Err(_) => PathBuf::from("pdlc"), }; - if !Path::new(packetgen.as_os_str()).exists() { - panic!( - "bluetooth_packetgen not found in the current environment: {:?}", - packetgen.as_os_str().to_str().unwrap() - ); + if !Path::new(pdl.as_os_str()).exists() { + panic!("pdl not found in the current environment: {:?}", pdl.as_os_str().to_str().unwrap()); } - println!("cargo:rerun-if-changed={}", pdl_name.display()); - let output = Command::new(packetgen.as_os_str().to_str().unwrap()) - .arg("--out=".to_owned() + out_dir.as_os_str().to_str().unwrap()) - .arg("--include=".to_owned() + pdl_name.parent().unwrap().as_os_str().to_str().unwrap()) - .arg("--rust") - .arg(pdl_name) + println!("cargo:rerun-if-changed={}", in_file.display()); + let output = Command::new(pdl.as_os_str().to_str().unwrap()) + .arg("--output-format") + .arg("rust") + .arg(in_file) + .stdout(Stdio::from(out_file)) .output() .unwrap(); println!( - "Status: {}, stdout: {}, stderr: {}", + "Status: {}, stderr: {}", output.status, - String::from_utf8_lossy(output.stdout.as_slice()), String::from_utf8_lossy(output.stderr.as_slice()) ); diff --git a/tools/rootcanal/rust/cbindgen.toml b/tools/rootcanal/rust/cbindgen.toml index 72866f64a9aba9afa8ad01ad36cd41be4d571a59..a9e94a5f899932c31774b4f1d60f2aa78a59d959 100644 --- a/tools/rootcanal/rust/cbindgen.toml +++ b/tools/rootcanal/rust/cbindgen.toml @@ -4,8 +4,11 @@ language = "C++" pragma_once = true autogen_warning = ''' // This file is autogenerated by: -// cbindgen --config cbindgen.toml src/ffi.rs -o include/lmp.h +// cbindgen --config cbindgen.toml src/ffi.rs -o include/rootcanal_rs.h // Don't modify manually. + +struct LinkManager; +struct LinkLayer; ''' sys_includes = ["stdint.h"] no_includes = true diff --git a/tools/rootcanal/rust/include/lmp.h b/tools/rootcanal/rust/include/lmp.h deleted file mode 100644 index 40c2ec5c0d2c4230740eca13f3e24dc314dbc4c8..0000000000000000000000000000000000000000 --- a/tools/rootcanal/rust/include/lmp.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -// This file is autogenerated by: -// cbindgen --config cbindgen.toml src/ffi.rs -o include/lmp.h -// Don't modify manually. - -#include - -/// Link Manager callbacks -struct LinkManagerOps { - void* user_pointer; - uint16_t (*get_handle)(void* user, const uint8_t (*address)[6]); - void (*get_address)(void* user, uint16_t handle, uint8_t (*result)[6]); - uint64_t (*extended_features)(void* user, uint8_t features_page); - void (*send_hci_event)(void* user, const uint8_t* data, uintptr_t len); - void (*send_lmp_packet)(void* user, const uint8_t (*to)[6], - const uint8_t* data, uintptr_t len); -}; - -extern "C" { - -/// Create a new link manager instance -/// # Arguments -/// * `ops` - Function callbacks required by the link manager -const LinkManager* link_manager_create(LinkManagerOps ops); - -/// Register a new link with a peer inside the link manager -/// # Arguments -/// * `lm` - link manager pointer -/// * `peer` - peer address as array of 6 bytes -/// # Safety -/// - This should be called from the thread of creation -/// - `lm` must be a valid pointer -/// - `peer` must be valid for reads for 6 bytes -bool link_manager_add_link(const LinkManager* lm, const uint8_t (*peer)[6]); - -/// Unregister a link with a peer inside the link manager -/// Returns true if successful -/// # Arguments -/// * `lm` - link manager pointer -/// * `peer` - peer address as array of 6 bytes -/// # Safety -/// - This should be called from the thread of creation -/// - `lm` must be a valid pointer -/// - `peer` must be valid for reads for 6 bytes -bool link_manager_remove_link(const LinkManager* lm, const uint8_t (*peer)[6]); - -/// Run the Link Manager procedures -/// # Arguments -/// * `lm` - link manager pointer -/// # Safety -/// - This should be called from the thread of creation -/// - `lm` must be a valid pointer -void link_manager_tick(const LinkManager* lm); - -/// Process an HCI packet with the link manager -/// Returns true if successful -/// # Arguments -/// * `lm` - link manager pointer -/// * `data` - HCI packet data -/// * `len` - HCI packet len -/// # Safety -/// - This should be called from the thread of creation -/// - `lm` must be a valid pointer -/// - `data` must be valid for reads of len `len` -bool link_manager_ingest_hci(const LinkManager* lm, const uint8_t* data, - uintptr_t len); - -/// Process an LMP packet from a peer with the link manager -/// Returns true if successful -/// # Arguments -/// * `lm` - link manager pointer -/// * `from` - Address of peer as array of 6 bytes -/// * `data` - HCI packet data -/// * `len` - HCI packet len -/// # Safety -/// - This should be called from the thread of creation -/// - `lm` must be a valid pointers -/// - `from` must be valid pointer for reads for 6 bytes -/// - `data` must be valid for reads of len `len` -bool link_manager_ingest_lmp(const LinkManager* lm, const uint8_t (*from)[6], - const uint8_t* data, uintptr_t len); - -/// Deallocate the link manager instance -/// # Arguments -/// * `lm` - link manager pointer -/// # Safety -/// - This should be called from the thread of creation -/// - `lm` must be a valid pointers and must not be reused afterwards -void link_manager_destroy(const LinkManager* lm); - -} // extern "C" diff --git a/tools/rootcanal/rust/include/rootcanal_rs.h b/tools/rootcanal/rust/include/rootcanal_rs.h new file mode 100644 index 0000000000000000000000000000000000000000..1b395cd63250b0cc3afd3c053d4f68b33d98cd25 --- /dev/null +++ b/tools/rootcanal/rust/include/rootcanal_rs.h @@ -0,0 +1,218 @@ +// Copyright 2023 Google LLC +// +// 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 +// +// https://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 + +// This file is autogenerated by: +// cbindgen --config cbindgen.toml src/ffi.rs -o include/rootcanal_rs.h +// Don't modify manually. + +struct LinkManager; +struct LinkLayer; + +#include + +/// Link Manager callbacks +struct ControllerOps { + void* user_pointer; + uint16_t (*get_handle)(void* user, const uint8_t (*address)[6]); + void (*get_address)(void* user, uint16_t handle, uint8_t (*result)[6]); + uint64_t (*get_extended_features)(void* user, uint8_t features_page); + uint64_t (*get_le_features)(void* user); + uint64_t (*get_le_event_mask)(void* user); + void (*send_hci_event)(void* user, const uint8_t* data, uintptr_t len); + void (*send_lmp_packet)(void* user, const uint8_t (*to)[6], + const uint8_t* data, uintptr_t len); + void (*send_llcp_packet)(void* user, uint16_t handle, const uint8_t* data, + uintptr_t len); +}; + +extern "C" { + +/// Create a new link manager instance +/// # Arguments +/// * `ops` - Function callbacks required by the link manager +const LinkManager* link_manager_create(ControllerOps ops); + +/// Register a new link with a peer inside the link manager +/// # Arguments +/// * `lm` - link manager pointer +/// * `peer` - peer address as array of 6 bytes +/// # Safety +/// - This should be called from the thread of creation +/// - `lm` must be a valid pointer +/// - `peer` must be valid for reads for 6 bytes +bool link_manager_add_link(const LinkManager* lm, const uint8_t (*peer)[6]); + +/// Unregister a link with a peer inside the link manager +/// Returns true if successful +/// # Arguments +/// * `lm` - link manager pointer +/// * `peer` - peer address as array of 6 bytes +/// # Safety +/// - This should be called from the thread of creation +/// - `lm` must be a valid pointer +/// - `peer` must be valid for reads for 6 bytes +bool link_manager_remove_link(const LinkManager* lm, const uint8_t (*peer)[6]); + +/// Run the Link Manager procedures +/// # Arguments +/// * `lm` - link manager pointer +/// # Safety +/// - This should be called from the thread of creation +/// - `lm` must be a valid pointer +void link_manager_tick(const LinkManager* lm); + +/// Process an HCI packet with the link manager +/// Returns true if successful +/// # Arguments +/// * `lm` - link manager pointer +/// * `data` - HCI packet data +/// * `len` - HCI packet len +/// # Safety +/// - This should be called from the thread of creation +/// - `lm` must be a valid pointer +/// - `data` must be valid for reads of len `len` +bool link_manager_ingest_hci(const LinkManager* lm, const uint8_t* data, + uintptr_t len); + +/// Process an LMP packet from a peer with the link manager +/// Returns true if successful +/// # Arguments +/// * `lm` - link manager pointer +/// * `from` - Address of peer as array of 6 bytes +/// * `data` - HCI packet data +/// * `len` - HCI packet len +/// # Safety +/// - This should be called from the thread of creation +/// - `lm` must be a valid pointers +/// - `from` must be valid pointer for reads for 6 bytes +/// - `data` must be valid for reads of len `len` +bool link_manager_ingest_lmp(const LinkManager* lm, const uint8_t (*from)[6], + const uint8_t* data, uintptr_t len); + +/// Deallocate the link manager instance +/// # Arguments +/// * `lm` - link manager pointer +/// # Safety +/// - This should be called from the thread of creation +/// - `lm` must be a valid pointers and must not be reused afterwards +void link_manager_destroy(const LinkManager* lm); + +/// Create a new link manager instance +/// # Arguments +/// * `ops` - Function callbacks required by the link manager +const LinkLayer* link_layer_create(ControllerOps ops); + +/// Register a new link with a peer inside the link layer +/// # Arguments +/// * `ll` - link layer pointer +/// * `handle` - connection handle for the link +/// * `peer_address` - peer address as array of 6 bytes +/// * `role` - connection role (peripheral or centrl) for the link +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointer +/// - `peer` must be valid for reads for 6 bytes +/// - `role` must be 0 (central) or 1 (peripheral) +bool link_layer_add_link(const LinkLayer* ll, uint16_t handle, + const uint8_t (*peer_address)[6], uint8_t role); + +/// Unregister a link with a peer inside the link layer +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `peer` - peer address as array of 6 bytes +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointer +/// - `peer` must be valid for reads for 6 bytes +bool link_layer_remove_link(const LinkLayer* ll, uint16_t handle); + +/// Run the Link Manager procedures +/// # Arguments +/// * `ll` - link layer pointer +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointer +void link_layer_tick(const LinkLayer* ll); + +/// Process an HCI packet with the link layer +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `data` - HCI packet data +/// * `len` - HCI packet len +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointer +/// - `data` must be valid for reads of len `len` +bool link_layer_ingest_hci(const LinkLayer* ll, const uint8_t* data, + uintptr_t len); + +/// Process an LLCP packet from a peer with the link layer +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `handle` - ACL handle of the connection +/// * `data` - HCI packet data +/// * `len` - HCI packet len +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointers +/// - `data` must be valid for reads of len `len` +bool link_layer_ingest_llcp(const LinkLayer* ll, uint16_t handle, + const uint8_t* data, uintptr_t len); + +/// Query the connection handle for a CIS established with +/// the input CIS and CIG identifiers. +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `cig_id` - Identifier of the established Cig +/// * `cis_id` - Identifier of the established Cis +/// * `cis_connection_handle` - Returns the handle of the CIS if connected +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointers +bool link_layer_get_cis_connection_handle(const LinkLayer* ll, uint8_t cig_id, + uint8_t cis_id, + uint16_t* cis_connection_handle); + +/// Query the CIS and CIG identifiers for a CIS established with +/// the input CIS connection handle. +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `cis_connection_handle` - CIS connection handle +/// * `cig_id` - Returns the CIG identifier +/// * `cis_id` - Returns the CIS identifier +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointers +bool link_layer_get_cis_information(const LinkLayer* ll, + uint16_t cis_connection_handle, + uint16_t* acl_connection_handle, + uint8_t* cig_id, uint8_t* cis_id, + uint16_t* max_sdu_tx); + +/// Deallocate the link layer instance +/// # Arguments +/// * `ll` - link layer pointer +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointers and must not be reused afterwards +void link_layer_destroy(const LinkLayer* ll); + +} // extern "C" diff --git a/tools/rootcanal/rust/llcp_packets.pdl b/tools/rootcanal/rust/llcp_packets.pdl new file mode 100644 index 0000000000000000000000000000000000000000..56cb597511967890ea698fff7e3bcf80e031fae8 --- /dev/null +++ b/tools/rootcanal/rust/llcp_packets.pdl @@ -0,0 +1,327 @@ +little_endian_packets + +enum Opcode : 8 { + LL_CONNECTION_UPDATE_IND = 0x00, + LL_CHANNEL_MAP_IND = 0x01, + LL_TERMINATE_IND = 0x02, + LL_ENC_REQ = 0x03, + LL_ENC_RSP = 0x04, + LL_START_ENC_REQ = 0x05, + LL_START_ENC_RSP = 0x06, + LL_UNKNOWN_RSP = 0x07, + LL_FEATURE_REQ = 0x08, + LL_FEATURE_RSP = 0x09, + LL_PAUSE_ENC_REQ = 0x0A, + LL_PAUSE_ENC_RSP = 0x0B, + LL_VERSION_IND = 0x0C, + LL_REJECT_IND = 0x0D, + LL_PERIPHERAL_FEATURE_REQ = 0x0E, + LL_CONNECTION_PARAM_REQ = 0x0F, + LL_CONNECTION_PARAM_RSP = 0x10, + LL_REJECT_EXT_IND = 0x11, + LL_PING_REQ = 0x12, + LL_PING_RSP = 0x13, + LL_LENGTH_REQ = 0x14, + LL_LENGTH_RSP = 0x15, + LL_PHY_REQ = 0x16, + LL_PHY_RSP = 0x17, + LL_PHY_UPDATE_IND = 0x18, + LL_MIN_USED_CHANNELS_IND = 0x19, + LL_CTE_REQ = 0x1A, + LL_CTE_RSP = 0x1B, + LL_PERIODIC_SYNC_IND = 0x1C, + LL_CLOCK_ACCURACY_REQ = 0x1D, + LL_CLOCK_ACCURACY_RSP = 0x1E, + LL_CIS_REQ = 0x1F, + LL_CIS_RSP = 0x20, + LL_CIS_IND = 0x21, + LL_CIS_TERMINATE_IND = 0x22, + LL_POWER_CONTROL_REQ = 0x23, + LL_POWER_CONTROL_RSP = 0x24, + LL_POWER_CHANGE_IND = 0x25, + LL_SUBRATE_REQ = 0x26, + LL_SUBRATE_IND = 0x27, + LL_CHANNEL_REPORTING_IND = 0x28, + LL_CHANNEL_STATUS_IND = 0x29, +} + +packet LlcpPacket { + opcode: Opcode, + _payload_, +} + +packet ConnectionUpdateInd : LlcpPacket (opcode = LL_CONNECTION_UPDATE_IND) { + window_size: 8, + window_offset: 16, + interval: 16, + latency: 16, + timeout: 16, + instant: 16, +} + +packet ChannelMapInd : LlcpPacket (opcode = LL_CHANNEL_MAP_IND) { + channel_map: 40, + instant: 16, +} + +packet TerminateInd : LlcpPacket (opcode = LL_TERMINATE_IND) { + error_code: 8, +} + +packet EncReq : LlcpPacket (opcode = LL_ENC_REQ) { + rand: 64, + ediv: 16, + skd_c: 64, + iv_c: 16, +} + +packet EncRsp : LlcpPacket (opcode = LL_ENC_RSP) { + skd_p: 64, + iv_p: 16, +} + +packet StartEncReq : LlcpPacket (opcode = LL_START_ENC_REQ) { +} + +packet StartEncRsp : LlcpPacket (opcode = LL_START_ENC_RSP) { +} + +packet UnknownRsp : LlcpPacket (opcode = LL_UNKNOWN_RSP) { + unknown_type: 8, +} + +packet FeatureReq : LlcpPacket (opcode = LL_FEATURE_REQ) { + feature_set: 64, +} + +packet FeatureRsp : LlcpPacket (opcode = LL_FEATURE_RSP) { + feature_set: 64, +} + +packet PauseEncReq : LlcpPacket (opcode = LL_PAUSE_ENC_REQ) { +} + +packet PauseEncRsp : LlcpPacket (opcode = LL_PAUSE_ENC_RSP) { +} + +packet VersionInd : LlcpPacket (opcode = LL_VERSION_IND) { + version: 8, + company_identifier: 16, + subversion: 16, +} + +packet RejectInd : LlcpPacket (opcode = LL_REJECT_IND) { + error_code: 16, +} + +packet PeripheralFeatureReq : LlcpPacket (opcode = LL_PERIPHERAL_FEATURE_REQ) { + feature_set: 64, +} + +packet ConnectionParamReq : LlcpPacket (opcode = LL_CONNECTION_PARAM_REQ) { + interval_min: 16, + interval_max: 16, + latency: 16, + timeout: 16, + preferred_periodicity: 8, + reference_conn_event_count: 16, + offset0: 16, + offset1: 16, + offset2: 16, + offset3: 16, + offset4: 16, + offset5: 16, +} + +packet ConnectionParamRsp : LlcpPacket (opcode = LL_CONNECTION_PARAM_RSP) { + interval_min: 16, + interval_max: 16, + latency: 16, + timeout: 16, + preferred_periodicity: 8, + reference_conn_event_count: 16, + offset0: 16, + offset1: 16, + offset2: 16, + offset3: 16, + offset4: 16, + offset5: 16, +} + +packet RejectExtInd : LlcpPacket (opcode = LL_REJECT_EXT_IND) { + reject_opcode: 8, + error_code: 8, +} + +packet PingReq : LlcpPacket (opcode = LL_PING_REQ) { +} + +packet PingRsp : LlcpPacket (opcode = LL_PING_RSP) { +} + +packet LengthReq : LlcpPacket (opcode = LL_LENGTH_REQ) { + max_rx_octets: 16, + max_rx_time: 16, + max_tx_octets: 16, + max_tx_time: 16, +} + +packet LengthRsp : LlcpPacket (opcode = LL_LENGTH_RSP) { + max_rx_octets: 16, + max_rx_time: 16, + max_tx_octets: 16, + max_tx_time: 16, +} + +packet PhyReq : LlcpPacket (opcode = LL_PHY_REQ) { + tx_phys: 8, + rx_phys: 8, +} + +packet PhyRsp : LlcpPacket (opcode = LL_PHY_RSP) { + tx_phys: 8, + rx_phys: 8, +} + +packet PhyUpdateInd : LlcpPacket (opcode = LL_PHY_UPDATE_IND) { + phy_c_to_p: 8, + phy_p_to_c: 8, + instant: 16, +} + +packet MinUsedChannelsInd : LlcpPacket (opcode = LL_MIN_USED_CHANNELS_IND) { + phys: 8, + min_used_channels: 8, +} + +packet CteReq : LlcpPacket (opcode = LL_CTE_REQ) { + min_cte_len_req: 5, + _reserved_: 1, + cte_type_req: 2, +} + +packet CteRsp : LlcpPacket (opcode = LL_CTE_RSP) { +} + +packet PeriodicSyncInd : LlcpPacket (opcode = LL_PERIODIC_SYNC_IND) { + id: 16, + sync_info: 8[18], + conn_event_count: 16, + last_pa_event_counter: 16, + sid: 4, + atype: 1, + sca: 3, + phy: 8, + adva: 48, + sync_conn_event_count: 16, +} + +packet ClockAccuracyReq : LlcpPacket (opcode = LL_CLOCK_ACCURACY_REQ) { + sca: 8, +} + +packet ClockAccuracyRsp : LlcpPacket (opcode = LL_CLOCK_ACCURACY_RSP) { + sca: 8, +} + +// 2.4.2.29 LL_CIS_REQ +packet CisReq : LlcpPacket (opcode = LL_CIS_REQ) { + cig_id : 8, + cis_id : 8, + phy_c_to_p : 8, + phy_p_to_c : 8, + framed : 1, + _reserved_ : 3, + max_sdu_c_to_p : 12, + _reserved_ : 4, + max_sdu_p_to_c : 12, + _reserved_ : 4, + sdu_interval_c_to_p : 20, + _reserved_ : 4, + sdu_interval_p_to_c : 20, + max_pdu_c_to_p : 16, + max_pdu_p_to_c : 16, + nse : 8, + sub_interval : 24, + bn_p_to_c : 4, + bn_c_to_p : 4, + ft_c_to_p : 8, + ft_p_to_c : 8, + iso_interval : 16, + cis_offset_min : 24, + cis_offset_max : 24, + conn_event_count : 16, +} + +// 2.4.2.30 LL_CIS_RSP +packet CisRsp : LlcpPacket (opcode = LL_CIS_RSP) { + cis_offset_min: 24, + cis_offset_max: 24, + conn_event_count: 16, +} + +// 2.4.2.31 LL_CIS_IND +packet CisInd : LlcpPacket (opcode = LL_CIS_IND) { + aa: 32, + cis_offset: 24, + cig_sync_delay: 24, + cis_sync_delay: 24, + conn_event_count: 16, +} + +// 2.4.2.32 LL_CIS_TERMINATE_IND +packet CisTerminateInd : LlcpPacket (opcode = LL_CIS_TERMINATE_IND) { + cig_id: 8, + cis_id: 8, + error_code: 8, +} + +packet PowerControlReq : LlcpPacket (opcode = LL_POWER_CONTROL_REQ) { + phy: 8, + delta: 8, + tx_power: 8, +} + +packet PowerControlRsp : LlcpPacket (opcode = LL_POWER_CONTROL_RSP) { + min: 1, + max: 1, + _reserved_: 6, + delta: 8, + tx_power: 8, + apr: 8, +} + +packet PowerChangeInd : LlcpPacket (opcode = LL_POWER_CHANGE_IND) { + phy: 8, + min: 1, + max: 1, + _reserved_: 6, + delta: 8, + tx_power: 8, +} + +packet SubrateReq : LlcpPacket (opcode = LL_SUBRATE_REQ) { + subrate_factor_min: 16, + subrate_factor_max: 16, + max_latency: 16, + continuation_number: 16, + timeout: 16, +} + +packet SubrateInd : LlcpPacket (opcode = LL_SUBRATE_IND) { + subrate_factor: 16, + subrate_base_event: 16, + latency: 16, + continuation_number: 16, + timeout: 16, +} + +packet ChannelReportingInd : LlcpPacket (opcode = LL_CHANNEL_REPORTING_IND) { + enable: 8, + min_spacing: 8, + max_delay: 8, +} + +packet ChannelStatusInd : LlcpPacket (opcode = LL_CHANNEL_STATUS_IND) { + channel_classification: 8[10], +} diff --git a/tools/rootcanal/rust/src/either.rs b/tools/rootcanal/rust/src/either.rs index af18e93da8941b4aa2907a2ceca58e03c5a4f93b..87b6d7e8b4559adbe8d10a384779e30ca82f3d1b 100644 --- a/tools/rootcanal/rust/src/either.rs +++ b/tools/rootcanal/rust/src/either.rs @@ -1,3 +1,17 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::convert::TryFrom; use crate::packets::{hci, lmp}; @@ -32,4 +46,4 @@ macro_rules! impl_try_from { } impl_try_from!(lmp::LmpPacket); -impl_try_from!(hci::CommandPacket); +impl_try_from!(hci::Command); diff --git a/tools/rootcanal/rust/src/ffi.rs b/tools/rootcanal/rust/src/ffi.rs index 96fa9b5c662c4cb65ec5edcbd62d5263257d6e83..0024bbc70715a3eb220b3d2b9d88ebf7bef89ab1 100644 --- a/tools/rootcanal/rust/src/ffi.rs +++ b/tools/rootcanal/rust/src/ffi.rs @@ -1,40 +1,69 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO(b/290018030): Remove this and add proper safety comments. +#![allow(clippy::undocumented_unsafe_blocks)] + +use std::convert::TryFrom; use std::mem::ManuallyDrop; use std::rc::Rc; use std::slice; +use crate::llcp::manager::LinkLayer; use crate::lmp::manager::LinkManager; -use crate::packets::{hci, lmp}; +use crate::packets::{hci, llcp, lmp}; /// Link Manager callbacks #[repr(C)] #[derive(Clone)] -pub struct LinkManagerOps { +pub struct ControllerOps { user_pointer: *mut (), get_handle: unsafe extern "C" fn(user: *mut (), address: *const [u8; 6]) -> u16, get_address: unsafe extern "C" fn(user: *mut (), handle: u16, result: *mut [u8; 6]), - extended_features: unsafe extern "C" fn(user: *mut (), features_page: u8) -> u64, + get_extended_features: unsafe extern "C" fn(user: *mut (), features_page: u8) -> u64, + get_le_features: unsafe extern "C" fn(user: *mut ()) -> u64, + get_le_event_mask: unsafe extern "C" fn(user: *mut ()) -> u64, send_hci_event: unsafe extern "C" fn(user: *mut (), data: *const u8, len: usize), send_lmp_packet: unsafe extern "C" fn(user: *mut (), to: *const [u8; 6], data: *const u8, len: usize), + send_llcp_packet: unsafe extern "C" fn(user: *mut (), handle: u16, data: *const u8, len: usize), } -impl LinkManagerOps { +impl ControllerOps { pub(crate) fn get_address(&self, handle: u16) -> Option { - let mut result = hci::EMPTY_ADDRESS; - unsafe { (self.get_address)(self.user_pointer, handle, &mut result.bytes as *mut _) }; - if result == hci::EMPTY_ADDRESS { - None - } else { - Some(result) - } + let mut result = [0; 6]; + unsafe { (self.get_address)(self.user_pointer, handle, &mut result as *mut _) }; + let addr = hci::Address::from(&result); + (addr != hci::EMPTY_ADDRESS).then_some(addr) } pub(crate) fn get_handle(&self, addr: hci::Address) -> u16 { - unsafe { (self.get_handle)(self.user_pointer, &addr.bytes as *const _) } + let addr_bytes: [u8; 6] = addr.into(); + unsafe { (self.get_handle)(self.user_pointer, &addr_bytes as *const _) } + } + + pub(crate) fn get_extended_features(&self, features_page: u8) -> u64 { + unsafe { (self.get_extended_features)(self.user_pointer, features_page) } + } + + pub(crate) fn get_le_features(&self) -> u64 { + unsafe { (self.get_le_features)(self.user_pointer) } } - pub(crate) fn extended_features(&self, features_page: u8) -> u64 { - unsafe { (self.extended_features)(self.user_pointer, features_page) } + #[allow(dead_code)] + pub(crate) fn get_le_event_mask(&self) -> u64 { + unsafe { (self.get_le_event_mask)(self.user_pointer) } } pub(crate) fn send_hci_event(&self, packet: &[u8]) { @@ -42,22 +71,27 @@ impl LinkManagerOps { } pub(crate) fn send_lmp_packet(&self, to: hci::Address, packet: &[u8]) { + let to_bytes: [u8; 6] = to.into(); unsafe { (self.send_lmp_packet)( self.user_pointer, - &to.bytes as *const _, + &to_bytes as *const _, packet.as_ptr(), packet.len(), ) } } + + pub(crate) fn send_llcp_packet(&self, handle: u16, packet: &[u8]) { + unsafe { (self.send_llcp_packet)(self.user_pointer, handle, packet.as_ptr(), packet.len()) } + } } /// Create a new link manager instance /// # Arguments /// * `ops` - Function callbacks required by the link manager #[no_mangle] -pub extern "C" fn link_manager_create(ops: LinkManagerOps) -> *const LinkManager { +pub extern "C" fn link_manager_create(ops: ControllerOps) -> *const LinkManager { Rc::into_raw(Rc::new(LinkManager::new(ops))) } @@ -74,8 +108,8 @@ pub unsafe extern "C" fn link_manager_add_link( lm: *const LinkManager, peer: *const [u8; 6], ) -> bool { - let lm = ManuallyDrop::new(Rc::from_raw(lm)); - lm.add_link(hci::Address { bytes: *peer }).is_ok() + let lm = ManuallyDrop::new(unsafe { Rc::from_raw(lm) }); + unsafe { lm.add_link(hci::Address::from(&*peer)).is_ok() } } /// Unregister a link with a peer inside the link manager @@ -92,8 +126,8 @@ pub unsafe extern "C" fn link_manager_remove_link( lm: *const LinkManager, peer: *const [u8; 6], ) -> bool { - let lm = ManuallyDrop::new(Rc::from_raw(lm)); - lm.remove_link(hci::Address { bytes: *peer }).is_ok() + let lm = ManuallyDrop::new(unsafe { Rc::from_raw(lm) }); + unsafe { lm.remove_link(hci::Address::from(&*peer)).is_ok() } } /// Run the Link Manager procedures @@ -104,7 +138,7 @@ pub unsafe extern "C" fn link_manager_remove_link( /// - `lm` must be a valid pointer #[no_mangle] pub unsafe extern "C" fn link_manager_tick(lm: *const LinkManager) { - let lm = ManuallyDrop::new(Rc::from_raw(lm)); + let lm = ManuallyDrop::new(unsafe { Rc::from_raw(lm) }); lm.as_ref().tick(); } @@ -124,10 +158,10 @@ pub unsafe extern "C" fn link_manager_ingest_hci( data: *const u8, len: usize, ) -> bool { - let lm = ManuallyDrop::new(Rc::from_raw(lm)); - let data = slice::from_raw_parts(data, len); + let lm = ManuallyDrop::new(unsafe { Rc::from_raw(lm) }); + let data = unsafe { slice::from_raw_parts(data, len) }; - if let Ok(packet) = hci::CommandPacket::parse(data) { + if let Ok(packet) = hci::Command::parse(data) { lm.ingest_hci(packet).is_ok() } else { false @@ -153,11 +187,11 @@ pub unsafe extern "C" fn link_manager_ingest_lmp( data: *const u8, len: usize, ) -> bool { - let lm = ManuallyDrop::new(Rc::from_raw(lm)); - let data = slice::from_raw_parts(data, len); + let lm = ManuallyDrop::new(unsafe { Rc::from_raw(lm) }); + let data = unsafe { slice::from_raw_parts(data, len) }; if let Ok(packet) = lmp::LmpPacket::parse(data) { - lm.ingest_lmp(hci::Address { bytes: *from }, packet).is_ok() + unsafe { lm.ingest_lmp(hci::Address::from(&*from), packet).is_ok() } } else { false } @@ -171,5 +205,202 @@ pub unsafe extern "C" fn link_manager_ingest_lmp( /// - `lm` must be a valid pointers and must not be reused afterwards #[no_mangle] pub unsafe extern "C" fn link_manager_destroy(lm: *const LinkManager) { - let _ = Rc::from_raw(lm); + unsafe { + let _ = Rc::from_raw(lm); + } +} + +/// Create a new link manager instance +/// # Arguments +/// * `ops` - Function callbacks required by the link manager +#[no_mangle] +pub extern "C" fn link_layer_create(ops: ControllerOps) -> *const LinkLayer { + Rc::into_raw(Rc::new(LinkLayer::new(ops))) +} + +/// Register a new link with a peer inside the link layer +/// # Arguments +/// * `ll` - link layer pointer +/// * `handle` - connection handle for the link +/// * `peer_address` - peer address as array of 6 bytes +/// * `role` - connection role (peripheral or centrl) for the link +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointer +/// - `peer` must be valid for reads for 6 bytes +/// - `role` must be 0 (central) or 1 (peripheral) +#[no_mangle] +pub unsafe extern "C" fn link_layer_add_link( + ll: *const LinkLayer, + handle: u16, + peer_address: *const [u8; 6], + role: u8, +) -> bool { + let mut ll = ManuallyDrop::new(unsafe { Rc::from_raw(ll) }); + let ll = Rc::get_mut(&mut ll).unwrap(); + let role = hci::Role::try_from(role).unwrap_or(hci::Role::Peripheral); + unsafe { ll.add_link(handle, hci::Address::from(&*peer_address), role).is_ok() } +} + +/// Unregister a link with a peer inside the link layer +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `peer` - peer address as array of 6 bytes +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointer +/// - `peer` must be valid for reads for 6 bytes +#[no_mangle] +pub unsafe extern "C" fn link_layer_remove_link(ll: *const LinkLayer, handle: u16) -> bool { + let mut ll = ManuallyDrop::new(unsafe { Rc::from_raw(ll) }); + let ll = Rc::get_mut(&mut ll).unwrap(); + ll.remove_link(handle).is_ok() +} + +/// Run the Link Manager procedures +/// # Arguments +/// * `ll` - link layer pointer +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointer +#[no_mangle] +pub unsafe extern "C" fn link_layer_tick(ll: *const LinkLayer) { + let mut ll = ManuallyDrop::new(unsafe { Rc::from_raw(ll) }); + let ll = Rc::get_mut(&mut ll).unwrap(); + ll.tick(); +} + +/// Process an HCI packet with the link layer +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `data` - HCI packet data +/// * `len` - HCI packet len +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointer +/// - `data` must be valid for reads of len `len` +#[no_mangle] +pub unsafe extern "C" fn link_layer_ingest_hci( + ll: *const LinkLayer, + data: *const u8, + len: usize, +) -> bool { + let mut ll = ManuallyDrop::new(unsafe { Rc::from_raw(ll) }); + let ll = Rc::get_mut(&mut ll).unwrap(); + let data = unsafe { slice::from_raw_parts(data, len) }; + + if let Ok(packet) = hci::Command::parse(data) { + ll.ingest_hci(packet).is_ok() + } else { + false + } +} + +/// Process an LLCP packet from a peer with the link layer +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `handle` - ACL handle of the connection +/// * `data` - HCI packet data +/// * `len` - HCI packet len +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointers +/// - `data` must be valid for reads of len `len` +#[no_mangle] +pub unsafe extern "C" fn link_layer_ingest_llcp( + ll: *const LinkLayer, + handle: u16, + data: *const u8, + len: usize, +) -> bool { + let mut ll = ManuallyDrop::new(unsafe { Rc::from_raw(ll) }); + let ll = Rc::get_mut(&mut ll).unwrap(); + let data = unsafe { slice::from_raw_parts(data, len) }; + + if let Ok(packet) = llcp::LlcpPacket::parse(data) { + ll.ingest_llcp(handle, packet).is_ok() + } else { + false + } +} + +/// Query the connection handle for a CIS established with +/// the input CIS and CIG identifiers. +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `cig_id` - Identifier of the established Cig +/// * `cis_id` - Identifier of the established Cis +/// * `cis_connection_handle` - Returns the handle of the CIS if connected +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointers +#[no_mangle] +pub unsafe extern "C" fn link_layer_get_cis_connection_handle( + ll: *const LinkLayer, + cig_id: u8, + cis_id: u8, + cis_connection_handle: *mut u16, +) -> bool { + let mut ll = ManuallyDrop::new(unsafe { Rc::from_raw(ll) }); + let ll = Rc::get_mut(&mut ll).unwrap(); + ll.get_cis_connection_handle(cig_id, cis_id) + .map(|handle| unsafe { + *cis_connection_handle = handle; + }) + .is_some() +} + +/// Query the CIS and CIG identifiers for a CIS established with +/// the input CIS connection handle. +/// Returns true if successful +/// # Arguments +/// * `ll` - link layer pointer +/// * `cis_connection_handle` - CIS connection handle +/// * `cig_id` - Returns the CIG identifier +/// * `cis_id` - Returns the CIS identifier +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointers +#[no_mangle] +pub unsafe extern "C" fn link_layer_get_cis_information( + ll: *const LinkLayer, + cis_connection_handle: u16, + acl_connection_handle: *mut u16, + cig_id: *mut u8, + cis_id: *mut u8, + max_sdu_tx: *mut u16, +) -> bool { + let mut ll = ManuallyDrop::new(unsafe { Rc::from_raw(ll) }); + let ll = Rc::get_mut(&mut ll).unwrap(); + ll.get_cis(cis_connection_handle) + .map(|cis| { + if let Some(handle) = cis.acl_connection_handle { + unsafe { + *acl_connection_handle = handle; + } + } + unsafe { + *cig_id = cis.cig_id; + *cis_id = cis.cis_id; + *max_sdu_tx = cis.max_sdu_tx().unwrap_or(0); + } + }) + .is_some() +} + +/// Deallocate the link layer instance +/// # Arguments +/// * `ll` - link layer pointer +/// # Safety +/// - This should be called from the thread of creation +/// - `ll` must be a valid pointers and must not be reused afterwards +#[no_mangle] +pub unsafe extern "C" fn link_layer_destroy(ll: *const LinkLayer) { + unsafe { + let _ = Rc::from_raw(ll); + } } diff --git a/tools/rootcanal/rust/src/future.rs b/tools/rootcanal/rust/src/future.rs index afe021f5010e557ec6c70357793cfea3cd3ba854..f12d88db7a8ffe62ec390a5040bb423b61f4e929 100644 --- a/tools/rootcanal/rust/src/future.rs +++ b/tools/rootcanal/rust/src/future.rs @@ -1,3 +1,17 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::sync::Arc; use std::task::{Wake, Waker}; diff --git a/tools/rootcanal/rust/src/lib.rs b/tools/rootcanal/rust/src/lib.rs index 9a3602542cf710f82b527735355c1518b36e06d8..21307886e863028ffa3b31cdec6140833c3716d9 100644 --- a/tools/rootcanal/rust/src/lib.rs +++ b/tools/rootcanal/rust/src/lib.rs @@ -1,8 +1,23 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + //! Link Manager implemented in Rust mod either; mod ffi; mod future; +mod llcp; mod lmp; mod packets; diff --git a/tools/rootcanal/rust/src/llcp/iso.rs b/tools/rootcanal/rust/src/llcp/iso.rs new file mode 100644 index 0000000000000000000000000000000000000000..75754d3657d3958a0f1874eabe0a23d4a205fd6b --- /dev/null +++ b/tools/rootcanal/rust/src/llcp/iso.rs @@ -0,0 +1,1481 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::ffi; +use crate::packets::{hci, llcp}; +use pdl_runtime::Packet as _; +use std::collections::HashMap; +use std::convert::{TryFrom, TryInto}; + +#[derive(Clone, Copy, Debug)] +enum IsoDataPath { + Hci, +} + +// Description of CIS configuration parameters: +// +// - ISO_Interval (multiple of 1.25ms) +// ISO_Interval is the time between the CIS anchor points of adjacent CIS +// events. ISO_Interval is equal for all CISes in a CIG. +// - Sub_Interval (ms) +// Sub_Interval is the time between start of two consecutive +// subevents of a CIS +// - NSE +// NSE is the maximum number of subevents in each CIS event. +// - BN (Burst Number) +// BN is the number of payloads expected in each CIS event. +// Each CIS event has NSE - BN retransmission slots. +// - FT (Flush Timeout) +// The Flush Timeout (FT) parameter is the maximum number of CIS events +// that may be used to transmit (and retransmit) a given payload +// - Framed +// Framed indicates whether the CIS carries framed or unframed data; the +// value shall be the same in both directions. +// Unframed PDUs shall only be used when the ISO_Interval is equal to +// or an integer multiple of the SDU_Interval. +// +// For the purpose of emulating the CISes, the intervals between CIS subevents, +// and different CIS events are ignored, leading to a number of approximations: +// +// - CIG_Sync_Delay = ISO_Interval +// The CIG synchronization point is the same as the next event anchor +// - CIS_Sync_Delay = ISO_Interval +// All CISes start on the CIG anchor. +// - BN = NSE +// Unless otherwise specified in test commands. +// No retransmission slots. +// - FT = 1 +// All PDUs are sent within one event. +// - Sub_Interval = ISO_Interval / NSE + +#[allow(non_camel_case_types)] +type microseconds = u32; + +#[allow(non_camel_case_types)] +type slots = u16; + +/// CIG configuration. +#[derive(Clone, Debug, Default)] +struct CigConfig { + // CIG parameters. + iso_interval: slots, + sdu_interval_c_to_p: microseconds, + sdu_interval_p_to_c: microseconds, + ft_c_to_p: u8, + ft_p_to_c: u8, + framed: bool, + // True when the CIG can still be configured. + configurable: bool, +} + +/// CIS configuration. +#[derive(Clone, Debug, Default)] +struct CisConfig { + // CIS parameters. + // cf Vol 6, Part B § 4.5.13.1 CIS parameters. + max_sdu_c_to_p: u16, + max_sdu_p_to_c: u16, + phy_c_to_p: u8, + phy_p_to_c: u8, + nse: Option, + bn_c_to_p: Option, + bn_p_to_c: Option, + max_pdu_c_to_p: Option, + max_pdu_p_to_c: Option, +} + +/// CIG configuration. +#[derive(Clone, Debug, Default)] +struct CisRequest { + cig_id: u8, + cis_id: u8, + acl_connection_handle: u16, + cis_connection_handle: u16, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum CisState { + Configuration, + PendingRsp, + PendingAccept, + PendingInd, + Connected, +} + +/// Full CIS configuration parameters, evaluated when the CIS is created +/// or established. +#[derive(Clone, Debug)] +struct CisParameters { + cig_sync_delay: microseconds, + cis_sync_delay: microseconds, + phy_c_to_p: u8, + phy_p_to_c: u8, + nse: u8, + bn_c_to_p: u8, + bn_p_to_c: u8, + ft_c_to_p: u8, + ft_p_to_c: u8, + max_pdu_c_to_p: u16, + max_pdu_p_to_c: u16, + max_sdu_c_to_p: u16, + max_sdu_p_to_c: u16, + sdu_interval_c_to_p: microseconds, + sdu_interval_p_to_c: microseconds, + iso_interval: slots, + sub_interval: microseconds, + framed: bool, +} + +impl CisParameters { + fn new(cig_config: &CigConfig, cis_config: &CisConfig) -> CisParameters { + let bn_c_to_p: u8 = cis_config + .bn_c_to_p + .unwrap_or_else(|| ((cis_config.max_sdu_c_to_p + 250) / 251).try_into().unwrap()); + let bn_p_to_c: u8 = cis_config + .bn_p_to_c + .unwrap_or_else(|| ((cis_config.max_sdu_p_to_c + 250) / 251).try_into().unwrap()); + let nse = cis_config.nse.unwrap_or(std::cmp::max(bn_c_to_p, bn_p_to_c)); + let max_pdu_c_to_p = cis_config.max_pdu_c_to_p.unwrap_or(251); + let max_pdu_p_to_c = cis_config.max_pdu_p_to_c.unwrap_or(251); + let sub_interval = (cig_config.iso_interval as u32 * 1250) / nse as u32; + + // Select one phy in the enabled mask with + // the priority LE 2M > LE 1M > LE Coded. + fn select_phy(phys: u8) -> u8 { + match phys { + 0x2 | 0x3 | 0x6 | 0x7 => 0x2, + 0x1 | 0x5 => 0x1, + 0x4 => 0x4, + 0x0 => panic!(), // Not allowed by parameter LE Set Cig Parameters validation + _ => unreachable!(), + } + } + + let phy_c_to_p = select_phy(cis_config.phy_c_to_p); + let phy_p_to_c = select_phy(cis_config.phy_p_to_c); + + CisParameters { + cig_sync_delay: cig_config.iso_interval as u32 * 1250, + cis_sync_delay: cig_config.iso_interval as u32 * 1250, + phy_c_to_p, + phy_p_to_c, + nse, + bn_c_to_p, + bn_p_to_c, + ft_c_to_p: cig_config.ft_c_to_p, + ft_p_to_c: cig_config.ft_p_to_c, + max_pdu_c_to_p, + max_pdu_p_to_c, + max_sdu_c_to_p: cis_config.max_sdu_c_to_p, + max_sdu_p_to_c: cis_config.max_sdu_p_to_c, + sdu_interval_c_to_p: cig_config.sdu_interval_c_to_p, + sdu_interval_p_to_c: cig_config.sdu_interval_p_to_c, + iso_interval: cig_config.iso_interval, + framed: cig_config.framed, + sub_interval, + } + } + + fn phy_c_to_p(&self) -> hci::SecondaryPhyType { + match self.phy_c_to_p { + 0x1 => hci::SecondaryPhyType::Le1m, + 0x2 => hci::SecondaryPhyType::Le2m, + 0x4 => hci::SecondaryPhyType::LeCoded, + _ => unreachable!(), + } + } + + fn phy_p_to_c(&self) -> hci::SecondaryPhyType { + match self.phy_p_to_c { + 0x1 => hci::SecondaryPhyType::Le1m, + 0x2 => hci::SecondaryPhyType::Le2m, + 0x4 => hci::SecondaryPhyType::LeCoded, + _ => unreachable!(), + } + } + + fn transport_latency_c_to_p(&self) -> microseconds { + transport_latency( + self.cig_sync_delay, + self.iso_interval, + self.ft_c_to_p, + self.sdu_interval_c_to_p, + self.framed, + ) + } + + fn transport_latency_p_to_c(&self) -> microseconds { + transport_latency( + self.cig_sync_delay, + self.iso_interval, + self.ft_p_to_c, + self.sdu_interval_p_to_c, + self.framed, + ) + } +} + +/// Established CIS configuration. +#[derive(Clone)] +pub struct Cis { + pub cig_id: u8, + pub cis_id: u8, + pub role: hci::Role, + pub cis_connection_handle: u16, + pub acl_connection_handle: Option, + pub state: CisState, + parameters: Option, + iso_data_path_c_to_p: Option, + iso_data_path_p_to_c: Option, +} + +impl Cis { + pub fn max_sdu_tx(&self) -> Option { + self.parameters.as_ref().map(|parameters| match self.role { + hci::Role::Central => parameters.max_sdu_c_to_p, + hci::Role::Peripheral => parameters.max_sdu_p_to_c, + }) + } +} + +/// ISO manager state. +pub struct IsoManager { + /// CIG configuration. + cig_config: HashMap, + /// CIS configuration. + cis_config: HashMap<(u8, u8), CisConfig>, + /// Mapping from ACL connection handle to connection role. + acl_connections: HashMap, + /// Mapping from CIS connection handle to a CIS connection + /// opened as central (initiated a LL_CIS_REQ) or peripheral + /// (accepted with LL_CIS_RSP). Central connections are in the + /// configuration state as long as HCI LE Create CIS has not been + /// invoked. + cis_connections: HashMap, + /// Pending CIS connection requests, initiated from the command + /// HCI LE Create CIS. + cis_connection_requests: Vec, + /// Link layer callbacks. + ops: ffi::ControllerOps, +} + +impl IsoManager { + pub fn new(ops: ffi::ControllerOps) -> IsoManager { + IsoManager { + ops, + cig_config: Default::default(), + cis_config: Default::default(), + acl_connections: Default::default(), + cis_connections: Default::default(), + cis_connection_requests: Default::default(), + } + } + + pub fn add_acl_connection(&mut self, acl_connection_handle: u16, role: hci::Role) { + self.acl_connections.insert(acl_connection_handle, role); + } + + pub fn remove_acl_connection(&mut self, acl_connection_handle: u16) { + self.acl_connections.remove(&acl_connection_handle); + } + + // Returns the first unused handle in the range 0xe00..0xefe. + fn new_cis_connection_handle(&self) -> u16 { + (0xe00..0xefe).find(|handle| !self.cis_connections.contains_key(handle)).unwrap() + } + + // Insert a new CIS connection, optionally allocating an handle for the + // selected CIG_Id, CIS_Id, Role triplet. Returns the handle for the connection. + fn new_cis_connection(&mut self, cig_id: u8, cis_id: u8, role: hci::Role) -> u16 { + let cis_connection_handle = self + .cis_connections + .values() + .filter_map(|cis| { + (cis.cig_id == cig_id && cis.cis_id == cis_id && cis.role == role) + .then_some(cis.cis_connection_handle) + }) + .next(); + cis_connection_handle.unwrap_or_else(|| { + let cis_connection_handle = self.new_cis_connection_handle(); + self.cis_connections.insert( + cis_connection_handle, + Cis { + cig_id, + cis_id, + role, + cis_connection_handle, + state: CisState::Configuration, + acl_connection_handle: None, + parameters: None, + iso_data_path_c_to_p: None, + iso_data_path_p_to_c: None, + }, + ); + cis_connection_handle + }) + } + + fn send_hci_event>(&self, event: E) { + self.ops.send_hci_event(&event.into().to_vec()) + } + + fn send_llcp_packet>(&self, acl_connection_handle: u16, packet: P) { + self.ops.send_llcp_packet(acl_connection_handle, &packet.into().to_vec()) + } + + fn get_le_features(&self) -> u64 { + self.ops.get_le_features() + } + + fn supported_phys(&self) -> u8 { + let le_features = self.get_le_features(); + let mut supported_phys = 0x1; + if (le_features & hci::LLFeaturesBits::Le2mPhy as u64) != 0 { + supported_phys |= 0x2; + } + if (le_features & hci::LLFeaturesBits::LeCodedPhy as u64) != 0 { + supported_phys |= 0x4; + } + supported_phys + } + + fn connected_isochronous_stream_host_support(&self) -> bool { + (self.get_le_features() & hci::LLFeaturesBits::ConnectedIsochronousStreamHostSupport as u64) + != 0 + } + + pub fn get_cis_connection_handle(&self, predicate: F) -> Option + where + F: Fn(&Cis) -> bool, + { + self.cis_connections + .iter() + .filter(|(_, cis)| predicate(cis)) + .map(|(handle, _)| handle) + .next() + .cloned() + } + + pub fn get_cis(&self, cis_connection_handle: u16) -> Option<&Cis> { + self.cis_connections.get(&cis_connection_handle) + } + + /// Start the next CIS connection request, if any. + fn deque_cis_connection_request(&mut self) { + if let Some(request) = self.cis_connection_requests.pop() { + let cis_config = self.cis_config.get(&(request.cig_id, request.cis_id)).unwrap(); + let cig_config = self.cig_config.get(&request.cig_id).unwrap(); + let parameters = CisParameters::new(cig_config, cis_config); + + self.send_llcp_packet( + request.acl_connection_handle, + llcp::CisReqBuilder { + cig_id: request.cig_id, + cis_id: request.cis_id, + phy_c_to_p: parameters.phy_c_to_p, + phy_p_to_c: parameters.phy_p_to_c, + framed: cig_config.framed as u8, + max_sdu_c_to_p: cis_config.max_sdu_c_to_p, + max_sdu_p_to_c: cis_config.max_sdu_p_to_c, + sdu_interval_c_to_p: cig_config.sdu_interval_c_to_p, + sdu_interval_p_to_c: cig_config.sdu_interval_p_to_c, + max_pdu_c_to_p: parameters.max_pdu_c_to_p, + max_pdu_p_to_c: parameters.max_pdu_p_to_c, + nse: parameters.nse, + sub_interval: parameters.sub_interval, + bn_c_to_p: parameters.bn_c_to_p, + bn_p_to_c: parameters.bn_p_to_c, + ft_c_to_p: cig_config.ft_c_to_p, + ft_p_to_c: cig_config.ft_p_to_c, + iso_interval: cig_config.iso_interval, + cis_offset_min: 0, + cis_offset_max: 0, + conn_event_count: 0, + }, + ); + + let cis = self.cis_connections.get_mut(&request.cis_connection_handle).unwrap(); + cis.acl_connection_handle = Some(request.acl_connection_handle); + cis.state = CisState::PendingRsp; + cis.parameters = Some(parameters); + } + } + + pub fn hci_le_set_cig_parameters(&mut self, packet: hci::LeSetCigParameters) { + let cig_id: u8 = packet.get_cig_id(); + let sdu_interval_c_to_p: u32 = packet.get_sdu_interval_c_to_p(); + let sdu_interval_p_to_c: u32 = packet.get_sdu_interval_p_to_c(); + let framed: bool = packet.get_framing() == hci::Enable::Enabled; + let max_transport_latency_c_to_p: u16 = packet.get_max_transport_latency_c_to_p(); + let max_transport_latency_p_to_c: u16 = packet.get_max_transport_latency_p_to_c(); + let cis_config: &[hci::CisParametersConfig] = packet.get_cis_config(); + + let command_complete = |status| hci::LeSetCigParametersCompleteBuilder { + status, + cig_id, + connection_handle: vec![], + num_hci_command_packets: 1, + }; + + // If the Host issues this command when the CIG is not in the configurable + // state, the Controller shall return the error code + // Command Disallowed (0x0C). + if !self.cig_config.get(&cig_id).map(|cig| cig.configurable).unwrap_or(true) { + println!("CIG ({}) is no longer in the configurable state", cig_id); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + for cis in cis_config { + let cis_id = cis.cis_id; + let cis_connection = self.cis_connections.values().find(|cis| { + cis.cis_id == cis_id && cis.cig_id == cig_id && cis.role == hci::Role::Central + }); + let (iso_data_path_c_to_p, iso_data_path_p_to_c) = cis_connection + .map(|cis| (cis.iso_data_path_c_to_p, cis.iso_data_path_p_to_c)) + .unwrap_or((None, None)); + + // The PHY_C_To_P[i] parameter identifies which PHY to use for transmission + // from the Central to the Peripheral. The Host shall set at least one bit in this + // parameter and the Controller shall pick a PHY from the bits that are set. + if cis.phy_c_to_p == 0 || cis.phy_p_to_c == 0 { + println!( + "CIS ({}) does not configure PHys ({:x}, {:x})", + cis.cis_id, cis.phy_c_to_p, cis.phy_p_to_c + ); + return self.send_hci_event(command_complete( + hci::ErrorCode::UnsupportedFeatureOrParameterValue, + )); + } + + // If the Host sets, in the PHY_C_To_P[i] or PHY_P_To_C[i] parameters, a bit + // for a PHY that the Controller does not support, including a bit that is + // reserved for future use, the Controller shall return the error code + // Unsupported Feature or Parameter Value (0x11). + if (cis.phy_c_to_p & !self.supported_phys()) != 0 + || (cis.phy_p_to_c & !self.supported_phys()) != 0 + { + println!( + "CIS ({}) configures unsupported PHYs ({:x}, {:x})", + cis.cis_id, cis.phy_c_to_p, cis.phy_p_to_c + ); + return self.send_hci_event(command_complete( + hci::ErrorCode::UnsupportedFeatureOrParameterValue, + )); + } + + // If a CIS configuration that is being modified has a data path set in + // the Central to Peripheral direction and the Host has specified + // that Max_SDU_C_To_P[i] shall be set to zero, the Controller shall + // return the error code Command Disallowed (0x0C). + if cis.max_sdu_c_to_p == 0 && iso_data_path_c_to_p.is_some() { + println!( + "CIS ({}) has a data path for C->P but Max_SDU_C_To_P is zero", + cis.cis_id + ); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + // If a CIS configuration that is being modified has a data path set in the + // Peripheral to Central direction and the Host has specified that + // Max_SDU_P_To_C[i] shall be set to zero, the Controller shall return + // the error code Command Disallowed (0x0C). + if cis.max_sdu_p_to_c == 0 && iso_data_path_p_to_c.is_some() { + println!( + "CIS ({}) has a data path for P->C but Max_SDU_P_To_C is zero", + cis.cis_id + ); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + if cis.max_sdu_c_to_p > 0xfff || cis.max_sdu_p_to_c > 0xfff { + println!( + "invalid Max_SDU C->P ({}) or Max_SDU P->C ({}) for CIS ({})", + cis.max_sdu_c_to_p, cis.max_sdu_p_to_c, cis_id + ); + return self + .send_hci_event(command_complete(hci::ErrorCode::InvalidHciCommandParameters)); + } + } + + let configures_c_to_p = cis_config.iter().any(|cis| cis.max_sdu_c_to_p != 0) + || self.cis_config.iter().any(|(key, cis)| { + key.0 == cig_id + && cis.max_sdu_c_to_p != 0 + && cis_config.iter().all(|new_cis| new_cis.cis_id != key.1) + }); + let configures_p_to_c = cis_config.iter().any(|cis| cis.max_sdu_p_to_c != 0) + || self.cis_config.iter().any(|(key, cis)| { + key.0 == cig_id + && cis.max_sdu_p_to_c != 0 + && cis_config.iter().all(|new_cis| new_cis.cis_id != key.1) + }); + + // If the Host specifies an invalid combination of CIS parameters, the + // Controller shall return the error code Unsupported Feature or + // Parameter Value (0x11). + if (configures_c_to_p && !(0xff..=0xf_ffff).contains(&sdu_interval_c_to_p)) + || (configures_p_to_c && !(0xff..=0xf_ffff).contains(&sdu_interval_p_to_c)) + { + println!( + "invalid SDU_Interval C->P ({}) or SDU_Interval P->C ({})", + sdu_interval_c_to_p, sdu_interval_p_to_c + ); + return self + .send_hci_event(command_complete(hci::ErrorCode::InvalidHciCommandParameters)); + } + if (configures_c_to_p && !(0x5..=0xfa0).contains(&max_transport_latency_c_to_p)) + || (configures_p_to_c && !(0x5..=0xfa0).contains(&max_transport_latency_p_to_c)) + { + println!( + "invalid Max_Transport_Latency C->P ({}) or Max_Transport_Latency P->C ({})", + max_transport_latency_c_to_p, max_transport_latency_p_to_c + ); + return self + .send_hci_event(command_complete(hci::ErrorCode::InvalidHciCommandParameters)); + } + + let Some(iso_interval) = iso_interval( + sdu_interval_c_to_p, + sdu_interval_p_to_c, + framed, + max_transport_latency_c_to_p as u32 * 1000, + max_transport_latency_p_to_c as u32 * 1000, + ) else { + println!( + "ISO_Interval cannot be chosen that fulfills the requirement from the CIG parameters"); + return self.send_hci_event(command_complete( + hci::ErrorCode::UnsupportedFeatureOrParameterValue, + )); + }; + + // If the Status return parameter is non-zero, then the state of the CIG + // and its CIS configurations shall not be changed by the command. + // If the CIG did not already exist, it shall not be created. + let cig = self.cig_config.entry(cig_id).or_default(); + let mut cis_connection_handles = vec![]; + cig.iso_interval = iso_interval; + cig.sdu_interval_c_to_p = sdu_interval_c_to_p; + cig.sdu_interval_p_to_c = sdu_interval_p_to_c; + cig.ft_c_to_p = 1; + cig.ft_p_to_c = 1; + cig.framed = framed; + + for cis_config in cis_config { + self.cis_config.insert( + (cig_id, cis_config.cis_id), + CisConfig { + max_sdu_c_to_p: cis_config.max_sdu_c_to_p, + max_sdu_p_to_c: cis_config.max_sdu_p_to_c, + phy_c_to_p: cis_config.phy_c_to_p, + phy_p_to_c: cis_config.phy_p_to_c, + nse: None, + bn_c_to_p: None, + bn_p_to_c: None, + max_pdu_c_to_p: None, + max_pdu_p_to_c: None, + }, + ); + + let cis_connection_handle = + self.new_cis_connection(cig_id, cis_config.cis_id, hci::Role::Central); + cis_connection_handles.push(cis_connection_handle); + } + + self.send_hci_event(hci::LeSetCigParametersCompleteBuilder { + status: hci::ErrorCode::Success, + cig_id, + connection_handle: cis_connection_handles, + num_hci_command_packets: 1, + }) + } + + pub fn hci_le_set_cig_parameters_test(&mut self, packet: hci::LeSetCigParametersTest) { + let cig_id: u8 = packet.get_cig_id(); + let sdu_interval_c_to_p: u32 = packet.get_sdu_interval_c_to_p(); + let sdu_interval_p_to_c: u32 = packet.get_sdu_interval_p_to_c(); + let ft_c_to_p: u8 = packet.get_ft_c_to_p(); + let ft_p_to_c: u8 = packet.get_ft_p_to_c(); + let iso_interval: u16 = packet.get_iso_interval(); + let framed: bool = packet.get_framing() == hci::Enable::Enabled; + let cis_config: &[hci::LeCisParametersTestConfig] = packet.get_cis_config(); + + let command_complete = |status| hci::LeSetCigParametersTestCompleteBuilder { + status, + cig_id, + connection_handle: vec![], + num_hci_command_packets: 1, + }; + + // If the Host issues this command when the CIG is not in the configurable + // state, the Controller shall return the error code + // Command Disallowed (0x0C). + if !self.cig_config.get(&cig_id).map(|cig| cig.configurable).unwrap_or(true) { + println!("CIG ({}) is no longer in the configurable state", cig_id); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + for cis in cis_config { + let cis_id = cis.cis_id; + let cis_connection = self.cis_connections.values().find(|cis| { + cis.cis_id == cis_id && cis.cig_id == cig_id && cis.role == hci::Role::Central + }); + let (iso_data_path_c_to_p, iso_data_path_p_to_c) = cis_connection + .map(|cis| (cis.iso_data_path_c_to_p, cis.iso_data_path_p_to_c)) + .unwrap_or((None, None)); + + // The PHY_C_To_P[i] parameter identifies which PHY to use for transmission + // from the Central to the Peripheral. The Host shall set at least one bit in this + // parameter and the Controller shall pick a PHY from the bits that are set. + if cis.phy_c_to_p == 0 || cis.phy_p_to_c == 0 { + println!( + "CIS ({}) does not configure PHys ({:x}, {:x})", + cis.cis_id, cis.phy_c_to_p, cis.phy_p_to_c + ); + return self.send_hci_event(command_complete( + hci::ErrorCode::UnsupportedFeatureOrParameterValue, + )); + } + + // If the Host sets, in the PHY_C_To_P[i] or PHY_P_To_C[i] parameters, a bit + // for a PHY that the Controller does not support, including a bit that is + // reserved for future use, the Controller shall return the error code + // Unsupported Feature or Parameter Value (0x11). + if (cis.phy_c_to_p & !self.supported_phys()) != 0 + || (cis.phy_p_to_c & !self.supported_phys()) != 0 + { + println!( + "CIS ({}) configures unsupported PHYs ({:x}, {:x})", + cis.cis_id, cis.phy_c_to_p, cis.phy_p_to_c + ); + return self.send_hci_event(command_complete( + hci::ErrorCode::UnsupportedFeatureOrParameterValue, + )); + } + + // If a CIS configuration that is being modified has a data path set in + // the Central to Peripheral direction and the Host has specified + // that Max_SDU_C_To_P[i] shall be set to zero, the Controller shall + // return the error code Command Disallowed (0x0C). + if cis.max_sdu_c_to_p == 0 && iso_data_path_c_to_p.is_some() { + println!( + "CIS ({}) has a data path for C->P but Max_SDU_C_To_P is zero", + cis.cis_id + ); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + // If a CIS configuration that is being modified has a data path set in the + // Peripheral to Central direction and the Host has specified that + // Max_SDU_P_To_C[i] shall be set to zero, the Controller shall return + // the error code Command Disallowed (0x0C). + if cis.max_sdu_p_to_c == 0 && iso_data_path_p_to_c.is_some() { + println!( + "CIS ({}) has a data path for P->C but Max_SDU_P_To_C is zero", + cis.cis_id + ); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + if cis.max_sdu_c_to_p > 0xfff || cis.max_sdu_p_to_c > 0xfff { + println!( + "invalid Max_SDU C->P ({}) or Max_SDU P->C ({}) for CIS ({})", + cis.max_sdu_c_to_p, cis.max_sdu_p_to_c, cis_id + ); + return self + .send_hci_event(command_complete(hci::ErrorCode::InvalidHciCommandParameters)); + } + } + + let configures_c_to_p = cis_config.iter().any(|cis| cis.max_sdu_c_to_p != 0) + || self.cis_config.iter().any(|(key, cis)| { + key.0 == cig_id + && cis.max_sdu_c_to_p != 0 + && cis_config.iter().all(|new_cis| new_cis.cis_id != key.1) + }); + let configures_p_to_c = cis_config.iter().any(|cis| cis.max_sdu_p_to_c != 0) + || self.cis_config.iter().any(|(key, cis)| { + key.0 == cig_id + && cis.max_sdu_p_to_c != 0 + && cis_config.iter().all(|new_cis| new_cis.cis_id != key.1) + }); + + // If the Host specifies an invalid combination of CIS parameters, the + // Controller shall return the error code Unsupported Feature or + // Parameter Value (0x11). + if (configures_c_to_p && !(0xff..=0xf_ffff).contains(&sdu_interval_c_to_p)) + || (configures_p_to_c && !(0xff..=0xf_ffff).contains(&sdu_interval_p_to_c)) + { + println!( + "invalid SDU_Interval C->P ({}) or SDU_Interval P->C ({})", + sdu_interval_c_to_p, sdu_interval_p_to_c + ); + return self + .send_hci_event(command_complete(hci::ErrorCode::InvalidHciCommandParameters)); + } + + // If the Status return parameter is non-zero, then the state of the CIG + // and its CIS configurations shall not be changed by the command. + // If the CIG did not already exist, it shall not be created. + let cig = self.cig_config.entry(cig_id).or_default(); + let mut cis_connection_handles = vec![]; + cig.iso_interval = iso_interval; + cig.sdu_interval_c_to_p = sdu_interval_c_to_p; + cig.sdu_interval_p_to_c = sdu_interval_p_to_c; + cig.ft_c_to_p = ft_c_to_p; + cig.ft_p_to_c = ft_p_to_c; + cig.framed = framed; + + for cis_config in cis_config { + self.cis_config.insert( + (cig_id, cis_config.cis_id), + CisConfig { + max_sdu_c_to_p: cis_config.max_sdu_c_to_p, + max_sdu_p_to_c: cis_config.max_sdu_p_to_c, + phy_c_to_p: cis_config.phy_c_to_p, + phy_p_to_c: cis_config.phy_p_to_c, + nse: Some(cis_config.nse), + bn_c_to_p: Some(cis_config.bn_c_to_p), + bn_p_to_c: Some(cis_config.bn_p_to_c), + max_pdu_c_to_p: Some(cis_config.max_pdu_c_to_p), + max_pdu_p_to_c: Some(cis_config.max_pdu_p_to_c), + }, + ); + + let cis_connection_handle = + self.new_cis_connection(cig_id, cis_config.cis_id, hci::Role::Central); + cis_connection_handles.push(cis_connection_handle); + } + + self.send_hci_event(hci::LeSetCigParametersTestCompleteBuilder { + status: hci::ErrorCode::Success, + cig_id, + connection_handle: cis_connection_handles, + num_hci_command_packets: 1, + }) + } + + pub fn hci_le_remove_cig(&mut self, packet: hci::LeRemoveCig) { + let cig_id: u8 = packet.get_cig_id(); + + let command_complete = + |status| hci::LeRemoveCigCompleteBuilder { status, cig_id, num_hci_command_packets: 1 }; + + // If the Host issues this command with a CIG_ID that does not exist, the + // Controller shall return the error code Unknown Connection Identifier (0x02). + if !self.cig_config.contains_key(&cig_id) { + println!("CIG ({}) does not exist", cig_id); + return self.send_hci_event(command_complete(hci::ErrorCode::UnknownConnection)); + } + + // If the Host tries to remove a CIG which is in the active state, + // then the Controller shall return the error code + // Command Disallowed (0x0C). + if self.cis_connections.values().any(|cis| { + cis.role == hci::Role::Central + && cis.cig_id == cig_id + && cis.state != CisState::Configuration + }) { + println!("CIG ({}) cannot be removed as it is in active state", cig_id); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + // Clear the CIG configuration. + self.cig_config.remove(&cig_id); + self.cis_config.retain(|key, _| key.0 != cig_id); + + // Remove the CIS connections. + self.cis_connections + .retain(|_, cis| cis.role != hci::Role::Central || cis.cig_id != cig_id); + + self.send_hci_event(command_complete(hci::ErrorCode::Success)) + } + + pub fn hci_le_create_cis(&mut self, packet: hci::LeCreateCis) { + let cis_config: &[hci::LeCreateCisConfig] = packet.get_cis_config(); + let mut cis_connection_requests: Vec = vec![]; + + let command_status = + |status| hci::LeCreateCisStatusBuilder { status, num_hci_command_packets: 1 }; + + for cis_config in cis_config { + match self.acl_connections.get(&cis_config.acl_connection_handle) { + // If any ACL_Connection_Handle[i] is not the handle of an existing ACL + // connection, the Controller shall return the error code Unknown Connection + // Identifier (0x02). + None => { + println!( + "cannot create LE CIS with unknown ACL connection handle {}", + cis_config.acl_connection_handle + ); + return self.send_hci_event(command_status(hci::ErrorCode::UnknownConnection)); + } + // If the Host issues this command on an ACL_Connection_Handle where the + // Controller is the Peripheral, the Controller shall return the error code + // Command Disallowed (0x0C). + Some(hci::Role::Peripheral) => { + println!( + "the ACL connection handle {} is for a peripheral connection", + cis_config.acl_connection_handle + ); + return self.send_hci_event(command_status( + hci::ErrorCode::InvalidHciCommandParameters, + )); + } + Some(hci::Role::Central) => (), + } + + // If any CIS_Connection_Handle[i] is not the handle of a CIS or CIS + // configuration, the Controller shall return the error code Unknown Connection + // Identifier (0x02). + let Some(cis) = self.cis_connections.get(&cis_config.cis_connection_handle) else { + println!( + "cannot create LE CIS with unknown CIS connection handle {}", + cis_config.cis_connection_handle + ); + return self.send_hci_event(command_status(hci::ErrorCode::UnknownConnection)); + }; + + // If the Host attempts to create a CIS that has already been created, the + // Controller shall return the error code Connection Already Exists (0x0B). + if cis.state != CisState::Configuration { + println!( + "cannot create LE CIS with CIS connection handle {} as it is already connected", + cis_config.cis_connection_handle + ); + return self + .send_hci_event(command_status(hci::ErrorCode::ConnectionAlreadyExists)); + } + + // If two different elements of the CIS_Connection_Handle arrayed parameter + // identify the same CIS, the Controller shall return the error code + // Invalid HCI Command Parameters (0x12). + if cis_connection_requests + .iter() + .any(|request| request.cis_connection_handle == cis_config.cis_connection_handle) + { + println!( + "the CIS connection handle {} is requested twice", + cis_config.cis_connection_handle + ); + return self + .send_hci_event(command_status(hci::ErrorCode::InvalidHciCommandParameters)); + } + + cis_connection_requests.push(CisRequest { + cis_connection_handle: cis_config.cis_connection_handle, + acl_connection_handle: cis_config.acl_connection_handle, + cig_id: cis.cig_id, + cis_id: cis.cis_id, + }); + } + + // If the Host issues this command before all the HCI_LE_CIS_Established + // events from the previous use of the command have been generated, the + // Controller shall return the error code Command Disallowed (0x0C). + if !self.cis_connection_requests.is_empty() { + println!("another LE Create CIS request is already pending"); + return self.send_hci_event(command_status(hci::ErrorCode::CommandDisallowed)); + } + + // If the Host issues this command when the Connected Isochronous Stream + // (Host Support) feature bit (see [Vol 6] Part B, Section 4.6.27) is not set, + // the Controller shall return the error code Command Disallowed (0x0C). + if !self.connected_isochronous_stream_host_support() { + println!("the feature bit Connected Isochronous Stream (Host Support) is not set"); + return self.send_hci_event(command_status(hci::ErrorCode::CommandDisallowed)); + } + + // Update the pending CIS request list. + cis_connection_requests.reverse(); + self.cis_connection_requests = cis_connection_requests; + + // Send the first connection request. + self.deque_cis_connection_request(); + self.send_hci_event(command_status(hci::ErrorCode::Success)) + } + + pub fn hci_le_accept_cis_request(&mut self, packet: hci::LeAcceptCisRequest) { + let connection_handle: u16 = packet.get_connection_handle(); + + let command_status = + |status| hci::LeAcceptCisRequestStatusBuilder { status, num_hci_command_packets: 1 }; + + // If the Peripheral’s Host issues this command with a + // Connection_Handle that does not exist, or the Connection_Handle + // is not for a CIS, the Controller shall return the error code + // Unknown Connection Identifier (0x02). + if !self.cis_connections.contains_key(&connection_handle) { + println!( + "cannot accept LE CIS request with invalid connection handle {}", + connection_handle + ); + return self.send_hci_event(command_status(hci::ErrorCode::UnknownConnection)); + } + + let cis = self.cis_connections.get_mut(&connection_handle).unwrap(); + + // If the Central’s Host issues this command, the Controller shall + // return the error code Command Disallowed (0x0C). + if cis.role == hci::Role::Central { + println!( + "cannot accept LE CIS request with central connection handle {}", + connection_handle + ); + return self.send_hci_event(command_status(hci::ErrorCode::CommandDisallowed)); + } + + // If the Peripheral's Host issues this command with a Connection_Handle + // for a CIS that has already been established or that already has an + // HCI_LE_Accept_CIS_Request or HCI_LE_Reject_CIS_Request command in progress, + // the Controller shall return the error code Command Disallowed (0x0C). + if cis.state != CisState::PendingAccept { + println!( + "cannot accept LE CIS request for non-pending connection handle {}", + connection_handle + ); + return self.send_hci_event(command_status(hci::ErrorCode::CommandDisallowed)); + } + + // Update local state. + cis.state = CisState::PendingInd; + + // Send back LL_CIS_RSP to accept the request. + let acl_connection_handle = cis.acl_connection_handle.unwrap(); + self.send_llcp_packet( + acl_connection_handle, + llcp::CisRspBuilder { + cis_offset_min: 0, + cis_offset_max: 0xffffff, + conn_event_count: 0, + }, + ); + + self.send_hci_event(command_status(hci::ErrorCode::Success)) + } + + pub fn hci_le_reject_cis_request(&mut self, packet: hci::LeRejectCisRequest) { + let connection_handle: u16 = packet.get_connection_handle(); + + let command_complete = |status| hci::LeRejectCisRequestCompleteBuilder { + status, + connection_handle, + num_hci_command_packets: 1, + }; + + // If the Peripheral’s Host issues this command with a + // Connection_Handle that does not exist, or the Connection_Handle + // is not for a CIS, the Controller shall return the error code + // Unknown Connection Identifier (0x02). + if !self.cis_connections.contains_key(&connection_handle) { + println!( + "cannot accept LE CIS request with invalid connection handle {}", + connection_handle + ); + return self.send_hci_event(command_complete(hci::ErrorCode::UnknownConnection)); + } + + let cis = self.cis_connections.get(&connection_handle).unwrap(); + + // If the Central’s Host issues this command, the Controller shall + // return the error code Command Disallowed (0x0C). + if cis.role == hci::Role::Central { + println!( + "cannot accept LE CIS request with central connection handle {}", + connection_handle + ); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + // If the Peripheral's Host issues this command with a Connection_Handle + // for a CIS that has already been established or that already has an + // HCI_LE_Accept_CIS_Request or HCI_LE_Reject_CIS_Request command in progress, + // the Controller shall return the error code Command Disallowed (0x0C). + if cis.state != CisState::PendingAccept { + println!( + "cannot accept LE CIS request for non-pending connection handle {}", + connection_handle + ); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + // Update local state. + let acl_connection_handle = cis.acl_connection_handle.unwrap(); + self.cis_connections.remove(&connection_handle); + + // Send back LL_CIS_RSP to reject the request. + let error_code = if packet.get_reason() == hci::ErrorCode::Success { + hci::ErrorCode::RemoteUserTerminatedConnection + } else { + packet.get_reason() + }; + self.send_llcp_packet( + acl_connection_handle, + llcp::RejectExtIndBuilder { + reject_opcode: llcp::Opcode::LlCisReq as u8, + error_code: error_code as u8, + }, + ); + + self.send_hci_event(command_complete(hci::ErrorCode::Success)) + } + + pub fn hci_le_setup_iso_data_path(&mut self, packet: hci::LeSetupIsoDataPath) { + let connection_handle: u16 = packet.get_connection_handle(); + let codec_configuration = packet.get_codec_configuration(); + + let command_complete = |status| hci::LeSetupIsoDataPathCompleteBuilder { + status, + connection_handle, + num_hci_command_packets: 1, + }; + + // If the Host attempts to set a data path with a Connection Handle that does not + // exist or that is not for a CIS, CIS configuration, or BIS, the Controller shall + // return the error code Unknown Connection Identifier (0x02). + let Some(cis) = self.cis_connections.get_mut(&connection_handle) else { + println!("the CIS connection handle 0x{:x} is not assigned", connection_handle); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + }; + + let (c_to_p_direction, p_to_c_direction) = if cis.role == hci::Role::Central { + (hci::DataPathDirection::Output, hci::DataPathDirection::Input) + } else { + (hci::DataPathDirection::Input, hci::DataPathDirection::Output) + }; + + // If the Host issues this command more than once for the same + // Connection_Handle and direction before issuing the HCI_LE_Remove_ISO_Data_- + // Path command for that Connection_Handle and direction, the Controller shall + // return the error code Command Disallowed (0x0C). + if cis.iso_data_path_c_to_p.is_some() + && packet.get_data_path_direction() == c_to_p_direction + { + println!("C->P ISO data path already configured for ({}, {})", cis.cig_id, cis.cis_id); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + if cis.iso_data_path_p_to_c.is_some() + && packet.get_data_path_direction() == p_to_c_direction + { + println!("P->C ISO data path already configured for ({}, {})", cis.cig_id, cis.cis_id); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + // If the Host issues this command for a CIS on a Peripheral before it has issued + // the HCI_LE_Accept_CIS_Request command for that CIS, then the Controller + // shall return the error code Command Disallowed (0x0C). + if cis.role == hci::Role::Peripheral && cis.state == CisState::PendingAccept { + println!("setup ISO data path sent before accepting the CIS request"); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + // If the Host issues this command for a vendor-specific data transport path that + // has not been configured using the HCI_Configure_Data_Path command, the + // Controller shall return the error code Command Disallowed (0x0C). + + // If the Host attempts to set an output data path using a connection handle that is + // for an Isochronous Broadcaster, for an input data path on a Synchronized + // Receiver, or for a data path for the direction on a unidirectional CIS where BN + // is set to 0, the Controller shall return the error code Command Disallowed + // (0x0C). + + // If the Host issues this command with Codec_Configuration_Length non-zero + // and Codec_ID set to transparent air mode, the Controller shall return the error + // code Invalid HCI Command Parameters (0x12). + if !codec_configuration.is_empty() && packet.get_codec_id() == 0x3 { + println!("Codec Configuration is not empty and Codec ID is for transparent air mode"); + return self + .send_hci_event(command_complete(hci::ErrorCode::InvalidHciCommandParameters)); + } + + // If the Host issues this command with codec-related parameters that exceed the + // bandwidth and latency allowed on the established CIS or BIS identified by the + // Connection_Handle parameter, the Controller shall return the error code + // Invalid HCI Command Parameters (0x12). + + if packet.get_data_path_direction() == c_to_p_direction { + cis.iso_data_path_c_to_p = Some(IsoDataPath::Hci); + } else { + cis.iso_data_path_p_to_c = Some(IsoDataPath::Hci); + } + + self.send_hci_event(command_complete(hci::ErrorCode::Success)) + } + + pub fn hci_le_remove_iso_data_path(&mut self, packet: hci::LeRemoveIsoDataPath) { + let connection_handle: u16 = packet.get_connection_handle(); + let data_path_direction = packet.get_remove_data_path_direction(); + + let command_complete = |status| hci::LeRemoveIsoDataPathCompleteBuilder { + status, + connection_handle, + num_hci_command_packets: 1, + }; + + // If the Host issues this command with a Connection_Handle that does not exist + // or is not for a CIS, CIS configuration, or BIS, the Controller shall return the + // error code Unknown Connection Identifier (0x02). + let Some(cis) = self.cis_connections.get_mut(&connection_handle) else { + println!("the CIS connection handle 0x{:x} is not assigned", connection_handle); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + }; + + let (remove_c_to_p, remove_p_to_c) = if cis.role == hci::Role::Central { + ( + data_path_direction == hci::RemoveDataPathDirection::Output + || data_path_direction == hci::RemoveDataPathDirection::InputAndOutput, + data_path_direction == hci::RemoveDataPathDirection::Input + || data_path_direction == hci::RemoveDataPathDirection::InputAndOutput, + ) + } else { + ( + data_path_direction == hci::RemoveDataPathDirection::Input + || data_path_direction == hci::RemoveDataPathDirection::InputAndOutput, + data_path_direction == hci::RemoveDataPathDirection::Output + || data_path_direction == hci::RemoveDataPathDirection::InputAndOutput, + ) + }; + + // If the Host issues this command for a data path that has not been set up (using + // the HCI_LE_Setup_ISO_Data_Path command), the Controller shall return the + // error code Command Disallowed (0x0C) + if cis.iso_data_path_c_to_p.is_none() && remove_c_to_p { + println!("attempted to remove Iso Data Path C->P but it is not configured"); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + if cis.iso_data_path_p_to_c.is_none() && remove_p_to_c { + println!("attempted to remove Iso Data Path P->C but it is not configured"); + return self.send_hci_event(command_complete(hci::ErrorCode::CommandDisallowed)); + } + + if remove_c_to_p { + cis.iso_data_path_c_to_p = None; + } + if remove_p_to_c { + cis.iso_data_path_p_to_c = None; + } + + self.send_hci_event(command_complete(hci::ErrorCode::Success)) + } + + pub fn hci_disconnect(&mut self, packet: hci::Disconnect) { + let connection_handle: u16 = packet.get_connection_handle(); + let command_status = + |status| hci::DisconnectStatusBuilder { status, num_hci_command_packets: 1 }; + + let Some(cis) = self.cis_connections.get(&connection_handle).cloned() else { + return self.send_hci_event(command_status(hci::ErrorCode::UnknownConnection)); + }; + + // If, on the Central, the Host issues this command before issuing the + // HCI_LE_Create_CIS command for the same CIS, then the Controller shall + // return the error code Command Disallowed (0x0C). + // If, on the Peripheral, the Host issues this command before the Controller has + // generated the HCI_LE_CIS_Established event for that CIS, then the Controller + // shall return the error code Command Disallowed (0x0C). + if !matches!(cis.state, CisState::Connected | CisState::PendingRsp) { + println!( + "cannot disconnect CIS connection with handle {} because it is not connected", + connection_handle + ); + return self.send_hci_event(command_status(hci::ErrorCode::CommandDisallowed)); + } + + if cis.role == hci::Role::Central { + self.cis_connections + .entry(connection_handle) + .and_modify(|cis| cis.state = CisState::Configuration); + } else { + self.cis_connections.remove(&connection_handle); + } + + self.send_llcp_packet( + cis.acl_connection_handle.unwrap(), + llcp::CisTerminateIndBuilder { + cig_id: cis.cig_id, + cis_id: cis.cis_id, + error_code: packet.get_reason().into(), + }, + ); + + self.send_hci_event(command_status(hci::ErrorCode::Success)); + self.send_hci_event(hci::DisconnectionCompleteBuilder { + status: hci::ErrorCode::Success, + connection_handle, + reason: hci::ErrorCode::ConnectionTerminatedByLocalHost, + }); + } + + pub fn ll_cis_req(&mut self, acl_connection_handle: u16, packet: llcp::CisReq) { + let cis_connection_handle = self.new_cis_connection_handle(); + self.cis_connections.insert( + cis_connection_handle, + Cis { + cig_id: packet.get_cig_id(), + cis_id: packet.get_cis_id(), + role: hci::Role::Peripheral, + acl_connection_handle: Some(acl_connection_handle), + cis_connection_handle, + state: CisState::PendingAccept, + iso_data_path_c_to_p: None, + iso_data_path_p_to_c: None, + parameters: Some(CisParameters { + cig_sync_delay: 0, + cis_sync_delay: 0, + phy_c_to_p: packet.get_phy_c_to_p(), + phy_p_to_c: packet.get_phy_p_to_c(), + nse: packet.get_nse(), + bn_c_to_p: packet.get_bn_c_to_p(), + bn_p_to_c: packet.get_bn_p_to_c(), + ft_c_to_p: packet.get_ft_c_to_p(), + ft_p_to_c: packet.get_ft_p_to_c(), + max_pdu_c_to_p: packet.get_max_pdu_c_to_p(), + max_pdu_p_to_c: packet.get_max_pdu_p_to_c(), + max_sdu_c_to_p: packet.get_max_sdu_c_to_p(), + max_sdu_p_to_c: packet.get_max_sdu_p_to_c(), + sdu_interval_c_to_p: packet.get_sdu_interval_c_to_p(), + sdu_interval_p_to_c: packet.get_sdu_interval_p_to_c(), + iso_interval: packet.get_iso_interval(), + sub_interval: packet.get_sub_interval(), + framed: packet.get_framed() != 0, + }), + }, + ); + + self.send_hci_event(hci::LeCisRequestBuilder { + acl_connection_handle, + cis_connection_handle, + cig_id: packet.get_cig_id(), + cis_id: packet.get_cis_id(), + }) + } + + pub fn ll_cis_rsp(&mut self, acl_connection_handle: u16, _packet: llcp::CisRsp) { + let cis_connection_handle = self.get_cis_connection_handle(|cis| { + cis.acl_connection_handle == Some(acl_connection_handle) + && cis.role == hci::Role::Central + && cis.state == CisState::PendingRsp + }); + + if let Some(cis_connection_handle) = cis_connection_handle { + self.cis_connections + .entry(cis_connection_handle) + .and_modify(|cis| cis.state = CisState::Connected); + let cis = self.cis_connections.get(&cis_connection_handle).unwrap(); + let parameters = cis.parameters.as_ref().unwrap(); + self.send_llcp_packet( + acl_connection_handle, + llcp::CisIndBuilder { + aa: 0, + cis_offset: 0, + cig_sync_delay: parameters.cig_sync_delay, + cis_sync_delay: parameters.cis_sync_delay, + conn_event_count: 0, + }, + ); + self.send_hci_event(hci::LeCisEstablishedBuilder { + status: hci::ErrorCode::Success, + connection_handle: cis_connection_handle, + cig_sync_delay: parameters.cig_sync_delay, + cis_sync_delay: parameters.cis_sync_delay, + transport_latency_c_to_p: parameters.transport_latency_c_to_p(), + transport_latency_p_to_c: parameters.transport_latency_p_to_c(), + phy_c_to_p: parameters.phy_c_to_p(), + phy_p_to_c: parameters.phy_p_to_c(), + nse: parameters.nse, + bn_c_to_p: parameters.bn_c_to_p, + bn_p_to_c: parameters.bn_p_to_c, + ft_c_to_p: parameters.ft_c_to_p, + ft_p_to_c: parameters.ft_p_to_c, + max_pdu_c_to_p: parameters.max_pdu_c_to_p as u8, + max_pdu_p_to_c: parameters.max_pdu_p_to_c as u8, + iso_interval: parameters.iso_interval, + }); + // Start the next pending connection request. + self.deque_cis_connection_request(); + } else { + println!("skipping out of place packet LL_CIS_RSP"); + } + } + + pub fn ll_reject_ext_ind(&mut self, acl_connection_handle: u16, packet: llcp::RejectExtInd) { + if packet.get_reject_opcode() != llcp::Opcode::LlCisReq as u8 { + return; + } + + let cis_connection_handle = self.get_cis_connection_handle(|cis| { + cis.acl_connection_handle == Some(acl_connection_handle) + && cis.role == hci::Role::Central + && cis.state == CisState::PendingRsp + }); + + if let Some(cis_connection_handle) = cis_connection_handle { + let cis = self.cis_connections.get_mut(&cis_connection_handle).unwrap(); + cis.state = CisState::Configuration; + cis.parameters = None; + self.send_hci_event(hci::LeCisEstablishedBuilder { + status: hci::ErrorCode::RemoteUserTerminatedConnection, + connection_handle: cis_connection_handle, + cig_sync_delay: 0, + cis_sync_delay: 0, + transport_latency_c_to_p: 0, + transport_latency_p_to_c: 0, + phy_c_to_p: hci::SecondaryPhyType::NoPackets, + phy_p_to_c: hci::SecondaryPhyType::NoPackets, + nse: 0, + bn_p_to_c: 0, + bn_c_to_p: 0, + ft_p_to_c: 0, + ft_c_to_p: 0, + max_pdu_p_to_c: 0, + max_pdu_c_to_p: 0, + iso_interval: 0, + }); + // Start the next pending connection request. + self.deque_cis_connection_request(); + } else { + println!("skipping out of place packet LL_CIS_IND"); + } + } + + pub fn ll_cis_ind(&mut self, acl_connection_handle: u16, packet: llcp::CisInd) { + let cis_connection_handle = self.get_cis_connection_handle(|cis| { + cis.acl_connection_handle == Some(acl_connection_handle) + && cis.role == hci::Role::Peripheral + && cis.state == CisState::PendingInd + }); + + if let Some(cis_connection_handle) = cis_connection_handle { + self.cis_connections.entry(cis_connection_handle).and_modify(|cis| { + cis.state = CisState::Connected; + let parameters = cis.parameters.as_mut().unwrap(); + parameters.cig_sync_delay = packet.get_cig_sync_delay(); + parameters.cis_sync_delay = packet.get_cis_sync_delay(); + }); + let cis = self.cis_connections.get(&cis_connection_handle).unwrap(); + let parameters = cis.parameters.as_ref().unwrap(); + self.send_hci_event(hci::LeCisEstablishedBuilder { + status: hci::ErrorCode::Success, + connection_handle: cis_connection_handle, + cig_sync_delay: parameters.cig_sync_delay, + cis_sync_delay: parameters.cis_sync_delay, + transport_latency_c_to_p: parameters.transport_latency_c_to_p(), + transport_latency_p_to_c: parameters.transport_latency_p_to_c(), + phy_c_to_p: parameters.phy_c_to_p(), + phy_p_to_c: parameters.phy_p_to_c(), + nse: parameters.nse, + bn_p_to_c: parameters.bn_c_to_p, + bn_c_to_p: parameters.bn_p_to_c, + ft_p_to_c: parameters.ft_c_to_p, + ft_c_to_p: parameters.ft_p_to_c, + max_pdu_p_to_c: parameters.max_pdu_c_to_p as u8, + max_pdu_c_to_p: parameters.max_pdu_p_to_c as u8, + iso_interval: parameters.iso_interval, + }); + } else { + println!("skipping out of place packet LL_CIS_IND"); + } + } + + pub fn ll_cis_terminate_ind( + &mut self, + acl_connection_handle: u16, + packet: llcp::CisTerminateInd, + ) { + let cis_connection_handle = self.get_cis_connection_handle(|cis| { + cis.acl_connection_handle == Some(acl_connection_handle) + && cis.cig_id == packet.get_cig_id() + && cis.cis_id == packet.get_cis_id() + }); + + if let Some(cis_connection_handle) = cis_connection_handle { + self.send_hci_event(hci::DisconnectionCompleteBuilder { + status: hci::ErrorCode::Success, + connection_handle: cis_connection_handle, + reason: hci::ErrorCode::try_from(packet.get_error_code()).unwrap(), + }); + self.cis_connections.remove(&cis_connection_handle); + } else { + println!("skipping out of place packet LL_CIS_TERMINATE_IND"); + } + } +} + +/// Derive a valid ISO_Interval for a CIG based on the +/// LE Set Cig Parameters command input. SDU_Interval, Max_Transport_Latency are +/// provided microseconds. +fn iso_interval( + sdu_interval_c_to_p: microseconds, + sdu_interval_p_to_c: microseconds, + framed: bool, + max_transport_latency_c_to_p: microseconds, + max_transport_latency_p_to_c: microseconds, +) -> Option { + if framed { + let iso_interval = std::cmp::max(sdu_interval_c_to_p, sdu_interval_p_to_c); + Some(((iso_interval + 1249) / 1250) as u16) + } else { + // Unframed PDUs shall only be used when the ISO_Interval is equal to + // or an integer multiple of the SDU_Interval and a constant time offset + // alignment is maintained between the SDU generation and the timing in + // the isochronous transport. + let iso_interval = num_integer::lcm( + 1250, + match (sdu_interval_c_to_p, sdu_interval_p_to_c) { + (0, 0) => panic!(), + (0, _) => sdu_interval_p_to_c, + (_, 0) => sdu_interval_c_to_p, + _ => num_integer::lcm(sdu_interval_c_to_p, sdu_interval_p_to_c), + }, + ); + let min_transport_latency_c_to_p = 2 * iso_interval - sdu_interval_c_to_p; + let min_transport_latency_p_to_c = 2 * iso_interval - sdu_interval_p_to_c; + + ((iso_interval / 1250) <= u16::MAX as u32 + && (sdu_interval_c_to_p == 0 + || min_transport_latency_c_to_p <= max_transport_latency_c_to_p) + && (sdu_interval_p_to_c == 0 + || min_transport_latency_p_to_c <= max_transport_latency_p_to_c)) + .then_some((iso_interval / 1250) as u16) + } +} + +/// Compute the transport latency for a CIG based on the +/// configuration parameters. CIG_Sync_Delay, SDU_Interval are provided +/// in microseconds, ISO_Interval in multiple of 1.25ms, +fn transport_latency( + cig_sync_delay: microseconds, + iso_interval: slots, + ft: u8, + sdu_interval: microseconds, + framed: bool, +) -> microseconds { + let iso_interval = iso_interval as u32 * 1250; + if framed { + cig_sync_delay + ft as u32 * iso_interval + sdu_interval + } else { + cig_sync_delay + ft as u32 * iso_interval - sdu_interval + } +} + +#[cfg(test)] +mod test { + use crate::llcp::iso::*; + + #[test] + fn test_iso_interval() { + assert!(iso_interval(0x7530, 0x7530, false, 0x7530, 0x7530).is_some()); + assert!(iso_interval(0x7530, 0, false, 0x7530, 0x7530).is_some()); + assert!(iso_interval(0x7530, 0x7530, false, 0x7000, 0x7000).is_none()); + } +} diff --git a/tools/rootcanal/rust/src/llcp/manager.rs b/tools/rootcanal/rust/src/llcp/manager.rs new file mode 100644 index 0000000000000000000000000000000000000000..9be01494e7f408a5e035cd461981f95eb10911cb --- /dev/null +++ b/tools/rootcanal/rust/src/llcp/manager.rs @@ -0,0 +1,125 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::ffi; +use crate::llcp::iso; +use crate::packets::{hci, llcp}; +use std::collections::HashMap; +use std::convert::TryFrom; +use thiserror::Error; + +struct Link { + acl_connection_handle: u16, + role: hci::Role, +} + +pub struct LinkLayer { + ops: ffi::ControllerOps, + links: HashMap, + iso: iso::IsoManager, +} + +#[derive(Error, Debug)] +pub enum LinkLayerError { + #[error("Unknown peer")] + UnknownPeer, + #[error("Link already exists")] + LinkAlreadyExists, + #[error("Unhandled HCI packet")] + UnhandledHciPacket, + #[error("Invalid HCI packet")] + InvalidHciPacket, + #[error("Invalid LLCP packet")] + InvalidLlcpPacket, +} + +impl LinkLayer { + pub fn new(ops: ffi::ControllerOps) -> LinkLayer { + let iso = iso::IsoManager::new(ops.clone()); + LinkLayer { ops, links: HashMap::new(), iso } + } + + pub fn add_link( + &mut self, + acl_connection_handle: u16, + _peer_address: hci::Address, + role: hci::Role, + ) -> Result<(), LinkLayerError> { + if self.links.contains_key(&acl_connection_handle) { + return Err(LinkLayerError::LinkAlreadyExists); + } + + self.links.insert(acl_connection_handle, Link { acl_connection_handle, role }); + self.iso.add_acl_connection(acl_connection_handle, role); + Ok(()) + } + + pub fn remove_link(&mut self, acl_connection_handle: u16) -> Result<(), LinkLayerError> { + if self.links.remove(&acl_connection_handle).is_none() { + return Err(LinkLayerError::UnknownPeer); + } + + self.iso.remove_acl_connection(acl_connection_handle); + Ok(()) + } + + pub fn tick(&mut self) {} + + pub fn ingest_hci(&mut self, packet: hci::Command) -> Result<(), LinkLayerError> { + use hci::CommandChild::*; + match packet.specialize() { + Disconnect(packet) => self.iso.hci_disconnect(packet), + LeSetCigParameters(packet) => self.iso.hci_le_set_cig_parameters(packet), + LeSetCigParametersTest(packet) => self.iso.hci_le_set_cig_parameters_test(packet), + LeCreateCis(packet) => self.iso.hci_le_create_cis(packet), + LeRemoveCig(packet) => self.iso.hci_le_remove_cig(packet), + LeAcceptCisRequest(packet) => self.iso.hci_le_accept_cis_request(packet), + LeRejectCisRequest(packet) => self.iso.hci_le_reject_cis_request(packet), + LeSetupIsoDataPath(packet) => self.iso.hci_le_setup_iso_data_path(packet), + LeRemoveIsoDataPath(packet) => self.iso.hci_le_remove_iso_data_path(packet), + _ => Err(LinkLayerError::UnhandledHciPacket)?, + }; + Ok(()) + } + + pub fn ingest_llcp( + &mut self, + acl_connection_handle: u16, + packet: llcp::LlcpPacket, + ) -> Result<(), LinkLayerError> { + use llcp::LlcpPacketChild::*; + match packet.specialize() { + RejectExtInd(packet) => match llcp::Opcode::try_from(packet.get_reject_opcode()) { + Ok(llcp::Opcode::LlCisReq) => { + self.iso.ll_reject_ext_ind(acl_connection_handle, packet) + } + _ => unreachable!(), + }, + CisReq(packet) => self.iso.ll_cis_req(acl_connection_handle, packet), + CisRsp(packet) => self.iso.ll_cis_rsp(acl_connection_handle, packet), + CisInd(packet) => self.iso.ll_cis_ind(acl_connection_handle, packet), + CisTerminateInd(packet) => self.iso.ll_cis_terminate_ind(acl_connection_handle, packet), + _ => unimplemented!(), + } + Ok(()) + } + + pub fn get_cis_connection_handle(&self, cig_id: u8, cis_id: u8) -> Option { + self.iso.get_cis_connection_handle(|cis| cis.cig_id == cig_id && cis.cis_id == cis_id) + } + + pub fn get_cis(&self, cis_connection_handle: u16) -> Option<&iso::Cis> { + self.iso.get_cis(cis_connection_handle) + } +} diff --git a/tools/pdl/src/backends/rust_no_allocation/utils.rs b/tools/rootcanal/rust/src/llcp/mod.rs similarity index 56% rename from tools/pdl/src/backends/rust_no_allocation/utils.rs rename to tools/rootcanal/rust/src/llcp/mod.rs index a9286de354b9e0995f76300ce70bc0f9e1da0924..6aa87c03ad6d26d2baf8c61a0c0d196d6d94331b 100644 --- a/tools/pdl/src/backends/rust_no_allocation/utils.rs +++ b/tools/rootcanal/rust/src/llcp/mod.rs @@ -1,10 +1,10 @@ -// Copyright 2023 Google LLC +// Copyright 2023 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// https://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -12,14 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use proc_macro2::Ident; -use quote::format_ident; +#![allow(dead_code, missing_docs)] -pub fn get_integer_type(width: usize) -> Ident { - let best_width = [8, 16, 32, 64] - .into_iter() - .filter(|x| *x >= width) - .min() - .unwrap_or_else(|| panic!("width {width} is too large")); - format_ident!("u{best_width}") -} +mod iso; +pub mod manager; diff --git a/tools/rootcanal/rust/src/lmp/ec.rs b/tools/rootcanal/rust/src/lmp/ec.rs index 0076b7e636a0f2e8fe1dfb0b16e5d90c870d29c7..c8beee9ee0a167baf0e7ade7faa4c94bb563a420 100644 --- a/tools/rootcanal/rust/src/lmp/ec.rs +++ b/tools/rootcanal/rust/src/lmp/ec.rs @@ -1,30 +1,23 @@ -/****************************************************************************** - * - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -/****************************************************************************** - * IMPORTANT - * - * These cryptography methods do not provide any security or correctness - * ensurance. - * They should be used only in Bluetooth emulation, not including any production - * environment. - * - ******************************************************************************/ +// Copyright 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Cryptography library for LMP procedures. +//! +//! IMPORTANT +//! These cryptography methods do not provide any security or correctness +//! ensurance. They should be used only in Bluetooth emulation, not including +//! any production environment. use num_bigint::{BigInt, Sign}; use num_integer::Integer; diff --git a/tools/rootcanal/rust/src/lmp/manager.rs b/tools/rootcanal/rust/src/lmp/manager.rs index 4280f46c64f6c0f523380ff16c77a7de39be0c72..9e93a016ff81cac2c6cb2c2deb3ddf3df815f5a1 100644 --- a/tools/rootcanal/rust/src/lmp/manager.rs +++ b/tools/rootcanal/rust/src/lmp/manager.rs @@ -1,3 +1,17 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::cell::{Cell, RefCell}; use std::collections::VecDeque; use std::convert::{TryFrom, TryInto}; @@ -6,22 +20,20 @@ use std::pin::Pin; use std::rc::{Rc, Weak}; use std::task::{Context, Poll}; +use pdl_runtime::Packet as _; use thiserror::Error; -use crate::ffi::LinkManagerOps; +use crate::ffi::ControllerOps; use crate::future::noop_waker; use crate::lmp::procedure; use crate::num_hci_command_packets; use crate::packets::{hci, lmp}; -use hci::Packet as _; -use lmp::Packet as _; - struct Link { peer: Cell, // Only store one HCI packet as our Num_HCI_Command_Packets // is always 1 - hci: Cell>, + hci: Cell>, lmp: RefCell>, } @@ -40,11 +52,11 @@ impl Link { self.lmp.borrow_mut().push_back(packet); } - fn ingest_hci(&self, command: hci::CommandPacket) { + fn ingest_hci(&self, command: hci::Command) { assert!(self.hci.replace(Some(command)).is_none(), "HCI flow control violation"); } - fn poll_hci_command>(&self) -> Poll { + fn poll_hci_command>(&self) -> Poll { let command = self.hci.take(); if let Some(command) = command.clone().and_then(|c| c.try_into().ok()) { @@ -88,13 +100,13 @@ pub enum LinkManagerError { pub const MAX_PEER_NUMBER: usize = 7; pub struct LinkManager { - ops: LinkManagerOps, + ops: ControllerOps, links: [Link; MAX_PEER_NUMBER], procedures: RefCell<[Option>>>; MAX_PEER_NUMBER]>, } impl LinkManager { - pub fn new(ops: LinkManagerOps) -> Self { + pub fn new(ops: ControllerOps) -> Self { Self { ops, links: Default::default(), procedures: Default::default() } } @@ -117,14 +129,14 @@ impl LinkManager { /// with the specified error code. fn send_command_complete_event( &self, - command: &hci::CommandPacket, + command: &hci::Command, status: hci::ErrorCode, ) -> Result<(), LinkManagerError> { use hci::CommandChild::*; #[allow(unused_imports)] use Option::None; // Overwrite `None` variant of `Child` enum - let event: hci::EventPacket = match command.specialize() { + let event: hci::Event = match command.specialize() { LinkKeyRequestReply(packet) => hci::LinkKeyRequestReplyCompleteBuilder { status, bd_addr: packet.get_bd_addr(), @@ -229,7 +241,7 @@ impl LinkManager { Ok(()) } - pub fn ingest_hci(&self, command: hci::CommandPacket) -> Result<(), LinkManagerError> { + pub fn ingest_hci(&self, command: hci::Command) -> Result<(), LinkManagerError> { // Try to find the matching link from the command arguments let link = hci::command_connection_handle(&command) .and_then(|handle| self.ops.get_address(handle)) @@ -288,7 +300,7 @@ struct LinkContext { } impl procedure::Context for LinkContext { - fn poll_hci_command>(&self) -> Poll { + fn poll_hci_command>(&self) -> Poll { if let Some(manager) = self.manager.upgrade() { manager.link(self.index).poll_hci_command() } else { @@ -304,7 +316,7 @@ impl procedure::Context for LinkContext { } } - fn send_hci_event>(&self, event: E) { + fn send_hci_event>(&self, event: E) { if let Some(manager) = self.manager.upgrade() { manager.ops.send_hci_event(&event.into().to_vec()) } @@ -334,7 +346,7 @@ impl procedure::Context for LinkContext { fn extended_features(&self, features_page: u8) -> u64 { if let Some(manager) = self.manager.upgrade() { - manager.ops.extended_features(features_page) + manager.ops.get_extended_features(features_page) } else { 0 } diff --git a/tools/rootcanal/rust/src/lmp/mod.rs b/tools/rootcanal/rust/src/lmp/mod.rs index e3047a87522e12e5678985b5167981f5ce4f9314..6ec6663bf02f5c6e1f6d1d39267ecf69e06f37c7 100644 --- a/tools/rootcanal/rust/src/lmp/mod.rs +++ b/tools/rootcanal/rust/src/lmp/mod.rs @@ -1,3 +1,17 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + pub mod ec; pub mod manager; pub mod procedure; diff --git a/tools/rootcanal/rust/src/lmp/procedure/authentication.rs b/tools/rootcanal/rust/src/lmp/procedure/authentication.rs index 83fa0cb66ef98e930b190269083405b81747e7ac..db69eaa575692c8f548971c2eacc51dab97a0d1f 100644 --- a/tools/rootcanal/rust/src/lmp/procedure/authentication.rs +++ b/tools/rootcanal/rust/src/lmp/procedure/authentication.rs @@ -1,4 +1,18 @@ -// Bluetooth Core, Vol 2, Part C, 4.2.1 +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Bluetooth Core, Vol 2, Part C, 4.2.1 use crate::either::Either; use crate::lmp::procedure::features; @@ -28,7 +42,7 @@ pub async fn receive_challenge(ctx: &impl Context, _link_key: [u8; 16]) { } pub async fn initiate(ctx: &impl Context) { - let _ = ctx.receive_hci_command::().await; + let _ = ctx.receive_hci_command::().await; ctx.send_hci_event( hci::AuthenticationRequestedStatusBuilder { num_hci_command_packets, @@ -39,10 +53,10 @@ pub async fn initiate(ctx: &impl Context) { ctx.send_hci_event(hci::LinkKeyRequestBuilder { bd_addr: ctx.peer_address() }.build()); - let status = match ctx.receive_hci_command::>().await { + let status = match ctx + .receive_hci_command::>() + .await + { Either::Left(_reply) => { ctx.send_hci_event( hci::LinkKeyRequestReplyCompleteBuilder { @@ -53,7 +67,7 @@ pub async fn initiate(ctx: &impl Context) { .build(), ); hci::ErrorCode::Success - }, + } Either::Right(_) => { ctx.send_hci_event( hci::LinkKeyRequestNegativeReplyCompleteBuilder { @@ -64,7 +78,12 @@ pub async fn initiate(ctx: &impl Context) { .build(), ); - let result = if features::supported_on_both_page1(ctx, hci::LMPFeaturesPage1Bits::SecureSimplePairingHostSupport).await { + let result = if features::supported_on_both_page1( + ctx, + hci::LMPFeaturesPage1Bits::SecureSimplePairingHostSupport, + ) + .await + { secure_simple_pairing::initiate(ctx).await } else { legacy_pairing::initiate(ctx).await @@ -72,7 +91,7 @@ pub async fn initiate(ctx: &impl Context) { match result { Ok(_) => hci::ErrorCode::Success, - Err(_) => hci::ErrorCode::AuthenticationFailure + Err(_) => hci::ErrorCode::AuthenticationFailure, } } }; diff --git a/tools/rootcanal/rust/src/lmp/procedure/encryption.rs b/tools/rootcanal/rust/src/lmp/procedure/encryption.rs index 6b7d85d73d6ddf2a91c1b96ab9f5611caae9f9b1..573ef350239532f8cff6e652f4dbc43297d552b0 100644 --- a/tools/rootcanal/rust/src/lmp/procedure/encryption.rs +++ b/tools/rootcanal/rust/src/lmp/procedure/encryption.rs @@ -1,4 +1,18 @@ -// Bluetooth Core, Vol 2, Part C, 4.2.5 +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Bluetooth Core, Vol 2, Part C, 4.2.5 use super::features; use crate::lmp::procedure::Context; @@ -10,7 +24,7 @@ use hci::LMPFeaturesPage2Bits::SecureConnectionsControllerSupport; pub async fn initiate(ctx: &impl Context) { // TODO: handle turn off - let _ = ctx.receive_hci_command::().await; + let _ = ctx.receive_hci_command::().await; ctx.send_hci_event( hci::SetConnectionEncryptionStatusBuilder { num_hci_command_packets, diff --git a/tools/rootcanal/rust/src/lmp/procedure/features.rs b/tools/rootcanal/rust/src/lmp/procedure/features.rs index 2e0f7cbd0328a810dd2c9c1b81a0fdea23631f4c..649931323e5f3a4c61d7a83ccbc6dd07a7222aa5 100644 --- a/tools/rootcanal/rust/src/lmp/procedure/features.rs +++ b/tools/rootcanal/rust/src/lmp/procedure/features.rs @@ -1,6 +1,18 @@ -// Bluetooth Core, Vol 2, Part C, 4.3.4 +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -use num_traits::ToPrimitive; +//! Bluetooth Core, Vol 2, Part C, 4.3.4 use crate::lmp::procedure::Context; use crate::packets::lmp; @@ -54,12 +66,12 @@ pub async fn supported_on_both_page1( ctx: &impl Context, feature: crate::packets::hci::LMPFeaturesPage1Bits, ) -> bool { - supported_on_both_page(ctx, 1, feature.to_u64().unwrap()).await + supported_on_both_page(ctx, 1, feature.into()).await } pub async fn supported_on_both_page2( ctx: &impl Context, feature: crate::packets::hci::LMPFeaturesPage2Bits, ) -> bool { - supported_on_both_page(ctx, 2, feature.to_u64().unwrap()).await + supported_on_both_page(ctx, 2, feature.into()).await } diff --git a/tools/rootcanal/rust/src/lmp/procedure/legacy_pairing.rs b/tools/rootcanal/rust/src/lmp/procedure/legacy_pairing.rs index f6367f692dd3e7e8a90bb5118e7c8b8cc1e398f3..bb30c3fac1560908fa5ddde8129f072e32a5d737 100644 --- a/tools/rootcanal/rust/src/lmp/procedure/legacy_pairing.rs +++ b/tools/rootcanal/rust/src/lmp/procedure/legacy_pairing.rs @@ -1,4 +1,18 @@ -// Bluetooth Core, Vol 2, Part C, 4.2.2 +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Bluetooth Core, Vol 2, Part C, 4.2.2 use crate::lmp::procedure::{authentication, Context}; use crate::packets::{hci, lmp}; @@ -8,7 +22,7 @@ use crate::num_hci_command_packets; pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { ctx.send_hci_event(hci::PinCodeRequestBuilder { bd_addr: ctx.peer_address() }.build()); - let _pin_code = ctx.receive_hci_command::().await; + let _pin_code = ctx.receive_hci_command::().await; ctx.send_hci_event( hci::PinCodeRequestReplyCompleteBuilder { @@ -53,7 +67,7 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { pub async fn respond(ctx: &impl Context, _request: lmp::InRand) -> Result<(), ()> { ctx.send_hci_event(hci::PinCodeRequestBuilder { bd_addr: ctx.peer_address() }.build()); - let _pin_code = ctx.receive_hci_command::().await; + let _pin_code = ctx.receive_hci_command::().await; ctx.send_hci_event( hci::PinCodeRequestReplyCompleteBuilder { diff --git a/tools/rootcanal/rust/src/lmp/procedure/mod.rs b/tools/rootcanal/rust/src/lmp/procedure/mod.rs index ea702fd87bb105f111f03c280d5e6eb31e2e611e..c9b845df48fa28efa167fca535d20d5e396886ff 100644 --- a/tools/rootcanal/rust/src/lmp/procedure/mod.rs +++ b/tools/rootcanal/rust/src/lmp/procedure/mod.rs @@ -1,3 +1,17 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::convert::TryFrom; use std::future::Future; use std::pin::Pin; @@ -7,10 +21,10 @@ use crate::lmp::ec::PrivateKey; use crate::packets::{hci, lmp}; pub trait Context { - fn poll_hci_command>(&self) -> Poll; + fn poll_hci_command>(&self) -> Poll; fn poll_lmp_packet>(&self) -> Poll

    ; - fn send_hci_event>(&self, event: E); + fn send_hci_event>(&self, event: E); fn send_lmp_packet>(&self, packet: P); fn peer_address(&self) -> hci::Address; @@ -22,7 +36,7 @@ pub trait Context { fn extended_features(&self, features_page: u8) -> u64; - fn receive_hci_command>(&self) -> ReceiveFuture<'_, Self, C> { + fn receive_hci_command>(&self) -> ReceiveFuture<'_, Self, C> { ReceiveFuture(Self::poll_hci_command, self) } diff --git a/tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs b/tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs index ccdfa9fad5f9854e6537e30212b23b8c67867397..543219691f7eec71f63be30f1885e3e61c49fdcd 100644 --- a/tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs +++ b/tools/rootcanal/rust/src/lmp/procedure/secure_simple_pairing.rs @@ -1,8 +1,20 @@ -// Bluetooth Core, Vol 2, Part C, 4.2.7 - -use std::convert::TryInto; - -use num_traits::{FromPrimitive, ToPrimitive}; +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Bluetooth Core, Vol 2, Part C, 4.2.7 + +use std::convert::{TryFrom, TryInto}; use crate::either::Either; use crate::lmp::ec::{DhKey, PrivateKey, PublicKey}; @@ -131,11 +143,14 @@ async fn receive_public_key(ctx: &impl Context, transaction_id: u8) -> PublicKey const COMMITMENT_VALUE_SIZE: usize = 16; const NONCE_SIZE: usize = 16; -async fn receive_commitment(ctx: &impl Context, skip_first: bool) { - let commitment_value = [0; COMMITMENT_VALUE_SIZE]; +fn build_commitment(_ctx: &impl Context) -> [u8; COMMITMENT_VALUE_SIZE] { + [0; COMMITMENT_VALUE_SIZE] +} + +async fn receive_commitment(ctx: &impl Context, confirm: Option) { + let commitment_value = build_commitment(ctx); - if !skip_first { - let confirm = ctx.receive_lmp_packet::().await; + if let Some(confirm) = confirm { if confirm.get_commitment_value() != &commitment_value { todo!(); } @@ -165,16 +180,8 @@ async fn receive_commitment(ctx: &impl Context, skip_first: bool) { .await; } -async fn send_commitment(ctx: &impl Context, skip_first: bool) { - let commitment_value = [0; COMMITMENT_VALUE_SIZE]; - - if !skip_first { - ctx.send_lmp_packet( - lmp::SimplePairingConfirmBuilder { transaction_id: 0, commitment_value }.build(), - ); - } - - let confirm = ctx.receive_lmp_packet::().await; +async fn send_commitment(ctx: &impl Context, confirm: lmp::SimplePairingConfirm) { + let commitment_value = build_commitment(ctx); if confirm.get_commitment_value() != &commitment_value { todo!(); @@ -207,8 +214,8 @@ async fn user_confirmation_request(ctx: &impl Context) -> Result<(), ()> { match ctx .receive_hci_command::>() .await { @@ -243,11 +250,8 @@ async fn user_passkey_request(ctx: &impl Context) -> Result<(), ()> { loop { match ctx .receive_hci_command::, - hci::SendKeypressNotificationPacket, + Either, + hci::SendKeypressNotification, >>() .await { @@ -293,8 +297,8 @@ async fn remote_oob_data_request(ctx: &impl Context) -> Result<(), ()> { match ctx .receive_hci_command::>() .await { @@ -331,8 +335,8 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { ctx.send_hci_event(hci::IoCapabilityRequestBuilder { bd_addr: ctx.peer_address() }.build()); match ctx .receive_hci_command::>() .await { @@ -348,12 +352,11 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { ctx.send_lmp_packet( lmp::IoCapabilityReqBuilder { transaction_id: 0, - io_capabilities: reply.get_io_capability().to_u8().unwrap(), - oob_authentication_data: reply.get_oob_present().to_u8().unwrap(), + io_capabilities: reply.get_io_capability().into(), + oob_authentication_data: reply.get_oob_present().into(), authentication_requirement: reply .get_authentication_requirements() - .to_u8() - .unwrap(), + .into(), } .build(), ); @@ -386,11 +389,11 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { let responder = { let response = ctx.receive_lmp_packet::().await; - let io_capability = hci::IoCapability::from_u8(response.get_io_capabilities()).unwrap(); + let io_capability = hci::IoCapability::try_from(response.get_io_capabilities()).unwrap(); let oob_data_present = - hci::OobDataPresent::from_u8(response.get_oob_authentication_data()).unwrap(); + hci::OobDataPresent::try_from(response.get_oob_authentication_data()).unwrap(); let authentication_requirements = - hci::AuthenticationRequirements::from_u8(response.get_authentication_requirement()) + hci::AuthenticationRequirements::try_from(response.get_authentication_requirement()) .unwrap(); ctx.send_hci_event( @@ -429,14 +432,33 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { match auth_method { AuthenticationMethod::NumericComparisonJustWork | AuthenticationMethod::NumericComparisonUserConfirm => { - send_commitment(ctx, true).await; + let confirm = ctx.receive_lmp_packet::().await; + send_commitment(ctx, confirm).await; - user_confirmation_request(ctx).await?; + if user_confirmation_request(ctx).await.is_err() { + ctx.send_lmp_packet( + lmp::NumericComparisonFailedBuilder { transaction_id: 0 }.build(), + ); + Err(())?; + } Ok(()) } AuthenticationMethod::PasskeyEntry => { - if initiator.io_capability == hci::IoCapability::KeyboardOnly { - user_passkey_request(ctx).await?; + let confirm = if initiator.io_capability == hci::IoCapability::KeyboardOnly { + if user_passkey_request(ctx).await.is_err() { + ctx.send_lmp_packet( + lmp::PasskeyFailedBuilder { transaction_id: 0 }.build(), + ); + Err(())?; + } + ctx.send_lmp_packet( + lmp::SimplePairingConfirmBuilder { + transaction_id: 0, + commitment_value: build_commitment(ctx), + } + .build(), + ); + ctx.receive_lmp_packet::().await } else { ctx.send_hci_event( hci::UserPasskeyNotificationBuilder { @@ -445,9 +467,32 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { } .build(), ); - } - for _ in 0..PASSKEY_ENTRY_REPEAT_NUMBER { - send_commitment(ctx, false).await; + ctx.send_lmp_packet( + lmp::SimplePairingConfirmBuilder { + transaction_id: 0, + commitment_value: build_commitment(ctx), + } + .build(), + ); + match ctx + .receive_lmp_packet::>() + .await + { + Either::Left(confirm) => confirm, + Either::Right(_) => Err(())?, + } + }; + send_commitment(ctx, confirm).await; + for _ in 1..PASSKEY_ENTRY_REPEAT_NUMBER { + ctx.send_lmp_packet( + lmp::SimplePairingConfirmBuilder { + transaction_id: 0, + commitment_value: build_commitment(ctx), + } + .build(), + ); + let confirm = ctx.receive_lmp_packet::().await; + send_commitment(ctx, confirm).await; } Ok(()) } @@ -456,7 +501,15 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { remote_oob_data_request(ctx).await?; } - send_commitment(ctx, false).await; + ctx.send_lmp_packet( + lmp::SimplePairingConfirmBuilder { + transaction_id: 0, + commitment_value: build_commitment(ctx), + } + .build(), + ); + let confirm = ctx.receive_lmp_packet::().await; + send_commitment(ctx, confirm).await; Ok(()) } } @@ -464,7 +517,6 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { .await; if result.is_err() { - ctx.send_lmp_packet(lmp::NumericComparisonFailedBuilder { transaction_id: 0 }.build()); ctx.send_hci_event( hci::SimplePairingCompleteBuilder { status: hci::ErrorCode::AuthenticationFailure, @@ -537,11 +589,11 @@ pub async fn initiate(ctx: &impl Context) -> Result<(), ()> { pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Result<(), ()> { let initiator = { - let io_capability = hci::IoCapability::from_u8(request.get_io_capabilities()).unwrap(); + let io_capability = hci::IoCapability::try_from(request.get_io_capabilities()).unwrap(); let oob_data_present = - hci::OobDataPresent::from_u8(request.get_oob_authentication_data()).unwrap(); + hci::OobDataPresent::try_from(request.get_oob_authentication_data()).unwrap(); let authentication_requirements = - hci::AuthenticationRequirements::from_u8(request.get_authentication_requirement()) + hci::AuthenticationRequirements::try_from(request.get_authentication_requirement()) .unwrap(); ctx.send_hci_event( @@ -561,8 +613,8 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul ctx.send_hci_event(hci::IoCapabilityRequestBuilder { bd_addr: ctx.peer_address() }.build()); match ctx .receive_hci_command::>() .await { @@ -578,12 +630,11 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul ctx.send_lmp_packet( lmp::IoCapabilityResBuilder { transaction_id: 0, - io_capabilities: reply.get_io_capability().to_u8().unwrap(), - oob_authentication_data: reply.get_oob_present().to_u8().unwrap(), + io_capabilities: reply.get_io_capability().into(), + oob_authentication_data: reply.get_oob_present().into(), authentication_requirement: reply .get_authentication_requirements() - .to_u8() - .unwrap(), + .into(), } .build(), ); @@ -605,7 +656,7 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul ctx.send_lmp_packet( lmp::NotAcceptedExtBuilder { transaction_id: 0, - error_code: reply.get_reason().to_u8().unwrap(), + error_code: reply.get_reason().into(), not_accepted_opcode: lmp::ExtendedOpcode::IoCapabilityReq, } .build(), @@ -637,37 +688,78 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul // Authentication Stage 1 let auth_method = authentication_method(initiator, responder); - let negative_user_confirmation = match auth_method { - AuthenticationMethod::NumericComparisonJustWork - | AuthenticationMethod::NumericComparisonUserConfirm => { - receive_commitment(ctx, true).await; + let result: Result = async { + match auth_method { + AuthenticationMethod::NumericComparisonJustWork + | AuthenticationMethod::NumericComparisonUserConfirm => { + receive_commitment(ctx, None).await; - let user_confirmation = user_confirmation_request(ctx).await; - user_confirmation.is_err() - } - AuthenticationMethod::PasskeyEntry => { - if responder.io_capability == hci::IoCapability::KeyboardOnly { - // TODO: handle error - let _user_passkey = user_passkey_request(ctx).await; - } else { - ctx.send_hci_event( - hci::UserPasskeyNotificationBuilder { bd_addr: ctx.peer_address(), passkey: 0 } + let user_confirmation = user_confirmation_request(ctx).await; + Ok(user_confirmation.is_err()) + } + AuthenticationMethod::PasskeyEntry => { + let confirm = if responder.io_capability == hci::IoCapability::KeyboardOnly { + let user_passkey = user_passkey_request(ctx).await; + let confirm = ctx.receive_lmp_packet::().await; + if user_passkey.is_err() { + ctx.send_lmp_packet( + lmp::NotAcceptedBuilder { + transaction_id: 0, + not_accepted_opcode: lmp::Opcode::SimplePairingConfirm, + error_code: hci::ErrorCode::AuthenticationFailure.into(), + }.build(), + ); + return Err(()); + } + confirm + } else { + ctx.send_hci_event( + hci::UserPasskeyNotificationBuilder { + bd_addr: ctx.peer_address(), + passkey: 0, + } .build(), - ); + ); + match ctx + .receive_lmp_packet::>() + .await + { + Either::Left(confirm) => confirm, + Either::Right(_) => Err(())?, + } + }; + receive_commitment(ctx, Some(confirm)).await; + for _ in 1..PASSKEY_ENTRY_REPEAT_NUMBER { + let confirm = ctx.receive_lmp_packet::().await; + receive_commitment(ctx, Some(confirm)).await; + } + Ok(false) } - for _ in 0..PASSKEY_ENTRY_REPEAT_NUMBER { - receive_commitment(ctx, false).await; + AuthenticationMethod::OutOfBand => { + if responder.oob_data_present != hci::OobDataPresent::NotPresent { + // TODO: handle error + let _remote_oob_data = remote_oob_data_request(ctx).await; + } + + let confirm = ctx.receive_lmp_packet::().await; + receive_commitment(ctx, Some(confirm)).await; + Ok(false) } - false } - AuthenticationMethod::OutOfBand => { - if responder.oob_data_present != hci::OobDataPresent::NotPresent { - // TODO: handle error - let _remote_oob_data = remote_oob_data_request(ctx).await; - } + } + .await; - receive_commitment(ctx, false).await; - false + let negative_user_confirmation = match result { + Ok(negative_user_confirmation) => negative_user_confirmation, + Err(_) => { + ctx.send_hci_event( + hci::SimplePairingCompleteBuilder { + status: hci::ErrorCode::AuthenticationFailure, + bd_addr: ctx.peer_address(), + } + .build(), + ); + return Err(()); } }; @@ -694,7 +786,7 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul lmp::NotAcceptedBuilder { transaction_id: 0, not_accepted_opcode: lmp::Opcode::DhkeyCheck, - error_code: hci::ErrorCode::AuthenticationFailure.to_u8().unwrap(), + error_code: hci::ErrorCode::AuthenticationFailure.into(), } .build(), ); @@ -754,8 +846,6 @@ pub async fn respond(ctx: &impl Context, request: lmp::IoCapabilityReq) -> Resul #[cfg(test)] mod tests { - use num_traits::ToPrimitive; - use crate::lmp::ec::PrivateKey; use crate::lmp::procedure::Context; use crate::lmp::test::{sequence, TestContext}; @@ -862,8 +952,7 @@ mod tests { } #[test] - #[should_panic] // TODO: make the test pass - fn passkey_entry_initiator_failure_on_initiating_side() { + fn passkey_entry_initiator_negative_reply_on_initiating_side() { let context = TestContext::new(); let procedure = initiate; @@ -871,14 +960,29 @@ mod tests { } #[test] - #[should_panic] // TODO: make the test pass - fn passkey_entry_responder_failure_on_initiating_side() { + fn passkey_entry_responder_negative_reply_on_responding_side() { + let context = TestContext::new(); + let procedure = respond; + + include!("../../../test/SP/BV-14bis-C.in"); + } + + #[test] + fn passkey_entry_responder_negative_reply_on_initiating_side() { let context = TestContext::new(); let procedure = respond; include!("../../../test/SP/BV-15-C.in"); } + #[test] + fn passkey_entry_initiator_negative_reply_on_responding_side() { + let context = TestContext::new(); + let procedure = initiate; + + include!("../../../test/SP/BV-15bis-C.in"); + } + #[test] #[should_panic] // TODO: make the test pass fn passkey_entry_initiator_failure_on_responding_side() { diff --git a/tools/rootcanal/rust/src/lmp/test/context.rs b/tools/rootcanal/rust/src/lmp/test/context.rs index 5ab6e9b9899d67a56a3b25f7350e1a57befdb824..f0eb783a5ca160d898cf12a87738cf16b7fe54dc 100644 --- a/tools/rootcanal/rust/src/lmp/test/context.rs +++ b/tools/rootcanal/rust/src/lmp/test/context.rs @@ -1,3 +1,17 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::cell::RefCell; use std::collections::VecDeque; use std::convert::{TryFrom, TryInto}; @@ -5,8 +19,6 @@ use std::future::Future; use std::pin::Pin; use std::task::{self, Poll}; -use num_traits::ToPrimitive; - use crate::lmp::ec::PrivateKey; use crate::packets::{hci, lmp}; @@ -16,8 +28,8 @@ use crate::lmp::procedure::Context; pub struct TestContext { pub in_lmp_packets: RefCell>, pub out_lmp_packets: RefCell>, - pub hci_events: RefCell>, - pub hci_commands: RefCell>, + pub hci_events: RefCell>, + pub hci_commands: RefCell>, private_key: RefCell>, features_pages: [u64; 3], peer_features_pages: [u64; 3], @@ -31,28 +43,28 @@ impl TestContext { } pub fn with_page_1_feature(mut self, feature: hci::LMPFeaturesPage1Bits) -> Self { - self.features_pages[1] |= feature.to_u64().unwrap(); + self.features_pages[1] |= u64::from(feature); self } pub fn with_page_2_feature(mut self, feature: hci::LMPFeaturesPage2Bits) -> Self { - self.features_pages[2] |= feature.to_u64().unwrap(); + self.features_pages[2] |= u64::from(feature); self } pub fn with_peer_page_1_feature(mut self, feature: hci::LMPFeaturesPage1Bits) -> Self { - self.peer_features_pages[1] |= feature.to_u64().unwrap(); + self.peer_features_pages[1] |= u64::from(feature); self } pub fn with_peer_page_2_feature(mut self, feature: hci::LMPFeaturesPage2Bits) -> Self { - self.peer_features_pages[2] |= feature.to_u64().unwrap(); + self.peer_features_pages[2] |= u64::from(feature); self } } impl Context for TestContext { - fn poll_hci_command>(&self) -> Poll { + fn poll_hci_command>(&self) -> Poll { let command = self.hci_commands.borrow().front().and_then(|command| command.clone().try_into().ok()); @@ -76,7 +88,7 @@ impl Context for TestContext { } } - fn send_hci_event>(&self, event: E) { + fn send_hci_event>(&self, event: E) { self.hci_events.borrow_mut().push_back(event.into()); } @@ -85,7 +97,7 @@ impl Context for TestContext { } fn peer_address(&self) -> hci::Address { - hci::Address { bytes: [0; 6] } + hci::Address::try_from(0).unwrap() } fn peer_handle(&self) -> u16 { diff --git a/tools/rootcanal/rust/src/lmp/test/mod.rs b/tools/rootcanal/rust/src/lmp/test/mod.rs index ad790a1acdb4dd3ecd56488c10a3248de967a1af..bf84ec33e8e07a53e2e99280bd5f554844fffdf3 100644 --- a/tools/rootcanal/rust/src/lmp/test/mod.rs +++ b/tools/rootcanal/rust/src/lmp/test/mod.rs @@ -1,3 +1,17 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + mod context; mod sequence; diff --git a/tools/rootcanal/rust/src/lmp/test/sequence.rs b/tools/rootcanal/rust/src/lmp/test/sequence.rs index 42460090713b42513671f02a745af9c9e97bcf07..9735b1a8f0b5b58ac5aab80bd6dbc00bd2e110cb 100644 --- a/tools/rootcanal/rust/src/lmp/test/sequence.rs +++ b/tools/rootcanal/rust/src/lmp/test/sequence.rs @@ -1,3 +1,17 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + macro_rules! sequence_body { ($ctx:ident, ) => { None }; ($ctx:ident, Lower Tester -> IUT: $packet:ident { @@ -46,7 +60,7 @@ macro_rules! sequence_body { use crate::packets::hci::*; paste! { - let packet: [<$packet Packet>] = $ctx.0.hci_events.borrow_mut().pop_front().expect("No hci packet").try_into().unwrap(); + let packet: $packet = $ctx.0.hci_events.borrow_mut().pop_front().expect("No hci packet").try_into().unwrap(); } $( diff --git a/tools/rootcanal/rust/src/packets.rs b/tools/rootcanal/rust/src/packets.rs index 4b88a3df0ffde7dfb514925aaadf80a4bda61dec..a64a22aa6326dcf62ab2d6ade2333a474db64af0 100644 --- a/tools/rootcanal/rust/src/packets.rs +++ b/tools/rootcanal/rust/src/packets.rs @@ -1,98 +1,61 @@ +// Copyright 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + pub mod hci { #![allow(clippy::all)] #![allow(unused)] #![allow(missing_docs)] + #![allow(non_camel_case_types)] - pub const EMPTY_ADDRESS: Address = Address { bytes: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }; - pub const ANY_ADDRESS: Address = Address { bytes: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] }; - - /// A Bluetooth address - #[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)] - pub struct Address { - pub bytes: [u8; 6], - } + include!(concat!(env!("OUT_DIR"), "/hci_packets.rs")); - impl Address { - pub fn is_empty(&self) -> bool { - *self == EMPTY_ADDRESS - } - } + pub const EMPTY_ADDRESS: Address = Address(0x000000000000); + pub const ANY_ADDRESS: Address = Address(0xffffffffffff); impl fmt::Display for Address { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let bytes = u64::to_le_bytes(self.0); write!( f, "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", - self.bytes[5], - self.bytes[4], - self.bytes[3], - self.bytes[2], - self.bytes[1], - self.bytes[0] + bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0], ) } } - #[derive(Debug, Clone)] - pub struct InvalidAddressError; - - impl TryFrom<&[u8]> for Address { - type Error = InvalidAddressError; - - fn try_from(slice: &[u8]) -> std::result::Result { - match <[u8; 6]>::try_from(slice) { - Ok(bytes) => Ok(Self { bytes }), - Err(_) => Err(InvalidAddressError), - } + impl From<&[u8; 6]> for Address { + fn from(bytes: &[u8; 6]) -> Self { + Self(u64::from_le_bytes([ + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], 0, 0, + ])) } } impl From

    for [u8; 6] { - fn from(addr: Address) -> [u8; 6] { - addr.bytes - } - } - - #[derive(Clone, Eq, Copy, PartialEq, Hash, Ord, PartialOrd, Debug)] - pub struct ClassOfDevice { - pub bytes: [u8; 3], - } - - impl fmt::Display for ClassOfDevice { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{:03X}-{:01X}-{:02X}", - ((self.bytes[2] as u16) << 4) | ((self.bytes[1] as u16) >> 4), - self.bytes[1] & 0x0F, - self.bytes[0] - ) + fn from(Address(addr): Address) -> Self { + let bytes = u64::to_le_bytes(addr); + bytes[0..6].try_into().unwrap() } } - #[derive(Debug, Clone)] - pub struct InvalidClassOfDeviceError; - - impl TryFrom<&[u8]> for ClassOfDevice { - type Error = InvalidClassOfDeviceError; - - fn try_from(slice: &[u8]) -> std::result::Result { - match <[u8; 3]>::try_from(slice) { - Ok(bytes) => Ok(Self { bytes }), - Err(_) => Err(InvalidClassOfDeviceError), - } - } - } - - impl From for [u8; 3] { - fn from(cod: ClassOfDevice) -> [u8; 3] { - cod.bytes + impl Address { + pub fn is_empty(&self) -> bool { + *self == EMPTY_ADDRESS } } - include!(concat!(env!("OUT_DIR"), "/hci_packets.rs")); - - pub fn command_remote_device_address(command: &CommandPacket) -> Option
    { + pub fn command_remote_device_address(command: &Command) -> Option
    { use CommandChild::*; #[allow(unused_imports)] use Option::None; // Overwrite `None` variant of `Child` enum @@ -115,7 +78,7 @@ pub mod hci { } } - pub fn command_connection_handle(command: &CommandPacket) -> Option { + pub fn command_connection_handle(command: &Command) -> Option { use CommandChild::*; #[allow(unused_imports)] use Option::None; // Overwrite `None` variant of `Child` enum @@ -135,3 +98,11 @@ pub mod lmp { include!(concat!(env!("OUT_DIR"), "/lmp_packets.rs")); } + +pub mod llcp { + #![allow(clippy::all)] + #![allow(unused)] + #![allow(missing_docs)] + + include!(concat!(env!("OUT_DIR"), "/llcp_packets.rs")); +} diff --git a/tools/rootcanal/rust/test/SP/BV-14bis-C.in b/tools/rootcanal/rust/test/SP/BV-14bis-C.in new file mode 100644 index 0000000000000000000000000000000000000000..b98f45096d1eaf0934ef744e4e4db250e5be2497 --- /dev/null +++ b/tools/rootcanal/rust/test/SP/BV-14bis-C.in @@ -0,0 +1,106 @@ +// Passkey entry responder, negative reply on responding side: +// - Test case not present in LMP.TS, but other permutations are described in SP/BV-14-C, SP/BV-15-C +// - IUT is KeyboardOnly, responder +// - Lower Tester is Display, initiator +// - IUT fails passkey entry with User_Passkey_Request_NegativeReply, responds Not Accepted to the SimplePairingConfirm +sequence! { procedure, context, + // ACL Connection Established + Lower Tester -> IUT: IoCapabilityReq { + transaction_id: 0, + io_capabilities: 0x00, + oob_authentication_data: 0x00, + authentication_requirement: 0x01, + } + IUT -> Upper Tester: IoCapabilityResponse { + bd_addr: context.peer_address(), + io_capability: IoCapability::DisplayOnly, + oob_data_present: OobDataPresent::NotPresent, + authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, + } + IUT -> Upper Tester: IoCapabilityRequest { + bd_addr: context.peer_address(), + } + Upper Tester -> IUT: IoCapabilityRequestReply { + bd_addr: context.peer_address(), + io_capability: IoCapability::KeyboardOnly, + oob_present: OobDataPresent::NotPresent, + authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, + } + IUT -> Upper Tester: IoCapabilityRequestReplyComplete { + num_hci_command_packets: 1, + status: ErrorCode::Success, + bd_addr: context.peer_address(), + } + IUT -> Lower Tester: IoCapabilityRes { + transaction_id: 0, + io_capabilities: 0x02, + oob_authentication_data: 0x00, + authentication_requirement: 0x01, + } + // Public Key Exchange + Lower Tester -> IUT: EncapsulatedHeader { + transaction_id: 0, + major_type: 1, + minor_type: 1, + payload_length: 48, + } + IUT -> Lower Tester: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedHeader, + } + repeat 3 times with (part in peer_p192_public_key()) { + Lower Tester -> IUT: EncapsulatedPayload { + transaction_id: 0, + data: part, + } + IUT -> Lower Tester: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedPayload, + } + } + IUT -> Lower Tester: EncapsulatedHeader { + transaction_id: 0, + major_type: 1, + minor_type: 1, + payload_length: 48, + } + Lower Tester -> IUT: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedHeader, + } + repeat 3 times with (part in local_p192_public_key(&context)) { + IUT -> Lower Tester: EncapsulatedPayload { + transaction_id: 0, + data: part, + } + Lower Tester -> IUT: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedPayload, + } + } + // Authentication Stage 1: Passkey Entry Protocol + IUT -> Upper Tester: UserPasskeyRequest { + bd_addr: context.peer_address(), + } + Upper Tester -> IUT: UserPasskeyRequestNegativeReply { + bd_addr: context.peer_address(), + } + IUT -> Upper Tester: UserPasskeyRequestNegativeReplyComplete { + num_hci_command_packets: 1, + status: ErrorCode::Success, + bd_addr: context.peer_address(), + } + Lower Tester -> IUT: SimplePairingConfirm { + transaction_id: 0, + commitment_value: [0; 16], + } + IUT -> Lower Tester: NotAccepted { + transaction_id: 0, + not_accepted_opcode: Opcode::SimplePairingConfirm, + error_code: ErrorCode::AuthenticationFailure.into(), + } + IUT -> Upper Tester: SimplePairingComplete { + status: ErrorCode::AuthenticationFailure, + bd_addr: context.peer_address(), + } +} diff --git a/tools/rootcanal/rust/test/SP/BV-15bis-C.in b/tools/rootcanal/rust/test/SP/BV-15bis-C.in new file mode 100644 index 0000000000000000000000000000000000000000..f9fda299c8bb97b6e562bcd9f3335898ea9720b0 --- /dev/null +++ b/tools/rootcanal/rust/test/SP/BV-15bis-C.in @@ -0,0 +1,118 @@ +// Passkey entry initiator, negative reply on responding side: +// - Test case not present in LMP.TS, but other permutations are described in SP/BV-14-C, SP/BV-15-C +// - IUT is DisplayOnly, initiator +// - Lower Tester is KeyboardOnly, responder +// - Lower Tester fails passkey entry with User_Passkey_Request_NegativeReply, responds Not Accepted to the SimplePairingConfirm +sequence! { procedure, context, + // ACL Connection Established + Upper Tester -> IUT: AuthenticationRequested { + connection_handle: context.peer_handle() + } + IUT -> Upper Tester: AuthenticationRequestedStatus { + num_hci_command_packets: 1, + status: ErrorCode::Success, + } + IUT -> Upper Tester: LinkKeyRequest { + bd_addr: context.peer_address(), + } + Upper Tester -> IUT: LinkKeyRequestNegativeReply { + bd_addr: context.peer_address(), + } + IUT -> Upper Tester: LinkKeyRequestNegativeReplyComplete { + num_hci_command_packets: 1, + status: ErrorCode::Success, + bd_addr: context.peer_address(), + } + IUT -> Upper Tester: IoCapabilityRequest { + bd_addr: context.peer_address(), + } + Upper Tester -> IUT: IoCapabilityRequestReply { + bd_addr: context.peer_address(), + io_capability: IoCapability::DisplayOnly, + oob_present: OobDataPresent::NotPresent, + authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, + } + IUT -> Upper Tester: IoCapabilityRequestReplyComplete { + num_hci_command_packets: 1, + status: ErrorCode::Success, + bd_addr: context.peer_address(), + } + IUT -> Lower Tester: IoCapabilityReq { + transaction_id: 0, + io_capabilities: 0x00, + oob_authentication_data: 0x00, + authentication_requirement: 0x01, + } + Lower Tester -> IUT: IoCapabilityRes { + transaction_id: 0, + io_capabilities: 0x02, + oob_authentication_data: 0x00, + authentication_requirement: 0x01, + } + IUT -> Upper Tester: IoCapabilityResponse { + bd_addr: context.peer_address(), + io_capability: IoCapability::KeyboardOnly, + oob_data_present: OobDataPresent::NotPresent, + authentication_requirements: AuthenticationRequirements::NoBondingMitmProtection, + } + // Public Key Exchange + IUT -> Lower Tester: EncapsulatedHeader { + transaction_id: 0, + major_type: 1, + minor_type: 1, + payload_length: 48, + } + Lower Tester -> IUT: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedHeader, + } + repeat 3 times with (part in local_p192_public_key(&context)) { + IUT -> Lower Tester: EncapsulatedPayload { + transaction_id: 0, + data: part, + } + Lower Tester -> IUT: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedPayload, + } + } + Lower Tester -> IUT: EncapsulatedHeader { + transaction_id: 0, + major_type: 1, + minor_type: 1, + payload_length: 48, + } + IUT -> Lower Tester: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedHeader, + } + repeat 3 times with (part in peer_p192_public_key()) { + Lower Tester -> IUT: EncapsulatedPayload { + transaction_id: 0, + data: part, + } + IUT -> Lower Tester: Accepted { + transaction_id: 0, + accepted_opcode: Opcode::EncapsulatedPayload, + } + } + // Authentication Stage 1: Passkey Entry Protocol + IUT -> Upper Tester: UserPasskeyNotification { bd_addr: context.peer_address(), passkey: 0 } + IUT -> Lower Tester: SimplePairingConfirm { + transaction_id: 0, + commitment_value: [0; 16], + } + Lower Tester -> IUT: NotAccepted { + transaction_id: 0, + not_accepted_opcode: Opcode::SimplePairingConfirm, + error_code: ErrorCode::AuthenticationFailure.into(), + } + IUT -> Upper Tester: SimplePairingComplete { + status: ErrorCode::AuthenticationFailure, + bd_addr: context.peer_address(), + } + IUT -> Upper Tester: AuthenticationComplete { + status: ErrorCode::AuthenticationFailure, + connection_handle: context.peer_handle(), + } +} diff --git a/tools/rootcanal/rust/test/SP/BV-16-C.in b/tools/rootcanal/rust/test/SP/BV-16-C.in index fc3f014f3b1822ada6534bec614dfee7d2c9f888..dc0b6ba9fc0bab5c1fec0287f6d765180f45edb6 100644 --- a/tools/rootcanal/rust/test/SP/BV-16-C.in +++ b/tools/rootcanal/rust/test/SP/BV-16-C.in @@ -119,7 +119,7 @@ sequence! { procedure, context, Lower Tester -> IUT: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::SimplePairingNumber, - error_code: ErrorCode::AuthenticationFailure.to_u8().unwrap(), + error_code: ErrorCode::AuthenticationFailure.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, diff --git a/tools/rootcanal/rust/test/SP/BV-17-C.in b/tools/rootcanal/rust/test/SP/BV-17-C.in index 33ea83983dcf935fe63185d361d29daecf55f191..fd8d50e8aacb817125fcb3e05c340fc97bdab72e 100644 --- a/tools/rootcanal/rust/test/SP/BV-17-C.in +++ b/tools/rootcanal/rust/test/SP/BV-17-C.in @@ -90,7 +90,7 @@ sequence! { procedure, context, IUT -> Lower Tester: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::SimplePairingNumber, - error_code: ErrorCode::AuthenticationFailure.to_u8().unwrap(), + error_code: ErrorCode::AuthenticationFailure.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, diff --git a/tools/rootcanal/rust/test/SP/BV-30-C.in b/tools/rootcanal/rust/test/SP/BV-30-C.in index 29784f0b16f3661e6118f9f5537d8e971c0aac9b..8c19aecf60eb435aad15d8a2639ec454a98ac2cb 100644 --- a/tools/rootcanal/rust/test/SP/BV-30-C.in +++ b/tools/rootcanal/rust/test/SP/BV-30-C.in @@ -27,7 +27,7 @@ sequence! { procedure, context, IUT -> Lower Tester: NotAcceptedExt { transaction_id: 0, not_accepted_opcode: ExtendedOpcode::IoCapabilityReq, - error_code: ErrorCode::PairingNotAllowed.to_u8().unwrap(), + error_code: ErrorCode::PairingNotAllowed.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, diff --git a/tools/rootcanal/rust/test/SP/BV-32-C.in b/tools/rootcanal/rust/test/SP/BV-32-C.in index bd3017e53b8045fafc12a1136f42513c97d38cfe..c1fd00686269462262b278905465dbc07c89c665 100644 --- a/tools/rootcanal/rust/test/SP/BV-32-C.in +++ b/tools/rootcanal/rust/test/SP/BV-32-C.in @@ -27,7 +27,7 @@ sequence! { procedure, context, IUT -> Lower Tester: NotAcceptedExt { transaction_id: 0, not_accepted_opcode: ExtendedOpcode::IoCapabilityReq, - error_code: ErrorCode::HostBusy.to_u8().unwrap(), + error_code: ErrorCode::HostBusy.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, diff --git a/tools/rootcanal/rust/test/SP/BV-35-C.in b/tools/rootcanal/rust/test/SP/BV-35-C.in index 999a4baf16240c8e7a1a12057c4f5d0845447439..b14a593f58ab5b3f82c88cab4d8618cff8b0dd62 100644 --- a/tools/rootcanal/rust/test/SP/BV-35-C.in +++ b/tools/rootcanal/rust/test/SP/BV-35-C.in @@ -145,7 +145,7 @@ sequence! { procedure, context, Lower Tester -> IUT: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::SimplePairingNumber, - error_code: ErrorCode::AuthenticationFailure.to_u8().unwrap(), + error_code: ErrorCode::AuthenticationFailure.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, diff --git a/tools/rootcanal/rust/test/SP/BV-36-C.in b/tools/rootcanal/rust/test/SP/BV-36-C.in index f9948d6c7e6e7edf099f4aafebb750f1ff79d9e4..03d276915be408f65a8b0546a9afb4a4fce1d0bc 100644 --- a/tools/rootcanal/rust/test/SP/BV-36-C.in +++ b/tools/rootcanal/rust/test/SP/BV-36-C.in @@ -106,7 +106,7 @@ sequence! { procedure, context, IUT -> Lower Tester: NotAccepted { transaction_id: 0, not_accepted_opcode: Opcode::SimplePairingNumber, - error_code: ErrorCode::AuthenticationFailure.to_u8().unwrap(), + error_code: ErrorCode::AuthenticationFailure.into(), } IUT -> Upper Tester: SimplePairingComplete { status: ErrorCode::AuthenticationFailure, diff --git a/tools/rootcanal/scripts/controller_info.py b/tools/rootcanal/scripts/controller_info.py new file mode 100755 index 0000000000000000000000000000000000000000..10a74a0dafde9b71e82a77a7b99368f1f88ea189 --- /dev/null +++ b/tools/rootcanal/scripts/controller_info.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 + +# Copyright 2015 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. +"""Dump the configuration of a Bluetooth controller. + +The script expects to find the generated module hci_packets +in PYTHONPATH. + +The controller is expected to be available through HCI over TCP +at the port passed as parameter.""" + +import argparse +import asyncio +import collections +import sys + +import hci_packets as hci + +H4_IDC_CMD = 0x01 +H4_IDC_ACL = 0x02 +H4_IDC_SCO = 0x03 +H4_IDC_EVT = 0x04 +H4_IDC_ISO = 0x05 + +HCI_HEADER_SIZES = dict([(H4_IDC_CMD, 3), (H4_IDC_ACL, 4), (H4_IDC_SCO, 3), (H4_IDC_EVT, 2), (H4_IDC_ISO, 4)]) + + +class Host: + + def __init__(self): + self.evt_queue = collections.deque() + self.evt_queue_event = asyncio.Event() + + async def connect(self, ip: str, port: int): + reader, writer = await asyncio.open_connection(ip, port) + self.reader = asyncio.create_task(self._read(reader)) + self.writer = writer + + async def _read(self, reader): + try: + while True: + idc = await reader.readexactly(1) + + assert idc[0] in HCI_HEADER_SIZES + header = await reader.readexactly(HCI_HEADER_SIZES[idc[0]]) + + if idc[0] == H4_IDC_EVT: + evt = hci.Event.parse_all(header + (await reader.readexactly(header[1]))) + #print(f"<< {evt.__class__.__name__}") + self.evt_queue.append(evt) + self.evt_queue_event.set() + else: + assert False + except Exception as exn: + print(f"Reader interrupted: {exn}") + return + + async def send_cmd(self, cmd: hci.Command): + #print(f">> {cmd.__class__.__name__}") + packet = bytes([H4_IDC_CMD]) + cmd.serialize() + self.writer.write(packet) + + async def recv_evt(self) -> hci.Event: + while not self.evt_queue: + await self.evt_queue_event.wait() + self.evt_queue_event.clear() + return self.evt_queue.popleft() + + async def expect_evt(self, expected_evt: type) -> hci.Event: + evt = await self.recv_evt() + assert isinstance(evt, expected_evt) + if not isinstance(evt, expected_evt): + print("Received unexpected event:") + evt.show() + print(f"Expected event of type {expected_evt.__name__}") + print(f"{list(evt.payload)}") + return evt + + +async def br_edr_properties(host: Host): + await host.send_cmd(hci.ReadLocalSupportedFeatures()) + page0 = await host.expect_evt(hci.ReadLocalSupportedFeaturesComplete) + await host.send_cmd(hci.ReadLocalExtendedFeatures(page_number=1)) + page1 = await host.expect_evt(hci.ReadLocalExtendedFeaturesComplete) + await host.send_cmd(hci.ReadLocalExtendedFeatures(page_number=2)) + page2 = await host.expect_evt(hci.ReadLocalExtendedFeaturesComplete) + + print( + f"lmp_features: {{ 0x{page0.lmp_features:x}, 0x{page1.extended_lmp_features:x}, 0x{page2.extended_lmp_features:x} }}" + ) + + await host.send_cmd(hci.ReadBufferSize()) + evt = await host.expect_evt(hci.ReadBufferSizeComplete) + + print(f"acl_data_packet_length: {evt.acl_data_packet_length}") + print(f"total_num_acl_data_packets: {evt.total_num_acl_data_packets}") + print(f"sco_data_packet_length: {evt.synchronous_data_packet_length}") + print(f"total_num_sco_data_packets: {evt.total_num_synchronous_data_packets}") + + await host.send_cmd(hci.ReadNumberOfSupportedIac()) + evt = await host.expect_evt(hci.ReadNumberOfSupportedIacComplete) + + print(f"num_supported_iac: {evt.num_support_iac}") + + +async def le_properties(host: Host): + await host.send_cmd(hci.LeReadLocalSupportedFeatures()) + evt = await host.expect_evt(hci.LeReadLocalSupportedFeaturesComplete) + + print(f"le_features: 0x{evt.le_features:x}") + + await host.send_cmd(hci.LeReadBufferSizeV2()) + evt = await host.expect_evt(hci.LeReadBufferSizeV2Complete) + + print(f"le_acl_data_packet_length: {evt.le_buffer_size.le_data_packet_length}") + print(f"total_num_le_acl_data_packets: {evt.le_buffer_size.total_num_le_packets}") + print(f"iso_data_packet_length: {evt.iso_buffer_size.le_data_packet_length}") + print(f"total_num_iso_data_packets: {evt.iso_buffer_size.total_num_le_packets}") + + await host.send_cmd(hci.LeReadFilterAcceptListSize()) + evt = await host.expect_evt(hci.LeReadFilterAcceptListSizeComplete) + + print(f"le_filter_accept_list_size: {evt.filter_accept_list_size}") + + await host.send_cmd(hci.LeReadResolvingListSize()) + evt = await host.expect_evt(hci.LeReadResolvingListSizeComplete) + + print(f"le_resolving_list_size: {evt.resolving_list_size}") + + await host.send_cmd(hci.LeReadSupportedStates()) + evt = await host.expect_evt(hci.LeReadSupportedStatesComplete) + + print(f"le_supported_states: 0x{evt.le_states:x}") + + await host.send_cmd(hci.LeReadMaximumAdvertisingDataLength()) + evt = await host.expect_evt(hci.LeReadMaximumAdvertisingDataLengthComplete) + + print(f"le_max_advertising_data_length: {evt.maximum_advertising_data_length}") + + await host.send_cmd(hci.LeReadNumberOfSupportedAdvertisingSets()) + evt = await host.expect_evt(hci.LeReadNumberOfSupportedAdvertisingSetsComplete) + + print(f"le_num_supported_advertising_sets: {evt.number_supported_advertising_sets}") + + await host.send_cmd(hci.LeReadPeriodicAdvertiserListSize()) + evt = await host.expect_evt(hci.LeReadPeriodicAdvertiserListSizeComplete) + + print(f"le_periodic_advertiser_list_size: {evt.periodic_advertiser_list_size}") + + +async def run(tcp_port: int): + host = Host() + await host.connect('127.0.0.1', tcp_port) + + await host.send_cmd(hci.Reset()) + await host.expect_evt(hci.ResetComplete) + + await host.send_cmd(hci.ReadLocalVersionInformation()) + evt = await host.expect_evt(hci.ReadLocalVersionInformationComplete) + + print(f"hci_version: {evt.local_version_information.hci_version}") + print(f"hci_subversion: 0x{evt.local_version_information.hci_revision:x}") + print(f"lmp_version: {evt.local_version_information.lmp_version}") + print(f"lmp_subversion: 0x{evt.local_version_information.lmp_subversion:x}") + print(f"company_identifier: 0x{evt.local_version_information.manufacturer_name:x}") + + await host.send_cmd(hci.ReadLocalSupportedCommands()) + evt = await host.expect_evt(hci.ReadLocalSupportedCommandsComplete) + + print(f"supported_commands: {{ {', '.join([f'0x{b:x}' for b in evt.supported_commands])} }}") + + try: + await br_edr_properties(host) + except Exception: + pass + + try: + await le_properties(host) + except Exception: + pass + + +def main() -> int: + """Generate cxx PDL backend.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('tcp_port', type=int, help='HCI port') + return asyncio.run(run(**vars(parser.parse_args()))) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/rootcanal/scripts/scripted_beacon_test/run_test.sh b/tools/rootcanal/scripts/scripted_beacon_test/run_test.sh index 3cededbf5ac2461f1971083d042cfff563a71836..a58e9f0a11739da24ed2bd6ac90e7bb92b0a0c15 100644 --- a/tools/rootcanal/scripts/scripted_beacon_test/run_test.sh +++ b/tools/rootcanal/scripts/scripted_beacon_test/run_test.sh @@ -1,3 +1,16 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://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. mkdir -p /tmp/logs/scripted_beacon_test/ chmod 200 scripts/scripted_beacon_test/no_permission.pb diff --git a/tools/rootcanal/scripts/test_channel.py b/tools/rootcanal/scripts/test_channel.py index dc9d8f894c446fe67cba578cc54158873862c1a0..7a2d3675f3e97ab96aa276636989eafd5aef39ea 100644 --- a/tools/rootcanal/scripts/test_channel.py +++ b/tools/rootcanal/scripts/test_channel.py @@ -214,6 +214,12 @@ class TestChannelShell(cmd.Cmd): """ self._test_channel.send_command('set_device_address', args.split()) + def do_set_device_configuration(self, args): + """Arguments: dev_num config Set the controller properties of the selected device. + + """ + self._test_channel.send_command('set_device_configuration', args.split()) + def do_list(self, args): """Arguments: [dev_num [attr]] List the devices from the controller, optionally filtered by device and attr. diff --git a/tools/rootcanal/test/LL/CIS/CEN/BV_01_C.py b/tools/rootcanal/test/LL/CIS/CEN/BV_01_C.py new file mode 100644 index 0000000000000000000000000000000000000000..67184f2555f998cef71b839f3c4ce760c4647947 --- /dev/null +++ b/tools/rootcanal/test/LL/CIS/CEN/BV_01_C.py @@ -0,0 +1,206 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hci_packets as hci +import link_layer_packets as ll +import llcp_packets as llcp +import random +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + SDU_Interval_C_TO_P = 10000 # 10ms + SDU_Interval_P_TO_C = 10000 # 10ms + ISO_Interval = 16 # 20ms + Worst_Case_SCA = hci.ClockAccuracy.PPM_500 + Packing = hci.Packing.SEQUENTIAL + Framing = hci.Enable.DISABLED + NSE = 4 + Max_SDU_C_TO_P = 130 + Max_SDU_P_TO_C = 130 + Max_PDU_C_TO_P = 130 + Max_PDU_P_TO_C = 130 + PHY_C_TO_P = 0x1 + PHY_P_TO_C = 0x1 + FT_C_TO_P = 1 + FT_P_TO_C = 1 + BN_C_TO_P = 2 + BN_P_TO_C = 2 + Max_Transport_Latency_C_TO_P = 40000 # 40ms + Max_Transport_Latency_P_TO_C = 40000 # 40ms + RTN_C_TO_P = 3 + RTN_P_TO_C = 3 + + # LL/CIS/CEN/BV-01-C [CIS Setup Procedure, Central Initiated] + async def test(self): + # Test parameters. + cig_id = 0x12 + cis_id = 0x42 + cis_connection_handle = 0xe00 + peer_address = Address('aa:bb:cc:dd:ee:ff') + controller = self.controller + + # Enable Connected Isochronous Stream Host Support. + await self.enable_connected_isochronous_stream_host_support() + + # Prelude: Establish an ACL connection as central with the IUT. + acl_connection_handle = await self.establish_le_connection_central(peer_address) + + # 1. The Upper Tester sends an HCI_LE_Set_CIG_Parameters_Test command to the IUT with + # CIS_Count set to 1, BN, FT, NSE, PHY_C_TO_P[], PHY_P_TO_C[] and ISO_Interval to be set to + # the values specified in Table 4.135 and Table 4.136. Any remaining values are assigned the + # default values as specified in Section 4.10.1.3 Default Values for Set CIG Parameters + # Commands. The Upper Tester receives a successful HCI_Command_Complete event with a + # valid Connection_Handle from the IUT and CIS_Count = 1. + controller.send_cmd( + hci.LeSetCigParametersTest(cig_id=cig_id, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + worst_case_sca=self.Worst_Case_SCA, + packing=self.Packing, + framing=self.Framing, + cis_config=[ + hci.LeCisParametersTestConfig(cis_id=cis_id, + nse=self.NSE, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + phy_c_to_p=self.PHY_C_TO_P, + phy_p_to_c=self.PHY_P_TO_C, + bn_c_to_p=self.BN_C_TO_P, + bn_p_to_c=self.BN_P_TO_C) + ])) + + await self.expect_evt( + hci.LeSetCigParametersTestComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + cig_id=cig_id, + connection_handle=[cis_connection_handle])) + + # 2. The Upper Tester sends an HCI_LE_Create_CIS command to the IUT with the + # ACL_Connection_Handle of the established ACL connection and CIS_Count set to 1. The Upper + # Tester receives a Status of Success from the IUT. + controller.send_cmd( + hci.LeCreateCis(cis_config=[ + hci.LeCreateCisConfig(cis_connection_handle=cis_connection_handle, + acl_connection_handle=acl_connection_handle) + ])) + + await self.expect_evt(hci.LeCreateCisStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # 3. The Lower Tester receives an LL_CIS_REQ PDU from the IUT with all fields set to valid values. + # CIS_Offset_Min is a value between 500µs and TSPX_conn_interval, CIS_Offset_Max is a value + # between CIS_Offset_Min and the CIS_Offset_Max value as calculated in [14] Section 2.4.2.29 + # using TSPX_conn_interval as the value of connInterval, and connEventCount is the reference + # event anchor point for which the offsets applied. + cis_req = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisReq(cig_id=cig_id, + cis_id=cis_id, + phy_c_to_p=hci.PhyType.LE_1M, + phy_p_to_c=hci.PhyType.LE_1M, + framed=self.Framing == hci.Enable.ENABLED, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + nse=self.NSE, + sub_interval=self.Any, + bn_p_to_c=self.BN_C_TO_P, + bn_c_to_p=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + cis_offset_min=self.Any, + cis_offset_max=self.Any, + conn_event_count=0)) + + # 4. The Lower Tester sends an LL_CIS_RSP PDU to the IUT. + controller.send_llcp(source_address=peer_address, + destination_address=controller.address, + pdu=llcp.CisRsp(cis_offset_min=cis_req.cis_offset_min, + cis_offset_max=cis_req.cis_offset_max, + conn_event_count=0)) + + # 5. The Lower Tester receives an LL_CIS_IND from the IUT where the CIS_Offset is the time (ms) + # from the start of the ACL connection event in connEvent Count to the first CIS anchor point, the + # CIS_Sync_Delay is CIG_Sync_Delay minus the offset from the CIG reference point to the CIS + # anchor point in ï­s, and the connEventCount is the CIS_Offset reference point. + cis_ind = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisInd(aa=0, + cis_offset=self.Any, + cig_sync_delay=self.Any, + cis_sync_delay=self.Any, + conn_event_count=0)) + + # 6. The IUT sends a CIS Null PDU to the Lower Tester and the Lower Tester responds with a CIS + # Null PDU. Alternately, the IUT sends an empty Data PDU, which the Lower Tester acknowledges. + # These exchanges will continue until data is exchanged between the IUT and the Lower Tester in + # later steps. + + # 7. The Upper Tester receives a successful HCI_LE_CIS_Established event with the NSE, BN, FT, + # and Max_PDU parameters as set in step 1 from the IUT, after the first CIS packet sent by the LT. + # The Connection_Handle parameter is set to the value provided in the HCI_LE_Create_CIS + # command. + await self.expect_evt( + hci.LeCisEstablished(status=ErrorCode.SUCCESS, + connection_handle=cis_connection_handle, + cig_sync_delay=cis_ind.cig_sync_delay, + cis_sync_delay=cis_ind.cis_sync_delay, + transport_latency_c_to_p=self.Any, + transport_latency_p_to_c=self.Any, + phy_c_to_p=hci.SecondaryPhyType.LE_1M, + phy_p_to_c=hci.SecondaryPhyType.LE_1M, + nse=self.NSE, + bn_c_to_p=self.BN_C_TO_P, + bn_p_to_c=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + iso_interval=self.ISO_Interval)) + + # 8. The Upper Tester orders the IUT to send data packets to the Lower Tester. + iso_sdu = [random.randint(1, 251) for n in range(self.Max_SDU_C_TO_P)] + controller.send_iso( + hci.IsoWithoutTimestamp( + connection_handle=cis_connection_handle, + pb_flag=hci.IsoPacketBoundaryFlag.COMPLETE_SDU, + packet_sequence_number=42, + payload=iso_sdu, + )) + + # 9. The Lower Tester receives CIS data PDUs from the IUT in each sub-event of the CIS and + # acknowledges those PDUs. + await self.expect_ll( + ll.LeConnectedIsochronousPdu(source_address=controller.address, + destination_address=peer_address, + cig_id=cig_id, + cis_id=cis_id, + sequence_number=42, + data=iso_sdu)) + + # 10. Repeat step 9 for 50 ÷ BN isochronous events starting with the first event where a CIS data PDU + # with nonzero payload is received. diff --git a/tools/rootcanal/test/LL/CIS/CEN/BV_03_C.py b/tools/rootcanal/test/LL/CIS/CEN/BV_03_C.py new file mode 100644 index 0000000000000000000000000000000000000000..c3b0e11e435b5015afba9e612a362bb1cd6f11a3 --- /dev/null +++ b/tools/rootcanal/test/LL/CIS/CEN/BV_03_C.py @@ -0,0 +1,140 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hci_packets as hci +import link_layer_packets as ll +import llcp_packets as llcp +import random +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + SDU_Interval_C_TO_P = 10000 # 10ms + SDU_Interval_P_TO_C = 10000 # 10ms + ISO_Interval = 16 # 20ms + Worst_Case_SCA = hci.ClockAccuracy.PPM_500 + Packing = hci.Packing.SEQUENTIAL + Framing = hci.Enable.DISABLED + NSE = 4 + Max_SDU_C_TO_P = 130 + Max_SDU_P_TO_C = 130 + Max_PDU_C_TO_P = 130 + Max_PDU_P_TO_C = 130 + PHY_C_TO_P = 0x1 + PHY_P_TO_C = 0x1 + FT_C_TO_P = 1 + FT_P_TO_C = 1 + BN_C_TO_P = 2 + BN_P_TO_C = 2 + Max_Transport_Latency_C_TO_P = 40000 # 40ms + Max_Transport_Latency_P_TO_C = 40000 # 40ms + RTN_C_TO_P = 3 + RTN_P_TO_C = 3 + + # LL/CIS/CEN/BV-03-C [CIS Setup Procedure, Central Initiated, Rejected] + async def test(self): + # Test parameters. + cig_id = 0x12 + cis_id = 0x42 + cis_connection_handle = 0xe00 + peer_address = Address('aa:bb:cc:dd:ee:ff') + controller = self.controller + + # Enable Connected Isochronous Stream Host Support. + await self.enable_connected_isochronous_stream_host_support() + + # Prelude: Establish an ACL connection as central with the IUT. + acl_connection_handle = await self.establish_le_connection_central(peer_address) + + # 1. The Upper Tester sends an HCI_LE_Set_CIG_Parameters command to the IUT with valid + # parameters and receives a successful HCI_Command_Complete event. + controller.send_cmd( + hci.LeSetCigParametersTest(cig_id=cig_id, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + worst_case_sca=self.Worst_Case_SCA, + packing=self.Packing, + framing=self.Framing, + cis_config=[ + hci.LeCisParametersTestConfig(cis_id=cis_id, + nse=self.NSE, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + phy_c_to_p=self.PHY_C_TO_P, + phy_p_to_c=self.PHY_P_TO_C, + bn_c_to_p=self.BN_C_TO_P, + bn_p_to_c=self.BN_P_TO_C) + ])) + + await self.expect_evt( + hci.LeSetCigParametersTestComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + cig_id=cig_id, + connection_handle=[cis_connection_handle])) + + # 2. The Upper Tester sends an HCI_LE_Create_CIS command with the ACL_Connection_Handle of + # the established ACL and valid Connection_Handle from the IUT received in step 1. + controller.send_cmd( + hci.LeCreateCis(cis_config=[ + hci.LeCreateCisConfig(cis_connection_handle=cis_connection_handle, + acl_connection_handle=acl_connection_handle) + ])) + + await self.expect_evt(hci.LeCreateCisStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # 3. The Lower Tester receives an LL_CIS_REQ PDU from the IUT with all fields set to valid values. + cis_req = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisReq(cig_id=cig_id, + cis_id=cis_id, + phy_c_to_p=hci.PhyType.LE_1M, + phy_p_to_c=hci.PhyType.LE_1M, + framed=self.Framing == hci.Enable.ENABLED, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + nse=self.NSE, + sub_interval=self.Any, + bn_p_to_c=self.BN_C_TO_P, + bn_c_to_p=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + cis_offset_min=self.Any, + cis_offset_max=self.Any, + conn_event_count=0)) + + # 4. The Lower Tester sends an LL_REJECT_EXT_IND to the IUT with an error code not equal to 0x00. + controller.send_llcp(source_address=peer_address, + destination_address=controller.address, + pdu=llcp.RejectExtInd(reject_opcode=llcp.Opcode.LL_CIS_REQ, + error_code=hci.ErrorCode.REMOTE_USER_TERMINATED_CONNECTION)) + + # 5. The Upper Tester receives an HCI_LE_CIS_Established event from the IUT with a status failure. + # The Status field has the same value as the LL_REJECT_EXT_IND PDU in step 4. + await self.expect_evt( + hci.LeCisEstablished(status=ErrorCode.REMOTE_USER_TERMINATED_CONNECTION, + connection_handle=cis_connection_handle)) diff --git a/tools/rootcanal/test/LL/CIS/CEN/BV_10_C.py b/tools/rootcanal/test/LL/CIS/CEN/BV_10_C.py new file mode 100644 index 0000000000000000000000000000000000000000..cb30823647a767af4a3d8790a6b770353a04bc72 --- /dev/null +++ b/tools/rootcanal/test/LL/CIS/CEN/BV_10_C.py @@ -0,0 +1,284 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hci_packets as hci +import link_layer_packets as ll +import llcp_packets as llcp +import random +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + SDU_Interval_C_TO_P = 10000 # 10ms + SDU_Interval_P_TO_C = 10000 # 10ms + ISO_Interval = 16 # 20ms + Worst_Case_SCA = hci.ClockAccuracy.PPM_500 + Packing = hci.Packing.SEQUENTIAL + Framing = hci.Enable.DISABLED + NSE = 4 + Max_SDU_C_TO_P = 130 + Max_SDU_P_TO_C = 130 + Max_PDU_C_TO_P = 130 + Max_PDU_P_TO_C = 130 + PHY_C_TO_P = 0x1 + PHY_P_TO_C = 0x1 + FT_C_TO_P = 1 + FT_P_TO_C = 1 + BN_C_TO_P = 2 + BN_P_TO_C = 2 + Max_Transport_Latency_C_TO_P = 40000 # 40ms + Max_Transport_Latency_P_TO_C = 40000 # 40ms + RTN_C_TO_P = 3 + RTN_P_TO_C = 3 + + # LL/CIS/CEN/BV-01-C [CIS Setup Procedure, Central Initiated] + async def test(self): + # Test parameters. + cig_id = 0x12 + cis_id_1 = 0x42 + cis_id_2 = 0x43 + cis_connection_handle_1 = 0xe00 + cis_connection_handle_2 = 0xe01 + peer_address_1 = Address('aa:bb:cc:dd:ee:ff') + peer_address_2 = Address('aa:bb:cc:dd:ee:fe') + controller = self.controller + + # Enable Connected Isochronous Stream Host Support. + await self.enable_connected_isochronous_stream_host_support() + + # Prelude: Establish ACL connections as central with the IUT. + acl_connection_handle_1 = await self.establish_le_connection_central(peer_address_1) + acl_connection_handle_2 = await self.establish_le_connection_central(peer_address_2) + + # Prelude: Establish CIS(1) and CIS(2) with connected peers. + controller.send_cmd( + hci.LeSetCigParametersTest(cig_id=cig_id, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + worst_case_sca=self.Worst_Case_SCA, + packing=self.Packing, + framing=self.Framing, + cis_config=[ + hci.LeCisParametersTestConfig(cis_id=cis_id_1, + nse=self.NSE, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + phy_c_to_p=self.PHY_C_TO_P, + phy_p_to_c=self.PHY_P_TO_C, + bn_c_to_p=self.BN_C_TO_P, + bn_p_to_c=self.BN_P_TO_C), + hci.LeCisParametersTestConfig(cis_id=cis_id_2, + nse=self.NSE, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + phy_c_to_p=self.PHY_C_TO_P, + phy_p_to_c=self.PHY_P_TO_C, + bn_c_to_p=self.BN_C_TO_P, + bn_p_to_c=self.BN_P_TO_C) + ])) + + await self.expect_evt( + hci.LeSetCigParametersTestComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + cig_id=cig_id, + connection_handle=[cis_connection_handle_1, cis_connection_handle_2])) + + controller.send_cmd( + hci.LeCreateCis(cis_config=[ + hci.LeCreateCisConfig(cis_connection_handle=cis_connection_handle_1, + acl_connection_handle=acl_connection_handle_1), + hci.LeCreateCisConfig(cis_connection_handle=cis_connection_handle_2, + acl_connection_handle=acl_connection_handle_2) + ])) + + await self.expect_evt(hci.LeCreateCisStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + cis_req_1 = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address_1, + expected_pdu=llcp.CisReq(cig_id=cig_id, + cis_id=cis_id_1, + phy_c_to_p=hci.PhyType.LE_1M, + phy_p_to_c=hci.PhyType.LE_1M, + framed=self.Framing == hci.Enable.ENABLED, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + nse=self.NSE, + sub_interval=self.Any, + bn_p_to_c=self.BN_C_TO_P, + bn_c_to_p=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + cis_offset_min=self.Any, + cis_offset_max=self.Any, + conn_event_count=0)) + + controller.send_llcp(source_address=peer_address_1, + destination_address=controller.address, + pdu=llcp.CisRsp(cis_offset_min=cis_req_1.cis_offset_min, + cis_offset_max=cis_req_1.cis_offset_max, + conn_event_count=0)) + + cis_ind_1 = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address_1, + expected_pdu=llcp.CisInd(aa=0, + cis_offset=self.Any, + cig_sync_delay=self.Any, + cis_sync_delay=self.Any, + conn_event_count=0)) + + await self.expect_evt( + hci.LeCisEstablished(status=ErrorCode.SUCCESS, + connection_handle=cis_connection_handle_1, + cig_sync_delay=cis_ind_1.cig_sync_delay, + cis_sync_delay=cis_ind_1.cis_sync_delay, + transport_latency_c_to_p=self.Any, + transport_latency_p_to_c=self.Any, + phy_c_to_p=hci.SecondaryPhyType.LE_1M, + phy_p_to_c=hci.SecondaryPhyType.LE_1M, + nse=self.NSE, + bn_c_to_p=self.BN_C_TO_P, + bn_p_to_c=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + iso_interval=self.ISO_Interval)) + + cis_req_2 = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address_2, + expected_pdu=llcp.CisReq(cig_id=cig_id, + cis_id=cis_id_2, + phy_c_to_p=hci.PhyType.LE_1M, + phy_p_to_c=hci.PhyType.LE_1M, + framed=self.Framing == hci.Enable.ENABLED, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + nse=self.NSE, + sub_interval=self.Any, + bn_p_to_c=self.BN_C_TO_P, + bn_c_to_p=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + cis_offset_min=self.Any, + cis_offset_max=self.Any, + conn_event_count=0)) + + controller.send_llcp(source_address=peer_address_2, + destination_address=controller.address, + pdu=llcp.CisRsp(cis_offset_min=cis_req_2.cis_offset_min, + cis_offset_max=cis_req_2.cis_offset_max, + conn_event_count=0)) + + cis_ind_2 = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address_2, + expected_pdu=llcp.CisInd(aa=0, + cis_offset=self.Any, + cig_sync_delay=self.Any, + cis_sync_delay=self.Any, + conn_event_count=0)) + + await self.expect_evt( + hci.LeCisEstablished(status=ErrorCode.SUCCESS, + connection_handle=cis_connection_handle_2, + cig_sync_delay=cis_ind_2.cig_sync_delay, + cis_sync_delay=cis_ind_2.cis_sync_delay, + transport_latency_c_to_p=self.Any, + transport_latency_p_to_c=self.Any, + phy_c_to_p=hci.SecondaryPhyType.LE_1M, + phy_p_to_c=hci.SecondaryPhyType.LE_1M, + nse=self.NSE, + bn_c_to_p=self.BN_C_TO_P, + bn_p_to_c=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + iso_interval=self.ISO_Interval)) + + # 1. The Upper Tester orders the IUT to send a payload of the specified length to the Lower Testers. + iso_sdu = [random.randint(1, 251) for n in range(self.Max_SDU_C_TO_P)] + + # 2. Lower Tester 1 receives the payload PDU in the first subevent on CIS(1). + # 3. Lower Tester 1 sends an Ack T_IFS after receiving the payload PDU. + controller.send_iso( + hci.IsoWithoutTimestamp( + connection_handle=cis_connection_handle_1, + pb_flag=hci.IsoPacketBoundaryFlag.COMPLETE_SDU, + packet_sequence_number=42, + payload=iso_sdu, + )) + + await self.expect_ll( + ll.LeConnectedIsochronousPdu(source_address=controller.address, + destination_address=peer_address_1, + cig_id=cig_id, + cis_id=cis_id_1, + sequence_number=42, + data=iso_sdu)) + + # 4. Lower Tester 2 receives the payload PDU in the first subevent on CIS(2). + # 5. Lower Tester 2 sends an Ack T_IFS after receiving the payload PDU. + controller.send_iso( + hci.IsoWithoutTimestamp( + connection_handle=cis_connection_handle_2, + pb_flag=hci.IsoPacketBoundaryFlag.COMPLETE_SDU, + packet_sequence_number=42, + payload=iso_sdu, + )) + + await self.expect_ll( + ll.LeConnectedIsochronousPdu(source_address=controller.address, + destination_address=peer_address_2, + cig_id=cig_id, + cis_id=cis_id_2, + sequence_number=42, + data=iso_sdu)) + + # 6. If Table 4.139 specifies a BN of 2 or 3, when CIS(1) subevent interval ends, repeat steps 1–3 in + # the next subevent. + # 7. If Table 4.139 specifies a BN of 2 or 3, when CIS(2) subevent interval ends, repeat steps 4 and 5 + # in the next subevent. + # 8. If Table 4.139 specifies a BN of 3, when CIS(1) subevent interval ends, repeat steps 1–3 in the + # next subevent. + # 9. If Table 4.139 specifies a BN of 3, when CIS(2) subevent interval ends, repeat steps 4 and 5 in + # the next subevent. + # 10. The time between the ACL connection event for the first received CIS and the start of the first + # subevent on the same CIS is the observed CIS_Offset(a). The Lower Tester validates that + # CIS_Offset(a) = CIS_Offset in the LL_CIS_IND associated with CIS sent during setup of the + # CISes. + # 11. The time between the ACL connection event for the second received CIS and the start of the first + # subevent on the same CIS is the observed CIS_Offset(b). The Lower Tester validates that the + # CIS_Offset(b) = CIS_Offset in the LL_CIS_IND associated with CIS sent during setup of the + # CISes. diff --git a/tools/rootcanal/test/LL/CIS/CEN/BV_26_C.py b/tools/rootcanal/test/LL/CIS/CEN/BV_26_C.py new file mode 100644 index 0000000000000000000000000000000000000000..010ee283d3c5bfb70a8e4577cc9c3f1c412311c4 --- /dev/null +++ b/tools/rootcanal/test/LL/CIS/CEN/BV_26_C.py @@ -0,0 +1,375 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hci_packets as hci +import link_layer_packets as ll +import llcp_packets as llcp +import random +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + SDU_Interval_C_TO_P = 10000 # 10ms + SDU_Interval_P_TO_C = 10000 # 10ms + ISO_Interval = 16 # 20ms + Worst_Case_SCA = hci.ClockAccuracy.PPM_500 + Packing = hci.Packing.SEQUENTIAL + Framing = hci.Enable.ENABLED + NSE = 4 + Max_SDU_C_TO_P = 16 + Max_SDU_P_TO_C = 16 + PHY_C_TO_P = 0x1 + PHY_P_TO_C = 0x1 + Max_Transport_Latency_C_TO_P = 60 # 60ms + Max_Transport_Latency_P_TO_C = 60 # 60ms + RTN_C_TO_P = 3 + RTN_P_TO_C = 3 + + # LL/CIS/CEN/BV-01-C [CIS Setup Procedure, Central Initiated] + async def test(self): + # Test parameters. + cig_id = 0x12 + cis_id = 0x42 + cis_connection_handle = 0xe00 + peer_address = Address('aa:bb:cc:dd:ee:ff') + controller = self.controller + + # Enable Connected Isochronous Stream Host Support. + await self.enable_connected_isochronous_stream_host_support() + + # Prelude: Establish an ACL connection as central with the IUT. + acl_connection_handle = await self.establish_le_connection_central(peer_address) + + # 1. The Upper Tester sends an HCI_LE_Set_CIG_Parameters command to the IUT with + # Max_SDU_C_To_P and Max_SDU_P_To_C both set to 16, other parameters set to default, but + # with PHY and latency specified in Table 4.142 and framing enabled. The Upper Tester receives a + # success response from the IUT with CIS_Count = 1. + controller.send_cmd( + hci.LeSetCigParameters(cig_id=cig_id, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + worst_case_sca=self.Worst_Case_SCA, + max_transport_latency_c_to_p=self.Max_Transport_Latency_C_TO_P, + max_transport_latency_p_to_c=self.Max_Transport_Latency_P_TO_C, + packing=self.Packing, + framing=self.Framing, + cis_config=[ + hci.CisParametersConfig(cis_id=cis_id, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + phy_c_to_p=self.PHY_C_TO_P, + phy_p_to_c=self.PHY_P_TO_C, + rtn_c_to_p=self.RTN_C_TO_P, + rtn_p_to_c=self.RTN_P_TO_C) + ])) + + await self.expect_evt( + hci.LeSetCigParametersComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + cig_id=cig_id, + connection_handle=[cis_connection_handle])) + + # 2. The Upper Tester sends an HCI_LE_Create_CIS command to create a single CIS and receives a + # success response from the IUT. + controller.send_cmd( + hci.LeCreateCis(cis_config=[ + hci.LeCreateCisConfig(cis_connection_handle=cis_connection_handle, + acl_connection_handle=acl_connection_handle) + ])) + + await self.expect_evt(hci.LeCreateCisStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # 3. The Lower Tester receives an LL_CIS_REQ PDU from the IUT with all fields set to valid values. + # CIS_Offset_Min is a value between 500µs and TSPX_conn_interval, CIS_Offset_Max is a value + # between CIS_Offset_Min and the CIS_Offset_Max value as calculated in [14] Section 2.4.2.29 + # using TSPX_conn_interval as the value of connInterval, and connEventCount is the reference + # event anchor point for which the offsets applied. + cis_req = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisReq(cig_id=cig_id, + cis_id=cis_id, + phy_c_to_p=hci.PhyType.LE_1M, + phy_p_to_c=hci.PhyType.LE_1M, + framed=self.Framing == hci.Enable.ENABLED, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + sdu_interval_c_to_p=self.Any, + sdu_interval_p_to_c=self.Any, + max_pdu_c_to_p=self.Any, + max_pdu_p_to_c=self.Any, + nse=self.Any, + sub_interval=self.Any, + bn_p_to_c=self.Any, + bn_c_to_p=self.Any, + ft_c_to_p=self.Any, + ft_p_to_c=self.Any, + iso_interval=self.Any, + cis_offset_min=self.Any, + cis_offset_max=self.Any, + conn_event_count=0)) + + # 4. The Lower Tester sends an LL_CIS_RSP PDU to the IUT. + controller.send_llcp(source_address=peer_address, + destination_address=controller.address, + pdu=llcp.CisRsp(cis_offset_min=cis_req.cis_offset_min, + cis_offset_max=cis_req.cis_offset_max, + conn_event_count=0)) + + # 5. The Lower Tester receives an LL_CIS_IND from the IUT where the CIS_Offset is the time (ms) + # from the start of the ACL connection event in connEvent Count to the first CIS anchor point, the + # CIS_Sync_Delay is CIG_Sync_Delay minus the offset from the CIG reference point to the CIS + # anchor point in ï­s, and the connEventCount is the CIS_Offset reference point. + cis_ind = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisInd(aa=0, + cis_offset=self.Any, + cig_sync_delay=self.Any, + cis_sync_delay=self.Any, + conn_event_count=0)) + + # 6. The Upper Tester receives an HCI_LE_CIS_Established event indicating success, after the first + # CIS packet sent by the Lower Tester. The Connection_Handle parameter is set to the value + # provided in the HCI_LE_Create_CIS command. + await self.expect_evt( + hci.LeCisEstablished(status=ErrorCode.SUCCESS, + connection_handle=cis_connection_handle, + cig_sync_delay=cis_ind.cig_sync_delay, + cis_sync_delay=cis_ind.cis_sync_delay, + transport_latency_c_to_p=self.Any, + transport_latency_p_to_c=self.Any, + phy_c_to_p=hci.SecondaryPhyType.LE_1M, + phy_p_to_c=hci.SecondaryPhyType.LE_1M, + nse=cis_req.nse, + bn_c_to_p=cis_req.bn_c_to_p, + bn_p_to_c=cis_req.bn_p_to_c, + ft_c_to_p=cis_req.ft_c_to_p, + ft_p_to_c=cis_req.ft_p_to_c, + max_pdu_c_to_p=cis_req.max_pdu_c_to_p, + max_pdu_p_to_c=cis_req.max_pdu_p_to_c, + iso_interval=cis_req.iso_interval)) + + # 7. The Upper Tester sends an HCI_LE_Setup_ISO_Data_Path command and receives a success + # response from the IUT. + controller.send_cmd( + hci.LeSetupIsoDataPath( + connection_handle=cis_connection_handle, + data_path_direction=hci.DataPathDirection.OUTPUT, + data_path_id=0, + codec_id=0, + controller_delay=0, + codec_configuration=[], + )) + + await self.expect_evt( + hci.LeSetupIsoDataPathComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=cis_connection_handle)) + + # 8. The Upper Tester sends HCI ISO data packets over the CIS and the Lower Tester receives + # framed ISO data. + iso_sdu = [random.randint(1, 251) for n in range(self.Max_SDU_C_TO_P)] + controller.send_iso( + hci.IsoWithoutTimestamp( + connection_handle=cis_connection_handle, + pb_flag=hci.IsoPacketBoundaryFlag.COMPLETE_SDU, + packet_sequence_number=42, + payload=iso_sdu, + )) + + await self.expect_ll( + ll.LeConnectedIsochronousPdu(source_address=controller.address, + destination_address=peer_address, + cig_id=cig_id, + cis_id=cis_id, + sequence_number=42, + data=iso_sdu)) + + # 9. The Upper Tester sends an HCI_Disconnect command to the IUT with Reason set to any valid + # value and Connection_Handle set to the connection handle of the active CIS and receives a + # successful HCI_Command_Status event in response. + controller.send_cmd( + hci.Disconnect(connection_handle=cis_connection_handle, reason=ErrorCode.REMOTE_USER_TERMINATED_CONNECTION)) + + await self.expect_evt(hci.DisconnectStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # 10. The IUT sends an LL_CIS_TERMINATE_IND PDU to the Lower Tester, and the ErrorCode field + # in the CrtData matches the Reason code value that the Upper Tester sent in step 9. + await self.expect_llcp( + source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisTerminateInd(cig_id=cig_id, + cis_id=cis_id, + error_code=ErrorCode.REMOTE_USER_TERMINATED_CONNECTION)) + + # 11. The Lower Tester sends an LL Ack to the IUT. + # 12. The IUT sends an HCI_Disconnection_Complete event to the Upper Tester. + await self.expect_evt( + hci.DisconnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=cis_connection_handle, + reason=ErrorCode.CONNECTION_TERMINATED_BY_LOCAL_HOST)) + + # 13. The Upper Tester sends an HCI_LE_Remove_CIG command to the IUT with CIG_ID set to the + # value of the current inactive CIG. + controller.send_cmd(hci.LeRemoveCig(cig_id=cig_id)) + + # 14. The IUT sends an HCI_Command_Complete event to the Upper Tester with Status set to 0x00 + # and CIG_ID set to the CIG_ID value in step 13. + await self.expect_evt( + hci.LeRemoveCigComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1, cig_id=cig_id)) + + # 15. The Upper Tester sends an HCI_LE_Set_CIG_Parameters command to the IUT with default + # parameters but with Max_SDU_C_To_P set to 0 and receives a success response from the IUT + # with CIS_Count = 1. + controller.send_cmd( + hci.LeSetCigParameters(cig_id=cig_id, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + worst_case_sca=self.Worst_Case_SCA, + max_transport_latency_c_to_p=self.Max_Transport_Latency_C_TO_P, + max_transport_latency_p_to_c=self.Max_Transport_Latency_P_TO_C, + packing=self.Packing, + framing=self.Framing, + cis_config=[ + hci.CisParametersConfig(cis_id=cis_id, + max_sdu_c_to_p=0, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + phy_c_to_p=self.PHY_C_TO_P, + phy_p_to_c=self.PHY_P_TO_C, + rtn_c_to_p=self.RTN_C_TO_P, + rtn_p_to_c=self.RTN_P_TO_C) + ])) + + await self.expect_evt( + hci.LeSetCigParametersComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + cig_id=cig_id, + connection_handle=[cis_connection_handle])) + + # 16. The Upper Tester sends an HCI_LE_Create_CIS command to create a single CIS and receives a + # success response from the IUT. + controller.send_cmd( + hci.LeCreateCis(cis_config=[ + hci.LeCreateCisConfig(cis_connection_handle=cis_connection_handle, + acl_connection_handle=acl_connection_handle) + ])) + + await self.expect_evt(hci.LeCreateCisStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # 17. The IUT sends an LL_CIS_REQ PDU to the Lower Tester with all fields set to valid values. + # 18. The value of Max_SDU_C_To_P and BN_C_To_P in the CrtData of the LL_CIS_REQ PDU are + # verified to be equal to 0. The test fails if the values are not equal to 0. + cis_req = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisReq(cig_id=cig_id, + cis_id=cis_id, + phy_c_to_p=hci.PhyType.LE_1M, + phy_p_to_c=hci.PhyType.LE_1M, + framed=self.Framing == hci.Enable.ENABLED, + max_sdu_c_to_p=0, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + sdu_interval_c_to_p=self.Any, + sdu_interval_p_to_c=self.Any, + max_pdu_c_to_p=self.Any, + max_pdu_p_to_c=self.Any, + nse=self.Any, + sub_interval=self.Any, + bn_c_to_p=0, + bn_p_to_c=self.Any, + ft_c_to_p=self.Any, + ft_p_to_c=self.Any, + iso_interval=self.Any, + cis_offset_min=self.Any, + cis_offset_max=self.Any, + conn_event_count=0)) + + # 19. The Lower Tester sends an LL_CIS_RSP PDU to the IUT. + controller.send_llcp(source_address=peer_address, + destination_address=controller.address, + pdu=llcp.CisRsp(cis_offset_min=cis_req.cis_offset_min, + cis_offset_max=cis_req.cis_offset_max, + conn_event_count=0)) + + # 20. The IUT sends an LL_CIS_IND to the Lower Tester. + cis_ind = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisInd(aa=0, + cis_offset=self.Any, + cig_sync_delay=self.Any, + cis_sync_delay=self.Any, + conn_event_count=0)) + + # 21. The IUT sends an empty ISO Data Packet to the Lower Tester. + # 22. The Lower Tester sends an LL Ack to the IUT. + # 23. The IUT sends an HCI_LE_CIS_Established event to the Upper Tester. The Connection_Handle + # parameter is set to the value provided in step 16. + await self.expect_evt( + hci.LeCisEstablished(status=ErrorCode.SUCCESS, + connection_handle=cis_connection_handle, + cig_sync_delay=cis_ind.cig_sync_delay, + cis_sync_delay=cis_ind.cis_sync_delay, + transport_latency_c_to_p=self.Any, + transport_latency_p_to_c=self.Any, + phy_c_to_p=hci.SecondaryPhyType.LE_1M, + phy_p_to_c=hci.SecondaryPhyType.LE_1M, + nse=cis_req.nse, + bn_c_to_p=cis_req.bn_c_to_p, + bn_p_to_c=cis_req.bn_p_to_c, + ft_c_to_p=cis_req.ft_c_to_p, + ft_p_to_c=cis_req.ft_p_to_c, + max_pdu_c_to_p=cis_req.max_pdu_c_to_p, + max_pdu_p_to_c=cis_req.max_pdu_p_to_c, + iso_interval=cis_req.iso_interval)) + + # 24. The Upper Tester sends an HCI_LE_Setup_ISO_Data_Path command to the IUT with + # Connection_Handle set to the value provided in step 16 and Data_Path_Direction set to Output. + controller.send_cmd( + hci.LeSetupIsoDataPath( + connection_handle=cis_connection_handle, + data_path_direction=hci.DataPathDirection.OUTPUT, + data_path_id=0, + codec_id=0, + controller_delay=0, + codec_configuration=[], + )) + + # 25. The IUT sends a successful HCI_Command_Complete event to the Upper Tester. + await self.expect_evt( + hci.LeSetupIsoDataPathComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=cis_connection_handle)) + + # 26. The IUT sends a CIS Null PDU to the Lower Tester. + # 27. The Lower Tester sends an ISO Data Packet to the IUT. + # 28. Repeat steps 26 and 27, 50 times. + iso_sdu = [random.randint(1, 251) for n in range(self.Max_SDU_P_TO_C)] + controller.send_ll( + ll.LeConnectedIsochronousPdu(source_address=peer_address, + destination_address=controller.address, + cig_id=cig_id, + cis_id=cis_id, + sequence_number=42, + data=iso_sdu)) + + await self.expect_iso( + hci.IsoWithoutTimestamp( + connection_handle=cis_connection_handle, + pb_flag=hci.IsoPacketBoundaryFlag.COMPLETE_SDU, + iso_sdu_length=len(iso_sdu), + packet_sequence_number=42, + payload=iso_sdu, + )) diff --git a/tools/rootcanal/test/LL/CIS/PER/BV_01_C.py b/tools/rootcanal/test/LL/CIS/PER/BV_01_C.py new file mode 100644 index 0000000000000000000000000000000000000000..63e3be15d12be819342e11926913f6f37be22b21 --- /dev/null +++ b/tools/rootcanal/test/LL/CIS/PER/BV_01_C.py @@ -0,0 +1,192 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hci_packets as hci +import link_layer_packets as ll +import llcp_packets as llcp +import random +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + SDU_Interval_C_TO_P = 7500 # 7.5ms + SDU_Interval_P_TO_C = 7500 # 7.5ms + ISO_Interval = 6 # 7.5ms + Sub_Interval = 7500 # 7.5ms (approximation) + CIG_Sync_Delay = 7500 # 7.5ms (approximation) + CIS_Sync_Delay = 7500 # 7.5ms (approximation) + Worst_Case_SCA = hci.ClockAccuracy.PPM_500 + Packing = hci.Packing.SEQUENTIAL + Framing = hci.Enable.DISABLED + NSE = 2 + Max_SDU_C_TO_P = 160 + Max_SDU_P_TO_C = 160 + Max_PDU_C_TO_P = 160 + Max_PDU_P_TO_C = 160 + PHY_C_TO_P = 0x1 + PHY_P_TO_C = 0x1 + FT_C_TO_P = 1 + FT_P_TO_C = 1 + BN_C_TO_P = 1 + BN_P_TO_C = 1 + Max_Transport_Latency_C_TO_P = 40000 # 40ms + Max_Transport_Latency_P_TO_C = 40000 # 40ms + RTN_C_TO_P = 3 + RTN_P_TO_C = 3 + + # LL/CIS/PER/BV-01-C [CIS Setup Response Procedure, Peripheral] + async def test(self): + # Test parameters. + cig_id = 0x12 + cis_id = 0x42 + acl_connection_handle = 0xefe + cis_connection_handle = 0xe00 + peer_address = Address('aa:bb:cc:dd:ee:ff') + controller = self.controller + + # Enable Connected Isochronous Stream Host Support. + await self.enable_connected_isochronous_stream_host_support() + + # Prelude: Establish an ACL connection as peripheral with the IUT. + acl_connection_handle = await self.establish_le_connection_peripheral(peer_address) + + # 1. The Upper Tester sends an HCI_LE_Set_Event_Mask command with all events enabled, + # including the HCI_LE_CIS_Request event. The IUT sends a successful + # HCI_Command_Complete in response. + controller.send_cmd(hci.LeSetEventMask(le_event_mask=0xffffffffffffffff)) + + await self.expect_evt(hci.LeSetEventMaskComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # 2. The Lower Tester sends an LL_CIS_REQ to the IUT with the contents specified in Table 4.156. + # All bits in the RFU fields in the LL_CIS_REQ are set. + controller.send_llcp(source_address=peer_address, + destination_address=controller.address, + pdu=llcp.CisReq(cig_id=cig_id, + cis_id=cis_id, + phy_c_to_p=hci.PhyType.LE_1M, + phy_p_to_c=hci.PhyType.LE_1M, + framed=self.Framing == hci.Enable.ENABLED, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + nse=self.NSE, + sub_interval=self.Sub_Interval, + bn_p_to_c=self.BN_C_TO_P, + bn_c_to_p=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + cis_offset_min=0, + cis_offset_max=0, + conn_event_count=0)) + + # 3. The IUT sends an HCI_LE_CIS_Request event to the Upper Tester and the parameters include + # CIS_Connection_Handle assigned by the IUT. + await self.expect_evt( + hci.LeCisRequest(acl_connection_handle=acl_connection_handle, + cis_connection_handle=cis_connection_handle, + cig_id=cig_id, + cis_id=cis_id)) + + # 4. The Upper Tester sends an HCI_LE_Accept_CIS_Request command to the IUT, with the + # Connection_Handle field set to the value of the CIS_Connection_Handle received in step 3. + controller.send_cmd(hci.LeAcceptCisRequest(connection_handle=cis_connection_handle)) + + # 5. The IUT sends a successful Command Status to the Upper Tester. + await self.expect_evt(hci.LeAcceptCisRequestStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # 6. The IUT sends an LL_CIS_RSP PDU to the Upper Tester. In the message, the CIS_Offset_Min + # field and the CIS_Offset_Max field are equal to or a subset of the values received in the + # LL_CIS_REQ sent in step 2. + cis_rsp = await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.CisRsp(cis_offset_min=self.Any, + cis_offset_max=self.Any, + conn_event_count=0)) + + # 7. The Lower Tester sends an LL_CIS_IND where the CIS_Offset is the time (ms) from the start of + # the ACL connection event in connEvent Count to the first CIS anchor point, the CIS_Sync_Delay + # is CIG_Sync_Delay minus the offset from the CIG reference point to the CIS anchor point in ï­s, + # and the connEventCount is the CIS_Offset reference point. + controller.send_llcp(source_address=peer_address, + destination_address=controller.address, + pdu=llcp.CisInd(aa=0, + cis_offset=cis_rsp.cis_offset_max, + cig_sync_delay=self.CIG_Sync_Delay, + cis_sync_delay=self.CIS_Sync_Delay, + conn_event_count=0)) + + # 8. The IUT sends a successful HCI_LE_CIS_Established event to the Upper Tester, after the first + # CIS packet sent by the Lower Tester. The Connection_Handle parameter is the + # CIS_Connection_Handle value provided in the HCI_LE_CIS_Request event. + await self.expect_evt( + hci.LeCisEstablished(status=ErrorCode.SUCCESS, + connection_handle=cis_connection_handle, + cig_sync_delay=self.CIG_Sync_Delay, + cis_sync_delay=self.CIS_Sync_Delay, + transport_latency_c_to_p=self.Any, + transport_latency_p_to_c=self.Any, + phy_c_to_p=hci.SecondaryPhyType.LE_1M, + phy_p_to_c=hci.SecondaryPhyType.LE_1M, + nse=self.NSE, + bn_c_to_p=self.BN_C_TO_P, + bn_p_to_c=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + iso_interval=self.ISO_Interval)) + + # 9. The Upper Tester sends an HCI_LE_Setup_ISO_Data_Path command to the IUT with the output + # path enabled and receives a successful HCI_Command_Complete in response. + controller.send_cmd( + hci.LeSetupIsoDataPath( + connection_handle=cis_connection_handle, + data_path_direction=hci.DataPathDirection.OUTPUT, + data_path_id=0, + codec_id=0, + controller_delay=0, + codec_configuration=[], + )) + + await self.expect_evt( + hci.LeSetupIsoDataPathComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=cis_connection_handle)) + + # 10. The Lower Tester sends data packets to the IUT. + iso_sdu = [random.randint(1, 251) for n in range(self.Max_SDU_C_TO_P)] + controller.send_ll( + ll.LeConnectedIsochronousPdu(source_address=controller.address, + cig_id=cig_id, + cis_id=cis_id, + sequence_number=42, + data=iso_sdu)) + + # 11. The IUT sends an ISO data packet to the Upper Tester + await self.expect_iso( + hci.IsoWithoutTimestamp( + connection_handle=cis_connection_handle, + pb_flag=hci.IsoPacketBoundaryFlag.COMPLETE_SDU, + packet_sequence_number=42, + iso_sdu_length=len(iso_sdu), + payload=iso_sdu, + )) diff --git a/tools/rootcanal/test/LL/CIS/PER/BV_02_C.py b/tools/rootcanal/test/LL/CIS/PER/BV_02_C.py new file mode 100644 index 0000000000000000000000000000000000000000..13c3ec7c37a84aa632b063203e2a0c403c20a54e --- /dev/null +++ b/tools/rootcanal/test/LL/CIS/PER/BV_02_C.py @@ -0,0 +1,122 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hci_packets as hci +import link_layer_packets as ll +import llcp_packets as llcp +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + SDU_Interval_C_TO_P = 10000 # 7.5ms + SDU_Interval_P_TO_C = 10000 # 7.5ms + ISO_Interval = 20000 # 7.5ms + Worst_Case_SCA = hci.ClockAccuracy.PPM_500 + Packing = hci.Packing.SEQUENTIAL + Framing = hci.Enable.DISABLED + NSE = 2 + Max_SDU_C_TO_P = 160 + Max_SDU_P_TO_C = 160 + Max_PDU_C_TO_P = 160 + Max_PDU_P_TO_C = 160 + PHY_C_TO_P = 0x1 + PHY_P_TO_C = 0x1 + FT_C_TO_P = 1 + FT_P_TO_C = 1 + BN_C_TO_P = 1 + BN_P_TO_C = 1 + Max_Transport_Latency_C_TO_P = 40000 # 40ms + Max_Transport_Latency_P_TO_C = 40000 # 40ms + RTN_C_TO_P = 3 + RTN_P_TO_C = 3 + + # LL/CIS/PER/BV-02-C [CIS Setup Response Procedure, Peripheral, Reject Response] + async def test(self): + # Test parameters. + cig_id = 0x12 + cis_id = 0x42 + acl_connection_handle = 0xefe + cis_connection_handle = 0xe00 + peer_address = Address('aa:bb:cc:dd:ee:ff') + controller = self.controller + + # Enable Connected Isochronous Stream Host Support. + await self.enable_connected_isochronous_stream_host_support() + + # Prelude: Establish an ACL connection as peripheral with the IUT. + acl_connection_handle = await self.establish_le_connection_peripheral(peer_address) + + # 1. The Upper Tester sends an HCI_LE_Set_Event_Mask command with all events enabled, + # including the HCI_LE_CIS_Request event. The IUT sends a successful + # HCI_Command_Complete in response. + controller.send_cmd(hci.LeSetEventMask(le_event_mask=0xffffffffffffffff)) + + await self.expect_evt(hci.LeSetEventMaskComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # 2. The Lower Tester sends an LL_CIS_REQ to the IUT with the contents specified in Table 4.156. + # All bits in the RFU fields in the LL_CIS_REQ are set. + controller.send_llcp(source_address=peer_address, + destination_address=controller.address, + pdu=llcp.CisReq(cig_id=cig_id, + cis_id=cis_id, + phy_c_to_p=hci.PhyType.LE_1M, + phy_p_to_c=hci.PhyType.LE_1M, + framed=self.Framing == hci.Enable.ENABLED, + max_sdu_c_to_p=self.Max_SDU_C_TO_P, + max_sdu_p_to_c=self.Max_SDU_P_TO_C, + sdu_interval_c_to_p=self.SDU_Interval_C_TO_P, + sdu_interval_p_to_c=self.SDU_Interval_P_TO_C, + max_pdu_c_to_p=self.Max_PDU_C_TO_P, + max_pdu_p_to_c=self.Max_PDU_P_TO_C, + nse=self.NSE, + sub_interval=0, + bn_p_to_c=self.BN_C_TO_P, + bn_c_to_p=self.BN_P_TO_C, + ft_c_to_p=self.FT_C_TO_P, + ft_p_to_c=self.FT_P_TO_C, + iso_interval=self.ISO_Interval, + cis_offset_min=0, + cis_offset_max=0, + conn_event_count=0)) + + # 3. The IUT sends an HCI_LE_CIS_Request event to the Upper Tester and the parameters include + # CIS_Connection_Handle assigned by the IUT. + await self.expect_evt( + hci.LeCisRequest(acl_connection_handle=acl_connection_handle, + cis_connection_handle=cis_connection_handle, + cig_id=cig_id, + cis_id=cis_id)) + + # 4. The Upper Tester sends an HCI_LE_Reject_CIS_Request command to the IUT with a valid + # reason code and receives a successful return status + controller.send_cmd( + hci.LeRejectCisRequest(connection_handle=cis_connection_handle, + reason=ErrorCode.CONNECTION_REJECTED_LIMITED_RESOURCES)) + + # 5. The Upper Tester receives an HCI_Command_Complete event from the IUT + await self.expect_evt( + hci.LeRejectCisRequestComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=cis_connection_handle)) + + # 6. The Lower Tester receives an LL_REJECT_EXT_IND from the IUT with a valid reason code. + await self.expect_llcp(source_address=controller.address, + destination_address=peer_address, + expected_pdu=llcp.RejectExtInd( + reject_opcode=llcp.Opcode.LL_CIS_REQ, + error_code=ErrorCode.CONNECTION_REJECTED_LIMITED_RESOURCES)) diff --git a/tools/rootcanal/test/LL/CON_/CEN/BV_41_C.py b/tools/rootcanal/test/LL/CON_/CEN/BV_41_C.py index 4de878b0a3a87f223866473e043423ff53f880eb..9d377ef54a4a8f480c50e063427c9cebcb5e5cb0 100644 --- a/tools/rootcanal/test/LL/CON_/CEN/BV_41_C.py +++ b/tools/rootcanal/test/LL/CON_/CEN/BV_41_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from dataclasses import dataclass import hci_packets as hci import link_layer_packets as ll @@ -32,13 +46,13 @@ class Test(ControllerTest): peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, initiating_phys=0x1, - phy_scan_parameters=[ - hci.LeCreateConnPhyScanParameters( + initiating_phy_parameters=[ + hci.InitiatingPhyParameters( scan_interval=0x200, scan_window=0x100, - conn_interval_min=0x200, - conn_interval_max=0x200, - conn_latency=0x6, + connection_interval_min=0x200, + connection_interval_max=0x200, + max_latency=0x6, supervision_timeout=0xc80, min_ce_length=0, max_ce_length=0, @@ -77,8 +91,8 @@ class Test(ControllerTest): role=hci.Role.CENTRAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x6, + connection_interval=0x200, + peripheral_latency=0x6, supervision_timeout=0xc80, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/CON_/CEN/BV_43_C.py b/tools/rootcanal/test/LL/CON_/CEN/BV_43_C.py index d475606a291a7f80025898438c83b98187ca4483..914df4cfe95586a1c2e117279fdbd8eaeb4176bc 100644 --- a/tools/rootcanal/test/LL/CON_/CEN/BV_43_C.py +++ b/tools/rootcanal/test/LL/CON_/CEN/BV_43_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from dataclasses import dataclass import hci_packets as hci import link_layer_packets as ll @@ -29,13 +43,13 @@ class Test(ControllerTest): peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, initiating_phys=0x1, - phy_scan_parameters=[ - hci.LeCreateConnPhyScanParameters( + initiating_phy_parameters=[ + hci.InitiatingPhyParameters( scan_interval=0x200, scan_window=0x100, - conn_interval_min=0x200, - conn_interval_max=0x200, - conn_latency=0x6, + connection_interval_min=0x200, + connection_interval_max=0x200, + max_latency=0x6, supervision_timeout=0xc80, min_ce_length=0, max_ce_length=0, @@ -74,8 +88,8 @@ class Test(ControllerTest): role=hci.Role.CENTRAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x6, + connection_interval=0x200, + peripheral_latency=0x6, supervision_timeout=0xc80, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/CON_/PER/BV_40_C.py b/tools/rootcanal/test/LL/CON_/PER/BV_40_C.py index 635fcc6f7b090d32385b92de234b54267d30d592..045bca32a30057206212c9c4915ff94b89fca0dd 100644 --- a/tools/rootcanal/test/LL/CON_/PER/BV_40_C.py +++ b/tools/rootcanal/test/LL/CON_/PER/BV_40_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from dataclasses import dataclass import hci_packets as hci import link_layer_packets as ll @@ -63,8 +77,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x200, + connection_interval=0x200, + peripheral_latency=0x200, supervision_timeout=0x200, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/CON_/PER/BV_42_C.py b/tools/rootcanal/test/LL/CON_/PER/BV_42_C.py index fe781732d4036fb7c6ac8bd6c09d316b6b31d451..ae067c2269221334c6ef64da452772bde5390241 100644 --- a/tools/rootcanal/test/LL/CON_/PER/BV_42_C.py +++ b/tools/rootcanal/test/LL/CON_/PER/BV_42_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from dataclasses import dataclass import hci_packets as hci import link_layer_packets as ll @@ -63,8 +77,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=0x200, - conn_latency=0x200, + connection_interval=0x200, + peripheral_latency=0x200, supervision_timeout=0x200, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_01_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_01_C.py index be89bfc3b88bb41c4b5c4fc2152a5505cd9d7ea8..23760249539dea0b2056b5ee61957e352883a257 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_01_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_01_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -33,7 +47,7 @@ class Test(ControllerTest): await self.expect_evt( hci.LeSetAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) - controller.send_cmd(hci.LeSetAdvertisingDataRaw()) + controller.send_cmd(hci.LeSetAdvertisingData()) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_02_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_02_C.py index 3f49d18c1c7dd02dfed3e52924b5751d2c1222e2..2b7f44cb48ba66801d904a6f81fe5e0bf5159b32 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_02_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_02_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -32,7 +46,7 @@ class Test(ControllerTest): await self.expect_evt( hci.LeSetAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) - controller.send_cmd(hci.LeSetAdvertisingDataRaw()) + controller.send_cmd(hci.LeSetAdvertisingData()) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_03_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_03_C.py index 1eb851153d268af48fc5429f42296c093fb42162..47eb0d146d59b352b268014812e2d4057914e542 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_03_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_03_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -37,7 +51,7 @@ class Test(ControllerTest): # HCI_Command_Complete in response. The data element used in the command is the length of # the data field. The data length is 1 byte. advertising_data = [1] - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=advertising_data)) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=advertising_data)) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -67,7 +81,7 @@ class Test(ControllerTest): # 9. Upper Tester sends an HCI_LE_Set_Advertising_Data to configure the IUT to send advertising # packets without advertising data and receives an HCI_Command_Complete event in response. - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=[])) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=[])) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -101,7 +115,7 @@ class Test(ControllerTest): # zeroes. The data length is either 31 bytes by default or it may be specified by IXIT value if less # than 31 bytes. advertising_data = [31] + [0] * 30 - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=advertising_data)) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=advertising_data)) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -121,7 +135,7 @@ class Test(ControllerTest): await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=[])) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=[])) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_04_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_04_C.py index 8888d51fdd9ab64da895b43dcde5667e954a7b17..0d84e45a0c3be933f502a312ecd8e4eeb8541498 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_04_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_04_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -36,7 +50,7 @@ class Test(ControllerTest): # HCI_Command_Complete in response. The data element used in the command is the length of # the data field. The data length is 1 byte. advertising_data = [1] - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=advertising_data)) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=advertising_data)) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -66,7 +80,7 @@ class Test(ControllerTest): # 9. Upper Tester sends an HCI_LE_Set_Advertising_Data to configure the IUT to send advertising # packets without advertising data and receives an HCI_Command_Complete event in response. - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=[])) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=[])) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -99,7 +113,7 @@ class Test(ControllerTest): # data field in the first octet encoded unsigned least significant bit first and the rest of the octets # zeroes. The data length is 31 bytes. advertising_data = [31] + [0] * 30 - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=advertising_data)) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=advertising_data)) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -119,7 +133,7 @@ class Test(ControllerTest): await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=[])) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=[])) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_05_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_05_C.py index 3f846aec4bad3a82e2fe2dc3725c17b179f05c32..a4b920ce2da524c718423109349a202e0d774c77 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_05_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_05_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -41,7 +55,7 @@ class Test(ControllerTest): # 3. Configure Scan Response Data in the IUT using device name length of 0 as response data. scan_response_data = [] - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -80,7 +94,7 @@ class Test(ControllerTest): await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) scan_response_data = [31] + [0] * 30 - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -119,7 +133,7 @@ class Test(ControllerTest): await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) scan_response_data = [] - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -146,7 +160,7 @@ class Test(ControllerTest): await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) scan_response_data = [31] + [0] * 30 - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py index 38acd5bea8c045a6ba0e74a6d8169985c92889ba..f52edd3deba0fb588a1597fc534e629e61341f34 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_06_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -81,8 +95,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=LL_initiator_connInterval, - conn_latency=LL_initiator_connPeripheralLatency, + connection_interval=LL_initiator_connInterval, + peripheral_latency=LL_initiator_connPeripheralLatency, supervision_timeout=LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py index 8a10b6a1ba5c75f2cd266477b55400a982ed409f..271a4fc564979caede3f6ee26aed68fe2977cc85 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_07_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -39,7 +53,7 @@ class Test(ControllerTest): # 2. Upper Tester sends an HCI_LE_Set_Scan_Response_Data command with data set to “IUT†and # receives an HCI_Command_Complete event from the IUT. scan_response_data = [ord('I'), ord('U'), ord('T')] - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -111,8 +125,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=LL_initiator_connInterval, - conn_latency=LL_initiator_connPeripheralLatency, + connection_interval=LL_initiator_connInterval, + peripheral_latency=LL_initiator_connPeripheralLatency, supervision_timeout=LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_08_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_08_C.py index 13eb857aee2d1541c53db296a9de14d86034fc78..4a2145304b3d90ff9f8ee836590b0f27aab8789e 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_08_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_08_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -53,7 +67,7 @@ class Test(ControllerTest): # 2. Upper Tester sends an HCI_LE_Set_Scan_Response_Data command with data set to “IUT†and # receives an HCI_Command_Complete event from the IUT. scan_response_data = [ord('I'), ord('U'), ord('T')] - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py index bad9c81ba7b4448c43d4f35dd869473d4b76a931..719ddc76e3314afdf72ea67be9a11920b2955151 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_09_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -55,7 +69,7 @@ class Test(ControllerTest): # 2. Upper Tester sends an HCI_LE_Set_Scan_Response_Data command with data set to “IUT†and # receives an HCI_Command_Complete event from the IUT. scan_response_data = [ord('I'), ord('U'), ord('T')] - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -296,8 +310,8 @@ class Test(ControllerTest): peer_address_type=(hci.AddressType.PUBLIC_DEVICE_ADDRESS if peer_address_type == ll.AddressType.PUBLIC else hci.AddressType.RANDOM_DEVICE_ADDRESS), peer_address=peer_address, - conn_interval=self.LL_initiator_connInterval, - conn_latency=self.LL_initiator_connPeripheralLatency, + connection_interval=self.LL_initiator_connInterval, + peripheral_latency=self.LL_initiator_connPeripheralLatency, supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) @@ -366,8 +380,8 @@ class Test(ControllerTest): peer_address_type=(hci.AddressType.PUBLIC_DEVICE_ADDRESS if peer_address_type == ll.AddressType.PUBLIC else hci.AddressType.RANDOM_DEVICE_ADDRESS), peer_address=peer_address, - conn_interval=self.LL_initiator_connInterval, - conn_latency=self.LL_initiator_connPeripheralLatency, + connection_interval=self.LL_initiator_connInterval, + peripheral_latency=self.LL_initiator_connPeripheralLatency, supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py index f2d14f325c6da03f1c574dcc8d838dc6a26a50ce..014417f9becdafe783c74f19de455efc4538aefe 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_11_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import asyncio import hci_packets as hci import link_layer_packets as ll @@ -123,8 +137,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=peer_address, - conn_interval=self.LL_initiator_connInterval, - conn_latency=self.LL_initiator_connPeripheralLatency, + connection_interval=self.LL_initiator_connInterval, + peripheral_latency=self.LL_initiator_connPeripheralLatency, supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_15_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_15_C.py index 14d5be02fe3e39bd422c846fb5cb322d020f7fb0..f04aa898c91eaea99e2a6219b8c003bd43e3e4da 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_15_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_15_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_16_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_16_C.py index 1512ddc7b66a999559ca058c0a3d36e514a33c2a..d07bce0a42d89e3077844f4fe5fe7aedc9ec8708 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_16_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_16_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -35,7 +49,7 @@ class Test(ControllerTest): # HCI_Command_Complete in response. The data element used in the command is a number # indicating the length of the data. The data length is 1 byte. advertising_data = [1] - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=advertising_data)) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=advertising_data)) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -98,7 +112,7 @@ class Test(ControllerTest): # data field in the first octet encoded unsigned least significant bit first and the rest of the octets # zeroes. The data length is 31 bytes. advertising_data = [31] + [0] * 30 - controller.send_cmd(hci.LeSetAdvertisingDataRaw(advertising_data=advertising_data)) + controller.send_cmd(hci.LeSetAdvertisingData(advertising_data=advertising_data)) await self.expect_evt(hci.LeSetAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_17_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_17_C.py index f22c0421ad49fb81e59b665c3d729162c43a8d43..c27619c2da399aafe82001b58f327be055dd19ff 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_17_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_17_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -38,7 +52,7 @@ class Test(ControllerTest): # 3. Configure Scan Response Data in the IUT using device name length of 0 as response data. scan_response_data = [] - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -55,8 +69,8 @@ class Test(ControllerTest): await self.steps_4_6(peer_address=peer_address, scan_response_data=scan_response_data) # 7. Configure Scan Response Data in the IUT using device name length of 31 as response data. - scan_response_data = [31] + [0] * 31 - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + scan_response_data = [31] + [0] * 30 + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -78,7 +92,7 @@ class Test(ControllerTest): # 10. Configure Scan Response Data in the IUT using device name length of 0 as response data. scan_response_data = [] - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) @@ -90,8 +104,8 @@ class Test(ControllerTest): await self.steps_4_6(peer_address=peer_address, scan_response_data=scan_response_data) # 12. Configure Scan Response Data in the IUT using device name length of 31 as response data. - scan_response_data = [31] + [0] * 31 - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + scan_response_data = [31] + [0] * 30 + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_18_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_18_C.py index 729d934ffaab444b9935c91e3fa79fdfbacdeb29..9f3fb8378ae29a833d425d24099609cec2d108e4 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_18_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_18_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -51,7 +65,7 @@ class Test(ControllerTest): hci.LeSetAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) scan_response_data = [ord('I'), ord('U'), ord('T')] - controller.send_cmd(hci.LeSetScanResponseDataRaw(advertising_data=scan_response_data)) + controller.send_cmd(hci.LeSetScanResponseData(advertising_data=scan_response_data)) await self.expect_evt(hci.LeSetScanResponseDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py index f48caf2fc0c2bf406d0b904af7f80ce7474e9e08..9247324a4fc17accc90c740140fbfcdd04e1af29 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_19_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -98,8 +112,8 @@ class Test(ControllerTest): role=hci.Role.PERIPHERAL, peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS, peer_address=public_peer_address, - conn_interval=self.LL_initiator_connInterval, - conn_latency=self.LL_initiator_connPeripheralLatency, + connection_interval=self.LL_initiator_connInterval, + peripheral_latency=self.LL_initiator_connPeripheralLatency, supervision_timeout=self.LL_initiator_connSupervisionTimeout, central_clock_accuracy=hci.ClockAccuracy.PPM_500)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_20_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_20_C.py index f342961cce907da28a9541291483833cb572874e..61e70e10e1ac90e399ba61f86ab0d7be86bf22a7 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_20_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_20_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_21_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_21_C.py index 7400e8c30e5a164feaa59c8ca7a555e682d023fa..064194cf38b22022547121f3ed6bd8afad45d0d9 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_21_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_21_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -46,9 +60,9 @@ class Test(ControllerTest): # 3. Upper Tester sends an HCI_LE_Set_Extended_Advertising_Data command to the IUT with # values according to Table 4.2 and receives an HCI_Command_Complete in response. controller.send_cmd( - hci.LeSetExtendedAdvertisingDataRaw(advertising_handle=0, - operation=hci.Operation.COMPLETE_ADVERTISEMENT, - advertising_data=advertising_data)) + hci.LeSetExtendedAdvertisingData(advertising_handle=0, + operation=hci.Operation.COMPLETE_ADVERTISEMENT, + advertising_data=advertising_data)) await self.expect_evt( hci.LeSetExtendedAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py index 5c36abe633b92f05f6cb6c3f761397021169528c..dd8b5b19cc8495de5775d187905f26a4bce21135 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_22_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -45,9 +59,9 @@ class Test(ControllerTest): # 3. Upper Tester sends an HCI_LE_Set_Extended_Advertising_Data command to the IUT with # values according to Table 4.4 and receives an HCI_Command_Complete in response. controller.send_cmd( - hci.LeSetExtendedAdvertisingDataRaw(advertising_handle=0, - operation=hci.Operation.COMPLETE_ADVERTISEMENT, - advertising_data=advertising_data)) + hci.LeSetExtendedAdvertisingData(advertising_handle=0, + operation=hci.Operation.COMPLETE_ADVERTISEMENT, + advertising_data=advertising_data)) await self.expect_evt( hci.LeSetExtendedAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_26_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_26_C.py index 6cdbaa70104e09bfe5a0f9dd5edcb4be88c1c22f..909b08a614f73ecb626d2c24d2ebfbacedebf4ce 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_26_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_26_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import asyncio import hci_packets as hci import link_layer_packets as ll @@ -114,10 +128,10 @@ class Test(ControllerTest): operation = hci.Operation.INTERMEDIATE_FRAGMENT controller.send_cmd( - hci.LeSetPeriodicAdvertisingDataRaw(advertising_handle=0, - operation=operation, - advertising_data=advertising_data[fragment_offset:fragment_offset + - fragment_length])) + hci.LeSetPeriodicAdvertisingData(advertising_handle=0, + operation=operation, + advertising_data=advertising_data[fragment_offset:fragment_offset + + fragment_length])) await self.expect_evt( hci.LeSetPeriodicAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/ADV/BV_47_C.py b/tools/rootcanal/test/LL/DDI/ADV/BV_47_C.py index 48e16f82356c68c0041d55dffca4d79c1e6c29ac..5430f8ed3b2d3e9197ea028e11362cc7c42e6fa3 100644 --- a/tools/rootcanal/test/LL/DDI/ADV/BV_47_C.py +++ b/tools/rootcanal/test/LL/DDI/ADV/BV_47_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import asyncio import hci_packets as hci import link_layer_packets as ll @@ -126,10 +140,10 @@ class Test(ControllerTest): operation = hci.Operation.INTERMEDIATE_FRAGMENT controller.send_cmd( - hci.LeSetExtendedAdvertisingDataRaw(advertising_handle=0, - operation=operation, - advertising_data=advertising_data[fragment_offset:fragment_offset + - fragment_length])) + hci.LeSetExtendedAdvertisingData(advertising_handle=0, + operation=operation, + advertising_data=advertising_data[fragment_offset:fragment_offset + + fragment_length])) await self.expect_evt( hci.LeSetExtendedAdvertisingDataComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_13_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_13_C.py index 1052503eb88c9821f89f1964092557f6849e6d93..e25f2dbbbdea673eba5b2e343d73b9f344ee8d98 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_13_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_13_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest @@ -77,12 +91,12 @@ class Test(ControllerTest): # reporting the advertising packets sent by the Lower Tester. The address in # the report is resolved by the IUT using the distributed IRK. await self.expect_evt( - hci.LeAdvertisingReportRaw(responses=[ - hci.LeAdvertisingResponseRaw(event_type=hci.AdvertisingEventType.ADV_NONCONN_IND, - address_type=hci.AddressType.PUBLIC_IDENTITY_ADDRESS, - address=peer_identity_address, - advertising_data=[1, 2, 3], - rssi=0xf0) + hci.LeAdvertisingReport(responses=[ + hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.ADV_NONCONN_IND, + address_type=hci.AddressType.PUBLIC_IDENTITY_ADDRESS, + address=peer_identity_address, + advertising_data=[1, 2, 3], + rssi=0xf0) ])) # 6. The Upper Tester sends an HCI_LE_Set_Scan_Enable to the IUT to stop the @@ -116,12 +130,12 @@ class Test(ControllerTest): # unresolved (as received in the advertising PDU) in the advertising report # events to the Upper Tester. await self.expect_evt( - hci.LeAdvertisingReportRaw(responses=[ - hci.LeAdvertisingResponseRaw(event_type=hci.AdvertisingEventType.ADV_NONCONN_IND, - address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS, - address=peer_resolvable_address, - advertising_data=[1, 2, 3], - rssi=0xf0) + hci.LeAdvertisingReport(responses=[ + hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.ADV_NONCONN_IND, + address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS, + address=peer_resolvable_address, + advertising_data=[1, 2, 3], + rssi=0xf0) ])) # 11. The Upper Tester sends an HCI_LE_Set_Scan_Enable to the IUT to stop the diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_14_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_14_C.py index 7caa4e1240b41a0eb3b9107b28e1f72008677d8f..5e55a18d2e9a871da8cbe118a6d6315fe6c36572 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_14_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_14_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import unittest diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_18_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_18_C.py index 5ab25411b5f78ad3d6cb7e5bc8ff5099deaf442e..55369396e4ccef04dfe629419f5925b6ed7b250a 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_18_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_18_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import asyncio import hci_packets as hci import link_layer_packets as ll @@ -100,12 +114,12 @@ class Test(ControllerTest): # HCI_LE_Advertising_Report containing the information used in the # ADV_SCAN_IND packets. await self.expect_evt( - hci.LeAdvertisingReportRaw(responses=[ - hci.LeAdvertisingResponseRaw(event_type=hci.AdvertisingEventType.ADV_SCAN_IND, - address_type=hci.AddressType.PUBLIC_IDENTITY_ADDRESS, - address=peer_identity_address, - advertising_data=[1, 2, 3], - rssi=0xf0) + hci.LeAdvertisingReport(responses=[ + hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.ADV_SCAN_IND, + address_type=hci.AddressType.PUBLIC_IDENTITY_ADDRESS, + address=peer_identity_address, + advertising_data=[1, 2, 3], + rssi=0xf0) ])) # 7. Lower Tester sends a SCAN_RSP packet T_IFS after the SCAN_REQ @@ -119,11 +133,11 @@ class Test(ControllerTest): # 9. Interleave with step 7: Upper Tester receives an # HCI_LE_Advertising_Report event containing the scan response # information. - await self.expect_evt(hci.LeAdvertisingReportRaw(responses=[ - hci.LeAdvertisingResponseRaw(event_type=hci.AdvertisingEventType.SCAN_RESPONSE, - address_type=hci.AddressType.PUBLIC_IDENTITY_ADDRESS, - address=peer_identity_address, - advertising_data=[4, 5, 6], - rssi=0xf0) + await self.expect_evt(hci.LeAdvertisingReport(responses=[ + hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.SCAN_RESPONSE, + address_type=hci.AddressType.PUBLIC_IDENTITY_ADDRESS, + address=peer_identity_address, + advertising_data=[4, 5, 6], + rssi=0xf0) ]), timeout=3) diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_19_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_19_C.py index 03508e2142a5785396d4498d0be4291261ccd2f7..41c3db5b94c18751a00cc6bc1e8759840390bbc4 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_19_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_19_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import math @@ -68,10 +82,10 @@ class Test(ControllerTest): hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS, scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL, scanning_phys=0x1, - parameters=[ - hci.PhyScanParameters(le_scan_type=hci.LeScanType.PASSIVE, - le_scan_interval=0x0010, - le_scan_window=0x0010) + scanning_phy_parameters=[ + hci.ScanningPhyParameters(le_scan_type=hci.LeScanType.PASSIVE, + le_scan_interval=0x0010, + le_scan_window=0x0010) ])) await self.expect_evt( @@ -170,8 +184,8 @@ class Test(ControllerTest): fragment_length = min(max_fragment_length, remaining_length) data_status = hci.DataStatus.CONTINUING if remaining_length > max_fragment_length else hci.DataStatus.COMPLETE await self.expect_evt( - hci.LeExtendedAdvertisingReportRaw(responses=[ - hci.LeExtendedAdvertisingResponseRaw( + hci.LeExtendedAdvertisingReport(responses=[ + hci.LeExtendedAdvertisingResponse( connectable=connectable, scannable=scannable, directed=not target_address is None, diff --git a/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py b/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py index ff2ccba5d7efd0fbc5e12ab6227436a39a3ec24f..80a6245c68d15c0bd6f41ce4188904e79915bcfe 100644 --- a/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py +++ b/tools/rootcanal/test/LL/DDI/SCN/BV_79_C.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import hci_packets as hci import link_layer_packets as ll import math @@ -38,10 +52,10 @@ class Test(ControllerTest): hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS, scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL, scanning_phys=0x1, - parameters=[ - hci.PhyScanParameters(le_scan_type=hci.LeScanType.PASSIVE, - le_scan_interval=0x0010, - le_scan_window=0x0010) + scanning_phy_parameters=[ + hci.ScanningPhyParameters(le_scan_type=hci.LeScanType.PASSIVE, + le_scan_interval=0x0010, + le_scan_window=0x0010) ])) await self.expect_evt( @@ -81,8 +95,8 @@ class Test(ControllerTest): # nonzero Periodic_Advertising_Interval, Data Status in the Event_Type[i] field set to the value # 0b00 (Complete), and RSSI[i] set to a valid value. await self.expect_evt( - hci.LeExtendedAdvertisingReportRaw(responses=[ - hci.LeExtendedAdvertisingResponseRaw( + hci.LeExtendedAdvertisingReport(responses=[ + hci.LeExtendedAdvertisingResponse( connectable=False, scannable=False, directed=False, diff --git a/tools/rootcanal/test/LL/scan_collision.py b/tools/rootcanal/test/LL/scan_collision.py new file mode 100644 index 0000000000000000000000000000000000000000..3239a6158da412e3701529968b2e670d67b65ad9 --- /dev/null +++ b/tools/rootcanal/test/LL/scan_collision.py @@ -0,0 +1,124 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest, generate_rpa + + +class Test(ControllerTest): + + # Verify that the scanner gracefully handles being disabled before + # receiving the response to a scan request. + async def test(self): + # Test parameters. + LL_scanner_scanInterval_MIN = 0x2000 + LL_scanner_scanInterval_MAX = 0x2000 + LL_scanner_scanWindow_MIN = 0x200 + LL_scanner_scanWindow_MAX = 0x200 + LL_scanner_Adv_Channel_Map = 0x7 + + controller = self.controller + peer_address = Address('aa:bb:cc:dd:ee:ff') + + controller.send_cmd( + hci.LeSetScanParameters(le_scan_type=hci.LeScanType.ACTIVE, + le_scan_interval=LL_scanner_scanInterval_MAX, + le_scan_window=LL_scanner_scanWindow_MAX, + own_address_type=hci.OwnAddressType.RESOLVABLE_OR_PUBLIC_ADDRESS, + scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL)) + + await self.expect_evt(hci.LeSetScanParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + controller.send_cmd( + hci.LeSetScanEnable(le_scan_enable=hci.Enable.ENABLED, filter_duplicates=hci.Enable.DISABLED)) + + await self.expect_evt(hci.LeSetScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + controller.send_ll(ll.LeLegacyAdvertisingPdu(source_address=peer_address, + advertising_address_type=ll.AddressType.RANDOM, + advertising_type=ll.LegacyAdvertisingType.ADV_SCAN_IND, + advertising_data=[]), + rssi=-16) + + await self.expect_evt( + hci.LeAdvertisingReport(responses=[ + hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.ADV_SCAN_IND, + address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS, + address=peer_address, + advertising_data=[], + rssi=0xf0) + ])) + + await self.expect_ll( + ll.LeScan(source_address=controller.address, + destination_address=peer_address, + advertising_address_type=ll.AddressType.RANDOM, + scanning_address_type=ll.AddressType.PUBLIC)) + + # Disable the scanner before the scan response is received. + controller.send_cmd(hci.LeSetScanEnable(le_scan_enable=hci.Enable.DISABLED)) + + await self.expect_evt(hci.LeSetScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + # Send the scan response now; it should be ignored by the disabled scanner. + controller.send_ll(ll.LeScanResponse(source_address=peer_address, + advertising_address_type=ll.AddressType.RANDOM, + scan_response_data=[]), + rssi=-16) + + # Re-enable the scanner and send the advertising PDU again. + # This time expect the scan response to be properly reported. + controller.send_cmd( + hci.LeSetScanEnable(le_scan_enable=hci.Enable.ENABLED, filter_duplicates=hci.Enable.DISABLED)) + + await self.expect_evt(hci.LeSetScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + controller.send_ll(ll.LeLegacyAdvertisingPdu(source_address=peer_address, + advertising_address_type=ll.AddressType.RANDOM, + advertising_type=ll.LegacyAdvertisingType.ADV_SCAN_IND, + advertising_data=[]), + rssi=-16) + + await self.expect_evt( + hci.LeAdvertisingReport(responses=[ + hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.ADV_SCAN_IND, + address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS, + address=peer_address, + advertising_data=[], + rssi=0xf0) + ])) + + await self.expect_ll( + ll.LeScan(source_address=controller.address, + destination_address=peer_address, + advertising_address_type=ll.AddressType.RANDOM, + scanning_address_type=ll.AddressType.PUBLIC)) + + controller.send_ll(ll.LeScanResponse(source_address=peer_address, + advertising_address_type=ll.AddressType.RANDOM, + scan_response_data=[]), + rssi=-16) + + await self.expect_evt( + hci.LeAdvertisingReport(responses=[ + hci.LeAdvertisingResponse(event_type=hci.AdvertisingEventType.SCAN_RESPONSE, + address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS, + address=peer_address, + advertising_data=[], + rssi=0xf0) + ])) diff --git a/tools/rootcanal/test/LMP/LIH/BV_01_C.py b/tools/rootcanal/test/LMP/LIH/BV_01_C.py new file mode 100644 index 0000000000000000000000000000000000000000..fe4c7786ec4ce1ed12d1ae2079345d3b7fd30a13 --- /dev/null +++ b/tools/rootcanal/test/LMP/LIH/BV_01_C.py @@ -0,0 +1,77 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # LMP/LIH/BV-01-C [Initiate Role Switch] + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) + + await self.expect_evt(hci.WriteScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + controller.send_ll( + ll.Page(source_address=peer_address, destination_address=controller.address, allow_role_switch=False)) + + await self.expect_evt(hci.ConnectionRequest(bd_addr=peer_address, link_type=hci.ConnectionRequestLinkType.ACL)) + + controller.send_cmd( + hci.AcceptConnectionRequest(bd_addr=peer_address, role=hci.AcceptConnectionRequestRole.REMAIN_PERIPHERAL)) + + await self.expect_evt(hci.AcceptConnectionRequestStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.PageResponse(source_address=controller.address, destination_address=peer_address, try_role_switch=False)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) + + controller.send_cmd( + hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, + link_policy_settings=hci.LinkPolicy.ENABLE_ROLE_SWITCH)) + + await self.expect_evt( + hci.WriteLinkPolicySettingsComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=acl_connection_handle)) + + controller.send_cmd(hci.SwitchRole(bd_addr=peer_address, role=hci.Role.CENTRAL)) + + await self.expect_evt(hci.SwitchRoleStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll(ll.RoleSwitchRequest(source_address=controller.address, destination_address=peer_address)) + + controller.send_ll( + ll.RoleSwitchResponse(source_address=peer_address, + destination_address=controller.address, + status=ErrorCode.SUCCESS)) + + await self.expect_evt(hci.RoleChange(status=ErrorCode.SUCCESS, bd_addr=peer_address, new_role=hci.Role.CENTRAL)) diff --git a/tools/rootcanal/test/LMP/LIH/BV_02_C.py b/tools/rootcanal/test/LMP/LIH/BV_02_C.py new file mode 100644 index 0000000000000000000000000000000000000000..c633b1c8c2e1b9be71e4e95babd86a2d9c490384 --- /dev/null +++ b/tools/rootcanal/test/LMP/LIH/BV_02_C.py @@ -0,0 +1,80 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # LMP/LIH/BV-02-C [Accept Role Switch] + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd( + hci.CreateConnection(bd_addr=peer_address, + packet_type=0x7fff, + page_scan_repetition_mode=hci.PageScanRepetitionMode.R0, + allow_role_switch=hci.CreateConnectionRoleSwitch.REMAIN_CENTRAL)) + + await self.expect_evt(hci.CreateConnectionStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.Page(source_address=controller.address, destination_address=peer_address, allow_role_switch=False)) + + controller.send_ll( + ll.PageResponse(source_address=peer_address, destination_address=controller.address, try_role_switch=False)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) + + controller.send_cmd( + hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, + link_policy_settings=hci.LinkPolicy.ENABLE_ROLE_SWITCH)) + + await self.expect_evt( + hci.WriteLinkPolicySettingsComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=acl_connection_handle)) + + controller.send_ll(ll.RoleSwitchRequest(source_address=peer_address, destination_address=controller.address)) + + await self.expect_ll( + ll.RoleSwitchResponse(source_address=controller.address, + destination_address=peer_address, + status=ErrorCode.SUCCESS)) + + await self.expect_evt( + hci.RoleChange(status=ErrorCode.SUCCESS, bd_addr=peer_address, new_role=hci.Role.PERIPHERAL)) + + controller.send_ll(ll.RoleSwitchRequest(source_address=peer_address, destination_address=controller.address)) + + await self.expect_ll( + ll.RoleSwitchResponse(source_address=controller.address, + destination_address=peer_address, + status=ErrorCode.SUCCESS)) + + await self.expect_evt(hci.RoleChange(status=ErrorCode.SUCCESS, bd_addr=peer_address, new_role=hci.Role.CENTRAL)) diff --git a/tools/rootcanal/test/LMP/LIH/BV_142_C.py b/tools/rootcanal/test/LMP/LIH/BV_142_C.py new file mode 100644 index 0000000000000000000000000000000000000000..408ab56044b9647ff483f7244ada9cc7adb7726b --- /dev/null +++ b/tools/rootcanal/test/LMP/LIH/BV_142_C.py @@ -0,0 +1,67 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # LMP/LIH/BV-142-C [Reject Role Switch Request] + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd( + hci.CreateConnection(bd_addr=peer_address, + packet_type=0x7fff, + page_scan_repetition_mode=hci.PageScanRepetitionMode.R0, + allow_role_switch=hci.CreateConnectionRoleSwitch.REMAIN_CENTRAL)) + + await self.expect_evt(hci.CreateConnectionStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.Page(source_address=controller.address, destination_address=peer_address, allow_role_switch=False)) + + controller.send_ll( + ll.PageResponse(source_address=peer_address, destination_address=controller.address, try_role_switch=False)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) + + controller.send_cmd(hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, + link_policy_settings=0)) + + await self.expect_evt( + hci.WriteLinkPolicySettingsComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=acl_connection_handle)) + + controller.send_ll(ll.RoleSwitchRequest(source_address=peer_address, destination_address=controller.address)) + + await self.expect_ll( + ll.RoleSwitchResponse(source_address=controller.address, + destination_address=peer_address, + status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED)) diff --git a/tools/rootcanal/test/LMP/LIH/BV_143_C.py b/tools/rootcanal/test/LMP/LIH/BV_143_C.py new file mode 100644 index 0000000000000000000000000000000000000000..9c56fd895d7482c13da707d10bc4a23e7657feb6 --- /dev/null +++ b/tools/rootcanal/test/LMP/LIH/BV_143_C.py @@ -0,0 +1,86 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # LMP/LIH/BV-143-C [Rejected Role Switch Request] + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) + + await self.expect_evt(hci.WriteScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + controller.send_ll( + ll.Page(source_address=peer_address, destination_address=controller.address, allow_role_switch=False)) + + await self.expect_evt(hci.ConnectionRequest(bd_addr=peer_address, link_type=hci.ConnectionRequestLinkType.ACL)) + + controller.send_cmd( + hci.AcceptConnectionRequest(bd_addr=peer_address, role=hci.AcceptConnectionRequestRole.REMAIN_PERIPHERAL)) + + await self.expect_evt(hci.AcceptConnectionRequestStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.PageResponse(source_address=controller.address, destination_address=peer_address, try_role_switch=False)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) + + controller.send_cmd( + hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, + link_policy_settings=hci.LinkPolicy.ENABLE_ROLE_SWITCH)) + + await self.expect_evt( + hci.WriteLinkPolicySettingsComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=acl_connection_handle)) + + controller.send_cmd(hci.SwitchRole(bd_addr=peer_address, role=hci.Role.CENTRAL)) + + await self.expect_evt(hci.SwitchRoleStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll(ll.RoleSwitchRequest(source_address=controller.address, destination_address=peer_address)) + + controller.send_ll( + ll.RoleSwitchResponse(source_address=peer_address, + destination_address=controller.address, + status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED)) + + await self.expect_evt( + hci.RoleChange(status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED, bd_addr=peer_address, + new_role=hci.Role.PERIPHERAL)) + + controller.send_cmd(hci.SwitchRole(bd_addr=peer_address, role=hci.Role.PERIPHERAL)) + + await self.expect_evt(hci.SwitchRoleStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_evt( + hci.RoleChange(status=ErrorCode.ROLE_SWITCH_FAILED, bd_addr=peer_address, new_role=hci.Role.PERIPHERAL)) diff --git a/tools/rootcanal/test/LMP/LIH/BV_144_C.py b/tools/rootcanal/test/LMP/LIH/BV_144_C.py new file mode 100644 index 0000000000000000000000000000000000000000..307144c01dd56a8663f504b233f159f9a464cc98 --- /dev/null +++ b/tools/rootcanal/test/LMP/LIH/BV_144_C.py @@ -0,0 +1,55 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # LMP/LIH/BV-144-C [Rejected Role Switch request at Setup, Peripheral] + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) + + await self.expect_evt(hci.WriteScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + controller.send_ll( + ll.Page(source_address=peer_address, destination_address=controller.address, allow_role_switch=False)) + + await self.expect_evt(hci.ConnectionRequest(bd_addr=peer_address, link_type=hci.ConnectionRequestLinkType.ACL)) + + controller.send_cmd( + hci.AcceptConnectionRequest(bd_addr=peer_address, role=hci.AcceptConnectionRequestRole.BECOME_CENTRAL)) + + await self.expect_evt(hci.AcceptConnectionRequestStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.PageResponse(source_address=controller.address, destination_address=peer_address, try_role_switch=True)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) diff --git a/tools/rootcanal/test/LMP/LIH/BV_149_C.py b/tools/rootcanal/test/LMP/LIH/BV_149_C.py new file mode 100644 index 0000000000000000000000000000000000000000..e80aa0af2b68c6fe02be6a5d7242233fc80be4de --- /dev/null +++ b/tools/rootcanal/test/LMP/LIH/BV_149_C.py @@ -0,0 +1,82 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # LMP/LIH/BV-149-C [Reject Role Switch] + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd( + hci.CreateConnection(bd_addr=peer_address, + packet_type=0x7fff, + page_scan_repetition_mode=hci.PageScanRepetitionMode.R0, + allow_role_switch=hci.CreateConnectionRoleSwitch.REMAIN_CENTRAL)) + + await self.expect_evt(hci.CreateConnectionStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.Page(source_address=controller.address, destination_address=peer_address, allow_role_switch=False)) + + controller.send_ll( + ll.PageResponse(source_address=peer_address, destination_address=controller.address, try_role_switch=False)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) + + controller.send_cmd( + hci.WriteLinkPolicySettings(connection_handle=acl_connection_handle, + link_policy_settings=hci.LinkPolicy.ENABLE_ROLE_SWITCH)) + + await self.expect_evt( + hci.WriteLinkPolicySettingsComplete(status=ErrorCode.SUCCESS, + num_hci_command_packets=1, + connection_handle=acl_connection_handle)) + + controller.send_cmd(hci.SwitchRole(bd_addr=peer_address, role=hci.Role.CENTRAL)) + + await self.expect_evt(hci.SwitchRoleStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_evt( + hci.RoleChange(status=ErrorCode.ROLE_SWITCH_FAILED, bd_addr=peer_address, new_role=hci.Role.CENTRAL)) + + controller.send_cmd(hci.SwitchRole(bd_addr=peer_address, role=hci.Role.PERIPHERAL)) + + await self.expect_evt(hci.SwitchRoleStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll(ll.RoleSwitchRequest(source_address=controller.address, destination_address=peer_address)) + + controller.send_ll( + ll.RoleSwitchResponse(source_address=peer_address, + destination_address=controller.address, + status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED)) + + await self.expect_evt( + hci.RoleChange(status=ErrorCode.ROLE_CHANGE_NOT_ALLOWED, bd_addr=peer_address, new_role=hci.Role.CENTRAL)) diff --git a/tools/rootcanal/test/LMP/LIH/BV_78_C.py b/tools/rootcanal/test/LMP/LIH/BV_78_C.py new file mode 100644 index 0000000000000000000000000000000000000000..24a75f62b719984f342cffb59ac734b363fa5084 --- /dev/null +++ b/tools/rootcanal/test/LMP/LIH/BV_78_C.py @@ -0,0 +1,55 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # LMP/LIH/BV-78-C [Role Switch at Setup, Central] + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd( + hci.CreateConnection(bd_addr=peer_address, + packet_type=0x7fff, + page_scan_repetition_mode=hci.PageScanRepetitionMode.R1, + allow_role_switch=hci.CreateConnectionRoleSwitch.ALLOW_ROLE_SWITCH)) + + await self.expect_evt(hci.CreateConnectionStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.Page(source_address=controller.address, destination_address=peer_address, allow_role_switch=True)) + + controller.send_ll( + ll.PageResponse(source_address=peer_address, destination_address=controller.address, try_role_switch=True)) + + await self.expect_evt( + hci.RoleChange(status=ErrorCode.SUCCESS, bd_addr=peer_address, new_role=hci.Role.PERIPHERAL)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) diff --git a/tools/rootcanal/test/LMP/LIH/BV_79_C.py b/tools/rootcanal/test/LMP/LIH/BV_79_C.py new file mode 100644 index 0000000000000000000000000000000000000000..a538c1c63a077a71489fb5d37637d207edc1e936 --- /dev/null +++ b/tools/rootcanal/test/LMP/LIH/BV_79_C.py @@ -0,0 +1,57 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # LMP/LIH/BV-79-C [Role Switch at Setup, Peripheral] + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) + + await self.expect_evt(hci.WriteScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + controller.send_ll( + ll.Page(source_address=peer_address, destination_address=controller.address, allow_role_switch=True)) + + await self.expect_evt(hci.ConnectionRequest(bd_addr=peer_address, link_type=hci.ConnectionRequestLinkType.ACL)) + + controller.send_cmd( + hci.AcceptConnectionRequest(bd_addr=peer_address, role=hci.AcceptConnectionRequestRole.BECOME_CENTRAL)) + + await self.expect_evt(hci.AcceptConnectionRequestStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.PageResponse(source_address=controller.address, destination_address=peer_address, try_role_switch=True)) + + await self.expect_evt(hci.RoleChange(status=ErrorCode.SUCCESS, bd_addr=peer_address, new_role=hci.Role.CENTRAL)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) diff --git a/tools/rootcanal/test/LMP/page_collision.py b/tools/rootcanal/test/LMP/page_collision.py new file mode 100644 index 0000000000000000000000000000000000000000..a90c9b16bbe7d32fcdfba9a7086cd45f2f716a87 --- /dev/null +++ b/tools/rootcanal/test/LMP/page_collision.py @@ -0,0 +1,58 @@ +from dataclasses import dataclass +import hci_packets as hci +import link_layer_packets as ll +import unittest +from hci_packets import ErrorCode +from py.bluetooth import Address +from py.controller import ControllerTest + + +class Test(ControllerTest): + + # Verify that the controller can establish a connection if the remote device + # is initiating a connection at the same time. The local device responds to he + # page events and accepts the connection. The local connection attempt is + # abandoned and a Connection Complete event with status Connection Already + # Exists is sent to the Host. + async def test(self): + # Test parameters. + controller = self.controller + acl_connection_handle = 0xefe + peer_address = Address('11:22:33:44:55:66') + + controller.send_cmd(hci.WriteScanEnable(scan_enable=hci.ScanEnable.PAGE_SCAN_ONLY)) + + await self.expect_evt(hci.WriteScanEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + controller.send_cmd( + hci.CreateConnection( + bd_addr=peer_address, + packet_type=0, + page_scan_repetition_mode=hci.PageScanRepetitionMode.R1, + allow_role_switch=hci.CreateConnectionRoleSwitch.REMAIN_CENTRAL, + )) + + await self.expect_evt(hci.CreateConnectionStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.Page(source_address=controller.address, destination_address=peer_address, allow_role_switch=False)) + + controller.send_ll( + ll.Page(source_address=peer_address, destination_address=controller.address, allow_role_switch=False)) + + await self.expect_evt(hci.ConnectionRequest(bd_addr=peer_address, link_type=hci.ConnectionRequestLinkType.ACL)) + + controller.send_cmd( + hci.AcceptConnectionRequest(bd_addr=peer_address, role=hci.AcceptConnectionRequestRole.REMAIN_PERIPHERAL)) + + await self.expect_evt(hci.AcceptConnectionRequestStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1)) + + await self.expect_ll( + ll.PageResponse(source_address=controller.address, destination_address=peer_address, try_role_switch=False)) + + await self.expect_evt( + hci.ConnectionComplete(status=ErrorCode.SUCCESS, + connection_handle=acl_connection_handle, + bd_addr=peer_address, + link_type=hci.LinkType.ACL, + encryption_enabled=hci.Enable.DISABLED)) diff --git a/tools/rootcanal/test/controller/le/le_add_device_to_resolving_list_test.cc b/tools/rootcanal/test/controller/le/le_add_device_to_resolving_list_test.cc index 427861e0e9d20b590220279517635c2d9b6a0ea8..b2a44d4812e80169354d798b1a93a95ad9c6d70e 100644 --- a/tools/rootcanal/test/controller/le/le_add_device_to_resolving_list_test.cc +++ b/tools/rootcanal/test/controller/le/le_add_device_to_resolving_list_test.cc @@ -130,4 +130,16 @@ TEST_F(LeAddDeviceToResolvingListTest, PeerIrkDuplicate) { ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); } +TEST_F(LeAddDeviceToResolvingListTest, EmptyPeerIrkDuplicate) { + ASSERT_EQ(controller_.LeAddDeviceToResolvingList( + PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS, Address{1}, + std::array{0}, std::array{1}), + ErrorCode::SUCCESS); + + ASSERT_EQ(controller_.LeAddDeviceToResolvingList( + PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, Address{1}, + std::array{0}, std::array{1}), + ErrorCode::SUCCESS); +} + } // namespace rootcanal diff --git a/tools/rootcanal/test/controller/le/le_scanning_filter_duplicates_test.cc b/tools/rootcanal/test/controller/le/le_scanning_filter_duplicates_test.cc index a37dafc4d85ac8ae38dd9bce94bf17cbea5e03fe..feed4edcd7d44cf82d47915fc00155886237fe23 100644 --- a/tools/rootcanal/test/controller/le/le_scanning_filter_duplicates_test.cc +++ b/tools/rootcanal/test/controller/le/le_scanning_filter_duplicates_test.cc @@ -23,10 +23,8 @@ #include #include "hci/address.h" -#include "hci/hci_packets.h" #include "model/controller/link_layer_controller.h" -#include "packet/bit_inserter.h" -#include "packet/packet_view.h" +#include "packets/hci_packets.h" #include "packets/link_layer_packets.h" namespace rootcanal { @@ -73,7 +71,7 @@ class LeScanningFilterDuplicates : public ::testing::Test { void StartExtendedScan(FilterDuplicates filter_duplicates, uint16_t duration = 0, uint16_t period = 0) { - bluetooth::hci::PhyScanParameters param; + bluetooth::hci::ScanningPhyParameters param; param.le_scan_type_ = LeScanType::ACTIVE; param.le_scan_interval_ = 0x4; param.le_scan_window_ = 0x4; @@ -95,7 +93,7 @@ class LeScanningFilterDuplicates : public ::testing::Test { /// Helper for building ScanResponse packets static model::packets::LinkLayerPacketView LeScanResponse( std::vector const data = {}) { - return FromBuilder(*model::packets::LeScanResponseBuilder::Create( + return FromBuilder(model::packets::LeScanResponseBuilder::Create( Address::kEmpty, Address::kEmpty, model::packets::AddressType::PUBLIC, data)); } @@ -103,7 +101,7 @@ class LeScanningFilterDuplicates : public ::testing::Test { /// Helper for building LeLegacyAdvertisingPdu packets static model::packets::LinkLayerPacketView LeLegacyAdvertisingPdu( std::vector const data = {}) { - return FromBuilder(*model::packets::LeLegacyAdvertisingPduBuilder::Create( + return FromBuilder(model::packets::LeLegacyAdvertisingPduBuilder::Create( Address::kEmpty, Address::kEmpty, model::packets::AddressType::PUBLIC, model::packets::AddressType::PUBLIC, model::packets::LegacyAdvertisingType::ADV_IND, data)); @@ -112,13 +110,21 @@ class LeScanningFilterDuplicates : public ::testing::Test { /// Helper for building LeExtendedAdvertisingPdu packets static model::packets::LinkLayerPacketView LeExtendedAdvertisingPdu( std::vector const data = {}) { - return FromBuilder(*model::packets::LeExtendedAdvertisingPduBuilder::Create( + return FromBuilder(model::packets::LeExtendedAdvertisingPduBuilder::Create( Address::kEmpty, Address::kEmpty, model::packets::AddressType::PUBLIC, model::packets::AddressType::PUBLIC, 0, 1, 0, 0, 0, model::packets::PrimaryPhyType::LE_1M, model::packets::SecondaryPhyType::LE_1M, 0, data)); } + static model::packets::LinkLayerPacketView FromBuilder( + std::unique_ptr builder) { + auto data = + std::make_shared>(builder->SerializeToBytes()); + return model::packets::LinkLayerPacketView::Create( + pdl::packet::slice(data)); + } + enum Filtered { kFiltered, kReported, @@ -154,18 +160,6 @@ class LeScanningFilterDuplicates : public ::testing::Test { static void remote_listener_( std::shared_ptr /* packet */, Phy::Type /* phy */, int8_t /* tx_power */) {} - - /// Helper for building packet view from packet builder - static model::packets::LinkLayerPacketView FromBuilder( - model::packets::LinkLayerPacketBuilder& builder) { - std::shared_ptr> buffer(new std::vector); - auto bit_inserter = bluetooth::packet::BitInserter(*buffer); - - builder.Serialize(bit_inserter); - - return model::packets::LinkLayerPacketView::Create( - PacketView(buffer)); - } }; unsigned LeScanningFilterDuplicates::event_listener_called_ = 0; diff --git a/tools/rootcanal/test/controller/le/le_set_extended_scan_enable_test.cc b/tools/rootcanal/test/controller/le/le_set_extended_scan_enable_test.cc index 79b9663619312a2ba68f4cba0443ab3748065077..278b9d06aa267c4a744ee05b16f7f9a351390ff4 100644 --- a/tools/rootcanal/test/controller/le/le_set_extended_scan_enable_test.cc +++ b/tools/rootcanal/test/controller/le/le_set_extended_scan_enable_test.cc @@ -33,10 +33,10 @@ class LeSetExtendedScanEnableTest : public ::testing::Test { LinkLayerController controller_{address_, properties_}; }; -static PhyScanParameters MakePhyScanParameters(LeScanType scan_type, - uint16_t scan_interval, - uint16_t scan_window) { - PhyScanParameters parameters; +static ScanningPhyParameters MakeScanningPhyParameters(LeScanType scan_type, + uint16_t scan_interval, + uint16_t scan_window) { + ScanningPhyParameters parameters; parameters.le_scan_type_ = scan_type; parameters.le_scan_interval_ = scan_interval; parameters.le_scan_window_ = scan_window; @@ -44,22 +44,24 @@ static PhyScanParameters MakePhyScanParameters(LeScanType scan_type, } TEST_F(LeSetExtendedScanEnableTest, EnableUsingPublicAddress) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), ErrorCode::SUCCESS); } TEST_F(LeSetExtendedScanEnableTest, EnableUsingRandomAddress) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::RANDOM_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::RANDOM_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetRandomAddress(Address{1}), ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), @@ -67,11 +69,12 @@ TEST_F(LeSetExtendedScanEnableTest, EnableUsingRandomAddress) { } TEST_F(LeSetExtendedScanEnableTest, EnableUsingResolvableAddress) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetRandomAddress(Address{1}), ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), @@ -79,11 +82,12 @@ TEST_F(LeSetExtendedScanEnableTest, EnableUsingResolvableAddress) { } TEST_F(LeSetExtendedScanEnableTest, ResetEachPeriod) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::RESET_EACH_PERIOD, 100, 1000), ErrorCode::SUCCESS); @@ -96,11 +100,12 @@ TEST_F(LeSetExtendedScanEnableTest, Disable) { } TEST_F(LeSetExtendedScanEnableTest, ValidDuration) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 127, 1), @@ -108,11 +113,12 @@ TEST_F(LeSetExtendedScanEnableTest, ValidDuration) { } TEST_F(LeSetExtendedScanEnableTest, InvalidDuration) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::RESET_EACH_PERIOD, 0, 0), @@ -123,20 +129,22 @@ TEST_F(LeSetExtendedScanEnableTest, InvalidDuration) { } TEST_F(LeSetExtendedScanEnableTest, NoRandomAddress) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::RANDOM_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::RANDOM_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::SUCCESS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); diff --git a/tools/rootcanal/test/controller/le/le_set_extended_scan_parameters_test.cc b/tools/rootcanal/test/controller/le/le_set_extended_scan_parameters_test.cc index 0c153ea1acf2b17a0d459edb74fe3eb69cf6debe..3e1ab5390a7a1747991431e99f20461d9ee93428 100644 --- a/tools/rootcanal/test/controller/le/le_set_extended_scan_parameters_test.cc +++ b/tools/rootcanal/test/controller/le/le_set_extended_scan_parameters_test.cc @@ -33,10 +33,10 @@ class LeSetExtendedScanParametersTest : public ::testing::Test { LinkLayerController controller_{address_, properties_}; }; -static PhyScanParameters MakePhyScanParameters(LeScanType scan_type, - uint16_t scan_interval, - uint16_t scan_window) { - PhyScanParameters parameters; +static ScanningPhyParameters MakeScanningPhyParameters(LeScanType scan_type, + uint16_t scan_interval, + uint16_t scan_window) { + ScanningPhyParameters parameters; parameters.le_scan_type_ = scan_type; parameters.le_scan_interval_ = scan_interval; parameters.le_scan_window_ = scan_window; @@ -47,8 +47,8 @@ TEST_F(LeSetExtendedScanParametersTest, Success) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x5, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200), - MakePhyScanParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200), + MakeScanningPhyParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), ErrorCode::SUCCESS); } @@ -56,8 +56,8 @@ TEST_F(LeSetExtendedScanParametersTest, ScanningActive) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x5, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200), - MakePhyScanParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200), + MakeScanningPhyParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), ErrorCode::SUCCESS); ASSERT_EQ(controller_.LeSetExtendedScanEnable( true, FilterDuplicates::DISABLED, 0, 0), @@ -66,17 +66,18 @@ TEST_F(LeSetExtendedScanParametersTest, ScanningActive) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x5, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200), - MakePhyScanParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200), + MakeScanningPhyParameters(LeScanType::ACTIVE, 0x2000, 0x200)}), ErrorCode::COMMAND_DISALLOWED); } TEST_F(LeSetExtendedScanParametersTest, ReservedPhy) { - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x80, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x80, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); } TEST_F(LeSetExtendedScanParametersTest, InvalidPhyParameters) { @@ -85,19 +86,20 @@ TEST_F(LeSetExtendedScanParametersTest, InvalidPhyParameters) { LeScanningFilterPolicy::ACCEPT_ALL, 0x1, {}), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200), - MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), - ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200), + MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x200)}), + ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); } TEST_F(LeSetExtendedScanParametersTest, InvalidScanInterval) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x0, 0x200)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x0, 0x200)}), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); } @@ -105,14 +107,15 @@ TEST_F(LeSetExtendedScanParametersTest, InvalidScanWindow) { ASSERT_EQ(controller_.LeSetExtendedScanParameters( OwnAddressType::PUBLIC_DEVICE_ADDRESS, LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x0)}), + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x0)}), ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); - ASSERT_EQ(controller_.LeSetExtendedScanParameters( - OwnAddressType::PUBLIC_DEVICE_ADDRESS, - LeScanningFilterPolicy::ACCEPT_ALL, 0x1, - {MakePhyScanParameters(LeScanType::PASSIVE, 0x2000, 0x2001)}), - ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); + ASSERT_EQ( + controller_.LeSetExtendedScanParameters( + OwnAddressType::PUBLIC_DEVICE_ADDRESS, + LeScanningFilterPolicy::ACCEPT_ALL, 0x1, + {MakeScanningPhyParameters(LeScanType::PASSIVE, 0x2000, 0x2001)}), + ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); } } // namespace rootcanal diff --git a/tools/rootcanal/test/controller/le/test_helpers.h b/tools/rootcanal/test/controller/le/test_helpers.h index 074e258d5c4c3b01139f807136b0ec4bd285dcb4..4c9016c22cb8840e36893b2da7eb3754e9e73e80 100644 --- a/tools/rootcanal/test/controller/le/test_helpers.h +++ b/tools/rootcanal/test/controller/le/test_helpers.h @@ -49,18 +49,18 @@ MakeAdvertisingEventProperties(unsigned mask = 0) { return set; } -[[maybe_unused]] static bluetooth::hci::LeCreateConnPhyScanParameters +[[maybe_unused]] static bluetooth::hci::InitiatingPhyParameters MakeInitiatingPhyParameters(uint16_t scan_interval, uint16_t scan_window, uint16_t connection_interval_min, uint16_t connection_interval_max, uint16_t max_latency, uint16_t supervision_timeout, uint16_t min_ce_length, uint16_t max_ce_length) { - bluetooth::hci::LeCreateConnPhyScanParameters parameters; + bluetooth::hci::InitiatingPhyParameters parameters; parameters.scan_interval_ = scan_interval; parameters.scan_window_ = scan_window; - parameters.conn_interval_min_ = connection_interval_min; - parameters.conn_interval_max_ = connection_interval_max; - parameters.conn_latency_ = max_latency; + parameters.connection_interval_min_ = connection_interval_min; + parameters.connection_interval_max_ = connection_interval_max; + parameters.max_latency_ = max_latency; parameters.supervision_timeout_ = supervision_timeout; parameters.min_ce_length_ = min_ce_length; parameters.max_ce_length_ = max_ce_length; diff --git a/tools/rootcanal/test/main.py b/tools/rootcanal/test/main.py index 8868e26c0a163820d0ff81a50a1a3244d5c54d50..63e223a1f078c9b1f30174dbaa5fd19458d7dedc 100644 --- a/tools/rootcanal/test/main.py +++ b/tools/rootcanal/test/main.py @@ -1,3 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from importlib import resources from pathlib import Path import importlib @@ -6,6 +20,12 @@ import tempfile import unittest tests = [ + 'LL.CIS.CEN.BV_01_C', + 'LL.CIS.CEN.BV_03_C', + 'LL.CIS.CEN.BV_10_C', + 'LL.CIS.CEN.BV_26_C', + 'LL.CIS.PER.BV_01_C', + 'LL.CIS.PER.BV_02_C', 'LL.CON_.CEN.BV_41_C', 'LL.CON_.CEN.BV_43_C', 'LL.CON_.PER.BV_40_C', @@ -35,13 +55,28 @@ tests = [ 'LL.DDI.SCN.BV_18_C', 'LL.DDI.SCN.BV_19_C', 'LL.DDI.SCN.BV_79_C', + 'LMP.LIH.BV_01_C', + 'LMP.LIH.BV_02_C', + 'LMP.LIH.BV_78_C', + 'LMP.LIH.BV_79_C', + 'LMP.LIH.BV_142_C', + 'LMP.LIH.BV_143_C', + 'LMP.LIH.BV_144_C', + 'LMP.LIH.BV_149_C', + 'LL.scan_collision', + 'LMP.page_collision', ] + +def include_test(test: str, patterns) -> bool: + return not patterns or any(test.startswith(prefix) for prefix in patterns) + + if __name__ == "__main__": suite = unittest.TestSuite() + patterns = [arg for arg in sys.argv[1:] if not arg.startswith('-')] for test in tests: - if len(sys.argv) > 1 and test not in sys.argv: - continue - module = importlib.import_module(f'test.{test}') - suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(module)) + if include_test(test, patterns): + module = importlib.import_module(f'test.{test}') + suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(module)) unittest.TextTestRunner(verbosity=3).run(suite) diff --git a/tools/rootcanal/test/pcap_filter_unittest.cc b/tools/rootcanal/test/pcap_filter_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..41a80768a7286f6c80bac51efb5a17f5382a7e42 --- /dev/null +++ b/tools/rootcanal/test/pcap_filter_unittest.cc @@ -0,0 +1,94 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hci/pcap_filter.h" + +#include + +#include "packets/hci_packets.h" + +namespace rootcanal { + +using namespace bluetooth::hci; + +class PcapFilterTest : public ::testing::Test { + public: + PcapFilterTest() = default; + ~PcapFilterTest() override = default; + + protected: + PcapFilter pcap_filter_; +}; + +TEST_F(PcapFilterTest, UnchangedIfNotDeviceName) { + // Leaves gap data entries that do not contain a name unchanged. + std::vector input_gap_data{ + 0x2, static_cast(GapDataType::FLAGS), 0x0}; + std::vector output_gap_data{input_gap_data.begin(), + input_gap_data.end()}; + pcap_filter_.FilterGapData(output_gap_data); + ASSERT_EQ(input_gap_data, output_gap_data); +} + +TEST_F(PcapFilterTest, ReplacesShortenedDeviceName) { + // Replaces the input gap data once, with a name of equal length. + std::vector input_gap_data{ + 0x2, + static_cast(GapDataType::FLAGS), + 0x0, + 0x4, + static_cast(GapDataType::SHORTENED_LOCAL_NAME), + 0xa, + 0xb, + 0xc}; + std::vector output_gap_data_1{input_gap_data.begin(), + input_gap_data.end()}; + pcap_filter_.FilterGapData(output_gap_data_1); + ASSERT_EQ(input_gap_data.size(), output_gap_data_1.size()); + ASSERT_NE(input_gap_data, output_gap_data_1); + + // Replaces the input gap data a second time with the same name. + std::vector output_gap_data_2{input_gap_data.begin(), + input_gap_data.end()}; + pcap_filter_.FilterGapData(output_gap_data_2); + ASSERT_EQ(output_gap_data_1, output_gap_data_2); +} + +TEST_F(PcapFilterTest, ReplacesCompleteDeviceName) { + // Replaces the input gap data once, with a name of equal length. + std::vector input_gap_data{ + 0x2, + static_cast(GapDataType::FLAGS), + 0x0, + 0x4, + static_cast(GapDataType::COMPLETE_LOCAL_NAME), + 0xa, + 0xb, + 0xc}; + std::vector output_gap_data_1{input_gap_data.begin(), + input_gap_data.end()}; + pcap_filter_.FilterGapData(output_gap_data_1); + ASSERT_EQ(input_gap_data.size(), output_gap_data_1.size()); + ASSERT_NE(input_gap_data, output_gap_data_1); + + // Replaces the input gap data a second time with the same name. + std::vector output_gap_data_2{input_gap_data.begin(), + input_gap_data.end()}; + pcap_filter_.FilterGapData(output_gap_data_2); + ASSERT_EQ(output_gap_data_1, output_gap_data_2); +} + +} // namespace rootcanal diff --git a/tools/rootcanal/test/posix_socket_unittest.cc b/tools/rootcanal/test/posix_socket_unittest.cc index cc48873145aad512c1eb4c076093bc7595e21800..e10cd00dae9d85165c644d312225bc42cc6177d7 100644 --- a/tools/rootcanal/test/posix_socket_unittest.cc +++ b/tools/rootcanal/test/posix_socket_unittest.cc @@ -1,4 +1,3 @@ - // Copyright (C) 2021 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,6 +11,7 @@ // 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 #include #include @@ -31,7 +31,6 @@ #include #include -#include "log.h" // for LOG_INFO #include "model/setup/async_manager.h" #include "net/posix/posix_async_socket_connector.h" #include "net/posix/posix_async_socket_server.h"